pax_global_header00006660000000000000000000000064137011030050014500gustar00rootroot0000000000000052 comment=9dc8e5a0b2f4e7237ac50a922b87d234ff56a6e5 v_sim-3.8.0/000077500000000000000000000000001370110300500126255ustar00rootroot00000000000000v_sim-3.8.0/.gitignore000066400000000000000000000056401370110300500146220ustar00rootroot00000000000000 # / /Makefile.in /configure /tmp* /depcomp /config.* /autom4te.cache /missing /aclocal.m4 /install-sh /intltool*.in /stamp-h.in /ltmain.sh /compile /debian /py-compile /intltool-merge /intltool-extract /Makefile /intltool-update /stamp-h1 /libtool /gtk-doc.make /test-driver /INSTALL # /Documentation/ /Documentation/Makefile.in # /Documentation/reference/ /Documentation/reference/Makefile.in /Documentation/reference/v_sim* /Documentation/reference/*.stamp /Documentation/reference/xml /Documentation/reference/html /Documentation/reference/version /Documentation/reference/tmpl* /Documentation/reference/gtk-doc.make # /etc/ /etc/Makefile.in /etc/v_sim.rc # /etc/win32/ /etc/win32/Makefile.in # /examples/ /examples/Makefile.in /examples/t[a-z]t[a-z].* # /lib/ /lib/Makefile.in /lib/Makefile # /lib/plug-ins/ /lib/plug-ins/Makefile.in # /lib/plug-ins/OpenBabel-wrapper/ /lib/plug-ins/OpenBabel-wrapper/Makefile.in # /lib/plug-ins/abinit/ /lib/plug-ins/abinit/Makefile.in # /lib/plug-ins/archives/ /lib/plug-ins/archives/Makefile.in # /lib/plug-ins/bigdft/ /lib/plug-ins/bigdft/Makefile.in # /lib/plug-ins/cube/ /lib/plug-ins/cube/Makefile.in # /lib/plug-ins/fpcrystal/ /lib/plug-ins/fpcrystal/Makefile.in # /lib/plug-ins/msym/ /lib/plug-ins/msym/Makefile.in # /lib/plug-ins/msym/libmsym/ /lib/plug-ins/msym/libmsym/.git /lib/plug-ins/msym/libmsym/.gitignore /lib/plug-ins/msym/libmsym/tmp # /lib/plug-ins/nanoquanta-netcdf/ /lib/plug-ins/nanoquanta-netcdf/Makefile.in # /lib/plug-ins/python-gi/ /lib/plug-ins/python-gi/Makefile.in /lib/plug-ins/python-gi/Makefile # /lib/plug-ins/xsf/ /lib/plug-ins/xsf/Makefile.in # /lib/python/ /lib/python/Makefile.in # /m4/ /m4/Makefile.in /m4/*.m4 # /pixmaps/ /pixmaps/Makefile.in /pixmaps/Makefile # /pixmaps/illustration/ /pixmaps/illustration/Makefile.in # /pixmaps/logo/ /pixmaps/logo/Makefile.in # /po/ /po/Makefile.in /po/*.gmo /po/Makefile.in.in # /src/ /src/Makefile.in /src/Makefile /src/.deps /src/v_sim /src/v_sim-dev # /src/OSOpenGL/ /src/OSOpenGL/Makefile.in # /src/coreTools/ /src/coreTools/Makefile.in # /src/dumpModules/ /src/dumpModules/Makefile.in # /src/extensions/ /src/extensions/Makefile.in # /src/extraFunctions/ /src/extraFunctions/Makefile.in # /src/extraGtkFunctions/ /src/extraGtkFunctions/Makefile.in # /src/glade/ /src/glade/Makefile.in /src/glade/src /src/glade/*.bak # /src/openGLFunctions/ /src/openGLFunctions/Makefile.in # /src/pairsModeling/ /src/pairsModeling/Makefile.in # /src/panelModules/ /src/panelModules/Makefile.in # /src/renderingBackend/ /src/renderingBackend/Makefile.in # /src/renderingMethods/ /src/renderingMethods/Makefile.in # /tests/ /tests/Makefile.in /tests/core/Makefile.in /tests/core/*.pyc /tests/exports/*.png_diff /tests/exports/*.PNGlog /tests/exports/*.svg_diff /tests/exports/*.ui_diff /tests/exports/*.UIlog /tests/exports/*.svg /tests/exports/*.png /tests/exports/*.diff /tests/exports/*.log /tests/exports/tmp* /tests/exports/log v_sim-3.8.0/.gitlab-ci.yml000066400000000000000000000145001370110300500152610ustar00rootroot00000000000000image: ubuntu:latest stages: - build - deploy build: stage: build before_script: - export DEBIAN_FRONTEND=noninteractive - apt update && apt -y install make autotools-dev libtool intltool gfortran mesa-common-dev libglu1-mesa-dev libgtk-3-dev pkg-config libyaml-dev libarchive-dev libopenbabel-dev libnetcdf-dev gtk-doc-tools libgirepository1.0-dev python-gi-dev python-dev python-gi script: - ./autogen.sh - mkdir tmp - cd tmp/ - ../configure --with-strict-cflags --enable-gtk-doc --enable-introspection --with-xsf --with-cube --with-msym --with-openbabel --with-archives --with-etsf-file-format - make -j$(nproc) - make dist-bzip2 - make check artifacts: when: always paths: - tmp/Documentation/reference/html - "tmp/v_sim-dev*.tar.bz2" - tmp/Documentation/reference/test-suite.log - tmp/tests/core/test-suite.log # depending on your build setup it's most likely a good idea to cache outputs to reduce the build time # cache: # paths: # - "*.o" win32: stage: build before_script: - export DEBIAN_FRONTEND=noninteractive - apt update && apt -y install make dpkg-dev autotools-dev libtool intltool libglib2.0-dev-bin gtk-doc-tools gcc-mingw-w64-i686 g++-mingw-w64-i686 mingw-w64-tools gfortran-mingw-w64-i686 zip zstd xz-utils wget git - wget http://ftp.fr.debian.org/debian/pool/main/m/mingw-w64/mingw-w64-tools_7.0.0-4_amd64.deb - dpkg -i mingw-w64-tools_7.0.0-4_amd64.deb script: - wget http://repo.msys2.org/mingw/i686/mingw-w64-i686-gcc-libs-10.1.0-3-any.pkg.tar.zst - wget http://repo.msys2.org/mingw/i686/mingw-w64-i686-gmp-6.2.0-1-any.pkg.tar.xz - wget http://repo.msys2.org/mingw/i686/mingw-w64-i686-mpc-1.1.0-1-any.pkg.tar.xz - wget http://repo.msys2.org/mingw/i686/mingw-w64-i686-mpfr-4.0.2-2-any.pkg.tar.xz - wget http://repo.msys2.org/mingw/i686/mingw-w64-i686-libwinpthread-git-8.0.0.5906.c9a21571-1-any.pkg.tar.zst - wget http://repo.msys2.org/mingw/i686/mingw-w64-i686-pcre-8.44-1-any.pkg.tar.xz - wget http://repo.msys2.org/mingw/i686/mingw-w64-i686-glib2-2.64.3-1-any.pkg.tar.zst - wget http://repo.msys2.org/mingw/i686/mingw-w64-i686-libffi-3.3-1-any.pkg.tar.xz - wget http://repo.msys2.org/mingw/i686/mingw-w64-i686-cairo-1.16.0-1-any.pkg.tar.xz - wget http://repo.msys2.org/mingw/i686/mingw-w64-i686-freetype-2.10.2-2-any.pkg.tar.zst - wget http://repo.msys2.org/mingw/i686/mingw-w64-i686-harfbuzz-2.6.8-1-any.pkg.tar.zst - wget http://repo.msys2.org/mingw/i686/mingw-w64-i686-fontconfig-2.13.92-1-any.pkg.tar.zst - wget http://repo.msys2.org/mingw/i686/mingw-w64-i686-libiconv-1.16-1-any.pkg.tar.xz - wget http://repo.msys2.org/mingw/i686/mingw-w64-i686-bzip2-1.0.8-1-any.pkg.tar.xz - wget http://repo.msys2.org/mingw/i686/mingw-w64-i686-expat-2.2.9-1-any.pkg.tar.xz - wget http://repo.msys2.org/mingw/i686/mingw-w64-i686-lzo2-2.10-1-any.pkg.tar.xz - wget http://repo.msys2.org/mingw/i686/mingw-w64-i686-pixman-0.40.0-1-any.pkg.tar.xz - wget http://repo.msys2.org/mingw/i686/mingw-w64-i686-zlib-1.2.11-7-any.pkg.tar.xz - wget http://repo.msys2.org/mingw/i686/mingw-w64-i686-pango-1.43.0-3-any.pkg.tar.xz - wget http://repo.msys2.org/mingw/i686/mingw-w64-i686-fribidi-1.0.9-1-any.pkg.tar.xz - wget http://repo.msys2.org/mingw/i686/mingw-w64-i686-libthai-0.1.28-2-any.pkg.tar.xz - wget http://repo.msys2.org/mingw/i686/mingw-w64-i686-brotli-1.0.7-4-any.pkg.tar.xz - wget http://repo.msys2.org/mingw/i686/mingw-w64-i686-libdatrie-0.2.12-1-any.pkg.tar.xz - wget http://repo.msys2.org/mingw/i686/mingw-w64-i686-graphite2-1.3.14-1-any.pkg.tar.xz - wget http://repo.msys2.org/mingw/i686/mingw-w64-i686-libepoxy-1.5.4-1-any.pkg.tar.xz - wget http://repo.msys2.org/mingw/i686/mingw-w64-i686-gdk-pixbuf2-2.40.0-1-any.pkg.tar.xz - wget http://repo.msys2.org/mingw/i686/mingw-w64-i686-jasper-2.0.16-1-any.pkg.tar.xz - wget http://repo.msys2.org/mingw/i686/mingw-w64-i686-freeglut-3.2.1-1-any.pkg.tar.xz - wget http://repo.msys2.org/mingw/i686/mingw-w64-i686-libjpeg-turbo-2.0.5-1-any.pkg.tar.zst - wget http://repo.msys2.org/mingw/i686/mingw-w64-i686-libpng-1.6.37-3-any.pkg.tar.xz - wget http://repo.msys2.org/mingw/i686/mingw-w64-i686-libtiff-4.1.0-1-any.pkg.tar.xz - wget http://repo.msys2.org/mingw/i686/mingw-w64-i686-xz-5.2.5-1-any.pkg.tar.xz - wget http://repo.msys2.org/mingw/i686/mingw-w64-i686-gettext-0.19.8.1-9-any.pkg.tar.zst - wget http://repo.msys2.org/mingw/i686/mingw-w64-i686-zstd-1.4.5-1-any.pkg.tar.zst - wget http://repo.msys2.org/mingw/i686/mingw-w64-i686-atk-2.36.0-1-any.pkg.tar.xz - wget http://repo.msys2.org/mingw/i686/mingw-w64-i686-adwaita-icon-theme-3.36.0-1-any.pkg.tar.xz - wget http://repo.msys2.org/mingw/i686/mingw-w64-i686-hicolor-icon-theme-0.17-1-any.pkg.tar.xz - wget http://repo.msys2.org/mingw/i686/mingw-w64-i686-librsvg-2.48.7-1-any.pkg.tar.zst - wget http://repo.msys2.org/mingw/i686/mingw-w64-i686-libxml2-2.9.10-4-any.pkg.tar.zst - wget http://repo.msys2.org/mingw/i686/mingw-w64-i686-json-glib-1.4.4-1-any.pkg.tar.xz - wget http://repo.msys2.org/mingw/i686/mingw-w64-i686-shared-mime-info-2.0-1-any.pkg.tar.zst - wget http://repo.msys2.org/mingw/i686/mingw-w64-i686-gtk3-3.24.20-2-any.pkg.tar.zst - for i in *.pkg.tar.* ; do tar -xf $i; done - mv mingw32 V_Sim - export outdir=$PWD/V_Sim - for i in V_Sim/lib/pkgconfig/*.pc ; do sed -i "s;/mingw32;$outdir;" $i ; done - git clone https://github.com/yaml/libyaml - cd libyaml - ./bootstrap - ./configure --target=i686-w64-mingw32 --host=i686-w64-mingw32 prefix=$outdir - make -j3 install - cd - - ./autogen.sh - mkdir tmp - cd tmp - ../configure --host=i686-w64-mingw32 --target=i686-w64-mingw32 prefix=$outdir PKG_CONFIG_PATH=$outdir/lib/pkgconfig --with-yaml-path=$outdir - make install - cd - - zip -r V_Sim-win32.zip V_Sim artifacts: when: always paths: - V_Sim-win32.zip # run tests using the binary built before #test: # stage: test # script: # - cd tmp/tests/core # - make check pages: stage: deploy script: - mv tmp/Documentation/reference/html/ ${CI_PROJECT_DIR}/public/ - mv tmp/v_sim-dev*.tar.bz2 ${CI_PROJECT_DIR}/public/v_sim-dev.tar.bz2 - mv V_Sim-win32.zip ${CI_PROJECT_DIR}/public/ artifacts: paths: - public only: - master v_sim-3.8.0/AUTHORS000077700000000000000000000000001370110300500201112Documentation/authorsustar00rootroot00000000000000v_sim-3.8.0/COPYING000077700000000000000000000000001370110300500212302Documentation/licence.en.txtustar00rootroot00000000000000v_sim-3.8.0/ChangeLog000077700000000000000000000000001370110300500165452ChangeLog.enustar00rootroot00000000000000v_sim-3.8.0/ChangeLog.en000066400000000000000000001141021370110300500147770ustar00rootroot00000000000000 All changes leading to 3.8.x series.
  • Can now adjust the axis size.
  • Allow colorisation from command-ine using the name of a node property.
  • Implement loading of multiple scalar fields from command-line.
  • Add support to draw coloured maps on arbitrary surfaces, not just planes.
  • Switch to Gtk+3 by default and introspection build by default.
  • Scalar field loading is now asynchronous.
  • Use smooth transition when zooming or moving the camera.
  • Add a rotation method to move a group of nodes.
  • New plug-in to detect point group symmetries.
  • Add a fragment property to nodes, allowing to give a label and an id to a group of nodes.
  • Draw half pair when there is a neighbour by periodicity.
  • Draw cylinder pairs coloured by elements with the radii ratio (previously was always a 50/50 ratio).
  • Add unit length to pairs and element radii.
  • Add a command-line option to apply geometry differences.
  • All changes leading to 3.7.x series.
  • Correct an issue with pair rendering.
  • Add missing annotation for GObject Introspection.
  • Correct axes toggle in UI not working.
  • Correct crash when opening a scalar field from UI.
  • Correct CLI option --i-set not working.
  • Add support for older Glib than 2.28.
  • Draw black line around planes and at intersections.
  • Axes can be used to render the box basis-set and can be positioned anywhere.
  • Add a colour legend for the colourisation.
  • SVG output now clips its surface so that nodes partially inside are correctly rendered.
  • Add user defined shades in the resource file.
  • Resource file can be saved as XML file and merged with other XML files handled by V_Sim, like plane definitions…
  • The save resources dialog now propose the available .res files of the current directory as possibilities in the path completion.
  • The PythonGI plug-in logs stdout and stderr of the Python output.
  • Make the wire colouring depending on length applied only to the selected link and not to all.
  • Add a way to use other function than "lower than" to hide nodes on colourisation data.
  • Full support of the introspection for the core of V_Sim and for some parts of the GUI.
  • The PythonGI plug-in adds a panel to plot scalar field values along lines in the box using Matplotlib as rendering widget for curves.
  • Using GObject-Introspection, add a parser for CNT files from VASP.
  • The new BigDFT plug-in adds a panel to control and visualise parameters specific to BigDFT like the wavelet grids, the memory consumption, the pseudo-potential parameters... This plug-in is compatible with the linear version of the code. It can also be used to start or monitor a distant BigDFT run, retrieving density, potentials and wavefunctions.
  • Add natively a YAML parser, following the specifications from BigDFT.
  • Add key bindings ('Ctrl+v') on the rendering window to popup the orientation chooser.
  • Save prefered cameras in the resource file.
  • Add a search bar in the rendering window (Ctrl+f) to highlight nodes from their number.
  • Partial support of a possibility to scale the background image with camera settings.
  • Add resource entries to position the legend of the coloured maps.
  • Make the manual range of colourisation working per column and not for all as before.
  • Support the wavefunction file format of BigDFT thanks to a dedicated plug-in.
  • Add the possibility to draw arrows for forces directly in the atomic rendering mode without switching to the spin mode.
  • Implement a support for forces in ASCII and xyz file format.
  • Add a plug-in to handle compressed files (tar.gz, tar.bz2, ...).
  • Add key bindings ('n' and 'p') to load next or previous file from the browser list.
  • Add an option in the interactive dialog to hide highlighted or non-highlighted nodes.
  • Add support for recent files. Opened and saved files now appear in the recent list of Gtk file chooser.
  • Add an option to colourise nodes only if being in the manual range.
  • All changes leading to 3.6.x series.
  • Correct the missing texts in bitmap exportations.
  • Modify preview loading in open dialog to avoid grabbing of current file in case of long loading times.
  • Correct the id of nodes in measurement history and restrain to 6 values only.
  • Correct the not working spin modulus scaling.
  • Upgrade ABINIT plug-in for version 6.8.x.
  • Correct a crashing bug after several reload of a file with measurements when changing the colour.
  • Correct a memory corruption in the distance curve widget.
  • Make the drag action work again.
  • Correct pair build when using translations on command line.
  • Correct browser exportation of multi dataset files.
  • Correct the exportation crash with ATI proprietary drivers.
  • Display coordinates either in cartesian or reduced (see the configure panel).
  • Keep zoom adjustment between two files of different box size (see option in the geometry panel).
  • Modify the coloured map rendering to use adaptive mesh. The legend displays also the isoline values.
  • Add keybindings for the camera settings in the rendering window.
  • Add partial support for densities in XSF file format.
  • Add an exportation in ABINIT file format for the crystal part.
  • Add a transparency option for the coloured maps.
  • Begin to implement a support of GObject-Introspection, to allow scripting (Python, Javascript, ...).
  • The ABINIT interactive dialog now support different tolsym values and output the list of symmetries with their names.
  • Add a progress bar for file loading when the loading is too long. Add also the possibility to abort loading process.
  • V_Sim respects now the icon theme specification of FreeDesktop.
  • Demonstrate the Python scripting with the implementation of CNT file format of VASP.
  • Add keybindings for the rendering area (save, reload and open).
  • Add the possibility to export to any OpenBabel fileformats in command-line.
  • Modify the pair drawing to be able to use a per pair drawing method. Now, cylinder and wire pairs are available at the same time.
  • Add a calculation of g(r) and add a tab in the pair dialog to display it. Linear or log scale are available and filtering between kind of neighbours is also possible.
  • Sort pairs by distance.
  • Export a geometry difference in ASCII files as a keyword.
  • Add a keyword in ASCII files to store the total energy value of a system. This energy can be used to colourise paths.
  • Expand the XML file format generated by V_Sim to store the paths.
  • Use nicer message in the file browser when the loading is too long.
  • Add a command-line option to clamp coloured map values.
  • Add a full vectorial PDF export with Cairo.
  • Add the fog support in exportation in vectorial formats.
  • Add data colourisation support in exportation in vectorial formats.
  • Add a resource for the radius of the highlight mark.
  • Implement a legend showing the box lengths.
  • Implement an exportation in CIF (from OpenBabel) file format.
  • Implement a way to add two surfaces in one click, with good ressources for scalar fileds describing a wavefunction.
  • Remove the deprecated GTK curve in the pair dialog and replace it with the combobox for shades.
  • Add a path drawing tool.
  • Rename the panel "box" to "geometry" and store all geometry-related functions there, i.e. translation, expansion, units, paths...
  • All changes leading to 3.5.x series.
  • Correct a bug after changing the basis set with the upper limit of node id selectors.
  • Correct the position of the atom in case of spin rendering.
  • Correct compilation issues with GCC >= 4.4 (thanks to Thierry Thomas for his patch).
  • Correct a crashing bug in cube file format, when loading a file with a wrong atomic number.
  • Correct missing information on nodes after an image dump.
  • Correct a mistake in the legend when loading a new file with a varying number of nodes per element.
  • Correct a crash with the command line exportation.
  • Correct a wrong sort in the browser panel for multiset files.
  • Improve the output of the changelog in the about dialog window.
  • Correct mispositioned atoms in case of non-orthorhombic boxes in XSF files.
  • Add the reduced coordinates in case of peridic XYZ files.
  • Give a good position to the duplicated atoms for free BC.
  • Correct a blocking loop in the export dialog in case of wrong type detection.
  • Correctly associate colorisation to nodes in case of not sorted node in input file.
  • Correct several warnings, for the color selector widget, the rendering of text in the OpenGL area or the loading of XML value file.
  • Correct a wrong exportation of wire width greater than 10.
  • Avoid useless dialog when loading a value file with partial data.
  • Correct a masking bug for surfaces when the plane usage is unchecked.
  • Allow to parse XYZ files with additionnal columns different from a vibration file.
  • Correct a bug not showing the warning dialog box in case of error when exporting in image.
  • Correct a bug affecting the positions of atoms in Cube files when boxes are non-orthorombic.
  • Correct a crashing bug when pressing 'r' key without any saved camera.
  • Correct a bug for non orthorombic boxes using OpenBabel plug-in, thanks to patch sent by Atz Togo.
  • Correct a bug in ASCII file parsing when the files come from Macintosh or Windows.
  • Make the 'open with' action works under Windows.
  • Add a support for angles in the XML value files.
  • The tooltips in the browser now show the name of previous and next directories.
  • Draw a legend in SVG dump.
  • Add a way to change the basis set by pointing nodes as new vertices.
  • Declare in the resource file all parameters for the geometry diff (shape and size of the arrows, thresholds...).
  • Take into acount the boundary conditions when choosing the "up" direction. In case of surface, the y axis becomes the up axis.
  • Add a tab in the interactive dialog to show symmetry information, as calculated by ABINIT (space group, equivalent atoms...).
  • Add a key shortcut to switch between windows, mapped on "home" key.
  • Correct the visuals glitches when drawing cylindrical pairs.
  • Add phonons to ASCII file format.
  • Implement the phonon properties for solid, taking into account the imaginary parts of displacements and the q.r phase shift.
  • Add a clickable icon in the rendering window to access the saved cameras.
  • Implement a visualisation for the difference in positions using small arrows on nodes.
  • Add a phonon representation with vibration or arrows.
  • Add labels to nodes. These labels can be rendered as for the type or the node id for instance. They can be modified in the interactive dialog.
  • Implement the colourisation according to the coordinates.
  • Add a visualisation for the angles.
  • Add the support for labels for nodes in ASCII files.
  • Add a boundary condition keyword for ASCII files.
  • Parse a phonon column in the XYZ files.
  • Add 'previous' and 'next' buttons into the browser.
  • Add a tab for the phonon representation, listing available modes and displaying some parameters.
  • Modify the pick mouse buttons to easily access the measuring tool. Add also some button in the rendering window to set or unset measurements.
  • Add a scaling factor as post-process for the colourise tab.
  • Implement a legend displaying a frame with the atom names, number and representation.
  • Add a torus representation, in addition to existing ellipsoid and so on.
  • Add a hiding capability to the highlighted nodes.
  • Implement the support for several coloured maps.
  • Make the edges of the map planes smooth and highlight with a black line.
  • Add a drag and drop capability for file loading on the OpenGL area.
  • Modify the ASCII format to allow reduced coordinates and box definition based on vector lengths and angles.
  • Create a PDF/SVG exportation for the coloured maps.
  • Change the keys 's' and 'r' as a ring to save and restore the camera position, instead of saving only one value.
  • Add an exportation to XYZ file format.
  • Implement in the box subpanel a way to quickly switch distances between common units (bohr, angstroems...).
  • In the geometry modification panel, add a duplication possibility for the listed nodes.
  • Start the implementation of Python bindings for V_Sim. It is possible to open a rendering window and to load a file in it. It is also psossible to create a VisuData from scratch, creating elements and nodes by hand. The planes capability has also been ported to Python.
  • Code a plug-in for cube file support, commonly used by SIESTA and introduced by Gaussian.
  • Suppress the "highlight" tab in the interactive dialog. Move this capability to the pick tab using the control key to toggle highlight. Rework the relations between highlighted nodes and selected nodes. The highlight status can be changed in the listed nodes.
  • Add a column to print the date of files in the browser.
  • Extend the XML plane file to support various value fields in V_Sim. It is possible now to store in this XML file, the picked distances, the highlighted nodes, the values of created iso-surfaces.
  • Add the support for D3 posi files (concatenation of D3 files, adapted for movies).
  • Add non linear shades, logarithmic scale for zero-centred data and add the possibility to choose the isoline colour.
  • Reorganise a bit the pair dialog layout (the filter is now over the treeview and the management of links has been moved on the right).
  • All changes leading to 3.4.x series.
  • Correct the not working -d command line option when used in conjonction of the -u option.
  • Correct different memory leaks in the reading of input files or in the drawing routines.
  • Make the 'r' and 's' keys work again after the opening of a dialog from the rendering window.
  • Correct a crashing bug when nodes with persistent distances are removed.
  • Correct the automatic reload function that was broken in 3.4 series.
  • Correct wrong pathes in the browser when UTF8 characters are used.
  • Correct a jump of the camera in the interactive session when leaving pick mode with a right click and a drag.
  • Stop the interactive session also when the interactive dialog is closed by the window manager.
  • Disconnect signals for orientation chooser when the dialog is destroyed..
  • Solve a loading problem when using the filechooser in spin mode.
  • Correct a lack of cylinder pair drawing under specific conditions.
  • Correct some "assertion fails" error when loading new files.
  • Make the behaviour of "all elements" selection in the element tab works for atomic parameters in spin rendering.
  • Correct the tab character problem in ASCII files.
  • Correct a bug in the pair dialog when the sort is used. Modifications in the treeview are then inconsistent.
  • Correct a bug that makes the rendering disappear in the walker mode.
  • Correct a bug when expanding the nodes that could create several nodes at one place.
  • Correct a bug when the selection is zero pixel wide.
  • Correct a bug in the move interactive dialog that prints a wrong number of selected nodes.
  • Correct the error while reading the resources of cylinder pairs with the minimum value.
  • Add the missing exportation of the stipple pattern for the wire pairs.
  • Correct several Critical Warnings in drawDataOnNode() in the interactive dialog window.
  • Correct a crash in the interactive window when the current VisuData is deleted.
  • Correct wrong permissions on the directory created in the quit dialog.
  • Correct a bug in the subpanel menu.
  • Change the way to find a module name from its file name.
  • Correct a linking problem with variable in .h on MacOS.
  • Avoid V_Sim crash when a pixmap exportation is required on X server using AIGLX and a version of GLX prior to 1.3.
  • 3.4.0.1: correct a segfault in the Abinit plugin.
  • 3.4.0.2: correct a possible segfault when a VisuData object is freed.
  • 3.4.0.2: add an XML filter to the plane file dialog.
  • 3.4.0.2: correct a bug in the colour selection of surfaces.
  • 3.4.0.2: import the debian directory from official repository and update it for 3.4.0 (made for 3.3.3 by Debian).
  • 3.4.0.3: change the location of legal dir to data dir.
  • 3.4.0.3: only install the plugins related files when plugins are compiled. Also move the images to the pixmap dir.
  • Add the axes in the SVG output.
  • Correct bugs (preview widget, ABINIT bindings) and complete translation.
  • Add the capability to draw bitmap pictures on the background.
  • Change the zoom behaviour to none when the box is expanded.
  • Add a rectangular selection in the pick window and enable group moving in the move window.
  • Add iso-lines for the coloured map.
  • Add the support of vectors (for forces or spin) in the XSF plug-in.
  • Add a possibility to link with the ABINIT parser to read its input file. This depends on modifications not yet in ABINIT official releases. They may enter in ABINIT 5.6 series. The data sets are supported and when the geometry builder is used, the created box is shown. Current limitation is when nband must be computed since no pseudo-potential files are loaded and thus nelect is not known.
  • Add a tool to automatically compute range distance for first neighbours.
  • Implement the possibility to draw pattern wires for pairs and box.
  • Early implementation of a plug-in adding XSF reading capabilities. Atomic positions are only available yet.
  • The coloured map can now be drawn in logarithmic scale.
  • The XYZ parser has been modified to allow to read animation files. The browser panel has been modified accordingly to show the different node sets in one file.
  • Activate once again the stereo rendering (was disabled from version 3.0.0 because of lack of hardware for testing). The stereo parameters, like the eyes distance, can be tuned in the OpenGL panel.
  • Add keyboard support in the rendering window in observe mode. Page-Up and Page-Down keys are used for zoom and perspective. Also add the 's' key for 'save current camera position'. Key 'r' is now used to restore this saved position.
  • Add the possibility of a non-uniform mesh for the scalar-field representation.
  • Basic support for SVG exportation of box and nodes.
  • Allow changes of coordinates in the pick table (as for spin characteristics or colour data). Add a possibility to write information on selected or all nodes.
  • Better integration of OpenBabel library, with the use of the atom symbol instead of the atom labels, also use the OpenBabel colour and radius when the atom is not known by V_Sim. Try to reproduce as much as possible the handling of pairs as described in the OpenBabel input files.
  • Add a filter in the pairs dialog to show only pairs of interest (i.e. pairs containing one given element).
  • Implement a way to duplicate the box following a fractional ratio in the case of periodic boxes. Adapt all capabilities to take that extension into account (extend planes and coloured maps, duplicate colourisation data, draw box extension...).
  • Separate the box & axes subpanel into two subpanels and move the translations from the interactive window to the new box subpanel. Also add in this subpanel the gestion of box duplication.
  • Enable the box duplication on command-line and also the coloured map.
  • Modify the geometry tab in the interactive window to allow to add or remove nodes.
  • Add a support for GtkGlExt as an alternative to the built-in OpenGL widget.
  • Add a preview in the open dialog box, displaying the box and the elements with the current camera position.
  • Implement the 'smooth and edge' rendering mode, displaying a line around polygons.
  • Make the hiding of surfaces by planes smooth, adding polygons to avoid edgy borders.
  • Improve the parse speed of the browser and add a multiple matching for rendering method with several type files (spin and positions can be loaded in one clic).
  • Use the XDG specification for the location of the home config directory. The old $HOME/.v_sim is still supported.
  • Change the surface resources in the panel: each surfaces can has a name or not. In the latter case, the resources of the surface are private to this surface (all changes do not affect the other surfaces). Merge the two property dialogs into one (previously change current and change all). Add a special add button in the panel to add several surfaces at once (use the same than in the build dialog). Make the remove button remove all surfaces of a scalar field file before removing the file itself.
  • Implement the masking effect of planes on surfaces with a simple implementation (not smooth borders).
  • Make the masking effect of planes selective per surface or per element (see the new masking column in surface panel and the check box in the element panel).
  • Add a capability to print all distance of a pair (see the pair dialog and the 'length column). Distance values are now editable in the treeview.
  • Add an option in the browser panel to read the directories recursively. Also makes the double-click check the file entry in the list and implement the capability to browse several directories at one time.
  • Add a new widget to choose the orientation, using an orthogonal basis set, the box coordinates or the spherical basis set.
  • All changes leading to 3.3.x series.
  • Correct the implementation of the translation inside windows with a non-unitary ratio aspect.
  • Correct a memory leak during image exportation with the XLib.
  • Correct a memory leak in the save dialog window.
  • Add a man page.
  • Use a correct format for the v_sim.ini file in Windows.
  • Correct a bug making D3 file read impossible on Windows.
  • Correct a bug when selected the root directory.
  • Correct a crashing bug on MacOSX and Intel cards on Linux.
  • Make the normalisation of the colorisation stay during automatic reloading.
  • Correct a bug in the coordinate conversion for non-orthogonal boxes (both in structure and scalar field).
  • Correct a bug in D3 file parsing.
  • Correct an internal error dealing with to much signal connection to the VisuData objects.
  • Add a rendering shape as points for atoms to be able to plot grid position or to increase speed when a huge quantities of elements is drawn.
  • Implement a binary format for the spin rendering.
  • Some improvements in windows handling: it is possible to raise the command panel from the rendering window for instance.
  • Small improvements and redesign in the save parameters and resources window: it is possible to export resources related to rendered object only.
  • End of implemntation of separable subpanels. Their size and positions are now changeable and can be exported to the parameter file.
  • Upgrade the build system to be able to build plugins for Windows.
  • Change the transparency handling of isosurfaces to avoid to compute the order of them when the camera is moving.
  • Several bug corrections, including error on reading resources related to isosurfaces, wrong computation of normal vector of isosurfaces, automatic reload of file...
  • Improvements done on the gestion of the properties of isosurfaces. Names are editable and can be passed on command line when option -v is used. Change also the behavior of selecting buttons in that subpanel to be able to change properties of all surfaces of one unique file.
  • Save in the plane file in XML the rendering state of each plane.
  • Upgrade translation file for future version 3.3.
  • Implementation for the reading of scalar fields encoding with the Nanoquanta specification v1.3. Only real scalar fields (i.e. densities) without spin informations are currently supported. From this point basic support for specification v1.3 is operational.
  • Addition of a subpanel to draw colored planes representing the variations of a given scalar field. A colored scale is also available.
  • Density files and surface files can be automatically loaded and all drawing capabilities are available from the command line.
  • Colors and material values are more coherent between elements and surfaces.
  • Commandline capabilities for new fonctionalities associated to iso-surfaces.
  • Support of density/potential files directly in the isosurfaces panel, without need to use the convert tool. Implementation also of the merge of several surfaces directly in this panel.
  • Adding remove and add of surfaces on the fly in the isosurfaces panel. The add action is available only for density/potential files.
  • Complete support for detaching panels and associate them in several dialogs.
  • Implementation of the modulus handling in spin rendering. Spin shapes can be scaled according to the modulus read in the spin input file.
  • Total implementation of OpenBabel support. All format readable with OpenBabel are loadable in V_Sim.
  • Creation of a tool to retrieve values attached to nodes, such as colorisation informations or orientation and modulus for spin rendering. In this former rendering mode, these value are editable on the fly.
  • Some changements in the saving of resources of spin rendering. It is recommended to overwrite resources files since three keywords are now obsolete.
  • Some interface enhancements.
  • Adding a basic support for plugins. Shared libraries that matched the interfaces required by V_Sim located in the installation directory and in the user one (${HOME}/.v_sim) are automatically loaded on startup.
  • Partial implemntation of NANOQUANTA v1.2 specifications for atomic positions (plugin).
  • Usage of OpenBabel library for file loading (plugin), but nothing is actually functional.
  • Basic fuunctionnality to detach tabs from the command panel.
  • Creation of a simple OpenGL widget to avoid the hack used since v3.0 version to render OpenGL surfaces. Doing it, the backing store support has been removed and replaced by a complete gestion of the 'expose' events.
  • Improvements in the spin rendering mode where it is now possible to choose between, always spin, hide spin with a null modulus or draw atomic shapes instead.
  • Support of the atomic rendering within the spin one.
  • Addition of an elipsoid shape for both spin and atomic rendering.
  • Support for distance measurements in the default mode (restricted before to the pick / observe window).
  • All changes leading to 3.2.x series.
  • Correct a reading bug in the convert dialog for isosurfaces, when a potential/density file is read.
  • Correct a crashing bug using box and axes when no file is rendered.
  • Correct a crashing bug in the isosurface panel, when playing a list with only one entry.
  • Correct a crashing bug in the colorization panel.
  • Correct a bug with 64bits machines that disables the camera rotation in the observe window.
  • Correct a mispel in the French translation.
  • A warning message dialog has been added when the quit button is clicked. This message is optional and can be hidden with a key in the config file named 'v_sim.par' or by checking a button in this window.
  • Adding a functionnality to save or open informations about planes. The data type used is simple XML. The geometry, the hidden state and the color of each plane are stored. Only the drawn options is not saved.
  • Implement the constrained movements along x, y and z axis in the geometry builder.
  • Choose automatically the action associated to a tab when one is selected in the interactive window.
  • Implementing a new action to move the nodes. Using drag and drop, it is possible to move nodes in the plane of the screen.
  • Adding a ascii export with the option to output or not hidden nodes.
  • A new tab has been added in the planes subpanel to allow to change automatically the distance from origin (as it is done in the browser subpanel to chow several files one after an other).
  • Creating a new action to mark atoms. It draws some frame around clicked nodes to easily follow some.
  • Internal modifications to suppress global pointers (especially in opengl.c and visu_data.c).
  • VisuData is switched to a GObject and signals about OpenGL, Nodes and Elements are moved from visu_object to it.
  • Through the selection dialog, distances that are picked are label on screen and stay printed as long as required.
  • Add a possibility to hide some nodes in the colorization subpanel, depending on values in the associated data file.
  • Enable the choice of rendering mode per drawn elements, e.g. atoms are drawn smoothly wereas isosurfaces are rendered through wireframe (requires GTK+2.6).
  • Add a custom value to tune the power of used lights and two preset values for lights : one with the defaukt light and another with four lights, customized for spin rendering.
  • Adding a cycling mode in the browser. It is now possible to cycle once, to go on and back and still the classic cycle in loop.
  • Rebuild of the configuration files dialog: switching to GtkComboBoxes and adding auto-completion.
  • Improve French translation.
  • Extend minimal pick behavior (i.e. default mode) to allow distance measurements.
  • In pick/observe session, the little marks that identify references in pick mode, are now persistant during observe mode until the pick/observe session is closed.
  • Correct bugs 2 and 75.
  • The X11 backend mixed with the GTK interface is not supported anymore.
  • Modify the main interface : buttons related to the rendered file moved to the bottom bar on the rendering window.
  • Switch to a GtkComboBox for the list to select subpanel.
  • Update French translation.
  • Adding a status bar in the rendering window. This allows to show some basic informations as the description of the rendered file, the number of drawn nodes... This is only working if the rendering backend of this window is GTK (not X11).
  • Adding a minimal pick function on the third button as a default mode.
  • GUI improvements in the browser sub-panel and display of currently browse directory.
  • Adding JPG and PNG export image format, using GdkPixbuf.
  • GUI changings of the dump dialog to allow to tune some parameters for different file formats (e.g. the compression ratio in JPEG format). Adding the possibility to choose the export size for images and to add automatically the file extension if not is specified.
  • Changing default behavior (previously no action) to observe mode.
  • Adding a check box in the dataFile sub-panel to automatically load data file with the same name than the one of the rendered file.
  • Adding some preset shades in the dataFile sub-panel.
  • Allowing the possibility to use dataFile methods through the command line.
  • Displaying the color scale (in the dataFile sub-panel) even when several channels are changing if only one column is read.
  • Adding the choice of masquing algorithm in the plane sub-panel (using union or intersection).
  • Adding the possibility to specify in the command line some box translation.
  • Not translated in english. Not translated in english.
    v_sim-3.8.0/ChangeLog.fr000066400000000000000000001604361370110300500150170ustar00rootroot00000000000000 Ensemble des changements amenant à la branche 3.8.x.
  • Possibilité de changer la taille des axes.
  • Utilisation d'une propriété des nœuds comme source de colorisation depuis la ligne de commande.
  • Possibilité de charger plusieurs champs scalaires depuis la ligne de commande.
  • Support des cartes de couleurs projetées sur des surfaces arbitraires.
  • Utilisation de Gtk+3 par défaut et compilation si possible de l'introspection.
  • Le chargement des champs scalaires est maintenant asynchrone.
  • Ajout de transitions lors de changements de la camera.
  • Possibilité de tourner un ensemble de nœuds.
  • Nouveau grefon pour détecter les symétries.
  • Ajoute une propriété de fragment aux nœuds. Cette propriété permet de donner un label et un identifiant à un ensemble de nœuds.
  • Dessine des demi-liaisons pour les nœuds ayant un voisin par periodicité.
  • Dessine les liaisons cylindriques en mode « couleur des éléments » en suivant le ratio des rayons (précédemment, un ratio 50 / 50 était appliqué).
  • Ajoute l'unité de longueur aux liaisons et aux rayons..
  • Ajoute une option de ligne de commande pour charger des différences de géométrie.
  • Ensemble des changements amenant à la branche 3.7.x.
  • Correction d'un problème de rendu des liaisons.
  • Addition d'annotations manquantes pour l'introspection.
  • Correction du rendu ou non des axes dans l'interface utilisateur.
  • Correction d'un plantage lors de l'ouverture d'un champ scalaire.
  • Correction du fonctionnement de l'option --i-set.
  • Support des bibliothèques Glib antérieures à 2.28.
  • Dessine des lignes noires autour des plans et à leurs intersections.
  • Les axes peuvent maintenant aussi représenter la base de la boîte et être positionnés n'importe où dans la fenêtre de rendu.
  • Ajoute une légende des couleurs pour la colorisation.
  • L'exportation SVG prend correctement en charge les nœuds partiellement visible aux bords de la zone de rendu.
  • Permet l'ajout de définition de dégradés dans le fichier ressource.
  • Les ressources peuvent maintenant être enregistrées dans un fichier XML qui peut être identique aux autres fichiers XML générés par V_Sim (comme les plans…).
  • La fenêtre pour sauvegarder les ressources propose désormais aussi les fichiers en .res du répertoire courant dans la liste déroulante de propositions.
  • Le greffon de scriptage Python affiche la sortie d'erreur et la sortie standard des scripts python.
  • La coloration des liaisons en fonction de la distance est maintenant effectué par lien et non plus pour tous les liens en même temps.
  • Ajout de la possibilité de définir des fonctions pour le masquage des noeuds en fonction des données de colorisation.
  • Support complet de la partie moteur et rendu de V_Sim pour l'introspection, ainsi qu'un support partiel de l'interface utilisateur.
  • Le greffon PythonGI ajoute un nouvel onglet permettant de tracer les valeurs d'un champ scalaire suivant une ligne. Le rendu du graphe est fait par Matplotlib.
  • En utilisant l'introspection, les fichier CNT de VASP deviennent lisibles.
  • Le nouveau greffon BigDFT ajoute un onglet permettant de contrôler et de visualiser les paramètres spécifiques à BigDFT comme les grilles ondelettes, la consommation mémoire, les paramètres des pseudo-potentiels... Ce greffon est compatible avec la version linéaire du code. Il permet aussi de démarrer ou de superviser un calcul distant de BigDFT, tout en rapatriant la densité, les potentiels, les fonctions d'ondes...
  • Ajoute un parser natif YAML en suivant le format définit par BigDFT.
  • Ajoute des raccoursis clavier ('Ctrl+v') à la fenêtre de rendu permettant d'ouvrir le sélecteur d'orientation.
  • Sauve les préférences liés aux caméras dans le fichier ressources.
  • Ajoute une barre de recherche à la fenêtre de rendu (Ctrl+f) permettant de mettre en évidence les noeuds à partir de leur numéro.
  • Support partiel de la possibilité pour l'image de fond de suivre la caméra de visualisation (zoom).
  • Ajoute des entrées dans le fichier ressources permettant de positionner et de mettre à l'échelle la légende des cartes colorées.
  • Rend le choix de normalisation manuelle effectif par colonne dans l'onglet de colorisation.
  • Support du format de fichier de fonctions d'ondes de BigDFT par un greffon dédié.
  • Ajoute la possibilité de tracer des flèches pour les forces directement dans le rendu atomique sans passer par le rendu spin.
  • Implémente le support des forces dans les formats ASCII ou xyz.
  • Ajoute un greffon prenant en charge les formats compressés (comme tar.gz ou tar.bz2).
  • Ajoute des raccoursis claviers (« n » et « p ») pour charger les fichiers suivants ou précédent dans la liste du navigateur.
  • Ajoute la possibilité de choisir entre les noeuds mis en évidence ou ceux non mis en évidence lors du masquage dans la fenêtre interactive.
  • Implémente le support des fichiers récents. Les fichiers ouverts et les exportations sont maintenant listés dans la partie fichiers récents du navigateur de fichiers.
  • Ajoute la possibilité de ne coloriser les noeuds que si leur valeur se trouve dans la plage de valeurs choisies.
  • Ensemble des changements amenant à la branche 3.6.x.
  • Corrige l'absence de texte lors d'exportation en image.
  • Modifie l'affichage de la prévisualisation dans la fenêtre d'ouverture pour éviter de prendre le fichier courant quand le chargement est long.
  • Corrige la numérotation des noeuds dans l'historique de mesure et limite la liste à 6 valeurs seulement.
  • Corrige le fonctionnement de la mise à l'évchelle des spins en fonction du module.
  • Corrige un bug crashant dans la gestion du rendu couleur après plusieurs rechargement d'un fichier avec des mesures.
  • Mise à niveau du greffon ABINIT pour être compatible avec les versions 6.8.x.
  • Corrige une corruption mémoire dans le widget de dessin des distribution de longeurs de liaisons.
  • Rétablit le fonctionnement de la fonction de glisser-déposer.
  • Corrige le dessin des liaisons lorsque des translations sont utilisées sur la ligne de commande.
  • Corrige l'exportation dans le navigateur de fichiers pour les fichiers à multiple jeu de données.
  • Corrige le problème de crash lors de l'exportation en image avec les drivers ATI propriétaires.
  • Affiche les coordonnées en valeurs cartésiennes ou en valeurs réduites dans la fenêtre de rendu (cf. le panneau de configuration).
  • Conserve le niveau de zoom entre deux fichiers si la boîte change de taille (cf. l'option du panneau de géométrie).
  • Modifie les cartes colorées pour utiliser un maillage adaptatif. La légende affiche aussi désormais des repères pour les valeurs d'isoligne..
  • Ajoute des raccoursis claviers pour les paramètres de la caméra de la zone de rendu..
  • Ajoute un support partiel des densités aux format XSF.
  • Ajoute une exportation au format ABINIT pour la partie cristal.
  • Ajoute une option de transparence pour le rendu des cartes colorées.
  • Début de support de GObject-Introspection, permettant le scriptage (en Python, Javascript, ...).
  • La fenêtre relative à ABINIT propose maintenant de choisir différentes valeurs de tolsym et liste l'ensemble des symétries du système avec leur nom.
  • Ajoute une barre de progression lors du chargement d'un fichier trop long ainsi qu'un moyen d'annuler un chargement en cours.
  • V_Sim respecte maintenant la spécification FreeDesktop relative aux icônes.
  • Démonstration des possibilités de scriptage Python au travers du support des fichiers CNT de VASP.
  • Ajoute des raccoursis claviers à la fenêtre de rendu (exporter, recharger et ouvrir).
  • Ajoute la possibilité en ligne de commande d'exporter dans les formats connus d'OpenBabel.
  • Modifie la fenêtre de dialogue des liaisons pour permettre la dénition liaison par liaison des méthodes de rendu. On peut maintenant utiliser en même temps les liaisons filaires et les liaisons cylindriques.
  • Ajoute le calcul d'un g(r) et ajoute une interface pour la visualiser dans la fenêtre des liaisons. Les échelles liénaire et logarithmique sont disponibles, ainsi qu'un filtrage sur les types de liaisons.
  • Trie les liaisons par longueur.
  • Exporte les différences de géométrie dans le format ASCII en temps que mot-clef.
  • Ajoute un mot-clef dans le format ASCII pour stocker une valeur d'énergie. Cette valeur est utilisée pour coloriser les chemins.
  • Étend le format XML de V_Sim en ajoutant les chemins.
  • Montre un message plus clair dans le navigateur de fichiers lorsque le parcours du disque est trop long.
  • Ajoute une option de ligne de commande pour borner les valeurs pour la carte de coleurs.
  • Ajoute un format d'exportation purement vectoriel en PDF grâce à Cairo.
  • Ajoute le support du brouillard dans les exportations vectorielles.
  • Ajoute la colorisation par fichier de données lors d'une exportation vectorielle.
  • Ajoute une ressource pour modifier le rayon de la sphère de mise en valeur.
  • Implémente une légende donnant la taille de la boîte.
  • Implémente une exportation au format CIF au travers d'OpenBabel.
  • Implémente l'ajout automatique de deux surfaces en un clic dans le cas d'un fichier de fonctions d'ondes. La colorisation est aussi choisie astucieusement.
  • Utilise les dégradés pour la colorisation des liaisons en fonction de la longueur.
  • Ajoute une fonction de visualisation de chemins.
  • Renomme l'onglet « boîte » en « géométrie » pour y mettre toutes les actions relatives à la géométrie, i.e. les translations, l'expansion, les unités, les chemins...
  • Ensemble des changements autour de la branche 3.5.x.
  • Corrige un bug affectant la borne supérieur des sélecteur d'identifiants de noeuds après un changement de base.
  • Corrige la position des atomes en mode de rendu spin.
  • Corrige les erreurs de compilation signalées par GCC >= 4.4 (merci à Thierry Thomas pour son patch).
  • Corrige un crash lors du chargement d'un fichier cube avec des numéros atomiques hors limites.
  • Corrige l'absence d'affichage des informations sur les noeuds après une exportation en image.
  • Corrige un problème de mise à jour de la légende lors du chargement d'un fichier avec un nombre variable de noeuds par éléments.
  • Corrige un crash lors d'une exportation en ligne de commande.
  • Corrige une erreur de classement dans le navigateur de fichiers pour les fichiers à multiple jeu de données.
  • Améliore l'affichage des modifications dans la fenêtre à propos.
  • Corrige le positionnement des atomes dans le cas de boîtes non ortho-rhombic dans des fichiers XSF.
  • Ajoute les coordonnées réduites dans le cas des fichiers XYZ périodiques.
  • Positionne correctement les atomes dupliqués en conditions aux bords libres.
  • Corrige une boucle bloquante dans la fenêtre de dialogue d'exportation dans le cas d'un choix erronée de format de fichier.
  • Associe correctement la colorisation aux noeuds dans le cas où ceux-ci ne sont aps triés dans le fichier d'entrée.
  • Corrige plusieurs messages d'avertissement concernant en vrac, le sélecteur de couleur, l'affichage de textes dans la zone de rendu OpenGL ou le chargement de fixhiers XML de données.
  • Empêche l'exportation de largeurs de liaison supérieures à 10.
  • Évite d'afficher des avertissements au chargement d'un fichier de données contenant des informations partielles.
  • Réaffiche correctement les surfaces masquées lorsque les plans ne sont plus utilisés.
  • Permet le chargement de fichiers XYZ ayant des colonnes supplémentaires dans un format différent de celui d'un fichier de vibration.
  • Corrige une erreur empêchant l'ouverture d'une fenêtre de dialogue lors d'une erreur d'exportation.
  • Corrige une erreur dans la lecture des fichiers cube, sur la position des atomes, lorsque les boîtes ne sont pas orthorombiques.
  • Corrige une erreur de segmentation déclenchée par la touche « r » alors qu'aucune caméra n'a été sauvegardée.
  • Corrige la définition des super-cellules dans le cas non-orthorombic pour le greffon OpenBabel. Merci à Atz Togo pour son patch.
  • Corrige une mauvaise lecture des fichiers ASCII sous Macintosh et Windows.
  • Corrige les problèmes de fichiers liés à l'utilisation de l'action « ouvrir avec » sous Windows.
  • Ajoute le support des angles dans les fichiers de valeurs XML.
  • Les bulles d'aide du navigateur montrent les répertoires précédents et suivants.
  • Dessine une légende lors de l'exportation SVG.
  • Ajoute un moyen de changer la base en pointant des atomes comme nouveaux sommets.
  • Déclare dans le fichier ressources tous les paramètres de réglage du diff géométrique (forme et longueur des flèches, seuils...).
  • Prend en compte les conditions aux bords pour choisir correctement le « haut » de la boîte (l'axe y est l'axe du nord dans les fichiers surface).
  • Ajoute un onglet dans la fenêtre interactive donnant accès aux informations de symétries, calculées par ABINIT (groupe d'espace, atomes équivalents...).
  • Ajoute un raccoursis clavier utilisant la touche « home » pour passer d'une fenêtre à l'autre.
  • Corrige les défauts visuels sur le rendu des liaisons cylindriques.
  • Ajoute un support des phonons dans le format ASCII.
  • Implémente l'animation des phonons dans les solides, en prenant en compte la partie imaginaire des déplacements atomiques et la phase introduite par the produit q.r.
  • Apparition d'une icône cliquable dans la fenêtre de rendu donnant accès aux positions sauvegardées de la caméra.
  • Implémente une façon de visualiser les différences de positions entre deux fichiers en affichant des petites flèches sur les noeuds..
  • Ajoute le support d'étiquettes associées aux noeuds. Ces étiquettes peuvent être affichées comme sont affichés les types ou les numéros des noeuds. On peut modifier ces étiquettes dans la fenêtre de dialogue de sélection.
  • Modifie le format pour permettre l'ajout d'étiquettes sur les noeuds.
  • Ajoute des boutons « précédent » et « suivant » dans le navigateur.
  • Ajoute une représentation des phonons grâce à une visualisation des vibrations ou grâce à des petites flèches.
  • Implémente la colorisation en fonction des coordonnées.
  • Ajoute une représentation des angles.
  • Ajoute le support des étiquettes dans les fichiers ASCII.
  • Ajoute un mot clef de condition aux bords pour les fichiers ASCII.
  • Lit une colonne pour les phonons dans les fichiers XYZ.
  • Ajoute un onglet pour la repésentation des phonons, la liste des modes disponibles et quelques paramètres de réglage.
  • Change la sélection à la souris pour faciliter l'accès à l'outil de mesure. Ajoute aussi quelques boutons dans la fenêtre de rendu pour mesurer ou annuler.
  • Ajoute un facteur d'échelle à la représentation des noeuds dans l'onglet de colorisation.
  • Implémente une légende affichant un cadre avec le nom des éléments, leur nombre et leur représentation.
  • Ajoute une repésentation torique en plus des représentations existantes (ellipse, cube...).
  • Ajoute une possibilité de masquer les noeuds non mis en évidence.
  • Implémente le support pour plusieurs carte colorées en même temps.
  • Dessine les bords des plans colorés de façon lisses avec un surlignage noir.
  • Ajoute une capacité de glisser-déposer à la zone de rendu OpenGL pour charger un fichier.
  • Modifie le format de fichier ASCII pour permettre de rentrer les coordonnées en unités réduites et de définir la boîte en suivant la longueur. des vecteurs de base et leurs angles.
  • Crée une exportation pour les plans de coupe colorés, soit au format PDF, soit au format SVG.
  • Modifie le comportement des touches 's' et 'r' pour sauvegarder ou restaurer la position de la camera pour fonctionner comme un anneau à la place de ne conserver qu'une unique position.
  • Ajoute une exportation au format XYZ.
  • Implémente dans l'onglet « boîte » la possibilité de changer rapidement les distances entre les noeuds suivant des unités habituelles (bohr, angströms...).
  • Dans l'onglet de modification de géométrie, ajoute une possibilité de duplication des noeuds listés.
  • Début d'écriture de fichiers de liaison pour l'appel de V_Sim depuis Python. Il est possible de créer une fenêtre de rendu, d'y charger un fichier ou encore de construire directement des éléments, des noeuds ou un système atomique. Les plans sont aussi fonctionnels.
  • Implémentation d'un greffon pour le support des fichiers Cube de Gaussian, utilisés entre autre aussi dans SIESTA.
  • Extension du format de fichier XML gérant les plans. Celui-ci peut maintenant stocker d'autre valeur interne à V_Sim, comme les noeuds mis en évidence, les valeurs des iso-surfaces crées ou les distances mesurées.
  • Ajout du support des fichiers D3 posi (concaténation de fichiers D3, utilisé par exemple pour la réalisation de films).
  • Suppression de l'onglet des « mises en évidences », fonction transférée dans l'onglet de sélection grâce à l'ajout de la touche Control. Meilleure interaction entre les noeuds sélectionnés et les noeuds mis en évidence (possibilité de passer de l'un à l'autre).
  • Ajout d'une possibilité de tri dans la liste des noeuds sélectionnés (tri sur l'identifiant ou sur le genre).
  • Ajout d'une colonne affichant la date des fichiers dans le navigateur.
  • Ajout des dégradés non linéaires, d'une échelle logarithmique adaptée aux données centrées autour de zéro et ajout de la possibilité de choisir la couleur des isolignes.
  • Réorganisation partielle de la fenêtre de dialogue des liaisons (le filtre a été déplacé en haut et les boutons d'ajout et de suppression sont maintenant à droite de la liste des liaisons).
  • Ensemble des changements autour de la branche 3.4.x.
  • Corrige le disfonctionnement de l'option -d lorsqu'elle est utilisée en même temps que l'option -u.
  • Corrige plusieurs fuites mémoires intervenant durant la lecture de fichiers d'entrée ou dans certaines routines de dessin.
  • Rend les touches 's' et 'r' à nouveau opérantes après l'ouverture d'une fenêtre de dialogue depuis la fenêtre de rendu.
  • Corrige un crash quand on supprime des noeuds avec des marques de distances.
  • Corrige la fonction de rechargement automatique, cassée dans les versions 3.4.x.
  • Corrige l'affichage des chemins dans le navigateur quand des caractères UTF-8 sont utilisés.
  • Corrige un saut de la caméra dans le mode interactif lors d'un clic droit avec déplacement.
  • Termine aussi une session interactive lorsque la fenêtre de dialogue est fermée par l'intermédiaire du gestionnaire de fenêtre.
  • Déconnecte les signaux dans le dialogue de choix de l'orientation lorsque l'object est détruit.
  • Modifie la fenêtre de sélection de spin pour corriger un problème de validation.
  • Corrige un problème de dessin des liaisons cylindriques sous certaines conditions.
  • Supprime plusieurs "assertion fails" au chargement d'un nouveau fichier.
  • Rend fonctionnel le choix « tous les éléments » dans l'onglet « éléments » pour les paramètres atomiques en mode rendu de spins.
  • Corrige le problè du caractè tabulation dans les fichiers ASCII.
  • Corrige un disfonctionnement dans la fenêtre des liaisons lorsque la fonction de trie est utilisée. Les modifications effectuées dans le treeview sont alors incohérentes..
  • Corrige un problème dans le mode marcheur pour la visualisation où la boîte disparaît parfois.
  • Corrige l'expansion des noeuds qui amène dans certains cas à dupliquer le même noeud plusieurs fois au même endroit.
  • Corrige le comportement inattendu quand on sélectionne une zone de 0 pixel de côté.
  • Corrige le nombre affiché de noeuds sélectionnés dans l'onglet de modification de la géométrie.
  • Corrige l'erreur à la lecture du fichier de ressources quand le rayon des liaisons cylindrique est égal au rayon minimum.
  • Implémente l'exportation des motifs pour les liaisons filaires.
  • Corrige plusieurs Critical Warnings dans la routine drawDataOnNode() dans la fenêtre d'interaction.
  • Corrige un crash quand les données courantes disparaissent dans la fenêtre de dialogue interactive.
  • Corrige les permissions lors de la création du répertoire de cionfiguration de V_Sim.
  • Corrige un bug dans l'affichage du menu des onglets.
  • Change la façon de trouver le nom d'un module depuis son nom de fichier pour prendre en charge les modules du type toto.1.0.1.so.
  • Corrige un problème à l'édition des liens sous MacOS à cause de variables dans les .h.
  • Contourne le crash lors de l'exportation en image pour les serveur X fonctionnant avec AIGLX et une version de GLX antérieure à la 1.3.
  • 3.4.0.1 : corrige une erreur de segmentation dans le greffon pour ABINIT.
  • 3.4.0.2 : corrige une erreur de segmentation lorsqu'un objet VisuData est détruit.
  • 3.4.0.2 : ajoute un filtre XML sur les fichiers dans le sélecteur pour les plans.
  • 3.4.0.2 : corrige un bug dans le sélecteur de coleurs pour les surfaces.
  • 3.4.0.2 : importe le répertoire debian depuis l'archive officielle et le modifie pour l'adapter à la version 3.4.0 (fait à l'origine pour la 3.3.3).
  • 3.4.0.3 : fait pointer le répertoire legaldir sur datadir.
  • 3.4.0.3 : modifie l'installation des greffons pour éviter de copier des fichiers quand les greffons ne sont pas compilés. Déplace aussi les images dans le répertoire pixmapsdir.
  • Ajoute les axes dans l'export SVG.
  • Corrige quelques bugs (la vignette de prévisualisation, le chargeur d'ABINIT) et termine la traduction.
  • Implémente la possibilité d'afficher des images en fond de la zone de rendu.
  • Modifie le fonctionnement du zoom lors de l'extension d'une boîte, la vue reste maintenant la même.
  • Ajoute le tracé de lignes d'iso-valeurs sur la carte de couleurs.
  • Implémentation d'une sélection de groupe ainsi que d'un déplacement de groupe dans la fenêtre d'actions interactives.
  • Amélioration du greffon XSF. Il est maintenant possible de lire les vecteurs associés aux n~uds (pour dessiner les forces ou des spins).
  • Il est possible de compiler V_Sim avec le parser d'ABINIT, permettant ainsi de lire directement les fichiers d'entrée de celui-ci. Pour cela, il faut une version modifiée du code ABINIT qui devrait être publiquement disponible à partir des versions 5.6.x. Les datasets sont pris en compte ainsi que le système de construction de géométrie. Dans ce cas, la boîte résultante est affichée. La limitation actuelle est quand nband doit être calculé. Comme les fichiers de pseudo-potentiels ne sont pas chargés, il n'est pas possible alors de connaître nelect.
  • Ajoute un système permettant d'estimer un encadrement pour les liaisons premiers voisins d'un système.
  • Possibilité de dessiner des liaisons filaires et la boîte avec un motif.
  • Implémentation minimale d'un greffon lisant les fichiers de position XSF.
  • Ajout d'une possibilité de tracé des plans colorés en utilisant une échelle logarithmique.
  • Modification du parseur XYZ pour lire les fichiers d'animation. Le navigateur a été modifié en conséquence pour afficher les différentes positions dans un même fichier.
  • Ré-implémentation de la vision stéréo (supprimée depuis la version 3.0.0). Les paramètres, comme l'écartement des yeux, sont réglables dans le panneau OpenGL.
  • Ajoute le support du déplacement de la caméra au clavier dans le mode d'observation de la fenêtre de rendu. Les touches Page-Suivante et Page-Précédente servent pour le zoom. La touche « s » permet de « sauvegarder en mémoire la position courante de la caméra ». En contre-partie, la touche « r » permet de revenir dans la dernière position sauvegardée.
  • Implémentation d'un maillage non uniforme pour la grille d'un champ scalaire.
  • Support minimal de l'exportation en SVG. Pour le moment, la boîte et les n~uds seulement sont dessinés.
  • Modification possible des coordonnées dans le tableaux des n~uds sélectionnés (comme ça l'était pour les informations de spin ou les données de colorisation). Ajoute la possibilité d'afficher sur les atomes des informations.
  • Meilleure intégration de la bibliothèque OpenBabel, grâce à l'utilisation du symbole atomique à la place de son étiquette. Utilisation aussi des couleurs et du rayon atomique d'OpenBabel quand l'élément n'est pas déjà connu de V_Sim. Enfin, les liaisons sont tracées dans la mesure du possible en suivant les indications du fichier d'entrée.
  • Ajout d'un filtre dans la fenêtre des liaisons permettant de n'afficher que celles contenant une espèce chimique particulière.
  • Implémentation d'une façon de répliquer la boîte dans le cas de systèmes périodiques. Adaptation des autres fonctionnalités de V_Sim à la duplication (agrandissement des plans et des cartes de couleurs, réplication des informations de colorisation, tracé pointillé des boîtes répliquées...).
  • Séparation de l'onglet boîte & axe en deux onglets séparés. Déplacement aussi de la gestion des translations périodiques dans le nouvel onglet boîte. Ajout enfin dans ce nouvel onglet de la gestion de la réplication.
  • Ajoute la capacité d'utiliser en ligne de commande la duplication ainsi que les cartes de couleur.
  • Modification de l'onglet de géométrie dans la fenêtre d'actions de la souris pour permettre l'ajout ou la suppression de n~uds.
  • Support de GtkGlExt comme alternive à l'utilisation du widget interne OpenGL.
  • Ajoute une prévisualisation dans la fenêtre d'ouverture d'un fichier. La boîte et les éléments sont simplement dessinés dans l'état courant de la caméra.
  • Implémentation d'un mode de rendu « lisse souligné » affichant un trait autour des polygones.
  • Rend lisse le masquage par les plans des surfaces en ajoutant des polygones où nécessaire pour éviter d'avoir des bords en dentelles.
  • Améliore la vitesse de chargement du navigateur et ajoute une possibilité de chargement en un clic pour les méthodes de rendu à multiple fichiers comme le rendu de spin.
  • Utilise maintenant la spécification XDG pour l'emplacement des fichiers de configuration personnels. Le précédent repertoire $HOME/.v_sim est toujours lu néanmoins.
  • Modifie la gestion des ressources des surfaces dans l'onglet : chaque surface peut maintenant ne plus avoir de nom. Dans ce cas, ses propriétés ne sont pas partagées avec d'autres surfaces. Les deux fenêtres de dialogue permettant de changer les ressources (anciennement « modifier la surface courante » et « modifier toutes ») ont été fusionnées. Un boutton particulier a été ajouté dans l'onglet pour permettre l'ajout de plusieurs surfaces en même temps (comme dans le dialogue de construction). Le boutton supprimer commence maintenant par retirer toutes les surfaces d'un champ scalaire avant de retirer le champ lui-même.
  • Première implémentation de l'effet de masquage des plans sur les surfaces.
  • Rend l'effet masquant des plans sélectif par surface et par élément (voir la colonne ad hoc de l'onglet surface ou la case à cocher de l'onglet élément).
  • Les distances sont modifiables directement dans la liste dans la fenêtre de gestion des liaisons. Une colonne a été ajoutée permettant d'afficher par type de liaison les distances.
  • Ajout d'une option dans l'onglet de navigation permettant de visualiser récursivement le contenu d'un répertoire. Ajout aussi de la capacité de naviguer dans plusieurs répertoires en même temps.
  • Implémentation d'un nouveau dialogue permettant de choisir l'orientation de trois façons différentes : l'une dans un repère orthonormal, une autre dans le repère de la boîte ou enfin en suivant les coordonnées sphériques.
  • Ensemble des changements ayant aboutis à la branche 3.3.x.
  • Correction de la position de la caméra quand la fenêtre n'a pas un rapport d'aspect unitaire.
  • Correction d'une fuite de mémoire lors de l'exportation en image avec la XLib.
  • Correction d'une fuite mémoire dans le dialogue de sauvegarde des préférences.
  • Ajout d'une page de manuel.
  • Utilisation d'un format correct pour le fichier v_sim.ini sous Windows.
  • Correction d'un bug empêchant la lecture des fichiers D3 sous Windows.
  • Correction d'un bug lorsque le répertoire racine est choisi (dans le navigateur par exemple).
  • Correction d'un bug empêchant le lancement de V_Sim sur MacOSX et sur Linux avec carte Intel.
  • Correction d'un bug dans l'outil de colorisation où le choix de la normalisation n'était pas conservé lors d'un chargement automatique.
  • Correction d'un bug affectant les boîtes non orthogonales (aussi bien la structure atomique que les champs scalaires).
  • Correction d'un bug dans la lecture des fichiers D3.
  • Corrige un erreur interne impliquant un surnombre d'association de signaux aux objects VisuData.
  • Ajout d'un rendu sous forme de points des éléments en mode atomique pour afficher une grille ou obtenir un rendu plus rapide.
  • Utilisation d'un format binaire pour la description de l'orientation des spins.
  • Meilleure gestion des fenêtres entre elles : la fenêtre de commande est mise peut être placée au-dessus à partir de la fenêtre de rendu par exemple.
  • Légère refonte de la fenêtre de sauvegarde des ressources : on peut maintenant sauvegarder uniquement les ressources en rapport avec l'objet dessiné.
  • Fin de l'implémentation de la fonction de détachement des onglets. Leur position et leur taille sont maintenant modifiables et enregistrées dans le fichier de paramètres.
  • Modification des scripts de construction pour permettre la compilation des greffons sous Windows.
  • Modification de la gestion de la transparence des iso-surfaces, possibilité de ne recalculer celle-ci qu'à la fin d'un mouvement et non tout le long.
  • Plusieurs corrections de bug (lecture des ressources des iso-surfaces, calcul des normales aux surfaces, rechargement automatique d'un fichier).
  • Amélioration de la gestion du nom des surfaces et des propriétés de couleurs associées (passage en ligne de commande du nom des surfaces à créer dans l'option -v). Modification dans ce même onglet du comportement des boutons de sélection pour permettre d'appliquer les changements à l'ensemble des surfaces d'un même fichier.
  • Enregistrement de l'option de rendu d'un plan dans le fichier XML.
  • Mise à jour des fichiers de traduction pour la future version 3.3. La traduction française est complète (ou suposée).
  • Implémentation du support des champs scalaires encodés selon le format de fichier défini par Nanoquanta. Pour le moment, seul les champs scalaires réels (densités) sans information de spin sont chargeables. La lecture de fichiers Nanoquanta v1.3 est désormais possible.
  • Ajout d'un onglet permettant le dessin de plans colorés en fonction d'un champ scalaire chargé. Une légende de l'échelle de couleur est aussi dessinée.
  • Chargement automatique de fichiers de densité ou de surface et passage des options de dessin des surfaces en ligne de commande.
  • Gestion plus centralisée et uniforme des couleurs et des informations sur la lumière.
  • Support des fonctionnalités en rapport avec les iso-surfaces par la ligne de commande.
  • Ajout du support des fichiers de potentiel et de densité directement dans l'onglet de gestion des isosurfaces. Le passage par l'outil de conversion n'est plus nécessaire. Implémentation aussi de la fonction permettant d'afficher plusieurs surfaces de fichiers/sources différents, directement dans l'onglet.
  • Ajout de la fonction d'ajout/suppression d'isosurfaces à la volée dans l'onglet surfaces. La fonction d'ajout ne fonctionne que pour les fichiers de densité/potentiel.
  • Support complet des onglets détachables et associables.
  • Prise en charge du module dans le mode de rendu spin permettant de tracer des champs vectoriels avec toutes leurs informations (direction et norme). Les objets dessinés en mode spin sont alors mis à l'échelle en fonction de la valeur du module lue dans le fichier d'entrée de spin.
  • Fin de l'implémentation du la couche d'interface avec la bibliothèque OpenBabel. Tous les formats supportés en lecture par OpenBabel sont maintenant lisible dans V_Sim.
  • Création d'un outils pour visualiser et manipuler les données associées aux noeuds comme les informations de colorisation ou encore la direction et le module en mode spin. Dans ce mode, ces valeurs sont modifiables à la volée.
  • Changement dans l'enregistrement des ressources liées au mode de spin. Il est conseillé de réenregistrer ses fichiers de ressources car trois mots-clefs sont devenus obsolètes.
  • Quelques améliorations de l'interface.
  • Ajout du support de greffons. Ceux-ci se chargent automatiquement dès qu'ils se trouvent dans le répertoire d'installation ou dans le répertoire utilisateur ${HOME}/.v_sim.
  • Implémentation partielle de la norme NANOQUANTA v1.2 permettant le chargement de positions atomiques (greffon).
  • Interfaçage avec la bibliothèque OpenBabel, mais rien n'est chargé pour le moment (greffon).
  • Début d'implémentation de la fonctionnalité de détachement des onglets.
  • Remplacement du hack de la zone de rendu OpenGL par une implémentation minimale d'un widget OpenGL. Ceci à pour conséquence la suppression du support du backingstore, remplacé par une gestion des événements « expose ».
  • Amélioration de l'option de rendu spin « hiding-mode », permettant de choisir entre l'affichage permanent des spins, le masquage des spins de moment nul ou le rendu atomique pour ces derniers.
  • Support du rendu atomique en plus du rendu spin.
  • Ajout en mode spin et en mode atomique d'une forme élipsoïdale.
  • Support continu de la mesure de distances (aussi bien en mode courant que dans la fenêtre d'observation).
  • Ensemble des changements ayant donné lieu à la branche 3.2.x.
  • Correction d'un bug de lecture dans la fenêtre de dialogue de convertion des isosurfaces, lorsqu'un fichier de densité/potentiel est chargé.
  • Correction d'un plantage lors de l'utilisation des données liées à la boîte et aux axes alors qu'aucun fichier n'est chargé.
  • Correction d'un plantage dans l'onglet des isosurfaces lorsqu'on fait défiler la liste alors qu'elle n'a qu'une unique entrée.
  • Correction d'un plantage dans l'onglet de colorisation.
  • Correction d'un bug des machines 64bits empêchant la rotation de la caméra dans la fenêtre d'observation.
  • Correction d'une faute d'orthographe dans la traduction française.
  • Implémentation d'une fenêtre de dialogue d'avertissment au moment de quitter. Cette fenêtre est désactivable par une préférence du fichier « v_sim.par » ou en cochant une case dans cette fenêtre.
  • Ajout d'un fonction d'import-export des données de plans. Le format retenu est un XML simple contenant la définition de la géométrie du plan (normale et distance à l'origine), son état de masquage et sa couleur. Elle contient pas toutefois si le plan est affiché ou non.
  • Implémentation des mouvements contraints selon les axes x, y ou z dans l'outils de déplacement des noeuds.
  • Choix automatique de l'action associée à un onglet quand celui-ci est sélectionné dans la denêtre d'actions interactives.
  • Création d'une nouvelle action permettant de déplacer les noeuds. On peut déplacer les noeuds en glisser-déposer dans le plan de l'écran.
  • Ajout d'une exportation an ASCII avec le choix de sortir ou non les noeuds visibles.
  • Addition d'une interface dans l'onglet des plans permettant le déplacement automatique du plan sélectionné (à la manière du défilement automatique dans l'onglet navigateur).
  • Création d'une nouvelle action pour marquer les noeuds (que l'on souhaite suivre...). Cette action dessine des cadres autours des éléments.
  • Modifications internes supprimant les pointers globaux, notamment dans opengl.c et visu_data.c.
  • VisuData est maintenant un GObject et héberge les signaux OpenGL, Nodes et Elements ; signaux auparavant déclarés dans visu_object.
  • Dans la fenêtre de sélecion, les distances repérées restent affichées sur la fenêtre de rendu et ce aussi longtemps que désiré.
  • Ajout d'une action de masquage des éléments dans l'onglet de colorisation. Ce masquage est piloté par les valeurs lues dans une colonne du fichier de données associé.
  • Possibilité de choisir par élément dessiné le type de rendu (lisse, « fil de fer »...). Par exemple, on peut choisir de dessiner les atomes de façon lisse alors que les iso-surfaces sont affichées en fil de fer (nécessite GTK+2.6).
  • Ajout d'une valeur permettant d'ajuster la puissance des lumières utilisées dans l'onglet OpenGL. De plus, deux éclairages prédéfinis sont proposés : celui, classique, de la lumière unique et un nouveau, plus adapté au mode de rendu de spins, composé de quatre lumières.
  • Ajout d'un mode de parcours de la liste des fichiers dans le navigateur. On peut désormais ne lire la liste qu'une fois, en boucle aller-retour ou classiquement en boucle simple.
  • Refonte de la boîte de dialogue des fichiers de configuration : passage à des GtkComboBox et ajout de la complétion automatique.
  • Mise à jour de la traduction française.
  • Amélioration du mode minimal de sélection (c'est-à-dire le mode par défaut) en permettant les mesures de distances.
  • Lors d'une session de sélection/observation, les petites marques servant à identifier les références (en mode sélection), sont maintenant persistantes durant le mode d'observation et ce jusqu'à ce que la session soit terminée.
  • Correction des bugs 2 et 75.
  • Le support en X11 de la fenêtre de rendue en même temps que l'interface principale en GTK n'est plus supporté.
  • Modifications de l'interface principale : les boutons en rapport avec le fichier rendu ont été déplacés dans la la barre de la fenêtre OpenGL.
  • Passage à une GtkComboBox pour la gestion de la liste des onglets accessibles.
  • Amélioration de la traduction française.
  • Ajout d'une barre d'état dans la fenêtre de rendu, permettant d'afficher des informations diverses dont le commentaire associé au fichier rendu par exemple. Ceci ne fonctionne qu'avec un rendu GTK.
  • Ajout d'un mode pick minimal sur le troisième bouton comme comportement par défaut.
  • Modification de l'interface dans l'onglet de navigation, et ajout du répertoire courant affiché.
  • Ajout de l'exportation en JPEG et PNG via l'utilisation des GdkPixbuf.
  • Modification de l'interface d'exportation pour permettre le choix d'options selon les formats de fichiers (qualité JPEG...), une case à cocher permettant d'ajouter automatiquement l'extension si besoin et une réglage possible de la taille de l'image à exporter.
  • Passage au mode « observe » par défaut et de façon continue.
  • Ajout d'une option de chargement automatique des fichiers de colorisation.
  • Ajout de dégradés de couleurs prédéfinis dans l'onglet de colorisation.
  • Passage en ligne de commande des options de colorisation (fichier, colonne de données, dégradé prédéfini...).
  • Affichage de l'échelle de couleurs (onglet colorisation), même si plusieurs canaux varient tant que cette variable ne fait intervenir qu'une seule colonne.
  • Ajout du choix du masquage pour dans l'onglet des plans : union ou intersection. Ceci permet d'obtenir des volumes convexes.
  • Passage des options de translation en ligne de commande.
  • Ce fichier répertorie les changements introduits lors des versions permettant d'aboutir à la version 3.1. Cette version est marquée par l'incorporation du tracé d'isosurfaces à partir du code de Luc Billard VISUALIZE.
  • Correction des bugs 68, 69, 70, 71, 72, 73 et 74.
  • Passage par défaut du bouton « enregistrer » dans l'exportation.
  • Correction des bugs 61, 62, 63, 64, 65, 66 et 67.
  • Ajout d'un bouton qui recharge le répertoire courant dans l'onglet de navigation.
  • Changement du texte du bouton de fermeture de la fenêtre d'observation.
  • Amélioration de la traduction fr.
  • Autres modifications mineures.
  • Support de multiples fichiers en entrée (exemple : un fichier de position et un fichier d'orientation des spins).
  • Affichage dans la fenêtre de sélection des atomes des coordonnées du fichier d'entrée et non des coordonnées utilisées par V_Sim pour le rendu.
  • Ajout d'une fonctionnalité de tracé de plans. Les plans permettent de masquer les noeuds des zones de la boîte.
  • Transfert des paramètres qui ont une tête de ressources vers le fichier de ressources.
  • Améliorer le système de lecture et d'écriture des fichiers de paramètres et de ressources.
  • Ajout du rendu de spin (représentation de flèches), lecture des fichiers d'entrée au travers de l'interface GTK ou sur la ligne de commande. le rendu des spins est effectué par des flèches (cylindriques ou cubiques), les modifications de la géométrie des flèches sont possibles. Il y a aussi une coloration des spins en fonction de l'orientation.
  • Incorporation du tracé d'isosurfaces. Ces isosurfaces peuvent être obtenues à partir de fichier décrivant un champ scalaire par l'intégration de l'outil pot2surf.
  • Ajout d'une lecture des chemins au démarrage sous Windows : lecture d'un fichier v_sim.ii dans le répetoire courant ou dans le répertoire c:\windows.
  • Les ressources des liaisons (couleurs, taille...) sont gérées par type de liaisons et non plus de façon globale (avec tout de même une valeur par défaut).
  • Passage à une vue GtkTreeView pour la liste des liaisons (permet la sélection multiple pour appliquer des changements à plusieurs types de liaisons en même temps, permet le tri...).
  • Gestion de la couleur des liaisons au travers d'une liste déroulante qui permet le stockage des couleurs déjà rencontrées.
  • Support de la translation des noeuds à l'intérieur de la boîte pour les boîtes périodiques.
  • Ajout d'une zone pour stocker des informations liées à la méthode de rendu.
  • Onglet « éléments », support des couleurs déjà rencontrées au travers d'une liste déroulante.
  • Onglet « éléments », passage à une GtkComboBox pour la sélection des éléments et nettoyage du code en rapport avec la sélection des éléments par nom et non par pointeur.
  • Onglet « éléments », ajout d'une ressources permettant de masquer ou non tous noeuds d'un même élément.
  • Onglet « navigateur », ajout d'un filtre des fichiers affichés.
  • Onglet « coloration extérieure », affichage de la valeur min et de la valeur max associée au fichier chargé.
  • Onglet « plans », création d'un onglet pour gérer la création, la modification et les opérations sur les plans.
  • Onglet « configuration », ajout d'un facteur multiplicatif sur les GtkSpinButtons travaillant sur une grandeur physique.
  • Cette version a pour entry le support complet de la documentation pour l'API des fonctions basiques de V_Sim ; ainsi que la mise à jour du site web : VisuObject, visu_tools, visu_commandLine, visu_basic, visu_elements, visu_data, opengl, visu_rendering, visu_configFile, visu_extension, visu_pairs, visu_dump, visu_pickMesure.
  • Ce fichier répertorie les changements introduits lors des versions permettant d'aboutir à la version 3.0.
  • Correction dans le code d'écriture des fichiers tiff et gif sous Windows : les fichiers étaient ouverts en écriture seule (comprendre ascii simple) et la libc échappait tous les caractères 0x0a en rajoutant le caractère 0x0d devant. Il fallait ouvrir ces fichiers avec le flag 'b' pour demander une écriture en binaire (merci aux lecteurs de LinuxFR pour cette explication).
  • Corrections dans la partie d'initialisation d'OpenGL dépendant de la plateforme pour permettre le fonctionnement en ligne de commande sous Windows.
  • Correction des bugs 25, 26 et 28.
  • Ajout des entêtes de licence en tête des fichiers *.c et *.h.
  • Déplacement du fichier v_sim.par dans $(prefix)/etc/v_sim.
  • Mise en place d'une documentation automatique de l'API grâce à gtk-doc, 20% environ des fonctions sont documentées.
  • Internationalisation de toutes les chaînes de V_Sim (sauf les chaînes de débuggage) et traduction d'une petite partie de l'interface en français.
  • Passage à un système géré par automake/autoconf et conformation aux recommendations GNU pour le contenu des packages.
  • Modification mineur du logo : la barre verticale qui entoure « SIM » est remplacée par un arc de cercle.
  • Découpage du fichier opengl.c et isolement des fonctions dépendant du système d'exploitation et du serveur graphique (principalement les appels GLX ou des événements graphiques). Une interface simplifiée de la gestion des événements X est implémentée dans visu_windowInterface.h ainsi qu'une interface nécessaire pour l'initialisation d'OpenGL dans visu_OSInterface.h.
  • Ajout d'un support GTK pour la fenêtre de rendu.
  • L'exportation en image se fait maintenant par un changement de contexte OpenGL vers un rendu indirect en mémoire et non plus par l'intermédiaire d'une fenêtre. Ainsi le problème de recouvrement qui nécessitait d'avoir la fenêtre non masquée pour l'exportation est résolu.
  • Portage sous systèmes Win32 et mise à jour du fichier readme. Le support du backingstore ne fonctionne pas sous Windows. Le dessin du nom des axes est aussi cassé sur cette plateforme.
  • Correction des bugs 1, 21 et 22.
  • Ajout d'une fonction de coloration des atomes en fonction de valeurs passées dans un autre fichier.
  • Ajout d'une fonction expérimentale de rotation de la caméra sur elle-même (modifications dans le fichier de ressources de la clef opengl_theta_phi qui devient opengl_theta_phi_omega).
  • Ajout d'un format de fichier pour le rendu atomique noté « xyz ». Il n'y a pas de définition de la boîte et le nom des atomes vient avant les trois coordonnées.
  • Affichage de la licence et des auteurs en police monospace dans la fenêtre « à propos ».
  • Correction des bugs 7, 8, 9, 11, 12, 14, 15, 16, 17, 18, 19, 20.
  • Ajout des textes pour les auteurs et le readme dans la fenêtre de dialogue d'information et réorganisation de l'ordre des onglets.
  • Ajout d'une partie install et uninstall dans le Makefile.
  • Passage des variables de configuration par l'intermédiaire du Makefile.
  • Changement des répertoires des fichiers par défaut : la licence, les exemples et autre documentation sont dans $(prefix)/share/doc/v_sim, les fichiers de configurations et les images dans $(prefix)/share/v_sim.
  • Implémentation complète des liaisons cylindriques et remise de leur choix possible dans l'interface graphique.
  • Correction d'un manque de rafraîchissement de l'interface des liaisons lorsqu'un nouveau fichier de resources est lu.
  • Correction des bugs 3, 4 et 5.
  • Ajout d'icônes spécifiques pour l'ensemble des fenêtres de l'application.
  • Ajout d'une aide textuelle quand on tape v_sim --help.
  • Suppression des entrées de développement dans l'interface graphique (méthode de rendu des spins et liaison cylindriques).
  • Suppression de la gestion de la liste des raccoursis vers les fichiers de resources dans l'onglet de configuration.
  • Changement de tout les noms de visu_gl_gtk vers v_sim.
  • v_sim-3.8.0/Documentation/000077500000000000000000000000001370110300500154365ustar00rootroot00000000000000v_sim-3.8.0/Documentation/Makefile.am000066400000000000000000000005211370110300500174700ustar00rootroot00000000000000v_simlegal_DATA = \ authors \ licence.en.txt \ licence.fr.txt \ readme \ pot2surf_help man1_MANS = v_sim.1 v_sim.1: $(srcdir)/v_sim.cli.xml $(srcdir)/man.xsl xsltproc $(srcdir)/man.xsl $(srcdir)/v_sim.cli.xml > v_sim.1 EXTRA_DIST = $(v_simlegal_DATA) $(man1_MANS) man.xsl v_sim.cli.xml CLEANFILES = v_sim.1 SUBDIRS = reference v_sim-3.8.0/Documentation/authors000066400000000000000000000016611370110300500170520ustar00rootroot00000000000000*Luc Billard* Now on retirement Creator (all versions until 2.2) *Damien Caliste* damien.caliste (AT) cea.fr Developer and maintainer *Olivier D'Astier* dastier (AT) iie.cnam.fr Contributor (spin rendering method, portage of isosurfaces code from an older version) *Aurlien Lherbier* aurelien.lherbier (AT) cea.fr Contributor (non-linear mesh grid for densities, isolines) *Jrmy Blanc* Jeremy.Blanc (AT) bvra.etu.upmf-grenoble.fr Contributor (phonon visualisation) *Simon Plans* simon.planes (AT) laposte.net Contributor (loop selection visualisation) *Thomas Jourdan* Thomas.Jourdan (AT) cea.fr Contributor (torus representation) *Yoann Ratao* Ratao.yoann (AT) hotmail.fr Contributor (scale drawing) *Tristan Berthelot* tristan.berthelot (AT) isen.fr Contributor (GI integration) *Trung Vu* trungvp2000 (AT) yahoo.fr Contributor (adaptive colour map) v_sim-3.8.0/Documentation/licence.en.txt000066400000000000000000000543111370110300500202060ustar00rootroot00000000000000 FREE SOFTWARE LICENSING AGREEMENT CeCILL ======================================== Notice ------ This Agreement is a free software license that is the result of discussions between its authors in order to ensure compliance with the two main principles guiding its drafting: - firstly, its conformity with French law, both as regards the law of torts and intellectual property law, and the protection that it offers to authors and the holders of economic rights over software. - secondly, compliance with the principles for the distribution of free software: access to source codes, extended user-rights. The following bodies are the authors of this license CeCILL (Ce : CEA, C : CNRS, I : INRIA, LL : Logiciel Libre): Commissariat l'Energie Atomique - CEA, a public scientific, technical and industrial establishment, having its principal place of business at 31-33 rue de la Fdration, 75752 PARIS cedex 15, France. Centre National de la Recherche Scientifique - CNRS, a public scientific and technological establishment, having its principal place of business at 3 rue Michel-Ange 75794 Paris cedex 16, France. Institut National de Recherche en Informatique et en Automatique - INRIA, a public scientific and technological establishment, having its principal place of business at Domaine de Voluceau, Rocquencourt, BP 105, 78153 Le Chesnay cedex. PREAMBLE -------- The purpose of this Free Software Licensing Agreement is to grant users the right to modify and redistribute the software governed by this license within the framework of an "open source" distribution model. The exercising of these rights is conditional upon certain obligations for users so as to ensure that this status is retained for subsequent redistribution operations. As a counterpart to the access to the source code and rights to copy, modify and redistribute granted by the license, users are provided only with a limited warranty and the software's author, the holder of the economic rights, and the successive licensors only have limited liability. In this respect, it is brought to the user's attention that the risks associated with loading, using, modifying and/or developing or reproducing the software by the user given its nature of Free Software, that may mean that it is complicated to manipulate, and that also therefore means that it is reserved for developers and experienced professionals having in-depth computer knowledge. Users are therefore encouraged to load and test the Software's suitability as regards their requirements in conditions enabling the security of their systems and/or data to be ensured and, more generally, to use and operate it in the same conditions of security. This Agreement may be freely reproduced and published, provided it is not altered, and that no Articles are either added or removed herefrom. This Agreement may apply to any or all software for which the holder of the economic rights decides to submit the operation thereof to its provisions. Article 1 - DEFINITIONS ------------------------ For the purposes of this Agreement, when the following expressions commence with a capital letter, they shall have the following meaning: Agreement: means this Licensing Agreement, and any or all of its subsequent versions. Software: means the software in its Object Code and/or Source Code form and, where applicable, its documentation, "as is" at the time when the Licensee accepts the Agreement. Initial Software: means the Software in its Source Code and/or Object Code form and, where applicable, its documentation, "as is" at the time when it is distributed for the first time under the terms and conditions of the Agreement. Modified Software: means the Software modified by at least one Contribution. Source Code: means all the Software's instructions and program lines to which access is required so as to modify the Software. Object Code: means the binary files originating from the compilation of the Source Code. Holder: means the holder of the economic rights over the Initial Software. Licensee(s): mean(s) the Software user(s) having accepted the Agreement. Contributor: means a Licensee having made at least one Contribution. Licensor: means the Holder, or any or all other individual or legal entity, that distributes the Software under the Agreement. Contributions: mean any or all modifications, corrections, translations, adaptations and/or new functionalities integrated into the Software by any or all Contributor, and the Static Modules. Module: means a set of sources files including their documentation that, once compiled in executable form, enables supplementary functionalities or services to be developed in addition to those offered by the Software. Dynamic Module: means any or all module, created by the Contributor, that is independent of the Software, so that this module and the Software are in two different executable forms that are run in separate address spaces, with one calling the other when they are run. Static Module: means any or all module, created by the Contributor and connected to the Software by a static link that makes their object codes interdependent. This module and the Software to which it is connected, are combined in a single executable. Parties: mean both the Licensee and the Licensor. These expressions may be used both in singular and plural form. Article 2 - PURPOSE ------------------- The purpose of the Agreement is to enable the Licensor to grant the Licensee a free, non-exclusive, transferable and worldwide License for the Software as set forth in Article 5 hereinafter for the whole term of protection of the rights over said Software. Article 3 - ACCEPTANCE ---------------------- 3.1. The Licensee shall be deemed as having accepted the terms and conditions of this Agreement by the occurrence of the first of the following events: - (i) loading the Software by any or all means, notably, by downloading from a remote server, or by loading from a physical medium; - (ii) the first time the Licensee exercises any of the rights granted hereunder. 3.2. One copy of the Agreement, containing a notice relating to the specific nature of the Software, to the limited warranty, and to the limitation to use by experienced users has been provided to the Licensee prior to its acceptance as set forth in Article 3.1 hereinabove, and the Licensee hereby acknowledges that it is aware thereof. Article 4 - EFFECTIVE DATE AND TERM ----------------------------------- 4.1. EFFECTIVE DATE The Agreement shall become effective on the date when it is accepted by the Licensee as set forth in Article 3.1. 4.2. TERM The Agreement shall remain in force during the whole legal term of protection of the economic rights over the Software. Article 5 - SCOPE OF THE RIGHTS GRANTED --------------------------------------- The Licensor hereby grants to the Licensee, that accepts such, the following rights as regards the Software for any or all use, and for the term of the Agreement, on the basis of the terms and conditions set forth hereinafter. Otherwise, the Licensor grants to the Licensee free of charge exploitation rights on the patents he holds on whole or part of the inventions implemented in the Software. 5.1. RIGHTS OF USE The Licensee is authorized to use the Software, unrestrictedly, as regards the fields of application, with it being hereinafter specified that this relates to: - permanent or temporary reproduction of all or part of the Software by any or all means and in any or all form. - loading, displaying, running, or storing the Software on any or all medium. - entitlement to observe, study or test the operation thereof so as to establish the ideas and principles that form the basis for any or all constituent elements of said Software. This shall apply when the Licensee carries out any or all loading, displaying, running, transmission or storage operation as regards the Software, that it is entitled to carry out hereunder. 5.2. entitlement to make CONTRIBUTIONS The right to make Contributions includes the right to translate, adapt, arrange, or make any or all modification to the Software, and the right to reproduce the resulting Software. The Licensee is authorized to make any or all Contribution to the Software provided that it explicitly mentions its name as the author of said Contribution and the date of the development thereof. 5.3. DISTRIBUTION AND PUBLICATION RIGHTS In particular, the right of distribution and publication includes the right to transmit and communicate the Software to the general public on any or all medium, and by any or all means, and the right to market, either in consideration of a fee, or free of charge, a copy or copies of the Software by means of any or all process. The Licensee is further authorized to redistribute copies of the modified or unmodified Software to third parties according to the terms and conditions set forth hereinafter. 5.3.1. REDISTRIBUTION OF SOFTWARE WITHOUT MODIFICATION The Licensee is authorized to redistribute true copies of the Software in Source Code or Object Code form, provided that said redistribution complies with all the provisions of the Agreement and is accompanied by: - a copy of the Agreement, - a notice relating to the limitation of both the Licensor's warranty and liability as set forth in Articles 8 and 9, and that, in the event that only the Software's Object Code is redistributed, the Licensee allows future Licensees unhindered access to the Software's full Source Code by providing them with the terms and conditions for access thereto, it being understood that the additional cost of acquiring the Source Code shall not exceed the cost of transferring the data. 5.3.2. REDISTRIBUTION OF MODIFIED SOFTWARE When the Licensee makes a Contribution to the Software, the terms and conditions for the redistribution of the Modified Software shall then be subject to all the provisions hereof. The Licensee is authorized to redistribute the Modified Software, in Source Code or Object Code form, provided that said redistribution complies with all the provisions of the Agreement and is accompanied by: - a copy of the Agreement, - a notice relating to the limitation of both the Licensor's warranty and liability as set forth in Articles 8 and 9, and that, in the event that only the Modified Software's Object Code is redistributed, the Licensee allows future Licensees unhindered access to the Modified Software's full Source Code by providing them with the terms and conditions for access thereto, it being understood that the additional cost of acquiring the Source Code shall not exceed the cost of transferring the data. 5.3.3. redistribution OF DYNAMIC MODULES When the Licensee has developed a Dynamic Module, the terms and conditions hereof do not apply to said Dynamic Module, that may be distributed under a separate Licensing Agreement. 5.3.4. COMPATIBILITY WITH THE GPL LICENSE In the event that the Modified or unmodified Software is included in a code that is subject to the provisions of the GPL License, the Licensee is authorized to redistribute the whole under the GPL License. In the event that the Modified Software includes a code that is subject to the provisions of the GPL License, the Licensee is authorized to redistribute the Modified Software under the GPL License. Article 6 - INTELLECTUAL PROPERTY ---------------------------------- 6.1. OVER THE INITIAL SOFTWARE The Holder owns the economic rights over the Initial Software. Any or all use of the Initial Software is subject to compliance with the terms and conditions under which the Holder has elected to distribute its work and no one shall be entitled to and it shall have sole entitlement to modify the terms and conditions for the distribution of said Initial Software. The Holder undertakes to maintain the distribution of the Initial Software under the conditions of the Agreement, for the duration set forth in article 4.2.. 6.2. OVER THE CONTRIBUTIONS The intellectual property rights over the Contributions belong to the holder of the economic rights as designated by effective legislation. 6.3. OVER THE DYNAMIC MODULES The Licensee having developed a Dynamic Module is the holder of the intellectual property rights over said Dynamic Module and is free to choose the agreement that shall govern its distribution. 6.4. JOINT PROVISIONS 6.4.1. The Licensee expressly undertakes: - not to remove, or modify, in any or all manner, the intellectual property notices affixed to the Software; - to reproduce said notices, in an identical manner, in the copies of the Software. 6.4.2. The Licensee undertakes not to directly or indirectly infringe the intellectual property rights of the Holder and/or Contributors and to take, where applicable, vis--vis its staff, any or all measures required to ensure respect for said intellectual property rights of the Holder and/or Contributors. Article 7 - RELATED SERVICES ----------------------------- 7.1. Under no circumstances shall the Agreement oblige the Licensor to provide technical assistance or maintenance services for the Software. However, the Licensor is entitled to offer this type of service. The terms and conditions of such technical assistance, and/or such maintenance, shall then be set forth in a separate instrument. Only the Licensor offering said maintenance and/or technical assistance services shall incur liability therefor. 7.2. Similarly, any or all Licensor shall be entitled to offer to its Licensees, under its own responsibility, a warranty, that shall only be binding upon itself, for the redistribution of the Software and/or the Modified Software, under terms and conditions that it shall decide upon itself. Said warranty, and the financial terms and conditions of its application, shall be subject to a separate instrument executed between the Licensor and the Licensee. Article 8 - LIABILITY ---------------------- 8.1. Subject to the provisions of Article 8.2, should the Licensor fail to fulfill all or part of its obligations hereunder, the Licensee shall be entitled to claim compensation for the direct loss suffered as a result of a fault on the part of the Licensor, subject to providing evidence of it. 8.2. The Licensor's liability is limited to the commitments made under this Licensing Agreement and shall not be incurred as a result , in particular: (i) of loss due the Licensee's total or partial failure to fulfill its obligations, (ii) direct or consequential loss due to the Software's use or performance that is suffered by the Licensee, when the latter is a professional using said Software for professional purposes and (iii) consequential loss due to the Software's use or performance. The Parties expressly agree that any or all pecuniary or business loss (i.e. loss of data, loss of profits, operating loss, loss of customers or orders, opportunity cost, any disturbance to business activities) or any or all legal proceedings instituted against the Licensee by a third party, shall constitute consequential loss and shall not provide entitlement to any or all compensation from the Licensor. Article 9 - WARRANTY --------------------- 9.1. The Licensee acknowledges that the current situation as regards scientific and technical know-how at the time when the Software was distributed did not enable all possible uses to be tested and verified, nor for the presence of any or all faults to be detected. In this respect, the Licensee's attention has been drawn to the risks associated with loading, using, modifying and/or developing and reproducing the Software that are reserved for experienced users. The Licensee shall be responsible for verifying, by any or all means, the product's suitability for its requirements, its due and proper functioning, and for ensuring that it shall not cause damage to either persons or property. 9.2. The Licensor hereby represents, in good faith, that it is entitled to grant all the rights on the Software (including in particular the rights set forth in Article 5 hereof over the Software). 9.3. The Licensee acknowledges that the Software is supplied "as is" by the Licensor without any or all other express or tacit warranty, other than that provided for in Article 9.2 and, in particular, without any or all warranty as to its market value, its secured, innovative or relevant nature. Specifically, the Licensor does not warrant that the Software is free from any or all error, that it shall operate continuously, that it shall be compatible with the Licensee's own equipment and its software configuration, nor that it shall meet the Licensee's requirements. 9.4. The Licensor does not either expressly or tacitly warrant that the Software does not infringe any or all third party intellectual right relating to a patent, software or to any or all other property right. Moreover, the Licensor shall not hold the Licensee harmless against any or all proceedings for infringement that may be instituted in respect of the use, modification and redistribution of the Software. Nevertheless, should such proceedings be instituted against the Licensee, the Licensor shall provide it with technical and legal assistance for its defense. Such technical and legal assistance shall be decided upon on a case-by-case basis between the relevant Licensor and the Licensee pursuant to a memorandum of understanding. The Licensor disclaims any or all liability as regards the Licensee's use of the Software's name. No warranty shall be provided as regards the existence of prior rights over the name of the Software and as regards the existence of a trademark. Article 10 - TERMINATION ------------------------- 10.1. In the event of a breach by the Licensee of its obligations hereunder, the Licensor may automatically terminate this Agreement thirty (30) days after notice has been sent to the Licensee and has remained ineffective. 10.2. The Licensee whose Agreement is terminated shall no longer be authorized to use, modify or distribute the Software. However, any or all licenses that it may have granted prior to termination of the Agreement shall remain valid subject to their having been granted in compliance with the terms and conditions hereof. Article 11 - MISCELLANEOUS PROVISIONS -------------------------------------- 11.1. EXCUSABLE EVENTS Neither Party shall be liable for any or all delay, or failure to perform the Agreement, that may be attributable to an event of force majeure, an act of God or an outside cause, such as, notably, defective functioning, or interruptions affecting the electricity or telecommunications networks, blocking of the network following a virus attack, the intervention of the government authorities, natural disasters, water damage, earthquakes, fire, explosions, strikes and labor unrest, war, etc. 11.2. The fact that either Party may fail, on one or several occasions, to invoke one or several of the provisions hereof, shall under no circumstances be interpreted as being a waiver by the interested Party of its entitlement to invoke said provision(s) subsequently. 11.3. The Agreement cancels and replaces any or all previous agreement, whether written or oral, between the Parties and having the same purpose, and constitutes the entirety of the agreement between said Parties concerning said purpose. No supplement or modification to the terms and conditions hereof shall be effective as regards the Parties unless it is made in writing and signed by their duly authorized representatives. 11.4. In the event that one or several of the provisions hereof were to conflict with a current or future applicable act or legislative text, said act or legislative text shall take precedence, and the Parties shall make the necessary amendments so as to be in compliance with said act or legislative text. All the other provisions shall remain effective. Similarly, the fact that a provision of the Agreement may be null and void, for any reason whatsoever, shall not cause the Agreement as a whole to be null and void. 11.5. LANGUAGE The Agreement is drafted in both French and English. In the event of a conflict as regards construction, the French version shall be deemed authentic. Article 12 - NEW VERSIONS OF THE AGREEMENT ------------------------------------------- 12.1. Any or all person is authorized to duplicate and distribute copies of this Agreement. 12.2. So as to ensure coherence, the wording of this Agreement is protected and may only be modified by the authors of the License, that reserve the right to periodically publish updates or new versions of the Agreement, each with a separate number. These subsequent versions may address new issues encountered by Free Software. 12.3. Any or all Software distributed under a given version of the Agreement may only be subsequently distributed under the same version of the Agreement, or a subsequent version, subject to the provisions of article 5.3.4. Article 13 - GOVERNING LAW AND JURISDICTION ------------------------------------------- 13.1. The Agreement is governed by French law. The Parties agree to endeavor to settle the disagreements or disputes that may arise during the performance of the Agreement out-of-court. 13.2. In the absence of an out-of-court settlement within two (2) months as from their occurrence, and unless emergency proceedings are necessary, the disagreements or disputes shall be referred to the Paris Courts having jurisdiction, by the first Party to take action. Version 1.1 of 10/26/2004 v_sim-3.8.0/Documentation/licence.fr.txt000077500000000000000000000542541370110300500202240ustar00rootroot00000000000000 CONTRAT DE LICENCE DE LOGICIEL LIBRE CeCILL =========================================== Avertissement ------------- Ce contrat est une licence de logiciel libre issue d'une concertation entre ses auteurs afin que le respect de deux grands principes prside sa rdaction : - d'une part, sa conformit au droit franais, tant au regard du droit de la responsabilit civile que du droit de la proprit intellectuelle et de la protection qu'il offre aux auteurs et titulaires des droits patrimoniaux sur un logiciel. - d'autre part, le respect des principes de diffusion des logiciels libres : accs au code source, droits tendus confrs aux utilisateurs. Les auteurs de la cette licence CeCILL (Ce : CEA, C : CNRS, I : INRIA, LL : Logiciel Libre) sont : Commissariat l'Energie Atomique - CEA, tablissement public de caractre scientifique technique et industriel, dont le sige est situ 31-33 rue de la Fdration, 75752 PARIS cedex 15. Centre National de la Recherche Scientifique - CNRS, tablissement public caractre scientifique et technologique, dont le sige est situ 3 rue Michel-Ange 75794 Paris cedex 16. Institut National de Recherche en Informatique et en Automatique - INRIA, tablissement public caractre scientifique et technologique, dont le sige est situ Domaine de Voluceau, Rocquencourt, BP 105, 78153 Le Chesnay cedex. PREAMBULE --------- Ce contrat est une licence de logiciel libre dont l'objectif est de confrer aux utilisateurs la libert de modification et de redistribution du logiciel rgi par cette licence dans le cadre d'un modle de diffusion open source fonde sur le droit franais. L'exercice de ces liberts est assorti de certains devoirs la charge des utilisateurs afin de prserver ce statut au cours des redistributions ultrieures. L'accessibilit au code source et les droits de copie, de modification et de redistribution qui en dcoulent ont pour contrepartie de n'offrir aux utilisateurs qu'une garantie limite et de ne faire peser sur l'auteur du logiciel, le titulaire des droits patrimoniaux et les concdants successifs qu'une responsabilit restreinte. A cet gard l'attention de l'utilisateur est attire sur les risques associs au chargement, l'utilisation, la modification et/ou au dveloppement et la reproduction du logiciel par l'utilisateur tant donn sa spcificit de logiciel libre, qui peut le rendre complexe manipuler et qui le rserve donc des dveloppeurs et des professionnels avertis possdant des connaissances informatiques approfondies. Les utilisateurs sont donc invits charger et tester l'adquation du Logiciel leurs besoins dans des conditions permettant d'assurer la scurit de leurs systmes et ou de leurs donnes et, plus gnralement, l'utiliser et l'exploiter dans les mme conditions de scurit. Ce contrat peut tre reproduit et diffus librement, sous rserve de le conserver en l'tat, sans ajout ni suppression de clauses. Ce contrat est susceptible de s'appliquer tout logiciel dont le titulaire des droits patrimoniaux dcide de soumettre l'exploitation aux dispositions qu'il contient. Article 1er - DEFINITIONS ------------------------- Dans ce contrat, les termes suivants, lorsqu'ils seront crits avec une lettre capitale, auront la signification suivante : Contrat : dsigne le prsent contrat de licence, ses ventuelles versions postrieures avenants et annexes. Logiciel : dsigne le logiciel sous sa forme de Code Objet et/ou de Code Source et le cas chant sa documentation, dans leur tat au moment de l'acceptation du Contrat par le Licenci. Logiciel Initial : dsigne le Logiciel sous sa forme de Code Source et de Code Objet et le cas chant sa documentation, dans leur tat au moment de leur premire diffusion sous les termes du Contrat. Logiciel Modifi : dsigne le Logiciel modifi par au moins une Contribution. Code Source : dsigne l'ensemble des instructions et des lignes de programme du Logiciel et auquel l'accs est ncessaire en vue de modifier le Logiciel. Code Objet : dsigne les fichiers binaires issus de la compilation du Code Source. Titulaire : dsigne le dtenteur des droits patrimoniaux d'auteur sur le Logiciel Initial. Licenci(s) : dsigne le ou les utilisateur(s) du Logiciel ayant accept le Contrat. Contributeur : dsigne le Licenci auteur d'au moins une Contribution. Concdant : dsigne le Titulaire ou toute personne physique ou morale distribuant le Logiciel sous le Contrat. Contributions : dsigne l'ensemble des modifications, corrections, traductions, adaptations et/ou nouvelles fonctionnalits intgres dans le Logiciel par tout Contributeur, ainsi que les Modules Statiques. Module : dsigne un ensemble de fichiers sources y compris leur documentation qui, une fois compil sous forme excutable, permet de raliser des fonctionnalits ou services supplmentaires ceux fournis par le Logiciel. Module Dynamique : dsigne tout Module, cr par le Contributeur, indpendant du Logiciel, tel que ce Module et le Logiciel sont sous forme de deux excutables indpendants qui s'excutent dans un espace d'adressage indpendant, l'un appelant l'autre au moment de leur excution. Module Statique : dsigne tout Module cr par le Contributeur et li au Logiciel par un lien statique rendant leur code objet dpendant l'un de l'autre. Ce Module et le Logiciel auquel il est li, sont regroups en un seul excutable. Parties : dsigne collectivement le Licenci et le Concdant. Ces termes s'entendent au singulier comme au pluriel. Article 2 - OBJET ----------------- Le Contrat a pour objet la concession par le Concdant au Licenci d'une Licence non exclusive, transfrable et mondiale du Logiciel telle que dfinie ci-aprs l'article 5 pour toute la dure de protection des droits portant sur ce Logiciel. Article 3 - ACCEPTATION ----------------------- 3.1. L'acceptation par le Licenci des termes du Contrat est rpute acquise du fait du premier des faits suivants : - (i) le chargement du Logiciel par tout moyen notamment par tlchargement partir d'un serveur distant ou par chargement partir d'un support physique ; - (ii) le premier exercice par le Licenci de l'un quelconque des droits concds par le Contrat. 3.2. Un exemplaire du Contrat, contenant notamment un avertissement relatif aux spcificits du Logiciel, la restriction de garantie et la limitation un usage par des utilisateurs expriments a t mis disposition du Licenci pralablement son acceptation telle que dfinie l'article 3.1 ci dessus et le Licenci reconnat en avoir pris connaissances. Article 4 - ENTREE EN VIGUEUR ET DUREE -------------------------------------- 4.1. ENTREE EN VIGUEUR Le Contrat entre en vigueur la date de son acceptation par le Licenci telle que dfinie en 3.1. 4.2. DUREE Le Contrat produira ses effets pendant toute la dure lgale de protection des droits patrimoniaux portant sur le Logiciel. Article 5 - ETENDUE DES DROITS CONCEDES --------------------------------------- Le Concdant concde au Licenci, qui accepte, les droits suivants sur le Logiciel pour toutes destinations et pour la dure du Contrat dans les conditions ci-aprs dtailles. Par ailleurs, le Concdant concde au Licenci titre gracieux les droits d'exploitation du ou des brevets qu'il dtient sur toute ou partie des inventions implmentes dans le Logiciel. 5.1. DROITS D'UTILISATION Le Licenci est autoris utiliser le Logiciel, sans restriction quant aux domaines d'application, tant ci-aprs prcis que cela comporte : - la reproduction permanente ou provisoire du Logiciel en tout ou partie par tout moyen et sous toute forme. - le chargement, l'affichage, l'excution, ou le stockage du Logiciel sur tout support. - la possibilit d'en observer, d'en tudier, ou d'en tester le fonctionnement afin de dterminer les ides et principes qui sont la base de n'importe quel lment de ce Logiciel ; et ceci, lorsque le Licenci effectue toute opration de chargement, d'affichage, d'excution, de transmission ou de stockage du Logiciel qu'il est en droit d'effectuer en vertu du Contrat. 5.2. DROIT D'APPORTER DES CONTRIBUTIONS Le droit d'apporter des Contributions comporte le droit de traduire, d'adapter, d'arranger ou d'apporter toute autre modification du Logiciel et le droit de reproduire le Logiciel en rsultant. Le Licenci est autoris apporter toute Contribution au Logiciel sous rserve de mentionner, de faon explicite, son nom en tant qu'auteur de cette Contribution et la date de cration de celle-ci. 5.3. DROITS DE DISTRIBUTION ET DE DIFFUSION Le droit de distribution et de diffusion comporte notamment le droit de transmettre et de communiquer le Logiciel au public sur tout support et par tout moyen ainsi que le droit de mettre sur le march titre onreux ou gratuit, un ou des exemplaires du Logiciel par tout procd. Le Licenci est autoris redistribuer des copies du Logiciel, modifi ou non, des tiers dans les conditions ci-aprs dtailles. 5.3.1. REDISTRIBUTION DU LOGICIEL SANS MODIFICATION Le Licenci est autoris redistribuer des copies conformes du Logiciel, sous forme de Code Source ou de Code Objet, condition que cette redistribution respecte les dispositions du Contrat dans leur totalit et soit accompagne : - d'un exemplaire du Contrat, - d'un avertissement relatif la restriction de garantie et de responsabilit du Concdant telle que prvue aux articles 8 et 9, et que, dans le cas o seul le Code Objet du Logiciel est redistribu, le Licenci permette aux futurs Licencis d'accder facilement au Code Source complet du Logiciel en indiquant les modalits d'accs, tant entendu que le cot additionnel d'acquisition du Code Source ne devra pas excder le simple cot de transfert des donnes. 5.3.2. REDISTRIBUTION DU LOGICIEL MODIFIE Lorsque le Licenci apporte une Contribution au Logiciel, les conditions de redistribution du Logiciel Modifi sont alors soumises l'intgralit des dispositions du Contrat. Le Licenci est autoris redistribuer le Logiciel Modifi, sous forme de Code Source ou de Code Objet, condition que cette redistribution respecte les dispositions du Contrat dans leur totalit et soit accompagne : - d'un exemplaire du Contrat, - d'un avertissement relatif la restriction de garantie et de responsabilit du concdant telle que prvue aux articles 8 et 9, et que, dans le cas o seul le Code Objet du Logiciel Modifi est redistribu, le Licenci permette aux futurs Licencis d'accder facilement au Code Source complet du Logiciel Modifi en indiquant les modalits d'accs, tant entendu que le cot additionnel d'acquisition du Code Source ne devra pas excder le simple cot de transfert des donnes. 5.3.3. redistribution des MODULES DYNAMIQUES Lorsque le Licenci a dvelopp un Module Dynamique les conditions du Contrat ne s'appliquent pas ce Module Dynamique, qui peut tre distribu sous un contrat de licence diffrent. 5.3.4. COMPATIBILITE AVEC LA LICENCE GPL Dans le cas o le Logiciel, Modifi ou non, est intgr un code soumis aux dispositions de la licence GPL, le Licenci est autoris redistribuer l'ensemble sous la licence GPL. Dans le cas o le Logiciel Modifi intgre un code soumis aux dispositions de la licence GPL, le Licenci est autoris redistribuer le Logiciel Modifi sous la licence GPL. Article 6 - PROPRIETE INTELLECTUELLE ------------------------------------ 6.1. SUR LE LOGICIEL INITIAL Le Titulaire est dtenteur des droits patrimoniaux sur le Logiciel Initial. Toute utilisation du Logiciel Initial est soumise au respect des conditions dans lesquelles le Titulaire a choisi de diffuser son oeuvre et nul autre n'a la facult de modifier les conditions de diffusion de ce Logiciel Initial. Le Titulaire s'engage maintenir la diffusion du Logiciel initial sous les conditions du Contrat et ce, pour la dure vise l'article 4.2. 6.2. SUR LES CONTRIBUTIONS Les droits de proprit intellectuelle sur les Contributions sont attachs au titulaire de droits patrimoniaux dsigns par la lgislation applicable. 6.3. SUR LES MODULES DYNAMIQUES Le Licenci ayant dvelopp un Module Dynamique est titulaire des droits de proprit intellectuelle sur ce Module Dynamique et reste libre du choix du contrat rgissant sa diffusion. 6.4. DISPOSITIONS COMMUNES 6.4.1. Le Licenci s'engage expressment : - ne pas supprimer ou modifier de quelque manire que ce soit les mentions de proprit intellectuelle apposes sur le Logiciel; - reproduire l'identique lesdites mentions de proprit intellectuelle sur les copies du Logiciel. 6.4.2. Le Licenci s'engage ne pas porter atteinte, directement ou indirectement, aux droits de proprit intellectuelle du Titulaire et/ou des Contributeurs et prendre, le cas chant, l'gard de son personnel toutes les mesures ncessaires pour assurer le respect des dits droits de proprit intellectuelle du Titulaire et/ou des Contributeurs. Article 7 - SERVICES ASSOCIES ----------------------------- 7.1. Le Contrat n'oblige en aucun cas le Concdant la ralisation de prestations d'assistance technique ou de maintenance du Logiciel. Cependant le Concdant reste libre de proposer ce type de services. Les termes et conditions d'une telle assistance technique et/ou d'une telle maintenance seront alors dtermins dans un acte spar. Ces actes de maintenance et/ou assistance technique n'engageront que la seule responsabilit du Concdant qui les propose. 7.2. De mme, tout Concdant est libre de proposer, sous sa seule responsabilit, ses licencis une garantie, qui n'engagera que lui, lors de la redistribution du Logiciel et/ou du Logiciel Modifi et ce, dans les conditions qu'il souhaite. Cette garantie et les modalits financires de son application feront l'objet d'un acte spar entre le Concdant et le Licenci. Article 8 - RESPONSABILITE -------------------------- 8.1. Sous rserve des dispositions de l'article 8.2, si le Concdant n'excute pas tout ou partie des obligations mises sa charge par le Contrat, le Licenci a la facult, sous rserve de prouver la faute du Concdant concern, de solliciter la rparation du prjudice direct qu'il subit et dont il apportera la preuve. 8.2. La responsabilit du Concdant est limite aux engagements pris en application du Contrat et ne saurait tre engage en raison notamment :(i) des dommages dus l'inexcution, totale ou partielle, de ses obligations par le Licenci, (ii) des dommages directs ou indirects dcoulant de l'utilisation ou des performances du Logiciel subis par le Licenci lorsqu'il s'agit d'un professionnel utilisant le Logiciel des fins professionnelles et (iii) des dommages indirects dcoulant de l'utilisation ou des performances du Logiciel. Les Parties conviennent expressment que tout prjudice financier ou commercial (par exemple perte de donnes, perte de bnfices, perte d'exploitation, perte de clientle ou de commandes, manque gagner, trouble commercial quelconque) ou toute action dirige contre le Licenci par un tiers, constitue un dommage indirect et n'ouvre pas droit rparation par le Concdant. Article 9 - GARANTIE -------------------- 9.1. Le Licenci reconnat que l'tat actuel des connaissances scientifiques et techniques au moment de la mise en circulation du Logiciel ne permet pas d'en tester et d'en vrifier toutes les utilisations ni de dtecter l'existence d'ventuels dfauts. L'attention du Licenci a t attire sur ce point sur les risques associs au chargement, l'utilisation, la modification et/ou au dveloppement et la reproduction du Logiciel qui sont rservs des utilisateurs avertis. Il relve de la responsabilit du Licenci de contrler, par tous moyens, l'adquation du produit ses besoins, son bon fonctionnement et de s'assurer qu'il ne causera pas de dommages aux personnes et aux biens. 9.2. Le Concdant dclare de bonne foi tre en droit de concder l'ensemble des droits attachs au Logiciel (comprenant notamment les droits viss l'article 5). 9.3. Le Licenci reconnat que le Logiciel est fourni en l'tat par le Concdant sans autre garantie, expresse ou tacite, que celle prvue l'article 9.2 et notamment sans aucune garantie sur sa valeur commerciale, son caractre scuris, innovant ou pertinent. En particulier, le Concdant ne garantit pas que le Logiciel est exempt d'erreur, qu'il fonctionnera sans interruption, qu'il sera compatible avec l'quipement du Licenci et sa configuration logicielle ni qu'il remplira les besoins du Licenci. 9.4. Le Concdant ne garantit pas, de manire expresse ou tacite, que le Logiciel ne porte pas atteinte un quelconque droit de proprit intellectuelle d'un tiers portant sur un brevet, un logiciel ou sur tout autre droit de proprit. Ainsi, le Concdant exclut toute garantie au profit du Licenci contre les actions en contrefaon qui pourraient tre diligentes au titre de l'utilisation, de la modification, et de la redistribution du Logiciel. Nanmoins, si de telles actions sont exerces contre le Licenci, le Concdant lui apportera son aide technique et juridique pour sa dfense. Cette aide technique et juridique est dtermine au cas par cas entre le Concdant concern et le Licenci dans le cadre d'un protocole d'accord. Le Concdant dgage toute responsabilit quant l'utilisation de la dnomination du Logiciel par le Licenci. Aucune garantie n'est apporte quant l'existence de droits antrieurs sur le nom du Logiciel et sur l'existence d'une marque. Article 10 - RESILIATION ------------------------- 10.1. En cas de manquement par le Licenci aux obligations mises sa charge par le Contrat, le Concdant pourra rsilier de plein droit le Contrat trente (30) jours aprs notification adresse au Licenci et reste sans effet. 10.2. Le Licenci dont le Contrat est rsili n'est plus autoris utiliser, modifier ou distribuer le Logiciel. Cependant, toutes les Licences licences qu'il aura concdes antrieurement la rsiliation du Contrat resteront valides sous rserve qu'elles aient t effectues en conformit avec le Contrat. Article 11 - DISPOSITIONS DIVERSES ---------------------------------- 11.1. CAUSE EXTERIEURE Aucune des Parties ne sera responsable d'un retard ou d'une dfaillance d'excution du Contrat qui serait d un cas de force majeure, un cas fortuit ou une cause extrieure, telle que, notamment, le mauvais fonctionnement ou les interruptions du rseau lectrique ou de tlcommunication, la paralysie du rseau lie une attaque informatique, l'intervention des autorits gouvernementales, les catastrophes naturelles, les dgts des eaux, les tremblements de terre, le feu, les explosions, les grves et les conflits sociaux, l'tat de guerre. 11.2. Le fait, par l'une ou l'autre des Parties, d'omettre en une ou plusieurs occasions de se prvaloir d'une ou plusieurs dispositions du Contrat, ne pourra en aucun cas impliquer renonciation par la Partie intresse s'en prvaloir ultrieurement. 11.3. Le Contrat annule et remplace toute convention antrieure, crite ou orale, entre les Parties sur le mme objet et constitue l'accord entier entre les Parties sur cet objet. Aucune addition ou modification aux termes du Contrat n'aura d'effet l'gard des Parties moins d'tre faite par crit et signe par leurs reprsentants dment habilits. 11.4. Dans l'hypothse o une ou plusieurs des dispositions du Contrat s'avrerait contraire une loi ou un texte applicable, existants ou futurs, cette loi ou ce texte prvaudrait, et les Parties feraient les amendements ncessaires pour se conformer cette loi ou ce texte. Toutes les autres dispositions resteront en vigueur. De mme, la nullit, pour quelque raison que ce soit, d'une des dispositions du Contrat ne saurait entraner la nullit de l'ensemble du Contrat. 11.5. LANGUE Le Contrat est rdig en langue franaise et en langue anglaise. En cas de divergence d'interprtation, seule la version franaise fait foi. Article 12 - NOUVELLES VERSIONS DU CONTRAT ------------------------------------------ 12.1. Toute personne est autorise copier et distribuer des copies de ce Contrat. 12.2. Afin d'en prserver la cohrence, le texte du Contrat est protg et ne peut tre modifi que par les auteurs de la licence, lesquels se rservent le droit de publier priodiquement des mises jour ou de nouvelles versions du Contrat, qui possderont chacune un numro distinct. Ces versions ultrieures seront susceptibles de prendre en compte de nouvelles problmatiques rencontres par les logiciels libres. 12.3. Tout Logiciel diffus sous une version donne du Contrat ne pourra faire l'objet d'une diffusion ultrieure que sous la mme version du Contrat ou une version postrieure, sous rserve des dispositions de l'article 5.3.4. Article 13 - LOI APPLICABLE ET COMPETENCE TERRITORIALE ------------------------------------------------------ 13.1. Le Contrat est rgi par la loi franaise. Les Parties conviennent de tenter de rgler l'amiable les diffrends ou litiges qui viendraient se produire par suite ou l'occasion du Contrat. 13.2. A dfaut d'accord amiable dans un dlai de deux (2) mois compter de leur survenance et sauf situation relevant d'une procdure d'urgence, les diffrends ou litiges seront ports par la Partie la plus diligente devant les Tribunaux comptents de Paris. Version 1 du 21/06/2004 v_sim-3.8.0/Documentation/man.xsl000066400000000000000000000100701370110300500167370ustar00rootroot00000000000000 .\" Hey, EMACS: -*- nroff -*- .\" First parameter, NAME, should be all caps .\" Second parameter, SECTION, should be 1-8, maybe w/ subsection .\" other parameters are allowed: see man(7), man(1) .TH "V_SIM" "1" " , " .\" Please adjust this date whenever revising the manpage. .\" .\" Some roff macros, for reference: .\" .nh disable hyphenation .\" .hy enable hyphenation .\" .ad l left justify .\" .ad b justify to both left and right margins .\" .nf disable filling .\" .fi enable filling .\" .br insert line break .\" .sp <n> insert n+1 empty lines .\" for manpage-specific macros, see man(7) .SH NAME v_sim \- a GTK program for 3D visualisation of atomic systems .SH SYNOPSIS .B v_sim .PP This manual page documents briefly the .B v_sim commands. It is a software to visualise atomic structures with OpenGl rendering. .SH OPTIONS .PP This program follows the usual GNU command line syntax, with long options starting with two dashes (`-'). .PP A complete list of options is included below. .SH FILES .IR /usr/share/v_sim/v_sim.res specify all rendering informations from position of the camera to colour of the elements. .br .IR /usr/share/v_sim/v_sim.par specify all interface and non-rendering options such as the positions of the panels. .br .IR ~/$XDG_CONFIG_DIR/v_sim a directory where overloading .B v_sim.res and .B v_sim.par can be put. .SH AUTHOR V_Sim was written by Luc Billard, Damien Caliste, Olivier D'Astier Aurlien Lherbier, Jrmy Blanc, Simon Plans, Thomas Jourdan and Yoann Ratao. .PP This manual page was written by Damien Caliste <damien.caliste@cea.fr>. .B [ - -- .I .B ] .B [ .I fileToRender .B ] .TP .B \-, .B \-\- (from v.0) (Default value: ) v_sim-3.8.0/Documentation/pot2surf_help000066400000000000000000000036651370110300500201670ustar00rootroot00000000000000HOWTO use pot2surf through V_Sim to create a .surf file. Originnally written by Luc Billard for his program VISUALIZE, pot2surf allows you to create .surf files from .pot files. Please refer to V_Sim's website to learn about .pot files specifications. To use pot2surf through V_Sim, you need to select the "pot2surf" tab under the "convert" button of the "isosurfaces" module. You must then select a .pot file from which to build a .surf file and a name for the .surf file to build (notice that if you first select a .pot file, the other field will be auto filled by V_Sim but you can always specify the file names you want by yourself). Once you've selected your .pot file, pot_min and pot_max fields are automatically filled by V_Sim. These are the min and max values V_Sim found in your .pot file. Of course you can't create surfaces which isovalues aren't in the ]pot_min, pot_max[ range. You can now add surfaces to build by using the "+" button on the right column. Surfaces' names are auto-filled but you can change them by selecting and clicking them. Surfaces' name can't contain space character, but can contain any other you want. They should always by with the 'surface_' prefix. You can also specify the value of a surface by selecting and clicking the value field of a surface. You can remove any surface by clicking the "-" button, or re-orders them all by using the up and down arrows. The order is important if you want to use the "Play" function of the "isosurface" tab. Once you've added several surfaces to the list, you can click the "Build target .surf file" button to have your .surf file created. If no error message appears, it means the surf file you specified have been created succesfully. If you have selected "Autoload", your .surf file should be displayed in V_Sim (don't forget to check the "Use isosurfaces" button in the main panel !). Buttons in the toolbar are used to save/restore settings by exporting/reading it as a .instruc file. v_sim-3.8.0/Documentation/readme000066400000000000000000000017131370110300500166200ustar00rootroot00000000000000 V_Sim visualizes atomic structures such as crystals, grain boundaries, molecules and so on (either in binary format, or in plain text format). The rendering is done in pseudo-3D with spheres (atoms) or arrows (spins). The user can interact through many functions to choose the view, set the pairs, draw cutting planes, compute surfaces from scalar fields, duplicate nodes, measure geometry... Moreover V_Sim allows to export the view as images in PNG, JPG or scheme in PDF, SVG and other formats. Some tools are also available to colorize atoms from data values or to animate on screen many position files. The tool is fully scriptable with Python. A comprehensive manual is available on the web site, see http://inac.cea.fr/L_Sim/V_Sim/user_guide.html. Compiling and installing V_Sim is detailled at http://inac.cea.fr/L_Sim/V_Sim/install.html and in the INSTALL file of the package (providing dependencies information as well). 1998 - 2020, CEA (France) v_sim-3.8.0/Documentation/reference/000077500000000000000000000000001370110300500173745ustar00rootroot00000000000000v_sim-3.8.0/Documentation/reference/Makefile.am000066400000000000000000000077231370110300500214410ustar00rootroot00000000000000## Process this file with automake to produce Makefile.in # We require automake 1.6 at least. AUTOMAKE_OPTIONS = 1.6 # This is a blank Makefile.am for using gtk-doc. # Copy this to your project's API docs directory and modify the variables to # suit your project. See the GTK+ Makefiles in gtk+/docs/reference for examples # of using the various options. # The name of the module, e.g. 'glib'. DOC_MODULE=v_sim # The top-level SGML file. You can change this if you want to. DOC_MAIN_SGML_FILE=$(DOC_MODULE)-docs.sgml # The directory containing the source code. Relative to $(srcdir). # gtk-doc will search all .c & .h files beneath here for inline comments # documenting the functions and macros. # e.g. DOC_SOURCE_DIR=../../../gtk DOC_SOURCE_DIR=$(top_srcdir)/src # Extra options to pass to gtkdoc-scangobj. Not normally needed. SCANGOBJ_OPTIONS= # Extra options to supply to gtkdoc-scan. # e.g. SCAN_OPTIONS=--deprecated-guards="GTK_DISABLE_DEPRECATED" SCAN_OPTIONS=--rebuild-types --rebuild-sections --deprecated-guards="V_SIM_DISABLE_DEPRECATED" # Extra options to supply to gtkdoc-mkdb. # e.g. MKDB_OPTIONS=--sgml-mode --output-format=xml MKDB_OPTIONS=--xml-mode --output-format=xml --name-space=visu # Extra options to supply to gtkdoc-mktmpl # e.g. MKTMPL_OPTIONS=--only-section-tmpl MKTMPL_OPTIONS= # Extra options to supply to gtkdoc-mkhtml MKHTML_OPTIONS=--path=$(abs_top_builddir)/Documentation/reference # Extra options to supply to gtkdoc-fixref. Not normally needed. # e.g. FIXXREF_OPTIONS=--extra-dir=../gdk-pixbuf/html --extra-dir=../gdk/html FIXXREF_OPTIONS= # Used for dependencies. The docs will be rebuilt if any of these change. # e.g. HFILE_GLOB=$(top_srcdir)/gtk/*.h # e.g. CFILE_GLOB=$(top_srcdir)/gtk/*.c HFILE_GLOB=$(top_srcdir)/src/*.h $(top_srcdir)/src/*/*.h CFILE_GLOB=$(top_srcdir)/src/*.c $(top_srcdir)/src/*/*.c # Extra header to include when scanning, which are not under DOC_SOURCE_DIR # e.g. EXTRA_HFILES=$(top_srcdir}/contrib/extra.h EXTRA_HFILES= # Header files to ignore when scanning. Use base file name, no paths # e.g. IGNORE_HFILES=gtkdebug.h gtkintl.h IGNORE_HFILES=support.h interface.h visu_tools.h externalModules.h externalPairsExtensions.h externalGtkPairsExtensions.h externalDumpModules.h externalVisuExtensions.h atoms_yaml.h rings.h dumpToGif.h callbacks.h # Images to copy into HTML directory. # e.g. HTML_IMAGES=$(top_srcdir)/gtk/stock-icons/stock_about_24.png HTML_IMAGES=../../pixmaps/illustration/axesTransform.png # Extra SGML files that are included by $(DOC_MAIN_SGML_FILE). # e.g. content_files=running.sgml building.sgml changes-2.0.sgml content_files= # SGML files where gtk-doc abbrevations (#GtkWidget) are expanded # These files must be listed here *and* in content_files # e.g. expand_content_files=running.sgml expand_content_files= # CFLAGS and LDFLAGS for compiling gtkdoc-scangobj with your library. # Only needed if you are using gtkdoc-scangobj to dynamically query widget # signals and properties. # e.g. GTKDOC_CFLAGS=-I$(top_srcdir) -I$(top_builddir) $(GTK_DEBUG_FLAGS) # e.g. GTKDOC_LIBS=$(top_builddir)/gtk/$(gtktargetlib) CFLAGS=-Wno-error AM_CPPFLAGS=-I$(top_srcdir) -I$(top_srcdir)/src @GTKS_CFLAGS@ @GLU_CFLAGS@ GTKDOC_LIBS= \ $(top_builddir)/src/lib@PACKAGE_TARNAME@-3.la \ @GTKS_LIBS@ @GLU_LIBS@ @EXTRA_LDFLAGS@ @EXTRA_LIBS@ # This includes the standard gtk-doc make rules, copied by gtkdocize. include $(srcdir)/gtk-doc.make # Other files to distribute # e.g. EXTRA_DIST += version.xml.in EXTRA_DIST += version.in # Files not to distribute # for --rebuild-types in $(SCAN_OPTIONS), e.g. $(DOC_MODULE).types # for --rebuild-sections in $(SCAN_OPTIONS) e.g. $(DOC_MODULE)-sections.txt DISTCLEANFILES = $(DOC_MODULE).types $(DOC_MODULE)-sections.txt # Comment this out if you want your docs-status tested during 'make check' if ENABLE_GTK_DOC TESTS_ENVIRONMENT = \ DOC_MODULE=$(DOC_MODULE) DOC_MAIN_SGML_FILE=$(DOC_MAIN_SGML_FILE) \ SRCDIR=$(abs_srcdir) BUILDDIR=$(abs_builddir) TESTS = $(GTKDOC_CHECK) endif #-include $(top_srcdir)/git.mk v_sim-3.8.0/Documentation/reference/v_sim-docs.sgml000066400000000000000000000345371370110300500223370ustar00rootroot00000000000000 ]> V_Sim API - Reference Manual for V_Sim Core This is the program itself without the interface. Basically V_Sim allows the user to see in a pseudo 3D representation a list of elements known by their positions in space, all contained in a box. And it gives tools to rotate, zoom and retrieve informations on positions, angles and distances. The program is supposed to be modular and the programer can add new functions "easily". There are three sections. The first section deals with all the main functions to handle with this modularity, with the 3D drawing... The second section gathers all the extensions that have been added to improve V_Sim in the rendering area. The third section deals with the different possibilities that exist for the user to render different kind of elements. Main capabilities of V_Sim Main capabilities. Node related method and properties Scalar fields and surfaces Main capabilities. Methods to read input files Main purpose of V_Sim is to render some file describing positions and other informations n a graphical way. This is achieved implementing VisuRendering. Currently two methods exist, one draw spheres (or other geometric forms such as cubes) on defined positions. The other is a more specialised version of the former, adding a direction information on each position. This method is called SpinRendering and is usefull to render spin configurations. Methods to render nodes and pairs Objects to draw nodes and pairs between nodes. OpenGL drawing methods All rendering is done via objects inherited from VisuExtension. Animating changes Dealing with pairs Drawing pairs is done via external modules. For the moment, two modules exist to draw pairs : one draws flat lines between elements (colour and width are user-defined) and the other use cylinders to represents pairs (radius and colour also user-defined). Methods to export to other formats Generic tools There are differents tools that can be shared by every modules in V_Sim, such as file support, list of colors, common shades... OpenGL tools These little utilities are dealing with OpenGL. They are not essential to V_Sim but can add some nice features that can be shared between different modules. Miscellaneous Other methods, including OS dependancy and rendering window backend. Gtk interface Main interface Interface elements V_Sim specific widgets Panel add-ons Additional information Object Hierarchy New symbols in 3.1 New symbols in 3.2 New symbols in 3.3 New symbols in 3.4 New symbols in 3.5 New symbols in 3.6 New symbols in 3.7 New symbols in 3.8 API Index v_sim-3.8.0/Documentation/reference/version.in000066400000000000000000000000221370110300500214030ustar00rootroot00000000000000@PACKAGE_VERSION@ v_sim-3.8.0/Documentation/v_sim.cli.xml000066400000000000000000000166541370110300500200570ustar00rootroot00000000000000 v_sim-3.8.0/Makefile.am000066400000000000000000000005541370110300500146650ustar00rootroot00000000000000v_simlegal_DATA = \ ChangeLog.fr \ ChangeLog.en EXTRA_DIST = $(v_simlegal_DATA) \ autogen.sh \ configure \ bugs \ todo \ intltool-extract.in intltool-merge.in intltool-update.in ACLOCAL_AMFLAGS = -I m4 DISTCLEANFILES = intltool-extract intltool-merge intltool-update SUBDIRS = \ src \ lib \ etc \ po \ pixmaps \ examples \ Documentation \ tests v_sim-3.8.0/NEWS000066400000000000000000000003621370110300500133250ustar00rootroot00000000000000New features in version 3.5 =========================== - Vibrations and phonons representation. - Multi coloured maps. - Geometry diff, highlighting moving atoms. - Physical units. - Experimental Python module. - Visual angle measurements. v_sim-3.8.0/README000077700000000000000000000000001370110300500174712Documentation/readmeustar00rootroot00000000000000v_sim-3.8.0/autogen.sh000077500000000000000000000005611370110300500146300ustar00rootroot00000000000000#!/bin/sh echo "internationalisation" intltoolize --force --copy echo "libtoolize" libtoolize --copy --force echo "aclocal" aclocal -I m4 echo "gtkdocize --flavour=no-tmpl" gtkdocize --docdir Documentation/reference --flavour no-tmpl --copy || exit 1 echo "autoheader" autoheader echo "automake" automake --add-missing --copy --force-missing echo "autoconf" autoconf v_sim-3.8.0/bugs000066400000000000000000001024031370110300500135100ustar00rootroot00000000000000 Si aucun fichier n'est charg, le fait de changer dans l'onglet configuration la valeur du facteur multiplicatif fait crasher l'application. Quand le choix d'un rpertoire est fait en le slectionnant dans la bote de dialogue, et non en double-cliquant dessus, c'est le rpertoire un niveau en dessous qui est stock, mme si c'est le bon rpertoire qui est parcourru. Le redimensionnement des axes n'est pas ralis lors du chargement d'un fichier avec une gomtrie de bote diffrente (par exemple entre 'diff.ascii' et 'aluminium.d3'). Les axes ne sont pas mis jour au chargement des ressources. Lors du chargement des ressources, un changement sur l'utilisation des liaisons n'affecte pas la case cocher de l'interface. Quand les liaisons sont cylindriques, charger des ressources fait crasher V_Sim. Lors du chargement d'un fichier de ressources, un changement de la taille des atomes n'est pas rpercut l'cran. Quand plusieurs fichiers sont spcifis sur la ligne de commande, V_Sim passe en mode spin, mme si ces fichiers sont des fichiers de position. Le rglage des couleurs des axes n'a plus d'effet la vole sur celle qui est effectivement dessine. Dans l'onglet d'outils de colorisation, les spins boutons pour rgler les valeurs min et max la main n'ont pas assez de dcimales pour tre pratiques. Quand on choisit une couleur dans l'onglet lment pour un type d'atome, cette couleur ne reste pas quand on choisit un autre atome et qu'on revient au premier. Quand on clique sur une liaison, la taille du cylindre dans le spin bouton ne change pas pour se mettre la bonne valeur. Avec le rechargement automatique d'un fichier, si celui-ci contient de nouveaux atomes, la liste des lments dans l'onglet adquat n'est pas toujours mise jour. Quand un nouveau fichier est charg, d'un rpertoire diffrent du premier, le navigateur ne change pas son rpertoire courant. Si aucun fichier n'est charg, le fait d'ouvrir un fichier de surface fait crasher le programme. Mme si la case use planes n'est pas coche, le chargement d'un nouveau fichier fait appliquer le masquage par les plans. Dans la fentre d'outils des liaisons, le cadre de texte est inexact. Dans le navigateur, alors qu'aucun fichier n'est rendu, pour les mthodes ncessitant plusieurs fichiers d'entre, le message d'erreur n'est pas correct quand on essaye de rendre un fichier. Quand on choisit la mthode de rendu 'None', des Warnings apparaissent cause de l'onglet 'navigateur'. Lorsque des plans sont dessins et qu'ils masquent une partie de la bote, quand un nouveau fichier est charg, le masquage ne fonctionne pas. Lorsqu'un lment est masqu et qu'on applique des translations priodique sur la bote, le fait d'afficher nouveau lment ne le fait pas rapparatre, il faut modifier un paramtre de translation pour que a soit pris en compte. Au dmarrage de V_sim, le message WARNING! 'visuData_createAllElements' has been called with a null 'data' argument. apparat sans raison. l'ouverture d'un nouveau fichier, le dessin des liaisons ne tient pas compte des translations existantes. On peut fermer la fentre pick/observe sans pour autant revenir la fentre principale, V_Sim fini ensuite par mettre une erreur de segmentation. La liste d'onglets de la fentre propos n'est pas dans les tons verts comme le reste des lments des fentres annexes. De plus les boutons cocher dans la bote de dialogue d'ouverture d'un fichier en mode spin ne sont pas mauves. La fentre d'dition des proprits des surfaces partir du bouton Edit selected surface fait 1071 points de large. Lorsque Use isosurfaces n'est pas coch, chaque changement, la vue est tout de mme redessine. Les widgets permettant le rglage des paramtres spcifiques une mthode de rendu des liaisons disparat parfois. Un changement sur les spins boutons dans l'onglet de configuration alors qu'aucun fichier n'est charg entraine une erreur de segmentation. Il faudrait pouvoir compiler V_Sim sans certaines parties (en particulier certains onglets et proprits lies). Dans la fentre d'exportation en image, le fait de drouler la combobox de l'emplacement juste avant la destruction de la fentre la fin de l'enregistrement fait planter GTK. Il faudrait rendre tout le widget insensible pendant l'enregistrement, sauf la barre de progession et le bouton annuler . Lorsqu'un nouveau fichier est charg, les translations si elles sont actives, ne sont pas appliques. Lorsqu'aucun fichier n'est affich, et que l'option Automatic refresh est coch, le programme cherche charger un fichier n'existant pas et sort des warnings la pelle. Il faudrait un bouton permettant d'amener la vue dans une position normale au plan slectionn. Il pourrait y avoir une fonction qui permet de marquer d'une faon ou d'une autre les atomes de la bote (en chageant leur couleur par exemple). Lors d'une session pick , si les translations sont actives, les distances et les angles affiches ne sont pas bons. Lorsque les translations sont actives, le masquage par les plans ne fonctionne pas. Un plan avec une couleur transparente n'est pas transparent si l'antialiasing n'est pas activ. Quand un fichier est charg, la liste droulante de l'onglet des lments change pour son premier choix. C'est droutant quand on a par exemple le rechargement automatique d'un fichier qui marche : chaque fois que le fichier est modifi, la liste revient au dbut. Lorsqu'un fichier est charge avec la ligne de commande, le chemin connu de V_Sim (celui o sont ouvert les bote de dialogue de fichiers) peut contenir des ./ et des ../, ce qui fait parfois planter le slecteur de fichier. Le choix des fichiers cochs ou non dans le navigateur de fichiers est impossible quand un filtre est prsent (a slectionne/dslectionne n'importe quoi). Le refresh automatique ne fonctionne plus. Il faudrait rajouter un champ filtre o l'utilisateur pourrait spcifier un motif pour la liste des fichiers afficher. Le choix d'une nouvelle couleur pour les liaisons donne la possibilit de choisir le niveau alpha, alors qu'il n'est pas utile. De mme, les couleurs avec alpha apparassent avec un aperu montrant la composante alpha dans les menus n'ayant pas de composante alpha. Il serait souhaitable de pouvoir rgler la gamme de variation des rayons atomiques ainsi que les longueurs accessibles pour les liaisons. En effet pour une bote dont la taille caractristique est en 1e-5, les bornes par dfauts sont inadaptes par exemple. Lorsqu'on utilise le navigateur alors que le panneau de liaisons est affich, aprs un ou deux chagement de fichiers on obtient un crash et parfois des erreurs lors d'appels la fonction free . Dans le panneau data color , il n'y a pas de conversion de la locale du systme de fichier vers l'UTF-8 pour l'affichage du nom du fichier dans la barre d'tat. Les valeurs des paramtres des liaisons ne sont pas mis jour lorsque des ressources sont recharges. La partie spcifique dans la fentre des liaisons, n'est pas remise jour non plus. Quand la valeur de la perspective est trs lev, la zone de variation du brouillard semble contracte par rapport une valeur plus classique de la perspective. Quand on charge un fichier de ressources posteriori, les atomes du fichier visualis disparaissent et on ne peut plus les afficher mme en changeant leur rayon, il faut recharger le fichier. Aprs une exportation en image, le nom des axes disparat (pas toujours du premier coup). Il faut recharger d'autres fichiers pour faire apparatre ce bug. Tout est dans le titre. Sous Windows uniquement, le nom des axes ne s'affiche pas, ni l'cran, ni l'exportation. Il n'y a pas d'ascenseur horizontal dans la fentre sur les liaisons ce qui rend le bouton de couleur difficilement cliquable quand les noms des espces sont plutt grands. Lors d'une session observe, le clic droit ne permet plus de passer une session pick : il ne se passe plus rien. Lors de l'initialisation de la fentre X et du processus OpenGL, les messages d'erreur d'initialisation indiquent une erreur note INTERNAL ERROR , ce qui est incorrect. Il serait plus adapt de mettre un message sur l'incompatibilit du serveur X et de V_Sim en dtaillant que l'extension GLX n'est pas active par exemple. Idem. Dans le navigateur de fichier la bulle d'aide de la liste des fichiers a une faute d'orthographe sur le mot selected. Il existe encore une chane visu_gl_gtk dans la bulle d'aide de la fentre enregistrer pour la case cocher du fichier de paramtre. Lorsque quelques fichiers seulement sont slectionns dans le navigateur et qu'on clique sur le bouton exporter en image tous les fichiers slectionns , le systme exporte bien l'ensemble des fichiers slectionns mais il les exporte autant de fois qu'il y a de fichier en tout dans la liste. Si on baisse le rayon avec le bouton spin en laissant appuy la souris, quand on arrive zro le programme affiche un warning comme quoi on a essay de mettre une valeur ngative. Le nombre de dcimales (2) pour spcifier les distances min et max des paires traces me parat trop petit pour distinguer les variations de longueurs dans Si avec 1 Ge... Il serait pratique que la case cocher pour tracer ou non les paires existe aussi sur le panneau de contrle du trac des dtes paires. Les chanes de caractres passes aux fentres d'alerte ne sont pas UTF8 cause des noms de fichiers. Avec la mise jour automatique, si on ramne un fichier zro atome, v_sim sort sur un chec d'allocation. Mettre des raccoursis claviers sur l'ensembles des options cocher et faire qu'elles soient accessibles mme sur la fentre de rendu. Pouvoir dtecter automatiquement si les fichiers d3 sont en little ou en big endian. Si on dmarre V_Sim avec l'option rechargement automatique, la case dans le panel de configuration est bien coch mais le chargement automatique ne se fait pas, il faut dcocher et recocher pour que a fonctionne. On ne peut pas spcifier en ligne de commande la taille de la fentre de rendu. Lors d'une observation, il serait souhaitable de pouvoir faire tourner la bote aussi selon des directions propres l'cran et non seulement propres la bote. Mettre une explication permettant de comprendre qu'il faut double cliquer sur un nom de fichier dans le navigateur pour le faire afficher. Le fait d'utiliser les valeurs HSV comme coefficients pour chaque couleur de liaison dfinie par l'utilisateur n'est pas claire et devrait tre remplac par les valeurs HSV seules. L'option --export n'est pas reconnue. Des carrs en vido inverse (comme ceux permettant de reprer les rfrences) apparaissent dans une session pick quand la vue change suite une action extrieure comme le rechargement automatique du fichier par exemple. Cliquer sur le bouton rafrachir alors qu'on vient de quitter une session pick positionne les atomes n'importe o. v_sim-3.8.0/configure.ac000066400000000000000000000507341370110300500151240ustar00rootroot00000000000000dnl Process this file with autoconf to produce a configure script. dnl Every `configure' script must call `AC_INIT' dnl $package is the name of the program dnl $version is its number dnl $bugreport is an email dnl $tarname is used to call the directories, ... related to the program AC_INIT([V_Sim], [3.8.0], [damien D caliste AT cea D fr], [v_sim]) dnl Versioning V_SIM_MAJOR_VERSION=$(echo $PACKAGE_VERSION | cut -d'.' -f1) V_SIM_MINOR_VERSION=$(echo $PACKAGE_VERSION | cut -d'.' -f2) V_SIM_MICRO_VERSION=$(echo $PACKAGE_VERSION | cut -d'.' -f3) AC_SUBST(V_SIM_MAJOR_VERSION) AC_SUBST(V_SIM_MINOR_VERSION) AC_SUBST(V_SIM_MICRO_VERSION) dnl Some variables lib_v_sim_version=$V_SIM_MINOR_VERSION":0" AC_SUBST(lib_v_sim_version) need_cpp_compiler="no" dnl Save this value here, since automake will set cflags later cflags_set=${CFLAGS} cxxflags_set=${CXXFLAGS} dnl Initialize automake with same $package and $version AM_INIT_AUTOMAKE([subdir-objects]) dnl Use a config.h file to store macro definitions AM_CONFIG_HEADER(config.h) AC_CONFIG_MACRO_DIR([m4]) dnl Outputing some informations date="2020-07-07" AC_MSG_NOTICE([Compiling $PACKAGE_NAME]) AC_MSG_NOTICE([$PACKAGE_TARNAME $PACKAGE_VERSION $date]) dnl Set the default prefix AC_PREFIX_DEFAULT([/usr/local]) AC_MSG_CHECKING([for instalation directory]) AC_MSG_RESULT([$prefix]) dnl Starting of consistency checks dnl ------------------------------ dnl cherche un compilateur C dnl set the CC variable AC_PROG_CC dnl set the CXX variable AC_PROG_CXX dnl set the FC variable AC_PROG_F77 AC_PROG_FC dnl If GCC is used, then we define the flag not to tag unused parameters. if test "$GCC" = "yes" ; then AC_DEFINE([_U_], [__attribute((unused))], [Tag this parameter as unused.]) fi dnl Using libtool to handle libraries AC_CHECK_TOOL(LIBTOOL, libtool, :) if test "$libtool" = ":" ; then AC_MSG_ERROR(["No 'libtool' program found."]) fi AC_LIBTOOL_WIN32_DLL AC_PROG_LIBTOOL dnl check for platform AC_MSG_CHECKING([for target architecture]) case x"$target" in xNONE | x) target_or_host="$host" ;; *) target_or_host="$target" ;; esac AC_MSG_RESULT(['$target_or_host']) AC_MSG_CHECKING([for platform]) define_win32=0 define_X11=1 case "$target_or_host" in i686-w64-mingw32) platform=win32 define_win32=1 define_X11=0 EXEEXT=.exe FONT_NORMAL="Sans" FONT_BOLD="Sans bold" EXTRA_LDFLAGS="-no-undefined" EXTRA_CFLAGS="-mms-bitfields" EXTRA_LIBS="-lintl" ;; *-mingw* | *-*-cygwin*) platform=win32 define_win32=1 define_X11=0 EXEEXT=.exe FONT_NORMAL="Sans" FONT_BOLD="Sans bold" EXTRA_LDFLAGS="-no-undefined" EXTRA_CFLAGS="-mms-bitfields -mno-cygwin" EXTRA_LIBS="-lintl" ;; *-apple-darwin*) platform=Apple define_X11=1 define_win32=0 EXEEXT= FONT_NORMAL="Nimbus normal" FONT_BOLD="Nimbus bold" EXTRA_LDFLAGS= EXTRA_LIBS="-dylib_file /System/Library/Frameworks/OpenGL.framework/Versions/A/Libraries/libGL.dylib:/System/Library/Frameworks/OpenGL.framework/Versions/A/Libraries/libGL.dylib" EXTRA_CFLAGS= ;; *) platform=X11 define_X11=1 define_win32=0 EXEEXT= FONT_NORMAL="Nimbus normal" FONT_BOLD="Nimbus bold" EXTRA_LDFLAGS= EXTRA_CFLAGS= ;; esac AC_MSG_RESULT([$platform]) AC_SUBST(FONT_NORMAL) AC_SUBST(FONT_BOLD) AC_SUBST(EXTRA_LDFLAGS) AC_SUBST(EXTRA_CFLAGS) AC_SUBST(EXTRA_LIBS) AC_SUBST(EXEEXT) AM_CONDITIONAL(PLATFORM_X11, test "$define_X11" = "1") AM_CONDITIONAL(PLATFORM_WIN32, test "$define_win32" = "1") AM_CONDITIONAL(BUILD_STATIC_BINARY, test "$define_X11" = "1") AM_CONDITIONAL(BUILD_SHARED_BINARY, test "$define_win32" = "1") dnl Check the GL header and lib. if test x"$platform" = x"Apple" ; then LIBS_SVG="$LIBS" LIBS="$EXTRA_LIBS $LIBS" fi AX_CHECK_GL() if test x"$no_gl" = x"yes" ; then AC_MSG_ERROR(["No GL implementation (header or library issues)."]) fi dnl Check the GLU header and lib. AX_CHECK_GLU() if test x"$no_glu" = x"yes" ; then AC_MSG_ERROR(["No GLU implementation (header or library issues)."]) fi if test x"$platform" = x"Apple" ; then LIBS="$LIBS_SVG" fi dnl Look for FTGL PKG_CHECK_MODULES(FTGL, ftgl, [have_ftgl=yes], [have_ftgl=no]) if test x"$have_ftgl" = x"yes" ; then AC_DEFINE([HAVE_FTGL], [], [If set, we can call FTGL.h]) fi dnl Check the GLX header on Unix platform. if test x"$platform" != x"win32" ; then ac_save_CPPFLAGS="${CPPFLAGS}" CPPFLAGS="${GL_CFLAGS} ${CPPFLAGS}" AC_CHECK_HEADER([GL/glx.h], [glxh="yes"], [glxh="no"]) CPPFLAGS="${ac_save_CPPFLAGS}" if test "$glxh" = "no" ; then AC_MSG_ERROR(["No 'GL/glx.h' header file."]) fi dnl Test the Pbuffer availability. LIBS_SVG="$LIBS" LIBS="$LIBS $GLU_LIBS" AC_CHECK_FUNCS([glXChooseFBConfig glXGetVisualFromFBConfig glXCreatePbuffer], [], [ac_have_pbuffer=no]) LIBS="$LIBS_SVG" if test x"$ac_have_pbuffer" != x"no" ; then AC_DEFINE([HAVE_PBUFFER], [1], ["Will use Pbuffer from GLX 1.3 for pixmap rendering."]) fi fi dnl Add the languages which your application supports here. AC_PROG_INTLTOOL([0.35.0]) GETTEXT_PACKAGE=$PACKAGE_TARNAME AC_SUBST(GETTEXT_PACKAGE) AC_DEFINE_UNQUOTED(GETTEXT_PACKAGE,"$GETTEXT_PACKAGE", [Gettext package.]) AM_GLIB_GNU_GETTEXT dnl checking for glib and gtk if test x"$platform" = x"win32" ; then if test -z "$PKG_CONFIG_PATH" ; then export PKG_CONFIG_PATH=/usr/i686-w64-mingw32/lib/pkgconfig/ fi fi PKG_CHECK_MODULES(GLIB, glib-2.0 >= 2.2.0 gmodule-2.0 gobject-2.0 gthread-2.0) PKG_CHECK_MODULES(CAIRO, cairo, [have_cairo=yes], [have_cairo=no]) if test x"$have_cairo" = x"yes" ; then AC_DEFINE([HAVE_CAIRO], [], [If set, we can call cairo.h]) fi AC_ARG_WITH(gtk2, AS_HELP_STRING([--with-gtk2], [use Gtk2 instead of Gtk3.]), [ac_required_gtk="gtk+-2.0 >= 2.4.0"], [ac_required_gtk="gtk+-3.0 >= 3.0.2"]) opengl="built-in" dnl Look for gtkglext support and create the GTKS_CFLAGS and GTKS_LIBS variables. AC_ARG_WITH(gtkglext, AS_HELP_STRING([--with-gtkglext], [use GtkGlExt as rendering surface for OpenGl.]), [WITH_GTK_GL_EXT=$withval], [WITH_GTK_GL_EXT=""]) if test -n "$WITH_GTK_GL_EXT" -a "$WITH_GTK_GL_EXT" != "no" ; then PKG_CHECK_MODULES(GTKS, gtkglext-1.0 >= 1.0.0 glib-2.0 >= 2.2.0 ${ac_required_gtk} gmodule-2.0 gobject-2.0 gthread-2.0) opengl="GtkGlExt" AC_DEFINE([HAVE_GTKGLEXT], [], [If set, we can call gtkgl.h]) fi AM_CONDITIONAL(OPENGL_BUILTIN_WIN32, test "$define_win32" = "1") AM_CONDITIONAL(OPENGL_BUILTIN_X11, test "$define_X11" = "1" -a "$opengl" = "built-in") AM_CONDITIONAL(OPENGL_GTKGLEXT, test "$define_X11" = "1" -a "$opengl" = "GtkGlExt") if test "$opengl" != "GtkGlExt" ; then PKG_CHECK_MODULES(GTKS, glib-2.0 >= 2.2.0 ${ac_required_gtk} gmodule-2.0 gobject-2.0 gthread-2.0) dnl Add -lX11 if missing. if test "$define_X11" = "1" ; then lx="False" for fl in $GLU_LIBS ; do if test x"$fl" = x"-lX11" ; then lx="True" fi done if test x"$lx" = x"False" ; then GLU_LIBS=$GLU_LIBS" -lX11" fi fi fi dnl C-level YAML support. AX_YAML() if test x"$ax_have_yaml" != x"yes" ; then AC_MSG_WARN([libyaml is not available.]) else AC_DEFINE([HAVE_YAML], [], [If set, we can call yaml.h]) fi dnl Python bindings AC_ARG_ENABLE(python-module, AS_HELP_STRING([--enable-python-module], [create a Python module.]), [enable_python=$enableval], [enable_python="no"]) if test -n "$enable_python" -a "$enable_python" != "no" ; then AM_PATH_PYTHON(2.3.5) AM_CHECK_PYTHON_HEADERS(,[AC_MSG_ERROR(could not find Python headers)]) py_prefix=`$PYTHON -c "import sys; print sys.prefix"` PYTHON_INCLUDES="-I${py_prefix}/include/python${PYTHON_VERSION}" PKG_CHECK_MODULES(PYGTK, pygobject-2.0 pygtk-2.0, [have_pygtk=yes], [have_pygtk=no]) if test x"$have_pygtk" = x"yes" ; then AC_DEFINE([HAVE_PYGTK], [], [If set, we can call pygtk.h]) else AC_MSG_WARN([header files for pygtk not installed.]) enable_python="no" fi fi AM_CONDITIONAL(PYTHON_MODULE, test x"$enable_python" = x"yes") dnl Customization of V_Sim AC_MSG_CHECKING([for debug message]) with_debug_messages=no define_debug=0 AC_ARG_ENABLE(debug-messages, AS_HELP_STRING([--enable-debug-messages], [compile V_Sim with all the debug strings, it is very verbose (default=no).]), with_debug_messages=$enableval, with_debug_messages=no) AC_MSG_RESULT([$with_debug_messages]) if test "$with_debug_messages" = "yes" ; then define_debug=1 AC_MSG_WARN([--enable-debug-messages... are you sure, this is very verbose?]) fi dnl Building the doc GTK_DOC_CHECK([1.3]) dnl Test for plug-ins compilation dnl ----------------------------- dnl Nanoquanta netcdf format AC_MSG_CHECKING([for ETSF file format support]) AC_ARG_WITH(etsf_file_format, AS_HELP_STRING([--with-etsf-file-format], [compile plug-in support for files that follow the ETSF specifications for structural positions and densities (default=no).]), [have_etsf=yes], [have_etsf=no]) AC_ARG_WITH(nanoquanta, AS_HELP_STRING([--with-nanoquanta], [deprecated, use --with-etsf-file-format instead (default=no).]), [have_nanoquanta=$withval], [have_nanoquanta=no]) if test x"$have_nanoquanta" = x"yes" ; then have_etsf="yes" fi AC_MSG_RESULT([$have_etsf]) if test x"$have_nanoquanta" = x"yes" ; then AC_MSG_WARN(["--with-nanoquanta is deprecated, use --with-etsf-file-format instead."]) fi if test "$have_etsf" = "yes" ; then AC_CHECK_NETCDF([netcdf="yes"], [netcdf="no"], [3]) if test "$netcdf" = "yes" ; then have_etsf="yes" else AC_MSG_WARN(["No 'netcdf.h' header file, libetsf.so will not be built."]) have_etsf="no" fi fi AM_CONDITIONAL(HAVE_ETSF, test x"$have_etsf" = x"yes") dnl OpenBabel wrapper AC_MSG_CHECKING([for OpenBabel support]) AC_ARG_WITH(openbabel, AS_HELP_STRING([--with-openbabel], [compile plug-in support for a wrapper around the OpenBabel library (default=no).]), [have_openbabel=$withval], [have_openbabel=no]) AC_MSG_RESULT([$have_openbabel]) if test "$have_openbabel" = "yes" ; then PKG_CHECK_MODULES([OPENBABEL], [openbabel-3 >= 3.0.0], [ob=yes], [ob=no]) if test "$ob" = "yes" ; then have_openbabel="yes" need_cpp_compiler="yes" else AC_MSG_WARN(["No OpenBabel lib/header file found, libobloader.so will not be built."]) AC_MSG_WARN(["Maybe OpenBabel is not installed or version is to old (>=3.0 required)."]) have_openbabel="no" fi fi AM_CONDITIONAL(HAVE_OPENBABEL, test x"$have_openbabel" = x"yes") dnl XCrysDen file format have_xsf="no" AC_ARG_WITH(xsf, AS_HELP_STRING([--with-xsf], [compile plug-in support for files that follow the XCrysDen format for structural positions and densities (default=no).]), [have_xsf=$withval], [have_xsf=no]) AC_MSG_CHECKING([for XCrysDen file support]) AC_MSG_RESULT([$have_xsf]) AM_CONDITIONAL(HAVE_XSF, test x"$have_xsf" = x"yes") dnl Cube file format have_cube="yes" AC_ARG_WITH(cube, AS_HELP_STRING([--without-cube], [compile plug-in support for Cube files (densities and structures) (default=yes).]), [have_cube=$withval], [have_cube=no]) AC_MSG_CHECKING([for Cube file support]) AC_MSG_RESULT([$have_cube]) AM_CONDITIONAL(HAVE_CUBE, test x"$have_cube" = x"yes") dnl ABINIT input file ac_abinit="no" AC_CHECK_ABINIT() if test x"$ac_abinit_parser" = x"yes" ; then AC_DEFINE_UNQUOTED(AB_LIBRARY_VERSION, $AB_LIBRARY_VERSION, [ABINIT library version number.]) AC_DEFINE_UNQUOTED(HAVE_ABINIT_PARSER, "$ac_abinit_parser", [Compile the ABINIT parser part for static linking.]) fi AM_CONDITIONAL(HAVE_ABINIT_PARSER, test x"$ac_abinit_parser" = x"yes") AC_SUBST(AB_CPPFLAGS) AC_SUBST(AB_LIBS) AM_CONDITIONAL(HAVE_ABINIT, test x"$ac_abinit" = x"yes") dnl libmsym point group symmetry library AC_CHECK_MSYM() AC_SUBST(MSYM_CPPFLAGS) AC_SUBST(MSYM_LIBS) AM_CONDITIONAL(BUILTIN_MSYM, test x"$ac_msym" = x"builtin") AM_CONDITIONAL(HAVE_MSYM, test x"$ac_msym" = x"yes" -o x"$ac_msym" = x"builtin") dnl Archive input file support ac_archives="yes" AC_ARG_WITH([archives], AS_HELP_STRING([--without-archives], [add support of compression for input files (default=yes).]), [ac_archives=$withval], [ac_archives=yes]) if test x"$ac_archives" = x"yes" ; then PKG_CHECK_MODULES([LIB_ARCHIVE], [libarchive >= 2.8], [ac_archives=yes], [ac_archives=no]) if test x"$ac_archives" = x"yes" ; then AC_DEFINE([HAVE_LIB_ARCHIVE], [1], [libarchive is linkable.]) else AC_MSG_WARN([libarchive is not available]) fi fi AM_CONDITIONAL(HAVE_LIB_ARCHIVE, test x"$ac_archives" = x"yes") AC_SUBST(LIB_ARCHIVE_CFLAGS) AC_SUBST(LIB_ARCHIVE_LIBS) dnl CrystalFp library support ac_crystalfp="no" AC_ARG_WITH([crystal-fp], AS_HELP_STRING([--with-crystal-fp], [add support crystal fingerprint calculation.]), [ac_crystalfp=$withval], [ac_crystalfp=no]) if test x"$ac_crystalfp" != x"no" ; then CRYSTALFP_CXXFLAGS="-I$ac_crystalfp" CRYSTALFP_LIBS="-L$ac_crystalfp -lCrystalFp" ac_crystalfp="yes" fi AM_CONDITIONAL(HAVE_CRYSTALFP, test x"$ac_crystalfp" = x"yes") AC_SUBST(CRYSTALFP_CXXFLAGS) AC_SUBST(CRYSTALFP_LIBS) dnl BigDFT support ac_bigdft="no" AX_CHECK_BIGDFT() AC_SUBST(BIGDFT_CPPFLAGS) AC_SUBST(BIGDFT_LIBS) AM_CONDITIONAL(HAVE_BIGDFT, test x"$ac_bigdft" = x"yes") dnl Add Introspection capabilities GOBJECT_INTROSPECTION_REQUIRED=0.9.0 AC_SUBST(GOBJECT_INTROSPECTION_REQUIRED) PYGOBJECT_REQUIRED=2.21.0 AC_SUBST(PYGOBJECT_REQUIRED) AC_ARG_ENABLE([introspection], AS_HELP_STRING([--disable-introspection], [disable GObject introspection]), [], [enable_introspection=yes]) if test "x$enable_introspection" != "xno" ; then dnl if test "x$ac_required_gtk" != "xgtk+-3.0 >= 2.90.2" ; then dnl AC_MSG_ERROR(["GTK+ 3.0 is required for introspection."]) dnl fi PKG_CHECK_MODULES([GOBJECT_INTROSPECTION], [gobject-introspection-1.0 >= $GOBJECT_INTROSPECTION_REQUIRED], [enable_introspection=yes], [enable_introspection=no]) PKG_CHECK_MODULES([PYGOBJECT], [pygobject-3.0 >= $PYGOBJECT_REQUIRED], [], [enable_introspection=no]) fi if test "x$enable_introspection" = "xyes" ; then girdir=$($PKG_CONFIG --variable=girdir gobject-introspection-1.0) AC_DEFINE([WITH_GOBJECT_INTROSPECTION], [1], [enable GObject introspection support]) AC_SUBST(GOBJECT_INTROSPECTION_CFLAGS) AC_SUBST(GOBJECT_INTROSPECTION_LIBS) AC_SUBST([G_IR_SCANNER], [$($PKG_CONFIG --variable=g_ir_scanner gobject-introspection-1.0)]) AC_SUBST([G_IR_COMPILER], [$($PKG_CONFIG --variable=g_ir_compiler gobject-introspection-1.0)]) dnl Add Python support for the PythonGI plug-in. AM_PATH_PYTHON(2.3) AM_CHECK_PYTHON_HEADERS(,[AC_MSG_ERROR(could not find Python headers)]) PYTHON_INCLUDES="`python-config --cflags`" AC_SUBST(PYTHON_INCLUDES) PYTHON_LIBS="`python-config --libs`" AC_SUBST(PYTHON_LIBS) AC_MSG_CHECKING(for pygobject overrides directory) overrides_dir="`$PYTHON -c 'import gi; print(gi._overridesdir)' 2>/dev/null`" # fallback if the previous failed if test "x$overrides_dir" = "x" ; then overrides_dir="${pyexecdir}/gi/overrides" fi if ! test -w $overrides_dir ; then overrides_dir=${libdir}/python$PYTHON_VERSION/dist-packages/gi/overrides fi AC_MSG_RESULT($overrides_dir) else overrides_dir=${libdir}/python$PYTHON_VERSION/dist-packages/gi/overrides fi AM_CONDITIONAL([WITH_GOBJECT_INTROSPECTION], [test "x$enable_introspection" = "xyes"]) dnl AC_PROG_CC set the CC variable and detect if we use the GNU compiler dnl We now append some various CFLAGS depending on platform and choice dnl of the user. AC_ARG_WITH(strict-cflags, AS_HELP_STRING([--with-strict-cflags], [if set or absent some correctness cflags are appended to the CFLAGS variable. Appended values dependent on the platform and code branch (default on Unix for development is Wall Wno-unused W Werror ansi pedantic-errors).]), [STRICT_CFLAGS=$withval], [STRICT_CFLAGS="no"]) flags='Wall W ansi' flags_cpp='Wall W ansi' if test "$GCC" = "yes" -a "$STRICT_CFLAGS" = "yes"; then flags=$flags' Werror Wpedantic std=c99' flags_cpp=$flags_cpp' Werror Wpedantic' fi for fl in $flags ; do case " $CFLAGS " in *[\ \ ]-$fl[\ \ ]*) ;; *) CFLAGS="$CFLAGS -$fl" ;; esac done for fl in $flags_cpp ; do case " $CXXFLAGS " in *[\ \ ]-$fl[\ \ ]*) ;; *) CXXFLAGS="$CXXFLAGS -$fl" ;; esac done AC_MSG_CHECKING([for CFLAGS used]) AC_MSG_RESULT([$CFLAGS]) AC_MSG_CHECKING([for CXXFLAGS used]) AC_MSG_RESULT([$CXXFLAGS]) dnl compatibility for very old version of autotools if test -z "$docdir" ; then docdir="$datadir/doc/$PACKAGE" fi dnl default installation directories v_simexedir="$bindir" AC_SUBST(v_simexedir) v_simresourcesdir="$datadir/$PACKAGE" AC_SUBST(v_simresourcesdir) v_simpixmapsdir="$datadir/$PACKAGE/pixmaps" AC_SUBST(v_simpixmapsdir) v_simiconsdir="$datadir/pixmaps" AC_SUBST(v_simiconsdir) v_simlegaldir="${docdir}" AC_SUBST(v_simlegaldir) v_simexamplesdir="${docdir}/examples" AC_SUBST(v_simexamplesdir) v_simpluginsdir="$libdir/$PACKAGE/plug-ins" AC_SUBST(v_simpluginsdir) v_simgirdir="$datadir/gir-1.0" AC_SUBST(v_simgirdir) v_simtypelibsdir="$libdir/girepository-1.0" AC_SUBST(v_simtypelibsdir) v_simoverridesdir=$overrides_dir AC_SUBST(v_simoverridesdir) dnl Values of flags AC_DEFINE_UNQUOTED(DEBUG, $define_debug, [Compile V_Sim in debug mode, very verbose.]) AC_DEFINE_UNQUOTED(SYSTEM_WIN32, $define_win32, [Target platform.]) AC_DEFINE_UNQUOTED(SYSTEM_X11, $define_X11, [Target platform.]) AC_DEFINE_UNQUOTED(V_SIM_RELEASE_DATE, "$date", [Date of version release.]) AC_OUTPUT([ Makefile src/Makefile lib/plug-ins/Makefile lib/plug-ins/nanoquanta-netcdf/Makefile lib/plug-ins/OpenBabel-wrapper/Makefile lib/plug-ins/xsf/Makefile lib/plug-ins/cube/Makefile lib/plug-ins/abinit/Makefile lib/plug-ins/python-gi/Makefile lib/plug-ins/archives/Makefile lib/plug-ins/bigdft/Makefile lib/plug-ins/fpcrystal/Makefile lib/plug-ins/msym/Makefile lib/python/Makefile lib/Makefile etc/Makefile etc/v_sim.rc etc/v_sim.ini pixmaps/Makefile examples/Makefile po/Makefile.in Documentation/Makefile Documentation/reference/Makefile Documentation/reference/version tests/Makefile tests/core/Makefile ]) echo " Configuration: Source code location: ${srcdir} Destination path prefix: ${prefix} Compiler: ${CC} CFLAGS: ${CFLAGS} LDFLAGS: ${LDFLAGS} GLIB-part CFLAGS: ${GLIB_CFLAGS} GLIB-part LIBS: ${GLIB_LIBS} GTKS-part CFLAGS: ${GTKS_CFLAGS} GTKS-part LIBS: ${GTKS_LIBS} OpenGL: ${opengl} | CFLAGS: ${GLU_CFLAGS} | LIBS: ${GLU_LIBS} | FTGL LIBS: ${FTGL_LIBS} Enable debug messages: ${with_debug_messages} Enable gtk-doc: ${enable_gtk_doc} Enable introspection: ${enable_introspection} Plug-ins: With Nanoquanta support: ${have_etsf}" if test "$have_etsf" = "yes" ; then echo \ " | CFLAGS: ${NC_CFLAGS} | LDFLAGS LIBS: ${NC_LDFLAGS} ${NC_LIBS}" fi echo " With OpenBabel support: ${have_openbabel}" if test "$have_openbabel" = "yes" ; then echo \ " | CFLAGS: ${OPENBABEL_CFLAGS} | LDFLAGS LIBS: ${OPENBABEL_LIBS}" fi echo " With ABINIT support: ${ac_abinit}" if test "$ac_abinit" = "yes" ; then echo \ " | Input file support ${ac_abinit_parser} | Symmetry analyser built-in | CFLAGS: ${AB_CPPFLAGS} | LDFLAGS LIBS: ${AB_LIBS}" fi echo " With XCrysDen support: ${have_xsf} With Cube support: ${have_cube} With Python scripting: ${enable_introspection}" if test "${enable_introspection}" = "yes" ; then echo \ " | CFLAGS: ${PYTHON_INCLUDES} | LDFLAGS LIBS: ${PYTHON_LIBS}" fi echo " With archive support : ${ac_archives}" if test "${ac_archives}" = "yes" ; then echo \ " | CFLAGS: ${LIB_ARCHIVE_CFLAGS} | LDFLAGS LIBS: ${LIB_ARCHIVE_LIBS}" fi echo " With BigDFT support : ${ac_bigdft}" if test "${ac_bigdft}" = "yes" ; then echo \ " | CFLAGS: ${BIGDFT_CPPFLAGS} | LDFLAGS LIBS: ${BIGDFT_LIBS}" fi echo " With CrystalFp lib : ${ac_crystalfp}" if test "${ac_crystalfp}" = "yes" ; then echo \ " | CXXFLAGS: ${CRYSTALFP_CXXFLAGS} | LDFLAGS LIBS: ${CRYSTALFP_LIBS}" fi echo " With msym lib : ${ac_msym}" if test "${ac_msym}" = "yes" ; then echo \ " | CPPFLAGS: ${MSYM_CPPFLAGS} | LDFLAGS LIBS: ${MSYM_LIBS}" fi echo \ " Plug-ins options: Need a C++ compiler: ${need_cpp_compiler}" if test "$need_cpp_compiler" = "yes" ; then echo \ " | compiler: ${CXX} | CXXFLAGS: ${CXXFLAGS} " fi v_sim-3.8.0/etc/000077500000000000000000000000001370110300500134005ustar00rootroot00000000000000v_sim-3.8.0/etc/Makefile.am000066400000000000000000000003731370110300500154370ustar00rootroot00000000000000## Makefile.am for v_sim/etc if PLATFORM_WIN32 inifile = v_sim.ini endif v_simexe_DATA = $(inifile) v_simresources_DATA = \ v_sim.res \ v_sim.par \ v_sim.rc EXTRA_DIST = \ v_sim.ini.in \ v_sim.res v_sim.par \ v_sim.rc.in v_sim-3.8.0/etc/v_sim.ini.in000066400000000000000000000003341370110300500156230ustar00rootroot00000000000000[paths] data_dir = ..\share\@PACKAGE@ conf_dir = ..\share\@PACKAGE@ legal_dir = ..\share\doc\@PACKAGE@ pixmaps_dir = ..\share\@PACKAGE@\pixmaps plugins_dir = ..\lib\@PACKAGE@\plug-ins locale_dir = ..\share\locale v_sim-3.8.0/etc/v_sim.par000066400000000000000000000051651370110300500152300ustar00rootroot00000000000000#V_Sim parameters file v3.0 #==================== #WARNING: this file format is DIFFERENT from that for #standard v_sim version <= 2.x #Line beginning with a # are not parsed. #The only "useful" lines must have the following pattern: #parameter_name: value #The following parameter names are valid : # main_resourcesPath # opengl_trueTransparency # opengl_antialias # opengl_immediateDrawing # opengl_stereoAngle # opengl_stereo # opengl_render # opengl_details # opengl_observe_method # extension_render # rendering_favoriteMethod # atomic_sphere_method # scale_log_threshold # main_usePreview # main_confirmQuit # main_panelStatus # main_dock # browser_headersVisibility # browser_dateVisibility # dataFile_fileExtension # config_subPanelTabView # config_skin # config_refreshIsOn # config_refreshPeriod # presetShade # Favorite paths to find and save the resources file ; chain[:chain] main_resourcesPath: # If true, lines are drawn smoother ; boolean 0 or 1 opengl_antialias: 1 # If true, changes of parameters means immediate redrawing ; boolean 0 or 1 opengl_immediateDrawing: 1 # If true, the transparency rendering is enhanced ; boolean 0 or 1 opengl_trueTransparency: 0 # If true, try to draw in stereo ; boolean 0 or 1 opengl_stereo: 0 # Give the angle of the two receivers in stereo output ; float positive opengl_stereoAngle: 5.000000 # Give a value to the quality of rendering (100 is normal) ; positive integer opengl_details: 100 # Choose the observe method ; integer (0: constrained mode, 1: walker mode) opengl_observe_method[gtk]: 0 # The sphere drawing method, [GluSphere Icosahedron] atomic_sphere_method: GluSphere # Value of the threshold used in the zero centred logarithm scaling function ; a positive float (1e-3) scale_log_threshold: 0.001000 # Automatically compute preview in filechooser ; boolean main_usePreview[gtk]: 1 # Show up a dialog to confirm when quit button is clicked ; boolean 0 or 1 main_confirmQuit[gtk]: 1 # Show or hide the headers in the treeview ; boolean 0 or 1 browser_headersVisibility[gtk]: 0 # Show or hide the date column in the treeview ; boolean 0 or 1 browser_dateVisibility[gtk]: 0 # The extension used for data file ; chain e.g. '.dat' dataFile_fileExtension[gtk]: .dat # See or not the labels on tabs ; boolean 0 or 1 config_subPanelTabView[gtk]: 0 # Path to a gtkrc file ; chain config_skin[gtk]: None # When on V_Sim reloads the file at periodic time ; boolean 0 or 1 config_refreshIsOn[gtk]: 0 # The period of reloading in s ; integer (0 < v <= 10) config_refreshTimeout[gtk]: 1 # The id of a shade used as preset one in the shade selectors ; an integer ranging from 0 presetShade[gtk]: 0 v_sim-3.8.0/etc/v_sim.rc.in000066400000000000000000000217461370110300500154620ustar00rootroot00000000000000#v_sim.rc #this private file is used to set style ################################################################ style "fnt" { font_name = "@FONT_NORMAL@" } style "fnt_small" { font_name = "@FONT_NORMAL@" } ################################################################ style "fixed_bold" = "fnt_bold" { fg[NORMAL] = {0.00, 0.00, 0.00} fg[INSENSITIVE] = {0.50, 1.00, 0.50} } style "fixed" = "fnt" { fg[NORMAL] = {0.00, 0.00, 0.00} } ################################################################ # General redefinition style "main_window" { bg[NORMAL] = {1.00, 0.75, 0.60} bg[ACTIVE] = {0.90, 0.75, 0.60} bg[INSENSITIVE] = {1.00, 0.75, 0.60} } style "statusbar" { bg[NORMAL] = {1.00, 0.85, 0.75} } style "toolbar" { bg[NORMAL] = {0.90, 0.75, 0.60} } style "button" = "fnt" { bg[NORMAL] = {0.4, 0.4, 0.4} fg[NORMAL] = {0.6, 0.6, 0.6} bg[PRELIGHT] = {0.5, 0.3, 0.5} fg[PRELIGHT] = {0.5, 1.0, 0.5} bg[ACTIVE] = {0.7, 0.5, 0.7} fg[ACTIVE] = {0.5, 1.0, 0.5} bg[INSENSITIVE] = {1.00, 0.75, 0.60} fg[INSENSITIVE] = {0.70, 0.45, 0.20} } style "vscrollbar" { bg[ACTIVE] = {0.8, 1.0, 1.0} bg[NORMAL] = {0.0, 0.0, 1.0} bg[PRELIGHT] = {0.3, 0.3, 1.0} } style "menu" = "fnt" { fg[NORMAL] = {0., 0., 0.} fg[PRELIGHT] = {0.4, 0.4, 0.4} bg[NORMAL] = {1.0, 0.85, 0.6} bg[PRELIGHT] = {0.6, 0.5, 0.3} } style "list" { base[NORMAL] = {0.90, 0.75, 0.70} } style "listitem" { bg[SELECTED] = {1.00, 0.85, 0.80} } style "label" = "fnt" { fg[NORMAL] = {0.60, 0.45, 0.40} fg[SELECTED] = {0.50, 0.35, 0.30} } style "entryCombo" = "fnt" { base[NORMAL] = {0.90, 0.90, 0.90} fg[NORMAL] = {0.30, 0.30, 0.30} } style "combo" = "fnt" { bg[NORMAL] = {0.80, 0.65, 0.40} bg[PRELIGHT] = {0.80, 0.65, 0.60} bg[ACTIVE] = {0.80, 0.65, 0.60} bg[SELECTED] = {0.80, 0.65, 0.60} bg[INSENSITIVE] = {0.90, 0.75, 0.50} base[NORMAL] = {0.80, 0.85, 0.80} fg[NORMAL] = {0.50, 0.35, 0.30} fg[SELECTED] = {0.50, 0.35, 0.30} } style "tog" = "fnt" { bg[NORMAL] = {1.00, 0.75, 0.60} bg[PRELIGHT] = {1.00, 0.85, 0.70} bg[ACTIVE] = {0.5, 0.2, 0.0} fg[NORMAL] = {0.5, 0.4, 0.3} fg[PRELIGHT] = {0.5, 0.2, 0.0} fg[ACTIVE] = {0.5, 0.2, 0.0} } style "radio" = "fnt" { bg[NORMAL] = {1.00, 0.75, 0.60} bg[PRELIGHT] = {1.00, 0.85, 0.70} bg[ACTIVE] = {0.5, 0.2, 0.0} fg[NORMAL] = {0.5, 0.4, 0.3} fg[PRELIGHT] = {0.5, 0.2, 0.0} fg[ACTIVE] = {0.5, 0.2, 0.0} } style "spin" = "fnt" { fg[NORMAL] = {1.0, 0.0, 0.0} fg[INSENSITIVE] = {0.9, 0.9, 0.0} bg[NORMAL] = {0.90, 0.75, 0.70} bg[PRELIGHT] = {1.0, 0.0, 1.0} bg[ACTIVE] = {1.0, 0.0, 0.0} bg[INSENSITIVE] = {0.1, 0.1, 0.1} } style "filesel" = "fnt" { bg[NORMAL] = {0.80, 0.80, 1.00} } ################################################################ style "message" { bg[NORMAL] = {0.75, 1.00, 0.75} bg[ACTIVE] = {0.67, 0.90, 0.67} } style "message_viewport" { bg[NORMAL] = {0.65, 0.85, 0.65} } style "message_ele" { bg[NORMAL] = {0.5, 0.85, 0.5} bg[PRELIGHT] = {0.5, 0.85, 0.5} bg[ACTIVE] = {0.5, 0.75, 0.5} fg[NORMAL] = {0.5, 0.4, 0.3} fg[PRELIGHT] = {0.5, 0.85, 0.5} fg[ACTIVE] = {0.8, 0.8, 0.8} } style "message_toolbar" = "fnt" { bg[NORMAL] = {0.85, 0.9, 0.85} } style "message_statusbar" { bg[NORMAL] = {0.85, 1.0, 0.85} } ################################################################ style "error" { bg[NORMAL] = {1.00, 0.85, 0.70} } #style "error_font" = "fnt" { # fg[NORMAL] = {0.00, 0.00, 0.00} #} style "error_button" = "fnt" { bg[NORMAL] = {1.0, 1.0, 0.0} bg[PRELIGHT] = {0.6, 1.0, 0.6} bg[ACTIVE] = {0.0, 1.0, 0.0} fg[NORMAL] = {0.00, 0.00, 0.00} } ################################################################ #style "working" { # bg[NORMAL] = {0.80, 0.80, 1.00} #} #style "working_inside" { # bg[NORMAL] = {0.90, 0.90, 1.00} #} #style "working_font" = "fnt" { # fg[NORMAL] = {0.00, 0.00, 0.00} #} ################################################################ style "subpanel_title" = "fnt" { fg[NORMAL] = {0.30, 0.00, 0.30} } style "message_title" = "fnt" { fg[NORMAL] = {0.8, 0.3, 0.1} } style "label_head" = "fnt" { fg[NORMAL] = {0.8, 0.3, 0.1} fg[INSENSITIVE] = {0.9, 0.9, 0.0} } style "label_head_2" = "fnt" { fg[NORMAL] = {0.80, 0.40, 0.30} fg[INSENSITIVE] = {0.9, 0.9, 0.0} } style "label_info" = "fnt" { fg[NORMAL] = {0.20, 0.20, 0.20} } style "label_error" = "fnt" { fg[NORMAL] = {0.8, 0.3, 0.1} } ################################################################ style "scroll_r" { bg[ACTIVE] = {.9, 0.2, 0.2} bg[NORMAL] = {0.7, 0.7, 0.7} bg[PRELIGHT] = {0.9, 0.9, 0.9} bg[INSENSITIVE] = {0.8, 0.5, 0.50} } style "scroll_g" { bg[ACTIVE] = {0.2, 0.9, 0.2} bg[NORMAL] = {0.7, 0.7, 0.7} bg[PRELIGHT] = {0.9, 0.9, 0.9} bg[INSENSITIVE] = {0.5, 0.8, 0.50} } style "scroll_b" { bg[ACTIVE] = {0.2, 0.2, 0.9} bg[NORMAL] = {0.7, 0.7, 0.7} bg[PRELIGHT] = {0.9, 0.9, 0.9} bg[INSENSITIVE] = {0.5, 0.5, 0.80} } style "scroll_mat" { bg[ACTIVE] = {0.5, 0.5, 0.5} bg[NORMAL] = {0.7, 0.7, 0.7} bg[PRELIGHT] = {0.9, 0.9, 0.9} } ################################################################ style "atoms_pairs" { bg[NORMAL] = {0.8, 0.8, 0.0} bg[INSENSITIVE] = {0.1, 0.1, 0.1} } style "atoms_pairs_inside" { bg[NORMAL] = {1.0, 1.0, 0.0} bg[INSENSITIVE] = {0.1, 0.1, 0.1} } style "tog_pairs" = "fnt" { bg[NORMAL] = {1.00, 1.0, 0.00} bg[PRELIGHT] = {0.90, 0.90, 0.20} bg[ACTIVE] = {0.5, 0.2, 0.0} fg[NORMAL] = {0.3, 0.3, 0.3} fg[PRELIGHT] = {0.1, 0.7, 0.1} fg[ACTIVE] = {0.0, 0.7, 0.0} } #style "label_names" = "fnt" { # fg[NORMAL] = {0.0, 0.0, 1.0} # fg[INSENSITIVE] = {0.9, 0.9, 0.0} #} ################################################################ style "save" { bg[NORMAL] = {1.0, 0.5, 1.0} } style "save_head" = "fnt_small" { fg[NORMAL] = {0.5, 0.0, 0.0} } style "tog_save_par_res" = "fnt_small" { bg[NORMAL] = {0.75, 1.00, 0.60} bg[PRELIGHT] = {0.85, 1.00, 0.70} bg[ACTIVE] = {0.2, 0.3, 0.0} fg[NORMAL] = {0.3, 0.1, 0.3} fg[PRELIGHT] = {0.2, 0.3, 1.0} fg[ACTIVE] = {0.0, 0.0, 1.0} } style "save_entry" = "fnt_small" { fg[NORMAL] = {0.0, 0.0, 1.0} fg[ACTIVE] = {0.0, 1.0, 0.0} fg[INSENSITIVE] = {0.75, 0.75, 0.75} } ################################################################ style "tooltips" = "fnt_small" { bg[NORMAL] = {0.4, 0.6, 0.6} } ################################################################ style "font_pb" { font = "fixed" } ################################################################ ################################################################ widget "*fixed_bold" style "fixed_bold" widget "*fixed" style "fixed" widget "GtkW*" style "combo" widget "*GtkWindow" style "main_window" widget "*GtkDialog" style "main_window" widget "*RenderingWindow" style "main_window" widget "*OpenGLWidget" style "main_window" widget "*VisuUiMain" style "main_window" widget "*GtkNotebook" style "main_window" widget "*GtkViewport" style "main_window" widget "*GtkEventBox" style "main_window" widget "*GtkStatusbar*" style "statusbar" widget "*GtkHandleBox*" style "statusbar" widget "*GtkVScrollbar*" style "vscrollbar" widget "*GtkHScrollbar*" style "vscrollbar" widget "*GtkMenu*" style "menu" widget "*GtkButton*" style "button" widget "*GtkColorButton*" style "button" widget "*GtkToggleButton*" style "button" class "GtkList" style "list" class "GtkListItem" style "listitem" class "GtkLabel" style "label" widget "*Combo*" style "combo" widget "*GtkComboBoxEntry*" style "entryCombo" widget "*GtkCheckButton" style "tog" widget "*GtkRadioButton*" style "tog" widget "*GtkSpinButton" style "spin" class "GtkFileSelection" style "filesel" class "GtkFileChooserDialog" style "filesel" class "GtkColorSelectionDialog" style "filesel" class "GtkToolbar" style "toolbar" widget "*gtk-tooltips*" style "tooltips" # specific elements widget "*subpanel_title" style "subpanel_title" widget "*message_title" style "message_title" widget "*label_head" style "label_head" widget "*label_head_2" style "label_head_2" widget "*label_info" style "label_info" widget "*label_error" style "label_error" widget "*scroll_r" style "scroll_r" widget "*scroll_g" style "scroll_g" widget "*scroll_b" style "scroll_b" widget "*scroll_mat" style "scroll_mat" # specific dialogs widget "*message" style "message" widget "*message_tog" style "message_ele" widget "*message_radio" style "message_ele" widget "*message_viewport" style "message_viewport" widget "*message_notebook" style "message_ele" widget "*message_notebook" style "message" widget "*message_toolbar" style "message_toolbar" widget "*message_statusbar*" style "message_statusbar" widget "*error" style "error" widget "*save" style "save" widget "*filesel" style "filesel" widget "*error_button*" style "error_button" widget "*save_head" style "save_head" widget "*save_entry" style "save_entry" widget "*tog_save_par_res*" style "tog_save_par_res" ################################################################ v_sim-3.8.0/etc/v_sim.res000066400000000000000000000167371370110300500152460ustar00rootroot00000000000000#V_Sim resources file v3.0 #==================== #WARNING: this file format is DIFFERENT from that for #standard v_sim version <= 2.x #Line beginning with a # are not parsed. #The only "useful" lines must have the following contents #several two or more lines patterns: #resource_name: #values separeted by blank characters #The following resource names are valid : # opengl_theta_phi_omega # opengl_xs_ys # opengl_gross # opengl_d_red # atomic_radius_shape # spin_resources # material # element_color # element_is_rendered # element_properties # pairs_are_on # pair_data # pair_link # pairs_favoriteMethod # pairWire_width # pairWire_pairWidth # pairWire_linkWidth # pairWire_linkStipple # cylinder_colorType # pairCylinder_radius # pairCylinder_pairRadius # pairCylinder_linkRadius # fog_is_on # fog_color_is_specific # fog_specific_color # fog_start_end # backgroundColor_color # box_is_on # box_color # box_line_width # box_line_stipple # axes_are_on # axes_color # axes_line_width # axes_line_stipple # isosurfaces_drawIntra # isosurface_property # isosurface_color # isosurface_properties # scales_are_on # scales_color # scales_line_width # scale_definition # scales_line_stipple # 2 real values (degrees) for user orientation with respect to sample opengl_theta_phi_omega: 60.100 -65.600 0.000 # 2 real values for image position with respect to [0.0, 1.0]x[0.0, 1.0] window opengl_xs_ys: 0.500 0.500 # gross factor (must be real > 0.0) opengl_gross: 1.000 # reduced perspective distance (must be real > 1.0) opengl_d_red: 7.000 # The radius of the element and its shape, a real > 0. & [Sphere Cube Elipsoid Point] atomic_radius_shape: Si 1.175 Sphere atomic_radius_shape: Al 1.430 Sphere atomic_radius_shape: Ag 1.430 Sphere atomic_radius_shape: Au 1.437 Sphere atomic_radius_shape: Ge 1.225 Sphere atomic_radius_shape: O 1.350 Sphere atomic_radius_shape: C 0.600 Sphere atomic_radius_shape: Cd 1.490 Sphere atomic_radius_shape: Pd 1.375 Sphere atomic_radius_shape: Te 1.430 Sphere atomic_radius_shape: Co 1.250 Sphere atomic_radius_shape: Fe 1.240 Sphere atomic_radius_shape: Cu 1.250 Sphere atomic_radius_shape: H 0.500 Sphere atomic_radius_shape: Ni 1.243 Sphere atomic_radius_shape: Pt 1.385 Sphere # Global or element resource for rendering spin module spin_resources: spin_global_color_cone 0.000000 0.000000 spin_resources: spin_global_color_wheel 0.000000 spin_resources: spin_global_hiding_mode never spin_resources: spin_global_atomic 0 spin_resources: spin_global_modulus 0 # Codes the main color in RedGreenBlueAlpha formatand the light effects on material, nine floats between 0. and 1. element_color: Si 0.000 1.000 0.200 1.000 0.20 0.54 0.69 0.50 0.20 element_color: Al 0.600 0.600 1.000 1.000 0.25 0.80 0.50 0.70 0.00 element_color: Ag 1.000 1.000 1.000 1.000 0.20 0.60 0.50 1.00 0.00 element_color: Au 1.000 0.750 0.040 1.000 0.54 0.54 0.16 0.52 0.00 element_color: Ge 0.000 1.000 0.800 1.000 0.20 0.54 0.69 0.50 0.20 element_color: O 1.000 0.200 0.200 1.000 0.60 0.60 0.00 0.00 0.00 element_color: C 0.300 0.300 0.300 1.000 0.20 0.54 0.69 0.50 0.20 element_color: Cd 0.000 0.800 1.000 1.000 0.50 0.00 0.12 0.50 0.20 element_color: Pd 1.000 1.000 0.800 1.000 0.50 0.00 0.12 0.50 0.20 element_color: Te 0.900 0.400 0.100 1.000 0.20 0.54 0.69 0.50 0.20 element_color: Co 1.000 0.500 0.800 1.000 0.50 0.00 0.12 0.50 0.20 element_color: Fe 1.000 0.500 0.000 1.000 0.50 0.00 0.12 0.50 0.20 element_color: Cu 1.000 0.560 0.340 1.000 0.20 0.70 0.10 0.24 0.15 element_color: H 1.000 1.000 1.000 1.000 0.60 0.60 0.00 0.00 0.00 element_color: Ni 1.000 0.300 0.300 1.000 0.50 0.00 0.12 0.50 0.20 element_color: Pt 1.000 0.800 0.800 1.000 0.50 0.00 0.12 0.50 0.20 # Define some properties ; rendered (0 or 1) masked(0 or 1). element_properties: Si 1 1 element_properties: Al 1 1 element_properties: Ag 1 1 element_properties: Au 1 1 element_properties: Ge 1 1 element_properties: O 1 1 element_properties: C 1 1 element_properties: Cd 1 1 element_properties: Pd 1 1 element_properties: Te 1 1 element_properties: Co 1 1 element_properties: Fe 1 1 element_properties: Cu 1 1 element_properties: H 1 1 element_properties: Ni 1 1 element_properties: Pt 1 1 # Ask the opengl engine to draw pairs between elements ; boolean 0 or 1 pairs_are_on: 0 # Favorite method used to render files ; chain ('Wire pairs', 'Cylinder pairs') pairs_favoriteMethod: Wire pairs # Draw a link between [ele1] [ele2] [0. <= dmin] [0. <= dmax] # [0. <= RGB <= 1.]x3 [bool: drawn] [bool: printLength] pair_link: Ni Ni 0.000 4.100 0.750 0.400 0.200 1 0 pair_link: Si Si 2.200 2.500 0.750 0.400 0.200 1 0 pair_link: Au Ni 0.000 0.000 1.000 0.600 0.200 1 0 pair_link: Au Au 0.000 4.100 1.000 0.600 0.200 1 0 # This value is the width for all pairs drawn ; 0 < integer < 10 pairWire_width: 2 # Widths detail for each drawn link ; 0 < integer < 10 # It chooses the colors of the cylinders according differents criterion ; 0 <= integer < 2 cylinder_colorType: 0 # This value is the default radius of the pairs drawn as cylinders ; 0 < real < 10 pairCylinder_radius: 0.150000 # This value is the radius for specific pairs drawn as cylinders ; element1 elemen2 0 < real < 10 # Control if the fog is used ; boolean (0 or 1) fog_is_on: 1 # Control if the fog uses a specific color ; boolean (0 or 1) fog_color_is_specific: 0 # Define the color of the fog ; four floating point values (0. <= v <= 1.) fog_specific_color: 0.000 0.000 0.000 0.000 # Define the position of the fog ; two floating point values (0. <= v <= 1.) fog_start_end: 0.600 0.850 # Set the background of the background ; four floating point values (0. <= v <= 1.) backgroundColor_color: 0.000 0.000 0.000 1.000 # Control if a box is drawn around the rendering area ; boolean (0 or 1) box_is_on: 1 # Define the color of the box ; three floating point values (0. <= v <= 1.) box_color: 1.000 1.000 1.000 # Define the width of the lines of the box ; one integer (1. <= v <= 10.) box_line_width: 2 # Dot scheme detail for the lines of the box (main and expanded) ; 0 < 2 integers < 2^16 box_line_stipple: 65535 65280 # Control if the axes are drawn ; boolean (0 or 1) axes_are_on: 1 # Define the color of the axes ; three floating point values (0. <= v <= 1.) axes_color: 1.000 1.000 1.000 # Define the width of the lines of the axes ; one floating point values (1. <= v <= 10.) axes_line_width: 3 # Dot scheme detail for the lines of the axes ; 0 < integer < 2^16 axes_line_stipple: 65535 # Choose if the interior is drawn in color inverse ; a boolean (0 or 1) isosurfaces_drawIntra: 0 # Control if scales are drawn ; boolean (0 or 1) scales_are_on: 0 # Define the color RGBA of all scales ; four floating point values (0. <= v <= 1.) scales_color: 0.000 0.000 0.000 1.000 # Define the width of the lines of all scales ; one floating point value (1. <= v <= 10.) scales_line_width: 1 # Define the stipple pattern of the lines of all scales ; one integer value (0 <= v <= 65535) scales_line_stipple: 65535 # Define the position, the direction, the length and the legend of a scale ; position[3] direction[3] length legend scale_definition: 0 0 0 1 0 0 5 [auto] v_sim-3.8.0/examples/000077500000000000000000000000001370110300500144435ustar00rootroot00000000000000v_sim-3.8.0/examples/Makefile.am000066400000000000000000000005351370110300500165020ustar00rootroot00000000000000v_simexamples_DATA = \ cinchonidine.yaml \ diff.ascii \ diff.dat \ demo-browser.tar.gz \ demo.ascii \ demo.d3 \ demo.xyz \ demo_spin.d3 \ demo_spin.spin \ aluminium.d3 \ test_isosurfaces.ascii \ test_isosurfaces.surf \ planes.xml \ density-sih4.dat \ coord_vib_g_co.xyz \ values.xml EXTRA_DIST = $(v_simexamples_DATA) v_sim-3.8.0/examples/aluminium.d3000066400000000000000000000066141370110300500167020ustar00rootroot00000000000000Positions atomiques 3D.  Al 0@8~G {(~G A@5j^5?}@800@av6T@8@,m5@(@_*C<j97?Ϭ\jddJD_zfo =?mܿ\Z "N <8–yu-& em qİ_"J)t%Z.|@5|:&@4 1"k@2?}@16 $@{g}@Fn)@@2}FT@/0 %@1 ko4@, md@/)@)=<Q@,sHJ:@&1NZ@)}gT*@! `8@ 8le?:@(dZ@"pV=@%?Qw@<@"F/p^@b@kj@h&@ +iE@x׿?^@_=@/Jjq@)@)7`h@%п@&\ Ix@">){@]̼A@?B.@ 8ݢ@@U#&I6ܗe sD +? n\pO5?ȿe 0d ūeF"ϥFp`Oc !fvRi"$wj$ O'̛x@6؏F@5ghp!@3Ȥ@2 xr@/\:l,@$Ȣ/@3nz@1%F@2 .R@/`F(^@1@,Tbv@/hs.@)*@)څVQ@#<7@&/}@#<K@xV }s@,9@$釽u@)MT @" vR_@&RT@U>@$:Kdg&@R"7@#8@@+YE@xyU,@k@O @ e @9zK??-d@,W2.@,?X(/Em@&ɼ^ 2L@"rOLB bcڐb,D^gt'ضu}@,F}D@#ԍ00@)Ջ:@/,Lg@0-q]@2H ?i@1i.@4q>Ի@`wQ@#Ur-@#@)a0ˏe@)Tm@.gd@.\@1/}@5']~!5@4gE@\@t@"ղ@#qn@)OJL@+jS@1]ș @4qD2~3?N'@$,`@--V@#nQV@2#rޖ@46N@48t?p ۸?Nj+@@S@"K"@`@#@#Ӄ@)a (:@+[y/x@/,'xHb@41"?nTD?#?@@|4@!x @e@F-n@(Rej?X&l?$ b@!{[@M\Ţ@eT{[@)TxM{#N@03+@1K$@4|8`?1h@.>2B@2@+\T@1@2@zk@4 UO^@5%@!Mַd@& k@&|@+oHl;1@+m}@03'@01Ic@2[X@5&mPk@5'\z@+>@!u/G$@&|@+j3x@01|1@2@5&)w?%o@ ~\_@.YG@!bԼ@&{&z@4 2?񅎉R?EH@ *$@ [^X@-`n@*Ѓ@!U4@!d@&Lq@&b~@+o*@0-=F@1?@X@ |Me2<@Zϵf@]@^ @ 4"@#ڈBh@#|@&\d.@.K7:@! ,@ r@5(@B7S@Ā|@@ fG@+m{`{$@(@ }~A@2V]JcX@4 T-0@00*2@2gI@.7]4@1ذv@4g@.A/@23@.2@)r00@}7U@Sb1@RЃ@_$lo@X''@\n@ ι@@H8 '@_@P^_5@X$@Pr~@oނ@sOT@m @sR;@GwO@G|8 @e@\Dv}@@s@\7|Z@H#@jo-@H˴@e1@ `5u,@GwT[@G|]ݦ@j 2_@HDiUL@j! @G@G.!@ @_(lN@u@Pk@/5@aa@eO@e^@X'@_|@PŠ@j@8@/c@o+ev@Xً@PYWL@_@l8@X@@@s@Xz.F@e@e{@P7M@_ Fʬ@R_t@ӃaP@8ƀ@Ռvf@vdq@ӊ#7@LKs@8(@ߪ]@#`}@"@դ_g@횹6@Y(o@Ea@Prv@Ս`@*@XU@Tt@$Z@@2?n@𾏙4@ f@PW@:)@Pf2@𾇶HV@x~@\@?@'@J @ՙ17b@{""[@e ;@J@߹" @\@|@&@;@ՙ,@`-U@^U@+Σ@y\f@/heI@/q@S{s@|T"@/@C@?+@߻Wo@bv@s*a@{F@6)@/Yj@}0@ն@X@յV@L| s@M "@s `v@p@s%o@s#h`@; @ot]@)*F0v_sim-3.8.0/examples/anime.ascii000066400000000000000000000025451370110300500165540ustar00rootroot00000000000000# Phonopy generated file for v_sim 3.6 4.632136315 2.316068158 4.011547723 2.316068158 1.337182574 3.782123464 0.000000000 0.000000000 0.000000000 Pb 4.632136315 2.674365149 1.891061732 Te #metaData: qpt=[0.375000;0.375000;0.750000;1.181287 \ #; -0.038994; -0.022513; 0.031839; 0.024825; 0.014333; -0.020270 \ #; -0.017868; -0.010316; 0.014589; 0.011375; 0.006567; -0.009288 \ # ] #metaData: qpt=[0.375000;0.375000;0.750000;1.337473 \ #; -0.033663; 0.058306; -0.000000; -0.000000; -0.000000; 0.000000 \ #; 0.010914; -0.018903; -0.000000; -0.000000; 0.000000; 0.000000 \ # ] #metaData: qpt=[0.375000;0.375000;0.750000;1.874539 \ #; 0.030898; 0.017839; 0.050456; -0.000000; -0.000000; 0.000000 \ #; -0.020224; -0.011676; -0.033026; -0.000000; 0.000000; 0.000000 \ # ] #metaData: qpt=[0.375000;0.375000;0.750000;2.087001 \ #; 0.016503; 0.009528; -0.013475; -0.001981; -0.001144; 0.001617 \ #; -0.058486; -0.033767; 0.047753; 0.007020; 0.004053; -0.005732 \ # ] #metaData: qpt=[0.375000;0.375000;0.750000;2.207853 \ #; -0.008565; 0.014834; 0.000000; 0.000000; -0.000000; 0.000000 \ #; -0.042897; 0.074299; -0.000000; 0.000000; -0.000000; -0.000000 \ # ] #metaData: qpt=[0.375000;0.375000;0.750000;2.715620 \ #; 0.015871; 0.009163; 0.025917; -0.000000; 0.000000; -0.000000 \ #; 0.039373; 0.022732; 0.064296; -0.000000; -0.000000; -0.000000 \ # ] v_sim-3.8.0/examples/cinchonidine.yaml000066400000000000000000000065341370110300500177710ustar00rootroot00000000000000--- positions: - H: [ 7.0312401063990793, 20.323599199332200, 16.646399223743714 ] - H: [ 10.946099846957209, 20.355299603059386, 19.263199969550236 ] - H: [ 17.597800607145697, 20.301300785726941, 12.893700384406340 ] - H: [ 17.474399712068291, 20.308500507892383, 8.2691296083002328 ] - H: [ 13.365300208075425, 20.305299830404067, 5.9774499332156665 ] - H: [ 9.3268796286746376, 20.308999712658299, 8.4188703129668756 ] - H: [ 14.792099516388962, 22.924600204406698, 20.046099019348571 ] - H: [ 16.840200606097913, 16.869500501708860, 15.874199736022030 ] - H: [ 19.740299155469092, 20.447299256832498, 21.131599057721338 ] - H: [ 22.527099849176999, 18.633499113022896, 20.905999953743351 ] - H: [ 18.048499610335757, 17.586800080462879, 24.022499263680150 ] - H: [ 20.852900425862863, 15.788900599648441, 23.885299051300922 ] - H: [ 21.419299595015705, 12.533799879839640, 20.676400002904970 ] - H: [ 17.291800700923197, 11.406500002692093, 16.737499588064875 ] - H: [ 18.704299684985727, 7.0754400027442772, 17.295199618571264 ] - H: [ 21.048599507200844, 8.0980402406118586, 19.676599185591826 ] - H: [ 17.129200517530272, 13.172599959699472, 22.561000718677402 ] - H: [ 14.637700167968211, 14.431699807056347, 18.754299457641046 ] - H: [ 14.580599793227327, 16.871899207641828, 21.015199644649623 ] - H: [ 22.968800551297711, 15.458800096550240, 17.806500638596692 ] - H: [ 20.491800568329680, 14.823999962459167, 15.677799605391845 ] - H: [ 17.236900791955531, 21.553200009826742, 16.736200213926882 ] - C: [ 11.149299615066795, 20.307900380863323, 9.3582304088473567 ] - C: [ 11.149299615066795, 20.307900380863323, 12.041000073268636 ] - C: [ 13.511299580272619, 20.307900380863323, 13.369400175015695 ] - C: [ 15.785499879817106, 20.307900380863323, 11.935000158759044 ] - C: [ 15.718700154714670, 20.306799246885081, 9.3317401169550376 ] - C: [ 13.384299725204126, 20.305499872747088, 8.0295599796097292 ] - C: [ 8.8709696125580759, 20.322901754406534, 15.721199782910782 ] - C: [ 11.087500047448218, 20.334300563592119, 17.219399790216208 ] - C: [ 13.427099775694003, 20.322198902931060, 16.075299960621543 ] - C: [ 15.836999068953435, 20.322699909880246, 17.649899923311086 ] - C: [ 17.058499065647315, 17.664499409984987, 17.771599557381187 ] - C: [ 20.462500672718729, 18.549499350787301, 20.783500150301169 ] - C: [ 19.354700418557435, 16.634200245186051, 22.730200497206710 ] - C: [ 17.937299495999287, 14.560400022040508, 21.255800122170825 ] - C: [ 15.811499977859864, 15.835299610129404, 19.719100073658808 ] - C: [ 19.868800229201867, 13.225899529922980, 19.485299233617013 ] - C: [ 20.910399083106515, 15.318199164339674, 17.644999786998735 ] - C: [ 18.793399625876692, 10.997099831327626, 18.090400371373679 ] - C: [ 19.549900295129500, 8.6085996622214953, 18.365700085584091 ] - O: [ 15.377700047196795, 21.198200542664026, 20.162100149917517 ] - N: [ 8.8581696058797164, 20.311200178431516, 13.234799612004089 ] - N: [ 19.827099510506965, 17.827600600327099, 18.159800646935373 ] Properties: Comment: converted from examples/cinchonidine.xyz Timestamp: 2013-09-18 11:13:57.591 v_sim-3.8.0/examples/coord_vib_g_co.xyz000066400000000000000000032670431370110300500201730ustar00rootroot0000000000000061 Mode 1: freq= 7.09 N -0.44003451495 -0.00038510790 2.12369783068 0.001 -0.151 -0.002 C -1.76594470239 0.00039861437 2.37754210613 0.001 -0.175 0.000 C -2.24923313135 -0.00145267054 3.67997125809 0.003 -0.198 0.001 C -1.33887502024 -0.00450793845 4.73956848945 0.005 -0.183 -0.000 C 0.02462671625 -0.00591801736 4.46614405978 0.005 -0.146 -0.003 C 0.43187566201 -0.00376957955 3.13352499014 0.003 -0.126 -0.003 C -2.63984642995 0.00218980399 1.17162612704 -0.001 -0.187 0.002 N -1.98513620489 0.00132140951 0.00153900685 -0.003 -0.176 0.001 C -2.63911589169 0.00167522827 -1.17277445342 -0.005 -0.167 0.002 C -4.02452897564 0.00329996303 -1.20791476641 -0.005 -0.197 0.004 C -4.73391255267 0.00451580118 -0.00020876193 -0.003 -0.223 0.005 C -4.02924140493 0.00399189729 1.20660077672 -0.001 -0.218 0.004 Co 0.00000000000 0.00000000000 0.00000000000 -0.006 -0.244 -0.006 N -0.43839318333 -0.00054206762 -2.12229806799 -0.007 -0.111 -0.002 C -1.76408906064 -0.00030645034 -2.37697009192 -0.007 -0.135 0.000 C -2.24773885821 -0.00257631963 -3.67934971086 -0.009 -0.136 0.001 C -1.33713102227 -0.00526459193 -4.73855802198 -0.010 -0.103 -0.000 C 0.02654101484 -0.00591797621 -4.46472703619 -0.010 -0.070 -0.002 C 0.43371721952 -0.00363389350 -3.13225443930 -0.008 -0.071 -0.003 S -6.53329279136 0.00637481657 -0.11611178087 -0.005 -0.423 0.013 N 2.00981687167 0.00259443239 -0.00000686048 -0.003 -0.057 -0.006 C 2.67119656792 1.17263645248 0.00045766926 -0.036 -0.034 0.003 C 4.06129317470 1.20536051565 0.00241240325 -0.036 0.004 0.001 C 4.76783866331 0.00148799420 0.00346798881 -0.003 0.024 -0.010 C 4.05723810074 -1.20352939940 0.00211502115 0.031 0.004 -0.019 C 2.67108506586 -1.17139122066 0.00026591651 0.030 -0.034 -0.017 C 1.82209539371 2.39842937406 -0.00175320633 -0.070 -0.058 0.015 C 2.33938959521 3.68993217240 -0.00584554905 -0.105 -0.044 0.025 C 1.45736908622 4.77231118002 -0.00917967851 -0.135 -0.068 0.035 C 0.08658913130 4.53522926787 -0.00833235387 -0.129 -0.106 0.036 C -0.35359617412 3.21325694137 -0.00400174376 -0.092 -0.118 0.026 N 0.49290585413 2.18198449515 -0.00068475564 -0.069 -0.103 0.017 S 6.56718562933 -0.11349126889 0.00673479967 0.001 0.121 -0.022 C 1.82142022278 -2.39594383179 -0.00206827421 0.064 -0.058 -0.026 C 2.33969079820 -3.68709653410 -0.00625612120 0.100 -0.044 -0.037 C 1.45789786198 -4.76953179608 -0.00945089783 0.130 -0.068 -0.045 C 0.08684213972 -4.53272927032 -0.00840538011 0.123 -0.106 -0.041 C -0.35393854068 -3.21111942258 -0.00398541364 0.087 -0.119 -0.030 N 0.49225266031 -2.17934076887 -0.00084210065 0.063 -0.103 -0.024 H 1.83694111827 5.77332096953 -0.01265611066 -0.047 -0.017 0.012 H -0.61802819388 5.33967450634 -0.01131742088 -0.044 -0.036 0.013 H 3.39175422949 3.87200638269 -0.00704552340 -0.032 -0.004 0.007 H -1.39787683933 2.98334799634 -0.00369736757 -0.025 -0.043 0.008 H 1.83794742242 -5.77033326187 -0.01295832570 0.046 -0.017 -0.015 H -0.61749414542 -5.33746053721 -0.01121572048 0.042 -0.036 -0.014 H -1.39833026435 -2.98175334118 -0.00345676225 0.023 -0.043 -0.008 H 3.39230213722 -3.86796714602 -0.00754158092 0.030 -0.004 -0.011 H 4.58301895157 2.13678100538 0.00314824260 -0.018 0.005 0.003 H 4.58784714512 -2.12983634010 0.00211631073 0.016 0.005 -0.008 H -1.68997263563 -0.00719388386 -5.74925805817 -0.003 -0.030 0.000 H 0.75224758084 -0.00860493512 -5.25016290812 -0.003 -0.013 -0.001 H -3.29620044300 -0.00255800648 -3.88456579214 -0.003 -0.047 0.001 H 1.47161249279 -0.00457826661 -2.87685200854 -0.002 -0.013 -0.001 H -1.69176120521 -0.00597000955 5.75026973076 0.002 -0.058 0.000 H 0.75025791005 -0.00892914887 5.25161119224 0.002 -0.039 -0.001 H 1.46975366817 -0.00523069331 2.87805400798 0.001 -0.028 -0.001 H -3.29750276746 -0.00099200484 3.88584245085 0.001 -0.065 0.001 H -4.55513299541 0.00377930937 -2.13473279421 -0.002 -0.058 0.001 H -4.55107479454 0.00501307822 2.13844314827 0.000 -0.069 0.001 H -6.83436893102 0.00806057203 1.19721860356 -0.000 -0.081 0.003 H 6.86748209639 1.20005966818 0.00372860376 -0.010 0.024 -0.001 61 Mode 2: freq= 6.96 N -0.44003451495 -0.00038510790 2.12369783068 -0.074 -0.053 0.052 C -1.76594470239 0.00039861437 2.37754210613 -0.077 -0.053 0.005 C -2.24923313135 -0.00145267054 3.67997125809 -0.118 -0.083 -0.010 C -1.33887502024 -0.00450793845 4.73956848945 -0.152 -0.109 0.019 C 0.02462671625 -0.00591801736 4.46614405978 -0.144 -0.106 0.062 C 0.43187566201 -0.00376957955 3.13352499014 -0.101 -0.075 0.075 C -2.63984642995 0.00218980399 1.17162612704 -0.038 -0.022 -0.023 N -1.98513620489 0.00132140951 0.00153900685 -0.000 0.006 -0.002 C -2.63911589169 0.00167522827 -1.17277445342 0.037 0.035 -0.023 C -4.02452897564 0.00329996303 -1.20791476641 0.039 0.037 -0.067 C -4.73391255267 0.00451580118 -0.00020876193 -0.000 0.007 -0.090 C -4.02924140493 0.00399189729 1.20660077672 -0.039 -0.023 -0.067 Co 0.00000000000 0.00000000000 0.00000000000 -0.001 0.010 0.139 N -0.43839318333 -0.00054206762 -2.12229806799 0.074 0.063 0.052 C -1.76408906064 -0.00030645034 -2.37697009192 0.076 0.064 0.005 C -2.24773885821 -0.00257631963 -3.67934971086 0.118 0.095 -0.010 C -1.33713102227 -0.00526459193 -4.73855802198 0.152 0.121 0.019 C 0.02654101484 -0.00591797621 -4.46472703619 0.143 0.115 0.063 C 0.43371721952 -0.00363389350 -3.13225443930 0.100 0.083 0.076 S -6.53329279136 0.00637481657 -0.11611178087 0.006 0.018 -0.241 N 2.00981687167 0.00259443239 -0.00000686048 -0.000 0.003 0.136 C 2.67119656792 1.17263645248 0.00045766926 0.001 0.002 0.174 C 4.06129317470 1.20536051565 0.00241240325 0.001 0.001 0.216 C 4.76783866331 0.00148799420 0.00346798881 -0.000 -0.000 0.206 C 4.05723810074 -1.20352939940 0.00211502115 -0.001 0.001 0.155 C 2.67108506586 -1.17139122066 0.00026591651 -0.001 0.002 0.115 C 1.82209539371 2.39842937406 -0.00175320633 0.002 0.003 0.178 C 2.33938959521 3.68993217240 -0.00584554905 0.003 0.002 0.224 C 1.45736908622 4.77231118002 -0.00917967851 0.004 0.003 0.223 C 0.08658913130 4.53522926787 -0.00833235387 0.004 0.004 0.177 C -0.35359617412 3.21325694137 -0.00400174376 0.003 0.005 0.133 N 0.49290585413 2.18198449515 -0.00068475564 0.002 0.004 0.144 S 6.56718562933 -0.11349126889 0.00673479967 -0.001 -0.003 0.414 C 1.82142022278 -2.39594383179 -0.00206827421 -0.002 0.003 0.058 C 2.33969079820 -3.68709653410 -0.00625612120 -0.003 0.002 0.042 C 1.45789786198 -4.76953179608 -0.00945089783 -0.004 0.003 -0.012 C 0.08684213972 -4.53272927032 -0.00840538011 -0.004 0.004 -0.049 C -0.35393854068 -3.21111942258 -0.00398541364 -0.003 0.005 -0.030 N 0.49225266031 -2.17934076887 -0.00084210065 -0.002 0.004 0.024 H 1.83694111827 5.77332096953 -0.01265611066 0.002 0.001 0.075 H -0.61802819388 5.33967450634 -0.01131742088 0.001 0.001 0.051 H 3.39175422949 3.87200638269 -0.00704552340 0.001 0.000 0.075 H -1.39787683933 2.98334799634 -0.00369736757 0.001 0.002 0.028 H 1.83794742242 -5.77033326187 -0.01295832570 -0.001 0.001 -0.007 H -0.61749414542 -5.33746053721 -0.01121572048 -0.001 0.001 -0.026 H -1.39833026435 -2.98175334118 -0.00345676225 -0.001 0.002 -0.016 H 3.39230213722 -3.86796714602 -0.00754158092 -0.001 0.000 0.020 H 4.58301895157 2.13678100538 0.00314824260 0.000 0.000 0.074 H 4.58784714512 -2.12983634010 0.00211631073 -0.001 0.000 0.043 H -1.68997263563 -0.00719388386 -5.74925805817 0.053 0.042 0.002 H 0.75224758084 -0.00860493512 -5.25016290812 0.049 0.039 0.025 H -3.29620044300 -0.00255800648 -3.88456579214 0.036 0.029 -0.013 H 1.47161249279 -0.00457826661 -2.87685200854 0.027 0.022 0.032 H -1.69176120521 -0.00597000955 5.75026973076 -0.053 -0.038 0.002 H 0.75025791005 -0.00892914887 5.25161119224 -0.049 -0.036 0.025 H 1.46975366817 -0.00523069331 2.87805400798 -0.027 -0.021 0.031 H -3.29750276746 -0.00099200484 3.88584245085 -0.036 -0.025 -0.013 H -4.55513299541 0.00377930937 -2.13473279421 0.020 0.017 -0.024 H -4.55107479454 0.00501307822 2.13844314827 -0.020 -0.013 -0.024 H -6.83436893102 0.00806057203 1.19721860356 -0.011 -0.006 -0.046 H 6.86748209639 1.20005966818 0.00372860376 0.000 -0.001 0.086 61 Mode 3: freq= 6.60 N -0.44003451495 -0.00038510790 2.12369783068 -0.038 0.088 0.028 C -1.76594470239 0.00039861437 2.37754210613 -0.040 0.085 0.004 C -2.24923313135 -0.00145267054 3.67997125809 -0.061 0.141 -0.003 C -1.33887502024 -0.00450793845 4.73956848945 -0.078 0.194 0.012 C 0.02462671625 -0.00591801736 4.46614405978 -0.074 0.190 0.034 C 0.43187566201 -0.00376957955 3.13352499014 -0.052 0.133 0.041 C -2.63984642995 0.00218980399 1.17162612704 -0.020 0.026 -0.010 N -1.98513620489 0.00132140951 0.00153900685 -0.001 -0.028 0.001 C -2.63911589169 0.00167522827 -1.17277445342 0.019 -0.083 -0.010 C -4.02452897564 0.00329996303 -1.20791476641 0.019 -0.089 -0.033 C -4.73391255267 0.00451580118 -0.00020876193 -0.001 -0.036 -0.044 C -4.02924140493 0.00399189729 1.20660077672 -0.021 0.023 -0.033 Co 0.00000000000 0.00000000000 0.00000000000 -0.002 -0.039 0.075 N -0.43839318333 -0.00054206762 -2.12229806799 0.037 -0.130 0.029 C -1.76408906064 -0.00030645034 -2.37697009192 0.039 -0.135 0.005 C -2.24773885821 -0.00257631963 -3.67934971086 0.060 -0.195 -0.003 C -1.33713102227 -0.00526459193 -4.73855802198 0.078 -0.240 0.012 C 0.02654101484 -0.00591797621 -4.46472703619 0.073 -0.225 0.034 C 0.43371721952 -0.00363389350 -3.13225443930 0.051 -0.164 0.041 S -6.53329279136 0.00637481657 -0.11611178087 0.002 -0.076 -0.121 N 2.00981687167 0.00259443239 -0.00000686048 -0.001 -0.009 0.071 C 2.67119656792 1.17263645248 0.00045766926 -0.006 -0.006 0.021 C 4.06129317470 1.20536051565 0.00241240325 -0.006 0.000 0.040 C 4.76783866331 0.00148799420 0.00346798881 -0.001 0.004 0.107 C 4.05723810074 -1.20352939940 0.00211502115 0.005 0.000 0.153 C 2.67108506586 -1.17139122066 0.00026591651 0.005 -0.006 0.131 C 1.82209539371 2.39842937406 -0.00175320633 -0.011 -0.010 -0.050 C 2.33938959521 3.68993217240 -0.00584554905 -0.016 -0.008 -0.100 C 1.45736908622 4.77231118002 -0.00917967851 -0.021 -0.011 -0.165 C 0.08658913130 4.53522926787 -0.00833235387 -0.020 -0.017 -0.178 C -0.35359617412 3.21325694137 -0.00400174376 -0.014 -0.019 -0.124 N 0.49290585413 2.18198449515 -0.00068475564 -0.011 -0.016 -0.067 S 6.56718562933 -0.11349126889 0.00673479967 -0.000 0.019 0.226 C 1.82142022278 -2.39594383179 -0.00206827421 0.010 -0.010 0.174 C 2.33969079820 -3.68709653410 -0.00625612120 0.016 -0.008 0.240 C 1.45789786198 -4.76953179608 -0.00945089783 0.021 -0.012 0.276 C 0.08684213972 -4.53272927032 -0.00840538011 0.020 -0.018 0.246 C -0.35393854068 -3.21111942258 -0.00398541364 0.014 -0.020 0.180 N 0.49225266031 -2.17934076887 -0.00084210065 0.010 -0.017 0.157 H 1.83694111827 5.77332096953 -0.01265611066 -0.007 -0.003 -0.059 H -0.61802819388 5.33967450634 -0.01131742088 -0.007 -0.006 -0.066 H 3.39175422949 3.87200638269 -0.00704552340 -0.005 -0.001 -0.026 H -1.39787683933 2.98334799634 -0.00369736757 -0.004 -0.007 -0.038 H 1.83794742242 -5.77033326187 -0.01295832570 0.007 -0.003 0.094 H -0.61749414542 -5.33746053721 -0.01121572048 0.007 -0.006 0.079 H -1.39833026435 -2.98175334118 -0.00345676225 0.004 -0.007 0.045 H 3.39230213722 -3.86796714602 -0.00754158092 0.005 -0.001 0.076 H 4.58301895157 2.13678100538 0.00314824260 -0.003 0.001 0.001 H 4.58784714512 -2.12983634010 0.00211631073 0.003 0.001 0.059 H -1.68997263563 -0.00719388386 -5.74925805817 0.027 -0.083 0.002 H 0.75224758084 -0.00860493512 -5.25016290812 0.025 -0.075 0.013 H -3.29620044300 -0.00255800648 -3.88456579214 0.018 -0.060 -0.006 H 1.47161249279 -0.00457826661 -2.87685200854 0.014 -0.044 0.017 H -1.69176120521 -0.00597000955 5.75026973076 -0.027 0.069 0.002 H 0.75025791005 -0.00892914887 5.25161119224 -0.025 0.067 0.013 H 1.46975366817 -0.00523069331 2.87805400798 -0.014 0.037 0.017 H -3.29750276746 -0.00099200484 3.88584245085 -0.019 0.041 -0.006 H -4.55513299541 0.00377930937 -2.13473279421 0.010 -0.039 -0.012 H -4.55107479454 0.00501307822 2.13844314827 -0.010 0.019 -0.012 H -6.83436893102 0.00806057203 1.19721860356 -0.006 0.004 -0.023 H 6.86748209639 1.20005966818 0.00372860376 -0.002 0.004 0.024 61 Mode 4: freq= 0.86 N -0.44003451495 -0.00038510790 2.12369783068 -0.154 0.004 -0.002 C -1.76594470239 0.00039861437 2.37754210613 -0.143 0.003 -0.000 C -2.24923313135 -0.00145267054 3.67997125809 -0.141 0.004 0.000 C -1.33887502024 -0.00450793845 4.73956848945 -0.140 0.003 -0.001 C 0.02462671625 -0.00591801736 4.46614405978 -0.140 0.003 -0.003 C 0.43187566201 -0.00376957955 3.13352499014 -0.142 0.003 -0.003 C -2.63984642995 0.00218980399 1.17162612704 -0.144 0.004 0.001 N -1.98513620489 0.00132140951 0.00153900685 -0.156 0.004 0.001 C -2.63911589169 0.00167522827 -1.17277445342 -0.144 0.003 0.001 C -4.02452897564 0.00329996303 -1.20791476641 -0.144 0.004 0.000 C -4.73391255267 0.00451580118 -0.00020876193 -0.144 0.004 0.001 C -4.02924140493 0.00399189729 1.20660077672 -0.144 0.004 0.001 Co 0.00000000000 0.00000000000 0.00000000000 -0.321 0.007 0.001 N -0.43839318333 -0.00054206762 -2.12229806799 -0.155 0.004 0.003 C -1.76408906064 -0.00030645034 -2.37697009192 -0.143 0.003 0.001 C -2.24773885821 -0.00257631963 -3.67934971086 -0.142 0.003 0.001 C -1.33713102227 -0.00526459193 -4.73855802198 -0.141 0.003 0.002 C 0.02654101484 -0.00591797621 -4.46472703619 -0.141 0.003 0.003 C 0.43371721952 -0.00363389350 -3.13225443930 -0.142 0.003 0.004 S -6.53329279136 0.00637481657 -0.11611178087 -0.235 0.006 0.001 N 2.00981687167 0.00259443239 -0.00000686048 -0.155 0.003 0.000 C 2.67119656792 1.17263645248 0.00045766926 -0.143 0.003 0.000 C 4.06129317470 1.20536051565 0.00241240325 -0.143 0.003 -0.000 C 4.76783866331 0.00148799420 0.00346798881 -0.143 0.003 -0.000 C 4.05723810074 -1.20352939940 0.00211502115 -0.143 0.003 -0.000 C 2.67108506586 -1.17139122066 0.00026591651 -0.144 0.003 0.000 C 1.82209539371 2.39842937406 -0.00175320633 -0.142 0.004 0.000 C 2.33938959521 3.68993217240 -0.00584554905 -0.141 0.003 0.000 C 1.45736908622 4.77231118002 -0.00917967851 -0.140 0.004 0.000 C 0.08658913130 4.53522926787 -0.00833235387 -0.140 0.006 0.000 C -0.35359617412 3.21325694137 -0.00400174376 -0.142 0.006 0.000 N 0.49290585413 2.18198449515 -0.00068475564 -0.154 0.006 0.000 S 6.56718562933 -0.11349126889 0.00673479967 -0.234 0.005 -0.001 C 1.82142022278 -2.39594383179 -0.00206827421 -0.143 0.002 0.000 C 2.33969079820 -3.68709653410 -0.00625612120 -0.142 0.003 0.000 C 1.45789786198 -4.76953179608 -0.00945089783 -0.141 0.002 0.000 C 0.08684213972 -4.53272927032 -0.00840538011 -0.141 0.001 0.000 C -0.35393854068 -3.21111942258 -0.00398541364 -0.142 0.001 0.000 N 0.49225266031 -2.17934076887 -0.00084210065 -0.154 0.001 0.000 H 1.83694111827 5.77332096953 -0.01265611066 -0.040 0.001 0.000 H -0.61802819388 5.33967450634 -0.01131742088 -0.040 0.002 0.000 H 3.39175422949 3.87200638269 -0.00704552340 -0.041 0.001 -0.000 H -1.39787683933 2.98334799634 -0.00369736757 -0.041 0.002 0.000 H 1.83794742242 -5.77033326187 -0.01295832570 -0.041 0.001 0.000 H -0.61749414542 -5.33746053721 -0.01121572048 -0.041 0.000 0.000 H -1.39833026435 -2.98175334118 -0.00345676225 -0.041 -0.000 0.000 H 3.39230213722 -3.86796714602 -0.00754158092 -0.041 0.001 -0.000 H 4.58301895157 2.13678100538 0.00314824260 -0.041 0.001 -0.000 H 4.58784714512 -2.12983634010 0.00211631073 -0.042 0.001 -0.000 H -1.68997263563 -0.00719388386 -5.74925805817 -0.040 0.001 0.000 H 0.75224758084 -0.00860493512 -5.25016290812 -0.041 0.001 0.001 H -3.29620044300 -0.00255800648 -3.88456579214 -0.041 0.001 0.000 H 1.47161249279 -0.00457826661 -2.87685200854 -0.041 0.001 0.001 H -1.69176120521 -0.00597000955 5.75026973076 -0.040 0.001 -0.000 H 0.75025791005 -0.00892914887 5.25161119224 -0.040 0.001 -0.001 H 1.46975366817 -0.00523069331 2.87805400798 -0.041 0.001 -0.001 H -3.29750276746 -0.00099200484 3.88584245085 -0.041 0.001 0.000 H -4.55513299541 0.00377930937 -2.13473279421 -0.042 0.001 0.000 H -4.55107479454 0.00501307822 2.13844314827 -0.042 0.001 0.000 H -6.83436893102 0.00806057203 1.19721860356 -0.042 0.001 0.000 H 6.86748209639 1.20005966818 0.00372860376 -0.042 0.001 -0.000 61 Mode 5: freq= 3.65 N -0.44003451495 -0.00038510790 2.12369783068 0.044 -0.000 0.144 C -1.76594470239 0.00039861437 2.37754210613 0.046 -0.000 0.159 C -2.24923313135 -0.00145267054 3.67997125809 0.071 -0.001 0.168 C -1.33887502024 -0.00450793845 4.73956848945 0.091 -0.001 0.151 C 0.02462671625 -0.00591801736 4.46614405978 0.086 -0.001 0.124 C 0.43187566201 -0.00376957955 3.13352499014 0.061 -0.001 0.117 C -2.63984642995 0.00218980399 1.17162612704 0.023 0.001 0.176 N -1.98513620489 0.00132140951 0.00153900685 0.001 0.001 0.176 C -2.63911589169 0.00167522827 -1.17277445342 -0.022 0.001 0.176 C -4.02452897564 0.00329996303 -1.20791476641 -0.023 0.002 0.202 C -4.73391255267 0.00451580118 -0.00020876193 0.001 0.002 0.216 C -4.02924140493 0.00399189729 1.20660077672 0.024 0.001 0.202 Co 0.00000000000 0.00000000000 0.00000000000 0.001 0.001 0.279 N -0.43839318333 -0.00054206762 -2.12229806799 -0.043 0.001 0.144 C -1.76408906064 -0.00030645034 -2.37697009192 -0.045 0.002 0.159 C -2.24773885821 -0.00257631963 -3.67934971086 -0.070 0.002 0.168 C -1.33713102227 -0.00526459193 -4.73855802198 -0.090 0.002 0.151 C 0.02654101484 -0.00591797621 -4.46472703619 -0.085 0.002 0.125 C 0.43371721952 -0.00363389350 -3.13225443930 -0.059 0.001 0.117 S -6.53329279136 0.00637481657 -0.11611178087 -0.003 0.004 0.409 N 2.00981687167 0.00259443239 -0.00000686048 0.000 0.000 0.095 C 2.67119656792 1.17263645248 0.00045766926 0.001 0.000 0.074 C 4.06129317470 1.20536051565 0.00241240325 0.001 -0.000 0.043 C 4.76783866331 0.00148799420 0.00346798881 0.001 -0.000 0.026 C 4.05723810074 -1.20352939940 0.00211502115 0.000 -0.000 0.041 C 2.67108506586 -1.17139122066 0.00026591651 0.000 0.000 0.073 C 1.82209539371 2.39842937406 -0.00175320633 0.001 0.000 0.094 C 2.33938959521 3.68993217240 -0.00584554905 0.001 0.000 0.088 C 1.45736908622 4.77231118002 -0.00917967851 0.001 0.000 0.108 C 0.08658913130 4.53522926787 -0.00833235387 0.001 0.001 0.133 C -0.35359617412 3.21325694137 -0.00400174376 0.001 0.001 0.137 N 0.49290585413 2.18198449515 -0.00068475564 0.001 0.001 0.128 S 6.56718562933 -0.11349126889 0.00673479967 0.001 -0.001 -0.025 C 1.82142022278 -2.39594383179 -0.00206827421 0.000 0.000 0.091 C 2.33969079820 -3.68709653410 -0.00625612120 -0.000 0.000 0.084 C 1.45789786198 -4.76953179608 -0.00945089783 -0.000 0.000 0.102 C 0.08684213972 -4.53272927032 -0.00840538011 -0.000 0.000 0.128 C -0.35393854068 -3.21111942258 -0.00398541364 -0.000 0.000 0.134 N 0.49225266031 -2.17934076887 -0.00084210065 0.000 0.000 0.126 H 1.83694111827 5.77332096953 -0.01265611066 0.000 0.000 0.030 H -0.61802819388 5.33967450634 -0.01131742088 0.000 0.000 0.043 H 3.39175422949 3.87200638269 -0.00704552340 0.000 -0.000 0.020 H -1.39787683933 2.98334799634 -0.00369736757 0.000 0.000 0.045 H 1.83794742242 -5.77033326187 -0.01295832570 -0.000 0.000 0.028 H -0.61749414542 -5.33746053721 -0.01121572048 -0.000 0.000 0.041 H -1.39833026435 -2.98175334118 -0.00345676225 -0.000 0.000 0.045 H 3.39230213722 -3.86796714602 -0.00754158092 -0.000 -0.000 0.019 H 4.58301895157 2.13678100538 0.00314824260 0.000 -0.000 0.009 H 4.58784714512 -2.12983634010 0.00211631073 0.000 -0.000 0.008 H -1.68997263563 -0.00719388386 -5.74925805817 -0.032 0.001 0.046 H 0.75224758084 -0.00860493512 -5.25016290812 -0.029 0.001 0.032 H -3.29620044300 -0.00255800648 -3.88456579214 -0.021 0.001 0.055 H 1.47161249279 -0.00457826661 -2.87685200854 -0.016 0.000 0.028 H -1.69176120521 -0.00597000955 5.75026973076 0.032 -0.000 0.046 H 0.75025791005 -0.00892914887 5.25161119224 0.029 -0.001 0.032 H 1.46975366817 -0.00523069331 2.87805400798 0.016 -0.000 0.028 H -3.29750276746 -0.00099200484 3.88584245085 0.022 -0.000 0.055 H -4.55513299541 0.00377930937 -2.13473279421 -0.012 0.001 0.062 H -4.55107479454 0.00501307822 2.13844314827 0.012 0.000 0.061 H -6.83436893102 0.00806057203 1.19721860356 0.007 0.001 0.074 H 6.86748209639 1.20005966818 0.00372860376 0.000 -0.000 -0.006 61 Mode 6: freq= 7.35 N -0.44003451495 -0.00038510790 2.12369783068 -0.002 -0.091 -0.000 C -1.76594470239 0.00039861437 2.37754210613 -0.002 -0.046 -0.000 C -2.24923313135 -0.00145267054 3.67997125809 -0.002 -0.037 -0.000 C -1.33887502024 -0.00450793845 4.73956848945 -0.002 -0.067 -0.000 C 0.02462671625 -0.00591801736 4.46614405978 -0.002 -0.105 -0.000 C 0.43187566201 -0.00376957955 3.13352499014 -0.002 -0.112 -0.001 C -2.63984642995 0.00218980399 1.17162612704 -0.002 -0.017 -0.000 N -1.98513620489 0.00132140951 0.00153900685 -0.002 -0.042 -0.000 C -2.63911589169 0.00167522827 -1.17277445342 -0.002 -0.017 -0.000 C -4.02452897564 0.00329996303 -1.20791476641 -0.002 0.031 -0.000 C -4.73391255267 0.00451580118 -0.00020876193 -0.002 0.055 -0.000 C -4.02924140493 0.00399189729 1.20660077672 -0.002 0.030 -0.000 Co 0.00000000000 0.00000000000 0.00000000000 -0.005 -0.212 0.000 N -0.43839318333 -0.00054206762 -2.12229806799 -0.002 -0.090 0.001 C -1.76408906064 -0.00030645034 -2.37697009192 -0.002 -0.046 0.000 C -2.24773885821 -0.00257631963 -3.67934971086 -0.001 -0.036 -0.000 C -1.33713102227 -0.00526459193 -4.73855802198 -0.001 -0.065 0.000 C 0.02654101484 -0.00591797621 -4.46472703619 -0.001 -0.103 0.001 C 0.43371721952 -0.00363389350 -3.13225443930 -0.001 -0.111 0.001 S -6.53329279136 0.00637481657 -0.11611178087 -0.003 0.193 -0.001 N 2.00981687167 0.00259443239 -0.00000686048 -0.002 -0.164 0.000 C 2.67119656792 1.17263645248 0.00045766926 0.033 -0.172 0.000 C 4.06129317470 1.20536051565 0.00241240325 0.034 -0.213 0.001 C 4.76783866331 0.00148799420 0.00346798881 -0.002 -0.234 0.001 C 4.05723810074 -1.20352939940 0.00211502115 -0.037 -0.213 0.001 C 2.67108506586 -1.17139122066 0.00026591651 -0.036 -0.172 0.000 C 1.82209539371 2.39842937406 -0.00175320633 0.069 -0.147 0.000 C 2.33938959521 3.68993217240 -0.00584554905 0.107 -0.162 0.001 C 1.45736908622 4.77231118002 -0.00917967851 0.139 -0.136 0.001 C 0.08658913130 4.53522926787 -0.00833235387 0.132 -0.095 0.000 C -0.35359617412 3.21325694137 -0.00400174376 0.093 -0.082 0.000 N 0.49290585413 2.18198449515 -0.00068475564 0.067 -0.116 0.000 S 6.56718562933 -0.11349126889 0.00673479967 -0.009 -0.469 0.002 C 1.82142022278 -2.39594383179 -0.00206827421 -0.072 -0.147 -0.000 C 2.33969079820 -3.68709653410 -0.00625612120 -0.110 -0.162 -0.000 C 1.45789786198 -4.76953179608 -0.00945089783 -0.142 -0.136 -0.001 C 0.08684213972 -4.53272927032 -0.00840538011 -0.135 -0.096 -0.001 C -0.35393854068 -3.21111942258 -0.00398541364 -0.096 -0.083 -0.000 N 0.49225266031 -2.17934076887 -0.00084210065 -0.071 -0.117 -0.000 H 1.83694111827 5.77332096953 -0.01265611066 0.049 -0.043 0.000 H -0.61802819388 5.33967450634 -0.01131742088 0.045 -0.021 0.000 H 3.39175422949 3.87200638269 -0.00704552340 0.033 -0.056 0.000 H -1.39787683933 2.98334799634 -0.00369736757 0.025 -0.015 0.000 H 1.83794742242 -5.77033326187 -0.01295832570 -0.050 -0.043 -0.000 H -0.61749414542 -5.33746053721 -0.01121572048 -0.046 -0.022 -0.000 H -1.39833026435 -2.98175334118 -0.00345676225 -0.026 -0.015 -0.000 H 3.39230213722 -3.86796714602 -0.00754158092 -0.033 -0.056 -0.000 H 4.58301895157 2.13678100538 0.00314824260 0.018 -0.066 0.000 H 4.58784714512 -2.12983634010 0.00211631073 -0.019 -0.066 0.000 H -1.68997263563 -0.00719388386 -5.74925805817 -0.000 -0.017 0.000 H 0.75224758084 -0.00860493512 -5.25016290812 -0.000 -0.037 0.000 H -3.29620044300 -0.00255800648 -3.88456579214 -0.000 -0.002 -0.000 H 1.47161249279 -0.00457826661 -2.87685200854 -0.000 -0.041 0.000 H -1.69176120521 -0.00597000955 5.75026973076 -0.001 -0.017 -0.000 H 0.75025791005 -0.00892914887 5.25161119224 -0.001 -0.037 -0.000 H 1.46975366817 -0.00523069331 2.87805400798 -0.001 -0.041 -0.000 H -3.29750276746 -0.00099200484 3.88584245085 -0.001 -0.002 -0.000 H -4.55513299541 0.00377930937 -2.13473279421 -0.001 0.014 -0.000 H -4.55107479454 0.00501307822 2.13844314827 -0.001 0.014 -0.000 H -6.83436893102 0.00806057203 1.19721860356 -0.001 0.037 -0.000 H 6.86748209639 1.20005966818 0.00372860376 0.010 -0.086 0.000 61 Mode 7: freq= 18.65 N -0.44003451495 -0.00038510790 2.12369783068 0.058 -0.003 -0.027 C -1.76594470239 0.00039861437 2.37754210613 0.061 -0.004 0.008 C -2.24923313135 -0.00145267054 3.67997125809 0.093 -0.007 0.020 C -1.33887502024 -0.00450793845 4.73956848945 0.118 -0.010 -0.003 C 0.02462671625 -0.00591801736 4.46614405978 0.112 -0.009 -0.036 C 0.43187566201 -0.00376957955 3.13352499014 0.079 -0.005 -0.046 C -2.63984642995 0.00218980399 1.17162612704 0.030 -0.002 0.030 N -1.98513620489 0.00132140951 0.00153900685 0.000 -0.000 0.014 C -2.63911589169 0.00167522827 -1.17277445342 -0.030 0.002 0.030 C -4.02452897564 0.00329996303 -1.20791476641 -0.031 0.003 0.065 C -4.73391255267 0.00451580118 -0.00020876193 0.000 0.002 0.084 C -4.02924140493 0.00399189729 1.20660077672 0.031 -0.001 0.066 Co 0.00000000000 0.00000000000 0.00000000000 -0.000 -0.001 -0.077 N -0.43839318333 -0.00054206762 -2.12229806799 -0.058 0.002 -0.027 C -1.76408906064 -0.00030645034 -2.37697009192 -0.060 0.004 0.008 C -2.24773885821 -0.00257631963 -3.67934971086 -0.092 0.006 0.020 C -1.33713102227 -0.00526459193 -4.73855802198 -0.118 0.007 -0.003 C 0.02654101484 -0.00591797621 -4.46472703619 -0.111 0.006 -0.036 C 0.43371721952 -0.00363389350 -3.13225443930 -0.078 0.003 -0.046 S -6.53329279136 0.00637481657 -0.11611178087 -0.005 0.006 0.216 N 2.00981687167 0.00259443239 -0.00000686048 -0.000 0.000 -0.034 C 2.67119656792 1.17263645248 0.00045766926 -0.000 0.000 0.016 C 4.06129317470 1.20536051565 0.00241240325 -0.001 0.001 0.141 C 4.76783866331 0.00148799420 0.00346798881 -0.000 0.001 0.212 C 4.05723810074 -1.20352939940 0.00211502115 0.000 0.001 0.143 C 2.67108506586 -1.17139122066 0.00026591651 0.000 0.000 0.019 C 1.82209539371 2.39842937406 -0.00175320633 -0.000 0.000 -0.060 C 2.33938959521 3.68993217240 -0.00584554905 -0.001 -0.000 -0.130 C 1.45736908622 4.77231118002 -0.00917967851 -0.001 -0.000 -0.201 C 0.08658913130 4.53522926787 -0.00833235387 -0.001 -0.000 -0.201 C -0.35359617412 3.21325694137 -0.00400174376 -0.001 -0.000 -0.133 N 0.49290585413 2.18198449515 -0.00068475564 -0.000 0.000 -0.072 S 6.56718562933 -0.11349126889 0.00673479967 -0.001 0.002 0.662 C 1.82142022278 -2.39594383179 -0.00206827421 0.001 0.000 -0.055 C 2.33969079820 -3.68709653410 -0.00625612120 0.001 0.001 -0.116 C 1.45789786198 -4.76953179608 -0.00945089783 0.002 0.000 -0.186 C 0.08684213972 -4.53272927032 -0.00840538011 0.002 -0.000 -0.193 C -0.35393854068 -3.21111942258 -0.00398541364 0.001 -0.000 -0.133 N 0.49225266031 -2.17934076887 -0.00084210065 0.001 -0.000 -0.073 H 1.83694111827 5.77332096953 -0.01265611066 -0.000 -0.000 -0.074 H -0.61802819388 5.33967450634 -0.01131742088 -0.000 -0.000 -0.073 H 3.39175422949 3.87200638269 -0.00704552340 -0.000 -0.000 -0.040 H -1.39787683933 2.98334799634 -0.00369736757 -0.000 -0.000 -0.038 H 1.83794742242 -5.77033326187 -0.01295832570 0.001 0.000 -0.068 H -0.61749414542 -5.33746053721 -0.01121572048 0.001 -0.000 -0.071 H -1.39833026435 -2.98175334118 -0.00345676225 0.000 -0.000 -0.040 H 3.39230213722 -3.86796714602 -0.00754158092 0.000 0.000 -0.034 H 4.58301895157 2.13678100538 0.00314824260 -0.000 0.000 0.056 H 4.58784714512 -2.12983634010 0.00211631073 0.000 0.000 0.057 H -1.68997263563 -0.00719388386 -5.74925805817 -0.041 0.003 0.002 H 0.75224758084 -0.00860493512 -5.25016290812 -0.038 0.002 -0.016 H -3.29620044300 -0.00255800648 -3.88456579214 -0.028 0.002 0.013 H 1.47161249279 -0.00457826661 -2.87685200854 -0.021 0.001 -0.020 H -1.69176120521 -0.00597000955 5.75026973076 0.041 -0.004 0.002 H 0.75025791005 -0.00892914887 5.25161119224 0.038 -0.003 -0.016 H 1.46975366817 -0.00523069331 2.87805400798 0.021 -0.001 -0.020 H -3.29750276746 -0.00099200484 3.88584245085 0.028 -0.002 0.013 H -4.55513299541 0.00377930937 -2.13473279421 -0.016 0.001 0.023 H -4.55107479454 0.00501307822 2.13844314827 0.016 -0.000 0.023 H -6.83436893102 0.00806057203 1.19721860356 0.009 0.000 0.041 H 6.86748209639 1.20005966818 0.00372860376 -0.000 0.000 0.119 61 Mode 8: freq=19.65 N -0.44003451495 -0.00038510790 2.12369783068 0.001 0.077 0.000 C -1.76594470239 0.00039861437 2.37754210613 0.001 0.047 0.000 C -2.24923313135 -0.00145267054 3.67997125809 0.001 0.095 0.001 C -1.33887502024 -0.00450793845 4.73956848945 0.001 0.165 0.000 C 0.02462671625 -0.00591801736 4.46614405978 0.001 0.185 0.000 C 0.43187566201 -0.00376957955 3.13352499014 0.001 0.137 -0.000 C -2.63984642995 0.00218980399 1.17162612704 0.000 -0.024 0.001 N -1.98513620489 0.00132140951 0.00153900685 0.000 0.028 0.000 C -2.63911589169 0.00167522827 -1.17277445342 -0.000 -0.027 0.001 C -4.02452897564 0.00329996303 -1.20791476641 -0.001 -0.150 0.001 C -4.73391255267 0.00451580118 -0.00020876193 -0.000 -0.217 0.001 C -4.02924140493 0.00399189729 1.20660077672 0.000 -0.147 0.001 Co 0.00000000000 0.00000000000 0.00000000000 0.000 0.097 -0.001 N -0.43839318333 -0.00054206762 -2.12229806799 -0.001 0.076 -0.000 C -1.76408906064 -0.00030645034 -2.37697009192 -0.001 0.042 0.000 C -2.24773885821 -0.00257631963 -3.67934971086 -0.001 0.084 0.000 C -1.33713102227 -0.00526459193 -4.73855802198 -0.001 0.152 -0.000 C 0.02654101484 -0.00591797621 -4.46472703619 -0.001 0.178 -0.001 C 0.43371721952 -0.00363389350 -3.13225443930 -0.001 0.135 -0.001 S -6.53329279136 0.00637481657 -0.11611178087 -0.001 -0.665 0.003 N 2.00981687167 0.00259443239 -0.00000686048 0.000 -0.008 -0.000 C 2.67119656792 1.17263645248 0.00045766926 0.034 -0.027 0.002 C 4.06129317470 1.20536051565 0.00241240325 0.035 -0.067 0.003 C 4.76783866331 0.00148799420 0.00346798881 0.000 -0.087 0.002 C 4.05723810074 -1.20352939940 0.00211502115 -0.035 -0.067 -0.000 C 2.67108506586 -1.17139122066 0.00026591651 -0.034 -0.027 -0.001 C 1.82209539371 2.39842937406 -0.00175320633 0.068 -0.003 0.003 C 2.33938959521 3.68993217240 -0.00584554905 0.103 -0.018 0.005 C 1.45736908622 4.77231118002 -0.00917967851 0.133 0.007 0.006 C 0.08658913130 4.53522926787 -0.00833235387 0.127 0.044 0.004 C -0.35359617412 3.21325694137 -0.00400174376 0.090 0.056 0.002 N 0.49290585413 2.18198449515 -0.00068475564 0.066 0.036 0.001 S 6.56718562933 -0.11349126889 0.00673479967 -0.006 -0.231 0.005 C 1.82142022278 -2.39594383179 -0.00206827421 -0.068 -0.003 -0.004 C 2.33969079820 -3.68709653410 -0.00625612120 -0.104 -0.018 -0.007 C 1.45789786198 -4.76953179608 -0.00945089783 -0.133 0.007 -0.009 C 0.08684213972 -4.53272927032 -0.00840538011 -0.127 0.045 -0.008 C -0.35393854068 -3.21111942258 -0.00398541364 -0.090 0.057 -0.004 N 0.49225266031 -2.17934076887 -0.00084210065 -0.066 0.036 -0.003 H 1.83694111827 5.77332096953 -0.01265611066 0.046 -0.001 0.002 H -0.61802819388 5.33967450634 -0.01131742088 0.043 0.019 0.001 H 3.39175422949 3.87200638269 -0.00704552340 0.031 -0.014 0.002 H -1.39787683933 2.98334799634 -0.00369736757 0.024 0.024 0.000 H 1.83794742242 -5.77033326187 -0.01295832570 -0.047 -0.001 -0.003 H -0.61749414542 -5.33746053721 -0.01121572048 -0.043 0.019 -0.003 H -1.39833026435 -2.98175334118 -0.00345676225 -0.024 0.025 -0.001 H 3.39230213722 -3.86796714602 -0.00754158092 -0.031 -0.014 -0.002 H 4.58301895157 2.13678100538 0.00314824260 0.018 -0.024 0.001 H 4.58784714512 -2.12983634010 0.00211631073 -0.018 -0.024 -0.000 H -1.68997263563 -0.00719388386 -5.74925805817 -0.000 0.054 -0.000 H 0.75224758084 -0.00860493512 -5.25016290812 -0.000 0.067 -0.000 H -3.29620044300 -0.00255800648 -3.88456579214 -0.000 0.020 0.000 H 1.47161249279 -0.00457826661 -2.87685200854 -0.000 0.045 -0.000 H -1.69176120521 -0.00597000955 5.75026973076 0.001 0.059 0.000 H 0.75025791005 -0.00892914887 5.25161119224 0.000 0.069 0.000 H 1.46975366817 -0.00523069331 2.87805400798 0.000 0.044 -0.000 H -3.29750276746 -0.00099200484 3.88584245085 0.000 0.024 0.000 H -4.55513299541 0.00377930937 -2.13473279421 -0.000 -0.059 0.000 H -4.55107479454 0.00501307822 2.13844314827 0.000 -0.057 0.000 H -6.83436893102 0.00806057203 1.19721860356 -0.000 -0.119 0.001 H 6.86748209639 1.20005966818 0.00372860376 0.010 -0.044 0.001 61 Mode 9: freq=28.18 N -0.44003451495 -0.00038510790 2.12369783068 -0.002 -0.060 0.002 C -1.76594470239 0.00039861437 2.37754210613 -0.002 -0.121 0.001 C -2.24923313135 -0.00145267054 3.67997125809 -0.003 -0.238 -0.000 C -1.33887502024 -0.00450793845 4.73956848945 -0.004 -0.285 0.001 C 0.02462671625 -0.00591801736 4.46614405978 -0.004 -0.209 0.002 C 0.43187566201 -0.00376957955 3.13352499014 -0.003 -0.095 0.003 C -2.63984642995 0.00218980399 1.17162612704 -0.001 -0.062 -0.000 N -1.98513620489 0.00132140951 0.00153900685 0.000 0.000 0.000 C -2.63911589169 0.00167522827 -1.17277445342 0.001 0.060 -0.000 C -4.02452897564 0.00329996303 -1.20791476641 0.001 0.057 -0.001 C -4.73391255267 0.00451580118 -0.00020876193 0.000 -0.007 -0.002 C -4.02924140493 0.00399189729 1.20660077672 -0.001 -0.066 -0.001 Co 0.00000000000 0.00000000000 0.00000000000 0.001 0.003 0.004 N -0.43839318333 -0.00054206762 -2.12229806799 0.002 0.065 0.001 C -1.76408906064 -0.00030645034 -2.37697009192 0.002 0.123 0.000 C -2.24773885821 -0.00257631963 -3.67934971086 0.003 0.242 -0.000 C -1.33713102227 -0.00526459193 -4.73855802198 0.004 0.292 0.000 C 0.02654101484 -0.00591797621 -4.46472703619 0.003 0.220 0.001 C 0.43371721952 -0.00363389350 -3.13225443930 0.002 0.103 0.001 S -6.53329279136 0.00637481657 -0.11611178087 0.000 -0.009 -0.006 N 2.00981687167 0.00259443239 -0.00000686048 0.000 0.000 0.001 C 2.67119656792 1.17263645248 0.00045766926 0.001 -0.000 -0.059 C 4.06129317470 1.20536051565 0.00241240325 0.001 -0.001 -0.062 C 4.76783866331 0.00148799420 0.00346798881 0.000 -0.002 -0.007 C 4.05723810074 -1.20352939940 0.00211502115 -0.001 -0.001 0.052 C 2.67108506586 -1.17139122066 0.00026591651 -0.001 -0.000 0.057 C 1.82209539371 2.39842937406 -0.00175320633 0.002 0.000 -0.117 C 2.33938959521 3.68993217240 -0.00584554905 0.002 -0.001 -0.250 C 1.45736908622 4.77231118002 -0.00917967851 0.003 -0.000 -0.293 C 0.08658913130 4.53522926787 -0.00833235387 0.003 0.001 -0.200 C -0.35359617412 3.21325694137 -0.00400174376 0.002 0.001 -0.072 N 0.49290585413 2.18198449515 -0.00068475564 0.002 0.001 -0.038 S 6.56718562933 -0.11349126889 0.00673479967 0.000 -0.005 -0.012 C 1.82142022278 -2.39594383179 -0.00206827421 -0.002 0.000 0.119 C 2.33969079820 -3.68709653410 -0.00625612120 -0.003 -0.001 0.254 C 1.45789786198 -4.76953179608 -0.00945089783 -0.004 -0.000 0.303 C 0.08684213972 -4.53272927032 -0.00840538011 -0.004 0.001 0.213 C -0.35393854068 -3.21111942258 -0.00398541364 -0.003 0.002 0.082 N 0.49225266031 -2.17934076887 -0.00084210065 -0.002 0.002 0.045 H 1.83694111827 5.77332096953 -0.01265611066 0.001 -0.000 -0.115 H -0.61802819388 5.33967450634 -0.01131742088 0.001 0.000 -0.065 H 3.39175422949 3.87200638269 -0.00704552340 0.001 -0.000 -0.094 H -1.39787683933 2.98334799634 -0.00369736757 0.001 0.001 0.001 H 1.83794742242 -5.77033326187 -0.01295832570 -0.001 -0.000 0.118 H -0.61749414542 -5.33746053721 -0.01121572048 -0.001 0.001 0.070 H -1.39833026435 -2.98175334118 -0.00345676225 -0.001 0.001 0.003 H 3.39230213722 -3.86796714602 -0.00754158092 -0.001 -0.001 0.094 H 4.58301895157 2.13678100538 0.00314824260 0.000 -0.000 -0.030 H 4.58784714512 -2.12983634010 0.00211631073 -0.000 -0.000 0.026 H -1.68997263563 -0.00719388386 -5.74925805817 0.001 0.112 -0.000 H 0.75224758084 -0.00860493512 -5.25016290812 0.001 0.073 0.000 H -3.29620044300 -0.00255800648 -3.88456579214 0.001 0.086 -0.000 H 1.47161249279 -0.00457826661 -2.87685200854 0.001 0.013 0.001 H -1.69176120521 -0.00597000955 5.75026973076 -0.002 -0.109 0.000 H 0.75025791005 -0.00892914887 5.25161119224 -0.001 -0.069 0.001 H 1.46975366817 -0.00523069331 2.87805400798 -0.001 -0.010 0.001 H -3.29750276746 -0.00099200484 3.88584245085 -0.001 -0.086 -0.000 H -4.55513299541 0.00377930937 -2.13473279421 0.001 0.029 -0.001 H -4.55107479454 0.00501307822 2.13844314827 -0.000 -0.032 -0.001 H -6.83436893102 0.00806057203 1.19721860356 -0.000 -0.021 -0.001 H 6.86748209639 1.20005966818 0.00372860376 0.000 -0.001 -0.021 61 Mode 10: freq=47.21 N -0.44003451495 -0.00038510790 2.12369783068 0.063 0.001 -0.130 C -1.76594470239 0.00039861437 2.37754210613 0.066 -0.001 -0.083 C -2.24923313135 -0.00145267054 3.67997125809 0.105 -0.003 -0.069 C -1.33887502024 -0.00450793845 4.73956848945 0.137 -0.004 -0.096 C 0.02462671625 -0.00591801736 4.46614405978 0.129 -0.002 -0.136 C 0.43187566201 -0.00376957955 3.13352499014 0.089 0.001 -0.148 C -2.63984642995 0.00218980399 1.17162612704 0.033 -0.000 -0.059 N -1.98513620489 0.00132140951 0.00153900685 0.000 0.000 -0.085 C -2.63911589169 0.00167522827 -1.17277445342 -0.033 0.000 -0.059 C -4.02452897564 0.00329996303 -1.20791476641 -0.035 0.000 -0.019 C -4.73391255267 0.00451580118 -0.00020876193 0.000 -0.000 0.001 C -4.02924140493 0.00399189729 1.20660077672 0.035 -0.000 -0.019 Co 0.00000000000 0.00000000000 0.00000000000 0.001 0.001 -0.261 N -0.43839318333 -0.00054206762 -2.12229806799 -0.062 -0.000 -0.131 C -1.76408906064 -0.00030645034 -2.37697009192 -0.066 0.000 -0.084 C -2.24773885821 -0.00257631963 -3.67934971086 -0.105 0.000 -0.069 C -1.33713102227 -0.00526459193 -4.73855802198 -0.137 -0.000 -0.097 C 0.02654101484 -0.00591797621 -4.46472703619 -0.130 -0.001 -0.137 C 0.43371721952 -0.00363389350 -3.13225443930 -0.089 -0.001 -0.148 S -6.53329279136 0.00637481657 -0.11611178087 -0.006 -0.000 0.094 N 2.00981687167 0.00259443239 -0.00000686048 0.000 0.000 -0.043 C 2.67119656792 1.17263645248 0.00045766926 0.000 0.000 0.001 C 4.06129317470 1.20536051565 0.00241240325 0.000 0.000 0.033 C 4.76783866331 0.00148799420 0.00346798881 0.000 -0.000 0.042 C 4.05723810074 -1.20352939940 0.00211502115 -0.000 0.000 0.034 C 2.67108506586 -1.17139122066 0.00026591651 0.000 0.000 0.003 C 1.82209539371 2.39842937406 -0.00175320633 0.000 0.001 0.057 C 2.33938959521 3.68993217240 -0.00584554905 0.001 0.001 0.270 C 1.45736908622 4.77231118002 -0.00917967851 0.001 0.001 0.347 C 0.08658913130 4.53522926787 -0.00833235387 0.001 0.001 0.202 C -0.35359617412 3.21325694137 -0.00400174376 0.001 0.001 -0.008 N 0.49290585413 2.18198449515 -0.00068475564 0.000 0.000 -0.074 S 6.56718562933 -0.11349126889 0.00673479967 0.000 -0.001 0.151 C 1.82142022278 -2.39594383179 -0.00206827421 -0.000 0.000 0.058 C 2.33969079820 -3.68709653410 -0.00625612120 -0.000 -0.000 0.269 C 1.45789786198 -4.76953179608 -0.00945089783 -0.001 -0.001 0.347 C 0.08684213972 -4.53272927032 -0.00840538011 -0.001 0.000 0.204 C -0.35393854068 -3.21111942258 -0.00398541364 -0.000 0.001 -0.004 N 0.49225266031 -2.17934076887 -0.00084210065 -0.000 0.001 -0.070 H 1.83694111827 5.77332096953 -0.01265611066 0.000 0.001 0.150 H -0.61802819388 5.33967450634 -0.01131742088 0.000 0.000 0.073 H 3.39175422949 3.87200638269 -0.00704552340 0.000 0.000 0.112 H -1.39787683933 2.98334799634 -0.00369736757 0.000 0.000 -0.035 H 1.83794742242 -5.77033326187 -0.01295832570 -0.000 -0.000 0.149 H -0.61749414542 -5.33746053721 -0.01121572048 -0.000 0.000 0.073 H -1.39833026435 -2.98175334118 -0.00345676225 -0.000 0.000 -0.034 H 3.39230213722 -3.86796714602 -0.00754158092 -0.000 -0.000 0.111 H 4.58301895157 2.13678100538 0.00314824260 0.000 -0.000 0.015 H 4.58784714512 -2.12983634010 0.00211631073 -0.000 0.000 0.016 H -1.68997263563 -0.00719388386 -5.74925805817 -0.049 0.000 -0.025 H 0.75224758084 -0.00860493512 -5.25016290812 -0.044 -0.000 -0.046 H -3.29620044300 -0.00255800648 -3.88456579214 -0.032 0.000 -0.011 H 1.47161249279 -0.00457826661 -2.87685200854 -0.023 -0.000 -0.052 H -1.69176120521 -0.00597000955 5.75026973076 0.048 -0.002 -0.025 H 0.75025791005 -0.00892914887 5.25161119224 0.044 -0.001 -0.046 H 1.46975366817 -0.00523069331 2.87805400798 0.023 0.001 -0.052 H -3.29750276746 -0.00099200484 3.88584245085 0.032 -0.001 -0.011 H -4.55513299541 0.00377930937 -2.13473279421 -0.018 0.000 -0.001 H -4.55107479454 0.00501307822 2.13844314827 0.018 -0.000 -0.001 H -6.83436893102 0.00806057203 1.19721860356 0.011 -0.000 0.019 H 6.86748209639 1.20005966818 0.00372860376 0.000 -0.000 0.019 61 Mode 11: freq=48.49 N -0.44003451495 -0.00038510790 2.12369783068 0.000 0.053 0.001 C -1.76594470239 0.00039861437 2.37754210613 -0.000 -0.062 0.001 C -2.24923313135 -0.00145267054 3.67997125809 -0.001 -0.271 0.000 C -1.33887502024 -0.00450793845 4.73956848945 -0.001 -0.361 0.000 C 0.02462671625 -0.00591801736 4.46614405978 -0.001 -0.231 0.001 C 0.43187566201 -0.00376957955 3.13352499014 -0.000 -0.023 0.001 C -2.63984642995 0.00218980399 1.17162612704 0.000 -0.002 0.000 N -1.98513620489 0.00132140951 0.00153900685 0.001 0.040 0.000 C -2.63911589169 0.00167522827 -1.17277445342 0.001 -0.003 0.000 C -4.02452897564 0.00329996303 -1.20791476641 0.001 -0.027 0.000 C -4.73391255267 0.00451580118 -0.00020876193 0.000 -0.028 0.000 C -4.02924140493 0.00399189729 1.20660077672 0.000 -0.026 0.000 Co 0.00000000000 0.00000000000 0.00000000000 0.002 0.256 0.001 N -0.43839318333 -0.00054206762 -2.12229806799 0.001 0.051 -0.000 C -1.76408906064 -0.00030645034 -2.37697009192 0.001 -0.063 0.000 C -2.24773885821 -0.00257631963 -3.67934971086 0.000 -0.269 0.001 C -1.33713102227 -0.00526459193 -4.73855802198 0.000 -0.359 0.001 C 0.02654101484 -0.00591797621 -4.46472703619 0.000 -0.231 0.001 C 0.43371721952 -0.00363389350 -3.13225443930 0.000 -0.024 0.000 S -6.53329279136 0.00637481657 -0.11611178087 0.001 -0.096 -0.000 N 2.00981687167 0.00259443239 -0.00000686048 0.000 0.090 0.000 C 2.67119656792 1.17263645248 0.00045766926 0.030 0.066 0.000 C 4.06129317470 1.20536051565 0.00241240325 0.032 0.030 -0.000 C 4.76783866331 0.00148799420 0.00346798881 0.000 0.012 -0.000 C 4.05723810074 -1.20352939940 0.00211502115 -0.031 0.030 -0.000 C 2.67108506586 -1.17139122066 0.00026591651 -0.029 0.066 0.000 C 1.82209539371 2.39842937406 -0.00175320633 0.060 0.087 -0.000 C 2.33938959521 3.68993217240 -0.00584554905 0.096 0.072 -0.000 C 1.45736908622 4.77231118002 -0.00917967851 0.126 0.097 -0.001 C 0.08658913130 4.53522926787 -0.00833235387 0.120 0.133 -0.001 C -0.35359617412 3.21325694137 -0.00400174376 0.083 0.145 -0.001 N 0.49290585413 2.18198449515 -0.00068475564 0.058 0.130 -0.001 S 6.56718562933 -0.11349126889 0.00673479967 -0.005 -0.062 -0.001 C 1.82142022278 -2.39594383179 -0.00206827421 -0.060 0.087 -0.000 C 2.33969079820 -3.68709653410 -0.00625612120 -0.096 0.072 -0.002 C 1.45789786198 -4.76953179608 -0.00945089783 -0.127 0.097 -0.003 C 0.08684213972 -4.53272927032 -0.00840538011 -0.121 0.134 -0.001 C -0.35393854068 -3.21111942258 -0.00398541364 -0.083 0.146 0.001 N 0.49225266031 -2.17934076887 -0.00084210065 -0.058 0.131 0.001 H 1.83694111827 5.77332096953 -0.01265611066 0.044 0.025 -0.000 H -0.61802819388 5.33967450634 -0.01131742088 0.041 0.044 -0.001 H 3.39175422949 3.87200638269 -0.00704552340 0.029 0.012 0.000 H -1.39787683933 2.98334799634 -0.00369736757 0.022 0.050 -0.000 H 1.83794742242 -5.77033326187 -0.01295832570 -0.045 0.025 -0.001 H -0.61749414542 -5.33746053721 -0.01121572048 -0.041 0.044 -0.000 H -1.39833026435 -2.98175334118 -0.00345676225 -0.022 0.051 0.001 H 3.39230213722 -3.86796714602 -0.00754158092 -0.029 0.012 -0.001 H 4.58301895157 2.13678100538 0.00314824260 0.016 0.005 -0.000 H 4.58784714512 -2.12983634010 0.00211631073 -0.016 0.005 -0.000 H -1.68997263563 -0.00719388386 -5.74925805817 -0.000 -0.152 0.000 H 0.75224758084 -0.00860493512 -5.25016290812 0.000 -0.084 0.000 H -3.29620044300 -0.00255800648 -3.88456579214 0.000 -0.107 0.000 H 1.47161249279 -0.00457826661 -2.87685200854 0.000 0.022 -0.000 H -1.69176120521 -0.00597000955 5.75026973076 -0.001 -0.153 -0.000 H 0.75025791005 -0.00892914887 5.25161119224 -0.000 -0.084 0.000 H 1.46975366817 -0.00523069331 2.87805400798 -0.000 0.023 0.001 H -3.29750276746 -0.00099200484 3.88584245085 -0.000 -0.109 -0.000 H -4.55513299541 0.00377930937 -2.13473279421 0.000 -0.013 0.000 H -4.55107479454 0.00501307822 2.13844314827 0.000 -0.013 0.000 H -6.83436893102 0.00806057203 1.19721860356 0.000 -0.010 -0.000 H 6.86748209639 1.20005966818 0.00372860376 0.010 -0.014 -0.000 61 Mode 12: freq=56.40 N -0.44003451495 -0.00038510790 2.12369783068 -0.027 -0.000 -0.173 C -1.76594470239 0.00039861437 2.37754210613 -0.014 0.000 -0.055 C -2.24923313135 -0.00145267054 3.67997125809 0.088 0.000 -0.023 C -1.33887502024 -0.00450793845 4.73956848945 0.172 -0.001 -0.092 C 0.02462671625 -0.00591801736 4.46614405978 0.150 -0.003 -0.197 C 0.43187566201 -0.00376957955 3.13352499014 0.051 -0.002 -0.227 C -2.63984642995 0.00218980399 1.17162612704 -0.087 0.001 0.001 N -1.98513620489 0.00132140951 0.00153900685 -0.118 0.002 -0.001 C -2.63911589169 0.00167522827 -1.17277445342 -0.087 0.001 -0.002 C -4.02452897564 0.00329996303 -1.20791476641 -0.086 0.001 -0.009 C -4.73391255267 0.00451580118 -0.00020876193 -0.082 0.000 -0.000 C -4.02924140493 0.00399189729 1.20660077672 -0.086 0.000 0.008 Co 0.00000000000 0.00000000000 0.00000000000 -0.323 0.001 -0.000 N -0.43839318333 -0.00054206762 -2.12229806799 -0.027 -0.001 0.172 C -1.76408906064 -0.00030645034 -2.37697009192 -0.014 0.001 0.054 C -2.24773885821 -0.00257631963 -3.67934971086 0.088 0.002 0.022 C -1.33713102227 -0.00526459193 -4.73855802198 0.172 0.001 0.091 C 0.02654101484 -0.00591797621 -4.46472703619 0.150 -0.002 0.196 C 0.43371721952 -0.00363389350 -3.13225443930 0.051 -0.003 0.226 S -6.53329279136 0.00637481657 -0.11611178087 -0.137 -0.003 -0.001 N 2.00981687167 0.00259443239 -0.00000686048 -0.069 0.001 -0.001 C 2.67119656792 1.17263645248 0.00045766926 -0.049 -0.001 -0.001 C 4.06129317470 1.20536051565 0.00241240325 -0.047 -0.006 -0.001 C 4.76783866331 0.00148799420 0.00346798881 -0.044 0.001 -0.000 C 4.05723810074 -1.20352939940 0.00211502115 -0.047 0.008 -0.000 C 2.67108506586 -1.17139122066 0.00026591651 -0.049 0.003 -0.000 C 1.82209539371 2.39842937406 -0.00175320633 0.010 0.044 -0.001 C 2.33938959521 3.68993217240 -0.00584554905 0.097 0.014 -0.002 C 1.45736908622 4.77231118002 -0.00917967851 0.174 0.073 -0.001 C 0.08658913130 4.53522926787 -0.00833235387 0.157 0.166 0.002 C -0.35359617412 3.21325694137 -0.00400174376 0.071 0.195 0.003 N 0.49290585413 2.18198449515 -0.00068475564 0.001 0.147 0.002 S 6.56718562933 -0.11349126889 0.00673479967 -0.073 0.001 -0.000 C 1.82142022278 -2.39594383179 -0.00206827421 0.010 -0.042 -0.000 C 2.33969079820 -3.68709653410 -0.00625612120 0.097 -0.012 -0.001 C 1.45789786198 -4.76953179608 -0.00945089783 0.174 -0.071 0.000 C 0.08684213972 -4.53272927032 -0.00840538011 0.157 -0.165 0.002 C -0.35393854068 -3.21111942258 -0.00398541364 0.070 -0.193 0.002 N 0.49225266031 -2.17934076887 -0.00084210065 0.000 -0.145 0.001 H 1.83694111827 5.77332096953 -0.01265611066 0.071 0.014 -0.001 H -0.61802819388 5.33967450634 -0.01131742088 0.061 0.062 0.001 H 3.39175422949 3.87200638269 -0.00704552340 0.031 -0.015 -0.001 H -1.39787683933 2.98334799634 -0.00369736757 0.016 0.077 0.002 H 1.83794742242 -5.77033326187 -0.01295832570 0.070 -0.013 0.000 H -0.61749414542 -5.33746053721 -0.01121572048 0.061 -0.061 0.001 H -1.39833026435 -2.98175334118 -0.00345676225 0.016 -0.076 0.001 H 3.39230213722 -3.86796714602 -0.00754158092 0.031 0.015 -0.000 H 4.58301895157 2.13678100538 0.00314824260 -0.013 -0.002 -0.000 H 4.58784714512 -2.12983634010 0.00211631073 -0.014 0.003 -0.000 H -1.68997263563 -0.00719388386 -5.74925805817 0.073 0.000 0.018 H 0.75224758084 -0.00860493512 -5.25016290812 0.061 -0.001 0.073 H -3.29620044300 -0.00255800648 -3.88456579214 0.029 0.001 -0.015 H 1.47161249279 -0.00457826661 -2.87685200854 0.009 -0.001 0.088 H -1.69176120521 -0.00597000955 5.75026973076 0.073 -0.001 -0.019 H 0.75025791005 -0.00892914887 5.25161119224 0.061 -0.001 -0.073 H 1.46975366817 -0.00523069331 2.87805400798 0.009 -0.001 -0.088 H -3.29750276746 -0.00099200484 3.88584245085 0.029 0.000 0.014 H -4.55513299541 0.00377930937 -2.13473279421 -0.025 0.000 -0.003 H -4.55107479454 0.00501307822 2.13844314827 -0.025 -0.000 0.003 H -6.83436893102 0.00806057203 1.19721860356 -0.024 -0.001 -0.000 H 6.86748209639 1.20005966818 0.00372860376 -0.013 0.000 -0.000 61 Mode 13: freq=73.34 N -0.44003451495 -0.00038510790 2.12369783068 -0.000 -0.171 -0.001 C -1.76594470239 0.00039861437 2.37754210613 0.000 0.029 -0.001 C -2.24923313135 -0.00145267054 3.67997125809 0.000 0.212 -0.001 C -1.33887502024 -0.00450793845 4.73956848945 0.000 0.163 -0.001 C 0.02462671625 -0.00591801736 4.46614405978 -0.000 -0.076 -0.001 C 0.43187566201 -0.00376957955 3.13352499014 -0.000 -0.224 -0.001 C -2.63984642995 0.00218980399 1.17162612704 0.000 0.027 -0.001 N -1.98513620489 0.00132140951 0.00153900685 0.000 0.005 -0.001 C -2.63911589169 0.00167522827 -1.17277445342 0.000 -0.017 -0.001 C -4.02452897564 0.00329996303 -1.20791476641 0.000 -0.016 -0.001 C -4.73391255267 0.00451580118 -0.00020876193 0.000 0.003 -0.001 C -4.02924140493 0.00399189729 1.20660077672 0.000 0.025 -0.001 Co 0.00000000000 0.00000000000 0.00000000000 0.000 0.002 -0.004 N -0.43839318333 -0.00054206762 -2.12229806799 0.000 0.167 -0.001 C -1.76408906064 -0.00030645034 -2.37697009192 0.000 -0.024 -0.001 C -2.24773885821 -0.00257631963 -3.67934971086 -0.000 -0.204 -0.001 C -1.33713102227 -0.00526459193 -4.73855802198 -0.000 -0.166 -0.001 C 0.02654101484 -0.00591797621 -4.46472703619 0.000 0.060 -0.001 C 0.43371721952 -0.00363389350 -3.13225443930 0.000 0.209 -0.002 S -6.53329279136 0.00637481657 -0.11611178087 0.000 -0.009 -0.003 N 2.00981687167 0.00259443239 -0.00000686048 0.000 0.000 -0.010 C 2.67119656792 1.17263645248 0.00045766926 -0.000 0.000 -0.040 C 4.06129317470 1.20536051565 0.00241240325 -0.000 0.000 -0.036 C 4.76783866331 0.00148799420 0.00346798881 0.000 0.001 -0.005 C 4.05723810074 -1.20352939940 0.00211502115 0.000 0.000 0.022 C 2.67108506586 -1.17139122066 0.00026591651 0.000 0.000 0.022 C 1.82209539371 2.39842937406 -0.00175320633 -0.000 0.000 -0.035 C 2.33938959521 3.68993217240 -0.00584554905 -0.000 -0.000 -0.255 C 1.45736908622 4.77231118002 -0.00917967851 -0.001 -0.000 -0.159 C 0.08658913130 4.53522926787 -0.00833235387 -0.001 0.000 0.163 C -0.35359617412 3.21325694137 -0.00400174376 -0.000 0.001 0.329 N 0.49290585413 2.18198449515 -0.00068475564 -0.000 0.001 0.231 S 6.56718562933 -0.11349126889 0.00673479967 -0.000 0.001 0.018 C 1.82142022278 -2.39594383179 -0.00206827421 0.000 0.000 0.025 C 2.33969079820 -3.68709653410 -0.00625612120 0.000 -0.000 0.236 C 1.45789786198 -4.76953179608 -0.00945089783 0.000 -0.000 0.162 C 0.08684213972 -4.53272927032 -0.00840538011 -0.000 0.001 -0.130 C -0.35393854068 -3.21111942258 -0.00398541364 -0.000 0.001 -0.295 N 0.49225266031 -2.17934076887 -0.00084210065 -0.000 0.001 -0.218 H 1.83694111827 5.77332096953 -0.01265611066 -0.000 -0.000 -0.094 H -0.61802819388 5.33967450634 -0.01131742088 -0.000 0.000 0.077 H 3.39175422949 3.87200638269 -0.00704552340 -0.000 -0.000 -0.144 H -1.39787683933 2.98334799634 -0.00369736757 -0.000 0.000 0.158 H 1.83794742242 -5.77033326187 -0.01295832570 0.000 -0.000 0.093 H -0.61749414542 -5.33746053721 -0.01121572048 0.000 0.000 -0.062 H -1.39833026435 -2.98175334118 -0.00345676225 -0.000 0.001 -0.143 H 3.39230213722 -3.86796714602 -0.00754158092 0.000 -0.000 0.132 H 4.58301895157 2.13678100538 0.00314824260 -0.000 0.000 -0.011 H 4.58784714512 -2.12983634010 0.00211631073 0.000 0.000 0.008 H -1.68997263563 -0.00719388386 -5.74925805817 -0.000 -0.089 -0.000 H 0.75224758084 -0.00860493512 -5.25016290812 0.000 0.032 -0.000 H -3.29620044300 -0.00255800648 -3.88456579214 -0.000 -0.108 -0.000 H 1.47161249279 -0.00457826661 -2.87685200854 0.000 0.105 -0.001 H -1.69176120521 -0.00597000955 5.75026973076 0.000 0.088 -0.000 H 0.75025791005 -0.00892914887 5.25161119224 -0.000 -0.039 -0.000 H 1.46975366817 -0.00523069331 2.87805400798 -0.000 -0.111 -0.000 H -3.29750276746 -0.00099200484 3.88584245085 0.000 0.114 -0.000 H -4.55513299541 0.00377930937 -2.13473279421 0.000 -0.006 -0.000 H -4.55107479454 0.00501307822 2.13844314827 -0.000 0.008 -0.000 H -6.83436893102 0.00806057203 1.19721860356 -0.000 0.008 -0.000 H 6.86748209639 1.20005966818 0.00372860376 -0.000 0.000 -0.012 61 Mode 14: freq=79.05 N -0.44003451495 -0.00038510790 2.12369783068 -0.001 0.010 -0.014 C -1.76594470239 0.00039861437 2.37754210613 -0.001 -0.002 -0.014 C -2.24923313135 -0.00145267054 3.67997125809 -0.002 -0.013 -0.014 C -1.33887502024 -0.00450793845 4.73956848945 -0.002 -0.008 -0.014 C 0.02462671625 -0.00591801736 4.46614405978 -0.002 0.007 -0.013 C 0.43187566201 -0.00376957955 3.13352499014 -0.002 0.015 -0.013 C -2.63984642995 0.00218980399 1.17162612704 -0.001 -0.002 -0.015 N -1.98513620489 0.00132140951 0.00153900685 0.001 0.000 -0.014 C -2.63911589169 0.00167522827 -1.17277445342 0.003 0.002 -0.015 C -4.02452897564 0.00329996303 -1.20791476641 0.004 0.002 -0.019 C -4.73391255267 0.00451580118 -0.00020876193 0.001 -0.000 -0.021 C -4.02924140493 0.00399189729 1.20660077672 -0.002 -0.002 -0.019 Co 0.00000000000 0.00000000000 0.00000000000 0.002 0.000 -0.075 N -0.43839318333 -0.00054206762 -2.12229806799 0.002 -0.010 -0.015 C -1.76408906064 -0.00030645034 -2.37697009192 0.002 0.002 -0.014 C -2.24773885821 -0.00257631963 -3.67934971086 0.002 0.013 -0.014 C -1.33713102227 -0.00526459193 -4.73855802198 0.001 0.008 -0.015 C 0.02654101484 -0.00591797621 -4.46472703619 0.001 -0.007 -0.015 C 0.43371721952 -0.00363389350 -3.13225443930 0.002 -0.015 -0.016 S -6.53329279136 0.00637481657 -0.11611178087 0.003 0.000 -0.052 N 2.00981687167 0.00259443239 -0.00000686048 0.000 0.000 -0.194 C 2.67119656792 1.17263645248 0.00045766926 0.000 0.000 -0.180 C 4.06129317470 1.20536051565 0.00241240325 0.000 0.000 -0.126 C 4.76783866331 0.00148799420 0.00346798881 -0.000 0.000 -0.062 C 4.05723810074 -1.20352939940 0.00211502115 0.000 -0.000 -0.127 C 2.67108506586 -1.17139122066 0.00026591651 0.000 0.000 -0.181 C 1.82209539371 2.39842937406 -0.00175320633 -0.000 -0.000 -0.120 C 2.33938959521 3.68993217240 -0.00584554905 -0.001 -0.000 -0.225 C 1.45736908622 4.77231118002 -0.00917967851 -0.002 -0.000 -0.011 C 0.08658913130 4.53522926787 -0.00833235387 -0.002 -0.000 0.301 C -0.35359617412 3.21325694137 -0.00400174376 -0.001 -0.000 0.331 N 0.49290585413 2.18198449515 -0.00068475564 -0.000 -0.000 0.119 S 6.56718562933 -0.11349126889 0.00673479967 -0.001 0.000 0.342 C 1.82142022278 -2.39594383179 -0.00206827421 -0.000 0.000 -0.122 C 2.33969079820 -3.68709653410 -0.00625612120 -0.001 0.000 -0.248 C 1.45789786198 -4.76953179608 -0.00945089783 -0.002 0.000 -0.031 C 0.08684213972 -4.53272927032 -0.00840538011 -0.002 0.000 0.306 C -0.35393854068 -3.21111942258 -0.00398541364 -0.001 0.000 0.354 N 0.49225266031 -2.17934076887 -0.00084210065 -0.000 0.001 0.139 H 1.83694111827 5.77332096953 -0.01265611066 -0.001 -0.000 -0.022 H -0.61802819388 5.33967450634 -0.01131742088 -0.001 0.000 0.144 H 3.39175422949 3.87200638269 -0.00704552340 -0.000 -0.000 -0.132 H -1.39787683933 2.98334799634 -0.00369736757 -0.000 -0.000 0.154 H 1.83794742242 -5.77033326187 -0.01295832570 -0.001 0.000 -0.033 H -0.61749414542 -5.33746053721 -0.01121572048 -0.001 0.000 0.147 H -1.39833026435 -2.98175334118 -0.00345676225 -0.000 0.000 0.166 H 3.39230213722 -3.86796714602 -0.00754158092 -0.000 0.000 -0.144 H 4.58301895157 2.13678100538 0.00314824260 -0.000 0.000 -0.022 H 4.58784714512 -2.12983634010 0.00211631073 -0.000 -0.000 -0.023 H -1.68997263563 -0.00719388386 -5.74925805817 0.000 0.005 -0.004 H 0.75224758084 -0.00860493512 -5.25016290812 0.000 -0.003 -0.004 H -3.29620044300 -0.00255800648 -3.88456579214 0.001 0.007 -0.004 H 1.47161249279 -0.00457826661 -2.87685200854 0.000 -0.007 -0.005 H -1.69176120521 -0.00597000955 5.75026973076 -0.001 -0.005 -0.004 H 0.75025791005 -0.00892914887 5.25161119224 -0.001 0.004 -0.004 H 1.46975366817 -0.00523069331 2.87805400798 -0.000 0.007 -0.004 H -3.29750276746 -0.00099200484 3.88584245085 -0.001 -0.007 -0.004 H -4.55513299541 0.00377930937 -2.13473279421 0.002 0.001 -0.006 H -4.55107479454 0.00501307822 2.13844314827 -0.001 -0.001 -0.006 H -6.83436893102 0.00806057203 1.19721860356 -0.002 -0.001 -0.010 H 6.86748209639 1.20005966818 0.00372860376 0.000 -0.000 0.039 61 Mode 15: freq=81.60 N -0.44003451495 -0.00038510790 2.12369783068 -0.000 -0.091 0.001 C -1.76594470239 0.00039861437 2.37754210613 -0.000 0.143 0.000 C -2.24923313135 -0.00145267054 3.67997125809 -0.001 0.234 0.000 C -1.33887502024 -0.00450793845 4.73956848945 -0.002 0.010 0.000 C 0.02462671625 -0.00591801736 4.46614405978 -0.002 -0.299 0.001 C 0.43187566201 -0.00376957955 3.13352499014 -0.001 -0.316 0.001 C -2.63984642995 0.00218980399 1.17162612704 0.001 0.209 -0.000 N -1.98513620489 0.00132140951 0.00153900685 0.001 0.219 -0.000 C -2.63911589169 0.00167522827 -1.17277445342 0.000 0.203 -0.000 C -4.02452897564 0.00329996303 -1.20791476641 0.000 0.147 0.000 C -4.73391255267 0.00451580118 -0.00020876193 0.000 0.075 0.000 C -4.02924140493 0.00399189729 1.20660077672 0.000 0.153 -0.000 Co 0.00000000000 0.00000000000 0.00000000000 0.002 0.063 -0.000 N -0.43839318333 -0.00054206762 -2.12229806799 -0.000 -0.094 -0.001 C -1.76408906064 -0.00030645034 -2.37697009192 -0.000 0.140 -0.000 C -2.24773885821 -0.00257631963 -3.67934971086 -0.001 0.236 -0.000 C -1.33713102227 -0.00526459193 -4.73855802198 -0.002 0.020 -0.000 C 0.02654101484 -0.00591797621 -4.46472703619 -0.002 -0.285 -0.001 C 0.43371721952 -0.00363389350 -3.13225443930 -0.001 -0.309 -0.001 S -6.53329279136 0.00637481657 -0.11611178087 -0.000 -0.388 0.000 N 2.00981687167 0.00259443239 -0.00000686048 0.001 0.001 -0.000 C 2.67119656792 1.17263645248 0.00045766926 -0.004 0.004 0.002 C 4.06129317470 1.20536051565 0.00241240325 -0.004 0.010 0.003 C 4.76783866331 0.00148799420 0.00346798881 0.001 0.013 0.000 C 4.05723810074 -1.20352939940 0.00211502115 0.006 0.010 -0.002 C 2.67108506586 -1.17139122066 0.00026591651 0.005 0.004 -0.002 C 1.82209539371 2.39842937406 -0.00175320633 -0.006 0.001 0.002 C 2.33938959521 3.68993217240 -0.00584554905 -0.011 0.003 0.009 C 1.45736908622 4.77231118002 -0.00917967851 -0.015 -0.000 0.004 C 0.08658913130 4.53522926787 -0.00833235387 -0.014 -0.005 -0.009 C -0.35359617412 3.21325694137 -0.00400174376 -0.009 -0.006 -0.013 N 0.49290585413 2.18198449515 -0.00068475564 -0.006 -0.003 -0.008 S 6.56718562933 -0.11349126889 0.00673479967 0.003 0.044 -0.000 C 1.82142022278 -2.39594383179 -0.00206827421 0.007 0.002 -0.002 C 2.33969079820 -3.68709653410 -0.00625612120 0.010 0.003 -0.008 C 1.45789786198 -4.76953179608 -0.00945089783 0.013 0.001 -0.003 C 0.08684213972 -4.53272927032 -0.00840538011 0.012 -0.002 0.008 C -0.35393854068 -3.21111942258 -0.00398541364 0.009 -0.003 0.012 N 0.49225266031 -2.17934076887 -0.00084210065 0.006 -0.001 0.007 H 1.83694111827 5.77332096953 -0.01265611066 -0.005 0.000 0.002 H -0.61802819388 5.33967450634 -0.01131742088 -0.005 -0.002 -0.004 H 3.39175422949 3.87200638269 -0.00704552340 -0.003 0.002 0.005 H -1.39787683933 2.98334799634 -0.00369736757 -0.002 -0.003 -0.006 H 1.83794742242 -5.77033326187 -0.01295832570 0.004 0.000 -0.002 H -0.61749414542 -5.33746053721 -0.01121572048 0.004 -0.001 0.004 H -1.39833026435 -2.98175334118 -0.00345676225 0.002 -0.002 0.006 H 3.39230213722 -3.86796714602 -0.00754158092 0.003 0.002 -0.005 H 4.58301895157 2.13678100538 0.00314824260 -0.002 0.003 0.001 H 4.58784714512 -2.12983634010 0.00211631073 0.003 0.003 -0.001 H -1.68997263563 -0.00719388386 -5.74925805817 -0.001 0.023 -0.000 H 0.75224758084 -0.00860493512 -5.25016290812 -0.001 -0.140 -0.000 H -3.29620044300 -0.00255800648 -3.88456579214 -0.000 0.132 -0.000 H 1.47161249279 -0.00457826661 -2.87685200854 -0.000 -0.147 -0.000 H -1.69176120521 -0.00597000955 5.75026973076 -0.001 0.019 0.000 H 0.75025791005 -0.00892914887 5.25161119224 -0.001 -0.146 0.000 H 1.46975366817 -0.00523069331 2.87805400798 -0.000 -0.149 0.000 H -3.29750276746 -0.00099200484 3.88584245085 -0.000 0.133 -0.000 H -4.55513299541 0.00377930937 -2.13473279421 0.000 0.028 0.000 H -4.55107479454 0.00501307822 2.13844314827 0.000 0.030 -0.000 H -6.83436893102 0.00806057203 1.19721860356 -0.000 -0.040 0.000 H 6.86748209639 1.20005966818 0.00372860376 -0.003 0.009 0.001 61 Mode 16: freq=91.60 N -0.44003451495 -0.00038510790 2.12369783068 -0.000 0.109 0.001 C -1.76594470239 0.00039861437 2.37754210613 -0.000 -0.100 0.001 C -2.24923313135 -0.00145267054 3.67997125809 -0.001 -0.210 0.000 C -1.33887502024 -0.00450793845 4.73956848945 -0.001 -0.034 0.001 C 0.02462671625 -0.00591801736 4.46614405978 -0.000 0.253 0.002 C 0.43187566201 -0.00376957955 3.13352499014 -0.000 0.292 0.002 C -2.63984642995 0.00218980399 1.17162612704 -0.000 -0.101 0.000 N -1.98513620489 0.00132140951 0.00153900685 0.000 0.006 0.000 C -2.63911589169 0.00167522827 -1.17277445342 0.000 0.111 0.000 C -4.02452897564 0.00329996303 -1.20791476641 0.000 0.132 0.000 C -4.73391255267 0.00451580118 -0.00020876193 0.000 -0.003 0.000 C -4.02924140493 0.00399189729 1.20660077672 -0.000 -0.130 0.000 Co 0.00000000000 0.00000000000 0.00000000000 0.001 0.003 0.002 N -0.43839318333 -0.00054206762 -2.12229806799 0.000 -0.115 0.001 C -1.76408906064 -0.00030645034 -2.37697009192 0.000 0.108 0.000 C -2.24773885821 -0.00257631963 -3.67934971086 0.000 0.225 0.000 C -1.33713102227 -0.00526459193 -4.73855802198 -0.000 0.036 0.000 C 0.02654101484 -0.00591797621 -4.46472703619 -0.000 -0.271 0.001 C 0.43371721952 -0.00363389350 -3.13225443930 -0.000 -0.311 0.001 S -6.53329279136 0.00637481657 -0.11611178087 0.000 0.002 0.000 N 2.00981687167 0.00259443239 -0.00000686048 0.000 0.000 0.003 C 2.67119656792 1.17263645248 0.00045766926 0.000 0.000 -0.085 C 4.06129317470 1.20536051565 0.00241240325 0.000 0.000 -0.110 C 4.76783866331 0.00148799420 0.00346798881 0.000 0.000 -0.003 C 4.05723810074 -1.20352939940 0.00211502115 0.000 0.000 0.108 C 2.67108506586 -1.17139122066 0.00026591651 0.000 0.000 0.089 C 1.82209539371 2.39842937406 -0.00175320633 0.000 0.000 -0.082 C 2.33938959521 3.68993217240 -0.00584554905 -0.000 -0.000 -0.144 C 1.45736908622 4.77231118002 -0.00917967851 -0.000 0.000 0.003 C 0.08658913130 4.53522926787 -0.00833235387 -0.000 0.001 0.210 C -0.35359617412 3.21325694137 -0.00400174376 -0.000 0.001 0.216 N 0.49290585413 2.18198449515 -0.00068475564 0.000 0.000 0.067 S 6.56718562933 -0.11349126889 0.00673479967 0.000 0.001 0.006 C 1.82142022278 -2.39594383179 -0.00206827421 -0.000 0.000 0.085 C 2.33969079820 -3.68709653410 -0.00625612120 -0.000 -0.000 0.153 C 1.45789786198 -4.76953179608 -0.00945089783 -0.000 0.001 -0.001 C 0.08684213972 -4.53272927032 -0.00840538011 -0.000 0.001 -0.220 C -0.35393854068 -3.21111942258 -0.00398541364 -0.000 0.001 -0.229 N 0.49225266031 -2.17934076887 -0.00084210065 -0.000 0.001 -0.072 H 1.83694111827 5.77332096953 -0.01265611066 -0.000 0.000 -0.009 H -0.61802819388 5.33967450634 -0.01131742088 -0.000 0.000 0.101 H 3.39175422949 3.87200638269 -0.00704552340 -0.000 -0.000 -0.083 H -1.39787683933 2.98334799634 -0.00369736757 -0.000 0.000 0.101 H 1.83794742242 -5.77033326187 -0.01295832570 -0.000 0.000 0.011 H -0.61749414542 -5.33746053721 -0.01121572048 -0.000 0.001 -0.106 H -1.39833026435 -2.98175334118 -0.00345676225 -0.000 0.001 -0.107 H 3.39230213722 -3.86796714602 -0.00754158092 -0.000 -0.000 0.088 H 4.58301895157 2.13678100538 0.00314824260 0.000 0.000 -0.055 H 4.58784714512 -2.12983634010 0.00211631073 0.000 0.000 0.053 H -1.68997263563 -0.00719388386 -5.74925805817 -0.000 0.032 0.000 H 0.75224758084 -0.00860493512 -5.25016290812 -0.000 -0.132 0.000 H -3.29620044300 -0.00255800648 -3.88456579214 0.000 0.126 -0.000 H 1.47161249279 -0.00457826661 -2.87685200854 -0.000 -0.147 0.000 H -1.69176120521 -0.00597000955 5.75026973076 -0.000 -0.030 0.000 H 0.75025791005 -0.00892914887 5.25161119224 -0.000 0.123 0.001 H 1.46975366817 -0.00523069331 2.87805400798 0.000 0.138 0.001 H -3.29750276746 -0.00099200484 3.88584245085 -0.000 -0.118 -0.000 H -4.55513299541 0.00377930937 -2.13473279421 0.000 0.064 0.000 H -4.55107479454 0.00501307822 2.13844314827 -0.000 -0.065 0.000 H -6.83436893102 0.00806057203 1.19721860356 -0.000 -0.053 0.000 H 6.86748209639 1.20005966818 0.00372860376 0.000 0.000 -0.045 61 Mode 17: freq=93.03 N -0.44003451495 -0.00038510790 2.12369783068 -0.117 -0.000 0.060 C -1.76594470239 0.00039861437 2.37754210613 -0.118 -0.000 0.008 C -2.24923313135 -0.00145267054 3.67997125809 -0.179 -0.000 -0.013 C -1.33887502024 -0.00450793845 4.73956848945 -0.232 0.000 0.029 C 0.02462671625 -0.00591801736 4.46614405978 -0.221 0.001 0.085 C 0.43187566201 -0.00376957955 3.13352499014 -0.158 0.000 0.102 C -2.63984642995 0.00218980399 1.17162612704 -0.081 -0.000 -0.009 N -1.98513620489 0.00132140951 0.00153900685 -0.064 -0.001 -0.000 C -2.63911589169 0.00167522827 -1.17277445342 -0.081 -0.001 0.008 C -4.02452897564 0.00329996303 -1.20791476641 -0.082 -0.001 0.008 C -4.73391255267 0.00451580118 -0.00020876193 -0.090 -0.000 -0.000 C -4.02924140493 0.00399189729 1.20660077672 -0.082 -0.000 -0.009 Co 0.00000000000 0.00000000000 0.00000000000 0.003 -0.001 -0.001 N -0.43839318333 -0.00054206762 -2.12229806799 -0.116 -0.000 -0.059 C -1.76408906064 -0.00030645034 -2.37697009192 -0.117 -0.001 -0.009 C -2.24773885821 -0.00257631963 -3.67934971086 -0.178 -0.001 0.013 C -1.33713102227 -0.00526459193 -4.73855802198 -0.231 -0.000 -0.029 C 0.02654101484 -0.00591797621 -4.46472703619 -0.219 0.001 -0.084 C 0.43371721952 -0.00363389350 -3.13225443930 -0.157 0.001 -0.102 S -6.53329279136 0.00637481657 -0.11611178087 -0.151 0.001 0.002 N 2.00981687167 0.00259443239 -0.00000686048 0.072 -0.000 -0.001 C 2.67119656792 1.17263645248 0.00045766926 0.087 -0.009 -0.000 C 4.06129317470 1.20536051565 0.00241240325 0.089 -0.008 -0.000 C 4.76783866331 0.00148799420 0.00346798881 0.097 -0.000 -0.000 C 4.05723810074 -1.20352939940 0.00211502115 0.089 0.008 -0.000 C 2.67108506586 -1.17139122066 0.00026591651 0.087 0.008 -0.000 C 1.82209539371 2.39842937406 -0.00175320633 0.119 0.004 -0.000 C 2.33938959521 3.68993217240 -0.00584554905 0.171 -0.016 -0.001 C 1.45736908622 4.77231118002 -0.00917967851 0.218 0.019 -0.000 C 0.08658913130 4.53522926787 -0.00833235387 0.210 0.067 0.001 C -0.35359617412 3.21325694137 -0.00400174376 0.157 0.083 0.001 N 0.49290585413 2.18198449515 -0.00068475564 0.120 0.046 0.000 S 6.56718562933 -0.11349126889 0.00673479967 0.163 0.002 0.000 C 1.82142022278 -2.39594383179 -0.00206827421 0.118 -0.004 -0.000 C 2.33969079820 -3.68709653410 -0.00625612120 0.170 0.015 -0.001 C 1.45789786198 -4.76953179608 -0.00945089783 0.216 -0.019 -0.000 C 0.08684213972 -4.53272927032 -0.00840538011 0.208 -0.066 0.001 C -0.35393854068 -3.21111942258 -0.00398541364 0.155 -0.082 0.001 N 0.49225266031 -2.17934076887 -0.00084210065 0.120 -0.046 0.000 H 1.83694111827 5.77332096953 -0.01265611066 0.074 0.001 -0.000 H -0.61802819388 5.33967450634 -0.01131742088 0.069 0.027 0.000 H 3.39175422949 3.87200638269 -0.00704552340 0.051 -0.017 -0.001 H -1.39787683933 2.98334799634 -0.00369736757 0.042 0.037 0.000 H 1.83794742242 -5.77033326187 -0.01295832570 0.073 -0.001 -0.000 H -0.61749414542 -5.33746053721 -0.01121572048 0.069 -0.026 0.000 H -1.39833026435 -2.98175334118 -0.00345676225 0.042 -0.037 0.000 H 3.39230213722 -3.86796714602 -0.00754158092 0.051 0.016 -0.000 H 4.58301895157 2.13678100538 0.00314824260 0.025 -0.002 -0.000 H 4.58784714512 -2.12983634010 0.00211631073 0.024 0.002 -0.000 H -1.68997263563 -0.00719388386 -5.74925805817 -0.080 -0.000 -0.004 H 0.75224758084 -0.00860493512 -5.25016290812 -0.073 0.000 -0.033 H -3.29620044300 -0.00255800648 -3.88456579214 -0.054 -0.000 0.018 H 1.47161249279 -0.00457826661 -2.87685200854 -0.042 0.000 -0.044 H -1.69176120521 -0.00597000955 5.75026973076 -0.080 0.000 0.004 H 0.75025791005 -0.00892914887 5.25161119224 -0.074 0.000 0.034 H 1.46975366817 -0.00523069331 2.87805400798 -0.042 0.000 0.045 H -3.29750276746 -0.00099200484 3.88584245085 -0.054 -0.000 -0.018 H -4.55513299541 0.00377930937 -2.13473279421 -0.022 -0.000 0.002 H -4.55107479454 0.00501307822 2.13844314827 -0.023 -0.000 -0.002 H -6.83436893102 0.00806057203 1.19721860356 -0.026 0.000 0.001 H 6.86748209639 1.20005966818 0.00372860376 0.028 0.001 0.000 61 Mode 18: freq=124.32 N -0.44003451495 -0.00038510790 2.12369783068 0.002 -0.164 -0.010 C -1.76594470239 0.00039861437 2.37754210613 0.003 -0.168 -0.006 C -2.24923313135 -0.00145267054 3.67997125809 0.008 -0.048 -0.004 C -1.33887502024 -0.00450793845 4.73956848945 0.012 0.134 -0.007 C 0.02462671625 -0.00591801736 4.46614405978 0.011 0.160 -0.012 C 0.43187566201 -0.00376957955 3.13352499014 0.006 -0.008 -0.013 C -2.63984642995 0.00218980399 1.17162612704 0.000 -0.170 -0.005 N -1.98513620489 0.00132140951 0.00153900685 -0.000 -0.005 -0.006 C -2.63911589169 0.00167522827 -1.17277445342 -0.001 0.154 -0.005 C -4.02452897564 0.00329996303 -1.20791476641 -0.001 0.215 -0.004 C -4.73391255267 0.00451580118 -0.00020876193 -0.000 -0.017 -0.004 C -4.02924140493 0.00399189729 1.20660077672 0.000 -0.245 -0.004 Co 0.00000000000 0.00000000000 0.00000000000 0.000 0.000 -0.003 N -0.43839318333 -0.00054206762 -2.12229806799 -0.002 0.141 -0.010 C -1.76408906064 -0.00030645034 -2.37697009192 -0.003 0.162 -0.006 C -2.24773885821 -0.00257631963 -3.67934971086 -0.008 0.066 -0.004 C -1.33713102227 -0.00526459193 -4.73855802198 -0.012 -0.117 -0.007 C 0.02654101484 -0.00591797621 -4.46472703619 -0.011 -0.172 -0.012 C 0.43371721952 -0.00363389350 -3.13225443930 -0.006 -0.021 -0.013 S -6.53329279136 0.00637481657 -0.11611178087 0.000 0.033 -0.009 N 2.00981687167 0.00259443239 -0.00000686048 0.000 0.003 0.014 C 2.67119656792 1.17263645248 0.00045766926 0.000 0.003 0.210 C 4.06129317470 1.20536051565 0.00241240325 -0.000 0.002 0.305 C 4.76783866331 0.00148799420 0.00346798881 0.000 0.002 0.028 C 4.05723810074 -1.20352939940 0.00211502115 0.000 0.002 -0.247 C 2.67108506586 -1.17139122066 0.00026591651 0.000 0.003 -0.171 C 1.82209539371 2.39842937406 -0.00175320633 0.001 0.003 0.203 C 2.33938959521 3.68993217240 -0.00584554905 0.004 0.002 0.059 C 1.45736908622 4.77231118002 -0.00917967851 0.007 0.003 -0.151 C 0.08658913130 4.53522926787 -0.00833235387 0.006 0.006 -0.178 C -0.35359617412 3.21325694137 -0.00400174376 0.003 0.007 0.019 N 0.49290585413 2.18198449515 -0.00068475564 0.001 0.006 0.201 S 6.56718562933 -0.11349126889 0.00673479967 0.000 0.007 -0.054 C 1.82142022278 -2.39594383179 -0.00206827421 -0.001 0.003 -0.182 C 2.33969079820 -3.68709653410 -0.00625612120 -0.004 0.002 -0.079 C 1.45789786198 -4.76953179608 -0.00945089783 -0.007 0.003 0.122 C 0.08684213972 -4.53272927032 -0.00840538011 -0.006 0.006 0.188 C -0.35393854068 -3.21111942258 -0.00398541364 -0.003 0.007 0.024 N 0.49225266031 -2.17934076887 -0.00084210065 -0.001 0.006 -0.156 H 1.83694111827 5.77332096953 -0.01265611066 0.003 0.001 -0.087 H -0.61802819388 5.33967450634 -0.01131742088 0.002 0.002 -0.100 H 3.39175422949 3.87200638269 -0.00704552340 0.001 -0.000 0.016 H -1.39787683933 2.98334799634 -0.00369736757 0.001 0.003 0.005 H 1.83794742242 -5.77033326187 -0.01295832570 -0.003 0.001 0.069 H -0.61749414542 -5.33746053721 -0.01121572048 -0.002 0.002 0.103 H -1.39833026435 -2.98175334118 -0.00345676225 -0.001 0.003 0.014 H 3.39230213722 -3.86796714602 -0.00754158092 -0.001 -0.000 -0.030 H 4.58301895157 2.13678100538 0.00314824260 -0.000 0.001 0.155 H 4.58784714512 -2.12983634010 0.00211631073 0.000 0.001 -0.135 H -1.68997263563 -0.00719388386 -5.74925805817 -0.005 -0.065 -0.002 H 0.75224758084 -0.00860493512 -5.25016290812 -0.004 -0.094 -0.004 H -3.29620044300 -0.00255800648 -3.88456579214 -0.002 0.025 -0.000 H 1.47161249279 -0.00457826661 -2.87685200854 -0.001 -0.012 -0.005 H -1.69176120521 -0.00597000955 5.75026973076 0.005 0.076 -0.002 H 0.75025791005 -0.00892914887 5.25161119224 0.004 0.088 -0.004 H 1.46975366817 -0.00523069331 2.87805400798 0.001 -0.001 -0.005 H -3.29750276746 -0.00099200484 3.88584245085 0.002 -0.014 -0.000 H -4.55513299541 0.00377930937 -2.13473279421 -0.000 0.115 -0.001 H -4.55107479454 0.00501307822 2.13844314827 0.000 -0.126 -0.001 H -6.83436893102 0.00806057203 1.19721860356 -0.001 -0.099 -0.002 H 6.86748209639 1.20005966818 0.00372860376 -0.001 0.002 0.119 61 Mode 19: freq=131.51 N -0.44003451495 -0.00038510790 2.12369783068 -0.018 -0.032 0.098 C -1.76594470239 0.00039861437 2.37754210613 -0.028 -0.025 0.051 C -2.24923313135 -0.00145267054 3.67997125809 -0.086 0.001 0.030 C -1.33887502024 -0.00450793845 4.73956848945 -0.139 0.024 0.073 C 0.02462671625 -0.00591801736 4.46614405978 -0.129 0.015 0.126 C 0.43187566201 -0.00376957955 3.13352499014 -0.067 -0.015 0.140 C -2.63984642995 0.00218980399 1.17162612704 -0.002 -0.028 0.039 N -1.98513620489 0.00132140951 0.00153900685 0.000 -0.006 0.047 C -2.63911589169 0.00167522827 -1.17277445342 0.002 0.015 0.039 C -4.02452897564 0.00329996303 -1.20791476641 -0.000 0.023 0.037 C -4.73391255267 0.00451580118 -0.00020876193 -0.000 -0.007 0.042 C -4.02924140493 0.00399189729 1.20660077672 0.000 -0.039 0.037 Co 0.00000000000 0.00000000000 0.00000000000 0.000 -0.003 -0.030 N -0.43839318333 -0.00054206762 -2.12229806799 0.019 0.017 0.098 C -1.76408906064 -0.00030645034 -2.37697009192 0.028 0.018 0.051 C -2.24773885821 -0.00257631963 -3.67934971086 0.087 0.007 0.030 C -1.33713102227 -0.00526459193 -4.73855802198 0.141 -0.013 0.073 C 0.02654101484 -0.00591797621 -4.46472703619 0.130 -0.018 0.126 C 0.43371721952 -0.00363389350 -3.13225443930 0.068 -0.001 0.141 S -6.53329279136 0.00637481657 -0.11611178087 -0.006 0.011 0.166 N 2.00981687167 0.00259443239 -0.00000686048 -0.000 0.001 -0.190 C 2.67119656792 1.17263645248 0.00045766926 -0.000 0.001 -0.199 C 4.06129317470 1.20536051565 0.00241240325 -0.000 0.001 -0.224 C 4.76783866331 0.00148799420 0.00346798881 -0.000 0.002 -0.186 C 4.05723810074 -1.20352939940 0.00211502115 0.000 0.001 -0.274 C 2.67108506586 -1.17139122066 0.00026591651 -0.000 0.001 -0.231 C 1.82209539371 2.39842937406 -0.00175320633 0.001 0.002 -0.112 C 2.33938959521 3.68993217240 -0.00584554905 0.003 0.002 0.093 C 1.45736908622 4.77231118002 -0.00917967851 0.005 0.004 0.152 C 0.08658913130 4.53522926787 -0.00833235387 0.005 0.005 -0.033 C -0.35359617412 3.21325694137 -0.00400174376 0.002 0.005 -0.205 N 0.49290585413 2.18198449515 -0.00068475564 0.000 0.004 -0.223 S 6.56718562933 -0.11349126889 0.00673479967 -0.001 0.008 0.293 C 1.82142022278 -2.39594383179 -0.00206827421 -0.001 0.001 -0.150 C 2.33969079820 -3.68709653410 -0.00625612120 -0.003 -0.000 0.068 C 1.45789786198 -4.76953179608 -0.00945089783 -0.005 0.001 0.170 C 0.08684213972 -4.53272927032 -0.00840538011 -0.005 0.004 0.009 C -0.35393854068 -3.21111942258 -0.00398541364 -0.003 0.005 -0.193 N 0.49225266031 -2.17934076887 -0.00084210065 -0.001 0.003 -0.251 H 1.83694111827 5.77332096953 -0.01265611066 0.002 0.001 0.095 H -0.61802819388 5.33967450634 -0.01131742088 0.002 0.002 -0.007 H 3.39175422949 3.87200638269 -0.00704552340 0.001 0.000 0.063 H -1.39787683933 2.98334799634 -0.00369736757 0.001 0.002 -0.092 H 1.83794742242 -5.77033326187 -0.01295832570 -0.002 -0.000 0.105 H -0.61749414542 -5.33746053721 -0.01121572048 -0.002 0.001 0.016 H -1.39833026435 -2.98175334118 -0.00345676225 -0.001 0.002 -0.086 H 3.39230213722 -3.86796714602 -0.00754158092 -0.001 -0.001 0.052 H 4.58301895157 2.13678100538 0.00314824260 -0.000 0.000 -0.060 H 4.58784714512 -2.12983634010 0.00211631073 0.000 0.000 -0.089 H -1.68997263563 -0.00719388386 -5.74925805817 0.054 -0.007 0.017 H 0.75224758084 -0.00860493512 -5.25016290812 0.047 -0.010 0.045 H -3.29620044300 -0.00255800648 -3.88456579214 0.028 0.003 -0.006 H 1.47161249279 -0.00457826661 -2.87685200854 0.016 -0.001 0.056 H -1.69176120521 -0.00597000955 5.75026973076 -0.053 0.014 0.017 H 0.75025791005 -0.00892914887 5.25161119224 -0.046 0.009 0.045 H 1.46975366817 -0.00523069331 2.87805400798 -0.016 -0.006 0.056 H -3.29750276746 -0.00099200484 3.88584245085 -0.027 0.003 -0.005 H -4.55513299541 0.00377930937 -2.13473279421 0.001 0.014 0.010 H -4.55107479454 0.00501307822 2.13844314827 -0.000 -0.019 0.010 H -6.83436893102 0.00806057203 1.19721860356 0.015 -0.015 0.033 H 6.86748209639 1.20005966818 0.00372860376 -0.001 0.001 -0.031 61 Mode 20: freq=133.14 N -0.44003451495 -0.00038510790 2.12369783068 -0.000 0.221 0.003 C -1.76594470239 0.00039861437 2.37754210613 -0.001 0.096 0.001 C -2.24923313135 -0.00145267054 3.67997125809 -0.003 -0.120 0.000 C -1.33887502024 -0.00450793845 4.73956848945 -0.005 -0.163 0.002 C 0.02462671625 -0.00591801736 4.46614405978 -0.005 0.053 0.004 C 0.43187566201 -0.00376957955 3.13352499014 -0.002 0.226 0.005 C -2.63984642995 0.00218980399 1.17162612704 0.000 0.177 0.001 N -1.98513620489 0.00132140951 0.00153900685 0.000 0.184 0.001 C -2.63911589169 0.00167522827 -1.17277445342 0.000 0.188 0.001 C -4.02452897564 0.00329996303 -1.20791476641 0.000 0.210 0.001 C -4.73391255267 0.00451580118 -0.00020876193 0.000 0.154 0.001 C -4.02924140493 0.00399189729 1.20660077672 0.000 0.193 0.001 Co 0.00000000000 0.00000000000 0.00000000000 0.001 0.130 -0.002 N -0.43839318333 -0.00054206762 -2.12229806799 0.001 0.228 0.003 C -1.76408906064 -0.00030645034 -2.37697009192 0.001 0.111 0.002 C -2.24773885821 -0.00257631963 -3.67934971086 0.002 -0.103 0.001 C -1.33713102227 -0.00526459193 -4.73855802198 0.004 -0.165 0.003 C 0.02654101484 -0.00591797621 -4.46472703619 0.004 0.031 0.004 C 0.43371721952 -0.00363389350 -3.13225443930 0.002 0.212 0.004 S -6.53329279136 0.00637481657 -0.11611178087 -0.001 -0.226 0.006 N 2.00981687167 0.00259443239 -0.00000686048 0.000 -0.029 -0.006 C 2.67119656792 1.17263645248 0.00045766926 0.008 -0.027 0.008 C 4.06129317470 1.20536051565 0.00241240325 0.013 -0.035 0.016 C 4.76783866331 0.00148799420 0.00346798881 -0.000 -0.049 -0.005 C 4.05723810074 -1.20352939940 0.00211502115 -0.012 -0.035 -0.030 C 2.67108506586 -1.17139122066 0.00026591651 -0.008 -0.027 -0.022 C 1.82209539371 2.39842937406 -0.00175320633 -0.024 -0.040 0.011 C 2.33938959521 3.68993217240 -0.00584554905 -0.096 -0.013 0.005 C 1.45736908622 4.77231118002 -0.00917967851 -0.163 -0.063 -0.007 C 0.08658913130 4.53522926787 -0.00833235387 -0.152 -0.129 -0.010 C -0.35359617412 3.21325694137 -0.00400174376 -0.077 -0.150 -0.000 N 0.49290585413 2.18198449515 -0.00068475564 -0.015 -0.098 0.010 S 6.56718562933 -0.11349126889 0.00673479967 -0.013 -0.278 0.007 C 1.82142022278 -2.39594383179 -0.00206827421 0.025 -0.040 -0.020 C 2.33969079820 -3.68709653410 -0.00625612120 0.098 -0.012 -0.000 C 1.45789786198 -4.76953179608 -0.00945089783 0.166 -0.064 0.017 C 0.08684213972 -4.53272927032 -0.00840538011 0.155 -0.130 0.010 C -0.35393854068 -3.21111942258 -0.00398541364 0.079 -0.152 -0.012 N 0.49225266031 -2.17934076887 -0.00084210065 0.016 -0.099 -0.025 H 1.83694111827 5.77332096953 -0.01265611066 -0.063 -0.012 -0.004 H -0.61802819388 5.33967450634 -0.01131742088 -0.056 -0.048 -0.006 H 3.39175422949 3.87200638269 -0.00704552340 -0.030 0.013 0.002 H -1.39787683933 2.98334799634 -0.00369736757 -0.018 -0.062 -0.000 H 1.83794742242 -5.77033326187 -0.01295832570 0.064 -0.012 0.010 H -0.61749414542 -5.33746053721 -0.01121572048 0.057 -0.048 0.007 H -1.39833026435 -2.98175334118 -0.00345676225 0.019 -0.063 -0.005 H 3.39230213722 -3.86796714602 -0.00754158092 0.031 0.014 0.002 H 4.58301895157 2.13678100538 0.00314824260 0.005 -0.010 0.010 H 4.58784714512 -2.12983634010 0.00211631073 -0.005 -0.010 -0.014 H -1.68997263563 -0.00719388386 -5.74925805817 0.002 -0.101 0.001 H 0.75224758084 -0.00860493512 -5.25016290812 0.001 0.006 0.001 H -3.29620044300 -0.00255800648 -3.88456579214 0.001 -0.067 0.000 H 1.47161249279 -0.00457826661 -2.87685200854 0.001 0.096 0.002 H -1.69176120521 -0.00597000955 5.75026973076 -0.002 -0.100 0.000 H 0.75025791005 -0.00892914887 5.25161119224 -0.002 0.018 0.001 H 1.46975366817 -0.00523069331 2.87805400798 -0.000 0.103 0.002 H -3.29750276746 -0.00099200484 3.88584245085 -0.001 -0.076 -0.001 H -4.55513299541 0.00377930937 -2.13473279421 0.000 0.064 0.000 H -4.55107479454 0.00501307822 2.13844314827 0.000 0.052 0.000 H -6.83436893102 0.00806057203 1.19721860356 0.001 0.033 0.001 H 6.86748209639 1.20005966818 0.00372860376 0.029 -0.056 0.009 61 Mode 21: freq=151.59 N -0.44003451495 -0.00038510790 2.12369783068 -0.008 0.070 -0.045 C -1.76594470239 0.00039861437 2.37754210613 -0.011 0.043 -0.104 C -2.24923313135 -0.00145267054 3.67997125809 -0.098 -0.024 -0.137 C -1.33887502024 -0.00450793845 4.73956848945 -0.170 -0.054 -0.085 C 0.02462671625 -0.00591801736 4.46614405978 -0.155 0.002 -0.011 C 0.43187566201 -0.00376957955 3.13352499014 -0.070 0.060 0.014 C -2.63984642995 0.00218980399 1.17162612704 0.031 0.057 -0.110 N -1.98513620489 0.00132140951 0.00153900685 -0.005 0.004 -0.133 C -2.63911589169 0.00167522827 -1.17277445342 -0.044 -0.029 -0.109 C -4.02452897564 0.00329996303 -1.20791476641 -0.066 -0.042 -0.053 C -4.73391255267 0.00451580118 -0.00020876193 -0.009 0.026 -0.003 C -4.02924140493 0.00399189729 1.20660077672 0.053 0.098 -0.054 Co 0.00000000000 0.00000000000 0.00000000000 0.003 -0.034 -0.154 N -0.43839318333 -0.00054206762 -2.12229806799 -0.000 -0.043 -0.032 C -1.76408906064 -0.00030645034 -2.37697009192 0.005 -0.034 -0.100 C -2.24773885821 -0.00257631963 -3.67934971086 0.102 -0.002 -0.137 C -1.33713102227 -0.00526459193 -4.73855802198 0.184 0.029 -0.078 C 0.02654101484 -0.00591797621 -4.46472703619 0.166 0.017 0.006 C 0.43371721952 -0.00363389350 -3.13225443930 0.070 -0.021 0.034 S -6.53329279136 0.00637481657 -0.11611178087 -0.062 -0.038 0.678 N 2.00981687167 0.00259443239 -0.00000686048 0.010 -0.030 0.011 C 2.67119656792 1.17263645248 0.00045766926 0.001 -0.025 0.082 C 4.06129317470 1.20536051565 0.00241240325 -0.003 -0.013 0.149 C 4.76783866331 0.00148799420 0.00346798881 0.011 -0.002 0.078 C 4.05723810074 -1.20352939940 0.00211502115 0.023 -0.013 0.037 C 2.67108506586 -1.17139122066 0.00026591651 0.018 -0.024 0.015 C 1.82209539371 2.39842937406 -0.00175320633 0.006 -0.026 0.047 C 2.33938959521 3.68993217240 -0.00584554905 0.017 -0.031 -0.043 C 1.45736908622 4.77231118002 -0.00917967851 0.026 -0.025 -0.066 C 0.08658913130 4.53522926787 -0.00833235387 0.024 -0.016 0.021 C -0.35359617412 3.21325694137 -0.00400174376 0.014 -0.012 0.088 N 0.49290585413 2.18198449515 -0.00068475564 0.007 -0.020 0.087 S 6.56718562933 -0.11349126889 0.00673479967 0.030 0.142 -0.112 C 1.82142022278 -2.39594383179 -0.00206827421 0.005 -0.020 -0.008 C 2.33969079820 -3.68709653410 -0.00625612120 -0.021 -0.030 -0.021 C 1.45789786198 -4.76953179608 -0.00945089783 -0.044 -0.014 -0.006 C 0.08684213972 -4.53272927032 -0.00840538011 -0.040 0.010 0.023 C -0.35393854068 -3.21111942258 -0.00398541364 -0.014 0.018 0.021 N 0.49225266031 -2.17934076887 -0.00084210065 0.007 0.001 0.003 H 1.83694111827 5.77332096953 -0.01265611066 0.009 -0.008 -0.042 H -0.61802819388 5.33967450634 -0.01131742088 0.009 -0.003 0.007 H 3.39175422949 3.87200638269 -0.00704552340 0.005 -0.011 -0.030 H -1.39787683933 2.98334799634 -0.00369736757 0.003 -0.001 0.039 H 1.83794742242 -5.77033326187 -0.01295832570 -0.018 -0.006 -0.004 H -0.61749414542 -5.33746053721 -0.01121572048 -0.016 0.007 0.012 H -1.39833026435 -2.98175334118 -0.00345676225 -0.003 0.011 0.009 H 3.39230213722 -3.86796714602 -0.00754158092 -0.007 -0.014 -0.011 H 4.58301895157 2.13678100538 0.00314824260 -0.004 -0.002 0.062 H 4.58784714512 -2.12983634010 0.00211631073 0.009 -0.003 0.005 H -1.68997263563 -0.00719388386 -5.74925805817 0.073 0.018 -0.029 H 0.75224758084 -0.00860493512 -5.25016290812 0.063 0.011 0.016 H -3.29620044300 -0.00255800648 -3.88456579214 0.033 0.003 -0.060 H 1.47161249279 -0.00457826661 -2.87685200854 0.015 -0.009 0.032 H -1.69176120521 -0.00597000955 5.75026973076 -0.066 -0.033 -0.031 H 0.75025791005 -0.00892914887 5.25161119224 -0.058 -0.003 0.009 H 1.46975366817 -0.00523069331 2.87805400798 -0.015 0.026 0.023 H -3.29750276746 -0.00099200484 3.88584245085 -0.031 -0.018 -0.058 H -4.55513299541 0.00377930937 -2.13473279421 -0.030 -0.027 -0.011 H -4.55107479454 0.00501307822 2.13844314827 0.028 0.047 -0.010 H -6.83436893102 0.00806057203 1.19721860356 0.097 0.053 0.145 H 6.86748209639 1.20005966818 0.00372860376 -0.018 0.031 0.074 61 Mode 22: freq=152.34 N -0.44003451495 -0.00038510790 2.12369783068 0.004 -0.135 -0.008 C -1.76594470239 0.00039861437 2.37754210613 0.002 -0.069 -0.030 C -2.24923313135 -0.00145267054 3.67997125809 -0.029 0.075 -0.042 C -1.33887502024 -0.00450793845 4.73956848945 -0.055 0.110 -0.023 C 0.02462671625 -0.00591801736 4.46614405978 -0.049 -0.035 0.004 C 0.43187566201 -0.00376957955 3.13352499014 -0.019 -0.142 0.013 C -2.63984642995 0.00218980399 1.17162612704 0.018 -0.120 -0.034 N -1.98513620489 0.00132140951 0.00153900685 0.007 -0.033 -0.042 C -2.63911589169 0.00167522827 -1.17277445342 -0.005 -0.021 -0.035 C -4.02452897564 0.00329996303 -1.20791476641 -0.011 -0.045 -0.017 C -4.73391255267 0.00451580118 -0.00020876193 0.007 -0.106 -0.002 C -4.02924140493 0.00399189729 1.20660077672 0.025 -0.204 -0.018 Co 0.00000000000 0.00000000000 0.00000000000 0.007 0.137 -0.044 N -0.43839318333 -0.00054206762 -2.12229806799 0.006 -0.006 -0.020 C -1.76408906064 -0.00030645034 -2.37697009192 0.006 0.015 -0.035 C -2.24773885821 -0.00257631963 -3.67934971086 0.029 0.040 -0.044 C -1.33713102227 -0.00526459193 -4.73855802198 0.048 0.012 -0.030 C 0.02654101484 -0.00591797621 -4.46472703619 0.044 -0.042 -0.011 C 0.43371721952 -0.00363389350 -3.13225443930 0.022 -0.040 -0.005 S -6.53329279136 0.00637481657 -0.11611178087 -0.001 0.146 0.205 N 2.00981687167 0.00259443239 -0.00000686048 -0.005 0.132 0.010 C 2.67119656792 1.17263645248 0.00045766926 0.031 0.109 -0.031 C 4.06129317470 1.20536051565 0.00241240325 0.050 0.059 -0.054 C 4.76783866331 0.00148799420 0.00346798881 -0.008 0.011 0.022 C 4.05723810074 -1.20352939940 0.00211502115 -0.062 0.058 0.115 C 2.67108506586 -1.17139122066 0.00026591651 -0.042 0.108 0.070 C 1.82209539371 2.39842937406 -0.00175320633 -0.004 0.105 -0.035 C 2.33938959521 3.68993217240 -0.00584554905 -0.076 0.135 -0.002 C 1.45736908622 4.77231118002 -0.00917967851 -0.139 0.092 0.028 C 0.08658913130 4.53522926787 -0.00833235387 -0.127 0.027 0.015 C -0.35359617412 3.21325694137 -0.00400174376 -0.056 0.003 -0.023 N 0.49290585413 2.18198449515 -0.00068475564 -0.002 0.053 -0.043 S 6.56718562933 -0.11349126889 0.00673479967 -0.056 -0.613 -0.027 C 1.82142022278 -2.39594383179 -0.00206827421 -0.001 0.101 0.055 C 2.33969079820 -3.68709653410 -0.00625612120 0.082 0.135 -0.018 C 1.45789786198 -4.76953179608 -0.00945089783 0.154 0.086 -0.057 C 0.08684213972 -4.53272927032 -0.00840538011 0.140 0.011 -0.004 C -0.35393854068 -3.21111942258 -0.00398541364 0.058 -0.016 0.063 N 0.49225266031 -2.17934076887 -0.00084210065 -0.005 0.041 0.081 H 1.83694111827 5.77332096953 -0.01265611066 -0.055 0.032 0.018 H -0.61802819388 5.33967450634 -0.01131742088 -0.049 -0.002 0.010 H 3.39175422949 3.87200638269 -0.00704552340 -0.024 0.054 0.003 H -1.39787683933 2.98334799634 -0.00369736757 -0.013 -0.015 -0.009 H 1.83794742242 -5.77033326187 -0.01295832570 0.061 0.031 -0.036 H -0.61749414542 -5.33746053721 -0.01121572048 0.054 -0.009 -0.006 H -1.39833026435 -2.98175334118 -0.00345676225 0.013 -0.024 0.027 H 3.39230213722 -3.86796714602 -0.00754158092 0.026 0.057 -0.017 H 4.58301895157 2.13678100538 0.00314824260 0.026 0.012 -0.035 H 4.58784714512 -2.12983634010 0.00211631073 -0.027 0.013 0.056 H -1.68997263563 -0.00719388386 -5.74925805817 0.018 0.007 -0.010 H 0.75224758084 -0.00860493512 -5.25016290812 0.016 -0.023 -0.000 H -3.29620044300 -0.00255800648 -3.88456579214 0.009 0.021 -0.017 H 1.47161249279 -0.00457826661 -2.87685200854 0.005 -0.018 0.004 H -1.69176120521 -0.00597000955 5.75026973076 -0.022 0.068 -0.009 H 0.75025791005 -0.00892914887 5.25161119224 -0.019 -0.012 0.006 H 1.46975366817 -0.00523069331 2.87805400798 -0.004 -0.064 0.011 H -3.29750276746 -0.00099200484 3.88584245085 -0.009 0.050 -0.019 H -4.55513299541 0.00377930937 -2.13473279421 -0.007 -0.002 -0.003 H -4.55107479454 0.00501307822 2.13844314827 0.011 -0.083 -0.003 H -6.83436893102 0.00806057203 1.19721860356 0.033 -0.104 0.044 H 6.86748209639 1.20005966818 0.00372860376 0.090 -0.131 -0.031 61 Mode 23: freq=154.19 N -0.44003451495 -0.00038510790 2.12369783068 0.005 0.161 0.017 C -1.76594470239 0.00039861437 2.37754210613 0.004 0.121 0.022 C -2.24923313135 -0.00145267054 3.67997125809 0.013 -0.012 0.026 C -1.33887502024 -0.00450793845 4.73956848945 0.020 -0.115 0.021 C 0.02462671625 -0.00591801736 4.46614405978 0.019 -0.041 0.014 C 0.43187566201 -0.00376957955 3.13352499014 0.010 0.101 0.011 C -2.63984642995 0.00218980399 1.17162612704 -0.000 0.117 0.022 N -1.98513620489 0.00132140951 0.00153900685 0.006 -0.032 0.026 C -2.63911589169 0.00167522827 -1.17277445342 0.012 -0.199 0.021 C -4.02452897564 0.00329996303 -1.20791476641 0.016 -0.310 0.012 C -4.73391255267 0.00451580118 -0.00020876193 0.007 -0.033 0.003 C -4.02924140493 0.00399189729 1.20660077672 -0.004 0.207 0.012 Co 0.00000000000 0.00000000000 0.00000000000 0.003 0.040 0.019 N -0.43839318333 -0.00054206762 -2.12229806799 0.004 -0.247 0.006 C -1.76408906064 -0.00030645034 -2.37697009192 0.003 -0.163 0.019 C -2.24773885821 -0.00257631963 -3.67934971086 -0.014 0.062 0.025 C -1.33713102227 -0.00526459193 -4.73855802198 -0.029 0.184 0.014 C 0.02654101484 -0.00591797621 -4.46472703619 -0.025 0.016 -0.001 C 0.43371721952 -0.00363389350 -3.13225443930 -0.009 -0.194 -0.005 S -6.53329279136 0.00637481657 -0.11611178087 0.021 0.031 -0.112 N 2.00981687167 0.00259443239 -0.00000686048 -0.006 0.058 -0.016 C 2.67119656792 1.17263645248 0.00045766926 0.008 0.049 0.116 C 4.06129317470 1.20536051565 0.00241240325 0.016 0.028 0.209 C 4.76783866331 0.00148799420 0.00346798881 -0.008 0.008 -0.008 C 4.05723810074 -1.20352939940 0.00211502115 -0.030 0.028 -0.248 C 2.67108506586 -1.17139122066 0.00026591651 -0.021 0.048 -0.155 C 1.82209539371 2.39842937406 -0.00175320633 -0.004 0.048 0.105 C 2.33938959521 3.68993217240 -0.00584554905 -0.027 0.058 -0.023 C 1.45736908622 4.77231118002 -0.00917967851 -0.047 0.045 -0.102 C 0.08658913130 4.53522926787 -0.00833235387 -0.043 0.024 -0.017 C -0.35359617412 3.21325694137 -0.00400174376 -0.020 0.017 0.106 N 0.49290585413 2.18198449515 -0.00068475564 -0.004 0.033 0.147 S 6.56718562933 -0.11349126889 0.00673479967 -0.032 -0.247 -0.000 C 1.82142022278 -2.39594383179 -0.00206827421 -0.004 0.045 -0.130 C 2.33969079820 -3.68709653410 -0.00625612120 0.030 0.058 0.035 C 1.45789786198 -4.76953179608 -0.00945089783 0.060 0.038 0.132 C 0.08684213972 -4.53272927032 -0.00840538011 0.054 0.007 0.016 C -0.35393854068 -3.21111942258 -0.00398541364 0.020 -0.003 -0.140 N 0.49225266031 -2.17934076887 -0.00084210065 -0.005 0.019 -0.188 H 1.83694111827 5.77332096953 -0.01265611066 -0.018 0.015 -0.065 H -0.61802819388 5.33967450634 -0.01131742088 -0.016 0.004 -0.018 H 3.39175422949 3.87200638269 -0.00704552340 -0.008 0.021 -0.027 H -1.39787683933 2.98334799634 -0.00369736757 -0.005 -0.000 0.046 H 1.83794742242 -5.77033326187 -0.01295832570 0.024 0.013 0.084 H -0.61749414542 -5.33746053721 -0.01121572048 0.021 -0.003 0.019 H -1.39833026435 -2.98175334118 -0.00345676225 0.004 -0.009 -0.061 H 3.39230213722 -3.86796714602 -0.00754158092 0.010 0.024 0.035 H 4.58301895157 2.13678100538 0.00314824260 0.009 0.006 0.117 H 4.58784714512 -2.12983634010 0.00211631073 -0.012 0.006 -0.127 H -1.68997263563 -0.00719388386 -5.74925805817 -0.012 0.115 0.005 H 0.75224758084 -0.00860493512 -5.25016290812 -0.010 0.021 -0.003 H -3.29620044300 -0.00255800648 -3.88456579214 -0.005 0.052 0.011 H 1.47161249279 -0.00457826661 -2.87685200854 -0.002 -0.085 -0.005 H -1.69176120521 -0.00597000955 5.75026973076 0.007 -0.072 0.007 H 0.75025791005 -0.00892914887 5.25161119224 0.007 -0.030 0.003 H 1.46975366817 -0.00523069331 2.87805400798 0.003 0.043 0.001 H -3.29750276746 -0.00099200484 3.88584245085 0.004 -0.021 0.009 H -4.55513299541 0.00377930937 -2.13473279421 0.006 -0.153 0.003 H -4.55107479454 0.00501307822 2.13844314827 -0.003 0.123 0.002 H -6.83436893102 0.00806057203 1.19721860356 -0.015 0.127 -0.024 H 6.86748209639 1.20005966818 0.00372860376 0.035 -0.053 0.122 61 Mode 24: freq=162.67 N -0.44003451495 -0.00038510790 2.12369783068 0.098 0.001 0.111 C -1.76594470239 0.00039861437 2.37754210613 0.081 -0.001 0.030 C -2.24923313135 -0.00145267054 3.67997125809 -0.005 -0.005 0.002 C -1.33887502024 -0.00450793845 4.73956848945 -0.081 -0.002 0.063 C 0.02462671625 -0.00591801736 4.46614405978 -0.063 0.005 0.146 C 0.43187566201 -0.00376957955 3.13352499014 0.024 0.005 0.169 C -2.63984642995 0.00218980399 1.17162612704 0.126 0.004 -0.001 N -1.98513620489 0.00132140951 0.00153900685 0.121 0.000 -0.008 C -2.63911589169 0.00167522827 -1.17277445342 0.120 0.009 -0.013 C -4.02452897564 0.00329996303 -1.20791476641 0.126 0.019 -0.003 C -4.73391255267 0.00451580118 -0.00020876193 0.144 0.012 0.002 C -4.02924140493 0.00399189729 1.20660077672 0.135 0.009 -0.001 Co 0.00000000000 0.00000000000 0.00000000000 0.032 -0.020 -0.014 N -0.43839318333 -0.00054206762 -2.12229806799 0.097 0.008 -0.116 C -1.76408906064 -0.00030645034 -2.37697009192 0.081 0.004 -0.043 C -2.24773885821 -0.00257631963 -3.67934971086 0.008 -0.005 -0.019 C -1.33713102227 -0.00526459193 -4.73855802198 -0.058 -0.007 -0.073 C 0.02654101484 -0.00591797621 -4.46472703619 -0.042 0.003 -0.146 C 0.43371721952 -0.00363389350 -3.13225443930 0.033 0.009 -0.165 S -6.53329279136 0.00637481657 -0.11611178087 0.265 -0.015 0.044 N 2.00981687167 0.00259443239 -0.00000686048 -0.146 -0.011 -0.001 C 2.67119656792 1.17263645248 0.00045766926 -0.152 -0.002 0.002 C 4.06129317470 1.20536051565 0.00241240325 -0.163 -0.003 0.005 C 4.76783866331 0.00148799420 0.00346798881 -0.173 0.002 0.007 C 4.05723810074 -1.20352939940 0.00211502115 -0.152 -0.004 0.012 C 2.67108506586 -1.17139122066 0.00026591651 -0.144 -0.016 0.006 C 1.82209539371 2.39842937406 -0.00175320633 -0.095 0.034 -0.001 C 2.33938959521 3.68993217240 -0.00584554905 0.020 -0.009 -0.002 C 1.45736908622 4.77231118002 -0.00917967851 0.128 0.073 -0.001 C 0.08658913130 4.53522926787 -0.00833235387 0.108 0.186 0.002 C -0.35359617412 3.21325694137 -0.00400174376 -0.013 0.221 0.001 N 0.49290585413 2.18198449515 -0.00068475564 -0.118 0.141 -0.001 S 6.56718562933 -0.11349126889 0.00673479967 -0.320 0.055 -0.010 C 1.82142022278 -2.39594383179 -0.00206827421 -0.094 -0.052 0.003 C 2.33969079820 -3.68709653410 -0.00625612120 0.006 -0.014 -0.003 C 1.45789786198 -4.76953179608 -0.00945089783 0.100 -0.087 -0.004 C 0.08684213972 -4.53272927032 -0.00840538011 0.083 -0.187 0.001 C -0.35393854068 -3.21111942258 -0.00398541364 -0.023 -0.217 0.005 N 0.49225266031 -2.17934076887 -0.00084210065 -0.116 -0.148 0.005 H 1.83694111827 5.77332096953 -0.01265611066 0.063 0.011 -0.000 H -0.61802819388 5.33967450634 -0.01131742088 0.051 0.071 0.001 H 3.39175422949 3.87200638269 -0.00704552340 0.010 -0.030 -0.001 H -1.39787683933 2.98334799634 -0.00369736757 -0.010 0.093 0.001 H 1.83794742242 -5.77033326187 -0.01295832570 0.052 -0.016 -0.003 H -0.61749414542 -5.33746053721 -0.01121572048 0.041 -0.069 0.000 H -1.39833026435 -2.98175334118 -0.00345676225 -0.012 -0.089 0.002 H 3.39230213722 -3.86796714602 -0.00754158092 0.006 0.019 -0.002 H 4.58301895157 2.13678100538 0.00314824260 -0.044 -0.003 0.001 H 4.58784714512 -2.12983634010 0.00211631073 -0.039 0.002 0.005 H -1.68997263563 -0.00719388386 -5.74925805817 -0.034 -0.005 -0.015 H 0.75224758084 -0.00860493512 -5.25016290812 -0.024 0.001 -0.054 H -3.29620044300 -0.00255800648 -3.88456579214 -0.001 -0.003 0.011 H 1.47161249279 -0.00457826661 -2.87685200854 0.014 0.004 -0.066 H -1.69176120521 -0.00597000955 5.75026973076 -0.043 -0.001 0.011 H 0.75025791005 -0.00892914887 5.25161119224 -0.032 0.002 0.055 H 1.46975366817 -0.00523069331 2.87805400798 0.012 0.002 0.070 H -3.29750276746 -0.00099200484 3.88584245085 -0.005 -0.003 -0.019 H -4.55513299541 0.00377930937 -2.13473279421 0.033 0.008 0.002 H -4.55107479454 0.00501307822 2.13844314827 0.037 0.002 -0.002 H -6.83436893102 0.00806057203 1.19721860356 0.052 0.007 0.009 H 6.86748209639 1.20005966818 0.00372860376 -0.063 0.011 0.004 61 Mode 25: freq=191.04 N -0.44003451495 -0.00038510790 2.12369783068 0.003 0.146 0.010 C -1.76594470239 0.00039861437 2.37754210613 0.002 0.130 0.008 C -2.24923313135 -0.00145267054 3.67997125809 -0.000 0.076 0.008 C -1.33887502024 -0.00450793845 4.73956848945 -0.003 -0.062 0.010 C 0.02462671625 -0.00591801736 4.46614405978 -0.003 -0.094 0.012 C 0.43187566201 -0.00376957955 3.13352499014 -0.001 0.043 0.012 C -2.63984642995 0.00218980399 1.17162612704 0.001 0.066 0.008 N -1.98513620489 0.00132140951 0.00153900685 0.001 0.147 0.009 C -2.63911589169 0.00167522827 -1.17277445342 0.001 0.012 0.008 C -4.02452897564 0.00329996303 -1.20791476641 0.002 -0.186 0.007 C -4.73391255267 0.00451580118 -0.00020876193 0.001 -0.184 0.006 C -4.02924140493 0.00399189729 1.20660077672 -0.000 -0.080 0.007 Co 0.00000000000 0.00000000000 0.00000000000 -0.001 0.210 -0.028 N -0.43839318333 -0.00054206762 -2.12229806799 -0.001 0.036 0.008 C -1.76408906064 -0.00030645034 -2.37697009192 -0.000 0.027 0.008 C -2.24773885821 -0.00257631963 -3.67934971086 0.000 0.018 0.008 C -1.33713102227 -0.00526459193 -4.73855802198 0.002 -0.015 0.009 C 0.02654101484 -0.00591797621 -4.46472703619 0.002 -0.023 0.010 C 0.43371721952 -0.00363389350 -3.13225443930 0.001 0.013 0.010 S -6.53329279136 0.00637481657 -0.11611178087 0.005 0.248 -0.020 N 2.00981687167 0.00259443239 -0.00000686048 -0.002 -0.047 -0.031 C 2.67119656792 1.17263645248 0.00045766926 -0.001 -0.044 -0.007 C 4.06129317470 1.20536051565 0.00241240325 -0.009 -0.038 0.035 C 4.76783866331 0.00148799420 0.00346798881 -0.002 -0.031 0.038 C 4.05723810074 -1.20352939940 0.00211502115 0.005 -0.037 0.011 C 2.67108506586 -1.17139122066 0.00026591651 -0.003 -0.044 -0.017 C 1.82209539371 2.39842937406 -0.00175320633 0.005 -0.044 -0.028 C 2.33938959521 3.68993217240 -0.00584554905 0.001 -0.046 -0.026 C 1.45736908622 4.77231118002 -0.00917967851 -0.006 -0.052 0.008 C 0.08658913130 4.53522926787 -0.00833235387 -0.006 -0.055 0.029 C -0.35359617412 3.21325694137 -0.00400174376 -0.002 -0.053 -0.000 N 0.49290585413 2.18198449515 -0.00068475564 0.009 -0.046 -0.030 S 6.56718562933 -0.11349126889 0.00673479967 0.008 0.115 -0.056 C 1.82142022278 -2.39594383179 -0.00206827421 -0.008 -0.045 -0.012 C 2.33969079820 -3.68709653410 -0.00625612120 -0.002 -0.046 0.004 C 1.45789786198 -4.76953179608 -0.00945089783 0.007 -0.054 0.014 C 0.08684213972 -4.53272927032 -0.00840538011 0.007 -0.059 -0.001 C -0.35393854068 -3.21111942258 -0.00398541364 0.000 -0.058 -0.017 N 0.49225266031 -2.17934076887 -0.00084210065 -0.012 -0.049 -0.017 H 1.83694111827 5.77332096953 -0.01265611066 -0.003 -0.015 0.006 H -0.61802819388 5.33967450634 -0.01131742088 -0.002 -0.016 0.018 H 3.39175422949 3.87200638269 -0.00704552340 0.000 -0.011 -0.012 H -1.39787683933 2.98334799634 -0.00369736757 0.000 -0.018 0.001 H 1.83794742242 -5.77033326187 -0.01295832570 0.004 -0.015 0.009 H -0.61749414542 -5.33746053721 -0.01121572048 0.003 -0.018 0.000 H -1.39833026435 -2.98175334118 -0.00345676225 -0.001 -0.020 -0.008 H 3.39230213722 -3.86796714602 -0.00754158092 -0.000 -0.011 0.003 H 4.58301895157 2.13678100538 0.00314824260 -0.004 -0.010 0.012 H 4.58784714512 -2.12983634010 0.00211631073 0.003 -0.010 0.010 H -1.68997263563 -0.00719388386 -5.74925805817 0.001 -0.009 0.003 H 0.75224758084 -0.00860493512 -5.25016290812 0.001 -0.014 0.003 H -3.29620044300 -0.00255800648 -3.88456579214 0.000 0.010 0.002 H 1.47161249279 -0.00457826661 -2.87685200854 0.000 0.005 0.003 H -1.69176120521 -0.00597000955 5.75026973076 -0.002 -0.042 0.003 H 0.75025791005 -0.00892914887 5.25161119224 -0.001 -0.061 0.004 H 1.46975366817 -0.00523069331 2.87805400798 0.000 0.015 0.004 H -3.29750276746 -0.00099200484 3.88584245085 -0.000 0.030 0.002 H -4.55513299541 0.00377930937 -2.13473279421 0.001 -0.110 0.002 H -4.55107479454 0.00501307822 2.13844314827 -0.000 -0.011 0.002 H -6.83436893102 0.00806057203 1.19721860356 -0.005 -0.772 -0.004 H 6.86748209639 1.20005966818 0.00372860376 -0.026 0.027 0.208 61 Mode 26: freq=192.86 N -0.44003451495 -0.00038510790 2.12369783068 0.006 -0.044 0.035 C -1.76594470239 0.00039861437 2.37754210613 0.003 -0.038 0.033 C -2.24923313135 -0.00145267054 3.67997125809 -0.002 -0.012 0.034 C -1.33887502024 -0.00450793845 4.73956848945 -0.010 0.025 0.040 C 0.02462671625 -0.00591801736 4.46614405978 -0.009 0.017 0.044 C 0.43187566201 -0.00376957955 3.13352499014 -0.004 -0.023 0.044 C -2.63984642995 0.00218980399 1.17162612704 -0.002 -0.027 0.034 N -1.98513620489 0.00132140951 0.00153900685 -0.002 -0.037 0.037 C -2.63911589169 0.00167522827 -1.17277445342 -0.001 0.010 0.034 C -4.02452897564 0.00329996303 -1.20791476641 0.004 0.074 0.029 C -4.73391255267 0.00451580118 -0.00020876193 -0.001 0.047 0.024 C -4.02924140493 0.00399189729 1.20660077672 -0.007 -0.004 0.029 Co 0.00000000000 0.00000000000 0.00000000000 -0.001 -0.055 -0.122 N -0.43839318333 -0.00054206762 -2.12229806799 -0.009 -0.001 0.038 C -1.76408906064 -0.00030645034 -2.37697009192 -0.005 -0.001 0.034 C -2.24773885821 -0.00257631963 -3.67934971086 0.001 -0.014 0.034 C -1.33713102227 -0.00526459193 -4.73855802198 0.011 -0.007 0.042 C 0.02654101484 -0.00591797621 -4.46472703619 0.010 0.013 0.048 C 0.43371721952 -0.00363389350 -3.13225443930 0.002 0.010 0.048 S -6.53329279136 0.00637481657 -0.11611178087 0.005 -0.060 -0.080 N 2.00981687167 0.00259443239 -0.00000686048 0.002 0.011 -0.129 C 2.67119656792 1.17263645248 0.00045766926 0.001 0.011 -0.077 C 4.06129317470 1.20536051565 0.00241240325 0.003 0.009 0.043 C 4.76783866331 0.00148799420 0.00346798881 0.002 0.008 0.163 C 4.05723810074 -1.20352939940 0.00211502115 -0.000 0.009 0.163 C 2.67108506586 -1.17139122066 0.00026591651 0.002 0.011 -0.017 C 1.82209539371 2.39842937406 -0.00175320633 -0.001 0.010 -0.139 C 2.33938959521 3.68993217240 -0.00584554905 -0.000 0.011 -0.077 C 1.45736908622 4.77231118002 -0.00917967851 0.001 0.013 0.069 C 0.08658913130 4.53522926787 -0.00833235387 0.001 0.013 0.096 C -0.35359617412 3.21325694137 -0.00400174376 0.001 0.012 -0.052 N 0.49290585413 2.18198449515 -0.00068475564 -0.001 0.010 -0.157 S 6.56718562933 -0.11349126889 0.00673479967 0.000 -0.028 -0.230 C 1.82142022278 -2.39594383179 -0.00206827421 0.003 0.011 -0.030 C 2.33969079820 -3.68709653410 -0.00625612120 0.000 0.011 -0.017 C 1.45789786198 -4.76953179608 -0.00945089783 -0.003 0.014 0.020 C 0.08684213972 -4.53272927032 -0.00840538011 -0.003 0.016 0.025 C -0.35393854068 -3.21111942258 -0.00398541364 0.000 0.017 -0.017 N 0.49225266031 -2.17934076887 -0.00084210065 0.004 0.013 -0.041 H 1.83694111827 5.77332096953 -0.01265611066 0.000 0.004 0.047 H -0.61802819388 5.33967450634 -0.01131742088 0.000 0.004 0.063 H 3.39175422949 3.87200638269 -0.00704552340 -0.000 0.003 -0.030 H -1.39787683933 2.98334799634 -0.00369736757 0.000 0.004 -0.020 H 1.83794742242 -5.77033326187 -0.01295832570 -0.002 0.004 0.012 H -0.61749414542 -5.33746053721 -0.01121572048 -0.001 0.005 0.016 H -1.39833026435 -2.98175334118 -0.00345676225 0.000 0.006 -0.007 H 3.39230213722 -3.86796714602 -0.00754158092 -0.000 0.002 -0.010 H 4.58301895157 2.13678100538 0.00314824260 0.001 0.003 -0.007 H 4.58784714512 -2.12983634010 0.00211631073 -0.000 0.002 0.102 H -1.68997263563 -0.00719388386 -5.74925805817 0.005 -0.004 0.011 H 0.75224758084 -0.00860493512 -5.25016290812 0.004 0.007 0.015 H -3.29620044300 -0.00255800648 -3.88456579214 0.001 -0.008 0.007 H 1.47161249279 -0.00457826661 -2.87685200854 -0.000 0.005 0.017 H -1.69176120521 -0.00597000955 5.75026973076 -0.004 0.016 0.011 H 0.75025791005 -0.00892914887 5.25161119224 -0.003 0.012 0.013 H 1.46975366817 -0.00523069331 2.87805400798 -0.000 -0.009 0.015 H -3.29750276746 -0.00099200484 3.88584245085 -0.001 -0.003 0.008 H -4.55513299541 0.00377930937 -2.13473279421 0.002 0.042 0.008 H -4.55107479454 0.00501307822 2.13844314827 -0.004 -0.010 0.008 H -6.83436893102 0.00806057203 1.19721860356 -0.018 0.174 -0.019 H 6.86748209639 1.20005966818 0.00372860376 0.005 -0.004 0.820 61 Mode 27: freq=216.37 N -0.44003451495 -0.00038510790 2.12369783068 -0.002 -0.056 -0.003 C -1.76594470239 0.00039861437 2.37754210613 -0.001 -0.042 -0.002 C -2.24923313135 -0.00145267054 3.67997125809 -0.000 -0.067 -0.001 C -1.33887502024 -0.00450793845 4.73956848945 0.001 -0.005 -0.002 C 0.02462671625 -0.00591801736 4.46614405978 0.001 0.064 -0.003 C 0.43187566201 -0.00376957955 3.13352499014 -0.000 0.008 -0.004 C -2.63984642995 0.00218980399 1.17162612704 -0.001 0.037 -0.001 N -1.98513620489 0.00132140951 0.00153900685 -0.001 -0.176 -0.001 C -2.63911589169 0.00167522827 -1.17277445342 -0.001 0.022 -0.001 C -4.02452897564 0.00329996303 -1.20791476641 -0.001 0.278 -0.001 C -4.73391255267 0.00451580118 -0.00020876193 -0.001 0.224 -0.001 C -4.02924140493 0.00399189729 1.20660077672 -0.001 0.299 -0.002 Co 0.00000000000 0.00000000000 0.00000000000 0.002 -0.480 0.009 N -0.43839318333 -0.00054206762 -2.12229806799 -0.000 -0.121 -0.000 C -1.76408906064 -0.00030645034 -2.37697009192 -0.000 -0.099 -0.001 C -2.24773885821 -0.00257631963 -3.67934971086 -0.000 -0.110 -0.001 C -1.33713102227 -0.00526459193 -4.73855802198 0.000 0.018 -0.001 C 0.02654101484 -0.00591797621 -4.46472703619 0.000 0.109 -0.001 C 0.43371721952 -0.00363389350 -3.13225443930 -0.000 -0.011 -0.001 S -6.53329279136 0.00637481657 -0.11611178087 -0.003 -0.135 0.003 N 2.00981687167 0.00259443239 -0.00000686048 0.002 0.050 0.005 C 2.67119656792 1.17263645248 0.00045766926 -0.013 0.055 0.005 C 4.06129317470 1.20536051565 0.00241240325 -0.000 0.057 0.008 C 4.76783866331 0.00148799420 0.00346798881 0.001 0.056 -0.007 C 4.05723810074 -1.20352939940 0.00211502115 0.004 0.056 -0.023 C 2.67108506586 -1.17139122066 0.00026591651 0.017 0.055 -0.005 C 1.82209539371 2.39842937406 -0.00175320633 -0.023 0.056 0.002 C 2.33938959521 3.68993217240 -0.00584554905 -0.004 0.054 -0.003 C 1.45736908622 4.77231118002 -0.00917967851 0.020 0.073 -0.004 C 0.08658913130 4.53522926787 -0.00833235387 0.018 0.088 0.002 C -0.35359617412 3.21325694137 -0.00400174376 -0.001 0.089 0.004 N 0.49290585413 2.18198449515 -0.00068475564 -0.030 0.065 0.002 S 6.56718562933 -0.11349126889 0.00673479967 -0.014 -0.141 0.005 C 1.82142022278 -2.39594383179 -0.00206827421 0.026 0.056 0.004 C 2.33969079820 -3.68709653410 -0.00625612120 0.005 0.053 0.009 C 1.45789786198 -4.76953179608 -0.00945089783 -0.022 0.075 0.002 C 0.08684213972 -4.53272927032 -0.00840538011 -0.019 0.093 -0.008 C -0.35393854068 -3.21111942258 -0.00398541364 0.003 0.095 -0.002 N 0.49225266031 -2.17934076887 -0.00084210065 0.034 0.068 0.006 H 1.83694111827 5.77332096953 -0.01265611066 0.011 0.019 -0.002 H -0.61802819388 5.33967450634 -0.01131742088 0.007 0.028 0.001 H 3.39175422949 3.87200638269 -0.00704552340 -0.000 0.010 -0.002 H -1.39787683933 2.98334799634 -0.00369736757 -0.002 0.033 0.002 H 1.83794742242 -5.77033326187 -0.01295832570 -0.012 0.020 0.001 H -0.61749414542 -5.33746053721 -0.01121572048 -0.008 0.029 -0.005 H -1.39833026435 -2.98175334118 -0.00345676225 0.003 0.036 -0.001 H 3.39230213722 -3.86796714602 -0.00754158092 0.000 0.009 0.004 H 4.58301895157 2.13678100538 0.00314824260 0.000 0.017 0.005 H 4.58784714512 -2.12983634010 0.00211631073 0.002 0.017 -0.012 H -1.68997263563 -0.00719388386 -5.74925805817 0.000 0.017 -0.000 H 0.75224758084 -0.00860493512 -5.25016290812 0.000 0.070 -0.000 H -3.29620044300 -0.00255800648 -3.88456579214 -0.000 -0.050 -0.000 H 1.47161249279 -0.00457826661 -2.87685200854 -0.000 -0.001 -0.000 H -1.69176120521 -0.00597000955 5.75026973076 0.001 -0.001 -0.001 H 0.75025791005 -0.00892914887 5.25161119224 0.001 0.040 -0.001 H 1.46975366817 -0.00523069331 2.87805400798 -0.000 0.005 -0.001 H -3.29750276746 -0.00099200484 3.88584245085 0.000 -0.034 -0.000 H -4.55513299541 0.00377930937 -2.13473279421 -0.000 0.098 -0.000 H -4.55107479454 0.00501307822 2.13844314827 -0.000 0.138 -0.000 H -6.83436893102 0.00806057203 1.19721860356 -0.000 -0.530 0.001 H 6.86748209639 1.20005966818 0.00372860376 0.037 -0.034 0.002 61 Mode 28: freq=223.19 N -0.44003451495 -0.00038510790 2.12369783068 -0.031 0.003 -0.061 C -1.76594470239 0.00039861437 2.37754210613 -0.022 0.001 -0.052 C -2.24923313135 -0.00145267054 3.67997125809 0.001 0.006 -0.048 C -1.33887502024 -0.00450793845 4.73956848945 0.031 0.003 -0.072 C 0.02462671625 -0.00591801736 4.46614405978 0.028 -0.006 -0.091 C 0.43187566201 -0.00376957955 3.13352499014 0.002 -0.003 -0.092 C -2.63984642995 0.00218980399 1.17162612704 -0.012 -0.006 -0.054 N -1.98513620489 0.00132140951 0.00153900685 0.002 0.003 -0.051 C -2.63911589169 0.00167522827 -1.17277445342 0.015 0.004 -0.054 C -4.02452897564 0.00329996303 -1.20791476641 0.003 0.009 -0.058 C -4.73391255267 0.00451580118 -0.00020876193 0.000 -0.004 -0.057 C -4.02924140493 0.00399189729 1.20660077672 -0.001 -0.020 -0.058 Co 0.00000000000 0.00000000000 0.00000000000 0.003 0.009 0.385 N -0.43839318333 -0.00054206762 -2.12229806799 0.034 0.000 -0.064 C -1.76408906064 -0.00030645034 -2.37697009192 0.025 0.001 -0.052 C -2.24773885821 -0.00257631963 -3.67934971086 0.000 -0.003 -0.048 C -1.33713102227 -0.00526459193 -4.73855802198 -0.031 -0.003 -0.074 C 0.02654101484 -0.00591797621 -4.46472703619 -0.027 0.003 -0.094 C 0.43371721952 -0.00363389350 -3.13225443930 0.000 0.003 -0.096 S -6.53329279136 0.00637481657 -0.11611178087 -0.015 0.002 0.123 N 2.00981687167 0.00259443239 -0.00000686048 -0.001 -0.001 0.206 C 2.67119656792 1.17263645248 0.00045766926 -0.001 -0.001 -0.012 C 4.06129317470 1.20536051565 0.00241240325 -0.001 -0.001 -0.313 C 4.76783866331 0.00148799420 0.00346798881 -0.001 -0.001 -0.265 C 4.05723810074 -1.20352939940 0.00211502115 -0.001 -0.001 -0.316 C 2.67108506586 -1.17139122066 0.00026591651 -0.001 -0.001 -0.006 C 1.82209539371 2.39842937406 -0.00175320633 -0.000 -0.001 0.095 C 2.33938959521 3.68993217240 -0.00584554905 0.000 -0.001 0.096 C 1.45736908622 4.77231118002 -0.00917967851 0.001 -0.001 -0.029 C 0.08658913130 4.53522926787 -0.00833235387 0.001 -0.001 -0.097 C -0.35359617412 3.21325694137 -0.00400174376 -0.000 -0.000 0.030 N 0.49290585413 2.18198449515 -0.00068475564 -0.000 -0.000 0.121 S 6.56718562933 -0.11349126889 0.00673479967 -0.004 0.003 0.164 C 1.82142022278 -2.39594383179 -0.00206827421 -0.001 -0.002 0.148 C 2.33969079820 -3.68709653410 -0.00625612120 -0.000 -0.001 0.140 C 1.45789786198 -4.76953179608 -0.00945089783 0.001 -0.002 -0.048 C 0.08684213972 -4.53272927032 -0.00840538011 0.001 -0.002 -0.142 C -0.35393854068 -3.21111942258 -0.00398541364 -0.000 -0.003 0.047 N 0.49225266031 -2.17934076887 -0.00084210065 -0.001 -0.003 0.183 H 1.83694111827 5.77332096953 -0.01265611066 0.000 -0.000 -0.023 H -0.61802819388 5.33967450634 -0.01131742088 0.000 -0.000 -0.063 H 3.39175422949 3.87200638269 -0.00704552340 0.000 -0.000 0.045 H -1.39787683933 2.98334799634 -0.00369736757 -0.000 0.000 0.011 H 1.83794742242 -5.77033326187 -0.01295832570 0.001 -0.000 -0.038 H -0.61749414542 -5.33746053721 -0.01121572048 0.000 -0.001 -0.093 H -1.39833026435 -2.98175334118 -0.00345676225 -0.000 -0.001 0.017 H 3.39230213722 -3.86796714602 -0.00754158092 0.000 -0.000 0.063 H 4.58301895157 2.13678100538 0.00314824260 -0.000 -0.000 -0.140 H 4.58784714512 -2.12983634010 0.00211631073 -0.000 -0.000 -0.117 H -1.68997263563 -0.00719388386 -5.74925805817 -0.016 -0.002 -0.019 H 0.75224758084 -0.00860493512 -5.25016290812 -0.011 0.002 -0.030 H -3.29620044300 -0.00255800648 -3.88456579214 -0.001 -0.002 -0.006 H 1.47161249279 -0.00457826661 -2.87685200854 0.003 0.002 -0.038 H -1.69176120521 -0.00597000955 5.75026973076 0.015 0.002 -0.019 H 0.75025791005 -0.00892914887 5.25161119224 0.011 -0.004 -0.029 H 1.46975366817 -0.00523069331 2.87805400798 -0.002 -0.002 -0.036 H -3.29750276746 -0.00099200484 3.88584245085 0.002 0.003 -0.007 H -4.55513299541 0.00377930937 -2.13473279421 0.002 0.006 -0.017 H -4.55107479454 0.00501307822 2.13844314827 -0.000 -0.011 -0.017 H -6.83436893102 0.00806057203 1.19721860356 0.034 0.014 0.030 H 6.86748209639 1.20005966818 0.00372860376 -0.002 0.002 0.450 61 Mode 29: freq=252.71 N -0.44003451495 -0.00038510790 2.12369783068 0.003 0.139 0.004 C -1.76594470239 0.00039861437 2.37754210613 0.003 0.090 0.003 C -2.24923313135 -0.00145267054 3.67997125809 0.000 0.131 0.002 C -1.33887502024 -0.00450793845 4.73956848945 -0.002 -0.018 0.004 C 0.02462671625 -0.00591801736 4.46614405978 -0.002 -0.126 0.005 C 0.43187566201 -0.00376957955 3.13352499014 0.000 0.034 0.006 C -2.63984642995 0.00218980399 1.17162612704 0.002 -0.056 0.003 N -1.98513620489 0.00132140951 0.00153900685 -0.000 0.003 0.002 C -2.63911589169 0.00167522827 -1.17277445342 -0.002 0.049 0.003 C -4.02452897564 0.00329996303 -1.20791476641 -0.001 0.252 0.004 C -4.73391255267 0.00451580118 -0.00020876193 0.000 0.004 0.004 C -4.02924140493 0.00399189729 1.20660077672 0.001 -0.260 0.004 Co 0.00000000000 0.00000000000 0.00000000000 -0.001 0.030 -0.034 N -0.43839318333 -0.00054206762 -2.12229806799 -0.003 -0.150 0.004 C -1.76408906064 -0.00030645034 -2.37697009192 -0.003 -0.101 0.003 C -2.24773885821 -0.00257631963 -3.67934971086 -0.001 -0.136 0.002 C -1.33713102227 -0.00526459193 -4.73855802198 0.002 0.025 0.004 C 0.02654101484 -0.00591797621 -4.46472703619 0.002 0.131 0.006 C 0.43371721952 -0.00363389350 -3.13225443930 -0.000 -0.041 0.006 S -6.53329279136 0.00637481657 -0.11611178087 0.001 -0.004 -0.007 N 2.00981687167 0.00259443239 -0.00000686048 0.000 -0.001 -0.008 C 2.67119656792 1.17263645248 0.00045766926 0.001 -0.002 0.066 C 4.06129317470 1.20536051565 0.00241240325 0.000 -0.002 0.354 C 4.76783866331 0.00148799420 0.00346798881 0.000 -0.002 0.002 C 4.05723810074 -1.20352939940 0.00211502115 -0.000 -0.002 -0.331 C 2.67108506586 -1.17139122066 0.00026591651 -0.001 -0.002 -0.059 C 1.82209539371 2.39842937406 -0.00175320633 0.001 -0.002 -0.144 C 2.33938959521 3.68993217240 -0.00584554905 0.000 -0.002 -0.189 C 1.45736908622 4.77231118002 -0.00917967851 -0.001 -0.003 0.042 C 0.08658913130 4.53522926787 -0.00833235387 -0.001 -0.003 0.181 C -0.35359617412 3.21325694137 -0.00400174376 0.000 -0.004 -0.070 N 0.49290585413 2.18198449515 -0.00068475564 0.002 -0.003 -0.216 S 6.56718562933 -0.11349126889 0.00673479967 0.001 0.004 0.001 C 1.82142022278 -2.39594383179 -0.00206827421 -0.001 -0.002 0.147 C 2.33969079820 -3.68709653410 -0.00625612120 -0.000 -0.002 0.187 C 1.45789786198 -4.76953179608 -0.00945089783 0.001 -0.003 -0.046 C 0.08684213972 -4.53272927032 -0.00840538011 0.001 -0.003 -0.179 C -0.35393854068 -3.21111942258 -0.00398541364 -0.000 -0.004 0.072 N 0.49225266031 -2.17934076887 -0.00084210065 -0.002 -0.003 0.217 H 1.83694111827 5.77332096953 -0.01265611066 -0.001 -0.001 0.037 H -0.61802819388 5.33967450634 -0.01131742088 -0.000 -0.001 0.119 H 3.39175422949 3.87200638269 -0.00704552340 0.000 -0.000 -0.091 H -1.39787683933 2.98334799634 -0.00369736757 0.000 -0.002 -0.032 H 1.83794742242 -5.77033326187 -0.01295832570 0.001 -0.001 -0.039 H -0.61749414542 -5.33746053721 -0.01121572048 0.000 -0.001 -0.118 H -1.39833026435 -2.98175334118 -0.00345676225 -0.000 -0.002 0.033 H 3.39230213722 -3.86796714602 -0.00754158092 -0.000 -0.000 0.089 H 4.58301895157 2.13678100538 0.00314824260 -0.000 -0.001 0.205 H 4.58784714512 -2.12983634010 0.00211631073 0.000 -0.001 -0.192 H -1.68997263563 -0.00719388386 -5.74925805817 0.001 0.024 0.001 H 0.75224758084 -0.00860493512 -5.25016290812 0.001 0.086 0.002 H -3.29620044300 -0.00255800648 -3.88456579214 -0.000 -0.064 0.000 H 1.47161249279 -0.00457826661 -2.87685200854 -0.000 -0.018 0.003 H -1.69176120521 -0.00597000955 5.75026973076 -0.001 -0.018 0.001 H 0.75025791005 -0.00892914887 5.25161119224 -0.001 -0.082 0.002 H 1.46975366817 -0.00523069331 2.87805400798 0.000 0.015 0.002 H -3.29750276746 -0.00099200484 3.88584245085 0.000 0.063 0.000 H -4.55513299541 0.00377930937 -2.13473279421 -0.000 0.144 0.001 H -4.55107479454 0.00501307822 2.13844314827 0.000 -0.150 0.001 H -6.83436893102 0.00806057203 1.19721860356 -0.002 0.039 -0.002 H 6.86748209639 1.20005966818 0.00372860376 -0.001 0.001 -0.056 61 Mode 30: freq=266.39 N -0.44003451495 -0.00038510790 2.12369783068 0.005 -0.187 0.004 C -1.76594470239 0.00039861437 2.37754210613 0.004 -0.128 0.002 C -2.24923313135 -0.00145267054 3.67997125809 0.001 -0.154 0.001 C -1.33887502024 -0.00450793845 4.73956848945 -0.002 0.054 0.005 C 0.02462671625 -0.00591801736 4.46614405978 -0.002 0.138 0.008 C 0.43187566201 -0.00376957955 3.13352499014 0.001 -0.089 0.008 C -2.63984642995 0.00218980399 1.17162612704 0.003 0.043 0.003 N -1.98513620489 0.00132140951 0.00153900685 -0.000 -0.012 0.001 C -2.63911589169 0.00167522827 -1.17277445342 -0.004 -0.038 0.003 C -4.02452897564 0.00329996303 -1.20791476641 -0.003 -0.324 0.005 C -4.73391255267 0.00451580118 -0.00020876193 -0.000 -0.032 0.006 C -4.02924140493 0.00399189729 1.20660077672 0.002 0.285 0.005 Co 0.00000000000 0.00000000000 0.00000000000 0.000 -0.108 -0.048 N -0.43839318333 -0.00054206762 -2.12229806799 -0.006 0.282 0.004 C -1.76408906064 -0.00030645034 -2.37697009192 -0.005 0.206 0.002 C -2.24773885821 -0.00257631963 -3.67934971086 -0.001 0.221 0.001 C -1.33713102227 -0.00526459193 -4.73855802198 0.003 -0.095 0.005 C 0.02654101484 -0.00591797621 -4.46472703619 0.002 -0.197 0.009 C 0.43371721952 -0.00363389350 -3.13225443930 -0.002 0.143 0.008 S -6.53329279136 0.00637481657 -0.11611178087 0.001 0.015 -0.010 N 2.00981687167 0.00259443239 -0.00000686048 0.000 -0.001 -0.012 C 2.67119656792 1.17263645248 0.00045766926 -0.008 0.003 0.022 C 4.06129317470 1.20536051565 0.00241240325 -0.005 0.008 0.206 C 4.76783866331 0.00148799420 0.00346798881 -0.000 0.011 -0.008 C 4.05723810074 -1.20352939940 0.00211502115 0.006 0.008 -0.209 C 2.67108506586 -1.17139122066 0.00026591651 0.008 0.003 -0.022 C 1.82209539371 2.39842937406 -0.00175320633 -0.010 0.003 -0.113 C 2.33938959521 3.68993217240 -0.00584554905 -0.004 0.001 -0.124 C 1.45736908622 4.77231118002 -0.00917967851 0.004 0.007 0.054 C 0.08658913130 4.53522926787 -0.00833235387 0.003 0.014 0.109 C -0.35359617412 3.21325694137 -0.00400174376 -0.004 0.014 -0.085 N 0.49290585413 2.18198449515 -0.00068475564 -0.012 0.007 -0.159 S 6.56718562933 -0.11349126889 0.00673479967 -0.003 -0.019 0.003 C 1.82142022278 -2.39594383179 -0.00206827421 0.011 0.003 0.138 C 2.33969079820 -3.68709653410 -0.00625612120 0.004 0.001 0.146 C 1.45789786198 -4.76953179608 -0.00945089783 -0.004 0.008 -0.066 C 0.08684213972 -4.53272927032 -0.00840538011 -0.002 0.015 -0.129 C -0.35393854068 -3.21111942258 -0.00398541364 0.005 0.015 0.101 N 0.49225266031 -2.17934076887 -0.00084210065 0.013 0.008 0.189 H 1.83694111827 5.77332096953 -0.01265611066 0.003 0.002 0.043 H -0.61802819388 5.33967450634 -0.01131742088 0.002 0.005 0.075 H 3.39175422949 3.87200638269 -0.00704552340 -0.001 -0.002 -0.058 H -1.39787683933 2.98334799634 -0.00369736757 -0.002 0.006 -0.040 H 1.83794742242 -5.77033326187 -0.01295832570 -0.003 0.002 -0.052 H -0.61749414542 -5.33746053721 -0.01121572048 -0.002 0.005 -0.089 H -1.39833026435 -2.98175334118 -0.00345676225 0.002 0.006 0.047 H 3.39230213722 -3.86796714602 -0.00754158092 0.001 -0.001 0.067 H 4.58301895157 2.13678100538 0.00314824260 -0.003 0.003 0.123 H 4.58784714512 -2.12983634010 0.00211631073 0.003 0.003 -0.119 H -1.68997263563 -0.00719388386 -5.74925805817 0.002 -0.077 0.001 H 0.75224758084 -0.00860493512 -5.25016290812 0.001 -0.136 0.003 H -3.29620044300 -0.00255800648 -3.88456579214 -0.000 0.099 -0.001 H 1.47161249279 -0.00457826661 -2.87685200854 -0.001 0.065 0.004 H -1.69176120521 -0.00597000955 5.75026973076 -0.002 0.044 0.001 H 0.75025791005 -0.00892914887 5.25161119224 -0.001 0.094 0.003 H 1.46975366817 -0.00523069331 2.87805400798 0.001 -0.042 0.003 H -3.29750276746 -0.00099200484 3.88584245085 0.000 -0.072 -0.001 H -4.55513299541 0.00377930937 -2.13473279421 -0.001 -0.179 0.002 H -4.55107479454 0.00501307822 2.13844314827 0.001 0.173 0.002 H -6.83436893102 0.00806057203 1.19721860356 -0.004 -0.010 -0.003 H 6.86748209639 1.20005966818 0.00372860376 0.006 -0.005 -0.014 61 Mode 31: freq=269.49 N -0.44003451495 -0.00038510790 2.12369783068 -0.005 0.315 -0.003 C -1.76594470239 0.00039861437 2.37754210613 -0.004 0.246 -0.001 C -2.24923313135 -0.00145267054 3.67997125809 -0.001 0.236 -0.000 C -1.33887502024 -0.00450793845 4.73956848945 0.003 -0.122 -0.004 C 0.02462671625 -0.00591801736 4.46614405978 0.002 -0.207 -0.008 C 0.43187566201 -0.00376957955 3.13352499014 -0.001 0.171 -0.007 C -2.63984642995 0.00218980399 1.17162612704 -0.004 -0.020 -0.002 N -1.98513620489 0.00132140951 0.00153900685 -0.000 -0.077 -0.001 C -2.63911589169 0.00167522827 -1.17277445342 0.003 -0.000 -0.002 C -4.02452897564 0.00329996303 -1.20791476641 0.001 -0.069 -0.004 C -4.73391255267 0.00451580118 -0.00020876193 -0.002 -0.166 -0.006 C -4.02924140493 0.00399189729 1.20660077672 -0.003 -0.198 -0.005 Co 0.00000000000 0.00000000000 0.00000000000 0.006 -0.543 0.042 N -0.43839318333 -0.00054206762 -2.12229806799 0.005 0.229 -0.004 C -1.76408906064 -0.00030645034 -2.37697009192 0.004 0.187 -0.002 C -2.24773885821 -0.00257631963 -3.67934971086 0.001 0.165 -0.001 C -1.33713102227 -0.00526459193 -4.73855802198 -0.002 -0.097 -0.003 C 0.02654101484 -0.00591797621 -4.46472703619 -0.001 -0.143 -0.006 C 0.43371721952 -0.00363389350 -3.13225443930 0.001 0.129 -0.006 S -6.53329279136 0.00637481657 -0.11611178087 -0.005 0.074 0.008 N 2.00981687167 0.00259443239 -0.00000686048 0.001 -0.006 0.012 C 2.67119656792 1.17263645248 0.00045766926 -0.038 0.015 -0.000 C 4.06129317470 1.20536051565 0.00241240325 -0.025 0.038 -0.023 C 4.76783866331 0.00148799420 0.00346798881 -0.001 0.053 0.008 C 4.05723810074 -1.20352939940 0.00211502115 0.026 0.037 0.033 C 2.67108506586 -1.17139122066 0.00026591651 0.040 0.014 0.005 C 1.82209539371 2.39842937406 -0.00175320633 -0.050 0.014 0.005 C 2.33938959521 3.68993217240 -0.00584554905 -0.018 0.006 0.005 C 1.45736908622 4.77231118002 -0.00917967851 0.019 0.034 -0.003 C 0.08658913130 4.53522926787 -0.00833235387 0.014 0.063 -0.004 C -0.35359617412 3.21325694137 -0.00400174376 -0.019 0.068 0.006 N 0.49290585413 2.18198449515 -0.00068475564 -0.056 0.037 0.008 S 6.56718562933 -0.11349126889 0.00673479967 -0.017 -0.088 -0.003 C 1.82142022278 -2.39594383179 -0.00206827421 0.053 0.015 -0.031 C 2.33969079820 -3.68709653410 -0.00625612120 0.020 0.007 -0.032 C 1.45789786198 -4.76953179608 -0.00945089783 -0.018 0.036 0.015 C 0.08684213972 -4.53272927032 -0.00840538011 -0.013 0.067 0.028 C -0.35393854068 -3.21111942258 -0.00398541364 0.021 0.072 -0.022 N 0.49225266031 -2.17934076887 -0.00084210065 0.059 0.040 -0.042 H 1.83694111827 5.77332096953 -0.01265611066 0.014 0.006 -0.002 H -0.61802819388 5.33967450634 -0.01131742088 0.009 0.023 -0.003 H 3.39175422949 3.87200638269 -0.00704552340 -0.004 -0.006 0.003 H -1.39787683933 2.98334799634 -0.00369736757 -0.008 0.029 0.003 H 1.83794742242 -5.77033326187 -0.01295832570 -0.014 0.007 0.012 H -0.61749414542 -5.33746053721 -0.01121572048 -0.009 0.024 0.020 H -1.39833026435 -2.98175334118 -0.00345676225 0.008 0.031 -0.010 H 3.39230213722 -3.86796714602 -0.00754158092 0.005 -0.006 -0.014 H 4.58301895157 2.13678100538 0.00314824260 -0.012 0.014 -0.016 H 4.58784714512 -2.12983634010 0.00211631073 0.013 0.014 0.016 H -1.68997263563 -0.00719388386 -5.74925805817 -0.001 -0.077 -0.001 H 0.75224758084 -0.00860493512 -5.25016290812 -0.001 -0.102 -0.002 H -3.29620044300 -0.00255800648 -3.88456579214 0.000 0.065 0.000 H 1.47161249279 -0.00457826661 -2.87685200854 0.001 0.056 -0.003 H -1.69176120521 -0.00597000955 5.75026973076 0.002 -0.098 -0.001 H 0.75025791005 -0.00892914887 5.25161119224 0.001 -0.146 -0.003 H 1.46975366817 -0.00523069331 2.87805400798 -0.001 0.076 -0.003 H -3.29750276746 -0.00099200484 3.88584245085 0.000 0.098 0.001 H -4.55513299541 0.00377930937 -2.13473279421 0.001 0.007 -0.002 H -4.55107479454 0.00501307822 2.13844314827 -0.001 -0.073 -0.001 H -6.83436893102 0.00806057203 1.19721860356 0.002 0.098 0.002 H 6.86748209639 1.20005966818 0.00372860376 0.030 -0.023 -0.002 61 Mode 32: freq=270.15 N -0.44003451495 -0.00038510790 2.12369783068 -0.067 -0.031 -0.046 C -1.76594470239 0.00039861437 2.37754210613 -0.058 -0.023 -0.024 C -2.24923313135 -0.00145267054 3.67997125809 -0.013 -0.024 -0.013 C -1.33887502024 -0.00450793845 4.73956848945 0.038 0.012 -0.052 C 0.02462671625 -0.00591801736 4.46614405978 0.030 0.021 -0.089 C 0.43187566201 -0.00376957955 3.13352499014 -0.016 -0.017 -0.094 C -2.63984642995 0.00218980399 1.17162612704 -0.043 0.003 -0.031 N -1.98513620489 0.00132140951 0.00153900685 0.001 0.004 -0.010 C -2.63911589169 0.00167522827 -1.17277445342 0.044 -0.002 -0.031 C -4.02452897564 0.00329996303 -1.20791476641 0.027 -0.012 -0.060 C -4.73391255267 0.00451580118 -0.00020876193 -0.003 0.009 -0.078 C -4.02924140493 0.00399189729 1.20660077672 -0.027 0.028 -0.062 Co 0.00000000000 0.00000000000 0.00000000000 0.008 0.031 0.606 N -0.43839318333 -0.00054206762 -2.12229806799 0.071 -0.000 -0.052 C -1.76408906064 -0.00030645034 -2.37697009192 0.061 -0.001 -0.027 C -2.24773885821 -0.00257631963 -3.67934971086 0.018 0.001 -0.017 C -1.33713102227 -0.00526459193 -4.73855802198 -0.033 0.001 -0.057 C 0.02654101484 -0.00591797621 -4.46472703619 -0.026 -0.001 -0.095 C 0.43371721952 -0.00363389350 -3.13225443930 0.019 -0.001 -0.099 S -6.53329279136 0.00637481657 -0.11611178087 -0.027 -0.004 0.113 N 2.00981687167 0.00259443239 -0.00000686048 -0.000 0.000 0.181 C 2.67119656792 1.17263645248 0.00045766926 0.001 -0.001 0.046 C 4.06129317470 1.20536051565 0.00241240325 0.000 -0.002 0.107 C 4.76783866331 0.00148799420 0.00346798881 -0.002 -0.003 0.115 C 4.05723810074 -1.20352939940 0.00211502115 -0.003 -0.002 0.054 C 2.67108506586 -1.17139122066 0.00026591651 -0.003 -0.001 0.038 C 1.82209539371 2.39842937406 -0.00175320633 0.002 -0.002 -0.200 C 2.33938959521 3.68993217240 -0.00584554905 0.001 -0.002 -0.212 C 1.45736908622 4.77231118002 -0.00917967851 0.000 -0.002 0.087 C 0.08658913130 4.53522926787 -0.00833235387 0.000 -0.002 0.190 C -0.35359617412 3.21325694137 -0.00400174376 0.001 -0.003 -0.132 N 0.49290585413 2.18198449515 -0.00068475564 0.002 -0.003 -0.267 S 6.56718562933 -0.11349126889 0.00673479967 -0.003 0.005 -0.045 C 1.82142022278 -2.39594383179 -0.00206827421 -0.004 -0.000 -0.177 C 2.33969079820 -3.68709653410 -0.00625612120 -0.001 0.001 -0.184 C 1.45789786198 -4.76953179608 -0.00945089783 0.002 -0.002 0.078 C 0.08684213972 -4.53272927032 -0.00840538011 0.002 -0.005 0.164 C -0.35393854068 -3.21111942258 -0.00398541364 -0.001 -0.004 -0.115 N 0.49225266031 -2.17934076887 -0.00084210065 -0.004 -0.002 -0.232 H 1.83694111827 5.77332096953 -0.01265611066 -0.000 -0.000 0.073 H -0.61802819388 5.33967450634 -0.01131742088 -0.000 -0.001 0.132 H 3.39175422949 3.87200638269 -0.00704552340 0.000 -0.000 -0.089 H -1.39787683933 2.98334799634 -0.00369736757 0.000 -0.001 -0.060 H 1.83794742242 -5.77033326187 -0.01295832570 0.001 -0.001 0.065 H -0.61749414542 -5.33746053721 -0.01121572048 0.001 -0.002 0.114 H -1.39833026435 -2.98175334118 -0.00345676225 -0.001 -0.002 -0.052 H 3.39230213722 -3.86796714602 -0.00754158092 -0.000 0.001 -0.075 H 4.58301895157 2.13678100538 0.00314824260 0.000 -0.001 0.021 H 4.58784714512 -2.12983634010 0.00211631073 -0.001 -0.001 -0.013 H -1.68997263563 -0.00719388386 -5.74925805817 -0.021 0.001 -0.013 H 0.75224758084 -0.00860493512 -5.25016290812 -0.014 -0.000 -0.033 H -3.29620044300 -0.00255800648 -3.88456579214 0.003 0.001 0.007 H 1.47161249279 -0.00457826661 -2.87685200854 0.009 -0.000 -0.042 H -1.69176120521 -0.00597000955 5.75026973076 0.022 0.009 -0.011 H 0.75025791005 -0.00892914887 5.25161119224 0.015 0.015 -0.032 H 1.46975366817 -0.00523069331 2.87805400798 -0.008 -0.008 -0.041 H -3.29750276746 -0.00099200484 3.88584245085 -0.002 -0.010 0.008 H -4.55513299541 0.00377930937 -2.13473279421 0.015 -0.010 -0.021 H -4.55107479454 0.00501307822 2.13844314827 -0.013 0.014 -0.021 H -6.83436893102 0.00806057203 1.19721860356 0.039 -0.007 0.030 H 6.86748209639 1.20005966818 0.00372860376 -0.002 0.001 -0.060 61 Mode 33: freq=292.99 N -0.44003451495 -0.00038510790 2.12369783068 -0.032 -0.002 0.148 C -1.76594470239 0.00039861437 2.37754210613 -0.030 -0.001 0.141 C -2.24923313135 -0.00145267054 3.67997125809 0.074 -0.002 0.209 C -1.33887502024 -0.00450793845 4.73956848945 0.150 0.000 0.171 C 0.02462671625 -0.00591801736 4.46614405978 0.142 0.001 0.121 C 0.43187566201 -0.00376957955 3.13352499014 0.036 -0.001 0.090 C -2.63984642995 0.00218980399 1.17162612704 -0.043 0.001 0.049 N -1.98513620489 0.00132140951 0.00153900685 -0.054 0.004 0.004 C -2.63911589169 0.00167522827 -1.17277445342 -0.038 0.001 -0.044 C -4.02452897564 0.00329996303 -1.20791476641 -0.058 0.001 -0.016 C -4.73391255267 0.00451580118 -0.00020876193 -0.074 0.001 -0.005 C -4.02924140493 0.00399189729 1.20660077672 -0.062 0.000 0.010 Co 0.00000000000 0.00000000000 0.00000000000 -0.074 0.011 -0.012 N -0.43839318333 -0.00054206762 -2.12229806799 -0.024 -0.002 -0.145 C -1.76408906064 -0.00030645034 -2.37697009192 -0.023 -0.002 -0.132 C -2.24773885821 -0.00257631963 -3.67934971086 0.075 -0.003 -0.197 C -1.33713102227 -0.00526459193 -4.73855802198 0.145 0.001 -0.164 C 0.02654101484 -0.00591797621 -4.46472703619 0.138 0.002 -0.120 C 0.43371721952 -0.00363389350 -3.13225443930 0.039 -0.002 -0.091 S -6.53329279136 0.00637481657 -0.11611178087 -0.213 0.000 -0.005 N 2.00981687167 0.00259443239 -0.00000686048 -0.066 -0.006 -0.006 C 2.67119656792 1.17263645248 0.00045766926 -0.048 -0.055 -0.002 C 4.06129317470 1.20536051565 0.00241240325 -0.067 -0.013 -0.001 C 4.76783866331 0.00148799420 0.00346798881 -0.074 0.007 -0.001 C 4.05723810074 -1.20352939940 0.00211502115 -0.059 0.020 0.000 C 2.67108506586 -1.17139122066 0.00026591651 -0.038 0.048 -0.002 C 1.82209539371 2.39842937406 -0.00175320633 -0.028 -0.148 0.002 C 2.33938959521 3.68993217240 -0.00584554905 0.075 -0.221 0.003 C 1.45736908622 4.77231118002 -0.00917967851 0.152 -0.188 -0.000 C 0.08658913130 4.53522926787 -0.00833235387 0.145 -0.139 -0.002 C -0.35359617412 3.21325694137 -0.00400174376 0.040 -0.104 0.002 N 0.49290585413 2.18198449515 -0.00068475564 -0.027 -0.159 0.003 S 6.56718562933 -0.11349126889 0.00673479967 -0.217 0.001 -0.000 C 1.82142022278 -2.39594383179 -0.00206827421 -0.013 0.137 0.002 C 2.33969079820 -3.68709653410 -0.00625612120 0.080 0.204 0.003 C 1.45789786198 -4.76953179608 -0.00945089783 0.144 0.179 -0.000 C 0.08684213972 -4.53272927032 -0.00840538011 0.139 0.144 -0.002 C -0.35393854068 -3.21111942258 -0.00398541364 0.048 0.113 0.001 N 0.49225266031 -2.17934076887 -0.00084210065 -0.008 0.158 0.003 H 1.83694111827 5.77332096953 -0.01265611066 0.055 -0.059 -0.001 H -0.61802819388 5.33967450634 -0.01131742088 0.056 -0.028 -0.001 H 3.39175422949 3.87200638269 -0.00704552340 0.025 -0.089 0.001 H -1.39787683933 2.98334799634 -0.00369736757 0.007 -0.007 0.001 H 1.83794742242 -5.77033326187 -0.01295832570 0.050 0.055 -0.000 H -0.61749414542 -5.33746053721 -0.01121572048 0.052 0.032 -0.001 H -1.39833026435 -2.98175334118 -0.00345676225 0.010 0.013 0.001 H 3.39230213722 -3.86796714602 -0.00754158092 0.026 0.081 0.001 H 4.58301895157 2.13678100538 0.00314824260 -0.022 -0.004 0.000 H 4.58784714512 -2.12983634010 0.00211631073 -0.017 0.007 0.001 H -1.68997263563 -0.00719388386 -5.74925805817 0.052 0.001 -0.051 H 0.75224758084 -0.00860493512 -5.25016290812 0.052 0.001 -0.024 H -3.29620044300 -0.00255800648 -3.88456579214 0.025 -0.001 -0.082 H 1.47161249279 -0.00457826661 -2.87685200854 0.006 -0.001 -0.005 H -1.69176120521 -0.00597000955 5.75026973076 0.055 0.000 0.054 H 0.75025791005 -0.00892914887 5.25161119224 0.055 0.001 0.023 H 1.46975366817 -0.00523069331 2.87805400798 0.005 -0.001 0.003 H -3.29750276746 -0.00099200484 3.88584245085 0.025 -0.001 0.086 H -4.55513299541 0.00377930937 -2.13473279421 -0.017 -0.000 -0.006 H -4.55107479454 0.00501307822 2.13844314827 -0.020 -0.000 0.003 H -6.83436893102 0.00806057203 1.19721860356 -0.033 -0.000 0.001 H 6.86748209639 1.20005966818 0.00372860376 -0.032 -0.002 -0.000 61 Mode 34: freq=302.98 N -0.44003451495 -0.00038510790 2.12369783068 -0.002 0.031 0.015 C -1.76594470239 0.00039861437 2.37754210613 -0.002 0.019 0.015 C -2.24923313135 -0.00145267054 3.67997125809 0.006 0.038 0.021 C -1.33887502024 -0.00450793845 4.73956848945 0.012 -0.008 0.019 C 0.02462671625 -0.00591801736 4.46614405978 0.011 -0.035 0.014 C 0.43187566201 -0.00376957955 3.13352499014 0.003 0.018 0.012 C -2.63984642995 0.00218980399 1.17162612704 -0.003 -0.028 0.006 N -1.98513620489 0.00132140951 0.00153900685 -0.006 -0.090 0.001 C -2.63911589169 0.00167522827 -1.17277445342 -0.002 -0.028 -0.005 C -4.02452897564 0.00329996303 -1.20791476641 -0.003 0.014 -0.002 C -4.73391255267 0.00451580118 -0.00020876193 -0.003 0.009 -0.001 C -4.02924140493 0.00399189729 1.20660077672 -0.004 0.015 0.002 Co 0.00000000000 0.00000000000 0.00000000000 -0.025 -0.203 -0.001 N -0.43839318333 -0.00054206762 -2.12229806799 0.001 0.031 -0.016 C -1.76408906064 -0.00030645034 -2.37697009192 -0.000 0.019 -0.013 C -2.24773885821 -0.00257631963 -3.67934971086 0.007 0.039 -0.019 C -1.33713102227 -0.00526459193 -4.73855802198 0.011 -0.009 -0.018 C 0.02654101484 -0.00591797621 -4.46472703619 0.011 -0.035 -0.015 C 0.43371721952 -0.00363389350 -3.13225443930 0.004 0.019 -0.013 S -6.53329279136 0.00637481657 -0.11611178087 -0.010 -0.007 0.001 N 2.00981687167 0.00259443239 -0.00000686048 -0.004 0.153 -0.001 C 2.67119656792 1.17263645248 0.00045766926 0.148 0.088 0.000 C 4.06129317470 1.20536051565 0.00241240325 0.119 -0.047 0.002 C 4.76783866331 0.00148799420 0.00346798881 0.007 -0.113 0.000 C 4.05723810074 -1.20352939940 0.00211502115 -0.119 -0.043 -0.002 C 2.67108506586 -1.17139122066 0.00026591651 -0.152 0.091 -0.001 C 1.82209539371 2.39842937406 -0.00175320633 0.254 0.126 -0.001 C 2.33938959521 3.68993217240 -0.00584554905 0.112 0.200 -0.001 C 1.45736908622 4.77231118002 -0.00917967851 -0.071 0.068 0.000 C 0.08658913130 4.53522926787 -0.00833235387 -0.038 -0.138 0.001 C -0.35359617412 3.21325694137 -0.00400174376 0.153 -0.192 0.000 N 0.49290585413 2.18198449515 -0.00068475564 0.316 -0.047 -0.001 S 6.56718562933 -0.11349126889 0.00673479967 0.053 0.199 0.000 C 1.82142022278 -2.39594383179 -0.00206827421 -0.261 0.125 0.001 C 2.33969079820 -3.68709653410 -0.00625612120 -0.118 0.200 0.002 C 1.45789786198 -4.76953179608 -0.00945089783 0.069 0.064 -0.000 C 0.08684213972 -4.53272927032 -0.00840538011 0.036 -0.147 -0.001 C -0.35393854068 -3.21111942258 -0.00398541364 -0.159 -0.202 0.000 N 0.49225266031 -2.17934076887 -0.00084210065 -0.327 -0.053 0.001 H 1.83694111827 5.77332096953 -0.01265611066 -0.068 0.038 0.000 H -0.61802819388 5.33967450634 -0.01131742088 -0.046 -0.070 0.001 H 3.39175422949 3.87200638269 -0.00704552340 0.027 0.099 -0.001 H -1.39787683933 2.98334799634 -0.00369736757 0.054 -0.100 0.000 H 1.83794742242 -5.77033326187 -0.01295832570 0.069 0.037 -0.000 H -0.61749414542 -5.33746053721 -0.01121572048 0.046 -0.074 -0.001 H -1.39833026435 -2.98175334118 -0.00345676225 -0.056 -0.105 0.000 H 3.39230213722 -3.86796714602 -0.00754158092 -0.029 0.099 0.001 H 4.58301895157 2.13678100538 0.00314824260 0.054 -0.024 0.001 H 4.58784714512 -2.12983634010 0.00211631073 -0.058 -0.025 -0.001 H -1.68997263563 -0.00719388386 -5.74925805817 0.004 -0.008 -0.005 H 0.75224758084 -0.00860493512 -5.25016290812 0.004 -0.023 -0.004 H -3.29620044300 -0.00255800648 -3.88456579214 0.002 0.018 -0.007 H 1.47161249279 -0.00457826661 -2.87685200854 0.001 0.012 -0.002 H -1.69176120521 -0.00597000955 5.75026973076 0.004 -0.008 0.006 H 0.75025791005 -0.00892914887 5.25161119224 0.004 -0.023 0.003 H 1.46975366817 -0.00523069331 2.87805400798 0.000 0.012 0.002 H -3.29750276746 -0.00099200484 3.88584245085 0.002 0.017 0.008 H -4.55513299541 0.00377930937 -2.13473279421 -0.001 0.015 -0.001 H -4.55107479454 0.00501307822 2.13844314827 -0.002 0.017 0.000 H -6.83436893102 0.00806057203 1.19721860356 -0.001 -0.009 0.000 H 6.86748209639 1.20005966818 0.00372860376 -0.070 0.053 0.000 61 Mode 35: freq=309.50 N -0.44003451495 -0.00038510790 2.12369783068 -0.106 -0.001 0.123 C -1.76594470239 0.00039861437 2.37754210613 -0.097 -0.001 0.161 C -2.24923313135 -0.00145267054 3.67997125809 0.034 -0.002 0.243 C -1.33887502024 -0.00450793845 4.73956848945 0.140 -0.000 0.185 C 0.02462671625 -0.00591801736 4.46614405978 0.122 0.001 0.091 C 0.43187566201 -0.00376957955 3.13352499014 -0.018 -0.001 0.049 C -2.63984642995 0.00218980399 1.17162612704 -0.090 0.001 0.066 N -1.98513620489 0.00132140951 0.00153900685 -0.034 0.004 0.053 C -2.63911589169 0.00167522827 -1.17277445342 0.012 0.001 -0.002 C -4.02452897564 0.00329996303 -1.20791476641 -0.029 -0.001 -0.026 C -4.73391255267 0.00451580118 -0.00020876193 -0.115 -0.000 -0.050 C -4.02924140493 0.00399189729 1.20660077672 -0.114 0.000 -0.021 Co 0.00000000000 0.00000000000 0.00000000000 0.131 0.009 -0.079 N -0.43839318333 -0.00054206762 -2.12229806799 0.107 -0.001 -0.141 C -1.76408906064 -0.00030645034 -2.37697009192 0.073 -0.000 -0.065 C -2.24773885821 -0.00257631963 -3.67934971086 0.101 -0.001 -0.095 C -1.33713102227 -0.00526459193 -4.73855802198 0.083 -0.000 -0.128 C 0.02654101484 -0.00591797621 -4.46472703619 0.092 0.001 -0.175 C 0.43371721952 -0.00363389350 -3.13225443930 0.088 -0.001 -0.168 S -6.53329279136 0.00637481657 -0.11611178087 -0.366 0.001 0.053 N 2.00981687167 0.00259443239 -0.00000686048 0.049 -0.007 -0.046 C 2.67119656792 1.17263645248 0.00045766926 0.023 0.041 -0.015 C 4.06129317470 1.20536051565 0.00241240325 0.044 0.013 0.009 C 4.76783866331 0.00148799420 0.00346798881 0.064 0.001 0.007 C 4.05723810074 -1.20352939940 0.00211502115 0.056 -0.014 0.009 C 2.67108506586 -1.17139122066 0.00026591651 0.039 -0.050 -0.015 C 1.82209539371 2.39842937406 -0.00175320633 -0.003 0.119 0.006 C 2.33938959521 3.68993217240 -0.00584554905 -0.066 0.170 0.016 C 1.45736908622 4.77231118002 -0.00917967851 -0.097 0.169 -0.002 C 0.08658913130 4.53522926787 -0.00833235387 -0.095 0.155 -0.016 C -0.35359617412 3.21325694137 -0.00400174376 -0.041 0.132 0.007 N 0.49290585413 2.18198449515 -0.00068475564 -0.017 0.144 0.013 S 6.56718562933 -0.11349126889 0.00673479967 0.197 -0.017 -0.004 C 1.82142022278 -2.39594383179 -0.00206827421 0.025 -0.129 0.006 C 2.33969079820 -3.68709653410 -0.00625612120 -0.051 -0.187 0.016 C 1.45789786198 -4.76953179608 -0.00945089783 -0.101 -0.172 -0.002 C 0.08684213972 -4.53272927032 -0.00840538011 -0.095 -0.137 -0.015 C -0.35393854068 -3.21111942258 -0.00398541364 -0.022 -0.108 0.007 N 0.49225266031 -2.17934076887 -0.00084210065 0.018 -0.135 0.013 H 1.83694111827 5.77332096953 -0.01265611066 -0.030 0.050 -0.002 H -0.61802819388 5.33967450634 -0.01131742088 -0.035 0.039 -0.010 H 3.39175422949 3.87200638269 -0.00704552340 -0.020 0.062 0.007 H -1.39787683933 2.98334799634 -0.00369736757 -0.010 0.028 0.005 H 1.83794742242 -5.77033326187 -0.01295832570 -0.036 -0.052 -0.002 H -0.61749414542 -5.33746053721 -0.01121572048 -0.038 -0.031 -0.010 H -1.39833026435 -2.98175334118 -0.00345676225 -0.003 -0.017 0.005 H 3.39230213722 -3.86796714602 -0.00754158092 -0.017 -0.071 0.007 H 4.58301895157 2.13678100538 0.00314824260 0.013 0.005 0.009 H 4.58784714512 -2.12983634010 0.00211631073 0.018 -0.004 0.008 H -1.68997263563 -0.00719388386 -5.74925805817 0.012 0.000 -0.033 H 0.75224758084 -0.00860493512 -5.25016290812 0.024 0.001 -0.053 H -3.29620044300 -0.00255800648 -3.88456579214 0.029 -0.001 -0.031 H 1.47161249279 -0.00457826661 -2.87685200854 0.026 -0.000 -0.050 H -1.69176120521 -0.00597000955 5.75026973076 0.061 0.000 0.061 H 0.75025791005 -0.00892914887 5.25161119224 0.056 0.001 0.007 H 1.46975366817 -0.00523069331 2.87805400798 -0.012 -0.000 -0.015 H -3.29750276746 -0.00099200484 3.88584245085 0.014 -0.001 0.103 H -4.55513299541 0.00377930937 -2.13473279421 0.004 -0.001 -0.016 H -4.55107479454 0.00501307822 2.13844314827 -0.038 -0.000 -0.007 H -6.83436893102 0.00806057203 1.19721860356 -0.028 0.000 0.018 H 6.86748209639 1.20005966818 0.00372860376 0.034 -0.002 -0.005 61 Mode 36: freq=311.74 N -0.44003451495 -0.00038510790 2.12369783068 0.292 -0.000 0.094 C -1.76594470239 0.00039861437 2.37754210613 0.228 0.000 -0.071 C -2.24923313135 -0.00145267054 3.67997125809 0.126 0.000 -0.114 C -1.33887502024 -0.00450793845 4.73956848945 -0.021 -0.000 0.005 C 0.02462671625 -0.00591801736 4.46614405978 0.014 -0.000 0.185 C 0.43187566201 -0.00376957955 3.13352499014 0.163 -0.000 0.220 C -2.63984642995 0.00218980399 1.17162612704 0.123 0.000 -0.067 N -1.98513620489 0.00132140951 0.00153900685 -0.022 0.001 -0.144 C -2.63911589169 0.00167522827 -1.17277445342 -0.158 0.001 -0.105 C -4.02452897564 0.00329996303 -1.20791476641 -0.140 0.001 0.041 C -4.73391255267 0.00451580118 -0.00020876193 -0.033 0.000 0.112 C -4.02924140493 0.00399189729 1.20660077672 0.086 -0.001 0.052 Co 0.00000000000 0.00000000000 0.00000000000 -0.011 0.003 0.200 N -0.43839318333 -0.00054206762 -2.12229806799 -0.306 -0.000 -0.020 C -1.76408906064 -0.00030645034 -2.37697009192 -0.248 -0.000 -0.176 C -2.24773885821 -0.00257631963 -3.67934971086 -0.076 -0.001 -0.269 C -1.33713102227 -0.00526459193 -4.73855802198 0.113 -0.000 -0.135 C 0.02654101484 -0.00591797621 -4.46472703619 0.074 0.001 0.073 C 0.43371721952 -0.00363389350 -3.13225443930 -0.142 0.000 0.131 S -6.53329279136 0.00637481657 -0.11611178087 -0.072 0.000 -0.182 N 2.00981687167 0.00259443239 -0.00000686048 0.014 -0.003 0.106 C 2.67119656792 1.17263645248 0.00045766926 0.010 0.012 0.036 C 4.06129317470 1.20536051565 0.00241240325 0.020 0.002 -0.022 C 4.76783866331 0.00148799420 0.00346798881 0.033 -0.000 -0.017 C 4.05723810074 -1.20352939940 0.00211502115 0.024 -0.004 -0.021 C 2.67108506586 -1.17139122066 0.00026591651 0.015 -0.016 0.036 C 1.82209539371 2.39842937406 -0.00175320633 -0.002 0.040 -0.011 C 2.33938959521 3.68993217240 -0.00584554905 -0.025 0.058 -0.036 C 1.45736908622 4.77231118002 -0.00917967851 -0.035 0.059 0.002 C 0.08658913130 4.53522926787 -0.00833235387 -0.035 0.055 0.033 C -0.35359617412 3.21325694137 -0.00400174376 -0.015 0.047 -0.014 N 0.49290585413 2.18198449515 -0.00068475564 -0.008 0.050 -0.027 S 6.56718562933 -0.11349126889 0.00673479967 0.103 -0.007 0.011 C 1.82142022278 -2.39594383179 -0.00206827421 0.009 -0.043 -0.012 C 2.33969079820 -3.68709653410 -0.00625612120 -0.019 -0.064 -0.036 C 1.45789786198 -4.76953179608 -0.00945089783 -0.036 -0.059 0.003 C 0.08684213972 -4.53272927032 -0.00840538011 -0.034 -0.047 0.034 C -0.35393854068 -3.21111942258 -0.00398541364 -0.008 -0.037 -0.015 N 0.49225266031 -2.17934076887 -0.00084210065 0.006 -0.046 -0.027 H 1.83694111827 5.77332096953 -0.01265611066 -0.011 0.017 0.004 H -0.61802819388 5.33967450634 -0.01131742088 -0.013 0.014 0.022 H 3.39175422949 3.87200638269 -0.00704552340 -0.008 0.022 -0.017 H -1.39787683933 2.98334799634 -0.00369736757 -0.004 0.010 -0.010 H 1.83794742242 -5.77033326187 -0.01295832570 -0.013 -0.018 0.004 H -0.61749414542 -5.33746053721 -0.01121572048 -0.014 -0.011 0.022 H -1.39833026435 -2.98175334118 -0.00345676225 -0.001 -0.006 -0.010 H 3.39230213722 -3.86796714602 -0.00754158092 -0.006 -0.025 -0.017 H 4.58301895157 2.13678100538 0.00314824260 0.005 0.001 -0.021 H 4.58784714512 -2.12983634010 0.00211631073 0.007 -0.002 -0.019 H -1.68997263563 -0.00719388386 -5.74925805817 0.081 -0.000 -0.056 H 0.75224758084 -0.00860493512 -5.25016290812 0.058 0.000 0.055 H -3.29620044300 -0.00255800648 -3.88456579214 -0.015 -0.000 -0.125 H 1.47161249279 -0.00457826661 -2.87685200854 -0.053 0.000 0.086 H -1.69176120521 -0.00597000955 5.75026973076 -0.049 -0.000 -0.013 H 0.75025791005 -0.00892914887 5.25161119224 -0.024 -0.000 0.079 H 1.46975366817 -0.00523069331 2.87805400798 0.056 -0.000 0.099 H -3.29750276746 -0.00099200484 3.88584245085 0.031 0.000 -0.065 H -4.55513299541 0.00377930937 -2.13473279421 -0.064 0.000 0.024 H -4.55107479454 0.00501307822 2.13844314827 0.045 -0.001 0.026 H -6.83436893102 0.00806057203 1.19721860356 -0.085 0.000 -0.048 H 6.86748209639 1.20005966818 0.00372860376 0.017 -0.001 0.012 61 Mode 37: freq=323.84 N -0.44003451495 -0.00038510790 2.12369783068 -0.062 0.002 0.053 C -1.76594470239 0.00039861437 2.37754210613 -0.042 0.001 0.086 C -2.24923313135 -0.00145267054 3.67997125809 -0.016 0.001 0.109 C -1.33887502024 -0.00450793845 4.73956848945 0.018 -0.000 0.089 C 0.02462671625 -0.00591801736 4.46614405978 0.011 -0.001 0.043 C 0.43187566201 -0.00376957955 3.13352499014 -0.028 0.001 0.027 C -2.63984642995 0.00218980399 1.17162612704 -0.004 -0.001 0.052 N -1.98513620489 0.00132140951 0.00153900685 -0.061 -0.004 0.014 C -2.63911589169 0.00167522827 -1.17277445342 0.021 -0.001 -0.037 C -4.02452897564 0.00329996303 -1.20791476641 0.054 0.000 -0.028 C -4.73391255267 0.00451580118 -0.00020876193 0.133 0.000 0.005 C -4.02924140493 0.00399189729 1.20660077672 0.035 0.001 0.040 Co 0.00000000000 0.00000000000 0.00000000000 -0.683 0.006 -0.014 N -0.43839318333 -0.00054206762 -2.12229806799 0.001 0.002 -0.071 C -1.76408906064 -0.00030645034 -2.37697009192 0.006 0.001 -0.070 C -2.24773885821 -0.00257631963 -3.67934971086 0.012 0.001 -0.084 C -1.33713102227 -0.00526459193 -4.73855802198 0.016 -0.001 -0.089 C 0.02654101484 -0.00591797621 -4.46472703619 0.016 -0.001 -0.081 C 0.43371721952 -0.00363389350 -3.13225443930 0.008 0.001 -0.072 S -6.53329279136 0.00637481657 -0.11611178087 0.426 -0.001 0.030 N 2.00981687167 0.00259443239 -0.00000686048 -0.040 -0.008 0.002 C 2.67119656792 1.17263645248 0.00045766926 0.006 -0.028 0.001 C 4.06129317470 1.20536051565 0.00241240325 0.047 -0.033 -0.001 C 4.76783866331 0.00148799420 0.00346798881 0.133 -0.009 -0.000 C 4.05723810074 -1.20352939940 0.00211502115 0.056 0.016 -0.000 C 2.67108506586 -1.17139122066 0.00026591651 0.020 0.020 0.001 C 1.82209539371 2.39842937406 -0.00175320633 -0.030 -0.025 -0.001 C 2.33938959521 3.68993217240 -0.00584554905 -0.035 -0.024 -0.001 C 1.45736908622 4.77231118002 -0.00917967851 -0.019 -0.009 0.000 C 0.08658913130 4.53522926787 -0.00833235387 -0.023 0.020 0.000 C -0.35359617412 3.21325694137 -0.00400174376 -0.030 0.023 -0.001 N 0.49290585413 2.18198449515 -0.00068475564 -0.049 0.007 -0.001 S 6.56718562933 -0.11349126889 0.00673479967 0.435 -0.024 0.001 C 1.82142022278 -2.39594383179 -0.00206827421 -0.001 0.020 -0.001 C 2.33969079820 -3.68709653410 -0.00625612120 -0.015 0.015 -0.001 C 1.45789786198 -4.76953179608 -0.00945089783 -0.015 0.014 0.000 C 0.08684213972 -4.53272927032 -0.00840538011 -0.015 0.007 0.001 C -0.35393854068 -3.21111942258 -0.00398541364 -0.007 0.007 -0.001 N 0.49225266031 -2.17934076887 -0.00084210065 -0.011 0.010 -0.001 H 1.83694111827 5.77332096953 -0.01265611066 0.001 -0.005 0.000 H -0.61802819388 5.33967450634 -0.01131742088 -0.003 0.009 0.000 H 3.39175422949 3.87200638269 -0.00704552340 -0.010 -0.009 -0.000 H -1.39787683933 2.98334799634 -0.00369736757 -0.010 0.011 -0.000 H 1.83794742242 -5.77033326187 -0.01295832570 -0.003 0.005 0.000 H -0.61749414542 -5.33746053721 -0.01121572048 -0.004 0.002 0.000 H -1.39833026435 -2.98175334118 -0.00345676225 -0.002 0.002 -0.000 H 3.39230213722 -3.86796714602 -0.00754158092 -0.004 0.003 -0.000 H 4.58301895157 2.13678100538 0.00314824260 0.003 -0.003 -0.001 H 4.58784714512 -2.12983634010 0.00211631073 0.004 -0.003 -0.000 H -1.68997263563 -0.00719388386 -5.74925805817 0.005 -0.000 -0.026 H 0.75224758084 -0.00860493512 -5.25016290812 0.007 -0.001 -0.022 H -3.29620044300 -0.00255800648 -3.88456579214 0.004 0.001 -0.026 H 1.47161249279 -0.00457826661 -2.87685200854 0.002 0.001 -0.019 H -1.69176120521 -0.00597000955 5.75026973076 0.014 -0.000 0.029 H 0.75025791005 -0.00892914887 5.25161119224 0.011 -0.001 0.005 H 1.46975366817 -0.00523069331 2.87805400798 -0.011 0.000 -0.001 H -3.29750276746 -0.00099200484 3.88584245085 -0.003 0.000 0.041 H -4.55513299541 0.00377930937 -2.13473279421 0.001 0.001 0.000 H -4.55107479454 0.00501307822 2.13844314827 -0.004 0.001 0.003 H -6.83436893102 0.00806057203 1.19721860356 0.068 -0.000 0.003 H 6.86748209639 1.20005966818 0.00372860376 0.066 -0.001 0.001 61 Mode 38: freq=340.90 N -0.44003451495 -0.00038510790 2.12369783068 0.001 0.132 -0.001 C -1.76594470239 0.00039861437 2.37754210613 0.000 0.006 -0.001 C -2.24923313135 -0.00145267054 3.67997125809 0.000 0.147 -0.001 C -1.33887502024 -0.00450793845 4.73956848945 -0.001 0.026 -0.001 C 0.02462671625 -0.00591801736 4.46614405978 -0.001 -0.150 -0.001 C 0.43187566201 -0.00376957955 3.13352499014 0.000 0.062 -0.001 C -2.63984642995 0.00218980399 1.17162612704 0.000 -0.260 -0.001 N -1.98513620489 0.00132140951 0.00153900685 0.001 -0.658 0.000 C -2.63911589169 0.00167522827 -1.17277445342 -0.000 -0.261 0.001 C -4.02452897564 0.00329996303 -1.20791476641 -0.000 0.148 0.000 C -4.73391255267 0.00451580118 -0.00020876193 -0.001 0.152 -0.000 C -4.02924140493 0.00399189729 1.20660077672 0.000 0.155 -0.001 Co 0.00000000000 0.00000000000 0.00000000000 0.009 0.367 -0.002 N -0.43839318333 -0.00054206762 -2.12229806799 0.000 0.134 0.001 C -1.76408906064 -0.00030645034 -2.37697009192 0.000 0.006 0.001 C -2.24773885821 -0.00257631963 -3.67934971086 -0.000 0.150 0.002 C -1.33713102227 -0.00526459193 -4.73855802198 -0.001 0.025 0.002 C 0.02654101484 -0.00591797621 -4.46472703619 -0.001 -0.152 0.002 C 0.43371721952 -0.00363389350 -3.13225443930 -0.000 0.064 0.001 S -6.53329279136 0.00637481657 -0.11611178087 -0.005 -0.077 -0.000 N 2.00981687167 0.00259443239 -0.00000686048 -0.001 -0.011 0.002 C 2.67119656792 1.17263645248 0.00045766926 0.004 -0.023 0.001 C 4.06129317470 1.20536051565 0.00241240325 0.002 -0.026 -0.001 C 4.76783866331 0.00148799420 0.00346798881 -0.001 -0.028 -0.000 C 4.05723810074 -1.20352939940 0.00211502115 -0.004 -0.026 -0.000 C 2.67108506586 -1.17139122066 0.00026591651 -0.006 -0.023 0.001 C 1.82209539371 2.39842937406 -0.00175320633 -0.015 -0.034 -0.000 C 2.33938959521 3.68993217240 -0.00584554905 -0.009 -0.045 -0.001 C 1.45736908622 4.77231118002 -0.00917967851 0.001 -0.038 0.000 C 0.08658913130 4.53522926787 -0.00833235387 -0.002 -0.016 0.001 C -0.35359617412 3.21325694137 -0.00400174376 -0.018 -0.008 -0.000 N 0.49290585413 2.18198449515 -0.00068475564 -0.026 -0.012 -0.001 S 6.56718562933 -0.11349126889 0.00673479967 0.002 0.015 0.000 C 1.82142022278 -2.39594383179 -0.00206827421 0.013 -0.032 0.000 C 2.33969079820 -3.68709653410 -0.00625612120 0.009 -0.042 -0.000 C 1.45789786198 -4.76953179608 -0.00945089783 0.001 -0.037 -0.000 C 0.08684213972 -4.53272927032 -0.00840538011 0.004 -0.017 0.000 C -0.35393854068 -3.21111942258 -0.00398541364 0.016 -0.009 0.000 N 0.49225266031 -2.17934076887 -0.00084210065 0.023 -0.011 -0.000 H 1.83694111827 5.77332096953 -0.01265611066 0.004 -0.013 0.000 H -0.61802819388 5.33967450634 -0.01131742088 0.003 -0.001 0.000 H 3.39175422949 3.87200638269 -0.00704552340 -0.002 -0.016 -0.000 H -1.39787683933 2.98334799634 -0.00369736757 -0.006 0.001 -0.000 H 1.83794742242 -5.77033326187 -0.01295832570 -0.003 -0.012 -0.000 H -0.61749414542 -5.33746053721 -0.01121572048 -0.002 -0.002 0.000 H -1.39833026435 -2.98175334118 -0.00345676225 0.006 0.000 0.000 H 3.39230213722 -3.86796714602 -0.00754158092 0.002 -0.014 -0.000 H 4.58301895157 2.13678100538 0.00314824260 0.002 -0.009 -0.000 H 4.58784714512 -2.12983634010 0.00211631073 -0.003 -0.009 -0.000 H -1.68997263563 -0.00719388386 -5.74925805817 -0.000 0.004 0.001 H 0.75224758084 -0.00860493512 -5.25016290812 -0.000 -0.102 0.001 H -3.29620044300 -0.00255800648 -3.88456579214 -0.000 0.065 0.001 H 1.47161249279 -0.00457826661 -2.87685200854 0.000 0.041 0.000 H -1.69176120521 -0.00597000955 5.75026973076 -0.000 0.005 -0.000 H 0.75025791005 -0.00892914887 5.25161119224 -0.000 -0.101 -0.000 H 1.46975366817 -0.00523069331 2.87805400798 0.000 0.040 -0.000 H -3.29750276746 -0.00099200484 3.88584245085 -0.000 0.063 -0.000 H -4.55513299541 0.00377930937 -2.13473279421 0.000 0.125 -0.000 H -4.55107479454 0.00501307822 2.13844314827 0.000 0.135 -0.000 H -6.83436893102 0.00806057203 1.19721860356 -0.001 -0.066 0.000 H 6.86748209639 1.20005966818 0.00372860376 -0.011 0.005 0.000 61 Mode 39: freq=350.16 N -0.44003451495 -0.00038510790 2.12369783068 -0.029 -0.000 0.006 C -1.76594470239 0.00039861437 2.37754210613 -0.015 0.000 0.039 C -2.24923313135 -0.00145267054 3.67997125809 -0.013 -0.000 0.049 C -1.33887502024 -0.00450793845 4.73956848945 -0.007 -0.000 0.044 C 0.02462671625 -0.00591801736 4.46614405978 -0.012 0.000 0.016 C 0.43187566201 -0.00376957955 3.13352499014 -0.026 0.000 0.007 C -2.63984642995 0.00218980399 1.17162612704 0.004 0.001 0.034 N -1.98513620489 0.00132140951 0.00153900685 -0.001 0.002 0.022 C -2.63911589169 0.00167522827 -1.17277445342 -0.008 0.001 0.034 C -4.02452897564 0.00329996303 -1.20791476641 -0.006 -0.000 0.050 C -4.73391255267 0.00451580118 -0.00020876193 -0.003 -0.001 0.054 C -4.02924140493 0.00399189729 1.20660077672 0.001 -0.001 0.050 Co 0.00000000000 0.00000000000 0.00000000000 0.015 -0.001 -0.435 N -0.43839318333 -0.00054206762 -2.12229806799 0.024 -0.001 0.006 C -1.76408906064 -0.00030645034 -2.37697009192 0.011 -0.000 0.037 C -2.24773885821 -0.00257631963 -3.67934971086 0.012 -0.001 0.045 C -1.33713102227 -0.00526459193 -4.73855802198 0.010 0.000 0.043 C 0.02654101484 -0.00591797621 -4.46472703619 0.014 0.001 0.018 C 0.43371721952 -0.00363389350 -3.13225443930 0.024 -0.001 0.010 S -6.53329279136 0.00637481657 -0.11611178087 0.002 0.000 -0.024 N 2.00981687167 0.00259443239 -0.00000686048 0.001 0.000 0.630 C 2.67119656792 1.17263645248 0.00045766926 0.000 0.001 0.259 C 4.06129317470 1.20536051565 0.00241240325 0.000 0.001 -0.148 C 4.76783866331 0.00148799420 0.00346798881 -0.002 0.001 -0.155 C 4.05723810074 -1.20352939940 0.00211502115 0.000 -0.000 -0.142 C 2.67108506586 -1.17139122066 0.00026591651 0.000 -0.001 0.259 C 1.82209539371 2.39842937406 -0.00175320633 0.001 0.002 0.012 C 2.33938959521 3.68993217240 -0.00584554905 0.000 0.002 -0.134 C 1.45736908622 4.77231118002 -0.00917967851 -0.001 0.002 -0.035 C 0.08658913130 4.53522926787 -0.00833235387 -0.000 0.001 0.142 C -0.35359617412 3.21325694137 -0.00400174376 0.001 0.000 -0.056 N 0.49290585413 2.18198449515 -0.00068475564 0.001 0.001 -0.119 S 6.56718562933 -0.11349126889 0.00673479967 -0.008 0.000 0.074 C 1.82142022278 -2.39594383179 -0.00206827421 0.001 -0.001 0.011 C 2.33969079820 -3.68709653410 -0.00625612120 -0.000 -0.002 -0.136 C 1.45789786198 -4.76953179608 -0.00945089783 -0.001 -0.002 -0.034 C 0.08684213972 -4.53272927032 -0.00840538011 -0.001 -0.002 0.144 C -0.35393854068 -3.21111942258 -0.00398541364 -0.000 -0.001 -0.058 N 0.49225266031 -2.17934076887 -0.00084210065 0.001 -0.001 -0.120 H 1.83694111827 5.77332096953 -0.01265611066 -0.000 0.001 -0.013 H -0.61802819388 5.33967450634 -0.01131742088 -0.000 0.000 0.095 H 3.39175422949 3.87200638269 -0.00704552340 0.000 0.001 -0.059 H -1.39787683933 2.98334799634 -0.00369736757 0.000 -0.000 -0.038 H 1.83794742242 -5.77033326187 -0.01295832570 -0.000 -0.001 -0.012 H -0.61749414542 -5.33746053721 -0.01121572048 -0.000 -0.001 0.096 H -1.39833026435 -2.98175334118 -0.00345676225 0.000 0.000 -0.040 H 3.39230213722 -3.86796714602 -0.00754158092 -0.000 -0.001 -0.061 H 4.58301895157 2.13678100538 0.00314824260 0.000 0.000 -0.129 H 4.58784714512 -2.12983634010 0.00211631073 0.000 0.000 -0.119 H -1.68997263563 -0.00719388386 -5.74925805817 -0.000 0.000 0.014 H 0.75224758084 -0.00860493512 -5.25016290812 0.000 0.000 0.002 H -3.29620044300 -0.00255800648 -3.88456579214 0.003 -0.000 0.014 H 1.47161249279 -0.00457826661 -2.87685200854 0.008 -0.000 0.002 H -1.69176120521 -0.00597000955 5.75026973076 0.002 -0.000 0.014 H 0.75025791005 -0.00892914887 5.25161119224 0.001 0.000 0.001 H 1.46975366817 -0.00523069331 2.87805400798 -0.008 -0.000 0.001 H -3.29750276746 -0.00099200484 3.88584245085 -0.003 -0.000 0.016 H -4.55513299541 0.00377930937 -2.13473279421 -0.005 -0.000 0.016 H -4.55107479454 0.00501307822 2.13844314827 0.004 -0.000 0.016 H -6.83436893102 0.00806057203 1.19721860356 -0.020 0.000 -0.009 H 6.86748209639 1.20005966818 0.00372860376 -0.001 0.000 0.062 61 Mode 40: freq=372.59 N -0.44003451495 -0.00038510790 2.12369783068 -0.170 0.001 0.012 C -1.76594470239 0.00039861437 2.37754210613 -0.129 -0.000 0.085 C -2.24923313135 -0.00145267054 3.67997125809 -0.059 0.001 0.134 C -1.33887502024 -0.00450793845 4.73956848945 0.037 0.000 0.066 C 0.02462671625 -0.00591801736 4.46614405978 0.018 -0.001 -0.043 C 0.43187566201 -0.00376957955 3.13352499014 -0.087 0.001 -0.068 C -2.63984642995 0.00218980399 1.17162612704 -0.040 -0.002 0.032 N -1.98513620489 0.00132140951 0.00153900685 -0.038 -0.004 0.008 C -2.63911589169 0.00167522827 -1.17277445342 -0.037 -0.002 -0.021 C -4.02452897564 0.00329996303 -1.20791476641 -0.005 0.001 0.010 C -4.73391255267 0.00451580118 -0.00020876193 0.069 0.002 0.034 C -4.02924140493 0.00399189729 1.20660077672 -0.006 0.001 0.047 Co 0.00000000000 0.00000000000 0.00000000000 -0.044 0.006 0.009 N -0.43839318333 -0.00054206762 -2.12229806799 -0.148 0.001 -0.037 C -1.76408906064 -0.00030645034 -2.37697009192 -0.116 -0.000 -0.093 C -2.24773885821 -0.00257631963 -3.67934971086 -0.038 0.001 -0.148 C -1.33713102227 -0.00526459193 -4.73855802198 0.055 0.000 -0.088 C 0.02654101484 -0.00591797621 -4.46472703619 0.038 -0.001 0.009 C 0.43371721952 -0.00363389350 -3.13225443930 -0.069 0.001 0.037 S -6.53329279136 0.00637481657 -0.11611178087 0.350 -0.001 0.007 N 2.00981687167 0.00259443239 -0.00000686048 0.038 0.011 -0.006 C 2.67119656792 1.17263645248 0.00045766926 0.051 0.037 -0.003 C 4.06129317470 1.20536051565 0.00241240325 0.004 0.058 0.002 C 4.76783866331 0.00148799420 0.00346798881 -0.095 0.045 0.003 C 4.05723810074 -1.20352939940 0.00211502115 0.003 0.016 0.002 C 2.67108506586 -1.17139122066 0.00026591651 0.048 -0.023 -0.003 C 1.82209539371 2.39842937406 -0.00175320633 0.184 0.111 -0.001 C 2.33938959521 3.68993217240 -0.00584554905 0.090 0.181 0.001 C 1.45736908622 4.77231118002 -0.00917967851 -0.049 0.087 0.001 C 0.08658913130 4.53522926787 -0.00833235387 -0.027 -0.067 -0.002 C -0.35359617412 3.21325694137 -0.00400174376 0.120 -0.105 0.001 N 0.49290585413 2.18198449515 -0.00068475564 0.241 0.007 0.001 S 6.56718562933 -0.11349126889 0.00673479967 -0.479 0.009 -0.002 C 1.82142022278 -2.39594383179 -0.00206827421 0.171 -0.121 -0.001 C 2.33969079820 -3.68709653410 -0.00625612120 0.065 -0.201 0.001 C 1.45789786198 -4.76953179608 -0.00945089783 -0.073 -0.114 0.000 C 0.08684213972 -4.53272927032 -0.00840538011 -0.054 0.027 -0.002 C -0.35393854068 -3.21111942258 -0.00398541364 0.098 0.068 0.001 N 0.49225266031 -2.17934076887 -0.00084210065 0.217 -0.038 0.001 H 1.83694111827 5.77332096953 -0.01265611066 -0.050 0.039 0.000 H -0.61802819388 5.33967450634 -0.01131742088 -0.034 -0.043 -0.001 H 3.39175422949 3.87200638269 -0.00704552340 0.021 0.087 0.000 H -1.39787683933 2.98334799634 -0.00369736757 0.043 -0.065 0.001 H 1.83794742242 -5.77033326187 -0.01295832570 -0.054 -0.046 0.000 H -0.61749414542 -5.33746053721 -0.01121572048 -0.042 0.031 -0.001 H -1.39833026435 -2.98175334118 -0.00345676225 0.036 0.055 0.001 H 3.39230213722 -3.86796714602 -0.00754158092 0.014 -0.093 0.000 H 4.58301895157 2.13678100538 0.00314824260 0.007 0.013 0.002 H 4.58784714512 -2.12983634010 0.00211631073 0.016 0.013 0.001 H -1.68997263563 -0.00719388386 -5.74925805817 0.039 0.000 -0.034 H 0.75224758084 -0.00860493512 -5.25016290812 0.029 -0.001 0.019 H -3.29620044300 -0.00255800648 -3.88456579214 -0.007 0.000 -0.068 H 1.47161249279 -0.00457826661 -2.87685200854 -0.026 0.000 0.035 H -1.69176120521 -0.00597000955 5.75026973076 0.036 0.000 0.028 H 0.75025791005 -0.00892914887 5.25161119224 0.024 -0.001 -0.030 H 1.46975366817 -0.00523069331 2.87805400798 -0.032 0.000 -0.044 H -3.29750276746 -0.00099200484 3.88584245085 -0.013 0.000 0.064 H -4.55513299541 0.00377930937 -2.13473279421 -0.013 0.001 0.010 H -4.55107479454 0.00501307822 2.13844314827 -0.007 0.001 0.010 H -6.83436893102 0.00806057203 1.19721860356 0.040 -0.000 -0.005 H 6.86748209639 1.20005966818 0.00372860376 -0.055 -0.006 -0.002 61 Mode 41: freq=394.34 N -0.44003451495 -0.00038510790 2.12369783068 0.258 0.000 0.040 C -1.76594470239 0.00039861437 2.37754210613 0.190 -0.000 -0.066 C -2.24923313135 -0.00145267054 3.67997125809 0.109 0.001 -0.118 C -1.33887502024 -0.00450793845 4.73956848945 -0.031 -0.000 -0.005 C 0.02462671625 -0.00591801736 4.46614405978 -0.003 -0.001 0.150 C 0.43187566201 -0.00376957955 3.13352499014 0.139 0.001 0.172 C -2.63984642995 0.00218980399 1.17162612704 0.044 -0.002 -0.021 N -1.98513620489 0.00132140951 0.00153900685 -0.019 -0.003 -0.027 C -2.63911589169 0.00167522827 -1.17277445342 0.042 -0.002 -0.025 C -4.02452897564 0.00329996303 -1.20791476641 0.014 0.001 -0.100 C -4.73391255267 0.00451580118 -0.00020876193 -0.040 0.001 -0.111 C -4.02924140493 0.00399189729 1.20660077672 0.012 0.001 -0.095 Co 0.00000000000 0.00000000000 0.00000000000 -0.463 0.005 -0.018 N -0.43839318333 -0.00054206762 -2.12229806799 0.218 0.001 0.029 C -1.76408906064 -0.00030645034 -2.37697009192 0.174 0.000 0.088 C -2.24773885821 -0.00257631963 -3.67934971086 0.057 0.001 0.168 C -1.33713102227 -0.00526459193 -4.73855802198 -0.090 -0.000 0.070 C 0.02654101484 -0.00591797621 -4.46472703619 -0.068 -0.001 -0.061 C 0.43371721952 -0.00363389350 -3.13225443930 0.098 0.001 -0.095 S -6.53329279136 0.00637481657 -0.11611178087 -0.307 -0.000 0.016 N 2.00981687167 0.00259443239 -0.00000686048 -0.018 0.015 0.012 C 2.67119656792 1.17263645248 0.00045766926 0.025 0.009 0.006 C 4.06129317470 1.20536051565 0.00241240325 0.005 0.050 -0.003 C 4.76783866331 0.00148799420 0.00346798881 -0.029 0.060 -0.004 C 4.05723810074 -1.20352939940 0.00211502115 0.007 0.056 -0.003 C 2.67108506586 -1.17139122066 0.00026591651 0.025 0.016 0.006 C 1.82209539371 2.39842937406 -0.00175320633 0.128 0.045 0.001 C 2.33938959521 3.68993217240 -0.00584554905 0.071 0.086 -0.003 C 1.45736908622 4.77231118002 -0.00917967851 -0.024 0.014 -0.001 C 0.08658913130 4.53522926787 -0.00833235387 -0.010 -0.090 0.003 C -0.35359617412 3.21325694137 -0.00400174376 0.089 -0.109 -0.002 N 0.49290585413 2.18198449515 -0.00068475564 0.171 -0.023 -0.002 S 6.56718562933 -0.11349126889 0.00673479967 -0.206 -0.007 0.001 C 1.82142022278 -2.39594383179 -0.00206827421 0.121 -0.057 0.001 C 2.33969079820 -3.68709653410 -0.00625612120 0.045 -0.113 -0.003 C 1.45789786198 -4.76953179608 -0.00945089783 -0.057 -0.048 -0.001 C 0.08684213972 -4.53272927032 -0.00840538011 -0.045 0.044 0.003 C -0.35393854068 -3.21111942258 -0.00398541364 0.068 0.070 -0.002 N 0.49225266031 -2.17934076887 -0.00084210065 0.153 -0.014 -0.002 H 1.83694111827 5.77332096953 -0.01265611066 -0.033 0.014 -0.000 H -0.61802819388 5.33967450634 -0.01131742088 -0.020 -0.041 0.002 H 3.39175422949 3.87200638269 -0.00704552340 0.017 0.048 -0.001 H -1.39787683933 2.98334799634 -0.00369736757 0.031 -0.055 -0.001 H 1.83794742242 -5.77033326187 -0.01295832570 -0.040 -0.023 -0.000 H -0.61749414542 -5.33746053721 -0.01121572048 -0.031 0.028 0.002 H -1.39833026435 -2.98175334118 -0.00345676225 0.025 0.046 -0.001 H 3.39230213722 -3.86796714602 -0.00754158092 0.009 -0.059 -0.001 H 4.58301895157 2.13678100538 0.00314824260 -0.003 0.017 -0.003 H 4.58784714512 -2.12983634010 0.00211631073 0.008 0.019 -0.002 H -1.68997263563 -0.00719388386 -5.74925805817 -0.060 -0.000 0.032 H 0.75224758084 -0.00860493512 -5.25016290812 -0.045 -0.001 -0.041 H -3.29620044300 -0.00255800648 -3.88456579214 0.010 0.001 0.088 H 1.47161249279 -0.00457826661 -2.87685200854 0.038 0.000 -0.065 H -1.69176120521 -0.00597000955 5.75026973076 -0.048 -0.000 -0.015 H 0.75025791005 -0.00892914887 5.25161119224 -0.025 -0.001 0.066 H 1.46975366817 -0.00523069331 2.87805400798 0.049 0.000 0.084 H -3.29750276746 -0.00099200484 3.88584245085 0.025 0.001 -0.069 H -4.55513299541 0.00377930937 -2.13473279421 0.016 0.001 -0.035 H -4.55107479454 0.00501307822 2.13844314827 -0.004 0.001 -0.031 H -6.83436893102 0.00806057203 1.19721860356 -0.006 -0.000 0.015 H 6.86748209639 1.20005966818 0.00372860376 -0.009 -0.008 0.001 61 Mode 42: freq=403.32 N -0.44003451495 -0.00038510790 2.12369783068 0.014 0.000 -0.131 C -1.76594470239 0.00039861437 2.37754210613 0.038 0.000 -0.069 C -2.24923313135 -0.00145267054 3.67997125809 -0.068 0.000 -0.146 C -1.33887502024 -0.00450793845 4.73956848945 -0.134 0.000 -0.140 C 0.02462671625 -0.00591801736 4.46614405978 -0.134 0.000 -0.136 C 0.43187566201 -0.00376957955 3.13352499014 -0.034 0.000 -0.102 C -2.63984642995 0.00218980399 1.17162612704 0.002 -0.001 0.101 N -1.98513620489 0.00132140951 0.00153900685 -0.012 -0.001 0.112 C -2.63911589169 0.00167522827 -1.17277445342 0.005 -0.001 0.102 C -4.02452897564 0.00329996303 -1.20791476641 -0.018 0.001 0.395 C -4.73391255267 0.00451580118 -0.00020876193 -0.033 0.000 0.439 C -4.02924140493 0.00399189729 1.20660077672 -0.005 -0.000 0.397 Co 0.00000000000 0.00000000000 0.00000000000 -0.080 0.002 0.054 N -0.43839318333 -0.00054206762 -2.12229806799 0.140 -0.000 -0.134 C -1.76408906064 -0.00030645034 -2.37697009192 0.076 -0.000 -0.013 C -2.24773885821 -0.00257631963 -3.67934971086 0.128 0.001 -0.051 C -1.33713102227 -0.00526459193 -4.73855802198 0.103 -0.001 -0.111 C 0.02654101484 -0.00591797621 -4.46472703619 0.120 -0.001 -0.202 C 0.43371721952 -0.00363389350 -3.13225443930 0.113 0.000 -0.186 S -6.53329279136 0.00637481657 -0.11611178087 -0.086 -0.000 -0.117 N 2.00981687167 0.00259443239 -0.00000686048 -0.003 0.011 -0.027 C 2.67119656792 1.17263645248 0.00045766926 0.003 0.008 -0.015 C 4.06129317470 1.20536051565 0.00241240325 0.001 0.038 0.008 C 4.76783866331 0.00148799420 0.00346798881 -0.001 0.044 0.011 C 4.05723810074 -1.20352939940 0.00211502115 0.002 0.040 0.007 C 2.67108506586 -1.17139122066 0.00026591651 0.003 0.012 -0.015 C 1.82209539371 2.39842937406 -0.00175320633 0.016 -0.000 -0.004 C 2.33938959521 3.68993217240 -0.00584554905 0.016 -0.001 0.007 C 1.45736908622 4.77231118002 -0.00917967851 0.007 -0.011 0.002 C 0.08658913130 4.53522926787 -0.00833235387 0.009 -0.026 -0.007 C -0.35359617412 3.21325694137 -0.00400174376 0.016 -0.026 0.006 N 0.49290585413 2.18198449515 -0.00068475564 0.025 -0.015 0.005 S 6.56718562933 -0.11349126889 0.00673479967 -0.021 -0.010 -0.004 C 1.82142022278 -2.39594383179 -0.00206827421 0.014 -0.008 -0.004 C 2.33969079820 -3.68709653410 -0.00625612120 -0.002 -0.020 0.007 C 1.45789786198 -4.76953179608 -0.00945089783 -0.017 -0.013 0.002 C 0.08684213972 -4.53272927032 -0.00840538011 -0.016 -0.006 -0.007 C -0.35393854068 -3.21111942258 -0.00398541364 0.002 -0.001 0.006 N 0.49225266031 -2.17934076887 -0.00084210065 0.014 -0.012 0.005 H 1.83694111827 5.77332096953 -0.01265611066 -0.002 -0.002 0.001 H -0.61802819388 5.33967450634 -0.01131742088 0.001 -0.009 -0.005 H 3.39175422949 3.87200638269 -0.00704552340 0.004 0.002 0.003 H -1.39787683933 2.98334799634 -0.00369736757 0.005 -0.009 0.003 H 1.83794742242 -5.77033326187 -0.01295832570 -0.007 -0.005 0.001 H -0.61749414542 -5.33746053721 -0.01121572048 -0.007 0.000 -0.005 H -1.39833026435 -2.98175334118 -0.00345676225 0.002 0.004 0.003 H 3.39230213722 -3.86796714602 -0.00754158092 -0.001 -0.010 0.003 H 4.58301895157 2.13678100538 0.00314824260 -0.003 0.013 0.006 H 4.58784714512 -2.12983634010 0.00211631073 0.004 0.013 0.006 H -1.68997263563 -0.00719388386 -5.74925805817 0.008 -0.000 -0.025 H 0.75224758084 -0.00860493512 -5.25016290812 0.029 -0.000 -0.065 H -3.29620044300 -0.00255800648 -3.88456579214 0.035 0.000 -0.014 H 1.47161249279 -0.00457826661 -2.87685200854 0.034 0.000 -0.056 H -1.69176120521 -0.00597000955 5.75026973076 -0.040 0.000 -0.042 H 0.75025791005 -0.00892914887 5.25161119224 -0.049 0.000 -0.031 H 1.46975366817 -0.00523069331 2.87805400798 -0.005 0.000 -0.009 H -3.29750276746 -0.00099200484 3.88584245085 -0.022 0.000 -0.064 H -4.55513299541 0.00377930937 -2.13473279421 -0.042 0.001 0.134 H -4.55107479454 0.00501307822 2.13844314827 0.035 0.000 0.135 H -6.83436893102 0.00806057203 1.19721860356 -0.164 0.000 -0.054 H 6.86748209639 1.20005966818 0.00372860376 0.012 -0.005 -0.003 61 Mode 43: freq=405.04 N -0.44003451495 -0.00038510790 2.12369783068 0.019 -0.002 -0.008 C -1.76594470239 0.00039861437 2.37754210613 0.016 -0.000 -0.009 C -2.24923313135 -0.00145267054 3.67997125809 0.002 -0.004 -0.020 C -1.33887502024 -0.00450793845 4.73956848945 -0.014 0.002 -0.011 C 0.02462671625 -0.00591801736 4.46614405978 -0.012 0.001 -0.000 C 0.43187566201 -0.00376957955 3.13352499014 0.007 -0.005 0.004 C -2.63984642995 0.00218980399 1.17162612704 0.003 0.003 0.008 N -1.98513620489 0.00132140951 0.00153900685 -0.004 0.006 0.008 C -2.63911589169 0.00167522827 -1.17277445342 0.003 0.003 0.006 C -4.02452897564 0.00329996303 -1.20791476641 -0.001 -0.002 0.027 C -4.73391255267 0.00451580118 -0.00020876193 -0.005 -0.003 0.031 C -4.02924140493 0.00399189729 1.20660077672 0.000 -0.002 0.029 Co 0.00000000000 0.00000000000 0.00000000000 -0.049 -0.021 0.003 N -0.43839318333 -0.00054206762 -2.12229806799 0.028 -0.002 -0.010 C -1.76408906064 -0.00030645034 -2.37697009192 0.019 -0.000 0.004 C -2.24773885821 -0.00257631963 -3.67934971086 0.016 -0.004 0.006 C -1.33713102227 -0.00526459193 -4.73855802198 0.003 0.002 -0.007 C 0.02654101484 -0.00591797621 -4.46472703619 0.006 0.001 -0.024 C 0.43371721952 -0.00363389350 -3.13225443930 0.017 -0.005 -0.024 S -6.53329279136 0.00637481657 -0.11611178087 -0.025 0.001 -0.009 N 2.00981687167 0.00259443239 -0.00000686048 -0.012 -0.119 -0.001 C 2.67119656792 1.17263645248 0.00045766926 -0.000 -0.107 -0.001 C 4.06129317470 1.20536051565 0.00241240325 -0.007 -0.408 0.001 C 4.76783866331 0.00148799420 0.00346798881 -0.029 -0.453 0.001 C 4.05723810074 -1.20352939940 0.00211502115 -0.021 -0.406 -0.001 C 2.67108506586 -1.17139122066 0.00026591651 -0.004 -0.107 -0.001 C 1.82209539371 2.39842937406 -0.00175320633 0.028 0.062 -0.000 C 2.33938959521 3.68993217240 -0.00584554905 -0.072 0.138 0.000 C 1.45736908622 4.77231118002 -0.00917967851 -0.133 0.139 -0.000 C 0.08658913130 4.53522926787 -0.00833235387 -0.136 0.146 -0.001 C -0.35359617412 3.21325694137 -0.00400174376 -0.044 0.111 0.000 N 0.49290585413 2.18198449515 -0.00068475564 0.000 0.136 -0.000 S 6.56718562933 -0.11349126889 0.00673479967 -0.053 0.117 -0.000 C 1.82142022278 -2.39594383179 -0.00206827421 0.049 0.022 -0.000 C 2.33969079820 -3.68709653410 -0.00625612120 0.116 0.071 0.000 C 1.45789786198 -4.76953179608 -0.00945089783 0.116 0.114 0.001 C 0.08684213972 -4.53272927032 -0.00840538011 0.128 0.188 0.000 C -0.35393854068 -3.21111942258 -0.00398541364 0.097 0.167 0.000 N 0.49225266031 -2.17934076887 -0.00084210065 0.105 0.138 0.001 H 1.83694111827 5.77332096953 -0.01265611066 -0.038 0.041 -0.000 H -0.61802819388 5.33967450634 -0.01131742088 -0.048 0.035 -0.000 H 3.39175422949 3.87200638269 -0.00704552340 -0.022 0.059 0.000 H -1.39787683933 2.98334799634 -0.00369736757 -0.009 0.013 0.000 H 1.83794742242 -5.77033326187 -0.01295832570 0.017 0.027 0.000 H -0.61749414542 -5.33746053721 -0.01121572048 0.034 0.057 -0.000 H -1.39833026435 -2.98175334118 -0.00345676225 0.028 0.044 0.000 H 3.39230213722 -3.86796714602 -0.00754158092 0.032 0.025 0.000 H 4.58301895157 2.13678100538 0.00314824260 0.034 -0.137 0.001 H 4.58784714512 -2.12983634010 0.00211631073 -0.043 -0.137 -0.000 H -1.68997263563 -0.00719388386 -5.74925805817 -0.004 0.002 -0.000 H 0.75224758084 -0.00860493512 -5.25016290812 -0.000 0.002 -0.009 H -3.29620044300 -0.00255800648 -3.88456579214 0.004 -0.002 0.004 H 1.47161249279 -0.00457826661 -2.87685200854 0.006 -0.002 -0.010 H -1.69176120521 -0.00597000955 5.75026973076 -0.007 0.002 -0.004 H 0.75025791005 -0.00892914887 5.25161119224 -0.006 0.002 0.002 H 1.46975366817 -0.00523069331 2.87805400798 0.003 -0.002 0.005 H -3.29750276746 -0.00099200484 3.88584245085 -0.000 -0.002 -0.010 H -4.55513299541 0.00377930937 -2.13473279421 -0.003 -0.001 0.009 H -4.55107479454 0.00501307822 2.13844314827 0.003 -0.002 0.010 H -6.83436893102 0.00806057203 1.19721860356 -0.014 0.001 -0.004 H 6.86748209639 1.20005966818 0.00372860376 -0.165 0.055 -0.000 61 Mode 44: freq=473.28 N -0.44003451495 -0.00038510790 2.12369783068 -0.000 -0.229 -0.000 C -1.76594470239 0.00039861437 2.37754210613 -0.000 -0.051 -0.000 C -2.24923313135 -0.00145267054 3.67997125809 0.000 0.198 0.000 C -1.33887502024 -0.00450793845 4.73956848945 -0.000 -0.185 -0.000 C 0.02462671625 -0.00591801736 4.46614405978 0.000 0.028 -0.000 C 0.43187566201 -0.00376957955 3.13352499014 0.000 0.171 0.000 C -2.63984642995 0.00218980399 1.17162612704 -0.000 -0.015 -0.000 N -1.98513620489 0.00132140951 0.00153900685 -0.000 -0.000 -0.000 C -2.63911589169 0.00167522827 -1.17277445342 -0.000 0.015 -0.000 C -4.02452897564 0.00329996303 -1.20791476641 -0.000 -0.031 0.000 C -4.73391255267 0.00451580118 -0.00020876193 -0.000 -0.001 0.000 C -4.02924140493 0.00399189729 1.20660077672 0.000 0.032 0.000 Co 0.00000000000 0.00000000000 0.00000000000 0.000 0.000 -0.000 N -0.43839318333 -0.00054206762 -2.12229806799 0.000 0.228 -0.000 C -1.76408906064 -0.00030645034 -2.37697009192 0.000 0.050 -0.000 C -2.24773885821 -0.00257631963 -3.67934971086 -0.000 -0.197 0.000 C -1.33713102227 -0.00526459193 -4.73855802198 0.000 0.184 -0.000 C 0.02654101484 -0.00591797621 -4.46472703619 -0.000 -0.028 -0.000 C 0.43371721952 -0.00363389350 -3.13225443930 -0.000 -0.170 0.000 S -6.53329279136 0.00637481657 -0.11611178087 0.000 -0.000 -0.000 N 2.00981687167 0.00259443239 -0.00000686048 -0.000 0.000 0.000 C 2.67119656792 1.17263645248 0.00045766926 0.000 0.000 0.016 C 4.06129317470 1.20536051565 0.00241240325 0.000 -0.000 -0.037 C 4.76783866331 0.00148799420 0.00346798881 0.000 -0.000 0.000 C 4.05723810074 -1.20352939940 0.00211502115 -0.000 -0.000 0.036 C 2.67108506586 -1.17139122066 0.00026591651 -0.000 0.000 -0.016 C 1.82209539371 2.39842937406 -0.00175320633 -0.000 0.000 0.057 C 2.33938959521 3.68993217240 -0.00584554905 -0.000 -0.001 -0.228 C 1.45736908622 4.77231118002 -0.00917967851 -0.000 0.001 0.219 C 0.08658913130 4.53522926787 -0.00833235387 -0.000 0.000 -0.036 C -0.35359617412 3.21325694137 -0.00400174376 -0.000 -0.001 -0.199 N 0.49290585413 2.18198449515 -0.00068475564 -0.000 0.001 0.270 S 6.56718562933 -0.11349126889 0.00673479967 0.000 0.000 0.000 C 1.82142022278 -2.39594383179 -0.00206827421 0.000 0.000 -0.055 C 2.33969079820 -3.68709653410 -0.00625612120 0.000 -0.001 0.226 C 1.45789786198 -4.76953179608 -0.00945089783 -0.000 0.001 -0.217 C 0.08684213972 -4.53272927032 -0.00840538011 0.000 0.000 0.036 C -0.35393854068 -3.21111942258 -0.00398541364 0.000 -0.001 0.196 N 0.49225266031 -2.17934076887 -0.00084210065 0.000 0.001 -0.266 H 1.83694111827 5.77332096953 -0.01265611066 0.000 0.001 0.141 H -0.61802819388 5.33967450634 -0.01131742088 0.000 -0.000 -0.030 H 3.39175422949 3.87200638269 -0.00704552340 -0.000 -0.001 -0.172 H -1.39787683933 2.98334799634 -0.00369736757 0.000 -0.000 -0.150 H 1.83794742242 -5.77033326187 -0.01295832570 -0.000 0.000 -0.140 H -0.61749414542 -5.33746053721 -0.01121572048 -0.000 -0.000 0.030 H -1.39833026435 -2.98175334118 -0.00345676225 0.000 -0.000 0.148 H 3.39230213722 -3.86796714602 -0.00754158092 0.000 -0.001 0.169 H 4.58301895157 2.13678100538 0.00314824260 0.000 -0.000 -0.013 H 4.58784714512 -2.12983634010 0.00211631073 -0.000 -0.000 0.012 H -1.68997263563 -0.00719388386 -5.74925805817 0.000 0.119 -0.000 H 0.75224758084 -0.00860493512 -5.25016290812 -0.000 -0.024 -0.000 H -3.29620044300 -0.00255800648 -3.88456579214 -0.000 -0.147 0.000 H 1.47161249279 -0.00457826661 -2.87685200854 -0.000 -0.129 0.000 H -1.69176120521 -0.00597000955 5.75026973076 -0.000 -0.119 -0.000 H 0.75025791005 -0.00892914887 5.25161119224 0.000 0.024 0.000 H 1.46975366817 -0.00523069331 2.87805400798 0.000 0.130 0.000 H -3.29750276746 -0.00099200484 3.88584245085 0.000 0.148 0.000 H -4.55513299541 0.00377930937 -2.13473279421 -0.000 -0.011 0.000 H -4.55107479454 0.00501307822 2.13844314827 0.000 0.012 0.000 H -6.83436893102 0.00806057203 1.19721860356 -0.000 -0.000 -0.000 H 6.86748209639 1.20005966818 0.00372860376 -0.000 0.000 0.000 61 Mode 45: freq=481.40 N -0.44003451495 -0.00038510790 2.12369783068 -0.004 0.003 0.003 C -1.76594470239 0.00039861437 2.37754210613 0.001 0.001 -0.000 C -2.24923313135 -0.00145267054 3.67997125809 -0.001 -0.002 0.000 C -1.33887502024 -0.00450793845 4.73956848945 0.002 0.002 -0.002 C 0.02462671625 -0.00591801736 4.46614405978 0.001 -0.000 -0.004 C 0.43187566201 -0.00376957955 3.13352499014 -0.001 -0.002 -0.004 C -2.63984642995 0.00218980399 1.17162612704 0.007 0.000 -0.003 N -1.98513620489 0.00132140951 0.00153900685 -0.000 0.000 -0.006 C -2.63911589169 0.00167522827 -1.17277445342 -0.008 -0.000 -0.003 C -4.02452897564 0.00329996303 -1.20791476641 -0.006 0.001 -0.000 C -4.73391255267 0.00451580118 -0.00020876193 -0.000 0.000 0.006 C -4.02924140493 0.00399189729 1.20660077672 0.005 -0.001 -0.000 Co 0.00000000000 0.00000000000 0.00000000000 0.000 0.000 -0.042 N -0.43839318333 -0.00054206762 -2.12229806799 0.004 -0.003 0.003 C -1.76408906064 -0.00030645034 -2.37697009192 -0.001 -0.001 0.000 C -2.24773885821 -0.00257631963 -3.67934971086 0.001 0.003 0.000 C -1.33713102227 -0.00526459193 -4.73855802198 -0.002 -0.002 -0.002 C 0.02654101484 -0.00591797621 -4.46472703619 -0.001 0.000 -0.004 C 0.43371721952 -0.00363389350 -3.13225443930 0.002 0.002 -0.004 S -6.53329279136 0.00637481657 -0.11611178087 0.000 -0.000 -0.002 N 2.00981687167 0.00259443239 -0.00000686048 0.000 -0.000 -0.080 C 2.67119656792 1.17263645248 0.00045766926 -0.000 0.000 0.016 C 4.06129317470 1.20536051565 0.00241240325 0.000 0.000 -0.002 C 4.76783866331 0.00148799420 0.00346798881 0.000 -0.000 -0.097 C 4.05723810074 -1.20352939940 0.00211502115 0.000 -0.000 -0.000 C 2.67108506586 -1.17139122066 0.00026591651 0.000 -0.000 0.018 C 1.82209539371 2.39842937406 -0.00175320633 -0.000 0.000 0.105 C 2.33938959521 3.68993217240 -0.00584554905 -0.000 -0.001 -0.290 C 1.45736908622 4.77231118002 -0.00917967851 -0.000 0.001 0.275 C 0.08658913130 4.53522926787 -0.00833235387 -0.000 -0.000 -0.050 C -0.35359617412 3.21325694137 -0.00400174376 -0.000 -0.001 -0.243 N 0.49290585413 2.18198449515 -0.00068475564 -0.000 0.001 0.370 S 6.56718562933 -0.11349126889 0.00673479967 -0.000 0.000 0.014 C 1.82142022278 -2.39594383179 -0.00206827421 -0.000 -0.000 0.105 C 2.33969079820 -3.68709653410 -0.00625612120 -0.000 0.001 -0.290 C 1.45789786198 -4.76953179608 -0.00945089783 0.000 -0.001 0.274 C 0.08684213972 -4.53272927032 -0.00840538011 -0.000 0.000 -0.050 C -0.35393854068 -3.21111942258 -0.00398541364 -0.000 0.001 -0.242 N 0.49225266031 -2.17934076887 -0.00084210065 0.000 -0.001 0.368 H 1.83694111827 5.77332096953 -0.01265611066 0.000 0.001 0.171 H -0.61802819388 5.33967450634 -0.01131742088 0.000 -0.000 -0.045 H 3.39175422949 3.87200638269 -0.00704552340 -0.000 -0.001 -0.230 H -1.39787683933 2.98334799634 -0.00369736757 0.000 -0.001 -0.193 H 1.83794742242 -5.77033326187 -0.01295832570 0.000 -0.001 0.171 H -0.61749414542 -5.33746053721 -0.01121572048 0.000 0.000 -0.045 H -1.39833026435 -2.98175334118 -0.00345676225 -0.000 0.001 -0.192 H 3.39230213722 -3.86796714602 -0.00754158092 -0.000 0.001 -0.229 H 4.58301895157 2.13678100538 0.00314824260 -0.000 0.000 0.042 H 4.58784714512 -2.12983634010 0.00211631073 -0.000 -0.000 0.043 H -1.68997263563 -0.00719388386 -5.74925805817 -0.001 -0.001 -0.000 H 0.75224758084 -0.00860493512 -5.25016290812 -0.001 0.000 -0.001 H -3.29620044300 -0.00255800648 -3.88456579214 0.000 0.002 0.001 H 1.47161249279 -0.00457826661 -2.87685200854 0.001 0.002 -0.002 H -1.69176120521 -0.00597000955 5.75026973076 0.001 0.001 -0.000 H 0.75025791005 -0.00892914887 5.25161119224 0.001 -0.000 -0.001 H 1.46975366817 -0.00523069331 2.87805400798 -0.001 -0.002 -0.002 H -3.29750276746 -0.00099200484 3.88584245085 -0.000 -0.002 0.001 H -4.55513299541 0.00377930937 -2.13473279421 -0.004 0.000 0.001 H -4.55107479454 0.00501307822 2.13844314827 0.003 -0.000 0.001 H -6.83436893102 0.00806057203 1.19721860356 -0.003 -0.000 -0.001 H 6.86748209639 1.20005966818 0.00372860376 0.000 0.000 0.011 61 Mode 46: freq=486.06 N -0.44003451495 -0.00038510790 2.12369783068 -0.001 -0.378 -0.001 C -1.76594470239 0.00039861437 2.37754210613 -0.000 -0.126 -0.000 C -2.24923313135 -0.00145267054 3.67997125809 0.000 0.292 0.001 C -1.33887502024 -0.00450793845 4.73956848945 -0.000 -0.265 -0.001 C 0.02462671625 -0.00591801736 4.46614405978 0.000 0.045 -0.000 C 0.43187566201 -0.00376957955 3.13352499014 0.000 0.239 0.000 C -2.63984642995 0.00218980399 1.17162612704 -0.000 -0.019 -0.000 N -1.98513620489 0.00132140951 0.00153900685 -0.000 0.090 0.000 C -2.63911589169 0.00167522827 -1.17277445342 -0.000 -0.019 0.000 C -4.02452897564 0.00329996303 -1.20791476641 -0.000 -0.001 0.000 C -4.73391255267 0.00451580118 -0.00020876193 0.000 0.104 -0.000 C -4.02924140493 0.00399189729 1.20660077672 -0.000 0.002 0.000 Co 0.00000000000 0.00000000000 0.00000000000 0.001 0.054 -0.000 N -0.43839318333 -0.00054206762 -2.12229806799 -0.000 -0.370 0.001 C -1.76408906064 -0.00030645034 -2.37697009192 -0.000 -0.122 0.000 C -2.24773885821 -0.00257631963 -3.67934971086 0.000 0.287 -0.001 C -1.33713102227 -0.00526459193 -4.73855802198 -0.000 -0.260 0.001 C 0.02654101484 -0.00591797621 -4.46472703619 0.000 0.044 -0.000 C 0.43371721952 -0.00363389350 -3.13225443930 0.000 0.233 -0.000 S -6.53329279136 0.00637481657 -0.11611178087 0.000 -0.015 0.000 N 2.00981687167 0.00259443239 -0.00000686048 -0.000 0.007 0.000 C 2.67119656792 1.17263645248 0.00045766926 0.008 0.004 -0.001 C 4.06129317470 1.20536051565 0.00241240325 0.006 -0.001 0.001 C 4.76783866331 0.00148799420 0.00346798881 -0.000 -0.008 -0.000 C 4.05723810074 -1.20352939940 0.00211502115 -0.007 -0.000 -0.001 C 2.67108506586 -1.17139122066 0.00026591651 -0.009 0.004 0.001 C 1.82209539371 2.39842937406 -0.00175320633 0.001 0.000 -0.002 C 2.33938959521 3.68993217240 -0.00584554905 -0.001 -0.000 0.003 C 1.45736908622 4.77231118002 -0.00917967851 0.002 0.003 -0.003 C 0.08658913130 4.53522926787 -0.00833235387 0.002 0.004 0.000 C -0.35359617412 3.21325694137 -0.00400174376 -0.001 0.005 0.003 N 0.49290585413 2.18198449515 -0.00068475564 -0.005 -0.003 -0.004 S 6.56718562933 -0.11349126889 0.00673479967 0.000 0.003 -0.000 C 1.82142022278 -2.39594383179 -0.00206827421 -0.001 0.000 0.002 C 2.33969079820 -3.68709653410 -0.00625612120 0.002 -0.000 -0.003 C 1.45789786198 -4.76953179608 -0.00945089783 -0.002 0.003 0.003 C 0.08684213972 -4.53272927032 -0.00840538011 -0.002 0.005 -0.000 C -0.35393854068 -3.21111942258 -0.00398541364 0.002 0.005 -0.003 N 0.49225266031 -2.17934076887 -0.00084210065 0.005 -0.003 0.004 H 1.83694111827 5.77332096953 -0.01265611066 0.001 0.001 -0.002 H -0.61802819388 5.33967450634 -0.01131742088 0.001 0.001 0.000 H 3.39175422949 3.87200638269 -0.00704552340 -0.000 -0.001 0.003 H -1.39787683933 2.98334799634 -0.00369736757 -0.001 0.002 0.002 H 1.83794742242 -5.77033326187 -0.01295832570 -0.001 0.001 0.002 H -0.61749414542 -5.33746053721 -0.01121572048 -0.001 0.002 -0.000 H -1.39833026435 -2.98175334118 -0.00345676225 0.001 0.003 -0.002 H 3.39230213722 -3.86796714602 -0.00754158092 0.000 -0.001 -0.003 H 4.58301895157 2.13678100538 0.00314824260 0.004 -0.001 0.000 H 4.58784714512 -2.12983634010 0.00211631073 -0.004 -0.001 -0.000 H -1.68997263563 -0.00719388386 -5.74925805817 -0.000 -0.161 0.000 H 0.75224758084 -0.00860493512 -5.25016290812 0.000 0.044 -0.000 H -3.29620044300 -0.00255800648 -3.88456579214 0.000 0.230 -0.000 H 1.47161249279 -0.00457826661 -2.87685200854 0.000 0.192 -0.000 H -1.69176120521 -0.00597000955 5.75026973076 -0.000 -0.164 -0.000 H 0.75025791005 -0.00892914887 5.25161119224 0.000 0.045 0.000 H 1.46975366817 -0.00523069331 2.87805400798 0.000 0.196 0.000 H -3.29750276746 -0.00099200484 3.88584245085 0.000 0.235 0.000 H -4.55513299541 0.00377930937 -2.13473279421 -0.000 -0.046 0.000 H -4.55107479454 0.00501307822 2.13844314827 -0.000 -0.044 0.000 H -6.83436893102 0.00806057203 1.19721860356 0.000 -0.012 0.000 H 6.86748209639 1.20005966818 0.00372860376 -0.004 0.001 0.000 61 Mode 47: freq=488.64 N -0.44003451495 -0.00038510790 2.12369783068 0.000 0.259 0.000 C -1.76594470239 0.00039861437 2.37754210613 0.000 0.130 0.000 C -2.24923313135 -0.00145267054 3.67997125809 -0.000 -0.224 -0.000 C -1.33887502024 -0.00450793845 4.73956848945 0.000 0.167 0.001 C 0.02462671625 -0.00591801736 4.46614405978 -0.000 0.005 0.000 C 0.43187566201 -0.00376957955 3.13352499014 -0.000 -0.192 -0.000 C -2.63984642995 0.00218980399 1.17162612704 0.000 0.067 0.000 N -1.98513620489 0.00132140951 0.00153900685 0.000 0.002 0.000 C -2.63911589169 0.00167522827 -1.17277445342 0.000 -0.068 0.000 C -4.02452897564 0.00329996303 -1.20791476641 0.000 0.069 -0.000 C -4.73391255267 0.00451580118 -0.00020876193 0.000 0.003 -0.000 C -4.02924140493 0.00399189729 1.20660077672 -0.000 -0.071 -0.000 Co 0.00000000000 0.00000000000 0.00000000000 0.000 0.000 -0.000 N -0.43839318333 -0.00054206762 -2.12229806799 -0.000 -0.270 0.001 C -1.76408906064 -0.00030645034 -2.37697009192 -0.000 -0.133 0.000 C -2.24773885821 -0.00257631963 -3.67934971086 0.000 0.233 -0.001 C -1.33713102227 -0.00526459193 -4.73855802198 -0.000 -0.175 0.000 C 0.02654101484 -0.00591797621 -4.46472703619 0.000 -0.004 0.000 C 0.43371721952 -0.00363389350 -3.13225443930 0.000 0.199 -0.000 S -6.53329279136 0.00637481657 -0.11611178087 -0.000 0.001 0.000 N 2.00981687167 0.00259443239 -0.00000686048 0.000 0.000 0.001 C 2.67119656792 1.17263645248 0.00045766926 0.000 0.000 0.057 C 4.06129317470 1.20536051565 0.00241240325 0.000 -0.000 -0.061 C 4.76783866331 0.00148799420 0.00346798881 -0.000 -0.001 0.002 C 4.05723810074 -1.20352939940 0.00211502115 -0.000 -0.000 0.060 C 2.67108506586 -1.17139122066 0.00026591651 -0.000 0.000 -0.058 C 1.82209539371 2.39842937406 -0.00175320633 -0.000 0.000 0.111 C 2.33938959521 3.68993217240 -0.00584554905 -0.000 -0.001 -0.193 C 1.45736908622 4.77231118002 -0.00917967851 0.000 0.001 0.147 C 0.08658913130 4.53522926787 -0.00833235387 0.000 0.000 0.002 C -0.35359617412 3.21325694137 -0.00400174376 -0.000 -0.000 -0.166 N 0.49290585413 2.18198449515 -0.00068475564 -0.000 0.001 0.226 S 6.56718562933 -0.11349126889 0.00673479967 0.000 0.000 0.001 C 1.82142022278 -2.39594383179 -0.00206827421 0.000 0.000 -0.112 C 2.33969079820 -3.68709653410 -0.00625612120 0.000 -0.001 0.197 C 1.45789786198 -4.76953179608 -0.00945089783 -0.000 0.001 -0.151 C 0.08684213972 -4.53272927032 -0.00840538011 -0.000 0.000 -0.001 C -0.35393854068 -3.21111942258 -0.00398541364 0.000 -0.000 0.169 N 0.49225266031 -2.17934076887 -0.00084210065 0.000 0.001 -0.231 H 1.83694111827 5.77332096953 -0.01265611066 0.000 0.000 0.088 H -0.61802819388 5.33967450634 -0.01131742088 0.000 0.000 -0.010 H 3.39175422949 3.87200638269 -0.00704552340 -0.000 -0.001 -0.154 H -1.39787683933 2.98334799634 -0.00369736757 -0.000 -0.000 -0.137 H 1.83794742242 -5.77033326187 -0.01295832570 -0.000 0.000 -0.091 H -0.61749414542 -5.33746053721 -0.01121572048 -0.000 0.000 0.011 H -1.39833026435 -2.98175334118 -0.00345676225 0.000 -0.000 0.140 H 3.39230213722 -3.86796714602 -0.00754158092 0.000 -0.001 0.156 H 4.58301895157 2.13678100538 0.00314824260 0.000 -0.000 -0.033 H 4.58784714512 -2.12983634010 0.00211631073 -0.000 -0.000 0.031 H -1.68997263563 -0.00719388386 -5.74925805817 -0.000 -0.106 0.000 H 0.75224758084 -0.00860493512 -5.25016290812 0.000 0.012 0.000 H -3.29620044300 -0.00255800648 -3.88456579214 0.000 0.184 -0.000 H 1.47161249279 -0.00457826661 -2.87685200854 0.000 0.165 -0.000 H -1.69176120521 -0.00597000955 5.75026973076 0.000 0.101 0.000 H 0.75025791005 -0.00892914887 5.25161119224 -0.000 -0.010 0.000 H 1.46975366817 -0.00523069331 2.87805400798 -0.000 -0.160 -0.000 H -3.29750276746 -0.00099200484 3.88584245085 -0.000 -0.177 -0.000 H -4.55513299541 0.00377930937 -2.13473279421 0.000 0.036 -0.000 H -4.55107479454 0.00501307822 2.13844314827 -0.000 -0.039 -0.000 H -6.83436893102 0.00806057203 1.19721860356 0.000 -0.006 0.000 H 6.86748209639 1.20005966818 0.00372860376 -0.000 0.000 -0.005 61 Mode 48: freq=518.55 N -0.44003451495 -0.00038510790 2.12369783068 0.000 0.022 -0.000 C -1.76594470239 0.00039861437 2.37754210613 0.000 0.055 0.000 C -2.24923313135 -0.00145267054 3.67997125809 -0.000 -0.029 -0.000 C -1.33887502024 -0.00450793845 4.73956848945 -0.000 -0.001 -0.000 C 0.02462671625 -0.00591801736 4.46614405978 0.000 0.029 0.000 C 0.43187566201 -0.00376957955 3.13352499014 -0.000 -0.040 -0.000 C -2.63984642995 0.00218980399 1.17162612704 -0.000 0.037 0.000 N -1.98513620489 0.00132140951 0.00153900685 -0.000 0.000 0.000 C -2.63911589169 0.00167522827 -1.17277445342 0.000 -0.037 0.000 C -4.02452897564 0.00329996303 -1.20791476641 0.000 0.025 -0.000 C -4.73391255267 0.00451580118 -0.00020876193 0.000 0.001 -0.000 C -4.02924140493 0.00399189729 1.20660077672 -0.000 -0.025 -0.000 Co 0.00000000000 0.00000000000 0.00000000000 -0.000 0.000 0.001 N -0.43839318333 -0.00054206762 -2.12229806799 -0.000 -0.022 -0.000 C -1.76408906064 -0.00030645034 -2.37697009192 -0.000 -0.056 0.000 C -2.24773885821 -0.00257631963 -3.67934971086 0.000 0.030 -0.000 C -1.33713102227 -0.00526459193 -4.73855802198 0.000 0.001 -0.000 C 0.02654101484 -0.00591797621 -4.46472703619 -0.000 -0.030 -0.000 C 0.43371721952 -0.00363389350 -3.13225443930 -0.000 0.041 -0.000 S -6.53329279136 0.00637481657 -0.11611178087 0.000 0.000 0.000 N 2.00981687167 0.00259443239 -0.00000686048 0.000 -0.002 -0.003 C 2.67119656792 1.17263645248 0.00045766926 -0.000 -0.001 -0.254 C 4.06129317470 1.20536051565 0.00241240325 -0.001 0.001 0.155 C 4.76783866331 0.00148799420 0.00346798881 0.000 0.001 -0.004 C 4.05723810074 -1.20352939940 0.00211502115 0.002 0.000 -0.154 C 2.67108506586 -1.17139122066 0.00026591651 0.001 -0.001 0.257 C 1.82209539371 2.39842937406 -0.00175320633 0.000 -0.001 -0.328 C 2.33938959521 3.68993217240 -0.00584554905 0.000 0.000 0.012 C 1.45736908622 4.77231118002 -0.00917967851 -0.000 0.001 0.222 C 0.08658913130 4.53522926787 -0.00833235387 -0.000 -0.001 -0.298 C -0.35359617412 3.21325694137 -0.00400174376 0.000 0.001 0.168 N 0.49290585413 2.18198449515 -0.00068475564 0.000 0.001 0.137 S 6.56718562933 -0.11349126889 0.00673479967 -0.000 -0.000 -0.004 C 1.82142022278 -2.39594383179 -0.00206827421 -0.000 -0.001 0.332 C 2.33969079820 -3.68709653410 -0.00625612120 -0.000 0.001 -0.011 C 1.45789786198 -4.76953179608 -0.00945089783 0.000 0.001 -0.225 C 0.08684213972 -4.53272927032 -0.00840538011 0.000 -0.001 0.302 C -0.35393854068 -3.21111942258 -0.00398541364 -0.001 0.000 -0.170 N 0.49225266031 -2.17934076887 -0.00084210065 -0.001 0.001 -0.140 H 1.83694111827 5.77332096953 -0.01265611066 -0.000 0.001 0.177 H -0.61802819388 5.33967450634 -0.01131742088 -0.000 -0.001 -0.167 H 3.39175422949 3.87200638269 -0.00704552340 0.000 0.000 0.049 H -1.39787683933 2.98334799634 -0.00369736757 0.000 0.000 0.158 H 1.83794742242 -5.77033326187 -0.01295832570 0.000 0.001 -0.180 H -0.61749414542 -5.33746053721 -0.01121572048 0.000 -0.001 0.169 H -1.39833026435 -2.98175334118 -0.00345676225 -0.000 0.000 -0.160 H 3.39230213722 -3.86796714602 -0.00754158092 -0.000 0.001 -0.050 H 4.58301895157 2.13678100538 0.00314824260 -0.001 0.000 0.124 H 4.58784714512 -2.12983634010 0.00211631073 0.001 0.000 -0.119 H -1.68997263563 -0.00719388386 -5.74925805817 0.000 0.006 -0.000 H 0.75224758084 -0.00860493512 -5.25016290812 0.000 -0.014 0.000 H -3.29620044300 -0.00255800648 -3.88456579214 0.000 0.029 -0.000 H 1.47161249279 -0.00457826661 -2.87685200854 0.000 0.035 -0.000 H -1.69176120521 -0.00597000955 5.75026973076 -0.000 -0.006 -0.000 H 0.75025791005 -0.00892914887 5.25161119224 -0.000 0.014 0.000 H 1.46975366817 -0.00523069331 2.87805400798 -0.000 -0.034 -0.000 H -3.29750276746 -0.00099200484 3.88584245085 -0.000 -0.029 -0.000 H -4.55513299541 0.00377930937 -2.13473279421 0.000 0.017 -0.000 H -4.55107479454 0.00501307822 2.13844314827 -0.000 -0.018 -0.000 H -6.83436893102 0.00806057203 1.19721860356 0.000 -0.003 0.000 H 6.86748209639 1.20005966818 0.00372860376 0.001 -0.000 0.022 61 Mode 49: freq=519.38 N -0.44003451495 -0.00038510790 2.12369783068 0.000 -0.164 -0.000 C -1.76594470239 0.00039861437 2.37754210613 0.000 0.314 0.000 C -2.24923313135 -0.00145267054 3.67997125809 0.000 0.007 -0.000 C -1.33887502024 -0.00450793845 4.73956848945 -0.000 -0.236 -0.001 C 0.02462671625 -0.00591801736 4.46614405978 0.000 0.302 0.001 C 0.43187566201 -0.00376957955 3.13352499014 0.000 -0.157 -0.000 C -2.63984642995 0.00218980399 1.17162612704 0.000 0.251 0.001 N -1.98513620489 0.00132140951 0.00153900685 0.000 0.003 0.001 C -2.63911589169 0.00167522827 -1.17277445342 0.000 -0.254 0.001 C -4.02452897564 0.00329996303 -1.20791476641 0.001 0.151 -0.000 C -4.73391255267 0.00451580118 -0.00020876193 0.000 0.004 -0.001 C -4.02924140493 0.00399189729 1.20660077672 -0.001 -0.152 -0.000 Co 0.00000000000 0.00000000000 0.00000000000 -0.000 -0.001 -0.000 N -0.43839318333 -0.00054206762 -2.12229806799 -0.000 0.167 -0.000 C -1.76408906064 -0.00030645034 -2.37697009192 -0.000 -0.317 0.000 C -2.24773885821 -0.00257631963 -3.67934971086 -0.000 -0.008 -0.000 C -1.33713102227 -0.00526459193 -4.73855802198 0.000 0.239 -0.001 C 0.02654101484 -0.00591797621 -4.46472703619 -0.000 -0.306 0.001 C 0.43371721952 -0.00363389350 -3.13225443930 -0.000 0.158 -0.000 S -6.53329279136 0.00637481657 -0.11611178087 -0.000 0.004 0.000 N 2.00981687167 0.00259443239 -0.00000686048 -0.000 -0.000 0.000 C 2.67119656792 1.17263645248 0.00045766926 -0.000 -0.000 0.021 C 4.06129317470 1.20536051565 0.00241240325 -0.000 -0.000 -0.010 C 4.76783866331 0.00148799420 0.00346798881 -0.000 0.000 0.000 C 4.05723810074 -1.20352939940 0.00211502115 0.000 0.000 0.010 C 2.67108506586 -1.17139122066 0.00026591651 0.000 -0.000 -0.021 C 1.82209539371 2.39842937406 -0.00175320633 0.000 0.000 0.018 C 2.33938959521 3.68993217240 -0.00584554905 0.000 0.000 0.028 C 1.45736908622 4.77231118002 -0.00917967851 -0.000 -0.000 -0.051 C 0.08658913130 4.53522926787 -0.00833235387 -0.000 0.000 0.039 C -0.35359617412 3.21325694137 -0.00400174376 0.000 0.000 0.002 N 0.49290585413 2.18198449515 -0.00068475564 0.000 -0.000 -0.056 S 6.56718562933 -0.11349126889 0.00673479967 0.000 -0.000 0.000 C 1.82142022278 -2.39594383179 -0.00206827421 0.000 0.000 -0.018 C 2.33969079820 -3.68709653410 -0.00625612120 -0.000 0.000 -0.028 C 1.45789786198 -4.76953179608 -0.00945089783 0.000 -0.000 0.051 C 0.08684213972 -4.53272927032 -0.00840538011 0.000 0.000 -0.040 C -0.35393854068 -3.21111942258 -0.00398541364 0.000 0.000 -0.002 N 0.49225266031 -2.17934076887 -0.00084210065 0.000 -0.000 0.057 H 1.83694111827 5.77332096953 -0.01265611066 -0.000 -0.000 -0.035 H -0.61802819388 5.33967450634 -0.01131742088 -0.000 0.000 0.025 H 3.39175422949 3.87200638269 -0.00704552340 0.000 0.000 0.019 H -1.39787683933 2.98334799634 -0.00369736757 0.000 -0.000 -0.000 H 1.83794742242 -5.77033326187 -0.01295832570 0.000 -0.000 0.036 H -0.61749414542 -5.33746053721 -0.01121572048 0.000 0.000 -0.025 H -1.39833026435 -2.98175334118 -0.00345676225 0.000 -0.000 0.000 H 3.39230213722 -3.86796714602 -0.00754158092 -0.000 0.000 -0.019 H 4.58301895157 2.13678100538 0.00314824260 -0.000 0.000 -0.010 H 4.58784714512 -2.12983634010 0.00211631073 0.000 0.000 0.010 H -1.68997263563 -0.00719388386 -5.74925805817 0.000 0.187 -0.000 H 0.75224758084 -0.00860493512 -5.25016290812 -0.000 -0.173 0.000 H -3.29620044300 -0.00255800648 -3.88456579214 0.000 0.032 -0.000 H 1.47161249279 -0.00457826661 -2.87685200854 0.000 0.147 -0.000 H -1.69176120521 -0.00597000955 5.75026973076 -0.000 -0.184 -0.000 H 0.75025791005 -0.00892914887 5.25161119224 0.000 0.171 0.000 H 1.46975366817 -0.00523069331 2.87805400798 -0.000 -0.146 -0.000 H -3.29750276746 -0.00099200484 3.88584245085 -0.000 -0.032 -0.000 H -4.55513299541 0.00377930937 -2.13473279421 0.000 0.118 -0.000 H -4.55107479454 0.00501307822 2.13844314827 -0.000 -0.123 -0.000 H -6.83436893102 0.00806057203 1.19721860356 0.000 -0.022 0.000 H 6.86748209639 1.20005966818 0.00372860376 0.000 -0.000 -0.002 61 Mode 50: freq=541.38 N -0.44003451495 -0.00038510790 2.12369783068 -0.069 -0.001 0.007 C -1.76594470239 0.00039861437 2.37754210613 -0.037 0.005 0.036 C -2.24923313135 -0.00145267054 3.67997125809 -0.058 0.000 0.039 C -1.33887502024 -0.00450793845 4.73956848945 -0.003 -0.003 -0.009 C 0.02462671625 -0.00591801736 4.46614405978 -0.008 0.004 -0.062 C 0.43187566201 -0.00376957955 3.13352499014 -0.029 -0.003 -0.055 C -2.63984642995 0.00218980399 1.17162612704 0.131 0.002 -0.039 N -1.98513620489 0.00132140951 0.00153900685 0.221 -0.004 0.007 C -2.63911589169 0.00167522827 -1.17277445342 0.135 0.002 0.053 C -4.02452897564 0.00329996303 -1.20791476641 0.142 0.000 0.071 C -4.73391255267 0.00451580118 -0.00020876193 0.036 -0.005 0.004 C -4.02924140493 0.00399189729 1.20660077672 0.139 -0.000 -0.053 Co 0.00000000000 0.00000000000 0.00000000000 0.045 -0.000 -0.001 N -0.43839318333 -0.00054206762 -2.12229806799 -0.076 -0.001 -0.013 C -1.76408906064 -0.00030645034 -2.37697009192 -0.043 0.005 -0.036 C -2.24773885821 -0.00257631963 -3.67934971086 -0.057 0.000 -0.045 C -1.33713102227 -0.00526459193 -4.73855802198 0.003 -0.003 0.003 C 0.02654101484 -0.00591797621 -4.46472703619 -0.002 0.004 0.056 C 0.43371721952 -0.00363389350 -3.13225443930 -0.031 -0.003 0.052 S -6.53329279136 0.00637481657 -0.11611178087 -0.182 0.001 -0.011 N 2.00981687167 0.00259443239 -0.00000686048 -0.410 0.015 0.002 C 2.67119656792 1.17263645248 0.00045766926 -0.244 -0.065 0.000 C 4.06129317470 1.20536051565 0.00241240325 -0.257 -0.097 -0.001 C 4.76783866331 0.00148799420 0.00346798881 -0.068 0.007 0.000 C 4.05723810074 -1.20352939940 0.00211502115 -0.266 0.131 -0.001 C 2.67108506586 -1.17139122066 0.00026591651 -0.253 0.093 0.001 C 1.82209539371 2.39842937406 -0.00175320633 0.070 0.074 -0.001 C 2.33938959521 3.68993217240 -0.00584554905 0.104 0.088 -0.001 C 1.45736908622 4.77231118002 -0.00917967851 0.010 0.014 0.001 C 0.08658913130 4.53522926787 -0.00833235387 0.019 -0.097 -0.001 C -0.35359617412 3.21325694137 -0.00400174376 0.058 -0.092 0.001 N 0.49290585413 2.18198449515 -0.00068475564 0.124 0.002 0.001 S 6.56718562933 -0.11349126889 0.00673479967 0.342 -0.020 0.001 C 1.82142022278 -2.39594383179 -0.00206827421 0.082 -0.075 -0.000 C 2.33969079820 -3.68709653410 -0.00625612120 0.103 -0.101 -0.001 C 1.45789786198 -4.76953179608 -0.00945089783 -0.002 -0.025 0.000 C 0.08684213972 -4.53272927032 -0.00840538011 0.007 0.086 -0.000 C -0.35393854068 -3.21111942258 -0.00398541364 0.062 0.086 0.000 N 0.49225266031 -2.17934076887 -0.00084210065 0.137 -0.014 0.000 H 1.83694111827 5.77332096953 -0.01265611066 -0.029 0.016 0.001 H -0.61802819388 5.33967450634 -0.01131742088 -0.006 -0.039 -0.000 H 3.39175422949 3.87200638269 -0.00704552340 0.028 0.041 -0.000 H -1.39787683933 2.98334799634 -0.00369736757 0.021 -0.043 0.001 H 1.83794742242 -5.77033326187 -0.01295832570 -0.033 -0.020 0.000 H -0.61749414542 -5.33746053721 -0.01121572048 -0.011 0.037 -0.000 H -1.39833026435 -2.98175334118 -0.00345676225 0.023 0.045 0.000 H 3.39230213722 -3.86796714602 -0.00754158092 0.027 -0.049 -0.000 H 4.58301895157 2.13678100538 0.00314824260 -0.115 -0.007 -0.001 H 4.58784714512 -2.12983634010 0.00211631073 -0.121 0.015 -0.001 H -1.68997263563 -0.00719388386 -5.74925805817 0.019 -0.003 -0.005 H 0.75224758084 -0.00860493512 -5.25016290812 0.005 0.002 0.022 H -3.29620044300 -0.00255800648 -3.88456579214 -0.014 -0.001 -0.025 H 1.47161249279 -0.00457826661 -2.87685200854 -0.012 -0.003 0.027 H -1.69176120521 -0.00597000955 5.75026973076 0.017 -0.003 0.004 H 0.75025791005 -0.00892914887 5.25161119224 0.002 0.002 -0.023 H 1.46975366817 -0.00523069331 2.87805400798 -0.011 -0.003 -0.026 H -3.29750276746 -0.00099200484 3.88584245085 -0.015 -0.001 0.021 H -4.55513299541 0.00377930937 -2.13473279421 0.065 0.001 0.008 H -4.55107479454 0.00501307822 2.13844314827 0.062 0.001 -0.004 H -6.83436893102 0.00806057203 1.19721860356 -0.017 0.001 0.003 H 6.86748209639 1.20005966818 0.00372860376 0.032 0.005 0.000 61 Mode 51: freq=550.50 N -0.44003451495 -0.00038510790 2.12369783068 0.004 0.002 -0.006 C -1.76594470239 0.00039861437 2.37754210613 -0.001 -0.007 -0.002 C -2.24923313135 -0.00145267054 3.67997125809 -0.002 -0.001 -0.008 C -1.33887502024 -0.00450793845 4.73956848945 -0.003 0.005 -0.009 C 0.02462671625 -0.00591801736 4.46614405978 -0.004 -0.006 -0.009 C 0.43187566201 -0.00376957955 3.13352499014 0.001 0.004 -0.006 C -2.63984642995 0.00218980399 1.17162612704 -0.011 -0.002 0.013 N -1.98513620489 0.00132140951 0.00153900685 0.010 0.007 0.029 C -2.63911589169 0.00167522827 -1.17277445342 0.025 -0.001 0.017 C -4.02452897564 0.00329996303 -1.20791476641 0.028 -0.001 0.002 C -4.73391255267 0.00451580118 -0.00020876193 0.003 0.006 -0.014 C -4.02924140493 0.00399189729 1.20660077672 -0.013 -0.000 -0.004 Co 0.00000000000 0.00000000000 0.00000000000 -0.007 -0.001 0.066 N -0.43839318333 -0.00054206762 -2.12229806799 -0.010 0.002 -0.007 C -1.76408906064 -0.00030645034 -2.37697009192 -0.003 -0.007 -0.006 C -2.24773885821 -0.00257631963 -3.67934971086 -0.003 -0.001 -0.013 C -1.33713102227 -0.00526459193 -4.73855802198 0.003 0.005 -0.010 C 0.02654101484 -0.00591797621 -4.46472703619 0.003 -0.006 -0.003 C 0.43371721952 -0.00363389350 -3.13225443930 -0.004 0.004 -0.001 S -6.53329279136 0.00637481657 -0.11611178087 -0.010 -0.001 0.005 N 2.00981687167 0.00259443239 -0.00000686048 0.004 -0.001 -0.320 C 2.67119656792 1.17263645248 0.00045766926 0.003 0.000 0.067 C 4.06129317470 1.20536051565 0.00241240325 0.003 0.001 0.026 C 4.76783866331 0.00148799420 0.00346798881 0.002 0.000 -0.300 C 4.05723810074 -1.20352939940 0.00211502115 0.004 -0.001 0.031 C 2.67108506586 -1.17139122066 0.00026591651 0.004 -0.002 0.064 C 1.82209539371 2.39842937406 -0.00175320633 -0.000 0.000 0.349 C 2.33938959521 3.68993217240 -0.00584554905 -0.001 -0.000 0.044 C 1.45736908622 4.77231118002 -0.00917967851 -0.000 -0.000 -0.220 C 0.08658913130 4.53522926787 -0.00833235387 -0.000 0.002 0.286 C -0.35359617412 3.21325694137 -0.00400174376 -0.000 0.000 -0.178 N 0.49290585413 2.18198449515 -0.00068475564 -0.001 -0.000 -0.084 S 6.56718562933 -0.11349126889 0.00673479967 -0.004 0.000 0.038 C 1.82142022278 -2.39594383179 -0.00206827421 -0.000 -0.000 0.343 C 2.33969079820 -3.68709653410 -0.00625612120 -0.001 0.001 0.043 C 1.45789786198 -4.76953179608 -0.00945089783 -0.000 0.001 -0.216 C 0.08684213972 -4.53272927032 -0.00840538011 -0.000 -0.002 0.281 C -0.35393854068 -3.21111942258 -0.00398541364 -0.001 -0.000 -0.175 N 0.49225266031 -2.17934076887 -0.00084210065 -0.001 0.001 -0.083 H 1.83694111827 5.77332096953 -0.01265611066 0.000 -0.001 -0.198 H -0.61802819388 5.33967450634 -0.01131742088 -0.000 0.001 0.142 H 3.39175422949 3.87200638269 -0.00704552340 -0.000 -0.000 -0.056 H -1.39787683933 2.98334799634 -0.00369736757 -0.000 -0.000 -0.178 H 1.83794742242 -5.77033326187 -0.01295832570 0.000 0.001 -0.195 H -0.61749414542 -5.33746053721 -0.01121572048 0.000 -0.001 0.140 H -1.39833026435 -2.98175334118 -0.00345676225 -0.000 0.000 -0.175 H 3.39230213722 -3.86796714602 -0.00754158092 -0.000 0.001 -0.056 H 4.58301895157 2.13678100538 0.00314824260 0.001 0.000 0.109 H 4.58784714512 -2.12983634010 0.00211631073 0.002 -0.000 0.115 H -1.68997263563 -0.00719388386 -5.74925805817 0.002 0.004 -0.003 H 0.75224758084 -0.00860493512 -5.25016290812 0.002 -0.003 0.000 H -3.29620044300 -0.00255800648 -3.88456579214 -0.001 0.001 -0.006 H 1.47161249279 -0.00457826661 -2.87685200854 -0.002 0.004 0.003 H -1.69176120521 -0.00597000955 5.75026973076 -0.001 0.004 -0.003 H 0.75025791005 -0.00892914887 5.25161119224 -0.002 -0.003 -0.002 H 1.46975366817 -0.00523069331 2.87805400798 0.001 0.004 0.001 H -3.29750276746 -0.00099200484 3.88584245085 -0.001 0.001 -0.004 H -4.55513299541 0.00377930937 -2.13473279421 0.015 -0.002 -0.003 H -4.55107479454 0.00501307822 2.13844314827 -0.008 -0.002 -0.003 H -6.83436893102 0.00806057203 1.19721860356 0.008 -0.001 0.003 H 6.86748209639 1.20005966818 0.00372860376 0.000 -0.000 0.034 61 Mode 52: freq=550.82 N -0.44003451495 -0.00038510790 2.12369783068 -0.003 0.098 0.000 C -1.76594470239 0.00039861437 2.37754210613 -0.001 -0.341 0.001 C -2.24923313135 -0.00145267054 3.67997125809 -0.002 -0.050 0.002 C -1.33887502024 -0.00450793845 4.73956848945 0.000 0.227 0.000 C 0.02462671625 -0.00591801736 4.46614405978 -0.001 -0.292 -0.003 C 0.43187566201 -0.00376957955 3.13352499014 -0.001 0.177 -0.002 C -2.63984642995 0.00218980399 1.17162612704 0.006 -0.070 -0.002 N -1.98513620489 0.00132140951 0.00153900685 0.009 0.309 -0.000 C -2.63911589169 0.00167522827 -1.17277445342 0.005 -0.067 0.002 C -4.02452897564 0.00329996303 -1.20791476641 0.006 -0.029 0.003 C -4.73391255267 0.00451580118 -0.00020876193 0.002 0.296 0.000 C -4.02924140493 0.00399189729 1.20660077672 0.006 -0.024 -0.002 Co 0.00000000000 0.00000000000 0.00000000000 -0.003 -0.065 -0.001 N -0.43839318333 -0.00054206762 -2.12229806799 -0.003 0.097 -0.000 C -1.76408906064 -0.00030645034 -2.37697009192 -0.002 -0.336 -0.001 C -2.24773885821 -0.00257631963 -3.67934971086 -0.002 -0.048 -0.002 C -1.33713102227 -0.00526459193 -4.73855802198 0.000 0.223 -0.000 C 0.02654101484 -0.00591797621 -4.46472703619 -0.001 -0.287 0.003 C 0.43371721952 -0.00363389350 -3.13225443930 -0.001 0.175 0.002 S -6.53329279136 0.00637481657 -0.11611178087 -0.008 -0.038 -0.001 N 2.00981687167 0.00259443239 -0.00000686048 -0.004 -0.030 0.007 C 2.67119656792 1.17263645248 0.00045766926 -0.020 -0.016 -0.001 C 4.06129317470 1.20536051565 0.00241240325 -0.024 0.002 -0.001 C 4.76783866331 0.00148799420 0.00346798881 -0.000 0.017 0.006 C 4.05723810074 -1.20352939940 0.00211502115 0.019 0.005 -0.001 C 2.67108506586 -1.17139122066 0.00026591651 0.016 -0.014 -0.002 C 1.82209539371 2.39842937406 -0.00175320633 0.003 0.004 -0.007 C 2.33938959521 3.68993217240 -0.00584554905 0.004 0.010 -0.001 C 1.45736908622 4.77231118002 -0.00917967851 -0.003 0.007 0.005 C 0.08658913130 4.53522926787 -0.00833235387 -0.004 0.003 -0.006 C -0.35359617412 3.21325694137 -0.00400174376 0.002 0.001 0.004 N 0.49290585413 2.18198449515 -0.00068475564 0.010 0.008 0.002 S 6.56718562933 -0.11349126889 0.00673479967 0.002 -0.007 -0.001 C 1.82142022278 -2.39594383179 -0.00206827421 -0.002 0.002 -0.008 C 2.33969079820 -3.68709653410 -0.00625612120 -0.002 0.008 -0.001 C 1.45789786198 -4.76953179608 -0.00945089783 0.003 0.006 0.005 C 0.08684213972 -4.53272927032 -0.00840538011 0.004 0.005 -0.006 C -0.35393854068 -3.21111942258 -0.00398541364 -0.001 0.003 0.004 N 0.49225266031 -2.17934076887 -0.00084210065 -0.008 0.008 0.002 H 1.83694111827 5.77332096953 -0.01265611066 -0.002 0.002 0.004 H -0.61802819388 5.33967450634 -0.01131742088 -0.002 0.000 -0.003 H 3.39175422949 3.87200638269 -0.00704552340 0.001 0.006 0.001 H -1.39787683933 2.98334799634 -0.00369736757 0.002 -0.003 0.004 H 1.83794742242 -5.77033326187 -0.01295832570 0.001 0.002 0.004 H -0.61749414542 -5.33746053721 -0.01121572048 0.002 0.001 -0.003 H -1.39833026435 -2.98175334118 -0.00345676225 -0.001 -0.002 0.004 H 3.39230213722 -3.86796714602 -0.00754158092 -0.000 0.005 0.001 H 4.58301895157 2.13678100538 0.00314824260 -0.013 0.004 -0.002 H 4.58784714512 -2.12983634010 0.00211631073 0.011 0.004 -0.002 H -1.68997263563 -0.00719388386 -5.74925805817 0.001 0.198 -0.001 H 0.75224758084 -0.00860493512 -5.25016290812 -0.000 -0.145 0.001 H -3.29620044300 -0.00255800648 -3.88456579214 -0.001 0.047 -0.001 H 1.47161249279 -0.00457826661 -2.87685200854 -0.000 0.172 0.001 H -1.69176120521 -0.00597000955 5.75026973076 0.001 0.201 0.001 H 0.75025791005 -0.00892914887 5.25161119224 -0.000 -0.147 -0.001 H 1.46975366817 -0.00523069331 2.87805400798 -0.000 0.175 -0.001 H -3.29750276746 -0.00099200484 3.88584245085 -0.001 0.047 0.001 H -4.55513299541 0.00377930937 -2.13473279421 0.002 -0.110 0.000 H -4.55107479454 0.00501307822 2.13844314827 0.003 -0.104 -0.000 H -6.83436893102 0.00806057203 1.19721860356 -0.001 -0.034 0.000 H 6.86748209639 1.20005966818 0.00372860376 0.010 -0.003 -0.001 61 Mode 53: freq=557.41 N -0.44003451495 -0.00038510790 2.12369783068 0.104 0.002 -0.006 C -1.76594470239 0.00039861437 2.37754210613 0.048 -0.005 -0.077 C -2.24923313135 -0.00145267054 3.67997125809 0.100 -0.001 -0.081 C -1.33887502024 -0.00450793845 4.73956848945 0.017 0.004 -0.009 C 0.02462671625 -0.00591801736 4.46614405978 0.027 -0.005 0.096 C 0.43187566201 -0.00376957955 3.13352499014 0.045 0.002 0.086 C -2.63984642995 0.00218980399 1.17162612704 -0.249 -0.000 0.057 N -1.98513620489 0.00132140951 0.00153900685 -0.379 0.005 -0.015 C -2.63911589169 0.00167522827 -1.17277445342 -0.259 -0.000 -0.087 C -4.02452897564 0.00329996303 -1.20791476641 -0.278 -0.000 -0.124 C -4.73391255267 0.00451580118 -0.00020876193 -0.087 0.004 -0.005 C -4.02924140493 0.00399189729 1.20660077672 -0.269 -0.000 0.092 Co 0.00000000000 0.00000000000 0.00000000000 0.248 -0.002 0.003 N -0.43839318333 -0.00054206762 -2.12229806799 0.118 0.002 0.018 C -1.76408906064 -0.00030645034 -2.37697009192 0.062 -0.005 0.077 C -2.24773885821 -0.00257631963 -3.67934971086 0.100 -0.001 0.094 C -1.33713102227 -0.00526459193 -4.73855802198 0.005 0.004 0.019 C 0.02654101484 -0.00591797621 -4.46472703619 0.015 -0.005 -0.086 C 0.43371721952 -0.00363389350 -3.13225443930 0.051 0.002 -0.080 S -6.53329279136 0.00637481657 -0.11611178087 0.335 -0.001 0.020 N 2.00981687167 0.00259443239 -0.00000686048 -0.198 0.009 -0.010 C 2.67119656792 1.17263645248 0.00045766926 -0.132 -0.028 0.001 C 4.06129317470 1.20536051565 0.00241240325 -0.142 -0.048 0.001 C 4.76783866331 0.00148799420 0.00346798881 -0.046 0.002 -0.008 C 4.05723810074 -1.20352939940 0.00211502115 -0.148 0.065 0.001 C 2.67108506586 -1.17139122066 0.00026591651 -0.138 0.045 0.001 C 1.82209539371 2.39842937406 -0.00175320633 0.024 0.039 0.009 C 2.33938959521 3.68993217240 -0.00584554905 0.053 0.039 0.002 C 1.45736908622 4.77231118002 -0.00917967851 0.010 0.002 -0.006 C 0.08658913130 4.53522926787 -0.00833235387 0.013 -0.050 0.008 C -0.35359617412 3.21325694137 -0.00400174376 0.019 -0.044 -0.005 N 0.49290585413 2.18198449515 -0.00068475564 0.052 0.004 -0.003 S 6.56718562933 -0.11349126889 0.00673479967 0.179 -0.010 0.001 C 1.82142022278 -2.39594383179 -0.00206827421 0.032 -0.039 0.009 C 2.33969079820 -3.68709653410 -0.00625612120 0.054 -0.046 0.002 C 1.45789786198 -4.76953179608 -0.00945089783 0.003 -0.008 -0.007 C 0.08684213972 -4.53272927032 -0.00840538011 0.006 0.044 0.008 C -0.35393854068 -3.21111942258 -0.00398541364 0.022 0.041 -0.005 N 0.49225266031 -2.17934076887 -0.00084210065 0.060 -0.011 -0.003 H 1.83694111827 5.77332096953 -0.01265611066 -0.013 0.007 -0.006 H -0.61802819388 5.33967450634 -0.01131742088 -0.000 -0.018 0.004 H 3.39175422949 3.87200638269 -0.00704552340 0.015 0.017 -0.001 H -1.39787683933 2.98334799634 -0.00369736757 0.008 -0.021 -0.005 H 1.83794742242 -5.77033326187 -0.01295832570 -0.015 -0.008 -0.006 H -0.61749414542 -5.33746053721 -0.01121572048 -0.003 0.017 0.004 H -1.39833026435 -2.98175334118 -0.00345676225 0.009 0.022 -0.005 H 3.39230213722 -3.86796714602 -0.00754158092 0.014 -0.022 -0.001 H 4.58301895157 2.13678100538 0.00314824260 -0.061 -0.004 0.003 H 4.58784714512 -2.12983634010 0.00211631073 -0.065 0.007 0.003 H -1.68997263563 -0.00719388386 -5.74925805817 -0.030 0.003 0.017 H 0.75224758084 -0.00860493512 -5.25016290812 -0.006 -0.002 -0.035 H -3.29620044300 -0.00255800648 -3.88456579214 0.026 0.001 0.043 H 1.47161249279 -0.00457826661 -2.87685200854 0.020 0.003 -0.041 H -1.69176120521 -0.00597000955 5.75026973076 -0.026 0.003 -0.013 H 0.75025791005 -0.00892914887 5.25161119224 -0.001 -0.002 0.036 H 1.46975366817 -0.00523069331 2.87805400798 0.017 0.002 0.039 H -3.29750276746 -0.00099200484 3.88584245085 0.027 0.000 -0.035 H -4.55513299541 0.00377930937 -2.13473279421 -0.123 -0.002 -0.013 H -4.55107479454 0.00501307822 2.13844314827 -0.116 -0.002 0.007 H -6.83436893102 0.00806057203 1.19721860356 0.028 -0.000 -0.006 H 6.86748209639 1.20005966818 0.00372860376 0.015 0.003 0.001 61 Mode 54: freq=611.57 N -0.44003451495 -0.00038510790 2.12369783068 0.000 -0.009 0.001 C -1.76594470239 0.00039861437 2.37754210613 -0.000 0.015 -0.001 C -2.24923313135 -0.00145267054 3.67997125809 0.000 0.013 -0.001 C -1.33887502024 -0.00450793845 4.73956848945 0.000 -0.020 -0.001 C 0.02462671625 -0.00591801736 4.46614405978 0.001 0.023 0.000 C 0.43187566201 -0.00376957955 3.13352499014 0.000 -0.014 0.000 C -2.63984642995 0.00218980399 1.17162612704 -0.001 -0.021 -0.000 N -1.98513620489 0.00132140951 0.00153900685 -0.001 -0.031 -0.000 C -2.63911589169 0.00167522827 -1.17277445342 -0.001 -0.021 -0.000 C -4.02452897564 0.00329996303 -1.20791476641 -0.002 0.002 -0.000 C -4.73391255267 0.00451580118 -0.00020876193 -0.001 0.008 0.000 C -4.02924140493 0.00399189729 1.20660077672 -0.001 0.002 0.000 Co 0.00000000000 0.00000000000 0.00000000000 0.006 0.045 0.000 N -0.43839318333 -0.00054206762 -2.12229806799 0.000 -0.009 -0.000 C -1.76408906064 -0.00030645034 -2.37697009192 0.000 0.016 0.001 C -2.24773885821 -0.00257631963 -3.67934971086 0.000 0.013 0.001 C -1.33713102227 -0.00526459193 -4.73855802198 0.000 -0.020 0.001 C 0.02654101484 -0.00591797621 -4.46472703619 0.000 0.023 -0.000 C 0.43371721952 -0.00363389350 -3.13225443930 0.000 -0.014 -0.000 S -6.53329279136 0.00637481657 -0.11611178087 0.002 -0.002 0.000 N 2.00981687167 0.00259443239 -0.00000686048 -0.019 -0.420 -0.000 C 2.67119656792 1.17263645248 0.00045766926 -0.226 -0.279 0.001 C 4.06129317470 1.20536051565 0.00241240325 -0.306 0.027 -0.001 C 4.76783866331 0.00148799420 0.00346798881 -0.000 0.232 -0.000 C 4.05723810074 -1.20352939940 0.00211502115 0.286 0.034 0.001 C 2.67108506586 -1.17139122066 0.00026591651 0.205 -0.271 -0.001 C 1.82209539371 2.39842937406 -0.00175320633 0.128 0.005 0.002 C 2.33938959521 3.68993217240 -0.00584554905 0.058 0.133 0.000 C 1.45736908622 4.77231118002 -0.00917967851 -0.067 0.080 -0.001 C 0.08658913130 4.53522926787 -0.00833235387 -0.076 0.033 0.001 C -0.35359617412 3.21325694137 -0.00400174376 0.095 0.004 -0.001 N 0.49290585413 2.18198449515 -0.00068475564 0.195 0.091 -0.000 S 6.56718562933 -0.11349126889 0.00673479967 -0.004 -0.063 -0.000 C 1.82142022278 -2.39594383179 -0.00206827421 -0.125 0.001 -0.002 C 2.33969079820 -3.68709653410 -0.00625612120 -0.050 0.128 -0.000 C 1.45789786198 -4.76953179608 -0.00945089783 0.068 0.080 0.001 C 0.08684213972 -4.53272927032 -0.00840538011 0.076 0.039 -0.001 C -0.35393854068 -3.21111942258 -0.00398541364 -0.094 0.008 0.001 N 0.49225266031 -2.17934076887 -0.00084210065 -0.189 0.088 -0.000 H 1.83694111827 5.77332096953 -0.01265611066 -0.036 0.030 -0.001 H -0.61802819388 5.33967450634 -0.01131742088 -0.043 -0.008 0.000 H 3.39175422949 3.87200638269 -0.00704552340 0.008 0.094 -0.000 H -1.39787683933 2.98334799634 -0.00369736757 0.037 -0.040 -0.001 H 1.83794742242 -5.77033326187 -0.01295832570 0.034 0.029 0.001 H -0.61749414542 -5.33746053721 -0.01121572048 0.042 -0.006 -0.001 H -1.39833026435 -2.98175334118 -0.00345676225 -0.037 -0.038 0.001 H 3.39230213722 -3.86796714602 -0.00754158092 -0.006 0.092 0.001 H 4.58301895157 2.13678100538 0.00314824260 -0.178 0.055 -0.001 H 4.58784714512 -2.12983634010 0.00211631073 0.172 0.058 0.001 H -1.68997263563 -0.00719388386 -5.74925805817 -0.000 -0.018 0.000 H 0.75224758084 -0.00860493512 -5.25016290812 -0.000 0.011 -0.000 H -3.29620044300 -0.00255800648 -3.88456579214 0.000 0.002 0.000 H 1.47161249279 -0.00457826661 -2.87685200854 0.000 -0.014 -0.000 H -1.69176120521 -0.00597000955 5.75026973076 -0.000 -0.018 -0.000 H 0.75025791005 -0.00892914887 5.25161119224 0.000 0.011 0.000 H 1.46975366817 -0.00523069331 2.87805400798 0.000 -0.014 -0.000 H -3.29750276746 -0.00099200484 3.88584245085 0.000 0.002 -0.000 H -4.55513299541 0.00377930937 -2.13473279421 -0.001 0.008 -0.000 H -4.55107479454 0.00501307822 2.13844314827 -0.001 0.009 0.000 H -6.83436893102 0.00806057203 1.19721860356 0.000 -0.002 -0.000 H 6.86748209639 1.20005966818 0.00372860376 0.140 -0.042 0.000 61 Mode 55: freq=614.50 N -0.44003451495 -0.00038510790 2.12369783068 0.194 -0.000 -0.092 C -1.76594470239 0.00039861437 2.37754210613 0.128 -0.001 -0.009 C -2.24923313135 -0.00145267054 3.67997125809 0.051 -0.000 -0.135 C -1.33887502024 -0.00450793845 4.73956848945 -0.070 0.001 -0.082 C 0.02462671625 -0.00591801736 4.46614405978 -0.076 -0.000 -0.033 C 0.43187566201 -0.00376957955 3.13352499014 0.099 0.000 -0.006 C -2.63984642995 0.00218980399 1.17162612704 -0.226 -0.000 0.282 N -1.98513620489 0.00132140951 0.00153900685 -0.020 0.000 0.418 C -2.63911589169 0.00167522827 -1.17277445342 0.203 0.000 0.274 C -4.02452897564 0.00329996303 -1.20791476641 0.286 -0.001 -0.028 C -4.73391255267 0.00451580118 -0.00020876193 -0.001 -0.000 -0.225 C -4.02924140493 0.00399189729 1.20660077672 -0.309 0.001 -0.020 Co 0.00000000000 0.00000000000 0.00000000000 0.007 0.000 -0.042 N -0.43839318333 -0.00054206762 -2.12229806799 -0.187 0.000 -0.089 C -1.76408906064 -0.00030645034 -2.37697009192 -0.125 0.001 -0.004 C -2.24773885821 -0.00257631963 -3.67934971086 -0.043 -0.000 -0.130 C -1.33713102227 -0.00526459193 -4.73855802198 0.071 -0.001 -0.084 C 0.02654101484 -0.00591797621 -4.46472703619 0.077 0.000 -0.040 C 0.43371721952 -0.00363389350 -3.13225443930 -0.098 -0.000 -0.011 S -6.53329279136 0.00637481657 -0.11611178087 -0.003 -0.000 0.062 N 2.00981687167 0.00259443239 -0.00000686048 -0.001 -0.000 0.031 C 2.67119656792 1.17263645248 0.00045766926 -0.001 -0.000 0.021 C 4.06129317470 1.20536051565 0.00241240325 -0.001 -0.000 -0.002 C 4.76783866331 0.00148799420 0.00346798881 -0.001 0.000 -0.008 C 4.05723810074 -1.20352939940 0.00211502115 -0.001 0.000 -0.002 C 2.67108506586 -1.17139122066 0.00026591651 -0.001 0.000 0.021 C 1.82209539371 2.39842937406 -0.00175320633 0.000 0.000 -0.015 C 2.33938959521 3.68993217240 -0.00584554905 0.000 0.000 -0.012 C 1.45736908622 4.77231118002 -0.00917967851 0.000 0.000 0.018 C 0.08658913130 4.53522926787 -0.00833235387 0.000 -0.000 -0.021 C -0.35359617412 3.21325694137 -0.00400174376 -0.000 -0.000 0.013 N 0.49290585413 2.18198449515 -0.00068475564 0.000 0.000 0.007 S 6.56718562933 -0.11349126889 0.00673479967 0.001 -0.000 0.002 C 1.82142022278 -2.39594383179 -0.00206827421 0.000 -0.000 -0.015 C 2.33969079820 -3.68709653410 -0.00625612120 0.000 -0.000 -0.012 C 1.45789786198 -4.76953179608 -0.00945089783 0.000 -0.000 0.019 C 0.08684213972 -4.53272927032 -0.00840538011 0.000 0.000 -0.021 C -0.35393854068 -3.21111942258 -0.00398541364 -0.000 0.000 0.014 N 0.49225266031 -2.17934076887 -0.00084210065 0.000 -0.000 0.007 H 1.83694111827 5.77332096953 -0.01265611066 -0.000 0.000 0.016 H -0.61802819388 5.33967450634 -0.01131742088 0.000 -0.000 -0.010 H 3.39175422949 3.87200638269 -0.00704552340 0.000 0.000 -0.002 H -1.39787683933 2.98334799634 -0.00369736757 0.000 -0.000 0.013 H 1.83794742242 -5.77033326187 -0.01295832570 -0.000 -0.000 0.016 H -0.61749414542 -5.33746053721 -0.01121572048 0.000 0.000 -0.010 H -1.39833026435 -2.98175334118 -0.00345676225 0.000 0.000 0.013 H 3.39230213722 -3.86796714602 -0.00754158092 0.000 -0.000 -0.002 H 4.58301895157 2.13678100538 0.00314824260 -0.000 -0.000 -0.008 H 4.58784714512 -2.12983634010 0.00211631073 -0.000 0.000 -0.008 H -1.68997263563 -0.00719388386 -5.74925805817 0.034 -0.001 -0.030 H 0.75224758084 -0.00860493512 -5.25016290812 0.043 0.000 0.008 H -3.29620044300 -0.00255800648 -3.88456579214 -0.003 -0.000 -0.092 H 1.47161249279 -0.00457826661 -2.87685200854 -0.039 -0.000 0.036 H -1.69176120521 -0.00597000955 5.75026973076 -0.036 0.001 -0.030 H 0.75025791005 -0.00892914887 5.25161119224 -0.043 -0.000 0.010 H 1.46975366817 -0.00523069331 2.87805400798 0.039 0.000 0.039 H -3.29750276746 -0.00099200484 3.88584245085 0.005 0.000 -0.094 H -4.55513299541 0.00377930937 -2.13473279421 0.172 -0.000 -0.057 H -4.55107479454 0.00501307822 2.13844314827 -0.179 0.000 -0.054 H -6.83436893102 0.00806057203 1.19721860356 0.137 -0.000 0.042 H 6.86748209639 1.20005966818 0.00372860376 0.000 0.000 0.002 61 Mode 56: freq=664.08 N -0.44003451495 -0.00038510790 2.12369783068 0.007 0.000 -0.004 C -1.76594470239 0.00039861437 2.37754210613 0.008 0.000 0.003 C -2.24923313135 -0.00145267054 3.67997125809 0.001 0.000 -0.001 C -1.33887502024 -0.00450793845 4.73956848945 -0.004 -0.000 0.001 C 0.02462671625 -0.00591801736 4.46614405978 -0.005 0.000 -0.003 C 0.43187566201 -0.00376957955 3.13352499014 0.004 -0.000 -0.002 C -2.63984642995 0.00218980399 1.17162612704 -0.002 -0.000 0.012 N -1.98513620489 0.00132140951 0.00153900685 -0.000 0.000 0.013 C -2.63911589169 0.00167522827 -1.17277445342 0.002 -0.000 0.011 C -4.02452897564 0.00329996303 -1.20791476641 0.006 -0.000 -0.003 C -4.73391255267 0.00451580118 -0.00020876193 0.000 0.001 -0.007 C -4.02924140493 0.00399189729 1.20660077672 -0.006 -0.000 -0.003 Co 0.00000000000 0.00000000000 0.00000000000 -0.000 -0.000 -0.021 N -0.43839318333 -0.00054206762 -2.12229806799 -0.007 0.000 -0.004 C -1.76408906064 -0.00030645034 -2.37697009192 -0.007 0.000 0.004 C -2.24773885821 -0.00257631963 -3.67934971086 -0.001 0.000 -0.001 C -1.33713102227 -0.00526459193 -4.73855802198 0.004 -0.000 0.001 C 0.02654101484 -0.00591797621 -4.46472703619 0.005 0.000 -0.003 C 0.43371721952 -0.00363389350 -3.13225443930 -0.004 -0.000 -0.002 S -6.53329279136 0.00637481657 -0.11611178087 -0.000 -0.000 0.001 N 2.00981687167 0.00259443239 -0.00000686048 0.000 -0.000 0.076 C 2.67119656792 1.17263645248 0.00045766926 0.000 -0.000 -0.194 C 4.06129317470 1.20536051565 0.00241240325 0.000 0.000 -0.199 C 4.76783866331 0.00148799420 0.00346798881 -0.001 0.000 0.718 C 4.05723810074 -1.20352939940 0.00211502115 0.000 0.000 -0.203 C 2.67108506586 -1.17139122066 0.00026591651 0.000 -0.000 -0.197 C 1.82209539371 2.39842937406 -0.00175320633 -0.000 0.000 0.132 C 2.33938959521 3.68993217240 -0.00584554905 -0.000 0.000 0.044 C 1.45736908622 4.77231118002 -0.00917967851 0.000 -0.000 -0.084 C 0.08658913130 4.53522926787 -0.00833235387 0.000 0.000 0.129 C -0.35359617412 3.21325694137 -0.00400174376 0.000 -0.000 -0.120 N 0.49290585413 2.18198449515 -0.00068475564 -0.000 0.000 0.100 S 6.56718562933 -0.11349126889 0.00673479967 0.000 -0.000 -0.070 C 1.82142022278 -2.39594383179 -0.00206827421 -0.000 -0.000 0.135 C 2.33969079820 -3.68709653410 -0.00625612120 -0.000 -0.000 0.044 C 1.45789786198 -4.76953179608 -0.00945089783 0.000 0.000 -0.085 C 0.08684213972 -4.53272927032 -0.00840538011 0.000 -0.000 0.133 C -0.35393854068 -3.21111942258 -0.00398541364 -0.000 0.000 -0.123 N 0.49225266031 -2.17934076887 -0.00084210065 -0.000 0.000 0.102 H 1.83694111827 5.77332096953 -0.01265611066 0.000 -0.000 -0.097 H -0.61802819388 5.33967450634 -0.01131742088 0.000 0.000 0.041 H 3.39175422949 3.87200638269 -0.00704552340 -0.000 -0.000 -0.021 H -1.39787683933 2.98334799634 -0.00369736757 0.000 -0.000 -0.136 H 1.83794742242 -5.77033326187 -0.01295832570 0.000 0.000 -0.099 H -0.61749414542 -5.33746053721 -0.01121572048 0.000 -0.000 0.042 H -1.39833026435 -2.98175334118 -0.00345676225 -0.000 0.000 -0.140 H 3.39230213722 -3.86796714602 -0.00754158092 -0.000 0.000 -0.022 H 4.58301895157 2.13678100538 0.00314824260 0.000 -0.000 -0.232 H 4.58784714512 -2.12983634010 0.00211631073 0.001 0.000 -0.242 H -1.68997263563 -0.00719388386 -5.74925805817 0.001 -0.000 0.000 H 0.75224758084 -0.00860493512 -5.25016290812 0.002 0.000 -0.000 H -3.29620044300 -0.00255800648 -3.88456579214 0.000 -0.000 -0.003 H 1.47161249279 -0.00457826661 -2.87685200854 -0.001 -0.000 0.001 H -1.69176120521 -0.00597000955 5.75026973076 -0.001 -0.000 0.000 H 0.75025791005 -0.00892914887 5.25161119224 -0.002 0.000 -0.000 H 1.46975366817 -0.00523069331 2.87805400798 0.001 -0.000 0.001 H -3.29750276746 -0.00099200484 3.88584245085 -0.000 -0.000 -0.003 H -4.55513299541 0.00377930937 -2.13473279421 0.005 -0.000 -0.003 H -4.55107479454 0.00501307822 2.13844314827 -0.005 -0.000 -0.003 H -6.83436893102 0.00806057203 1.19721860356 0.004 -0.000 0.001 H 6.86748209639 1.20005966818 0.00372860376 -0.001 0.000 -0.064 61 Mode 57: freq=664.95 N -0.44003451495 -0.00038510790 2.12369783068 -0.000 -0.100 0.000 C -1.76594470239 0.00039861437 2.37754210613 -0.000 -0.130 -0.000 C -2.24923313135 -0.00145267054 3.67997125809 -0.000 -0.046 -0.000 C -1.33887502024 -0.00450793845 4.73956848945 0.000 0.083 0.000 C 0.02462671625 -0.00591801736 4.46614405978 -0.000 -0.129 -0.000 C 0.43187566201 -0.00376957955 3.13352499014 0.000 0.119 0.000 C -2.63984642995 0.00218980399 1.17162612704 0.000 0.196 -0.000 N -1.98513620489 0.00132140951 0.00153900685 -0.000 -0.079 0.000 C -2.63911589169 0.00167522827 -1.17277445342 0.000 0.199 -0.000 C -4.02452897564 0.00329996303 -1.20791476641 0.000 0.203 -0.000 C -4.73391255267 0.00451580118 -0.00020876193 -0.001 -0.718 0.000 C -4.02924140493 0.00399189729 1.20660077672 0.000 0.199 -0.000 Co 0.00000000000 0.00000000000 0.00000000000 0.000 0.022 -0.000 N -0.43839318333 -0.00054206762 -2.12229806799 -0.000 -0.103 0.000 C -1.76408906064 -0.00030645034 -2.37697009192 -0.000 -0.133 0.000 C -2.24773885821 -0.00257631963 -3.67934971086 -0.000 -0.046 0.000 C -1.33713102227 -0.00526459193 -4.73855802198 0.000 0.085 -0.000 C 0.02654101484 -0.00591797621 -4.46472703619 0.000 -0.132 0.000 C 0.43371721952 -0.00363389350 -3.13225443930 0.000 0.122 -0.000 S -6.53329279136 0.00637481657 -0.11611178087 0.000 0.070 -0.000 N 2.00981687167 0.00259443239 -0.00000686048 -0.000 -0.014 0.000 C 2.67119656792 1.17263645248 0.00045766926 -0.002 -0.012 -0.000 C 4.06129317470 1.20536051565 0.00241240325 -0.007 0.003 -0.000 C 4.76783866331 0.00148799420 0.00346798881 0.000 0.007 0.001 C 4.05723810074 -1.20352939940 0.00211502115 0.007 0.003 -0.000 C 2.67108506586 -1.17139122066 0.00026591651 0.002 -0.012 -0.000 C 1.82209539371 2.39842937406 -0.00175320633 0.007 -0.004 0.000 C 2.33938959521 3.68993217240 -0.00584554905 0.000 0.002 0.000 C 1.45736908622 4.77231118002 -0.00917967851 -0.004 0.001 -0.000 C 0.08658913130 4.53522926787 -0.00833235387 -0.005 0.003 0.000 C -0.35359617412 3.21325694137 -0.00400174376 0.005 0.002 -0.000 N 0.49290585413 2.18198449515 -0.00068475564 0.007 0.003 0.000 S 6.56718562933 -0.11349126889 0.00673479967 -0.000 -0.001 -0.000 C 1.82142022278 -2.39594383179 -0.00206827421 -0.007 -0.004 0.000 C 2.33969079820 -3.68709653410 -0.00625612120 -0.000 0.002 0.000 C 1.45789786198 -4.76953179608 -0.00945089783 0.004 0.001 -0.000 C 0.08684213972 -4.53272927032 -0.00840538011 0.005 0.003 0.000 C -0.35393854068 -3.21111942258 -0.00398541364 -0.005 0.002 -0.000 N 0.49225266031 -2.17934076887 -0.00084210065 -0.007 0.003 0.000 H 1.83694111827 5.77332096953 -0.01265611066 -0.001 0.000 -0.000 H -0.61802819388 5.33967450634 -0.01131742088 -0.002 0.000 0.000 H 3.39175422949 3.87200638269 -0.00704552340 -0.000 0.003 -0.000 H -1.39787683933 2.98334799634 -0.00369736757 0.002 -0.001 -0.000 H 1.83794742242 -5.77033326187 -0.01295832570 0.001 0.000 -0.000 H -0.61749414542 -5.33746053721 -0.01121572048 0.002 0.000 0.000 H -1.39833026435 -2.98175334118 -0.00345676225 -0.002 -0.001 -0.000 H 3.39230213722 -3.86796714602 -0.00754158092 0.000 0.003 0.000 H 4.58301895157 2.13678100538 0.00314824260 -0.005 0.003 -0.000 H 4.58784714512 -2.12983634010 0.00211631073 0.005 0.003 -0.000 H -1.68997263563 -0.00719388386 -5.74925805817 0.000 0.099 -0.000 H 0.75224758084 -0.00860493512 -5.25016290812 -0.000 -0.041 0.000 H -3.29620044300 -0.00255800648 -3.88456579214 -0.000 0.023 -0.000 H 1.47161249279 -0.00457826661 -2.87685200854 0.000 0.139 -0.000 H -1.69176120521 -0.00597000955 5.75026973076 0.000 0.097 0.000 H 0.75025791005 -0.00892914887 5.25161119224 -0.000 -0.040 -0.000 H 1.46975366817 -0.00523069331 2.87805400798 0.000 0.135 0.000 H -3.29750276746 -0.00099200484 3.88584245085 0.000 0.022 0.000 H -4.55513299541 0.00377930937 -2.13473279421 0.000 0.241 -0.000 H -4.55107479454 0.00501307822 2.13844314827 0.000 0.231 -0.000 H -6.83436893102 0.00806057203 1.19721860356 0.000 0.064 -0.000 H 6.86748209639 1.20005966818 0.00372860376 0.004 -0.001 -0.000 61 Mode 58: freq=696.79 N -0.44003451495 -0.00038510790 2.12369783068 0.056 0.000 -0.248 C -1.76594470239 0.00039861437 2.37754210613 0.092 -0.000 -0.001 C -2.24923313135 -0.00145267054 3.67997125809 0.165 -0.000 0.081 C -1.33887502024 -0.00450793845 4.73956848945 -0.053 -0.001 0.283 C 0.02462671625 -0.00591801736 4.46614405978 -0.137 0.000 -0.007 C 0.43187566201 -0.00376957955 3.13352499014 -0.168 0.000 -0.064 C -2.63984642995 0.00218980399 1.17162612704 0.019 -0.000 0.035 N -1.98513620489 0.00132140951 0.00153900685 -0.007 0.000 -0.000 C -2.63911589169 0.00167522827 -1.17277445342 0.016 0.000 -0.034 C -4.02452897564 0.00329996303 -1.20791476641 0.017 0.000 -0.024 C -4.73391255267 0.00451580118 -0.00020876193 0.034 -0.000 0.001 C -4.02924140493 0.00399189729 1.20660077672 0.021 0.000 0.025 Co 0.00000000000 0.00000000000 0.00000000000 0.033 -0.000 0.000 N -0.43839318333 -0.00054206762 -2.12229806799 0.055 0.000 0.244 C -1.76408906064 -0.00030645034 -2.37697009192 0.090 -0.000 0.003 C -2.24773885821 -0.00257631963 -3.67934971086 0.164 -0.000 -0.079 C -1.33713102227 -0.00526459193 -4.73855802198 -0.051 -0.000 -0.279 C 0.02654101484 -0.00591797621 -4.46472703619 -0.134 0.000 0.005 C 0.43371721952 -0.00363389350 -3.13225443930 -0.166 0.000 0.062 S -6.53329279136 0.00637481657 -0.11611178087 -0.033 0.000 -0.002 N 2.00981687167 0.00259443239 -0.00000686048 -0.007 0.000 -0.000 C 2.67119656792 1.17263645248 0.00045766926 0.009 -0.034 -0.000 C 4.06129317470 1.20536051565 0.00241240325 0.009 -0.025 -0.000 C 4.76783866331 0.00148799420 0.00346798881 0.024 -0.000 0.000 C 4.05723810074 -1.20352939940 0.00211502115 0.006 0.025 -0.000 C 2.67108506586 -1.17139122066 0.00026591651 0.006 0.033 -0.000 C 1.82209539371 2.39842937406 -0.00175320633 0.091 0.004 -0.000 C 2.33938959521 3.68993217240 -0.00584554905 0.166 -0.078 0.000 C 1.45736908622 4.77231118002 -0.00917967851 -0.056 -0.275 0.001 C 0.08658913130 4.53522926787 -0.00833235387 -0.131 0.004 0.000 C -0.35359617412 3.21325694137 -0.00400174376 -0.164 0.063 -0.000 N 0.49290585413 2.18198449515 -0.00068475564 0.063 0.244 -0.001 S 6.56718562933 -0.11349126889 0.00673479967 -0.023 0.001 -0.000 C 1.82142022278 -2.39594383179 -0.00206827421 0.088 -0.006 -0.000 C 2.33969079820 -3.68709653410 -0.00625612120 0.164 0.076 0.000 C 1.45789786198 -4.76953179608 -0.00945089783 -0.054 0.268 0.001 C 0.08684213972 -4.53272927032 -0.00840538011 -0.127 -0.003 0.000 C -0.35393854068 -3.21111942258 -0.00398541364 -0.161 -0.060 -0.000 N 0.49225266031 -2.17934076887 -0.00084210065 0.062 -0.239 -0.001 H 1.83694111827 5.77332096953 -0.01265611066 -0.024 -0.078 0.000 H -0.61802819388 5.33967450634 -0.01131742088 0.022 0.054 -0.000 H 3.39175422949 3.87200638269 -0.00704552340 0.040 0.027 -0.000 H -1.39787683933 2.98334799634 -0.00369736757 -0.036 -0.037 0.000 H 1.83794742242 -5.77033326187 -0.01295832570 -0.024 0.076 0.000 H -0.61749414542 -5.33746053721 -0.01121572048 0.022 -0.053 -0.000 H -1.39833026435 -2.98175334118 -0.00345676225 -0.036 0.037 0.000 H 3.39230213722 -3.86796714602 -0.00754158092 0.039 -0.026 -0.000 H 4.58301895157 2.13678100538 0.00314824260 -0.003 -0.005 -0.000 H 4.58784714512 -2.12983634010 0.00211631073 -0.004 0.004 -0.000 H -1.68997263563 -0.00719388386 -5.74925805817 -0.020 -0.000 -0.080 H 0.75224758084 -0.00860493512 -5.25016290812 0.020 0.000 0.056 H -3.29620044300 -0.00255800648 -3.88456579214 0.038 0.000 0.026 H 1.47161249279 -0.00457826661 -2.87685200854 -0.035 0.000 -0.037 H -1.69176120521 -0.00597000955 5.75026973076 -0.020 -0.000 0.081 H 0.75025791005 -0.00892914887 5.25161119224 0.020 0.000 -0.058 H 1.46975366817 -0.00523069331 2.87805400798 -0.036 -0.000 0.037 H -3.29750276746 -0.00099200484 3.88584245085 0.038 0.000 -0.026 H -4.55513299541 0.00377930937 -2.13473279421 -0.001 0.000 -0.004 H -4.55107479454 0.00501307822 2.13844314827 0.001 0.000 0.005 H -6.83436893102 0.00806057203 1.19721860356 -0.003 0.000 0.001 H 6.86748209639 1.20005966818 0.00372860376 -0.002 -0.000 -0.000 61 Mode 59: freq=707.89 N -0.44003451495 -0.00038510790 2.12369783068 -0.004 -0.004 0.019 C -1.76594470239 0.00039861437 2.37754210613 -0.008 -0.002 0.001 C -2.24923313135 -0.00145267054 3.67997125809 -0.013 0.001 -0.005 C -1.33887502024 -0.00450793845 4.73956848945 0.004 -0.003 -0.021 C 0.02462671625 -0.00591801736 4.46614405978 0.010 0.002 0.001 C 0.43187566201 -0.00376957955 3.13352499014 0.013 -0.004 0.005 C -2.63984642995 0.00218980399 1.17162612704 -0.001 0.003 -0.002 N -1.98513620489 0.00132140951 0.00153900685 0.001 0.002 0.000 C -2.63911589169 0.00167522827 -1.17277445342 -0.001 0.003 0.002 C -4.02452897564 0.00329996303 -1.20791476641 -0.001 -0.001 0.002 C -4.73391255267 0.00451580118 -0.00020876193 -0.003 0.001 0.000 C -4.02924140493 0.00399189729 1.20660077672 -0.002 -0.001 -0.002 Co 0.00000000000 0.00000000000 0.00000000000 -0.000 -0.047 -0.000 N -0.43839318333 -0.00054206762 -2.12229806799 -0.004 -0.004 -0.017 C -1.76408906064 -0.00030645034 -2.37697009192 -0.007 -0.002 -0.001 C -2.24773885821 -0.00257631963 -3.67934971086 -0.013 0.001 0.005 C -1.33713102227 -0.00526459193 -4.73855802198 0.004 -0.003 0.019 C 0.02654101484 -0.00591797621 -4.46472703619 0.009 0.002 -0.001 C 0.43371721952 -0.00363389350 -3.13225443930 0.012 -0.004 -0.005 S -6.53329279136 0.00637481657 -0.11611178087 0.002 0.000 0.000 N 2.00981687167 0.00259443239 -0.00000686048 -0.003 0.034 0.000 C 2.67119656792 1.17263645248 0.00045766926 0.033 -0.010 0.002 C 4.06129317470 1.20536051565 0.00241240325 0.050 0.028 -0.000 C 4.76783866331 0.00148799420 0.00346798881 0.004 0.024 -0.000 C 4.05723810074 -1.20352939940 0.00211502115 -0.047 0.032 0.000 C 2.67108506586 -1.17139122066 0.00026591651 -0.031 -0.005 -0.002 C 1.82209539371 2.39842937406 -0.00175320633 0.131 0.035 -0.001 C 2.33938959521 3.68993217240 -0.00584554905 0.271 -0.094 -0.000 C 1.45736908622 4.77231118002 -0.00917967851 -0.068 -0.398 0.002 C 0.08658913130 4.53522926787 -0.00833235387 -0.178 -0.004 -0.001 C -0.35359617412 3.21325694137 -0.00400174376 -0.260 0.089 0.000 N 0.49290585413 2.18198449515 -0.00068475564 0.076 0.351 -0.001 S 6.56718562933 -0.11349126889 0.00673479967 -0.002 0.007 0.000 C 1.82142022278 -2.39594383179 -0.00206827421 -0.119 0.035 0.000 C 2.33969079820 -3.68709653410 -0.00625612120 -0.251 -0.085 0.000 C 1.45789786198 -4.76953179608 -0.00945089783 0.062 -0.366 -0.002 C 0.08684213972 -4.53272927032 -0.00840538011 0.161 -0.007 0.001 C -0.35393854068 -3.21111942258 -0.00398541364 0.241 0.080 -0.000 N 0.49225266031 -2.17934076887 -0.00084210065 -0.068 0.322 0.001 H 1.83694111827 5.77332096953 -0.01265611066 -0.039 -0.110 0.001 H -0.61802819388 5.33967450634 -0.01131742088 0.041 0.080 -0.000 H 3.39175422949 3.87200638269 -0.00704552340 0.066 0.043 -0.000 H -1.39787683933 2.98334799634 -0.00369736757 -0.060 -0.051 0.001 H 1.83794742242 -5.77033326187 -0.01295832570 0.036 -0.101 -0.001 H -0.61749414542 -5.33746053721 -0.01121572048 -0.038 0.073 0.000 H -1.39833026435 -2.98175334118 -0.00345676225 0.055 -0.047 -0.001 H 3.39230213722 -3.86796714602 -0.00754158092 -0.062 0.039 0.000 H 4.58301895157 2.13678100538 0.00314824260 0.014 0.008 -0.001 H 4.58784714512 -2.12983634010 0.00211631073 -0.015 0.008 0.001 H -1.68997263563 -0.00719388386 -5.74925805817 0.002 0.000 0.005 H 0.75224758084 -0.00860493512 -5.25016290812 -0.002 0.004 -0.004 H -3.29620044300 -0.00255800648 -3.88456579214 -0.003 0.003 -0.002 H 1.47161249279 -0.00457826661 -2.87685200854 0.003 0.001 0.002 H -1.69176120521 -0.00597000955 5.75026973076 0.002 -0.000 -0.006 H 0.75025791005 -0.00892914887 5.25161119224 -0.002 0.004 0.005 H 1.46975366817 -0.00523069331 2.87805400798 0.003 0.001 -0.003 H -3.29750276746 -0.00099200484 3.88584245085 -0.003 0.003 0.002 H -4.55513299541 0.00377930937 -2.13473279421 0.000 -0.002 0.000 H -4.55107479454 0.00501307822 2.13844314827 -0.000 -0.002 -0.000 H -6.83436893102 0.00806057203 1.19721860356 0.000 -0.000 -0.000 H 6.86748209639 1.20005966818 0.00372860376 0.001 0.001 -0.000 61 Mode 60: freq=709.67 N -0.44003451495 -0.00038510790 2.12369783068 0.054 0.000 -0.252 C -1.76594470239 0.00039861437 2.37754210613 0.103 -0.000 -0.016 C -2.24923313135 -0.00145267054 3.67997125809 0.186 -0.000 0.065 C -1.33887502024 -0.00450793845 4.73956848945 -0.052 -0.001 0.282 C 0.02462671625 -0.00591801736 4.46614405978 -0.139 0.000 -0.014 C 0.43187566201 -0.00376957955 3.13352499014 -0.178 0.000 -0.071 C -2.63984642995 0.00218980399 1.17162612704 0.019 0.000 0.032 N -1.98513620489 0.00132140951 0.00153900685 -0.014 0.000 -0.002 C -2.63911589169 0.00167522827 -1.17277445342 0.013 0.000 -0.029 C -4.02452897564 0.00329996303 -1.20791476641 0.014 0.000 -0.026 C -4.73391255267 0.00451580118 -0.00020876193 0.037 -0.000 -0.001 C -4.02924140493 0.00399189729 1.20660077672 0.023 0.000 0.024 Co 0.00000000000 0.00000000000 0.00000000000 0.010 -0.003 0.003 N -0.43839318333 -0.00054206762 -2.12229806799 0.048 -0.000 0.221 C -1.76408906064 -0.00030645034 -2.37697009192 0.090 -0.000 0.015 C -2.24773885821 -0.00257631963 -3.67934971086 0.164 -0.000 -0.056 C -1.33713102227 -0.00526459193 -4.73855802198 -0.045 -0.001 -0.246 C 0.02654101484 -0.00591797621 -4.46472703619 -0.121 0.000 0.012 C 0.43371721952 -0.00363389350 -3.13225443930 -0.156 0.000 0.062 S -6.53329279136 0.00637481657 -0.11611178087 -0.032 0.000 -0.002 N 2.00981687167 0.00259443239 -0.00000686048 0.014 0.002 -0.000 C 2.67119656792 1.17263645248 0.00045766926 -0.020 0.032 -0.000 C 4.06129317470 1.20536051565 0.00241240325 -0.023 0.029 0.000 C 4.76783866331 0.00148799420 0.00346798881 -0.042 0.002 -0.001 C 4.05723810074 -1.20352939940 0.00211502115 -0.025 -0.024 0.000 C 2.67108506586 -1.17139122066 0.00026591651 -0.020 -0.032 -0.000 C 1.82209539371 2.39842937406 -0.00175320633 -0.093 -0.008 0.000 C 2.33938959521 3.68993217240 -0.00584554905 -0.157 0.062 -0.000 C 1.45736908622 4.77231118002 -0.00917967851 0.053 0.243 -0.001 C 0.08658913130 4.53522926787 -0.00833235387 0.122 -0.020 0.000 C -0.35359617412 3.21325694137 -0.00400174376 0.150 -0.067 0.000 N 0.49290585413 2.18198449515 -0.00068475564 -0.055 -0.219 0.001 S 6.56718562933 -0.11349126889 0.00673479967 0.037 -0.002 0.000 C 1.82142022278 -2.39594383179 -0.00206827421 -0.109 0.016 0.000 C 2.33969079820 -3.68709653410 -0.00625612120 -0.196 -0.072 -0.000 C 1.45789786198 -4.76953179608 -0.00945089783 0.060 -0.294 -0.001 C 0.08684213972 -4.53272927032 -0.00840538011 0.143 0.016 -0.000 C -0.35393854068 -3.21111942258 -0.00398541364 0.186 0.077 0.000 N 0.49225266031 -2.17934076887 -0.00084210065 -0.064 0.265 0.001 H 1.83694111827 5.77332096953 -0.01265611066 0.022 0.069 -0.000 H -0.61802819388 5.33967450634 -0.01131742088 -0.020 -0.055 0.000 H 3.39175422949 3.87200638269 -0.00704552340 -0.037 -0.029 0.000 H -1.39787683933 2.98334799634 -0.00369736757 0.033 0.030 -0.000 H 1.83794742242 -5.77033326187 -0.01295832570 0.028 -0.082 -0.000 H -0.61749414542 -5.33746053721 -0.01121572048 -0.026 0.064 0.000 H -1.39833026435 -2.98175334118 -0.00345676225 0.042 -0.037 -0.000 H 3.39230213722 -3.86796714602 -0.00754158092 -0.047 0.035 0.000 H 4.58301895157 2.13678100538 0.00314824260 -0.001 0.006 0.000 H 4.58784714512 -2.12983634010 0.00211631073 -0.001 -0.004 0.000 H -1.68997263563 -0.00719388386 -5.74925805817 -0.021 -0.000 -0.069 H 0.75224758084 -0.00860493512 -5.25016290812 0.020 0.000 0.055 H -3.29620044300 -0.00255800648 -3.88456579214 0.039 0.000 0.030 H 1.47161249279 -0.00457826661 -2.87685200854 -0.034 0.000 -0.031 H -1.69176120521 -0.00597000955 5.75026973076 -0.024 -0.000 0.080 H 0.75025791005 -0.00892914887 5.25161119224 0.023 0.000 -0.063 H 1.46975366817 -0.00523069331 2.87805400798 -0.038 0.000 0.036 H -3.29750276746 -0.00099200484 3.88584245085 0.043 0.000 -0.034 H -4.55513299541 0.00377930937 -2.13473279421 -0.002 -0.000 -0.005 H -4.55107479454 0.00501307822 2.13844314827 0.001 0.000 0.004 H -6.83436893102 0.00806057203 1.19721860356 -0.002 0.000 0.001 H 6.86748209639 1.20005966818 0.00372860376 0.003 0.001 0.000 61 Mode 61: freq=711.74 N -0.44003451495 -0.00038510790 2.12369783068 0.060 0.001 -0.323 C -1.76594470239 0.00039861437 2.37754210613 0.122 0.000 -0.041 C -2.24923313135 -0.00145267054 3.67997125809 0.260 0.000 0.072 C -1.33887502024 -0.00450793845 4.73956848945 -0.054 -0.001 0.367 C 0.02462671625 -0.00591801736 4.46614405978 -0.165 0.001 0.006 C 0.43187566201 -0.00376957955 3.13352499014 -0.245 0.000 -0.079 C -2.63984642995 0.00218980399 1.17162612704 0.028 -0.001 0.008 N -1.98513620489 0.00132140951 0.00153900685 -0.001 -0.000 -0.029 C -2.63911589169 0.00167522827 -1.17277445342 -0.030 0.001 0.010 C -4.02452897564 0.00329996303 -1.20791476641 -0.045 -0.000 -0.027 C -4.73391255267 0.00451580118 -0.00020876193 -0.000 -0.000 -0.024 C -4.02924140493 0.00399189729 1.20660077672 0.043 0.000 -0.028 Co 0.00000000000 0.00000000000 0.00000000000 -0.000 0.000 0.062 N -0.43839318333 -0.00054206762 -2.12229806799 -0.065 -0.001 -0.347 C -1.76408906064 -0.00030645034 -2.37697009192 -0.132 -0.000 -0.044 C -2.24773885821 -0.00257631963 -3.67934971086 -0.279 -0.000 0.078 C -1.33713102227 -0.00526459193 -4.73855802198 0.058 0.001 0.394 C 0.02654101484 -0.00591797621 -4.46472703619 0.178 -0.001 0.005 C 0.43371721952 -0.00363389350 -3.13225443930 0.263 0.000 -0.085 S -6.53329279136 0.00637481657 -0.11611178087 0.002 -0.000 -0.006 N 2.00981687167 0.00259443239 -0.00000686048 -0.001 -0.000 -0.004 C 2.67119656792 1.17263645248 0.00045766926 0.001 -0.001 -0.005 C 4.06129317470 1.20536051565 0.00241240325 0.001 -0.001 0.002 C 4.76783866331 0.00148799420 0.00346798881 0.002 -0.000 -0.005 C 4.05723810074 -1.20352939940 0.00211502115 0.001 0.001 0.003 C 2.67108506586 -1.17139122066 0.00026591651 0.001 0.001 -0.005 C 1.82209539371 2.39842937406 -0.00175320633 0.004 0.000 0.002 C 2.33938959521 3.68993217240 -0.00584554905 0.007 -0.003 -0.000 C 1.45736908622 4.77231118002 -0.00917967851 -0.002 -0.010 0.002 C 0.08658913130 4.53522926787 -0.00833235387 -0.005 0.001 -0.001 C -0.35359617412 3.21325694137 -0.00400174376 -0.007 0.003 0.003 N 0.49290585413 2.18198449515 -0.00068475564 0.002 0.009 0.003 S 6.56718562933 -0.11349126889 0.00673479967 -0.002 0.000 0.000 C 1.82142022278 -2.39594383179 -0.00206827421 0.004 -0.001 0.002 C 2.33969079820 -3.68709653410 -0.00625612120 0.008 0.003 -0.000 C 1.45789786198 -4.76953179608 -0.00945089783 -0.002 0.011 0.002 C 0.08684213972 -4.53272927032 -0.00840538011 -0.006 -0.001 -0.001 C -0.35393854068 -3.21111942258 -0.00398541364 -0.007 -0.003 0.003 N 0.49225266031 -2.17934076887 -0.00084210065 0.002 -0.010 0.003 H 1.83694111827 5.77332096953 -0.01265611066 -0.001 -0.003 -0.001 H -0.61802819388 5.33967450634 -0.01131742088 0.001 0.002 -0.003 H 3.39175422949 3.87200638269 -0.00704552340 0.002 0.001 -0.003 H -1.39787683933 2.98334799634 -0.00369736757 -0.001 -0.001 -0.001 H 1.83794742242 -5.77033326187 -0.01295832570 -0.001 0.003 -0.001 H -0.61749414542 -5.33746053721 -0.01121572048 0.001 -0.003 -0.003 H -1.39833026435 -2.98175334118 -0.00345676225 -0.002 0.001 -0.001 H 3.39230213722 -3.86796714602 -0.00754158092 0.002 -0.001 -0.003 H 4.58301895157 2.13678100538 0.00314824260 0.000 -0.000 0.005 H 4.58784714512 -2.12983634010 0.00211631073 0.000 0.000 0.005 H -1.68997263563 -0.00719388386 -5.74925805817 0.037 0.001 0.109 H 0.75224758084 -0.00860493512 -5.25016290812 -0.038 -0.000 -0.082 H -3.29620044300 -0.00255800648 -3.88456579214 -0.067 0.000 -0.047 H 1.47161249279 -0.00457826661 -2.87685200854 0.059 0.001 0.051 H -1.69176120521 -0.00597000955 5.75026973076 -0.035 -0.001 0.101 H 0.75025791005 -0.00892914887 5.25161119224 0.036 0.000 -0.076 H 1.46975366817 -0.00523069331 2.87805400798 -0.055 -0.001 0.047 H -3.29750276746 -0.00099200484 3.88584245085 0.063 -0.000 -0.044 H -4.55513299541 0.00377930937 -2.13473279421 -0.012 -0.000 -0.008 H -4.55107479454 0.00501307822 2.13844314827 0.011 0.000 -0.008 H -6.83436893102 0.00806057203 1.19721860356 0.002 0.000 -0.001 H 6.86748209639 1.20005966818 0.00372860376 -0.000 -0.000 0.000 61 Mode 62: freq=722.64 N -0.44003451495 -0.00038510790 2.12369783068 0.001 0.129 0.001 C -1.76594470239 0.00039861437 2.37754210613 0.001 0.061 0.002 C -2.24923313135 -0.00145267054 3.67997125809 -0.002 0.132 0.001 C -1.33887502024 -0.00450793845 4.73956848945 -0.001 -0.100 -0.001 C 0.02462671625 -0.00591801736 4.46614405978 -0.000 0.151 -0.001 C 0.43187566201 -0.00376957955 3.13352499014 0.002 -0.121 -0.001 C -2.63984642995 0.00218980399 1.17162612704 0.001 -0.442 0.001 N -1.98513620489 0.00132140951 0.00153900685 -0.000 0.002 0.001 C -2.63911589169 0.00167522827 -1.17277445342 -0.001 0.441 0.001 C -4.02452897564 0.00329996303 -1.20791476641 -0.001 -0.074 -0.001 C -4.73391255267 0.00451580118 -0.00020876193 0.000 0.004 -0.000 C -4.02924140493 0.00399189729 1.20660077672 0.001 0.068 -0.001 Co 0.00000000000 0.00000000000 0.00000000000 0.000 -0.000 0.000 N -0.43839318333 -0.00054206762 -2.12229806799 -0.001 -0.128 0.001 C -1.76408906064 -0.00030645034 -2.37697009192 -0.000 -0.061 0.001 C -2.24773885821 -0.00257631963 -3.67934971086 0.002 -0.130 0.001 C -1.33713102227 -0.00526459193 -4.73855802198 0.001 0.099 -0.001 C 0.02654101484 -0.00591797621 -4.46472703619 0.000 -0.150 -0.001 C 0.43371721952 -0.00363389350 -3.13225443930 -0.002 0.121 -0.001 S -6.53329279136 0.00637481657 -0.11611178087 0.000 -0.005 -0.000 N 2.00981687167 0.00259443239 -0.00000686048 0.000 -0.001 -0.001 C 2.67119656792 1.17263645248 0.00045766926 0.001 -0.001 0.276 C 4.06129317470 1.20536051565 0.00241240325 0.001 0.001 -0.042 C 4.76783866331 0.00148799420 0.00346798881 -0.000 0.000 -0.002 C 4.05723810074 -1.20352939940 0.00211502115 -0.001 0.001 0.046 C 2.67108506586 -1.17139122066 0.00026591651 -0.001 -0.001 -0.275 C 1.82209539371 2.39842937406 -0.00175320633 0.000 -0.001 -0.036 C 2.33938959521 3.68993217240 -0.00584554905 -0.001 -0.001 -0.085 C 1.45736908622 4.77231118002 -0.00917967851 -0.000 0.001 0.063 C 0.08658913130 4.53522926787 -0.00833235387 -0.000 0.001 -0.094 C -0.35359617412 3.21325694137 -0.00400174376 0.002 0.001 0.074 N 0.49290585413 2.18198449515 -0.00068475564 0.001 -0.001 -0.077 S 6.56718562933 -0.11349126889 0.00673479967 -0.000 0.000 0.003 C 1.82142022278 -2.39594383179 -0.00206827421 -0.000 -0.001 0.036 C 2.33969079820 -3.68709653410 -0.00625612120 0.001 -0.001 0.083 C 1.45789786198 -4.76953179608 -0.00945089783 0.000 0.001 -0.063 C 0.08684213972 -4.53272927032 -0.00840538011 0.000 0.001 0.094 C -0.35393854068 -3.21111942258 -0.00398541364 -0.001 0.001 -0.074 N 0.49225266031 -2.17934076887 -0.00084210065 -0.001 -0.001 0.077 H 1.83694111827 5.77332096953 -0.01265611066 0.000 0.000 0.097 H -0.61802819388 5.33967450634 -0.01131742088 -0.000 0.000 -0.007 H 3.39175422949 3.87200638269 -0.00704552340 -0.000 0.000 0.019 H -1.39787683933 2.98334799634 -0.00369736757 0.000 0.000 0.102 H 1.83794742242 -5.77033326187 -0.01295832570 -0.000 0.000 -0.096 H -0.61749414542 -5.33746053721 -0.01121572048 0.000 0.000 0.007 H -1.39833026435 -2.98175334118 -0.00345676225 -0.000 0.000 -0.102 H 3.39230213722 -3.86796714602 -0.00754158092 0.000 0.000 -0.019 H 4.58301895157 2.13678100538 0.00314824260 0.000 0.000 -0.098 H 4.58784714512 -2.12983634010 0.00211631073 -0.000 0.000 0.096 H -1.68997263563 -0.00719388386 -5.74925805817 -0.000 0.153 -0.000 H 0.75224758084 -0.00860493512 -5.25016290812 0.000 -0.010 -0.000 H -3.29620044300 -0.00255800648 -3.88456579214 0.001 0.032 -0.000 H 1.47161249279 -0.00457826661 -2.87685200854 -0.000 0.163 -0.000 H -1.69176120521 -0.00597000955 5.75026973076 0.000 -0.154 -0.000 H 0.75025791005 -0.00892914887 5.25161119224 -0.000 0.010 -0.000 H 1.46975366817 -0.00523069331 2.87805400798 0.000 -0.164 -0.000 H -3.29750276746 -0.00099200484 3.88584245085 -0.001 -0.033 -0.000 H -4.55513299541 0.00377930937 -2.13473279421 -0.000 -0.153 -0.000 H -4.55107479454 0.00501307822 2.13844314827 0.000 0.157 -0.000 H -6.83436893102 0.00806057203 1.19721860356 -0.000 0.024 -0.000 H 6.86748209639 1.20005966818 0.00372860376 -0.000 -0.000 -0.015 61 Mode 63: freq=726.16 N -0.44003451495 -0.00038510790 2.12369783068 -0.001 -0.084 -0.001 C -1.76594470239 0.00039861437 2.37754210613 -0.001 -0.044 -0.002 C -2.24923313135 -0.00145267054 3.67997125809 0.002 -0.078 -0.001 C -1.33887502024 -0.00450793845 4.73956848945 0.001 0.058 0.001 C 0.02462671625 -0.00591801736 4.46614405978 0.001 -0.091 0.002 C 0.43187566201 -0.00376957955 3.13352499014 -0.002 0.077 0.001 C -2.63984642995 0.00218980399 1.17162612704 -0.001 0.277 -0.001 N -1.98513620489 0.00132140951 0.00153900685 0.000 -0.001 -0.001 C -2.63911589169 0.00167522827 -1.17277445342 0.001 -0.276 -0.001 C -4.02452897564 0.00329996303 -1.20791476641 0.002 0.044 0.001 C -4.73391255267 0.00451580118 -0.00020876193 -0.000 -0.002 0.001 C -4.02924140493 0.00399189729 1.20660077672 -0.002 -0.041 0.001 Co 0.00000000000 0.00000000000 0.00000000000 -0.000 -0.000 0.000 N -0.43839318333 -0.00054206762 -2.12229806799 0.001 0.084 -0.000 C -1.76408906064 -0.00030645034 -2.37697009192 0.001 0.044 -0.002 C -2.24773885821 -0.00257631963 -3.67934971086 -0.002 0.077 -0.001 C -1.33713102227 -0.00526459193 -4.73855802198 -0.001 -0.058 0.000 C 0.02654101484 -0.00591797621 -4.46472703619 -0.001 0.090 0.002 C 0.43371721952 -0.00363389350 -3.13225443930 0.002 -0.077 0.001 S -6.53329279136 0.00637481657 -0.11611178087 -0.000 0.003 0.000 N 2.00981687167 0.00259443239 -0.00000686048 -0.000 -0.001 -0.002 C 2.67119656792 1.17263645248 0.00045766926 0.002 -0.002 0.445 C 4.06129317470 1.20536051565 0.00241240325 0.003 0.002 -0.065 C 4.76783866331 0.00148799420 0.00346798881 0.000 0.001 -0.003 C 4.05723810074 -1.20352939940 0.00211502115 -0.003 0.002 0.071 C 2.67108506586 -1.17139122066 0.00026591651 -0.002 -0.002 -0.444 C 1.82209539371 2.39842937406 -0.00175320633 0.002 -0.004 -0.066 C 2.33938959521 3.68993217240 -0.00584554905 -0.004 -0.002 -0.129 C 1.45736908622 4.77231118002 -0.00917967851 -0.002 0.001 0.095 C 0.08658913130 4.53522926787 -0.00833235387 -0.002 0.003 -0.146 C -0.35359617412 3.21325694137 -0.00400174376 0.004 0.002 0.120 N 0.49290585413 2.18198449515 -0.00068475564 0.002 -0.001 -0.131 S 6.56718562933 -0.11349126889 0.00673479967 -0.000 0.000 0.005 C 1.82142022278 -2.39594383179 -0.00206827421 -0.001 -0.004 0.066 C 2.33969079820 -3.68709653410 -0.00625612120 0.004 -0.002 0.127 C 1.45789786198 -4.76953179608 -0.00945089783 0.002 0.001 -0.094 C 0.08684213972 -4.53272927032 -0.00840538011 0.002 0.003 0.145 C -0.35393854068 -3.21111942258 -0.00398541364 -0.004 0.002 -0.120 N 0.49225266031 -2.17934076887 -0.00084210065 -0.002 -0.001 0.131 H 1.83694111827 5.77332096953 -0.01265611066 0.001 0.000 0.152 H -0.61802819388 5.33967450634 -0.01131742088 -0.001 0.001 -0.007 H 3.39175422949 3.87200638269 -0.00704552340 -0.001 0.000 0.038 H -1.39787683933 2.98334799634 -0.00369736757 0.001 0.001 0.162 H 1.83794742242 -5.77033326187 -0.01295832570 -0.001 0.000 -0.151 H -0.61749414542 -5.33746053721 -0.01121572048 0.001 0.001 0.008 H -1.39833026435 -2.98175334118 -0.00345676225 -0.001 0.001 -0.161 H 3.39230213722 -3.86796714602 -0.00754158092 0.001 0.000 -0.038 H 4.58301895157 2.13678100538 0.00314824260 0.001 0.001 -0.161 H 4.58784714512 -2.12983634010 0.00211631073 -0.001 0.001 0.156 H -1.68997263563 -0.00719388386 -5.74925805817 0.000 -0.093 -0.000 H 0.75224758084 -0.00860493512 -5.25016290812 -0.001 0.005 0.000 H -3.29620044300 -0.00255800648 -3.88456579214 -0.001 -0.025 0.000 H 1.47161249279 -0.00457826661 -2.87685200854 0.000 -0.100 0.000 H -1.69176120521 -0.00597000955 5.75026973076 -0.000 0.094 0.000 H 0.75025791005 -0.00892914887 5.25161119224 0.001 -0.005 0.000 H 1.46975366817 -0.00523069331 2.87805400798 -0.000 0.100 0.000 H -3.29750276746 -0.00099200484 3.88584245085 0.001 0.025 0.000 H -4.55513299541 0.00377930937 -2.13473279421 0.000 0.097 0.000 H -4.55107479454 0.00501307822 2.13844314827 -0.000 -0.100 0.000 H -6.83436893102 0.00806057203 1.19721860356 0.000 -0.015 0.000 H 6.86748209639 1.20005966818 0.00372860376 -0.000 0.000 -0.024 61 Mode 64: freq=731.79 N -0.44003451495 -0.00038510790 2.12369783068 -0.126 0.002 0.006 C -1.76594470239 0.00039861437 2.37754210613 -0.128 0.001 -0.232 C -2.24923313135 -0.00145267054 3.67997125809 0.216 0.001 -0.167 C -1.33887502024 -0.00450793845 4.73956848945 0.131 -0.001 -0.036 C 0.02462671625 -0.00591801736 4.46614405978 0.146 0.001 0.256 C 0.43187566201 -0.00376957955 3.13352499014 -0.199 -0.001 0.130 C -2.63984642995 0.00218980399 1.17162612704 -0.218 -0.004 -0.149 N -1.98513620489 0.00132140951 0.00153900685 0.004 -0.000 -0.065 C -2.63911589169 0.00167522827 -1.17277445342 0.220 0.004 -0.143 C -4.02452897564 0.00329996303 -1.20791476641 0.232 -0.001 0.163 C -4.73391255267 0.00451580118 -0.00020876193 -0.006 0.000 0.086 C -4.02924140493 0.00399189729 1.20660077672 -0.231 0.001 0.155 Co 0.00000000000 0.00000000000 0.00000000000 -0.001 -0.000 -0.023 N -0.43839318333 -0.00054206762 -2.12229806799 0.126 -0.001 0.011 C -1.76408906064 -0.00030645034 -2.37697009192 0.129 -0.001 -0.228 C -2.24773885821 -0.00257631963 -3.67934971086 -0.209 -0.001 -0.167 C -1.33713102227 -0.00526459193 -4.73855802198 -0.130 0.001 -0.042 C 0.02654101484 -0.00591797621 -4.46472703619 -0.146 -0.001 0.252 C 0.43371721952 -0.00363389350 -3.13225443930 0.193 0.001 0.130 S -6.53329279136 0.00637481657 -0.11611178087 -0.003 -0.000 0.027 N 2.00981687167 0.00259443239 -0.00000686048 -0.000 -0.001 -0.002 C 2.67119656792 1.17263645248 0.00045766926 0.002 -0.002 0.003 C 4.06129317470 1.20536051565 0.00241240325 0.002 0.001 -0.006 C 4.76783866331 0.00148799420 0.00346798881 0.000 0.001 0.013 C 4.05723810074 -1.20352939940 0.00211502115 -0.002 0.002 -0.007 C 2.67108506586 -1.17139122066 0.00026591651 -0.002 -0.001 0.006 C 1.82209539371 2.39842937406 -0.00175320633 0.001 -0.003 0.004 C 2.33938959521 3.68993217240 -0.00584554905 -0.003 -0.002 -0.003 C 1.45736908622 4.77231118002 -0.00917967851 -0.001 0.000 0.002 C 0.08658913130 4.53522926787 -0.00833235387 -0.001 0.003 -0.002 C -0.35359617412 3.21325694137 -0.00400174376 0.003 0.001 -0.000 N 0.49290585413 2.18198449515 -0.00068475564 0.001 -0.000 0.002 S 6.56718562933 -0.11349126889 0.00673479967 -0.000 0.000 -0.001 C 1.82142022278 -2.39594383179 -0.00206827421 -0.001 -0.002 0.004 C 2.33969079820 -3.68709653410 -0.00625612120 0.001 -0.001 -0.004 C 1.45789786198 -4.76953179608 -0.00945089783 0.001 -0.001 0.003 C 0.08684213972 -4.53272927032 -0.00840538011 0.001 0.002 -0.003 C -0.35393854068 -3.21111942258 -0.00398541364 -0.001 0.001 0.001 N 0.49225266031 -2.17934076887 -0.00084210065 -0.001 0.001 0.001 H 1.83694111827 5.77332096953 -0.01265611066 0.001 -0.000 0.002 H -0.61802819388 5.33967450634 -0.01131742088 -0.001 0.000 -0.000 H 3.39175422949 3.87200638269 -0.00704552340 -0.001 -0.000 -0.002 H -1.39787683933 2.98334799634 -0.00369736757 0.001 0.000 0.000 H 1.83794742242 -5.77033326187 -0.01295832570 -0.000 -0.001 0.003 H -0.61749414542 -5.33746053721 -0.01121572048 0.000 0.001 -0.000 H -1.39833026435 -2.98175334118 -0.00345676225 -0.000 -0.000 0.002 H 3.39230213722 -3.86796714602 -0.00754158092 0.001 0.000 -0.001 H 4.58301895157 2.13678100538 0.00314824260 0.000 0.001 -0.007 H 4.58784714512 -2.12983634010 0.00211631073 -0.001 0.001 -0.008 H -1.68997263563 -0.00719388386 -5.74925805817 0.055 0.001 -0.045 H 0.75224758084 -0.00860493512 -5.25016290812 -0.061 0.000 0.057 H -3.29620044300 -0.00255800648 -3.88456579214 -0.071 0.000 0.002 H 1.47161249279 -0.00457826661 -2.87685200854 0.065 0.002 0.001 H -1.69176120521 -0.00597000955 5.75026973076 -0.057 -0.001 -0.044 H 0.75025791005 -0.00892914887 5.25161119224 0.063 -0.000 0.057 H 1.46975366817 -0.00523069331 2.87805400798 -0.067 -0.002 0.002 H -3.29750276746 -0.00099200484 3.88584245085 0.073 -0.001 0.002 H -4.55513299541 0.00377930937 -2.13473279421 0.048 -0.002 0.059 H -4.55107479454 0.00501307822 2.13844314827 -0.043 0.002 0.060 H -6.83436893102 0.00806057203 1.19721860356 0.015 0.000 0.008 H 6.86748209639 1.20005966818 0.00372860376 -0.000 0.000 -0.001 61 Mode 65: freq=731.85 N -0.44003451495 -0.00038510790 2.12369783068 -0.001 -0.002 0.001 C -1.76594470239 0.00039861437 2.37754210613 -0.001 -0.004 -0.002 C -2.24923313135 -0.00145267054 3.67997125809 0.001 0.003 -0.002 C -1.33887502024 -0.00450793845 4.73956848945 0.001 -0.002 -0.001 C 0.02462671625 -0.00591801736 4.46614405978 0.002 0.002 0.002 C 0.43187566201 -0.00376957955 3.13352499014 -0.001 0.000 0.001 C -2.63984642995 0.00218980399 1.17162612704 -0.002 -0.002 -0.001 N -1.98513620489 0.00132140951 0.00153900685 -0.000 0.001 -0.001 C -2.63911589169 0.00167522827 -1.17277445342 0.002 -0.006 -0.002 C -4.02452897564 0.00329996303 -1.20791476641 0.002 0.007 0.002 C -4.73391255267 0.00451580118 -0.00020876193 0.000 -0.013 0.001 C -4.02924140493 0.00399189729 1.20660077672 -0.002 0.006 0.002 Co 0.00000000000 0.00000000000 0.00000000000 -0.001 0.020 -0.000 N -0.43839318333 -0.00054206762 -2.12229806799 0.001 -0.001 -0.001 C -1.76408906064 -0.00030645034 -2.37697009192 0.001 -0.004 -0.003 C -2.24773885821 -0.00257631963 -3.67934971086 -0.003 0.004 -0.002 C -1.33713102227 -0.00526459193 -4.73855802198 -0.001 -0.003 0.000 C 0.02654101484 -0.00591797621 -4.46472703619 -0.001 0.003 0.003 C 0.43371721952 -0.00363389350 -3.13225443930 0.003 -0.001 0.001 S -6.53329279136 0.00637481657 -0.11611178087 -0.000 0.001 0.000 N 2.00981687167 0.00259443239 -0.00000686048 0.004 0.067 0.000 C 2.67119656792 1.17263645248 0.00045766926 -0.217 0.151 0.007 C 4.06129317470 1.20536051565 0.00241240325 -0.232 -0.156 -0.001 C 4.76783866331 0.00148799420 0.00346798881 -0.006 -0.085 0.000 C 4.05723810074 -1.20352939940 0.00211502115 0.232 -0.163 0.001 C 2.67108506586 -1.17139122066 0.00026591651 0.219 0.145 -0.007 C 1.82209539371 2.39842937406 -0.00175320633 -0.123 0.235 -0.002 C 2.33938959521 3.68993217240 -0.00584554905 0.221 0.161 -0.003 C 1.45736908622 4.77231118002 -0.00917967851 0.132 0.030 0.001 C 0.08658913130 4.53522926787 -0.00833235387 0.138 -0.258 -0.002 C -0.35359617412 3.21325694137 -0.00400174376 -0.205 -0.123 0.002 N 0.49290585413 2.18198449515 -0.00068475564 -0.126 -0.001 -0.002 S 6.56718562933 -0.11349126889 0.00673479967 -0.003 -0.027 0.000 C 1.82142022278 -2.39594383179 -0.00206827421 0.123 0.231 0.002 C 2.33969079820 -3.68709653410 -0.00625612120 -0.214 0.160 0.003 C 1.45789786198 -4.76953179608 -0.00945089783 -0.131 0.036 -0.001 C 0.08684213972 -4.53272927032 -0.00840538011 -0.138 -0.255 0.002 C -0.35393854068 -3.21111942258 -0.00398541364 0.198 -0.123 -0.002 N 0.49225266031 -2.17934076887 -0.00084210065 0.126 -0.006 0.002 H 1.83694111827 5.77332096953 -0.01265611066 -0.055 0.044 0.002 H -0.61802819388 5.33967450634 -0.01131742088 0.062 -0.057 0.000 H 3.39175422949 3.87200638269 -0.00704552340 0.074 -0.004 0.001 H -1.39787683933 2.98334799634 -0.00369736757 -0.068 -0.001 0.003 H 1.83794742242 -5.77033326187 -0.01295832570 0.054 0.046 -0.002 H -0.61749414542 -5.33746053721 -0.01121572048 -0.060 -0.058 -0.000 H -1.39833026435 -2.98175334118 -0.00345676225 0.066 0.000 -0.003 H 3.39230213722 -3.86796714602 -0.00754158092 -0.072 -0.004 -0.001 H 4.58301895157 2.13678100538 0.00314824260 -0.043 -0.060 -0.003 H 4.58784714512 -2.12983634010 0.00211631073 0.048 -0.059 0.002 H -1.68997263563 -0.00719388386 -5.74925805817 0.001 -0.003 -0.000 H 0.75224758084 -0.00860493512 -5.25016290812 -0.001 0.000 0.000 H -3.29620044300 -0.00255800648 -3.88456579214 -0.001 0.001 -0.000 H 1.47161249279 -0.00457826661 -2.87685200854 0.001 -0.002 0.000 H -1.69176120521 -0.00597000955 5.75026973076 -0.000 -0.002 -0.001 H 0.75025791005 -0.00892914887 5.25161119224 0.000 0.000 0.001 H 1.46975366817 -0.00523069331 2.87805400798 -0.000 -0.000 -0.000 H -3.29750276746 -0.00099200484 3.88584245085 0.000 0.002 0.000 H -4.55513299541 0.00377930937 -2.13473279421 0.000 0.008 0.001 H -4.55107479454 0.00501307822 2.13844314827 -0.000 0.006 0.001 H -6.83436893102 0.00806057203 1.19721860356 0.000 0.001 0.000 H 6.86748209639 1.20005966818 0.00372860376 0.015 -0.008 -0.000 61 Mode 66: freq=759.85 N -0.44003451495 -0.00038510790 2.12369783068 0.098 -0.000 0.009 C -1.76594470239 0.00039861437 2.37754210613 0.075 -0.000 0.136 C -2.24923313135 -0.00145267054 3.67997125809 -0.139 -0.000 0.107 C -1.33887502024 -0.00450793845 4.73956848945 -0.082 0.000 0.019 C 0.02462671625 -0.00591801736 4.46614405978 -0.083 0.000 -0.148 C 0.43187566201 -0.00376957955 3.13352499014 0.160 -0.000 -0.063 C -2.63984642995 0.00218980399 1.17162612704 0.011 0.000 0.111 N -1.98513620489 0.00132140951 0.00153900685 -0.103 0.000 0.001 C -2.63911589169 0.00167522827 -1.17277445342 0.014 -0.000 -0.112 C -4.02452897564 0.00329996303 -1.20791476641 -0.004 0.000 -0.091 C -4.73391255267 0.00451580118 -0.00020876193 0.082 -0.000 0.001 C -4.02924140493 0.00399189729 1.20660077672 -0.006 0.000 0.094 Co 0.00000000000 0.00000000000 0.00000000000 -0.004 -0.000 -0.000 N -0.43839318333 -0.00054206762 -2.12229806799 0.100 0.000 -0.008 C -1.76408906064 -0.00030645034 -2.37697009192 0.077 -0.000 -0.139 C -2.24773885821 -0.00257631963 -3.67934971086 -0.141 -0.000 -0.109 C -1.33713102227 -0.00526459193 -4.73855802198 -0.083 0.000 -0.021 C 0.02654101484 -0.00591797621 -4.46472703619 -0.086 0.000 0.151 C 0.43371721952 -0.00363389350 -3.13225443930 0.162 -0.000 0.064 S -6.53329279136 0.00637481657 -0.11611178087 -0.049 0.000 -0.002 N 2.00981687167 0.00259443239 -0.00000686048 0.140 0.001 0.000 C 2.67119656792 1.17263645248 0.00045766926 -0.018 0.152 -0.000 C 4.06129317470 1.20536051565 0.00241240325 0.004 0.128 0.000 C 4.76783866331 0.00148799420 0.00346798881 -0.117 0.002 -0.000 C 4.05723810074 -1.20352939940 0.00211502115 0.001 -0.123 0.000 C 2.67108506586 -1.17139122066 0.00026591651 -0.021 -0.154 -0.000 C 1.82209539371 2.39842937406 -0.00175320633 -0.103 0.188 -0.001 C 2.33938959521 3.68993217240 -0.00584554905 0.188 0.141 -0.000 C 1.45736908622 4.77231118002 -0.00917967851 0.114 0.026 -0.000 C 0.08658913130 4.53522926787 -0.00833235387 0.112 -0.209 0.001 C -0.35359617412 3.21325694137 -0.00400174376 -0.215 -0.083 0.000 N 0.49290585413 2.18198449515 -0.00068475564 -0.132 0.011 0.000 S 6.56718562933 -0.11349126889 0.00673479967 0.070 -0.002 0.000 C 1.82142022278 -2.39594383179 -0.00206827421 -0.105 -0.192 -0.001 C 2.33969079820 -3.68709653410 -0.00625612120 0.192 -0.144 -0.000 C 1.45789786198 -4.76953179608 -0.00945089783 0.117 -0.029 -0.000 C 0.08684213972 -4.53272927032 -0.00840538011 0.115 0.213 0.001 C -0.35393854068 -3.21111942258 -0.00398541364 -0.219 0.085 0.000 N 0.49225266031 -2.17934076887 -0.00084210065 -0.136 -0.010 0.000 H 1.83694111827 5.77332096953 -0.01265611066 -0.048 0.039 -0.000 H -0.61802819388 5.33967450634 -0.01131742088 0.059 -0.038 0.000 H 3.39175422949 3.87200638269 -0.00704552340 0.062 0.001 0.000 H -1.39787683933 2.98334799634 -0.00369736757 -0.070 0.008 -0.000 H 1.83794742242 -5.77033326187 -0.01295832570 -0.049 -0.040 -0.000 H -0.61749414542 -5.33746053721 -0.01121572048 0.060 0.040 0.000 H -1.39833026435 -2.98175334118 -0.00345676225 -0.072 -0.009 -0.000 H 3.39230213722 -3.86796714602 -0.00754158092 0.063 -0.001 -0.000 H 4.58301895157 2.13678100538 0.00314824260 0.044 0.014 0.000 H 4.58784714512 -2.12983634010 0.00211631073 0.045 -0.011 0.000 H -1.68997263563 -0.00719388386 -5.74925805817 0.037 -0.000 -0.028 H 0.75224758084 -0.00860493512 -5.25016290812 -0.045 0.000 0.026 H -3.29620044300 -0.00255800648 -3.88456579214 -0.047 0.000 -0.003 H 1.47161249279 -0.00457826661 -2.87685200854 0.053 -0.000 -0.004 H -1.69176120521 -0.00597000955 5.75026973076 0.037 -0.000 0.027 H 0.75025791005 -0.00892914887 5.25161119224 -0.044 0.000 -0.025 H 1.46975366817 -0.00523069331 2.87805400798 0.052 -0.000 0.004 H -3.29750276746 -0.00099200484 3.88584245085 -0.046 0.000 0.003 H -4.55513299541 0.00377930937 -2.13473279421 -0.033 0.000 -0.009 H -4.55107479454 0.00501307822 2.13844314827 -0.033 0.000 0.011 H -6.83436893102 0.00806057203 1.19721860356 -0.006 -0.000 0.001 H 6.86748209639 1.20005966818 0.00372860376 0.008 0.001 0.000 61 Mode 67: freq=763.87 N -0.44003451495 -0.00038510790 2.12369783068 -0.134 0.000 -0.012 C -1.76594470239 0.00039861437 2.37754210613 -0.102 0.001 -0.184 C -2.24923313135 -0.00145267054 3.67997125809 0.189 0.000 -0.148 C -1.33887502024 -0.00450793845 4.73956848945 0.110 -0.000 -0.026 C 0.02462671625 -0.00591801736 4.46614405978 0.113 -0.001 0.206 C 0.43187566201 -0.00376957955 3.13352499014 -0.217 0.000 0.086 C -2.63984642995 0.00218980399 1.17162612704 -0.009 -0.000 -0.150 N -1.98513620489 0.00132140951 0.00153900685 0.141 -0.000 -0.001 C -2.63911589169 0.00167522827 -1.17277445342 -0.012 0.000 0.151 C -4.02452897564 0.00329996303 -1.20791476641 0.015 -0.000 0.126 C -4.73391255267 0.00451580118 -0.00020876193 -0.107 0.000 -0.001 C -4.02924140493 0.00399189729 1.20660077672 0.018 -0.000 -0.129 Co 0.00000000000 0.00000000000 0.00000000000 -0.063 -0.000 0.000 N -0.43839318333 -0.00054206762 -2.12229806799 -0.136 -0.000 0.011 C -1.76408906064 -0.00030645034 -2.37697009192 -0.104 0.001 0.187 C -2.24773885821 -0.00257631963 -3.67934971086 0.192 0.000 0.151 C -1.33713102227 -0.00526459193 -4.73855802198 0.112 0.000 0.028 C 0.02654101484 -0.00591797621 -4.46472703619 0.115 -0.001 -0.209 C 0.43371721952 -0.00363389350 -3.13225443930 -0.220 0.000 -0.087 S -6.53329279136 0.00637481657 -0.11611178087 0.059 -0.000 0.002 N 2.00981687167 0.00259443239 -0.00000686048 0.101 0.001 0.000 C 2.67119656792 1.17263645248 0.00045766926 -0.008 0.109 -0.000 C 4.06129317470 1.20536051565 0.00241240325 0.011 0.093 0.000 C 4.76783866331 0.00148799420 0.00346798881 -0.080 0.001 -0.000 C 4.05723810074 -1.20352939940 0.00211502115 0.009 -0.090 0.000 C 2.67108506586 -1.17139122066 0.00026591651 -0.009 -0.110 -0.000 C 1.82209539371 2.39842937406 -0.00175320633 -0.071 0.137 -0.001 C 2.33938959521 3.68993217240 -0.00584554905 0.143 0.105 -0.000 C 1.45736908622 4.77231118002 -0.00917967851 0.082 0.014 -0.000 C 0.08658913130 4.53522926787 -0.00833235387 0.078 -0.154 0.001 C -0.35359617412 3.21325694137 -0.00400174376 -0.161 -0.058 0.000 N 0.49290585413 2.18198449515 -0.00068475564 -0.096 0.013 0.000 S 6.56718562933 -0.11349126889 0.00673479967 0.045 -0.001 0.000 C 1.82142022278 -2.39594383179 -0.00206827421 -0.073 -0.139 -0.001 C 2.33969079820 -3.68709653410 -0.00625612120 0.145 -0.107 -0.000 C 1.45789786198 -4.76953179608 -0.00945089783 0.083 -0.015 -0.000 C 0.08684213972 -4.53272927032 -0.00840538011 0.079 0.156 0.001 C -0.35393854068 -3.21111942258 -0.00398541364 -0.163 0.059 0.000 N 0.49225266031 -2.17934076887 -0.00084210065 -0.098 -0.012 0.000 H 1.83694111827 5.77332096953 -0.01265611066 -0.037 0.027 -0.000 H -0.61802819388 5.33967450634 -0.01131742088 0.043 -0.027 0.000 H 3.39175422949 3.87200638269 -0.00704552340 0.047 0.003 0.000 H -1.39787683933 2.98334799634 -0.00369736757 -0.053 0.008 -0.000 H 1.83794742242 -5.77033326187 -0.01295832570 -0.038 -0.028 -0.000 H -0.61749414542 -5.33746053721 -0.01121572048 0.044 0.028 0.000 H -1.39833026435 -2.98175334118 -0.00345676225 -0.054 -0.008 -0.000 H 3.39230213722 -3.86796714602 -0.00754158092 0.047 -0.003 -0.000 H 4.58301895157 2.13678100538 0.00314824260 0.035 0.010 0.000 H 4.58784714512 -2.12983634010 0.00211631073 0.035 -0.008 0.000 H -1.68997263563 -0.00719388386 -5.74925805817 -0.053 0.000 0.038 H 0.75224758084 -0.00860493512 -5.25016290812 0.060 -0.000 -0.037 H -3.29620044300 -0.00255800648 -3.88456579214 0.064 -0.000 0.005 H 1.47161249279 -0.00457826661 -2.87685200854 -0.073 0.000 0.009 H -1.69176120521 -0.00597000955 5.75026973076 -0.052 0.000 -0.037 H 0.75025791005 -0.00892914887 5.25161119224 0.059 -0.000 0.036 H 1.46975366817 -0.00523069331 2.87805400798 -0.072 0.000 -0.009 H -3.29750276746 -0.00099200484 3.88584245085 0.063 -0.000 -0.005 H -4.55513299541 0.00377930937 -2.13473279421 0.049 -0.000 0.012 H -4.55107479454 0.00501307822 2.13844314827 0.049 -0.000 -0.014 H -6.83436893102 0.00806057203 1.19721860356 0.008 0.000 -0.001 H 6.86748209639 1.20005966818 0.00372860376 0.006 0.001 0.000 61 Mode 68: freq=850.59 N -0.44003451495 -0.00038510790 2.12369783068 -0.000 -0.176 -0.000 C -1.76594470239 0.00039861437 2.37754210613 0.000 0.207 0.000 C -2.24923313135 -0.00145267054 3.67997125809 0.000 -0.154 -0.001 C -1.33887502024 -0.00450793845 4.73956848945 0.000 0.056 -0.000 C 0.02462671625 -0.00591801736 4.46614405978 -0.000 -0.132 0.000 C 0.43187566201 -0.00376957955 3.13352499014 0.000 0.079 0.000 C -2.63984642995 0.00218980399 1.17162612704 0.000 0.344 0.001 N -1.98513620489 0.00132140951 0.00153900685 -0.001 -0.431 0.000 C -2.63911589169 0.00167522827 -1.17277445342 0.001 0.343 0.000 C -4.02452897564 0.00329996303 -1.20791476641 0.001 -0.135 0.000 C -4.73391255267 0.00451580118 -0.00020876193 0.000 0.174 -0.000 C -4.02924140493 0.00399189729 1.20660077672 -0.001 -0.122 0.000 Co 0.00000000000 0.00000000000 0.00000000000 0.000 0.033 -0.002 N -0.43839318333 -0.00054206762 -2.12229806799 -0.000 -0.192 0.000 C -1.76408906064 -0.00030645034 -2.37697009192 -0.000 0.222 -0.001 C -2.24773885821 -0.00257631963 -3.67934971086 -0.001 -0.157 -0.000 C -1.33713102227 -0.00526459193 -4.73855802198 -0.000 0.066 -0.000 C 0.02654101484 -0.00591797621 -4.46472703619 -0.000 -0.137 0.001 C 0.43371721952 -0.00363389350 -3.13225443930 0.000 0.089 0.000 S -6.53329279136 0.00637481657 -0.11611178087 -0.000 0.002 0.000 N 2.00981687167 0.00259443239 -0.00000686048 -0.000 -0.004 0.030 C 2.67119656792 1.17263645248 0.00045766926 -0.003 -0.005 -0.025 C 4.06129317470 1.20536051565 0.00241240325 -0.010 -0.002 0.008 C 4.76783866331 0.00148799420 0.00346798881 -0.000 0.001 -0.012 C 4.05723810074 -1.20352939940 0.00211502115 0.010 -0.002 0.009 C 2.67108506586 -1.17139122066 0.00026591651 0.003 -0.006 -0.024 C 1.82209539371 2.39842937406 -0.00175320633 0.004 0.001 -0.012 C 2.33938959521 3.68993217240 -0.00584554905 0.007 0.006 0.010 C 1.45736908622 4.77231118002 -0.00917967851 0.000 0.001 -0.002 C 0.08658913130 4.53522926787 -0.00833235387 0.001 -0.006 0.009 C -0.35359617412 3.21325694137 -0.00400174376 -0.001 -0.001 -0.004 N 0.49290585413 2.18198449515 -0.00068475564 -0.001 -0.001 0.010 S 6.56718562933 -0.11349126889 0.00673479967 -0.001 -0.000 -0.000 C 1.82142022278 -2.39594383179 -0.00206827421 -0.004 0.002 -0.017 C 2.33969079820 -3.68709653410 -0.00625612120 -0.007 0.006 0.011 C 1.45789786198 -4.76953179608 -0.00945089783 -0.000 0.002 -0.006 C 0.08684213972 -4.53272927032 -0.00840538011 -0.001 -0.006 0.010 C -0.35393854068 -3.21111942258 -0.00398541364 0.001 -0.001 -0.007 N 0.49225266031 -2.17934076887 -0.00084210065 0.001 -0.002 0.014 H 1.83694111827 5.77332096953 -0.01265611066 -0.003 0.002 -0.012 H -0.61802819388 5.33967450634 -0.01131742088 -0.000 -0.002 -0.007 H 3.39175422949 3.87200638269 -0.00704552340 0.002 0.003 -0.004 H -1.39787683933 2.98334799634 -0.00369736757 -0.001 0.003 -0.011 H 1.83794742242 -5.77033326187 -0.01295832570 0.003 0.002 -0.009 H -0.61749414542 -5.33746053721 -0.01121572048 0.000 -0.002 -0.002 H -1.39833026435 -2.98175334118 -0.00345676225 0.001 0.003 -0.011 H 3.39230213722 -3.86796714602 -0.00754158092 -0.002 0.003 0.002 H 4.58301895157 2.13678100538 0.00314824260 -0.004 0.000 0.020 H 4.58784714512 -2.12983634010 0.00211631073 0.004 0.000 0.018 H -1.68997263563 -0.00719388386 -5.74925805817 0.000 0.148 -0.000 H 0.75224758084 -0.00860493512 -5.25016290812 0.000 0.052 0.000 H -3.29620044300 -0.00255800648 -3.88456579214 -0.000 -0.007 -0.000 H 1.47161249279 -0.00457826661 -2.87685200854 0.000 0.161 -0.001 H -1.69176120521 -0.00597000955 5.75026973076 0.000 0.153 0.000 H 0.75025791005 -0.00892914887 5.25161119224 0.000 0.065 0.000 H 1.46975366817 -0.00523069331 2.87805400798 0.000 0.158 0.000 H -3.29750276746 -0.00099200484 3.88584245085 0.000 0.010 -0.000 H -4.55513299541 0.00377930937 -2.13473279421 -0.000 -0.255 0.000 H -4.55107479454 0.00501307822 2.13844314827 -0.001 -0.272 0.000 H -6.83436893102 0.00806057203 1.19721860356 0.000 -0.003 0.000 H 6.86748209639 1.20005966818 0.00372860376 0.004 -0.001 0.000 61 Mode 69: freq=850.67 N -0.44003451495 -0.00038510790 2.12369783068 -0.001 0.014 0.002 C -1.76594470239 0.00039861437 2.37754210613 0.003 -0.017 -0.001 C -2.24923313135 -0.00145267054 3.67997125809 0.005 0.011 -0.006 C -1.33887502024 -0.00450793845 4.73956848945 0.000 -0.005 -0.002 C 0.02462671625 -0.00591801736 4.46614405978 0.002 0.010 0.007 C 0.43187566201 -0.00376957955 3.13352499014 0.001 -0.007 0.002 C -2.63984642995 0.00218980399 1.17162612704 -0.003 -0.023 0.005 N -1.98513620489 0.00132140951 0.00153900685 0.000 0.030 0.003 C -2.63911589169 0.00167522827 -1.17277445342 0.003 -0.025 0.005 C -4.02452897564 0.00329996303 -1.20791476641 0.009 0.009 0.002 C -4.73391255267 0.00451580118 -0.00020876193 -0.000 -0.012 -0.001 C -4.02924140493 0.00399189729 1.20660077672 -0.010 0.009 0.002 Co 0.00000000000 0.00000000000 0.00000000000 -0.000 -0.002 -0.033 N -0.43839318333 -0.00054206762 -2.12229806799 0.001 0.012 0.002 C -1.76408906064 -0.00030645034 -2.37697009192 -0.003 -0.014 -0.001 C -2.24773885821 -0.00257631963 -3.67934971086 -0.006 0.011 -0.006 C -1.33713102227 -0.00526459193 -4.73855802198 -0.000 -0.003 -0.002 C 0.02654101484 -0.00591797621 -4.46472703619 -0.002 0.009 0.007 C 0.43371721952 -0.00363389350 -3.13225443930 -0.001 -0.005 0.002 S -6.53329279136 0.00637481657 -0.11611178087 -0.000 -0.000 0.000 N 2.00981687167 0.00259443239 -0.00000686048 -0.000 0.000 0.438 C 2.67119656792 1.17263645248 0.00045766926 0.001 0.000 -0.349 C 4.06129317470 1.20536051565 0.00241240325 0.000 0.000 0.118 C 4.76783866331 0.00148799420 0.00346798881 0.000 -0.000 -0.168 C 4.05723810074 -1.20352939940 0.00211502115 -0.001 0.000 0.132 C 2.67108506586 -1.17139122066 0.00026591651 0.000 0.001 -0.348 C 1.82209539371 2.39842937406 -0.00175320633 -0.000 -0.001 -0.198 C 2.33938959521 3.68993217240 -0.00584554905 -0.001 -0.000 0.155 C 1.45736908622 4.77231118002 -0.00917967851 -0.000 -0.000 -0.051 C 0.08658913130 4.53522926787 -0.00833235387 -0.000 0.001 0.129 C -0.35359617412 3.21325694137 -0.00400174376 0.000 -0.000 -0.074 N 0.49290585413 2.18198449515 -0.00068475564 0.000 0.001 0.164 S 6.56718562933 -0.11349126889 0.00673479967 0.000 0.000 -0.002 C 1.82142022278 -2.39594383179 -0.00206827421 0.000 0.001 -0.217 C 2.33969079820 -3.68709653410 -0.00625612120 0.000 -0.001 0.158 C 1.45789786198 -4.76953179608 -0.00945089783 -0.000 0.000 -0.066 C 0.08684213972 -4.53272927032 -0.00840538011 -0.000 -0.000 0.136 C -0.35393854068 -3.21111942258 -0.00398541364 0.000 0.000 -0.089 N 0.49225266031 -2.17934076887 -0.00084210065 0.000 -0.000 0.186 H 1.83694111827 5.77332096953 -0.01265611066 0.000 -0.001 -0.157 H -0.61802819388 5.33967450634 -0.01131742088 0.000 -0.000 -0.070 H 3.39175422949 3.87200638269 -0.00704552340 -0.000 -0.000 -0.020 H -1.39787683933 2.98334799634 -0.00369736757 0.000 -0.001 -0.156 H 1.83794742242 -5.77033326187 -0.01295832570 -0.000 0.000 -0.149 H -0.61749414542 -5.33746053721 -0.01121572048 -0.000 0.000 -0.051 H -1.39833026435 -2.98175334118 -0.00345676225 -0.000 0.000 -0.158 H 3.39230213722 -3.86796714602 -0.00754158092 0.000 -0.000 0.004 H 4.58301895157 2.13678100538 0.00314824260 -0.000 0.000 0.278 H 4.58784714512 -2.12983634010 0.00211631073 -0.001 -0.000 0.259 H -1.68997263563 -0.00719388386 -5.74925805817 0.003 -0.011 -0.002 H 0.75224758084 -0.00860493512 -5.25016290812 0.001 -0.006 0.003 H -3.29620044300 -0.00255800648 -3.88456579214 -0.002 -0.002 -0.002 H 1.47161249279 -0.00457826661 -2.87685200854 0.001 -0.011 -0.003 H -1.69176120521 -0.00597000955 5.75026973076 -0.003 -0.010 -0.002 H 0.75025791005 -0.00892914887 5.25161119224 -0.001 -0.002 0.003 H 1.46975366817 -0.00523069331 2.87805400798 -0.001 -0.011 -0.003 H -3.29750276746 -0.00099200484 3.88584245085 0.002 0.002 -0.002 H -4.55513299541 0.00377930937 -2.13473279421 0.004 0.018 -0.000 H -4.55107479454 0.00501307822 2.13844314827 -0.004 0.018 -0.000 H -6.83436893102 0.00806057203 1.19721860356 0.004 0.000 0.001 H 6.86748209639 1.20005966818 0.00372860376 -0.000 0.000 0.003 61 Mode 70: freq=859.24 N -0.44003451495 -0.00038510790 2.12369783068 -0.001 -0.148 0.000 C -1.76594470239 0.00039861437 2.37754210613 0.001 0.140 -0.000 C -2.24923313135 -0.00145267054 3.67997125809 0.002 -0.020 -0.001 C -1.33887502024 -0.00450793845 4.73956848945 0.000 0.110 -0.000 C 0.02462671625 -0.00591801736 4.46614405978 -0.000 -0.032 -0.000 C 0.43187566201 -0.00376957955 3.13352499014 -0.002 0.108 -0.000 C -2.63984642995 0.00218980399 1.17162612704 0.001 -0.039 0.001 N -1.98513620489 0.00132140951 0.00153900685 0.000 -0.003 0.001 C -2.63911589169 0.00167522827 -1.17277445342 -0.001 0.043 0.001 C -4.02452897564 0.00329996303 -1.20791476641 -0.001 0.012 -0.001 C -4.73391255267 0.00451580118 -0.00020876193 -0.000 0.006 -0.000 C -4.02924140493 0.00399189729 1.20660077672 0.001 -0.022 -0.001 Co 0.00000000000 0.00000000000 0.00000000000 0.000 0.001 -0.002 N -0.43839318333 -0.00054206762 -2.12229806799 0.001 0.120 0.000 C -1.76408906064 -0.00030645034 -2.37697009192 -0.001 -0.114 -0.000 C -2.24773885821 -0.00257631963 -3.67934971086 -0.002 0.015 -0.001 C -1.33713102227 -0.00526459193 -4.73855802198 -0.000 -0.092 -0.000 C 0.02654101484 -0.00591797621 -4.46472703619 0.000 0.024 -0.000 C 0.43371721952 -0.00363389350 -3.13225443930 0.002 -0.090 -0.000 S -6.53329279136 0.00637481657 -0.11611178087 0.000 -0.001 -0.000 N 2.00981687167 0.00259443239 -0.00000686048 -0.000 -0.000 -0.018 C 2.67119656792 1.17263645248 0.00045766926 0.000 -0.000 0.082 C 4.06129317470 1.20536051565 0.00241240325 0.000 0.000 0.051 C 4.76783866331 0.00148799420 0.00346798881 0.000 0.000 -0.025 C 4.05723810074 -1.20352939940 0.00211502115 -0.000 0.000 -0.014 C 2.67108506586 -1.17139122066 0.00026591651 -0.000 -0.000 -0.044 C 1.82209539371 2.39842937406 -0.00175320633 0.000 -0.001 -0.288 C 2.33938959521 3.68993217240 -0.00584554905 0.000 0.000 0.037 C 1.45736908622 4.77231118002 -0.00917967851 0.000 -0.001 -0.238 C 0.08658913130 4.53522926787 -0.00833235387 0.000 0.000 0.069 C -0.35359617412 3.21325694137 -0.00400174376 -0.000 -0.001 -0.235 N 0.49290585413 2.18198449515 -0.00068475564 -0.000 0.001 0.327 S 6.56718562933 -0.11349126889 0.00673479967 -0.000 0.000 0.004 C 1.82142022278 -2.39594383179 -0.00206827421 -0.000 -0.000 0.139 C 2.33969079820 -3.68709653410 -0.00625612120 -0.000 0.000 -0.017 C 1.45789786198 -4.76953179608 -0.00945089783 -0.000 -0.000 0.115 C 0.08684213972 -4.53272927032 -0.00840538011 -0.000 0.000 -0.031 C -0.35393854068 -3.21111942258 -0.00398541364 0.000 -0.000 0.114 N 0.49225266031 -2.17934076887 -0.00084210065 0.000 0.000 -0.152 H 1.83694111827 5.77332096953 -0.01265611066 -0.000 0.001 0.181 H -0.61802819388 5.33967450634 -0.01131742088 0.000 0.001 0.344 H 3.39175422949 3.87200638269 -0.00704552340 0.000 0.001 0.387 H -1.39787683933 2.98334799634 -0.00369736757 -0.000 0.000 0.016 H 1.83794742242 -5.77033326187 -0.01295832570 0.000 0.000 -0.091 H -0.61749414542 -5.33746053721 -0.01121572048 -0.000 0.001 -0.170 H -1.39833026435 -2.98175334118 -0.00345676225 0.000 0.000 -0.013 H 3.39230213722 -3.86796714602 -0.00754158092 -0.000 0.001 -0.187 H 4.58301895157 2.13678100538 0.00314824260 0.000 -0.000 -0.091 H 4.58784714512 -2.12983634010 0.00211631073 -0.000 0.000 0.036 H -1.68997263563 -0.00719388386 -5.74925805817 0.001 0.073 -0.000 H 0.75224758084 -0.00860493512 -5.25016290812 -0.000 0.136 -0.001 H -3.29620044300 -0.00255800648 -3.88456579214 -0.001 0.150 -0.001 H 1.47161249279 -0.00457826661 -2.87685200854 0.001 0.010 -0.000 H -1.69176120521 -0.00597000955 5.75026973076 -0.001 -0.081 -0.000 H 0.75025791005 -0.00892914887 5.25161119224 -0.000 -0.158 -0.001 H 1.46975366817 -0.00523069331 2.87805400798 -0.001 -0.006 -0.000 H -3.29750276746 -0.00099200484 3.88584245085 0.000 -0.178 -0.001 H -4.55513299541 0.00377930937 -2.13473279421 -0.000 -0.034 -0.000 H -4.55107479454 0.00501307822 2.13844314827 0.000 0.038 -0.000 H -6.83436893102 0.00806057203 1.19721860356 0.000 0.003 -0.000 H 6.86748209639 1.20005966818 0.00372860376 0.000 -0.000 -0.003 61 Mode 71: freq=860.67 N -0.44003451495 -0.00038510790 2.12369783068 -0.002 0.061 0.001 C -1.76594470239 0.00039861437 2.37754210613 0.004 -0.056 -0.002 C -2.24923313135 -0.00145267054 3.67997125809 0.006 0.008 -0.003 C -1.33887502024 -0.00450793845 4.73956848945 0.000 -0.045 -0.001 C 0.02462671625 -0.00591801736 4.46614405978 -0.001 0.013 -0.002 C 0.43187566201 -0.00376957955 3.13352499014 -0.006 -0.044 -0.002 C -2.63984642995 0.00218980399 1.17162612704 0.003 0.016 0.003 N -1.98513620489 0.00132140951 0.00153900685 0.000 -0.000 0.004 C -2.63911589169 0.00167522827 -1.17277445342 -0.003 -0.015 0.003 C -4.02452897564 0.00329996303 -1.20791476641 -0.003 -0.005 -0.002 C -4.73391255267 0.00451580118 -0.00020876193 -0.000 -0.002 -0.001 C -4.02924140493 0.00399189729 1.20660077672 0.003 0.009 -0.002 Co 0.00000000000 0.00000000000 0.00000000000 0.000 -0.000 -0.003 N -0.43839318333 -0.00054206762 -2.12229806799 0.002 -0.047 0.001 C -1.76408906064 -0.00030645034 -2.37697009192 -0.004 0.044 -0.002 C -2.24773885821 -0.00257631963 -3.67934971086 -0.006 -0.006 -0.003 C -1.33713102227 -0.00526459193 -4.73855802198 -0.000 0.036 -0.001 C 0.02654101484 -0.00591797621 -4.46472703619 0.001 -0.009 -0.002 C 0.43371721952 -0.00363389350 -3.13225443930 0.006 0.035 -0.002 S -6.53329279136 0.00637481657 -0.11611178087 0.000 0.000 -0.000 N 2.00981687167 0.00259443239 -0.00000686048 -0.000 0.000 -0.112 C 2.67119656792 1.17263645248 0.00045766926 -0.000 0.000 0.089 C 4.06129317470 1.20536051565 0.00241240325 -0.000 -0.000 0.034 C 4.76783866331 0.00148799420 0.00346798881 0.000 -0.000 -0.060 C 4.05723810074 -1.20352939940 0.00211502115 0.000 0.000 0.043 C 2.67108506586 -1.17139122066 0.00026591651 -0.000 0.000 0.129 C 1.82209539371 2.39842937406 -0.00175320633 -0.000 -0.001 -0.163 C 2.33938959521 3.68993217240 -0.00584554905 -0.000 -0.000 0.008 C 1.45736908622 4.77231118002 -0.00917967851 -0.000 -0.001 -0.149 C 0.08658913130 4.53522926787 -0.00833235387 0.000 0.000 0.032 C -0.35359617412 3.21325694137 -0.00400174376 0.000 -0.000 -0.145 N 0.49290585413 2.18198449515 -0.00068475564 0.000 0.001 0.202 S 6.56718562933 -0.11349126889 0.00673479967 -0.000 0.000 0.009 C 1.82142022278 -2.39594383179 -0.00206827421 -0.000 0.001 -0.282 C 2.33969079820 -3.68709653410 -0.00625612120 0.000 -0.000 0.026 C 1.45789786198 -4.76953179608 -0.00945089783 -0.000 0.001 -0.245 C 0.08684213972 -4.53272927032 -0.00840538011 0.000 -0.000 0.058 C -0.35393854068 -3.21111942258 -0.00398541364 -0.000 0.001 -0.240 N 0.49225266031 -2.17934076887 -0.00084210065 -0.000 -0.001 0.331 H 1.83694111827 5.77332096953 -0.01265611066 0.000 0.000 0.131 H -0.61802819388 5.33967450634 -0.01131742088 -0.000 0.001 0.227 H 3.39175422949 3.87200638269 -0.00704552340 0.000 0.001 0.250 H -1.39787683933 2.98334799634 -0.00369736757 0.000 0.000 0.022 H 1.83794742242 -5.77033326187 -0.01295832570 0.000 -0.001 0.205 H -0.61749414542 -5.33746053721 -0.01121572048 0.000 -0.001 0.368 H -1.39833026435 -2.98175334118 -0.00345676225 -0.000 -0.000 0.033 H 3.39230213722 -3.86796714602 -0.00754158092 0.000 -0.001 0.403 H 4.58301895157 2.13678100538 0.00314824260 0.000 -0.000 -0.101 H 4.58784714512 -2.12983634010 0.00211631073 0.000 0.000 -0.122 H -1.68997263563 -0.00719388386 -5.74925805817 0.001 -0.028 -0.001 H 0.75224758084 -0.00860493512 -5.25016290812 -0.001 -0.053 -0.001 H -3.29620044300 -0.00255800648 -3.88456579214 -0.002 -0.058 -0.002 H 1.47161249279 -0.00457826661 -2.87685200854 0.002 -0.004 -0.000 H -1.69176120521 -0.00597000955 5.75026973076 -0.001 0.034 -0.001 H 0.75025791005 -0.00892914887 5.25161119224 0.001 0.065 -0.001 H 1.46975366817 -0.00523069331 2.87805400798 -0.002 0.003 -0.000 H -3.29750276746 -0.00099200484 3.88584245085 0.002 0.073 -0.002 H -4.55513299541 0.00377930937 -2.13473279421 -0.000 0.012 -0.001 H -4.55107479454 0.00501307822 2.13844314827 0.000 -0.016 -0.001 H -6.83436893102 0.00806057203 1.19721860356 -0.000 -0.001 -0.000 H 6.86748209639 1.20005966818 0.00372860376 0.000 -0.000 0.009 61 Mode 72: freq=864.32 N -0.44003451495 -0.00038510790 2.12369783068 -0.001 -0.344 -0.001 C -1.76594470239 0.00039861437 2.37754210613 0.000 0.281 0.000 C -2.24923313135 -0.00145267054 3.67997125809 0.000 -0.021 -0.000 C -1.33887502024 -0.00450793845 4.73956848945 0.000 0.246 0.000 C 0.02462671625 -0.00591801736 4.46614405978 -0.000 -0.054 -0.000 C 0.43187566201 -0.00376957955 3.13352499014 0.000 0.237 0.000 C -2.63984642995 0.00218980399 1.17162612704 0.000 -0.125 0.000 N -1.98513620489 0.00132140951 0.00153900685 0.000 0.112 0.000 C -2.63911589169 0.00167522827 -1.17277445342 -0.000 -0.093 0.000 C -4.02452897564 0.00329996303 -1.20791476641 -0.000 -0.024 -0.000 C -4.73391255267 0.00451580118 -0.00020876193 0.000 0.056 -0.000 C -4.02924140493 0.00399189729 1.20660077672 0.000 -0.051 0.000 Co 0.00000000000 0.00000000000 0.00000000000 0.000 0.006 0.000 N -0.43839318333 -0.00054206762 -2.12229806799 -0.000 -0.193 0.000 C -1.76408906064 -0.00030645034 -2.37697009192 -0.000 0.157 -0.000 C -2.24773885821 -0.00257631963 -3.67934971086 -0.000 -0.009 -0.000 C -1.33713102227 -0.00526459193 -4.73855802198 0.000 0.141 -0.000 C 0.02654101484 -0.00591797621 -4.46472703619 0.000 -0.026 -0.000 C 0.43371721952 -0.00363389350 -3.13225443930 0.000 0.136 -0.000 S -6.53329279136 0.00637481657 -0.11611178087 -0.000 -0.009 -0.000 N 2.00981687167 0.00259443239 -0.00000686048 0.000 -0.005 -0.005 C 2.67119656792 1.17263645248 0.00045766926 0.003 -0.003 -0.009 C 4.06129317470 1.20536051565 0.00241240325 0.003 0.002 -0.008 C 4.76783866331 0.00148799420 0.00346798881 -0.000 0.001 -0.001 C 4.05723810074 -1.20352939940 0.00211502115 -0.003 0.002 0.008 C 2.67108506586 -1.17139122066 0.00026591651 -0.003 -0.003 0.018 C 1.82209539371 2.39842937406 -0.00175320633 0.004 0.002 0.044 C 2.33938959521 3.68993217240 -0.00584554905 0.006 0.003 -0.005 C 1.45736908622 4.77231118002 -0.00917967851 0.000 0.001 0.037 C 0.08658913130 4.53522926787 -0.00833235387 -0.001 0.001 -0.010 C -0.35359617412 3.21325694137 -0.00400174376 -0.006 0.002 0.036 N 0.49290585413 2.18198449515 -0.00068475564 -0.003 -0.001 -0.053 S 6.56718562933 -0.11349126889 0.00673479967 0.000 0.000 0.000 C 1.82142022278 -2.39594383179 -0.00206827421 -0.004 0.002 -0.053 C 2.33969079820 -3.68709653410 -0.00625612120 -0.006 0.003 0.005 C 1.45789786198 -4.76953179608 -0.00945089783 -0.001 0.001 -0.046 C 0.08684213972 -4.53272927032 -0.00840538011 0.001 0.001 0.011 C -0.35393854068 -3.21111942258 -0.00398541364 0.006 0.002 -0.045 N 0.49225266031 -2.17934076887 -0.00084210065 0.003 -0.001 0.065 H 1.83694111827 5.77332096953 -0.01265611066 -0.001 0.001 -0.028 H -0.61802819388 5.33967450634 -0.01131742088 0.001 0.001 -0.052 H 3.39175422949 3.87200638269 -0.00704552340 0.002 0.002 -0.059 H -1.39787683933 2.98334799634 -0.00369736757 -0.002 0.001 -0.002 H 1.83794742242 -5.77033326187 -0.01295832570 0.001 0.001 0.038 H -0.61749414542 -5.33746053721 -0.01121572048 -0.001 0.001 0.069 H -1.39833026435 -2.98175334118 -0.00345676225 0.002 0.001 0.005 H 3.39230213722 -3.86796714602 -0.00754158092 -0.002 0.002 0.075 H 4.58301895157 2.13678100538 0.00314824260 0.000 0.001 0.011 H 4.58784714512 -2.12983634010 0.00211631073 -0.001 0.001 -0.017 H -1.68997263563 -0.00719388386 -5.74925805817 -0.000 -0.129 0.000 H 0.75224758084 -0.00860493512 -5.25016290812 -0.000 -0.220 0.000 H -3.29620044300 -0.00255800648 -3.88456579214 -0.000 -0.237 0.000 H 1.47161249279 -0.00457826661 -2.87685200854 0.000 -0.023 0.000 H -1.69176120521 -0.00597000955 5.75026973076 -0.000 -0.212 -0.000 H 0.75025791005 -0.00892914887 5.25161119224 -0.001 -0.371 -0.001 H 1.46975366817 -0.00523069331 2.87805400798 -0.000 -0.028 -0.000 H -3.29750276746 -0.00099200484 3.88584245085 -0.000 -0.410 -0.001 H -4.55513299541 0.00377930937 -2.13473279421 0.000 0.089 -0.000 H -4.55107479454 0.00501307822 2.13844314827 0.000 0.137 -0.000 H -6.83436893102 0.00806057203 1.19721860356 -0.000 -0.006 -0.000 H 6.86748209639 1.20005966818 0.00372860376 -0.001 0.000 0.001 61 Mode 73: freq=865.63 N -0.44003451495 -0.00038510790 2.12369783068 0.000 0.163 0.000 C -1.76594470239 0.00039861437 2.37754210613 -0.000 -0.141 -0.000 C -2.24923313135 -0.00145267054 3.67997125809 -0.000 0.022 0.000 C -1.33887502024 -0.00450793845 4.73956848945 -0.000 -0.110 -0.000 C 0.02462671625 -0.00591801736 4.46614405978 0.000 0.034 0.000 C 0.43187566201 -0.00376957955 3.13352499014 0.000 -0.108 -0.000 C -2.63984642995 0.00218980399 1.17162612704 -0.000 0.019 -0.000 N -1.98513620489 0.00132140951 0.00153900685 0.000 0.045 -0.000 C -2.63911589169 0.00167522827 -1.17277445342 0.000 -0.106 -0.000 C -4.02452897564 0.00329996303 -1.20791476641 0.000 -0.037 0.000 C -4.73391255267 0.00451580118 -0.00020876193 -0.000 0.014 0.000 C -4.02924140493 0.00399189729 1.20660077672 -0.000 0.022 0.000 Co 0.00000000000 0.00000000000 0.00000000000 0.000 0.002 -0.000 N -0.43839318333 -0.00054206762 -2.12229806799 -0.000 -0.333 0.001 C -1.76408906064 -0.00030645034 -2.37697009192 0.000 0.278 -0.000 C -2.24773885821 -0.00257631963 -3.67934971086 0.000 -0.027 0.000 C -1.33713102227 -0.00526459193 -4.73855802198 0.000 0.237 -0.000 C 0.02654101484 -0.00591797621 -4.46472703619 -0.000 -0.054 0.000 C 0.43371721952 -0.00363389350 -3.13225443930 -0.000 0.230 -0.000 S -6.53329279136 0.00637481657 -0.11611178087 0.000 -0.002 0.000 N 2.00981687167 0.00259443239 -0.00000686048 0.000 -0.002 0.010 C 2.67119656792 1.17263645248 0.00045766926 0.001 -0.001 0.022 C 4.06129317470 1.20536051565 0.00241240325 0.001 0.001 0.020 C 4.76783866331 0.00148799420 0.00346798881 -0.000 0.000 0.000 C 4.05723810074 -1.20352939940 0.00211502115 -0.001 0.001 -0.018 C 2.67108506586 -1.17139122066 0.00026591651 -0.001 -0.001 -0.041 C 1.82209539371 2.39842937406 -0.00175320633 0.001 0.000 -0.107 C 2.33938959521 3.68993217240 -0.00584554905 0.002 0.001 0.012 C 1.45736908622 4.77231118002 -0.00917967851 0.000 0.000 -0.091 C 0.08658913130 4.53522926787 -0.00833235387 -0.000 0.001 0.025 C -0.35359617412 3.21325694137 -0.00400174376 -0.002 0.000 -0.090 N 0.49290585413 2.18198449515 -0.00068475564 -0.001 0.000 0.135 S 6.56718562933 -0.11349126889 0.00673479967 0.000 0.000 0.000 C 1.82142022278 -2.39594383179 -0.00206827421 -0.001 0.000 0.124 C 2.33969079820 -3.68709653410 -0.00625612120 -0.002 0.001 -0.012 C 1.45789786198 -4.76953179608 -0.00945089783 -0.000 0.000 0.108 C 0.08684213972 -4.53272927032 -0.00840538011 0.000 0.001 -0.026 C -0.35393854068 -3.21111942258 -0.00398541364 0.002 0.000 0.107 N 0.49225266031 -2.17934076887 -0.00084210065 0.001 0.000 -0.156 H 1.83694111827 5.77332096953 -0.01265611066 -0.000 0.000 0.071 H -0.61802819388 5.33967450634 -0.01131742088 0.000 0.001 0.130 H 3.39175422949 3.87200638269 -0.00704552340 0.001 0.001 0.147 H -1.39787683933 2.98334799634 -0.00369736757 -0.001 0.000 0.004 H 1.83794742242 -5.77033326187 -0.01295832570 0.000 0.001 -0.091 H -0.61749414542 -5.33746053721 -0.01121572048 -0.000 0.001 -0.162 H -1.39833026435 -2.98175334118 -0.00345676225 0.001 0.000 -0.011 H 3.39230213722 -3.86796714602 -0.00754158092 -0.001 0.001 -0.177 H 4.58301895157 2.13678100538 0.00314824260 0.000 0.000 -0.028 H 4.58784714512 -2.12983634010 0.00211631073 -0.000 0.000 0.041 H -1.68997263563 -0.00719388386 -5.74925805817 -0.000 -0.199 0.000 H 0.75224758084 -0.00860493512 -5.25016290812 -0.000 -0.354 0.001 H -3.29620044300 -0.00255800648 -3.88456579214 -0.000 -0.388 0.001 H 1.47161249279 -0.00457826661 -2.87685200854 -0.000 -0.025 0.000 H -1.69176120521 -0.00597000955 5.75026973076 0.000 0.079 0.000 H 0.75025791005 -0.00892914887 5.25161119224 0.000 0.153 0.000 H 1.46975366817 -0.00523069331 2.87805400798 0.000 -0.000 0.000 H -3.29750276746 -0.00099200484 3.88584245085 0.000 0.176 0.000 H -4.55513299541 0.00377930937 -2.13473279421 0.000 0.097 0.000 H -4.55107479454 0.00501307822 2.13844314827 -0.000 -0.019 0.000 H -6.83436893102 0.00806057203 1.19721860356 0.000 -0.007 0.000 H 6.86748209639 1.20005966818 0.00372860376 -0.000 0.000 -0.003 61 Mode 74: freq=887.91 N -0.44003451495 -0.00038510790 2.12369783068 0.084 -0.000 -0.026 C -1.76594470239 0.00039861437 2.37754210613 -0.004 0.000 0.015 C -2.24923313135 -0.00145267054 3.67997125809 -0.049 -0.000 0.058 C -1.33887502024 -0.00450793845 4.73956848945 -0.025 -0.000 0.070 C 0.02462671625 -0.00591801736 4.46614405978 -0.028 -0.000 -0.030 C 0.43187566201 -0.00376957955 3.13352499014 0.100 -0.000 -0.013 C -2.63984642995 0.00218980399 1.17162612704 -0.029 -0.000 -0.110 N -1.98513620489 0.00132140951 0.00153900685 0.159 -0.000 -0.000 C -2.63911589169 0.00167522827 -1.17277445342 -0.026 -0.000 0.101 C -4.02452897564 0.00329996303 -1.20791476641 -0.078 0.000 0.196 C -4.73391255267 0.00451580118 -0.00020876193 -0.306 0.000 -0.000 C -4.02924140493 0.00399189729 1.20660077672 -0.090 -0.000 -0.209 Co 0.00000000000 0.00000000000 0.00000000000 -0.046 -0.000 0.000 N -0.43839318333 -0.00054206762 -2.12229806799 0.078 0.000 0.025 C -1.76408906064 -0.00030645034 -2.37697009192 -0.004 0.000 -0.014 C -2.24773885821 -0.00257631963 -3.67934971086 -0.045 -0.000 -0.054 C -1.33713102227 -0.00526459193 -4.73855802198 -0.024 -0.000 -0.064 C 0.02654101484 -0.00591797621 -4.46472703619 -0.026 -0.000 0.027 C 0.43371721952 -0.00363389350 -3.13225443930 0.094 -0.000 0.011 S -6.53329279136 0.00637481657 -0.11611178087 0.135 -0.000 0.012 N 2.00981687167 0.00259443239 -0.00000686048 0.235 -0.001 -0.000 C 2.67119656792 1.17263645248 0.00045766926 -0.045 0.152 0.000 C 4.06129317470 1.20536051565 0.00241240325 -0.141 0.290 -0.000 C 4.76783866331 0.00148799420 0.00346798881 -0.446 0.001 -0.001 C 4.05723810074 -1.20352939940 0.00211502115 -0.123 -0.269 -0.000 C 2.67108506586 -1.17139122066 0.00026591651 -0.042 -0.141 0.000 C 1.82209539371 2.39842937406 -0.00175320633 0.003 -0.022 -0.000 C 2.33938959521 3.68993217240 -0.00584554905 -0.064 -0.080 0.000 C 1.45736908622 4.77231118002 -0.00917967851 -0.041 -0.103 0.000 C 0.08658913130 4.53522926787 -0.00833235387 -0.045 0.053 -0.000 C -0.35359617412 3.21325694137 -0.00400174376 0.143 0.021 -0.000 N 0.49290585413 2.18198449515 -0.00068475564 0.122 0.034 -0.000 S 6.56718562933 -0.11349126889 0.00673479967 0.198 -0.018 0.000 C 1.82142022278 -2.39594383179 -0.00206827421 0.003 0.020 -0.000 C 2.33969079820 -3.68709653410 -0.00625612120 -0.059 0.075 0.000 C 1.45789786198 -4.76953179608 -0.00945089783 -0.039 0.094 0.000 C 0.08684213972 -4.53272927032 -0.00840538011 -0.042 -0.050 -0.000 C -0.35393854068 -3.21111942258 -0.00398541364 0.134 -0.018 -0.000 N 0.49225266031 -2.17934076887 -0.00084210065 0.115 -0.033 -0.000 H 1.83694111827 5.77332096953 -0.01265611066 0.028 -0.046 0.000 H -0.61802819388 5.33967450634 -0.01131742088 -0.020 0.009 -0.000 H 3.39175422949 3.87200638269 -0.00704552340 -0.024 -0.006 -0.000 H -1.39787683933 2.98334799634 -0.00369736757 0.050 -0.026 0.000 H 1.83794742242 -5.77033326187 -0.01295832570 0.025 0.043 0.000 H -0.61749414542 -5.33746053721 -0.01121572048 -0.019 -0.008 0.000 H -1.39833026435 -2.98175334118 -0.00345676225 0.047 0.025 0.000 H 3.39230213722 -3.86796714602 -0.00754158092 -0.022 0.006 0.000 H 4.58301895157 2.13678100538 0.00314824260 0.014 0.053 -0.000 H 4.58784714512 -2.12983634010 0.00211631073 0.025 -0.043 -0.000 H -1.68997263563 -0.00719388386 -5.74925805817 0.018 0.000 -0.028 H 0.75224758084 -0.00860493512 -5.25016290812 -0.013 0.001 0.002 H -3.29620044300 -0.00255800648 -3.88456579214 -0.016 0.000 -0.007 H 1.47161249279 -0.00457826661 -2.87685200854 0.033 0.000 -0.016 H -1.69176120521 -0.00597000955 5.75026973076 0.020 0.000 0.031 H 0.75025791005 -0.00892914887 5.25161119224 -0.014 0.000 -0.003 H 1.46975366817 -0.00523069331 2.87805400798 0.036 0.000 0.017 H -3.29750276746 -0.00099200484 3.88584245085 -0.018 -0.000 0.007 H -4.55513299541 0.00377930937 -2.13473279421 0.021 0.000 0.032 H -4.55107479454 0.00501307822 2.13844314827 0.013 0.000 -0.039 H -6.83436893102 0.00806057203 1.19721860356 -0.013 -0.000 -0.008 H 6.86748209639 1.20005966818 0.00372860376 -0.020 0.012 0.000 61 Mode 75: freq=889.38 N -0.44003451495 -0.00038510790 2.12369783068 0.122 -0.000 -0.036 C -1.76594470239 0.00039861437 2.37754210613 0.009 -0.000 0.020 C -2.24923313135 -0.00145267054 3.67997125809 -0.054 -0.000 0.081 C -1.33887502024 -0.00450793845 4.73956848945 -0.040 0.000 0.110 C 0.02462671625 -0.00591801736 4.46614405978 -0.052 0.000 -0.059 C 0.43187566201 -0.00376957955 3.13352499014 0.138 0.000 -0.029 C -2.63984642995 0.00218980399 1.17162612704 -0.042 0.001 -0.154 N -1.98513620489 0.00132140951 0.00153900685 0.228 -0.000 -0.000 C -2.63911589169 0.00167522827 -1.17277445342 -0.038 0.000 0.142 C -4.02452897564 0.00329996303 -1.20791476641 -0.119 0.000 0.277 C -4.73391255267 0.00451580118 -0.00020876193 -0.443 0.000 -0.000 C -4.02924140493 0.00399189729 1.20660077672 -0.137 0.000 -0.297 Co 0.00000000000 0.00000000000 0.00000000000 -0.014 0.000 0.000 N -0.43839318333 -0.00054206762 -2.12229806799 0.114 -0.000 0.035 C -1.76408906064 -0.00030645034 -2.37697009192 0.009 -0.000 -0.019 C -2.24773885821 -0.00257631963 -3.67934971086 -0.048 -0.000 -0.075 C -1.33713102227 -0.00526459193 -4.73855802198 -0.038 -0.000 -0.101 C 0.02654101484 -0.00591797621 -4.46472703619 -0.049 0.000 0.056 C 0.43371721952 -0.00363389350 -3.13225443930 0.128 0.000 0.026 S -6.53329279136 0.00637481657 -0.11611178087 0.197 -0.000 0.018 N 2.00981687167 0.00259443239 -0.00000686048 -0.161 0.000 -0.000 C 2.67119656792 1.17263645248 0.00045766926 0.030 -0.106 0.000 C 4.06129317470 1.20536051565 0.00241240325 0.100 -0.201 0.000 C 4.76783866331 0.00148799420 0.00346798881 0.310 -0.000 0.000 C 4.05723810074 -1.20352939940 0.00211502115 0.087 0.186 0.000 C 2.67108506586 -1.17139122066 0.00026591651 0.028 0.097 0.000 C 1.82209539371 2.39842937406 -0.00175320633 -0.008 0.015 -0.000 C 2.33938959521 3.68993217240 -0.00584554905 0.038 0.055 -0.000 C 1.45736908622 4.77231118002 -0.00917967851 0.030 0.075 -0.000 C 0.08658913130 4.53522926787 -0.00833235387 0.036 -0.044 0.000 C -0.35359617412 3.21325694137 -0.00400174376 -0.097 -0.018 0.000 N 0.49290585413 2.18198449515 -0.00068475564 -0.085 -0.022 -0.000 S 6.56718562933 -0.11349126889 0.00673479967 -0.138 0.013 -0.000 C 1.82142022278 -2.39594383179 -0.00206827421 -0.008 -0.013 -0.000 C 2.33969079820 -3.68709653410 -0.00625612120 0.035 -0.051 -0.000 C 1.45789786198 -4.76953179608 -0.00945089783 0.029 -0.069 -0.000 C 0.08684213972 -4.53272927032 -0.00840538011 0.034 0.042 0.000 C -0.35393854068 -3.21111942258 -0.00398541364 -0.090 0.017 0.000 N 0.49225266031 -2.17934076887 -0.00084210065 -0.080 0.021 0.000 H 1.83694111827 5.77332096953 -0.01265611066 -0.020 0.034 -0.000 H -0.61802819388 5.33967450634 -0.01131742088 0.014 -0.010 -0.000 H 3.39175422949 3.87200638269 -0.00704552340 0.015 0.002 -0.000 H -1.39787683933 2.98334799634 -0.00369736757 -0.034 0.018 -0.000 H 1.83794742242 -5.77033326187 -0.01295832570 -0.018 -0.031 -0.000 H -0.61749414542 -5.33746053721 -0.01121572048 0.013 0.009 -0.000 H -1.39833026435 -2.98175334118 -0.00345676225 -0.032 -0.017 -0.000 H 3.39230213722 -3.86796714602 -0.00754158092 0.014 -0.002 -0.000 H 4.58301895157 2.13678100538 0.00314824260 -0.009 -0.037 -0.000 H 4.58784714512 -2.12983634010 0.00211631073 -0.017 0.030 -0.000 H -1.68997263563 -0.00719388386 -5.74925805817 0.026 -0.000 -0.044 H 0.75224758084 -0.00860493512 -5.25016290812 -0.019 -0.000 0.012 H -3.29620044300 -0.00255800648 -3.88456579214 -0.019 -0.000 -0.004 H 1.47161249279 -0.00457826661 -2.87685200854 0.046 -0.000 -0.023 H -1.69176120521 -0.00597000955 5.75026973076 0.029 -0.000 0.048 H 0.75025791005 -0.00892914887 5.25161119224 -0.020 -0.000 -0.013 H 1.46975366817 -0.00523069331 2.87805400798 0.050 -0.000 0.024 H -3.29750276746 -0.00099200484 3.88584245085 -0.022 -0.000 0.004 H -4.55513299541 0.00377930937 -2.13473279421 0.026 -0.000 0.046 H -4.55107479454 0.00501307822 2.13844314827 0.015 -0.000 -0.056 H -6.83436893102 0.00806057203 1.19721860356 -0.020 0.000 -0.012 H 6.86748209639 1.20005966818 0.00372860376 0.014 -0.009 -0.000 61 Mode 76: freq=917.01 N -0.44003451495 -0.00038510790 2.12369783068 0.003 0.107 -0.001 C -1.76594470239 0.00039861437 2.37754210613 -0.000 -0.330 -0.001 C -2.24923313135 -0.00145267054 3.67997125809 -0.003 0.118 0.004 C -1.33887502024 -0.00450793845 4.73956848945 -0.002 0.046 0.004 C 0.02462671625 -0.00591801736 4.46614405978 -0.001 0.162 -0.001 C 0.43187566201 -0.00376957955 3.13352499014 0.005 0.019 -0.000 C -2.63984642995 0.00218980399 1.17162612704 -0.003 0.186 -0.006 N -1.98513620489 0.00132140951 0.00153900685 -0.000 -0.020 -0.006 C -2.63911589169 0.00167522827 -1.17277445342 0.004 -0.144 -0.006 C -4.02452897564 0.00329996303 -1.20791476641 0.006 -0.022 0.003 C -4.73391255267 0.00451580118 -0.00020876193 0.000 -0.008 0.001 C -4.02924140493 0.00399189729 1.20660077672 -0.006 0.042 0.003 Co 0.00000000000 0.00000000000 0.00000000000 0.000 0.001 -0.001 N -0.43839318333 -0.00054206762 -2.12229806799 -0.003 -0.090 -0.001 C -1.76408906064 -0.00030645034 -2.37697009192 0.000 0.272 -0.001 C -2.24773885821 -0.00257631963 -3.67934971086 0.003 -0.097 0.004 C -1.33713102227 -0.00526459193 -4.73855802198 0.002 -0.033 0.004 C 0.02654101484 -0.00591797621 -4.46472703619 0.001 -0.131 -0.002 C 0.43371721952 -0.00363389350 -3.13225443930 -0.005 -0.012 -0.000 S -6.53329279136 0.00637481657 -0.11611178087 -0.000 0.003 -0.000 N 2.00981687167 0.00259443239 -0.00000686048 -0.000 0.010 0.014 C 2.67119656792 1.17263645248 0.00045766926 -0.006 0.009 -0.134 C 4.06129317470 1.20536051565 0.00241240325 -0.009 -0.005 -0.031 C 4.76783866331 0.00148799420 0.00346798881 -0.000 -0.001 0.006 C 4.05723810074 -1.20352939940 0.00211502115 0.009 -0.006 0.017 C 2.67108506586 -1.17139122066 0.00026591651 0.006 0.009 0.104 C 1.82209539371 2.39842937406 -0.00175320633 0.000 0.001 0.237 C 2.33938959521 3.68993217240 -0.00584554905 -0.005 -0.006 -0.087 C 1.45736908622 4.77231118002 -0.00917967851 -0.003 -0.006 -0.032 C 0.08658913130 4.53522926787 -0.00833235387 -0.002 0.003 -0.116 C -0.35359617412 3.21325694137 -0.00400174376 0.008 0.001 -0.013 N 0.49290585413 2.18198449515 -0.00068475564 0.005 0.001 -0.075 S 6.56718562933 -0.11349126889 0.00673479967 -0.001 0.000 -0.002 C 1.82142022278 -2.39594383179 -0.00206827421 -0.000 0.001 -0.194 C 2.33969079820 -3.68709653410 -0.00625612120 0.005 -0.006 0.071 C 1.45789786198 -4.76953179608 -0.00945089783 0.003 -0.006 0.023 C 0.08684213972 -4.53272927032 -0.00840538011 0.002 0.003 0.093 C -0.35393854068 -3.21111942258 -0.00398541364 -0.008 0.001 0.008 N 0.49225266031 -2.17934076887 -0.00084210065 -0.005 0.001 0.062 H 1.83694111827 5.77332096953 -0.01265611066 0.002 -0.002 0.177 H -0.61802819388 5.33967450634 -0.01131742088 -0.001 0.001 0.197 H 3.39175422949 3.87200638269 -0.00704552340 -0.001 -0.001 0.037 H -1.39787683933 2.98334799634 -0.00369736757 0.003 -0.000 0.151 H 1.83794742242 -5.77033326187 -0.01295832570 -0.002 -0.002 -0.140 H -0.61749414542 -5.33746053721 -0.01121572048 0.001 0.001 -0.154 H -1.39833026435 -2.98175334118 -0.00345676225 -0.003 -0.001 -0.121 H 3.39230213722 -3.86796714602 -0.00754158092 0.001 -0.001 -0.027 H 4.58301895157 2.13678100538 0.00314824260 -0.002 -0.002 0.107 H 4.58784714512 -2.12983634010 0.00211631073 0.002 -0.002 -0.063 H -1.68997263563 -0.00719388386 -5.74925805817 -0.001 0.195 0.001 H 0.75224758084 -0.00860493512 -5.25016290812 0.001 0.219 -0.001 H -3.29620044300 -0.00255800648 -3.88456579214 0.001 0.036 0.001 H 1.47161249279 -0.00457826661 -2.87685200854 -0.001 0.171 0.000 H -1.69176120521 -0.00597000955 5.75026973076 0.001 -0.246 0.001 H 0.75025791005 -0.00892914887 5.25161119224 -0.001 -0.278 -0.001 H 1.46975366817 -0.00523069331 2.87805400798 0.001 -0.213 0.000 H -3.29750276746 -0.00099200484 3.88584245085 -0.001 -0.050 0.001 H -4.55513299541 0.00377930937 -2.13473279421 0.001 0.085 0.001 H -4.55107479454 0.00501307822 2.13844314827 -0.001 -0.146 0.001 H -6.83436893102 0.00806057203 1.19721860356 0.003 -0.010 0.001 H 6.86748209639 1.20005966818 0.00372860376 0.005 -0.001 0.007 61 Mode 77: freq=919.03 N -0.44003451495 -0.00038510790 2.12369783068 0.006 -0.088 -0.001 C -1.76594470239 0.00039861437 2.37754210613 -0.000 0.257 -0.000 C -2.24923313135 -0.00145267054 3.67997125809 -0.005 -0.090 0.007 C -1.33887502024 -0.00450793845 4.73956848945 -0.003 -0.036 0.008 C 0.02462671625 -0.00591801736 4.46614405978 -0.002 -0.126 -0.004 C 0.43187566201 -0.00376957955 3.13352499014 0.010 -0.015 -0.001 C -2.63984642995 0.00218980399 1.17162612704 -0.007 -0.149 -0.011 N -1.98513620489 0.00132140951 0.00153900685 -0.000 0.035 -0.013 C -2.63911589169 0.00167522827 -1.17277445342 0.007 0.074 -0.011 C -4.02452897564 0.00329996303 -1.20791476641 0.011 0.011 0.007 C -4.73391255267 0.00451580118 -0.00020876193 -0.000 0.011 0.002 C -4.02924140493 0.00399189729 1.20660077672 -0.012 -0.033 0.006 Co 0.00000000000 0.00000000000 0.00000000000 -0.000 -0.001 -0.002 N -0.43839318333 -0.00054206762 -2.12229806799 -0.006 0.061 -0.001 C -1.76408906064 -0.00030645034 -2.37697009192 0.000 -0.162 -0.000 C -2.24773885821 -0.00257631963 -3.67934971086 0.005 0.057 0.007 C -1.33713102227 -0.00526459193 -4.73855802198 0.003 0.016 0.008 C 0.02654101484 -0.00591797621 -4.46472703619 0.002 0.077 -0.003 C 0.43371721952 -0.00363389350 -3.13225443930 -0.010 0.004 -0.001 S -6.53329279136 0.00637481657 -0.11611178087 -0.001 -0.004 -0.000 N 2.00981687167 0.00259443239 -0.00000686048 0.000 -0.013 0.045 C 2.67119656792 1.17263645248 0.00045766926 0.008 -0.012 -0.205 C 4.06129317470 1.20536051565 0.00241240325 0.012 0.007 -0.047 C 4.76783866331 0.00148799420 0.00346798881 -0.000 0.002 0.015 C 4.05723810074 -1.20352939940 0.00211502115 -0.012 0.007 0.017 C 2.67108506586 -1.17139122066 0.00026591651 -0.008 -0.012 0.108 C 1.82209539371 2.39842937406 -0.00175320633 0.000 0.000 0.358 C 2.33938959521 3.68993217240 -0.00584554905 0.006 0.007 -0.129 C 1.45736908622 4.77231118002 -0.00917967851 0.003 0.008 -0.049 C 0.08658913130 4.53522926787 -0.00833235387 0.002 -0.004 -0.176 C -0.35359617412 3.21325694137 -0.00400174376 -0.011 -0.001 -0.019 N 0.49290585413 2.18198449515 -0.00068475564 -0.007 -0.001 -0.120 S 6.56718562933 -0.11349126889 0.00673479967 0.001 -0.000 -0.005 C 1.82142022278 -2.39594383179 -0.00206827421 -0.000 -0.000 -0.231 C 2.33969079820 -3.68709653410 -0.00625612120 -0.006 0.007 0.083 C 1.45789786198 -4.76953179608 -0.00945089783 -0.003 0.008 0.023 C 0.08684213972 -4.53272927032 -0.00840538011 -0.002 -0.004 0.110 C -0.35393854068 -3.21111942258 -0.00398541364 0.011 -0.001 0.005 N 0.49225266031 -2.17934076887 -0.00084210065 0.007 -0.001 0.084 H 1.83694111827 5.77332096953 -0.01265611066 -0.002 0.005 0.268 H -0.61802819388 5.33967450634 -0.01131742088 0.001 0.001 0.300 H 3.39175422949 3.87200638269 -0.00704552340 0.002 0.002 0.054 H -1.39787683933 2.98334799634 -0.00369736757 -0.004 0.002 0.232 H 1.83794742242 -5.77033326187 -0.01295832570 0.002 0.004 -0.160 H -0.61749414542 -5.33746053721 -0.01121572048 -0.001 0.000 -0.175 H -1.39833026435 -2.98175334118 -0.00345676225 0.004 0.002 -0.143 H 3.39230213722 -3.86796714602 -0.00754158092 -0.002 0.002 -0.026 H 4.58301895157 2.13678100538 0.00314824260 0.002 0.003 0.172 H 4.58784714512 -2.12983634010 0.00211631073 -0.002 0.003 -0.052 H -1.68997263563 -0.00719388386 -5.74925805817 -0.002 -0.112 0.004 H 0.75224758084 -0.00860493512 -5.25016290812 0.001 -0.124 -0.000 H -3.29620044300 -0.00255800648 -3.88456579214 0.002 -0.017 0.002 H 1.47161249279 -0.00457826661 -2.87685200854 -0.004 -0.102 0.001 H -1.69176120521 -0.00597000955 5.75026973076 0.002 0.192 0.004 H 0.75025791005 -0.00892914887 5.25161119224 -0.001 0.218 0.000 H 1.46975366817 -0.00523069331 2.87805400798 0.004 0.169 0.001 H -3.29750276746 -0.00099200484 3.88584245085 -0.002 0.037 0.002 H -4.55513299541 0.00377930937 -2.13473279421 0.002 -0.033 0.003 H -4.55107479454 0.00501307822 2.13844314827 -0.002 0.123 0.003 H -6.83436893102 0.00806057203 1.19721860356 0.005 0.006 0.001 H 6.86748209639 1.20005966818 0.00372860376 -0.006 0.001 0.009 61 Mode 78: freq=919.94 N -0.44003451495 -0.00038510790 2.12369783068 0.002 0.035 -0.000 C -1.76594470239 0.00039861437 2.37754210613 -0.000 -0.157 -0.000 C -2.24923313135 -0.00145267054 3.67997125809 -0.001 0.051 0.002 C -1.33887502024 -0.00450793845 4.73956848945 -0.001 0.040 0.002 C 0.02462671625 -0.00591801736 4.46614405978 -0.001 0.084 -0.001 C 0.43187566201 -0.00376957955 3.13352499014 0.003 0.026 -0.000 C -2.63984642995 0.00218980399 1.17162612704 -0.002 0.153 -0.003 N -1.98513620489 0.00132140951 0.00153900685 -0.000 -0.171 -0.003 C -2.63911589169 0.00167522827 -1.17277445342 0.002 0.228 -0.003 C -4.02452897564 0.00329996303 -1.20791476641 0.003 0.029 0.002 C -4.73391255267 0.00451580118 -0.00020876193 -0.000 -0.039 0.001 C -4.02924140493 0.00399189729 1.20660077672 -0.003 0.034 0.001 Co 0.00000000000 0.00000000000 0.00000000000 0.000 0.006 -0.000 N -0.43839318333 -0.00054206762 -2.12229806799 -0.002 0.079 -0.000 C -1.76408906064 -0.00030645034 -2.37697009192 0.000 -0.284 0.000 C -2.24773885821 -0.00257631963 -3.67934971086 0.002 0.095 0.001 C -1.33713102227 -0.00526459193 -4.73855802198 0.001 0.053 0.002 C 0.02654101484 -0.00591797621 -4.46472703619 0.001 0.144 -0.001 C 0.43371721952 -0.00363389350 -3.13225443930 -0.003 0.031 -0.000 S -6.53329279136 0.00637481657 -0.11611178087 -0.000 0.010 -0.000 N 2.00981687167 0.00259443239 -0.00000686048 -0.005 0.206 0.008 C 2.67119656792 1.17263645248 0.00045766926 -0.115 0.184 -0.020 C 4.06129317470 1.20536051565 0.00241240325 -0.187 -0.104 -0.004 C 4.76783866331 0.00148799420 0.00346798881 0.002 -0.033 0.002 C 4.05723810074 -1.20352939940 0.00211502115 0.188 -0.103 0.001 C 2.67108506586 -1.17139122066 0.00026591651 0.115 0.186 0.003 C 1.82209539371 2.39842937406 -0.00175320633 -0.005 0.011 0.032 C 2.33938959521 3.68993217240 -0.00584554905 -0.091 -0.110 -0.011 C 1.45736908622 4.77231118002 -0.00917967851 -0.051 -0.124 -0.004 C 0.08658913130 4.53522926787 -0.00833235387 -0.037 0.062 -0.016 C -0.35359617412 3.21325694137 -0.00400174376 0.162 0.013 -0.002 N 0.49290585413 2.18198449515 -0.00068475564 0.100 0.016 -0.011 S 6.56718562933 -0.11349126889 0.00673479967 -0.014 -0.000 -0.001 C 1.82142022278 -2.39594383179 -0.00206827421 0.005 0.011 -0.011 C 2.33969079820 -3.68709653410 -0.00625612120 0.092 -0.111 0.004 C 1.45789786198 -4.76953179608 -0.00945089783 0.051 -0.125 0.000 C 0.08684213972 -4.53272927032 -0.00840538011 0.037 0.062 0.005 C -0.35393854068 -3.21111942258 -0.00398541364 -0.163 0.014 -0.000 N 0.49225266031 -2.17934076887 -0.00084210065 -0.101 0.017 0.005 H 1.83694111827 5.77332096953 -0.01265611066 0.037 -0.058 0.025 H -0.61802819388 5.33967450634 -0.01131742088 -0.018 0.010 0.028 H 3.39175422949 3.87200638269 -0.00704552340 -0.029 -0.032 0.005 H -1.39787683933 2.98334799634 -0.00369736757 0.055 -0.021 0.022 H 1.83794742242 -5.77033326187 -0.01295832570 -0.037 -0.058 -0.007 H -0.61749414542 -5.33746053721 -0.01121572048 0.018 0.010 -0.008 H -1.39833026435 -2.98175334118 -0.00345676225 -0.055 -0.021 -0.007 H 3.39230213722 -3.86796714602 -0.00754158092 0.029 -0.032 -0.001 H 4.58301895157 2.13678100538 0.00314824260 -0.034 -0.043 0.017 H 4.58784714512 -2.12983634010 0.00211631073 0.038 -0.041 0.001 H -1.68997263563 -0.00719388386 -5.74925805817 -0.001 -0.226 0.001 H 0.75224758084 -0.00860493512 -5.25016290812 -0.000 -0.269 0.001 H -3.29620044300 -0.00255800648 -3.88456579214 0.000 -0.050 0.001 H 1.47161249279 -0.00457826661 -2.87685200854 -0.001 -0.194 0.001 H -1.69176120521 -0.00597000955 5.75026973076 0.000 -0.139 0.001 H 0.75025791005 -0.00892914887 5.25161119224 -0.001 -0.170 -0.001 H 1.46975366817 -0.00523069331 2.87805400798 0.001 -0.116 0.000 H -3.29750276746 -0.00099200484 3.88584245085 -0.000 -0.037 0.000 H -4.55513299541 0.00377930937 -2.13473279421 0.000 -0.204 0.001 H -4.55107479454 0.00501307822 2.13844314827 -0.001 -0.183 0.001 H -6.83436893102 0.00806057203 1.19721860356 0.001 0.008 0.000 H 6.86748209639 1.20005966818 0.00372860376 0.085 -0.020 0.001 61 Mode 79: freq=920.54 N -0.44003451495 -0.00038510790 2.12369783068 0.057 0.010 -0.011 C -1.76594470239 0.00039861437 2.37754210613 -0.004 -0.028 -0.006 C -2.24923313135 -0.00145267054 3.67997125809 -0.050 0.009 0.063 C -1.33887502024 -0.00450793845 4.73956848945 -0.027 0.003 0.073 C 0.02462671625 -0.00591801736 4.46614405978 -0.021 0.014 -0.032 C 0.43187566201 -0.00376957955 3.13352499014 0.093 0.001 -0.010 C -2.63984642995 0.00218980399 1.17162612704 -0.066 0.015 -0.105 N -1.98513620489 0.00132140951 0.00153900685 -0.003 -0.002 -0.115 C -2.63911589169 0.00167522827 -1.17277445342 0.066 -0.010 -0.105 C -4.02452897564 0.00329996303 -1.20791476641 0.107 -0.001 0.058 C -4.73391255267 0.00451580118 -0.00020876193 0.001 -0.001 0.019 C -4.02924140493 0.00399189729 1.20660077672 -0.106 0.003 0.059 Co 0.00000000000 0.00000000000 0.00000000000 0.000 0.000 -0.009 N -0.43839318333 -0.00054206762 -2.12229806799 -0.058 -0.008 -0.012 C -1.76408906064 -0.00030645034 -2.37697009192 0.004 0.021 -0.006 C -2.24773885821 -0.00257631963 -3.67934971086 0.050 -0.007 0.064 C -1.33713102227 -0.00526459193 -4.73855802198 0.027 -0.002 0.074 C 0.02654101484 -0.00591797621 -4.46472703619 0.021 -0.010 -0.033 C 0.43371721952 -0.00363389350 -3.13225443930 -0.094 -0.001 -0.010 S -6.53329279136 0.00637481657 -0.11611178087 -0.008 0.000 -0.000 N 2.00981687167 0.00259443239 -0.00000686048 -0.000 -0.010 0.205 C 2.67119656792 1.17263645248 0.00045766926 0.005 -0.009 -0.180 C 4.06129317470 1.20536051565 0.00241240325 0.009 0.005 -0.043 C 4.76783866331 0.00148799420 0.00346798881 -0.000 0.002 0.050 C 4.05723810074 -1.20352939940 0.00211502115 -0.009 0.005 -0.039 C 2.67108506586 -1.17139122066 0.00026591651 -0.005 -0.009 -0.278 C 1.82209539371 2.39842937406 -0.00175320633 0.000 0.000 0.188 C 2.33938959521 3.68993217240 -0.00584554905 0.004 0.005 -0.063 C 1.45736908622 4.77231118002 -0.00917967851 0.002 0.006 -0.046 C 0.08658913130 4.53522926787 -0.00833235387 0.002 -0.003 -0.101 C -0.35359617412 3.21325694137 -0.00400174376 -0.007 -0.001 -0.029 N 0.49290585413 2.18198449515 -0.00068475564 -0.005 -0.001 -0.045 S 6.56718562933 -0.11349126889 0.00673479967 0.001 -0.000 -0.012 C 1.82142022278 -2.39594383179 -0.00206827421 -0.000 -0.002 0.357 C 2.33969079820 -3.68709653410 -0.00625612120 -0.004 0.006 -0.123 C 1.45789786198 -4.76953179608 -0.00945089783 -0.002 0.006 -0.064 C 0.08684213972 -4.53272927032 -0.00840538011 -0.002 -0.002 -0.180 C -0.35393854068 -3.21111942258 -0.00398541364 0.007 -0.001 -0.035 N 0.49225266031 -2.17934076887 -0.00084210065 0.005 -0.000 -0.103 H 1.83694111827 5.77332096953 -0.01265611066 -0.002 0.003 0.168 H -0.61802819388 5.33967450634 -0.01131742088 0.001 0.000 0.201 H 3.39175422949 3.87200638269 -0.00704552340 0.001 0.002 0.046 H -1.39787683933 2.98334799634 -0.00369736757 -0.003 0.002 0.138 H 1.83794742242 -5.77033326187 -0.01295832570 0.002 0.002 0.284 H -0.61749414542 -5.33746053721 -0.01121572048 -0.001 -0.002 0.331 H -1.39833026435 -2.98175334118 -0.00345676225 0.002 0.000 0.242 H 3.39230213722 -3.86796714602 -0.00754158092 -0.001 0.001 0.064 H 4.58301895157 2.13678100538 0.00314824260 0.001 0.002 0.221 H 4.58784714512 -2.12983634010 0.00211631073 -0.002 0.002 0.251 H -1.68997263563 -0.00719388386 -5.74925805817 -0.021 0.014 0.033 H 0.75224758084 -0.00860493512 -5.25016290812 0.011 0.016 -0.005 H -3.29620044300 -0.00255800648 -3.88456579214 0.016 0.002 0.018 H 1.47161249279 -0.00457826661 -2.87685200854 -0.032 0.014 0.010 H -1.69176120521 -0.00597000955 5.75026973076 0.021 -0.020 0.032 H 0.75025791005 -0.00892914887 5.25161119224 -0.011 -0.023 -0.005 H 1.46975366817 -0.00523069331 2.87805400798 0.031 -0.018 0.010 H -3.29750276746 -0.00099200484 3.88584245085 -0.016 -0.003 0.018 H -4.55513299541 0.00377930937 -2.13473279421 0.022 0.005 0.023 H -4.55107479454 0.00501307822 2.13844314827 -0.019 -0.012 0.025 H -6.83436893102 0.00806057203 1.19721860356 0.048 -0.001 0.011 H 6.86748209639 1.20005966818 0.00372860376 -0.004 0.001 -0.010 61 Mode 80: freq=921.79 N -0.44003451495 -0.00038510790 2.12369783068 -0.002 0.051 0.000 C -1.76594470239 0.00039861437 2.37754210613 -0.000 -0.167 -0.000 C -2.24923313135 -0.00145267054 3.67997125809 0.002 0.054 -0.002 C -1.33887502024 -0.00450793845 4.73956848945 0.001 0.035 -0.003 C 0.02462671625 -0.00591801736 4.46614405978 0.001 0.088 0.002 C 0.43187566201 -0.00376957955 3.13352499014 -0.003 0.017 0.001 C -2.63984642995 0.00218980399 1.17162612704 0.003 0.147 0.004 N -1.98513620489 0.00132140951 0.00153900685 -0.000 -0.152 0.004 C -2.63911589169 0.00167522827 -1.17277445342 -0.002 0.186 0.004 C -4.02452897564 0.00329996303 -1.20791476641 -0.004 0.027 -0.002 C -4.73391255267 0.00451580118 -0.00020876193 0.000 -0.037 -0.001 C -4.02924140493 0.00399189729 1.20660077672 0.004 0.037 -0.002 Co 0.00000000000 0.00000000000 0.00000000000 -0.001 0.009 0.000 N -0.43839318333 -0.00054206762 -2.12229806799 0.002 0.073 0.000 C -1.76408906064 -0.00030645034 -2.37697009192 -0.000 -0.230 0.001 C -2.24773885821 -0.00257631963 -3.67934971086 -0.002 0.075 -0.003 C -1.33713102227 -0.00526459193 -4.73855802198 -0.001 0.040 -0.003 C 0.02654101484 -0.00591797621 -4.46472703619 -0.001 0.116 0.001 C 0.43371721952 -0.00363389350 -3.13225443930 0.003 0.019 0.000 S -6.53329279136 0.00637481657 -0.11611178087 0.000 0.009 -0.000 N 2.00981687167 0.00259443239 -0.00000686048 0.006 -0.237 -0.003 C 2.67119656792 1.17263645248 0.00045766926 0.130 -0.217 -0.004 C 4.06129317470 1.20536051565 0.00241240325 0.216 0.118 -0.001 C 4.76783866331 0.00148799420 0.00346798881 -0.004 0.042 -0.001 C 4.05723810074 -1.20352939940 0.00211502115 -0.218 0.114 0.001 C 2.67108506586 -1.17139122066 0.00026591651 -0.130 -0.220 0.011 C 1.82209539371 2.39842937406 -0.00175320633 0.009 -0.013 0.012 C 2.33938959521 3.68993217240 -0.00584554905 0.107 0.128 -0.005 C 1.45736908622 4.77231118002 -0.00917967851 0.055 0.142 -0.001 C 0.08658913130 4.53522926787 -0.00833235387 0.042 -0.074 -0.005 C -0.35359617412 3.21325694137 -0.00400174376 -0.183 -0.016 0.000 N 0.49290585413 2.18198449515 -0.00068475564 -0.115 -0.017 -0.005 S 6.56718562933 -0.11349126889 0.00673479967 0.016 0.001 0.000 C 1.82142022278 -2.39594383179 -0.00206827421 -0.009 -0.013 -0.020 C 2.33969079820 -3.68709653410 -0.00625612120 -0.108 0.129 0.007 C 1.45789786198 -4.76953179608 -0.00945089783 -0.056 0.144 0.003 C 0.08684213972 -4.53272927032 -0.00840538011 -0.042 -0.075 0.009 C -0.35393854068 -3.21111942258 -0.00398541364 0.185 -0.017 0.001 N 0.49225266031 -2.17934076887 -0.00084210065 0.117 -0.018 0.007 H 1.83694111827 5.77332096953 -0.01265611066 -0.045 0.067 0.007 H -0.61802819388 5.33967450634 -0.01131742088 0.020 -0.014 0.008 H 3.39175422949 3.87200638269 -0.00704552340 0.034 0.039 0.001 H -1.39787683933 2.98334799634 -0.00369736757 -0.063 0.028 0.007 H 1.83794742242 -5.77033326187 -0.01295832570 0.045 0.068 -0.014 H -0.61749414542 -5.33746053721 -0.01121572048 -0.020 -0.014 -0.016 H -1.39833026435 -2.98175334118 -0.00345676225 0.063 0.028 -0.012 H 3.39230213722 -3.86796714602 -0.00754158092 -0.034 0.039 -0.002 H 4.58301895157 2.13678100538 0.00314824260 0.038 0.050 0.002 H 4.58784714512 -2.12983634010 0.00211631073 -0.043 0.047 -0.008 H -1.68997263563 -0.00719388386 -5.74925805817 0.001 -0.180 -0.001 H 0.75224758084 -0.00860493512 -5.25016290812 -0.001 -0.211 0.001 H -3.29620044300 -0.00255800648 -3.88456579214 -0.001 -0.036 -0.001 H 1.47161249279 -0.00457826661 -2.87685200854 0.001 -0.155 -0.000 H -1.69176120521 -0.00597000955 5.75026973076 -0.001 -0.139 -0.002 H 0.75025791005 -0.00892914887 5.25161119224 0.000 -0.165 -0.000 H 1.46975366817 -0.00523069331 2.87805400798 -0.001 -0.117 -0.001 H -3.29750276746 -0.00099200484 3.88584245085 0.001 -0.032 -0.001 H -4.55513299541 0.00377930937 -2.13473279421 -0.001 -0.174 -0.001 H -4.55107479454 0.00501307822 2.13844314827 0.000 -0.175 -0.001 H -6.83436893102 0.00806057203 1.19721860356 -0.002 0.007 -0.000 H 6.86748209639 1.20005966818 0.00372860376 -0.093 0.022 0.000 61 Mode 81: freq=923.04 N -0.44003451495 -0.00038510790 2.12369783068 -0.143 0.003 0.026 C -1.76594470239 0.00039861437 2.37754210613 0.015 -0.007 0.017 C -2.24923313135 -0.00145267054 3.67997125809 0.127 0.002 -0.159 C -1.33887502024 -0.00450793845 4.73956848945 0.062 0.001 -0.180 C 0.02462671625 -0.00591801736 4.46614405978 0.054 0.003 0.087 C 0.43187566201 -0.00376957955 3.13352499014 -0.225 0.000 0.027 C -2.63984642995 0.00218980399 1.17162612704 0.160 0.003 0.268 N -1.98513620489 0.00132140951 0.00153900685 0.007 0.001 0.285 C -2.63911589169 0.00167522827 -1.17277445342 -0.160 -0.004 0.272 C -4.02452897564 0.00329996303 -1.20791476641 -0.268 -0.000 -0.138 C -4.73391255267 0.00451580118 -0.00020876193 -0.005 0.000 -0.054 C -4.02924140493 0.00399189729 1.20660077672 0.266 0.000 -0.145 Co 0.00000000000 0.00000000000 0.00000000000 -0.001 -0.000 -0.009 N -0.43839318333 -0.00054206762 -2.12229806799 0.146 -0.003 0.027 C -1.76408906064 -0.00030645034 -2.37697009192 -0.015 0.008 0.017 C -2.24773885821 -0.00257631963 -3.67934971086 -0.128 -0.003 -0.161 C -1.33713102227 -0.00526459193 -4.73855802198 -0.063 -0.001 -0.183 C 0.02654101484 -0.00591797621 -4.46472703619 -0.055 -0.003 0.088 C 0.43371721952 -0.00363389350 -3.13225443930 0.227 -0.000 0.027 S -6.53329279136 0.00637481657 -0.11611178087 0.020 0.000 -0.001 N 2.00981687167 0.00259443239 -0.00000686048 -0.000 0.002 0.085 C 2.67119656792 1.17263645248 0.00045766926 -0.001 0.001 -0.082 C 4.06129317470 1.20536051565 0.00241240325 -0.001 -0.001 -0.023 C 4.76783866331 0.00148799420 0.00346798881 0.000 -0.000 0.023 C 4.05723810074 -1.20352939940 0.00211502115 0.002 -0.001 -0.017 C 2.67108506586 -1.17139122066 0.00026591651 0.001 0.002 -0.103 C 1.82209539371 2.39842937406 -0.00175320633 -0.000 0.000 0.098 C 2.33938959521 3.68993217240 -0.00584554905 -0.001 -0.001 -0.033 C 1.45736908622 4.77231118002 -0.00917967851 -0.000 -0.001 -0.019 C 0.08658913130 4.53522926787 -0.00833235387 -0.000 0.000 -0.052 C -0.35359617412 3.21325694137 -0.00400174376 0.001 -0.000 -0.007 N 0.49290585413 2.18198449515 -0.00068475564 0.001 0.000 -0.034 S 6.56718562933 -0.11349126889 0.00673479967 -0.000 -0.000 -0.005 C 1.82142022278 -2.39594383179 -0.00206827421 0.000 -0.000 0.131 C 2.33969079820 -3.68709653410 -0.00625612120 0.001 -0.001 -0.044 C 1.45789786198 -4.76953179608 -0.00945089783 0.000 -0.001 -0.022 C 0.08684213972 -4.53272927032 -0.00840538011 0.000 0.001 -0.067 C -0.35393854068 -3.21111942258 -0.00398541364 -0.001 0.000 -0.008 N 0.49225266031 -2.17934076887 -0.00084210065 -0.001 0.000 -0.045 H 1.83694111827 5.77332096953 -0.01265611066 0.000 -0.000 0.081 H -0.61802819388 5.33967450634 -0.01131742088 -0.000 0.000 0.094 H 3.39175422949 3.87200638269 -0.00704552340 -0.000 -0.000 0.018 H -1.39787683933 2.98334799634 -0.00369736757 0.000 -0.000 0.068 H 1.83794742242 -5.77033326187 -0.01295832570 -0.000 -0.001 0.102 H -0.61749414542 -5.33746053721 -0.01121572048 0.000 -0.000 0.117 H -1.39833026435 -2.98175334118 -0.00345676225 -0.000 -0.000 0.087 H 3.39230213722 -3.86796714602 -0.00754158092 0.000 -0.000 0.021 H 4.58301895157 2.13678100538 0.00314824260 -0.000 -0.000 0.102 H 4.58784714512 -2.12983634010 0.00211631073 0.000 -0.000 0.100 H -1.68997263563 -0.00719388386 -5.74925805817 0.057 0.005 -0.083 H 0.75224758084 -0.00860493512 -5.25016290812 -0.025 0.006 0.016 H -3.29620044300 -0.00255800648 -3.88456579214 -0.041 0.001 -0.048 H 1.47161249279 -0.00457826661 -2.87685200854 0.079 0.005 -0.032 H -1.69176120521 -0.00597000955 5.75026973076 -0.057 -0.004 -0.082 H 0.75025791005 -0.00892914887 5.25161119224 0.025 -0.005 0.016 H 1.46975366817 -0.00523069331 2.87805400798 -0.078 -0.004 -0.031 H -3.29750276746 -0.00099200484 3.88584245085 0.040 -0.000 -0.049 H -4.55513299541 0.00377930937 -2.13473279421 -0.051 0.003 -0.058 H -4.55107479454 0.00501307822 2.13844314827 0.046 -0.002 -0.061 H -6.83436893102 0.00806057203 1.19721860356 -0.112 -0.000 -0.027 H 6.86748209639 1.20005966818 0.00372860376 0.000 -0.000 -0.004 61 Mode 82: freq=1008.19 N -0.44003451495 -0.00038510790 2.12369783068 0.030 0.000 -0.012 C -1.76594470239 0.00039861437 2.37754210613 -0.021 -0.000 -0.009 C -2.24923313135 -0.00145267054 3.67997125809 -0.012 0.000 -0.002 C -1.33887502024 -0.00450793845 4.73956848945 0.003 -0.000 0.029 C 0.02462671625 -0.00591801736 4.46614405978 -0.003 0.000 0.009 C 0.43187566201 -0.00376957955 3.13352499014 0.028 -0.000 -0.013 C -2.63984642995 0.00218980399 1.17162612704 -0.040 0.000 -0.034 N -1.98513620489 0.00132140951 0.00153900685 0.050 -0.000 0.064 C -2.63911589169 0.00167522827 -1.17277445342 0.091 0.000 -0.063 C -4.02452897564 0.00329996303 -1.20791476641 0.098 -0.001 -0.195 C -4.73391255267 0.00451580118 -0.00020876193 0.011 0.000 0.041 C -4.02924140493 0.00399189729 1.20660077672 -0.095 -0.000 -0.071 Co 0.00000000000 0.00000000000 0.00000000000 -0.006 -0.000 -0.002 N -0.43839318333 -0.00054206762 -2.12229806799 -0.057 0.000 -0.032 C -1.76408906064 -0.00030645034 -2.37697009192 0.040 -0.000 -0.022 C -2.24773885821 -0.00257631963 -3.67934971086 0.034 0.000 0.011 C -1.33713102227 -0.00526459193 -4.73855802198 0.003 0.000 0.056 C 0.02654101484 -0.00591797621 -4.46472703619 0.001 0.000 0.017 C 0.43371721952 -0.00363389350 -3.13225443930 -0.068 -0.000 -0.014 S -6.53329279136 0.00637481657 -0.11611178087 0.113 0.000 0.189 N 2.00981687167 0.00259443239 -0.00000686048 -0.002 0.001 0.004 C 2.67119656792 1.17263645248 0.00045766926 0.001 -0.000 -0.004 C 4.06129317470 1.20536051565 0.00241240325 0.002 0.001 0.004 C 4.76783866331 0.00148799420 0.00346798881 -0.002 0.001 -0.002 C 4.05723810074 -1.20352939940 0.00211502115 -0.001 -0.005 0.003 C 2.67108506586 -1.17139122066 0.00026591651 -0.001 -0.002 -0.003 C 1.82209539371 2.39842937406 -0.00175320633 0.001 -0.000 0.002 C 2.33938959521 3.68993217240 -0.00584554905 0.001 0.000 -0.001 C 1.45736908622 4.77231118002 -0.00917967851 -0.000 0.000 -0.001 C 0.08658913130 4.53522926787 -0.00833235387 -0.001 0.001 -0.001 C -0.35359617412 3.21325694137 -0.00400174376 -0.001 0.000 0.000 N 0.49290585413 2.18198449515 -0.00068475564 -0.001 -0.001 0.001 S 6.56718562933 -0.11349126889 0.00673479967 -0.001 0.003 0.000 C 1.82142022278 -2.39594383179 -0.00206827421 0.000 -0.000 0.002 C 2.33969079820 -3.68709653410 -0.00625612120 0.000 0.000 -0.001 C 1.45789786198 -4.76953179608 -0.00945089783 -0.000 0.001 -0.001 C 0.08684213972 -4.53272927032 -0.00840538011 -0.001 -0.001 -0.001 C -0.35393854068 -3.21111942258 -0.00398541364 0.001 -0.001 0.000 N 0.49225266031 -2.17934076887 -0.00084210065 0.001 0.001 0.001 H 1.83694111827 5.77332096953 -0.01265611066 0.000 0.000 0.002 H -0.61802819388 5.33967450634 -0.01131742088 -0.000 0.001 0.001 H 3.39175422949 3.87200638269 -0.00704552340 0.000 0.000 0.001 H -1.39787683933 2.98334799634 -0.00369736757 -0.000 0.000 -0.000 H 1.83794742242 -5.77033326187 -0.01295832570 0.000 0.001 0.002 H -0.61749414542 -5.33746053721 -0.01121572048 -0.000 -0.000 0.001 H -1.39833026435 -2.98175334118 -0.00345676225 0.000 0.000 -0.000 H 3.39230213722 -3.86796714602 -0.00754158092 0.000 -0.000 0.001 H 4.58301895157 2.13678100538 0.00314824260 0.002 -0.000 -0.005 H 4.58784714512 -2.12983634010 0.00211631073 -0.000 -0.001 -0.002 H -1.68997263563 -0.00719388386 -5.74925805817 -0.010 0.000 0.021 H 0.75224758084 -0.00860493512 -5.25016290812 0.004 0.000 0.010 H -3.29620044300 -0.00255800648 -3.88456579214 0.013 -0.000 -0.002 H 1.47161249279 -0.00457826661 -2.87685200854 -0.024 0.000 0.007 H -1.69176120521 -0.00597000955 5.75026973076 0.005 -0.000 0.010 H 0.75025791005 -0.00892914887 5.25161119224 -0.001 -0.000 0.003 H 1.46975366817 -0.00523069331 2.87805400798 0.010 -0.000 0.002 H -3.29750276746 -0.00099200484 3.88584245085 -0.006 0.000 -0.007 H -4.55513299541 0.00377930937 -2.13473279421 0.043 0.000 -0.068 H -4.55107479454 0.00501307822 2.13844314827 -0.062 0.000 -0.041 H -6.83436893102 0.00806057203 1.19721860356 -0.896 0.001 -0.176 H 6.86748209639 1.20005966818 0.00372860376 0.014 -0.003 0.000 61 Mode 83: freq=1008.49 N -0.44003451495 -0.00038510790 2.12369783068 0.001 -0.001 -0.000 C -1.76594470239 0.00039861437 2.37754210613 -0.000 -0.002 -0.000 C -2.24923313135 -0.00145267054 3.67997125809 -0.001 0.001 0.000 C -1.33887502024 -0.00450793845 4.73956848945 0.000 0.001 0.000 C 0.02462671625 -0.00591801736 4.46614405978 0.000 0.001 0.000 C 0.43187566201 -0.00376957955 3.13352499014 0.000 -0.000 -0.000 C -2.63984642995 0.00218980399 1.17162612704 -0.001 0.004 -0.001 N -1.98513620489 0.00132140951 0.00153900685 0.000 -0.004 0.001 C -2.63911589169 0.00167522827 -1.17277445342 0.002 0.003 -0.001 C -4.02452897564 0.00329996303 -1.20791476641 0.002 -0.002 -0.002 C -4.73391255267 0.00451580118 -0.00020876193 -0.000 0.002 0.001 C -4.02924140493 0.00399189729 1.20660077672 -0.001 -0.004 -0.002 Co 0.00000000000 0.00000000000 0.00000000000 -0.005 0.002 -0.000 N -0.43839318333 -0.00054206762 -2.12229806799 -0.001 -0.001 -0.000 C -1.76408906064 -0.00030645034 -2.37697009192 0.001 -0.001 -0.000 C -2.24773885821 -0.00257631963 -3.67934971086 0.000 0.000 0.000 C -1.33713102227 -0.00526459193 -4.73855802198 0.000 0.001 0.001 C 0.02654101484 -0.00591797621 -4.46472703619 0.000 0.001 0.000 C 0.43371721952 -0.00363389350 -3.13225443930 -0.001 0.000 -0.000 S -6.53329279136 0.00637481657 -0.11611178087 0.002 -0.000 0.003 N 2.00981687167 0.00259443239 -0.00000686048 0.053 -0.063 -0.001 C 2.67119656792 1.17263645248 0.00045766926 -0.043 0.035 0.002 C 4.06129317470 1.20536051565 0.00241240325 -0.097 0.067 -0.004 C 4.76783866331 0.00148799420 0.00346798881 0.015 -0.038 0.001 C 4.05723810074 -1.20352939940 0.00211502115 0.097 0.196 -0.002 C 2.67108506586 -1.17139122066 0.00026591651 0.093 0.068 0.002 C 1.82209539371 2.39842937406 -0.00175320633 -0.021 0.010 -0.001 C 2.33938959521 3.68993217240 -0.00584554905 -0.015 0.001 0.001 C 1.45736908622 4.77231118002 -0.00917967851 0.001 -0.030 -0.000 C 0.08658913130 4.53522926787 -0.00833235387 -0.001 -0.011 0.000 C -0.35359617412 3.21325694137 -0.00400174376 0.031 0.011 -0.000 N 0.49290585413 2.18198449515 -0.00068475564 0.031 0.012 0.000 S 6.56718562933 -0.11349126889 0.00673479967 0.113 -0.189 0.000 C 1.82142022278 -2.39594383179 -0.00206827421 0.038 0.024 -0.001 C 2.33969079820 -3.68709653410 -0.00625612120 0.034 -0.011 -0.000 C 1.45789786198 -4.76953179608 -0.00945089783 0.006 -0.058 -0.000 C 0.08684213972 -4.53272927032 -0.00840538011 0.000 -0.016 0.000 C -0.35393854068 -3.21111942258 -0.00398541364 -0.071 0.012 0.000 N 0.49225266031 -2.17934076887 -0.00084210065 -0.057 0.030 0.000 H 1.83694111827 5.77332096953 -0.01265611066 0.005 -0.011 -0.000 H -0.61802819388 5.33967450634 -0.01131742088 -0.001 -0.004 0.000 H 3.39175422949 3.87200638269 -0.00704552340 -0.007 0.007 -0.000 H -1.39787683933 2.98334799634 -0.00369736757 0.011 -0.002 0.000 H 1.83794742242 -5.77033326187 -0.01295832570 -0.010 -0.022 -0.000 H -0.61749414542 -5.33746053721 -0.01121572048 0.004 -0.009 -0.001 H -1.39833026435 -2.98175334118 -0.00345676225 -0.025 -0.008 -0.001 H 3.39230213722 -3.86796714602 -0.00754158092 0.013 0.004 0.001 H 4.58301895157 2.13678100538 0.00314824260 -0.063 0.040 0.004 H 4.58784714512 -2.12983634010 0.00211631073 0.041 0.067 0.002 H -1.68997263563 -0.00719388386 -5.74925805817 -0.000 -0.002 0.000 H 0.75224758084 -0.00860493512 -5.25016290812 0.000 -0.002 0.000 H -3.29620044300 -0.00255800648 -3.88456579214 0.000 -0.001 -0.000 H 1.47161249279 -0.00457826661 -2.87685200854 -0.000 -0.000 0.000 H -1.69176120521 -0.00597000955 5.75026973076 0.000 -0.002 0.000 H 0.75025791005 -0.00892914887 5.25161119224 -0.000 -0.002 0.000 H 1.46975366817 -0.00523069331 2.87805400798 0.000 -0.000 0.000 H -3.29750276746 -0.00099200484 3.88584245085 -0.000 -0.001 0.000 H -4.55513299541 0.00377930937 -2.13473279421 0.001 0.001 -0.001 H -4.55107479454 0.00501307822 2.13844314827 -0.001 0.004 -0.001 H -6.83436893102 0.00806057203 1.19721860356 -0.015 -0.000 -0.003 H 6.86748209639 1.20005966818 0.00372860376 -0.895 0.175 -0.002 61 Mode 84: freq=1017.90 N -0.44003451495 -0.00038510790 2.12369783068 0.001 -0.004 0.002 C -1.76594470239 0.00039861437 2.37754210613 0.001 0.015 -0.000 C -2.24923313135 -0.00145267054 3.67997125809 0.000 -0.008 0.002 C -1.33887502024 -0.00450793845 4.73956848945 -0.000 -0.000 0.000 C 0.02462671625 -0.00591801736 4.46614405978 -0.001 -0.002 -0.004 C 0.43187566201 -0.00376957955 3.13352499014 -0.000 0.005 0.000 C -2.63984642995 0.00218980399 1.17162612704 -0.001 -0.023 -0.002 N -1.98513620489 0.00132140951 0.00153900685 0.001 0.007 -0.001 C -2.63911589169 0.00167522827 -1.17277445342 0.002 -0.009 -0.003 C -4.02452897564 0.00329996303 -1.20791476641 0.002 0.010 -0.001 C -4.73391255267 0.00451580118 -0.00020876193 0.000 -0.015 0.000 C -4.02924140493 0.00399189729 1.20660077672 -0.002 0.036 -0.000 Co 0.00000000000 0.00000000000 0.00000000000 -0.000 -0.000 0.003 N -0.43839318333 -0.00054206762 -2.12229806799 -0.001 -0.001 0.001 C -1.76408906064 -0.00030645034 -2.37697009192 -0.001 0.002 -0.001 C -2.24773885821 -0.00257631963 -3.67934971086 0.000 0.004 0.002 C -1.33713102227 -0.00526459193 -4.73855802198 0.000 0.002 0.001 C 0.02654101484 -0.00591797621 -4.46472703619 0.001 -0.002 -0.004 C 0.43371721952 -0.00363389350 -3.13225443930 -0.000 -0.004 0.000 S -6.53329279136 0.00637481657 -0.11611178087 0.001 0.001 0.002 N 2.00981687167 0.00259443239 -0.00000686048 -0.000 0.001 -0.099 C 2.67119656792 1.17263645248 0.00045766926 -0.000 -0.000 0.322 C 4.06129317470 1.20536051565 0.00241240325 0.001 -0.001 -0.505 C 4.76783866331 0.00148799420 0.00346798881 -0.000 0.000 0.226 C 4.05723810074 -1.20352939940 0.00211502115 -0.000 -0.001 -0.168 C 2.67108506586 -1.17139122066 0.00026591651 -0.001 -0.000 0.151 C 1.82209539371 2.39842937406 -0.00175320633 0.000 -0.001 -0.201 C 2.33938959521 3.68993217240 -0.00584554905 0.000 0.000 0.079 C 1.45736908622 4.77231118002 -0.00917967851 -0.000 0.000 -0.011 C 0.08658913130 4.53522926787 -0.00833235387 -0.000 0.001 0.031 C -0.35359617412 3.21325694137 -0.00400174376 -0.000 -0.000 -0.033 N 0.49290585413 2.18198449515 -0.00068475564 -0.000 -0.000 0.059 S 6.56718562933 -0.11349126889 0.00673479967 -0.001 0.001 -0.019 C 1.82142022278 -2.39594383179 -0.00206827421 -0.000 0.000 -0.068 C 2.33969079820 -3.68709653410 -0.00625612120 -0.000 -0.000 -0.001 C 1.45789786198 -4.76953179608 -0.00945089783 0.000 0.000 -0.004 C 0.08684213972 -4.53272927032 -0.00840538011 -0.000 0.000 0.026 C -0.35393854068 -3.21111942258 -0.00398541364 0.000 -0.000 0.005 N 0.49225266031 -2.17934076887 -0.00084210065 0.000 -0.000 0.017 H 1.83694111827 5.77332096953 -0.01265611066 0.000 -0.000 -0.040 H -0.61802819388 5.33967450634 -0.01131742088 -0.000 0.000 -0.012 H 3.39175422949 3.87200638269 -0.00704552340 0.000 -0.000 -0.017 H -1.39787683933 2.98334799634 -0.00369736757 0.000 -0.000 0.003 H 1.83794742242 -5.77033326187 -0.01295832570 -0.000 0.000 -0.009 H -0.61749414542 -5.33746053721 -0.01121572048 -0.000 0.000 -0.039 H -1.39833026435 -2.98175334118 -0.00345676225 0.000 0.000 -0.027 H 3.39230213722 -3.86796714602 -0.00754158092 -0.000 -0.000 0.036 H 4.58301895157 2.13678100538 0.00314824260 -0.001 -0.000 0.661 H 4.58784714512 -2.12983634010 0.00211631073 -0.000 -0.001 0.156 H -1.68997263563 -0.00719388386 -5.74925805817 -0.002 -0.003 0.001 H 0.75224758084 -0.00860493512 -5.25016290812 0.000 0.004 -0.001 H -3.29620044300 -0.00255800648 -3.88456579214 0.000 -0.009 0.000 H 1.47161249279 -0.00457826661 -2.87685200854 -0.000 0.007 0.001 H -1.69176120521 -0.00597000955 5.75026973076 0.002 0.006 0.001 H 0.75025791005 -0.00892914887 5.25161119224 -0.000 0.000 -0.001 H 1.46975366817 -0.00523069331 2.87805400798 0.000 -0.003 0.001 H -3.29750276746 -0.00099200484 3.88584245085 0.000 0.006 0.000 H -4.55513299541 0.00377930937 -2.13473279421 0.001 -0.009 -0.000 H -4.55107479454 0.00501307822 2.13844314827 -0.001 -0.047 -0.000 H -6.83436893102 0.00806057203 1.19721860356 -0.008 0.000 -0.002 H 6.86748209639 1.20005966818 0.00372860376 0.006 -0.001 -0.004 61 Mode 85: freq=1018.47 N -0.44003451495 -0.00038510790 2.12369783068 -0.000 -0.055 -0.000 C -1.76594470239 0.00039861437 2.37754210613 -0.000 0.190 0.000 C -2.24923313135 -0.00145267054 3.67997125809 0.000 -0.057 -0.000 C -1.33887502024 -0.00450793845 4.73956848945 0.000 0.013 -0.000 C 0.02462671625 -0.00591801736 4.46614405978 -0.000 -0.038 0.000 C 0.43187566201 -0.00376957955 3.13352499014 0.000 0.020 -0.000 C -2.63984642995 0.00218980399 1.17162612704 -0.000 -0.316 0.000 N -1.98513620489 0.00132140951 0.00153900685 0.000 0.098 0.000 C -2.63911589169 0.00167522827 -1.17277445342 -0.000 -0.154 0.000 C -4.02452897564 0.00329996303 -1.20791476641 0.000 0.176 -0.000 C -4.73391255267 0.00451580118 -0.00020876193 -0.000 -0.228 0.000 C -4.02924140493 0.00399189729 1.20660077672 0.001 0.503 -0.000 Co 0.00000000000 0.00000000000 0.00000000000 -0.000 -0.003 -0.000 N -0.43839318333 -0.00054206762 -2.12229806799 0.000 -0.017 -0.000 C -1.76408906064 -0.00030645034 -2.37697009192 0.000 0.069 -0.000 C -2.24773885821 -0.00257631963 -3.67934971086 0.000 0.004 -0.000 C -1.33713102227 -0.00526459193 -4.73855802198 0.000 0.005 0.000 C 0.02654101484 -0.00591797621 -4.46472703619 -0.000 -0.028 0.000 C 0.43371721952 -0.00363389350 -3.13225443930 -0.000 -0.007 -0.000 S -6.53329279136 0.00637481657 -0.11611178087 0.000 0.020 -0.000 N 2.00981687167 0.00259443239 -0.00000686048 0.001 0.001 0.007 C 2.67119656792 1.17263645248 0.00045766926 -0.001 0.002 -0.022 C 4.06129317470 1.20536051565 0.00241240325 -0.002 0.000 0.036 C 4.76783866331 0.00148799420 0.00346798881 0.000 -0.000 -0.017 C 4.05723810074 -1.20352939940 0.00211502115 0.002 0.001 0.014 C 2.67108506586 -1.17139122066 0.00026591651 0.001 0.003 -0.013 C 1.82209539371 2.39842937406 -0.00175320633 0.001 0.000 0.012 C 2.33938959521 3.68993217240 -0.00584554905 -0.000 -0.002 -0.002 C 1.45736908622 4.77231118002 -0.00917967851 -0.000 -0.000 0.002 C 0.08658913130 4.53522926787 -0.00833235387 -0.001 0.004 -0.003 C -0.35359617412 3.21325694137 -0.00400174376 0.000 -0.000 -0.001 N 0.49290585413 2.18198449515 -0.00068475564 0.001 -0.001 -0.004 S 6.56718562933 -0.11349126889 0.00673479967 0.001 -0.002 0.001 C 1.82142022278 -2.39594383179 -0.00206827421 -0.001 0.001 0.007 C 2.33969079820 -3.68709653410 -0.00625612120 0.000 -0.002 -0.004 C 1.45789786198 -4.76953179608 -0.00945089783 0.000 -0.001 -0.001 C 0.08684213972 -4.53272927032 -0.00840538011 0.001 0.004 -0.001 C -0.35393854068 -3.21111942258 -0.00398541364 -0.000 -0.000 0.003 N 0.49225266031 -2.17934076887 -0.00084210065 -0.001 -0.001 -0.002 H 1.83694111827 5.77332096953 -0.01265611066 0.001 -0.001 -0.001 H -0.61802819388 5.33967450634 -0.01131742088 -0.000 0.001 0.003 H 3.39175422949 3.87200638269 -0.00704552340 -0.000 -0.000 -0.005 H -1.39787683933 2.98334799634 -0.00369736757 0.000 -0.001 0.004 H 1.83794742242 -5.77033326187 -0.01295832570 -0.001 -0.001 0.004 H -0.61749414542 -5.33746053721 -0.01121572048 0.000 0.001 0.001 H -1.39833026435 -2.98175334118 -0.00345676225 -0.000 -0.001 -0.003 H 3.39230213722 -3.86796714602 -0.00754158092 0.000 -0.000 0.003 H 4.58301895157 2.13678100538 0.00314824260 -0.001 0.000 -0.047 H 4.58784714512 -2.12983634010 0.00211631073 0.000 0.000 -0.014 H -1.68997263563 -0.00719388386 -5.74925805817 0.000 0.007 -0.000 H 0.75224758084 -0.00860493512 -5.25016290812 -0.000 0.043 -0.000 H -3.29620044300 -0.00255800648 -3.88456579214 -0.000 -0.043 0.000 H 1.47161249279 -0.00457826661 -2.87685200854 0.000 0.031 -0.000 H -1.69176120521 -0.00597000955 5.75026973076 -0.000 0.031 -0.000 H 0.75025791005 -0.00892914887 5.25161119224 -0.000 0.031 0.000 H 1.46975366817 -0.00523069331 2.87805400798 0.000 0.017 -0.000 H -3.29750276746 -0.00099200484 3.88584245085 0.000 -0.012 0.000 H -4.55513299541 0.00377930937 -2.13473279421 -0.000 -0.169 0.000 H -4.55107479454 0.00501307822 2.13844314827 -0.001 -0.663 0.000 H -6.83436893102 0.00806057203 1.19721860356 -0.000 0.005 -0.000 H 6.86748209639 1.20005966818 0.00372860376 -0.007 0.001 0.000 61 Mode 86: freq=1034.72 N -0.44003451495 -0.00038510790 2.12369783068 0.000 0.006 0.001 C -1.76594470239 0.00039861437 2.37754210613 0.001 -0.018 -0.000 C -2.24923313135 -0.00145267054 3.67997125809 0.000 0.033 0.001 C -1.33887502024 -0.00450793845 4.73956848945 -0.000 0.005 -0.000 C 0.02462671625 -0.00591801736 4.46614405978 -0.001 -0.011 -0.002 C 0.43187566201 -0.00376957955 3.13352499014 -0.000 -0.021 0.000 C -2.63984642995 0.00218980399 1.17162612704 -0.000 0.009 -0.001 N -1.98513620489 0.00132140951 0.00153900685 0.000 0.008 -0.000 C -2.63911589169 0.00167522827 -1.17277445342 0.000 -0.053 -0.001 C -4.02452897564 0.00329996303 -1.20791476641 0.001 0.096 -0.000 C -4.73391255267 0.00451580118 -0.00020876193 -0.000 -0.026 -0.000 C -4.02924140493 0.00399189729 1.20660077672 -0.001 -0.021 0.000 Co 0.00000000000 0.00000000000 0.00000000000 -0.000 -0.000 0.001 N -0.43839318333 -0.00054206762 -2.12229806799 -0.000 -0.012 0.001 C -1.76408906064 -0.00030645034 -2.37697009192 -0.001 0.041 -0.000 C -2.24773885821 -0.00257631963 -3.67934971086 -0.000 -0.035 0.001 C -1.33713102227 -0.00526459193 -4.73855802198 0.000 -0.003 0.000 C 0.02654101484 -0.00591797621 -4.46472703619 0.000 0.004 -0.002 C 0.43371721952 -0.00363389350 -3.13225443930 0.000 0.021 0.000 S -6.53329279136 0.00637481657 -0.11611178087 0.000 0.002 0.000 N 2.00981687167 0.00259443239 -0.00000686048 0.000 0.000 -0.035 C 2.67119656792 1.17263645248 0.00045766926 0.000 -0.000 -0.045 C 4.06129317470 1.20536051565 0.00241240325 -0.000 -0.000 0.105 C 4.76783866331 0.00148799420 0.00346798881 -0.000 0.000 0.111 C 4.05723810074 -1.20352939940 0.00211502115 0.001 0.000 -0.424 C 2.67108506586 -1.17139122066 0.00026591651 -0.000 -0.000 0.245 C 1.82209539371 2.39842937406 -0.00175320633 0.000 0.000 0.082 C 2.33938959521 3.68993217240 -0.00584554905 -0.000 -0.001 -0.144 C 1.45736908622 4.77231118002 -0.00917967851 0.000 -0.000 -0.017 C 0.08658913130 4.53522926787 -0.00833235387 0.000 0.000 0.053 C -0.35359617412 3.21325694137 -0.00400174376 -0.000 0.000 0.086 N 0.49290585413 2.18198449515 -0.00068475564 0.000 -0.000 -0.034 S 6.56718562933 -0.11349126889 0.00673479967 -0.000 0.000 -0.007 C 1.82142022278 -2.39594383179 -0.00206827421 -0.000 0.001 -0.195 C 2.33969079820 -3.68709653410 -0.00625612120 0.000 -0.001 0.186 C 1.45789786198 -4.76953179608 -0.00945089783 -0.000 -0.000 0.012 C 0.08684213972 -4.53272927032 -0.00840538011 -0.000 0.000 -0.035 C -0.35393854068 -3.21111942258 -0.00398541364 0.000 0.000 -0.106 N 0.49225266031 -2.17934076887 -0.00084210065 -0.000 -0.000 0.066 H 1.83694111827 5.77332096953 -0.01265611066 0.000 0.000 0.065 H -0.61802819388 5.33967450634 -0.01131742088 0.000 -0.000 -0.132 H 3.39175422949 3.87200638269 -0.00704552340 0.000 0.001 0.204 H -1.39787683933 2.98334799634 -0.00369736757 0.000 -0.000 -0.130 H 1.83794742242 -5.77033326187 -0.01295832570 -0.000 0.000 -0.088 H -0.61749414542 -5.33746053721 -0.01121572048 -0.000 -0.000 0.123 H -1.39833026435 -2.98175334118 -0.00345676225 0.000 -0.000 0.136 H 3.39230213722 -3.86796714602 -0.00754158092 -0.000 0.001 -0.213 H 4.58301895157 2.13678100538 0.00314824260 0.000 -0.000 -0.187 H 4.58784714512 -2.12983634010 0.00211631073 -0.001 -0.001 0.597 H -1.68997263563 -0.00719388386 -5.74925805817 -0.001 0.019 0.000 H 0.75224758084 -0.00860493512 -5.25016290812 0.000 -0.018 -0.000 H -3.29620044300 -0.00255800648 -3.88456579214 -0.000 0.038 0.000 H 1.47161249279 -0.00457826661 -2.87685200854 -0.000 -0.025 0.001 H -1.69176120521 -0.00597000955 5.75026973076 0.001 -0.017 0.000 H 0.75025791005 -0.00892914887 5.25161119224 -0.000 0.029 -0.000 H 1.46975366817 -0.00523069331 2.87805400798 0.000 0.031 0.001 H -3.29750276746 -0.00099200484 3.88584245085 0.000 -0.049 -0.000 H -4.55513299541 0.00377930937 -2.13473279421 0.000 -0.136 -0.000 H -4.55107479454 0.00501307822 2.13844314827 -0.000 0.039 -0.000 H -6.83436893102 0.00806057203 1.19721860356 -0.002 0.005 -0.000 H 6.86748209639 1.20005966818 0.00372860376 0.001 -0.000 -0.024 61 Mode 87: freq=1036.58 N -0.44003451495 -0.00038510790 2.12369783068 0.000 0.037 -0.000 C -1.76594470239 0.00039861437 2.37754210613 -0.000 -0.088 -0.000 C -2.24923313135 -0.00145267054 3.67997125809 -0.000 0.143 0.000 C -1.33887502024 -0.00450793845 4.73956848945 0.000 0.015 0.000 C 0.02462671625 -0.00591801736 4.46614405978 0.000 -0.051 0.000 C 0.43187566201 -0.00376957955 3.13352499014 -0.000 -0.083 -0.000 C -2.63984642995 0.00218980399 1.17162612704 0.000 0.057 0.000 N -1.98513620489 0.00132140951 0.00153900685 0.000 0.031 0.000 C -2.63911589169 0.00167522827 -1.17277445342 -0.000 -0.241 0.000 C -4.02452897564 0.00329996303 -1.20791476641 0.000 0.439 -0.000 C -4.73391255267 0.00451580118 -0.00020876193 -0.000 -0.108 0.000 C -4.02924140493 0.00399189729 1.20660077672 -0.000 -0.129 -0.000 Co 0.00000000000 0.00000000000 0.00000000000 -0.000 -0.001 -0.000 N -0.43839318333 -0.00054206762 -2.12229806799 -0.000 -0.061 -0.000 C -1.76408906064 -0.00030645034 -2.37697009192 0.000 0.182 -0.000 C -2.24773885821 -0.00257631963 -3.67934971086 0.000 -0.148 0.000 C -1.33713102227 -0.00526459193 -4.73855802198 -0.000 -0.004 0.000 C 0.02654101484 -0.00591797621 -4.46472703619 -0.000 0.019 0.000 C 0.43371721952 -0.00363389350 -3.13225443930 0.000 0.080 -0.000 S -6.53329279136 0.00637481657 -0.11611178087 0.000 0.007 0.000 N 2.00981687167 0.00259443239 -0.00000686048 0.000 0.000 0.007 C 2.67119656792 1.17263645248 0.00045766926 -0.000 0.001 0.014 C 4.06129317470 1.20536051565 0.00241240325 -0.000 -0.000 -0.030 C 4.76783866331 0.00148799420 0.00346798881 0.000 0.000 -0.023 C 4.05723810074 -1.20352939940 0.00211502115 0.000 0.000 0.095 C 2.67108506586 -1.17139122066 0.00026591651 0.000 0.001 -0.054 C 1.82209539371 2.39842937406 -0.00175320633 0.001 0.000 -0.018 C 2.33938959521 3.68993217240 -0.00584554905 0.000 -0.001 0.027 C 1.45736908622 4.77231118002 -0.00917967851 -0.000 0.000 0.001 C 0.08658913130 4.53522926787 -0.00833235387 -0.000 0.001 -0.010 C -0.35359617412 3.21325694137 -0.00400174376 -0.000 -0.000 -0.015 N 0.49290585413 2.18198449515 -0.00068475564 0.000 -0.001 0.009 S 6.56718562933 -0.11349126889 0.00673479967 0.000 -0.000 0.001 C 1.82142022278 -2.39594383179 -0.00206827421 -0.001 0.000 0.042 C 2.33969079820 -3.68709653410 -0.00625612120 -0.000 -0.001 -0.039 C 1.45789786198 -4.76953179608 -0.00945089783 0.000 0.000 -0.001 C 0.08684213972 -4.53272927032 -0.00840538011 0.000 0.001 0.008 C -0.35393854068 -3.21111942258 -0.00398541364 -0.000 -0.000 0.020 N 0.49225266031 -2.17934076887 -0.00084210065 -0.000 -0.001 -0.016 H 1.83694111827 5.77332096953 -0.01265611066 0.000 -0.000 -0.010 H -0.61802819388 5.33967450634 -0.01131742088 -0.000 0.000 0.026 H 3.39175422949 3.87200638269 -0.00704552340 0.000 -0.000 -0.036 H -1.39787683933 2.98334799634 -0.00369736757 0.000 -0.000 0.022 H 1.83794742242 -5.77033326187 -0.01295832570 -0.000 -0.000 0.016 H -0.61749414542 -5.33746053721 -0.01121572048 0.000 0.000 -0.027 H -1.39833026435 -2.98175334118 -0.00345676225 -0.000 -0.000 -0.026 H 3.39230213722 -3.86796714602 -0.00754158092 -0.000 -0.000 0.043 H 4.58301895157 2.13678100538 0.00314824260 -0.000 0.000 0.051 H 4.58784714512 -2.12983634010 0.00211631073 0.000 0.000 -0.135 H -1.68997263563 -0.00719388386 -5.74925805817 0.000 0.067 -0.000 H 0.75224758084 -0.00860493512 -5.25016290812 -0.000 -0.086 0.000 H -3.29620044300 -0.00255800648 -3.88456579214 0.000 0.155 -0.000 H 1.47161249279 -0.00457826661 -2.87685200854 -0.000 -0.093 0.000 H -1.69176120521 -0.00597000955 5.75026973076 -0.000 -0.063 -0.000 H 0.75025791005 -0.00892914887 5.25161119224 0.000 0.129 0.000 H 1.46975366817 -0.00523069331 2.87805400798 0.000 0.122 0.000 H -3.29750276746 -0.00099200484 3.88584245085 -0.000 -0.200 -0.000 H -4.55513299541 0.00377930937 -2.13473279421 -0.001 -0.630 0.000 H -4.55107479454 0.00501307822 2.13844314827 0.000 0.221 -0.000 H -6.83436893102 0.00806057203 1.19721860356 -0.000 0.026 -0.000 H 6.86748209639 1.20005966818 0.00372860376 -0.002 0.000 0.006 61 Mode 88: freq=1040.50 N -0.44003451495 -0.00038510790 2.12369783068 0.000 -0.008 -0.002 C -1.76594470239 0.00039861437 2.37754210613 -0.001 0.013 0.000 C -2.24923313135 -0.00145267054 3.67997125809 -0.002 -0.033 0.001 C -1.33887502024 -0.00450793845 4.73956848945 -0.000 -0.006 -0.000 C 0.02462671625 -0.00591801736 4.46614405978 0.002 0.014 0.001 C 0.43187566201 -0.00376957955 3.13352499014 0.001 0.021 0.001 C -2.63984642995 0.00218980399 1.17162612704 0.000 -0.006 -0.000 N -1.98513620489 0.00132140951 0.00153900685 -0.000 0.002 0.000 C -2.63911589169 0.00167522827 -1.17277445342 -0.000 -0.005 -0.000 C -4.02452897564 0.00329996303 -1.20791476641 0.001 0.017 0.000 C -4.73391255267 0.00451580118 -0.00020876193 0.000 -0.004 0.001 C -4.02924140493 0.00399189729 1.20660077672 -0.001 -0.006 -0.000 Co 0.00000000000 0.00000000000 0.00000000000 -0.000 0.000 0.000 N -0.43839318333 -0.00054206762 -2.12229806799 -0.000 0.002 -0.002 C -1.76408906064 -0.00030645034 -2.37697009192 0.001 -0.002 0.000 C -2.24773885821 -0.00257631963 -3.67934971086 0.002 0.013 0.001 C -1.33713102227 -0.00526459193 -4.73855802198 0.000 0.003 -0.000 C 0.02654101484 -0.00591797621 -4.46472703619 -0.002 -0.006 0.001 C 0.43371721952 -0.00363389350 -3.13225443930 -0.001 -0.009 0.001 S -6.53329279136 0.00637481657 -0.11611178087 -0.000 0.000 -0.000 N 2.00981687167 0.00259443239 -0.00000686048 0.000 0.000 0.028 C 2.67119656792 1.17263645248 0.00045766926 0.000 -0.000 -0.049 C 4.06129317470 1.20536051565 0.00241240325 -0.000 -0.000 -0.042 C 4.76783866331 0.00148799420 0.00346798881 -0.000 0.000 -0.006 C 4.05723810074 -1.20352939940 0.00211502115 -0.000 0.000 0.059 C 2.67108506586 -1.17139122066 0.00026591651 0.000 0.000 -0.063 C 1.82209539371 2.39842937406 -0.00175320633 -0.000 0.000 0.126 C 2.33938959521 3.68993217240 -0.00584554905 -0.000 -0.001 -0.332 C 1.45736908622 4.77231118002 -0.00917967851 0.000 -0.000 -0.063 C 0.08658913130 4.53522926787 -0.00833235387 -0.000 0.000 0.147 C -0.35359617412 3.21325694137 -0.00400174376 -0.000 0.001 0.211 N 0.49290585413 2.18198449515 -0.00068475564 0.000 -0.000 -0.067 S 6.56718562933 -0.11349126889 0.00673479967 0.000 -0.000 -0.002 C 1.82142022278 -2.39594383179 -0.00206827421 -0.000 -0.000 0.091 C 2.33969079820 -3.68709653410 -0.00625612120 -0.000 0.001 -0.192 C 1.45789786198 -4.76953179608 -0.00945089783 0.000 0.000 -0.035 C 0.08684213972 -4.53272927032 -0.00840538011 0.000 -0.000 0.078 C -0.35393854068 -3.21111942258 -0.00398541364 -0.000 -0.000 0.121 N 0.49225266031 -2.17934076887 -0.00084210065 0.000 -0.000 -0.043 H 1.83694111827 5.77332096953 -0.01265611066 0.000 0.001 0.176 H -0.61802819388 5.33967450634 -0.01131742088 0.000 -0.001 -0.336 H 3.39175422949 3.87200638269 -0.00704552340 0.000 0.002 0.521 H -1.39787683933 2.98334799634 -0.00369736757 0.000 -0.001 -0.335 H 1.83794742242 -5.77033326187 -0.01295832570 0.000 -0.000 0.103 H -0.61749414542 -5.33746053721 -0.01121572048 0.000 0.001 -0.184 H -1.39833026435 -2.98175334118 -0.00345676225 0.000 0.001 -0.188 H 3.39230213722 -3.86796714602 -0.00754158092 0.000 -0.001 0.291 H 4.58301895157 2.13678100538 0.00314824260 -0.000 -0.000 0.117 H 4.58784714512 -2.12983634010 0.00211631073 0.000 0.000 -0.054 H -1.68997263563 -0.00719388386 -5.74925805817 -0.000 -0.008 0.000 H 0.75224758084 -0.00860493512 -5.25016290812 0.000 0.014 0.001 H -3.29620044300 -0.00255800648 -3.88456579214 0.001 -0.022 0.001 H 1.47161249279 -0.00457826661 -2.87685200854 -0.000 0.015 -0.001 H -1.69176120521 -0.00597000955 5.75026973076 0.000 0.018 0.000 H 0.75025791005 -0.00892914887 5.25161119224 -0.000 -0.032 0.001 H 1.46975366817 -0.00523069331 2.87805400798 0.000 -0.033 -0.001 H -3.29750276746 -0.00099200484 3.88584245085 -0.001 0.052 0.001 H -4.55513299541 0.00377930937 -2.13473279421 0.000 -0.026 -0.000 H -4.55107479454 0.00501307822 2.13844314827 -0.000 0.015 -0.000 H -6.83436893102 0.00806057203 1.19721860356 0.002 0.001 0.000 H 6.86748209639 1.20005966818 0.00372860376 -0.000 0.000 0.005 61 Mode 89: freq=1041.86 N -0.44003451495 -0.00038510790 2.12369783068 0.001 0.072 -0.000 C -1.76594470239 0.00039861437 2.37754210613 -0.000 -0.138 -0.000 C -2.24923313135 -0.00145267054 3.67997125809 -0.000 0.340 0.001 C -1.33887502024 -0.00450793845 4.73956848945 0.000 0.063 0.000 C 0.02462671625 -0.00591801736 4.46614405978 -0.000 -0.148 -0.000 C 0.43187566201 -0.00376957955 3.13352499014 -0.000 -0.212 -0.001 C -2.63984642995 0.00218980399 1.17162612704 0.000 0.063 -0.000 N -1.98513620489 0.00132140951 0.00153900685 0.000 -0.034 -0.000 C -2.63911589169 0.00167522827 -1.17277445342 0.000 0.081 -0.000 C -4.02452897564 0.00329996303 -1.20791476641 0.000 -0.104 -0.000 C -4.73391255267 0.00451580118 -0.00020876193 0.000 0.023 0.000 C -4.02924140493 0.00399189729 1.20660077672 -0.000 0.035 0.000 Co 0.00000000000 0.00000000000 0.00000000000 -0.000 -0.001 0.000 N -0.43839318333 -0.00054206762 -2.12229806799 0.000 0.040 -0.000 C -1.76408906064 -0.00030645034 -2.37697009192 -0.000 -0.091 0.000 C -2.24773885821 -0.00257631963 -3.67934971086 0.000 0.158 -0.000 C -1.33713102227 -0.00526459193 -4.73855802198 0.000 0.025 -0.000 C 0.02654101484 -0.00591797621 -4.46472703619 -0.000 -0.059 0.000 C 0.43371721952 -0.00363389350 -3.13225443930 -0.000 -0.095 0.000 S -6.53329279136 0.00637481657 -0.11611178087 -0.000 0.000 -0.000 N 2.00981687167 0.00259443239 -0.00000686048 0.000 -0.001 0.001 C 2.67119656792 1.17263645248 0.00045766926 0.000 0.000 -0.003 C 4.06129317470 1.20536051565 0.00241240325 -0.001 0.000 0.017 C 4.76783866331 0.00148799420 0.00346798881 -0.000 -0.001 0.010 C 4.05723810074 -1.20352939940 0.00211502115 0.001 0.000 -0.046 C 2.67108506586 -1.17139122066 0.00026591651 -0.001 0.000 0.006 C 1.82209539371 2.39842937406 -0.00175320633 -0.001 -0.000 -0.000 C 2.33938959521 3.68993217240 -0.00584554905 -0.002 -0.001 0.006 C 1.45736908622 4.77231118002 -0.00917967851 -0.000 0.000 0.003 C 0.08658913130 4.53522926787 -0.00833235387 0.001 -0.002 -0.003 C -0.35359617412 3.21325694137 -0.00400174376 0.001 -0.001 -0.006 N 0.49290585413 2.18198449515 -0.00068475564 0.001 0.002 0.002 S 6.56718562933 -0.11349126889 0.00673479967 -0.000 0.000 -0.001 C 1.82142022278 -2.39594383179 -0.00206827421 0.001 -0.000 0.019 C 2.33969079820 -3.68709653410 -0.00625612120 0.002 -0.001 -0.074 C 1.45789786198 -4.76953179608 -0.00945089783 0.000 0.000 -0.017 C 0.08684213972 -4.53272927032 -0.00840538011 -0.001 -0.002 0.035 C -0.35393854068 -3.21111942258 -0.00398541364 -0.001 -0.001 0.050 N 0.49225266031 -2.17934076887 -0.00084210065 -0.000 0.002 -0.014 H 1.83694111827 5.77332096953 -0.01265611066 0.000 -0.000 -0.005 H -0.61802819388 5.33967450634 -0.01131742088 -0.000 -0.001 0.007 H 3.39175422949 3.87200638269 -0.00704552340 -0.001 -0.001 -0.012 H -1.39787683933 2.98334799634 -0.00369736757 0.000 0.000 0.009 H 1.83794742242 -5.77033326187 -0.01295832570 0.000 -0.000 0.043 H -0.61749414542 -5.33746053721 -0.01121572048 0.000 -0.001 -0.078 H -1.39833026435 -2.98175334118 -0.00345676225 -0.000 0.001 -0.080 H 3.39230213722 -3.86796714602 -0.00754158092 0.001 -0.001 0.122 H 4.58301895157 2.13678100538 0.00314824260 -0.000 0.000 -0.029 H 4.58784714512 -2.12983634010 0.00211631073 0.000 0.000 0.079 H -1.68997263563 -0.00719388386 -5.74925805817 -0.000 -0.082 0.000 H 0.75224758084 -0.00860493512 -5.25016290812 0.000 0.144 -0.000 H -3.29620044300 -0.00255800648 -3.88456579214 -0.000 -0.230 0.001 H 1.47161249279 -0.00457826661 -2.87685200854 0.000 0.143 -0.000 H -1.69176120521 -0.00597000955 5.75026973076 -0.000 -0.179 -0.000 H 0.75025791005 -0.00892914887 5.25161119224 0.000 0.340 0.001 H 1.46975366817 -0.00523069331 2.87805400798 0.001 0.330 0.001 H -3.29750276746 -0.00099200484 3.88584245085 -0.001 -0.532 -0.001 H -4.55513299541 0.00377930937 -2.13473279421 0.000 0.123 -0.000 H -4.55107479454 0.00501307822 2.13844314827 -0.000 -0.113 0.000 H -6.83436893102 0.00806057203 1.19721860356 0.000 -0.007 0.000 H 6.86748209639 1.20005966818 0.00372860376 0.002 -0.000 -0.003 61 Mode 90: freq=1042.91 N -0.44003451495 -0.00038510790 2.12369783068 -0.000 -0.002 0.000 C -1.76594470239 0.00039861437 2.37754210613 -0.000 -0.002 -0.000 C -2.24923313135 -0.00145267054 3.67997125809 0.000 -0.012 -0.001 C -1.33887502024 -0.00450793845 4.73956848945 0.000 -0.005 0.000 C 0.02462671625 -0.00591801736 4.46614405978 -0.000 0.007 0.000 C 0.43187566201 -0.00376957955 3.13352499014 -0.000 0.011 -0.000 C -2.63984642995 0.00218980399 1.17162612704 0.000 0.011 0.000 N -1.98513620489 0.00132140951 0.00153900685 -0.000 -0.008 0.000 C -2.63911589169 0.00167522827 -1.17277445342 -0.000 0.006 0.000 C -4.02452897564 0.00329996303 -1.20791476641 -0.000 0.099 -0.000 C -4.73391255267 0.00451580118 -0.00020876193 -0.000 -0.019 -0.000 C -4.02924140493 0.00399189729 1.20660077672 0.000 -0.047 -0.000 Co 0.00000000000 0.00000000000 0.00000000000 -0.000 -0.001 -0.000 N -0.43839318333 -0.00054206762 -2.12229806799 0.000 0.047 0.000 C -1.76408906064 -0.00030645034 -2.37697009192 -0.000 -0.077 0.000 C -2.24773885821 -0.00257631963 -3.67934971086 -0.000 0.235 -0.001 C -1.33713102227 -0.00526459193 -4.73855802198 0.000 0.051 -0.000 C 0.02654101484 -0.00591797621 -4.46472703619 0.000 -0.108 0.000 C 0.43371721952 -0.00363389350 -3.13225443930 -0.000 -0.152 0.000 S -6.53329279136 0.00637481657 -0.11611178087 0.000 0.001 -0.000 N 2.00981687167 0.00259443239 -0.00000686048 -0.000 -0.000 0.003 C 2.67119656792 1.17263645248 0.00045766926 -0.000 0.000 0.004 C 4.06129317470 1.20536051565 0.00241240325 -0.001 0.000 -0.077 C 4.76783866331 0.00148799420 0.00346798881 0.000 -0.000 -0.037 C 4.05723810074 -1.20352939940 0.00211502115 0.001 0.000 0.180 C 2.67108506586 -1.17139122066 0.00026591651 0.000 0.000 -0.037 C 1.82209539371 2.39842937406 -0.00175320633 -0.000 -0.000 0.024 C 2.33938959521 3.68993217240 -0.00584554905 -0.001 -0.001 -0.090 C 1.45736908622 4.77231118002 -0.00917967851 -0.000 0.000 -0.022 C 0.08658913130 4.53522926787 -0.00833235387 0.001 -0.000 0.043 C -0.35359617412 3.21325694137 -0.00400174376 0.000 -0.000 0.061 N 0.49290585413 2.18198449515 -0.00068475564 0.000 0.001 -0.017 S 6.56718562933 -0.11349126889 0.00673479967 0.000 -0.000 0.002 C 1.82142022278 -2.39594383179 -0.00206827421 0.000 -0.000 -0.048 C 2.33969079820 -3.68709653410 -0.00625612120 0.001 -0.001 0.220 C 1.45789786198 -4.76953179608 -0.00945089783 -0.000 -0.000 0.055 C 0.08684213972 -4.53272927032 -0.00840538011 -0.001 -0.000 -0.111 C -0.35393854068 -3.21111942258 -0.00398541364 -0.000 0.000 -0.149 N 0.49225266031 -2.17934076887 -0.00084210065 -0.001 0.001 0.037 H 1.83694111827 5.77332096953 -0.01265611066 0.000 0.000 0.053 H -0.61802819388 5.33967450634 -0.01131742088 -0.000 -0.001 -0.096 H 3.39175422949 3.87200638269 -0.00704552340 -0.000 0.000 0.149 H -1.39787683933 2.98334799634 -0.00369736757 0.000 -0.000 -0.098 H 1.83794742242 -5.77033326187 -0.01295832570 -0.000 0.000 -0.130 H -0.61749414542 -5.33746053721 -0.01121572048 0.000 -0.001 0.240 H -1.39833026435 -2.98175334118 -0.00345676225 -0.000 -0.001 0.243 H 3.39230213722 -3.86796714602 -0.00754158092 0.000 0.001 -0.372 H 4.58301895157 2.13678100538 0.00314824260 -0.001 0.000 0.137 H 4.58784714512 -2.12983634010 0.00211631073 0.001 0.000 -0.297 H -1.68997263563 -0.00719388386 -5.74925805817 0.000 -0.133 0.000 H 0.75224758084 -0.00860493512 -5.25016290812 0.000 0.242 -0.001 H -3.29620044300 -0.00255800648 -3.88456579214 -0.000 -0.381 0.000 H 1.47161249279 -0.00457826661 -2.87685200854 0.000 0.241 -0.000 H -1.69176120521 -0.00597000955 5.75026973076 -0.000 0.010 -0.000 H 0.75025791005 -0.00892914887 5.25161119224 0.000 -0.014 -0.000 H 1.46975366817 -0.00523069331 2.87805400798 -0.000 -0.017 -0.000 H -3.29750276746 -0.00099200484 3.88584245085 0.000 0.024 -0.000 H -4.55513299541 0.00377930937 -2.13473279421 -0.000 -0.180 0.000 H -4.55107479454 0.00501307822 2.13844314827 0.000 0.074 -0.000 H -6.83436893102 0.00806057203 1.19721860356 -0.000 0.008 -0.000 H 6.86748209639 1.20005966818 0.00372860376 -0.000 0.000 0.014 61 Mode 91: freq=1044.54 N -0.44003451495 -0.00038510790 2.12369783068 -0.000 -0.022 0.000 C -1.76594470239 0.00039861437 2.37754210613 0.000 0.039 -0.000 C -2.24923313135 -0.00145267054 3.67997125809 -0.000 -0.126 0.000 C -1.33887502024 -0.00450793845 4.73956848945 -0.000 -0.027 -0.000 C 0.02462671625 -0.00591801736 4.46614405978 0.000 0.061 -0.000 C 0.43187566201 -0.00376957955 3.13352499014 0.000 0.079 0.000 C -2.63984642995 0.00218980399 1.17162612704 -0.000 0.000 -0.000 N -1.98513620489 0.00132140951 0.00153900685 0.000 0.002 -0.000 C -2.63911589169 0.00167522827 -1.17277445342 0.000 -0.026 -0.000 C -4.02452897564 0.00329996303 -1.20791476641 0.000 0.162 -0.000 C -4.73391255267 0.00451580118 -0.00020876193 -0.000 -0.030 0.000 C -4.02924140493 0.00399189729 1.20660077672 -0.000 -0.079 0.000 Co 0.00000000000 0.00000000000 0.00000000000 -0.000 -0.000 0.000 N -0.43839318333 -0.00054206762 -2.12229806799 0.000 0.039 -0.000 C -1.76408906064 -0.00030645034 -2.37697009192 -0.000 -0.058 -0.000 C -2.24773885821 -0.00257631963 -3.67934971086 0.000 0.227 -0.000 C -1.33713102227 -0.00526459193 -4.73855802198 0.000 0.052 -0.000 C 0.02654101484 -0.00591797621 -4.46472703619 -0.000 -0.113 -0.000 C 0.43371721952 -0.00363389350 -3.13225443930 -0.000 -0.146 0.001 S -6.53329279136 0.00637481657 -0.11611178087 0.000 0.001 0.000 N 2.00981687167 0.00259443239 -0.00000686048 0.000 -0.000 -0.004 C 2.67119656792 1.17263645248 0.00045766926 0.000 0.000 -0.006 C 4.06129317470 1.20536051565 0.00241240325 -0.001 -0.000 0.075 C 4.76783866331 0.00148799420 0.00346798881 -0.000 -0.000 0.030 C 4.05723810074 -1.20352939940 0.00211502115 0.001 0.000 -0.158 C 2.67108506586 -1.17139122066 0.00026591651 -0.000 0.000 0.040 C 1.82209539371 2.39842937406 -0.00175320633 0.000 -0.000 -0.027 C 2.33938959521 3.68993217240 -0.00584554905 -0.000 -0.000 0.102 C 1.45736908622 4.77231118002 -0.00917967851 -0.000 0.000 0.023 C 0.08658913130 4.53522926787 -0.00833235387 0.000 0.000 -0.051 C -0.35359617412 3.21325694137 -0.00400174376 0.000 -0.000 -0.065 N 0.49290585413 2.18198449515 -0.00068475564 0.000 0.000 0.016 S 6.56718562933 -0.11349126889 0.00673479967 -0.000 0.000 -0.001 C 1.82142022278 -2.39594383179 -0.00206827421 -0.000 0.000 0.028 C 2.33969079820 -3.68709653410 -0.00625612120 0.000 0.000 -0.162 C 1.45789786198 -4.76953179608 -0.00945089783 0.000 0.000 -0.041 C 0.08684213972 -4.53272927032 -0.00840538011 -0.000 -0.000 0.086 C -0.35393854068 -3.21111942258 -0.00398541364 -0.000 -0.001 0.108 N 0.49225266031 -2.17934076887 -0.00084210065 -0.000 0.000 -0.024 H 1.83694111827 5.77332096953 -0.01265611066 0.000 -0.000 -0.057 H -0.61802819388 5.33967450634 -0.01131742088 -0.000 0.000 0.110 H 3.39175422949 3.87200638269 -0.00704552340 -0.000 -0.001 -0.169 H -1.39787683933 2.98334799634 -0.00369736757 -0.000 0.000 0.108 H 1.83794742242 -5.77033326187 -0.01295832570 -0.000 -0.000 0.095 H -0.61749414542 -5.33746053721 -0.01121572048 -0.000 0.001 -0.182 H -1.39833026435 -2.98175334118 -0.00345676225 0.000 0.001 -0.181 H 3.39230213722 -3.86796714602 -0.00754158092 0.000 -0.001 0.279 H 4.58301895157 2.13678100538 0.00314824260 0.000 -0.000 -0.134 H 4.58784714512 -2.12983634010 0.00211631073 -0.000 -0.000 0.256 H -1.68997263563 -0.00719388386 -5.74925805817 -0.000 -0.129 0.000 H 0.75224758084 -0.00860493512 -5.25016290812 0.000 0.245 -0.001 H -3.29620044300 -0.00255800648 -3.88456579214 -0.000 -0.379 0.001 H 1.47161249279 -0.00457826661 -2.87685200854 0.000 0.238 -0.000 H -1.69176120521 -0.00597000955 5.75026973076 0.000 0.069 0.000 H 0.75025791005 -0.00892914887 5.25161119224 -0.000 -0.134 -0.000 H 1.46975366817 -0.00523069331 2.87805400798 -0.000 -0.128 -0.000 H -3.29750276746 -0.00099200484 3.88584245085 0.000 0.207 0.000 H -4.55513299541 0.00377930937 -2.13473279421 -0.000 -0.271 0.000 H -4.55107479454 0.00501307822 2.13844314827 0.000 0.142 -0.000 H -6.83436893102 0.00806057203 1.19721860356 -0.000 0.013 -0.000 H 6.86748209639 1.20005966818 0.00372860376 0.001 -0.000 -0.012 61 Mode 92: freq=1088.92 N -0.44003451495 -0.00038510790 2.12369783068 -0.114 -0.000 0.291 C -1.76594470239 0.00039861437 2.37754210613 0.107 -0.000 0.051 C -2.24923313135 -0.00145267054 3.67997125809 0.281 -0.000 -0.028 C -1.33887502024 -0.00450793845 4.73956848945 -0.004 0.000 -0.052 C 0.02462671625 -0.00591801736 4.46614405978 -0.175 0.001 -0.236 C 0.43187566201 -0.00376957955 3.13352499014 -0.053 0.000 0.018 C -2.63984642995 0.00218980399 1.17162612704 0.029 -0.000 0.044 N -1.98513620489 0.00132140951 0.00153900685 0.091 -0.000 -0.001 C -2.63911589169 0.00167522827 -1.17277445342 0.018 0.000 -0.045 C -4.02452897564 0.00329996303 -1.20791476641 -0.059 -0.000 -0.015 C -4.73391255267 0.00451580118 -0.00020876193 -0.131 0.000 -0.000 C -4.02924140493 0.00399189729 1.20660077672 -0.060 0.000 0.021 Co 0.00000000000 0.00000000000 0.00000000000 -0.024 0.000 -0.000 N -0.43839318333 -0.00054206762 -2.12229806799 -0.106 -0.000 -0.278 C -1.76408906064 -0.00030645034 -2.37697009192 0.100 -0.000 -0.049 C -2.24773885821 -0.00257631963 -3.67934971086 0.270 -0.000 0.028 C -1.33713102227 -0.00526459193 -4.73855802198 -0.004 0.000 0.049 C 0.02654101484 -0.00591797621 -4.46472703619 -0.169 0.001 0.225 C 0.43371721952 -0.00363389350 -3.13225443930 -0.048 0.000 -0.016 S -6.53329279136 0.00637481657 -0.11611178087 0.031 -0.000 -0.005 N 2.00981687167 0.00259443239 -0.00000686048 0.017 0.000 -0.000 C 2.67119656792 1.17263645248 0.00045766926 0.022 -0.024 -0.000 C 4.06129317470 1.20536051565 0.00241240325 -0.022 0.022 0.000 C 4.76783866331 0.00148799420 0.00346798881 -0.094 -0.000 -0.000 C 4.05723810074 -1.20352939940 0.00211502115 -0.021 -0.024 0.000 C 2.67108506586 -1.17139122066 0.00026591651 0.016 0.025 -0.000 C 1.82209539371 2.39842937406 -0.00175320633 0.078 -0.036 0.000 C 2.33938959521 3.68993217240 -0.00584554905 0.223 0.021 -0.000 C 1.45736908622 4.77231118002 -0.00917967851 -0.003 0.026 -0.000 C 0.08658913130 4.53522926787 -0.00833235387 -0.135 0.192 -0.001 C -0.35359617412 3.21325694137 -0.00400174376 -0.037 -0.007 0.000 N 0.49290585413 2.18198449515 -0.00068475564 -0.093 -0.235 0.001 S 6.56718562933 -0.11349126889 0.00673479967 0.023 0.002 0.000 C 1.82142022278 -2.39594383179 -0.00206827421 0.074 0.035 0.000 C 2.33969079820 -3.68709653410 -0.00625612120 0.216 -0.021 -0.000 C 1.45789786198 -4.76953179608 -0.00945089783 -0.003 -0.025 -0.000 C 0.08684213972 -4.53272927032 -0.00840538011 -0.131 -0.186 -0.000 C -0.35393854068 -3.21111942258 -0.00398541364 -0.035 0.006 0.000 N 0.49225266031 -2.17934076887 -0.00084210065 -0.089 0.227 0.000 H 1.83694111827 5.77332096953 -0.01265611066 0.009 0.008 0.000 H -0.61802819388 5.33967450634 -0.01131742088 -0.034 0.068 -0.000 H 3.39175422949 3.87200638269 -0.00704552340 0.065 0.035 -0.000 H -1.39787683933 2.98334799634 -0.00369736757 -0.014 -0.005 0.000 H 1.83794742242 -5.77033326187 -0.01295832570 0.008 -0.007 0.000 H -0.61749414542 -5.33746053721 -0.01121572048 -0.034 -0.065 -0.000 H -1.39833026435 -2.98175334118 -0.00345676225 -0.013 0.005 0.000 H 3.39230213722 -3.86796714602 -0.00754158092 0.063 -0.033 -0.000 H 4.58301895157 2.13678100538 0.00314824260 -0.001 0.002 -0.000 H 4.58784714512 -2.12983634010 0.00211631073 -0.000 -0.002 -0.000 H -1.68997263563 -0.00719388386 -5.74925805817 0.009 -0.000 0.015 H 0.75224758084 -0.00860493512 -5.25016290812 -0.048 0.000 0.076 H -3.29620044300 -0.00255800648 -3.88456579214 0.079 0.000 0.038 H 1.47161249279 -0.00457826661 -2.87685200854 -0.017 -0.000 -0.009 H -1.69176120521 -0.00597000955 5.75026973076 0.010 -0.000 -0.016 H 0.75025791005 -0.00892914887 5.25161119224 -0.049 0.001 -0.080 H 1.46975366817 -0.00523069331 2.87805400798 -0.019 -0.000 0.009 H -3.29750276746 -0.00099200484 3.88584245085 0.082 -0.000 -0.040 H -4.55513299541 0.00377930937 -2.13473279421 -0.015 0.000 -0.008 H -4.55107479454 0.00501307822 2.13844314827 -0.014 0.000 0.011 H -6.83436893102 0.00806057203 1.19721860356 0.037 -0.000 0.005 H 6.86748209639 1.20005966818 0.00372860376 0.017 -0.002 0.000 61 Mode 93: freq=1100.13 N -0.44003451495 -0.00038510790 2.12369783068 0.085 0.001 -0.216 C -1.76594470239 0.00039861437 2.37754210613 -0.069 -0.000 -0.046 C -2.24923313135 -0.00145267054 3.67997125809 -0.212 0.000 0.013 C -1.33887502024 -0.00450793845 4.73956848945 -0.006 -0.000 0.058 C 0.02462671625 -0.00591801736 4.46614405978 0.138 -0.000 0.174 C 0.43187566201 -0.00376957955 3.13352499014 0.044 -0.000 -0.027 C -2.63984642995 0.00218980399 1.17162612704 -0.022 0.000 -0.036 N -1.98513620489 0.00132140951 0.00153900685 -0.112 0.000 0.002 C -2.63911589169 0.00167522827 -1.17277445342 -0.014 0.000 0.040 C -4.02452897564 0.00329996303 -1.20791476641 0.056 -0.000 0.044 C -4.73391255267 0.00451580118 -0.00020876193 0.101 -0.000 0.000 C -4.02924140493 0.00399189729 1.20660077672 0.060 -0.000 -0.050 Co 0.00000000000 0.00000000000 0.00000000000 -0.002 0.001 0.000 N -0.43839318333 -0.00054206762 -2.12229806799 0.074 0.001 0.190 C -1.76408906064 -0.00030645034 -2.37697009192 -0.060 -0.000 0.043 C -2.24773885821 -0.00257631963 -3.67934971086 -0.190 0.000 -0.013 C -1.33713102227 -0.00526459193 -4.73855802198 -0.006 -0.000 -0.055 C 0.02654101484 -0.00591797621 -4.46472703619 0.124 -0.000 -0.153 C 0.43371721952 -0.00363389350 -3.13225443930 0.040 -0.000 0.024 S -6.53329279136 0.00637481657 -0.11611178087 -0.023 0.000 0.004 N 2.00981687167 0.00259443239 -0.00000686048 0.211 0.003 0.000 C 2.67119656792 1.17263645248 0.00045766926 0.030 -0.053 0.000 C 4.06129317470 1.20536051565 0.00241240325 -0.106 -0.107 -0.000 C 4.76783866331 0.00148799420 0.00346798881 -0.136 0.001 -0.000 C 4.05723810074 -1.20352939940 0.00211502115 -0.096 0.098 -0.000 C 2.67108506586 -1.17139122066 0.00026591651 0.016 0.061 0.000 C 1.82209539371 2.39842937406 -0.00175320633 0.083 -0.067 0.000 C 2.33938959521 3.68993217240 -0.00584554905 0.290 0.017 -0.000 C 1.45736908622 4.77231118002 -0.00917967851 0.019 0.079 -0.000 C 0.08658913130 4.53522926787 -0.00833235387 -0.187 0.241 -0.001 C -0.35359617412 3.21325694137 -0.00400174376 -0.070 -0.030 -0.000 N 0.49290585413 2.18198449515 -0.00068475564 -0.115 -0.295 0.001 S 6.56718562933 -0.11349126889 0.00673479967 0.031 0.007 0.000 C 1.82142022278 -2.39594383179 -0.00206827421 0.067 0.063 0.000 C 2.33969079820 -3.68709653410 -0.00625612120 0.238 -0.015 -0.000 C 1.45789786198 -4.76953179608 -0.00945089783 0.019 -0.075 -0.000 C 0.08684213972 -4.53272927032 -0.00840538011 -0.155 -0.193 -0.000 C -0.35393854068 -3.21111942258 -0.00398541364 -0.061 0.027 -0.000 N 0.49225266031 -2.17934076887 -0.00084210065 -0.091 0.235 0.001 H 1.83694111827 5.77332096953 -0.01265611066 0.019 0.024 0.000 H -0.61802819388 5.33967450634 -0.01131742088 -0.058 0.077 -0.001 H 3.39175422949 3.87200638269 -0.00704552340 0.089 0.018 0.000 H -1.39787683933 2.98334799634 -0.00369736757 -0.022 -0.023 0.000 H 1.83794742242 -5.77033326187 -0.01295832570 0.015 -0.023 0.000 H -0.61749414542 -5.33746053721 -0.01121572048 -0.051 -0.060 -0.000 H -1.39833026435 -2.98175334118 -0.00345676225 -0.019 0.021 0.000 H 3.39230213722 -3.86796714602 -0.00754158092 0.074 -0.013 -0.000 H 4.58301895157 2.13678100538 0.00314824260 -0.029 -0.038 -0.000 H 4.58784714512 -2.12983634010 0.00211631073 -0.029 0.033 -0.000 H -1.68997263563 -0.00719388386 -5.74925805817 -0.010 0.000 -0.017 H 0.75224758084 -0.00860493512 -5.25016290812 0.041 -0.000 -0.047 H -3.29620044300 -0.00255800648 -3.88456579214 -0.058 -0.000 -0.013 H 1.47161249279 -0.00457826661 -2.87685200854 0.013 0.000 0.014 H -1.69176120521 -0.00597000955 5.75026973076 -0.012 0.000 0.018 H 0.75025791005 -0.00892914887 5.25161119224 0.044 -0.000 0.054 H 1.46975366817 -0.00523069331 2.87805400798 0.015 0.000 -0.015 H -3.29750276746 -0.00099200484 3.88584245085 -0.065 -0.000 0.015 H -4.55513299541 0.00377930937 -2.13473279421 0.014 0.000 0.017 H -4.55107479454 0.00501307822 2.13844314827 0.014 0.000 -0.020 H -6.83436893102 0.00806057203 1.19721860356 -0.030 0.000 -0.005 H 6.86748209639 1.20005966818 0.00372860376 0.049 -0.008 0.000 61 Mode 94: freq=1106.09 N -0.44003451495 -0.00038510790 2.12369783068 -0.006 0.008 0.017 C -1.76594470239 0.00039861437 2.37754210613 0.005 -0.004 0.004 C -2.24923313135 -0.00145267054 3.67997125809 0.016 0.003 -0.001 C -1.33887502024 -0.00450793845 4.73956848945 0.001 -0.002 -0.005 C 0.02462671625 -0.00591801736 4.46614405978 -0.011 -0.003 -0.014 C 0.43187566201 -0.00376957955 3.13352499014 -0.004 0.002 0.003 C -2.63984642995 0.00218980399 1.17162612704 0.002 0.002 0.003 N -1.98513620489 0.00132140951 0.00153900685 0.009 0.000 -0.000 C -2.63911589169 0.00167522827 -1.17277445342 0.001 0.002 -0.003 C -4.02452897564 0.00329996303 -1.20791476641 -0.004 -0.002 -0.004 C -4.73391255267 0.00451580118 -0.00020876193 -0.008 0.001 -0.000 C -4.02924140493 0.00399189729 1.20660077672 -0.005 -0.001 0.004 Co 0.00000000000 0.00000000000 0.00000000000 -0.001 0.015 -0.000 N -0.43839318333 -0.00054206762 -2.12229806799 -0.004 0.008 -0.011 C -1.76408906064 -0.00030645034 -2.37697009192 0.004 -0.004 -0.003 C -2.24773885821 -0.00257631963 -3.67934971086 0.012 0.003 0.000 C -1.33713102227 -0.00526459193 -4.73855802198 0.001 -0.002 0.005 C 0.02654101484 -0.00591797621 -4.46472703619 -0.008 -0.003 0.009 C 0.43371721952 -0.00363389350 -3.13225443930 -0.003 0.002 -0.002 S -6.53329279136 0.00637481657 -0.11611178087 0.002 -0.000 -0.000 N 2.00981687167 0.00259443239 -0.00000686048 0.005 0.054 0.000 C 2.67119656792 1.17263645248 0.00045766926 -0.006 0.053 -0.000 C 4.06129317470 1.20536051565 0.00241240325 -0.068 -0.014 -0.000 C 4.76783866331 0.00148799420 0.00346798881 0.008 0.013 -0.000 C 4.05723810074 -1.20352939940 0.00211502115 0.069 0.002 0.000 C 2.67108506586 -1.17139122066 0.00026591651 0.007 0.048 0.000 C 1.82209539371 2.39842937406 -0.00175320633 0.066 -0.007 0.000 C 2.33938959521 3.68993217240 -0.00584554905 0.325 0.013 -0.000 C 1.45736908622 4.77231118002 -0.00917967851 -0.007 0.001 0.000 C 0.08658913130 4.53522926787 -0.00833235387 -0.215 0.296 -0.000 C -0.35359617412 3.21325694137 -0.00400174376 -0.000 -0.021 -0.000 N 0.49290585413 2.18198449515 -0.00068475564 -0.133 -0.369 0.001 S 6.56718562933 -0.11349126889 0.00673479967 0.004 -0.015 0.000 C 1.82142022278 -2.39594383179 -0.00206827421 -0.078 -0.015 -0.000 C 2.33969079820 -3.68709653410 -0.00625612120 -0.374 0.015 0.000 C 1.45789786198 -4.76953179608 -0.00945089783 0.005 0.010 0.000 C 0.08684213972 -4.53272927032 -0.00840538011 0.248 0.338 0.001 C -0.35393854068 -3.21111942258 -0.00398541364 0.006 -0.026 0.000 N 0.49225266031 -2.17934076887 -0.00084210065 0.151 -0.420 -0.001 H 1.83694111827 5.77332096953 -0.01265611066 0.026 -0.006 0.000 H -0.61802819388 5.33967450634 -0.01131742088 -0.062 0.097 -0.001 H 3.39175422949 3.87200638269 -0.00704552340 0.097 0.026 0.000 H -1.39787683933 2.98334799634 -0.00369736757 -0.002 -0.015 0.001 H 1.83794742242 -5.77033326187 -0.01295832570 -0.031 -0.003 -0.000 H -0.61749414542 -5.33746053721 -0.01121572048 0.073 0.110 0.001 H -1.39833026435 -2.98175334118 -0.00345676225 0.004 -0.019 -0.001 H 3.39230213722 -3.86796714602 -0.00754158092 -0.112 0.030 -0.000 H 4.58301895157 2.13678100538 0.00314824260 -0.021 -0.005 -0.000 H 4.58784714512 -2.12983634010 0.00211631073 0.021 -0.000 0.000 H -1.68997263563 -0.00719388386 -5.74925805817 0.001 0.003 0.001 H 0.75224758084 -0.00860493512 -5.25016290812 -0.003 0.005 0.003 H -3.29620044300 -0.00255800648 -3.88456579214 0.004 -0.004 0.000 H 1.47161249279 -0.00457826661 -2.87685200854 -0.001 -0.005 -0.002 H -1.69176120521 -0.00597000955 5.75026973076 0.001 0.003 -0.002 H 0.75025791005 -0.00892914887 5.25161119224 -0.004 0.005 -0.004 H 1.46975366817 -0.00523069331 2.87805400798 -0.001 -0.006 0.002 H -3.29750276746 -0.00099200484 3.88584245085 0.005 -0.003 -0.000 H -4.55513299541 0.00377930937 -2.13473279421 -0.001 0.002 -0.002 H -4.55107479454 0.00501307822 2.13844314827 -0.001 0.002 0.002 H -6.83436893102 0.00806057203 1.19721860356 0.002 0.000 0.000 H 6.86748209639 1.20005966818 0.00372860376 -0.047 0.008 -0.000 61 Mode 95: freq=1108.94 N -0.44003451495 -0.00038510790 2.12369783068 -0.132 -0.001 0.377 C -1.76594470239 0.00039861437 2.37754210613 0.075 -0.000 0.010 C -2.24923313135 -0.00145267054 3.67997125809 0.336 -0.000 -0.007 C -1.33887502024 -0.00450793845 4.73956848945 -0.005 0.000 -0.023 C 0.02462671625 -0.00591801736 4.46614405978 -0.232 0.000 -0.304 C 0.43187566201 -0.00376957955 3.13352499014 -0.004 0.000 0.039 C -2.63984642995 0.00218980399 1.17162612704 -0.006 0.000 -0.054 N -1.98513620489 0.00132140951 0.00153900685 0.014 -0.000 -0.059 C -2.63911589169 0.00167522827 -1.17277445342 0.010 -0.000 -0.052 C -4.02452897564 0.00329996303 -1.20791476641 0.068 0.000 -0.005 C -4.73391255267 0.00451580118 -0.00020876193 0.001 -0.000 -0.013 C -4.02924140493 0.00399189729 1.20660077672 -0.075 0.000 0.020 Co 0.00000000000 0.00000000000 0.00000000000 -0.001 -0.000 -0.021 N -0.43839318333 -0.00054206762 -2.12229806799 0.140 0.001 0.404 C -1.76408906064 -0.00030645034 -2.37697009192 -0.080 0.000 0.013 C -2.24773885821 -0.00257631963 -3.67934971086 -0.362 0.000 -0.009 C -1.33713102227 -0.00526459193 -4.73855802198 0.004 -0.000 -0.025 C 0.02654101484 -0.00591797621 -4.46472703619 0.250 -0.000 -0.325 C 0.43371721952 -0.00363389350 -3.13225443930 0.004 -0.000 0.041 S -6.53329279136 0.00637481657 -0.11611178087 0.006 0.000 0.015 N 2.00981687167 0.00259443239 -0.00000686048 0.010 -0.000 0.001 C 2.67119656792 1.17263645248 0.00045766926 0.001 -0.002 -0.003 C 4.06129317470 1.20536051565 0.00241240325 -0.004 -0.006 0.002 C 4.76783866331 0.00148799420 0.00346798881 -0.004 -0.000 -0.001 C 4.05723810074 -1.20352939940 0.00211502115 -0.004 0.005 0.002 C 2.67108506586 -1.17139122066 0.00026591651 0.000 0.002 -0.003 C 1.82209539371 2.39842937406 -0.00175320633 0.001 -0.002 0.004 C 2.33938959521 3.68993217240 -0.00584554905 0.003 -0.000 -0.003 C 1.45736908622 4.77231118002 -0.00917967851 0.001 0.003 0.003 C 0.08658913130 4.53522926787 -0.00833235387 -0.003 0.003 0.003 C -0.35359617412 3.21325694137 -0.00400174376 -0.002 -0.001 -0.002 N 0.49290585413 2.18198449515 -0.00068475564 -0.001 -0.003 -0.007 S 6.56718562933 -0.11349126889 0.00673479967 0.001 0.000 0.000 C 1.82142022278 -2.39594383179 -0.00206827421 0.001 0.002 0.004 C 2.33969079820 -3.68709653410 -0.00625612120 0.007 -0.000 -0.003 C 1.45789786198 -4.76953179608 -0.00945089783 0.001 -0.003 0.002 C 0.08684213972 -4.53272927032 -0.00840538011 -0.005 -0.006 0.003 C -0.35393854068 -3.21111942258 -0.00398541364 -0.002 0.001 -0.002 N 0.49225266031 -2.17934076887 -0.00084210065 -0.002 0.007 -0.007 H 1.83694111827 5.77332096953 -0.01265611066 0.001 0.001 -0.003 H -0.61802819388 5.33967450634 -0.01131742088 -0.001 0.001 -0.005 H 3.39175422949 3.87200638269 -0.00704552340 0.001 -0.001 0.004 H -1.39787683933 2.98334799634 -0.00369736757 -0.001 -0.001 0.006 H 1.83794742242 -5.77033326187 -0.01295832570 0.001 -0.001 -0.003 H -0.61749414542 -5.33746053721 -0.01121572048 -0.002 -0.002 -0.005 H -1.39833026435 -2.98175334118 -0.00345676225 -0.001 0.001 0.006 H 3.39230213722 -3.86796714602 -0.00754158092 0.002 0.000 0.004 H 4.58301895157 2.13678100538 0.00314824260 -0.001 -0.002 -0.002 H 4.58784714512 -2.12983634010 0.00211631073 -0.001 0.002 -0.002 H -1.68997263563 -0.00719388386 -5.74925805817 -0.034 0.000 -0.001 H 0.75224758084 -0.00860493512 -5.25016290812 0.080 -0.001 -0.101 H -3.29620044300 -0.00255800648 -3.88456579214 -0.109 0.000 -0.018 H 1.47161249279 -0.00457826661 -2.87685200854 0.003 0.001 0.026 H -1.69176120521 -0.00597000955 5.75026973076 0.032 -0.000 -0.001 H 0.75025791005 -0.00892914887 5.25161119224 -0.074 0.001 -0.095 H 1.46975366817 -0.00523069331 2.87805400798 -0.003 -0.001 0.024 H -3.29750276746 -0.00099200484 3.88584245085 0.102 -0.000 -0.016 H -4.55513299541 0.00377930937 -2.13473279421 0.022 -0.000 -0.001 H -4.55107479454 0.00501307822 2.13844314827 -0.023 0.000 0.007 H -6.83436893102 0.00806057203 1.19721860356 -0.046 0.000 -0.008 H 6.86748209639 1.20005966818 0.00372860376 0.002 -0.000 -0.000 61 Mode 96: freq=1125.58 N -0.44003451495 -0.00038510790 2.12369783068 0.005 -0.001 -0.037 C -1.76594470239 0.00039861437 2.37754210613 -0.015 -0.001 -0.031 C -2.24923313135 -0.00145267054 3.67997125809 -0.050 0.003 -0.014 C -1.33887502024 -0.00450793845 4.73956848945 -0.029 -0.002 0.060 C 0.02462671625 -0.00591801736 4.46614405978 0.050 -0.004 0.047 C 0.43187566201 -0.00376957955 3.13352499014 0.044 0.006 -0.033 C -2.63984642995 0.00218980399 1.17162612704 -0.014 0.000 -0.021 N -1.98513620489 0.00132140951 0.00153900685 -0.087 -0.000 -0.001 C -2.63911589169 0.00167522827 -1.17277445342 -0.009 0.000 0.021 C -4.02452897564 0.00329996303 -1.20791476641 0.034 -0.000 0.046 C -4.73391255267 0.00451580118 -0.00020876193 0.056 -0.000 -0.001 C -4.02924140493 0.00399189729 1.20660077672 0.034 -0.000 -0.047 Co 0.00000000000 0.00000000000 0.00000000000 0.044 0.001 -0.000 N -0.43839318333 -0.00054206762 -2.12229806799 0.007 -0.001 0.042 C -1.76408906064 -0.00030645034 -2.37697009192 -0.014 -0.001 0.030 C -2.24773885821 -0.00257631963 -3.67934971086 -0.056 0.003 0.014 C -1.33713102227 -0.00526459193 -4.73855802198 -0.028 -0.002 -0.060 C 0.02654101484 -0.00591797621 -4.46472703619 0.054 -0.004 -0.051 C 0.43371721952 -0.00363389350 -3.13225443930 0.041 0.006 0.034 S -6.53329279136 0.00637481657 -0.11611178087 -0.011 0.000 0.002 N 2.00981687167 0.00259443239 -0.00000686048 -0.597 0.004 -0.000 C 2.67119656792 1.17263645248 0.00045766926 -0.030 0.027 -0.001 C 4.06129317470 1.20536051565 0.00241240325 0.228 0.398 0.000 C 4.76783866331 0.00148799420 0.00346798881 0.103 0.000 0.000 C 4.05723810074 -1.20352939940 0.00211502115 0.228 -0.384 0.000 C 2.67108506586 -1.17139122066 0.00026591651 -0.003 -0.027 -0.000 C 1.82209539371 2.39842937406 -0.00175320633 0.019 0.028 0.001 C 2.33938959521 3.68993217240 -0.00584554905 0.106 0.017 -0.002 C 1.45736908622 4.77231118002 -0.00917967851 -0.041 -0.066 0.002 C 0.08658913130 4.53522926787 -0.00833235387 -0.042 0.092 0.003 C -0.35359617412 3.21325694137 -0.00400174376 0.063 0.009 -0.005 N 0.49290585413 2.18198449515 -0.00068475564 -0.073 -0.140 0.001 S 6.56718562933 -0.11349126889 0.00673479967 -0.023 -0.015 0.000 C 1.82142022278 -2.39594383179 -0.00206827421 0.023 -0.022 0.001 C 2.33969079820 -3.68709653410 -0.00625612120 0.081 -0.015 -0.002 C 1.45789786198 -4.76953179608 -0.00945089783 -0.035 0.057 0.002 C 0.08684213972 -4.53272927032 -0.00840538011 -0.028 -0.074 0.003 C -0.35393854068 -3.21111942258 -0.00398541364 0.047 -0.007 -0.005 N 0.49225266031 -2.17934076887 -0.00084210065 -0.064 0.115 0.001 H 1.83694111827 5.77332096953 -0.01265611066 -0.011 -0.020 -0.003 H -0.61802819388 5.33967450634 -0.01131742088 -0.005 0.034 -0.005 H 3.39175422949 3.87200638269 -0.00704552340 0.023 0.054 0.003 H -1.39787683933 2.98334799634 -0.00369736757 0.013 0.025 0.008 H 1.83794742242 -5.77033326187 -0.01295832570 -0.010 0.018 -0.003 H -0.61749414542 -5.33746053721 -0.01121572048 0.001 -0.031 -0.004 H -1.39833026435 -2.98175334118 -0.00345676225 0.009 -0.023 0.007 H 3.39230213722 -3.86796714602 -0.00754158092 0.017 -0.048 0.003 H 4.58301895157 2.13678100538 0.00314824260 0.063 0.129 0.000 H 4.58784714512 -2.12983634010 0.00211631073 0.075 -0.118 0.000 H -1.68997263563 -0.00719388386 -5.74925805817 -0.022 0.004 -0.015 H 0.75224758084 -0.00860493512 -5.25016290812 0.025 0.005 -0.010 H -3.29620044300 -0.00255800648 -3.88456579214 -0.022 -0.004 0.026 H 1.47161249279 -0.00457826661 -2.87685200854 0.007 -0.010 0.035 H -1.69176120521 -0.00597000955 5.75026973076 -0.022 0.004 0.015 H 0.75025791005 -0.00892914887 5.25161119224 0.023 0.005 0.009 H 1.46975366817 -0.00523069331 2.87805400798 0.008 -0.009 -0.035 H -3.29750276746 -0.00099200484 3.88584245085 -0.020 -0.004 -0.026 H -4.55513299541 0.00377930937 -2.13473279421 0.005 -0.000 0.018 H -4.55107479454 0.00501307822 2.13844314827 0.004 -0.000 -0.019 H -6.83436893102 0.00806057203 1.19721860356 -0.016 0.000 -0.003 H 6.86748209639 1.20005966818 0.00372860376 -0.086 0.015 -0.000 61 Mode 97: freq=1126.61 N -0.44003451495 -0.00038510790 2.12369783068 -0.000 -0.001 -0.000 C -1.76594470239 0.00039861437 2.37754210613 0.000 0.000 -0.000 C -2.24923313135 -0.00145267054 3.67997125809 -0.000 -0.000 -0.000 C -1.33887502024 -0.00450793845 4.73956848945 -0.000 0.002 0.000 C 0.02462671625 -0.00591801736 4.46614405978 0.000 -0.001 0.000 C 0.43187566201 -0.00376957955 3.13352499014 0.000 -0.001 -0.000 C -2.63984642995 0.00218980399 1.17162612704 -0.000 -0.003 0.000 N -1.98513620489 0.00132140951 0.00153900685 -0.000 0.000 -0.000 C -2.63911589169 0.00167522827 -1.17277445342 0.000 0.003 0.000 C -4.02452897564 0.00329996303 -1.20791476641 -0.000 -0.003 0.000 C -4.73391255267 0.00451580118 -0.00020876193 0.000 0.000 -0.000 C -4.02924140493 0.00399189729 1.20660077672 0.000 0.003 -0.000 Co 0.00000000000 0.00000000000 0.00000000000 -0.000 0.000 -0.000 N -0.43839318333 -0.00054206762 -2.12229806799 0.000 0.000 -0.000 C -1.76408906064 -0.00030645034 -2.37697009192 -0.000 -0.000 -0.000 C -2.24773885821 -0.00257631963 -3.67934971086 0.000 0.001 -0.000 C -1.33713102227 -0.00526459193 -4.73855802198 0.000 -0.002 0.000 C 0.02654101484 -0.00591797621 -4.46472703619 -0.000 0.000 0.000 C 0.43371721952 -0.00363389350 -3.13225443930 -0.000 0.001 -0.000 S -6.53329279136 0.00637481657 -0.11611178087 0.000 0.000 0.000 N 2.00981687167 0.00259443239 -0.00000686048 0.001 0.000 0.001 C 2.67119656792 1.17263645248 0.00045766926 0.000 0.000 0.020 C 4.06129317470 1.20536051565 0.00241240325 -0.000 -0.000 0.002 C 4.76783866331 0.00148799420 0.00346798881 -0.000 -0.000 0.000 C 4.05723810074 -1.20352939940 0.00211502115 -0.000 0.000 -0.002 C 2.67108506586 -1.17139122066 0.00026591651 0.000 0.000 -0.024 C 1.82209539371 2.39842937406 -0.00175320633 0.000 -0.000 -0.055 C 2.33938959521 3.68993217240 -0.00584554905 0.000 0.000 0.125 C 1.45736908622 4.77231118002 -0.00917967851 0.000 0.000 -0.106 C 0.08658913130 4.53522926787 -0.00833235387 -0.001 0.000 -0.163 C -0.35359617412 3.21325694137 -0.00400174376 -0.000 0.001 0.270 N 0.49290585413 2.18198449515 -0.00068475564 0.000 -0.001 -0.032 S 6.56718562933 -0.11349126889 0.00673479967 0.000 0.000 0.000 C 1.82142022278 -2.39594383179 -0.00206827421 -0.000 -0.000 0.065 C 2.33969079820 -3.68709653410 -0.00625612120 -0.001 0.000 -0.149 C 1.45789786198 -4.76953179608 -0.00945089783 -0.000 0.000 0.121 C 0.08684213972 -4.53272927032 -0.00840538011 0.001 0.000 0.197 C -0.35393854068 -3.21111942258 -0.00398541364 0.000 0.001 -0.321 N 0.49225266031 -2.17934076887 -0.00084210065 -0.000 -0.001 0.038 H 1.83694111827 5.77332096953 -0.01265611066 0.001 0.001 0.181 H -0.61802819388 5.33967450634 -0.01131742088 -0.000 0.001 0.223 H 3.39175422949 3.87200638269 -0.00704552340 0.000 -0.001 -0.169 H -1.39787683933 2.98334799634 -0.00369736757 0.000 -0.002 -0.416 H 1.83794742242 -5.77033326187 -0.01295832570 -0.001 0.001 -0.208 H -0.61749414542 -5.33746053721 -0.01121572048 0.000 0.001 -0.270 H -1.39833026435 -2.98175334118 -0.00345676225 -0.000 -0.002 0.493 H 3.39230213722 -3.86796714602 -0.00754158092 -0.000 -0.001 0.204 H 4.58301895157 2.13678100538 0.00314824260 -0.000 -0.000 -0.012 H 4.58784714512 -2.12983634010 0.00211631073 -0.000 0.000 0.014 H -1.68997263563 -0.00719388386 -5.74925805817 0.000 0.003 -0.000 H 0.75224758084 -0.00860493512 -5.25016290812 -0.000 -0.001 0.000 H -3.29620044300 -0.00255800648 -3.88456579214 0.000 -0.000 -0.000 H 1.47161249279 -0.00457826661 -2.87685200854 -0.000 -0.002 -0.000 H -1.69176120521 -0.00597000955 5.75026973076 -0.000 -0.003 -0.000 H 0.75025791005 -0.00892914887 5.25161119224 0.000 0.001 0.000 H 1.46975366817 -0.00523069331 2.87805400798 0.000 0.001 -0.000 H -3.29750276746 -0.00099200484 3.88584245085 -0.000 -0.000 -0.000 H -4.55513299541 0.00377930937 -2.13473279421 -0.000 0.004 0.000 H -4.55107479454 0.00501307822 2.13844314827 0.000 -0.004 -0.000 H -6.83436893102 0.00806057203 1.19721860356 -0.000 -0.000 -0.000 H 6.86748209639 1.20005966818 0.00372860376 0.000 -0.000 -0.001 61 Mode 98: freq=1126.78 N -0.44003451495 -0.00038510790 2.12369783068 -0.001 0.000 -0.004 C -1.76594470239 0.00039861437 2.37754210613 0.001 -0.000 -0.000 C -2.24923313135 -0.00145267054 3.67997125809 -0.002 0.000 -0.001 C -1.33887502024 -0.00450793845 4.73956848945 -0.002 -0.000 0.001 C 0.02462671625 -0.00591801736 4.46614405978 0.003 0.000 0.004 C 0.43187566201 -0.00376957955 3.13352499014 0.002 0.000 -0.001 C -2.63984642995 0.00218980399 1.17162612704 -0.002 0.000 0.003 N -1.98513620489 0.00132140951 0.00153900685 -0.003 0.000 -0.001 C -2.63911589169 0.00167522827 -1.17277445342 0.002 -0.000 0.002 C -4.02452897564 0.00329996303 -1.20791476641 -0.003 0.000 0.003 C -4.73391255267 0.00451580118 -0.00020876193 -0.000 -0.000 -0.003 C -4.02924140493 0.00399189729 1.20660077672 0.005 -0.000 -0.001 Co 0.00000000000 0.00000000000 0.00000000000 -0.000 -0.000 -0.002 N -0.43839318333 -0.00054206762 -2.12229806799 -0.000 -0.000 -0.007 C -1.76408906064 -0.00030645034 -2.37697009192 0.000 0.000 -0.001 C -2.24773885821 -0.00257631963 -3.67934971086 0.005 -0.000 -0.001 C -1.33713102227 -0.00526459193 -4.73855802198 0.003 0.000 0.002 C 0.02654101484 -0.00591797621 -4.46472703619 -0.006 0.000 0.007 C 0.43371721952 -0.00363389350 -3.13225443930 -0.003 -0.000 -0.003 S -6.53329279136 0.00637481657 -0.11611178087 0.000 -0.000 0.000 N 2.00981687167 0.00259443239 -0.00000686048 0.010 -0.000 0.012 C 2.67119656792 1.17263645248 0.00045766926 0.000 -0.000 -0.027 C 4.06129317470 1.20536051565 0.00241240325 -0.004 -0.007 0.003 C 4.76783866331 0.00148799420 0.00346798881 -0.001 0.000 -0.001 C 4.05723810074 -1.20352939940 0.00211502115 -0.004 0.007 0.003 C 2.67108506586 -1.17139122066 0.00026591651 -0.000 -0.000 -0.023 C 1.82209539371 2.39842937406 -0.00175320633 -0.001 0.000 0.064 C 2.33938959521 3.68993217240 -0.00584554905 -0.002 -0.000 -0.147 C 1.45736908622 4.77231118002 -0.00917967851 -0.000 0.000 0.125 C 0.08658913130 4.53522926787 -0.00833235387 0.001 -0.001 0.193 C -0.35359617412 3.21325694137 -0.00400174376 0.000 -0.001 -0.322 N 0.49290585413 2.18198449515 -0.00068475564 0.001 0.003 0.039 S 6.56718562933 -0.11349126889 0.00673479967 0.000 0.000 -0.000 C 1.82142022278 -2.39594383179 -0.00206827421 -0.001 -0.000 0.054 C 2.33969079820 -3.68709653410 -0.00625612120 -0.002 0.000 -0.125 C 1.45789786198 -4.76953179608 -0.00945089783 -0.000 -0.000 0.102 C 0.08684213972 -4.53272927032 -0.00840538011 0.001 0.001 0.165 C -0.35393854068 -3.21111942258 -0.00398541364 0.000 0.001 -0.270 N 0.49225266031 -2.17934076887 -0.00084210065 0.001 -0.002 0.033 H 1.83694111827 5.77332096953 -0.01265611066 -0.001 -0.001 -0.215 H -0.61802819388 5.33967450634 -0.01131742088 0.000 -0.002 -0.263 H 3.39175422949 3.87200638269 -0.00704552340 -0.000 0.000 0.200 H -1.39787683933 2.98334799634 -0.00369736757 -0.000 0.002 0.495 H 1.83794742242 -5.77033326187 -0.01295832570 -0.000 0.000 -0.175 H -0.61749414542 -5.33746053721 -0.01121572048 0.000 0.001 -0.226 H -1.39833026435 -2.98175334118 -0.00345676225 -0.000 -0.002 0.415 H 3.39230213722 -3.86796714602 -0.00754158092 -0.000 -0.000 0.171 H 4.58301895157 2.13678100538 0.00314824260 -0.001 -0.002 0.010 H 4.58784714512 -2.12983634010 0.00211631073 -0.001 0.002 0.008 H -1.68997263563 -0.00719388386 -5.74925805817 0.004 -0.000 -0.000 H 0.75224758084 -0.00860493512 -5.25016290812 -0.002 -0.000 0.002 H -3.29620044300 -0.00255800648 -3.88456579214 0.002 0.000 -0.002 H 1.47161249279 -0.00457826661 -2.87685200854 -0.000 0.001 -0.004 H -1.69176120521 -0.00597000955 5.75026973076 -0.003 0.000 -0.000 H 0.75025791005 -0.00892914887 5.25161119224 0.001 -0.000 0.002 H 1.46975366817 -0.00523069331 2.87805400798 0.000 -0.000 -0.003 H -3.29750276746 -0.00099200484 3.88584245085 -0.001 0.000 -0.002 H -4.55513299541 0.00377930937 -2.13473279421 -0.001 -0.000 0.001 H -4.55107479454 0.00501307822 2.13844314827 0.001 0.000 -0.001 H -6.83436893102 0.00806057203 1.19721860356 -0.002 0.000 -0.000 H 6.86748209639 1.20005966818 0.00372860376 0.001 -0.000 0.000 61 Mode 99: freq=1128.28 N -0.44003451495 -0.00038510790 2.12369783068 -0.000 -0.039 -0.000 C -1.76594470239 0.00039861437 2.37754210613 -0.000 -0.059 -0.000 C -2.24923313135 -0.00145267054 3.67997125809 -0.000 0.137 0.000 C -1.33887502024 -0.00450793845 4.73956848945 -0.001 -0.118 0.000 C 0.02462671625 -0.00591801736 4.46614405978 0.000 -0.182 0.000 C 0.43187566201 -0.00376957955 3.13352499014 0.001 0.308 0.000 C -2.63984642995 0.00218980399 1.17162612704 -0.000 0.022 0.000 N -1.98513620489 0.00132140951 0.00153900685 -0.000 -0.000 0.000 C -2.63911589169 0.00167522827 -1.17277445342 -0.000 -0.020 0.000 C -4.02452897564 0.00329996303 -1.20791476641 -0.000 -0.002 0.000 C -4.73391255267 0.00451580118 -0.00020876193 0.000 0.000 -0.000 C -4.02924140493 0.00399189729 1.20660077672 0.000 0.002 -0.000 Co 0.00000000000 0.00000000000 0.00000000000 0.000 0.000 0.000 N -0.43839318333 -0.00054206762 -2.12229806799 0.000 0.037 -0.001 C -1.76408906064 -0.00030645034 -2.37697009192 0.000 0.056 -0.000 C -2.24773885821 -0.00257631963 -3.67934971086 0.000 -0.131 0.000 C -1.33713102227 -0.00526459193 -4.73855802198 0.001 0.108 0.000 C 0.02654101484 -0.00591797621 -4.46472703619 -0.001 0.175 0.000 C 0.43371721952 -0.00363389350 -3.13225443930 -0.001 -0.290 0.000 S -6.53329279136 0.00637481657 -0.11611178087 -0.000 0.000 -0.000 N 2.00981687167 0.00259443239 -0.00000686048 0.000 0.000 0.000 C 2.67119656792 1.17263645248 0.00045766926 -0.000 -0.000 -0.003 C 4.06129317470 1.20536051565 0.00241240325 0.000 -0.000 0.003 C 4.76783866331 0.00148799420 0.00346798881 -0.000 0.000 0.000 C 4.05723810074 -1.20352939940 0.00211502115 -0.000 0.000 -0.003 C 2.67108506586 -1.17139122066 0.00026591651 0.000 -0.000 0.003 C 1.82209539371 2.39842937406 -0.00175320633 -0.000 -0.000 0.000 C 2.33938959521 3.68993217240 -0.00584554905 -0.000 0.000 0.000 C 1.45736908622 4.77231118002 -0.00917967851 -0.000 -0.000 0.001 C 0.08658913130 4.53522926787 -0.00833235387 0.000 -0.000 -0.002 C -0.35359617412 3.21325694137 -0.00400174376 0.000 0.000 0.001 N 0.49290585413 2.18198449515 -0.00068475564 0.000 0.000 -0.001 S 6.56718562933 -0.11349126889 0.00673479967 0.000 0.000 0.000 C 1.82142022278 -2.39594383179 -0.00206827421 -0.000 0.000 -0.000 C 2.33969079820 -3.68709653410 -0.00625612120 0.000 0.000 -0.000 C 1.45789786198 -4.76953179608 -0.00945089783 0.000 -0.000 -0.001 C 0.08684213972 -4.53272927032 -0.00840538011 -0.000 -0.000 0.002 C -0.35393854068 -3.21111942258 -0.00398541364 -0.000 0.000 -0.001 N 0.49225266031 -2.17934076887 -0.00084210065 0.000 0.000 0.001 H 1.83694111827 5.77332096953 -0.01265611066 -0.000 0.000 -0.001 H -0.61802819388 5.33967450634 -0.01131742088 0.000 -0.000 0.002 H 3.39175422949 3.87200638269 -0.00704552340 -0.000 0.000 -0.001 H -1.39787683933 2.98334799634 -0.00369736757 0.000 0.000 -0.001 H 1.83794742242 -5.77033326187 -0.01295832570 0.000 -0.000 0.002 H -0.61749414542 -5.33746053721 -0.01121572048 -0.000 -0.000 -0.002 H -1.39833026435 -2.98175334118 -0.00345676225 -0.000 0.000 0.001 H 3.39230213722 -3.86796714602 -0.00754158092 0.000 0.000 0.001 H 4.58301895157 2.13678100538 0.00314824260 0.000 -0.000 -0.004 H 4.58784714512 -2.12983634010 0.00211631073 -0.000 0.000 0.004 H -1.68997263563 -0.00719388386 -5.74925805817 0.000 -0.186 0.000 H 0.75224758084 -0.00860493512 -5.25016290812 -0.001 -0.239 0.001 H -3.29620044300 -0.00255800648 -3.88456579214 0.000 0.180 -0.001 H 1.47161249279 -0.00457826661 -2.87685200854 0.001 0.447 -0.001 H -1.69176120521 -0.00597000955 5.75026973076 -0.000 0.203 0.000 H 0.75025791005 -0.00892914887 5.25161119224 0.001 0.247 0.001 H 1.46975366817 -0.00523069331 2.87805400798 -0.001 -0.474 -0.001 H -3.29750276746 -0.00099200484 3.88584245085 -0.000 -0.187 -0.001 H -4.55513299541 0.00377930937 -2.13473279421 0.000 0.011 0.000 H -4.55107479454 0.00501307822 2.13844314827 0.000 -0.011 -0.000 H -6.83436893102 0.00806057203 1.19721860356 -0.000 -0.001 -0.000 H 6.86748209639 1.20005966818 0.00372860376 -0.000 0.000 -0.000 61 Mode 100: freq=1128.50 N -0.44003451495 -0.00038510790 2.12369783068 -0.001 -0.039 0.001 C -1.76594470239 0.00039861437 2.37754210613 0.000 -0.055 0.000 C -2.24923313135 -0.00145267054 3.67997125809 0.001 0.129 0.000 C -1.33887502024 -0.00450793845 4.73956848945 -0.000 -0.111 -0.001 C 0.02462671625 -0.00591801736 4.46614405978 -0.001 -0.172 -0.001 C 0.43187566201 -0.00376957955 3.13352499014 0.000 0.292 0.001 C -2.63984642995 0.00218980399 1.17162612704 0.000 0.023 0.000 N -1.98513620489 0.00132140951 0.00153900685 0.001 -0.012 0.000 C -2.63911589169 0.00167522827 -1.17277445342 0.000 0.025 -0.000 C -4.02452897564 0.00329996303 -1.20791476641 -0.000 -0.003 -0.001 C -4.73391255267 0.00451580118 -0.00020876193 -0.001 0.001 0.000 C -4.02924140493 0.00399189729 1.20660077672 -0.000 -0.003 0.001 Co 0.00000000000 0.00000000000 0.00000000000 -0.001 0.003 0.000 N -0.43839318333 -0.00054206762 -2.12229806799 -0.001 -0.041 -0.001 C -1.76408906064 -0.00030645034 -2.37697009192 0.000 -0.059 -0.000 C -2.24773885821 -0.00257631963 -3.67934971086 0.001 0.137 -0.000 C -1.33713102227 -0.00526459193 -4.73855802198 -0.000 -0.114 0.001 C 0.02654101484 -0.00591797621 -4.46472703619 -0.001 -0.185 0.001 C 0.43371721952 -0.00363389350 -3.13225443930 0.000 0.308 -0.001 S -6.53329279136 0.00637481657 -0.11611178087 0.000 0.000 -0.000 N 2.00981687167 0.00259443239 -0.00000686048 0.013 0.002 0.000 C 2.67119656792 1.17263645248 0.00045766926 -0.002 -0.003 0.000 C 4.06129317470 1.20536051565 0.00241240325 -0.000 -0.010 -0.000 C 4.76783866331 0.00148799420 0.00346798881 -0.002 0.003 -0.000 C 4.05723810074 -1.20352939940 0.00211502115 -0.009 0.007 0.000 C 2.67108506586 -1.17139122066 0.00026591651 0.002 -0.002 -0.000 C 1.82209539371 2.39842937406 -0.00175320633 0.000 -0.000 0.000 C 2.33938959521 3.68993217240 -0.00584554905 -0.005 0.000 -0.000 C 1.45736908622 4.77231118002 -0.00917967851 -0.002 0.001 0.000 C 0.08658913130 4.53522926787 -0.00833235387 0.005 -0.007 0.000 C -0.35359617412 3.21325694137 -0.00400174376 0.001 0.001 -0.000 N 0.49290585413 2.18198449515 -0.00068475564 0.001 0.009 0.000 S 6.56718562933 -0.11349126889 0.00673479967 0.001 0.000 0.000 C 1.82142022278 -2.39594383179 -0.00206827421 -0.001 0.001 0.000 C 2.33969079820 -3.68709653410 -0.00625612120 0.001 0.001 0.000 C 1.45789786198 -4.76953179608 -0.00945089783 0.003 -0.002 -0.000 C 0.08684213972 -4.53272927032 -0.00840538011 -0.004 -0.004 -0.000 C -0.35393854068 -3.21111942258 -0.00398541364 -0.003 0.001 0.000 N 0.49225266031 -2.17934076887 -0.00084210065 0.001 0.004 -0.000 H 1.83694111827 5.77332096953 -0.01265611066 -0.003 0.001 -0.000 H -0.61802819388 5.33967450634 -0.01131742088 0.001 -0.003 -0.000 H 3.39175422949 3.87200638269 -0.00704552340 -0.001 0.000 0.000 H -1.39787683933 2.98334799634 -0.00369736757 -0.000 0.002 0.000 H 1.83794742242 -5.77033326187 -0.01295832570 0.003 0.000 -0.000 H -0.61749414542 -5.33746053721 -0.01121572048 -0.001 -0.001 0.000 H -1.39833026435 -2.98175334118 -0.00345676225 -0.000 0.003 -0.000 H 3.39230213722 -3.86796714602 -0.00754158092 0.001 0.002 -0.000 H 4.58301895157 2.13678100538 0.00314824260 -0.000 -0.003 0.000 H 4.58784714512 -2.12983634010 0.00211631073 -0.003 0.002 -0.000 H -1.68997263563 -0.00719388386 -5.74925805817 0.000 0.196 -0.000 H 0.75224758084 -0.00860493512 -5.25016290812 -0.000 0.251 -0.000 H -3.29620044300 -0.00255800648 -3.88456579214 0.000 -0.189 0.000 H 1.47161249279 -0.00457826661 -2.87685200854 -0.001 -0.473 0.001 H -1.69176120521 -0.00597000955 5.75026973076 0.000 0.191 0.000 H 0.75025791005 -0.00892914887 5.25161119224 0.000 0.232 0.000 H 1.46975366817 -0.00523069331 2.87805400798 -0.001 -0.448 -0.001 H -3.29750276746 -0.00099200484 3.88584245085 0.000 -0.176 -0.000 H -4.55513299541 0.00377930937 -2.13473279421 0.000 -0.008 -0.000 H -4.55107479454 0.00501307822 2.13844314827 0.000 -0.008 0.000 H -6.83436893102 0.00806057203 1.19721860356 0.000 0.000 0.000 H 6.86748209639 1.20005966818 0.00372860376 0.000 0.000 0.000 61 Mode 101: freq=1133.54 N -0.44003451495 -0.00038510790 2.12369783068 -0.068 -0.000 0.126 C -1.76594470239 0.00039861437 2.37754210613 0.019 0.000 -0.020 C -2.24923313135 -0.00145267054 3.67997125809 0.097 -0.000 -0.016 C -1.33887502024 -0.00450793845 4.73956848945 -0.036 0.000 0.053 C 0.02462671625 -0.00591801736 4.46614405978 -0.037 0.000 -0.082 C 0.43187566201 -0.00376957955 3.13352499014 0.057 -0.001 -0.004 C -2.63984642995 0.00218980399 1.17162612704 -0.035 0.000 -0.005 N -1.98513620489 0.00132140951 0.00153900685 -0.609 0.001 -0.004 C -2.63911589169 0.00167522827 -1.17277445342 -0.008 -0.000 0.006 C -4.02452897564 0.00329996303 -1.20791476641 0.225 -0.000 0.406 C -4.73391255267 0.00451580118 -0.00020876193 0.132 -0.000 -0.000 C -4.02924140493 0.00399189729 1.20660077672 0.227 -0.000 -0.419 Co 0.00000000000 0.00000000000 0.00000000000 0.043 -0.000 -0.001 N -0.43839318333 -0.00054206762 -2.12229806799 -0.060 -0.000 -0.106 C -1.76408906064 -0.00030645034 -2.37697009192 0.024 0.000 0.013 C -2.24773885821 -0.00257631963 -3.67934971086 0.074 -0.000 0.014 C -1.33713102227 -0.00526459193 -4.73855802198 -0.029 0.000 -0.044 C 0.02654101484 -0.00591797621 -4.46472703619 -0.025 0.000 0.067 C 0.43371721952 -0.00363389350 -3.13225443930 0.039 -0.000 0.003 S -6.53329279136 0.00637481657 -0.11611178087 -0.029 0.000 0.014 N 2.00981687167 0.00259443239 -0.00000686048 0.072 -0.000 -0.000 C 2.67119656792 1.17263645248 0.00045766926 -0.001 0.011 0.000 C 4.06129317470 1.20536051565 0.00241240325 -0.028 -0.055 -0.000 C 4.76783866331 0.00148799420 0.00346798881 0.007 0.000 0.000 C 4.05723810074 -1.20352939940 0.00211502115 -0.028 0.053 -0.000 C 2.67108506586 -1.17139122066 0.00026591651 -0.003 -0.011 0.000 C 1.82209539371 2.39842937406 -0.00175320633 -0.008 0.015 -0.001 C 2.33938959521 3.68993217240 -0.00584554905 -0.028 0.008 0.001 C 1.45736908622 4.77231118002 -0.00917967851 -0.018 -0.027 -0.001 C 0.08658913130 4.53522926787 -0.00833235387 0.028 -0.031 -0.001 C -0.35359617412 3.21325694137 -0.00400174376 0.022 0.020 0.002 N 0.49290585413 2.18198449515 -0.00068475564 0.003 0.024 -0.000 S 6.56718562933 -0.11349126889 0.00673479967 -0.001 0.002 -0.000 C 1.82142022278 -2.39594383179 -0.00206827421 -0.008 -0.015 -0.001 C 2.33969079820 -3.68709653410 -0.00625612120 -0.026 -0.009 0.001 C 1.45789786198 -4.76953179608 -0.00945089783 -0.019 0.029 -0.001 C 0.08684213972 -4.53272927032 -0.00840538011 0.027 0.030 -0.001 C -0.35393854068 -3.21111942258 -0.00398541364 0.024 -0.020 0.002 N 0.49225266031 -2.17934076887 -0.00084210065 0.002 -0.022 -0.000 H 1.83694111827 5.77332096953 -0.01265611066 -0.016 -0.005 0.002 H -0.61802819388 5.33967450634 -0.01131742088 0.011 -0.009 0.002 H 3.39175422949 3.87200638269 -0.00704552340 -0.010 0.010 -0.001 H -1.39787683933 2.98334799634 -0.00369736757 0.004 0.022 -0.004 H 1.83794742242 -5.77033326187 -0.01295832570 -0.016 0.006 0.001 H -0.61749414542 -5.33746053721 -0.01121572048 0.011 0.008 0.002 H -1.39833026435 -2.98175334118 -0.00345676225 0.004 -0.023 -0.004 H 3.39230213722 -3.86796714602 -0.00754158092 -0.010 -0.011 -0.001 H 4.58301895157 2.13678100538 0.00314824260 -0.010 -0.016 -0.000 H 4.58784714512 -2.12983634010 0.00211631073 -0.011 0.015 -0.000 H -1.68997263563 -0.00719388386 -5.74925805817 -0.008 -0.000 -0.013 H 0.75224758084 -0.00860493512 -5.25016290812 -0.000 -0.000 0.027 H -3.29620044300 -0.00255800648 -3.88456579214 0.014 0.000 0.047 H 1.47161249279 -0.00457826661 -2.87685200854 0.006 0.001 0.020 H -1.69176120521 -0.00597000955 5.75026973076 -0.010 -0.001 0.016 H 0.75025791005 -0.00892914887 5.25161119224 -0.007 -0.000 -0.029 H 1.46975366817 -0.00523069331 2.87805400798 0.011 0.001 -0.022 H -3.29750276746 -0.00099200484 3.88584245085 0.020 0.000 -0.052 H -4.55513299541 0.00377930937 -2.13473279421 0.055 0.000 0.136 H -4.55107479454 0.00501307822 2.13844314827 0.044 0.000 -0.146 H -6.83436893102 0.00806057203 1.19721860356 -0.085 0.000 -0.015 H 6.86748209639 1.20005966818 0.00372860376 0.008 -0.002 0.000 61 Mode 102: freq=1150.51 N -0.44003451495 -0.00038510790 2.12369783068 0.066 0.000 -0.057 C -1.76594470239 0.00039861437 2.37754210613 0.024 -0.000 0.058 C -2.24923313135 -0.00145267054 3.67997125809 -0.013 0.000 0.057 C -1.33887502024 -0.00450793845 4.73956848945 0.095 -0.000 -0.138 C 0.02462671625 -0.00591801736 4.46614405978 -0.055 0.000 -0.028 C 0.43187566201 -0.00376957955 3.13352499014 -0.123 0.000 0.087 C -2.63984642995 0.00218980399 1.17162612704 0.011 0.000 0.044 N -1.98513620489 0.00132140951 0.00153900685 -0.101 0.000 0.000 C -2.63911589169 0.00167522827 -1.17277445342 0.013 -0.000 -0.045 C -4.02452897564 0.00329996303 -1.20791476641 0.035 -0.000 0.091 C -4.73391255267 0.00451580118 -0.00020876193 -0.028 0.000 0.001 C -4.02924140493 0.00399189729 1.20660077672 0.035 -0.000 -0.094 Co 0.00000000000 0.00000000000 0.00000000000 0.012 0.000 -0.000 N -0.43839318333 -0.00054206762 -2.12229806799 0.070 0.000 0.062 C -1.76408906064 -0.00030645034 -2.37697009192 0.024 -0.000 -0.059 C -2.24773885821 -0.00257631963 -3.67934971086 -0.016 0.000 -0.059 C -1.33713102227 -0.00526459193 -4.73855802198 0.099 -0.000 0.142 C 0.02654101484 -0.00591797621 -4.46472703619 -0.056 0.000 0.027 C 0.43371721952 -0.00363389350 -3.13225443930 -0.128 0.000 -0.089 S -6.53329279136 0.00637481657 -0.11611178087 0.005 -0.000 0.002 N 2.00981687167 0.00259443239 -0.00000686048 -0.135 -0.001 -0.000 C 2.67119656792 1.17263645248 0.00045766926 0.024 -0.072 -0.000 C 4.06129317470 1.20536051565 0.00241240325 0.044 0.131 0.000 C 4.76783866331 0.00148799420 0.00346798881 -0.068 -0.002 -0.000 C 4.05723810074 -1.20352939940 0.00211502115 0.044 -0.127 0.000 C 2.67108506586 -1.17139122066 0.00026591651 0.024 0.073 -0.000 C 1.82209539371 2.39842937406 -0.00175320633 0.045 -0.104 0.000 C 2.33938959521 3.68993217240 -0.00584554905 -0.046 -0.107 -0.000 C 1.45736908622 4.77231118002 -0.00917967851 0.183 0.249 -0.000 C 0.08658913130 4.53522926787 -0.00833235387 -0.090 0.049 -0.000 C -0.35359617412 3.21325694137 -0.00400174376 -0.237 -0.156 -0.000 N 0.49290585413 2.18198449515 -0.00068475564 0.132 0.118 -0.000 S 6.56718562933 -0.11349126889 0.00673479967 0.014 -0.002 0.000 C 1.82142022278 -2.39594383179 -0.00206827421 0.045 0.106 0.000 C 2.33969079820 -3.68709653410 -0.00625612120 -0.050 0.111 -0.000 C 1.45789786198 -4.76953179608 -0.00945089783 0.189 -0.257 -0.000 C 0.08684213972 -4.53272927032 -0.00840538011 -0.092 -0.049 0.000 C -0.35393854068 -3.21111942258 -0.00398541364 -0.244 0.161 -0.000 N 0.49225266031 -2.17934076887 -0.00084210065 0.138 -0.124 -0.000 H 1.83694111827 5.77332096953 -0.01265611066 0.152 0.044 -0.001 H -0.61802819388 5.33967450634 -0.01131742088 -0.048 0.005 -0.000 H 3.39175422949 3.87200638269 -0.00704552340 0.006 -0.149 0.001 H -1.39787683933 2.98334799634 -0.00369736757 -0.041 -0.196 0.001 H 1.83794742242 -5.77033326187 -0.01295832570 0.157 -0.045 -0.001 H -0.61749414542 -5.33746053721 -0.01121572048 -0.050 -0.004 -0.000 H -1.39833026435 -2.98175334118 -0.00345676225 -0.042 0.203 0.002 H 3.39230213722 -3.86796714602 -0.00754158092 0.006 0.155 0.001 H 4.58301895157 2.13678100538 0.00314824260 0.012 0.039 -0.000 H 4.58784714512 -2.12983634010 0.00211631073 0.016 -0.036 -0.000 H -1.68997263563 -0.00719388386 -5.74925805817 0.082 0.000 0.028 H 0.75224758084 -0.00860493512 -5.25016290812 -0.030 0.000 0.001 H -3.29620044300 -0.00255800648 -3.88456579214 0.008 -0.000 -0.083 H 1.47161249279 -0.00457826661 -2.87685200854 -0.020 -0.001 -0.110 H -1.69176120521 -0.00597000955 5.75026973076 0.079 0.000 -0.027 H 0.75025791005 -0.00892914887 5.25161119224 -0.030 0.000 -0.001 H 1.46975366817 -0.00523069331 2.87805400798 -0.019 -0.000 0.106 H -3.29750276746 -0.00099200484 3.88584245085 0.009 -0.000 0.080 H -4.55513299541 0.00377930937 -2.13473279421 0.008 0.000 0.029 H -4.55107479454 0.00501307822 2.13844314827 0.006 0.000 -0.031 H -6.83436893102 0.00806057203 1.19721860356 -0.008 -0.000 -0.002 H 6.86748209639 1.20005966818 0.00372860376 -0.008 0.002 -0.000 61 Mode 103: freq=1152.96 N -0.44003451495 -0.00038510790 2.12369783068 -0.149 -0.000 0.148 C -1.76594470239 0.00039861437 2.37754210613 -0.038 0.000 -0.093 C -2.24923313135 -0.00145267054 3.67997125809 0.063 -0.000 -0.117 C -1.33887502024 -0.00450793845 4.73956848945 -0.184 0.000 0.258 C 0.02462671625 -0.00591801736 4.46614405978 0.088 -0.000 0.035 C 0.43187566201 -0.00376957955 3.13352499014 0.239 -0.000 -0.166 C -2.63984642995 0.00218980399 1.17162612704 -0.024 0.000 -0.059 N -1.98513620489 0.00132140951 0.00153900685 0.072 -0.000 -0.001 C -2.63911589169 0.00167522827 -1.17277445342 -0.022 0.000 0.061 C -4.02452897564 0.00329996303 -1.20791476641 -0.019 -0.000 -0.079 C -4.73391255267 0.00451580118 -0.00020876193 0.063 -0.000 -0.001 C -4.02924140493 0.00399189729 1.20660077672 -0.017 0.000 0.081 Co 0.00000000000 0.00000000000 0.00000000000 -0.004 -0.000 0.000 N -0.43839318333 -0.00054206762 -2.12229806799 -0.148 -0.000 -0.149 C -1.76408906064 -0.00030645034 -2.37697009192 -0.037 0.000 0.092 C -2.24773885821 -0.00257631963 -3.67934971086 0.064 -0.000 0.116 C -1.33713102227 -0.00526459193 -4.73855802198 -0.182 0.000 -0.255 C 0.02654101484 -0.00591797621 -4.46472703619 0.087 -0.000 -0.033 C 0.43371721952 -0.00363389350 -3.13225443930 0.237 -0.000 0.164 S -6.53329279136 0.00637481657 -0.11611178087 -0.014 0.000 -0.001 N 2.00981687167 0.00259443239 -0.00000686048 -0.002 0.000 -0.000 C 2.67119656792 1.17263645248 0.00045766926 0.016 -0.026 -0.000 C 4.06129317470 1.20536051565 0.00241240325 -0.006 0.015 -0.000 C 4.76783866331 0.00148799420 0.00346798881 -0.044 -0.000 -0.000 C 4.05723810074 -1.20352939940 0.00211502115 -0.004 -0.014 -0.000 C 2.67108506586 -1.17139122066 0.00026591651 0.013 0.027 -0.000 C 1.82209539371 2.39842937406 -0.00175320633 0.023 -0.049 0.000 C 2.33938959521 3.68993217240 -0.00584554905 -0.051 -0.069 -0.000 C 1.45736908622 4.77231118002 -0.00917967851 0.109 0.143 0.000 C 0.08658913130 4.53522926787 -0.00833235387 -0.043 0.018 -0.000 C -0.35359617412 3.21325694137 -0.00400174376 -0.142 -0.093 -0.000 N 0.49290585413 2.18198449515 -0.00068475564 0.092 0.093 -0.000 S 6.56718562933 -0.11349126889 0.00673479967 0.010 0.000 0.000 C 1.82142022278 -2.39594383179 -0.00206827421 0.022 0.047 0.000 C 2.33969079820 -3.68709653410 -0.00625612120 -0.050 0.064 -0.000 C 1.45789786198 -4.76953179608 -0.00945089783 0.101 -0.134 0.000 C 0.08684213972 -4.53272927032 -0.00840538011 -0.038 -0.014 -0.000 C -0.35393854068 -3.21111942258 -0.00398541364 -0.132 0.086 -0.000 N 0.49225266031 -2.17934076887 -0.00084210065 0.087 -0.090 -0.000 H 1.83694111827 5.77332096953 -0.01265611066 0.094 0.023 -0.001 H -0.61802819388 5.33967450634 -0.01131742088 -0.023 0.001 0.000 H 3.39175422949 3.87200638269 -0.00704552340 -0.002 -0.098 0.001 H -1.39787683933 2.98334799634 -0.00369736757 -0.024 -0.120 0.001 H 1.83794742242 -5.77033326187 -0.01295832570 0.087 -0.021 -0.001 H -0.61749414542 -5.33746053721 -0.01121572048 -0.021 -0.000 0.000 H -1.39833026435 -2.98175334118 -0.00345676225 -0.022 0.111 0.001 H 3.39230213722 -3.86796714602 -0.00754158092 -0.003 0.090 0.001 H 4.58301895157 2.13678100538 0.00314824260 0.002 0.001 -0.000 H 4.58784714512 -2.12983634010 0.00211631073 0.003 -0.001 0.000 H -1.68997263563 -0.00719388386 -5.74925805817 -0.157 -0.001 -0.046 H 0.75224758084 -0.00860493512 -5.25016290812 0.048 0.000 0.002 H -3.29620044300 -0.00255800648 -3.88456579214 -0.006 0.001 0.165 H 1.47161249279 -0.00457826661 -2.87685200854 0.035 0.001 0.206 H -1.69176120521 -0.00597000955 5.75026973076 -0.158 -0.001 0.047 H 0.75025791005 -0.00892914887 5.25161119224 0.048 0.000 -0.001 H 1.46975366817 -0.00523069331 2.87805400798 0.035 0.001 -0.208 H -3.29750276746 -0.00099200484 3.88584245085 -0.007 0.001 -0.167 H -4.55513299541 0.00377930937 -2.13473279421 -0.007 -0.000 -0.022 H -4.55107479454 0.00501307822 2.13844314827 -0.004 -0.000 0.024 H -6.83436893102 0.00806057203 1.19721860356 0.001 -0.000 0.001 H 6.86748209639 1.20005966818 0.00372860376 0.004 -0.000 0.000 61 Mode 104: freq=1154.53 N -0.44003451495 -0.00038510790 2.12369783068 -0.003 0.003 0.004 C -1.76594470239 0.00039861437 2.37754210613 -0.001 0.000 -0.002 C -2.24923313135 -0.00145267054 3.67997125809 0.002 0.000 -0.003 C -1.33887502024 -0.00450793845 4.73956848945 -0.004 -0.002 0.006 C 0.02462671625 -0.00591801736 4.46614405978 0.002 0.002 0.000 C 0.43187566201 -0.00376957955 3.13352499014 0.005 -0.003 -0.004 C -2.63984642995 0.00218980399 1.17162612704 -0.001 -0.004 -0.002 N -1.98513620489 0.00132140951 0.00153900685 0.002 0.006 -0.000 C -2.63911589169 0.00167522827 -1.17277445342 -0.001 -0.004 0.002 C -4.02452897564 0.00329996303 -1.20791476641 -0.001 0.001 -0.002 C -4.73391255267 0.00451580118 -0.00020876193 0.001 -0.001 -0.000 C -4.02924140493 0.00399189729 1.20660077672 -0.001 0.001 0.002 Co 0.00000000000 0.00000000000 0.00000000000 -0.000 0.003 0.000 N -0.43839318333 -0.00054206762 -2.12229806799 -0.004 0.003 -0.004 C -1.76408906064 -0.00030645034 -2.37697009192 -0.001 0.000 0.002 C -2.24773885821 -0.00257631963 -3.67934971086 0.002 0.000 0.003 C -1.33713102227 -0.00526459193 -4.73855802198 -0.004 -0.002 -0.006 C 0.02654101484 -0.00591797621 -4.46472703619 0.002 0.002 -0.001 C 0.43371721952 -0.00363389350 -3.13225443930 0.006 -0.003 0.004 S -6.53329279136 0.00637481657 -0.11611178087 -0.000 -0.000 -0.000 N 2.00981687167 0.00259443239 -0.00000686048 0.008 -0.058 0.000 C 2.67119656792 1.17263645248 0.00045766926 0.021 -0.017 0.000 C 4.06129317470 1.20536051565 0.00241240325 0.020 0.002 -0.000 C 4.76783866331 0.00148799420 0.00346798881 -0.001 -0.028 0.000 C 4.05723810074 -1.20352939940 0.00211502115 -0.026 0.010 0.000 C 2.67108506586 -1.17139122066 0.00026591651 -0.022 -0.015 -0.000 C 1.82209539371 2.39842937406 -0.00175320633 -0.007 0.050 -0.000 C 2.33938959521 3.68993217240 -0.00584554905 0.039 0.153 -0.000 C 1.45736908622 4.77231118002 -0.00917967851 -0.222 -0.265 0.000 C 0.08658913130 4.53522926787 -0.00833235387 0.149 -0.100 0.000 C -0.35359617412 3.21325694137 -0.00400174376 0.238 0.204 -0.000 N 0.49290585413 2.18198449515 -0.00068475564 -0.175 -0.121 0.000 S 6.56718562933 -0.11349126889 0.00673479967 -0.004 0.009 -0.000 C 1.82142022278 -2.39594383179 -0.00206827421 0.006 0.051 0.000 C 2.33969079820 -3.68709653410 -0.00625612120 -0.042 0.151 0.000 C 1.45789786198 -4.76953179608 -0.00945089783 0.223 -0.264 -0.000 C 0.08684213972 -4.53272927032 -0.00840538011 -0.147 -0.097 -0.000 C -0.35393854068 -3.21111942258 -0.00398541364 -0.237 0.201 0.000 N 0.49225266031 -2.17934076887 -0.00084210065 0.176 -0.124 -0.000 H 1.83694111827 5.77332096953 -0.01265611066 -0.210 -0.032 0.001 H -0.61802819388 5.33967450634 -0.01131742088 0.078 -0.012 0.000 H 3.39175422949 3.87200638269 -0.00704552340 -0.019 0.229 -0.001 H -1.39787683933 2.98334799634 -0.00369736757 0.030 0.265 -0.002 H 1.83794742242 -5.77033326187 -0.01295832570 0.210 -0.032 -0.001 H -0.61749414542 -5.33746053721 -0.01121572048 -0.078 -0.010 -0.000 H -1.39833026435 -2.98175334118 -0.00345676225 -0.030 0.264 0.002 H 3.39230213722 -3.86796714602 -0.00754158092 0.018 0.227 0.001 H 4.58301895157 2.13678100538 0.00314824260 -0.007 0.009 0.000 H 4.58784714512 -2.12983634010 0.00211631073 0.003 0.011 -0.000 H -1.68997263563 -0.00719388386 -5.74925805817 -0.004 0.003 -0.001 H 0.75224758084 -0.00860493512 -5.25016290812 0.001 -0.003 0.000 H -3.29620044300 -0.00255800648 -3.88456579214 -0.000 -0.000 0.004 H 1.47161249279 -0.00457826661 -2.87685200854 0.001 0.005 0.005 H -1.69176120521 -0.00597000955 5.75026973076 -0.003 0.003 0.001 H 0.75025791005 -0.00892914887 5.25161119224 0.001 -0.003 -0.000 H 1.46975366817 -0.00523069331 2.87805400798 0.001 0.005 -0.004 H -3.29750276746 -0.00099200484 3.88584245085 -0.000 -0.000 -0.004 H -4.55513299541 0.00377930937 -2.13473279421 -0.000 0.000 -0.001 H -4.55107479454 0.00501307822 2.13844314827 -0.000 0.000 0.001 H -6.83436893102 0.00806057203 1.19721860356 0.000 0.000 0.000 H 6.86748209639 1.20005966818 0.00372860376 0.033 -0.006 0.000 61 Mode 105: freq=1156.03 N -0.44003451495 -0.00038510790 2.12369783068 -0.182 0.000 0.140 C -1.76594470239 0.00039861437 2.37754210613 0.001 0.000 -0.047 C -2.24923313135 -0.00145267054 3.67997125809 0.045 -0.000 -0.151 C -1.33887502024 -0.00450793845 4.73956848945 -0.216 0.000 0.266 C 0.02462671625 -0.00591801736 4.46614405978 0.148 -0.000 0.082 C 0.43187566201 -0.00376957955 3.13352499014 0.231 -0.000 -0.203 C -2.63984642995 0.00218980399 1.17162612704 0.019 -0.000 0.018 N -1.98513620489 0.00132140951 0.00153900685 0.007 0.000 0.049 C -2.63911589169 0.00167522827 -1.17277445342 -0.019 0.000 0.016 C -4.02452897564 0.00329996303 -1.20791476641 -0.023 0.000 -0.008 C -4.73391255267 0.00451580118 -0.00020876193 -0.002 0.000 0.022 C -4.02924140493 0.00399189729 1.20660077672 0.017 -0.000 -0.000 Co 0.00000000000 0.00000000000 0.00000000000 -0.001 0.000 -0.006 N -0.43839318333 -0.00054206762 -2.12229806799 0.185 0.000 0.144 C -1.76408906064 -0.00030645034 -2.37697009192 -0.002 -0.000 -0.048 C -2.24773885821 -0.00257631963 -3.67934971086 -0.048 0.000 -0.150 C -1.33713102227 -0.00526459193 -4.73855802198 0.218 -0.000 0.266 C 0.02654101484 -0.00591797621 -4.46472703619 -0.147 0.000 0.079 C 0.43371721952 -0.00363389350 -3.13225443930 -0.232 0.000 -0.202 S -6.53329279136 0.00637481657 -0.11611178087 -0.003 -0.000 -0.007 N 2.00981687167 0.00259443239 -0.00000686048 0.001 -0.000 -0.007 C 2.67119656792 1.17263645248 0.00045766926 -0.000 0.001 0.005 C 4.06129317470 1.20536051565 0.00241240325 -0.000 -0.001 -0.001 C 4.76783866331 0.00148799420 0.00346798881 0.001 -0.000 0.001 C 4.05723810074 -1.20352939940 0.00211502115 -0.000 0.001 -0.001 C 2.67108506586 -1.17139122066 0.00026591651 -0.000 -0.001 0.005 C 1.82209539371 2.39842937406 -0.00175320633 -0.000 0.001 -0.001 C 2.33938959521 3.68993217240 -0.00584554905 0.001 0.001 -0.001 C 1.45736908622 4.77231118002 -0.00917967851 -0.002 -0.002 0.002 C 0.08658913130 4.53522926787 -0.00833235387 0.001 -0.000 -0.003 C -0.35359617412 3.21325694137 -0.00400174376 0.002 0.002 0.004 N 0.49290585413 2.18198449515 -0.00068475564 -0.002 -0.002 -0.003 S 6.56718562933 -0.11349126889 0.00673479967 -0.000 0.000 0.000 C 1.82142022278 -2.39594383179 -0.00206827421 -0.000 -0.001 -0.001 C 2.33969079820 -3.68709653410 -0.00625612120 0.001 -0.001 -0.001 C 1.45789786198 -4.76953179608 -0.00945089783 -0.001 0.002 0.003 C 0.08684213972 -4.53272927032 -0.00840538011 0.000 0.000 -0.003 C -0.35393854068 -3.21111942258 -0.00398541364 0.002 -0.001 0.004 N 0.49225266031 -2.17934076887 -0.00084210065 -0.001 0.001 -0.003 H 1.83694111827 5.77332096953 -0.01265611066 -0.002 -0.000 -0.004 H -0.61802819388 5.33967450634 -0.01131742088 0.000 0.000 0.003 H 3.39175422949 3.87200638269 -0.00704552340 0.000 0.002 0.000 H -1.39787683933 2.98334799634 -0.00369736757 0.000 0.002 -0.006 H 1.83794742242 -5.77033326187 -0.01295832570 -0.001 0.000 -0.004 H -0.61749414542 -5.33746053721 -0.01121572048 0.000 -0.000 0.004 H -1.39833026435 -2.98175334118 -0.00345676225 0.000 -0.001 -0.006 H 3.39230213722 -3.86796714602 -0.00754158092 0.000 -0.001 0.001 H 4.58301895157 2.13678100538 0.00314824260 -0.000 -0.000 -0.000 H 4.58784714512 -2.12983634010 0.00211631073 -0.000 0.000 -0.000 H -1.68997263563 -0.00719388386 -5.74925805817 0.208 0.001 0.037 H 0.75224758084 -0.00860493512 -5.25016290812 -0.078 -0.000 0.003 H -3.29620044300 -0.00255800648 -3.88456579214 0.021 -0.001 -0.232 H 1.47161249279 -0.00457826661 -2.87685200854 -0.022 -0.001 -0.265 H -1.69176120521 -0.00597000955 5.75026973076 -0.207 -0.001 0.037 H 0.75025791005 -0.00892914887 5.25161119224 0.078 -0.000 0.004 H 1.46975366817 -0.00523069331 2.87805400798 0.022 0.001 -0.265 H -3.29750276746 -0.00099200484 3.88584245085 -0.022 0.001 -0.233 H -4.55513299541 0.00377930937 -2.13473279421 0.006 0.000 -0.011 H -4.55107479454 0.00501307822 2.13844314827 -0.009 -0.000 -0.009 H -6.83436893102 0.00806057203 1.19721860356 0.027 -0.000 0.005 H 6.86748209639 1.20005966818 0.00372860376 0.000 -0.000 -0.000 61 Mode 106: freq=1164.51 N -0.44003451495 -0.00038510790 2.12369783068 -0.002 -0.000 0.001 C -1.76594470239 0.00039861437 2.37754210613 -0.000 -0.000 -0.000 C -2.24923313135 -0.00145267054 3.67997125809 0.001 0.000 -0.001 C -1.33887502024 -0.00450793845 4.73956848945 -0.001 -0.000 0.002 C 0.02462671625 -0.00591801736 4.46614405978 0.001 -0.000 0.001 C 0.43187566201 -0.00376957955 3.13352499014 0.002 0.001 -0.002 C -2.63984642995 0.00218980399 1.17162612704 -0.000 0.000 0.000 N -1.98513620489 0.00132140951 0.00153900685 0.000 -0.000 -0.000 C -2.63911589169 0.00167522827 -1.17277445342 0.000 -0.000 0.000 C -4.02452897564 0.00329996303 -1.20791476641 -0.001 0.000 -0.000 C -4.73391255267 0.00451580118 -0.00020876193 -0.000 -0.000 -0.000 C -4.02924140493 0.00399189729 1.20660077672 0.001 -0.000 0.000 Co 0.00000000000 0.00000000000 0.00000000000 -0.000 -0.000 -0.000 N -0.43839318333 -0.00054206762 -2.12229806799 0.001 0.000 0.001 C -1.76408906064 -0.00030645034 -2.37697009192 0.000 0.000 -0.000 C -2.24773885821 -0.00257631963 -3.67934971086 -0.001 0.000 -0.001 C -1.33713102227 -0.00526459193 -4.73855802198 0.001 -0.000 0.002 C 0.02654101484 -0.00591797621 -4.46472703619 -0.001 0.001 0.001 C 0.43371721952 -0.00363389350 -3.13225443930 -0.002 -0.001 -0.001 S -6.53329279136 0.00637481657 -0.11611178087 0.000 -0.000 -0.000 N 2.00981687167 0.00259443239 -0.00000686048 0.000 -0.000 -0.003 C 2.67119656792 1.17263645248 0.00045766926 -0.000 0.000 0.005 C 4.06129317470 1.20536051565 0.00241240325 0.000 -0.000 0.010 C 4.76783866331 0.00148799420 0.00346798881 0.000 -0.000 -0.001 C 4.05723810074 -1.20352939940 0.00211502115 -0.000 0.000 -0.003 C 2.67108506586 -1.17139122066 0.00026591651 -0.000 -0.000 0.001 C 1.82209539371 2.39842937406 -0.00175320633 -0.000 0.000 -0.006 C 2.33938959521 3.68993217240 -0.00584554905 -0.000 0.000 0.216 C 1.45736908622 4.77231118002 -0.00917967851 0.000 -0.001 -0.402 C 0.08658913130 4.53522926787 -0.00833235387 -0.000 0.001 0.288 C -0.35359617412 3.21325694137 -0.00400174376 -0.000 -0.001 -0.104 N 0.49290585413 2.18198449515 -0.00068475564 0.000 0.001 -0.010 S 6.56718562933 -0.11349126889 0.00673479967 -0.000 0.000 0.000 C 1.82142022278 -2.39594383179 -0.00206827421 -0.000 -0.000 -0.000 C 2.33969079820 -3.68709653410 -0.00625612120 0.000 0.000 -0.000 C 1.45789786198 -4.76953179608 -0.00945089783 0.000 -0.000 0.000 C 0.08684213972 -4.53272927032 -0.00840538011 -0.000 -0.000 -0.000 C -0.35393854068 -3.21111942258 -0.00398541364 -0.000 0.000 0.000 N 0.49225266031 -2.17934076887 -0.00084210065 0.000 0.000 -0.000 H 1.83694111827 5.77332096953 -0.01265611066 0.000 0.002 0.628 H -0.61802819388 5.33967450634 -0.01131742088 -0.000 -0.002 -0.419 H 3.39175422949 3.87200638269 -0.00704552340 -0.000 -0.002 -0.317 H -1.39787683933 2.98334799634 -0.00369736757 -0.000 0.000 0.167 H 1.83794742242 -5.77033326187 -0.01295832570 0.000 0.000 -0.001 H -0.61749414542 -5.33746053721 -0.01121572048 -0.000 -0.000 0.001 H -1.39833026435 -2.98175334118 -0.00345676225 0.000 0.000 -0.000 H 3.39230213722 -3.86796714602 -0.00754158092 0.000 0.000 0.000 H 4.58301895157 2.13678100538 0.00314824260 0.000 -0.000 -0.027 H 4.58784714512 -2.12983634010 0.00211631073 -0.000 0.000 0.002 H -1.68997263563 -0.00719388386 -5.74925805817 0.002 0.001 0.000 H 0.75224758084 -0.00860493512 -5.25016290812 -0.000 -0.001 0.000 H -3.29620044300 -0.00255800648 -3.88456579214 -0.000 -0.000 -0.002 H 1.47161249279 -0.00457826661 -2.87685200854 -0.000 0.002 -0.002 H -1.69176120521 -0.00597000955 5.75026973076 -0.002 0.001 0.000 H 0.75025791005 -0.00892914887 5.25161119224 0.000 0.000 0.000 H 1.46975366817 -0.00523069331 2.87805400798 0.000 -0.001 -0.002 H -3.29750276746 -0.00099200484 3.88584245085 0.000 -0.000 -0.002 H -4.55513299541 0.00377930937 -2.13473279421 -0.000 -0.000 0.000 H -4.55107479454 0.00501307822 2.13844314827 0.000 0.000 0.000 H -6.83436893102 0.00806057203 1.19721860356 0.000 0.000 0.000 H 6.86748209639 1.20005966818 0.00372860376 0.000 -0.000 -0.001 61 Mode 107: freq=1164.78 N -0.44003451495 -0.00038510790 2.12369783068 -0.002 0.000 0.001 C -1.76594470239 0.00039861437 2.37754210613 -0.000 -0.000 -0.000 C -2.24923313135 -0.00145267054 3.67997125809 0.001 0.003 -0.001 C -1.33887502024 -0.00450793845 4.73956848945 -0.002 -0.007 0.002 C 0.02462671625 -0.00591801736 4.46614405978 0.001 0.005 0.001 C 0.43187566201 -0.00376957955 3.13352499014 0.002 -0.003 -0.002 C -2.63984642995 0.00218980399 1.17162612704 -0.000 -0.000 0.000 N -1.98513620489 0.00132140951 0.00153900685 0.000 -0.000 0.000 C -2.63911589169 0.00167522827 -1.17277445342 0.000 0.000 0.000 C -4.02452897564 0.00329996303 -1.20791476641 -0.001 -0.000 -0.000 C -4.73391255267 0.00451580118 -0.00020876193 -0.000 -0.000 -0.000 C -4.02924140493 0.00399189729 1.20660077672 0.001 0.000 0.000 Co 0.00000000000 0.00000000000 0.00000000000 -0.000 0.000 -0.000 N -0.43839318333 -0.00054206762 -2.12229806799 0.002 -0.000 0.001 C -1.76408906064 -0.00030645034 -2.37697009192 0.000 -0.000 -0.000 C -2.24773885821 -0.00257631963 -3.67934971086 -0.001 -0.001 -0.001 C -1.33713102227 -0.00526459193 -4.73855802198 0.001 0.002 0.002 C 0.02654101484 -0.00591797621 -4.46472703619 -0.001 -0.002 0.001 C 0.43371721952 -0.00363389350 -3.13225443930 -0.002 0.001 -0.002 S -6.53329279136 0.00637481657 -0.11611178087 -0.000 0.000 -0.000 N 2.00981687167 0.00259443239 -0.00000686048 0.000 0.000 -0.003 C 2.67119656792 1.17263645248 0.00045766926 -0.000 0.000 0.001 C 4.06129317470 1.20536051565 0.00241240325 -0.000 -0.000 -0.003 C 4.76783866331 0.00148799420 0.00346798881 0.000 0.000 -0.001 C 4.05723810074 -1.20352939940 0.00211502115 0.000 0.000 0.011 C 2.67108506586 -1.17139122066 0.00026591651 -0.000 -0.000 0.005 C 1.82209539371 2.39842937406 -0.00175320633 -0.000 0.000 0.000 C 2.33938959521 3.68993217240 -0.00584554905 -0.000 -0.000 0.000 C 1.45736908622 4.77231118002 -0.00917967851 0.000 0.000 -0.001 C 0.08658913130 4.53522926787 -0.00833235387 -0.000 0.000 0.000 C -0.35359617412 3.21325694137 -0.00400174376 -0.000 -0.000 0.000 N 0.49290585413 2.18198449515 -0.00068475564 0.000 0.000 -0.000 S 6.56718562933 -0.11349126889 0.00673479967 -0.000 -0.000 0.000 C 1.82142022278 -2.39594383179 -0.00206827421 -0.000 -0.000 -0.007 C 2.33969079820 -3.68709653410 -0.00625612120 -0.000 -0.000 0.220 C 1.45789786198 -4.76953179608 -0.00945089783 0.000 0.001 -0.403 C 0.08684213972 -4.53272927032 -0.00840538011 -0.000 -0.001 0.284 C -0.35393854068 -3.21111942258 -0.00398541364 -0.000 0.001 -0.101 N 0.49225266031 -2.17934076887 -0.00084210065 0.000 -0.001 -0.010 H 1.83694111827 5.77332096953 -0.01265611066 0.000 -0.000 0.001 H -0.61802819388 5.33967450634 -0.01131742088 -0.000 0.000 -0.001 H 3.39175422949 3.87200638269 -0.00704552340 0.000 -0.000 -0.001 H -1.39787683933 2.98334799634 -0.00369736757 -0.000 -0.000 -0.000 H 1.83794742242 -5.77033326187 -0.01295832570 0.000 -0.002 0.628 H -0.61749414542 -5.33746053721 -0.01121572048 -0.000 0.002 -0.414 H -1.39833026435 -2.98175334118 -0.00345676225 0.000 -0.000 0.162 H 3.39230213722 -3.86796714602 -0.00754158092 -0.000 0.002 -0.324 H 4.58301895157 2.13678100538 0.00314824260 -0.000 -0.000 0.002 H 4.58784714512 -2.12983634010 0.00211631073 0.000 0.000 -0.030 H -1.68997263563 -0.00719388386 -5.74925805817 0.002 -0.003 0.000 H 0.75224758084 -0.00860493512 -5.25016290812 -0.000 0.002 0.000 H -3.29620044300 -0.00255800648 -3.88456579214 -0.000 0.001 -0.002 H 1.47161249279 -0.00457826661 -2.87685200854 -0.000 -0.002 -0.002 H -1.69176120521 -0.00597000955 5.75026973076 -0.002 0.010 0.000 H 0.75025791005 -0.00892914887 5.25161119224 0.000 -0.007 0.000 H 1.46975366817 -0.00523069331 2.87805400798 0.000 0.004 -0.002 H -3.29750276746 -0.00099200484 3.88584245085 0.000 -0.005 -0.002 H -4.55513299541 0.00377930937 -2.13473279421 -0.000 0.000 0.000 H -4.55107479454 0.00501307822 2.13844314827 0.000 -0.001 0.000 H -6.83436893102 0.00806057203 1.19721860356 0.000 -0.000 0.000 H 6.86748209639 1.20005966818 0.00372860376 -0.000 0.000 0.001 61 Mode 108: freq=1164.81 N -0.44003451495 -0.00038510790 2.12369783068 0.000 0.009 -0.001 C -1.76594470239 0.00039861437 2.37754210613 -0.000 0.007 -0.000 C -2.24923313135 -0.00145267054 3.67997125809 -0.000 -0.216 0.000 C -1.33887502024 -0.00450793845 4.73956848945 0.001 0.403 0.000 C 0.02462671625 -0.00591801736 4.46614405978 -0.001 -0.287 -0.000 C 0.43187566201 -0.00376957955 3.13352499014 0.000 0.103 0.000 C -2.63984642995 0.00218980399 1.17162612704 -0.000 -0.006 -0.000 N -1.98513620489 0.00132140951 0.00153900685 0.000 0.003 0.000 C -2.63911589169 0.00167522827 -1.17277445342 -0.000 -0.001 0.000 C -4.02452897564 0.00329996303 -1.20791476641 -0.000 0.003 -0.000 C -4.73391255267 0.00451580118 -0.00020876193 0.000 0.000 -0.000 C -4.02924140493 0.00399189729 1.20660077672 0.000 -0.009 0.000 Co 0.00000000000 0.00000000000 0.00000000000 -0.000 0.000 0.000 N -0.43839318333 -0.00054206762 -2.12229806799 0.000 0.000 -0.000 C -1.76408906064 -0.00030645034 -2.37697009192 -0.000 0.000 0.000 C -2.24773885821 -0.00257631963 -3.67934971086 0.000 -0.001 -0.000 C -1.33713102227 -0.00526459193 -4.73855802198 0.000 0.002 0.000 C 0.02654101484 -0.00591797621 -4.46472703619 -0.000 -0.001 0.000 C 0.43371721952 -0.00363389350 -3.13225443930 -0.000 0.000 -0.000 S -6.53329279136 0.00637481657 -0.11611178087 -0.000 -0.000 -0.000 N 2.00981687167 0.00259443239 -0.00000686048 0.000 0.000 -0.000 C 2.67119656792 1.17263645248 0.00045766926 -0.000 -0.000 -0.000 C 4.06129317470 1.20536051565 0.00241240325 0.001 -0.000 0.000 C 4.76783866331 0.00148799420 0.00346798881 -0.000 0.000 -0.000 C 4.05723810074 -1.20352939940 0.00211502115 -0.001 -0.000 -0.000 C 2.67108506586 -1.17139122066 0.00026591651 0.000 -0.000 0.001 C 1.82209539371 2.39842937406 -0.00175320633 -0.000 0.000 0.000 C 2.33938959521 3.68993217240 -0.00584554905 0.001 0.001 -0.000 C 1.45736908622 4.77231118002 -0.00917967851 -0.001 -0.001 0.000 C 0.08658913130 4.53522926787 -0.00833235387 0.000 -0.001 0.000 C -0.35359617412 3.21325694137 -0.00400174376 0.002 0.001 -0.001 N 0.49290585413 2.18198449515 -0.00068475564 -0.001 -0.001 0.000 S 6.56718562933 -0.11349126889 0.00673479967 0.000 0.000 0.000 C 1.82142022278 -2.39594383179 -0.00206827421 0.000 0.000 -0.000 C 2.33969079820 -3.68709653410 -0.00625612120 -0.001 0.001 0.004 C 1.45789786198 -4.76953179608 -0.00945089783 0.001 -0.001 -0.007 C 0.08684213972 -4.53272927032 -0.00840538011 -0.001 -0.001 0.005 C -0.35393854068 -3.21111942258 -0.00398541364 -0.002 0.001 -0.001 N 0.49225266031 -2.17934076887 -0.00084210065 0.001 -0.001 -0.000 H 1.83694111827 5.77332096953 -0.01265611066 -0.002 -0.000 -0.000 H -0.61802819388 5.33967450634 -0.01131742088 0.000 -0.000 -0.000 H 3.39175422949 3.87200638269 -0.00704552340 0.000 0.001 0.000 H -1.39787683933 2.98334799634 -0.00369736757 0.000 0.001 0.002 H 1.83794742242 -5.77033326187 -0.01295832570 0.002 -0.000 0.011 H -0.61749414542 -5.33746053721 -0.01121572048 -0.000 -0.000 -0.007 H -1.39833026435 -2.98175334118 -0.00345676225 -0.000 0.001 0.001 H 3.39230213722 -3.86796714602 -0.00754158092 -0.000 0.001 -0.006 H 4.58301895157 2.13678100538 0.00314824260 0.000 -0.000 -0.000 H 4.58784714512 -2.12983634010 0.00211631073 -0.000 -0.000 -0.000 H -1.68997263563 -0.00719388386 -5.74925805817 0.000 -0.002 -0.000 H 0.75224758084 -0.00860493512 -5.25016290812 -0.000 0.001 0.000 H -3.29620044300 -0.00255800648 -3.88456579214 0.000 0.001 -0.000 H 1.47161249279 -0.00457826661 -2.87685200854 0.000 -0.000 -0.000 H -1.69176120521 -0.00597000955 5.75026973076 -0.001 -0.628 -0.001 H 0.75025791005 -0.00892914887 5.25161119224 0.000 0.418 0.001 H 1.46975366817 -0.00523069331 2.87805400798 -0.000 -0.165 0.000 H -3.29750276746 -0.00099200484 3.88584245085 0.000 0.316 0.002 H -4.55513299541 0.00377930937 -2.13473279421 -0.000 -0.001 -0.000 H -4.55107479454 0.00501307822 2.13844314827 0.000 0.025 0.000 H -6.83436893102 0.00806057203 1.19721860356 0.000 0.001 0.000 H 6.86748209639 1.20005966818 0.00372860376 0.000 -0.000 0.000 61 Mode 109: freq=1165.12 N -0.44003451495 -0.00038510790 2.12369783068 0.000 0.000 0.000 C -1.76594470239 0.00039861437 2.37754210613 -0.000 -0.000 -0.000 C -2.24923313135 -0.00145267054 3.67997125809 0.000 0.001 0.000 C -1.33887502024 -0.00450793845 4.73956848945 0.000 -0.001 0.000 C 0.02462671625 -0.00591801736 4.46614405978 -0.000 0.001 -0.000 C 0.43187566201 -0.00376957955 3.13352499014 0.000 -0.001 0.000 C -2.63984642995 0.00218980399 1.17162612704 -0.000 -0.001 -0.000 N -1.98513620489 0.00132140951 0.00153900685 0.000 0.003 -0.000 C -2.63911589169 0.00167522827 -1.17277445342 -0.000 -0.006 0.000 C -4.02452897564 0.00329996303 -1.20791476641 0.000 -0.010 -0.000 C -4.73391255267 0.00451580118 -0.00020876193 0.000 0.001 -0.000 C -4.02924140493 0.00399189729 1.20660077672 -0.000 0.003 0.000 Co 0.00000000000 0.00000000000 0.00000000000 -0.000 0.000 -0.000 N -0.43839318333 -0.00054206762 -2.12229806799 0.001 0.010 0.001 C -1.76408906064 -0.00030645034 -2.37697009192 -0.000 0.008 0.000 C -2.24773885821 -0.00257631963 -3.67934971086 -0.000 -0.220 -0.000 C -1.33713102227 -0.00526459193 -4.73855802198 0.001 0.404 -0.000 C 0.02654101484 -0.00591797621 -4.46472703619 -0.001 -0.284 0.000 C 0.43371721952 -0.00363389350 -3.13225443930 -0.000 0.100 -0.001 S -6.53329279136 0.00637481657 -0.11611178087 -0.000 -0.000 0.000 N 2.00981687167 0.00259443239 -0.00000686048 0.000 0.000 -0.000 C 2.67119656792 1.17263645248 0.00045766926 -0.000 -0.000 0.000 C 4.06129317470 1.20536051565 0.00241240325 0.001 -0.000 -0.000 C 4.76783866331 0.00148799420 0.00346798881 0.000 0.000 0.000 C 4.05723810074 -1.20352939940 0.00211502115 -0.001 -0.000 0.000 C 2.67108506586 -1.17139122066 0.00026591651 0.000 -0.000 -0.000 C 1.82209539371 2.39842937406 -0.00175320633 -0.000 0.000 -0.000 C 2.33938959521 3.68993217240 -0.00584554905 0.001 0.001 0.001 C 1.45736908622 4.77231118002 -0.00917967851 -0.001 -0.002 -0.001 C 0.08658913130 4.53522926787 -0.00833235387 0.000 -0.001 0.000 C -0.35359617412 3.21325694137 -0.00400174376 0.002 0.001 0.001 N 0.49290585413 2.18198449515 -0.00068475564 -0.001 -0.001 -0.000 S 6.56718562933 -0.11349126889 0.00673479967 -0.000 0.000 -0.000 C 1.82142022278 -2.39594383179 -0.00206827421 0.000 0.000 0.000 C 2.33969079820 -3.68709653410 -0.00625612120 -0.001 0.001 -0.001 C 1.45789786198 -4.76953179608 -0.00945089783 0.001 -0.001 0.003 C 0.08684213972 -4.53272927032 -0.00840538011 -0.001 -0.001 -0.001 C -0.35393854068 -3.21111942258 -0.00398541364 -0.002 0.001 -0.000 N 0.49225266031 -2.17934076887 -0.00084210065 0.001 -0.001 0.000 H 1.83694111827 5.77332096953 -0.01265611066 -0.002 -0.000 0.001 H -0.61802819388 5.33967450634 -0.01131742088 0.000 -0.000 -0.000 H 3.39175422949 3.87200638269 -0.00704552340 0.000 0.001 -0.001 H -1.39787683933 2.98334799634 -0.00369736757 0.000 0.002 -0.001 H 1.83794742242 -5.77033326187 -0.01295832570 0.001 -0.000 -0.004 H -0.61749414542 -5.33746053721 -0.01121572048 -0.000 -0.000 0.002 H -1.39833026435 -2.98175334118 -0.00345676225 -0.000 0.001 0.001 H 3.39230213722 -3.86796714602 -0.00754158092 -0.000 0.001 0.002 H 4.58301895157 2.13678100538 0.00314824260 0.000 -0.000 0.000 H 4.58784714512 -2.12983634010 0.00211631073 -0.000 -0.000 -0.000 H -1.68997263563 -0.00719388386 -5.74925805817 -0.000 -0.629 0.002 H 0.75224758084 -0.00860493512 -5.25016290812 -0.000 0.413 -0.001 H -3.29620044300 -0.00255800648 -3.88456579214 0.000 0.324 -0.002 H 1.47161249279 -0.00457826661 -2.87685200854 -0.000 -0.160 -0.000 H -1.69176120521 -0.00597000955 5.75026973076 0.000 0.002 0.000 H 0.75025791005 -0.00892914887 5.25161119224 -0.000 -0.002 -0.000 H 1.46975366817 -0.00523069331 2.87805400798 0.000 0.001 0.000 H -3.29750276746 -0.00099200484 3.88584245085 0.000 -0.001 0.000 H -4.55513299541 0.00377930937 -2.13473279421 0.000 0.028 -0.000 H -4.55107479454 0.00501307822 2.13844314827 0.000 -0.001 0.000 H -6.83436893102 0.00806057203 1.19721860356 -0.000 -0.001 -0.000 H 6.86748209639 1.20005966818 0.00372860376 0.000 -0.000 -0.000 61 Mode 110: freq=1194.78 N -0.44003451495 -0.00038510790 2.12369783068 0.045 -0.000 0.001 C -1.76594470239 0.00039861437 2.37754210613 -0.230 0.001 -0.195 C -2.24923313135 -0.00145267054 3.67997125809 0.119 -0.000 0.070 C -1.33887502024 -0.00450793845 4.73956848945 0.048 -0.001 0.043 C 0.02462671625 -0.00591801736 4.46614405978 -0.191 0.001 -0.062 C 0.43187566201 -0.00376957955 3.13352499014 0.176 -0.000 0.026 C -2.63984642995 0.00218980399 1.17162612704 -0.121 0.000 -0.228 N -1.98513620489 0.00132140951 0.00153900685 -0.056 0.000 -0.005 C -2.63911589169 0.00167522827 -1.17277445342 -0.094 0.000 0.239 C -4.02452897564 0.00329996303 -1.20791476641 0.051 -0.000 -0.113 C -4.73391255267 0.00451580118 -0.00020876193 0.157 -0.000 -0.009 C -4.02924140493 0.00399189729 1.20660077672 0.070 -0.000 0.115 Co 0.00000000000 0.00000000000 0.00000000000 0.003 0.000 -0.000 N -0.43839318333 -0.00054206762 -2.12229806799 0.051 -0.000 -0.011 C -1.76408906064 -0.00030645034 -2.37697009192 -0.217 0.001 0.191 C -2.24773885821 -0.00257631963 -3.67934971086 0.098 -0.000 -0.062 C -1.33713102227 -0.00526459193 -4.73855802198 0.056 -0.001 -0.047 C 0.02654101484 -0.00591797621 -4.46472703619 -0.182 0.001 0.066 C 0.43371721952 -0.00363389350 -3.13225443930 0.153 -0.000 -0.029 S -6.53329279136 0.00637481657 -0.11611178087 -0.033 0.000 0.001 N 2.00981687167 0.00259443239 -0.00000686048 -0.028 0.003 -0.000 C 2.67119656792 1.17263645248 0.00045766926 -0.057 0.105 -0.000 C 4.06129317470 1.20536051565 0.00241240325 0.033 -0.052 0.000 C 4.76783866331 0.00148799420 0.00346798881 0.073 0.004 0.000 C 4.05723810074 -1.20352939940 0.00211502115 0.024 0.051 0.000 C 2.67108506586 -1.17139122066 0.00026591651 -0.044 -0.111 -0.000 C 1.82209539371 2.39842937406 -0.00175320633 -0.102 0.093 -0.000 C 2.33938959521 3.68993217240 -0.00584554905 0.059 -0.041 0.000 C 1.45736908622 4.77231118002 -0.00917967851 0.023 -0.013 0.000 C 0.08658913130 4.53522926787 -0.00833235387 -0.092 0.033 -0.000 C -0.35359617412 3.21325694137 -0.00400174376 0.082 -0.020 0.000 N 0.49290585413 2.18198449515 -0.00068475564 0.017 0.003 0.000 S 6.56718562933 -0.11349126889 0.00673479967 -0.015 -0.001 -0.000 C 1.82142022278 -2.39594383179 -0.00206827421 -0.096 -0.091 -0.000 C 2.33969079820 -3.68709653410 -0.00625612120 0.049 0.037 0.000 C 1.45789786198 -4.76953179608 -0.00945089783 0.027 0.015 0.000 C 0.08684213972 -4.53272927032 -0.00840538011 -0.088 -0.034 -0.000 C -0.35393854068 -3.21111942258 -0.00398541364 0.071 0.021 0.000 N 0.49225266031 -2.17934076887 -0.00084210065 0.021 0.001 0.000 H 1.83694111827 5.77332096953 -0.01265611066 0.034 -0.013 -0.000 H -0.61802819388 5.33967450634 -0.01131742088 -0.082 -0.037 0.000 H 3.39175422949 3.87200638269 -0.00704552340 0.034 -0.115 0.000 H -1.39787683933 2.98334799634 -0.00369736757 0.034 -0.044 -0.000 H 1.83794742242 -5.77033326187 -0.01295832570 0.039 0.015 -0.000 H -0.61749414542 -5.33746053721 -0.01121572048 -0.073 0.030 0.000 H -1.39833026435 -2.98175334118 -0.00345676225 0.031 0.045 -0.000 H 3.39230213722 -3.86796714602 -0.00754158092 0.030 0.107 0.000 H 4.58301895157 2.13678100538 0.00314824260 0.070 -0.048 0.000 H 4.58784714512 -2.12983634010 0.00211631073 0.063 0.046 0.000 H -1.68997263563 -0.00719388386 -5.74925805817 0.082 0.000 -0.035 H 0.75224758084 -0.00860493512 -5.25016290812 -0.143 -0.000 -0.059 H -3.29620044300 -0.00255800648 -3.88456579214 0.065 -0.001 -0.214 H 1.47161249279 -0.00457826661 -2.87685200854 0.068 0.000 -0.090 H -1.69176120521 -0.00597000955 5.75026973076 0.069 0.000 0.030 H 0.75025791005 -0.00892914887 5.25161119224 -0.162 -0.000 0.075 H 1.46975366817 -0.00523069331 2.87805400798 0.075 0.000 0.087 H -3.29750276746 -0.00099200484 3.88584245085 0.074 -0.001 0.232 H -4.55513299541 0.00377930937 -2.13473279421 0.135 -0.000 -0.099 H -4.55107479454 0.00501307822 2.13844314827 0.151 -0.000 0.104 H -6.83436893102 0.00806057203 1.19721860356 -0.023 0.000 -0.003 H 6.86748209639 1.20005966818 0.00372860376 -0.011 0.001 -0.000 61 Mode 111: freq=1195.41 N -0.44003451495 -0.00038510790 2.12369783068 -0.023 -0.000 -0.005 C -1.76594470239 0.00039861437 2.37754210613 0.109 -0.000 0.102 C -2.24923313135 -0.00145267054 3.67997125809 -0.045 -0.000 -0.029 C -1.33887502024 -0.00450793845 4.73956848945 -0.019 0.000 -0.032 C 0.02462671625 -0.00591801736 4.46614405978 0.082 -0.000 0.032 C 0.43187566201 -0.00376957955 3.13352499014 -0.085 0.000 -0.011 C -2.63984642995 0.00218980399 1.17162612704 0.058 -0.000 0.116 N -1.98513620489 0.00132140951 0.00153900685 0.026 0.000 0.003 C -2.63911589169 0.00167522827 -1.17277445342 0.046 -0.000 -0.122 C -4.02452897564 0.00329996303 -1.20791476641 -0.022 0.000 0.059 C -4.73391255267 0.00451580118 -0.00020876193 -0.078 0.000 0.004 C -4.02924140493 0.00399189729 1.20660077672 -0.031 0.000 -0.061 Co 0.00000000000 0.00000000000 0.00000000000 -0.001 0.000 0.000 N -0.43839318333 -0.00054206762 -2.12229806799 -0.027 -0.000 0.010 C -1.76408906064 -0.00030645034 -2.37697009192 0.102 -0.000 -0.100 C -2.24773885821 -0.00257631963 -3.67934971086 -0.035 -0.000 0.025 C -1.33713102227 -0.00526459193 -4.73855802198 -0.024 0.000 0.034 C 0.02654101484 -0.00591797621 -4.46472703619 0.077 -0.000 -0.034 C 0.43371721952 -0.00363389350 -3.13225443930 -0.073 0.000 0.012 S -6.53329279136 0.00637481657 -0.11611178087 0.016 -0.000 -0.001 N 2.00981687167 0.00259443239 -0.00000686048 -0.044 0.006 0.000 C 2.67119656792 1.17263645248 0.00045766926 -0.118 0.242 -0.000 C 4.06129317470 1.20536051565 0.00241240325 0.061 -0.137 0.000 C 4.76783866331 0.00148799420 0.00346798881 0.151 0.009 0.000 C 4.05723810074 -1.20352939940 0.00211502115 0.042 0.134 0.000 C 2.67108506586 -1.17139122066 0.00026591651 -0.092 -0.255 -0.000 C 1.82209539371 2.39842937406 -0.00175320633 -0.210 0.217 -0.001 C 2.33938959521 3.68993217240 -0.00584554905 0.092 -0.080 0.000 C 1.45736908622 4.77231118002 -0.00917967851 0.043 -0.049 0.000 C 0.08658913130 4.53522926787 -0.00833235387 -0.173 0.073 -0.000 C -0.35359617412 3.21325694137 -0.00400174376 0.168 -0.042 0.000 N 0.49290585413 2.18198449515 -0.00068475564 0.047 0.005 -0.000 S 6.56718562933 -0.11349126889 0.00673479967 -0.031 -0.001 -0.000 C 1.82142022278 -2.39594383179 -0.00206827421 -0.198 -0.214 -0.001 C 2.33969079820 -3.68709653410 -0.00625612120 0.072 0.070 0.000 C 1.45789786198 -4.76953179608 -0.00945089783 0.053 0.054 0.000 C 0.08684213972 -4.53272927032 -0.00840538011 -0.164 -0.076 -0.000 C -0.35393854068 -3.21111942258 -0.00398541364 0.144 0.044 0.000 N 0.49225266031 -2.17934076887 -0.00084210065 0.055 0.005 -0.000 H 1.83694111827 5.77332096953 -0.01265611066 0.078 -0.037 -0.000 H -0.61802819388 5.33967450634 -0.01131742088 -0.148 -0.060 0.000 H 3.39175422949 3.87200638269 -0.00704552340 0.060 -0.233 0.001 H -1.39787683933 2.98334799634 -0.00369736757 0.072 -0.099 0.000 H 1.83794742242 -5.77033326187 -0.01295832570 0.091 0.043 -0.000 H -0.61749414542 -5.33746053721 -0.01121572048 -0.129 0.045 0.000 H -1.39833026435 -2.98175334118 -0.00345676225 0.065 0.102 0.000 H 3.39230213722 -3.86796714602 -0.00754158092 0.051 0.216 0.001 H 4.58301895157 2.13678100538 0.00314824260 0.153 -0.113 0.000 H 4.58784714512 -2.12983634010 0.00211631073 0.137 0.108 0.000 H -1.68997263563 -0.00719388386 -5.74925805817 -0.041 -0.000 0.022 H 0.75224758084 -0.00860493512 -5.25016290812 0.057 0.000 0.020 H -3.29620044300 -0.00255800648 -3.88456579214 -0.026 0.000 0.094 H 1.47161249279 -0.00457826661 -2.87685200854 -0.033 0.000 0.045 H -1.69176120521 -0.00597000955 5.75026973076 -0.035 -0.000 -0.019 H 0.75025791005 -0.00892914887 5.25161119224 0.066 0.000 -0.028 H 1.46975366817 -0.00523069331 2.87805400798 -0.037 0.000 -0.043 H -3.29750276746 -0.00099200484 3.88584245085 -0.030 0.000 -0.103 H -4.55513299541 0.00377930937 -2.13473279421 -0.064 0.000 0.049 H -4.55107479454 0.00501307822 2.13844314827 -0.072 0.000 -0.052 H -6.83436893102 0.00806057203 1.19721860356 0.011 -0.000 0.001 H 6.86748209639 1.20005966818 0.00372860376 -0.021 0.002 -0.000 61 Mode 112: freq=1214.56 N -0.44003451495 -0.00038510790 2.12369783068 -0.001 0.003 -0.002 C -1.76594470239 0.00039861437 2.37754210613 -0.002 -0.001 0.001 C -2.24923313135 -0.00145267054 3.67997125809 0.003 0.000 0.001 C -1.33887502024 -0.00450793845 4.73956848945 -0.000 0.000 -0.001 C 0.02462671625 -0.00591801736 4.46614405978 -0.002 -0.001 0.001 C 0.43187566201 -0.00376957955 3.13352499014 0.002 0.001 -0.001 C -2.63984642995 0.00218980399 1.17162612704 -0.001 0.002 0.001 N -1.98513620489 0.00132140951 0.00153900685 0.000 -0.003 0.000 C -2.63911589169 0.00167522827 -1.17277445342 0.001 0.002 -0.000 C -4.02452897564 0.00329996303 -1.20791476641 -0.001 -0.001 0.000 C -4.73391255267 0.00451580118 -0.00020876193 0.000 0.000 -0.000 C -4.02924140493 0.00399189729 1.20660077672 0.001 -0.001 -0.001 Co 0.00000000000 0.00000000000 0.00000000000 0.001 0.001 0.000 N -0.43839318333 -0.00054206762 -2.12229806799 0.001 0.003 -0.001 C -1.76408906064 -0.00030645034 -2.37697009192 0.002 -0.001 -0.001 C -2.24773885821 -0.00257631963 -3.67934971086 -0.002 0.000 0.001 C -1.33713102227 -0.00526459193 -4.73855802198 0.001 0.000 -0.000 C 0.02654101484 -0.00591797621 -4.46472703619 0.001 -0.001 0.001 C 0.43371721952 -0.00363389350 -3.13225443930 -0.003 0.001 -0.001 S -6.53329279136 0.00637481657 -0.11611178087 0.000 0.000 -0.000 N 2.00981687167 0.00259443239 -0.00000686048 -0.016 0.008 -0.000 C 2.67119656792 1.17263645248 0.00045766926 0.113 0.046 0.000 C 4.06129317470 1.20536051565 0.00241240325 -0.110 -0.018 -0.000 C 4.76783866331 0.00148799420 0.00346798881 0.001 -0.047 0.000 C 4.05723810074 -1.20352939940 0.00211502115 0.128 -0.004 0.000 C 2.67108506586 -1.17139122066 0.00026591651 -0.115 0.023 -0.000 C 1.82209539371 2.39842937406 -0.00175320633 0.161 0.001 -0.000 C 2.33938959521 3.68993217240 -0.00584554905 -0.221 0.109 -0.000 C 1.45736908622 4.77231118002 -0.00917967851 0.042 -0.080 -0.000 C 0.08658913130 4.53522926787 -0.00833235387 0.140 0.091 -0.000 C -0.35359617412 3.21325694137 -0.00400174376 -0.232 -0.068 0.000 N 0.49290585413 2.18198449515 -0.00068475564 0.068 -0.150 0.000 S 6.56718562933 -0.11349126889 0.00673479967 -0.003 -0.005 -0.000 C 1.82142022278 -2.39594383179 -0.00206827421 -0.178 -0.022 0.000 C 2.33969079820 -3.68709653410 -0.00625612120 0.231 0.123 0.000 C 1.45789786198 -4.76953179608 -0.00945089783 -0.045 -0.078 0.000 C 0.08684213972 -4.53272927032 -0.00840538011 -0.151 0.087 0.000 C -0.35393854068 -3.21111942258 -0.00398541364 0.254 -0.062 -0.000 N 0.49225266031 -2.17934076887 -0.00084210065 -0.073 -0.158 -0.000 H 1.83694111827 5.77332096953 -0.01265611066 0.125 -0.071 0.001 H -0.61802819388 5.33967450634 -0.01131742088 0.279 0.236 -0.001 H 3.39175422949 3.87200638269 -0.00704552340 -0.098 0.214 -0.001 H -1.39787683933 2.98334799634 -0.00369736757 -0.066 -0.058 0.000 H 1.83794742242 -5.77033326187 -0.01295832570 -0.125 -0.070 -0.001 H -0.61749414542 -5.33746053721 -0.01121572048 -0.296 0.247 0.001 H -1.39833026435 -2.98175334118 -0.00345676225 0.073 -0.053 -0.001 H 3.39230213722 -3.86796714602 -0.00754158092 0.105 0.243 0.001 H 4.58301895157 2.13678100538 0.00314824260 -0.100 0.031 0.000 H 4.58784714512 -2.12983634010 0.00211631073 0.129 0.049 0.000 H -1.68997263563 -0.00719388386 -5.74925805817 0.001 -0.000 -0.000 H 0.75224758084 -0.00860493512 -5.25016290812 0.002 0.001 0.002 H -3.29620044300 -0.00255800648 -3.88456579214 -0.001 -0.000 0.002 H 1.47161249279 -0.00457826661 -2.87685200854 -0.001 -0.003 -0.000 H -1.69176120521 -0.00597000955 5.75026973076 -0.001 -0.000 -0.001 H 0.75025791005 -0.00892914887 5.25161119224 -0.003 0.001 0.003 H 1.46975366817 -0.00523069331 2.87805400798 0.001 -0.003 -0.001 H -3.29750276746 -0.00099200484 3.88584245085 0.001 -0.000 0.003 H -4.55513299541 0.00377930937 -2.13473279421 -0.002 0.000 0.001 H -4.55107479454 0.00501307822 2.13844314827 0.001 0.000 0.000 H -6.83436893102 0.00806057203 1.19721860356 -0.000 -0.000 -0.000 H 6.86748209639 1.20005966818 0.00372860376 0.004 -0.002 0.000 61 Mode 113: freq=1214.77 N -0.44003451495 -0.00038510790 2.12369783068 0.063 -0.000 0.149 C -1.76594470239 0.00039861437 2.37754210613 0.171 -0.000 0.001 C -2.24923313135 -0.00145267054 3.67997125809 -0.217 0.000 -0.099 C -1.33887502024 -0.00450793845 4.73956848945 0.044 0.000 0.073 C 0.02462671625 -0.00591801736 4.46614405978 0.137 -0.000 -0.099 C 0.43187566201 -0.00376957955 3.13352499014 -0.231 0.000 0.080 C -2.63984642995 0.00218980399 1.17162612704 0.109 -0.000 -0.046 N -1.98513620489 0.00132140951 0.00153900685 -0.018 -0.000 -0.018 C -2.63911589169 0.00167522827 -1.17277445342 -0.113 0.000 -0.024 C -4.02452897564 0.00329996303 -1.20791476641 0.131 -0.000 0.007 C -4.73391255267 0.00451580118 -0.00020876193 0.001 0.000 0.043 C -4.02924140493 0.00399189729 1.20660077672 -0.112 0.000 0.018 Co 0.00000000000 0.00000000000 0.00000000000 0.001 0.000 -0.003 N -0.43839318333 -0.00054206762 -2.12229806799 -0.067 0.000 0.156 C -1.76408906064 -0.00030645034 -2.37697009192 -0.190 0.000 0.022 C -2.24773885821 -0.00257631963 -3.67934971086 0.230 -0.000 -0.111 C -1.33713102227 -0.00526459193 -4.73855802198 -0.046 -0.000 0.070 C 0.02654101484 -0.00591797621 -4.46472703619 -0.150 0.000 -0.096 C 0.43371721952 -0.00363389350 -3.13225443930 0.254 -0.000 0.078 S -6.53329279136 0.00637481657 -0.11611178087 -0.002 0.000 0.006 N 2.00981687167 0.00259443239 -0.00000686048 -0.000 0.000 0.003 C 2.67119656792 1.17263645248 0.00045766926 0.001 -0.001 -0.002 C 4.06129317470 1.20536051565 0.00241240325 -0.001 0.001 0.001 C 4.76783866331 0.00148799420 0.00346798881 0.000 -0.001 -0.000 C 4.05723810074 -1.20352939940 0.00211502115 0.001 -0.001 0.001 C 2.67108506586 -1.17139122066 0.00026591651 -0.001 0.001 -0.002 C 1.82209539371 2.39842937406 -0.00175320633 0.002 -0.001 0.001 C 2.33938959521 3.68993217240 -0.00584554905 -0.001 0.001 -0.000 C 1.45736908622 4.77231118002 -0.00917967851 0.000 0.000 -0.000 C 0.08658913130 4.53522926787 -0.00833235387 0.001 0.000 0.001 C -0.35359617412 3.21325694137 -0.00400174376 -0.002 -0.000 -0.000 N 0.49290585413 2.18198449515 -0.00068475564 0.000 -0.001 -0.003 S 6.56718562933 -0.11349126889 0.00673479967 -0.000 -0.000 -0.000 C 1.82142022278 -2.39594383179 -0.00206827421 -0.002 0.001 0.001 C 2.33969079820 -3.68709653410 -0.00625612120 0.004 0.002 -0.000 C 1.45789786198 -4.76953179608 -0.00945089783 -0.000 -0.002 -0.000 C 0.08684213972 -4.53272927032 -0.00840538011 -0.002 0.001 0.001 C -0.35393854068 -3.21111942258 -0.00398541364 0.003 -0.001 -0.000 N 0.49225266031 -2.17934076887 -0.00084210065 -0.001 -0.002 -0.003 H 1.83694111827 5.77332096953 -0.01265611066 0.001 -0.000 0.000 H -0.61802819388 5.33967450634 -0.01131742088 0.002 0.001 -0.001 H 3.39175422949 3.87200638269 -0.00704552340 -0.001 0.002 0.000 H -1.39787683933 2.98334799634 -0.00369736757 -0.001 0.000 0.002 H 1.83794742242 -5.77033326187 -0.01295832570 -0.002 -0.001 0.000 H -0.61749414542 -5.33746053721 -0.01121572048 -0.004 0.004 -0.001 H -1.39833026435 -2.98175334118 -0.00345676225 0.001 -0.001 0.003 H 3.39230213722 -3.86796714602 -0.00754158092 0.001 0.003 0.000 H 4.58301895157 2.13678100538 0.00314824260 -0.002 0.001 -0.000 H 4.58784714512 -2.12983634010 0.00211631073 0.001 -0.000 -0.000 H -1.68997263563 -0.00719388386 -5.74925805817 -0.131 0.001 0.066 H 0.75224758084 -0.00860493512 -5.25016290812 -0.284 -0.001 -0.252 H -3.29620044300 -0.00255800648 -3.88456579214 0.111 -0.001 -0.245 H 1.47161249279 -0.00457826661 -2.87685200854 0.073 0.000 0.056 H -1.69176120521 -0.00597000955 5.75026973076 0.130 -0.001 0.067 H 0.75025791005 -0.00892914887 5.25161119224 0.266 0.000 -0.239 H 1.46975366817 -0.00523069331 2.87805400798 -0.065 -0.000 0.060 H -3.29750276746 -0.00099200484 3.88584245085 -0.103 0.001 -0.217 H -4.55513299541 0.00377930937 -2.13473279421 0.131 -0.000 -0.048 H -4.55107479454 0.00501307822 2.13844314827 -0.101 0.000 -0.032 H -6.83436893102 0.00806057203 1.19721860356 0.001 -0.000 0.002 H 6.86748209639 1.20005966818 0.00372860376 -0.000 -0.000 0.000 61 Mode 114: freq=1228.24 N -0.44003451495 -0.00038510790 2.12369783068 0.034 -0.000 0.081 C -1.76594470239 0.00039861437 2.37754210613 0.015 0.000 -0.060 C -2.24923313135 -0.00145267054 3.67997125809 -0.077 0.000 -0.045 C -1.33887502024 -0.00450793845 4.73956848945 0.020 -0.000 0.062 C 0.02462671625 -0.00591801736 4.46614405978 0.032 0.000 -0.067 C 0.43187566201 -0.00376957955 3.13352499014 -0.052 0.000 0.047 C -2.63984642995 0.00218980399 1.17162612704 -0.010 -0.000 -0.047 N -1.98513620489 0.00132140951 0.00153900685 -0.008 -0.000 -0.004 C -2.63911589169 0.00167522827 -1.17277445342 -0.007 -0.000 0.050 C -4.02452897564 0.00329996303 -1.20791476641 -0.009 0.000 -0.021 C -4.73391255267 0.00451580118 -0.00020876193 0.028 -0.000 -0.003 C -4.02924140493 0.00399189729 1.20660077672 -0.009 0.000 0.025 Co 0.00000000000 0.00000000000 0.00000000000 0.004 0.000 0.000 N -0.43839318333 -0.00054206762 -2.12229806799 0.037 -0.000 -0.083 C -1.76408906064 -0.00030645034 -2.37697009192 0.010 0.000 0.060 C -2.24773885821 -0.00257631963 -3.67934971086 -0.076 0.000 0.049 C -1.33713102227 -0.00526459193 -4.73855802198 0.024 -0.000 -0.064 C 0.02654101484 -0.00591797621 -4.46472703619 0.027 0.000 0.065 C 0.43371721952 -0.00363389350 -3.13225443930 -0.052 0.000 -0.042 S -6.53329279136 0.00637481657 -0.11611178087 -0.004 0.000 0.000 N 2.00981687167 0.00259443239 -0.00000686048 0.019 -0.011 -0.000 C 2.67119656792 1.17263645248 0.00045766926 0.027 -0.121 -0.000 C 4.06129317470 1.20536051565 0.00241240325 0.017 0.069 0.000 C 4.76783866331 0.00148799420 0.00346798881 -0.065 -0.009 -0.000 C 4.05723810074 -1.20352939940 0.00211502115 0.019 -0.060 0.000 C 2.67108506586 -1.17139122066 0.00026591651 0.020 0.130 -0.000 C 1.82209539371 2.39842937406 -0.00175320633 -0.035 -0.155 0.000 C 2.33938959521 3.68993217240 -0.00584554905 0.194 -0.105 0.000 C 1.45736908622 4.77231118002 -0.00917967851 -0.050 0.144 -0.000 C 0.08658913130 4.53522926787 -0.00833235387 -0.076 -0.148 0.000 C -0.35359617412 3.21325694137 -0.00400174376 0.133 0.109 -0.000 N 0.49290585413 2.18198449515 -0.00068475564 -0.096 0.172 -0.000 S 6.56718562933 -0.11349126889 0.00673479967 0.010 0.000 0.000 C 1.82142022278 -2.39594383179 -0.00206827421 -0.018 0.156 0.000 C 2.33969079820 -3.68709653410 -0.00625612120 0.190 0.112 0.000 C 1.45789786198 -4.76953179608 -0.00945089783 -0.061 -0.150 -0.000 C 0.08684213972 -4.53272927032 -0.00840538011 -0.061 0.142 0.000 C -0.35393854068 -3.21111942258 -0.00398541364 0.129 -0.097 -0.000 N 0.49225266031 -2.17934076887 -0.00084210065 -0.105 -0.175 -0.000 H 1.83694111827 5.77332096953 -0.01265611066 -0.178 0.110 -0.001 H -0.61802819388 5.33967450634 -0.01131742088 -0.255 -0.250 0.001 H 3.39175422949 3.87200638269 -0.00704552340 0.079 -0.137 0.001 H -1.39787683933 2.98334799634 -0.00369736757 0.021 0.130 -0.001 H 1.83794742242 -5.77033326187 -0.01295832570 -0.185 -0.113 -0.001 H -0.61749414542 -5.33746053721 -0.01121572048 -0.242 0.241 0.001 H -1.39833026435 -2.98175334118 -0.00345676225 0.020 -0.128 -0.001 H 3.39230213722 -3.86796714602 -0.00754158092 0.077 0.132 0.001 H 4.58301895157 2.13678100538 0.00314824260 0.003 0.020 -0.000 H 4.58784714512 -2.12983634010 0.00211631073 -0.000 -0.019 -0.000 H -1.68997263563 -0.00719388386 -5.74925805817 0.076 -0.000 -0.045 H 0.75224758084 -0.00860493512 -5.25016290812 0.101 0.000 0.106 H -3.29620044300 -0.00255800648 -3.88456579214 -0.034 0.000 0.067 H 1.47161249279 -0.00457826661 -2.87685200854 -0.007 -0.000 -0.052 H -1.69176120521 -0.00597000955 5.75026973076 0.074 -0.000 0.044 H 0.75025791005 -0.00892914887 5.25161119224 0.104 0.000 -0.109 H 1.46975366817 -0.00523069331 2.87805400798 -0.007 -0.000 0.053 H -3.29750276746 -0.00099200484 3.88584245085 -0.035 0.000 -0.068 H -4.55513299541 0.00377930937 -2.13473279421 -0.004 -0.000 -0.005 H -4.55107479454 0.00501307822 2.13844314827 -0.005 -0.000 0.005 H -6.83436893102 0.00806057203 1.19721860356 -0.001 -0.000 0.000 H 6.86748209639 1.20005966818 0.00372860376 0.004 -0.000 0.000 61 Mode 115: freq=1229.92 N -0.44003451495 -0.00038510790 2.12369783068 -0.113 0.000 -0.168 C -1.76594470239 0.00039861437 2.37754210613 -0.015 -0.000 0.158 C -2.24923313135 -0.00145267054 3.67997125809 0.193 -0.000 0.107 C -1.33887502024 -0.00450793845 4.73956848945 -0.073 0.000 -0.146 C 0.02462671625 -0.00591801736 4.46614405978 -0.052 -0.000 0.146 C 0.43187566201 -0.00376957955 3.13352499014 0.128 0.000 -0.109 C -2.63984642995 0.00218980399 1.17162612704 0.034 0.000 0.130 N -1.98513620489 0.00132140951 0.00153900685 0.033 -0.000 0.012 C -2.63911589169 0.00167522827 -1.17277445342 0.026 -0.000 -0.139 C -4.02452897564 0.00329996303 -1.20791476641 0.008 -0.000 0.062 C -4.73391255267 0.00451580118 -0.00020876193 -0.062 0.000 0.009 C -4.02924140493 0.00399189729 1.20660077672 0.006 -0.000 -0.072 Co 0.00000000000 0.00000000000 0.00000000000 0.015 0.000 -0.000 N -0.43839318333 -0.00054206762 -2.12229806799 -0.123 0.000 0.171 C -1.76408906064 -0.00030645034 -2.37697009192 0.003 -0.000 -0.158 C -2.24773885821 -0.00257631963 -3.67934971086 0.188 -0.000 -0.116 C -1.33713102227 -0.00526459193 -4.73855802198 -0.085 0.000 0.151 C 0.02654101484 -0.00591797621 -4.46472703619 -0.037 -0.000 -0.138 C 0.43371721952 -0.00363389350 -3.13225443930 0.124 0.000 0.095 S -6.53329279136 0.00637481657 -0.11611178087 0.010 -0.000 -0.001 N 2.00981687167 0.00259443239 -0.00000686048 0.012 -0.005 0.000 C 2.67119656792 1.17263645248 0.00045766926 0.012 -0.060 -0.000 C 4.06129317470 1.20536051565 0.00241240325 0.001 0.043 -0.000 C 4.76783866331 0.00148799420 0.00346798881 -0.010 -0.004 0.000 C 4.05723810074 -1.20352939940 0.00211502115 0.002 -0.039 -0.000 C 2.67108506586 -1.17139122066 0.00026591651 0.008 0.064 -0.000 C 1.82209539371 2.39842937406 -0.00175320633 -0.013 -0.072 0.000 C 2.33938959521 3.68993217240 -0.00584554905 0.086 -0.040 0.000 C 1.45736908622 4.77231118002 -0.00917967851 -0.025 0.058 -0.000 C 0.08658913130 4.53522926787 -0.00833235387 -0.028 -0.059 0.000 C -0.35359617412 3.21325694137 -0.00400174376 0.056 0.048 -0.000 N 0.49290585413 2.18198449515 -0.00068475564 -0.049 0.061 -0.000 S 6.56718562933 -0.11349126889 0.00673479967 0.002 0.000 0.000 C 1.82142022278 -2.39594383179 -0.00206827421 -0.005 0.073 0.000 C 2.33969079820 -3.68709653410 -0.00625612120 0.085 0.043 0.000 C 1.45789786198 -4.76953179608 -0.00945089783 -0.030 -0.061 -0.000 C 0.08684213972 -4.53272927032 -0.00840538011 -0.022 0.056 0.000 C -0.35393854068 -3.21111942258 -0.00398541364 0.055 -0.043 -0.000 N 0.49225266031 -2.17934076887 -0.00084210065 -0.053 -0.063 -0.000 H 1.83694111827 5.77332096953 -0.01265611066 -0.079 0.047 -0.000 H -0.61802819388 5.33967450634 -0.01131742088 -0.103 -0.101 0.000 H 3.39175422949 3.87200638269 -0.00704552340 0.033 -0.043 0.000 H -1.39787683933 2.98334799634 -0.00369736757 0.008 0.058 -0.000 H 1.83794742242 -5.77033326187 -0.01295832570 -0.083 -0.048 -0.000 H -0.61749414542 -5.33746053721 -0.01121572048 -0.097 0.097 0.000 H -1.39833026435 -2.98175334118 -0.00345676225 0.008 -0.057 -0.000 H 3.39230213722 -3.86796714602 -0.00754158092 0.032 0.042 0.000 H 4.58301895157 2.13678100538 0.00314824260 -0.019 0.023 -0.000 H 4.58784714512 -2.12983634010 0.00211631073 -0.020 -0.023 -0.000 H -1.68997263563 -0.00719388386 -5.74925805817 -0.209 0.001 0.113 H 0.75224758084 -0.00860493512 -5.25016290812 -0.216 -0.000 -0.234 H -3.29620044300 -0.00255800648 -3.88456579214 0.078 -0.000 -0.127 H 1.47161249279 -0.00457826661 -2.87685200854 0.014 0.000 0.132 H -1.69176120521 -0.00597000955 5.75026973076 -0.202 0.001 -0.111 H 0.75025791005 -0.00892914887 5.25161119224 -0.230 -0.000 0.245 H 1.46975366817 -0.00523069331 2.87805400798 0.016 0.000 -0.136 H -3.29750276746 -0.00099200484 3.88584245085 0.081 -0.001 0.132 H -4.55513299541 0.00377930937 -2.13473279421 -0.020 0.000 0.029 H -4.55107479454 0.00501307822 2.13844314827 -0.017 0.000 -0.030 H -6.83436893102 0.00806057203 1.19721860356 0.005 0.000 0.000 H 6.86748209639 1.20005966818 0.00372860376 0.001 -0.000 -0.000 61 Mode 116: freq=1242.20 N -0.44003451495 -0.00038510790 2.12369783068 -0.079 0.000 -0.036 C -1.76594470239 0.00039861437 2.37754210613 0.112 0.000 -0.054 C -2.24923313135 -0.00145267054 3.67997125809 -0.026 -0.000 0.088 C -1.33887502024 -0.00450793845 4.73956848945 -0.116 0.000 -0.022 C 0.02462671625 -0.00591801736 4.46614405978 0.102 0.000 -0.048 C 0.43187566201 -0.00376957955 3.13352499014 0.009 -0.001 0.082 C -2.63984642995 0.00218980399 1.17162612704 0.073 -0.000 -0.081 N -1.98513620489 0.00132140951 0.00153900685 -0.234 0.001 0.061 C -2.63911589169 0.00167522827 -1.17277445342 0.034 -0.000 0.044 C -4.02452897564 0.00329996303 -1.20791476641 0.112 -0.000 -0.169 C -4.73391255267 0.00451580118 -0.00020876193 -0.373 0.000 0.053 C -4.02924140493 0.00399189729 1.20660077672 0.106 -0.000 0.115 Co 0.00000000000 0.00000000000 0.00000000000 0.013 -0.001 -0.001 N -0.43839318333 -0.00054206762 -2.12229806799 -0.158 0.000 0.081 C -1.76408906064 -0.00030645034 -2.37697009192 0.222 0.000 0.054 C -2.24773885821 -0.00257631963 -3.67934971086 -0.021 -0.000 -0.176 C -1.33713102227 -0.00526459193 -4.73855802198 -0.210 0.000 0.077 C 0.02654101484 -0.00591797621 -4.46472703619 0.189 0.000 0.092 C 0.43371721952 -0.00363389350 -3.13225443930 0.011 -0.001 -0.169 S -6.53329279136 0.00637481657 -0.11611178087 0.055 -0.000 -0.006 N 2.00981687167 0.00259443239 -0.00000686048 0.051 0.031 0.001 C 2.67119656792 1.17263645248 0.00045766926 -0.026 -0.025 0.000 C 4.06129317470 1.20536051565 0.00241240325 -0.022 0.029 -0.000 C 4.76783866331 0.00148799420 0.00346798881 0.102 0.025 0.000 C 4.05723810074 -1.20352939940 0.00211502115 -0.026 -0.055 -0.000 C 2.67108506586 -1.17139122066 0.00026591651 -0.008 0.004 0.000 C 1.82209539371 2.39842937406 -0.00175320633 -0.025 -0.015 0.000 C 2.33938959521 3.68993217240 -0.00584554905 0.006 0.021 -0.000 C 1.45736908622 4.77231118002 -0.00917967851 0.030 -0.004 0.000 C 0.08658913130 4.53522926787 -0.00833235387 -0.025 -0.010 0.000 C -0.35359617412 3.21325694137 -0.00400174376 -0.005 0.018 -0.000 N 0.49290585413 2.18198449515 -0.00068475564 0.020 -0.009 -0.000 S 6.56718562933 -0.11349126889 0.00673479967 -0.015 -0.003 -0.000 C 1.82142022278 -2.39594383179 -0.00206827421 -0.078 0.011 0.000 C 2.33969079820 -3.68709653410 -0.00625612120 0.001 -0.062 -0.000 C 1.45789786198 -4.76953179608 -0.00945089783 0.076 0.032 0.000 C 0.08684213972 -4.53272927032 -0.00840538011 -0.067 0.030 0.000 C -0.35393854068 -3.21111942258 -0.00398541364 -0.005 -0.059 -0.001 N 0.49225266031 -2.17934076887 -0.00084210065 0.059 0.030 0.000 H 1.83694111827 5.77332096953 -0.01265611066 0.027 -0.008 -0.000 H -0.61802819388 5.33967450634 -0.01131742088 -0.022 -0.015 0.000 H 3.39175422949 3.87200638269 -0.00704552340 -0.001 0.022 0.000 H -1.39787683933 2.98334799634 -0.00369736757 -0.000 0.002 0.001 H 1.83794742242 -5.77033326187 -0.01295832570 0.065 0.026 0.000 H -0.61749414542 -5.33746053721 -0.01121572048 -0.048 0.033 0.000 H -1.39833026435 -2.98175334118 -0.00345676225 0.001 -0.009 0.001 H 3.39230213722 -3.86796714602 -0.00754158092 -0.002 -0.029 0.000 H 4.58301895157 2.13678100538 0.00314824260 -0.079 0.050 0.000 H 4.58784714512 -2.12983634010 0.00211631073 -0.063 -0.049 0.000 H -1.68997263563 -0.00719388386 -5.74925805817 -0.171 0.000 0.059 H 0.75224758084 -0.00860493512 -5.25016290812 0.141 0.000 0.104 H -3.29620044300 -0.00255800648 -3.88456579214 0.003 -0.000 -0.095 H 1.47161249279 -0.00457826661 -2.87685200854 -0.005 0.001 -0.030 H -1.69176120521 -0.00597000955 5.75026973076 -0.094 0.000 -0.026 H 0.75025791005 -0.00892914887 5.25161119224 0.085 0.000 -0.064 H 1.46975366817 -0.00523069331 2.87805400798 -0.002 0.001 0.011 H -3.29750276746 -0.00099200484 3.88584245085 0.003 -0.000 0.077 H -4.55513299541 0.00377930937 -2.13473279421 0.267 -0.000 -0.186 H -4.55107479454 0.00501307822 2.13844314827 0.299 -0.000 0.186 H -6.83436893102 0.00806057203 1.19721860356 0.038 0.000 0.004 H 6.86748209639 1.20005966818 0.00372860376 -0.016 0.002 -0.000 61 Mode 117: freq=1243.07 N -0.44003451495 -0.00038510790 2.12369783068 0.001 0.000 0.004 C -1.76594470239 0.00039861437 2.37754210613 -0.005 0.001 0.012 C -2.24923313135 -0.00145267054 3.67997125809 0.008 -0.001 -0.005 C -1.33887502024 -0.00450793845 4.73956848945 0.008 0.000 -0.003 C 0.02462671625 -0.00591801736 4.46614405978 -0.006 0.001 0.001 C 0.43187566201 -0.00376957955 3.13352499014 -0.001 -0.001 -0.002 C -2.63984642995 0.00218980399 1.17162612704 -0.020 -0.000 0.023 N -1.98513620489 0.00132140951 0.00153900685 0.055 0.004 -0.032 C -2.63911589169 0.00167522827 -1.17277445342 -0.003 -0.000 -0.004 C -4.02452897564 0.00329996303 -1.20791476641 -0.027 -0.001 0.044 C -4.73391255267 0.00451580118 -0.00020876193 0.083 0.000 -0.026 C -4.02924140493 0.00399189729 1.20660077672 -0.025 -0.001 -0.017 Co 0.00000000000 0.00000000000 0.00000000000 -0.008 -0.005 0.001 N -0.43839318333 -0.00054206762 -2.12229806799 0.045 0.000 -0.031 C -1.76408906064 -0.00030645034 -2.37697009192 -0.064 0.001 -0.010 C -2.24773885821 -0.00257631963 -3.67934971086 0.002 -0.001 0.055 C -1.33713102227 -0.00526459193 -4.73855802198 0.059 0.000 -0.028 C 0.02654101484 -0.00591797621 -4.46472703619 -0.052 0.001 -0.022 C 0.43371721952 -0.00363389350 -3.13225443930 -0.004 -0.001 0.046 S -6.53329279136 0.00637481657 -0.11611178087 -0.011 -0.000 0.003 N 2.00981687167 0.00259443239 -0.00000686048 0.108 0.252 -0.000 C 2.67119656792 1.17263645248 0.00045766926 -0.094 -0.115 0.000 C 4.06129317470 1.20536051565 0.00241240325 -0.035 -0.021 0.000 C 4.76783866331 0.00148799420 0.00346798881 0.187 0.193 0.000 C 4.05723810074 -1.20352939940 0.00211502115 -0.065 -0.173 -0.000 C 2.67108506586 -1.17139122066 0.00026591651 0.035 -0.051 -0.000 C 1.82209539371 2.39842937406 -0.00175320633 0.128 -0.052 -0.000 C 2.33938959521 3.68993217240 -0.00584554905 0.041 -0.110 0.000 C 1.45736908622 4.77231118002 -0.00917967851 -0.103 0.095 -0.000 C 0.08658913130 4.53522926787 -0.00833235387 0.090 0.035 -0.000 C -0.35359617412 3.21325694137 -0.00400174376 0.004 -0.091 0.001 N 0.49290585413 2.18198449515 -0.00068475564 -0.103 0.066 -0.000 S 6.56718562933 -0.11349126889 0.00673479967 -0.015 -0.023 0.000 C 1.82142022278 -2.39594383179 -0.00206827421 -0.303 0.011 0.000 C 2.33969079820 -3.68709653410 -0.00625612120 -0.015 -0.248 -0.001 C 1.45789786198 -4.76953179608 -0.00945089783 0.278 0.151 0.000 C 0.08684213972 -4.53272927032 -0.00840538011 -0.246 0.112 0.000 C -0.35393854068 -3.21111942258 -0.00398541364 -0.011 -0.228 -0.001 N 0.49225266031 -2.17934076887 -0.00084210065 0.226 0.126 0.000 H 1.83694111827 5.77332096953 -0.01265611066 -0.100 0.056 -0.000 H -0.61802819388 5.33967450634 -0.01131742088 0.031 0.014 -0.000 H 3.39175422949 3.87200638269 -0.00704552340 0.007 0.008 -0.000 H -1.39787683933 2.98334799634 -0.00369736757 -0.004 -0.009 -0.000 H 1.83794742242 -5.77033326187 -0.01295832570 0.243 0.105 0.000 H -0.61749414542 -5.33746053721 -0.01121572048 -0.161 0.108 0.000 H -1.39833026435 -2.98175334118 -0.00345676225 0.008 -0.033 -0.000 H 3.39230213722 -3.86796714602 -0.00754158092 -0.009 -0.088 -0.000 H 4.58301895157 2.13678100538 0.00314824260 -0.205 0.101 -0.001 H 4.58784714512 -2.12983634010 0.00211631073 -0.071 -0.085 -0.000 H -1.68997263563 -0.00719388386 -5.74925805817 0.051 -0.000 -0.020 H 0.75224758084 -0.00860493512 -5.25016290812 -0.033 -0.001 -0.022 H -3.29620044300 -0.00255800648 -3.88456579214 -0.002 0.001 0.030 H 1.47161249279 -0.00457826661 -2.87685200854 0.001 0.003 0.006 H -1.69176120521 -0.00597000955 5.75026973076 0.007 -0.000 0.000 H 0.75025791005 -0.00892914887 5.25161119224 -0.007 -0.000 0.005 H 1.46975366817 -0.00523069331 2.87805400798 0.000 0.003 0.001 H -3.29750276746 -0.00099200484 3.88584245085 -0.001 0.001 -0.017 H -4.55513299541 0.00377930937 -2.13473279421 -0.056 0.001 0.041 H -4.55107479454 0.00501307822 2.13844314827 -0.074 0.001 -0.042 H -6.83436893102 0.00806057203 1.19721860356 -0.015 0.000 -0.002 H 6.86748209639 1.20005966818 0.00372860376 -0.097 0.017 -0.000 61 Mode 118: freq=1243.74 N -0.44003451495 -0.00038510790 2.12369783068 0.208 -0.000 0.134 C -1.76594470239 0.00039861437 2.37754210613 -0.271 0.000 -0.015 C -2.24923313135 -0.00145267054 3.67997125809 -0.034 0.000 -0.234 C -1.33887502024 -0.00450793845 4.73956848945 0.243 -0.001 0.149 C 0.02462671625 -0.00591801736 4.46614405978 -0.207 0.000 0.084 C 0.43187566201 -0.00376957955 3.13352499014 -0.020 0.000 -0.191 C -2.63984642995 0.00218980399 1.17162612704 0.047 -0.000 -0.067 N -1.98513620489 0.00132140951 0.00153900685 0.029 0.001 0.250 C -2.63911589169 0.00167522827 -1.17277445342 -0.067 -0.000 -0.081 C -4.02452897564 0.00329996303 -1.20791476641 -0.007 -0.000 -0.074 C -4.73391255267 0.00451580118 -0.00020876193 0.059 0.000 0.192 C -4.02924140493 0.00399189729 1.20660077672 -0.020 -0.000 -0.120 Co 0.00000000000 0.00000000000 0.00000000000 0.000 -0.002 -0.008 N -0.43839318333 -0.00054206762 -2.12229806799 -0.158 0.000 0.106 C -1.76408906064 -0.00030645034 -2.37697009192 0.205 0.000 -0.018 C -2.24773885821 -0.00257631963 -3.67934971086 0.032 -0.001 -0.181 C -1.33713102227 -0.00526459193 -4.73855802198 -0.180 0.000 0.121 C 0.02654101484 -0.00591797621 -4.46472703619 0.154 0.000 0.066 C 0.43371721952 -0.00363389350 -3.13225443930 0.014 -0.001 -0.152 S -6.53329279136 0.00637481657 -0.11611178087 -0.025 -0.000 -0.024 N 2.00981687167 0.00259443239 -0.00000686048 -0.056 0.072 0.005 C 2.67119656792 1.17263645248 0.00045766926 0.003 -0.008 -0.000 C 4.06129317470 1.20536051565 0.00241240325 0.030 -0.070 -0.001 C 4.76783866331 0.00148799420 0.00346798881 -0.110 0.052 0.000 C 4.05723810074 -1.20352939940 0.00211502115 0.023 0.018 -0.001 C 2.67108506586 -1.17139122066 0.00026591651 0.034 -0.039 -0.000 C 1.82209539371 2.39842937406 -0.00175320633 0.119 0.004 0.001 C 2.33938959521 3.68993217240 -0.00584554905 0.007 -0.099 -0.000 C 1.45736908622 4.77231118002 -0.00917967851 -0.112 0.059 0.000 C 0.08658913130 4.53522926787 -0.00833235387 0.096 0.039 0.000 C -0.35359617412 3.21325694137 -0.00400174376 0.008 -0.084 -0.001 N 0.49290585413 2.18198449515 -0.00068475564 -0.090 0.053 -0.000 S 6.56718562933 -0.11349126889 0.00673479967 0.022 -0.006 0.000 C 1.82142022278 -2.39594383179 -0.00206827421 -0.007 -0.019 0.001 C 2.33969079820 -3.68709653410 -0.00625612120 -0.014 -0.009 -0.001 C 1.45789786198 -4.76953179608 -0.00945089783 0.001 0.016 0.000 C 0.08684213972 -4.53272927032 -0.00840538011 -0.000 -0.000 0.000 C -0.35393854068 -3.21111942258 -0.00398541364 0.000 -0.006 -0.001 N 0.49225266031 -2.17934076887 -0.00084210065 0.008 0.007 0.000 H 1.83694111827 5.77332096953 -0.01265611066 -0.103 0.044 -0.000 H -0.61802819388 5.33967450634 -0.01131742088 0.060 0.038 -0.000 H 3.39175422949 3.87200638269 -0.00704552340 0.005 -0.044 0.002 H -1.39787683933 2.98334799634 -0.00369736757 -0.003 -0.008 0.002 H 1.83794742242 -5.77033326187 -0.01295832570 0.003 0.006 -0.000 H -0.61749414542 -5.33746053721 -0.01121572048 0.010 -0.009 -0.000 H -1.39833026435 -2.98175334118 -0.00345676225 0.000 -0.000 0.003 H 3.39230213722 -3.86796714602 -0.00754158092 -0.001 0.015 0.002 H 4.58301895157 2.13678100538 0.00314824260 0.057 -0.050 0.001 H 4.58784714512 -2.12983634010 0.00211631073 0.096 0.056 0.002 H -1.68997263563 -0.00719388386 -5.74925805817 -0.162 0.000 0.075 H 0.75224758084 -0.00860493512 -5.25016290812 0.074 -0.000 0.045 H -3.29620044300 -0.00255800648 -3.88456579214 0.010 0.000 -0.047 H 1.47161249279 -0.00457826661 -2.87685200854 -0.004 0.001 -0.023 H -1.69176120521 -0.00597000955 5.75026973076 0.223 -0.000 0.097 H 0.75025791005 -0.00892914887 5.25161119224 -0.106 -0.000 0.064 H 1.46975366817 -0.00523069331 2.87805400798 0.006 0.000 -0.022 H -3.29750276746 -0.00099200484 3.88584245085 -0.013 0.001 -0.078 H -4.55513299541 0.00377930937 -2.13473279421 -0.112 0.001 0.037 H -4.55107479454 0.00501307822 2.13844314827 0.031 0.000 -0.019 H -6.83436893102 0.00806057203 1.19721860356 0.089 -0.000 0.018 H 6.86748209639 1.20005966818 0.00372860376 -0.020 0.005 0.000 61 Mode 119: freq=1243.95 N -0.44003451495 -0.00038510790 2.12369783068 -0.097 0.000 -0.070 C -1.76594470239 0.00039861437 2.37754210613 0.130 0.000 -0.002 C -2.24923313135 -0.00145267054 3.67997125809 0.010 -0.001 0.114 C -1.33887502024 -0.00450793845 4.73956848945 -0.119 0.000 -0.069 C 0.02462671625 -0.00591801736 4.46614405978 0.100 0.000 -0.036 C 0.43187566201 -0.00376957955 3.13352499014 0.011 -0.001 0.088 C -2.63984642995 0.00218980399 1.17162612704 -0.004 -0.000 0.013 N -1.98513620489 0.00132140951 0.00153900685 -0.063 0.002 -0.089 C -2.63911589169 0.00167522827 -1.17277445342 0.034 -0.000 0.040 C -4.02452897564 0.00329996303 -1.20791476641 0.028 -0.000 -0.003 C -4.73391255267 0.00451580118 -0.00020876193 -0.102 0.000 -0.067 C -4.02924140493 0.00399189729 1.20660077672 0.032 -0.000 0.070 Co 0.00000000000 0.00000000000 0.00000000000 0.012 -0.003 0.003 N -0.43839318333 -0.00054206762 -2.12229806799 0.035 0.000 -0.018 C -1.76408906064 -0.00030645034 -2.37697009192 -0.041 0.000 0.015 C -2.24773885821 -0.00257631963 -3.67934971086 -0.015 -0.000 0.035 C -1.33713102227 -0.00526459193 -4.73855802198 0.033 0.000 -0.030 C 0.02654101484 -0.00591797621 -4.46472703619 -0.029 0.000 -0.016 C 0.43371721952 -0.00363389350 -3.13225443930 -0.002 -0.001 0.033 S -6.53329279136 0.00637481657 -0.11611178087 0.021 -0.000 0.008 N 2.00981687167 0.00259443239 -0.00000686048 -0.161 0.134 -0.002 C 2.67119656792 1.17263645248 0.00045766926 0.023 -0.000 0.000 C 4.06129317470 1.20536051565 0.00241240325 0.080 -0.169 0.000 C 4.76783866331 0.00148799420 0.00346798881 -0.304 0.096 -0.001 C 4.05723810074 -1.20352939940 0.00211502115 0.068 0.074 0.000 C 2.67108506586 -1.17139122066 0.00026591651 0.079 -0.086 0.000 C 1.82209539371 2.39842937406 -0.00175320633 0.271 0.018 -0.001 C 2.33938959521 3.68993217240 -0.00584554905 0.011 -0.226 0.001 C 1.45736908622 4.77231118002 -0.00917967851 -0.258 0.131 -0.001 C 0.08658913130 4.53522926787 -0.00833235387 0.221 0.090 -0.000 C -0.35359617412 3.21325694137 -0.00400174376 0.018 -0.192 0.001 N 0.49290585413 2.18198449515 -0.00068475564 -0.204 0.120 -0.000 S 6.56718562933 -0.11349126889 0.00673479967 0.056 -0.012 0.000 C 1.82142022278 -2.39594383179 -0.00206827421 0.035 -0.049 -0.001 C 2.33969079820 -3.68709653410 -0.00625612120 -0.030 0.022 0.000 C 1.45789786198 -4.76953179608 -0.00945089783 -0.046 0.012 -0.000 C 0.08684213972 -4.53272927032 -0.00840538011 0.041 -0.019 -0.000 C -0.35393854068 -3.21111942258 -0.00398541364 0.002 0.025 0.001 N 0.49225266031 -2.17934076887 -0.00084210065 -0.018 -0.004 -0.000 H 1.83694111827 5.77332096953 -0.01265611066 -0.236 0.099 -0.000 H -0.61802819388 5.33967450634 -0.01131742088 0.141 0.090 -0.000 H 3.39175422949 3.87200638269 -0.00704552340 0.013 -0.111 -0.000 H -1.39787683933 2.98334799634 -0.00369736757 -0.007 -0.017 -0.001 H 1.83794742242 -5.77033326187 -0.01295832570 -0.036 -0.004 0.000 H -0.61749414542 -5.33746053721 -0.01121572048 0.051 -0.039 -0.000 H -1.39833026435 -2.98175334118 -0.00345676225 -0.001 0.003 -0.001 H 3.39230213722 -3.86796714602 -0.00754158092 -0.001 0.055 -0.000 H 4.58301895157 2.13678100538 0.00314824260 0.177 -0.140 -0.000 H 4.58784714512 -2.12983634010 0.00211631073 0.252 0.153 0.000 H -1.68997263563 -0.00719388386 -5.74925805817 0.029 -0.000 -0.016 H 0.75224758084 -0.00860493512 -5.25016290812 -0.011 -0.000 -0.007 H -3.29620044300 -0.00255800648 -3.88456579214 -0.001 0.001 -0.008 H 1.47161249279 -0.00457826661 -2.87685200854 0.000 0.002 0.007 H -1.69176120521 -0.00597000955 5.75026973076 -0.111 0.000 -0.047 H 0.75025791005 -0.00892914887 5.25161119224 0.051 -0.000 -0.029 H 1.46975366817 -0.00523069331 2.87805400798 -0.003 0.002 0.007 H -3.29750276746 -0.00099200484 3.88584245085 0.008 0.001 0.054 H -4.55513299541 0.00377930937 -2.13473279421 0.102 0.001 -0.054 H -4.55107479454 0.00501307822 2.13844314827 0.051 0.001 0.046 H -6.83436893102 0.00806057203 1.19721860356 -0.028 0.000 -0.007 H 6.86748209639 1.20005966818 0.00372860376 -0.033 0.009 -0.000 61 Mode 120: freq=1281.91 N -0.44003451495 -0.00038510790 2.12369783068 0.101 -0.000 0.074 C -1.76594470239 0.00039861437 2.37754210613 -0.060 -0.000 0.119 C -2.24923313135 -0.00145267054 3.67997125809 -0.039 0.000 -0.160 C -1.33887502024 -0.00450793845 4.73956848945 0.152 -0.000 0.050 C 0.02462671625 -0.00591801736 4.46614405978 -0.107 -0.000 0.124 C 0.43187566201 -0.00376957955 3.13352499014 -0.075 0.001 -0.181 C -2.63984642995 0.00218980399 1.17162612704 0.079 0.000 0.060 N -1.98513620489 0.00132140951 0.00153900685 -0.173 -0.000 -0.001 C -2.63911589169 0.00167522827 -1.17277445342 0.051 0.000 -0.070 C -4.02452897564 0.00329996303 -1.20791476641 0.113 -0.000 -0.093 C -4.73391255267 0.00451580118 -0.00020876193 -0.323 0.000 0.011 C -4.02924140493 0.00399189729 1.20660077672 0.094 -0.000 0.086 Co 0.00000000000 0.00000000000 0.00000000000 0.007 0.000 0.001 N -0.43839318333 -0.00054206762 -2.12229806799 0.110 -0.000 -0.083 C -1.76408906064 -0.00030645034 -2.37697009192 -0.076 -0.000 -0.102 C -2.24773885821 -0.00257631963 -3.67934971086 -0.046 0.000 0.173 C -1.33713102227 -0.00526459193 -4.73855802198 0.156 -0.000 -0.064 C 0.02654101484 -0.00591797621 -4.46472703619 -0.109 -0.000 -0.117 C 0.43371721952 -0.00363389350 -3.13225443930 -0.071 0.001 0.177 S -6.53329279136 0.00637481657 -0.11611178087 0.047 -0.000 0.000 N 2.00981687167 0.00259443239 -0.00000686048 0.091 -0.001 -0.000 C 2.67119656792 1.17263645248 0.00045766926 -0.042 0.021 0.000 C 4.06129317470 1.20536051565 0.00241240325 -0.051 0.059 -0.000 C 4.76783866331 0.00148799420 0.00346798881 0.179 0.005 0.000 C 4.05723810074 -1.20352939940 0.00211502115 -0.061 -0.062 -0.000 C 2.67108506586 -1.17139122066 0.00026591651 -0.028 -0.026 0.000 C 1.82209539371 2.39842937406 -0.00175320633 0.027 0.052 -0.000 C 2.33938959521 3.68993217240 -0.00584554905 0.026 -0.081 0.000 C 1.45736908622 4.77231118002 -0.00917967851 -0.072 0.029 -0.000 C 0.08658913130 4.53522926787 -0.00833235387 0.050 0.057 -0.000 C -0.35359617412 3.21325694137 -0.00400174376 0.040 -0.086 0.000 N 0.49290585413 2.18198449515 -0.00068475564 -0.054 0.040 -0.000 S 6.56718562933 -0.11349126889 0.00673479967 -0.026 0.000 -0.000 C 1.82142022278 -2.39594383179 -0.00206827421 0.036 -0.043 -0.000 C 2.33969079820 -3.68709653410 -0.00625612120 0.031 0.089 0.000 C 1.45789786198 -4.76953179608 -0.00945089783 -0.075 -0.037 -0.000 C 0.08684213972 -4.53272927032 -0.00840538011 0.052 -0.054 -0.000 C -0.35393854068 -3.21111942258 -0.00398541364 0.038 0.084 0.000 N 0.49225266031 -2.17934076887 -0.00084210065 -0.059 -0.045 -0.000 H 1.83694111827 5.77332096953 -0.01265611066 -0.072 0.028 -0.000 H -0.61802819388 5.33967450634 -0.01131742088 0.045 0.044 -0.000 H 3.39175422949 3.87200638269 -0.00704552340 0.012 -0.054 0.000 H -1.39787683933 2.98334799634 -0.00369736757 0.019 -0.060 0.000 H 1.83794742242 -5.77033326187 -0.01295832570 -0.079 -0.033 -0.000 H -0.61749414542 -5.33746053721 -0.01121572048 0.040 -0.037 -0.000 H -1.39833026435 -2.98175334118 -0.00345676225 0.017 0.054 0.000 H 3.39230213722 -3.86796714602 -0.00754158092 0.013 0.057 0.000 H 4.58301895157 2.13678100538 0.00314824260 -0.117 0.076 -0.000 H 4.58784714512 -2.12983634010 0.00211631073 -0.127 -0.081 -0.000 H -1.68997263563 -0.00719388386 -5.74925805817 0.162 -0.000 -0.060 H 0.75224758084 -0.00860493512 -5.25016290812 -0.105 -0.000 -0.102 H -3.29620044300 -0.00255800648 -3.88456579214 -0.027 0.000 0.130 H 1.47161249279 -0.00457826661 -2.87685200854 -0.036 0.000 0.115 H -1.69176120521 -0.00597000955 5.75026973076 0.149 -0.000 0.051 H 0.75025791005 -0.00892914887 5.25161119224 -0.117 -0.000 0.115 H 1.46975366817 -0.00523069331 2.87805400798 -0.039 0.000 -0.127 H -3.29750276746 -0.00099200484 3.88584245085 -0.024 0.000 -0.123 H -4.55513299541 0.00377930937 -2.13473279421 0.220 -0.000 -0.135 H -4.55107479454 0.00501307822 2.13844314827 0.202 -0.000 0.125 H -6.83436893102 0.00806057203 1.19721860356 0.012 0.000 -0.000 H 6.86748209639 1.20005966818 0.00372860376 -0.007 -0.000 -0.000 61 Mode 121: freq=1284.76 N -0.44003451495 -0.00038510790 2.12369783068 0.048 0.000 0.030 C -1.76594470239 0.00039861437 2.37754210613 -0.030 -0.000 0.064 C -2.24923313135 -0.00145267054 3.67997125809 -0.017 0.000 -0.078 C -1.33887502024 -0.00450793845 4.73956848945 0.075 -0.000 0.024 C 0.02462671625 -0.00591801736 4.46614405978 -0.054 -0.000 0.069 C 0.43187566201 -0.00376957955 3.13352499014 -0.033 0.000 -0.100 C -2.63984642995 0.00218980399 1.17162612704 0.041 -0.000 0.032 N -1.98513620489 0.00132140951 0.00153900685 -0.089 0.000 -0.001 C -2.63911589169 0.00167522827 -1.17277445342 0.025 -0.000 -0.038 C -4.02452897564 0.00329996303 -1.20791476641 0.058 -0.000 -0.045 C -4.73391255267 0.00451580118 -0.00020876193 -0.161 0.000 0.006 C -4.02924140493 0.00399189729 1.20660077672 0.046 -0.000 0.041 Co 0.00000000000 0.00000000000 0.00000000000 0.018 -0.001 0.000 N -0.43839318333 -0.00054206762 -2.12229806799 0.053 0.000 -0.035 C -1.76408906064 -0.00030645034 -2.37697009192 -0.039 -0.000 -0.054 C -2.24773885821 -0.00257631963 -3.67934971086 -0.021 0.000 0.085 C -1.33713102227 -0.00526459193 -4.73855802198 0.077 -0.000 -0.032 C 0.02654101484 -0.00591797621 -4.46472703619 -0.054 -0.000 -0.064 C 0.43371721952 -0.00363389350 -3.13225443930 -0.031 0.000 0.097 S -6.53329279136 0.00637481657 -0.11611178087 0.023 -0.000 0.000 N 2.00981687167 0.00259443239 -0.00000686048 -0.172 0.003 -0.000 C 2.67119656792 1.17263645248 0.00045766926 0.086 -0.045 0.000 C 4.06129317470 1.20536051565 0.00241240325 0.091 -0.109 0.000 C 4.76783866331 0.00148799420 0.00346798881 -0.339 -0.012 -0.001 C 4.05723810074 -1.20352939940 0.00211502115 0.115 0.115 0.000 C 2.67108506586 -1.17139122066 0.00026591651 0.053 0.057 0.000 C 1.82209539371 2.39842937406 -0.00175320633 -0.052 -0.112 0.000 C 2.33938959521 3.68993217240 -0.00584554905 -0.045 0.154 -0.000 C 1.45736908622 4.77231118002 -0.00917967851 0.139 -0.055 0.000 C 0.08658913130 4.53522926787 -0.00833235387 -0.099 -0.121 0.000 C -0.35359617412 3.21325694137 -0.00400174376 -0.070 0.183 -0.001 N 0.49290585413 2.18198449515 -0.00068475564 0.097 -0.070 0.000 S 6.56718562933 -0.11349126889 0.00673479967 0.049 -0.000 0.000 C 1.82142022278 -2.39594383179 -0.00206827421 -0.071 0.090 0.000 C 2.33969079820 -3.68709653410 -0.00625612120 -0.053 -0.169 -0.000 C 1.45789786198 -4.76953179608 -0.00945089783 0.143 0.072 0.000 C 0.08684213972 -4.53272927032 -0.00840538011 -0.100 0.112 0.000 C -0.35393854068 -3.21111942258 -0.00398541364 -0.064 -0.177 -0.001 N 0.49225266031 -2.17934076887 -0.00084210065 0.108 0.080 0.000 H 1.83694111827 5.77332096953 -0.01265611066 0.139 -0.054 0.000 H -0.61802819388 5.33967450634 -0.01131742088 -0.113 -0.109 0.000 H 3.39175422949 3.87200638269 -0.00704552340 -0.022 0.112 -0.001 H -1.39787683933 2.98334799634 -0.00369736757 -0.036 0.129 -0.000 H 1.83794742242 -5.77033326187 -0.01295832570 0.154 0.064 0.000 H -0.61749414542 -5.33746053721 -0.01121572048 -0.098 0.094 0.000 H -1.39833026435 -2.98175334118 -0.00345676225 -0.031 -0.114 -0.000 H 3.39230213722 -3.86796714602 -0.00754158092 -0.025 -0.118 -0.001 H 4.58301895157 2.13678100538 0.00314824260 0.214 -0.139 0.000 H 4.58784714512 -2.12983634010 0.00211631073 0.236 0.150 0.001 H -1.68997263563 -0.00719388386 -5.74925805817 0.081 -0.000 -0.030 H 0.75224758084 -0.00860493512 -5.25016290812 -0.064 -0.000 -0.063 H -3.29620044300 -0.00255800648 -3.88456579214 -0.013 0.000 0.066 H 1.47161249279 -0.00457826661 -2.87685200854 -0.017 -0.000 0.063 H -1.69176120521 -0.00597000955 5.75026973076 0.075 -0.000 0.025 H 0.75025791005 -0.00892914887 5.25161119224 -0.071 -0.000 0.071 H 1.46975366817 -0.00523069331 2.87805400798 -0.019 -0.000 -0.070 H -3.29750276746 -0.00099200484 3.88584245085 -0.012 0.000 -0.063 H -4.55513299541 0.00377930937 -2.13473279421 0.110 -0.000 -0.066 H -4.55107479454 0.00501307822 2.13844314827 0.099 -0.000 0.061 H -6.83436893102 0.00806057203 1.19721860356 0.006 0.000 -0.000 H 6.86748209639 1.20005966818 0.00372860376 0.013 0.000 0.000 61 Mode 122: freq=1298.90 N -0.44003451495 -0.00038510790 2.12369783068 0.000 -0.003 0.000 C -1.76594470239 0.00039861437 2.37754210613 -0.001 0.000 0.000 C -2.24923313135 -0.00145267054 3.67997125809 0.000 0.000 -0.001 C -1.33887502024 -0.00450793845 4.73956848945 0.000 0.000 0.000 C 0.02462671625 -0.00591801736 4.46614405978 -0.000 -0.000 0.000 C 0.43187566201 -0.00376957955 3.13352499014 0.000 0.001 -0.001 C -2.63984642995 0.00218980399 1.17162612704 -0.000 0.003 0.000 N -1.98513620489 0.00132140951 0.00153900685 -0.001 -0.009 0.000 C -2.63911589169 0.00167522827 -1.17277445342 0.001 0.003 -0.000 C -4.02452897564 0.00329996303 -1.20791476641 0.000 -0.000 -0.000 C -4.73391255267 0.00451580118 -0.00020876193 -0.001 0.000 -0.000 C -4.02924140493 0.00399189729 1.20660077672 0.001 -0.000 0.000 Co 0.00000000000 0.00000000000 0.00000000000 0.001 0.013 -0.000 N -0.43839318333 -0.00054206762 -2.12229806799 0.000 -0.003 -0.000 C -1.76408906064 -0.00030645034 -2.37697009192 -0.000 0.000 -0.001 C -2.24773885821 -0.00257631963 -3.67934971086 0.000 0.000 0.001 C -1.33713102227 -0.00526459193 -4.73855802198 0.001 0.000 -0.000 C 0.02654101484 -0.00591797621 -4.46472703619 -0.000 -0.000 -0.001 C 0.43371721952 -0.00363389350 -3.13225443930 -0.000 0.001 0.001 S -6.53329279136 0.00637481657 -0.11611178087 0.000 0.000 -0.000 N 2.00981687167 0.00259443239 -0.00000686048 -0.004 -0.329 -0.000 C 2.67119656792 1.17263645248 0.00045766926 -0.175 0.006 -0.000 C 4.06129317470 1.20536051565 0.00241240325 0.157 0.081 0.000 C 4.76783866331 0.00148799420 0.00346798881 -0.023 -0.043 -0.000 C 4.05723810074 -1.20352939940 0.00211502115 -0.147 0.090 -0.000 C 2.67108506586 -1.17139122066 0.00026591651 0.175 0.015 0.000 C 1.82209539371 2.39842937406 -0.00175320633 -0.144 0.237 -0.000 C 2.33938959521 3.68993217240 -0.00584554905 -0.023 0.014 -0.000 C 1.45736908622 4.77231118002 -0.00917967851 -0.081 -0.085 0.000 C 0.08658913130 4.53522926787 -0.00833235387 0.050 0.132 -0.000 C -0.35359617412 3.21325694137 -0.00400174376 0.103 -0.135 0.001 N 0.49290585413 2.18198449515 -0.00068475564 0.035 -0.024 -0.000 S 6.56718562933 -0.11349126889 0.00673479967 -0.001 0.017 -0.000 C 1.82142022278 -2.39594383179 -0.00206827421 0.146 0.252 0.000 C 2.33969079820 -3.68709653410 -0.00625612120 0.019 0.002 0.000 C 1.45789786198 -4.76953179608 -0.00945089783 0.087 -0.083 -0.000 C 0.08684213972 -4.53272927032 -0.00840538011 -0.053 0.141 0.000 C -0.35393854068 -3.21111942258 -0.00398541364 -0.111 -0.149 -0.001 N 0.49225266031 -2.17934076887 -0.00084210065 -0.027 -0.018 0.000 H 1.83694111827 5.77332096953 -0.01265611066 -0.090 -0.004 0.000 H -0.61802819388 5.33967450634 -0.01131742088 0.217 0.217 -0.001 H 3.39175422949 3.87200638269 -0.00704552340 0.012 -0.132 0.000 H -1.39787683933 2.98334799634 -0.00369736757 0.069 -0.206 0.001 H 1.83794742242 -5.77033326187 -0.01295832570 0.095 -0.002 -0.000 H -0.61749414542 -5.33746053721 -0.01121572048 -0.220 0.221 0.001 H -1.39833026435 -2.98175334118 -0.00345676225 -0.073 -0.217 -0.001 H 3.39230213722 -3.86796714602 -0.00754158092 -0.014 -0.143 -0.001 H 4.58301895157 2.13678100538 0.00314824260 0.246 -0.081 0.000 H 4.58784714512 -2.12983634010 0.00211631073 -0.219 -0.065 -0.000 H -1.68997263563 -0.00719388386 -5.74925805817 0.001 0.000 -0.000 H 0.75224758084 -0.00860493512 -5.25016290812 -0.001 0.000 -0.001 H -3.29620044300 -0.00255800648 -3.88456579214 -0.000 -0.000 0.001 H 1.47161249279 -0.00457826661 -2.87685200854 -0.000 0.001 0.001 H -1.69176120521 -0.00597000955 5.75026973076 0.000 0.000 0.000 H 0.75025791005 -0.00892914887 5.25161119224 -0.000 0.000 0.000 H 1.46975366817 -0.00523069331 2.87805400798 0.000 0.001 -0.000 H -3.29750276746 -0.00099200484 3.88584245085 -0.000 -0.000 -0.000 H -4.55513299541 0.00377930937 -2.13473279421 0.000 -0.001 -0.000 H -4.55107479454 0.00501307822 2.13844314827 0.001 -0.001 0.001 H -6.83436893102 0.00806057203 1.19721860356 0.000 -0.000 -0.000 H 6.86748209639 1.20005966818 0.00372860376 0.037 -0.005 0.000 61 Mode 123: freq=1300.93 N -0.44003451495 -0.00038510790 2.12369783068 0.049 -0.000 0.036 C -1.76594470239 0.00039861437 2.37754210613 -0.168 0.000 -0.223 C -2.24923313135 -0.00145267054 3.67997125809 -0.028 0.000 -0.039 C -1.33887502024 -0.00450793845 4.73956848945 -0.064 -0.000 0.098 C 0.02462671625 -0.00591801736 4.46614405978 0.040 0.000 -0.132 C 0.43187566201 -0.00376957955 3.13352499014 0.101 -0.000 0.127 C -2.63984642995 0.00218980399 1.17162612704 -0.217 0.000 0.040 N -1.98513620489 0.00132140951 0.00153900685 -0.002 0.000 0.247 C -2.63911589169 0.00167522827 -1.17277445342 0.217 -0.000 0.030 C -4.02452897564 0.00329996303 -1.20791476641 -0.186 0.000 -0.057 C -4.73391255267 0.00451580118 -0.00020876193 -0.025 0.000 -0.025 C -4.02924140493 0.00399189729 1.20660077672 0.194 -0.000 -0.047 Co 0.00000000000 0.00000000000 0.00000000000 0.001 -0.000 -0.014 N -0.43839318333 -0.00054206762 -2.12229806799 -0.042 0.000 0.032 C -1.76408906064 -0.00030645034 -2.37697009192 0.174 -0.000 -0.242 C -2.24773885821 -0.00257631963 -3.67934971086 0.024 -0.000 -0.029 C -1.33713102227 -0.00526459193 -4.73855802198 0.070 0.000 0.099 C 0.02654101484 -0.00591797621 -4.46472703619 -0.042 -0.000 -0.142 C 0.43371721952 -0.00363389350 -3.13225443930 -0.111 0.000 0.140 S -6.53329279136 0.00637481657 -0.11611178087 0.003 -0.000 -0.013 N 2.00981687167 0.00259443239 -0.00000686048 -0.000 0.001 0.009 C 2.67119656792 1.17263645248 0.00045766926 0.001 -0.000 -0.003 C 4.06129317470 1.20536051565 0.00241240325 0.000 -0.000 0.000 C 4.76783866331 0.00148799420 0.00346798881 -0.001 0.000 -0.000 C 4.05723810074 -1.20352939940 0.00211502115 0.001 0.000 0.000 C 2.67108506586 -1.17139122066 0.00026591651 -0.000 0.000 -0.003 C 1.82209539371 2.39842937406 -0.00175320633 -0.000 -0.001 -0.001 C 2.33938959521 3.68993217240 -0.00584554905 0.000 0.000 -0.000 C 1.45736908622 4.77231118002 -0.00917967851 0.000 -0.000 -0.000 C 0.08658913130 4.53522926787 -0.00833235387 -0.000 -0.001 -0.000 C -0.35359617412 3.21325694137 -0.00400174376 -0.000 0.001 -0.000 N 0.49290585413 2.18198449515 -0.00068475564 0.000 -0.000 0.004 S 6.56718562933 -0.11349126889 0.00673479967 0.000 -0.000 -0.000 C 1.82142022278 -2.39594383179 -0.00206827421 -0.001 0.000 -0.001 C 2.33969079820 -3.68709653410 -0.00625612120 -0.000 -0.001 -0.000 C 1.45789786198 -4.76953179608 -0.00945089783 0.000 0.000 -0.000 C 0.08684213972 -4.53272927032 -0.00840538011 -0.000 0.000 -0.000 C -0.35393854068 -3.21111942258 -0.00398541364 0.000 -0.001 -0.000 N 0.49225266031 -2.17934076887 -0.00084210065 0.000 0.000 0.004 H 1.83694111827 5.77332096953 -0.01265611066 0.000 -0.000 -0.000 H -0.61802819388 5.33967450634 -0.01131742088 -0.001 -0.001 0.000 H 3.39175422949 3.87200638269 -0.00704552340 -0.000 0.001 0.000 H -1.39787683933 2.98334799634 -0.00369736757 -0.000 0.001 -0.001 H 1.83794742242 -5.77033326187 -0.01295832570 0.000 0.000 -0.000 H -0.61749414542 -5.33746053721 -0.01121572048 -0.000 0.000 0.000 H -1.39833026435 -2.98175334118 -0.00345676225 0.000 -0.000 -0.001 H 3.39230213722 -3.86796714602 -0.00754158092 -0.000 -0.000 0.000 H 4.58301895157 2.13678100538 0.00314824260 0.000 -0.000 0.001 H 4.58784714512 -2.12983634010 0.00211631073 0.001 0.000 0.001 H -1.68997263563 -0.00719388386 -5.74925805817 0.074 0.000 0.015 H 0.75224758084 -0.00860493512 -5.25016290812 -0.219 -0.000 -0.234 H -3.29620044300 -0.00255800648 -3.88456579214 -0.012 0.000 0.113 H 1.47161249279 -0.00457826661 -2.87685200854 -0.080 0.000 0.221 H -1.69176120521 -0.00597000955 5.75026973076 -0.070 0.000 0.015 H 0.75025791005 -0.00892914887 5.25161119224 0.216 0.000 -0.228 H 1.46975366817 -0.00523069331 2.87805400798 0.074 -0.000 0.208 H -3.29750276746 -0.00099200484 3.88584245085 0.009 -0.000 0.100 H -4.55513299541 0.00377930937 -2.13473279421 -0.218 0.000 0.068 H -4.55107479454 0.00501307822 2.13844314827 0.244 -0.000 0.084 H -6.83436893102 0.00806057203 1.19721860356 0.016 -0.000 0.001 H 6.86748209639 1.20005966818 0.00372860376 -0.000 0.000 0.000 61 Mode 124: freq=1316.89 N -0.44003451495 -0.00038510790 2.12369783068 0.000 0.003 0.000 C -1.76594470239 0.00039861437 2.37754210613 0.000 -0.001 -0.000 C -2.24923313135 -0.00145267054 3.67997125809 -0.000 0.000 0.000 C -1.33887502024 -0.00450793845 4.73956848945 -0.000 -0.000 -0.000 C 0.02462671625 -0.00591801736 4.46614405978 0.000 -0.000 -0.000 C 0.43187566201 -0.00376957955 3.13352499014 -0.000 0.001 0.001 C -2.63984642995 0.00218980399 1.17162612704 -0.000 -0.000 -0.000 N -1.98513620489 0.00132140951 0.00153900685 0.000 -0.001 -0.000 C -2.63911589169 0.00167522827 -1.17277445342 0.000 -0.000 0.000 C -4.02452897564 0.00329996303 -1.20791476641 -0.000 0.000 0.000 C -4.73391255267 0.00451580118 -0.00020876193 0.001 -0.000 -0.000 C -4.02924140493 0.00399189729 1.20660077672 0.000 0.000 0.000 Co 0.00000000000 0.00000000000 0.00000000000 -0.000 -0.004 -0.000 N -0.43839318333 -0.00054206762 -2.12229806799 0.000 0.003 0.000 C -1.76408906064 -0.00030645034 -2.37697009192 0.000 -0.001 0.000 C -2.24773885821 -0.00257631963 -3.67934971086 -0.000 0.000 -0.000 C -1.33713102227 -0.00526459193 -4.73855802198 -0.000 -0.000 0.000 C 0.02654101484 -0.00591797621 -4.46472703619 0.000 -0.000 0.000 C 0.43371721952 -0.00363389350 -3.13225443930 -0.000 0.001 -0.001 S -6.53329279136 0.00637481657 -0.11611178087 -0.000 0.000 0.000 N 2.00981687167 0.00259443239 -0.00000686048 -0.002 -0.346 0.000 C 2.67119656792 1.17263645248 0.00045766926 0.277 0.232 0.000 C 4.06129317470 1.20536051565 0.00241240325 -0.262 0.184 -0.001 C 4.76783866331 0.00148799420 0.00346798881 0.029 -0.350 0.000 C 4.05723810074 -1.20352939940 0.00211502115 0.260 0.160 0.000 C 2.67108506586 -1.17139122066 0.00026591651 -0.278 0.229 -0.000 C 1.82209539371 2.39842937406 -0.00175320633 0.080 -0.057 0.000 C 2.33938959521 3.68993217240 -0.00584554905 0.041 -0.117 0.000 C 1.45736908622 4.77231118002 -0.00917967851 -0.068 0.082 -0.000 C 0.08658913130 4.53522926787 -0.00833235387 0.031 -0.003 -0.000 C -0.35359617412 3.21325694137 -0.00400174376 -0.016 0.012 0.000 N 0.49290585413 2.18198449515 -0.00068475564 -0.017 0.043 -0.000 S 6.56718562933 -0.11349126889 0.00673479967 -0.023 0.015 -0.000 C 1.82142022278 -2.39594383179 -0.00206827421 -0.097 -0.088 -0.000 C 2.33969079820 -3.68709653410 -0.00625612120 -0.038 -0.113 -0.000 C 1.45789786198 -4.76953179608 -0.00945089783 0.063 0.091 0.000 C 0.08684213972 -4.53272927032 -0.00840538011 -0.031 -0.014 -0.000 C -0.35393854068 -3.21111942258 -0.00398541364 0.032 0.026 0.000 N 0.49225266031 -2.17934076887 -0.00084210065 0.012 0.040 0.000 H 1.83694111827 5.77332096953 -0.01265611066 -0.228 0.106 -0.000 H -0.61802819388 5.33967450634 -0.01131742088 0.042 0.027 -0.000 H 3.39175422949 3.87200638269 -0.00704552340 0.038 -0.186 0.001 H -1.39787683933 2.98334799634 -0.00369736757 -0.009 0.020 -0.000 H 1.83794742242 -5.77033326187 -0.01295832570 0.230 0.110 0.000 H -0.61749414542 -5.33746053721 -0.01121572048 -0.038 0.020 0.000 H -1.39833026435 -2.98175334118 -0.00345676225 0.017 0.037 0.000 H 3.39230213722 -3.86796714602 -0.00754158092 -0.035 -0.171 -0.001 H 4.58301895157 2.13678100538 0.00314824260 -0.037 0.032 0.000 H 4.58784714512 -2.12983634010 0.00211631073 0.010 0.008 -0.000 H -1.68997263563 -0.00719388386 -5.74925805817 -0.000 0.000 0.000 H 0.75224758084 -0.00860493512 -5.25016290812 0.001 0.000 0.001 H -3.29620044300 -0.00255800648 -3.88456579214 0.000 -0.000 -0.001 H 1.47161249279 -0.00457826661 -2.87685200854 -0.000 -0.005 -0.000 H -1.69176120521 -0.00597000955 5.75026973076 0.000 0.000 0.000 H 0.75025791005 -0.00892914887 5.25161119224 0.001 0.000 -0.001 H 1.46975366817 -0.00523069331 2.87805400798 -0.000 -0.005 0.000 H -3.29750276746 -0.00099200484 3.88584245085 -0.000 -0.000 0.000 H -4.55513299541 0.00377930937 -2.13473279421 -0.000 -0.000 0.000 H -4.55107479454 0.00501307822 2.13844314827 -0.000 -0.000 -0.000 H -6.83436893102 0.00806057203 1.19721860356 -0.000 -0.000 -0.000 H 6.86748209639 1.20005966818 0.00372860376 0.092 -0.020 0.000 61 Mode 125: freq=1319.86 N -0.44003451495 -0.00038510790 2.12369783068 0.022 0.000 -0.022 C -1.76594470239 0.00039861437 2.37754210613 0.030 -0.000 0.039 C -2.24923313135 -0.00145267054 3.67997125809 0.034 -0.000 0.088 C -1.33887502024 -0.00450793845 4.73956848945 -0.067 0.000 -0.060 C 0.02462671625 -0.00591801736 4.46614405978 0.025 0.000 -0.007 C 0.43187566201 -0.00376957955 3.13352499014 -0.009 0.000 -0.020 C -2.63984642995 0.00218980399 1.17162612704 0.239 -0.000 -0.218 N -1.98513620489 0.00132140951 0.00153900685 -0.003 0.000 0.370 C -2.63911589169 0.00167522827 -1.17277445342 -0.240 0.000 -0.216 C -4.02452897564 0.00329996303 -1.20791476641 0.230 -0.000 -0.175 C -4.73391255267 0.00451580118 -0.00020876193 0.023 0.000 0.363 C -4.02924140493 0.00399189729 1.20660077672 -0.230 0.000 -0.196 Co 0.00000000000 0.00000000000 0.00000000000 -0.000 -0.000 0.003 N -0.43839318333 -0.00054206762 -2.12229806799 -0.024 0.000 -0.021 C -1.76408906064 -0.00030645034 -2.37697009192 -0.049 0.000 0.066 C -2.24773885821 -0.00257631963 -3.67934971086 -0.033 0.000 0.087 C -1.33713102227 -0.00526459193 -4.73855802198 0.064 -0.000 -0.069 C 0.02654101484 -0.00591797621 -4.46472703619 -0.026 -0.000 0.002 C 0.43371721952 -0.00363389350 -3.13225443930 0.022 -0.000 -0.030 S -6.53329279136 0.00637481657 -0.11611178087 -0.023 -0.000 -0.018 N 2.00981687167 0.00259443239 -0.00000686048 0.000 -0.000 0.002 C 2.67119656792 1.17263645248 0.00045766926 0.000 0.000 -0.000 C 4.06129317470 1.20536051565 0.00241240325 -0.000 0.000 -0.000 C 4.76783866331 0.00148799420 0.00346798881 0.000 -0.000 0.000 C 4.05723810074 -1.20352939940 0.00211502115 0.000 0.000 -0.000 C 2.67108506586 -1.17139122066 0.00026591651 -0.000 0.000 -0.000 C 1.82209539371 2.39842937406 -0.00175320633 0.000 0.000 0.001 C 2.33938959521 3.68993217240 -0.00584554905 -0.000 -0.000 -0.000 C 1.45736908622 4.77231118002 -0.00917967851 -0.000 0.000 0.000 C 0.08658913130 4.53522926787 -0.00833235387 0.000 0.000 0.000 C -0.35359617412 3.21325694137 -0.00400174376 -0.000 -0.001 -0.001 N 0.49290585413 2.18198449515 -0.00068475564 0.000 -0.000 -0.002 S 6.56718562933 -0.11349126889 0.00673479967 -0.000 0.000 -0.000 C 1.82142022278 -2.39594383179 -0.00206827421 -0.000 -0.000 0.001 C 2.33969079820 -3.68709653410 -0.00625612120 -0.000 -0.000 -0.000 C 1.45789786198 -4.76953179608 -0.00945089783 0.000 0.000 0.000 C 0.08684213972 -4.53272927032 -0.00840538011 -0.000 -0.000 0.000 C -0.35393854068 -3.21111942258 -0.00398541364 -0.000 0.001 -0.001 N 0.49225266031 -2.17934076887 -0.00084210065 0.000 0.000 -0.002 H 1.83694111827 5.77332096953 -0.01265611066 -0.000 0.000 -0.000 H -0.61802819388 5.33967450634 -0.01131742088 0.001 0.001 -0.000 H 3.39175422949 3.87200638269 -0.00704552340 0.000 -0.000 0.000 H -1.39787683933 2.98334799634 -0.00369736757 -0.000 -0.000 0.004 H 1.83794742242 -5.77033326187 -0.01295832570 0.000 0.000 -0.000 H -0.61749414542 -5.33746053721 -0.01121572048 0.000 -0.001 -0.000 H -1.39833026435 -2.98175334118 -0.00345676225 0.000 0.000 0.004 H 3.39230213722 -3.86796714602 -0.00754158092 -0.000 0.000 0.000 H 4.58301895157 2.13678100538 0.00314824260 -0.000 0.000 0.001 H 4.58784714512 -2.12983634010 0.00211631073 -0.000 -0.000 0.001 H -1.68997263563 -0.00719388386 -5.74925805817 0.269 -0.000 -0.110 H 0.75224758084 -0.00860493512 -5.25016290812 -0.087 -0.000 -0.072 H -3.29620044300 -0.00255800648 -3.88456579214 -0.044 0.001 0.200 H 1.47161249279 -0.00457826661 -2.87685200854 0.006 -0.000 -0.002 H -1.69176120521 -0.00597000955 5.75026973076 -0.270 0.001 -0.107 H 0.75025791005 -0.00892914887 5.25161119224 0.094 0.000 -0.081 H 1.46975366817 -0.00523069331 2.87805400798 0.002 0.000 0.013 H -3.29750276746 -0.00099200484 3.88584245085 0.046 -0.001 0.215 H -4.55513299541 0.00377930937 -2.13473279421 -0.022 0.000 -0.001 H -4.55107479454 0.00501307822 2.13844314827 0.002 -0.000 -0.020 H -6.83436893102 0.00806057203 1.19721860356 0.100 -0.000 0.022 H 6.86748209639 1.20005966818 0.00372860376 0.000 -0.000 0.000 61 Mode 126: freq=1344.52 N -0.44003451495 -0.00038510790 2.12369783068 0.248 -0.001 0.110 C -1.76594470239 0.00039861437 2.37754210613 -0.210 -0.000 0.130 C -2.24923313135 -0.00145267054 3.67997125809 0.008 0.000 -0.106 C -1.33887502024 -0.00450793845 4.73956848945 0.050 -0.000 0.010 C 0.02462671625 -0.00591801736 4.46614405978 -0.077 0.000 0.036 C 0.43187566201 -0.00376957955 3.13352499014 -0.031 0.001 -0.164 C -2.63984642995 0.00218980399 1.17162612704 -0.001 0.000 0.073 N -1.98513620489 0.00132140951 0.00153900685 -0.015 0.000 -0.004 C -2.63911589169 0.00167522827 -1.17277445342 -0.003 0.000 -0.070 C -4.02452897564 0.00329996303 -1.20791476641 0.020 -0.000 0.019 C -4.73391255267 0.00451580118 -0.00020876193 -0.026 0.000 -0.003 C -4.02924140493 0.00399189729 1.20660077672 0.021 -0.000 -0.016 Co 0.00000000000 0.00000000000 0.00000000000 0.001 0.000 0.000 N -0.43839318333 -0.00054206762 -2.12229806799 0.247 -0.000 -0.108 C -1.76408906064 -0.00030645034 -2.37697009192 -0.209 -0.000 -0.130 C -2.24773885821 -0.00257631963 -3.67934971086 0.008 0.000 0.105 C -1.33713102227 -0.00526459193 -4.73855802198 0.049 -0.000 -0.009 C 0.02654101484 -0.00591797621 -4.46472703619 -0.076 0.000 -0.036 C 0.43371721952 -0.00363389350 -3.13225443930 -0.030 0.000 0.163 S -6.53329279136 0.00637481657 -0.11611178087 0.003 -0.000 0.001 N 2.00981687167 0.00259443239 -0.00000686048 -0.001 -0.000 -0.000 C 2.67119656792 1.17263645248 0.00045766926 -0.000 0.001 0.000 C 4.06129317470 1.20536051565 0.00241240325 0.002 -0.002 0.000 C 4.76783866331 0.00148799420 0.00346798881 -0.003 -0.000 -0.000 C 4.05723810074 -1.20352939940 0.00211502115 0.002 0.002 0.000 C 2.67108506586 -1.17139122066 0.00026591651 -0.000 -0.001 0.000 C 1.82209539371 2.39842937406 -0.00175320633 0.011 0.006 -0.000 C 2.33938959521 3.68993217240 -0.00584554905 0.001 -0.004 0.000 C 1.45736908622 4.77231118002 -0.00917967851 -0.003 -0.001 0.000 C 0.08658913130 4.53522926787 -0.00833235387 0.006 0.002 -0.000 C -0.35359617412 3.21325694137 -0.00400174376 0.004 -0.009 0.000 N 0.49290585413 2.18198449515 -0.00068475564 -0.019 0.007 -0.000 S 6.56718562933 -0.11349126889 0.00673479967 0.000 0.000 -0.000 C 1.82142022278 -2.39594383179 -0.00206827421 0.011 -0.006 -0.000 C 2.33969079820 -3.68709653410 -0.00625612120 0.001 0.003 0.000 C 1.45789786198 -4.76953179608 -0.00945089783 -0.003 0.002 0.000 C 0.08684213972 -4.53272927032 -0.00840538011 0.005 -0.002 -0.000 C -0.35393854068 -3.21111942258 -0.00398541364 0.004 0.009 0.000 N 0.49225266031 -2.17934076887 -0.00084210065 -0.018 -0.007 -0.000 H 1.83694111827 5.77332096953 -0.01265611066 0.027 -0.011 0.000 H -0.61802819388 5.33967450634 -0.01131742088 -0.018 -0.016 0.000 H 3.39175422949 3.87200638269 -0.00704552340 -0.004 0.022 -0.000 H -1.39787683933 2.98334799634 -0.00369736757 -0.000 0.003 -0.000 H 1.83794742242 -5.77033326187 -0.01295832570 0.026 0.011 0.000 H -0.61749414542 -5.33746053721 -0.01121572048 -0.017 0.016 0.000 H -1.39833026435 -2.98175334118 -0.00345676225 -0.000 -0.003 -0.000 H 3.39230213722 -3.86796714602 -0.00754158092 -0.003 -0.021 -0.000 H 4.58301895157 2.13678100538 0.00314824260 0.000 -0.000 0.000 H 4.58784714512 -2.12983634010 0.00211631073 0.000 0.000 0.000 H -1.68997263563 -0.00719388386 -5.74925805817 -0.371 0.001 0.133 H 0.75224758084 -0.00860493512 -5.25016290812 0.225 0.000 0.218 H -3.29620044300 -0.00255800648 -3.88456579214 0.049 -0.000 -0.211 H 1.47161249279 -0.00457826661 -2.87685200854 0.025 -0.000 -0.078 H -1.69176120521 -0.00597000955 5.75026973076 -0.370 0.001 -0.132 H 0.75025791005 -0.00892914887 5.25161119224 0.226 0.000 -0.219 H 1.46975366817 -0.00523069331 2.87805400798 0.024 -0.000 0.077 H -3.29750276746 -0.00099200484 3.88584245085 0.049 -0.000 0.211 H -4.55513299541 0.00377930937 -2.13473279421 0.044 -0.000 -0.017 H -4.55107479454 0.00501307822 2.13844314827 0.039 -0.000 0.014 H -6.83436893102 0.00806057203 1.19721860356 -0.002 0.000 -0.001 H 6.86748209639 1.20005966818 0.00372860376 0.000 0.000 0.000 61 Mode 127: freq=1345.66 N -0.44003451495 -0.00038510790 2.12369783068 0.015 -0.000 0.009 C -1.76594470239 0.00039861437 2.37754210613 -0.019 -0.000 0.012 C -2.24923313135 -0.00145267054 3.67997125809 0.002 0.000 -0.011 C -1.33887502024 -0.00450793845 4.73956848945 0.004 -0.000 0.003 C 0.02462671625 -0.00591801736 4.46614405978 -0.005 0.000 0.003 C 0.43187566201 -0.00376957955 3.13352499014 0.001 0.000 -0.014 C -2.63984642995 0.00218980399 1.17162612704 -0.001 0.000 0.009 N -1.98513620489 0.00132140951 0.00153900685 -0.003 0.000 -0.000 C -2.63911589169 0.00167522827 -1.17277445342 -0.001 -0.000 -0.009 C -4.02452897564 0.00329996303 -1.20791476641 0.005 -0.000 0.001 C -4.73391255267 0.00451580118 -0.00020876193 -0.006 0.000 -0.000 C -4.02924140493 0.00399189729 1.20660077672 0.005 -0.000 -0.001 Co 0.00000000000 0.00000000000 0.00000000000 0.003 -0.000 0.000 N -0.43839318333 -0.00054206762 -2.12229806799 0.015 -0.000 -0.009 C -1.76408906064 -0.00030645034 -2.37697009192 -0.020 -0.000 -0.013 C -2.24773885821 -0.00257631963 -3.67934971086 0.002 0.000 0.011 C -1.33713102227 -0.00526459193 -4.73855802198 0.004 -0.000 -0.003 C 0.02654101484 -0.00591797621 -4.46472703619 -0.006 0.000 -0.003 C 0.43371721952 -0.00363389350 -3.13225443930 0.001 0.000 0.014 S -6.53329279136 0.00637481657 -0.11611178087 0.000 -0.000 0.000 N 2.00981687167 0.00259443239 -0.00000686048 -0.010 0.003 -0.000 C 2.67119656792 1.17263645248 0.00045766926 -0.009 -0.065 -0.000 C 4.06129317470 1.20536051565 0.00241240325 0.019 0.018 0.000 C 4.76783866331 0.00148799420 0.00346798881 -0.012 0.002 -0.000 C 4.05723810074 -1.20352939940 0.00211502115 0.020 -0.021 0.000 C 2.67108506586 -1.17139122066 0.00026591651 -0.012 0.064 -0.000 C 1.82209539371 2.39842937406 -0.00175320633 -0.216 -0.126 0.000 C 2.33938959521 3.68993217240 -0.00584554905 0.009 0.102 -0.000 C 1.45736908622 4.77231118002 -0.00917967851 0.051 -0.010 0.000 C 0.08658913130 4.53522926787 -0.00833235387 -0.080 -0.037 0.000 C -0.35359617412 3.21325694137 -0.00400174376 -0.022 0.166 -0.001 N 0.49290585413 2.18198449515 -0.00068475564 0.246 -0.108 0.000 S 6.56718562933 -0.11349126889 0.00673479967 0.001 -0.001 0.000 C 1.82142022278 -2.39594383179 -0.00206827421 -0.215 0.122 0.000 C 2.33969079820 -3.68709653410 -0.00625612120 0.010 -0.100 -0.000 C 1.45789786198 -4.76953179608 -0.00945089783 0.050 0.010 0.000 C 0.08684213972 -4.53272927032 -0.00840538011 -0.078 0.036 0.000 C -0.35393854068 -3.21111942258 -0.00398541364 -0.020 -0.163 -0.001 N 0.49225266031 -2.17934076887 -0.00084210065 0.242 0.105 0.000 H 1.83694111827 5.77332096953 -0.01265611066 -0.370 0.144 -0.000 H -0.61802819388 5.33967450634 -0.01131742088 0.229 0.210 -0.001 H 3.39175422949 3.87200638269 -0.00704552340 0.045 -0.221 0.001 H -1.39787683933 2.98334799634 -0.00369736757 0.026 -0.084 0.000 H 1.83794742242 -5.77033326187 -0.01295832570 -0.365 -0.142 -0.000 H -0.61749414542 -5.33746053721 -0.01121572048 0.226 -0.208 -0.001 H -1.39833026435 -2.98175334118 -0.00345676225 0.027 0.086 0.000 H 3.39230213722 -3.86796714602 -0.00754158092 0.044 0.218 0.001 H 4.58301895157 2.13678100538 0.00314824260 0.041 -0.015 -0.000 H 4.58784714512 -2.12983634010 0.00211631073 0.046 0.017 0.000 H -1.68997263563 -0.00719388386 -5.74925805817 -0.025 0.000 0.008 H 0.75224758084 -0.00860493512 -5.25016290812 0.014 0.000 0.014 H -3.29620044300 -0.00255800648 -3.88456579214 0.003 -0.000 -0.008 H 1.47161249279 -0.00457826661 -2.87685200854 0.004 -0.000 -0.008 H -1.69176120521 -0.00597000955 5.75026973076 -0.025 0.000 -0.008 H 0.75025791005 -0.00892914887 5.25161119224 0.014 -0.000 -0.014 H 1.46975366817 -0.00523069331 2.87805400798 0.004 -0.000 0.008 H -3.29750276746 -0.00099200484 3.88584245085 0.003 -0.000 0.007 H -4.55513299541 0.00377930937 -2.13473279421 0.007 -0.000 -0.003 H -4.55107479454 0.00501307822 2.13844314827 0.006 -0.000 0.002 H -6.83436893102 0.00806057203 1.19721860356 -0.000 0.000 -0.000 H 6.86748209639 1.20005966818 0.00372860376 -0.003 0.001 0.000 61 Mode 128: freq=1355.36 N -0.44003451495 -0.00038510790 2.12369783068 0.000 0.000 0.000 C -1.76594470239 0.00039861437 2.37754210613 -0.000 0.000 0.000 C -2.24923313135 -0.00145267054 3.67997125809 0.000 -0.000 -0.000 C -1.33887502024 -0.00450793845 4.73956848945 0.000 -0.000 0.000 C 0.02462671625 -0.00591801736 4.46614405978 -0.000 -0.000 0.000 C 0.43187566201 -0.00376957955 3.13352499014 -0.000 0.000 -0.000 C -2.63984642995 0.00218980399 1.17162612704 -0.000 0.001 0.000 N -1.98513620489 0.00132140951 0.00153900685 -0.000 -0.002 -0.001 C -2.63911589169 0.00167522827 -1.17277445342 -0.000 0.001 0.000 C -4.02452897564 0.00329996303 -1.20791476641 0.000 -0.000 0.000 C -4.73391255267 0.00451580118 -0.00020876193 -0.000 0.000 -0.000 C -4.02924140493 0.00399189729 1.20660077672 0.000 -0.000 0.000 Co 0.00000000000 0.00000000000 0.00000000000 0.000 0.001 0.000 N -0.43839318333 -0.00054206762 -2.12229806799 -0.000 0.000 0.000 C -1.76408906064 -0.00030645034 -2.37697009192 0.000 0.000 0.000 C -2.24773885821 -0.00257631963 -3.67934971086 0.000 -0.000 -0.000 C -1.33713102227 -0.00526459193 -4.73855802198 -0.000 -0.000 -0.000 C 0.02654101484 -0.00591797621 -4.46472703619 0.000 -0.000 0.000 C 0.43371721952 -0.00363389350 -3.13225443930 0.000 0.000 -0.000 S -6.53329279136 0.00637481657 -0.11611178087 0.000 -0.000 0.000 N 2.00981687167 0.00259443239 -0.00000686048 -0.000 -0.272 -0.000 C 2.67119656792 1.17263645248 0.00045766926 0.013 0.077 0.000 C 4.06129317470 1.20536051565 0.00241240325 -0.012 0.084 -0.000 C 4.76783866331 0.00148799420 0.00346798881 0.002 -0.135 0.000 C 4.05723810074 -1.20352939940 0.00211502115 0.015 0.081 0.000 C 2.67108506586 -1.17139122066 0.00026591651 -0.015 0.080 -0.000 C 1.82209539371 2.39842937406 -0.00175320633 0.163 0.191 -0.001 C 2.33938959521 3.68993217240 -0.00584554905 -0.003 -0.098 0.000 C 1.45736908622 4.77231118002 -0.00917967851 -0.079 -0.008 -0.000 C 0.08658913130 4.53522926787 -0.00833235387 0.095 0.068 -0.000 C -0.35359617412 3.21325694137 -0.00400174376 0.063 -0.203 0.001 N 0.49290585413 2.18198449515 -0.00068475564 -0.250 0.120 -0.000 S 6.56718562933 -0.11349126889 0.00673479967 -0.008 0.012 -0.000 C 1.82142022278 -2.39594383179 -0.00206827421 -0.172 0.187 0.001 C 2.33969079820 -3.68709653410 -0.00625612120 0.003 -0.100 -0.000 C 1.45789786198 -4.76953179608 -0.00945089783 0.079 -0.006 -0.000 C 0.08684213972 -4.53272927032 -0.00840538011 -0.096 0.067 0.000 C -0.35393854068 -3.21111942258 -0.00398541364 -0.060 -0.204 -0.001 N 0.49225266031 -2.17934076887 -0.00084210065 0.254 0.121 0.000 H 1.83694111827 5.77332096953 -0.01265611066 0.331 -0.139 0.000 H -0.61802819388 5.33967450634 -0.01131742088 -0.175 -0.158 0.001 H 3.39175422949 3.87200638269 -0.00704552340 -0.035 0.171 -0.000 H -1.39787683933 2.98334799634 -0.00369736757 0.000 0.016 -0.000 H 1.83794742242 -5.77033326187 -0.01295832570 -0.337 -0.140 -0.000 H -0.61749414542 -5.33746053721 -0.01121572048 0.179 -0.162 -0.001 H -1.39833026435 -2.98175334118 -0.00345676225 0.002 0.021 0.000 H 3.39230213722 -3.86796714602 -0.00754158092 0.036 0.177 0.000 H 4.58301895157 2.13678100538 0.00314824260 0.055 -0.003 0.000 H 4.58784714512 -2.12983634010 0.00211631073 -0.054 -0.005 -0.000 H -1.68997263563 -0.00719388386 -5.74925805817 0.001 0.000 -0.000 H 0.75224758084 -0.00860493512 -5.25016290812 -0.000 0.000 -0.000 H -3.29620044300 -0.00255800648 -3.88456579214 -0.000 0.001 0.000 H 1.47161249279 -0.00457826661 -2.87685200854 0.000 -0.001 -0.000 H -1.69176120521 -0.00597000955 5.75026973076 -0.000 0.000 -0.000 H 0.75025791005 -0.00892914887 5.25161119224 0.000 0.000 -0.000 H 1.46975366817 -0.00523069331 2.87805400798 0.000 -0.001 0.000 H -3.29750276746 -0.00099200484 3.88584245085 0.000 0.001 0.000 H -4.55513299541 0.00377930937 -2.13473279421 0.000 0.001 -0.000 H -4.55107479454 0.00501307822 2.13844314827 -0.000 0.001 -0.000 H -6.83436893102 0.00806057203 1.19721860356 -0.000 0.000 -0.000 H 6.86748209639 1.20005966818 0.00372860376 0.042 -0.008 0.000 61 Mode 129: freq=1357.62 N -0.44003451495 -0.00038510790 2.12369783068 -0.247 0.001 -0.123 C -1.76594470239 0.00039861437 2.37754210613 0.152 0.000 -0.191 C -2.24923313135 -0.00145267054 3.67997125809 -0.000 -0.000 0.102 C -1.33887502024 -0.00450793845 4.73956848945 -0.083 0.000 0.008 C 0.02462671625 -0.00591801736 4.46614405978 0.095 -0.000 -0.070 C 0.43187566201 -0.00376957955 3.13352499014 0.074 -0.001 0.200 C -2.63984642995 0.00218980399 1.17162612704 0.013 -0.000 -0.099 N -1.98513620489 0.00132140951 0.00153900685 -0.001 0.000 0.329 C -2.63911589169 0.00167522827 -1.17277445342 -0.015 -0.000 -0.102 C -4.02452897564 0.00329996303 -1.20791476641 0.030 -0.000 -0.113 C -4.73391255267 0.00451580118 -0.00020876193 0.003 0.000 0.183 C -4.02924140493 0.00399189729 1.20660077672 -0.027 0.000 -0.118 Co 0.00000000000 0.00000000000 0.00000000000 0.000 0.000 0.000 N -0.43839318333 -0.00054206762 -2.12229806799 0.248 -0.000 -0.122 C -1.76408906064 -0.00030645034 -2.37697009192 -0.160 -0.000 -0.184 C -2.24773885821 -0.00257631963 -3.67934971086 0.000 0.000 0.103 C -1.33713102227 -0.00526459193 -4.73855802198 0.083 -0.000 0.005 C 0.02654101484 -0.00591797621 -4.46472703619 -0.096 -0.000 -0.069 C 0.43371721952 -0.00363389350 -3.13225443930 -0.069 0.001 0.199 S -6.53329279136 0.00637481657 -0.11611178087 -0.010 -0.000 -0.015 N 2.00981687167 0.00259443239 -0.00000686048 -0.000 -0.000 0.002 C 2.67119656792 1.17263645248 0.00045766926 -0.000 0.000 -0.001 C 4.06129317470 1.20536051565 0.00241240325 0.000 0.000 0.000 C 4.76783866331 0.00148799420 0.00346798881 -0.000 -0.000 -0.000 C 4.05723810074 -1.20352939940 0.00211502115 0.000 0.000 0.000 C 2.67108506586 -1.17139122066 0.00026591651 -0.000 0.000 -0.001 C 1.82209539371 2.39842937406 -0.00175320633 0.000 0.000 -0.000 C 2.33938959521 3.68993217240 -0.00584554905 0.000 -0.000 0.000 C 1.45736908622 4.77231118002 -0.00917967851 -0.000 -0.000 0.000 C 0.08658913130 4.53522926787 -0.00833235387 0.000 0.000 0.000 C -0.35359617412 3.21325694137 -0.00400174376 0.000 -0.000 -0.000 N 0.49290585413 2.18198449515 -0.00068475564 -0.001 0.000 0.000 S 6.56718562933 -0.11349126889 0.00673479967 -0.000 0.000 0.000 C 1.82142022278 -2.39594383179 -0.00206827421 -0.000 0.000 -0.000 C 2.33969079820 -3.68709653410 -0.00625612120 0.000 -0.000 0.000 C 1.45789786198 -4.76953179608 -0.00945089783 0.000 0.000 0.000 C 0.08684213972 -4.53272927032 -0.00840538011 -0.000 0.000 0.000 C -0.35393854068 -3.21111942258 -0.00398541364 -0.000 -0.000 -0.000 N 0.49225266031 -2.17934076887 -0.00084210065 0.000 0.000 0.000 H 1.83694111827 5.77332096953 -0.01265611066 0.001 -0.000 -0.000 H -0.61802819388 5.33967450634 -0.01131742088 -0.000 -0.000 -0.000 H 3.39175422949 3.87200638269 -0.00704552340 -0.000 0.001 -0.001 H -1.39787683933 2.98334799634 -0.00369736757 0.000 -0.000 0.001 H 1.83794742242 -5.77033326187 -0.01295832570 -0.000 -0.000 -0.000 H -0.61749414542 -5.33746053721 -0.01121572048 0.000 -0.000 -0.000 H -1.39833026435 -2.98175334118 -0.00345676225 0.000 0.000 0.001 H 3.39230213722 -3.86796714602 -0.00754158092 0.000 -0.000 -0.001 H 4.58301895157 2.13678100538 0.00314824260 0.000 -0.000 -0.001 H 4.58784714512 -2.12983634010 0.00211631073 -0.000 0.000 -0.001 H -1.68997263563 -0.00719388386 -5.74925805817 -0.311 0.000 0.120 H 0.75224758084 -0.00860493512 -5.25016290812 0.158 0.000 0.152 H -3.29620044300 -0.00255800648 -3.88456579214 0.036 -0.000 -0.154 H 1.47161249279 -0.00457826661 -2.87685200854 -0.003 -0.000 -0.006 H -1.69176120521 -0.00597000955 5.75026973076 0.309 -0.001 0.120 H 0.75025791005 -0.00892914887 5.25161119224 -0.156 -0.000 0.150 H 1.46975366817 -0.00523069331 2.87805400798 0.006 0.000 -0.001 H -3.29750276746 -0.00099200484 3.88584245085 -0.036 0.000 -0.150 H -4.55513299541 0.00377930937 -2.13473279421 -0.090 0.000 0.017 H -4.55107479454 0.00501307822 2.13844314827 0.089 -0.000 0.014 H -6.83436893102 0.00806057203 1.19721860356 0.055 -0.000 0.011 H 6.86748209639 1.20005966818 0.00372860376 0.000 -0.000 -0.000 61 Mode 130: freq=1427.77 N -0.44003451495 -0.00038510790 2.12369783068 -0.092 0.000 -0.035 C -1.76594470239 0.00039861437 2.37754210613 -0.175 0.001 -0.270 C -2.24923313135 -0.00145267054 3.67997125809 0.002 0.000 -0.034 C -1.33887502024 -0.00450793845 4.73956848945 -0.007 -0.000 0.086 C 0.02462671625 -0.00591801736 4.46614405978 -0.013 0.000 -0.031 C 0.43187566201 -0.00376957955 3.13352499014 0.123 -0.000 0.052 C -2.63984642995 0.00218980399 1.17162612704 0.257 -0.000 0.124 N -1.98513620489 0.00132140951 0.00153900685 -0.001 0.000 -0.053 C -2.63911589169 0.00167522827 -1.17277445342 -0.240 0.000 0.108 C -4.02452897564 0.00329996303 -1.20791476641 -0.047 0.000 0.062 C -4.73391255267 0.00451580118 -0.00020876193 -0.007 0.000 0.090 C -4.02924140493 0.00399189729 1.20660077672 0.052 -0.000 0.071 Co 0.00000000000 0.00000000000 0.00000000000 -0.000 -0.000 0.004 N -0.43839318333 -0.00054206762 -2.12229806799 0.084 -0.000 -0.032 C -1.76408906064 -0.00030645034 -2.37697009192 0.162 -0.000 -0.245 C -2.24773885821 -0.00257631963 -3.67934971086 -0.003 -0.000 -0.031 C -1.33713102227 -0.00526459193 -4.73855802198 0.005 0.000 0.078 C 0.02654101484 -0.00591797621 -4.46472703619 0.013 -0.000 -0.028 C 0.43371721952 -0.00363389350 -3.13225443930 -0.113 0.000 0.047 S -6.53329279136 0.00637481657 -0.11611178087 -0.004 -0.000 -0.008 N 2.00981687167 0.00259443239 -0.00000686048 0.000 0.000 -0.001 C 2.67119656792 1.17263645248 0.00045766926 0.001 -0.000 -0.000 C 4.06129317470 1.20536051565 0.00241240325 0.000 -0.000 -0.000 C 4.76783866331 0.00148799420 0.00346798881 -0.000 -0.000 0.000 C 4.05723810074 -1.20352939940 0.00211502115 0.000 -0.000 -0.000 C 2.67108506586 -1.17139122066 0.00026591651 -0.001 -0.000 -0.000 C 1.82209539371 2.39842937406 -0.00175320633 -0.001 0.001 -0.000 C 2.33938959521 3.68993217240 -0.00584554905 0.000 0.000 -0.000 C 1.45736908622 4.77231118002 -0.00917967851 -0.000 -0.000 0.000 C 0.08658913130 4.53522926787 -0.00833235387 -0.000 0.000 0.000 C -0.35359617412 3.21325694137 -0.00400174376 0.000 -0.000 -0.001 N 0.49290585413 2.18198449515 -0.00068475564 -0.000 0.000 0.001 S 6.56718562933 -0.11349126889 0.00673479967 -0.000 0.000 -0.000 C 1.82142022278 -2.39594383179 -0.00206827421 0.000 0.001 -0.000 C 2.33969079820 -3.68709653410 -0.00625612120 0.000 0.000 -0.000 C 1.45789786198 -4.76953179608 -0.00945089783 0.000 -0.000 0.000 C 0.08684213972 -4.53272927032 -0.00840538011 0.000 -0.000 0.000 C -0.35393854068 -3.21111942258 -0.00398541364 -0.000 0.000 -0.001 N 0.49225266031 -2.17934076887 -0.00084210065 0.000 -0.000 0.001 H 1.83694111827 5.77332096953 -0.01265611066 0.000 -0.000 0.000 H -0.61802819388 5.33967450634 -0.01131742088 0.000 0.000 -0.000 H 3.39175422949 3.87200638269 -0.00704552340 0.000 -0.000 0.000 H -1.39787683933 2.98334799634 -0.00369736757 0.000 -0.001 0.001 H 1.83794742242 -5.77033326187 -0.01295832570 -0.000 -0.000 0.000 H -0.61749414542 -5.33746053721 -0.01121572048 0.000 -0.000 -0.000 H -1.39833026435 -2.98175334118 -0.00345676225 -0.000 -0.000 0.001 H 3.39230213722 -3.86796714602 -0.00754158092 -0.000 -0.001 0.000 H 4.58301895157 2.13678100538 0.00314824260 -0.001 0.001 0.000 H 4.58784714512 -2.12983634010 0.00211631073 0.001 0.001 0.000 H -1.68997263563 -0.00719388386 -5.74925805817 -0.043 0.000 0.041 H 0.75224758084 -0.00860493512 -5.25016290812 -0.003 -0.000 -0.014 H -3.29620044300 -0.00255800648 -3.88456579214 -0.024 0.000 0.140 H 1.47161249279 -0.00457826661 -2.87685200854 -0.066 0.000 0.132 H -1.69176120521 -0.00597000955 5.75026973076 0.050 -0.000 0.047 H 0.75025791005 -0.00892914887 5.25161119224 0.003 0.000 -0.014 H 1.46975366817 -0.00523069331 2.87805400798 0.072 -0.000 0.142 H -3.29750276746 -0.00099200484 3.88584245085 0.027 -0.000 0.152 H -4.55513299541 0.00377930937 -2.13473279421 0.417 -0.001 -0.220 H -4.55107479454 0.00501307822 2.13844314827 -0.439 0.001 -0.226 H -6.83436893102 0.00806057203 1.19721860356 0.031 -0.000 0.008 H 6.86748209639 1.20005966818 0.00372860376 0.000 -0.000 0.000 61 Mode 131: freq=1427.85 N -0.44003451495 -0.00038510790 2.12369783068 0.000 -0.001 0.000 C -1.76594470239 0.00039861437 2.37754210613 0.001 0.000 0.001 C -2.24923313135 -0.00145267054 3.67997125809 -0.000 0.000 0.000 C -1.33887502024 -0.00450793845 4.73956848945 0.000 -0.000 -0.000 C 0.02462671625 -0.00591801736 4.46614405978 -0.000 -0.000 0.000 C 0.43187566201 -0.00376957955 3.13352499014 -0.000 0.001 -0.000 C -2.63984642995 0.00218980399 1.17162612704 -0.001 0.000 -0.000 N -1.98513620489 0.00132140951 0.00153900685 0.000 0.001 0.000 C -2.63911589169 0.00167522827 -1.17277445342 0.001 0.000 -0.000 C -4.02452897564 0.00329996303 -1.20791476641 0.000 0.000 -0.000 C -4.73391255267 0.00451580118 -0.00020876193 0.000 -0.000 -0.000 C -4.02924140493 0.00399189729 1.20660077672 -0.000 0.000 -0.000 Co 0.00000000000 0.00000000000 0.00000000000 -0.000 -0.004 -0.000 N -0.43839318333 -0.00054206762 -2.12229806799 -0.000 -0.001 -0.000 C -1.76408906064 -0.00030645034 -2.37697009192 -0.000 0.000 0.001 C -2.24773885821 -0.00257631963 -3.67934971086 -0.000 0.000 0.000 C -1.33713102227 -0.00526459193 -4.73855802198 -0.000 -0.000 -0.000 C 0.02654101484 -0.00591797621 -4.46472703619 -0.000 -0.000 0.000 C 0.43371721952 -0.00363389350 -3.13225443930 0.000 0.001 -0.000 S -6.53329279136 0.00637481657 -0.11611178087 -0.000 0.000 0.000 N 2.00981687167 0.00259443239 -0.00000686048 -0.002 0.068 0.000 C 2.67119656792 1.17263645248 0.00045766926 0.267 -0.138 0.000 C 4.06129317470 1.20536051565 0.00241240325 0.042 -0.078 0.000 C 4.76783866331 0.00148799420 0.00346798881 -0.006 -0.061 -0.000 C 4.05723810074 -1.20352939940 0.00211502115 -0.038 -0.070 -0.000 C 2.67108506586 -1.17139122066 0.00026591651 -0.248 -0.122 -0.000 C 1.82209539371 2.39842937406 -0.00175320633 -0.169 0.282 -0.001 C 2.33938959521 3.68993217240 -0.00584554905 -0.001 0.034 -0.000 C 1.45736908622 4.77231118002 -0.00917967851 -0.005 -0.087 0.000 C 0.08658913130 4.53522926787 -0.00833235387 -0.019 0.027 -0.000 C -0.35359617412 3.21325694137 -0.00400174376 0.115 -0.045 0.000 N 0.49290585413 2.18198449515 -0.00068475564 -0.078 0.026 -0.000 S 6.56718562933 -0.11349126889 0.00673479967 -0.003 0.006 -0.000 C 1.82142022278 -2.39594383179 -0.00206827421 0.159 0.257 0.001 C 2.33969079820 -3.68709653410 -0.00625612120 -0.001 0.030 0.000 C 1.45789786198 -4.76953179608 -0.00945089783 0.003 -0.079 -0.000 C 0.08684213972 -4.53272927032 -0.00840538011 0.019 0.025 0.000 C -0.35393854068 -3.21111942258 -0.00398541364 -0.107 -0.041 -0.000 N 0.49225266031 -2.17934076887 -0.00084210065 0.072 0.025 0.000 H 1.83694111827 5.77332096953 -0.01265611066 0.040 -0.044 0.000 H -0.61802819388 5.33967450634 -0.01131742088 0.004 0.015 -0.000 H 3.39175422949 3.87200638269 -0.00704552340 0.025 -0.174 0.001 H -1.39787683933 2.98334799634 -0.00369736757 0.064 -0.130 0.000 H 1.83794742242 -5.77033326187 -0.01295832570 -0.033 -0.039 -0.000 H -0.61749414542 -5.33746053721 -0.01121572048 -0.004 0.015 0.000 H -1.39833026435 -2.98175334118 -0.00345676225 -0.060 -0.124 -0.000 H 3.39230213722 -3.86796714602 -0.00754158092 -0.023 -0.158 -0.001 H 4.58301895157 2.13678100538 0.00314824260 -0.433 0.217 -0.001 H 4.58784714512 -2.12983634010 0.00211631073 0.412 0.211 0.001 H -1.68997263563 -0.00719388386 -5.74925805817 0.000 -0.000 -0.000 H 0.75224758084 -0.00860493512 -5.25016290812 0.000 0.000 0.000 H -3.29620044300 -0.00255800648 -3.88456579214 0.000 -0.000 -0.001 H 1.47161249279 -0.00457826661 -2.87685200854 0.000 -0.002 0.000 H -1.69176120521 -0.00597000955 5.75026973076 -0.000 0.000 -0.000 H 0.75025791005 -0.00892914887 5.25161119224 0.000 0.000 -0.000 H 1.46975366817 -0.00523069331 2.87805400798 -0.000 -0.002 -0.001 H -3.29750276746 -0.00099200484 3.88584245085 -0.000 -0.000 -0.000 H -4.55513299541 0.00377930937 -2.13473279421 -0.001 -0.000 0.001 H -4.55107479454 0.00501307822 2.13844314827 0.001 -0.000 0.001 H -6.83436893102 0.00806057203 1.19721860356 -0.000 -0.000 -0.000 H 6.86748209639 1.20005966818 0.00372860376 0.023 -0.006 0.000 61 Mode 132: freq=1438.49 N -0.44003451495 -0.00038510790 2.12369783068 -0.110 0.000 -0.088 C -1.76594470239 0.00039861437 2.37754210613 -0.142 -0.000 0.103 C -2.24923313135 -0.00145267054 3.67997125809 0.059 -0.000 -0.026 C -1.33887502024 -0.00450793845 4.73956848945 0.027 0.000 -0.006 C 0.02462671625 -0.00591801736 4.46614405978 0.024 -0.000 -0.018 C 0.43187566201 -0.00376957955 3.13352499014 0.094 -0.000 0.037 C -2.63984642995 0.00218980399 1.17162612704 -0.032 0.000 0.064 N -1.98513620489 0.00132140951 0.00153900685 0.032 -0.000 -0.001 C -2.63911589169 0.00167522827 -1.17277445342 -0.028 0.000 -0.066 C -4.02452897564 0.00329996303 -1.20791476641 0.043 -0.000 -0.007 C -4.73391255267 0.00451580118 -0.00020876193 -0.029 0.000 0.001 C -4.02924140493 0.00399189729 1.20660077672 0.045 -0.000 0.007 Co 0.00000000000 0.00000000000 0.00000000000 0.009 0.000 -0.000 N -0.43839318333 -0.00054206762 -2.12229806799 -0.110 0.000 0.086 C -1.76408906064 -0.00030645034 -2.37697009192 -0.139 -0.000 -0.095 C -2.24773885821 -0.00257631963 -3.67934971086 0.057 0.000 0.028 C -1.33713102227 -0.00526459193 -4.73855802198 0.025 0.000 0.003 C 0.02654101484 -0.00591797621 -4.46472703619 0.023 0.000 0.018 C 0.43371721952 -0.00363389350 -3.13225443930 0.094 -0.000 -0.038 S -6.53329279136 0.00637481657 -0.11611178087 0.001 0.000 0.000 N 2.00981687167 0.00259443239 -0.00000686048 0.035 0.002 0.000 C 2.67119656792 1.17263645248 0.00045766926 -0.042 -0.072 -0.000 C 4.06129317470 1.20536051565 0.00241240325 0.058 -0.012 0.000 C 4.76783866331 0.00148799420 0.00346798881 -0.036 -0.003 -0.000 C 4.05723810074 -1.20352939940 0.00211502115 0.055 0.011 0.000 C 2.67108506586 -1.17139122066 0.00026591651 -0.040 0.075 -0.000 C 1.82209539371 2.39842937406 -0.00175320633 -0.177 -0.125 0.000 C 2.33938959521 3.68993217240 -0.00584554905 0.071 0.036 -0.000 C 1.45736908622 4.77231118002 -0.00917967851 0.034 0.005 -0.000 C 0.08658913130 4.53522926787 -0.00833235387 0.029 0.020 -0.000 C -0.35359617412 3.21325694137 -0.00400174376 0.117 -0.049 0.000 N 0.49290585413 2.18198449515 -0.00068475564 -0.131 0.114 -0.000 S 6.56718562933 -0.11349126889 0.00673479967 0.001 -0.000 -0.000 C 1.82142022278 -2.39594383179 -0.00206827421 -0.170 0.115 0.000 C 2.33969079820 -3.68709653410 -0.00625612120 0.067 -0.038 -0.000 C 1.45789786198 -4.76953179608 -0.00945089783 0.031 -0.002 -0.000 C 0.08684213972 -4.53272927032 -0.00840538011 0.028 -0.020 -0.000 C -0.35393854068 -3.21111942258 -0.00398541364 0.113 0.048 0.000 N 0.49225266031 -2.17934076887 -0.00084210065 -0.128 -0.109 -0.000 H 1.83694111827 5.77332096953 -0.01265611066 -0.016 0.012 -0.000 H -0.61802819388 5.33967450634 -0.01131742088 0.018 0.014 -0.000 H 3.39175422949 3.87200638269 -0.00704552340 -0.018 0.271 -0.001 H -1.39787683933 2.98334799634 -0.00369736757 0.109 -0.329 0.001 H 1.83794742242 -5.77033326187 -0.01295832570 -0.011 -0.009 -0.000 H -0.61749414542 -5.33746053721 -0.01121572048 0.018 -0.013 -0.000 H -1.39833026435 -2.98175334118 -0.00345676225 0.105 0.315 0.001 H 3.39230213722 -3.86796714602 -0.00754158092 -0.016 -0.257 -0.001 H 4.58301895157 2.13678100538 0.00314824260 0.066 -0.029 0.000 H 4.58784714512 -2.12983634010 0.00211631073 0.074 0.034 0.000 H -1.68997263563 -0.00719388386 -5.74925805817 -0.013 0.000 0.009 H 0.75224758084 -0.00860493512 -5.25016290812 0.012 -0.000 0.010 H -3.29620044300 -0.00255800648 -3.88456579214 -0.018 0.000 0.211 H 1.47161249279 -0.00457826661 -2.87685200854 0.092 -0.001 -0.255 H -1.69176120521 -0.00597000955 5.75026973076 -0.017 0.000 -0.011 H 0.75025791005 -0.00892914887 5.25161119224 0.012 -0.000 -0.010 H 1.46975366817 -0.00523069331 2.87805400798 0.094 -0.001 0.261 H -3.29750276746 -0.00099200484 3.88584245085 -0.019 0.000 -0.220 H -4.55513299541 0.00377930937 -2.13473279421 0.051 -0.000 -0.023 H -4.55107479454 0.00501307822 2.13844314827 0.049 -0.000 0.021 H -6.83436893102 0.00806057203 1.19721860356 -0.001 0.000 -0.000 H 6.86748209639 1.20005966818 0.00372860376 -0.001 0.000 0.000 61 Mode 133: freq=1444.91 N -0.44003451495 -0.00038510790 2.12369783068 -0.125 0.001 -0.116 C -1.76594470239 0.00039861437 2.37754210613 -0.174 -0.000 0.142 C -2.24923313135 -0.00145267054 3.67997125809 0.070 -0.000 -0.027 C -1.33887502024 -0.00450793845 4.73956848945 0.043 0.000 -0.011 C 0.02462671625 -0.00591801736 4.46614405978 0.027 -0.000 -0.017 C 0.43187566201 -0.00376957955 3.13352499014 0.111 -0.000 0.033 C -2.63984642995 0.00218980399 1.17162612704 -0.038 0.000 0.057 N -1.98513620489 0.00132140951 0.00153900685 0.038 0.000 -0.002 C -2.63911589169 0.00167522827 -1.17277445342 -0.035 0.000 -0.062 C -4.02452897564 0.00329996303 -1.20791476641 0.043 -0.000 -0.010 C -4.73391255267 0.00451580118 -0.00020876193 -0.026 0.000 0.003 C -4.02924140493 0.00399189729 1.20660077672 0.046 -0.000 0.010 Co 0.00000000000 0.00000000000 0.00000000000 0.002 -0.000 -0.000 N -0.43839318333 -0.00054206762 -2.12229806799 -0.120 0.000 0.109 C -1.76408906064 -0.00030645034 -2.37697009192 -0.165 -0.000 -0.127 C -2.24773885821 -0.00257631963 -3.67934971086 0.065 -0.000 0.030 C -1.33713102227 -0.00526459193 -4.73855802198 0.038 0.000 0.008 C 0.02654101484 -0.00591797621 -4.46472703619 0.026 -0.000 0.016 C 0.43371721952 -0.00363389350 -3.13225443930 0.107 -0.000 -0.033 S -6.53329279136 0.00637481657 -0.11611178087 0.001 -0.000 -0.000 N 2.00981687167 0.00259443239 -0.00000686048 -0.029 -0.003 0.000 C 2.67119656792 1.17263645248 0.00045766926 0.030 0.035 0.000 C 4.06129317470 1.20536051565 0.00241240325 -0.037 0.012 -0.000 C 4.76783866331 0.00148799420 0.00346798881 0.020 0.008 0.000 C 4.05723810074 -1.20352939940 0.00211502115 -0.035 -0.014 -0.000 C 2.67108506586 -1.17139122066 0.00026591651 0.031 -0.043 0.000 C 1.82209539371 2.39842937406 -0.00175320633 0.150 0.125 -0.000 C 2.33938959521 3.68993217240 -0.00584554905 -0.059 -0.025 0.000 C 1.45736908622 4.77231118002 -0.00917967851 -0.038 -0.009 0.000 C 0.08658913130 4.53522926787 -0.00833235387 -0.023 -0.012 0.000 C -0.35359617412 3.21325694137 -0.00400174376 -0.093 0.028 -0.000 N 0.49290585413 2.18198449515 -0.00068475564 0.102 -0.101 0.000 S 6.56718562933 -0.11349126889 0.00673479967 -0.001 -0.000 0.000 C 1.82142022278 -2.39594383179 -0.00206827421 0.128 -0.096 -0.000 C 2.33969079820 -3.68709653410 -0.00625612120 -0.048 0.026 0.000 C 1.45789786198 -4.76953179608 -0.00945089783 -0.030 0.004 0.000 C 0.08684213972 -4.53272927032 -0.00840538011 -0.020 0.010 0.000 C -0.35393854068 -3.21111942258 -0.00398541364 -0.082 -0.026 -0.000 N 0.49225266031 -2.17934076887 -0.00084210065 0.088 0.086 0.000 H 1.83694111827 5.77332096953 -0.01265611066 0.030 -0.019 0.000 H -0.61802819388 5.33967450634 -0.01131742088 -0.014 -0.009 0.000 H 3.39175422949 3.87200638269 -0.00704552340 0.016 -0.236 0.001 H -1.39787683933 2.98334799634 -0.00369736757 -0.094 0.289 -0.001 H 1.83794742242 -5.77033326187 -0.01295832570 0.018 0.012 0.000 H -0.61749414542 -5.33746053721 -0.01121572048 -0.013 0.008 0.000 H -1.39833026435 -2.98175334118 -0.00345676225 -0.080 -0.245 -0.001 H 3.39230213722 -3.86796714602 -0.00754158092 0.013 0.195 0.001 H 4.58301895157 2.13678100538 0.00314824260 -0.050 0.024 -0.000 H 4.58784714512 -2.12983634010 0.00211631073 -0.059 -0.031 -0.000 H -1.68997263563 -0.00719388386 -5.74925805817 -0.029 0.000 0.017 H 0.75224758084 -0.00860493512 -5.25016290812 0.014 0.000 0.009 H -3.29620044300 -0.00255800648 -3.88456579214 -0.023 0.001 0.255 H 1.47161249279 -0.00457826661 -2.87685200854 0.113 -0.001 -0.316 H -1.69176120521 -0.00597000955 5.75026973076 -0.036 0.000 -0.022 H 0.75025791005 -0.00892914887 5.25161119224 0.014 0.000 -0.009 H 1.46975366817 -0.00523069331 2.87805400798 0.119 -0.001 0.335 H -3.29750276746 -0.00099200484 3.88584245085 -0.025 0.001 -0.275 H -4.55513299541 0.00377930937 -2.13473279421 0.065 -0.000 -0.031 H -4.55107479454 0.00501307822 2.13844314827 0.061 -0.000 0.028 H -6.83436893102 0.00806057203 1.19721860356 -0.001 0.000 -0.000 H 6.86748209639 1.20005966818 0.00372860376 -0.001 0.000 -0.000 61 Mode 134: freq=1446.89 N -0.44003451495 -0.00038510790 2.12369783068 -0.005 -0.002 -0.005 C -1.76594470239 0.00039861437 2.37754210613 -0.007 0.000 0.006 C -2.24923313135 -0.00145267054 3.67997125809 0.003 0.000 -0.001 C -1.33887502024 -0.00450793845 4.73956848945 0.002 0.000 -0.000 C 0.02462671625 -0.00591801736 4.46614405978 0.001 0.000 -0.001 C 0.43187566201 -0.00376957955 3.13352499014 0.004 0.000 0.001 C -2.63984642995 0.00218980399 1.17162612704 -0.002 0.001 0.002 N -1.98513620489 0.00132140951 0.00153900685 0.002 -0.001 -0.000 C -2.63911589169 0.00167522827 -1.17277445342 -0.001 0.001 -0.002 C -4.02452897564 0.00329996303 -1.20791476641 0.002 0.000 -0.000 C -4.73391255267 0.00451580118 -0.00020876193 -0.001 -0.000 0.000 C -4.02924140493 0.00399189729 1.20660077672 0.002 0.000 0.000 Co 0.00000000000 0.00000000000 0.00000000000 -0.000 0.002 -0.000 N -0.43839318333 -0.00054206762 -2.12229806799 -0.005 -0.002 0.005 C -1.76408906064 -0.00030645034 -2.37697009192 -0.007 0.000 -0.006 C -2.24773885821 -0.00257631963 -3.67934971086 0.003 0.000 0.001 C -1.33713102227 -0.00526459193 -4.73855802198 0.002 0.000 0.000 C 0.02654101484 -0.00591797621 -4.46472703619 0.001 0.000 0.001 C 0.43371721952 -0.00363389350 -3.13225443930 0.004 0.000 -0.001 S -6.53329279136 0.00637481657 -0.11611178087 0.000 0.000 -0.000 N 2.00981687167 0.00259443239 -0.00000686048 -0.003 0.047 -0.000 C 2.67119656792 1.17263645248 0.00045766926 0.012 0.064 -0.000 C 4.06129317470 1.20536051565 0.00241240325 -0.001 0.031 0.000 C 4.76783866331 0.00148799420 0.00346798881 -0.000 -0.141 0.000 C 4.05723810074 -1.20352939940 0.00211502115 -0.003 0.031 -0.000 C 2.67108506586 -1.17139122066 0.00026591651 -0.002 0.060 0.000 C 1.82209539371 2.39842937406 -0.00175320633 -0.178 -0.241 0.001 C 2.33938959521 3.68993217240 -0.00584554905 0.090 -0.001 0.000 C 1.45736908622 4.77231118002 -0.00917967851 0.072 0.035 -0.000 C 0.08658913130 4.53522926787 -0.00833235387 0.024 0.011 -0.000 C -0.35359617412 3.21325694137 -0.00400174376 0.097 -0.012 0.000 N 0.49290585413 2.18198449515 -0.00068475564 -0.123 0.125 -0.000 S 6.56718562933 -0.11349126889 0.00673479967 -0.005 0.009 -0.000 C 1.82142022278 -2.39594383179 -0.00206827421 0.195 -0.265 -0.001 C 2.33969079820 -3.68709653410 -0.00625612120 -0.099 0.004 0.000 C 1.45789786198 -4.76953179608 -0.00945089783 -0.078 0.037 0.000 C 0.08684213972 -4.53272927032 -0.00840538011 -0.029 0.012 0.000 C -0.35393854068 -3.21111942258 -0.00398541364 -0.109 -0.015 -0.000 N 0.49225266031 -2.17934076887 -0.00084210065 0.138 0.139 0.000 H 1.83694111827 5.77332096953 -0.01265611066 -0.094 0.057 -0.000 H -0.61802819388 5.33967450634 -0.01131742088 0.006 0.002 0.000 H 3.39175422949 3.87200638269 -0.00704552340 -0.024 0.346 -0.001 H -1.39787683933 2.98334799634 -0.00369736757 0.116 -0.376 0.001 H 1.83794742242 -5.77033326187 -0.01295832570 0.097 0.059 0.000 H -0.61749414542 -5.33746053721 -0.01121572048 -0.007 0.002 0.000 H -1.39833026435 -2.98175334118 -0.00345676225 -0.129 -0.415 -0.001 H 3.39230213722 -3.86796714602 -0.00754158092 0.027 0.384 0.001 H 4.58301895157 2.13678100538 0.00314824260 -0.054 0.041 -0.000 H 4.58784714512 -2.12983634010 0.00211631073 0.036 0.032 0.000 H -1.68997263563 -0.00719388386 -5.74925805817 -0.001 -0.000 0.001 H 0.75224758084 -0.00860493512 -5.25016290812 0.001 -0.000 0.000 H -3.29620044300 -0.00255800648 -3.88456579214 -0.001 -0.001 0.011 H 1.47161249279 -0.00457826661 -2.87685200854 0.005 -0.000 -0.013 H -1.69176120521 -0.00597000955 5.75026973076 -0.002 -0.000 -0.001 H 0.75025791005 -0.00892914887 5.25161119224 0.001 -0.000 -0.000 H 1.46975366817 -0.00523069331 2.87805400798 0.005 -0.000 0.014 H -3.29750276746 -0.00099200484 3.88584245085 -0.001 -0.001 -0.011 H -4.55513299541 0.00377930937 -2.13473279421 0.003 -0.001 -0.001 H -4.55107479454 0.00501307822 2.13844314827 0.003 -0.001 0.001 H -6.83436893102 0.00806057203 1.19721860356 -0.000 -0.000 -0.000 H 6.86748209639 1.20005966818 0.00372860376 0.032 -0.007 0.000 61 Mode 135: freq=1449.30 N -0.44003451495 -0.00038510790 2.12369783068 -0.122 0.000 -0.122 C -1.76594470239 0.00039861437 2.37754210613 -0.172 -0.000 0.260 C -2.24923313135 -0.00145267054 3.67997125809 0.093 -0.000 0.005 C -1.33887502024 -0.00450793845 4.73956848945 0.077 0.000 -0.042 C 0.02462671625 -0.00591801736 4.46614405978 0.025 -0.000 -0.011 C 0.43187566201 -0.00376957955 3.13352499014 0.092 -0.000 0.002 C -2.63984642995 0.00218980399 1.17162612704 0.002 0.000 -0.063 N -1.98513620489 0.00132140951 0.00153900685 -0.001 0.000 -0.055 C -2.63911589169 0.00167522827 -1.17277445342 0.004 -0.000 -0.061 C -4.02452897564 0.00329996303 -1.20791476641 0.001 -0.000 -0.031 C -4.73391255267 0.00451580118 -0.00020876193 -0.001 0.000 0.130 C -4.02924140493 0.00399189729 1.20660077672 -0.003 -0.000 -0.030 Co 0.00000000000 0.00000000000 0.00000000000 -0.000 0.000 -0.001 N -0.43839318333 -0.00054206762 -2.12229806799 0.131 -0.000 -0.130 C -1.76408906064 -0.00030645034 -2.37697009192 0.179 0.000 0.275 C -2.24773885821 -0.00257631963 -3.67934971086 -0.097 0.000 0.002 C -1.33713102227 -0.00526459193 -4.73855802198 -0.080 -0.000 -0.044 C 0.02654101484 -0.00591797621 -4.46472703619 -0.027 0.000 -0.011 C 0.43371721952 -0.00363389350 -3.13225443930 -0.097 0.000 0.003 S -6.53329279136 0.00637481657 -0.11611178087 -0.005 -0.000 -0.008 N 2.00981687167 0.00259443239 -0.00000686048 0.000 -0.000 0.000 C 2.67119656792 1.17263645248 0.00045766926 -0.000 -0.000 -0.001 C 4.06129317470 1.20536051565 0.00241240325 0.000 -0.000 -0.000 C 4.76783866331 0.00148799420 0.00346798881 -0.000 -0.000 0.000 C 4.05723810074 -1.20352939940 0.00211502115 0.000 0.000 -0.000 C 2.67108506586 -1.17139122066 0.00026591651 -0.000 0.000 -0.001 C 1.82209539371 2.39842937406 -0.00175320633 -0.002 -0.002 -0.000 C 2.33938959521 3.68993217240 -0.00584554905 0.001 0.000 -0.000 C 1.45736908622 4.77231118002 -0.00917967851 0.001 0.000 -0.000 C 0.08658913130 4.53522926787 -0.00833235387 0.000 0.000 -0.000 C -0.35359617412 3.21325694137 -0.00400174376 0.001 -0.000 -0.000 N 0.49290585413 2.18198449515 -0.00068475564 -0.001 0.001 0.002 S 6.56718562933 -0.11349126889 0.00673479967 0.000 0.000 -0.000 C 1.82142022278 -2.39594383179 -0.00206827421 -0.002 0.001 -0.000 C 2.33969079820 -3.68709653410 -0.00625612120 0.001 -0.000 -0.000 C 1.45789786198 -4.76953179608 -0.00945089783 0.000 -0.000 -0.000 C 0.08684213972 -4.53272927032 -0.00840538011 0.000 -0.000 -0.000 C -0.35393854068 -3.21111942258 -0.00398541364 0.001 0.000 -0.000 N 0.49225266031 -2.17934076887 -0.00084210065 -0.001 -0.001 0.002 H 1.83694111827 5.77332096953 -0.01265611066 -0.001 0.000 0.000 H -0.61802819388 5.33967450634 -0.01131742088 0.000 0.000 0.000 H 3.39175422949 3.87200638269 -0.00704552340 -0.000 0.003 0.001 H -1.39787683933 2.98334799634 -0.00369736757 0.001 -0.004 0.000 H 1.83794742242 -5.77033326187 -0.01295832570 -0.000 -0.000 0.000 H -0.61749414542 -5.33746053721 -0.01121572048 0.000 -0.000 0.000 H -1.39833026435 -2.98175334118 -0.00345676225 0.001 0.003 0.000 H 3.39230213722 -3.86796714602 -0.00754158092 -0.000 -0.003 0.001 H 4.58301895157 2.13678100538 0.00314824260 0.001 -0.000 0.001 H 4.58784714512 -2.12983634010 0.00211631073 0.001 0.000 0.001 H -1.68997263563 -0.00719388386 -5.74925805817 0.109 -0.000 -0.062 H 0.75224758084 -0.00860493512 -5.25016290812 -0.002 0.000 0.003 H -3.29620044300 -0.00255800648 -3.88456579214 0.037 -0.001 -0.383 H 1.47161249279 -0.00457826661 -2.87685200854 -0.132 0.001 0.397 H -1.69176120521 -0.00597000955 5.75026973076 -0.107 0.000 -0.061 H 0.75025791005 -0.00892914887 5.25161119224 0.002 -0.000 0.002 H 1.46975366817 -0.00523069331 2.87805400798 0.126 -0.001 0.377 H -3.29750276746 -0.00099200484 3.88584245085 -0.035 0.001 -0.362 H -4.55513299541 0.00377930937 -2.13473279421 0.025 -0.000 -0.025 H -4.55107479454 0.00501307822 2.13844314827 -0.037 0.000 -0.031 H -6.83436893102 0.00806057203 1.19721860356 0.029 -0.000 0.006 H 6.86748209639 1.20005966818 0.00372860376 0.000 -0.000 0.000 61 Mode 136: freq=1487.47 N -0.44003451495 -0.00038510790 2.12369783068 0.009 0.000 -0.003 C -1.76594470239 0.00039861437 2.37754210613 0.011 -0.000 0.039 C -2.24923313135 -0.00145267054 3.67997125809 0.004 -0.000 0.014 C -1.33887502024 -0.00450793845 4.73956848945 0.007 0.000 -0.013 C 0.02462671625 -0.00591801736 4.46614405978 0.001 -0.000 0.000 C 0.43187566201 -0.00376957955 3.13352499014 -0.011 0.000 -0.003 C -2.63984642995 0.00218980399 1.17162612704 -0.031 0.000 -0.043 N -1.98513620489 0.00132140951 0.00153900685 0.008 -0.000 0.001 C -2.63911589169 0.00167522827 -1.17277445342 -0.036 0.000 0.042 C -4.02452897564 0.00329996303 -1.20791476641 -0.010 0.000 0.004 C -4.73391255267 0.00451580118 -0.00020876193 0.040 -0.000 0.001 C -4.02924140493 0.00399189729 1.20660077672 -0.012 0.000 -0.004 Co 0.00000000000 0.00000000000 0.00000000000 -0.003 -0.000 0.000 N -0.43839318333 -0.00054206762 -2.12229806799 0.011 0.000 0.003 C -1.76408906064 -0.00030645034 -2.37697009192 0.013 -0.000 -0.040 C -2.24773885821 -0.00257631963 -3.67934971086 0.004 -0.000 -0.015 C -1.33713102227 -0.00526459193 -4.73855802198 0.007 0.000 0.014 C 0.02654101484 -0.00591797621 -4.46472703619 0.001 -0.000 -0.000 C 0.43371721952 -0.00363389350 -3.13225443930 -0.012 0.000 0.003 S -6.53329279136 0.00637481657 -0.11611178087 -0.004 0.000 -0.000 N 2.00981687167 0.00259443239 -0.00000686048 0.058 -0.007 0.000 C 2.67119656792 1.17263645248 0.00045766926 -0.247 0.327 -0.001 C 4.06129317470 1.20536051565 0.00241240325 -0.081 0.034 -0.000 C 4.76783866331 0.00148799420 0.00346798881 0.311 -0.006 0.000 C 4.05723810074 -1.20352939940 0.00211502115 -0.069 -0.036 -0.000 C 2.67108506586 -1.17139122066 0.00026591651 -0.283 -0.324 -0.001 C 1.82209539371 2.39842937406 -0.00175320633 0.120 -0.266 0.001 C 2.33938959521 3.68993217240 -0.00584554905 0.019 -0.107 0.000 C 1.45736908622 4.77231118002 -0.00917967851 0.032 0.090 -0.000 C 0.08658913130 4.53522926787 -0.00833235387 0.013 0.003 0.000 C -0.35359617412 3.21325694137 -0.00400174376 -0.103 0.027 -0.000 N 0.49290585413 2.18198449515 -0.00068475564 0.094 -0.020 0.000 S 6.56718562933 -0.11349126889 0.00673479967 -0.034 0.001 -0.000 C 1.82142022278 -2.39594383179 -0.00206827421 0.130 0.277 0.001 C 2.33969079820 -3.68709653410 -0.00625612120 0.019 0.110 0.000 C 1.45789786198 -4.76953179608 -0.00945089783 0.030 -0.095 -0.000 C 0.08684213972 -4.53272927032 -0.00840538011 0.014 -0.003 0.000 C -0.35393854068 -3.21111942258 -0.00398541364 -0.111 -0.026 -0.000 N 0.49225266031 -2.17934076887 -0.00084210065 0.105 0.025 0.000 H 1.83694111827 5.77332096953 -0.01265611066 -0.100 0.073 -0.000 H -0.61802819388 5.33967450634 -0.01131742088 -0.021 -0.018 0.000 H 3.39175422949 3.87200638269 -0.00704552340 -0.029 0.204 -0.001 H -1.39787683933 2.98334799634 -0.00369736757 -0.054 0.094 -0.000 H 1.83794742242 -5.77033326187 -0.01295832570 -0.100 -0.074 -0.000 H -0.61749414542 -5.33746053721 -0.01121572048 -0.020 0.017 0.000 H -1.39833026435 -2.98175334118 -0.00345676225 -0.061 -0.113 -0.000 H 3.39230213722 -3.86796714602 -0.00754158092 -0.030 -0.210 -0.001 H 4.58301895157 2.13678100538 0.00314824260 0.184 -0.096 0.000 H 4.58784714512 -2.12983634010 0.00211631073 0.211 0.110 0.000 H -1.68997263563 -0.00719388386 -5.74925805817 -0.016 0.000 0.011 H 0.75224758084 -0.00860493512 -5.25016290812 -0.002 0.000 -0.002 H -3.29620044300 -0.00255800648 -3.88456579214 -0.006 0.000 0.035 H 1.47161249279 -0.00457826661 -2.87685200854 -0.004 -0.000 0.002 H -1.69176120521 -0.00597000955 5.75026973076 -0.016 0.000 -0.011 H 0.75025791005 -0.00892914887 5.25161119224 -0.002 0.000 0.002 H 1.46975366817 -0.00523069331 2.87805400798 -0.003 -0.000 0.000 H -3.29750276746 -0.00099200484 3.88584245085 -0.005 0.000 -0.034 H -4.55513299541 0.00377930937 -2.13473279421 0.029 -0.000 -0.015 H -4.55107479454 0.00501307822 2.13844314827 0.025 -0.000 0.014 H -6.83436893102 0.00806057203 1.19721860356 -0.002 -0.000 0.000 H 6.86748209639 1.20005966818 0.00372860376 -0.012 -0.001 -0.000 61 Mode 137: freq=1489.42 N -0.44003451495 -0.00038510790 2.12369783068 -0.099 0.000 -0.021 C -1.76594470239 0.00039861437 2.37754210613 -0.123 0.000 -0.258 C -2.24923313135 -0.00145267054 3.67997125809 -0.022 0.000 -0.111 C -1.33887502024 -0.00450793845 4.73956848945 -0.033 -0.000 0.091 C 0.02462671625 -0.00591801736 4.46614405978 -0.012 0.000 0.004 C 0.43187566201 -0.00376957955 3.13352499014 0.105 -0.000 0.027 C -2.63984642995 0.00218980399 1.17162612704 0.247 -0.000 0.317 N -1.98513620489 0.00132140951 0.00153900685 -0.057 0.000 -0.008 C -2.63911589169 0.00167522827 -1.17277445342 0.283 -0.001 -0.313 C -4.02452897564 0.00329996303 -1.20791476641 0.075 -0.000 -0.041 C -4.73391255267 0.00451580118 -0.00020876193 -0.315 0.000 -0.007 C -4.02924140493 0.00399189729 1.20660077672 0.086 -0.000 0.040 Co 0.00000000000 0.00000000000 0.00000000000 0.003 -0.000 -0.000 N -0.43839318333 -0.00054206762 -2.12229806799 -0.110 0.000 0.025 C -1.76408906064 -0.00030645034 -2.37697009192 -0.133 0.000 0.270 C -2.24773885821 -0.00257631963 -3.67934971086 -0.022 0.000 0.115 C -1.33713102227 -0.00526459193 -4.73855802198 -0.031 -0.000 -0.096 C 0.02654101484 -0.00591797621 -4.46472703619 -0.012 0.000 -0.003 C 0.43371721952 -0.00363389350 -3.13225443930 0.113 -0.000 -0.026 S -6.53329279136 0.00637481657 -0.11611178087 0.034 -0.000 0.001 N 2.00981687167 0.00259443239 -0.00000686048 0.007 -0.001 0.000 C 2.67119656792 1.17263645248 0.00045766926 -0.035 0.041 -0.000 C 4.06129317470 1.20536051565 0.00241240325 -0.010 0.006 -0.000 C 4.76783866331 0.00148799420 0.00346798881 0.042 -0.001 0.000 C 4.05723810074 -1.20352939940 0.00211502115 -0.008 -0.006 -0.000 C 2.67108506586 -1.17139122066 0.00026591651 -0.040 -0.041 -0.000 C 1.82209539371 2.39842937406 -0.00175320633 0.020 -0.030 0.000 C 2.33938959521 3.68993217240 -0.00584554905 0.001 -0.014 0.000 C 1.45736908622 4.77231118002 -0.00917967851 0.001 0.011 -0.000 C 0.08658913130 4.53522926787 -0.00833235387 0.002 0.001 -0.000 C -0.35359617412 3.21325694137 -0.00400174376 -0.016 0.004 0.000 N 0.49290585413 2.18198449515 -0.00068475564 0.016 -0.008 0.000 S 6.56718562933 -0.11349126889 0.00673479967 -0.005 0.000 -0.000 C 1.82142022278 -2.39594383179 -0.00206827421 0.022 0.032 0.000 C 2.33969079820 -3.68709653410 -0.00625612120 0.001 0.015 0.000 C 1.45789786198 -4.76953179608 -0.00945089783 0.001 -0.012 -0.000 C 0.08684213972 -4.53272927032 -0.00840538011 0.002 -0.001 -0.000 C -0.35393854068 -3.21111942258 -0.00398541364 -0.017 -0.004 0.000 N 0.49225266031 -2.17934076887 -0.00084210065 0.017 0.008 0.000 H 1.83694111827 5.77332096953 -0.01265611066 -0.011 0.008 -0.000 H -0.61802819388 5.33967450634 -0.01131742088 -0.004 -0.003 0.000 H 3.39175422949 3.87200638269 -0.00704552340 -0.003 0.020 -0.000 H -1.39787683933 2.98334799634 -0.00369736757 -0.011 0.024 -0.000 H 1.83794742242 -5.77033326187 -0.01295832570 -0.011 -0.008 -0.000 H -0.61749414542 -5.33746053721 -0.01121572048 -0.003 0.003 0.000 H -1.39833026435 -2.98175334118 -0.00345676225 -0.012 -0.026 -0.000 H 3.39230213722 -3.86796714602 -0.00754158092 -0.003 -0.021 -0.000 H 4.58301895157 2.13678100538 0.00314824260 0.025 -0.012 0.000 H 4.58784714512 -2.12983634010 0.00211631073 0.029 0.014 0.000 H -1.68997263563 -0.00719388386 -5.74925805817 0.108 -0.000 -0.074 H 0.75224758084 -0.00860493512 -5.25016290812 0.021 0.000 0.019 H -3.29620044300 -0.00255800648 -3.88456579214 0.035 -0.000 -0.210 H 1.47161249279 -0.00457826661 -2.87685200854 0.064 -0.000 -0.111 H -1.69176120521 -0.00597000955 5.75026973076 0.108 -0.000 0.072 H 0.75025791005 -0.00892914887 5.25161119224 0.022 0.000 -0.020 H 1.46975366817 -0.00523069331 2.87805400798 0.057 -0.000 0.094 H -3.29750276746 -0.00099200484 3.88584245085 0.034 -0.000 0.203 H -4.55513299541 0.00377930937 -2.13473279421 -0.215 0.000 0.113 H -4.55107479454 0.00501307822 2.13844314827 -0.188 0.000 -0.098 H -6.83436893102 0.00806057203 1.19721860356 0.012 -0.000 -0.001 H 6.86748209639 1.20005966818 0.00372860376 -0.002 -0.000 -0.000 61 Mode 138: freq=1570.89 N -0.44003451495 -0.00038510790 2.12369783068 0.010 0.000 0.019 C -1.76594470239 0.00039861437 2.37754210613 0.007 -0.000 -0.005 C -2.24923313135 -0.00145267054 3.67997125809 -0.009 -0.000 0.019 C -1.33887502024 -0.00450793845 4.73956848945 0.022 -0.000 0.010 C 0.02462671625 -0.00591801736 4.46614405978 0.012 0.000 -0.019 C 0.43187566201 -0.00376957955 3.13352499014 -0.021 0.000 -0.015 C -2.63984642995 0.00218980399 1.17162612704 0.027 -0.000 -0.044 N -1.98513620489 0.00132140951 0.00153900685 -0.033 0.000 -0.001 C -2.63911589169 0.00167522827 -1.17277445342 0.040 -0.000 0.043 C -4.02452897564 0.00329996303 -1.20791476641 -0.002 0.000 -0.023 C -4.73391255267 0.00451580118 -0.00020876193 -0.020 0.000 0.009 C -4.02924140493 0.00399189729 1.20660077672 0.007 0.000 0.017 Co 0.00000000000 0.00000000000 0.00000000000 0.002 -0.000 -0.000 N -0.43839318333 -0.00054206762 -2.12229806799 0.004 0.000 -0.019 C -1.76408906064 -0.00030645034 -2.37697009192 0.008 -0.000 0.006 C -2.24773885821 -0.00257631963 -3.67934971086 -0.011 -0.000 -0.014 C -1.33713102227 -0.00526459193 -4.73855802198 0.022 -0.000 -0.013 C 0.02654101484 -0.00591797621 -4.46472703619 0.013 0.000 0.017 C 0.43371721952 -0.00363389350 -3.13225443930 -0.020 0.000 0.019 S -6.53329279136 0.00637481657 -0.11611178087 0.002 0.000 -0.001 N 2.00981687167 0.00259443239 -0.00000686048 0.195 -0.003 0.000 C 2.67119656792 1.17263645248 0.00045766926 -0.190 -0.271 -0.000 C 4.06129317470 1.20536051565 0.00241240325 -0.032 0.110 -0.000 C 4.76783866331 0.00148799420 0.00346798881 0.128 0.050 0.000 C 4.05723810074 -1.20352939940 0.00211502115 0.015 -0.140 -0.000 C 2.67108506586 -1.17139122066 0.00026591651 -0.257 0.264 -0.000 C 1.82209539371 2.39842937406 -0.00175320633 -0.035 -0.032 0.000 C 2.33938959521 3.68993217240 -0.00584554905 0.069 0.107 -0.000 C 1.45736908622 4.77231118002 -0.00917967851 -0.161 0.076 -0.000 C 0.08658913130 4.53522926787 -0.00833235387 -0.077 -0.103 0.000 C -0.35359617412 3.21325694137 -0.00400174376 0.106 -0.108 0.000 N 0.49290585413 2.18198449515 -0.00068475564 -0.033 0.074 -0.000 S 6.56718562933 -0.11349126889 0.00673479967 -0.013 -0.004 -0.000 C 1.82142022278 -2.39594383179 -0.00206827421 -0.041 0.035 0.000 C 2.33969079820 -3.68709653410 -0.00625612120 0.076 -0.080 -0.000 C 1.45789786198 -4.76953179608 -0.00945089783 -0.162 -0.090 -0.000 C 0.08684213972 -4.53272927032 -0.00840538011 -0.083 0.096 0.000 C -0.35393854068 -3.21111942258 -0.00398541364 0.099 0.130 0.000 N 0.49225266031 -2.17934076887 -0.00084210065 -0.002 -0.072 -0.000 H 1.83694111827 5.77332096953 -0.01265611066 0.247 -0.088 0.000 H -0.61802819388 5.33967450634 -0.01131742088 0.180 0.144 -0.000 H 3.39175422949 3.87200638269 -0.00704552340 0.046 -0.099 0.000 H -1.39787683933 2.98334799634 -0.00369736757 -0.003 0.140 -0.000 H 1.83794742242 -5.77033326187 -0.01295832570 0.240 0.081 0.000 H -0.61749414542 -5.33746053721 -0.01121572048 0.186 -0.153 -0.001 H -1.39833026435 -2.98175334118 -0.00345676225 -0.018 -0.188 -0.001 H 3.39230213722 -3.86796714602 -0.00754158092 0.044 0.080 0.000 H 4.58301895157 2.13678100538 0.00314824260 0.255 -0.109 0.000 H 4.58784714512 -2.12983634010 0.00211631073 0.216 0.070 0.000 H -1.68997263563 -0.00719388386 -5.74925805817 -0.037 0.000 0.011 H 0.75224758084 -0.00860493512 -5.25016290812 -0.030 -0.000 -0.025 H -3.29620044300 -0.00255800648 -3.88456579214 -0.006 -0.000 0.010 H 1.47161249279 -0.00457826661 -2.87685200854 -0.002 -0.000 -0.013 H -1.69176120521 -0.00597000955 5.75026973076 -0.038 0.000 -0.012 H 0.75025791005 -0.00892914887 5.25161119224 -0.029 -0.000 0.024 H 1.46975366817 -0.00523069331 2.87805400798 -0.005 -0.000 0.004 H -3.29750276746 -0.00099200484 3.88584245085 -0.007 -0.000 -0.014 H -4.55513299541 0.00377930937 -2.13473279421 -0.034 -0.000 0.011 H -4.55107479454 0.00501307822 2.13844314827 -0.041 -0.000 -0.018 H -6.83436893102 0.00806057203 1.19721860356 0.004 -0.000 0.001 H 6.86748209639 1.20005966818 0.00372860376 -0.023 0.003 -0.000 61 Mode 139: freq=1572.37 N -0.44003451495 -0.00038510790 2.12369783068 0.023 -0.002 0.007 C -1.76594470239 0.00039861437 2.37754210613 -0.002 0.000 0.001 C -2.24923313135 -0.00145267054 3.67997125809 0.001 -0.000 0.026 C -1.33887502024 -0.00450793845 4.73956848945 0.009 0.000 -0.004 C 0.02462671625 -0.00591801736 4.46614405978 0.001 -0.000 -0.013 C 0.43187566201 -0.00376957955 3.13352499014 -0.013 0.000 0.008 C -2.63984642995 0.00218980399 1.17162612704 -0.031 0.000 -0.026 N -1.98513620489 0.00132140951 0.00153900685 -0.010 -0.002 0.003 C -2.63911589169 0.00167522827 -1.17277445342 0.051 0.000 0.004 C -4.02452897564 0.00329996303 -1.20791476641 -0.031 -0.000 -0.020 C -4.73391255267 0.00451580118 -0.00020876193 -0.007 0.000 0.053 C -4.02924140493 0.00399189729 1.20660077672 0.035 -0.000 -0.005 Co 0.00000000000 0.00000000000 0.00000000000 0.000 0.006 -0.001 N -0.43839318333 -0.00054206762 -2.12229806799 -0.019 -0.001 -0.003 C -1.76408906064 -0.00030645034 -2.37697009192 0.006 0.000 0.004 C -2.24773885821 -0.00257631963 -3.67934971086 -0.008 -0.000 0.014 C -1.33713102227 -0.00526459193 -4.73855802198 0.007 0.000 -0.012 C 0.02654101484 -0.00591797621 -4.46472703619 0.006 -0.000 -0.001 C 0.43371721952 -0.00363389350 -3.13225443930 0.000 0.000 0.018 S -6.53329279136 0.00637481657 -0.11611178087 -0.001 -0.000 -0.004 N 2.00981687167 0.00259443239 -0.00000686048 0.026 -0.032 0.000 C 2.67119656792 1.17263645248 0.00045766926 -0.329 0.066 -0.000 C 4.06129317470 1.20536051565 0.00241240325 0.258 0.093 0.000 C 4.76783866331 0.00148799420 0.00346798881 0.007 -0.396 -0.000 C 4.05723810074 -1.20352939940 0.00211502115 -0.240 0.083 -0.000 C 2.67108506586 -1.17139122066 0.00026591651 0.264 0.106 0.000 C 1.82209539371 2.39842937406 -0.00175320633 -0.034 -0.018 0.000 C 2.33938959521 3.68993217240 -0.00584554905 0.034 -0.143 0.000 C 1.45736908622 4.77231118002 -0.00917967851 0.001 0.066 -0.000 C 0.08658913130 4.53522926787 -0.00833235387 -0.027 0.044 -0.000 C -0.35359617412 3.21325694137 -0.00400174376 -0.041 -0.107 0.000 N 0.49290585413 2.18198449515 -0.00068475564 0.157 -0.012 0.000 S 6.56718562933 -0.11349126889 0.00673479967 -0.014 0.032 -0.000 C 1.82142022278 -2.39594383179 -0.00206827421 0.022 -0.008 -0.000 C 2.33969079820 -3.68709653410 -0.00625612120 -0.017 -0.150 -0.000 C 1.45789786198 -4.76953179608 -0.00945089783 -0.031 0.043 0.000 C 0.08684213972 -4.53272927032 -0.00840538011 0.008 0.062 0.000 C -0.35393854068 -3.21111942258 -0.00398541364 0.059 -0.076 -0.000 N 0.49225266031 -2.17934076887 -0.00084210065 -0.148 -0.025 0.000 H 1.83694111827 5.77332096953 -0.01265611066 -0.048 0.042 -0.000 H -0.61802819388 5.33967450634 -0.01131742088 0.015 0.039 -0.000 H 3.39175422949 3.87200638269 -0.00704552340 -0.016 0.109 -0.000 H -1.39787683933 2.98334799634 -0.00369736757 -0.076 0.236 -0.001 H 1.83794742242 -5.77033326187 -0.01295832570 0.091 0.054 0.000 H -0.61749414542 -5.33746053721 -0.01121572048 0.023 0.006 -0.000 H -1.39833026435 -2.98175334118 -0.00345676225 0.068 0.186 0.000 H 3.39230213722 -3.86796714602 -0.00754158092 0.023 0.116 0.000 H 4.58301895157 2.13678100538 0.00314824260 -0.226 0.208 -0.001 H 4.58784714512 -2.12983634010 0.00211631073 0.253 0.218 0.000 H -1.68997263563 -0.00719388386 -5.74925805817 -0.004 0.000 -0.002 H 0.75224758084 -0.00860493512 -5.25016290812 -0.009 0.000 -0.011 H -3.29620044300 -0.00255800648 -3.88456579214 0.001 0.000 -0.011 H 1.47161249279 -0.00457826661 -2.87685200854 0.010 0.001 -0.034 H -1.69176120521 -0.00597000955 5.75026973076 -0.022 0.000 -0.010 H 0.75025791005 -0.00892914887 5.25161119224 -0.010 0.000 0.004 H 1.46975366817 -0.00523069331 2.87805400798 -0.011 0.001 -0.024 H -3.29750276746 -0.00099200484 3.88584245085 -0.006 0.000 -0.021 H -4.55513299541 0.00377930937 -2.13473279421 0.016 0.000 -0.022 H -4.55107479454 0.00501307822 2.13844314827 -0.043 0.001 -0.033 H -6.83436893102 0.00806057203 1.19721860356 0.012 0.000 0.002 H 6.86748209639 1.20005966818 0.00372860376 0.081 -0.018 0.000 61 Mode 140: freq=1572.48 N -0.44003451495 -0.00038510790 2.12369783068 0.164 -0.000 0.025 C -1.76594470239 0.00039861437 2.37754210613 -0.024 -0.000 0.014 C -2.24923313135 -0.00145267054 3.67997125809 0.022 -0.000 0.168 C -1.33887502024 -0.00450793845 4.73956848945 0.036 0.000 -0.048 C 0.02462671625 -0.00591801736 4.46614405978 -0.007 0.000 -0.069 C 0.43187566201 -0.00376957955 3.13352499014 -0.067 -0.000 0.081 C -2.63984642995 0.00218980399 1.17162612704 -0.280 0.000 -0.128 N -1.98513620489 0.00132140951 0.00153900685 -0.024 0.000 0.025 C -2.63911589169 0.00167522827 -1.17277445342 0.326 -0.000 -0.034 C -4.02452897564 0.00329996303 -1.20791476641 -0.234 0.000 -0.116 C -4.73391255267 0.00451580118 -0.00020876193 -0.026 0.000 0.389 C -4.02924140493 0.00399189729 1.20660077672 0.258 -0.000 -0.063 Co 0.00000000000 0.00000000000 0.00000000000 -0.000 -0.001 -0.006 N -0.43839318333 -0.00054206762 -2.12229806799 -0.145 0.000 0.002 C -1.76408906064 -0.00030645034 -2.37697009192 0.031 -0.000 0.024 C -2.24773885821 -0.00257631963 -3.67934971086 -0.041 0.000 0.127 C -1.33713102227 -0.00526459193 -4.73855802198 0.016 -0.000 -0.068 C 0.02654101484 -0.00591797621 -4.46472703619 0.028 -0.000 -0.033 C 0.43371721952 -0.00363389350 -3.13225443930 0.031 0.000 0.109 S -6.53329279136 0.00637481657 -0.11611178087 -0.010 -0.000 -0.032 N 2.00981687167 0.00259443239 -0.00000686048 -0.012 0.005 0.002 C 2.67119656792 1.17263645248 0.00045766926 0.055 0.003 0.000 C 4.06129317470 1.20536051565 0.00241240325 -0.035 -0.018 0.000 C 4.76783866331 0.00148799420 0.00346798881 -0.007 0.054 -0.000 C 4.05723810074 -1.20352939940 0.00211502115 0.033 -0.005 0.000 C 2.67108506586 -1.17139122066 0.00026591651 -0.025 -0.027 -0.000 C 1.82209539371 2.39842937406 -0.00175320633 0.006 0.004 -0.000 C 2.33938959521 3.68993217240 -0.00584554905 -0.008 0.016 0.000 C 1.45736908622 4.77231118002 -0.00917967851 0.008 -0.013 -0.000 C 0.08658913130 4.53522926787 -0.00833235387 0.007 -0.002 0.000 C -0.35359617412 3.21325694137 -0.00400174376 0.002 0.020 -0.000 N 0.49290585413 2.18198449515 -0.00068475564 -0.021 -0.001 0.001 S 6.56718562933 -0.11349126889 0.00673479967 0.003 -0.004 0.000 C 1.82142022278 -2.39594383179 -0.00206827421 -0.002 -0.000 -0.000 C 2.33969079820 -3.68709653410 -0.00625612120 -0.001 0.025 0.000 C 1.45789786198 -4.76953179608 -0.00945089783 0.012 -0.002 -0.000 C 0.08684213972 -4.53272927032 -0.00840538011 0.002 -0.013 -0.000 C -0.35393854068 -3.21111942258 -0.00398541364 -0.012 0.005 -0.000 N 0.49225266031 -2.17934076887 -0.00084210065 0.021 0.006 0.002 H 1.83694111827 5.77332096953 -0.01265611066 -0.004 -0.002 -0.000 H -0.61802819388 5.33967450634 -0.01131742088 -0.010 -0.012 -0.000 H 3.39175422949 3.87200638269 -0.00704552340 0.000 -0.011 -0.000 H -1.39787683933 2.98334799634 -0.00369736757 0.011 -0.041 -0.001 H 1.83794742242 -5.77033326187 -0.01295832570 -0.024 -0.011 -0.000 H -0.61749414542 -5.33746053721 -0.01121572048 -0.011 0.006 -0.000 H -1.39833026435 -2.98175334118 -0.00345676225 -0.008 -0.016 -0.001 H 3.39230213722 -3.86796714602 -0.00754158092 -0.005 -0.020 -0.000 H 4.58301895157 2.13678100538 0.00314824260 0.020 -0.024 -0.000 H 4.58784714512 -2.12983634010 0.00211631073 -0.045 -0.034 -0.001 H -1.68997263563 -0.00719388386 -5.74925805817 0.025 -0.000 -0.031 H 0.75224758084 -0.00860493512 -5.25016290812 -0.026 -0.000 -0.046 H -3.29620044300 -0.00255800648 -3.88456579214 0.014 -0.000 -0.101 H 1.47161249279 -0.00457826661 -2.87685200854 0.078 -0.001 -0.230 H -1.69176120521 -0.00597000955 5.75026973076 -0.106 0.000 -0.059 H 0.75025791005 -0.00892914887 5.25161119224 -0.029 0.000 -0.002 H 1.46975366817 -0.00523069331 2.87805400798 -0.080 0.000 -0.197 H -3.29750276746 -0.00099200484 3.88584245085 -0.031 0.000 -0.138 H -4.55513299541 0.00377930937 -2.13473279421 0.176 -0.000 -0.186 H -4.55107479454 0.00501307822 2.13844314827 -0.267 0.000 -0.221 H -6.83436893102 0.00806057203 1.19721860356 0.082 -0.000 0.017 H 6.86748209639 1.20005966818 0.00372860376 -0.010 0.002 -0.000 61 Mode 141: freq=1573.97 N -0.44003451495 -0.00038510790 2.12369783068 -0.007 -0.000 0.071 C -1.76594470239 0.00039861437 2.37754210613 0.044 0.000 -0.045 C -2.24923313135 -0.00145267054 3.67997125809 -0.078 -0.000 0.064 C -1.33887502024 -0.00450793845 4.73956848945 0.161 -0.000 0.093 C 0.02462671625 -0.00591801736 4.46614405978 0.082 0.000 -0.097 C 0.43187566201 -0.00376957955 3.13352499014 -0.096 0.000 -0.127 C -2.63984642995 0.00218980399 1.17162612704 0.263 -0.000 -0.241 N -1.98513620489 0.00132140951 0.00153900685 -0.196 0.000 -0.011 C -2.63911589169 0.00167522827 -1.17277445342 0.165 -0.000 0.280 C -4.02452897564 0.00329996303 -1.20791476641 0.059 -0.000 -0.111 C -4.73391255267 0.00451580118 -0.00020876193 -0.127 0.000 -0.059 C -4.02924140493 0.00399189729 1.20660077672 -0.030 0.000 0.131 Co 0.00000000000 0.00000000000 0.00000000000 -0.001 -0.000 0.001 N -0.43839318333 -0.00054206762 -2.12229806799 0.047 -0.000 -0.077 C -1.76408906064 -0.00030645034 -2.37697009192 0.034 0.000 0.040 C -2.24773885821 -0.00257631963 -3.67934971086 -0.069 -0.000 -0.119 C -1.33713102227 -0.00526459193 -4.73855802198 0.170 -0.000 -0.076 C 0.02654101484 -0.00591797621 -4.46472703619 0.079 0.000 0.118 C 0.43371721952 -0.00363389350 -3.13225443930 -0.116 0.000 0.097 S -6.53329279136 0.00637481657 -0.11611178087 0.016 -0.000 0.004 N 2.00981687167 0.00259443239 -0.00000686048 -0.027 0.001 -0.000 C 2.67119656792 1.17263645248 0.00045766926 0.038 0.037 0.000 C 4.06129317470 1.20536051565 0.00241240325 -0.003 -0.019 -0.000 C 4.76783866331 0.00148799420 0.00346798881 -0.019 0.004 -0.000 C 4.05723810074 -1.20352939940 0.00211502115 0.005 0.018 -0.000 C 2.67108506586 -1.17139122066 0.00026591651 0.030 -0.041 0.000 C 1.82209539371 2.39842937406 -0.00175320633 0.004 0.005 0.000 C 2.33938959521 3.68993217240 -0.00584554905 -0.012 -0.010 0.000 C 1.45736908622 4.77231118002 -0.00917967851 0.027 -0.013 0.000 C 0.08658913130 4.53522926787 -0.00833235387 0.011 0.013 -0.000 C -0.35359617412 3.21325694137 -0.00400174376 -0.011 0.018 -0.000 N 0.49290585413 2.18198449515 -0.00068475564 -0.003 -0.005 -0.000 S 6.56718562933 -0.11349126889 0.00673479967 0.002 -0.000 0.000 C 1.82142022278 -2.39594383179 -0.00206827421 0.004 -0.005 0.000 C 2.33969079820 -3.68709653410 -0.00625612120 -0.011 0.014 0.000 C 1.45789786198 -4.76953179608 -0.00945089783 0.028 0.012 0.000 C 0.08684213972 -4.53272927032 -0.00840538011 0.011 -0.015 -0.000 C -0.35393854068 -3.21111942258 -0.00398541364 -0.013 -0.016 -0.000 N 0.49225266031 -2.17934076887 -0.00084210065 0.002 0.006 -0.000 H 1.83694111827 5.77332096953 -0.01265611066 -0.035 0.012 -0.000 H -0.61802819388 5.33967450634 -0.01131742088 -0.025 -0.021 0.000 H 3.39175422949 3.87200638269 -0.00704552340 -0.007 0.013 0.000 H -1.39787683933 2.98334799634 -0.00369736757 0.006 -0.039 0.000 H 1.83794742242 -5.77033326187 -0.01295832570 -0.038 -0.014 -0.000 H -0.61749414542 -5.33746053721 -0.01121572048 -0.026 0.021 0.000 H -1.39833026435 -2.98175334118 -0.00345676225 0.004 0.034 0.000 H 3.39230213722 -3.86796714602 -0.00754158092 -0.008 -0.017 0.000 H 4.58301895157 2.13678100538 0.00314824260 -0.030 0.010 0.000 H 4.58784714512 -2.12983634010 0.00211631073 -0.039 -0.016 0.000 H -1.68997263563 -0.00719388386 -5.74925805817 -0.262 0.000 0.085 H 0.75224758084 -0.00860493512 -5.25016290812 -0.186 -0.000 -0.155 H -3.29620044300 -0.00255800648 -3.88456579214 -0.052 0.000 0.106 H 1.47161249279 -0.00457826661 -2.87685200854 -0.000 -0.000 -0.128 H -1.69176120521 -0.00597000955 5.75026973076 -0.231 0.000 -0.067 H 0.75025791005 -0.00892914887 5.25161119224 -0.180 -0.000 0.158 H 1.46975366817 -0.00523069331 2.87805400798 0.027 -0.000 0.197 H -3.29750276746 -0.00099200484 3.88584245085 -0.043 0.000 -0.060 H -4.55513299541 0.00377930937 -2.13473279421 -0.270 0.000 0.125 H -4.55107479454 0.00501307822 2.13844314827 -0.184 0.000 -0.051 H -6.83436893102 0.00806057203 1.19721860356 0.000 -0.000 -0.002 H 6.86748209639 1.20005966818 0.00372860376 0.001 0.000 0.000 61 Mode 142: freq=1599.48 N -0.44003451495 -0.00038510790 2.12369783068 -0.000 0.001 -0.000 C -1.76594470239 0.00039861437 2.37754210613 0.000 -0.000 -0.000 C -2.24923313135 -0.00145267054 3.67997125809 -0.000 -0.000 -0.000 C -1.33887502024 -0.00450793845 4.73956848945 -0.000 0.000 0.000 C 0.02462671625 -0.00591801736 4.46614405978 0.000 -0.000 0.000 C 0.43187566201 -0.00376957955 3.13352499014 0.000 -0.000 -0.000 C -2.63984642995 0.00218980399 1.17162612704 -0.000 0.001 0.000 N -1.98513620489 0.00132140951 0.00153900685 0.000 -0.003 -0.000 C -2.63911589169 0.00167522827 -1.17277445342 -0.000 0.001 -0.000 C -4.02452897564 0.00329996303 -1.20791476641 -0.000 -0.000 0.000 C -4.73391255267 0.00451580118 -0.00020876193 0.000 0.000 0.000 C -4.02924140493 0.00399189729 1.20660077672 -0.000 -0.000 -0.000 Co 0.00000000000 0.00000000000 0.00000000000 -0.000 0.002 0.000 N -0.43839318333 -0.00054206762 -2.12229806799 -0.000 0.001 -0.000 C -1.76408906064 -0.00030645034 -2.37697009192 0.000 -0.000 0.000 C -2.24773885821 -0.00257631963 -3.67934971086 -0.000 -0.000 0.000 C -1.33713102227 -0.00526459193 -4.73855802198 0.000 0.000 -0.000 C 0.02654101484 -0.00591797621 -4.46472703619 0.000 -0.000 0.000 C 0.43371721952 -0.00363389350 -3.13225443930 -0.000 -0.000 0.000 S -6.53329279136 0.00637481657 -0.11611178087 -0.000 -0.000 -0.000 N 2.00981687167 0.00259443239 -0.00000686048 -0.000 -0.065 -0.000 C 2.67119656792 1.17263645248 0.00045766926 -0.014 -0.002 0.000 C 4.06129317470 1.20536051565 0.00241240325 0.029 -0.033 0.000 C 4.76783866331 0.00148799420 0.00346798881 -0.002 0.072 -0.000 C 4.05723810074 -1.20352939940 0.00211502115 -0.028 -0.032 -0.000 C 2.67108506586 -1.17139122066 0.00026591651 0.015 -0.001 -0.000 C 1.82209539371 2.39842937406 -0.00175320633 0.084 0.172 -0.000 C 2.33938959521 3.68993217240 -0.00584554905 -0.133 -0.066 0.000 C 1.45736908622 4.77231118002 -0.00917967851 0.163 -0.166 0.001 C 0.08658913130 4.53522926787 -0.00833235387 0.190 0.216 -0.001 C -0.35359617412 3.21325694137 -0.00400174376 -0.168 0.096 -0.000 N 0.49290585413 2.18198449515 -0.00068475564 0.061 -0.126 0.000 S 6.56718562933 -0.11349126889 0.00673479967 0.002 -0.003 0.000 C 1.82142022278 -2.39594383179 -0.00206827421 -0.080 0.167 0.000 C 2.33969079820 -3.68709653410 -0.00625612120 0.128 -0.066 -0.000 C 1.45789786198 -4.76953179608 -0.00945089783 -0.158 -0.160 -0.000 C 0.08684213972 -4.53272927032 -0.00840538011 -0.184 0.209 0.001 C -0.35393854068 -3.21111942258 -0.00398541364 0.162 0.092 0.000 N 0.49225266031 -2.17934076887 -0.00084210065 -0.061 -0.122 -0.000 H 1.83694111827 5.77332096953 -0.01265611066 -0.294 0.073 -0.000 H -0.61802819388 5.33967450634 -0.01131742088 -0.284 -0.229 0.001 H 3.39175422949 3.87200638269 -0.00704552340 -0.059 0.044 -0.000 H -1.39787683933 2.98334799634 -0.00369736757 -0.015 -0.162 0.001 H 1.83794742242 -5.77033326187 -0.01295832570 0.284 0.071 0.000 H -0.61749414542 -5.33746053721 -0.01121572048 0.275 -0.222 -0.001 H -1.39833026435 -2.98175334118 -0.00345676225 0.016 -0.155 -0.001 H 3.39230213722 -3.86796714602 -0.00754158092 0.057 0.045 0.000 H 4.58301895157 2.13678100538 0.00314824260 0.003 -0.006 0.000 H 4.58784714512 -2.12983634010 0.00211631073 -0.004 -0.006 -0.000 H -1.68997263563 -0.00719388386 -5.74925805817 -0.000 0.000 0.000 H 0.75224758084 -0.00860493512 -5.25016290812 -0.000 0.000 -0.000 H -3.29620044300 -0.00255800648 -3.88456579214 -0.000 0.000 -0.000 H 1.47161249279 -0.00457826661 -2.87685200854 0.000 -0.000 -0.000 H -1.69176120521 -0.00597000955 5.75026973076 0.000 0.000 0.000 H 0.75025791005 -0.00892914887 5.25161119224 -0.000 0.000 0.000 H 1.46975366817 -0.00523069331 2.87805400798 0.000 -0.000 0.000 H -3.29750276746 -0.00099200484 3.88584245085 0.000 0.000 0.000 H -4.55513299541 0.00377930937 -2.13473279421 0.000 0.000 -0.000 H -4.55107479454 0.00501307822 2.13844314827 0.000 0.000 0.000 H -6.83436893102 0.00806057203 1.19721860356 -0.000 0.000 -0.000 H 6.86748209639 1.20005966818 0.00372860376 -0.010 0.002 -0.000 61 Mode 143: freq=1601.21 N -0.44003451495 -0.00038510790 2.12369783068 0.066 -0.000 0.125 C -1.76594470239 0.00039861437 2.37754210613 0.079 0.000 -0.178 C -2.24923313135 -0.00145267054 3.67997125809 -0.133 0.000 0.065 C -1.33887502024 -0.00450793845 4.73956848945 0.168 -0.001 0.166 C 0.02462671625 -0.00591801736 4.46614405978 0.184 0.000 -0.226 C 0.43187566201 -0.00376957955 3.13352499014 -0.169 0.000 -0.084 C -2.63984642995 0.00218980399 1.17162612704 -0.013 -0.000 0.002 N -1.98513620489 0.00132140951 0.00153900685 -0.001 -0.000 0.069 C -2.63911589169 0.00167522827 -1.17277445342 0.015 0.000 0.001 C -4.02452897564 0.00329996303 -1.20791476641 -0.029 0.000 0.030 C -4.73391255267 0.00451580118 -0.00020876193 -0.002 -0.000 -0.066 C -4.02924140493 0.00399189729 1.20660077672 0.030 -0.000 0.031 Co 0.00000000000 0.00000000000 0.00000000000 -0.000 0.000 -0.002 N -0.43839318333 -0.00054206762 -2.12229806799 -0.065 0.000 0.121 C -1.76408906064 -0.00030645034 -2.37697009192 -0.075 -0.000 -0.172 C -2.24773885821 -0.00257631963 -3.67934971086 0.128 0.000 0.065 C -1.33713102227 -0.00526459193 -4.73855802198 -0.162 0.000 0.160 C 0.02654101484 -0.00591797621 -4.46472703619 -0.179 -0.000 -0.219 C 0.43371721952 -0.00363389350 -3.13225443930 0.164 -0.000 -0.080 S -6.53329279136 0.00637481657 -0.11611178087 0.002 0.000 0.002 N 2.00981687167 0.00259443239 -0.00000686048 0.000 -0.000 0.003 C 2.67119656792 1.17263645248 0.00045766926 -0.000 -0.000 -0.001 C 4.06129317470 1.20536051565 0.00241240325 -0.000 0.000 0.000 C 4.76783866331 0.00148799420 0.00346798881 0.000 0.000 -0.000 C 4.05723810074 -1.20352939940 0.00211502115 -0.000 -0.000 0.000 C 2.67108506586 -1.17139122066 0.00026591651 -0.000 0.000 -0.001 C 1.82209539371 2.39842937406 -0.00175320633 0.000 0.000 0.000 C 2.33938959521 3.68993217240 -0.00584554905 -0.000 0.000 0.000 C 1.45736908622 4.77231118002 -0.00917967851 0.000 -0.000 -0.000 C 0.08658913130 4.53522926787 -0.00833235387 0.000 0.000 0.000 C -0.35359617412 3.21325694137 -0.00400174376 -0.000 0.000 0.000 N 0.49290585413 2.18198449515 -0.00068475564 -0.000 -0.000 -0.001 S 6.56718562933 -0.11349126889 0.00673479967 -0.000 -0.000 0.000 C 1.82142022278 -2.39594383179 -0.00206827421 0.000 0.000 0.000 C 2.33969079820 -3.68709653410 -0.00625612120 -0.000 -0.000 0.000 C 1.45789786198 -4.76953179608 -0.00945089783 -0.000 0.000 -0.000 C 0.08684213972 -4.53272927032 -0.00840538011 0.000 0.000 0.000 C -0.35393854068 -3.21111942258 -0.00398541364 0.000 -0.000 0.000 N 0.49225266031 -2.17934076887 -0.00084210065 -0.000 -0.000 -0.001 H 1.83694111827 5.77332096953 -0.01265611066 -0.000 -0.000 -0.000 H -0.61802819388 5.33967450634 -0.01131742088 -0.000 -0.000 -0.000 H 3.39175422949 3.87200638269 -0.00704552340 -0.000 -0.000 -0.000 H -1.39787683933 2.98334799634 -0.00369736757 0.000 -0.000 -0.000 H 1.83794742242 -5.77033326187 -0.01295832570 0.000 0.000 -0.000 H -0.61749414542 -5.33746053721 -0.01121572048 0.000 0.000 -0.000 H -1.39833026435 -2.98175334118 -0.00345676225 0.000 0.000 0.000 H 3.39230213722 -3.86796714602 -0.00754158092 0.000 0.000 -0.000 H 4.58301895157 2.13678100538 0.00314824260 0.000 -0.000 -0.000 H 4.58784714512 -2.12983634010 0.00211631073 0.000 0.000 -0.000 H -1.68997263563 -0.00719388386 -5.74925805817 0.286 -0.000 -0.062 H 0.75224758084 -0.00860493512 -5.25016290812 0.270 0.000 0.229 H -3.29620044300 -0.00255800648 -3.88456579214 0.057 -0.000 -0.035 H 1.47161249279 -0.00457826661 -2.87685200854 0.014 0.000 0.147 H -1.69176120521 -0.00597000955 5.75026973076 -0.295 0.001 -0.064 H 0.75025791005 -0.00892914887 5.25161119224 -0.279 -0.000 0.237 H 1.46975366817 -0.00523069331 2.87805400798 -0.014 -0.000 0.154 H -3.29750276746 -0.00099200484 3.88584245085 -0.059 0.000 -0.034 H -4.55513299541 0.00377930937 -2.13473279421 -0.000 0.000 0.004 H -4.55107479454 0.00501307822 2.13844314827 -0.001 -0.000 0.003 H -6.83436893102 0.00806057203 1.19721860356 -0.009 0.000 -0.002 H 6.86748209639 1.20005966818 0.00372860376 -0.000 0.000 -0.000 61 Mode 144: freq=1621.93 N -0.44003451495 -0.00038510790 2.12369783068 0.011 0.000 -0.053 C -1.76594470239 0.00039861437 2.37754210613 -0.082 -0.000 0.069 C -2.24923313135 -0.00145267054 3.67997125809 0.062 -0.000 0.054 C -1.33887502024 -0.00450793845 4.73956848945 -0.019 0.000 -0.081 C 0.02462671625 -0.00591801736 4.46614405978 -0.098 -0.000 0.073 C 0.43187566201 -0.00376957955 3.13352499014 0.061 -0.000 0.060 C -2.63984642995 0.00218980399 1.17162612704 0.088 -0.000 -0.130 N -1.98513620489 0.00132140951 0.00153900685 -0.088 0.000 -0.004 C -2.63911589169 0.00167522827 -1.17277445342 0.087 -0.000 0.139 C -4.02452897564 0.00329996303 -1.20791476641 0.048 -0.000 -0.076 C -4.73391255267 0.00451580118 -0.00020876193 -0.080 0.000 0.001 C -4.02924140493 0.00399189729 1.20660077672 0.041 -0.000 0.071 Co 0.00000000000 0.00000000000 0.00000000000 0.007 -0.000 0.000 N -0.43839318333 -0.00054206762 -2.12229806799 0.016 0.000 0.056 C -1.76408906064 -0.00030645034 -2.37697009192 -0.089 -0.000 -0.072 C -2.24773885821 -0.00257631963 -3.67934971086 0.066 -0.000 -0.060 C -1.33713102227 -0.00526459193 -4.73855802198 -0.019 0.000 0.086 C 0.02654101484 -0.00591797621 -4.46472703619 -0.103 -0.000 -0.074 C 0.43371721952 -0.00363389350 -3.13225443930 0.063 -0.000 -0.067 S -6.53329279136 0.00637481657 -0.11611178087 0.007 -0.000 -0.000 N 2.00981687167 0.00259443239 -0.00000686048 -0.138 0.006 -0.000 C 2.67119656792 1.17263645248 0.00045766926 0.141 0.213 0.000 C 4.06129317470 1.20536051565 0.00241240325 0.047 -0.104 0.000 C 4.76783866331 0.00148799420 0.00346798881 -0.110 -0.004 -0.000 C 4.05723810074 -1.20352939940 0.00211502115 0.057 0.113 0.000 C 2.67108506586 -1.17139122066 0.00026591651 0.141 -0.225 -0.000 C 1.82209539371 2.39842937406 -0.00175320633 -0.105 -0.117 0.000 C 2.33938959521 3.68993217240 -0.00584554905 0.091 -0.061 0.000 C 1.45736908622 4.77231118002 -0.00917967851 -0.033 0.124 -0.000 C 0.08658913130 4.53522926787 -0.00833235387 -0.156 -0.126 0.000 C -0.35359617412 3.21325694137 -0.00400174376 0.096 -0.073 0.000 N 0.49290585413 2.18198449515 -0.00068475564 0.001 0.080 -0.000 S 6.56718562933 -0.11349126889 0.00673479967 0.010 0.000 0.000 C 1.82142022278 -2.39594383179 -0.00206827421 -0.114 0.121 0.000 C 2.33969079820 -3.68709653410 -0.00625612120 0.096 0.070 0.000 C 1.45789786198 -4.76953179608 -0.00945089783 -0.033 -0.131 -0.000 C 0.08684213972 -4.53272927032 -0.00840538011 -0.164 0.128 0.000 C -0.35393854068 -3.21111942258 -0.00398541364 0.100 0.082 0.000 N 0.49225266031 -2.17934076887 -0.00084210065 0.006 -0.084 -0.000 H 1.83694111827 5.77332096953 -0.01265611066 0.105 0.001 -0.000 H -0.61802819388 5.33967450634 -0.01131742088 0.164 0.147 -0.000 H 3.39175422949 3.87200638269 -0.00704552340 0.017 0.080 -0.000 H -1.39787683933 2.98334799634 -0.00369736757 -0.002 0.139 -0.000 H 1.83794742242 -5.77033326187 -0.01295832570 0.107 -0.003 -0.000 H -0.61749414542 -5.33746053721 -0.01121572048 0.170 -0.154 -0.001 H -1.39833026435 -2.98175334118 -0.00345676225 -0.005 -0.153 -0.001 H 3.39230213722 -3.86796714602 -0.00754158092 0.016 -0.090 -0.000 H 4.58301895157 2.13678100538 0.00314824260 -0.175 0.069 -0.000 H 4.58784714512 -2.12983634010 0.00211631073 -0.188 -0.076 -0.000 H -1.68997263563 -0.00719388386 -5.74925805817 0.059 -0.000 0.008 H 0.75224758084 -0.00860493512 -5.25016290812 0.104 0.000 0.104 H -3.29620044300 -0.00255800648 -3.88456579214 0.005 0.000 0.080 H 1.47161249279 -0.00457826661 -2.87685200854 -0.012 0.000 0.114 H -1.69176120521 -0.00597000955 5.75026973076 0.058 -0.000 -0.007 H 0.75025791005 -0.00892914887 5.25161119224 0.100 0.000 -0.098 H 1.46975366817 -0.00523069331 2.87805400798 -0.009 0.000 -0.103 H -3.29750276746 -0.00099200484 3.88584245085 0.006 0.000 -0.071 H -4.55513299541 0.00377930937 -2.13473279421 -0.125 0.000 0.052 H -4.55107479454 0.00501307822 2.13844314827 -0.116 0.000 -0.047 H -6.83436893102 0.00806057203 1.19721860356 0.006 -0.000 0.000 H 6.86748209639 1.20005966818 0.00372860376 0.009 -0.001 -0.000 61 Mode 145: freq=1625.26 N -0.44003451495 -0.00038510790 2.12369783068 0.008 0.000 -0.077 C -1.76594470239 0.00039861437 2.37754210613 -0.107 -0.000 0.111 C -2.24923313135 -0.00145267054 3.67997125809 0.094 -0.000 0.075 C -1.33887502024 -0.00450793845 4.73956848945 -0.038 0.000 -0.126 C 0.02462671625 -0.00591801736 4.46614405978 -0.148 -0.000 0.124 C 0.43187566201 -0.00376957955 3.13352499014 0.092 -0.000 0.072 C -2.63984642995 0.00218980399 1.17162612704 0.128 -0.000 -0.213 N -1.98513620489 0.00132140951 0.00153900685 -0.135 0.000 -0.007 C -2.63911589169 0.00167522827 -1.17277445342 0.129 -0.000 0.226 C -4.02452897564 0.00329996303 -1.20791476641 0.069 -0.000 -0.115 C -4.73391255267 0.00451580118 -0.00020876193 -0.113 0.000 0.004 C -4.02924140493 0.00399189729 1.20660077672 0.058 -0.000 0.106 Co 0.00000000000 0.00000000000 0.00000000000 0.004 0.000 0.000 N -0.43839318333 -0.00054206762 -2.12229806799 0.016 0.000 0.082 C -1.76408906064 -0.00030645034 -2.37697009192 -0.118 -0.000 -0.114 C -2.24773885821 -0.00257631963 -3.67934971086 0.099 -0.000 -0.085 C -1.33713102227 -0.00526459193 -4.73855802198 -0.038 0.000 0.133 C 0.02654101484 -0.00591797621 -4.46472703619 -0.155 -0.000 -0.125 C 0.43371721952 -0.00363389350 -3.13225443930 0.095 -0.000 -0.083 S -6.53329279136 0.00637481657 -0.11611178087 0.009 -0.000 -0.000 N 2.00981687167 0.00259443239 -0.00000686048 0.089 -0.004 -0.000 C 2.67119656792 1.17263645248 0.00045766926 -0.090 -0.154 -0.000 C 4.06129317470 1.20536051565 0.00241240325 -0.025 0.066 -0.000 C 4.76783866331 0.00148799420 0.00346798881 0.063 0.004 0.000 C 4.05723810074 -1.20352939940 0.00211502115 -0.031 -0.073 -0.000 C 2.67108506586 -1.17139122066 0.00026591651 -0.092 0.162 0.000 C 1.82209539371 2.39842937406 -0.00175320633 0.050 0.088 -0.000 C 2.33938959521 3.68993217240 -0.00584554905 -0.060 0.029 -0.000 C 1.45736908622 4.77231118002 -0.00917967851 0.032 -0.085 0.000 C 0.08658913130 4.53522926787 -0.00833235387 0.104 0.100 -0.000 C -0.35359617412 3.21325694137 -0.00400174376 -0.067 0.027 -0.000 N 0.49290585413 2.18198449515 -0.00068475564 0.012 -0.053 0.000 S 6.56718562933 -0.11349126889 0.00673479967 -0.006 -0.000 -0.000 C 1.82142022278 -2.39594383179 -0.00206827421 0.057 -0.090 -0.000 C 2.33969079820 -3.68709653410 -0.00625612120 -0.063 -0.034 -0.000 C 1.45789786198 -4.76953179608 -0.00945089783 0.032 0.089 0.000 C 0.08684213972 -4.53272927032 -0.00840538011 0.109 -0.101 -0.000 C -0.35393854068 -3.21111942258 -0.00398541364 -0.069 -0.033 -0.000 N 0.49225266031 -2.17934076887 -0.00084210065 0.009 0.056 0.000 H 1.83694111827 5.77332096953 -0.01265611066 -0.084 0.005 -0.000 H -0.61802819388 5.33967450634 -0.01131742088 -0.115 -0.097 0.000 H 3.39175422949 3.87200638269 -0.00704552340 -0.015 -0.035 0.000 H -1.39787683933 2.98334799634 -0.00369736757 -0.005 -0.074 0.000 H 1.83794742242 -5.77033326187 -0.01295832570 -0.085 -0.004 0.000 H -0.61749414542 -5.33746053721 -0.01121572048 -0.119 0.102 0.000 H -1.39833026435 -2.98175334118 -0.00345676225 -0.004 0.083 0.000 H 3.39230213722 -3.86796714602 -0.00754158092 -0.014 0.042 0.000 H 4.58301895157 2.13678100538 0.00314824260 0.115 -0.045 0.000 H 4.58784714512 -2.12983634010 0.00211631073 0.122 0.049 0.000 H -1.68997263563 -0.00719388386 -5.74925805817 0.099 -0.000 0.009 H 0.75224758084 -0.00860493512 -5.25016290812 0.161 0.000 0.155 H -3.29620044300 -0.00255800648 -3.88456579214 0.010 0.000 0.107 H 1.47161249279 -0.00457826661 -2.87685200854 -0.014 0.000 0.162 H -1.69176120521 -0.00597000955 5.75026973076 0.099 -0.000 -0.007 H 0.75025791005 -0.00892914887 5.25161119224 0.155 0.000 -0.147 H 1.46975366817 -0.00523069331 2.87805400798 -0.010 0.000 -0.146 H -3.29750276746 -0.00099200484 3.88584245085 0.011 0.000 -0.094 H -4.55513299541 0.00377930937 -2.13473279421 -0.188 0.000 0.079 H -4.55107479454 0.00501307822 2.13844314827 -0.176 0.000 -0.072 H -6.83436893102 0.00806057203 1.19721860356 0.009 -0.000 0.001 H 6.86748209639 1.20005966818 0.00372860376 -0.006 0.001 0.000 61 Mode 146: freq=1643.60 N -0.44003451495 -0.00038510790 2.12369783068 0.116 -0.000 -0.006 C -1.76594470239 0.00039861437 2.37754210613 -0.135 0.000 -0.113 C -2.24923313135 -0.00145267054 3.67997125809 0.002 -0.000 0.108 C -1.33887502024 -0.00450793845 4.73956848945 0.054 -0.000 0.022 C 0.02462671625 -0.00591801736 4.46614405978 0.026 0.000 -0.129 C 0.43187566201 -0.00376957955 3.13352499014 -0.025 -0.000 0.151 C -2.63984642995 0.00218980399 1.17162612704 -0.040 0.000 0.135 N -1.98513620489 0.00132140951 0.00153900685 0.056 -0.000 0.001 C -2.63911589169 0.00167522827 -1.17277445342 -0.044 -0.000 -0.138 C -4.02452897564 0.00329996303 -1.20791476641 0.057 -0.000 0.008 C -4.73391255267 0.00451580118 -0.00020876193 -0.039 0.000 -0.007 C -4.02924140493 0.00399189729 1.20660077672 0.055 -0.000 -0.003 Co 0.00000000000 0.00000000000 0.00000000000 -0.002 -0.000 0.000 N -0.43839318333 -0.00054206762 -2.12229806799 0.119 -0.000 0.006 C -1.76408906064 -0.00030645034 -2.37697009192 -0.139 0.000 0.115 C -2.24773885821 -0.00257631963 -3.67934971086 0.002 -0.000 -0.112 C -1.33713102227 -0.00526459193 -4.73855802198 0.056 -0.000 -0.022 C 0.02654101484 -0.00591797621 -4.46472703619 0.026 0.000 0.132 C 0.43371721952 -0.00363389350 -3.13225443930 -0.025 -0.000 -0.156 S -6.53329279136 0.00637481657 -0.11611178087 0.001 0.000 0.001 N 2.00981687167 0.00259443239 -0.00000686048 0.045 0.000 0.000 C 2.67119656792 1.17263645248 0.00045766926 -0.036 -0.137 0.000 C 4.06129317470 1.20536051565 0.00241240325 0.082 -0.014 0.000 C 4.76783866331 0.00148799420 0.00346798881 -0.069 0.006 -0.000 C 4.05723810074 -1.20352939940 0.00211502115 0.086 0.010 0.000 C 2.67108506586 -1.17139122066 0.00026591651 -0.038 0.139 0.000 C 1.82209539371 2.39842937406 -0.00175320633 -0.186 0.132 -0.000 C 2.33938959521 3.68993217240 -0.00584554905 0.010 -0.153 0.000 C 1.45736908622 4.77231118002 -0.00917967851 0.071 -0.010 0.000 C 0.08658913130 4.53522926787 -0.00833235387 0.009 0.142 -0.000 C -0.35359617412 3.21325694137 -0.00400174376 -0.021 -0.197 0.001 N 0.49290585413 2.18198449515 -0.00068475564 0.150 0.017 -0.000 S 6.56718562933 -0.11349126889 0.00673479967 0.003 -0.001 -0.000 C 1.82142022278 -2.39594383179 -0.00206827421 -0.196 -0.136 -0.000 C 2.33969079820 -3.68709653410 -0.00625612120 0.011 0.161 0.001 C 1.45789786198 -4.76953179608 -0.00945089783 0.075 0.009 0.000 C 0.08684213972 -4.53272927032 -0.00840538011 0.008 -0.147 -0.000 C -0.35393854068 -3.21111942258 -0.00398541364 -0.021 0.207 0.001 N 0.49225266031 -2.17934076887 -0.00084210065 0.157 -0.019 -0.000 H 1.83694111827 5.77332096953 -0.01265611066 -0.122 0.053 -0.000 H -0.61802819388 5.33967450634 -0.01131742088 -0.053 0.003 -0.000 H 3.39175422949 3.87200638269 -0.00704552340 -0.037 0.181 -0.001 H -1.39787683933 2.98334799634 -0.00369736757 -0.070 0.207 -0.001 H 1.83794742242 -5.77033326187 -0.01295832570 -0.127 -0.056 -0.000 H -0.61749414542 -5.33746053721 -0.01121572048 -0.054 -0.005 -0.000 H -1.39833026435 -2.98175334118 -0.00345676225 -0.073 -0.218 -0.001 H 3.39230213722 -3.86796714602 -0.00754158092 -0.039 -0.192 -0.001 H 4.58301895157 2.13678100538 0.00314824260 0.002 0.009 0.000 H 4.58784714512 -2.12983634010 0.00211631073 -0.002 -0.014 0.000 H -1.68997263563 -0.00719388386 -5.74925805817 -0.107 0.000 0.037 H 0.75224758084 -0.00860493512 -5.25016290812 -0.062 0.000 -0.016 H -3.29620044300 -0.00255800648 -3.88456579214 -0.033 0.000 0.130 H 1.47161249279 -0.00457826661 -2.87685200854 -0.062 0.000 0.154 H -1.69176120521 -0.00597000955 5.75026973076 -0.104 0.000 -0.036 H 0.75025791005 -0.00892914887 5.25161119224 -0.060 0.000 0.017 H 1.46975366817 -0.00523069331 2.87805400798 -0.060 0.000 -0.149 H -3.29750276746 -0.00099200484 3.88584245085 -0.032 0.000 -0.125 H -4.55513299541 0.00377930937 -2.13473279421 0.019 -0.000 0.003 H -4.55107479454 0.00501307822 2.13844314827 0.021 -0.000 0.001 H -6.83436893102 0.00806057203 1.19721860356 -0.002 -0.000 -0.000 H 6.86748209639 1.20005966818 0.00372860376 -0.001 0.000 0.000 61 Mode 147: freq=1644.81 N -0.44003451495 -0.00038510790 2.12369783068 0.150 -0.000 -0.025 C -1.76594470239 0.00039861437 2.37754210613 -0.191 0.000 -0.135 C -2.24923313135 -0.00145267054 3.67997125809 0.014 -0.000 0.151 C -1.33887502024 -0.00450793845 4.73956848945 0.064 -0.000 0.010 C 0.02462671625 -0.00591801736 4.46614405978 0.014 0.000 -0.145 C 0.43187566201 -0.00376957955 3.13352499014 -0.017 -0.000 0.200 C -2.63984642995 0.00218980399 1.17162612704 -0.041 0.000 0.155 N -1.98513620489 0.00132140951 0.00153900685 0.060 -0.000 0.000 C -2.63911589169 0.00167522827 -1.17277445342 -0.044 -0.000 -0.157 C -4.02452897564 0.00329996303 -1.20791476641 0.084 -0.000 -0.003 C -4.73391255267 0.00451580118 -0.00020876193 -0.065 0.000 -0.007 C -4.02924140493 0.00399189729 1.20660077672 0.080 -0.000 0.008 Co 0.00000000000 0.00000000000 0.00000000000 -0.001 0.000 0.000 N -0.43839318333 -0.00054206762 -2.12229806799 0.156 -0.000 0.027 C -1.76408906064 -0.00030645034 -2.37697009192 -0.199 0.000 0.139 C -2.24773885821 -0.00257631963 -3.67934971086 0.015 -0.000 -0.158 C -1.33713102227 -0.00526459193 -4.73855802198 0.067 -0.000 -0.010 C 0.02654101484 -0.00591797621 -4.46472703619 0.013 0.000 0.151 C 0.43371721952 -0.00363389350 -3.13225443930 -0.017 -0.000 -0.208 S -6.53329279136 0.00637481657 -0.11611178087 0.002 -0.000 0.001 N 2.00981687167 0.00259443239 -0.00000686048 -0.035 -0.000 -0.000 C 2.67119656792 1.17263645248 0.00045766926 0.024 0.102 -0.000 C 4.06129317470 1.20536051565 0.00241240325 -0.067 0.015 -0.000 C 4.76783866331 0.00148799420 0.00346798881 0.059 -0.005 0.000 C 4.05723810074 -1.20352939940 0.00211502115 -0.070 -0.012 -0.000 C 2.67108506586 -1.17139122066 0.00026591651 0.025 -0.103 -0.000 C 1.82209539371 2.39842937406 -0.00175320633 0.154 -0.099 0.000 C 2.33938959521 3.68993217240 -0.00584554905 -0.013 0.123 -0.000 C 1.45736908622 4.77231118002 -0.00917967851 -0.053 -0.000 0.000 C 0.08658913130 4.53522926787 -0.00833235387 0.002 -0.100 0.000 C -0.35359617412 3.21325694137 -0.00400174376 0.008 0.155 -0.000 N 0.49290585413 2.18198449515 -0.00068475564 -0.117 -0.023 0.000 S 6.56718562933 -0.11349126889 0.00673479967 -0.002 0.000 -0.000 C 1.82142022278 -2.39594383179 -0.00206827421 0.162 0.103 0.000 C 2.33969079820 -3.68709653410 -0.00625612120 -0.014 -0.131 -0.000 C 1.45789786198 -4.76953179608 -0.00945089783 -0.056 0.001 0.000 C 0.08684213972 -4.53272927032 -0.00840538011 0.003 0.105 0.000 C -0.35393854068 -3.21111942258 -0.00398541364 0.008 -0.164 -0.001 N 0.49225266031 -2.17934076887 -0.00084210065 -0.122 0.024 0.000 H 1.83694111827 5.77332096953 -0.01265611066 0.087 -0.041 0.000 H -0.61802819388 5.33967450634 -0.01131742088 0.030 -0.011 0.000 H 3.39175422949 3.87200638269 -0.00704552340 0.028 -0.147 0.000 H -1.39787683933 2.98334799634 -0.00369736757 0.052 -0.161 0.001 H 1.83794742242 -5.77033326187 -0.01295832570 0.091 0.044 0.000 H -0.61749414542 -5.33746053721 -0.01121572048 0.031 0.013 0.000 H -1.39833026435 -2.98175334118 -0.00345676225 0.054 0.171 0.001 H 3.39230213722 -3.86796714602 -0.00754158092 0.030 0.156 0.001 H 4.58301895157 2.13678100538 0.00314824260 0.005 -0.010 -0.000 H 4.58784714512 -2.12983634010 0.00211631073 0.008 0.014 0.000 H -1.68997263563 -0.00719388386 -5.74925805817 -0.124 0.000 0.049 H 0.75224758084 -0.00860493512 -5.25016290812 -0.056 0.000 -0.001 H -3.29620044300 -0.00255800648 -3.88456579214 -0.042 0.000 0.184 H 1.47161249279 -0.00457826661 -2.87685200854 -0.077 0.000 0.208 H -1.69176120521 -0.00597000955 5.75026973076 -0.119 0.000 -0.047 H 0.75025791005 -0.00892914887 5.25161119224 -0.055 0.000 0.002 H 1.46975366817 -0.00523069331 2.87805400798 -0.074 0.001 -0.199 H -3.29750276746 -0.00099200484 3.88584245085 -0.041 0.000 -0.175 H -4.55513299541 0.00377930937 -2.13473279421 0.005 -0.000 0.012 H -4.55107479454 0.00501307822 2.13844314827 0.009 -0.000 -0.007 H -6.83436893102 0.00806057203 1.19721860356 -0.002 0.000 -0.001 H 6.86748209639 1.20005966818 0.00372860376 0.000 -0.000 -0.000 61 Mode 148: freq=1657.89 N -0.44003451495 -0.00038510790 2.12369783068 -0.000 -0.002 0.000 C -1.76594470239 0.00039861437 2.37754210613 0.000 0.000 -0.000 C -2.24923313135 -0.00145267054 3.67997125809 -0.000 0.000 -0.000 C -1.33887502024 -0.00450793845 4.73956848945 0.000 0.000 0.000 C 0.02462671625 -0.00591801736 4.46614405978 0.000 0.000 -0.000 C 0.43187566201 -0.00376957955 3.13352499014 -0.000 0.000 -0.000 C -2.63984642995 0.00218980399 1.17162612704 -0.000 -0.000 0.001 N -1.98513620489 0.00132140951 0.00153900685 0.000 -0.000 0.000 C -2.63911589169 0.00167522827 -1.17277445342 -0.000 -0.000 -0.001 C -4.02452897564 0.00329996303 -1.20791476641 -0.000 -0.000 0.000 C -4.73391255267 0.00451580118 -0.00020876193 0.000 -0.000 -0.000 C -4.02924140493 0.00399189729 1.20660077672 -0.000 0.000 -0.000 Co 0.00000000000 0.00000000000 0.00000000000 0.000 -0.000 -0.000 N -0.43839318333 -0.00054206762 -2.12229806799 -0.000 -0.002 -0.000 C -1.76408906064 -0.00030645034 -2.37697009192 0.000 0.000 0.000 C -2.24773885821 -0.00257631963 -3.67934971086 -0.000 0.000 0.000 C -1.33713102227 -0.00526459193 -4.73855802198 0.000 0.000 -0.000 C 0.02654101484 -0.00591797621 -4.46472703619 0.000 0.000 0.000 C 0.43371721952 -0.00363389350 -3.13225443930 -0.000 0.000 0.000 S -6.53329279136 0.00637481657 -0.11611178087 -0.000 -0.000 0.000 N 2.00981687167 0.00259443239 -0.00000686048 -0.008 -0.058 -0.000 C 2.67119656792 1.17263645248 0.00045766926 0.240 -0.021 0.000 C 4.06129317470 1.20536051565 0.00241240325 -0.093 -0.094 -0.000 C 4.76783866331 0.00148799420 0.00346798881 -0.000 0.246 0.000 C 4.05723810074 -1.20352939940 0.00211502115 0.084 -0.093 0.000 C 2.67108506586 -1.17139122066 0.00026591651 -0.215 -0.027 -0.000 C 1.82209539371 2.39842937406 -0.00175320633 -0.281 0.118 -0.000 C 2.33938959521 3.68993217240 -0.00584554905 0.041 -0.199 0.001 C 1.45736908622 4.77231118002 -0.00917967851 0.092 0.029 -0.000 C 0.08658913130 4.53522926787 -0.00833235387 -0.066 0.102 -0.000 C -0.35359617412 3.21325694137 -0.00400174376 0.033 -0.251 0.001 N 0.49290585413 2.18198449515 -0.00068475564 0.141 0.073 -0.000 S 6.56718562933 -0.11349126889 0.00673479967 0.007 -0.016 0.000 C 1.82142022278 -2.39594383179 -0.00206827421 0.265 0.114 0.000 C 2.33969079820 -3.68709653410 -0.00625612120 -0.037 -0.187 -0.001 C 1.45789786198 -4.76953179608 -0.00945089783 -0.088 0.025 0.000 C 0.08684213972 -4.53272927032 -0.00840538011 0.058 0.101 0.000 C -0.35393854068 -3.21111942258 -0.00398541364 -0.029 -0.238 -0.001 N 0.49225266031 -2.17934076887 -0.00084210065 -0.135 0.067 0.000 H 1.83694111827 5.77332096953 -0.01265611066 -0.104 0.064 -0.000 H -0.61802819388 5.33967450634 -0.01131742088 0.004 0.062 -0.000 H 3.39175422949 3.87200638269 -0.00704552340 -0.040 0.259 -0.001 H -1.39787683933 2.98334799634 -0.00369736757 -0.067 0.261 -0.001 H 1.83794742242 -5.77033326187 -0.01295832570 0.101 0.061 0.000 H -0.61749414542 -5.33746053721 -0.01121572048 -0.000 0.056 0.000 H -1.39833026435 -2.98175334118 -0.00345676225 0.064 0.246 0.001 H 3.39230213722 -3.86796714602 -0.00754158092 0.038 0.245 0.001 H 4.58301895157 2.13678100538 0.00314824260 0.066 -0.088 0.000 H 4.58784714512 -2.12983634010 0.00211631073 -0.066 -0.086 -0.000 H -1.68997263563 -0.00719388386 -5.74925805817 -0.000 -0.000 -0.000 H 0.75224758084 -0.00860493512 -5.25016290812 -0.000 -0.000 -0.000 H -3.29620044300 -0.00255800648 -3.88456579214 -0.000 0.000 -0.000 H 1.47161249279 -0.00457826661 -2.87685200854 0.000 -0.000 -0.001 H -1.69176120521 -0.00597000955 5.75026973076 -0.000 -0.000 -0.000 H 0.75025791005 -0.00892914887 5.25161119224 -0.000 -0.000 0.000 H 1.46975366817 -0.00523069331 2.87805400798 0.000 -0.000 0.001 H -3.29750276746 -0.00099200484 3.88584245085 -0.000 0.000 0.000 H -4.55513299541 0.00377930937 -2.13473279421 0.001 0.000 -0.000 H -4.55107479454 0.00501307822 2.13844314827 0.000 0.000 0.000 H -6.83436893102 0.00806057203 1.19721860356 -0.000 0.000 -0.000 H 6.86748209639 1.20005966818 0.00372860376 -0.040 0.009 -0.000 61 Mode 149: freq=1658.38 N -0.44003451495 -0.00038510790 2.12369783068 0.136 -0.000 -0.078 C -1.76594470239 0.00039861437 2.37754210613 -0.282 0.000 -0.115 C -2.24923313135 -0.00145267054 3.67997125809 0.049 -0.000 0.198 C -1.33887502024 -0.00450793845 4.73956848945 0.082 -0.000 -0.033 C 0.02462671625 -0.00591801736 4.46614405978 -0.062 0.000 -0.100 C 0.43187566201 -0.00376957955 3.13352499014 0.038 -0.001 0.249 C -2.63984642995 0.00218980399 1.17162612704 0.253 -0.000 0.016 N -1.98513620489 0.00132140951 0.00153900685 -0.010 0.000 0.066 C -2.63911589169 0.00167522827 -1.17277445342 -0.227 0.000 0.025 C -4.02452897564 0.00329996303 -1.20791476641 0.088 -0.000 0.093 C -4.73391255267 0.00451580118 -0.00020876193 -0.000 -0.000 -0.247 C -4.02924140493 0.00399189729 1.20660077672 -0.097 0.000 0.095 Co 0.00000000000 0.00000000000 0.00000000000 0.000 0.000 0.001 N -0.43839318333 -0.00054206762 -2.12229806799 -0.133 -0.000 -0.073 C -1.76408906064 -0.00030645034 -2.37697009192 0.269 -0.000 -0.114 C -2.24773885821 -0.00257631963 -3.67934971086 -0.045 0.000 0.187 C -1.33713102227 -0.00526459193 -4.73855802198 -0.079 0.000 -0.027 C 0.02654101484 -0.00591797621 -4.46472703619 0.054 -0.000 -0.102 C 0.43371721952 -0.00363389350 -3.13225443930 -0.033 0.001 0.239 S -6.53329279136 0.00637481657 -0.11611178087 0.007 0.000 0.016 N 2.00981687167 0.00259443239 -0.00000686048 0.000 -0.000 0.000 C 2.67119656792 1.17263645248 0.00045766926 -0.000 -0.000 0.000 C 4.06129317470 1.20536051565 0.00241240325 -0.000 0.000 0.000 C 4.76783866331 0.00148799420 0.00346798881 0.000 -0.000 0.000 C 4.05723810074 -1.20352939940 0.00211502115 -0.000 -0.000 0.000 C 2.67108506586 -1.17139122066 0.00026591651 0.000 0.000 0.000 C 1.82209539371 2.39842937406 -0.00175320633 0.001 -0.000 -0.000 C 2.33938959521 3.68993217240 -0.00584554905 -0.000 0.001 -0.000 C 1.45736908622 4.77231118002 -0.00917967851 0.000 -0.000 -0.000 C 0.08658913130 4.53522926787 -0.00833235387 0.000 -0.000 -0.000 C -0.35359617412 3.21325694137 -0.00400174376 -0.000 0.000 -0.000 N 0.49290585413 2.18198449515 -0.00068475564 -0.000 -0.000 0.002 S 6.56718562933 -0.11349126889 0.00673479967 -0.000 0.000 0.000 C 1.82142022278 -2.39594383179 -0.00206827421 0.001 0.000 -0.000 C 2.33969079820 -3.68709653410 -0.00625612120 -0.000 -0.001 -0.000 C 1.45789786198 -4.76953179608 -0.00945089783 0.000 0.000 -0.000 C 0.08684213972 -4.53272927032 -0.00840538011 0.000 0.000 -0.000 C -0.35393854068 -3.21111942258 -0.00398541364 -0.000 -0.000 -0.000 N 0.49225266031 -2.17934076887 -0.00084210065 -0.000 0.000 0.002 H 1.83694111827 5.77332096953 -0.01265611066 -0.000 -0.000 0.000 H -0.61802819388 5.33967450634 -0.01131742088 -0.000 -0.000 0.000 H 3.39175422949 3.87200638269 -0.00704552340 0.000 -0.001 -0.000 H -1.39787683933 2.98334799634 -0.00369736757 0.000 -0.001 0.000 H 1.83794742242 -5.77033326187 -0.01295832570 -0.000 0.000 0.000 H -0.61749414542 -5.33746053721 -0.01121572048 -0.000 0.000 0.000 H -1.39833026435 -2.98175334118 -0.00345676225 0.000 0.001 0.000 H 3.39230213722 -3.86796714602 -0.00754158092 0.000 0.001 -0.000 H 4.58301895157 2.13678100538 0.00314824260 0.000 -0.000 -0.000 H 4.58784714512 -2.12983634010 0.00211631073 0.000 0.000 -0.000 H -1.68997263563 -0.00719388386 -5.74925805817 0.098 -0.000 -0.056 H 0.75224758084 -0.00860493512 -5.25016290812 0.003 -0.000 -0.054 H -3.29620044300 -0.00255800648 -3.88456579214 0.043 -0.001 -0.238 H 1.47161249279 -0.00457826661 -2.87685200854 0.071 -0.001 -0.244 H -1.69176120521 -0.00597000955 5.75026973076 -0.099 0.000 -0.058 H 0.75025791005 -0.00892914887 5.25161119224 0.002 0.000 -0.060 H 1.46975366817 -0.00523069331 2.87805400798 -0.073 0.001 -0.256 H -3.29750276746 -0.00099200484 3.88584245085 -0.044 0.001 -0.250 H -4.55513299541 0.00377930937 -2.13473279421 -0.061 0.000 0.085 H -4.55107479454 0.00501307822 2.13844314827 0.060 -0.000 0.086 H -6.83436893102 0.00806057203 1.19721860356 -0.040 0.000 -0.009 H 6.86748209639 1.20005966818 0.00372860376 -0.000 0.000 -0.000 61 Mode 150: freq=1733.12 N -0.44003451495 -0.00038510790 2.12369783068 -0.000 -0.001 -0.000 C -1.76594470239 0.00039861437 2.37754210613 -0.000 0.000 -0.000 C -2.24923313135 -0.00145267054 3.67997125809 -0.000 -0.000 0.000 C -1.33887502024 -0.00450793845 4.73956848945 0.000 0.000 -0.000 C 0.02462671625 -0.00591801736 4.46614405978 -0.000 -0.000 0.000 C 0.43187566201 -0.00376957955 3.13352499014 0.000 -0.000 -0.000 C -2.63984642995 0.00218980399 1.17162612704 0.000 0.001 0.000 N -1.98513620489 0.00132140951 0.00153900685 -0.000 -0.004 -0.000 C -2.63911589169 0.00167522827 -1.17277445342 0.000 0.001 -0.000 C -4.02452897564 0.00329996303 -1.20791476641 -0.000 -0.000 -0.000 C -4.73391255267 0.00451580118 -0.00020876193 0.000 0.000 0.000 C -4.02924140493 0.00399189729 1.20660077672 -0.000 -0.000 -0.000 Co 0.00000000000 0.00000000000 0.00000000000 0.000 0.006 0.000 N -0.43839318333 -0.00054206762 -2.12229806799 -0.000 -0.001 0.000 C -1.76408906064 -0.00030645034 -2.37697009192 0.000 0.000 0.000 C -2.24773885821 -0.00257631963 -3.67934971086 -0.000 -0.000 -0.000 C -1.33713102227 -0.00526459193 -4.73855802198 0.000 0.000 0.000 C 0.02654101484 -0.00591797621 -4.46472703619 -0.000 -0.000 -0.000 C 0.43371721952 -0.00363389350 -3.13225443930 0.000 -0.000 -0.000 S -6.53329279136 0.00637481657 -0.11611178087 -0.000 -0.000 -0.000 N 2.00981687167 0.00259443239 -0.00000686048 -0.001 -0.438 -0.000 C 2.67119656792 1.17263645248 0.00045766926 -0.004 0.362 -0.000 C 4.06129317470 1.20536051565 0.00241240325 0.227 -0.287 0.000 C 4.76783866331 0.00148799420 0.00346798881 -0.018 0.422 -0.000 C 4.05723810074 -1.20352939940 0.00211502115 -0.182 -0.264 -0.000 C 2.67108506586 -1.17139122066 0.00026591651 -0.019 0.341 0.000 C 1.82209539371 2.39842937406 -0.00175320633 0.085 -0.034 0.000 C 2.33938959521 3.68993217240 -0.00584554905 -0.004 -0.060 0.000 C 1.45736908622 4.77231118002 -0.00917967851 0.022 0.052 -0.000 C 0.08658913130 4.53522926787 -0.00833235387 -0.076 -0.106 0.000 C -0.35359617412 3.21325694137 -0.00400174376 0.013 0.109 -0.000 N 0.49290585413 2.18198449515 -0.00068475564 -0.035 -0.020 0.000 S 6.56718562933 -0.11349126889 0.00673479967 0.010 -0.016 0.000 C 1.82142022278 -2.39594383179 -0.00206827421 -0.072 -0.031 -0.000 C 2.33969079820 -3.68709653410 -0.00625612120 0.002 -0.057 -0.000 C 1.45789786198 -4.76953179608 -0.00945089783 -0.020 0.049 0.000 C 0.08684213972 -4.53272927032 -0.00840538011 0.071 -0.097 -0.000 C -0.35393854068 -3.21111942258 -0.00398541364 -0.013 0.099 0.000 N 0.49225266031 -2.17934076887 -0.00084210065 0.032 -0.017 -0.000 H 1.83694111827 5.77332096953 -0.01265611066 0.018 0.015 -0.000 H -0.61802819388 5.33967450634 -0.01131742088 0.049 0.028 -0.000 H 3.39175422949 3.87200638269 -0.00704552340 -0.006 0.015 -0.000 H -1.39787683933 2.98334799634 -0.00369736757 0.024 -0.042 0.000 H 1.83794742242 -5.77033326187 -0.01295832570 -0.016 0.014 0.000 H -0.61749414542 -5.33746053721 -0.01121572048 -0.046 0.027 0.000 H -1.39833026435 -2.98175334118 -0.00345676225 -0.022 -0.037 -0.000 H 3.39230213722 -3.86796714602 -0.00754158092 0.006 0.018 0.000 H 4.58301895157 2.13678100538 0.00314824260 -0.165 0.039 -0.000 H 4.58784714512 -2.12983634010 0.00211631073 0.132 0.021 0.000 H -1.68997263563 -0.00719388386 -5.74925805817 -0.000 0.000 0.000 H 0.75224758084 -0.00860493512 -5.25016290812 0.000 0.000 0.000 H -3.29620044300 -0.00255800648 -3.88456579214 -0.000 0.000 0.000 H 1.47161249279 -0.00457826661 -2.87685200854 0.000 0.001 0.000 H -1.69176120521 -0.00597000955 5.75026973076 -0.000 0.000 -0.000 H 0.75025791005 -0.00892914887 5.25161119224 0.000 0.000 -0.000 H 1.46975366817 -0.00523069331 2.87805400798 0.000 0.001 -0.000 H -3.29750276746 -0.00099200484 3.88584245085 -0.000 0.000 -0.000 H -4.55513299541 0.00377930937 -2.13473279421 0.000 0.000 -0.000 H -4.55107479454 0.00501307822 2.13844314827 0.000 0.000 0.000 H -6.83436893102 0.00806057203 1.19721860356 0.000 0.000 0.000 H 6.86748209639 1.20005966818 0.00372860376 -0.051 0.012 -0.000 61 Mode 151: freq=1738.03 N -0.44003451495 -0.00038510790 2.12369783068 -0.032 -0.000 0.025 C -1.76594470239 0.00039861437 2.37754210613 0.087 -0.000 0.027 C -2.24923313135 -0.00145267054 3.67997125809 -0.001 -0.000 0.065 C -1.33887502024 -0.00450793845 4.73956848945 0.016 0.000 -0.054 C 0.02462671625 -0.00591801736 4.46614405978 -0.070 -0.000 0.108 C 0.43187566201 -0.00376957955 3.13352499014 0.007 0.000 -0.115 C -2.63984642995 0.00218980399 1.17162612704 -0.009 0.000 -0.368 N -1.98513620489 0.00132140951 0.00153900685 0.000 0.000 0.455 C -2.63911589169 0.00167522827 -1.17277445342 -0.021 -0.000 -0.346 C -4.02452897564 0.00329996303 -1.20791476641 -0.175 0.000 0.255 C -4.73391255267 0.00451580118 -0.00020876193 -0.019 -0.000 -0.407 C -4.02924140493 0.00399189729 1.20660077672 0.226 -0.000 0.280 Co 0.00000000000 0.00000000000 0.00000000000 0.000 0.000 -0.007 N -0.43839318333 -0.00054206762 -2.12229806799 0.030 0.000 0.020 C -1.76408906064 -0.00030645034 -2.37697009192 -0.073 0.000 0.024 C -2.24773885821 -0.00257631963 -3.67934971086 0.000 0.000 0.063 C -1.33713102227 -0.00526459193 -4.73855802198 -0.017 -0.000 -0.051 C 0.02654101484 -0.00591797621 -4.46472703619 0.067 0.000 0.100 C 0.43371721952 -0.00363389350 -3.13225443930 -0.009 -0.000 -0.103 S -6.53329279136 0.00637481657 -0.11611178087 0.009 0.000 0.016 N 2.00981687167 0.00259443239 -0.00000686048 0.000 -0.000 0.004 C 2.67119656792 1.17263645248 0.00045766926 0.000 -0.000 -0.001 C 4.06129317470 1.20536051565 0.00241240325 -0.000 0.000 0.000 C 4.76783866331 0.00148799420 0.00346798881 0.000 0.000 -0.000 C 4.05723810074 -1.20352939940 0.00211502115 -0.000 -0.000 0.000 C 2.67108506586 -1.17139122066 0.00026591651 0.000 0.000 -0.001 C 1.82209539371 2.39842937406 -0.00175320633 0.000 0.000 -0.000 C 2.33938959521 3.68993217240 -0.00584554905 -0.000 -0.000 0.000 C 1.45736908622 4.77231118002 -0.00917967851 0.000 0.000 -0.000 C 0.08658913130 4.53522926787 -0.00833235387 -0.000 -0.000 0.000 C -0.35359617412 3.21325694137 -0.00400174376 0.000 0.000 0.000 N 0.49290585413 2.18198449515 -0.00068475564 -0.000 0.000 0.001 S 6.56718562933 -0.11349126889 0.00673479967 -0.000 -0.000 0.000 C 1.82142022278 -2.39594383179 -0.00206827421 0.000 -0.000 -0.000 C 2.33969079820 -3.68709653410 -0.00625612120 -0.000 0.000 0.000 C 1.45789786198 -4.76953179608 -0.00945089783 0.000 -0.000 -0.000 C 0.08684213972 -4.53272927032 -0.00840538011 -0.000 0.000 0.000 C -0.35393854068 -3.21111942258 -0.00398541364 0.000 0.000 0.000 N 0.49225266031 -2.17934076887 -0.00084210065 -0.000 -0.000 0.001 H 1.83694111827 5.77332096953 -0.01265611066 -0.000 0.000 -0.000 H -0.61802819388 5.33967450634 -0.01131742088 0.000 0.000 -0.000 H 3.39175422949 3.87200638269 -0.00704552340 -0.000 0.000 -0.000 H -1.39787683933 2.98334799634 -0.00369736757 0.000 0.000 -0.001 H 1.83794742242 -5.77033326187 -0.01295832570 -0.000 -0.000 -0.000 H -0.61749414542 -5.33746053721 -0.01121572048 0.000 -0.000 -0.000 H -1.39833026435 -2.98175334118 -0.00345676225 0.000 -0.000 -0.001 H 3.39230213722 -3.86796714602 -0.00754158092 -0.000 -0.000 -0.000 H 4.58301895157 2.13678100538 0.00314824260 0.000 -0.000 -0.000 H 4.58784714512 -2.12983634010 0.00211631073 0.000 0.000 -0.000 H -1.68997263563 -0.00719388386 -5.74925805817 -0.016 -0.000 -0.015 H 0.75224758084 -0.00860493512 -5.25016290812 -0.044 -0.000 -0.027 H -3.29620044300 -0.00255800648 -3.88456579214 0.007 -0.000 -0.020 H 1.47161249279 -0.00457826661 -2.87685200854 -0.023 0.000 0.039 H -1.69176120521 -0.00597000955 5.75026973076 0.019 0.000 -0.015 H 0.75025791005 -0.00892914887 5.25161119224 0.047 -0.000 -0.027 H 1.46975366817 -0.00523069331 2.87805400798 0.025 -0.000 0.045 H -3.29750276746 -0.00099200484 3.88584245085 -0.006 0.000 -0.016 H -4.55513299541 0.00377930937 -2.13473279421 0.128 -0.000 -0.020 H -4.55107479454 0.00501307822 2.13844314827 -0.163 0.000 -0.040 H -6.83436893102 0.00806057203 1.19721860356 -0.049 0.000 -0.012 H 6.86748209639 1.20005966818 0.00372860376 -0.000 -0.000 -0.000 61 Mode 152: freq=1758.61 N -0.44003451495 -0.00038510790 2.12369783068 0.174 -0.000 0.070 C -1.76594470239 0.00039861437 2.37754210613 -0.129 0.000 0.062 C -2.24923313135 -0.00145267054 3.67997125809 0.120 -0.000 0.018 C -1.33887502024 -0.00450793845 4.73956848945 -0.302 0.000 -0.054 C 0.02462671625 -0.00591801736 4.46614405978 0.228 -0.000 -0.053 C 0.43187566201 -0.00376957955 3.13352499014 -0.128 0.000 -0.094 C -2.63984642995 0.00218980399 1.17162612704 -0.102 0.000 -0.018 N -1.98513620489 0.00132140951 0.00153900685 0.023 -0.000 -0.012 C -2.63911589169 0.00167522827 -1.17277445342 -0.099 0.000 0.040 C -4.02452897564 0.00329996303 -1.20791476641 0.157 -0.000 -0.063 C -4.73391255267 0.00451580118 -0.00020876193 -0.091 0.000 0.008 C -4.02924140493 0.00399189729 1.20660077672 0.141 -0.000 0.049 Co 0.00000000000 0.00000000000 0.00000000000 -0.002 0.000 0.001 N -0.43839318333 -0.00054206762 -2.12229806799 0.237 -0.000 -0.093 C -1.76408906064 -0.00030645034 -2.37697009192 -0.184 -0.000 -0.082 C -2.24773885821 -0.00257631963 -3.67934971086 0.166 -0.000 -0.033 C -1.33713102227 -0.00526459193 -4.73855802198 -0.410 0.000 0.077 C 0.02654101484 -0.00591797621 -4.46472703619 0.306 -0.000 0.069 C 0.43371721952 -0.00363389350 -3.13225443930 -0.171 0.000 0.129 S -6.53329279136 0.00637481657 -0.11611178087 0.001 -0.000 -0.000 N 2.00981687167 0.00259443239 -0.00000686048 -0.004 -0.002 -0.001 C 2.67119656792 1.17263645248 0.00045766926 0.023 -0.003 0.000 C 4.06129317470 1.20536051565 0.00241240325 -0.039 0.015 -0.000 C 4.76783866331 0.00148799420 0.00346798881 0.028 0.001 0.000 C 4.05723810074 -1.20352939940 0.00211502115 -0.043 -0.018 -0.000 C 2.67108506586 -1.17139122066 0.00026591651 0.023 0.008 0.000 C 1.82209539371 2.39842937406 -0.00175320633 0.058 0.020 -0.000 C 2.33938959521 3.68993217240 -0.00584554905 -0.048 0.012 -0.000 C 1.45736908622 4.77231118002 -0.00917967851 0.117 -0.026 0.000 C 0.08658913130 4.53522926787 -0.00833235387 -0.087 -0.017 0.000 C -0.35359617412 3.21325694137 -0.00400174376 0.047 -0.037 0.000 N 0.49290585413 2.18198449515 -0.00068475564 -0.068 0.027 -0.000 S 6.56718562933 -0.11349126889 0.00673479967 -0.001 -0.000 -0.000 C 1.82142022278 -2.39594383179 -0.00206827421 0.068 -0.024 -0.000 C 2.33969079820 -3.68709653410 -0.00625612120 -0.056 -0.014 -0.000 C 1.45789786198 -4.76953179608 -0.00945089783 0.135 0.030 0.000 C 0.08684213972 -4.53272927032 -0.00840538011 -0.101 0.019 0.000 C -0.35393854068 -3.21111942258 -0.00398541364 0.054 0.043 0.000 N 0.49225266031 -2.17934076887 -0.00084210065 -0.079 -0.031 -0.000 H 1.83694111827 5.77332096953 -0.01265611066 -0.046 0.025 -0.000 H -0.61802819388 5.33967450634 -0.01131742088 0.011 0.031 -0.000 H 3.39175422949 3.87200638269 -0.00704552340 -0.017 0.005 0.000 H -1.39787683933 2.98334799634 -0.00369736757 0.007 0.026 -0.000 H 1.83794742242 -5.77033326187 -0.01295832570 -0.054 -0.028 -0.000 H -0.61749414542 -5.33746053721 -0.01121572048 0.013 -0.036 -0.000 H -1.39833026435 -2.98175334118 -0.00345676225 0.008 -0.030 -0.000 H 3.39230213722 -3.86796714602 -0.00754158092 -0.020 -0.006 0.000 H 4.58301895157 2.13678100538 0.00314824260 0.023 -0.015 0.000 H 4.58784714512 -2.12983634010 0.00211631073 0.026 0.016 0.000 H -1.68997263563 -0.00719388386 -5.74925805817 0.164 -0.000 -0.082 H 0.75224758084 -0.00860493512 -5.25016290812 -0.038 -0.000 -0.113 H -3.29620044300 -0.00255800648 -3.88456579214 0.060 -0.000 -0.020 H 1.47161249279 -0.00457826661 -2.87685200854 -0.024 -0.000 -0.094 H -1.69176120521 -0.00597000955 5.75026973076 0.120 -0.000 0.061 H 0.75025791005 -0.00892914887 5.25161119224 -0.030 -0.000 0.085 H 1.46975366817 -0.00523069331 2.87805400798 -0.018 -0.000 0.070 H -3.29750276746 -0.00099200484 3.88584245085 0.044 -0.000 0.020 H -4.55513299541 0.00377930937 -2.13473279421 -0.091 0.000 0.060 H -4.55107479454 0.00501307822 2.13844314827 -0.077 0.000 -0.053 H -6.83436893102 0.00806057203 1.19721860356 0.003 0.000 0.000 H 6.86748209639 1.20005966818 0.00372860376 -0.001 -0.000 0.000 61 Mode 153: freq=1759.61 N -0.44003451495 -0.00038510790 2.12369783068 0.038 0.000 0.016 C -1.76594470239 0.00039861437 2.37754210613 -0.019 -0.000 0.020 C -2.24923313135 -0.00145267054 3.67997125809 0.024 -0.000 -0.002 C -1.33887502024 -0.00450793845 4.73956848945 -0.066 0.000 -0.009 C 0.02462671625 -0.00591801736 4.46614405978 0.052 -0.000 -0.015 C 0.43187566201 -0.00376957955 3.13352499014 -0.030 0.000 -0.020 C -2.63984642995 0.00218980399 1.17162612704 -0.052 -0.000 -0.009 N -1.98513620489 0.00132140951 0.00153900685 0.012 0.000 -0.006 C -2.63911589169 0.00167522827 -1.17277445342 -0.045 -0.000 0.023 C -4.02452897564 0.00329996303 -1.20791476641 0.069 -0.000 -0.029 C -4.73391255267 0.00451580118 -0.00020876193 -0.038 0.000 0.006 C -4.02924140493 0.00399189729 1.20660077672 0.062 -0.000 0.019 Co 0.00000000000 0.00000000000 0.00000000000 -0.003 -0.000 0.000 N -0.43839318333 -0.00054206762 -2.12229806799 0.091 -0.000 -0.035 C -1.76408906064 -0.00030645034 -2.37697009192 -0.068 -0.000 -0.035 C -2.24773885821 -0.00257631963 -3.67934971086 0.063 -0.000 -0.009 C -1.33713102227 -0.00526459193 -4.73855802198 -0.158 0.000 0.028 C 0.02654101484 -0.00591797621 -4.46472703619 0.119 -0.000 0.029 C 0.43371721952 -0.00363389350 -3.13225443930 -0.067 0.000 0.047 S -6.53329279136 0.00637481657 -0.11611178087 0.000 0.000 -0.000 N 2.00981687167 0.00259443239 -0.00000686048 0.026 0.010 -0.000 C 2.67119656792 1.17263645248 0.00045766926 -0.115 0.025 -0.000 C 4.06129317470 1.20536051565 0.00241240325 0.163 -0.058 0.000 C 4.76783866331 0.00148799420 0.00346798881 -0.106 -0.007 -0.000 C 4.05723810074 -1.20352939940 0.00211502115 0.180 0.072 0.000 C 2.67108506586 -1.17139122066 0.00026591651 -0.113 -0.046 -0.000 C 1.82209539371 2.39842937406 -0.00175320633 -0.130 -0.062 0.000 C 2.33938959521 3.68993217240 -0.00584554905 0.118 -0.019 0.000 C 1.45736908622 4.77231118002 -0.00917967851 -0.296 0.060 -0.000 C 0.08658913130 4.53522926787 -0.00833235387 0.226 0.049 -0.000 C -0.35359617412 3.21325694137 -0.00400174376 -0.124 0.092 -0.000 N 0.49290585413 2.18198449515 -0.00068475564 0.173 -0.071 0.000 S 6.56718562933 -0.11349126889 0.00673479967 0.001 0.000 -0.000 C 1.82142022278 -2.39594383179 -0.00206827421 -0.183 0.080 0.000 C 2.33969079820 -3.68709653410 -0.00625612120 0.160 0.033 0.000 C 1.45789786198 -4.76953179608 -0.00945089783 -0.395 -0.085 -0.000 C 0.08684213972 -4.53272927032 -0.00840538011 0.298 -0.062 -0.000 C -0.35393854068 -3.21111942258 -0.00398541364 -0.163 -0.123 -0.000 N 0.49225266031 -2.17934076887 -0.00084210065 0.231 0.093 0.000 H 1.83694111827 5.77332096953 -0.01265611066 0.116 -0.063 0.000 H -0.61802819388 5.33967450634 -0.01131742088 -0.033 -0.083 0.000 H 3.39175422949 3.87200638269 -0.00704552340 0.044 -0.025 0.000 H -1.39787683933 2.98334799634 -0.00369736757 -0.020 -0.065 0.000 H 1.83794742242 -5.77033326187 -0.01295832570 0.155 0.084 0.000 H -0.61749414542 -5.33746053721 -0.01121572048 -0.041 0.108 0.000 H -1.39833026435 -2.98175334118 -0.00345676225 -0.026 0.086 0.000 H 3.39230213722 -3.86796714602 -0.00754158092 0.058 0.025 0.000 H 4.58301895157 2.13678100538 0.00314824260 -0.092 0.061 -0.000 H 4.58784714512 -2.12983634010 0.00211631073 -0.106 -0.069 -0.000 H -1.68997263563 -0.00719388386 -5.74925805817 0.062 -0.000 -0.032 H 0.75224758084 -0.00860493512 -5.25016290812 -0.016 -0.000 -0.045 H -3.29620044300 -0.00255800648 -3.88456579214 0.023 -0.000 -0.010 H 1.47161249279 -0.00457826661 -2.87685200854 -0.010 -0.000 -0.034 H -1.69176120521 -0.00597000955 5.75026973076 0.025 -0.000 0.014 H 0.75025791005 -0.00892914887 5.25161119224 -0.009 -0.000 0.020 H 1.46975366817 -0.00523069331 2.87805400798 -0.005 -0.000 0.015 H -3.29750276746 -0.00099200484 3.88584245085 0.010 -0.000 0.010 H -4.55513299541 0.00377930937 -2.13473279421 -0.040 0.000 0.026 H -4.55107479454 0.00501307822 2.13844314827 -0.033 0.000 -0.024 H -6.83436893102 0.00806057203 1.19721860356 0.002 -0.000 0.000 H 6.86748209639 1.20005966818 0.00372860376 0.003 -0.000 0.000 61 Mode 154: freq=1760.53 N -0.44003451495 -0.00038510790 2.12369783068 0.267 -0.000 0.092 C -1.76594470239 0.00039861437 2.37754210613 -0.246 0.000 0.075 C -2.24923313135 -0.00145267054 3.67997125809 0.192 -0.000 0.050 C -1.33887502024 -0.00450793845 4.73956848945 -0.455 0.001 -0.088 C 0.02462671625 -0.00591801736 4.46614405978 0.338 -0.000 -0.082 C 0.43187566201 -0.00376957955 3.13352499014 -0.185 0.001 -0.125 C -2.63984642995 0.00218980399 1.17162612704 0.035 -0.000 -0.038 N -1.98513620489 0.00132140951 0.00153900685 0.003 0.000 0.025 C -2.63911589169 0.00167522827 -1.17277445342 -0.067 0.000 -0.025 C -4.02452897564 0.00329996303 -1.20791476641 0.025 -0.000 0.020 C -4.73391255267 0.00451580118 -0.00020876193 -0.016 -0.000 -0.049 C -4.02924140493 0.00399189729 1.20660077672 0.026 -0.000 0.040 Co 0.00000000000 0.00000000000 0.00000000000 -0.001 -0.000 -0.003 N -0.43839318333 -0.00054206762 -2.12229806799 -0.195 0.000 0.061 C -1.76408906064 -0.00030645034 -2.37697009192 0.192 -0.000 0.053 C -2.24773885821 -0.00257631963 -3.67934971086 -0.142 0.000 0.037 C -1.33713102227 -0.00526459193 -4.73855802198 0.329 -0.000 -0.063 C 0.02654101484 -0.00591797621 -4.46472703619 -0.245 0.000 -0.063 C 0.43371721952 -0.00363389350 -3.13225443930 0.131 -0.000 -0.082 S -6.53329279136 0.00637481657 -0.11611178087 0.001 0.000 0.003 N 2.00981687167 0.00259443239 -0.00000686048 0.003 0.001 0.003 C 2.67119656792 1.17263645248 0.00045766926 -0.011 0.002 -0.001 C 4.06129317470 1.20536051565 0.00241240325 0.014 -0.004 0.000 C 4.76783866331 0.00148799420 0.00346798881 -0.009 -0.001 -0.000 C 4.05723810074 -1.20352939940 0.00211502115 0.015 0.006 0.000 C 2.67108506586 -1.17139122066 0.00026591651 -0.010 -0.005 -0.001 C 1.82209539371 2.39842937406 -0.00175320633 -0.005 -0.004 -0.000 C 2.33938959521 3.68993217240 -0.00584554905 0.006 -0.000 0.000 C 1.45736908622 4.77231118002 -0.00917967851 -0.015 0.003 -0.000 C 0.08658913130 4.53522926787 -0.00833235387 0.012 0.003 -0.000 C -0.35359617412 3.21325694137 -0.00400174376 -0.007 0.005 -0.000 N 0.49290585413 2.18198449515 -0.00068475564 0.009 -0.004 0.001 S 6.56718562933 -0.11349126889 0.00673479967 0.000 0.000 0.000 C 1.82142022278 -2.39594383179 -0.00206827421 -0.014 0.006 -0.000 C 2.33969079820 -3.68709653410 -0.00625612120 0.012 0.002 0.000 C 1.45789786198 -4.76953179608 -0.00945089783 -0.030 -0.006 -0.000 C 0.08684213972 -4.53272927032 -0.00840538011 0.023 -0.005 -0.000 C -0.35393854068 -3.21111942258 -0.00398541364 -0.013 -0.009 -0.000 N 0.49225266031 -2.17934076887 -0.00084210065 0.018 0.007 0.001 H 1.83694111827 5.77332096953 -0.01265611066 0.006 -0.003 -0.000 H -0.61802819388 5.33967450634 -0.01131742088 -0.002 -0.005 -0.000 H 3.39175422949 3.87200638269 -0.00704552340 0.002 -0.002 -0.000 H -1.39787683933 2.98334799634 -0.00369736757 -0.001 -0.003 0.000 H 1.83794742242 -5.77033326187 -0.01295832570 0.012 0.006 0.000 H -0.61749414542 -5.33746053721 -0.01121572048 -0.003 0.008 -0.000 H -1.39833026435 -2.98175334118 -0.00345676225 -0.002 0.006 0.000 H 3.39230213722 -3.86796714602 -0.00754158092 0.004 0.002 -0.000 H 4.58301895157 2.13678100538 0.00314824260 -0.007 0.005 -0.000 H 4.58784714512 -2.12983634010 0.00211631073 -0.009 -0.006 -0.000 H -1.68997263563 -0.00719388386 -5.74925805817 -0.130 0.000 0.065 H 0.75224758084 -0.00860493512 -5.25016290812 0.031 0.000 0.087 H -3.29620044300 -0.00255800648 -3.88456579214 -0.046 0.000 -0.005 H 1.47161249279 -0.00457826661 -2.87685200854 0.022 0.000 0.062 H -1.69176120521 -0.00597000955 5.75026973076 0.180 -0.000 0.090 H 0.75025791005 -0.00892914887 5.25161119224 -0.041 -0.000 0.122 H 1.46975366817 -0.00523069331 2.87805400798 -0.029 -0.000 0.092 H -3.29750276746 -0.00099200484 3.88584245085 0.064 -0.000 -0.000 H -4.55513299541 0.00377930937 -2.13473279421 0.000 -0.000 0.013 H -4.55107479454 0.00501307822 2.13844314827 -0.030 0.000 -0.006 H -6.83436893102 0.00806057203 1.19721860356 -0.006 0.000 -0.001 H 6.86748209639 1.20005966818 0.00372860376 0.000 -0.000 -0.000 61 Mode 155: freq=1761.76 N -0.44003451495 -0.00038510790 2.12369783068 0.006 -0.001 0.002 C -1.76594470239 0.00039861437 2.37754210613 -0.004 0.000 0.002 C -2.24923313135 -0.00145267054 3.67997125809 0.004 -0.000 0.000 C -1.33887502024 -0.00450793845 4.73956848945 -0.010 0.000 -0.002 C 0.02462671625 -0.00591801736 4.46614405978 0.008 -0.000 -0.002 C 0.43187566201 -0.00376957955 3.13352499014 -0.004 0.000 -0.003 C -2.63984642995 0.00218980399 1.17162612704 -0.004 0.001 -0.001 N -1.98513620489 0.00132140951 0.00153900685 0.001 -0.003 -0.000 C -2.63911589169 0.00167522827 -1.17277445342 -0.005 0.001 0.001 C -4.02452897564 0.00329996303 -1.20791476641 0.006 -0.000 -0.002 C -4.73391255267 0.00451580118 -0.00020876193 -0.003 0.000 -0.000 C -4.02924140493 0.00399189729 1.20660077672 0.005 -0.000 0.002 Co 0.00000000000 0.00000000000 0.00000000000 -0.000 0.002 -0.000 N -0.43839318333 -0.00054206762 -2.12229806799 0.002 -0.001 -0.001 C -1.76408906064 -0.00030645034 -2.37697009192 -0.000 0.000 -0.001 C -2.24773885821 -0.00257631963 -3.67934971086 0.001 -0.000 0.000 C -1.33713102227 -0.00526459193 -4.73855802198 -0.004 0.000 0.001 C 0.02654101484 -0.00591797621 -4.46472703619 0.003 -0.000 0.001 C 0.43371721952 -0.00363389350 -3.13225443930 -0.002 0.000 0.001 S -6.53329279136 0.00637481657 -0.11611178087 0.000 -0.000 0.000 N 2.00981687167 0.00259443239 -0.00000686048 0.002 -0.030 0.000 C 2.67119656792 1.17263645248 0.00045766926 0.039 0.041 -0.000 C 4.06129317470 1.20536051565 0.00241240325 0.025 -0.043 0.000 C 4.76783866331 0.00148799420 0.00346798881 -0.013 0.056 -0.000 C 4.05723810074 -1.20352939940 0.00211502115 0.016 -0.027 0.000 C 2.67108506586 -1.17139122066 0.00026591651 -0.064 0.031 -0.000 C 1.82209539371 2.39842937406 -0.00175320633 -0.252 -0.070 0.000 C 2.33938959521 3.68993217240 -0.00584554905 0.187 -0.053 0.000 C 1.45736908622 4.77231118002 -0.00917967851 -0.439 0.097 -0.000 C 0.08658913130 4.53522926787 -0.00833235387 0.329 0.075 -0.000 C -0.35359617412 3.21325694137 -0.00400174376 -0.174 0.118 -0.000 N 0.49290585413 2.18198449515 -0.00068475564 0.263 -0.091 0.000 S 6.56718562933 -0.11349126889 0.00673479967 0.001 -0.003 0.000 C 1.82142022278 -2.39594383179 -0.00206827421 0.209 -0.055 -0.000 C 2.33969079820 -3.68709653410 -0.00625612120 -0.148 -0.040 -0.000 C 1.45789786198 -4.76953179608 -0.00945089783 0.343 0.074 0.000 C 0.08684213972 -4.53272927032 -0.00840538011 -0.258 0.063 0.000 C -0.35393854068 -3.21111942258 -0.00398541364 0.135 0.084 0.000 N 0.49225266031 -2.17934076887 -0.00084210065 -0.207 -0.067 -0.000 H 1.83694111827 5.77332096953 -0.01265611066 0.171 -0.091 0.000 H -0.61802819388 5.33967450634 -0.01131742088 -0.043 -0.115 0.000 H 3.39175422949 3.87200638269 -0.00704552340 0.062 -0.001 -0.000 H -1.39787683933 2.98334799634 -0.00369736757 -0.031 -0.082 0.000 H 1.83794742242 -5.77033326187 -0.01295832570 -0.133 -0.071 -0.000 H -0.61749414542 -5.33746053721 -0.01121572048 0.035 -0.090 -0.000 H -1.39833026435 -2.98175334118 -0.00345676225 0.026 -0.060 -0.000 H 3.39230213722 -3.86796714602 -0.00754158092 -0.049 0.003 0.000 H 4.58301895157 2.13678100538 0.00314824260 -0.030 0.005 -0.000 H 4.58784714512 -2.12983634010 0.00211631073 0.006 -0.010 0.000 H -1.68997263563 -0.00719388386 -5.74925805817 0.001 0.000 -0.001 H 0.75224758084 -0.00860493512 -5.25016290812 -0.001 0.000 -0.001 H -3.29620044300 -0.00255800648 -3.88456579214 0.001 0.000 -0.001 H 1.47161249279 -0.00457826661 -2.87685200854 -0.000 -0.000 -0.001 H -1.69176120521 -0.00597000955 5.75026973076 0.004 0.000 0.002 H 0.75025791005 -0.00892914887 5.25161119224 -0.001 0.000 0.003 H 1.46975366817 -0.00523069331 2.87805400798 -0.001 -0.000 0.002 H -3.29750276746 -0.00099200484 3.88584245085 0.001 0.000 0.001 H -4.55513299541 0.00377930937 -2.13473279421 -0.003 0.000 0.002 H -4.55107479454 0.00501307822 2.13844314827 -0.003 0.000 -0.002 H -6.83436893102 0.00806057203 1.19721860356 0.000 0.000 -0.000 H 6.86748209639 1.20005966818 0.00372860376 -0.007 0.002 -0.000 61 Mode 156: freq=1782.72 N -0.44003451495 -0.00038510790 2.12369783068 0.005 0.001 0.006 C -1.76594470239 0.00039861437 2.37754210613 0.002 -0.000 -0.012 C -2.24923313135 -0.00145267054 3.67997125809 0.002 -0.000 0.015 C -1.33887502024 -0.00450793845 4.73956848945 -0.005 0.000 -0.008 C 0.02462671625 -0.00591801736 4.46614405978 -0.000 -0.000 0.008 C 0.43187566201 -0.00376957955 3.13352499014 -0.003 -0.000 -0.014 C -2.63984642995 0.00218980399 1.17162612704 -0.016 0.000 0.005 N -1.98513620489 0.00132140951 0.00153900685 0.008 -0.000 -0.001 C -2.63911589169 0.00167522827 -1.17277445342 -0.017 0.000 -0.004 C -4.02452897564 0.00329996303 -1.20791476641 0.018 -0.000 -0.004 C -4.73391255267 0.00451580118 -0.00020876193 -0.009 0.000 0.000 C -4.02924140493 0.00399189729 1.20660077672 0.017 -0.000 0.004 Co 0.00000000000 0.00000000000 0.00000000000 -0.002 -0.002 0.000 N -0.43839318333 -0.00054206762 -2.12229806799 0.005 0.001 -0.008 C -1.76408906064 -0.00030645034 -2.37697009192 0.003 -0.000 0.015 C -2.24773885821 -0.00257631963 -3.67934971086 0.002 -0.000 -0.020 C -1.33713102227 -0.00526459193 -4.73855802198 -0.005 0.000 0.010 C 0.02654101484 -0.00591797621 -4.46472703619 -0.002 -0.000 -0.012 C 0.43371721952 -0.00363389350 -3.13225443930 -0.003 -0.000 0.018 S -6.53329279136 0.00637481657 -0.11611178087 0.000 0.000 0.000 N 2.00981687167 0.00259443239 -0.00000686048 -0.055 0.045 -0.000 C 2.67119656792 1.17263645248 0.00045766926 0.166 -0.129 0.000 C 4.06129317470 1.20536051565 0.00241240325 -0.210 0.106 -0.000 C 4.76783866331 0.00148799420 0.00346798881 0.103 -0.052 0.000 C 4.05723810074 -1.20352939940 0.00211502115 -0.160 -0.023 -0.000 C 2.67108506586 -1.17139122066 0.00026591651 0.176 -0.029 0.000 C 1.82209539371 2.39842937406 -0.00175320633 -0.008 0.354 -0.001 C 2.33938959521 3.68993217240 -0.00584554905 0.053 -0.457 0.001 C 1.45736908622 4.77231118002 -0.00917967851 -0.083 0.224 -0.001 C 0.08658913130 4.53522926787 -0.00833235387 -0.091 -0.258 0.001 C -0.35359617412 3.21325694137 -0.00400174376 -0.035 0.356 -0.001 N 0.49290585413 2.18198449515 -0.00068475564 0.068 -0.173 0.000 S 6.56718562933 -0.11349126889 0.00673479967 -0.002 0.002 0.000 C 1.82142022278 -2.39594383179 -0.00206827421 -0.106 0.084 0.000 C 2.33969079820 -3.68709653410 -0.00625612120 0.033 -0.089 -0.000 C 1.45789786198 -4.76953179608 -0.00945089783 -0.059 0.037 0.000 C 0.08684213972 -4.53272927032 -0.00840538011 0.082 -0.089 -0.000 C -0.35393854068 -3.21111942258 -0.00398541364 -0.016 0.096 0.000 N 0.49225266031 -2.17934076887 -0.00084210065 0.039 -0.043 -0.000 H 1.83694111827 5.77332096953 -0.01265611066 0.076 0.042 -0.000 H -0.61802819388 5.33967450634 -0.01131742088 0.113 0.034 -0.000 H 3.39175422949 3.87200638269 -0.00704552340 -0.047 0.221 -0.001 H -1.39787683933 2.98334799634 -0.00369736757 0.051 -0.142 0.000 H 1.83794742242 -5.77033326187 -0.01295832570 0.010 0.025 0.000 H -0.61749414542 -5.33746053721 -0.01121572048 -0.036 0.024 0.000 H -1.39833026435 -2.98175334118 -0.00345676225 -0.022 -0.037 -0.000 H 3.39230213722 -3.86796714602 -0.00754158092 0.022 0.025 0.000 H 4.58301895157 2.13678100538 0.00314824260 0.126 -0.074 0.000 H 4.58784714512 -2.12983634010 0.00211631073 0.062 0.060 0.000 H -1.68997263563 -0.00719388386 -5.74925805817 0.004 0.000 0.002 H 0.75224758084 -0.00860493512 -5.25016290812 0.005 0.000 0.001 H -3.29620044300 -0.00255800648 -3.88456579214 -0.002 -0.000 0.008 H 1.47161249279 -0.00457826661 -2.87685200854 0.003 -0.000 -0.010 H -1.69176120521 -0.00597000955 5.75026973076 0.003 0.000 -0.001 H 0.75025791005 -0.00892914887 5.25161119224 0.003 0.000 -0.000 H 1.46975366817 -0.00523069331 2.87805400798 0.002 -0.000 0.009 H -3.29750276746 -0.00099200484 3.88584245085 -0.001 -0.000 -0.006 H -4.55513299541 0.00377930937 -2.13473279421 -0.006 -0.000 0.005 H -4.55107479454 0.00501307822 2.13844314827 -0.005 -0.000 -0.005 H -6.83436893102 0.00806057203 1.19721860356 0.000 -0.000 -0.000 H 6.86748209639 1.20005966818 0.00372860376 0.005 -0.002 -0.000 61 Mode 157: freq=1783.53 N -0.44003451495 -0.00038510790 2.12369783068 -0.008 0.001 -0.015 C -1.76594470239 0.00039861437 2.37754210613 -0.003 -0.000 0.033 C -2.24923313135 -0.00145267054 3.67997125809 -0.004 -0.000 -0.040 C -1.33887502024 -0.00450793845 4.73956848945 0.007 -0.000 0.020 C 0.02462671625 -0.00591801736 4.46614405978 0.007 -0.000 -0.024 C 0.43187566201 -0.00376957955 3.13352499014 0.004 -0.000 0.033 C -2.63984642995 0.00218980399 1.17162612704 0.012 0.000 -0.012 N -1.98513620489 0.00132140951 0.00153900685 -0.008 -0.000 0.001 C -2.63911589169 0.00167522827 -1.17277445342 0.012 0.000 0.011 C -4.02452897564 0.00329996303 -1.20791476641 -0.011 0.000 0.001 C -4.73391255267 0.00451580118 -0.00020876193 0.006 -0.000 -0.000 C -4.02924140493 0.00399189729 1.20660077672 -0.010 0.000 -0.000 Co 0.00000000000 0.00000000000 0.00000000000 0.003 -0.002 -0.000 N -0.43839318333 -0.00054206762 -2.12229806799 -0.008 0.001 0.017 C -1.76408906064 -0.00030645034 -2.37697009192 -0.004 -0.000 -0.035 C -2.24773885821 -0.00257631963 -3.67934971086 -0.004 0.000 0.044 C -1.33713102227 -0.00526459193 -4.73855802198 0.007 -0.000 -0.021 C 0.02654101484 -0.00591797621 -4.46472703619 0.008 -0.000 0.026 C 0.43371721952 -0.00363389350 -3.13225443930 0.005 -0.000 -0.036 S -6.53329279136 0.00637481657 -0.11611178087 0.000 0.000 -0.000 N 2.00981687167 0.00259443239 -0.00000686048 0.031 0.049 0.000 C 2.67119656792 1.17263645248 0.00045766926 -0.116 -0.005 -0.000 C 4.06129317470 1.20536051565 0.00241240325 0.107 -0.017 0.000 C 4.76783866331 0.00148799420 0.00346798881 -0.078 -0.046 -0.000 C 4.05723810074 -1.20352939940 0.00211502115 0.173 0.096 0.000 C 2.67108506586 -1.17139122066 0.00026591651 -0.126 -0.146 -0.000 C 1.82209539371 2.39842937406 -0.00175320633 0.054 -0.020 0.000 C 2.33938959521 3.68993217240 -0.00584554905 -0.026 0.038 -0.000 C 1.45736908622 4.77231118002 -0.00917967851 0.045 -0.023 0.000 C 0.08658913130 4.53522926787 -0.00833235387 -0.025 0.002 -0.000 C -0.35359617412 3.21325694137 -0.00400174376 0.015 -0.017 0.000 N 0.49290585413 2.18198449515 -0.00068475564 -0.033 0.009 -0.000 S 6.56718562933 -0.11349126889 0.00673479967 -0.000 0.002 -0.000 C 1.82142022278 -2.39594383179 -0.00206827421 -0.012 0.385 0.001 C 2.33969079820 -3.68709653410 -0.00625612120 -0.047 -0.489 -0.002 C 1.45789786198 -4.76953179608 -0.00945089783 0.075 0.238 0.001 C 0.08684213972 -4.53272927032 -0.00840538011 0.109 -0.281 -0.001 C -0.35393854068 -3.21111942258 -0.00398541364 0.033 0.385 0.001 N 0.49225266031 -2.17934076887 -0.00084210065 -0.063 -0.187 -0.001 H 1.83694111827 5.77332096953 -0.01265611066 -0.019 0.005 -0.000 H -0.61802819388 5.33967450634 -0.01131742088 -0.003 0.006 -0.000 H 3.39175422949 3.87200638269 -0.00704552340 -0.003 -0.027 0.000 H -1.39787683933 2.98334799634 -0.00369736757 0.002 0.007 -0.000 H 1.83794742242 -5.77033326187 -0.01295832570 -0.076 0.048 0.000 H -0.61749414542 -5.33746053721 -0.01121572048 -0.123 0.039 0.000 H -1.39833026435 -2.98175334118 -0.00345676225 -0.057 -0.153 -0.000 H 3.39230213722 -3.86796714602 -0.00754158092 0.052 0.234 0.001 H 4.58301895157 2.13678100538 0.00314824260 -0.050 0.042 -0.000 H 4.58784714512 -2.12983634010 0.00211631073 -0.118 -0.067 -0.000 H -1.68997263563 -0.00719388386 -5.74925805817 -0.007 0.000 -0.004 H 0.75224758084 -0.00860493512 -5.25016290812 -0.011 0.000 -0.003 H -3.29620044300 -0.00255800648 -3.88456579214 0.005 -0.000 -0.019 H 1.47161249279 -0.00457826661 -2.87685200854 -0.006 -0.000 0.017 H -1.69176120521 -0.00597000955 5.75026973076 -0.006 0.000 0.004 H 0.75025791005 -0.00892914887 5.25161119224 -0.010 0.000 0.003 H 1.46975366817 -0.00523069331 2.87805400798 -0.005 -0.000 -0.015 H -3.29750276746 -0.00099200484 3.88584245085 0.005 -0.000 0.018 H -4.55513299541 0.00377930937 -2.13473279421 0.001 -0.000 -0.002 H -4.55107479454 0.00501307822 2.13844314827 0.000 -0.000 0.002 H -6.83436893102 0.00806057203 1.19721860356 0.000 -0.000 0.000 H 6.86748209639 1.20005966818 0.00372860376 0.008 -0.001 0.000 61 Mode 158: freq=1784.90 N -0.44003451495 -0.00038510790 2.12369783068 -0.085 0.000 -0.102 C -1.76594470239 0.00039861437 2.37754210613 0.103 -0.000 0.219 C -2.24923313135 -0.00145267054 3.67997125809 -0.075 0.001 -0.292 C -1.33887502024 -0.00450793845 4.73956848945 0.114 -0.000 0.143 C 0.02462671625 -0.00591801736 4.46614405978 0.004 0.000 -0.132 C 0.43187566201 -0.00376957955 3.13352499014 0.045 -0.000 0.203 C -2.63984642995 0.00218980399 1.17162612704 -0.325 0.000 -0.066 N -1.98513620489 0.00132140951 0.00153900685 0.123 -0.000 0.003 C -2.63911589169 0.00167522827 -1.17277445342 -0.345 0.000 0.031 C -4.02452897564 0.00329996303 -1.20791476641 0.343 -0.000 -0.096 C -4.73391255267 0.00451580118 -0.00020876193 -0.180 0.000 -0.014 C -4.02924140493 0.00399189729 1.20660077672 0.334 -0.000 0.114 Co 0.00000000000 0.00000000000 0.00000000000 0.003 0.000 -0.000 N -0.43839318333 -0.00054206762 -2.12229806799 -0.078 0.000 0.020 C -1.76408906064 -0.00030645034 -2.37697009192 0.149 -0.000 -0.058 C -2.24773885821 -0.00257631963 -3.67934971086 -0.070 0.000 0.094 C -1.33713102227 -0.00526459193 -4.73855802198 0.112 -0.000 -0.050 C 0.02654101484 -0.00591797621 -4.46472703619 -0.063 0.000 -0.001 C 0.43371721952 -0.00363389350 -3.13225443930 0.035 -0.000 -0.034 S -6.53329279136 0.00637481657 -0.11611178087 0.000 0.000 0.001 N 2.00981687167 0.00259443239 -0.00000686048 -0.024 -0.006 -0.000 C 2.67119656792 1.17263645248 0.00045766926 0.054 0.012 0.000 C 4.06129317470 1.20536051565 0.00241240325 -0.051 0.011 -0.000 C 4.76783866331 0.00148799420 0.00346798881 0.031 0.005 0.000 C 4.05723810074 -1.20352939940 0.00211502115 -0.061 -0.020 -0.000 C 2.67108506586 -1.17139122066 0.00026591651 0.057 0.004 0.000 C 1.82209539371 2.39842937406 -0.00175320633 -0.020 -0.030 0.000 C 2.33938959521 3.68993217240 -0.00584554905 0.003 0.035 -0.000 C 1.45736908622 4.77231118002 -0.00917967851 -0.001 -0.017 0.000 C 0.08658913130 4.53522926787 -0.00833235387 0.013 0.026 -0.000 C -0.35359617412 3.21325694137 -0.00400174376 0.002 -0.036 0.000 N 0.49290585413 2.18198449515 -0.00068475564 -0.001 0.017 0.000 S 6.56718562933 -0.11349126889 0.00673479967 0.000 -0.000 0.000 C 1.82142022278 -2.39594383179 -0.00206827421 -0.017 0.000 -0.000 C 2.33969079820 -3.68709653410 -0.00625612120 0.004 0.000 -0.000 C 1.45789786198 -4.76953179608 -0.00945089783 -0.004 0.001 0.000 C 0.08684213972 -4.53272927032 -0.00840538011 0.003 -0.005 -0.000 C -0.35393854068 -3.21111942258 -0.00398541364 0.001 0.008 -0.000 N 0.49225266031 -2.17934076887 -0.00084210065 0.002 -0.003 0.000 H 1.83694111827 5.77332096953 -0.01265611066 -0.004 -0.005 0.000 H -0.61802819388 5.33967450634 -0.01131742088 -0.010 -0.003 0.000 H 3.39175422949 3.87200638269 -0.00704552340 0.005 -0.012 0.000 H -1.39787683933 2.98334799634 -0.00369736757 -0.007 0.019 -0.000 H 1.83794742242 -5.77033326187 -0.01295832570 0.001 0.001 0.000 H -0.61749414542 -5.33746053721 -0.01121572048 -0.001 -0.000 0.000 H -1.39833026435 -2.98175334118 -0.00345676225 -0.002 -0.008 -0.000 H 3.39230213722 -3.86796714602 -0.00754158092 0.001 -0.005 -0.000 H 4.58301895157 2.13678100538 0.00314824260 0.018 -0.016 0.000 H 4.58784714512 -2.12983634010 0.00211631073 0.026 0.020 0.000 H -1.68997263563 -0.00719388386 -5.74925805817 -0.046 0.000 0.012 H 0.75224758084 -0.00860493512 -5.25016290812 -0.006 0.000 0.015 H -3.29620044300 -0.00255800648 -3.88456579214 -0.005 -0.000 -0.071 H 1.47161249279 -0.00457826661 -2.87685200854 0.005 0.000 0.015 H -1.69176120521 -0.00597000955 5.75026973076 -0.066 0.000 0.015 H 0.75025791005 -0.00892914887 5.25161119224 -0.060 0.000 0.009 H 1.46975366817 -0.00523069331 2.87805400798 -0.025 0.000 -0.081 H -3.29750276746 -0.00099200484 3.88584245085 0.023 -0.000 0.155 H -4.55513299541 0.00377930937 -2.13473279421 -0.147 0.000 0.119 H -4.55107479454 0.00501307822 2.13844314827 -0.154 0.000 -0.112 H -6.83436893102 0.00806057203 1.19721860356 0.001 0.000 -0.000 H 6.86748209639 1.20005966818 0.00372860376 -0.001 0.000 -0.000 61 Mode 159: freq=1786.46 N -0.44003451495 -0.00038510790 2.12369783068 -0.021 0.000 -0.006 C -1.76594470239 0.00039861437 2.37754210613 0.036 -0.000 0.003 C -2.24923313135 -0.00145267054 3.67997125809 -0.019 0.000 -0.013 C -1.33887502024 -0.00450793845 4.73956848945 0.034 -0.000 0.009 C 0.02462671625 -0.00591801736 4.46614405978 -0.024 0.000 0.005 C 0.43187566201 -0.00376957955 3.13352499014 0.012 -0.000 0.007 C -2.63984642995 0.00218980399 1.17162612704 -0.078 0.000 -0.002 N -1.98513620489 0.00132140951 0.00153900685 0.037 0.000 0.011 C -2.63911589169 0.00167522827 -1.17277445342 -0.080 0.000 -0.039 C -4.02452897564 0.00329996303 -1.20791476641 0.066 -0.000 -0.005 C -4.73391255267 0.00451580118 -0.00020876193 -0.037 0.000 -0.013 C -4.02924140493 0.00399189729 1.20660077672 0.077 -0.000 0.025 Co 0.00000000000 0.00000000000 0.00000000000 -0.001 -0.001 -0.000 N -0.43839318333 -0.00054206762 -2.12229806799 -0.012 0.000 -0.054 C -1.76408906064 -0.00030645034 -2.37697009192 0.061 0.000 0.118 C -2.24773885821 -0.00257631963 -3.67934971086 -0.011 -0.000 -0.133 C -1.33713102227 -0.00526459193 -4.73855802198 0.027 0.000 0.059 C 0.02654101484 -0.00591797621 -4.46472703619 -0.068 -0.000 -0.098 C 0.43371721952 -0.00363389350 -3.13225443930 0.004 0.000 0.114 S -6.53329279136 0.00637481657 -0.11611178087 -0.000 0.000 0.001 N 2.00981687167 0.00259443239 -0.00000686048 0.142 0.027 -0.000 C 2.67119656792 1.17263645248 0.00045766926 -0.315 -0.076 -0.000 C 4.06129317470 1.20536051565 0.00241240325 0.286 -0.059 0.000 C 4.76783866331 0.00148799420 0.00346798881 -0.164 -0.017 -0.000 C 4.05723810074 -1.20352939940 0.00211502115 0.330 0.092 0.001 C 2.67108506586 -1.17139122066 0.00026591651 -0.334 0.013 -0.000 C 1.82209539371 2.39842937406 -0.00175320633 0.182 0.191 -0.001 C 2.33938959521 3.68993217240 -0.00584554905 -0.054 -0.202 0.001 C 1.45736908622 4.77231118002 -0.00917967851 0.094 0.085 -0.000 C 0.08658913130 4.53522926787 -0.00833235387 -0.150 -0.177 0.001 C -0.35359617412 3.21325694137 -0.00400174376 0.023 0.198 -0.001 N 0.49290585413 2.18198449515 -0.00068475564 -0.057 -0.092 0.001 S 6.56718562933 -0.11349126889 0.00673479967 -0.001 0.000 -0.000 C 1.82142022278 -2.39594383179 -0.00206827421 0.174 -0.097 -0.000 C 2.33969079820 -3.68709653410 -0.00625612120 -0.059 0.095 0.000 C 1.45789786198 -4.76953179608 -0.00945089783 0.101 -0.036 -0.000 C 0.08684213972 -4.53272927032 -0.00840538011 -0.120 0.115 0.000 C -0.35393854068 -3.21111942258 -0.00398541364 0.027 -0.118 -0.000 N 0.49225266031 -2.17934076887 -0.00084210065 -0.066 0.051 0.001 H 1.83694111827 5.77332096953 -0.01265611066 -0.011 0.048 -0.000 H -0.61802819388 5.33967450634 -0.01131742088 0.071 0.045 -0.000 H 3.39175422949 3.87200638269 -0.00704552340 -0.044 0.068 -0.000 H -1.39787683933 2.98334799634 -0.00369736757 0.042 -0.075 0.000 H 1.83794742242 -5.77033326187 -0.01295832570 -0.023 -0.036 -0.000 H -0.61749414542 -5.33746053721 -0.01121572048 0.044 -0.034 -0.000 H -1.39833026435 -2.98175334118 -0.00345676225 0.029 0.043 0.000 H 3.39230213722 -3.86796714602 -0.00754158092 -0.030 -0.017 0.000 H 4.58301895157 2.13678100538 0.00314824260 -0.089 0.086 -0.000 H 4.58784714512 -2.12983634010 0.00211631073 -0.122 -0.104 -0.000 H -1.68997263563 -0.00719388386 -5.74925805817 0.002 0.000 0.024 H 0.75224758084 -0.00860493512 -5.25016290812 0.040 -0.000 0.023 H -3.29620044300 -0.00255800648 -3.88456579214 -0.024 0.000 0.053 H 1.47161249279 -0.00457826661 -2.87685200854 0.022 -0.000 -0.038 H -1.69176120521 -0.00597000955 5.75026973076 -0.013 0.000 -0.006 H 0.75025791005 -0.00892914887 5.25161119224 0.001 0.000 -0.007 H 1.46975366817 -0.00523069331 2.87805400798 0.001 -0.000 -0.010 H -3.29750276746 -0.00099200484 3.88584245085 -0.004 -0.000 0.011 H -4.55513299541 0.00377930937 -2.13473279421 -0.013 -0.000 0.020 H -4.55107479454 0.00501307822 2.13844314827 -0.028 0.000 -0.022 H -6.83436893102 0.00806057203 1.19721860356 -0.002 -0.000 -0.000 H 6.86748209639 1.20005966818 0.00372860376 0.003 -0.000 0.000 61 Mode 160: freq=1787.32 N -0.44003451495 -0.00038510790 2.12369783068 -0.003 -0.000 0.103 C -1.76594470239 0.00039861437 2.37754210613 0.077 0.000 -0.216 C -2.24923313135 -0.00145267054 3.67997125809 -0.004 -0.000 0.247 C -1.33887502024 -0.00450793845 4.73956848945 0.018 0.000 -0.112 C 0.02462671625 -0.00591801736 4.46614405978 -0.097 -0.000 0.168 C 0.43187566201 -0.00376957955 3.13352499014 -0.006 0.000 -0.210 C -2.63984642995 0.00218980399 1.17162612704 -0.082 0.000 0.094 N -1.98513620489 0.00132140951 0.00153900685 0.030 -0.000 -0.075 C -2.63911589169 0.00167522827 -1.17277445342 -0.093 0.000 0.136 C -4.02452897564 0.00329996303 -1.20791476641 0.136 -0.000 -0.088 C -4.73391255267 0.00451580118 -0.00020876193 -0.047 0.000 0.070 C -4.02924140493 0.00399189729 1.20660077672 0.043 -0.000 -0.029 Co 0.00000000000 0.00000000000 0.00000000000 0.001 -0.000 0.002 N -0.43839318333 -0.00054206762 -2.12229806799 -0.047 0.000 0.164 C -1.76408906064 -0.00030645034 -2.37697009192 -0.019 -0.001 -0.344 C -2.24773885821 -0.00257631963 -3.67934971086 -0.039 0.001 0.416 C -1.33713102227 -0.00526459193 -4.73855802198 0.050 -0.000 -0.194 C 0.02654101484 -0.00591797621 -4.46472703619 0.098 0.000 0.245 C 0.43371721952 -0.00363389350 -3.13225443930 0.033 -0.001 -0.330 S -6.53329279136 0.00637481657 -0.11611178087 -0.002 -0.000 -0.003 N 2.00981687167 0.00259443239 -0.00000686048 0.027 0.005 0.000 C 2.67119656792 1.17263645248 0.00045766926 -0.059 -0.017 -0.000 C 4.06129317470 1.20536051565 0.00241240325 0.052 -0.010 0.000 C 4.76783866331 0.00148799420 0.00346798881 -0.029 -0.003 -0.000 C 4.05723810074 -1.20352939940 0.00211502115 0.060 0.015 0.000 C 2.67108506586 -1.17139122066 0.00026591651 -0.063 0.007 -0.000 C 1.82209539371 2.39842937406 -0.00175320633 0.039 0.045 -0.000 C 2.33938959521 3.68993217240 -0.00584554905 -0.011 -0.049 0.000 C 1.45736908622 4.77231118002 -0.00917967851 0.020 0.021 -0.000 C 0.08658913130 4.53522926787 -0.00833235387 -0.034 -0.041 0.000 C -0.35359617412 3.21325694137 -0.00400174376 0.005 0.046 -0.000 N 0.49290585413 2.18198449515 -0.00068475564 -0.013 -0.022 -0.002 S 6.56718562933 -0.11349126889 0.00673479967 -0.000 0.000 -0.000 C 1.82142022278 -2.39594383179 -0.00206827421 0.038 -0.031 0.000 C 2.33969079820 -3.68709653410 -0.00625612120 -0.012 0.033 0.000 C 1.45789786198 -4.76953179608 -0.00945089783 0.021 -0.013 -0.000 C 0.08684213972 -4.53272927032 -0.00840538011 -0.030 0.032 0.000 C -0.35393854068 -3.21111942258 -0.00398541364 0.006 -0.035 0.000 N 0.49225266031 -2.17934076887 -0.00084210065 -0.014 0.016 -0.002 H 1.83694111827 5.77332096953 -0.01265611066 -0.002 0.011 -0.000 H -0.61802819388 5.33967450634 -0.01131742088 0.017 0.010 -0.000 H 3.39175422949 3.87200638269 -0.00704552340 -0.010 0.017 -0.000 H -1.39787683933 2.98334799634 -0.00369736757 0.009 -0.016 0.000 H 1.83794742242 -5.77033326187 -0.01295832570 -0.004 -0.009 -0.000 H -0.61749414542 -5.33746053721 -0.01121572048 0.013 -0.009 -0.000 H -1.39833026435 -2.98175334118 -0.00345676225 0.008 0.012 0.000 H 3.39230213722 -3.86796714602 -0.00754158092 -0.008 -0.010 0.000 H 4.58301895157 2.13678100538 0.00314824260 -0.015 0.015 0.000 H 4.58784714512 -2.12983634010 0.00211631073 -0.020 -0.018 0.000 H -1.68997263563 -0.00719388386 -5.74925805817 -0.055 -0.000 -0.046 H 0.75224758084 -0.00860493512 -5.25016290812 -0.103 0.000 -0.038 H -3.29620044300 -0.00255800648 -3.88456579214 0.053 -0.000 -0.192 H 1.47161249279 -0.00457826661 -2.87685200854 -0.054 0.000 0.132 H -1.69176120521 -0.00597000955 5.75026973076 0.016 0.000 -0.037 H 0.75025791005 -0.00892914887 5.25161119224 0.068 -0.000 -0.034 H 1.46975366817 -0.00523069331 2.87805400798 0.038 -0.000 0.081 H -3.29750276746 -0.00099200484 3.88584245085 -0.039 0.000 -0.103 H -4.55513299541 0.00377930937 -2.13473279421 -0.089 0.000 0.047 H -4.55107479454 0.00501307822 2.13844314827 0.005 -0.000 -0.016 H -6.83436893102 0.00806057203 1.19721860356 0.010 -0.000 0.002 H 6.86748209639 1.20005966818 0.00372860376 0.000 -0.000 0.000 61 Mode 161: freq=1789.64 N -0.44003451495 -0.00038510790 2.12369783068 -0.011 -0.000 0.143 C -1.76594470239 0.00039861437 2.37754210613 0.135 0.000 -0.297 C -2.24923313135 -0.00145267054 3.67997125809 -0.018 -0.001 0.334 C -1.33887502024 -0.00450793845 4.73956848945 0.039 0.000 -0.149 C 0.02462671625 -0.00591801736 4.46614405978 -0.142 -0.000 0.236 C 0.43187566201 -0.00376957955 3.13352499014 -0.006 0.001 -0.293 C -2.63984642995 0.00218980399 1.17162612704 -0.199 0.000 0.113 N -1.98513620489 0.00132140951 0.00153900685 0.106 -0.000 -0.022 C -2.63911589169 0.00167522827 -1.17277445342 -0.210 0.000 -0.062 C -4.02452897564 0.00329996303 -1.20791476641 0.191 -0.000 -0.041 C -4.73391255267 0.00451580118 -0.00020876193 -0.089 0.000 0.015 C -4.02924140493 0.00399189729 1.20660077672 0.160 -0.000 0.014 Co 0.00000000000 0.00000000000 0.00000000000 -0.003 0.000 0.001 N -0.43839318333 -0.00054206762 -2.12229806799 -0.018 -0.000 -0.107 C -1.76408906064 -0.00030645034 -2.37697009192 0.125 0.000 0.213 C -2.24773885821 -0.00257631963 -3.67934971086 -0.022 -0.000 -0.241 C -1.33713102227 -0.00526459193 -4.73855802198 0.041 0.000 0.108 C 0.02654101484 -0.00591797621 -4.46472703619 -0.115 -0.000 -0.181 C 0.43371721952 -0.00363389350 -3.13225443930 -0.001 0.000 0.222 S -6.53329279136 0.00637481657 -0.11611178087 -0.001 0.000 -0.000 N 2.00981687167 0.00259443239 -0.00000686048 -0.026 -0.004 -0.000 C 2.67119656792 1.17263645248 0.00045766926 0.055 0.025 0.000 C 4.06129317470 1.20536051565 0.00241240325 -0.046 0.006 -0.000 C 4.76783866331 0.00148799420 0.00346798881 0.026 0.002 0.000 C 4.05723810074 -1.20352939940 0.00211502115 -0.052 -0.011 -0.000 C 2.67108506586 -1.17139122066 0.00026591651 0.058 -0.017 0.000 C 1.82209539371 2.39842937406 -0.00175320633 -0.040 -0.069 0.000 C 2.33938959521 3.68993217240 -0.00584554905 0.007 0.079 -0.000 C 1.45736908622 4.77231118002 -0.00917967851 -0.010 -0.036 0.000 C 0.08658913130 4.53522926787 -0.00833235387 0.036 0.058 -0.000 C -0.35359617412 3.21325694137 -0.00400174376 0.001 -0.075 0.000 N 0.49290585413 2.18198449515 -0.00068475564 0.007 0.038 -0.000 S 6.56718562933 -0.11349126889 0.00673479967 0.000 0.000 0.000 C 1.82142022278 -2.39594383179 -0.00206827421 -0.040 0.061 0.000 C 2.33969079820 -3.68709653410 -0.00625612120 0.007 -0.071 -0.000 C 1.45789786198 -4.76953179608 -0.00945089783 -0.010 0.033 0.000 C 0.08684213972 -4.53272927032 -0.00840538011 0.033 -0.054 -0.000 C -0.35393854068 -3.21111942258 -0.00398541364 0.001 0.069 0.000 N 0.49225266031 -2.17934076887 -0.00084210065 0.007 -0.035 -0.000 H 1.83694111827 5.77332096953 -0.01265611066 -0.005 -0.013 0.000 H -0.61802819388 5.33967450634 -0.01131742088 -0.023 -0.010 0.000 H 3.39175422949 3.87200638269 -0.00704552340 0.012 -0.030 0.000 H -1.39787683933 2.98334799634 -0.00369736757 -0.013 0.032 -0.000 H 1.83794742242 -5.77033326187 -0.01295832570 -0.004 0.012 0.000 H -0.61749414542 -5.33746053721 -0.01121572048 -0.021 0.009 0.000 H -1.39833026435 -2.98175334118 -0.00345676225 -0.012 -0.030 -0.000 H 3.39230213722 -3.86796714602 -0.00754158092 0.011 0.027 0.000 H 4.58301895157 2.13678100538 0.00314824260 0.009 -0.012 0.000 H 4.58784714512 -2.12983634010 0.00211631073 0.013 0.015 0.000 H -1.68997263563 -0.00719388386 -5.74925805817 0.008 0.000 0.042 H 0.75224758084 -0.00860493512 -5.25016290812 0.071 -0.000 0.037 H -3.29620044300 -0.00255800648 -3.88456579214 -0.043 0.000 0.090 H 1.47161249279 -0.00457826661 -2.87685200854 0.042 -0.000 -0.086 H -1.69176120521 -0.00597000955 5.75026973076 0.016 0.000 -0.054 H 0.75025791005 -0.00892914887 5.25161119224 0.094 -0.000 -0.047 H 1.46975366817 -0.00523069331 2.87805400798 0.054 -0.000 0.114 H -3.29750276746 -0.00099200484 3.88584245085 -0.056 0.000 -0.132 H -4.55513299541 0.00377930937 -2.13473279421 -0.048 0.000 0.053 H -4.55107479454 0.00501307822 2.13844314827 -0.024 0.000 -0.041 H -6.83436893102 0.00806057203 1.19721860356 0.001 0.000 0.000 H 6.86748209639 1.20005966818 0.00372860376 -0.000 -0.000 0.000 61 Mode 162: freq=2753.40 N -0.44003451495 -0.00038510790 2.12369783068 -0.000 -0.000 0.000 C -1.76594470239 0.00039861437 2.37754210613 -0.000 0.000 0.000 C -2.24923313135 -0.00145267054 3.67997125809 -0.000 0.000 -0.000 C -1.33887502024 -0.00450793845 4.73956848945 0.000 0.000 0.000 C 0.02462671625 -0.00591801736 4.46614405978 -0.000 -0.000 0.000 C 0.43187566201 -0.00376957955 3.13352499014 0.000 -0.000 -0.000 C -2.63984642995 0.00218980399 1.17162612704 -0.000 0.000 0.000 N -1.98513620489 0.00132140951 0.00153900685 -0.000 -0.000 -0.000 C -2.63911589169 0.00167522827 -1.17277445342 0.000 0.000 0.000 C -4.02452897564 0.00329996303 -1.20791476641 -0.000 -0.000 -0.000 C -4.73391255267 0.00451580118 -0.00020876193 0.000 0.000 0.000 C -4.02924140493 0.00399189729 1.20660077672 0.000 -0.000 -0.000 Co 0.00000000000 0.00000000000 0.00000000000 0.000 0.000 -0.000 N -0.43839318333 -0.00054206762 -2.12229806799 -0.000 -0.000 -0.000 C -1.76408906064 -0.00030645034 -2.37697009192 -0.000 0.000 -0.000 C -2.24773885821 -0.00257631963 -3.67934971086 -0.000 0.000 0.000 C -1.33713102227 -0.00526459193 -4.73855802198 0.000 0.000 -0.000 C 0.02654101484 -0.00591797621 -4.46472703619 -0.000 -0.000 -0.000 C 0.43371721952 -0.00363389350 -3.13225443930 0.000 -0.000 0.000 S -6.53329279136 0.00637481657 -0.11611178087 -0.001 0.000 0.004 N 2.00981687167 0.00259443239 -0.00000686048 -0.000 -0.001 -0.000 C 2.67119656792 1.17263645248 0.00045766926 0.001 0.000 0.000 C 4.06129317470 1.20536051565 0.00241240325 -0.002 -0.002 0.000 C 4.76783866331 0.00148799420 0.00346798881 -0.005 0.005 -0.000 C 4.05723810074 -1.20352939940 0.00211502115 0.000 -0.001 0.000 C 2.67108506586 -1.17139122066 0.00026591651 -0.000 0.000 0.000 C 1.82209539371 2.39842937406 -0.00175320633 -0.000 -0.000 -0.000 C 2.33938959521 3.68993217240 -0.00584554905 -0.000 -0.000 -0.000 C 1.45736908622 4.77231118002 -0.00917967851 0.000 -0.000 0.000 C 0.08658913130 4.53522926787 -0.00833235387 -0.000 -0.000 0.000 C -0.35359617412 3.21325694137 -0.00400174376 -0.000 0.000 -0.000 N 0.49290585413 2.18198449515 -0.00068475564 0.000 0.000 -0.000 S 6.56718562933 -0.11349126889 0.00673479967 0.043 0.170 -0.000 C 1.82142022278 -2.39594383179 -0.00206827421 0.000 -0.000 0.000 C 2.33969079820 -3.68709653410 -0.00625612120 0.000 0.000 0.000 C 1.45789786198 -4.76953179608 -0.00945089783 0.000 -0.000 -0.000 C 0.08684213972 -4.53272927032 -0.00840538011 0.000 -0.000 0.000 C -0.35393854068 -3.21111942258 -0.00398541364 0.000 -0.000 -0.000 N 0.49225266031 -2.17934076887 -0.00084210065 0.000 -0.000 -0.000 H 1.83694111827 5.77332096953 -0.01265611066 0.000 0.000 -0.000 H -0.61802819388 5.33967450634 -0.01131742088 0.000 0.000 0.000 H 3.39175422949 3.87200638269 -0.00704552340 0.000 -0.000 -0.000 H -1.39787683933 2.98334799634 -0.00369736757 0.000 0.000 0.000 H 1.83794742242 -5.77033326187 -0.01295832570 -0.000 0.000 0.000 H -0.61749414542 -5.33746053721 -0.01121572048 0.000 -0.000 0.000 H -1.39833026435 -2.98175334118 -0.00345676225 -0.000 0.000 0.000 H 3.39230213722 -3.86796714602 -0.00754158092 -0.000 0.000 -0.000 H 4.58301895157 2.13678100538 0.00314824260 0.002 0.001 -0.000 H 4.58784714512 -2.12983634010 0.00211631073 -0.002 -0.001 -0.000 H -1.68997263563 -0.00719388386 -5.74925805817 -0.000 0.000 0.000 H 0.75224758084 -0.00860493512 -5.25016290812 0.000 0.000 0.000 H -3.29620044300 -0.00255800648 -3.88456579214 0.000 0.000 0.000 H 1.47161249279 -0.00457826661 -2.87685200854 0.000 0.000 0.000 H -1.69176120521 -0.00597000955 5.75026973076 -0.000 0.000 -0.000 H 0.75025791005 -0.00892914887 5.25161119224 0.000 0.000 -0.000 H 1.46975366817 -0.00523069331 2.87805400798 0.000 0.000 -0.000 H -3.29750276746 -0.00099200484 3.88584245085 0.000 0.000 -0.000 H -4.55513299541 0.00377930937 -2.13473279421 0.000 0.000 -0.000 H -4.55107479454 0.00501307822 2.13844314827 -0.000 0.000 0.000 H -6.83436893102 0.00806057203 1.19721860356 0.005 -0.000 -0.024 H 6.86748209639 1.20005966818 0.00372860376 -0.219 -0.960 0.002 61 Mode 163: freq=2753.72 N -0.44003451495 -0.00038510790 2.12369783068 0.000 -0.000 -0.000 C -1.76594470239 0.00039861437 2.37754210613 -0.000 0.000 0.000 C -2.24923313135 -0.00145267054 3.67997125809 -0.000 -0.000 0.000 C -1.33887502024 -0.00450793845 4.73956848945 0.000 0.000 0.000 C 0.02462671625 -0.00591801736 4.46614405978 -0.000 0.000 0.000 C 0.43187566201 -0.00376957955 3.13352499014 -0.000 -0.000 -0.000 C -2.63984642995 0.00218980399 1.17162612704 0.001 -0.000 -0.000 N -1.98513620489 0.00132140951 0.00153900685 -0.000 -0.000 0.001 C -2.63911589169 0.00167522827 -1.17277445342 -0.000 0.000 -0.000 C -4.02452897564 0.00329996303 -1.20791476641 0.000 0.000 0.001 C -4.73391255267 0.00451580118 -0.00020876193 -0.005 0.000 -0.005 C -4.02924140493 0.00399189729 1.20660077672 -0.002 0.000 0.002 Co 0.00000000000 0.00000000000 0.00000000000 0.000 0.000 -0.000 N -0.43839318333 -0.00054206762 -2.12229806799 0.000 -0.000 0.000 C -1.76408906064 -0.00030645034 -2.37697009192 0.000 0.000 0.000 C -2.24773885821 -0.00257631963 -3.67934971086 0.000 -0.000 -0.000 C -1.33713102227 -0.00526459193 -4.73855802198 -0.000 0.000 0.000 C 0.02654101484 -0.00591797621 -4.46472703619 0.000 -0.000 0.000 C 0.43371721952 -0.00363389350 -3.13225443930 0.000 0.000 0.000 S -6.53329279136 0.00637481657 -0.11611178087 0.043 -0.000 -0.170 N 2.00981687167 0.00259443239 -0.00000686048 -0.000 -0.000 0.000 C 2.67119656792 1.17263645248 0.00045766926 0.000 0.000 -0.000 C 4.06129317470 1.20536051565 0.00241240325 -0.000 -0.000 0.000 C 4.76783866331 0.00148799420 0.00346798881 -0.000 0.000 0.000 C 4.05723810074 -1.20352939940 0.00211502115 0.000 -0.000 0.000 C 2.67108506586 -1.17139122066 0.00026591651 -0.000 0.000 -0.000 C 1.82209539371 2.39842937406 -0.00175320633 -0.000 -0.000 -0.000 C 2.33938959521 3.68993217240 -0.00584554905 -0.000 0.000 -0.000 C 1.45736908622 4.77231118002 -0.00917967851 0.000 -0.000 -0.000 C 0.08658913130 4.53522926787 -0.00833235387 -0.000 -0.000 0.000 C -0.35359617412 3.21325694137 -0.00400174376 0.000 0.000 0.000 N 0.49290585413 2.18198449515 -0.00068475564 -0.000 0.000 0.000 S 6.56718562933 -0.11349126889 0.00673479967 0.001 0.004 -0.000 C 1.82142022278 -2.39594383179 -0.00206827421 -0.000 0.000 -0.000 C 2.33969079820 -3.68709653410 -0.00625612120 -0.000 -0.000 -0.000 C 1.45789786198 -4.76953179608 -0.00945089783 0.000 -0.000 -0.000 C 0.08684213972 -4.53272927032 -0.00840538011 -0.000 0.000 0.000 C -0.35393854068 -3.21111942258 -0.00398541364 0.000 -0.000 0.000 N 0.49225266031 -2.17934076887 -0.00084210065 -0.000 -0.000 0.000 H 1.83694111827 5.77332096953 -0.01265611066 -0.000 0.000 -0.000 H -0.61802819388 5.33967450634 -0.01131742088 0.000 0.000 -0.000 H 3.39175422949 3.87200638269 -0.00704552340 0.000 -0.000 -0.000 H -1.39787683933 2.98334799634 -0.00369736757 0.000 0.000 -0.000 H 1.83794742242 -5.77033326187 -0.01295832570 -0.000 -0.000 -0.000 H -0.61749414542 -5.33746053721 -0.01121572048 0.000 -0.000 -0.000 H -1.39833026435 -2.98175334118 -0.00345676225 0.000 -0.000 -0.000 H 3.39230213722 -3.86796714602 -0.00754158092 -0.000 0.000 -0.000 H 4.58301895157 2.13678100538 0.00314824260 0.000 0.000 -0.000 H 4.58784714512 -2.12983634010 0.00211631073 -0.000 -0.000 -0.000 H -1.68997263563 -0.00719388386 -5.74925805817 -0.000 -0.000 -0.000 H 0.75224758084 -0.00860493512 -5.25016290812 0.000 0.000 0.000 H -3.29620044300 -0.00255800648 -3.88456579214 -0.000 0.000 -0.000 H 1.47161249279 -0.00457826661 -2.87685200854 0.000 0.000 -0.000 H -1.69176120521 -0.00597000955 5.75026973076 0.000 0.000 -0.000 H 0.75025791005 -0.00892914887 5.25161119224 0.000 0.000 -0.000 H 1.46975366817 -0.00523069331 2.87805400798 0.000 0.000 -0.000 H -3.29750276746 -0.00099200484 3.88584245085 0.000 0.000 0.000 H -4.55513299541 0.00377930937 -2.13473279421 -0.002 0.000 0.001 H -4.55107479454 0.00501307822 2.13844314827 0.002 -0.000 -0.001 H -6.83436893102 0.00806057203 1.19721860356 -0.219 0.001 0.960 H 6.86748209639 1.20005966818 0.00372860376 -0.005 -0.024 0.000 61 Mode 164: freq=3424.18 N -0.44003451495 -0.00038510790 2.12369783068 -0.000 -0.000 -0.000 C -1.76594470239 0.00039861437 2.37754210613 -0.000 0.000 -0.000 C -2.24923313135 -0.00145267054 3.67997125809 0.001 -0.000 -0.000 C -1.33887502024 -0.00450793845 4.73956848945 -0.000 -0.000 0.001 C 0.02462671625 -0.00591801736 4.46614405978 -0.001 0.000 -0.001 C 0.43187566201 -0.00376957955 3.13352499014 0.001 0.000 -0.000 C -2.63984642995 0.00218980399 1.17162612704 0.000 0.000 -0.000 N -1.98513620489 0.00132140951 0.00153900685 -0.000 -0.000 0.000 C -2.63911589169 0.00167522827 -1.17277445342 0.000 0.000 0.000 C -4.02452897564 0.00329996303 -1.20791476641 -0.000 0.000 -0.000 C -4.73391255267 0.00451580118 -0.00020876193 -0.000 -0.000 -0.000 C -4.02924140493 0.00399189729 1.20660077672 -0.000 0.000 0.000 Co 0.00000000000 0.00000000000 0.00000000000 -0.000 0.000 -0.000 N -0.43839318333 -0.00054206762 -2.12229806799 0.000 -0.000 0.000 C -1.76408906064 -0.00030645034 -2.37697009192 -0.000 0.000 0.000 C -2.24773885821 -0.00257631963 -3.67934971086 0.000 -0.000 0.000 C -1.33713102227 -0.00526459193 -4.73855802198 -0.000 -0.000 -0.001 C 0.02654101484 -0.00591797621 -4.46472703619 -0.001 0.000 0.001 C 0.43371721952 -0.00363389350 -3.13225443930 0.001 0.000 0.000 S -6.53329279136 0.00637481657 -0.11611178087 -0.000 0.000 0.000 N 2.00981687167 0.00259443239 -0.00000686048 0.000 -0.000 0.000 C 2.67119656792 1.17263645248 0.00045766926 -0.001 -0.000 0.000 C 4.06129317470 1.20536051565 0.00241240325 0.011 0.021 0.000 C 4.76783866331 0.00148799420 0.00346798881 0.001 -0.002 0.000 C 4.05723810074 -1.20352939940 0.00211502115 -0.004 0.007 0.000 C 2.67108506586 -1.17139122066 0.00026591651 0.000 -0.000 -0.000 C 1.82209539371 2.39842937406 -0.00175320633 0.004 0.002 -0.000 C 2.33938959521 3.68993217240 -0.00584554905 -0.060 -0.020 0.000 C 1.45736908622 4.77231118002 -0.00917967851 0.065 0.181 -0.001 C 0.08658913130 4.53522926787 -0.00833235387 0.085 -0.104 0.000 C -0.35359617412 3.21325694137 -0.00400174376 -0.115 -0.020 0.000 N 0.49290585413 2.18198449515 -0.00068475564 0.003 -0.002 0.000 S 6.56718562933 -0.11349126889 0.00673479967 -0.000 0.000 -0.000 C 1.82142022278 -2.39594383179 -0.00206827421 -0.001 0.001 0.000 C 2.33969079820 -3.68709653410 -0.00625612120 0.022 -0.007 -0.000 C 1.45789786198 -4.76953179608 -0.00945089783 -0.023 0.066 0.000 C 0.08684213972 -4.53272927032 -0.00840538011 -0.034 -0.040 -0.000 C -0.35393854068 -3.21111942258 -0.00398541364 0.047 -0.008 -0.000 N 0.49225266031 -2.17934076887 -0.00084210065 -0.001 -0.001 -0.000 H 1.83694111827 5.77332096953 -0.01265611066 -0.223 -0.589 0.002 H -0.61802819388 5.33967450634 -0.01131742088 -0.297 0.341 -0.001 H 3.39175422949 3.87200638269 -0.00704552340 0.211 0.037 -0.000 H -1.39787683933 2.98334799634 -0.00369736757 0.377 0.084 -0.000 H 1.83794742242 -5.77033326187 -0.01295832570 0.081 -0.215 -0.001 H -0.61749414542 -5.33746053721 -0.01121572048 0.116 0.133 0.000 H -1.39833026435 -2.98175334118 -0.00345676225 -0.153 0.034 0.000 H 3.39230213722 -3.86796714602 -0.00754158092 -0.075 0.013 0.000 H 4.58301895157 2.13678100538 0.00314824260 -0.037 -0.066 -0.000 H 4.58784714512 -2.12983634010 0.00211631073 0.012 -0.021 0.000 H -1.68997263563 -0.00719388386 -5.74925805817 0.001 0.000 0.004 H 0.75224758084 -0.00860493512 -5.25016290812 0.002 0.000 -0.003 H -3.29620044300 -0.00255800648 -3.88456579214 -0.002 0.000 -0.000 H 1.47161249279 -0.00457826661 -2.87685200854 -0.004 -0.000 -0.001 H -1.69176120521 -0.00597000955 5.75026973076 0.002 0.000 -0.005 H 0.75025791005 -0.00892914887 5.25161119224 0.003 0.000 0.003 H 1.46975366817 -0.00523069331 2.87805400798 -0.004 -0.000 0.001 H -3.29750276746 -0.00099200484 3.88584245085 -0.002 0.000 0.000 H -4.55513299541 0.00377930937 -2.13473279421 0.000 0.000 0.000 H -4.55107479454 0.00501307822 2.13844314827 0.000 0.000 -0.001 H -6.83436893102 0.00806057203 1.19721860356 0.000 0.000 -0.000 H 6.86748209639 1.20005966818 0.00372860376 -0.000 -0.000 0.000 61 Mode 165: freq=3424.31 N -0.44003451495 -0.00038510790 2.12369783068 0.000 -0.000 0.000 C -1.76594470239 0.00039861437 2.37754210613 0.000 0.000 -0.000 C -2.24923313135 -0.00145267054 3.67997125809 -0.002 -0.000 0.001 C -1.33887502024 -0.00450793845 4.73956848945 0.001 0.000 -0.004 C 0.02462671625 -0.00591801736 4.46614405978 0.002 -0.000 0.002 C 0.43187566201 -0.00376957955 3.13352499014 -0.003 0.000 0.001 C -2.63984642995 0.00218980399 1.17162612704 -0.000 0.000 0.000 N -1.98513620489 0.00132140951 0.00153900685 0.000 -0.000 -0.000 C -2.63911589169 0.00167522827 -1.17277445342 -0.000 0.000 -0.000 C -4.02452897564 0.00329996303 -1.20791476641 0.000 0.000 0.000 C -4.73391255267 0.00451580118 -0.00020876193 0.000 -0.000 0.000 C -4.02924140493 0.00399189729 1.20660077672 0.000 0.000 -0.001 Co 0.00000000000 0.00000000000 0.00000000000 0.000 0.000 0.000 N -0.43839318333 -0.00054206762 -2.12229806799 0.000 -0.000 -0.000 C -1.76408906064 -0.00030645034 -2.37697009192 0.000 0.000 -0.000 C -2.24773885821 -0.00257631963 -3.67934971086 -0.001 -0.000 -0.000 C -1.33713102227 -0.00526459193 -4.73855802198 0.001 0.000 0.004 C 0.02654101484 -0.00591797621 -4.46472703619 0.002 -0.000 -0.002 C 0.43371721952 -0.00363389350 -3.13225443930 -0.003 0.000 -0.001 S -6.53329279136 0.00637481657 -0.11611178087 0.000 0.000 -0.000 N 2.00981687167 0.00259443239 -0.00000686048 -0.000 -0.000 0.000 C 2.67119656792 1.17263645248 0.00045766926 0.001 0.000 0.000 C 4.06129317470 1.20536051565 0.00241240325 -0.004 -0.007 -0.000 C 4.76783866331 0.00148799420 0.00346798881 -0.001 -0.001 -0.000 C 4.05723810074 -1.20352939940 0.00211502115 -0.009 0.017 0.000 C 2.67108506586 -1.17139122066 0.00026591651 0.001 -0.000 -0.000 C 1.82209539371 2.39842937406 -0.00175320633 -0.001 -0.001 0.000 C 2.33938959521 3.68993217240 -0.00584554905 0.022 0.008 -0.000 C 1.45736908622 4.77231118002 -0.00917967851 -0.025 -0.069 0.000 C 0.08658913130 4.53522926787 -0.00833235387 -0.032 0.039 -0.000 C -0.35359617412 3.21325694137 -0.00400174376 0.043 0.008 -0.000 N 0.49290585413 2.18198449515 -0.00068475564 -0.001 0.001 -0.000 S 6.56718562933 -0.11349126889 0.00673479967 0.000 0.000 0.000 C 1.82142022278 -2.39594383179 -0.00206827421 -0.004 0.002 0.000 C 2.33969079820 -3.68709653410 -0.00625612120 0.056 -0.019 -0.000 C 1.45789786198 -4.76953179608 -0.00945089783 -0.062 0.175 0.001 C 0.08684213972 -4.53272927032 -0.00840538011 -0.089 -0.107 -0.000 C -0.35393854068 -3.21111942258 -0.00398541364 0.122 -0.022 -0.000 N 0.49225266031 -2.17934076887 -0.00084210065 -0.003 -0.002 -0.000 H 1.83694111827 5.77332096953 -0.01265611066 0.085 0.224 -0.001 H -0.61802819388 5.33967450634 -0.01131742088 0.113 -0.129 0.000 H 3.39175422949 3.87200638269 -0.00704552340 -0.078 -0.014 0.000 H -1.39787683933 2.98334799634 -0.00369736757 -0.141 -0.031 0.000 H 1.83794742242 -5.77033326187 -0.01295832570 0.215 -0.569 -0.002 H -0.61749414542 -5.33746053721 -0.01121572048 0.308 0.353 0.001 H -1.39833026435 -2.98175334118 -0.00345676225 -0.400 0.089 0.000 H 3.39230213722 -3.86796714602 -0.00754158092 -0.195 0.034 0.000 H 4.58301895157 2.13678100538 0.00314824260 0.013 0.023 0.000 H 4.58784714512 -2.12983634010 0.00211631073 0.030 -0.052 0.000 H -1.68997263563 -0.00719388386 -5.74925805817 -0.004 -0.000 -0.012 H 0.75224758084 -0.00860493512 -5.25016290812 -0.007 0.000 0.007 H -3.29620044300 -0.00255800648 -3.88456579214 0.005 0.000 0.001 H 1.47161249279 -0.00457826661 -2.87685200854 0.009 -0.000 0.002 H -1.69176120521 -0.00597000955 5.75026973076 -0.005 -0.000 0.013 H 0.75025791005 -0.00892914887 5.25161119224 -0.007 0.000 -0.007 H 1.46975366817 -0.00523069331 2.87805400798 0.009 -0.000 -0.002 H -3.29750276746 -0.00099200484 3.88584245085 0.005 0.000 -0.001 H -4.55513299541 0.00377930937 -2.13473279421 -0.001 0.000 -0.001 H -4.55107479454 0.00501307822 2.13844314827 -0.001 0.000 0.002 H -6.83436893102 0.00806057203 1.19721860356 -0.000 0.000 0.000 H 6.86748209639 1.20005966818 0.00372860376 0.000 0.000 -0.000 61 Mode 166: freq=3425.56 N -0.44003451495 -0.00038510790 2.12369783068 0.002 -0.000 0.001 C -1.76594470239 0.00039861437 2.37754210613 0.003 0.000 -0.004 C -2.24923313135 -0.00145267054 3.67997125809 -0.079 0.000 0.027 C -1.33887502024 -0.00450793845 4.73956848945 0.070 0.000 -0.207 C 0.02462671625 -0.00591801736 4.46614405978 0.083 -0.000 0.101 C 0.43187566201 -0.00376957955 3.13352499014 -0.075 0.000 0.013 C -2.63984642995 0.00218980399 1.17162612704 -0.002 0.000 0.000 N -1.98513620489 0.00132140951 0.00153900685 0.000 0.000 0.000 C -2.63911589169 0.00167522827 -1.17277445342 0.000 0.000 0.000 C -4.02452897564 0.00329996303 -1.20791476641 -0.004 0.000 -0.007 C -4.73391255267 0.00451580118 -0.00020876193 0.001 0.000 0.002 C -4.02924140493 0.00399189729 1.20660077672 0.016 -0.000 -0.030 Co 0.00000000000 0.00000000000 0.00000000000 -0.000 0.000 -0.000 N -0.43839318333 -0.00054206762 -2.12229806799 -0.000 0.000 0.000 C -1.76408906064 -0.00030645034 -2.37697009192 -0.001 -0.000 -0.001 C -2.24773885821 -0.00257631963 -3.67934971086 0.020 0.000 0.007 C -1.33713102227 -0.00526459193 -4.73855802198 -0.018 -0.000 -0.053 C 0.02654101484 -0.00591797621 -4.46472703619 -0.022 0.000 0.027 C 0.43371721952 -0.00363389350 -3.13225443930 0.021 -0.000 0.004 S -6.53329279136 0.00637481657 -0.11611178087 -0.000 0.000 -0.000 N 2.00981687167 0.00259443239 -0.00000686048 -0.000 -0.000 0.000 C 2.67119656792 1.17263645248 0.00045766926 0.000 0.000 0.000 C 4.06129317470 1.20536051565 0.00241240325 0.000 0.000 -0.000 C 4.76783866331 0.00148799420 0.00346798881 0.000 -0.000 0.000 C 4.05723810074 -1.20352939940 0.00211502115 0.000 -0.000 -0.000 C 2.67108506586 -1.17139122066 0.00026591651 0.000 -0.000 0.000 C 1.82209539371 2.39842937406 -0.00175320633 0.000 0.000 -0.000 C 2.33938959521 3.68993217240 -0.00584554905 -0.001 -0.000 0.000 C 1.45736908622 4.77231118002 -0.00917967851 0.001 0.003 -0.000 C 0.08658913130 4.53522926787 -0.00833235387 0.001 -0.001 0.000 C -0.35359617412 3.21325694137 -0.00400174376 -0.001 -0.000 -0.000 N 0.49290585413 2.18198449515 -0.00068475564 0.000 0.000 0.000 S 6.56718562933 -0.11349126889 0.00673479967 -0.000 -0.000 0.000 C 1.82142022278 -2.39594383179 -0.00206827421 0.000 -0.000 -0.000 C 2.33969079820 -3.68709653410 -0.00625612120 -0.001 0.000 0.000 C 1.45789786198 -4.76953179608 -0.00945089783 0.001 -0.003 -0.000 C 0.08684213972 -4.53272927032 -0.00840538011 0.001 0.001 0.000 C -0.35393854068 -3.21111942258 -0.00398541364 -0.001 0.000 -0.000 N 0.49225266031 -2.17934076887 -0.00084210065 0.000 -0.000 0.000 H 1.83694111827 5.77332096953 -0.01265611066 -0.003 -0.008 0.000 H -0.61802819388 5.33967450634 -0.01131742088 -0.003 0.004 -0.000 H 3.39175422949 3.87200638269 -0.00704552340 0.003 0.001 -0.000 H -1.39787683933 2.98334799634 -0.00369736757 0.002 0.000 0.000 H 1.83794742242 -5.77033326187 -0.01295832570 -0.003 0.009 0.000 H -0.61749414542 -5.33746053721 -0.01121572048 -0.004 -0.004 -0.000 H -1.39833026435 -2.98175334118 -0.00345676225 0.003 -0.001 0.000 H 3.39230213722 -3.86796714602 -0.00754158092 0.003 -0.001 -0.000 H 4.58301895157 2.13678100538 0.00314824260 -0.001 -0.001 -0.000 H 4.58784714512 -2.12983634010 0.00211631073 -0.000 0.001 -0.000 H -1.68997263563 -0.00719388386 -5.74925805817 0.061 0.000 0.175 H 0.75224758084 -0.00860493512 -5.25016290812 0.080 -0.000 -0.087 H -3.29620044300 -0.00255800648 -3.88456579214 -0.070 0.000 -0.014 H 1.47161249279 -0.00457826661 -2.87685200854 -0.069 0.000 -0.017 H -1.69176120521 -0.00597000955 5.75026973076 -0.236 -0.001 0.677 H 0.75025791005 -0.00892914887 5.25161119224 -0.295 0.001 -0.322 H 1.46975366817 -0.00523069331 2.87805400798 0.246 -0.000 -0.061 H -3.29750276746 -0.00099200484 3.88584245085 0.273 -0.000 -0.054 H -4.55513299541 0.00377930937 -2.13473279421 0.013 -0.000 0.022 H -4.55107479454 0.00501307822 2.13844314827 -0.053 0.000 0.094 H -6.83436893102 0.00806057203 1.19721860356 -0.000 0.000 0.000 H 6.86748209639 1.20005966818 0.00372860376 -0.000 0.000 -0.000 61 Mode 167: freq=3425.70 N -0.44003451495 -0.00038510790 2.12369783068 -0.001 0.000 -0.000 C -1.76594470239 0.00039861437 2.37754210613 -0.001 -0.000 0.001 C -2.24923313135 -0.00145267054 3.67997125809 0.020 -0.000 -0.007 C -1.33887502024 -0.00450793845 4.73956848945 -0.018 -0.000 0.055 C 0.02462671625 -0.00591801736 4.46614405978 -0.022 0.000 -0.027 C 0.43187566201 -0.00376957955 3.13352499014 0.019 -0.000 -0.003 C -2.63984642995 0.00218980399 1.17162612704 0.001 -0.000 -0.000 N -1.98513620489 0.00132140951 0.00153900685 -0.000 -0.000 0.000 C -2.63911589169 0.00167522827 -1.17277445342 0.002 -0.000 0.000 C -4.02452897564 0.00329996303 -1.20791476641 -0.013 0.000 -0.024 C -4.73391255267 0.00451580118 -0.00020876193 -0.001 0.000 0.001 C -4.02924140493 0.00399189729 1.20660077672 -0.004 0.000 0.007 Co 0.00000000000 0.00000000000 0.00000000000 0.000 -0.000 -0.000 N -0.43839318333 -0.00054206762 -2.12229806799 -0.002 0.000 0.001 C -1.76408906064 -0.00030645034 -2.37697009192 -0.003 -0.000 -0.003 C -2.24773885821 -0.00257631963 -3.67934971086 0.075 0.000 0.026 C -1.33713102227 -0.00526459193 -4.73855802198 -0.069 -0.000 -0.205 C 0.02654101484 -0.00591797621 -4.46472703619 -0.087 0.000 0.104 C 0.43371721952 -0.00363389350 -3.13225443930 0.080 -0.000 0.014 S -6.53329279136 0.00637481657 -0.11611178087 0.000 -0.000 -0.000 N 2.00981687167 0.00259443239 -0.00000686048 0.000 0.000 0.000 C 2.67119656792 1.17263645248 0.00045766926 -0.000 -0.000 0.000 C 4.06129317470 1.20536051565 0.00241240325 -0.000 -0.000 -0.000 C 4.76783866331 0.00148799420 0.00346798881 -0.000 0.000 0.000 C 4.05723810074 -1.20352939940 0.00211502115 -0.000 0.000 -0.000 C 2.67108506586 -1.17139122066 0.00026591651 -0.000 0.000 0.000 C 1.82209539371 2.39842937406 -0.00175320633 -0.000 -0.000 -0.000 C 2.33938959521 3.68993217240 -0.00584554905 0.001 0.000 -0.000 C 1.45736908622 4.77231118002 -0.00917967851 -0.002 -0.004 0.000 C 0.08658913130 4.53522926787 -0.00833235387 -0.001 0.002 -0.000 C -0.35359617412 3.21325694137 -0.00400174376 0.001 0.000 -0.000 N 0.49290585413 2.18198449515 -0.00068475564 -0.000 -0.000 0.000 S 6.56718562933 -0.11349126889 0.00673479967 0.000 0.000 -0.000 C 1.82142022278 -2.39594383179 -0.00206827421 -0.000 0.000 -0.000 C 2.33969079820 -3.68709653410 -0.00625612120 0.001 -0.001 -0.000 C 1.45789786198 -4.76953179608 -0.00945089783 -0.002 0.005 0.000 C 0.08684213972 -4.53272927032 -0.00840538011 -0.002 -0.002 -0.000 C -0.35393854068 -3.21111942258 -0.00398541364 0.001 -0.000 -0.000 N 0.49225266031 -2.17934076887 -0.00084210065 -0.000 0.000 0.000 H 1.83694111827 5.77332096953 -0.01265611066 0.005 0.014 -0.000 H -0.61802819388 5.33967450634 -0.01131742088 0.005 -0.006 0.000 H 3.39175422949 3.87200638269 -0.00704552340 -0.005 -0.001 -0.000 H -1.39787683933 2.98334799634 -0.00369736757 -0.002 -0.000 0.000 H 1.83794742242 -5.77033326187 -0.01295832570 0.006 -0.015 -0.000 H -0.61749414542 -5.33746053721 -0.01121572048 0.006 0.007 0.000 H -1.39833026435 -2.98175334118 -0.00345676225 -0.004 0.001 0.000 H 3.39230213722 -3.86796714602 -0.00754158092 -0.005 0.001 -0.000 H 4.58301895157 2.13678100538 0.00314824260 0.001 0.001 -0.000 H 4.58784714512 -2.12983634010 0.00211631073 0.001 -0.001 -0.000 H -1.68997263563 -0.00719388386 -5.74925805817 0.233 0.001 0.668 H 0.75224758084 -0.00860493512 -5.25016290812 0.307 -0.001 -0.335 H -3.29620044300 -0.00255800648 -3.88456579214 -0.260 0.000 -0.051 H 1.47161249279 -0.00457826661 -2.87685200854 -0.261 0.000 -0.064 H -1.69176120521 -0.00597000955 5.75026973076 0.062 0.000 -0.178 H 0.75025791005 -0.00892914887 5.25161119224 0.078 -0.000 0.085 H 1.46975366817 -0.00523069331 2.87805400798 -0.063 0.000 0.016 H -3.29750276746 -0.00099200484 3.88584245085 -0.070 0.000 0.014 H -4.55513299541 0.00377930937 -2.13473279421 0.043 -0.000 0.075 H -4.55107479454 0.00501307822 2.13844314827 0.012 -0.000 -0.022 H -6.83436893102 0.00806057203 1.19721860356 0.000 -0.000 0.000 H 6.86748209639 1.20005966818 0.00372860376 0.000 -0.000 -0.000 61 Mode 168: freq=3431.96 N -0.44003451495 -0.00038510790 2.12369783068 -0.000 -0.000 0.000 C -1.76594470239 0.00039861437 2.37754210613 0.000 -0.000 0.000 C -2.24923313135 -0.00145267054 3.67997125809 0.000 0.000 -0.000 C -1.33887502024 -0.00450793845 4.73956848945 -0.000 -0.000 0.001 C 0.02462671625 -0.00591801736 4.46614405978 0.000 -0.000 -0.000 C 0.43187566201 -0.00376957955 3.13352499014 -0.001 -0.000 0.000 C -2.63984642995 0.00218980399 1.17162612704 -0.000 -0.000 0.000 N -1.98513620489 0.00132140951 0.00153900685 0.000 0.001 -0.000 C -2.63911589169 0.00167522827 -1.17277445342 -0.000 -0.000 -0.000 C -4.02452897564 0.00329996303 -1.20791476641 -0.000 -0.000 -0.000 C -4.73391255267 0.00451580118 -0.00020876193 -0.000 -0.000 0.000 C -4.02924140493 0.00399189729 1.20660077672 -0.000 -0.000 0.000 Co 0.00000000000 0.00000000000 0.00000000000 0.000 0.000 0.000 N -0.43839318333 -0.00054206762 -2.12229806799 -0.000 -0.000 -0.000 C -1.76408906064 -0.00030645034 -2.37697009192 0.000 -0.000 -0.000 C -2.24773885821 -0.00257631963 -3.67934971086 0.000 0.000 0.000 C -1.33713102227 -0.00526459193 -4.73855802198 -0.000 -0.000 -0.001 C 0.02654101484 -0.00591797621 -4.46472703619 0.000 -0.000 0.000 C 0.43371721952 -0.00363389350 -3.13225443930 -0.001 -0.000 -0.000 S -6.53329279136 0.00637481657 -0.11611178087 0.000 0.000 -0.000 N 2.00981687167 0.00259443239 -0.00000686048 -0.000 -0.001 -0.000 C 2.67119656792 1.17263645248 0.00045766926 -0.002 -0.000 -0.000 C 4.06129317470 1.20536051565 0.00241240325 0.016 0.028 0.000 C 4.76783866331 0.00148799420 0.00346798881 0.001 -0.002 0.000 C 4.05723810074 -1.20352939940 0.00211502115 -0.007 0.012 -0.000 C 2.67108506586 -1.17139122066 0.00026591651 0.001 -0.000 0.000 C 1.82209539371 2.39842937406 -0.00175320633 -0.002 0.003 -0.000 C 2.33938959521 3.68993217240 -0.00584554905 -0.059 -0.017 0.000 C 1.45736908622 4.77231118002 -0.00917967851 0.057 0.134 -0.000 C 0.08658913130 4.53522926787 -0.00833235387 -0.056 0.039 -0.000 C -0.35359617412 3.21325694137 -0.00400174376 0.194 0.043 -0.000 N 0.49290585413 2.18198449515 -0.00068475564 -0.004 0.003 -0.000 S 6.56718562933 -0.11349126889 0.00673479967 -0.000 0.000 -0.000 C 1.82142022278 -2.39594383179 -0.00206827421 0.001 0.002 0.000 C 2.33969079820 -3.68709653410 -0.00625612120 0.028 -0.008 -0.000 C 1.45789786198 -4.76953179608 -0.00945089783 -0.029 0.069 0.000 C 0.08684213972 -4.53272927032 -0.00840538011 0.025 0.016 0.000 C -0.35393854068 -3.21111942258 -0.00398541364 -0.092 0.020 0.000 N 0.49225266031 -2.17934076887 -0.00084210065 0.002 0.001 0.000 H 1.83694111827 5.77332096953 -0.01265611066 -0.168 -0.438 0.002 H -0.61802819388 5.33967450634 -0.01131742088 0.145 -0.159 0.001 H 3.39175422949 3.87200638269 -0.00704552340 0.203 0.035 -0.000 H -1.39787683933 2.98334799634 -0.00369736757 -0.633 -0.143 0.000 H 1.83794742242 -5.77033326187 -0.01295832570 0.086 -0.226 -0.001 H -0.61749414542 -5.33746053721 -0.01121572048 -0.062 -0.068 -0.000 H -1.39833026435 -2.98175334118 -0.00345676225 0.299 -0.067 -0.000 H 3.39230213722 -3.86796714602 -0.00754158092 -0.098 0.017 0.000 H 4.58301895157 2.13678100538 0.00314824260 -0.051 -0.091 -0.000 H 4.58784714512 -2.12983634010 0.00211631073 0.022 -0.038 0.000 H -1.68997263563 -0.00719388386 -5.74925805817 0.001 0.000 0.004 H 0.75224758084 -0.00860493512 -5.25016290812 -0.000 -0.000 0.000 H -3.29620044300 -0.00255800648 -3.88456579214 -0.002 -0.000 -0.000 H 1.47161249279 -0.00457826661 -2.87685200854 0.004 0.000 0.001 H -1.69176120521 -0.00597000955 5.75026973076 0.001 -0.000 -0.003 H 0.75025791005 -0.00892914887 5.25161119224 -0.000 0.000 -0.000 H 1.46975366817 -0.00523069331 2.87805400798 0.004 0.000 -0.001 H -3.29750276746 -0.00099200484 3.88584245085 -0.002 -0.000 0.000 H -4.55513299541 0.00377930937 -2.13473279421 0.000 -0.000 0.001 H -4.55107479454 0.00501307822 2.13844314827 0.000 -0.000 -0.001 H -6.83436893102 0.00806057203 1.19721860356 0.000 -0.000 -0.000 H 6.86748209639 1.20005966818 0.00372860376 -0.000 -0.000 0.000 61 Mode 169: freq=3432.06 N -0.44003451495 -0.00038510790 2.12369783068 -0.000 0.000 0.000 C -1.76594470239 0.00039861437 2.37754210613 0.000 0.000 0.000 C -2.24923313135 -0.00145267054 3.67997125809 0.001 -0.000 -0.000 C -1.33887502024 -0.00450793845 4.73956848945 -0.001 -0.000 0.003 C 0.02462671625 -0.00591801736 4.46614405978 0.000 0.000 -0.000 C 0.43187566201 -0.00376957955 3.13352499014 -0.003 0.000 0.001 C -2.63984642995 0.00218980399 1.17162612704 -0.000 0.000 0.000 N -1.98513620489 0.00132140951 0.00153900685 0.000 -0.000 -0.000 C -2.63911589169 0.00167522827 -1.17277445342 -0.000 0.000 -0.000 C -4.02452897564 0.00329996303 -1.20791476641 -0.000 0.000 -0.001 C -4.73391255267 0.00451580118 -0.00020876193 -0.000 0.000 -0.000 C -4.02924140493 0.00399189729 1.20660077672 -0.000 0.000 0.001 Co 0.00000000000 0.00000000000 0.00000000000 0.000 -0.000 0.000 N -0.43839318333 -0.00054206762 -2.12229806799 -0.000 0.000 -0.000 C -1.76408906064 -0.00030645034 -2.37697009192 0.000 0.000 -0.000 C -2.24773885821 -0.00257631963 -3.67934971086 0.001 -0.000 0.000 C -1.33713102227 -0.00526459193 -4.73855802198 -0.001 -0.000 -0.003 C 0.02654101484 -0.00591797621 -4.46472703619 0.000 0.000 0.000 C 0.43371721952 -0.00363389350 -3.13225443930 -0.003 0.000 -0.001 S -6.53329279136 0.00637481657 -0.11611178087 0.000 -0.000 -0.000 N 2.00981687167 0.00259443239 -0.00000686048 -0.000 0.000 -0.000 C 2.67119656792 1.17263645248 0.00045766926 -0.001 -0.000 -0.000 C 4.06129317470 1.20536051565 0.00241240325 0.007 0.013 0.000 C 4.76783866331 0.00148799420 0.00346798881 0.001 0.000 0.000 C 4.05723810074 -1.20352939940 0.00211502115 0.013 -0.023 -0.000 C 2.67108506586 -1.17139122066 0.00026591651 -0.002 0.000 -0.000 C 1.82209539371 2.39842937406 -0.00175320633 -0.001 0.002 -0.000 C 2.33938959521 3.68993217240 -0.00584554905 -0.028 -0.008 0.000 C 1.45736908622 4.77231118002 -0.00917967851 0.028 0.065 -0.000 C 0.08658913130 4.53522926787 -0.00833235387 -0.027 0.019 -0.000 C -0.35359617412 3.21325694137 -0.00400174376 0.094 0.021 -0.000 N 0.49290585413 2.18198449515 -0.00068475564 -0.002 0.001 -0.000 S 6.56718562933 -0.11349126889 0.00673479967 -0.000 -0.000 -0.000 C 1.82142022278 -2.39594383179 -0.00206827421 -0.002 -0.003 -0.000 C 2.33969079820 -3.68709653410 -0.00625612120 -0.058 0.017 0.000 C 1.45789786198 -4.76953179608 -0.00945089783 0.061 -0.143 -0.000 C 0.08684213972 -4.53272927032 -0.00840538011 -0.052 -0.033 -0.000 C -0.35393854068 -3.21111942258 -0.00398541364 0.190 -0.042 -0.000 N 0.49225266031 -2.17934076887 -0.00084210065 -0.003 -0.002 -0.000 H 1.83694111827 5.77332096953 -0.01265611066 -0.081 -0.212 0.001 H -0.61802819388 5.33967450634 -0.01131742088 0.071 -0.078 0.000 H 3.39175422949 3.87200638269 -0.00704552340 0.097 0.017 -0.000 H -1.39787683933 2.98334799634 -0.00369736757 -0.305 -0.069 0.000 H 1.83794742242 -5.77033326187 -0.01295832570 -0.179 0.468 0.002 H -0.61749414542 -5.33746053721 -0.01121572048 0.131 0.143 0.000 H -1.39833026435 -2.98175334118 -0.00345676225 -0.620 0.140 0.000 H 3.39230213722 -3.86796714602 -0.00754158092 0.201 -0.035 -0.000 H 4.58301895157 2.13678100538 0.00314824260 -0.023 -0.041 -0.000 H 4.58784714512 -2.12983634010 0.00211631073 -0.041 0.072 -0.000 H -1.68997263563 -0.00719388386 -5.74925805817 0.004 0.000 0.010 H 0.75224758084 -0.00860493512 -5.25016290812 -0.000 0.000 0.000 H -3.29620044300 -0.00255800648 -3.88456579214 -0.005 0.000 -0.001 H 1.47161249279 -0.00457826661 -2.87685200854 0.011 -0.000 0.003 H -1.69176120521 -0.00597000955 5.75026973076 0.003 0.000 -0.010 H 0.75025791005 -0.00892914887 5.25161119224 -0.001 0.000 -0.001 H 1.46975366817 -0.00523069331 2.87805400798 0.011 -0.000 -0.003 H -3.29750276746 -0.00099200484 3.88584245085 -0.005 0.000 0.001 H -4.55513299541 0.00377930937 -2.13473279421 0.001 0.000 0.002 H -4.55107479454 0.00501307822 2.13844314827 0.001 0.000 -0.002 H -6.83436893102 0.00806057203 1.19721860356 0.000 0.000 -0.000 H 6.86748209639 1.20005966818 0.00372860376 -0.000 -0.000 0.000 61 Mode 170: freq=3435.62 N -0.44003451495 -0.00038510790 2.12369783068 0.002 -0.000 0.002 C -1.76594470239 0.00039861437 2.37754210613 0.001 -0.000 0.003 C -2.24923313135 -0.00145267054 3.67997125809 0.060 -0.000 -0.015 C -1.33887502024 -0.00450793845 4.73956848945 -0.032 -0.000 0.068 C 0.02462671625 -0.00591801736 4.46614405978 0.070 -0.000 0.060 C 0.43187566201 -0.00376957955 3.13352499014 -0.137 0.000 0.031 C -2.63984642995 0.00218980399 1.17162612704 0.003 -0.000 -0.000 N -1.98513620489 0.00132140951 0.00153900685 0.000 -0.000 -0.001 C -2.63911589169 0.00167522827 -1.17277445342 -0.002 0.000 -0.000 C -4.02452897564 0.00329996303 -1.20791476641 0.019 -0.000 0.032 C -4.73391255267 0.00451580118 -0.00020876193 -0.000 -0.000 -0.003 C -4.02924140493 0.00399189729 1.20660077672 -0.023 0.000 0.041 Co 0.00000000000 0.00000000000 0.00000000000 0.000 -0.000 -0.000 N -0.43839318333 -0.00054206762 -2.12229806799 -0.003 0.000 0.002 C -1.76408906064 -0.00030645034 -2.37697009192 -0.001 0.000 0.003 C -2.24773885821 -0.00257631963 -3.67934971086 -0.061 -0.000 -0.016 C -1.33713102227 -0.00526459193 -4.73855802198 0.037 0.000 0.084 C 0.02654101484 -0.00591797621 -4.46472703619 -0.073 0.000 0.062 C 0.43371721952 -0.00363389350 -3.13225443930 0.149 -0.000 0.034 S -6.53329279136 0.00637481657 -0.11611178087 0.000 0.000 0.000 N 2.00981687167 0.00259443239 -0.00000686048 -0.000 -0.000 0.001 C 2.67119656792 1.17263645248 0.00045766926 -0.000 -0.000 0.000 C 4.06129317470 1.20536051565 0.00241240325 0.000 0.000 -0.000 C 4.76783866331 0.00148799420 0.00346798881 -0.000 -0.000 -0.000 C 4.05723810074 -1.20352939940 0.00211502115 0.000 -0.000 -0.000 C 2.67108506586 -1.17139122066 0.00026591651 -0.000 0.000 0.000 C 1.82209539371 2.39842937406 -0.00175320633 -0.000 -0.000 -0.000 C 2.33938959521 3.68993217240 -0.00584554905 -0.000 -0.000 0.000 C 1.45736908622 4.77231118002 -0.00917967851 0.000 0.000 0.000 C 0.08658913130 4.53522926787 -0.00833235387 -0.000 0.000 -0.000 C -0.35359617412 3.21325694137 -0.00400174376 0.000 0.000 -0.000 N 0.49290585413 2.18198449515 -0.00068475564 -0.000 -0.000 -0.000 S 6.56718562933 -0.11349126889 0.00673479967 0.000 0.000 -0.000 C 1.82142022278 -2.39594383179 -0.00206827421 -0.000 0.000 -0.000 C 2.33969079820 -3.68709653410 -0.00625612120 -0.000 0.000 0.000 C 1.45789786198 -4.76953179608 -0.00945089783 0.000 -0.000 0.000 C 0.08684213972 -4.53272927032 -0.00840538011 -0.000 -0.000 -0.000 C -0.35393854068 -3.21111942258 -0.00398541364 0.000 -0.000 -0.000 N 0.49225266031 -2.17934076887 -0.00084210065 -0.000 0.000 -0.000 H 1.83694111827 5.77332096953 -0.01265611066 -0.000 -0.000 -0.000 H -0.61802819388 5.33967450634 -0.01131742088 0.000 -0.000 0.000 H 3.39175422949 3.87200638269 -0.00704552340 0.000 0.000 -0.000 H -1.39787683933 2.98334799634 -0.00369736757 -0.001 -0.000 0.000 H 1.83794742242 -5.77033326187 -0.01295832570 -0.000 0.000 -0.000 H -0.61749414542 -5.33746053721 -0.01121572048 0.000 0.000 0.000 H -1.39833026435 -2.98175334118 -0.00345676225 -0.001 0.000 0.000 H 3.39230213722 -3.86796714602 -0.00754158092 0.000 -0.000 -0.000 H 4.58301895157 2.13678100538 0.00314824260 -0.000 -0.000 -0.000 H 4.58784714512 -2.12983634010 0.00211631073 -0.000 0.000 -0.000 H -1.68997263563 -0.00719388386 -5.74925805817 -0.098 -0.001 -0.277 H 0.75224758084 -0.00860493512 -5.25016290812 0.212 -0.001 -0.225 H -3.29620044300 -0.00255800648 -3.88456579214 0.205 -0.000 0.040 H 1.47161249279 -0.00457826661 -2.87685200854 -0.485 0.000 -0.122 H -1.69176120521 -0.00597000955 5.75026973076 0.081 0.000 -0.226 H 0.75025791005 -0.00892914887 5.25161119224 -0.204 0.001 -0.218 H 1.46975366817 -0.00523069331 2.87805400798 0.446 -0.001 -0.112 H -3.29750276746 -0.00099200484 3.88584245085 -0.201 0.000 0.039 H -4.55513299541 0.00377930937 -2.13473279421 -0.059 0.000 -0.104 H -4.55107479454 0.00501307822 2.13844314827 0.075 -0.000 -0.135 H -6.83436893102 0.00806057203 1.19721860356 0.000 -0.000 -0.001 H 6.86748209639 1.20005966818 0.00372860376 -0.000 -0.000 0.000 61 Mode 171: freq=3435.73 N -0.44003451495 -0.00038510790 2.12369783068 -0.003 0.000 -0.002 C -1.76594470239 0.00039861437 2.37754210613 -0.001 0.000 -0.003 C -2.24923313135 -0.00145267054 3.67997125809 -0.064 0.000 0.016 C -1.33887502024 -0.00450793845 4.73956848945 0.035 0.000 -0.075 C 0.02462671625 -0.00591801736 4.46614405978 -0.075 0.000 -0.065 C 0.43187566201 -0.00376957955 3.13352499014 0.147 -0.000 -0.034 C -2.63984642995 0.00218980399 1.17162612704 -0.003 0.000 0.000 N -1.98513620489 0.00132140951 0.00153900685 -0.000 0.000 0.000 C -2.63911589169 0.00167522827 -1.17277445342 -0.002 0.000 -0.001 C -4.02452897564 0.00329996303 -1.20791476641 0.015 -0.000 0.027 C -4.73391255267 0.00451580118 -0.00020876193 0.002 -0.000 0.001 C -4.02924140493 0.00399189729 1.20660077672 0.023 -0.000 -0.041 Co 0.00000000000 0.00000000000 0.00000000000 0.001 -0.000 -0.000 N -0.43839318333 -0.00054206762 -2.12229806799 -0.002 0.000 0.002 C -1.76408906064 -0.00030645034 -2.37697009192 -0.001 0.000 0.003 C -2.24773885821 -0.00257631963 -3.67934971086 -0.055 -0.000 -0.015 C -1.33713102227 -0.00526459193 -4.73855802198 0.035 0.000 0.080 C 0.02654101484 -0.00591797621 -4.46472703619 -0.068 0.000 0.057 C 0.43371721952 -0.00363389350 -3.13225443930 0.139 -0.000 0.032 S -6.53329279136 0.00637481657 -0.11611178087 -0.000 0.000 -0.000 N 2.00981687167 0.00259443239 -0.00000686048 0.000 0.000 -0.000 C 2.67119656792 1.17263645248 0.00045766926 -0.000 -0.000 -0.000 C 4.06129317470 1.20536051565 0.00241240325 0.000 0.001 0.000 C 4.76783866331 0.00148799420 0.00346798881 0.000 -0.000 -0.000 C 4.05723810074 -1.20352939940 0.00211502115 0.000 -0.000 0.000 C 2.67108506586 -1.17139122066 0.00026591651 -0.000 0.000 -0.000 C 1.82209539371 2.39842937406 -0.00175320633 -0.000 -0.000 0.000 C 2.33938959521 3.68993217240 -0.00584554905 -0.001 -0.000 0.000 C 1.45736908622 4.77231118002 -0.00917967851 0.001 0.002 -0.000 C 0.08658913130 4.53522926787 -0.00833235387 -0.002 0.002 -0.000 C -0.35359617412 3.21325694137 -0.00400174376 0.003 0.001 -0.000 N 0.49290585413 2.18198449515 -0.00068475564 -0.000 -0.000 0.000 S 6.56718562933 -0.11349126889 0.00673479967 0.000 0.000 0.000 C 1.82142022278 -2.39594383179 -0.00206827421 -0.000 0.000 0.000 C 2.33969079820 -3.68709653410 -0.00625612120 -0.001 0.000 0.000 C 1.45789786198 -4.76953179608 -0.00945089783 0.001 -0.002 -0.000 C 0.08684213972 -4.53272927032 -0.00840538011 -0.002 -0.002 -0.000 C -0.35393854068 -3.21111942258 -0.00398541364 0.003 -0.001 -0.000 N 0.49225266031 -2.17934076887 -0.00084210065 -0.000 0.000 0.000 H 1.83694111827 5.77332096953 -0.01265611066 -0.002 -0.006 0.000 H -0.61802819388 5.33967450634 -0.01131742088 0.006 -0.007 0.000 H 3.39175422949 3.87200638269 -0.00704552340 0.004 0.001 -0.000 H -1.39787683933 2.98334799634 -0.00369736757 -0.011 -0.002 0.000 H 1.83794742242 -5.77033326187 -0.01295832570 -0.002 0.006 0.000 H -0.61749414542 -5.33746053721 -0.01121572048 0.006 0.007 0.000 H -1.39833026435 -2.98175334118 -0.00345676225 -0.011 0.002 0.000 H 3.39230213722 -3.86796714602 -0.00754158092 0.003 -0.001 -0.000 H 4.58301895157 2.13678100538 0.00314824260 -0.001 -0.002 -0.000 H 4.58784714512 -2.12983634010 0.00211631073 -0.001 0.002 -0.000 H -1.68997263563 -0.00719388386 -5.74925805817 -0.093 -0.000 -0.262 H 0.75224758084 -0.00860493512 -5.25016290812 0.197 -0.001 -0.210 H -3.29620044300 -0.00255800648 -3.88456579214 0.187 -0.000 0.036 H 1.47161249279 -0.00457826661 -2.87685200854 -0.452 0.000 -0.114 H -1.69176120521 -0.00597000955 5.75026973076 -0.088 -0.000 0.248 H 0.75025791005 -0.00892914887 5.25161119224 0.221 -0.001 0.235 H 1.46975366817 -0.00523069331 2.87805400798 -0.481 0.001 0.121 H -3.29750276746 -0.00099200484 3.88584245085 0.214 -0.000 -0.042 H -4.55513299541 0.00377930937 -2.13473279421 -0.048 0.000 -0.085 H -4.55107479454 0.00501307822 2.13844314827 -0.074 0.000 0.134 H -6.83436893102 0.00806057203 1.19721860356 -0.000 0.000 0.000 H 6.86748209639 1.20005966818 0.00372860376 -0.000 -0.000 0.000 61 Mode 172: freq=3442.05 N -0.44003451495 -0.00038510790 2.12369783068 0.003 -0.000 0.002 C -1.76594470239 0.00039861437 2.37754210613 0.005 0.000 -0.008 C -2.24923313135 -0.00145267054 3.67997125809 -0.140 0.000 0.023 C -1.33887502024 -0.00450793845 4.73956848945 -0.029 -0.000 0.103 C 0.02462671625 -0.00591801736 4.46614405978 -0.009 0.000 -0.024 C 0.43187566201 -0.00376957955 3.13352499014 -0.088 0.000 0.024 C -2.63984642995 0.00218980399 1.17162612704 -0.011 0.000 0.000 N -1.98513620489 0.00132140951 0.00153900685 -0.000 0.000 0.002 C -2.63911589169 0.00167522827 -1.17277445342 0.001 -0.000 0.000 C -4.02452897564 0.00329996303 -1.20791476641 -0.017 0.000 -0.029 C -4.73391255267 0.00451580118 -0.00020876193 0.005 -0.000 0.010 C -4.02924140493 0.00399189729 1.20660077672 0.105 -0.000 -0.185 Co 0.00000000000 0.00000000000 0.00000000000 -0.000 0.000 -0.000 N -0.43839318333 -0.00054206762 -2.12229806799 -0.000 0.000 0.000 C -1.76408906064 -0.00030645034 -2.37697009192 -0.001 -0.000 -0.001 C -2.24773885821 -0.00257631963 -3.67934971086 0.024 -0.000 0.004 C -1.33713102227 -0.00526459193 -4.73855802198 0.005 0.000 0.017 C 0.02654101484 -0.00591797621 -4.46472703619 0.002 -0.000 -0.005 C 0.43371721952 -0.00363389350 -3.13225443930 0.014 -0.000 0.004 S -6.53329279136 0.00637481657 -0.11611178087 -0.000 -0.000 -0.000 N 2.00981687167 0.00259443239 -0.00000686048 0.000 0.000 0.000 C 2.67119656792 1.17263645248 0.00045766926 0.000 0.000 0.000 C 4.06129317470 1.20536051565 0.00241240325 -0.000 -0.001 -0.000 C 4.76783866331 0.00148799420 0.00346798881 -0.000 0.000 -0.000 C 4.05723810074 -1.20352939940 0.00211502115 -0.000 0.000 -0.000 C 2.67108506586 -1.17139122066 0.00026591651 0.000 -0.000 0.000 C 1.82209539371 2.39842937406 -0.00175320633 -0.000 -0.000 -0.000 C 2.33938959521 3.68993217240 -0.00584554905 0.001 0.000 0.000 C 1.45736908622 4.77231118002 -0.00917967851 -0.000 0.000 -0.000 C 0.08658913130 4.53522926787 -0.00833235387 0.001 -0.001 0.000 C -0.35359617412 3.21325694137 -0.00400174376 0.000 0.000 -0.000 N 0.49290585413 2.18198449515 -0.00068475564 0.000 0.000 0.000 S 6.56718562933 -0.11349126889 0.00673479967 -0.000 -0.000 0.000 C 1.82142022278 -2.39594383179 -0.00206827421 -0.000 -0.000 -0.000 C 2.33969079820 -3.68709653410 -0.00625612120 0.001 -0.000 0.000 C 1.45789786198 -4.76953179608 -0.00945089783 -0.000 0.000 -0.000 C 0.08684213972 -4.53272927032 -0.00840538011 0.001 0.001 0.000 C -0.35393854068 -3.21111942258 -0.00398541364 -0.000 -0.000 -0.000 N 0.49225266031 -2.17934076887 -0.00084210065 0.000 -0.000 0.000 H 1.83694111827 5.77332096953 -0.01265611066 -0.000 -0.000 -0.000 H -0.61802819388 5.33967450634 -0.01131742088 -0.003 0.003 -0.000 H 3.39175422949 3.87200638269 -0.00704552340 -0.003 -0.001 -0.000 H -1.39787683933 2.98334799634 -0.00369736757 -0.000 -0.000 -0.000 H 1.83794742242 -5.77033326187 -0.01295832570 0.000 -0.001 -0.000 H -0.61749414542 -5.33746053721 -0.01121572048 -0.002 -0.002 -0.000 H -1.39833026435 -2.98175334118 -0.00345676225 0.000 -0.000 -0.000 H 3.39230213722 -3.86796714602 -0.00754158092 -0.002 0.000 -0.000 H 4.58301895157 2.13678100538 0.00314824260 0.002 0.003 -0.000 H 4.58784714512 -2.12983634010 0.00211631073 0.000 -0.001 -0.000 H -1.68997263563 -0.00719388386 -5.74925805817 -0.018 -0.000 -0.052 H 0.75224758084 -0.00860493512 -5.25016290812 -0.011 0.000 0.013 H -3.29620044300 -0.00255800648 -3.88456579214 -0.077 0.000 -0.014 H 1.47161249279 -0.00457826661 -2.87685200854 -0.047 0.000 -0.012 H -1.69176120521 -0.00597000955 5.75026973076 0.109 0.000 -0.317 H 0.75025791005 -0.00892914887 5.25161119224 0.050 -0.000 0.059 H 1.46975366817 -0.00523069331 2.87805400798 0.287 -0.000 -0.073 H -3.29750276746 -0.00099200484 3.88584245085 0.443 -0.000 -0.084 H -4.55513299541 0.00377930937 -2.13473279421 0.055 -0.000 0.098 H -4.55107479454 0.00501307822 2.13844314827 -0.335 0.001 0.604 H -6.83436893102 0.00806057203 1.19721860356 -0.001 0.000 0.002 H 6.86748209639 1.20005966818 0.00372860376 0.000 0.000 -0.000 61 Mode 173: freq=3443.68 N -0.44003451495 -0.00038510790 2.12369783068 0.000 -0.000 -0.000 C -1.76594470239 0.00039861437 2.37754210613 0.000 0.000 -0.000 C -2.24923313135 -0.00145267054 3.67997125809 0.000 -0.000 -0.000 C -1.33887502024 -0.00450793845 4.73956848945 -0.000 0.000 0.000 C 0.02462671625 -0.00591801736 4.46614405978 0.001 -0.000 0.001 C 0.43187566201 -0.00376957955 3.13352499014 -0.000 0.000 0.000 C -2.63984642995 0.00218980399 1.17162612704 0.000 0.000 -0.000 N -1.98513620489 0.00132140951 0.00153900685 0.000 -0.000 0.000 C -2.63911589169 0.00167522827 -1.17277445342 0.000 0.000 0.000 C -4.02452897564 0.00329996303 -1.20791476641 -0.003 0.000 -0.005 C -4.73391255267 0.00451580118 -0.00020876193 -0.000 0.000 0.000 C -4.02924140493 0.00399189729 1.20660077672 0.000 0.000 -0.000 Co 0.00000000000 0.00000000000 0.00000000000 -0.000 0.000 -0.000 N -0.43839318333 -0.00054206762 -2.12229806799 -0.000 -0.000 0.000 C -1.76408906064 -0.00030645034 -2.37697009192 -0.000 0.000 -0.000 C -2.24773885821 -0.00257631963 -3.67934971086 0.005 -0.000 0.001 C -1.33713102227 -0.00526459193 -4.73855802198 0.001 0.000 0.003 C 0.02654101484 -0.00591797621 -4.46472703619 0.001 -0.000 -0.002 C 0.43371721952 -0.00363389350 -3.13225443930 0.002 0.000 0.001 S -6.53329279136 0.00637481657 -0.11611178087 0.000 -0.000 -0.000 N 2.00981687167 0.00259443239 -0.00000686048 -0.000 -0.002 0.000 C 2.67119656792 1.17263645248 0.00045766926 -0.011 -0.001 -0.000 C 4.06129317470 1.20536051565 0.00241240325 0.098 0.174 0.000 C 4.76783866331 0.00148799420 0.00346798881 0.005 -0.009 0.000 C 4.05723810074 -1.20352939940 0.00211502115 -0.016 0.027 -0.000 C 2.67108506586 -1.17139122066 0.00026591651 0.001 -0.000 0.000 C 1.82209539371 2.39842937406 -0.00175320633 0.005 0.009 -0.000 C 2.33938959521 3.68993217240 -0.00584554905 -0.171 -0.027 0.000 C 1.45736908622 4.77231118002 -0.00917967851 -0.013 -0.065 0.000 C 0.08658913130 4.53522926787 -0.00833235387 -0.049 0.066 -0.000 C -0.35359617412 3.21325694137 -0.00400174376 -0.066 -0.019 0.000 N 0.49290585413 2.18198449515 -0.00068475564 0.003 -0.002 0.000 S 6.56718562933 -0.11349126889 0.00673479967 -0.000 0.000 -0.000 C 1.82142022278 -2.39594383179 -0.00206827421 -0.001 0.001 0.000 C 2.33969079820 -3.68709653410 -0.00625612120 0.028 -0.004 -0.000 C 1.45789786198 -4.76953179608 -0.00945089783 0.002 -0.010 -0.000 C 0.08684213972 -4.53272927032 -0.00840538011 0.009 0.012 0.000 C -0.35393854068 -3.21111942258 -0.00398541364 0.011 -0.003 -0.000 N 0.49225266031 -2.17934076887 -0.00084210065 -0.000 -0.000 -0.000 H 1.83694111827 5.77332096953 -0.01265611066 0.070 0.194 -0.001 H -0.61802819388 5.33967450634 -0.01131742088 0.174 -0.202 0.001 H 3.39175422949 3.87200638269 -0.00704552340 0.547 0.090 -0.001 H -1.39787683933 2.98334799634 -0.00369736757 0.212 0.049 -0.000 H 1.83794742242 -5.77033326187 -0.01295832570 -0.011 0.030 0.000 H -0.61749414542 -5.33746053721 -0.01121572048 -0.031 -0.036 -0.000 H -1.39833026435 -2.98175334118 -0.00345676225 -0.034 0.008 0.000 H 3.39230213722 -3.86796714602 -0.00754158092 -0.089 0.015 0.000 H 4.58301895157 2.13678100538 0.00314824260 -0.314 -0.567 -0.000 H 4.58784714512 -2.12983634010 0.00211631073 0.050 -0.089 0.000 H -1.68997263563 -0.00719388386 -5.74925805817 -0.003 -0.000 -0.008 H 0.75224758084 -0.00860493512 -5.25016290812 -0.004 0.000 0.005 H -3.29620044300 -0.00255800648 -3.88456579214 -0.016 0.000 -0.003 H 1.47161249279 -0.00457826661 -2.87685200854 -0.008 0.000 -0.002 H -1.69176120521 -0.00597000955 5.75026973076 0.000 0.000 -0.001 H 0.75025791005 -0.00892914887 5.25161119224 -0.002 0.000 -0.002 H 1.46975366817 -0.00523069331 2.87805400798 0.000 0.000 -0.000 H -3.29750276746 -0.00099200484 3.88584245085 -0.001 0.000 0.000 H -4.55513299541 0.00377930937 -2.13473279421 0.009 0.000 0.016 H -4.55107479454 0.00501307822 2.13844314827 -0.000 0.000 0.001 H -6.83436893102 0.00806057203 1.19721860356 0.000 0.000 0.000 H 6.86748209639 1.20005966818 0.00372860376 -0.001 -0.002 0.000 61 Mode 174: freq=3444.05 N -0.44003451495 -0.00038510790 2.12369783068 -0.001 0.000 -0.000 C -1.76594470239 0.00039861437 2.37754210613 -0.001 -0.000 0.002 C -2.24923313135 -0.00145267054 3.67997125809 0.027 -0.000 -0.005 C -1.33887502024 -0.00450793845 4.73956848945 0.004 0.000 -0.015 C 0.02462671625 -0.00591801736 4.46614405978 0.003 -0.000 0.006 C 0.43187566201 -0.00376957955 3.13352499014 0.014 -0.000 -0.004 C -2.63984642995 0.00218980399 1.17162612704 0.003 -0.000 -0.000 N -1.98513620489 0.00132140951 0.00153900685 0.001 0.000 0.001 C -2.63911589169 0.00167522827 -1.17277445342 0.011 -0.000 0.001 C -4.02452897564 0.00329996303 -1.20791476641 -0.096 0.000 -0.166 C -4.73391255267 0.00451580118 -0.00020876193 -0.005 0.000 0.006 C -4.02924140493 0.00399189729 1.20660077672 -0.017 0.000 0.029 Co 0.00000000000 0.00000000000 0.00000000000 0.000 -0.000 -0.000 N -0.43839318333 -0.00054206762 -2.12229806799 -0.004 0.000 0.002 C -1.76408906064 -0.00030645034 -2.37697009192 -0.006 -0.000 -0.009 C -2.24773885821 -0.00257631963 -3.67934971086 0.171 -0.000 0.030 C -1.33713102227 -0.00526459193 -4.73855802198 0.022 0.000 0.092 C 0.02654101484 -0.00591797621 -4.46472703619 0.026 -0.000 -0.041 C 0.43371721952 -0.00363389350 -3.13225443930 0.086 -0.000 0.024 S -6.53329279136 0.00637481657 -0.11611178087 0.001 -0.000 -0.000 N 2.00981687167 0.00259443239 -0.00000686048 0.000 0.000 0.000 C 2.67119656792 1.17263645248 0.00045766926 0.000 -0.000 0.000 C 4.06129317470 1.20536051565 0.00241240325 -0.003 -0.005 -0.000 C 4.76783866331 0.00148799420 0.00346798881 -0.000 0.000 -0.000 C 4.05723810074 -1.20352939940 0.00211502115 0.002 -0.003 -0.000 C 2.67108506586 -1.17139122066 0.00026591651 -0.000 0.000 0.000 C 1.82209539371 2.39842937406 -0.00175320633 -0.000 -0.000 -0.000 C 2.33938959521 3.68993217240 -0.00584554905 0.004 0.001 0.000 C 1.45736908622 4.77231118002 -0.00917967851 0.001 0.002 -0.000 C 0.08658913130 4.53522926787 -0.00833235387 0.000 -0.001 0.000 C -0.35359617412 3.21325694137 -0.00400174376 0.002 0.000 -0.000 N 0.49290585413 2.18198449515 -0.00068475564 -0.000 -0.000 0.000 S 6.56718562933 -0.11349126889 0.00673479967 0.000 -0.000 0.000 C 1.82142022278 -2.39594383179 -0.00206827421 0.000 -0.000 -0.000 C 2.33969079820 -3.68709653410 -0.00625612120 -0.003 0.001 0.000 C 1.45789786198 -4.76953179608 -0.00945089783 0.000 0.001 -0.000 C 0.08684213972 -4.53272927032 -0.00840538011 -0.002 -0.002 -0.000 C -0.35393854068 -3.21111942258 -0.00398541364 -0.001 0.000 -0.000 N 0.49225266031 -2.17934076887 -0.00084210065 0.000 0.000 0.000 H 1.83694111827 5.77332096953 -0.01265611066 -0.002 -0.007 0.000 H -0.61802819388 5.33967450634 -0.01131742088 -0.002 0.002 -0.000 H 3.39175422949 3.87200638269 -0.00704552340 -0.014 -0.002 0.000 H -1.39787683933 2.98334799634 -0.00369736757 -0.006 -0.001 0.000 H 1.83794742242 -5.77033326187 -0.01295832570 0.000 -0.001 -0.000 H -0.61749414542 -5.33746053721 -0.01121572048 0.007 0.008 0.000 H -1.39833026435 -2.98175334118 -0.00345676225 0.004 -0.001 -0.000 H 3.39230213722 -3.86796714602 -0.00754158092 0.011 -0.002 -0.000 H 4.58301895157 2.13678100538 0.00314824260 0.009 0.016 0.000 H 4.58784714512 -2.12983634010 0.00211631073 -0.005 0.009 -0.000 H -1.68997263563 -0.00719388386 -5.74925805817 -0.094 -0.001 -0.278 H 0.75224758084 -0.00860493512 -5.25016290812 -0.103 0.000 0.115 H -3.29620044300 -0.00255800648 -3.88456579214 -0.545 0.000 -0.102 H 1.47161249279 -0.00457826661 -2.87685200854 -0.279 0.000 -0.071 H -1.69176120521 -0.00597000955 5.75026973076 -0.016 -0.000 0.047 H 0.75025791005 -0.00892914887 5.25161119224 -0.014 0.000 -0.016 H 1.46975366817 -0.00523069331 2.87805400798 -0.046 0.000 0.012 H -3.29750276746 -0.00099200484 3.88584245085 -0.086 0.000 0.016 H -4.55513299541 0.00377930937 -2.13473279421 0.304 -0.000 0.540 H -4.55107479454 0.00501307822 2.13844314827 0.052 -0.000 -0.093 H -6.83436893102 0.00806057203 1.19721860356 0.001 -0.000 0.000 H 6.86748209639 1.20005966818 0.00372860376 0.000 0.000 -0.000 61 Mode 175: freq=3445.53 N -0.44003451495 -0.00038510790 2.12369783068 -0.000 -0.000 0.000 C -1.76594470239 0.00039861437 2.37754210613 -0.000 0.000 0.000 C -2.24923313135 -0.00145267054 3.67997125809 0.001 -0.000 -0.000 C -1.33887502024 -0.00450793845 4.73956848945 0.000 0.000 -0.001 C 0.02462671625 -0.00591801736 4.46614405978 -0.001 0.000 -0.001 C 0.43187566201 -0.00376957955 3.13352499014 0.000 0.000 -0.000 C -2.63984642995 0.00218980399 1.17162612704 0.000 0.000 0.000 N -1.98513620489 0.00132140951 0.00153900685 0.000 -0.000 0.000 C -2.63911589169 0.00167522827 -1.17277445342 0.000 0.000 -0.000 C -4.02452897564 0.00329996303 -1.20791476641 -0.002 0.000 -0.003 C -4.73391255267 0.00451580118 -0.00020876193 -0.000 0.000 0.000 C -4.02924140493 0.00399189729 1.20660077672 -0.001 0.000 0.001 Co 0.00000000000 0.00000000000 0.00000000000 0.000 0.000 -0.000 N -0.43839318333 -0.00054206762 -2.12229806799 -0.000 -0.000 -0.000 C -1.76408906064 -0.00030645034 -2.37697009192 -0.000 0.000 -0.000 C -2.24773885821 -0.00257631963 -3.67934971086 0.002 -0.000 0.000 C -1.33713102227 -0.00526459193 -4.73855802198 0.001 0.000 0.002 C 0.02654101484 -0.00591797621 -4.46472703619 -0.001 0.000 0.000 C 0.43371721952 -0.00363389350 -3.13225443930 0.001 0.000 0.000 S -6.53329279136 0.00637481657 -0.11611178087 0.000 -0.000 -0.000 N 2.00981687167 0.00259443239 -0.00000686048 0.000 -0.001 0.000 C 2.67119656792 1.17263645248 0.00045766926 0.002 0.000 0.000 C 4.06129317470 1.20536051565 0.00241240325 -0.014 -0.025 -0.000 C 4.76783866331 0.00148799420 0.00346798881 -0.005 -0.005 -0.000 C 4.05723810074 -1.20352939940 0.00211502115 -0.085 0.147 -0.000 C 2.67108506586 -1.17139122066 0.00026591651 0.010 -0.001 0.000 C 1.82209539371 2.39842937406 -0.00175320633 -0.001 -0.002 0.000 C 2.33938959521 3.68993217240 -0.00584554905 0.030 0.005 -0.000 C 1.45736908622 4.77231118002 -0.00917967851 0.001 0.009 -0.000 C 0.08658913130 4.53522926787 -0.00833235387 0.010 -0.013 0.000 C -0.35359617412 3.21325694137 -0.00400174376 0.013 0.004 -0.000 N 0.49290585413 2.18198449515 -0.00068475564 -0.001 0.000 -0.000 S 6.56718562933 -0.11349126889 0.00673479967 0.000 0.000 0.000 C 1.82142022278 -2.39594383179 -0.00206827421 -0.006 0.009 0.000 C 2.33969079820 -3.68709653410 -0.00625612120 0.186 -0.030 -0.000 C 1.45789786198 -4.76953179608 -0.00945089783 0.004 -0.049 -0.000 C 0.08684213972 -4.53272927032 -0.00840538011 0.069 0.089 0.000 C -0.35393854068 -3.21111942258 -0.00398541364 0.079 -0.023 -0.000 N 0.49225266031 -2.17934076887 -0.00084210065 -0.004 -0.002 -0.000 H 1.83694111827 5.77332096953 -0.01265611066 -0.009 -0.025 0.000 H -0.61802819388 5.33967450634 -0.01131742088 -0.036 0.041 -0.000 H 3.39175422949 3.87200638269 -0.00704552340 -0.095 -0.016 0.000 H -1.39787683933 2.98334799634 -0.00369736757 -0.040 -0.009 0.000 H 1.83794742242 -5.77033326187 -0.01295832570 -0.049 0.139 0.000 H -0.61749414542 -5.33746053721 -0.01121572048 -0.237 -0.274 -0.001 H -1.39833026435 -2.98175334118 -0.00345676225 -0.253 0.059 0.000 H 3.39230213722 -3.86796714602 -0.00754158092 -0.599 0.098 0.001 H 4.58301895157 2.13678100538 0.00314824260 0.044 0.080 0.000 H 4.58784714512 -2.12983634010 0.00211631073 0.268 -0.477 0.000 H -1.68997263563 -0.00719388386 -5.74925805817 -0.002 -0.000 -0.005 H 0.75224758084 -0.00860493512 -5.25016290812 0.001 0.000 -0.001 H -3.29620044300 -0.00255800648 -3.88456579214 -0.007 0.000 -0.001 H 1.47161249279 -0.00457826661 -2.87685200854 -0.004 -0.000 -0.001 H -1.69176120521 -0.00597000955 5.75026973076 -0.001 -0.000 0.003 H 0.75025791005 -0.00892914887 5.25161119224 0.002 -0.000 0.003 H 1.46975366817 -0.00523069331 2.87805400798 -0.001 -0.000 0.000 H -3.29750276746 -0.00099200484 3.88584245085 -0.002 0.000 0.000 H -4.55513299541 0.00377930937 -2.13473279421 0.005 0.000 0.009 H -4.55107479454 0.00501307822 2.13844314827 0.002 0.000 -0.004 H -6.83436893102 0.00806057203 1.19721860356 0.000 0.000 -0.000 H 6.86748209639 1.20005966818 0.00372860376 0.001 -0.000 -0.000 61 Mode 176: freq=3451.88 N -0.44003451495 -0.00038510790 2.12369783068 -0.000 0.000 -0.000 C -1.76594470239 0.00039861437 2.37754210613 -0.000 0.000 -0.000 C -2.24923313135 -0.00145267054 3.67997125809 0.001 -0.000 -0.000 C -1.33887502024 -0.00450793845 4.73956848945 -0.001 -0.000 0.002 C 0.02462671625 -0.00591801736 4.46614405978 0.004 -0.000 0.004 C 0.43187566201 -0.00376957955 3.13352499014 0.003 0.000 -0.001 C -2.63984642995 0.00218980399 1.17162612704 -0.000 -0.000 -0.000 N -1.98513620489 0.00132140951 0.00153900685 -0.000 -0.000 0.000 C -2.63911589169 0.00167522827 -1.17277445342 -0.000 -0.000 0.000 C -4.02452897564 0.00329996303 -1.20791476641 0.001 -0.000 0.002 C -4.73391255267 0.00451580118 -0.00020876193 0.000 -0.000 0.000 C -4.02924140493 0.00399189729 1.20660077672 0.001 -0.000 -0.003 Co 0.00000000000 0.00000000000 0.00000000000 -0.000 -0.000 -0.000 N -0.43839318333 -0.00054206762 -2.12229806799 -0.000 0.000 0.000 C -1.76408906064 -0.00030645034 -2.37697009192 -0.000 0.000 0.000 C -2.24773885821 -0.00257631963 -3.67934971086 0.000 -0.000 0.000 C -1.33713102227 -0.00526459193 -4.73855802198 -0.001 -0.000 -0.002 C 0.02654101484 -0.00591797621 -4.46472703619 0.003 -0.000 -0.003 C 0.43371721952 -0.00363389350 -3.13225443930 0.002 0.000 0.001 S -6.53329279136 0.00637481657 -0.11611178087 -0.000 -0.000 -0.000 N 2.00981687167 0.00259443239 -0.00000686048 0.000 0.001 -0.000 C 2.67119656792 1.17263645248 0.00045766926 0.005 -0.000 0.000 C 4.06129317470 1.20536051565 0.00241240325 -0.049 -0.086 -0.000 C 4.76783866331 0.00148799420 0.00346798881 -0.002 0.005 -0.000 C 4.05723810074 -1.20352939940 0.00211502115 0.014 -0.024 0.000 C 2.67108506586 -1.17139122066 0.00026591651 -0.001 0.000 -0.000 C 1.82209539371 2.39842937406 -0.00175320633 0.002 -0.002 0.000 C 2.33938959521 3.68993217240 -0.00584554905 0.005 -0.004 0.000 C 1.45736908622 4.77231118002 -0.00917967851 0.045 0.088 -0.000 C 0.08658913130 4.53522926787 -0.00833235387 -0.146 0.169 -0.001 C -0.35359617412 3.21325694137 -0.00400174376 -0.123 -0.040 0.000 N 0.49290585413 2.18198449515 -0.00068475564 0.003 -0.003 0.000 S 6.56718562933 -0.11349126889 0.00673479967 0.000 -0.000 0.000 C 1.82142022278 -2.39594383179 -0.00206827421 -0.000 -0.001 -0.000 C 2.33969079820 -3.68709653410 -0.00625612120 -0.007 -0.000 0.000 C 1.45789786198 -4.76953179608 -0.00945089783 -0.012 0.026 0.000 C 0.08684213972 -4.53272927032 -0.00840538011 0.038 0.044 0.000 C -0.35393854068 -3.21111942258 -0.00398541364 0.032 -0.010 -0.000 N 0.49225266031 -2.17934076887 -0.00084210065 -0.001 -0.001 -0.000 H 1.83694111827 5.77332096953 -0.01265611066 -0.109 -0.278 0.001 H -0.61802819388 5.33967450634 -0.01131742088 0.462 -0.530 0.002 H 3.39175422949 3.87200638269 -0.00704552340 -0.002 -0.000 0.000 H -1.39787683933 2.98334799634 -0.00369736757 0.387 0.091 -0.000 H 1.83794742242 -5.77033326187 -0.01295832570 0.031 -0.081 -0.000 H -0.61749414542 -5.33746053721 -0.01121572048 -0.119 -0.137 -0.000 H -1.39833026435 -2.98175334118 -0.00345676225 -0.099 0.023 0.000 H 3.39230213722 -3.86796714602 -0.00754158092 0.021 -0.003 -0.000 H 4.58301895157 2.13678100538 0.00314824260 0.156 0.284 0.000 H 4.58784714512 -2.12983634010 0.00211631073 -0.044 0.079 0.000 H -1.68997263563 -0.00719388386 -5.74925805817 0.002 0.000 0.005 H 0.75224758084 -0.00860493512 -5.25016290812 -0.008 0.000 0.009 H -3.29620044300 -0.00255800648 -3.88456579214 -0.000 0.000 -0.000 H 1.47161249279 -0.00457826661 -2.87685200854 -0.007 -0.000 -0.002 H -1.69176120521 -0.00597000955 5.75026973076 0.002 0.000 -0.005 H 0.75025791005 -0.00892914887 5.25161119224 -0.011 0.000 -0.012 H 1.46975366817 -0.00523069331 2.87805400798 -0.010 -0.000 0.003 H -3.29750276746 -0.00099200484 3.88584245085 -0.005 0.000 0.001 H -4.55513299541 0.00377930937 -2.13473279421 -0.004 0.000 -0.007 H -4.55107479454 0.00501307822 2.13844314827 -0.005 0.000 0.008 H -6.83436893102 0.00806057203 1.19721860356 -0.000 0.000 0.000 H 6.86748209639 1.20005966818 0.00372860376 0.000 0.001 -0.000 61 Mode 177: freq=3452.32 N -0.44003451495 -0.00038510790 2.12369783068 0.000 0.000 0.000 C -1.76594470239 0.00039861437 2.37754210613 0.000 0.000 -0.000 C -2.24923313135 -0.00145267054 3.67997125809 -0.004 -0.000 0.001 C -1.33887502024 -0.00450793845 4.73956848945 0.002 0.000 -0.004 C 0.02462671625 -0.00591801736 4.46614405978 -0.009 0.000 -0.010 C 0.43187566201 -0.00376957955 3.13352499014 -0.008 0.000 0.003 C -2.63984642995 0.00218980399 1.17162612704 0.000 -0.000 0.000 N -1.98513620489 0.00132140951 0.00153900685 0.000 -0.000 -0.000 C -2.63911589169 0.00167522827 -1.17277445342 0.000 -0.000 -0.000 C -4.02452897564 0.00329996303 -1.20791476641 -0.003 0.000 -0.004 C -4.73391255267 0.00451580118 -0.00020876193 -0.000 -0.000 -0.000 C -4.02924140493 0.00399189729 1.20660077672 -0.004 0.000 0.006 Co 0.00000000000 0.00000000000 0.00000000000 0.000 -0.000 0.000 N -0.43839318333 -0.00054206762 -2.12229806799 0.000 0.000 -0.000 C -1.76408906064 -0.00030645034 -2.37697009192 0.000 0.000 -0.000 C -2.24773885821 -0.00257631963 -3.67934971086 -0.000 -0.000 -0.000 C -1.33713102227 -0.00526459193 -4.73855802198 0.002 0.000 0.003 C 0.02654101484 -0.00591797621 -4.46472703619 -0.006 0.000 0.006 C 0.43371721952 -0.00363389350 -3.13225443930 -0.005 0.000 -0.002 S -6.53329279136 0.00637481657 -0.11611178087 0.000 -0.000 0.000 N 2.00981687167 0.00259443239 -0.00000686048 -0.000 0.001 0.000 C 2.67119656792 1.17263645248 0.00045766926 -0.002 -0.000 -0.000 C 4.06129317470 1.20536051565 0.00241240325 0.014 0.025 0.000 C 4.76783866331 0.00148799420 0.00346798881 0.003 0.003 0.000 C 4.05723810074 -1.20352939940 0.00211502115 0.056 -0.097 0.000 C 2.67108506586 -1.17139122066 0.00026591651 -0.006 0.000 -0.000 C 1.82209539371 2.39842937406 -0.00175320633 -0.000 0.001 -0.000 C 2.33938959521 3.68993217240 -0.00584554905 -0.007 0.000 0.000 C 1.45736908622 4.77231118002 -0.00917967851 -0.012 -0.025 0.000 C 0.08658913130 4.53522926787 -0.00833235387 0.037 -0.043 0.000 C -0.35359617412 3.21325694137 -0.00400174376 0.032 0.010 -0.000 N 0.49290585413 2.18198449515 -0.00068475564 -0.001 0.001 -0.000 S 6.56718562933 -0.11349126889 0.00673479967 -0.000 -0.000 -0.000 C 1.82142022278 -2.39594383179 -0.00206827421 -0.001 -0.005 -0.000 C 2.33969079820 -3.68709653410 -0.00625612120 -0.050 0.003 0.000 C 1.45789786198 -4.76953179608 -0.00945089783 -0.047 0.101 0.000 C 0.08684213972 -4.53272927032 -0.00840538011 0.138 0.159 0.001 C -0.35393854068 -3.21111942258 -0.00398541364 0.115 -0.037 -0.000 N 0.49225266031 -2.17934076887 -0.00084210065 -0.003 -0.003 -0.000 H 1.83694111827 5.77332096953 -0.01265611066 0.030 0.077 -0.000 H -0.61802819388 5.33967450634 -0.01131742088 -0.118 0.135 -0.001 H 3.39175422949 3.87200638269 -0.00704552340 0.019 0.003 -0.000 H -1.39787683933 2.98334799634 -0.00369736757 -0.099 -0.023 0.000 H 1.83794742242 -5.77033326187 -0.01295832570 0.123 -0.316 -0.001 H -0.61749414542 -5.33746053721 -0.01121572048 -0.434 -0.498 -0.002 H -1.39833026435 -2.98175334118 -0.00345676225 -0.363 0.086 0.000 H 3.39230213722 -3.86796714602 -0.00754158092 0.147 -0.024 -0.000 H 4.58301895157 2.13678100538 0.00314824260 -0.044 -0.080 -0.000 H 4.58784714512 -2.12983634010 0.00211631073 -0.177 0.316 0.000 H -1.68997263563 -0.00719388386 -5.74925805817 -0.004 -0.000 -0.011 H 0.75224758084 -0.00860493512 -5.25016290812 0.018 -0.000 -0.019 H -3.29620044300 -0.00255800648 -3.88456579214 0.001 0.000 0.000 H 1.47161249279 -0.00457826661 -2.87685200854 0.015 -0.000 0.004 H -1.69176120521 -0.00597000955 5.75026973076 -0.004 -0.000 0.012 H 0.75025791005 -0.00892914887 5.25161119224 0.028 -0.000 0.030 H 1.46975366817 -0.00523069331 2.87805400798 0.027 -0.000 -0.007 H -3.29750276746 -0.00099200484 3.88584245085 0.013 0.000 -0.002 H -4.55513299541 0.00377930937 -2.13473279421 0.008 0.000 0.014 H -4.55107479454 0.00501307822 2.13844314827 0.011 -0.000 -0.020 H -6.83436893102 0.00806057203 1.19721860356 0.000 0.000 -0.000 H 6.86748209639 1.20005966818 0.00372860376 -0.000 0.000 0.000 61 Mode 178: freq=3453.00 N -0.44003451495 -0.00038510790 2.12369783068 -0.004 0.000 -0.003 C -1.76594470239 0.00039861437 2.37754210613 -0.003 -0.000 0.002 C -2.24923313135 -0.00145267054 3.67997125809 0.065 -0.000 -0.016 C -1.33887502024 -0.00450793845 4.73956848945 -0.031 -0.000 0.050 C 0.02462671625 -0.00591801736 4.46614405978 0.131 -0.001 0.150 C 0.43187566201 -0.00376957955 3.13352499014 0.149 -0.000 -0.048 C -2.63984642995 0.00218980399 1.17162612704 -0.005 0.000 -0.001 N -1.98513620489 0.00132140951 0.00153900685 -0.000 0.000 0.001 C -2.63911589169 0.00167522827 -1.17277445342 0.001 -0.000 -0.000 C -4.02452897564 0.00329996303 -1.20791476641 -0.016 0.000 -0.027 C -4.73391255267 0.00451580118 -0.00020876193 0.002 0.000 0.005 C -4.02924140493 0.00399189729 1.20660077672 0.052 -0.000 -0.091 Co 0.00000000000 0.00000000000 0.00000000000 0.000 -0.000 -0.000 N -0.43839318333 -0.00054206762 -2.12229806799 0.001 -0.000 -0.001 C -1.76408906064 -0.00030645034 -2.37697009192 0.001 -0.000 0.000 C -2.24773885821 -0.00257631963 -3.67934971086 -0.011 -0.000 -0.003 C -1.33713102227 -0.00526459193 -4.73855802198 0.010 0.000 0.019 C 0.02654101484 -0.00591797621 -4.46472703619 -0.040 0.000 0.046 C 0.43371721952 -0.00363389350 -3.13225443930 -0.044 0.000 -0.014 S -6.53329279136 0.00637481657 -0.11611178087 -0.000 0.000 -0.000 N 2.00981687167 0.00259443239 -0.00000686048 -0.000 0.000 -0.000 C 2.67119656792 1.17263645248 0.00045766926 -0.000 -0.000 -0.000 C 4.06129317470 1.20536051565 0.00241240325 0.001 0.002 0.000 C 4.76783866331 0.00148799420 0.00346798881 0.000 0.000 -0.000 C 4.05723810074 -1.20352939940 0.00211502115 0.002 -0.004 0.000 C 2.67108506586 -1.17139122066 0.00026591651 -0.000 0.000 -0.000 C 1.82209539371 2.39842937406 -0.00175320633 -0.000 0.000 0.000 C 2.33938959521 3.68993217240 -0.00584554905 -0.000 0.000 -0.000 C 1.45736908622 4.77231118002 -0.00917967851 -0.001 -0.003 0.000 C 0.08658913130 4.53522926787 -0.00833235387 0.004 -0.005 0.000 C -0.35359617412 3.21325694137 -0.00400174376 0.004 0.001 0.000 N 0.49290585413 2.18198449515 -0.00068475564 -0.000 0.000 0.000 S 6.56718562933 -0.11349126889 0.00673479967 -0.000 -0.000 -0.000 C 1.82142022278 -2.39594383179 -0.00206827421 -0.000 -0.000 0.000 C 2.33969079820 -3.68709653410 -0.00625612120 -0.002 0.000 -0.000 C 1.45789786198 -4.76953179608 -0.00945089783 -0.002 0.004 0.000 C 0.08684213972 -4.53272927032 -0.00840538011 0.006 0.007 0.000 C -0.35393854068 -3.21111942258 -0.00398541364 0.006 -0.002 0.000 N 0.49225266031 -2.17934076887 -0.00084210065 -0.000 -0.000 0.000 H 1.83694111827 5.77332096953 -0.01265611066 0.003 0.008 -0.000 H -0.61802819388 5.33967450634 -0.01131742088 -0.014 0.016 -0.000 H 3.39175422949 3.87200638269 -0.00704552340 0.000 0.000 0.000 H -1.39787683933 2.98334799634 -0.00369736757 -0.013 -0.003 -0.000 H 1.83794742242 -5.77033326187 -0.01295832570 0.005 -0.013 -0.000 H -0.61749414542 -5.33746053721 -0.01121572048 -0.018 -0.021 -0.000 H -1.39833026435 -2.98175334118 -0.00345676225 -0.017 0.004 -0.000 H 3.39230213722 -3.86796714602 -0.00754158092 0.005 -0.001 0.000 H 4.58301895157 2.13678100538 0.00314824260 -0.004 -0.008 0.000 H 4.58784714512 -2.12983634010 0.00211631073 -0.007 0.012 0.000 H -1.68997263563 -0.00719388386 -5.74925805817 -0.022 -0.000 -0.061 H 0.75224758084 -0.00860493512 -5.25016290812 0.130 -0.000 -0.142 H -3.29620044300 -0.00255800648 -3.88456579214 0.040 -0.000 0.007 H 1.47161249279 -0.00457826661 -2.87685200854 0.141 -0.000 0.037 H -1.69176120521 -0.00597000955 5.75026973076 0.060 0.000 -0.162 H 0.75025791005 -0.00892914887 5.25161119224 -0.424 0.002 -0.463 H 1.46975366817 -0.00523069331 2.87805400798 -0.473 0.001 0.123 H -3.29750276746 -0.00099200484 3.88584245085 -0.223 0.000 0.041 H -4.55513299541 0.00377930937 -2.13473279421 0.050 -0.000 0.090 H -4.55107479454 0.00501307822 2.13844314827 -0.165 0.000 0.300 H -6.83436893102 0.00806057203 1.19721860356 -0.000 -0.000 0.001 H 6.86748209639 1.20005966818 0.00372860376 -0.000 -0.000 0.000 61 Mode 179: freq=3453.40 N -0.44003451495 -0.00038510790 2.12369783068 -0.001 0.000 -0.001 C -1.76594470239 0.00039861437 2.37754210613 -0.001 0.000 0.000 C -2.24923313135 -0.00145267054 3.67997125809 0.015 -0.000 -0.004 C -1.33887502024 -0.00450793845 4.73956848945 -0.010 -0.000 0.017 C 0.02462671625 -0.00591801736 4.46614405978 0.039 -0.000 0.044 C 0.43187566201 -0.00376957955 3.13352499014 0.044 -0.000 -0.014 C -2.63984642995 0.00218980399 1.17162612704 -0.002 0.000 -0.000 N -1.98513620489 0.00132140951 0.00153900685 -0.001 -0.000 -0.001 C -2.63911589169 0.00167522827 -1.17277445342 -0.006 0.000 -0.000 C -4.02452897564 0.00329996303 -1.20791476641 0.054 -0.000 0.092 C -4.73391255267 0.00451580118 -0.00020876193 0.003 -0.000 -0.003 C -4.02924140493 0.00399189729 1.20660077672 0.016 -0.000 -0.028 Co 0.00000000000 0.00000000000 0.00000000000 0.000 -0.000 0.000 N -0.43839318333 -0.00054206762 -2.12229806799 -0.004 0.000 0.003 C -1.76408906064 -0.00030645034 -2.37697009192 -0.003 -0.000 0.001 C -2.24773885821 -0.00257631963 -3.67934971086 0.020 0.000 0.008 C -1.33713102227 -0.00526459193 -4.73855802198 -0.036 -0.000 -0.070 C 0.02654101484 -0.00591797621 -4.46472703619 0.135 -0.000 -0.152 C 0.43371721952 -0.00363389350 -3.13225443930 0.149 -0.000 0.049 S -6.53329279136 0.00637481657 -0.11611178087 -0.000 0.000 0.000 N 2.00981687167 0.00259443239 -0.00000686048 -0.000 0.000 0.000 C 2.67119656792 1.17263645248 0.00045766926 -0.000 0.000 0.000 C 4.06129317470 1.20536051565 0.00241240325 0.002 0.003 -0.000 C 4.76783866331 0.00148799420 0.00346798881 0.000 0.000 0.000 C 4.05723810074 -1.20352939940 0.00211502115 0.002 -0.004 -0.000 C 2.67108506586 -1.17139122066 0.00026591651 -0.000 0.000 0.000 C 1.82209539371 2.39842937406 -0.00175320633 -0.000 0.000 -0.000 C 2.33938959521 3.68993217240 -0.00584554905 -0.000 0.000 0.000 C 1.45736908622 4.77231118002 -0.00917967851 -0.002 -0.003 0.000 C 0.08658913130 4.53522926787 -0.00833235387 0.005 -0.006 0.000 C -0.35359617412 3.21325694137 -0.00400174376 0.006 0.002 -0.000 N 0.49290585413 2.18198449515 -0.00068475564 -0.000 -0.000 -0.000 S 6.56718562933 -0.11349126889 0.00673479967 -0.000 0.000 0.000 C 1.82142022278 -2.39594383179 -0.00206827421 -0.000 -0.000 -0.000 C 2.33969079820 -3.68709653410 -0.00625612120 -0.002 0.000 0.000 C 1.45789786198 -4.76953179608 -0.00945089783 -0.002 0.004 0.000 C 0.08684213972 -4.53272927032 -0.00840538011 0.007 0.008 0.000 C -0.35393854068 -3.21111942258 -0.00398541364 0.007 -0.002 -0.000 N 0.49225266031 -2.17934076887 -0.00084210065 -0.000 0.000 -0.000 H 1.83694111827 5.77332096953 -0.01265611066 0.004 0.010 -0.000 H -0.61802819388 5.33967450634 -0.01131742088 -0.017 0.020 -0.000 H 3.39175422949 3.87200638269 -0.00704552340 0.000 -0.000 -0.000 H -1.39787683933 2.98334799634 -0.00369736757 -0.018 -0.004 0.000 H 1.83794742242 -5.77033326187 -0.01295832570 0.005 -0.014 -0.000 H -0.61749414542 -5.33746053721 -0.01121572048 -0.021 -0.024 -0.000 H -1.39833026435 -2.98175334118 -0.00345676225 -0.021 0.005 0.000 H 3.39230213722 -3.86796714602 -0.00754158092 0.005 -0.001 -0.000 H 4.58301895157 2.13678100538 0.00314824260 -0.005 -0.010 -0.000 H 4.58784714512 -2.12983634010 0.00211631073 -0.007 0.012 -0.000 H -1.68997263563 -0.00719388386 -5.74925805817 0.080 0.000 0.222 H 0.75224758084 -0.00860493512 -5.25016290812 -0.432 0.002 0.471 H -3.29620044300 -0.00255800648 -3.88456579214 -0.078 0.000 -0.014 H 1.47161249279 -0.00457826661 -2.87685200854 -0.475 0.000 -0.124 H -1.69176120521 -0.00597000955 5.75026973076 0.020 0.000 -0.054 H 0.75025791005 -0.00892914887 5.25161119224 -0.126 0.001 -0.137 H 1.46975366817 -0.00523069331 2.87805400798 -0.141 0.000 0.037 H -3.29750276746 -0.00099200484 3.88584245085 -0.051 0.000 0.010 H -4.55513299541 0.00377930937 -2.13473279421 -0.170 0.000 -0.304 H -4.55107479454 0.00501307822 2.13844314827 -0.051 0.000 0.092 H -6.83436893102 0.00806057203 1.19721860356 -0.000 -0.000 -0.000 H 6.86748209639 1.20005966818 0.00372860376 -0.000 -0.000 -0.000 61 Mode 180: freq=3459.28 N -0.44003451495 -0.00038510790 2.12369783068 0.000 -0.000 0.002 C -1.76594470239 0.00039861437 2.37754210613 -0.001 -0.000 0.011 C -2.24923313135 -0.00145267054 3.67997125809 0.209 -0.000 -0.037 C -1.33887502024 -0.00450793845 4.73956848945 0.028 0.000 -0.093 C 0.02462671625 -0.00591801736 4.46614405978 -0.062 0.000 -0.065 C 0.43187566201 -0.00376957955 3.13352499014 -0.058 0.000 0.020 C -2.63984642995 0.00218980399 1.17162612704 -0.006 0.000 -0.001 N -1.98513620489 0.00132140951 0.00153900685 -0.001 -0.000 0.001 C -2.63911589169 0.00167522827 -1.17277445342 0.000 -0.000 -0.000 C -4.02452897564 0.00329996303 -1.20791476641 -0.009 0.000 -0.016 C -4.73391255267 0.00451580118 -0.00020876193 0.003 -0.000 0.006 C -4.02924140493 0.00399189729 1.20660077672 0.072 -0.000 -0.127 Co 0.00000000000 0.00000000000 0.00000000000 -0.000 0.000 0.000 N -0.43839318333 -0.00054206762 -2.12229806799 0.000 0.000 0.000 C -1.76408906064 -0.00030645034 -2.37697009192 0.000 0.000 0.001 C -2.24773885821 -0.00257631963 -3.67934971086 -0.026 0.000 -0.005 C -1.33713102227 -0.00526459193 -4.73855802198 -0.003 -0.000 -0.011 C 0.02654101484 -0.00591797621 -4.46472703619 0.007 -0.000 -0.007 C 0.43371721952 -0.00363389350 -3.13225443930 0.006 -0.000 0.002 S -6.53329279136 0.00637481657 -0.11611178087 -0.000 0.000 -0.000 N 2.00981687167 0.00259443239 -0.00000686048 0.000 0.000 0.000 C 2.67119656792 1.17263645248 0.00045766926 -0.000 -0.000 0.000 C 4.06129317470 1.20536051565 0.00241240325 0.000 0.001 -0.000 C 4.76783866331 0.00148799420 0.00346798881 0.000 -0.000 0.000 C 4.05723810074 -1.20352939940 0.00211502115 0.000 -0.000 -0.000 C 2.67108506586 -1.17139122066 0.00026591651 -0.000 0.000 0.000 C 1.82209539371 2.39842937406 -0.00175320633 -0.000 -0.000 -0.000 C 2.33938959521 3.68993217240 -0.00584554905 0.001 0.000 0.000 C 1.45736908622 4.77231118002 -0.00917967851 0.000 0.000 0.000 C 0.08658913130 4.53522926787 -0.00833235387 -0.000 0.000 0.000 C -0.35359617412 3.21325694137 -0.00400174376 -0.000 -0.000 0.000 N 0.49290585413 2.18198449515 -0.00068475564 0.000 0.000 -0.000 S 6.56718562933 -0.11349126889 0.00673479967 0.000 0.000 -0.000 C 1.82142022278 -2.39594383179 -0.00206827421 -0.000 0.000 -0.000 C 2.33969079820 -3.68709653410 -0.00625612120 0.000 -0.000 0.000 C 1.45789786198 -4.76953179608 -0.00945089783 0.000 -0.000 0.000 C 0.08684213972 -4.53272927032 -0.00840538011 -0.000 -0.000 0.000 C -0.35393854068 -3.21111942258 -0.00398541364 -0.000 0.000 0.000 N 0.49225266031 -2.17934076887 -0.00084210065 0.000 -0.000 -0.000 H 1.83694111827 5.77332096953 -0.01265611066 -0.000 -0.001 -0.000 H -0.61802819388 5.33967450634 -0.01131742088 0.000 -0.000 -0.000 H 3.39175422949 3.87200638269 -0.00704552340 -0.003 -0.000 -0.000 H -1.39787683933 2.98334799634 -0.00369736757 0.001 0.000 -0.000 H 1.83794742242 -5.77033326187 -0.01295832570 -0.000 0.000 -0.000 H -0.61749414542 -5.33746053721 -0.01121572048 0.000 0.000 -0.000 H -1.39833026435 -2.98175334118 -0.00345676225 0.001 -0.000 -0.000 H 3.39230213722 -3.86796714602 -0.00754158092 -0.001 0.000 -0.000 H 4.58301895157 2.13678100538 0.00314824260 -0.001 -0.002 -0.000 H 4.58784714512 -2.12983634010 0.00211631073 -0.001 0.001 -0.000 H -1.68997263563 -0.00719388386 -5.74925805817 0.011 0.000 0.033 H 0.75224758084 -0.00860493512 -5.25016290812 -0.021 0.000 0.022 H -3.29620044300 -0.00255800648 -3.88456579214 0.084 -0.000 0.015 H 1.47161249279 -0.00457826661 -2.87685200854 -0.020 0.000 -0.005 H -1.69176120521 -0.00597000955 5.75026973076 -0.096 -0.000 0.277 H 0.75025791005 -0.00892914887 5.25161119224 0.187 -0.001 0.203 H 1.46975366817 -0.00523069331 2.87805400798 0.181 -0.000 -0.047 H -3.29750276746 -0.00099200484 3.88584245085 -0.674 0.000 0.124 H -4.55513299541 0.00377930937 -2.13473279421 0.030 -0.000 0.054 H -4.55107479454 0.00501307822 2.13844314827 -0.231 0.000 0.422 H -6.83436893102 0.00806057203 1.19721860356 -0.001 0.000 0.002 H 6.86748209639 1.20005966818 0.00372860376 -0.000 -0.000 0.000 61 Mode 181: freq=3460.36 N -0.44003451495 -0.00038510790 2.12369783068 0.000 -0.000 0.000 C -1.76594470239 0.00039861437 2.37754210613 -0.000 -0.000 0.001 C -2.24923313135 -0.00145267054 3.67997125809 0.024 -0.000 -0.004 C -1.33887502024 -0.00450793845 4.73956848945 0.003 0.000 -0.010 C 0.02462671625 -0.00591801736 4.46614405978 -0.006 0.000 -0.006 C 0.43187566201 -0.00376957955 3.13352499014 -0.006 0.000 0.002 C -2.63984642995 0.00218980399 1.17162612704 -0.002 0.000 -0.000 N -1.98513620489 0.00132140951 0.00153900685 -0.001 0.000 -0.001 C -2.63911589169 0.00167522827 -1.17277445342 -0.008 0.000 0.001 C -4.02452897564 0.00329996303 -1.20791476641 0.091 -0.000 0.156 C -4.73391255267 0.00451580118 -0.00020876193 0.004 -0.000 -0.006 C -4.02924140493 0.00399189729 1.20660077672 0.011 -0.000 -0.020 Co 0.00000000000 0.00000000000 0.00000000000 -0.000 -0.000 -0.000 N -0.43839318333 -0.00054206762 -2.12229806799 -0.000 -0.000 -0.002 C -1.76408906064 -0.00030645034 -2.37697009192 -0.001 -0.000 -0.010 C -2.24773885821 -0.00257631963 -3.67934971086 0.199 -0.000 0.036 C -1.33713102227 -0.00526459193 -4.73855802198 0.022 0.000 0.080 C 0.02654101484 -0.00591797621 -4.46472703619 -0.046 0.000 0.048 C 0.43371721952 -0.00363389350 -3.13225443930 -0.042 0.000 -0.015 S -6.53329279136 0.00637481657 -0.11611178087 -0.000 0.000 0.000 N 2.00981687167 0.00259443239 -0.00000686048 0.000 -0.000 -0.000 C 2.67119656792 1.17263645248 0.00045766926 -0.000 -0.000 -0.000 C 4.06129317470 1.20536051565 0.00241240325 0.001 0.001 0.000 C 4.76783866331 0.00148799420 0.00346798881 0.000 -0.000 -0.000 C 4.05723810074 -1.20352939940 0.00211502115 0.000 -0.000 0.000 C 2.67108506586 -1.17139122066 0.00026591651 -0.000 0.000 -0.000 C 1.82209539371 2.39842937406 -0.00175320633 -0.000 -0.000 0.000 C 2.33938959521 3.68993217240 -0.00584554905 0.001 0.000 -0.000 C 1.45736908622 4.77231118002 -0.00917967851 0.000 0.000 -0.000 C 0.08658913130 4.53522926787 -0.00833235387 -0.000 0.000 -0.000 C -0.35359617412 3.21325694137 -0.00400174376 -0.000 -0.000 -0.000 N 0.49290585413 2.18198449515 -0.00068475564 0.000 0.000 0.000 S 6.56718562933 -0.11349126889 0.00673479967 -0.000 0.000 0.000 C 1.82142022278 -2.39594383179 -0.00206827421 -0.000 0.000 0.000 C 2.33969079820 -3.68709653410 -0.00625612120 0.000 -0.000 -0.000 C 1.45789786198 -4.76953179608 -0.00945089783 -0.000 -0.000 -0.000 C 0.08684213972 -4.53272927032 -0.00840538011 0.000 0.000 -0.000 C -0.35393854068 -3.21111942258 -0.00398541364 -0.000 0.000 -0.000 N 0.49225266031 -2.17934076887 -0.00084210065 0.000 -0.000 0.000 H 1.83694111827 5.77332096953 -0.01265611066 -0.000 -0.001 0.000 H -0.61802819388 5.33967450634 -0.01131742088 0.000 -0.000 0.000 H 3.39175422949 3.87200638269 -0.00704552340 -0.004 -0.001 0.000 H -1.39787683933 2.98334799634 -0.00369736757 0.001 0.000 0.000 H 1.83794742242 -5.77033326187 -0.01295832570 0.000 -0.000 0.000 H -0.61749414542 -5.33746053721 -0.01121572048 -0.000 -0.000 0.000 H -1.39833026435 -2.98175334118 -0.00345676225 0.000 -0.000 0.000 H 3.39230213722 -3.86796714602 -0.00754158092 -0.002 0.000 0.000 H 4.58301895157 2.13678100538 0.00314824260 -0.002 -0.003 0.000 H 4.58784714512 -2.12983634010 0.00211631073 -0.001 0.002 0.000 H -1.68997263563 -0.00719388386 -5.74925805817 -0.081 -0.000 -0.236 H 0.75224758084 -0.00860493512 -5.25016290812 0.138 -0.001 -0.150 H -3.29620044300 -0.00255800648 -3.88456579214 -0.644 0.000 -0.118 H 1.47161249279 -0.00457826661 -2.87685200854 0.133 -0.000 0.035 H -1.69176120521 -0.00597000955 5.75026973076 -0.010 -0.000 0.030 H 0.75025791005 -0.00892914887 5.25161119224 0.019 -0.000 0.020 H 1.46975366817 -0.00523069331 2.87805400798 0.018 -0.000 -0.005 H -3.29750276746 -0.00099200484 3.88584245085 -0.079 0.000 0.014 H -4.55513299541 0.00377930937 -2.13473279421 -0.287 0.000 -0.515 H -4.55107479454 0.00501307822 2.13844314827 -0.035 0.000 0.064 H -6.83436893102 0.00806057203 1.19721860356 -0.001 -0.000 -0.001 H 6.86748209639 1.20005966818 0.00372860376 -0.000 -0.000 -0.000 61 Mode 182: freq=3463.13 N -0.44003451495 -0.00038510790 2.12369783068 0.000 0.000 -0.000 C -1.76594470239 0.00039861437 2.37754210613 -0.000 0.000 -0.000 C -2.24923313135 -0.00145267054 3.67997125809 -0.001 -0.000 0.000 C -1.33887502024 -0.00450793845 4.73956848945 -0.000 -0.000 0.000 C 0.02462671625 -0.00591801736 4.46614405978 0.000 -0.000 0.000 C 0.43187566201 -0.00376957955 3.13352499014 0.000 -0.000 -0.000 C -2.63984642995 0.00218980399 1.17162612704 0.000 -0.000 0.000 N -1.98513620489 0.00132140951 0.00153900685 0.000 -0.000 0.000 C -2.63911589169 0.00167522827 -1.17277445342 0.000 -0.000 -0.000 C -4.02452897564 0.00329996303 -1.20791476641 -0.000 -0.000 -0.001 C -4.73391255267 0.00451580118 -0.00020876193 -0.000 -0.000 0.000 C -4.02924140493 0.00399189729 1.20660077672 -0.000 0.000 0.001 Co 0.00000000000 0.00000000000 0.00000000000 -0.000 -0.000 0.000 N -0.43839318333 -0.00054206762 -2.12229806799 0.000 0.000 0.000 C -1.76408906064 -0.00030645034 -2.37697009192 -0.000 0.000 0.000 C -2.24773885821 -0.00257631963 -3.67934971086 -0.001 -0.000 -0.000 C -1.33713102227 -0.00526459193 -4.73855802198 -0.000 -0.000 -0.000 C 0.02654101484 -0.00591797621 -4.46472703619 0.000 -0.000 -0.000 C 0.43371721952 -0.00363389350 -3.13225443930 0.000 -0.000 0.000 S -6.53329279136 0.00637481657 -0.11611178087 0.000 0.000 -0.000 N 2.00981687167 0.00259443239 -0.00000686048 -0.001 -0.001 -0.000 C 2.67119656792 1.17263645248 0.00045766926 -0.008 0.002 -0.000 C 4.06129317470 1.20536051565 0.00241240325 0.088 0.155 0.000 C 4.76783866331 0.00148799420 0.00346798881 0.004 -0.008 0.000 C 4.05723810074 -1.20352939940 0.00211502115 -0.010 0.016 -0.000 C 2.67108506586 -1.17139122066 0.00026591651 0.000 0.000 0.000 C 1.82209539371 2.39842937406 -0.00175320633 -0.002 -0.011 0.000 C 2.33938959521 3.68993217240 -0.00584554905 0.212 0.034 -0.000 C 1.45736908622 4.77231118002 -0.00917967851 0.019 0.069 -0.000 C 0.08658913130 4.53522926787 -0.00833235387 -0.030 0.031 -0.000 C -0.35359617412 3.21325694137 -0.00400174376 -0.023 -0.008 0.000 N 0.49290585413 2.18198449515 -0.00068475564 -0.001 -0.001 0.000 S 6.56718562933 -0.11349126889 0.00673479967 -0.000 0.000 -0.000 C 1.82142022278 -2.39594383179 -0.00206827421 0.000 -0.001 -0.000 C 2.33969079820 -3.68709653410 -0.00625612120 -0.024 0.004 0.000 C 1.45789786198 -4.76953179608 -0.00945089783 -0.002 0.008 0.000 C 0.08684213972 -4.53272927032 -0.00840538011 0.003 0.003 0.000 C -0.35393854068 -3.21111942258 -0.00398541364 0.003 -0.001 -0.000 N 0.49225266031 -2.17934076887 -0.00084210065 0.000 -0.000 -0.000 H 1.83694111827 5.77332096953 -0.01265611066 -0.075 -0.201 0.001 H -0.61802819388 5.33967450634 -0.01131742088 0.087 -0.099 0.000 H 3.39175422949 3.87200638269 -0.00704552340 -0.690 -0.109 0.001 H -1.39787683933 2.98334799634 -0.00369736757 0.071 0.017 -0.000 H 1.83794742242 -5.77033326187 -0.01295832570 0.008 -0.022 -0.000 H -0.61749414542 -5.33746053721 -0.01121572048 -0.009 -0.010 -0.000 H -1.39833026435 -2.98175334118 -0.00345676225 -0.008 0.002 0.000 H 3.39230213722 -3.86796714602 -0.00754158092 0.077 -0.012 -0.000 H 4.58301895157 2.13678100538 0.00314824260 -0.282 -0.516 -0.000 H 4.58784714512 -2.12983634010 0.00211631073 0.031 -0.056 -0.000 H -1.68997263563 -0.00719388386 -5.74925805817 0.000 0.000 0.001 H 0.75224758084 -0.00860493512 -5.25016290812 -0.001 0.000 0.001 H -3.29620044300 -0.00255800648 -3.88456579214 0.003 0.000 0.001 H 1.47161249279 -0.00457826661 -2.87685200854 -0.000 0.000 -0.000 H -1.69176120521 -0.00597000955 5.75026973076 0.000 0.000 -0.001 H 0.75025791005 -0.00892914887 5.25161119224 -0.001 0.000 -0.001 H 1.46975366817 -0.00523069331 2.87805400798 -0.000 0.000 0.000 H -3.29750276746 -0.00099200484 3.88584245085 0.003 0.000 -0.001 H -4.55513299541 0.00377930937 -2.13473279421 0.001 0.000 0.002 H -4.55107479454 0.00501307822 2.13844314827 0.001 0.000 -0.002 H -6.83436893102 0.00806057203 1.19721860356 0.000 -0.000 -0.000 H 6.86748209639 1.20005966818 0.00372860376 -0.001 -0.002 0.000 61 Mode 183: freq=3464.87 N -0.44003451495 -0.00038510790 2.12369783068 0.000 -0.000 -0.000 C -1.76594470239 0.00039861437 2.37754210613 -0.000 -0.000 -0.000 C -2.24923313135 -0.00145267054 3.67997125809 -0.001 0.000 0.000 C -1.33887502024 -0.00450793845 4.73956848945 -0.000 0.000 0.000 C 0.02462671625 -0.00591801736 4.46614405978 0.000 0.000 0.000 C 0.43187566201 -0.00376957955 3.13352499014 0.000 0.000 -0.000 C -2.63984642995 0.00218980399 1.17162612704 0.000 0.000 0.000 N -1.98513620489 0.00132140951 0.00153900685 0.000 0.000 0.000 C -2.63911589169 0.00167522827 -1.17277445342 0.000 0.000 -0.000 C -4.02452897564 0.00329996303 -1.20791476641 -0.000 0.000 -0.000 C -4.73391255267 0.00451580118 -0.00020876193 -0.000 0.000 0.000 C -4.02924140493 0.00399189729 1.20660077672 -0.000 0.000 0.000 Co 0.00000000000 0.00000000000 0.00000000000 -0.000 0.000 -0.000 N -0.43839318333 -0.00054206762 -2.12229806799 0.000 -0.000 0.000 C -1.76408906064 -0.00030645034 -2.37697009192 -0.000 -0.000 0.000 C -2.24773885821 -0.00257631963 -3.67934971086 -0.000 0.000 -0.000 C -1.33713102227 -0.00526459193 -4.73855802198 -0.000 -0.000 -0.000 C 0.02654101484 -0.00591797621 -4.46472703619 0.000 0.000 -0.000 C 0.43371721952 -0.00363389350 -3.13225443930 0.000 0.000 0.000 S -6.53329279136 0.00637481657 -0.11611178087 0.000 -0.000 -0.000 N 2.00981687167 0.00259443239 -0.00000686048 -0.001 0.001 -0.000 C 2.67119656792 1.17263645248 0.00045766926 -0.002 0.000 -0.000 C 4.06129317470 1.20536051565 0.00241240325 0.012 0.021 0.000 C 4.76783866331 0.00148799420 0.00346798881 0.005 0.007 0.000 C 4.05723810074 -1.20352939940 0.00211502115 0.103 -0.176 0.000 C 2.67108506586 -1.17139122066 0.00026591651 -0.010 -0.001 -0.000 C 1.82209539371 2.39842937406 -0.00175320633 -0.000 -0.001 0.000 C 2.33938959521 3.68993217240 -0.00584554905 0.021 0.003 -0.000 C 1.45736908622 4.77231118002 -0.00917967851 0.002 0.006 -0.000 C 0.08658913130 4.53522926787 -0.00833235387 -0.003 0.003 -0.000 C -0.35359617412 3.21325694137 -0.00400174376 -0.002 -0.001 0.000 N 0.49290585413 2.18198449515 -0.00068475564 -0.000 -0.000 0.000 S 6.56718562933 -0.11349126889 0.00673479967 -0.001 -0.000 -0.000 C 1.82142022278 -2.39594383179 -0.00206827421 -0.002 0.009 0.000 C 2.33969079820 -3.68709653410 -0.00625612120 0.194 -0.031 -0.000 C 1.45789786198 -4.76953179608 -0.00945089783 0.015 -0.058 -0.000 C 0.08684213972 -4.53272927032 -0.00840538011 -0.023 -0.023 -0.000 C -0.35393854068 -3.21111942258 -0.00398541364 -0.017 0.006 0.000 N 0.49225266031 -2.17934076887 -0.00084210065 -0.001 0.001 0.000 H 1.83694111827 5.77332096953 -0.01265611066 -0.007 -0.018 0.000 H -0.61802819388 5.33967450634 -0.01131742088 0.008 -0.009 0.000 H 3.39175422949 3.87200638269 -0.00704552340 -0.068 -0.011 0.000 H -1.39787683933 2.98334799634 -0.00369736757 0.006 0.001 -0.000 H 1.83794742242 -5.77033326187 -0.01295832570 -0.062 0.168 0.001 H -0.61749414542 -5.33746053721 -0.01121572048 0.064 0.073 0.000 H -1.39833026435 -2.98175334118 -0.00345676225 0.053 -0.012 -0.000 H 3.39230213722 -3.86796714602 -0.00754158092 -0.633 0.099 0.001 H 4.58301895157 2.13678100538 0.00314824260 -0.036 -0.066 -0.000 H 4.58784714512 -2.12983634010 0.00211631073 -0.324 0.585 0.000 H -1.68997263563 -0.00719388386 -5.74925805817 0.000 -0.000 0.001 H 0.75224758084 -0.00860493512 -5.25016290812 -0.001 -0.000 0.001 H -3.29620044300 -0.00255800648 -3.88456579214 0.002 -0.000 0.000 H 1.47161249279 -0.00457826661 -2.87685200854 -0.000 -0.000 -0.000 H -1.69176120521 -0.00597000955 5.75026973076 0.000 -0.000 -0.001 H 0.75025791005 -0.00892914887 5.25161119224 -0.001 -0.000 -0.001 H 1.46975366817 -0.00523069331 2.87805400798 -0.000 -0.000 0.000 H -3.29750276746 -0.00099200484 3.88584245085 0.002 -0.000 -0.000 H -4.55513299541 0.00377930937 -2.13473279421 0.001 -0.000 0.001 H -4.55107479454 0.00501307822 2.13844314827 0.001 -0.000 -0.001 H -6.83436893102 0.00806057203 1.19721860356 0.000 -0.000 -0.000 H 6.86748209639 1.20005966818 0.00372860376 -0.001 0.001 0.000 61 Mode 184: freq=3464.87 N -0.44003451495 -0.00038510790 2.12369783068 0.000 -0.000 -0.000 C -1.76594470239 0.00039861437 2.37754210613 -0.000 -0.000 -0.000 C -2.24923313135 -0.00145267054 3.67997125809 -0.001 0.000 0.000 C -1.33887502024 -0.00450793845 4.73956848945 -0.000 0.000 0.000 C 0.02462671625 -0.00591801736 4.46614405978 0.000 0.000 0.000 C 0.43187566201 -0.00376957955 3.13352499014 0.000 0.000 -0.000 C -2.63984642995 0.00218980399 1.17162612704 0.000 0.000 0.000 N -1.98513620489 0.00132140951 0.00153900685 0.000 0.000 0.000 C -2.63911589169 0.00167522827 -1.17277445342 0.000 0.000 -0.000 C -4.02452897564 0.00329996303 -1.20791476641 -0.000 0.000 -0.000 C -4.73391255267 0.00451580118 -0.00020876193 -0.000 0.000 0.000 C -4.02924140493 0.00399189729 1.20660077672 -0.000 0.000 0.000 Co 0.00000000000 0.00000000000 0.00000000000 -0.000 0.000 -0.000 N -0.43839318333 -0.00054206762 -2.12229806799 0.000 -0.000 0.000 C -1.76408906064 -0.00030645034 -2.37697009192 -0.000 -0.000 0.000 C -2.24773885821 -0.00257631963 -3.67934971086 -0.000 0.000 -0.000 C -1.33713102227 -0.00526459193 -4.73855802198 -0.000 -0.000 -0.000 C 0.02654101484 -0.00591797621 -4.46472703619 0.000 0.000 -0.000 C 0.43371721952 -0.00363389350 -3.13225443930 0.000 0.000 0.000 S -6.53329279136 0.00637481657 -0.11611178087 0.000 -0.000 -0.000 N 2.00981687167 0.00259443239 -0.00000686048 -0.001 0.001 -0.000 C 2.67119656792 1.17263645248 0.00045766926 -0.002 0.000 -0.000 C 4.06129317470 1.20536051565 0.00241240325 0.012 0.021 0.000 C 4.76783866331 0.00148799420 0.00346798881 0.005 0.007 0.000 C 4.05723810074 -1.20352939940 0.00211502115 0.103 -0.176 0.000 C 2.67108506586 -1.17139122066 0.00026591651 -0.010 -0.001 -0.000 C 1.82209539371 2.39842937406 -0.00175320633 -0.000 -0.001 0.000 C 2.33938959521 3.68993217240 -0.00584554905 0.021 0.003 -0.000 C 1.45736908622 4.77231118002 -0.00917967851 0.002 0.006 -0.000 C 0.08658913130 4.53522926787 -0.00833235387 -0.003 0.003 -0.000 C -0.35359617412 3.21325694137 -0.00400174376 -0.002 -0.001 0.000 N 0.49290585413 2.18198449515 -0.00068475564 -0.000 -0.000 0.000 S 6.56718562933 -0.11349126889 0.00673479967 -0.001 -0.000 -0.000 C 1.82142022278 -2.39594383179 -0.00206827421 -0.002 0.009 0.000 C 2.33969079820 -3.68709653410 -0.00625612120 0.194 -0.031 -0.000 C 1.45789786198 -4.76953179608 -0.00945089783 0.015 -0.058 -0.000 C 0.08684213972 -4.53272927032 -0.00840538011 -0.023 -0.023 -0.000 C -0.35393854068 -3.21111942258 -0.00398541364 -0.017 0.006 0.000 N 0.49225266031 -2.17934076887 -0.00084210065 -0.001 0.001 0.000 H 1.83694111827 5.77332096953 -0.01265611066 -0.007 -0.018 0.000 H -0.61802819388 5.33967450634 -0.01131742088 0.008 -0.009 0.000 H 3.39175422949 3.87200638269 -0.00704552340 -0.068 -0.011 0.000 H -1.39787683933 2.98334799634 -0.00369736757 0.006 0.001 -0.000 H 1.83794742242 -5.77033326187 -0.01295832570 -0.062 0.168 0.001 H -0.61749414542 -5.33746053721 -0.01121572048 0.064 0.073 0.000 H -1.39833026435 -2.98175334118 -0.00345676225 0.053 -0.012 -0.000 H 3.39230213722 -3.86796714602 -0.00754158092 -0.633 0.099 0.001 H 4.58301895157 2.13678100538 0.00314824260 -0.036 -0.066 -0.000 H 4.58784714512 -2.12983634010 0.00211631073 -0.324 0.585 0.000 H -1.68997263563 -0.00719388386 -5.74925805817 0.000 -0.000 0.001 H 0.75224758084 -0.00860493512 -5.25016290812 -0.001 -0.000 0.001 H -3.29620044300 -0.00255800648 -3.88456579214 0.002 -0.000 0.000 H 1.47161249279 -0.00457826661 -2.87685200854 -0.000 -0.000 -0.000 H -1.69176120521 -0.00597000955 5.75026973076 0.000 -0.000 -0.001 H 0.75025791005 -0.00892914887 5.25161119224 -0.001 -0.000 -0.001 H 1.46975366817 -0.00523069331 2.87805400798 -0.000 -0.000 0.000 H -3.29750276746 -0.00099200484 3.88584245085 0.002 -0.000 -0.000 H -4.55513299541 0.00377930937 -2.13473279421 0.001 -0.000 0.001 H -4.55107479454 0.00501307822 2.13844314827 0.001 -0.000 -0.001 H -6.83436893102 0.00806057203 1.19721860356 0.000 -0.000 -0.000 H 6.86748209639 1.20005966818 0.00372860376 -0.001 0.001 0.000 v_sim-3.8.0/examples/demo-browser.tar.gz000066400000000000000000004610201370110300500202020ustar00rootroot00000000000000P}/BˎeɎ%8B_oy"2I/ B"I fYЦ{mSճlEr=˿|5k׿6;/A?׿__7|o?Z? 9h9X>^{OO/??.}?h^F|{^_7f}fsZgz׼ /7OcX&7_z9f^}6wM;x9_3y\\çY/*_Y/|>m^\v5]=V5}flϸF\h5߇]#?ޔC+;iw==͸}ErCo$gC,Y4_nX>yZB|y$?[cu}?\~{e5D;n|'ϷtIȶ/߾ˣĽ/vm:=9{ykω(*;Zcw|>s_Y*g?tcX<$mȳQշ3<9NyKˢ?+G|+Qmga^IYX@xc"bVG1[Y#1۱Vf4hge{Ք~5[@ޮ/YKCm/we#yOQ~Vo+n,؂h`+U}-嚁C6BC++lkbռaleǔ]y]rL3Y?S]n!N.R\ycG}r}6vu5~ߎbsrk~S],~/nFpqx5k(amTz-r;XA8sLp|W֗ǮNj??o?g|(k$/MNmON[<#<ONwUmx..Tk,ɟC-|=RTt3w ivo(PWhƾ`v~AlwO5`Zۢ_w!grMӷC3z+7HwRP!.}MrFWB>Nw8Ll x+;Y)_ˣ`M VP{ V>2;XV m>sҶoRbRnHySC)z'ԏkT}~e=5OD\f"5ƴ٣Zyo_m-o&Jc~^C~ :`O_ʇeYQie\֏GF1 "X/]S,Qt /3v(O-,v&Tb{w B% Hnh/Esh+ChdIg,m^\j]~)_V'nכ;tw GNHPջu( ˦?k-<_~o._ ('eM/q, {t:-,֓;Ūv,-߷tYs:ԭޞYNKNF,[޻܆©9~փ(T.KvRk.ݼ 577(ٛ zѢRģ'%Nx3qU)mּ[*q#:}M\K}}A?T<\bC]׳ߟ< kmΓYꂀGv9yJ1Ǻ?S$ g|H/vmbcW/%h =ZnymVk?)۷& /eC]O^eA #117Z/sLʦhnUHNdoƶL<7:5曉g}cW(a ښ݆Ko\VwVr֑ ٝ79Vv5!CD~]:SA?x(ѯKA'ۍV+Ѷb^3tih~YxAMN9O߸U:*3FtC] 5ho{6$&cxmhf c~[MZ&.C*;[q .n9basߒ8r)K..c? (ڧ@OXcϩVT򡾿<>^AD=;β*n{M~Y?RPŻLCg`[!gszT}d왉/U9oὤ;kñj++%;CK]kDRkNPJ{(e0ohA}Q|z[bSqil?kz+[N7yv@]kKެ%4w෕ =ٺC~DgX1œ_PF r}r}{9N m$U*yc ׉2u U-R!ӎ05BSVݸ:tcR#huGj=|,>~oKFF lqʁ h-E&^IkcKON@:x)5uov15&[tM_)@~{Ȏ?V OH[hά@\?64` y\CJ{f07"ÇFG4-ZQ4^lxMZ}<7g+='gQ$Ȃlސ l@m|wv kX#6CwGmHy徱I[{h8ڛZ%{xܔ-2&@ɳF\+op[&R^c ͑U/*\g%6A#eXhi1X|=\_jk)m }ݤֶ彯+?6)< <7_pπahgl?P(#fz9,؃l:O|oZ;reMFm齔M }ܮۃ#a@.0g+-㏵5liy86aRob4}'1ֵ_q&QiOvrvtJ׍7}p!0]&Uz ȷSղYqKHMoQp]VW q: p{yoMq6눽(֨p;(YH12[G;0]Vns ڏ(ACD}%} >#ќ8ǍXF&N'$+ @ym[TOYA볁eKLE4ј>zR7(YBuÄ}S}.2G>$+@mUg^zq^ LBZIC>E/c#.Uk =!}uNC} leE0poϼ> EFgћA^mA<6 92~[_O~CGNÇRD9FV ϗ@WIO Dn/ս/ O?i'ơ* E~?Rߦ!M2)U. 7zF/Czoiΰ<RGFwj8e 0$ͷ?95(>B-U90 fPm|xAۄ =隆J`W?oir2nJi8{U(Rñ@9V?3oT<;|ϰ8eMQ/"r>k zšQ1QdyQh]mp9aJ;Ry)U"< ;WT. Y5*BZ> gV?5fcjOJePbʒD9=ӷC礄JpZA(Սy !O8뇋u,hž^c"'c B;#ȡ Hž̫h rU~*_RPKf!j rnT[$@D~;IE-d2C=wVپXǝAz !uNh O+??8x24$x?]+Rf>"`  B dnFxy`;#ZZܠ^D0yYAw9;a'9mj6wNowg*ýtYQsogl襧Tgq@w(kRhIx+Oq:;Q&+gLŶ6?oޮiof[˸Kg&~6L)VX ,>[0ρi]Ll`NHNs5IrHni݄.f[2:G~}f:rl߉:ny/PPу  0Sn7UYm'M7mxʮ>1U;D'co{H'm|(HyQNQE -Zc/(v>HIcXx-"]Z ̶w>:iqNPfQ^t2[H8746OC/ U5wO_˟2]stV~E_?ӽu).Gdz̸0誨2<&;urtxNo.vܥG'N>|B~[zrNjFw(7"c u^ڷ5dpiZx(JvJ6?C59~X\v WauRJ* >;:Szv?zg/ NlpR> cug`}z,x gAqU y:M6پwVNO*0 m*}^" f>#;5fyV_ZɁy %nׁv3o[8S=MȲ@ 3hsAqyBx&"{sFs 7VELҸrta4?䦻( GR)3>{zP)~_jZ?L>,C/\1x͵_dUr GFjZ7;d^AU#@>xB=HO85耣GRǭeãułXwG0ҡ (i /WNwL Áq=ssaݔ /o~J-{*V{ْT/J*IRSP`˫~gvw.p kFW&@.Ũz#۹~xi$]&ǟ(ٻ4qG^N!hH QPn0,܂? >ZkT#)԰y;Y{H@kݓ֊ :ȇE"jo3τE}pЬ R'(RC!#++zyrQQ&|&<^jBͽ"cp4bCrYD4~fD{]pp0Փ p%INgʤUxSއ[KK~}&v83Vgv3oc~[\]^7D7PY@ic-_t XĪ4c QT7zǩ<|l`}X`W WM)ʂfɃU a3V&_`q{3EdS:S'oI9咲M}lS6OFMD.enT,2sΚw #28_%W* @tayze 3 ̷><scU\Lh Z(4h#)B(K]fP[ jR"5)ҧn rjn#{sKmiɩ&]4ޠܑ!  |TW/G˪Z!kI2zJt>SO0g]%hm'q* "x4p{gP4!=H`Oʽ]!-ׄ/_MT@r5t~M[7Ћ~tsao;HJq?Q̔F=#^ XՅ}(++cHtyNӢRِP%ݏ Yq$ط/ߘBO~2J2tAT:o巧r,hCTᔨuKk'=pW+#V[ܡߞA#r2jpyjC(hH yfIYu "Nۘ˘`=k1" M.+GG/wשR:V|Y:W?__NOa:0-`~7m0*938ZH<ӱ%ldpުZȅe%<s%WηVk_8 f7;W&ظOW},/+n +頗Dmven)𪜙miDl_']׎^3vCe뷚y'I54_ށ8I]⼊h+)Ab)צ>${6mpcO̗;ǭ=cC[g>#֬yͨi}X؆uIy O7my1+Tۭx+bgSs.'YB' KmjAxg'-`Dd|*1i-n5L{G/94}=9& 5]̍Zua"KV4J[Z)`nr?O&fK&a8JWi3{|P/s5mFŠExA퓓yLH9 ,cI$,O_'6X_DMjn#z(U36Ca1;ƶ n$ou#vFv(@qkqJ|ѴNSmit:ƈ|],je& 8ӽr6wd4NiجyŅj^+{|fzWWG-jC}9hUzFi Y;1rn%=Q/9ѕPG\fJ/CYyG],\0ۍRISJ}4==GLStNϒ_pbMqd ֕Ge8֪ ǂ׺z;Miܞ6:/#$~q8m`a/1ۂ=أ.֞0Z?ը)c;cv67IC|m)R|sFd^u*5cãģ5N_tdi`Nk~g> H ~]kyzG2m&%ĤH:{_ĥ4<1h^"b1Խ.{OM{ w4g82]2.7yцi#7JUֆ!8t2VݺY ȭ1)};[ZB< Eޒ5}j)AՓ3#4K=J3??zi*P`Ebaǎv9ވU*SC/GܬYvлvow z^*yHU?Q5ooi'1F!#tg?`39l@F$`ZXpp8ByzK}f^Z|w˹T`Y{L{}K( Bt G g+!7'p"&su[`!/]bejg8Mj1AI nɔ Nbp?8BuӳO:`SitRgG(t, yzq1gXėz6rNÿ44/Э `52b.bɌ4" F& jHMG [>JżM{) Bҟ8F^ .?qjqڇC:AJsÂ2ϙܐ%U}z&c2[n4Xdp'pַ$s,g-{ l7/opZ=j{'( (ʫ$q vve{] ~Y cBጫ.PJ޳AӌehL\諟{n ҟe32m>Ǫ jwj4oRb$C iWDHGO$1=ٛZhj _'o=!~g1Ҕ_vA 3Մ,j=$a) Jyduq۸&NW+?Ʒw++4cxh<0X&JtSf}Jwj_[=bo0{ذr0(ap(sH>cpV>s\9Hnz}.'1PBêd۠j.\娣+j3a=։4\ )O[nz|q϶Cl>l⺭tޚy}_kLO {'b};]jΪ%r(&wzYR'yL)`=\Bn1hFSP=֨#$ڦ`ZUroGkz &~` s$y/ ]zcf o庹6 5E`4AC8yfbc{$ij1"h28% E[\m|v6lX4\WF-+ hbU@-."L`$ Zǭ*ky0!١Wb83XH0bnO2Y+XE=9C'oIP<]JAr"`\gaVC<M`tMarI0Mj=|}LUar)+"$0j'ZƝEA. :'I@#认Cz '}L-84_fF#?Z6SB}l ݜzG f)sE'`%\~/ZgvC`H\ܽL"%LH`l# ~j5#0F"57̿|XOEL?Yl`>wLLlB4k(>9HoA OJR<%R|Fcd6LS}_fє,#gFiN1/Z v6Teeb͖bt}ipQ*ʲx?݅5 }S4hRjCq 4!G3/J? μ[$ZڬiG*Ϗx&ܣ8dpţ3wjr3eKU4@K[覭@8N '_ƃb|')6SűlԆ[a%$D q[Q6)?Ϡ5;0DYGfI1AbqmY y\+FƄ{䦚ALrB /.Oc`6݊w靲Oh>jniX:83Ԫ۳)m{F9>t b5]o {UlyZz1wꡔ+a 58;m?K(q%׵pZ+cNc#3ܣǼ( H߾̿3g|Pi\!i g,?׼w˒oE {2~; lTJ/mцEv: -3̻w}F=[Ɗ6N7/)Ǖ߲}/}qm'`LշOg6^Ľ7B#`/\'F S ~{u# %j9;vl}#r/닿Xzku=wCǫ^9?jaH{/ [A"3c@^&Pci7.ྷwU:b9|Z<* nv(ZYi1,x%(뷙׌9V/9="%l_@dH24vO.Sɥ_4Z_Bl}6y/\kJG{ J|kJt*|9@'} bmg K⩒R;RIv5Ab G fcHUI$#o*mn$›QlJUV wy@ʜEIrJxjU"\Z2wzDPZ_g*{4)35džN'Ջ:o3~(ל}#_vQ<'sQ}_2ɹ0dy?v]IU6S @v4~Ϲ?mo<.6YhFN>Oߖ}sJ3!*uovR Ezw.9)ɼ6;l0\qKx ZZ]{zLU&*j=EܣKAYBB'~]%-׌s"MOYb":L+t"-Y'A p{뽷`EAk#7z2+d{0W-#xU y[5+8ydm`fܠvR$5kFQĿ)%9-|DI oM2ꅮ^@< ϭ=NF(* BdhIHaAۆf[  AXg DՄ&(mr=#x`S<{iq7v>/꧰7Ww :k^T*+2eO3țVy2@ Vsj3%!X5BZϱ3FY8U]jJ1Qٔ)Y~Sl QW[ݕ[  ?N\%E:Ft_ϝ{O[`۫{s=>6\h  UZWv@u(G>"%Hv>-% ","d!h7BRt}nhvURc g;/C'Y5l&wӜG$VA\0֠ 4;s,/1З_M֟|;Mu?qZ9+r&hFiG{[tp B>w*of?#tc0i=)Fpgx,DbNxw2८ɪR{p4HZN)2wo="E.&k5C o=HϠ Utû{͘]ۢӷ:򧾂b 7VZ2 8LHzˇ_(Էg'yW8TYHN#hC8ݭh(x#X[$&WבXl[B/8-ʹP߱ ZֺƷ\Tdv_|-;Jo]?[@FSpWS[q0`*\Ug3zsS?;8<h&h]_87J}f!1lfwv+Gvez;;"*sSlpr҃$𪆨5<{7rǎئdoK3?cܳ̌h01ra6 HЪxk;*X?tHxZ)'?j];^GjGK=@K DG@^4Of0LSGV l@{"wb!{\VWQtT815d~[_I_?^A<d( Js_OO n一'sC]oyA6:Eqڶ|P a]Kd, '|LNSx!6^`]?P5?9cecW@)dzOx 9Phǁ|}3iH;N?rNMwam(RYPVbBu{b0!o)OXV4Ó+eĆא}}5OE\AhXjO=bi,?\yw5p\0xi!ܸ u2JkUţ%*<61f Bv_o񺳩VuyUI:hCwZ) ykZm.)=O7n8 [~yK2Y9Kn#fXܕP_3QrZ(Z?|'.nΦָa][LuG ՓnJr։N#7Sz.@MoT9ՐI c¶3xer׃0dDEUE3lɮ[):U6<)GTG:f'trޓΝ!peVܼ'*\lv8)e7 i3Fnh6 bkQUyoX؀Ni1Hj9ԇn'|KF!)2p,*+T- 쩂!xS#!Ś\+uBM 6EIR(f*Gocql+"y+`@&jQV,#+[Sl zYG6*3ҧA\;SS~7Rd7nO6vFaֺ_A wbfr'_"o;bwѮڱc-mF4p~~N[ oOyNhA+>~ zo M1m??;JýfG ORB(6:iJr#a|?o]6VLrv,EKsPDW'Лbh$ h,2BC-=k.7LŴf#8ڤ_?t֎u!'o3$ª#z|"mX 1re̋$ʯ;56heџ W#");zzۯ(r{UOEٯ`F*"oq>;$\sЩv"s)hD?G Hxގ\RRM(g3#`O*G"LhIj'\cL 9:jwƈD pNQ~j2k,@Z% ym'hG{hYl;*< Y} :Q|h~>jXc? $;GaĄozrrxK!Z#Dze-~m-~e:}L]E^ qtCʅQ^}M7[TKxQoϬ5'@7--v}]TdFz- 1JczJ[u7W}U"NSxjplZ+hFwLH^Uf*Zr5~SdӸ6`-jq m)m*.L"h{}>^$5]#pC&h~N(6j; : [Qs[mC4az,M65q TR|!V30*/)~.\>_ rOzxru6(q]:=^cs4D#p(4,vUgPrدfexmY@WVKf j2Yż]YOᶔ?I3""XJeܞgHD&UvGxrPwo: ,bsh/F:?L)=o1nRdH(y?BJob@P2~k(ɑˇ%D%ky+t=YOX Ek:AU hAp6?'vS8rc;(B5\C @>]U I\Ig;XJ9|T,5i||z5n Ϯ:"eed277)_?#ǪXky!>]A}!lx2tT.xe[0daT`+Dj0p_V_hx @l?9⃤N2<5,sLSB5fI[A">n7 Bmn&rMɯ ǰzm+}`6+gSizFkʻpߐ23^4ȏP^#f]7FT7z X3yb8!M'TE ^I Ar>\,pkJK}\lTdZ5-[?8m d{Əzj}yڃ 7_L+}OYV컐AJ@4S#xȶ`-6%9Gc pOTDV ͷ+NǢ]5L(IfVP~T=7gk|؟ )jK9أ4nLoL3õGAŊr?(c VST8+qvc/tR{r`Q~jFp}FqG}/XtrO3)r {PNٳ? 6 {r27  4HUoLD?.jS'+A' @;_> 3HCw~ǧ{\a]LP}A?k(VUy ԓWǭ{r[]V i=fm/C4r.x!1GE(Wz֗Wi#%W{rE]2sg1Z6 O>Ȕ;U[);ҽvga[f:@ZhBYd Ab.߲< ߮5_3KFʱd3 a#M(fG*g6[J4h[dߕrorq f}zG䏶*R s0dȀ:Z"2L?K.ěfy焀m<ˢ(y6슳pNѴ`@o:6o%27\_JS{0\3=#)gZzy(LD~t%ߵ?JI.w+JM2Nn3wwoF76Hꣃ#4n-~#/aOq[6|$(30U/~T!=&yZm=\lZ'/}JМ%K9 #-fQ 1^Eیs_fa<޵τ@RImP!}kBMﮍDѐ6ΨTjmРF# 'm q^=]{ڈo.r !N>RD2X0mr옞""MwYQɭDC*yR<`s*u.8% B1RY 7JԿgp4RWAȠn#"Db%џ<|4 2$X=ES7L*O ړ?e@Tm)|8h En+/дxg8 ҹa:֨}#/~)|hجZ-ATJLLn!xP`c}^ .=[JbݰíL6x z 9)9!VNR)[+،pg0 'X}%\`(_,/grܝ_uhpp!R&0䢩~{e`ai&?YNeXC]Z݂!+] x$7UʳMs9~ ?Pqio̕䡼Jgn suL6Ϩot>a0ǜ]ZA,:]=̫ԵL!l>TbbוmU=9^nUW5+m?=#@Nsoս4 4>亃o{S*ےC#DflwTxj:e:"Ѿ1] 6YWZh4 +A=?Cm"_X@=#31q(#4WMn.lX߲y#SC? 0?7hԘx lp65XL&c`_v9{C$O7cxP4MjWrˋt.gkQby)hQu;, o~=Gg<e!35\[fjaI>bLĻjIWūn_(G&e7^l #Y$rm02v:|@ ?nޢ|s#[kRG|jׄ[ M' ̖aozt6?a3j4A<( emloedqvu>e$4r]D76W쫷LX&LqDsJ[nN$\*%(aήvwK9_Vcsf3 u5G8 պ i/O5ӏP# 5w *5/Ugv6$\S}и^fCEWP%MR/ }| R,UK{3BՅ.2[O+?)_?s^z]ལfÅs4 "< s`,1ݯ,`^7uoP#߅Kfo{gkb{Vz{Yo؂wcm6[5F q.;&b><~FX@XD!?nKhph@ʙw}} M.7 w`dRcAb;m}5;wz??BҮPȟF- 3]AsLfP?Vsw/uD\ܩG~|ɮܞnְk|cc|p3DOv DP< GX}{Vz.(rA 7Aem@pO6_&x Cv OqO, L fK$Yipo`}*Ëw#4IJ\?uݕF}Ɛ:!z23LghBC-HMGN܎Mu/o`MZ%l@)oј1n֞ 1vqI{[Ǡ/ M-Q,!B.ӺAj!( ⾡c.ZMZmsb? m2ŽÚWaփ>W+5;6FD)ni33"N gf3JB @yΧE95G 5bW^yU^ 8OЀW rC?ҩ4#꬝c#MȏVwe M0[OjT@C&Hҕ=`WA;4zT S:mu6ƈ{9Zb(J _57|݂ߺ{i~ p9crP y>*4i᩾wzvF!jU:dl$mً0W@i߮o{_AxStPyYCk@sce^$hI6R~*-\ K-ރ/7\[ qb)118=?XcR}? @#u(~nocØeŢ8 XEKݿb1HƘ}ޤZ濏E ڪڱ38xPr ;^9{f"yl5$q_?}xmnOO H|]2ߕ#&lr0G~N\ёZ3&KDg YF'Xl8"Wq{E_?BC̲\XrkSFuNX}H<ւB*W^bn03e/10pOki#_ՂW>-;:ʓ#$og?|ӻ޸hwy3{ vb8DT)!Us@slou#a]Ֆ oUZh?K2.t^My!s3~9K=wK|p`uӂ 3 y !1ʈ`%t;Ku wT{gjӂ[9c}f|H†b~o*J6nQߞ QK# OU? 1Pv3D'-֪o|}~D[J)`VoPo՞"U>$ط9Jkef&!%| OcF?hA?ϣo.>c ܟ8lؕhMʈ`[7&c)ŰF4nF|6I*mHvҷru]X޻'#=g;OG=+8+k}!^1$/ 7GNϸI9Wïfd֩h"R.ܻ&"H1]C=.XFoeCϊMow3Qs~NA\2_Z!sa1Qʨ/3=Y`6( ___o?GQY{nuҟᩇ=Zz^# qli۩eKUEbxu=M_GT *su~ķ.PѵUvwyb^͡ny l``VIH3jxnJ; G Iqy M\.BI.U\^i9BMuTg^T̞ǓıVӦ&JL+}{,*yzO%H1Xd3rSAؼ8G\H{ /N vd"(xWHFir\G>cI&N"@ug 2 NHa6鰨lpUG'ִ+pGx9Yp[3̩f{[h`yz(eF@AJCP-mGC)L?}&:Q÷ x\$״S{7FjaYgE,ka|aԼ>[/GݽW0\ @ҽsM U6UPT~yϛuY[LxP$jwDW%NCQ)3Qu?1jJ_>Ɉ]qZ]csaԏ},[G/S5>³Xӓ #nb=YCHC̀QRu#F6M9f]?½YjW|~~] q1i7-lCK4n!=cB/K8R6Qg |/ܐaoX@w}<,߾XI9 o&4'шn+z5bXY~9Ks{#cqAJ 虨Flno ҡf0;$VR 7T~>x|Qsۺ&k,cKA}YT FK(H?ãC(#Gά9 6*U3-fe8ǁ`St朅jPɁ?db9;L.)#Y`'u5pUSTD'C Cő3V5ՀOŕPcyZy+PM_w;I_?/2A}BldclC˛d{W@4rR?221Y=[XfLS;=yǶƌ!{C[HU+8XYG9r49yt@Q\+> |@ٽuXg1\&x5`hxzxoLj TCvk A*3f1[[`ZiOZ"wƜcp8:"(:x_ͽR@',:Iy,nr~:)FCW㿂 s>&]Sz~罔rC϶~LRcwJw6>crNpT1Nx_9ڱAKy `|OZ5RwTnqA H>'*`*s& py&!hRVb’y" jneqdɲ@ό{nu* i FpԻ.ýfaÿIc?LԳ@@!1m5T17Cip |Fw0!G%]}_Y޿ EJ0=8MG ԃ ! moiy+.oٜ%WMoպTA%xkTnttz=Gv!v_ԑ0`^(~^'p0WOpXfHH^X΃G{q R9Jd5u3/ 6jvf ڔYlImS3ۅťBݾ׺$گml $ ֌r S_׸WTș-$SIĚiBEE.!FugI<13U$mv (Y7\#p}$]倍Ϯ*nL?4Cn!n,ml֪L@)\O 򸭠0MiBtQ+ ]>GJ0fG@kLFҧ`VwВm5kr֑ID9=[ϊա*Rseg߿@M)1ϫQ|X `hJ:u#\5:l@ w?;M`\kjjZ"C)RѪd/4g7]3}M7*eހWKi>Agg8jޒy>= Y” ͙9Ma2OG%36VIv_ZPv_^?ut(*l.T>2 gPK}!cK0ytva:KOfyr|!Op{zXoW_3ehv5 \O2!ar$yp6Q^f vGq!Ƚ𷄱$R6Ъ"fǹ{B~RS` DFuar>O7 -;:J>T|\"pŁ E)oY0:nn;V5툻7K{Ok&`o\aAAhIX,WvV[oGy7mAk$ۢS:1,)ِ9GI7|&_4ځWOü?a?kJȴDYnul7A7" D}ӝJr[u =$ir|On>;V9VG6\c[ T7~'qFq(Hؾ"Ƞ[O4%xPB2(\xS #cquCқ?^tFӁ^ј9?J Hӧjq,4gN&MqPStrkM;(iz+(sQ5?` 6i־A;4V f@36lt+wxNtkzS0fZn 5x}<<vs79Yjr~j%.\RZmSU#Q}$;|,1.i^RN˶Y-Bwt*$r"]S}};|`OURVI aUvHwo%pR؅o+M|i=0h/~j+Ǎ^y=47VW/qN~}:,U W)M-o !fFAQ;x;ݬq̮FLFB1f P8$9+|rHiwݚ;t=ڶ[|@Oּ@3_w~׏ޞWU[;[% ۩lޖxOO V.XLnhJu':k9iˢ|[SЅ2@v ][: (؇Vf @ji>8MϘ} I٤l((/<脾|q#^3N{#56mܣj%H΍hVG}D\L_aӾTg 2[ک@f8cp;sA M:l}-}zgG5`ٌi? \1L>S#jf+r6lԻ1%5cL*Ӊ޹v@K)q% o N޴{G59PE1HK']TQ?ᖨ[SK7EA.;Ԇ;U(y:+C@7RFΊF&]8ݬ["fʤ9y@-(.T輼y ?`q[3 (.E.*G(,ǬE3`{fIyeD b[=A?771_{ۋ$ȲDG lIn  jHIo*-!m$(edy{T[3bٺ JS!6&HT ہTӍm-Al,d Ldjr-.Ja3et[̖Q-6Ql s7=o^т .Ubmpz6}zNx{` lG?% ,데Î;WRχÖl7EƊ|̓NHݥy$r[cA@]R2ixٲ@zsY(14j44wH9ؓN'R*W)o)_?ƭ>Ɉn\}xkW+X Z.̃Mm3͆w%`Ӎ5v [;ȉu,t.T:ؓ`xt ~]46܉ȍQN NQI8(t+V^ aX1ۮtދ]kOVz u D̕j <&g۹3x8%Gq TSn%?RJO3V~z;7(Co $LU+i-)`{)OR??ܟYUP?gyYA[C4A2UMPog}۪ CEFgo9|;̻t|܃Ȣ"zj$ds4NF3`]UTnjy[#T^iz@8:zwegMxcdK4GE΍m7$V7^/@JV[ .zcܡgg?eҤUNgS=]\`,Xy&Dټ*gyua>g7F͊H K^ХTnAߟ'HTUˌ"X O4yq?gh7J7Ip cXսGl rGE%P% Ze,}^6}{#)u#2uǔI/:Fslps>pԸ,-HdȞ7W=,M`$ݶ%|-eG9p#myE]}Fby+WDesJ@Fe8RjtZbbku fFYR(At2hSawXq g9mbhw*l8DW'e cW$6rY(z:'F/. _l: Y`rX͵n( VJed/Į @6ϴw"7oCǖV0lӅ5dڸa~n8-!iTɉ !l f¼ T'XEkʩ#Hn@-މfE%_Ztqξ~:P- (B72=qj8'biV4bU6 SˏpݽmtG0h8v6;D;zڂ(] zڽxs+cOBZ6UAUOG%KeazU@ =V?˅zRnTIoLIoY>Y7'.x4VP {~g`>(>e~Cf6 r=k+e%G0}o]c2gnD!Ѧlζ| x=A}'0Y- VŮ\a k/s&_Im:x%8pV"*=P NΛQ3{otwAxyP ߹k| Yަtr~8hֺ{d2qmڄy%n58p#w]pQio d#gnV^ }| Iàj '?_*hK\Z! {)GG I&K-cWX*o1KD qKqLBF˭_[lː`Z/b գL3Ro\vmZ}ׄx짬f^.=N#VKYA[f3_ǦA*2#?j(d !1eRa@CXg30SXKihTzJ0WB]ueƴ`Jڮ u"@ë ٦㚡^?&X K 5fENywU^ vC MV2bhÔj,ѿͪx&>)K$X).Ami[' bCh4gig75|,4*Yh^YQTKP33h :{>%"JmG J^WU8x;Q67' wԕ*@DPEh*FZ)7>( gXSKjVbVx?|#`6>ϊML$hű!l@wl6Sp(ս LQ&֒fHɈ~RPF#7J6%0h_υPM>_uQڸI0=.|t!ȲhљS9qol#m a醹l^1ҿE~=ɳ'M&AF_=A >0OP4fx'ix#Ph ;S*{ /ܜt&&WWkīn~sg&7Q8雹/ۥ}8,,O14/ Hnš!$ojjoUYJ:5ʵs+R]iO7VvdLy!l)sTF6B52 bڕkk F'qlv?6evpu{ 3S>-B`] k"eγ:6Q⼟3g5{gg37j ƒLޗ4mZkp -sb%w߫}An1*[ѩQ,||Xk>߹86'!~N%.%L BィcwDSEa\? ̼AEOf ܆2\W ǀv5d_>{&B~m7oLn?w5ODd{kWVv_m|dnP 5b<ʆLӦb*yRǦ=n +2v_Iv7`cvª{Tד}uf 8haϋ{hֆA* v6!GHXk9G9x6FI ^W9~7@Nۜ 5Nu^[@mo6D[[zϥj] E};_{TPGqfDj>Hv\t{_D}B7)P>o._pQ.MsO╣5nzΈ~viDQO3Ywmra5vW1HՉ"s%EA>E7n $qӹ\ۇ9( (ԩx{OO{6BdPv @O-0I YRlV bkv!~ܬ?҂؝"s}PTsBVn@jt4 $z@ךKp,6i5tNڻ\OuG߇wF%!Lfq%'h㑽) 1~$ow9|׃dMg|=g%FK99or6C܄s9(&#lw;|MBMp2bU(jO;*rsΟ\Y'{d% n sVH{Y-W[r.[nD]'᳢FV]ƨ\:%igt/{žy=Tvkn>a1].3'ml !$ \@4燛C8|)G? @؜~U1,'PI#O(|16~䆈XpS(yFw\y9G3E!W?cJn) 6=-TMW>czCbxEA T6e{Ef?kN& =ҿ-lxNmQ[u~魲=o3zP#Xӛȣ# 1`?rWI,V;>2T~Z{H>RmpD\Oг Y>}̏hTڐ*'Own~L5,[K>%%Z W^P&al)?U}ZD"IE{J̬! 'v~7YO!8Re䯔=y6e~u?O ܽU" nzW/:zV|7}̬Ϡ|i-4,,, lQϦ#tq?k=߃|POAE/_) 3>rĸZż\ȍ23iI5{1キW|; :Nt OL:E̝ŀ$JpNnQKx \mϤ9& D^ iicdꨭt>õ>x~K*o5%W W ?" gVS6WLѣ3b5w1p}:q'mŹ(TnaNoɮ nO5 noj'xÇ*Fs.s88 I"!Js鳧iH(7Q ?[*Q}fS:@嘗0:A o/ʹpN(GǨŹFL(‚uul.vT;'zx ߪaoO6~Mz !:O^k3^Lhk^m'mtO{sa'Xع枲,0Yo pLX֬HTveg5 iA6sӟv$ه;4W꽊1;s4^)n)(d PI}x t'\LԹK չ<#xߑ@|(ƹLq;L.3D07I+*'cTtr#S ;MbLw"mOu^ho-4p{C5)߶ɱ6%la0(Ax74PVQCq޺׸Qo+77ujd(2jYgӌulL\n2ܖaf vK]12 / d[%!P c)o \RBJ[o:$i$@~'0:trBּX\ѫc^TH5x k[ʈM EƜ/߀ _WMƾ 2|,Zd{Y8B|dNfV\u%3d/Ho7z_Yϵp 0o*{L{F@cPwW \n}wtCJi8IPP}:(. kh&2>^ۛe#EBgfH]yGo :̦D}m?)'{?rNɫJzެ[XnaFBP 6} 3újʞe8rd)6>p;q$IІw <^q'oSd lпHhbBή'Yc8raŷQR4nܸ{FбOG_XcUP9Ś]cu7W!13}-}Ā AkO10?R_o3< 避X@[LO.5Ӛ0Z1[#d /)6Q=ZASi Gn8DO.Ѥ8IK؅q_?{2 _;'W LuDڹ F6, 2De(0Siln[fTp{.[ͥ?#D`GU_<|2[G))X)@M.T_ې-~JW OM=`tkz4yl+sT4t(T]?þGd@hwX݄- e ?G[߾NdS>fZϝ_bxWh[us6;˄Q{x˱_BƗDJcᛓRcz?xkA6Q]ck l6jto`·ywdy!B֞꩙h­-cW|fHc{(6oG\>A֎h^ho!F࿦la)o3=f~2 3c 퍙frTvqT/}2xVݖ)IinAm|.ԇ?í\ߖrVh?Fx)I*Y>~0ü4">O G=ڣͨ92l7^4i54'Ӎ$]{s&CYAij >JeD0Up!K'l}Y>goᵭk5Щ E_ $ u c}n*i Jπjv$HKv.B}QAN皵.q 2>w갶)X֊=`^]-D8m4vaa*Hϵ!GaJawD `(72[צ$aY3ɿӄtCj@A? 3c<vؒ5<]$w߈-lDvQ;1wi78XЮg}/~3#j(?܉@V27W?!{2yJȩZu8 \a{”o] 8L;=ƺ̟2Ck^I3h2ö-e{FT,7g;{tJ׌{1#3[/% -*B`##C+Li6} 8S{ }DVLkFpK#|1RkSɀǽ)mQʉ?7gj߸gKxxz17<X)snVw*kkZ_Y]gi 9ܓpI$%6\ʄ? { )'eG18~Xskԣ?9oaQ{H>=&tR 2S ӕ 1lV,˓jSA 52xU.ֆf4ТGMY`` :lqU(^pS]aZg gYN ݣUfR]*=.26.?؄a.fv7S\8f)3k([ڀr!]m0M)ZLLT391},y }+޸}T`fbARܿ ؍A?107DxpO@\mĈVHûvZZxʲ&K/\`]&Wj9ԪzpXK2?]UDف8Pơ؎FJjB؏Q6_MWv}~lzΦ4>,#o3~9;+JfyCij=?)姲0'+?3>'h;_#fyQ?T?3Q"uo٧児p0ArE曛`oEnJ܉guzgBe'b1  ۾f~.[2ķ -iԌz޲/xVQ`Oщϧ d·:~qgł!ܭqcnxP> [@H@O!}Xnvm궻b _m]䃝U:/|{}Lҕ3v@;:23[ntx_2jxq[vzA#VŜ S18 .gzm@~lIt [=$FA?( U<˜?!m?zstӛW ),*:hA#w?ѾL?4:nl(>cwgvpg I…zւ!60ViLlM_ˠ7poO{Eω-q1==4LS֋ɚ;]CtQ %oo^xJ/j'o Pйxo=DOcq>Oz9C[v'?K&EAxZ>(4v/2k.jUoRB+sc b]2 ML UτMзWosCD_~\yJE>x'S qT6 ;gHցZyz'yCq^Jk\RYme?v(>vV8ŠԖrU,gkƖD*B cx /V:v頮}=tT_r)z@"S[F9 H+Pn+~oJ׀\V/_,1hy|V¢XˉR)+/߻ EgE2Po$cց>J-1ղD*NDAXz!HNF{[PL; qBb?+s] nSȥaJsf{T5,YDE-kڼ(l:Kq~@4)f5{X=DF>QmB+>h.Ȳ="6wK(J0i{nA4AZd:7oO_C ޙ3k,L mԞn̵Yv80j.~g{A-_x{D;5j FVzJ(ynWA0~iW-}9 b:)ҼuΪ>ƣƹDrgF;T#Tx \ÞAfxULm4ncѓVDD {Qy6BR&CyMmS&] ;+ D~oKo ޅm]&$rh $# c%I&AKk7Jt7W2ݾ^N֣OKo^r >x0ŜuF"'nYa}'\ SVsV'&cIz]t NUrQSg`:D&$샇kB$|ht2A֙A`avH> Mڞc}a H@R"{O{6y~cI|@AL!:iq@- ?؟OMN4w“v٬ڇylz3_ 壇 ]En3LS&ixkVj޸ tz/AY42\NgՉN }5mPH;e>ѯvKZP{mr-woi`]z^޻+ *'|3UڐEu!l I?6sC(Uc)kE['$ײw!?FIڈ<%viX9Iܒ<&8^C 1G(K7BM ed ~,M'碯?HlP7{B\DTmNjdF()]q!zcgKuNҴfG^G0-B9}?3Mc &>pSJ;Jp~و m;%@6K-8)JCٗR=0a3J[n( jѝq` 6,NO~׏7(A- z+,yN@ƜI(W׌HM> >!mF9t|Wx/I*D#yoTi~'PmSivDVUl1/2ad1ѡ=SdU:_ :%-k%xMO.~|-o?F@znZ80}?˽`H /7 r$V˞{2SCdlt#%dߧK p  F#c(4p{IqQU&6o濙_<%eZPpεkzbyl{Pl(zp."AD`}*E}ڇ]Ӷ$JH( ~^kTYΰ j]NV=W0vT꡺&I zh;^[&x%q?wC sA.qs}tp0oQpMl@Ì[)6 h7`ž6L 0A?x`m- QHjݧ?* f9=ټWGN 99|d)Ha3P\bh[8 ^681w?> AD@g[#p6fRwz{lE(]~G0Zӕ}k{iA+4߫4Ӽh"ڙѮ}= uCX.ؓ=ۮ[].iU s v{ݴ!4SR.l GBt^-=pFQNI#HD}C05@ZCG_<ɀC ;PZ[}~ôJG_qe -{ֳM>jS Unb*Kچ8zY*\\WEC#SG1X z>;_6?)g|qZ9{.(d +j^~!qy[+ mfˎ^M9%ۊ[&ۇCIR&.`ȳAj%]cGr-*~^G rmֽGx',ѭ?/X5CZj h ['=-Йeq]y R;-c 8Q֏Ai8sb@.kjJ}18l.!2⏪osX:9zlU0 "'l,:}zݻ*.Sh1Q]?>7z>FF;u48 hNn<_gcqvsk t%5//?Hi_% f _oOEo(\ KD~DߛN7gj<`l"*Y{ǂؙQ|kWP+\NuuOV[6 2@[{FRUO+gx4ôvbE82BWVq]o1ec6WN>qo]GnP\Ç-#"M3}oQê0]^ #.59>#݉B^o1:ˎT>L /̸UVrCod~#1orO_3Ĕ.v/)Hp1> J C穷Y7A|4L藁_*g|X7絝^Ij/ A~q>8i] zmFn'~F%;6v6>K 'P2}%m$ӬǑ_oWޝj +>9 +(enq qRd (#i΄`+3Ȕ !z!@hF @5hWlxoښ[E$"^Ю~qP\#cf'[nz?ʩcϋvA(#[ZݬMbu|ĀJStQVШBtdmn40Bto7ڻlhiDo1M"ح$n Fzr Ȱ5ޜ;,*\t'Һ,&*`et&IנzkBI 1b*@[5|oqlEYeI-D^1 >kdX] Q}VIHKk\28>G&SL@佄ê\\16aryCtX~g"%qyDiF@N1Δg _ viCѐFEE~<߄jZ^|b|L/#j:4vU7W)_?6>;zyW/˹f ?;O0Yg$WLByj #j#&?U|R-rwAНVo̴n\h/J&п`![t5n\[ 0G ay'1ǙT3ؓ:ȷES+5jVەϔ*]SI#8:š*$:{v*!k+ݰ66̫fY홱0)?ZJk Rf\x;N)`ߪ1lU)! F9tN?+'GWýȃWXL}kM>Lm6wj[Q6 "[ccR/ЍquƖ&1] 4ZE(,u? RX?sCLkHr g#d:VGBO~cMJўD\?%ɼa;Aה r6:% mIA[i Ψ͡XeE$s#Ɵ 75^h7E YPcRˬ RY}AcU.}bFj`(# G.oifUm;=)Io[0jJPhr`2uN? 5<cT)@.~Vod>-؀H =W9Lsf8. a5o44/9W X%}};)~c~\'߅Wx`^frI4AeÊ_+NqW䧟J~d a:D\X ˙'\mķ۸w,z6Y>wQZ0%dH&}cVA+),v{״ e-7G|s%O6_c_^5thɯn|^\Dωb5ߡ&<)W,ٸUS&pEV&HGƙI ʜ5%}c \thLoxtsܑ7&:l'kD;ߙz\)އ3s_+q~˓sEp:L#z:g/ E_3 Oh|Xdv.jFezO['1Rae^ @kLF} S r|2_!\9d|mtm}qZ%\$3@p `(l.7 )d( Wxw_*4ր ~YI N{S7Y+ ::]O\*-Bh)"8HIhmVi7=-sFV͠ 7pwhS/D𔸠`Gw Tn_Fy..}KZj $aKjZm:B{k5{giO8r5&fpvx_vaX3VQ7*^:4s oq 8EC@y,uoW2q87@&sG+@χxQ(2}h(ФXo\}f } }о2Ā3no\hiInJvBH#·g*?0]}3 CoB@# |yT?]ό|@u@$kB[C/ )]GM#;zi㥟]'gA]v-j% A*3a*o#&:m%l,t+6zl|G#GL?HO?tGHg-oΆlkU"ו4O#Hf]2(Cܟ8ߜ!Fluhޠy#+S-LVYF% |a bsZN-j[ }Q$p/Q 埩M`S{R W5?M-ncl'@'g%7`7p?^Kҝ]a%fP+|r>x ٧/.0odN_$|Cq Ƿ[(7j?g9ר5<;#G C7&B $6tsO$~ BD`ovmݹY- 8FEp8 N_߶ߧ7M|ξ'ۉ/-C<}vNm>)hTxx5#xYs4RLûÝePGu,]vpji2;[ h؀mlqӝ;0<̋4uݨ]4hNZl'Hkeg,LߕCaEe^w~L+wM[ g|0\IN*pGa |ȱhTFraܰ͠tO._N%E%h2G,l7T>ړ0W2V>QBb m-b}~7&CQmԈ7|@$kb0(аëtvvB(b'`ck} ן|Khaf0`[~gEl/0*ZByþEj}tsf2k8v>qè~ֽu4ZKM:p;Z.wivP0ޢaIN홂WxC2?vNѲ7OA ڋj$uA+K|V4' jY7%{RXqhYɓywM*pho!5bo9bjpxV~dxP>rB`3 99sb佫pgriF+9b;$g"ˤ[]BV-|%*l}3'[oP'D`Iw>>1dƨB0քSCH6h־k^'{͉MᜊMf.7yKxCUOv&>h:?fv"> @Py|_Sfj?(1N5G N _=:Dgih/W PG_Vm7|^6.W11#x"zknMo]eT2o۳c%U ʅ"iߦe&v9Y$5/Y뱓wҼOM)Ȭ3ڽFvoOx;ޙjSKDܒpîR`rfi99m?pŜ %A tsIamC@Nۛ(O߭m?.N k/Af<+-žN+nimc4#:>ɒ$Ǖo)C HG=AdV~*UJ yg&aQHuRtEi5*a[}ӽrTMPG¥;> oŀK|H y"dSn4=V.ăѣCwW?o_?:E4 =\6Tf!S_w%!l_uqn]n*P5'q%u'gSۚ-(3- ?{oADX1ZkNASF|bjg.Y۱ t U].aBp5e=VҎ軑VIh;U?椪'f?YSL 5`7ӰoeA׊?3vK&{}.cXb/mM6Hoij DKkX ̰ۏh*bVtbxI/^\;ěf%m׆Vn~},BAM`{vKin\u7_/kK"'x>EBt#t\0nax;tߖ3;9p9BO?_fws]h FUG^Yos&{O/#L?ud viYz?OF q3n|,z%ZnBB Y |)25Doȏ]j~;49Y ^?S@gfp5e|τuT'?qjrz  ;k,#lЯC`o43+YIg)Os=#Zw3rLjPIvzmœQYϰפ]5J7W]b|,+RofsKo:yew(څ* J!KRǼ`[8 Z줮 ZNx @W5.6#cH I`*`ш\d`oMpYD랅߮jE)}Ĩ)4'Zi=e=ZOIB0nQ,}'?*Jج&ܿWlY{~ *ʈ '7㛞f<8qZ%No*Ujj^|]*>%I3óUu%cUP ƲVtYƔ֝*_AP=Sm2q:hܝ_,pPJ:ѿCh:L #bO}oA\۳Z;: <ߏNZK;tnWcLg6fH[Y .YMb+{;Դ$F 닐] t&XB03&T};!ʼ-a2[o_reωsF@#꥓|^P|M0FA]u50 Uh|sVLT ])WUT*'}bĖZ{U%!yM؀| w(9#c1Ç[FЂ8hSV v0; 9F}g=FphgqLő]+ٵ-& 9y8V.F~gJ3\{j~c ?_?ooĬ׆AB bP#!~ /dgmQ D=NKF觯Qk 8 =wq`uOX}2}`6uLA 0lD NB3[ H  vKP_K0[ 6P+gweqo?j"9{(s*7T %>`84C!ۈ=e4x"vxފ9M|&x^L~RBuMW/ԋ!7C6{\@i79NkAZ Jkߑ ~Ih#N 䌆 ?c=lrMfb_F>`d¶_m3,TCu]Ybmp!-v')|FAx+7򉔳?n Ng #ssQHW9R;y,DM hl`*KI6 ÙҚ]?…{)Pޜ9]xL$0SMF_fAmn.ʵqh<_{e/U "f =aW6KwݭTGG]IP{3\+&k4Oy1íxRc7pm~8i!,v 8+"r{ohBK 6XuB+Wx `-^Sv~6hӪUF$`|;UH;(wiH^Gɭhmrz3Qs\K2B>K. Pf:$u?%;\*8uuL4ʫw} \jOuYDXŃYm-#$6e:!LxZBTJu\sbOJ4݈ɸ=OLR-pm\TG.G0r{34:ֱP1JZvij8BP\: d~:1<S!CB^($fXdIgȫSzf;^hZ@gn@wI3Ba*5!A.C ~~pvF3J |k|aثSc[\]@7VOż{ؓ܊!~yngU;Lx|(@;b#4J/{) پ )2wQ(e"ϕo. mJsKqe$;? O~^?k(а*>9^nt {|cW}%xL{3~װ][Ά8EˁH, SVH~F[Y-Uw`ط;upa|>n >*Rj@LK g#{P7w8Esz[;iV`GٯgiяH`x:W EW1Y7#Q<.a'tm1M}\=SApᢃ_.T# "euB;]d7-bv-+bC'L^ΒA Z9%Wjg`#Ԓ3ظO?~/aJ/CvZ[uIfij{JpS\ibpm2C$DV[5PhHxW w[M9k}c*ޱ#XH=c#ͫtt<_h pd6C1N Y;B@ 8nσk^1@Q\'@mJf5KҙfLq4v Wb㖯2<#@gQ*$E+3l[{轧풢0YHFUʿH5N)A^}Uu|uzC ;{nX4@cE1mJ(1=d$>hd %xG$%վi+.iae;l7=:wwG~?m30\}`#,b@dOjy> !,tB?Ul, Z11Qs Uu `1/ȈAI>H>JFﺋGoKb Y3z]$rVMO0ss {Xdv'\~"Ck|܇|h|Vo˄jg`ܘS}PT|Ȩ9&0_Kq=-CJ$q#&C4@6rƮ )%ǧM0kq6iUH}I. [5V mIH0Kˏ6ަN$]j}/=ٳdǪ%c=m+~ c3k@\νSIS) 0n e @A)e1,kTTpڿ@74ۮ)r-D:% c!Nю9UAvJoVNI ,H}>zXH kAPc[0k7oP\ߪ|QiכtG|36J$[d d2CaB2[w16ׁJ&D 4Kȶb/F:TǪ݀EBҚۣ@BS%Mx~U/>A?ݞ#B:ێ r xLC__XoGf}|`z~JF3GyhE;dzϹ3juk1TstciߐvQq>Sg3l#Jwr2DUH&GόTQf]Gшh/kHvëCM\L?R DN^0ר4@F׮4% 9q"~Hi|g F 3XmLEh!̝8Wj9/ 6M>m""#mO hKzW>TM؍*>"0#K"?m&zpqGwe8I͏z7d#: ԩ7c*mZÈrś{Hcқ[B6IQZX{bFԹ[ۀk(I+1k!Et_mnǹ= ^cJ[ݺ*~qsF `1?IVx`gfJSNd.׆v>ݭe!cMc}b݊WFZVY1]qga*=фq _1˩`NXޠhZ);3/!ܱ[6j#yh[}59΅s(mgvj ڄp~޿~7??K?jZhY Za}vz|:_8B?cy%Y?r APdr`$r E{M'_Kr Ӫ'`ޣ#&Sୋ=W7;HCHh9{ξNCTUòƈ,1=({ӂ[$gVwni]xIP+dkܷVxcF05hbp{:̫TʫHzoY:)MNk'(Hy&cC-$')ӚShf("uz"Ue %6L iWU.,&0-nlGvos6ǃewښ\%psU$kEC|IZd{%rMurQ'oD:93}si^pJV>ԙ,8EE@Â~ڒ$ }e8ٚ#JLDjtblUvUVK ܔ$<%muq;~z1s MhC*V Ro#D@H@N Lx9vLGl@"@- 9nعXC\EdUR8PX3M,emRQV%vt֩N}a"yVr<'Ȥ*&jO@N. SJ[")+˗Xp߁?;Ӄ2i<Š0CӐټ8w9=?҅i65My9&8NJ\cu&Rd@#h=) j.6+weedH/LjEŭ9:-Tl\nii"R_GuW}?޻J> N8@qVFbiT5y1N&݌ Y4ܖ[)ؾ5l ~`D3bFx.hn&(~[h v;'=|LY3m h&R&QnS&iBnܯwtvDɈYȌH6vTbC#w)f_`۱h7 {:A6CʍcW< Vm"lq+Lnx4!}(g[_KD:bwJKfulH'[证K c!RF-0S娣Ro?D{0C|@X_/&1d zHfin rB1;GME,=G'=Mj3UǵkiMec߸Nm{޻ZJF$Qԟ'Xq+P+szBLn;WQNA?3Xo[T\#6wO:ߎ _^;NeKa3Uq4׈w4gP]'K%.[aN:cvO ܁Kw,ڜJ~ts$oZݟDuM7Jʵώܮgx צ+.cO[2hٜ6يTnA"oNF&>4d)q$ʍfCCFUj1ׯ|J# SL(9>qKtwxJ+܍3' =˦@7}+~SLJ-]hC6N81bWѻ9 &@";᭰fe.jRm =D(F\m2or ޴gs{V{[S˕jo32\oya7}b.}nǑGb$v7X*r]9k̘vy֞1[pzdtޠ0j_ԴA{wAk5 9T <ѩLGK~ߣ~gnhC&r.5g AG)i{[k'(Kuo ?4;hܚ+pd&]Z@ty.YEN;z SawػxGk:Aڊv 4 F 4x)/@ tn$Da O(׾'.+mgSY[/ue#$DV&M$R:'];}3׀A*Gc|֎Tөk[(Yb%b{z*\sgŧ:rK8[@>GߨSK .Yu>\>N^,s7#.ǛZso3E5j_F}|(񯸀:Nu5 3=k-teH/h''~97}]qv4`~Jp`5´+GaE?R׾jgS#ZI? #FaN⏱fd/º+-S&Ív?e/ʈbq8x-0s#?e7 ;31 `*%j͋]?\9>>)_oh?=S"0P\Q93 x'zO?9 t 3zd84)׎ϽM z*?- 1QfVϑAOaxt iTae1Wk⅟ ׆&?/Cu?1ÙW+u{pc;BmrfjYJ7ԆD|GRvw|v'Qam!|;ՍBu2(V*~00[HQG\kc:k8 w2]c07Җ[b>G}%?25a/U'TW]Ȕ׽6-u #jnVFao/ BaH#nZz wæ/)s.1;ô{g_l`eD(>'`,b4ށCY/2Xy~qv~j#zןQrDpx{tta;s:}?/hg^(Pu.]^#A'UWϗT@家za*hJgaR2Ŭ @Lߠi+ݵP9ͬ |TF>dkr[ 6^<'~#905X'žYAER#^N47bzNt̏1PָD#{o\0y1?IZH9DAjo ];kǔJɥ|: Ӊ°A&WoCX>%Yg.$mgޟd 8` -ULÈ'{8E[ߴD{x|Oxk.LᰫmC'Nrw;!|(wͷfV`]RDg'\<\JnjJUOqyʵ;'2}V`$$t*|޾T(LiY)p.;|ԛ*nی,SŭmDBy,=bFSHTGZUץqN͝$3~n*@=!9Qo aۙrYkQl\[ T#eu RD}v$B G=-Vv-"ڴEq2NTY?g<>zi @0p32#Ik5m ?auY[R>U;m_!Lo# ~A5 pL7L+/yvO 'x8z/yĆn\XEZ47qBKψKر̯_;]vhtJ?7SgцBWk<}Zғͼ^zkY-/zt*Sv-m)pA65n^y*{M Dܴc0E7%0[<{UΑ q̊6՜CFq{"պQ8}ш9ʹ6ongE`R>J[ +5* N=PLnم_G QkT6qs!ρY3v{(R`;Uۓ =1J2{0]i3Hl%!O< j!/FIl D|W -ƸkVn?$l 3#_Ҫ> d{t tewk77U]0Jy بL` h{7Ɖmy+4Υ0K_6kR;3YFIsvc1K1A`x ?{]"#}1! xxPҩH aP֋~11H{6F)}:65!+.ˆ0xb [* jf}<=ɗ6/Ƭ^JT;= ?_O׿kO^lfU=ECyЍ0M i晟y7/&!>%j5FBo/.qO9[?Cpzn;\lg:{?14ChrI;ڔ<P=.^9jj [GtS2LgǗb6Z!ĝs_' &j 5N4ت'S7NW;K P$Ϯ dӣd%@O~ac:kƊ L6G6=Cg - ,b6#YJËxy~{|xFaA2~9f"8%I}&EF0\nM{8 /zULTX"\H^}zm>Po>G^Pضcݑ6C$?:}Lg4p9e<[BD /nJ~P?A{QbTSZ͝rS) )5̍8VwS[aċw pQ_sͫ v{G^$cܕ3"Zvn `x۝\im}T3!žjԱY5bDpOLAN&-8s-WwLkY,hllE?pJWMh6"l2x.=*f&eUPѭ?%ׯz4WM3@|Ж stl!2D:[=*C~CISod߭S1#P.}I19:X`*U#^/ ;N7DAJ)hҥ`)FB 7#9;~8$ⱶ]=pKY-Me`3nI0/n`j @B>c5{" $$G2P 6ٙ /Ѵ|T8x:F (ͯ@Pв]F:7^[T+jyh.aWN I3Ha[HՎqB5?47o4˭^:G]eRO6vX!X ]#N (}{#ǚTnq ]ɮ̐K䔮C"R1pcq,凫 2Gt%: BE07$ţdb[gzfP]0a\b"'xD6*{w߾*хb_qt+SMtWL]x??R;]hVu,d]j "a2£CAOl:/!X[~@U4:oVgaD0)~6ݜqlsvw O=lȭ=Ek|NXjUǑz0.Qi`^k|E,l:9 B$dokGB7ϊlekGM=w1a&䛦Ii+ kt2Gʼ$ ׊8#;-TCw8iĨ=:zj1g_q CxU#Z?-:o5_#gB=*9x+qv ݜ_Sph4MVo!y*b4vzh[$ƽXşd[[4 ~-kˇ /W҂&?['_MzM+h/hj$n\ѸfF@V PwbIڠ>w]%  WF1{sqU]ggy][d`6>#curfnjlcL1XqUs23 gPJh nK}vU Ѫ'LlM>^XGd?ÁuJ /( _X1f# @zhzOCu&<7#%UV-*vt\IKm7.(_+'> mpxJ Cε aNKw݈X .HD3 >qL)Lamm2,mu'ĩN#ɾ&Rw Oכ }/.mGӋ4Iq}qq8yryLZ=cPI" >i"or[\mFGcЁByO+8/^25)Lb|oUg>2ata0vOVu1MZ,o1gqQGXzp/ōl`rO>r'oaq(u@ѿ08D\`GD.P@=ߢu<%AE w!5vr-.m mY?K [y[y*>鱣ȡ峫EH VۻTXǩ`3{ܜnP֘J 9Ec):ګ6 it.-h-]Y);Y<ϟ B }|Ki: \&?,Z]Gǐ~BA;H0j4} t{PYd.L` !'r/w=+Kbm+>;ЩdJ&Bbyvt֜hR,z&^Nesjs %N$M2Բ0Vod3C_ ?=Nb /D ŅoL=Zt6TH>hGisٯcM5? NnkDs }ƥ}Kp(<@}9hX{+iKVĄii2w#lM5jTN*G7BYdHiaB 5lHD}9}u4xe{[]O)B5){%!M$*gO Ξ*w;L~LlTIQS)I_kcp& 1Uvf/:(9⑭hFI>:[E2i!KĠE1WW+FdHcl44%K+AeR:hb|xlAɿ'mؤfZ̞T70v'hb[@ڇӶTWn~EA ϫ#2=/,[YWHj:_Aӄ9 zpmȵ_/m2 “AmHG+b޻}7PW `{D*~~;Qwd5ʱZͳ!6TaP~/#nOrm®1ˌ`bGHdezP\Jluf囋vjEW1 ݧ;6߿~o/M~gsyLhH>:!q!UaF"^F_$}όXS@k(?)&9o]]b@(Evޔ8F Ҿ?xi/8DE#"m{֨܌5є+?,?jS$pV,fR}@S5G ߪȁoY५GĴ^(Y @ 7ivC8tGX!KT㷧@1_%s<][qb.&liʩm8B%~] P)kl>R{b|WFi?^]\ڭ_[oi7KUá7K| JGFf}ڢ Yq5ٖHT<>7x *;³F Ҭ1R9dYcQH[5zN :1 ƌgM5ANJU=B˝6 #d tfڽzѳ3Za. p7!Lzfi \5I-4.G}N0Vvyv B4F kg!|0Y-F铁·䏬~viE .C&H"s[/%2 `>0hw:SD>) ;:$Z&>SkLbmL?}C? >{ ~}1ĥ\&I=W>?#_LY>PgyHKZ* 8fO;TG8mGBC `I40.吋+GN!hkci80Њ-_%) -RW5l .\^JgJ?n`[Jd{ uu[9 ς Zpof^b&J,*KҐgg5(!, [pr>UĵR[hWn$,f#H֑tX<@/;a_jۆV-Y4XVԳMHyjQ܉v:{VME&m]}otjn5̕>(<@ם/dqlԌ+8ǙU^k0ЛЬ$!rL;C!gjtj^?9K~t2jS +?FRY@%̺/)?Run<}k# =?$7ͅl #o}qV+)<>w(WIl2Bǐv?=aWm_BDV47-UCSknoϊUe=&FϪû'vS9i {M2l)kc1|i,SgF:zdK/(=ߗ??()j@1-w kSݝ̼㥘?f+CVMO=G5J- V*jW)¨X 7ЌK ǂMG6—{u]iݗ]~3~%[J6U.WޣKnD-ś΄[vO?c|YжSEGZE=+a`eluvyۅ8]i^u첣\,u4PHcKKk$4D/er {ocq6DpHPup@Zl'pl>M֠9 e* *NNW*tWQfmL|whQ<_R W48{G;SРBV|Bg7=dv1",j;颩# .(D"HA.ݠEG>%ޙ_T3ό>d$3sTt5xv(3I7o`b2,oM>_zo8)5zd1J+yHJGV*QGjZfw%f;6zaPԊIƂV)m\iזtzl[8Nby| 0^SSl&(i, Ĺ붗֚gOt: i2n^ks߳! zaENeH=wjh>Le)>eh/EN='ͣyBRc4t-lC;x=U:7!; LR~D-Ց"}]gy#k#Nۓ߅M t I < N+_'04"Ov;425.JaGb-ZjEz sVm3m F-fZcF2:V:B\J4p˲ +gC%?1I&(@ #k@:b ʩA‖{M_Ⱥn2{t?FDHtRu4BڊLb ~'v;b+Ѱs @f{Xpr C렰H2).PIZ D,e<͓F< 25kCZ9z&z($v9 =km |RftUZ4Uktk_Ѩ5[O!e/ }V33|0<#4^ (vfr"@g^_Fjφ9@= zg{Ta2G uw(&zO zs{aF 5tb(}`?'zRRYۍ.wv~ .m{k/?^q̓{Dmx[N$(:z+F}?ZpU??G41~>N/2$eKو%vXp3Uw^ehFҷG-&+b x%5XsV#] Ⱥ+57Jn- i+DŽ$:,"3OیUҖ}v/C5/(4%|#Wf_݀FP}8[Tl^0C#g/FT\޿c,^zbj+[Yx.8_ÿ}hMs"e4/- L1:dC`SذC <1 URp3DZ6'}yD$Y>ʩAYoabuSC#Ag}(R]XۆY^?Niž\*>140gt; *.Ԏ 㑿jy>{nEmTkkK ~=N*[1ЕWJN#$H.[n;#ϟoׯ]4oo9UCƫaaVw0c*SMvKyjoyS7V_GBr4]Ź]-J2FpJ 2jt"GOX4'kR8 ރt.4p/n1Dvl̹tQyv01k `1!U&so[7 dX6>U!D SF 0M  [ M<o!E"U) M:&Grx4yPZkm! NqoћDeTI1BLgߚ#=+}{x3*ނS!\?ա!+{ d[XieI*'bW(E9Y n! OHUՙqdڊu GZ˳5&o.M|) 䒜E,I$ 73٧Ul1wrO7?__&yUD+o[c[X7SugޓmE~JRYc_Ia'htx\R1nVʨ nѸy 8mq]d2JBY8:-~\{U:.WαNTAhϯ @\PK|Jށ=]ܳ  dy+*n!O#f+H2C>Lq؝lA]s^NmpF5Jy<%ʒ %dwuH!2v1ڞqV4m`$]ܶPF+k=$foB MqcaAXmֵ [L6YcBjw?$oyt(.,:XUE3ʾf%--u-Ihq;LKߪvuO%?,M͓k6.088&hBt(`oD5 `B+y?d*+h%z!ֺOתA[^269#=Ȟ9@UV U YE@ p/4'kyja6Ͳ.<=g'uf7tgm}=ө?z_[ÍwF\>'w.͇Azk$x<.`Y,^Pssr3K Ө')=PrH?3+7?a]UƟIGS5L `Τ@:~ ,hp:fvϑ E5][Ө?:"x}gpiTPGAZΐ\U.B0 fsR.lE_vlǮv4Q4JlO 'qU9L'9==FۧV#SKɸ{'h-F,kٶfm  5U][;FwW@Pj /h 3N c'tr7iA8a)iy_5m&ڶES6p]}f؍E z{O=n C$\\hMmGwA9c|]Q?w(K+ te0FiO8Ә-#i#dgOUx+SHB8d7.scGG8xuS7R[Og]׆;bL&IbN hxn#p܈l5eHU/SDh ^ MPe( 6 uڤ?0 D8ȶlȞH $t$Z$RmC,2\V=/ca>p+0ҁnV`%<$Qjl}o'~iXtaf0q{{氙6&-nL! ϝ8|-!RBX`|]>Tf? ?.3lϩHWYxRu }2\hi҄~r@MpXuȚOt )FiN؎5>N i(@$'{{ޟ1j;jP?޽VẌw!Եo~Kg&ky٩5ҒLzW4 $@${WB{SF|1tƔuo܅mb涛2kyTvkc`G#+Y @ O2}^:2Η3ῦ #6q-}Xƪ"u٫8wѝE@hxQ*s c0'<#f <_sՐWiݕ:{xʈ\ 4٩w7G~)_"AY j"VRYOxH1KOzaTQ>ja/*6A 5k{#hJ4,ڇa$#D瀹(?Ԩg\p=*:n!(M:m?#Fl0 :Lɾc?7X\p^h$hJz$z#ar`%1禾5h N d~.Zt:Yq֛IHU)E>rGgM)-H*{#C\mke=4ķI~^Zo,M!-3]pzƎbcbApſ10 #bsjirhi4XcZQz74A UnVF5SH0eQFhϿ;,)ZCy5͌c?&:4 G3Z[BQz[m>*׷cXd뜘 n$LmU/EFoegBO?K[/Z]xʁ3h.`ӊ?窟Bf [Հ'chZie O6{yJwƎi}*>t#2Sԝ".8փ*q(=Du)>5Ngf((dn. ^Fbl3Ð\im}m_Ɯ55'ާd<$5+KRʣ ^툒??ȷ1ϓboK V޿}G@ǘ+-|Fk~eRu.Y9G0kk/+sk'&36l8em x y#L6 :[b6oפ@~65]V )^Cv on_x|Ki?/o z[ ߜy`4/m߬!f5w/i{%(.@oȚ辽oQfj3`xNN=*Hd+3{G\D>ɧu2+(>أ mHפ29-<by4zYSt}zGs#\ޕ3aPj >zS]-B%[4퉕85_?'P%海sG娑ơkb:{{ձIuQM|Ro&AY?fsZFeb○5'=}bא[Bxz'ǶJ'h-n2/Fl6K=ZI~bB>a888U@w1Y+vߵNhYu*wu Ih)54ÕT)잹`-.+F{IBfD_d 0L-]7卒 ڊ)8gjrl˓ ܴxs*.mF~SEtEQE('WRcW  InKt]=䃥^Qo`Qm(*?K`7N}hK;s$=BjWQB6.j V#5블Q_‹HflqQmA,c C|*,E8>lw{WN{9L~~{{"cNOڡ;.*&{WǘjcFo'WJqߒd&<#+qPߞ}{Ԋ %n' i3bһg<*%j2(cRtJ>9ޫe " tRA7Нܲ K َ:1Nk'Ҋ=\{dmnb̌Ǯrilܒ=Lf[-ZH.z))O|5GΏF#[D{F cawW sJwZ 7-sVKߥFK_͇f[FWxW?B5k%Cp. F>\b07kRDf@/`F{n9_61fEؼE7H{[@kSU:sΉ=Y<1hqw*ZӒ3d7+wUuÍB"` h70v)Oβ_F%3$af?sz*l lCtu$;AEw$lR[2x9feN&Ч:22ߏrg^0dywѨy!(뢥niP2 Oj?q Ǿ`g ;?KH/ >:̠Zaot}q#n_Iކ=( -0P/dR)bl>=#6: YiEӔźKTh^ ô8nR`@O3X]nKҵ98ʎ]Vφ9@*hA\a.\N"qM`CD"ahD܂h,rfl'Ow@kb-q~z]Ad'@A ]=*l9>6nO.ǰ\$V=ʸ3c>'X9Sv>%.?OG~%G=xvVbdX]0^N洟lg/gѦ#X8[})MAwiWˏ7𭱝G'Hr񞳫WSoת#_x\ܻy)BFXݨwnWҲa1o'qYyW=۴a4`l,K)Ҭ GFC{t?0#-Brg;Y#lt QޣNGj ݤL:qsW'DD0[m_|foYM Bk [ajtHT @ymVruA${6#uM{Nh):^{M7 ޠO]NҸNzN񦨶ڨ)wAg )-:+BT{O 9&dh먺~[$c_߮E>GYʶ(;ŲEZM=_?vi,LUƪ -MR~d՚qBf6G$Z"?7b;͇ص#zV"p/f?ҥ =o.3 *? <ޱwEF9&@ QN$ 1!F{:֭$=]"iJG˱KL-x=,z9d<*%@ X>$lB:Q) d%hMAuTP6 ѱ te(2݁/(Cuzd[Rb b@H̬1˃GQ$C;ЏO>>  Jk\T4`;ܟ>li "~F6p?"?]xV]eܗ+3G%p4, kIּkٮjuk:wz`_J*`~C&v81oҸŪ:2s2\xwBo_$}@r5w%N Sh$,0iJXZc1f)ًD\/&/60Y>BOb.(Q9_m5%xdSL@ͻCa4,< ߧ?/_a/P7ʑGģ2füx A-Gx[z= :c?{ĩUtzwxCF@O3*+b>s6<"4,*I#]R=,}%%n@N#[qbNfxڸh(5 %CYd7&JCqnQbZ: h4˭(HL5yx;O(G%"* [%yqz~ai7UA3%8{J)(bw;3&͒nR3(Rsu,1“,N/@ m KIZ[ ̕~j" ܻ3.{57%+I jg\:-TF/ϑ5w}-ID=l<@TQJð4z5vl*MݚuSUΜnVֿkn)$mg12Od,Aﶗc<=cEݤDVu;[Jy=876A>0c4,yY=HY<;h+vF) R7%I M `f5\5noiz5so#_YGi-o FL{8>$xg< ۣXkK+L"8eԘYZO*xS:s|TDu]dskoo˖uj44gdcl'T* g$>`q~eVī€xKWFa8)[0\دHj-6 NJ q cOru )7Ȼk(F.-Uɸ`q{֪X0| Ajt8.B(g#]Os_E6>ʋϳȬEQKt TR>]A_ 7㈵c3*j'Q{z|=4l/ V38Uj#,?Mĥ_;{݌6X? S5+wd @'QRΔ{cF˟Ť~?txZX KK*V{ǫVu/l=Our.%EVa joU ]Ӟ$zV|$E)nf,F7.%oڻ&ɿ$}PyeH4􆙟>3X<}*/h@bKA;gH؛DV:$~ XH찙WrI-u~il.ˬM=ah2Ҋﺁldn9|>ϖ \*C1"' 6ńcW<,n/8b'k:B(F?}Rl#,hnBߊ@W D?@{؟" W17&w7^H*M\* ||[[3:+8Vۯ3;Yǁ>M\n]MXq}Ԉ+j7vO'R$VhB:^B("Q &&@kj&.iUS.B$HPYdϽBh?Yܸ OCT>M+dpW -5d['-B6שkAҴk5bz(Gة>fTóe @ S]EwSrbM-=|eM\#.!U\ẢA{{"(6 V&w+'=єQd$}J<@.|٤GÙƠ  a y] DUS4Z S^5Hh16/C=_>rW *B:25 7)]XܴqwR/ޞ|U-c`D(nnL_G̭Ӌ:ӵRl?S#@Lw>S(Hnq*G f0kBM\N#6\!<(ֈInyቍ_zjO[LFZuZ>?}ZTx˘ֆn!0^Z c}xZ¸!T> S_úu8~Q2 h=?5F5eBSM$ Kz#LUt̤dGUWL5`{lHByA{ r\@d uP:T}io?VfD;b֔ߴ*~Mߟpڊ ^~*1B'w󹘁*":"08]T5FhrJ.x6oȠ} 95boaKmigNx"=c j}#c_6hf5ehԋ2-ӋEx8CݕZy~% [V>,_xD#A`?}Kx_CtcfYP:?Z5#`O/4b*ɵ*H_6?b-a,$OϞ#.- JB> _!SM;a*aO&LaU ؾZr[L0ɺ 9QA2SWnr[CИϔe/ij7F\sG'{ao-^n@*[G_]4+%llN]dS Q`nhg߅9UjPSU*BOܔL"@͏6tr{8gE_AEp窭,FcEB HFI۵ ;=*U̷-+Ir$|)Wp \cT؛k8p㰗o#k=`t1L6¸} Of?K;^b6'QkaeN~N8'']Qs3{y0Ogw ?9%Ts^XfޝJ 5صM0a ^*j'U[szXL?ֆlo8C;ܳff(e \h7[ qƾ>ksS'(F,sh±VSXkbkk0ڜ {K;^e~@HN5Gmpܟ Hڞ1[+x P%^X߷,l.H"8.h"v >5M6šV- ]<yD1Yj_~x; M;;wZ(Hzv>fIJpћtff&%?vר>?老2++Rahݭ1x?GՆɟ5AJ'j&WKP3[ ){Ůt9 r]?\-78AO~ϒ%/TIʹd >nXX)<^sh}ʎ.DPIo'o_qòdaT_L^.ϰ0 NOưYLK₁5ǪzB~ӓ⮝r$<1hx?.sL\QЭ"`Ya&}FL'#7L"ZG)Z_~BB-=ruJzL| ;˝\+cncdy[ܢB=p&}񠰉%) v Njo;иn=bt `"jZod)S;Oƺ*7&@H$ζ`;y$P>I[S9\3mj:bĠ3׍u7Xs::ڛJ󟫄}A] u^H߮, ;~CH*:pKCy^BƳcXr_G Uas(X;-TtszZ4`l*ZpշT{ph#\6Τ^`-m9@ _՞?RPϚzc}S^Ed{2bg}c$9v!ߠ=Cզ- =U%^vH: 5FC=OЄʬQ3BBRT:*}hư^tM :B+Mspd p'P |JΧ jBc׶TFhNo FPax.1 G0 ,ޕcCG$Q3/muqDKWfyNr1@W۴ʈq]=`/j:fnv| "ӎԅDƋQGt@t__Kh_ rT$%AB=0#9-IOzƖ!/4Å>K*X9mkCHݡhLaۏFզ@V!̂caU\k5=Yʧr6u9~ XXXJƣ$ td@/<;2f+ 5pSr'oJ2'Dm9H6{4O` }7??E?k?6{66φHz OCȤQ],݇W;J35,7z*M>~3;Pi_m?FsNۻ㱻f`А.1f.J_Կm>qU-j /{ nm<e#?z,oHꅿXz9,\OK]+L'zx2Twe<DiVIkLd:߽f{)R.u2h7TXV߬9;>`γ ? 3hc8VM͐WtT_Dž0z~B;έo$dQ`O²Y$:5D9c4RSD1*\xn|2@nW[O>HE@ռ2RG@0Ie10 ._EVDLM[f6El?4@?wf}S~8Px9kvcy+=4ìϻJÓj?sTJCq_gaj̶'z#? Z~;CU~D geYݳ;Ga?%tz_;-yba;k4G>A6JEp_1.ڞ2JIQ-6k.g!Ō{>wY2_; @5ПSl7wDPg#_6oڌDX4 }kyi ӮVLU-%~6$1;9xl %?GP `汽kTY[ HFj}6-6Q:Hje'CP' ۈo= ;$c$OոCIo5fAK?nJ=Ҋ;BaXHv*dwu'x1#,7"QF{{V#RuvmM(ƉBq!-$=]"H7<@+!_0_`+ӿ[ͨۓ+:iV]j ~^rY5q꫐wڇͷ=Zx̪ONghL+V,ˋgôt,QM+ IÆ*ǢOY4oO<kgf . <4f س?$v"!&aUS+/BE|F`Fٍ1:,(V-efG黇{:*[Rݽp=1\VKJzZLv֑R=.oR3-]Lc36wz2i/KK2ڠHCO0?yf<~@x~8D+yN=hg 1F|ޫ4M޾g4uh?Cet?xt_{5d}LP]1ᔧV'̾z>3ƭ/%*>>w m?gt!>_䢜?7Y#T[_<:No$01SV[r{#hC U}U*Vh-{ZA8ឬI!pd-+_(Ca+?*VWu䱐0zȭΨ̄:UuJoq9^h̥;'(|a:!k-]Qcƨ?,seSo93>[FSNF,S+F{Z y"3f?>[#Fq4'e1?,7 Bdӣ}洟j(zeZ2R]ޛ,'H?MuuS dݻcQUÉ fkwC52h脐1= e|?h\#Gʁ S6.]?BCVqU4*:^(A nM\WlrY`9sŃL `Op2, $8OEApjL YxmceL0&XXRK>"[r*U"c~yM7__;뿥<)FnF1sb?AƑϭ'z j/kfmfhwtW p%Oݍ;jD4Jp̿U˂i#‡dq.\E$E.ީwEgpH9lnu@+g*ᚨc~n[8M!`sHM=Tcx7qN );4Bjh1zR b7Ax㴠Y ]me @hq[Z*bBe_ǩ@2Jy$[)Ma9ާp]jbK1a*lVlj^͎*H;&'8إ̜7TsWȭT nN)1ϰMG%0{TF$ʘ4G[Rv:ͩA q`\*yoC?'~m,緄Oq0 ~GMF U1Nwo "ssN *Ǐ_$m 7$*)hHhY\=* &},?Z;Nr"X֢`{V!5+cVqg<-T·UFb~R.[q5?>7S&o"%.{-%b%t(}Q ̍ZULQDRp;<oa"38[5n>eNI†q?ForD@{b4?kѻkc:z JG F=@ߞ) 1* b Y#RKmd}@]S!1D]@6JA~O#\N%^O?.D,":hAǍ$D*V EģH;F *>'\#p2Bv䠣GJcE-R޴wM>ꏔIeP>yg]4T82pģ-.kiFQT `hṀr?8G-p{L}8>, 1RԭN>s]XA c.,?& rN1 NsQ~NyL| SL" P a`sOLlkkb yz ,:o_o-Y?S؟/xrGNBOfN]–/s4A.|4ڐq1i-,*MN {--B-TFI-VoZ 8ܧXiwo6&N.Ӕ{ [`A6f`҂[Ȧ3}oS ?m'qUIp/Z6ZQHI.NGy9r2GbR3kw:A݁~qmc{f;;J_U/V&, 7_WT}̾^w)$u3H^Y~ϛA9k,R\i^$7c_qu%'l։l*OOG _qbW>2at/)GQ?B8Y= 0OT.alLof|tm5crwpeؠU ?7(t.׊߼%69/7v!VWu)hg^csh[au&RcJAm)A*m?G2+`|`tܸ:t@?? }ƂfEH6CM}Hjے﨏wWs)|xN+ώ?ݲb̿$sWiJ*/N<6Q1ΐ0j?K}؅3 Jܝ#r Op;fLNf~TcG{2b]˘)̓e1 p|[n}{{2ўAT._VTnEV}NȎd䄷N-sßʉNO擒V mCJ)(3nhd-0o~ \!b9}|d;Xg: ,d[N[J_6{Nw~n%иx,n:k'4A~ժ 8+ҽ>3F`kTKٟ$aK+s*_NPC"> o?} u ,1NR%MUFg7LM#Z\@3>esVBK8:Q?G Rstnp)͖ RUgg  ߀y-_g_OOcV ,dS TYSw Bpriw{7[v8y0dN{࿁%ӏ{ jE6sẒ{IЗw ͬ (t/UoO+=~@evC-_j&¼X¬[69NAASsɥtZC/U'sBrOO/"YM OI&]qZ&z5@4C)߲{ԛTcegWLUَ5-H:P ՜mjM :ލ6v!g0sæ fwܧ9+&HVdmՋLpHE`UT GNU}$n1Ƥ Ak;Bp٦0 lcz^$v&;3Aրwi`<~hdFEb3^H'?c &akp΄7!. l.{jFF!/ [`%wĻV#&],ŷ4.OdOj%sJvn̸]R}tQ+{$yr 9*&tYۉ峫5L_] Vx'x!̺^A,Od謯? OՔ5fFkF}3nIZPTfܜdSmXKc;wT{ ,5SBL |uK-`t i-{-Ƃmω j`yF#}[ѩ!;:ּmUĦiPLk:"9a_9(!OnYa2pK g29R_ O|RY 2*6 CU/k1>)-<RNiD}4ͻf%0 GlmĀfX͈923J40؛@NY}***=f&bp=ZFArn'x R/F|2oh/q4\4m|!={>opGbRaolZ3t`|k.[]cI+﹵C;gL; q+NVNyC _]0v<'j;Er''?5gU Qtʴo(? ZhGONA'~RzSV[ B6o9`{9&Dr*w= p:D vs%pM N Qڷ\^U1}҂%!G dtYo+xsQ #ijb;%}F|-hQ,kp$*U&bt`=F<0{b\rl_ ?q NGTvGEwBntՏ&?OaPS+Ux2{>?_F)DeOq~9`8i?Q}r[vjx 0@Q 9c$[bc^ES)ifgf m̞;?ձ(EѰ{~~?V}sG#l<.GkMn 5ڐQۆABl_\ppRpF+k`uu'[_J{Is`ߢQi8?mr$'4Bwͨ1;#?w q,,gǸ?ڐ17T59.r{i:~.V ]cwo(A7Ҹ')2 78#tH?Aӷ*@ %3 >\>40wl@AZ**CmIqk\o Cm/`Unl@-شJ]URj 3-tM]of 0hjFX<5J?G'/(ݜ1P]C.SG98!-b='$= `!GM~!$UIOjgph⦩|-أ+ `>=o>K{&C]$@|OKh*,Feg7f[tYJ ;Y6vpZToO|Z=a'郁&76oS*A;i2,}Bclz@$ &㡆snI-DPM{{rBn"5|? $D0gb;5t^ @΋WH0WR.j}"Nyh1#%>^[ˢ(Zs5 4@y3kEQ Rr0njv\# CfNiJc&ZPtSi(.qV5VVWk#5=-|46׏iݒ ah62HJ [A +5Y͘/E@T"s"CS6HcNO x^I7fmF%g [I>T n\bFvf71Z*^&ke{vhmF1=i`q~]r%˦uVV9B!OO}GKjAw))LptY˧f;# 뚌8}~C nzr &FK7-Awey}q8TlMJ!'%1˨fS;6Qws If+ .ݴ>_B{r+z)H !33*n, Ecn`}FVuGhQ2y؀v*JxY@v9>>Vzrp4H5NZ1~TBBGvGS֑7u RoS_~yv(Y?@U8@or|o?Rd{ UT?:]H>; q^hlox,"\o7JOM:,OS rF(g߿"\kt& -+zoׄj@}}^&ݵV>_v1*"Qqs62eY65 )cTKt>.0J}:30D Snr 3DZ=;[ u*p< s- &I .Bs$Ru6gw__dM$݇)ƩK": o+426oϕQQgy=- ^>ڵfT>Q祅VOe,Y`fO4n{CyLitѾ\{f_"Dx:pkf蘞մgK:prL&kнAa4݅T|?+aF|"}ω"=m@EFoaevA֫{FYyP^WxhSgߵ)dYr2|F 5 `*)b޵ZNHVڼ?/g*Xմx/uDekZ~FŴ7߸c]sOj;AKoA$>P̯!2=w[j+ii#י&Sv6Z -SWUgj\꒤古Sҧp?"B♲0"S|ae9~?YQuC\-:0t)~_C1 =(=LQOwW⥋%3;.`<~8E4SfHD{pힽQķG@LLm^o M F/ˎ J2o9v4 &w:Ͳє^1PoOovbp}ﵟxQdrK ~|83Bzbsح/ N96-Y XG!=[Ӄ i$7|Fܛ#l#gV\9+"-lO2":3:06{VmBiaJ 8~rXGl )a!>ktM~? }a<;y (fg#dmd4wR佃/59]ߣg ]r64Z٠' ~Gғ ˡt}G\Z-l@*BxnRsil CQLoNUWqcHKFdBWi?|85O$0o<ẬNP_VY?^4'7nU ^f1< nO1dW;~6 }| J/1ꠣ@ BiE΂~K}\밡5XCɧNa/:0c^f^]N俰1ƱJԢ7??O|Z朦7Uoɒ#ו|K {H$uz[h zJd$T41  7ECO XG|.ip[ŁQb~Wo2b{]ܨo߶ oZ4~Wv-0%\aYgTHQo5E c]_(#i߸@]$>Mq|ЌRg=I)1)vC_tZ OY)=ӱL\W+ |8^ m9ߏ9#b5DQiME5Jȧؓ LM+ї3΃o>2峣}kre!hSQ#LpY]k Mv)2|'V <pjrSomqM[')O)=׹SkU{0T.Bߎ&(drKN?r?d:ʙS;_"11?2Wbܟ9{%);yځDا[㦘89yr;|4ۄOרM3|;x+?K7_ydg#nl%2!n{C+ ~?߆ ?9YcSKh]aoUbp)qNJN OBN&?Bp} 0PVUXļ={#g1i^(Շ"=SfxpkћR1cq&>ע}o֩|H=?aE]K黮> oWgV$GJ=fAT}Kf55G zN 4JBE_{{AԵ!A+(䛒\qEUl;UGN( 3ӊp5Ԃÿ6׀ ix-]kk  =AF`7UC'n-X,K]a387BC%[J LG1F''T-/pSl)E_5~ BFCo#t]~3=8_bڤv,Z7p"j{}lL(9Fĕ%,3Sbrͅ5sgxH̉=Oߞl/ |D>ORv/n U:G-jny%:jʻ  OQqZEg?IeS|1V+WjF$ ȃV)=ig}=lVV c^:J;9+NLFSA_ŵJb?tY3iΏ轚sy잽[/?suV o!T/mn;l92Tҏ5woj2JyzT"!7nATT i"=hTM_O*B"BQؽcHCrh(0~x_=Zj{MPY7&Yǻ{;6.Q+*qk `IG4o\QdS5F7WJ:{ C~wG#:t<ϧO~nZԠ>,[V=]!KUK,`1UGLH ?fXu__;t1ϲiFlGאjmv Ay s.9o-=Mc3,OyGQ^M㫶9fONeLEըʫHՉbGZ}K|Q3]qA%DÔyiZ/SX]J{M!:&&hu4S5ս*W#VR@cK-_n*_&j >hKsLڜ@b.<p#4/ .Q2m?< >ϣ* fٻG2:Ro8(incڣfR9مE.!! F=kp=KXV.NoW6hvJ ׯkG5f#0?Mar/^rގͷā[@+Ӑoˌu7a{;3|^)\s 5AQlpsA77=֌8~z2^B\\ss&Wo''=kR #_2T\sI$dDfDbȩii?7??Ӡ~ I-Ʀ!^cV}Dnj-J\xJ-V\<$}'GCK>PK1 ,ߕA)Ʈ A8[N/ňSXvfo=[z^HXc{TF_kso/ $>ޒNnWOz;mwc2g %1#0#8\c@~Z旱dϿ7V7&Kݣ, wC^6Mzٻ;~Β4*y٣s}@-p|uBZ LF Zֿt΍㍷US{r!\s6j Q?|:,X;ǐƺLK3̕ |xI O0{MǖjdZ^IwjgBThSπѳ[CE3iB?hUoWfK)&Ҽ;t?N+Q[kH- mV?·Rpn"Go1n>LpPO>ty\` ֠8wI6:YEpjA{z.E=2t3GOcso_ w#M_ \qopa u+D׊K{t[2r?[Ҥ&`tR}A7qN%Hq[3 sL[4)9ࢡ)gFƠz; (QQV@ C W3;,$4Lv[ey? qFsЀ#V +࿽w՜q*]Z- Qp5>l>W(emF*OI,yKVb'-?gZ$0su7[m`u$zϳ-&p5#g[6O4\P>vhZ jH  E6Z} .Yt7bG>mchffXقJWN u;*NncvNf=aCjD[xmNG?2ߖ7ZpƖZ2šZědN9~%Wc1g- 3>J=zk XJc/}*ӌVOֻܟ^6(S!@ѼPR}vsH0@I ]&Ypx{j-wuT?۟?߭ח]Sx}9z@`{h Bmqs\pF>YABWKs͌2O 0?k;8Bylj'"T7ZlO5PF]㽷mF9I;%W2C?gc_DPZ\v"Rymr܈OE4\?QcDϸRVOadu^ ٕ̺fxSxfE>س"2OWJEpޱ̡;aa9 { ;EXxܞsRN*hK^0w`QXB")#,B1VI?0 VP!呙jjفV $iOHeG{a&4(v? 1~xBp4Uv N%V.O@<fMeR4xTf TZĆ~R"PN/BWQ_68(t^ WF;)84x7U) jVRO=-M ;fPx9?qMcV=\ϾdGDSg IY2R3GsyNj ˥r={kɜS}R%.XdU}>jp ai4j bPWhrqB1હNk`OXd f*.+ǵ~V8qm5y3RapLʞX@{wF%pwsX]*+ ITϥaS~gAjQ] }C}0oҖ^fqu9HGEpAr$HL c0Y)<}hNUgKwڰ*\ӓݣM9`c^#\ QkӀ_f~kxKɣ Aj^^g8l EeA)Z؅6H)(ņd2֪ ř[Up;ho73唖*zeDkK7"Tdjhe7nPeɬVYi#1j[sWvKߐZ[#|R1G]NfF)  J5.c0xs[K9сMB`Ƥ/KL?F/uuDzZA씦vS#50ه<"{nSzo?[pg#D%u;Fg}NhN :tfZMO<{7YƶAlm LY#XvZ$=U?">WaqdA t` )ܠ͑%C׏։=zaΏu8@ v݂f\*+kIPрH8Xp<؝V}P7N|wVRdži>3-nqEZ&dl63}sY@VkJL9x2(}p/޳qM;5fRc&JP䰧:ȇgCC T]( pHDͤFܬ2!VDYe¦>HSUs(K1ph֚Z|. $Ґ-eS\usp%3s )kfS=LٚՀu* slX& fAb}9?jHiN)x)ZhP.FDnO%`NӸOJ%6aԊ:+=vf>=uMkcv)I*mZq*ןr/V={ TKR2O2y~L>Ft85GK$; 6]Omss 2VU;hBRZ QE>"T0#~*򈸝7L KD詵34#kCOI~T C(1iuC2~Gf (h-߀5\,B3_k``?(OtX)9  8وiߩq_o -no;iĦUmƻ)aU}FN^v$)%u0Rۑk6Q6LU]oxY04ͩ }NsN}\e>)?ܟ1c~تTnD6&5'-vdy௞6soTS  kT?$ʣ5 [G4f[}4^oLߓőDJߧGr{ua4^Ν0`UnMڜ{&{>OO?O֏iwR{I'aoǾIsIf()DhM {˞3WH[t]QiR؍D3 k(_?͍Df o=eȲ#i5w7odY|/o GL=KЀ9KCS0SchQ>,okletU)Stˣ }sg~yzxDr/QjgeޭA0z?Ep}?BTPՙ>1 Mﻵ+MHEs܀*)\Hwl<-wE ==cPEvpm-\]4AmHi3V;}h SSc*IJ Wa]d[KхDXЁgkfB7ͬoA!0=Pr1PBnySAd;?rWweDB#5T2NK$R8.ghi{r%bnY^h>]]M-'43Zb̸yu#;OHiQ9dvhKuhEMrfA#>H^34$Ⱥg:)֙;T]˒GYvKF?'?^6g/En%TQcFdSpxs%zm~޾``0K3K{Bvms.GϾ}t4i0Ko!i+M^1`s SPMß\{QIWsW_.A"쥎'W:C=byb>HeyP픠y0d<+ܷV(ܓϞXk'#'sbXOF#h"qEN[])' l Ի|2ΕPg΄( dFZ]R - Y'dpˬ>#pﴏ M5ur Pj@I"iRo=nz:HX#mKҭB?(Y$CD0 jiGYҧ/W#ؔv\5F0:=Ґf}7:e%Tͥ'qlzyX&ؿfK()5 P?iRwݤ-?'oyZ92]9砭amiG[$zV 3cSNۻ*׼߮oz;k,r3e*K(5fZI+<ڲ0>'?pf ~ǿ>t*miWn,O A'Te'h}Oe|t4{/RʝK?2Jz#,<\W.zfsbK [ sYA:AY-UGq&Zr2YC+sJ [kjE_n k4,Iպ{tr rzߧ0?T @=RaƗ̗U¸g1__[ /uQ|m7??{߿~3/ihlS0 zV >hQM::h3gsazhTIr/#5c[?ϜdeNf~ߩ-je[S4W!oW(NC?RA>f>G1'։+tDL)m b]' xppVpCA  n{(Iwr]{ ^OU>8;ӥ>-<#i3??je/1.pݷxTyӑ$bG=}@oq!=(5kl5E˭DxC</,}XjXꈈkyd&km^Ӂ5C0O: /9OWԨK5j!с߆a((rRu"J?C3PE߿ou4oZ5G OKv٪`` _xubRNxNsA9_*O; ZI ܆ΤR[v˞FƩTkR ޠճà!C'6䀃q%X󳏬AB( 1kPBnU(Hnr1|뱂xAnKh@1_: >Z,FI/]McPc: [@GCPat?S(%ZH{PSjCIFQfZmIxFG7 ^>YU&? ad"KnАKYti  yL0mM y$Uebo||fTb=N]?pcM%K^-dq~m".FQ~$mFpv VʖB/o,w[Fpٮ>2St*F+]yMKOyTX>!M/C2+QnM9LJ)ZU&+yߜGxR?Yk+ ,8YNңe>mGv4voJ3}[u2֘s\A*%`ժ9_ 5mocw--|ue`1u$oDa|2|wznvɾ 16P+nd~ekx?q!"_?t7JmEq#3)`_XNy?gYWJ])9śY4N)+VԜxDJ(PG8J2Quυƀ<RW]R:3BhԳ ]u=]#:dx>`utXp5qn9O3QoDB؇0VGk&5>].L / V:wk2@z4c'a?/`lO}N߼+OCwF?SӞ> JiMv%7n]Fe'8nb61bM2hT{afDMuJ[{9Fp:c2(St}xYGȄ!QrF<~@Y F}2IS]cx? fU(i6H.ݮ meYhaL}fuG:+Ah˿tTp}ZiǾixA>r(V9 ]PUi@JP{hv L 򭎄0kSVO2|eXkrOz0O Lo8n?)L C -=WiOz>T-owf(#I9f֎/P ./ ]ث(e=Vc}Sv#y`<;6ZNqߌul1|4J4\@a#ކ: `)AVI)1)aj>ZMvN#DPVSfVzP-vGQ"_{_wgsFWeFF7b萺|I^(Bi0{<2V/#T ^vW퀐,˹Mݟ;VPK(ͳeA tU?0j\\9Z" ʝUYޒ4G?臠UϊKkK+(iʮB~-`% jV4>_>g % ,r)Љd3x 2? S@F}k }|R {PLNrg YjaRJ%|n꧚5' 緼~)d{|΃&  7:6?wx0N֌]YmzufܳKrz0%2?\Xm#sJ]i^u6슮bq]R{R52{e Ò9|*}#vMiѯ4[PT_ եX66{Y#gZX]ڬ|GeX"Y1}GV22fCJ_gsn%PÞ~DeD0[v;9eNd<5 6B*oe<ְ<[яdؒm[N70] U4FQKA1y ;Ou>hHq]A1,h=r7s/,&'DId/kC_>/CJjk$u?|ۢcFィ+[ JO^vop &>}W"k=X-+=I$nEcD+w朵Au';w/M/߿zPb+SY?3(# w!Oirf%өD1gDVr?TΆQ)+̇>/P(US]J4XDSثM-BԤ﨎VgXiN=>fӻo;rGC6nEmqж .M1514 =HԎ^Cۑq'7CVRJ` !f0V(Y]ȈAS{ Oxp%nBg}:vk]!7YгAK xN^8|ڕwR ^F | -k@+̀{:piX9E4o >Zh L{.PzՌ5qj̀rB^Dܠ^ic~Wa1V3uVPrZXDwyWkx{R#7UR}*[>cCVE$=e]vg{RwbZgti kF kyTŊ4JpDu,v-Fhz_3g|ׯk>ɤC`a"]t1գ }dc?l+ @A 4 )\L>kw_ )5], -'H`/^Jz8\ot:4/g-)G6\$OSpi~ԝ[otV cV6pGѱLL dkzk'G-ѧeH:zA3Q4F0T./-dIbeVdcJfX##Q(BFl5QFgfU9-GQ됐B*u;6Gi_ `BBc$UXM.\ 掭, 6fY.ΔensAW V 3bD݊S?mfduj _A= T+`ЛZnevoX > .RJQ3Ohƀj@WUr!SSNJ[{BpɿUYSߺ&Z}^2sjg#[rktvE\L#-Vr2;$œoC :-(:`ܳm<̰>yk?RiI{+Yl^(TG#<6c;*@v.V_>_|4&ivpLJ \@p&M,khgLPذ:.R0H-*Hߚ"*vhվ%5'/|/?ݔWs<|V/1@nCwAzp'+. վj<i>ƌf<",iУN<9wP!T\lpo`mņ}Y'+ "Y\P @?,F(*73?fK)A M{T~ɴgrSv'Dx8H{n$, D`RPDQ"{wZ+:Cvl-p[%ph@IՆ˒O~;X9^3ƨSFv nm8AߐU}`5vϮ5_qQ ;F gDibmIMs\}^D]ImrHQ.͉A R q\5ÕY= թ^ n %BL՛$lh ID?={xЎ$)8ҷN7HrE&L]:m̆|hPlufq%VuW[a'e}UT8Y Fս~ͭ:ܫ$Ļ#359 `@hVY$5bO =Gub~2c*J95,vOS3sxڠp[~濫WCJlO$S&ulaVO>Ho*,ZwN*l(w xw-eF?29 h@vPckzw0o F$Ek}.Hb>TG{u+G/@ E&>ǪK!Hi&UAEmt#$g 19>>ˆei>FcF4Uk㾠v]ZB[D煉S SkvoWk=Yp{ }M /5dRK> e5FMxuO8گNo@2Sb# N\F7-dfjd)ڠϽQQ;/u#Wewz j rp$x܍d$T,HJ1Mکٻ^!gg*fq9%=n?yb`O .LK&[?{0/8_i]4L$a$%'&H7屐c:CuGNԣ0GP8߭Lcn3_,~:&>OjxM_#O~~Cy#m8 /M E|| kܒeʠ`)QZK "]-k111?mR ǞQ=#ռ8/ >p!jzF?\$Rg~K惵d~ح[9m <7GWnF: -!/4~hDžDGE7LY\ ٔh?Zō sQĈR!@[<^8~˜gE4% c2h[̶<3qvr. f{3'GlCCɌR`;ւjaW#`[5kAU,~osқ_zj!m߻݁w?l Ӛ{>ۏ)?F;ļzoKMp94&jzV=K\2R8hC~9j~Ӈ@A>N޶t ܌PʩhvWz'>}X@?Ok|Ԡ,:+֍*8Pg#- @u@c}g}l<#"*1cR"-2;('mɣ;N21uU {[dC˂pI ) JT @l%L%Rڇ Is ~FDhRϲ? N?p3'T2UZ&;$En!w7_8yzfuaD> Lcr ۓU'}s6'HW #B3vIMpNl?'m2]mHwÌš߉;94Xoe>%KN$ZY[Z)gTw)!:rFHn= ߶E";7N?JǦm6Jfsr^ThS2ZJ{~DR[_ףKQkaq/M:MzIxr QS7$H碝9Gӫ3G.gĈ;x?BvF[ih3Y }yQj>bsƣ$D'+̂&K6s6tBBTc(fgvֽvk'@"%WFMlh؅J3|mcĩ,Z[bIFLxKȢ\_rfߟvJ-V6_SJXSf1=dE?evHB*ozz$t5W%0χ~EkFFEjc|ǕNf"oYZ c¬@eh2.tu5N,IّyQ`H+?oyJѫeʩiOE͟Cs?A¨4bFpxeEN(b[N,wzJŜcӞG @*w{l ap19 &} MeUsÞߘĶ|p96vlz-e;|"Bk A ɍJ7 xU_eBoAqޛ!ų?&[jPHxG 8tmU;cLVwWGj#ұf'n~ĈcĜ}-U({ L",廽 ™hi}ЦO=K[؀SfF)sEp _Q  {3oa5,tTo햷ǃ$ 5}gOGB_Ź,۞.<ʂJ^ǎ胱p?,*e[OIkuc(v- DDuW?s2sR$ho+~o|Gf@U3Г`&?+}Ws`3=y2wM[*{Wx Ȭ/ʪA tH#_-_Ics=T,L7 @ h82og,3}svrEF#{z< Wl{eG4ElvJitGw[݃auZipW=KXá2P"E^5 [bykrôsLN k;mÄ E־VevÚ0CjĄp;>~2}~@az )rø3{ h)W&*.+Z }{?'#K.*X m" a $ U :aMUکq4U&s4gBZ{ dEqT) ܦ`q#QiWj>&[?ѬjTWkfh4&V4^{iv]_EUay@ ~ߧ:9)u2R?F'# psh:Â,k0^5pYeQ񝮪g%noX?[1kPS'H#?^aӪc ƭ[;8?ص7C]‰a,mhc|;%9o%nL!G5N?iKذ[Sn?2lo_CͽNEϥ~m3Oq?pP5D%o:n: 2 AOv,(S2vU 88i8I3),+M>H+ Ӫ8DDSsdVf(g&gBX1N}C=5pRQԭOZv3P }Z z7LvkcΫFNo5S^a3_5._wy3`!BE^rm!3ji{/44 F350LLiqC1C1)b'7=PGl',>W#^7v޸el`-o ?w3NڣP1H{jUӿ#%y"GDNz^bQtJ}?iȪ/)w~pI,?N{tnG?Y7Ⱥ+(?2 1a@was=d0ZPN;7PW>/KooR׿hLI߮wٌa 'Ovvc ]N!n6pw$<򗟿Q39ks@[H^jىꮆj97FH&$d KnEI1Xnl '8"!GH=&[a>N@ |=y>|@f3K2?ڙ3:lg\} T#(T Zxl[0Yߩ̉d= fNx,&Gvu. T:>#5)9_?ILS/X?F1,y9 @D6k`ޥcMCb}۹%k•*}0gjp.;6>5*m@֮2a0 [K-VN]}DZmjuO{|H⦈dkn PY?u_H VAF;k*\--)V1ꓲA*>6TH3}}#,Sؐ Ff`9M PýLޮaXii@a5\N}{/ӝ.^ Bm(2pS<+Ýۿ #f% /w^3=ۻ,}T{ۄ}{pO8Y>-1?Ub4{_3kޢuݵ4|G{v9d^͠yZ>&Wovu0)9.! Y+Fv1o*p'o`|U#wep`@y7[XU6餖?iP8"ӦHfH}3`?X' SdGPx]#J} Z!Orvak.;T*xQL2owf=q鵅Iji'qNJ,i(~1W5`t9?#AmHp;bhfś`heO!:fR#p$ tL(c̰I~vCȧ^a#6Aa%-W9|s>~};6>JpN7S}jUF/ Sc3z{&d!0e!\?iSuW,Piem@]5RIGбm93k 7M!PmTU@Z1⾛(t|#PV?lm #E)~ϻ )#s{9$m+ڍX (j˭E|qvth_@ ۟ᵾxW?yHa$ƛkzVF.2?+Ho8> fws% rQFd*#of)D<-(M5>pd`Z{D'w$T1BN{לU @u :)@[푢3KEG,VI,[U;ߌKo PôS{{UΩ}0 \~gMHLոtj)$Mo?n>qpa<7re5<C$C" Y# (O,՚utd pV:Z;fg עq\p_OŦ%Н6&/?׏? qѠ]? G&T ^@jcp WM<3o-/aVƩ3,ތj$twe:2TB>gbZ 5 0յ҄俘?}Fͭklx։=!\_I hO;lɋڭ鏘ҽZ:6#)M-9`Ј(pG 81 fə Q HrJgm($q_73zV(FLC~uʿ?2cұUY{=Jӡ?QDXpD>+Zk!z*(=AOے'<@Q#gwozZy/a D݌ހ&׎4ڎ!kyo~>τ=vIvB< 3K.>t?6'5x l~Q!nm{k3ߺ\<6!2 +NR7K`~;6|YŸ0{EfZ6cߴ'o}`-}Ϥ' !1J(_z /y쫰7To2#[B%;Qөb4w wQy%VG} = ݇?/G Odl= ȕ>F\ا]_yO)0 F cwyX@Xo]=/*b95+ )gWyii;3!A~gh2(?3OaU~Zs)" hXjJi3?+.8forO-cSޟ g0sǬ^0/N3ڷVi=Kv̗;a-s #N\`jmMtpwD6?_D\avهdr%ymf44sUV%͸|\uڵr&H-D=XYVDw844yw0j S 7x 㶬tUd*X a!dqP˩ SvLHW nyVdeAҕAVtoFLZKT?ٽ٭,*UB \>UYz'+l*tT\ ,;-[WK84yJVbqxٌy5?[ΊX}aN Wo)e:,ޒB͊c9j{H؀+{ Yt4{%T:"Ś#Y#\cmي @2 W_`*λk1={.q͌;X*cgJrj'g l*J{vXK.Gْ, &DE4Vﯓ"&20.1;5?-)ѳk2OoݲrTp~:,RGP_uƆteyKrk|xhY5fPhVQ ' QHVb-6Gg5TŞ0o4⸥Qן$xZ/5ti%Z-:&G쒉%C '':y_ /sw>;gFңo\QE&THէx~7o Fa C3 zwGq#U^^ ܁WooY 0nh@jTajS9T2N?g~vL!mh/ s1VP<SN]xAV)2 4 7 ȥSS&Zs%Q)fDXK08 ?U6;?L[TQ@vw|p_ xoKyD;&BҊ**"/lb[?;u@?4(L97Iڕ eS$'cDqtc \ `/3 {W`!`Rrc&0رո*6pU/LVQdRJ 9ͭ:<8A@LD/ֱNaf|plVa?ׄҾnVw`pg{̗a^@M -<f_Ô(F@Tݼy3p2pS%\]6N[:4tub亜([&BtԔ@XXᔼ? |75Td=?(:1|~ _bm(@Gf(}F37g rp21QόLz%nHNZWI]>RCGkx/M_;'??-_A,PKNeS w@&zhxP 8Jbh984}fBr`и"z>8H!>]-&Z$Ks9b~V xZ՛Ov*ۧdvS*7qM1X0; -9N!sl/V>{-S!qzarwΌ6Ƕvp8q7.,M@sgFRO?-ԭ6thIA{0|)Ѝ CmBY;= rM+oaZ4U+0Yu>M0ַb@>muY8ո?MBecv|r8joCxkda|ۋu*؅#*orn3OY?ֲL./A"֏1aۄ_ޥ0-I3%@&Tͅ6?Cʉ<;;ʂZIk)jVӀrGUQDkZ/_!q?o7{F+eOL.$z 5rvc. w-eB@z5"fm9.H9Y'OĀ0o=z@&u\+Vz;TBF>?O0xN(`29¤·ڀȌx{VRIU=s:f3`y2nPF@1Wo@fp3@U* ?$W{K?q!qώu,ܞӀ\^>>1Y)9^|9%oPsОDB~ $U ͍Şoak'<0Qo*``|y'Wyno4 O-Vh:qS!,8rkS9?7C2pP/IRmU{!9*^l9;g\RR P\Suf^h)ч*_R_NlgG7wC0絑q\ANi1֫k==e/1ӟ6ҽt-,nT;G;uO ^'\}QTYpUmp̬,gew<muAȬPizx*O++Gne˪ |,m{(TZކ|v>Y$j{X du{Z@ZxpA\ShɅ0V7+ԡ801ڇ: ۙ콱5@{ F,f1",TdDBroQU akVk? pl&-}I!&-NH:vo״?jg4mH[`h*AFuWj)^p")=e1ٓ} m^] EԑM^FZ: ݱڙmc*[е{=) \ JSB6>ND>@6zժ>=޵dsjTdle<]?+5Hg 8G֙`<2;3+ z w?s@bUӗy[\>EXmq|jWK`UzY?i z·:%KP/ޑ{fzv"ռ79g%5/sOǃ0\3 \ wk8f(xJv|tQNFYFQF U( n=?sv %#4VJ4vu@aH2?Nvt_"r25>1j)RSX LPFYieܖ/}teh yk c+O#,XowO+Iˬc|#;;Ǔq޴=4Rp٥Bh#tɂnX{ÓX+^t `?24. w;XtXbVn,~sO!ģ:jX(ϊ>.kZz"N&QX?!jnaPц`S.(s^$p8]"%^yɈMMz%'|}߾[Ԝ!#J >gFOx8*;I_ы6Gx+ǚ3)9T[mUgpfnߪuQZ|@< Wq sO)͙X~X4,?v}&Qݵ*@т}=.-3%O3sDCkͥq8T9f^aydq1ڋc%:ytB8/cíoڇ\b}532s3]f/QhM8HTX;ձbvUК\խ}ēnU1 a&1  ̬ 9f)Ƃ P82"B֧@vZI[TwґAeGr[HM ͝?*$膷|yW ]38rO#L|!-H72h ־UBt e{_:Te5M k:w2rŵZY>s@[E"8=HQGkqnF=N=l~E}EKmQ?=|8‚pi"BwF>kKZDoIMSE_Q g,x uw5[xe){GؠKK#O׷zRoloˣ]1Od4KU$(0#7F=u 4ZF⼿-)[ =0mZ@FNڪi8}SD8"*)F>DgH3\v, 9 O1/Y7&A)x~+dC9u?.D%먔׾iwvtcj4 wGvntUEе 4+9e}hsqӺ@ B]6 &|^>QoBK6$Cxs7U!.Z D3q5?/}[ $a~AC.T_U;jL/$uκ[Ǽ*-8l#ЭJv('1fTRoM< ZՁAS>Bߑ+1zJ,R*^(]˚S/zL+}b, uo 44*&UR=a{P!VJx$D{XBTԲ *|v0p?uuWJ$`^WOq s`cI(w_`юV+" Y$ͷioQD')-q[: {rV:DWк+ʖ]Ml7RoA3f<`ZR2W֎ӛ;~L+Dz9uF4a\3o- GZ-}bF1xUUޟ~>0Ej;-aæs΀,55ڨT)^1Yͧ >X{d؇vƚ-F\/wlQXtϤ ѻNV2R;O?{;k?.2`Y(zܧ7uGiyq>!R?ni풎mҁ/+xTJ0ӵA: i;)*͇H|ZR=PJ|O薜6}i7;oZ7LF#qTŦ|[c}>1vn7L[ǠZn*M19^-qf9;,@ng$-{[^> vp ۻD2`cz>R. GP@08ݕ$+9 & ' {B/-i0[^[̝˹v Ʈ6~DD̩3Х E9`w?FN0ޟg6ˎ=zϛ 6>,i{Y?6ݣlQGF8T &[ԏF/ Y <0.Rcl{>1xK.g7\9nTqšv_Stѯtbs@=?kooC 'agt2y''[{8%NtrpC#WEܾ{ ߱#7L0BBжcCdw8i/NѴIELGw7u>,Q7"V慿/WNIr3$K]\Y}WE=Y"9NU]ǿu?Se1gJi[wBZ֡nZUվg.](7ݶԾ[[t*ѷWWF[L!Soy LK uҜant|v1.W{l嘯ilhfՕ.Tk:F?H!&7,(Rw4QOpilt稝ՀN8~ ыZܑJYbƤfU*-Ip[R ݍ- \47O<0%Hb&f kt/H@ᴌ:ܫ(՜jE?s ?RN*}l=2\k8ʾPwͤ!P,:moX(tmp ڒs̑!э6?a6us?( )cz$mXk tG=3J/Wf#}54<#~LZNGV+Go͔=P-cOyhHBѬ(KpV@FQ1U2i{l7c3ZZlM+hސ{hOݩ*wTjQt`by ʱ rB4oO9#@c3{?|\Ia hy@ t/JzoxWxt뛌vu(k$_:-В8'0+[t'g17lހU:@ó܅ ǚ_ΎKc͖\xG8B|@ųqq uwe{g:QSX:<-,-!mՒbr@һEZ ΦWRȖ._K>L a6|%)P"bٝ-iy_e@X!NCafDLE؍L:^kV{迾\c-n FxE NڟQD"dzIl *7I^xcq'|ӖQIo ,ʟ!ٳ3.Z Qq^"Z;xfњOjY儅,7BQkjiƳנJ9fz2MBRaP\|vhL!P 0X&{"lwoYӳ ͆qPF|hH'؍||8:guY~zXΎ0rV- C#CDz$v.K~ABZE'?w~efNwmCؙSgz% vrwU)M82)׻(NKT?.NQlj} {98 1 p'hjwi ?ֳ  'əR>;'ѤOiX rkBA*X SOJOzzΤ ]|+q?}2N 06>e}@Ө_*[K'~]¡5l8^EoM[hǔXdgˆJOIyryS(ypqN}=ת62ûƵgyIオ0`zFS#" 5xp"3'Y+_U۫WZ S^'i'A9dDIqA]5'nim՝ܛՠna9Y7Mnj f FP5 h 4-2e.xPCiz$0sJp {mY}#zw4z2Hd6L)3 q30ΐ; [-ףgg,dƗR$8qqOq;VRcPoީz, Z&`\8l} ƺlLtGz+ܯ1BPI RA Wcgtjig|qf#H3^.f!UDI8g8,)YpWuAA4V닠wοso;^ ?K1x]6yq&P[!ߤM.35Ӫ@}!Nm|O[%GTPz%ui&cEvA/ɩm{j߭]bړRST߬tlG%C`^kKChLMFXwJ]I?طڡ}w~CXN} '_.3ޝ(N[ }sVv;;>.rHB ϧ=u\$f9 f~q`ID pd^KUt4OfI:<4[9ux4zCcGV#Nk:sqRg=4N6sCi!.!Z9"yWn:}y7PT'? NOVQ,A;c'.JyCG[eшcv:Qb6I=;>H7u=<){ {;4OeMcd2d^#use ,Q1>{38rMm,Φ>-t^%(yVmOt-?1'GTT$W?c'6&Vbh\2p4^Ln('OqXlpڼ?Xtӣg<~&Q$,dj}5iEg[p*5HH`hzpzYxZ2@_6W4vhFqHNOf.x~ 9np<_Pw!Ǹ:=25;g&\N a& '*g`O)E*LomOcD[HL ^nlXpz ]feZq;x6epi=ԎAyvZC_j 2(5dhf+iH:&M=4`qVο7n~ʹ#aô>U)[Z'_~/Åyyk-05hw5e}}{IL^G5ÜPQ"GݾS85z`qp[q$:#3/hO>i=nc"},H* {I8I~Л(핓 u as/ʮipKQdl$T[ݵ4<_zյ{eBTsWz1)nF=knI.=U }W8}A{Iwy#Oe6NcV T<]UlPW@7v:_焂\rQ4t{j~@ܐLĕߡ4ϲȀv+ru+s)SVd(鐬N֪͍ҁ1Sͯ<Ge"x`La:>L_ dmoOaLM` 5 ak }QED[jzY?#27|&Uݷ+#M;a,^A Cq Ci-4k+] tbqS?ɻz;J,㚴/G̟An2LݢՂwo'??ׯZ9YmptuO?wX* ]HqiMLɀσNK7|˱Fu_Sd}D6}K .Kմql?d@TPsׅF^Leq|7y7o*'<MnXPG[OR189? `82H}&K:*_)VܦRʎ$:+Ĝz솓[IONg;OdJ6{ymvم.HJ'y?El+h#ѩk f ,+GߏzO]431^7*=ZޒV8]uJI@=G Ϋ6xMp2 6'olۉ5wt$Vo E GEQ\~S2`L8E>}g MhwYg ]fQw,J b9@L|\? ˒3zޖ dzaPFV?FQ,0c~}_M)Qn Uy`MZ=Rb}$LgǂHF#DmPP) 7ws _5쨳TM5f?%@`:aF? lo[}x8t$9G/rubiutadU<,׶gޓvqV{n˗㗳z>M CnK@>B㿚Vo p)Nfh;>/|RC{m4ST'bZo+ *_{rOh6Z2{QOR[KvXu_g@rq%]ұxKOj1`1>sW5# ǝt+8!m*]5I]_1,`F>%0cQ3)o2'Q >/5?.la ΎfF*}fr_REfT=mkѡkᣡeUq&ZUiG5IviaKշ:JƳƅ,!G&]>dhT/y@0TvYA޵}kܑB?n7| ,F-IAjh(D|Mg" 5&c8?pQP+ھϱ B]氱nׇww46@%6N8Ux D13I}x@ *T*VW= @WXjT?}'-gR6+GFI2K/fr'gG+G:Us? O y]FL33?Zp*߻[LnM1ZM_?O~KK~p?~o#nsӳ'ZsTpsF{e)!B=SE'K#A\&.v=aj="oͲ KJ$~X3h G|{=Ivz*`'L;jwggVN4pr ͆6N t8ZeFG9^{,с!H}B!oc?ӛ:?YZ8̄a튙 ֜q)x+۫FH:pVš2.~&8 J8ߤڈ`M-ޮ5Q "=h1׈0ks<̾QڷڷP4w{moI%gNoiIz O%Q_c9e_Ķ[4F@<[2-1^Ӱwӣvb L|ykv:$9sEOqX` u< r f|o iEv&KegFJo)StQq;7ZC:FioWDTHJ469^GL'8Llt;^GJ R#[B:1%/–fX?XiTθޟqχWT(ΖM>*03#g ssZ5ʤ{>*_Ͽ7_٧rvwl~,́RZk:( 3=:\8d;$ufw/[$܍%ś]% /pEKe0Β`Wxg3Bj7i-^OqB(gUz;.))oB֕VWXD7={P6fMۜ#6`s6ޑJ?8N<_5pT?Cz,7.Sj@TKthK(V1ZͅJ !DzIUGカ f ?A$3^GMy:5?:F59sg~IQPMaMqNZ/(o(wV $ج{ԢnqThG1$ۺ֬RZrAE #ݮ})L|$=aaW?#B6J>ۓ.Ii)EXH(H{*RMhU v6 ynfmF1Od!3& (BV /trP OXj_5X)~^oB܇bs3aQhc,Fv3}e2Pp0ZsQ:z*{9ߎqny q΃zvU$ҿMt*G†{˞nET {R#Ax8i'9IWD!>-ƌI:@]?8u᷒k7vW&=:ܷM #xuv q*|$ @  i #[5#B#V︳3,})>574`\p9iVU@uF) jTtmMj#A:Tg;B97  POo fo\/} Q S9 ޜot{5@ pdPzH|NJf?yċb9&rׄڔ L!?"uk^CӀ7P;.G9Cx^6|eǴr%yVwf:#"nkk/q8-M )!F;]IXO]1pO~?V)g$[HXSa QC/D].EW _/i Xtha7*H+Hϔ&_9Uľ*`"c(<71+<uDooz2o~3W|>-5Y(#_p9w h;TO=6oxu88gϖsL*P.6Pi\|1&3Qbq/N{8ep\7T6Q4[,7bʜD^Z@6 l}N y&V$D>i&;MFm߾;?irnZ)٣v^Q$db6T*zHD|J… dlb4Q@-bm(oIʆ{3TS>kNhS}>qܜڭCZ{N_4?!>Չ4!!.g`^+'Si'aϧ <>[+cw{"^!?-F[6[ep6z ,<fTΏU}F.NTs`Q8D^j/5+VYbb :Ύ4L9-o=k#'Fx_+^SI`6 T Le8QL81i5LR^Fc`Ad͝*y sy% -"9 N {l^լ[i1׃i\69Ξ =lSv{k}rfH;e$ߒC ~߃2g 䴝v OgeA]TV!P?~胻R|7Z+:yΎA$l,ih,fGp^#]_7㐫UoPɪ5jn~̌!3c4^JnƣtߚЊ}>oy gnjS+1,#O:,> 402*w}3W(4*7wڈ'F[ޡO|#w|=g7]$ _> vB~ c/ݽ=h3Ua}W758yh#"xyfJc [%p?Z7x6v9͏<)QY 'BMNq\юG>JoggtYJԠ!#ai`^.5&-PU?:! (ڢ *䏬IYvwhj6|95v(/Xq6 iK{Y~z ~Vtb\X?m }v}و1QKbzVGo^U<[-Ff9? S(0N3x\2e T+R |(jFfќ)#m;xU߷A? q5̽W&E Klj-&w]!YָS>#'?ywslfWRU?:}礓\a6A6lHO}!BV/:qnj%G/mErn5B^9$feDϕ{+9]H#kcM20T @'iCy{3'aN8ahP=p{?GaHrp1"qLНZ }sI^ܛvPNJ?(l'{@64с!>:^kRh^$3FInhSJޣU9?0 }(7hϏ.&>40\+żC;<=btrC-:5+J5ߍS.lWw?E+$&Kv0% i#'IwlU%c )&Lf`MTJA˓Fbefs%8[cTˍ}wAYR(Q)~ cL=[Qj*"\%\֊FWUm]&8$.XUf)=`Z ({I+  % X+ƀJLtk=u{ ?o?{GY'm't2N8,JbxB_fliArV>X[ h6̤r*oY[$0!,3U?Sg ~}_߯~}_߯~}_߯~}_߯~}_߯r v_sim-3.8.0/examples/demo.ascii000066400000000000000000000314341370110300500164060ustar00rootroot00000000000000Fichier Ni3Au 1.60800000000000e+01 0.00000000000000e+00 1.60800000000000e+01 0.00000000000000e+00 0.00000000000000e+00 1.60800000000000e+01 !This is a sample atomic file in ascii format !All lines must contain at most 256 characters !1st line is arbitrary !2nd line must contain dxx dyx dyy values !3rd line must contain dzx dzy dzz values !All subsequent lines can be comment lines (ignored), i.e. ! empty, containing only blanks, or beginning with ! or with # !After the mandatory 3 beginning lines, a non comment line must ! contain x y z name, giving the 3 coordinates and the name of the atom !Please note that the name must contain at most 8 characters (non blank) !Please also note that real values are in free format ! HOWEVER, (Fortran) format like 1.03D+05 is NOT SUPPORTED ! and must be written 1.03E+05 (or 1.03e+05) !keyword: angstroem 4.02000000000000e+00 4.02000000000000e+00 2.01000000000000e+00 Ni 4.02000000000000e+00 4.02000000000000e+00 6.03000000000000e+00 Ni 4.02000000000000e+00 4.02000000000000e+00 1.00500000000000e+01 Ni 4.02000000000000e+00 4.02000000000000e+00 1.40700000000000e+01 Ni 4.02000000000000e+00 8.04000000000000e+00 2.01000000000000e+00 Ni 4.02000000000000e+00 8.04000000000000e+00 6.03000000000000e+00 Ni 4.02000000000000e+00 8.04000000000000e+00 1.00500000000000e+01 Ni 4.02000000000000e+00 8.04000000000000e+00 1.40700000000000e+01 Ni 4.02000000000000e+00 1.20600000000000e+01 2.01000000000000e+00 Ni 4.02000000000000e+00 1.20600000000000e+01 6.03000000000000e+00 Ni 4.02000000000000e+00 1.20600000000000e+01 1.00500000000000e+01 Ni 4.02000000000000e+00 1.20600000000000e+01 1.40700000000000e+01 Ni 8.04000000000000e+00 4.02000000000000e+00 2.01000000000000e+00 Ni 8.04000000000000e+00 4.02000000000000e+00 6.03000000000000e+00 Ni 8.04000000000000e+00 4.02000000000000e+00 1.00500000000000e+01 Ni 8.04000000000000e+00 4.02000000000000e+00 1.40700000000000e+01 Ni 8.04000000000000e+00 8.04000000000000e+00 2.01000000000000e+00 Ni 8.04000000000000e+00 8.04000000000000e+00 6.03000000000000e+00 Ni 8.04000000000000e+00 8.04000000000000e+00 1.00500000000000e+01 Ni 8.04000000000000e+00 8.04000000000000e+00 1.40700000000000e+01 Ni 8.04000000000000e+00 1.20600000000000e+01 2.01000000000000e+00 Ni 8.04000000000000e+00 1.20600000000000e+01 6.03000000000000e+00 Ni 8.04000000000000e+00 1.20600000000000e+01 1.00500000000000e+01 Ni 8.04000000000000e+00 1.20600000000000e+01 1.40700000000000e+01 Ni 1.20600000000000e+01 4.02000000000000e+00 2.01000000000000e+00 Ni 1.20600000000000e+01 4.02000000000000e+00 6.03000000000000e+00 Ni 1.20600000000000e+01 4.02000000000000e+00 1.00500000000000e+01 Ni 1.20600000000000e+01 4.02000000000000e+00 1.40700000000000e+01 Ni 1.20600000000000e+01 8.04000000000000e+00 2.01000000000000e+00 Ni 1.20600000000000e+01 8.04000000000000e+00 6.03000000000000e+00 Ni 1.20600000000000e+01 8.04000000000000e+00 1.00500000000000e+01 Ni 1.20600000000000e+01 8.04000000000000e+00 1.40700000000000e+01 Ni 1.20600000000000e+01 1.20600000000000e+01 2.01000000000000e+00 Ni 1.20600000000000e+01 1.20600000000000e+01 6.03000000000000e+00 Ni 1.20600000000000e+01 1.20600000000000e+01 1.00500000000000e+01 Ni 1.20600000000000e+01 1.20600000000000e+01 1.40700000000000e+01 Ni 2.01000000000000e+00 4.02000000000000e+00 4.02000000000000e+00 Ni 2.01000000000000e+00 4.02000000000000e+00 8.04000000000000e+00 Ni 2.01000000000000e+00 4.02000000000000e+00 1.20600000000000e+01 Ni 2.01000000000000e+00 8.04000000000000e+00 4.02000000000000e+00 Ni 2.01000000000000e+00 8.04000000000000e+00 8.04000000000000e+00 Ni 2.01000000000000e+00 8.04000000000000e+00 1.20600000000000e+01 Ni 2.01000000000000e+00 1.20600000000000e+01 4.02000000000000e+00 Ni 2.01000000000000e+00 1.20600000000000e+01 8.04000000000000e+00 Ni 2.01000000000000e+00 1.20600000000000e+01 1.20600000000000e+01 Ni 6.03000000000000e+00 4.02000000000000e+00 4.02000000000000e+00 Ni 6.03000000000000e+00 4.02000000000000e+00 8.04000000000000e+00 Ni 6.03000000000000e+00 4.02000000000000e+00 1.20600000000000e+01 Ni 6.03000000000000e+00 8.04000000000000e+00 4.02000000000000e+00 Ni 6.03000000000000e+00 8.04000000000000e+00 8.04000000000000e+00 Ni 6.03000000000000e+00 8.04000000000000e+00 1.20600000000000e+01 Ni 6.03000000000000e+00 1.20600000000000e+01 4.02000000000000e+00 Ni 6.03000000000000e+00 1.20600000000000e+01 8.04000000000000e+00 Ni 6.03000000000000e+00 1.20600000000000e+01 1.20600000000000e+01 Ni 1.00500000000000e+01 4.02000000000000e+00 4.02000000000000e+00 Ni 1.00500000000000e+01 4.02000000000000e+00 8.04000000000000e+00 Ni 1.00500000000000e+01 4.02000000000000e+00 1.20600000000000e+01 Ni 1.00500000000000e+01 8.04000000000000e+00 4.02000000000000e+00 Ni 1.00500000000000e+01 8.04000000000000e+00 8.04000000000000e+00 Ni 1.00500000000000e+01 8.04000000000000e+00 1.20600000000000e+01 Ni 1.00500000000000e+01 1.20600000000000e+01 4.02000000000000e+00 Ni 1.00500000000000e+01 1.20600000000000e+01 8.04000000000000e+00 Ni 1.00500000000000e+01 1.20600000000000e+01 1.20600000000000e+01 Ni 1.40700000000000e+01 4.02000000000000e+00 4.02000000000000e+00 Ni 1.40700000000000e+01 4.02000000000000e+00 8.04000000000000e+00 Ni 1.40700000000000e+01 4.02000000000000e+00 1.20600000000000e+01 Ni 1.40700000000000e+01 8.04000000000000e+00 4.02000000000000e+00 Ni 1.40700000000000e+01 8.04000000000000e+00 8.04000000000000e+00 Ni 1.40700000000000e+01 8.04000000000000e+00 1.20600000000000e+01 Ni 1.40700000000000e+01 1.20600000000000e+01 4.02000000000000e+00 Ni 1.40700000000000e+01 1.20600000000000e+01 8.04000000000000e+00 Ni 1.40700000000000e+01 1.20600000000000e+01 1.20600000000000e+01 Ni 4.02000000000000e+00 2.01000000000000e+00 4.02000000000000e+00 Ni 4.02000000000000e+00 2.01000000000000e+00 8.04000000000000e+00 Ni 4.02000000000000e+00 2.01000000000000e+00 1.20600000000000e+01 Ni 4.02000000000000e+00 6.03000000000000e+00 4.02000000000000e+00 Ni 4.02000000000000e+00 6.03000000000000e+00 8.04000000000000e+00 Ni 4.02000000000000e+00 6.03000000000000e+00 1.20600000000000e+01 Ni 4.02000000000000e+00 1.00500000000000e+01 4.02000000000000e+00 Ni 4.02000000000000e+00 1.00500000000000e+01 8.04000000000000e+00 Ni 4.02000000000000e+00 1.00500000000000e+01 1.20600000000000e+01 Ni 4.02000000000000e+00 1.40700000000000e+01 4.02000000000000e+00 Ni 4.02000000000000e+00 1.40700000000000e+01 8.04000000000000e+00 Ni 4.02000000000000e+00 1.40700000000000e+01 1.20600000000000e+01 Ni 8.04000000000000e+00 2.01000000000000e+00 4.02000000000000e+00 Ni 8.04000000000000e+00 2.01000000000000e+00 8.04000000000000e+00 Ni 8.04000000000000e+00 2.01000000000000e+00 1.20600000000000e+01 Ni 8.04000000000000e+00 6.03000000000000e+00 4.02000000000000e+00 Ni 8.04000000000000e+00 6.03000000000000e+00 8.04000000000000e+00 Ni 8.04000000000000e+00 6.03000000000000e+00 1.20600000000000e+01 Ni 8.04000000000000e+00 1.00500000000000e+01 4.02000000000000e+00 Ni 8.04000000000000e+00 1.00500000000000e+01 8.04000000000000e+00 Ni 8.04000000000000e+00 1.00500000000000e+01 1.20600000000000e+01 Ni 8.04000000000000e+00 1.40700000000000e+01 4.02000000000000e+00 Ni 8.04000000000000e+00 1.40700000000000e+01 8.04000000000000e+00 Ni 8.04000000000000e+00 1.40700000000000e+01 1.20600000000000e+01 Ni 1.20600000000000e+01 2.01000000000000e+00 4.02000000000000e+00 Ni 1.20600000000000e+01 2.01000000000000e+00 8.04000000000000e+00 Ni 1.20600000000000e+01 2.01000000000000e+00 1.20600000000000e+01 Ni 1.20600000000000e+01 6.03000000000000e+00 4.02000000000000e+00 Ni 1.20600000000000e+01 6.03000000000000e+00 8.04000000000000e+00 Ni 1.20600000000000e+01 6.03000000000000e+00 1.20600000000000e+01 Ni 1.20600000000000e+01 1.00500000000000e+01 4.02000000000000e+00 Ni 1.20600000000000e+01 1.00500000000000e+01 8.04000000000000e+00 Ni 1.20600000000000e+01 1.00500000000000e+01 1.20600000000000e+01 Ni 1.20600000000000e+01 1.40700000000000e+01 4.02000000000000e+00 Ni 1.20600000000000e+01 1.40700000000000e+01 8.04000000000000e+00 Ni 1.20600000000000e+01 1.40700000000000e+01 1.20600000000000e+01 Ni 2.01000000000000e+00 2.01000000000000e+00 2.01000000000000e+00 Au 2.01000000000000e+00 2.01000000000000e+00 6.03000000000000e+00 Au 2.01000000000000e+00 2.01000000000000e+00 1.00500000000000e+01 Au 2.01000000000000e+00 2.01000000000000e+00 1.40700000000000e+01 Au 2.01000000000000e+00 6.03000000000000e+00 2.01000000000000e+00 Au 2.01000000000000e+00 6.03000000000000e+00 6.03000000000000e+00 Au 2.01000000000000e+00 6.03000000000000e+00 1.00500000000000e+01 Au 2.01000000000000e+00 6.03000000000000e+00 1.40700000000000e+01 Au 2.01000000000000e+00 1.00500000000000e+01 2.01000000000000e+00 Au 2.01000000000000e+00 1.00500000000000e+01 6.03000000000000e+00 Au 2.01000000000000e+00 1.00500000000000e+01 1.00500000000000e+01 Au 2.01000000000000e+00 1.00500000000000e+01 1.40700000000000e+01 Au 2.01000000000000e+00 1.40700000000000e+01 2.01000000000000e+00 Au 2.01000000000000e+00 1.40700000000000e+01 6.03000000000000e+00 Au 2.01000000000000e+00 1.40700000000000e+01 1.00500000000000e+01 Au 2.01000000000000e+00 1.40700000000000e+01 1.40700000000000e+01 Au 6.03000000000000e+00 2.01000000000000e+00 2.01000000000000e+00 Au 6.03000000000000e+00 2.01000000000000e+00 6.03000000000000e+00 Au 6.03000000000000e+00 2.01000000000000e+00 1.00500000000000e+01 Au 6.03000000000000e+00 2.01000000000000e+00 1.40700000000000e+01 Au 6.03000000000000e+00 6.03000000000000e+00 2.01000000000000e+00 Au 6.03000000000000e+00 6.03000000000000e+00 6.03000000000000e+00 Au 6.03000000000000e+00 6.03000000000000e+00 1.00500000000000e+01 Au 6.03000000000000e+00 6.03000000000000e+00 1.40700000000000e+01 Au 6.03000000000000e+00 1.00500000000000e+01 2.01000000000000e+00 Au 6.03000000000000e+00 1.00500000000000e+01 6.03000000000000e+00 Au 6.03000000000000e+00 1.00500000000000e+01 1.00500000000000e+01 Au 6.03000000000000e+00 1.00500000000000e+01 1.40700000000000e+01 Au 6.03000000000000e+00 1.40700000000000e+01 2.01000000000000e+00 Au 6.03000000000000e+00 1.40700000000000e+01 6.03000000000000e+00 Au 6.03000000000000e+00 1.40700000000000e+01 1.00500000000000e+01 Au 6.03000000000000e+00 1.40700000000000e+01 1.40700000000000e+01 Au 1.00500000000000e+01 2.01000000000000e+00 2.01000000000000e+00 Au 1.00500000000000e+01 2.01000000000000e+00 6.03000000000000e+00 Au 1.00500000000000e+01 2.01000000000000e+00 1.00500000000000e+01 Au 1.00500000000000e+01 2.01000000000000e+00 1.40700000000000e+01 Au 1.00500000000000e+01 6.03000000000000e+00 2.01000000000000e+00 Au 1.00500000000000e+01 6.03000000000000e+00 6.03000000000000e+00 Au 1.00500000000000e+01 6.03000000000000e+00 1.00500000000000e+01 Au 1.00500000000000e+01 6.03000000000000e+00 1.40700000000000e+01 Au 1.00500000000000e+01 1.00500000000000e+01 2.01000000000000e+00 Au 1.00500000000000e+01 1.00500000000000e+01 6.03000000000000e+00 Au 1.00500000000000e+01 1.00500000000000e+01 1.00500000000000e+01 Au 1.00500000000000e+01 1.00500000000000e+01 1.40700000000000e+01 Au 1.00500000000000e+01 1.40700000000000e+01 2.01000000000000e+00 Au 1.00500000000000e+01 1.40700000000000e+01 6.03000000000000e+00 Au 1.00500000000000e+01 1.40700000000000e+01 1.00500000000000e+01 Au 1.00500000000000e+01 1.40700000000000e+01 1.40700000000000e+01 Au 1.40700000000000e+01 2.01000000000000e+00 2.01000000000000e+00 Au 1.40700000000000e+01 2.01000000000000e+00 6.03000000000000e+00 Au 1.40700000000000e+01 2.01000000000000e+00 1.00500000000000e+01 Au 1.40700000000000e+01 2.01000000000000e+00 1.40700000000000e+01 Au 1.40700000000000e+01 6.03000000000000e+00 2.01000000000000e+00 Au 1.40700000000000e+01 6.03000000000000e+00 6.03000000000000e+00 Au 1.40700000000000e+01 6.03000000000000e+00 1.00500000000000e+01 Au 1.40700000000000e+01 6.03000000000000e+00 1.40700000000000e+01 Au 1.40700000000000e+01 1.00500000000000e+01 2.01000000000000e+00 Au 1.40700000000000e+01 1.00500000000000e+01 6.03000000000000e+00 Au 1.40700000000000e+01 1.00500000000000e+01 1.00500000000000e+01 Au 1.40700000000000e+01 1.00500000000000e+01 1.40700000000000e+01 Au 1.40700000000000e+01 1.40700000000000e+01 2.01000000000000e+00 Au 1.40700000000000e+01 1.40700000000000e+01 6.03000000000000e+00 Au 1.40700000000000e+01 1.40700000000000e+01 1.00500000000000e+01 Au 1.40700000000000e+01 1.40700000000000e+01 1.40700000000000e+01 Au v_sim-3.8.0/examples/demo.d3000066400000000000000000000104501370110300500156170ustar00rootroot00000000000000Fichier Ni3Au l@Ni Au 0@0zG@0zG@0zG0`@zG@zG@zG@zG@zG@zG@zG@zG@zG@zG@zG@zG@ zG@ zG@ zG@ zG@ zG@ zG@ zG@ zG@ zG@ zG@ zG@ zG@(Q @(Q @(Q @(Q @(Q @(Q @(Q @(Q @(Q @(Q @(Q @(Q @zG@zG@zG@zG@zG@zG@zG@zG@zG@Q @Q @Q @Q @Q @Q @Q @Q @Q @$@$@$@$@$@$@$@$@$@,# =p@,# =p@,# =p@,# =p@,# =p@,# =p@,# =p@,# =p@,# =p@zG@zG@zG@zG@zG@zG@zG@zG@zG@zG@zG@zG@ zG@ zG@ zG@ zG@ zG@ zG@ zG@ zG@ zG@ zG@ zG@ zG@(Q @(Q @(Q @(Q @(Q @(Q @(Q @(Q @(Q @(Q @(Q @(Q @zG@zG@zG@zG@zG@zG@zG@zG@zG@zG@zG@zG@zG@zG@zG@zG@Q @Q @Q @Q @Q @Q @Q @Q @Q @Q @Q @Q @Q @Q @Q @Q @$@$@$@$@$@$@$@$@$@$@$@$@$@$@$@$@,# =p@,# =p@,# =p@,# =p@,# =p@,# =p@,# =p@,# =p@,# =p@,# =p@,# =p@,# =p@,# =p@,# =p@,# =p@,# =p``@zG@zG@zG@zG@ zG@ zG@ zG@ zG@(Q @(Q @(Q @(Q @zG@zG@zG@zG@ zG@ zG@ zG@ zG@(Q @(Q @(Q @(Q @zG@zG@zG@zG@ zG@ zG@ zG@ zG@(Q @(Q @(Q @(Q @zG@zG@zG@ zG@ zG@ zG@(Q @(Q @(Q @zG@zG@zG@ zG@ zG@ zG@(Q @(Q @(Q @zG@zG@zG@ zG@ zG@ zG@(Q @(Q @(Q @zG@zG@zG@ zG@ zG@ zG@(Q @(Q @(Q @zG@zG@zG@Q @Q @Q @$@$@$@,# =p@,# =p@,# =p@zG@zG@zG@Q @Q @Q @$@$@$@,# =p@,# =p@,# =p@zG@zG@zG@Q @Q @Q @$@$@$@,# =p@,# =p@,# =p@zG@zG@zG@zG@Q @Q @Q @Q @$@$@$@$@,# =p@,# =p@,# =p@,# =p@zG@zG@zG@zG@Q @Q @Q @Q @$@$@$@$@,# =p@,# =p@,# =p@,# =p@zG@zG@zG@zG@Q @Q @Q @Q @$@$@$@$@,# =p@,# =p@,# =p@,# =p@zG@zG@zG@zG@Q @Q @Q @Q @$@$@$@$@,# =p@,# =p@,# =p@,# =p``@zG@Q @$@,# =p@zG@Q @$@,# =p@zG@Q @$@,# =p@zG@Q @$@,# =p@zG@Q @$@,# =p@zG@Q @$@,# =p@zG@Q @$@,# =p@zG@Q @$@,# =p@zG@Q @$@,# =p@zG@ zG@(Q @zG@ zG@(Q @zG@ zG@(Q @zG@ zG@(Q @zG@ zG@(Q @zG@ zG@(Q @zG@ zG@(Q @zG@ zG@(Q @zG@ zG@(Q @zG@ zG@(Q @zG@ zG@(Q @zG@ zG@(Q @zG@ zG@(Q @zG@ zG@(Q @zG@ zG@(Q @zG@ zG@(Q @zG@ zG@(Q @zG@ zG@(Q @zG@ zG@(Q @zG@ zG@(Q @zG@ zG@(Q @zG@ zG@(Q @zG@ zG@(Q @zG@ zG@(Q @zG@Q @$@,# =p@zG@Q @$@,# =p@zG@Q @$@,# =p@zG@Q @$@,# =p@zG@Q @$@,# =p@zG@Q @$@,# =p@zG@Q @$@,# =p@zG@Q @$@,# =p@zG@Q @$@,# =p@zG@Q @$@,# =p@zG@Q @$@,# =p@zG@Q @$@,# =p@zG@Q @$@,# =p@zG@Q @$@,# =p@zG@Q @$@,# =p@zG@Q @$@,# =p`v_sim-3.8.0/examples/demo.xyz000066400000000000000000001336221370110300500161520ustar00rootroot00000000000000 950 This is a file for testing pseudo-XYZ file format C 11.277072 0.000000 0.000000 C 25.373412 0.000000 0.000000 C 36.650484 0.000000 0.000000 C 7.048170 0.000000 0.000000 C 38.060118 0.000000 0.000000 C 23.963778 0.000000 0.000000 C 29.602314 0.000000 0.000000 C 4.228902 0.000000 0.000000 C 8.457804 0.000000 0.000000 C 33.831216 0.000000 0.000000 C 2.819268 0.000000 0.000000 C 28.192680 0.000000 0.000000 C 12.686706 0.000000 0.000000 C 16.915608 0.000000 0.000000 C 0.000000 0.000000 0.000000 C 15.505974 0.000000 0.000000 C 32.421582 0.000000 0.000000 C 40.879386 0.000000 0.000000 C 19.734876 0.000000 0.000000 C 21.144510 0.000000 0.000000 Ni 26.042891 0.488311 3.283000 Ni 27.523201 0.488311 3.283000 Ni 0.873321 0.615443 3.283000 Ni 40.006065 0.615443 3.283000 Ni 7.752987 1.122941 3.283000 C 19.030059 1.220779 0.000000 C 9.162621 1.220779 0.000000 C 31.716765 1.220779 0.000000 C 30.307131 1.220779 0.000000 C 38.764935 1.220779 0.000000 C 2.114451 1.220779 0.000000 C 13.391523 1.220779 0.000000 C 35.945667 1.220779 0.000000 C 14.801157 1.220779 0.000000 C 40.174569 1.220779 0.000000 C 27.487863 1.220779 0.000000 C 26.078229 1.220779 0.000000 C 21.849327 1.220779 0.000000 C 4.933719 1.220779 0.000000 C 10.572255 1.220779 0.000000 C 17.620425 1.220779 0.000000 C 0.704817 1.220779 0.000000 C 34.536033 1.220779 0.000000 C 6.343353 1.220779 0.000000 C 23.258961 1.220779 0.000000 Ni 0.035338 1.709090 3.283000 Ni 40.844048 1.709090 3.283000 Ni 6.498915 1.709755 3.283000 Ni 9.007059 1.709755 3.283000 Ni 27.922480 1.823919 3.283000 Ni 25.643612 1.823919 3.283000 C 32.421582 2.441558 0.000000 C 23.963778 2.441558 0.000000 C 33.831216 2.441558 0.000000 C 15.505974 2.441558 0.000000 C 28.192680 2.441558 0.000000 C 25.373412 2.441558 0.000000 C 36.650484 2.441558 0.000000 C 21.144510 2.441558 0.000000 C 8.457804 2.441558 0.000000 C 7.048170 2.441558 0.000000 C 38.060118 2.441558 0.000000 C 12.686706 2.441558 0.000000 C 11.277072 2.441558 0.000000 C 29.602314 2.441558 0.000000 C 2.819268 2.441558 0.000000 C 16.915608 2.441558 0.000000 C 4.228902 2.441558 0.000000 C 0.000000 2.441558 0.000000 C 19.734876 2.441558 0.000000 C 40.879386 2.441558 0.000000 Ni 26.783046 2.625126 3.283000 Ni 40.444769 3.044698 3.283000 Ni 0.434617 3.044698 3.283000 Ni 6.174849 3.057000 3.283000 Ni 9.331125 3.057000 3.283000 C 35.945667 3.662337 0.000000 C 13.391523 3.662337 0.000000 C 31.716765 3.662337 0.000000 C 27.487863 3.662337 0.000000 C 40.174569 3.662337 0.000000 C 6.343353 3.662337 0.000000 C 26.078229 3.662337 0.000000 C 4.933719 3.662337 0.000000 C 30.307131 3.662337 0.000000 C 21.849327 3.662337 0.000000 C 0.704817 3.662337 0.000000 C 2.114451 3.662337 0.000000 C 10.572255 3.662337 0.000000 C 34.536033 3.662337 0.000000 C 9.162621 3.662337 0.000000 C 14.801157 3.662337 0.000000 C 17.620425 3.662337 0.000000 C 38.764935 3.662337 0.000000 C 23.258961 3.662337 0.000000 C 19.030059 3.662337 0.000000 Ni 41.584203 3.845905 3.283000 Ni 7.012832 4.150647 3.283000 Ni 8.493142 4.150647 3.283000 C 36.650484 4.883115 0.000000 C 40.879386 4.883115 0.000000 C 23.963778 4.883115 0.000000 C 38.060118 4.883115 0.000000 C 12.686706 4.883115 0.000000 C 19.734876 4.883115 0.000000 C 21.144510 4.883115 0.000000 C 8.457804 4.883115 0.000000 C 29.602314 4.883115 0.000000 C 15.505974 4.883115 0.000000 C 33.831216 4.883115 0.000000 C 32.421582 4.883115 0.000000 C 25.373412 4.883115 0.000000 C 7.048170 4.883115 0.000000 C 2.819268 4.883115 0.000000 C 28.192680 4.883115 0.000000 C 0.000000 4.883115 0.000000 C 16.915608 4.883115 0.000000 C 11.277072 4.883115 0.000000 C 4.228902 4.883115 0.000000 Ni 8.892421 5.486255 3.283000 Ni 6.613553 5.486255 3.283000 C 38.764935 6.103894 0.000000 C 10.572255 6.103894 0.000000 C 35.945667 6.103894 0.000000 C 31.716765 6.103894 0.000000 C 26.078229 6.103894 0.000000 C 2.114451 6.103894 0.000000 C 14.801157 6.103894 0.000000 C 9.162621 6.103894 0.000000 C 0.704817 6.103894 0.000000 C 40.174569 6.103894 0.000000 C 30.307131 6.103894 0.000000 C 34.536033 6.103894 0.000000 C 17.620425 6.103894 0.000000 C 21.849327 6.103894 0.000000 C 27.487863 6.103894 0.000000 C 19.030059 6.103894 0.000000 C 6.343353 6.103894 0.000000 C 4.933719 6.103894 0.000000 C 13.391523 6.103894 0.000000 C 23.258961 6.103894 0.000000 Ni 7.752987 6.287462 3.283000 Ni 31.011948 7.141105 3.283000 {frag: [cycle, 0]} C 28.192680 7.324673 0.000000 C 23.963778 7.324673 0.000000 C 29.602314 7.324673 0.000000 C 0.000000 7.324673 0.000000 C 11.277072 7.324673 0.000000 C 7.048170 7.324673 0.000000 C 15.505974 7.324673 0.000000 C 4.228902 7.324673 0.000000 C 36.650484 7.324673 0.000000 C 2.819268 7.324673 0.000000 C 40.879386 7.324673 0.000000 C 38.060118 7.324673 0.000000 C 33.831216 7.324673 0.000000 C 25.373412 7.324673 0.000000 C 21.144510 7.324673 0.000000 C 19.734876 7.324673 0.000000 C 16.915608 7.324673 0.000000 C 32.421582 7.324673 0.000000 C 12.686706 7.324673 0.000000 C 8.457804 7.324673 0.000000 Ni 29.872514 7.942312 3.283000 {frag: [cycle, 0]} Ni 32.151382 7.942312 3.283000 {frag: [cycle, 0]} C 6.343353 8.545452 0.000000 C 23.258961 8.545452 0.000000 C 2.114451 8.545452 0.000000 C 30.307131 8.545452 0.000000 C 38.764935 8.545452 0.000000 C 17.620425 8.545452 0.000000 C 19.030059 8.545452 0.000000 C 27.487863 8.545452 0.000000 C 13.391523 8.545452 0.000000 C 9.162621 8.545452 0.000000 C 14.801157 8.545452 0.000000 C 0.704817 8.545452 0.000000 C 40.174569 8.545452 0.000000 C 35.945667 8.545452 0.000000 C 4.933719 8.545452 0.000000 C 31.716765 8.545452 0.000000 C 21.849327 8.545452 0.000000 C 34.536033 8.545452 0.000000 C 10.572255 8.545452 0.000000 C 26.078229 8.545452 0.000000 Ni 31.752103 9.277920 3.283000 {frag: [cycle, 0]} Ni 30.271793 9.277920 3.283000 {frag: [cycle, 0]} Ni 9.867438 9.668393 3.283000 C 40.879386 9.766231 0.000000 C 12.686706 9.766231 0.000000 C 2.819268 9.766231 0.000000 C 28.192680 9.766231 0.000000 C 15.505974 9.766231 0.000000 C 8.457804 9.766231 0.000000 C 19.734876 9.766231 0.000000 C 7.048170 9.766231 0.000000 C 0.000000 9.766231 0.000000 C 29.602314 9.766231 0.000000 C 25.373412 9.766231 0.000000 C 21.144510 9.766231 0.000000 C 11.277072 9.766231 0.000000 C 38.060118 9.766231 0.000000 C 32.421582 9.766231 0.000000 C 16.915608 9.766231 0.000000 C 4.228902 9.766231 0.000000 C 36.650484 9.766231 0.000000 C 33.831216 9.766231 0.000000 C 23.963778 9.766231 0.000000 Ni 11.121510 10.255207 3.283000 Ni 8.613366 10.255207 3.283000 Ni 32.590086 10.371567 3.283000 {frag: [cycle, 0]} Ni 29.433810 10.371567 3.283000 {frag: [cycle, 0]} C 34.536033 10.987010 0.000000 C 21.849327 10.987010 0.000000 C 27.487863 10.987010 0.000000 C 17.620425 10.987010 0.000000 C 30.307131 10.987010 0.000000 C 35.945667 10.987010 0.000000 C 31.716765 10.987010 0.000000 C 38.764935 10.987010 0.000000 C 40.174569 10.987010 0.000000 C 10.572255 10.987010 0.000000 C 19.030059 10.987010 0.000000 C 23.258961 10.987010 0.000000 C 4.933719 10.987010 0.000000 C 6.343353 10.987010 0.000000 C 14.801157 10.987010 0.000000 C 9.162621 10.987010 0.000000 C 13.391523 10.987010 0.000000 C 26.078229 10.987010 0.000000 C 0.704817 10.987010 0.000000 C 2.114451 10.987010 0.000000 Ni 11.445576 11.602452 3.283000 Ni 8.289300 11.602452 3.283000 Ni 29.757876 11.718812 3.283000 {frag: [cycle, 0]} Ni 32.266020 11.718812 3.283000 {frag: [cycle, 0]} C 40.879386 12.207789 0.000000 C 33.831216 12.207789 0.000000 C 25.373412 12.207789 0.000000 C 12.686706 12.207789 0.000000 C 15.505974 12.207789 0.000000 C 11.277072 12.207789 0.000000 C 28.192680 12.207789 0.000000 C 36.650484 12.207789 0.000000 C 21.144510 12.207789 0.000000 C 16.915608 12.207789 0.000000 C 19.734876 12.207789 0.000000 C 0.000000 12.207789 0.000000 C 8.457804 12.207789 0.000000 C 4.228902 12.207789 0.000000 C 32.421582 12.207789 0.000000 C 38.060118 12.207789 0.000000 C 7.048170 12.207789 0.000000 C 29.602314 12.207789 0.000000 C 2.819268 12.207789 0.000000 C 23.963778 12.207789 0.000000 Ni 31.011948 12.305626 3.283000 {frag: [cycle, 0]} Ni 10.607593 12.696099 3.283000 Ni 9.127283 12.696099 3.283000 Ni 37.355301 13.244999 3.283000 C 40.174569 13.428567 0.000000 C 38.764935 13.428567 0.000000 C 6.343353 13.428567 0.000000 C 34.536033 13.428567 0.000000 C 27.487863 13.428567 0.000000 C 26.078229 13.428567 0.000000 C 23.258961 13.428567 0.000000 C 14.801157 13.428567 0.000000 C 19.030059 13.428567 0.000000 C 10.572255 13.428567 0.000000 C 17.620425 13.428567 0.000000 C 35.945667 13.428567 0.000000 C 30.307131 13.428567 0.000000 C 31.716765 13.428567 0.000000 C 13.391523 13.428567 0.000000 C 21.849327 13.428567 0.000000 C 4.933719 13.428567 0.000000 C 9.162621 13.428567 0.000000 C 2.114451 13.428567 0.000000 C 0.704817 13.428567 0.000000 Ni 8.728004 14.031707 3.283000 Ni 11.006872 14.031707 3.283000 Ni 36.215867 14.046206 3.283000 Ni 38.494735 14.046206 3.283000 Ni 22.554144 14.465778 3.283000 {frag: [cycle, 1]} C 12.686706 14.649346 0.000000 C 11.277072 14.649346 0.000000 C 8.457804 14.649346 0.000000 C 7.048170 14.649346 0.000000 C 4.228902 14.649346 0.000000 C 2.819268 14.649346 0.000000 C 0.000000 14.649346 0.000000 C 40.879386 14.649346 0.000000 C 38.060118 14.649346 0.000000 C 36.650484 14.649346 0.000000 C 33.831216 14.649346 0.000000 C 32.421582 14.649346 0.000000 C 29.602314 14.649346 0.000000 C 28.192680 14.649346 0.000000 C 25.373412 14.649346 0.000000 C 23.963778 14.649346 0.000000 C 21.144510 14.649346 0.000000 C 19.734876 14.649346 0.000000 C 16.915608 14.649346 0.000000 C 15.505974 14.649346 0.000000 Ni 9.867438 14.832914 3.283000 Ni 21.414710 15.266985 3.283000 {frag: [cycle, 1]} Ni 23.693578 15.266985 3.283000 {frag: [cycle, 1]} Ni 38.095456 15.381814 3.283000 Ni 36.615146 15.381814 3.283000 C 14.801157 15.870125 0.000000 C 13.391523 15.870125 0.000000 C 10.572255 15.870125 0.000000 C 9.162621 15.870125 0.000000 C 6.343353 15.870125 0.000000 C 4.933719 15.870125 0.000000 C 2.114451 15.870125 0.000000 C 0.704817 15.870125 0.000000 C 40.174569 15.870125 0.000000 C 38.764935 15.870125 0.000000 C 35.945667 15.870125 0.000000 C 34.536033 15.870125 0.000000 C 31.716765 15.870125 0.000000 C 30.307131 15.870125 0.000000 C 27.487863 15.870125 0.000000 C 26.078229 15.870125 0.000000 C 23.258961 15.870125 0.000000 C 21.849327 15.870125 0.000000 C 19.030059 15.870125 0.000000 C 17.620425 15.870125 0.000000 Ni 38.933439 16.475461 3.283000 Ni 35.777163 16.475461 3.283000 Ni 23.294299 16.602593 3.283000 {frag: [cycle, 1]} Ni 21.813989 16.602593 3.283000 {frag: [cycle, 1]} C 40.879386 17.090904 0.000000 C 38.060118 17.090904 0.000000 C 36.650484 17.090904 0.000000 C 33.831216 17.090904 0.000000 C 32.421582 17.090904 0.000000 C 29.602314 17.090904 0.000000 C 28.192680 17.090904 0.000000 C 25.373412 17.090904 0.000000 C 23.963778 17.090904 0.000000 C 21.144510 17.090904 0.000000 C 19.734876 17.090904 0.000000 C 16.915608 17.090904 0.000000 C 15.505974 17.090904 0.000000 C 12.686706 17.090904 0.000000 C 11.277072 17.090904 0.000000 C 8.457804 17.090904 0.000000 C 7.048170 17.090904 0.000000 C 4.228902 17.090904 0.000000 C 2.819268 17.090904 0.000000 C 0.000000 17.090904 0.000000 Ni 20.976006 17.696240 3.283000 {frag: [cycle, 1]} Ni 24.132282 17.696240 3.283000 {frag: [cycle, 1]} Ni 38.609373 17.822706 3.283000 Ni 36.101229 17.822706 3.283000 Ni 3.524085 18.213845 3.283000 C 40.174569 18.311683 0.000000 C 38.764935 18.311683 0.000000 C 35.945667 18.311683 0.000000 C 34.536033 18.311683 0.000000 C 31.716765 18.311683 0.000000 C 30.307131 18.311683 0.000000 C 27.487863 18.311683 0.000000 C 26.078229 18.311683 0.000000 C 23.258961 18.311683 0.000000 C 21.849327 18.311683 0.000000 C 19.030059 18.311683 0.000000 C 17.620425 18.311683 0.000000 C 14.801157 18.311683 0.000000 C 13.391523 18.311683 0.000000 C 10.572255 18.311683 0.000000 C 9.162621 18.311683 0.000000 C 6.343353 18.311683 0.000000 C 4.933719 18.311683 0.000000 C 2.114451 18.311683 0.000000 C 0.704817 18.311683 0.000000 Ni 37.355301 18.409520 3.283000 Ni 4.778157 18.800659 3.283000 Ni 2.270013 18.800659 3.283000 Ni 23.808216 19.043485 3.283000 {frag: [cycle, 1]} Ni 21.300072 19.043485 3.283000 {frag: [cycle, 1]} C 40.879386 19.532462 0.000000 C 38.060118 19.532462 0.000000 C 36.650484 19.532462 0.000000 C 33.831216 19.532462 0.000000 C 32.421582 19.532462 0.000000 C 29.602314 19.532462 0.000000 C 28.192680 19.532462 0.000000 C 25.373412 19.532462 0.000000 C 23.963778 19.532462 0.000000 C 21.144510 19.532462 0.000000 C 19.734876 19.532462 0.000000 C 16.915608 19.532462 0.000000 C 15.505974 19.532462 0.000000 C 12.686706 19.532462 0.000000 C 11.277072 19.532462 0.000000 C 8.457804 19.532462 0.000000 C 7.048170 19.532462 0.000000 C 4.228902 19.532462 0.000000 C 2.819268 19.532462 0.000000 C 0.000000 19.532462 0.000000 Ni 22.554144 19.630299 3.283000 {frag: [cycle, 1]} Ni 5.102223 20.147904 3.283000 Ni 1.945947 20.147904 3.283000 Ni 11.981889 20.569672 3.283000 C 40.174569 20.753241 0.000000 C 38.764935 20.753241 0.000000 C 35.945667 20.753241 0.000000 C 34.536033 20.753241 0.000000 C 31.716765 20.753241 0.000000 C 30.307131 20.753241 0.000000 C 27.487863 20.753241 0.000000 C 26.078229 20.753241 0.000000 C 23.258961 20.753241 0.000000 C 21.849327 20.753241 0.000000 C 19.030059 20.753241 0.000000 C 17.620425 20.753241 0.000000 C 14.801157 20.753241 0.000000 C 13.391523 20.753241 0.000000 C 10.572255 20.753241 0.000000 C 9.162621 20.753241 0.000000 C 6.343353 20.753241 0.000000 C 4.933719 20.753241 0.000000 C 2.114451 20.753241 0.000000 C 0.704817 20.753241 0.000000 Ni 4.264240 21.241551 3.283000 Ni 2.783930 21.241551 3.283000 Ni 13.121323 21.370879 3.283000 Ni 10.842455 21.370879 3.283000 C 40.879386 21.974019 0.000000 C 38.060118 21.974019 0.000000 C 36.650484 21.974019 0.000000 C 33.831216 21.974019 0.000000 C 32.421582 21.974019 0.000000 C 29.602314 21.974019 0.000000 C 28.192680 21.974019 0.000000 C 25.373412 21.974019 0.000000 C 23.963778 21.974019 0.000000 C 21.144510 21.974019 0.000000 C 19.734876 21.974019 0.000000 C 16.915608 21.974019 0.000000 C 15.505974 21.974019 0.000000 C 12.686706 21.974019 0.000000 C 11.277072 21.974019 0.000000 C 8.457804 21.974019 0.000000 C 7.048170 21.974019 0.000000 C 4.228902 21.974019 0.000000 C 2.819268 21.974019 0.000000 C 0.000000 21.974019 0.000000 Ni 2.384651 22.577159 3.283000 Ni 4.663519 22.577159 3.283000 Ni 12.722044 22.706487 3.283000 Ni 11.241734 22.706487 3.283000 C 40.174569 23.194798 0.000000 C 38.764935 23.194798 0.000000 C 35.945667 23.194798 0.000000 C 34.536033 23.194798 0.000000 C 31.716765 23.194798 0.000000 C 30.307131 23.194798 0.000000 C 27.487863 23.194798 0.000000 C 26.078229 23.194798 0.000000 C 23.258961 23.194798 0.000000 C 21.849327 23.194798 0.000000 C 19.030059 23.194798 0.000000 C 17.620425 23.194798 0.000000 C 14.801157 23.194798 0.000000 C 13.391523 23.194798 0.000000 C 10.572255 23.194798 0.000000 C 9.162621 23.194798 0.000000 C 6.343353 23.194798 0.000000 C 4.933719 23.194798 0.000000 C 2.114451 23.194798 0.000000 C 0.704817 23.194798 0.000000 Ni 3.524085 23.378366 3.283000 Ni 13.560027 23.800134 3.283000 Ni 10.403751 23.800134 3.283000 C 0.000000 24.415577 0.000000 C 33.831216 24.415577 0.000000 C 32.421582 24.415577 0.000000 C 29.602314 24.415577 0.000000 C 28.192680 24.415577 0.000000 C 25.373412 24.415577 0.000000 C 23.963778 24.415577 0.000000 C 21.144510 24.415577 0.000000 C 19.734876 24.415577 0.000000 C 16.915608 24.415577 0.000000 C 15.505974 24.415577 0.000000 C 12.686706 24.415577 0.000000 C 11.277072 24.415577 0.000000 C 8.457804 24.415577 0.000000 C 7.048170 24.415577 0.000000 C 4.228902 24.415577 0.000000 C 2.819268 24.415577 0.000000 C 38.060118 24.415577 0.000000 C 40.879386 24.415577 0.000000 C 36.650484 24.415577 0.000000 Ni 10.727817 25.147379 3.283000 Ni 13.235961 25.147379 3.283000 C 38.764935 25.636356 0.000000 C 40.174569 25.636356 0.000000 C 0.704817 25.636356 0.000000 C 35.945667 25.636356 0.000000 C 34.536033 25.636356 0.000000 C 31.716765 25.636356 0.000000 C 30.307131 25.636356 0.000000 C 27.487863 25.636356 0.000000 C 26.078229 25.636356 0.000000 C 23.258961 25.636356 0.000000 C 21.849327 25.636356 0.000000 C 19.030059 25.636356 0.000000 C 17.620425 25.636356 0.000000 C 14.801157 25.636356 0.000000 C 13.391523 25.636356 0.000000 C 10.572255 25.636356 0.000000 C 9.162621 25.636356 0.000000 C 6.343353 25.636356 0.000000 C 4.933719 25.636356 0.000000 C 2.114451 25.636356 0.000000 Ni 11.981889 25.734193 3.283000 Ni 31.011948 26.759297 3.283000 C 40.879386 26.857135 0.000000 C 38.060118 26.857135 0.000000 C 36.650484 26.857135 0.000000 C 29.602314 26.857135 0.000000 C 28.192680 26.857135 0.000000 C 25.373412 26.857135 0.000000 C 23.963778 26.857135 0.000000 C 21.144510 26.857135 0.000000 C 19.734876 26.857135 0.000000 C 12.686706 26.857135 0.000000 C 11.277072 26.857135 0.000000 C 8.457804 26.857135 0.000000 C 7.048170 26.857135 0.000000 C 4.228902 26.857135 0.000000 C 2.819268 26.857135 0.000000 C 15.505974 26.857135 0.000000 C 16.915608 26.857135 0.000000 C 33.831216 26.857135 0.000000 C 32.421582 26.857135 0.000000 C 0.000000 26.857135 0.000000 Ni 32.266020 27.346111 3.283000 Ni 29.757876 27.346111 3.283000 C 40.174569 28.077914 0.000000 C 38.764935 28.077914 0.000000 C 35.945667 28.077914 0.000000 C 34.536033 28.077914 0.000000 C 31.716765 28.077914 0.000000 C 30.307131 28.077914 0.000000 C 27.487863 28.077914 0.000000 C 26.078229 28.077914 0.000000 C 23.258961 28.077914 0.000000 C 21.849327 28.077914 0.000000 C 19.030059 28.077914 0.000000 C 14.801157 28.077914 0.000000 C 13.391523 28.077914 0.000000 C 10.572255 28.077914 0.000000 C 9.162621 28.077914 0.000000 C 6.343353 28.077914 0.000000 C 4.933719 28.077914 0.000000 C 2.114451 28.077914 0.000000 C 0.704817 28.077914 0.000000 C 17.620425 28.077914 0.000000 Ni 29.433810 28.693356 3.283000 Ni 32.590086 28.693356 3.283000 C 29.602314 29.298692 0.000000 C 28.192680 29.298692 0.000000 C 25.373412 29.298692 0.000000 C 23.963778 29.298692 0.000000 C 21.144510 29.298692 0.000000 C 19.734876 29.298692 0.000000 C 16.915608 29.298692 0.000000 C 15.505974 29.298692 0.000000 C 12.686706 29.298692 0.000000 C 11.277072 29.298692 0.000000 C 8.457804 29.298692 0.000000 C 7.048170 29.298692 0.000000 C 4.228902 29.298692 0.000000 C 2.819268 29.298692 0.000000 C 0.000000 29.298692 0.000000 C 40.879386 29.298692 0.000000 C 38.060118 29.298692 0.000000 C 36.650484 29.298692 0.000000 C 33.831216 29.298692 0.000000 C 32.421582 29.298692 0.000000 Ni 30.271793 29.787003 3.283000 Ni 31.752103 29.787003 3.283000 C 31.716765 30.519471 0.000000 C 30.307131 30.519471 0.000000 C 27.487863 30.519471 0.000000 C 26.078229 30.519471 0.000000 C 23.258961 30.519471 0.000000 C 21.849327 30.519471 0.000000 C 19.030059 30.519471 0.000000 C 17.620425 30.519471 0.000000 C 14.801157 30.519471 0.000000 C 13.391523 30.519471 0.000000 C 10.572255 30.519471 0.000000 C 9.162621 30.519471 0.000000 C 6.343353 30.519471 0.000000 C 4.933719 30.519471 0.000000 C 2.114451 30.519471 0.000000 C 0.704817 30.519471 0.000000 C 40.174569 30.519471 0.000000 C 38.764935 30.519471 0.000000 C 35.945667 30.519471 0.000000 C 34.536033 30.519471 0.000000 Ni 29.872514 31.122611 3.283000 Ni 32.151382 31.122611 3.283000 C 40.879386 31.740250 0.000000 C 38.060118 31.740250 0.000000 C 36.650484 31.740250 0.000000 C 33.831216 31.740250 0.000000 C 32.421582 31.740250 0.000000 C 29.602314 31.740250 0.000000 C 28.192680 31.740250 0.000000 C 25.373412 31.740250 0.000000 C 23.963778 31.740250 0.000000 C 21.144510 31.740250 0.000000 C 19.734876 31.740250 0.000000 C 16.915608 31.740250 0.000000 C 15.505974 31.740250 0.000000 C 12.686706 31.740250 0.000000 C 11.277072 31.740250 0.000000 C 8.457804 31.740250 0.000000 C 7.048170 31.740250 0.000000 C 4.228902 31.740250 0.000000 C 2.819268 31.740250 0.000000 C 0.000000 31.740250 0.000000 Ni 31.011948 31.923818 3.283000 Ni 7.752987 32.863192 3.283000 Ni 20.439693 32.863192 3.283000 C 40.174569 32.961029 0.000000 C 38.764935 32.961029 0.000000 C 35.945667 32.961029 0.000000 C 34.536033 32.961029 0.000000 C 31.716765 32.961029 0.000000 C 30.307131 32.961029 0.000000 C 27.487863 32.961029 0.000000 C 26.078229 32.961029 0.000000 C 23.258961 32.961029 0.000000 C 21.849327 32.961029 0.000000 C 19.030059 32.961029 0.000000 C 17.620425 32.961029 0.000000 C 14.801157 32.961029 0.000000 C 13.391523 32.961029 0.000000 C 10.572255 32.961029 0.000000 C 9.162621 32.961029 0.000000 C 6.343353 32.961029 0.000000 C 4.933719 32.961029 0.000000 C 2.114451 32.961029 0.000000 C 0.704817 32.961029 0.000000 Ni 9.007059 33.450006 3.283000 Ni 19.185621 33.450006 3.283000 Ni 21.693765 33.450006 3.283000 Ni 6.498915 33.450006 3.283000 C 40.879386 34.181808 0.000000 C 38.060118 34.181808 0.000000 C 36.650484 34.181808 0.000000 C 33.831216 34.181808 0.000000 C 32.421582 34.181808 0.000000 C 29.602314 34.181808 0.000000 C 28.192680 34.181808 0.000000 C 25.373412 34.181808 0.000000 C 23.963778 34.181808 0.000000 C 21.144510 34.181808 0.000000 C 19.734876 34.181808 0.000000 C 16.915608 34.181808 0.000000 C 15.505974 34.181808 0.000000 C 12.686706 34.181808 0.000000 C 11.277072 34.181808 0.000000 C 8.457804 34.181808 0.000000 C 7.048170 34.181808 0.000000 C 4.228902 34.181808 0.000000 C 2.819268 34.181808 0.000000 C 0.000000 34.181808 0.000000 Ni 6.174849 34.797251 3.283000 Ni 9.331125 34.797251 3.283000 Ni 22.017831 34.797251 3.283000 Ni 18.861555 34.797251 3.283000 C 40.174569 35.402587 0.000000 C 38.764935 35.402587 0.000000 C 35.945667 35.402587 0.000000 C 34.536033 35.402587 0.000000 C 31.716765 35.402587 0.000000 C 30.307131 35.402587 0.000000 C 27.487863 35.402587 0.000000 C 26.078229 35.402587 0.000000 C 23.258961 35.402587 0.000000 C 21.849327 35.402587 0.000000 C 19.030059 35.402587 0.000000 C 17.620425 35.402587 0.000000 C 14.801157 35.402587 0.000000 C 13.391523 35.402587 0.000000 C 10.572255 35.402587 0.000000 C 9.162621 35.402587 0.000000 C 6.343353 35.402587 0.000000 C 4.933719 35.402587 0.000000 C 2.114451 35.402587 0.000000 C 0.704817 35.402587 0.000000 Ni 7.012832 35.890898 3.283000 Ni 8.493142 35.890898 3.283000 Ni 19.699538 35.890898 3.283000 Ni 21.179848 35.890898 3.283000 C 40.879386 36.623366 0.000000 C 38.060118 36.623366 0.000000 C 36.650484 36.623366 0.000000 C 33.831216 36.623366 0.000000 C 32.421582 36.623366 0.000000 C 29.602314 36.623366 0.000000 C 28.192680 36.623366 0.000000 C 25.373412 36.623366 0.000000 C 23.963778 36.623366 0.000000 C 21.144510 36.623366 0.000000 C 19.734876 36.623366 0.000000 C 16.915608 36.623366 0.000000 C 15.505974 36.623366 0.000000 C 12.686706 36.623366 0.000000 C 11.277072 36.623366 0.000000 C 8.457804 36.623366 0.000000 C 7.048170 36.623366 0.000000 C 4.228902 36.623366 0.000000 C 2.819268 36.623366 0.000000 C 0.000000 36.623366 0.000000 Ni 6.613553 37.226506 3.283000 Ni 8.892421 37.226506 3.283000 Ni 19.300259 37.226506 3.283000 Ni 21.579127 37.226506 3.283000 Ni 41.584203 37.746307 3.283000 C 40.174569 37.844144 0.000000 C 38.764935 37.844144 0.000000 C 35.945667 37.844144 0.000000 C 34.536033 37.844144 0.000000 C 31.716765 37.844144 0.000000 C 30.307131 37.844144 0.000000 C 27.487863 37.844144 0.000000 C 26.078229 37.844144 0.000000 C 23.258961 37.844144 0.000000 C 21.849327 37.844144 0.000000 C 19.030059 37.844144 0.000000 C 17.620425 37.844144 0.000000 C 14.801157 37.844144 0.000000 C 13.391523 37.844144 0.000000 C 10.572255 37.844144 0.000000 C 9.162621 37.844144 0.000000 C 6.343353 37.844144 0.000000 C 4.933719 37.844144 0.000000 C 2.114451 37.844144 0.000000 C 0.704817 37.844144 0.000000 Ni 7.752987 38.027713 3.283000 Ni 20.439693 38.027713 3.283000 Ni 40.330131 38.333121 3.283000 Ni 0.549255 38.333121 3.283000 C 40.879386 39.064923 0.000000 C 38.060118 39.064923 0.000000 C 36.650484 39.064923 0.000000 C 33.831216 39.064923 0.000000 C 32.421582 39.064923 0.000000 C 29.602314 39.064923 0.000000 C 28.192680 39.064923 0.000000 C 25.373412 39.064923 0.000000 C 23.963778 39.064923 0.000000 C 21.144510 39.064923 0.000000 C 19.734876 39.064923 0.000000 C 16.915608 39.064923 0.000000 C 15.505974 39.064923 0.000000 C 12.686706 39.064923 0.000000 C 11.277072 39.064923 0.000000 C 8.457804 39.064923 0.000000 C 7.048170 39.064923 0.000000 C 4.228902 39.064923 0.000000 C 2.819268 39.064923 0.000000 C 0.000000 39.064923 0.000000 Ni 0.873321 39.680366 3.283000 Ni 40.006065 39.680366 3.283000 Ni 33.126399 40.187865 3.283000 C 40.174569 40.285702 0.000000 C 38.764935 40.285702 0.000000 C 35.945667 40.285702 0.000000 C 34.536033 40.285702 0.000000 C 31.716765 40.285702 0.000000 C 30.307131 40.285702 0.000000 C 27.487863 40.285702 0.000000 C 26.078229 40.285702 0.000000 C 23.258961 40.285702 0.000000 C 21.849327 40.285702 0.000000 C 19.030059 40.285702 0.000000 C 17.620425 40.285702 0.000000 C 14.801157 40.285702 0.000000 C 13.391523 40.285702 0.000000 C 10.572255 40.285702 0.000000 C 9.162621 40.285702 0.000000 C 6.343353 40.285702 0.000000 C 4.933719 40.285702 0.000000 C 2.114451 40.285702 0.000000 C 0.704817 40.285702 0.000000 Ni 40.844048 40.774013 3.283000 Ni 0.035338 40.774013 3.283000 Ni 31.872327 40.774679 3.283000 Ni 34.380471 40.774679 3.283000 Ni 9.867438 41.408644 3.283000 C 40.879386 41.506481 0.000000 C 38.060118 41.506481 0.000000 C 36.650484 41.506481 0.000000 C 33.831216 41.506481 0.000000 C 32.421582 41.506481 0.000000 C 29.602314 41.506481 0.000000 C 28.192680 41.506481 0.000000 C 25.373412 41.506481 0.000000 C 23.963778 41.506481 0.000000 C 21.144510 41.506481 0.000000 C 19.734876 41.506481 0.000000 C 16.915608 41.506481 0.000000 C 15.505974 41.506481 0.000000 C 12.686706 41.506481 0.000000 C 11.277072 41.506481 0.000000 C 8.457804 41.506481 0.000000 C 7.048170 41.506481 0.000000 C 4.228902 41.506481 0.000000 C 2.819268 41.506481 0.000000 C 0.000000 41.506481 0.000000 Ni 8.613366 41.995458 3.283000 Ni 11.121510 41.995458 3.283000 Ni 40.444769 42.109621 3.283000 Ni 0.434617 42.109621 3.283000 Ni 31.548261 42.121924 3.283000 Ni 34.704537 42.121924 3.283000 C 40.174569 42.727260 0.000000 C 38.764935 42.727260 0.000000 C 35.945667 42.727260 0.000000 C 34.536033 42.727260 0.000000 C 31.716765 42.727260 0.000000 C 30.307131 42.727260 0.000000 C 27.487863 42.727260 0.000000 C 26.078229 42.727260 0.000000 C 23.258961 42.727260 0.000000 C 21.849327 42.727260 0.000000 C 19.030059 42.727260 0.000000 C 17.620425 42.727260 0.000000 C 14.801157 42.727260 0.000000 C 13.391523 42.727260 0.000000 C 10.572255 42.727260 0.000000 C 9.162621 42.727260 0.000000 C 6.343353 42.727260 0.000000 C 4.933719 42.727260 0.000000 C 2.114451 42.727260 0.000000 C 0.704817 42.727260 0.000000 Ni 41.584203 42.910828 3.283000 Ni 32.386244 43.215571 3.283000 Ni 33.866554 43.215571 3.283000 Ni 8.289300 43.342703 3.283000 Ni 11.445576 43.342703 3.283000 C 40.879386 43.948039 0.000000 C 38.060118 43.948039 0.000000 C 36.650484 43.948039 0.000000 C 33.831216 43.948039 0.000000 C 32.421582 43.948039 0.000000 C 29.602314 43.948039 0.000000 C 28.192680 43.948039 0.000000 C 25.373412 43.948039 0.000000 C 23.963778 43.948039 0.000000 C 21.144510 43.948039 0.000000 C 19.734876 43.948039 0.000000 C 16.915608 43.948039 0.000000 C 15.505974 43.948039 0.000000 C 12.686706 43.948039 0.000000 C 11.277072 43.948039 0.000000 C 8.457804 43.948039 0.000000 C 7.048170 43.948039 0.000000 C 4.228902 43.948039 0.000000 C 2.819268 43.948039 0.000000 C 0.000000 43.948039 0.000000 Ni 9.127283 44.436350 3.283000 Ni 10.607593 44.436350 3.283000 Ni 31.986965 44.551179 3.283000 Ni 34.265833 44.551179 3.283000 C 40.174569 45.168818 0.000000 C 38.764935 45.168818 0.000000 C 35.945667 45.168818 0.000000 C 34.536033 45.168818 0.000000 C 31.716765 45.168818 0.000000 C 30.307131 45.168818 0.000000 C 27.487863 45.168818 0.000000 C 26.078229 45.168818 0.000000 C 23.258961 45.168818 0.000000 C 21.849327 45.168818 0.000000 C 19.030059 45.168818 0.000000 C 17.620425 45.168818 0.000000 C 14.801157 45.168818 0.000000 C 13.391523 45.168818 0.000000 C 10.572255 45.168818 0.000000 C 9.162621 45.168818 0.000000 C 6.343353 45.168818 0.000000 C 4.933719 45.168818 0.000000 C 2.114451 45.168818 0.000000 C 0.704817 45.168818 0.000000 Ni 33.126399 45.352386 3.283000 Ni 8.728004 45.771958 3.283000 Ni 11.006872 45.771958 3.283000 Ni 26.783046 46.291759 3.283000 C 40.879386 46.389596 0.000000 C 38.060118 46.389596 0.000000 C 36.650484 46.389596 0.000000 C 33.831216 46.389596 0.000000 C 32.421582 46.389596 0.000000 C 29.602314 46.389596 0.000000 C 28.192680 46.389596 0.000000 C 25.373412 46.389596 0.000000 C 23.963778 46.389596 0.000000 C 21.144510 46.389596 0.000000 C 19.734876 46.389596 0.000000 C 16.915608 46.389596 0.000000 C 15.505974 46.389596 0.000000 C 12.686706 46.389596 0.000000 C 11.277072 46.389596 0.000000 C 8.457804 46.389596 0.000000 C 7.048170 46.389596 0.000000 C 4.228902 46.389596 0.000000 C 2.819268 46.389596 0.000000 C 0.000000 46.389596 0.000000 Ni 9.867438 46.573165 3.283000 Ni 25.528974 46.878573 3.283000 Ni 28.037118 46.878573 3.283000 Ni 41.584203 47.512538 3.283000 C 40.174569 47.610375 0.000000 C 38.764935 47.610375 0.000000 C 35.945667 47.610375 0.000000 C 34.536033 47.610375 0.000000 C 31.716765 47.610375 0.000000 C 30.307131 47.610375 0.000000 C 27.487863 47.610375 0.000000 C 26.078229 47.610375 0.000000 C 23.258961 47.610375 0.000000 C 21.849327 47.610375 0.000000 C 19.030059 47.610375 0.000000 C 17.620425 47.610375 0.000000 C 14.801157 47.610375 0.000000 C 13.391523 47.610375 0.000000 C 10.572255 47.610375 0.000000 C 9.162621 47.610375 0.000000 C 6.343353 47.610375 0.000000 C 4.933719 47.610375 0.000000 C 2.114451 47.610375 0.000000 C 0.704817 47.610375 0.000000 Ni 40.330131 48.099352 3.283000 Ni 0.549255 48.099352 3.283000 Ni 25.204908 48.225818 3.283000 Ni 28.361184 48.225818 3.283000 v_sim-3.8.0/examples/demo_spin.d3000066400000000000000000000167641370110300500166660ustar00rootroot00000000000000Positions atomiques 3D. 5 5Co 0@/u%F@/u%F@/u%F0 @.}Vl@.}Vl??@.}Vl@.}Vl?@.}Vl@.}Vl@.}Vl??@.}Vl@.}Vl??@.}Vl@.}Vl??@.}Vl@.}Vl?@.}Vl?@.}Vl@.}Vl??@.}Vl@.}Vl??@.}Vl@.}Vl??@.}Vl@.}Vl??@.}Vl@.}Vl?@.}Vl@.}Vl??@.}Vl@.}Vl??@.}Vl@.}Vl@.}Vl?@.}Vl@En/@En/@.}Vl@.}Vl@En/@En/@.}Vl@.}Vl@En/@En/@.}Vl@.}Vl@En/@En/@.}Vl@En/@.}Vl@En/@En/@.}Vl@.}Vl@En/@En/@.}Vl@.}Vl@En/@En/@.}Vl@.}Vl@En/@En/@.}Vl@.}Vl@En/@.}Vl@En/@En/@.}Vl@.}Vl@En/@En/@.}Vl@.}Vl@En/@En/@.}Vl@.}Vl@En/@En/@.}Vl@.}Vl@En/@.}Vl@En/@En/@.}Vl@.}Vl@En/@En/@.}Vl@.}Vl@En/@En/@.}Vl@.}Vl@En/@En/@.}Vl@.}Vl@En/@En/@.}Vl@En/@.}Vl@En/@.}Vl@En/@ .}Vl@#1'@#1'@ .}Vl@ .}Vl@#1'@#1'@ .}Vl@ .}Vl@#1'@#1'@ .}Vl@ .}Vl@#1'@#1'@ .}Vl@ .}Vl@#1'@ .}Vl@#1'@#1'@ .}Vl@ .}Vl@#1'@#1'@ .}Vl@ .}Vl@#1'@#1'@ .}Vl@ .}Vl@#1'@#1'@ .}Vl@ .}Vl@#1'@ .}Vl@#1'@#1'@ .}Vl@ .}Vl@#1'@#1'@ .}Vl@ .}Vl@#1'@#1'@ .}Vl@ .}Vl@#1'@#1'@ .}Vl@ .}Vl@#1'@ .}Vl@#1'@#1'@ .}Vl@ .}Vl@#1'@#1'@ .}Vl@ .}Vl@#1'@#1'@ .}Vl@ .}Vl@#1'@#1'@ .}Vl@ .}Vl@#1'@ .}Vl@#1'@ .}Vl@#1'@ .}Vl@#1'@ .}Vl@#1'@ .}Vl@'En/@'En/@*[W>6@*[W>6@'En/@'En/@*[W>6@*[W>6@'En/@'En/@*[W>6@'En/@'En/@*[W>6@*[W>6@'En/@'En/@*[W>6@*[W>6@'En/@'En/@*[W>6@*[W>6@'En/@'En/@*[W>6@*[W>6@'En/@'En/@*[W>6@'En/@*[W>6@*[W>6@'En/@'En/@*[W>6@*[W>6@'En/@'En/@*[W>6@*[W>6@'En/@'En/@*[W>6@*[W>6@'En/@'En/@*[W>6@'En/@*[W>6@'En/@'En/@*[W>6@*[W>6@'En/@'En/@*[W>6@*[W>6@'En/@'En/@*[W>6@*[W>6@'En/@'En/@'En/@*[W>6@'En/@*[W>6@'En/@.\>@.\>@.\>@.\>@.\>@.\>@.\>@.\>@.\>@.\>@.\>@.\>@.\>@.\>@.\>@.\>@.\>@.\>@.\>@.\>@.\>@.\>@.\>@.\>@.\> ?@.}Vl@.}Vl??@.}Vl@.}Vl@.}Vl@.}Vl@En/@En/@.}Vl@.}Vl@En/@En/@.}Vl@.}Vl@En/@En/@.}Vl@.}Vl@En/@En/@En/@ .}Vl@ .}Vl@#1'@#1'@ .}Vl@ .}Vl@#1'@#1'@ .}Vl@ .}Vl@#1'@#1'@ .}Vl@ .}Vl@#1'@#1'@ .}Vl@#1'@'En/@'En/@'En/@*[W>6@*[W>6@'En/@'En/@*[W>6@*[W>6@'En/@'En/@*[W>6@.\>@.\>@.\>?@.}Vl@.}Vl??@.}Vl@.}Vl??@.}Vl@.}Vl??@.}Vl@.}Vl@.}Vl@.}Vl@.}Vl@En/@En/@.}Vl@.}Vl@En/@En/@.}Vl@.}Vl@En/@En/@.}Vl@.}Vl@En/@En/@.}Vl@En/@ .}Vl@ .}Vl@#1'@#1'@ .}Vl@ .}Vl@#1'@#1'@ .}Vl@ .}Vl@#1'@#1'@ .}Vl@ .}Vl@#1'@#1'@ .}Vl@#1'@'En/@'En/@*[W>6@*[W>6@'En/@'En/@*[W>6@*[W>6@'En/@'En/@*[W>6@*[W>6@'En/@'En/@*[W>6@*[W>6@'En/@*[W>6@.\>@.\>@.\>@.\>@.\>@.\>@.\>??@.}Vl@.}Vl??@.}Vl@.}Vl??@.}Vl@.}Vl??@.}Vl@.}Vl?@.}Vl@.}Vl@.}Vl@En/@En/@.}Vl@.}Vl@En/@En/@.}Vl@.}Vl@En/@En/@.}Vl@.}Vl@En/@En/@.}Vl@En/@ .}Vl@ .}Vl@#1'@#1'@ .}Vl@ .}Vl@#1'@#1'@ .}Vl@ .}Vl@#1'@#1'@ .}Vl@ .}Vl@#1'@#1'@ .}Vl@#1'@'En/@'En/@*[W>6@*[W>6@'En/@'En/@*[W>6@*[W>6@'En/@'En/@*[W>6@*[W>6@'En/@'En/@*[W>6@*[W>6@'En/@*[W>6@.\>@.\>@.\>@.\>@.\>@.\>@.\>@.\>@.\>@.}Vl??@.}Vl@.}Vl??@.}Vl@.}Vl?@.}Vl@.}Vl@.}Vl@.}Vl@En/@En/@.}Vl@.}Vl@En/@En/@.}Vl@.}Vl@En/@En/@.}Vl@.}Vl@En/@En/@.}Vl@En/@ .}Vl@ .}Vl@#1'@#1'@ .}Vl@ .}Vl@#1'@#1'@ .}Vl@ .}Vl@#1'@#1'@ .}Vl@ .}Vl@#1'@#1'@ .}Vl@#1'@'En/@'En/@*[W>6@'En/@'En/@*[W>6@*[W>6@'En/@'En/@*[W>6@*[W>6@'En/@'En/@*[W>6@*[W>6@'En/@.\>@.\>@.\>@.\>@.\>@.}Vl?@.}Vl@En/@.}Vl@En/@.}Vl@En/@.}Vl@En/@ .}Vl@#1'@ .}Vl@#1'@ .}Vl@#1'@ .}Vl@#1'@ .}Vl@'En/@*[W>6@'En/@*[W>6@'En/@.\> @En/@.}Vl@En/@ .}Vl@#1'@ .}Vl@#1'@'En/@.}Vl?@.}Vl@.}Vl@En/@.}Vl@En/@ .}Vl@#1'@ .}Vl@#1'@'En/@*[W>6@'En/@*[W>6@.\>?@.}Vl?@.}Vl@.}Vl@En/@.}Vl@En/@ .}Vl@#1'@ .}Vl@#1'@'En/@*[W>6@'En/@*[W>6@.\>@.\>@.}Vl@.}Vl@En/@.}Vl@En/@ .}Vl@#1'@ .}Vl@#1'@'En/@*[W>6@'En/@En/@ .}Vl@#1'@.}Vl?@.}Vl@.}Vl@En/@.}Vl@En/@ .}Vl@#1'@ .}Vl@#1'@'En/@*[W>6@'En/@*[W>6@.\>?@.}Vl?@.}Vl@.}Vl@En/@.}Vl@En/@ .}Vl@#1'@ .}Vl@#1'@'En/@*[W>6@'En/@*[W>6@.\>@.\>?@.}Vl?@.}Vl@.}Vl@En/@.}Vl@En/@ .}Vl@#1'@ .}Vl@#1'@'En/@*[W>6@'En/@*[W>6@.\>@.\>?@.}Vl?@.}Vl@.}Vl@En/@.}Vl@En/@ .}Vl@#1'@ .}Vl@#1'@'En/@*[W>6@'En/@*[W>6@.\>@.\>@.}Vl@.}Vl@En/@ .}Vl@#1'@'En/@*[W>6?@.}Vl?@.}Vl@.}Vl@En/@.}Vl@En/@ .}Vl@#1'@ .}Vl@#1'@'En/@*[W>6@'En/@*[W>6@.\>@.\>?@.}Vl?@.}Vl@.}Vl@En/@.}Vl@En/@ .}Vl@#1'@ .}Vl@#1'@'En/@*[W>6@'En/@*[W>6@.\>@.\>?@.}Vl?@.}Vl@.}Vl@En/@.}Vl@En/@ .}Vl@#1'@ .}Vl@#1'@'En/@*[W>6@'En/@*[W>6@.\>@.\>?@.}Vl?@.}Vl@.}Vl@En/@.}Vl@En/@ .}Vl@#1'@ .}Vl@#1'@'En/@*[W>6@'En/@*[W>6@.\>@.\>?@.}Vl@.}Vl@En/@ .}Vl@#1'@'En/@*[W>6@.\>@.}Vl@.}Vl@En/@.}Vl@En/@ .}Vl@#1'@ .}Vl@#1'@'En/@'En/@*[W>6?@.}Vl?@.}Vl@.}Vl@En/@.}Vl@En/@ .}Vl@#1'@ .}Vl@#1'@'En/@*[W>6@'En/@*[W>6@.\>@.\>?@.}Vl?@.}Vl@.}Vl@En/@.}Vl@En/@ .}Vl@#1'@ .}Vl@#1'@'En/@*[W>6@'En/@*[W>6@.\>@.\>?@.}Vl@.}Vl@.}Vl@En/@.}Vl@En/@ .}Vl@#1'@ .}Vl@#1'@'En/@*[W>6@'En/@*[W>6@.\>@.}Vl@En/@ .}Vl@#1'@'En/@En/@ .}Vl@#1'@.}Vl@.}Vl@En/@ .}Vl@#1'@'En/@*[W>6?@.}Vl@.}Vl@En/@ .}Vl@#1'@'En/@*[W>6@.\>@.}Vl@En/@ .}Vl@#1'@'En/@ .}Vl v_sim-3.8.0/examples/demo_spin.spin000066400000000000000000000632221370110300500173200ustar00rootroot00000000000000 309 spins [mi_magnet 5/ 8/2005 16h. 33mn. 34s.] 1 0.153720000000000E-19 0.918208753776186E+02 0.147958518961907E+03 2 0.153720000000000E-19 0.981262168766058E+02 0.128897414709384E+03 3 0.153720000000000E-19 0.107656426709260E+03 0.115968657955198E+03 4 0.153720000000000E-19 0.104055312849868E+03 0.135367823703964E+03 5 0.153720000000000E-19 0.108797043242461E+03 0.154595738070520E+03 6 0.153720000000000E-19 0.968663483709659E+02 0.135277160291596E+03 7 0.153720000000000E-19 0.910609826857498E+02 0.122435632108987E+03 8 0.153720000000000E-19 0.984132776670431E+02 0.141927578829619E+03 9 0.153720000000000E-19 0.100738023144548E+03 0.116409291745864E+03 10 0.153720000000000E-19 0.951453393927765E+02 0.104115835397709E+03 11 0.153720000000000E-19 0.104358721380705E+03 0.972018853470579E+02 12 0.153720000000000E-19 0.108827983482391E+03 0.105265408721338E+03 13 0.153720000000000E-19 0.957568521947007E+02 0.115493310810805E+03 14 0.153720000000000E-19 0.938592798858775E+02 0.102208382829287E+03 15 0.153720000000000E-19 0.968112351851991E+02 0.962358982494064E+02 16 0.153720000000000E-19 0.963652881494200E+02 0.104885226814504E+03 17 0.153720000000000E-19 0.891859611687746E+02 0.121220032016575E+03 18 0.153720000000000E-19 0.873721651891317E+02 0.102994108048791E+03 19 0.153720000000000E-19 0.895744564510215E+02 0.982521023613757E+02 20 0.153720000000000E-19 0.816673750978014E+02 0.112836486694710E+03 21 0.153720000000000E-19 0.878082076499980E+02 0.129971648453243E+03 22 0.153720000000000E-19 0.837165717219787E+02 0.108256989765592E+03 23 0.153720000000000E-19 0.806760470674415E+02 0.105282772571551E+03 24 0.153720000000000E-19 0.856826268765424E+02 0.117961030400768E+03 25 0.153720000000000E-19 0.903639068344780E+02 0.859544249841534E+02 26 0.153720000000000E-19 0.883212572239590E+02 0.867796365436785E+02 27 0.153720000000000E-19 0.850239723517062E+02 0.656617736785253E+02 28 0.153720000000000E-19 0.792702195853489E+02 0.765101886156107E+02 29 0.153720000000000E-19 0.916560095242037E+02 0.885748600224633E+02 30 0.153720000000000E-19 0.854474064514874E+02 0.898307073679660E+02 31 0.153720000000000E-19 0.822843244202630E+02 0.740161572973152E+02 32 0.153720000000000E-19 0.874354123247119E+02 0.823352526247933E+02 33 0.153720000000000E-19 0.912100217742308E+02 0.900554139207985E+02 34 0.153720000000000E-19 0.845924580176903E+02 0.906502850363942E+02 35 0.153720000000000E-19 0.849265270157966E+02 0.775265163541650E+02 36 0.153720000000000E-19 0.946225628386394E+02 0.834806860681420E+02 37 0.153720000000000E-19 0.915020027824033E+02 0.916892877429596E+02 38 0.153720000000000E-19 0.871256373183968E+02 0.941354560495114E+02 39 0.153720000000000E-19 0.905837433080781E+02 0.766441299874661E+02 40 0.153720000000000E-19 0.103063174444336E+03 0.823670689756905E+02 41 0.153720000000000E-19 0.900561314179558E+02 0.951878796384809E+02 42 0.153720000000000E-19 0.931950452284099E+02 0.752472162025276E+02 43 0.153720000000000E-19 0.835136613826249E+02 0.549413663448683E+02 44 0.153720000000000E-19 0.778420549807558E+02 0.694156724918977E+02 45 0.153720000000000E-19 0.850039413646267E+02 0.609526110604814E+02 46 0.153720000000000E-19 0.922520335272437E+02 0.421765199127961E+02 47 0.153720000000000E-19 0.850134193992967E+02 0.594999913493116E+02 48 0.153720000000000E-19 0.921981853905151E+02 0.752523750986412E+02 49 0.153720000000000E-19 0.912452313320103E+02 0.633117231267531E+02 50 0.153720000000000E-19 0.913641787953528E+02 0.449976012986465E+02 51 0.153720000000000E-19 0.102981553977062E+03 0.628637903990295E+02 52 0.153720000000000E-19 0.105920268998696E+03 0.734225370049746E+02 53 0.153720000000000E-19 0.964928835377597E+02 0.603457395771277E+02 54 0.153720000000000E-19 0.922535168086087E+02 0.478202034380883E+02 55 0.153720000000000E-19 0.102988577398399E+03 0.271324187612992E+02 56 0.153720000000000E-19 0.967896211717540E+02 0.449977604950162E+02 57 0.153720000000000E-19 0.850199620355266E+02 0.304974576326736E+02 58 0.153720000000000E-19 0.832834000470526E+02 0.163494821037368E+03 59 0.153720000000000E-19 0.880175907163896E+02 0.150056097737266E+03 60 0.153720000000000E-19 0.893351131576851E+02 0.139894751176460E+03 61 0.153720000000000E-19 0.837505848111609E+02 0.156997578993529E+03 62 0.153720000000000E-19 0.943890370186016E+02 0.171340960221538E+03 63 0.153720000000000E-19 0.883513281452454E+02 0.160241726617283E+03 64 0.153720000000000E-19 0.912869561736940E+02 0.149054158180231E+03 65 0.153720000000000E-19 0.991121148188033E+02 0.165350840338310E+03 66 0.153720000000000E-19 0.101280734107805E+03 0.174636582036684E+03 67 0.153720000000000E-19 0.918678656695631E+02 0.167722640915129E+03 68 0.153720000000000E-19 0.972168951796680E+02 0.155654169242473E+03 69 0.153720000000000E-19 0.110924414403556E+03 0.166070838060885E+03 70 0.153720000000000E-19 0.106736177401381E+03 0.175530434780704E+03 71 0.153720000000000E-19 0.962671567547934E+02 0.170843581493139E+03 72 0.153720000000000E-19 0.101720599092686E+03 0.156266891939720E+03 73 0.153720000000000E-19 0.955413353925272E+02 0.171105421515740E+03 74 0.153720000000000E-19 0.916276389392183E+02 0.125551642876964E+03 75 0.153720000000000E-19 0.847329250866417E+02 0.145083674550188E+03 76 0.153720000000000E-19 0.812370938161036E+02 0.123299477563250E+03 77 0.153720000000000E-19 0.862932061019818E+02 0.110295592162898E+03 78 0.153720000000000E-19 0.888437148544340E+02 0.129516730196040E+03 79 0.153720000000000E-19 0.791414328391479E+02 0.154665870209379E+03 80 0.153720000000000E-19 0.662220950361308E+02 0.133091297510578E+03 81 0.153720000000000E-19 0.778572126515043E+02 0.113178151631345E+03 82 0.153720000000000E-19 0.849594168718424E+02 0.135831619844816E+03 83 0.153720000000000E-19 0.787587482094439E+02 0.160627842069236E+03 84 0.153720000000000E-19 0.570526415494540E+02 0.138453180320661E+03 85 0.153720000000000E-19 0.735670474658189E+02 0.116200225221754E+03 86 0.153720000000000E-19 0.868933729499117E+02 0.142046848789657E+03 87 0.153720000000000E-19 0.839420446009097E+02 0.166386730581672E+03 88 0.153720000000000E-19 0.564930232042758E+02 0.142442060366936E+03 89 0.153720000000000E-19 0.785255653256647E+02 0.122800010855536E+03 90 0.153720000000000E-19 0.900754391817982E+02 0.147651713118578E+03 91 0.153720000000000E-19 0.713359365270181E+02 0.153467657341561E+03 92 0.153720000000000E-19 0.848772849108432E+02 0.848197841151049E+02 93 0.153720000000000E-19 0.594917071793219E+02 0.969470099420935E+02 94 0.153720000000000E-19 0.736789759180671E+02 0.530689218325734E+02 95 0.153720000000000E-19 0.786285842754052E+02 0.642924419297026E+02 96 0.153720000000000E-19 0.747262370879032E+02 0.905619418004292E+02 97 0.153720000000000E-19 0.445906646211507E+02 0.964571232585695E+02 98 0.153720000000000E-19 0.569388369350721E+02 0.503347577579780E+02 99 0.153720000000000E-19 0.722036053358122E+02 0.673634921068056E+02 100 0.153720000000000E-19 0.693335359734771E+02 0.910792876938119E+02 101 0.153720000000000E-19 0.392859214287789E+02 0.906191829989384E+02 102 0.153720000000000E-19 0.519535742861722E+02 0.449688309242843E+02 103 0.153720000000000E-19 0.729294551686280E+02 0.664715854172454E+02 104 0.153720000000000E-19 0.701318920331224E+02 0.904525068449758E+02 105 0.153720000000000E-19 0.437512667416611E+02 0.821399721370912E+02 106 0.153720000000000E-19 0.570273616732338E+02 0.396396519295173E+02 107 0.153720000000000E-19 0.801944450031769E+02 0.650774393344206E+02 108 0.153720000000000E-19 0.812734332450353E+02 0.974084809804673E+02 109 0.153720000000000E-19 0.737648954745384E+02 0.369521782741463E+02 110 0.153720000000000E-19 0.873945128319830E+02 0.430267838366604E+02 111 0.153720000000000E-19 0.801609397372084E+02 0.248835148608745E+02 112 0.153720000000000E-19 0.931931414262145E+02 0.147165418439899E+02 113 0.153720000000000E-19 0.964938074411239E+02 0.296385287562660E+02 114 0.153720000000000E-19 0.827061812819708E+02 0.438415629054693E+02 115 0.153720000000000E-19 0.729317563051082E+02 0.234952254700781E+02 116 0.153720000000000E-19 0.905991772120016E+02 0.133344913304031E+02 117 0.153720000000000E-19 0.912511714497936E+02 0.266820206292131E+02 118 0.153720000000000E-19 0.797802779561741E+02 0.449939889793210E+02 119 0.153720000000000E-19 0.722437454806211E+02 0.226274329880699E+02 120 0.153720000000000E-19 0.849613936646827E+02 0.124717482633040E+02 121 0.153720000000000E-19 0.850212140112288E+02 0.290481675139825E+02 122 0.153720000000000E-19 0.827243832848504E+02 0.461488200333366E+02 123 0.153720000000000E-19 0.786769824985727E+02 0.257358010870222E+02 124 0.153720000000000E-19 0.823191905747306E+02 0.159957797291935E+02 125 0.153720000000000E-19 0.835288918801617E+02 0.350636474298856E+02 126 0.153720000000000E-19 0.874126978572675E+02 0.469684544938280E+02 127 0.153720000000000E-19 0.850409843534735E+02 0.243565634235538E+02 128 0.153720000000000E-19 0.103078001834870E+03 0.761417226711830E+01 129 0.153720000000000E-19 0.105933539764138E+03 0.165697227289200E+02 130 0.153720000000000E-19 0.946515405156089E+02 0.651310163461715E+01 131 0.153720000000000E-19 0.922178755528345E+02 0.147447273638738E+02 132 0.153720000000000E-19 0.874703908012233E+02 0.766761226602838E+01 133 0.153720000000000E-19 0.778585827139441E+02 0.205867030116366E+02 134 0.153720000000000E-19 0.792894255153850E+02 0.135000409122764E+02 135 0.153720000000000E-19 0.917906089949904E+02 0.173108154292768E+03 136 0.153720000000000E-19 0.107798344266444E+03 0.184085223642807E+03 137 0.153720000000000E-19 0.973278788564400E+02 0.188356141830748E+03 138 0.153720000000000E-19 0.924111001175221E+02 0.171409293806737E+03 139 0.153720000000000E-19 0.972908716205462E+02 0.176530359445692E+03 140 0.153720000000000E-19 0.103126630680993E+03 0.185177715876063E+03 141 0.153720000000000E-19 0.992254720988856E+02 0.188434569925754E+03 142 0.153720000000000E-19 0.922805047977342E+02 0.177985127520255E+03 143 0.153720000000000E-19 0.984549202389557E+02 0.180084856506915E+03 144 0.153720000000000E-19 0.963733231028734E+02 0.189241329824603E+03 145 0.153720000000000E-19 0.941640248366337E+02 0.192925772686409E+03 146 0.153720000000000E-19 0.915833867405494E+02 0.182757741343161E+03 147 0.153720000000000E-19 0.971425819025358E+02 0.183719979398165E+03 148 0.153720000000000E-19 0.846612095586820E+02 0.198006655928026E+03 149 0.153720000000000E-19 0.897745596166772E+02 0.202118181401122E+03 150 0.153720000000000E-19 0.911950785368090E+02 0.189488094888712E+03 151 0.153720000000000E-19 0.916329749568709E+02 0.187716696116142E+03 152 0.153720000000000E-19 0.887330547769193E+02 0.212941683853477E+03 153 0.153720000000000E-19 0.873317852937430E+02 0.163085136621486E+03 154 0.153720000000000E-19 0.902895995842507E+02 0.190648118550328E+03 155 0.153720000000000E-19 0.817282314804433E+02 0.191618444192580E+03 156 0.153720000000000E-19 0.661772790328666E+02 0.164735776839672E+03 157 0.153720000000000E-19 0.812246779322670E+02 0.173562161963152E+03 158 0.153720000000000E-19 0.835706502716043E+02 0.199514867813750E+03 159 0.153720000000000E-19 0.671749219563972E+02 0.212390610270352E+03 160 0.153720000000000E-19 0.514143728506926E+02 0.178766585322418E+03 161 0.153720000000000E-19 0.765326114581508E+02 0.181208629811623E+03 162 0.153720000000000E-19 0.807775804789998E+02 0.208943199407398E+03 163 0.153720000000000E-19 0.621865929777061E+02 0.225030347059038E+03 164 0.153720000000000E-19 0.470864007275458E+02 0.189009461247688E+03 165 0.153720000000000E-19 0.773715568507317E+02 0.188777451644313E+03 166 0.153720000000000E-19 0.849380814994829E+02 0.221960482155687E+03 167 0.153720000000000E-19 0.671072842138069E+02 0.237656599778709E+03 168 0.153720000000000E-19 0.534714217101525E+02 0.205847371697945E+03 169 0.153720000000000E-19 0.836972034200412E+02 0.198819796890445E+03 170 0.153720000000000E-19 0.816719545483550E+02 0.258467497509074E+03 171 0.153720000000000E-19 0.452904621962800E+02 0.134508776865426E+03 172 0.153720000000000E-19 0.536948764275220E+02 0.244051543407262E+03 173 0.153720000000000E-19 0.714286028136464E+02 0.296115760125651E+03 174 0.153720000000000E-19 0.436206751197078E+02 0.758176200071891E+01 175 0.153720000000000E-19 0.131989327183022E+02 0.159190727283121E+03 176 0.153720000000000E-19 0.471797269803317E+02 0.261013760502019E+03 177 0.153720000000000E-19 0.565873416879088E+02 0.307413492469681E+03 178 0.153720000000000E-19 0.393028803866827E+02 0.359241429642229E+03 179 0.153720000000000E-19 0.560901677301279E+01 0.225457338228243E+03 180 0.153720000000000E-19 0.514382650983778E+02 0.271340806367047E+03 181 0.153720000000000E-19 0.571377762630078E+02 0.311551060007264E+03 182 0.153720000000000E-19 0.446799478534127E+02 0.353560121229244E+03 183 0.153720000000000E-19 0.132043894270751E+02 0.291682151580716E+03 184 0.153720000000000E-19 0.661640233205417E+02 0.285478094731800E+03 185 0.153720000000000E-19 0.662942147057757E+02 0.317035544272179E+03 186 0.153720000000000E-19 0.596178639632786E+02 0.353234757428907E+03 187 0.153720000000000E-19 0.452703213814565E+02 0.316405457769747E+03 188 0.153720000000000E-19 0.812886890081098E+02 0.326992680457742E+03 189 0.153720000000000E-19 0.812474360548718E+02 0.352488592712672E+03 190 0.153720000000000E-19 0.785724240270051E+02 0.327063715443110E+03 191 0.153720000000000E-19 0.857086456669661E+02 0.331972427500745E+03 192 0.153720000000000E-19 0.871407481654022E+02 0.355818189063728E+03 193 0.153720000000000E-19 0.701411417975934E+02 0.359476362163416E+03 194 0.153720000000000E-19 0.736322852736214E+02 0.333747045023444E+03 195 0.153720000000000E-19 0.837774134038248E+02 0.341694883716887E+03 196 0.153720000000000E-19 0.846328890649937E+02 0.359331022278026E+03 197 0.153720000000000E-19 0.693910806754094E+02 0.358898859076454E+03 198 0.153720000000000E-19 0.779327470664367E+02 0.336849534579753E+03 199 0.153720000000000E-19 0.874451429503056E+02 0.347004561403328E+03 200 0.153720000000000E-19 0.854998149968175E+02 0.180092907680517E+00 201 0.153720000000000E-19 0.748060124756345E+02 0.359483112272185E+03 202 0.153720000000000E-19 0.863656233737902E+02 0.339810603481419E+03 203 0.153720000000000E-19 0.939230785440560E+02 0.347826277401942E+03 204 0.153720000000000E-19 0.883590526859944E+02 0.325501425610566E+01 205 0.153720000000000E-19 0.849145483819230E+02 0.525792227658935E+01 206 0.153720000000000E-19 0.951748206552050E+02 0.345934324629183E+03 207 0.153720000000000E-19 0.900644275735043E+02 0.354784951488104E+03 208 0.153720000000000E-19 0.807154734175169E+02 0.344682907298770E+03 209 0.153720000000000E-19 0.915414567495973E+02 0.358294743515967E+03 210 0.153720000000000E-19 0.896388421941480E+02 0.351736091779706E+03 211 0.153720000000000E-19 0.912639163639559E+02 0.359943090882521E+03 212 0.153720000000000E-19 0.968745489724729E+02 0.353774091990167E+03 213 0.153720000000000E-19 0.916993405555229E+02 0.143795261194798E+01 214 0.153720000000000E-19 0.104393670819117E+03 0.352825374286044E+03 215 0.153720000000000E-19 0.903759657366161E+02 0.406012982720612E+01 216 0.153720000000000E-19 0.105220341338558E+03 0.201276947924312E+03 217 0.153720000000000E-19 0.113190163811795E+03 0.192908152043853E+03 218 0.153720000000000E-19 0.112674247563758E+03 0.204445314305272E+03 219 0.153720000000000E-19 0.103521249059153E+03 0.215233400935018E+03 220 0.153720000000000E-19 0.101278398701871E+03 0.203384096313289E+03 221 0.153720000000000E-19 0.102803881744325E+03 0.194815243350463E+03 222 0.153720000000000E-19 0.977973532275613E+02 0.213957016307440E+03 223 0.153720000000000E-19 0.102058373246190E+03 0.225002227553215E+03 224 0.153720000000000E-19 0.952442671014143E+02 0.213069215427282E+03 225 0.153720000000000E-19 0.876277102555801E+02 0.205136211341446E+03 226 0.153720000000000E-19 0.103523470243081E+03 0.234772842055527E+03 227 0.153720000000000E-19 0.932425794080445E+02 0.224570428375733E+03 228 0.153720000000000E-19 0.940603395078986E+02 0.206879431924348E+03 229 0.153720000000000E-19 0.932509226864596E+02 0.225426981078925E+03 230 0.153720000000000E-19 0.887539421926179E+02 0.237041052420198E+03 231 0.153720000000000E-19 0.849835886641029E+02 0.228032812560383E+03 232 0.153720000000000E-19 0.929065959380137E+02 0.214205177046751E+03 233 0.153720000000000E-19 0.952578336218214E+02 0.236940367181845E+03 234 0.153720000000000E-19 0.898231418555504E+02 0.247873934079166E+03 235 0.153720000000000E-19 0.808133815993144E+02 0.241059634973185E+03 236 0.153720000000000E-19 0.900100228215119E+02 0.225003861973293E+03 237 0.153720000000000E-19 0.101293845695030E+03 0.246633187280323E+03 238 0.153720000000000E-19 0.942024218918001E+02 0.257082770989828E+03 239 0.153720000000000E-19 0.835882617170392E+02 0.250507014627309E+03 240 0.153720000000000E-19 0.928822050387954E+02 0.235809080371743E+03 241 0.153720000000000E-19 0.105234508147716E+03 0.248742511863686E+03 242 0.153720000000000E-19 0.992371776773114E+02 0.261593803844224E+03 243 0.153720000000000E-19 0.902871237071365E+02 0.259407558112380E+03 244 0.153720000000000E-19 0.940524919092207E+02 0.243152279689297E+03 245 0.153720000000000E-19 0.973347734028799E+02 0.261684763836460E+03 246 0.153720000000000E-19 0.837613934592725E+02 0.251098883065442E+03 247 0.153720000000000E-19 0.912398197450195E+02 0.260476580794689E+03 248 0.153720000000000E-19 0.955795034807096E+02 0.278838917485610E+03 249 0.153720000000000E-19 0.840369359380632E+02 0.283493542588466E+03 250 0.153720000000000E-19 0.774725421754243E+02 0.261176613424613E+03 251 0.153720000000000E-19 0.916391340325775E+02 0.267236261904917E+03 252 0.153720000000000E-19 0.963497700540005E+02 0.279120325475232E+03 253 0.153720000000000E-19 0.788423753558586E+02 0.289338466805117E+03 254 0.153720000000000E-19 0.765958653059499E+02 0.268807400554717E+03 255 0.153720000000000E-19 0.923352174881665E+02 0.272042047669058E+03 256 0.153720000000000E-19 0.919440972264010E+02 0.282285934085096E+03 257 0.153720000000000E-19 0.792075522507790E+02 0.295377118286305E+03 258 0.153720000000000E-19 0.812459305524987E+02 0.276502073105009E+03 259 0.153720000000000E-19 0.924406653262606E+02 0.278638955147008E+03 260 0.153720000000000E-19 0.884069370514122E+02 0.289805449063030E+03 261 0.153720000000000E-19 0.847874539316248E+02 0.305034609532730E+03 262 0.153720000000000E-19 0.873330486130517E+02 0.287020347491105E+03 263 0.153720000000000E-19 0.880487045344674E+02 0.300010113417177E+03 264 0.153720000000000E-19 0.901348602582418E+02 0.302199602883241E+03 265 0.153720000000000E-19 0.101793755468655E+03 0.293661404271586E+03 266 0.153720000000000E-19 0.878864209120275E+02 0.319949717975016E+03 267 0.153720000000000E-19 0.869849319522394E+02 0.307874831341615E+03 268 0.153720000000000E-19 0.972930198712245E+02 0.294324883392906E+03 269 0.153720000000000E-19 0.985049785014545E+02 0.308018699950868E+03 270 0.153720000000000E-19 0.892614892917086E+02 0.328751357042796E+03 271 0.153720000000000E-19 0.850427517561306E+02 0.314170061380212E+03 272 0.153720000000000E-19 0.913681140162761E+02 0.300979577803705E+03 273 0.153720000000000E-19 0.969502793338031E+02 0.314721935512374E+03 274 0.153720000000000E-19 0.958329701729385E+02 0.334533841719940E+03 275 0.153720000000000E-19 0.889181818864605E+02 0.320551915122753E+03 276 0.153720000000000E-19 0.894105567918471E+02 0.310175669722219E+03 277 0.153720000000000E-19 0.982116333160673E+02 0.321155245584175E+03 278 0.153720000000000E-19 0.100802903566362E+03 0.333652615021205E+03 279 0.153720000000000E-19 0.916762022879496E+02 0.324567483955626E+03 280 0.153720000000000E-19 0.817433639294407E+02 0.337128859860710E+03 281 0.153720000000000E-19 0.911591901226842E+02 0.327537759967937E+03 282 0.153720000000000E-19 0.964465074479308E+02 0.345112858913414E+03 283 0.153720000000000E-19 0.107729441067555E+03 0.334051487651779E+03 284 0.153720000000000E-19 0.108882850061864E+03 0.344762289825269E+03 285 0.153720000000000E-19 0.978033960897058E+02 0.236043715633942E+03 286 0.153720000000000E-19 0.110985233610429E+03 0.225001192967105E+03 287 0.153720000000000E-19 0.112683754856285E+03 0.245556511505113E+03 288 0.153720000000000E-19 0.846829102133808E+02 0.251980334767300E+03 289 0.153720000000000E-19 0.876459364804726E+02 0.244861046205312E+03 290 0.153720000000000E-19 0.964112682437566E+02 0.260755923385053E+03 291 0.153720000000000E-19 0.102825998188338E+03 0.255184192118316E+03 292 0.153720000000000E-19 0.103163941076524E+03 0.264829391429637E+03 293 0.153720000000000E-19 0.113207047491815E+03 0.257100386295909E+03 294 0.153720000000000E-19 0.107820263157219E+03 0.265933993255387E+03 295 0.153720000000000E-19 0.916482254793818E+02 0.262268017086819E+03 296 0.153720000000000E-19 0.106775314408033E+03 0.274437177968716E+03 297 0.153720000000000E-19 0.971945112986331E+02 0.266265076574787E+03 298 0.153720000000000E-19 0.101347836642765E+03 0.275352546636602E+03 299 0.153720000000000E-19 0.985138434689115E+02 0.269913552153628E+03 300 0.153720000000000E-19 0.944614110710391E+02 0.278670995145976E+03 301 0.153720000000000E-19 0.973344986349568E+02 0.273486979453433E+03 302 0.153720000000000E-19 0.833277967563459E+02 0.286539088404136E+03 303 0.153720000000000E-19 0.918024437577138E+02 0.276919333206543E+03 304 0.153720000000000E-19 0.110984304771874E+03 0.283898536598521E+03 305 0.153720000000000E-19 0.108872076396721E+03 0.295383033640307E+03 306 0.153720000000000E-19 0.991962540198020E+02 0.284647794090248E+03 307 0.153720000000000E-19 0.919187297354377E+02 0.302067462694708E+03 308 0.153720000000000E-19 0.838269879804949E+02 0.293036915191419E+03 309 0.153720000000000E-19 0.104163063898865E+03 0.314632923421369E+03 mi_magnet info sur ext, the_ext, phi_ext: 0.00000000000000D+000 0.00000000000000D+000 0.00000000000000D+000 mi_magnet info sur anis, the_anis, phi_anis: 0.00000000000000D+000 0.00000000000000D+000 0.00000000000000D+000 v_sim-3.8.0/examples/density-sih4.dat000066400000000000000000022664031370110300500174760ustar00rootroot00000000000000 Grid for testing 30 30 30 10. 0. 10. 0. 0. 10. xyz periodic 4.73652474252816E-7 8.731497576473942E-7 9.817260510168E-7 0.0000011014415294973527 0.000003129312492499613 0.00000956561795367725 0.000017222828270284477 0.000020168309059148432 0.000022151566164277554 0.00002876807497365709 0.00003655595560015854 0.00003710588664386429 0.0000326951435086569 0.00003299600592525289 0.000039996705480559104 0.00004478315592366391 0.000039996705480558996 0.00003299600592525289 0.0000326951435086569 0.00003710588664386418 0.00003655595560015859 0.000028768074973657036 0.000022151566164277554 0.000020168309059148432 0.000017222828270284477 0.000009565617953677223 0.000003129312492499613 0.0000011014415294973662 9.817260510167865E-7 8.731497576473434E-7 8.7314975764729E-7 0.000001572758838964555 0.0000021373228939780984 0.0000024559531885521286 0.000004556866447378803 0.00001051283086449952 0.000017412833723629524 0.00002043402073580928 0.00002254157915947913 0.000028324619977963402 0.00003557185750931382 0.00003732366030448026 0.00003494468682886889 0.000035973655853699436 0.000041943241076209215 0.00004589492550742054 0.00004194324107620919 0.000035973655853699436 0.00003494468682886887 0.00003732366030448028 0.00003557185750931379 0.000028324619977963324 0.000022541579159479208 0.00002043402073580931 0.00001741283372362949 0.000010512830864499486 0.000004556866447378799 0.0000024559531885521413 0.0000021373228939780946 0.000001572758838964499 9.817260510166362E-7 0.0000021373228939780696 0.000003996439040510895 0.0000060047954966968644 0.000009341733308209034 0.000014781998225035517 0.0000207814513884258 0.00002521359185904715 0.000029077834577926722 0.000034395759926610535 0.00004131938524832004 0.000046397958466130725 0.00004926469609027373 0.000052163891300051554 0.00005534744024333387 0.000057049049509911594 0.00005534744024333374 0.000052163891300051493 0.00004926469609027365 0.000046397958466130644 0.00004131938524832002 0.00003439575992661042 0.000029077834577926725 0.000025213591859047158 0.000020781451388425793 0.00001478199822503547 0.000009341733308209026 0.00000600479549669688 0.000003996439040510875 0.000002137322893978012 0.0000011014415294973 0.00000245595318855219 0.000006004795496696907 0.00001130838817807543 0.000017423225697002 0.000023945460612412804 0.000031838852771596376 0.00004158095417466843 0.00005157501937403713 0.000060288850131598055 0.00006927841106991465 0.00007921512669109889 0.00008836635431708629 0.0000929621703342678 0.00009223278715530918 0.00009102652667143358 0.00009223278715530911 0.00009296217033426784 0.00008836635431708633 0.00007921512669109902 0.00006927841106991464 0.000060288850131597954 0.00005157501937403713 0.000041580954174668434 0.00003183885277159631 0.00002394546061241277 0.00001742322569700198 0.000011308388178075445 0.000006004795496696895 0.0000024559531885521315 0.0000031293124924995295 0.0000045568664473788485 0.000009341733308209056 0.000017423225697002007 0.00002659310644048791 0.00003634591631691762 0.00005006992510114424 0.00007002096897945217 0.00009202672100430485 0.00010990207288447243 0.0001244369771430504 0.00013968876242537664 0.00015338033482130143 0.00015775652622947948 0.00015267581316422986 0.00014878985649779478 0.0001526758131642298 0.00015775652622947948 0.00015338033482130138 0.0001396887624253766 0.0001244369771430505 0.00010990207288447232 0.00009202672100430489 0.00007002096897945223 0.00005006992510114419 0.000036345916316917585 0.000026593106440487877 0.00001742322569700202 0.00000934173330820904 0.000004556866447378791 0.000009565617953677157 0.000010512830864499584 0.000014781998225035556 0.000023945460612412905 0.00003634591631691774 0.00005142955062686039 0.00007364236764164765 0.00010639592520414873 0.00014390693080602865 0.00017526872371932762 0.00019823253447444456 0.00021814488333106853 0.00023414234946933713 0.00023864228845880243 0.000232347104625103 0.00022768469543646452 0.00023234710462510287 0.00023864228845880237 0.0002341423494693371 0.00021814488333106848 0.00019823253447444456 0.00017526872371932748 0.00014390693080602868 0.00010639592520414873 0.00007364236764164755 0.000051429550626860336 0.00003634591631691769 0.00002394546061241291 0.000014781998225035534 0.000010512830864499533 0.000017222828270284307 0.0000174128337236295 0.00002078145138842572 0.00003183885277159634 0.00005006992510114432 0.00007364236764164751 0.00010556425488906758 0.00014926894555381768 0.00019991623908953302 0.00024516722341407903 0.00027877854625725496 0.0003040176982251545 0.0003235039291855624 0.00033441079730572653 0.0003361344573057893 0.0003352029974325339 0.0003361344573057892 0.00033441079730572653 0.0003235039291855624 0.0003040176982251546 0.00027877854625725496 0.0002451672234140789 0.0001999162390895331 0.0001492689455538177 0.00010556425488906753 0.00007364236764164748 0.00005006992510114427 0.00003183885277159635 0.00002078145138842569 0.000017412833723629453 0.000020168309059148307 0.000020434020735809416 0.000025213591859047212 0.000041580954174668576 0.00007002096897945247 0.00010639592520414889 0.00014926894555381806 0.0002010143453447904 0.0002615690115628146 0.00032132396993738853 0.00036883179365408003 0.00040141036955367216 0.00042623502672549575 0.000449610976650894 0.00046879496476522574 0.0004764957920562696 0.00046879496476522563 0.000449610976650894 0.0004262350267254957 0.00040141036955367216 0.00036883179365408003 0.0003213239699373884 0.00026156901156281463 0.00020101434534479043 0.00014926894555381795 0.00010639592520414886 0.0000700209689794524 0.00004158095417466857 0.000025213591859047182 0.000020434020735809372 0.00002215156616427748 0.000022541579159479245 0.000029077834577926756 0.00005157501937403711 0.00009202672100430512 0.00014390693080602868 0.00019991623908953332 0.0002615690115628144 0.00033609296454867885 0.00041701622182258394 0.0004837211007552422 0.0005240339424709021 0.0005506553884725052 0.0005832294783845775 0.0006197248184155329 0.0006368373327308808 0.0006197248184155328 0.0005832294783845774 0.0005506553884725052 0.0005240339424709022 0.00048372110075524215 0.00041701622182258377 0.00033609296454867885 0.0002615690115628144 0.00019991623908953323 0.00014390693080602865 0.00009202672100430502 0.00005157501937403712 0.000029077834577926722 0.000022541579159479208 0.000028768074973657084 0.00002832461997796342 0.00003439575992661068 0.00006028885013159811 0.00010990207288447273 0.0001752687237193278 0.0002451672234140793 0.0003213239699373884 0.00041701622182258377 0.0005262171083925534 0.0006161255593246747 0.0006638652867328147 0.0006876207794232068 0.0007212546483763897 0.0007667896670978377 0.0007897162282245125 0.0007667896670978376 0.0007212546483763899 0.0006876207794232068 0.0006638652867328147 0.0006161255593246747 0.0005262171083925533 0.0004170162218225838 0.0003213239699373885 0.00024516722341407925 0.0001752687237193278 0.00010990207288447265 0.000060288850131598116 0.00003439575992661066 0.000028324619977963392 0.000036555955600158483 0.00003557185750931371 0.000041319385248320063 0.00006927841106991455 0.0001244369771430508 0.0001982325344744446 0.0002787785462572553 0.0003688317936540799 0.0004837211007552419 0.0006161255593246748 0.0007258557129460845 0.0007842331047055573 0.0008116561588309146 0.0008486525878630218 0.0008995969267711847 0.0009254338743022511 0.0008995969267711845 0.0008486525878630218 0.0008116561588309146 0.0007842331047055573 0.0007258557129460845 0.0006161255593246748 0.000483721100755242 0.00036883179365408 0.00027877854625725523 0.0001982325344744446 0.00012443697714305073 0.00006927841106991455 0.00004131938524832002 0.000035571857509313694 0.00003710588664386422 0.00003732366030448009 0.000046397958466130834 0.00007921512669109885 0.00013968876242537683 0.00021814488333106864 0.00030401769822515474 0.0004014103695536721 0.0005240339424709018 0.0006638652867328144 0.0007842331047055572 0.0008602438311349426 0.0009088671603585743 0.0009628131037069255 0.0010223797079019653 0.001050310032841179 0.0010223797079019653 0.0009628131037069256 0.0009088671603585743 0.0008602438311349426 0.0007842331047055571 0.0006638652867328143 0.0005240339424709019 0.00040141036955367216 0.0003040176982251547 0.00021814488333106864 0.00013968876242537675 0.00007921512669109886 0.00004639795846613081 0.00003732366030448009 0.00003269514350865678 0.000034944686828868745 0.000049264696090273646 0.0000883663543170863 0.00015338033482130165 0.00023414234946933719 0.0003235039291855628 0.0004262350267254957 0.0005506553884725049 0.0006876207794232064 0.0008116561588309145 0.000908867160358574 0.0009886570927394604 0.001064406485380005 0.0011288125431500472 0.001155389745083632 0.001128812543150047 0.0010644064853800052 0.0009886570927394604 0.000908867160358574 0.0008116561588309145 0.0006876207794232064 0.000550655388472505 0.0004262350267254957 0.00032350392918556274 0.00023414234946933719 0.00015338033482130154 0.00008836635431708629 0.000049264696090273606 0.00003494468682886875 0.0000329960059252528 0.00003597365585369935 0.000052163891300051615 0.00009296217033426761 0.0001577565262294795 0.0002386422884588025 0.00033441079730572653 0.0004496109766508942 0.0005832294783845773 0.0007212546483763893 0.0008486525878630215 0.0009628131037069254 0.0010644064853800052 0.0011463175132408869 0.001198608070877356 0.0012163029673619547 0.001198608070877356 0.0011463175132408869 0.0010644064853800052 0.0009628131037069254 0.0008486525878630215 0.0007212546483763893 0.0005832294783845774 0.00044961097665089425 0.00033441079730572653 0.00023864228845880256 0.00015775652622947945 0.00009296217033426761 0.000052163891300051595 0.000035973655853699375 0.00003999670548055916 0.00004194324107620926 0.00005534744024333387 0.00009223278715530905 0.00015267581316423008 0.00023234710462510306 0.00033613445730578957 0.0004687949647652258 0.0006197248184155328 0.0007667896670978375 0.0008995969267711845 0.001022379707901965 0.001128812543150047 0.001198608070877356 0.0012264093166083295 0.0012312082497994402 0.0012264093166083293 0.001198608070877356 0.001128812543150047 0.001022379707901965 0.0008995969267711845 0.0007667896670978374 0.0006197248184155328 0.00046879496476522585 0.00033613445730578957 0.0002323471046251031 0.00015267581316423 0.00009223278715530905 0.000055347440243333844 0.000041943241076209296 0.000044783155923663996 0.00004589492550742053 0.00005704904950991192 0.00009102652667143356 0.00014878985649779508 0.0002276846954364649 0.0003352029974325343 0.0004764957920562702 0.0006368373327308813 0.0007897162282245126 0.0009254338743022514 0.001050310032841179 0.0011553897450836323 0.0012163029673619547 0.00123120824979944 0.0012297430304380845 0.0012312082497994402 0.0012163029673619547 0.0011553897450836323 0.001050310032841179 0.0009254338743022513 0.0007897162282245126 0.0006368373327308813 0.0004764957920562702 0.0003352029974325343 0.00022768469543646492 0.000148789856497795 0.00009102652667143356 0.000057049049509911906 0.00004589492550742057 0.00003999670548055909 0.00004194324107620916 0.00005534744024333381 0.000092232787155309 0.0001526758131642301 0.00023234710462510309 0.0003361344573057896 0.00046879496476522596 0.0006197248184155331 0.0007667896670978378 0.0008995969267711853 0.0010223797079019657 0.0011288125431500476 0.0011986080708773562 0.0012264093166083298 0.0012312082497994402 0.0012264093166083298 0.0011986080708773562 0.0011288125431500476 0.0010223797079019657 0.0008995969267711854 0.0007667896670978379 0.000619724818415533 0.00046879496476522596 0.0003361344573057897 0.0002323471046251031 0.00015267581316423003 0.000092232787155309 0.00005534744024333379 0.00004194324107620921 0.000032996005925252856 0.00003597365585369947 0.00005216389130005163 0.00009296217033426765 0.00015775652622947964 0.00023864228845880264 0.0003344107973057266 0.0004496109766508943 0.0005832294783845775 0.0007212546483763895 0.0008486525878630219 0.0009628131037069258 0.0010644064853800054 0.0011463175132408869 0.001198608070877356 0.0012163029673619545 0.001198608070877356 0.0011463175132408869 0.0010644064853800057 0.0009628131037069258 0.0008486525878630219 0.0007212546483763896 0.0005832294783845775 0.00044961097665089425 0.00033441079730572664 0.0002386422884588027 0.00015775652622947956 0.00009296217033426767 0.00005216389130005163 0.00003597365585369953 0.00003269514350865687 0.00003494468682886899 0.000049264696090273775 0.0000883663543170863 0.0001533803348213017 0.0002341423494693373 0.0003235039291855629 0.0004262350267254959 0.0005506553884725056 0.0006876207794232069 0.0008116561588309152 0.0009088671603585748 0.0009886570927394613 0.0010644064853800059 0.0011288125431500476 0.0011553897450836325 0.0011288125431500478 0.0010644064853800059 0.000988657092739461 0.0009088671603585749 0.0008116561588309152 0.000687620779423207 0.0005506553884725056 0.0004262350267254959 0.00032350392918556296 0.00023414234946933735 0.00015338033482130162 0.0000883663543170863 0.00004926469609027377 0.00003494468682886904 0.000037105886643864283 0.00003732366030448033 0.00004639795846613087 0.00007921512669109873 0.00013968876242537686 0.00021814488333106861 0.00030401769822515474 0.0004014103695536723 0.0005240339424709022 0.0006638652867328143 0.0007842331047055574 0.0008602438311349426 0.0009088671603585746 0.0009628131037069257 0.0010223797079019655 0.001050310032841179 0.0010223797079019655 0.0009628131037069257 0.0009088671603585746 0.0008602438311349426 0.0007842331047055573 0.0006638652867328145 0.0005240339424709021 0.00040141036955367227 0.0003040176982251548 0.00021814488333106864 0.0001396887624253768 0.00007921512669109873 0.00004639795846613087 0.000037323660304480386 0.00003655595560015866 0.00003557185750931389 0.00004131938524832031 0.00006927841106991443 0.00012443697714305076 0.0001982325344744447 0.00027877854625725534 0.0003688317936540803 0.0004837211007552422 0.0006161255593246745 0.0007258557129460845 0.0007842331047055571 0.0008116561588309147 0.0008486525878630218 0.0008995969267711849 0.0009254338743022516 0.000899596926771185 0.0008486525878630219 0.0008116561588309147 0.0007842331047055572 0.0007258557129460845 0.0006161255593246746 0.00048372110075524215 0.0003688317936540803 0.00027877854625725545 0.00019823253447444472 0.00012443697714305073 0.00006927841106991445 0.00004131938524832031 0.00003557185750931395 0.000028768074973656955 0.00002832461997796313 0.00003439575992661065 0.000060288850131597595 0.00010990207288447235 0.0001752687237193275 0.00024516722341407914 0.00032132396993738875 0.00041701622182258377 0.000526217108392553 0.0006161255593246746 0.0006638652867328142 0.0006876207794232066 0.0007212546483763894 0.0007667896670978377 0.000789716228224513 0.0007667896670978378 0.0007212546483763894 0.0006876207794232066 0.0006638652867328141 0.0006161255593246746 0.0005262171083925531 0.00041701622182258366 0.00032132396993738875 0.0002451672234140792 0.00017526872371932754 0.00010990207288447231 0.0000602888501315976 0.000034395759926610664 0.000028324619977963185 0.00002215156616427764 0.000022541579159479093 0.000029077834577926993 0.00005157501937403697 0.00009202672100430498 0.0001439069308060288 0.00019991623908953334 0.00026156901156281496 0.0003360929645486789 0.0004170162218225835 0.0004837211007552419 0.0005240339424709016 0.0005506553884725051 0.0005832294783845773 0.0006197248184155328 0.0006368373327308815 0.0006197248184155329 0.0005832294783845773 0.0005506553884725051 0.0005240339424709016 0.0004837211007552419 0.0004170162218225836 0.00033609296454867885 0.00026156901156281496 0.00019991623908953345 0.00014390693080602887 0.00009202672100430497 0.00005157501937403699 0.000029077834577926996 0.000022541579159479143 0.00002016830905914839 0.000020434020735809162 0.000025213591859047355 0.00004158095417466831 0.00007002096897945226 0.00010639592520414893 0.00014926894555381798 0.000201014345344791 0.00026156901156281474 0.0003213239699373884 0.00036883179365408003 0.00040141036955367205 0.0004262350267254958 0.00044961097665089425 0.0004687949647652261 0.0004764957920562704 0.0004687949647652262 0.0004496109766508943 0.00042623502672549575 0.0004014103695536721 0.0003688317936540801 0.0003213239699373886 0.00026156901156281474 0.00020101434534479097 0.00014926894555381806 0.00010639592520414896 0.00007002096897945224 0.00004158095417466832 0.000025213591859047368 0.0000204340207358092 0.000017222828270284538 0.00001741283372362953 0.000020781451388425996 0.000031838852771596315 0.00005006992510114434 0.00007364236764164771 0.00010556425488906784 0.0001492689455538184 0.0001999162390895338 0.00024516722341407947 0.00027877854625725593 0.00030401769822515495 0.00032350392918556323 0.00033441079730572697 0.00033613445730579 0.0003352029974325348 0.0003361344573057901 0.0003344107973057269 0.00032350392918556323 0.0003040176982251549 0.0002787785462572559 0.0002451672234140796 0.00019991623908953372 0.00014926894555381833 0.00010556425488906792 0.00007364236764164771 0.00005006992510114432 0.00003183885277159632 0.000020781451388426 0.000017412833723629558 0.000009565617953677253 0.000010512830864499501 0.000014781998225035683 0.000023945460612412746 0.00003634591631691766 0.0000514295506268604 0.00007364236764164765 0.00010639592520414913 0.00014390693080602897 0.00017526872371932765 0.00019823253447444483 0.0002181448833310685 0.00023414234946933746 0.00023864228845880267 0.00023234710462510325 0.00022768469543646503 0.0002323471046251033 0.0002386422884588027 0.00023414234946933746 0.0002181448833310685 0.00019823253447444485 0.0001752687237193277 0.00014390693080602887 0.0001063959252041491 0.00007364236764164769 0.00005142955062686042 0.00003634591631691765 0.00002394546061241275 0.000014781998225035688 0.000010512830864499516 0.0000031293124924995536 0.00000455686644737876 0.000009341733308209112 0.000017423225697001906 0.00002659310644048793 0.00003634591631691771 0.00005006992510114432 0.00007002096897945255 0.00009202672100430521 0.0001099020728844727 0.000124436977143051 0.00013968876242537688 0.0001533803348213018 0.00015775652622947964 0.00015267581316423022 0.00014878985649779532 0.00015267581316423027 0.00015775652622947964 0.00015338033482130187 0.00013968876242537688 0.00012443697714305103 0.00010990207288447275 0.00009202672100430519 0.00007002096897945254 0.00005006992510114436 0.0000363459163169177 0.000026593106440487928 0.000017423225697001916 0.00000934173330820911 0.00000455686644737876 0.0000011014415294971636 0.000002455953188551963 0.000006004795496696787 0.000011308388178075157 0.000017423225697001845 0.000023945460612412753 0.00003183885277159621 0.00004158095417466848 0.00005157501937403695 0.00006028885013159774 0.00006927841106991426 0.00007921512669109862 0.00008836635431708625 0.00009296217033426748 0.00009223278715530893 0.00009102652667143341 0.00009223278715530897 0.00009296217033426745 0.00008836635431708616 0.00007921512669109855 0.00006927841106991423 0.000060288850131597764 0.00005157501937403691 0.00004158095417466847 0.000031838852771596254 0.000023945460612412756 0.000017423225697001865 0.000011308388178075184 0.0000060047954966967924 0.0000024559531885519477 9.817260510167414E-7 0.000002137322893978135 0.000003996439040510992 0.0000060047954966968416 0.0000093417333082091 0.000014781998225035585 0.000020781451388425847 0.000025213591859047345 0.00002907783457792701 0.00003439575992661074 0.000041319385248320246 0.00004639795846613066 0.00004926469609027361 0.00005216389130005141 0.00005534744024333385 0.00005704904950991171 0.000055347440243333844 0.0000521638913000514 0.00004926469609027358 0.00004639795846613067 0.00004131938524832029 0.00003439575992661073 0.00002907783457792696 0.000025213591859047307 0.000020781451388425857 0.000014781998225035547 0.000009341733308209093 0.000006004795496696851 0.000003996439040510982 0.0000021373228939781085 8.731497576473113E-7 0.0000015727588389645566 0.0000021373228939781407 0.000002455953188552092 0.00000455686644737881 0.000010512830864499521 0.000017412833723629534 0.000020434020735809318 0.000022541579159479225 0.000028324619977963243 0.00003557185750931374 0.00003732366030448015 0.00003494468682886883 0.0000359736558536994 0.00004194324107620919 0.00004589492550742042 0.00004194324107620929 0.000035973655853699416 0.00003494468682886883 0.00003732366030448008 0.0000355718575093138 0.000028324619977963267 0.000022541579159479208 0.000020434020735809294 0.000017412833723629534 0.000010512830864499486 0.000004556866447378805 0.0000024559531885521053 0.0000021373228939781407 0.0000015727588389645185 8.731497576476449E-7 0.0000015727588389647836 0.000002137322893978404 0.0000024559531885526135 0.000004556866447379422 0.000010512830864500068 0.000017412833723629917 0.000020434020735809772 0.000022541579159479706 0.00002832461997796386 0.00003557185750931429 0.00003732366030448093 0.00003494468682886957 0.00003597365585370014 0.0000419432410762099 0.00004589492550742134 0.00004194324107621044 0.00003597365585370101 0.000034944686828870765 0.00003732366030448201 0.0000355718575093157 0.000028324619977965215 0.000022541579159481115 0.000020434020735811344 0.000017412833723631598 0.000010512830864501505 0.000004556866447380479 0.0000024559531885532572 0.0000021373228939788175 0.0000015727588389648717 0.0000015727588389652626 0.00000285892175176496 0.000002762615652369505 0.000002036722977855606 0.000003983409389721915 0.000010520403821835282 0.000017076032718197428 0.000019088382184320965 0.00002053205010782843 0.000025849658985386505 0.00003378055041345735 0.000038182571490199756 0.000039276793556516195 0.00004246476366108822 0.00004804046316260092 0.00005028754494385229 0.00004603987620568666 0.000041852286247621125 0.00004233764706958042 0.000044717298415451535 0.00004323547790220825 0.000036828364883751334 0.00003018052248613238 0.000025034130620912827 0.000019548538281867914 0.00001299998014039852 0.000008151547957648139 0.0000055356148465817726 0.0000036084647764521415 0.0000018701035482080726 0.0000021373228939793935 0.0000027626156523701492 0.0000023858417075119453 0.0000025097644122411145 0.00000554226616858285 0.000011415154720125453 0.000016053898680696026 0.00001784863927513438 0.00002071187565953676 0.00002671170950945761 0.0000353858168292177 0.00004365864520425263 0.00005081018743245168 0.00005773213817806005 0.0000637862729806354 0.00006774528075202899 0.00006979335205075105 0.00007273331620749089 0.00007494986032959587 0.00007386269411413508 0.00006945342397726736 0.00006258753462346807 0.00005384413321554055 0.00004262943994522773 0.00003105710711973258 0.00002223858765754982 0.00001699613417881604 0.000012912197025181602 0.00000804868882886601 0.000003608464776452429 0.0000024559531885541182 0.000002036722977856951 0.000002509764412241885 0.0000054046570067347725 0.000010432721977928645 0.0000154869764750901 0.000019053487707614036 0.000022572177159263184 0.00002876662995246088 0.00003706462000962938 0.00004701150675251019 0.00005906705547390568 0.00007319711621452098 0.00008633426488525763 0.00009660617943874871 0.00010792134312512637 0.00012382628362151183 0.0001400195734721019 0.00014552776986352707 0.00013880284057141276 0.00012834877183814158 0.00011796120117655284 0.00010298248083767368 0.00007998449698244473 0.00005616002450131098 0.00003976068444587585 0.000030311141079121294 0.00002214979980321094 0.00001291219702518201 0.000005535614846582486 0.000004556866447381208 0.000003983409389723775 0.000005542266168584321 0.000010432721977929538 0.00001699753266601417 0.00002242632725749176 0.0000276868003413488 0.00003641977923896503 0.00004966829372031973 0.00006307845147368935 0.00007498642144383799 0.0000897053040096315 0.00010991083482162108 0.00013107499389271288 0.00014969492195175308 0.00017215285754228538 0.00020453187540746886 0.00023703570095634643 0.000249626848933341 0.0002390574811461117 0.00022075191810651295 0.0002022661710982103 0.00017486743176160918 0.0001337877755735311 0.00009205475009134067 0.00006284740975602363 0.00004485817630947686 0.000030311141079121602 0.00001699613417881663 0.000008151547957648943 0.000010512830864501934 0.00001052040382183743 0.000011415154720127518 0.000015486976475091856 0.000022426327257492767 0.000030050283810161233 0.00004046369803591167 0.000057993578281355464 0.00008184139687993365 0.00010322000910759505 0.00011896774347644046 0.00013719159990130853 0.00016417085279852374 0.0001957018338934871 0.00022539912279093702 0.000257889403851152 0.0003006000119108427 0.00034400341974442786 0.00036504846722240934 0.00035604221904844165 0.0003314013116227085 0.00030038990046507455 0.0002556769954001611 0.0001953274840006317 0.00013600659857995748 0.00009243873198667929 0.0000628474097560239 0.0000397606844458764 0.000022238587657550493 0.000012999980140399251 0.000017412833723631628 0.000017076032718199478 0.00001605389868069811 0.000019053487707616045 0.000027686800341350382 0.000040463698035912216 0.00005883925589510527 0.00008587912888930913 0.00012021240778397824 0.00015154206168441168 0.0001759200090281856 0.00020289046441401883 0.00024181346590353568 0.0002898163901862287 0.000334974298923437 0.00037446751049341487 0.00041543744447833944 0.00045571802826237646 0.0004787892601050384 0.0004735132988821235 0.00044462886976899703 0.0003988059216545916 0.00033639172392144326 0.00026232352305726305 0.00019199258158379256 0.00013600659857995756 0.0000920547500913411 0.000056160024501311595 0.000031057107119733166 0.000019548538281868396 0.000020434020735811266 0.000019088382184322808 0.000017848639275136353 0.00002257217715926533 0.000036419779238966876 0.000057993578281356535 0.00008587912888930977 0.0001212177467132263 0.00016484178283184583 0.0002087267249035142 0.00024777767599729424 0.0002890580940773188 0.0003443313341783671 0.0004144589417778407 0.0004813101651604774 0.0005287625121494391 0.0005603349195352476 0.0005865215698875168 0.0006045988410517463 0.0006011759042085234 0.0005666602319166289 0.0005030317145494117 0.0004222368852196871 0.00033846068511081314 0.00026232352305726315 0.00019532748400063189 0.00013378777557353162 0.0000799844969824454 0.000042629439945228246 0.000025034130620913203 0.000022541579159481027 0.000020532050107829862 0.000020711875659538402 0.000028766629952462575 0.00004966829372032134 0.00008184139687993411 0.00012021240778397832 0.00016484178283184505 0.00022033393740473507 0.00028173929364136977 0.00033999731898394584 0.0003957651850725636 0.00046335640422671086 0.0005519973573561747 0.0006423483931220779 0.0007038565058097183 0.0007313386636297369 0.0007465776724080139 0.0007619127265753577 0.0007609761381989924 0.0007178665296542976 0.0006296342986623041 0.0005222137760460878 0.00042223688521968666 0.0003363917239214431 0.00025567699540016104 0.0001748674317616096 0.00010298248083767409 0.00005384413321554087 0.00003018052248613249 0.00002832461997796525 0.000025849658985387877 0.000026711709509459135 0.00003706462000963078 0.00006307845147369058 0.00010322000910759531 0.00015154206168441095 0.00020872672490351241 0.0002817392936413682 0.0003660870006756866 0.0004453625188348372 0.0005122217700908266 0.0005841060597842323 0.0006814304005537422 0.000790059915324497 0.0008701737083641774 0.000905575712490908 0.0009218909549822137 0.0009416347748850418 0.0009450532555018936 0.0008912224146887227 0.0007727221740842523 0.0006296342986623036 0.0005030317145494112 0.00039880592165459126 0.0003003899004650746 0.0002022661710982107 0.00011796120117655318 0.00006258753462346834 0.00003682836488375131 0.00003557185750931561 0.00003378055041345842 0.00003538581682921896 0.00004701150675251137 0.00007498642144383937 0.0001189677434764406 0.00017592000902818487 0.0002477776759972918 0.00033999731898394286 0.0004453625188348356 0.0005424395332519977 0.0006206635119981518 0.0006992403467680987 0.0008039528511211494 0.0009248564411888024 0.001018928388904482 0.0010633634004518998 0.0010826685402583547 0.0011029764516615216 0.0011033690494170367 0.001035912206518223 0.0008912224146887224 0.0007178665296542967 0.000566660231916628 0.0004446288697689966 0.0003314013116227081 0.00022075191810651287 0.00012834877183814122 0.00006945342397726691 0.00004323547790220782 0.000037323660304481796 0.00003818257149020044 0.000043658645204253795 0.00005906705547390675 0.00008970530400963274 0.0001371915999013091 0.00020289046441401829 0.0002890580940773165 0.00039576518507256005 0.0005122217700908235 0.0006206635119981499 0.0007164119706880185 0.0008161527036543696 0.0009370424568941316 0.0010646588843713982 0.0011579051791739618 0.001197342979212863 0.0012065670294402907 0.001209821010486132 0.001189321765510574 0.0011033690494170359 0.0009450532555018922 0.0007609761381989911 0.0006011759042085222 0.00047351329888212245 0.00035604221904844067 0.00023905748114611098 0.00013880284057141203 0.00007386269411413449 0.00004471729841545076 0.000034944686828870195 0.000039276793556516656 0.00005081018743245241 0.0000731971162145221 0.00010991083482162258 0.0001641708527985246 0.0002418134659035361 0.0003443313341783657 0.0004633564042267081 0.0005841060597842293 0.0006992403467680962 0.000816152703654368 0.0009448279369217375 0.0010815579702260227 0.0012018072025311523 0.0012756356763438074 0.0012975573945890684 0.0012883678922504813 0.0012632413019571791 0.0012098210104861315 0.0011029764516615208 0.0009416347748850404 0.0007619127265753562 0.0006045988410517448 0.00047878926010503736 0.0003650484672224079 0.00024962684893333994 0.00014552776986352596 0.00007494986032959456 0.0000423376470695795 0.000035973655853700426 0.0000424647636610883 0.00005773213817806051 0.0000863342648852583 0.00013107499389271402 0.00019570183389348823 0.00028981639018622933 0.00041445894177784026 0.0005519973573561732 0.0006814304005537398 0.0008039528511211471 0.0009370424568941302 0.0010815579702260223 0.0012123734799485142 0.001302133175859918 0.0013445560159961191 0.0013517795309755743 0.001333902222608254 0.001288367892250481 0.0012065670294402902 0.0010826685402583534 0.0009218909549822122 0.0007465776724080122 0.0005865215698875151 0.00045571802826237473 0.00034400341974442634 0.00023703570095634494 0.00014001957347210044 0.0000727333162074897 0.000041852286247620034 0.00004194324107621011 0.000048040463162600965 0.00006378627298063543 0.0000966061794387492 0.00014969492195175438 0.000225399122790938 0.00033497429892343785 0.0004813101651604773 0.000642348393122077 0.0007900599153244959 0.000924856441188801 0.001064658884371397 0.0012018072025311518 0.001302133175859918 0.0013490440679071716 0.001362676440433753 0.001365906690206462 0.001351779530975574 0.0012975573945890678 0.0011973429792128622 0.0010633634004518985 0.0009055757124909065 0.000731338663629735 0.0005603349195352457 0.00041543744447833776 0.0003006000119108408 0.00020453187540746755 0.00012382628362151075 0.00006979335205074981 0.000046039876205685885 0.000045894925507421364 0.0000502875449438521 0.00006774528075202891 0.00010792134312512648 0.00017215285754228644 0.00025788940385115334 0.000374467510493416 0.0005287625121494397 0.0007038565058097182 0.000870173708364177 0.0010189283889044819 0.0011579051791739616 0.0012756356763438076 0.0013445560159961191 0.0013626764404337534 0.0013618288308587497 0.0013626764404337524 0.0013445560159961178 0.0012756356763438067 0.0011579051791739611 0.0010189283889044812 0.0008701737083641763 0.0007038565058097169 0.0005287625121494376 0.0003744675104934133 0.0002578894038511507 0.00017215285754228438 0.00010792134312512537 0.00006774528075202826 0.00005028754494385194 0.00004194324107621028 0.00004603987620568613 0.00006979335205075044 0.0001238262836215117 0.00020453187540746956 0.00030060001191084345 0.00041543744447834047 0.0005603349195352479 0.0007313386636297368 0.0009055757124909078 0.0010633634004519 0.0011973429792128635 0.0012975573945890693 0.0013517795309755751 0.0013659066902064626 0.0013626764404337526 0.0013490440679071705 0.0013021331758599171 0.001201807202531152 0.0010646588843713982 0.0009248564411888022 0.0007900599153244963 0.0006423483931220763 0.00048131016516047545 0.0003349742989234354 0.00022539912279093542 0.00014969492195175238 0.00009660617943874795 0.00006378627298063474 0.00004804046316260086 0.000035973655853700724 0.00004185228624762049 0.00007273331620749024 0.00014001957347210118 0.00023703570095634648 0.00034400341974442846 0.0004557180282623771 0.0005865215698875171 0.0007465776724080136 0.0009218909549822131 0.0010826685402583547 0.001206567029440291 0.0012883678922504824 0.0013339022226082544 0.0013517795309755743 0.001344556015996118 0.001302133175859917 0.0012123734799485135 0.001081557970226023 0.0009370424568941321 0.0008039528511211492 0.000681430400553741 0.000551997357356173 0.00041445894177783875 0.00028981639018622706 0.00019570183389348595 0.00013107499389271212 0.00008633426488525703 0.000057732138178059735 0.00004246476366108836 0.00003494468682887012 0.0000423376470695797 0.0000749498603295947 0.00014552776986352593 0.00024962684893334053 0.00036504846722240907 0.000478789260105039 0.0006045988410517462 0.0007619127265753575 0.0009416347748850411 0.0011029764516615219 0.0012098210104861324 0.0012632413019571802 0.001288367892250482 0.0012975573945890684 0.001275635676343807 0.0012018072025311516 0.0010815579702260227 0.0009448279369217387 0.0008161527036543706 0.0006992403467680988 0.0005841060597842311 0.0004633564042267088 0.0003443313341783647 0.00024181346590353416 0.00016417085279852233 0.00010991083482162034 0.00007319711621452028 0.00005081018743245121 0.00003927679355651635 0.00003732366030448117 0.00004471729841545039 0.0000738626941141338 0.00013880284057141094 0.00023905748114611038 0.00035604221904844056 0.0004735132988821229 0.0006011759042085226 0.0007609761381989913 0.0009450532555018918 0.0011033690494170357 0.0011893217655105735 0.001209821010486132 0.0012065670294402905 0.0011973429792128622 0.0011579051791739607 0.0010646588843713969 0.0009370424568941306 0.0008161527036543691 0.0007164119706880187 0.0006206635119981504 0.0005122217700908238 0.00039576518507256016 0.00028905809407731557 0.00020289046441401652 0.00013719159990130674 0.00008970530400963028 0.00005906705547390435 0.00004365864520425199 0.00003818257149019959 0.000035571857509314636 0.00004323547790220683 0.00006945342397726568 0.0001283487718381392 0.00022075191810651108 0.0003314013116227069 0.0004446288697689961 0.0005666602319166277 0.000717866529654296 0.0008912224146887208 0.0010359122065182213 0.001103369049417035 0.0011029764516615206 0.0010826685402583539 0.0010633634004518985 0.001018928388904481 0.0009248564411888008 0.0008039528511211472 0.0006992403467680964 0.0006206635119981487 0.0005424395332519948 0.0004453625188348333 0.00033999731898394156 0.00024777767599729067 0.00017592000902818327 0.00011896774347643848 0.00007498642144383677 0.000047011506752508744 0.000035385816829217066 0.00003378055041345714 0.000028324619977963917 0.00003682836488374965 0.00006258753462346646 0.00011796120117655025 0.00020226617109820802 0.0003003899004650723 0.0003988059216545899 0.0005030317145494102 0.0006296342986623023 0.0007727221740842499 0.0008912224146887202 0.0009450532555018906 0.0009416347748850399 0.0009218909549822113 0.0009055757124909062 0.0008701737083641757 0.0007900599153244949 0.0006814304005537387 0.0005841060597842278 0.0005122217700908206 0.00044536251883483136 0.00036608700067568175 0.0002817392936413651 0.0002087267249035106 0.000151542061684409 0.00010322000910759298 0.00006307845147368776 0.000037064620009627816 0.000026711709509457082 0.00002584965898538618 0.000022541579159479987 0.000030180522486130877 0.00005384413321553908 0.00010298248083767142 0.00017486743176160693 0.0002556769954001589 0.00033639172392144147 0.00042223688521968557 0.000522213776046086 0.0006296342986623016 0.0007178665296542948 0.0007609761381989897 0.0007619127265753557 0.0007465776724080118 0.0007313386636297346 0.0007038565058097165 0.0006423483931220753 0.0005519973573561715 0.00046335640422670604 0.0003957651850725567 0.0003399973189839388 0.00028173929364136365 0.00022033393740473112 0.0001648417828318429 0.00012021240778397634 0.00008184139687993215 0.000049668293720318825 0.000028766629952460085 0.000020711875659536752 0.000020532050107828385 0.000020434020735809907 0.000025034130620911244 0.000042629439945226186 0.00007998449698244254 0.00013378777557352875 0.00019532748400062942 0.0002623235230572611 0.0003384606851108115 0.0004222368852196851 0.0005030317145494095 0.0005666602319166264 0.0006011759042085212 0.0006045988410517447 0.0005865215698875151 0.0005603349195352459 0.0005287625121494381 0.0004813101651604754 0.0004144589417778384 0.0003443313341783635 0.0002890580940773134 0.00024777767599728833 0.00020872672490350886 0.0001648417828318422 0.00012121774671322424 0.00008587912888930793 0.00005799357828135468 0.000036419779238964504 0.00002257217715926288 0.00001784863927513466 0.0000190883821843211 0.000017412833723629965 0.000019548538281866352 0.000031057107119731086 0.00005616002450130904 0.00009205475009133861 0.00013600659857995525 0.00019199258158379055 0.0002623235230572614 0.0003363917239214416 0.0003988059216545896 0.00044462886976899573 0.00047351329888212207 0.0004787892601050378 0.0004557180282623754 0.00041543744447833874 0.00037446751049341427 0.00033497429892343633 0.0002898163901862277 0.00024181346590353454 0.00020289046441401593 0.0001759200090281825 0.00015154206168440827 0.0001202124077839762 0.00008587912888930825 0.000058839255895104684 0.0000404636980359114 0.000027686800341348983 0.000019053487707614232 0.000016053898680696598 0.000017076032718197743 0.000010512830864499604 0.00001299998014039669 0.000022238587657548094 0.0000397606844458738 0.00006284740975602143 0.00009243873198667693 0.00013600659857995528 0.00019532748400062966 0.00025567699540015893 0.00030038990046507227 0.0003314013116227064 0.00035604221904843975 0.0003650484672224079 0.0003440034197444268 0.00030060001191084177 0.00025788940385115176 0.00022539912279093683 0.00019570183389348693 0.00016417085279852353 0.00013719159990130723 0.00011896774347643869 0.00010322000910759308 0.00008184139687993265 0.00005799357828135557 0.000040463698035912094 0.000030050283810161392 0.00002242632725749212 0.000015486976475090375 0.00001141515472012588 0.00001052040382183519 0.000004556866447378755 0.000008151547957646456 0.000016996134178814386 0.000030311141079119407 0.00004485817630947493 0.0000628474097560218 0.00009205475009133893 0.00013378777557352943 0.0001748674317616075 0.00020226617109820832 0.000220751918106511 0.0002390574811461098 0.0002496268489333395 0.00023703570095634507 0.000204531875407468 0.0001721528575422854 0.0001496949219517536 0.00013107499389271345 0.00010991083482162192 0.00008970530400963177 0.00007498642144383812 0.00006307845147368902 0.000049668293720320214 0.000036419779238966354 0.000027686800341350558 0.000022426327257493204 0.000016997532666014656 0.00001043272197792881 0.000005542266168582924 0.000003983409389721539 0.0000024559531885517627 0.000005535614846580171 0.00001291219702517993 0.000022149799803209 0.00003031114107911963 0.000039760684445874345 0.00005616002450130953 0.00007998449698244325 0.00010298248083767175 0.00011796120117655056 0.00012834877183813878 0.00013880284057141024 0.00014552776986352482 0.00014001957347209963 0.00012382628362151042 0.00010792134312512567 0.00009660617943874856 0.00008633426488525782 0.00007319711621452144 0.00005906705547390559 0.00004701150675251003 0.00003706462000962928 0.00002876662995246159 0.00002257217715926501 0.000019053487707616333 0.000015486976475092236 0.0000104327219779297 0.000005404657006734469 0.0000025097644122407176 0.0000020367229778548194 0.0000021373228939778095 0.0000036084647764509243 0.00000804868882886463 0.000012912197025180331 0.00001699613417881494 0.00002223858765754882 0.000031057107119731594 0.0000426294399452267 0.00005384413321553943 0.00006258753462346658 0.0000694534239772654 0.00007386269411413315 0.0000749498603295937 0.00007273331620748898 0.00006979335205074949 0.00006774528075202831 0.000063786272980635 0.0000577321381780602 0.00005081018743245223 0.00004365864520425314 0.000035385816829218516 0.000026711709509458495 0.000020711875659538334 0.000017848639275136526 0.000016053898680698733 0.000011415154720127911 0.000005542266168584369 0.0000025097644122414376 0.0000023858417075114697 0.0000027626156523688075 0.0000015727588389643586 0.0000018701035482071881 0.0000036084647764512254 0.000005535614846580862 0.000008151547957647203 0.000012999980140397454 0.000019548538281866796 0.000025034130620911597 0.00003018052248613109 0.00003682836488374957 0.00004323547790220643 0.00004471729841544972 0.00004233764706957879 0.000041852286247619465 0.000046039876205685445 0.000050287544943851696 0.000048040463162600735 0.00004246476366108848 0.00003927679355651678 0.0000381825714902004 0.00003378055041345832 0.00002584965898538748 0.00002053205010782981 0.000019088382184322947 0.00001707603271819972 0.000010520403821837366 0.000003983409389723301 0.0000020367229778561213 0.0000027626156523694517 0.000002858921751764244 9.817260510201408E-7 0.0000021373228939813857 0.000003996439040513987 0.000006004795496699741 0.000009341733308211779 0.000014781998225038171 0.000020781451388428117 0.000025213591859049242 0.00002907783457792838 0.000034395759926611653 0.0000413193852483205 0.000046397958466131 0.00004926469609027378 0.00005216389130005138 0.0000553474402433334 0.00005704904950991157 0.00005534744024333362 0.00005216389130005127 0.00004926469609027324 0.00004639795846613046 0.000041319385248319955 0.000034395759926610244 0.000029077834577926698 0.000025213591859047345 0.00002078145138842603 0.000014781998225036355 0.000009341733308210477 0.0000060047954966988465 0.000003996439040513506 0.000002137322893981196 0.0000021373228939808716 0.0000027626156523715595 0.000002385841707513484 0.0000025097644122428716 0.00000554226616858484 0.000011415154720127828 0.00001605389868069832 0.000017848639275136248 0.00002071187565953805 0.000026711709509458193 0.000035385816829217527 0.00004365864520425237 0.00005081018743245086 0.0000577321381780593 0.00006378627298063418 0.00006774528075202785 0.0000697933520507491 0.00007273331620748857 0.00007494986032959292 0.00007386269411413235 0.00006945342397726454 0.00006258753462346589 0.00005384413321553909 0.00004262943994522706 0.00003105710711973233 0.00002223858765755019 0.000016996134178816845 0.00001291219702518283 0.000008048688828867482 0.000003608464776454052 0.000003996439040513075 0.0000023858417075130405 6.283755755600709E-7 6.970502856839491E-7 0.0000032397046829942637 0.000007875181309266322 0.00001132604885683347 0.00001323928814553792 0.00001916527902950354 0.000029796252276296665 0.00004244351625248921 0.000055340012144678935 0.00006872525418735631 0.00008108726648983381 0.00009111223839643629 0.0001009865955692158 0.00011389516179237136 0.0001291653947954474 0.00013665578847337002 0.00013267912482792065 0.0001251445831073876 0.00011779395139745095 0.00010487748323798 0.00008197322550826215 0.000057456869677795186 0.00004136804712597341 0.00003342638176964166 0.000026517972173532293 0.000016860768505252787 0.000008048688828867311 0.000006004795496698804 0.000002509764412242281 6.970502856836598E-7 0.00000210345413853406 0.000004768890798279119 0.00000743690503610258 0.000009782308601454668 0.000013352842787482394 0.00002325992677889557 0.0000381200977722772 0.00005348677304968866 0.00007040658488428554 0.00009227334361629819 0.00011571395533526819 0.00013678820046357412 0.0001608040602893099 0.0001937282923613049 0.00022688081584744393 0.00023897829057065157 0.0002281113462259244 0.0002138467588570359 0.00020424986233035116 0.00018588342694629103 0.00014795151506898899 0.0001045802073061642 0.00007448828453249649 0.000057817829717251914 0.00004337238133691328 0.00002651797217353242 0.000012912197025182901 0.000009341733308210855 0.000005542266168584212 0.000003239704682993852 0.000004768890798279055 0.000008699922739315374 0.000011558312453101056 0.00001433077570750724 0.000021744405128661447 0.00003722540034797436 0.00005473562818606974 0.00006978108319975302 0.00008929388863324293 0.00012122019196753916 0.0001613491010113378 0.00020099329412540356 0.00024459489967905944 0.000299980327941695 0.0003533047695374995 0.0003746363628123272 0.00036059264973204076 0.0003382569558404374 0.0003206654954183211 0.0002900741872742535 0.00023213625592551543 0.0001657061623183757 0.0001159460434494748 0.0000841340859818303 0.00005781782971725231 0.00003342638176964209 0.000016996134178817282 0.00001478199822503726 0.000011415154720127218 0.000007875181309265949 0.000007436905036102507 0.0000115583124531012 0.00001716538851728464 0.000024903658690918604 0.00003947296941473771 0.00006174356940784497 0.00008236911364063759 0.00009890637973825997 0.00012413553643969962 0.00016975481507747303 0.00023073618568791363 0.00029156831156405523 0.00035198131564532874 0.00042271980596803336 0.0004938311102070534 0.000532876705549302 0.0005270594962774765 0.0004984623059909894 0.0004633285841213855 0.0004090335134792757 0.0003264489629536636 0.00023726111223035316 0.00016665216540789774 0.00011594604344947545 0.00007448828453249743 0.00004136804712597433 0.000022238587657551093 0.000020781451388427256 0.000016053898680697737 0.000011326048856832987 0.000009782308601454584 0.000014330775707507347 0.000024903658690918445 0.00004128492951896332 0.00006383462345803208 0.00009202995412545335 0.00011899803177516591 0.0001453677778402728 0.00018599940050380604 0.0002543426496727875 0.0003431122089624043 0.0004273720105761922 0.0004998642579464924 0.0005759894400297521 0.0006575346592259328 0.0007162791068696818 0.0007261632918973094 0.0006923623475488193 0.0006304765274554537 0.0005429488252746256 0.00043445457211483004 0.00032649751656326544 0.00023726111223035384 0.00016570616231837695 0.00010458020730616559 0.00005745686967779637 0.00003105710711973362 0.000025213591859048513 0.000017848639275135902 0.000013239288145537783 0.000013352842787482574 0.000021744405128662003 0.00003947296941473812 0.00006383462345803264 0.00009202547110128832 0.0001254154478450814 0.00016298950258330578 0.0002082531196669474 0.00027449300329203283 0.0003738581341875558 0.0004963521413852157 0.0006092634042455426 0.0006972250267069901 0.000777491075557374 0.0008649531896832557 0.0009395915246891037 0.000963234949391186 0.0009202033550585047 0.0008239745350408541 0.0006969509137475141 0.0005606707485081437 0.00043445457211483085 0.0003264489629536649 0.0002321362559255171 0.00014795151506899075 0.00008197322550826355 0.00004262943994522839 0.000029077834577927704 0.0000207118756595376 0.00001916527902950326 0.000023259926778895813 0.000037225400347975044 0.0000617435694078454 0.0000920299541254542 0.00012541544784508153 0.00016606419909648878 0.00021817936648991368 0.0002867002807287315 0.0003796380781566135 0.0005052944369660894 0.0006561523056794495 0.0008015254916949653 0.0009190083262633692 0.0010183403054298283 0.0011191498215588778 0.0012087368131948224 0.0012408721734380671 0.0011822360315786298 0.0010447624265133978 0.000870308782622395 0.0006969509137475146 0.000542948825274627 0.0004090335134792773 0.00029007418727425554 0.00018588342694629274 0.00010487748323798141 0.00005384413321554032 0.000034395759926611206 0.00002671170950945782 0.000029796252276296618 0.00003812009777227761 0.00005473562818607074 0.00008236911364063883 0.00011899803177516728 0.00016298950258330675 0.00021817936648991452 0.00029029939436916124 0.0003820241157457605 0.0004938979088174669 0.0006317512268016343 0.0007970503483696824 0.0009705099287999358 0.0011270689633863353 0.0012624736503087067 0.0013888305176585206 0.001494949249301127 0.0015311746859497813 0.0014533516270413816 0.0012722104792645434 0.0010447624265133987 0.0008239745350408559 0.000630476527455456 0.0004633285841213879 0.0003206654954183236 0.0002042498623303531 0.00011779395139745253 0.00006258753462346703 0.000041319385248320145 0.00003538581682921707 0.000042443516252489176 0.00005348677304968902 0.00006978108319975416 0.000098906379738261 0.00014536777784027467 0.0002082531196669491 0.00028670028072873304 0.00038202411574576146 0.000493614023555863 0.0006199289354965157 0.000766854104188563 0.0009407587239141569 0.0011311065461327978 0.0013145279401521061 0.0014775571166893019 0.0016224551241649794 0.0017355804206419642 0.0017673346539450873 0.0016700548810745658 0.0014533516270413827 0.0011822360315786313 0.0009202033550585067 0.0006923623475488217 0.0004984623059909914 0.0003382569558404394 0.00021384675885703717 0.0001251445831073882 0.000069453423977265 0.00004639795846613058 0.000043658645204251674 0.00005534001214467875 0.00007040658488428546 0.00008929388863324351 0.00012413553643970078 0.00018599940050380767 0.0002744930032920348 0.00037963807815661547 0.000493897908817469 0.0006199289354965168 0.0007654503468072623 0.0009350204265439997 0.0011239034969201724 0.0013165680957763388 0.0014941165032954476 0.0016478117139200597 0.001779416797872281 0.0018739209437563806 0.0018846393517467884 0.001767334653945088 0.0015311746859497826 0.0012408721734380693 0.0009632349493911884 0.0007261632918973119 0.0005270594962774786 0.00036059264973204244 0.00022811134622592542 0.00013267912482792135 0.00007386269411413248 0.000049264696090273226 0.000050810187432450355 0.00006872525418735568 0.00009227334361629783 0.00012122019196753981 0.00016975481507747376 0.00025434264967278926 0.0003738581341875577 0.0005052944369660916 0.0006317512268016368 0.0007668541041885653 0.0009350204265440004 0.0011362470259058453 0.0013402003972896616 0.0015145682355305664 0.0016503940612064283 0.001758561840287146 0.0018474983033848536 0.0018998605429481883 0.0018739209437563808 0.0017355804206419657 0.0014949492493011288 0.0012087368131948246 0.0009395915246891058 0.0007162791068696841 0.0005328767055493037 0.0003746363628123286 0.00023897829057065227 0.00013665578847337018 0.00007494986032959281 0.00005216389130005117 0.0000577321381780588 0.00008108726648983337 0.0001157139553352678 0.0001613491010113379 0.00023073618568791434 0.00034311220896240556 0.0004963521413852176 0.0006561523056794515 0.0007970503483696849 0.0009407587239141593 0.0011239034969201742 0.0013402003972896627 0.001536173869727399 0.0016687172925344592 0.0017464322160936922 0.001801726194786024 0.0018436353554615215 0.0018474983033848543 0.001779416797872282 0.0016224551241649805 0.0013888305176585221 0.0011191498215588796 0.0008649531896832576 0.0006575346592259345 0.0004938311102070548 0.00035330476953750043 0.00022688081584744429 0.00012916539479544751 0.00007273331620748844 0.00005534744024333344 0.00006378627298063387 0.00009111223839643554 0.00013678820046357347 0.00020099329412540356 0.0002915683115640556 0.00042737201057619316 0.0006092634042455439 0.0008015254916949667 0.0009705099287999377 0.0011311065461328 0.0013165680957763404 0.0015145682355305675 0.0016687172925344597 0.001746878230703638 0.0017766517541786208 0.001796369665921988 0.0018017261947860235 0.001758561840287146 0.0016478117139200597 0.001477557116689303 0.0012624736503087078 0.0010183403054298296 0.0007774910755573752 0.0005759894400297536 0.0004227198059680342 0.00029998032794169586 0.00019372829236130528 0.00011389516179237105 0.0000697933520507489 0.00005704904950991158 0.00006774528075202734 0.0001009865955692151 0.000160804060289309 0.00024459489967905917 0.00035198131564532896 0.000499864257946493 0.0006972250267069912 0.0009190083262633707 0.001127068963386337 0.0013145279401521083 0.0014941165032954493 0.0016503940612064298 0.0017464322160936927 0.001776651754178621 0.0017783579871622293 0.0017766517541786201 0.0017464322160936911 0.0016503940612064283 0.001494116503295448 0.0013145279401521072 0.0011270689633863366 0.0009190083262633707 0.0006972250267069915 0.0004998642579464938 0.00035198131564533 0.00024459489967906025 0.00016080406028930996 0.00010098659556921567 0.00006774528075202769 0.00005534744024333359 0.00006979335205074866 0.00011389516179237051 0.0001937282923613042 0.0002999803279416947 0.000422719805968033 0.0005759894400297524 0.0007774910755573744 0.0010183403054298294 0.0012624736503087084 0.001477557116689304 0.0016478117139200612 0.0017585618402871474 0.0018017261947860248 0.001796369665921989 0.0017766517541786201 0.0017468782307036366 0.0016687172925344584 0.0015145682355305666 0.0013165680957763393 0.0011311065461327991 0.0009705099287999369 0.0008015254916949664 0.0006092634042455439 0.00042737201057619387 0.0002915683115640564 0.0002009932941254045 0.00013678820046357428 0.00009111223839643611 0.00006378627298063429 0.0000521638913000515 0.00007273331620748843 0.00012916539479544703 0.00022688081584744317 0.00035330476953749913 0.0004938311102070532 0.0006575346592259329 0.0008649531896832562 0.0011191498215588785 0.0013888305176585215 0.001622455124164981 0.0017794167978722824 0.0018474983033848554 0.0018436353554615223 0.0018017261947860241 0.0017464322160936916 0.0016687172925344586 0.0015361738697273984 0.001340200397289662 0.001123903496920173 0.000940758723914158 0.0007970503483696835 0.0006561523056794508 0.0004963521413852175 0.00034311220896240604 0.000230736185687915 0.00016134910101133857 0.00011571395533526843 0.00008108726648983387 0.00005773213817805945 0.00004926469609027361 0.00007494986032959294 0.0001366557884733698 0.000238978290570651 0.0003746363628123271 0.0005328767055493019 0.0007162791068696823 0.0009395915246891042 0.0012087368131948237 0.0014949492493011283 0.001735580420641966 0.0018739209437563821 0.0018998605429481905 0.0018474983033848554 0.0017585618402871472 0.0016503940612064294 0.0015145682355305677 0.0013402003972896631 0.0011362470259058466 0.0009350204265440007 0.0007668541041885645 0.0006317512268016359 0.0005052944369660914 0.0003738581341875579 0.00025434264967278975 0.00016975481507747428 0.00012122019196754014 0.00009227334361629816 0.0000687252541873562 0.00005081018743245112 0.000046397958466130725 0.00007386269411413237 0.0001326791248279205 0.00022811134622592366 0.00036059264973204043 0.0005270594962774761 0.0007261632918973096 0.0009632349493911864 0.001240872173438068 0.0015311746859497822 0.0017673346539450884 0.0018846393517467895 0.0018739209437563828 0.001779416797872283 0.0016478117139200614 0.0014941165032954493 0.0013165680957763408 0.0011239034969201748 0.0009350204265440018 0.0007654503468072631 0.000619928935496517 0.0004938979088174686 0.0003796380781566157 0.0002744930032920351 0.00018599940050380802 0.0001241355364397008 0.00008929388863324346 0.00007040658488428528 0.00005534001214467892 0.0000436586452042522 0.00004131938524832026 0.00006945342397726467 0.00012514458310738735 0.0002138467588570351 0.000338256955840437 0.0004984623059909889 0.0006923623475488193 0.0009202033550585049 0.0011822360315786303 0.0014533516270413829 0.0016700548810745673 0.0017673346539450892 0.001735580420641967 0.001622455124164982 0.0014775571166893047 0.0013145279401521092 0.001131106546132801 0.0009407587239141606 0.0007668541041885666 0.0006199289354965183 0.0004936140235558652 0.000382024115745763 0.00028670028072873423 0.00020825311966695008 0.0001453677778402752 0.0000989063797382611 0.00006978108319975388 0.00005348677304968862 0.00004244351625248937 0.000035385816829217384 0.00003439575992661075 0.00006258753462346604 0.00011779395139745125 0.00020424986233035043 0.00032066549541832077 0.0004633285841213848 0.0006304765274554535 0.0008239745350408543 0.0010447624265133982 0.001272210479264544 0.0014533516270413837 0.001531174685949784 0.0014949492493011303 0.001388830517658523 0.0012624736503087095 0.001127068963386338 0.0009705099287999389 0.0007970503483696857 0.0006317512268016386 0.0004938979088174708 0.0003820241157457642 0.000290299394369164 0.0002181793664899162 0.00016298950258330808 0.00011899803177516751 0.0000823691136406385 0.00005473562818606978 0.0000381200977722764 0.00002979625227629616 0.000026711709509457292 0.00002907783457792725 0.00005384413321553934 0.00010487748323798032 0.00018588342694629055 0.0002900741872742531 0.00040903351347927494 0.0005429488252746249 0.0006969509137475136 0.0008703087826223946 0.0010447624265133991 0.001182236031578632 0.00124087217343807 0.0012087368131948255 0.0011191498215588804 0.0010183403054298307 0.0009190083262633721 0.000801525491694968 0.0006561523056794529 0.0005052944369660935 0.00037963807815661775 0.00028670028072873575 0.00021817936648991685 0.0001660641990964909 0.00012541544784508313 0.00009202995412545457 0.00006174356940784516 0.00003722540034797393 0.00002325992677889447 0.00001916527902950255 0.000020711875659536765 0.000025213591859047883 0.000042629439945227365 0.00008197322550826253 0.00014795151506898877 0.00023213625592551497 0.00032644896295366284 0.0004344545721148293 0.0005606707485081431 0.000696950913747514 0.0008239745350408555 0.0009202033550585068 0.0009632349493911887 0.0009395915246891063 0.0008649531896832579 0.0007774910755573756 0.0006972250267069928 0.0006092634042455452 0.0004963521413852191 0.0003738581341875603 0.000274493003292037 0.0002082531196669518 0.00016298950258330903 0.00012541544784508356 0.00009202547110128986 0.00006383462345803265 0.00003947296941473735 0.000021744405128660332 0.000013352842787480663 0.000013239288145536595 0.000017848639275134693 0.000020781451388426948 0.00003105710711973318 0.000057456869677795945 0.00010458020730616448 0.00016570616231837576 0.0002372611122303529 0.00032649751656326506 0.0004344545721148304 0.0005429488252746265 0.0006304765274554557 0.0006923623475488219 0.000726163291897312 0.0007162791068696847 0.0006575346592259347 0.0005759894400297539 0.0004998642579464946 0.000427372010576195 0.0003431122089624073 0.0002543426496727917 0.00018599940050380962 0.00014536777784027708 0.00011899803177516887 0.00009202995412545545 0.0000638346234580331 0.00004128492951896302 0.000024903658690917228 0.000014330775707505503 0.00000978230860145257 0.000011326048856831784 0.000016053898680696832 0.00001478199822503725 0.000022238587657551035 0.00004136804712597435 0.00007448828453249694 0.00011594604344947506 0.00016665216540789763 0.00023726111223035346 0.0003264489629536644 0.0004090335134792767 0.0004633285841213871 0.0004984623059909912 0.0005270594962774785 0.0005328767055493038 0.0004938311102070544 0.0004227198059680341 0.0003519813156453301 0.00029156831156405713 0.00023073618568791556 0.00016975481507747544 0.0001241355364397018 0.00009890637973826253 0.00008236911364063934 0.00006174356940784596 0.00003947296941473778 0.000024903658690917296 0.000017165388517282642 0.000011558312453098908 0.000007436905036100288 0.000007875181309264785 0.000011415154720126562 0.000009341733308211362 0.000016996134178817797 0.00003342638176964267 0.00005781782971725264 0.0000841340859818309 0.0001159460434494757 0.00016570616231837692 0.0002321362559255168 0.0002900741872742551 0.00032066549541832294 0.0003382569558404392 0.0003605926497320423 0.00037463636281232843 0.00035330476953750005 0.0002999803279416953 0.0002445948996790601 0.00020099329412540448 0.00016134910101133878 0.00012122019196754075 0.00008929388863324417 0.00006978108319975487 0.00005473562818607066 0.0000372254003479746 0.000021744405128660878 0.000014330775707505504 0.000011558312453098906 0.000008699922739313134 0.000004768890798277165 0.0000032397046829931215 0.000005542266168584141 0.000006004795496699644 0.000012912197025183723 0.000026517972173533272 0.00004337238133691402 0.00005781782971725297 0.0000744882845324978 0.00010458020730616577 0.0001479515150689906 0.00018588342694629233 0.00020424986233035235 0.0002138467588570364 0.00022811134622592488 0.00023897829057065178 0.00022688081584744353 0.00019372829236130438 0.00016080406028930945 0.00013678820046357374 0.00011571395533526792 0.000092273343616298 0.00007040658488428555 0.00005348677304968876 0.00003812009777227678 0.000023259926778894647 0.000013352842787480995 0.000009782308601452464 0.000007436905036100242 0.000004768890798276993 0.000002103454138532517 6.970502856833257E-7 0.0000025097644122426328 0.000003996439040514289 0.000008048688828868533 0.000016860768505253996 0.000026517972173533455 0.000033426381769643115 0.000041368047125975154 0.000057456869677797124 0.00008197322550826404 0.00010487748323798178 0.00011779395139745266 0.00012514458310738821 0.0001326791248279212 0.00013665578847337024 0.00012916539479544686 0.0001138951617923706 0.00010098659556921528 0.00009111223839643561 0.00008108726648983308 0.0000687252541873559 0.000055340012144678453 0.00004244351625248936 0.00002979625227629596 0.000019165279029502547 0.00001323928814553634 0.000011326048856831317 0.000007875181309264238 0.0000032397046829926785 6.970502856830178E-7 6.283755755602484E-7 0.0000023858417075138655 0.0000021373228939816737 0.0000036084647764549282 0.000008048688828868455 0.000012912197025183933 0.000016996134178818275 0.00002223858765755196 0.00003105710711973445 0.000042629439945228917 0.00005384413321554071 0.00006258753462346711 0.00006945342397726515 0.00007386269411413275 0.000074949860329593 0.00007273331620748825 0.00006979335205074847 0.00006774528075202721 0.00006378627298063388 0.00005773213817805891 0.00005081018743245061 0.0000436586452042516 0.00003538581682921696 0.00002671170950945692 0.000020711875659536427 0.000017848639275134394 0.000016053898680696222 0.000011415154720125956 0.0000055422661685834875 0.0000025097644122421343 0.0000023858417075135064 0.0000027626156523720665 0.0000011014415294991077 0.000002455953188553955 0.0000060047954966982095 0.000011308388178076347 0.00001742322569700267 0.00002394546061241311 0.00003183885277159619 0.0000415809541746676 0.0000515750193740359 0.00006028885013159655 0.00006927841106991377 0.00007921512669109803 0.00008836635431708553 0.00009296217033426626 0.00009223278715530755 0.00009102652667143207 0.00009223278715530755 0.00009296217033426648 0.00008836635431708553 0.00007921512669109847 0.00006927841106991431 0.000060288850131596985 0.00005157501937403579 0.00004158095417466782 0.00003183885277159619 0.000023945460612413 0.000017423225697002563 0.00001130838817807594 0.000006004795496697966 0.0000024559531885535486 0.0000024559531885538493 0.0000020367229778568345 0.000002509764412241785 0.000005404657006734887 0.000010432721977928987 0.000015486976475090745 0.000019053487707614324 0.000022572177159262686 0.0000287666299524591 0.000037064620009627247 0.00004701150675250798 0.0000590670554739036 0.00007319711621451908 0.00008633426488525536 0.00009660617943874613 0.00010792134312512334 0.00012382628362150855 0.00014001957347209852 0.00014552776986352377 0.00013880284057141018 0.00012834877183813895 0.0001179612011765502 0.00010298248083767106 0.00007998449698244306 0.000056160024501310165 0.00003976068444587551 0.000030311141079121406 0.00002214979980321087 0.000012912197025181922 0.0000055356148465822605 0.000006004795496698422 0.0000025097644122420534 6.970502856830586E-7 0.0000021034541385329567 0.000004768890798277777 0.000007436905036100866 0.000009782308601453003 0.000013352842787480588 0.00002325992677889354 0.00003812009777227517 0.00005348677304968756 0.00007040658488428418 0.00009227334361629697 0.00011571395533526673 0.0001367882004635725 0.00016080406028930788 0.00019372829236130398 0.00022688081584744353 0.0002389782905706519 0.00022811134622592518 0.00021384675885703655 0.0002042498623303507 0.00018588342694628962 0.0001479515150689872 0.00010458020730616249 0.00007448828453249478 0.00005781782971725066 0.00004337238133691192 0.00002651797217353142 0.000012912197025182122 0.000011308388178076672 0.000005404657006735217 0.0000021034541385329617 0.0000025328140596884667 0.00000317877217892394 0.0000031201939834984807 0.000004898912629719532 0.000011059872777091713 0.000026642519656199345 0.00004802404642698151 0.00006835590124955169 0.00009168287533173682 0.00012639541981940454 0.0001683149555407384 0.00020775715760439038 0.0002493944217476879 0.00030167391628042526 0.0003502417832487409 0.000364465513432218 0.0003451011794924644 0.0003245071852586884 0.00031586544220100674 0.0002965114623418749 0.0002452872893603429 0.00018025469510181787 0.00013093515947900205 0.00009994215145477061 0.00007225334020257851 0.000043372381336912186 0.000022149799803211352 0.000017423225697003034 0.00001043272197792939 0.000004768890798277753 0.0000031787721789239 0.000004456594710891686 0.000005160683492612734 0.000007592282948860392 0.000017393788614679816 0.000038268184393989986 0.000062243267721062 0.00008400938969302691 0.00011453422882451952 0.00016700154404711122 0.00023540318016430556 0.0003017151935110238 0.0003666949538984365 0.00044161447486532583 0.0005110280207879582 0.0005378107763058998 0.0005189558821759169 0.000491527841542821 0.0004737128545823631 0.00044009280330434156 0.00036629691993682507 0.0002740329507050847 0.0001991324089233129 0.00014628899357183145 0.0000999421514547705 0.000057817829717250735 0.00003031114107912174 0.000023945460612413552 0.000015486976475091155 0.000007436905036101102 0.0000031201939834985823 0.000005160683492613007 0.000010385853195488016 0.00001880341685770464 0.000035082504194899516 0.000060656874779021644 0.00008687310358683714 0.00011318982875864764 0.0001565403139405482 0.00023267207177716633 0.00033243221307557706 0.00042942899124734265 0.000520989639560758 0.000624626478730455 0.0007311047369061573 0.0007970905713095698 0.0008006309005604029 0.0007669655867827643 0.0007181879547709627 0.0006398426918513255 0.0005202161617967752 0.00038815661933965857 0.0002798504780587137 0.00019913240892331318 0.00013093515947900226 0.00007448828453249514 0.00003976068444587607 0.000031838852771596484 0.000019053487707614723 0.000009782308601453074 0.000004898912629719679 0.0000075922829488607 0.000018803416857704492 0.00003721783122293183 0.00006124525023194392 0.00009092448574327717 0.0001243940374230858 0.00016697925239011875 0.00023652325713133428 0.0003471667243337949 0.00048445332287481833 0.0006161688271076252 0.0007402030304244064 0.0008828322819484 0.001044077037541584 0.0011733734294710797 0.0012183841389811474 0.001176654669354027 0.0010719536575662394 0.0009163199990738546 0.0007258660541463047 0.0005389628394804259 0.0003881566193396585 0.0002740329507050849 0.000180254695101818 0.00010458020730616272 0.00005616002450131056 0.00004158095417466803 0.00002257217715926318 0.000013352842787480771 0.000011059872777091947 0.00001739378861468023 0.00003508250419489966 0.0000612452502319441 0.00008987407423056648 0.0001230483526989908 0.00016905754840345746 0.00023964913362904753 0.00034950119417326926 0.000504257417278923 0.0006838316235267759 0.0008589568636188341 0.001031963980737475 0.0012316737057361765 0.0014604341919198362 0.0016589400069480268 0.0017456059351057581 0.0016880521502273208 0.0015115507963728541 0.0012607018118170803 0.000982944920174478 0.0007258660541463049 0.0005202161617967753 0.00036629691993682545 0.00024528728936034315 0.00014795151506898758 0.00007998449698244356 0.00005157501937403612 0.000028766629952459604 0.00002325992677889374 0.000026642519656199555 0.0000382681843939907 0.000060656874779021197 0.0000909244857432773 0.00012304835269899052 0.00016213711920641744 0.00022463885487634464 0.00032749602997659557 0.0004781079751338984 0.0006692846682037849 0.0008835265101450328 0.0011094531117226164 0.001356002967794807 0.0016396186116322178 0.001946569880229298 0.002204423345366915 0.0023155029140805253 0.002231884518609748 0.0019821064539637767 0.0016349871298253276 0.00126070181181708 0.0009163199990738548 0.0006398426918513257 0.00044009280330434205 0.00029651146234187524 0.00018588342694628995 0.00010298248083767152 0.000060288850131597046 0.000037064620009627355 0.00003812009777227552 0.00004802404642698156 0.00006224326772106227 0.0000868731035868369 0.00012439403742308503 0.00016905754840345634 0.0002246388548763436 0.00031008840053104635 0.00044308360009883004 0.0006217834696838479 0.0008297072438039148 0.0010612533502024877 0.0013314457145501772 0.0016584905708846606 0.0020380349828360155 0.0024239791870858617 0.00272520129786015 0.0028419649976218716 0.002727826283899672 0.0024148623704578053 0.0019821064539637767 0.0015115507963728546 0.0010719536575662394 0.0007181879547709629 0.0004737128545823634 0.000315865442201007 0.00020424986233035102 0.00011796120117655029 0.0000692784110699138 0.00004701150675250792 0.000053486773049687424 0.00006835590124955127 0.0000840093896930271 0.00011318982875864675 0.00016697925239011772 0.00023964913362904555 0.00032749602997659335 0.00044308360009882885 0.0006026697091401581 0.0008023405097078608 0.0010219478720986813 0.0012617286215816479 0.0015544662428557971 0.0019295502396633531 0.002369722530313519 0.002801816126635195 0.0031199679870699925 0.0032284375798712255 0.0030869250399333226 0.002727826283899672 0.002231884518609747 0.0016880521502273204 0.0011766546693540265 0.0007669655867827639 0.0004915278415428208 0.000324507185258688 0.000213846758857036 0.00012834877183813849 0.00007921512669109828 0.00005906705547390353 0.00007040658488428433 0.00009168287533173637 0.00011453422882451954 0.0001565403139405482 0.00023652325713133327 0.00034950119417326736 0.0004781079751338952 0.0006217834696838452 0.0008023405097078591 0.0010287461375446986 0.0012781043115712625 0.001534031609806589 0.0018231338833620294 0.0021839809405514547 0.0026064943852817275 0.003017057632244766 0.003310130795263662 0.003393885837083695 0.003228437579871225 0.0028419649976218707 0.0023155029140805245 0.0017456059351057575 0.0012183841389811468 0.0008006309005604022 0.0005189558821759165 0.00034510117949246375 0.0002281113462259248 0.00013880284057140967 0.0000883663543170857 0.0000731971162145191 0.00009227334361629699 0.00012639541981940468 0.00016700154404711143 0.00023267207177716593 0.0003471667243337946 0.0005042574172789216 0.0006692846682037823 0.0008297072438039117 0.0010219478720986787 0.001278104311571261 0.0015723081188699917 0.0018521698782702958 0.0021135152535489174 0.002399856396544477 0.002728447959614903 0.0030503657603172013 0.00327321590283921 0.0033101307952636615 0.003119967987069992 0.002725201297860149 0.002204423345366914 0.0016589400069480257 0.0011733734294710797 0.0007970905713095692 0.0005378107763058997 0.0003644655134322179 0.00023897829057065162 0.0001455277698635239 0.00009296217033426664 0.00008633426488525539 0.00011571395533526693 0.0001683149555407384 0.00023540318016430578 0.00033243221307557755 0.0004844533228748184 0.0006838316235267754 0.0008835265101450314 0.0010612533502024853 0.0012617286215816453 0.0015340316098065873 0.0018521698782702951 0.0021340427011982506 0.0023443134697092006 0.0025286503275099067 0.002732186407408238 0.0029314670065587107 0.003050365760317202 0.0030170576322447666 0.002801816126635194 0.002423979187085861 0.0019465698802292972 0.0014604341919198357 0.0010440770375415834 0.0007311047369061571 0.0005110280207879579 0.0003502417832487408 0.00022688081584744315 0.00014001957347209846 0.00009223278715530771 0.00009660617943874612 0.0001367882004635726 0.00020775715760439043 0.00030171519351102413 0.0004294289912473429 0.0006161688271076253 0.0008589568636188339 0.0011094531117226151 0.0013314457145501757 0.0015544662428557952 0.0018231338833620276 0.002113515253548916 0.0023443134697092 0.002478914196022791 0.002566043478233657 0.0026569839345356025 0.002732186407408238 0.0027284479596149033 0.0026064943852817267 0.0023697225303135187 0.0020380349828360146 0.0016396186116322173 0.0012316737057361758 0.0008828322819484001 0.0006246264787304548 0.00044161447486532616 0.0003016739162804253 0.00019372829236130362 0.0001238262836215087 0.00009102652667143187 0.00010792134312512311 0.00016080406028930807 0.0002493944217476877 0.00036669495389843673 0.0005209896395607587 0.0007402030304244065 0.0010319639807374755 0.0013560029677948066 0.0016584905708846597 0.001929550239663352 0.002183980940551454 0.002399856396544476 0.002528650327509906 0.002566043478233657 0.002566554332134192 0.002566043478233657 0.0025286503275099063 0.002399856396544478 0.0021839809405514547 0.0019295502396633527 0.0016584905708846602 0.0013560029677948063 0.001031963980737475 0.0007402030304244065 0.0005209896395607582 0.0003666949538984366 0.00024939442174768767 0.0001608040602893077 0.00010792134312512316 0.00009223278715530728 0.00012382628362150817 0.00019372829236130351 0.000301673916280425 0.00044161447486532626 0.0006246264787304553 0.0008828322819484007 0.0012316737057361765 0.0016396186116322178 0.0020380349828360155 0.002369722530313519 0.0026064943852817267 0.002728447959614903 0.002732186407408238 0.002656983934535603 0.0025660434782336576 0.0024789141960227918 0.002344313469709201 0.0021135152535489182 0.0018231338833620296 0.0015544662428557978 0.001331445714550177 0.0011094531117226162 0.000858956863618834 0.0006161688271076254 0.00042942899124734244 0.00030171519351102375 0.00020775715760438986 0.00013678820046357176 0.00009660617943874566 0.00009296217033426606 0.00014001957347209795 0.00022688081584744285 0.0003502417832487404 0.0005110280207879581 0.0007311047369061577 0.0010440770375415838 0.0014604341919198362 0.0019465698802292974 0.002423979187085861 0.0028018161266351945 0.003017057632244766 0.0030503657603172018 0.002931467006558711 0.0027321864074082384 0.0025286503275099067 0.0023443134697092014 0.002134042701198252 0.0018521698782702973 0.0015340316098065901 0.0012617286215816479 0.0010612533502024875 0.0008835265101450324 0.0006838316235267758 0.0004844533228748182 0.000332432213075577 0.00023540318016430497 0.0001683149555407375 0.00011571395533526582 0.00008633426488525487 0.00008836635431708509 0.0001455277698635234 0.0002389782905706513 0.0003644655134322173 0.0005378107763058997 0.0007970905713095697 0.0011733734294710804 0.0016589400069480262 0.0022044233453669144 0.002725201297860149 0.003119967987069992 0.003310130795263661 0.00327321590283921 0.0030503657603172018 0.0027284479596149033 0.002399856396544477 0.0021135152535489174 0.0018521698782702962 0.0015723081188699936 0.0012781043115712635 0.001021947872098681 0.000829707243803914 0.0006692846682037836 0.0005042574172789218 0.00034716672433379427 0.00023267207177716517 0.00016700154404711021 0.00012639541981940348 0.0000922733436162959 0.00007319711621451861 0.00007921512669109774 0.00013880284057140918 0.00022811134622592423 0.0003451011794924629 0.0005189558821759162 0.0008006309005604022 0.001218384138981147 0.0017456059351057575 0.002315502914080524 0.0028419649976218694 0.0032284375798712233 0.0033938858370836937 0.0033101307952636606 0.003017057632244765 0.0026064943852817262 0.0021839809405514534 0.0018231338833620283 0.0015340316098065875 0.001278104311571262 0.0010287461375446982 0.0008023405097078592 0.0006217834696838452 0.0004781079751338956 0.0003495011941732671 0.00023652325713133287 0.00015654031394054724 0.00011453422882451833 0.00009168287533173511 0.00007040658488428338 0.00005906705547390318 0.00006927841106991347 0.00012834877183813794 0.00021384675885703554 0.00032450718525868695 0.0004915278415428202 0.0007669655867827636 0.0011766546693540267 0.0016880521502273202 0.002231884518609747 0.00272782628389967 0.003086925039933321 0.0032284375798712233 0.003119967987069991 0.002801816126635193 0.002369722530313518 0.0019295502396633516 0.0015544662428557956 0.0012617286215816453 0.0010219478720986787 0.0008023405097078575 0.0006026697091401552 0.00044308360009882663 0.0003274960299765926 0.00023964913362904528 0.0001669792523901176 0.00011318982875864644 0.0000840093896930262 0.00006835590124955038 0.000053486773049687085 0.000047011506752507714 0.00006028885013159638 0.0001179612011765492 0.00020424986233035018 0.0003158654422010055 0.00047371285458236244 0.0007181879547709622 0.0010719536575662394 0.0015115507963728541 0.001982106453963776 0.0024148623704578036 0.00272782628389967 0.0028419649976218686 0.0027252012978601476 0.002423979187085859 0.002038034982836014 0.0016584905708846595 0.0013314457145501752 0.0010612533502024845 0.0008297072438039106 0.0006217834696838425 0.00044308360009882527 0.00031008840053104277 0.00022463885487634207 0.0001690575484034562 0.0001243940374230849 0.00008687310358683669 0.00006224326772106136 0.00004802404642698051 0.00003812009777227511 0.00003706462000962671 0.00005157501937403566 0.00010298248083767055 0.00018588342694628924 0.00029651146234187416 0.0004400928033043411 0.0006398426918513254 0.0009163199990738546 0.0012607018118170805 0.0016349871298253274 0.001982106453963776 0.0022318845186097462 0.002315502914080523 0.0022044233453669135 0.0019465698802292966 0.001639618611632217 0.0013560029677948063 0.0011094531117226154 0.0008835265101450306 0.0006692846682037811 0.00047810797513389276 0.00032749602997659037 0.00022463885487634106 0.000162137119206416 0.00012304835269899054 0.00009092448574327762 0.00006065687477902151 0.00003826818439399013 0.000026642519656198918 0.00002325992677889364 0.000028766629952459038 0.000041580954174667214 0.00007998449698244225 0.00014795151506898652 0.0002452872893603417 0.0003662969199368241 0.0005202161617967744 0.0007258660541463044 0.0009829449201744784 0.00126070181181708 0.0015115507963728537 0.0016880521502273193 0.001745605935105757 0.0016589400069480257 0.001460434191919835 0.0012316737057361763 0.0010319639807374757 0.000858956863618834 0.0006838316235267749 0.0005042574172789205 0.0003495011941732654 0.00023964913362904366 0.00016905754840345523 0.00012304835269899014 0.00008987407423056675 0.00006124525023194407 0.00003508250419489967 0.000017393788614679453 0.000011059872777091012 0.000013352842787480358 0.000022572177159262192 0.00003183885277159571 0.000056160024501309494 0.00010458020730616176 0.0001802546951018168 0.00027403295070508384 0.0003881566193396578 0.0005389628394804256 0.0007258660541463049 0.000916319999073855 0.0010719536575662394 0.001176654669354027 0.0012183841389811468 0.0011733734294710804 0.0010440770375415834 0.000882832281948401 0.000740203030424407 0.0006161688271076265 0.0004844533228748181 0.0003471667243337943 0.00023652325713133186 0.00016697925239011707 0.00012439403742308416 0.0000909244857432774 0.00006124525023194411 0.00003721783122293218 0.000018803416857704374 0.00000759228294886021 0.00000489891262971896 0.000009782308601452776 0.000019053487707613866 0.000023945460612412563 0.000039760684445874894 0.00007448828453249404 0.00013093515947900102 0.00019913240892331196 0.00027985047805871273 0.0003881566193396579 0.0005202161617967749 0.0006398426918513256 0.0007181879547709623 0.0007669655867827634 0.0008006309005604021 0.0007970905713095697 0.0007311047369061571 0.0006246264787304555 0.0005209896395607591 0.0004294289912473432 0.0003324322130755768 0.00023267207177716552 0.00015654031394054683 0.00011318982875864624 0.00008687310358683604 0.00006065687477902123 0.00003508250419489931 0.00001880341685770431 0.000010385853195487628 0.000005160683492612503 0.000003120193983497831 0.000007436905036100658 0.000015486976475090074 0.000017423225697002126 0.000030311141079120816 0.00005781782971724982 0.00009994215145476952 0.00014628899357183053 0.00019913240892331218 0.0002740329507050841 0.0003662969199368246 0.0004400928033043415 0.0004737128545823627 0.0004915278415428204 0.0005189558821759162 0.0005378107763058997 0.0005110280207879578 0.0004416144748653268 0.0003666949538984373 0.00030171519351102435 0.00023540318016430513 0.00016700154404711038 0.00011453422882451867 0.00008400938969302649 0.00006224326772106169 0.00003826818439399035 0.000017393788614679833 0.0000075922829488604 0.0000051606834926127 0.000004456594710891556 0.000003178772178923408 0.0000047688907982773585 0.000010432721977928382 0.000011308388178075708 0.000022149799803210498 0.000043372381336911197 0.00007225334020257758 0.0000999421514547696 0.00013093515947900129 0.00018025469510181714 0.00024528728936034234 0.0002965114623418742 0.00031586544220100576 0.0003245071852586869 0.00034510117949246316 0.0003644655134322173 0.0003502417832487405 0.0003016739162804254 0.00024939442174768805 0.0002077571576043903 0.00016831495554073776 0.00012639541981940335 0.0000916828753317356 0.00006835590124955031 0.000048024046426980946 0.00002664251965619906 0.00001105987277709156 0.0000048989126297193256 0.000003120193983498295 0.0000031787721789235633 0.0000025328140596876527 0.000002103454138532271 0.0000054046570067340305 0.000006004795496697858 0.000012912197025181817 0.00002651797217353093 0.00004337238133691148 0.000057817829717250125 0.0000744882845324944 0.00010458020730616219 0.00014795151506898687 0.00018588342694628954 0.00020424986233035037 0.00021384675885703576 0.0002281113462259242 0.00023897829057065148 0.00022688081584744255 0.00019372829236130376 0.0001608040602893079 0.0001367882004635722 0.00011571395533526572 0.00009227334361629608 0.00007040658488428344 0.000053486773049687505 0.00003812009777227526 0.00002325992677889372 0.000013352842787480348 0.000009782308601453135 0.000007436905036100798 0.000004768890798277512 0.0000021034541385321444 6.970502856824662E-7 0.0000025097644122411437 0.000002455953188553523 0.0000055356148465823 0.000012912197025181815 0.000022149799803210827 0.00003031114107912119 0.000039760684445875335 0.00005616002450130997 0.0000799844969824428 0.00010298248083767087 0.00011796120117654938 0.0001283487718381381 0.00013880284057140915 0.00014552776986352363 0.00014001957347209792 0.00012382628362150847 0.00010792134312512295 0.000096606179438746 0.00008633426488525512 0.00007319711621451849 0.0000590670554739035 0.00004701150675250808 0.000037064620009627084 0.00002876662995245912 0.000022572177159262612 0.00001905348770761432 0.000015486976475090545 0.0000104327219779287 0.000005404657006734168 0.000002509764412241259 0.000002036722977856108 0.0000031293124925022556 0.000004556866447381577 0.000009341733308211955 0.000017423225697004243 0.000026593106440489555 0.00003634591631691825 0.000050069925101144585 0.0000700209689794523 0.00009202672100430491 0.00010990207288447281 0.00012443697714305192 0.00013968876242537805 0.0001533803348213029 0.00015775652622948013 0.00015267581316423008 0.00014878985649779465 0.0001526758131642303 0.00015775652622948056 0.00015338033482130311 0.0001396887624253787 0.0001244369771430528 0.00010990207288447433 0.00009202672100430643 0.00007002096897945392 0.00005006992510114556 0.00003634591631691852 0.000026593106440488958 0.000017423225697003593 0.000009341733308211643 0.000004556866447381333 0.000004556866447381576 0.000003983409389724147 0.000005542266168585179 0.000010432721977930493 0.000016997532666015232 0.000022426327257492334 0.00002768680034134916 0.00003641977923896486 0.00004966829372031868 0.00006307845147368834 0.0000749864214438376 0.00008970530400963139 0.00010991083482162048 0.0001310749938927117 0.00014969492195175124 0.00017215285754228324 0.0002045318754074673 0.00023703570095634537 0.0002496268489333403 0.00023905748114611146 0.0002207519181065128 0.0002022661710982108 0.00017486743176160964 0.00013378777557353146 0.00009205475009134094 0.00006284740975602359 0.000044858176309477044 0.00003031114107912231 0.00001699613417881791 0.000008151547957649682 0.000009341733308211723 0.000005542266168585128 0.0000032397046829946783 0.000004768890798279072 0.000008699922739315044 0.000011558312453099845 0.000014330775707506477 0.000021744405128660634 0.00003722540034797373 0.00005473562818606947 0.00006978108319975389 0.00008929388863324299 0.00012122019196753952 0.00016134910101133618 0.00020099329412540237 0.0002445948996790583 0.0002999803279416953 0.0003533047695375013 0.00037463636281233006 0.00036059264973204374 0.00033825695584044097 0.00032066549541832397 0.00029007418727425516 0.00023213625592551564 0.00016570616231837494 0.00011594604344947282 0.00008413408598182838 0.00005781782971725101 0.00003342638176964219 0.00001699613417881771 0.000017423225697004243 0.000010432721977930746 0.000004768890798279305 0.000003178772178925172 0.000004456594710892471 0.00000516068349261315 0.000007592282948861032 0.000017393788614680114 0.00003826818439399077 0.00006224326772106257 0.00008400938969302709 0.00011453422882452001 0.00016700154404711105 0.000235403180164305 0.00030171519351102365 0.00036669495389843684 0.00044161447486532713 0.0005110280207879608 0.0005378107763059025 0.0005189558821759202 0.0004915278415428242 0.0004737128545823665 0.0004400928033043449 0.00036629691993682713 0.00027403295070508584 0.0001991324089233129 0.00014628899357183094 0.00009994215145477048 0.00005781782971725158 0.000030311141079122693 0.00002659310644048955 0.00001699753266601552 0.00000869992273931517 0.0000044565947108927375 0.000004787201589209632 0.0000057707171994394186 0.0000092811650637103 0.000021968432045004513 0.000046950126076282304 0.00007553666539708477 0.00010514847136896235 0.00015191940053495878 0.00023265115775077415 0.00033826785089126777 0.0004417062437438282 0.0005404671613561364 0.000650809913868007 0.0007582882900205607 0.0008160465074447732 0.0008095426567044875 0.000775324106980641 0.0007370114712795593 0.0006706709826168852 0.0005542117430241079 0.00041731035941536596 0.00030362571165412953 0.0002190980462848827 0.0001462889935718313 0.00008413408598182914 0.000044858176309477634 0.000036345916316918954 0.000022426327257493296 0.00001155831245310078 0.000005160683492613845 0.000005770717199440049 0.00001065768400657194 0.00001976722459274499 0.000037990950535600114 0.00006762487901667244 0.00010310204404458373 0.00014673972099954008 0.00021758712571749142 0.00033281035166037254 0.00048101407562923935 0.0006333943940810136 0.0007900615193276615 0.0009736510857595714 0.0011702724834703963 0.0013144301327347942 0.001357619312193841 0.0013149137141692095 0.0012147289412613573 0.001054170370761786 0.000837650187846445 0.00061443423145097 0.00043493165283709927 0.0003036257116541299 0.00019913240892331362 0.00011594604344947383 0.00006284740975602416 0.000050069925101145344 0.00002768680034135033 0.00001433077570750713 0.000007592282948861774 0.000009281165063710936 0.000019767224592745063 0.00003797559959623498 0.0000641857891828636 0.00010089256600215905 0.00015107953004165478 0.00022295862859127917 0.00033287461528254023 0.0004921829205170345 0.0006895470735222093 0.0009066580400836052 0.0011543632072385753 0.0014590527240740756 0.0018004153950183027 0.0020849230176929025 0.0022129533178503248 0.00215753309620079 0.0019497470457856582 0.001629992492352759 0.0012523497139305837 0.0008942164552661246 0.00061443423145097 0.0004173103594153662 0.00027403295070508617 0.00016570616231837532 0.00009205475009134103 0.00007002096897945362 0.000036419779238966543 0.000021744405128662118 0.000017393788614681625 0.000021968432045006332 0.00003799095053560157 0.00006418578918286504 0.00009673607156472298 0.00014055573155341824 0.00021079146292320793 0.0003238747221292818 0.000488359505814756 0.0007011280080980822 0.0009554476063526737 0.0012589495116249166 0.001638503470141067 0.0021106035581529687 0.0026293898016959963 0.0030673464280526826 0.0032799082195145495 0.003200677769729534 0.002863405644151266 0.002355939341597527 0.0017836111952503066 0.001252349713930584 0.0008376501878464447 0.0005542117430241079 0.00036629691993682757 0.00023213625592551594 0.00013378777557353146 0.00009202672100430658 0.000049668293720320905 0.00003722540034797547 0.00003826818439399216 0.00004695012607628424 0.00006762487901667339 0.000100892566002161 0.00014055573155341794 0.00019395528069379335 0.0002871615092159507 0.00044466320001632694 0.0006636557209989313 0.0009232854720992075 0.0012310199292264758 0.0016351864912215184 0.002180842443607052 0.0028541081215029012 0.0035548620122397632 0.004117426952608126 0.004379127580087881 0.004261837790878292 0.003804765825581194 0.003124326272372129 0.0023559393415975263 0.0016299924923527589 0.0010541703707617855 0.0006706709826168848 0.00044009280330434476 0.00029007418727425516 0.00017486743176160947 0.00010990207288447468 0.00006307845147369019 0.00005473562818607131 0.00006224326772106361 0.0000755366653970865 0.00010310204404458526 0.0001510795300416558 0.00021079146292320738 0.00028716150921594987 0.0004103825706411249 0.0006090221462856632 0.0008696279545382154 0.0011583572591615165 0.0015021101566728308 0.0019935386997361353 0.0026987296766766236 0.00356559349575431 0.004422978400784092 0.005065990398946283 0.005337764510923133 0.005174646336827468 0.0046228314730095855 0.0038047658255811936 0.002863405644151265 0.0019497470457856575 0.0012147289412613566 0.0007370114712795587 0.0004737128545823666 0.00032066549541832413 0.00020226617109821073 0.00012443697714305314 0.00007498642144383895 0.00006978108319975496 0.00008400938969302804 0.00010514847136896317 0.00014673972099954046 0.00022295862859127987 0.0003238747221292813 0.0004446632000163255 0.000609022146285663 0.0008478810904686633 0.0011458895699827541 0.001460493792564863 0.0018252040088143613 0.0023618270227441967 0.0031582873446044644 0.004139463137881498 0.005081308636276989 0.005751359337704071 0.00600452093612034 0.005795395785142974 0.005174646336827468 0.00426183779087829 0.003200677769729532 0.0021575330962007888 0.001314913714169208 0.0007753241069806399 0.0004915278415428239 0.0003382569558404406 0.00022075191810651308 0.0001396887624253793 0.00008970530400963235 0.00008929388863324446 0.00011453422882452027 0.00015191940053495932 0.00021758712571749264 0.00033287461528254034 0.0004883595058147556 0.0006636557209989296 0.0008696279545382143 0.0011458895699827526 0.001490218126094515 0.0018515398190606298 0.002240658034798414 0.002773962381173297 0.003552837721414815 0.004510620325940204 0.0054211106133543185 0.006050605342605956 0.0062588429466127376 0.0060045209361203385 0.00533776451092313 0.004379127580087878 0.003279908219514547 0.0022129533178503226 0.0013576193121938392 0.0008095426567044858 0.0005189558821759193 0.00036059264973204396 0.00023905748114611154 0.00015338033482130387 0.00010991083482162193 0.00012122019196754055 0.0001670015440471118 0.0002326511577507751 0.0003328103516603732 0.0004921829205170356 0.0007011280080980815 0.0009232854720992061 0.0011583572591615156 0.001460493792564862 0.0018515398190606294 0.0022749560695569785 0.002694549901459466 0.003183343133357702 0.0038416187382218974 0.004640662862214505 0.005402100311051645 0.005918258582049202 0.0060506053426059555 0.00575135933770407 0.005065990398946282 0.004117426952608124 0.00306734642805268 0.002084923017692901 0.0013144301327347927 0.0008160465074447725 0.0005378107763059024 0.0003746363628123302 0.00024962684893334086 0.00015775652622948108 0.00013107499389271285 0.00016134910101133813 0.0002354031801643059 0.0003382678508912686 0.0004810140756292409 0.0006895470735222102 0.0009554476063526743 0.0012310199292264751 0.0015021101566728302 0.0018252040088143598 0.0022406580347984133 0.0026945499014594666 0.0031091760870718323 0.0035057823399257397 0.0039758207687176335 0.004534767905786572 0.005066004126662922 0.005402100311051646 0.0054211106133543185 0.0050813086362769865 0.00442297840078409 0.00355486201223976 0.002629389801695994 0.001800415395018301 0.0011702724834703948 0.0007582882900205598 0.0005110280207879605 0.00035330476953750173 0.00023703570095634594 0.00015267581316423068 0.00014969492195175246 0.0002009932941254036 0.00030171519351102435 0.0004417062437438293 0.0006333943940810149 0.0009066580400836069 0.0012589495116249172 0.0016351864912215184 0.001993538699736136 0.0023618270227441962 0.002773962381173297 0.003183343133357702 0.0035057823399257406 0.0037430278481098904 0.003984092645329025 0.004273017834966273 0.004534767905786573 0.004640662862214506 0.0045106203259402036 0.004139463137881497 0.0035655934957543093 0.0028541081215028995 0.0021106035581529665 0.0014590527240740745 0.0009736510857595701 0.0006508099138680072 0.00044161447486532784 0.0002999803279416962 0.00020453187540746804 0.00014878985649779497 0.00017215285754228413 0.00024459489967905955 0.0003666949538984374 0.0005404671613561379 0.0007900615193276639 0.0011543632072385775 0.0016385034701410694 0.0021808424436070535 0.0026987296766766257 0.0031582873446044657 0.0035528377214148164 0.0038416187382218987 0.003975820768717634 0.003984092645329026 0.003967720801133171 0.003984092645329027 0.003975820768717635 0.003841618738221899 0.003552837721414816 0.003158287344604464 0.0026987296766766227 0.0021808424436070505 0.0016385034701410658 0.0011543632072385747 0.0007900615193276613 0.000540467161356137 0.0003666949538984374 0.0002445948996790594 0.00017215285754228413 0.00015267581316422978 0.00020453187540746723 0.00029998032794169576 0.00044161447486532757 0.0006508099138680079 0.0009736510857595726 0.0014590527240740774 0.002110603558152971 0.002854108121502904 0.003565593495754314 0.004139463137881502 0.004510620325940207 0.0046406628622145075 0.0045347679057865745 0.004273017834966274 0.003984092645329027 0.003743027848109892 0.0035057823399257415 0.003183343133357704 0.0027739623811732974 0.0023618270227441967 0.0019935386997361345 0.0016351864912215158 0.0012589495116249144 0.0009066580400836044 0.0006333943940810125 0.00044170624374382866 0.00030171519351102386 0.00020099329412540278 0.00014969492195175154 0.00015775652622947964 0.00023703570095634486 0.000353304769537501 0.0005110280207879599 0.0007582882900205603 0.001170272483470396 0.0018004153950183029 0.002629389801695997 0.003554862012239764 0.0044229784007840936 0.005081308636276991 0.005421110613354321 0.00540210031105165 0.005066004126662925 0.0045347679057865745 0.003975820768717635 0.003505782339925742 0.0031091760870718336 0.0026945499014594688 0.0022406580347984154 0.0018252040088143611 0.00150211015667283 0.0012310199292264734 0.0009554476063526725 0.0006895470735222084 0.00048101407562923935 0.0003382678508912682 0.00023540318016430543 0.00016134910101133694 0.0001310749938927115 0.00015338033482130225 0.0002496268489333398 0.00037463636281232946 0.0005378107763059015 0.0008160465074447725 0.0013144301327347935 0.002084923017692902 0.003067346428052682 0.0041174269526081265 0.005065990398946285 0.005751359337704073 0.006050605342605959 0.005918258582049207 0.00540210031105165 0.004640662862214508 0.0038416187382219 0.0031833431333577046 0.0026945499014594683 0.0022749560695569807 0.0018515398190606315 0.0014604937925648631 0.0011583572591615154 0.0009232854720992048 0.00070112800809808 0.0004921829205170341 0.000332810351660372 0.00023265115775077458 0.00016700154404711103 0.00012122019196753919 0.00010991083482162033 0.0001396887624253777 0.00023905748114611054 0.00036059264973204314 0.0005189558821759181 0.0008095426567044853 0.001357619312193839 0.002212953317850322 0.0032799082195145474 0.004379127580087879 0.005337764510923132 0.00600452093612034 0.006258842946612739 0.00605060534260596 0.005421110613354321 0.004510620325940207 0.003552837721414817 0.0027739623811732983 0.0022406580347984137 0.0018515398190606307 0.001490218126094514 0.001145889569982752 0.0008696279545382119 0.0006636557209989272 0.0004883595058147534 0.00033287461528253844 0.00021758712571749115 0.0001519194005349586 0.00011453422882451916 0.00008929388863324295 0.00008970530400963067 0.00012443697714305152 0.0002207519181065119 0.0003382569558404398 0.0004915278415428223 0.0007753241069806388 0.0013149137141692069 0.0021575330962007875 0.003200677769729531 0.004261837790878289 0.005174646336827467 0.005795395785142973 0.00600452093612034 0.0057513593377040715 0.005081308636276991 0.0041394631378815 0.0031582873446044657 0.0023618270227441962 0.00182520400881436 0.0014604937925648612 0.00114588956998275 0.0008478810904686599 0.0006090221462856584 0.0004446632000163218 0.00032387472212927845 0.00022295862859127754 0.00014673972099953878 0.00010514847136896181 0.00008400938969302643 0.00006978108319975339 0.00007498642144383692 0.00010990207288447275 0.0002022661710982091 0.00032066549541832304 0.00047371285458236456 0.0007370114712795571 0.0012147289412613544 0.0019497470457856552 0.0028634056441512626 0.00380476582558119 0.004622831473009582 0.005174646336827465 0.005337764510923129 0.0050659903989462825 0.00442297840078409 0.0035655934957543114 0.002698729676676624 0.0019935386997361345 0.0015021101566728278 0.0011583572591615133 0.0008696279545382099 0.0006090221462856575 0.00041038257064111936 0.00028716150921594515 0.0002107914629232052 0.00015107953004165318 0.00010310204404458332 0.00007553666539708456 0.00006224326772106128 0.00005473562818606937 0.00006307845147368759 0.00009202672100430502 0.00017486743176160807 0.00029007418727425424 0.00044009280330434324 0.0006706709826168832 0.0010541703707617834 0.001629992492352756 0.002355939341597524 0.003124326272372125 0.0038047658255811897 0.004261837790878287 0.004379127580087877 0.004117426952608124 0.003554862012239762 0.0028541081215029017 0.0021808424436070527 0.0016351864912215169 0.0012310199292264728 0.0009232854720992034 0.0006636557209989256 0.000444663200016321 0.0002871615092159456 0.00019395528069378974 0.00014055573155341648 0.00010089256600215916 0.00006762487901667237 0.00004695012607628267 0.000038268184393990325 0.000037225400347974075 0.000049668293720318595 0.0000700209689794522 0.00013378777557352997 0.00023213625592551475 0.0003662969199368258 0.0005542117430241061 0.0008376501878464423 0.0012523497139305814 0.0017836111952503038 0.002355939341597523 0.0028634056441512613 0.0032006777697295282 0.003279908219514545 0.00306734642805268 0.0026293898016959954 0.0021106035581529687 0.0016385034701410677 0.0012589495116249161 0.0009554476063526725 0.0007011280080980799 0.0004883595058147531 0.00032387472212927856 0.00021079146292320554 0.00014055573155341656 0.00009673607156472282 0.00006418578918286429 0.000037990950535601395 0.00002196843204500532 0.000017393788614680317 0.000021744405128661362 0.00003641977923896463 0.00005006992510114432 0.00009205475009133987 0.00016570616231837424 0.00027403295070508476 0.00041731035941536477 0.0006144342314509682 0.0008942164552661226 0.0012523497139305814 0.001629992492352756 0.0019497470457856543 0.002157533096200786 0.00221295331785032 0.0020849230176929008 0.0018004153950183005 0.001459052724074076 0.001154363207238576 0.0009066580400836065 0.0006895470735222085 0.0004921829205170346 0.0003328746152825376 0.0002229586285912786 0.00015107953004165364 0.00010089256600215984 0.00006418578918286429 0.000037975599596235755 0.00001976722459274575 0.000009281165063711231 0.000007592282948861567 0.000014330775707507263 0.000027686800341349196 0.000036345916316917815 0.00006284740975602299 0.00011594604344947272 0.00019913240892331237 0.0003036257116541287 0.0004349316528370979 0.0006144342314509684 0.0008376501878464427 0.001054170370761783 0.0012147289412613536 0.001314913714169205 0.001357619312193837 0.001314430132734792 0.0011702724834703946 0.0009736510857595717 0.0007900615193276627 0.0006333943940810151 0.0004810140756292398 0.00033281035166037314 0.00021758712571749033 0.00014673972099954016 0.00010310204404458375 0.00006762487901667336 0.000037990950535601585 0.000019767224592746194 0.000010657684006573166 0.0000057707171994407425 0.000005160683492613977 0.000011558312453100927 0.000022426327257492093 0.000026593106440488467 0.00004485817630947679 0.00008413408598182843 0.00014628899357183077 0.00021909804628488235 0.00030362571165412877 0.00041731035941536493 0.0005542117430241064 0.000670670982616883 0.0007370114712795565 0.0007753241069806378 0.0008095426567044842 0.0008160465074447714 0.0007582882900205593 0.0006508099138680077 0.0005404671613561382 0.00044170624374382996 0.00033826785089126864 0.00023265115775077526 0.00015191940053495935 0.000105148471368963 0.00007553666539708624 0.00004695012607628412 0.000021968432045006756 0.000009281165063712161 0.000005770717199441211 0.000004787201589210744 0.000004456594710892873 0.000008699922739314981 0.000016997532666014256 0.000017423225697003058 0.00003031114107912197 0.0000578178297172511 0.00009994215145477031 0.00014628899357183096 0.00019913240892331256 0.0002740329507050851 0.00036629691993682605 0.000440092803304343 0.00047371285458236423 0.0004915278415428213 0.0005189558821759175 0.0005378107763059015 0.0005110280207879596 0.0004416144748653279 0.0003666949538984386 0.000301715193511025 0.00023540318016430624 0.00016700154404711192 0.00011453422882452015 0.00008400938969302702 0.00006224326772106311 0.00003826818439399188 0.000017393788614682103 0.000007592282948862718 0.000005160683492614906 0.000004456594710893072 0.000003178772178924716 0.0000047688907982784605 0.00001043272197792916 0.000009341733308210957 0.00001699613417881743 0.00003342638176964216 0.00005781782971725131 0.00008413408598182883 0.00011594604344947287 0.00016570616231837448 0.0002321362559255147 0.000290074187274254 0.00032066549541832283 0.00033825695584043924 0.00036059264973204266 0.0003746363628123298 0.00035330476953750124 0.0002999803279416969 0.0002445948996790598 0.00020099329412540397 0.0001613491010113377 0.00012122019196754052 0.0000892938886332434 0.00006978108319975454 0.00005473562818607017 0.000037225400347975586 0.00002174440512866193 0.000014330775707507957 0.000011558312453100982 0.000008699922739314998 0.000004768890798278284 0.000003239704682993797 0.000005542266168583941 0.000004556866447381192 0.000008151547957649602 0.000016996134178818045 0.00003031114107912279 0.00004485817630947777 0.00006284740975602347 0.00009205475009134027 0.00013378777557353013 0.0001748674317616082 0.00020226617109820924 0.00022075191810651178 0.00023905748114611027 0.00024962684893334 0.00023703570095634475 0.00020453187540746755 0.00017215285754228448 0.00014969492195175194 0.00013107499389271174 0.00010991083482162089 0.00008970530400963116 0.00007498642144383785 0.00006307845147368914 0.0000496682937203204 0.0000364197792389662 0.00002768680034135053 0.000022426327257492916 0.00001699753266601474 0.00001043272197792967 0.000005542266168584561 0.000003983409389723437 0.000009565617953679229 0.000010512830864501315 0.000014781998225036111 0.000023945460612412946 0.000036345916316916894 0.0000514295506268594 0.0000736423676416469 0.00010639592520414812 0.00014390693080602716 0.00017526872371932548 0.000198232534474443 0.00021814488333106712 0.00023414234946933727 0.00023864228845880226 0.00023234710462510192 0.0002276846954364642 0.0002323471046251028 0.000238642288458804 0.00023414234946933943 0.00021814488333107103 0.00019823253447444778 0.00017526872371933025 0.00014390693080603128 0.0001063959252041505 0.00007364236764164874 0.000051429550626861135 0.000036345916316917544 0.00002394546061241273 0.000014781998225036735 0.000010512830864501315 0.000010512830864500938 0.000010520403821836045 0.000011415154720125172 0.000015486976475089603 0.000022426327257490114 0.00003005028381015896 0.000040463698035909926 0.000057993578281353885 0.00008184139687992986 0.00010322000910759108 0.00011896774347643668 0.0001371915999013051 0.00016417085279852184 0.00019570183389348505 0.0002253991227909334 0.0002578894038511493 0.00030060001191083944 0.0003440034197444265 0.00036504846722240815 0.0003560422190484409 0.00033140131162270837 0.0003003899004650747 0.0002556769954001614 0.00019532748400063194 0.0001360065985799574 0.00009243873198667915 0.00006284740975602314 0.00003976068444587522 0.00002223858765754991 0.000012999980140398524 0.000014781998225035949 0.000011415154720125412 0.000007875181309262793 0.000007436905036098886 0.00001155831245309693 0.00001716538851728076 0.000024903658690916063 0.00003947296941473592 0.0000617435694078424 0.00008236911364063455 0.00009890637973825918 0.00012413553643969729 0.0001697548150774735 0.000230736185687913 0.0002915683115640538 0.0003519813156453269 0.0004227198059680316 0.0004938311102070528 0.0005328767055493037 0.0005270594962774782 0.0004984623059909915 0.00046332858412138634 0.000409033513479277 0.0003264489629536633 0.00023726111223035243 0.0001666521654078959 0.00011594604344947263 0.00007448828453249409 0.000041368047125972186 0.00002223858765754949 0.000023945460612412106 0.00001548697647508912 0.0000074369050360980084 0.0000031201939834955563 0.000005160683492609013 0.00001038585319548425 0.000018803416857701596 0.000035082504194897476 0.00006065687477901769 0.00008687310358683215 0.00011318982875864333 0.00015654031394054429 0.000232672071777164 0.00033243221307557603 0.0004294289912473399 0.0005209896395607559 0.0006246264787304529 0.0007311047369061561 0.0007970905713095697 0.0008006309005604036 0.0007669655867827656 0.0007181879547709647 0.000639842691851328 0.0005202161617967771 0.00038815661933965976 0.000279850478058714 0.00019913240892331261 0.00013093515947900115 0.00007448828453249432 0.00003976068444587504 0.00003634591631691635 0.000022426327257489908 0.000011558312453096316 0.000005160683492609428 0.000005770717199434233 0.000010657684006565916 0.000019767224592739462 0.000037990950535595554 0.00006762487901666623 0.00010310204404457773 0.00014673972099953328 0.00021758712571748565 0.0003328103516603683 0.0004810140756292372 0.0006333943940810102 0.0007900615193276593 0.0009736510857595673 0.0011702724834703922 0.0013144301327347907 0.0013576193121938379 0.0013149137141692073 0.001214728941261355 0.0010541703707617847 0.0008376501878464435 0.0006144342314509688 0.0004349316528370986 0.0003036257116541291 0.0001991324089233122 0.00011594604344947219 0.00006284740975602233 0.00005142955062685911 0.00003005028381015901 0.00001716538851728061 0.000010385853195484833 0.00001065768400656642 0.000016583212038356986 0.00002852916790209378 0.000051132788221313236 0.00008826731038414268 0.00013978608385999846 0.00021069153291212932 0.00031773507373240753 0.0004765515140829146 0.0006826700179281677 0.000922898554807162 0.0012072437313161203 0.0015553507761918541 0.001935566873213156 0.0022442729591142284 0.0023815163812629966 0.0023263946674731396 0.002110820674846313 0.0017698156072572192 0.0013573848039995394 0.0009616761756505637 0.0006521197197017322 0.00043493165283709835 0.0002798504780587135 0.0001666521654078948 0.0000924387319866776 0.00007364236764164657 0.00004046369803590985 0.000024903658690915422 0.00001880341685770199 0.0000197672245927391 0.000028529167902092255 0.0000466416265857588 0.00007753218240796042 0.00012770593467778012 0.00020537152754663245 0.0003185229014366685 0.0004755767626457426 0.0006872824206897146 0.0009682847789069711 0.0013400322643710167 0.0018268018963580755 0.0024284076200209266 0.003075601895107347 0.0036190780350586114 0.003896104402377146 0.003824457020248541 0.0034314450613520163 0.0028175502559398624 0.0021175621572112483 0.0014682296666435253 0.0009616761756505635 0.0006144342314509684 0.0003881566193396588 0.0002372611122303507 0.0001360065985799555 0.00010639592520414836 0.00005799357828135423 0.00003947296941473617 0.000035082504194898066 0.00003799095053559609 0.000051132788221313134 0.00007753218240796162 0.00011815501475325578 0.00018259355712859317 0.00029086213465636225 0.0004580270798664932 0.0006808862036298985 0.0009614150171436365 0.0013428023934787103 0.0018950825958768758 0.0026546496802874794 0.0035749591955013833 0.00452618886654798 0.00532025186854428 0.0057449444572470745 0.00564867826547514 0.0050451035960170625 0.004111723142629156 0.0030750543906270084 0.0021175621572112474 0.0013573848039995387 0.0008376501878464424 0.0005202161617967756 0.0003264489629536616 0.00019532748400062958 0.00014390693080602862 0.00008184139687993204 0.00006174356940784423 0.000060656874779020126 0.00006762487901666858 0.00008826731038414361 0.00012770593467778394 0.00018259355712859496 0.00026363326213075513 0.00040315658918494703 0.0006269184999834613 0.0009209194452240705 0.0012775314669896 0.0017735870623411683 0.0025357859259002263 0.0036108433250700133 0.004883702047003988 0.006144054076131455 0.007172574512613117 0.007727115860575974 0.007593348891884837 0.006767615584404148 0.005502479458646104 0.004111723142629155 0.002817550255939862 0.0017698156072572181 0.0010541703707617827 0.0006398426918513263 0.0004090335134792741 0.00025567699540015855 0.00017526872371932843 0.0001032200091075937 0.00008236911364063835 0.00008687310358683626 0.0001031020440445812 0.00013978608386000258 0.00020537152754663816 0.000290862134656367 0.0004031565891849512 0.0005817603729256107 0.0008625415369535966 0.0012246577971138633 0.001651926371329776 0.0022502321078609728 0.003201956733093729 0.004570037806178959 0.006171924531510288 0.00771043317878115 0.008932914694551075 0.009578011906467706 0.0093861663720719 0.008343439782146935 0.006767615584404148 0.005045103596017063 0.0034314450613520155 0.0021108206748463123 0.0012147289412613536 0.0007181879547709634 0.00046332858412138493 0.0003003899004650723 0.00019823253447444588 0.00011896774347643942 0.00009890637973826143 0.00011318982875864646 0.0001467397209995374 0.00021069153291213322 0.0003185229014366743 0.0004580270798664997 0.000626918499983468 0.0008625415369536014 0.0012086120836674085 0.0016434510892206968 0.0021391237296633733 0.0028100800161901967 0.003877184629721819 0.005425288999380866 0.007230885503687016 0.008929833570272596 0.010237380254440178 0.010884820552833414 0.010602809983184984 0.0093861663720719 0.007593348891884834 0.005648678265475139 0.0038244570202485392 0.002326394667473138 0.001314913714169205 0.000766965586782764 0.0004984623059909889 0.00033140131162270626 0.00021814488333107019 0.0001371915999013081 0.00012413553643970176 0.0001565403139405482 0.00021758712571749004 0.0003177350737324144 0.0004755767626457488 0.0006808862036299065 0.0009209194452240799 0.0012246577971138728 0.0016434510892207024 0.0021621361682891216 0.0027352573802774567 0.0034530126341166365 0.004537419787465311 0.006089358996347639 0.007885851634352308 0.009543175734881953 0.010762009478327438 0.011287232360719128 0.010884820552833411 0.009578011906467702 0.007727115860575971 0.005744944457247072 0.0038961044023771447 0.0023815163812629953 0.001357619312193836 0.000800630900560402 0.0005270594962774765 0.0003560422190484392 0.0002341423494693385 0.00016417085279852334 0.00016975481507747488 0.0002326720717771661 0.0003328103516603715 0.0004765515140829175 0.0006872824206897205 0.0009614150171436425 0.0012775314669896086 0.0016519263713297859 0.0021391237296633824 0.0027352573802774606 0.0033781442189325314 0.004107130107226397 0.005105322245516997 0.006480340695556078 0.00805326866256104 0.009473934063312555 0.010451266211617063 0.010762009478327434 0.010237380254440176 0.008932914694551073 0.007172574512613115 0.005320251868544277 0.0036190780350586114 0.0022442729591142267 0.0013144301327347894 0.0007970905713095684 0.0005328767055493017 0.0003650484672224066 0.0002386422884588031 0.00019570183389348625 0.00023073618568791488 0.00033243221307557744 0.00048101407562923935 0.0006826700179281712 0.0009682847789069752 0.0013428023934787157 0.0017735870623411753 0.002250232107860982 0.002810080016190206 0.0034530126341166425 0.0041071301072264 0.0047603283170296485 0.0055452060541457005 0.0065805791958524875 0.007765271584428243 0.008819247828205529 0.009473934063312553 0.009543175734881948 0.008929833570272591 0.007710433178781145 0.006144054076131452 0.00452618886654798 0.003075601895107346 0.0019355668732131549 0.0011702724834703913 0.000731104736906156 0.0004938311102070523 0.000344003419744425 0.00023234710462510298 0.00022539912279093512 0.00029156831156405556 0.0004294289912473424 0.0006333943940810131 0.0009228985548071664 0.0013400322643710213 0.0018950825958768806 0.002535785925900232 0.0032019567330937387 0.0038771846297218286 0.004537419787465318 0.0051053222455170015 0.005545206054145705 0.0059636461988787845 0.006507829512702054 0.007171889765094902 0.007765271584428243 0.008053268662561038 0.007885851634352304 0.0072308855036870125 0.006171924531510285 0.004883702047003985 0.003574959195501383 0.0024284076200209266 0.0015553507761918535 0.0009736510857595679 0.0006246264787304535 0.0004227198059680314 0.00030060001191083917 0.00022768469543646433 0.00025788940385114987 0.0003519813156453285 0.0005209896395607576 0.0007900615193276616 0.0012072437313161253 0.0018268018963580792 0.0026546496802874846 0.0036108433250700194 0.004570037806178968 0.005425288999380875 0.006089358996347647 0.006480340695556084 0.006580579195852492 0.006507829512702056 0.006452482316727427 0.0065078295127020515 0.006580579195852485 0.0064803406955560765 0.006089358996347634 0.0054252889993808605 0.004570037806178957 0.0036108433250700116 0.0026546496802874802 0.001826801896358076 0.0012072437313161218 0.0007900615193276601 0.0005209896395607572 0.00035198131564532706 0.0002578894038511489 0.0002323471046251026 0.0003006000119108398 0.0004227198059680326 0.000624626478730454 0.0009736510857595697 0.0015553507761918578 0.0024284076200209305 0.0035749591955013876 0.004883702047003993 0.006171924531510297 0.0072308855036870255 0.007885851634352316 0.008053268662561047 0.0077652715844282495 0.0071718897650949074 0.006507829512702054 0.005963646198878782 0.005545206054145698 0.005105322245516994 0.004537419787465304 0.0038771846297218147 0.0032019567330937265 0.002535785925900224 0.0018950825958768762 0.001340032264371018 0.0009228985548071632 0.0006333943940810121 0.00042942899124734206 0.000291568311564054 0.0002253991227909338 0.00023864228845880243 0.00034400341974442537 0.0004938311102070531 0.0007311047369061564 0.0011702724834703935 0.0019355668732131586 0.003075601895107349 0.004526188866547984 0.00614405407613146 0.007710433178781155 0.008929833570272603 0.00954317573488196 0.009473934063312562 0.008819247828205534 0.007765271584428247 0.006580579195852489 0.0055452060541457 0.004760328317029645 0.004107130107226392 0.003453012634116629 0.00281008001619019 0.0022502321078609697 0.0017735870623411675 0.0013428023934787126 0.0009682847789069727 0.0006826700179281693 0.00048101407562923864 0.0003324322130755773 0.00023073618568791307 0.00019570183389348473 0.0002341423494693375 0.0003650484672224069 0.0005328767055493025 0.000797090571309569 0.0013144301327347916 0.00224427295911423 0.003619078035058615 0.005320251868544282 0.007172574512613122 0.008932914694551082 0.010237380254440188 0.010762009478327445 0.010451266211617072 0.00947393406331256 0.008053268662561045 0.006480340695556082 0.005105322245516998 0.004107130107226395 0.0033781442189325258 0.0027352573802774498 0.002139123729663369 0.001651926371329775 0.0012775314669896017 0.0009614150171436406 0.0006872824206897184 0.00047655151408291634 0.00033281035166037097 0.00023267207177716563 0.00016975481507747303 0.00016417085279852163 0.00021814488333106907 0.00035604221904843926 0.0005270594962774771 0.0008006309005604022 0.001357619312193838 0.002381516381262998 0.0038961044023771477 0.005744944457247076 0.007727115860575977 0.009578011906467709 0.01088482055283342 0.011287232360719136 0.010762009478327443 0.009543175734881957 0.007885851634352313 0.006089358996347642 0.004537419787465313 0.003453012634116636 0.0027352573802774554 0.002162136168289116 0.0016434510892206957 0.0012246577971138665 0.0009209194452240763 0.0006808862036299057 0.0004755767626457476 0.00031773507373241387 0.00021758712571748966 0.0001565403139405474 0.00012413553643969992 0.0001371915999013062 0.0001982325344744452 0.00033140131162270637 0.0004984623059909898 0.0007669655867827641 0.0013149137141692064 0.00232639466747314 0.003824457020248541 0.005648678265475141 0.0075933488918848374 0.009386166372071904 0.010602809983184988 0.010884820552833418 0.010237380254440183 0.0089298335702726 0.00723088550368702 0.00542528899938087 0.0038771846297218234 0.0028100800161902006 0.002139123729663379 0.0016434510892207005 0.0012086120836674128 0.0008625415369536038 0.0006269184999834691 0.00045802707986650096 0.00031852290143667407 0.00021069153291213393 0.00014673972099953702 0.00011318982875864587 0.00009890637973826036 0.00011896774347643793 0.00017526872371932808 0.00030038990046507227 0.0004633285841213856 0.000718187954770963 0.0012147289412613549 0.0021108206748463136 0.0034314450613520176 0.005045103596017065 0.00676761558440415 0.008343439782146933 0.009386166372071902 0.009578011906467706 0.008932914694551078 0.007710433178781151 0.006171924531510292 0.004570037806178964 0.003201956733093734 0.002250232107860979 0.0016519263713297857 0.001224657797113875 0.0008625415369536093 0.0005817603729256206 0.00040315658918495603 0.0002908621346563703 0.00020537152754663854 0.00013978608386000434 0.00010310204404458114 0.00008687310358683577 0.00008236911364063789 0.00010322000910759252 0.0001439069308060293 0.00025567699540015915 0.00040903351347927494 0.0006398426918513264 0.0010541703707617836 0.0017698156072572197 0.002817550255939863 0.004111723142629157 0.005502479458646106 0.0067676155844041495 0.007593348891884835 0.007727115860575974 0.007172574512613119 0.006144054076131457 0.00488370204700399 0.0036108433250700185 0.0025357859259002302 0.0017735870623411755 0.0012775314669896114 0.0009209194452240842 0.0006269184999834771 0.00040315658918495847 0.000263633262130762 0.00018259355712859864 0.00012770593467778532 0.00008826731038414665 0.00006762487901666954 0.00006065687477902062 0.00006174356940784502 0.0000818413968799319 0.00010639592520414935 0.00019532748400063015 0.0003264489629536621 0.0005202161617967754 0.0008376501878464423 0.0013573848039995385 0.0021175621572112474 0.003075054390627009 0.004111723142629155 0.0050451035960170625 0.005648678265475138 0.005744944457247074 0.005320251868544281 0.004526188866547982 0.003574959195501387 0.0026546496802874854 0.0018950825958768814 0.0013428023934787176 0.0009614150171436482 0.0006808862036299125 0.0004580270798665076 0.0002908621346563732 0.0001825935571286007 0.0001181550147532603 0.00007753218240796379 0.00005113278822131678 0.000037990950535597675 0.000035082504194898845 0.00003947296941473756 0.00005799357828135463 0.00007364236764164817 0.00013600659857995658 0.00023726111223035126 0.0003881566193396586 0.0006144342314509681 0.0009616761756505631 0.0014682296666435253 0.002117562157211248 0.0028175502559398633 0.003431445061352016 0.0038244570202485405 0.0038961044023771456 0.003619078035058615 0.0030756018951073488 0.0024284076200209313 0.0018268018963580799 0.0013400322643710232 0.0009682847789069777 0.0006872824206897248 0.0004755767626457522 0.00031852290143668025 0.0002053715275466418 0.00012770593467778803 0.00007753218240796359 0.0000466416265857618 0.000028529167902095897 0.000019767224592741505 0.000018803416857703378 0.000024903658690917645 0.000040463698035911085 0.00005142955062686055 0.00009243873198667857 0.00016665216540789503 0.0002798504780587133 0.00043493165283709764 0.0006521197197017313 0.000961676175650563 0.0013573848039995385 0.0017698156072572181 0.0021108206748463114 0.0023263946674731374 0.0023815163812629958 0.0022442729591142297 0.0019355668732131573 0.0015553507761918582 0.001207243731316125 0.0009228985548071683 0.0006826700179281726 0.0004765515140829219 0.0003177350737324163 0.00021069153291213973 0.0001397860838600053 0.00008826731038414794 0.0000511327882213154 0.000028529167902095413 0.000016583212038359615 0.000010657684006568264 0.000010385853195485914 0.000017165388517282744 0.000030050283810160288 0.00003634591631691775 0.0000628474097560234 0.00011594604344947243 0.00019913240892331245 0.0003036257116541287 0.00043493165283709753 0.0006144342314509678 0.0008376501878464419 0.0010541703707617825 0.0012147289412613527 0.001314913714169205 0.001357619312193835 0.0013144301327347914 0.0011702724834703933 0.0009736510857595705 0.0007900615193276627 0.0006333943940810141 0.0004810140756292426 0.0003328103516603753 0.000217587125717493 0.0001467397209995421 0.00010310204404458428 0.00006762487901667222 0.000037990950535598535 0.00001976722459274149 0.000010657684006568768 0.00000577071719943607 0.000005160683492610466 0.000011558312453098434 0.0000224263272574913 0.000023945460612413054 0.0000397606844458758 0.00007448828453249428 0.0001309351594790015 0.00019913240892331218 0.00027985047805871295 0.000388156619339658 0.0005202161617967749 0.0006398426918513243 0.0007181879547709615 0.0007669655867827621 0.0008006309005604 0.0007970905713095695 0.0007311047369061568 0.0006246264787304543 0.0005209896395607591 0.00042942899124734385 0.0003324322130755808 0.00023267207177716913 0.00015654031394055136 0.00011318982875864875 0.00008687310358683866 0.00006065687477902303 0.000035082504194899746 0.00001880341685770348 0.000010385853195486339 0.00000516068349261015 0.000003120193983496121 0.000007436905036099654 0.00001548697647508999 0.000014781998225036672 0.000022238587657550164 0.00004136804712597216 0.00007448828453249472 0.00011594604344947238 0.0001666521654078945 0.00023726111223035056 0.0003264489629536609 0.00040903351347927353 0.0004633285841213831 0.0004984623059909877 0.0005270594962774742 0.0005328767055493032 0.0004938311102070524 0.00042271980596803347 0.00035198131564532885 0.00029156831156405664 0.00023073618568791532 0.00016975481507747742 0.00012413553643970233 0.00009890637973826463 0.0000823691136406397 0.00006174356940784727 0.00003947296941473751 0.00002490365869091769 0.000017165388517282368 0.000011558312453097915 0.000007436905036099069 0.000007875181309264164 0.000011415154720126097 0.000010512830864501312 0.000012999980140398875 0.00002223858765754962 0.000039760684445875646 0.00006284740975602264 0.00009243873198667753 0.00013600659857995544 0.00019532748400062907 0.0002556769954001573 0.00030038990046506994 0.00033140131162270474 0.000356042219048437 0.000365048467222407 0.000344003419744425 0.0003006000119108392 0.0002578894038511498 0.0002253991227909351 0.0001957018338934871 0.00016417085279852442 0.00013719159990130828 0.00011896774347644118 0.00010322000910759489 0.00008184139687993429 0.00005799357828135562 0.00004046369803591202 0.000030050283810160898 0.00002242632725749099 0.000015486976475089718 0.00001141515472012626 0.000010520403821836417 0.000017222828270286916 0.00001741283372363222 0.000020781451388427683 0.00003183885277159825 0.00005006992510114578 0.00007364236764164874 0.00010556425488906975 0.00014926894555382072 0.00019991623908953513 0.0002451672234140825 0.00027877854625725767 0.0003040176982251567 0.0003235039291855637 0.00033441079730572865 0.0003361344573057923 0.0003352029974325356 0.0003361344573057897 0.0003344107973057278 0.0003235039291855637 0.00030401769822515495 0.0002787785462572568 0.00024516722341408163 0.0001999162390895347 0.00014926894555381985 0.00010556425488906867 0.00007364236764164842 0.000050069925101144585 0.00003183885277159679 0.000020781451388427412 0.00001741283372363184 0.00001741283372363213 0.000017076032718200067 0.000016053898680698075 0.000019053487707616333 0.000027686800341350724 0.00004046369803591242 0.000058839255895106405 0.00008587912888931043 0.00012021240778397742 0.00015154206168441206 0.00017592000902818451 0.00020289046441401942 0.00024181346590353508 0.0002898163901862291 0.0003349742989234373 0.00037446751049341465 0.00041543744447833744 0.00045571802826237603 0.00047878926010503774 0.00047351329888212245 0.00044462886976899606 0.00039880592165459164 0.0003363917239214423 0.00026232352305726326 0.0001919925815837915 0.00013600659857995696 0.00009205475009134023 0.00005616002450131104 0.00003105710711973365 0.00001954853828186915 0.000020781451388428178 0.000016053898680698726 0.000011326048856833274 0.000009782308601454928 0.000014330775707507915 0.000024903658690919322 0.00004128492951896587 0.00006383462345803564 0.00009202995412545742 0.00011899803177517085 0.00014536777784027877 0.00018599940050381022 0.0002543426496727912 0.00034311220896240794 0.0004273720105761965 0.0004998642579464935 0.0005759894400297546 0.0006575346592259349 0.0007162791068696851 0.0007261632918973096 0.000692362347548822 0.0006304765274554558 0.0005429488252746259 0.00043445457211482993 0.0003264975165632639 0.00023726111223035135 0.00016570616231837418 0.00010458020730616313 0.00005745686967779581 0.00003105710711973412 0.00003183885277159818 0.000019053487707616566 0.000009782308601454604 0.000004898912629721735 0.000007592282948862543 0.000018803416857706898 0.00003721783122293514 0.00006124525023194773 0.0000909244857432813 0.00012439403742309124 0.00016697925239012016 0.0002365232571313375 0.00034716672433379584 0.00048445332287482164 0.0006161688271076281 0.0007402030304244086 0.0008828322819484016 0.0010440770375415866 0.0011733734294710817 0.0012183841389811496 0.0011766546693540297 0.001071953657566242 0.0009163199990738567 0.0007258660541463074 0.0005389628394804272 0.000388156619339659 0.0002740329507050848 0.00018025469510181817 0.00010458020730616391 0.00005616002450131228 0.000050069925101145676 0.00002768680034135087 0.000014330775707507634 0.000007592282948862893 0.00000928116506371165 0.000019767224592745703 0.00003797559959623588 0.00006418578918286552 0.0001008925660021609 0.00015107953004165868 0.00022295862859127936 0.0003328746152825414 0.0004921829205170343 0.0006895470735222107 0.0009066580400836058 0.0011543632072385766 0.0014590527240740763 0.0018004153950183042 0.0020849230176929016 0.0022129533178503226 0.0021575330962007896 0.0019497470457856582 0.0016299924923527573 0.0012523497139305829 0.0008942164552661231 0.0006144342314509689 0.0004173103594153651 0.0002740329507050849 0.0001657061623183747 0.00009205475009134124 0.00007364236764164912 0.000040463698035913036 0.000024903658690919647 0.00001880341685770734 0.000019767224592746408 0.0000285291679021 0.000046641626585767215 0.00007753218240796757 0.0001277059346777906 0.0002053715275466433 0.00031852290143667987 0.00047557676264574974 0.0006872824206897223 0.000968284778906975 0.001340032264371022 0.0018268018963580783 0.0024284076200209313 0.003075601895107351 0.003619078035058615 0.0038961044023771477 0.0038244570202485427 0.0034314450613520202 0.0028175502559398637 0.002117562157211251 0.0014682296666435272 0.000961676175650565 0.0006144342314509691 0.00038815661933965954 0.00023726111223035191 0.00013600659857995742 0.0001055642548890696 0.00005883925589510617 0.00004128492951896523 0.00003721783122293537 0.0000379755995962357 0.00004664162658576585 0.00006935526794948106 0.00011089533149965061 0.00018172430257399152 0.0002970360003488049 0.0004639337960051313 0.000679723422008454 0.0009616996260649231 0.0013718781379051658 0.0019875854776645503 0.002834046611981744 0.0038449800445796004 0.004884730385322294 0.005769895370865572 0.006270310653227988 0.006190457485260748 0.005522965993520521 0.004478765621190833 0.003335298109769367 0.002294832699007048 0.0014682296666435276 0.0008942164552661234 0.0005389628394804275 0.00032649751656326414 0.00019199258158379218 0.0001492689455538206 0.0000858791288893104 0.0000638346234580353 0.00006124525023194808 0.00006418578918286539 0.00007753218240796795 0.00011089533149965058 0.0001681751866778894 0.0002627441367086598 0.00041937212860091735 0.0006500135096252661 0.0009448983181505493 0.0013339424895266404 0.001936662429462747 0.002888371790448019 0.004192815454864293 0.005688885411737056 0.007194256015802472 0.00853527201755081 0.009383109611456558 0.009317982583385747 0.008248830730131534 0.006586079256877101 0.0048550501102774335 0.0033352981097693663 0.0021175621572112504 0.0012523497139305824 0.000725866054146307 0.00043445457211482955 0.0002623235230572629 0.00019991623908953627 0.00012021240778397891 0.0000920299541254573 0.00009092448574328152 0.00010089256600216118 0.00012770593467778952 0.00018172430257399247 0.00026274413670865864 0.00038445738581479054 0.0005833386314490051 0.0008847228995316223 0.0012792562992190344 0.0018108488201475682 0.0026549678017238915 0.0040011689290604365 0.005824229496243898 0.007878392384066563 0.009977253075154284 0.011973630808074337 0.013355186574400194 0.013326033228026436 0.011664359723122488 0.009110995346707661 0.006586079256877101 0.004478765621190832 0.0028175502559398646 0.0016299924923527567 0.000916319999073857 0.0005429488252746257 0.0003363917239214429 0.00024516722341408223 0.00015154206168441133 0.00011899803177517026 0.00012439403742308866 0.00015107953004165532 0.00020537152754664256 0.00029703600034880224 0.0004193721286009149 0.0005833386314490033 0.000836403898914005 0.0012208498047828063 0.0017314033525384158 0.00241985937463722 0.0035046384072238627 0.005225728102749312 0.0075469727353497315 0.010174247183974281 0.012938092278920265 0.01569272215250288 0.017674996409659055 0.017646077493263045 0.015258430610257596 0.011664359723122486 0.008248830730131532 0.005522965993520518 0.0034314450613520185 0.0019497470457856552 0.001071953657566242 0.0006304765274554547 0.00039880592165459115 0.000278778546257258 0.00017592000902818462 0.00014536777784027744 0.0001669792523901203 0.00022295862859127868 0.0003185229014366769 0.0004639337960051305 0.0006500135096252628 0.0008847228995316201 0.0012208498047828053 0.0017124336763814888 0.0023548311695479303 0.0031929167216776452 0.0044628838411544195 0.00644373146324931 0.00910666745054715 0.012128142883814001 0.01532637714196794 0.01852265778312246 0.020780306627006542 0.020611122010000135 0.017646077493263045 0.013326033228026432 0.009317982583385745 0.006190457485260745 0.003824457020248542 0.0021575330962007866 0.0011766546693540289 0.0006923623475488206 0.00044462886976899654 0.0003040176982251572 0.00020289046441401736 0.00018599940050381003 0.0002365232571313349 0.0003328746152825381 0.0004755767626457499 0.0006797234220084497 0.0009448983181505469 0.0012792562992190307 0.0017314033525384145 0.0023548311695479277 0.0031372780911037693 0.004098860343354649 0.0054609172296757776 0.007517489748370425 0.010250489182735958 0.013300080450640451 0.01641060648739892 0.01935827036648119 0.021259632970865444 0.02078030662700654 0.017674996409659048 0.01335518657440019 0.009383109611456554 0.006270310653227985 0.003896104402377147 0.002212953317850321 0.0012183841389811492 0.0007261632918973111 0.00047351329888212256 0.000323503929185565 0.00024181346590353462 0.0002543426496727915 0.0003471667243337957 0.0004921829205170333 0.0006872824206897201 0.0009616996260649228 0.0013339424895266383 0.0018108488201475667 0.002419859374637219 0.0031929167216776452 0.004098860343354648 0.005121132327984123 0.006439066476751876 0.008340585241485126 0.010834126637829374 0.013543651521091854 0.016108051723821838 0.0182594250735667 0.019358270366481183 0.018522657783122457 0.015692722152502878 0.011973630808074334 0.008535272017550806 0.005769895370865572 0.0036190780350586135 0.0020849230176929003 0.001173373429471082 0.0007162791068696837 0.0004787892601050378 0.00033441079730572854 0.00028981639018622744 0.00034311220896240767 0.00048445332287481947 0.0006895470735222077 0.0009682847789069749 0.001371878137905162 0.001936662429462744 0.0026549678017238876 0.003504638407223862 0.004462883841154417 0.005460917229675775 0.006439066476751874 0.007521783518469322 0.008986628223726752 0.01091608195421444 0.013006136920165742 0.014842004087681637 0.016108051723821838 0.016410606487398918 0.015326377141967933 0.01293809227892026 0.00997725307515428 0.007194256015802469 0.004884730385322292 0.003075601895107349 0.0018004153950183014 0.0010440770375415866 0.0006575346592259346 0.0004557180282623756 0.00033613445730579103 0.00033497429892343547 0.00042737201057619495 0.0006161688271076264 0.0009066580400836043 0.0013400322643710213 0.001987585477664549 0.002888371790448017 0.004001168929060434 0.005225728102749314 0.00644373146324931 0.007517489748370426 0.008340585241485125 0.008986628223726754 0.009724646432491059 0.010754562411234783 0.01196189193032467 0.013006136920165742 0.013543651521091854 0.013300080450640446 0.012128142883814 0.01017424718397428 0.007878392384066561 0.005688885411737053 0.003844980044579599 0.0024284076200209296 0.0014590527240740763 0.0008828322819484037 0.000575989440029754 0.00041543744447833847 0.00033520299743253527 0.000374467510493413 0.0004998642579464946 0.0007402030304244072 0.0011543632072385755 0.0018268018963580796 0.002834046611981742 0.004192815454864291 0.005824229496243898 0.0075469727353497315 0.00910666745054715 0.010250489182735958 0.010834126637829372 0.010916081954214441 0.010754562411234783 0.010655259614595913 0.010754562411234781 0.010916081954214441 0.010834126637829372 0.010250489182735956 0.009106667450547149 0.00754697273534973 0.005824229496243897 0.004192815454864291 0.002834046611981742 0.0018268018963580788 0.0011543632072385768 0.0007402030304244102 0.0004998642579464946 0.0003744675104934138 0.0003361344573057903 0.00041543744447833717 0.0005759894400297539 0.0008828322819484009 0.0014590527240740752 0.002428407620020931 0.003844980044579599 0.0056888854117370545 0.007878392384066561 0.010174247183974283 0.012128142883814004 0.013300080450640451 0.013543651521091856 0.013006136920165745 0.01196189193032467 0.010754562411234783 0.009724646432491057 0.008986628223726752 0.008340585241485125 0.007517489748370423 0.006443731463249309 0.00522572810274931 0.004001168929060435 0.002888371790448016 0.0019875854776645495 0.0013400322643710202 0.0009066580400836062 0.0006161688271076293 0.0004273720105761948 0.00033497429892343547 0.00033441079730572735 0.0004557180282623742 0.0006575346592259346 0.0010440770375415842 0.001800415395018301 0.00307560189510735 0.004884730385322292 0.007194256015802469 0.00997725307515428 0.012938092278920264 0.01532637714196794 0.01641060648739892 0.016108051723821834 0.014842004087681639 0.013006136920165742 0.01091608195421444 0.00898662822372675 0.007521783518469321 0.006439066476751876 0.005460917229675776 0.004462883841154415 0.0035046384072238623 0.002654967801723887 0.001936662429462745 0.0013718781379051628 0.0009682847789069746 0.0006895470735222096 0.00048445332287482234 0.00034311220896240724 0.0002898163901862271 0.0003235039291855637 0.00047878926010503666 0.0007162791068696842 0.0011733734294710806 0.0020849230176929008 0.003619078035058615 0.005769895370865573 0.008535272017550806 0.011973630808074336 0.01569272215250288 0.018522657783122464 0.01935827036648119 0.0182594250735667 0.016108051723821838 0.013543651521091854 0.010834126637829372 0.008340585241485125 0.006439066476751876 0.005121132327984125 0.00409886034335465 0.0031929167216776452 0.00241985937463722 0.001810848820147567 0.0013339424895266398 0.0009616996260649239 0.0006872824206897204 0.0004921829205170349 0.00034716672433379833 0.0002543426496727912 0.00024181346590353394 0.00030401769822515555 0.00047351329888212137 0.0007261632918973113 0.0012183841389811474 0.0022129533178503213 0.0038961044023771473 0.006270310653227985 0.009383109611456553 0.01335518657440019 0.01767499640965905 0.020780306627006542 0.021259632970865444 0.019358270366481186 0.016410606487398918 0.013300080450640447 0.010250489182735955 0.0075174897483704225 0.005460917229675773 0.004098860343354649 0.0031372780911037663 0.002354831169547929 0.0017314033525384132 0.0012792562992190305 0.0009448983181505475 0.0006797234220084514 0.0004755767626457503 0.00033287461528253953 0.00023652325713133655 0.00018599940050380967 0.00020289046441401612 0.00027877854625725626 0.0004446288697689952 0.0006923623475488209 0.0011766546693540276 0.0021575330962007875 0.0038244570202485414 0.006190457485260745 0.009317982583385743 0.013326033228026429 0.017646077493263038 0.020611122010000132 0.02078030662700654 0.018522657783122454 0.015326377141967934 0.012128142883814 0.009106667450547149 0.006443731463249307 0.004462883841154416 0.003192916721677644 0.0023548311695479256 0.0017124336763814862 0.001220849804782802 0.000884722899531618 0.0006500135096252631 0.0004639337960051314 0.0003185229014366779 0.00022295862859127925 0.00016697925239012108 0.00014536777784027708 0.00017592000902818278 0.00024516722341408033 0.00039880592165458947 0.0006304765274554548 0.0010719536575662402 0.0019497470457856554 0.0034314450613520163 0.005522965993520517 0.008248830730131529 0.011664359723122483 0.015258430610257584 0.017646077493263038 0.017674996409659045 0.015692722152502878 0.012938092278920257 0.01017424718397428 0.007546972735349728 0.00522572810274931 0.003504638407223859 0.0024198593746372174 0.00173140335253841 0.0012208498047828005 0.0008364038989140004 0.0005833386314490006 0.00041937212860091485 0.00029703600034880224 0.00020537152754664364 0.000151079530041655 0.00012439403742308847 0.00011899803177516971 0.00015154206168440894 0.00019991623908953454 0.0003363917239214414 0.0005429488252746257 0.0009163199990738562 0.0016299924923527567 0.0028175502559398633 0.004478765621190831 0.0065860792568770985 0.009110995346707656 0.011664359723122481 0.013326033228026427 0.013355186574400187 0.01197363080807433 0.009977253075154279 0.007878392384066561 0.005824229496243895 0.004001168929060433 0.0026549678017238863 0.001810848820147565 0.0012792562992190264 0.0008847228995316162 0.0005833386314489988 0.00038445738581478647 0.000262744136708658 0.0001817243025739924 0.0001277059346777907 0.00010089256600216032 0.0000909244857432809 0.00009202995412545675 0.00012021240778397656 0.0001492689455538187 0.0002623235230572611 0.0004344545721148291 0.000725866054146306 0.0012523497139305818 0.0021175621572112487 0.0033352981097693646 0.004855050110277432 0.006586079256877097 0.008248830730131523 0.009317982583385738 0.009383109611456551 0.008535272017550803 0.0071942560158024665 0.0056888854117370545 0.004192815454864292 0.0028883717904480168 0.0019366624294627427 0.0013339424895266387 0.0009448983181505443 0.0006500135096252611 0.000419372128600912 0.00026274413670865685 0.000168175186677889 0.00011089533149965108 0.00007753218240796904 0.00006418578918286436 0.00006124525023194694 0.00006383462345803438 0.00008587912888930786 0.00010556425488906781 0.00019199258158379055 0.0003264975165632636 0.0005389628394804269 0.0008942164552661237 0.0014682296666435268 0.002294832699007048 0.003335298109769366 0.004478765621190832 0.005522965993520514 0.006190457485260743 0.006270310653227982 0.005769895370865571 0.004884730385322288 0.003844980044579601 0.00283404661198174 0.0019875854776645503 0.001371878137905161 0.0009616996260649249 0.0006797234220084476 0.00046393379600513077 0.00029703600034879904 0.00018172430257399087 0.00011089533149964874 0.00006935526794948163 0.000046641626585766457 0.00003797559959623504 0.000037217831222933955 0.000041284929518964227 0.00005883925589510377 0.00007364236764164702 0.00013600659857995542 0.00023726111223035086 0.0003881566193396591 0.0006144342314509695 0.0009616761756505648 0.0014682296666435279 0.0021175621572112504 0.0028175502559398624 0.003431445061352015 0.0038244570202485384 0.0038961044023771447 0.003619078035058612 0.0030756018951073475 0.002428407620020932 0.0018268018963580772 0.0013400322643710213 0.0009682847789069726 0.0006872824206897214 0.00047557676264574545 0.000318522901436678 0.00020537152754663865 0.00012770593467778852 0.0000775321824079654 0.0000466416265857667 0.000028529167902100498 0.00001976722459274507 0.00001880341685770536 0.00002490365869091799 0.000040463698035910326 0.00005006992510114385 0.00009205475009133954 0.00016570616231837375 0.00027403295070508525 0.0004173103594153662 0.0006144342314509691 0.0008942164552661246 0.0012523497139305827 0.0016299924923527563 0.001949747045785653 0.0021575330962007857 0.0022129533178503196 0.0020849230176929 0.0018004153950183003 0.0014590527240740771 0.0011543632072385768 0.0009066580400836048 0.0006895470735222084 0.0004921829205170355 0.00033287461528253823 0.00022295862859127857 0.0001510795300416539 0.00010089256600216013 0.00006418578918286504 0.00003797559959623617 0.00001976722459274703 0.000009281165063710943 0.000007592282948861104 0.000014330775707506121 0.000027686800341348515 0.000031838852771596525 0.000056160024501310795 0.00010458020730616288 0.00018025469510181874 0.0002740329507050858 0.00038815661933965943 0.0005389628394804278 0.0007258660541463073 0.0009163199990738565 0.0010719536575662396 0.0011766546693540271 0.0012183841389811483 0.0011733734294710793 0.001044077037541585 0.0008828322819484035 0.0007402030304244084 0.0006161688271076267 0.00048445332287482077 0.00034716672433379654 0.0002365232571313344 0.00016697925239012084 0.00012439403742308845 0.00009092448574328031 0.00006124525023194832 0.000037217831222935094 0.000018803416857707738 0.000007592282948861659 0.000004898912629719904 0.000009782308601453017 0.00001905348770761447 0.00002078145138842714 0.00003105710711973328 0.00005745686967779514 0.00010458020730616406 0.0001657061623183752 0.00023726111223035197 0.00032649751656326506 0.00043445457211483074 0.0005429488252746259 0.0006304765274554537 0.0006923623475488201 0.0007261632918973122 0.0007162791068696839 0.0006575346592259341 0.0005759894400297566 0.0004998642579464945 0.0004273720105761968 0.00034311220896240745 0.0002543426496727941 0.0001859994005038074 0.0001453677778402782 0.00011899803177516738 0.00009202995412545686 0.00006383462345803376 0.000041284929518965385 0.000024903658690919176 0.000014330775707506619 0.000009782308601452996 0.000011326048856832181 0.000016053898680697235 0.00001741283372363156 0.00001954853828186883 0.00003105710711973334 0.000056160024501312015 0.00009205475009134129 0.000136006598579957 0.0001919925815837928 0.00026232352305726337 0.0003363917239214427 0.0003988059216545908 0.00044462886976899616 0.00047351329888212305 0.00047878926010503693 0.00045571802826237614 0.00041543744447833977 0.00037446751049341427 0.0003349742989234356 0.0002898163901862289 0.00024181346590353476 0.00020289046441401568 0.0001759200090281847 0.00015154206168441068 0.00012021240778397708 0.00008587912888930916 0.0000588392558951052 0.00004046369803591241 0.000027686800341349284 0.000019053487707614506 0.000016053898680697317 0.000017076032718199058 0.00002016830905914911 0.000020434020735810585 0.000025213591859049405 0.00004158095417467042 0.0000700209689794537 0.00010639592520414898 0.00014926894555381898 0.00020101434534479162 0.00026156901156281463 0.0003213239699373892 0.00036883179365407824 0.00040141036955367027 0.0004262350267254973 0.0004496109766508917 0.00046879496476522585 0.0004764957920562699 0.00046879496476522585 0.00044961097665089343 0.0004262350267254956 0.00040141036955367373 0.0003688317936540817 0.0003213239699373857 0.00026156901156281637 0.00020101434534479292 0.00014926894555381941 0.00010639592520415115 0.00007002096897945306 0.00004158095417466955 0.000025213591859048808 0.000020434020735811073 0.00002043402073580984 0.000019088382184321653 0.000017848639275136065 0.000022572177159265163 0.00003641977923896626 0.00005799357828135498 0.00008587912888930795 0.000121217746713224 0.00016484178283184304 0.00020872672490351081 0.00024777767599728725 0.0002890580940773158 0.0003443313341783649 0.00041445894177783577 0.0004813101651604745 0.000528762512149438 0.0005603349195352459 0.0005865215698875146 0.0006045988410517434 0.0006011759042085235 0.0005666602319166265 0.0005030317145494069 0.00042223688521968677 0.0003384606851108134 0.0002623235230572627 0.00019532748400063254 0.00013378777557353057 0.00007998449698244487 0.000042629439945227914 0.000025034130620912688 0.000025213591859047748 0.000017848639275135218 0.000013239288145537937 0.000013352842787483133 0.000021744405128662595 0.000039472969414737765 0.00006383462345803325 0.0000920254711012881 0.0001254154478450835 0.00016298950258330854 0.00020825311966695022 0.00027449300329203516 0.0003738581341875596 0.0004963521413852147 0.0006092634042455473 0.0006972250267069924 0.0007774910755573765 0.0008649531896832558 0.0009395915246891064 0.0009632349493911865 0.0009202033550585057 0.000823974535040851 0.0006969509137475159 0.0005606707485081435 0.00043445457211482977 0.00032644896295366403 0.0002321362559255148 0.00014795151506898907 0.00008197322550826237 0.00004262943994522783 0.00004158095417466899 0.000022572177159264133 0.000013352842787482213 0.000011059872777094312 0.00001739378861468206 0.00003508250419490083 0.00006124525023194476 0.00008987407423056634 0.0001230483526989911 0.00016905754840345737 0.00023964913362904425 0.0003495011941732715 0.0005042574172789188 0.0006838316235267738 0.0008589568636188338 0.0010319639807374755 0.001231673705736176 0.001460434191919836 0.001658940006948028 0.0017456059351057603 0.001688052150227322 0.0015115507963728535 0.0012607018118170842 0.0009829449201744812 0.0007258660541463063 0.000520216161796778 0.00036629691993682664 0.00024528728936034445 0.00014795151506898863 0.00007998449698244478 0.00007002096897945306 0.00003641977923896592 0.000021744405128661616 0.000017393788614682303 0.000021968432045006593 0.00003799095053560039 0.00006418578918286177 0.00009673607156471977 0.00014055573155341238 0.00021079146292320167 0.0003238747221292761 0.0004883595058147554 0.0007011280080980785 0.0009554476063526703 0.001258949511624915 0.0016385034701410666 0.0021106035581529656 0.0026293898016959945 0.0030673464280526804 0.0032799082195145495 0.0032006777697295317 0.0028634056441512613 0.0023559393415975268 0.001783611195250306 0.0012523497139305822 0.0008376501878464459 0.0005542117430241074 0.0003662969199368268 0.00023213625592551461 0.00013378777557353097 0.00010639592520415006 0.00005799357828135611 0.00003947296941473816 0.00003508250419490173 0.00003799095053560212 0.00005113278822131752 0.000077532182407965 0.00011815501475325719 0.00018259355712859965 0.0002908621346563631 0.0004580270798665035 0.0006808862036299006 0.0009614150171436405 0.0013428023934787074 0.001895082595876876 0.002654649680287479 0.003574959195501383 0.004526188866547981 0.005320251868544279 0.005744944457247075 0.00564867826547514 0.0050451035960170625 0.004111723142629159 0.0030750543906270123 0.0021175621572112487 0.0013573848039995428 0.0008376501878464442 0.0005202161617967776 0.00032644896295366295 0.0001953274840006314 0.00014926894555381928 0.00008587912888930942 0.00006383462345803247 0.0000612452502319462 0.00006418578918286364 0.00007753218240796379 0.00011089533149964597 0.00016817518667788282 0.00026274413670865197 0.0004193721286009105 0.0006500135096252594 0.0009448983181505456 0.001333942489526634 0.0019366624294627414 0.002888371790448014 0.00419281545486429 0.00568888541173705 0.007194256015802467 0.008535272017550806 0.009383109611456556 0.009317982583385743 0.008248830730131527 0.006586079256877099 0.004855050110277433 0.0033352981097693646 0.002117562157211252 0.0012523497139305829 0.0007258660541463077 0.00043445457211482977 0.0002623235230572628 0.000201014345344792 0.00012121774671322607 0.0000920254711012889 0.00008987407423056888 0.00009673607156472229 0.00011815501475325783 0.0001681751866778857 0.0002515028079262426 0.00038392241691224044 0.000596245251061393 0.0009038676023293271 0.0013044219419490954 0.001873168016668069 0.002815159394638281 0.004314121678006399 0.006298943931691477 0.008518072672587643 0.010880890615936677 0.01331133934917503 0.015142111007148459 0.015236007343764202 0.013230330906524543 0.010128569135575999 0.007181038655257922 0.00485505011027743 0.0030750543906270114 0.001783611195250305 0.0009829449201744815 0.0005606707485081436 0.0003384606851108131 0.00026156901156281555 0.00016484178283184483 0.00012541544784508201 0.0001230483526989928 0.00014055573155341593 0.00018259355712859512 0.00026274413670865474 0.0003839224169122386 0.0005632734506421869 0.0008408650019755421 0.0012460069125889634 0.001795365947832472 0.002613715989201991 0.003986452395490247 0.006129708980026596 0.008910303039589451 0.012113170777656663 0.01593390230487786 0.020422393654937348 0.024168342736126208 0.024603902216747155 0.020864596443750796 0.015156039132763184 0.010128569135575995 0.006586079256877097 0.004111723142629157 0.002355939341597524 0.0012607018118170837 0.0006969509137475145 0.0004222368852196867 0.00032132396993738896 0.0002087267249035122 0.00016298950258330716 0.00016905754840345843 0.00021079146292320532 0.00029086213465636665 0.00041937212860091165 0.0005962452510613939 0.0008408650019755427 0.00120604395331257 0.001739525606265022 0.0024757860587300423 0.0035767109487630246 0.005391246813130981 0.008167517098673105 0.011767808214400967 0.01613095381440367 0.02183352634840638 0.029017297434719518 0.035232198896081986 0.036027717391526014 0.02995435275689363 0.020864596443750796 0.013230330906524548 0.008248830730131527 0.005045103596017065 0.002863405644151262 0.0015115507963728578 0.0008239745350408553 0.0005030317145494113 0.00036883179365408003 0.00024777767599729175 0.0002082531196669498 0.00023964913362904732 0.00032387472212927867 0.00045802707986649857 0.00065001350962526 0.0009038676023293259 0.0012460069125889623 0.0017395256062650221 0.002441698447335635 0.003389059665699427 0.0047539207128256475 0.006923153073596428 0.01017912446384883 0.014399348124765439 0.019618811318097885 0.02661953106469915 0.03552916848266973 0.043157985044019645 0.043882570046413404 0.03602771739152602 0.024603902216747155 0.015236007343764204 0.009317982583385741 0.00564867826547514 0.003200677769729529 0.0016880521502273232 0.0009202033550585056 0.000566660231916628 0.0004014103695536722 0.0002890580940773163 0.0002744930032920358 0.00034950119417326877 0.0004883595058147528 0.0006808862036299052 0.0009448983181505438 0.0013044219419490952 0.0017953659478324702 0.002475786058730045 0.0033890596656994273 0.004548630795370624 0.0061038190074699065 0.008449495985470212 0.011899632005612578 0.016313578902386973 0.021600447001363182 0.028345846801708416 0.03654237041029714 0.04316919361830617 0.043157985044019645 0.03523219889608198 0.02416834273612621 0.015142111007148459 0.009383109611456554 0.005744944457247074 0.0032799082195145456 0.0017456059351057592 0.0009632349493911872 0.0006011759042085222 0.00042623502672549585 0.000344331334178365 0.000373858134187559 0.0005042574172789229 0.0007011280080980793 0.0009614150171436409 0.0013339424895266367 0.001873168016668069 0.0026137159892019955 0.0035767109487630276 0.004753920712825652 0.00610381900746991 0.0077175839492831 0.00996652434644405 0.013205451880473075 0.017291184098801107 0.02187189839919169 0.027043933065993453 0.032628634466063365 0.036542370410297134 0.03552916848266974 0.029017297434719525 0.02042239365493735 0.01331133934917503 0.008535272017550806 0.005320251868544279 0.00306734642805268 0.0016589400069480277 0.0009395915246891048 0.0006045988410517451 0.00044961097665089425 0.00041445894177783886 0.0004963521413852188 0.0006838316235267767 0.000955447606352672 0.0013428023934787137 0.0019366624294627419 0.0028151593946382832 0.003986452395490249 0.005391246813130981 0.006923153073596427 0.008449495985470212 0.00996652434644405 0.011780429057506368 0.014298536985646171 0.0174979794835227 0.020913217290195893 0.02420311060051783 0.027043933065993456 0.02834584680170842 0.026619531064699147 0.021833526348406383 0.015933902304877862 0.010880890615936679 0.007194256015802468 0.0045261888665479805 0.002629389801695995 0.001460434191919838 0.0008649531896832569 0.0005865215698875155 0.00046879496476522563 0.00048131016516047523 0.0006092634042455449 0.0008589568636188349 0.001258949511624915 0.0018950825958768788 0.002888371790448016 0.004314121678006401 0.0061297089800265965 0.008167517098673109 0.010179124463848836 0.011899632005612582 0.013205451880473076 0.014298536985646176 0.01560668739343887 0.017344440296077856 0.019262043358730805 0.020913217290195893 0.021871898399191698 0.021600447001363182 0.01961881131809789 0.016130953814403673 0.012113170777656666 0.008518072672587642 0.005688885411737054 0.0035749591955013824 0.0021106035581529682 0.001231673705736178 0.0007774910755573748 0.0005603349195352458 0.0004764957920562697 0.0005287625121494373 0.0006972250267069924 0.001031963980737476 0.0016385034701410675 0.0026546496802874837 0.004192815454864291 0.006298943931691482 0.008910303039589456 0.011767808214400969 0.014399348124765442 0.016313578902386973 0.01729118409880111 0.0174979794835227 0.017344440296077852 0.017236761403595646 0.017344440296077852 0.017497979483522698 0.017291184098801114 0.01631357890238697 0.014399348124765435 0.011767808214400969 0.008910303039589455 0.0062989439316914805 0.00419281545486429 0.002654649680287479 0.001638503470141067 0.0010319639807374772 0.0006972250267069912 0.0005287625121494371 0.0004687949647652254 0.0005603349195352457 0.0007774910755573758 0.001231673705736177 0.002110603558152969 0.0035749591955013876 0.005688885411737055 0.008518072672587647 0.01211317077765667 0.016130953814403676 0.0196188113180979 0.02160044700136319 0.021871898399191694 0.020913217290195896 0.019262043358730805 0.017344440296077852 0.015606687393438866 0.014298536985646171 0.01320545188047308 0.011899632005612578 0.010179124463848829 0.008167517098673107 0.006129708980026594 0.004314121678006399 0.0028883717904480155 0.0018950825958768736 0.0012589495116249148 0.000858956863618836 0.0006092634042455434 0.0004813101651604746 0.00044961097665089376 0.0005865215698875154 0.0008649531896832575 0.0014604341919198364 0.0026293898016959954 0.004526188866547983 0.00719425601580247 0.01088089061593668 0.015933902304877862 0.021833526348406383 0.02661953106469915 0.028345846801708423 0.02704393306599346 0.02420311060051783 0.02091321729019589 0.017497979483522698 0.01429853698564617 0.011780429057506366 0.009966524346444053 0.008449495985470212 0.006923153073596421 0.005391246813130983 0.003986452395490248 0.002815159394638284 0.0019366624294627414 0.0013428023934787094 0.0009554476063526721 0.0006838316235267776 0.0004963521413852168 0.00041445894177783777 0.0004262350267254957 0.0006045988410517456 0.0009395915246891061 0.001658940006948027 0.0030673464280526813 0.005320251868544282 0.00853527201755081 0.013311339349175033 0.02042239365493735 0.029017297434719525 0.03552916848266974 0.03654237041029714 0.032628634466063365 0.027043933065993456 0.021871898399191694 0.01729118409880111 0.013205451880473073 0.009966524346444051 0.007717583949283106 0.006103819007469913 0.004753920712825648 0.0035767109487630303 0.002613715989201994 0.0018731680166680711 0.001333942489526636 0.0009614150171436376 0.0007011280080980797 0.0005042574172789239 0.00037385813418755763 0.00034433133417836377 0.0004014103695536724 0.0006011759042085231 0.0009632349493911887 0.0017456059351057588 0.0032799082195145474 0.005744944457247076 0.009383109611456556 0.015142111007148462 0.02416834273612621 0.03523219889608198 0.043157985044019645 0.04316919361830618 0.03654237041029714 0.02834584680170842 0.021600447001363186 0.01631357890238697 0.011899632005612577 0.00844949598547021 0.006103819007469915 0.004548630795370626 0.003389059665699425 0.002475786058730046 0.0017953659478324704 0.0013044219419490978 0.0009448983181505447 0.0006808862036299029 0.0004883595058147535 0.00034950119417326904 0.00027449300329203516 0.00028905809407731465 0.00036883179365408057 0.0005666602319166288 0.0009202033550585073 0.0016880521502273221 0.0032006777697295313 0.005648678265475141 0.009317982583385741 0.015236007343764204 0.024603902216747155 0.036027717391526014 0.043882570046413404 0.043157985044019645 0.03552916848266974 0.026619531064699154 0.019618811318097895 0.014399348124765442 0.010179124463848832 0.006923153073596427 0.004753920712825657 0.00338905966569943 0.0024416984473356338 0.0017395256062650252 0.0012460069125889638 0.0009038676023293296 0.0006500135096252617 0.0004580270798664991 0.00032387472212927915 0.0002396491336290471 0.00020825311966695046 0.00024777767599728985 0.0003213239699373895 0.0005030317145494116 0.0008239745350408571 0.0015115507963728565 0.002863405644151264 0.005045103596017065 0.00824883073013153 0.013230330906524547 0.020864596443750796 0.029954352756893624 0.03602771739152602 0.03523219889608198 0.02901729743471953 0.021833526348406376 0.01613095381440368 0.011767808214400969 0.008167517098673107 0.005391246813130981 0.0035767109487630316 0.0024757860587300462 0.001739525606265023 0.0012060439533125736 0.0008408650019755434 0.0005962452510614003 0.0004193721286009138 0.0002908621346563702 0.00021079146292320527 0.00016905754840345767 0.0001629895025833087 0.00020872672490351025 0.0002615690115628162 0.0004222368852196872 0.0006969509137475162 0.001260701811817083 0.0023559393415975246 0.004111723142629158 0.0065860792568770985 0.010128569135575999 0.01515603913276318 0.020864596443750796 0.024603902216747152 0.024168342736126214 0.020422393654937355 0.015933902304877866 0.01211317077765667 0.008910303039589456 0.006129708980026595 0.00398645239549025 0.002613715989201996 0.0017953659478324691 0.0012460069125889647 0.0008408650019755422 0.0005632734506421882 0.0003839224169122433 0.0002627441367086567 0.0001825935571285996 0.00014055573155341607 0.00012304835269899163 0.0001254154478450841 0.00016484178283184318 0.00020101434534479251 0.00033846068511081336 0.0005606707485081452 0.0009829449201744812 0.0017836111952503047 0.003075054390627011 0.004855050110277432 0.007181038655257923 0.010128569135575995 0.013230330906524543 0.015236007343764197 0.015142111007148462 0.013311339349175033 0.010880890615936679 0.008518072672587649 0.006298943931691482 0.004314121678006399 0.0028151593946382837 0.0018731680166680724 0.0013044219419490976 0.0009038676023293309 0.0005962452510613963 0.0003839224169122432 0.00025150280792624844 0.00016817518667788808 0.00011815501475326242 0.00009673607156472203 0.00008987407423056795 0.00009202547110129114 0.00012121774671322484 0.00014926894555382017 0.0002623235230572635 0.00043445457211483193 0.0007258660541463079 0.0012523497139305827 0.0021175621572112504 0.0033352981097693663 0.004855050110277433 0.0065860792568770985 0.008248830730131525 0.009317982583385743 0.009383109611456554 0.008535272017550811 0.007194256015802466 0.005688885411737059 0.004192815454864292 0.002888371790448019 0.0019366624294627419 0.0013339424895266387 0.0009448983181505426 0.0006500135096252624 0.00041937212860091144 0.0002627441367086567 0.00016817518667788605 0.00011089533149964913 0.0000775321824079665 0.0000641857891828635 0.00006124525023194535 0.000063834623458035 0.00008587912888930905 0.00010639592520415098 0.00019532748400063189 0.0003264489629536652 0.0005202161617967776 0.0008376501878464437 0.0013573848039995409 0.00211756215721125 0.003075054390627012 0.004111723142629156 0.005045103596017063 0.005648678265475138 0.0057449444572470745 0.005320251868544285 0.0045261888665479805 0.0035749591955013893 0.002654649680287483 0.0018950825958768806 0.0013428023934787103 0.0009614150171436458 0.0006808862036299009 0.0004580270798665039 0.0002908621346563642 0.00018259355712860008 0.000118155014753258 0.00007753218240796791 0.00005113278822131939 0.00003799095053560132 0.00003508250419490084 0.00003947296941474019 0.000057993578281356325 0.00007002096897945437 0.00013378777557353168 0.00023213625592551722 0.0003662969199368274 0.0005542117430241069 0.0008376501878464438 0.0012523497139305829 0.0017836111952503051 0.0023559393415975237 0.0028634056441512613 0.0032006777697295287 0.003279908219514544 0.0030673464280526826 0.0026293898016959906 0.0021106035581529687 0.0016385034701410675 0.0012589495116249157 0.000955447606352673 0.000701128008098081 0.0004883595058147523 0.0003238747221292777 0.00021079146292320234 0.00014055573155341566 0.00009673607156472213 0.00006418578918286517 0.00003799095053560291 0.000021968432045006254 0.000017393788614681794 0.00002174440512866354 0.00003641977923896701 0.00004158095417467013 0.00007998449698244527 0.0001479515150689909 0.0002452872893603451 0.00036629691993682594 0.0005202161617967763 0.0007258660541463065 0.0009829449201744812 0.0012607018118170816 0.0015115507963728559 0.0016880521502273206 0.0017456059351057592 0.001658940006948028 0.0014604341919198353 0.0012316737057361785 0.0010319639807374783 0.0008589568636188358 0.000683831623526777 0.0005042574172789216 0.0003495011941732703 0.000239649133629049 0.0001690575484034583 0.00012304835269899298 0.00008987407423057003 0.00006124525023194752 0.00003508250419490369 0.000017393788614681676 0.000011059872777093842 0.000013352842787483661 0.000022572177159265424 0.000025213591859048774 0.000042629439945228314 0.00008197322550826467 0.00014795151506899007 0.00023213625592551494 0.00032644896295366235 0.00043445457211482977 0.0005606707485081437 0.0006969509137475148 0.0008239745350408553 0.0009202033550585029 0.0009632349493911877 0.0009395915246891069 0.0008649531896832539 0.0007774910755573774 0.0006972250267069908 0.000609263404245547 0.0004963521413852153 0.0003738581341875597 0.0002744930032920352 0.00020825311966695217 0.00016298950258330453 0.00012541544784508416 0.0000920254711012893 0.0000638346234580349 0.00003947296941473982 0.000021744405128662467 0.000013352842787482537 0.000013239288145538976 0.000017848639275136654 0.000020434020735810358 0.00002503413062091278 0.00004262943994522939 0.00007998449698244577 0.00013378777557353127 0.00019532748400063026 0.000262323523057262 0.00033846068511081255 0.00042223688521968574 0.0005030317145494102 0.000566660231916625 0.0006011759042085214 0.000604598841051746 0.0005865215698875098 0.0005603349195352462 0.0005287625121494361 0.0004813101651604744 0.0004144589417778359 0.00034433133417836133 0.0002890580940773151 0.00024777767599728866 0.00020872672490350748 0.00016484178283184426 0.00012121774671322542 0.00008587912888930863 0.000057993578281356914 0.00003641977923896593 0.000022572177159264526 0.00001784863927513646 0.000019088382184322727 0.000022151566164276253 0.000022541579159477104 0.000029077834577924042 0.000051575019374037524 0.00009202672100430405 0.00014390693080602694 0.0001999162390895347 0.00026156901156281463 0.0003360929645486767 0.00041701622182258036 0.0004837211007552387 0.0005240339424709035 0.0005506553884725048 0.0005832294783845778 0.0006197248184155353 0.0006368373327308822 0.0006197248184155336 0.0005832294783845778 0.0005506553884725065 0.000524033942470907 0.00048372110075524215 0.0004170162218225821 0.00033609296454868275 0.0002615690115628129 0.00019991623908953557 0.00014390693080603215 0.00009202672100430557 0.00005157501937403579 0.00002907783457792426 0.00002254157915947759 0.000022541579159477697 0.000020532050107825877 0.00002071187565953361 0.00002876662995246124 0.00004966829372031848 0.00008184139687993044 0.0001202124077839765 0.0001648417828318425 0.00022033393740472767 0.00028173929364136603 0.00033999731898393863 0.00039576518507256157 0.0004633564042267076 0.0005519973573561739 0.0006423483931220768 0.0007038565058097157 0.0007313386636297324 0.0007465776724080139 0.0007619127265753534 0.0007609761381989967 0.0007178665296543006 0.0006296342986623052 0.0005222137760460901 0.00042223688521968574 0.0003363917239214436 0.00025567699540016316 0.00017486743176160763 0.00010298248083767119 0.00005384413321553652 0.000030180522486128723 0.000029077834577925546 0.0000207118756595351 0.00001916527902949986 0.000023259926778895508 0.000037225400347974265 0.0000617435694078435 0.00009202995412545556 0.00012541544784508136 0.0001660641990964881 0.00021817936648991512 0.00028670028072873445 0.0003796380781566173 0.0005052944369660959 0.0006561523056794493 0.0008015254916949723 0.0009190083262633681 0.0010183403054298296 0.0011191498215588785 0.0012087368131948246 0.0012408721734380747 0.0011822360315786376 0.0010447624265133974 0.0008703087826223994 0.0006969509137475114 0.0005429488252746273 0.00040903351347927846 0.00029007418727425326 0.00018588342694629008 0.00010487748323797793 0.00005384413321553721 0.000051575019374036345 0.000028766629952460214 0.000023259926778892964 0.00002664251965620183 0.00003826818439399159 0.00006065687477902104 0.00009092448574327897 0.00012304835269899003 0.0001621371192064125 0.00022463885487634133 0.000327496029976597 0.0004781079751339023 0.0006692846682037877 0.0008835265101450363 0.001109453111722614 0.0013560029677948042 0.0016396186116322176 0.0019465698802293002 0.0022044233453669157 0.0023155029140805314 0.0022318845186097523 0.001982106453963783 0.001634987129825333 0.001260701811817081 0.0009163199990738582 0.0006398426918513308 0.0004400928033043427 0.00029651146234187616 0.00018588342694628946 0.00010298248083767107 0.00009202672100430471 0.000049668293720319645 0.00003722540034797266 0.000038268184393992676 0.00004695012607628447 0.00006762487901667132 0.00010089256600215854 0.0001405557315534138 0.00019395528069378302 0.0002871615092159448 0.00044466320001632 0.0006636557209989328 0.0009232854720992022 0.001231019929226476 0.0016351864912215125 0.0021808424436070496 0.0028541081215029 0.003554862012239764 0.004117426952608123 0.004379127580087882 0.004261837790878294 0.003804765825581196 0.0031243262723721285 0.002355939341597523 0.0016299924923527578 0.0010541703707617875 0.0006706709826168829 0.0004400928033043434 0.0002900741872742524 0.00017486743176160758 0.00014390693080602897 0.00008184139687993334 0.00006174356940784399 0.00006065687477902385 0.00006762487901667458 0.00008826731038414719 0.00012770593467778914 0.0001825935571285962 0.0002636332621307591 0.0004031565891849483 0.0006269184999834754 0.0009209194452240731 0.0012775314669896014 0.0017735870623411612 0.002535785925900226 0.003610843325070009 0.004883702047003986 0.006144054076131455 0.007172574512613114 0.007727115860575978 0.00759334889188484 0.006767615584404152 0.005502479458646107 0.004111723142629156 0.002817550255939863 0.0017698156072572227 0.0010541703707617836 0.000639842691851328 0.0004090335134792748 0.00025567699540016023 0.0001999162390895334 0.00012021240778397742 0.0000920299541254521 0.00009092448574328022 0.00010089256600215938 0.00012770593467778592 0.00018172430257398808 0.0002627441367086533 0.00038445738581477883 0.0005833386314489981 0.0008847228995316164 0.0012792562992190316 0.0018108488201475637 0.002654967801723887 0.00400116892906043 0.005824229496243894 0.007878392384066558 0.009977253075154284 0.011973630808074323 0.013355186574400194 0.013326033228026434 0.011664359723122485 0.009110995346707656 0.006586079256877096 0.0044787656211908305 0.0028175502559398664 0.0016299924923527565 0.0009163199990738572 0.0005429488252746245 0.0003363917239214428 0.0002615690115628146 0.00016484178283184445 0.00012541544784507957 0.0001230483526989935 0.0001405557315534168 0.00018259355712859702 0.00026274413670865506 0.00038392241691223914 0.0005632734506421879 0.0008408650019755418 0.0012460069125889636 0.0017953659478324802 0.002613715989201993 0.00398645239549025 0.006129708980026597 0.008910303039589451 0.012113170777656668 0.015933902304877862 0.02042239365493734 0.02416834273612621 0.024603902216747162 0.020864596443750796 0.015156039132763184 0.010128569135575992 0.006586079256877095 0.004111723142629158 0.0023559393415975246 0.0012607018118170829 0.0006969509137475126 0.00042223688521968693 0.0003360929645486784 0.00022033393740473374 0.00016606419909648664 0.00016213711920641955 0.00019395528069379028 0.00026363326213075757 0.00038445738581478636 0.0005632734506421869 0.0008231909664002674 0.001209958761093529 0.0017619709067586754 0.0025319910818477533 0.0037347489483499185 0.0057619506783170744 0.008839845022533021 0.01281726508027634 0.01786507350603816 0.025055637667848858 0.034760915202820916 0.04358793167375026 0.04510783438860939 0.037099549047796304 0.02500960208422867 0.015156039132763179 0.009110995346707654 0.0055024794586461066 0.003124326272372126 0.0016349871298253305 0.0008703087826223929 0.0005222137760460876 0.00041701622182258307 0.0002817392936413675 0.00021817936648991227 0.00022463885487634475 0.0002871615092159459 0.0004031565891849524 0.0005833386314489996 0.0008408650019755421 0.0012099587610935284 0.001746532729020491 0.0024978119909228043 0.003543537105845854 0.005172902766082886 0.007869541377713726 0.011889215069225807 0.017197117076335002 0.024608649914735676 0.0363667313100634 0.053219103003259556 0.06896977349167828 0.07184481865601179 0.057874007302206903 0.037099549047796304 0.0208645964437508 0.01166435972312248 0.006767615584404149 0.00380476582558119 0.0019821064539637793 0.0010447624265133959 0.0006296342986623034 0.00048372110075524155 0.00033999731898394275 0.0002867002807287311 0.0003274960299765937 0.0004446632000163215 0.0006269184999834691 0.0008847228995316167 0.0012460069125889628 0.0017619709067586732 0.0024978119909228034 0.0035001160310624765 0.004852504630671366 0.006884090603571319 0.0101486926733028 0.014947087410735692 0.021340499097863345 0.030550059905471983 0.04551782647970808 0.06708402303583846 0.0870489735205125 0.09023345115385845 0.0718448186560118 0.04510783438860939 0.024603902216747155 0.013326033228026427 0.007593348891884835 0.004261837790878287 0.0022318845186097497 0.0011822360315786274 0.0007178665296542961 0.0005240339424709019 0.0003957651850725601 0.0003796380781566136 0.00047810797513389504 0.0006636557209989256 0.0009209194452240809 0.001279256299219027 0.0017953659478324715 0.002531991081847751 0.003543537105845858 0.004852504630671364 0.006514726734788961 0.008851163896473169 0.012455354564246367 0.01767088697656699 0.0244766164533361 0.03380867422689518 0.04815204876374486 0.06795136304519563 0.0854511061047993 0.0870489735205125 0.06896977349167827 0.04358793167375026 0.024168342736126204 0.013355186574400187 0.007727115860575971 0.004379127580087877 0.0023155029140805258 0.0012408721734380648 0.0007609761381989899 0.0005506553884725054 0.0004633564042267077 0.0005052944369660898 0.0006692846682037812 0.0009232854720992028 0.0012775314669896088 0.001810848820147565 0.002613715989201994 0.003734748948349924 0.005172902766082895 0.006884090603571321 0.008851163896473172 0.0113179299397326 0.014864650915170599 0.019899013037081064 0.02625038192951192 0.03407391682098447 0.04456266870809132 0.05761291075195856 0.06795136304519561 0.06708402303583848 0.05321910300325957 0.03476091520282092 0.020422393654937344 0.011973630808074334 0.007172574512613113 0.004117426952608125 0.0022044233453669152 0.00120873681319482 0.000761912726575355 0.0005832294783845778 0.0005519973573561726 0.0006561523056794498 0.0008835265101450297 0.0012310199292264715 0.0017735870623411761 0.0026549678017238863 0.00398645239549025 0.005761950678317075 0.007869541377713727 0.010148692673302801 0.012455354564246368 0.014864650915170599 0.01784026965500825 0.021878320719838733 0.026874775620886443 0.03239910529167102 0.0384400990072735 0.04456266870809132 0.04815204876374486 0.04551782647970807 0.0363667313100634 0.025055637667848855 0.015933902304877862 0.00997725307515428 0.006144054076131451 0.003554862012239763 0.001946569880229299 0.0011191498215588752 0.0007465776724080114 0.0006197248184155333 0.0006423483931220763 0.0008015254916949652 0.0011094531117226132 0.0016351864912215138 0.002535785925900233 0.004001168929060434 0.0061297089800265965 0.008839845022533025 0.011889215069225821 0.0149470874107357 0.01767088697656699 0.019899013037081057 0.02187832071983874 0.024131797236828956 0.026888939960480213 0.029813679189042687 0.03239910529167102 0.03407391682098447 0.03380867422689517 0.03055005990547198 0.02460864991473567 0.017865073506038154 0.012113170777656663 0.00787839238406656 0.004883702047003981 0.0028541081215029017 0.001639618611632218 0.0010183403054298255 0.0007313386636297344 0.0006368373327308818 0.0007038565058097178 0.0009190083262633701 0.0013560029677948042 0.002180842443607049 0.0036108433250700202 0.005824229496243897 0.008910303039589453 0.012817265080276342 0.01719711707633501 0.021340499097863348 0.0244766164533361 0.02625038192951192 0.026874775620886436 0.02688893996048021 0.02682014002358007 0.02688893996048021 0.026874775620886436 0.026250381929511922 0.024476616453336097 0.02134049909786334 0.017197117076335 0.012817265080276339 0.008910303039589451 0.005824229496243895 0.0036108433250700077 0.0021808424436070514 0.0013560029677948072 0.0009190083262633666 0.0007038565058097162 0.000619724818415534 0.0007313386636297371 0.0010183403054298298 0.0016396186116322156 0.0028541081215029 0.004883702047003993 0.007878392384066563 0.012113170777656668 0.017865073506038165 0.024608649914735686 0.030550059905471997 0.03380867422689519 0.03407391682098447 0.032399105291671025 0.029813679189042683 0.026888939960480213 0.024131797236828952 0.021878320719838733 0.019899013037081064 0.017670886976566984 0.014947087410735686 0.011889215069225805 0.008839845022533014 0.006129708980026589 0.004001168929060432 0.0025357859259002194 0.0016351864912215153 0.0011094531117226162 0.0008015254916949628 0.0006423483931220756 0.0005832294783845791 0.0007465776724080148 0.00111914982155888 0.0019465698802292963 0.0035548620122397615 0.00614405407613146 0.009977253075154282 0.015933902304877862 0.02505563766784886 0.036366731310063405 0.04551782647970808 0.04815204876374487 0.044562668708091314 0.0384400990072735 0.03239910529167102 0.02687477562088644 0.02187832071983873 0.01784026965500825 0.014864650915170597 0.012455354564246363 0.010148692673302796 0.007869541377713724 0.005761950678317066 0.00398645239549025 0.0026549678017238855 0.0017735870623411638 0.0012310199292264717 0.0008835265101450334 0.0006561523056794481 0.0005519973573561727 0.0005506553884725077 0.0007619127265753595 0.001208736813194826 0.0022044233453669144 0.004117426952608126 0.007172574512613121 0.011973630808074337 0.020422393654937348 0.03476091520282092 0.05321910300325958 0.06708402303583849 0.06795136304519564 0.05761291075195857 0.04456266870809132 0.03407391682098447 0.02625038192951192 0.01989901303708106 0.0148646509151706 0.011317929939732605 0.008851163896473169 0.006884090603571315 0.00517290276608289 0.003734748948349914 0.0026137159892019963 0.0018108488201475654 0.0012775314669895988 0.0009232854720992025 0.0006692846682037851 0.00050529443696609 0.00046335640422670837 0.0005240339424709044 0.0007609761381989941 0.00124087217343807 0.0023155029140805245 0.004379127580087879 0.0077271158605759765 0.013355186574400192 0.024168342736126208 0.04358793167375025 0.06896977349167828 0.0870489735205125 0.0854511061047993 0.06795136304519563 0.04815204876374486 0.03380867422689518 0.024476616453336097 0.017670886976566987 0.012455354564246363 0.008851163896473172 0.006514726734788954 0.004852504630671363 0.0035435371058458514 0.0025319910818477473 0.0017953659478324737 0.0012792562992190305 0.000920919445224075 0.0006636557209989256 0.0004781079751338974 0.0003796380781566157 0.00039576518507255967 0.0004837211007552442 0.0007178665296542994 0.0011822360315786324 0.0022318845186097484 0.00426183779087829 0.007593348891884837 0.01332603322802643 0.024603902216747155 0.04510783438860937 0.07184481865601179 0.09023345115385845 0.0870489735205125 0.06708402303583848 0.04551782647970808 0.030550059905471983 0.021340499097863345 0.014947087410735692 0.010148692673302796 0.006884090603571322 0.004852504630671363 0.003500116031062476 0.0024978119909228004 0.001761970906758673 0.0012460069125889673 0.0008847228995316207 0.0006269184999834704 0.0004446632000163216 0.0003274960299765947 0.00028670028072873516 0.00033999731898394156 0.00041701622182258567 0.0006296342986623056 0.0010447624265134 0.001982106453963778 0.0038047658255811927 0.006767615584404148 0.011664359723122486 0.020864596443750792 0.0370995490477963 0.05787400730220689 0.07184481865601179 0.06896977349167827 0.05321910300325957 0.036366731310063384 0.02460864991473568 0.017197117076335 0.011889215069225807 0.007869541377713719 0.005172902766082889 0.0035435371058458497 0.002497811990922802 0.0017465327290204981 0.0012099587610935306 0.0008408650019755483 0.0005833386314490053 0.0004031565891849596 0.0002871615092159463 0.000224638854876344 0.00021817936648991747 0.0002817392936413661 0.00033609296454868075 0.0005222137760460894 0.0008703087826223956 0.00163498712982533 0.0031243262723721276 0.005502479458646106 0.009110995346707658 0.015156039132763182 0.025009602084228668 0.037099549047796304 0.04510783438860938 0.04358793167375026 0.03476091520282092 0.02505563766784886 0.017865073506038165 0.012817265080276342 0.008839845022533023 0.0057619506783170675 0.0037347489483499185 0.0025319910818477516 0.0017619709067586795 0.001209958761093529 0.0008231909664002713 0.0005632734506421918 0.00038445738581479065 0.0002636332621307659 0.00019395528069379115 0.0001621371192064178 0.000166064199096492 0.000220333937404733 0.0002615690115628166 0.00042223688521968807 0.0006969509137475142 0.0012607018118170827 0.0023559393415975263 0.004111723142629157 0.006586079256877099 0.010128569135575995 0.015156039132763179 0.020864596443750796 0.024603902216747152 0.02416834273612621 0.020422393654937348 0.01593390230487786 0.012113170777656673 0.008910303039589453 0.006129708980026597 0.003986452395490248 0.0026137159892019985 0.0017953659478324791 0.0012460069125889714 0.0008408650019755503 0.0005632734506421936 0.00038392241691224407 0.00026274413670866113 0.00018259355712860488 0.0001405557315534179 0.0001230483526989916 0.00012541544784508424 0.00016484178283184434 0.00019991623908953543 0.00033639172392144423 0.0005429488252746259 0.000916319999073858 0.0016299924923527595 0.0028175502559398646 0.004478765621190836 0.006586079256877097 0.009110995346707656 0.011664359723122481 0.013326033228026429 0.013355186574400183 0.011973630808074337 0.009977253075154274 0.007878392384066568 0.005824229496243891 0.004001168929060436 0.002654967801723881 0.0018108488201475726 0.0012792562992190305 0.0008847228995316255 0.0005833386314489991 0.0003844573858147898 0.00026274413670865474 0.00018172430257399345 0.00012770593467779115 0.00010089256600216149 0.00009092448574327847 0.00009202995412545612 0.0001202124077839777 0.00014390693080603038 0.0002556769954001614 0.0004090335134792755 0.0006398426918513291 0.0010541703707617855 0.001769815607257221 0.0028175502559398664 0.004111723142629157 0.005502479458646101 0.006767615584404149 0.007593348891884835 0.007727115860575973 0.00717257451261312 0.006144054076131452 0.004883702047003994 0.00361084332507001 0.002535785925900232 0.0017735870623411612 0.00127753146698961 0.0009209194452240697 0.0006269184999834714 0.00040315658918493803 0.00026363326213076397 0.00018259355712859328 0.00012770593467779142 0.00008826731038415093 0.00006762487901667495 0.000060656874779022125 0.00006174356940784631 0.00008184139687993319 0.00009202672100430631 0.00017486743176160945 0.00029007418727425337 0.00044009280330434535 0.0006706709826168844 0.0010541703707617849 0.0016299924923527608 0.0023559393415975233 0.003124326272372123 0.0038047658255811914 0.0042618377908782866 0.004379127580087872 0.004117426952608125 0.0035548620122397567 0.002854108121502904 0.002180842443607048 0.0016351864912215158 0.001231019929226471 0.0009232854720991983 0.0006636557209989321 0.0004446632000163269 0.00028716150921595176 0.00019395528069379324 0.00014055573155341485 0.000100892566002163 0.0000676248790166762 0.000046950126076286004 0.00003826818439399211 0.000037225400347974936 0.00004966829372031998 0.00005157501937403751 0.00010298248083767288 0.00018588342694628992 0.0002965114623418782 0.00044009280330434335 0.000639842691851327 0.0009163199990738591 0.001260701811817083 0.0016349871298253253 0.001982106453963781 0.002231884518609744 0.002315502914080526 0.002204423345366912 0.0019465698802292974 0.0016396186116322212 0.001356002967794805 0.0011094531117226117 0.0008835265101450313 0.0006692846682037799 0.00047810797513390263 0.0003274960299765977 0.00022463885487634488 0.00016213711920642384 0.00012304835269899417 0.0000909244857432821 0.000060656874779025906 0.000038268184393993225 0.000026642519656200917 0.00002325992677889443 0.00002876662995246054 0.00002907783457792697 0.00005384413321553897 0.00010487748323797891 0.00018588342694629247 0.00029007418727425364 0.0004090335134792744 0.0005429488252746284 0.0006969509137475135 0.0008703087826223919 0.0010447624265133995 0.0011822360315786298 0.0012408721734380674 0.0012087368131948261 0.001119149821558876 0.0010183403054298344 0.0009190083262633667 0.0008015254916949675 0.0006561523056794472 0.0005052944369660986 0.00037963807815662013 0.00028670028072873434 0.0002181793664899127 0.00016606419909649594 0.00012541544784508234 0.00009202995412545839 0.00006174356940784803 0.000037225400347975674 0.000023259926778894495 0.000019165279029501507 0.00002071187565953616 0.000022541579159478432 0.00003018052248612914 0.000053844133215536816 0.0001029824808376731 0.00017486743176160758 0.00025567699540015774 0.0003363917239214445 0.00042223688521968465 0.0005222137760460825 0.0006296342986623031 0.0007178665296542929 0.0007609761381989928 0.0007619127265753564 0.0007465776724080108 0.0007313386636297376 0.0007038565058097155 0.000642348393122072 0.0005519973573561703 0.00046335640422670365 0.00039576518507256303 0.0003399973189839436 0.0002817392936413648 0.00022033393740473206 0.00016484178283184225 0.00012021240778397754 0.00008184139687993539 0.00004966829372031977 0.000028766629952459756 0.000020711875659534577 0.00002053205010782692 0.000028768074973657795 0.000028324619977966516 0.000034395759926610244 0.000060288850131598936 0.00010990207288447715 0.00017526872371933112 0.00024516722341408293 0.0003213239699373918 0.00041701622182258556 0.000526217108392556 0.0006161255593246703 0.0006638652867328142 0.0006876207794232064 0.0007212546483763918 0.0007667896670978426 0.0007897162282245115 0.0007667896670978461 0.0007212546483763953 0.0006876207794232134 0.0006638652867328246 0.000616125559324672 0.0005262171083925613 0.0004170162218225925 0.00032132396993739265 0.0002451672234140812 0.00017526872371933112 0.00010990207288447476 0.00006028885013160067 0.00003439575992661111 0.000028324619977961203 0.00002832461997796466 0.000025849658985389592 0.00002671170950945675 0.00003706462000962985 0.000063078451473693 0.00010322000910759584 0.00015154206168441109 0.0002087267249035139 0.0002817392936413671 0.000366087000675691 0.00044536251883482947 0.000512221770090827 0.0005841060597842261 0.0006814304005537463 0.0007900599153245034 0.0008701737083641782 0.0009055757124909107 0.0009218909549822199 0.0009416347748850476 0.0009450532555019055 0.0008912224146887266 0.0007727221740842567 0.0006296342986623078 0.0005030317145494129 0.00039880592165459093 0.0003003899004650741 0.00020226617109820992 0.00011796120117655345 0.00006258753462346653 0.00003682836488374709 0.00003439575992661313 0.000026711709509461476 0.000029796252276295578 0.000038120097772277946 0.00005473562818607579 0.00008236911364064026 0.00011899803177516972 0.0001629895025833104 0.00021817936648992113 0.0002902993943691675 0.0003820241157457591 0.0004938979088174679 0.0006317512268016382 0.0007970503483696848 0.0009705099287999502 0.0011270689633863375 0.0012624736503087186 0.0013888305176585237 0.0014949492493011405 0.0015311746859497898 0.001453351627041389 0.0012722104792645462 0.0010447624265134054 0.0008239745350408578 0.0006304765274554547 0.00046332858412138564 0.0003206654954183226 0.00020424986233035343 0.00011779395139745176 0.00006258753462346452 0.00006028885013160232 0.00003706462000963406 0.0000381200977722763 0.00004802404642698417 0.0000622432677210684 0.0000868731035868383 0.0001243940374230856 0.00016905754840346063 0.00022463885487634472 0.000310088400531053 0.0004430836000988281 0.0006217834696838508 0.0008297072438039136 0.0010612533502024984 0.001331445714550185 0.0016584905708846665 0.00203803498283602 0.0024239791870858678 0.0027252012978601593 0.002841964997621884 0.0027278262838996794 0.0024148623704578105 0.0019821064539637862 0.0015115507963728593 0.0010719536575662409 0.0007181879547709635 0.0004737128545823651 0.0003158654422010087 0.00020424986233035194 0.00011796120117655011 0.00010990207288447766 0.00006307845147369451 0.000054735628186069044 0.00006224326772106424 0.00007553666539709105 0.00010310204404458244 0.00015107953004165302 0.0002107914629232051 0.00028716150921593886 0.00041038257064112326 0.000609022146285657 0.0008696279545382163 0.0011583572591615126 0.0015021101566728339 0.0019935386997361414 0.002698729676676629 0.0035655934957543154 0.004422978400784099 0.00506599039894629 0.005337764510923145 0.005174646336827478 0.004622831473009593 0.0038047658255811975 0.0028634056441512717 0.0019497470457856565 0.001214728941261355 0.0007370114712795588 0.00047371285458236526 0.0003206654954183219 0.0002022661710982085 0.00017526872371933277 0.00010322000910759977 0.00008236911364063782 0.00008687310358683928 0.00010310204404459031 0.00013978608386000234 0.00020537152754664508 0.00029086213465636654 0.0004031565891849637 0.0005817603729256123 0.0008625415369535998 0.0012246577971138563 0.0016519263713297863 0.002250232107860967 0.00320195673309374 0.004570037806178961 0.006171924531510293 0.007710433178781156 0.008932914694551087 0.00957801190646772 0.009386166372071906 0.008343439782146946 0.006767615584404156 0.005045103596017072 0.003431445061352018 0.0021108206748463145 0.0012147289412613573 0.0007181879547709658 0.0004633285841213858 0.00030038990046507325 0.00024516722341408304 0.00015154206168441507 0.0001189980317751659 0.00012439403742308774 0.00015107953004165833 0.00020537152754663445 0.00029703600034880175 0.0004193721286009148 0.0005833386314490031 0.0008364038989140021 0.0012208498047827957 0.0017314033525384091 0.002419859374637218 0.0035046384072238645 0.005225728102749314 0.0075469727353497384 0.010174247183974288 0.012938092278920276 0.015692722152502888 0.017674996409659065 0.017646077493263055 0.015258430610257605 0.011664359723122492 0.008248830730131537 0.005522965993520519 0.0034314450613520176 0.0019497470457856578 0.001071953657566244 0.0006304765274554538 0.00039880592165459077 0.0003213239699373915 0.00020872672490351626 0.00016298950258330648 0.00016905754840346014 0.00021079146292321072 0.0002908621346563621 0.00041937212860091827 0.0005962452510613986 0.0008408650019755518 0.0012060439533125764 0.001739525606265022 0.0024757860587300427 0.00357671094876303 0.005391246813130981 0.008167517098673117 0.011767808214400977 0.016130953814403687 0.02183352634840639 0.02901729743471954 0.035232198896082 0.03602771739152604 0.02995435275689364 0.02086459644375081 0.013230330906524554 0.008248830730131529 0.005045103596017063 0.0028634056441512634 0.0015115507963728598 0.0008239745350408545 0.0005030317145494119 0.00041701622182258627 0.0002817392936413712 0.00021817936648991512 0.0002246388548763481 0.0002871615092159535 0.0004031565891849467 0.0005833386314490058 0.0008408650019755469 0.0012099587610935386 0.0017465327290204968 0.0024978119909227986 0.0035435371058458467 0.005172902766082889 0.007869541377713726 0.01188921506922582 0.017197117076335013 0.024608649914735686 0.036366731310063405 0.05321910300325958 0.0689697734916783 0.0718448186560118 0.05787400730220691 0.03709954904779632 0.020864596443750806 0.011664359723122483 0.006767615584404147 0.0038047658255811892 0.0019821064539637823 0.001044762426513398 0.0006296342986623054 0.0005262171083925555 0.0003660870006756881 0.0002902993943691631 0.0003100884005310505 0.00041038257064112744 0.0005817603729256101 0.000836403898914007 0.0012060439533125749 0.0017465327290205014 0.0025187898826278437 0.0035620064684013302 0.004986649428306462 0.007195842070608358 0.010803241393581735 0.01612544317183192 0.02345686346995568 0.03492861208914283 0.055054691285063385 0.0853932486432805 0.11441220866588603 0.12002991041620258 0.09489057748909485 0.057874007302206903 0.02995435275689364 0.01525843061025759 0.008343439782146932 0.004622831473009578 0.00241486237045781 0.0012722104792645425 0.0007727221740842545 0.0006161255593246769 0.0004453625188348372 0.00038202411574576374 0.0004430836000988335 0.0006090221462856665 0.0008625415369536017 0.0012208498047828072 0.0017395256062650276 0.002497811990922806 0.0035620064684013355 0.004960423816152605 0.006814124455876283 0.00960322788700752 0.01405594523443135 0.020572286992175944 0.029682723819807404 0.04435217915922054 0.07046765868336341 0.1097939337563083 0.14696938808169446 0.15337842354304512 0.12002991041620262 0.0718448186560118 0.03602771739152603 0.017646077493263038 0.009386166372071899 0.005174646336827459 0.002727826283899674 0.00145335162704138 0.0008912224146887244 0.0006638652867328162 0.0005122217700908248 0.0004938979088174711 0.0006217834696838501 0.0008696279545382181 0.0012246577971138728 0.001731403352538417 0.002475786058730051 0.0035435371058458575 0.004986649428306476 0.006814124455876276 0.00913081995232882 0.012428670230404577 0.017509967750017327 0.0248332761242959 0.034771922171507014 0.0497965695295235 0.07491270404560921 0.11099495791676932 0.1434970768803001 0.14696938808169446 0.11441220866588601 0.06896977349167827 0.03523219889608198 0.017674996409659055 0.009578011906467702 0.005337764510923124 0.002841964997621871 0.0015311746859497785 0.0009450532555018935 0.000687620779423208 0.0005841060597842301 0.0006317512268016393 0.000829707243803917 0.0011583572591615206 0.0016519263713297863 0.002419859374637224 0.0035767109487630346 0.0051729027660828986 0.007195842070608365 0.009603227887007525 0.012428670230404578 0.016052285022226307 0.02124810892754825 0.028546983150662536 0.037967471560866946 0.0504913049371569 0.06864617972454859 0.09210298693624547 0.1109949579167693 0.1097939337563083 0.08539324864328052 0.05321910300325957 0.02901729743471952 0.015692722152502885 0.008932914694551075 0.005065990398946277 0.002725201297860149 0.0014949492493011238 0.0009416347748850412 0.0007212546483763905 0.0006814304005537403 0.0007970503483696877 0.0010612533502024906 0.0015021101566728347 0.0022502321078609827 0.0035046384072238653 0.005391246813130988 0.007869541377713727 0.01080324139358174 0.014055945234431346 0.01750996775001733 0.021248108927548248 0.025804124095663225 0.0318112285958015 0.039271442880153225 0.04793840415454885 0.05804858897493285 0.0686461797245486 0.0749127040456092 0.07046765868336338 0.055054691285063385 0.03636673131006339 0.02183352634840638 0.012938092278920265 0.007710433178781149 0.0044229784007840875 0.002423979187085862 0.0013888305176585171 0.000921890954982213 0.0007667896670978386 0.0007900599153244961 0.0009705099287999408 0.00133144571455018 0.0019935386997361393 0.00320195673309374 0.005225728102749316 0.008167517098673117 0.011889215069225816 0.016125443171831934 0.020572286992175958 0.02483327612429591 0.028546983150662536 0.031811228595801516 0.035269934863478375 0.039394509519579526 0.043876076872530166 0.04793840415454884 0.05049130493715689 0.049796569529523466 0.044352179159220524 0.03492861208914282 0.024608649914735672 0.016130953814403666 0.010174247183974283 0.006171924531510287 0.0035655934957543097 0.002038034982836017 0.0012624736503087039 0.0009055757124909079 0.0007897162282245139 0.0008701737083641773 0.00112706896338634 0.001658490570884663 0.0026987296766766275 0.004570037806178969 0.007546972735349737 0.011767808214400977 0.017197117076335006 0.02345686346995568 0.029682723819807404 0.034771922171507014 0.037967471560866946 0.039271442880153225 0.03939450951957951 0.039285425289338295 0.03939450951957952 0.039271442880153204 0.037967471560866946 0.03477192217150699 0.029682723819807365 0.023456863469955666 0.017197117076334992 0.011767808214400963 0.0075469727353497315 0.004570037806178957 0.0026987296766766244 0.0016584905708846639 0.0011270689633863335 0.0008701737083641782 0.0007667896670978398 0.0009055757124909084 0.0012624736503087108 0.002038034982836017 0.003565593495754315 0.006171924531510298 0.010174247183974288 0.016130953814403683 0.024608649914735686 0.03492861208914286 0.044352179159220566 0.049796569529523514 0.050491304937156894 0.047938404154548864 0.04387607687253016 0.03939450951957952 0.035269934863478375 0.031811228595801495 0.02854698315066253 0.02483327612429588 0.020572286992175923 0.016125443171831913 0.011889215069225799 0.0081675170986731 0.005225728102749311 0.0032019567330937248 0.001993538699736137 0.0013314457145501813 0.0009705099287999353 0.0007900599153244982 0.0007212546483763916 0.0009218909549822137 0.0013888305176585232 0.002423979187085861 0.004422978400784094 0.007710433178781157 0.012938092278920265 0.021833526348406386 0.0363667313100634 0.05505469128506339 0.07046765868336342 0.07491270404560922 0.06864617972454862 0.05804858897493286 0.04793840415454885 0.03927144288015322 0.03181122859580151 0.02580412409566321 0.02124810892754824 0.017509967750017317 0.014055945234431325 0.010803241393581731 0.007869541377713712 0.005391246813130979 0.0035046384072238597 0.002250232107860967 0.0015021101566728326 0.0010612533502024916 0.0007970503483696827 0.0006814304005537424 0.0006876207794232091 0.0009416347748850419 0.0014949492493011294 0.0027252012978601485 0.005065990398946286 0.008932914694551082 0.015692722152502885 0.02901729743471953 0.05321910300325958 0.08539324864328053 0.10979393375630835 0.11099495791676933 0.09210298693624547 0.0686461797245486 0.05049130493715689 0.037967471560866946 0.028546983150662536 0.021248108927548245 0.0160522850222263 0.012428670230404578 0.009603227887007511 0.007195842070608357 0.005172902766082885 0.00357671094876303 0.002419859374637219 0.0016519263713297727 0.0011583572591615193 0.0008297072438039185 0.0006317512268016363 0.0005841060597842315 0.0006638652867328166 0.0009450532555018925 0.0015311746859497824 0.002841964997621868 0.005337764510923132 0.009578011906467707 0.01767499640965905 0.03523219889608198 0.06896977349167827 0.11441220866588603 0.14696938808169446 0.14349707688030014 0.11099495791676932 0.07491270404560921 0.049796569529523486 0.03477192217150701 0.024833276124295894 0.017509967750017317 0.012428670230404575 0.009130819952328817 0.006814124455876278 0.004986649428306462 0.003543537105845846 0.002475786058730045 0.0017314033525384163 0.0012246577971138652 0.0008696279545382181 0.0006217834696838501 0.0004938979088174706 0.0005122217700908235 0.0006161255593246767 0.0008912224146887217 0.0014533516270413829 0.0027278262838996694 0.005174646336827465 0.009386166372071904 0.017646077493263038 0.03602771739152602 0.07184481865601178 0.12002991041620259 0.15337842354304512 0.14696938808169446 0.10979393375630832 0.07046765868336341 0.04435217915922054 0.0296827238198074 0.02057228699217594 0.01405594523443134 0.009603227887007522 0.006814124455876277 0.004960423816152613 0.003562006468401314 0.002497811990922799 0.0017395256062650282 0.001220849804782811 0.0008625415369536054 0.0006090221462856666 0.00044308360009883183 0.00038202411574576645 0.0004453625188348333 0.0005262171083925554 0.0007727221740842515 0.0012722104792645447 0.002414862370457803 0.004622831473009581 0.008343439782146932 0.015258430610257591 0.029954352756893624 0.0578740073022069 0.09489057748909481 0.12002991041620258 0.114412208665886 0.0853932486432805 0.055054691285063365 0.03492861208914283 0.023456863469955666 0.016125443171831916 0.010803241393581723 0.00719584207060836 0.004986649428306469 0.0035620064684013346 0.0025187898826278384 0.0017465327290204899 0.0012060439533125807 0.0008364038989140117 0.0005817603729256263 0.0004103825706411281 0.000310088400531048 0.0002902993943691686 0.0003660870006756833 0.00041701622182258605 0.0006296342986623041 0.0010447624265133995 0.001982106453963776 0.003804765825581188 0.006767615584404147 0.011664359723122485 0.020864596443750796 0.03709954904779629 0.05787400730220689 0.07184481865601178 0.06896977349167827 0.05321910300325957 0.03636673131006339 0.02460864991473568 0.017197117076335006 0.011889215069225807 0.007869541377713717 0.005172902766082889 0.0035435371058458415 0.0024978119909227995 0.0017465327290204834 0.0012099587610935293 0.0008408650019755478 0.0005833386314490105 0.0004031565891849658 0.00028716150921595285 0.00022463885487634575 0.00021817936648992146 0.0002817392936413669 0.00032132396993739184 0.0005030317145494129 0.0008239745350408558 0.0015115507963728537 0.00286340564415126 0.005045103596017061 0.008248830730131529 0.013230330906524545 0.02086459644375079 0.029954352756893617 0.036027717391526 0.03523219889608198 0.029017297434719525 0.021833526348406372 0.01613095381440368 0.01176780821440097 0.00816751709867311 0.005391246813130981 0.0035767109487630368 0.002475786058730046 0.0017395256062650386 0.0012060439533125768 0.0008408650019755485 0.0005962452510614011 0.0004193721286009223 0.0002908621346563818 0.00021079146292321104 0.00016905754840345952 0.00016298950258331329 0.00020872672490351304 0.000245167223414084 0.0003988059216545937 0.0006304765274554554 0.0010719536575662396 0.0019497470457856536 0.0034314450613520146 0.005522965993520521 0.008248830730131525 0.011664359723122481 0.015258430610257577 0.017646077493263034 0.017674996409659038 0.015692722152502885 0.01293809227892025 0.010174247183974286 0.0075469727353497254 0.005225728102749313 0.003504638407223856 0.002419859374637237 0.0017314033525384063 0.0012208498047828174 0.0008364038989139964 0.0005833386314490078 0.0004193721286009135 0.000297036000348807 0.00020537152754665028 0.00015107953004165833 0.00012439403742308856 0.00011899803177517318 0.00015154206168441263 0.0001752687237193329 0.0003003899004650764 0.000463328584121386 0.0007181879547709626 0.0012147289412613525 0.0021108206748463114 0.0034314450613520202 0.005045103596017063 0.006767615584404143 0.008343439782146925 0.009386166372071894 0.009578011906467697 0.008932914694551078 0.007710433178781143 0.006171924531510297 0.004570037806178956 0.003201956733093745 0.0022502321078609736 0.0016519263713298074 0.001224657797113856 0.0008625415369536225 0.0005817603729255985 0.000403156589184957 0.0002908621346563638 0.00020537152754664635 0.0001397860838600137 0.00010310204404458767 0.00008687310358684034 0.00008236911364064419 0.00010322000910759706 0.00010990207288447763 0.0002022661710982121 0.0003206654954183218 0.00047371285458236304 0.0007370114712795549 0.0012147289412613527 0.0019497470457856593 0.0028634056441512613 0.00380476582558119 0.004622831473009572 0.005174646336827454 0.005337764510923113 0.005065990398946279 0.004422978400784082 0.003565593495754312 0.0026987296766766184 0.0019935386997361375 0.0015021101566728265 0.0011583572591615354 0.0008696279545382088 0.0006090221462856638 0.00041038257064111204 0.0002871615092159495 0.00021079146292321042 0.00015107953004165608 0.00010310204404459268 0.00007553666539708805 0.00006224326772106643 0.00005473562818607552 0.00006307845147369203 0.000060288850131601315 0.00011796120117655361 0.0002042498623303512 0.0003158654422010065 0.00047371285458236217 0.000718187954770962 0.0010719536575662428 0.0015115507963728576 0.0019821064539637745 0.0024148623704578044 0.0027278262838996655 0.0028419649976218716 0.00272520129786015 0.0024239791870858582 0.0020380349828360176 0.0016584905708846597 0.00133144571455018 0.001061253350202484 0.0008297072438039154 0.0006217834696838464 0.00044308360009883866 0.0003100884005310577 0.00022463885487634778 0.00016905754840346548 0.00012439403742308885 0.00008687310358684594 0.0000622432677210637 0.00004802404642698561 0.000038120097772280616 0.00003706462000963045 0.000034395759926612866 0.00006258753462346925 0.00011779395139745174 0.00020424986233035156 0.0003206654954183222 0.0004633285841213859 0.0006304765274554571 0.0008239745350408571 0.0010447624265133967 0.0012722104792645436 0.0014533516270413785 0.0015311746859497843 0.00149494924930113 0.0013888305176585202 0.0012624736503087145 0.0011270689633863335 0.0009705099287999461 0.0007970503483696849 0.0006317512268016499 0.0004938979088174703 0.00038202411574577295 0.0002902993943691596 0.00021817936648992235 0.0001629895025833073 0.00011899803177517131 0.00008236911364064257 0.0000547356281860716 0.00003812009777227909 0.000029796252276298756 0.00002671170950945748 0.0000283246199779643 0.00003682836488375211 0.00006258753462346604 0.0001179612011765511 0.00020226617109821062 0.0003003899004650742 0.00039880592165459305 0.0005030317145494126 0.0006296342986623011 0.0007727221740842557 0.0008912224146887111 0.0009450532555018952 0.0009416347748850449 0.0009218909549822147 0.0009055757124909083 0.0008701737083641748 0.0007900599153245 0.0006814304005537375 0.0005841060597842309 0.0005122217700908241 0.0004453625188348344 0.0003660870006756852 0.00028173929364136836 0.00020872672490351515 0.0001515420616844106 0.00010322000910759709 0.0000630784514736897 0.00003706462000963082 0.00002671170950945835 0.00002584965898538464 0.00003655595560015577 0.00003557185750931505 0.000041319385248321364 0.00006927841106991529 0.00012443697714304802 0.0001982325344744391 0.00027877854625725593 0.0003688317936540765 0.00048372110075524215 0.0006161255593246789 0.0007258557129460851 0.0007842331047055416 0.0008116561588309215 0.000848652587863017 0.000899596926771197 0.0009254338743022589 0.0008995969267711935 0.0008486525878630274 0.0008116561588309285 0.0007842331047055624 0.000725855712946092 0.0006161255593246789 0.00048372110075524215 0.00036883179365407824 0.00027877854625725246 0.00019823253447444344 0.00012443697714305214 0.0000692784110699141 0.00004131938524831941 0.00003557185750931386 0.00003557185750931063 0.00003378055041345855 0.000035385816829217635 0.00004701150675251061 0.00007498642144383452 0.00011896774347643631 0.00017592000902818525 0.0002477776759972891 0.0003399973189839411 0.00044536251883483543 0.0005424395332519994 0.0006206635119981463 0.0006992403467681046 0.0008039528511211475 0.0009248564411888041 0.0010189283889044897 0.0010633634004519066 0.0010826685402583601 0.0011029764516615383 0.0011033690494170456 0.0010359122065182317 0.0008912224146887286 0.0007178665296542963 0.0005666602319166247 0.0004446288697689905 0.00033140131162270317 0.00022075191810651056 0.00012834877183813854 0.0000694534239772626 0.000043235477902205726 0.00004131938524831631 0.00003538581682921974 0.00004244351625248899 0.0000534867730496908 0.00006978108319975275 0.00009890637973826212 0.00014536777784028253 0.0002082531196669506 0.00028670028072873743 0.0003820241157457642 0.0004936140235558717 0.000619928935496508 0.0007668541041885802 0.0009407587239141591 0.001131106546132809 0.0013145279401521133 0.0014775571166893112 0.0016224551241649828 0.0017355804206419878 0.0017673346539450925 0.0016700548810745848 0.0014533516270413879 0.0011822360315786303 0.0009202033550584999 0.0006923623475488142 0.000498462305990984 0.00033825695584043756 0.0002138467588570359 0.00012514458310738434 0.00006945342397726359 0.00006927841106991042 0.00004701150675251299 0.00005348677304968804 0.00006835590124955515 0.00008400938969302702 0.00011318982875864928 0.00016697925239012322 0.00023964913362904756 0.0003274960299765997 0.0004430836000988382 0.0006026697091401506 0.000802340509707852 0.0010219478720986856 0.0012617286215816496 0.0015544662428558075 0.0019295502396633577 0.0023697225303135235 0.002801816126635201 0.003119967987070013 0.003228437579871231 0.003086925039933336 0.0027278262838996764 0.0022318845186097467 0.0016880521502273173 0.0011766546693540224 0.0007669655867827602 0.0004915278415428211 0.0003245071852586883 0.00021384675885703197 0.00012834877183813626 0.00012443697714304626 0.00007498642144384081 0.00006978108319975293 0.00008400938969303111 0.00010514847136896313 0.00014673972099953975 0.00022295862859128117 0.00032387472212927856 0.0004446632000163196 0.0006090221462856611 0.0008478810904686472 0.0011458895699827402 0.0014604937925648636 0.001825204008814365 0.0023618270227441997 0.003158287344604469 0.004139463137881508 0.005081308636276995 0.005751359337704085 0.006004520936120351 0.005795395785142994 0.005174646336827471 0.004261837790878293 0.003200677769729527 0.002157533096200783 0.0013149137141692023 0.000775324106980638 0.0004915278415428211 0.00033825695584043306 0.00022075191810650628 0.00019823253447444098 0.00011896774347644245 0.00009890637973826047 0.00011318982875865142 0.00014673972099954252 0.00021069153291213466 0.00031852290143668437 0.00045802707986650036 0.0006269184999834852 0.0008625415369536149 0.0012086120836674226 0.0016434510892206775 0.002139123729663383 0.0028100800161901893 0.0038771846297218334 0.005425288999380869 0.007230885503687026 0.008929833570272605 0.010237380254440192 0.010884820552833423 0.010602809983185002 0.00938616637207191 0.0075933488918848374 0.005648678265475139 0.0038244570202485345 0.0023263946674731348 0.0013149137141692056 0.0007669655867827637 0.0004984623059909851 0.0003314013116227013 0.0002787785462572521 0.00017592000902818633 0.0001453677778402738 0.00016697925239012314 0.00022295862859128158 0.00031852290143667385 0.0004639337960051334 0.0006500135096252602 0.0008847228995316183 0.00122084980478281 0.001712433676381477 0.002354831169547929 0.003192916721677649 0.004462883841154424 0.006443731463249312 0.009106667450547156 0.012128142883814006 0.015326377141967948 0.018522657783122464 0.020780306627006553 0.02061112201000015 0.017646077493263048 0.013326033228026436 0.009317982583385745 0.006190457485260739 0.003824457020248536 0.002157533096200785 0.0011766546693540256 0.0006923623475488161 0.00044462886976899036 0.00036883179365407775 0.00024777767599729386 0.00020825311966694886 0.00023964913362905182 0.00032387472212928463 0.0004580270798664974 0.0006500135096252667 0.0009038676023293295 0.0012460069125889664 0.0017395256062650273 0.0024416984473356416 0.00338905966569943 0.00475392071282566 0.006923153073596431 0.010179124463848844 0.01439934812476545 0.019618811318097906 0.026619531064699168 0.03552916848266975 0.04315798504401966 0.04388257004641344 0.03602771739152603 0.024603902216747162 0.015236007343764202 0.009317982583385733 0.005648678265475134 0.0032006777697295256 0.0016880521502273195 0.000920203355058503 0.0005666602319166236 0.0004837211007552403 0.000339997318983945 0.0002867002807287326 0.00032749602997659936 0.0004446632000163286 0.0006269184999834628 0.0008847228995316204 0.0012460069125889643 0.0017619709067586797 0.0024978119909228086 0.003500116031062487 0.00485250463067137 0.006884090603571326 0.010148692673302803 0.014947087410735702 0.021340499097863355 0.030550059905471997 0.0455178264797081 0.06708402303583848 0.08704897352051251 0.09023345115385847 0.0718448186560118 0.0451078343886094 0.024603902216747162 0.01332603322802642 0.0075933488918848305 0.004261837790878281 0.0022318845186097475 0.00118223603157863 0.0007178665296542943 0.0006161255593246733 0.0004453625188348368 0.00038202411574576124 0.00044308360009883286 0.0006090221462856643 0.0008625415369535959 0.0012208498047828024 0.0017395256062650221 0.0024978119909228047 0.0035620064684013346 0.004960423816152617 0.00681412445587629 0.009603227887007527 0.014055945234431357 0.020572286992175955 0.02968272381980741 0.044352179159220545 0.07046765868336342 0.10979393375630832 0.1469693880816945 0.15337842354304512 0.1200299104162026 0.0718448186560118 0.036027717391526035 0.01764607749326303 0.0093861663720719 0.005174646336827457 0.002727826283899673 0.0014533516270413829 0.0008912224146887214 0.0007258557129460842 0.0005424395332519978 0.0004936140235558637 0.0006026697091401597 0.0008478810904686651 0.0012086120836674065 0.0017124336763814814 0.002441698447335636 0.003500116031062475 0.004960423816152626 0.006844460467642525 0.009298505535895465 0.012911808749935786 0.0185772433999658 0.02683461413438965 0.03855471669697163 0.05780088809326292 0.09217668859203688 0.14346166377168398 0.19105889057568617 0.1979651696277933 0.15337842354304515 0.09023345115385846 0.043882570046413424 0.02061112201000013 0.010602809983184988 0.005795395785142966 0.003086925039933325 0.001670054881074567 0.0010359122065182228 0.0007842331047055581 0.00062066351199815 0.0006199289354965178 0.0008023405097078604 0.001145889569982755 0.0016434510892207013 0.002354831169547921 0.0033890596656994294 0.004852504630671363 0.006814124455876296 0.009298505535895476 0.01244252109941377 0.016841301099417103 0.02349789729598117 0.03308671725470336 0.046321660756907544 0.06659102873504198 0.1001822094906155 0.14741724073021095 0.1885942788956873 0.19105889057568615 0.14696938808169446 0.0870489735205125 0.043157985044019645 0.02078030662700654 0.010884820552833413 0.006004520936120335 0.003228437579871226 0.0017673346539450881 0.0011033690494170354 0.0008116561588309164 0.0006992403467680959 0.0007668541041885663 0.00102194787209868 0.0014604937925648649 0.002139123729663382 0.00319291672167764 0.0047539207128256536 0.006884090603571322 0.009603227887007529 0.012911808749935801 0.016841301099417096 0.02177177369997527 0.0286496823361066 0.03834686322647695 0.05122583225919664 0.06866773887166151 0.09348758096382308 0.12425304459139379 0.14741724073021095 0.143461663771684 0.10979393375630832 0.06708402303583848 0.03552916848266974 0.01852265778312246 0.010237380254440178 0.005751359337704071 0.0031199679870699925 0.0017355804206419642 0.00110297645166152 0.0008486525878630239 0.0008039528511211462 0.0009407587239141598 0.0012617286215816463 0.0018252040088143618 0.0028100800161902067 0.004462883841154413 0.0069231530735964315 0.010148692673302805 0.01405594523443136 0.01857724339996581 0.023497897295981174 0.0286496823361066 0.03456537249730393 0.042377732608002046 0.052654803118563104 0.06518714478868118 0.07957358172116913 0.09348758096382308 0.1001822094906155 0.09217668859203684 0.07046765868336341 0.045517826479708076 0.02661953106469916 0.015326377141967936 0.008929833570272593 0.005081308636276989 0.002801816126635195 0.0016224551241649783 0.0010826685402583534 0.0008995969267711873 0.0009248564411887993 0.0011311065461327998 0.0015544662428557954 0.0023618270227441962 0.0038771846297218303 0.00644373146324931 0.010179124463848839 0.014947087410735702 0.020572286992175958 0.02683461413438966 0.03308671725470338 0.03834686322647696 0.04237773260800206 0.04639919581004443 0.05188798945407267 0.05874562097273794 0.06518714478868118 0.06866773887166151 0.06659102873504194 0.057800888093262906 0.044352179159220524 0.030550059905471987 0.01961881131809789 0.012128142883814001 0.007230885503687011 0.004139463137881499 0.0023697225303135195 0.0014775571166893002 0.001063363400451899 0.0009254338743022541 0.0010189283889044795 0.001314527940152107 0.0019295502396633503 0.003158287344604465 0.005425288999380874 0.00910666745054715 0.014399348124765447 0.021340499097863355 0.02968272381980741 0.03855471669697165 0.04632166075690755 0.05122583225919665 0.052654803118563104 0.05188798945407266 0.05123786746513384 0.051887989454072664 0.05265480311856309 0.051225832259196635 0.04632166075690752 0.03855471669697161 0.02968272381980739 0.02134049909786334 0.014399348124765442 0.009106667450547147 0.00542528899938086 0.003158287344604465 0.0019295502396633546 0.0013145279401521044 0.0010189283889044827 0.0008995969267711874 0.001063363400451897 0.0014775571166893028 0.002369722530313517 0.004139463137881499 0.007230885503687026 0.012128142883814003 0.0196188113180979 0.030550059905472007 0.044352179159220566 0.05780088809326296 0.066591028735042 0.06866773887166153 0.06518714478868119 0.05874562097273794 0.051887989454072664 0.04639919581004443 0.04237773260800204 0.03834686322647694 0.033086717254703336 0.026834614134389628 0.02057228699217593 0.014947087410735685 0.010179124463848834 0.006443731463249307 0.0038771846297218113 0.0023618270227441954 0.0015544662428558014 0.001131106546132797 0.0009248564411888035 0.0008486525878630232 0.0010826685402583521 0.0016224551241649802 0.002801816126635193 0.005081308636276988 0.008929833570272603 0.015326377141967938 0.026619531064699158 0.04551782647970809 0.07046765868336342 0.0921766885920369 0.10018220949061553 0.09348758096382309 0.07957358172116913 0.06518714478868116 0.0526548031185631 0.042377732608002046 0.034565372497303924 0.02864968233610659 0.02349789729598116 0.018577243399965776 0.014055945234431351 0.010148692673302786 0.006923153073596436 0.00446288384115441 0.0028100800161901876 0.0018252040088143576 0.0012617286215816537 0.000940758723914156 0.0008039528511211503 0.0008116561588309158 0.00110297645166152 0.0017355804206419666 0.003119967987069992 0.005751359337704071 0.010237380254440187 0.018522657783122464 0.035529168482669744 0.0670840230358385 0.10979393375630833 0.14346166377168404 0.14741724073021098 0.12425304459139382 0.09348758096382308 0.0686677388716615 0.051225832259196635 0.03834686322647694 0.02864968233610659 0.02177177369997526 0.016841301099417092 0.012911808749935779 0.009603227887007527 0.0068840906035713065 0.004753920712825661 0.0031929167216776387 0.002139123729663366 0.001460493792564859 0.001021947872098687 0.0007668541041885632 0.0006992403467680987 0.0007842331047055571 0.0011033690494170344 0.001767334653945089 0.003228437579871225 0.006004520936120338 0.01088482055283342 0.020780306627006542 0.043157985044019645 0.0870489735205125 0.14696938808169446 0.19105889057568615 0.18859427889568733 0.14741724073021098 0.1001822094906155 0.06659102873504195 0.04632166075690754 0.03308671725470335 0.02349789729598115 0.0168413010994171 0.012442521099413757 0.009298505535895462 0.006814124455876292 0.004852504630671351 0.003389059665699437 0.0023548311695479242 0.0016434510892206946 0.001145889569982748 0.0008023405097078638 0.0006199289354965168 0.0006206635119981489 0.0007258557129460834 0.0010359122065182202 0.001670054881074567 0.003086925039933323 0.00579539578514297 0.01060280998318499 0.020611122010000132 0.04388257004641341 0.09023345115385843 0.15337842354304512 0.1979651696277933 0.19105889057568617 0.143461663771684 0.09217668859203687 0.05780088809326291 0.03855471669697162 0.02683461413438964 0.018577243399965783 0.012911808749935784 0.009298505535895457 0.0068444604676425125 0.0049604238161526145 0.003500116031062465 0.0024416984473356446 0.0017124336763814881 0.0012086120836674137 0.0008478810904686578 0.000602669709140158 0.0004936140235558664 0.0005424395332519924 0.0006161255593246732 0.0008912224146887186 0.001453351627041383 0.0027278262838996707 0.0051746463368274615 0.0093861663720719 0.017646077493263038 0.036027717391526014 0.07184481865601179 0.12002991041620256 0.15337842354304512 0.14696938808169444 0.10979393375630832 0.0704676586833634 0.044352179159220545 0.029682723819807393 0.02057228699217595 0.014055945234431337 0.009603227887007524 0.0068141244558762816 0.0049604238161526145 0.0035620064684013315 0.002497811990922798 0.001739525606265033 0.0012208498047828087 0.000862541536953614 0.0006090221462856579 0.0004430836000988263 0.0003820241157457679 0.00044536251883482936 0.00048372110075524047 0.0007178665296542936 0.0011822360315786303 0.0022318845186097462 0.004261837790878282 0.007593348891884832 0.013326033228026423 0.02460390221674716 0.04510783438860937 0.07184481865601178 0.09023345115385843 0.0870489735205125 0.06708402303583849 0.04551782647970808 0.030550059905471993 0.02134049909786335 0.014947087410735698 0.010148692673302786 0.006884090603571321 0.004852504630671358 0.0035001160310624726 0.002497811990922794 0.0017619709067586723 0.0012460069125889682 0.000884722899531625 0.000626918499983482 0.00044466320001632255 0.00032749602997659026 0.0002867002807287414 0.00033999731898393777 0.0003688317936540787 0.0005666602319166262 0.0009202033550585045 0.001688052150227317 0.0032006777697295217 0.005648678265475134 0.009317982583385736 0.0152360073437642 0.02460390221674714 0.03602771739152599 0.0438825700464134 0.04315798504401964 0.03552916848266973 0.02661953106469915 0.019618811318097906 0.014399348124765447 0.01017912446384884 0.00692315307359642 0.004753920712825662 0.0033890596656994294 0.002441698447335657 0.0017395256062650293 0.0012460069125889669 0.000903867602329332 0.0006500135096252711 0.0004580270798665131 0.00032387472212928067 0.00023964913362904173 0.0002082531196669581 0.00024777767599728833 0.0002787785462572542 0.00044462886976899616 0.0006923623475488196 0.0011766546693540232 0.0021575330962007797 0.0038244570202485336 0.006190457485260741 0.00931798258338574 0.013326033228026425 0.017646077493263013 0.02061112201000013 0.02078030662700652 0.01852265778312246 0.015326377141967922 0.012128142883814017 0.009106667450547147 0.006443731463249319 0.0044628838411544065 0.0031929167216776582 0.0023548311695479156 0.0017124336763815128 0.0012208498047827996 0.0008847228995316188 0.0006500135096252572 0.0004639337960051376 0.00031852290143668437 0.00022295862859128123 0.00016697925239011235 0.000145367777840283 0.00017592000902818267 0.0001982325344744422 0.00033140131162270783 0.0004984623059909883 0.0007669655867827594 0.0013149137141691982 0.0023263946674731296 0.003824457020248536 0.0056486782654751365 0.007593348891884826 0.009386166372071885 0.010602809983184976 0.010884820552833404 0.010237380254440183 0.008929833570272588 0.0072308855036870325 0.005425288999380864 0.003877184629721836 0.0028100800161901867 0.0021391237296634062 0.0016434510892206903 0.0012086120836674306 0.0008625415369535828 0.0006269184999834736 0.0004580270798664898 0.00031852290143668155 0.00021069153291214046 0.00014673972099954312 0.0001131898287586402 0.00009890637973826746 0.00011896774347643869 0.00012443697714304775 0.00022075191810651287 0.0003382569558404369 0.0004915278415428163 0.000775324106980632 0.0013149137141691952 0.0021575330962007836 0.0032006777697295248 0.004261837790878279 0.005174646336827446 0.005795395785142959 0.006004520936120316 0.0057513593377040715 0.005081308636276978 0.004139463137881506 0.0031582873446044635 0.0023618270227442084 0.0018252040088143579 0.0014604937925648683 0.0011458895699827595 0.0008478810904686616 0.0006090221462856633 0.0004446632000163286 0.0003238747221292787 0.00022295862859127993 0.0001467397209995456 0.00010514847136896577 0.00008400938969302141 0.00006978108319975903 0.00007498642144383795 0.00006927841106991065 0.00012834877183814063 0.00021384675885703522 0.0003245071852586839 0.000491527841542816 0.0007669655867827531 0.001176654669354023 0.001688052150227317 0.0022318845186097367 0.0027278262838996642 0.0030869250399333183 0.003228437579871211 0.0031199679870699986 0.00280181612663519 0.002369722530313526 0.0019295502396633594 0.0015544662428557978 0.0012617286215816485 0.0010219478720986798 0.0008023405097078758 0.0006026697091401487 0.00044308360009883866 0.00032749602997659584 0.00023964913362905187 0.0001669792523901186 0.0001131898287586526 0.00008400938969303006 0.00006835590124954741 0.000053486773049692154 0.00004701150675250955 0.00004131938524831699 0.00006945342397726673 0.00012514458310738857 0.00021384675885703365 0.0003382569558404347 0.0004984623059909787 0.0006923623475488191 0.0009202033550585009 0.0011822360315786244 0.0014533516270413746 0.0016700548810745675 0.001767334653945067 0.0017355804206419716 0.0016224551241649774 0.0014775571166893142 0.0013145279401521057 0.0011311065461328087 0.0009407587239141525 0.0007668541041885816 0.0006199289354965078 0.0004936140235558746 0.00038202411574576444 0.0002867002807287348 0.0002082531196669457 0.00014536777784027521 0.00009890637973826383 0.00006978108319975709 0.000053486773049685533 0.00004244351625249162 0.000035385816829217384 0.00003557185750931097 0.00004323547790220721 0.00006945342397726619 0.00012834877183813797 0.00022075191810650758 0.000331401311622697 0.00044462886976899416 0.0005666602319166228 0.0007178665296542953 0.0008912224146887197 0.0010359122065182222 0.0011033690494170257 0.001102976451661527 0.0010826685402583489 0.0010633634004519066 0.0010189283889044836 0.0009248564411887997 0.0008039528511211419 0.0006992403467681069 0.000620663511998158 0.0005424395332519974 0.0004453625188348392 0.0003399973189839387 0.00024777767599728774 0.00017592000902818037 0.00011896774347643943 0.00007498642144383883 0.00004701150675250793 0.00003538581682921806 0.00003378055041345674 0.00003710588664386657 0.000037323660304483097 0.000046397958466130786 0.00007921512669110194 0.0001396887624253813 0.00021814488333107016 0.00030401769822515756 0.00040141036955367547 0.0005240339424708983 0.0006638652867328142 0.0007842331047055694 0.0008602438311349526 0.0009088671603585778 0.0009628131037069318 0.0010223797079019666 0.0010503100328411834 0.00102237970790197 0.0009628131037069318 0.0009088671603585674 0.0008602438311349457 0.0007842331047055555 0.0006638652867328246 0.000524033942470907 0.000401410369553672 0.0003040176982251593 0.00021814488333107666 0.00013968876242537653 0.00007921512669110129 0.00004639795846613534 0.00003732366030448136 0.00003732366030448217 0.0000381825714902025 0.000043658645204252785 0.00005906705547390923 0.00008970530400963627 0.00013719159990130793 0.00020289046441402024 0.0002890580940773222 0.0003957651850725558 0.0005122217700908269 0.0006206635119981522 0.0007164119706880387 0.0008161527036543772 0.0009370424568941398 0.0010646588843714019 0.001157905179173965 0.0011973429792128698 0.0012065670294402967 0.0012098210104861202 0.0011893217655105826 0.0011033690494170383 0.0009450532555019064 0.0007609761381989977 0.0006011759042085253 0.00047351329888212587 0.00035604221904844495 0.0002390574811461089 0.00013880284057141338 0.00007386269411413579 0.00004471729841545008 0.00004639795846613285 0.000043658645204256316 0.00005534001214468058 0.00007040658488429089 0.00008929388863325043 0.00012413553643970019 0.00018599940050381252 0.00027449300329204123 0.00037963807815661916 0.0004938979088174731 0.0006199289354965269 0.0007654503468072759 0.0009350204265440118 0.0011239034969201798 0.001316568095776349 0.001494116503295452 0.0016478117139200673 0.0017794167978722845 0.0018739209437563904 0.0018846393517467962 0.00176733465394509 0.0015311746859497852 0.001240872173438077 0.000963234949391188 0.0007261632918973136 0.0005270594962774794 0.0003605926497320415 0.00022811134622592927 0.00013267912482792314 0.00007386269411413397 0.00007921512669110129 0.00005906705547390955 0.00007040658488428776 0.00009168287533174389 0.00011453422882452683 0.00015654031394054602 0.00023652325713134043 0.00034950119417327577 0.00047810797513389623 0.0006217834696838629 0.0008023405097078542 0.0010287461375447157 0.001278104311571265 0.0015340316098065984 0.0018231338833620346 0.002183980940551461 0.0026064943852817293 0.003017057632244775 0.0033101307952636545 0.0033938858370837002 0.003228437579871227 0.002841964997621869 0.0023155029140805305 0.0017456059351057607 0.0012183841389811479 0.0008006309005604039 0.000518955882175917 0.000345101179492469 0.0002281113462259259 0.00013880284057141235 0.0001396887624253797 0.00008970530400963526 0.00008929388863324616 0.00011453422882452715 0.00015191940053496685 0.00021758712571748762 0.00033287461528254435 0.0004883595058147604 0.0006636557209989223 0.0008696279545382316 0.0011458895699827463 0.0014902181260945438 0.0018515398190606307 0.0022406580347984115 0.0027739623811732983 0.003552837721414822 0.004510620325940206 0.005421110613354327 0.006050605342605949 0.006258842946612745 0.006004520936120342 0.005337764510923133 0.004379127580087883 0.0032799082195145513 0.0022129533178503204 0.0013576193121938379 0.0008095426567044831 0.0005189558821759218 0.000360592649732042 0.00023905748114611228 0.00021814488333107254 0.00013719159990131205 0.00012413553643970404 0.0001565403139405559 0.00021758712571749988 0.00031773507373240915 0.00047557676264576226 0.0006808862036299094 0.0009209194452240965 0.0012246577971138746 0.0016434510892206979 0.002162136168289131 0.0027352573802774706 0.003453012634116618 0.004537419787465313 0.006089358996347633 0.007885851634352308 0.009543175734881951 0.01076200947832743 0.01128723236071914 0.01088482055283341 0.009578011906467709 0.007727115860575976 0.005744944457247077 0.0038961044023771425 0.0023815163812629975 0.0013576193121938361 0.0008006309005604077 0.0005270594962774784 0.0003560422190484434 0.00030401769822515956 0.0002028904644140221 0.00018599940050381095 0.0002365232571313414 0.00033287461528254435 0.00047557676264574166 0.0006797234220084588 0.0009448983181505521 0.0012792562992190331 0.0017314033525384223 0.002354831169547914 0.003137278091103788 0.004098860343354643 0.005460917229675777 0.007517489748370425 0.01025048918273596 0.013300080450640442 0.01641060648739892 0.019358270366481176 0.021259632970865458 0.02078030662700654 0.01767499640965906 0.013355186574400192 0.00938310961145656 0.00627031065322798 0.003896104402377146 0.002212953317850318 0.001218384138981152 0.0007261632918973125 0.00047351329888212684 0.00040141036955367867 0.0002890580940773222 0.0002744930032920391 0.00034950119417327647 0.0004883595058147583 0.0006808862036298988 0.0009448983181505558 0.0013044219419491028 0.0017953659478324852 0.0024757860587300558 0.0033890596656994264 0.004548630795370643 0.00610381900746991 0.008449495985470217 0.011899632005612585 0.016313578902386976 0.021600447001363182 0.02834584680170842 0.03654237041029714 0.04316919361830618 0.04315798504401965 0.035232198896081986 0.024168342736126214 0.015142111007148462 0.009383109611456546 0.0057449444572470745 0.0032799082195145417 0.0017456059351057636 0.0009632349493911905 0.0006011759042085286 0.0005240339424709094 0.0003957651850725665 0.0003796380781566204 0.0004781079751339055 0.0006636557209989316 0.0009209194452240732 0.0012792562992190403 0.0017953659478324774 0.0025319910818477646 0.003543537105845861 0.00485250463067136 0.006514726734788965 0.00885116389647317 0.012455354564246365 0.01767088697656699 0.0244766164533361 0.03380867422689518 0.048152048763744876 0.06795136304519563 0.0854511061047993 0.0870489735205125 0.06896977349167828 0.04358793167375027 0.024168342736126214 0.01335518657440018 0.007727115860575974 0.004379127580087871 0.002315502914080532 0.0012408721734380723 0.0007609761381989986 0.0006638652867328214 0.0005122217700908284 0.0004938979088174735 0.0006217834696838544 0.000869627954538214 0.0012246577971138683 0.0017314033525384206 0.0024757860587300493 0.003543537105845862 0.004986649428306471 0.006814124455876287 0.009130819952328827 0.01242867023040457 0.017509967750017324 0.0248332761242959 0.03477192217150701 0.04979656952952348 0.07491270404560924 0.1109949579167693 0.14349707688030017 0.14696938808169446 0.11441220866588603 0.06896977349167828 0.035232198896082 0.01767499640965904 0.009578011906467706 0.005337764510923121 0.002841964997621879 0.0015311746859497856 0.0009450532555018989 0.0007842331047055634 0.0006206635119981527 0.0006199289354965222 0.0008023405097078669 0.001145889569982752 0.0016434510892207057 0.0023548311695479347 0.0033890596656994333 0.00485250463067137 0.006814124455876285 0.009298505535895455 0.012442521099413769 0.016841301099417078 0.02349789729598117 0.03308671725470335 0.04632166075690753 0.06659102873504195 0.10018220949061551 0.14741724073021095 0.18859427889568736 0.19105889057568615 0.1469693880816945 0.0870489735205125 0.043157985044019666 0.02078030662700654 0.010884820552833414 0.006004520936120329 0.0032284375798712333 0.00176733465394509 0.001103369049417041 0.0008602438311349474 0.0007164119706880187 0.0007654503468072695 0.0010287461375447044 0.0014902181260945126 0.002162136168289133 0.0031372780911037693 0.004548630795370629 0.006514726734788959 0.009130819952328827 0.012442521099413758 0.016525152107304975 0.02189076798410276 0.029690429604246074 0.0409670487024712 0.05648559203452079 0.07887991219536251 0.11281644974287013 0.1567811615087032 0.19153674991461137 0.18859427889568733 0.14349707688030014 0.08545110610479931 0.043169193618306186 0.021259632970865448 0.01128723236071913 0.006258842946612733 0.0033938858370837037 0.0018846393517467897 0.0011893217655105767 0.0009088671603585781 0.0008161527036543686 0.0009350204265440095 0.0012781043115712668 0.0018515398190606278 0.0027352573802774728 0.0040988603433546504 0.006103819007469914 0.008851163896473174 0.012428670230404582 0.016841301099417096 0.02189076798410277 0.027636802532900424 0.03518834279291237 0.046238820468267196 0.061744137967736784 0.08242112353905497 0.10918928639667484 0.13854009018097047 0.15678116150870317 0.14741724073021098 0.11099495791676933 0.06795136304519564 0.03654237041029714 0.01935827036648119 0.010762009478327436 0.006050605342605956 0.003310130795263671 0.0018739209437563815 0.001209821010486134 0.0009628131037069287 0.0009370424568941306 0.001123903496920184 0.001534031609806593 0.002240658034798411 0.0034530126341166516 0.005460917229675774 0.008449495985470214 0.012455354564246367 0.017509967750017327 0.023497897295981143 0.02969042960424606 0.035188342792912344 0.04060359154257609 0.048458000595130814 0.06076976938801451 0.0770637825693041 0.09479720627444045 0.10918928639667484 0.11281644974287014 0.1001822094906155 0.07491270404560924 0.04815204876374487 0.02834584680170843 0.016410606487398924 0.009543175734881951 0.005421110613354321 0.0030170576322447774 0.001779416797872282 0.0012065670294402922 0.0010223797079019676 0.0010646588843713969 0.0013165680957763501 0.0018231338833620317 0.002773962381173295 0.004537419787465323 0.007517489748370423 0.011899632005612584 0.017670886976566987 0.02483327612429591 0.03308671725470334 0.0409670487024712 0.046238820468267175 0.048458000595130835 0.0506179217203155 0.05654257027060355 0.06663205520314515 0.0770637825693041 0.082421123539055 0.0788799121953625 0.06659102873504197 0.049796569529523486 0.03380867422689518 0.021600447001363186 0.013300080450640454 0.007885851634352301 0.004510620325940207 0.002606494385281738 0.0016478117139200601 0.0011973429792128628 0.0010503100328411814 0.001157905179173961 0.0014941165032954585 0.0021839809405514565 0.0035528377214148164 0.006089358996347648 0.010250489182735956 0.016313578902386973 0.024476616453336097 0.034771922171507014 0.04632166075690752 0.05648559203452079 0.06174413796773677 0.060769769388014525 0.05654257027060354 0.05427095251989683 0.05654257027060355 0.06076976938801452 0.06174413796773681 0.05648559203452079 0.04632166075690752 0.03477192217150702 0.024476616453336097 0.016313578902386973 0.010250489182735963 0.006089358996347631 0.0035528377214148186 0.0021839809405514664 0.0014941165032954491 0.001157905179173961 0.0010223797079019679 0.0011973429792128628 0.00164781171392007 0.0026064943852817293 0.00451062032594021 0.007885851634352316 0.01330008045064045 0.02160044700136319 0.03380867422689518 0.04979656952952351 0.06659102873504198 0.0788799121953625 0.08242112353905497 0.0770637825693041 0.06663205520314515 0.05654257027060355 0.050617921720315505 0.04845800059513082 0.04623882046826721 0.040967048702471184 0.03308671725470334 0.024833276124295905 0.017670886976566984 0.011899632005612577 0.007517489748370429 0.0045374197874653 0.0027739623811733 0.0018231338833620406 0.0013165680957763415 0.001064658884371397 0.000962813103706928 0.0012065670294402915 0.0017794167978722908 0.0030170576322447688 0.0054211106133543255 0.009543175734881957 0.016410606487398918 0.028345846801708423 0.048152048763744855 0.07491270404560922 0.10018220949061549 0.11281644974287011 0.10918928639667483 0.09479720627444045 0.07706378256930409 0.06076976938801452 0.048458000595130814 0.04060359154257608 0.035188342792912365 0.02969042960424607 0.023497897295981146 0.017509967750017334 0.01245535456424636 0.008449495985470215 0.005460917229675776 0.003453012634116628 0.002240658034798418 0.0015340316098066001 0.0011239034969201763 0.00093704245689413 0.0009088671603585776 0.0012098210104861337 0.001873920943756391 0.003310130795263665 0.006050605342605965 0.010762009478327441 0.019358270366481193 0.03654237041029714 0.06795136304519564 0.11099495791676933 0.14741724073021098 0.15678116150870314 0.13854009018097047 0.10918928639667483 0.08242112353905495 0.061744137967736784 0.04623882046826719 0.035188342792912365 0.027636802532900448 0.021890767984102773 0.016841301099417078 0.012428670230404594 0.008851163896473169 0.006103819007469917 0.00409886034335465 0.0027352573802774493 0.0018515398190606354 0.0012781043115712722 0.000935020426544005 0.0008161527036543664 0.0008602438311349465 0.0011893217655105756 0.0018846393517467975 0.0033938858370836976 0.006258842946612742 0.011287232360719131 0.021259632970865444 0.04316919361830618 0.08545110610479928 0.14349707688030014 0.18859427889568733 0.19153674991461137 0.15678116150870317 0.11281644974287013 0.0788799121953625 0.05648559203452078 0.04096704870247119 0.029690429604246057 0.021890767984102787 0.016525152107304965 0.012442521099413751 0.009130819952328827 0.0065147267347889564 0.004548630795370631 0.003137278091103771 0.002162136168289117 0.0014902181260945193 0.0010287461375447055 0.0007654503468072685 0.0007164119706880131 0.000784233104705562 0.0011033690494170376 0.0017673346539450957 0.0032284375798712277 0.006004520936120339 0.010884820552833413 0.02078030662700654 0.04315798504401965 0.08704897352051248 0.14696938808169446 0.19105889057568612 0.18859427889568733 0.14741724073021098 0.10018220949061551 0.06659102873504195 0.04632166075690754 0.03308671725470335 0.023497897295981156 0.0168413010994171 0.01244252109941375 0.009298505535895457 0.006814124455876288 0.004852504630671364 0.00338905966569944 0.002354831169547936 0.001643451089220705 0.001145889569982758 0.0008023405097078638 0.0006199289354965256 0.000620663511998144 0.0006638652867328201 0.0009450532555018936 0.0015311746859497895 0.002841964997621873 0.005337764510923131 0.009578011906467702 0.017674996409659048 0.03523219889608198 0.06896977349167828 0.114412208665886 0.14696938808169446 0.14349707688030014 0.11099495791676933 0.07491270404560921 0.0497965695295235 0.034771922171507 0.0248332761242959 0.01750996775001732 0.012428670230404582 0.009130819952328811 0.0068141244558762816 0.004986649428306471 0.003543537105845855 0.002475786058730059 0.0017314033525384254 0.00122465779711388 0.0008696279545382199 0.0006217834696838484 0.0004938979088174801 0.0005122217700908189 0.0005240339424709079 0.0007609761381989933 0.0012408721734380737 0.002315502914080527 0.004379127580087877 0.007727115860575972 0.013355186574400185 0.024168342736126214 0.04358793167375025 0.06896977349167827 0.08704897352051248 0.08545110610479931 0.06795136304519564 0.048152048763744876 0.03380867422689519 0.0244766164533361 0.01767088697656699 0.012455354564246358 0.008851163896473172 0.006514726734788941 0.004852504630671362 0.003543537105845842 0.0025319910818477572 0.001795365947832483 0.001279256299219043 0.0009209194452240897 0.0006636557209989366 0.0004781079751338988 0.0003796380781566281 0.0003957651850725581 0.0004014103695536777 0.0006011759042085248 0.0009632349493911909 0.001745605935105759 0.003279908219514546 0.005744944457247073 0.009383109611456551 0.01514211100714846 0.024168342736126204 0.03523219889608198 0.04315798504401964 0.043169193618306186 0.036542370410297155 0.02834584680170842 0.02160044700136319 0.016313578902386976 0.011899632005612589 0.008449495985470215 0.006103819007469912 0.0045486307953706145 0.0033890596656994364 0.0024757860587300475 0.0017953659478324808 0.0013044219419491084 0.0009448983181505612 0.0006808862036299146 0.0004883595058147634 0.00034950119417327083 0.0002744930032920474 0.00028905809407731595 0.0003040176982251596 0.0004735132988821252 0.000726163291897313 0.0012183841389811474 0.0022129533178503217 0.0038961044023771447 0.006270310653227986 0.009383109611456553 0.013355186574400192 0.01767499640965904 0.02078030662700655 0.02125963297086543 0.0193582703664812 0.016410606487398904 0.013300080450640454 0.010250489182735951 0.007517489748370436 0.005460917229675767 0.004098860343354656 0.0031372780911037355 0.00235483116954794 0.0017314033525384054 0.0012792562992190327 0.0009448983181505499 0.0006797234220084657 0.00047557676264575456 0.000332874615282547 0.00023652325713133644 0.00018599940050381932 0.0002028904644140181 0.00021814488333107222 0.0003560422190484422 0.0005270594962774781 0.0008006309005604014 0.0013576193121938379 0.0023815163812629958 0.0038961044023771456 0.005744944457247074 0.007727115860575973 0.009578011906467697 0.010884820552833418 0.011287232360719135 0.01076200947832745 0.009543175734881938 0.007885851634352316 0.006089358996347636 0.004537419787465325 0.003453012634116625 0.002735257380277469 0.0021621361682890917 0.0016434510892207135 0.0012246577971138423 0.0009209194452240791 0.0006808862036298989 0.0004755767626457625 0.0003177350737324186 0.0002175871257174978 0.0001565403139405499 0.0001241355364397104 0.00013719159990130866 0.00013968876242537976 0.00023905748114611203 0.00036059264973204125 0.0005189558821759151 0.0008095426567044845 0.001357619312193837 0.002212953317850322 0.0032799082195145443 0.004379127580087875 0.005337764510923121 0.006004520936120349 0.00625884294661273 0.006050605342605958 0.005421110613354311 0.004510620325940208 0.003552837721414814 0.0027739623811732987 0.0022406580347984076 0.0018515398190606213 0.0014902181260944918 0.001145889569982768 0.0008696279545382156 0.0006636557209989301 0.000488359505814754 0.00033287461528254837 0.00021758712571749717 0.00015191940053496338 0.00011453422882452171 0.00008929388863325178 0.00008970530400963299 0.00007921512669110095 0.0001388028405714125 0.00022811134622592317 0.000345101179492462 0.0005189558821759169 0.0008006309005604034 0.0012183841389811476 0.0017456059351057581 0.0023155029140805214 0.002841964997621871 0.0032284375798712355 0.003393885837083705 0.003310130795263669 0.0030170576322447705 0.002606494385281731 0.0021839809405514565 0.0018231338833620283 0.0015340316098065984 0.001278104311571257 0.0010287461375447075 0.0008023405097078524 0.0006217834696838503 0.0004781079751338971 0.00034950119417326926 0.00023652325713134124 0.0001565403139405562 0.0001145342288245226 0.00009168287533173836 0.00007040658488429245 0.00005906705547390706 0.00004639795846613323 0.00007386269411413525 0.00013267912482791991 0.00022811134622592423 0.0003605926497320429 0.0005270594962774789 0.000726163291897312 0.0009632349493911882 0.0012408721734380622 0.0015311746859497852 0.001767334653945104 0.001884639351746797 0.0018739209437563854 0.0017794167978722787 0.0016478117139200634 0.0014941165032954476 0.0013165680957763547 0.001123903496920176 0.000935020426543997 0.000765450346807241 0.0006199289354965226 0.0004938979088174602 0.00037963807815662425 0.0002744930032920349 0.00018599940050381412 0.00012413553643970759 0.00008929388863324507 0.00007040658488428612 0.000055340012144685616 0.00004365864520425422 0.00003732366030448258 0.00004471729841545175 0.00007386269411413178 0.00013880284057141094 0.00023905748114611222 0.00035604221904844127 0.00047351329888212386 0.0006011759042085248 0.000760976138198986 0.0009450532555018981 0.0011033690494170472 0.0011893217655105871 0.0012098210104861378 0.0012065670294402946 0.0011973429792128678 0.001157905179173967 0.0010646588843714016 0.0009370424568941314 0.0008161527036543481 0.0007164119706880082 0.000620663511998146 0.0005122217700908257 0.0003957651850725602 0.0002890580940773183 0.00020289046441402073 0.0001371915999013154 0.00008970530400963071 0.000059067055473906016 0.00004365864520425762 0.0000381825714902008 0.00003269514350865853 0.00003494468682887391 0.00004926469609027736 0.00008836635431708944 0.00015338033482130593 0.00023414234946933597 0.0003235039291855689 0.0004262350267255008 0.0005506553884725117 0.0006876207794232099 0.0008116561588309111 0.0009088671603585743 0.000988657092739452 0.0010644064853800005 0.0011288125431500387 0.00115538974508363 0.0011288125431500352 0.0010644064853800005 0.000988657092739459 0.0009088671603585639 0.0008116561588309215 0.0006876207794232099 0.0005506553884725048 0.0004262350267254973 0.0003235039291855646 0.00023414234946933727 0.00015338033482130398 0.00008836635431708987 0.00004926469609028029 0.000034944686828872825 0.000034944686828870283 0.00003927679355652081 0.000050810187432453526 0.00007319711621452375 0.00010991083482162319 0.00016417085279851984 0.0002418134659035405 0.000344331334178368 0.00046335640422671005 0.0005841060597842287 0.000699240346768092 0.0008161527036543748 0.0009448279369217254 0.0010815579702260216 0.0012018072025311438 0.0012756356763438043 0.0012975573945890558 0.0012883678922504806 0.001263241301957172 0.0012098210104861237 0.0011029764516615236 0.0009416347748850448 0.0007619127265753586 0.00060459884105175 0.0004787892601050396 0.00036504846722240755 0.0002496268489333387 0.00014552776986352688 0.00007494986032959889 0.00004233764706958161 0.000049264696090275245 0.00005081018743245673 0.00006872525418735784 0.00009227334361630166 0.0001212201919675421 0.00016975481507747048 0.0002543426496727985 0.0003738581341875606 0.0005052944369660939 0.0006317512268016357 0.0007668541041885725 0.0009350204265439971 0.0011362470259058443 0.0013402003972896577 0.001514568235530564 0.0016503940612064224 0.0017585618402871405 0.0018474983033848521 0.0018998605429481868 0.00187392094375638 0.001735580420641968 0.0014949492493011318 0.0012087368131948285 0.0009395915246891072 0.0007162791068696853 0.0005328767055493027 0.0003746363628123273 0.00023897829057065268 0.00013665578847337528 0.00007494986032959574 0.00008836635431708837 0.00007319711621452634 0.00009227334361629799 0.00012639541981940923 0.00016700154404711295 0.00023267207177716276 0.00034716672433380094 0.0005042574172789228 0.0006692846682037822 0.000829707243803918 0.0010219478720986705 0.0012781043115712696 0.0015723081188699908 0.0018521698782703047 0.0021135152535489117 0.0023998563965444814 0.002728447959614896 0.0030503657603172126 0.0032732159028392017 0.0033101307952636575 0.003119967987069993 0.0027252012978601515 0.0022044233453669187 0.0016589400069480307 0.0011733734294710806 0.00079709057130957 0.0005378107763058989 0.0003644655134322177 0.000238978290570656 0.0001455277698635268 0.00015338033482130387 0.00010991083482162575 0.00012122019196753876 0.00016700154404711442 0.00023265115775077518 0.0003328103516603686 0.0004921829205170368 0.0007011280080980817 0.0009232854720991964 0.0011583572591615232 0.0014604937925648553 0.001851539819060632 0.002274956069556984 0.002694549901459474 0.0031833431333577007 0.0038416187382218953 0.004640662862214497 0.005402100311051655 0.0059182585820492005 0.0060506053426059555 0.005751359337704069 0.005065990398946288 0.00411742695260813 0.003067346428052686 0.0020849230176929008 0.0013144301327347916 0.0008160465074447702 0.0005378107763058989 0.00037463636281233077 0.0002496268489333407 0.00023414234946933938 0.00016417085279852656 0.0001697548150774726 0.0002326720717771684 0.00033281035166037097 0.00047655151408291184 0.0006872824206897226 0.0009614150171436383 0.0012775314669896038 0.0016519263713297664 0.00213912372966339 0.00273525738027744 0.0033781442189325306 0.004107130107226387 0.005105322245517002 0.00648034069555607 0.008053268662561034 0.009473934063312555 0.010451266211617063 0.010762009478327436 0.010237380254440175 0.008932914694551077 0.007172574512613121 0.005320251868544285 0.0036190780350586127 0.0022442729591142293 0.0013144301327347922 0.0007970905713095691 0.0005328767055493049 0.00036504846722240907 0.00032350392918556394 0.00024181346590353668 0.000254342649672787 0.00034716672433379714 0.0004921829205170287 0.0006872824206897135 0.000961699626064919 0.0013339424895266322 0.001810848820147552 0.00241985937463721 0.0031929167216776413 0.004098860343354641 0.0051211323279841195 0.006439066476751874 0.00834058524148512 0.010834126637829369 0.013543651521091844 0.01610805172382184 0.018259425073566694 0.019358270366481183 0.01852265778312245 0.01569272215250288 0.011973630808074336 0.008535272017550811 0.00576989537086557 0.0036190780350586122 0.0020849230176929008 0.0011733734294710801 0.0007162791068696838 0.0004787892601050387 0.00042623502672549623 0.0003443313341783667 0.00037385813418755546 0.0005042574172789247 0.0007011280080980739 0.0009614150171436327 0.0013339424895266335 0.001873168016668062 0.002613715989201985 0.003576710948763024 0.004753920712825659 0.0061038190074699005 0.007717583949283099 0.009966524346444055 0.013205451880473075 0.017291184098801104 0.02187189839919169 0.027043933065993463 0.032628634466063365 0.03654237041029714 0.03552916848266974 0.029017297434719525 0.020422393654937355 0.013311339349175035 0.008535272017550801 0.005320251868544278 0.0030673464280526795 0.0016589400069480272 0.0009395915246891047 0.0006045988410517465 0.0005506553884725053 0.00046335640422671026 0.0005052944369660891 0.000669284668203787 0.0009232854720991991 0.0012775314669895965 0.0018108488201475602 0.002613715989201988 0.0037347489483499116 0.0051729027660828856 0.00688409060357132 0.008851163896473157 0.0113179299397326 0.014864650915170597 0.01989901303708106 0.02625038192951192 0.034073916820984464 0.04456266870809133 0.05761291075195857 0.06795136304519563 0.06708402303583848 0.05321910300325957 0.03476091520282093 0.020422393654937355 0.011973630808074325 0.007172574512613115 0.004117426952608121 0.002204423345366916 0.0012087368131948224 0.0007619127265753577 0.0006876207794232071 0.000584106059784232 0.0006317512268016333 0.0008297072438039175 0.0011583572591615091 0.0016519263713297744 0.002419859374637212 0.0035767109487630237 0.005172902766082883 0.007195842070608358 0.009603227887007524 0.012428670230404566 0.01605228502222629 0.02124810892754824 0.028546983150662533 0.03796747156086694 0.050491304937156874 0.06864617972454862 0.09210298693624545 0.11099495791676933 0.1097939337563083 0.08539324864328052 0.05321910300325958 0.029017297434719536 0.015692722152502874 0.008932914694551075 0.005065990398946278 0.0027252012978601515 0.001494949249301125 0.0009416347748850411 0.0008116561588309151 0.0006992403467680977 0.0007668541041885614 0.001021947872098684 0.0014604937925648566 0.002139123729663374 0.003192916721677636 0.0047539207128256475 0.006884090603571311 0.009603227887007525 0.012911808749935777 0.01684130109941709 0.02177177369997525 0.028649682336106586 0.03834686322647694 0.051225832259196635 0.06866773887166149 0.09348758096382309 0.12425304459139376 0.14741724073021095 0.14346166377168398 0.10979393375630833 0.06708402303583849 0.03552916848266975 0.01852265778312245 0.010237380254440178 0.005751359337704067 0.0031199679870699943 0.00173558042064196 0.0011029764516615201 0.0009088671603585745 0.0008161527036543669 0.0009350204265439971 0.0012781043115712644 0.0018515398190606233 0.0027352573802774597 0.004098860343354639 0.006103819007469908 0.008851163896473163 0.012428670230404585 0.016841301099417096 0.021890767984102767 0.02763680253290043 0.03518834279291236 0.04623882046826719 0.061744137967736784 0.08242112353905497 0.10918928639667483 0.13854009018097044 0.15678116150870314 0.14741724073021095 0.11099495791676933 0.06795136304519563 0.03654237041029714 0.019358270366481183 0.010762009478327436 0.0060506053426059555 0.0033101307952636636 0.0018739209437563745 0.0012098210104861291 0.0009886570927394598 0.000944827936921733 0.0011362470259058425 0.001572308118869993 0.002274956069556972 0.0033781442189325358 0.005121132327984115 0.0077175839492831 0.011317929939732595 0.016052285022226307 0.021771773699975263 0.027636802532900427 0.032874540091875515 0.03869452315378 0.04829702195877415 0.06391931164200326 0.08510319364006401 0.10931266537743455 0.13065893556352043 0.13854009018097044 0.12425304459139379 0.09210298693624547 0.057612910751958575 0.032628634466063365 0.018259425073566697 0.010451266211617061 0.005918258582049203 0.0032732159028392134 0.0018998605429481805 0.0012632413019571752 0.0010644064853800035 0.0010815579702260166 0.0013402003972896597 0.001852169878270296 0.0026945499014594592 0.004107130107226406 0.006439066476751865 0.00996652434644405 0.014864650915170597 0.02124810892754825 0.028649682336106597 0.03518834279291236 0.03869452315377998 0.04018000327837753 0.04470094384614952 0.05667798221207814 0.07545099821496906 0.09562570069848383 0.10931266537743456 0.10918928639667483 0.09348758096382308 0.06864617972454862 0.04456266870809132 0.02704393306599346 0.016108051723821834 0.009473934063312556 0.005402100311051646 0.0030503657603172083 0.0018474983033848456 0.001288367892250477 0.0011288125431500441 0.0012018072025311451 0.0015145682355305644 0.002113515253548916 0.003183343133357695 0.005105322245517008 0.008340585241485116 0.013205451880473076 0.019899013037081057 0.028546983150662543 0.03834686322647694 0.046238820468267196 0.04829702195877414 0.04470094384614952 0.041758922589336805 0.046378590835054814 0.05954917846784605 0.07545099821496908 0.08510319364006404 0.08242112353905495 0.0686677388716615 0.050491304937156874 0.03407391682098447 0.02187189839919169 0.013543651521091854 0.00805326866256104 0.004640662862214502 0.00272844795961491 0.0017585618402871362 0.0012975573945890623 0.001155389745083629 0.0012756356763438002 0.0016503940612064266 0.0023998563965444753 0.003841618738221894 0.006480340695556089 0.010834126637829365 0.01729118409880111 0.02625038192951192 0.03796747156086695 0.051225832259196635 0.06174413796773678 0.06391931164200326 0.056677982212078135 0.04637859083505481 0.041682684735277545 0.046378590835054814 0.056677982212078135 0.06391931164200328 0.061744137967736784 0.05122583225919663 0.03796747156086694 0.02625038192951192 0.01729118409880111 0.01083412663782937 0.006480340695556079 0.003841618738221893 0.0023998563965444853 0.0016503940612064183 0.0012756356763438006 0.001128812543150045 0.0012975573945890626 0.0017585618402871446 0.002728447959614901 0.004640662862214505 0.00805326866256105 0.013543651521091849 0.021871898399191694 0.03407391682098447 0.0504913049371569 0.06866773887166151 0.08242112353905495 0.08510319364006401 0.07545099821496906 0.05954917846784604 0.04637859083505481 0.04175892258933681 0.04470094384614951 0.04829702195877415 0.04623882046826718 0.03834686322647693 0.028546983150662526 0.01989901303708105 0.013205451880473076 0.008340585241485123 0.005105322245516997 0.0031833431333576972 0.0021135152535489256 0.0015145682355305569 0.0012018072025311455 0.0010644064853800041 0.0012883678922504776 0.001847498303384853 0.0030503657603172 0.005402100311051649 0.009473934063312563 0.01610805172382183 0.027043933065993456 0.04456266870809132 0.06864617972454862 0.09348758096382308 0.10918928639667481 0.10931266537743455 0.09562570069848383 0.07545099821496906 0.05667798221207814 0.04470094384614952 0.040180003278377535 0.03869452315378 0.035188342792912365 0.028649682336106586 0.02124810892754825 0.014864650915170589 0.009966524346444057 0.0064390664767518735 0.0041071301072263975 0.0026945499014594627 0.001852169878270305 0.0013402003972896538 0.0010815579702260166 0.0009886570927394615 0.001263241301957178 0.001899860542948189 0.003273215902839208 0.0059182585820492075 0.01045126621161707 0.0182594250735667 0.032628634466063365 0.057612910751958575 0.09210298693624547 0.1242530445913938 0.13854009018097044 0.13065893556352043 0.10931266537743455 0.08510319364006401 0.06391931164200326 0.048297021958774146 0.03869452315378 0.03287454009187553 0.02763680253290044 0.021771773699975256 0.016052285022226307 0.011317929939732591 0.007717583949283108 0.005121132327984124 0.0033781442189325314 0.0022749560695569772 0.0015723081188700008 0.0011362470259058406 0.0009448279369217323 0.0009088671603585758 0.001209821010486132 0.001873920943756382 0.003310130795263659 0.006050605342605961 0.010762009478327441 0.019358270366481183 0.03654237041029714 0.06795136304519561 0.11099495791676932 0.14741724073021095 0.15678116150870314 0.13854009018097044 0.10918928639667481 0.08242112353905495 0.06174413796773678 0.04623882046826719 0.03518834279291235 0.027636802532900445 0.021890767984102773 0.016841301099417096 0.012428670230404577 0.008851163896473163 0.006103819007469914 0.0040988603433546504 0.0027352573802774624 0.0018515398190606298 0.0012781043115712683 0.0009350204265439989 0.0008161527036543632 0.0008116561588309162 0.0011029764516615225 0.0017355804206419668 0.00311996798706999 0.005751359337704073 0.010237380254440182 0.018522657783122454 0.03552916848266974 0.06708402303583848 0.10979393375630832 0.143461663771684 0.14741724073021098 0.12425304459139379 0.09348758096382309 0.0686677388716615 0.051225832259196635 0.03834686322647694 0.028649682336106586 0.021771773699975266 0.016841301099417092 0.01291180874993578 0.009603227887007525 0.006884090603571313 0.004753920712825656 0.003192916721677648 0.002139123729663386 0.0014604937925648631 0.0010219478720986837 0.0007668541041885669 0.0006992403467680916 0.000687620779423208 0.0009416347748850431 0.0014949492493011311 0.0027252012978601476 0.005065990398946284 0.008932914694551077 0.01569272215250288 0.029017297434719525 0.05321910300325958 0.0853932486432805 0.10979393375630832 0.1109949579167693 0.09210298693624547 0.06864617972454859 0.050491304937156894 0.03796747156086693 0.028546983150662533 0.02124810892754824 0.016052285022226307 0.012428670230404582 0.009603227887007527 0.007195842070608363 0.005172902766082881 0.0035767109487630337 0.002419859374637222 0.0016519263713297928 0.0011583572591615163 0.0008297072438039136 0.0006317512268016408 0.0005841060597842249 0.0005506553884725063 0.0007619127265753602 0.0012087368131948272 0.0022044233453669144 0.004117426952608125 0.007172574512613119 0.011973630808074332 0.020422393654937355 0.03476091520282092 0.05321910300325958 0.06708402303583848 0.06795136304519564 0.05761291075195858 0.04456266870809133 0.03407391682098448 0.02625038192951192 0.019899013037081057 0.014864650915170597 0.01131792993973261 0.008851163896473165 0.0068840906035713256 0.005172902766082882 0.0037347489483499086 0.002613715989201994 0.0018108488201475682 0.0012775314669896157 0.0009232854720992062 0.0006692846682037825 0.0005052944369660971 0.0004633564042267045 0.00042623502672549764 0.0006045988410517498 0.0009395915246891086 0.001658940006948027 0.0030673464280526817 0.005320251868544281 0.008535272017550806 0.013311339349175033 0.02042239365493735 0.02901729743471953 0.03552916848266973 0.03654237041029715 0.032628634466063365 0.02704393306599347 0.0218718983991917 0.01729118409880111 0.013205451880473078 0.009966524346444053 0.0077175839492831105 0.0061038190074699 0.004753920712825666 0.0035767109487630324 0.002613715989201989 0.001873168016668069 0.0013339424895266391 0.0009614150171436506 0.0007011280080980819 0.000504257417278921 0.00037385813418756435 0.00034433133417836306 0.0003235039291855663 0.00047878926010504316 0.0007162791068696876 0.0011733734294710814 0.002084923017692904 0.003619078035058615 0.005769895370865575 0.00853527201755081 0.011973630808074344 0.015692722152502878 0.018522657783122468 0.019358270366481176 0.01825942507356671 0.016108051723821827 0.013543651521091864 0.010834126637829363 0.008340585241485126 0.0064390664767518604 0.005121132327984138 0.004098860343354634 0.0031929167216776617 0.0024198593746372035 0.0018108488201475583 0.0013339424895266307 0.0009616996260649233 0.0006872824206897265 0.0004921829205170365 0.00034716672433379454 0.0002543426496727969 0.00024181346590353492 0.0002341423494693413 0.00036504846722241324 0.0005328767055493063 0.0007970905713095705 0.0013144301327347953 0.0022442729591142306 0.003619078035058614 0.005320251868544285 0.007172574512613124 0.008932914694551077 0.010237380254440178 0.010762009478327434 0.01045126621161707 0.009473934063312556 0.008053268662561052 0.006480340695556071 0.005105322245517006 0.004107130107226387 0.0033781442189325475 0.002735257380277427 0.0021391237296633976 0.0016519263713297683 0.0012775314669896006 0.0009614150171436285 0.0006872824206897197 0.0004765515140829215 0.0003328103516603765 0.0002326720717771661 0.00016975481507748181 0.00016417085279852488 0.00015338033482130582 0.00024962684893334476 0.00037463636281233147 0.0005378107763059002 0.0008160465074447749 0.001314430132734793 0.0020849230176929025 0.0030673464280526835 0.00411742695260813 0.005065990398946274 0.005751359337704065 0.006050605342605952 0.0059182585820492005 0.005402100311051648 0.00464066286221451 0.0038416187382218935 0.0031833431333576964 0.002694549901459459 0.002274956069556983 0.0018515398190606307 0.0014604937925648688 0.0011583572591615152 0.000923285472099198 0.0007011280080980804 0.0004921829205170339 0.0003328103516603761 0.00023265115775077984 0.0001670015440471132 0.00012122019196754828 0.00010991083482162482 0.00008836635431708948 0.00014552776986352997 0.00023897829057065525 0.0003644655134322182 0.0005378107763059037 0.000797090571309572 0.0011733734294710817 0.001658940006948032 0.0022044233453669205 0.002725201297860147 0.0031199679870699943 0.003310130795263662 0.003273215902839203 0.0030503657603172065 0.0027284479596148947 0.002399856396544473 0.0021135152535489135 0.0018521698782703049 0.0015723081188700055 0.0012781043115712696 0.001021947872098682 0.0008297072438039245 0.0006692846682037784 0.000504257417278921 0.00034716672433379687 0.0002326720717771706 0.00016700154404711675 0.0001263954198194078 0.00009227334361630623 0.00007319711621452528 0.000049264696090276255 0.00007494986032959826 0.0001366557884733742 0.00023897829057065235 0.0003746363628123325 0.0005328767055493044 0.0007162791068696877 0.0009395915246891099 0.001208736813194831 0.001494949249301126 0.0017355804206419562 0.0018739209437563813 0.00189986054294818 0.0018474983033848612 0.0017585618402871398 0.0016503940612064253 0.0015145682355305657 0.0013402003972896558 0.0011362470259058555 0.0009350204265439838 0.0007668541041885774 0.0006317512268016338 0.0005052944369660918 0.000373858134187557 0.00025434264967279246 0.00016975481507747376 0.00012122019196754444 0.00009227334361630001 0.00006872525418736414 0.00005081018743245576 0.000034944686828870887 0.000042337647069583256 0.00007494986032959736 0.0001455277698635257 0.00024962684893334335 0.000365048467222407 0.00047878926010504224 0.0006045988410517504 0.00076191272657536 0.0009416347748850421 0.001102976451661512 0.0012098210104861356 0.0012632413019571674 0.001288367892250478 0.0012975573945890587 0.0012756356763438054 0.0012018072025311362 0.001081557970226014 0.000944827936921733 0.0008161527036543521 0.0006992403467680993 0.0005841060597842307 0.0004633564042267051 0.0003443313341783655 0.00024181346590353573 0.0001641708527985222 0.00010991083482162347 0.0000731971162145234 0.000050810187432458324 0.00003927679355652013 0.000032996005925251914 0.0000359736558537048 0.000052163891300053764 0.00009296217033426778 0.00015775652622948295 0.00023864228845880053 0.00033441079730572865 0.00044961097665089343 0.0005832294783845744 0.0007212546483763918 0.000848652587863017 0.0009628131037069249 0.001064406485380004 0.0011463175132408777 0.0011986080708773564 0.0012163029673619534 0.0011986080708773598 0.0011463175132408812 0.001064406485380004 0.0009628131037069214 0.000848652587863024 0.0007212546483763918 0.0005832294783845796 0.00044961097665089517 0.00033441079730573125 0.00023864228845880573 0.00015775652622948425 0.00009296217033426995 0.000052163891300056474 0.00003597365585370285 0.000035973655853698894 0.00004246476366109258 0.00005773213817806045 0.00008633426488525599 0.00013107499389271513 0.00019570183389348424 0.0002898163901862272 0.0004144589417778363 0.0005519973573561678 0.0006814304005537411 0.0008039528511211472 0.0009370424568941315 0.0010815579702260286 0.0012123734799485114 0.0013021331758599158 0.0013445560159961215 0.0013517795309755777 0.0013339022226082544 0.001288367892250482 0.001206567029440293 0.0010826685402583543 0.0009218909549822153 0.0007465776724080101 0.0005865215698875149 0.00045571802826237874 0.0003440034197444288 0.00023703570095634776 0.0001400195734721015 0.00007273331620749286 0.00004185228624762219 0.00005216389130005243 0.00005773213817806443 0.0000810872664898346 0.00011571395533526701 0.00016134910101134155 0.0002307361856879122 0.0003431122089624084 0.0004963521413852141 0.0006561523056794473 0.0007970503483696845 0.0009407587239141621 0.0011239034969201755 0.0013402003972896642 0.0015361738697273945 0.001668717292534463 0.00174643221609369 0.0018017261947860278 0.001843635355461522 0.0018474983033848567 0.0017794167978722824 0.001622455124164982 0.0013888305176585195 0.0011191498215588802 0.0008649531896832562 0.0006575346592259384 0.0004938311102070549 0.000353304769537503 0.00022688081584744534 0.00012916539479545104 0.00007273331620749191 0.00009296217033426969 0.0000863342648852617 0.00011571395533526814 0.00016831495554073806 0.00023540318016430938 0.0003324322130755759 0.00048445332287481985 0.0006838316235267722 0.0008835265101450215 0.0010612533502024903 0.001261728621581642 0.0015340316098065904 0.0018521698782702973 0.002134042701198249 0.002344313469709197 0.0025286503275099097 0.0027321864074082367 0.0029314670065587163 0.0030503657603172035 0.003017057632244774 0.0028018161266351945 0.002423979187085864 0.0019465698802292994 0.001460434191919837 0.001044077037541588 0.0007311047369061586 0.0005110280207879603 0.00035024178324874244 0.00022688081584744626 0.0001400195734721025 0.00015775652622948197 0.0001310749938927161 0.00016134910101133735 0.00023540318016430464 0.0003382678508912706 0.0004810140756292363 0.000689547073522208 0.0009554476063526676 0.0012310199292264637 0.0015021101566728239 0.0018252040088143496 0.0022406580347984085 0.002694549901459469 0.0031091760870718367 0.0035057823399257384 0.003975820768717632 0.004534767905786571 0.005066004126662923 0.005402100311051645 0.005421110613354323 0.005081308636276988 0.004422978400784093 0.0035548620122397637 0.002629389801695996 0.0018004153950183035 0.001170272483470394 0.0007582882900205593 0.0005110280207879591 0.00035330476953750086 0.00023703570095634654 0.00023864228845880479 0.0001957018338934891 0.0002307361856879137 0.00033243221307557614 0.0004810140756292422 0.0006826700179281662 0.0009682847789069762 0.0013428023934787061 0.0017735870623411712 0.002250232107860971 0.0028100800161902028 0.0034530126341166274 0.0041071301072264 0.004760328317029637 0.005545206054145711 0.006580579195852483 0.007765271584428247 0.00881924782820553 0.009473934063312555 0.009543175734881951 0.008929833570272596 0.00771043317878115 0.006144054076131459 0.004526188866547983 0.0030756018951073488 0.0019355668732131575 0.0011702724834703943 0.000731104736906158 0.000493831110207054 0.0003440034197444272 0.00033441079730572794 0.00028981639018622874 0.00034311220896240393 0.00048445332287481654 0.0006895470735222085 0.0009682847789069693 0.0013718781379051617 0.0019366624294627377 0.0026549678017238807 0.003504638407223862 0.004462883841154415 0.005460917229675768 0.006439066476751867 0.007521783518469318 0.008986628223726747 0.010916081954214436 0.013006136920165733 0.014842004087681642 0.01610805172382183 0.01641060648739892 0.015326377141967943 0.012938092278920265 0.009977253075154284 0.007194256015802471 0.00488473038532229 0.0030756018951073475 0.0018004153950183 0.0010440770375415847 0.0006575346592259329 0.0004557180282623751 0.00044961097665089495 0.00041445894177783923 0.0004963521413852151 0.0006838316235267734 0.0009554476063526714 0.0013428023934787068 0.0019366624294627453 0.002815159394638278 0.003986452395490249 0.00539124681313098 0.006923153073596429 0.008449495985470208 0.009966524346444048 0.011780429057506363 0.014298536985646175 0.017497979483522694 0.02091321729019589 0.024203110600517837 0.02704393306599346 0.02834584680170842 0.026619531064699158 0.021833526348406383 0.01593390230487787 0.010880890615936683 0.007194256015802466 0.004526188866547979 0.002629389801695993 0.0014604341919198368 0.000864953189683256 0.0005865215698875151 0.0005832294783845783 0.0005519973573561725 0.0006561523056794482 0.0008835265101450294 0.0012310199292264719 0.001773587062341164 0.002654967801723887 0.003986452395490245 0.005761950678317071 0.007869541377713724 0.010148692673302807 0.012455354564246358 0.014864650915170599 0.01784026965500825 0.021878320719838737 0.026874775620886443 0.03239910529167102 0.038440099007273514 0.04456266870809132 0.04815204876374487 0.04551782647970808 0.0363667313100634 0.025055637667848872 0.01593390230487787 0.009977253075154275 0.006144054076131452 0.003554862012239758 0.0019465698802292987 0.0011191498215588783 0.0007465776724080122 0.0007212546483763903 0.0006814304005537394 0.0007970503483696805 0.001061253350202484 0.0015021101566728252 0.002250232107860968 0.0035046384072238593 0.005391246813130978 0.007869541377713719 0.010803241393581728 0.014055945234431346 0.017509967750017324 0.02124810892754824 0.02580412409566322 0.03181122859580151 0.03927144288015321 0.04793840415454884 0.05804858897493287 0.06864617972454859 0.07491270404560922 0.0704676586833634 0.055054691285063385 0.036366731310063405 0.021833526348406393 0.012938092278920255 0.007710433178781145 0.004422978400784085 0.0024239791870858617 0.0013888305176585204 0.0009218909549822121 0.0008486525878630225 0.0008039528511211468 0.0009407587239141552 0.001261728621581644 0.0018252040088143555 0.0028100800161901932 0.004462883841154414 0.0069231530735964246 0.010148692673302798 0.014055945234431346 0.01857724339996579 0.02349789729598116 0.02864968233610658 0.03456537249730393 0.04237773260800204 0.05265480311856309 0.06518714478868116 0.07957358172116913 0.09348758096382306 0.1001822094906155 0.09217668859203686 0.07046765868336341 0.04551782647970808 0.026619531064699165 0.01532637714196793 0.008929833570272593 0.005081308636276981 0.002801816126635195 0.0016224551241649785 0.0010826685402583534 0.0009628131037069264 0.0009370424568941283 0.001123903496920171 0.0015340316098065854 0.002240658034798408 0.0034530126341166343 0.005460917229675771 0.008449495985470208 0.012455354564246362 0.017509967750017327 0.02349789729598116 0.029690429604246067 0.03518834279291235 0.04060359154257608 0.04845800059513082 0.06076976938801451 0.0770637825693041 0.09479720627444045 0.10918928639667483 0.11281644974287011 0.1001822094906155 0.07491270404560921 0.048152048763744876 0.028345846801708426 0.01641060648739891 0.009543175734881948 0.0054211106133543125 0.003017057632244766 0.0017794167978722798 0.0012065670294402894 0.0010644064853800065 0.0010815579702260186 0.0013402003972896607 0.0018521698782702925 0.0026945499014594605 0.004107130107226396 0.006439066476751872 0.00996652434644405 0.0148646509151706 0.021248108927548248 0.028649682336106597 0.03518834279291236 0.03869452315378 0.040180003278377535 0.04470094384614951 0.056677982212078135 0.07545099821496906 0.09562570069848383 0.10931266537743455 0.10918928639667481 0.09348758096382308 0.0686461797245486 0.04456266870809133 0.02704393306599346 0.01610805172382183 0.00947393406331255 0.00540210031105164 0.0030503657603172018 0.0018474983033848523 0.0012883678922504796 0.0011463175132408884 0.0012123734799485092 0.0015361738697273982 0.0021340427011982475 0.003109176087071825 0.004760328317029649 0.007521783518469315 0.011780429057506366 0.01784026965500825 0.025804124095663225 0.03456537249730392 0.04060359154257608 0.04018000327837753 0.035044097630737146 0.03325555919185391 0.04165728956585284 0.05996092486880794 0.08137680617881791 0.09562570069848383 0.09479720627444044 0.0795735817211691 0.05804858897493287 0.0384400990072735 0.024203110600517833 0.01484200408768163 0.008819247828205526 0.005066004126662914 0.0029314670065587116 0.001843635355461519 0.0013339022226082512 0.0011986080708773581 0.0013021331758599122 0.0016687172925344594 0.0023443134697091975 0.003505782339925733 0.005545206054145704 0.008986628223726747 0.014298536985646175 0.021878320719838737 0.031811228595801516 0.042377732608002046 0.04845800059513083 0.04470094384614951 0.033255559191853926 0.024326738604191475 0.0263126367861459 0.040029830238656375 0.059960924868807955 0.07545099821496908 0.07706378256930409 0.06518714478868118 0.04793840415454885 0.03239910529167102 0.020913217290195893 0.013006136920165737 0.007765271584428239 0.004534767905786562 0.002732186407408239 0.0018017261947860207 0.00135177953097557 0.0012163029673619573 0.0013445560159961135 0.0017464322160936929 0.0025286503275099032 0.003975820768717628 0.006580579195852492 0.010916081954214436 0.017497979483522698 0.026874775620886443 0.03927144288015322 0.05265480311856309 0.06076976938801451 0.056677982212078135 0.04165728956585284 0.0263126367861459 0.020232834606957056 0.0263126367861459 0.04165728956585283 0.056677982212078135 0.06076976938801451 0.052654803118563076 0.03927144288015321 0.026874775620886436 0.017497979483522698 0.01091608195421443 0.006580579195852481 0.003975820768717622 0.002528650327509907 0.0017464322160936872 0.0013445560159961129 0.0011986080708773588 0.0013517795309755702 0.0018017261947860254 0.0027321864074082358 0.004534767905786569 0.00776527158442825 0.013006136920165742 0.020913217290195896 0.03239910529167102 0.047938404154548864 0.06518714478868119 0.0770637825693041 0.07545099821496906 0.05996092486880796 0.04002983023865638 0.0263126367861459 0.024326738604191475 0.03325555919185392 0.04470094384614951 0.0484580005951308 0.04237773260800204 0.03181122859580151 0.02187832071983873 0.01429853698564617 0.008986628223726742 0.0055452060541456944 0.003505782339925729 0.002344313469709202 0.0016687172925344538 0.001302133175859911 0.0011463175132408895 0.001333902222608251 0.0018436353554615228 0.0029314670065587094 0.00506600412666292 0.008819247828205536 0.014842004087681635 0.02420311060051783 0.0384400990072735 0.05804858897493286 0.07957358172116911 0.09479720627444044 0.09562570069848385 0.08137680617881793 0.059960924868807955 0.04165728956585284 0.03325555919185391 0.03504409763073714 0.04018000327837753 0.040603591542576076 0.03456537249730392 0.025804124095663225 0.017840269655008248 0.011780429057506365 0.007521783518469311 0.004760328317029643 0.0031091760870718224 0.0021340427011982523 0.0015361738697273939 0.001212373479948507 0.0010644064853800087 0.0012883678922504804 0.0018474983033848569 0.0030503657603172005 0.005402100311051647 0.009473934063312562 0.016108051723821838 0.02704393306599346 0.044562668708091335 0.06864617972454862 0.09348758096382309 0.10918928639667483 0.10931266537743457 0.09562570069848383 0.07545099821496906 0.05667798221207814 0.04470094384614952 0.04018000327837753 0.03869452315377999 0.03518834279291235 0.02864968233610659 0.02124810892754825 0.014864650915170597 0.009966524346444051 0.006439066476751869 0.004107130107226395 0.0026945499014594592 0.0018521698782702968 0.0013402003972896597 0.0010815579702260168 0.0009628131037069289 0.0012065670294402905 0.0017794167978722848 0.0030170576322447644 0.0054211106133543185 0.009543175734881957 0.016410606487398918 0.028345846801708423 0.04815204876374487 0.07491270404560921 0.1001822094906155 0.11281644974287011 0.10918928639667483 0.09479720627444044 0.0770637825693041 0.06076976938801452 0.048458000595130814 0.04060359154257607 0.03518834279291236 0.02969042960424605 0.023497897295981153 0.01750996775001732 0.012455354564246363 0.00844949598547021 0.0054609172296757715 0.0034530126341166378 0.0022406580347984076 0.0015340316098065875 0.0011239034969201733 0.0009370424568941256 0.000848652587863025 0.0010826685402583547 0.0016224551241649844 0.002801816126635193 0.0050813086362769865 0.008929833570272598 0.015326377141967933 0.026619531064699158 0.04551782647970807 0.0704676586833634 0.09217668859203684 0.1001822094906155 0.09348758096382308 0.07957358172116913 0.06518714478868118 0.05265480311856309 0.042377732608002046 0.03456537249730392 0.028649682336106583 0.02349789729598115 0.018577243399965786 0.014055945234431346 0.010148692673302798 0.006923153073596429 0.004462883841154416 0.0028100800161902028 0.0018252040088143555 0.0012617286215816446 0.0009407587239141606 0.0008039528511211438 0.0007212546483763925 0.0009218909549822126 0.0013888305176585263 0.002423979187085859 0.004422978400784089 0.00771043317878115 0.012938092278920264 0.021833526348406383 0.0363667313100634 0.055054691285063365 0.07046765868336341 0.0749127040456092 0.0686461797245486 0.05804858897493285 0.04793840415454885 0.039271442880153204 0.031811228595801516 0.025804124095663208 0.021248108927548245 0.01750996775001732 0.01405594523443134 0.01080324139358173 0.007869541377713722 0.005391246813130982 0.003504638407223863 0.002250232107860981 0.001502110156672826 0.0010612533502024825 0.0007970503483696871 0.0006814304005537366 0.00058322947838458 0.000746577672408013 0.0011191498215588837 0.0019465698802292966 0.0035548620122397606 0.006144054076131457 0.009977253075154282 0.01593390230487787 0.025055637667848858 0.03636673131006339 0.04551782647970807 0.04815204876374487 0.04456266870809133 0.0384400990072735 0.03239910529167102 0.02687477562088644 0.021878320719838733 0.01784026965500824 0.014864650915170599 0.012455354564246356 0.010148692673302796 0.007869541377713719 0.005761950678317072 0.00398645239549025 0.002654967801723893 0.0017735870623411777 0.0012310199292264732 0.0008835265101450278 0.0006561523056794547 0.0005519973573561706 0.00044961097665089717 0.0005865215698875163 0.000864953189683261 0.001460434191919835 0.0026293898016959954 0.004526188866547982 0.007194256015802471 0.01088089061593668 0.015933902304877862 0.021833526348406376 0.02661953106469914 0.028345846801708412 0.02704393306599346 0.024203110600517826 0.020913217290195893 0.017497979483522698 0.014298536985646176 0.01178042905750636 0.009966524346444058 0.008449495985470215 0.0069231530735964315 0.005391246813130981 0.0039864523954902505 0.002815159394638282 0.0019366624294627505 0.00134280239347872 0.000955447606352674 0.0006838316235267718 0.0004963521413852214 0.00041445894177783875 0.0003344107973057303 0.0004557180282623764 0.0006575346592259378 0.0010440770375415831 0.001800415395018303 0.0030756018951073483 0.004884730385322296 0.007194256015802468 0.009977253075154284 0.012938092278920257 0.015326377141967933 0.016410606487398904 0.01610805172382184 0.01484200408768162 0.013006136920165745 0.010916081954214429 0.008986628223726754 0.007521783518469299 0.006439066476751875 0.005460917229675762 0.004462883841154419 0.0035046384072238536 0.0026549678017238907 0.0019366624294627388 0.0013718781379051686 0.0009682847789069788 0.0006895470735222122 0.0004844533228748154 0.00034311220896240984 0.0002898163901862289 0.00023864228845880682 0.0003440034197444283 0.0004938311102070575 0.0007311047369061569 0.001170272483470397 0.0019355668732131573 0.0030756018951073522 0.004526188866547982 0.006144054076131453 0.007710433178781145 0.008929833570272593 0.009543175734881941 0.009473934063312556 0.008819247828205515 0.007765271584428254 0.006580579195852482 0.005545206054145712 0.004760328317029631 0.004107130107226406 0.0034530126341166243 0.002810080016190209 0.002250232107860962 0.0017735870623411712 0.0013428023934787055 0.0009682847789069801 0.0006826700179281745 0.00048101407562924477 0.00033243221307557554 0.00023073618568791878 0.00019570183389348904 0.0001577565262294838 0.00023703570095634765 0.0003533047695375032 0.000511028020787958 0.0007582882900205616 0.0011702724834703933 0.001800415395018304 0.0026293898016959937 0.003554862012239762 0.004422978400784084 0.00508130863627698 0.005421110613354311 0.005402100311051644 0.005066004126662912 0.004534767905786564 0.0039758207687176205 0.003505782339925739 0.0031091760870718167 0.0026945499014594653 0.0022406580347984102 0.001825204008814358 0.0015021101566728239 0.001231019929226468 0.0009554476063526678 0.0006895470735222135 0.0004810140756292449 0.00033826785089127465 0.0002354031801643059 0.00016134910101134255 0.0001310749938927161 0.0000929621703342707 0.00014001957347210364 0.000226880815847447 0.00035024178324874104 0.000511028020787961 0.0007311047369061564 0.0010440770375415858 0.001460434191919838 0.001946569880229296 0.0024239791870858617 0.0028018161266351884 0.003017057632244766 0.0030503657603172005 0.0029314670065587046 0.002732186407408235 0.0025286503275099054 0.0023443134697091997 0.002134042701198249 0.0018521698782702975 0.0015340316098065988 0.0012617286215816487 0.0010612533502024897 0.0008835265101450272 0.0006838316235267771 0.00048445332287482364 0.000332432213075583 0.00023540318016431258 0.00016831495554074018 0.00011571395533527272 0.00008633426488526111 0.0000521638913000531 0.00007273331620749368 0.00012916539479545088 0.00022688081584744388 0.00035330476953750303 0.0004938311102070521 0.0006575346592259355 0.0008649531896832559 0.0011191498215588768 0.0013888305176585221 0.0016224551241649757 0.0017794167978722763 0.001847498303384854 0.0018436353554615113 0.0018017261947860224 0.0017464322160936846 0.001668717292534466 0.0015361738697273822 0.0013402003972896727 0.001123903496920165 0.0009407587239141578 0.0007970503483696752 0.0006561523056794501 0.000496352141385213 0.00034311220896241136 0.00023073618568791667 0.00016134910101134423 0.00011571395533526911 0.00008108726648983891 0.0000577321381780634 0.0000359736558536994 0.000041852286247624316 0.00007273331620749141 0.0001400195734720992 0.0002370357009563469 0.0003440034197444236 0.00045571802826237625 0.0005865215698875139 0.0007465776724080085 0.0009218909549822132 0.0010826685402583515 0.0012065670294402857 0.0012883678922504806 0.0013339022226082475 0.001351779530975571 0.0013445560159961172 0.0013021331758599174 0.001212373479948499 0.0010815579702260138 0.00093704245689413 0.0008039528511211465 0.0006814304005537366 0.0005519973573561686 0.0004144589417778351 0.00028981639018623096 0.00019570183389348871 0.0001310749938927175 0.00008633426488525886 0.00005773213817806459 0.000042464763661091196 0.00003999670548055932 0.00004194324107620925 0.00005534744024333362 0.00009223278715530885 0.00015267581316423333 0.00023234710462510235 0.0003361344573057888 0.0004687949647652241 0.0006197248184155353 0.0007667896670978391 0.0008995969267711901 0.0010223797079019666 0.0011288125431500456 0.0011986080708773633 0.0012264093166083276 0.0012312082497994417 0.0012264093166083284 0.0011986080708773564 0.0011288125431500456 0.001022379707901963 0.0008995969267711866 0.0007667896670978391 0.0006197248184155353 0.0004687949647652293 0.0003361344573057923 0.0002323471046251067 0.00015267581316423594 0.00009223278715531362 0.00005534744024333709 0.0000419432410762138 0.00004194324107621045 0.00004804046316260148 0.00006378627298063483 0.00009660617943874872 0.00014969492195175612 0.0002253991227909354 0.0003349742989234351 0.00048131016516047296 0.0006423483931220762 0.000790059915324492 0.0009248564411887966 0.001064658884371408 0.0012018072025311505 0.0013021331758599247 0.0013490440679071677 0.0013626764404337537 0.0013659066902064606 0.0013517795309755736 0.0012975573945890636 0.0011973429792128596 0.001063363400451896 0.0009055757124909062 0.0007313386636297361 0.0005603349195352478 0.00041543744447833885 0.0003006000119108431 0.0002045318754074718 0.0001238262836215145 0.00006979335205075183 0.000046039876205689693 0.000055347440243336934 0.00006378627298063688 0.00009111223839643769 0.00013678820046357593 0.00020099329412540963 0.00029156831156405653 0.0004273720105761972 0.0006092634042455439 0.0008015254916949723 0.0009705099287999346 0.0011311065461328037 0.0013165680957763454 0.0015145682355305631 0.00166871729253446 0.0017468782307036408 0.0017766517541786208 0.0017963696659219913 0.0018017261947860198 0.0017585618402871457 0.0016478117139200527 0.001477557116689299 0.0012624736503087056 0.0010183403054298311 0.0007774910755573753 0.0005759894400297534 0.00042271980596803396 0.0002999803279416986 0.00019372829236130856 0.00011389516179237384 0.00006979335205075364 0.00009223278715531401 0.00009660617943875155 0.00013678820046357612 0.0002077571576043947 0.00030171519351103134 0.00042942899124734493 0.0006161688271076281 0.0008589568636188337 0.0011094531117226162 0.0013314457145501813 0.001554466242855795 0.0018231338833620415 0.0021135152535489165 0.0023443134697092144 0.0024789141960227918 0.002566043478233661 0.0026569839345356007 0.002732186407408237 0.0027284479596148964 0.0026064943852817223 0.0023697225303135135 0.002038034982836015 0.0016396186116322189 0.0012316737057361758 0.0008828322819483993 0.000624626478730455 0.00044161447486532854 0.00030167391628042883 0.00019372829236130693 0.0001238262836215147 0.00015267581316423556 0.00014969492195175647 0.00020099329412540625 0.00030171519351102874 0.000441706243743836 0.0006333943940810152 0.0009066580400836066 0.0012589495116249138 0.0016351864912215125 0.0019935386997361293 0.00236182702274419 0.002773962381173301 0.0031833431333576964 0.003505782339925747 0.003743027848109884 0.003984092645329029 0.004273017834966269 0.004534767905786567 0.004640662862214501 0.0045106203259402036 0.004139463137881489 0.003565593495754305 0.0028541081215029004 0.0021106035581529665 0.0014590527240740717 0.0009736510857595682 0.0006508099138680069 0.00044161447486532827 0.0002999803279416966 0.00020453187540747167 0.0002323471046251079 0.00022539912279093954 0.0002915683115640583 0.0004294289912473471 0.0006333943940810204 0.0009228985548071653 0.0013400322643710232 0.0018950825958768756 0.0025357859259002285 0.0032019567330937287 0.0038771846297218247 0.004537419787465316 0.005105322245516997 0.005545206054145707 0.005963646198878793 0.006507829512702058 0.007171889765094907 0.007765271584428247 0.008053268662561038 0.007885851634352301 0.007230885503687011 0.006171924531510282 0.004883702047003987 0.0035749591955013815 0.002428407620020926 0.0015553507761918532 0.0009736510857595695 0.0006246264787304561 0.0004227198059680344 0.00030060001191084524 0.0003361344573057928 0.00033497429892343915 0.00042737201057619495 0.0006161688271076298 0.0009066580400836098 0.0013400322643710198 0.00198758547766455 0.0028883717904480146 0.00400116892906043 0.0052257281027493115 0.006443731463249304 0.007517489748370434 0.00834058524148512 0.008986628223726756 0.009724646432491055 0.010754562411234786 0.011961891930324662 0.013006136920165744 0.013543651521091845 0.01330008045064044 0.012128142883813992 0.010174247183974278 0.00787839238406656 0.005688885411737051 0.0038449800445795944 0.002428407620020925 0.0014590527240740728 0.0008828322819484014 0.0005759894400297527 0.00041543744447834226 0.0004687949647652281 0.0004813101651604788 0.000609263404245546 0.0008589568636188386 0.0012589495116249198 0.0018950825958768771 0.002888371790448019 0.004314121678006397 0.0061297089800265965 0.008167517098673105 0.01017912446384884 0.011899632005612589 0.013205451880473076 0.01429853698564618 0.015606687393438875 0.017344440296077856 0.01926204335873081 0.020913217290195896 0.02187189839919169 0.021600447001363175 0.019618811318097888 0.01613095381440367 0.012113170777656666 0.008518072672587643 0.00568888541173705 0.0035749591955013802 0.0021106035581529648 0.0012316737057361771 0.0007774910755573744 0.0005603349195352502 0.0006197248184155348 0.0006423483931220795 0.0008015254916949697 0.001109453111722621 0.0016351864912215206 0.0025357859259002268 0.0040011689290604365 0.006129708980026595 0.00883984502253302 0.011889215069225812 0.014947087410735697 0.017670886976566998 0.019899013037081064 0.02187832071983874 0.024131797236828956 0.026888939960480213 0.02981367918904268 0.032399105291671025 0.034073916820984464 0.03380867422689517 0.03055005990547198 0.02460864991473567 0.01786507350603816 0.012113170777656666 0.007878392384066556 0.004883702047003983 0.0028541081215028965 0.001639618611632219 0.0010183403054298285 0.0007313386636297397 0.0007667896670978398 0.0007900599153244995 0.000970509928799941 0.0013314457145501824 0.001993538699736137 0.0032019567330937313 0.005225728102749311 0.008167517098673107 0.011889215069225805 0.01612544317183192 0.020572286992175948 0.02483327612429591 0.028546983150662533 0.03181122859580152 0.03526993486347837 0.03939450951957952 0.04387607687253016 0.047938404154548864 0.05049130493715688 0.04979656952952349 0.04435217915922053 0.03492861208914283 0.024608649914735676 0.016130953814403676 0.010174247183974276 0.006171924531510285 0.003565593495754305 0.0020380349828360176 0.001262473650308706 0.0009055757124909114 0.0008995969267711873 0.0009248564411888047 0.0011311065461328041 0.0015544662428558025 0.002361827022744199 0.003877184629721822 0.00644373146324931 0.010179124463848834 0.014947087410735692 0.02057228699217595 0.026834614134389638 0.03308671725470337 0.038346863226476936 0.04237773260800205 0.046399195810044425 0.05188798945407266 0.05874562097273792 0.06518714478868119 0.0686677388716615 0.06659102873504197 0.057800888093262906 0.044352179159220545 0.030550059905471983 0.0196188113180979 0.012128142883813994 0.007230885503687014 0.004139463137881493 0.0023697225303135213 0.0014775571166893006 0.0010633634004519035 0.001022379707901968 0.0010646588843714 0.0013165680957763451 0.0018231338833620346 0.002773962381173299 0.004537419787465314 0.007517489748370424 0.011899632005612582 0.017670886976566984 0.024833276124295905 0.03308671725470335 0.0409670487024712 0.04623882046826718 0.04845800059513082 0.050617921720315505 0.056542570270603554 0.06663205520314516 0.0770637825693041 0.08242112353905497 0.0788799121953625 0.06659102873504197 0.04979656952952349 0.03380867422689519 0.02160044700136319 0.013300080450640444 0.007885851634352306 0.004510620325940199 0.00260649438528173 0.0016478117139200575 0.0011973429792128667 0.0011288125431500495 0.001201807202531153 0.0015145682355305722 0.0021135152535489217 0.0031833431333577037 0.005105322245517002 0.008340585241485126 0.013205451880473076 0.019899013037081057 0.028546983150662533 0.03834686322647694 0.04623882046826719 0.048297021958774146 0.04470094384614951 0.041758922589336805 0.04637859083505481 0.05954917846784604 0.07545099821496906 0.08510319364006402 0.08242112353905497 0.06866773887166151 0.05049130493715689 0.03407391682098448 0.021871898399191698 0.01354365152109185 0.008053268662561038 0.0046406628622145 0.0027284479596149064 0.001758561840287144 0.0012975573945890712 0.0011986080708773577 0.001302133175859918 0.001668717292534464 0.002344313469709205 0.003505782339925739 0.005545206054145707 0.008986628223726749 0.014298536985646176 0.021878320719838727 0.03181122859580151 0.04237773260800204 0.04845800059513082 0.044700943846149505 0.033255559191853926 0.024326738604191468 0.0263126367861459 0.040029830238656375 0.05996092486880796 0.07545099821496908 0.07706378256930412 0.06518714478868118 0.047938404154548864 0.032399105291671025 0.020913217290195903 0.01300613692016574 0.007765271584428246 0.004534767905786566 0.0027321864074082427 0.0018017261947860228 0.0013517795309755769 0.0012264093166083308 0.001349044067907171 0.0017468782307036416 0.002478914196022795 0.003743027848109888 0.005963646198878789 0.009724646432491053 0.015606687393438871 0.02413179723682895 0.035269934863478375 0.046399195810044425 0.050617921720315505 0.0417589225893368 0.024326738604191475 0.011332167747017898 0.010166722672810909 0.020571592507962828 0.04002983023865639 0.05954917846784606 0.06663205520314516 0.058745620972737944 0.043876076872530166 0.02981367918904269 0.019262043358730812 0.01196189193032467 0.007171889765094905 0.004273017834966266 0.0026569839345356077 0.0017963696659219878 0.001365906690206463 0.0012312082497994408 0.0013626764404337526 0.0017766517541786245 0.0025660434782336606 0.003984092645329023 0.006507829512702059 0.010754562411234778 0.017344440296077852 0.026888939960480206 0.03939450951957951 0.05188798945407265 0.05654257027060354 0.0463785908350548 0.0263126367861459 0.010166722672810907 0.004844895108568839 0.01016672267281091 0.026312636786145913 0.04637859083505483 0.056542570270603554 0.051887989454072664 0.03939450951957952 0.026888939960480213 0.01734444029607786 0.010754562411234783 0.006507829512702056 0.00398409264532902 0.0025660434782336632 0.0017766517541786201 0.0013626764404337526 0.0012264093166083304 0.001365906690206462 0.001796369665921992 0.002656983934535607 0.00427301783496627 0.007171889765094909 0.011961891930324667 0.019262043358730805 0.029813679189042677 0.04387607687253016 0.05874562097273793 0.06663205520314515 0.05954917846784603 0.040029830238656375 0.020571592507962828 0.01016672267281091 0.0113321677470179 0.024326738604191486 0.041758922589336826 0.050617921720315505 0.04639919581004443 0.035269934863478375 0.024131797236828956 0.015606687393438875 0.009724646432491057 0.005963646198878786 0.003743027848109887 0.0024789141960227974 0.0017468782307036366 0.0013490440679071708 0.0011986080708773572 0.0013517795309755743 0.001801726194786027 0.0027321864074082423 0.00453476790578657 0.0077652715844282495 0.013006136920165737 0.020913217290195893 0.03239910529167101 0.04793840415454885 0.06518714478868116 0.07706378256930409 0.07545099821496906 0.059960924868807955 0.040029830238656375 0.026312636786145902 0.024326738604191475 0.03325555919185394 0.044700943846149525 0.04845800059513082 0.042377732608002046 0.031811228595801516 0.021878320719838737 0.014298536985646183 0.008986628223726754 0.005545206054145706 0.003505782339925738 0.0023443134697092075 0.0016687172925344586 0.0013021331758599178 0.0011288125431500493 0.0012975573945890684 0.0017585618402871498 0.0027284479596149064 0.004640662862214506 0.008053268662561045 0.013543651521091852 0.021871898399191694 0.03407391682098447 0.05049130493715688 0.0686677388716615 0.08242112353905495 0.08510319364006401 0.07545099821496906 0.05954917846784605 0.046378590835054814 0.04175892258933681 0.044700943846149525 0.04829702195877417 0.04623882046826719 0.03834686322647695 0.028546983150662536 0.019899013037081064 0.013205451880473083 0.008340585241485128 0.005105322245517002 0.003183343133357703 0.002113515253548923 0.0015145682355305686 0.0012018072025311534 0.0010223797079019674 0.0011973429792128624 0.0016478117139200634 0.0026064943852817293 0.004510620325940204 0.007885851634352313 0.013300080450640447 0.021600447001363186 0.03380867422689518 0.049796569529523486 0.06659102873504195 0.07887991219536249 0.08242112353905497 0.0770637825693041 0.06663205520314515 0.056542570270603554 0.05061792172031551 0.04845800059513083 0.0462388204682672 0.040967048702471184 0.03308671725470336 0.0248332761242959 0.01767088697656699 0.011899632005612584 0.007517489748370427 0.004537419787465315 0.002773962381173298 0.0018231338833620333 0.0013165680957763434 0.0010646588843713995 0.0008995969267711865 0.0010633634004518985 0.0014775571166893067 0.0023697225303135204 0.004139463137881498 0.00723088550368702 0.012128142883813997 0.0196188113180979 0.030550059905471983 0.04435217915922054 0.05780088809326291 0.06659102873504197 0.0686677388716615 0.06518714478868118 0.05874562097273793 0.05188798945407266 0.04639919581004443 0.04237773260800205 0.03834686322647695 0.03308671725470335 0.02683461413438964 0.020572286992175948 0.014947087410735692 0.010179124463848837 0.0064437314632493125 0.003877184629721826 0.0023618270227441967 0.0015544662428557997 0.0011311065461328052 0.0009248564411888041 0.0007667896670978386 0.0009055757124909058 0.0012624736503087115 0.0020380349828360168 0.003565593495754311 0.006171924531510292 0.010174247183974281 0.01613095381440368 0.02460864991473568 0.03492861208914283 0.044352179159220545 0.04979656952952349 0.05049130493715689 0.04793840415454885 0.043876076872530166 0.03939450951957951 0.035269934863478375 0.03181122859580151 0.02854698315066254 0.024833276124295894 0.02057228699217595 0.01612544317183192 0.011889215069225805 0.00816751709867311 0.005225728102749314 0.0032019567330937356 0.0019935386997361345 0.0013314457145501776 0.0009705099287999437 0.0007900599153244978 0.000619724818415533 0.0007313386636297341 0.0010183403054298322 0.001639618611632219 0.002854108121502902 0.004883702047003991 0.007878392384066561 0.012113170777656673 0.017865073506038165 0.024608649914735683 0.030550059905471987 0.033808674226895194 0.03407391682098448 0.032399105291671025 0.029813679189042687 0.026888939960480213 0.024131797236828956 0.021878320719838733 0.019899013037081064 0.017670886976566977 0.014947087410735693 0.011889215069225809 0.008839845022533018 0.0061297089800265965 0.004001168929060437 0.0025357859259002324 0.0016351864912215162 0.0011094531117226169 0.0008015254916949728 0.0006423483931220777 0.00046879496476522623 0.0005603349195352449 0.0007774910755573767 0.0012316737057361774 0.0021106035581529704 0.0035749591955013876 0.005688885411737053 0.00851807267258765 0.012113170777656668 0.01613095381440368 0.0196188113180979 0.02160044700136319 0.021871898399191705 0.020913217290195896 0.01926204335873081 0.017344440296077856 0.015606687393438875 0.014298536985646173 0.013205451880473075 0.011899632005612577 0.010179124463848832 0.008167517098673107 0.0061297089800265965 0.004314121678006401 0.0028883717904480202 0.001895082595876883 0.0012589495116249157 0.0008589568636188347 0.0006092634042455493 0.0004813101651604771 0.000336134457305791 0.0004154374444783369 0.0005759894400297541 0.0008828322819484011 0.0014590527240740782 0.002428407620020931 0.0038449800445796004 0.005688885411737055 0.007878392384066566 0.010174247183974281 0.01212814288381401 0.013300080450640444 0.013543651521091864 0.013006136920165737 0.011961891930324674 0.010754562411234776 0.009724646432491062 0.008986628223726744 0.00834058524148513 0.007517489748370415 0.006443731463249307 0.005225728102749303 0.004001168929060433 0.002888371790448015 0.001987585477664553 0.0013400322643710248 0.0009066580400836072 0.0006161688271076264 0.00042737201057619793 0.000334974298923437 0.0002323471046251049 0.0003006000119108392 0.00042271980596803326 0.0006246264787304549 0.0009736510857595731 0.0015553507761918578 0.0024284076200209305 0.003574959195501386 0.004883702047003992 0.006171924531510288 0.00723088550368703 0.007885851634352308 0.008053268662561053 0.007765271584428246 0.007171889765094913 0.006507829512702053 0.0059636461988787975 0.005545206054145702 0.005105322245517006 0.004537419787465301 0.0038771846297218273 0.003201956733093727 0.0025357859259002285 0.0018950825958768765 0.001340032264371024 0.00092289855480717 0.0006333943940810176 0.0004294289912473436 0.0002915683115640592 0.00022539912279093697 0.00015267581316423255 0.00020453187540746544 0.00029998032794169375 0.00044161447486532556 0.0006508099138680083 0.00097365108575957 0.0014590527240740745 0.0021106035581529665 0.0028541081215029025 0.003565593495754309 0.0041394631378815 0.004510620325940205 0.004640662862214508 0.00453476790578657 0.00427301783496627 0.003984092645329021 0.0037430278481098895 0.0035057823399257354 0.0031833431333577003 0.0027739623811732896 0.002361827022744194 0.0019935386997361393 0.0016351864912215151 0.0012589495116249161 0.0009066580400836086 0.0006333943940810198 0.0004417062437438339 0.00030171519351102603 0.00020099329412540682 0.00014969492195175427 0.00009223278715531097 0.00012382628362150806 0.0001937282923613028 0.0003016739162804245 0.00044161447486532724 0.0006246264787304542 0.0008828322819483994 0.0012316737057361765 0.0016396186116322182 0.0020380349828360163 0.0023697225303135187 0.002606494385281733 0.002728447959614904 0.0027321864074082423 0.002656983934535601 0.0025660434782336637 0.002478914196022798 0.002344313469709213 0.0021135152535489104 0.0018231338833620283 0.001554466242855799 0.001331445714550186 0.0011094531117226162 0.0008589568636188372 0.0006161688271076303 0.00042942899124735 0.00030171519351103037 0.00020775715760439344 0.00013678820046357677 0.00009660617943875017 0.000055347440243335036 0.00006979335205074744 0.00011389516179236943 0.00019372829236130284 0.00029998032794169635 0.0004227198059680317 0.0005759894400297524 0.0007774910755573735 0.0010183403054298322 0.001262473650308705 0.001477557116689308 0.001647811713920054 0.0017585618402871479 0.0018017261947860198 0.001796369665921989 0.001776651754178623 0.0017468782307036427 0.0016687172925344555 0.0015145682355305608 0.0013165680957763323 0.0011311065461327978 0.0009705099287999334 0.0008015254916949723 0.0006092634042455428 0.0004273720105761982 0.00029156831156406006 0.00020099329412540985 0.00013678820046357583 0.00009111223839643924 0.00006378627298063754 0.00004194324107620964 0.000046039876205684096 0.0000697933520507481 0.0001238262836215087 0.00020453187540746804 0.00030060001191083906 0.0004154374444783353 0.0005603349195352435 0.0007313386636297372 0.0009055757124909016 0.001063363400451899 0.0011973429792128626 0.001297557394589067 0.0013517795309755784 0.0013659066902064567 0.001362676440433754 0.0013490440679071708 0.0013021331758599152 0.0012018072025311458 0.0010646588843713888 0.0009248564411887988 0.0007900599153244912 0.0006423483931220755 0.0004813101651604767 0.0003349742989234382 0.00022539912279093976 0.0001496949219517583 0.00009660617943875134 0.00006378627298063758 0.000048040463162604035 0.000044783155923660764 0.00004589492550741451 0.00005704904950990799 0.00009102652667143164 0.00014878985649779573 0.00022768469543646462 0.00033520299743253386 0.00047649579205626645 0.0006368373327308805 0.000789716228224515 0.0009254338743022519 0.0010503100328411868 0.0011553897450836334 0.0012163029673619569 0.0012312082497994443 0.0012297430304380862 0.0012312082497994425 0.0012163029673619603 0.00115538974508363 0.00105031003284118 0.0009254338743022519 0.0007897162282245115 0.0006368373327308822 0.0004764957920562682 0.0003352029974325347 0.0002276846954364642 0.00014878985649779573 0.00009102652667143185 0.000057049049509906254 0.00004589492550742037 0.00004589492550741781 0.000050287544943846146 0.00006774528075202411 0.00010792134312512247 0.00017215285754228543 0.0002578894038511502 0.0003744675104934129 0.0005287625121494359 0.0007038565058097163 0.0008701737083641837 0.0010189283889044795 0.0011579051791739715 0.00127563567634381 0.0013445560159961218 0.001362676440433758 0.0013618288308587564 0.0013626764404337545 0.0013445560159961233 0.001275635676343808 0.0011579051791739661 0.001018928388904478 0.0008701737083641796 0.0007038565058097175 0.0005287625121494382 0.00037446751049341275 0.0002578894038511497 0.00017215285754228383 0.00010792134312512308 0.00006774528075202235 0.000050287544943851215 0.00005704904950991015 0.00006774528075202443 0.0001009865955692126 0.00016080406028930728 0.0002445948996790621 0.00035198131564532917 0.0004998642579464946 0.0006972250267069883 0.0009190083262633714 0.0011270689633863403 0.001314527940152116 0.0014941165032954563 0.0016503940612064305 0.0017464322160936927 0.0017766517541786299 0.0017783579871622375 0.0017766517541786288 0.0017464322160936948 0.0016503940612064333 0.0014941165032954537 0.0013145279401521124 0.0011270689633863362 0.0009190083262633731 0.0006972250267069906 0.0004998642579464931 0.0003519813156453275 0.00024459489967905966 0.00016080406028930741 0.00010098659556921097 0.00006774528075202789 0.00009102652667143248 0.00010792134312512293 0.000160804060289307 0.0002493944217476876 0.00036669495389843977 0.0005209896395607595 0.0007402030304244075 0.0010319639807374735 0.001356002967794804 0.0016584905708846658 0.0019295502396633488 0.0021839809405514625 0.0023998563965444797 0.0025286503275099123 0.002566043478233661 0.002566554332134203 0.0025660434782336615 0.0025286503275099154 0.0023998563965444823 0.002183980940551458 0.0019295502396633505 0.0016584905708846645 0.0013560029677948083 0.0010319639807374755 0.0007402030304244066 0.000520989639560759 0.0003666949538984376 0.0002493944217476875 0.00016080406028930576 0.00010792134312512529 0.0001487898564977942 0.00017215285754228278 0.00024459489967905727 0.00036669495389843624 0.0005404671613561396 0.0007900615193276627 0.0011543632072385755 0.0016385034701410658 0.002180842443607051 0.0026987296766766296 0.0031582873446044657 0.003552837721414823 0.003841618738221895 0.003975820768717631 0.0039840926453290244 0.003967720801133174 0.003984092645329026 0.003975820768717638 0.0038416187382218974 0.00355283772141482 0.0031582873446044635 0.002698729676676628 0.0021808424436070535 0.001638503470141067 0.0011543632072385747 0.0007900615193276616 0.0005404671613561377 0.00036669495389843635 0.000244594899679056 0.00017215285754228435 0.00022768469543646446 0.0002578894038511495 0.00035198131564532733 0.0005209896395607585 0.0007900615193276649 0.0012072437313161246 0.0018268018963580805 0.0026546496802874794 0.003610843325070015 0.004570037806178964 0.005425288999380871 0.006089358996347642 0.006480340695556085 0.0065805791958524875 0.006507829512702066 0.00645248231672743 0.006507829512702066 0.006580579195852489 0.006480340695556085 0.006089358996347637 0.005425288999380869 0.004570037806178958 0.0036108433250700155 0.0026546496802874802 0.0018268018963580766 0.0012072437313161224 0.000790061519327663 0.0005209896395607582 0.0003519813156453257 0.00025788940385115084 0.0003352029974325342 0.00037446751049341167 0.000499864257946491 0.0007402030304244071 0.0011543632072385773 0.0018268018963580781 0.0028340466119817415 0.00419281545486429 0.005824229496243895 0.007546972735349735 0.009106667450547144 0.010250489182735962 0.010834126637829372 0.010916081954214438 0.010754562411234781 0.010655259614595916 0.010754562411234781 0.010916081954214443 0.010834126637829372 0.01025048918273596 0.00910666745054715 0.0075469727353497315 0.005824229496243898 0.004192815454864293 0.0028340466119817394 0.0018268018963580766 0.0011543632072385755 0.0007402030304244069 0.0004998642579464891 0.00037446751049341346 0.0004764957920562704 0.0005287625121494359 0.000697225026706989 0.001031963980737476 0.0016385034701410692 0.0026546496802874815 0.004192815454864293 0.006298943931691479 0.008910303039589455 0.011767808214400974 0.014399348124765444 0.016313578902386976 0.017291184098801114 0.017497979483522698 0.01734444029607786 0.01723676140359565 0.01734444029607786 0.017497979483522705 0.017291184098801114 0.016313578902386973 0.014399348124765447 0.011767808214400967 0.008910303039589456 0.00629894393169148 0.004192815454864289 0.002654649680287479 0.001638503470141067 0.0010319639807374757 0.000697225026706987 0.0005287625121494373 0.0006368373327308822 0.0007038565058097156 0.0009190083262633688 0.0013560029677948083 0.0021808424436070535 0.003610843325070015 0.005824229496243899 0.008910303039589453 0.01281726508027634 0.017197117076335006 0.021340499097863345 0.024476616453336104 0.026250381929511925 0.026874775620886446 0.026888939960480217 0.026820140023580078 0.026888939960480217 0.026874775620886443 0.026250381929511925 0.0244766164533361 0.021340499097863348 0.017197117076335002 0.012817265080276344 0.008910303039589455 0.005824229496243893 0.0036108433250700124 0.002180842443607051 0.0013560029677948083 0.0009190083262633667 0.0007038565058097168 0.0007897162282245146 0.0008701737083641763 0.0011270689633863357 0.0016584905708846623 0.002698729676676625 0.004570037806178961 0.007546972735349731 0.01176780821440097 0.017197117076335 0.023456863469955676 0.029682723819807397 0.034771922171507014 0.03796747156086694 0.03927144288015322 0.03939450951957952 0.039285425289338295 0.03939450951957952 0.03927144288015322 0.03796747156086694 0.03477192217150701 0.029682723819807397 0.023456863469955673 0.017197117076335002 0.011767808214400974 0.007546972735349726 0.0045700378061789585 0.002698729676676622 0.001658490570884663 0.0011270689633863333 0.0008701737083641769 0.0009254338743022539 0.0010189283889044823 0.001314527940152108 0.001929550239663355 0.0031582873446044666 0.0054252889993808675 0.00910666745054715 0.014399348124765442 0.021340499097863338 0.0296827238198074 0.038554716696971615 0.04632166075690754 0.051225832259196635 0.0526548031185631 0.05188798945407265 0.05123786746513384 0.05188798945407265 0.0526548031185631 0.051225832259196635 0.04632166075690754 0.038554716696971615 0.029682723819807397 0.021340499097863345 0.014399348124765446 0.009106667450547145 0.005425288999380865 0.0031582873446044627 0.001929550239663356 0.0013145279401521055 0.001018928388904483 0.0010503100328411823 0.0011579051791739618 0.0014941165032954513 0.0021839809405514578 0.0035528377214148195 0.006089358996347642 0.01025048918273596 0.016313578902386976 0.0244766164533361 0.03477192217150701 0.04632166075690754 0.05648559203452079 0.06174413796773679 0.06076976938801452 0.056542570270603554 0.054270952519896845 0.056542570270603554 0.06076976938801452 0.0617441379677368 0.05648559203452079 0.04632166075690754 0.03477192217150701 0.024476616453336104 0.016313578902386976 0.010250489182735955 0.00608935899634764 0.0035528377214148147 0.0021839809405514586 0.001494116503295449 0.0011579051791739633 0.0011553897450836354 0.0012756356763438071 0.0016503940612064335 0.00239985639654448 0.0038416187382219013 0.006480340695556083 0.010834126637829376 0.01729118409880111 0.026250381929511922 0.037967471560866946 0.05122583225919664 0.06174413796773679 0.06391931164200328 0.05667798221207814 0.046378590835054814 0.04168268473527755 0.046378590835054814 0.05667798221207814 0.06391931164200328 0.06174413796773678 0.05122583225919664 0.03796747156086694 0.026250381929511922 0.01729118409880111 0.01083412663782937 0.006480340695556081 0.0038416187382218974 0.0023998563965444814 0.0016503940612064315 0.0012756356763438093 0.0012163029673619577 0.0013445560159961183 0.0017464322160936976 0.00252865032750991 0.003975820768717635 0.0065805791958524935 0.01091608195421444 0.0174979794835227 0.026874775620886436 0.03927144288015322 0.05265480311856309 0.06076976938801452 0.05667798221207815 0.04165728956585284 0.0263126367861459 0.02023283460695706 0.026312636786145902 0.041657289565852844 0.05667798221207815 0.060769769388014525 0.05265480311856308 0.03927144288015322 0.02687477562088644 0.017497979483522705 0.010916081954214438 0.006580579195852493 0.003975820768717632 0.002528650327509912 0.0017464322160936968 0.001344556015996121 0.0012312082497994432 0.0013626764404337521 0.0017766517541786266 0.002566043478233662 0.003984092645329028 0.006507829512702059 0.010754562411234783 0.017344440296077856 0.026888939960480217 0.03939450951957952 0.051887989454072664 0.056542570270603554 0.04637859083505482 0.026312636786145902 0.010166722672810914 0.004844895108568841 0.010166722672810916 0.026312636786145906 0.046378590835054814 0.056542570270603554 0.05188798945407266 0.03939450951957952 0.026888939960480213 0.01734444029607786 0.010754562411234781 0.0065078295127020585 0.003984092645329024 0.002566043478233663 0.0017766517541786258 0.001362676440433755 0.0012297430304380873 0.0013618288308587492 0.0017783579871622351 0.0025665543321341973 0.003967720801133173 0.006452482316727433 0.010655259614595913 0.017236761403595646 0.026820140023580075 0.03928542528933829 0.05123786746513384 0.05427095251989684 0.041682684735277545 0.02023283460695706 0.0048448951085688415 0.00038991590232485655 0.004844895108568843 0.020232834606957063 0.041682684735277545 0.05427095251989684 0.05123786746513384 0.03928542528933829 0.026820140023580075 0.017236761403595646 0.010655259614595913 0.006452482316727432 0.0039677208011331695 0.0025665543321341977 0.0017783579871622338 0.0013618288308587514 0.0012312082497994434 0.0013626764404337526 0.001776651754178626 0.002566043478233663 0.003984092645329028 0.006507829512702059 0.010754562411234785 0.017344440296077856 0.026888939960480213 0.03939450951957952 0.051887989454072664 0.056542570270603554 0.046378590835054814 0.026312636786145902 0.010166722672810912 0.004844895108568844 0.010166722672810914 0.026312636786145906 0.04637859083505482 0.05654257027060355 0.05188798945407266 0.03939450951957951 0.026888939960480217 0.017344440296077856 0.010754562411234781 0.006507829512702059 0.003984092645329025 0.0025660434782336632 0.0017766517541786234 0.0013626764404337539 0.0012163029673619577 0.0013445560159961187 0.0017464322160936966 0.002528650327509911 0.003975820768717636 0.0065805791958524935 0.01091608195421444 0.017497979483522698 0.026874775620886436 0.03927144288015322 0.05265480311856308 0.06076976938801452 0.05667798221207815 0.041657289565852844 0.026312636786145902 0.02023283460695706 0.0263126367861459 0.04165728956585284 0.05667798221207814 0.06076976938801452 0.05265480311856309 0.03927144288015321 0.026874775620886443 0.017497979483522705 0.01091608195421444 0.006580579195852494 0.003975820768717634 0.0025286503275099115 0.0017464322160936929 0.0013445560159961191 0.0011553897450836358 0.0012756356763438078 0.001650394061206434 0.002399856396544481 0.0038416187382219013 0.006480340695556084 0.010834126637829376 0.01729118409880111 0.026250381929511922 0.037967471560866946 0.05122583225919665 0.06174413796773679 0.06391931164200328 0.05667798221207814 0.04637859083505482 0.04168268473527755 0.046378590835054814 0.05667798221207815 0.06391931164200328 0.061744137967736784 0.05122583225919664 0.03796747156086694 0.026250381929511925 0.017291184098801114 0.010834126637829376 0.006480340695556085 0.003841618738221901 0.0023998563965444814 0.0016503940612064296 0.0012756356763438076 0.0010503100328411825 0.0011579051791739618 0.0014941165032954535 0.0021839809405514565 0.003552837721414818 0.006089358996347644 0.01025048918273596 0.016313578902386976 0.0244766164533361 0.03477192217150701 0.04632166075690754 0.05648559203452079 0.0617441379677368 0.06076976938801452 0.056542570270603554 0.054270952519896845 0.056542570270603554 0.060769769388014525 0.06174413796773679 0.05648559203452078 0.04632166075690754 0.034771922171507 0.024476616453336104 0.016313578902386973 0.01025048918273596 0.006089358996347645 0.003552837721414818 0.002183980940551457 0.00149411650329545 0.0011579051791739613 0.0009254338743022545 0.0010189283889044814 0.0013145279401521126 0.0019295502396633531 0.0031582873446044657 0.00542528899938087 0.009106667450547149 0.014399348124765442 0.02134049909786334 0.029682723819807397 0.038554716696971615 0.04632166075690754 0.051225832259196635 0.05265480311856309 0.05188798945407266 0.051237867465133834 0.05188798945407266 0.0526548031185631 0.051225832259196635 0.04632166075690753 0.038554716696971615 0.029682723819807397 0.021340499097863345 0.014399348124765444 0.009106667450547154 0.005425288999380872 0.003158287344604467 0.001929550239663354 0.0013145279401521103 0.0010189283889044823 0.0007897162282245153 0.0008701737083641748 0.0011270689633863414 0.0016584905708846597 0.0026987296766766244 0.004570037806178963 0.007546972735349732 0.01176780821440097 0.017197117076335002 0.023456863469955666 0.0296827238198074 0.03477192217150701 0.037967471560866946 0.03927144288015321 0.039394509519579526 0.039285425289338295 0.039394509519579526 0.03927144288015321 0.037967471560866946 0.034771922171507 0.0296827238198074 0.023456863469955666 0.017197117076335006 0.011767808214400969 0.007546972735349735 0.004570037806178965 0.0026987296766766253 0.0016584905708846606 0.00112706896338634 0.0008701737083641767 0.0006368373327308828 0.0007038565058097144 0.0009190083262633745 0.001356002967794806 0.0021808424436070527 0.003610843325070017 0.005824229496243899 0.008910303039589456 0.012817265080276342 0.017197117076335002 0.021340499097863345 0.024476616453336108 0.02625038192951193 0.026874775620886443 0.026888939960480217 0.026820140023580078 0.026888939960480217 0.026874775620886443 0.02625038192951193 0.024476616453336104 0.021340499097863348 0.017197117076335002 0.012817265080276344 0.008910303039589456 0.005824229496243902 0.00361084332507002 0.0021808424436070535 0.001356002967794807 0.0009190083262633733 0.0007038565058097171 0.0004764957920562713 0.0005287625121494352 0.0006972250267069946 0.0010319639807374744 0.0016385034701410686 0.0026546496802874846 0.004192815454864295 0.0062989439316914805 0.008910303039589456 0.011767808214400972 0.014399348124765444 0.01631357890238698 0.017291184098801118 0.0174979794835227 0.01734444029607786 0.01723676140359565 0.01734444029607786 0.017497979483522705 0.017291184098801118 0.016313578902386976 0.014399348124765447 0.01176780821440097 0.008910303039589456 0.006298943931691482 0.004192815454864296 0.0026546496802874863 0.0016385034701410694 0.0010319639807374753 0.000697225026706993 0.0005287625121494383 0.0003352029974325353 0.0003744675104934115 0.000499864257946496 0.0007402030304244057 0.0011543632072385783 0.0018268018963580805 0.0028340466119817454 0.004192815454864291 0.0058242294962438995 0.00754697273534973 0.009106667450547154 0.010250489182735956 0.010834126637829379 0.010916081954214429 0.010754562411234786 0.010655259614595906 0.010754562411234795 0.010916081954214434 0.01083412663782938 0.010250489182735953 0.009106667450547156 0.007546972735349725 0.0058242294962439 0.004192815454864291 0.0028340466119817463 0.0018268018963580818 0.0011543632072385786 0.0007402030304244063 0.0004998642579464938 0.0003744675104934143 0.0002276846954364653 0.00025788940385114884 0.0003519813156453309 0.0005209896395607575 0.0007900615193276649 0.0012072437313161264 0.001826801896358081 0.00265464968028748 0.0036108433250700176 0.0045700378061789585 0.005425288999380871 0.006089358996347638 0.006480340695556088 0.006580579195852483 0.0065078295127020645 0.0064524823167274245 0.006507829512702066 0.006580579195852487 0.006480340695556086 0.006089358996347634 0.005425288999380871 0.004570037806178954 0.0036108433250700176 0.002654649680287479 0.0018268018963580812 0.0012072437313161266 0.0007900615193276653 0.0005209896395607576 0.00035198131564532896 0.00025788940385115165 0.00014878985649779492 0.0001721528575422823 0.00024459489967905976 0.00036669495389843597 0.0005404671613561393 0.0007900615193276644 0.0011543632072385777 0.001638503470141066 0.002180842443607053 0.0026987296766766253 0.0031582873446044657 0.0035528377214148173 0.0038416187382218983 0.003975820768717629 0.003984092645329028 0.0039677208011331695 0.0039840926453290305 0.003975820768717629 0.0038416187382218922 0.0035528377214148134 0.003158287344604466 0.0026987296766766236 0.002180842443607054 0.0016385034701410668 0.0011543632072385775 0.0007900615193276644 0.0005404671613561405 0.0003666949538984363 0.00024459489967905857 0.00017215285754228514 0.00009102652667143261 0.00010792134312512213 0.00016080406028930844 0.0002493944217476872 0.00036669495389843895 0.0005209896395607608 0.0007402030304244087 0.0010319639807374746 0.0013560029677948037 0.0016584905708846652 0.0019295502396633525 0.0021839809405514677 0.0023998563965444814 0.0025286503275099097 0.002566043478233659 0.002566554332134203 0.002566043478233664 0.0025286503275099128 0.0023998563965444823 0.0021839809405514634 0.0019295502396633527 0.0016584905708846628 0.001356002967794807 0.0010319639807374764 0.0007402030304244089 0.0005209896395607609 0.00036669495389844036 0.00024939442174768723 0.0001608040602893073 0.00010792134312512541 0.00005704904950991022 0.00006774528075202357 0.00010098659556921375 0.00016080406028930752 0.0002445948996790608 0.0003519813156453298 0.0004998642579464958 0.0006972250267069905 0.0009190083262633712 0.0011270689633863375 0.0013145279401521116 0.0014941165032954478 0.0016503940612064363 0.0017464322160936894 0.001776651754178625 0.0017783579871622347 0.0017766517541786277 0.001746432216093693 0.0016503940612064357 0.0014941165032954452 0.0013145279401521096 0.0011270689633863322 0.0009190083262633719 0.0006972250267069877 0.0004998642579464957 0.0003519813156453289 0.00024459489967906177 0.0001608040602893069 0.00010098659556921245 0.00006774528075202805 0.00004589492550741785 0.00005028754494384571 0.0000677452807520246 0.00010792134312512266 0.0001721528575422849 0.00025788940385115046 0.00037446751049341324 0.0005287625121494353 0.0007038565058097144 0.0008701737083641822 0.0010189283889044814 0.0011579051791739672 0.0012756356763438063 0.0013445560159961161 0.0013626764404337543 0.0013618288308587555 0.0013626764404337539 0.0013445560159961202 0.001275635676343809 0.0011579051791739624 0.0010189283889044786 0.0008701737083641729 0.000703856505809718 0.0005287625121494371 0.0003744675104934144 0.00025788940385115057 0.0001721528575422853 0.00010792134312512288 0.00006774528075202308 0.00005028754494385116 0.00003999670548055596 0.00004194324107620589 0.00005534744024333297 0.00009223278715530712 0.00015267581316422878 0.00023234710462510192 0.00033613445730578447 0.0004687949647652224 0.0006197248184155318 0.0007667896670978357 0.0008995969267711935 0.00102237970790197 0.0011288125431500491 0.0011986080708773564 0.0012264093166083293 0.0012312082497994321 0.0012264093166083276 0.0011986080708773581 0.0011288125431500456 0.001022379707901963 0.0008995969267711831 0.0007667896670978357 0.0006197248184155318 0.0004687949647652224 0.00033613445730578794 0.0002323471046251041 0.00015267581316422878 0.00009223278715531145 0.00005534744024333427 0.00004194324107621044 0.000041943241076205705 0.00004603987620568197 0.00006979335205074732 0.00012382628362150774 0.00020453187540746552 0.0003006000119108388 0.00041543744447833353 0.000560334919535244 0.0007313386636297325 0.0009055757124909107 0.0010633634004519068 0.0011973429792128734 0.001297557394589074 0.0013517795309755715 0.001365906690206458 0.001362676440433748 0.0013490440679071673 0.0013021331758599228 0.0012018072025311497 0.0010646588843713984 0.0009248564411888015 0.0007900599153244988 0.0006423483931220769 0.0004813101651604727 0.00033497429892343406 0.00022539912279093632 0.00014969492195175143 0.00009660617943875016 0.00006378627298063432 0.00004804046316260132 0.00005534744024333038 0.0000697933520507466 0.00011389516179236906 0.0001937282923613023 0.00029998032794169424 0.00042271980596803185 0.0005759894400297503 0.0007774910755573733 0.001018340305429829 0.0012624736503087115 0.0014775571166893116 0.0016478117139200619 0.0017585618402871544 0.0018017261947860187 0.0017963696659219924 0.0017766517541786143 0.0017468782307036386 0.0016687172925344625 0.0015145682355305722 0.0013165680957763406 0.0011311065461328004 0.0009705099287999392 0.0008015254916949674 0.0006092634042455399 0.0004273720105761918 0.000291568311564055 0.00020099329412540405 0.00013678820046357607 0.00009111223839643591 0.00006378627298063536 0.00009223278715530541 0.00012382628362150782 0.0001937282923613024 0.00030167391628042374 0.00044161447486532637 0.0006246264787304545 0.0008828322819483976 0.0012316737057361756 0.0016396186116322173 0.00203803498283602 0.00236972253031352 0.0026064943852817345 0.002728447959614904 0.002732186407408239 0.0026569839345356033 0.0025660434782336554 0.0024789141960227853 0.0023443134697092127 0.0021135152535489135 0.0018231338833620278 0.0015544662428557939 0.0013314457145501835 0.0011094531117226147 0.0008589568636188326 0.0006161688271076232 0.0004294289912473426 0.00030171519351102576 0.0002077571576043944 0.00013678820046357333 0.00009660617943874875 0.0001526758131642261 0.00020453187540746503 0.0002999803279416919 0.0004416144748653246 0.0006508099138680067 0.00097365108575957 0.0014590527240740728 0.0021106035581529674 0.002854108121502899 0.003565593495754314 0.004139463137881501 0.0045106203259402105 0.004640662862214502 0.004534767905786569 0.004273017834966273 0.0039840926453290244 0.00374302784810988 0.003505782339925744 0.0031833431333576964 0.002773962381173288 0.002361827022744189 0.001993538699736136 0.0016351864912215134 0.0012589495116249135 0.0009066580400836018 0.0006333943940810118 0.00044170624374382985 0.00030171519351102717 0.0002009932941254022 0.00014969492195175235 0.00023234710462509907 0.0003006000119108386 0.00042271980596803006 0.0006246264787304536 0.0009736510857595716 0.001555350776191856 0.0024284076200209283 0.0035749591955013837 0.0048837020470039886 0.006171924531510292 0.007230885503687027 0.007885851634352315 0.008053268662561041 0.007765271584428248 0.007171889765094909 0.0065078295127020515 0.005963646198878781 0.005545206054145702 0.005105322245517 0.004537419787465299 0.00387718462972182 0.0032019567330937243 0.002535785925900223 0.0018950825958768706 0.0013400322643710159 0.0009228985548071604 0.0006333943940810139 0.00042942899124734466 0.00029156831156405306 0.00022539912279093493 0.0003361344573057855 0.0004154374444783357 0.0005759894400297491 0.0008828322819483996 0.0014590527240740752 0.0024284076200209287 0.0038449800445795974 0.0056888854117370545 0.007878392384066558 0.010174247183974288 0.012128142883814004 0.013300080450640456 0.013543651521091849 0.013006136920165738 0.011961891930324663 0.010754562411234785 0.009724646432491046 0.00898662822372675 0.008340585241485118 0.007517489748370419 0.006443731463249301 0.005225728102749308 0.004001168929060429 0.0028883717904480124 0.001987585477664543 0.0013400322643710137 0.0009066580400836037 0.0006161688271076269 0.0004273720105761894 0.00033497429892343427 0.0004687949647652226 0.0005603349195352447 0.0007774910755573722 0.0012316737057361767 0.0021106035581529687 0.003574959195501384 0.005688885411737054 0.008518072672587645 0.012113170777656668 0.016130953814403683 0.0196188113180979 0.021600447001363186 0.021871898399191694 0.020913217290195893 0.019262043358730805 0.01734444029607785 0.015606687393438859 0.014298536985646171 0.01320545188047307 0.011899632005612573 0.010179124463848827 0.008167517098673105 0.006129708980026591 0.004314121678006393 0.0028883717904480103 0.0018950825958768695 0.001258949511624913 0.000858956863618835 0.0006092634042455397 0.0004813101651604741 0.0006197248184155306 0.000731338663629735 0.0010183403054298279 0.0016396186116322189 0.002854108121502902 0.004883702047003988 0.007878392384066561 0.012113170777656668 0.01786507350603816 0.024608649914735686 0.030550059905471993 0.03380867422689518 0.034073916820984464 0.03239910529167102 0.02981367918904268 0.02688893996048021 0.024131797236828945 0.021878320719838727 0.019899013037081054 0.01767088697656698 0.014947087410735683 0.011889215069225804 0.008839845022533018 0.006129708980026591 0.004001168929060429 0.002535785925900218 0.001635186491221514 0.001109453111722617 0.0008015254916949625 0.0006423483931220744 0.0007667896670978363 0.0009055757124909078 0.0012624736503087073 0.002038034982836018 0.003565593495754312 0.00617192453151029 0.01017424718397428 0.016130953814403676 0.024608649914735676 0.034928612089142844 0.04435217915922054 0.04979656952952351 0.050491304937156874 0.047938404154548864 0.04387607687253015 0.03939450951957952 0.03526993486347836 0.0318112285958015 0.02854698315066252 0.02483327612429589 0.02057228699217593 0.016125443171831916 0.011889215069225802 0.008167517098673105 0.005225728102749304 0.0032019567330937226 0.0019935386997361314 0.0013314457145501787 0.0009705099287999336 0.0007900599153244941 0.0008995969267711839 0.0010633634004519007 0.0014775571166893028 0.0023697225303135213 0.004139463137881501 0.007230885503687018 0.012128142883814 0.019618811318097895 0.030550059905471983 0.04435217915922055 0.05780088809326291 0.06659102873504198 0.06866773887166149 0.06518714478868119 0.05874562097273792 0.05188798945407266 0.04639919581004441 0.042377732608002046 0.03834686322647693 0.03308671725470335 0.026834614134389624 0.02057228699217594 0.014947087410735683 0.010179124463848832 0.006443731463249304 0.003877184629721814 0.0023618270227441936 0.0015544662428557995 0.0011311065461327963 0.0009248564411887997 0.0010223797079019646 0.001197342979212864 0.0016478117139200605 0.002606494385281729 0.004510620325940209 0.00788585163435231 0.01330008045064045 0.021600447001363186 0.03380867422689518 0.0497965695295235 0.06659102873504197 0.0788799121953625 0.08242112353905495 0.0770637825693041 0.06663205520314515 0.05654257027060355 0.05061792172031549 0.04845800059513081 0.04623882046826718 0.040967048702471184 0.033086717254703336 0.02483327612429589 0.01767088697656698 0.011899632005612578 0.00751748974837042 0.004537419787465307 0.002773962381173295 0.0018231338833620322 0.0013165680957763384 0.0010646588843713958 0.0011288125431500463 0.0012975573945890686 0.001758561840287147 0.002728447959614904 0.004640662862214509 0.008053268662561041 0.013543651521091854 0.02187189839919169 0.03407391682098447 0.05049130493715689 0.0686677388716615 0.08242112353905495 0.08510319364006401 0.07545099821496906 0.05954917846784604 0.04637859083505481 0.0417589225893368 0.044700943846149505 0.048297021958774146 0.04623882046826718 0.038346863226476936 0.028546983150662522 0.019899013037081057 0.013205451880473075 0.008340585241485121 0.005105322245516996 0.0031833431333577003 0.0021135152535489204 0.0015145682355305675 0.0012018072025311503 0.0011986080708773549 0.001351779530975574 0.0018017261947860246 0.0027321864074082393 0.004534767905786574 0.007765271584428245 0.013006136920165738 0.020913217290195893 0.03239910529167102 0.04793840415454885 0.06518714478868116 0.0770637825693041 0.07545099821496906 0.05996092486880796 0.04002983023865638 0.026312636786145902 0.024326738604191468 0.03325555919185392 0.04470094384614951 0.04845800059513082 0.04237773260800204 0.03181122859580151 0.02187832071983873 0.014298536985646175 0.008986628223726749 0.005545206054145702 0.003505782339925737 0.002344313469709204 0.0016687172925344614 0.0013021331758599167 0.0012264093166083284 0.0013659066902064608 0.001796369665921989 0.0026569839345356033 0.004273017834966273 0.007171889765094904 0.011961891930324667 0.0192620433587308 0.029813679189042683 0.04387607687253016 0.05874562097273792 0.06663205520314515 0.05954917846784604 0.04002983023865638 0.02057159250796283 0.010166722672810909 0.011332167747017898 0.02432673860419147 0.04175892258933681 0.050617921720315505 0.04639919581004443 0.035269934863478375 0.024131797236828952 0.015606687393438875 0.009724646432491055 0.005963646198878786 0.003743027848109887 0.0024789141960227935 0.0017468782307036403 0.0013490440679071703 0.001231208249799439 0.0013626764404337515 0.0017766517541786208 0.002566043478233659 0.0039840926453290244 0.006507829512702053 0.010754562411234778 0.017344440296077852 0.02688893996048021 0.03939450951957951 0.05188798945407265 0.05654257027060355 0.0463785908350548 0.0263126367861459 0.010166722672810912 0.0048448951085688415 0.010166722672810914 0.026312636786145906 0.046378590835054814 0.056542570270603554 0.05188798945407266 0.03939450951957951 0.026888939960480213 0.01734444029607786 0.010754562411234781 0.006507829512702058 0.003984092645329023 0.002566043478233658 0.001776651754178623 0.0013626764404337521 0.001226409316608329 0.00134904406790717 0.0017468782307036375 0.002478914196022793 0.0037430278481098895 0.005963646198878784 0.009724646432491053 0.015606687393438864 0.024131797236828952 0.03526993486347836 0.04639919581004442 0.05061792172031549 0.0417589225893368 0.024326738604191475 0.011332167747017903 0.010166722672810909 0.02057159250796283 0.04002983023865638 0.05954917846784604 0.06663205520314516 0.05874562097273793 0.04387607687253016 0.029813679189042687 0.01926204335873081 0.01196189193032467 0.0071718897650949074 0.004273017834966269 0.0026569839345356025 0.0017963696659219893 0.0013659066902064613 0.0011986080708773555 0.0013021331758599171 0.0016687172925344594 0.0023443134697092027 0.003505782339925739 0.005545206054145701 0.008986628223726747 0.014298536985646171 0.021878320719838727 0.0318112285958015 0.04237773260800203 0.048458000595130814 0.044700943846149505 0.033255559191853926 0.024326738604191475 0.026312636786145902 0.04002983023865638 0.059960924868807955 0.07545099821496906 0.07706378256930412 0.06518714478868118 0.04793840415454886 0.032399105291671025 0.020913217290195903 0.013006136920165744 0.0077652715844282495 0.004534767905786571 0.002732186407408238 0.0018017261947860235 0.0013517795309755728 0.0011288125431500476 0.0012018072025311523 0.0015145682355305688 0.0021135152535489187 0.0031833431333577024 0.005105322245516999 0.008340585241485125 0.013205451880473073 0.01989901303708106 0.028546983150662526 0.03834686322647693 0.04623882046826718 0.04829702195877414 0.04470094384614952 0.04175892258933681 0.04637859083505481 0.05954917846784604 0.07545099821496906 0.08510319364006402 0.08242112353905497 0.0686677388716615 0.05049130493715689 0.03407391682098448 0.021871898399191698 0.013543651521091856 0.008053268662561045 0.004640662862214505 0.0027284479596149025 0.0017585618402871457 0.0012975573945890665 0.0010223797079019657 0.0010646588843713977 0.0013165680957763423 0.001823133883362029 0.0027739623811732965 0.004537419787465312 0.0075174897483704225 0.011899632005612575 0.017670886976566984 0.024833276124295887 0.033086717254703336 0.04096704870247118 0.04623882046826718 0.048458000595130814 0.050617921720315505 0.05654257027060355 0.06663205520314515 0.0770637825693041 0.08242112353905498 0.0788799121953625 0.06659102873504197 0.0497965695295235 0.03380867422689519 0.021600447001363186 0.013300080450640451 0.007885851634352313 0.0045106203259402036 0.002606494385281726 0.0016478117139200608 0.0011973429792128609 0.0008995969267711855 0.0009248564411888013 0.0011311065461328028 0.0015544662428557965 0.0023618270227441945 0.003877184629721822 0.006443731463249307 0.010179124463848832 0.01494708741073569 0.020572286992175937 0.026834614134389628 0.03308671725470335 0.038346863226476936 0.042377732608002046 0.046399195810044425 0.05188798945407265 0.05874562097273792 0.06518714478868118 0.0686677388716615 0.06659102873504197 0.05780088809326291 0.04435217915922055 0.030550059905471987 0.019618811318097895 0.012128142883814004 0.007230885503687022 0.004139463137881496 0.0023697225303135182 0.0014775571166893054 0.0010633634004518979 0.0007667896670978382 0.0007900599153244942 0.0009705099287999405 0.0013314457145501752 0.0019935386997361327 0.0032019567330937326 0.005225728102749309 0.008167517098673107 0.011889215069225807 0.016125443171831913 0.020572286992175937 0.0248332761242959 0.028546983150662536 0.03181122859580151 0.035269934863478375 0.03939450951957951 0.043876076872530166 0.04793840415454885 0.0504913049371569 0.04979656952952349 0.04435217915922054 0.03492861208914283 0.024608649914735683 0.016130953814403673 0.010174247183974285 0.006171924531510291 0.0035655934957543067 0.0020380349828360137 0.0012624736503087104 0.0009055757124909056 0.0006197248184155327 0.0006423483931220739 0.0008015254916949692 0.0011094531117226143 0.0016351864912215147 0.0025357859259002285 0.004001168929060432 0.006129708980026596 0.00883984502253302 0.011889215069225807 0.01494708741073569 0.017670886976566987 0.01989901303708106 0.02187832071983873 0.024131797236828952 0.026888939960480206 0.029813679189042687 0.032399105291671025 0.03407391682098448 0.03380867422689519 0.030550059905471976 0.024608649914735683 0.017865073506038165 0.01211317077765667 0.007878392384066565 0.004883702047003991 0.0028541081215028973 0.001639618611632216 0.0010183403054298316 0.0007313386636297343 0.0004687949647652253 0.0004813101651604733 0.0006092634042455458 0.0008589568636188317 0.0012589495116249144 0.0018950825958768797 0.0028883717904480155 0.004314121678006399 0.006129708980026601 0.008167517098673109 0.010179124463848834 0.011899632005612585 0.013205451880473082 0.014298536985646175 0.015606687393438871 0.017344440296077852 0.019262043358730812 0.020913217290195896 0.0218718983991917 0.021600447001363186 0.01961881131809789 0.01613095381440368 0.01211317077765667 0.008518072672587643 0.005688885411737055 0.0035749591955013876 0.0021106035581529643 0.0012316737057361748 0.0007774910755573765 0.0005603349195352455 0.0003361344573057894 0.00033497429892343384 0.00042737201057619517 0.0006161688271076233 0.0009066580400836056 0.0013400322643710217 0.001987585477664548 0.0028883717904480155 0.004001168929060438 0.005225728102749307 0.0064437314632493185 0.007517489748370426 0.008340585241485133 0.00898662822372674 0.009724646432491064 0.010754562411234772 0.011961891930324677 0.013006136920165737 0.013543651521091863 0.013300080450640446 0.012128142883814 0.010174247183974278 0.007878392384066563 0.0056888854117370475 0.0038449800445796004 0.002428407620020931 0.0014590527240740724 0.0008828322819483993 0.0005759894400297552 0.00041543744447833814 0.00023234710462510268 0.00022539912279093444 0.0002915683115640577 0.0004294289912473406 0.0006333943940810149 0.0009228985548071664 0.0013400322643710193 0.001895082595876875 0.002535785925900232 0.003201956733093728 0.003877184629721837 0.004537419787465309 0.005105322245517014 0.005545206054145691 0.0059636461988788 0.006507829512702049 0.007171889765094911 0.007765271584428249 0.008053268662561043 0.007885851634352308 0.007230885503687017 0.006171924531510287 0.004883702047003988 0.0035749591955013794 0.0024284076200209296 0.001555350776191858 0.0009736510857595681 0.0006246264787304553 0.00042271980596803635 0.00030060001191084155 0.00015267581316422965 0.00014969492195175162 0.00020099329412540606 0.00030171519351102305 0.00044170624374383007 0.0006333943940810146 0.0009066580400836023 0.0012589495116249142 0.0016351864912215158 0.001993538699736134 0.0023618270227442023 0.0027739623811733013 0.0031833431333577124 0.0035057823399257376 0.0037430278481098934 0.003984092645329021 0.004273017834966271 0.00453476790578657 0.0046406628622145 0.004510620325940202 0.004139463137881491 0.00356559349575431 0.002854108121502901 0.0021106035581529626 0.001459052724074074 0.0009736510857595725 0.0006508099138680042 0.0004416144748653283 0.00029998032794169885 0.00020453187540746888 0.00009223278715530793 0.00009660617943874651 0.0001367882004635758 0.00020775715760438994 0.00030171519351102457 0.0004294289912473441 0.0006161688271076231 0.0008589568636188358 0.0011094531117226134 0.0013314457145501815 0.0015544662428558047 0.001823133883362037 0.0021135152535489217 0.0023443134697092014 0.002478914196022792 0.0025660434782336567 0.0026569839345356016 0.002732186407408241 0.002728447959614899 0.0026064943852817284 0.0023697225303135156 0.0020380349828360168 0.0016396186116322173 0.0012316737057361735 0.0008828322819483996 0.0006246264787304579 0.00044161447486532453 0.00030167391628042856 0.00019372829236130828 0.00012382628362151183 0.000055347440243331865 0.00006378627298063215 0.00009111223839643755 0.00013678820046357206 0.00020099329412540378 0.0002915683115640557 0.00042737201057619105 0.000609263404245541 0.0008015254916949697 0.0009705099287999337 0.0011311065461328124 0.0013165680957763425 0.0015145682355305757 0.0016687172925344477 0.0017468782307036397 0.001776651754178611 0.001796369665921988 0.0018017261947860224 0.0017585618402871444 0.0016478117139200534 0.0014775571166893004 0.0012624736503087047 0.0010183403054298324 0.0007774910755573704 0.0005759894400297526 0.0004227198059680353 0.00029998032794169326 0.00019372829236130696 0.0001138951617923737 0.00006979335205075092 0.00004194324107620657 0.000048040463162597204 0.00006378627298063461 0.00009660617943874616 0.00014969492195175105 0.0002253991227909347 0.0003349742989234308 0.00048131016516047377 0.0006423483931220736 0.0007900599153244932 0.000924856441188805 0.0010646588843714036 0.0012018072025311486 0.0013021331758599096 0.0013490440679071695 0.0013626764404337448 0.0013659066902064565 0.0013517795309755764 0.0012975573945890628 0.0011973429792128596 0.0010633634004518942 0.0009055757124909079 0.0007313386636297343 0.0005603349195352413 0.00041543744447833554 0.00030060001191084155 0.00020453187540746465 0.00012382628362151218 0.0000697933520507505 0.000046039876205686495 0.00003299600592525473 0.00003597365585370491 0.00005216389130005615 0.000092962170334268 0.00015775652622948642 0.00023864228845880443 0.0003344107973057269 0.00044961097665089343 0.0005832294783845796 0.0007212546483763883 0.000848652587863024 0.0009628131037069249 0.0010644064853800005 0.0011463175132408882 0.0011986080708773546 0.0012163029673619517 0.0011986080708773616 0.0011463175132408847 0.001064406485380004 0.0009628131037069214 0.0008486525878630274 0.0007212546483763883 0.0005832294783845726 0.0004496109766508917 0.0003344107973057304 0.00023864228845880487 0.00015775652622948013 0.0000929621703342706 0.00005216389130005355 0.000035973655853705345 0.000035973655853702086 0.00004185228624762491 0.00007273331620749328 0.00014001957347210055 0.0002370357009563509 0.00034400341974442824 0.0004557180282623762 0.0005865215698875135 0.0007465776724080113 0.000921890954982216 0.0010826685402583554 0.0012065670294402905 0.0012883678922504763 0.001333902222608257 0.001351779530975571 0.001344556015996115 0.0013021331758599176 0.0012123734799485172 0.0010815579702260208 0.0009370424568941393 0.0008039528511211515 0.0006814304005537412 0.000551997357356167 0.00041445894177783723 0.0002898163901862302 0.0001957018338934876 0.0001310749938927124 0.00008633426488525946 0.00005773213817806121 0.000042464763661093724 0.000052163891300055464 0.00007273331620749526 0.00012916539479545172 0.00022688081584744548 0.0003533047695375068 0.0004938311102070564 0.0006575346592259378 0.0008649531896832565 0.0011191498215588833 0.0013888305176585234 0.0016224551241649854 0.001779416797872281 0.00184749830338486 0.0018436353554615293 0.0018017261947860244 0.0017464322160936892 0.0016687172925344657 0.0015361738697273987 0.0013402003972896673 0.001123903496920181 0.0009407587239141637 0.0007970503483696793 0.0006561523056794497 0.0004963521413852153 0.00034311220896241027 0.00023073618568791475 0.00016134910101133876 0.00011571395533526906 0.00008108726648983507 0.000057732138178066003 0.00009296217033427238 0.00014001957347210638 0.00022688081584744732 0.0003502417832487437 0.000511028020787966 0.0007311047369061616 0.0010440770375415899 0.0014604341919198373 0.0019465698802292974 0.002423979187085867 0.0028018161266351953 0.0030170576322447735 0.0030503657603172044 0.0029314670065587237 0.0027321864074082367 0.0025286503275099063 0.002344313469709197 0.002134042701198258 0.0018521698782702916 0.0015340316098065938 0.001261728621581648 0.0010612533502024912 0.0008835265101450246 0.0006838316235267733 0.0004844533228748201 0.0003324322130755776 0.0002354031801643062 0.00016831495554073925 0.00011571395533526804 0.00008633426488526339 0.0001577565262294843 0.00023703570095635077 0.000353304769537502 0.0005110280207879605 0.0007582882900205657 0.0011702724834703985 0.0018004153950183074 0.0026293898016959954 0.003554862012239765 0.004422978400784097 0.005081308636276987 0.005421110613354324 0.0054021003110516505 0.005066004126662931 0.004534767905786569 0.003975820768717635 0.003505782339925739 0.003109176087071831 0.002694549901459452 0.002240658034798413 0.0018252040088143572 0.0015021101566728263 0.001231019929226467 0.00095544760635267 0.0006895470735222081 0.0004810140756292388 0.00033826785089126793 0.0002354031801643047 0.00016134910101133602 0.00013107499389271676 0.00023864228845880647 0.0003440034197444315 0.0004938311102070554 0.0007311047369061594 0.0011702724834704002 0.0019355668732131612 0.0030756018951073553 0.004526188866547983 0.006144054076131457 0.007710433178781155 0.008929833570272596 0.009543175734881953 0.009473934063312556 0.008819247828205534 0.007765271584428251 0.0065805791958524875 0.005545206054145708 0.0047603283170296485 0.0041071301072263975 0.0034530126341166304 0.0028100800161902036 0.0022502321078609715 0.0017735870623411655 0.0013428023934787074 0.0009682847789069727 0.000682670017928165 0.00048101407562923837 0.00033243221307557446 0.00023073618568791117 0.0001957018338934878 0.0003344107973057288 0.00045571802826237863 0.0006575346592259343 0.0010440770375415855 0.0018004153950183044 0.0030756018951073514 0.004884730385322297 0.00719425601580247 0.00997725307515428 0.012938092278920269 0.015326377141967931 0.01641060648739892 0.01610805172382183 0.014842004087681647 0.01300613692016574 0.010916081954214438 0.008986628223726745 0.0075217835184693245 0.006439066476751874 0.005460917229675782 0.004462883841154418 0.003504638407223866 0.0026549678017238824 0.0019366624294627401 0.001371878137905159 0.0009682847789069686 0.0006895470735222058 0.00048445332287481573 0.0003431122089624009 0.00028981639018622575 0.00044961097665089506 0.0005865215698875174 0.000864953189683257 0.0014604341919198368 0.0026293898016959963 0.004526188866547983 0.007194256015802475 0.01088089061593668 0.015933902304877866 0.021833526348406386 0.026619531064699154 0.028345846801708416 0.02704393306599346 0.024203110600517833 0.020913217290195893 0.017497979483522698 0.014298536985646173 0.011780429057506373 0.009966524346444055 0.008449495985470215 0.006923153073596433 0.005391246813130986 0.003986452395490247 0.0028151593946382815 0.0019366624294627393 0.0013428023934787042 0.0009554476063526688 0.0006838316235267724 0.0004963521413852117 0.00041445894177783436 0.0005832294783845777 0.0007465776724080131 0.001119149821558879 0.0019465698802292985 0.0035548620122397606 0.0061440540761314565 0.009977253075154284 0.015933902304877866 0.025055637667848858 0.036366731310063405 0.04551782647970808 0.04815204876374487 0.044562668708091314 0.03844009900727351 0.03239910529167102 0.02687477562088644 0.021878320719838733 0.01784026965500826 0.014864650915170599 0.012455354564246363 0.0101486926733028 0.007869541377713729 0.005761950678317071 0.003986452395490251 0.0026549678017238816 0.0017735870623411614 0.0012310199292264686 0.0008835265101450296 0.000656152305679445 0.0005519973573561665 0.0007212546483763897 0.0009218909549822119 0.0013888305176585206 0.0024239791870858617 0.0044229784007840875 0.007710433178781149 0.012938092278920262 0.021833526348406383 0.036366731310063384 0.055054691285063385 0.0704676586833634 0.07491270404560922 0.06864617972454859 0.058048588974932876 0.04793840415454885 0.03927144288015322 0.0318112285958015 0.02580412409566322 0.021248108927548248 0.017509967750017324 0.014055945234431344 0.010803241393581735 0.007869541377713719 0.005391246813130983 0.003504638407223854 0.0022502321078609654 0.0015021101566728226 0.0010612533502024851 0.0007970503483696779 0.0006814304005537331 0.0008486525878630221 0.0010826685402583528 0.0016224551241649792 0.002801816126635195 0.005081308636276986 0.008929833570272596 0.015326377141967934 0.026619531064699158 0.04551782647970806 0.07046765868336341 0.09217668859203686 0.1001822094906155 0.09348758096382306 0.07957358172116913 0.06518714478868116 0.05265480311856309 0.04237773260800204 0.034565372497303924 0.028649682336106586 0.023497897295981156 0.018577243399965783 0.014055945234431351 0.010148692673302795 0.006923153073596433 0.004462883841154409 0.0028100800161901906 0.0018252040088143529 0.0012617286215816461 0.0009407587239141535 0.0008039528511211408 0.0009628131037069264 0.0012065670294402887 0.0017794167978722815 0.0030170576322447666 0.005421110613354317 0.009543175734881951 0.016410606487398918 0.028345846801708423 0.04815204876374486 0.07491270404560921 0.1001822094906155 0.11281644974287011 0.10918928639667483 0.09479720627444044 0.0770637825693041 0.06076976938801452 0.048458000595130814 0.04060359154257608 0.03518834279291235 0.029690429604246064 0.02349789729598115 0.017509967750017327 0.01245535456424636 0.008449495985470214 0.005460917229675767 0.0034530126341166334 0.0022406580347984063 0.0015340316098065882 0.0011239034969201713 0.0009370424568941241 0.0010644064853800065 0.0012883678922504793 0.0018474983033848552 0.0030503657603172026 0.005402100311051645 0.009473934063312555 0.016108051723821838 0.02704393306599346 0.04456266870809132 0.0686461797245486 0.09348758096382309 0.10918928639667483 0.10931266537743456 0.09562570069848383 0.07545099821496906 0.05667798221207814 0.04470094384614951 0.04018000327837753 0.03869452315378 0.03518834279291235 0.028649682336106586 0.021248108927548245 0.014864650915170599 0.009966524346444055 0.006439066476751869 0.004107130107226395 0.0026945499014594597 0.0018521698782702955 0.0013402003972896636 0.0010815579702260168 0.0011463175132408882 0.0013339022226082522 0.001843635355461523 0.0029314670065587133 0.00506600412666292 0.00881924782820553 0.014842004087681633 0.02420311060051783 0.03844009900727349 0.058048588974932855 0.07957358172116911 0.09479720627444044 0.09562570069848383 0.0813768061788179 0.059960924868807955 0.04165728956585284 0.03325555919185391 0.03504409763073714 0.04018000327837752 0.04060359154257607 0.03456537249730392 0.025804124095663218 0.01784026965500825 0.01178042905750637 0.007521783518469312 0.004760328317029649 0.0031091760870718245 0.002134042701198251 0.0015361738697274032 0.0012123734799485094 0.0011986080708773572 0.0013517795309755725 0.0018017261947860259 0.002732186407408241 0.00453476790578657 0.007765271584428244 0.013006136920165742 0.020913217290195896 0.03239910529167102 0.04793840415454884 0.06518714478868118 0.0770637825693041 0.07545099821496906 0.05996092486880795 0.04002983023865638 0.0263126367861459 0.02432673860419147 0.03325555919185392 0.04470094384614951 0.048458000595130814 0.04237773260800204 0.03181122859580151 0.02187832071983874 0.014298536985646178 0.008986628223726747 0.005545206054145705 0.0035057823399257328 0.0023443134697092 0.0016687172925344653 0.001302133175859914 0.001216302967361956 0.0013445560159961165 0.0017464322160936935 0.0025286503275099093 0.00397582076871763 0.006580579195852487 0.010916081954214438 0.017497979483522698 0.026874775620886436 0.039271442880153204 0.052654803118563076 0.06076976938801451 0.056677982212078135 0.04165728956585282 0.0263126367861459 0.020232834606957052 0.0263126367861459 0.04165728956585282 0.05667798221207813 0.06076976938801451 0.05265480311856308 0.039271442880153204 0.026874775620886443 0.0174979794835227 0.010916081954214436 0.006580579195852492 0.0039758207687176274 0.002528650327509905 0.0017464322160936985 0.0013445560159961157 0.0011986080708773577 0.0013021331758599148 0.00166871729253446 0.0023443134697092036 0.003505782339925736 0.005545206054145699 0.00898662822372675 0.014298536985646175 0.02187832071983873 0.0318112285958015 0.042377732608002046 0.04845800059513081 0.04470094384614952 0.03325555919185391 0.02432673860419148 0.0263126367861459 0.040029830238656375 0.059960924868807955 0.07545099821496906 0.0770637825693041 0.06518714478868118 0.04793840415454886 0.03239910529167103 0.0209132172901959 0.01300613692016574 0.00776527158442825 0.0045347679057865685 0.0027321864074082367 0.0018017261947860293 0.0013517795309755715 0.001146317513240888 0.0012123734799485103 0.0015361738697273989 0.0021340427011982523 0.0031091760870718267 0.004760328317029645 0.007521783518469316 0.011780429057506368 0.017840269655008244 0.02580412409566321 0.03456537249730391 0.040603591542576076 0.04018000327837753 0.03504409763073714 0.03325555919185392 0.04165728956585283 0.05996092486880795 0.0813768061788179 0.09562570069848382 0.09479720627444044 0.07957358172116911 0.058048588974932855 0.03844009900727351 0.024203110600517833 0.014842004087681635 0.008819247828205534 0.0050660041266629196 0.0029314670065587085 0.0018436353554615245 0.0013339022226082505 0.001064406485380007 0.0010815579702260188 0.0013402003972896625 0.0018521698782702964 0.002694549901459462 0.004107130107226395 0.0064390664767518735 0.009966524346444055 0.014864650915170599 0.021248108927548245 0.02864968233610659 0.03518834279291236 0.03869452315378 0.04018000327837753 0.04470094384614952 0.056677982212078135 0.07545099821496906 0.09562570069848383 0.10931266537743456 0.10918928639667481 0.09348758096382308 0.0686461797245486 0.04456266870809133 0.027043933065993456 0.016108051723821838 0.00947393406331256 0.0054021003110516445 0.003050365760317199 0.001847498303384856 0.0012883678922504778 0.0009628131037069266 0.0009370424568941263 0.0011239034969201733 0.0015340316098065867 0.0022406580347984085 0.003453012634116636 0.005460917229675773 0.008449495985470214 0.012455354564246365 0.017509967750017317 0.023497897295981153 0.029690429604246053 0.03518834279291236 0.040603591542576076 0.04845800059513082 0.06076976938801451 0.0770637825693041 0.09479720627444044 0.10918928639667483 0.11281644974287011 0.10018220949061549 0.07491270404560921 0.04815204876374487 0.02834584680170842 0.01641060648739892 0.009543175734881955 0.005421110613354316 0.0030170576322447627 0.0017794167978722824 0.0012065670294402863 0.0008486525878630223 0.0008039528511211433 0.0009407587239141585 0.0012617286215816433 0.0018252040088143553 0.0028100800161901997 0.004462883841154416 0.006923153073596431 0.010148692673302798 0.014055945234431343 0.01857724339996578 0.02349789729598115 0.028649682336106586 0.03456537249730392 0.04237773260800204 0.05265480311856308 0.06518714478868116 0.07957358172116911 0.09348758096382308 0.1001822094906155 0.09217668859203684 0.07046765868336341 0.045517826479708076 0.026619531064699154 0.01532637714196794 0.008929833570272598 0.005081308636276985 0.002801816126635192 0.0016224551241649815 0.0010826685402583495 0.0007212546483763901 0.0006814304005537352 0.0007970503483696838 0.0010612533502024812 0.0015021101566728243 0.002250232107860977 0.0035046384072238614 0.005391246813130983 0.007869541377713726 0.010803241393581726 0.014055945234431341 0.017509967750017313 0.02124810892754825 0.02580412409566321 0.03181122859580151 0.03927144288015321 0.04793840415454885 0.05804858897493284 0.06864617972454862 0.0749127040456092 0.07046765868336341 0.05505469128506337 0.0363667313100634 0.02183352634840638 0.012938092278920267 0.0077104331787811505 0.0044229784007840875 0.002423979187085859 0.001388830517658523 0.0009218909549822074 0.0005832294783845781 0.000551997357356169 0.0006561523056794505 0.0008835265101450259 0.0012310199292264702 0.001773587062341174 0.002654967801723888 0.003986452395490252 0.005761950678317072 0.007869541377713717 0.010148692673302793 0.012455354564246353 0.0148646509151706 0.017840269655008244 0.02187832071983873 0.026874775620886436 0.03239910529167102 0.0384400990072735 0.04456266870809133 0.04815204876374487 0.04551782647970807 0.0363667313100634 0.025055637667848865 0.015933902304877866 0.009977253075154287 0.00614405407613146 0.0035548620122397615 0.0019465698802292985 0.001119149821558881 0.0007465776724080085 0.00044961097665089587 0.0004144589417778374 0.0004963521413852169 0.0006838316235267697 0.0009554476063526705 0.0013428023934787172 0.0019366624294627451 0.0028151593946382863 0.003986452395490254 0.0053912468131309815 0.00692315307359643 0.008449495985470207 0.009966524346444062 0.011780429057506361 0.014298536985646173 0.0174979794835227 0.020913217290195896 0.024203110600517826 0.02704393306599346 0.02834584680170842 0.026619531064699147 0.021833526348406386 0.015933902304877862 0.01088089061593668 0.007194256015802478 0.004526188866547987 0.0026293898016959976 0.0014604341919198383 0.0008649531896832588 0.0005865215698875134 0.00033441079730572957 0.0002898163901862282 0.0003431122089624053 0.0004844533228748129 0.0006895470735222085 0.0009682847789069771 0.001371878137905164 0.0019366624294627419 0.0026549678017238946 0.0035046384072238554 0.004462883841154424 0.005460917229675758 0.0064390664767518795 0.007521783518469307 0.008986628223726752 0.010916081954214429 0.013006136920165749 0.014842004087681628 0.01610805172382184 0.016410606487398904 0.015326377141967938 0.012938092278920257 0.00997725307515428 0.007194256015802468 0.004884730385322302 0.0030756018951073527 0.0018004153950183053 0.0010440770375415873 0.0006575346592259354 0.0004557180282623753 0.00023864228845880625 0.0001957018338934886 0.0002307361856879142 0.00033243221307557234 0.0004810140756292427 0.0006826700179281734 0.0009682847789069752 0.00134280239347871 0.0017735870623411785 0.0022502321078609697 0.0028100800161902123 0.00345301263411662 0.004107130107226409 0.00476032831702963 0.00554520605414571 0.006580579195852482 0.007765271584428254 0.008819247828205526 0.009473934063312563 0.009543175734881943 0.008929833570272596 0.007710433178781151 0.006144054076131453 0.004526188866547984 0.0030756018951073596 0.0019355668732131631 0.0011702724834703987 0.0007311047369061614 0.000493831110207055 0.0003440034197444288 0.0001577565262294836 0.00013107499389271592 0.000161349101011338 0.00023540318016430215 0.00033826785089127254 0.00048101407562924347 0.0006895470735222074 0.000955447606352669 0.0012310199292264728 0.0015021101566728234 0.0018252040088143598 0.002240658034798401 0.002694549901459473 0.0031091760870718254 0.003505782339925739 0.003975820768717632 0.004534767905786573 0.005066004126662919 0.005402100311051647 0.005421110613354317 0.005081308636276988 0.0044229784007840875 0.003554862012239756 0.0026293898016959963 0.001800415395018311 0.0011702724834703991 0.0007582882900205628 0.0005110280207879623 0.0003533047695375002 0.00023703570095634925 0.00009296217033427087 0.00008633426488526103 0.00011571395533526858 0.00016831495554073595 0.00023540318016431068 0.00033243221307558015 0.0004844533228748176 0.0006838316235267763 0.0008835265101450294 0.001061253350202492 0.0012617286215816435 0.0015340316098065869 0.001852169878270292 0.0021340427011982605 0.0023443134697091984 0.0025286503275099084 0.002732186407408242 0.0029314670065587116 0.003050365760317208 0.003017057632244768 0.002801816126635197 0.002423979187085863 0.0019465698802292946 0.0014604341919198377 0.0010440770375415927 0.0007311047369061628 0.0005110280207879618 0.00035024178324874505 0.0002268808158474439 0.00014001957347210527 0.000052163891300054224 0.00005773213817806405 0.00008108726648983629 0.00011571395533526608 0.00016134910101134458 0.000230736185687916 0.00034311220896240697 0.0004963521413852142 0.0006561523056794556 0.000797050348369679 0.0009407587239141674 0.001123903496920162 0.001340200397289664 0.0015361738697273837 0.0016687172925344584 0.0017464322160936855 0.0018017261947860306 0.0018436353554615193 0.0018474983033848584 0.001779416797872274 0.0016224551241649813 0.0013888305176585221 0.001119149821558877 0.0008649531896832564 0.0006575346592259414 0.0004938311102070569 0.00035330476953750195 0.0002268808158474467 0.00012916539479544814 0.0000727333162074948 0.000035973655853701456 0.00004246476366109243 0.000057732138178062974 0.00008633426488525599 0.00013107499389271814 0.00019570183389348687 0.00028981639018622646 0.00041445894177783506 0.0005519973573561698 0.0006814304005537374 0.000803952851121144 0.0009370424568941216 0.001081557970226015 0.0012123734799485088 0.001302133175859909 0.0013445560159961113 0.0013517795309755751 0.0013339022226082548 0.001288367892250477 0.0012065670294402933 0.0010826685402583543 0.000921890954982214 0.0007465776724080076 0.0005865215698875128 0.0004557180282623798 0.00034400341974442884 0.0002370357009563452 0.00014001957347210245 0.00007273331620748998 0.00004185228624762494 0.00003269514350865809 0.00003494468682887586 0.00004926469609027389 0.00008836635431709074 0.00015338033482130246 0.00023414234946934377 0.0003235039291855611 0.0004262350267254973 0.0005506553884725048 0.0006876207794232099 0.000811656158830918 0.0009088671603585639 0.000988657092739459 0.001064406485379997 0.0011288125431500352 0.001155389745083623 0.0011288125431500387 0.0010644064853800005 0.0009886570927394658 0.0009088671603585709 0.0008116561588309111 0.0006876207794232099 0.0005506553884725048 0.0004262350267254973 0.00032350392918556285 0.00023414234946933813 0.00015338033482130333 0.0000883663543170903 0.00004926469609027779 0.000034944686828877487 0.00003494468682886994 0.00004233764706958481 0.00007494986032959229 0.0001455277698635282 0.0002496268489333397 0.00036504846722241254 0.00047878926010503617 0.000604598841051747 0.0007619127265753541 0.0009416347748850403 0.0011029764516615253 0.0012098210104861285 0.0012632413019571787 0.0012883678922504763 0.0012975573945890606 0.0012756356763438035 0.0012018072025311397 0.0010815579702260195 0.0009448279369217497 0.0008161527036543698 0.0006992403467680972 0.0005841060597842339 0.00046335640422670685 0.0003443313341783671 0.00024181346590353262 0.0001641708527985226 0.00010991083482162293 0.00007319711621452497 0.00005081018743245419 0.00003927679355652316 0.000049264696090274995 0.0000749498603295989 0.00013665578847336831 0.00023897829057065422 0.0003746363628123295 0.0005328767055493069 0.0007162791068696843 0.000939591524689107 0.0012087368131948252 0.0014949492493011296 0.0017355804206419722 0.0018739209437563804 0.001899860542948196 0.001847498303384851 0.0017585618402871418 0.0016503940612064257 0.0015145682355305599 0.0013402003972896584 0.0011362470259058631 0.0009350204265439976 0.0007668541041885661 0.0006317512268016322 0.0005052944369660935 0.00037385813418755833 0.00025434264967278807 0.0001697548150774731 0.00012122019196754269 0.00009227334361630228 0.00006872525418735833 0.0000508101874324573 0.0000883663543170882 0.00014552776986352913 0.00023897829057064888 0.0003644655134322192 0.0005378107763059015 0.0007970905713095736 0.0011733734294710804 0.0016589400069480294 0.0022044233453669152 0.0027252012978601537 0.003119967987069998 0.003310130795263664 0.003273215902839205 0.0030503657603172083 0.0027284479596148934 0.0023998563965444758 0.0021135152535489074 0.0018521698782703008 0.0015723081188699962 0.0012781043115712705 0.0010219478720986713 0.0008297072438039105 0.0006692846682037816 0.0005042574172789205 0.0003471667243337908 0.00023267207177716593 0.000167001544047114 0.00012639541981941075 0.00009227334361629918 0.00007319711621452556 0.0001533803348213041 0.00024962684893334205 0.0003746363628123246 0.0005378107763059002 0.0008160465074447724 0.0013144301327347955 0.0020849230176929008 0.0030673464280526835 0.00411742695260812 0.005065990398946286 0.005751359337704072 0.0060506053426059615 0.0059182585820492005 0.005402100311051653 0.004640662862214502 0.0038416187382218927 0.0031833431333576937 0.0026945499014594683 0.0022749560695569816 0.0018515398190606343 0.0014604937925648547 0.0011583572591615137 0.0009232854720991987 0.0007011280080980788 0.0004921829205170276 0.0003328103516603706 0.00023265115775077575 0.00016700154404711688 0.00012122019196753992 0.00010991083482162441 0.00023414234946934022 0.0003650484672224096 0.0005328767055493002 0.00079709057130957 0.001314430132734794 0.0022442729591142336 0.0036190780350586153 0.005320251868544282 0.007172574512613117 0.008932914694551082 0.01023738025444018 0.010762009478327438 0.010451266211617063 0.009473934063312556 0.00805326866256104 0.006480340695556072 0.005105322245516995 0.004107130107226393 0.0033781442189325405 0.0027352573802774554 0.0021391237296633776 0.001651926371329771 0.0012775314669896075 0.0009614150171436347 0.0006872824206897126 0.0004765515140829129 0.0003328103516603713 0.00023267207177717105 0.00016975481507747292 0.00016417085279852507 0.00032350392918556524 0.0004787892601050389 0.0007162791068696814 0.0011733734294710804 0.002084923017692903 0.003619078035058618 0.005769895370865576 0.00853527201755081 0.01197363080807433 0.015692722152502885 0.018522657783122457 0.019358270366481186 0.018259425073566694 0.016108051723821834 0.013543651521091847 0.010834126637829369 0.008340585241485112 0.006439066476751874 0.005121132327984122 0.004098860343354646 0.003192916721677637 0.0024198593746372144 0.00181084882014756 0.001333942489526634 0.0009616996260649131 0.0006872824206897124 0.0004921829205170304 0.00034716672433380056 0.00025434264967278655 0.00024181346590353492 0.000426235026725498 0.0006045988410517469 0.0009395915246891048 0.0016589400069480272 0.0030673464280526826 0.005320251868544286 0.008535272017550811 0.013311339349175031 0.02042239365493735 0.029017297434719532 0.03552916848266974 0.03654237041029714 0.032628634466063365 0.02704393306599346 0.02187189839919169 0.017291184098801104 0.013205451880473071 0.009966524346444057 0.007717583949283111 0.006103819007469902 0.0047539207128256536 0.0035767109487630233 0.00261371598920199 0.0018731680166680666 0.0013339424895266263 0.0009614150171436305 0.0007011280080980748 0.0005042574172789276 0.00037385813418755356 0.00034433133417836366 0.0005506553884725072 0.0007619127265753587 0.001208736813194825 0.002204423345366916 0.004117426952608126 0.007172574512613124 0.011973630808074339 0.02042239365493735 0.03476091520282093 0.053219103003259584 0.06708402303583849 0.06795136304519563 0.05761291075195856 0.04456266870809133 0.034073916820984464 0.02625038192951192 0.019899013037081054 0.0148646509151706 0.011317929939732605 0.008851163896473165 0.006884090603571322 0.005172902766082891 0.003734748948349916 0.0026137159892019937 0.0018108488201475528 0.001277531466989591 0.0009232854720991993 0.0006692846682037894 0.0005052944369660858 0.00046335640422670533 0.0006876207794232085 0.0009416347748850433 0.0014949492493011305 0.0027252012978601506 0.005065990398946282 0.008932914694551082 0.01569272215250288 0.02901729743471953 0.05321910300325956 0.08539324864328052 0.1097939337563083 0.11099495791676933 0.09210298693624545 0.06864617972454862 0.05049130493715687 0.03796747156086694 0.028546983150662522 0.021248108927548255 0.0160522850222263 0.012428670230404578 0.009603227887007524 0.007195842070608356 0.005172902766082883 0.003576710948763031 0.0024198593746372057 0.0016519263713297672 0.001158357259161509 0.000829707243803919 0.0006317512268016295 0.0005841060597842258 0.0008116561588309162 0.0011029764516615236 0.0017355804206419681 0.003119967987069993 0.005751359337704069 0.010237380254440183 0.018522657783122454 0.03552916848266974 0.06708402303583846 0.10979393375630833 0.14346166377168398 0.14741724073021098 0.12425304459139377 0.09348758096382309 0.06866773887166149 0.05122583225919664 0.03834686322647693 0.0286496823361066 0.021771773699975253 0.016841301099417085 0.01291180874993578 0.009603227887007525 0.006884090603571315 0.004753920712825658 0.0031929167216776357 0.002139123729663368 0.001460493792564857 0.0010219478720986848 0.0007668541041885578 0.0006992403467680918 0.0009088671603585749 0.0012098210104861337 0.0018739209437563847 0.0033101307952636615 0.006050605342605957 0.01076200947832744 0.019358270366481186 0.03654237041029714 0.06795136304519563 0.11099495791676932 0.14741724073021095 0.15678116150870317 0.13854009018097044 0.10918928639667483 0.08242112353905495 0.061744137967736784 0.046238820468267175 0.035188342792912365 0.027636802532900434 0.021890767984102763 0.016841301099417096 0.012428670230404582 0.008851163896473165 0.006103819007469916 0.004098860343354645 0.0027352573802774563 0.001851539819060626 0.001278104311571265 0.0009350204265439954 0.0008161527036543632 0.0009886570927394598 0.0012632413019571798 0.001899860542948192 0.003273215902839209 0.005918258582049203 0.010451266211617065 0.0182594250735667 0.03262863446606336 0.05761291075195857 0.09210298693624545 0.12425304459139379 0.13854009018097047 0.13065893556352043 0.10931266537743456 0.08510319364006401 0.06391931164200326 0.048297021958774146 0.03869452315378 0.03287454009187552 0.02763680253290042 0.02177177369997527 0.016052285022226293 0.011317929939732595 0.007717583949283107 0.005121132327984123 0.003378144218932534 0.002274956069556975 0.0015723081188699932 0.0011362470259058427 0.0009448279369217321 0.0010644064853800033 0.0012883678922504809 0.0018474983033848569 0.0030503657603172026 0.005402100311051647 0.009473934063312556 0.01610805172382183 0.027043933065993456 0.04456266870809132 0.0686461797245486 0.09348758096382308 0.10918928639667484 0.10931266537743456 0.09562570069848385 0.07545099821496906 0.05667798221207815 0.04470094384614951 0.040180003278377535 0.03869452315377998 0.03518834279291235 0.028649682336106593 0.021248108927548245 0.014864650915170597 0.009966524346444057 0.006439066476751875 0.004107130107226405 0.0026945499014594636 0.001852169878270297 0.0013402003972896623 0.001081557970226018 0.001128812543150044 0.001297557394589066 0.0017585618402871477 0.0027284479596149033 0.004640662862214507 0.008053268662561038 0.013543651521091852 0.02187189839919169 0.03407391682098447 0.050491304937156874 0.06866773887166151 0.08242112353905495 0.08510319364006401 0.07545099821496905 0.05954917846784604 0.04637859083505481 0.041758922589336805 0.04470094384614952 0.04829702195877413 0.046238820468267196 0.03834686322647695 0.028546983150662536 0.019899013037081057 0.013205451880473083 0.008340585241485125 0.0051053222455170084 0.003183343133357699 0.002113515253548918 0.0015145682355305686 0.001201807202531147 0.001155389745083629 0.0012756356763438037 0.0016503940612064283 0.002399856396544478 0.003841618738221899 0.0064803406955560765 0.010834126637829369 0.01729118409880111 0.02625038192951192 0.037967471560866925 0.051225832259196635 0.061744137967736784 0.06391931164200326 0.056677982212078135 0.046378590835054814 0.041682684735277545 0.04637859083505481 0.056677982212078135 0.06391931164200326 0.061744137967736784 0.051225832259196635 0.03796747156086694 0.02625038192951192 0.01729118409880111 0.010834126637829372 0.0064803406955560895 0.0038416187382218957 0.002399856396544478 0.0016503940612064313 0.0012756356763438022 0.0011288125431500443 0.0012018072025311484 0.001514568235530565 0.002113515253548918 0.003183343133357703 0.005105322245516992 0.008340585241485121 0.013205451880473076 0.019899013037081057 0.028546983150662515 0.03834686322647694 0.04623882046826718 0.048297021958774146 0.04470094384614951 0.041758922589336805 0.04637859083505481 0.05954917846784604 0.07545099821496906 0.08510319364006401 0.08242112353905495 0.06866773887166151 0.05049130493715689 0.03407391682098447 0.021871898399191694 0.013543651521091854 0.008053268662561052 0.004640662862214505 0.0027284479596149046 0.001758561840287149 0.0012975573945890639 0.001064406485380003 0.0010815579702260195 0.0013402003972896588 0.0018521698782702962 0.0026945499014594657 0.00410713010722639 0.00643906647675187 0.009966524346444053 0.014864650915170596 0.021248108927548238 0.028649682336106586 0.035188342792912365 0.03869452315377999 0.04018000327837754 0.04470094384614951 0.05667798221207814 0.07545099821496906 0.09562570069848383 0.10931266537743453 0.10918928639667481 0.09348758096382308 0.0686461797245486 0.04456266870809132 0.02704393306599346 0.016108051723821834 0.009473934063312567 0.005402100311051646 0.0030503657603172044 0.0018474983033848565 0.0012883678922504787 0.0009886570927394602 0.0009448279369217356 0.0011362470259058425 0.001572308118869992 0.002274956069556977 0.003378144218932522 0.005121132327984119 0.0077175839492831045 0.011317929939732603 0.016052285022226297 0.02177177369997526 0.027636802532900434 0.03287454009187552 0.03869452315378 0.04829702195877415 0.06391931164200328 0.08510319364006402 0.10931266537743455 0.13065893556352043 0.13854009018097044 0.1242530445913938 0.09210298693624547 0.057612910751958575 0.032628634466063365 0.018259425073566704 0.010451266211617075 0.005918258582049202 0.003273215902839213 0.0018998605429481911 0.001263241301957178 0.0009088671603585747 0.0008161527036543669 0.0009350204265439979 0.0012781043115712607 0.0018515398190606268 0.0027352573802774498 0.004098860343354643 0.00610381900746991 0.008851163896473172 0.012428670230404568 0.016841301099417096 0.02189076798410276 0.027636802532900445 0.03518834279291236 0.04623882046826719 0.061744137967736784 0.08242112353905497 0.10918928639667481 0.13854009018097044 0.15678116150870314 0.14741724073021095 0.11099495791676933 0.06795136304519563 0.03654237041029714 0.01935827036648119 0.010762009478327448 0.006050605342605954 0.0033101307952636636 0.0018739209437563828 0.0012098210104861309 0.0008116561588309158 0.0006992403467680952 0.0007668541041885636 0.0010219478720986785 0.0014604937925648566 0.002139123729663372 0.0031929167216776366 0.004753920712825652 0.006884090603571321 0.009603227887007513 0.012911808749935779 0.016841301099417078 0.021771773699975256 0.028649682336106586 0.03834686322647694 0.051225832259196635 0.0686677388716615 0.09348758096382308 0.12425304459139377 0.14741724073021095 0.14346166377168398 0.10979393375630833 0.06708402303583848 0.035529168482669744 0.018522657783122464 0.01023738025444019 0.005751359337704066 0.003119967987069994 0.0017355804206419666 0.0011029764516615197 0.000687620779423208 0.0005841060597842278 0.0006317512268016367 0.0008297072438039113 0.0011583572591615083 0.001651926371329778 0.0024198593746372074 0.003576710948763029 0.005172902766082886 0.0071958420706083465 0.009603227887007522 0.012428670230404568 0.016052285022226293 0.021248108927548248 0.028546983150662536 0.03796747156086694 0.050491304937156894 0.0686461797245486 0.09210298693624548 0.11099495791676932 0.10979393375630832 0.0853932486432805 0.05321910300325958 0.029017297434719525 0.01569272215250289 0.008932914694551082 0.005065990398946279 0.0027252012978601485 0.0014949492493011294 0.000941634774885039 0.0005506553884725069 0.0004633564042267069 0.0005052944369660931 0.0006692846682037825 0.0009232854720991991 0.0012775314669896047 0.0018108488201475557 0.0026137159892019933 0.003734748948349921 0.005172902766082875 0.006884090603571317 0.008851163896473151 0.011317929939732596 0.014864650915170599 0.01989901303708105 0.02625038192951192 0.03407391682098447 0.04456266870809133 0.05761291075195858 0.06795136304519565 0.06708402303583848 0.05321910300325959 0.03476091520282093 0.020422393654937355 0.011973630808074343 0.007172574512613125 0.004117426952608123 0.002204423345366914 0.0012087368131948248 0.0007619127265753561 0.00042623502672549835 0.0003443313341783653 0.0003738581341875605 0.0005042574172789226 0.0007011280080980759 0.0009614150171436438 0.0013339424895266328 0.0018731680166680685 0.0026137159892019968 0.00357671094876302 0.00475392071282566 0.006103819007469896 0.007717583949283101 0.00996652434644405 0.013205451880473071 0.01729118409880111 0.021871898399191694 0.027043933065993456 0.03262863446606337 0.03654237041029715 0.03552916848266973 0.029017297434719536 0.020422393654937355 0.013311339349175035 0.008535272017550813 0.005320251868544285 0.0030673464280526813 0.001658940006948026 0.0009395915246891056 0.0006045988410517467 0.0003235039291855666 0.0002418134659035371 0.0002543426496727932 0.00034716672433379617 0.0004921829205170324 0.0006872824206897245 0.0009616996260649202 0.0013339424895266335 0.0018108488201475747 0.002419859374637202 0.0031929167216776487 0.004098860343354625 0.005121132327984129 0.006439066476751863 0.008340585241485125 0.010834126637829363 0.013543651521091861 0.016108051723821827 0.01825942507356672 0.019358270366481176 0.01852265778312246 0.01569272215250288 0.011973630808074337 0.008535272017550805 0.005769895370865579 0.003619078035058616 0.0020849230176929034 0.0011733734294710801 0.000716279106869684 0.0004787892601050411 0.0002341423494693411 0.00016417085279852694 0.00016975481507747759 0.00023267207177716736 0.0003328103516603717 0.00047655151408292366 0.0006872824206897218 0.0009614150171436403 0.0012775314669896203 0.0016519263713297668 0.002139123729663395 0.002735257380277435 0.003378144218932536 0.004107130107226377 0.005105322245517003 0.006480340695556067 0.008053268662561043 0.00947393406331255 0.010451266211617084 0.010762009478327433 0.010237380254440182 0.008932914694551077 0.00717257451261312 0.005320251868544283 0.003619078035058618 0.0022442729591142315 0.0013144301327347944 0.0007970905713095697 0.0005328767055493034 0.0003650484672224121 0.0001533803348213049 0.00010991083482162614 0.00012122019196754284 0.00016700154404711352 0.00023265115775077482 0.00033281035166038024 0.0004921829205170339 0.0007011280080980825 0.0009232854720992042 0.001158357259161511 0.0014604937925648475 0.0018515398190606155 0.0022749560695569816 0.002694549901459462 0.003183343133357701 0.0038416187382218914 0.0046406628622145014 0.005402100311051643 0.005918258582049218 0.006050605342605949 0.005751359337704072 0.0050659903989462764 0.004117426952608124 0.0030673464280526813 0.002084923017692905 0.0013144301327347935 0.0008160465074447729 0.0005378107763059004 0.000374636362812329 0.00024962684893334487 0.00008836635431708842 0.00007319711621452625 0.00009227334361630013 0.00012639541981940755 0.00016700154404711116 0.00023267207177717433 0.000347166724333795 0.0005042574172789249 0.0006692846682037828 0.0008297072438039165 0.0010219478720986744 0.0012781043115712553 0.0015723081188699904 0.0018521698782702968 0.0021135152535489096 0.0023998563965444805 0.0027284479596148977 0.003050365760317207 0.0032732159028392186 0.003310130795263662 0.003119967987069991 0.0027252012978601532 0.002204423345366912 0.00165894000694803 0.001173373429471085 0.000797090571309571 0.0005378107763059011 0.00036446551343221906 0.00023897829057065376 0.00014552776986353152 0.000049264696090275354 0.00005081018743245721 0.00006872525418735778 0.00009227334361630073 0.00012122019196754076 0.0001697548150774814 0.0002543426496727943 0.0003738581341875585 0.000505294436966101 0.0006317512268016302 0.0007668541041885754 0.000935020426543982 0.0011362470259058464 0.0013402003972896419 0.0015145682355305603 0.0016503940612064148 0.0017585618402871396 0.0018474983033848486 0.0018998605429482007 0.0018739209437563787 0.001735580420641968 0.0014949492493011281 0.0012087368131948242 0.0009395915246891073 0.000716279106869686 0.0005328767055493036 0.00037463636281232876 0.00023897829057065395 0.00013665578847337363 0.00007494986032960139 0.00003494468682887023 0.00003927679355652218 0.00005081018743245188 0.00007319711621452404 0.00010991083482162082 0.0001641708527985288 0.00024181346590353332 0.000344331334178365 0.0004633564042267047 0.0005841060597842235 0.0006992403467680941 0.0008161527036543527 0.0009448279369217385 0.0010815579702260155 0.0012018072025311354 0.0012756356763438013 0.0012975573945890556 0.0012883678922504765 0.0012632413019571852 0.0012098210104861283 0.0011029764516615182 0.0009416347748850439 0.000761912726575356 0.0006045988410517475 0.00047878926010503823 0.0003650484672224073 0.0002496268489333397 0.00014552776986352753 0.00007494986032959752 0.000042337647069587214 0.00003710588664386375 0.000037323660304481904 0.000046397958466131654 0.00007921512669109695 0.00013968876242537675 0.00021814488333107016 0.0003040176982251506 0.00040141036955367027 0.0005240339424709018 0.0006638652867328211 0.0007842331047055555 0.0008602438311349457 0.0009088671603585674 0.0009628131037069283 0.0010223797079019596 0.0010503100328411764 0.0010223797079019561 0.0009628131037069179 0.0009088671603585743 0.0008602438311349492 0.0007842331047055624 0.0006638652867328142 0.0005240339424708931 0.00040141036955366853 0.0003040176982251541 0.0002181448833310693 0.00013968876242537675 0.00007921512669109869 0.00004639795846612862 0.000037323660304483097 0.00003732366030447986 0.000044717298415450566 0.00007386269411413186 0.00013880284057140772 0.00023905748114610843 0.00035604221904844273 0.00047351329888211595 0.0006011759042085202 0.000760976138198984 0.0009450532555019045 0.0011033690494170387 0.0011893217655105878 0.0012098210104861259 0.0012065670294402957 0.0011973429792128585 0.001157905179173963 0.0010646588843713904 0.0009370424568941306 0.0008161527036543685 0.0007164119706880244 0.0006206635119981585 0.0005122217700908306 0.00039576518507255197 0.0002890580940773193 0.00020289046441401552 0.00013719159990130614 0.00008970530400963101 0.00005906705547390598 0.000043658645204250014 0.00003818257149020234 0.00004639795846613056 0.00007386269411413363 0.00013267912482791932 0.00022811134622592307 0.00036059264973204114 0.0005270594962774825 0.0007261632918973068 0.0009632349493911841 0.0012408721734380704 0.001531174685949792 0.0017673346539450962 0.0018846393517467934 0.0018739209437563817 0.001779416797872288 0.0016478117139200634 0.0014941165032954509 0.001316568095776341 0.001123903496920179 0.0009350204265440169 0.000765450346807275 0.0006199289354965262 0.0004938979088174652 0.00037963807815661276 0.0002744930032920338 0.00018599940050380818 0.00012413553643969883 0.00008929388863324511 0.00007040658488428744 0.000055340012144677166 0.000043658645204255035 0.00007921512669109862 0.00013880284057141054 0.0002281113462259221 0.00034510117949246327 0.0005189558821759174 0.0008006309005604108 0.0012183841389811444 0.0017456059351057588 0.002315502914080523 0.0028419649976218837 0.003228437579871228 0.0033938858370837046 0.0033101307952636467 0.0030170576322447757 0.002606494385281724 0.0021839809405514573 0.0018231338833620237 0.001534031609806594 0.001278104311571264 0.0010287461375447155 0.0008023405097078695 0.0006217834696838581 0.00047810797513388837 0.00034950119417326937 0.0002365232571313324 0.00015654031394054719 0.00011453422882452295 0.00009168287533174011 0.00007040658488428368 0.00005906705547390712 0.0001396887624253762 0.00023905748114610862 0.00036059264973203783 0.0005189558821759176 0.0008095426567044855 0.0013576193121938474 0.0022129533178503204 0.003279908219514548 0.004379127580087876 0.005337764510923142 0.006004520936120347 0.006258842946612751 0.00605060534260595 0.00542111061335433 0.004510620325940202 0.0035528377214148134 0.002773962381173283 0.002240658034798409 0.001851539819060631 0.0014902181260945345 0.0011458895699827545 0.0008696279545382277 0.0006636557209989187 0.000488359505814749 0.00033287461528253644 0.00021758712571749028 0.00015191940053496268 0.00011453422882452252 0.0000892938886332413 0.00008970530400963142 0.00021814488333106802 0.00035604221904843823 0.000527059496277473 0.0008006309005604044 0.0013576193121938396 0.0023815163812630066 0.0038961044023771464 0.005744944457247076 0.007727115860575966 0.009578011906467723 0.010884820552833414 0.011287232360719148 0.010762009478327431 0.009543175734881953 0.007885851634352308 0.006089358996347635 0.0045374197874653065 0.0034530126341166235 0.002735257380277469 0.0021621361682891077 0.0016434510892206998 0.0012246577971138633 0.0009209194452240764 0.0006808862036298897 0.0004755767626457468 0.0003177350737324117 0.00021758712571749548 0.0001565403139405508 0.00012413553643969889 0.00013719159990130606 0.00030401769822515425 0.0004735132988821201 0.0007261632918973047 0.001218384138981149 0.002212953317850322 0.0038961044023771547 0.006270310653227986 0.009383109611456554 0.01335518657440018 0.01767499640965907 0.020780306627006542 0.021259632970865458 0.019358270366481176 0.016410606487398924 0.013300080450640439 0.010250489182735956 0.007517489748370414 0.0054609172296757715 0.004098860343354649 0.003137278091103773 0.0023548311695479208 0.0017314033525384282 0.0012792562992190227 0.0009448983181505419 0.0006797234220084422 0.00047557676264574404 0.0003328746152825414 0.0002365232571313364 0.00018599940050380534 0.0002028904644140138 0.0004014103695536724 0.00060117590420852 0.0009632349493911804 0.0017456059351057594 0.003279908219514547 0.00574494445724708 0.009383109611456556 0.015142111007148459 0.024168342736126208 0.035232198896082 0.04315798504401966 0.043169193618306186 0.036542370410297134 0.028345846801708426 0.021600447001363182 0.016313578902386966 0.011899632005612577 0.00844949598547021 0.006103819007469923 0.004548630795370629 0.0033890596656994294 0.0024757860587300527 0.0017953659478324702 0.0013044219419490908 0.0009448983181505376 0.000680886203629895 0.0004883595058147552 0.00034950119417327197 0.0002744930032920325 0.000289058094077311 0.0005240339424709029 0.000760976138198989 0.001240872173438061 0.0023155029140805258 0.004379127580087877 0.007727115860575976 0.013355186574400192 0.02416834273612621 0.04358793167375025 0.0689697734916783 0.0870489735205125 0.0854511061047993 0.06795136304519561 0.048152048763744876 0.03380867422689517 0.024476616453336097 0.01767088697656698 0.012455354564246363 0.008851163896473186 0.006514726734788957 0.0048525046306713586 0.003543537105845856 0.002531991081847747 0.00179536594783247 0.0012792562992190203 0.0009209194452240627 0.0006636557209989281 0.00047810797513390306 0.0003796380781566135 0.0003957651850725536 0.0006638652867328161 0.0009450532555018901 0.0015311746859497752 0.002841964997621872 0.0053377645109231285 0.009578011906467704 0.01767499640965905 0.03523219889608198 0.06896977349167825 0.11441220866588603 0.14696938808169444 0.14349707688030014 0.11099495791676929 0.07491270404560924 0.04979656952952348 0.034771922171507 0.024833276124295887 0.01750996775001732 0.012428670230404584 0.009130819952328822 0.006814124455876273 0.004986649428306473 0.003543537105845849 0.0024757860587300454 0.001731403352538404 0.001224657797113856 0.0008696279545382128 0.0006217834696838555 0.0004938979088174678 0.0005122217700908156 0.0007842331047055596 0.0011033690494170344 0.0017673346539450825 0.003228437579871227 0.006004520936120338 0.01088482055283341 0.02078030662700654 0.043157985044019645 0.08704897352051247 0.14696938808169446 0.19105889057568612 0.18859427889568733 0.14741724073021092 0.10018220949061551 0.06659102873504195 0.04632166075690754 0.033086717254703336 0.023497897295981156 0.016841301099417096 0.012442521099413757 0.009298505535895457 0.006814124455876288 0.00485250463067136 0.003389059665699436 0.0023548311695479225 0.0016434510892206922 0.0011458895699827541 0.0008023405097078705 0.0006199289354965183 0.0006206635119981419 0.0008602438311349448 0.0011893217655105724 0.0018846393517467858 0.003393885837083698 0.006258842946612738 0.011287232360719122 0.021259632970865448 0.04316919361830617 0.0854511061047993 0.14349707688030014 0.1885942788956873 0.19153674991461134 0.15678116150870314 0.1128164497428701 0.0788799121953625 0.05648559203452078 0.040967048702471184 0.02969042960424606 0.021890767984102767 0.01652515210730497 0.012442521099413755 0.009130819952328824 0.0065147267347889564 0.004548630795370634 0.0031372780911037646 0.002162136168289122 0.0014902181260945187 0.0010287461375447086 0.0007654503468072667 0.0007164119706880113 0.0009088671603585753 0.00120982101048613 0.0018739209437563802 0.0033101307952636662 0.006050605342605957 0.010762009478327431 0.01935827036648119 0.036542370410297134 0.06795136304519564 0.1109949579167693 0.14741724073021095 0.15678116150870314 0.13854009018097044 0.10918928639667481 0.08242112353905497 0.061744137967736784 0.04623882046826719 0.03518834279291235 0.027636802532900438 0.021890767984102763 0.01684130109941709 0.012428670230404571 0.008851163896473172 0.006103819007469919 0.004098860343354648 0.0027352573802774637 0.001851539819060635 0.0012781043115712696 0.0009350204265440066 0.0008161527036543635 0.0009628131037069247 0.0012065670294402885 0.0017794167978722817 0.003017057632244772 0.005421110613354318 0.009543175734881944 0.016410606487398918 0.028345846801708423 0.04815204876374486 0.07491270404560921 0.10018220949061549 0.11281644974287013 0.10918928639667481 0.09479720627444045 0.0770637825693041 0.06076976938801452 0.048458000595130814 0.040603591542576076 0.03518834279291235 0.029690429604246064 0.023497897295981156 0.01750996775001732 0.012455354564246365 0.00844949598547022 0.005460917229675774 0.0034530126341166464 0.0022406580347984176 0.001534031609806594 0.0011239034969201802 0.0009370424568941268 0.001022379707901963 0.00119734297921286 0.0016478117139200612 0.0026064943852817327 0.004510620325940203 0.007885851634352301 0.013300080450640447 0.021600447001363182 0.03380867422689519 0.04979656952952347 0.06659102873504197 0.07887991219536249 0.08242112353905497 0.07706378256930409 0.06663205520314516 0.05654257027060355 0.05061792172031551 0.04845800059513082 0.04623882046826719 0.0409670487024712 0.033086717254703364 0.024833276124295905 0.017670886976566998 0.011899632005612589 0.007517489748370425 0.004537419787465322 0.002773962381173299 0.0018231338833620326 0.001316568095776346 0.0010646588843713936 0.0010503100328411767 0.0011579051791739598 0.0014941165032954506 0.0021839809405514612 0.003552837721414813 0.0060893589963476324 0.010250489182735956 0.01631357890238697 0.024476616453336104 0.034771922171506986 0.04632166075690752 0.05648559203452079 0.061744137967736784 0.0607697693880145 0.056542570270603554 0.05427095251989683 0.056542570270603554 0.06076976938801451 0.06174413796773679 0.05648559203452079 0.04632166075690755 0.034771922171507 0.02447661645333611 0.01631357890238698 0.01025048918273596 0.006089358996347648 0.0035528377214148164 0.002183980940551458 0.0014941165032954543 0.001157905179173958 0.0010223797079019642 0.0010646588843713977 0.0013165680957763434 0.0018231338833620367 0.002773962381173296 0.004537419787465304 0.0075174897483704225 0.011899632005612575 0.017670886976566994 0.024833276124295874 0.03308671725470334 0.040967048702471184 0.04623882046826719 0.04845800059513079 0.050617921720315505 0.05654257027060355 0.06663205520314516 0.0770637825693041 0.08242112353905495 0.0788799121953625 0.06659102873504198 0.049796569529523486 0.033808674226895194 0.021600447001363196 0.013300080450640451 0.007885851634352318 0.004510620325940205 0.0026064943852817323 0.0016478117139200658 0.001197342979212861 0.0009628131037069259 0.0009370424568941329 0.0011239034969201783 0.0015340316098065975 0.0022406580347984154 0.00345301263411663 0.00546091722967577 0.008449495985470208 0.012455354564246363 0.017509967750017306 0.023497897295981153 0.029690429604246067 0.03518834279291236 0.04060359154257606 0.04845800059513082 0.06076976938801451 0.0770637825693041 0.09479720627444044 0.10918928639667481 0.11281644974287011 0.10018220949061551 0.07491270404560921 0.048152048763744876 0.028345846801708433 0.016410606487398918 0.009543175734881958 0.005421110613354316 0.0030170576322447735 0.0017794167978722863 0.0012065670294402907 0.0009088671603585768 0.0008161527036543716 0.0009350204265440073 0.0012781043115712716 0.001851539819060634 0.0027352573802774524 0.004098860343354646 0.006103819007469911 0.008851163896473174 0.012428670230404565 0.01684130109941709 0.021890767984102773 0.027636802532900438 0.035188342792912344 0.046238820468267196 0.061744137967736784 0.08242112353905497 0.10918928639667481 0.13854009018097044 0.15678116150870314 0.14741724073021098 0.1109949579167693 0.06795136304519565 0.03654237041029715 0.01935827036648119 0.010762009478327441 0.006050605342605949 0.003310130795263669 0.0018739209437563854 0.001209821010486133 0.0008602438311349458 0.0007164119706880196 0.0007654503468072708 0.0010287461375447064 0.001490218126094518 0.0021621361682891186 0.0031372780911037633 0.004548630795370626 0.006514726734788963 0.009130819952328804 0.012442521099413757 0.016525152107304965 0.021890767984102773 0.029690429604246043 0.04096704870247119 0.056485592034520776 0.07887991219536251 0.11281644974287011 0.15678116150870314 0.19153674991461134 0.1885942788956873 0.1434970768803001 0.08545110610479931 0.043169193618306186 0.021259632970865448 0.011287232360719133 0.006258842946612726 0.0033938858370837002 0.0018846393517467908 0.0011893217655105732 0.0007842331047055605 0.000620663511998149 0.0006199289354965262 0.0008023405097078653 0.0011458895699827541 0.0016434510892207035 0.002354831169547925 0.003389059665699428 0.00485250463067137 0.006814124455876269 0.009298505535895459 0.012442521099413748 0.01684130109941709 0.02349789729598114 0.03308671725470335 0.04632166075690753 0.06659102873504197 0.1001822094906155 0.14741724073021095 0.18859427889568733 0.19105889057568612 0.14696938808169446 0.08704897352051251 0.04315798504401966 0.020780306627006546 0.010884820552833416 0.0060045209361203255 0.003228437579871228 0.0017673346539450884 0.0011033690494170328 0.0006638652867328172 0.0005122217700908201 0.0004938979088174777 0.0006217834696838486 0.0008696279545382126 0.0012246577971138767 0.0017314033525384102 0.0024757860587300467 0.0035435371058458605 0.004986649428306458 0.006814124455876292 0.009130819952328818 0.012428670230404587 0.017509967750017317 0.024833276124295905 0.034771922171507 0.0497965695295235 0.07491270404560921 0.11099495791676933 0.1434970768803001 0.14696938808169444 0.114412208665886 0.06896977349167828 0.03523219889608198 0.01767499640965906 0.009578011906467707 0.005337764510923122 0.002841964997621871 0.0015311746859497817 0.0009450532555018865 0.0005240339424709039 0.00039576518507255544 0.00037963807815662273 0.00047810797513389645 0.0006636557209989272 0.0009209194452240858 0.001279256299219027 0.0017953659478324717 0.0025319910818477555 0.0035435371058458393 0.00485250463067136 0.006514726734788946 0.00885116389647317 0.012455354564246351 0.01767088697656699 0.024476616453336097 0.03380867422689518 0.048152048763744876 0.06795136304519564 0.0854511061047993 0.0870489735205125 0.06896977349167828 0.04358793167375026 0.02416834273612621 0.013355186574400197 0.00772711586057598 0.004379127580087873 0.0023155029140805245 0.001240872173438067 0.0007609761381989853 0.00040141036955367325 0.0002890580940773114 0.00027449300329204015 0.0003495011941732663 0.0004883595058147534 0.0006808862036299146 0.0009448983181505471 0.001304421941949099 0.0017953659478324815 0.0024757860587300475 0.0033890596656994338 0.004548630795370619 0.0061038190074699196 0.00844949598547021 0.01189963200561258 0.016313578902386973 0.021600447001363186 0.02834584680170842 0.03654237041029714 0.04316919361830618 0.04315798504401964 0.03523219889608198 0.02416834273612621 0.015142111007148457 0.009383109611456561 0.005744944457247081 0.0032799082195145435 0.001745605935105757 0.0009632349493911854 0.0006011759042085173 0.00030401769822515517 0.00020289046441401343 0.00018599940050381192 0.00023652325713133075 0.0003328746152825388 0.00047557676264575635 0.0006797234220084539 0.0009448983181505466 0.0012792562992190398 0.0017314033525384085 0.002354831169547952 0.0031372780911037568 0.004098860343354656 0.005460917229675762 0.007517489748370426 0.010250489182735951 0.013300080450640454 0.016410606487398914 0.0193582703664812 0.02125963297086543 0.020780306627006542 0.01767499640965904 0.013355186574400189 0.009383109611456547 0.006270310653227992 0.003896104402377152 0.0022129533178503196 0.0012183841389811463 0.0007261632918973092 0.00047351329888211893 0.00021814488333106823 0.00013719159990130446 0.00012413553643970395 0.0001565403139405443 0.00021758712571749326 0.0003177350737324214 0.000475576762645756 0.0006808862036299019 0.0009209194452240968 0.0012246577971138635 0.0016434510892207198 0.002162136168289102 0.0027352573802774645 0.0034530126341166174 0.004537419787465308 0.006089358996347628 0.007885851634352311 0.009543175734881946 0.010762009478327441 0.01128723236071913 0.01088482055283341 0.009578011906467706 0.007727115860575972 0.005744944457247068 0.0038961044023771525 0.002381516381263004 0.0013576193121938352 0.0008006309005604021 0.0005270594962774763 0.0003560422190484379 0.00013968876242537637 0.00008970530400962941 0.00008929388863324627 0.00011453422882451631 0.000151919400534961 0.0002175871257174981 0.00033287461528254175 0.000488359505814756 0.0006636557209989332 0.0008696279545382155 0.0011458895699827604 0.0014902181260945163 0.0018515398190606385 0.002240658034798414 0.002773962381173293 0.003552837721414817 0.004510620325940204 0.005421110613354313 0.0060506053426059555 0.00625884294661272 0.006004520936120328 0.005337764510923121 0.004379127580087869 0.00327990821951454 0.002212953317850325 0.0013576193121938428 0.0008095426567044819 0.0005189558821759161 0.000360592649732041 0.00023905748114610967 0.00007921512669109814 0.00005906705547390443 0.00007040658488428818 0.000091682875331734 0.00011453422882452135 0.00015654031394055326 0.0002365232571313338 0.00034950119417326807 0.00047810797513389477 0.0006217834696838552 0.0008023405097078668 0.001028746137544718 0.0012781043115712668 0.0015340316098066042 0.001823133883362023 0.0021839809405514586 0.002606494385281726 0.0030170576322447714 0.0033101307952636593 0.0033938858370836885 0.0032284375798712172 0.002841964997621874 0.00231550291408052 0.0017456059351057555 0.0012183841389811487 0.0008006309005604074 0.0005189558821759151 0.0003451011794924622 0.000228111346225924 0.00013880284057141143 0.000046397958466130475 0.000043658645204253124 0.0000553400121446822 0.00007040658488428272 0.00008929388863324582 0.00012413553643970208 0.00018599940050380802 0.00027449300329203445 0.0003796380781566229 0.0004938979088174763 0.0006199289354965255 0.0007654503468072535 0.0009350204265439997 0.0011239034969201696 0.0013165680957763432 0.0014941165032954405 0.001647811713920058 0.0017794167978722728 0.001873920943756391 0.001884639351746783 0.0017673346539450892 0.001531174685949782 0.001240872173438061 0.0009632349493911834 0.0007261632918973096 0.0005270594962774799 0.0003605926497320403 0.00022811134622592315 0.00013267912482792 0.00007386269411413491 0.000037323660304479675 0.00003818257149020072 0.000043658645204254106 0.00005906705547390262 0.00008970530400963086 0.0001371915999013078 0.00020289046441401243 0.00028905809407731313 0.0003957651850725546 0.0005122217700908315 0.0006206635119981501 0.0007164119706880192 0.0008161527036543626 0.0009370424568941328 0.001064658884371393 0.0011579051791739616 0.001197342979212855 0.0012065670294402842 0.0012098210104861387 0.001189321765510577 0.001103369049417036 0.0009450532555018878 0.0007609761381989821 0.0006011759042085234 0.00047351329888212023 0.00035604221904844024 0.00023905748114610824 0.0001388028405714085 0.0000738626941141306 0.00004471729841545174 0.000036555955600153605 0.00003557185750931516 0.00004131938524831941 0.00006927841106991485 0.000124436977143053 0.0001982325344744443 0.00027877854625725507 0.0003688317936540765 0.0004837211007552352 0.0006161255593246789 0.0007258557129460955 0.0007842331047055624 0.0008116561588309285 0.000848652587863024 0.0008995969267711901 0.0009254338743022589 0.0008995969267711866 0.0008486525878630205 0.0008116561588309215 0.0007842331047055555 0.0007258557129460746 0.0006161255593246651 0.0004837211007552404 0.0003688317936540791 0.00027877854625724813 0.0001982325344744365 0.00012443697714304976 0.00006927841106991637 0.000041319385248317136 0.000035571857509317326 0.0000355718575093092 0.000043235477902206925 0.00006945342397726398 0.00012834877183813808 0.0002207519181065114 0.0003314013116227033 0.00044462886976899416 0.0005666602319166238 0.000717866529654296 0.0008912224146887258 0.0010359122065182276 0.0011033690494170495 0.0011029764516615273 0.0010826685402583597 0.0010633634004519037 0.001018928388904485 0.0009248564411887989 0.0008039528511211491 0.000699240346768104 0.0006206635119981574 0.0005424395332519846 0.00044536251883483445 0.0003399973189839407 0.00024777767599728844 0.00017592000902817687 0.00011896774347643264 0.0000749864214438372 0.00004701150675251168 0.000035385816829213976 0.00003378055041345974 0.000041319385248315943 0.00006945342397726527 0.00012514458310738689 0.00021384675885703405 0.0003382569558404387 0.0004984623059909844 0.0006923623475488188 0.0009202033550585023 0.0011822360315786305 0.0014533516270413848 0.001670054881074572 0.001767334653945095 0.0017355804206419798 0.001622455124164984 0.001477557116689311 0.0013145279401521155 0.001131106546132808 0.00094075872391416 0.0007668541041885822 0.0006199289354965128 0.0004936140235558583 0.00038202411574575387 0.0002867002807287356 0.000208253119666945 0.00014536777784027055 0.00009890637973825491 0.00006978108319975405 0.000053486773049691144 0.00004244351625248585 0.000035385816829219614 0.00006927841106991099 0.000128348771838139 0.00021384675885703462 0.00032450718525868527 0.0004915278415428217 0.0007669655867827592 0.0011766546693540256 0.0016880521502273182 0.002231884518609751 0.0027278262838996785 0.0030869250399333317 0.003228437579871225 0.003119967987070008 0.0028018161266351984 0.002369722530313525 0.0019295502396633611 0.0015544662428557871 0.0012617286215816442 0.001021947872098684 0.0008023405097078598 0.000602669709140137 0.0004430836000988306 0.00032749602997659037 0.0002396491336290469 0.0001669792523901127 0.0001131898287586416 0.00008400938969302717 0.00006835590124955515 0.00005348677304968547 0.00004701150675251182 0.0001244369771430477 0.00022075191810651 0.00033825695584043517 0.0004915278415428176 0.0007753241069806382 0.0013149137141692014 0.0021575330962007866 0.0032006777697295282 0.004261837790878288 0.005174646336827477 0.005795395785142989 0.006004520936120348 0.005751359337704081 0.005081308636276993 0.004139463137881502 0.003158287344604468 0.0023618270227441945 0.0018252040088143592 0.0014604937925648631 0.0011458895699827706 0.0008478810904686457 0.0006090221462856671 0.0004446632000163215 0.0003238747221292839 0.00022295862859127215 0.00014673972099953124 0.00010514847136896128 0.00008400938969302996 0.00006978108319975004 0.0000749864214438389 0.0001982325344744429 0.00033140131162270566 0.0004984623059909865 0.0007669655867827614 0.0013149137141692062 0.0023263946674731356 0.003824457020248542 0.005648678265475138 0.007593348891884835 0.009386166372071913 0.010602809983184995 0.01088482055283343 0.01023738025444019 0.008929833570272602 0.0072308855036870255 0.005425288999380874 0.00387718462972183 0.002810080016190194 0.0021391237296633915 0.001643451089220701 0.0012086120836674228 0.0008625415369535796 0.0006269184999834714 0.00045802707986649657 0.0003185229014366694 0.0002106915329121225 0.0001467397209995375 0.00011318982875864932 0.00009890637973825788 0.00011896774347644001 0.0002787785462572546 0.0004446288697689947 0.0006923623475488165 0.0011766546693540252 0.0021575330962007853 0.003824457020248539 0.006190457485260748 0.009317982583385741 0.013326033228026425 0.01764607749326306 0.02061112201000015 0.020780306627006556 0.018522657783122468 0.015326377141967946 0.012128142883814001 0.009106667450547161 0.006443731463249307 0.004462883841154415 0.0031929167216776496 0.0023548311695479537 0.0017124336763814718 0.001220849804782795 0.0008847228995316143 0.0006500135096252639 0.0004639337960051206 0.0003185229014366623 0.00022295862859127437 0.00016697925239012162 0.00014536777784027248 0.0001759200090281841 0.00036883179365408036 0.0005666602319166272 0.0009202033550585023 0.00168805215022732 0.003200677769729527 0.005648678265475139 0.009317982583385747 0.015236007343764202 0.024603902216747155 0.03602771739152604 0.04388257004641343 0.043157985044019666 0.03552916848266975 0.026619531064699158 0.0196188113180979 0.01439934812476545 0.010179124463848836 0.00692315307359643 0.004753920712825662 0.0033890596656994355 0.002441698447335629 0.0017395256062650163 0.0012460069125889602 0.0009038676023293324 0.0006500135096252522 0.00045802707986648437 0.00032387472212927514 0.0002396491336290505 0.00020825311966694867 0.0002477776759972914 0.0004837211007552424 0.0007178665296542967 0.001182236031578628 0.002231884518609749 0.004261837790878285 0.007593348891884837 0.013326033228026437 0.02460390221674716 0.045107834388609394 0.07184481865601182 0.09023345115385849 0.08704897352051252 0.06708402303583849 0.04551782647970809 0.030550059905471987 0.021340499097863355 0.014947087410735692 0.010148692673302805 0.006884090603571328 0.004852504630671365 0.003500116031062478 0.0024978119909227913 0.001761970906758676 0.0012460069125889697 0.0008847228995316081 0.0006269184999834524 0.00044466320001631886 0.0003274960299765992 0.00028670028072873353 0.00033999731898394145 0.0006161255593246745 0.0008912224146887227 0.0014533516270413803 0.002727826283899674 0.0051746463368274615 0.009386166372071902 0.017646077493263045 0.03602771739152602 0.07184481865601178 0.12002991041620263 0.15337842354304515 0.14696938808169452 0.10979393375630832 0.07046765868336344 0.04435217915922054 0.02968272381980741 0.020572286992175944 0.014055945234431355 0.009603227887007518 0.006814124455876285 0.0049604238161526076 0.0035620064684013246 0.0024978119909228 0.0017395256062650295 0.001220849804782795 0.0008625415369535896 0.0006090221462856566 0.0004430836000988339 0.0003820241157457625 0.0004453625188348316 0.0007258557129460841 0.0010359122065182241 0.0016700548810745651 0.003086925039933326 0.005795395785142971 0.010602809983184988 0.02061112201000014 0.04388257004641341 0.09023345115385843 0.15337842354304515 0.19796516962779334 0.1910588905756862 0.143461663771684 0.09217668859203688 0.05780088809326291 0.03855471669697163 0.026834614134389638 0.018577243399965797 0.012911808749935779 0.009298505535895465 0.00684446046764251 0.004960423816152609 0.0035001160310624735 0.0024416984473356463 0.0017124336763814849 0.0012086120836674063 0.0008478810904686604 0.0006026697091401616 0.0004936140235558659 0.0005424395332519921 0.0007842331047055572 0.0011033690494170372 0.001767334653945088 0.0032284375798712277 0.0060045209361203385 0.010884820552833414 0.020780306627006546 0.04315798504401965 0.08704897352051251 0.14696938808169446 0.19105889057568615 0.18859427889568733 0.14741724073021098 0.10018220949061551 0.06659102873504197 0.046321660756907544 0.03308671725470335 0.023497897295981167 0.016841301099417096 0.012442521099413769 0.009298505535895469 0.006814124455876281 0.004852504630671365 0.003389059665699442 0.002354831169547931 0.001643451089220707 0.001145889569982753 0.0008023405097078632 0.0006199289354965219 0.0006206635119981462 0.000811656158830915 0.0011029764516615216 0.0017355804206419657 0.0031199679870699947 0.005751359337704072 0.01023738025444018 0.018522657783122464 0.03552916848266974 0.06708402303583848 0.10979393375630832 0.143461663771684 0.14741724073021098 0.1242530445913938 0.09348758096382308 0.06866773887166151 0.051225832259196635 0.03834686322647694 0.028649682336106597 0.021771773699975263 0.01684130109941709 0.012911808749935796 0.009603227887007527 0.006884090603571321 0.004753920712825661 0.0031929167216776517 0.002139123729663389 0.0014604937925648633 0.001021947872098682 0.0007668541041885722 0.0006992403467680955 0.0008486525878630218 0.0010826685402583534 0.00162245512416498 0.0028018161266351966 0.00508130863627699 0.008929833570272596 0.015326377141967936 0.026619531064699154 0.045517826479708076 0.0704676586833634 0.09217668859203684 0.10018220949061551 0.09348758096382308 0.07957358172116913 0.06518714478868119 0.0526548031185631 0.04237773260800205 0.03456537249730394 0.028649682336106593 0.02349789729598116 0.018577243399965804 0.01405594523443135 0.010148692673302807 0.006923153073596439 0.004462883841154424 0.0028100800161902128 0.0018252040088143605 0.0012617286215816476 0.0009407587239141672 0.0008039528511211486 0.0008995969267711849 0.0010633634004518972 0.001477557116689302 0.00236972253031352 0.004139463137881502 0.007230885503687016 0.012128142883814003 0.019618811318097895 0.030550059905471993 0.044352179159220524 0.05780088809326292 0.06659102873504197 0.0686677388716615 0.06518714478868118 0.058745620972737944 0.051887989454072664 0.04639919581004444 0.04237773260800206 0.03834686322647695 0.03308671725470337 0.026834614134389652 0.020572286992175965 0.014947087410735705 0.010179124463848848 0.006443731463249315 0.0038771846297218342 0.002361827022744195 0.0015544662428557952 0.0011311065461328078 0.0009248564411888034 0.0009254338743022519 0.0010189283889044803 0.0013145279401521066 0.0019295502396633546 0.003158287344604469 0.005425288999380865 0.009106667450547149 0.014399348124765444 0.02134049909786334 0.02968272381980739 0.038554716696971615 0.04632166075690752 0.051225832259196635 0.05265480311856309 0.051887989454072664 0.05123786746513384 0.051887989454072664 0.0526548031185631 0.05122583225919664 0.04632166075690754 0.03855471669697162 0.029682723819807397 0.021340499097863355 0.01439934812476545 0.009106667450547154 0.005425288999380878 0.003158287344604463 0.001929550239663349 0.0013145279401521157 0.0010189283889044842 0.0008995969267711861 0.0009248564411888022 0.0011311065461327998 0.0015544662428558012 0.002361827022744202 0.0038771846297218165 0.006443731463249307 0.010179124463848837 0.014947087410735695 0.020572286992175934 0.02683461413438963 0.03308671725470334 0.03834686322647694 0.04237773260800204 0.04639919581004444 0.05188798945407266 0.05874562097273795 0.06518714478868119 0.06866773887166151 0.06659102873504198 0.05780088809326294 0.04435217915922055 0.030550059905472004 0.01961881131809791 0.012128142883814004 0.007230885503687028 0.004139463137881497 0.002369722530313515 0.0014775571166893116 0.0010633634004519024 0.0008486525878630232 0.000803952851121151 0.0009407587239141599 0.0012617286215816528 0.0018252040088143652 0.0028100800161901915 0.004462883841154412 0.00692315307359643 0.010148692673302791 0.014055945234431343 0.018577243399965776 0.023497897295981163 0.02864968233610659 0.034565372497303924 0.04237773260800205 0.05265480311856309 0.06518714478868118 0.07957358172116913 0.09348758096382309 0.1001822094906155 0.09217668859203688 0.07046765868336341 0.0455178264797081 0.026619531064699165 0.015326377141967938 0.008929833570272605 0.005081308636276986 0.0028018161266351906 0.0016224551241649885 0.001082668540258358 0.0008116561588309169 0.0006992403467681019 0.0007668541041885674 0.0010219478720986856 0.001460493792564866 0.002139123729663369 0.003192916721677641 0.004753920712825655 0.00688409060357132 0.009603227887007517 0.01291180874993577 0.016841301099417096 0.02177177369997526 0.028649682336106593 0.03834686322647696 0.05122583225919664 0.06866773887166153 0.09348758096382308 0.12425304459139382 0.14741724073021095 0.14346166377168404 0.10979393375630833 0.0670840230358385 0.035529168482669744 0.01852265778312246 0.01023738025444019 0.005751359337704066 0.0031199679870699895 0.001735580420641973 0.0011029764516615253 0.0007842331047055586 0.0006206635119981534 0.0006199289354965198 0.0008023405097078617 0.0011458895699827528 0.0016434510892206942 0.0023548311695479234 0.0033890596656994303 0.004852504630671367 0.006814124455876277 0.009298505535895452 0.012442521099413762 0.0168413010994171 0.023497897295981153 0.033086717254703364 0.04632166075690754 0.06659102873504198 0.1001822094906155 0.14741724073021098 0.18859427889568733 0.19105889057568615 0.14696938808169446 0.08704897352051251 0.04315798504401965 0.020780306627006542 0.010884820552833423 0.006004520936120331 0.003228437579871222 0.0017673346539450927 0.0011033690494170385 0.000725855712946085 0.0005424395332519972 0.0004936140235558674 0.0006026697091401558 0.0008478810904686588 0.0012086120836674106 0.0017124336763814803 0.0024416984473356394 0.003500116031062482 0.0049604238161526 0.006844460467642506 0.00929850553589546 0.012911808749935779 0.018577243399965786 0.02683461413438965 0.038554716696971615 0.05780088809326293 0.09217668859203687 0.143461663771684 0.19105889057568615 0.1979651696277933 0.15337842354304512 0.09023345115385846 0.04388257004641342 0.02061112201000014 0.010602809983184996 0.0057953957851429655 0.0030869250399333196 0.0016700548810745684 0.0010359122065182224 0.0006161255593246744 0.0004453625188348326 0.0003820241157457662 0.0004430836000988252 0.0006090221462856562 0.0008625415369536079 0.0012208498047827946 0.0017395256062650284 0.0024978119909228004 0.003562006468401324 0.004960423816152609 0.00681412445587629 0.009603227887007527 0.014055945234431346 0.020572286992175955 0.029682723819807397 0.04435217915922056 0.07046765868336341 0.10979393375630833 0.14696938808169444 0.15337842354304512 0.12002991041620258 0.0718448186560118 0.036027717391526014 0.017646077493263048 0.009386166372071904 0.005174646336827461 0.0027278262838996664 0.0014533516270413822 0.0008912224146887185 0.00048372110075524166 0.00033999731898393923 0.0002867002807287375 0.00032749602997659064 0.0004446632000163202 0.0006269184999834747 0.0008847228995316126 0.001246006912588968 0.0017619709067586793 0.0024978119909227956 0.003500116031062479 0.004852504630671364 0.006884090603571323 0.010148692673302796 0.014947087410735697 0.02134049909786335 0.030550059905471997 0.04551782647970808 0.06708402303583849 0.0870489735205125 0.09023345115385845 0.0718448186560118 0.04510783438860939 0.02460390221674716 0.013326033228026439 0.00759334889188484 0.004261837790878287 0.0022318845186097428 0.0011822360315786287 0.0007178665296542925 0.0003688317936540794 0.0002477776759972886 0.00020825311966695258 0.00023964913362904368 0.0003238747221292779 0.0004580270798665073 0.0006500135096252602 0.0009038676023293326 0.001246006912588973 0.0017395256062650273 0.002441698447335647 0.0033890596656994372 0.004753920712825661 0.006923153073596427 0.010179124463848846 0.014399348124765447 0.019618811318097902 0.026619531064699158 0.035529168482669744 0.043157985044019645 0.043882570046413404 0.03602771739152603 0.024603902216747155 0.015236007343764199 0.009317982583385747 0.005648678265475142 0.0032006777697295304 0.001688052150227315 0.0009202033550585025 0.0005666602319166244 0.00027877854625725425 0.00017592000902818273 0.00014536777784027684 0.0001669792523901159 0.00022295862859127868 0.00031852290143668063 0.00046393379600513033 0.0006500135096252618 0.0008847228995316335 0.0012208498047827979 0.0017124336763815024 0.002354831169547917 0.003192916721677661 0.004462883841154403 0.006443731463249317 0.009106667450547147 0.012128142883814013 0.015326377141967927 0.01852265778312248 0.020780306627006518 0.020611122010000135 0.01764607749326303 0.01332603322802643 0.00931798258338573 0.006190457485260748 0.0038244570202485405 0.0021575330962007875 0.0011766546693540221 0.0006923623475488167 0.0004446288697689942 0.0001982325344744418 0.00011896774347643909 0.00009890637973826152 0.00011318982875864426 0.00014673972099954 0.00021069153291213873 0.0003185229014366778 0.00045802707986649955 0.00062691849998349 0.0008625415369535847 0.0012086120836674347 0.001643451089220683 0.002139123729663384 0.0028100800161901768 0.0038771846297218373 0.005425288999380863 0.00723088550368703 0.00892983357027259 0.01023738025444019 0.010884820552833397 0.01060280998318498 0.00938616637207189 0.007593348891884834 0.005648678265475131 0.0038244570202485397 0.002326394667473137 0.0013149137141692045 0.0007669655867827598 0.000498462305990985 0.0003314013116227057 0.00012443697714304694 0.00007498642144383899 0.00006978108319975359 0.0000840093896930257 0.00010514847136896344 0.00014673972099954377 0.00022295862859127708 0.00032387472212927753 0.0004446632000163271 0.0006090221462856554 0.000847881090468675 0.0011458895699827673 0.0014604937925648646 0.001825204008814356 0.002361827022744202 0.0031582873446044627 0.004139463137881507 0.0050813086362769795 0.005751359337704079 0.006004520936120322 0.005795395785142955 0.005174646336827455 0.004261837790878286 0.003200677769729519 0.002157533096200785 0.001314913714169202 0.0007753241069806352 0.0004915278415428176 0.0003382569558404332 0.00022075191810651162 0.00006927841106990965 0.000047011506752511245 0.00005348677304968811 0.00006835590124955128 0.00008400938969302819 0.00011318982875865147 0.00016697925239011807 0.0002396491336290465 0.0003274960299765961 0.00044308360009883416 0.0006026697091401616 0.0008023405097078794 0.0010219478720986965 0.001261728621581665 0.0015544662428557995 0.001929550239663361 0.0023697225303135248 0.0028018161266351867 0.0031199679870699947 0.0032284375798712207 0.0030869250399333087 0.0027278262838996707 0.0022318845186097445 0.0016880521502273152 0.0011766546693540234 0.000766965586782758 0.0004915278415428169 0.00032450718525868597 0.00021384675885703145 0.0001283487718381412 0.000041319385248315476 0.00003538581682921948 0.00004244351625248921 0.000053486773049688854 0.00006978108319975714 0.00009890637973826453 0.00014536777784027852 0.00020825311966694688 0.0002867002807287425 0.0003820241157457652 0.0004936140235558765 0.0006199289354965172 0.0007668541041885844 0.0009407587239141529 0.0011311065461328132 0.0013145279401521074 0.0014775571166893077 0.001622455124164968 0.0017355804206419675 0.0017673346539450847 0.0016700548810745545 0.0014533516270413783 0.0011822360315786316 0.0009202033550584996 0.0006923623475488149 0.0004984623059909811 0.0003382569558404342 0.0002138467588570355 0.00012514458310738442 0.00006945342397726898 0.000035571857509308856 0.0000337805504134586 0.0000353858168292166 0.000047011506752509605 0.00007498642144383934 0.00011896774347644033 0.00017592000902818319 0.0002477776759972869 0.00033999731898393934 0.0004453625188348335 0.0005424395332519976 0.0006206635119981517 0.0006992403467681 0.0008039528511211492 0.0009248564411888036 0.0010189283889044806 0.0010633634004519016 0.0010826685402583495 0.0011029764516615277 0.0011033690494170292 0.001035912206518209 0.0008912224146887179 0.000717866529654296 0.0005666602319166242 0.00044462886976898895 0.0003314013116226965 0.00022075191810650793 0.00012834877183813943 0.00006945342397726169 0.00004323547790221009 0.000028768074973662457 0.000028324619977967112 0.00003439575992661447 0.00006028885013160403 0.00010990207288447541 0.00017526872371933459 0.0002451672234140825 0.00032132396993739265 0.00041701622182258556 0.0005262171083925526 0.0006161255593246772 0.0006638652867328107 0.0006876207794232064 0.0007212546483763883 0.0007667896670978391 0.000789716228224515 0.0007667896670978357 0.0007212546483763918 0.0006876207794232064 0.0006638652867328211 0.0006161255593246668 0.0005262171083925595 0.0004170162218225873 0.0003213239699373866 0.00024516722341408077 0.00017526872371932505 0.00010990207288447606 0.00006028885013160262 0.00003439575992661198 0.000028324619977965486 0.000028324619977969288 0.00003682836488375323 0.00006258753462346968 0.0001179612011765563 0.0002022661710982116 0.000300389900465077 0.00039880592165459305 0.000503031714549414 0.0006296342986623017 0.0007727221740842517 0.0008912224146887254 0.000945053255501897 0.00094163477488504 0.0009218909549822134 0.0009055757124909082 0.0008701737083641827 0.0007900599153244924 0.0006814304005537475 0.0005841060597842247 0.0005122217700908299 0.0004453625188348309 0.00036608700067569856 0.00028173929364136495 0.00020872672490351035 0.00015154206168440856 0.00010322000910759061 0.00006307845147369103 0.00003706462000963355 0.000026711709509458173 0.000025849658985388867 0.000034395759926617156 0.00006258753462347056 0.00011779395139745461 0.00020424986233035655 0.0003206654954183247 0.00046332858412138857 0.0006304765274554577 0.0008239745350408579 0.0010447624265134021 0.0012722104792645395 0.001453351627041393 0.00153117468594978 0.0014949492493011294 0.0013888305176585204 0.0012624736503087134 0.0011270689633863396 0.0009705099287999345 0.0007970503483696879 0.000631751226801641 0.0004938979088174735 0.0003820241157457645 0.0002902993943691713 0.00021817936648991514 0.00016298950258330662 0.00011899803177516696 0.000082369113640634 0.00005473562818607192 0.00003812009777228135 0.00002979625227629649 0.000026711709509460294 0.00006028885013160421 0.00011796120117655539 0.00020424986233035381 0.0003158654422010122 0.0004737128545823659 0.000718187954770966 0.0010719536575662437 0.0015115507963728585 0.0019821064539637784 0.002414862370457804 0.0027278262838996738 0.002841964997621872 0.0027252012978601437 0.002423979187085863 0.002038034982836012 0.0016584905708846669 0.001331445714550177 0.001061253350202495 0.0008297072438039132 0.0006217834696838594 0.00044308360009882023 0.0003100884005310616 0.00022463885487634228 0.00016905754840345927 0.00012439403742308457 0.00008687310358683194 0.0000622432677210635 0.00004802404642698687 0.0000381200977722766 0.00003706462000963173 0.00010990207288447719 0.0002022661710982126 0.0003206654954183231 0.0004737128545823687 0.0007370114712795577 0.001214728941261357 0.0019497470457856601 0.0028634056441512665 0.0038047658255811944 0.004622831473009585 0.0051746463368274685 0.005337764510923129 0.00506599039894628 0.00442297840078409 0.0035655934957543067 0.0026987296766766266 0.00199353869973613 0.0015021101566728304 0.0011583572591615122 0.0008696279545382202 0.0006090221462856684 0.0004103825706411369 0.0002871615092159441 0.00021079146292320332 0.0001510795300416486 0.00010310204404457669 0.00007553666539708584 0.0000622432677210665 0.00005473562818606882 0.00006307845147369061 0.0001752687237193304 0.00030038990046507607 0.00046332858412138656 0.0007181879547709682 0.0012147289412613557 0.002110820674846315 0.0034314450613520202 0.005045103596017067 0.006767615584404145 0.008343439782146935 0.009386166372071895 0.009578011906467702 0.008932914694551073 0.007710433178781151 0.0061719245315102885 0.004570037806178963 0.0032019567330937387 0.0022502321078609775 0.001651926371329788 0.0012246577971138568 0.0008625415369535976 0.0005817603729256054 0.00040315658918495603 0.0002908621346563611 0.00020537152754663638 0.00013978608385999746 0.00010310204404458469 0.0000868731035868409 0.0000823691136406368 0.00010322000910759473 0.0002451672234140804 0.0003988059216545924 0.000630476527455454 0.0010719536575662443 0.0019497470457856573 0.0034314450613520176 0.00552296599352052 0.00824883073013153 0.011664359723122485 0.015258430610257591 0.01764607749326303 0.017674996409659048 0.01569272215250288 0.012938092278920262 0.01017424718397428 0.007546972735349737 0.005225728102749311 0.003504638407223866 0.0024198593746372152 0.0017314033525384113 0.0012208498047827962 0.0008364038989140087 0.000583338631448998 0.0004193721286009111 0.0002970360003487952 0.00020537152754663296 0.0001510795300416534 0.00012439403742308994 0.00011899803177516465 0.0001515420616844099 0.00032132396993738924 0.0005030317145494126 0.0008239745350408541 0.0015115507963728585 0.0028634056441512656 0.005045103596017063 0.008248830730131532 0.013230330906524548 0.0208645964437508 0.02995435275689363 0.03602771739152602 0.03523219889608197 0.029017297434719525 0.021833526348406383 0.016130953814403673 0.011767808214400976 0.008167517098673112 0.005391246813130986 0.0035767109487630376 0.002475786058730046 0.001739525606265023 0.0012060439533125725 0.0008408650019755449 0.0005962452510613948 0.0004193721286009082 0.0002908621346563618 0.00021079146292320551 0.0001690575484034621 0.00016298950258330483 0.0002087267249035111 0.0004170162218225841 0.0006296342986623049 0.0010447624265133965 0.0019821064539637793 0.0038047658255811936 0.006767615584404148 0.011664359723122485 0.0208645964437508 0.037099549047796304 0.057874007302206903 0.07184481865601179 0.06896977349167827 0.05321910300325957 0.0363667313100634 0.02460864991473567 0.017197117076335006 0.011889215069225812 0.007869541377713726 0.005172902766082888 0.003543537105845857 0.0024978119909228 0.0017465327290204908 0.001209958761093527 0.0008408650019755447 0.0005833386314489975 0.00040315658918494546 0.00028716150921594694 0.00022463885487634944 0.00021817936648991287 0.0002817392936413655 0.0005262171083925531 0.0007727221740842528 0.0012722104792645408 0.0024148623704578057 0.004622831473009584 0.008343439782146932 0.015258430610257587 0.02995435275689363 0.05787400730220689 0.09489057748909484 0.12002991041620258 0.11441220866588601 0.0853932486432805 0.05505469128506339 0.034928612089142816 0.02345686346995568 0.01612544317183192 0.010803241393581731 0.007195842070608353 0.004986649428306471 0.00356200646840133 0.002518789882627828 0.0017465327290204895 0.001206043953312578 0.0008364038989139976 0.0005817603729256088 0.0004103825706411209 0.00031008840053105074 0.0002902993943691606 0.0003660870006756813 0.0006161255593246745 0.0008912224146887226 0.0014533516270413792 0.0027278262838996707 0.005174646336827465 0.0093861663720719 0.017646077493263038 0.03602771739152602 0.07184481865601179 0.12002991041620259 0.1533784235430451 0.14696938808169446 0.10979393375630832 0.07046765868336342 0.04435217915922054 0.0296827238198074 0.02057228699217594 0.014055945234431346 0.009603227887007524 0.0068141244558762816 0.004960423816152613 0.0035620064684013185 0.0024978119909228 0.0017395256062650323 0.0012208498047828024 0.0008625415369536012 0.0006090221462856606 0.00044308360009883324 0.0003820241157457617 0.00044536251883483033 0.0006638652867328147 0.0009450532555018928 0.0015311746859497796 0.0028419649976218694 0.00533776451092313 0.009578011906467702 0.017674996409659048 0.03523219889608198 0.06896977349167828 0.11441220866588601 0.14696938808169446 0.14349707688030014 0.11099495791676933 0.07491270404560922 0.0497965695295235 0.03477192217150701 0.024833276124295898 0.01750996775001732 0.012428670230404575 0.009130819952328818 0.006814124455876286 0.0049866494283064625 0.0035435371058458484 0.0024757860587300536 0.0017314033525384158 0.0012246577971138756 0.0008696279545382139 0.0006217834696838496 0.0004938979088174704 0.0005122217700908201 0.0006876207794232075 0.0009416347748850421 0.0014949492493011266 0.002725201297860149 0.0050659903989462825 0.008932914694551075 0.01569272215250288 0.02901729743471953 0.05321910300325958 0.08539324864328052 0.10979393375630832 0.11099495791676932 0.09210298693624547 0.06864617972454862 0.050491304937156894 0.03796747156086694 0.028546983150662536 0.02124810892754824 0.0160522850222263 0.01242867023040457 0.009603227887007529 0.007195842070608347 0.00517290276608289 0.0035767109487630346 0.0024198593746372235 0.0016519263713297915 0.0011583572591615172 0.0008297072438039161 0.0006317512268016397 0.0005841060597842288 0.0007212546483763908 0.0009218909549822148 0.0013888305176585208 0.002423979187085862 0.004422978400784091 0.007710433178781149 0.012938092278920262 0.021833526348406383 0.03636673131006339 0.055054691285063385 0.0704676586833634 0.07491270404560922 0.06864617972454862 0.05804858897493287 0.047938404154548864 0.03927144288015322 0.03181122859580151 0.02580412409566321 0.02124810892754824 0.017509967750017317 0.014055945234431348 0.010803241393581726 0.007869541377713724 0.005391246813130988 0.003504638407223866 0.002250232107860988 0.001502110156672832 0.0010612533502024893 0.0007970503483696889 0.0006814304005537423 0.0007667896670978392 0.0009055757124909097 0.0012624736503087082 0.002038034982836017 0.003565593495754314 0.0061719245315102885 0.010174247183974286 0.016130953814403676 0.024608649914735683 0.03492861208914282 0.04435217915922054 0.04979656952952348 0.05049130493715689 0.04793840415454886 0.043876076872530166 0.03939450951957952 0.03526993486347838 0.0318112285958015 0.02854698315066253 0.0248332761242959 0.02057228699217595 0.01612544317183192 0.011889215069225814 0.008167517098673117 0.005225728102749316 0.003201956733093745 0.0019935386997361375 0.001331445714550179 0.0009705099287999424 0.0007900599153245003 0.0007897162282245144 0.0008701737083641794 0.0011270689633863377 0.0016584905708846628 0.002698729676676629 0.00457003780617896 0.007546972735349735 0.01176780821440097 0.017197117076335 0.023456863469955666 0.029682723819807383 0.03477192217150701 0.037967471560866946 0.03927144288015322 0.039394509519579526 0.03928542528933829 0.039394509519579526 0.039271442880153204 0.03796747156086694 0.034771922171507 0.02968272381980739 0.023456863469955666 0.017197117076335006 0.011767808214400974 0.007546972735349735 0.0045700378061789716 0.002698729676676626 0.0016584905708846623 0.0011270689633863422 0.0008701737083641819 0.0007667896670978396 0.0007900599153244987 0.0009705099287999391 0.00133144571455018 0.001993538699736142 0.0032019567330937295 0.005225728102749315 0.008167517098673109 0.011889215069225805 0.016125443171831916 0.020572286992175944 0.024833276124295884 0.028546983150662533 0.0318112285958015 0.03526993486347838 0.03939450951957952 0.043876076872530166 0.04793840415454885 0.05049130493715688 0.049796569529523486 0.04435217915922054 0.03492861208914284 0.024608649914735686 0.016130953814403683 0.010174247183974285 0.006171924531510298 0.003565593495754312 0.002038034982836017 0.0012624736503087134 0.0009055757124909124 0.0007212546483763909 0.0006814304005537427 0.0007970503483696861 0.0010612533502024908 0.001502110156672837 0.0022502321078609715 0.003504638407223862 0.005391246813130984 0.007869541377713717 0.010803241393581735 0.014055945234431341 0.017509967750017327 0.02124810892754824 0.025804124095663218 0.03181122859580151 0.03927144288015322 0.047938404154548864 0.058048588974932855 0.06864617972454859 0.07491270404560921 0.0704676586833634 0.05505469128506338 0.0363667313100634 0.021833526348406386 0.012938092278920264 0.007710433178781157 0.004422978400784088 0.002423979187085863 0.001388830517658526 0.0009218909549822169 0.0006876207794232083 0.0005841060597842323 0.0006317512268016387 0.0008297072438039172 0.0011583572591615232 0.001651926371329776 0.0024198593746372196 0.0035767109487630324 0.005172902766082889 0.00719584207060836 0.009603227887007527 0.012428670230404585 0.016052285022226304 0.021248108927548245 0.028546983150662543 0.037967471560866946 0.0504913049371569 0.0686461797245486 0.09210298693624547 0.1109949579167693 0.10979393375630833 0.0853932486432805 0.05321910300325958 0.029017297434719532 0.01569272215250288 0.008932914694551082 0.005065990398946277 0.0027252012978601506 0.0014949492493011322 0.0009416347748850447 0.0006638652867328158 0.0005122217700908245 0.0004938979088174713 0.0006217834696838486 0.00086962795453822 0.0012246577971138663 0.0017314033525384135 0.0024757860587300484 0.003543537105845848 0.0049866494283064685 0.006814124455876288 0.009130819952328827 0.012428670230404575 0.017509967750017317 0.024833276124295905 0.034771922171507 0.0497965695295235 0.07491270404560921 0.11099495791676932 0.14349707688030014 0.14696938808169446 0.11441220866588601 0.06896977349167828 0.035232198896081986 0.01767499640965905 0.00957801190646771 0.0053377645109231224 0.0028419649976218716 0.0015311746859497846 0.0009450532555018949 0.0006161255593246757 0.0004453625188348341 0.0003820241157457657 0.00044308360009883 0.000609022146285666 0.0008625415369536038 0.0012208498047828037 0.0017395256062650263 0.0024978119909228004 0.0035620064684013294 0.004960423816152609 0.006814124455876284 0.009603227887007522 0.01405594523443134 0.020572286992175948 0.029682723819807397 0.044352179159220545 0.07046765868336341 0.10979393375630832 0.14696938808169446 0.15337842354304512 0.1200299104162026 0.0718448186560118 0.036027717391526035 0.01764607749326304 0.009386166372071906 0.005174646336827459 0.0027278262838996733 0.0014533516270413844 0.0008912224146887232 0.0005262171083925543 0.0003660870006756829 0.00029029939436916693 0.00031008840053104673 0.0004103825706411251 0.0005817603729256219 0.0008364038989140025 0.0012060439533125773 0.0017465327290204936 0.0025187898826278454 0.003562006468401335 0.004986649428306465 0.007195842070608359 0.01080324139358173 0.016125443171831927 0.023456863469955673 0.034928612089142844 0.05505469128506338 0.08539324864328052 0.11441220866588601 0.12002991041620259 0.09489057748909482 0.057874007302206903 0.02995435275689363 0.015258430610257596 0.008343439782146937 0.004622831473009581 0.002414862370457806 0.0012722104792645455 0.0007727221740842516 0.00041701622182258475 0.00028173929364136544 0.00021817936648992016 0.0002246388548763457 0.00028716150921594965 0.000403156589184961 0.0005833386314490023 0.0008408650019755465 0.0012099587610935284 0.0017465327290204944 0.002497811990922797 0.003543537105845849 0.005172902766082889 0.00786954137771372 0.011889215069225816 0.017197117076335006 0.024608649914735686 0.0363667313100634 0.05321910300325958 0.0689697734916783 0.0718448186560118 0.05787400730220692 0.037099549047796304 0.020864596443750803 0.011664359723122492 0.006767615584404154 0.003804765825581194 0.001982106453963779 0.0010447624265134006 0.0006296342986623027 0.0003213239699373899 0.00020872672490351098 0.00016298950258331223 0.00016905754840345976 0.00021079146292320682 0.0002908621346563778 0.00041937212860091534 0.000596245251061401 0.00084086500197555 0.0012060439533125842 0.0017395256062650267 0.002475786058730054 0.003576710948763036 0.005391246813130979 0.008167517098673114 0.011767808214400977 0.016130953814403683 0.021833526348406386 0.029017297434719532 0.035232198896081986 0.03602771739152603 0.02995435275689364 0.020864596443750803 0.013230330906524552 0.008248830730131535 0.005045103596017068 0.0028634056441512686 0.001511550796372857 0.0008239745350408574 0.0005030317145494104 0.00024516722341408163 0.0001515420616844106 0.00011899803177517174 0.00012439403742308872 0.00015107953004165446 0.00020537152754664781 0.0002970360003488034 0.00041937212860091545 0.0005833386314490128 0.000836403898914009 0.0012208498047828107 0.0017314033525384026 0.002419859374637229 0.0035046384072238567 0.005225728102749319 0.007546972735349732 0.010174247183974293 0.01293809227892026 0.015692722152502902 0.01767499640965905 0.017646077493263048 0.015258430610257596 0.011664359723122488 0.008248830730131525 0.005522965993520526 0.00343144506135202 0.0019497470457856632 0.0010719536575662424 0.0006304765274554577 0.0003988059216545907 0.00017526872371933114 0.00010322000910759549 0.00008236911364064196 0.00008687310358683993 0.00010310204404458433 0.0001397860838600126 0.00020537152754664613 0.0002908621346563706 0.0004031565891849726 0.0005817603729256173 0.00086254153695361 0.0012246577971138585 0.001651926371329783 0.002250232107860959 0.0032019567330937404 0.004570037806178958 0.006171924531510295 0.007710433178781149 0.008932914694551082 0.009578011906467707 0.009386166372071899 0.00834343978214694 0.006767615584404153 0.005045103596017063 0.003431445061352024 0.0021108206748463158 0.0012147289412613622 0.0007181879547709652 0.0004633285841213894 0.0003003899004650735 0.00010990207288447781 0.0000630784514736914 0.00005473562818607286 0.00006224326772106597 0.00007553666539708483 0.00010310204404459096 0.00015107953004165703 0.00021079146292320817 0.0002871615092159451 0.00041038257064112565 0.0006090221462856625 0.0008696279545382138 0.0011583572591615126 0.0015021101566728293 0.0019935386997361414 0.002698729676676627 0.0035655934957543123 0.004422978400784091 0.0050659903989462825 0.005337764510923126 0.00517464633682746 0.004622831473009582 0.0038047658255811914 0.0028634056441512595 0.0019497470457856604 0.0012147289412613564 0.0007370114712795641 0.0004737128545823654 0.0003206654954183253 0.0002022661710982098 0.00006028885013160397 0.00003706462000963189 0.00003812009777227942 0.00004802404642698642 0.00006224326772106257 0.00008687310358684564 0.00012439403742308858 0.00016905754840346345 0.0002246388548763492 0.00031008840053105806 0.0004430836000988292 0.0006217834696838609 0.0008297072438039137 0.0010612533502024897 0.0013314457145501824 0.001658490570884668 0.0020380349828360137 0.002423979187085864 0.00272520129786015 0.0028419649976218755 0.002727826283899671 0.002414862370457813 0.0019821064539637784 0.0015115507963728552 0.0010719536575662443 0.0007181879547709643 0.00047371285458237 0.0003158654422010087 0.00020424986233035425 0.00011796120117655193 0.00003439575992661719 0.000026711709509460995 0.000029796252276299843 0.00003812009777228172 0.00005473562818607164 0.00008236911364064623 0.00011899803177517325 0.0001629895025833117 0.00021817936648991997 0.00029029939436916465 0.00038202411574576775 0.0004938979088174606 0.000631751226801638 0.0007970503483696749 0.0009705099287999425 0.001127068963386337 0.0012624736503087089 0.0013888305176585245 0.0014949492493011294 0.0015311746859497776 0.0014533516270413772 0.0012722104792645499 0.0010447624265133982 0.0008239745350408516 0.0006304765274554577 0.00046332858412138456 0.00032066549541832684 0.00020424986233035387 0.00011779395139745396 0.00006258753462346796 0.000028324619977969094 0.000025849658985389822 0.000026711709509460995 0.00003706462000963425 0.00006307845147369002 0.00010322000910760118 0.0001515420616844126 0.0002087267249035151 0.0002817392936413667 0.0003660870006756826 0.0004453625188348309 0.000512221770090817 0.0005841060597842239 0.0006814304005537388 0.0007900599153244969 0.0008701737083641812 0.000905575712490906 0.0009218909549822178 0.0009416347748850434 0.0009450532555018891 0.0008912224146887153 0.0007727221740842612 0.0006296342986623026 0.0005030317145494055 0.00039880592165459115 0.0003003899004650696 0.00020226617109821238 0.00011796120117655388 0.00006258753462346787 0.000036828364883750995 0.000022151566164280536 0.000022541579159481766 0.000029077834577928216 0.000051575019374038066 0.00009202672100431012 0.00014390693080603475 0.0001999162390895386 0.00026156901156281723 0.000336092964548681 0.0004170162218225873 0.0004837211007552439 0.0005240339424709087 0.0005506553884725048 0.0005832294783845796 0.0006197248184155353 0.000636837332730884 0.0006197248184155336 0.0005832294783845796 0.0005506553884725082 0.0005240339424709001 0.0004837211007552404 0.00041701622182258556 0.000336092964548681 0.00026156901156281463 0.0001999162390895386 0.0001439069308060317 0.00009202672100431034 0.00005157501937403828 0.000029077834577927132 0.00002254157915948247 0.000022541579159482372 0.000030180522486133588 0.000053844133215540664 0.00010298248083767324 0.0001748674317616123 0.0002556769954001648 0.0003363917239214455 0.0004222368852196884 0.0005222137760460877 0.0006296342986623082 0.000717866529654303 0.000760976138198997 0.0007619127265753531 0.0007465776724080165 0.0007313386636297347 0.000703856505809719 0.0006423483931220714 0.0005519973573561758 0.0004633564042267089 0.00039576518507255837 0.00033999731898394 0.00028173929364137015 0.00022033393740473364 0.00016484178283184467 0.00012021240778398076 0.00008184139687993517 0.00004966829372032497 0.00002876662995246254 0.000020711875659537473 0.000020532050107831735 0.000029077834577929998 0.00005384413321554238 0.00010487748323798162 0.00018588342694629182 0.00029007418727425765 0.0004090335134792802 0.0005429488252746297 0.0006969509137475167 0.0008703087826223959 0.0010447624265134 0.0011822360315786385 0.0012408721734380763 0.0012087368131948198 0.0011191498215588802 0.0010183403054298285 0.0009190083262633709 0.0008015254916949685 0.0006561523056794518 0.0005052944369660961 0.00037963807815661374 0.000286700280728732 0.00021817936648991555 0.00016606419909649285 0.00012541544784508535 0.00009202995412546045 0.00006174356940784728 0.000037225400347980404 0.000023259926778897243 0.000019165279029503557 0.00002071187565954053 0.000051575019374040336 0.00010298248083767599 0.00018588342694629242 0.00029651146234187746 0.00044009280330434687 0.0006398426918513317 0.0009163199990738608 0.0012607018118170853 0.0016349871298253318 0.0019821064539637828 0.0022318845186097567 0.002315502914080532 0.0022044233453669096 0.0019465698802292996 0.0016396186116322171 0.001356002967794808 0.0011094531117226132 0.0008835265101450347 0.0006692846682037813 0.0004781079751338991 0.0003274960299765942 0.00022463885487634475 0.00016213711920641887 0.0001230483526989929 0.00009092448574328187 0.00006065687477902413 0.00003826818439399707 0.000026642519656203414 0.00002325992677889598 0.000028766629952464916 0.00009202672100430781 0.00017486743176161148 0.0002900741872742545 0.0004400928033043441 0.0006706709826168872 0.0010541703707617888 0.0016299924923527612 0.0023559393415975285 0.0031243262723721276 0.003804765825581197 0.004261837790878295 0.004379127580087887 0.004117426952608121 0.0035548620122397654 0.0028541081215028995 0.002180842443607052 0.001635186491221512 0.0012310199292264743 0.0009232854720991968 0.0006636557209989204 0.0004446632000163179 0.0002871615092159499 0.00019395528069378738 0.00014055573155341786 0.00010089256600216066 0.00006762487901667203 0.00004695012607628765 0.0000382681843939944 0.00003722540034797463 0.00004966829372032345 0.00014390693080603152 0.00025567699540016327 0.00040903351347927635 0.0006398426918513282 0.0010541703707617883 0.0017698156072572246 0.0028175502559398694 0.00411172314262916 0.0055024794586461066 0.006767615584404155 0.007593348891884841 0.007727115860575981 0.007172574512613112 0.00614405407613146 0.004883702047003988 0.003610843325070013 0.0025357859259002276 0.0017735870623411655 0.0012775314669896038 0.0009209194452240717 0.000626918499983466 0.00040315658918494617 0.00026363326213075866 0.0001825935571285964 0.00012770593467778803 0.0000882673103841458 0.00006762487901667583 0.000060656874779025005 0.00006174356940784516 0.00008184139687993647 0.00019991623908953605 0.0003363917239214457 0.0005429488252746259 0.0009163199990738571 0.001629992492352761 0.0028175502559398685 0.004478765621190837 0.0065860792568771 0.009110995346707656 0.011664359723122492 0.013326033228026436 0.013355186574400197 0.011973630808074325 0.009977253075154286 0.007878392384066558 0.005824229496243895 0.004001168929060427 0.002654967801723886 0.001810848820147553 0.0012792562992190268 0.0008847228995316139 0.0005833386314490027 0.0003844573858147839 0.00026274413670865804 0.0001817243025739877 0.00012770593467778467 0.00010089256600216069 0.00009092448574328166 0.00009202995412545364 0.00012021240778398026 0.0002615690115628175 0.00042223688521968996 0.000696950913747514 0.0012607018118170829 0.002355939341597529 0.004111723142629161 0.0065860792568771045 0.010128569135575999 0.015156039132763182 0.020864596443750806 0.02460390221674716 0.024168342736126214 0.02042239365493734 0.015933902304877866 0.012113170777656664 0.008910303039589453 0.006129708980026593 0.003986452395490244 0.0026137159892019837 0.001795365947832466 0.0012460069125889589 0.0008408650019755398 0.0005632734506421861 0.0003839224169122416 0.00026274413670865425 0.00018259355712859485 0.00014055573155341686 0.00012304835269899507 0.00012541544784508126 0.0001648417828318467 0.0003360929645486815 0.000522213776046091 0.0008703087826223947 0.0016349871298253302 0.00312432627237213 0.005502479458646109 0.009110995346707663 0.015156039132763184 0.02500960208422867 0.03709954904779632 0.04510783438860939 0.04358793167375027 0.034760915202820916 0.025055637667848865 0.01786507350603816 0.012817265080276339 0.008839845022533014 0.0057619506783170675 0.003734748948349907 0.0025319910818477455 0.0017619709067586704 0.0012099587610935232 0.0008231909664002661 0.0005632734506421877 0.0003844573858147841 0.0002636332621307547 0.00019395528069378988 0.00016213711920642053 0.00016606419909648802 0.00022033393740473453 0.0004170162218225857 0.0006296342986623068 0.0010447624265133982 0.0019821064539637793 0.003804765825581194 0.006767615584404151 0.011664359723122486 0.0208645964437508 0.0370995490477963 0.05787400730220692 0.0718448186560118 0.0689697734916783 0.05321910300325956 0.036366731310063405 0.024608649914735672 0.017197117076335002 0.011889215069225802 0.007869541377713717 0.005172902766082877 0.0035435371058458423 0.0024978119909227978 0.0017465327290204836 0.0012099587610935238 0.0008408650019755443 0.0005833386314489976 0.0004031565891849493 0.00028716150921594423 0.00022463885487634524 0.00021817936648991287 0.0002817392936413663 0.00048372110075524356 0.0007178665296542994 0.0011822360315786307 0.0022318845186097497 0.004261837790878291 0.0075933488918848374 0.013326033228026432 0.02460390221674716 0.04510783438860937 0.0718448186560118 0.09023345115385845 0.08704897352051251 0.06708402303583848 0.04551782647970808 0.030550059905471983 0.02134049909786334 0.014947087410735685 0.010148692673302791 0.006884090603571305 0.004852504630671356 0.00350011603106247 0.0024978119909227965 0.0017619709067586678 0.0012460069125889636 0.0008847228995316152 0.0006269184999834658 0.00044466320001631935 0.0003274960299765939 0.0002867002807287315 0.00033999731898394 0.0005240339424709034 0.0007609761381989933 0.0012408721734380684 0.0023155029140805258 0.004379127580087879 0.007727115860575973 0.01335518657440019 0.024168342736126208 0.04358793167375025 0.06896977349167827 0.0870489735205125 0.0854511061047993 0.06795136304519563 0.04815204876374486 0.03380867422689519 0.024476616453336097 0.01767088697656698 0.012455354564246358 0.008851163896473153 0.006514726734788952 0.004852504630671362 0.003543537105845842 0.0025319910818477425 0.0017953659478324717 0.0012792562992190283 0.000920919445224078 0.0006636557209989238 0.0004781079751338952 0.00037963807815661444 0.0003957651850725568 0.0005506553884725067 0.0007619127265753577 0.0012087368131948237 0.0022044233453669157 0.004117426952608124 0.007172574512613115 0.011973630808074334 0.020422393654937348 0.03476091520282092 0.05321910300325957 0.06708402303583848 0.06795136304519563 0.05761291075195856 0.04456266870809132 0.03407391682098448 0.026250381929511915 0.019899013037081057 0.014864650915170589 0.011317929939732588 0.008851163896473162 0.0068840906035713195 0.00517290276608288 0.0037347489483499125 0.002613715989201993 0.0018108488201475654 0.0012775314669896056 0.0009232854720992009 0.0006692846682037818 0.0005052944369660909 0.00046335640422670457 0.0005832294783845791 0.0007465776724080134 0.001119149821558879 0.0019465698802292985 0.0035548620122397593 0.006144054076131452 0.00997725307515428 0.015933902304877862 0.025055637667848855 0.0363667313100634 0.04551782647970806 0.04815204876374487 0.044562668708091314 0.0384400990072735 0.03239910529167102 0.02687477562088644 0.02187832071983873 0.017840269655008244 0.014864650915170585 0.012455354564246362 0.010148692673302801 0.007869541377713715 0.005761950678317068 0.003986452395490247 0.0026549678017238876 0.0017735870623411738 0.0012310199292264704 0.0008835265101450307 0.0006561523056794514 0.0005519973573561696 0.0006197248184155347 0.0007313386636297358 0.0010183403054298294 0.001639618611632218 0.0028541081215028986 0.0048837020470039825 0.007878392384066561 0.01211317077765666 0.017865073506038158 0.024608649914735665 0.03055005990547198 0.03380867422689517 0.034073916820984464 0.03239910529167101 0.029813679189042683 0.02688893996048021 0.024131797236828952 0.02187832071983873 0.019899013037081054 0.01767088697656699 0.014947087410735698 0.01188921506922581 0.00883984502253302 0.006129708980026594 0.004001168929060434 0.0025357859259002307 0.0016351864912215134 0.0011094531117226143 0.0008015254916949671 0.0006423483931220735 0.0006368373327308829 0.0007038565058097171 0.0009190083262633708 0.0013560029677948074 0.002180842443607049 0.003610843325070009 0.005824229496243897 0.008910303039589451 0.012817265080276335 0.017197117076334992 0.02134049909786333 0.024476616453336097 0.02625038192951191 0.02687477562088643 0.026888939960480213 0.026820140023580068 0.026888939960480217 0.026874775620886436 0.026250381929511915 0.0244766164533361 0.021340499097863345 0.017197117076335 0.012817265080276342 0.008910303039589453 0.005824229496243896 0.0036108433250700168 0.0021808424436070483 0.0013560029677948046 0.0009190083262633717 0.0007038565058097149 0.0006197248184155346 0.0006423483931220761 0.0008015254916949667 0.0011094531117226164 0.0016351864912215143 0.0025357859259002202 0.004001168929060435 0.006129708980026589 0.008839845022533014 0.011889215069225797 0.014947087410735685 0.01767088697656698 0.01989901303708105 0.02187832071983872 0.024131797236828952 0.02688893996048021 0.02981367918904269 0.03239910529167102 0.03407391682098447 0.03380867422689519 0.030550059905471993 0.024608649914735676 0.017865073506038165 0.012113170777656666 0.007878392384066561 0.004883702047003989 0.0028541081215028978 0.0016396186116322154 0.001018340305429831 0.000731338663629734 0.0005832294783845787 0.0005519973573561727 0.0006561523056794511 0.0008835265101450324 0.0012310199292264712 0.0017735870623411638 0.002654967801723886 0.0039864523954902436 0.005761950678317063 0.007869541377713712 0.010148692673302788 0.01245535456424636 0.014864650915170585 0.017840269655008244 0.02187832071983873 0.02687477562088644 0.032399105291671025 0.03844009900727349 0.044562668708091314 0.04815204876374487 0.04551782647970808 0.0363667313100634 0.02505563766784886 0.015933902304877862 0.00997725307515428 0.0061440540761314565 0.0035548620122397576 0.0019465698802292955 0.0011191498215588802 0.0007465776724080115 0.0005506553884725064 0.0004633564042267083 0.0005052944369660916 0.0006692846682037828 0.0009232854720992024 0.001277531466989598 0.0018108488201475637 0.00261371598920199 0.003734748948349912 0.005172902766082881 0.0068840906035713125 0.008851163896473162 0.01131792993973259 0.01486465091517059 0.019899013037081064 0.02625038192951192 0.03407391682098448 0.04456266870809132 0.05761291075195857 0.06795136304519564 0.06708402303583849 0.05321910300325957 0.03476091520282093 0.020422393654937348 0.011973630808074336 0.007172574512613119 0.004117426952608121 0.002204423345366912 0.0012087368131948252 0.0007619127265753563 0.0005240339424709026 0.00039576518507255956 0.00037963807815661585 0.000478107975133894 0.0006636557209989251 0.0009209194452240723 0.001279256299219027 0.0017953659478324654 0.002531991081847744 0.00354353710584584 0.00485250463067136 0.006514726734788944 0.00885116389647316 0.012455354564246355 0.017670886976566987 0.024476616453336094 0.03380867422689519 0.04815204876374486 0.06795136304519563 0.08545110610479928 0.0870489735205125 0.06896977349167827 0.04358793167375026 0.024168342736126208 0.013355186574400192 0.0077271158605759765 0.0043791275800878745 0.0023155029140805223 0.0012408721734380687 0.0007609761381989912 0.0004837211007552427 0.0003399973189839411 0.00028670028072873434 0.00032749602997659075 0.00044466320001632006 0.0006269184999834666 0.0008847228995316145 0.0012460069125889589 0.0017619709067586717 0.002497811990922791 0.0035001160310624774 0.004852504630671348 0.006884090603571314 0.010148692673302788 0.01494708741073569 0.02134049909786334 0.03055005990547199 0.045517826479708076 0.06708402303583848 0.0870489735205125 0.09023345115385846 0.0718448186560118 0.04510783438860939 0.02460390221674716 0.013326033228026434 0.00759334889188484 0.004261837790878287 0.0022318845186097467 0.0011822360315786307 0.0007178665296542969 0.00041701622182258486 0.00028173929364136527 0.00021817936648991655 0.0002246388548763406 0.0002871615092159439 0.00040315658918495544 0.000583338631448998 0.0008408650019755401 0.0012099587610935269 0.0017465327290204897 0.0024978119909228004 0.003543537105845844 0.005172902766082885 0.007869541377713713 0.011889215069225807 0.017197117076334995 0.024608649914735683 0.03636673131006339 0.05321910300325958 0.06896977349167827 0.07184481865601179 0.057874007302206903 0.03709954904779631 0.020864596443750796 0.01166435972312249 0.006767615584404152 0.003804765825581192 0.0019821064539637754 0.0010447624265133985 0.0006296342986623039 0.00033609296454868096 0.0002203339374047324 0.0001660641990964923 0.00016213711920641568 0.00019395528069378936 0.0002636332621307638 0.00038445738581478506 0.000563273450642185 0.0008231909664002669 0.0012099587610935275 0.0017619709067586765 0.002531991081847741 0.0037347489483499138 0.005761950678317064 0.008839845022533016 0.012817265080276337 0.017865073506038165 0.02505563766784886 0.034760915202820916 0.04358793167375026 0.04510783438860939 0.03709954904779631 0.02500960208422867 0.015156039132763184 0.009110995346707665 0.005502479458646111 0.0031243262723721285 0.0016349871298253279 0.0008703087826223949 0.0005222137760460888 0.0002615690115628177 0.00016484178283184456 0.000125415447845086 0.00012304835269899108 0.00014055573155341686 0.0001825935571286043 0.0002627441367086569 0.00038392241691224087 0.0005632734506421904 0.0008408650019755488 0.0012460069125889688 0.0017953659478324737 0.002613715989201997 0.003986452395490247 0.006129708980026594 0.008910303039589451 0.012113170777656666 0.01593390230487786 0.020422393654937344 0.024168342736126208 0.024603902216747155 0.020864596443750806 0.015156039132763182 0.010128569135575997 0.006586079256877103 0.004111723142629162 0.002355939341597527 0.001260701811817081 0.0006969509137475145 0.000422236885219689 0.000199916239089537 0.00012021240778397906 0.00009202995412545907 0.00009092448574327907 0.00010089256600216104 0.00012770593467779297 0.0001817243025739935 0.00026274413670865306 0.00038445738581478945 0.000583338631449001 0.000884722899531625 0.0012792562992190188 0.0018108488201475717 0.002654967801723881 0.004001168929060434 0.005824229496243893 0.007878392384066563 0.009977253075154275 0.011973630808074332 0.013355186574400178 0.013326033228026432 0.011664359723122485 0.009110995346707658 0.006586079256877097 0.004478765621190837 0.00281755025593987 0.0016299924923527604 0.0009163199990738566 0.0005429488252746267 0.0003363917239214463 0.00014390693080603217 0.00008184139687993541 0.00006174356940784978 0.00006065687477902309 0.00006762487901667497 0.00008826731038415386 0.0001277059346777914 0.0001825935571285964 0.00026363326213076587 0.00040315658918494953 0.0006269184999834778 0.0009209194452240704 0.0012775314669896155 0.0017735870623411581 0.002535785925900228 0.0036108433250700103 0.004883702047003989 0.006144054076131453 0.007172574512613118 0.007727115860575966 0.0075933488918848374 0.00676761558440415 0.0055024794586461066 0.004111723142629157 0.0028175502559398672 0.001769815607257226 0.0010541703707617873 0.0006398426918513279 0.00040903351347927635 0.0002556769954001641 0.00009202672100430814 0.000049668293720322566 0.00003722540034797812 0.000038268184393992724 0.000046950126076286 0.0000676248790166784 0.00010089256600216112 0.00014055573155341463 0.00019395528069379226 0.00028716150921594873 0.00044466320001632163 0.0006636557209989277 0.0009232854720992041 0.001231019929226472 0.0016351864912215143 0.0021808424436070496 0.0028541081215029012 0.0035548620122397593 0.004117426952608124 0.004379127580087867 0.0042618377908782866 0.0038047658255811936 0.0031243262723721255 0.002355939341597523 0.001629992492352759 0.0010541703707617892 0.0006706709826168864 0.0004400928033043438 0.00029007418727425397 0.00017486743176161219 0.000051575019374039516 0.000028766629952463266 0.000023259926778897205 0.00002664251965620179 0.00003826818439399427 0.00006065687477902831 0.00009092448574328088 0.00012304835269899377 0.00016213711920641606 0.0002246388548763444 0.0003274960299765906 0.0004781079751339033 0.0006692846682037812 0.0008835265101450343 0.0011094531117226169 0.0013560029677948077 0.0016396186116322202 0.001946569880229301 0.0022044233453669126 0.0023155029140805236 0.0022318845186097484 0.001982106453963784 0.001634987129825329 0.0012607018118170833 0.0009163199990738587 0.0006398426918513316 0.0004400928033043455 0.0002965114623418765 0.00018588342694629063 0.0001029824808376757 0.000029077834577929602 0.00002071187565953922 0.000019165279029504448 0.000023259926778896233 0.00003722540034797889 0.00006174356940785098 0.00009202995412545945 0.00012541544784508196 0.000166064199096494 0.00021817936648991693 0.0002867002807287382 0.00037963807815661693 0.0005052944369660933 0.0006561523056794489 0.0008015254916949709 0.0009190083262633708 0.0010183403054298342 0.0011191498215588796 0.0012087368131948252 0.0012408721734380648 0.0011822360315786329 0.0010447624265134045 0.0008703087826223966 0.0006969509137475152 0.0005429488252746278 0.00040903351347927895 0.00029007418727425695 0.00018588342694629122 0.00010487748323797995 0.000053844133215542406 0.000022541579159481864 0.000020532050107830323 0.00002071187565953794 0.000028766629952461616 0.00004966829372032352 0.00008184139687993808 0.00012021240778397925 0.00016484178283184502 0.00022033393740473285 0.0002817392936413682 0.0003399973189839377 0.00039576518507256244 0.0004633564042267068 0.0005519973573561703 0.0006423483931220767 0.0007038565058097207 0.0007313386636297358 0.000746577672408016 0.0007619127265753565 0.0007609761381989931 0.0007178665296542961 0.0006296342986623114 0.0005222137760460883 0.0004222368852196862 0.00033639172392144537 0.00025567699540016224 0.0001748674317616121 0.00010298248083767284 0.0000538441332155389 0.000030180522486133568 0.000020168309059153175 0.000020434020735812537 0.000025213591859050597 0.00004158095417467053 0.0000700209689794562 0.00010639592520415245 0.00014926894555382202 0.0002010143453447938 0.00026156901156281637 0.0003213239699373918 0.0003688317936540826 0.000401410369553672 0.0004262350267254956 0.00044961097665089517 0.00046879496476522585 0.0004764957920562699 0.0004687949647652241 0.00044961097665089517 0.00042623502672549385 0.00040141036955367027 0.0003688317936540791 0.00032132396993738745 0.0002615690115628155 0.00020101434534479205 0.00014926894555382072 0.0001063959252041518 0.00007002096897945598 0.000041580954174672046 0.000025213591859050706 0.000020434020735813675 0.000020434020735814176 0.000025034130620914903 0.00004262943994523017 0.00007998449698244632 0.00013378777557353425 0.00019532748400063433 0.0002623235230572654 0.00033846068511081493 0.0004222368852196865 0.0005030317145494135 0.0005666602319166321 0.0006011759042085248 0.0006045988410517456 0.0005865215698875179 0.0005603349195352443 0.0005287625121494384 0.00048131016516047155 0.0004144589417778395 0.0003443313341783586 0.0002890580940773138 0.00024777767599728617 0.00020872672490351081 0.0001648417828318437 0.00012121774671322516 0.00008587912888930963 0.00005799357828135729 0.000036419779238968434 0.000022572177159267243 0.00001784863927513798 0.000019088382184325383 0.000025213591859051817 0.00004262943994523051 0.00008197322550826526 0.00014795151506899096 0.000232136255925519 0.000326448962953667 0.0004344545721148336 0.0005606707485081453 0.0006969509137475168 0.0008239745350408589 0.0009202033550585111 0.0009632349493911878 0.0009395915246891081 0.0008649531896832593 0.0007774910755573768 0.0006972250267069921 0.0006092634042455441 0.0004963521413852185 0.0003738581341875541 0.00027449300329203104 0.00020825311966694756 0.000162989502583307 0.00012541544784508405 0.00009202547110128884 0.00006383462345803368 0.000039472969414739195 0.000021744405128664364 0.000013352842787484985 0.000013239288145540043 0.000017848639275139158 0.00004158095417467264 0.00007998449698244772 0.0001479515150689918 0.0002452872893603469 0.00036629691993683066 0.000520216161796781 0.0007258660541463104 0.0009829449201744825 0.001260701811817085 0.0015115507963728606 0.001688052150227326 0.00174560593510576 0.0016589400069480294 0.001460434191919839 0.0012316737057361765 0.0010319639807374755 0.0008589568636188316 0.000683831623526777 0.0005042574172789162 0.0003495011941732627 0.00023964913362904187 0.00016905754840345962 0.0001230483526989912 0.0000898740742305677 0.00006124525023194466 0.000035082504194901806 0.000017393788614683787 0.000011059872777096343 0.000013352842787484547 0.000022572177159267897 0.0000700209689794561 0.000133787775573534 0.00023213625592551808 0.00036629691993682946 0.0005542117430241116 0.0008376501878464484 0.0012523497139305861 0.0017836111952503064 0.002355939341597528 0.002863405644151268 0.003200677769729535 0.003279908219514549 0.003067346428052681 0.002629389801695998 0.0021106035581529665 0.0016385034701410664 0.0012589495116249127 0.0009554476063526719 0.000701128008098073 0.0004883595058147472 0.000323874722129273 0.00021079146292320386 0.00014055573155341395 0.00009673607156472153 0.00006418578918286192 0.00003799095053560095 0.000021968432045007298 0.000017393788614684305 0.000021744405128663676 0.000036419779238969105 0.00010639592520415245 0.00019532748400063438 0.00032644896295366637 0.00052021616179678 0.0008376501878464485 0.0013573848039995448 0.002117562157211253 0.003075054390627012 0.004111723142629158 0.0050451035960170695 0.005648678265475143 0.005744944457247075 0.005320251868544281 0.004526188866547986 0.0035749591955013854 0.002654649680287482 0.0018950825958768778 0.0013428023934787107 0.0009614150171436423 0.0006808862036298993 0.000458027079866502 0.00029086213465636784 0.00018259355712859742 0.00011815501475325737 0.00007753218240796333 0.00005113278822131692 0.00003799095053560169 0.0000350825041949035 0.000039472969414739804 0.00005799357828135835 0.00014926894555382115 0.00026232352305726565 0.0004344545721148325 0.00072586605414631 0.0012523497139305866 0.0021175621572112535 0.0033352981097693685 0.004855050110277433 0.0065860792568770985 0.008248830730131534 0.009317982583385743 0.009383109611456556 0.008535272017550805 0.007194256015802473 0.005688885411737054 0.004192815454864294 0.002888371790448015 0.0019366624294627427 0.0013339424895266328 0.0009448983181505428 0.0006500135096252582 0.00041937212860091084 0.00026274413670865474 0.00016817518667788673 0.0001108953314996443 0.00007753218240796398 0.00006418578918286279 0.00006124525023194778 0.0000638346234580336 0.00008587912888931068 0.00020101434534479338 0.00033846068511081574 0.0005606707485081457 0.0009829449201744834 0.0017836111952503086 0.003075054390627014 0.004855050110277434 0.007181038655257922 0.010128569135575997 0.01323033090652455 0.015236007343764207 0.01514211100714846 0.013311339349175031 0.01088089061593668 0.008518072672587645 0.0062989439316914805 0.0043141216780064 0.0028151593946382837 0.0018731680166680688 0.001304421941949093 0.0009038676023293272 0.0005962452510613957 0.0003839224169122432 0.00025150280792624616 0.00016817518667788296 0.0001181550147532579 0.0000967360715647207 0.00008987407423056995 0.00009202547110128937 0.00012121774671322629 0.0002615690115628166 0.0004222368852196893 0.0006969509137475161 0.0012607018118170853 0.0023559393415975285 0.004111723142629159 0.006586079256877099 0.010128569135575997 0.015156039132763182 0.0208645964437508 0.02460390221674716 0.024168342736126214 0.020422393654937348 0.015933902304877866 0.012113170777656668 0.008910303039589455 0.0061297089800265965 0.003986452395490252 0.002613715989201994 0.0017953659478324717 0.0012460069125889658 0.0008408650019755462 0.0005632734506421914 0.00038392241691224217 0.0002627441367086527 0.00018259355712859515 0.0001405557315534144 0.00012304835269899314 0.0001254154478450819 0.00016484178283184407 0.0003213239699373895 0.0005030317145494138 0.0008239745350408566 0.0015115507963728587 0.002863405644151266 0.005045103596017066 0.008248830730131529 0.013230330906524547 0.020864596443750796 0.029954352756893635 0.036027717391526014 0.035232198896081986 0.02901729743471952 0.021833526348406386 0.016130953814403673 0.01176780821440097 0.008167517098673107 0.005391246813130984 0.0035767109487630294 0.0024757860587300484 0.0017395256062650293 0.0012060439533125777 0.0008408650019755473 0.0005962452510613989 0.0004193721286009096 0.00029086213465636627 0.00021079146292320297 0.00016905754840345822 0.00016298950258330637 0.00020872672490351044 0.0003688317936540802 0.0005666602319166303 0.000920203355058507 0.0016880521502273239 0.003200677769729532 0.00564867826547514 0.009317982583385741 0.015236007343764202 0.02460390221674715 0.03602771739152602 0.043882570046413404 0.04315798504401965 0.03552916848266973 0.02661953106469916 0.01961881131809789 0.014399348124765442 0.010179124463848834 0.0069231530735964315 0.004753920712825657 0.0033890596656994355 0.002441698447335644 0.00173952560626503 0.0012460069125889686 0.0009038676023293315 0.0006500135096252594 0.00045802707986649787 0.00032387472212927644 0.00023964913362904648 0.00020825311966694848 0.000247777675997289 0.00040141036955367195 0.0006011759042085242 0.0009632349493911886 0.0017456059351057603 0.0032799082195145474 0.005744944457247074 0.009383109611456554 0.015142111007148459 0.02416834273612621 0.03523219889608198 0.043157985044019645 0.04316919361830618 0.03654237041029714 0.028345846801708423 0.021600447001363186 0.016313578902386973 0.01189963200561258 0.008449495985470214 0.006103819007469914 0.0045486307953706345 0.003389059665699438 0.002475786058730052 0.0017953659478324763 0.0013044219419491008 0.0009448983181505444 0.0006808862036299049 0.000488359505814751 0.0003495011941732675 0.0002744930032920343 0.00028905809407731313 0.0004262350267254954 0.0006045988410517468 0.0009395915246891058 0.0016589400069480283 0.0030673464280526804 0.005320251868544278 0.008535272017550806 0.01331133934917503 0.020422393654937348 0.02901729743471952 0.03552916848266973 0.036542370410297134 0.032628634466063365 0.027043933065993456 0.021871898399191694 0.017291184098801107 0.013205451880473078 0.009966524346444053 0.007717583949283108 0.006103819007469919 0.004753920712825662 0.0035767109487630324 0.002613715989202001 0.0018731680166680733 0.0013339424895266372 0.0009614150171436411 0.0007011280080980777 0.0005042574172789213 0.0003738581341875577 0.000344331334178362 0.0004496109766508938 0.0005865215698875173 0.0008649531896832575 0.001460434191919838 0.002629389801695994 0.004526188866547979 0.007194256015802467 0.010880890615936677 0.01593390230487786 0.021833526348406376 0.026619531064699144 0.028345846801708423 0.027043933065993453 0.02420311060051783 0.020913217290195893 0.017497979483522698 0.014298536985646173 0.011780429057506368 0.009966524346444055 0.008449495985470219 0.006923153073596434 0.005391246813130986 0.003986452395490254 0.0028151593946382867 0.0019366624294627434 0.0013428023934787146 0.000955447606352671 0.0006838316235267752 0.0004963521413852182 0.0004144589417778366 0.0004687949647652256 0.0005603349195352479 0.0007774910755573754 0.001231673705736178 0.0021106035581529674 0.0035749591955013815 0.005688885411737054 0.008518072672587643 0.012113170777656668 0.016130953814403673 0.019618811318097888 0.021600447001363182 0.02187189839919169 0.02091321729019589 0.01926204335873081 0.017344440296077856 0.015606687393438871 0.014298536985646176 0.013205451880473082 0.01189963200561259 0.010179124463848839 0.00816751709867311 0.0061297089800266 0.004314121678006404 0.0028883717904480168 0.0018950825958768804 0.001258949511624914 0.0008589568636188339 0.0006092634042455455 0.00048131016516047404 0.00047649579205627003 0.0005287625121494397 0.000697225026706992 0.001031963980737477 0.0016385034701410658 0.0026546496802874785 0.004192815454864291 0.0062989439316914805 0.008910303039589455 0.011767808214400963 0.014399348124765433 0.016313578902386973 0.017291184098801107 0.017497979483522698 0.01734444029607786 0.01723676140359564 0.017344440296077856 0.0174979794835227 0.017291184098801114 0.016313578902386976 0.014399348124765444 0.011767808214400969 0.008910303039589458 0.006298943931691484 0.004192815454864291 0.0026546496802874846 0.0016385034701410666 0.0010319639807374753 0.0006972250267069939 0.0005287625121494369 0.00046879496476522585 0.00048131016516047724 0.0006092634042455441 0.0008589568636188352 0.0012589495116249135 0.0018950825958768734 0.002888371790448016 0.004314121678006399 0.0061297089800265965 0.008167517098673102 0.010179124463848829 0.011899632005612578 0.013205451880473075 0.01429853698564617 0.015606687393438871 0.017344440296077852 0.019262043358730812 0.020913217290195896 0.021871898399191698 0.021600447001363193 0.0196188113180979 0.016130953814403676 0.012113170777656671 0.008518072672587647 0.0056888854117370545 0.0035749591955013876 0.0021106035581529682 0.0012316737057361767 0.0007774910755573779 0.0005603349195352456 0.00044961097665089387 0.0004144589417778401 0.0004963521413852173 0.0006838316235267764 0.0009554476063526702 0.0013428023934787087 0.0019366624294627419 0.0028151593946382832 0.003986452395490249 0.00539124681313098 0.006923153073596423 0.008449495985470212 0.009966524346444048 0.011780429057506368 0.014298536985646175 0.017497979483522698 0.020913217290195896 0.02420311060051783 0.02704393306599346 0.028345846801708426 0.026619531064699154 0.02183352634840638 0.015933902304877866 0.01088089061593668 0.007194256015802468 0.004526188866547984 0.0026293898016959945 0.0014604341919198364 0.0008649531896832597 0.0005865215698875152 0.0004262350267254952 0.00034433133417836545 0.00037385813418755736 0.000504257417278922 0.0007011280080980773 0.0009614150171436365 0.0013339424895266359 0.0018731680166680707 0.0026137159892019968 0.0035767109487630285 0.0047539207128256536 0.006103819007469916 0.007717583949283103 0.009966524346444053 0.013205451880473078 0.01729118409880111 0.0218718983991917 0.027043933065993456 0.03262863446606337 0.03654237041029714 0.035529168482669744 0.029017297434719525 0.02042239365493735 0.013311339349175031 0.008535272017550806 0.0053202518685442814 0.0030673464280526795 0.0016589400069480266 0.0009395915246891076 0.0006045988410517448 0.00040141036955367124 0.00028905809407731573 0.00027449300329203435 0.0003495011941732668 0.0004883595058147506 0.0006808862036299019 0.0009448983181505436 0.0013044219419490973 0.001795365947832473 0.002475786058730046 0.003389059665699432 0.00454863079537063 0.0061038190074699135 0.00844949598547021 0.01189963200561258 0.01631357890238697 0.02160044700136319 0.02834584680170842 0.03654237041029714 0.04316919361830618 0.043157985044019645 0.03523219889608198 0.024168342736126208 0.015142111007148462 0.009383109611456553 0.005744944457247075 0.003279908219514545 0.0017456059351057584 0.0009632349493911897 0.0006011759042085218 0.00036883179365407905 0.00024777767599729056 0.00020825311966694946 0.00023964913362904496 0.0003238747221292762 0.0004580270798664981 0.0006500135096252593 0.0009038676023293299 0.0012460069125889686 0.0017395256062650256 0.0024416984473356433 0.003389059665699434 0.004753920712825657 0.006923153073596428 0.010179124463848834 0.01439934812476544 0.01961881131809789 0.02661953106469915 0.03552916848266974 0.04315798504401965 0.043882570046413404 0.03602771739152602 0.024603902216747152 0.015236007343764204 0.009317982583385741 0.005648678265475141 0.0032006777697295295 0.0016880521502273217 0.0009202033550585078 0.0005666602319166274 0.00032132396993738815 0.0002087267249035106 0.0001629895025833078 0.00016905754840345597 0.00021079146292320248 0.0002908621346563687 0.0004193721286009101 0.0005962452510613989 0.0008408650019755457 0.0012060439533125773 0.0017395256062650297 0.002475786058730053 0.0035767109487630355 0.005391246813130982 0.008167517098673109 0.011767808214400969 0.016130953814403676 0.02183352634840638 0.02901729743471953 0.03523219889608198 0.03602771739152602 0.029954352756893624 0.0208645964437508 0.013230330906524545 0.00824883073013153 0.005045103596017064 0.002863405644151263 0.001511550796372856 0.0008239745350408573 0.0005030317145494104 0.00026156901156281534 0.00016484178283184345 0.00012541544784508375 0.0001230483526989911 0.0001405557315534141 0.0001825935571285986 0.000262744136708654 0.00038392241691224277 0.0005632734506421927 0.0008408650019755453 0.0012460069125889675 0.0017953659478324735 0.0026137159892019976 0.0039864523954902505 0.006129708980026595 0.008910303039589455 0.012113170777656666 0.015933902304877862 0.02042239365493735 0.024168342736126214 0.024603902216747152 0.0208645964437508 0.015156039132763182 0.010128569135575999 0.0065860792568771 0.004111723142629159 0.0023559393415975255 0.001260701811817083 0.0006969509137475167 0.00042223688521968644 0.00020101434534479232 0.00012121774671322504 0.00009202547110129147 0.00008987407423056794 0.00009673607156472092 0.00011815501475326161 0.00016817518667788605 0.0002515028079262482 0.00038392241691224526 0.000596245251061398 0.0009038676023293329 0.0013044219419490997 0.001873168016668074 0.002815159394638284 0.004314121678006399 0.0062989439316914805 0.008518072672587643 0.010880890615936679 0.013311339349175031 0.015142111007148459 0.015236007343764199 0.013230330906524545 0.010128569135575995 0.007181038655257924 0.004855050110277434 0.0030750543906270123 0.0017836111952503066 0.0009829449201744817 0.0005606707485081462 0.00033846068511081336 0.0001492689455538203 0.00008587912888930897 0.00006383462345803566 0.00006124525023194591 0.0000641857891828629 0.0000775321824079673 0.0001108953314996491 0.00016817518667788597 0.0002627441367086583 0.00041937212860091106 0.0006500135096252648 0.0009448983181505474 0.0013339424895266409 0.0019366624294627406 0.0028883717904480168 0.00419281545486429 0.005688885411737055 0.007194256015802466 0.00853527201755081 0.009383109611456554 0.009317982583385741 0.008248830730131525 0.006586079256877099 0.004855050110277432 0.00333529810976937 0.0021175621572112526 0.0012523497139305853 0.0007258660541463092 0.00043445457211483324 0.000262323523057264 0.00010639592520415103 0.000057993578281355674 0.00003947296941474078 0.000035082504194901535 0.00003799095053560186 0.00005113278822132045 0.00007753218240796772 0.00011815501475325975 0.00018259355712860233 0.0002908621346563656 0.00045802707986650323 0.0006808862036298977 0.0009614150171436444 0.0013428023934787068 0.0018950825958768784 0.0026546496802874802 0.003574959195501385 0.004526188866547982 0.005320251868544281 0.0057449444572470745 0.005648678265475138 0.005045103596017064 0.004111723142629158 0.003075054390627013 0.0021175621572112535 0.0013573848039995441 0.0008376501878464467 0.0005202161617967795 0.0003264489629536666 0.0001953274840006328 0.00007002096897945438 0.000036419779238965934 0.000021744405128663717 0.000017393788614682086 0.000021968432045006695 0.000037990950535603204 0.00006418578918286425 0.0000967360715647213 0.0001405557315534133 0.00021079146292320232 0.00032387472212927764 0.0004883595058147543 0.0007011280080980803 0.0009554476063526689 0.0012589495116249148 0.0016385034701410677 0.0021106035581529665 0.0026293898016959954 0.003067346428052681 0.0032799082195145456 0.0032006777697295274 0.0028634056441512613 0.0023559393415975255 0.0017836111952503051 0.0012523497139305866 0.0008376501878464473 0.0005542117430241103 0.0003662969199368294 0.00023213625592551827 0.00013378777557353246 0.00004158095417467066 0.000022572177159264364 0.000013352842787483865 0.000011059872777093981 0.000017393788614682276 0.0000350825041949032 0.00006124525023194657 0.00008987407423056874 0.0001230483526989883 0.0001690575484034569 0.00023964913362904618 0.00034950119417326953 0.0005042574172789227 0.0006838316235267774 0.0008589568636188337 0.0010319639807374772 0.0012316737057361756 0.0014604341919198397 0.0016589400069480257 0.0017456059351057607 0.0016880521502273208 0.001511550796372858 0.0012607018118170837 0.000982944920174482 0.0007258660541463103 0.0005202161617967802 0.0003662969199368296 0.000245287289360347 0.00014795151506899145 0.00007998449698244612 0.000025213591859050512 0.000017848639275136234 0.000013239288145539521 0.000013352842787482997 0.000021744405128664123 0.00003947296941474061 0.00006383462345803578 0.00009202547110128992 0.00012541544784508304 0.0001629895025833065 0.00020825311966695483 0.0002744930032920344 0.0003738581341875619 0.0004963521413852159 0.0006092634042455441 0.0006972250267069895 0.0007774910755573756 0.0008649531896832586 0.0009395915246891051 0.0009632349493911862 0.0009202033550585051 0.0008239745350408556 0.0006969509137475148 0.0005606707485081441 0.00043445457211483307 0.0003264489629536658 0.00023213625592551825 0.00014795151506899162 0.00008197322550826497 0.00004262943994522971 0.000020434020735813438 0.00001908838218432321 0.000017848639275137545 0.000022572177159265153 0.000036419779238968014 0.0000579935782813576 0.00008587912888930997 0.00012121774671322557 0.0001648417828318415 0.00020872672490350978 0.00024777767599729137 0.0002890580940773153 0.0003443313341783633 0.0004144589417778375 0.00048131016516047393 0.0005287625121494373 0.0005603349195352446 0.0005865215698875153 0.0006045988410517417 0.0006011759042085197 0.0005666602319166268 0.00050303171454941 0.0004222368852196863 0.0003384606851108134 0.0002623235230572648 0.00019532748400063302 0.00013378777557353377 0.00007998449698244745 0.00004262943994523006 0.00002503413062091488 0.000017222828270285886 0.000017412833723630486 0.00002078145138842763 0.00003183885277159771 0.00005006992510114415 0.00007364236764164972 0.00010556425488906997 0.00014926894555382158 0.00019991623908953773 0.00024516722341408467 0.00027877854625726114 0.0003040176982251584 0.0003235039291855663 0.0003344107973057295 0.0003361344573057923 0.0003352029974325356 0.0003361344573057914 0.0003344107973057278 0.0003235039291855646 0.0003040176982251584 0.00027877854625725767 0.0002451672234140825 0.00019991623908953513 0.00014926894555381898 0.0001055642548890678 0.00007364236764164625 0.00005006992510114296 0.00003183885277159603 0.000020781451388425678 0.000017412833723629755 0.00001741283372363054 0.00001954853828186728 0.000031057107119733464 0.00005616002450131203 0.00009205475009134014 0.00013600659857995872 0.00019199258158379297 0.00026232352305726565 0.0003363917239214458 0.00039880592165459413 0.0004446288697689996 0.00047351329888212576 0.00047878926010504045 0.00045571802826237815 0.0004154374444783397 0.00037446751049341465 0.00033497429892343704 0.00028981639018622863 0.00024181346590353427 0.0002028904644140176 0.0001759200090281833 0.00015154206168441144 0.00012021240778397677 0.00008587912888930824 0.00005883925589510313 0.00004046369803590856 0.000027686800341346408 0.00001905348770761315 0.000016053898680695375 0.00001707603271819705 0.000020781451388426304 0.00003105710711973215 0.00005745686967779563 0.00010458020730616448 0.00016570616231837483 0.00023726111223035392 0.00032649751656326637 0.00043445457211483215 0.0005429488252746284 0.0006304765274554577 0.0006923623475488251 0.0007261632918973129 0.0007162791068696867 0.0006575346592259362 0.0005759894400297583 0.0004998642579464963 0.00042737201057619533 0.0003431122089624075 0.00025434264967279057 0.0001859994005038084 0.00014536777784027673 0.00011899803177516816 0.0000920299541254538 0.0000638346234580317 0.00004128492951896136 0.000024903658690914253 0.000014330775707502797 0.000009782308601450687 0.000011326048856829811 0.000016053898680695263 0.0000318388527715962 0.00005616002450131059 0.00010458020730616413 0.00018025469510182012 0.0002740329507050864 0.00038815661933966263 0.0005389628394804299 0.0007258660541463093 0.0009163199990738583 0.0010719536575662433 0.0011766546693540308 0.0012183841389811483 0.0011733734294710823 0.001044077037541587 0.000882832281948404 0.00074020303042441 0.0006161688271076281 0.0004844533228748211 0.00034716672433379297 0.0002365232571313332 0.00016697925239011696 0.0001243940374230868 0.00009092448574327661 0.00006124525023194545 0.00003721783122293056 0.000018803416857701477 0.000007592282948856761 0.0000048989126297168344 0.000009782308601450514 0.0000190534877076129 0.00005006992510114358 0.00009205475009133984 0.00016570616231837521 0.0002740329507050872 0.0004173103594153671 0.0006144342314509729 0.0008942164552661263 0.0012523497139305853 0.0016299924923527582 0.0019497470457856573 0.002157533096200789 0.002212953317850322 0.0020849230176929008 0.0018004153950183035 0.001459052724074077 0.0011543632072385783 0.0009066580400836058 0.0006895470735222088 0.0004921829205170313 0.00033287461528253725 0.00022295862859127475 0.00015107953004165353 0.00010089256600215549 0.00006418578918286242 0.00003797559959623122 0.000019767224592740566 0.000009281165063706064 0.000007592282948857939 0.000014330775707503199 0.00002768680034134704 0.00007364236764164693 0.00013600659857995623 0.00023726111223035235 0.00038815661933966155 0.0006144342314509711 0.0009616761756505689 0.00146822966664353 0.0021175621572112517 0.0028175502559398633 0.0034314450613520176 0.003824457020248541 0.0038961044023771447 0.0036190780350586122 0.0030756018951073505 0.0024284076200209318 0.0018268018963580788 0.0013400322643710202 0.0009682847789069717 0.0006872824206897174 0.0004755767626457441 0.00031852290143667363 0.00020537152754663816 0.000127705934677785 0.0000775321824079642 0.00004664162658576194 0.000028529167902094806 0.00001976722459274082 0.000018803416857702703 0.000024903658690915182 0.00004046369803590922 0.00010556425488906756 0.00019199258158379158 0.00032649751656326474 0.0005389628394804292 0.0008942164552661251 0.0014682296666435305 0.00229483269900705 0.0033352981097693676 0.004478765621190831 0.005522965993520515 0.006190457485260742 0.0062703106532279815 0.005769895370865569 0.004884730385322291 0.0038449800445795983 0.002834046611981741 0.001987585477664547 0.0013718781379051602 0.0009616996260649177 0.0006797234220084449 0.0004639337960051243 0.0002970360003487965 0.0001817243025739854 0.00011089533149964692 0.00006935526794947672 0.00004664162658576097 0.00003797559959623125 0.00003721783122293192 0.00004128492951896136 0.00005883925589510279 0.00014926894555381906 0.0002623235230572631 0.0004344545721148304 0.0007258660541463088 0.0012523497139305842 0.0021175621572112517 0.0033352981097693676 0.004855050110277432 0.006586079256877096 0.008248830730131523 0.009317982583385738 0.009383109611456547 0.008535272017550801 0.007194256015802466 0.005688885411737053 0.004192815454864289 0.002888371790448013 0.0019366624294627408 0.0013339424895266322 0.0009448983181505387 0.0006500135096252576 0.00041937212860090846 0.0002627441367086521 0.00016817518667788575 0.0001108953314996463 0.00007753218240796382 0.0000641857891828621 0.0000612452502319456 0.00006383462345803224 0.00008587912888930779 0.0001999162390895352 0.00033639172392144407 0.0005429488252746271 0.0009163199990738591 0.001629992492352759 0.0028175502559398655 0.004478765621190833 0.006586079256877098 0.009110995346707654 0.01166435972312248 0.013326033228026422 0.01335518657440018 0.011973630808074325 0.009977253075154277 0.007878392384066558 0.005824229496243893 0.0040011689290604295 0.0026549678017238833 0.00181084882014756 0.0012792562992190223 0.0008847228995316136 0.0005833386314489975 0.00038445738581478295 0.00026274413670865533 0.0001817243025739889 0.00012770593467778613 0.0001008925660021591 0.00009092448574328033 0.00009202995412545518 0.00012021240778397717 0.00024516722341408163 0.00039880592165459305 0.0006304765274554567 0.0010719536575662443 0.0019497470457856584 0.0034314450613520194 0.005522965993520518 0.008248830730131529 0.011664359723122478 0.015258430610257584 0.017646077493263027 0.01767499640965904 0.015692722152502867 0.01293809227892026 0.010174247183974276 0.007546972735349727 0.005225728102749305 0.0035046384072238567 0.0024198593746372126 0.0017314033525384065 0.0012208498047827992 0.0008364038989139974 0.0005833386314489984 0.000419372128600914 0.00029703600034880007 0.0002053715275466406 0.00015107953004165492 0.0001243940374230888 0.00011899803177516921 0.0001515420616844104 0.0002787785462572576 0.00044462886976899866 0.0006923623475488227 0.0011766546693540315 0.00215753309620079 0.0038244570202485427 0.0061904574852607456 0.009317982583385743 0.013326033228026427 0.017646077493263038 0.020611122010000125 0.020780306627006535 0.01852265778312245 0.015326377141967934 0.012128142883813996 0.009106667450547145 0.006443731463249305 0.004462883841154414 0.0031929167216776413 0.0023548311695479256 0.0017124336763814864 0.0012208498047828037 0.0008847228995316179 0.0006500135096252637 0.00046393379600513017 0.0003185229014366768 0.00022295862859127966 0.00016697925239012162 0.00014536777784027714 0.0001759200090281842 0.0003040176982251567 0.00047351329888212446 0.000726163291897313 0.0012183841389811511 0.0022129533178503248 0.0038961044023771486 0.006270310653227987 0.009383109611456554 0.013355186574400189 0.017674996409659048 0.02078030662700654 0.02125963297086544 0.019358270366481183 0.016410606487398914 0.013300080450640446 0.010250489182735955 0.007517489748370421 0.005460917229675773 0.004098860343354647 0.0031372780911037685 0.0023548311695479325 0.0017314033525384165 0.0012792562992190314 0.0009448983181505491 0.0006797234220084513 0.00047557676264575115 0.00033287461528254034 0.0002365232571313371 0.00018599940050381046 0.00020289046441401718 0.00032350392918556415 0.000478789260105039 0.000716279106869685 0.0011733734294710834 0.002084923017692904 0.0036190780350586144 0.005769895370865575 0.008535272017550808 0.011973630808074336 0.01569272215250288 0.01852265778312246 0.019358270366481186 0.0182594250735667 0.016108051723821834 0.013543651521091854 0.01083412663782937 0.008340585241485121 0.0064390664767518735 0.0051211323279841256 0.00409886034335465 0.0031929167216776513 0.002419859374637221 0.0018108488201475689 0.0013339424895266413 0.0009616996260649247 0.0006872824206897221 0.0004921829205170362 0.0003471667243337981 0.0002543426496727922 0.00024181346590353435 0.00033441079730572745 0.0004557180282623761 0.000657534659225935 0.0010440770375415864 0.0018004153950183037 0.00307560189510735 0.004884730385322293 0.00719425601580247 0.00997725307515428 0.012938092278920264 0.015326377141967936 0.01641060648739892 0.016108051723821834 0.014842004087681639 0.013006136920165742 0.01091608195421444 0.008986628223726749 0.00752178351846932 0.006439066476751877 0.005460917229675777 0.004462883841154422 0.003504638407223864 0.0026549678017238902 0.0019366624294627475 0.001371878137905165 0.0009682847789069772 0.0006895470735222111 0.0004844533228748221 0.00034311220896240854 0.0002898163901862272 0.0003361344573057902 0.0004154374444783388 0.000575989440029754 0.0008828322819484026 0.0014590527240740782 0.00242840762002093 0.0038449800445796004 0.0056888854117370545 0.007878392384066561 0.01017424718397428 0.012128142883814001 0.013300080450640447 0.013543651521091854 0.013006136920165744 0.011961891930324674 0.010754562411234783 0.009724646432491057 0.008986628223726752 0.008340585241485125 0.007517489748370426 0.006443731463249314 0.005225728102749314 0.004001168929060437 0.0028883717904480207 0.001987585477664552 0.0013400322643710243 0.0009066580400836078 0.0006161688271076291 0.0004273720105761963 0.0003349742989234356 0.00033520299743253527 0.00037446751049341443 0.0004998642579464945 0.0007402030304244087 0.001154363207238578 0.0018268018963580788 0.002834046611981743 0.004192815454864293 0.005824229496243897 0.007546972735349728 0.009106667450547147 0.010250489182735958 0.010834126637829372 0.010916081954214441 0.010754562411234785 0.010655259614595913 0.010754562411234785 0.010916081954214438 0.010834126637829372 0.010250489182735956 0.00910666745054715 0.00754697273534973 0.005824229496243899 0.004192815454864295 0.0028340466119817446 0.0018268018963580827 0.0011543632072385786 0.0007402030304244102 0.0004998642579464966 0.00037446751049341394 0.00033613445730579125 0.00033497429892343693 0.00042737201057619484 0.0006161688271076273 0.000906658040083607 0.0013400322643710198 0.00198758547766455 0.002888371790448017 0.004001168929060434 0.005225728102749307 0.006443731463249307 0.007517489748370423 0.008340585241485125 0.008986628223726752 0.00972464643249106 0.010754562411234783 0.011961891930324674 0.013006136920165742 0.013543651521091852 0.013300080450640446 0.012128142883814001 0.01017424718397428 0.007878392384066563 0.005688885411737056 0.0038449800445796026 0.002428407620020934 0.0014590527240740782 0.0008828322819484041 0.0005759894400297565 0.0004154374444783391 0.0003344107973057291 0.0002898163901862293 0.00034311220896240756 0.0004844533228748201 0.0006895470735222095 0.0009682847789069736 0.0013718781379051625 0.0019366624294627447 0.0026549678017238868 0.0035046384072238575 0.0044628838411544134 0.005460917229675774 0.0064390664767518735 0.007521783518469321 0.008986628223726754 0.010916081954214441 0.013006136920165744 0.014842004087681637 0.016108051723821838 0.016410606487398914 0.015326377141967933 0.012938092278920258 0.00997725307515428 0.007194256015802472 0.004884730385322294 0.0030756018951073535 0.0018004153950183035 0.0010440770375415875 0.0006575346592259378 0.000455718028262377 0.000323503929185566 0.00024181346590353682 0.0002543426496727918 0.0003471667243337961 0.0004921829205170345 0.0006872824206897192 0.0009616996260649229 0.0013339424895266396 0.0018108488201475656 0.002419859374637217 0.0031929167216776435 0.00409886034335465 0.005121132327984124 0.006439066476751879 0.00834058524148513 0.010834126637829376 0.013543651521091857 0.016108051723821838 0.0182594250735667 0.019358270366481183 0.018522657783122457 0.015692722152502878 0.011973630808074336 0.008535272017550808 0.005769895370865576 0.0036190780350586174 0.0020849230176929034 0.0011733734294710843 0.0007162791068696877 0.0004787892601050401 0.00030401769822515826 0.00020289046441401945 0.00018599940050381062 0.00023652325713133463 0.0003328746152825388 0.0004755767626457488 0.0006797234220084503 0.0009448983181505478 0.001279256299219031 0.0017314033525384132 0.002354831169547931 0.00313727809110377 0.004098860343354652 0.005460917229675778 0.007517489748370429 0.01025048918273596 0.013300080450640451 0.01641060648739892 0.01935827036648119 0.021259632970865444 0.02078030662700654 0.017674996409659048 0.013355186574400192 0.009383109611456556 0.0062703106532279885 0.0038961044023771508 0.002212953317850324 0.0012183841389811513 0.0007261632918973152 0.0004735132988821253 0.00027877854625725913 0.00017592000902818609 0.00014536777784027817 0.0001669792523901193 0.00022295862859127827 0.00031852290143667645 0.00046393379600513017 0.0006500135096252643 0.0008847228995316224 0.0012208498047828061 0.001712433676381494 0.0023548311695479355 0.003192916721677651 0.004462883841154422 0.006443731463249314 0.009106667450547152 0.012128142883814004 0.015326377141967941 0.018522657783122464 0.020780306627006546 0.020611122010000135 0.017646077493263045 0.013326033228026434 0.009317982583385747 0.006190457485260749 0.0038244570202485453 0.00215753309620079 0.0011766546693540317 0.0006923623475488246 0.00044462886976899915 0.00024516722341408277 0.0001515420616844115 0.00011899803177517033 0.00012439403742308644 0.00015107953004165348 0.00020537152754664153 0.00029703600034880083 0.00041937212860091675 0.000583338631449006 0.0008364038989140085 0.0012208498047828126 0.0017314033525384236 0.002419859374637228 0.003504638407223867 0.005225728102749317 0.007546972735349733 0.010174247183974286 0.012938092278920267 0.015692722152502888 0.017674996409659055 0.017646077493263048 0.015258430610257596 0.01166435972312249 0.00824883073013153 0.005522965993520521 0.0034314450613520202 0.0019497470457856578 0.0010719536575662435 0.0006304765274554578 0.00039880592165459283 0.00019991623908953646 0.00012021240778397814 0.00009202995412545693 0.00009092448574327846 0.00010089256600215806 0.0001277059346777878 0.00018172430257398998 0.000262744136708659 0.0003844573858147929 0.000583338631449007 0.0008847228995316277 0.0012792562992190383 0.0018108488201475734 0.0026549678017238937 0.00400116892906044 0.005824229496243902 0.007878392384066565 0.009977253075154287 0.011973630808074343 0.0133551865744002 0.013326033228026439 0.011664359723122495 0.009110995346707665 0.006586079256877103 0.004478765621190837 0.0028175502559398677 0.0016299924923527586 0.0009163199990738587 0.0005429488252746277 0.00033639172392144407 0.00014926894555382025 0.00008587912888930866 0.0000638346234580342 0.00006124525023194427 0.00006418578918286168 0.00007753218240796608 0.00011089533149964805 0.00016817518667788982 0.0002627441367086608 0.0004193721286009198 0.000650013509625272 0.0009448983181505545 0.0013339424895266465 0.0019366624294627505 0.0028883717904480237 0.004192815454864296 0.00568888541173706 0.007194256015802474 0.008535272017550815 0.009383109611456563 0.00931798258338575 0.008248830730131537 0.006586079256877104 0.004855050110277435 0.00333529810976937 0.0021175621572112526 0.0012523497139305835 0.000725866054146308 0.0004344545721148306 0.00026232352305726315 0.0001055642548890692 0.0000588392558951041 0.00004128492951896402 0.0000372178312229316 0.00003797559959623187 0.000046641626585763075 0.00006935526794947877 0.00011089533149964947 0.00018172430257399502 0.00029703600034880484 0.00046393379600513873 0.000679723422008455 0.0009616996260649308 0.0013718781379051673 0.001987585477664556 0.0028340466119817468 0.003844980044579606 0.004884730385322296 0.005769895370865581 0.006270310653227993 0.006190457485260754 0.005522965993520526 0.004478765621190838 0.003335298109769368 0.0022948326990070516 0.0014682296666435302 0.0008942164552661252 0.0005389628394804287 0.0003264975165632648 0.00019199258158379223 0.0000736423676416483 0.000040463698035910346 0.000024903658690918004 0.000018803416857703442 0.000019767224592742244 0.00002852916790209723 0.000046641626585764024 0.00007753218240796605 0.00012770593467779286 0.00020537152754664247 0.00031852290143668366 0.00047557676264575147 0.0006872824206897251 0.0009682847789069757 0.0013400322643710254 0.001826801896358082 0.002428407620020936 0.0030756018951073535 0.00361907803505862 0.0038961044023771547 0.0038244570202485466 0.0034314450613520246 0.002817550255939868 0.0021175621572112513 0.0014682296666435302 0.0009616761756505678 0.0006144342314509709 0.0003881566193396608 0.00023726111223035202 0.00013600659857995677 0.00005006992510114477 0.000027686800341348234 0.000014330775707506021 0.00000759228294885953 0.000009281165063707765 0.000019767224592743528 0.00003797559959623296 0.00006418578918286421 0.00010089256600216211 0.00015107953004165752 0.00022295862859128318 0.0003328746152825439 0.0004921829205170385 0.0006895470735222133 0.0009066580400836101 0.0011543632072385796 0.0014590527240740797 0.001800415395018306 0.0020849230176929055 0.0022129533178503282 0.002157533096200793 0.001949747045785661 0.0016299924923527604 0.0012523497139305835 0.000894216455266126 0.0006144342314509711 0.00041731035941536666 0.00027403295070508655 0.00016570616231837456 0.00009205475009134033 0.00003183885277159699 0.000019053487707613934 0.000009782308601453122 0.0000048989126297187724 0.000007592282948858844 0.00001880341685770488 0.00003721783122293279 0.00006124525023194656 0.00009092448574328202 0.0001243940374230898 0.0001669792523901237 0.00023652325713133972 0.00034716672433379893 0.00048445332287482375 0.00061616882710763 0.0007402030304244115 0.0008828322819484036 0.0010440770375415886 0.0011733734294710847 0.0012183841389811548 0.0011766546693540317 0.0010719536575662465 0.0009163199990738592 0.0007258660541463075 0.0005389628394804289 0.00038815661933966057 0.0002740329507050858 0.00018025469510181923 0.0001045802073061631 0.00005616002450131068 0.000020781451388427067 0.00001605389868069649 0.000011326048856832537 0.000009782308601452995 0.000014330775707505047 0.000024903658690918062 0.00004128492951896458 0.00006383462345803447 0.0000920299541254592 0.00011899803177517022 0.00014536777784028017 0.00018599940050380954 0.00025434264967279425 0.00034311220896240615 0.00042737201057619674 0.0004998642579464946 0.0005759894400297556 0.0006575346592259354 0.0007162791068696861 0.000726163291897314 0.0006923623475488232 0.0006304765274554592 0.0005429488252746275 0.0004344545721148302 0.0003264975165632651 0.00023726111223035173 0.0001657061623183743 0.00010458020730616368 0.000057456869677794515 0.00003105710711973228 0.000017412833723630988 0.00001707603271819813 0.000016053898680697794 0.000019053487707615133 0.000027686800341348376 0.00004046369803591219 0.00005883925589510555 0.00008587912888931041 0.0001202124077839796 0.00015154206168441252 0.00017592000902818733 0.00020289046441401926 0.0002418134659035367 0.0002898163901862289 0.0003349742989234369 0.00037446751049341427 0.0004154374444783395 0.00045571802826237587 0.00047878926010503866 0.00047351329888212505 0.0004446288697689967 0.0003988059216545925 0.0003363917239214433 0.000262323523057262 0.00019199258158379196 0.0001360065985799558 0.00009205475009133973 0.000056160024501310856 0.00003105710711973203 0.00001954853828186702 0.000009565617953678985 0.000010512830864501234 0.000014781998225036654 0.000023945460612413 0.000036345916316917165 0.00005142955062686027 0.00007364236764164712 0.00010639592520414898 0.0001439069308060291 0.00017526872371932982 0.00019823253447444691 0.00021814488333107103 0.00023414234946933987 0.00023864228845880357 0.00023234710462510235 0.0002276846954364629 0.00023234710462510192 0.0002386422884588014 0.00023414234946933597 0.00021814488333106712 0.0001982325344744443 0.00017526872371932678 0.00014390693080602868 0.00010639592520414877 0.00007364236764164798 0.000051429550626859726 0.00003634591631691749 0.00002394546061241289 0.000014781998225036355 0.000010512830864500963 0.000010512830864501036 0.000012999980140398885 0.000022238587657550093 0.00003976068444587589 0.00006284740975602294 0.00009243873198667838 0.00013600659857995585 0.00019532748400062996 0.00025567699540015784 0.0003003899004650737 0.00033140131162270805 0.00035604221904844067 0.00036504846722240826 0.0003440034197444269 0.00030060001191083906 0.0002578894038511489 0.00022539912279093314 0.00019570183389348462 0.00016417085279852 0.00013719159990130444 0.000118967743476437 0.00010322000910759203 0.00008184139687993089 0.00005799357828135432 0.00004046369803591065 0.00003005028381015951 0.000022426327257490928 0.000015486976475089955 0.000011415154720125809 0.000010520403821836184 0.000014781998225036477 0.000022238587657550286 0.00004136804712597268 0.00007448828453249503 0.00011594604344947278 0.00016665216540789532 0.0002372611122303509 0.00032644896295366165 0.00040903351347927396 0.00046332858412138645 0.0004984623059909905 0.0005270594962774771 0.0005328767055493041 0.0004938311102070539 0.0004227198059680322 0.00035198131564532695 0.00029156831156405507 0.0002307361856879123 0.0001697548150774713 0.00012413553643969693 0.00009890637973825854 0.00008236911364063511 0.00006174356940784354 0.00003947296941473584 0.000024903658690916327 0.000017165388517281 0.000011558312453097888 0.00000743690503609951 0.000007875181309263721 0.000011415154720126014 0.000023945460612412997 0.00003976068444587614 0.00007448828453249484 0.00013093515947900196 0.00019913240892331261 0.0002798504780587137 0.00038815661933965857 0.0005202161617967755 0.0006398426918513259 0.0007181879547709639 0.0007669655867827645 0.0008006309005604024 0.0007970905713095698 0.0007311047369061571 0.0006246264787304537 0.0005209896395607567 0.00042942899124734054 0.00033243221307557543 0.00023267207177716208 0.00015654031394054298 0.00011318982875864121 0.00008687310358683295 0.0000606568747790176 0.00003508250419489705 0.000018803416857701694 0.0000103858531954846 0.000005160683492610259 0.000003120193983496586 0.000007436905036099254 0.00001548697647509013 0.000036345916316917395 0.00006284740975602353 0.00011594604344947263 0.00019913240892331261 0.0003036257116541288 0.0004349316528370981 0.0006144342314509674 0.0008376501878464422 0.001054170370761782 0.0012147289412613553 0.0013149137141692056 0.001357619312193837 0.0013144301327347907 0.001170272483470393 0.000973651085759568 0.0007900615193276598 0.0006333943940810099 0.0004810140756292361 0.0003328103516603664 0.00021758712571748312 0.00014673972099953127 0.00010310204404457717 0.00006762487901666569 0.0000379909505355954 0.000019767224592738866 0.000010657684006566407 0.00000577071719943569 0.000005160683492610622 0.00001155831245309771 0.000022426327257491175 0.00005142955062686024 0.00009243873198667886 0.00016665216540789513 0.00027985047805871355 0.0004349316528370981 0.0006521197197017316 0.0009616761756505626 0.0013573848039995383 0.0017698156072572181 0.002110820674846313 0.0023263946674731383 0.0023815163812629966 0.002244272959114228 0.0019355668732131568 0.0015553507761918548 0.0012072437313161207 0.0009228985548071619 0.0006826700179281655 0.0004765515140829118 0.0003177350737324053 0.00021069153291212634 0.00013978608385999667 0.00008826731038414147 0.00005113278822131277 0.00002852916790209258 0.00001658321203835733 0.00001065768400656792 0.000010385853195486275 0.000017165388517281853 0.00003005028381016026 0.00007364236764164766 0.00013600659857995688 0.00023726111223035118 0.00038815661933965884 0.0006144342314509684 0.0009616761756505632 0.001468229666643525 0.0021175621572112474 0.002817550255939862 0.0034314450613520168 0.0038244570202485392 0.0038961044023771456 0.0036190780350586114 0.003075601895107348 0.002428407620020926 0.001826801896358075 0.0013400322643710154 0.0009682847789069693 0.0006872824206897105 0.00047557676264573797 0.0003185229014366626 0.0002053715275466303 0.0001277059346777788 0.00007753218240795925 0.00004664162658575797 0.00002852916790209323 0.000019767224592740868 0.000018803416857703425 0.000024903658690916534 0.00004046369803591107 0.00010639592520414919 0.00019532748400063096 0.0003264489629536623 0.000520216161796776 0.000837650187846443 0.0013573848039995387 0.002117562157211248 0.0030750543906270084 0.004111723142629155 0.005045103596017063 0.005648678265475138 0.005744944457247073 0.005320251868544279 0.0045261888665479805 0.003574959195501383 0.002654649680287479 0.0018950825958768739 0.0013428023934787066 0.0009614150171436316 0.000680886203629893 0.0004580270798664877 0.00029086213465635727 0.00018259355712859038 0.0001181550147532549 0.00007753218240796014 0.000051132788221314076 0.000037990950535597546 0.00003508250419489921 0.000039472969414736796 0.000057993578281355024 0.00014390693080602897 0.0002556769954001598 0.0004090335134792749 0.0006398426918513267 0.0010541703707617842 0.001769815607257219 0.002817550255939863 0.004111723142629155 0.005502479458646105 0.006767615584404148 0.007593348891884834 0.007727115860575973 0.007172574512613116 0.006144054076131456 0.004883702047003986 0.0036108433250700124 0.0025357859259002233 0.0017735870623411646 0.0012775314669895943 0.0009209194452240633 0.0006269184999834547 0.0004031565891849417 0.0002636332621307518 0.00018259355712859363 0.0001277059346777822 0.00008826731038414429 0.00006762487901666965 0.000060656874779020776 0.0000617435694078442 0.0000818413968799322 0.00017526872371932795 0.0003003899004650731 0.00046332858412138564 0.0007181879547709638 0.0012147289412613553 0.0021108206748463136 0.0034314450613520163 0.005045103596017064 0.006767615584404147 0.008343439782146933 0.009386166372071897 0.009578011906467704 0.008932914694551073 0.00771043317878115 0.006171924531510287 0.004570037806178959 0.003201956733093727 0.0022502321078609693 0.0016519263713297707 0.0012246577971138572 0.0008625415369535906 0.000581760372925606 0.00040315658918494796 0.0002908621346563656 0.00020537152754663627 0.00013978608386000285 0.00010310204404458158 0.00008687310358683629 0.00008236911364063748 0.00010322000910759289 0.0001982325344744447 0.00033140131162270653 0.0004984623059909896 0.0007669655867827643 0.0013149137141692069 0.0023263946674731387 0.00382445702024854 0.005648678265475139 0.007593348891884834 0.0093861663720719 0.010602809983184984 0.010884820552833413 0.010237380254440176 0.008929833570272596 0.007230885503687015 0.005425288999380865 0.0038771846297218173 0.002810080016190194 0.0021391237296633707 0.001643451089220695 0.001208612083667406 0.0008625415369535991 0.0006269184999834667 0.0004580270798664992 0.00031852290143667266 0.00021069153291213303 0.0001467397209995372 0.00011318982875864602 0.00009890637973825984 0.0001189677434764377 0.00021814488333106864 0.0003560422190484393 0.0005270594962774771 0.0008006309005604024 0.001357619312193838 0.0023815163812629966 0.003896104402377147 0.005744944457247074 0.007727115860575973 0.009578011906467702 0.010884820552833411 0.01128723236071913 0.010762009478327436 0.009543175734881951 0.007885851634352308 0.006089358996347638 0.004537419787465309 0.003453012634116636 0.0027352573802774567 0.0021621361682891234 0.0016434510892207046 0.0012246577971138735 0.0009209194452240801 0.000680886203629907 0.00047557676264574746 0.00031773507373241425 0.00021758712571749 0.0001565403139405475 0.0001241355364397 0.00013719159990130593 0.00023414234946933691 0.00036504846722240663 0.0005328767055493022 0.0007970905713095687 0.0013144301327347916 0.0022442729591142284 0.003619078035058613 0.005320251868544279 0.007172574512613116 0.008932914694551073 0.010237380254440178 0.010762009478327436 0.010451266211617061 0.009473934063312553 0.00805326866256104 0.006480340695556078 0.005105322245516997 0.0041071301072263975 0.0033781442189325345 0.002735257380277466 0.0021391237296633867 0.0016519263713297876 0.00127753146698961 0.0009614150171436439 0.0006872824206897194 0.0004765515140829171 0.00033281035166037146 0.00023267207177716544 0.0001697548150774733 0.00016417085279852117 0.00023864228845880172 0.00034400341974442504 0.0004938311102070529 0.0007311047369061561 0.001170272483470393 0.0019355668732131562 0.003075601895107347 0.0045261888665479805 0.006144054076131453 0.007710433178781145 0.00892983357027259 0.00954317573488195 0.009473934063312551 0.008819247828205529 0.0077652715844282435 0.0065805791958524875 0.005545206054145701 0.004760328317029651 0.0041071301072264045 0.0034530126341166486 0.00281008001619021 0.0022502321078609845 0.0017735870623411772 0.0013428023934787166 0.0009682847789069743 0.0006826700179281708 0.0004810140756292392 0.00033243221307557695 0.00023073618568791366 0.0001957018338934844 0.0002323471046251019 0.0003006000119108395 0.0004227198059680323 0.0006246264787304535 0.0009736510857595694 0.0015553507761918548 0.002428407620020928 0.0035749591955013824 0.004883702047003985 0.006171924531510283 0.007230885503687011 0.007885851634352303 0.008053268662561034 0.007765271584428242 0.007171889765094903 0.006507829512702053 0.005963646198878785 0.005545206054145706 0.005105322245517006 0.004537419787465323 0.003877184629721832 0.00320195673309374 0.0025357859259002333 0.0018950825958768814 0.0013400322643710204 0.0009228985548071656 0.0006333943940810126 0.0004294289912473419 0.00029156831156405475 0.00022539912279093363 0.00022768469543646373 0.0002578894038511497 0.00035198131564532825 0.0005209896395607571 0.0007900615193276615 0.0012072437313161224 0.0018268018963580766 0.00265464968028748 0.003610843325070011 0.004570037806178954 0.005425288999380858 0.0060893589963476324 0.006480340695556072 0.006580579195852484 0.006507829512702052 0.006452482316727426 0.006507829512702057 0.0065805791958524935 0.006480340695556089 0.006089358996347651 0.005425288999380877 0.004570037806178968 0.0036108433250700202 0.0026546496802874846 0.0018268018963580788 0.0012072437313161242 0.0007900615193276608 0.0005209896395607571 0.00035198131564532814 0.0002578894038511489 0.00023234710462510268 0.00022539912279093526 0.00029156831156405567 0.0004294289912473422 0.0006333943940810134 0.0009228985548071641 0.0013400322643710187 0.001895082595876876 0.0025357859259002233 0.003201956733093722 0.003877184629721811 0.004537419787465301 0.005105322245516989 0.005545206054145696 0.005963646198878782 0.006507829512702054 0.007171889765094908 0.007765271584428251 0.00805326866256105 0.00788585163435232 0.007230885503687027 0.006171924531510296 0.004883702047003993 0.0035749591955013876 0.00242840762002093 0.0015553507761918567 0.000973651085759569 0.0006246264787304538 0.0004227198059680327 0.00030060001191083944 0.00023864228845880308 0.00019570183389348682 0.00023073618568791523 0.00033243221307557765 0.00048101407562923994 0.0006826700179281697 0.0009682847789069729 0.0013428023934787122 0.0017735870623411662 0.0022502321078609654 0.002810080016190186 0.0034530126341166256 0.004107130107226387 0.004760328317029643 0.0055452060541457005 0.006580579195852489 0.0077652715844282495 0.008819247828205536 0.009473934063312563 0.009543175734881962 0.008929833570272603 0.007710433178781155 0.00614405407613146 0.004526188866547984 0.0030756018951073488 0.0019355668732131573 0.0011702724834703926 0.0007311047369061564 0.0004938311102070537 0.0003440034197444256 0.00023414234946933846 0.00016417085279852399 0.00016975481507747544 0.00023267207177716606 0.00033281035166037205 0.0004765515140829167 0.0006872824206897184 0.0009614150171436401 0.0012775314669896006 0.0016519263713297716 0.0021391237296633655 0.0027352573802774476 0.003378144218932523 0.004107130107226394 0.005105322245517 0.006480340695556083 0.008053268662561047 0.009473934063312562 0.010451266211617074 0.010762009478327445 0.010237380254440187 0.00893291469455108 0.007172574512613121 0.005320251868544281 0.003619078035058614 0.002244272959114229 0.0013144301327347905 0.0007970905713095687 0.0005328767055493031 0.00036504846722240733 0.00021814488333106983 0.0001371915999013084 0.00012413553643970216 0.0001565403139405476 0.00021758712571749042 0.000317735073732414 0.0004755767626457474 0.0006808862036299053 0.0009209194452240764 0.0012246577971138646 0.0016434510892206948 0.0021621361682891155 0.0027352573802774545 0.003453012634116637 0.004537419787465314 0.006089358996347643 0.007885851634352315 0.009543175734881958 0.010762009478327445 0.011287232360719136 0.01088482055283342 0.009578011906467707 0.0077271158605759765 0.005744944457247075 0.0038961044023771464 0.0023815163812629966 0.0013576193121938368 0.0008006309005604017 0.0005270594962774774 0.0003560422190484397 0.00019823253447444559 0.00011896774347643954 0.00009890637973826207 0.00011318982875864571 0.0001467397209995375 0.00021069153291213377 0.00031852290143667396 0.00045802707986650106 0.000626918499983471 0.0008625415369536057 0.0012086120836674158 0.001643451089220705 0.002139123729663381 0.002810080016190203 0.003877184629721825 0.005425288999380871 0.007230885503687022 0.008929833570272602 0.010237380254440185 0.01088482055283342 0.01060280998318499 0.009386166372071904 0.007593348891884837 0.00564867826547514 0.0038244570202485405 0.0023263946674731387 0.0013149137141692056 0.0007669655867827635 0.0004984623059909899 0.0003314013116227065 0.00017526872371932786 0.0001032200091075933 0.00008236911364063887 0.0000868731035868351 0.00010310204404458101 0.00013978608386000383 0.00020537152754663814 0.0002908621346563715 0.00040315658918495923 0.0005817603729256246 0.000862541536953616 0.001224657797113883 0.0016519263713297915 0.0022502321078609823 0.003201956733093737 0.0045700378061789655 0.006171924531510295 0.007710433178781153 0.00893291469455108 0.009578011906467707 0.009386166372071904 0.008343439782146933 0.0067676155844041495 0.005045103596017063 0.0034314450613520163 0.0021108206748463123 0.001214728941261354 0.0007181879547709624 0.0004633285841213854 0.00030038990046507205 0.00014390693080602865 0.00008184139687993197 0.00006174356940784532 0.00006065687477901948 0.00006762487901666894 0.0000882673103841458 0.00012770593467778473 0.00018259355712860016 0.00026363326213076565 0.0004031565891849643 0.0006269184999834842 0.000920919445224092 0.0012775314669896162 0.0017735870623411792 0.0025357859259002333 0.00361084332507002 0.004883702047003992 0.006144054076131459 0.007172574512613122 0.007727115860575978 0.007593348891884839 0.00676761558440415 0.0055024794586461066 0.004111723142629157 0.002817550255939863 0.001769815607257219 0.0010541703707617834 0.000639842691851326 0.000409033513479275 0.0002556769954001587 0.00010639592520414835 0.00005799357828135403 0.0000394729694147373 0.000035082504194897374 0.00003799095053559662 0.000051132788221315635 0.00007753218240796294 0.0001181550147532616 0.00018259355712860363 0.00029086213465637906 0.0004580270798665133 0.000680886203629919 0.0009614150171436529 0.0013428023934787207 0.0018950825958768834 0.0026546496802874854 0.0035749591955013876 0.004526188866547984 0.005320251868544282 0.005744944457247076 0.005648678265475141 0.005045103596017065 0.004111723142629156 0.0030750543906270093 0.0021175621572112483 0.001357384803999539 0.0008376501878464428 0.0005202161617967753 0.00032644896295366225 0.0001953274840006296 0.00007364236764164687 0.00004046369803590998 0.00002490365869091685 0.000018803416857701602 0.000019767224592740157 0.000028529167902094864 0.000046641626585760575 0.00007753218240796464 0.00012770593467779034 0.00020537152754664613 0.0003185229014366854 0.0004755767626457572 0.0006872824206897284 0.0009682847789069793 0.0013400322643710237 0.0018268018963580794 0.0024284076200209318 0.0030756018951073488 0.0036190780350586157 0.0038961044023771473 0.0038244570202485423 0.003431445061352017 0.0028175502559398637 0.0021175621572112483 0.0014682296666435263 0.0009616761756505639 0.0006144342314509691 0.0003881566193396587 0.00023726111223035148 0.0001360065985799558 0.000051429550626859285 0.000030050283810159038 0.00001716538851728185 0.000010385853195484436 0.00001065768400656722 0.000016583212038359026 0.000028529167902095446 0.00005113278822131675 0.0000882673103841499 0.00013978608386000838 0.0002106915329121427 0.0003177350737324193 0.0004765515140829242 0.0006826700179281732 0.0009228985548071676 0.0012072437313161235 0.0015553507761918576 0.001935566873213157 0.0022442729591142297 0.0023815163812629975 0.002326394667473139 0.002110820674846313 0.0017698156072572194 0.0013573848039995391 0.0009616761756505645 0.0006521197197017324 0.0004349316528370989 0.0002798504780587134 0.0001666521654078953 0.00009243873198667766 0.00003634591631691672 0.000022426327257490284 0.000011558312453097722 0.000005160683492609497 0.000005770717199435334 0.000010657684006568218 0.000019767224592741214 0.00003799095053559868 0.00006762487901667209 0.0001031020440445858 0.00014673972099954385 0.0002175871257174957 0.000332810351660377 0.00048101407562924233 0.0006333943940810151 0.000790061519327662 0.0009736510857595698 0.001170272483470393 0.0013144301327347914 0.0013576193121938366 0.0013149137141692066 0.0012147289412613542 0.001054170370761784 0.000837650187846443 0.0006144342314509694 0.00043493165283709856 0.0003036257116541297 0.00019913240892331248 0.00011594604344947269 0.00006284740975602255 0.00002394546061241231 0.000015486976475089396 0.000007436905036099171 0.000003120193983495674 0.000005160683492609752 0.000010385853195486142 0.000018803416857703042 0.000035082504194899726 0.00006065687477902199 0.00008687310358684024 0.00011318982875865059 0.0001565403139405516 0.0002326720717771701 0.0003324322130755801 0.0004294289912473433 0.000520989639560758 0.0006246264787304539 0.0007311047369061563 0.000797090571309569 0.0008006309005604018 0.000766965586782764 0.0007181879547709634 0.0006398426918513272 0.0005202161617967763 0.0003881566193396596 0.000279850478058714 0.000199132408923313 0.00013093515947900145 0.00007448828453249455 0.000039760684445875124 0.000014781998225036166 0.000011415154720125732 0.000007875181309263935 0.000007436905036099088 0.00001155831245309763 0.00001716538851728199 0.000024903658690917462 0.00003947296941473758 0.00006174356940784689 0.00008236911364064104 0.00009890637973826539 0.00012413553643970303 0.00016975481507747813 0.00023073618568791494 0.00029156831156405605 0.00035198131564532695 0.00042271980596803266 0.0004938311102070523 0.0005328767055493014 0.0005270594962774761 0.00049846230599099 0.00046332858412138526 0.00040903351347927543 0.0003264489629536626 0.00023726111223035205 0.00016665216540789543 0.00011594604344947299 0.00007448828453249453 0.00004136804712597235 0.000022238587657549605 0.00001051283086450085 0.000010520403821836123 0.000011415154720125964 0.00001548697647508965 0.000022426327257490467 0.00003005028381016001 0.00004046369803591042 0.00005799357828135499 0.0000818413968799325 0.00010322000910759546 0.00011896774347644129 0.00013719159990130948 0.0001641708527985246 0.00019570183389348627 0.000225399122790935 0.000257889403851149 0.00030060001191083933 0.0003440034197444238 0.00036504846722240576 0.0003560422190484379 0.00033140131162270555 0.0003003899004650715 0.0002556769954001589 0.0001953274840006299 0.0001360065985799569 0.00009243873198667812 0.00006284740975602322 0.000039760684445875375 0.000022238587657549727 0.000012999980140398365 0.0000031293124925016864 0.000004556866447380845 0.000009341733308210803 0.00001742322569700316 0.00002659310644048874 0.00003634591631691868 0.00005006992510114513 0.00007002096897945338 0.00009202672100430687 0.00010990207288447476 0.0001244369771430528 0.00013968876242537805 0.0001533803348213018 0.00015775652622947948 0.00015267581316422965 0.00014878985649779508 0.00015267581316423138 0.00015775652622948165 0.0001533803348213042 0.00013968876242537978 0.00012443697714305344 0.00010990207288447454 0.00009202672100430665 0.0000700209689794536 0.00005006992510114502 0.00003634591631691771 0.000026593106440488145 0.000017423225697002427 0.00000934173330821003 0.000004556866447380899 0.000004556866447380362 0.00000815154795764844 0.000016996134178816483 0.000030311141079121582 0.00004485817630947705 0.00006284740975602419 0.00009205475009134121 0.00013378777557353152 0.00017486743176160945 0.00020226617109821051 0.00022075191810651216 0.00023905748114611003 0.00024962684893333815 0.00023703570095634348 0.00020453187540746634 0.00017215285754228354 0.00014969492195175219 0.00013107499389271264 0.00010991083482162159 0.00008970530400963203 0.00007498642144383827 0.00006307845147368939 0.000049668293720319984 0.000036419779238965724 0.000027686800341349017 0.000022426327257491294 0.000016997532666013203 0.000010432721977928254 0.0000055422661685828285 0.000003983409389722974 0.00000934173330820988 0.000016996134178816015 0.000033426381769640465 0.00005781782971725022 0.00008413408598182858 0.00011594604344947384 0.00016570616231837573 0.00023213625592551602 0.0002900741872742551 0.0003206654954183235 0.00033825695584043956 0.0003605926497320417 0.0003746363628123273 0.00035330476953749853 0.0002999803279416941 0.00024459489967905825 0.00020099329412540375 0.00016134910101133816 0.00012122019196754034 0.00008929388863324412 0.00006978108319975457 0.00005473562818607025 0.000037225400347974834 0.00002174440512866124 0.000014330775707505953 0.00001155831245309845 0.000008699922739312372 0.00000476889079827607 0.0000032397046829915456 0.000005542266168583185 0.00001742322569700212 0.000030311141079121016 0.00005781782971724997 0.00009994215145476977 0.00014628899357183123 0.00019913240892331383 0.00027403295070508666 0.0003662969199368273 0.00044009280330434427 0.0004737128545823653 0.0004915278415428218 0.0005189558821759167 0.0005378107763058987 0.0005110280207879575 0.0004416144748653255 0.00036669495389843646 0.0003017151935110241 0.0002354031801643062 0.00016700154404711097 0.00011453422882452032 0.00008400938969302754 0.00006224326772106277 0.000038268184393991436 0.000017393788614680703 0.000007592282948860224 0.000005160683492611315 0.000004456594710889651 0.000003178772178921801 0.00000476889079827572 0.000010432721977928293 0.0000265931064404876 0.00004485817630947633 0.00008413408598182793 0.0001462889935718308 0.00021909804628488284 0.00030362571165413 0.00041731035941536623 0.000554211743024107 0.0006706709826168834 0.0007370114712795571 0.0007753241069806379 0.0008095426567044833 0.0008160465074447693 0.0007582882900205576 0.0006508099138680056 0.0005404671613561362 0.0004417062437438284 0.00033826785089126826 0.0002326511577507735 0.00015191940053495872 0.00010514847136896204 0.00007553666539708604 0.00004695012607628337 0.000021968432045005126 0.000009281165063708668 0.000005770717199436939 0.0000047872015892067966 0.000004456594710889641 0.000008699922739311893 0.000016997532666013196 0.00003634591631691744 0.00006284740975602339 0.00011594604344947308 0.00019913240892331335 0.0003036257116541299 0.00043493165283709894 0.000614434231450969 0.0008376501878464424 0.0010541703707617825 0.0012147289412613536 0.0013149137141692051 0.0013576193121938366 0.0013144301327347903 0.0011702724834703933 0.0009736510857595704 0.0007900615193276619 0.0006333943940810138 0.00048101407562923956 0.00033281035166037227 0.00021758712571749145 0.00014673972099953984 0.00010310204404458363 0.00006762487901667244 0.00003799095053559957 0.000019767224592742955 0.000010657684006569102 0.000005770717199437455 0.000005160683492611513 0.000011558312453098307 0.000022426327257491504 0.0000500699251011444 0.00009205475009134091 0.00016570616231837516 0.00027403295070508617 0.0004173103594153659 0.0006144342314509686 0.0008942164552661221 0.0012523497139305796 0.0016299924923527536 0.001949747045785653 0.002157533096200785 0.002212953317850319 0.0020849230176928986 0.0018004153950183003 0.0014590527240740747 0.0011543632072385753 0.0009066580400836042 0.0006895470735222086 0.0004921829205170332 0.0003328746152825381 0.00022295862859127754 0.00015107953004165418 0.00010089256600215894 0.0000641857891828626 0.000037975599596232346 0.000019767224592742142 0.00000928116506370898 0.000007592282948860274 0.000014330775707505384 0.000027686800341349125 0.00007002096897945316 0.00013378777557353192 0.00023213625592551624 0.0003662969199368278 0.0005542117430241076 0.0008376501878464425 0.0012523497139305803 0.0017836111952503012 0.00235593934159752 0.0028634056441512587 0.0032006777697295256 0.0032799082195145426 0.003067346428052678 0.0026293898016959937 0.0021106035581529674 0.0016385034701410666 0.0012589495116249148 0.0009554476063526725 0.0007011280080980795 0.0004883595058147539 0.00032387472212927975 0.00021079146292320587 0.00014055573155341686 0.0000967360715647216 0.00006418578918286243 0.000037990950535598996 0.000021968432045004723 0.00001739378861468048 0.0000217444051286608 0.00003641977923896566 0.00009202672100430627 0.00017486743176161007 0.0002900741872742555 0.00044009280330434486 0.0006706709826168842 0.0010541703707617827 0.0016299924923527545 0.0023559393415975203 0.0031243262723721203 0.0038047658255811845 0.0042618377908782805 0.004379127580087871 0.004117426952608119 0.0035548620122397598 0.0028541081215029 0.002180842443607051 0.0016351864912215162 0.0012310199292264736 0.0009232854720992046 0.0006636557209989274 0.0004446632000163234 0.00028716150921594775 0.00019395528069379172 0.0001405557315534167 0.00010089256600215868 0.00006762487901667132 0.00004695012607628297 0.000038268184393991335 0.00003722540034797428 0.000049668293720320126 0.00010990207288447414 0.00020226617109821087 0.0003206654954183238 0.0004737128545823661 0.0007370114712795575 0.001214728941261354 0.0019497470457856532 0.002863405644151259 0.003804765825581184 0.004622831473009574 0.005174646336827454 0.005337764510923122 0.005065990398946276 0.004422978400784088 0.0035655934957543093 0.0026987296766766223 0.001993538699736133 0.0015021101566728289 0.001158357259161514 0.0008696279545382123 0.0006090221462856599 0.0004103825706411219 0.000287161509215948 0.00021079146292320603 0.00015107953004165345 0.00010310204404458333 0.00007553666539708535 0.00006224326772106292 0.00005473562818607028 0.00006307845147368935 0.00012443697714305209 0.00022075191810651235 0.00033825695584043935 0.0004915278415428226 0.0007753241069806385 0.0013149137141692056 0.0021575330962007853 0.003200677769729527 0.004261837790878281 0.0051746463368274554 0.00579539578514296 0.006004520936120329 0.005751359337704064 0.0050813086362769865 0.004139463137881497 0.003158287344604464 0.002361827022744195 0.0018252040088143602 0.0014604937925648616 0.0011458895699827526 0.0008478810904686614 0.0006090221462856603 0.0004446632000163235 0.0003238747221292794 0.0002229586285912774 0.00014673972099953843 0.0001051484713689618 0.00008400938969302735 0.00006978108319975395 0.0000749864214438379 0.00013968876242537761 0.00023905748114611 0.000360592649732042 0.0005189558821759175 0.0008095426567044843 0.0013576193121938372 0.0022129533178503204 0.003279908219514544 0.004379127580087873 0.0053377645109231224 0.006004520936120329 0.006258842946612731 0.006050605342605953 0.005421110613354318 0.004510620325940204 0.0035528377214148147 0.0027739623811732957 0.0022406580347984133 0.0018515398190606298 0.0014902181260945148 0.0011458895699827522 0.0008696279545382126 0.0006636557209989276 0.0004883595058147531 0.0003328746152825373 0.0002175871257174902 0.0001519194005349578 0.00011453422882451947 0.00008929388863324334 0.00008970530400963091 0.00015338033482130176 0.00024962684893333874 0.0003746363628123278 0.0005378107763059003 0.0008160465074447712 0.0013144301327347916 0.0020849230176929008 0.003067346428052679 0.004117426952608121 0.005065990398946278 0.005751359337704066 0.006050605342605955 0.005918258582049202 0.005402100311051646 0.004640662862214505 0.003841618738221896 0.0031833431333577003 0.0026945499014594653 0.0022749560695569777 0.00185153981906063 0.001460493792564862 0.0011583572591615137 0.0009232854720992034 0.0007011280080980784 0.0004921829205170325 0.0003328103516603706 0.00023265115775077344 0.00016700154404711087 0.0001212201919675394 0.00010991083482162025 0.00015775652622947907 0.0002370357009563439 0.0003533047695374995 0.0005110280207879588 0.000758288290020559 0.0011702724834703946 0.0018004153950183018 0.002629389801695996 0.0035548620122397615 0.00442297840078409 0.005081308636276987 0.00542111061335432 0.005402100311051647 0.005066004126662924 0.004534767905786572 0.003975820768717631 0.003505782339925737 0.00310917608707183 0.0026945499014594653 0.002240658034798413 0.001825204008814359 0.0015021101566728278 0.0012310199292264719 0.0009554476063526708 0.0006895470735222068 0.0004810140756292384 0.00033826785089126707 0.00023540318016430505 0.0001613491010113372 0.00013107499389271136 0.0001526758131642295 0.0002045318754074669 0.00029998032794169494 0.0004416144748653272 0.0006508099138680075 0.0009736510857595715 0.0014590527240740774 0.002110603558152969 0.0028541081215029025 0.0035655934957543114 0.004139463137881499 0.004510620325940207 0.0046406628622145075 0.004534767905786572 0.00427301783496627 0.003984092645329023 0.003743027848109887 0.003505782339925737 0.003183343133357699 0.0027739623811732952 0.0023618270227441936 0.0019935386997361323 0.0016351864912215145 0.001258949511624913 0.0009066580400836034 0.0006333943940810125 0.0004417062437438279 0.00030171519351102365 0.00020099329412540302 0.00014969492195175156 0.00014878985649779486 0.00017215285754228432 0.00024459489967905944 0.0003666949538984378 0.0005404671613561383 0.0007900615193276634 0.0011543632072385777 0.001638503470141069 0.0021808424436070535 0.002698729676676625 0.0031582873446044666 0.003552837721414818 0.0038416187382219 0.0039758207687176335 0.0039840926453290244 0.003967720801133167 0.003984092645329023 0.003975820768717631 0.0038416187382218957 0.003552837721414814 0.003158287344604462 0.0026987296766766205 0.00218084244360705 0.0016385034701410653 0.0011543632072385744 0.0007900615193276617 0.0005404671613561364 0.0003666949538984369 0.00024459489967905944 0.00017215285754228397 0.00015267581316423065 0.00014969492195175292 0.00020099329412540394 0.00030171519351102506 0.0004417062437438301 0.0006333943940810145 0.0009066580400836072 0.0012589495116249168 0.0016351864912215186 0.0019935386997361358 0.002361827022744198 0.0027739623811732996 0.003183343133357704 0.00350578233992574 0.0037430278481098895 0.003984092645329023 0.00427301783496627 0.00453476790578657 0.004640662862214503 0.004510620325940202 0.004139463137881496 0.0035655934957543075 0.0028541081215028995 0.002110603558152967 0.0014590527240740747 0.0009736510857595709 0.0006508099138680069 0.00044161447486532746 0.00029998032794169614 0.00020453187540746783 0.00015775652622948108 0.00013107499389271345 0.0001613491010113385 0.00023540318016430665 0.00033826785089126945 0.0004810140756292406 0.0006895470735222102 0.0009554476063526739 0.0012310199292264751 0.0015021101566728306 0.001825204008814362 0.0022406580347984167 0.002694549901459469 0.0031091760870718336 0.00350578233992574 0.003975820768717633 0.004534767905786572 0.005066004126662922 0.005402100311051644 0.005421110613354315 0.005081308636276982 0.004422978400784086 0.003554862012239759 0.002629389801695994 0.0018004153950183014 0.0011702724834703956 0.0007582882900205602 0.0005110280207879605 0.000353304769537502 0.00023703570095634602 0.0001533803348213039 0.00010991083482162244 0.00012122019196754083 0.00016700154404711217 0.00023265115775077553 0.00033281035166037287 0.0004921829205170355 0.0007011280080980812 0.0009232854720992068 0.0011583572591615165 0.0014604937925648644 0.0018515398190606333 0.002274956069556982 0.0026945499014594696 0.003183343133357704 0.0038416187382218987 0.004640662862214507 0.005402100311051645 0.0059182585820492 0.00605060534260595 0.005751359337704063 0.005065990398946276 0.004117426952608121 0.0030673464280526795 0.0020849230176929016 0.001314430132734794 0.0008160465074447736 0.0005378107763059031 0.0003746363628123311 0.0002496268489333414 0.00013968876242537957 0.00008970530400963289 0.00008929388863324467 0.00011453422882452039 0.00015191940053495975 0.00021758712571749218 0.0003328746152825401 0.0004883595058147553 0.0006636557209989302 0.0008696279545382143 0.0011458895699827543 0.0014902181260945174 0.0018515398190606333 0.002240658034798416 0.0027739623811732987 0.0035528377214148164 0.004510620325940205 0.005421110613354316 0.00605060534260595 0.006258842946612728 0.006004520936120326 0.005337764510923122 0.004379127580087874 0.0032799082195145456 0.002212953317850323 0.0013576193121938409 0.0008095426567044877 0.0005189558821759207 0.00036059264973204526 0.0002390574811461126 0.0001244369771430536 0.00007498642144383937 0.0000697810831997553 0.000084009389693028 0.00010514847136896323 0.0001467397209995402 0.00022295862859127963 0.000323874722129281 0.00044466320001632597 0.0006090221462856622 0.0008478810904686642 0.0011458895699827545 0.0014604937925648646 0.0018252040088143618 0.002361827022744197 0.0031582873446044644 0.004139463137881497 0.005081308636276986 0.0057513593377040645 0.00600452093612033 0.005795395785142963 0.005174646336827457 0.004261837790878285 0.00320067776972953 0.0021575330962007896 0.0013149137141692097 0.000775324106980642 0.0004915278415428254 0.00033825695584044216 0.00022075191810651428 0.00010990207288447494 0.0000630784514736902 0.000054735628186071544 0.00006224326772106326 0.00007553666539708627 0.0001031020440445847 0.00015107953004165478 0.00021079146292320725 0.0002871615092159495 0.0004103825706411241 0.0006090221462856628 0.000869627954538215 0.0011583572591615165 0.0015021101566728297 0.001993538699736135 0.002698729676676623 0.0035655934957543097 0.0044229784007840875 0.005065990398946278 0.005337764510923123 0.005174646336827459 0.004622831473009578 0.0038047658255811892 0.0028634056441512626 0.0019497470457856575 0.0012147289412613575 0.0007370114712795606 0.00047371285458236786 0.00032066549541832565 0.00020226617109821168 0.00009202672100430708 0.00004966829372032104 0.000037225400347976094 0.000038268184393992324 0.000046950126076284215 0.00006762487901667297 0.00010089256600215967 0.00014055573155341737 0.00019395528069379226 0.00028716150921594916 0.000444663200016326 0.0006636557209989297 0.0009232854720992056 0.0012310199292264738 0.0016351864912215166 0.002180842443607052 0.002854108121502901 0.0035548620122397615 0.004117426952608123 0.004379127580087876 0.0042618377908782866 0.0038047658255811892 0.0031243262723721255 0.002355939341597525 0.0016299924923527586 0.001054170370761787 0.0006706709826168871 0.00044009280330434676 0.00029007418727425706 0.0001748674317616107 0.00007002096897945387 0.00003641977923896645 0.00002174440512866272 0.000017393788614681625 0.000021968432045005932 0.00003799095053560086 0.00006418578918286345 0.00009673607156472251 0.00014055573155341786 0.00021079146292320738 0.0003238747221292818 0.0004883595058147553 0.0007011280080980804 0.0009554476063526733 0.0012589495116249157 0.0016385034701410677 0.0021106035581529695 0.0026293898016959963 0.0030673464280526813 0.0032799082195145474 0.0032006777697295313 0.002863405644151264 0.002355939341597525 0.0017836111952503056 0.001252349713930584 0.0008376501878464461 0.00055421174302411 0.00036629691993682925 0.0002321362559255174 0.00013378777557353238 0.00005006992510114558 0.000027686800341350294 0.000014330775707507574 0.000007592282948861648 0.000009281165063710577 0.000019767224592744192 0.00003797559959623394 0.00006418578918286294 0.00010089256600215959 0.0001510795300416542 0.00022295862859127977 0.00033287461528253915 0.0004921829205170349 0.000689547073522208 0.0009066580400836058 0.0011543632072385762 0.0014590527240740774 0.0018004153950183029 0.0020849230176929034 0.002212953317850324 0.002157533096200791 0.0019497470457856578 0.0016299924923527589 0.001252349713930584 0.0008942164552661257 0.0006144342314509717 0.0004173103594153685 0.0002740329507050878 0.00016570616231837654 0.00009205475009134195 0.00003634591631691868 0.00002242632725749264 0.000011558312453100263 0.00000516068349261278 0.000005770717199438788 0.000010657684006570988 0.000019767224592744327 0.00003799095053560012 0.00006762487901667312 0.0001031020440445835 0.00014673972099954032 0.00021758712571749055 0.00033281035166037276 0.00048101407562923913 0.0006333943940810141 0.0007900615193276625 0.0009736510857595726 0.0011702724834703965 0.0013144301327347955 0.001357619312193842 0.0013149137141692106 0.0012147289412613581 0.0010541703707617868 0.000837650187846446 0.0006144342314509717 0.0004349316528371011 0.0003036257116541317 0.00019913240892331448 0.00011594604344947422 0.00006284740975602456 0.000026593106440488904 0.000016997532666014433 0.000008699922739313898 0.000004456594710890996 0.000004787201589208164 0.000005770717199438922 0.000009281165063710175 0.000021968432045005566 0.00004695012607628377 0.00007553666539708578 0.00010514847136896211 0.00015191940053495853 0.0002326511577507748 0.00033826785089126864 0.0004417062437438292 0.0005404671613561379 0.0006508099138680084 0.0007582882900205614 0.0008160465074447749 0.0008095426567044883 0.0007753241069806431 0.0007370114712795613 0.0006706709826168871 0.0005542117430241098 0.00041731035941536797 0.00030362571165413126 0.00021909804628488403 0.00014628899357183148 0.00008413408598182872 0.00004485817630947755 0.000017423225697003186 0.000010432721977929368 0.00000476889079827757 0.0000031787721789231114 0.000004456594710890829 0.000005160683492612901 0.00000759228294886136 0.000017393788614681462 0.000038268184393991585 0.00006224326772106322 0.00008400938969302736 0.00011453422882451999 0.00016700154404711103 0.00023540318016430548 0.00030171519351102435 0.00036669495389843803 0.00044161447486532843 0.0005110280207879617 0.0005378107763059038 0.0005189558821759214 0.000491527841542826 0.0004737128545823684 0.0004400928033043468 0.0003662969199368294 0.00027403295070508747 0.00019913240892331416 0.00014628899357183142 0.00009994215145476973 0.000057817829717250166 0.00003031114107912194 0.000009341733308210943 0.000005542266168584276 0.000003239704682993392 0.0000047688907982775025 0.000008699922739313714 0.000011558312453099984 0.000014330775707507176 0.000021744405128661877 0.000037225400347975945 0.00005473562818607072 0.00006978108319975556 0.00008929388863324338 0.00012122019196753966 0.00016134910101133748 0.0002009932941254033 0.0002445948996790592 0.00029998032794169673 0.00035330476953750233 0.00037463636281233174 0.0003605926497320457 0.00033825695584044276 0.00032066549541832597 0.0002900741872742571 0.00023213625592551738 0.00016570616231837608 0.00011594604344947354 0.00008413408598182843 0.00005781782971724998 0.00003342638176964047 0.00001699613417881695 0.0000045568664473809915 0.000003983409389723577 0.0000055422661685842574 0.000010432721977929368 0.000016997532666014182 0.000022426327257492608 0.000027686800341349945 0.000036419779238965974 0.000049668293720320404 0.00006307845147368975 0.00007498642144383873 0.00008970530400963173 0.00010991083482162044 0.00013107499389271177 0.0001496949219517515 0.0001721528575422842 0.0002045318754074682 0.00023703570095634638 0.0002496268489333416 0.00023905748114611238 0.00022075191810651455 0.00020226617109821146 0.00017486743176161042 0.00013378777557353209 0.00009205475009134133 0.00006284740975602358 0.000044858176309476746 0.00003031114107912113 0.00001699613417881618 0.000008151547957649013 0.0000011014415294988164 0.0000024559531885533724 0.000006004795496697776 0.000011308388178075967 0.000017423225697002373 0.000023945460612413054 0.00003183885277159587 0.00004158095417466771 0.000051575019374036114 0.0000602888501315972 0.0000692784110699141 0.00007921512669109847 0.00008836635431708575 0.00009296217033426713 0.00009223278715530842 0.00009102652667143316 0.0000922327871553082 0.00009296217033426756 0.0000883663543170864 0.00007921512669109934 0.00006927841106991496 0.000060288850131598394 0.000051575019374037415 0.000041580954174669444 0.00003183885277159793 0.00002394546061241479 0.000017423225697004 0.000011308388178077268 0.000006004795496698467 0.000002455953188553603 0.0000024559531885537998 0.0000055356148465826476 0.000012912197025182488 0.000022149799803211674 0.00003031114107912192 0.000039760684445876344 0.000056160024501310565 0.00007998449698244372 0.00010298248083767183 0.00011796120117655059 0.00012834877183813862 0.0001388028405714098 0.00014552776986352358 0.000140019573472099 0.00012382628362150958 0.00010792134312512467 0.00009660617943874742 0.00008633426488525685 0.0000731971162145203 0.00005906705547390492 0.00004701150675250932 0.0000370646200096285 0.000028766629952460654 0.000022572177159264153 0.0000190534877076157 0.00001548697647509194 0.000010432721977929851 0.000005404657006735292 0.0000025097644122416697 0.000002036722977856414 0.000006004795496698778 0.00001291219702518306 0.000026517972173532645 0.000043372381336913385 0.00005781782971725189 0.0000744882845324962 0.00010458020730616355 0.00014795151506898847 0.00018588342694629087 0.00020424986233035167 0.00021384675885703652 0.00022811134622592475 0.00023897829057065165 0.00022688081584744334 0.00019372829236130506 0.00016080406028930929 0.0001367882004635741 0.00011571395533526857 0.00009227334361629835 0.00007040658488428558 0.00005348677304968896 0.000038120097772276624 0.000023259926778894986 0.000013352842787481783 0.000009782308601454165 0.000007436905036101816 0.00000476889079827831 0.000002103454138533134 6.970502856828834E-7 0.0000025097644122418205 0.000011308388178077502 0.000022149799803212833 0.000043372381336913955 0.0000722533402025806 0.00009994215145477239 0.0001309351594790039 0.00018025469510181926 0.0002452872893603442 0.00029651146234187616 0.0003158654422010077 0.00032450718525868846 0.00034510117949246375 0.00036446551343221755 0.0003502417832487414 0.00030167391628042634 0.0002493944217476897 0.0002077571576043921 0.00016831495554074034 0.00012639541981940606 0.00009168287533173801 0.00006835590124955292 0.000048024046426983094 0.00002664251965620066 0.000011059872777092924 0.000004898912629720445 0.0000031201939834991532 0.000003178772178924252 0.0000025328140596886403 0.0000021034541385329884 0.000005404657006735378 0.00001742322569700421 0.000030311141079123608 0.000057817829717253026 0.0000999421514547731 0.00014628899357183392 0.0001991324089233152 0.0002740329507050863 0.0003662969199368263 0.0004400928033043427 0.0004737128545823639 0.0004915278415428208 0.0005189558821759162 0.0005378107763058991 0.0005110280207879582 0.0004416144748653272 0.0003666949538984381 0.00030171519351102565 0.00023540318016430765 0.00016700154404711268 0.00011453422882452125 0.00008400938969302854 0.00006224326772106344 0.00003826818439399177 0.000017393788614681 0.00000759228294886118 0.000005160683492613104 0.000004456594710891873 0.000003178772178924185 0.000004768890798277997 0.000010432721977929905 0.000023945460612414803 0.00003976068444587804 0.00007448828453249762 0.00013093515947900524 0.00019913240892331603 0.0002798504780587163 0.00038815661933966036 0.0005202161617967765 0.0006398426918513266 0.0007181879547709636 0.0007669655867827642 0.0008006309005604021 0.000797090571309569 0.0007311047369061575 0.0006246264787304559 0.0005209896395607601 0.00042942899124734477 0.0003324322130755795 0.0002326720717771683 0.0001565403139405502 0.0001131898287586495 0.00008687310358683868 0.000060656874779023094 0.00003508250419490063 0.000018803416857705018 0.000010385853195488002 0.000005160683492612983 0.000003120193983498801 0.000007436905036101343 0.000015486976475091775 0.00003183885277159762 0.000056160024501312415 0.00010458020730616512 0.00018025469510182088 0.00027403295070508785 0.00038815661933966117 0.0005389628394804278 0.0007258660541463061 0.0009163199990738556 0.0010719536575662402 0.0011766546693540267 0.0012183841389811468 0.001173373429471079 0.0010440770375415834 0.0008828322819484006 0.0007402030304244078 0.0006161688271076271 0.0004844533228748211 0.00034716672433379714 0.0002365232571313365 0.00016697925239012078 0.000124394037423088 0.00009092448574327911 0.0000612452502319453 0.000037217831222932336 0.000018803416857704465 0.000007592282948860588 0.000004898912629719744 0.000009782308601453186 0.000019053487707615276 0.000041580954174669105 0.0000799844969824453 0.00014795151506898974 0.00024528728936034565 0.000366296919936828 0.0005202161617967776 0.0007258660541463067 0.0009829449201744793 0.001260701811817081 0.001511550796372855 0.0016880521502273208 0.0017456059351057575 0.0016589400069480257 0.0014604341919198353 0.0012316737057361767 0.0010319639807374764 0.0008589568636188361 0.0006838316235267788 0.0005042574172789256 0.00034950119417327165 0.00023964913362905033 0.00016905754840346017 0.000123048352698993 0.00008987407423056801 0.00006124525023194468 0.00003508250419489974 0.000017393788614680107 0.00001105987277709196 0.000013352842787480826 0.000022572177159263706 0.000051575019374037226 0.00010298248083767318 0.00018588342694629177 0.0002965114623418773 0.00044009280330434405 0.0006398426918513275 0.0009163199990738562 0.001260701811817081 0.001634987129825328 0.001982106453963777 0.0022318845186097475 0.0023155029140805245 0.002204423345366914 0.0019465698802292972 0.0016396186116322176 0.0013560029677948077 0.0011094531117226182 0.0008835265101450356 0.0006692846682037878 0.00047810797513390165 0.00032749602997659904 0.00022463885487634773 0.0001621371192064199 0.00012304835269899211 0.00009092448574327809 0.000060656874779021495 0.000038268184393990684 0.000026642519656199717 0.000023259926778893855 0.000028766629952460237 0.00006028885013159813 0.00011796120117655174 0.0002042498623303524 0.00031586544220100837 0.0004737128545823648 0.0007181879547709641 0.0010719536575662402 0.0015115507963728546 0.0019821064539637763 0.002414862370457805 0.0027278262838996707 0.0028419649976218703 0.0027252012978601485 0.002423979187085861 0.002038034982836015 0.0016584905708846613 0.0013314457145501785 0.0010612533502024906 0.0008297072438039182 0.0006217834696838515 0.0004430836000988343 0.00031008840053104976 0.00022463885487634608 0.0001690575484034582 0.00012439403742308582 0.00008687310358683723 0.00006224326772106238 0.00004802404642698182 0.00003812009777227575 0.00003706462000962808 0.00006927841106991466 0.00012834877183813952 0.00021384675885703676 0.00032450718525868857 0.0004915278415428214 0.0007669655867827642 0.001176654669354027 0.00168805215022732 0.0022318845186097467 0.0027278262838996707 0.003086925039933321 0.0032284375798712238 0.0031199679870699912 0.0028018161266351945 0.0023697225303135187 0.0019295502396633535 0.0015544662428557984 0.0012617286215816505 0.0010219478720986845 0.0008023405097078645 0.0006026697091401619 0.000443083600098832 0.0003274960299765955 0.00023964913362904694 0.00016697925239011826 0.00011318982875864685 0.00008400938969302702 0.0000683559012495514 0.00005348677304968761 0.000047011506752508595 0.00007921512669109878 0.00013880284057141018 0.00022811134622592485 0.00034510117949246365 0.0005189558821759166 0.0008006309005604022 0.0012183841389811468 0.0017456059351057568 0.002315502914080523 0.002841964997621869 0.003228437579871223 0.003393885837083694 0.003310130795263661 0.003017057632244766 0.0026064943852817275 0.0021839809405514556 0.0018231338833620304 0.0015340316098065914 0.0012781043115712648 0.0010287461375447014 0.0008023405097078619 0.0006217834696838474 0.00047810797513389667 0.00034950119417326823 0.00023652325713133338 0.00015654031394054786 0.00011453422882451915 0.00009168287533173623 0.00007040658488428432 0.00005906705547390401 0.0000883663543170859 0.000145527769863524 0.00023897829057065127 0.0003644655134322173 0.0005378107763058993 0.0007970905713095689 0.0011733734294710797 0.0016589400069480253 0.002204423345366913 0.0027252012978601476 0.003119967987069991 0.003310130795263661 0.00327321590283921 0.003050365760317202 0.0027284479596149038 0.002399856396544478 0.0021135152535489182 0.0018521698782702973 0.0015723081188699934 0.001278104311571262 0.0010219478720986802 0.0008297072438039127 0.0006692846682037828 0.0005042574172789218 0.0003471667243337943 0.00023267207177716539 0.00016700154404711084 0.00012639541981940435 0.00009227334361629688 0.00007319711621451941 0.00009296217033426681 0.00014001957347209855 0.00022688081584744274 0.0003502417832487402 0.0005110280207879575 0.0007311047369061566 0.001044077037541583 0.001460434191919835 0.0019465698802292966 0.00242397918708586 0.0028018161266351936 0.0030170576322447675 0.0030503657603172035 0.002931467006558713 0.0027321864074082397 0.002528650327509908 0.002344313469709201 0.002134042701198251 0.0018521698782702953 0.001534031609806587 0.0012617286215816453 0.0010612533502024851 0.0008835265101450311 0.0006838316235267752 0.0004844533228748179 0.000332432213075577 0.0002354031801643053 0.0001683149555407382 0.00011571395533526693 0.00008633426488525578 0.00009223278715530819 0.00012382628362150912 0.0001937282923613037 0.00030167391628042515 0.00044161447486532605 0.0006246264787304545 0.0008828322819484 0.0012316737057361756 0.0016396186116322171 0.0020380349828360146 0.0023697225303135195 0.0026064943852817284 0.0027284479596149055 0.0027321864074082406 0.0026569839345356046 0.0025660434782336585 0.002478914196022791 0.0023443134697091997 0.0021135152535489148 0.0018231338833620257 0.0015544662428557939 0.0013314457145501741 0.001109453111722614 0.0008589568636188332 0.0006161688271076247 0.00042942899124734244 0.00030171519351102397 0.00020775715760439062 0.00013678820046357293 0.0000966061794387468 0.00009102652667143278 0.00010792134312512423 0.00016080406028930853 0.00024939442174768816 0.0003666949538984369 0.000520989639560758 0.0007402030304244063 0.001031963980737475 0.0013560029677948068 0.0016584905708846608 0.0019295502396633538 0.0021839809405514573 0.002399856396544481 0.0025286503275099093 0.0025660434782336598 0.0025665543321341934 0.0025660434782336567 0.002528650327509904 0.002399856396544474 0.0021839809405514504 0.001929550239663349 0.0016584905708846571 0.0013560029677948044 0.0010319639807374735 0.0007402030304244054 0.000520989639560758 0.00036669495389843657 0.0002493944217476881 0.00016080406028930866 0.00010792134312512408 0.00009223278715530858 0.00009660617943874737 0.0001367882004635733 0.000207757157604391 0.0003017151935110246 0.00042942899124734254 0.0006161688271076255 0.0008589568636188337 0.0011094531117226162 0.0013314457145501776 0.0015544662428557993 0.0018231338833620326 0.0021135152535489213 0.002344313469709204 0.002478914196022794 0.0025660434782336585 0.002656983934535602 0.0027321864074082358 0.0027284479596149 0.002606494385281723 0.0023697225303135156 0.0020380349828360116 0.0016396186116322147 0.0012316737057361737 0.0008828322819483985 0.000624626478730454 0.0004416144748653258 0.00030167391628042536 0.00019372829236130425 0.00012382628362150934 0.00009296217033426759 0.00008633426488525692 0.00011571395533526778 0.00016831495554073912 0.00023540318016430627 0.00033243221307557755 0.00048445332287481876 0.0006838316235267758 0.0008835265101450328 0.0010612533502024884 0.0012617286215816498 0.001534031609806593 0.0018521698782702997 0.0021340427011982536 0.0023443134697092027 0.0025286503275099067 0.0027321864074082367 0.0029314670065587085 0.0030503657603171983 0.0030170576322447627 0.0028018161266351906 0.0024239791870858565 0.0019465698802292937 0.0014604341919198325 0.0010440770375415812 0.0007311047369061559 0.0005110280207879571 0.00035024178324874055 0.00022688081584744353 0.00014001957347209914 0.00008836635431708654 0.00007319711621452062 0.0000922733436162979 0.00012639541981940527 0.00016700154404711184 0.0002326720717771661 0.00034716672433379524 0.0005042574172789222 0.0006692846682037843 0.0008297072438039152 0.0010219478720986835 0.001278104311571266 0.0015723081188699951 0.0018521698782702977 0.0021135152535489182 0.0023998563965444766 0.0027284479596149016 0.003050365760317199 0.0032732159028392074 0.0033101307952636575 0.0031199679870699886 0.002725201297860145 0.002204423345366911 0.0016589400069480227 0.0011733734294710773 0.0007970905713095676 0.0005378107763058986 0.0003644655134322173 0.00023897829057065184 0.00014552776986352447 0.00007921512669109894 0.000059067055473904837 0.00007040658488428508 0.00009168287533173676 0.00011453422882452007 0.00015654031394054843 0.0002365232571313341 0.0003495011941732679 0.0004781079751338967 0.0006217834696838468 0.0008023405097078614 0.0010287461375447001 0.0012781043115712627 0.0015340316098065882 0.0018231338833620276 0.0021839809405514526 0.0026064943852817245 0.0030170576322447627 0.0033101307952636575 0.0033938858370836903 0.00322843757987122 0.002841964997621866 0.0023155029140805206 0.001745605935105754 0.0012183841389811444 0.0008006309005604005 0.0005189558821759154 0.0003451011794924631 0.00022811134622592485 0.00013880284057141013 0.00006927841106991446 0.00004701150675250896 0.00005348677304968837 0.00006835590124955179 0.00008400938969302769 0.00011318982875864753 0.00016697925239011883 0.0002396491336290464 0.0003274960299765939 0.0004430836000988282 0.0006026697091401571 0.0008023405097078586 0.0010219478720986787 0.0012617286215816448 0.0015544662428557943 0.00192955023966335 0.002369722530313516 0.002801816126635191 0.0031199679870699878 0.003228437579871219 0.0030869250399333174 0.002727826283899667 0.002231884518609744 0.0016880521502273178 0.001176654669354025 0.0007669655867827629 0.0004915278415428201 0.00032450718525868776 0.00021384675885703652 0.00012834877183813892 0.00006028885013159725 0.00003706462000962762 0.000038120097772276035 0.00004802404642698167 0.0000622432677210626 0.0000868731035868377 0.00012439403742308614 0.00016905754840345713 0.00022463885487634304 0.0003100884005310438 0.0004430836000988261 0.0006217834696838428 0.0008297072438039096 0.001061253350202483 0.0013314457145501733 0.0016584905708846571 0.002038034982836012 0.002423979187085856 0.0027252012978601445 0.0028419649976218647 0.002727826283899666 0.0024148623704578 0.0019821064539637737 0.001511550796372852 0.0010719536575662385 0.0007181879547709622 0.0004737128545823631 0.0003158654422010068 0.0002042498623303516 0.00011796120117655034 0.00005157501937403647 0.000028766629952459678 0.000023259926778894285 0.00002664251965619989 0.000038268184393991226 0.000060656874779022484 0.00009092448574327865 0.0001230483526989913 0.0001621371192064169 0.00022463885487634141 0.0003274960299765903 0.0004781079751338921 0.0006692846682037793 0.000883526510145028 0.0011094531117226125 0.0013560029677948037 0.001639618611632214 0.0019465698802292937 0.00220442334536691 0.0023155029140805197 0.002231884518609743 0.0019821064539637732 0.0016349871298253257 0.0012607018118170794 0.000916319999073855 0.0006398426918513264 0.0004400928033043426 0.0002965114623418761 0.0001858834269462911 0.00010298248083767191 0.000041580954174667885 0.000022572177159262564 0.000013352842787480693 0.000011059872777091726 0.000017393788614680205 0.0000350825041949004 0.00006124525023194502 0.00008987407423056724 0.00012304835269899054 0.00016905754840345483 0.0002396491336290432 0.0003495011941732639 0.0005042574172789183 0.0006838316235267724 0.0008589568636188309 0.0010319639807374725 0.0012316737057361728 0.0014604341919198323 0.001658940006948023 0.001745605935105754 0.001688052150227317 0.001511550796372852 0.0012607018118170794 0.0009829449201744784 0.0007258660541463059 0.0005202161617967764 0.0003662969199368263 0.00024528728936034413 0.00014795151506898858 0.0000799844969824436 0.000031838852771596227 0.000019053487707613978 0.000009782308601452683 0.0000048989126297191265 0.000007592282948860459 0.000018803416857704716 0.000037217831222932586 0.00006124525023194438 0.0000909244857432777 0.00012439403742308398 0.00016697925239011612 0.00023652325713133032 0.00034716672433379205 0.00048445332287481535 0.000616168827107623 0.0007402030304244037 0.000882832281948398 0.001044077037541581 0.001173373429471078 0.0012183841389811446 0.0011766546693540254 0.001071953657566239 0.0009163199990738555 0.0007258660541463063 0.0005389628394804282 0.0003881566193396606 0.0002740329507050866 0.00018025469510181942 0.0001045802073061638 0.00005616002450131072 0.000023945460612412875 0.00001548697647508985 0.000007436905036099987 0.0000031201939834972893 0.0000051606834926119 0.000010385853195487327 0.000018803416857704235 0.000035082504194899346 0.00006065687477902109 0.0000868731035868355 0.00011318982875864541 0.00015654031394054548 0.00023267207177716333 0.00033243221307557446 0.00042942899124734054 0.000520989639560756 0.0006246264787304525 0.0007311047369061548 0.0007970905713095677 0.0008006309005604008 0.0007669655867827629 0.000718187954770963 0.000639842691851327 0.0005202161617967775 0.0003881566193396614 0.0002798504780587163 0.00019913240892331503 0.00013093515947900364 0.00007448828453249594 0.00003976068444587594 0.000017423225697002177 0.000010432721977927768 0.000004768890798276098 0.000003178772178922116 0.000004456594710890081 0.000005160683492611813 0.0000075922829488596915 0.00001739378861467943 0.000038268184393989945 0.00006224326772106124 0.00008400938969302531 0.00011453422882451759 0.00016700154404710935 0.00023540318016430404 0.00030171519351102256 0.00036669495389843527 0.0004416144748653245 0.0005110280207879563 0.0005378107763058985 0.0005189558821759156 0.0004915278415428206 0.000473712854582364 0.00044009280330434394 0.00036629691993682773 0.000274032950705088 0.00019913240892331592 0.00014628899357183362 0.00009994215145477201 0.00005781782971725153 0.00003031114107912161 0.00001130838817807549 0.0000054046570067331 0.0000021034541385306493 0.00000253281405968594 0.0000031787721789217557 0.0000031201939834970454 0.000004898912629718258 0.000011059872777090857 0.000026642519656198592 0.00004802404642698049 0.00006835590124954975 0.00009168287533173504 0.00012639541981940286 0.00016831495554073706 0.00020775715760438965 0.0002493944217476872 0.000301673916280424 0.00035024178324873973 0.00036446551343221673 0.0003451011794924632 0.00032450718525868787 0.0003158654422010076 0.0002965114623418768 0.00024528728936034543 0.00018025469510182083 0.00013093515947900486 0.00009994215145477252 0.00007225334020257993 0.00004337238133691275 0.000022149799803211027 0.000006004795496697475 0.0000025097644122402102 6.970502856809709E-7 0.000002103454138530692 0.000004768890798275864 0.0000074369050360995644 0.000009782308601451858 0.000013352842787479785 0.00002325992677889343 0.00003812009777227496 0.000053486773049687146 0.00007040658488428341 0.00009227334361629613 0.000115713955335266 0.00013678820046357236 0.00016080406028930782 0.00019372829236130324 0.00022688081584744247 0.00023897829057065132 0.00022811134622592472 0.00021384675885703668 0.0002042498623303522 0.00018588342694629196 0.00014795151506898966 0.00010458020730616531 0.00007448828453249737 0.00005781782971725266 0.00004337238133691351 0.00002651797217353215 0.000012912197025182022 0.0000024559531885531086 0.000002036722977855442 0.0000025097644122402814 0.0000054046570067333105 0.000010432721977927649 0.000015486976475089816 0.000019053487707613446 0.000022572177159262287 0.000028766629952458997 0.00003706462000962706 0.00004701150675250769 0.000059067055473903495 0.00007319711621451902 0.00008633426488525554 0.00009660617943874673 0.00010792134312512376 0.00012382628362150871 0.00014001957347209855 0.000145527769863524 0.00013880284057141013 0.00012834877183813933 0.0001179612011765514 0.000102982480837673 0.00007998449698244497 0.000056160024501312435 0.0000397606844458777 0.000030311141079123158 0.000022149799803212294 0.000012912197025182564 0.000005535614846582187 9.81726051017725E-7 0.0000021373228939795493 0.000003996439040512916 0.000006004795496699307 0.000009341733308212104 0.000014781998225039012 0.000020781451388428957 0.000025213591859049892 0.000029077834577928758 0.00003439575992661176 0.000041319385248320714 0.000046397958466131 0.000049264696090273456 0.00005216389130005105 0.000055347440243332644 0.00005704904950991059 0.000055347440243331994 0.000052163891300049644 0.00004926469609027161 0.000046397958466128835 0.00004131938524831833 0.00003439575992660927 0.000029077834577926048 0.000025213591859047074 0.000020781451388426003 0.00001478199822503603 0.000009341733308209556 0.000006004795496697112 0.000003996439040511005 0.0000021373228939785736 0.0000021373228939791745 0.0000036084647764528056 0.000008048688828866994 0.000012912197025183226 0.000016996134178818387 0.000022238587657552844 0.000031057107119735416 0.000042629439945229676 0.0000538441332155412 0.00006258753462346747 0.00006945342397726543 0.00007386269411413273 0.00007494986032959275 0.00007273331620748795 0.00006979335205074739 0.00006774528075202603 0.00006378627298063204 0.000057732138178057005 0.00005081018743244838 0.000043658645204249756 0.00003538581682921512 0.00002671170950945582 0.000020711875659535844 0.00001784863927513446 0.00001605389868069652 0.000011415154720126163 0.000005542266168583229 0.0000025097644122410624 0.000002385841707511477 0.0000027626156523696605 0.000003996439040512145 0.000008048688828866481 0.000016860768505252387 0.00002651797217353259 0.000033426381769643074 0.00004136804712597599 0.00005745686967779826 0.00008197322550826501 0.00010487748323798244 0.00011779395139745302 0.00012514458310738862 0.00013267912482792127 0.0001366557884733702 0.0001291653947954468 0.00011389516179236978 0.00010098659556921376 0.00009111223839643386 0.00008108726648983121 0.00006872525418735331 0.00005534001214467613 0.000042443516252486866 0.000029796252276294253 0.000019165279029501412 0.0000132392881455362 0.000011326048856831707 0.000007875181309264875 0.0000032397046829930702 6.970502856828241E-7 6.283755755589767E-7 0.000002385841707512079 0.000006004795496698472 0.00001291219702518243 0.00002651797217353209 0.00004337238133691348 0.000057817829717253175 0.00007448828453249885 0.00010458020730616731 0.000147951515068992 0.0001858834269462937 0.00020424986233035343 0.00021384675885703752 0.00022811134622592537 0.00023897829057065176 0.00022688081584744364 0.00019372829236130384 0.00016080406028930812 0.00013678820046357195 0.0001157139553352658 0.00009227334361629518 0.0000704065848842826 0.00005348677304968628 0.0000381200977722749 0.000023259926778893485 0.000013352842787480546 0.00000978230860145279 0.000007436905036100996 0.000004768890798277987 0.0000021034541385332692 6.970502856831253E-7 0.0000025097644122419814 0.000009341733308210992 0.00001699613417881717 0.000033426381769641916 0.000057817829717252456 0.00008413408598183135 0.0001159460434494769 0.00016570616231837847 0.00023213625592551817 0.000290074187274256 0.00032066549541832353 0.00033825695584043897 0.0003605926497320419 0.0003746363628123277 0.00035330476953749956 0.00029998032794169413 0.00024459489967905814 0.00020099329412540167 0.00016134910101133556 0.00012122019196753659 0.00008929388863324011 0.00006978108319975057 0.00005473562818606756 0.00003722540034797237 0.000021744405128659573 0.000014330775707505259 0.000011558312453099384 0.000008699922739314137 0.000004768890798278275 0.000003239704682993547 0.0000055422661685843015 0.000014781998225037773 0.000022238587657551303 0.00004136804712597429 0.0000744882845324975 0.00011594604344947612 0.0001666521654078993 0.00023726111223035538 0.00032644896295366577 0.0004090335134792776 0.00046332858412138727 0.0004984623059909907 0.0005270594962774776 0.0005328767055493025 0.0004938311102070535 0.0004227198059680326 0.00035198131564532776 0.0002915683115640537 0.00023073618568791163 0.00016975481507747054 0.00012413553643969715 0.00009890637973825761 0.00008236911364063543 0.0000617435694078432 0.0000394729694147359 0.000024903658690916645 0.00001716538851728297 0.000011558312453099892 0.00000743690503610177 0.000007875181309265814 0.000011415154720127604 0.000020781451388427978 0.000031057107119734 0.000057456869677796365 0.00010458020730616547 0.0001657061623183771 0.00023726111223035463 0.0003264975165632666 0.000434454572114831 0.0005429488252746263 0.0006304765274554547 0.00069236234754882 0.00072616329189731 0.0007162791068696817 0.0006575346592259326 0.0005759894400297511 0.0004998642579464914 0.00042737201057619067 0.00034311220896240247 0.00025434264967278514 0.00018599940050380352 0.00014536777784027074 0.00011899803177516411 0.00009202995412545186 0.00006383462345803074 0.000041284929518961834 0.000024903658690917062 0.000014330775707506279 0.000009782308601454028 0.000011326048856833026 0.0000160538986806983 0.000025213591859049242 0.00004262943994522873 0.00008197322550826339 0.0001479515150689903 0.00023213625592551667 0.0003264489629536647 0.00043445457211483074 0.0005606707485081433 0.0006969509137475135 0.0008239745350408541 0.0009202033550585044 0.0009632349493911857 0.000939591524689103 0.0008649531896832548 0.0007774910755573726 0.0006972250267069887 0.0006092634042455408 0.0004963521413852135 0.0003738581341875531 0.0002744930032920301 0.00020825311966694518 0.00016298950258330377 0.0001254154478450801 0.00009202547110128748 0.00006383462345803163 0.000039472969414737236 0.000021744405128661257 0.00001335284278748225 0.000013239288145537956 0.0000178486392751365 0.000029077834577928375 0.000053844133215540556 0.0001048774832379811 0.00018588342694629196 0.00029007418727425445 0.0004090335134792761 0.0005429488252746256 0.0006969509137475128 0.0008703087826223931 0.0010447624265133965 0.0011822360315786283 0.0012408721734380656 0.0012087368131948207 0.0011191498215588763 0.0010183403054298266 0.0009190083262633676 0.0008015254916949629 0.0006561523056794468 0.0005052944369660862 0.0003796380781566101 0.00028670028072872876 0.00021817936648991154 0.00016606419909648762 0.00012541544784508088 0.00009202995412545372 0.00006174356940784493 0.00003722540034797466 0.000023259926778895705 0.000019165279029503527 0.000020711875659538192 0.000034395759926611816 0.0000625875346234672 0.00011779395139745214 0.0002042498623303521 0.000320665495418322 0.0004633285841213858 0.0006304765274554535 0.0008239745350408528 0.0010447624265133954 0.0012722104792645403 0.001453351627041378 0.001531174685949778 0.001494949249301124 0.0013888305176585182 0.0012624736503087045 0.0011270689633863331 0.0009705099287999332 0.0007970503483696792 0.0006317512268016305 0.0004938979088174631 0.0003820241157457572 0.00029029939436915896 0.00021817936648991327 0.00016298950258330627 0.00011899803177516705 0.0000823691136406388 0.00005473562818607056 0.00003812009777227764 0.000029796252276296933 0.00002671170950945837 0.00004131938524832065 0.00006945342397726513 0.00012514458310738783 0.00021384675885703611 0.00033825695584043766 0.000498462305990989 0.0006923623475488187 0.0009202033550585028 0.0011822360315786266 0.0014533516270413775 0.0016700548810745601 0.0017673346539450819 0.0017355804206419594 0.0016224551241649761 0.0014775571166892995 0.001314527940152104 0.0011311065461327954 0.0009407587239141541 0.0007668541041885596 0.000619928935496512 0.00049361402355586 0.00038202411574575956 0.0002867002807287322 0.00020825311966694894 0.00014536777784027486 0.00009890637973826121 0.00006978108319975414 0.0000534867730496891 0.000042443516252489434 0.00003538581682921752 0.0000463979584661309 0.00007386269411413252 0.000132679124827921 0.00022811134622592447 0.0003605926497320408 0.0005270594962774761 0.0007261632918973087 0.000963234949391184 0.0012408721734380637 0.001531174685949776 0.0017673346539450803 0.0018846393517467812 0.0018739209437563748 0.001779416797872277 0.0016478117139200573 0.0014941165032954463 0.0013165680957763373 0.0011239034969201707 0.0009350204265439972 0.0007654503468072599 0.0006199289354965151 0.0004938979088174678 0.0003796380781566151 0.0002744930032920351 0.00018599940050380816 0.00012413553643970124 0.00008929388863324354 0.00007040658488428546 0.00005534001214467886 0.0000436586452042519 0.00004926469609027327 0.00007494986032959262 0.00013665578847336972 0.00023897829057065127 0.00037463636281232697 0.0005328767055493013 0.000716279106869681 0.0009395915246891014 0.0012087368131948187 0.0014949492493011216 0.0017355804206419573 0.001873920943756373 0.0018998605429481818 0.00184749830338485 0.0017585618402871442 0.0016503940612064283 0.0015145682355305668 0.0013402003972896616 0.001136247025905845 0.000935020426544 0.0007668541041885649 0.0006317512268016363 0.0005052944369660918 0.00037385813418755833 0.0002543426496727901 0.00016975481507747447 0.00012122019196753992 0.00009227334361629777 0.00006872525418735562 0.0000508101874324503 0.00005216389130005088 0.0000727333162074879 0.0001291653947954468 0.00022688081584744315 0.0003533047695374988 0.0004938311102070524 0.0006575346592259315 0.0008649531896832535 0.0011191498215588744 0.0013888305176585152 0.0016224551241649724 0.001779416797872274 0.0018474983033848478 0.0018436353554615178 0.0018017261947860226 0.0017464322160936929 0.001668717292534461 0.001536173869727401 0.0013402003972896642 0.0011239034969201752 0.0009407587239141604 0.0007970503483696854 0.0006561523056794524 0.0004963521413852187 0.00034311220896240675 0.00023073618568791534 0.00016134910101133827 0.00011571395533526785 0.00008108726648983324 0.0000577321381780585 0.000055347440243332746 0.00006979335205074802 0.00011389516179237009 0.000193728292361304 0.00029998032794169424 0.000422719805968032 0.0005759894400297508 0.0007774910755573715 0.0010183403054298248 0.0012624736503087015 0.0014775571166892956 0.0016478117139200523 0.0017585618402871396 0.0018017261947860196 0.001796369665921987 0.0017766517541786214 0.00174687823070364 0.0016687172925344623 0.00151456823553057 0.0013165680957763425 0.0011311065461328017 0.0009705099287999391 0.0008015254916949681 0.0006092634042455452 0.00042737201057619473 0.000291568311564057 0.0002009932941254042 0.00013678820046357368 0.00009111223839643536 0.00006378627298063327 0.000057049049509910456 0.00006774528075202643 0.00010098659556921448 0.0001608040602893086 0.0002445948996790586 0.0003519813156453279 0.0004998642579464915 0.0006972250267069885 0.0009190083262633666 0.001127068963386331 0.0013145279401521005 0.001494116503295441 0.0016503940612064222 0.0017464322160936868 0.0017766517541786186 0.0017783579871622295 0.001776651754178623 0.001746432216093695 0.0016503940612064322 0.0014941165032954517 0.0013145279401521105 0.0011270689633863388 0.0009190083262633726 0.0006972250267069928 0.0004998642579464948 0.00035198131564533053 0.0002445948996790599 0.0001608040602893092 0.00010098659556921475 0.00006774528075202641 0.000055347440243332136 0.00006378627298063274 0.0000911122383964348 0.00013678820046357293 0.00020099329412540302 0.00029156831156405464 0.0004273720105761917 0.0006092634042455413 0.000801525491694963 0.0009705099287999322 0.0011311065461327933 0.001316568095776333 0.0015145682355305608 0.001668717292534454 0.0017468782307036345 0.0017766517541786193 0.0017963696659219891 0.0018017261947860259 0.001758561840287149 0.0016478117139200632 0.0014775571166893064 0.0012624736503087104 0.0010183403054298311 0.0007774910755573762 0.0005759894400297542 0.0004227198059680346 0.0002999803279416955 0.00019372829236130444 0.00011389516179237006 0.00006979335205074748 0.00005216389130004984 0.00005773213817805767 0.0000810872664898324 0.0001157139553352671 0.00016134910101133718 0.0002307361856879134 0.0003431122089624042 0.0004963521413852153 0.000656152305679448 0.0007970503483696796 0.000940758723914153 0.0011239034969201679 0.0013402003972896568 0.0015361738697273939 0.0016687172925344553 0.0017464322160936894 0.0018017261947860226 0.0018436353554615215 0.0018474983033848554 0.0017794167978722837 0.0016224551241649824 0.001388830517658523 0.0011191498215588802 0.0008649531896832576 0.0006575346592259345 0.0004938311102070548 0.00035330476953750005 0.0002268808158474435 0.0001291653947954466 0.00007273331620748715 0.000049264696090271817 0.00005081018743244911 0.00006872525418735452 0.00009227334361629671 0.00012122019196753882 0.0001697548150774728 0.000254342649672788 0.000373858134187556 0.0005052944369660891 0.0006317512268016328 0.000766854104188561 0.0009350204265439969 0.0011362470259058427 0.0013402003972896592 0.0015145682355305642 0.0016503940612064261 0.0017585618402871444 0.0018474983033848534 0.0018998605429481894 0.0018739209437563821 0.0017355804206419664 0.0014949492493011288 0.0012087368131948244 0.0009395915246891051 0.0007162791068696837 0.0005328767055493034 0.000374636362812328 0.00023897829057065138 0.00013665578847336943 0.00007494986032959166 0.00004639795846612882 0.00004365864520425 0.00005534001214467697 0.00007040658488428361 0.00008929388863324196 0.00012413553643969932 0.00018599940050380629 0.0002744930032920332 0.0003796380781566137 0.0004938979088174662 0.0006199289354965147 0.0007654503468072608 0.0009350204265439996 0.0011239034969201722 0.0013165680957763384 0.0014941165032954463 0.0016478117139200584 0.0017794167978722802 0.0018739209437563806 0.0018846393517467875 0.0017673346539450866 0.001531174685949781 0.0012408721734380678 0.0009632349493911869 0.0007261632918973106 0.0005270594962774775 0.00036059264973204135 0.0002281113462259241 0.00013267912482792018 0.00007386269411413107 0.00004131938524831839 0.00003538581682921517 0.00004244351625248737 0.00005348677304968685 0.00006978108319975224 0.00009890637973825949 0.00014536777784027334 0.00020825311966694832 0.00028670028072873255 0.0003820241157457613 0.0004936140235558639 0.0006199289354965177 0.0007668541041885661 0.0009407587239141592 0.0011311065461327996 0.001314527940152107 0.0014775571166893023 0.0016224551241649794 0.0017355804206419638 0.0017673346539450858 0.001670054881074564 0.0014533516270413805 0.0011822360315786294 0.0009202033550585047 0.0006923623475488202 0.0004984623059909901 0.000338256955840438 0.0002138467588570357 0.0001251445831073871 0.00006945342397726345 0.00003439575992660924 0.000026711709509455493 0.000029796252276294477 0.00003812009777227482 0.00005473562818606821 0.00008236911364063684 0.00011899803177516564 0.00016298950258330637 0.00021817936648991493 0.00029029939436916313 0.000382024115745764 0.0004938979088174711 0.0006317512268016389 0.0007970503483696857 0.0009705099287999384 0.0011270689633863368 0.0012624736503087078 0.0013888305176585204 0.0014949492493011266 0.0015311746859497793 0.0014533516270413796 0.001272210479264541 0.0010447624265133965 0.0008239745350408537 0.0006304765274554541 0.0004633285841213861 0.0003206654954183219 0.0002042498623303512 0.0001177939513974512 0.00006258753462346509 0.000029077834577926434 0.000020711875659535735 0.000019165279029501592 0.000023259926778893438 0.00003722540034797272 0.00006174356940784373 0.00009202995412545284 0.00012541544784508155 0.00016606419909648984 0.00021817936648991642 0.000286700280728736 0.0003796380781566185 0.0005052944369660947 0.0006561523056794536 0.0008015254916949681 0.0009190083262633716 0.0010183403054298292 0.0011191498215588783 0.0012087368131948222 0.0012408721734380658 0.0011822360315786277 0.0010447624265133956 0.0008703087826223929 0.0006969509137475131 0.0005429488252746255 0.0004090335134792762 0.0002900741872742544 0.00018588342694629163 0.00010487748323798067 0.00005384413321553895 0.00002521359185904781 0.00001784863927513455 0.000013239288145536533 0.00001335284278748044 0.0000217444051286598 0.000039472969414736464 0.0000638346234580312 0.00009202547110128851 0.00012541544784508264 0.0001629895025833087 0.0002082531196669524 0.00027449300329203814 0.00037385813418756137 0.0004963521413852202 0.0006092634042455458 0.0006972250267069927 0.0007774910755573752 0.0008649531896832565 0.0009395915246891038 0.0009632349493911852 0.0009202033550585032 0.0008239745350408527 0.0006969509137475122 0.0005606707485081424 0.00043445457211482966 0.00032644896295366403 0.00023213625592551632 0.00014795151506899 0.00008197322550826322 0.00004262943994522755 0.00002078145138842728 0.000016053898680697313 0.000011326048856832496 0.000009782308601453196 0.000014330775707505806 0.000024903658690917167 0.00004128492951896229 0.00006383462345803226 0.00009202995412545496 0.00011899803177516879 0.00014536777784027787 0.0001859994005038109 0.00025434264967279317 0.00034311220896240843 0.00042737201057619576 0.0004998642579464947 0.0005759894400297537 0.0006575346592259335 0.0007162791068696828 0.0007261632918973093 0.000692362347548819 0.000630476527455453 0.0005429488252746246 0.0004344545721148293 0.0003264975165632649 0.00023726111223035354 0.0001657061623183768 0.00010458020730616544 0.00005745686967779656 0.000031057107119733545 0.000014781998225037387 0.000011415154720127074 0.000007875181309265827 0.000007436905036101565 0.000011558312453100087 0.000017165388517283577 0.000024903658690917567 0.000039472969414737616 0.00006174356940784585 0.00008236911364063969 0.00009890637973826364 0.0001241355364397033 0.00016975481507747718 0.00023073618568791675 0.0002915683115640578 0.0003519813156453304 0.0004227198059680342 0.0004938311102070538 0.0005328767055493023 0.0005270594962774761 0.0004984623059909885 0.00046332858412138456 0.0004090335134792746 0.0003264489629536629 0.00023726111223035273 0.00016665216540789746 0.00011594604344947528 0.00007448828453249714 0.00004136804712597431 0.00002223858765755101 0.000009341733308210754 0.000005542266168584129 0.0000032397046829939325 0.000004768890798278595 0.000008699922739314856 0.000011558312453100626 0.000014330775707506627 0.000021744405128661525 0.00003722540034797516 0.00005473562818607148 0.00006978108319975598 0.00008929388863324568 0.00012122019196754244 0.00016134910101134014 0.00020099329412540538 0.00024459489967906063 0.0002999803279416955 0.0003533047695374996 0.00037463636281232735 0.00036059264973204043 0.0003382569558404369 0.0003206654954183206 0.0002900741872742528 0.00023213625592551489 0.0001657061623183754 0.00011594604344947457 0.00008413408598182995 0.00005781782971725161 0.000033426381769641516 0.00001699613417881685 0.00000600479549669807 0.0000025097644122418175 6.970502856835564E-7 0.0000021034541385337067 0.000004768890798278901 0.000007436905036102499 0.000009782308601454277 0.000013352842787482321 0.000023259926778895657 0.000038120097772277824 0.00005348677304968987 0.00007040658488428666 0.00009227334361629942 0.00011571395533526948 0.00013678820046357463 0.0001608040602893099 0.00019372829236130444 0.00022688081584744323 0.0002389782905706508 0.00022811134622592328 0.0002138467588570345 0.00020424986233035 0.00018588342694628987 0.0001479515150689883 0.00010458020730616361 0.00007448828453249581 0.000057817829717250905 0.00004337238133691177 0.000026517972173530918 0.000012912197025181688 0.00000399643904051191 0.0000023858417075123582 6.283755755599387E-7 6.970502856838313E-7 0.0000032397046829945525 0.000007875181309266803 0.000011326048856833751 0.000013239288145538268 0.000019165279029504045 0.000029796252276297184 0.00004244351625249042 0.000055340012144679626 0.00006872525418735701 0.00008108726648983418 0.00009111223839643622 0.00010098659556921542 0.00011389516179237047 0.0001291653947954465 0.00013665578847336918 0.00013267912482791962 0.00012514458310738648 0.00011779395139745038 0.0001048774832379793 0.00008197322550826157 0.00005745686967779466 0.00004136804712597267 0.00003342638176964038 0.00002651797217353041 0.000016860768505250757 0.000008048688828865619 0.000002137322893978969 0.000002762615652370274 0.0000023858417075129033 0.0000025097644122426565 0.0000055422661685851985 0.00001141515472012854 0.000016053898680698926 0.000017848639275136702 0.000020711875659538226 0.000026711709509458285 0.00003538581682921774 0.00004365864520425236 0.00005081018743245126 0.000057732138178059254 0.0000637862729806338 0.00006774528075202696 0.00006979335205074783 0.00007273331620748723 0.00007494986032959162 0.00007386269411413088 0.00006945342397726313 0.00006258753462346482 0.00005384413321553829 0.00004262943994522644 0.00003105710711973199 0.000022238587657549456 0.000016996134178815524 0.000012912197025180743 0.000008048688828864992 0.0000036084647764516905 8.73149757648946E-7 0.000001572758838966122 0.000002137322893979895 0.000002455953188554111 0.000004556866447380913 0.000010512830864501505 0.000017412833723631164 0.00002043402073581053 0.00002254157915948041 0.000028324619977964293 0.00003557185750931483 0.00003732366030448136 0.000034944686828870006 0.00003597365585370068 0.000041943241076210116 0.000045894925507421126 0.00004194324107621001 0.000035973655853700466 0.000034944686828870114 0.00003732366030448158 0.000035571857509315375 0.00002832461997796478 0.000022541579159481115 0.000020434020735811832 0.00001741283372363271 0.000010512830864502996 0.000004556866447382051 0.0000024559531885546803 0.0000021373228939800372 0.0000015727588389660542 0.0000015727588389653844 0.0000018701035482082512 0.000003608464776452416 0.000005535614846582189 0.000008151547957648525 0.00001299998014039879 0.00001954853828186793 0.000025034130620912433 0.000030180522486131775 0.000036828364883750426 0.000043235477902207156 0.00004471729841545048 0.000042337647069579435 0.00004185228624762004 0.000046039876205685614 0.000050287544943851445 0.000048040463162600606 0.000042464763661088364 0.00003927679355651664 0.0000381825714902006 0.00003378055041345835 0.00002584965898538766 0.000020532050107830184 0.00001908838218432385 0.000017076032718201206 0.000010520403821839167 0.000003983409389725189 0.0000020367229778577654 0.0000027626156523706003 0.0000028589217517652334 0.0000021373228939785494 0.000003608464776451687 0.000008048688828865551 0.000012912197025181463 0.000016996134178816103 0.000022238587657550002 0.000031057107119732766 0.00004262943994522755 0.00005384413321554019 0.00006258753462346737 0.00006945342397726634 0.00007386269411413395 0.00007494986032959446 0.0000727333162074898 0.0000697933520507496 0.00006774528075202793 0.00006378627298063517 0.0000577321381780606 0.000050810187432452754 0.000043658645204254134 0.00003538581682921929 0.000026711709509459118 0.000020711875659539025 0.000017848639275137772 0.000016053898680700457 0.000011415154720129993 0.0000055422661685865275 0.0000025097644122433337 0.0000023858417075126293 0.000002762615652369644 0.000002455953188552689 0.000005535614846581098 0.000012912197025180914 0.000022149799803210258 0.00003031114107912091 0.000039760684445875734 0.000056160024501310903 0.00007998449698244437 0.00010298248083767322 0.00011796120117655212 0.00012834877183814046 0.00013880284057141154 0.0001455277698635257 0.0001400195734721005 0.00012382628362151048 0.00010792134312512538 0.00009660617943874882 0.00008633426488525863 0.0000731971162145227 0.00005906705547390762 0.00004701150675251195 0.000037064620009630994 0.000028766629952463148 0.000022572177159266623 0.000019053487707618325 0.00001548697647509452 0.000010432721977932138 0.000005404657006736728 0.0000025097644122421957 0.0000020367229778559735 0.0000045568664473796735 0.000008151547957647344 0.000016996134178815236 0.00003031114107912057 0.000044858176309476136 0.0000628474097560231 0.00009205475009134019 0.00013378777557353032 0.0001748674317616085 0.00020226617109820954 0.00022075191810651205 0.00023905748114611065 0.0002496268489333396 0.00023703570095634513 0.0002045318754074676 0.00017215285754228465 0.0001496949219517533 0.0001310749938927138 0.00010991083482162284 0.00008970530400963329 0.00007498642144383938 0.00006307845147369026 0.0000496682937203212 0.00003641977923896746 0.000027686800341352137 0.000022426327257495115 0.0000169975326660168 0.000010432721977930847 0.000005542266168584273 0.00000398340938972269 0.000010512830864500727 0.000012999980140397884 0.000022238587657549172 0.00003976068444587528 0.000062847409756023 0.00009243873198667849 0.0001360065985799567 0.00019532748400063064 0.0002556769954001602 0.00030038990046507395 0.00033140131162270805 0.000356042219048441 0.0003650484672224081 0.0003440034197444266 0.0003006000119108411 0.00025788940385115095 0.00022539912279093648 0.00019570183389348744 0.00016417085279852464 0.0001371915999013091 0.0001189677434764404 0.00010322000910759442 0.00008184139687993344 0.00005799357828135614 0.00004046369803591311 0.00003005028381016287 0.000022426327257493984 0.000015486976475092303 0.000011415154720127205 0.00001052040382183655 0.00001741283372363091 0.000019548538281867484 0.00003105710711973213 0.00005616002450131058 0.00009205475009134022 0.00013600659857995672 0.00019199258158379177 0.0002623235230572621 0.00033639172392144255 0.0003988059216545913 0.00044462886976899714 0.0004735132988821233 0.0004787892601050375 0.0004557180282623749 0.00041543744447833744 0.00037446751049341297 0.0003349742989234355 0.0002898163901862278 0.00024181346590353492 0.00020289046441401755 0.0001759200090281835 0.00015154206168440916 0.0001202124077839763 0.00008587912888930806 0.000058839255895104785 0.00004046369803591205 0.000027686800341350223 0.000019053487707615692 0.0000160538986806976 0.000017076032718198902 0.000020434020735810795 0.000025034130620912586 0.00004262943994522741 0.00007998449698244444 0.00013378777557353076 0.00019532748400063115 0.00026232352305726267 0.0003384606851108126 0.00042223688521968693 0.0005030317145494122 0.0005666602319166294 0.0006011759042085236 0.0006045988410517454 0.0005865215698875149 0.000560334919535245 0.0005287625121494365 0.00048131016516047485 0.00041445894177783837 0.0003443313341783644 0.0002890580940773154 0.0002477776759972901 0.0002087267249035101 0.0001648417828318426 0.00012121774671322388 0.0000858791288893079 0.00005799357828135503 0.00003641977923896559 0.000022572177159264296 0.000017848639275135577 0.000019088382184322324 0.000022541579159480438 0.000030180522486131836 0.00005384413321553998 0.00010298248083767297 0.00017486743176160858 0.0002556769954001603 0.00033639172392144277 0.00042223688521968655 0.000522213776046088 0.0006296342986623047 0.0007178665296542983 0.0007609761381989926 0.0007619127265753567 0.0007465776724080118 0.000731338663629734 0.0007038565058097151 0.0006423483931220747 0.0005519973573561713 0.00046335640422670647 0.000395765185072558 0.00033999731898393977 0.0002817392936413644 0.0002203339374047312 0.00016484178283184225 0.00012021240778397596 0.00008184139687993205 0.000049668293720319455 0.000028766629952461023 0.00002071187565953727 0.000020532050107829174 0.0000283246199779644 0.00003682836488375047 0.00006258753462346728 0.0001179612011765518 0.00020226617109820946 0.0003003899004650738 0.00039880592165459104 0.0005030317145494111 0.0006296342986623036 0.0007727221740842524 0.0008912224146887228 0.0009450532555018931 0.0009416347748850405 0.0009218909549822114 0.0009055757124909051 0.0008701737083641742 0.0007900599153244937 0.0006814304005537377 0.0005841060597842265 0.0005122217700908191 0.0004453625188348296 0.0003660870006756803 0.000281739293641364 0.00020872672490350954 0.0001515420616844086 0.00010322000910759309 0.00006307845147368843 0.00003706462000962894 0.000026711709509457732 0.00002584965898538693 0.00003557185750931473 0.00004323547790220699 0.00006945342397726592 0.00012834877183813987 0.00022075191810651165 0.0003314013116227074 0.0004446288697689965 0.0005666602319166277 0.0007178665296542958 0.0008912224146887213 0.0010359122065182215 0.0011033690494170352 0.0011029764516615197 0.0010826685402583528 0.0010633634004518972 0.0010189283889044795 0.000924856441188799 0.0008039528511211447 0.0006992403467680923 0.0006206635119981436 0.0005424395332519894 0.0004453625188348291 0.00033999731898393874 0.00024777767599728904 0.00017592000902818243 0.00011896774347643816 0.00007498642144383707 0.000047011506752509497 0.000035385816829217554 0.000033780550413457466 0.00003732366030448127 0.000044717298415450275 0.00007386269411413385 0.00013880284057141108 0.00023905748114611027 0.00035604221904844046 0.0004735132988821227 0.0006011759042085219 0.0007609761381989897 0.0009450532555018899 0.0011033690494170328 0.0011893217655105709 0.0012098210104861294 0.0012065670294402883 0.0011973429792128606 0.0011579051791739592 0.001064658884371395 0.0009370424568941269 0.0008161527036543634 0.0007164119706880112 0.0006206635119981425 0.0005122217700908176 0.00039576518507255626 0.00028905809407731367 0.00020289046441401555 0.00013719159990130647 0.00008970530400963048 0.00005906705547390514 0.000043658645204252765 0.00003818257149019987 0.00003494468682887018 0.00004233764706957948 0.00007494986032959442 0.00014552776986352558 0.00024962684893333994 0.0003650484672224083 0.00047878926010503796 0.0006045988410517448 0.0007619127265753547 0.0009416347748850375 0.001102976451661517 0.0012098210104861276 0.0012632413019571759 0.001288367892250479 0.001297557394589066 0.0012756356763438045 0.0012018072025311488 0.0010815579702260186 0.0009448279369217326 0.0008161527036543626 0.0006992403467680908 0.0005841060597842248 0.0004633564042267046 0.0003443313341783627 0.00024181346590353313 0.00016417085279852193 0.00010991083482162055 0.00007319711621452102 0.000050810187432451995 0.00003927679355651668 0.00003597365585370076 0.00004185228624762028 0.00007273331620748986 0.00014001957347210052 0.00023703570095634545 0.00034400341974442726 0.00045571802826237576 0.0005865215698875154 0.000746577672408011 0.0009218909549822096 0.0010826685402583502 0.0012065670294402868 0.0012883678922504783 0.0013339022226082516 0.0013517795309755719 0.001344556015996116 0.0013021331758599143 0.0012123734799485103 0.0010815579702260186 0.0009370424568941262 0.0008039528511211433 0.0006814304005537364 0.0005519973573561699 0.000414458941777837 0.00028981639018622613 0.0001957018338934856 0.0001310749938927123 0.00008633426488525771 0.00005773213817806066 0.00004246476366108878 0.000041943241076210354 0.000046039876205686075 0.00006979335205075006 0.00012382628362151105 0.00020453187540746845 0.0003006000119108421 0.00041543744447833906 0.0005603349195352462 0.0007313386636297344 0.0009055757124909049 0.0010633634004518961 0.0011973429792128596 0.0012975573945890652 0.0013517795309755717 0.0013659066902064595 0.0013626764404337497 0.0013490440679071677 0.001302133175859914 0.0012018072025311484 0.0010646588843713938 0.0009248564411887978 0.0007900599153244927 0.0006423483931220738 0.0004813101651604738 0.00033497429892343454 0.00022539912279093526 0.0001496949219517527 0.00009660617943874877 0.00006378627298063568 0.000048040463162601446 0.00004589492550742116 0.000050287544943851825 0.00006774528075202842 0.00010792134312512572 0.0001721528575422854 0.00025788940385115203 0.0003744675104934146 0.0005287625121494382 0.0007038565058097165 0.0008701737083641753 0.00101892838890448 0.001157905179173959 0.0012756356763438045 0.0013445560159961157 0.00136267644043375 0.0013618288308587466 0.0013626764404337493 0.001344556015996115 0.001275635676343804 0.0011579051791739585 0.0010189283889044793 0.0008701737083641743 0.0007038565058097152 0.0005287625121494363 0.0003744675104934125 0.0002578894038511504 0.00017215285754228454 0.00010792134312512586 0.0000677452807520289 0.000050287544943852164 0.00004194324107620965 0.00004804046316260057 0.000063786272980635 0.00009660617943874859 0.0001496949219517536 0.00022539912279093688 0.0003349742989234367 0.00048131016516047615 0.000642348393122076 0.0007900599153244952 0.0009248564411888004 0.0010646588843713958 0.0012018072025311495 0.0013021331758599145 0.0013490440679071682 0.0013626764404337493 0.0013659066902064589 0.001351779530975571 0.0012975573945890658 0.001197342979212861 0.0010633634004518983 0.0009055757124909059 0.0007313386636297341 0.0005603349195352446 0.00041543744447833695 0.00030060001191084036 0.00020453187540746758 0.00012382628362151088 0.0000697933520507501 0.000046039876205685736 0.00003597365585370008 0.00004246476366108828 0.00005773213817806051 0.00008633426488525826 0.00013107499389271383 0.00019570183389348777 0.0002898163901862286 0.00041445894177783934 0.0005519973573561722 0.0006814304005537391 0.0008039528511211465 0.0009370424568941289 0.0010815579702260199 0.0012123734799485107 0.0013021331758599143 0.001344556015996115 0.0013517795309755708 0.001333902222608251 0.0012883678922504796 0.0012065670294402898 0.001082668540258354 0.0009218909549822121 0.0007465776724080115 0.000586521569887514 0.0004557180282623739 0.00034400341974442586 0.00023703570095634486 0.00014001957347210052 0.00007273331620748989 0.000041852286247619986 0.00003494468682886992 0.000039276793556516913 0.000050810187432452794 0.0000731971162145224 0.00010991083482162277 0.0001641708527985245 0.0002418134659035356 0.00034433133417836496 0.0004633564042267073 0.0005841060597842276 0.0006992403467680943 0.0008161527036543659 0.0009448279369217349 0.0010815579702260199 0.001201807202531149 0.0012756356763438039 0.0012975573945890654 0.001288367892250479 0.0012632413019571782 0.0012098210104861317 0.0011029764516615219 0.000941634774885041 0.0007619127265753562 0.000604598841051744 0.00047878926010503677 0.00036504846722240744 0.0002496268489333397 0.00014552776986352585 0.00007494986032959475 0.000042337647069579536 0.00003732366030448152 0.00003818257149020075 0.00004365864520425418 0.00005906705547390704 0.00008970530400963302 0.0001371915999013088 0.00020289046441401753 0.0002890580940773151 0.00039576518507255766 0.0005122217700908191 0.0006206635119981446 0.0007164119706880132 0.0008161527036543651 0.0009370424568941278 0.0010646588843713947 0.0011579051791739583 0.0011973429792128598 0.0012065670294402879 0.0012098210104861302 0.0011893217655105726 0.0011033690494170354 0.0009450532555018917 0.0007609761381989906 0.0006011759042085212 0.00047351329888212186 0.0003560422190484401 0.00023905748114611062 0.00013880284057141162 0.00007386269411413446 0.00004471729841545076 0.00003557185750931526 0.000033780550413458475 0.000035385816829219336 0.000047011506752511394 0.00007498642144383921 0.00011896774347643996 0.0001759200090281835 0.0002477776759972896 0.0003399973189839388 0.0004453625188348288 0.0005424395332519895 0.0006206635119981439 0.0006992403467680928 0.0008039528511211452 0.0009248564411887994 0.0010189283889044797 0.001063363400451897 0.001082668540258352 0.0011029764516615188 0.0011033690494170335 0.0010359122065182207 0.0008912224146887203 0.0007178665296542953 0.0005666602319166269 0.0004446288697689959 0.00033140131162270745 0.00022075191810651222 0.0001283487718381406 0.00006945342397726687 0.00004323547790220758 0.00002832461997796456 0.00002584965898538739 0.000026711709509459108 0.00003706462000963019 0.00006307845147368975 0.00010322000910759397 0.00015154206168440892 0.0002087267249035096 0.0002817392936413632 0.0003660870006756789 0.000445362518834828 0.0005122217700908177 0.0005841060597842259 0.0006814304005537374 0.0007900599153244942 0.0008701737083641752 0.0009055757124909055 0.0009218909549822101 0.0009416347748850379 0.0009450532555018884 0.0008912224146887185 0.0007727221740842489 0.0006296342986623015 0.0005030317145494099 0.00039880592165459017 0.0003003899004650734 0.00020226617109820965 0.00011796120117655204 0.00006258753462346795 0.00003682836488375057 0.000022541579159480838 0.000020532050107829706 0.000020711875659538812 0.000028766629952462443 0.00004966829372032076 0.00008184139687993308 0.0001202124077839763 0.00016484178283184236 0.00022033393740473033 0.00028173929364136267 0.00033999731898393766 0.00039576518507255577 0.0004633564042267051 0.0005519973573561708 0.0006423483931220749 0.0007038565058097163 0.0007313386636297343 0.0007465776724080108 0.0007619127265753537 0.0007609761381989874 0.0007178665296542929 0.0006296342986623004 0.0005222137760460855 0.0004222368852196855 0.00033639172392144217 0.00025567699540016023 0.00017486743176160888 0.00010298248083767345 0.000053844133215540834 0.000030180522486132033 0.000020434020735811588 0.00001908838218432317 0.00001784863927513727 0.000022572177159265654 0.00003641977923896669 0.00005799357828135579 0.00008587912888930802 0.00012121774671322405 0.00016484178283184212 0.00020872672490350892 0.00024777767599728833 0.0002890580940773132 0.00034433133417836295 0.0004144589417778378 0.00048131016516047507 0.0005287625121494377 0.0005603349195352457 0.0005865215698875145 0.0006045988410517431 0.0006011759042085194 0.0005666602319166252 0.0005030317145494089 0.00042223688521968514 0.00033846068511081217 0.0002623235230572623 0.0001953274840006312 0.00013378777557353106 0.00007998449698244501 0.00004262943994522851 0.000025034130620913118 0.000017412833723632983 0.00001707603271820102 0.000016053898680700068 0.00001905348770761748 0.000027686800341351327 0.00004046369803591245 0.00005883925589510464 0.00008587912888930786 0.00012021240778397615 0.00015154206168440832 0.00017592000902818243 0.00020289046441401544 0.00024181346590353365 0.00028981639018622684 0.0003349742989234357 0.0003744675104934138 0.0004154374444783384 0.0004557180282623746 0.0004787892601050369 0.000473513298882121 0.00044462886976899524 0.0003988059216545899 0.0003363917239214424 0.0002623235230572628 0.0001919925815837926 0.00013600659857995767 0.00009205475009134139 0.000056160024501312055 0.00003105710711973423 0.000019548538281869368 0.00001051283086450379 0.00001052040382183948 0.000011415154720129966 0.000015486976475093797 0.000022426327257494238 0.000030050283810161985 0.00004046369803591153 0.00005799357828135471 0.00008184139687993207 0.00010322000910759261 0.00011896774347643806 0.0001371915999013061 0.000164170852798522 0.0001957018338934858 0.00022539912279093588 0.00025788940385115117 0.00030060001191084144 0.00034400341974442645 0.00036504846722240755 0.0003560422190484396 0.00033140131162270685 0.00030038990046507325 0.00025567699540016034 0.00019532748400063164 0.00013600659857995772 0.00009243873198667972 0.00006284740975602455 0.00003976068444587723 0.00002223858765755192 0.00001299998014040068 0.000004556866447383407 0.000003983409389726192 0.000005542266168587071 0.000010432721977931928 0.000016997532666016137 0.000022426327257493113 0.000027686800341349423 0.00003641977923896498 0.00004966829372031921 0.00006307845147368805 0.0000749864214438368 0.00008970530400963029 0.00010991083482162049 0.00013107499389271237 0.0001496949219517529 0.00017215285754228516 0.00020453187540746831 0.00023703570095634535 0.00024962684893333983 0.00023905748114611027 0.00022075191810651203 0.00020226617109820967 0.00017486743176160912 0.00013378777557353154 0.00009205475009134147 0.00006284740975602455 0.00004485817630947802 0.00003031114107912289 0.00001699613417881837 0.000008151547957650781 0.000002455953188556177 0.000002036722977859156 0.000002509764412244402 0.000005404657006736967 0.00001043272197793052 0.00001548697647509154 0.000019053487707614757 0.000022572177159263425 0.000028766629952460417 0.00003706462000962825 0.0000470115067525089 0.000059067055473904586 0.00007319711621452056 0.0000863342648852576 0.00009660617943874849 0.00010792134312512591 0.00012382628362151126 0.0001400195734721007 0.00014552776986352564 0.00013880284057141124 0.00012834877183813995 0.00011796120117655186 0.0001029824808376733 0.0000799844969824451 0.000056160024501311744 0.00003976068444587685 0.000030311141079122477 0.000022149799803212206 0.000012912197025183665 0.000005535614846584238 0.0000021373228939814696 0.0000027626156523723193 0.0000023858417075143212 0.0000025097644122432617 0.000005542266168584792 0.00001141515472012714 0.00001605389868069723 0.000017848639275135038 0.000020711875659537294 0.000026711709509457614 0.00003538581682921766 0.000043658645204252616 0.00005081018743245207 0.00005773213817806058 0.00006378627298063556 0.00006774528075202873 0.00006979335205075053 0.00007273331620748996 0.00007494986032959469 0.00007386269411413401 0.00006945342397726653 0.00006258753462346775 0.00005384413321554071 0.00004262943994522832 0.0000310571071197336 0.000022238587657551042 0.00001699613417881745 0.0000129121970251831 0.000008048688828867775 0.0000036084647764543023 0.0000015727588389669031 0.0000028589217517666437 0.0000027626156523713634 0.0000020367229778573796 0.000003983409389723629 0.000010520403821836887 0.000017076032718198702 0.000019088382184321667 0.00002053205010782885 0.00002584965898538662 0.000033780550413457534 0.00003818257149019994 0.00003927679355651675 0.00004246476366108888 0.00004804046316260131 0.000050287544943852075 0.000046039876205686116 0.00004185228624762024 0.0000423376470695796 0.000044717298415450525 0.00004323547790220745 0.00003682836488375059 0.00003018052248613219 0.000025034130620913226 0.000019548538281868944 0.000012999980140399761 0.000008151547957649562 0.000005535614846583136 0.0000036084647764535853 0.0000018701035482095566 v_sim-3.8.0/examples/diff.ascii000066400000000000000000000250741370110300500163750ustar00rootroot00000000000000# Fichier ascii standard : boite + x y z element 16.28940 0.000000E+00 16.28940 0.000000E+00 0.000000E+00 16.28940 #keyword: angstroem # 217 (Nb atomes) 8.119324 8.146099 8.123883 Si 10.85920 10.85780 8.123933 Si 10.76350 8.060740 10.77760 Si 8.131874 10.88780 10.87450 Si 9.470533 9.540169 9.485503 Si 12.17690 12.24650 9.485553 Si 9.418084 12.29900 12.25770 Si 13.57240 8.144619 8.123933 Si 1.852515E-02 10.85630 8.130282 Si 1.217505E-02 8.112019 10.87680 Si 13.65630 10.95340 10.77760 Si 14.95430 9.460839 9.495132 Si 1.358984 12.21410 9.495293 Si 1.365974 9.494289 12.21010 Si 14.95080 12.23790 12.25460 Si 2.716214 8.141809 8.138383 Si 5.425764 10.86090 8.138323 Si 5.426774 8.144669 10.85350 Si 2.715474 10.85800 10.85360 Si 4.071014 9.501319 9.495613 Si 6.774474 12.22420 9.497883 Si 6.776434 9.508410 12.20950 Si 4.068954 12.21710 12.21320 Si 8.141603 13.57540 8.141923 Si 10.85610 1.850862E-03 8.138323 Si 10.82930 13.58520 10.87450 Si 8.135364 9.153512E-03 10.85530 Si 9.492914 14.94250 9.497833 Si 12.21570 1.356599 9.495613 Si 12.20860 14.94060 12.20950 Si 9.499954 1.358659 12.21320 Si 13.57090 13.59770 8.123883 Si 1.627031E-04 -3.387988E-03 8.139543 Si -3.488620E-03 13.57220 10.84730 Si 13.57230 8.983433E-04 10.85350 Si 14.92780 14.93420 9.494233 Si 1.359094 1.351889 9.494443 Si 1.353374 14.92870 12.21050 Si 14.93180 1.354059 12.21310 Si 2.710924 13.57520 8.139703 Si 5.427934 16.28910 8.142403 Si 5.418464 13.58170 10.85530 Si 2.713144 -1.800458E-03 10.85430 Si 4.066834 14.93340 9.494713 Si 6.783634 1.360779 9.494713 Si 6.747224 14.96980 12.20780 Si 4.072284 1.355379 12.21120 Si 8.141873 2.716739 8.139703 Si 10.86070 5.409139 8.130282 Si 10.85900 2.712189 10.85360 Si 8.144834 5.431098 10.84730 Si 9.502964 4.068629 9.495343 Si 12.25620 6.762779 9.495132 Si 12.22280 4.061648 12.21010 Si 9.479154 6.766269 12.25470 Si 13.57520 2.711399 8.138383 Si 16.29020 5.426818 8.141763 Si 7.571180E-03 2.703139 10.85540 Si 13.60500 5.415439 10.87670 Si 14.93960 4.059159 9.497513 Si 1.368514 6.777489 9.497513 Si 1.398354 4.029309 12.20750 Si 15.02190 6.695098 12.26200 Si 2.714474 2.713139 8.142033 Si 5.431004 5.427449 8.139543 Si 5.429464 2.714519 10.85430 Si 2.724524 5.420099 10.85540 Si 4.075724 4.068529 9.494443 Si 6.782834 6.789178 9.494233 Si 6.788344 4.074239 12.21050 Si 4.073614 6.785219 12.21310 Si 8.124564 8.151229 13.57780 Si 10.76110 10.95590 13.64270 Si 10.86100 8.145519 -5.235760E-03 Si 8.135314 10.86620 -4.177410E-03 Si 9.482434 9.491799 14.94140 Si 12.22520 12.23460 14.94140 Si 12.21580 9.501219 1.352583 Si 9.500374 12.21670 1.351943 Si 13.67490 8.042059 13.63780 Si 1.640845E-02 10.85170 13.57670 Si 5.930730E-03 8.136259 -5.712020E-03 Si 13.57150 10.85600 -5.235760E-03 Si 14.94820 9.509579 14.93840 Si 1.361414 12.21730 14.93520 Si 1.358134 9.496609 1.352213 Si 14.92980 12.21430 1.354163 Si 2.717804 8.139959 13.57420 Si 5.424914 10.86240 13.57420 Si 5.425504 8.145099 16.29140 Si 2.716434 10.85730 1.273120E-03 Si 4.071284 9.501169 14.93070 Si 6.770664 12.22740 14.93480 Si 6.783154 9.505769 1.353483 Si 4.066784 12.21610 1.362583 Si 8.070534 13.64650 13.59130 Si 10.85460 2.750462E-03 13.57420 Si 10.85080 13.58180 -4.177410E-03 Si 8.141394 1.010604E-02 4.501100E-03 Si 9.489684 14.94640 14.93480 Si 12.21580 1.356329 14.93070 Si 12.21120 14.93390 1.353483 Si 9.500904 1.360829 1.362583 Si 13.56580 13.59240 13.57780 Si 16.28810 16.28620 13.57040 Si 16.28630 13.57160 16.28730 Si 13.57190 16.29150 16.29140 Si 14.93170 14.93670 14.93610 Si 1.357874 1.351359 14.92980 Si 1.353854 14.92820 1.357713 Si 14.93090 1.351729 1.363583 Si 2.711134 13.57350 13.56980 Si 5.412424 1.523904E-02 13.57560 Si 5.417504 13.57560 4.501100E-03 Si 2.711084 16.28530 16.28980 Si 4.066364 14.93220 14.92940 Si 6.784904 1.361259 14.92940 Si 6.782894 14.93420 1.353483 Si 4.071174 1.356439 1.354483 Si 8.143514 2.716479 13.56980 Si 10.86540 5.411209 13.57670 Si 10.85970 2.711239 1.273120E-03 Si 8.145473 5.430678 16.28730 Si 9.499743 4.066198 14.93520 Si 12.20740 6.768808 14.93850 Si 12.22040 4.069479 1.352263 Si 9.502754 6.787229 1.354223 Si 13.57700 2.709859 13.57420 Si 7.774005E-02 5.349928 13.59490 Si 16.29070 2.702029 16.29520 Si 13.58080 5.421689 -5.712020E-03 Si 14.94220 4.054399 14.93600 Si 1.373214 6.774838 14.93600 Si 1.359194 4.068419 1.354383 Si 14.93110 6.785899 1.351313 Si 2.732464 2.695149 13.57600 Si 5.430844 5.428928 13.57040 Si 5.431694 2.716529 16.28980 Si 2.725584 5.426339 16.29520 Si 4.076254 4.069798 14.92980 Si 6.780354 6.785269 14.93610 Si 6.788764 4.073759 1.357713 Si 4.075884 6.786119 1.363583 Si 8.143464 8.147899 2.708063 Si 10.85800 10.85900 2.710603 Si 10.85440 8.139799 5.424653 Si 8.140814 10.86030 5.422273 Si 9.500274 9.501799 4.068373 Si 12.21530 12.21670 4.068373 Si 12.21570 9.501319 6.765903 Si 9.496934 12.22010 6.775803 Si 13.57360 8.143399 2.710343 Si -6.310629E-04 10.85430 2.708543 Si 16.29040 8.142659 5.423063 Si 13.57730 10.86260 5.424603 Si 14.93120 9.500479 4.068373 Si 1.351894 12.21180 4.070113 Si 1.366444 9.496609 6.772153 Si 14.93030 12.21540 6.789773 Si 2.712194 8.143189 2.711823 Si 5.428624 10.85920 2.712833 Si 5.422434 8.145409 5.417243 Si 2.717644 10.85690 5.419673 Si 4.069534 9.501269 4.061653 Si 6.784634 12.21850 4.068163 Si 6.772094 9.506619 6.768393 Si 4.068004 12.21630 6.782313 Si 8.141504 13.57550 2.708433 Si 10.85780 -1.006698E-03 2.712833 Si 10.85680 13.57630 5.422273 Si 8.142714 16.29000 5.427083 Si 9.498474 14.93240 4.068103 Si 12.21570 1.358079 4.061653 Si 12.21040 14.94490 6.768393 Si 9.500694 1.359619 6.782313 Si 13.56920 13.57360 2.708063 Si 16.28610 16.28250 2.717593 Si -8.198300E-03 13.56600 5.427723 Si 13.57160 5.184682E-03 5.417243 Si 14.92640 14.92600 4.070113 Si 1.356074 1.354159 4.070333 Si 1.351364 14.92630 6.780293 Si 14.93070 1.353789 6.781883 Si 2.708434 13.57110 2.717113 Si 5.427564 16.28950 2.714103 Si 5.427084 13.57430 5.427083 Si 2.712194 16.28690 5.428353 Si 4.068844 14.93080 4.070113 Si 6.786224 1.358819 4.070113 Si 6.784324 14.93270 6.783213 Si 4.071284 1.356329 6.784163 Si 8.145944 2.719229 2.717113 Si 10.86270 5.428298 2.708543 Si 10.86010 2.709969 5.419673 Si 8.151084 5.435809 5.427723 Si 9.505244 4.075718 4.070113 Si 12.21650 6.785849 4.068423 Si 12.22040 4.061169 6.772153 Si 9.501694 6.786748 6.789773 Si 13.57380 2.715419 2.711823 Si 16.28960 5.427449 2.708913 Si 16.28880 2.712719 5.426823 Si 13.57430 5.426609 5.423063 Si 14.93250 4.070539 4.068423 Si 1.357074 6.784529 4.068423 Si 1.357974 4.069689 6.782943 Si 14.93480 6.782248 6.776063 Si 2.714844 2.712769 2.714203 Si 5.434544 5.430889 2.717593 Si 5.430154 2.715469 5.428353 Si 2.714894 5.428248 5.426823 Si 4.073454 4.071538 4.070273 Si 6.790984 6.790558 4.070113 Si 6.790724 4.076299 6.780293 Si 4.073824 6.786269 6.781883 Si 11.36820 10.34880 11.47930 Si 13.08220 8.634739 11.45930 Ge v_sim-3.8.0/examples/diff.dat000066400000000000000000000112151370110300500160450ustar00rootroot00000000000000# Data file to be associated to a coordinate file. 6.570164E-03 19070 2.974598E-03 21796 1.731830E-02 8592 2.430072E-03 11318 1.223075E-02 14044 1.224811E-02 16769 3.805334E-03 19495 1.294667E-03 22221 3.690429E-03 24947 9.115873E-04 27673 1.730585E-02 30399 6.334600E-03 356 2.171126E-03 3082 3.281970E-04 5808 3.891863E-03 8534 4.806420E-04 11260 1.183936E-03 13986 6.233510E-04 16711 5.197012E-04 19437 6.011208E-04 22163 1.800709E-03 24889 8.525641E-04 27615 4.560292E-04 30341 9.893049E-04 298 1.161778E-03 3024 2.435714E-03 5750 1.006440E-03 8476 1.853548E-03 11202 6.038504E-04 13928 9.035654E-04 16653 4.430178E-04 19379 6.674202E-03 6175 8.742520E-04 8901 2.610827E-03 11627 5.939400E-04 14353 1.292323E-03 17079 2.969896E-04 19805 1.738480E-03 22530 2.903526E-04 25256 1.166387E-03 27982 5.186840E-04 30708 9.789558E-04 666 1.011609E-03 3392 8.096921E-04 6118 7.522728E-04 8843 1.030050E-03 11569 2.058406E-03 14295 1.093966E-03 17021 3.666771E-03 19747 4.978379E-04 22473 2.510549E-03 25198 2.155186E-03 27924 6.251096E-03 30650 2.473853E-04 608 3.803856E-03 3334 5.334322E-04 6060 3.392569E-04 8785 8.984001E-04 11511 1.041334E-03 14237 8.918630E-04 16963 6.023200E-04 3759 5.528382E-03 6485 1.579587E-02 9211 2.043177E-04 11937 8.341062E-04 14662 5.693425E-04 17388 7.363030E-04 20114 1.369141E-04 22840 1.177616E-03 25566 1.539351E-03 28292 2.112410E-04 31017 1.261092E-03 975 3.971077E-03 3701 1.277568E-03 6427 9.084927E-04 9153 1.041299E-03 11879 1.124810E-03 14604 9.488023E-04 17330 6.559787E-04 20056 3.678184E-02 22782 2.637983E-03 25508 6.267929E-03 28234 1.220824E-03 30960 9.176202E-03 917 1.780591E-03 3643 4.133081E-03 6369 5.599756E-04 9095 4.521608E-04 11821 4.335155E-04 31385 3.878977E-04 1343 8.888541E-04 4069 2.013055E-04 6794 1.293673E-03 9520 2.011516E-04 12246 1.280444E-03 14972 2.852374E-03 17698 3.863503E-04 20424 9.168704E-04 23149 1.215224E-03 25875 1.294192E-03 28601 2.326683E-04 31327 7.681947E-05 1285 1.240069E-03 4011 1.171654E-03 6736 4.572209E-04 9462 2.901929E-04 12188 3.926119E-04 14914 5.130023E-04 17640 1.044555E-03 20366 5.607470E-04 23091 1.084728E-03 25817 3.887035E-04 28543 1.615384E-03 31269 1.199160E-03 1227 8.419976E-04 3953 6.524244E-04 6678 5.817484E-04 9404 5.962151E-04 28968 1.610473E-04 31694 2.897185E-04 1652 2.598920E-03 4378 7.955292E-04 7104 2.092386E-04 9830 1.747306E-03 12555 9.297648E-03 15281 4.288580E-03 18007 6.392249E-04 20733 4.856915E-04 23459 1.146234E-02 26185 1.844554E-03 28911 6.399885E-03 31636 2.864202E-03 1594 2.822826E-03 4320 8.716902E-04 7046 1.057102E-03 9772 3.857189E-03 12498 5.175588E-04 15223 7.891920E-04 17949 1.947628E-03 20675 1.074624E-03 23401 5.650293E-04 26127 5.493931E-04 28853 1.093119E-03 31578 3.162337E-04 1536 4.636911E-04 4262 5.731404E-04 6988 1.723355E-03 26552 5.305600E-04 29278 5.873258E-04 32004 5.787968E-04 1962 2.477913E-03 4687 5.587140E-04 7413 5.248204E-04 10139 8.590595E-04 12865 5.286413E-04 15591 3.411490E-04 18317 6.333592E-04 21042 1.167577E-03 23768 2.112019E-03 26494 2.188447E-03 29220 1.001759E-03 31946 1.666042E-03 1904 6.451811E-04 4629 6.093479E-04 7355 1.469396E-03 10081 4.096397E-03 12807 9.380101E-04 15533 9.771852E-04 18259 9.387092E-04 20985 1.796349E-03 23710 5.808801E-04 26436 1.556493E-03 29162 6.438167E-04 31888 4.122168E-03 1846 8.969044E-04 4572 2.728397E-04 24136 6.784681E-04 26862 1.246364E-03 29587 1.680853E-03 32313 5.072682E-04 2271 1.854861E-04 4997 8.002766E-04 7723 6.886625E-04 10449 7.213067E-04 13174 2.425564E-04 15900 5.429324E-04 18626 2.458674E-04 21352 3.533097E-04 24078 3.849826E-04 26804 7.527438E-04 29529 3.319036E-04 32255 6.979374E-04 2213 6.326417E-04 4939 6.761690E-04 7665 1.108872E-03 10391 5.806101E-04 13116 3.332751E-04 15842 1.242824E-03 18568 2.114240E-03 21294 2.290128E-03 24020 1.032811E-03 26746 3.774135E-04 29471 8.700287E-04 16268 8.995404E-04 18993 8.144235E-04 21719 3.915108E-04 24445 1.229944E-03 27171 3.311058E-04 29897 6.830165E-04 32623 2.235148E-04 2580 3.085337E-04 5306 1.393266E-04 8032 4.356533E-04 10758 7.541666E-04 13484 6.845300E-04 16210 3.873261E-03 18936 2.514560E-02 31869 v_sim-3.8.0/examples/planes.xml000066400000000000000000000007471370110300500164570ustar00rootroot00000000000000 v_sim-3.8.0/examples/test_isosurfaces.ascii000066400000000000000000000031711370110300500210440ustar00rootroot00000000000000sample atomic file: see movie.datafilm bottom 4.1213 -2.3795 4.7589 0 0 12.991 0 0 1.92267 Al 1.9544 1.5863 2.40767 Al 0 0 4.57284 Al 1.9544 1.5863 6.25301 Al 0.693276 1.5863 1.08258 O -0.728113 1.45622 3.24775 O 1.26113 0 3.24775 O 1.20886 3.30268 3.24775 O 0.515588 1.71638 5.41292 O 0 0 8.41818 Al 1.9544 1.5863 8.90317 Al 0 0 11.0683 Al 1.9544 1.5863 12.7485 Al 1.22629 3.04253 7.57809 O 1.42139 0.130077 7.57809 O 0.533015 1.45622 9.74326 O -0.74554 1.71638 11.9084 O 1.0486 3.1726 11.9084 O -2.37945 4.7589 1.92267 Al -2.37945 4.7589 4.57284 Al -1.11833 4.7589 3.24775 O -1.47365 3.1726 5.41292 O -2.37945 4.7589 8.41818 Al -2.37945 4.7589 11.0683 Al -1.65134 3.30268 9.74326 O -0.940639 4.62883 11.9084 O 4.12133 0 1.92267 Al 4.12133 0 4.57284 Al 2.68252 0.130077 1.08258 O 3.39322 1.45622 3.24775 O 4.12133 0 8.41818 Al 4.12133 0 11.0683 Al 3.21553 1.5863 7.57809 O 2.8602 0 9.74326 O -0.212526 3.1726 0.242499 Al 1.74188 4.7589 1.92267 Al -0.212526 3.1726 4.08784 Al 1.74188 4.7589 4.57284 Al 2.48742 3.04253 1.08258 O 0.320489 4.62883 5.41292 O -0.212526 3.1726 6.738 Al 1.74188 4.7589 8.41818 Al -0.212526 3.1726 10.5833 Al 1.74188 4.7589 11.0683 Al 2.46999 3.30268 9.74326 O 0.48075 4.7589 9.74326 O v_sim-3.8.0/examples/test_isosurfaces.surf000066400000000000000000006272441370110300500207500ustar00rootroot00000000000000sample surfaces file: see movie.datafilm 4.1213 -2.3795 4.7589 0 0 12.991 4 3400 3797 # First surface # potentialValue 2.345e-2 surface_Al2O3_1 1510 1677 4 1 3 4 2 4 1 5 6 2 4 3 7 8 4 4 5 9 10 6 4 11 13 14 12 4 11 15 16 12 4 17 19 20 18 4 17 21 22 18 3 23 24 25 5 23 26 8 7 24 5 27 29 10 9 28 3 27 28 30 4 31 33 34 32 4 31 13 14 32 4 15 35 36 16 4 19 37 38 20 4 39 21 22 40 3 23 41 25 5 23 26 43 42 41 5 27 29 46 45 44 3 27 44 30 4 33 47 48 34 4 35 49 50 36 4 37 51 52 38 4 42 53 54 43 4 45 55 56 46 4 47 57 58 48 4 49 59 60 50 4 51 61 62 52 4 63 53 54 64 4 63 55 56 64 4 65 57 58 66 4 65 67 68 66 4 59 69 70 60 4 61 71 72 62 4 73 67 68 74 4 73 69 70 74 4 75 71 72 76 4 75 77 78 76 3 79 80 81 4 79 80 83 82 3 82 83 84 3 85 86 87 3 85 86 88 5 79 81 90 91 89 4 79 89 92 82 5 82 84 93 94 92 5 85 87 96 97 95 5 85 88 98 99 95 4 98 100 101 99 4 102 104 105 103 4 102 106 107 103 4 90 108 109 91 4 93 110 111 94 4 96 112 113 97 4 100 114 115 101 4 104 116 117 105 4 106 118 119 107 4 108 120 121 109 4 110 122 123 111 4 112 124 125 113 4 114 126 127 115 3 128 129 130 5 128 131 117 116 129 4 132 118 119 133 4 132 134 135 133 4 136 120 121 137 4 136 138 139 137 4 122 140 141 123 4 124 142 143 125 3 144 145 146 5 144 147 127 126 145 3 128 148 130 5 128 131 150 149 148 4 151 153 154 152 4 151 134 135 152 4 155 138 139 156 4 155 140 141 156 4 157 142 143 158 5 144 159 158 157 146 3 144 159 147 4 149 160 161 150 4 153 162 163 154 4 164 160 161 165 4 164 162 163 165 3 166 2 4 3 166 2 6 5 166 4 8 168 167 5 166 6 10 169 167 3 170 12 14 3 170 12 16 3 171 18 20 3 171 18 22 4 8 26 172 168 4 10 29 173 169 3 174 32 34 6 174 32 14 170 175 176 5 170 16 36 177 175 5 171 20 38 179 178 6 171 178 181 180 40 22 4 26 43 182 172 4 29 46 183 173 5 174 34 48 185 184 3 174 184 176 4 36 50 186 177 4 38 52 187 179 3 180 188 181 4 43 54 189 182 4 46 56 190 183 4 48 58 191 185 4 50 60 192 186 4 52 62 193 187 5 194 195 189 54 64 5 194 196 190 56 64 4 66 58 191 197 4 66 68 198 197 4 60 70 199 192 4 62 72 200 193 3 194 201 195 3 194 201 196 4 74 68 198 202 4 74 70 199 202 4 76 72 200 203 4 76 78 204 203 3 205 89 91 5 205 207 206 92 89 4 92 94 208 206 4 95 97 210 209 5 211 212 209 95 99 3 211 99 101 3 213 103 105 3 213 103 107 5 205 91 109 215 214 3 205 214 207 4 94 111 216 208 4 97 113 217 210 3 211 218 212 5 211 101 115 219 218 5 213 105 117 221 220 5 213 107 119 222 220 4 109 121 223 215 4 111 123 224 216 4 113 125 225 217 4 115 127 226 219 4 117 131 227 221 5 228 229 222 119 133 3 228 133 135 4 137 121 223 230 4 137 139 231 230 4 123 141 232 224 4 125 143 233 225 4 127 147 234 226 4 131 150 235 227 5 228 229 236 154 152 3 228 152 135 4 156 139 231 237 4 156 141 232 237 5 238 239 233 143 158 5 238 241 240 159 158 4 159 147 234 240 4 150 161 242 235 4 154 163 243 236 3 238 244 239 3 238 244 241 4 165 161 242 245 4 165 163 243 245 3 246 247 248 3 246 247 249 3 250 251 252 3 250 251 253 3 254 167 168 3 254 167 169 4 250 252 256 255 4 250 253 257 255 5 254 168 172 259 258 5 254 169 173 260 258 3 261 175 176 3 261 175 177 4 255 256 263 262 4 255 257 264 262 3 265 178 179 3 265 178 181 4 172 182 266 259 4 173 183 267 260 3 268 184 185 5 268 269 261 176 184 4 261 177 186 269 3 262 270 263 3 262 270 264 5 265 179 187 272 271 6 265 271 274 273 188 181 4 182 189 275 266 4 183 190 276 267 4 268 185 191 277 4 268 269 278 277 4 269 186 192 278 4 187 193 279 272 3 273 280 274 5 281 195 189 275 282 5 281 196 190 276 282 3 277 197 191 5 277 197 198 283 278 4 278 192 199 283 4 193 200 284 279 3 281 201 195 3 281 201 196 3 283 202 198 3 283 202 199 4 203 200 284 285 4 203 204 286 285 3 287 206 207 3 287 206 208 3 288 209 210 3 288 209 212 3 289 214 215 5 289 290 287 207 214 4 287 208 216 290 5 288 210 217 292 291 5 288 212 218 293 291 4 218 219 294 293 3 295 220 221 3 295 220 222 4 289 215 223 296 5 289 290 297 298 296 5 290 216 224 299 297 4 217 225 300 292 4 219 226 301 294 5 295 221 227 303 302 5 295 222 229 304 302 3 296 230 223 6 296 230 231 305 306 298 5 305 232 224 299 306 4 225 233 307 300 4 226 234 308 301 4 227 235 309 303 4 229 236 310 304 3 305 237 231 3 305 237 232 5 311 239 233 307 312 5 311 241 240 313 312 4 240 234 308 313 4 235 242 314 309 4 236 243 315 310 3 311 244 239 3 311 244 241 4 245 242 314 316 4 245 243 315 316 3 317 318 319 3 317 318 320 4 317 319 322 321 4 317 320 323 321 5 324 326 325 248 247 5 324 328 327 249 247 3 329 330 331 3 329 330 332 3 333 334 335 3 333 334 336 3 324 337 326 3 324 337 328 4 251 252 339 338 4 251 253 340 338 3 341 342 343 3 341 342 344 3 345 346 347 3 345 346 348 4 252 256 349 339 4 253 257 350 340 4 341 343 352 351 4 341 344 353 351 3 354 258 259 3 354 258 260 4 345 347 356 355 5 345 348 358 357 355 3 357 358 359 4 256 263 360 349 4 257 264 361 350 3 351 362 352 3 351 362 353 4 354 259 266 363 4 354 260 267 363 4 355 356 365 364 5 355 357 366 367 364 3 357 366 359 5 368 369 360 263 270 5 368 370 361 264 270 3 371 271 272 3 371 271 274 4 363 266 275 372 4 363 267 276 372 3 364 373 365 3 364 373 367 3 368 374 369 3 368 374 370 4 371 272 279 375 5 371 274 280 376 375 3 372 282 275 3 372 282 276 4 375 279 284 377 4 375 376 378 377 3 377 285 284 4 377 285 286 378 3 379 291 292 4 379 291 293 380 3 380 293 294 3 381 297 298 3 381 297 299 5 379 292 300 383 382 5 379 382 385 384 380 4 380 294 301 384 3 386 302 303 3 386 302 304 3 381 306 298 3 381 306 299 4 300 307 387 383 4 384 385 389 388 4 384 301 308 388 4 386 303 309 390 4 386 304 310 390 4 312 307 387 391 5 388 389 391 312 313 3 388 313 308 4 390 309 314 392 4 390 310 315 392 3 392 316 314 3 392 316 315 3 393 394 395 3 393 394 396 4 318 319 398 397 4 318 320 399 397 4 393 395 401 400 5 393 396 403 402 400 4 319 322 404 398 4 320 323 405 399 3 406 407 408 3 406 407 409 4 400 401 411 410 4 400 402 412 410 3 413 414 415 5 413 325 326 416 414 5 417 327 328 419 418 3 417 418 420 3 421 422 423 6 421 422 425 424 330 331 5 424 427 426 332 330 5 428 430 429 335 334 6 428 334 336 431 432 433 5 434 435 416 326 337 5 434 436 419 328 337 3 424 437 425 3 424 437 427 3 428 438 430 3 428 438 433 3 434 439 435 3 434 439 436 3 440 441 442 3 440 441 443 4 338 339 445 444 4 338 340 446 444 3 447 448 449 6 447 448 442 440 342 343 5 440 443 450 344 342 4 346 347 452 451 4 346 348 453 451 4 339 349 454 445 4 340 350 455 446 4 447 449 457 456 4 447 343 352 456 4 344 353 458 450 4 347 356 459 452 4 358 348 453 460 4 358 359 461 460 4 349 360 462 454 4 350 361 463 455 4 456 457 465 464 5 456 352 362 466 464 5 466 467 458 353 362 4 356 365 468 459 3 469 366 367 5 469 470 461 359 366 4 360 369 471 462 4 361 370 472 463 3 464 473 465 4 464 473 474 466 3 466 474 467 5 475 476 468 365 373 5 475 477 469 367 373 4 469 470 478 477 5 479 480 471 369 374 5 479 481 472 370 374 3 475 482 476 4 475 482 483 477 3 477 483 478 3 479 484 480 3 479 484 481 3 485 382 383 3 485 382 385 4 485 383 387 486 4 485 385 389 486 3 486 391 387 3 486 391 389 4 394 395 488 487 4 394 396 489 487 4 397 398 491 490 4 397 399 492 490 3 493 494 495 3 493 494 496 4 395 401 497 488 4 403 396 489 498 4 398 404 499 491 4 399 405 500 492 3 501 502 503 6 501 502 495 493 407 408 5 493 496 504 409 407 4 401 411 505 497 4 414 415 507 506 4 414 416 508 506 4 418 419 510 509 4 418 420 511 509 5 512 514 513 423 422 3 512 422 425 4 426 427 516 515 4 429 430 518 517 3 519 432 433 4 416 435 520 508 4 419 436 521 510 3 512 522 514 6 512 522 524 523 437 425 5 523 525 516 427 437 4 438 430 518 526 5 519 527 526 438 433 4 439 435 520 528 4 439 436 521 528 3 523 529 524 3 523 529 525 4 441 442 531 530 4 441 443 532 530 4 444 445 534 533 4 444 446 535 533 4 448 449 537 536 4 448 442 531 536 4 443 450 538 532 4 451 452 540 539 4 451 453 541 539 4 445 454 542 534 4 446 455 543 535 4 449 457 544 537 4 450 458 545 538 4 452 459 546 540 4 460 453 541 547 4 460 461 548 547 3 549 550 551 5 549 462 454 542 550 5 552 463 455 543 553 3 552 553 554 4 457 465 555 544 4 458 467 556 545 4 459 468 557 546 4 461 470 558 548 3 549 559 551 5 549 462 471 560 559 5 552 463 472 562 561 3 552 561 554 5 563 564 555 465 473 4 563 473 474 565 5 565 566 556 467 474 4 468 476 567 557 4 470 478 568 558 4 471 480 569 560 4 472 481 570 562 3 563 571 564 4 563 571 572 565 3 565 572 566 5 573 574 567 476 482 5 573 576 575 483 482 4 483 478 568 575 4 484 480 569 577 4 484 481 570 577 3 573 578 574 3 573 578 576 4 487 488 580 579 4 487 489 581 579 4 490 491 583 582 4 490 492 584 582 4 494 495 586 585 4 494 496 587 585 4 488 497 588 580 4 498 489 581 589 4 491 499 590 583 4 492 500 591 584 4 502 503 593 592 4 502 495 586 592 4 496 504 594 587 4 497 505 595 588 3 596 506 507 5 596 597 598 508 506 5 599 600 601 510 509 3 599 509 511 4 513 514 603 602 4 515 516 605 604 4 517 518 607 606 4 508 520 608 598 4 510 521 609 601 5 610 611 603 514 522 3 610 522 524 4 516 525 612 605 4 526 518 607 613 4 526 527 614 613 4 528 520 608 615 4 528 521 609 615 3 610 616 611 5 610 524 529 617 616 4 529 525 612 617 3 618 530 531 3 618 530 532 4 533 534 620 619 4 533 535 621 619 4 536 537 623 622 5 618 624 622 536 531 5 618 532 538 625 624 4 539 540 627 626 4 539 541 628 626 4 534 542 629 620 4 535 543 630 621 4 537 544 631 623 4 538 545 632 625 4 540 546 633 627 4 547 541 628 634 4 547 548 635 634 4 550 551 637 636 4 550 542 629 636 5 638 639 630 543 553 3 638 553 554 4 544 555 640 631 4 545 556 641 632 4 546 557 642 633 4 548 558 643 635 4 559 551 637 644 4 559 560 645 644 5 638 639 646 562 561 3 638 561 554 4 555 564 647 640 4 556 566 648 641 4 557 567 649 642 4 558 568 650 643 4 560 569 651 645 4 562 570 652 646 4 571 564 647 653 5 654 655 653 571 572 5 654 656 648 566 572 4 567 574 657 649 3 658 575 576 5 658 659 650 568 575 4 577 569 651 660 4 577 570 652 660 3 654 661 655 3 654 661 656 4 578 574 657 662 5 658 663 662 578 576 3 658 663 659 3 664 579 580 3 664 579 581 4 582 583 666 665 4 582 584 667 665 3 668 585 586 3 668 585 587 5 664 580 588 670 669 5 664 581 589 671 669 4 583 590 672 666 4 584 591 673 667 4 592 593 675 674 5 668 676 674 592 586 5 668 587 594 677 676 4 588 595 678 670 4 597 598 680 679 4 600 601 682 681 4 602 603 684 683 4 604 605 686 685 4 606 607 688 687 4 598 608 689 680 4 601 609 690 682 4 603 611 691 684 4 605 612 692 686 5 693 694 688 607 613 5 693 696 695 614 613 4 615 608 689 697 4 615 609 690 697 4 616 611 691 698 5 699 700 698 616 617 5 699 701 692 612 617 3 693 702 694 3 693 702 696 3 699 703 700 3 699 703 701 3 704 619 620 3 704 619 621 4 622 623 706 705 4 622 624 707 705 4 624 625 708 707 3 709 626 627 3 709 626 628 5 704 620 629 711 710 5 704 621 630 712 710 4 623 631 713 706 4 625 632 714 708 5 709 627 633 716 715 5 709 628 634 717 715 4 634 635 718 717 3 719 636 637 5 719 720 711 629 636 4 630 639 721 712 4 631 640 722 713 4 632 641 723 714 4 633 642 724 716 4 635 643 725 718 3 719 644 637 5 719 720 726 645 644 4 639 646 727 721 4 640 647 728 722 4 641 648 729 723 4 642 649 730 724 4 643 650 731 725 4 645 651 732 726 4 646 652 733 727 4 653 647 728 734 4 653 655 735 734 4 648 656 736 729 4 649 657 737 730 4 650 659 738 731 4 660 651 732 739 4 660 652 733 739 4 661 655 735 740 4 661 656 736 740 4 662 657 737 741 4 662 663 742 741 4 663 659 738 742 3 743 665 666 3 743 665 667 4 669 670 745 744 5 746 747 744 669 671 5 743 666 672 749 748 5 743 667 673 750 748 4 674 675 752 751 4 674 676 753 751 4 676 677 754 753 4 670 678 755 745 3 746 756 747 4 679 680 758 757 4 681 682 760 759 4 683 684 762 761 4 685 686 764 763 4 687 688 766 765 4 680 689 767 758 4 682 690 768 760 4 684 691 769 762 4 686 692 770 764 4 688 694 771 766 4 695 696 773 772 4 697 689 767 774 4 697 690 768 774 4 698 691 769 775 4 698 700 776 775 4 692 701 777 770 4 702 694 771 778 4 702 696 773 778 4 703 700 776 779 4 703 701 777 779 3 780 705 706 4 780 705 707 781 3 781 707 708 3 782 710 711 3 782 710 712 5 780 706 713 784 783 4 780 783 785 781 5 781 708 714 786 785 3 787 715 716 4 787 715 717 788 3 788 717 718 5 782 711 720 790 789 5 782 712 721 791 789 4 713 722 792 784 4 714 723 793 786 5 787 716 724 795 794 4 787 794 796 788 5 788 718 725 797 796 4 720 726 798 790 4 721 727 799 791 4 722 728 800 792 4 723 729 801 793 4 724 730 802 795 4 725 731 803 797 4 726 732 804 798 4 727 733 805 799 4 734 728 800 806 4 734 735 807 806 4 729 736 808 801 4 730 737 809 802 4 731 738 810 803 4 739 732 804 811 4 739 733 805 811 4 740 735 807 812 4 740 736 808 812 4 741 737 809 813 4 741 742 814 813 4 742 738 810 814 3 815 744 745 3 815 744 747 3 816 748 749 3 816 748 750 3 817 751 752 4 817 751 753 818 3 818 753 754 5 815 745 755 820 819 6 815 819 822 821 756 747 3 823 824 825 3 823 824 826 4 827 757 758 828 4 827 759 760 828 4 829 761 762 830 5 829 831 832 833 830 5 831 763 764 834 832 4 765 766 836 835 4 837 839 840 838 4 828 758 767 841 4 828 760 768 841 4 830 762 769 842 4 830 833 843 842 4 764 770 844 834 5 845 771 766 836 846 6 845 846 840 838 772 773 3 841 774 767 3 841 774 768 3 842 775 769 5 842 843 847 776 775 4 770 777 848 844 3 845 778 771 3 845 778 773 4 779 776 847 849 4 779 777 848 849 3 850 783 784 4 850 783 785 851 3 851 785 786 3 852 789 790 3 852 789 791 5 850 784 792 854 853 4 850 853 855 851 5 851 786 793 856 855 3 857 794 795 4 857 794 796 858 3 858 796 797 4 852 790 798 859 4 852 791 799 859 4 792 800 860 854 4 793 801 861 856 5 857 795 802 863 862 5 857 862 865 864 858 4 858 797 803 864 4 859 798 804 866 4 859 799 805 866 4 806 800 860 867 4 806 807 868 867 4 801 808 869 861 4 802 809 870 863 4 864 865 872 871 4 864 803 810 871 3 866 811 804 3 866 811 805 4 812 807 868 873 4 812 808 869 873 4 813 809 870 874 5 871 872 874 813 814 3 871 814 810 3 875 876 877 3 875 876 878 3 879 880 881 3 879 880 882 4 875 877 884 883 4 875 878 885 883 4 879 881 887 886 5 879 882 889 888 886 3 883 890 884 3 883 890 885 4 886 887 892 891 4 886 888 893 891 3 891 894 892 4 891 894 895 893 3 896 897 898 3 896 897 899 4 896 898 901 900 4 896 899 902 900 3 903 904 905 3 903 904 906 4 900 901 908 907 4 900 902 909 907 3 910 819 820 3 910 819 822 3 911 912 913 6 911 912 915 914 824 825 5 914 917 916 826 824 3 918 919 920 4 918 919 922 921 3 921 922 923 3 924 832 833 3 924 832 834 3 925 926 927 3 925 926 928 4 929 835 836 930 4 929 839 840 930 3 914 931 915 3 914 931 917 4 924 833 843 932 4 924 834 844 932 3 930 846 836 3 930 846 840 4 932 843 847 933 4 932 844 848 933 3 933 849 847 3 933 849 848 3 934 853 854 4 934 853 855 935 3 935 855 856 4 934 854 860 936 4 934 935 937 936 4 935 856 861 937 3 938 862 863 3 938 862 865 3 936 867 860 5 936 867 868 939 937 4 937 861 869 939 4 938 863 870 940 4 938 865 872 940 3 939 873 868 3 939 873 869 3 940 874 870 3 940 874 872 3 941 942 943 5 941 877 876 944 942 4 876 878 945 944 4 880 881 947 946 4 880 882 948 946 3 949 950 951 3 949 950 952 4 941 943 954 953 4 941 877 884 953 4 878 885 955 945 4 881 887 956 947 4 889 882 948 957 4 949 951 959 958 4 949 952 960 958 4 953 954 962 961 5 953 884 890 963 961 5 963 964 955 885 890 4 887 892 965 956 4 958 959 967 966 4 958 960 968 966 3 961 969 962 4 961 969 970 963 3 963 970 964 5 971 972 965 892 894 4 971 894 895 973 3 966 974 967 3 966 974 968 3 971 975 972 4 971 975 976 973 4 897 898 978 977 4 897 899 979 977 3 980 981 982 3 980 981 983 4 898 901 984 978 5 985 902 899 979 986 3 985 986 987 3 988 989 990 3 988 989 991 3 992 993 994 6 992 993 982 980 904 905 5 980 983 995 906 904 4 901 908 996 984 4 985 902 909 997 4 985 987 998 997 4 988 990 1000 999 4 988 991 1001 999 5 1002 1004 1003 913 912 3 1002 912 915 4 916 917 1006 1005 5 1007 1009 1008 920 919 4 1007 919 922 1010 5 1010 1012 1011 923 922 5 1013 1015 1014 927 926 5 1013 1017 1016 928 926 3 1002 1018 1004 6 1002 1018 1020 1019 931 915 5 1019 1021 1006 917 931 3 1007 1022 1009 4 1007 1022 1023 1010 3 1010 1023 1012 3 1013 1024 1015 3 1013 1024 1017 3 1019 1025 1020 3 1019 1025 1021 4 942 943 1027 1026 4 942 944 1028 1026 4 944 945 1029 1028 4 946 947 1031 1030 4 946 948 1032 1030 4 950 951 1034 1033 4 950 952 1035 1033 4 943 954 1036 1027 4 945 955 1037 1029 4 947 956 1038 1031 4 957 948 1032 1039 4 951 959 1040 1034 4 952 960 1041 1035 4 954 962 1042 1036 4 955 964 1043 1037 4 956 965 1044 1038 4 959 967 1045 1040 4 960 968 1046 1041 5 1047 1048 1042 962 969 4 1047 969 970 1049 5 1049 1050 1043 964 970 4 965 972 1051 1044 5 1052 1053 1045 967 974 5 1052 1054 1046 968 974 3 1047 1055 1048 4 1047 1055 1056 1049 3 1049 1056 1050 5 1057 1058 1051 972 975 4 1057 975 976 1059 3 1052 1060 1053 3 1052 1060 1054 3 1057 1061 1058 4 1057 1061 1062 1059 4 977 978 1064 1063 4 977 979 1065 1063 4 981 982 1067 1066 4 981 983 1068 1066 4 978 984 1069 1064 4 986 979 1065 1070 4 986 987 1071 1070 4 989 990 1073 1072 4 989 991 1074 1072 4 993 994 1076 1075 4 993 982 1067 1075 4 983 995 1077 1068 4 984 996 1078 1069 4 987 998 1079 1071 4 990 1000 1080 1073 4 991 1001 1081 1074 4 1003 1004 1083 1082 4 1005 1006 1085 1084 4 1008 1009 1087 1086 4 1011 1012 1089 1088 4 1014 1015 1091 1090 4 1016 1017 1093 1092 5 1094 1095 1083 1004 1018 3 1094 1018 1020 4 1006 1021 1096 1085 4 1022 1009 1087 1097 4 1022 1023 1098 1097 4 1023 1012 1089 1098 5 1099 1100 1091 1015 1024 5 1099 1101 1093 1017 1024 3 1094 1102 1095 5 1094 1020 1025 1103 1102 4 1025 1021 1096 1103 3 1099 1104 1100 3 1099 1104 1101 4 1026 1027 1106 1105 4 1026 1028 1107 1105 4 1028 1029 1108 1107 4 1030 1031 1110 1109 4 1030 1032 1111 1109 4 1033 1034 1113 1112 4 1033 1035 1114 1112 4 1027 1036 1115 1106 4 1029 1037 1116 1108 4 1031 1038 1117 1110 4 1039 1032 1111 1118 4 1034 1040 1119 1113 4 1035 1041 1120 1114 4 1036 1042 1121 1115 4 1037 1043 1122 1116 4 1038 1044 1123 1117 4 1040 1045 1124 1119 5 1125 1046 1041 1120 1126 3 1125 1126 1127 4 1042 1048 1128 1121 4 1043 1050 1129 1122 4 1044 1051 1130 1123 4 1045 1053 1131 1124 5 1125 1046 1054 1133 1132 3 1125 1132 1127 4 1055 1048 1128 1134 5 1135 1136 1134 1055 1056 5 1135 1137 1129 1050 1056 4 1051 1058 1138 1130 5 1139 1140 1131 1053 1060 5 1139 1141 1133 1054 1060 3 1135 1142 1136 3 1135 1142 1137 4 1061 1058 1138 1143 4 1061 1062 1144 1143 3 1139 1145 1140 3 1139 1145 1141 3 1146 1063 1064 3 1146 1063 1065 3 1147 1066 1067 3 1147 1066 1068 5 1146 1064 1069 1149 1148 5 1146 1065 1070 1150 1148 4 1070 1071 1151 1150 4 1072 1073 1153 1152 4 1072 1074 1154 1152 4 1075 1076 1156 1155 5 1147 1157 1155 1075 1067 5 1147 1068 1077 1158 1157 4 1069 1078 1159 1149 4 1071 1079 1160 1151 4 1073 1080 1161 1153 4 1074 1081 1162 1154 4 1082 1083 1164 1163 4 1084 1085 1166 1165 4 1086 1087 1168 1167 4 1088 1089 1170 1169 3 1171 1172 1173 5 1171 1090 1091 1174 1172 5 1175 1092 1093 1177 1176 3 1175 1176 1178 4 1083 1095 1179 1164 4 1085 1096 1180 1166 5 1181 1182 1168 1087 1097 5 1181 1184 1183 1098 1097 4 1098 1089 1170 1183 4 1091 1100 1185 1174 4 1093 1101 1186 1177 4 1102 1095 1179 1187 5 1188 1189 1187 1102 1103 5 1188 1190 1180 1096 1103 3 1181 1191 1182 3 1181 1191 1184 4 1104 1100 1185 1192 4 1104 1101 1186 1192 3 1188 1193 1189 3 1188 1193 1190 3 1194 1105 1106 5 1194 1196 1195 1107 1105 4 1107 1108 1197 1195 3 1198 1109 1110 3 1198 1109 1111 4 1112 1113 1200 1199 4 1112 1114 1201 1199 5 1194 1106 1115 1203 1202 3 1194 1202 1196 4 1108 1116 1204 1197 5 1198 1110 1117 1206 1205 5 1198 1111 1118 1207 1205 4 1113 1119 1208 1200 4 1114 1120 1209 1201 4 1115 1121 1210 1203 4 1116 1122 1211 1204 4 1117 1123 1212 1206 3 1213 1214 1215 5 1213 1124 1119 1208 1214 4 1126 1120 1209 1216 4 1126 1127 1217 1216 4 1121 1128 1218 1210 4 1122 1129 1219 1211 4 1123 1130 1220 1212 3 1213 1221 1215 5 1213 1124 1131 1222 1221 4 1132 1133 1224 1223 4 1132 1127 1217 1223 4 1134 1128 1218 1225 4 1134 1136 1226 1225 4 1129 1137 1227 1219 4 1130 1138 1228 1220 4 1131 1140 1229 1222 4 1133 1141 1230 1224 4 1142 1136 1226 1231 4 1142 1137 1227 1231 5 1232 1233 1228 1138 1143 5 1232 1235 1234 1144 1143 4 1145 1140 1229 1236 4 1145 1141 1230 1236 3 1232 1237 1233 3 1232 1237 1235 4 1148 1149 1239 1238 5 1240 1241 1238 1148 1150 3 1240 1150 1151 4 1152 1153 1243 1242 4 1152 1154 1244 1242 4 1155 1156 1246 1245 4 1155 1157 1247 1245 4 1157 1158 1248 1247 4 1149 1159 1249 1239 3 1240 1250 1241 5 1240 1151 1160 1251 1250 4 1153 1161 1252 1243 4 1154 1162 1253 1244 4 1163 1164 1255 1254 4 1165 1166 1257 1256 4 1167 1168 1259 1258 4 1169 1170 1261 1260 4 1172 1173 1263 1262 4 1172 1174 1264 1262 4 1176 1177 1266 1265 4 1176 1178 1267 1265 4 1164 1179 1268 1255 4 1166 1180 1269 1257 4 1168 1182 1270 1259 4 1183 1184 1272 1271 4 1183 1170 1261 1271 4 1174 1185 1273 1264 4 1177 1186 1274 1266 4 1187 1179 1268 1275 4 1187 1189 1276 1275 4 1180 1190 1277 1269 4 1191 1182 1270 1278 4 1191 1184 1272 1278 4 1192 1185 1273 1279 4 1192 1186 1274 1279 4 1193 1189 1276 1280 4 1193 1190 1277 1280 3 1281 1195 1196 3 1281 1195 1197 4 1199 1200 1283 1282 4 1199 1201 1284 1282 4 1202 1203 1286 1285 5 1281 1287 1285 1202 1196 5 1281 1197 1204 1288 1287 3 1289 1205 1206 4 1289 1205 1207 1290 4 1200 1208 1291 1283 4 1201 1209 1292 1284 4 1203 1210 1293 1286 4 1204 1211 1294 1288 5 1289 1206 1212 1296 1295 4 1289 1295 1297 1290 3 1298 1214 1215 5 1298 1299 1291 1208 1214 5 1300 1301 1292 1209 1216 3 1300 1216 1217 4 1210 1218 1302 1293 4 1211 1219 1303 1294 4 1212 1220 1304 1296 3 1298 1221 1215 5 1298 1299 1305 1222 1221 5 1300 1301 1306 1224 1223 3 1300 1223 1217 4 1225 1218 1302 1307 4 1225 1226 1308 1307 4 1219 1227 1309 1303 4 1220 1228 1310 1304 4 1222 1229 1311 1305 4 1224 1230 1312 1306 4 1231 1226 1308 1313 4 1231 1227 1309 1313 4 1228 1233 1314 1310 4 1234 1235 1316 1315 4 1236 1229 1311 1317 4 1236 1230 1312 1317 4 1237 1233 1314 1318 4 1237 1235 1316 1318 3 1319 1238 1239 3 1319 1238 1241 4 1242 1243 1321 1320 4 1242 1244 1322 1320 3 1323 1245 1246 5 1323 1325 1324 1247 1245 4 1247 1248 1326 1324 5 1319 1239 1249 1328 1327 6 1319 1327 1330 1329 1250 1241 3 1329 1250 1251 4 1243 1252 1331 1321 4 1244 1253 1332 1322 5 1333 1254 1255 1335 1334 3 1333 1334 1336 4 1256 1257 1338 1337 4 1258 1259 1340 1339 4 1341 1343 1344 1342 4 1341 1260 1261 1342 3 1345 1262 1263 5 1345 1346 1347 1264 1262 5 1348 1349 1350 1266 1265 3 1348 1265 1267 4 1255 1268 1351 1335 4 1257 1269 1352 1338 5 1353 1270 1259 1340 1354 6 1353 1354 1344 1342 1271 1272 3 1342 1271 1261 4 1264 1273 1355 1347 4 1266 1274 1356 1350 4 1275 1268 1351 1357 4 1275 1276 1358 1357 4 1269 1277 1359 1352 3 1353 1278 1270 3 1353 1278 1272 4 1279 1273 1355 1360 4 1279 1274 1356 1360 4 1280 1276 1358 1361 4 1280 1277 1359 1361 3 1362 1363 1364 3 1362 1363 1365 4 1362 1364 1367 1366 4 1362 1365 1368 1366 3 1366 1369 1367 3 1366 1369 1368 3 1370 1282 1283 3 1370 1282 1284 3 1371 1285 1286 4 1371 1285 1287 1372 3 1372 1287 1288 5 1370 1283 1291 1374 1373 5 1370 1284 1292 1375 1373 4 1371 1286 1293 1376 5 1371 1372 1377 1378 1376 5 1372 1288 1294 1379 1377 3 1380 1295 1296 4 1380 1295 1297 1381 4 1291 1299 1382 1374 4 1292 1301 1383 1375 5 1376 1293 1302 1385 1384 3 1376 1384 1378 4 1294 1303 1386 1379 5 1380 1296 1304 1388 1387 5 1380 1387 1390 1389 1381 4 1299 1305 1391 1382 4 1301 1306 1392 1383 4 1307 1302 1385 1393 4 1307 1308 1394 1393 4 1303 1309 1395 1386 4 1304 1310 1396 1388 4 1389 1390 1398 1397 4 1305 1311 1399 1391 4 1306 1312 1400 1392 4 1313 1308 1394 1401 4 1313 1309 1395 1401 5 1402 1314 1310 1396 1403 6 1402 1403 1398 1397 1315 1316 4 1317 1311 1399 1404 4 1317 1312 1400 1404 3 1402 1318 1314 3 1402 1318 1316 3 1405 1320 1321 3 1405 1320 1322 3 1406 1324 1325 3 1406 1324 1326 3 1407 1327 1328 3 1407 1327 1330 5 1405 1321 1331 1409 1408 5 1405 1322 1332 1410 1408 3 1411 1334 1335 5 1411 1413 1412 1336 1334 4 1412 1337 1338 1413 4 1414 1339 1340 1415 4 1414 1343 1344 1415 4 1346 1347 1417 1416 4 1349 1350 1419 1418 4 1411 1335 1351 1420 4 1411 1413 1421 1420 4 1413 1338 1352 1421 3 1415 1354 1340 3 1415 1354 1344 4 1347 1355 1422 1417 4 1350 1356 1423 1419 3 1420 1357 1351 5 1420 1357 1358 1424 1421 4 1421 1352 1359 1424 4 1360 1355 1422 1425 4 1360 1356 1423 1425 3 1424 1361 1358 3 1424 1361 1359 3 1426 1427 1428 3 1426 1427 1429 4 1426 1428 1431 1430 4 1426 1429 1432 1430 3 1433 1434 1435 5 1433 1364 1363 1436 1434 4 1363 1365 1437 1436 4 1430 1431 1439 1438 4 1430 1432 1440 1438 4 1433 1435 1442 1441 4 1433 1364 1367 1441 4 1365 1368 1443 1437 3 1444 1445 1446 3 1444 1445 1447 3 1438 1448 1439 3 1438 1448 1440 4 1441 1442 1450 1449 5 1441 1367 1369 1451 1449 5 1451 1452 1443 1368 1369 3 1444 1453 1446 3 1444 1453 1447 3 1449 1454 1450 4 1449 1454 1455 1451 3 1451 1455 1452 3 1456 1457 1458 4 1456 1457 1460 1459 3 1459 1460 1461 4 1456 1458 1463 1462 4 1456 1459 1464 1462 4 1459 1461 1465 1464 3 1466 1467 1468 3 1466 1467 1469 3 1462 1470 1463 5 1462 1470 1472 1471 1464 4 1464 1465 1473 1471 3 1474 1373 1374 3 1474 1373 1375 3 1475 1377 1378 3 1475 1377 1379 4 1466 1468 1477 1476 4 1466 1469 1478 1476 3 1471 1479 1472 3 1471 1479 1473 5 1474 1374 1382 1481 1480 5 1474 1375 1383 1482 1480 3 1483 1384 1385 5 1483 1484 1475 1378 1384 4 1475 1379 1386 1484 4 1476 1477 1486 1485 4 1476 1478 1487 1485 3 1488 1387 1388 3 1488 1387 1390 4 1382 1391 1489 1481 4 1383 1392 1490 1482 3 1483 1393 1385 5 1483 1393 1394 1491 1484 4 1484 1386 1395 1491 3 1485 1492 1486 3 1485 1492 1487 4 1488 1388 1396 1493 4 1488 1390 1398 1493 4 1391 1399 1494 1489 4 1392 1400 1495 1490 3 1491 1401 1394 3 1491 1401 1395 3 1493 1403 1396 3 1493 1403 1398 4 1404 1399 1494 1496 4 1404 1400 1495 1496 3 1497 1408 1409 3 1497 1408 1410 4 1498 1416 1417 1499 4 1498 1418 1419 1499 4 1499 1417 1422 1500 4 1499 1419 1423 1500 3 1500 1425 1422 3 1500 1425 1423 4 1427 1428 1502 1501 4 1427 1429 1503 1501 3 1504 1505 1506 3 1504 1505 1507 4 1428 1431 1508 1502 4 1429 1432 1509 1503 4 1434 1435 1511 1510 5 1504 1506 1510 1434 1436 5 1504 1507 1512 1437 1436 3 1513 1514 1515 3 1513 1514 1516 4 1431 1439 1517 1508 4 1432 1440 1518 1509 4 1435 1442 1519 1511 4 1437 1443 1520 1512 5 1513 1515 1521 1446 1445 6 1513 1445 1447 1522 1523 1516 5 1524 1525 1517 1439 1448 5 1524 1526 1518 1440 1448 4 1442 1450 1527 1519 4 1443 1452 1528 1520 5 1529 1530 1521 1446 1453 5 1529 1531 1522 1447 1453 3 1524 1532 1525 3 1524 1532 1526 4 1454 1450 1527 1533 5 1534 1535 1533 1454 1455 5 1534 1536 1528 1452 1455 4 1529 1530 1538 1537 5 1529 1531 1539 1540 1537 3 1534 1541 1535 3 1534 1541 1536 3 1537 1542 1538 3 1537 1542 1540 4 1457 1458 1544 1543 4 1457 1460 1545 1543 4 1460 1461 1546 1545 3 1547 1548 1549 3 1547 1548 1550 3 1551 1552 1553 3 1551 1552 1554 4 1458 1463 1555 1544 4 1461 1465 1556 1546 4 1547 1549 1558 1557 5 1547 1550 1560 1559 1557 3 1559 1560 1561 5 1551 1553 1562 1468 1467 5 1551 1554 1563 1469 1467 5 1564 1565 1555 1463 1470 3 1564 1470 1472 4 1465 1473 1566 1556 4 1557 1558 1568 1567 4 1557 1559 1569 1567 4 1559 1561 1570 1569 4 1468 1477 1571 1562 4 1469 1478 1572 1563 3 1564 1573 1565 6 1564 1573 1575 1574 1479 1472 5 1574 1576 1566 1473 1479 3 1577 1480 1481 3 1577 1480 1482 4 1567 1568 1579 1578 5 1567 1569 1580 1581 1578 3 1569 1580 1570 4 1477 1486 1582 1571 4 1478 1487 1583 1572 3 1574 1584 1575 3 1574 1584 1576 4 1577 1481 1489 1585 4 1577 1482 1490 1585 3 1578 1586 1579 3 1578 1586 1581 5 1587 1588 1582 1486 1492 5 1587 1589 1583 1487 1492 4 1585 1489 1494 1590 4 1585 1490 1495 1590 3 1587 1591 1588 3 1587 1591 1589 3 1590 1496 1494 3 1590 1496 1495 4 1501 1502 1593 1592 4 1501 1503 1594 1592 3 1595 1505 1506 3 1595 1505 1507 4 1502 1508 1596 1593 4 1503 1509 1597 1594 4 1510 1511 1599 1598 5 1595 1600 1598 1510 1506 5 1595 1507 1512 1601 1600 4 1514 1515 1603 1602 4 1514 1516 1604 1602 3 1605 1606 1607 5 1605 1517 1508 1596 1606 4 1509 1518 1608 1597 4 1511 1519 1609 1599 4 1512 1520 1610 1601 4 1515 1521 1611 1603 4 1523 1516 1604 1612 3 1605 1613 1607 5 1605 1517 1525 1614 1613 4 1518 1526 1615 1608 4 1519 1527 1616 1609 4 1520 1528 1617 1610 4 1521 1530 1618 1611 5 1619 1620 1614 1525 1532 5 1619 1621 1615 1526 1532 5 1622 1623 1616 1527 1533 3 1622 1533 1535 4 1528 1536 1624 1617 4 1530 1538 1625 1618 3 1626 1539 1540 3 1619 1627 1620 3 1619 1627 1621 3 1622 1628 1623 5 1622 1535 1541 1629 1628 4 1541 1536 1624 1629 4 1542 1538 1625 1630 5 1626 1631 1630 1542 1540 4 1543 1544 1633 1632 4 1543 1545 1634 1632 4 1545 1546 1635 1634 4 1548 1549 1637 1636 4 1548 1550 1638 1636 3 1639 1552 1553 3 1639 1552 1554 4 1544 1555 1640 1633 4 1546 1556 1641 1635 4 1549 1558 1642 1637 4 1560 1550 1638 1643 4 1560 1561 1644 1643 5 1639 1553 1562 1646 1645 5 1639 1554 1563 1647 1645 4 1555 1565 1648 1640 4 1556 1566 1649 1641 4 1558 1568 1650 1642 4 1561 1570 1651 1644 4 1562 1571 1652 1646 4 1563 1572 1653 1647 5 1654 1655 1648 1565 1573 3 1654 1573 1575 4 1566 1576 1656 1649 4 1568 1579 1657 1650 3 1658 1580 1581 5 1658 1659 1651 1570 1580 4 1571 1582 1660 1652 4 1572 1583 1661 1653 3 1654 1662 1655 6 1654 1662 1664 1663 1584 1575 5 1663 1665 1656 1576 1584 5 1666 1667 1657 1579 1586 6 1666 1586 1581 1658 1668 1669 3 1658 1668 1659 4 1582 1588 1670 1660 4 1583 1589 1671 1661 3 1663 1672 1664 3 1663 1672 1665 3 1666 1673 1667 3 1666 1673 1669 5 1674 1675 1670 1588 1591 5 1674 1676 1671 1589 1591 3 1674 1677 1675 3 1674 1677 1676 -0.420 0.841 3.419 0.172 0.985 -0.001 -0.279 0.991 3.419 0.103 0.995 -0.002 -0.501 1.002 2.993 0.153 0.967 0.206 -0.284 1.002 3.388 0.103 0.995 0.004 -0.501 1.002 3.841 0.149 0.967 -0.206 -0.284 1.002 3.449 0.103 0.995 -0.009 -0.626 1.252 2.756 -0.010 0.316 0.949 -0.409 1.252 2.822 -0.353 0.589 0.727 -0.626 1.252 4.076 -0.020 0.293 -0.956 -0.409 1.252 4.010 -0.368 0.591 -0.717 -0.533 1.066 8.205 0.017 0.997 -0.079 -0.407 1.248 8.205 -0.080 0.993 -0.083 -0.626 1.252 7.522 0.035 0.923 0.384 -0.409 1.252 8.190 -0.080 0.994 -0.077 -0.626 1.252 8.583 -0.074 0.951 -0.301 -0.409 1.252 8.213 -0.080 0.993 -0.085 -0.556 1.111 12.307 0.255 0.886 0.386 -0.396 1.226 12.307 0.156 0.927 0.342 -0.626 1.252 12.022 0.251 0.853 0.458 -0.409 1.252 12.254 0.160 0.924 0.348 -0.626 1.252 12.855 0.259 0.839 -0.478 -0.409 1.252 12.412 0.163 0.955 0.250 -0.588 1.503 2.735 -0.245 0.131 0.961 -0.680 1.361 2.735 -0.031 0.276 0.961 -0.751 1.503 2.638 -0.174 0.106 0.979 -0.535 1.503 2.745 -0.247 0.142 0.958 -0.631 1.503 4.102 -0.198 0.125 -0.972 -0.702 1.404 4.102 -0.025 0.216 -0.976 -0.535 1.503 4.088 -0.224 0.156 -0.962 -0.751 1.503 4.165 -0.078 0.064 -0.995 -0.626 1.253 7.521 0.035 0.922 0.386 -0.480 1.394 7.521 -0.356 0.801 0.481 -0.751 1.503 7.106 -0.305 0.581 0.755 -0.535 1.503 7.339 -0.414 0.719 0.558 -0.751 1.503 8.781 -0.195 0.341 -0.920 -0.535 1.503 8.678 -0.535 0.665 -0.522 -0.751 1.503 11.748 0.166 0.323 0.932 -0.535 1.503 11.790 -0.176 0.498 0.849 -0.640 1.280 12.991 0.197 0.619 -0.760 -0.457 1.347 12.991 0.002 0.595 -0.804 -0.856 1.711 2.735 -0.101 -0.283 0.954 -0.877 1.753 2.741 -0.087 -0.310 0.947 -0.660 1.753 2.750 -0.268 -0.195 0.943 -0.814 1.627 4.102 -0.025 -0.199 -0.980 -0.877 1.753 4.083 0.023 -0.291 -0.957 -0.660 1.753 4.086 -0.214 -0.174 -0.961 -0.877 1.753 7.035 -0.369 -0.057 0.928 -0.660 1.753 7.137 -0.673 0.157 0.722 -0.877 1.753 8.797 0.053 -0.048 -0.997 -0.660 1.753 8.767 -0.572 0.100 -0.814 -0.877 1.753 11.720 0.101 0.024 0.995 -0.660 1.753 11.721 0.082 0.138 0.987 -1.002 2.004 2.894 -0.059 -0.886 0.459 -0.785 2.004 2.849 -0.385 -0.679 0.626 -1.002 2.004 3.932 0.033 -0.890 -0.454 -0.785 2.004 3.994 -0.318 -0.675 -0.665 -1.002 2.004 7.145 -0.303 -0.659 0.688 -0.785 2.004 7.190 -0.661 -0.394 0.639 -1.002 2.004 8.762 -0.184 -0.492 -0.851 -0.785 2.004 8.736 -0.648 -0.391 -0.654 -1.002 2.004 11.738 0.021 -0.291 0.956 -0.785 2.004 11.719 0.021 -0.168 0.986 -1.106 2.212 3.419 -0.150 -0.989 -0.003 -0.908 2.249 3.419 -0.378 -0.926 0.006 -1.114 2.228 7.521 -0.268 -0.898 0.347 -0.905 2.244 7.521 -0.521 -0.775 0.357 -1.127 2.254 7.692 -0.272 -0.951 0.148 -0.910 2.254 7.565 -0.518 -0.805 0.290 -1.127 2.254 8.414 -0.292 -0.946 -0.139 -0.910 2.254 8.460 -0.566 -0.805 -0.179 -1.127 2.254 11.995 0.078 -0.879 0.470 -0.910 2.254 11.841 -0.111 -0.696 0.710 -1.174 2.348 8.205 -0.279 -0.957 -0.085 -0.973 2.379 8.205 -0.529 -0.843 -0.100 -1.199 2.397 12.307 0.021 -0.928 0.373 -1.019 2.471 12.307 -0.224 -0.908 0.353 -1.136 2.272 12.991 -0.011 -0.718 -0.695 -0.970 2.374 12.991 -0.177 -0.644 -0.744 -1.352 2.755 0.684 0.071 0.719 0.691 -1.369 2.738 0.684 0.079 0.716 0.693 -1.378 2.755 0.649 0.079 0.710 0.700 -1.197 2.755 1.367 -0.004 0.994 -0.109 -1.306 2.612 1.367 0.050 0.994 -0.096 -1.378 2.755 1.680 0.015 0.975 -0.220 -1.204 2.755 5.470 0.229 0.970 0.078 -1.331 2.662 5.470 0.289 0.954 0.085 -1.378 2.755 5.261 0.302 0.943 0.138 -1.378 2.755 5.983 0.287 0.947 -0.148 -1.214 2.862 0.684 -0.148 0.619 0.771 -1.503 3.006 0.261 -0.130 0.370 0.920 -1.286 3.006 0.446 -0.189 0.477 0.858 -1.171 2.776 1.367 -0.095 0.988 -0.119 -1.503 3.006 1.937 -0.262 0.375 -0.889 -1.286 3.006 1.813 -0.466 0.748 -0.473 -1.166 2.766 5.470 0.172 0.982 0.081 -1.503 3.006 4.913 0.223 0.488 0.844 -1.286 3.006 4.960 -0.152 0.757 0.636 -1.391 2.781 6.154 0.271 0.898 -0.347 -1.209 2.851 6.154 0.038 0.924 -0.379 -1.503 3.006 6.530 0.242 0.671 -0.701 -1.286 3.006 6.434 -0.009 0.835 -0.549 -1.399 2.797 10.256 0.182 0.983 0.003 -1.233 2.900 10.256 0.074 0.997 0.012 -1.503 3.006 9.743 -0.010 0.891 0.454 -1.286 3.006 9.994 0.060 0.993 0.101 -1.503 3.006 10.780 0.081 0.885 -0.459 -1.286 3.006 10.544 0.079 0.993 -0.092 -1.628 3.256 0.190 -0.178 -0.038 0.983 -1.411 3.256 0.271 -0.374 0.081 0.924 -1.628 3.256 1.955 0.093 -0.031 -0.995 -1.411 3.256 1.927 -0.555 0.150 -0.819 -1.628 3.256 4.878 0.219 0.047 0.975 -1.411 3.256 4.872 0.085 0.161 0.983 -1.628 3.256 6.639 0.321 0.058 -0.945 -1.411 3.256 6.634 -0.200 0.297 -0.934 -1.628 3.256 9.592 0.015 0.291 0.957 -1.411 3.256 9.639 -0.300 0.448 0.842 -1.628 3.256 10.934 0.096 0.309 -0.946 -1.411 3.256 10.900 -0.153 0.427 -0.891 -1.753 3.507 0.297 -0.192 -0.428 0.883 -1.536 3.507 0.331 -0.402 -0.280 0.872 -1.753 3.507 1.927 -0.124 -0.439 -0.890 -1.536 3.507 1.905 -0.625 -0.350 -0.698 -1.753 3.507 4.894 -0.063 -0.347 0.936 -1.536 3.507 4.879 0.070 -0.231 0.970 -1.753 3.507 6.568 0.316 -0.578 -0.752 -1.536 3.507 6.624 -0.222 -0.394 -0.892 -1.617 3.507 9.572 -0.232 0.070 0.970 -1.691 3.383 9.572 -0.033 0.198 0.980 -1.753 3.507 9.510 -0.077 -0.064 0.995 -1.536 3.507 9.584 -0.239 0.111 0.965 -1.649 3.298 10.940 0.083 0.283 -0.955 -1.504 3.441 10.940 -0.167 0.138 -0.976 -1.753 3.507 11.037 0.039 -0.107 -0.993 -1.536 3.507 10.985 -0.206 0.063 -0.977 -1.865 3.729 0.684 -0.205 -0.618 0.759 -1.654 3.742 0.684 -0.374 -0.542 0.753 -1.879 3.757 0.820 -0.245 -0.799 0.549 -1.662 3.757 0.740 -0.411 -0.622 0.666 -1.879 3.757 1.652 -0.284 -0.940 -0.188 -1.662 3.757 1.677 -0.598 -0.773 -0.214 -1.879 3.757 5.092 0.170 -0.940 0.297 -1.662 3.757 4.975 -0.150 -0.772 0.618 -1.878 3.757 6.154 0.080 -0.920 -0.385 -1.878 3.757 6.154 0.082 -0.919 -0.385 -1.879 3.757 6.153 0.082 -0.920 -0.383 -1.662 3.757 6.375 -0.217 -0.844 -0.491 -1.803 3.605 9.572 -0.036 -0.216 0.976 -1.879 3.757 9.599 0.009 -0.293 0.956 -1.662 3.757 9.596 -0.238 -0.224 0.945 -1.824 3.649 10.940 -0.003 -0.276 -0.961 -1.596 3.625 10.940 -0.213 -0.093 -0.973 -1.879 3.757 10.919 0.000 -0.316 -0.949 -1.662 3.757 10.927 -0.214 -0.259 -0.942 -1.949 3.898 1.367 -0.276 -0.958 -0.077 -1.742 3.919 1.367 -0.560 -0.825 -0.083 -1.971 3.943 5.470 0.051 -0.996 0.079 -1.784 4.002 5.470 -0.295 -0.953 0.068 -1.723 3.879 6.154 -0.227 -0.885 -0.406 -2.004 4.007 9.834 -0.113 -0.972 0.207 -1.787 4.007 9.743 -0.421 -0.814 0.401 -2.004 4.007 10.682 -0.119 -0.971 -0.207 -1.787 4.007 10.774 -0.413 -0.819 -0.399 -2.084 4.169 10.256 -0.139 -0.990 0.001 -1.890 4.214 10.256 -0.409 -0.913 0.000 -0.271 1.002 3.419 0.098 0.995 -0.002 -0.133 1.133 3.419 -0.383 0.924 -0.004 -0.192 1.252 3.126 -0.434 0.893 0.120 -0.192 1.252 3.705 -0.434 0.893 -0.122 -0.405 1.252 8.205 -0.082 0.993 -0.083 -0.376 1.252 12.307 0.144 0.928 0.344 -0.318 1.503 2.827 -0.492 0.396 0.776 -0.318 1.503 4.007 -0.480 0.423 -0.769 -0.431 1.503 7.521 -0.466 0.739 0.486 -0.295 1.457 8.205 -0.651 0.753 -0.100 -0.318 1.503 8.039 -0.665 0.746 -0.028 -0.318 1.503 8.287 -0.672 0.730 -0.125 -0.235 1.338 12.307 -0.179 0.879 0.441 -0.318 1.503 11.977 -0.243 0.789 0.564 -0.335 1.503 12.991 -0.125 0.579 -0.805 -0.318 1.503 12.943 -0.161 0.664 -0.730 -0.443 1.753 2.798 -0.497 -0.107 0.861 -0.443 1.753 4.043 -0.465 -0.066 -0.883 -0.418 1.704 7.521 -0.786 0.386 0.484 -0.443 1.753 7.459 -0.804 0.324 0.499 -0.443 1.753 8.589 -0.895 0.273 -0.353 -0.443 1.753 11.761 -0.218 0.314 0.924 -0.325 1.517 12.991 -0.155 0.560 -0.814 -0.568 2.004 2.896 -0.673 -0.584 0.453 -0.568 2.004 3.958 -0.653 -0.568 -0.500 -0.568 2.004 7.405 -0.836 -0.158 0.526 -0.568 2.004 8.596 -0.899 -0.241 -0.365 -0.568 2.004 11.735 -0.290 -0.088 0.953 -0.708 2.254 3.419 -0.538 -0.843 0.013 -0.693 2.254 3.416 -0.550 -0.835 0.015 -0.693 2.254 3.422 -0.550 -0.835 0.013 -0.632 2.132 7.521 -0.814 -0.363 0.454 -0.693 2.254 7.862 -0.752 -0.657 0.045 -0.693 2.254 8.319 -0.741 -0.653 -0.157 -0.693 2.254 11.829 -0.444 -0.548 0.709 -0.694 2.255 3.419 -0.550 -0.835 0.014 -0.726 2.319 8.205 -0.722 -0.680 -0.125 -0.814 2.495 12.307 -0.445 -0.833 0.328 -0.763 2.394 12.991 -0.361 -0.539 -0.761 -1.135 3.006 0.684 -0.283 0.568 0.773 -1.058 2.983 1.367 -0.544 0.826 -0.149 -1.069 3.006 1.212 -0.554 0.832 0.000 -1.069 3.006 1.409 -0.555 0.816 -0.161 -1.000 2.867 5.470 -0.128 0.987 0.095 -1.069 3.006 5.166 -0.175 0.958 0.228 -1.075 3.006 6.154 -0.129 0.919 -0.372 -1.069 3.006 6.136 -0.137 0.928 -0.347 -1.156 3.006 10.256 0.012 1.000 0.017 -1.119 3.106 0.684 -0.464 0.402 0.790 -1.194 3.256 0.511 -0.500 0.188 0.845 -1.194 3.256 1.749 -0.862 0.331 -0.385 -1.194 3.256 4.910 -0.268 0.422 0.866 -1.071 3.010 6.154 -0.143 0.916 -0.375 -1.194 3.256 6.524 -0.433 0.498 -0.751 -1.095 3.058 10.256 -0.255 0.967 0.024 -1.194 3.256 9.823 -0.468 0.824 0.320 -1.194 3.256 10.738 -0.438 0.824 -0.358 -1.319 3.507 0.504 -0.511 -0.167 0.843 -1.319 3.507 1.773 -0.889 -0.207 -0.408 -1.319 3.507 4.888 -0.326 -0.130 0.936 -1.319 3.507 6.579 -0.549 -0.167 -0.819 -1.319 3.507 9.650 -0.413 0.281 0.866 -1.481 3.507 10.940 -0.226 0.079 -0.971 -1.319 3.507 10.897 -0.354 0.201 -0.913 -1.398 3.663 0.684 -0.517 -0.341 0.785 -1.445 3.757 0.967 -0.698 -0.627 0.346 -1.445 3.757 1.530 -0.762 -0.626 -0.166 -1.445 3.757 4.973 -0.546 -0.630 0.552 -1.445 3.757 6.395 -0.519 -0.679 -0.519 -1.445 3.757 9.641 -0.528 -0.183 0.829 -1.445 3.757 10.893 -0.461 -0.223 -0.859 -1.493 3.853 1.367 -0.740 -0.664 -0.107 -1.706 4.007 5.470 -0.386 -0.920 0.069 -1.570 4.007 5.415 -0.514 -0.854 0.086 -1.516 3.899 6.154 -0.512 -0.763 -0.396 -1.570 4.007 5.580 -0.512 -0.858 0.038 -1.570 4.007 9.794 -0.675 -0.677 0.294 -1.570 4.007 10.731 -0.657 -0.693 -0.296 -1.583 4.034 5.470 -0.513 -0.855 0.073 -1.671 4.209 10.256 -0.605 -0.796 0.002 0.555 0.000 3.419 0.829 -0.560 0.000 0.587 0.128 3.419 0.753 -0.658 0.000 0.651 0.000 3.146 0.826 -0.551 0.118 0.651 0.000 3.691 0.827 -0.549 -0.118 0.063 1.002 10.256 0.919 0.395 -0.004 0.201 0.900 10.256 0.854 0.521 -0.003 0.150 1.002 10.054 0.894 0.442 0.073 0.150 1.002 10.454 0.895 0.440 -0.077 -0.082 1.252 3.419 -0.450 0.893 -0.005 -0.123 1.252 10.256 0.999 -0.048 -0.005 0.025 1.252 9.868 0.977 -0.007 0.212 0.025 1.252 10.637 0.978 -0.005 -0.210 -0.053 1.407 3.419 -0.820 0.572 -0.004 -0.101 1.503 3.222 -0.872 0.484 0.066 -0.101 1.503 3.613 -0.869 0.489 -0.071 -0.280 1.503 8.205 -0.674 0.731 -0.102 -0.177 1.503 10.256 0.912 -0.411 -0.003 -0.101 1.503 10.045 0.910 -0.408 0.074 -0.101 1.503 10.465 0.912 -0.403 -0.077 -0.154 1.503 12.307 -0.350 0.825 0.444 -0.226 1.753 3.005 -0.964 0.061 0.257 -0.226 1.753 3.838 -0.961 0.089 -0.263 -0.410 1.753 7.521 -0.811 0.335 0.479 -0.265 1.753 8.205 -0.940 0.321 -0.115 -0.156 1.614 10.256 0.859 -0.512 -0.002 -0.134 1.569 12.307 -0.559 0.690 0.460 -0.226 1.753 11.992 -0.669 0.480 0.568 -0.236 1.753 12.991 -0.432 0.350 -0.831 -0.226 1.753 12.946 -0.510 0.402 -0.761 -0.351 2.004 3.112 -0.910 -0.383 0.157 -0.351 2.004 3.745 -0.916 -0.368 -0.157 -0.496 2.004 7.521 -0.873 -0.113 0.475 -0.364 2.004 8.205 -0.990 -0.055 -0.128 -0.351 2.004 11.856 -0.689 0.046 0.723 -0.242 1.786 12.991 -0.460 0.305 -0.834 -0.690 2.254 3.419 -0.552 -0.834 0.014 -0.443 2.188 3.419 -0.818 -0.575 0.018 -0.610 2.254 8.205 -0.789 -0.600 -0.132 -0.476 2.254 11.946 -0.709 -0.397 0.583 -0.585 2.472 12.307 -0.638 -0.665 0.390 -0.499 2.300 12.991 -0.512 -0.319 -0.797 -1.048 3.006 1.367 -0.555 0.818 -0.150 -0.916 3.006 5.470 -0.246 0.964 0.103 -1.092 3.256 0.684 -0.565 0.237 0.790 -1.008 3.256 1.367 -0.910 0.381 -0.165 -0.884 3.070 5.470 -0.515 0.850 0.116 -0.977 3.256 5.127 -0.731 0.609 0.307 -0.961 3.223 6.154 -0.630 0.637 -0.444 -0.977 3.256 6.203 -0.650 0.602 -0.464 -1.003 3.256 10.256 -0.552 0.833 0.029 -1.194 3.507 0.684 -0.608 -0.128 0.783 -1.099 3.499 1.367 -0.987 -0.029 -0.157 -1.103 3.507 1.352 -0.989 -0.039 -0.143 -1.103 3.507 1.371 -0.987 -0.039 -0.158 -1.103 3.507 4.994 -0.830 0.042 0.555 -1.103 3.507 6.383 -0.818 0.029 -0.574 -0.999 3.300 10.256 -0.708 0.706 0.030 -1.103 3.507 9.916 -0.903 0.380 0.201 -1.103 3.507 10.646 -0.901 0.383 -0.206 -1.329 3.757 1.367 -0.821 -0.557 -0.126 -1.105 3.512 1.367 -0.987 -0.045 -0.157 -1.228 3.757 5.085 -0.819 -0.471 0.328 -1.228 3.757 6.241 -0.756 -0.480 -0.445 -1.228 3.757 9.825 -0.949 -0.079 0.306 -1.228 3.757 10.730 -0.935 -0.113 -0.336 -1.474 4.007 5.470 -0.579 -0.812 0.079 -1.342 3.985 5.470 -0.709 -0.700 0.090 -1.257 3.816 6.154 -0.746 -0.528 -0.406 -1.353 4.007 10.041 -0.855 -0.511 0.090 -1.353 4.007 10.489 -0.848 -0.524 -0.077 -1.407 4.115 10.256 -0.816 -0.578 0.009 -1.702 4.508 3.419 0.889 0.457 0.000 -1.549 4.400 3.419 0.835 0.551 0.003 -1.604 4.508 3.196 0.858 0.508 0.076 -1.604 4.508 3.643 0.861 0.503 -0.075 -1.891 4.759 3.419 1.000 0.009 -0.001 -1.729 4.759 2.992 0.962 0.119 0.247 -1.729 4.759 3.844 0.962 0.120 -0.245 0.607 0.250 3.419 0.513 -0.858 0.000 0.868 0.000 2.794 0.354 -0.458 0.816 0.742 0.250 3.057 0.473 -0.862 0.183 0.868 0.000 4.043 0.358 -0.452 -0.817 0.742 0.250 3.780 0.468 -0.865 -0.184 0.753 0.000 8.205 0.912 -0.400 -0.094 0.770 0.196 8.205 0.743 -0.663 -0.093 0.868 0.000 7.804 0.919 -0.358 0.165 0.868 0.000 8.442 0.911 -0.359 -0.203 0.775 0.000 12.307 0.582 -0.660 0.475 0.814 0.107 12.307 0.524 -0.712 0.468 0.868 0.000 12.116 0.583 -0.631 0.511 0.868 0.000 12.635 0.658 -0.748 -0.085 0.674 0.387 3.419 0.407 -0.913 -0.001 0.470 0.796 10.256 0.601 0.800 -0.002 0.367 1.002 9.774 0.684 0.656 0.319 0.367 1.002 10.732 0.683 0.657 -0.317 0.163 1.252 1.367 0.984 0.150 -0.099 0.311 1.114 1.367 0.921 0.377 -0.095 0.241 1.252 1.086 0.943 0.196 0.270 0.241 1.252 1.520 0.970 0.186 -0.156 0.125 1.252 5.470 0.868 0.485 0.102 0.296 1.144 5.470 0.760 0.643 0.092 0.241 1.252 5.294 0.800 0.578 0.164 0.241 1.252 5.805 0.805 0.588 -0.081 0.241 1.252 9.634 0.542 0.123 0.831 0.241 1.252 10.872 0.553 0.129 -0.823 0.056 1.503 1.367 0.965 -0.243 -0.101 0.116 1.503 1.105 0.954 -0.212 0.213 0.116 1.503 1.499 0.964 -0.227 -0.140 -0.030 1.503 3.419 -0.867 0.498 -0.004 -0.074 1.503 5.470 0.993 -0.018 0.115 0.116 1.503 5.091 0.931 0.126 0.341 0.097 1.503 6.154 0.874 0.150 -0.463 0.134 1.468 6.154 0.863 0.199 -0.464 0.116 1.503 6.186 0.867 0.157 -0.472 0.116 1.503 9.661 0.507 -0.372 0.778 0.116 1.503 10.848 0.523 -0.354 -0.776 0.063 1.609 1.367 0.928 -0.357 -0.109 -0.064 1.753 3.419 -0.990 0.138 0.001 -0.155 1.753 5.470 0.912 -0.393 0.118 -0.009 1.753 5.148 0.901 -0.349 0.257 0.038 1.659 6.154 0.878 -0.120 -0.464 -0.009 1.753 6.128 0.861 -0.307 -0.407 -0.148 1.753 10.256 0.576 -0.818 0.001 -0.009 1.753 9.905 0.539 -0.823 0.178 -0.009 1.753 10.612 0.554 -0.813 -0.181 -0.085 1.753 12.307 -0.732 0.505 0.458 -0.208 2.004 3.419 -0.963 -0.270 0.011 -0.116 1.967 5.470 0.712 -0.693 0.118 -0.086 1.907 10.256 0.447 -0.895 0.006 -0.140 2.004 12.307 -0.889 0.148 0.433 -0.249 2.004 12.991 -0.550 0.073 -0.832 -0.271 2.254 12.307 -0.871 -0.205 0.446 -0.434 2.254 12.991 -0.532 -0.269 -0.803 -0.820 3.256 5.470 -0.767 0.629 0.126 -0.949 3.256 6.154 -0.656 0.609 -0.445 -1.101 3.507 1.367 -0.987 -0.038 -0.157 -0.859 3.454 5.470 -0.968 0.218 0.122 -0.886 3.507 5.412 -0.980 0.149 0.135 -0.964 3.507 6.154 -0.890 0.094 -0.446 -0.886 3.507 5.627 -0.987 0.153 0.047 -0.958 3.507 10.256 -0.915 0.403 0.028 -1.011 3.757 5.463 -0.960 -0.255 0.115 -1.162 3.757 6.154 -0.797 -0.446 -0.409 -1.011 3.757 5.489 -0.961 -0.256 0.106 -1.040 3.757 10.256 -0.999 -0.018 0.028 -1.014 3.762 5.470 -0.959 -0.260 0.113 -1.246 4.007 10.256 -0.885 -0.465 0.015 -1.270 4.258 12.307 0.681 0.621 0.389 -1.258 4.252 12.307 0.677 0.625 0.388 -1.261 4.258 12.295 0.677 0.624 0.390 -1.261 4.258 12.334 0.686 0.629 0.366 -1.278 4.291 3.419 0.625 0.781 0.008 -1.387 4.508 2.929 0.667 0.680 0.303 -1.387 4.508 3.916 0.679 0.663 -0.314 -1.596 4.508 12.307 0.872 0.245 0.424 -1.387 4.508 11.927 0.748 0.399 0.530 -1.392 4.508 12.991 0.554 0.218 -0.803 -1.383 4.501 12.991 0.554 0.224 -0.802 -1.512 4.759 2.785 0.525 0.283 0.803 -1.512 4.759 4.053 0.529 0.271 -0.804 -1.627 4.759 8.205 0.947 0.309 -0.082 -1.433 4.602 8.205 0.855 0.512 -0.087 -1.512 4.759 7.835 0.933 0.342 0.110 -1.512 4.759 8.414 0.914 0.374 -0.159 -1.716 4.759 12.307 0.801 -0.333 0.497 -1.512 4.759 11.891 0.716 -0.199 0.669 -1.526 4.759 12.991 0.460 -0.167 -0.872 1.040 0.000 2.735 0.147 -0.186 0.972 1.060 0.049 2.735 0.108 -0.222 0.969 1.085 0.000 2.694 0.122 -0.169 0.978 0.959 0.250 2.796 -0.002 -0.701 0.713 1.043 0.000 4.102 0.145 -0.182 -0.972 1.062 0.045 4.102 0.104 -0.219 -0.970 0.959 0.250 4.040 -0.021 -0.710 -0.704 1.085 0.000 4.141 0.121 -0.169 -0.978 0.952 0.000 7.521 0.775 -0.299 0.556 0.965 0.240 7.521 0.584 -0.644 0.495 1.085 0.000 7.299 0.711 -0.274 0.647 0.765 0.250 8.205 0.616 -0.782 -0.091 0.959 0.250 7.535 0.575 -0.672 0.467 1.085 0.000 8.728 0.579 -0.291 -0.762 0.959 0.250 8.600 0.535 -0.768 -0.352 0.899 0.250 12.307 0.263 -0.853 0.452 1.085 0.000 11.801 0.187 -0.619 0.763 0.959 0.250 12.196 0.257 -0.841 0.476 0.970 0.000 12.991 0.271 -0.410 -0.871 1.022 0.124 12.991 0.221 -0.458 -0.861 0.959 0.250 12.507 0.285 -0.940 0.188 0.810 0.501 3.419 -0.069 -0.998 -0.002 0.834 0.501 3.359 -0.076 -0.997 0.010 0.834 0.501 3.477 -0.077 -0.997 -0.014 0.853 0.463 8.205 0.335 -0.939 -0.081 0.933 0.302 12.307 0.244 -0.860 0.448 0.824 0.521 3.419 -0.075 -0.997 -0.002 0.520 1.002 1.367 0.647 0.758 -0.079 0.599 0.971 1.367 0.594 0.801 -0.075 0.584 1.002 1.256 0.606 0.795 0.026 0.584 1.002 1.429 0.601 0.794 -0.094 0.688 0.793 10.256 0.416 0.909 -0.003 0.584 1.002 9.721 0.421 0.798 0.431 0.584 1.002 10.781 0.406 0.808 -0.426 0.395 1.252 0.684 0.461 0.233 0.856 0.490 1.188 0.684 0.439 0.296 0.848 0.458 1.252 0.596 0.439 0.256 0.861 0.458 1.252 1.804 0.776 0.456 -0.437 0.543 1.082 5.470 0.515 0.853 0.083 0.458 1.252 5.144 0.558 0.794 0.241 0.458 1.252 6.087 0.568 0.764 -0.306 0.458 1.252 9.584 0.232 0.193 0.953 0.458 1.252 10.921 0.218 0.203 -0.955 0.212 1.503 0.684 0.495 -0.059 0.867 0.333 1.503 0.473 0.461 -0.028 0.887 0.333 1.503 1.861 0.756 -0.119 -0.644 0.333 1.503 4.933 0.564 0.344 0.750 0.447 1.275 6.154 0.582 0.704 -0.407 0.333 1.503 6.469 0.659 0.383 -0.647 0.333 1.503 9.579 0.191 -0.149 0.970 0.333 1.503 10.928 0.171 -0.128 -0.977 0.198 1.753 0.684 0.433 -0.326 0.840 0.208 1.753 0.665 0.431 -0.324 0.842 0.042 1.753 1.367 0.751 -0.649 -0.118 0.208 1.753 1.723 0.707 -0.637 -0.306 0.208 1.753 4.917 0.403 -0.217 0.889 -0.003 1.753 6.154 0.842 -0.296 -0.451 0.208 1.753 6.513 0.659 -0.188 -0.728 0.208 1.753 9.649 0.168 -0.561 0.811 0.208 1.753 10.866 0.183 -0.520 -0.834 0.201 1.767 0.684 0.430 -0.332 0.840 0.108 1.953 1.367 0.524 -0.843 -0.120 -0.114 2.004 5.470 0.593 -0.797 0.118 0.083 2.004 5.056 0.463 -0.794 0.394 0.010 2.004 6.154 0.488 -0.752 -0.443 0.083 2.004 6.282 0.459 -0.740 -0.492 0.002 2.004 10.256 0.032 -0.999 0.008 0.083 2.004 10.081 -0.005 -0.998 0.057 0.083 2.004 10.444 0.000 -0.999 -0.047 -0.024 2.217 5.470 0.271 -0.957 0.107 0.043 2.083 6.154 0.423 -0.794 -0.436 0.046 2.076 10.256 0.001 -1.000 0.010 -0.859 3.507 5.470 -0.981 0.155 0.119 -1.007 3.757 5.470 -0.961 -0.254 0.114 -0.999 4.166 12.307 0.511 0.782 0.357 -1.044 4.258 12.116 0.513 0.762 0.395 -1.044 4.258 12.736 0.558 0.806 -0.194 -1.055 4.279 3.419 0.454 0.891 0.012 -1.170 4.508 2.879 0.430 0.795 0.427 -1.170 4.508 3.974 0.440 0.769 -0.463 -1.235 4.508 8.205 0.667 0.738 -0.101 -1.154 4.476 8.205 0.627 0.772 -0.105 -1.170 4.508 8.058 0.642 0.765 -0.043 -1.170 4.508 8.268 0.630 0.767 -0.122 -1.170 4.508 11.785 0.503 0.507 0.700 -1.073 4.314 12.991 0.432 0.513 -0.742 -1.295 4.759 2.747 0.254 0.344 0.904 -1.295 4.759 4.093 0.252 0.307 -0.918 -1.386 4.759 7.521 0.789 0.418 0.451 -1.245 4.659 7.521 0.727 0.538 0.428 -1.295 4.759 7.396 0.741 0.470 0.480 -1.295 4.759 8.660 0.719 0.584 -0.376 -1.295 4.759 11.733 0.281 0.003 0.960 1.207 0.188 2.735 -0.120 -0.350 0.929 1.301 0.000 2.632 -0.159 -0.071 0.985 1.176 0.250 2.746 -0.127 -0.415 0.901 1.219 0.166 4.102 -0.157 -0.356 -0.921 1.176 0.250 4.086 -0.166 -0.444 -0.880 1.301 0.000 4.202 -0.192 -0.125 -0.973 0.964 0.250 7.521 0.561 -0.668 0.490 1.301 0.000 7.092 0.489 0.020 0.872 1.176 0.250 7.168 0.257 -0.700 0.666 1.301 0.000 8.797 0.257 0.163 -0.953 1.176 0.250 8.773 0.016 -0.596 -0.803 1.301 0.000 11.719 -0.071 -0.378 0.923 1.176 0.250 11.886 -0.022 -0.782 0.623 1.123 0.250 12.991 0.059 -0.548 -0.834 1.051 0.501 2.958 -0.158 -0.952 0.264 1.051 0.501 3.866 -0.180 -0.950 -0.254 1.062 0.479 7.521 0.156 -0.896 0.415 0.878 0.501 8.205 0.189 -0.979 -0.078 1.051 0.501 7.605 0.129 -0.946 0.298 1.051 0.501 8.534 0.093 -0.968 -0.235 1.077 0.449 12.307 -0.106 -0.915 0.389 1.155 0.294 12.991 0.038 -0.554 -0.832 0.967 0.669 3.419 -0.185 -0.983 -0.007 0.976 0.651 8.205 0.046 -0.996 -0.077 0.815 0.972 1.367 0.412 0.908 -0.068 0.801 1.002 1.238 0.422 0.906 0.029 0.801 1.002 1.434 0.417 0.905 -0.083 0.882 0.839 10.256 0.239 0.971 -0.007 0.801 1.002 9.809 0.229 0.947 0.224 0.801 1.002 10.683 0.208 0.953 -0.219 0.748 1.107 0.684 0.330 0.516 0.790 0.675 1.252 0.439 0.327 0.428 0.842 0.675 1.252 1.878 0.457 0.630 -0.628 0.746 1.111 5.470 0.321 0.943 0.085 0.675 1.252 5.179 0.334 0.922 0.196 0.675 1.252 6.074 0.386 0.888 -0.248 0.675 1.252 9.584 0.073 0.310 0.948 0.675 1.252 10.915 0.004 0.302 -0.953 0.550 1.503 0.260 0.339 0.097 0.936 0.550 1.503 1.949 0.296 0.092 -0.951 0.550 1.503 4.910 0.208 0.430 0.879 0.667 1.268 6.154 0.395 0.850 -0.349 0.550 1.503 6.542 0.382 0.612 -0.692 0.373 1.503 9.572 0.194 -0.136 0.971 0.640 1.322 9.572 0.089 0.262 0.961 0.550 1.503 9.474 0.094 -0.057 0.994 0.426 1.503 10.940 0.151 -0.086 -0.985 0.599 1.406 10.940 0.025 0.191 -0.981 0.550 1.503 10.998 0.007 0.016 -1.000 0.425 1.753 0.311 0.260 -0.270 0.927 0.425 1.753 1.926 0.228 -0.416 -0.880 0.425 1.753 4.883 0.101 0.009 0.995 0.425 1.753 6.636 0.316 0.013 -0.949 0.477 1.650 9.572 0.005 -0.285 0.959 0.425 1.753 9.593 -0.008 -0.341 0.940 0.498 1.608 10.940 -0.019 -0.180 -0.983 0.425 1.753 10.917 -0.018 -0.284 -0.959 0.281 2.004 0.684 0.137 -0.590 0.796 0.300 2.004 0.652 0.128 -0.586 0.800 0.131 2.004 1.367 0.317 -0.941 -0.116 0.300 2.004 1.702 0.202 -0.942 -0.267 0.300 2.004 4.906 0.145 -0.417 0.897 0.300 2.004 6.548 0.164 -0.635 -0.754 0.300 2.004 9.770 -0.095 -0.922 0.376 0.300 2.004 10.757 -0.096 -0.908 -0.407 0.290 2.023 0.684 0.128 -0.593 0.795 0.217 2.169 1.367 0.132 -0.985 -0.115 0.013 2.254 5.470 0.087 -0.991 0.097 0.174 2.254 5.173 -0.039 -0.978 0.206 0.178 2.247 6.154 -0.042 -0.931 -0.363 0.174 2.254 6.113 -0.053 -0.951 -0.304 0.198 2.206 10.256 -0.196 -0.981 0.013 0.105 2.392 5.470 -0.054 -0.994 0.091 -0.793 4.189 12.307 0.352 0.879 0.322 -0.828 4.258 12.157 0.355 0.869 0.346 -0.828 4.258 12.660 0.374 0.926 -0.048 -0.855 4.312 3.419 0.250 0.968 0.017 -0.953 4.508 2.948 0.175 0.927 0.331 -0.953 4.508 3.914 0.179 0.914 -0.364 -0.927 4.458 8.205 0.428 0.896 -0.120 -0.953 4.508 7.936 0.449 0.893 0.011 -0.953 4.508 8.310 0.430 0.890 -0.151 -0.953 4.508 11.764 0.288 0.589 0.755 -0.852 4.307 12.991 0.273 0.637 -0.721 -1.078 4.759 2.759 0.107 0.474 0.874 -1.078 4.759 4.085 0.091 0.412 -0.906 -0.987 4.577 7.521 0.497 0.767 0.405 -1.078 4.759 7.239 0.518 0.660 0.544 -1.078 4.759 8.726 0.474 0.707 -0.525 -1.078 4.759 11.713 0.047 0.017 0.999 1.493 0.000 2.735 -0.209 0.189 0.960 1.518 0.000 2.740 -0.186 0.223 0.957 1.393 0.250 2.745 -0.257 -0.257 0.932 1.487 0.000 4.102 -0.240 0.130 -0.962 1.518 0.000 4.096 -0.211 0.173 -0.962 1.393 0.250 4.083 -0.302 -0.305 -0.903 1.518 0.000 7.051 0.228 0.473 0.851 1.393 0.250 7.052 -0.098 -0.576 0.812 1.518 0.000 8.798 0.085 0.248 -0.965 1.393 0.250 8.799 -0.038 -0.201 -0.979 1.518 0.000 11.714 -0.107 -0.146 0.984 1.393 0.250 11.794 -0.260 -0.661 0.704 1.268 0.501 2.862 -0.344 -0.770 0.538 1.268 0.501 3.954 -0.381 -0.782 -0.493 1.084 0.501 7.521 0.087 -0.910 0.406 1.268 0.501 7.274 -0.079 -0.851 0.519 1.268 0.501 8.712 -0.015 -0.765 -0.644 1.268 0.501 12.307 -0.328 -0.893 0.309 1.314 0.409 12.991 -0.167 -0.603 -0.780 1.158 0.721 3.419 -0.372 -0.928 -0.012 1.199 0.638 7.521 -0.103 -0.914 0.391 1.149 0.739 8.205 -0.226 -0.971 -0.072 0.874 1.002 1.367 0.376 0.924 -0.068 1.034 0.969 10.256 0.132 0.991 -0.011 1.017 1.002 10.156 0.133 0.991 0.011 1.017 1.002 10.345 0.130 0.991 -0.031 0.951 1.134 0.684 0.202 0.633 0.747 0.892 1.252 0.466 0.196 0.583 0.789 1.006 1.025 1.367 0.257 0.964 -0.075 0.892 1.252 1.853 0.153 0.815 -0.559 0.909 1.219 5.470 0.197 0.976 0.087 0.892 1.252 5.400 0.201 0.974 0.101 0.892 1.252 5.657 0.210 0.977 0.026 0.892 1.252 9.630 -0.116 0.543 0.832 0.892 1.252 10.855 -0.212 0.566 -0.796 0.767 1.503 0.215 0.123 0.232 0.965 0.767 1.503 1.959 0.103 0.205 -0.973 0.767 1.503 4.946 -0.063 0.649 0.758 0.863 1.311 6.154 0.190 0.912 -0.363 0.767 1.503 6.488 0.109 0.782 -0.614 0.796 1.444 9.572 -0.131 0.185 0.974 0.767 1.503 9.524 -0.154 0.116 0.981 0.676 1.503 10.940 -0.154 0.110 -0.982 0.767 1.503 10.926 -0.174 0.154 -0.973 0.642 1.753 0.205 0.053 -0.170 0.984 0.642 1.753 1.958 0.021 -0.186 -0.982 0.642 1.753 4.884 -0.001 0.161 0.987 0.642 1.753 6.644 -0.065 0.220 -0.973 0.682 1.673 9.572 -0.173 -0.148 0.974 0.642 1.753 9.579 -0.179 -0.259 0.949 0.642 1.753 10.920 -0.215 -0.196 -0.957 0.516 2.004 0.387 -0.045 -0.494 0.869 0.516 2.004 1.882 0.048 -0.711 -0.702 0.516 2.004 4.883 -0.103 -0.227 0.968 0.516 2.004 6.616 -0.185 -0.442 -0.878 0.516 2.004 9.692 -0.316 -0.727 0.609 0.516 2.004 10.824 -0.343 -0.683 -0.645 0.428 2.181 0.684 -0.089 -0.616 0.782 0.380 2.254 1.367 -0.228 -0.969 -0.091 0.391 2.254 1.314 -0.233 -0.971 -0.058 0.391 2.254 1.385 -0.234 -0.968 -0.093 0.391 2.254 5.012 -0.239 -0.852 0.465 0.195 2.254 6.154 -0.085 -0.930 -0.358 0.391 2.254 6.349 -0.286 -0.846 -0.450 0.395 2.246 10.256 -0.409 -0.913 0.010 0.387 2.263 1.367 -0.233 -0.968 -0.090 0.283 2.470 5.470 -0.308 -0.947 0.086 0.337 2.362 6.154 -0.290 -0.883 -0.370 -0.691 4.258 12.307 0.277 0.909 0.313 -0.692 4.420 3.419 -0.132 0.991 0.021 -0.736 4.508 3.209 -0.145 0.984 0.106 -0.736 4.508 3.650 -0.150 0.985 -0.087 -0.806 4.508 8.205 0.287 0.949 -0.130 -0.619 4.275 12.307 0.189 0.924 0.332 -0.736 4.508 11.818 0.071 0.717 0.693 -0.669 4.374 12.991 0.045 0.614 -0.788 -0.861 4.759 2.810 0.006 0.696 0.718 -0.861 4.759 4.037 -0.024 0.637 -0.770 -0.783 4.603 7.521 0.231 0.876 0.422 -0.861 4.759 7.259 0.230 0.799 0.556 -0.740 4.517 8.205 0.202 0.971 -0.131 -0.861 4.759 8.704 0.238 0.836 -0.494 -0.861 4.759 11.716 0.023 0.228 0.973 1.735 0.000 2.806 -0.264 0.465 0.845 1.610 0.250 2.784 -0.449 -0.158 0.879 1.735 0.000 4.031 -0.304 0.410 -0.860 1.610 0.250 4.042 -0.503 -0.231 -0.833 1.735 0.000 7.113 0.000 0.760 0.650 1.610 0.250 7.053 -0.416 -0.285 0.864 1.735 0.000 8.779 -0.114 0.370 -0.922 1.610 0.250 8.799 -0.096 0.022 -0.995 1.735 0.000 11.728 -0.264 -0.085 0.961 1.610 0.250 11.795 -0.459 -0.563 0.687 1.485 0.501 2.883 -0.615 -0.635 0.467 1.485 0.501 3.925 -0.638 -0.652 -0.411 1.485 0.501 7.180 -0.351 -0.684 0.640 1.485 0.501 8.754 -0.285 -0.543 -0.790 1.269 0.501 12.307 -0.329 -0.892 0.309 1.485 0.501 12.191 -0.453 -0.812 0.368 1.515 0.440 12.991 -0.339 -0.564 -0.753 1.485 0.501 12.615 -0.473 -0.881 0.030 1.369 0.733 3.419 -0.525 -0.851 -0.018 1.383 0.704 7.521 -0.349 -0.863 0.364 1.205 0.751 8.205 -0.293 -0.954 -0.069 1.360 0.751 7.830 -0.366 -0.928 0.068 1.360 0.751 8.373 -0.378 -0.919 -0.116 1.457 0.557 12.307 -0.447 -0.822 0.351 1.323 0.825 8.205 -0.370 -0.926 -0.074 1.060 1.002 10.256 0.116 0.993 -0.012 1.111 1.248 0.684 0.068 0.725 0.685 1.109 1.252 0.676 0.068 0.724 0.686 1.182 1.107 1.367 0.031 0.996 -0.086 1.109 1.252 1.692 0.012 0.974 -0.228 0.938 1.252 5.470 0.182 0.979 0.090 1.187 1.097 10.256 -0.254 0.967 -0.022 1.109 1.252 9.847 -0.335 0.917 0.215 1.109 1.252 10.618 -0.355 0.912 -0.207 0.984 1.503 0.269 -0.089 0.367 0.926 0.984 1.503 1.944 -0.064 0.403 -0.913 1.074 1.322 5.470 -0.100 0.987 0.123 0.984 1.503 5.105 -0.221 0.918 0.329 1.021 1.428 6.154 -0.098 0.919 -0.381 0.984 1.503 6.286 -0.121 0.888 -0.443 0.826 1.503 9.572 -0.181 0.137 0.974 0.984 1.503 9.615 -0.302 0.291 0.908 0.984 1.503 10.861 -0.358 0.367 -0.858 0.859 1.753 0.202 -0.165 -0.049 0.985 0.859 1.753 1.966 -0.086 -0.057 -0.995 0.859 1.753 4.914 -0.241 0.372 0.896 0.859 1.753 6.562 -0.413 0.392 -0.822 0.859 1.753 9.603 -0.348 -0.151 0.925 0.859 1.753 10.884 -0.421 -0.107 -0.901 0.733 2.004 0.317 -0.222 -0.402 0.888 0.733 2.004 1.923 -0.254 -0.515 -0.819 0.733 2.004 4.897 -0.369 -0.153 0.917 0.733 2.004 6.582 -0.515 -0.241 -0.822 0.733 2.004 9.709 -0.589 -0.640 0.494 0.733 2.004 10.791 -0.636 -0.595 -0.492 0.620 2.231 0.684 -0.285 -0.614 0.736 0.608 2.254 0.815 -0.351 -0.790 0.503 0.608 2.254 1.595 -0.391 -0.908 -0.152 0.608 2.254 4.997 -0.541 -0.686 0.487 0.608 2.254 6.376 -0.510 -0.705 -0.493 0.610 2.251 10.256 -0.549 -0.836 0.005 0.554 2.362 1.367 -0.388 -0.917 -0.093 0.489 2.492 5.470 -0.485 -0.870 0.083 0.543 2.385 6.154 -0.506 -0.774 -0.380 -0.634 4.508 3.419 -0.211 0.977 0.020 -0.456 4.383 12.307 -0.218 0.871 0.441 -0.519 4.508 12.044 -0.263 0.805 0.532 -0.564 4.508 12.991 -0.113 0.578 -0.808 -0.519 4.508 12.854 -0.247 0.798 -0.550 -0.554 4.579 3.419 -0.413 0.911 0.016 -0.644 4.759 3.015 -0.432 0.867 0.248 -0.644 4.759 3.838 -0.456 0.851 -0.259 -0.627 4.725 7.521 -0.102 0.890 0.445 -0.644 4.759 7.462 -0.103 0.879 0.466 -0.558 4.586 8.205 -0.068 0.990 -0.125 -0.644 4.759 8.567 -0.085 0.948 -0.307 -0.644 4.759 11.763 -0.093 0.526 0.845 -0.535 4.540 12.991 -0.181 0.549 -0.816 1.952 0.000 3.108 -0.690 0.712 0.128 1.827 0.250 2.951 -0.942 -0.022 0.335 1.952 0.000 3.729 -0.707 0.696 -0.129 1.827 0.250 3.869 -0.947 -0.075 -0.312 1.952 0.000 7.365 -0.218 0.877 0.428 1.827 0.250 7.173 -0.685 0.102 0.721 1.952 0.000 8.652 -0.185 0.914 -0.361 1.827 0.250 8.760 -0.474 0.131 -0.871 1.952 0.000 11.838 -0.657 0.066 0.751 1.827 0.250 11.898 -0.691 -0.451 0.565 1.702 0.501 3.066 -0.881 -0.440 0.174 1.702 0.501 3.738 -0.875 -0.451 -0.174 1.702 0.501 7.241 -0.652 -0.432 0.623 1.702 0.501 8.723 -0.630 -0.439 -0.641 1.702 0.501 12.274 -0.605 -0.684 0.407 1.770 0.365 12.991 -0.500 -0.352 -0.791 1.702 0.501 12.410 -0.630 -0.711 0.313 1.611 0.683 3.419 -0.774 -0.633 -0.024 1.601 0.703 7.521 -0.584 -0.709 0.395 1.576 0.751 7.733 -0.553 -0.821 0.140 1.576 0.751 8.411 -0.556 -0.817 -0.150 1.693 0.519 12.307 -0.604 -0.689 0.402 1.528 0.849 8.205 -0.537 -0.839 -0.087 1.115 1.252 0.684 0.066 0.726 0.684 1.284 1.252 1.367 -0.072 0.993 -0.092 1.267 1.252 10.256 -0.387 0.922 -0.026 1.260 1.384 0.684 -0.238 0.576 0.782 1.201 1.503 0.485 -0.279 0.463 0.841 1.313 1.278 1.367 -0.178 0.979 -0.100 1.201 1.503 1.822 -0.415 0.769 -0.485 1.176 1.503 5.470 -0.351 0.925 0.145 1.074 1.503 6.154 -0.185 0.905 -0.382 1.288 1.328 10.256 -0.675 0.737 -0.029 1.201 1.503 9.879 -0.841 0.509 0.186 1.201 1.503 10.583 -0.845 0.502 -0.186 1.076 1.753 0.304 -0.379 0.069 0.923 1.076 1.753 1.935 -0.412 0.115 -0.904 1.187 1.531 5.470 -0.476 0.866 0.152 1.076 1.753 5.102 -0.748 0.554 0.365 1.134 1.637 6.154 -0.604 0.671 -0.430 1.076 1.753 6.312 -0.691 0.502 -0.520 1.076 1.753 9.734 -0.892 -0.004 0.453 1.076 1.753 10.729 -0.919 0.026 -0.394 0.950 2.004 0.378 -0.389 -0.272 0.880 0.950 2.004 1.897 -0.601 -0.442 -0.666 0.950 2.004 4.999 -0.826 0.000 0.564 0.950 2.004 6.418 -0.791 -0.064 -0.608 0.950 2.004 9.869 -0.854 -0.478 0.203 0.950 2.004 10.613 -0.873 -0.443 -0.202 0.843 2.219 0.684 -0.423 -0.491 0.762 0.825 2.254 0.823 -0.515 -0.681 0.521 0.825 2.254 1.605 -0.580 -0.798 -0.165 0.825 2.254 5.106 -0.804 -0.509 0.306 0.825 2.254 6.236 -0.726 -0.532 -0.435 0.854 2.197 10.256 -0.773 -0.635 -0.006 0.767 2.370 1.367 -0.569 -0.817 -0.094 0.719 2.466 5.470 -0.690 -0.717 0.099 0.798 2.309 6.154 -0.719 -0.569 -0.398 -0.390 4.508 12.307 -0.334 0.827 0.452 -0.480 4.759 3.419 -0.583 0.813 0.010 -0.605 4.759 7.521 -0.131 0.886 0.445 -0.447 4.759 8.205 -0.355 0.927 -0.123 -0.346 4.596 12.307 -0.535 0.717 0.447 -0.427 4.759 12.011 -0.582 0.614 0.533 -0.451 4.759 12.991 -0.358 0.421 -0.833 -0.427 4.759 12.893 -0.522 0.547 -0.655 2.167 0.000 1.367 0.938 -0.332 -0.104 2.167 0.003 1.367 0.937 -0.334 -0.104 2.169 0.000 1.358 0.938 -0.332 -0.096 2.169 0.000 1.372 0.938 -0.331 -0.105 2.069 0.000 3.419 -0.712 0.702 0.000 2.010 0.250 3.419 -0.994 0.112 -0.009 2.037 0.000 7.521 -0.286 0.873 0.394 2.028 0.250 7.521 -0.804 0.366 0.470 2.158 0.000 8.205 -0.441 0.893 -0.093 2.156 0.026 8.205 -0.550 0.830 -0.097 2.044 0.250 7.587 -0.840 0.409 0.356 2.044 0.250 8.517 -0.878 0.409 -0.248 2.169 0.000 12.303 -0.856 0.295 0.425 2.044 0.250 12.265 -0.876 -0.211 0.434 2.057 0.000 12.991 -0.503 0.130 -0.854 1.917 0.250 12.991 -0.542 -0.221 -0.811 2.169 0.000 12.317 -0.860 0.297 0.416 2.044 0.250 12.416 -0.921 -0.211 0.326 1.861 0.501 3.419 -0.952 -0.306 -0.022 1.915 0.501 7.521 -0.876 -0.164 0.453 1.919 0.501 7.530 -0.885 -0.159 0.438 1.919 0.501 8.539 -0.938 -0.203 -0.282 1.731 0.501 12.307 -0.621 -0.669 0.408 2.023 0.292 12.307 -0.869 -0.241 0.433 1.793 0.751 8.145 -0.770 -0.633 -0.083 1.793 0.751 8.229 -0.767 -0.632 -0.112 1.787 0.765 8.205 -0.763 -0.637 -0.105 1.319 1.503 0.684 -0.338 0.514 0.788 1.415 1.503 1.367 -0.639 0.760 -0.120 1.339 1.503 10.256 -0.841 0.541 -0.027 1.320 1.697 0.684 -0.570 0.225 0.790 1.292 1.753 0.624 -0.579 0.162 0.799 1.415 1.508 1.367 -0.659 0.743 -0.120 1.292 1.753 1.718 -0.916 0.269 -0.299 1.253 1.753 5.470 -0.814 0.556 0.165 1.168 1.753 6.154 -0.728 0.533 -0.431 1.282 1.753 10.256 -0.993 0.113 -0.030 1.167 2.004 0.632 -0.571 -0.164 0.804 1.167 2.004 1.728 -0.922 -0.237 -0.306 1.213 1.912 5.470 -0.963 0.222 0.153 1.167 2.004 5.386 -0.981 0.103 0.166 1.120 2.004 6.154 -0.907 0.021 -0.421 1.167 2.004 5.776 -0.995 0.094 -0.013 1.131 2.004 10.256 -0.945 -0.326 -0.025 1.144 2.051 0.684 -0.577 -0.204 0.791 1.042 2.254 1.279 -0.780 -0.626 -0.027 1.042 2.254 1.403 -0.774 -0.623 -0.109 1.042 2.254 5.467 -0.949 -0.285 0.135 0.891 2.254 6.154 -0.766 -0.503 -0.401 1.042 2.254 5.478 -0.949 -0.286 0.131 1.032 2.273 1.367 -0.771 -0.629 -0.100 1.041 2.256 5.470 -0.949 -0.287 0.134 0.790 2.755 8.205 0.949 0.285 -0.134 0.793 2.753 8.205 0.948 0.287 -0.134 0.792 2.755 8.195 0.949 0.286 -0.130 0.792 2.755 8.208 0.949 0.285 -0.135 0.768 2.755 12.307 0.724 0.567 0.393 0.801 2.736 12.307 0.713 0.581 0.392 0.792 2.755 12.271 0.714 0.575 0.399 0.792 2.755 12.396 0.741 0.594 0.313 0.623 3.006 8.205 0.983 -0.111 -0.146 0.666 3.006 7.899 0.995 -0.094 0.013 0.666 3.006 8.289 0.981 -0.103 -0.166 0.481 3.006 12.307 0.896 0.119 0.427 0.666 3.006 11.946 0.796 0.205 0.569 0.633 3.006 12.991 0.587 0.160 -0.794 0.690 2.959 12.991 0.577 0.203 -0.791 0.620 3.098 8.205 0.963 -0.222 -0.153 0.377 3.256 12.307 0.844 -0.297 0.447 0.541 3.256 11.957 0.798 -0.235 0.554 0.507 3.256 12.991 0.590 -0.171 -0.789 0.418 3.501 12.307 0.605 -0.683 0.408 0.513 3.312 12.991 0.570 -0.224 -0.790 0.025 4.258 5.470 0.775 0.624 0.106 0.047 4.245 5.470 0.763 0.637 0.106 0.040 4.258 5.446 0.767 0.632 0.112 0.040 4.258 5.529 0.770 0.633 0.083 -0.252 4.508 5.470 0.977 0.188 0.102 -0.085 4.508 5.136 0.910 0.334 0.246 -0.085 4.508 6.145 0.880 0.239 -0.410 -0.232 4.759 1.367 0.968 0.224 -0.114 -0.190 4.717 1.367 0.956 0.270 -0.117 -0.210 4.759 1.259 0.975 0.224 -0.015 -0.210 4.759 1.409 0.965 0.233 -0.124 -0.353 4.759 5.470 0.884 -0.456 0.108 -0.210 4.759 5.158 0.878 -0.409 0.248 -0.210 4.759 6.088 0.840 -0.409 -0.356 -0.295 4.759 12.307 -0.626 0.637 0.450 2.281 0.000 0.684 0.466 -0.202 0.861 2.289 0.194 0.684 0.411 -0.345 0.843 2.386 0.000 0.491 0.420 -0.181 0.889 2.129 0.250 1.367 0.697 -0.710 -0.103 2.261 0.250 0.782 0.493 -0.517 0.700 2.386 0.000 1.837 0.738 -0.364 -0.568 2.261 0.250 1.663 0.669 -0.706 -0.232 2.180 0.000 5.470 0.719 -0.686 0.108 2.268 0.236 5.470 0.407 -0.905 0.123 2.386 0.000 5.023 0.371 -0.823 0.429 2.301 0.000 6.154 0.527 -0.710 -0.467 2.336 0.101 6.154 0.457 -0.759 -0.463 2.386 0.000 6.310 0.483 -0.701 -0.525 2.187 0.250 8.205 -0.883 0.456 -0.108 2.269 0.000 10.256 0.838 -0.545 0.000 2.304 0.164 10.256 0.775 -0.632 -0.005 2.386 0.000 9.946 0.838 -0.530 0.134 2.386 0.000 10.567 0.824 -0.551 -0.133 2.171 0.000 12.307 -0.856 0.296 0.425 2.065 0.250 12.307 -0.880 -0.203 0.430 2.180 0.413 1.367 0.554 -0.827 -0.100 2.086 0.501 8.205 -0.989 -0.100 -0.109 1.809 0.751 8.205 -0.775 -0.624 -0.106 1.327 1.753 0.684 -0.590 0.171 0.789 1.457 1.753 1.367 -0.936 0.329 -0.128 1.201 2.004 0.684 -0.587 -0.160 0.794 1.352 2.004 1.367 -0.985 -0.131 -0.115 1.210 2.004 5.470 -0.983 0.111 0.146 1.066 2.254 1.367 -0.784 -0.613 -0.101 1.043 2.254 5.470 -0.949 -0.285 0.134 0.942 2.755 7.521 0.766 0.503 0.401 1.036 2.700 7.521 0.719 0.569 0.398 1.008 2.755 7.439 0.726 0.532 0.435 1.114 2.543 8.205 0.690 0.717 -0.099 1.008 2.755 8.568 0.804 0.509 -0.306 1.067 2.639 12.307 0.531 0.761 0.372 1.008 2.755 12.070 0.533 0.733 0.423 1.008 2.755 12.852 0.540 0.714 -0.445 0.703 3.006 3.419 0.945 0.326 0.025 0.980 2.813 3.419 0.773 0.634 0.006 0.883 3.006 3.062 0.873 0.443 0.202 0.883 3.006 3.806 0.854 0.478 -0.203 0.714 3.006 7.521 0.906 -0.021 0.422 0.883 3.006 7.257 0.791 0.063 0.608 0.883 3.006 8.676 0.825 0.000 -0.565 0.883 3.006 11.777 0.476 0.350 0.807 0.991 2.790 12.991 0.423 0.491 -0.762 0.552 3.256 3.419 0.993 -0.113 0.030 0.758 3.256 2.946 0.919 -0.027 0.394 0.758 3.256 3.941 0.892 0.004 -0.453 0.665 3.256 7.521 0.728 -0.533 0.431 0.758 3.256 7.363 0.691 -0.501 0.520 0.580 3.256 8.205 0.814 -0.556 -0.164 0.758 3.256 8.573 0.748 -0.554 -0.366 0.758 3.256 11.740 0.311 -0.087 0.946 0.494 3.507 3.419 0.841 -0.541 0.027 0.633 3.507 3.092 0.845 -0.502 0.186 0.633 3.507 3.796 0.841 -0.509 -0.186 0.700 3.372 7.521 0.604 -0.671 0.430 0.647 3.479 8.205 0.476 -0.866 -0.152 0.418 3.507 12.307 0.588 -0.699 0.408 0.633 3.507 11.852 0.339 -0.629 0.699 0.514 3.507 12.991 0.337 -0.514 -0.789 0.545 3.681 3.419 0.676 -0.737 0.030 0.520 3.731 12.307 0.165 -0.912 0.376 0.573 3.625 12.991 0.238 -0.576 -0.782 0.306 4.160 5.470 0.538 0.839 0.087 0.257 4.258 5.264 0.556 0.817 0.150 0.257 4.258 5.942 0.554 0.821 -0.140 0.102 4.508 1.367 0.690 0.712 -0.130 0.141 4.490 1.367 0.670 0.731 -0.129 0.132 4.508 1.264 0.678 0.734 -0.037 0.132 4.508 1.401 0.674 0.726 -0.138 0.132 4.508 4.952 0.636 0.558 0.534 -0.082 4.508 6.154 0.872 0.244 -0.424 0.233 4.306 6.154 0.582 0.722 -0.374 0.132 4.508 6.433 0.654 0.528 -0.541 -0.027 4.508 10.256 0.931 0.364 0.020 0.223 4.327 10.256 0.762 0.648 0.023 0.132 4.508 9.936 0.847 0.508 0.157 0.132 4.508 10.608 0.853 0.498 -0.157 -0.083 4.759 0.684 0.542 0.221 0.811 0.064 4.645 0.684 0.502 0.356 0.788 0.007 4.759 0.552 0.493 0.268 0.827 0.007 4.759 1.776 0.794 0.518 -0.319 0.007 4.759 4.915 0.474 -0.131 0.871 -0.195 4.759 6.154 0.803 -0.366 -0.470 0.007 4.759 6.501 0.685 -0.102 -0.722 -0.177 4.759 10.256 0.994 -0.112 0.009 0.007 4.759 9.805 0.947 0.075 0.312 0.007 4.759 10.724 0.942 0.022 -0.335 2.284 0.250 0.684 0.358 -0.421 0.833 2.603 0.000 0.262 0.290 -0.029 0.957 2.478 0.250 0.351 0.187 -0.422 0.887 2.603 0.000 1.947 0.337 0.092 -0.937 2.478 0.250 1.912 0.120 -0.675 -0.728 2.280 0.250 5.470 0.355 -0.926 0.124 2.603 0.000 4.896 -0.048 -0.582 0.812 2.478 0.250 5.108 0.085 -0.948 0.307 2.439 0.250 6.154 0.131 -0.886 -0.445 2.603 0.000 6.561 0.075 -0.700 -0.710 2.478 0.250 6.213 0.103 -0.878 -0.467 2.313 0.250 10.256 0.583 -0.813 -0.010 2.603 0.000 9.644 0.279 -0.443 0.852 2.478 0.250 9.837 0.456 -0.851 0.259 2.603 0.000 10.869 0.239 -0.497 -0.834 2.478 0.250 10.660 0.432 -0.867 -0.248 2.368 0.469 0.684 0.148 -0.587 0.796 2.223 0.501 1.367 0.243 -0.965 -0.095 2.352 0.501 0.821 0.154 -0.799 0.581 2.352 0.501 1.631 0.166 -0.967 -0.193 2.391 0.424 5.470 0.004 -0.994 0.113 2.461 0.284 6.154 0.099 -0.890 -0.444 2.388 0.430 10.256 0.328 -0.944 -0.015 2.290 0.626 1.367 0.138 -0.986 -0.092 1.291 2.624 7.521 0.507 0.774 0.380 1.225 2.755 7.299 0.510 0.705 0.493 1.344 2.517 8.205 0.485 0.871 -0.083 1.225 2.755 8.677 0.541 0.686 -0.487 1.279 2.648 12.307 0.364 0.861 0.355 1.225 2.755 12.080 0.363 0.844 0.395 1.225 2.755 12.860 0.366 0.824 -0.433 1.224 2.758 3.419 0.549 0.836 -0.005 1.100 3.006 2.884 0.636 0.595 0.492 1.100 3.006 3.966 0.589 0.640 -0.494 1.100 3.006 7.093 0.516 0.241 0.822 1.100 3.006 8.778 0.369 0.153 -0.917 1.100 3.006 11.751 0.193 0.392 0.899 1.214 2.778 12.991 0.285 0.614 -0.736 0.975 3.256 2.791 0.421 0.107 0.901 0.975 3.256 4.072 0.348 0.151 -0.925 0.975 3.256 7.113 0.413 -0.392 0.822 0.975 3.256 8.761 0.241 -0.372 -0.896 0.975 3.256 11.709 0.068 0.045 0.997 0.850 3.507 2.814 0.358 -0.367 0.858 0.850 3.507 4.060 0.302 -0.291 -0.908 0.760 3.507 7.521 0.185 -0.905 0.383 0.850 3.507 7.389 0.121 -0.888 0.443 0.657 3.507 8.205 0.351 -0.925 -0.145 0.850 3.507 8.569 0.221 -0.918 -0.329 0.850 3.507 11.731 0.049 -0.311 0.949 0.567 3.757 3.419 0.387 -0.922 0.026 0.724 3.757 3.057 0.355 -0.912 0.207 0.724 3.757 3.827 0.335 -0.917 -0.214 0.812 3.582 7.521 0.099 -0.919 0.381 0.759 3.687 8.205 0.100 -0.987 -0.123 0.549 3.757 12.307 0.067 -0.933 0.352 0.724 3.757 11.983 -0.011 -0.879 0.477 0.719 3.757 12.991 -0.066 -0.726 -0.685 0.647 3.913 3.419 0.255 -0.967 0.022 0.652 3.902 12.307 -0.029 -0.929 0.369 0.722 3.761 12.991 -0.068 -0.725 -0.685 0.511 4.184 5.470 0.370 0.926 0.074 0.474 4.258 5.302 0.378 0.919 0.116 0.474 4.258 5.845 0.366 0.928 -0.068 0.377 4.452 1.367 0.468 0.875 -0.121 0.349 4.508 1.059 0.455 0.864 0.213 0.349 4.508 1.483 0.477 0.865 -0.158 0.349 4.508 4.921 0.371 0.681 0.631 0.450 4.305 6.154 0.357 0.866 -0.349 0.349 4.508 6.495 0.378 0.724 -0.576 0.465 4.276 10.256 0.525 0.851 0.017 0.349 4.508 9.750 0.629 0.686 0.366 0.349 4.508 10.792 0.610 0.674 -0.417 0.318 4.570 0.684 0.329 0.546 0.770 0.223 4.759 0.395 0.337 0.420 0.843 0.223 4.759 1.879 0.545 0.668 -0.507 0.223 4.759 4.875 0.096 -0.022 0.995 0.223 4.759 6.622 0.416 0.284 -0.864 0.223 4.759 9.633 0.503 0.231 0.833 0.223 4.759 10.891 0.449 0.158 -0.879 2.820 0.000 0.211 0.141 0.245 0.959 2.695 0.250 0.220 -0.044 -0.377 0.925 2.820 0.000 1.960 0.176 0.256 -0.951 2.695 0.250 1.958 -0.029 -0.289 -0.957 2.820 0.000 4.877 -0.091 -0.258 0.962 2.695 0.250 4.971 -0.238 -0.836 0.494 2.820 0.000 6.624 -0.276 -0.551 -0.788 2.695 0.250 6.416 -0.230 -0.798 -0.557 2.820 0.000 9.578 0.193 -0.202 0.960 2.695 0.250 9.637 0.024 -0.637 0.770 2.820 0.000 10.935 0.159 -0.265 -0.951 2.695 0.250 10.864 -0.006 -0.696 -0.718 2.398 0.501 0.684 0.077 -0.617 0.783 2.569 0.501 0.449 -0.042 -0.555 0.831 2.569 0.501 1.856 0.021 -0.811 -0.585 2.574 0.492 5.470 -0.305 -0.948 0.089 2.617 0.406 6.154 -0.245 -0.881 -0.405 2.467 0.501 10.256 -0.019 -1.000 -0.014 2.569 0.501 10.024 -0.072 -0.996 0.061 2.569 0.501 10.466 -0.077 -0.994 -0.074 2.502 0.635 0.684 -0.058 -0.628 0.776 2.453 0.734 1.367 -0.188 -0.978 -0.084 2.525 0.589 10.256 -0.076 -0.997 -0.015 1.496 2.647 7.521 0.290 0.883 0.370 1.442 2.755 7.326 0.286 0.846 0.449 1.550 2.539 8.205 0.308 0.947 -0.086 1.442 2.755 8.663 0.239 0.852 -0.465 1.446 2.747 12.307 0.221 0.918 0.330 1.442 2.755 12.289 0.222 0.917 0.332 1.442 2.755 12.361 0.223 0.930 0.293 1.438 2.763 3.419 0.409 0.913 -0.010 1.317 3.006 2.851 0.343 0.683 0.645 1.317 3.006 3.983 0.316 0.727 -0.609 1.317 3.006 7.059 0.185 0.442 0.878 1.317 3.006 8.791 0.102 0.227 -0.968 1.317 3.006 11.792 -0.036 0.533 0.845 1.405 2.829 12.991 0.089 0.616 -0.782 1.192 3.256 2.755 0.215 0.196 0.957 1.192 3.256 4.096 0.179 0.259 -0.949 1.192 3.256 7.031 0.065 -0.220 0.973 1.192 3.256 8.791 0.000 -0.161 -0.987 1.192 3.256 11.717 -0.016 0.145 0.989 1.067 3.507 2.748 0.174 -0.154 0.973 1.008 3.507 4.102 0.181 -0.137 -0.974 1.152 3.336 4.102 0.173 0.149 -0.974 1.067 3.507 4.151 0.154 -0.116 -0.981 1.067 3.507 7.186 -0.109 -0.782 0.614 1.067 3.507 8.729 0.063 -0.649 -0.758 1.067 3.507 11.716 -0.081 -0.161 0.984 0.941 3.757 2.820 0.212 -0.566 0.796 1.037 3.565 4.102 0.131 -0.185 -0.974 0.941 3.757 4.045 0.116 -0.543 -0.832 0.971 3.698 7.521 -0.189 -0.912 0.363 0.895 3.757 8.205 -0.182 -0.979 -0.090 0.941 3.757 8.018 -0.210 -0.977 -0.026 0.941 3.757 8.275 -0.201 -0.974 -0.101 0.941 3.757 11.822 -0.122 -0.648 0.752 0.774 4.007 3.419 -0.116 -0.993 0.012 0.816 4.007 3.330 -0.130 -0.991 0.031 0.816 4.007 3.519 -0.133 -0.991 -0.011 0.925 3.790 8.205 -0.197 -0.976 -0.087 0.828 3.984 12.307 -0.242 -0.908 0.341 0.882 3.875 12.991 -0.202 -0.633 -0.747 0.800 4.040 3.419 -0.132 -0.991 0.011 0.628 4.258 5.470 0.293 0.954 0.069 0.564 4.508 1.367 0.261 0.959 -0.114 0.684 4.271 5.470 0.236 0.969 0.070 0.566 4.508 4.963 0.142 0.843 0.520 0.634 4.371 6.154 0.095 0.912 -0.398 0.566 4.508 6.401 0.066 0.844 -0.532 0.676 4.288 10.256 0.379 0.925 0.011 0.566 4.508 9.720 0.407 0.810 0.422 0.566 4.508 10.813 0.376 0.802 -0.464 0.520 4.600 0.684 0.153 0.585 0.796 0.440 4.759 0.410 0.153 0.509 0.847 0.566 4.509 1.367 0.259 0.959 -0.114 0.440 4.759 1.880 0.311 0.791 -0.527 0.440 4.759 4.876 0.037 0.202 0.979 0.440 4.759 6.623 0.098 0.575 -0.812 0.440 4.759 9.592 0.302 0.306 0.903 0.440 4.759 10.929 0.257 0.257 -0.932 3.037 0.000 0.262 0.004 0.500 0.866 2.912 0.250 0.211 -0.250 -0.210 0.945 3.037 0.000 1.955 -0.074 0.226 -0.971 2.912 0.250 1.962 -0.060 -0.021 -0.998 3.037 0.000 4.878 -0.242 -0.135 0.961 2.912 0.250 4.949 -0.474 -0.707 0.525 3.037 0.000 6.583 -0.584 -0.294 -0.757 2.912 0.250 6.435 -0.518 -0.660 -0.545 2.852 0.000 9.572 0.183 -0.225 0.957 2.957 0.159 9.572 -0.063 -0.348 0.935 3.037 0.000 9.473 -0.021 -0.244 0.970 2.912 0.250 9.589 -0.091 -0.412 0.906 2.846 0.000 10.940 0.151 -0.283 -0.947 2.966 0.141 10.940 -0.076 -0.392 -0.917 2.912 0.250 10.916 -0.107 -0.474 -0.874 3.037 0.000 11.043 -0.057 -0.297 -0.953 2.786 0.501 0.348 -0.224 -0.445 0.867 2.786 0.501 1.911 -0.248 -0.567 -0.785 2.639 0.501 5.470 -0.360 -0.929 0.088 2.786 0.501 5.365 -0.450 -0.886 0.111 2.821 0.432 6.154 -0.499 -0.777 -0.384 2.786 0.501 5.739 -0.461 -0.887 -0.009 2.786 0.501 9.761 -0.179 -0.914 0.364 2.786 0.501 10.727 -0.176 -0.927 -0.331 2.685 0.703 0.684 -0.264 -0.625 0.735 2.525 0.751 1.367 -0.291 -0.954 -0.078 2.661 0.751 1.015 -0.366 -0.905 0.216 2.661 0.751 1.518 -0.375 -0.920 -0.113 2.761 0.552 5.470 -0.447 -0.890 0.090 2.688 0.697 10.256 -0.252 -0.968 -0.017 2.627 0.820 1.367 -0.370 -0.926 -0.079 1.638 2.755 7.521 0.085 0.930 0.358 1.728 2.617 8.205 0.054 0.994 -0.091 1.659 2.755 7.561 0.053 0.951 0.304 1.659 2.755 8.502 0.038 0.978 -0.206 1.454 2.755 12.307 0.216 0.918 0.331 1.635 2.803 3.419 0.196 0.981 -0.013 1.534 3.006 2.918 0.096 0.908 0.407 1.534 3.006 3.905 0.095 0.922 -0.376 1.655 2.763 7.521 0.042 0.931 0.363 1.534 3.006 7.127 -0.164 0.636 0.754 1.534 3.006 8.768 -0.145 0.417 -0.897 1.617 2.840 12.307 -0.119 0.892 0.436 1.534 3.006 11.972 -0.175 0.817 0.550 1.543 2.987 12.991 -0.128 0.593 -0.795 1.409 3.256 2.758 0.018 0.284 0.959 1.409 3.256 4.082 0.008 0.341 -0.940 1.409 3.256 7.039 -0.316 -0.013 0.949 1.409 3.256 8.792 -0.101 -0.009 -0.995 1.409 3.256 11.749 -0.169 0.307 0.937 1.158 3.507 2.735 0.154 -0.110 0.982 1.336 3.402 2.735 0.019 0.180 0.983 1.283 3.507 2.677 -0.007 -0.016 1.000 1.357 3.359 4.102 -0.005 0.285 -0.958 1.283 3.507 4.201 -0.094 0.057 -0.994 1.283 3.507 7.133 -0.382 -0.613 0.692 1.283 3.507 8.765 -0.208 -0.430 -0.879 1.283 3.507 11.725 -0.226 -0.070 0.972 1.235 3.604 2.735 -0.025 -0.191 0.981 1.158 3.757 2.760 -0.004 -0.302 0.953 1.193 3.687 4.102 -0.089 -0.262 -0.961 1.158 3.757 4.091 -0.073 -0.311 -0.948 1.166 3.741 7.521 -0.395 -0.850 0.349 1.158 3.757 7.601 -0.386 -0.888 0.248 1.158 3.757 8.496 -0.334 -0.922 -0.196 1.158 3.757 11.796 -0.358 -0.494 0.793 1.033 4.007 2.992 -0.208 -0.953 0.219 1.033 4.007 3.866 -0.229 -0.947 -0.224 1.087 3.898 8.205 -0.321 -0.943 -0.085 0.960 4.007 12.307 -0.357 -0.878 0.320 1.033 4.007 12.240 -0.394 -0.854 0.340 1.085 3.903 12.991 -0.330 -0.516 -0.790 1.033 4.007 12.437 -0.412 -0.885 0.216 0.952 4.170 3.419 -0.239 -0.971 0.007 1.018 4.037 12.307 -0.390 -0.860 0.330 0.857 4.359 5.470 -0.106 0.991 0.084 0.782 4.508 5.141 -0.179 0.948 0.262 0.749 4.508 6.154 -0.147 0.887 -0.437 0.782 4.508 6.070 -0.213 0.920 -0.328 0.867 4.340 10.256 0.156 0.988 0.007 0.782 4.508 9.809 0.151 0.950 0.274 0.782 4.508 10.717 0.128 0.950 -0.283 0.679 4.715 0.684 -0.039 0.552 0.833 0.657 4.759 0.606 -0.041 0.539 0.841 0.756 4.561 1.367 0.044 0.994 -0.096 0.657 4.759 1.788 0.025 0.927 -0.374 0.657 4.759 4.902 -0.016 0.596 0.803 0.772 4.530 6.154 -0.222 0.867 -0.445 0.657 4.759 6.506 -0.257 0.700 -0.666 0.657 4.759 9.588 0.166 0.444 0.880 0.657 4.759 10.929 0.127 0.415 -0.901 3.254 0.000 0.491 -0.112 0.577 0.809 3.128 0.250 0.320 -0.405 0.009 0.914 3.254 0.000 1.874 -0.144 0.832 -0.536 3.128 0.250 1.941 -0.373 -0.003 -0.928 3.254 0.000 4.947 -0.696 0.015 0.718 3.128 0.250 5.014 -0.719 -0.584 0.376 3.254 0.000 6.375 -0.792 0.045 -0.609 3.128 0.250 6.279 -0.740 -0.470 -0.480 3.190 0.126 9.572 -0.207 -0.106 0.973 3.254 0.000 9.534 -0.163 0.097 0.982 3.128 0.250 9.582 -0.252 -0.307 0.918 3.195 0.117 10.940 -0.203 -0.104 -0.974 3.128 0.250 10.928 -0.254 -0.344 -0.904 3.254 0.000 10.981 -0.159 0.106 -0.981 3.003 0.501 0.406 -0.394 -0.286 0.874 3.003 0.501 1.890 -0.588 -0.497 -0.638 3.003 0.501 5.406 -0.616 -0.781 0.107 3.079 0.350 6.154 -0.726 -0.538 -0.428 3.003 0.501 5.617 -0.627 -0.778 0.038 3.003 0.501 9.701 -0.420 -0.735 0.533 3.003 0.501 10.796 -0.408 -0.766 -0.497 2.906 0.695 0.684 -0.422 -0.487 0.765 2.878 0.751 0.939 -0.535 -0.773 0.341 2.878 0.751 1.559 -0.553 -0.821 -0.139 2.987 0.533 5.470 -0.613 -0.784 0.093 2.889 0.730 10.256 -0.452 -0.892 -0.013 2.832 0.843 1.367 -0.545 -0.834 -0.086 1.820 2.755 8.205 -0.087 0.991 -0.097 1.787 2.933 3.419 -0.001 1.000 -0.010 1.751 3.006 3.231 0.000 0.999 0.047 1.751 3.006 3.594 0.005 0.998 -0.057 1.791 2.926 7.521 -0.423 0.794 0.436 1.751 3.006 7.393 -0.459 0.740 0.492 1.857 2.793 8.205 -0.271 0.957 -0.107 1.751 3.006 8.619 -0.462 0.794 -0.394 1.703 3.006 12.307 -0.286 0.850 0.442 1.553 3.006 12.991 -0.137 0.590 -0.796 1.626 3.256 2.809 -0.183 0.520 0.834 1.626 3.256 4.026 -0.168 0.561 -0.811 1.626 3.256 7.162 -0.659 0.188 0.728 1.626 3.256 8.757 -0.402 0.217 -0.889 1.725 3.057 12.307 -0.468 0.753 0.463 1.626 3.256 11.951 -0.593 0.535 0.602 1.632 3.243 12.991 -0.430 0.332 -0.840 1.407 3.507 2.735 -0.151 0.086 0.985 1.500 3.507 2.747 -0.171 0.128 0.977 1.460 3.507 4.102 -0.195 0.136 -0.971 1.500 3.507 4.096 -0.191 0.149 -0.970 1.500 3.507 7.206 -0.660 -0.383 0.647 1.500 3.507 8.742 -0.564 -0.344 -0.750 1.500 3.507 11.813 -0.563 0.089 0.821 1.375 3.757 2.753 -0.218 -0.203 0.955 1.375 3.757 4.091 -0.232 -0.193 -0.953 1.386 3.734 7.521 -0.582 -0.704 0.407 1.375 3.757 7.588 -0.568 -0.764 0.306 1.375 3.757 8.531 -0.558 -0.794 -0.241 1.375 3.757 11.871 -0.627 -0.369 0.686 1.250 4.007 2.893 -0.407 -0.808 0.426 1.250 4.007 3.954 -0.421 -0.798 -0.431 1.290 3.927 8.205 -0.515 -0.853 -0.083 1.250 4.007 12.245 -0.554 -0.732 0.397 1.343 3.821 12.991 -0.439 -0.295 -0.848 1.250 4.007 12.419 -0.583 -0.765 0.273 1.145 4.217 3.419 -0.417 -0.909 0.003 1.235 4.038 12.307 -0.550 -0.741 0.385 0.955 4.508 5.470 -0.284 0.955 0.087 1.009 4.489 10.256 -0.175 0.985 0.003 0.999 4.508 10.198 -0.172 0.985 0.022 0.999 4.508 10.316 -0.174 0.985 -0.016 0.710 4.759 0.684 -0.059 0.548 0.834 0.900 4.707 1.367 -0.276 0.957 -0.091 0.874 4.759 1.167 -0.287 0.946 0.148 0.874 4.759 1.479 -0.289 0.948 -0.134 0.981 4.546 5.470 -0.404 0.911 0.086 0.874 4.759 5.075 -0.535 0.768 0.352 0.870 4.759 6.154 -0.561 0.668 -0.490 0.874 4.759 6.140 -0.574 0.672 -0.467 0.874 4.759 9.635 0.022 0.710 0.704 0.874 4.759 10.879 0.002 0.701 -0.713 3.368 0.000 0.684 -0.153 0.559 0.815 3.358 0.226 0.684 -0.449 0.190 0.873 3.345 0.250 0.659 -0.460 0.165 0.872 3.471 0.000 1.040 -0.365 0.877 0.313 3.471 0.000 1.559 -0.369 0.918 -0.143 3.345 0.250 1.783 -0.879 0.245 -0.408 3.471 0.000 5.233 -0.939 0.280 0.200 3.345 0.250 5.261 -0.914 -0.374 0.159 3.386 0.000 6.154 -0.832 0.143 -0.536 3.220 0.250 6.154 -0.789 -0.418 -0.451 3.471 0.000 5.871 -0.943 0.291 -0.162 3.345 0.250 5.840 -0.933 -0.342 -0.110 3.295 0.000 9.572 -0.183 0.118 0.976 3.471 0.000 9.632 -0.379 0.423 0.823 3.345 0.250 9.622 -0.529 -0.271 0.804 3.298 0.000 10.940 -0.179 0.132 -0.975 3.471 0.000 10.881 -0.368 0.439 -0.820 3.345 0.250 10.890 -0.525 -0.283 -0.803 3.220 0.501 0.675 -0.531 -0.151 0.834 3.220 0.501 1.747 -0.885 -0.333 -0.325 3.068 0.501 5.470 -0.653 -0.752 0.092 3.267 0.407 5.470 -0.859 -0.504 0.089 3.220 0.501 9.759 -0.692 -0.634 0.346 3.220 0.501 10.745 -0.680 -0.652 -0.336 3.216 0.509 0.684 -0.532 -0.157 0.832 3.095 0.751 1.341 -0.735 -0.675 -0.071 3.095 0.751 1.379 -0.732 -0.674 -0.095 3.111 0.719 10.256 -0.628 -0.778 -0.009 3.092 0.758 1.367 -0.731 -0.676 -0.092 2.841 1.252 8.205 0.961 0.254 -0.113 2.847 1.247 8.205 0.959 0.260 -0.113 2.844 1.252 8.185 0.961 0.256 -0.105 2.844 1.252 8.212 0.960 0.255 -0.115 2.692 1.503 8.205 0.981 -0.155 -0.119 2.719 1.503 8.047 0.987 -0.153 -0.046 2.719 1.503 8.264 0.980 -0.149 -0.135 2.692 1.556 8.205 0.968 -0.219 -0.122 1.831 3.006 3.419 -0.032 0.999 -0.008 1.823 3.006 7.521 -0.488 0.752 0.443 1.947 3.006 8.205 -0.593 0.797 -0.118 1.919 3.102 3.419 -0.447 0.895 -0.006 1.842 3.256 3.062 -0.554 0.812 0.181 1.842 3.256 3.769 -0.539 0.823 -0.178 1.836 3.256 7.521 -0.842 0.296 0.451 1.949 3.042 8.205 -0.711 0.693 -0.118 1.842 3.256 7.547 -0.861 0.307 0.406 1.842 3.256 8.526 -0.901 0.349 -0.257 1.792 3.256 12.307 -0.662 0.572 0.484 1.636 3.256 12.991 -0.433 0.325 -0.841 1.717 3.507 2.827 -0.523 0.354 0.775 1.717 3.507 4.014 -0.507 0.372 -0.778 1.795 3.351 7.521 -0.878 0.119 0.464 1.717 3.507 7.489 -0.867 -0.157 0.472 1.717 3.507 8.584 -0.931 -0.126 -0.341 1.771 3.400 12.307 -0.825 0.318 0.467 1.717 3.507 12.176 -0.856 0.202 0.476 1.622 3.507 12.991 -0.495 0.059 -0.867 1.717 3.507 12.570 -0.971 0.216 0.100 1.592 3.757 2.803 -0.553 -0.129 0.823 1.592 3.757 4.041 -0.542 -0.123 -0.831 1.700 3.541 7.521 -0.863 -0.199 0.464 1.592 3.757 7.870 -0.805 -0.588 0.081 1.592 3.757 8.381 -0.800 -0.578 -0.164 1.592 3.757 12.155 -0.845 -0.162 0.510 1.438 3.757 12.991 -0.461 -0.233 -0.856 1.592 3.757 12.588 -0.978 -0.204 0.051 1.467 4.007 2.943 -0.683 -0.657 0.317 1.467 4.007 3.901 -0.684 -0.656 -0.319 1.538 3.865 8.205 -0.760 -0.643 -0.092 1.314 4.007 12.307 -0.595 -0.697 0.400 1.523 3.895 12.307 -0.816 -0.335 0.470 1.364 4.214 3.419 -0.601 -0.799 0.002 1.024 4.508 10.256 -0.180 0.984 0.003 0.934 4.759 1.367 -0.294 0.952 -0.091 1.068 4.759 5.470 -0.616 0.782 0.091 1.159 4.622 10.256 -0.443 0.897 0.001 1.091 4.759 9.895 -0.468 0.865 0.184 1.091 4.759 10.618 -0.472 0.862 -0.183 3.359 0.250 0.684 -0.461 0.168 0.872 3.563 0.000 1.367 -0.398 0.914 -0.077 3.550 0.250 1.367 -0.919 0.382 -0.097 3.586 0.000 5.470 -0.934 0.345 0.094 3.461 0.250 5.470 -0.947 -0.309 0.083 3.687 0.000 9.984 -0.706 0.699 0.115 3.562 0.250 9.830 -0.962 -0.120 0.245 3.687 0.000 10.529 -0.703 0.702 -0.114 3.562 0.250 10.683 -0.962 -0.119 -0.247 3.225 0.501 0.684 -0.532 -0.150 0.834 3.429 0.501 1.367 -0.978 -0.187 -0.092 3.437 0.501 10.031 -0.889 -0.451 0.083 3.437 0.501 10.479 -0.886 -0.456 -0.084 3.103 0.751 1.367 -0.736 -0.671 -0.092 3.383 0.610 10.256 -0.855 -0.519 -0.003 3.079 1.002 3.419 0.885 0.465 -0.015 3.241 0.894 3.419 0.816 0.578 -0.009 3.187 1.002 3.186 0.848 0.524 0.077 3.187 1.002 3.634 0.855 0.511 -0.090 2.873 1.252 3.419 0.999 0.018 -0.028 3.061 1.252 2.945 0.935 0.113 0.336 3.061 1.252 3.850 0.949 0.079 -0.306 2.995 1.252 7.521 0.796 0.446 0.409 3.091 1.193 7.521 0.746 0.528 0.406 3.061 1.252 7.434 0.756 0.480 0.445 3.176 1.024 8.205 0.709 0.700 -0.090 3.061 1.252 8.590 0.819 0.471 -0.328 2.792 1.503 3.419 0.915 -0.403 -0.028 2.936 1.503 3.029 0.901 -0.383 0.206 2.936 1.503 3.759 0.903 -0.380 -0.201 2.798 1.503 7.521 0.890 -0.094 0.446 2.936 1.503 7.292 0.818 -0.029 0.574 2.936 1.503 8.681 0.830 -0.042 -0.556 2.934 1.503 12.307 0.877 0.034 0.479 2.939 1.497 12.307 0.877 0.041 0.479 2.936 1.503 12.303 0.877 0.034 0.479 2.936 1.503 12.324 0.885 0.035 0.465 2.833 1.709 3.419 0.708 -0.706 -0.030 2.783 1.753 7.521 0.656 -0.609 0.445 2.811 1.753 7.472 0.650 -0.602 0.463 2.653 1.753 8.205 0.767 -0.629 -0.126 2.811 1.753 8.548 0.731 -0.609 -0.308 2.932 1.511 12.307 0.877 0.025 0.480 2.795 1.786 7.521 0.630 -0.637 0.444 2.718 1.940 8.205 0.514 -0.850 -0.116 2.267 2.755 0.684 0.532 0.269 0.803 2.333 2.709 0.684 0.512 0.319 0.797 2.310 2.755 0.623 0.507 0.283 0.814 2.105 2.755 1.367 0.966 0.228 -0.118 2.419 2.537 1.367 0.689 0.718 -0.103 2.310 2.755 1.729 0.829 0.465 -0.310 2.083 3.006 0.684 0.550 -0.073 0.832 2.185 3.006 0.501 0.502 -0.043 0.864 1.973 3.006 1.367 0.980 -0.164 -0.110 2.185 3.006 1.819 0.870 -0.058 -0.489 2.042 3.006 10.256 0.963 0.270 -0.011 2.277 2.821 10.256 0.818 0.575 -0.018 2.185 3.006 9.930 0.916 0.368 0.157 2.185 3.006 10.563 0.910 0.383 -0.157 2.076 3.224 0.684 0.460 -0.305 0.834 1.919 3.256 1.367 0.817 -0.564 -0.115 2.059 3.256 0.728 0.495 -0.391 0.776 2.059 3.256 1.682 0.784 -0.563 -0.261 1.981 3.256 3.419 -0.576 0.818 -0.001 1.989 3.256 8.205 -0.912 0.393 -0.117 1.897 3.256 10.256 0.990 -0.138 -0.001 2.059 3.256 9.837 0.961 -0.089 0.263 2.059 3.256 10.669 0.964 -0.061 -0.257 1.967 3.441 1.367 0.626 -0.772 -0.111 1.990 3.396 3.419 -0.859 0.512 0.002 1.934 3.507 3.210 -0.912 0.402 0.077 1.934 3.507 3.630 -0.910 0.408 -0.074 1.737 3.507 7.521 -0.874 -0.150 0.463 1.908 3.507 8.205 -0.993 0.018 -0.115 1.863 3.507 10.256 0.867 -0.498 0.004 1.934 3.507 10.062 0.869 -0.489 0.071 1.934 3.507 10.453 0.872 -0.484 -0.067 1.778 3.507 12.307 -0.864 0.218 0.455 1.809 3.757 3.038 -0.978 0.005 0.210 1.809 3.757 3.807 -0.977 0.007 -0.212 1.709 3.757 8.205 -0.869 -0.485 -0.102 1.886 3.602 10.256 0.820 -0.572 0.004 1.670 3.757 12.307 -0.867 -0.132 0.481 1.684 4.007 3.221 -0.895 -0.440 0.077 1.684 4.007 3.621 -0.894 -0.442 -0.073 1.633 4.109 3.419 -0.854 -0.521 0.003 1.227 4.759 10.256 -0.513 0.858 0.000 3.783 0.000 10.256 -0.342 0.940 0.000 3.725 0.250 10.256 -1.000 -0.029 0.003 3.535 0.501 10.256 -0.897 -0.443 0.000 3.504 0.801 3.419 0.630 0.776 -0.002 3.403 1.002 2.944 0.692 0.663 0.284 3.403 1.002 3.880 0.712 0.644 -0.280 3.308 1.002 8.205 0.583 0.809 -0.078 3.417 0.976 8.205 0.519 0.852 -0.072 3.403 1.002 8.095 0.518 0.855 -0.038 3.403 1.002 8.260 0.521 0.850 -0.085 3.278 1.252 2.782 0.516 0.216 0.829 3.278 1.252 4.034 0.605 0.172 -0.778 3.349 1.110 7.521 0.538 0.748 0.388 3.278 1.252 7.279 0.563 0.657 0.502 3.278 1.252 8.701 0.588 0.608 -0.533 3.162 1.252 12.307 0.753 0.492 0.437 3.326 1.156 12.307 0.695 0.590 0.412 3.278 1.252 12.145 0.707 0.544 0.452 3.278 1.252 12.708 0.750 0.643 -0.152 3.153 1.503 2.778 0.443 -0.193 0.876 3.153 1.503 4.025 0.561 -0.256 -0.787 3.153 1.503 7.096 0.631 0.155 0.760 3.153 1.503 8.787 0.429 0.124 -0.895 3.153 1.503 11.902 0.751 0.163 0.640 3.027 1.503 12.991 0.606 0.128 -0.785 3.231 1.347 12.991 0.519 0.340 -0.785 2.837 1.753 3.419 0.539 -0.842 -0.029 3.028 1.753 2.937 0.406 -0.838 0.364 3.028 1.753 3.852 0.429 -0.842 -0.327 3.028 1.753 7.151 0.489 -0.482 0.727 3.028 1.753 8.765 0.457 -0.389 -0.800 2.841 1.753 12.307 0.788 -0.339 0.514 3.028 1.753 11.926 0.675 -0.284 0.681 2.926 1.753 12.991 0.534 -0.243 -0.810 2.929 1.951 3.419 0.207 -0.978 -0.024 2.905 2.000 7.521 0.121 -0.918 0.376 2.750 2.004 8.205 0.228 -0.968 -0.103 2.902 2.004 7.539 0.112 -0.931 0.348 2.902 2.004 8.509 0.143 -0.963 -0.230 2.882 2.004 12.307 0.363 -0.786 0.500 2.902 2.004 12.265 0.357 -0.784 0.508 2.953 1.903 12.991 0.429 -0.408 -0.806 2.902 2.004 12.463 0.399 -0.855 0.331 2.833 2.143 8.205 0.105 -0.990 -0.095 2.891 2.026 12.307 0.352 -0.793 0.497 2.597 2.616 0.684 0.375 0.536 0.756 2.527 2.755 0.453 0.379 0.429 0.820 2.647 2.514 1.367 0.462 0.883 -0.085 2.527 2.755 1.846 0.588 0.646 -0.486 2.443 2.755 5.470 0.803 0.582 0.128 2.559 2.690 5.470 0.743 0.659 0.121 2.527 2.755 5.356 0.763 0.629 0.151 2.527 2.755 5.813 0.771 0.636 -0.044 2.523 2.755 10.256 0.563 0.827 -0.014 2.527 2.754 10.256 0.561 0.828 -0.014 2.527 2.755 10.253 0.561 0.828 -0.013 2.527 2.755 10.259 0.561 0.828 -0.014 2.402 3.006 0.273 0.423 0.083 0.902 2.402 3.006 1.940 0.490 0.111 -0.865 2.198 3.006 5.470 0.990 0.054 0.127 2.402 3.006 5.079 0.912 0.226 0.343 2.329 3.006 6.154 0.877 0.111 -0.468 2.466 2.878 6.154 0.822 0.356 -0.445 2.402 3.006 6.270 0.842 0.156 -0.517 2.402 3.006 9.717 0.698 0.537 0.473 2.402 3.006 10.778 0.716 0.552 -0.428 2.070 3.256 0.684 0.437 -0.349 0.829 2.276 3.256 0.330 0.345 -0.280 0.896 2.276 3.256 1.914 0.522 -0.384 -0.762 2.099 3.256 5.470 0.938 -0.326 0.117 2.276 3.256 5.086 0.886 -0.284 0.367 2.243 3.256 6.154 0.784 -0.356 -0.509 2.276 3.256 6.216 0.773 -0.346 -0.532 2.276 3.256 9.632 0.568 0.061 0.821 2.276 3.256 10.877 0.595 0.099 -0.798 2.158 3.492 0.684 0.147 -0.561 0.815 1.988 3.507 1.367 0.390 -0.915 -0.105 2.151 3.507 0.732 0.142 -0.647 0.749 2.151 3.507 1.698 0.290 -0.920 -0.264 2.011 3.507 3.419 -0.808 0.589 0.005 2.114 3.507 5.470 0.554 -0.825 0.115 2.151 3.507 5.388 0.542 -0.828 0.142 2.252 3.306 6.154 0.753 -0.411 -0.515 2.151 3.507 5.635 0.545 -0.838 0.032 2.151 3.507 9.668 0.607 -0.383 0.696 2.151 3.507 10.848 0.613 -0.359 -0.704 2.069 3.671 1.367 0.204 -0.974 -0.094 1.956 3.757 3.419 -0.994 0.107 0.011 2.128 3.552 5.470 0.527 -0.842 0.112 1.916 3.757 10.256 0.356 -0.935 0.005 2.026 3.757 9.970 0.322 -0.938 0.128 2.026 3.757 10.549 0.324 -0.938 -0.126 1.770 4.007 3.419 -0.906 -0.424 0.004 1.966 3.876 10.256 0.277 -0.961 0.004 3.724 0.795 3.419 0.409 0.913 0.000 3.620 1.002 2.900 0.413 0.819 0.399 3.620 1.002 3.932 0.421 0.814 -0.401 3.540 1.002 8.205 0.389 0.919 -0.069 3.495 1.252 2.748 0.214 0.259 0.942 3.495 1.252 4.079 0.238 0.223 -0.945 3.556 1.130 7.521 0.227 0.885 0.406 3.495 1.252 7.300 0.217 0.844 0.491 3.618 1.007 8.205 0.295 0.953 -0.068 3.495 1.252 8.700 0.150 0.772 -0.618 3.576 1.091 12.307 0.517 0.762 0.389 3.495 1.252 11.998 0.537 0.694 0.480 3.495 1.252 12.935 0.422 0.639 -0.643 3.314 1.503 2.735 0.226 -0.079 0.971 3.429 1.384 2.735 0.213 0.093 0.973 3.370 1.503 2.689 0.206 -0.063 0.977 3.370 1.503 4.091 0.239 -0.111 -0.965 3.370 1.503 7.050 0.222 0.394 0.892 3.370 1.503 8.795 -0.070 0.231 -0.970 3.370 1.503 11.769 0.491 0.275 0.827 3.488 1.267 12.991 0.374 0.542 -0.753 3.337 1.568 2.735 0.167 -0.139 0.976 3.245 1.753 2.775 0.153 -0.428 0.891 3.245 1.753 4.036 0.300 -0.448 -0.842 3.245 1.753 7.040 0.200 -0.297 0.934 3.245 1.753 8.803 -0.085 -0.161 -0.983 3.245 1.753 11.747 0.428 -0.115 0.897 2.989 2.004 3.419 -0.025 -1.000 -0.017 3.119 2.004 3.131 -0.079 -0.993 0.092 3.119 2.004 3.680 -0.060 -0.993 -0.101 2.908 2.004 7.521 0.105 -0.922 0.373 3.119 2.004 7.240 0.009 -0.836 0.549 3.119 2.004 8.715 0.151 -0.757 -0.636 3.119 2.004 11.862 0.377 -0.605 0.701 2.968 2.004 12.991 0.273 -0.569 -0.776 3.067 2.109 3.419 -0.074 -0.997 -0.012 3.042 2.159 7.521 -0.037 -0.924 0.379 3.000 2.243 8.205 -0.172 -0.982 -0.081 3.005 2.233 12.307 0.087 -0.908 0.409 3.048 2.147 12.991 0.148 -0.618 -0.772 2.804 2.635 0.684 0.177 0.644 0.744 2.744 2.755 0.461 0.168 0.578 0.798 2.852 2.538 1.367 0.239 0.967 -0.089 2.744 2.755 1.833 0.137 0.858 -0.495 2.806 2.631 5.470 0.529 0.843 0.100 2.744 2.755 5.215 0.566 0.805 0.179 2.744 2.755 6.110 0.518 0.805 -0.291 2.542 2.755 10.256 0.548 0.837 -0.013 2.618 3.006 0.216 0.153 0.235 0.960 2.618 3.006 1.956 -0.027 0.218 -0.976 2.618 3.006 4.939 0.648 0.391 0.653 2.739 2.765 6.154 0.521 0.775 -0.357 2.618 3.006 6.485 0.660 0.394 -0.640 2.741 2.760 10.256 0.378 0.926 -0.006 2.618 3.006 9.681 0.318 0.675 0.665 2.618 3.006 10.825 0.384 0.679 -0.626 2.493 3.256 0.203 0.159 -0.172 0.972 2.493 3.256 1.954 -0.106 -0.178 -0.978 2.493 3.256 4.907 0.572 -0.101 0.814 2.493 3.256 6.537 0.673 -0.157 -0.723 2.493 3.256 9.589 0.214 0.174 0.961 2.493 3.256 10.924 0.268 0.195 -0.943 2.169 3.507 0.684 0.112 -0.580 0.807 2.368 3.507 0.401 0.049 -0.524 0.851 2.368 3.507 1.885 0.236 -0.664 -0.709 2.368 3.507 4.997 0.535 -0.665 0.522 2.264 3.507 6.154 0.452 -0.746 -0.490 2.368 3.507 6.336 0.414 -0.719 -0.558 2.368 3.507 9.587 0.224 -0.156 0.962 2.368 3.507 10.930 0.247 -0.142 -0.958 2.290 3.662 0.684 -0.002 -0.595 0.804 2.209 3.757 1.367 -0.153 -0.986 -0.072 2.243 3.757 1.263 -0.168 -0.986 0.009 2.243 3.757 1.421 -0.171 -0.982 -0.082 2.239 3.757 5.470 0.082 -0.993 0.083 2.243 3.757 5.462 0.080 -0.993 0.085 2.314 3.615 6.154 0.356 -0.801 -0.481 2.243 3.757 5.485 0.080 -0.994 0.078 2.243 3.757 9.665 0.368 -0.591 0.717 2.243 3.757 10.853 0.353 -0.589 -0.727 2.230 3.783 1.367 -0.166 -0.984 -0.071 2.241 3.761 5.470 0.080 -0.993 0.083 2.105 4.007 10.256 -0.098 -0.995 0.002 2.118 4.007 10.226 -0.103 -0.995 0.009 2.118 4.007 10.287 -0.103 -0.995 -0.004 2.112 4.019 10.256 -0.103 -0.995 0.002 surface_Al2O3_2 922 1037 4 1 3 4 2 4 1 5 6 2 5 7 9 4 3 8 5 7 10 6 5 8 3 11 12 13 5 11 16 15 14 12 4 14 17 18 15 4 19 21 22 20 5 23 25 20 19 24 5 7 9 28 27 26 5 7 10 30 29 26 5 11 13 32 33 31 3 11 31 16 4 17 34 35 18 4 21 36 37 22 3 23 38 25 4 27 39 40 28 4 29 41 42 30 4 43 32 33 44 4 43 45 46 44 4 34 47 48 35 4 36 49 50 37 4 51 39 40 52 4 51 41 42 52 4 53 45 46 54 4 53 47 48 54 5 55 57 50 49 56 5 55 60 59 58 56 3 55 61 57 3 55 61 60 3 62 63 64 5 62 67 66 65 63 4 65 68 69 66 4 70 72 73 71 4 70 74 75 71 3 76 77 78 3 76 77 79 5 62 64 81 82 80 3 62 80 67 4 68 83 84 69 4 72 85 86 73 4 87 74 75 88 4 87 89 90 88 5 76 78 92 93 91 5 76 79 94 95 91 5 96 98 81 82 97 3 96 97 99 4 83 100 101 84 4 85 102 103 86 4 89 104 105 90 5 106 108 93 92 107 5 106 109 95 94 107 3 96 110 98 5 96 99 112 111 110 4 111 100 101 112 5 113 115 103 102 114 5 113 118 117 116 114 4 116 104 105 117 5 106 108 121 120 119 5 106 109 123 122 119 3 113 124 115 3 113 124 118 5 125 127 121 120 126 5 125 128 123 122 126 3 125 129 127 3 125 129 128 3 130 2 4 3 130 2 6 5 130 4 9 132 131 5 130 6 10 133 131 3 134 15 16 3 134 15 18 3 135 20 22 3 135 20 25 4 9 28 136 132 4 10 30 137 133 3 138 31 33 5 138 139 134 16 31 4 134 18 35 139 5 135 22 37 141 140 6 135 140 143 142 38 25 4 28 40 144 136 4 30 42 145 137 3 138 44 33 6 138 44 46 147 146 139 5 139 35 48 148 146 4 37 50 149 141 3 142 150 143 4 52 40 144 151 4 52 42 145 151 4 54 46 147 152 4 54 48 148 152 4 50 57 153 149 4 59 60 155 154 4 61 57 153 156 4 61 60 155 156 3 157 66 67 3 157 66 69 3 158 71 73 3 158 71 75 3 159 80 82 5 159 160 157 67 80 4 157 69 84 160 5 158 73 86 162 161 6 158 161 164 163 88 75 3 163 88 90 3 165 91 93 3 165 91 95 3 159 97 82 6 159 97 99 167 166 160 5 160 84 101 168 166 4 86 103 169 162 3 163 170 164 5 163 90 105 171 170 5 165 93 108 173 172 5 165 95 109 174 172 4 112 99 167 175 4 112 101 168 175 4 103 115 176 169 4 117 118 178 177 4 117 105 171 177 4 108 121 179 173 4 109 123 180 174 4 124 115 176 181 4 124 118 178 181 4 121 127 182 179 4 123 128 183 180 4 129 127 182 184 4 129 128 183 184 3 185 131 132 3 185 131 133 4 185 132 136 186 4 185 133 137 186 3 187 140 141 3 187 140 143 4 186 136 144 188 4 186 137 145 188 3 189 146 147 3 189 146 148 5 187 141 149 191 190 6 187 190 193 192 150 143 3 188 151 144 3 188 151 145 3 189 152 147 3 189 152 148 5 194 153 149 191 195 6 194 195 193 192 154 155 3 194 156 153 3 194 156 155 3 196 161 162 3 196 161 164 3 197 166 167 3 197 166 168 5 196 162 169 199 198 6 196 198 201 200 170 164 3 200 170 171 3 202 172 173 3 202 172 174 3 197 175 167 3 197 175 168 5 203 176 169 199 204 6 203 204 201 200 177 178 3 200 177 171 4 202 173 179 205 4 202 174 180 205 3 203 181 176 3 203 181 178 4 205 179 182 206 4 205 180 183 206 3 206 184 182 3 206 184 183 3 207 208 209 3 207 208 210 3 211 212 213 3 211 212 214 4 211 213 216 215 4 211 214 217 215 3 215 218 216 3 215 218 217 3 219 190 191 3 219 190 193 3 219 195 191 3 219 195 193 3 220 198 199 3 220 198 201 3 220 204 199 3 220 204 201 3 221 222 223 3 221 222 224 4 221 223 226 225 4 221 224 227 225 3 228 229 230 3 228 229 231 5 232 234 233 209 208 5 232 236 235 210 208 3 237 238 239 3 237 238 240 3 241 242 243 3 241 242 244 3 232 245 234 3 232 245 236 3 246 247 248 3 246 247 249 3 250 251 252 3 250 251 253 5 246 248 254 213 212 5 246 249 255 214 212 4 250 252 257 256 4 250 253 258 256 3 259 260 261 3 259 260 262 4 213 216 263 254 4 214 217 264 255 3 256 265 257 3 256 265 258 4 259 261 267 266 4 259 262 268 266 5 269 270 263 216 218 5 269 271 264 217 218 4 266 267 273 272 4 266 268 274 272 3 269 275 270 3 269 275 271 3 272 276 273 3 272 276 274 4 222 223 278 277 4 222 224 279 277 3 280 281 282 3 280 281 283 4 223 226 284 278 4 224 227 285 279 3 286 287 288 3 286 287 289 5 280 282 290 230 229 5 280 283 291 231 229 5 292 233 234 294 293 5 292 235 236 295 293 3 296 297 298 6 296 297 300 299 238 239 5 299 302 301 240 238 5 303 305 304 243 242 6 303 242 244 306 307 308 4 245 234 294 309 4 245 236 295 309 3 299 310 300 3 299 310 302 3 303 311 305 3 303 311 308 3 312 247 248 3 312 247 249 4 251 252 314 313 4 251 253 315 313 5 312 248 254 317 316 5 312 249 255 318 316 3 319 320 321 5 319 257 252 314 320 4 253 258 322 315 4 260 261 324 323 5 325 326 323 260 262 3 325 326 327 4 254 263 328 317 4 255 264 329 318 4 319 321 331 330 5 319 257 265 332 330 5 332 333 322 258 265 4 261 267 334 324 4 325 262 268 335 4 325 327 336 335 4 263 270 337 328 4 264 271 338 329 3 330 339 331 4 330 339 340 332 3 332 340 333 4 267 273 341 334 4 335 268 274 342 4 335 336 343 342 5 344 345 337 270 275 5 344 346 338 271 275 4 276 273 341 347 5 342 348 347 276 274 3 342 348 343 3 344 349 345 3 344 349 346 4 277 278 351 350 4 277 279 352 350 4 281 282 354 353 4 281 283 355 353 4 278 284 356 351 4 279 285 357 352 4 287 288 359 358 4 287 289 360 358 4 282 290 361 354 5 362 291 283 355 363 5 364 365 366 294 293 5 364 367 368 295 293 5 369 371 370 298 297 3 369 297 300 4 301 302 373 372 4 304 305 375 374 4 307 308 377 376 5 378 379 366 294 309 5 378 380 368 295 309 3 369 381 371 6 369 381 383 382 310 300 5 382 384 373 302 310 4 311 305 375 385 4 311 308 377 385 3 378 386 379 3 378 386 380 3 382 387 383 3 382 387 384 4 313 314 389 388 4 313 315 390 388 4 316 317 392 391 4 316 318 393 391 4 320 321 395 394 4 320 314 389 394 4 315 322 396 390 4 323 324 398 397 5 399 400 397 323 326 3 399 326 327 4 317 328 401 392 4 318 329 402 393 4 321 331 403 395 4 322 333 404 396 4 324 334 405 398 3 399 406 400 5 399 327 336 407 406 4 328 337 408 401 4 329 338 409 402 4 339 331 403 410 5 411 412 410 339 340 5 411 413 404 333 340 4 334 341 414 405 4 336 343 415 407 4 337 345 416 408 4 338 346 417 409 3 411 418 412 3 411 418 413 5 419 420 414 341 347 5 419 422 421 348 347 4 348 343 415 421 4 349 345 416 423 4 349 346 417 423 3 419 424 420 3 419 424 422 3 425 350 351 3 425 350 352 4 353 354 427 426 4 353 355 428 426 5 425 351 356 430 429 5 425 352 357 431 429 4 358 359 433 432 4 358 360 434 432 4 354 361 435 427 4 363 355 428 436 4 365 366 438 437 4 367 368 440 439 4 370 371 442 441 4 372 373 444 443 4 374 375 446 445 4 376 377 448 447 4 366 379 449 438 4 368 380 450 440 4 381 371 442 451 4 381 383 452 451 4 373 384 453 444 4 385 375 446 454 4 385 377 448 454 4 386 379 449 455 4 386 380 450 455 4 387 383 452 456 4 387 384 453 456 3 457 388 389 3 457 388 390 3 458 391 392 3 458 391 393 4 394 395 460 459 5 457 461 459 394 389 5 457 390 396 462 461 3 463 397 398 3 463 397 400 5 458 392 401 465 464 5 458 393 402 466 464 4 395 403 467 460 4 396 404 468 462 5 463 398 405 470 469 5 463 400 406 471 469 4 406 407 472 471 4 401 408 473 465 4 402 409 474 466 4 410 403 467 475 4 410 412 476 475 4 404 413 477 468 4 405 414 478 470 4 407 415 479 472 4 408 416 480 473 4 409 417 481 474 4 418 412 476 482 4 418 413 477 482 4 414 420 483 478 4 421 422 485 484 4 421 415 479 484 4 423 416 480 486 4 423 417 481 486 4 424 420 483 487 4 424 422 485 487 3 488 426 427 3 488 426 428 3 489 429 430 3 489 429 431 3 490 432 433 3 490 432 434 5 488 427 435 492 491 6 488 491 494 493 436 428 5 495 437 438 497 496 5 495 439 440 498 496 4 499 441 442 500 4 499 501 502 500 4 443 444 504 503 4 445 446 506 505 5 507 508 509 448 447 5 510 449 438 497 511 5 510 450 440 498 511 3 500 451 442 5 500 502 512 452 451 4 444 453 513 504 4 454 446 506 514 4 454 448 509 514 3 510 455 449 3 510 455 450 4 456 452 512 515 4 456 453 513 515 3 516 459 460 5 516 518 517 461 459 4 461 462 519 517 3 520 464 465 3 520 464 466 4 516 460 467 521 4 516 518 522 521 4 462 468 523 519 3 524 469 470 4 524 469 471 525 3 525 471 472 5 520 465 473 527 526 5 520 466 474 528 526 3 521 475 467 5 521 522 529 476 475 4 468 477 530 523 5 524 470 478 532 531 5 524 531 534 533 525 4 525 472 479 533 5 535 480 473 527 536 5 535 481 474 528 536 4 482 476 529 537 4 482 477 530 537 5 538 483 478 532 539 6 538 539 534 533 484 485 3 533 484 479 3 535 486 480 3 535 486 481 3 538 487 483 3 538 487 485 3 540 491 492 3 540 491 494 3 541 496 497 3 541 496 498 4 542 501 502 543 4 542 503 504 543 4 544 505 506 545 4 544 508 509 545 3 541 511 497 3 541 511 498 4 543 502 512 546 4 543 504 513 546 3 545 514 506 3 545 514 509 3 546 515 512 3 546 515 513 3 547 517 518 3 547 517 519 4 547 518 522 548 4 547 519 523 548 3 549 526 527 3 549 526 528 4 548 522 529 550 4 548 523 530 550 3 551 531 532 3 551 531 534 3 549 536 527 3 549 536 528 3 550 537 529 3 550 537 530 3 551 539 532 3 551 539 534 3 552 553 554 3 552 553 555 3 556 557 558 3 556 557 559 3 560 561 562 3 560 561 563 3 564 565 566 3 564 565 567 3 568 569 570 3 568 569 571 3 560 572 562 3 560 572 563 4 564 566 574 573 4 564 567 575 573 3 568 576 570 3 568 576 571 4 573 574 578 577 4 573 575 579 577 3 577 580 578 3 577 580 579 3 581 582 583 3 581 582 584 3 585 586 587 3 585 586 588 4 581 583 590 589 4 581 584 591 589 3 592 593 594 3 592 593 595 3 596 597 598 6 596 597 600 599 553 554 5 599 602 601 555 553 4 557 558 604 603 5 605 606 603 557 559 3 605 606 607 3 608 609 610 3 608 609 611 3 599 612 600 3 599 612 602 3 613 614 615 3 613 614 616 3 617 618 619 3 617 618 620 3 621 622 623 6 621 622 615 613 561 562 5 613 616 624 563 561 4 565 566 626 625 4 565 567 627 625 5 617 619 628 570 569 5 617 620 629 571 569 4 621 623 631 630 5 621 562 572 632 630 5 632 633 624 563 572 4 566 574 634 626 5 635 575 567 627 636 5 637 638 628 570 576 5 637 639 629 571 576 3 630 640 631 4 630 640 641 632 3 632 641 633 4 574 578 642 634 4 635 575 579 643 3 637 644 638 3 637 644 639 4 580 578 642 645 5 643 646 645 580 579 4 582 583 648 647 4 582 584 649 647 3 650 651 652 3 650 651 653 4 586 587 655 654 4 586 588 656 654 4 583 590 657 648 5 658 591 584 649 659 3 658 659 660 5 650 652 661 594 593 5 650 653 662 595 593 5 663 665 664 598 597 3 663 597 600 4 601 602 667 666 5 668 670 669 604 603 5 668 672 671 606 603 4 606 607 673 671 5 674 676 675 610 609 5 674 678 677 611 609 3 663 679 665 6 663 679 681 680 612 600 5 680 682 667 602 612 3 668 683 670 3 668 683 672 3 674 684 676 3 674 684 678 3 680 685 681 3 680 685 682 4 614 615 687 686 4 614 616 688 686 4 618 619 690 689 4 618 620 691 689 4 622 623 693 692 4 622 615 687 692 4 616 624 694 688 4 625 626 696 695 4 625 627 697 695 4 619 628 698 690 4 620 629 699 691 4 623 631 700 693 4 624 633 701 694 4 626 634 702 696 4 636 627 697 703 4 628 638 704 698 4 629 639 705 699 4 640 631 700 706 5 707 708 706 640 641 5 707 709 701 633 641 4 634 642 710 702 5 711 712 704 638 644 5 711 713 705 639 644 3 707 714 708 3 707 714 709 5 715 716 710 642 645 5 715 718 717 646 645 3 711 719 712 3 711 719 713 3 715 720 716 3 715 720 718 4 647 648 722 721 4 647 649 723 721 4 651 652 725 724 4 651 653 726 724 4 654 655 728 727 4 654 656 729 727 4 648 657 730 722 4 659 649 723 731 4 659 660 732 731 4 652 661 733 725 4 653 662 734 726 4 664 665 736 735 4 666 667 738 737 4 669 670 740 739 4 671 672 742 741 4 671 673 743 741 5 744 675 676 746 745 5 744 677 678 747 745 4 679 665 736 748 4 679 681 749 748 4 667 682 750 738 4 683 670 740 751 4 683 672 742 751 5 752 753 746 676 684 5 752 754 747 678 684 4 685 681 749 755 4 685 682 750 755 3 752 756 753 3 752 756 754 3 757 686 687 3 757 686 688 4 689 690 759 758 4 689 691 760 758 4 692 693 762 761 5 757 763 761 692 687 5 757 688 694 764 763 3 765 695 696 3 765 695 697 4 690 698 766 759 4 691 699 767 760 4 693 700 768 762 4 694 701 769 764 5 765 696 702 771 770 5 765 697 703 772 770 4 698 704 773 766 4 699 705 774 767 5 775 776 768 700 706 3 775 706 708 4 701 709 777 769 4 702 710 778 771 4 704 712 779 773 4 705 713 780 774 3 775 781 776 5 775 708 714 782 781 4 714 709 777 782 4 710 716 783 778 4 717 718 785 784 4 719 712 779 786 4 719 713 780 786 4 720 716 783 787 4 720 718 785 787 3 788 721 722 3 788 721 723 3 789 724 725 3 789 724 726 4 727 728 791 790 4 727 729 792 790 5 788 722 730 794 793 6 788 793 796 795 731 723 3 795 731 732 5 789 725 733 798 797 5 789 726 734 799 797 4 800 735 736 801 4 800 802 803 801 4 737 738 805 804 4 739 740 807 806 5 808 809 810 742 741 3 808 741 743 5 811 812 813 746 745 5 811 814 815 747 745 3 801 748 736 5 801 803 816 749 748 4 738 750 817 805 4 751 740 807 818 4 751 742 810 818 4 746 753 819 813 4 747 754 820 815 4 755 749 816 821 4 755 750 817 821 4 756 753 819 822 4 756 754 820 822 3 823 758 759 3 823 758 760 3 824 761 762 5 824 826 825 763 761 4 763 764 827 825 5 823 759 766 829 828 5 823 760 767 830 828 4 824 762 768 831 4 824 826 832 831 4 764 769 833 827 3 834 770 771 4 834 770 772 835 4 766 773 836 829 4 767 774 837 830 4 831 768 776 838 4 831 832 839 838 4 769 777 840 833 5 834 771 778 842 841 5 834 841 844 843 835 4 773 779 845 836 4 774 780 846 837 3 838 781 776 5 838 839 847 782 781 4 782 777 840 847 4 778 783 848 842 5 843 844 849 785 784 5 850 851 845 779 786 5 850 852 846 780 786 4 787 783 848 853 4 787 785 849 853 3 850 854 851 3 850 854 852 3 855 790 791 3 855 790 792 3 856 793 794 3 856 793 796 4 797 798 858 857 4 797 799 859 857 5 860 802 803 862 861 5 860 804 805 863 861 4 864 806 807 865 4 864 809 810 865 4 812 813 867 866 4 814 815 869 868 5 870 816 803 862 871 5 870 817 805 863 871 3 865 818 807 3 865 818 810 4 813 819 872 867 4 815 820 873 869 3 870 821 816 3 870 821 817 4 822 819 872 874 4 822 820 873 874 3 875 825 826 3 875 825 827 3 876 828 829 3 876 828 830 4 875 826 832 877 4 875 827 833 877 5 876 829 836 879 878 5 876 830 837 880 878 4 877 832 839 881 4 877 833 840 881 3 882 841 842 3 882 841 844 4 836 845 883 879 4 837 846 884 880 3 881 847 839 3 881 847 840 4 882 842 848 885 4 882 844 849 885 5 886 851 845 883 887 5 886 852 846 884 887 3 885 853 848 3 885 853 849 3 886 854 851 3 886 854 852 3 888 857 858 3 888 857 859 3 889 861 862 3 889 861 863 4 890 866 867 891 4 890 868 869 891 3 889 871 862 3 889 871 863 4 891 867 872 892 4 891 869 873 892 3 892 874 872 3 892 874 873 3 893 894 895 3 893 894 896 3 893 897 895 3 893 897 896 3 898 899 900 3 898 899 901 3 898 902 900 3 898 902 901 3 903 878 879 3 903 878 880 4 903 879 883 904 4 903 880 884 904 3 904 887 883 3 904 887 884 3 905 906 907 3 905 906 908 4 905 907 910 909 4 905 908 911 909 3 912 913 914 3 912 913 915 4 909 910 917 916 4 909 911 918 916 3 919 920 921 6 919 920 914 912 894 895 5 912 915 922 896 894 3 923 924 925 3 923 924 926 3 916 927 917 3 916 927 918 3 919 928 921 6 919 928 930 929 897 895 5 929 931 922 896 897 3 923 932 925 3 923 932 926 3 929 933 930 3 929 933 931 3 934 935 936 3 934 935 937 3 938 939 940 6 938 939 936 934 899 900 5 934 937 941 901 899 3 942 943 944 3 942 943 945 3 946 947 948 3 946 947 949 3 938 950 940 6 938 950 952 951 902 900 5 951 953 941 901 902 3 942 954 944 3 942 954 945 4 946 948 956 955 4 946 949 957 955 3 951 958 952 3 951 958 953 4 955 956 960 959 4 955 957 961 959 3 959 962 960 3 959 962 961 4 906 907 964 963 4 906 908 965 963 4 907 910 966 964 4 908 911 967 965 4 913 914 969 968 4 913 915 970 968 4 910 917 971 966 4 911 918 972 967 4 920 921 974 973 4 920 914 969 973 4 915 922 975 970 4 924 925 977 976 4 924 926 978 976 5 979 980 971 917 927 5 979 981 972 918 927 5 982 983 974 921 928 3 982 928 930 4 922 931 984 975 5 985 986 977 925 932 6 985 932 926 978 988 987 3 979 989 980 3 979 989 981 3 982 990 983 6 982 990 992 991 933 930 5 991 993 984 931 933 4 985 986 995 994 5 985 987 996 997 994 3 991 998 992 3 991 998 993 3 994 999 995 3 994 999 997 4 935 936 1001 1000 4 935 937 1002 1000 4 939 940 1004 1003 4 939 936 1001 1003 4 937 941 1005 1002 4 943 944 1007 1006 4 943 945 1008 1006 4 947 948 1010 1009 4 947 949 1011 1009 5 1012 1013 1004 940 950 3 1012 950 952 4 941 953 1014 1005 5 1015 1016 1007 944 954 6 1015 954 945 1008 1018 1017 3 1017 1018 1019 4 948 956 1020 1010 4 949 957 1021 1011 3 1012 1022 1013 6 1012 1022 1024 1023 958 952 5 1023 1025 1014 953 958 4 1015 1016 1027 1026 5 1015 1017 1028 1029 1026 3 1017 1028 1019 4 956 960 1030 1020 4 957 961 1031 1021 3 1023 1032 1024 3 1023 1032 1025 3 1026 1033 1027 3 1026 1033 1029 5 1034 1035 1030 960 962 5 1034 1036 1031 961 962 3 1034 1037 1035 3 1034 1037 1036 -0.511 1.022 3.419 0.133 0.991 -0.001 -0.341 1.115 3.419 -0.366 0.931 -0.002 -0.626 1.252 2.945 -0.315 0.238 0.919 -0.409 1.252 3.096 -0.615 0.755 0.226 -0.626 1.252 3.888 -0.325 0.213 -0.921 -0.409 1.252 3.739 -0.617 0.753 -0.227 -0.747 1.503 3.419 0.999 -0.039 -0.002 -0.749 1.498 3.419 0.999 -0.043 -0.002 -0.535 1.503 2.944 -0.058 0.405 0.912 -0.535 1.503 3.890 -0.034 0.416 -0.909 -0.687 1.503 7.521 -0.392 0.715 0.580 -0.724 1.447 7.521 -0.319 0.755 0.573 -0.751 1.503 7.429 -0.371 0.692 0.619 -0.632 1.264 8.205 -0.082 0.992 -0.094 -0.487 1.409 8.205 -0.498 0.861 -0.107 -0.535 1.503 7.886 -0.579 0.811 0.087 -0.751 1.503 8.603 -0.355 0.639 -0.682 -0.535 1.503 8.382 -0.601 0.775 -0.193 -0.650 1.300 12.307 0.273 0.829 0.489 -0.466 1.366 12.307 -0.108 0.832 0.544 -0.751 1.503 11.939 0.236 0.471 0.850 -0.535 1.503 12.033 -0.252 0.649 0.717 -0.711 1.503 12.991 0.112 0.440 -0.891 -0.742 1.484 12.991 0.145 0.434 -0.889 -0.535 1.503 12.814 -0.156 0.777 -0.610 -0.754 1.508 3.419 0.999 -0.040 -0.002 -0.877 1.753 2.952 0.274 -0.049 0.960 -0.660 1.753 2.943 0.031 -0.455 0.890 -0.877 1.753 3.877 0.373 -0.021 -0.927 -0.660 1.753 3.894 0.086 -0.435 -0.896 -0.650 1.733 7.521 -0.780 0.204 0.591 -0.877 1.753 7.285 -0.554 -0.117 0.824 -0.660 1.753 7.499 -0.788 0.167 0.592 -0.877 1.753 8.632 0.343 -0.120 -0.932 -0.660 1.753 8.583 -0.866 0.158 -0.475 -0.877 1.753 11.884 0.136 0.035 0.990 -0.660 1.753 11.886 0.180 0.215 0.960 -0.573 1.579 12.991 -0.112 0.420 -0.900 -1.002 2.004 3.278 0.049 -0.997 0.058 -0.785 2.004 3.142 -0.442 -0.878 0.184 -1.002 2.004 3.557 0.061 -0.996 -0.064 -0.785 2.004 3.698 -0.427 -0.885 -0.185 -0.998 1.995 7.521 -0.350 -0.755 0.555 -0.685 1.804 7.521 -0.803 0.052 0.594 -1.002 2.004 7.534 -0.338 -0.777 0.531 -0.785 2.004 7.621 -0.788 -0.486 0.378 -1.002 2.004 8.560 -0.225 -0.815 -0.534 -0.785 2.004 8.514 -0.812 -0.499 -0.303 -1.002 2.004 11.919 -0.016 -0.445 0.895 -0.785 2.004 11.883 0.056 -0.284 0.957 -1.030 2.060 3.419 0.027 -1.000 -0.004 -0.845 2.123 3.419 -0.414 -0.910 0.004 -1.093 2.186 8.205 -0.271 -0.956 -0.113 -0.875 2.185 8.205 -0.684 -0.722 -0.104 -1.030 2.254 12.307 -0.035 -0.892 0.452 -1.109 2.217 12.307 0.050 -0.878 0.476 -0.910 2.254 12.161 -0.142 -0.823 0.550 -1.029 2.058 12.991 0.143 -0.425 -0.894 -0.851 2.136 12.991 -0.178 -0.417 -0.891 -0.910 2.254 12.597 -0.203 -0.978 0.048 -0.944 2.322 12.307 -0.163 -0.859 0.486 -1.435 3.006 0.684 -0.147 0.410 0.900 -1.476 2.951 0.684 -0.112 0.427 0.897 -1.503 3.006 0.595 -0.134 0.385 0.913 -1.396 2.792 1.367 -0.062 0.992 -0.114 -1.255 2.943 1.367 -0.445 0.886 -0.130 -1.286 3.006 1.099 -0.465 0.849 0.250 -1.503 3.006 1.756 -0.462 0.649 -0.604 -1.286 3.006 1.489 -0.506 0.844 -0.179 -1.412 2.824 5.470 0.302 0.947 0.112 -1.230 2.895 5.470 -0.126 0.986 0.114 -1.503 3.006 5.115 0.298 0.799 0.523 -1.286 3.006 5.234 -0.256 0.931 0.261 -1.503 3.006 6.141 0.269 0.795 -0.543 -1.286 3.006 5.918 -0.146 0.969 -0.201 -1.422 3.006 10.256 -0.001 1.000 0.006 -1.475 2.949 10.256 -0.005 1.000 0.004 -1.503 3.006 10.118 -0.041 0.997 0.064 -1.503 3.006 10.397 -0.029 0.998 -0.058 -1.378 3.190 0.684 -0.359 0.167 0.918 -1.628 3.256 0.430 -0.251 -0.036 0.967 -1.411 3.256 0.613 -0.386 0.093 0.918 -1.628 3.256 1.791 0.374 -0.062 -0.925 -1.411 3.256 1.741 -0.843 0.233 -0.484 -1.628 3.256 5.043 0.433 0.115 0.894 -1.411 3.256 5.037 0.196 0.385 0.902 -1.507 3.014 6.154 0.278 0.774 -0.569 -1.330 3.094 6.154 -0.151 0.794 -0.588 -1.628 3.256 6.390 0.494 0.122 -0.861 -1.411 3.256 6.371 -0.327 0.470 -0.820 -1.317 3.068 10.256 -0.184 0.983 0.013 -1.628 3.256 9.798 0.437 0.021 0.899 -1.411 3.256 9.856 -0.651 0.631 0.422 -1.628 3.256 10.723 0.495 0.044 -0.868 -1.411 3.256 10.674 -0.613 0.654 -0.444 -1.661 3.507 0.684 -0.282 -0.362 0.888 -1.490 3.414 0.684 -0.404 -0.132 0.905 -1.753 3.507 0.652 -0.194 -0.421 0.886 -1.536 3.507 0.734 -0.460 -0.300 0.836 -1.753 3.507 1.736 -0.178 -0.772 -0.610 -1.536 3.507 1.693 -0.819 -0.463 -0.340 -1.753 3.507 5.071 -0.242 -0.664 0.708 -1.536 3.507 5.050 0.198 -0.490 0.849 -1.753 3.507 6.246 0.386 -0.687 -0.615 -1.536 3.507 6.359 -0.338 -0.542 -0.769 -1.748 3.507 10.256 0.999 0.054 0.003 -1.751 3.501 10.256 0.999 0.050 0.003 -1.536 3.507 9.798 0.521 0.247 0.817 -1.536 3.507 10.731 0.517 0.204 -0.831 -1.763 3.525 0.684 -0.195 -0.430 0.882 -1.855 3.709 1.367 -0.271 -0.957 -0.106 -1.637 3.708 1.367 -0.683 -0.724 -0.097 -1.851 3.757 5.470 0.127 -0.988 0.092 -1.873 3.745 5.470 0.152 -0.984 0.093 -1.662 3.757 5.259 -0.190 -0.950 0.248 -1.781 3.562 6.154 0.349 -0.746 -0.567 -1.607 3.649 6.154 -0.301 -0.767 -0.567 -1.662 3.757 5.851 -0.220 -0.965 -0.144 -1.756 3.511 10.256 0.999 0.054 0.003 -1.879 3.757 9.786 0.198 -0.221 0.955 -1.662 3.757 9.783 -0.244 -0.507 0.827 -1.879 3.757 10.729 0.187 -0.246 -0.951 -1.662 3.757 10.737 -0.223 -0.534 -0.816 -1.714 3.861 5.470 -0.228 -0.968 0.109 -1.906 4.007 10.256 -0.270 -0.963 0.001 -1.994 3.987 10.256 -0.103 -0.995 0.001 -1.787 4.007 10.147 -0.447 -0.894 0.040 -1.787 4.007 10.366 -0.446 -0.894 -0.037 -1.809 4.052 10.256 -0.442 -0.897 0.001 -0.264 1.252 3.419 -0.533 0.846 -0.003 -0.232 1.332 3.419 -0.524 0.852 -0.003 -0.318 1.503 3.089 -0.674 0.681 0.288 -0.318 1.503 3.747 -0.666 0.688 -0.288 -0.447 1.503 8.205 -0.623 0.774 -0.108 -0.363 1.503 12.307 -0.266 0.813 0.518 -0.443 1.753 3.010 -0.855 -0.195 0.480 -0.443 1.753 3.830 -0.853 -0.176 -0.491 -0.646 1.753 7.521 -0.793 0.173 0.584 -0.444 1.753 8.205 -0.949 0.295 -0.111 -0.337 1.542 12.307 -0.283 0.795 0.536 -0.443 1.753 11.969 -0.308 0.451 0.838 -0.465 1.753 12.991 -0.287 0.268 -0.920 -0.443 1.753 12.950 -0.326 0.316 -0.891 -0.568 2.004 3.240 -0.749 -0.658 0.081 -0.568 2.004 3.603 -0.749 -0.659 -0.074 -0.488 1.843 8.205 -0.988 0.098 -0.117 -0.568 2.004 8.183 -0.960 -0.257 -0.108 -0.568 2.004 8.215 -0.959 -0.257 -0.121 -0.568 2.004 11.916 -0.454 -0.158 0.877 -0.485 1.837 12.991 -0.320 0.143 -0.937 -0.611 2.090 3.419 -0.712 -0.702 0.007 -0.572 2.012 8.205 -0.957 -0.266 -0.118 -0.693 2.254 12.138 -0.533 -0.654 0.538 -0.601 2.069 12.991 -0.355 -0.164 -0.921 -0.693 2.254 12.635 -0.629 -0.776 -0.047 -0.736 2.339 12.307 -0.530 -0.711 0.463 -1.224 3.006 1.367 -0.516 0.846 -0.133 -1.143 3.006 5.470 -0.225 0.968 0.108 -1.363 3.256 0.684 -0.404 0.107 0.909 -1.197 3.256 1.367 -0.925 0.353 -0.140 -1.097 3.061 5.470 -0.274 0.954 0.119 -1.194 3.256 5.129 -0.467 0.723 0.509 -1.214 3.256 6.154 -0.502 0.595 -0.628 -1.194 3.256 6.119 -0.528 0.630 -0.570 -1.199 3.256 10.256 -0.501 0.865 0.018 -1.215 3.298 1.367 -0.956 0.256 -0.142 -1.319 3.507 1.273 -0.971 -0.237 -0.020 -1.319 3.507 1.409 -0.962 -0.229 -0.146 -1.319 3.507 5.073 -0.674 -0.239 0.699 -1.222 3.311 6.154 -0.605 0.440 -0.664 -1.319 3.507 6.250 -0.712 -0.189 -0.676 -1.197 3.262 10.256 -0.498 0.867 0.019 -1.319 3.507 9.874 -0.664 0.560 0.496 -1.319 3.507 10.660 -0.664 0.543 -0.514 -1.336 3.539 1.367 -0.954 -0.271 -0.130 -1.445 3.757 5.263 -0.653 -0.728 0.208 -1.363 3.595 6.154 -0.699 -0.378 -0.607 -1.445 3.757 5.859 -0.644 -0.754 -0.134 -1.445 3.757 9.862 -0.848 -0.363 0.386 -1.445 3.757 10.664 -0.834 -0.390 -0.390 -1.499 3.866 5.470 -0.623 -0.776 0.099 -1.570 4.007 10.256 -0.692 -0.722 0.003 -1.570 4.007 10.256 -0.692 -0.722 0.003 -1.570 4.008 10.256 -0.692 -0.722 0.003 -0.182 1.503 3.419 -0.796 0.606 -0.003 -0.242 1.753 3.419 -0.999 0.051 0.001 -0.265 1.753 12.307 -0.642 0.523 0.561 -0.457 2.004 3.419 -0.829 -0.560 0.007 -0.563 2.004 8.205 -0.960 -0.254 -0.118 -0.287 1.876 12.307 -0.806 0.253 0.534 -0.351 2.004 12.187 -0.818 0.038 0.575 -0.518 2.004 12.991 -0.376 -0.078 -0.923 -0.351 2.004 12.542 -0.980 0.049 0.192 -0.536 2.254 12.307 -0.702 -0.527 0.480 -0.431 2.163 12.307 -0.820 -0.255 0.512 -1.015 3.256 5.470 -0.727 0.675 0.130 -1.297 3.507 1.367 -0.967 -0.220 -0.132 -1.031 3.364 5.470 -0.920 0.371 0.126 -1.103 3.507 5.327 -0.979 0.059 0.194 -1.248 3.507 6.154 -0.776 -0.133 -0.617 -1.103 3.507 5.756 -0.997 0.056 -0.053 -1.143 3.507 10.256 -0.902 0.432 0.022 -1.261 3.757 5.470 -0.838 -0.536 0.106 -1.199 3.700 5.470 -0.924 -0.366 0.112 -1.235 3.757 10.256 -0.993 -0.113 0.015 -1.570 4.007 10.256 -0.692 -0.722 0.003 0.726 0.000 3.419 0.680 -0.733 0.000 0.777 0.182 3.419 0.500 -0.866 0.000 0.868 0.000 3.069 0.465 -0.843 0.271 0.868 0.000 3.768 0.466 -0.842 -0.271 0.061 1.252 10.256 0.997 0.082 -0.003 0.367 1.002 10.256 0.715 0.699 -0.002 0.241 1.252 9.871 0.896 0.279 0.345 0.241 1.252 10.638 0.896 0.280 -0.344 -0.024 1.503 10.256 0.877 -0.481 -0.002 0.116 1.503 9.917 0.769 -0.564 0.300 0.116 1.503 10.593 0.775 -0.556 -0.302 0.019 1.697 10.256 0.631 -0.776 0.001 -0.295 2.004 12.307 -0.845 0.054 0.532 -1.034 3.507 5.470 -0.989 0.079 0.125 -1.420 4.508 3.419 0.742 0.671 0.002 -1.374 4.482 3.419 0.721 0.693 0.002 -1.387 4.508 3.360 0.725 0.688 0.018 -1.387 4.508 3.478 0.726 0.688 -0.014 -1.698 4.759 3.419 0.982 0.191 -0.001 -1.512 4.759 3.023 0.837 0.452 0.309 -1.512 4.759 3.814 0.839 0.447 -0.309 -1.517 4.759 12.307 0.829 -0.230 0.510 -1.494 4.722 12.307 0.851 -0.126 0.509 -1.512 4.759 12.297 0.828 -0.229 0.512 -1.512 4.759 12.325 0.839 -0.233 0.492 0.800 0.250 3.419 0.283 -0.959 0.000 1.085 0.000 2.918 -0.316 -0.139 0.939 0.959 0.250 3.065 -0.054 -0.977 0.206 1.085 0.000 3.919 -0.318 -0.137 -0.938 0.959 0.250 3.771 -0.060 -0.977 -0.206 0.951 0.000 8.205 0.890 -0.441 -0.114 0.970 0.228 8.205 0.601 -0.794 -0.094 1.085 0.000 7.772 0.860 -0.434 0.269 1.085 0.000 8.467 0.809 -0.479 -0.341 0.972 0.000 12.307 0.378 -0.768 0.517 1.025 0.119 12.307 0.258 -0.821 0.509 1.085 0.000 12.085 0.242 -0.771 0.590 1.085 0.000 12.679 0.368 -0.902 -0.227 0.886 0.396 3.419 -0.072 -0.997 -0.001 0.368 1.002 10.256 0.713 0.701 -0.002 0.609 0.951 10.256 0.456 0.890 -0.003 0.584 1.002 10.125 0.463 0.885 0.044 0.584 1.002 10.385 0.461 0.886 -0.049 0.412 1.252 1.367 0.870 0.482 -0.100 0.482 1.206 1.367 0.823 0.560 -0.098 0.458 1.252 1.233 0.850 0.522 0.077 0.458 1.252 1.444 0.845 0.520 -0.129 0.458 1.252 9.769 0.489 0.477 0.730 0.458 1.252 10.738 0.478 0.485 -0.732 0.225 1.503 1.367 0.980 -0.156 -0.120 0.333 1.503 0.979 0.807 -0.077 0.586 0.333 1.503 1.588 0.956 -0.119 -0.268 0.128 1.503 5.470 0.980 0.169 0.110 0.435 1.299 5.470 0.644 0.759 0.099 0.333 1.503 5.153 0.790 0.488 0.372 0.333 1.503 6.045 0.787 0.465 -0.405 0.333 1.503 9.769 -0.322 -0.323 0.890 0.333 1.503 10.740 -0.342 -0.302 -0.890 0.229 1.712 1.367 0.812 -0.573 -0.115 0.025 1.753 5.470 0.917 -0.378 0.125 0.208 1.753 5.118 0.696 -0.399 0.597 0.208 1.753 6.126 0.775 -0.247 -0.582 0.032 1.753 10.256 0.520 -0.854 0.002 0.208 1.753 9.877 0.287 -0.871 0.399 0.208 1.753 10.637 0.298 -0.863 -0.407 0.064 2.004 5.470 0.495 -0.862 0.113 0.083 2.004 5.430 0.489 -0.863 0.126 0.083 2.004 5.549 0.493 -0.867 0.077 0.122 1.924 10.256 0.106 -0.994 0.005 0.073 2.024 5.470 0.479 -0.871 0.113 -1.126 4.420 3.419 0.493 0.870 0.006 -1.170 4.508 3.211 0.498 0.863 0.083 -1.170 4.508 3.633 0.501 0.862 -0.078 -1.358 4.508 12.307 0.778 0.469 0.417 -1.096 4.362 12.307 0.593 0.693 0.411 -1.170 4.508 12.044 0.607 0.606 0.514 -1.170 4.508 12.791 0.656 0.613 -0.441 -1.295 4.759 2.936 0.477 0.619 0.624 -1.295 4.759 3.903 0.483 0.602 -0.636 -1.370 4.759 8.205 0.822 0.564 -0.079 -1.260 4.688 8.205 0.768 0.635 -0.082 -1.295 4.759 7.993 0.799 0.602 0.009 -1.295 4.759 8.326 0.783 0.611 -0.116 -1.295 4.759 11.926 0.449 0.001 0.894 -1.295 4.759 12.982 0.398 -0.004 -0.917 1.286 0.000 3.419 0.432 0.902 0.000 1.291 0.020 3.419 0.447 0.895 0.000 1.176 0.250 2.954 -0.292 -0.837 0.462 1.176 0.250 3.880 -0.306 -0.837 -0.453 1.209 0.000 7.521 0.711 -0.099 0.696 1.198 0.208 7.521 0.357 -0.710 0.607 1.301 0.000 7.391 0.639 0.021 0.769 0.971 0.250 8.205 0.532 -0.842 -0.093 1.176 0.250 7.554 0.257 -0.829 0.497 1.301 0.000 8.630 0.549 0.304 -0.778 1.176 0.250 8.568 -0.006 -0.914 -0.406 1.153 0.250 12.307 0.017 -0.882 0.470 1.301 0.000 11.891 -0.104 -0.587 0.803 1.176 0.250 12.268 0.001 -0.878 0.478 1.224 0.000 12.991 0.079 -0.455 -0.887 1.265 0.073 12.991 0.024 -0.483 -0.875 1.176 0.250 12.378 0.005 -0.917 0.398 1.057 0.489 3.419 -0.166 -0.986 -0.004 1.073 0.457 8.205 0.065 -0.994 -0.093 1.167 0.269 12.307 -0.004 -0.884 0.467 0.723 1.002 10.256 0.320 0.947 -0.004 0.736 1.131 1.367 0.511 0.854 -0.099 0.675 1.252 0.941 0.479 0.669 0.569 0.675 1.252 1.605 0.553 0.795 -0.248 0.792 1.019 10.256 0.213 0.977 -0.006 0.675 1.252 9.779 -0.249 0.266 0.931 0.675 1.252 10.723 -0.313 0.248 -0.917 0.470 1.503 0.684 0.372 0.063 0.926 0.601 1.402 0.684 0.336 0.209 0.919 0.550 1.503 0.572 0.339 0.100 0.936 0.550 1.503 1.777 0.589 0.254 -0.767 0.652 1.299 5.470 0.363 0.926 0.107 0.550 1.503 5.101 0.362 0.731 0.578 0.493 1.503 6.154 0.510 0.658 -0.554 0.560 1.482 6.154 0.433 0.727 -0.533 0.550 1.503 6.188 0.432 0.714 -0.551 0.550 1.503 10.166 -0.972 -0.210 0.103 0.550 1.503 10.340 -0.969 -0.197 -0.150 0.424 1.753 0.684 0.246 -0.264 0.933 0.425 1.753 0.683 0.245 -0.264 0.933 0.225 1.753 1.367 0.730 -0.673 -0.116 0.425 1.753 1.736 0.377 -0.705 -0.600 0.425 1.753 5.047 0.211 0.013 0.977 0.224 1.753 6.154 0.748 -0.216 -0.627 0.425 1.753 6.388 0.481 0.007 -0.877 0.425 1.753 9.792 0.228 -0.181 0.957 0.425 1.753 10.718 0.220 -0.118 -0.968 0.424 1.754 0.684 0.245 -0.265 0.933 0.314 1.976 1.367 0.235 -0.965 -0.117 0.300 2.004 5.097 0.257 -0.751 0.608 0.274 2.004 6.154 0.210 -0.779 -0.591 0.300 2.004 6.192 0.185 -0.771 -0.610 0.245 2.004 10.256 -0.069 -0.998 0.006 0.300 2.004 10.157 -0.086 -0.995 0.043 0.300 2.004 10.358 -0.086 -0.996 -0.034 0.197 2.208 5.470 0.019 -0.993 0.114 0.288 2.027 6.154 0.172 -0.791 -0.588 0.279 2.045 10.256 -0.098 -0.995 0.006 -0.939 4.481 3.419 0.190 0.982 0.009 -0.953 4.508 3.353 0.185 0.982 0.030 -0.953 4.508 3.487 0.186 0.983 -0.015 -0.873 4.350 12.307 0.381 0.831 0.405 -0.953 4.508 11.993 0.367 0.739 0.565 -0.953 4.508 12.905 0.319 0.634 -0.704 -1.078 4.759 2.955 0.277 0.814 0.511 -1.078 4.759 3.887 0.276 0.801 -0.531 -1.006 4.615 8.205 0.532 0.841 -0.097 -1.078 4.759 7.696 0.581 0.781 0.231 -1.078 4.759 8.484 0.559 0.802 -0.211 -1.078 4.759 11.881 0.064 -0.015 0.998 -1.288 4.759 12.991 0.387 0.006 -0.922 -0.976 4.555 12.991 0.268 0.455 -0.849 1.321 0.000 3.419 0.464 0.886 0.000 1.518 0.000 2.971 0.659 0.649 0.380 1.393 0.250 2.941 -0.423 -0.615 0.665 1.518 0.000 3.865 0.662 0.641 -0.388 1.393 0.250 3.890 -0.442 -0.629 -0.639 1.198 0.250 7.521 0.228 -0.805 0.547 1.518 0.000 7.307 0.301 0.645 0.703 1.393 0.250 7.312 -0.147 -0.766 0.626 1.518 0.000 8.635 0.179 0.455 -0.872 1.393 0.250 8.626 -0.080 -0.492 -0.867 1.518 0.000 11.877 -0.135 -0.218 0.967 1.393 0.250 12.050 -0.293 -0.793 0.535 1.435 0.167 12.991 -0.196 -0.476 -0.858 1.393 0.250 12.787 -0.283 -0.844 -0.456 1.088 0.501 3.419 -0.194 -0.981 -0.004 1.268 0.501 3.222 -0.387 -0.918 0.087 1.268 0.501 3.608 -0.392 -0.915 -0.097 1.317 0.403 7.521 -0.124 -0.861 0.493 1.124 0.501 8.205 0.061 -0.993 -0.100 1.268 0.501 7.802 -0.045 -0.985 0.164 1.268 0.501 8.422 0.000 -0.967 -0.256 1.330 0.376 12.307 -0.310 -0.853 0.420 1.229 0.579 3.419 -0.382 -0.924 -0.008 1.217 0.603 8.205 -0.073 -0.991 -0.113 0.932 1.173 1.367 0.181 0.977 -0.109 0.892 1.252 1.048 0.198 0.913 0.357 0.892 1.252 1.536 0.158 0.967 -0.201 0.968 1.101 10.256 -0.115 0.993 -0.013 0.892 1.252 9.893 -0.371 0.856 0.361 0.892 1.252 10.603 -0.402 0.842 -0.360 0.836 1.365 0.684 0.167 0.445 0.880 0.767 1.503 0.483 0.138 0.291 0.947 0.767 1.503 1.785 0.185 0.500 -0.846 0.840 1.357 5.470 0.061 0.989 0.132 0.767 1.503 5.178 -0.089 0.912 0.400 0.619 1.503 6.154 0.342 0.772 -0.535 0.767 1.503 6.056 0.073 0.920 -0.386 0.767 1.503 9.788 0.572 0.302 0.763 0.767 1.503 10.704 0.582 0.330 -0.743 0.642 1.753 0.460 0.055 -0.217 0.975 0.642 1.753 1.792 -0.001 -0.361 -0.932 0.642 1.753 5.048 0.040 0.356 0.934 0.746 1.545 6.154 0.069 0.826 -0.560 0.642 1.753 6.400 -0.136 0.360 -0.923 0.642 1.753 9.777 -0.250 -0.425 0.870 0.642 1.753 10.726 -0.285 -0.370 -0.884 0.553 1.930 0.684 -0.015 -0.408 0.913 0.338 2.004 1.367 0.184 -0.976 -0.114 0.516 2.004 0.850 -0.026 -0.667 0.745 0.516 2.004 1.642 0.070 -0.935 -0.348 0.516 2.004 5.047 -0.211 -0.505 0.837 0.516 2.004 6.337 -0.269 -0.615 -0.741 0.516 2.004 9.985 -0.406 -0.897 0.178 0.516 2.004 10.529 -0.416 -0.891 -0.180 0.449 2.139 1.367 -0.069 -0.989 -0.127 0.289 2.254 5.470 -0.171 -0.980 0.100 0.391 2.254 5.341 -0.263 -0.952 0.158 0.455 2.127 6.154 -0.299 -0.770 -0.564 0.391 2.254 5.721 -0.280 -0.960 -0.022 0.458 2.120 10.256 -0.413 -0.911 0.005 0.361 2.315 5.470 -0.272 -0.957 0.104 -0.912 4.508 3.419 0.148 0.989 0.009 -0.690 4.417 12.307 0.118 0.889 0.443 -0.736 4.508 12.115 0.092 0.848 0.521 -0.736 4.508 12.672 0.087 0.986 -0.145 -0.772 4.580 3.419 0.003 1.000 0.009 -0.861 4.759 3.031 0.102 0.958 0.268 -0.861 4.759 3.812 0.095 0.957 -0.275 -0.804 4.644 8.205 0.263 0.959 -0.104 -0.861 4.759 7.753 0.273 0.945 0.179 -0.861 4.759 8.443 0.274 0.941 -0.197 -0.861 4.759 11.883 0.073 0.377 0.924 -0.790 4.617 12.991 0.040 0.499 -0.865 1.735 0.000 3.022 -0.311 0.843 0.440 1.610 0.250 2.987 -0.782 -0.448 0.433 1.735 0.000 3.815 -0.335 0.828 -0.450 1.610 0.250 3.842 -0.781 -0.466 -0.414 1.735 0.000 7.444 -0.006 0.864 0.504 1.610 0.250 7.316 -0.581 -0.403 0.707 1.735 0.000 8.604 -0.257 0.635 -0.728 1.610 0.250 8.635 -0.185 0.020 -0.983 1.735 0.000 11.897 -0.390 -0.131 0.911 1.610 0.250 12.043 -0.533 -0.668 0.519 1.677 0.117 12.991 -0.370 -0.257 -0.893 1.610 0.250 12.810 -0.543 -0.677 -0.497 1.485 0.501 3.268 -0.683 -0.728 0.049 1.485 0.501 3.561 -0.683 -0.727 -0.064 1.508 0.454 7.521 -0.453 -0.706 0.545 1.485 0.501 7.600 -0.418 -0.806 0.419 1.485 0.501 8.524 -0.412 -0.817 -0.403 1.540 0.391 12.307 -0.521 -0.746 0.414 1.452 0.566 3.419 -0.659 -0.752 -0.011 1.404 0.662 8.205 -0.405 -0.908 -0.107 1.017 1.252 1.367 0.075 0.992 -0.103 1.066 1.252 10.256 -0.372 0.928 -0.017 1.006 1.458 0.684 -0.092 0.426 0.900 0.984 1.503 0.611 -0.106 0.389 0.915 1.088 1.295 1.367 -0.021 0.993 -0.113 0.984 1.503 1.746 -0.135 0.773 -0.620 0.965 1.503 5.470 -0.213 0.969 0.128 1.088 1.295 10.256 -0.371 0.928 -0.018 0.984 1.503 9.854 -0.482 0.733 0.480 0.984 1.503 10.635 -0.489 0.738 -0.465 0.859 1.753 0.462 -0.217 -0.056 0.975 0.859 1.753 1.802 -0.214 -0.069 -0.975 0.976 1.518 5.470 -0.239 0.962 0.130 0.859 1.753 5.104 -0.399 0.665 0.631 0.882 1.707 6.154 -0.504 0.576 -0.643 0.859 1.753 6.217 -0.542 0.494 -0.680 0.859 1.753 9.805 -0.743 -0.290 0.603 0.859 1.753 10.689 -0.769 -0.253 -0.587 0.742 1.986 0.684 -0.223 -0.363 0.905 0.733 2.004 0.708 -0.233 -0.406 0.884 0.733 2.004 1.723 -0.417 -0.768 -0.487 0.733 2.004 5.071 -0.676 -0.313 0.667 0.733 2.004 6.260 -0.667 -0.308 -0.679 0.733 2.004 10.046 -0.708 -0.701 0.089 0.733 2.004 10.461 -0.716 -0.692 -0.094 0.640 2.191 1.367 -0.423 -0.900 -0.109 0.608 2.254 5.303 -0.600 -0.781 0.174 0.690 2.091 6.154 -0.656 -0.461 -0.598 0.608 2.254 5.792 -0.600 -0.797 -0.070 0.686 2.099 10.256 -0.679 -0.734 -0.002 0.566 2.338 5.470 -0.578 -0.810 0.100 -0.618 4.508 12.307 -0.046 0.878 0.477 -0.662 4.759 3.419 -0.397 0.918 0.006 -0.672 4.759 8.205 -0.024 0.994 -0.107 -0.552 4.574 12.307 -0.191 0.834 0.517 -0.644 4.759 11.979 -0.089 0.723 0.685 -0.693 4.759 12.991 -0.123 0.431 -0.894 -0.644 4.759 12.908 -0.200 0.563 -0.802 1.906 0.000 3.419 -0.619 0.785 0.000 1.842 0.220 3.419 -1.000 -0.013 -0.005 1.827 0.250 3.389 -0.995 -0.096 0.003 1.827 0.250 3.448 -0.995 -0.097 -0.015 1.786 0.000 7.521 -0.043 0.880 0.473 1.793 0.250 7.521 -0.777 0.006 0.629 1.952 0.000 7.977 -0.203 0.979 0.010 1.827 0.250 7.574 -0.830 0.112 0.547 1.952 0.000 8.327 -0.193 0.974 -0.120 1.827 0.250 8.556 -0.825 0.153 -0.544 1.952 0.000 12.136 -0.790 0.085 0.607 1.827 0.250 12.263 -0.754 -0.494 0.433 1.807 0.000 12.991 -0.406 -0.096 -0.909 1.952 0.000 12.622 -0.992 0.125 -0.027 1.827 0.250 12.397 -0.788 -0.512 0.343 1.585 0.501 3.419 -0.766 -0.643 -0.011 1.810 0.283 3.419 -0.991 -0.134 -0.007 1.702 0.501 7.733 -0.794 -0.557 0.242 1.702 0.501 8.458 -0.781 -0.569 -0.258 1.813 0.278 12.307 -0.750 -0.508 0.425 1.629 0.646 8.205 -0.696 -0.711 -0.104 1.036 1.503 0.684 -0.136 0.405 0.904 1.223 1.459 1.367 -0.438 0.891 -0.118 1.201 1.503 1.186 -0.477 0.871 0.118 1.201 1.503 1.456 -0.469 0.870 -0.155 1.156 1.503 10.256 -0.802 0.597 -0.022 1.069 1.753 0.684 -0.371 0.065 0.926 1.076 1.753 0.694 -0.384 0.072 0.921 1.076 1.753 1.727 -0.765 0.260 -0.590 1.065 1.753 5.470 -0.787 0.599 0.145 0.901 1.753 6.154 -0.578 0.507 -0.640 1.115 1.675 10.256 -0.988 0.154 -0.019 1.076 1.753 10.170 -1.000 0.021 0.015 1.076 1.753 10.334 -0.999 0.023 -0.048 0.950 2.004 0.843 -0.562 -0.378 0.736 0.950 2.004 1.653 -0.793 -0.535 -0.291 1.059 1.786 5.470 -0.851 0.506 0.143 0.950 2.004 5.290 -0.973 -0.014 0.232 0.820 2.004 6.154 -0.752 -0.239 -0.615 0.950 2.004 5.850 -0.991 -0.041 -0.131 0.871 2.004 10.256 -0.817 -0.577 -0.009 1.031 1.843 10.256 -0.991 -0.135 -0.017 0.867 2.170 1.367 -0.702 -0.705 -0.102 0.778 2.254 5.470 -0.781 -0.615 0.107 0.850 2.205 5.470 -0.889 -0.444 0.117 -0.475 4.759 12.307 -0.444 0.733 0.515 1.839 0.250 3.419 -0.996 -0.092 -0.006 2.008 0.000 8.205 -0.228 0.970 -0.084 2.005 0.250 8.205 -0.928 0.353 -0.117 2.032 0.000 12.307 -0.831 0.134 0.540 1.851 0.250 12.307 -0.766 -0.482 0.426 1.864 0.501 8.205 -0.929 -0.354 -0.110 1.243 1.503 1.367 -0.490 0.864 -0.120 1.260 1.753 1.367 -0.950 0.288 -0.123 1.110 1.753 10.256 -0.999 0.030 -0.019 1.130 2.004 1.367 -0.946 -0.306 -0.108 1.040 2.004 5.470 -0.990 0.016 0.141 2.307 0.000 1.367 0.887 -0.444 -0.124 2.314 0.143 1.367 0.778 -0.618 -0.114 2.386 0.000 1.053 0.804 -0.415 0.426 2.386 0.000 1.538 0.858 -0.464 -0.219 2.330 0.000 5.470 0.470 -0.877 0.105 2.354 0.064 5.470 0.420 -0.901 0.106 2.386 0.000 5.348 0.418 -0.896 0.149 2.386 0.000 5.698 0.450 -0.893 -0.012 0.794 3.006 8.205 0.990 -0.017 -0.141 0.984 2.805 8.205 0.888 0.444 -0.117 0.883 3.006 7.825 0.991 0.040 0.131 0.883 3.006 8.385 0.973 0.014 -0.232 0.703 3.006 12.307 0.832 0.269 0.485 0.966 2.839 12.307 0.624 0.627 0.466 0.883 3.006 12.022 0.632 0.426 0.647 0.883 3.006 12.831 0.631 0.424 -0.650 0.724 3.256 3.419 0.999 -0.030 0.019 0.803 3.167 3.419 0.991 0.134 0.017 0.758 3.256 3.341 0.999 -0.023 0.048 0.758 3.256 3.504 1.000 -0.021 -0.015 0.774 3.223 8.205 0.850 -0.506 -0.143 0.573 3.256 12.307 0.821 -0.249 0.514 0.758 3.256 11.947 0.482 -0.164 0.861 0.758 3.256 12.981 0.388 -0.073 -0.919 0.719 3.334 3.419 0.988 -0.154 0.019 0.591 3.507 12.307 0.426 -0.752 0.503 0.633 3.507 12.218 0.402 -0.745 0.532 0.633 3.507 12.489 0.462 -0.843 0.275 0.611 3.550 12.307 0.382 -0.777 0.500 -0.030 4.508 5.470 0.870 0.484 0.090 0.204 4.363 5.470 0.667 0.740 0.087 0.132 4.508 5.217 0.725 0.661 0.196 0.132 4.508 5.941 0.742 0.644 -0.189 -0.018 4.759 1.367 0.843 0.530 -0.093 0.020 4.731 1.367 0.826 0.556 -0.094 0.007 4.759 1.278 0.839 0.545 -0.008 0.007 4.759 1.411 0.832 0.545 -0.104 -0.172 4.759 5.470 0.928 -0.353 0.117 0.007 4.759 5.119 0.825 -0.153 0.543 0.007 4.759 6.100 0.830 -0.112 -0.547 -0.005 4.759 10.256 0.996 0.092 0.006 0.023 4.726 10.256 0.989 0.145 0.007 0.007 4.759 10.227 0.995 0.098 0.015 0.007 4.759 10.287 0.995 0.096 -0.004 2.531 0.000 0.684 0.324 -0.068 0.944 2.526 0.153 0.684 0.235 -0.257 0.937 2.603 0.000 0.579 0.293 -0.032 0.955 2.308 0.250 1.367 0.515 -0.850 -0.110 2.478 0.250 0.767 0.187 -0.527 0.829 2.603 0.000 1.778 0.640 0.180 -0.747 2.478 0.250 1.696 0.115 -0.931 -0.345 2.485 0.237 5.470 0.077 -0.991 0.111 2.603 0.000 5.071 -0.099 -0.875 0.475 2.552 0.000 6.154 0.162 -0.821 -0.547 2.578 0.050 6.154 0.099 -0.836 -0.540 2.603 0.000 6.230 0.096 -0.818 -0.568 2.432 0.000 10.256 0.715 -0.699 0.000 2.487 0.231 10.256 0.445 -0.895 -0.006 2.603 0.000 9.859 0.230 -0.883 0.409 2.603 0.000 10.653 0.208 -0.893 -0.399 2.385 0.435 1.367 0.139 -0.985 -0.102 1.056 2.755 8.205 0.781 0.615 -0.107 1.267 2.671 8.205 0.578 0.810 -0.100 1.225 2.755 7.882 0.600 0.797 0.070 1.225 2.755 8.372 0.600 0.781 -0.174 0.962 3.006 3.419 0.817 0.577 0.009 1.148 2.911 3.419 0.679 0.734 0.002 1.100 3.006 3.214 0.716 0.692 0.094 1.100 3.006 3.628 0.708 0.701 -0.089 1.014 3.006 7.521 0.752 0.239 0.614 1.144 2.918 7.521 0.656 0.461 0.598 1.100 3.006 7.415 0.667 0.308 0.678 1.100 3.006 8.604 0.676 0.313 -0.667 1.194 2.819 12.307 0.374 0.795 0.477 1.100 3.006 11.952 0.287 0.529 0.798 1.100 3.006 12.966 0.237 0.415 -0.878 0.975 3.256 2.985 0.769 0.253 0.587 0.975 3.256 3.870 0.743 0.290 -0.603 0.933 3.256 7.521 0.578 -0.507 0.640 0.975 3.256 7.458 0.542 -0.494 0.680 0.768 3.256 8.205 0.787 -0.600 -0.145 0.975 3.256 8.571 0.399 -0.665 -0.631 0.975 3.256 11.873 0.116 0.038 0.993 0.765 3.256 12.991 0.372 -0.065 -0.926 1.091 3.024 12.991 0.223 0.364 -0.904 0.677 3.507 3.419 0.802 -0.597 0.022 0.850 3.507 3.040 0.489 -0.738 0.465 0.850 3.507 3.820 0.482 -0.734 -0.480 0.952 3.302 7.521 0.505 -0.576 0.643 0.857 3.492 8.205 0.239 -0.962 -0.130 0.850 3.507 11.929 0.087 -0.497 0.864 0.797 3.507 12.991 0.136 -0.405 -0.904 0.746 3.714 3.419 0.372 -0.928 0.018 0.746 3.714 12.307 0.019 -0.876 0.482 0.827 3.551 12.991 0.092 -0.426 -0.900 0.429 4.347 5.470 0.426 0.901 0.085 0.349 4.508 5.151 0.453 0.852 0.262 0.349 4.508 6.075 0.440 0.830 -0.343 0.248 4.508 10.256 0.738 0.675 0.010 0.381 4.443 10.256 0.642 0.767 0.010 0.349 4.508 10.113 0.662 0.747 0.056 0.349 4.508 10.407 0.662 0.748 -0.043 0.294 4.619 1.367 0.577 0.811 -0.100 0.223 4.759 0.865 0.496 0.618 0.610 0.223 4.759 1.631 0.610 0.765 -0.204 0.223 4.759 5.039 0.185 -0.019 0.983 0.041 4.759 6.154 0.777 -0.006 -0.630 0.325 4.556 6.154 0.466 0.736 -0.492 0.223 4.759 6.359 0.581 0.403 -0.707 0.223 4.759 9.833 0.781 0.467 0.414 0.223 4.759 10.687 0.782 0.448 -0.433 2.526 0.250 0.684 0.123 -0.431 0.894 2.820 0.000 0.464 0.179 0.301 0.937 2.695 0.250 0.487 -0.051 -0.447 0.893 2.820 0.000 1.797 0.323 0.536 -0.780 2.695 0.250 1.792 -0.119 -0.614 -0.781 2.505 0.250 5.470 0.025 -0.994 0.107 2.820 0.000 5.040 -0.191 -0.474 0.859 2.695 0.250 5.232 -0.274 -0.941 0.197 2.740 0.160 6.154 -0.298 -0.809 -0.507 2.695 0.250 5.921 -0.273 -0.945 -0.179 2.820 0.000 6.368 -0.347 -0.710 -0.613 2.495 0.250 10.256 0.397 -0.918 -0.006 2.820 0.000 9.809 -0.082 0.734 0.674 2.695 0.250 9.862 -0.095 -0.957 0.276 2.820 0.000 10.703 -0.109 0.710 -0.696 2.695 0.250 10.643 -0.102 -0.958 -0.268 2.624 0.392 0.684 -0.048 -0.510 0.859 2.451 0.501 1.367 0.088 -0.990 -0.109 2.569 0.501 1.002 -0.016 -0.891 0.454 2.569 0.501 1.559 0.020 -0.974 -0.224 2.637 0.366 5.470 -0.288 -0.953 0.094 2.605 0.429 10.256 -0.110 -0.994 -0.008 2.524 0.592 1.367 -0.039 -0.993 -0.115 1.473 2.694 8.205 0.272 0.957 -0.104 1.442 2.755 7.954 0.279 0.960 0.022 1.442 2.755 8.334 0.263 0.952 -0.158 1.375 2.889 3.419 0.413 0.911 -0.005 1.317 3.006 3.146 0.416 0.891 0.180 1.317 3.006 3.690 0.406 0.897 -0.178 1.379 2.882 7.521 0.299 0.770 0.563 1.317 3.006 7.338 0.269 0.616 0.741 1.317 3.006 8.627 0.211 0.505 -0.837 1.384 2.871 12.307 0.059 0.838 0.543 1.317 3.006 12.033 -0.051 0.681 0.731 1.317 3.006 12.825 0.029 0.757 -0.652 1.192 3.256 2.949 0.285 0.370 0.884 1.192 3.256 3.898 0.250 0.425 -0.870 1.192 3.256 7.274 0.137 -0.360 0.923 1.192 3.256 8.626 -0.040 -0.356 -0.934 1.192 3.256 11.882 0.000 0.200 0.980 1.280 3.079 12.991 0.015 0.408 -0.913 1.067 3.507 2.970 -0.582 -0.330 0.743 1.067 3.507 3.886 -0.572 -0.302 -0.762 1.088 3.464 7.521 -0.069 -0.826 0.560 0.869 3.507 8.205 0.213 -0.969 -0.128 1.067 3.507 7.618 -0.073 -0.920 0.386 1.067 3.507 8.497 0.089 -0.912 -0.400 1.067 3.507 11.890 -0.108 -0.291 0.951 0.768 3.757 3.419 0.372 -0.928 0.017 0.941 3.757 3.072 0.402 -0.842 0.360 0.941 3.757 3.782 0.372 -0.855 -0.361 0.994 3.652 8.205 -0.061 -0.989 -0.132 0.816 3.757 12.307 -0.067 -0.882 0.466 0.941 3.757 12.138 -0.130 -0.796 0.592 0.997 3.645 12.991 -0.168 -0.445 -0.880 0.941 3.757 12.626 -0.212 -0.977 -0.035 0.866 3.908 3.419 0.116 -0.993 0.013 0.902 3.836 12.307 -0.157 -0.848 0.506 0.616 4.407 5.470 0.177 0.980 0.088 0.566 4.508 5.253 0.155 0.970 0.186 0.566 4.508 5.873 0.128 0.982 -0.137 0.604 4.431 10.256 0.404 0.915 0.007 0.566 4.508 10.067 0.415 0.906 0.077 0.566 4.508 10.452 0.412 0.909 -0.069 0.503 4.633 1.367 0.320 0.942 -0.099 0.440 4.759 0.888 0.256 0.764 0.592 0.440 4.759 1.625 0.339 0.917 -0.209 0.440 4.759 5.049 0.080 0.493 0.867 0.516 4.607 6.154 0.118 0.858 -0.501 0.440 4.759 6.363 0.147 0.765 -0.627 0.440 4.759 9.785 0.442 0.629 0.639 0.440 4.759 10.734 0.423 0.615 -0.665 3.037 0.000 0.572 0.009 0.510 0.860 2.912 0.250 0.465 -0.312 -0.272 0.910 3.037 0.000 1.784 -0.260 0.434 -0.862 2.912 0.250 1.794 -0.121 0.028 -0.992 3.037 0.000 5.045 -0.525 -0.227 0.820 2.912 0.250 5.191 -0.559 -0.802 0.211 2.971 0.131 6.154 -0.652 -0.541 -0.531 2.912 0.250 5.979 -0.580 -0.781 -0.231 3.037 0.000 6.283 -0.705 -0.360 -0.610 3.017 0.000 10.256 0.533 0.846 0.000 3.027 0.019 10.256 0.555 0.832 0.000 2.912 0.250 9.788 -0.277 -0.801 0.531 2.912 0.250 10.720 -0.277 -0.814 -0.511 2.810 0.454 0.684 -0.248 -0.420 0.873 2.786 0.501 0.770 -0.258 -0.531 0.808 2.786 0.501 1.682 -0.370 -0.834 -0.410 2.839 0.395 5.470 -0.529 -0.844 0.087 2.746 0.501 10.256 -0.177 -0.984 -0.008 2.786 0.501 10.187 -0.193 -0.981 0.015 2.786 0.501 10.322 -0.193 -0.981 -0.030 2.707 0.660 1.367 -0.388 -0.915 -0.113 2.773 0.528 10.256 -0.198 -0.980 -0.009 1.545 2.755 8.205 0.171 0.980 -0.100 1.555 2.964 3.419 0.098 0.995 -0.006 1.534 3.006 3.316 0.086 0.996 0.034 1.534 3.006 3.518 0.086 0.995 -0.043 1.546 2.982 7.521 -0.172 0.791 0.587 1.534 3.006 7.483 -0.185 0.771 0.609 1.636 2.801 8.205 -0.019 0.993 -0.114 1.534 3.006 8.577 -0.257 0.751 -0.608 1.496 3.006 12.307 -0.160 0.849 0.503 1.409 3.256 2.956 -0.221 0.118 0.968 1.409 3.256 3.883 -0.228 0.181 -0.957 1.409 3.256 7.287 -0.481 -0.007 0.877 1.409 3.256 8.627 -0.210 -0.013 -0.978 1.520 3.034 12.307 -0.203 0.835 0.512 1.409 3.256 11.939 -0.234 0.438 0.868 1.409 3.255 12.991 -0.246 0.265 -0.932 1.283 3.507 3.335 0.969 0.198 0.149 1.283 3.507 3.508 0.972 0.210 -0.102 1.215 3.507 7.521 -0.342 -0.772 0.535 1.283 3.507 7.487 -0.432 -0.714 0.551 1.283 3.507 8.573 -0.362 -0.731 -0.578 1.283 3.507 11.898 -0.344 -0.148 0.927 1.158 3.757 2.952 0.313 -0.247 0.917 1.158 3.757 3.895 0.249 -0.266 -0.931 1.273 3.527 7.521 -0.433 -0.728 0.532 1.182 3.710 8.205 -0.363 -0.926 -0.107 1.158 3.757 12.069 -0.445 -0.639 0.627 1.233 3.608 12.991 -0.336 -0.209 -0.918 1.158 3.757 12.734 -0.542 -0.757 -0.365 1.042 3.990 3.419 -0.213 -0.977 0.006 1.097 3.879 12.307 -0.448 -0.748 0.489 0.710 4.508 5.470 -0.029 0.995 0.095 0.746 4.508 10.256 0.170 0.985 0.005 0.666 4.741 1.367 0.000 0.996 -0.094 0.657 4.759 1.297 -0.006 1.000 -0.015 0.657 4.759 1.406 -0.001 0.994 -0.106 0.760 4.552 5.470 -0.136 0.985 0.102 0.657 4.759 5.107 0.006 0.914 0.405 0.636 4.759 6.154 -0.228 0.805 -0.547 0.657 4.759 6.121 -0.257 0.829 -0.497 0.776 4.520 10.256 0.115 0.993 0.004 0.657 4.759 9.795 0.306 0.837 0.453 0.657 4.759 10.721 0.292 0.837 -0.463 3.114 0.000 0.684 -0.022 0.528 0.849 3.122 0.250 0.684 -0.387 -0.006 0.922 3.254 0.000 0.996 -0.156 0.890 0.427 3.128 0.250 0.693 -0.395 0.004 0.919 3.254 0.000 1.589 -0.162 0.969 -0.184 3.128 0.250 1.749 -0.748 -0.001 -0.663 3.254 0.000 5.208 -0.951 0.044 0.307 3.128 0.250 5.349 -0.783 -0.611 0.116 3.130 0.000 6.154 -0.778 -0.237 -0.581 3.254 0.000 5.903 -0.969 0.052 -0.241 3.128 0.250 5.682 -0.799 -0.602 -0.009 3.052 0.000 10.256 0.559 0.829 0.000 3.254 0.000 9.756 0.466 0.479 0.744 3.128 0.250 9.772 -0.483 -0.602 0.636 3.254 0.000 10.757 0.465 0.484 -0.741 3.128 0.250 10.738 -0.477 -0.619 -0.624 3.003 0.501 0.883 -0.589 -0.460 0.665 3.003 0.501 1.631 -0.742 -0.617 -0.263 3.093 0.321 5.470 -0.764 -0.641 0.080 3.003 0.501 10.042 -0.501 -0.860 0.099 3.003 0.501 10.464 -0.497 -0.862 -0.105 2.930 0.648 1.367 -0.672 -0.734 -0.101 2.959 0.589 10.256 -0.491 -0.871 -0.007 1.588 3.006 3.419 0.069 0.998 -0.006 1.559 3.006 7.521 -0.210 0.779 0.591 1.761 2.985 8.205 -0.478 0.871 -0.113 1.751 3.006 8.126 -0.493 0.867 -0.077 1.751 3.006 8.244 -0.489 0.863 -0.126 1.711 3.085 3.419 -0.106 0.994 -0.005 1.626 3.256 3.038 -0.298 0.863 0.407 1.626 3.256 3.797 -0.287 0.871 -0.399 1.610 3.256 7.521 -0.749 0.216 0.627 1.626 3.256 7.549 -0.775 0.247 0.581 1.626 3.256 8.557 -0.695 0.399 -0.598 1.609 3.256 12.307 -0.623 0.575 0.530 1.409 3.256 12.991 -0.246 0.264 -0.932 1.500 3.507 2.935 0.343 0.303 0.889 1.500 3.507 3.906 0.322 0.323 -0.890 1.341 3.507 7.521 -0.510 -0.658 0.554 1.500 3.507 7.629 -0.787 -0.465 0.405 1.500 3.507 8.521 -0.790 -0.488 -0.372 1.605 3.298 12.307 -0.692 0.489 0.531 1.500 3.507 12.086 -0.722 0.090 0.686 1.363 3.507 12.991 -0.372 -0.063 -0.926 1.500 3.507 12.696 -0.949 0.090 -0.302 1.375 3.757 2.936 -0.478 -0.485 0.732 1.375 3.757 3.906 -0.489 -0.477 -0.730 1.398 3.710 8.205 -0.644 -0.759 -0.099 1.375 3.757 12.231 -0.722 -0.444 0.530 1.375 3.757 12.441 -0.799 -0.490 0.349 1.110 4.007 3.419 -0.320 -0.947 0.004 1.250 4.007 3.290 -0.461 -0.886 0.049 1.250 4.007 3.550 -0.463 -0.885 -0.044 1.352 3.804 12.307 -0.715 -0.486 0.503 1.224 4.059 3.419 -0.456 -0.890 0.003 0.680 4.759 1.367 -0.019 0.995 -0.094 0.863 4.759 5.470 -0.532 0.842 0.094 0.947 4.613 10.256 -0.006 1.000 0.001 0.874 4.759 9.903 0.060 0.977 0.206 0.874 4.759 10.610 0.055 0.977 -0.206 3.367 0.000 1.367 -0.237 0.968 -0.081 3.350 0.242 1.367 -0.953 0.287 -0.097 3.345 0.250 1.350 -0.961 0.267 -0.076 3.345 0.250 1.378 -0.959 0.265 -0.101 3.387 0.000 5.470 -0.980 0.169 0.108 3.204 0.250 5.470 -0.822 -0.563 0.079 3.471 0.000 9.906 -0.520 0.806 0.281 3.345 0.250 9.861 -0.839 -0.447 0.309 3.471 0.000 10.606 -0.515 0.810 -0.280 3.345 0.250 10.652 -0.837 -0.452 -0.309 3.192 0.501 1.367 -0.912 -0.398 -0.100 3.328 0.286 1.367 -0.978 0.183 -0.099 3.220 0.501 10.197 -0.748 -0.664 0.016 3.220 0.501 10.315 -0.747 -0.665 -0.020 3.207 0.527 10.256 -0.741 -0.672 -0.003 1.769 3.006 8.205 -0.495 0.862 -0.113 1.802 3.256 3.419 -0.520 0.854 -0.002 1.808 3.256 8.205 -0.917 0.378 -0.125 1.814 3.313 3.419 -0.631 0.775 -0.001 1.717 3.507 3.082 -0.775 0.556 0.301 1.717 3.507 3.757 -0.769 0.564 -0.300 1.705 3.507 8.205 -0.980 -0.169 -0.110 1.609 3.507 12.307 -0.811 0.129 0.571 1.592 3.757 3.037 -0.896 -0.280 0.344 1.592 3.757 3.804 -0.896 -0.279 -0.345 1.422 3.757 12.307 -0.752 -0.416 0.512 1.465 4.007 3.419 -0.713 -0.702 0.002 1.467 4.007 3.419 -0.715 -0.699 0.002 1.033 4.759 10.256 -0.283 0.959 0.000 3.350 0.250 1.367 -0.959 0.267 -0.097 3.613 0.000 10.256 -0.622 0.783 0.000 3.531 0.250 10.256 -0.982 -0.191 0.001 3.254 0.501 10.256 -0.765 -0.644 -0.002 2.868 1.503 8.205 0.989 -0.079 -0.125 3.033 1.310 8.205 0.924 0.366 -0.112 2.936 1.503 7.919 0.997 -0.056 0.053 2.936 1.503 8.348 0.979 -0.059 -0.194 2.865 1.646 8.205 0.920 -0.372 -0.126 2.128 3.006 1.367 0.991 -0.063 -0.120 2.264 2.846 1.367 0.948 0.295 -0.116 2.185 3.006 1.133 0.973 -0.049 0.227 2.185 3.006 1.488 0.984 -0.046 -0.172 2.121 3.133 1.367 0.947 -0.297 -0.120 1.857 3.507 3.419 -0.877 0.481 0.002 1.773 3.757 3.419 -0.997 -0.082 0.003 3.403 1.002 3.419 0.735 0.678 -0.003 3.403 1.002 3.419 0.735 0.678 -0.003 3.403 1.002 3.419 0.735 0.678 -0.003 3.403 1.002 3.419 0.735 0.678 -0.003 3.069 1.252 3.419 0.994 0.111 -0.015 3.278 1.252 3.011 0.899 0.309 0.310 3.278 1.252 3.812 0.910 0.285 -0.303 3.094 1.252 8.205 0.843 0.528 -0.104 3.333 1.144 8.205 0.660 0.745 -0.095 3.278 1.252 7.816 0.689 0.714 0.127 3.278 1.252 8.412 0.698 0.688 -0.196 2.977 1.503 3.419 0.927 -0.373 -0.019 3.153 1.503 3.015 0.870 -0.358 0.339 3.153 1.503 3.801 0.873 -0.365 -0.323 3.081 1.503 7.521 0.822 0.120 0.556 3.197 1.415 7.521 0.765 0.340 0.547 3.153 1.503 7.424 0.785 0.167 0.596 3.153 1.503 8.602 0.799 0.194 -0.569 3.131 1.503 12.307 0.849 0.181 0.496 3.169 1.470 12.307 0.841 0.223 0.493 3.153 1.503 12.266 0.843 0.187 0.505 3.153 1.503 12.402 0.893 0.204 0.402 3.030 1.748 3.419 0.453 -0.891 -0.019 3.055 1.699 7.521 0.674 -0.409 0.616 2.848 1.753 8.205 0.772 -0.625 -0.120 3.028 1.753 7.555 0.610 -0.588 0.531 3.028 1.753 8.546 0.717 -0.570 -0.401 3.048 1.712 12.307 0.797 -0.232 0.558 2.930 1.948 8.205 0.360 -0.926 -0.116 2.370 2.755 1.367 0.805 0.583 -0.105 2.569 2.670 1.367 0.633 0.768 -0.098 2.527 2.755 1.040 0.634 0.697 0.333 2.527 2.755 1.536 0.668 0.725 -0.168 2.351 3.006 0.684 0.437 0.075 0.896 2.434 2.940 0.684 0.421 0.158 0.893 2.402 3.006 0.613 0.425 0.094 0.900 2.402 3.006 1.759 0.823 0.207 -0.529 2.396 3.006 5.470 0.965 0.237 0.110 2.406 2.998 5.470 0.962 0.248 0.110 2.402 3.006 5.459 0.964 0.240 0.113 2.402 3.006 5.492 0.966 0.239 0.101 2.291 3.006 10.256 0.851 0.525 -0.006 2.445 2.920 10.256 0.759 0.651 -0.007 2.402 3.006 10.071 0.797 0.601 0.067 2.402 3.006 10.435 0.796 0.601 -0.074 2.318 3.172 0.684 0.381 -0.139 0.914 2.098 3.256 1.367 0.812 -0.571 -0.118 2.276 3.256 0.725 0.387 -0.296 0.873 2.276 3.256 1.705 0.751 -0.529 -0.395 2.322 3.165 5.470 0.988 -0.094 0.118 2.076 3.256 10.256 0.999 -0.049 -0.001 2.276 3.256 9.845 0.933 0.121 0.338 2.276 3.256 10.665 0.933 0.135 -0.332 2.170 3.468 1.367 0.420 -0.901 -0.113 2.015 3.507 10.256 0.863 -0.506 0.002 2.151 3.507 9.928 0.831 -0.513 0.215 2.151 3.507 10.586 0.835 -0.507 -0.215 2.065 3.678 10.256 0.588 -0.809 0.003 3.642 0.958 3.419 0.442 0.897 -0.001 3.620 1.002 3.308 0.446 0.894 0.037 3.620 1.002 3.528 0.447 0.894 -0.040 3.495 1.252 2.938 0.223 0.533 0.816 3.495 1.252 3.892 0.244 0.506 -0.827 3.547 1.148 8.205 0.228 0.968 -0.109 3.495 1.252 7.823 0.220 0.965 0.144 3.495 1.252 8.416 0.190 0.950 -0.248 3.370 1.503 2.944 -0.518 -0.204 0.831 3.370 1.503 3.876 -0.521 -0.248 -0.817 3.441 1.361 7.521 0.301 0.767 0.566 3.370 1.503 7.316 0.339 0.542 0.769 3.370 1.503 8.625 -0.199 0.490 -0.849 3.471 1.301 12.307 0.612 0.650 0.451 3.370 1.503 11.982 0.643 0.364 0.674 3.370 1.503 12.941 0.478 0.311 -0.821 3.032 1.753 3.419 0.442 -0.897 -0.019 3.245 1.753 3.001 0.613 -0.654 0.444 3.245 1.753 3.819 0.651 -0.631 -0.422 3.047 1.753 7.521 0.561 -0.569 0.601 3.245 1.753 7.303 0.327 -0.470 0.820 3.245 1.753 8.638 -0.196 -0.385 -0.902 3.030 1.753 12.307 0.763 -0.323 0.560 3.245 1.753 11.933 0.606 -0.167 0.777 3.197 1.753 12.991 0.398 -0.107 -0.911 3.324 1.595 12.991 0.405 0.131 -0.905 3.151 1.941 3.419 0.184 -0.983 -0.013 3.164 1.915 7.521 0.151 -0.795 0.588 2.976 2.004 8.205 0.203 -0.973 -0.108 3.119 2.004 7.757 0.146 -0.969 0.201 3.119 2.004 8.441 0.256 -0.931 -0.261 3.058 2.004 12.307 0.423 -0.738 0.526 3.119 2.004 12.186 0.427 -0.713 0.556 3.212 1.819 12.991 0.359 -0.167 -0.918 3.119 2.004 12.576 0.476 -0.871 0.124 3.064 2.115 8.205 0.125 -0.986 -0.114 3.088 2.066 12.307 0.385 -0.765 0.517 2.778 2.687 1.367 0.185 0.977 -0.109 2.744 2.755 1.077 0.195 0.938 0.286 2.744 2.755 1.513 0.167 0.970 -0.176 2.684 2.874 0.684 0.178 0.417 0.891 2.618 3.006 0.493 0.175 0.279 0.944 2.618 3.006 1.792 -0.098 0.498 -0.862 2.709 2.825 5.470 0.684 0.722 0.104 2.618 3.006 5.161 0.812 0.499 0.303 2.618 3.006 6.054 0.788 0.486 -0.378 2.678 2.886 10.256 0.414 0.910 -0.004 2.618 3.006 9.976 0.427 0.885 0.186 2.618 3.006 10.533 0.442 0.878 -0.184 2.299 3.256 0.684 0.333 -0.263 0.905 2.493 3.256 0.455 0.210 -0.208 0.955 2.493 3.256 1.788 -0.312 -0.375 -0.873 2.278 3.256 5.470 0.943 -0.311 0.117 2.493 3.256 5.092 0.866 -0.158 0.475 2.480 3.256 6.154 0.792 -0.173 -0.586 2.518 3.206 6.154 0.803 -0.053 -0.594 2.493 3.256 6.175 0.788 -0.167 -0.592 2.493 3.256 9.781 -0.087 0.435 0.896 2.493 3.256 10.732 -0.031 0.455 -0.890 2.406 3.430 0.684 0.111 -0.420 0.901 2.196 3.507 1.367 0.311 -0.944 -0.110 2.368 3.507 0.861 0.138 -0.685 0.715 2.368 3.507 1.642 0.341 -0.878 -0.335 2.281 3.507 5.470 0.591 -0.799 0.112 2.368 3.507 5.293 0.601 -0.775 0.193 2.483 3.276 6.154 0.780 -0.203 -0.592 2.368 3.507 5.788 0.579 -0.811 -0.087 2.368 3.507 9.785 0.034 -0.416 0.909 2.368 3.507 10.730 0.058 -0.405 -0.912 2.299 3.644 1.367 0.128 -0.985 -0.116 2.321 3.601 5.470 0.498 -0.861 0.108 2.097 3.757 10.256 0.467 -0.884 0.003 2.243 3.757 9.936 0.617 -0.753 0.227 2.243 3.757 10.579 0.615 -0.755 -0.226 2.174 3.895 10.256 0.366 -0.931 0.002 surface_Al2O3_3 604 678 4 1 3 4 2 4 1 5 6 2 5 7 9 4 3 8 5 7 10 6 5 8 3 11 12 13 3 11 12 14 4 15 17 18 16 4 15 19 20 16 5 7 9 23 22 21 5 7 10 25 24 21 5 11 13 27 28 26 5 11 14 29 30 26 4 17 31 32 18 5 33 35 20 19 34 4 36 22 23 37 4 36 24 25 37 4 27 38 39 28 4 29 40 41 30 4 31 42 43 32 5 33 35 46 45 44 4 47 38 39 48 4 47 40 41 48 4 49 42 43 50 4 49 45 46 50 3 51 52 53 3 51 52 54 3 55 56 57 3 55 56 58 3 59 60 61 6 59 60 53 51 62 63 5 51 54 64 65 62 5 55 57 67 68 66 5 55 58 69 70 66 4 71 73 74 72 4 71 75 76 72 3 59 77 61 5 59 63 79 78 77 4 64 80 81 65 4 67 82 83 68 4 69 84 85 70 5 86 88 74 73 87 5 86 89 76 75 87 4 90 78 79 91 4 90 80 81 91 4 92 82 83 93 4 92 84 85 93 5 86 88 96 95 94 5 86 89 98 97 94 4 99 95 96 100 4 99 97 98 100 3 101 2 4 3 101 2 6 5 101 4 9 103 102 5 101 6 10 104 102 3 105 16 18 3 105 16 20 4 9 23 106 103 4 10 25 107 104 3 108 26 28 3 108 26 30 5 105 18 32 110 109 5 105 20 35 111 109 4 37 23 106 112 4 37 25 107 112 4 108 28 39 113 4 108 30 41 113 4 32 43 114 110 4 35 46 115 111 3 113 48 39 3 113 48 41 4 50 43 114 116 4 50 46 115 116 3 117 62 63 3 117 62 65 4 66 68 119 118 4 66 70 120 118 3 121 72 74 3 121 72 76 4 117 63 79 122 4 117 65 81 122 4 68 83 123 119 4 70 85 124 120 5 121 74 88 126 125 5 121 76 89 127 125 3 122 91 79 3 122 91 81 4 93 83 123 128 4 93 85 124 128 4 88 96 129 126 4 89 98 130 127 4 100 96 129 131 4 100 98 130 131 3 132 102 103 3 132 102 104 4 132 103 106 133 4 132 104 107 133 3 134 109 110 3 134 109 111 3 133 112 106 3 133 112 107 4 134 110 114 135 4 134 111 115 135 3 135 116 114 3 135 116 115 3 136 118 119 3 136 118 120 4 136 119 123 137 4 136 120 124 137 3 138 125 126 3 138 125 127 3 137 128 123 3 137 128 124 4 138 126 129 139 4 138 127 130 139 3 139 131 129 3 139 131 130 3 140 141 142 3 140 141 143 3 144 145 146 3 144 145 147 4 144 146 149 148 4 144 147 150 148 3 148 151 149 3 148 151 150 3 152 153 154 3 152 153 155 5 156 158 157 142 141 5 156 160 159 143 141 3 161 162 163 3 161 162 164 3 156 165 158 3 156 165 160 4 145 146 167 166 4 145 147 168 166 3 169 170 171 3 169 170 172 4 146 149 173 167 4 147 150 174 168 4 169 171 176 175 4 169 172 177 175 5 178 179 173 149 151 5 178 180 174 150 151 3 175 181 176 3 175 181 177 3 178 182 179 3 178 182 180 3 183 184 185 3 183 184 186 4 153 154 188 187 4 153 155 189 187 4 183 185 191 190 4 183 186 192 190 5 193 157 158 195 194 5 193 159 160 196 194 5 197 199 198 163 162 5 197 201 200 164 162 3 202 203 204 3 202 203 205 4 165 158 195 206 4 165 160 196 206 3 197 207 199 3 197 207 201 4 166 167 209 208 4 166 168 210 208 3 211 212 213 3 211 212 214 4 170 171 216 215 4 170 172 217 215 5 218 173 167 209 219 5 218 174 168 210 219 4 211 213 221 220 4 211 214 222 220 4 171 176 223 216 4 172 177 224 217 5 218 173 179 226 225 5 218 174 180 227 225 3 220 228 221 3 220 228 222 5 229 230 223 176 181 5 229 231 224 177 181 4 182 179 226 232 4 182 180 227 232 3 229 233 230 3 229 233 231 4 184 185 235 234 4 184 186 236 234 4 187 188 238 237 4 187 189 239 237 3 240 241 242 3 240 241 243 4 185 191 244 235 4 186 192 245 236 5 246 247 248 195 194 5 246 249 250 196 194 4 198 199 252 251 4 200 201 254 253 5 255 257 256 204 203 5 255 259 258 205 203 4 206 195 248 260 4 206 196 250 260 4 207 199 252 261 4 207 201 254 261 3 255 262 257 3 255 262 259 4 208 209 264 263 4 208 210 265 263 4 212 213 267 266 4 212 214 268 266 4 215 216 270 269 4 215 217 271 269 5 272 273 264 209 219 5 272 274 265 210 219 4 213 221 275 267 4 214 222 276 268 4 216 223 277 270 5 278 224 217 271 279 3 278 279 280 5 272 273 281 226 225 5 272 274 282 227 225 5 283 284 275 221 228 5 283 285 276 222 228 4 223 230 286 277 5 278 224 231 288 287 3 278 287 280 4 232 226 281 289 4 232 227 282 289 3 283 290 284 3 283 290 285 4 233 230 286 291 4 233 231 288 291 3 292 234 235 3 292 234 236 4 237 238 294 293 4 237 239 295 293 3 296 241 242 3 296 241 243 5 292 235 244 298 297 5 292 236 245 299 297 4 247 248 301 300 4 249 250 303 302 4 251 252 305 304 4 253 254 307 306 4 256 257 309 308 4 258 259 311 310 4 260 248 301 312 4 260 250 303 312 5 313 314 305 252 261 5 313 315 307 254 261 4 262 257 309 316 4 262 259 311 316 3 313 317 314 3 313 317 315 3 318 263 264 3 318 263 265 4 266 267 320 319 4 266 268 321 319 3 322 269 270 3 322 269 271 5 318 264 273 324 323 5 318 265 274 325 323 4 267 275 326 320 4 268 276 327 321 5 322 270 277 329 328 6 322 328 331 330 279 271 3 330 279 280 4 273 281 332 324 4 274 282 333 325 4 275 284 334 326 4 276 285 335 327 4 277 286 336 329 5 330 331 337 288 287 3 330 287 280 4 289 281 332 338 4 289 282 333 338 4 290 284 334 339 4 290 285 335 339 4 291 286 336 340 4 291 288 337 340 3 341 293 294 3 341 293 295 4 297 298 343 342 4 297 299 344 342 4 345 300 301 346 4 345 302 303 346 5 347 304 305 349 348 5 347 306 307 350 348 4 351 308 309 352 4 351 310 311 352 3 346 312 301 3 346 312 303 5 353 314 305 349 354 5 353 315 307 350 354 3 352 316 309 3 352 316 311 3 353 317 314 3 353 317 315 3 355 319 320 3 355 319 321 3 356 323 324 3 356 323 325 5 355 320 326 358 357 5 355 321 327 359 357 3 360 328 329 3 360 328 331 4 356 324 332 361 4 356 325 333 361 4 326 334 362 358 4 327 335 363 359 4 360 329 336 364 4 360 331 337 364 3 361 338 332 3 361 338 333 4 339 334 362 365 4 339 335 363 365 3 364 340 336 3 364 340 337 3 366 342 343 3 366 342 344 3 367 348 349 3 367 348 350 3 367 354 349 3 367 354 350 3 368 357 358 3 368 357 359 4 368 358 362 369 4 368 359 363 369 3 369 365 362 3 369 365 363 3 370 371 372 3 370 371 373 4 370 372 375 374 4 370 373 376 374 3 374 377 375 3 374 377 376 3 378 379 380 3 378 379 381 4 382 384 385 383 4 382 386 387 383 3 388 389 390 3 388 389 391 3 392 393 394 3 392 393 395 3 383 396 385 3 383 396 387 3 397 398 399 3 397 398 400 4 371 372 402 401 4 371 373 403 401 3 404 405 406 3 404 405 407 4 397 399 409 408 4 397 400 410 408 4 372 375 411 402 4 373 376 412 403 4 404 406 414 413 4 404 407 415 413 3 408 416 409 3 408 416 410 5 417 418 411 375 377 5 417 419 412 376 377 3 413 420 414 3 413 420 415 3 417 421 418 3 417 421 419 3 422 423 424 3 422 423 425 3 426 427 428 3 426 427 429 5 422 424 430 380 379 5 422 425 431 381 379 3 432 433 434 3 432 433 435 4 384 385 437 436 4 386 387 439 438 4 389 390 441 440 4 389 391 442 440 5 443 445 444 394 393 5 443 447 446 395 393 4 396 385 437 448 4 396 387 439 448 3 443 449 445 3 443 449 447 4 398 399 451 450 4 398 400 452 450 4 401 402 454 453 4 401 403 455 453 4 405 406 457 456 4 405 407 458 456 3 459 460 461 5 459 409 399 451 460 4 400 410 462 452 4 402 411 463 454 4 403 412 464 455 4 406 414 465 457 4 407 415 466 458 3 459 467 461 6 459 467 469 468 416 409 5 468 470 462 410 416 4 411 418 471 463 4 412 419 472 464 5 473 474 465 414 420 5 473 475 466 415 420 3 468 476 469 3 468 476 470 4 421 418 471 477 4 421 419 472 477 3 473 478 474 3 473 478 475 3 479 423 424 3 479 423 425 4 427 428 481 480 4 427 429 482 480 5 479 424 430 484 483 5 479 425 431 485 483 4 433 434 487 486 4 433 435 488 486 4 436 437 490 489 4 438 439 492 491 5 493 495 494 441 440 5 493 497 496 442 440 5 498 444 445 500 499 5 498 446 447 501 499 5 502 503 490 437 448 5 502 504 492 439 448 3 493 505 495 3 493 505 497 4 449 445 500 506 4 449 447 501 506 3 502 507 503 3 502 507 504 4 450 451 509 508 4 450 452 510 508 3 511 453 454 3 511 453 455 4 456 457 513 512 4 456 458 514 512 3 515 460 461 5 515 516 509 451 460 4 452 462 517 510 5 511 454 463 519 518 5 511 455 464 520 518 5 521 465 457 513 522 5 521 466 458 514 522 3 515 467 461 5 515 516 523 469 467 4 462 470 524 517 4 463 471 525 519 4 464 472 526 520 5 521 465 474 528 527 5 521 466 475 529 527 4 476 469 523 530 4 476 470 524 530 4 477 471 525 531 4 477 472 526 531 4 478 474 528 532 4 478 475 529 532 3 533 480 481 3 533 480 482 4 483 484 535 534 4 483 485 536 534 4 486 487 538 537 4 486 488 539 537 5 540 489 490 542 541 5 540 491 492 543 541 4 544 494 495 545 4 544 496 497 545 5 546 547 548 500 499 5 546 549 550 501 499 4 490 503 551 542 4 492 504 552 543 3 545 505 495 3 545 505 497 4 506 500 548 553 4 506 501 550 553 4 507 503 551 554 4 507 504 552 554 3 555 508 509 3 555 508 510 4 512 513 557 556 4 512 514 558 556 5 555 509 516 560 559 5 555 510 517 561 559 3 562 518 519 3 562 518 520 5 563 564 557 513 522 5 563 565 558 514 522 4 516 523 566 560 4 517 524 567 561 4 562 519 525 568 4 562 520 526 568 5 563 564 569 528 527 5 563 565 570 529 527 4 530 523 566 571 4 530 524 567 571 3 568 531 525 3 568 531 526 4 532 528 569 572 4 532 529 570 572 3 573 534 535 3 573 534 536 4 537 538 575 574 4 537 539 576 574 3 577 541 542 3 577 541 543 4 547 548 579 578 4 549 550 581 580 4 577 542 551 582 4 577 543 552 582 4 553 548 579 583 4 553 550 581 583 3 582 554 551 3 582 554 552 3 584 556 557 3 584 556 558 3 585 559 560 3 585 559 561 5 584 557 564 587 586 5 584 558 565 588 586 4 585 560 566 589 4 585 561 567 589 4 564 569 590 587 4 565 570 591 588 3 589 571 566 3 589 571 567 4 572 569 590 592 4 572 570 591 592 3 593 574 575 3 593 574 576 4 594 578 579 595 4 594 580 581 595 3 595 583 579 3 595 583 581 3 596 586 587 3 596 586 588 4 596 587 590 597 4 596 588 591 597 3 597 592 590 3 597 592 591 3 598 599 600 3 598 599 601 4 598 600 603 602 4 598 601 604 602 3 605 606 607 3 605 606 608 3 602 609 603 3 602 609 604 4 605 607 611 610 4 605 608 612 610 3 610 613 611 3 610 613 612 3 614 615 616 3 614 615 617 4 614 616 619 618 4 614 617 620 618 3 621 622 623 3 621 622 624 3 618 625 619 3 618 625 620 4 621 623 627 626 4 621 624 628 626 3 626 629 627 3 626 629 628 4 599 600 631 630 4 599 601 632 630 4 600 603 633 631 4 601 604 634 632 4 606 607 636 635 4 606 608 637 635 3 638 639 640 3 638 639 641 5 642 643 633 603 609 5 642 644 634 604 609 4 607 611 645 636 4 608 612 646 637 4 638 640 648 647 4 638 641 649 647 3 642 650 643 3 642 650 644 4 613 611 645 651 4 613 612 646 651 3 647 652 648 3 647 652 649 4 615 616 654 653 4 615 617 655 653 3 656 657 658 3 656 657 659 4 616 619 660 654 4 617 620 661 655 4 656 658 663 662 4 656 659 664 662 4 622 623 666 665 4 622 624 667 665 5 668 669 660 619 625 5 668 670 661 620 625 3 662 671 663 3 662 671 664 4 623 627 672 666 4 624 628 673 667 3 668 674 669 3 668 674 670 5 675 676 672 627 629 5 675 677 673 628 629 3 675 678 676 3 675 678 677 -0.557 1.114 3.419 -0.119 0.993 -0.003 -0.399 1.231 3.419 -0.632 0.775 -0.002 -0.626 1.252 3.135 -0.746 0.056 0.663 -0.409 1.252 3.369 -0.659 0.752 0.020 -0.626 1.252 3.701 -0.746 0.038 -0.665 -0.409 1.252 3.468 -0.659 0.751 -0.025 -0.657 1.503 3.419 0.999 0.049 -0.003 -0.700 1.400 3.419 0.997 -0.072 -0.003 -0.535 1.503 3.144 0.261 0.736 0.625 -0.535 1.503 3.691 0.274 0.733 -0.623 -0.587 1.503 8.205 -0.579 0.803 -0.141 -0.685 1.370 8.205 -0.249 0.954 -0.165 -0.751 1.503 7.769 -0.455 0.839 0.297 -0.751 1.503 8.426 -0.431 0.782 -0.450 -0.703 1.405 12.307 0.285 0.692 0.663 -0.527 1.487 12.307 -0.269 0.721 0.638 -0.751 1.503 12.129 0.269 0.541 0.797 -0.535 1.503 12.276 -0.281 0.705 0.652 -0.751 1.503 12.654 0.387 0.909 -0.154 -0.535 1.503 12.365 -0.291 0.762 0.579 -0.809 1.619 3.419 0.999 0.043 -0.004 -0.877 1.753 3.163 0.732 0.391 0.559 -0.660 1.753 3.135 0.445 -0.695 0.565 -0.877 1.753 3.670 0.748 0.382 -0.543 -0.660 1.753 3.702 0.477 -0.676 -0.562 -0.569 1.572 8.205 -0.764 0.631 -0.132 -0.877 1.753 7.543 -0.631 -0.156 0.760 -0.660 1.753 7.844 -0.970 0.189 0.151 -0.877 1.753 8.467 0.597 -0.181 -0.782 -0.660 1.753 8.398 -0.946 0.175 -0.272 -0.877 1.753 12.048 0.157 0.042 0.987 -0.660 1.753 12.052 0.235 0.258 0.937 -0.795 1.753 12.991 0.072 0.111 -0.991 -0.869 1.739 12.991 0.254 0.060 -0.965 -0.660 1.753 12.952 -0.225 0.252 -0.941 -0.959 1.918 3.419 0.286 -0.958 -0.009 -0.781 1.995 3.419 -0.421 -0.907 0.003 -1.002 2.004 7.915 -0.288 -0.954 0.086 -0.785 2.004 8.041 -0.850 -0.526 -0.031 -1.002 2.004 8.358 -0.228 -0.924 -0.308 -0.785 2.004 8.292 -0.841 -0.520 -0.153 -1.002 2.004 12.100 -0.036 -0.522 0.852 -0.785 2.004 12.047 0.076 -0.349 0.934 -0.886 1.771 12.991 0.254 0.003 -0.967 -1.002 2.004 12.723 0.154 -0.861 -0.485 -0.785 2.004 12.879 -0.187 -0.416 -0.890 -1.041 2.082 8.205 -0.245 -0.956 -0.162 -0.810 2.055 8.205 -0.813 -0.570 -0.116 -1.059 2.118 12.307 -0.002 -0.736 0.677 -0.878 2.190 12.307 -0.084 -0.754 0.652 -1.363 3.006 1.367 -0.530 0.833 -0.160 -1.446 2.892 1.367 -0.318 0.933 -0.170 -1.503 3.006 0.952 -0.330 0.631 0.702 -1.503 3.006 1.574 -0.539 0.753 -0.377 -1.319 3.006 5.470 -0.202 0.969 0.140 -1.464 2.927 5.470 0.309 0.938 0.159 -1.503 3.006 5.316 0.313 0.901 0.301 -1.503 3.006 5.760 0.319 0.944 -0.085 -1.614 3.256 0.684 -0.293 -0.026 0.956 -1.619 3.238 0.684 -0.277 -0.003 0.961 -1.628 3.256 0.670 -0.285 -0.035 0.958 -1.334 3.101 1.367 -0.752 0.640 -0.158 -1.411 3.256 0.984 -0.779 0.207 0.592 -1.628 3.256 1.627 0.616 -0.087 -0.783 -1.411 3.256 1.556 -0.924 0.257 -0.284 -1.296 3.025 5.470 -0.255 0.956 0.144 -1.628 3.256 5.208 0.621 0.177 0.764 -1.411 3.256 5.202 0.293 0.582 0.758 -1.628 3.256 6.131 0.600 0.161 -0.783 -1.411 3.256 6.088 -0.343 0.608 -0.716 -1.546 3.091 10.256 0.219 0.976 0.009 -1.368 3.170 10.256 -0.573 0.819 0.014 -1.628 3.256 10.005 0.812 -0.335 0.478 -1.411 3.256 10.072 -0.751 0.645 0.144 -1.628 3.256 10.512 0.834 -0.316 -0.452 -1.411 3.256 10.448 -0.745 0.655 -0.128 -1.635 3.271 0.684 -0.282 -0.059 0.958 -1.753 3.507 1.021 -0.243 -0.765 0.596 -1.536 3.507 1.147 -0.843 -0.493 0.216 -1.753 3.507 1.546 -0.194 -0.906 -0.377 -1.536 3.507 1.481 -0.856 -0.485 -0.179 -1.753 3.507 5.248 -0.342 -0.814 0.469 -1.536 3.507 5.221 0.296 -0.680 0.670 -1.753 3.507 5.905 0.119 -0.936 -0.331 -1.536 3.507 6.061 -0.322 -0.700 -0.637 -1.649 3.507 10.256 0.995 0.096 0.006 -1.695 3.391 10.256 0.999 -0.050 0.005 -1.536 3.507 10.013 0.918 0.246 0.310 -1.536 3.507 10.509 0.927 0.232 -0.293 -1.802 3.604 1.367 -0.235 -0.957 -0.170 -1.572 3.577 1.367 -0.819 -0.561 -0.121 -1.820 3.639 5.470 -0.076 -0.983 0.170 -1.643 3.720 5.470 -0.140 -0.977 0.162 -1.805 3.610 10.256 0.997 0.076 0.004 -1.879 3.757 9.974 0.552 -0.048 0.832 -1.662 3.757 9.969 -0.217 -0.806 0.551 -1.879 3.757 10.540 0.550 -0.071 -0.832 -1.662 3.757 10.547 -0.203 -0.821 -0.533 -1.948 3.895 10.256 0.046 -0.999 0.003 -1.747 3.927 10.256 -0.397 -0.918 0.003 -0.387 1.252 3.419 -0.647 0.762 -0.002 -0.300 1.467 3.419 -0.651 0.759 -0.002 -0.318 1.503 3.351 -0.680 0.732 0.038 -0.318 1.503 3.486 -0.679 0.733 -0.042 -0.515 1.503 12.307 -0.282 0.719 0.635 -0.443 1.753 3.221 -0.959 -0.223 0.173 -0.443 1.753 3.617 -0.961 -0.217 -0.172 -0.550 1.753 8.205 -0.964 0.229 -0.136 -0.402 1.672 12.307 -0.342 0.626 0.700 -0.443 1.753 12.178 -0.347 0.513 0.785 -0.443 1.753 12.553 -0.585 0.764 0.272 -0.526 1.919 3.419 -0.834 -0.551 0.005 -0.723 2.004 8.205 -0.874 -0.471 -0.119 -0.568 2.004 12.098 -0.532 -0.191 0.825 -0.568 2.004 12.713 -0.847 -0.275 -0.454 -0.658 2.184 12.307 -0.577 -0.552 0.603 -1.303 3.256 1.367 -0.941 0.301 -0.157 -1.159 3.186 5.470 -0.451 0.877 0.168 -1.194 3.256 5.347 -0.524 0.807 0.274 -1.194 3.256 5.703 -0.570 0.822 -0.024 -1.314 3.256 10.256 -0.673 0.740 0.015 -1.455 3.507 1.367 -0.899 -0.419 -0.130 -1.319 3.507 5.258 -0.842 -0.288 0.456 -1.319 3.507 5.893 -0.913 -0.271 -0.304 -1.269 3.405 10.256 -0.632 0.774 0.022 -1.319 3.507 10.098 -0.730 0.661 0.173 -1.319 3.507 10.423 -0.736 0.662 -0.139 -1.420 3.707 5.470 -0.716 -0.685 0.135 -1.445 3.757 10.084 -0.904 -0.409 0.123 -1.445 3.757 10.434 -0.902 -0.417 -0.108 -1.499 3.866 10.256 -0.830 -0.558 0.007 -0.290 1.503 3.419 -0.699 0.715 -0.002 -0.346 1.753 3.419 -0.995 -0.095 0.002 -0.375 1.753 12.307 -0.454 0.539 0.710 -0.428 2.004 12.307 -0.747 -0.068 0.661 -1.130 3.256 5.470 -0.601 0.781 0.172 -1.175 3.507 5.470 -0.984 -0.052 0.171 -1.246 3.507 10.256 -0.813 0.582 0.023 -1.353 3.757 10.256 -0.952 -0.305 0.012 0.837 0.000 3.419 0.488 -0.873 0.000 0.848 0.039 3.419 0.457 -0.889 0.000 0.868 0.000 3.344 0.453 -0.891 0.036 0.868 0.000 3.493 0.453 -0.891 -0.037 0.172 1.252 10.256 0.970 0.245 -0.003 0.290 1.156 10.256 0.882 0.472 -0.002 0.241 1.252 10.108 0.945 0.315 0.086 0.241 1.252 10.403 0.945 0.315 -0.090 0.082 1.503 10.256 0.823 -0.569 -0.002 0.116 1.503 10.174 0.806 -0.590 0.047 0.116 1.503 10.338 0.807 -0.589 -0.051 0.093 1.550 10.256 0.772 -0.636 -0.002 -1.586 4.759 3.419 0.921 0.390 0.000 -1.458 4.651 3.419 0.824 0.566 0.001 -1.512 4.759 3.262 0.877 0.473 0.080 -1.512 4.759 3.575 0.878 0.472 -0.080 0.921 0.250 3.419 -0.015 -1.000 0.000 1.085 0.000 3.112 -0.818 -0.048 0.573 0.959 0.250 3.334 -0.067 -0.997 0.030 1.085 0.000 3.725 -0.818 -0.047 -0.573 0.959 0.250 3.503 -0.068 -0.997 -0.031 1.084 0.000 8.205 0.843 -0.520 -0.140 1.085 0.000 8.205 0.843 -0.520 -0.140 1.085 0.000 8.205 0.843 -0.520 -0.140 1.085 0.000 8.205 0.843 -0.520 -0.140 0.942 0.285 3.419 -0.070 -0.998 -0.001 0.547 1.075 10.256 0.515 0.857 -0.003 0.458 1.252 9.953 0.642 0.657 0.395 0.458 1.252 10.556 0.635 0.661 -0.400 0.271 1.503 5.470 0.887 0.441 0.134 0.364 1.441 5.470 0.797 0.590 0.130 0.333 1.503 5.374 0.835 0.518 0.188 0.333 1.503 5.645 0.852 0.524 0.023 0.333 1.503 9.958 -0.782 -0.402 0.477 0.333 1.503 10.551 -0.788 -0.388 -0.478 0.129 1.753 5.470 0.876 -0.444 0.186 0.208 1.753 5.318 0.807 -0.471 0.357 0.208 1.753 5.753 0.895 -0.436 -0.096 0.138 1.753 10.256 0.401 -0.916 0.001 0.208 1.753 10.106 0.319 -0.941 0.116 0.208 1.753 10.407 0.323 -0.940 -0.114 0.150 1.868 5.470 0.686 -0.705 0.179 0.174 1.821 10.256 0.244 -0.970 0.003 -1.173 4.508 12.307 0.637 0.632 0.443 -1.169 4.506 12.307 0.634 0.634 0.442 -1.170 4.508 12.303 0.635 0.633 0.443 -1.170 4.508 12.315 0.637 0.635 0.436 -1.194 4.557 3.419 0.521 0.854 0.004 -1.295 4.759 3.126 0.586 0.748 0.313 -1.295 4.759 3.712 0.591 0.743 -0.315 -1.404 4.759 12.307 0.703 -0.101 0.704 -1.295 4.759 12.119 0.531 0.000 0.847 -1.295 4.759 12.641 0.987 -0.005 -0.163 1.208 0.000 3.419 0.324 0.946 0.000 1.240 0.124 3.419 0.507 0.862 -0.001 1.176 0.250 3.163 -0.332 -0.927 0.172 1.176 0.250 3.673 -0.337 -0.926 -0.173 1.087 0.250 8.205 0.166 -0.979 -0.119 1.301 0.000 7.704 0.844 0.169 0.508 1.176 0.250 7.922 0.070 -0.995 0.069 1.301 0.000 8.463 0.732 0.389 -0.560 1.176 0.250 8.363 -0.015 -0.978 -0.208 1.113 0.000 12.307 0.193 -0.806 0.560 1.225 0.154 12.307 -0.064 -0.816 0.574 1.301 0.000 12.062 -0.118 -0.676 0.728 1.301 0.000 12.780 -0.041 -0.830 -0.556 1.111 0.382 3.419 -0.257 -0.966 -0.003 1.131 0.340 8.205 0.011 -0.993 -0.114 0.744 1.115 10.256 -0.044 0.999 -0.011 0.675 1.252 9.975 -0.738 0.121 0.664 0.675 1.252 10.531 -0.750 0.105 -0.653 0.360 1.503 1.367 0.986 -0.062 -0.152 0.665 1.274 1.367 0.585 0.801 -0.128 0.550 1.503 0.902 0.515 0.189 0.836 0.550 1.503 1.604 0.761 0.356 -0.542 0.599 1.405 5.470 0.402 0.901 0.163 0.550 1.503 5.293 0.418 0.839 0.348 0.550 1.503 5.815 0.472 0.869 -0.149 0.473 1.503 10.256 -0.955 -0.296 -0.014 0.597 1.408 10.256 -0.986 -0.165 -0.024 0.328 1.753 1.367 0.598 -0.782 -0.174 0.425 1.753 1.035 0.426 -0.648 0.631 0.425 1.753 1.546 0.435 -0.821 -0.369 0.425 1.753 5.212 0.337 0.018 0.942 0.425 1.753 6.130 0.581 0.004 -0.814 0.500 1.602 10.256 -0.704 0.706 -0.080 0.425 1.753 9.991 0.640 0.184 0.746 0.425 1.753 10.520 0.627 0.233 -0.744 0.371 1.861 1.367 0.348 -0.921 -0.172 0.188 2.004 5.470 0.409 -0.897 0.167 0.300 2.004 5.288 0.299 -0.879 0.371 0.300 2.004 5.822 0.281 -0.944 -0.174 0.344 1.914 10.256 0.060 -0.998 0.005 0.250 2.103 5.470 0.171 -0.970 0.173 -0.931 4.465 12.307 0.392 0.798 0.457 -0.953 4.508 12.222 0.390 0.781 0.487 -0.953 4.508 12.469 0.429 0.859 0.280 -1.001 4.604 3.419 0.263 0.965 0.006 -1.078 4.759 3.152 0.344 0.913 0.220 -1.078 4.759 3.689 0.346 0.912 -0.220 -1.120 4.759 8.205 0.611 0.787 -0.086 -1.068 4.740 8.205 0.570 0.817 -0.087 -1.078 4.759 8.137 0.577 0.815 -0.061 -1.078 4.759 8.242 0.573 0.814 -0.098 -1.078 4.759 12.049 0.075 -0.034 0.997 -1.078 4.759 12.935 0.364 0.311 -0.878 1.423 0.000 3.419 0.606 0.796 0.000 1.518 0.000 3.203 0.772 0.628 0.099 1.393 0.250 3.137 -0.490 -0.810 0.324 1.518 0.000 3.634 0.773 0.626 -0.100 1.393 0.250 3.696 -0.494 -0.807 -0.322 1.518 0.000 7.583 0.340 0.740 0.581 1.393 0.250 7.602 -0.167 -0.860 0.483 1.518 0.000 8.472 0.259 0.630 -0.732 1.393 0.250 8.453 -0.112 -0.715 -0.690 1.391 0.250 12.307 -0.300 -0.832 0.467 1.518 0.000 12.040 -0.151 -0.261 0.953 1.393 0.250 12.305 -0.301 -0.831 0.467 1.518 0.000 12.939 -0.278 -0.470 -0.838 1.393 0.250 12.311 -0.302 -0.833 0.463 1.298 0.441 3.419 -0.405 -0.914 -0.007 1.287 0.463 8.205 -0.010 -0.986 -0.164 1.393 0.252 12.307 -0.301 -0.832 0.466 0.913 1.211 10.256 -0.377 0.926 -0.015 0.892 1.252 10.156 -0.450 0.891 0.056 0.892 1.252 10.352 -0.455 0.887 -0.083 0.861 1.315 1.367 0.179 0.968 -0.174 0.767 1.503 0.788 0.166 0.382 0.909 0.767 1.503 1.611 0.240 0.714 -0.657 0.782 1.473 5.470 -0.068 0.983 0.170 0.767 1.503 5.410 -0.096 0.973 0.211 0.767 1.503 5.590 -0.070 0.994 0.088 0.650 1.503 10.256 0.944 0.329 -0.038 0.767 1.503 10.020 0.916 0.319 0.244 0.767 1.503 10.482 0.909 0.325 -0.263 0.642 1.753 0.734 0.055 -0.257 0.965 0.642 1.753 1.627 -0.024 -0.539 -0.842 0.642 1.753 5.213 0.080 0.544 0.836 0.596 1.753 6.154 -0.015 0.369 -0.929 0.643 1.750 6.154 -0.175 0.450 -0.876 0.642 1.753 6.157 -0.178 0.441 -0.879 0.642 1.753 9.975 -0.349 -0.670 0.655 0.642 1.753 10.531 -0.375 -0.629 -0.681 0.495 2.004 1.367 0.089 -0.984 -0.152 0.516 2.004 1.304 0.067 -0.997 -0.046 0.516 2.004 1.401 0.076 -0.982 -0.174 0.516 2.004 5.211 -0.288 -0.705 0.648 0.636 1.764 6.154 -0.191 0.396 -0.898 0.516 2.004 6.032 -0.330 -0.763 -0.556 0.523 1.991 10.256 -0.416 -0.909 0.001 0.508 2.020 1.367 0.061 -0.986 -0.154 0.426 2.185 5.470 -0.282 -0.946 0.162 -0.842 4.508 12.307 0.265 0.838 0.477 -0.823 4.682 3.419 0.102 0.995 0.005 -0.861 4.759 3.253 0.131 0.988 0.077 -0.861 4.759 3.588 0.129 0.989 -0.073 -0.940 4.759 8.205 0.401 0.911 -0.093 -0.759 4.555 12.307 0.103 0.826 0.555 -0.861 4.759 12.049 0.100 0.455 0.885 -0.861 4.759 12.893 0.077 0.589 -0.804 1.735 0.000 3.237 -0.294 0.945 0.145 1.610 0.250 3.191 -0.836 -0.527 0.151 1.735 0.000 3.600 -0.303 0.942 -0.146 1.610 0.250 3.642 -0.833 -0.532 -0.155 1.735 0.000 7.777 -0.141 0.953 0.267 1.610 0.250 7.603 -0.667 -0.445 0.598 1.735 0.000 8.429 -0.346 0.787 -0.511 1.610 0.250 8.471 -0.293 0.016 -0.956 1.735 0.000 12.065 -0.457 -0.155 0.876 1.610 0.250 12.292 -0.554 -0.699 0.452 1.735 0.000 12.774 -0.706 -0.261 -0.658 1.610 0.250 12.337 -0.563 -0.710 0.423 1.529 0.413 3.419 -0.746 -0.666 -0.008 1.353 0.501 8.205 -0.184 -0.972 -0.145 1.485 0.501 8.034 -0.448 -0.894 -0.032 1.485 0.501 8.295 -0.436 -0.876 -0.204 1.606 0.259 12.307 -0.553 -0.702 0.448 1.462 0.546 8.205 -0.431 -0.891 -0.144 0.940 1.252 10.256 -0.438 0.899 -0.016 1.033 1.404 1.367 -0.101 0.979 -0.176 0.984 1.503 1.000 -0.166 0.754 0.636 0.984 1.503 1.548 -0.164 0.912 -0.375 0.808 1.503 5.470 -0.119 0.978 0.169 1.026 1.419 10.256 -0.438 0.899 -0.021 0.984 1.503 10.093 -0.496 0.860 0.121 0.984 1.503 10.409 -0.495 0.855 -0.154 0.859 1.753 0.740 -0.252 -0.062 0.966 0.859 1.753 1.637 -0.362 -0.081 -0.929 0.915 1.640 5.470 -0.365 0.910 0.196 0.859 1.753 5.294 -0.463 0.790 0.402 0.646 1.753 6.154 -0.187 0.444 -0.876 0.859 1.753 5.833 -0.593 0.780 -0.200 0.859 1.753 10.007 -0.906 -0.341 0.251 0.859 1.753 10.495 -0.908 -0.322 -0.267 0.733 2.004 1.080 -0.442 -0.778 0.446 0.733 2.004 1.523 -0.470 -0.839 -0.274 0.733 2.004 5.244 -0.812 -0.388 0.436 0.733 2.004 5.920 -0.854 -0.404 -0.328 0.763 1.945 10.256 -0.765 -0.644 -0.006 0.693 2.085 1.367 -0.460 -0.876 -0.146 0.641 2.189 5.470 -0.676 -0.724 0.137 -0.776 4.759 3.419 -0.020 1.000 0.004 -0.612 4.695 12.307 -0.110 0.817 0.567 -0.644 4.759 12.194 -0.086 0.790 0.607 -0.644 4.759 12.513 -0.148 0.951 0.271 1.814 0.000 3.419 -0.435 0.901 0.000 1.728 0.250 3.419 -0.940 -0.340 -0.006 1.881 0.000 8.205 -0.238 0.963 -0.127 1.894 0.116 8.205 -0.563 0.813 -0.147 1.827 0.250 7.941 -0.987 0.143 0.072 1.827 0.250 8.352 -0.940 0.150 -0.305 1.902 0.000 12.307 -0.755 0.021 0.655 1.625 0.250 12.307 -0.565 -0.692 0.449 1.680 0.501 8.205 -0.774 -0.621 -0.122 1.709 0.487 8.205 -0.816 -0.565 -0.122 1.102 1.503 1.367 -0.344 0.923 -0.171 1.054 1.503 10.256 -0.621 0.784 -0.023 1.137 1.630 1.367 -0.733 0.657 -0.177 1.076 1.753 1.083 -0.821 0.250 0.513 1.076 1.753 1.519 -0.887 0.316 -0.337 0.958 1.753 5.470 -0.643 0.737 0.207 0.990 1.753 10.256 -0.993 -0.114 -0.018 0.950 2.004 1.293 -0.836 -0.549 -0.014 0.950 2.004 1.408 -0.828 -0.544 -0.136 0.901 2.004 5.470 -0.980 -0.107 0.166 0.938 2.028 1.367 -0.817 -0.564 -0.117 -0.586 4.759 12.307 -0.174 0.801 0.572 1.902 0.250 8.205 -0.959 0.230 -0.165 1.154 1.753 1.367 -0.933 0.314 -0.178 0.976 2.004 1.367 -0.846 -0.520 -0.118 0.858 3.006 12.307 0.706 0.435 0.559 0.895 2.982 12.307 0.684 0.472 0.556 0.883 3.006 12.267 0.684 0.450 0.574 0.883 3.006 12.382 0.732 0.481 0.483 0.680 3.256 12.307 0.681 -0.229 0.695 0.758 3.256 12.155 0.559 -0.199 0.805 0.758 3.256 12.592 0.951 -0.290 0.103 0.696 3.379 12.307 0.536 -0.481 0.694 -0.068 4.759 5.470 0.959 -0.229 0.165 0.125 4.523 5.470 0.749 0.656 0.092 0.007 4.759 5.323 0.941 -0.149 0.305 0.007 4.759 5.734 0.987 -0.143 -0.072 2.436 0.000 1.367 0.922 -0.347 -0.170 2.420 0.250 1.367 0.210 -0.970 -0.121 2.603 0.000 0.901 0.498 0.028 0.866 2.478 0.250 1.162 0.150 -0.966 0.211 2.603 0.000 1.609 0.817 0.232 -0.528 2.478 0.250 1.480 0.107 -0.979 -0.174 2.457 0.000 5.470 0.212 -0.969 0.124 2.536 0.133 5.470 -0.035 -0.991 0.130 2.603 0.000 5.245 -0.116 -0.954 0.277 2.603 0.000 5.897 -0.017 -0.977 -0.212 2.525 0.000 10.256 0.385 -0.923 0.000 2.550 0.106 10.256 0.268 -0.963 -0.002 2.603 0.000 10.074 0.172 -0.977 0.127 2.603 0.000 10.438 0.165 -0.978 -0.126 2.446 0.314 1.367 0.113 -0.987 -0.117 0.932 3.006 8.205 0.980 0.107 -0.166 1.193 2.820 8.205 0.675 0.724 -0.138 1.100 3.006 7.755 0.854 0.404 0.328 1.100 3.006 8.430 0.812 0.389 -0.436 1.141 2.924 12.307 0.361 0.688 0.630 1.100 3.006 12.152 0.329 0.588 0.739 1.100 3.006 12.595 0.492 0.867 0.077 0.844 3.256 3.419 0.993 0.114 0.018 1.071 3.065 3.419 0.765 0.643 0.006 0.975 3.256 3.180 0.908 0.322 0.267 0.975 3.256 3.667 0.906 0.341 -0.250 0.876 3.256 8.205 0.643 -0.737 -0.208 0.975 3.256 7.842 0.592 -0.780 0.200 0.975 3.256 8.381 0.462 -0.791 -0.402 0.975 3.256 12.037 0.145 0.033 0.989 0.975 3.256 12.935 0.268 0.066 -0.961 0.780 3.507 3.419 0.621 -0.784 0.023 0.850 3.507 3.266 0.495 -0.855 0.154 0.850 3.507 3.581 0.496 -0.860 -0.120 0.918 3.369 8.205 0.365 -0.910 -0.196 0.731 3.507 12.307 0.262 -0.704 0.660 0.850 3.507 12.127 0.104 -0.581 0.807 0.850 3.507 12.674 0.208 -0.945 -0.253 0.808 3.590 3.419 0.438 -0.899 0.021 0.800 3.606 12.307 0.076 -0.741 0.667 0.153 4.508 5.470 0.708 0.700 0.089 0.371 4.463 5.470 0.456 0.885 0.094 0.349 4.508 5.380 0.463 0.877 0.126 0.349 4.508 5.640 0.467 0.884 0.021 0.209 4.759 1.367 0.630 0.771 -0.091 0.228 4.751 1.367 0.617 0.782 -0.091 0.223 4.759 1.337 0.620 0.782 -0.062 0.223 4.759 1.383 0.618 0.780 -0.095 0.223 4.759 5.204 0.294 -0.015 0.956 0.223 4.759 6.072 0.667 0.445 -0.598 0.105 4.759 10.256 0.940 0.340 0.006 0.305 4.597 10.256 0.728 0.686 0.007 0.223 4.759 10.033 0.832 0.532 0.155 0.223 4.759 10.484 0.836 0.528 -0.151 2.820 0.000 0.736 0.213 0.358 0.909 2.695 0.250 0.783 -0.071 -0.540 0.839 2.820 0.000 1.635 0.408 0.706 -0.578 2.695 0.250 1.626 -0.176 -0.804 -0.568 2.701 0.238 5.470 -0.282 -0.954 0.103 2.820 0.000 5.203 -0.274 -0.650 0.709 2.820 0.000 6.091 -0.379 -0.784 -0.492 2.609 0.250 10.256 0.020 -1.000 -0.004 2.820 0.000 10.041 -0.211 0.960 0.186 2.695 0.250 10.087 -0.130 -0.989 0.073 2.820 0.000 10.472 -0.220 0.957 -0.187 2.695 0.250 10.422 -0.131 -0.988 -0.078 2.593 0.454 1.367 -0.018 -0.987 -0.157 2.656 0.327 10.256 -0.131 -0.991 -0.005 1.407 2.825 8.205 0.282 0.946 -0.162 1.317 3.006 7.643 0.330 0.763 0.555 1.317 3.006 8.464 0.287 0.705 -0.648 1.325 2.989 12.307 -0.047 0.754 0.655 1.317 3.006 12.274 -0.057 0.738 0.672 1.317 3.006 12.370 -0.054 0.803 0.594 1.311 3.018 3.419 0.416 0.909 -0.001 1.192 3.256 3.143 0.375 0.629 0.681 1.192 3.256 3.700 0.349 0.670 -0.655 1.188 3.256 7.521 0.187 -0.445 0.876 1.197 3.245 7.521 0.192 -0.395 0.898 1.192 3.256 7.517 0.179 -0.442 0.879 1.192 3.256 8.461 -0.081 -0.543 -0.835 1.192 3.256 12.048 0.010 0.232 0.973 1.192 3.256 12.941 -0.058 0.271 -0.961 1.067 3.507 3.193 -0.909 -0.325 0.262 1.067 3.507 3.654 -0.916 -0.319 -0.244 1.190 3.259 7.521 0.175 -0.451 0.875 1.026 3.507 8.205 0.119 -0.978 -0.169 1.067 3.507 8.085 0.070 -0.994 -0.088 1.067 3.507 8.264 0.095 -0.973 -0.211 1.067 3.507 12.064 -0.122 -0.362 0.924 1.067 3.507 12.887 -0.186 -0.428 -0.885 0.894 3.757 3.419 0.438 -0.899 0.016 0.941 3.757 3.323 0.455 -0.886 0.083 0.941 3.757 3.519 0.451 -0.891 -0.056 1.052 3.536 8.205 0.068 -0.983 -0.170 0.973 3.694 12.307 -0.135 -0.734 0.665 0.920 3.799 3.419 0.378 -0.926 0.015 0.481 4.508 5.470 0.298 0.950 0.096 0.441 4.758 1.367 0.339 0.936 -0.094 0.440 4.759 1.363 0.339 0.936 -0.089 0.440 4.759 1.370 0.339 0.936 -0.094 0.547 4.546 5.470 0.154 0.981 0.121 0.440 4.759 5.222 0.111 0.715 0.690 0.440 4.759 6.072 0.167 0.860 -0.483 0.536 4.569 10.256 0.423 0.906 0.006 0.440 4.759 9.978 0.494 0.807 0.322 0.440 4.759 10.538 0.489 0.810 -0.324 3.037 0.000 0.895 -0.070 0.609 0.790 2.912 0.250 0.741 -0.345 -0.295 0.891 3.037 0.000 1.612 -0.420 0.601 -0.680 2.912 0.250 1.626 -0.197 0.090 -0.976 2.773 0.250 5.470 -0.401 -0.911 0.093 3.037 0.000 5.211 -0.730 -0.288 0.620 2.912 0.250 5.432 -0.573 -0.814 0.098 3.037 0.000 5.971 -0.825 -0.393 -0.407 2.912 0.250 5.538 -0.577 -0.815 0.061 2.915 0.000 10.256 0.361 0.932 0.000 2.978 0.117 10.256 0.615 0.788 -0.001 2.912 0.250 9.986 -0.346 -0.912 0.220 2.912 0.250 10.523 -0.344 -0.913 -0.220 2.675 0.501 1.367 -0.190 -0.971 -0.148 2.786 0.501 1.206 -0.409 -0.901 0.146 2.786 0.501 1.452 -0.398 -0.893 -0.211 2.902 0.270 5.470 -0.570 -0.817 0.087 2.834 0.405 10.256 -0.267 -0.964 -0.006 2.765 0.544 1.367 -0.399 -0.904 -0.151 1.584 2.906 8.205 -0.171 0.970 -0.174 1.534 3.006 7.853 -0.281 0.944 0.173 1.534 3.006 8.386 -0.300 0.879 -0.371 1.339 3.006 12.307 -0.069 0.756 0.651 1.489 3.095 3.419 -0.060 0.998 -0.005 1.409 3.256 3.155 -0.627 -0.233 0.744 1.409 3.256 3.684 -0.640 -0.185 -0.746 1.239 3.256 7.521 0.010 -0.367 0.930 1.409 3.256 7.545 -0.581 -0.004 0.814 1.409 3.256 8.462 -0.336 -0.018 -0.942 1.463 3.148 12.307 -0.255 0.675 0.692 1.409 3.256 12.129 -0.265 0.501 0.824 1.409 3.256 12.639 -0.546 0.829 -0.124 1.183 3.507 3.419 -0.944 -0.328 0.038 1.333 3.407 3.419 0.701 -0.709 0.080 1.283 3.507 7.860 -0.472 -0.869 0.148 1.283 3.507 8.381 -0.418 -0.839 -0.348 1.283 3.507 12.070 -0.407 -0.190 0.893 1.283 3.507 12.773 -0.664 -0.243 -0.707 1.236 3.601 3.419 0.986 0.166 0.025 1.158 3.757 3.143 0.750 -0.105 0.653 1.158 3.757 3.700 0.738 -0.120 -0.664 1.235 3.604 8.205 -0.402 -0.901 -0.163 1.169 3.736 12.307 -0.473 -0.648 0.597 1.089 3.895 3.419 0.044 -0.999 0.011 0.442 4.759 1.367 0.337 0.937 -0.094 0.702 4.669 5.470 -0.032 0.992 0.118 0.657 4.759 5.312 0.014 0.978 0.208 0.657 4.759 5.753 -0.070 0.995 -0.069 0.723 4.627 10.256 0.240 0.971 0.003 0.657 4.759 10.002 0.337 0.925 0.173 0.657 4.759 10.512 0.332 0.927 -0.172 3.225 0.000 1.367 -0.188 0.976 -0.105 3.231 0.046 1.367 -0.282 0.953 -0.111 3.128 0.250 1.034 -0.762 0.004 0.648 3.128 0.250 1.556 -0.915 0.001 -0.404 3.254 0.000 5.470 -0.991 0.053 0.125 2.954 0.250 5.470 -0.611 -0.787 0.086 3.130 0.000 10.256 0.614 0.789 0.000 3.254 0.000 9.949 0.754 0.582 0.303 3.128 0.250 9.962 -0.591 -0.743 0.315 3.254 0.000 10.563 0.753 0.584 -0.302 3.128 0.250 10.549 -0.586 -0.748 -0.313 3.003 0.501 1.360 -0.766 -0.634 -0.106 3.003 0.501 1.372 -0.765 -0.634 -0.117 3.028 0.452 10.256 -0.526 -0.851 -0.004 3.002 0.503 1.367 -0.764 -0.635 -0.116 1.645 3.006 8.205 -0.409 0.897 -0.167 1.659 3.188 3.419 -0.244 0.970 -0.003 1.626 3.256 3.268 -0.323 0.940 0.114 1.626 3.256 3.569 -0.319 0.941 -0.116 1.683 3.141 8.205 -0.686 0.705 -0.179 1.626 3.256 7.922 -0.895 0.436 0.096 1.626 3.256 8.357 -0.806 0.472 -0.357 1.506 3.256 12.307 -0.431 0.565 0.704 1.361 3.507 3.419 0.955 0.296 0.014 1.500 3.507 3.123 0.788 0.388 0.478 1.500 3.507 3.716 0.782 0.402 -0.476 1.500 3.507 8.030 -0.852 -0.524 -0.024 1.500 3.507 8.301 -0.835 -0.518 -0.188 1.474 3.507 12.307 -0.737 0.046 0.674 1.375 3.757 3.119 -0.635 -0.661 0.400 1.375 3.757 3.721 -0.642 -0.657 -0.395 1.469 3.568 8.205 -0.797 -0.589 -0.130 1.286 3.934 3.419 -0.515 -0.857 0.003 0.747 4.759 5.470 -0.166 0.979 0.119 0.892 4.724 10.256 0.058 0.998 0.001 0.874 4.759 10.171 0.068 0.997 0.031 0.874 4.759 10.341 0.067 0.997 -0.031 3.237 0.250 1.367 -0.977 0.140 -0.163 3.471 0.000 10.181 -0.513 0.858 0.038 3.345 0.250 10.099 -0.878 -0.472 0.080 3.471 0.000 10.331 -0.512 0.858 -0.038 3.345 0.250 10.413 -0.877 -0.474 -0.080 3.006 0.501 1.367 -0.767 -0.631 -0.116 3.291 0.359 10.256 -0.835 -0.551 -0.001 1.695 3.256 3.419 -0.401 0.916 -0.001 1.704 3.256 8.205 -0.876 0.444 -0.187 1.741 3.460 3.419 -0.772 0.636 0.002 1.717 3.507 3.337 -0.807 0.589 0.051 1.717 3.507 3.500 -0.806 0.590 -0.047 1.562 3.507 8.205 -0.887 -0.441 -0.134 1.592 3.757 3.272 -0.945 -0.315 0.090 1.592 3.757 3.567 -0.945 -0.315 -0.086 1.544 3.853 3.419 -0.882 -0.471 0.002 0.912 4.759 10.256 0.015 1.000 0.000 3.501 0.000 10.256 -0.529 0.849 0.000 3.419 0.250 10.256 -0.921 -0.390 0.000 1.751 3.507 3.419 -0.823 0.569 0.002 1.662 3.757 3.419 -0.970 -0.245 0.003 3.187 1.252 3.419 0.969 0.246 -0.010 3.333 1.143 3.419 0.891 0.454 -0.006 3.278 1.252 3.241 0.947 0.311 0.081 3.278 1.252 3.590 0.948 0.304 -0.091 3.080 1.503 3.419 0.927 -0.375 -0.015 3.153 1.503 3.252 0.923 -0.376 0.079 3.153 1.503 3.577 0.921 -0.377 -0.098 3.008 1.503 8.205 0.988 0.045 -0.151 3.253 1.302 8.205 0.776 0.618 -0.122 3.153 1.503 7.781 0.951 0.207 0.232 3.153 1.503 8.417 0.918 0.213 -0.336 3.102 1.604 3.419 0.824 -0.566 -0.016 2.963 1.753 8.205 0.779 -0.612 -0.135 3.028 1.753 7.971 0.776 -0.631 0.019 3.028 1.753 8.328 0.772 -0.602 -0.204 2.993 1.823 8.205 0.683 -0.718 -0.137 2.262 3.006 1.367 0.987 0.079 -0.143 2.491 2.826 1.367 0.781 0.613 -0.124 2.402 3.006 0.961 0.752 0.184 0.632 2.402 3.006 1.577 0.921 0.237 -0.309 2.208 3.256 1.367 0.813 -0.566 -0.137 2.276 3.256 1.121 0.777 -0.552 0.304 2.276 3.256 1.497 0.802 -0.558 -0.211 2.179 3.256 10.256 0.998 0.069 -0.001 2.359 3.090 10.256 0.899 0.439 -0.004 2.276 3.256 10.057 0.985 0.133 0.106 2.276 3.256 10.454 0.985 0.138 -0.107 2.236 3.337 1.367 0.715 -0.685 -0.139 2.123 3.507 10.256 0.854 -0.521 0.002 2.151 3.507 10.188 0.852 -0.523 0.030 2.151 3.507 10.325 0.852 -0.523 -0.027 2.133 3.542 10.256 0.822 -0.570 0.002 3.580 1.083 3.419 0.397 0.918 -0.003 3.495 1.252 3.127 0.204 0.821 0.533 3.495 1.252 3.705 0.218 0.806 -0.551 3.370 1.503 3.166 -0.927 -0.233 0.293 3.370 1.503 3.662 -0.918 -0.246 -0.309 3.476 1.290 8.205 0.139 0.977 -0.162 3.370 1.503 7.613 0.323 0.700 0.637 3.370 1.503 8.454 -0.298 0.680 -0.670 3.288 1.503 12.307 0.756 0.345 0.556 3.405 1.433 12.307 0.691 0.474 0.546 3.370 1.503 12.194 0.696 0.395 0.599 3.370 1.503 12.528 0.838 0.490 0.239 3.147 1.753 3.419 0.656 -0.755 -0.016 3.245 1.753 3.227 0.745 -0.655 0.128 3.245 1.753 3.602 0.751 -0.644 -0.144 3.245 1.753 7.586 0.344 -0.608 0.716 3.245 1.753 8.473 -0.294 -0.582 -0.758 3.137 1.753 12.307 0.738 -0.246 0.629 3.245 1.753 12.119 0.680 -0.189 0.708 3.245 1.753 12.691 0.931 -0.247 -0.269 3.202 1.839 3.419 0.573 -0.819 -0.014 3.129 1.984 8.205 0.255 -0.956 -0.144 3.167 1.908 12.307 0.596 -0.507 0.623 2.712 2.819 1.367 0.109 0.980 -0.168 2.618 3.006 0.796 0.165 0.367 0.915 2.618 3.006 1.628 -0.154 0.713 -0.684 2.556 3.006 5.470 0.878 0.464 0.117 2.644 2.955 5.470 0.813 0.570 0.116 2.618 3.006 5.383 0.841 0.519 0.153 2.618 3.006 5.634 0.850 0.526 0.031 2.493 3.256 0.723 0.215 -0.242 0.946 2.493 3.256 1.623 -0.474 -0.524 -0.708 2.383 3.256 5.470 0.962 -0.234 0.139 2.493 3.256 5.277 0.946 -0.175 0.272 2.493 3.256 5.830 0.970 -0.189 -0.151 2.614 3.014 10.256 0.421 0.907 -0.003 2.493 3.256 9.973 -0.477 0.676 0.562 2.493 3.256 10.539 -0.445 0.695 -0.564 2.348 3.507 1.367 0.362 -0.921 -0.143 2.368 3.507 1.309 0.356 -0.933 -0.049 2.368 3.507 1.399 0.366 -0.917 -0.161 2.403 3.437 5.470 0.764 -0.631 0.132 2.368 3.507 9.983 -0.274 -0.733 0.623 2.368 3.507 10.531 -0.261 -0.735 -0.626 2.360 3.522 1.367 0.346 -0.927 -0.144 2.220 3.757 10.256 0.641 -0.768 0.002 2.243 3.757 10.207 0.659 -0.752 0.025 2.243 3.757 10.306 0.659 -0.752 -0.020 2.232 3.778 10.256 0.632 -0.775 0.002 surface_Al2O3_4 364 405 3 1 2 3 3 1 2 4 6 1 3 6 5 8 7 6 1 4 6 5 9 7 3 10 11 12 3 10 11 13 5 5 8 16 15 14 5 5 9 18 17 14 5 10 12 20 21 19 5 10 13 22 23 19 4 24 26 27 25 4 24 28 29 25 4 30 15 16 31 4 30 17 18 31 4 32 20 21 33 4 32 22 23 33 4 26 34 35 27 4 28 36 37 29 4 38 34 35 39 4 38 36 37 39 3 40 41 42 3 40 41 43 5 40 42 45 46 44 5 40 43 47 48 44 4 49 51 52 50 4 49 53 54 50 3 55 56 57 3 55 56 58 4 59 45 46 60 4 59 47 48 60 4 51 61 62 52 4 53 63 64 54 6 55 57 66 65 68 67 6 55 58 66 65 69 67 4 70 61 62 71 4 70 63 64 71 5 65 68 74 73 72 5 65 69 76 75 72 4 77 73 74 78 4 77 75 76 78 3 79 7 8 3 79 7 9 4 79 8 16 80 4 79 9 18 80 3 81 19 21 3 81 19 23 3 82 25 27 3 82 25 29 3 80 31 16 3 80 31 18 3 81 33 21 3 81 33 23 5 82 27 35 84 83 5 82 29 37 85 83 4 39 35 84 86 4 39 37 85 86 3 87 44 46 3 87 44 48 3 88 50 52 3 88 50 54 3 87 60 46 3 87 60 48 5 88 52 62 90 89 5 88 54 64 91 89 3 92 67 68 3 92 67 69 4 71 62 90 93 4 71 64 91 93 4 92 68 74 94 4 92 69 76 94 3 94 78 74 3 94 78 76 3 95 83 84 3 95 83 85 3 95 86 84 3 95 86 85 3 96 89 90 3 96 89 91 3 96 93 90 3 96 93 91 3 97 98 99 3 97 98 100 3 101 102 103 3 101 102 104 4 101 103 106 105 4 101 104 107 105 3 105 108 106 3 105 108 107 3 109 110 111 3 109 110 112 6 113 99 98 114 116 115 6 113 100 98 114 117 115 3 118 119 120 3 118 119 121 3 122 123 124 3 122 123 125 3 114 126 116 3 114 126 117 4 102 103 128 127 4 102 104 129 127 3 130 131 132 3 130 131 133 5 134 106 103 128 135 5 134 107 104 129 135 3 130 136 132 3 130 136 133 3 137 138 139 3 137 138 140 6 134 106 108 141 143 142 6 134 107 108 141 144 142 3 137 145 139 3 137 145 140 3 141 146 143 3 141 146 144 4 110 111 148 147 4 110 112 149 147 3 150 151 152 3 150 151 153 4 115 116 155 154 4 115 117 156 154 5 157 159 158 120 119 5 157 161 160 121 119 4 123 124 163 162 4 123 125 164 162 4 126 116 155 165 4 126 117 156 165 3 157 166 159 3 157 166 161 3 167 127 128 3 167 127 129 4 131 132 169 168 4 131 133 170 168 6 167 128 135 171 173 172 6 167 129 135 171 174 172 5 175 176 169 132 136 5 175 177 170 133 136 4 138 139 179 178 4 138 140 180 178 5 171 173 181 143 142 5 171 174 182 144 142 3 175 183 176 3 175 183 177 5 184 185 179 139 145 5 184 186 180 140 145 4 146 143 181 187 4 146 144 182 187 3 184 188 185 3 184 188 186 3 189 147 148 3 189 147 149 4 151 152 191 190 4 151 153 192 190 4 154 155 194 193 4 154 156 195 193 4 158 159 197 196 4 160 161 199 198 4 162 163 201 200 4 162 164 202 200 4 165 155 194 203 4 165 156 195 203 4 166 159 197 204 4 166 161 199 204 3 205 168 169 3 205 168 170 3 206 172 173 3 206 172 174 5 205 169 176 208 207 5 205 170 177 209 207 3 210 178 179 3 210 178 180 5 206 173 181 212 211 5 206 174 182 213 211 4 183 176 208 214 4 183 177 209 214 5 210 179 185 216 215 5 210 180 186 217 215 4 187 181 212 218 4 187 182 213 218 4 188 185 216 219 4 188 186 217 219 3 220 190 191 3 220 190 192 3 221 193 194 3 221 193 195 4 222 196 197 223 4 222 198 199 223 3 224 200 201 3 224 200 202 3 221 203 194 3 221 203 195 3 223 204 197 3 223 204 199 3 225 207 208 3 225 207 209 3 226 211 212 3 226 211 213 3 225 214 208 3 225 214 209 3 227 215 216 3 227 215 217 3 226 218 212 3 226 218 213 3 227 219 216 3 227 219 217 3 228 229 230 3 228 229 231 3 232 233 234 3 232 233 235 3 236 237 238 3 236 237 239 3 240 241 242 3 240 241 243 3 236 244 238 3 236 244 239 3 245 246 247 3 245 246 248 3 240 249 242 3 240 249 243 3 245 250 247 3 245 250 248 3 251 252 253 3 251 252 254 3 255 256 257 3 255 256 258 5 259 261 260 230 229 5 259 263 262 231 229 4 233 234 265 264 4 233 235 266 264 3 259 267 261 3 259 267 263 4 237 238 269 268 4 237 239 270 268 4 241 242 272 271 4 241 243 273 271 5 274 275 269 238 244 5 274 276 270 239 244 4 246 247 278 277 4 246 248 279 277 5 280 281 272 242 249 5 280 282 273 243 249 3 274 283 275 3 274 283 276 5 284 285 278 247 250 5 284 286 279 248 250 3 280 287 281 3 280 287 282 3 284 288 285 3 284 288 286 4 252 253 290 289 4 252 254 291 289 4 256 257 293 292 4 256 258 294 292 4 260 261 296 295 4 262 263 298 297 4 264 265 300 299 4 264 266 301 299 3 302 303 304 3 302 303 305 4 267 261 296 306 4 267 263 298 306 3 302 307 304 3 302 307 305 3 308 268 269 3 308 268 270 4 271 272 310 309 4 271 273 311 309 5 308 269 275 313 312 5 308 270 276 314 312 3 315 277 278 3 315 277 279 5 316 281 272 310 317 5 316 282 273 311 317 4 283 275 313 318 4 283 276 314 318 5 315 278 285 320 319 5 315 279 286 321 319 6 316 281 287 322 324 323 6 316 282 287 322 325 323 4 288 285 320 326 4 288 286 321 326 3 322 327 324 3 322 327 325 3 328 289 290 3 328 289 291 4 292 293 330 329 4 292 294 331 329 4 332 295 296 333 4 332 297 298 333 3 334 299 300 3 334 299 301 5 335 336 337 304 303 5 335 338 339 305 303 3 333 306 296 3 333 306 298 4 307 304 337 340 4 307 305 339 340 3 341 309 310 3 341 309 311 3 342 312 313 3 342 312 314 6 341 310 317 343 345 344 6 341 311 317 343 346 344 3 342 318 313 3 342 318 314 3 347 319 320 3 347 319 321 5 343 345 348 324 323 5 343 346 349 325 323 3 347 326 320 3 347 326 321 4 327 324 348 350 4 327 325 349 350 3 351 329 330 3 351 329 331 4 352 336 337 353 4 352 338 339 353 3 353 340 337 3 353 340 339 3 354 344 345 3 354 344 346 4 354 345 348 355 4 354 346 349 355 3 355 350 348 3 355 350 349 3 356 357 358 3 356 357 359 3 356 360 358 3 356 360 359 3 361 362 363 3 361 362 364 3 361 365 363 3 361 365 364 3 366 367 368 3 366 367 369 4 366 368 371 370 4 366 369 372 370 4 357 358 374 373 4 357 359 375 373 3 370 376 371 3 370 376 372 5 377 378 374 358 360 5 377 379 375 359 360 3 380 381 382 3 380 381 383 3 377 384 378 3 377 384 379 3 380 385 382 3 380 385 383 4 362 363 387 386 4 362 364 388 386 5 389 390 387 363 365 5 389 391 388 364 365 3 392 393 394 3 392 393 395 3 396 397 398 3 396 397 399 3 389 400 390 3 389 400 391 3 392 401 394 3 392 401 395 4 396 398 403 402 4 396 399 404 402 3 402 405 403 3 402 405 404 -0.544 1.252 3.419 -0.887 0.461 -0.005 -0.603 1.206 3.419 -0.896 0.443 -0.008 -0.626 1.252 3.324 -0.970 -0.153 0.188 -0.626 1.252 3.513 -0.967 -0.157 -0.201 -0.568 1.503 3.419 0.916 0.400 -0.005 -0.651 1.302 3.419 0.914 -0.406 -0.016 -0.495 1.424 3.419 -0.189 0.982 -0.006 -0.535 1.503 3.344 0.508 0.850 0.140 -0.535 1.503 3.493 0.509 0.847 -0.153 -0.719 1.503 8.205 -0.492 0.840 -0.228 -0.738 1.476 8.205 -0.423 0.875 -0.236 -0.751 1.503 8.118 -0.474 0.866 -0.160 -0.751 1.503 8.249 -0.461 0.840 -0.285 -0.865 1.730 3.419 0.927 0.375 -0.011 -0.877 1.753 3.373 0.812 0.581 0.055 -0.660 1.753 3.328 0.681 -0.718 0.143 -0.877 1.753 3.463 0.813 0.577 -0.084 -0.660 1.753 3.509 0.687 -0.712 -0.144 -0.656 1.745 8.205 -0.968 0.199 -0.153 -0.877 1.753 7.959 0.786 -0.618 -0.022 -0.660 1.753 8.189 -0.973 0.181 -0.144 -0.877 1.753 8.302 0.768 -0.219 -0.602 -0.660 1.753 8.214 -0.971 0.180 -0.158 -0.764 1.529 12.307 0.280 0.536 0.797 -0.612 1.657 12.307 0.077 0.484 0.872 -0.877 1.753 12.212 0.171 0.047 0.984 -0.660 1.753 12.218 0.270 0.286 0.920 -0.877 1.753 12.567 0.692 0.144 0.707 -0.660 1.753 12.534 0.270 0.667 0.695 -0.891 1.782 3.419 0.937 0.348 -0.018 -0.698 1.831 3.419 0.216 -0.976 0.001 -0.966 1.932 8.205 -0.014 -0.952 -0.306 -0.669 1.771 8.205 -0.980 0.128 -0.154 -1.002 2.004 12.281 -0.048 -0.568 0.822 -0.785 2.004 12.211 0.089 -0.391 0.916 -1.002 2.004 12.359 -0.037 -0.634 0.773 -0.785 2.004 12.518 0.008 -0.776 0.630 -1.009 2.018 12.307 -0.044 -0.592 0.805 -0.819 2.073 12.307 0.035 -0.539 0.842 -1.485 3.006 1.367 -0.565 0.798 -0.209 -1.496 2.991 1.367 -0.542 0.813 -0.212 -1.503 3.006 1.316 -0.569 0.816 -0.103 -1.503 3.006 1.393 -0.567 0.790 -0.232 -1.410 3.254 1.367 -0.948 0.269 -0.169 -1.628 3.256 1.107 0.438 -0.162 0.884 -1.411 3.256 1.362 -0.951 0.265 -0.161 -1.628 3.256 1.463 0.781 -0.102 -0.616 -1.411 3.256 1.370 -0.949 0.265 -0.170 -1.539 3.078 5.470 0.438 0.856 0.275 -1.367 3.167 5.470 0.050 0.943 0.329 -1.628 3.256 5.372 0.758 0.223 0.613 -1.411 3.256 5.367 0.362 0.722 0.589 -1.628 3.256 5.715 0.961 0.277 0.009 -1.411 3.256 5.708 0.131 0.991 0.002 -1.501 3.256 10.256 -0.723 0.690 0.026 -1.613 3.227 10.256 0.955 -0.295 0.016 -1.628 3.256 10.211 0.866 -0.495 0.072 -1.628 3.256 10.301 0.869 -0.492 -0.047 -1.741 3.481 1.367 -0.132 -0.953 -0.271 -1.415 3.263 1.367 -0.955 0.244 -0.169 -1.753 3.507 5.425 -0.389 -0.872 0.296 -1.536 3.507 5.392 0.357 -0.793 0.494 -1.753 3.507 5.557 -0.325 -0.930 0.171 -1.536 3.507 5.656 0.201 -0.972 0.123 -1.550 3.507 10.256 0.982 0.188 0.013 -1.640 3.280 10.256 0.933 -0.359 0.010 -1.478 3.389 10.256 0.102 0.994 0.032 -1.536 3.507 10.227 0.976 0.213 0.038 -1.536 3.507 10.286 0.977 0.212 -0.009 -1.767 3.533 5.470 -0.333 -0.910 0.246 -1.570 3.573 5.470 0.180 -0.925 0.335 -1.854 3.708 10.256 0.988 0.152 0.006 -1.879 3.757 10.162 0.914 0.250 0.320 -1.662 3.757 10.156 -0.154 -0.971 0.185 -1.879 3.757 10.351 0.922 0.244 -0.301 -1.662 3.757 10.358 -0.150 -0.975 -0.162 -1.902 3.803 10.256 0.759 -0.651 0.012 -1.691 3.816 10.256 -0.265 -0.964 0.008 -0.462 1.503 3.419 -0.162 0.987 -0.006 -0.470 1.753 3.419 -0.956 -0.295 0.002 -0.655 1.753 8.205 -0.971 0.182 -0.153 -0.532 1.753 12.307 -0.095 0.463 0.881 -0.532 1.931 12.307 -0.556 -0.012 0.831 -0.568 2.004 12.279 -0.576 -0.211 0.790 -0.568 2.004 12.362 -0.638 -0.231 0.734 -0.580 2.028 12.307 -0.585 -0.257 0.769 -1.410 3.256 1.367 -0.949 0.265 -0.169 -1.284 3.256 5.470 -0.284 0.906 0.314 -1.288 3.444 5.470 -0.958 -0.002 0.287 -1.319 3.507 5.443 -0.909 -0.306 0.283 -1.319 3.507 5.524 -0.929 -0.308 0.206 -1.468 3.507 10.256 0.815 0.579 0.029 -1.332 3.532 5.470 -0.895 -0.374 0.245 -1.509 3.757 10.256 -0.846 -0.533 0.011 -0.549 2.004 12.307 -0.602 -0.197 0.774 -1.301 3.507 5.470 -0.928 -0.274 0.251 0.988 0.000 3.419 -0.254 -0.967 -0.001 1.027 0.115 3.419 -0.479 -0.878 -0.001 1.085 0.000 3.306 -0.987 0.032 0.157 1.085 0.000 3.532 -0.987 0.032 -0.158 0.321 1.252 10.256 0.894 0.448 -0.003 0.493 1.183 10.256 0.612 0.791 -0.004 0.458 1.252 10.138 0.685 0.719 0.120 0.458 1.252 10.373 0.683 0.719 -0.129 0.234 1.503 10.256 -0.068 -0.998 -0.007 0.333 1.503 10.148 -0.920 -0.373 0.121 0.333 1.503 10.363 -0.921 -0.369 -0.128 0.255 1.659 10.256 -0.118 -0.993 -0.001 -1.428 4.759 3.419 0.816 0.578 0.000 -1.259 4.688 3.419 0.578 0.816 0.002 -1.295 4.759 3.316 0.617 0.782 0.088 -1.295 4.759 3.522 0.619 0.781 -0.086 1.130 0.000 3.419 -0.234 0.972 -0.001 1.122 0.250 3.419 -0.270 -0.963 -0.001 1.188 0.227 3.419 -0.306 -0.952 -0.003 1.176 0.250 3.371 -0.341 -0.940 0.022 1.176 0.250 3.466 -0.341 -0.940 -0.025 1.224 0.000 8.205 0.960 0.087 -0.267 1.213 0.177 8.205 0.200 -0.957 -0.211 1.301 0.000 8.027 0.920 0.388 -0.057 1.301 0.000 8.297 0.822 0.428 -0.375 1.245 0.000 12.307 -0.049 -0.762 0.646 1.278 0.046 12.307 -0.112 -0.757 0.644 1.301 0.000 12.234 -0.126 -0.722 0.680 1.301 0.000 12.449 -0.127 -0.874 0.469 1.164 0.275 3.419 -0.328 -0.945 -0.002 0.696 1.211 10.256 -0.887 0.461 -0.024 0.675 1.252 10.171 -0.985 -0.072 0.154 0.675 1.252 10.340 -0.979 -0.073 -0.188 0.498 1.503 1.367 0.924 0.278 -0.263 0.581 1.440 1.367 0.784 0.569 -0.249 0.550 1.503 1.241 0.902 0.415 0.120 0.550 1.503 1.432 0.840 0.408 -0.358 0.384 1.503 10.256 -0.941 -0.337 -0.007 0.652 1.300 10.256 -0.990 -0.138 -0.021 0.442 1.720 1.367 0.558 -0.788 -0.259 0.273 1.753 5.470 0.833 -0.431 0.346 0.535 1.533 5.470 0.455 0.854 0.252 0.425 1.753 5.377 0.475 0.023 0.880 0.425 1.753 5.708 0.998 0.026 0.061 0.318 1.753 10.256 0.641 -0.768 0.000 0.444 1.716 10.256 0.780 0.626 -0.009 0.425 1.753 10.190 0.833 0.531 0.156 0.425 1.753 10.322 0.827 0.538 -0.163 0.310 1.983 5.470 0.329 -0.910 0.252 0.405 1.793 10.256 0.998 -0.063 -0.001 -1.058 4.718 3.419 0.344 0.939 0.004 -1.078 4.759 3.348 0.367 0.929 0.047 -1.078 4.759 3.490 0.367 0.929 -0.041 -1.287 4.759 12.307 0.562 -0.003 0.827 -1.020 4.643 12.307 0.305 0.500 0.810 -1.078 4.759 12.217 0.082 -0.047 0.996 -1.078 4.759 12.527 0.490 0.207 0.846 1.501 0.034 3.419 0.812 0.584 -0.001 1.393 0.250 3.333 -0.491 -0.868 0.073 1.393 0.250 3.503 -0.492 -0.866 -0.083 1.252 0.250 8.205 -0.041 -0.981 -0.188 1.518 0.000 7.964 0.403 0.915 0.004 1.393 0.250 8.023 -0.164 -0.980 -0.112 1.518 0.000 8.308 0.318 0.754 -0.575 1.393 0.250 8.280 -0.130 -0.850 -0.511 1.469 0.098 12.307 -0.244 -0.580 0.778 1.518 0.000 12.203 -0.162 -0.289 0.944 1.518 0.000 12.553 -0.440 -0.770 0.463 1.364 0.308 3.419 -0.458 -0.889 -0.007 1.361 0.315 8.205 -0.088 -0.937 -0.338 0.765 1.252 10.256 -0.813 0.582 -0.021 0.794 1.449 1.367 0.243 0.912 -0.332 0.767 1.503 1.202 0.320 0.925 0.203 0.767 1.503 1.437 0.269 0.837 -0.476 0.765 1.503 10.256 0.958 0.288 -0.016 0.771 1.495 10.256 0.949 0.315 -0.016 0.767 1.503 10.252 0.958 0.288 -0.013 0.767 1.503 10.260 0.957 0.288 -0.019 0.445 1.753 1.367 0.434 -0.866 -0.247 0.642 1.753 1.140 0.021 -0.785 0.619 0.642 1.753 1.461 -0.046 -0.696 -0.717 0.696 1.646 5.470 -0.005 0.928 0.371 0.642 1.753 5.378 0.115 0.699 0.705 0.642 1.753 5.718 0.010 0.999 0.031 0.642 1.753 10.173 -0.419 -0.886 0.197 0.642 1.753 10.337 -0.426 -0.871 -0.245 0.592 1.852 1.367 0.023 -0.930 -0.367 0.317 2.004 5.470 0.276 -0.931 0.239 0.516 2.004 5.375 -0.331 -0.820 0.468 0.516 2.004 5.677 -0.381 -0.923 0.048 0.607 1.823 10.256 -0.416 -0.909 -0.011 0.483 2.070 5.470 -0.319 -0.904 0.283 -0.950 4.759 3.419 0.219 0.976 0.003 -0.825 4.686 12.307 0.118 0.640 0.759 -0.861 4.759 12.215 0.116 0.502 0.857 -0.861 4.759 12.516 0.170 0.853 0.493 1.664 0.143 3.419 -1.000 -0.027 -0.005 1.610 0.250 3.395 -0.835 -0.550 0.007 1.610 0.250 3.442 -0.835 -0.550 -0.017 1.735 0.000 8.111 -0.352 0.921 -0.166 1.610 0.250 7.974 -0.921 -0.390 -0.018 1.735 0.000 8.254 -0.393 0.857 -0.334 1.610 0.250 8.307 -0.423 0.012 -0.906 1.696 0.079 12.307 -0.555 -0.388 0.735 1.735 0.000 12.234 -0.497 -0.170 0.851 1.735 0.000 12.448 -0.708 -0.248 0.661 1.601 0.268 3.419 -0.827 -0.563 -0.005 1.547 0.377 8.205 -0.519 -0.776 -0.358 0.944 1.503 1.367 -0.113 0.959 -0.261 0.779 1.503 10.256 0.940 0.340 -0.017 0.969 1.533 1.367 -0.206 0.940 -0.272 0.859 1.753 1.122 -0.622 -0.125 0.773 0.859 1.753 1.473 -0.523 -0.092 -0.847 0.833 1.753 5.470 -0.447 0.846 0.289 0.911 1.648 10.256 -0.981 0.193 -0.025 0.859 1.753 10.209 -0.937 -0.347 0.021 0.859 1.753 10.301 -0.937 -0.344 -0.054 0.766 1.939 1.367 -0.524 -0.814 -0.249 0.833 1.804 5.470 -0.684 0.663 0.304 0.733 2.004 5.418 -0.864 -0.420 0.277 0.733 2.004 5.573 -0.891 -0.432 0.140 0.841 1.789 10.256 -0.907 -0.421 -0.015 0.712 2.046 5.470 -0.833 -0.509 0.217 -0.745 4.759 12.307 0.005 0.701 0.713 1.623 0.250 3.419 -0.846 -0.533 -0.005 1.767 0.000 8.205 -0.353 0.903 -0.244 1.760 0.250 8.205 -0.945 0.132 -0.299 1.786 0.000 12.307 -0.584 -0.124 0.802 1.012 1.753 1.367 -0.908 0.277 -0.313 0.883 1.753 10.256 -0.953 -0.302 -0.017 0.772 2.004 5.470 -0.908 -0.354 0.225 2.552 0.000 1.367 0.962 0.071 -0.262 2.543 0.119 1.367 0.619 -0.736 -0.275 2.603 0.000 1.227 0.959 0.221 0.181 2.603 0.000 1.440 0.901 0.257 -0.350 2.571 0.000 5.470 -0.064 -0.988 0.141 2.588 0.029 5.470 -0.109 -0.984 0.141 2.603 0.000 5.420 -0.124 -0.978 0.166 2.603 0.000 5.564 -0.108 -0.990 0.087 1.062 3.006 8.205 0.907 0.355 -0.226 1.121 2.963 8.205 0.833 0.509 -0.217 1.100 3.006 8.102 0.891 0.432 -0.140 1.100 3.006 8.256 0.864 0.420 -0.277 0.950 3.256 3.419 0.953 0.302 0.017 0.993 3.220 3.419 0.907 0.420 0.015 0.975 3.256 3.374 0.937 0.344 0.053 0.975 3.256 3.465 0.938 0.347 -0.021 1.000 3.205 8.205 0.686 -0.661 -0.304 0.822 3.256 12.307 0.483 -0.147 0.863 1.067 3.071 12.307 0.320 0.496 0.807 0.975 3.256 12.202 0.164 0.029 0.986 0.975 3.256 12.553 0.652 0.132 0.747 0.923 3.360 3.419 0.982 -0.189 0.025 0.865 3.476 12.307 0.123 -0.563 0.817 0.074 4.759 5.470 0.945 -0.131 0.299 0.287 4.632 5.470 0.520 0.821 0.234 0.223 4.759 5.368 0.423 -0.010 0.906 0.223 4.759 5.701 0.920 0.390 0.017 0.211 4.759 10.256 0.846 0.533 0.005 0.232 4.742 10.256 0.824 0.566 0.005 0.223 4.759 10.232 0.835 0.550 0.017 0.223 4.759 10.280 0.835 0.550 -0.007 2.578 0.250 1.367 -0.008 -0.981 -0.194 2.820 0.000 1.121 0.453 0.791 0.411 2.695 0.250 1.159 -0.186 -0.937 0.297 2.820 0.000 1.472 0.449 0.793 -0.412 2.695 0.250 1.459 -0.207 -0.895 -0.395 2.774 0.092 5.470 -0.318 -0.915 0.248 2.820 0.000 5.366 -0.332 -0.768 0.548 2.820 0.000 5.711 -0.417 -0.909 -0.004 2.658 0.323 1.367 -0.140 -0.956 -0.259 1.350 2.939 8.205 0.319 0.904 -0.284 1.317 3.006 7.999 0.380 0.924 -0.049 1.317 3.006 8.300 0.330 0.820 -0.468 1.227 3.186 3.419 0.416 0.909 0.011 1.192 3.256 3.338 0.427 0.870 0.245 1.192 3.256 3.501 0.420 0.886 -0.196 1.001 3.256 8.205 0.446 -0.847 -0.290 1.192 3.256 7.958 -0.011 -0.999 -0.034 1.192 3.256 8.297 -0.116 -0.699 -0.705 1.241 3.157 12.307 -0.011 0.471 0.882 1.192 3.256 12.214 0.017 0.254 0.967 1.192 3.256 12.535 -0.018 0.662 0.749 1.055 3.507 3.419 -0.942 -0.336 0.017 1.067 3.507 3.415 -0.957 -0.288 0.019 1.067 3.507 3.423 -0.958 -0.288 0.013 1.138 3.363 8.205 0.004 -0.928 -0.372 0.889 3.507 12.307 0.070 -0.593 0.802 1.067 3.507 12.238 -0.131 -0.406 0.904 1.067 3.507 12.472 -0.226 -0.651 0.725 1.063 3.514 3.419 -0.949 -0.313 0.016 1.040 3.560 12.307 -0.136 -0.509 0.850 0.472 4.695 5.470 0.146 0.944 0.297 0.440 4.759 5.395 0.130 0.850 0.510 0.440 4.759 5.651 0.164 0.980 0.112 0.469 4.701 10.256 0.461 0.887 0.006 0.440 4.759 10.171 0.492 0.866 0.084 0.440 4.759 10.342 0.491 0.868 -0.073 3.037 0.000 1.226 -0.424 0.878 0.221 2.912 0.250 1.148 -0.664 -0.279 0.693 3.037 0.000 1.441 -0.527 0.700 -0.482 2.912 0.250 1.458 -0.289 0.166 -0.943 2.987 0.099 5.470 -0.725 -0.662 0.192 3.037 0.000 5.378 -0.845 -0.319 0.430 3.037 0.000 5.648 -0.924 -0.379 0.058 2.783 0.250 10.256 -0.218 -0.976 -0.003 2.929 0.215 10.256 -0.178 -0.984 -0.006 2.912 0.250 10.184 -0.367 -0.929 0.041 2.912 0.250 10.327 -0.367 -0.929 -0.047 2.854 0.366 1.367 -0.480 -0.755 -0.447 2.891 0.292 10.256 -0.345 -0.939 -0.004 1.516 3.006 8.205 -0.275 0.931 -0.240 1.429 3.216 3.419 -0.998 0.060 0.001 1.409 3.256 3.353 -0.827 -0.539 0.163 1.409 3.256 3.484 -0.833 -0.531 -0.156 1.523 3.027 8.205 -0.330 0.909 -0.254 1.409 3.256 7.967 -0.998 -0.026 -0.065 1.409 3.256 8.297 -0.474 -0.023 -0.880 1.388 3.256 12.307 -0.258 0.516 0.817 1.069 3.507 3.419 -0.958 -0.288 0.016 1.390 3.294 3.419 -0.779 -0.626 0.009 1.299 3.475 8.205 -0.455 -0.854 -0.253 1.392 3.290 12.307 -0.318 0.448 0.835 1.283 3.507 12.243 -0.445 -0.216 0.869 1.283 3.507 12.434 -0.624 -0.287 0.726 1.069 3.757 3.419 0.814 -0.581 0.021 1.182 3.710 3.419 0.990 0.138 0.021 1.158 3.757 3.335 0.979 0.074 0.188 1.158 3.757 3.504 0.985 0.073 -0.154 1.252 3.569 12.307 -0.472 -0.342 0.812 1.137 3.799 3.419 0.887 -0.461 0.024 0.582 4.759 5.470 0.041 0.981 0.188 0.669 4.734 10.256 0.326 0.945 0.002 0.657 4.759 10.209 0.341 0.940 0.025 0.657 4.759 10.304 0.341 0.940 -0.022 3.093 0.000 1.367 -0.392 0.880 -0.269 3.120 0.250 1.367 -0.970 0.006 -0.243 3.114 0.000 5.470 -0.954 -0.164 0.252 3.208 0.000 10.256 0.718 0.696 0.000 3.254 0.000 10.143 0.814 0.575 0.076 3.128 0.250 10.152 -0.619 -0.781 0.086 3.254 0.000 10.369 0.814 0.576 -0.076 3.128 0.250 10.359 -0.617 -0.782 -0.088 3.093 0.322 10.256 -0.585 -0.811 -0.002 1.515 3.256 3.419 -0.642 0.766 0.000 1.560 3.256 8.205 -0.833 0.431 -0.348 1.450 3.507 3.419 0.941 0.337 0.007 1.578 3.350 3.419 0.119 0.993 0.001 1.500 3.507 3.312 0.921 0.369 0.128 1.500 3.507 3.526 0.920 0.372 -0.120 1.335 3.507 12.307 -0.534 -0.160 0.830 1.375 3.757 3.302 -0.683 -0.719 0.129 1.375 3.757 3.537 -0.685 -0.718 -0.120 1.341 3.826 3.419 -0.612 -0.791 0.004 0.712 4.759 10.256 0.270 0.963 0.001 3.350 0.000 10.256 0.377 0.926 0.000 3.262 0.250 10.256 -0.816 -0.578 0.000 1.599 3.507 3.419 0.072 0.997 0.007 1.512 3.757 3.419 -0.894 -0.448 0.003 3.134 1.503 8.205 0.963 0.198 -0.181 3.166 1.477 8.205 0.945 0.273 -0.178 3.153 1.503 8.150 0.965 0.217 -0.145 3.153 1.503 8.232 0.956 0.216 -0.200 3.121 1.566 8.205 0.982 0.001 -0.186 2.383 3.006 1.367 0.959 0.230 -0.166 2.414 2.981 1.367 0.940 0.299 -0.165 2.402 3.006 1.313 0.966 0.250 -0.070 2.402 3.006 1.396 0.951 0.248 -0.183 2.365 3.079 1.367 0.985 0.013 -0.175 3.343 1.252 3.419 0.914 0.407 -0.008 3.525 1.193 3.419 0.266 0.964 -0.008 3.495 1.252 3.317 0.151 0.975 0.162 3.495 1.252 3.519 0.155 0.970 -0.185 3.303 1.503 3.419 -0.547 -0.836 -0.042 3.370 1.503 3.389 -0.977 -0.212 0.008 3.370 1.503 3.447 -0.976 -0.213 -0.038 3.403 1.436 8.205 -0.182 0.925 -0.335 3.370 1.503 8.019 -0.202 0.972 -0.123 3.370 1.503 8.283 -0.359 0.792 -0.494 3.312 1.619 3.419 -0.124 -0.992 -0.032 3.117 1.753 8.205 0.586 -0.766 -0.265 3.245 1.753 7.967 -0.132 -0.991 -0.002 3.245 1.753 8.308 -0.363 -0.722 -0.589 3.243 1.753 12.307 0.720 -0.201 0.664 3.248 1.746 12.307 0.723 -0.184 0.666 3.245 1.753 12.305 0.719 -0.201 0.665 3.245 1.753 12.313 0.724 -0.202 0.660 3.200 1.842 8.205 -0.051 -0.943 -0.329 3.244 1.755 12.307 0.719 -0.204 0.665 2.653 2.937 1.367 -0.061 0.951 -0.304 2.618 3.006 1.156 -0.009 0.896 0.444 2.618 3.006 1.464 -0.191 0.843 -0.503 2.365 3.256 1.367 0.575 -0.763 -0.295 2.493 3.256 1.141 -0.316 -0.787 0.530 2.493 3.256 1.457 -0.578 -0.614 -0.538 2.488 3.256 5.470 0.971 -0.183 0.153 2.502 3.238 5.470 0.980 -0.128 0.154 2.493 3.256 5.461 0.971 -0.180 0.158 2.493 3.256 5.486 0.973 -0.181 0.144 2.303 3.256 10.256 0.985 0.172 -0.001 2.532 3.179 10.256 -0.215 0.977 -0.001 2.493 3.256 10.165 -0.687 0.712 0.145 2.493 3.256 10.347 -0.681 0.718 -0.143 2.445 3.352 1.367 -0.144 -0.924 -0.355 2.489 3.264 5.470 0.968 -0.199 0.153 2.295 3.507 10.256 0.474 -0.881 0.005 2.368 3.507 10.182 -0.509 -0.847 0.154 2.368 3.507 10.331 -0.508 -0.850 -0.141 2.329 3.585 10.256 0.191 -0.982 0.006 v_sim-3.8.0/examples/test_xyz.xyz000066400000000000000000000006351370110300500171140ustar00rootroot000000000000005 Mode 1: freq= 7.09 N -0.44003451495 -0.00038510790 2.12369783068 0.001 -0.151 -0.002 C -1.76594470239 0.00039861437 2.37754210613 0.001 -0.175 0.000 C -2.24923313135 -0.00145267054 3.67997125809 0.003 -0.198 0.001 Co -1.33887502024 -0.00450793845 4.73956848945 0.005 -0.183 -0.000 C 0.02462671625 -0.00591801736 4.46614405978 0.005 -0.146 -0.003 v_sim-3.8.0/examples/v_sim-values.xml000066400000000000000000000022061370110300500175770ustar00rootroot00000000000000 v_sim-3.8.0/examples/values.xml000066400000000000000000000014531370110300500164670ustar00rootroot00000000000000 v_sim-3.8.0/lib/000077500000000000000000000000001370110300500133735ustar00rootroot00000000000000v_sim-3.8.0/lib/Makefile.am000066400000000000000000000000321370110300500154220ustar00rootroot00000000000000SUBDIRS = plug-ins python v_sim-3.8.0/lib/plug-ins/000077500000000000000000000000001370110300500151315ustar00rootroot00000000000000v_sim-3.8.0/lib/plug-ins/Makefile.am000066400000000000000000000002021370110300500171570ustar00rootroot00000000000000SUBDIRS = nanoquanta-netcdf \ OpenBabel-wrapper \ xsf \ cube \ abinit \ python-gi \ archives \ bigdft \ fpcrystal \ msym v_sim-3.8.0/lib/plug-ins/OpenBabel-wrapper/000077500000000000000000000000001370110300500204365ustar00rootroot00000000000000v_sim-3.8.0/lib/plug-ins/OpenBabel-wrapper/Makefile.am000066400000000000000000000012111370110300500224650ustar00rootroot00000000000000## Process this file with automake to produce Makefile.in vpath %.h $(top_srcdir)/src libobloader_la_SOURCES = ob_basic.cpp libobloader_la_LDFLAGS = -module -version-info $(lib_v_sim_version) libobloader_la_LIBADD = $(top_builddir)/src/libv_sim-3.la \ $(OPENBABEL_LIBS) @GLIB_LIBS@ if HAVE_OPENBABEL OB_LIB = libobloader.la OB_PIX = openbabel.png endif v_simplugins_LTLIBRARIES = \ $(OB_LIB) AM_CPPFLAGS = \ -Wno-variadic-macros \ -I$(top_srcdir)/src \ $(OPENBABEL_CFLAGS) \ @GLIB_CFLAGS@ if PLATFORM_WIN32 cflagWin = -mms-bitfields -mno-cygwin endif AM_CXXFLAGS = $(cflagWin) v_simpixmaps_DATA = $(OB_PIX) EXTRA_DIST = openbabel.png v_sim-3.8.0/lib/plug-ins/OpenBabel-wrapper/ob_basic.cpp000066400000000000000000000336221370110300500227110ustar00rootroot00000000000000#pragma GCC diagnostic push #pragma GCC diagnostic ignored "-Wunused-parameter" #pragma GCC diagnostic ignored "-Wpedantic" #pragma GCC diagnostic ignored "-Wlong-long" #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #pragma GCC diagnostic pop using namespace OpenBabel; extern "C" { gboolean obloaderInit(); const char* obloaderGet_description(); const char* obloaderGet_authors(); const char* obloaderGet_icon(); } #define OPENBABEL_DESCRIPTION _("" \ "This plug-in wraps the OpenBabel\n" \ "library (visit the home page at URL\n" \ "http://www.openbabel.org).") #define OPENBABEL_AUTHORS _("Caliste Damien:\n wrapper.") /* Local variables. */ static gchar *iconPath; static VisuDataLoader *obLoader = NULL; /* Local methods. */ static gboolean saveOpenBabelFile(VisuDumpData *format, const char* filename, VisuData *dataObj, GError **error); static gboolean loadOpenBabelFile(VisuDataLoader *self, VisuDataLoadable *data, guint type, guint nSet, GCancellable *cancel, GError **error); VisuDataLoader* visu_data_loader_babel_getStatic(void) { return obLoader; } /* Required methods for a loadable module. */ gboolean obloaderInit() { const gchar *type[] = {(char*)0}; const gchar *typeOut[] = {(char*)"*.cif", (char*)"*.cml", (char*)"*.dmol", (char*)0}; VisuDumpData *dump; DBG_fprintf(stderr, "OpenBabel: loading plug-in 'openbabel'...\n"); obLoader = visu_data_loader_new(_("OpenBabel known formats"), type, FALSE, loadOpenBabelFile, 75); tool_file_format_addPropertyBoolean(TOOL_FILE_FORMAT(obLoader), "add-hydrogens", _("Add implicit hydrogens"), TRUE); visu_data_atomic_class_addLoader(obLoader); iconPath = g_build_filename(V_SIM_PIXMAPS_DIR, "openbabel.png", NULL); /* Declare the output using OpenBabel. */ dump = visu_dump_data_new(_("OpenBabel output formats"), typeOut, saveOpenBabelFile); g_object_set(G_OBJECT(dump), "ignore-type", TRUE, NULL); return TRUE; } const char* obloaderGet_description() { return OPENBABEL_DESCRIPTION; } const char* obloaderGet_authors() { return OPENBABEL_AUTHORS; } const char* obloaderGet_icon() { return (char*)iconPath; } static gboolean loadOpenBabelFile(VisuDataLoader *self, VisuDataLoadable *data, guint type, guint nSet _U_, GCancellable *cancel _U_, GError **error) { OpenBabel::OBMol mol; OpenBabel::OBFormat *pFormat, *xyzFormat; bool res; std::ifstream fin(visu_data_loadable_getFilename(data, type)); std::istream* pIn = &fin; OpenBabel::OBConversion conv(pIn, NULL); VisuDataLoaderIter *iter; int i, j; VisuElement *ele1, *ele2; OpenBabel::OBUnitCell *uc; double rprimdFull[9], rprimd[3][3]; double eleRGB[3]; float xyz[3], xyz0[3], red[3], rgba[4], length, lengthMin, lengthMax; VisuPairSet *pairs; VisuPairLink *link; gchar *infoUTF8; double vect[3], radius; gboolean newEle; VisuBox *box; VisuElementAtomic *renderer; VisuNodeValues *vals, *hc; GValue hv = G_VALUE_INIT; g_return_val_if_fail(error && *error == (GError*)0, FALSE); /* Try to guess the file format. */ DBG_fprintf(stderr, "Open Babel: try to guess the file format of '%s'.\n", visu_data_loadable_getFilename(data, type)); pFormat = conv.FormatFromExt(visu_data_loadable_getFilename(data, type)); if (!pFormat) { *error = g_error_new(VISU_DATA_LOADABLE_ERROR, DATA_LOADABLE_ERROR_FORMAT, _("'%s' doesn't match any file format."), visu_data_loadable_getFilename(data, type)); return FALSE; } if ( pFormat->Flags() & NOTREADABLE ) { *error = g_error_new(VISU_DATA_LOADABLE_ERROR, DATA_LOADABLE_ERROR_FORMAT, _("format of '%s' is not a readable one."), visu_data_loadable_getFilename(data, type)); return FALSE; } /* Exclude the xyz file format since V_Sim handles it natively. */ xyzFormat = conv.FindFormat("xyz"); if (xyzFormat == pFormat) { DBG_fprintf(stderr, "OpenBabel: skip XYZ format.\n"); return FALSE; } DBG_fprintf(stderr, " | set format %p.\n", (gpointer)pFormat); DBG_fprintf(stderr, " | format description\n%s\n", pFormat->Description()); conv.SetInFormat(pFormat); /* Read the file. */ DBG_fprintf(stderr, "Open Babel: read the file.\n"); res = conv.Read(&mol); fin.close(); DBG_fprintf(stderr, " | read OK.\n"); if (!res) { *error = g_error_new(VISU_DATA_LOADABLE_ERROR, DATA_LOADABLE_ERROR_FORMAT, _("The given file doesn't match the format '%s'."), tool_file_format_getName(TOOL_FILE_FORMAT(self))); return FALSE; } if (tool_file_format_getPropertyBoolean(TOOL_FILE_FORMAT(self), "add-hydrogens")) mol.AddHydrogens(); /* Store if the file is periodic or not. */ uc = (OBUnitCell*)mol.GetData(OBGenericDataType::UnitCell); if (uc) { DBG_fprintf(stderr, "OpenBabel: file has periodic conditions.\n"); uc->GetCellMatrix().GetArray(rprimdFull); for (i = 0; i < 3; i++) { for (j = 0; j < 3; j++) rprimd[i][j] = rprimdFull[i * 3 + j]; DBG_fprintf(stderr, " | ( %g , %g , %g )\n", rprimd[0][i], rprimd[1][i], rprimd[2][i]); } box = visu_box_new_full(rprimd, VISU_BOX_PERIODIC); if (visu_box_getGeometry(box, VISU_BOX_DXX) == G_MAXFLOAT) { *error = g_error_new(VISU_DATA_LOADABLE_ERROR, DATA_LOADABLE_ERROR_FORMAT, _("Wrong OpenBabel format, basis-set is degenerated.\n")); g_object_unref(box); return TRUE; } visu_boxed_setBox(VISU_BOXED(data), VISU_BOXED(box)); g_object_unref(box); uc->GetOffset().Get(vect); uc->FillUnitCell(&mol); } else { DBG_fprintf(stderr, "OpenBabel: file has no periodic conditions.\n"); for (i = 0; i < 3; i++) vect[i] = 0.; box = (VisuBox*)0; } DBG_fprintf(stderr, "OpenBabel: first pass to find Elements.\n"); iter = visu_data_loader_iter_new(); for (OpenBabel::OBMolAtomIter a(mol); a; ++a) { ele1 = visu_element_retrieveFromName(OBElements::GetSymbol(a->GetAtomicNum()), &newEle); visu_data_loader_iter_addNode(iter, ele1); if (newEle) { renderer = visu_element_atomic_getFromPool(ele1); // We use the standard OB colours. OBElements::GetRGB(a->GetAtomicNum(), eleRGB, eleRGB + 1, eleRGB + 2); rgba[0] = eleRGB[0]; rgba[1] = eleRGB[1]; rgba[2] = eleRGB[2]; rgba[3] = 1.f; visu_element_renderer_setColor(VISU_ELEMENT_RENDERER(renderer), tool_color_addFloatRGBA(rgba, (int*)0)); // We use standard radius for element. radius = OBElements::GetCovalentRad(a->GetAtomicNum()); visu_element_atomic_setRadius(renderer, radius); } } visu_data_loader_iter_allocate(iter, VISU_NODE_ARRAY(data)); visu_data_loader_iter_unref(iter); vals = (VisuNodeValues*)0; hc = (VisuNodeValues*)0; g_value_init(&hv, G_TYPE_INT); /* Stores coordinates. */ FOR_ATOMS_OF_MOL(a,&mol) { VisuNode *node; xyz0[0] = xyz[0] = (float)a->GetX() + vect[0]; xyz0[1] = xyz[1] = (float)a->GetY() + vect[1]; xyz0[2] = xyz[2] = (float)a->GetZ() + vect[2]; if (uc) { visu_box_convertFullToCell(box, xyz, xyz0); visu_box_convertXYZtoBoxCoordinates(box, red, xyz); if (red[0] > 1 - 1e-6 || red[1] > 1 - 1e-6 || red[2] > 1 - 1e-6) continue; } ele1 = visu_element_lookup(OBElements::GetSymbol(a->GetAtomicNum())); node = visu_data_addNodeFromElement(VISU_DATA(data), ele1, xyz, FALSE); OpenBabel::OBResidue *residue = a->GetResidue(); if (residue) { VisuNodeFragment frag; if (!vals) { vals = VISU_NODE_VALUES (visu_node_values_frag_new(VISU_NODE_ARRAY(data), _("Fragment"))); visu_data_addNodeProperties(VISU_DATA(data), vals); } frag.label = (char*)residue->GetName().c_str(); frag.id = residue->GetNum(); visu_node_values_frag_setAt(VISU_NODE_VALUES_FRAG(vals), node, &frag); } if (a->GetImplicitHCount()) { if (!hc) { hc = visu_node_values_new(VISU_NODE_ARRAY(data), _("Implicit H"), G_TYPE_INT, 1); visu_data_addNodeProperties(VISU_DATA(data), hc); } g_value_set_int(&hv, a->GetImplicitHCount()); visu_node_values_setAt(hc, node, &hv); } } if (!uc) box = visu_data_setTightBox(VISU_DATA(data)); /* Set the bonds, if any. */ pairs = visu_pair_set_new(); visu_pair_set_setModel(pairs, VISU_DATA(data)); FOR_BONDS_OF_MOL(b, &mol) { ele1 = visu_element_lookup(OBElements::GetSymbol(b->GetBeginAtom()->GetAtomicNum())); ele2 = visu_element_lookup(OBElements::GetSymbol(b->GetEndAtom()->GetAtomicNum())); link = visu_pair_getNthLink(visu_pair_set_get(pairs, ele1, ele2), 0); lengthMin = visu_pair_link_getDistance(link, VISU_DISTANCE_MIN); lengthMax = visu_pair_link_getDistance(link, VISU_DISTANCE_MAX); length = (float)b->GetLength(); if (lengthMax < length) visu_pair_link_setDistance(link, length, VISU_DISTANCE_MAX); if (lengthMin > length || lengthMin == 0.) visu_pair_link_setDistance(link, length, VISU_DISTANCE_MIN); } g_object_unref(pairs); /* Set the commentary. */ if (mol.GetTitle()) { infoUTF8 = g_locale_to_utf8(mol.GetTitle(), -1, NULL, NULL, NULL); if (infoUTF8) { visu_data_setDescription(VISU_DATA(data), infoUTF8); g_free(infoUTF8); } else { g_warning("Can't convert '%s' to UTF8.\n", mol.GetTitle()); } } return TRUE; } static gboolean saveOpenBabelFile(VisuDumpData *format _U_, const char* filename, VisuData *dataObj, GError **error) { std::ofstream fout(filename); std::ostream* pOut = &fout; OpenBabel::OBConversion conv(NULL, pOut); OpenBabel::OBFormat *pFormat; OpenBabel::OBMol *mol; OpenBabel::OBAtom *atom; OpenBabel::OBResidue *residue; OpenBabel::OBUnitCell *cell; OpenBabel::vector3 a(0.,0.,0.), b(0.,0.,0.), c(0.,0.,0.); VisuNodeArrayIter iter; float coord[3]; bool res; const gchar *comment; double matrix[3][3]; VisuNodeValuesFrag *frags; const VisuNodeFragment *frag; /* Try to guess the file format. */ DBG_fprintf(stderr, "Open Babel: try to guess the fileformat of '%s'.\n", filename); pFormat = conv.FormatFromExt(filename); if (!pFormat) { *error = g_error_new(VISU_DUMP_ERROR, DUMP_ERROR_FILE, _("'%s' doesn't match any file format."), filename); fout.close(); return FALSE; } if ( pFormat->Flags() & NOTWRITABLE ) { *error = g_error_new(VISU_DUMP_ERROR, DUMP_ERROR_FILE, _("format of '%s' is not a readable one."), filename); fout.close(); return FALSE; } DBG_fprintf(stderr, " | set format %p.\n", (gpointer)pFormat); DBG_fprintf(stderr, " | format description\n%s\n", pFormat->Description()); conv.SetOutFormat(pFormat); /* Create a new OpenBabel object. */ mol = new OpenBabel::OBMol; comment = visu_data_getDescription(dataObj); if (comment) mol->SetTitle(comment); if (visu_box_getBoundary(visu_boxed_getBox(VISU_BOXED(dataObj))) != VISU_BOX_FREE) { cell = new OpenBabel::OBUnitCell; visu_box_getCellMatrix(visu_boxed_getBox(VISU_BOXED(dataObj)), matrix); a.Set(matrix[0]); b.Set(matrix[1]); c.Set(matrix[2]); cell->SetData(a, b, c); mol->SetData(cell); } frags = VISU_NODE_VALUES_FRAG(visu_data_getNodeProperties(dataObj, _("Fragment"))); visu_node_array_iter_new(VISU_NODE_ARRAY(dataObj), &iter); mol->ReserveAtoms(iter.nAllStoredNodes); for (visu_node_array_iterStart(VISU_NODE_ARRAY(dataObj), &iter); iter.node; visu_node_array_iterNext(VISU_NODE_ARRAY(dataObj), &iter)) { atom = mol->NewAtom(); atom->SetAtomicNum(OBElements::GetAtomicNum(iter.element->name)); visu_data_getNodePosition(dataObj, iter.node, coord); atom->SetVector((double)coord[0], (double)coord[1], (double)coord[2]); if (frags && (frag = visu_node_values_frag_getAt(frags, iter.node))) { residue = NULL; FOR_RESIDUES_OF_MOL(r, mol) if (r->GetName() == frag->label && guint(r->GetNum()) == frag->id) { residue = &(*r); break; } if (!residue) { residue = mol->NewResidue(); residue->SetName(frag->label); residue->SetNum(frag->id); } residue->AddAtom(atom); } } DBG_fprintf(stderr, "Open Babel: calling write routine.\n"); res = conv.Write(mol); DBG_fprintf(stderr, "Open Babel: free memory.\n"); delete mol; fout.close(); if (!res) { *error = g_error_new(VISU_DUMP_ERROR, DUMP_ERROR_FILE, _("Unable to write the file.")); return FALSE; } DBG_fprintf(stderr, "Open Babel: write succeed.\n"); return TRUE; } v_sim-3.8.0/lib/plug-ins/OpenBabel-wrapper/openbabel.png000066400000000000000000000054171370110300500231020ustar00rootroot00000000000000PNG  IHDR VόbKGD pHYs.#.#x?vtIME9: IDATHǭWiU~w~~I$:! Z,NA&S3UԄRA@HB NعI:Mw:}kۿb MEy{9e_T֮]+3㳿rï֯YLd*^Φ!}X>-V؝ G_Qѥe3Fs0LB CW[y#Xo5#3mR>8Ķ+{ۂ d,bSlnnNbqEVsQ?(,:̽pbn?TeA!,N|bR,_|_}Ta bĢbڤvٚ Bk S Ȃ I )U.AQ}_(bq]vYl}g?is=׌9FnxU3}X0vFFA(sVX`@qR׽<w#xwogzm>4.vc>)!4Igi zR#% K?3z{{AI߯Tg.l>iӕ3pe]VD1!,s1@р@K' G ' s.|nJ&&FlY## oqأdzчSx(}-@( $`qQ< @L(j;`||\k6ͷzkOnu|bb}me5fW\Gjg`i I ڀz@3ǘEE0yq`l#MӺ"4= yLW;+v=+7tJ VǵIE37g]x fr NMEa$ e}T,ȇzW cxddiPԶ$%NLڶ+?c -$x  ^*QzqkGٍDUZMlN^uB鍦^"qqLeT6dfgO jJɖPe۶#wLOk2qIѢѦ85L h@O4v,0}|d  7MC,i: r8 j/ ۶}s'Ye%M7/}pj 6rsumMwupQ2?oB\lKŽ?ƗFM6nB!wM\ Y?z̾WW{rC;?q&a݁᪆C@j@@Qh>3(j|̀0,['m}ji鎌yk˓' E1@7q B0bER{tX*CeqXƑFG`.,4<Ʋ+ }YPJI:=;ߙϿ/_YwO-J Ki*~@IՎ3Y92Jsض `4(#BGQV*2`) {ךDV'3A[y, x3c@aP1;;YUCB8GOrk[پvݝVd8L@uqT`Y{kwYw*p2HTDWAxrJP ru\_A1,+  D%)Ml8p  ²LԛLˆE @]L9A SR`ojg*%3<'&~G$?Fg5lTOۺnPC7=j TuX&cɕ8J^ 覴/BʔF ߏ*' pixh`D3g˥j5W\m/bzjP`; 4  <= $/'A2!$pLGacQ,(OOcJ>ua&R.Y<#80:/zn{e}ܼ)pGmqHwٌPC`bIH<Y׼||llrZ'#a̡BF)5ł,#[$*OmWm*]b)BdB5.&7~{knnNK{4MN>??_Cd*&A %%(\Mg2 _)i"iIENDB`v_sim-3.8.0/lib/plug-ins/README000066400000000000000000000012541370110300500160130ustar00rootroot00000000000000In each directory, a dynamic loadable library is built (.so under most Unix and .dll on Windows). All these library must have the following functions : - gboolean Init(); When V_Sim is started, it scans the directory where loadable modules are stored and proposes to the user the possibility to load the plug-in, calling this method. For example, if the plug-in brings new file formats for loading, it can add its new ones using appropriated methods from V_Sim. - const gchar* Get_description(); This method returns a short text describing the plug-in. This text is own by the plug-in and will not be altered by C_Sim. It must be in UTF-8. v_sim-3.8.0/lib/plug-ins/abinit/000077500000000000000000000000001370110300500163775ustar00rootroot00000000000000v_sim-3.8.0/lib/plug-ins/abinit/Makefile.am000066400000000000000000000077761370110300500204540ustar00rootroot00000000000000## Process this file with automake to produce Makefile.in vpath %.h $(top_srcdir)/src if PLATFORM_WIN32 cflagWin = -mms-bitfields -mno-cygwin endif ABINIT_MISC_SOURCES = defs_basis.F90 m_profiling_abi.F90 interfaces_32_util.F90 mati3det.F90 mati3inv.F90 metric.F90 m_errors.F90 m_xmpi.F90 m_io_tools.F90 m_fstrings.F90 m_build_info.F90 m_cppopts_dumper.F90 interfaces_14_hidewrite.F90 interfaces_16_hideleave.F90 matr3inv.F90 m_numeric_tools.F90 m_linalg_interfaces.F90 interfaces_28_numeric_noabirule.F90 coeffs_gausslegint.F90 abi_common.h ABINIT_SYMMETRY_SOURCES = ab7_symmetry.fortran.h m_ab7_symmetry.F90 interfaces_41_geometry.F90 spgdata.F90 symanal.F90 symatm.F90 symcharac.F90 symfind.F90 symlatt.F90 chkprimit.F90 getptgroupma.F90 holocell.F90 smallprim.F90 symaxes.F90 symbrav.F90 symchk.F90 symplanes.F90 symptgroup.F90 symrelrot.F90 symspgr.F90 symdet.F90 symlist_bcc.F90 symlist_fcc.F90 symlist_others.F90 symlist_prim.F90 xred2xcart.F90 noinst_LIBRARIES = libabfork.a libabfork_a_SOURCES = $(ABINIT_MISC_SOURCES) $(ABINIT_SYMMETRY_SOURCES) AM_FCFLAGS = -fPIC libabinit_la_SOURCES = ab7_base.h ab7_base.c ab7_symmetry.c ab7_symmetry.h abinit.c abinit.h ab_symmetry.h ab_symmetry.c libabinit_la_LIBADD = $(top_builddir)/src/libv_sim-3.la libabfork.a \ @GLIB_LIBS@ @AB_LIBS@ $(FCLIBS) libabinit_la_LDFLAGS = -module @EXTRA_LDFLAGS@ -version-info $(lib_v_sim_version) CLEANFILES = *.mod if HAVE_ABINIT AB_LIB = libabinit.la AB_EXAMPLE = ab_silicon.in AB_PIX = abinit.png endif v_simplugins_LTLIBRARIES = $(AB_LIB) AM_CPPFLAGS = \ -I$(top_srcdir)/src \ @AB_CPPFLAGS@ \ @GLIB_CFLAGS@ \ @GTKS_CFLAGS@ AM_CFLAGS = $(cflagWin) v_simexamples_DATA = $(AB_EXAMPLE) v_simpixmaps_DATA = $(AB_PIX) ABINIT_MPI_INCS = xmpi_allgather.finc xmpi_allgather.finc xmpi_alltoallv.finc xmpi_gather.finc xmpi_ialltoallv.finc xmpi_isum.finc xmpi_min.finc xmpi_send.finc xmpi_allgatherv.finc xmpi_bcast.finc xmpi_gatherv.finc xmpi_irecv.finc xmpi_land_lor.finc xmpi_recv.finc xmpi_sum.finc xmpi_alltoall.finc xmpi_exch.finc xmpi_ialltoall.finc xmpi_isend.finc xmpi_max.finc xmpi_scatterv.finc xmpi_sum_master.finc EXTRA_DIST = ab_silicon.in abinit.png $(ABINIT_MPI_INCS) m_profiling_abi.o: m_profiling_abi.F90 defs_basis.o interfaces_32_util.o: interfaces_32_util.F90 defs_basis.o m_io_tools.o: m_io_tools.F90 defs_basis.o m_fstrings.o: m_fstrings.F90 defs_basis.o m_cppopts_dumper.o: m_cppopts_dumper.F90 defs_basis.o interfaces_28_numeric_noabirule.o: interfaces_28_numeric_noabirule.F90 defs_basis.o interfaces_41_geometry.o: interfaces_41_geometry.F90 defs_basis.o coeffs_gausslegint.o: coeffs_gausslegint.F90 m_profiling_abi.o m_ab7_symmetry.o: m_ab7_symmetry.F90 defs_basis.o m_profiling_abi.o interfaces_41_geometry.o interfaces_32_util.o mati3det.o: mati3det.F90 m_errors.o matr3inv.o: matr3inv.F90 m_errors.o mati3inv.o: mati3inv.F90 m_errors.o metric.o: metric.F90 m_errors.o m_errors.o: m_errors.F90 m_xmpi.o m_fstrings.o m_build_info.o m_cppopts_dumper.o interfaces_14_hidewrite.o interfaces_16_hideleave.o m_xmpi.o: m_xmpi.F90 m_io_tools.o $(ABINIT_MPI_INCS) symspgr.o: symspgr.F90 m_numeric_tools.o m_numeric_tools.o: m_numeric_tools.F90 m_errors.o m_linalg_interfaces.o interfaces_28_numeric_noabirule.o holocell.o: holocell.F90 m_errors.o smallprim.o: smallprim.F90 m_errors.o symatm.o: symatm.F90 m_errors.o symbrav.o: symbrav.F90 m_errors.o chkprimit.o: chkprimit.F90 m_errors.o symfind.o: symfind.F90 m_errors.o symaxes.o: symaxes.F90 m_errors.o symchk.o: symchk.F90 m_errors.o symlatt.o: symlatt.F90 m_errors.o symplanes.o: symplanes.F90 m_errors.o symanal.o: symanal.F90 m_errors.o symcharac.o: symcharac.F90 m_errors.o symdet.o: symdet.F90 m_errors.o symptgroup.o: symptgroup.F90 m_errors.o xred2xcart.o: xred2xcart.F90 m_errors.o symrelrot.o: symrelrot.F90 m_errors.o symlist_fcc.o: symlist_fcc.F90 m_profiling_abi.o spgdata.o: spgdata.F90 m_profiling_abi.o getptgroupma.o: getptgroupma.F90 m_profiling_abi.o symlist_others.o: symlist_others.F90 m_profiling_abi.o symlist_prim.o: symlist_prim.F90 m_profiling_abi.o symlist_bcc.o: symlist_bcc.F90 m_profiling_abi.o v_sim-3.8.0/lib/plug-ins/abinit/ab7_base.c000066400000000000000000000022451370110300500202110ustar00rootroot00000000000000/** -*- C source file -*- * * Copyright (C) 2009-2016 ABINIT Group (Damien Caliste) * * This file is part of the ABINIT software package. For license information, * please see the COPYING file in the top-level directory of the ABINIT source * distribution. * */ #include "ab7_base.h" #include /* AB7_NO_ERROR, AB7_ERROR_OBJ, AB7_ERROR_ARG, AB7_ERROR_INVARS_ATT, AB7_ERROR_INVARS_ID, AB7_ERROR_INVARS_SIZE, AB7_ERROR_SYM_NOT_PRIMITIVE, AB7_ERROR_SYM_BRAVAIS_XRED */ static char* messages[8] = { "No error.", "Wrong pointer to object.", "Wrong value for one argument of the calling routine.", "Unknown attribute or wrong attribute type from Dtset structure.", "Out of bounds dtset number.", "Wrong input size for array.", "The cell is not primitive.", "The bravais lattice has more symmetries than the lattice" " system found from the atom coordinates."}; char* ab7_error_string_from_id(Ab7Error errno) { if (errno >= AB7_N_ERRORS) return "Unknown error id."; else return messages[errno]; } void ABI_FC_MOD(m_xmpi,M_XMPI, xmpi_init,XMPI_INIT)(); void ab7_mpi_init() { ABI_FC_MOD(m_xmpi,M_XMPI, xmpi_init,XMPI_INIT)(); } v_sim-3.8.0/lib/plug-ins/abinit/ab7_base.h000066400000000000000000000020001370110300500202030ustar00rootroot00000000000000/** -*- C header file -*- * * Copyright (C) 2009-2016 ABINIT Group (Damien Caliste) * * This file is part of the ABINIT software package. For license information, * please see the COPYING file in the top-level directory of the ABINIT source * distribution. * */ #ifndef AB7_BASE #define AB7_BASE /** * Ab7Error: * @AB7_NO_ERROR: no error. * @AB7_ERROR_INVARS_OBJ: wrong dataset object. * @AB7_ERROR_INVARS_ATT: wrong attribute in dataset. * @AB7_ERROR_INVARS_ID: wrong dataset index. * @AB7_ERROR_INVARS_SIZE: wrong size when accessing arrays. * * An error code. */ typedef enum { AB7_NO_ERROR, AB7_ERROR_OBJ, AB7_ERROR_ARG, AB7_ERROR_INVARS_ATT, AB7_ERROR_INVARS_ID, AB7_ERROR_INVARS_SIZE, AB7_ERROR_SYM_NOT_PRIMITIVE, AB7_ERROR_SYM_BRAVAIS_XRED, AB7_N_ERRORS } Ab7Error; char* ab7_error_string_from_id(Ab7Error errno); void ab7_mpi_init(); #ifndef GLIB_MAJOR_VERSION typedef int gboolean; #define g_malloc(A) malloc(A) #define g_free(A) free(A) #endif #endif v_sim-3.8.0/lib/plug-ins/abinit/ab7_symmetry.c000066400000000000000000000176021370110300500211730ustar00rootroot00000000000000/** - C source file - * * Copyright (C) 2009-2016 ABINIT Group (Damien Caliste) * * This file is part of the ABINIT software package. For license information, * please see the COPYING file in the top-level directory of the ABINIT source * distribution. * */ #include #include #include #include "ab7_symmetry.h" Ab7Symmetry* ab7_symmetry_new() { Ab7Symmetry *sym, tmpSym; SYM_CALL(new,NEW, &tmpSym); if (tmpSym > 0) { sym = g_malloc(sizeof(Ab7Symmetry)); *sym = tmpSym; } else sym = (Ab7Symmetry*)0; return sym; } void ab7_symmetry_free(Ab7Symmetry *sym) { SYM_CALL(free,FREE, sym); g_free(sym); } Ab7Error ab7_symmetry_set_tolerance(Ab7Symmetry *sym, double tolsym) { Ab7Error ab7_errno; SYM_CALL(set_tolerance,SET_TOLERANCE, sym, &tolsym, &ab7_errno); return ab7_errno; } Ab7Error ab7_symmetry_set_lattice(Ab7Symmetry *sym, double rprimd[3][3]) { Ab7Error ab7_errno; double rprimd_[9]; rprimd_[0] = rprimd[0][0]; rprimd_[1] = rprimd[1][0]; rprimd_[2] = rprimd[2][0]; rprimd_[3] = rprimd[0][1]; rprimd_[4] = rprimd[1][1]; rprimd_[5] = rprimd[2][1]; rprimd_[6] = rprimd[0][2]; rprimd_[7] = rprimd[1][2]; rprimd_[8] = rprimd[2][2]; SYM_CALL(set_lattice,SET_LATTICE, sym, rprimd_, &ab7_errno); return ab7_errno; } Ab7Error ab7_symmetry_set_structure(Ab7Symmetry *sym, int natoms, int *typeAt, double *xRed) { Ab7Error ab7_errno; SYM_CALL(set_structure,SET_STRUCTURE, sym, &natoms, typeAt, xRed, &ab7_errno); return ab7_errno; } Ab7Error ab7_symmetry_set_spin(Ab7Symmetry *sym, double *spinAt) { Ab7Error ab7_errno; int nAtoms; SYM_CALL(get_n_atoms,GET_N_ATOMS, sym, &nAtoms, &ab7_errno); if (ab7_errno != AB7_NO_ERROR) return ab7_errno; SYM_CALL(set_spin,SET_SPIN, sym, &nAtoms, spinAt, &ab7_errno); return ab7_errno; } Ab7Error ab7_symmetry_set_collinear_spin(Ab7Symmetry *sym, int *spinAt) { Ab7Error ab7_errno; int nAtoms; SYM_CALL(get_n_atoms,GET_N_ATOMS, sym, &nAtoms, &ab7_errno); if (ab7_errno != AB7_NO_ERROR) return ab7_errno; SYM_CALL(set_collinear_spin,SET_COLLINEAR_SPIN, sym, &nAtoms, spinAt, &ab7_errno); return ab7_errno; } Ab7Error ab7_symmetry_set_spin_orbit(Ab7Symmetry *sym, gboolean status) { Ab7Error ab7_errno; SYM_CALL(set_spin_orbit,SET_SPIN_ORBIT, sym, &status, &ab7_errno); return ab7_errno; } Ab7Error ab7_symmetry_set_field(Ab7Symmetry *sym, double field[3]) { Ab7Error ab7_errno; SYM_CALL(set_field,SET_FIELD, sym, field, &ab7_errno); return ab7_errno; } Ab7Error ab7_symmetry_set_jellium(Ab7Symmetry *sym, gboolean jellium) { Ab7Error ab7_errno; SYM_CALL(set_jellium,SET_JELLIUM, sym, &jellium, &ab7_errno); return ab7_errno; } Ab7Error ab7_symmetry_set_periodicity(Ab7Symmetry *sym, gboolean periodic[3]) { Ab7Error ab7_errno; SYM_CALL(set_periodicity,SET_PERIODICITY, sym, periodic, &ab7_errno); return ab7_errno; } Ab7Error ab7_symmetry_get_n_atoms(Ab7Symmetry *sym, int *nAtoms) { Ab7Error ab7_errno; SYM_CALL(get_n_atoms,GET_N_ATOMS, sym, nAtoms, &ab7_errno); return ab7_errno; } Ab7Error ab7_symmetry_get_n_sym(Ab7Symmetry *sym, int *nSym) { Ab7Error ab7_errno; SYM_CALL(get_n_sym,GET_N_SYM, sym, nSym, &ab7_errno); return ab7_errno; } Ab7Error ab7_symmetry_get_multiplicity(Ab7Symmetry *sym, int *multiplicity) { Ab7Error ab7_errno; SYM_CALL(get_multiplicity,GET_MULTIPLICITY, sym, multiplicity, &ab7_errno); return ab7_errno; } Ab7Error ab7_symmetry_get_bravais(Ab7Symmetry *sym, int bravais[3][3], int *holohedry, int *center, int *nBravSym, Ab7SymmetryMat **bravSym) { Ab7Error ab7_errno; int bravais_[9]; int syms[3 * 3 * AB7_MAX_SYMMETRIES]; int i; SYM_CALL(get_bravais,GET_BRAVAIS, sym, bravais_, holohedry, center, nBravSym, syms, &ab7_errno); if (ab7_errno != AB7_NO_ERROR) return ab7_errno; *bravSym = g_malloc(sizeof(Ab7SymmetryMat) * (*nBravSym)); for (i = 0; i < *nBravSym; i++) { (*bravSym)[i].mat[0][0] = syms[9 * i + 0]; (*bravSym)[i].mat[0][1] = syms[9 * i + 1]; (*bravSym)[i].mat[0][2] = syms[9 * i + 2]; (*bravSym)[i].mat[1][0] = syms[9 * i + 3]; (*bravSym)[i].mat[1][1] = syms[9 * i + 4]; (*bravSym)[i].mat[1][2] = syms[9 * i + 5]; (*bravSym)[i].mat[2][0] = syms[9 * i + 6]; (*bravSym)[i].mat[2][1] = syms[9 * i + 7]; (*bravSym)[i].mat[2][2] = syms[9 * i + 8]; } bravais[0][0] = bravais_[0]; bravais[0][1] = bravais_[1]; bravais[0][2] = bravais_[2]; bravais[1][0] = bravais_[3]; bravais[1][1] = bravais_[4]; bravais[1][2] = bravais_[5]; bravais[2][0] = bravais_[6]; bravais[2][1] = bravais_[7]; bravais[2][2] = bravais_[8]; return ab7_errno; } Ab7Error ab7_symmetry_get_matrices(Ab7Symmetry *sym, int *nSym, Ab7SymmetryMat **syms, Ab7SymmetryTrans **transNon, int **symAfm) { Ab7Error ab7_errno; int syms_[3 * 3 * AB7_MAX_SYMMETRIES]; int symAfm_[AB7_MAX_SYMMETRIES]; double trans[3 * AB7_MAX_SYMMETRIES]; int i; SYM_CALL(get_matrices,GET_MATRICES, sym, nSym, syms_, trans, symAfm_, &ab7_errno); if (ab7_errno != AB7_NO_ERROR && ab7_errno != AB7_ERROR_SYM_BRAVAIS_XRED) return ab7_errno; if (syms) *syms = g_malloc(sizeof(Ab7SymmetryMat) * (*nSym)); if (transNon) *transNon = g_malloc(sizeof(Ab7SymmetryTrans) * (*nSym)); if (symAfm) *symAfm = g_malloc(sizeof(int) * (*nSym)); for (i = 0; i < *nSym; i++) { if (syms) { (*syms)[i].mat[0][0] = syms_[9 * i + 0]; (*syms)[i].mat[0][1] = syms_[9 * i + 1]; (*syms)[i].mat[0][2] = syms_[9 * i + 2]; (*syms)[i].mat[1][0] = syms_[9 * i + 3]; (*syms)[i].mat[1][1] = syms_[9 * i + 4]; (*syms)[i].mat[1][2] = syms_[9 * i + 5]; (*syms)[i].mat[2][0] = syms_[9 * i + 6]; (*syms)[i].mat[2][1] = syms_[9 * i + 7]; (*syms)[i].mat[2][2] = syms_[9 * i + 8]; } if (transNon) { (*transNon)[i].vect[0] = trans[0]; (*transNon)[i].vect[1] = trans[1]; (*transNon)[i].vect[2] = trans[2]; } if (symAfm) (*symAfm)[i] = symAfm_[i]; } return ab7_errno; } Ab7Error ab7_symmetry_get_group(Ab7Symmetry *sym, char **spaceGroup, int *spaceGroupId, int *pointGroupMagn, double genAfm[3]) { Ab7Error ab7_errno; char name[15]; int i; SYM_CALL(get_group,GET_GROUP, sym, name, spaceGroupId, pointGroupMagn, genAfm, &ab7_errno); if (ab7_errno != AB7_NO_ERROR && ab7_errno != AB7_ERROR_SYM_BRAVAIS_XRED) return ab7_errno; *spaceGroup = g_malloc(sizeof(char) * 16); for (i = 0; i < 15; i++) (*spaceGroup)[i] = name[i]; for (i = 14; i >= 0; i--) if ((*spaceGroup)[i] == ' ') (*spaceGroup)[i] = '\0'; else break; (*spaceGroup)[15] = '\0'; return ab7_errno; } Ab7Error ab7_symmetry_get_equivalent_atom(Ab7Symmetry *sym, int **equiv, int *nSym, int iAtom) { Ab7Error ab7_errno; int equiv_[4 * AB7_MAX_SYMMETRIES]; int i; SYM_CALL(get_equivalent_atom,GET_EQUIVALENT_ATOM, sym, equiv_, &iAtom, &ab7_errno); if (ab7_errno != AB7_NO_ERROR && ab7_errno != AB7_ERROR_SYM_BRAVAIS_XRED) return ab7_errno; ab7_errno = ab7_symmetry_get_n_sym(sym, nSym); if (ab7_errno != AB7_NO_ERROR) return ab7_errno; *equiv = g_malloc(sizeof(int) * 4 * (*nSym)); for (i = 0; i < *nSym; i++) { (*equiv)[i * 4 + 0] = equiv_[i * 4 + 0]; (*equiv)[i * 4 + 1] = equiv_[i * 4 + 1]; (*equiv)[i * 4 + 2] = equiv_[i * 4 + 2]; (*equiv)[i * 4 + 3] = equiv_[i * 4 + 3]; } return ab7_errno; } Ab7Error ab7_symmetry_get_type(Ab7Symmetry *sym, int *type, char **label, int iSym) { Ab7Error ab7_errno; char label_[128]; int i; SYM_CALL(get_type, GET_TYPE, sym, &iSym, label_, type, &ab7_errno); if (ab7_errno != AB7_NO_ERROR && ab7_errno != AB7_ERROR_SYM_BRAVAIS_XRED) return ab7_errno; *label = g_malloc(sizeof(char) * 129); for (i = 0; i < 128; i++) (*label)[i] = label_[i]; for (i = 127; i >= 0; i--) if ((*label)[i] == ' ') (*label)[i] = '\0'; else break; (*label)[128] = '\0'; return ab7_errno; } v_sim-3.8.0/lib/plug-ins/abinit/ab7_symmetry.fortran.h000066400000000000000000000053331370110300500226500ustar00rootroot00000000000000/* Fortran interface for m_ab7_symmetry.F90. */ #ifndef M_AB7_SYMMETRY_EXPORT_H #define M_AB7_SYMMETRY_EXPORT_H #define SYM_NAME(a,A) ABI_FC_MOD(m_ab7_symmetry,M_AB7_SYMMETRY, \ symmetry_ ## a,SYMMETRY_ ## A) #define SYM_CALL(a,A,...) SYM_NAME(a,A)(__VA_ARGS__) void SYM_NAME(new,NEW) (int *dt); void SYM_NAME(free,FREE) (int *sym); void SYM_NAME(set_tolerance,SET_TOLERANCE) (int *sym, double *tolsym, unsigned int *ab7_errno); void SYM_NAME(set_lattice,SET_LATTICE) (int *sym, double *rprimd, unsigned int *ab7_errno); void SYM_NAME(set_structure,SET_STRUCTURE) (int *sym, int *natoms, int *typeAt, double *xRed, unsigned int *ab7_errno); void SYM_NAME(set_collinear_spin,SET_COLLINEAR_SPIN)(int *sym, int *nAtoms, int *spinAt, unsigned int *ab7_errno); void SYM_NAME(set_spin,SET_SPIN) (int *sym, int *nAtoms, double *spinAt, unsigned int *ab7_errno); void SYM_NAME(set_spin_orbit,SET_SPIN_ORBIT) (int *sym, int *status, unsigned int *ab7_errno); void SYM_NAME(set_field,SET_FIELD) (int *sym, double *field, unsigned int *ab7_errno); void SYM_NAME(set_jellium,SET_JELLIUM) (int *sym, int *jellium, unsigned int *ab7_errno); void SYM_NAME(set_periodicity,SET_PERIODICITY) (int *sym, int *periodic, unsigned int *ab7_errno); void SYM_NAME(get_n_atoms,GET_N_ATOMS) (int *sym, int *nAtoms, unsigned int *ab7_errno); void SYM_NAME(get_n_sym,GET_N_SYM) (int *sym, int *nSym, unsigned int *ab7_errno); void SYM_NAME(get_multiplicity,GET_MULTIPLICITY) (int *sym, int *multiplicity, unsigned int *ab7_errno); void SYM_NAME(get_bravais,GET_BRAVAIS) (int *sym, int *bravais, int *holohedry, int *center, int *nBravSym, int *bravSym, unsigned int *ab7_errno); void SYM_NAME(get_matrices,GET_MATRICES) (int *sym, int *nSym, int *syms, double *transNon, int *symAfm, unsigned int *ab7_errno); void SYM_NAME(get_group,GET_GROUP) (int *sym, char *spaceGroup, int *spaceGroupId, int *pointGroupMagn, double *genAfm, unsigned int *ab7_errno); void SYM_NAME(get_equivalent_atom,GET_EQUIVALENT_ATOM) (int *sym, int *equiv, int *iAtom, unsigned int *ab7_errno); void SYM_NAME(get_type,GET_TYPE) (int *sym, int *iSym, char *label, int *type, unsigned int *ab7_errno); #endif v_sim-3.8.0/lib/plug-ins/abinit/ab7_symmetry.h000066400000000000000000000171071370110300500212000ustar00rootroot00000000000000/** C header file * * Copyright (C) 2008-2016 ABINIT Group (Damien Caliste) * * This file is part of the ABINIT software package. For license information, * please see the COPYING file in the top-level directory of the ABINIT source * distribution. * */ #ifndef AB7_SYMMETRY #define AB7_SYMMETRY #include "ab7_base.h" /** * Ab7Symmetry: * * An object to handle a set of symmetries. */ typedef int Ab7Symmetry; /** * AB7_MAX_SYMMETRIES: * * Maximum size of internal arrays. */ #define AB7_MAX_SYMMETRIES 384 /** * Ab7SymmetryMat: * * A convenience name for 3x3 integer matrices. These matrices are * used to describe the symmetries. */ typedef struct Ab7SymmetryMat_ {int mat[3][3];} Ab7SymmetryMat; /** * Ab7SymmetryTrans: * * A convenience name for 3 double vectors. These vectors are used to * represent the non symmorphic translations. */ typedef struct Ab7SymmetryTrans_ {double vect[3];} Ab7SymmetryTrans; /** * ab7_symmetry_new: * * Create a new symmetry object. This object can't be used before * setting up the lattice with ab7_symmetry_set_lattice() and the * coordinates with ab7_symmetry_set_structure(). * * Returns: a newly created object. Use ab7_symmetry_free() to free it. */ Ab7Symmetry* ab7_symmetry_new(); /** * ab7_symmetry_free: * @sym: a pointer on a #Ab7Symmetry object. * * Free all memory used by an #Ab7Symmetry object. */ void ab7_symmetry_free (Ab7Symmetry *sym); Ab7Error ab7_symmetry_set_tolerance (Ab7Symmetry *sym, double tolsym); /** * ab7_symmetry_set_lattice: * @sym: a pointer on a #Ab7Symmetry object. * @rprimd: a matrix. * * Set up the lattice of the system. @rprimd describes the three * fundamental vectors of the basis set in dimensioned values. After * the lattice has been set, one can access the corresponding Bravais * lattice calling ab7_symmetry_get_bravais(). * * Returns: #AB7_NO_ERROR if the lattice has been set successfully. */ Ab7Error ab7_symmetry_set_lattice (Ab7Symmetry *sym, double rprimd[3][3]); /** * ab7_symmetry_set_structure: * @sym: a pointer on a #Ab7Symmetry object. * @natoms: the number of atoms. * @typeAt: the types of atoms. The types range if [1:maxtype]. * @xRed: the coordinates in reduced coordinates. * * Set up the structure of the system. After the structure has been * set, one can access the symmetry matrices calling ab7_symmetry_get_matrices(). * * Returns: #AB7_NO_ERROR if the structure has been set successfully or * #AB7_ERROR_SYM_BRAVAIS_XRED if the structure lattice found from * @xRed is less symmetric than the Bravais lattice. */ Ab7Error ab7_symmetry_set_structure (Ab7Symmetry *sym, int natoms, int *typeAt, double *xRed); /** * ab7_symmetry_set_spin: * @sym: a pointer on a #Ab7Symmetry object. * @spinAt: a matrix. * * Set up the spin for each atom of the * system. ab7_symmetry_set_structure() must have been called before. * * Returns: #AB7_NO_ERROR if the value has been set successfully. */ Ab7Error ab7_symmetry_set_spin (Ab7Symmetry *sym, double *spinAt); /** * ab7_symmetry_set_collinear_spin: * @sym: a pointer on a #Ab7Symmetry object. * @spinAt: a matrix. * * Set up the spin for each atom of the * system. ab7_symmetry_set_structure() must have been called before. * * Returns: #AB7_NO_ERROR if the value has been set successfully. */ Ab7Error ab7_symmetry_set_collinear_spin(Ab7Symmetry *sym, int *spinAt); /** * ab7_symmetry_set_spin_orbit: * @sym: a pointer on a #Ab7Symmetry object. * @status: a boolean. * * Set up if the system uses spin-orbit coupling or not. * * Returns: #AB7_NO_ERROR if the value has been set successfully. */ Ab7Error ab7_symmetry_set_spin_orbit(Ab7Symmetry *sym, gboolean status); /** * ab7_symmetry_set_field: * @sym: a pointer on a #Ab7Symmetry object. * @field: a vector. * * Set up if the system is under an electrical field. @field gives the * direction of the field. * * Returns: #AB7_NO_ERROR if the value has been set successfully. */ Ab7Error ab7_symmetry_set_field (Ab7Symmetry *sym, double field[3]); /** * ab7_symmetry_set_jellium: * @sym: a pointer on a #Ab7Symmetry object. * @jellium: a boolean. * * Set up if the system is charged and uses a jellium compensation charge. * * Returns: #AB7_NO_ERROR if the value has been set successfully. */ Ab7Error ab7_symmetry_set_jellium (Ab7Symmetry *sym, gboolean jellium); /** * ab7_symmetry_set_periodicity: * @sym: a pointer on a #Ab7Symmetry object. * @periodic: three booleans. * * Set up the system boundary conditions for the X, Y and Z * directions. If a direction is set to TRUE, then periodic * counditions are applied. Default is fully periodic. * * Returns: #AB7_NO_ERROR if the value has been set successfully. */ Ab7Error ab7_symmetry_set_periodicity(Ab7Symmetry *sym, gboolean periodic[3]); /** * ab7_symmetry_get_n_atoms: * @sym: a pointer on a #Ab7Symmetry object. * @nAtoms: a location to store an integer. * * Give the number of atoms defined by ab7_symmetry_set_structure(). * * Returns: #AB7_NO_ERROR if the value has been get successfully. */ Ab7Error ab7_symmetry_get_n_atoms (Ab7Symmetry *sym, int *nAtoms); /** * ab7_symmetry_get_n_sym: * @sym: a pointer on a #Ab7Symmetry object. * @nSym: a location to store an integer. * * Give the number of computed symmetries. * * Returns: #AB7_NO_ERROR if the value has been get successfully. */ Ab7Error ab7_symmetry_get_n_sym (Ab7Symmetry *sym, int *nSym); /** * ab7_symmetry_get_multiplicity: * @sym: a pointer on a #Ab7Symmetry object. * @multiplicity: a location to store an integer. * * Give the multiplicity of the cell. If the cell is primitive, * @multiplicity is set to 1. In that case, one can call * ab7_symmetry_get_group() to have information on the space group. * * Returns: #AB7_NO_ERROR if the value has been get successfully. */ Ab7Error ab7_symmetry_get_multiplicity (Ab7Symmetry *sym, int *multiplicity); /** * ab7_symmetry_get_bravais: * @sym: a pointer on a #Ab7Symmetry object. * @bravais: a location for a matrix. * @holohedry: a location for an integer. * @center: a location for an integer. * @nBravSym: a location for an integer. * @bravSym: a pointer on #Ab7SymmetryMat. * * This routine is used to get the Bravais lattice of a system. The * @bravais lattice is given in integer value of the reciprocal space * vectors. The @holohedry is an integer [1:7] giving the lattice * system (1 is triclinic, 2 is monoclinic, 3 is orthorhombic...). The * @center is an other integer [-3:3] that specifies the Bravais * lattice (the corresponding values are ["F", "F", "I", "P", "A", * "B", "C"]). This routine also allocate an array of symmetry * matrices, stored in @bravSym. The number of allocated array in set * in @nBravSym. Use free() (or g_free()) to deallocate the Bravais * symmetry matrices after use. * * Returns: #AB7_NO_ERROR if the value has been get successfully. */ Ab7Error ab7_symmetry_get_bravais (Ab7Symmetry *sym, int bravais[3][3], int *holohedry, int *center, int *nBravSym, Ab7SymmetryMat **bravSym); Ab7Error ab7_symmetry_get_matrices (Ab7Symmetry *sym, int *nSym, Ab7SymmetryMat **syms, Ab7SymmetryTrans **transNon, int **symAfm); Ab7Error ab7_symmetry_get_group (Ab7Symmetry *sym, char **spaceGroup, int *spaceGroupId, int *pointGroupMagn, double genAfm[3]); Ab7Error ab7_symmetry_get_equivalent_atom (Ab7Symmetry *sym, int **equiv, int *nSym, int iAtom); Ab7Error ab7_symmetry_get_type (Ab7Symmetry *sym, int *type, char **label, int iSym); #endif v_sim-3.8.0/lib/plug-ins/abinit/ab_silicon.in000066400000000000000000000032131370110300500210300ustar00rootroot00000000000000# Crystalline silicon # calculation of kss file for 256 shifted k-points in IBZ # Definition of the unit cell: fcc acell 3*10.217 # This is equivalent to 10.217 10.217 10.217 rprim 0.0 0.5 0.5 # FCC primitive vectors (to be scaled by acell) 0.5 0.0 0.5 0.5 0.5 0.0 # Definition of the atom types ntypat 1 # There is only one type of atom znucl 14 #zatnum 14 # The keyword "zatnum" refers to the atomic number of the # possible type(s) of atom. The pseudopotential(s) # mentioned in the "files" file must correspond # to the type(s) of atom. Here, the only type is Silicon. # Definition of the atoms natom 2 # There are two atoms typat 1 1 # They both are of type 1, that is, Silicon. xred # Reduced coordinate of atoms 0.0 0.0 0.0 0.25 0.25 0.25 # Definition of the planewave basis set (at convergence 16 Rydberg 8 Hartree) ecut 8.0 # Maximal kinetic energy cut-off, in Hartree accesswff 3 # Dataset1: usual self-consistent calculation # Definition of the k-point grid kptopt 1 # Option for the automatic generation of k points, nkpt 10 ngkpt 4 4 4 nshiftk 4 shiftk 0.5 0.5 0.5 # These shifts will be the same for all grids 0.5 0.0 0.0 0.0 0.5 0.0 0.0 0.0 0.5 # Definition of the SCF procedure nstep 10 # Maximal number of SCF cycles diemac 12.0 toldfe 1.0d-6 prtden 0 # Definition of the k-points for the kss 256 shifted k-points # Dataset2: calculation of kss file # Definition of k-points nband 9 nbandkss 100 # Number of bands to store in KSS file v_sim-3.8.0/lib/plug-ins/abinit/ab_symmetry.c000066400000000000000000000575571370110300500211210ustar00rootroot00000000000000/* EXTRAITS DE LA LICENCE Copyright CEA, contributeurs : Luc BILLARD et Damien CALISTE, laboratoire L_Sim, (2001-2005) Adresse ml : BILLARD, non joignable par ml ; CALISTE, damien P caliste AT cea P fr. Ce logiciel est un programme informatique servant visualiser des structures atomiques dans un rendu pseudo-3D. Ce logiciel est rgi par la licence CeCILL soumise au droit franais et respectant les principes de diffusion des logiciels libres. Vous pouvez utiliser, modifier et/ou redistribuer ce programme sous les conditions de la licence CeCILL telle que diffuse par le CEA, le CNRS et l'INRIA sur le site "http://www.cecill.info". Le fait que vous puissiez accder cet en-tte signifie que vous avez pris connaissance de la licence CeCILL, et que vous en avez accept les termes (cf. le fichier Documentation/licence.fr.txt fourni avec ce logiciel). */ /* LICENCE SUM UP Copyright CEA, contributors : Luc BILLARD et Damien CALISTE, laboratoire L_Sim, (2001-2005) E-mail address: BILLARD, not reachable any more ; CALISTE, damien P caliste AT cea P fr. This software is a computer program whose purpose is to visualize atomic configurations in 3D. This software is governed by the CeCILL license under French law and abiding by the rules of distribution of free software. You can use, modify and/ or redistribute the software under the terms of the CeCILL license as circulated by CEA, CNRS and INRIA at the following URL "http://www.cecill.info". The fact that you are presently reading this means that you have had knowledge of the CeCILL license and that you accept its terms. You can find a copy of this licence shipped with this software at Documentation/licence.en.txt. */ #include #include #include #include #include #include #include #include #include #include #include "abinit.h" #define ABINIT_SYMMETRIES_INFO \ _("left-button\t\t: select one atom to get the equivalent ones\n" \ "right-button\t\t: switch to observe") enum { SYM_ID, SYM_MATRIX_00, SYM_MATRIX_01, SYM_MATRIX_02, SYM_MATRIX_10, SYM_MATRIX_11, SYM_MATRIX_12, SYM_MATRIX_20, SYM_MATRIX_21, SYM_MATRIX_22, SYM_TRANS_0, SYM_TRANS_1, SYM_TRANS_2, SYM_COMMENT, SYM_N_COLS }; static gulong onSpin_id; static AbSymmetry *sym; static GtkWidget *lblSymName, *lblSymId, *lblSymWarning, *spinTol; static GtkWidget *spinNode, *vbox, *vboxSym; static guint timeout = 0; static VisuInteractive *inter; static GtkListStore *symList; static void onSelection(VisuInteractive *inter, VisuInteractivePick pick, VisuNodeArray *array, VisuNode *node0, VisuNode *node1, VisuNode *node2, gpointer data); static void onSymmetryToggled(GtkToggleButton *toggle, gpointer data); static void onSymmetryClicked(GtkButton *button, gpointer data); static void onTolChanged(GtkSpinButton *spin, gpointer data); static void onVisuDataChanged(VisuUiMain *visu, VisuData *dataObj, gpointer data); static void onSpinNode(GtkSpinButton *button, gpointer data); static gchar* symAnalyse(AbSymmetry *sym, int iSym); static void getEquivalents(VisuData *dataObj, VisuNode *node); static void updateSymmetries(VisuData *dataObj, gdouble tol); static void formatSymOperators(GtkTreeViewColumn *column, GtkCellRenderer *cell, GtkTreeModel *model, GtkTreeIter *iter, gpointer data); GtkWidget* buildTab(VisuUiMain *main, gchar **label, gchar **help, GtkWidget **radio) { GtkWidget *wd, *hbox, *bt, *scroll; VisuData *data; VisuUiRenderingWindow *window; VisuGlNodeScene *scene; GtkCellRenderer *renderer; GtkTreeViewColumn *column; window = visu_ui_main_class_getDefaultRendering(); scene = visu_ui_rendering_window_getGlScene(window); data = visu_gl_node_scene_getData(scene); g_return_val_if_fail(data, (GtkWidget*)0); inter = visu_interactive_new(interactive_pick); g_signal_connect_swapped(G_OBJECT(inter), "stop", G_CALLBACK(visu_ui_interactive_toggle), (gpointer)0); g_signal_connect(G_OBJECT(inter), "node-selection", G_CALLBACK(onSelection), (gpointer)0); *label = _("Symmetries"); *help = g_strdup(ABINIT_SYMMETRIES_INFO); symList = gtk_list_store_new(SYM_N_COLS, G_TYPE_INT, G_TYPE_INT, G_TYPE_INT, G_TYPE_INT, G_TYPE_INT, G_TYPE_INT, G_TYPE_INT, G_TYPE_INT, G_TYPE_INT, G_TYPE_INT, G_TYPE_FLOAT, G_TYPE_FLOAT, G_TYPE_FLOAT, G_TYPE_STRING); vbox = gtk_vbox_new(FALSE, 0); g_signal_connect_swapped(vbox, "destroy", G_CALLBACK(g_object_unref), inter); sym = (AbSymmetry*)0; hbox = gtk_hbox_new(FALSE, 0); gtk_box_pack_start(GTK_BOX(vbox), hbox, FALSE, FALSE, 0); *radio = gtk_radio_button_new_with_mnemonic (NULL, _("Analyse the symmetries")); gtk_box_pack_start(GTK_BOX(hbox), *radio, FALSE, FALSE, 0); gtk_widget_set_name(*radio, "message_radio"); g_signal_connect(G_OBJECT(*radio), "toggled", G_CALLBACK(onSymmetryToggled), (gpointer)0); wd = gtk_button_new_with_mnemonic(_("Compute symmetries")); bt = wd; gtk_box_pack_end(GTK_BOX(hbox), wd, FALSE, FALSE, 0); wd = gtk_label_new(") "); gtk_box_pack_end(GTK_BOX(hbox), wd, FALSE, FALSE, 0); wd = gtk_spin_button_new_with_range(-10, -2, 1); gtk_entry_set_width_chars(GTK_ENTRY(wd), 2); gtk_spin_button_set_value(GTK_SPIN_BUTTON(wd), -6); g_signal_connect(G_OBJECT(wd), "value-changed", G_CALLBACK(onTolChanged), (gpointer)0); g_signal_connect(G_OBJECT(bt), "clicked", G_CALLBACK(onSymmetryClicked), (gpointer)wd); gtk_box_pack_end(GTK_BOX(hbox), wd, FALSE, FALSE, 0); spinTol = wd; wd = gtk_label_new("(tolsym = 10^"); gtk_box_pack_end(GTK_BOX(hbox), wd, FALSE, FALSE, 0); vboxSym = gtk_vbox_new(FALSE, 0); gtk_widget_set_sensitive(vboxSym, FALSE); gtk_box_pack_start(GTK_BOX(vbox), vboxSym, TRUE, TRUE, 0); /* A message for ABINIT. */ wd = gtk_label_new(_("The symmetry routines" " are provided by ABINIT (" "" "http://www.abinit.org).")); gtk_widget_set_halign(wd, 1.0); gtk_label_set_use_markup(GTK_LABEL(wd), TRUE); gtk_box_pack_end(GTK_BOX(vbox), wd, FALSE, FALSE, 5); /* The labels showing the symmetry. */ hbox = gtk_hbox_new(FALSE, 0); gtk_box_pack_start(GTK_BOX(vboxSym), hbox, FALSE, FALSE, 10); wd = gtk_label_new(_("Space group:")); gtk_label_set_use_markup(GTK_LABEL(wd), TRUE); gtk_widget_set_margin_start(wd, 10); gtk_box_pack_start(GTK_BOX(hbox), wd, FALSE, FALSE, 0); wd = gtk_label_new(_("" "http://en.wikipedia.org/wiki/Space_group")); gtk_label_set_selectable(GTK_LABEL(wd), TRUE); gtk_label_set_use_markup(GTK_LABEL(wd), TRUE); gtk_box_pack_end(GTK_BOX(hbox), wd, FALSE, FALSE, 10); wd = gtk_image_new_from_icon_name("help-browser", GTK_ICON_SIZE_MENU); gtk_box_pack_end(GTK_BOX(hbox), wd, FALSE, FALSE, 0); hbox = gtk_hbox_new(FALSE, 0); gtk_box_pack_start(GTK_BOX(vboxSym), hbox, FALSE, FALSE, 0); wd = gtk_label_new(_("Crystal system:")); gtk_box_pack_start(GTK_BOX(hbox), wd, FALSE, FALSE, 0); lblSymName = gtk_label_new(""); gtk_widget_set_halign(lblSymName, 0.); gtk_box_pack_start(GTK_BOX(hbox), lblSymName, TRUE, TRUE, 5); wd = gtk_label_new(_("space group:")); gtk_box_pack_start(GTK_BOX(hbox), wd, FALSE, FALSE, 0); lblSymId = gtk_label_new(""); gtk_label_set_use_markup(GTK_LABEL(lblSymId), TRUE); gtk_widget_set_halign(lblSymId, 0.); gtk_box_pack_start(GTK_BOX(hbox), lblSymId, TRUE, TRUE, 5); lblSymWarning = gtk_label_new(_("Warning: the Bravais lattice determined from the primitive vectors is more symmetric than the real one obtained from coordinates (printed).")); gtk_label_set_use_markup(GTK_LABEL(lblSymWarning), TRUE); gtk_label_set_line_wrap(GTK_LABEL(lblSymWarning), TRUE); gtk_label_set_line_wrap_mode(GTK_LABEL(lblSymWarning), PANGO_WRAP_WORD); gtk_box_pack_start(GTK_BOX(vboxSym), lblSymWarning, FALSE, FALSE, 0); wd = gtk_label_new(_("List of symmetry operations:")); gtk_widget_set_halign(wd, 0.); gtk_box_pack_start(GTK_BOX(vboxSym), wd, FALSE, FALSE, 3); scroll = gtk_scrolled_window_new(NULL, NULL); gtk_scrolled_window_set_policy(GTK_SCROLLED_WINDOW(scroll), GTK_POLICY_AUTOMATIC, GTK_POLICY_ALWAYS); gtk_box_pack_start(GTK_BOX(vboxSym), scroll, TRUE, TRUE, 0); wd = gtk_tree_view_new_with_model(GTK_TREE_MODEL(symList)); gtk_container_add(GTK_CONTAINER(scroll), wd); renderer = gtk_cell_renderer_text_new(); column = gtk_tree_view_column_new_with_attributes(_("Id"), renderer, "text", SYM_ID, NULL); gtk_tree_view_append_column(GTK_TREE_VIEW(wd), column); renderer = gtk_cell_renderer_text_new (); column = gtk_tree_view_column_new(); gtk_tree_view_column_set_title(column, _("operation")); gtk_tree_view_column_pack_start(column, renderer, TRUE); gtk_tree_view_column_set_cell_data_func (column, renderer, formatSymOperators, GINT_TO_POINTER(SYM_MATRIX_00), (GDestroyNotify)0); gtk_tree_view_append_column(GTK_TREE_VIEW(wd), column); renderer = gtk_cell_renderer_text_new (); column = gtk_tree_view_column_new(); gtk_tree_view_column_set_title(column, _("translation")); gtk_tree_view_column_pack_start(column, renderer, TRUE); gtk_tree_view_column_set_cell_data_func (column, renderer, formatSymOperators, GINT_TO_POINTER(SYM_TRANS_0), (GDestroyNotify)0); gtk_tree_view_append_column(GTK_TREE_VIEW(wd), column); renderer = gtk_cell_renderer_text_new(); column = gtk_tree_view_column_new_with_attributes(_("comment"), renderer, "text", SYM_COMMENT, NULL); gtk_tree_view_append_column(GTK_TREE_VIEW(wd), column); /* The interface to choose one atom to select. */ wd = gtk_label_new(_("Equivalent atoms:")); gtk_label_set_use_markup(GTK_LABEL(wd), TRUE); gtk_widget_set_halign(wd, 0.); gtk_widget_set_margin_start(wd, 10); gtk_box_pack_start(GTK_BOX(vboxSym), wd, FALSE, FALSE, 10); hbox = gtk_hbox_new(FALSE, 0); gtk_box_pack_start(GTK_BOX(vboxSym), hbox, FALSE, FALSE, 0); wd = gtk_label_new(_("Visualise the equivalent nodes of node:")); gtk_box_pack_start(GTK_BOX(hbox), wd, FALSE, FALSE, 0); spinNode = gtk_spin_button_new_with_range(0, 1, 1); onSpin_id = g_signal_connect(G_OBJECT(spinNode), "value-changed", G_CALLBACK(onSpinNode), (gpointer)0); gtk_box_pack_start(GTK_BOX(hbox), spinNode, FALSE, FALSE, 5); wd = gtk_label_new(_(" or pick directly.")); gtk_box_pack_start(GTK_BOX(hbox), wd, FALSE, FALSE, 0); gtk_widget_show_all(vbox); gtk_widget_hide(lblSymWarning); g_signal_connect(main, "DataFocused", G_CALLBACK(onVisuDataChanged), (gpointer)0); onVisuDataChanged((VisuUiMain*)0, data, (gpointer)0); return vbox; } static void formatSymOperators(GtkTreeViewColumn *column _U_, GtkCellRenderer *cell, GtkTreeModel *model, GtkTreeIter *iter, gpointer data) { gchar *str; gfloat valf[3]; gint vali[9]; str = (gchar*)0; if (GPOINTER_TO_INT(data) == SYM_MATRIX_00) { gtk_tree_model_get(model, iter, SYM_MATRIX_00, vali, SYM_MATRIX_01, vali + 1, SYM_MATRIX_02, vali + 2, SYM_MATRIX_10, vali + 3, SYM_MATRIX_11, vali + 4, SYM_MATRIX_12, vali + 5, SYM_MATRIX_20, vali + 6, SYM_MATRIX_21, vali + 7, SYM_MATRIX_22, vali + 8, -1); str = g_strdup_printf("[ %2d %2d %2d\n" " %2d %2d %2d\n" " %2d %2d %2d ]", vali[0], vali[1], vali[2], vali[3], vali[4], vali[5], vali[6], vali[7], vali[8]); } else if (GPOINTER_TO_INT(data) == SYM_TRANS_0) { gtk_tree_model_get(model, iter, SYM_TRANS_0, valf, SYM_TRANS_1, valf + 1, SYM_TRANS_2, valf + 2, -1); str = g_strdup_printf("[ %2f\n" " %2f\n" " %2f ]", valf[0], valf[1], valf[2]); } if (str) { g_object_set(G_OBJECT(cell), "text", str, NULL); g_free(str); } } void startSelect(VisuUiRenderingWindow *window) { visu_ui_rendering_window_pushInteractive(window, inter); } void stopSelect(VisuUiRenderingWindow *window) { visu_ui_rendering_window_popInteractive(window, inter); } static void onSelection(VisuInteractive *inter _U_, VisuInteractivePick pick _U_, VisuNodeArray *array, VisuNode *node0, VisuNode *node1 _U_, VisuNode *node2 _U_, gpointer data _U_) { getEquivalents(VISU_DATA(array), node0); g_signal_handler_block(G_OBJECT(spinNode), onSpin_id); gtk_spin_button_set_value(GTK_SPIN_BUTTON(spinNode), node0->number + 1); g_signal_handler_unblock(G_OBJECT(spinNode), onSpin_id); } static void onSymmetryToggled(GtkToggleButton *toggle _U_, gpointer data _U_) { } static void onSymmetryClicked(GtkButton *button _U_, gpointer spin) { VisuData *dataObj; /* Get the current VisuData object. */ dataObj = visu_gl_node_scene_getData(visu_ui_rendering_window_getGlScene(visu_ui_main_class_getDefaultRendering())); updateSymmetries(dataObj, gtk_spin_button_get_value(GTK_SPIN_BUTTON(spin))); } static void onTolChanged(GtkSpinButton *spin, gpointer data _U_) { VisuData *dataObj; /* Get the current VisuData object. */ dataObj = visu_gl_node_scene_getData(visu_ui_rendering_window_getGlScene(visu_ui_main_class_getDefaultRendering())); updateSymmetries(dataObj, gtk_spin_button_get_value(spin)); } static void onVisuDataChanged(VisuUiMain *visu _U_, VisuData *dataObj, gpointer data _U_) { VisuNodeArrayIter iter; gtk_widget_set_sensitive(vbox, (dataObj !=(VisuData*)0)); updateSymmetries((VisuData*)0, 0); if (dataObj) { visu_node_array_iter_new(VISU_NODE_ARRAY(dataObj), &iter); gtk_spin_button_set_range(GTK_SPIN_BUTTON(spinNode), 0, iter.idMax + 1); } } static void onSpinNode(GtkSpinButton *button, gpointer data _U_) { VisuData *dataObj; VisuNode *node; if (gtk_spin_button_get_value(button) == 0) return; /* Get the current VisuData object. */ dataObj = visu_gl_node_scene_getData(visu_ui_rendering_window_getGlScene(visu_ui_main_class_getDefaultRendering())); node = visu_node_array_getFromId(VISU_NODE_ARRAY(dataObj), (int)gtk_spin_button_get_value(button) - 1); getEquivalents(dataObj, node); } static gboolean onRemoveEquivalents(gpointer data _U_) { timeout = 0; return FALSE; } static void removeEquivalents(gpointer data) { VisuGlExtMarks *marks; GArray *ids; ids = (GArray*)data; /* Get the current VisuData object. */ marks = visu_gl_node_scene_getMarks(visu_ui_rendering_window_getGlScene(visu_ui_main_class_getDefaultRendering())); visu_gl_ext_marks_setHighlight(marks, ids, MARKS_STATUS_TOGGLE); g_array_unref(ids); } static void getEquivalents(VisuData *dataObj, VisuNode *node) { guint j; int i, nSym; int *nodes; GArray *ids; gboolean found; #if GLIB_MINOR_VERSION > 13 #define fact 1 #define G_TIMEOUT_ADD_FULL g_timeout_add_seconds_full #else #define fact 1000 #define G_TIMEOUT_ADD_FULL g_timeout_add_full #endif if (!sym) updateSymmetries(dataObj, gtk_spin_button_get_value(GTK_SPIN_BUTTON(spinTol))); g_return_if_fail(sym); if (ab_symmetry_get_equivalent_atom(sym, &nodes, &nSym, node->number + 1) == AB_NO_ERROR) { ids = g_array_new(FALSE, FALSE, sizeof(guint)); for (i = 0; i < nSym; i++) { found = FALSE; for ( j = 0; j < ids->len && !found; j++) found = (nodes[i * 4 + 3] == g_array_index(ids, int, j) + 1); if (!found) { j = nodes[i * 4 + 3] - 1; g_array_append_val(ids, j); } } g_free(nodes); /* We remove possible earlier timeout. */ if (timeout > 0) g_source_remove(timeout); /* Set the new highlights. */ visu_gl_ext_marks_setHighlight (visu_gl_node_scene_getMarks(visu_ui_rendering_window_getGlScene(visu_ui_main_class_getDefaultRendering())), ids, MARKS_STATUS_SET); /* Add the new timeout. */ timeout = G_TIMEOUT_ADD_FULL(G_PRIORITY_DEFAULT, 3 * fact, onRemoveEquivalents, ids, removeEquivalents); /* ids will be freed in the timeout. */ } } gpointer startThreadSymmetry(gpointer data _U_) { float xred0[3], xyz[3]; char *spGrp; double box[3][3], genAfm[3], *xred; int i, *typat, grpId, grpMagnId; AbError errno; VisuNodeArrayIter iter; AbinitData *dt; DBG_fprintf(stderr, "AB symmetry(%p): starting symmetry detection.\n", (gpointer)g_thread_self()); dt = abinit_getDt(); visu_box_getCellMatrix(visu_boxed_getBox(VISU_BOXED(dt->data)), box); ab_symmetry_set_lattice(dt->sym, box); visu_node_array_iter_new(VISU_NODE_ARRAY(dt->data), &iter); i = 0; typat = g_malloc(sizeof(int) * iter.nAllStoredNodes); xred = g_malloc(sizeof(double) * 3 * iter.nAllStoredNodes); for (visu_node_array_iterStart(VISU_NODE_ARRAY(dt->data), &iter); iter.node; visu_node_array_iterNext(VISU_NODE_ARRAY(dt->data), &iter)) { typat[i] = iter.iElement; visu_data_getNodePosition(dt->data, iter.node, xyz); visu_box_convertXYZtoBoxCoordinates(visu_boxed_getBox(VISU_BOXED(dt->data)), xred0, xyz); xred[3 * i + 0] = (double)xred0[0]; xred[3 * i + 1] = (double)xred0[1]; xred[3 * i + 2] = (double)xred0[2]; i += 1; } ab_symmetry_set_structure(dt->sym, iter.nAllStoredNodes, typat, xred); g_free(typat); g_free(xred); /* Ask for the calculation of the symmetries. */ DBG_fprintf(stderr, "AB symmetry(%p): Ready to get symmetries from ABINIT.\n", (gpointer)g_thread_self()); errno = ab_symmetry_get_group(dt->sym, &spGrp, &grpId, &grpMagnId, genAfm); DBG_fprintf(stderr, "AB symmetry(%p): return from ABINIT (%d).\n", (gpointer)g_thread_self(), errno); if (errno == AB_NO_ERROR || errno == AB_ERROR_SYM_BRAVAIS_XRED) g_free(spGrp); else if (errno != AB_ERROR_SYM_NOT_PRIMITIVE) dt->error = g_error_new(TOOL_FILE_FORMAT_ERROR, TOOL_FILE_FORMAT_ERROR_METHOD, "An error occured in ABINIT plug-in."); abinit_mutexUnlock(); return (gpointer)0; } static void updateSymmetries(VisuData *dataObj, gdouble tol) { double genAfm[3]; int grpId, grpMagnId, centerId, nbrv; char *spGrp; gchar *str; AbSymmetryMat *brvSyms; int brvMat[3][3]; gchar *bravais[7] = {"triclinic", "monoclinic", "orthorhombic", "tetragonal", "trigonal", "hexagonal", "cubic"}; gchar *center[7] = {"F", "F", "I", "P", "A", "B", "C"}; AbError errno; #ifdef G_THREADS_ENABLED GThread *ld_thread; #endif int nSym, *amf, iSym; AbSymmetryMat *symOps; AbSymmetryTrans *trans; GtkTreeIter iter; AbinitData *dt; DBG_fprintf(stderr, "Abinit: upadte symmetries from %p.\n", (gpointer)dataObj); if (sym) ab_symmetry_free(sym); sym = (AbSymmetry*)0; gtk_list_store_clear(symList); if (dataObj) { dt = abinit_getDirectDt(); dt->data = dataObj; dt->sym = ab_symmetry_new(); dt->getMessages = FALSE; dt->useSignals = FALSE; DBG_fprintf(stderr, "AB symmetry: set tolerance to 10^%g.\n", tol); ab_symmetry_set_tolerance(dt->sym, pow(10., tol)); #ifdef G_THREADS_ENABLED abinit_mutexInit(); dt->error = (GError*)0; #if GLIB_MINOR_VERSION < 32 ld_thread = g_thread_create(startThreadSymmetry, (gpointer)0, TRUE, &(dt->error)); #else ld_thread = g_thread_new(NULL, startThreadSymmetry, (gpointer)0); #endif DBG_fprintf(stderr, "AB symmetry: run ABINIT symmetry into a thread (%p).\n", (gpointer)ld_thread); if (ld_thread) g_thread_join(ld_thread); else g_warning("Can't run thread for ABINIT symmetry."); abinit_mutexRelease(); #else startThreadSymmetry((gpointer)(&dt)); #endif DBG_fprintf(stderr, "AB symmetry: return after thread exec (%p).\n", (gpointer)dt->error); if (!dt->error) { sym = dt->sym; /* We get then the space group. */ DBG_fprintf(stderr, "AB symmetry: get group.\n"); errno = ab_symmetry_get_group(sym, &spGrp, &grpId, &grpMagnId, genAfm); if (errno == AB_NO_ERROR || errno == AB_ERROR_SYM_BRAVAIS_XRED) { str = g_strdup_printf("%s (#%d)", spGrp, grpId); gtk_label_set_text(GTK_LABEL(lblSymId), str); g_free(str); g_free(spGrp); DBG_fprintf(stderr, "AB symmetry: get matrices.\n"); if (ab_symmetry_get_matrices(sym, &nSym, &symOps, &trans, &amf) == AB_NO_ERROR) { for (iSym = 0; iSym < nSym; iSym++) { str = symAnalyse(dt->sym, iSym + 1); gtk_list_store_append(symList, &iter); gtk_list_store_set(symList, &iter, SYM_ID, iSym + 1, SYM_MATRIX_00, symOps[iSym].mat[0][0], SYM_MATRIX_01, symOps[iSym].mat[0][1], SYM_MATRIX_02, symOps[iSym].mat[0][2], SYM_MATRIX_10, symOps[iSym].mat[1][0], SYM_MATRIX_11, symOps[iSym].mat[1][1], SYM_MATRIX_12, symOps[iSym].mat[1][2], SYM_MATRIX_20, symOps[iSym].mat[2][0], SYM_MATRIX_21, symOps[iSym].mat[2][1], SYM_MATRIX_22, symOps[iSym].mat[2][2], SYM_TRANS_0, trans[iSym].vect[0], SYM_TRANS_1, trans[iSym].vect[1], SYM_TRANS_2, trans[iSym].vect[2], SYM_COMMENT, str, -1); g_free(str); } g_free(symOps); g_free(trans); g_free(amf); } } else { gtk_label_set_markup(GTK_LABEL(lblSymId), _("not primitive")); } DBG_fprintf(stderr, "AB symmetry: get bravais.\n"); if (ab_symmetry_get_bravais(sym, brvMat, &grpId, ¢erId, &nbrv, &brvSyms) == AB_NO_ERROR) { g_free(brvSyms); str = g_strdup_printf("%s (%s)", _(bravais[grpId - 1]), center[centerId+3]); gtk_label_set_text(GTK_LABEL(lblSymName), str); g_free(str); } else gtk_label_set_text(GTK_LABEL(lblSymName), "!"); /* If the bravais lattice doesn't match with the xred bravais lattice, we print a message. */ if (errno == AB_ERROR_SYM_BRAVAIS_XRED) gtk_widget_show(lblSymWarning); else gtk_widget_hide(lblSymWarning); gtk_widget_set_sensitive(vboxSym, (dataObj != (VisuData*)0)); } else { visu_ui_raiseWarning(_("ABINIT symmetry calculation"), dt->error->message, (GtkWindow*)0); g_error_free(dt->error); ab_symmetry_free(dt->sym); sym = (AbSymmetry*)0; gtk_widget_set_sensitive(vboxSym, FALSE); } } else { gtk_label_set_text(GTK_LABEL(lblSymName), ""); gtk_label_set_text(GTK_LABEL(lblSymId), ""); } } static gchar* symAnalyse(AbSymmetry *sym, int iSym) { AbError error; int type; gchar *label; error = ab_symmetry_get_type(sym, &type, &label, iSym); if (error == AB_NO_ERROR) return label; else return g_strdup(_("Unknown symmetry")); } v_sim-3.8.0/lib/plug-ins/abinit/ab_symmetry.h000066400000000000000000000041331370110300500211040ustar00rootroot00000000000000/* EXTRAITS DE LA LICENCE Copyright CEA, contributeurs : Luc BILLARD et Damien CALISTE, laboratoire L_Sim, (2001-2005) Adresse ml : BILLARD, non joignable par ml ; CALISTE, damien P caliste AT cea P fr. Ce logiciel est un programme informatique servant visualiser des structures atomiques dans un rendu pseudo-3D. Ce logiciel est rgi par la licence CeCILL soumise au droit franais et respectant les principes de diffusion des logiciels libres. Vous pouvez utiliser, modifier et/ou redistribuer ce programme sous les conditions de la licence CeCILL telle que diffuse par le CEA, le CNRS et l'INRIA sur le site "http://www.cecill.info". Le fait que vous puissiez accder cet en-tte signifie que vous avez pris connaissance de la licence CeCILL, et que vous en avez accept les termes (cf. le fichier Documentation/licence.fr.txt fourni avec ce logiciel). */ /* LICENCE SUM UP Copyright CEA, contributors : Luc BILLARD et Damien CALISTE, laboratoire L_Sim, (2001-2005) E-mail address: BILLARD, not reachable any more ; CALISTE, damien P caliste AT cea P fr. This software is a computer program whose purpose is to visualize atomic configurations in 3D. This software is governed by the CeCILL license under French law and abiding by the rules of distribution of free software. You can use, modify and/ or redistribute the software under the terms of the CeCILL license as circulated by CEA, CNRS and INRIA at the following URL "http://www.cecill.info". The fact that you are presently reading this means that you have had knowledge of the CeCILL license and that you accept its terms. You can find a copy of this licence shipped with this software at Documentation/licence.en.txt. */ #ifndef AB_SYMMETRY_H #define AB_SYMMETRY_H #include GtkWidget* buildTab(VisuUiMain *main, gchar **label, gchar **help, GtkWidget **radio); void startSelect(VisuUiRenderingWindow *window); void stopSelect(VisuUiRenderingWindow *window); #endif v_sim-3.8.0/lib/plug-ins/abinit/abi_common.h000066400000000000000000000267121370110300500206630ustar00rootroot00000000000000/* abi_common.h */ /* * Copyright (C) 2008-2016 ABINIT Group (MG) * * This file is part of the ABINIT software package. For license information, * please see the COPYING file in the top-level directory of the ABINIT source * distribution. * */ #ifndef _ABINIT_COMMON_H #define _ABINIT_COMMON_H /* * Language standards requires the existance of pre-defined macros * Microsoft Visual C++ does not define __STDC__, * Sun Workshop 4.2 supports C94 without setting __STDC_VERSION__ to the proper value */ #if defined (__STDC__) # define PREDEF_STANDARD_C_1989 /** ANSI X3.159-1989 **/ # if defined (__STDC_VERSION__) # define PREDEF_STANDARD_C_1990 /** ISO/IEC 9899:1990 **/ # if (__STDC_VERSION__ >= 199409L) # define PREDEF_STANDARD_C_1994 /** ISO/IEC 9899-1:1994 **/ # endif # if (__STDC_VERSION__ >= 199901L) # define PREDEF_STANDARD_C_1999 /** ISO/IEC 9899:1999 **/ # endif # endif #endif /** #define DEBUG_MODE **/ #if defined(HAVE_FC_LONG_LINES) || defined(__INTEL_COMPILER) || defined(FC_NAG) || !defined(HAVE_FC_MACRO_NEWLINE) # define NEWLINE ; #else # define NEWLINE \newline #endif /** #ifdef FC_NAG # undef HAVE_FC_LONG_LINES # define HAVE_FC_LONG_LINES #endif **/ /* * These macros are used to pass information on the file and the line to the children if the compiler supports long lines. * Remember, indeed, that ISO doesn't define any standard and __FILE__ could expand to the full path name. * This can lead to compilation errors if the compiler does not accept statements longer than 132 columns. */ #ifdef HAVE_FC_LONG_LINES #define _FILE_LINE_ARGS_ ,file=__FILE__, line=__LINE__ #define _FILE_ABIFUNC_LINE_ARGS_ ,file=__FILE__, func=ABI_FUNC, line=__LINE__ #else #define _FILE_LINE_ARGS_ #define _FILE_ABIFUNC_LINE_ARGS_ #endif /** this does not work with gfort, pgi, **/ #if defined (FC_GNU) || defined(FC_G95) || defined (FC_PGI) #define QUOTE(x) 'x' #else #define QUOTE(x) #x #endif /** Token concatenation 1) ANSI CPP 2) Traditional CPP **/ #if defined (FC_INTEL) #define CONCAT(x,y) x ## y #else #define CONCAT(x,y) x/**/y #endif #define BYTE_SIZE(array) PRODUCT(SHAPE(array)) * DBLE(KIND(array)) /* * ABI_ abinit macros. * DBG_ macros for debugging. Defined only if abinit is compiled in DEBUG_MODE. * MSG_ macros for logging. */ #define ABI_CHECK(expr, str) if (.not.(expr)) call assert(.FALSE., str _FILE_LINE_ARGS_) #define ABI_CHECK_MPI(ierr, msg) call check_mpi_ierr(ierr, msg _FILE_LINE_ARGS_) /* This macro is used in low-level MPI wrappers to return mpierr to the caller * so that one can locate the problematic call. Use it wisely since it may cause memory leaks. * #define ABI_HANDLE_MPIERR(mpierr) ABI_CHECK_MPI(mpierr,"ABI_HANDLE: Fatal error") */ #define ABI_HANDLE_MPIERR(mpierr) if (mpierr/=MPI_SUCCESS) RETURN /* Macros for memory checking and profiling * TODO * Add option to check automatically the exit status of allocate so that we can abort gracefully if oom. * and abipy can detect the problem. * * ABI_ALLOCATE --> Allocate memory for intrinsic datatypes (real, integer, complex). * ABI_CALLOC --> Clear alloc: same as ABI_ALLOCATE but initializes memory with zeros * ABI_DEALLOCATE --> Free memory allocated by ABI_ALLOCATE * * To allocate/deallocate arrays of user-defined type use: * * ABI_DT_ALLOCATE * ABI_DT_DEALLOCATE * * Note for programmers using OpenMP: * Do not use stat=ABI_ALLOC_STAT_ABI inside an OpenMP parallel region * ABI_ALLOC_STAT_ABI is a global variable defined in m_profiling_abi.F90 * and this can have a detrimental effect if the allocation is done inside an OpenMP parallel region. * #define HAVE_MEM_PROFILING */ #ifdef HAVE_MEM_PROFILING /* These macros are used to get the memory address of the objet and the memory allocated. - loc returns the address and is a language extension supported by gfortran and ifort. - storage_size was introduced in F2003 Both loc and storage_size are polymorphic so one can use it with intrinsic types as well as user-defined datatypes. */ # define _LOC(x) int(loc(x), kind=8) # define _MEM(arr) product(int(shape(arr), kind=8)) * storage_size(arr, kind=8)/8 /* and now the debugging macros */ # define ABI_ALLOCATE(ARR, SIZE) \ allocate(ARR SIZE) NEWLINE \ call abimem_record(0, QUOTE(ARR), _LOC(ARR), "A", _MEM(ARR), __FILE__, ABI_FUNC, __LINE__) # define ABI_DEALLOCATE(ARR) \ call abimem_record(0, QUOTE(ARR), _LOC(ARR), "D", - _MEM(ARR), __FILE__, ABI_FUNC, __LINE__) NEWLINE \ deallocate(ARR) # define ABI_STAT_ALLOCATE(ARR,SIZE,ierr) \ allocate(ARR SIZE, stat=ierr) NEWLINE \ call abimem_record(0, QUOTE(ARR), _LOC(ARR), "A", _MEM(ARR), __FILE__, ABI_FUNC, __LINE__) # define ABI_DATATYPE_ALLOCATE(ARR,SIZE) \ allocate(ARR SIZE) NEWLINE \ call abimem_record(0, QUOTE(ARR), _LOC(ARR), "A", _MEM(ARR), __FILE__, ABI_FUNC, __LINE__) # define ABI_DATATYPE_DEALLOCATE(ARR) \ call abimem_record(0, QUOTE(ARR), _LOC(ARR), "D", - _MEM(ARR), __FILE__, ABI_FUNC, __LINE__) NEWLINE \ deallocate(ARR) #else /* macros used in production */ # define ABI_ALLOCATE(ARR,SIZE) allocate(ARR SIZE) # define ABI_DEALLOCATE(ARR) deallocate(ARR) # define ABI_STAT_ALLOCATE(ARR,SIZE,ierr) allocate(ARR SIZE, stat=ierr) # define ABI_DATATYPE_ALLOCATE(ARR,SIZE) allocate(ARR SIZE) # define ABI_DATATYPE_DEALLOCATE(ARR) deallocate(ARR) #endif /* Macros defined in terms of previous macros */ #define ABI_CALLOC(ARR,SIZE) ABI_ALLOCATE(ARR, SIZE) NEWLINE ARR = zero /* Shorthand versions */ #define ABI_MALLOC(ARR,SIZE) ABI_ALLOCATE(ARR,SIZE) #define ABI_FREE(ARR) ABI_DEALLOCATE(ARR) #define ABI_STAT_MALLOC(ARR,SIZE,ierr) ABI_STAT_ALLOCATE(ARR,SIZE,ierr) #define ABI_DT_MALLOC(ARR,SIZE) ABI_DATATYPE_ALLOCATE(ARR,SIZE) #define ABI_DT_FREE(ARR) ABI_DATATYPE_DEALLOCATE(ARR) /* Macro for checking whether allocation was successful #define ABI_CHECK_ALLOC(msg) if (ABI_ALLOC_STAT_ABI/=0) MSG_ERROR(msg) */ /* Macro used to deallocate memory allocated by Fortran libraries that do not use m_profiling_abi.F90 In this case, indeed, we should not count the deallocation */ #define ABI_FREE_NOCOUNT(arr) deallocate(arr) /* * Macros to allocate/deallocate depending on the status of the entity * Caveat: pointers must use ABI_PTR_FREE_IF * #define ABI_MALLOC_IFNOT(ARR) if (.not.allocated(ARR)) ABI_MALLOC(ARR) #define ABI_SFREE(ARR) if (allocated(ARR)) ABI_FREE(ARR) #define ABI_SFREE_PTR(PTR) if (associated(PTR)) ABI_FREE(PTR) */ /* Macros used in debug mode */ #ifdef DEBUG_MODE # define ASSERT(expr) if (.not.expr) call assert((expr), "Assertion failed" _FILE_LINE_ARGS_) # define ASSERT_IF(condition, expr) if (condition) call assert((expr), "Assertion failed" _FILE_LINE_ARGS_) # define DBG_CHECK(expr,str) if (.not.expr) call assert((expr), str _FILE_LINE_ARGS_) # define DBG_ENTER(mode) call sentinel(1,mode _FILE_ABIFUNC_LINE_ARGS_) # define DBG_EXIT(mode) call sentinel(2,mode _FILE_ABIFUNC_LINE_ARGS_) /* Stop if two arrays have different shape */ # define DBG_EQSHAPE(arr1, arr2) if (any(shape(arr1)/=shape(arr2))) MSG_ERROR("Different shape") #else /* nops */ # define ASSERT(expr) # define ASSERT_IF(condition, expr) # define DBG_CHECK(expr,str) # define DBG_ENTER(mode) # define DBG_EXIT(mode) # define DBG_EQSHAPE(arr1, arr2) #endif /* Macro for basic messages */ #define MSG_COMMENT(msg) call msg_hndl(msg,"COMMENT", "PERS" _FILE_LINE_ARGS_) #define MSG_WARNING(msg) call msg_hndl(msg,"WARNING", "PERS" _FILE_LINE_ARGS_) #define MSG_ERROR(msg) call msg_hndl(msg,"ERROR", "PERS" _FILE_LINE_ARGS_) #define MSG_ERROR_CLASS(msg, cls) call msg_hndl(msg, cls , "PERS" _FILE_LINE_ARGS_) #define MSG_BUG(msg) call msg_hndl(msg,"BUG", "PERS" _FILE_LINE_ARGS_) #define MSG_ERROR_NODUMP(msg) call msg_hndl(msg, "ERROR", "PERS", NODUMP=.TRUE. _FILE_LINE_ARGS_) #define MSG_ERROR_NOSTOP(msg,ierr) \ ierr=ierr+1; call msg_hndl(msg, "ERROR", "PERS", NOSTOP=.TRUE. _FILE_LINE_ARGS_) #define ETSF_CHECK_ERROR(lstat,Error_data) if (.not. lstat) call abietsf_msg_hndl(lstat,Error_data,"PERS" _FILE_LINE_ARGS_) #define ETSF_WARN(lstat,Error_data) call abietsf_warn(lstat,Error_data,"PERS" _FILE_LINE_ARGS_) #define NCF_CHECK(ncerr) if (ncerr/=nf90_noerr) call netcdf_check(ncerr,"No msg from caller" _FILE_LINE_ARGS_) #define NCF_CHECK_MSG(ncerr,msg) if (ncerr/=nf90_noerr) call netcdf_check(ncerr,msg _FILE_LINE_ARGS_) #define NOT_IMPLEMENTED_ERROR() MSG_ERROR("Not Implemented Error") /* Macro to deprecate particular features. */ #define MSG_DEPRECATE(msg) call wrtout(ab_out, msg, "COLL") /* #define MSG_DEPRECATE(msg) MSG_ERROR(msg) */ /* Macro for clean exit */ /* #define ABI_EXIT(exit_status) call leave_new("COLL",exit_status=exit_status,print_config=.False.) */ /* Macros used for stopping the code if external libraries have not been enabled */ #define NETCDF_NOTENABLED_ERROR() MSG_ERROR("netcdf is not activated. Use configure --enable-netcdf") #ifdef HAVE_FC_LONG_LINES #define BIGDFT_NOTENABLED_ERROR() call bigdft_lib_error(__FILE__, __LINE__) #else #define BIGDFT_NOTENABLED_ERROR() call bigdft_lib_error() #endif /* Write a warning if msg is not empty */ #define MSG_WARNING_IF(msg) if (len_trim(msg)/=0) MSG_WARNING(msg) /* Dummy use of unused arguments to silence compiler warnings */ #define ABI_UNUSED(var) if (.FALSE.) call unused_var(var) #ifdef HAVE_TIMER_PAPI # define XPAPI_CHECK(check,msg) if (check/=PAPI_OK) call xpapi_handle_error(check, msg _FILE_LINE_ARGS_) #else # define XPAPI_CHECK(check,msg) #endif /* Portable support for /dev/null */ #if defined HAVE_OS_WINDOWS #define NULL_FILE "NUL" #else #define NULL_FILE "/dev/null" #endif /* Macros for Fortran IO (requires m_io_tools module) */ #ifdef DEBUG_MODE /* # define ABI_FCLOSE(fort_unit, msg) close(fort_unit) */ # define ABI_FCLOSE(fort_unit, msg) if (close_unit(fort_unit, msg)/=0) MSG_ERROR(msg) #else /* # define ABI_FCLOSE(fort_unit, msg) close(fort_unit) */ # define ABI_FCLOSE(fort_unit, msg) if (close_unit(fort_unit, msg)/=0) MSG_WARNING(msg) #endif /* F2003 support */ #define ABI_CHECK_CNULL(cptr,msg) if (.not.C_ASSOCIATED(cptr)) MSG_ERROR(msg) #ifdef HAVE_FC_ASYNC #define ABI_ASYNC ,asynchronous #else #define ABI_ASYNC #endif #ifdef HAVE_FC_PRIVATE #define ABI_PRIVATE ,private #else #define ABI_PRIVATE #endif #ifdef HAVE_FC_PROTECTED #define ABI_PROTECTED ,protected #else #define ABI_PROTECTED #endif /* F2008 support */ #ifdef HAVE_FC_CONTIGUOUS #define ABI_CONTIGUOUS contiguous, #else #define ABI_CONTIGUOUS #endif /* * Temporary trick used to pass contiguous array descriptors to F90 routines * Mainly used to avoid copy-in copy-out in m_abi_linalg #define DEV_CONTARRD contiguous, */ #define DEV_CONTARRD /* OpenMP support */ #ifndef HAVE_OMP_COLLAPSE #define COLLAPSE(x) #endif /* DFTI macros (should be declared in m_dfti but build-sys tests complain */ #define DFTI_CHECK(status) if (status/=0) call dfti_check_status(status _FILE_LINE_ARGS_) /* Macros used in the GW code */ #ifdef HAVE_GW_DPC # define GWPC_CONJG(cvar) DCONJG(cvar) # define GWPC_CMPLX(re,im) DCMPLX(re,im) #else # define GWPC_CONJG(cvar) CONJG(cvar) # define GWPC_CMPLX(re,im) CMPLX(re,im) #endif /* Macros used for particular slaves of the Abinit tests farm */ /* * IBM6 has a very problematic IO. Flushing the IO buffer helps avoid segmentation fault * To disable these tricks, comment the three lines below. * */ #ifdef FC_IBM #define HAVE_IBM6 #endif #undef HAVE_IBM6 #ifdef HAVE_IBM6 #define _IBM6(message) call wrtout(std_out,message,"COLL",do_flush=.True.) #else #define _IBM6(message) #endif /* */ #define DEV_MG_WFK #endif /* _ABINIT_COMMON_H */ v_sim-3.8.0/lib/plug-ins/abinit/abinit.c000066400000000000000000000701551370110300500200210ustar00rootroot00000000000000/* EXTRAITS DE LA LICENCE Copyright CEA, contributeurs : Luc BILLARD et Damien CALISTE, laboratoire L_Sim, (2001-2005) Adresse ml : BILLARD, non joignable par ml ; CALISTE, damien P caliste AT cea P fr. Ce logiciel est un programme informatique servant visualiser des structures atomiques dans un rendu pseudo-3D. Ce logiciel est rgi par la licence CeCILL soumise au droit franais et respectant les principes de diffusion des logiciels libres. Vous pouvez utiliser, modifier et/ou redistribuer ce programme sous les conditions de la licence CeCILL telle que diffuse par le CEA, le CNRS et l'INRIA sur le site "http://www.cecill.info". Le fait que vous puissiez accder cet en-tte signifie que vous avez pris connaissance de la licence CeCILL, et que vous en avez accept les termes (cf. le fichier Documentation/licence.fr.txt fourni avec ce logiciel). */ /* LICENCE SUM UP Copyright CEA, contributors : Luc BILLARD et Damien CALISTE, laboratoire L_Sim, (2001-2005) E-mail address: BILLARD, not reachable any more ; CALISTE, damien P caliste AT cea P fr. This software is a computer program whose purpose is to visualize atomic configurations in 3D. This software is governed by the CeCILL license under French law and abiding by the rules of distribution of free software. You can use, modify and/ or redistribute the software under the terms of the CeCILL license as circulated by CEA, CNRS and INRIA at the following URL "http://www.cecill.info". The fact that you are presently reading this means that you have had knowledge of the CeCILL license and that you accept its terms. You can find a copy of this licence shipped with this software at Documentation/licence.en.txt. */ #include #include "abinit.h" #include #include #include #include #include #include #include #include #include "ab_symmetry.h" /* For compatibility with older version. */ #ifndef AB6_INVARS_STR #define AB6_INVARS_STR(A) #A #endif #ifndef ab6_error_string_from_id #define ab6_error_string_from_id(A) #A #endif #define ABINIT_DT "ABINIT_datasets" #define ABINIT_DESCRIPTION _("" \ "This plug-in introduces support for\n" \ "crystallographic structures in\n" \ "ABINIT input files.") #define ABINIT_AUTHORS "Caliste Damien" /* Local methods */ #ifdef HAVE_ABINIT_PARSER static void abStructuralInit(VisuRendering *method); static void abSpinInit(VisuRendering *method); static gboolean loadAbinitIn(VisuData *data, const gchar* filename, ToolFileFormat *format, int nSet, GCancellable *cancel, GError **error); static gboolean loadAbinitSpin(VisuData *data, const gchar* filename, ToolFileFormat *format, int nSet, GCancellable *cancel, GError **error); static gpointer parseAbinitThread(gpointer data); static GError* loadAbinit(VisuData *data, AbInvars *dt, int nSet); static gboolean waitDt(gpointer data); static void freeDt(gpointer dt); static gchar** readPseudoFiles(AbinitData *dt); #endif /* Local variables */ static gchar *iconPath; /* Required methods for a loadable module. */ gboolean abinitInit() { DBG_fprintf(stderr, "Abinit: loading plug-in 'abinit'...\n"); iconPath = g_build_filename(V_SIM_PIXMAPS_DIR, "abinit.png", NULL); #ifdef HAVE_ABINIT_PARSER DBG_fprintf(stderr, "Abinit: declare a new rendering load method.\n"); abStructuralInit(visu_rendering_getByName(VISU_RENDERING_ATOMIC_NAME)); DBG_fprintf(stderr, "Abinit: declare a new spin load method.\n"); abSpinInit(visu_rendering_getByName(VISU_RENDERING_SPIN_NAME)); ab_mpi_init(); #endif return TRUE; } gboolean abinitInitGtk() { DBG_fprintf(stderr, "Abinit: declare a new interactive tab.\n"); visu_ui_interactive_addAction(buildTab, startSelect, stopSelect); return TRUE; } const char* abinitGet_description() { return ABINIT_DESCRIPTION; } const char* abinitGet_authors() { return ABINIT_AUTHORS; } const char* abinitGet_icon() { return iconPath; } #ifdef HAVE_ABINIT_PARSER static void abStructuralInit(VisuRendering *method) { #ifdef HAVE_NEW_WITH_PSEUDO const gchar *type[] = {"*.in", "*.files", (char*)0}; #else const gchar *type[] = {"*.in", (char*)0}; #endif visu_rendering_addFileFormat(method, 0, tool_file_format_new(_("ABINIT input file format"), type), 95, loadAbinitIn); } #endif static GMutex *dt_mutex = (GMutex*)0; void abinit_mutexInit() { if (!dt_mutex) { #if GLIB_MINOR_VERSION < 32 dt_mutex = g_mutex_new(); #else dt_mutex = g_malloc(sizeof(GMutex)); g_mutex_init(dt_mutex); #endif } } void abinit_mutexRelease() { if (dt_mutex) { #if GLIB_MINOR_VERSION < 32 g_mutex_free(dt_mutex); #else g_mutex_clear(dt_mutex); #endif dt_mutex = (GMutex*)0; } } void abinit_mutexUnlock() { if (dt_mutex) g_mutex_unlock(dt_mutex); } static AbinitData ABINIT_DATA; AbinitData* abinit_getDt() { if (!g_mutex_trylock(dt_mutex)) return (AbinitData*)0; else return &ABINIT_DATA; } AbinitData* abinit_getDirectDt() { return &ABINIT_DATA; } #ifdef HAVE_ABINIT_PARSER static gboolean loadAbinitIn(VisuData *data, const gchar* filename, ToolFileFormat *format _U_, int nSet, GCancellable *cancel, GError **error) { #ifdef G_THREADS_ENABLED GThread *ld_thread; #endif AbinitData *dt; AbInvars *dataset; g_return_val_if_fail(error && !*error, FALSE); /* Try to see if data has already read this dataset. */ dataset = (AbInvars*)g_object_get_data(G_OBJECT(data), ABINIT_DT); if (dataset) { *error = loadAbinit(data, dataset, nSet); return TRUE; } /* Read the file, since it's the first time. */ dt = abinit_getDirectDt(); dt->dt = (AbInvars*)0; dt->filename = g_strdup(filename); dt->error = (GError*)0; dt->isABFormat = FALSE; dt->data = data; dt->nSet = nSet; dt->getMessages = TRUE; dt->messages = g_async_queue_new(); dt->useSignals = TRUE; dt->signals = g_async_queue_new(); dt->cancel = cancel; #ifdef G_THREADS_ENABLED abinit_mutexInit(); ld_thread = g_thread_create(parseAbinitThread, (gpointer)0, FALSE, error); DBG_fprintf(stderr, "AB structure: run ABINIT parsing into a thread (%p) from me (%p).\n", (gpointer)ld_thread, (gpointer)g_thread_self()); if (ld_thread) { g_async_queue_pop(dt->signals); DBG_fprintf(stderr, "AB structure: start waiting.\n"); g_idle_add_full(G_PRIORITY_LOW, waitDt, (gpointer)0, (GDestroyNotify)0); } else g_warning("Can't run thread for ABINIT parsing."); #else DBG_fprintf(stderr, "AB structure: run ABINIT parsing directly.\n"); *error = (GError*)parseAbinitThread((gpointer)(&dt)); #endif while(g_main_context_pending(NULL)) g_main_context_dispatch(g_main_context_default()); if (dt->error) *error = dt->error; g_async_queue_unref(dt->signals); g_async_queue_unref(dt->messages); abinit_mutexRelease(); g_free(dt->filename); DBG_fprintf(stderr, "AB structure: file parsed, returns %d.\n", dt->isABFormat); return dt->isABFormat; } static gpointer parseAbinitThread(gpointer data _U_) { AbinitData *dt; AbInvars *dt_; gchar **pseudos; DBG_fprintf(stderr, "AB(%p) main: get the dt structure.\n", (gpointer)g_thread_self()); dt = abinit_getDt(); g_return_val_if_fail(dt, (gpointer)0); /* Send a signal to V_Sim to say that parsing will start. */ g_async_queue_push(dt->signals, GINT_TO_POINTER(TRUE)); /* Try to see if the provided file is a *.files with pseudo information. */ pseudos = readPseudoFiles(dt); if (!dt->error) { /* Read the file and store its contain as a string. */ DBG_fprintf(stderr, "AB(%p) main: read and store input file '%s'.\n", (gpointer)g_thread_self(), dt->filename); #ifdef HAVE_NEW_WITH_PSEUDO DBG_fprintf(stderr, "AB(%p) main: pseudo list %p.\n", (gpointer)g_thread_self(), (gpointer)pseudos); dt_ = ab_invars_new_from_file_with_pseudo(dt->filename, (const char**)pseudos); #else dt_ = ab_invars_new_from_file(dt->filename); if (pseudos) g_warning("Unsupported ABINIT input file with pseudo-potential information."); #endif if (pseudos) g_strfreev(pseudos); /* If we reach here, it means that no error happened. */ dt->dt = dt_; } DBG_fprintf(stderr, "AB(%p) main: unlock mutex, other thread can access dt.\n", (gpointer)g_thread_self()); abinit_mutexUnlock(); return (gpointer)0; } static gboolean waitDt(gpointer data _U_) { AbinitData *dt; gpointer mess; dt = abinit_getDirectDt(); /* We stop on cancel, without error. */ if (g_cancellable_is_cancelled(dt->cancel)) { /* We push a message in the queue to be tested by ABINIT. */ g_async_queue_push(dt->signals, GINT_TO_POINTER(TRUE)); return TRUE; } mess = g_async_queue_try_pop(dt->messages); if (mess) { visu_object_setLoadMessage(VISU_OBJECT_INSTANCE, (const gchar*)mess); g_free(mess); } /* DBG_fprintf(stderr, "AB structure: waiting...\n"); */ dt = abinit_getDt(); if (!dt) return TRUE; /* We empty the message queue, in case. */ DBG_fprintf(stderr, "AB structure: empty the queue.\n"); while (g_async_queue_length(dt->messages) > 0) { DBG_fprintf(stderr, " | emptying.\n"); g_free(g_async_queue_pop(dt->messages)); } DBG_fprintf(stderr, "AB structure: stop waiting, analyse.\n"); dt->isABFormat = TRUE; if (dt->error && dt->error->code == TOOL_FILE_FORMAT_ERROR_FILE) { dt->isABFormat = FALSE; g_error_free(dt->error); dt->error = (GError*)0; abinit_mutexUnlock(); return FALSE; } else if (dt->error) { abinit_mutexUnlock(); return FALSE; } else { dt->error = loadAbinit(dt->data, dt->dt, dt->nSet); /* We attach this Abinit dataset to this VisuData. */ DBG_fprintf(stderr, "AB structure: add '%s' to VisuData %p.\n", ABINIT_DT, (gpointer)dt->data); g_object_set_data_full(G_OBJECT(dt->data), ABINIT_DT, (gpointer)dt->dt, freeDt); } abinit_mutexUnlock(); return FALSE; } static void freeDt(gpointer dt) { DBG_fprintf(stderr, "AB structure: release ABINIT resources.\n"); ab_invars_free((AbInvars*)dt); } static gchar** readPseudoFiles(AbinitData *dt) { GIOChannel *ioFile; GString *line= (GString*)0; gchar *inFile; GList *lst, *tmpLst; gchar **out; int i; DBG_fprintf(stderr, "AB(%p) main: read '%s' to find pseudo files.\n", (gpointer)g_thread_self(), dt->filename); ioFile = g_io_channel_new_file(dt->filename, "r", NULL); if (!ioFile) return (gchar**)0; line = g_string_new(""); if (g_io_channel_read_line_string(ioFile, line, NULL, NULL) != G_IO_STATUS_NORMAL) { g_io_channel_shutdown(ioFile, FALSE, NULL); g_io_channel_unref(ioFile); g_string_free(line, TRUE); return (gchar**)0; } inFile = g_strstrip(g_strdup(line->str)); /* We test inFile in case. */ DBG_fprintf(stderr, "AB(%p) main: testing '%s' as input file.\n", (gpointer)g_thread_self(), inFile); if (!g_file_test(inFile, G_FILE_TEST_EXISTS | G_FILE_TEST_IS_REGULAR)) { g_io_channel_shutdown(ioFile, FALSE, NULL); g_io_channel_unref(ioFile); g_string_free(line, TRUE); g_free(inFile); return (gchar**)0; } /* From now on, we consider that we have a valid *.files file. */ for (i = 0; i < 4; i++) if (g_io_channel_read_line_string(ioFile, line, NULL, &dt->error) != G_IO_STATUS_NORMAL) { g_io_channel_shutdown(ioFile, FALSE, NULL); g_io_channel_unref(ioFile); g_string_free(line, TRUE); g_free(inFile); return (gchar**)0; } lst = (GList*)0; while (g_io_channel_read_line_string(ioFile, line, NULL, &dt->error) == G_IO_STATUS_NORMAL) { lst = g_list_append(lst, (gpointer)g_strstrip(g_strdup(line->str))); DBG_fprintf(stderr, "AB(%p) main: testing '%s' as a pseudo.\n", (gpointer)g_thread_self(), (gchar*)lst->data); if (!g_file_test((const gchar*)lst->data, G_FILE_TEST_EXISTS | G_FILE_TEST_IS_REGULAR)) { dt->error = g_error_new(VISU_ERROR_RENDERING, TOOL_FILE_FORMAT_ERROR_FILE, "Invalid psedo-potential file '%s'.", (const gchar*)lst->data); g_io_channel_shutdown(ioFile, FALSE, NULL); g_io_channel_unref(ioFile); g_string_free(line, TRUE); g_free(inFile); for (tmpLst = lst; tmpLst; tmpLst = g_list_next(tmpLst)) g_free(tmpLst->data); g_list_free(lst); return (gchar**)0; } } g_string_free(line, TRUE); out = g_malloc(sizeof(gchar*) * (g_list_length(lst) + 1)); for (i = 0, tmpLst = lst; tmpLst; i++, tmpLst = g_list_next(tmpLst)) out[i] = tmpLst->data; out[i] = (gchar*)0; g_list_free(lst); g_free(dt->filename); dt->filename = inFile; return out; } #endif void FC_FUNC(wrtout, WRTOUT)(int *unit,char message[500], char mode_paral[4]) { gchar *buf, *ptError, *ptInvars0, *ptInstrng, *ptSize, *ptLen, *ptMinus; AbinitData *dt; dt = abinit_getDirectDt(); g_return_if_fail(dt); #ifdef G_THREADS_ENABLED if (dt->useSignals && g_async_queue_try_pop(dt->signals)) { dt->error = g_error_new(TOOL_FILE_FORMAT_ERROR, TOOL_FILE_FORMAT_ERROR_CANCEL, "Loading process cancelled."); abinit_mutexUnlock(); g_thread_exit((gpointer)0); } #endif buf = g_strndup(message, 500); g_strstrip(buf); DBG_fprintf(stderr, "AB(%p) main: wrtout(%d %c%c%c%c) %s\n", (gpointer)g_thread_self(), *unit, mode_paral[0], mode_paral[1], mode_paral[2], mode_paral[3], buf); /* We analyse buf. If, it contains an error, we test if it is about natom in inarvs0. If so, the file is not a valid ABINIT file. On the contrary, we get the message and raise an error. */ ptError = strstr(buf, "ERROR"); if (!ptError) ptError = strstr(buf, "BUG"); if (!ptError) ptError = strstr(buf, "Error"); ptInvars0 = strstr(buf, "Input natom must be defined"); ptInstrng = strstr(buf, "The occurence of a tab"); ptSize = strstr(buf, "The size of your input file"); ptLen = strstr(buf, "The number of lines already read from input file="); ptMinus = strstr(buf, "the occurence of a minus sign followed"); if (ptError && ptInvars0) dt->error = g_error_new(TOOL_FILE_FORMAT_ERROR, TOOL_FILE_FORMAT_ERROR_FILE, "Not an ABINIT file (no 'natom' keyword found)."); else if (ptError && ptInstrng) dt->error = g_error_new(TOOL_FILE_FORMAT_ERROR, TOOL_FILE_FORMAT_ERROR_FILE, "Not an ABINIT file (tab characters found in the file)."); else if (ptError && ptSize) dt->error = g_error_new(TOOL_FILE_FORMAT_ERROR, TOOL_FILE_FORMAT_ERROR_FILE, "Not an ABINIT file (input file too long)."); else if (ptError && ptLen) dt->error = g_error_new(TOOL_FILE_FORMAT_ERROR, TOOL_FILE_FORMAT_ERROR_FILE, "Not an ABINIT file (too many lines)."); else if (ptError && ptMinus) dt->error = g_error_new(TOOL_FILE_FORMAT_ERROR, TOOL_FILE_FORMAT_ERROR_FILE, "Not an ABINIT file (minus space error)."); else if (ptError) dt->error = g_error_new(TOOL_FILE_FORMAT_ERROR, TOOL_FILE_FORMAT_ERROR_FORMAT, "%s", buf); else dt->error = (GError*)0; if (dt->getMessages && strstr(buf, "getkgrid")) g_async_queue_push(dt->messages, buf); else g_free(buf); if (dt->error) { DBG_fprintf(stderr, "AB(%p) main: an error occured in ABINIT.\n", (gpointer)g_thread_self()); #ifdef G_THREADS_ENABLED abinit_mutexUnlock(); g_thread_exit((gpointer)0); #else g_error("ABINIT plug-in requires threads."); #endif } } void FC_FUNC(leave_new, LEAVE_NEW)(char mode_paral[4]) { AbinitData *dt; dt = abinit_getDirectDt(); g_return_if_fail(dt); DBG_fprintf(stderr, "AB(%p) main: leave_new(%c%c%c%c)\n", (gpointer)g_thread_self(), mode_paral[0], mode_paral[1], mode_paral[2], mode_paral[3]); dt->error = g_error_new(TOOL_FILE_FORMAT_ERROR, TOOL_FILE_FORMAT_ERROR_FILE, "Not an ABINIT file"); DBG_fprintf(stderr, "AB(%p) main: return error (%p).\n", (gpointer)g_thread_self(), (gpointer)dt->error); #ifdef G_THREADS_ENABLED abinit_mutexUnlock(); g_thread_exit((gpointer)0); #else g_error("ABINIT plug-in requires threads."); #endif } void FC_FUNC(timab, TIMAB)() { } void FC_FUNC(psp_from_data, PSP_FROM_DATA)() { } #ifdef HAVE_ABINIT_PARSER static GError* loadAbinit(VisuData *data, AbInvars *dt, int nSet) { int ndtset, i; int ntypat, natom, nzero, *index; int *typat; double *znucl, rprimd[3][3], *coord, *spinat; VisuElement **ntypes; VisuElement *ele; float rcov, red[3]; char *ptChar, *name; GArray *nattyp, *types; AbError error; gboolean newEle; VisuBox *boxObj; g_return_val_if_fail(dt, (GError*)0); DBG_fprintf(stderr, "AB structure: transfer data.\n"); /* Ok, try to find the required keywords. */ error = ab_invars_get_ndtset(dt, &ndtset); if (error != AB_NO_ERROR) return g_error_new(TOOL_FILE_FORMAT_ERROR, TOOL_FILE_FORMAT_ERROR_METHOD, "Abinit loader report error %d while getting n datasets.", (int)error); DBG_fprintf(stderr, "AB structure: found %d dtsets.\n", ndtset); /* Store the number of datasets. */ visu_data_setNSubset(data, ndtset); g_return_val_if_fail(nSet >= 0 && nSet < ndtset, g_error_new(TOOL_FILE_FORMAT_ERROR, TOOL_FILE_FORMAT_ERROR_METHOD, "Can't load dataset %d.", nSet)); error = ab_invars_get_integer(dt, AB_INVARS_NTYPAT, nSet + 1, &ntypat); if (error != AB_NO_ERROR) return g_error_new(TOOL_FILE_FORMAT_ERROR, TOOL_FILE_FORMAT_ERROR_METHOD, "Abinit loader report error:\n %s\nwhile getting attribute '%s'.", ab6_error_string_from_id(error), AB_INVARS_STR(AB_INVARS_NTYPAT)); error = ab_invars_get_integer(dt, AB_INVARS_NATOM, nSet + 1, &natom); if (error != AB_NO_ERROR) return g_error_new(TOOL_FILE_FORMAT_ERROR, TOOL_FILE_FORMAT_ERROR_METHOD, "Abinit loader report error:\n %s\nwhile getting attribute '%s'.", ab6_error_string_from_id(error), AB_INVARS_STR(AB_INVARS_NATOM)); DBG_fprintf(stderr, "AB structure: with %d atoms and %d types.\n", natom, ntypat); typat = g_malloc(sizeof(int) * natom); error = ab_invars_get_integer_array(dt, typat, natom, AB_INVARS_TYPAT, nSet + 1); if (error != AB_NO_ERROR) { g_free(typat); return g_error_new(TOOL_FILE_FORMAT_ERROR, TOOL_FILE_FORMAT_ERROR_METHOD, "Abinit loader report error:\n %s\nwhile getting attribute '%s'.", ab6_error_string_from_id(error), AB_INVARS_STR(AB_INVARS_TYPAT)); } znucl = g_malloc(sizeof(double) * ntypat); error = ab_invars_get_real_array(dt, znucl, ntypat, AB_INVARS_ZNUCL, nSet + 1); if (error != AB_NO_ERROR) { g_free(typat); g_free(znucl); return g_error_new(TOOL_FILE_FORMAT_ERROR, TOOL_FILE_FORMAT_ERROR_METHOD, "Abinit loader report error:\n %s\nwhile getting attribute '%s'.", ab6_error_string_from_id(error), AB_INVARS_STR(AB_INVARS_ZNUCL)); } DBG_fprintf(stderr, "AB structure: read znucl OK.\n"); types = g_array_sized_new(FALSE, FALSE, sizeof(VisuElement*), ntypat); for (i = 0; i < ntypat; i++) { /* Try to find a name instead of a z number. */ tool_physic_getSymbolFromZ(&ptChar, &rcov, znucl[i]); name = g_strdup(ptChar); /* adding name to the hashtable */ ele = visu_element_retrieveFromName(name, &newEle); g_array_insert_val(types, i, ele); if (newEle) visu_rendering_atomic_setRadius(ele, rcov); g_free(name); } g_free(znucl); DBG_fprintf(stderr, "AB structure: all new elements created.\n"); nattyp = g_array_sized_new(FALSE, TRUE, sizeof(guint), ntypat); g_array_set_size(nattyp, ntypat); ntypes = g_malloc(sizeof(VisuElement*) * natom); for (i = 0; i < natom; i++) { g_array_index(nattyp, guint, typat[i] - 1) += 1; ntypes[i] = g_array_index(types, VisuElement*, typat[i] - 1); } /* Reduce the arrays when nattyp is 0. */ nzero = 0; index = g_malloc(sizeof(int) * ntypat); for (i = 0; i < ntypat; i++) { if (i > nzero) { g_array_index(nattyp, guint, nzero) = g_array_index(nattyp, guint, i); g_array_index(types, VisuElement*, nzero) = g_array_index(types, VisuElement*, i); } index[i] = nzero; if (g_array_index(nattyp, guint, i) > 0) nzero += 1; } DBG_fprintf(stderr, "AB structure: removing null types.\n"); for (i = 0; i < natom; i++) { DBG_fprintf(stderr, "AB structure: atom %d (%d)", i, typat[i] - 1); DBG_fprintf(stderr, " -> %d.\n", index[typat[i] - 1]); ntypes[i] = g_array_index(types, VisuElement*, index[typat[i] - 1]); } g_free(typat); g_free(index); ntypat = nzero; g_array_set_size(types, ntypat); g_array_set_size(nattyp, ntypat); DBG_fprintf(stderr, "AB structure: there are %d types in this file.\n", ntypat); if (DEBUG) for (i = 0; i < ntypat; i++) fprintf(stderr, " | %d atom(s) for type %d.\n", g_array_index(nattyp, guint, i), i); if (DEBUG) for (i = 0; i < natom; i++) fprintf(stderr, " | atom %d of type %p.\n", i, (gpointer)ntypes[i]); visu_node_array_allocate(VISU_NODE_ARRAY(data), types, nattyp); g_array_free(nattyp, TRUE); g_array_free(types, TRUE); error = ab_invars_get_real_array(dt, (double*)rprimd, 9, AB_INVARS_RPRIMD_ORIG, nSet + 1); if (error != AB_NO_ERROR) { g_free(ntypes); return g_error_new(TOOL_FILE_FORMAT_ERROR, TOOL_FILE_FORMAT_ERROR_METHOD, "Abinit loader report error:\n %s\nwhile getting attribute '%s'.", ab_error_string_from_id(error), AB_INVARS_STR(AB_INVARS_RPRIMD_ORIG)); } DBG_fprintf(stderr, " | box definition : ( %f %f %f )\n", rprimd[0][0], rprimd[0][1], rprimd[0][2]); DBG_fprintf(stderr, " | ( %f %f %f )\n", rprimd[1][0], rprimd[1][1], rprimd[1][2]); DBG_fprintf(stderr, " | ( %f %f %f )\n", rprimd[2][0], rprimd[2][1], rprimd[2][2]); boxObj = visu_box_new_full(rprimd, VISU_BOX_PERIODIC); if (visu_box_getGeometry(boxObj, VISU_BOX_DXX) == G_MAXFLOAT) { g_free(ntypes); return g_error_new(TOOL_FILE_FORMAT_ERROR, TOOL_FILE_FORMAT_ERROR_FORMAT, _("Abinit loader report error:\n basis-set is degenerated.\n")); } visu_boxed_setBox(VISU_BOXED(data), VISU_BOXED(boxObj)); g_object_unref(boxObj); coord = g_malloc(sizeof(double) * 3 * natom); error = ab_invars_get_real_array(dt, coord, 3 * natom, AB_INVARS_XRED_ORIG, nSet + 1); if (error != AB_NO_ERROR) { g_free(ntypes); g_free(coord); return g_error_new(TOOL_FILE_FORMAT_ERROR, TOOL_FILE_FORMAT_ERROR_METHOD, "Abinit loader report error:\n %s\nwhile getting attribute '%s'.", ab6_error_string_from_id(error), AB_INVARS_STR(AB_INVARS_XRED_ORIG)); } for (i = 0; i < natom; i++) { red[0] = (float)*(coord + 3 * i + 0); red[1] = (float)*(coord + 3 * i + 1); red[2] = (float)*(coord + 3 * i + 2); DBG_fprintf(stderr, " | ( %f %f %f )\n", red[0], red[1], red[2]); visu_data_addNodeFromElement(data, ntypes[i], red, TRUE, FALSE); } /* We reset the box size after we set all the coordinates to get the OpenGL box right. */ visu_box_setMargin(boxObj, visu_node_array_getMaxElementSize(VISU_NODE_ARRAY(data)) + visu_data_getAllNodeExtens(data, boxObj), TRUE); g_free(ntypes); g_free(coord); /* We set the units. */ visu_box_setUnit(boxObj, TOOL_UNITS_BOHR); /* We store the spinat array as a property to be used later by the spin loading method. */ spinat = g_malloc(sizeof(double) * 3 * natom); g_object_set_data_full(G_OBJECT(data), "ABINIT_spinat", (gpointer)spinat, g_free); error = ab_invars_get_real_array(dt, spinat, 3 * natom, AB_INVARS_SPINAT, nSet + 1); if (error != AB_NO_ERROR) { g_free(spinat); return g_error_new(TOOL_FILE_FORMAT_ERROR, TOOL_FILE_FORMAT_ERROR_METHOD, "Abinit loader report error:\n %s\nwhile getting attribute '%s'.", ab6_error_string_from_id(error), AB_INVARS_STR(AB_INVARS_SPINAT)); } return (GError*)0; } static void abSpinInit(VisuRendering *method) { const gchar *type[] = {"*.in", (char*)0}; visu_rendering_addFileFormat(method, FILE_KIND_SPIN, tool_file_format_new(_("ABINIT input file format"), type), 95, loadAbinitSpin); } static void freeSpin(gpointer obj, gpointer data _U_) { #if GLIB_MINOR_VERSION > 9 g_slice_free1(sizeof(float) * 3, obj); #else g_free(obj); #endif } static gpointer newOrCopySpin(gconstpointer obj, gpointer data _U_) { float *spinData; #if GLIB_MINOR_VERSION > 9 spinData = g_slice_alloc(sizeof(float) * 3); #else spinData = g_malloc(sizeof(float) * 3); #endif if (obj) memcpy(spinData, obj, sizeof(float) * 3); else memset(spinData, 0, sizeof(float) * 3); return (gpointer)spinData; } static void initMaxModulus(VisuElement *ele _U_, GValue *val) { DBG_fprintf(stderr, " | init max modulus of val %p.\n", (gpointer)val); g_value_init(val, G_TYPE_FLOAT); g_value_set_float(val, -G_MAXFLOAT); } static gboolean loadAbinitSpin(VisuData *data, const gchar* filename, ToolFileFormat *format _U_, int nSet _U_, GCancellable *cancel _U_, GError **error) { double *spinat; float spins[3]; float *svgSpinValues; float sph[3], vals[3]; VisuNodeProperty *spin; VisuNodeArrayIter iter; GValue spinValue = {0, {{0}, {0}}}; GValueArray *svgMaxSpinModulus; GValue *val; g_return_val_if_fail(error && *error == (GError*)0, FALSE); g_return_val_if_fail(data && filename, FALSE); spinat = (double*)g_object_get_data(G_OBJECT(data), "ABINIT_spinat"); if (!spinat) return FALSE; /* We check that spin and position are the same. */ /* TODO... */ /* Create a storage for max values of spin modulus for each element. */ svgMaxSpinModulus = visu_node_array_setElementProperty(VISU_NODE_ARRAY(data), VISU_RENDERING_SPIN_MAX_MODULUS_ID, initMaxModulus); spin = visu_node_array_property_newPointer(VISU_NODE_ARRAY(data), VISU_RENDERING_SPIN_VALUES_ID, freeSpin, newOrCopySpin, (gpointer)0); g_value_init(&spinValue, G_TYPE_POINTER); visu_node_array_iter_new(VISU_NODE_ARRAY(data), &iter); for(visu_node_array_iterStartNumber(VISU_NODE_ARRAY(data), &iter); iter.node; visu_node_array_iterNextNodeNumber(VISU_NODE_ARRAY(data), &iter)) { spins[0] = (float)(spinat + iter.node->number * 3)[0]; spins[1] = (float)(spinat + iter.node->number * 3)[1]; spins[2] = (float)(spinat + iter.node->number * 3)[2]; tool_matrix_cartesianToSpherical(sph, spins); vals[TOOL_MATRIX_SPHERICAL_MODULUS] = sph[0]; vals[TOOL_MATRIX_SPHERICAL_THETA] = sph[1]; vals[TOOL_MATRIX_SPHERICAL_PHI] = sph[2]; svgSpinValues = newOrCopySpin(vals, (gpointer)0); g_value_set_pointer(&spinValue, svgSpinValues); visu_node_property_setValue(spin, iter.node, &spinValue); val = g_value_array_get_nth(svgMaxSpinModulus, iter.iElement); g_value_set_float(val, MAX(vals[TOOL_MATRIX_SPHERICAL_MODULUS], g_value_get_float(val))); } /* We kill the temporary spinat property. */ g_free(g_object_steal_data(G_OBJECT(data), "ABINIT_spinat")); /* Everything is OK. */ *error = (GError*)0; return TRUE; } #endif v_sim-3.8.0/lib/plug-ins/abinit/abinit.h000066400000000000000000000104461370110300500200230ustar00rootroot00000000000000#ifndef ABINIT_H #define ABINIT_H #include #include #include #include #if AB_LIBRARY_VERSION == 6 #ifdef HAVE_ABINIT_SYMMETRY #include #define AbSymmetry Ab6Symmetry #define AbSymmetryMat Ab6SymmetryMat #define AbSymmetryTrans Ab6SymmetryTrans #endif #include #define AbError Ab6Error #define AbInvars Ab6Invars #define AB_NO_ERROR AB6_NO_ERROR #define AB_ERROR_SYM_BRAVAIS_XRED AB6_ERROR_SYM_BRAVAIS_XRED #define AB_ERROR_SYM_NOT_PRIMITIVE AB6_ERROR_SYM_NOT_PRIMITIVE #define AB_INVARS_NTYPAT AB6_INVARS_NTYPAT #define AB_INVARS_NATOM AB6_INVARS_NATOM #define AB_INVARS_TYPAT AB6_INVARS_TYPAT #define AB_INVARS_ZNUCL AB6_INVARS_ZNUCL #define AB_INVARS_RPRIMD_ORIG AB6_INVARS_RPRIMD_ORIG #define AB_INVARS_XRED_ORIG AB6_INVARS_XRED_ORIG #define AB_INVARS_SPINAT AB6_INVARS_SPINAT #define AB_INVARS_STR AB6_INVARS_STR #define ab_mpi_init ab6_mpi_init #define ab_error_string_from_id ab6_error_string_from_id #define ab_invars_new_from_file_with_pseudo ab6_invars_new_from_file_with_pseudo #define ab_invars_get_ndtset ab6_invars_get_ndtset #define ab_invars_get_integer ab6_invars_get_integer #define ab_invars_get_integer_array ab6_invars_get_integer_array #define ab_invars_get_real_array ab6_invars_get_real_array #define ab_invars_free ab6_invars_free #ifdef HAVE_ABINIT_SYMMETRY #define ab_symmetry_get_equivalent_atom ab7_symmetry_get_equivalent_atom #define ab_symmetry_set_lattice ab6_symmetry_set_lattice #define ab_symmetry_set_structure ab6_symmetry_set_structure #define ab_symmetry_get_type ab6_symmetry_get_type #define ab_symmetry_get_group ab6_symmetry_get_group #define ab_symmetry_get_matrices ab6_symmetry_get_matrices #define ab_symmetry_get_bravais ab6_symmetry_get_bravais #define ab_symmetry_new ab6_symmetry_new #define ab_symmetry_free ab6_symmetry_free #define ab_symmetry_set_tolerance ab6_symmetry_set_tolerance #endif #endif #if AB_LIBRARY_VERSION == 7 #include #define AbInvars Ab7Invars #define ab_mpi_init ab7_mpi_init #define ab_error_string_from_id ab7_error_string_from_id #define ab_invars_new_from_file_with_pseudo ab7_invars_new_from_file_with_pseudo #define ab_invars_get_ndtset ab7_invars_get_ndtset #define ab_invars_get_integer ab7_invars_get_integer #define ab_invars_get_integer_array ab7_invars_get_integer_array #define ab_invars_get_real_array ab7_invars_get_real_array #define ab_invars_free ab7_invars_free #endif #define AbError Ab7Error #define AB_NO_ERROR AB7_NO_ERROR #define AB_ERROR_SYM_BRAVAIS_XRED AB7_ERROR_SYM_BRAVAIS_XRED #define AB_ERROR_SYM_NOT_PRIMITIVE AB7_ERROR_SYM_NOT_PRIMITIVE #define AB_INVARS_NTYPAT AB7_INVARS_NTYPAT #define AB_INVARS_NATOM AB7_INVARS_NATOM #define AB_INVARS_TYPAT AB7_INVARS_TYPAT #define AB_INVARS_ZNUCL AB7_INVARS_ZNUCL #define AB_INVARS_RPRIMD_ORIG AB7_INVARS_RPRIMD_ORIG #define AB_INVARS_XRED_ORIG AB7_INVARS_XRED_ORIG #define AB_INVARS_SPINAT AB7_INVARS_SPINAT #define AB_INVARS_STR AB7_INVARS_STR #include #define AbSymmetry Ab7Symmetry #define AbSymmetryMat Ab7SymmetryMat #define AbSymmetryTrans Ab7SymmetryTrans #define ab_symmetry_get_equivalent_atom ab7_symmetry_get_equivalent_atom #define ab_symmetry_set_lattice ab7_symmetry_set_lattice #define ab_symmetry_set_structure ab7_symmetry_set_structure #define ab_symmetry_get_type ab7_symmetry_get_type #define ab_symmetry_get_group ab7_symmetry_get_group #define ab_symmetry_get_matrices ab7_symmetry_get_matrices #define ab_symmetry_get_bravais ab7_symmetry_get_bravais #define ab_symmetry_new ab7_symmetry_new #define ab_symmetry_free ab7_symmetry_free #define ab_symmetry_set_tolerance ab7_symmetry_set_tolerance struct _abinitData { VisuData *data; GCancellable *cancel; GError *error; /* Queue to send messages from V_Sim to ABINIT thread. */ GAsyncQueue *signals; gboolean useSignals; /* Queue to send messages from the ABINIT thread to V_Sim. */ GAsyncQueue *messages; gboolean getMessages; /* Data for the invars part. */ #ifdef HAVE_ABINIT_PARSER AbInvars *dt; gchar *filename; int nSet; gboolean isABFormat; #endif /* Data for the symmetries. */ AbSymmetry *sym; }; typedef struct _abinitData AbinitData; void abinit_mutexInit(); void abinit_mutexRelease(); void abinit_mutexUnlock(); AbinitData* abinit_getDt(); AbinitData* abinit_getDirectDt(); #endif v_sim-3.8.0/lib/plug-ins/abinit/abinit.png000066400000000000000000000042071370110300500203560ustar00rootroot00000000000000PNG  IHDR ꂣAbKGD pHYs  tIME  "4tEXtCommentCreated with The GIMPd%nIDATHǵ[l9q>8I;CBCTjh+ҋWTU+D7M[UURR  4 p6JH7ރٝݙݙkZ&*_3o 8u>/`?@BK~?7Ğ>>}\ Q6Hf78؆KRezm%\Vit< efv~5r]X+&l0>; D*4BrW?ۍee|/4:bO ==9PM=忽Jӛk/@c v/K- f'gl}D!Rcu P߻Ls12oPeLMrsH{J=ca/bpk_m>E4iB T)$ R|ThL ĺ&F6GXy^3?E˘s[? :z-w( >Q`xDU($S̜1'k:h#Ё(,3i@yNE~7ĺjrl\ ^Fxl*H*L\8 u{5ң\GA*çͶ{!,-zSjR&]'ڵunRHbqx~p+,upcu;T`N sHnñ Jf<ˎS'02( F[>8HղLboz\ʆcC zo2l)5^W}=;i̮ g3IENDB`v_sim-3.8.0/lib/plug-ins/abinit/chkprimit.F90000066400000000000000000000056411370110300500206570ustar00rootroot00000000000000!{\src2tex{textfont=tt}} !!****f* ABINIT/chkprimit !! NAME chkprimit !! chkprimit !! !! !! FUNCTION !! Check whether the cell is primitive or not. !! If chkprim/=0 and the cell is non-primitive, stops. !! !! COPYRIGHT !! Copyright (C) 2000-2016 ABINIT group (XG) !! This file is distributed under the terms of the !! GNU General Public License, see ~abinit/COPYING !! or http://www.gnu.org/copyleft/gpl.txt . !! For the initials of contributors, see ~abinit/doc/developers/contributors.txt . !! !! INPUTS !! chkprim= if non-zero, check that the unit cell is primitive. !! nsym=actual number of symmetries !! symafm(nsym)= (anti)ferromagnetic part of symmetry operations !! symrel(3,3,nsym)= nsym symmetry operations in real space in terms !! of primitive translations !! !! OUTPUT !! multi=multiplicity of the unit cell !! !! SIDE EFFECTS !! !! NOTES !! !! PARENTS !! symanal !! !! CHILDREN !! !! SOURCE #if defined HAVE_CONFIG_H #include "config.h" #endif #include "abi_common.h" subroutine chkprimit(chkprim,multi,nsym,symafm,symrel) use defs_basis use m_profiling_abi use m_errors !This section has been created automatically by the script Abilint (TD). !Do not modify the following lines by hand. #undef ABI_FUNC #define ABI_FUNC 'chkprimit' !End of the abilint section implicit none !Arguments ------------------------------------ !scalars integer,intent(in) :: chkprim,nsym integer,intent(out) :: multi !arrays integer,intent(in) :: symafm(nsym),symrel(3,3,nsym) !Local variables------------------------------- !scalars integer :: isym character(len=500) :: message !************************************************************************** !Loop over each symmetry operation of the Bravais lattice !Find whether it is the identity, or a pure translation, !without change of sign of the spin multi=0 do isym=1,nsym if( abs(symrel(1,1,isym)-1)+& & abs(symrel(2,2,isym)-1)+& & abs(symrel(3,3,isym)-1)+& & abs(symrel(1,2,isym))+abs(symrel(2,1,isym))+& & abs(symrel(2,3,isym))+abs(symrel(3,2,isym))+& & abs(symrel(3,1,isym))+abs(symrel(1,3,isym))+& & abs(symafm(isym)-1) == 0 )then multi=multi+1 end if end do !Check whether the cell is primitive if(multi>1)then if(chkprim/=0)then write(message,'(a,a,a,i0,a,a,a,a,a,a,a,a,a)')& & 'According to the symmetry finder, the unit cell is',ch10,& & 'NOT primitive. The multiplicity is ',multi,' .',ch10,& & 'The use of non-primitive unit cells is allowed',ch10,& & 'only when the input variable chkprim is 0.',ch10,& & 'Action : either change your unit cell (rprim or angdeg),',ch10,& & 'or set chkprim to 0.' MSG_ERROR(message) else write(message,'(3a,i0,a,a,a)')& & 'According to the symmetry finder, the unit cell is',ch10,& & 'not primitive, with multiplicity=',multi,'.',ch10,& & 'This is allowed, as the input variable chkprim is 0.' MSG_COMMENT(message) end if end if end subroutine chkprimit !!*** v_sim-3.8.0/lib/plug-ins/abinit/coeffs_gausslegint.F90000066400000000000000000000036521370110300500225370ustar00rootroot00000000000000!{\src2tex{textfont=tt}} !!****f* ABINIT/coeffs_gausslegint !! NAME !! coeffs_gausslegint !! !! FUNCTION !! Compute the coefficients (supports and weights) !! for Gauss-Legendre integration. !! Inspired by a routine due to G. Rybicki. !! !! COPYRIGHT !! Copyright (C) 2014-2016 ABINIT group (XG) !! This file is distributed under the terms of the !! GNU General Public License, see ~abinit/COPYING !! or http://www.gnu.org/copyleft/gpl.txt . !! !! INPUTS !! xmin=lower bound of integration !! xmax=upper bound of integration !! n=order of integration !! !! OUTPUT !! x(n)=array of support points !! weights(n)=array of integration weights !! !! PARENTS !! calc_rpa_functional,calc_sigc_me,integrho,integvol,m_numeric_tools !! screening,surf !! !! CHILDREN !! !! SOURCE #if defined HAVE_CONFIG_H #include "config.h" #endif #include "abi_common.h" subroutine coeffs_gausslegint(xmin,xmax,x,weights,n) use m_profiling_abi !This section has been created automatically by the script Abilint (TD). !Do not modify the following lines by hand. #undef ABI_FUNC #define ABI_FUNC 'coeffs_gausslegint' !End of the abilint section implicit none integer :: n,i,j double precision :: tol,xmin,xmax,x(n),weights(n) double precision :: z,z1,pi,xmean,p1,p2,p3,pp,xl tol=1.d-13 pi=4.d0*atan(1.d0) xl=(xmax-xmin)*0.5d0 xmean=(xmax+xmin)*0.5d0 do i=1,(n+1)/2 z=cos(pi*(i-0.25d0)/(n+0.5d0)) do p1=1.d0 p2=0.d0 do j=1,n p3=p2 p2=p1 p1=((2.d0*j - 1.d0)*z*p2 - (j-1.d0)*p3)/j enddo pp=n*(p2-z*p1)/(1.0d0-z**2) z1=z z=z1-p1/pp if(abs(z-z1) < tol) exit enddo x(i)=xmean-xl*z x(n+1-i)=xmean+xl*z weights(i)=2.d0*xl/((1.d0-z**2)*pp**2) weights(n+1-i)=weights(i) enddo end subroutine !!*** v_sim-3.8.0/lib/plug-ins/abinit/defs_basis.F90000066400000000000000000000504051370110300500207650ustar00rootroot00000000000000!{\src2tex{textfont=tt}} !!****m* ABINIT/defs_basis !! NAME !! defs_basis !! !! FUNCTION !! This module contains definitions for a number of named constants and !! physical constants, as well as associated datatypes and methods. !! !! COPYRIGHT !! Copyright (C) 2000-2016 ABINIT group (HM, XG,XW, EB) !! This file is distributed under the terms of the !! GNU General Public License, see ~abinit/COPYING !! or http://www.gnu.org/copyleft/gpl.txt . !! !! NOTES !! Of the named constants, !! by far the most important are those that define the 'kind' types of !! virtually all the variables used in a (well-written) FORTRAN 90 code !! the content of this file is derived from 'Numerical Recipes in Fortran 90' !! W.H. Press et al., volume 2 of 'Fortran Numerical Recipes', Cambridge !! University Press, Second Edition (1996), p. 937 and 1361 !! !! SOURCE #if defined HAVE_CONFIG_H #include "config.h" #endif module defs_basis implicit none !Keyword 'integer' stands for default integer type !and may be used whenever integer are presumed to be small !nb of bytes related to an integer subtype n such as -10^(argument) < n < 10^(argument) (this is standard F90) integer, parameter :: i1b=selected_int_kind(2) integer, parameter :: i2b=selected_int_kind(4) integer, parameter :: i4b=selected_int_kind(9) integer, parameter :: i8b=selected_int_kind(18) !nb of bytes related to default simple-precision real/complex subtypes !(= 4 for many machine architectures, = 8 for e.g. Cray) integer, parameter :: sp=kind(1.0) ! Single precision should not be used integer, parameter :: spc=kind((1.0,1.0)) !nb of bytes related to default double-precision real/complex subtypes !(= 8 for many machine architectures) integer, parameter :: dp=kind(1.0d0) integer, parameter :: dpc=kind((1.0_dp,1.0_dp)) ! Complex should not be used presently ! except for use of libraries !nb of bytes related to GW arrays, that can be tuned from sp to dp independently !of other variables in ABINIT. Presently double-precision is the default. #if defined HAVE_GW_DPC integer, parameter :: gwp=kind(1.0d0) integer, parameter :: gwpc=kind((1.0_dp,1.0_dp)) #else integer, parameter :: gwp=kind(1.0) integer, parameter :: gwpc=kind((1.0,1.0)) #endif !Example: ! integer, parameter :: urp=selected_real_kind((p=)12,(r=)50) ! real((kind=)urp) :: d ! d=5.04876_urp ! for a real d with 12 significative digits ! and such as 10^-50 < |d| < 10^50 !To modify sp/spc and / or dp/dpc, insert instructions such as 'dp=' ! but do not modify the other declarations in this module !The default lengths integer, parameter :: fnlen=264 ! maximum length of file name variables integer, parameter :: strlen=2000000 ! maximum length of input string integer, parameter :: md5_slen = 32 ! lenght of strings storing the pseudos' md5 checksum. character(len=md5_slen),parameter :: md5_none = "None" !Some constants: ! UNIX unit numbers: standard input, standard output, ab_out, and a number for temporary access to a file. ! Please, use these named constants instead of write(*,*), ! it makes the code more readable and easier to change. !Default values integer, parameter :: std_in=5,ab_in=5 integer, parameter :: std_out_default=6,ab_out_default=7 integer, parameter :: std_err=0 integer, parameter :: dev_null=-1 ! Fake unit number used to skip the printing in wrtout. integer, parameter :: ab_xml_out = 50 ! this unit is used to print output into an XML file integer, parameter :: tmp_unit=9,tmp_unit2=10 !These vars should be private and only modifiable via an appropriate method (see below) integer, public, save :: ab_out = ab_out_default integer, public, save :: std_out = std_out_default !It should be put to xmpi_world (but it is not possible for the moment - v6.9) integer, public, save :: abinit_comm_output = -1 !This default value has to be changed at start !!! ! the maximum length of a record in a file connected for sequential access. integer,public,parameter :: ABI_RECL=524288 ! 2**19 !Real constants real(dp), parameter :: zero=0._dp real(dp), parameter :: one=1._dp real(dp), parameter :: two=2._dp real(dp), parameter :: three=3._dp real(dp), parameter :: four=4._dp real(dp), parameter :: five=5._dp real(dp), parameter :: six=6._dp real(dp), parameter :: seven=7._dp real(dp), parameter :: eight=8._dp real(dp), parameter :: nine=9._dp real(dp), parameter :: ten=10._dp !Fractionary real constants real(dp), parameter :: half=0.50_dp real(dp), parameter :: onehalf=1.50_dp real(dp), parameter :: third=one/three real(dp), parameter :: quarter=0.25_dp real(dp), parameter :: fifth=0.20_dp real(dp), parameter :: sixth=one/six real(dp), parameter :: seventh=one/seven real(dp), parameter :: eighth=0.125_dp real(dp), parameter :: ninth=one/nine real(dp), parameter :: two_thirds=two*third real(dp), parameter :: four_thirds=four*third real(dp), parameter :: five_thirds=five*third real(dp), parameter :: three_quarters=0.75_dp real(dp), parameter :: three_fifth=three/five !Real constants related to the golden number real(dp), parameter :: gold=1.618033988749894848204586834365638117720309179_dp real(dp), parameter :: goldenratio=two-gold !Real constants derived from pi real(dp), parameter :: pi=3.141592653589793238462643383279502884197_dp real(dp), parameter :: two_pi=two*pi real(dp), parameter :: four_pi=four*pi real(dp), parameter :: piinv=one/pi !The following are not used !real(dp), parameter :: rad_to_deg=180._dp/pi !real(dp), parameter :: deg_to_rad=one/rad_to_deg !real(dp), parameter :: half_pi=pi*half !real(dp), parameter :: third_pi=pi*third !real(dp), parameter :: quarter_pi=pi*quarter !real(dp), parameter :: two_thirds_pi=two_thirds*pi !Real precision real(dp), parameter :: greatest_real = huge(one) real(dp), parameter :: smallest_real = -greatest_real !real(dp), parameter :: tol1= 0.1_dp !real(dp), parameter :: tol2= 0.01_dp real(dp), parameter :: tol3= 0.001_dp real(dp), parameter :: tol4= 0.0001_dp real(dp), parameter :: tol5= 0.00001_dp real(dp), parameter :: tol6= 0.000001_dp real(dp), parameter :: tol7= 0.0000001_dp real(dp), parameter :: tol8= 0.00000001_dp real(dp), parameter :: tol9= 0.000000001_dp real(dp), parameter :: tol10=0.0000000001_dp real(dp), parameter :: tol11=0.00000000001_dp real(dp), parameter :: tol12=0.000000000001_dp real(dp), parameter :: tol13=0.0000000000001_dp real(dp), parameter :: tol14=0.00000000000001_dp real(dp), parameter :: tol15=0.000000000000001_dp real(dp), parameter :: tol16=0.0000000000000001_dp real(dp), parameter :: tol20=0.00000000000000000001_dp !real constants derived from sqrt(n.) real(dp), parameter :: sqrt2=1.4142135623730950488016887242096939_dp real(dp), parameter :: half_sqrt2=0.70710678118654752440084436210484697_dp real(dp), parameter :: sqrt3=1.7320508075688772935274463415058739_dp real(dp), parameter :: half_sqrt3=0.86602540378443864676372317075293693_dp real(dp), parameter :: sqrthalf=0.70710678118654752440084436210484697_dp !Conversion factors of common use, not directly related to physical quantities. real(dp), parameter :: b2Mb=one/1024.0_dp**2 ! conversion factor bytes --> Mbytes real(dp), parameter :: b2Gb=b2Mb/1024.0_dp ! conversion factor bytes --> Gbytes !Real physical constants !Revised fundamental constants from http://physics.nist.gov/cuu/Constants/index.html !(from 2006 least squares adjustment) real(dp), parameter :: Bohr_Ang=0.52917720859_dp ! 1 Bohr, in Angstrom real(dp), parameter :: Ha_cmm1=219474.6313705_dp ! 1 Hartree, in cm^-1 real(dp), parameter :: Ha_eV=27.21138386_dp ! 1 Hartree, in eV real(dp), parameter :: eV_Ha=one/Ha_eV ! 1 eV in Hartree real(dp), parameter :: Ha_meV=Ha_eV*1000_dp ! 1 Hartree, in meV real(dp), parameter :: Ha_K=315774.65_dp ! 1Hartree, in Kelvin real(dp), parameter :: Ha_THz=6579.683920722_dp ! 1 Hartree, in THz real(dp), parameter :: Ha_J=4.35974394d-18 !1 Hartree, in J real(dp), parameter :: e_Cb=1.602176487d-19 ! minus the electron charge, in Coulomb real(dp), parameter :: kb_HaK=8.617343d-5/Ha_eV ! Boltzmann constant in Ha/K real(dp), parameter :: amu_emass=1.660538782d-27/9.10938215d-31 ! 1 atomic mass unit, in electronic mass real(dp), parameter :: HaBohr3_GPa=Ha_eV/Bohr_Ang**3*e_Cb*1.0d+21 ! 1 Ha/Bohr^3, in GPa real(dp), parameter :: Avogadro=6.02214179d23 ! per mole real(dp), parameter :: Ohmcm=two*pi*Ha_THz*ninth*ten ! 1 Ohm.cm in atomic units !real(dp), parameter :: eps0=8.854187817d-12 ! permittivity of free space in F/m real(dp), parameter :: eps0=one/(four_pi*0.0000001_dp*299792458.0_dp**2) real(dp), parameter :: AmuBohr2_Cm2=e_Cb*1.0d20/(Bohr_Ang*Bohr_Ang) real(dp), parameter :: InvFineStruct=137.035999679_dp ! Inverse of fine structure constant real(dp), parameter :: Sp_Lt_SI=2.99792458d8 ! speed of light in SI real(dp), parameter :: Sp_Lt=Sp_lt_SI/2.1876912633d6 ! speed of light in atomic units real(dp), parameter :: Time_Sec=2.418884326505D-17 ! Atomic unit of time, in seconds real(dp), parameter :: BField_Tesla=4.254383d-6 ! Tesla in a.u. real(dp), parameter :: dipole_moment_debye=0.393430307_dp ! Debye unit in a.u. !EB suppress *0.5_dp ! Atomic unit of induction field (in Tesla) * mu_B (in atomic units). !Complex constants complex(dpc), parameter :: czero=(0._dp,0._dp) complex(dpc), parameter :: cone =(1._dp,0._dp) complex(dpc) ,parameter :: j_dpc=(0._dp,1.0_dp) !Character constants character(len=1), parameter :: ch10 = char(10) character(len=fnlen),parameter :: ABI_NOFILE="__None__" ! File used to dump the error message in m_error. ! Extremely useful when we run on many CPUs since logging, in this case, is automatically disabled ! As a consequence, we get error messages in the main log only if the problem is encoutered by the master node! ! Note that the file is removed in xmpi_init (if present). character(len=fnlen),parameter :: ABI_MPIABORTFILE="__ABI_MPIABORTFILE__" ! Error codes used by the bindings. integer, parameter, public :: AB7_NO_ERROR = 0 integer, parameter, public :: AB7_ERROR_OBJ = 1 integer, parameter, public :: AB7_ERROR_ARG = 2 integer, parameter, public :: AB7_ERROR_INVARS_ATT = 3 integer, parameter, public :: AB7_ERROR_INVARS_ID = 4 integer, parameter, public :: AB7_ERROR_INVARS_SIZE = 5 integer, parameter, public :: AB7_ERROR_SYM_NOT_PRIMITIVE = 6 integer, parameter, public :: AB7_ERROR_SYM_BRAVAIS_XRED = 7 integer, parameter, public :: AB7_ERROR_MIXING_ARG = 8 integer, parameter, public :: AB7_ERROR_MIXING_CONVERGENCE = 9 integer, parameter, public :: AB7_ERROR_MIXING_INTERNAL = 10 integer, parameter, public :: AB7_ERROR_MIXING_INC_NNSLOOP = 11 ! Values of optdriver corresponding to the different run-levels. integer, parameter, public :: RUNL_GSTATE = 0 integer, parameter, public :: RUNL_RESPFN = 1 integer, parameter, public :: RUNL_SCREENING = 3 integer, parameter, public :: RUNL_SIGMA = 4 integer, parameter, public :: RUNL_NONLINEAR = 5 integer, parameter, public :: RUNL_EPH = 7 integer, parameter, public :: RUNL_WFK = 8 integer, parameter, public :: RUNL_GWLS = 66 integer, parameter, public :: RUNL_BSE = 99 !9 ! Integer flags defining the task to be performed in wfk_analyze integer,public,parameter :: WFK_TASK_NONE = 0 integer,public,parameter :: WFK_TASK_FULLBZ = 1 integer,public,parameter :: WFK_TASK_CLASSIFY = 2 integer,public,parameter :: WFK_TASK_PAW_AEPSI = 3 integer,public,parameter :: WFK_TASK_SHIRLEY = 4 ! Flags defining the method used for performing IO (input variable iomode) integer, parameter, public :: IO_MODE_FORTRAN_MASTER = -1 integer, parameter, public :: IO_MODE_FORTRAN = 0 integer, parameter, public :: IO_MODE_MPI = 1 integer, parameter, public :: IO_MODE_NETCDF = 2 ! Only for legacy code, should not be used for new implementations. integer, parameter, public :: IO_MODE_ETSF = 3 ! FFT libraries (correspond to fftalga = ngfft(7)/100) integer,parameter,public :: FFT_SG = 1 integer,parameter,public :: FFT_FFTW3 = 3 integer,parameter,public :: FFT_SG2002 = 4 integer,parameter,public :: FFT_DFTI = 5 ! Parameters for non-local algorithm (were previously stored in nloalg(3) and nloalg(4) integer,parameter,public :: NLO_MBLKPW = 199 integer,parameter,public :: NLO_MINCAT = 10 !Parameters for LOG/STATUS files treatment !This variables tell the code if some lines have to be written in a LOG/STATUS file logical, public, save :: do_write_log =.true. logical, public, save :: do_write_status=.true. ! Max. numbers of CPU core for the writing of LOG/STATUS file for each CPU ! (if more than NPROC_NO_EXTRA_LOG cpu core are used, no *_LOG_Pxxx is written; ! the same for the *_STATUS_Pxxx file) integer, parameter, public :: NPROC_NO_EXTRA_LOG = 2 !@WC integer, parameter, public :: NPROC_NO_EXTRA_STATUS = 2 !@WC !Name of the file that (if present in current directory) !will avoid creation of LOG/STATUS files character(len=fnlen),parameter :: ABI_NO_LOG_FILE="_NOLOG" !Name of the file that (if present in current directory) !will enforce creation of LOG/STATUS files character(len=fnlen),parameter :: ABI_ENFORCE_LOG_FILE="_LOG" !Name of the file that (if present in current directory) !will enforce creation of LOG file only for master proc character(len=fnlen),parameter :: ABI_MAIN_LOG_FILE="_MAINLOG" ! Arrays integer,parameter :: identity_3d(3,3)=reshape([1,0,0,0,1,0,0,0,1], [3,3]) !A collection of small datatypes for ragged arrays !A small datatype for ragged real 1D-arrays type coeff1_type real(dp), allocatable :: value(:) end type coeff1_type !A small datatype for ragged integer 1D-arrays type coeffi1_type !integer :: size integer, allocatable :: value(:) end type coeffi1_type !A small datatype for ragged integer 2D-arrays type coeffi2_type integer :: size integer, allocatable :: value(:,:) end type coeffi2_type !A small datatype for ragged real 2D-arrays type coeff2_type real(dp), allocatable :: value(:,:) end type coeff2_type !A small datatype for ragged complex 2D-arrays type coeff2c_type complex(dpc), allocatable :: value(:,:) end type coeff2c_type !A small datatype for ragged real 3D-arrays type coeff3_type real(dp), allocatable :: value(:,:,:) end type coeff3_type !A small datatype for ragged real 4D-arrays type coeff4_type real(dp), allocatable :: value(:,:,:,:) end type coeff4_type !A small datatype for ragged real 5D-arrays type coeff5_type real(dp), allocatable :: value(:,:,:,:,:) end type coeff5_type !A small datatype for ragged real 6D-arrays type coeff6_type real(dp), allocatable :: value(:,:,:,:,:,:) end type coeff6_type !A small datatype for ragged real 7D-arrays. type coeff7_type real(dp), allocatable :: value(:,:,:,:,:,:,:) end type coeff7_type CONTAINS !============================================================================== !!*** !!****f* defs_basis/abi_log_status_state !! NAME !! abi_log_status_state !! !! FUNCTION !! Change values of do_write_log and do_write_status flags. !! These flags tell the code to write (or not) a LOG/STATUS file. !! !! INPUTS !! new_do_write_log=new value for do_write_log !! new_do_write_status=new value for do_write_status !! !! PARENTS !! iofn1,m_argparse !! !! CHILDREN !! !! SOURCE subroutine abi_log_status_state(new_do_write_log,new_do_write_status) !This section has been created automatically by the script Abilint (TD). !Do not modify the following lines by hand. #undef ABI_FUNC #define ABI_FUNC 'abi_log_status_state' !End of the abilint section implicit none !Arguments ------------------------------------ !scalars logical,optional,intent(in) :: new_do_write_log,new_do_write_status !Local variables ------------------------------ !************************************************************************ if (PRESENT(new_do_write_log)) do_write_log =new_do_write_log if (PRESENT(new_do_write_status)) do_write_status=new_do_write_status end subroutine abi_log_status_state !!*** !---------------------------------------------------------------------- !!****f* defs_basis/abi_io_redirect !! NAME !! abi_io_redirect !! !! FUNCTION !! Redirect unit numbers (and|or) change the MPI communicator for the IO (output and log file). !! This routine can be used in client code (e.g. bigdft) !! that wants to call the abinit routines packed in an external library. !! !! INPUTS !! new_ab_out=new value for output file unit !! new_std_out=new value for standard output unit !! new_io_comm=new value for IO MPI communicator !! !! PARENTS !! abinit,aim,anaddb,band2eps,bsepostproc,conducti,cut3d,driver,fftprof !! fold2Bloch,initmpi_world,ioprof,lapackprof,m_io_redirect,macroave !! memory_eval,mpi_setup,mrgddb,mrgdv,mrggkk,mrgscr,optic,ujdet !! vdw_kernelgen !! !! CHILDREN !! !! SOURCE subroutine abi_io_redirect(new_ab_out,new_std_out,new_io_comm) !This section has been created automatically by the script Abilint (TD). !Do not modify the following lines by hand. #undef ABI_FUNC #define ABI_FUNC 'abi_io_redirect' !End of the abilint section implicit none !Arguments ------------------------------------ !scalars integer,optional,intent(in) :: new_std_out,new_ab_out,new_io_comm !************************************************************************ if (PRESENT(new_ab_out)) ab_out = new_ab_out if (PRESENT(new_std_out)) std_out = new_std_out if (PRESENT(new_io_comm)) abinit_comm_output = new_io_comm end subroutine abi_io_redirect !!*** !---------------------------------------------------------------------- !!****f* defs_basis/print_kinds !! NAME !! print_kinds !! !! FUNCTION !! Prints info on the basic data types, e.g. kind, precision... !! !! INPUTS !! unit = Unit number for output file. !! !! OUTPUT !! Only printing. !! !! PARENTS !! abinit,leave_new,m_errors !! !! CHILDREN !! !! SOURCE subroutine print_kinds(unit) !Arguments------------------------------------- !scalars !This section has been created automatically by the script Abilint (TD). !Do not modify the following lines by hand. #undef ABI_FUNC #define ABI_FUNC 'print_kinds' !End of the abilint section integer,optional,intent(in) :: unit !Local variables------------------------------- !scalars integer :: my_unt ! ********************************************************************* my_unt=std_out; if (PRESENT(unit)) my_unt = unit write(my_unt,'(a)')' DATA TYPE INFORMATION: ' write(my_unt,'(a,/,2(a,i6,/),2(a,e15.8,/),a,e15.8)')& & ' REAL: Data type name: REAL(DP) ',& & ' Kind value: ',KIND(0.0_dp),& & ' Precision: ',PRECISION(0.0_dp),& & ' Smallest nonnegligible quantity relative to 1: ',EPSILON(0.0_dp),& & ' Smallest positive number: ',TINY(0.0_dp),& & ' Largest representable number: ',HUGE(0.0_dp) write(my_unt,'(a,/,2(a,i0,/),a,i0)')& ' INTEGER: Data type name: INTEGER(default) ', & & ' Kind value: ',KIND(0), & & ' Bit size: ',BIT_SIZE(0), & ' Largest representable number: ',HUGE(0) write(my_unt,'(a,/,a,i0)')& & ' LOGICAL: Data type name: LOGICAL ',& & ' Kind value: ',KIND(.TRUE.) write(my_unt,'(2a,i0)')& & ' CHARACTER: Data type name: CHARACTER ',& & ' Kind value: ',KIND('C') end subroutine print_kinds !!*** !!****f* defs_basis/str2wfktask !! NAME !! str2wfktask !! !! FUNCTION !! Convert a string into one of the integer flags WFK_TASK_* !! Return WFK_TASK_NONE if string is invalid. !! !! PARENTS !! !! CHILDREN !! !! SOURCE integer pure function str2wfktask(str) result(wfk_task) !This section has been created automatically by the script Abilint (TD). !Do not modify the following lines by hand. #undef ABI_FUNC #define ABI_FUNC 'str2wfktask' !End of the abilint section implicit none !Arguments ------------------------------------ !scalars character(len=*),intent(in) :: str !************************************************************************ select case (str) case ("wfk_fullbz") wfk_task = WFK_TASK_FULLBZ case ("classify") wfk_task = WFK_TASK_CLASSIFY case ("paw_aepsi") wfk_task = WFK_TASK_PAW_AEPSI case ("shirley") wfk_task = WFK_TASK_SHIRLEY case default wfk_task = WFK_TASK_NONE end select end function str2wfktask !!*** !---------------------------------------------------------------------- end module defs_basis !!*** v_sim-3.8.0/lib/plug-ins/abinit/getptgroupma.F90000066400000000000000000000107001370110300500213730ustar00rootroot00000000000000!{\src2tex{textfont=tt}} !!****f* ABINIT/getptgroupma !! NAME !! getptgroupma !! !! FUNCTION !! Return magnetic point group number from the full point group number !! and the point group number of the non-magnetic symmetry operations. !! The (normal) point group numbers are taken from !! The International Tables for Crystallography !! Volume A, 1983 Ed. Theo Hahn, D. Reidel Publishing Company !! The magnetic point group number are taken from !! The mathematical theory of symmetry in solids, Representation theory for point !! groups and space groups, 1972, C.J. Bradley and A.P. !! Cracknell, Clarendon Press, Oxford. !! In particular, see table 7.1 of the latter reference !! !! COPYRIGHT !! Copyright (C) 2002-2016 ABINIT group (XG) !! This file is distributed under the terms of the !! GNU General Public License, see ~abinit/COPYING !! or http://www.gnu.org/copyleft/gpl.txt . !! For the initials of contributors, see ~abinit/doc/developers/contributors.txt . !! !! INPUTS !! ptgroup = character(len=5) point group of all the symmetry operation !! ptgroupha = character(len=5) point group of the non-magnetic symmetry operation (halved point group) !! !! OUTPUT !! ptgroupma = magnetic point group number !! !! NOTES !! !! PARENTS !! symanal !! !! CHILDREN !! !! SOURCE #if defined HAVE_CONFIG_H #include "config.h" #endif #include "abi_common.h" subroutine getptgroupma(ptgroup,ptgroupha,ptgroupma) use defs_basis use m_profiling_abi !This section has been created automatically by the script Abilint (TD). !Do not modify the following lines by hand. #undef ABI_FUNC #define ABI_FUNC 'getptgroupma' !End of the abilint section implicit none !Arguments ------------------------------------ !scalars integer,intent(out) :: ptgroupma character(len=5),intent(in) :: ptgroup,ptgroupha ! ************************************************************************* !DEBUG !write(std_out,*)' getptgroupma : enter ' !write(std_out,*)' ptgroup="',ptgroup,'"' !write(std_out,*)' ptgroupha="',ptgroupha,'"' !ENDDEBUG ptgroupma=0 select case (ptgroup) case(" -1") ptgroupma=1 case(" 2") ptgroupma=2 case(" -2") ptgroupma=3 case(" 2/m") if(ptgroupha==" 2")ptgroupma=4 if(ptgroupha==" -2")ptgroupma=5 if(ptgroupha==" -1")ptgroupma=6 case(" 222") ptgroupma=7 case(" mm2") if(ptgroupha==" 2")ptgroupma=8 if(ptgroupha==" -2")ptgroupma=9 case(" mmm") if(ptgroupha==" 222")ptgroupma=10 if(ptgroupha==" mm2")ptgroupma=11 if(ptgroupha==" 2/m")ptgroupma=12 case(" 4") ptgroupma=13 case(" -4") ptgroupma=14 case(" 422") if(ptgroupha==" 4")ptgroupma=15 if(ptgroupha==" 222")ptgroupma=16 case(" 4/m") if(ptgroupha==" 4")ptgroupma=17 if(ptgroupha==" -4")ptgroupma=18 if(ptgroupha==" 2/m")ptgroupma=19 case(" 4mm") if(ptgroupha==" 4")ptgroupma=20 if(ptgroupha==" mm2")ptgroupma=21 case(" -42m") if(ptgroupha==" -4")ptgroupma=22 if(ptgroupha==" 222")ptgroupma=23 if(ptgroupha==" mm2")ptgroupma=24 case("4/mmm") if(ptgroupha==" 422")ptgroupma=25 if(ptgroupha==" 4mm")ptgroupma=26 if(ptgroupha==" mmm")ptgroupma=27 if(ptgroupha==" -42m")ptgroupma=28 if(ptgroupha==" 4/m")ptgroupma=29 case(" 32") ptgroupma=30 case(" 3m") ptgroupma=31 case(" -6") ptgroupma=32 case(" -62m") if(ptgroupha==" -6")ptgroupma=33 if(ptgroupha==" 3m")ptgroupma=34 if(ptgroupha==" 32")ptgroupma=35 case(" 6") ptgroupma=36 case(" -3") ptgroupma=37 case(" -3m") if(ptgroupha==" -3")ptgroupma=38 if(ptgroupha==" 3m")ptgroupma=39 if(ptgroupha==" 32")ptgroupma=40 case(" 622") if(ptgroupha==" 6")ptgroupma=41 if(ptgroupha==" 32")ptgroupma=42 case(" 6/m") if(ptgroupha==" 6")ptgroupma=43 if(ptgroupha==" -3")ptgroupma=44 if(ptgroupha==" -6")ptgroupma=45 case(" 6mm") if(ptgroupha==" 6")ptgroupma=46 if(ptgroupha==" 3m")ptgroupma=47 case("6/mmm") if(ptgroupha==" -62m")ptgroupma=48 if(ptgroupha==" -3m")ptgroupma=49 if(ptgroupha==" 622")ptgroupma=50 if(ptgroupha==" 6mm")ptgroupma=51 if(ptgroupha==" 6/m")ptgroupma=52 case(" m-3") ptgroupma=53 case(" -43m") ptgroupma=54 case(" 432") ptgroupma=55 case(" m-3m") if(ptgroupha==" 432")ptgroupma=56 if(ptgroupha==" -43m")ptgroupma=57 if(ptgroupha==" m-3")ptgroupma=58 end select !DEBUG !write(std_out,*)' getptgroupma : exit ' !write(std_out,*)' ptgroupma="',ptgroupma,'"' !ENDDEBUG end subroutine getptgroupma !!*** v_sim-3.8.0/lib/plug-ins/abinit/holocell.F90000066400000000000000000000204341370110300500204630ustar00rootroot00000000000000!{\src2tex{textfont=tt}} !!****f* ABINIT/holocell !! NAME !! holocell !! !! FUNCTION !! Examine whether the trial conventional cell described by cell_base !! is coherent with the required holohedral group. !! Possibly enforce the holohedry and modify the basis vectors. !! Note : for iholohedry=4, the tetragonal axis is not required to be !! along the C axis. !! !! COPYRIGHT !! Copyright (C) 2000-2016 ABINIT group (XG). !! This file is distributed under the terms of the !! GNU General Public License, see ~abinit/COPYING !! or http://www.gnu.org/copyleft/gpl.txt . !! For the initials of contributors, see ~abinit/doc/developers/contributors.txt . !! !! INPUTS !! enforce= if 0, only check; if =1, enforce exactly the holohedry !! iholohedry=required holohegral group !! iholohedry=1 triclinic 1bar !! iholohedry=2 monoclinic 2/m !! iholohedry=3 orthorhombic mmm !! iholohedry=4 tetragonal 4/mmm !! iholohedry=5 trigonal 3bar m !! iholohedry=6 hexagonal 6/mmm !! iholohedry=7 cubic m3bar m !! tolsym=tolerance for the symmetry operations !! !! OUTPUT !! foundc=1 if the basis vectors supports the required holohedry ; =0 otherwise !! !! SIDE EFFECTS !! cell_base(3,3)=basis vectors of the conventional cell (changed if enforce==1, otherwise unchanged) !! !! PARENTS !! symlatt,symmetrize_rprimd !! !! CHILDREN !! !! SOURCE #if defined HAVE_CONFIG_H #include "config.h" #endif #include "abi_common.h" subroutine holocell(cell_base,enforce,foundc,iholohedry,tolsym) use defs_basis use m_errors use m_profiling_abi !This section has been created automatically by the script Abilint (TD). !Do not modify the following lines by hand. #undef ABI_FUNC #define ABI_FUNC 'holocell' !End of the abilint section implicit none !Arguments ------------------------------------ !scalars integer,intent(in) :: enforce,iholohedry integer,intent(out) :: foundc real(dp),intent(in) :: tolsym !arrays real(dp),intent(inout) :: cell_base(3,3) !Local variables ------------------------------ !scalars integer :: allequal,ii,jj,orth real(dp):: aa,reldiff,scprod1 character(len=500) :: msg !arrays integer :: ang90(3),equal(3) real(dp) :: length(3),metric(3,3),norm(3),rbasis(3,3),rconv(3,3),rconv_new(3,3) real(dp) :: rnormalized(3,3),symmetrized_length(3) !************************************************************************** do ii=1,3 metric(:,ii)=cell_base(1,:)*cell_base(1,ii)+& & cell_base(2,:)*cell_base(2,ii)+& & cell_base(3,:)*cell_base(3,ii) end do !Examine the angles and vector lengths ang90(:)=0 if(metric(1,2)**2two*tolsym)then write(msg,'(a,6(2a,3es14.6))')& & 'Failed rectification of lattice vectors to comply with Bravais lattice identification, modifs are too large',ch10,& & ' rconv =',rconv(:,1),ch10,& & ' ',rconv(:,2),ch10,& & ' ',rconv(:,3),ch10,& & ' rconv_new=',rconv_new(:,1),ch10,& & ' ',rconv_new(:,2),ch10,& & ' ',rconv_new(:,3) MSG_ERROR_CLASS(msg, "TolSymError") end if end do end do ! Copy back the cell_base vectors if(iholohedry==4.and.equal(1)==1)then cell_base(:,3)=rconv_new(:,2) ; cell_base(:,2)=rconv_new(:,1) ; cell_base(:,1)=rconv_new(:,3) else if (iholohedry==4.and.equal(2)==1)then cell_base(:,3)=rconv_new(:,1) ; cell_base(:,1)=rconv_new(:,2) ; cell_base(:,2)=rconv_new(:,3) else cell_base(:,:)=rconv_new(:,:) end if end if end subroutine holocell !!*** v_sim-3.8.0/lib/plug-ins/abinit/interfaces_14_hidewrite.F90000066400000000000000000000022301370110300500233470ustar00rootroot00000000000000!!****m* ABINIT/interfaces_14_hidewrite !! NAME !! interfaces_14_hidewrite !! !! FUNCTION !! This module contains the interfaces of the routines !! in the directory src/14_hidewrite !! !! COPYRIGHT !! Copyright (C) 2010-2016 ABINIT group !! This file is distributed under the terms of the !! GNU General Public License, see ~abinit/COPYING !! or http://www.gnu.org/copyleft/gpl.txt . !! !! NOTES !! THIS FILE IS GENERATED AUTOMATICALLY BY abilint. !! To do that: config/scripts/abilint . . !! !! !! SOURCE #if defined HAVE_CONFIG_H #include "config.h" #endif module interfaces_14_hidewrite implicit none interface subroutine wrtout(unit,msg,mode_paral,do_flush) implicit none integer,intent(in) :: unit logical,optional,intent(in) :: do_flush character(len=*),optional,intent(in) :: mode_paral character(len=*),intent(in) :: msg end subroutine wrtout end interface interface subroutine wrtout_myproc(unit,message,do_flush) ! optional argument implicit none integer,intent(in) :: unit logical,optional,intent(in) :: do_flush character(len=*),intent(in) :: message end subroutine wrtout_myproc end interface end module interfaces_14_hidewrite !!*** v_sim-3.8.0/lib/plug-ins/abinit/interfaces_16_hideleave.F90000066400000000000000000000016171370110300500233230ustar00rootroot00000000000000!!****m* ABINIT/interfaces_16_hideleave !! NAME !! interfaces_16_hideleave !! !! FUNCTION !! This module contains the interfaces of the routines !! in the directory src/16_hideleave !! !! COPYRIGHT !! Copyright (C) 2010-2016 ABINIT group !! This file is distributed under the terms of the !! GNU General Public License, see ~abinit/COPYING !! or http://www.gnu.org/copyleft/gpl.txt . !! !! NOTES !! THIS FILE IS GENERATED AUTOMATICALLY BY abilint. !! To do that: config/scripts/abilint . . !! !! !! SOURCE #if defined HAVE_CONFIG_H #include "config.h" #endif module interfaces_16_hideleave implicit none interface subroutine leave_new(mode_paral,exit_status,print_config) implicit none integer,intent(in),optional :: exit_status character(len=4),intent(in) :: mode_paral logical,intent(in),optional :: print_config end subroutine leave_new end interface end module interfaces_16_hideleave !!*** v_sim-3.8.0/lib/plug-ins/abinit/interfaces_28_numeric_noabirule.F90000066400000000000000000000355251370110300500251070ustar00rootroot00000000000000!!****m* ABINIT/interfaces_28_numeric_noabirule !! NAME !! interfaces_28_numeric_noabirule !! !! FUNCTION !! This module contains the interfaces of the routines !! in the directory src/28_numeric_noabirule !! !! COPYRIGHT !! Copyright (C) 2010-2016 ABINIT group !! This file is distributed under the terms of the !! GNU General Public License, see ~abinit/COPYING !! or http://www.gnu.org/copyleft/gpl.txt . !! !! NOTES !! THIS FILE IS GENERATED AUTOMATICALLY BY abilint. !! To do that: config/scripts/abilint . . !! !! !! SOURCE #if defined HAVE_CONFIG_H #include "config.h" #endif module interfaces_28_numeric_noabirule implicit none interface subroutine coeffs_gausslegint(xmin,xmax,x,weights,n) implicit none integer :: n double precision :: xmax double precision :: xmin double precision :: weights(n) double precision :: x(n) end subroutine coeffs_gausslegint end interface interface subroutine cspint ( ftab, xtab, ntab, a, b, y, e, work, result ) use defs_basis implicit none integer, intent(in) :: ntab real(dp), intent(in) :: a real(dp), intent(in) :: b real(dp), intent(out) :: result real(dp), intent(inout) :: e(ntab) real(dp), intent(in) :: ftab(ntab) real(dp), intent(inout) :: work(ntab) real(dp), intent(in) :: xtab(ntab) real(dp), intent(inout) :: y(3,ntab) end subroutine cspint end interface interface subroutine dzgedi(a,lda,n,ipvt,det,work,job) implicit none integer :: job integer :: lda integer :: n real*8 :: det(2,2) real*8 :: a(2,lda,n) integer :: ipvt(n) real*8 :: work(2,n) end subroutine dzgedi end interface interface subroutine dzgefa(a,lda,n,ipvt,info) implicit none integer :: info integer :: lda integer :: n real*8 :: a(2,lda,n) integer :: ipvt(n) end subroutine dzgefa end interface interface subroutine GAMMA_FUNCTION(X,GA) use defs_basis implicit none real(dp),intent(out) :: ga real(dp),intent(in) :: x end subroutine GAMMA_FUNCTION end interface interface function interp(n,z,f,z0,zz) use defs_basis implicit none integer :: n complex(gwpc) :: interp complex(gwpc) :: z0 complex(gwpc) :: zz complex(gwpc) :: f(n) complex(gwpc) :: z(n) end function interp end interface interface function dinterp(n,z,f,z0,zz) use defs_basis implicit none integer :: n complex(gwpc) :: dinterp complex(gwpc) :: z0 complex(gwpc) :: zz complex(gwpc) :: f(n) complex(gwpc) :: z(n) end function dinterp end interface interface function taylor_interp(n,z,f,z0,zz) use defs_basis implicit none integer :: n complex(gwpc) :: taylor_interp complex(gwpc) :: z0 complex(gwpc) :: zz complex(gwpc) :: f(n) complex(gwpc) :: z(n) end function taylor_interp end interface interface function dtaylor_interp(n,z,f,z0,zz) use defs_basis implicit none integer :: n complex(gwpc) :: dtaylor_interp complex(gwpc) :: z0 complex(gwpc) :: zz complex(gwpc) :: f(n) complex(gwpc) :: z(n) end function dtaylor_interp end interface interface subroutine calculate_taylor_c(n,z,f,z0,c) use defs_basis implicit none integer :: n complex(gwpc) :: z0 complex(gwpc) :: c(n) complex(gwpc) :: f(n) complex(gwpc) :: z(n) end subroutine calculate_taylor_c end interface interface SUBROUTINE INTRPL(L,X,Y,N,U,V,dv,dv2,ideriv) implicit none integer, parameter :: NQQ=12000 integer :: L integer :: N integer :: ideriv double precision :: DV(NQQ) double precision :: DV2(NQQ) double precision :: U(N) double precision :: V(N) double precision :: X(L) double precision :: Y(L) end subroutine INTRPL end interface interface SUBROUTINE CALJY0(ARG,RESULT,JINT) implicit none integer :: JINT double precision :: ARG double precision :: RESULT end subroutine CALJY0 end interface interface DOUBLE PRECISION FUNCTION BESJ0(X) implicit none double precision :: X end function BESJ0 end interface interface DOUBLE PRECISION FUNCTION BESY0(X) implicit none double precision :: X end function BESY0 end interface interface SUBROUTINE CALJY1(ARG,RESULT,JINT) implicit none integer :: JINT double precision :: ARG double precision :: RESULT end subroutine CALJY1 end interface interface DOUBLE PRECISION FUNCTION BESJ1(X) implicit none double precision :: X end function BESJ1 end interface interface DOUBLE PRECISION FUNCTION BESY1(X) implicit none double precision :: X end function BESY1 end interface interface subroutine jacobi(a,n,np,d,v,nrot) implicit none integer :: n integer :: np integer :: nrot real*8 :: a(np,np) real*8 :: d(np) real*8 :: v(np,np) end subroutine jacobi end interface interface SUBROUTINE CALCK0(ARG,RESULT,JINT) implicit none integer :: JINT double precision :: ARG double precision :: RESULT end subroutine CALCK0 end interface interface DOUBLE PRECISION FUNCTION BESK0(X) implicit none double precision :: X end function BESK0 end interface interface DOUBLE PRECISION FUNCTION BESEK0(X) implicit none double precision :: X end function BESEK0 end interface interface SUBROUTINE CALCK1(ARG,RESULT,JINT) implicit none integer :: JINT double precision :: ARG double precision :: RESULT end subroutine CALCK1 end interface interface DOUBLE PRECISION FUNCTION BESK1(X) implicit none double precision :: X end function BESK1 end interface interface DOUBLE PRECISION FUNCTION BESEK1(X) implicit none double precision :: X end function BESEK1 end interface interface subroutine gen_oh(code, num, x, y, z, w, a, b, v) implicit none integer :: code integer :: num double precision :: a double precision :: b double precision :: v double precision :: w(*) double precision :: x(*) double precision :: y(*) double precision :: z(*) end subroutine gen_oh end interface interface SUBROUTINE LD0006(X,Y,Z,W,N) implicit none integer :: N double precision :: W( 6) double precision :: X( 6) double precision :: Y( 6) double precision :: Z( 6) end subroutine LD0006 end interface interface SUBROUTINE LD0014(X,Y,Z,W,N) implicit none integer :: N double precision :: W( 14) double precision :: X( 14) double precision :: Y( 14) double precision :: Z( 14) end subroutine LD0014 end interface interface SUBROUTINE LD0026(X,Y,Z,W,N) implicit none integer :: N double precision :: W( 26) double precision :: X( 26) double precision :: Y( 26) double precision :: Z( 26) end subroutine LD0026 end interface interface SUBROUTINE LD0038(X,Y,Z,W,N) implicit none integer :: N double precision :: W( 38) double precision :: X( 38) double precision :: Y( 38) double precision :: Z( 38) end subroutine LD0038 end interface interface SUBROUTINE LD0050(X,Y,Z,W,N) implicit none integer :: N double precision :: W( 50) double precision :: X( 50) double precision :: Y( 50) double precision :: Z( 50) end subroutine LD0050 end interface interface SUBROUTINE LD0074(X,Y,Z,W,N) implicit none integer :: N double precision :: W( 74) double precision :: X( 74) double precision :: Y( 74) double precision :: Z( 74) end subroutine LD0074 end interface interface SUBROUTINE LD0086(X,Y,Z,W,N) implicit none integer :: N double precision :: W( 86) double precision :: X( 86) double precision :: Y( 86) double precision :: Z( 86) end subroutine LD0086 end interface interface SUBROUTINE LD0110(X,Y,Z,W,N) implicit none integer :: N double precision :: W( 110) double precision :: X( 110) double precision :: Y( 110) double precision :: Z( 110) end subroutine LD0110 end interface interface SUBROUTINE LD0146(X,Y,Z,W,N) implicit none integer :: N double precision :: W( 146) double precision :: X( 146) double precision :: Y( 146) double precision :: Z( 146) end subroutine LD0146 end interface interface SUBROUTINE LD0170(X,Y,Z,W,N) implicit none integer :: N double precision :: W( 170) double precision :: X( 170) double precision :: Y( 170) double precision :: Z( 170) end subroutine LD0170 end interface interface SUBROUTINE LD0194(X,Y,Z,W,N) implicit none integer :: N double precision :: W( 194) double precision :: X( 194) double precision :: Y( 194) double precision :: Z( 194) end subroutine LD0194 end interface interface SUBROUTINE LD0230(X,Y,Z,W,N) implicit none integer :: N double precision :: W( 230) double precision :: X( 230) double precision :: Y( 230) double precision :: Z( 230) end subroutine LD0230 end interface interface SUBROUTINE LD0266(X,Y,Z,W,N) implicit none integer :: N double precision :: W( 266) double precision :: X( 266) double precision :: Y( 266) double precision :: Z( 266) end subroutine LD0266 end interface interface SUBROUTINE LD0302(X,Y,Z,W,N) implicit none integer :: N double precision :: W( 302) double precision :: X( 302) double precision :: Y( 302) double precision :: Z( 302) end subroutine LD0302 end interface interface SUBROUTINE LD0350(X,Y,Z,W,N) implicit none integer :: N double precision :: W( 350) double precision :: X( 350) double precision :: Y( 350) double precision :: Z( 350) end subroutine LD0350 end interface interface SUBROUTINE LD0434(X,Y,Z,W,N) implicit none integer :: N double precision :: W( 434) double precision :: X( 434) double precision :: Y( 434) double precision :: Z( 434) end subroutine LD0434 end interface interface SUBROUTINE LD0590(X,Y,Z,W,N) implicit none integer :: N double precision :: W( 590) double precision :: X( 590) double precision :: Y( 590) double precision :: Z( 590) end subroutine LD0590 end interface interface SUBROUTINE LD0770(X,Y,Z,W,N) implicit none integer :: N double precision :: W( 770) double precision :: X( 770) double precision :: Y( 770) double precision :: Z( 770) end subroutine LD0770 end interface interface SUBROUTINE LD0974(X,Y,Z,W,N) implicit none integer :: N double precision :: W( 974) double precision :: X( 974) double precision :: Y( 974) double precision :: Z( 974) end subroutine LD0974 end interface interface SUBROUTINE LD1202(X,Y,Z,W,N) implicit none integer :: N double precision :: W(1202) double precision :: X(1202) double precision :: Y(1202) double precision :: Z(1202) end subroutine LD1202 end interface interface SUBROUTINE LD1454(X,Y,Z,W,N) implicit none integer :: N double precision :: W(1454) double precision :: X(1454) double precision :: Y(1454) double precision :: Z(1454) end subroutine LD1454 end interface interface SUBROUTINE LD1730(X,Y,Z,W,N) implicit none integer :: N double precision :: W(1730) double precision :: X(1730) double precision :: Y(1730) double precision :: Z(1730) end subroutine LD1730 end interface interface SUBROUTINE LD2030(X,Y,Z,W,N) implicit none integer :: N double precision :: W(2030) double precision :: X(2030) double precision :: Y(2030) double precision :: Z(2030) end subroutine LD2030 end interface interface SUBROUTINE LD2354(X,Y,Z,W,N) implicit none integer :: N double precision :: W(2354) double precision :: X(2354) double precision :: Y(2354) double precision :: Z(2354) end subroutine LD2354 end interface interface SUBROUTINE LD2702(X,Y,Z,W,N) implicit none integer :: N double precision :: W(2702) double precision :: X(2702) double precision :: Y(2702) double precision :: Z(2702) end subroutine LD2702 end interface interface SUBROUTINE LD3074(X,Y,Z,W,N) implicit none integer :: N double precision :: W(3074) double precision :: X(3074) double precision :: Y(3074) double precision :: Z(3074) end subroutine LD3074 end interface interface SUBROUTINE LD3470(X,Y,Z,W,N) implicit none integer :: N double precision :: W(3470) double precision :: X(3470) double precision :: Y(3470) double precision :: Z(3470) end subroutine LD3470 end interface interface SUBROUTINE LD3890(X,Y,Z,W,N) implicit none integer :: N double precision :: W(3890) double precision :: X(3890) double precision :: Y(3890) double precision :: Z(3890) end subroutine LD3890 end interface interface SUBROUTINE LD4334(X,Y,Z,W,N) implicit none integer :: N double precision :: W(4334) double precision :: X(4334) double precision :: Y(4334) double precision :: Z(4334) end subroutine LD4334 end interface interface SUBROUTINE LD4802(X,Y,Z,W,N) implicit none integer :: N double precision :: W(4802) double precision :: X(4802) double precision :: Y(4802) double precision :: Z(4802) end subroutine LD4802 end interface interface SUBROUTINE LD5294(X,Y,Z,W,N) implicit none integer :: N double precision :: W(5294) double precision :: X(5294) double precision :: Y(5294) double precision :: Z(5294) end subroutine LD5294 end interface interface SUBROUTINE LD5810(X,Y,Z,W,N) implicit none integer :: N double precision :: W(5810) double precision :: X(5810) double precision :: Y(5810) double precision :: Z(5810) end subroutine LD5810 end interface interface SUBROUTINE nfourier(rindata,coutdata,iflag,Iwmax,L,Beta) implicit none integer :: Iwmax integer :: L integer :: iflag double precision :: Beta complex*16 :: coutdata(Iwmax+1) double precision :: rindata(L) end subroutine nfourier end interface interface SUBROUTINE nfourier2(rindata,coutdata,iflag,om,L,Beta) implicit none integer :: L integer :: iflag double precision :: Beta complex*16 :: coutdata real*8 :: om double precision :: rindata(L) end subroutine nfourier2 end interface interface SUBROUTINE invfourier(cindata,routdata,Iwmax,L,iflag,beta) implicit none integer, intent(in) :: Iwmax integer, intent(in) :: L integer, intent(in) :: iflag double precision, intent(in) :: beta complex*16, intent(in) :: cindata(1:Iwmax) complex*16, intent(inout) :: routdata(1:L) end subroutine invfourier end interface interface SUBROUTINE ludcmp(a,n,np,indx,id,info) implicit none integer :: id integer :: info integer :: n integer :: np real*8 :: a(np,np) integer :: indx(n) end subroutine ludcmp end interface interface SUBROUTINE lubksb(a,n,np,indx,b) implicit none integer :: n integer :: np real*8 :: a(np,np) real*8 :: b(n) integer :: indx(n) end subroutine lubksb end interface interface subroutine smooth(a,mesh,it) implicit none integer, intent(in) :: it integer, intent(in) :: mesh real*8, intent(inout) :: a(mesh) end subroutine smooth end interface interface subroutine sort_dp(n,list,iperm,tol) implicit none integer, intent(in) :: n double precision, intent(in) :: tol integer, intent(inout) :: iperm(n) double precision, intent(inout) :: list(n) end subroutine sort_dp end interface interface subroutine sort_int(n,list,iperm) implicit none integer,intent(in) :: n integer,intent(inout) :: iperm(n) integer,intent(inout) :: list(n) end subroutine sort_int end interface interface function uniformrandom(seed) implicit none integer :: seed double precision :: uniformrandom end function uniformrandom end interface end module interfaces_28_numeric_noabirule !!*** v_sim-3.8.0/lib/plug-ins/abinit/interfaces_32_util.F90000066400000000000000000000252461370110300500223540ustar00rootroot00000000000000!!****m* ABINIT/interfaces_32_util !! NAME !! interfaces_32_util !! !! FUNCTION !! This module contains the interfaces of the routines !! in the directory src/32_util !! !! COPYRIGHT !! Copyright (C) 2010-2016 ABINIT group !! This file is distributed under the terms of the !! GNU General Public License, see ~abinit/COPYING !! or http://www.gnu.org/copyleft/gpl.txt . !! !! NOTES !! THIS FILE IS GENERATED AUTOMATICALLY BY abilint. !! To do that: config/scripts/abilint . . !! !! !! SOURCE #if defined HAVE_CONFIG_H #include "config.h" #endif module interfaces_32_util implicit none interface subroutine acrossb(a,b,c) use defs_basis implicit none real(dp),intent(in) :: a(3) real(dp),intent(in) :: b(3) real(dp),intent(out) :: c(3) end subroutine acrossb end interface interface subroutine appdig(integ,string,strinn) implicit none integer,intent(in) :: integ character(len=*),intent(in) :: string character(len=*),intent(out) :: strinn end subroutine appdig end interface interface subroutine besjm(arg,besjx,cosx,nn,nx,sinx,xx) use defs_basis implicit none integer,intent(in) :: nn integer,intent(in) :: nx real(dp),intent(in) :: arg real(dp),intent(out) :: besjx(nx) real(dp),intent(in) :: cosx(nx) real(dp),intent(in) :: sinx(nx) real(dp),intent(in) :: xx(nx) end subroutine besjm end interface interface subroutine blow_pawuj(mat,nj,matt) use defs_basis implicit none integer,intent(in) :: nj real(dp),intent(in) :: mat(nj,nj) real(dp),intent(out) :: matt(nj+1,nj+1) end subroutine blow_pawuj end interface interface function clp(x) use defs_basis implicit none real(dp) :: clp real(dp),intent(in) :: x end function clp end interface interface subroutine create_mlms2jmj(lcor,mlmstwojmj) use defs_basis implicit none integer,intent(in) :: lcor complex(dpc),intent(out) :: mlmstwojmj(2*(2*lcor+1),2*(2*lcor+1)) end subroutine create_mlms2jmj end interface interface subroutine create_slm2ylm(lcor,slmtwoylm) use defs_basis implicit none integer,intent(in) :: lcor complex(dpc),intent(out) :: slmtwoylm(2*lcor+1,2*lcor+1) end subroutine create_slm2ylm end interface interface subroutine ctrap(imax,ff,hh,ans) use defs_basis implicit none integer,intent(in) :: imax real(dp),intent(out) :: ans real(dp),intent(in) :: hh real(dp),intent(in) :: ff(imax) end subroutine ctrap end interface interface subroutine ddb_chkname(nmfond,nmxpct,nmxpct2) implicit none character(len=*),intent(in) :: nmfond character(len=*),intent(in) :: nmxpct character(len=*),intent(in),optional :: nmxpct2 end subroutine ddb_chkname end interface interface subroutine fappnd(filapp,filnam,iapp,& & suff) ! optional argument use defs_basis implicit none integer,intent(in) :: iapp character(len=fnlen),intent(out) :: filapp character(len=fnlen),intent(in) :: filnam character(len=3),optional,intent(in) :: suff end subroutine fappnd end interface interface subroutine findmin(dedv_1,dedv_2,dedv_predict,& & d2edv2_1,d2edv2_2,d2edv2_predict,& & etotal_1,etotal_2,etotal_predict,& & lambda_1,lambda_2,lambda_predict,status) use defs_basis implicit none integer,intent(out) :: status real(dp),intent(out) :: d2edv2_1 real(dp),intent(out) :: d2edv2_2 real(dp),intent(out) :: d2edv2_predict real(dp),intent(in) :: dedv_1 real(dp),intent(in) :: dedv_2 real(dp),intent(out) :: dedv_predict real(dp),intent(in) :: etotal_1 real(dp),intent(in) :: etotal_2 real(dp),intent(out) :: etotal_predict real(dp),intent(in) :: lambda_1 real(dp),intent(in) :: lambda_2 real(dp),intent(out) :: lambda_predict end subroutine findmin end interface interface subroutine hermit(chmin,chmout,ierr,ndim) use defs_basis implicit none integer,intent(out) :: ierr integer,intent(in) :: ndim real(dp),intent(inout) :: chmin(ndim*ndim+ndim) real(dp),intent(inout) :: chmout(ndim*ndim+ndim) end subroutine hermit end interface interface subroutine inupper(string) implicit none character(len=*),intent(inout) :: string end subroutine inupper end interface interface subroutine isfile(filnam,status) use defs_basis implicit none character(len=fnlen),intent(inout) :: filnam character(len=3),intent(in) :: status end subroutine isfile end interface interface subroutine kramerskronig(nomega,omega,eps,method,only_check) use defs_basis implicit none integer,intent(in) :: method integer,intent(in) :: nomega integer,intent(in) :: only_check complex,intent(inout) :: eps(nomega) real(dp),intent(in) :: omega(nomega) end subroutine kramerskronig end interface interface subroutine littlegroup_q(nsym,qpt,symq,symrec,symafm,timrev,prtvol,use_sym) use defs_basis implicit none integer,intent(in) :: nsym integer,intent(in),optional :: prtvol integer,intent(out) :: timrev integer,intent(in),optional :: use_sym real(dp),intent(in) :: qpt(3) integer,intent(in) :: symafm(nsym) integer,intent(out) :: symq(4,2,nsym) integer,intent(in) :: symrec(3,3,nsym) end subroutine littlegroup_q end interface interface subroutine mati3det(mm,det) implicit none integer,intent(out) :: det integer,intent(in) :: mm(3,3) end subroutine mati3det end interface interface subroutine mati3inv(mm,mit) implicit none integer,intent(out) :: mit(3,3) integer,intent(in) :: mm(3,3) end subroutine mati3inv end interface interface subroutine matr3eigval(eigval,matr) use defs_basis implicit none real(dp),intent(out) :: eigval(3) real(dp),intent(in) :: matr(3,3) end subroutine matr3eigval end interface interface subroutine matr3inv(aa,ait) use defs_basis implicit none real(dp),intent(in) :: aa(3,3) real(dp),intent(out) :: ait(3,3) end subroutine matr3inv end interface interface subroutine matrginv(a,lda,n) use defs_basis implicit none integer,intent(in) :: lda integer,intent(in) :: n real(dp),intent(inout) :: a(lda,n) end subroutine matrginv end interface interface subroutine mknormpath(nbounds,bounds,gmet,ndiv_small,ndiv,npt_tot,path) use defs_basis implicit none integer,intent(in) :: nbounds integer,intent(in) :: ndiv_small integer,intent(inout) :: npt_tot real(dp),intent(in) :: bounds(3,nbounds) real(dp),intent(in) :: gmet(3,3) integer,intent(inout) :: ndiv(nbounds-1) real(dp),intent(out),optional :: path(3,npt_tot) end subroutine mknormpath end interface interface subroutine nderiv(hh,yy,zz,ndim,norder) use defs_basis implicit none integer,intent(in) :: ndim integer,intent(in) :: norder real(dp),intent(in) :: hh real(dp),intent(in) :: yy(ndim) real(dp),intent(out) :: zz(ndim) end subroutine nderiv end interface interface subroutine overlap_g(doti,dotr,mpw,npw_k1,npw_k2,nspinor,pwind_k,vect1,vect2) use defs_basis implicit none integer,intent(in) :: mpw integer,intent(in) :: npw_k1 integer,intent(in) :: npw_k2 integer,intent(in) :: nspinor real(dp),intent(out) :: doti real(dp),intent(out) :: dotr integer,intent(in) :: pwind_k(mpw) real(dp),intent(in) :: vect1(1:2,0:mpw*nspinor) real(dp),intent(in) :: vect2(1:2,0:mpw*nspinor) end subroutine overlap_g end interface interface function permutations(nn,kk) use defs_basis implicit none integer,intent(in) :: kk integer,intent(in) :: nn real(dp) :: permutations end function permutations end interface interface function phim(costheta,sintheta,mm) use defs_basis implicit none integer,intent(in) :: mm real(dp),intent(in) :: costheta real(dp) :: phim real(dp),intent(in) :: sintheta end function phim end interface interface function proc_distrb_cycle(distrb,ikpt,iband1,iband2,isppol,me) implicit none integer,intent(in) :: iband1 integer,intent(in) :: iband2 integer,intent(in) :: ikpt integer,intent(in) :: isppol integer,intent(in) :: me logical :: proc_distrb_cycle integer,allocatable,intent(in) :: distrb(:,:,:) end function proc_distrb_cycle end interface interface subroutine radsintr(funr,funq,mqgrid,mrgrid,qgrid,rgrid,yq1,yqn) use defs_basis implicit none integer , intent(in) :: mqgrid integer , intent(in) :: mrgrid real(dp), intent(out) :: yq1 real(dp), intent(out) :: yqn real(dp), intent(out) :: funq(mqgrid) real(dp), intent(in) :: funr(mrgrid) real(dp), intent(in) :: qgrid(mqgrid) real(dp), intent(in) :: rgrid(mrgrid) end subroutine radsintr end interface interface function radsmear(r, rsph, rsm) use defs_basis implicit none real(dp), intent(in) :: r real(dp) :: radsmear real(dp), intent(in) :: rsm real(dp), intent(in) :: rsph end function radsmear end interface interface subroutine rotmat(xaxis,zaxis,inversion_flag,umat) use defs_basis implicit none integer,intent(out) :: inversion_flag real(dp),intent(out) :: umat(3,3) real(dp),intent(in) :: xaxis(3) real(dp),intent(in) :: zaxis(3) end subroutine rotmat end interface interface subroutine sbf8(nm,xx,sb_out) use defs_basis implicit none integer,intent(in) :: nm real(dp),intent(in) :: xx real(dp),intent(out) :: sb_out(nm) end subroutine sbf8 end interface interface function set_istwfk(kpoint) result(istwfk) use defs_basis implicit none integer :: istwfk real(dp),intent(in) :: kpoint(3) end function set_istwfk end interface interface subroutine smatrix(cg,cgq,cg1_k,ddkflag,dtm_k,icg,icg1,itrs,job,maxbd,& & mcg_k,mcg_q,mcg1_k,minbd,mpw,nband_occ,npw_k1,npw_k2,nspinor,& & pwind_k,pwnsfac_k,sflag_k,shiftbd,smat_inv,smat_k,smat_k_paw,usepaw) use defs_basis implicit none integer,intent(in) :: ddkflag integer,intent(in) :: icg integer,intent(in) :: icg1 integer,intent(in) :: itrs integer,intent(in) :: job integer,intent(in) :: maxbd integer,intent(in) :: mcg1_k integer,intent(in) :: mcg_k integer,intent(in) :: mcg_q integer,intent(in) :: minbd integer,intent(in) :: mpw integer,intent(in) :: nband_occ integer,intent(in) :: npw_k1 integer,intent(in) :: npw_k2 integer,intent(in) :: nspinor integer,intent(in) :: shiftbd integer,intent(in) :: usepaw real(dp),intent(in) :: cg(2,mcg_k) real(dp),intent(out) :: cg1_k(2,mcg1_k) real(dp),intent(in) :: cgq(2,mcg_q) real(dp),intent(out) :: dtm_k(2) integer,intent(in) :: pwind_k(mpw) real(dp),intent(in) :: pwnsfac_k(4,mpw) integer,intent(inout) :: sflag_k(nband_occ) real(dp),intent(out) :: smat_inv(2,nband_occ,nband_occ) real(dp),intent(inout) :: smat_k(2,nband_occ,nband_occ) real(dp),intent(in) :: smat_k_paw(2,usepaw*nband_occ,usepaw*nband_occ) end subroutine smatrix end interface interface subroutine status(counter,filstat,istat,level,routine) implicit none integer,intent(in) :: counter integer,intent(in) :: istat integer,intent(in) :: level character(len=*),intent(in) :: filstat character(len=*),intent(in) :: routine end subroutine status end interface end module interfaces_32_util !!*** v_sim-3.8.0/lib/plug-ins/abinit/interfaces_41_geometry.F90000066400000000000000000000703261370110300500232310ustar00rootroot00000000000000!!****m* ABINIT/interfaces_41_geometry !! NAME !! interfaces_41_geometry !! !! FUNCTION !! This module contains the interfaces of the routines !! in the directory src/41_geometry !! !! COPYRIGHT !! Copyright (C) 2010-2016 ABINIT group !! This file is distributed under the terms of the !! GNU General Public License, see ~abinit/COPYING !! or http://www.gnu.org/copyleft/gpl.txt . !! !! NOTES !! THIS FILE IS GENERATED AUTOMATICALLY BY abilint. !! To do that: config/scripts/abilint . . !! !! !! SOURCE #if defined HAVE_CONFIG_H #include "config.h" #endif module interfaces_41_geometry implicit none interface subroutine bldgrp(msym,nogen,nsym,symafm,symrel,tnons) use defs_basis implicit none integer,intent(in) :: msym integer,intent(inout) :: nogen integer,intent(in) :: nsym integer,intent(inout) :: symafm(msym) integer,intent(inout) :: symrel(3,3,msym) real(dp),intent(inout) :: tnons(3,msym) end subroutine bldgrp end interface interface subroutine bonds_lgth_angles(coordn,fnameabo_app_geo,natom,ntypat,rprimd,typat,xred,znucl) use defs_basis implicit none integer,intent(in) :: coordn integer,intent(in) :: natom integer,intent(in) :: ntypat character(len=*),intent(in) :: fnameabo_app_geo real(dp),intent(in) :: rprimd(3,3) integer,intent(in) :: typat(natom) real(dp),intent(inout) :: xred(3,natom) real(dp),intent(in) :: znucl(ntypat) end subroutine bonds_lgth_angles end interface interface subroutine chiscwrt(chi_org,disv_org,nat_org,sdisv_org,smult_org,nsh_org,chi_sc,& & disv_sc,nat_sc,smult_sc,nsh_sc,opt,prtvol) use defs_basis implicit none integer,intent(in) :: nat_org integer,intent(in) :: nat_sc integer,intent(in) :: nsh_org integer,intent(in) :: nsh_sc integer,intent(in),optional :: opt integer,intent(in),optional :: prtvol real(dp),intent(in) :: chi_org(nat_org) real(dp),intent(out) :: chi_sc(nat_sc) real(dp),intent(in) :: disv_org(nat_org) real(dp),intent(in) :: disv_sc(nat_sc) real(dp),intent(in) :: sdisv_org(nsh_org) integer,intent(in) :: smult_org(nsh_org) integer,intent(in) :: smult_sc(nsh_sc) end subroutine chiscwrt end interface interface subroutine chkdilatmx(dilatmx,rprimd,rprimd_orig,dilatmx_errmsg) use defs_basis implicit none real(dp),intent(in) :: dilatmx character(len=500),intent(out) :: dilatmx_errmsg real(dp),intent(inout) :: rprimd(3,3) real(dp),intent(in) :: rprimd_orig(3,3) end subroutine chkdilatmx end interface interface subroutine chkgrp(nsym,symafm,symrel,ierr) implicit none integer,intent(out) :: ierr integer,intent(in) :: nsym integer,intent(in) :: symafm(nsym) integer,intent(in) :: symrel(3,3,nsym) end subroutine chkgrp end interface interface subroutine sg_multable(nsym,symafm,symrel,tnons,tnons_tol,ierr,multable,toinv) use defs_basis implicit none integer,intent(out) :: ierr integer,intent(in) :: nsym real(dp),intent(in) :: tnons_tol integer,optional,intent(out) :: multable(4,nsym,nsym) integer,intent(in) :: symafm(nsym) integer,intent(in) :: symrel(3,3,nsym) real(dp),intent(in) :: tnons(3,nsym) integer,optional,intent(out) :: toinv(4,nsym) end subroutine sg_multable end interface interface subroutine chkorthsy(gprimd,iexit,nsym,rmet,rprimd,symrel) use defs_basis implicit none integer,intent(inout) :: iexit integer,intent(in) :: nsym real(dp),intent(in) :: gprimd(3,3) real(dp),intent(in) :: rmet(3,3) real(dp),intent(in) :: rprimd(3,3) integer,intent(in) :: symrel(3,3,nsym) end subroutine chkorthsy end interface interface subroutine chkprimit(chkprim,multi,nsym,symafm,symrel) implicit none integer,intent(in) :: chkprim integer,intent(out) :: multi integer,intent(in) :: nsym integer,intent(in) :: symafm(nsym) integer,intent(in) :: symrel(3,3,nsym) end subroutine chkprimit end interface interface subroutine chkrprimd(acell,rprim,rprimd,iout) use defs_basis implicit none integer,intent(in) :: iout real(dp),intent(in) :: acell(3) real(dp),intent(in) :: rprim(3,3) real(dp),intent(in) :: rprimd(3,3) end subroutine chkrprimd end interface interface function dbeta(cosbeta,ll,mp,mm) use defs_basis implicit none integer,intent(in) :: ll integer,intent(in) :: mm integer,intent(in) :: mp real(dp),intent(in) :: cosbeta real(dp) :: dbeta end function dbeta end interface interface function dist2(v1,v2,rprimd,option) use defs_basis implicit none integer,intent(in),optional :: option real(dp) :: dist2 real(dp),intent(in),optional :: rprimd(3,3) real(dp),intent(in) :: v1(3) real(dp),intent(in) :: v2(3) end function dist2 end interface interface subroutine fcart2fred(fcart,fred,rprimd,natom) use defs_basis implicit none integer,intent(in) :: natom real(dp),intent(in) :: fcart(3,natom) real(dp),intent(out) :: fred(3,natom) real(dp),intent(in) :: rprimd(3,3) end subroutine fcart2fred end interface interface subroutine fillcell(natom,natrd,nsym,nucdipmom,spinat,symafm,symrel,tnons,tolsym,typat,xred) use defs_basis implicit none integer,intent(in) :: natom integer,intent(in) :: natrd integer,intent(in) :: nsym real(dp),intent(in) :: tolsym real(dp),intent(inout) :: nucdipmom(3,natom) real(dp),intent(inout) :: spinat(3,natom) integer,intent(in) :: symafm(nsym) integer,intent(in) :: symrel(3,3,nsym) real(dp),intent(in) :: tnons(3,nsym) integer,intent(inout) :: typat(natom) real(dp),intent(inout) :: xred(3,natom) end subroutine fillcell end interface interface subroutine fred2fcart(favg,fcart,fred,gprimd,jellslab,natom) use defs_basis implicit none integer,intent(in) :: jellslab integer,intent(in) :: natom real(dp),intent(out) :: favg(3) real(dp),intent(out) :: fcart(3,natom) real(dp),intent(in) :: fred(3,natom) real(dp),intent(in) :: gprimd(3,3) end subroutine fred2fcart end interface interface subroutine gensymshub(genafm,spgroup,spgroupma,shubnikov) use defs_basis implicit none integer,intent(out) :: shubnikov integer,intent(in) :: spgroup integer,intent(in) :: spgroupma real(dp),intent(out) :: genafm(3) end subroutine gensymshub end interface interface subroutine gensymshub4(genafm,msym,nsym,symafm,symrel,tnons) use defs_basis implicit none integer,intent(in) :: msym integer,intent(inout) :: nsym real(dp),intent(in) :: genafm(3) integer,intent(inout) :: symafm(msym) integer,intent(inout) :: symrel(3,3,msym) real(dp),intent(inout) :: tnons(3,msym) end subroutine gensymshub4 end interface interface subroutine gensymspgr(brvltt,msym,nsym,shubnikov,spgaxor,spgorig,& & spgroup,spgroupma,symafm,symrel,tnons) use defs_basis implicit none integer,intent(inout) :: brvltt integer,intent(in) :: msym integer,intent(out) :: nsym integer,intent(in) :: shubnikov integer,intent(in) :: spgaxor integer,intent(in) :: spgorig integer,intent(in) :: spgroup integer,intent(in) :: spgroupma integer,intent(inout) :: symafm(msym) integer,intent(inout) :: symrel(3,3,msym) real(dp),intent(inout) :: tnons(3,msym) end subroutine gensymspgr end interface interface subroutine getptgroupma(ptgroup,ptgroupha,ptgroupma) implicit none integer,intent(out) :: ptgroupma character(len=5),intent(in) :: ptgroup character(len=5),intent(in) :: ptgroupha end subroutine getptgroupma end interface interface subroutine getspinrot(rprimd,spinrot,symrel_conv) use defs_basis implicit none integer,intent(in) :: symrel_conv(3,3) real(dp),intent(in) :: rprimd(3,3) real(dp),intent(out) :: spinrot(4) end subroutine getspinrot end interface interface subroutine holocell(cell_base,enforce,foundc,iholohedry,tolsym) use defs_basis implicit none integer,intent(in) :: enforce integer,intent(out) :: foundc integer,intent(in) :: iholohedry real(dp),intent(in) :: tolsym real(dp),intent(inout) :: cell_base(3,3) end subroutine holocell end interface interface subroutine ioniondist(natom,rprimd,xred,inm,option,varlist,magv,atp,prtvol) use defs_basis implicit none integer,intent(in),optional :: atp integer,intent(in) :: natom integer,intent(in) :: option integer,intent(in),optional :: prtvol real(dp),intent(out) :: inm(natom,natom) integer,intent(in),optional :: magv(natom) real(dp),intent(in) :: rprimd(3,3) real(dp),intent(in),optional :: varlist(natom) real(dp),intent(in) :: xred(3,natom) end subroutine ioniondist end interface interface subroutine irreducible_set_pert(indsym,mpert,natom,nsym,pertsy,rfdir,rfpert,symq,symrec,symrel) implicit none integer,intent(in) :: mpert integer,intent(in) :: natom integer,intent(in) :: nsym integer,intent(in) :: rfdir(3) integer,intent(in) :: indsym(4,nsym,natom) integer,intent(out) :: pertsy(3,mpert) integer,intent(in) :: rfpert(mpert) integer,intent(in) :: symq(4,2,nsym) integer,intent(in) :: symrec(3,3,nsym) integer,intent(in) :: symrel(3,3,nsym) end subroutine irreducible_set_pert end interface interface subroutine littlegroup_pert(gprimd,idir,indsym,iout,ipert,natom,nsym,nsym1,& & rfmeth,symafm,symaf1,symq,symrec,symrel,symrl1,syuse,tnons,tnons1) use defs_basis implicit none integer,intent(in) :: idir integer,intent(in) :: iout integer,intent(in) :: ipert integer,intent(in) :: natom integer,intent(in) :: nsym integer,intent(out) :: nsym1 integer,intent(in) :: rfmeth integer,intent(in) :: syuse real(dp),intent(in) :: gprimd(3,3) integer,intent(in) :: indsym(4,nsym,natom) integer,intent(out) :: symaf1(nsym) integer,intent(in) :: symafm(nsym) integer,intent(in) :: symq(4,2,nsym) integer,intent(in) :: symrec(3,3,nsym) integer,intent(in) :: symrel(3,3,nsym) integer,intent(out) :: symrl1(3,3,nsym) real(dp),intent(in) :: tnons(3,nsym) real(dp),intent(out) :: tnons1(3,nsym) end subroutine littlegroup_pert end interface interface subroutine metric(gmet,gprimd,iout,rmet,rprimd,ucvol) use defs_basis implicit none integer,intent(in) :: iout real(dp),intent(out) :: ucvol real(dp),intent(out) :: gmet(3,3) real(dp),intent(out) :: gprimd(3,3) real(dp),intent(out) :: rmet(3,3) real(dp),intent(in) :: rprimd(3,3) end subroutine metric end interface interface subroutine mkeuler(rot,cosbeta,cosalp,sinalp,cosgam,singam,isn) use defs_basis implicit none integer,intent(out) :: isn real(dp),intent(out) :: cosalp real(dp),intent(out) :: cosbeta real(dp),intent(out) :: cosgam real(dp),intent(out) :: sinalp real(dp),intent(out) :: singam real(dp),intent(in) :: rot(3,3) end subroutine mkeuler end interface interface subroutine mkradim(acell,rprim,rprimd) use defs_basis implicit none real(dp),intent(out) :: acell(3) real(dp),intent(out) :: rprim(3,3) real(dp),intent(in) :: rprimd(3,3) end subroutine mkradim end interface interface subroutine mkrdim(acell,rprim,rprimd) use defs_basis implicit none real(dp),intent(in) :: acell(3) real(dp),intent(in) :: rprim(3,3) real(dp),intent(out) :: rprimd(3,3) end subroutine mkrdim end interface interface subroutine mksupercell(xred_org,magv_org,rprimd_org,nat_org,nat_sc,xred_sc,magv_sc,rprimd_sc,ext,prtvol) use defs_basis implicit none integer,intent(in) :: nat_org integer,intent(in) :: nat_sc integer,intent(in),optional :: prtvol integer,intent(in) :: ext(3) integer,intent(in),optional :: magv_org(nat_org) real(dp),intent(out) :: magv_sc(nat_sc) real(dp),intent(in) :: rprimd_org(3,3) real(dp),intent(out) :: rprimd_sc(3,3) real(dp),intent(in) :: xred_org(3,nat_org) real(dp),intent(out) :: xred_sc(3,nat_sc) end subroutine mksupercell end interface interface subroutine polcart(red_ptot,pel,pel_cart,pelev,pion,pion_cart,polunit,& & ptot_cart,rprimd,ucvol,unit_out,usepaw) use defs_basis implicit none integer,intent(in) :: polunit integer,intent(in) :: unit_out integer,intent(in) :: usepaw real(dp),intent(in) :: ucvol real(dp),intent(in) :: pel(3) real(dp),intent(out) :: pel_cart(3) real(dp),intent(in) :: pelev(3) real(dp),intent(in) :: pion(3) real(dp),intent(out) :: pion_cart(3) real(dp),intent(out) :: ptot_cart(3) real(dp),intent(in) :: red_ptot(3) real(dp),intent(in) :: rprimd(3,3) end subroutine polcart end interface interface subroutine prt_cif(brvltt, ciffname, natom, nsym, ntypat, rprimd,& & spgaxor, spgroup, spgorig, symrel, tnon, typat, xred, znucl) use defs_basis implicit none integer, intent(in) :: brvltt integer,intent(in) :: natom integer,intent(in) :: nsym integer,intent(in) :: ntypat integer, intent(in) :: spgaxor integer, intent(in) :: spgorig integer, intent(in) :: spgroup character(len=*), intent(in) :: ciffname real(dp), intent(in) :: rprimd(3,3) integer, intent(in) :: symrel(3,3,nsym) real(dp), intent(in) :: tnon(3,nsym) integer, intent(in) :: typat(natom) real(dp), intent(in) :: xred(3,natom) real(dp), intent(in) :: znucl(ntypat) end subroutine prt_cif end interface interface subroutine symrel2string(symrel1, tnon, string) use defs_basis implicit none character(len=80), intent(out) :: string integer, intent(in) :: symrel1(3,3) real(dp), intent(in) :: tnon(3) end subroutine symrel2string end interface interface subroutine prtposcar(fcart, fnameradix, natom, ntypat, rprimd, typat, ucvol, xred, znucl) use defs_basis implicit none integer, intent(in) :: natom integer, intent(in) :: ntypat character(len=fnlen), intent(in) :: fnameradix real(dp), intent(in) :: ucvol real(dp), intent(in) :: fcart(3,natom) real(dp), intent(in) :: rprimd(3,3) integer, intent(in) :: typat(natom) real(dp), intent(in) :: xred(3,natom) real(dp), intent(in) :: znucl(ntypat) end subroutine prtposcar end interface interface subroutine prtspgroup(bravais,genafm,iout,jdtset,ptgroupma,spgroup) use defs_basis implicit none integer,intent(in) :: iout integer,intent(in) :: jdtset integer,intent(in) :: ptgroupma integer,intent(in) :: spgroup integer,intent(in) :: bravais(11) real(dp),intent(inout) :: genafm(3) end subroutine prtspgroup end interface interface subroutine ptgmadata(ptgroupma,ptgrpmasb) implicit none integer,intent(in) :: ptgroupma character(len=10),intent(out) :: ptgrpmasb end subroutine ptgmadata end interface interface subroutine randomcellpos(natom,npsp,ntypat,random_atpos,ratsph,rprim,rprimd,typat,xred,znucl,acell) use defs_basis implicit none integer,intent(in) :: natom integer,intent(in) :: npsp integer,intent(in) :: ntypat integer,intent(in) :: random_atpos real(dp), intent(inout) :: acell(3) real(dp),intent(in) :: ratsph(ntypat) real(dp), intent(inout) :: rprim(3,3) real(dp), intent(inout) :: rprimd(3,3) integer, intent(in) :: typat(natom) real(dp), intent(inout) :: xred(3,natom) real(dp), intent(in) :: znucl(npsp) end subroutine randomcellpos end interface interface subroutine remove_inversion(nsym,symrel,tnons,nsym_out,symrel_out,tnons_out,pinv) use defs_basis implicit none integer,intent(in) :: nsym integer,intent(out) :: nsym_out integer,intent(out) :: pinv integer,pointer :: symrel_out(:,:,:) integer,intent(in) :: symrel(3,3,nsym) real(dp),intent(in) :: tnons(3,nsym) real(dp),pointer :: tnons_out(:,:) end subroutine remove_inversion end interface interface subroutine shellstruct(xred,rprimd,natom,magv,distv,smult,sdisv,nsh,atp,prtvol) use defs_basis implicit none integer,intent(in),optional :: atp integer,intent(in) :: natom integer,intent(out) :: nsh integer,intent(in),optional :: prtvol real(dp),intent(out) :: distv(natom) integer,intent(in),optional :: magv(natom) real(dp),intent(in) :: rprimd(3,3) real(dp),intent(out) :: sdisv(natom) integer,intent(out) :: smult(natom) real(dp),intent(in) :: xred(3,natom) end subroutine shellstruct end interface interface subroutine smallprim(metmin,minim,rprimd) use defs_basis implicit none real(dp),intent(out) :: metmin(3,3) real(dp),intent(out) :: minim(3,3) real(dp),intent(in) :: rprimd(3,3) end subroutine smallprim end interface interface subroutine spgdata(brvsb,intsb,intsbl,ptintsb,ptschsb,& & schsb,spgaxor,spgroup,sporder,spgorig) implicit none integer,intent(in) :: spgaxor integer,intent(in) :: spgorig integer,intent(in) :: spgroup integer,intent(out) :: sporder character(len=1),intent(out) :: brvsb character(len=15),intent(out) :: intsb character(len=35),intent(out) :: intsbl character(len=15),intent(out) :: ptintsb character(len=15),intent(out) :: ptschsb character(len=15),intent(out) :: schsb end subroutine spgdata end interface interface subroutine strconv(frac,gprimd,cart) use defs_basis implicit none real(dp),intent(inout) :: cart(6) real(dp),intent(in) :: frac(6) real(dp),intent(in) :: gprimd(3,3) end subroutine strconv end interface interface subroutine stresssym(gprimd,nsym,stress,sym) use defs_basis implicit none integer,intent(in) :: nsym real(dp),intent(in) :: gprimd(3,3) real(dp),intent(inout) :: stress(6) integer,intent(in) :: sym(3,3,nsym) end subroutine stresssym end interface interface subroutine symanal(bravais,chkprim,genafm,msym,nsym,ptgroupma,rprimd,spgroup,symafm,symrel,tnons,tolsym) use defs_basis implicit none integer,intent(in) :: chkprim integer,intent(in) :: msym integer,intent(in) :: nsym integer,intent(out) :: ptgroupma integer,intent(out) :: spgroup real(dp),intent(in) :: tolsym integer,intent(out) :: bravais(11) real(dp),intent(out) :: genafm(3) real(dp),intent(in) :: rprimd(3,3) integer,intent(in) :: symafm(msym) integer,intent(in) :: symrel(3,3,msym) real(dp),intent(inout) :: tnons(3,msym) end subroutine symanal end interface interface subroutine symatm(indsym,natom,nsym,symrec,tnons,tolsym,typat,xred) use defs_basis implicit none integer,intent(in) :: natom integer,intent(in) :: nsym real(dp), intent(in) :: tolsym integer,intent(out) :: indsym(4,nsym,natom) integer,intent(in) :: symrec(3,3,nsym) real(dp),intent(in) :: tnons(3,nsym) integer,intent(in) :: typat(natom) real(dp),intent(in) :: xred(3,natom) end subroutine symatm end interface interface subroutine symaxes(center,iholohedry,isym,isymrelconv,label,ordersym,tnons_order,trialt,type_axis) use defs_basis implicit none integer,intent(in) :: center integer,intent(in) :: iholohedry integer,intent(in) :: isym integer,intent(in) :: ordersym integer,intent(in) :: tnons_order integer,intent(out) :: type_axis character(len=128),intent(out) :: label integer,intent(in) :: isymrelconv(3,3) real(dp),intent(in) :: trialt(3) end subroutine symaxes end interface interface subroutine symbrav(bravais,msym,nsym,ptgroup,rprimd,symrel,tolsym,axis) use defs_basis implicit none integer,intent(in) :: msym integer,intent(in) :: nsym character(len=5),intent(out) :: ptgroup real(dp),intent(in) :: tolsym integer,optional,intent(out) :: axis(3) integer,intent(out) :: bravais(11) real(dp),intent(in) :: rprimd(3,3) integer,intent(in) :: symrel(3,3,msym) end subroutine symbrav end interface interface subroutine symcharac(center, determinant, iholohedry, isym, label, symrel, tnons, type_axis) use defs_basis implicit none integer, intent(in) :: center integer, intent(in) :: determinant integer, intent(in) :: iholohedry integer, intent(in) :: isym integer, intent(out) :: type_axis character(len = 128), intent(out) :: label integer,intent(in) :: symrel(3,3) real(dp),intent(in) :: tnons(3) end subroutine symcharac end interface interface subroutine symchk(difmin,eatom,natom,tratom,transl,trtypat,typat,xred) use defs_basis implicit none integer,intent(out) :: eatom integer,intent(in) :: natom integer,intent(in) :: trtypat integer,intent(out) :: transl(3) real(dp),intent(out) :: difmin(3) real(dp),intent(in) :: tratom(3) integer,intent(in) :: typat(natom) real(dp),intent(in) :: xred(3,natom) end subroutine symchk end interface interface subroutine symdet(determinant,nsym,sym) implicit none integer,intent(in) :: nsym integer,intent(out) :: determinant(nsym) integer,intent(in) :: sym(3,3,nsym) end subroutine symdet end interface interface subroutine symfind(berryopt,efield,gprimd,jellslab,msym,natom,noncoll,nptsym,nsym,& & ptsymrel,spinat,symafm,symrel,tnons,tolsym,typat,use_inversion,xred,& & nucdipmom) use defs_basis implicit none integer,intent(in) :: berryopt integer,intent(in) :: jellslab integer,intent(in) :: msym integer,intent(in) :: natom integer,intent(in) :: noncoll integer,intent(in) :: nptsym integer,intent(out) :: nsym integer,intent(in) :: use_inversion real(dp),intent(in) :: tolsym real(dp),intent(in) :: efield(3) real(dp),intent(in) :: gprimd(3,3) real(dp),optional :: nucdipmom(3,natom) integer,intent(in) :: ptsymrel(3,3,msym) real(dp),intent(in) :: spinat(3,natom) integer,intent(inout) :: symafm(msym) integer,intent(inout) :: symrel(3,3,msym) real(dp),intent(inout) :: tnons(3,msym) integer,intent(in) :: typat(natom) real(dp),intent(in) :: xred(3,natom) end subroutine symfind end interface interface subroutine symkpt(chksymbreak,gmet,indkpt1,iout,kptns,nkpt,nkpt1,nsym1,& & symrc1,timrev,wtk,wtk_folded) use defs_basis implicit none integer,intent(in) :: chksymbreak integer,intent(in) :: iout integer,intent(in) :: nkpt integer,intent(out) :: nkpt1 integer,intent(in) :: nsym1 integer,intent(in) :: timrev real(dp),intent(in) :: gmet(3,3) integer,intent(inout) :: indkpt1(nkpt) real(dp),intent(in) :: kptns(3,nkpt) integer,intent(in) :: symrc1(3,3,nsym1) real(dp),intent(in) :: wtk(nkpt) real(dp),intent(out) :: wtk_folded(nkpt) end subroutine symkpt end interface interface subroutine symlatt(bravais,msym,nptsym,ptsymrel,rprimd,tolsym) use defs_basis implicit none integer,intent(in) :: msym integer,intent(out) :: nptsym real(dp),intent(in) :: tolsym integer,intent(out) :: bravais(11) integer,intent(out) :: ptsymrel(3,3,msym) real(dp),intent(in) :: rprimd(3,3) end subroutine symlatt end interface interface subroutine symlist_bcc(additional_info,nsym,n_axes,spgroup) implicit none integer,intent(in) :: additional_info integer,intent(in) :: nsym integer,intent(out) :: spgroup integer,intent(in) :: n_axes(31) end subroutine symlist_bcc end interface interface subroutine symlist_fcc(nsym,n_axes,spgroup) implicit none integer,intent(in) :: nsym integer,intent(out) :: spgroup integer,intent(in) :: n_axes(31) end subroutine symlist_fcc end interface interface subroutine symlist_others(brvltt,nsym,n_axes,spgroup) implicit none integer,intent(in) :: brvltt integer,intent(in) :: nsym integer,intent(out) :: spgroup integer,intent(in) :: n_axes(31) end subroutine symlist_others end interface interface subroutine symlist_prim(additional_info,nsym,n_axes,spgroup) implicit none integer,intent(in) :: additional_info integer,intent(in) :: nsym integer,intent(out) :: spgroup integer,intent(in) :: n_axes(31) end subroutine symlist_prim end interface interface subroutine symmetrize_rprimd(bravais,nsym,rprimd,symrel,tolsym) use defs_basis implicit none integer,intent(in) :: nsym real(dp) :: tolsym integer,intent(in) :: bravais(11) real(dp),intent(inout) :: rprimd(3,3) integer,intent(in) :: symrel(3,3,nsym) end subroutine symmetrize_rprimd end interface interface subroutine symmetrize_xred(indsym,natom,nsym,symrel,tnons,xred) use defs_basis implicit none integer,intent(in) :: natom integer,intent(in) :: nsym integer,intent(in) :: indsym(4,nsym,natom) integer,intent(in) :: symrel(3,3,nsym) real(dp),intent(in) :: tnons(3,nsym) real(dp),intent(inout) :: xred(3,natom) end subroutine symmetrize_xred end interface interface subroutine symplanes(center,iholohedry,isym,isymrelconv,itnonsconv,label,type_axis) use defs_basis implicit none integer,intent(in) :: center integer,intent(in) :: iholohedry integer,intent(in) :: isym integer,intent(out) :: type_axis character(len = 128), intent(out) :: label integer,intent(in) :: isymrelconv(3,3) real(dp),intent(in) :: itnonsconv(3) end subroutine symplanes end interface interface subroutine symptgroup(iholohedry,nsym,ptgroup,symrel) implicit none integer,intent(out) :: iholohedry integer,intent(in) :: nsym character(len=5),intent(out) :: ptgroup integer,intent(in) :: symrel(3,3,nsym) end subroutine symptgroup end interface interface subroutine symredcart(aprim,bprim,symcart,symred) use defs_basis implicit none integer,intent(in) :: symred(3,3) real(dp),intent(in) :: aprim(3,3) real(dp),intent(in) :: bprim(3,3) real(dp),intent(out) :: symcart(3,3) end subroutine symredcart end interface interface subroutine symrelrot(nsym,rprimd,rprimd_new,symrel,tolsym) use defs_basis implicit none integer,intent(in) :: nsym real(dp),intent(in) :: tolsym real(dp),intent(in) :: rprimd(3,3) real(dp),intent(in) :: rprimd_new(3,3) integer,intent(inout) :: symrel(3,3,nsym) end subroutine symrelrot end interface interface subroutine symsgcube(msym,nsym,shubnikov,spgaxor,spgorig,spgroup,& & spgroupma,symafm,symrel,tnons) use defs_basis implicit none integer,intent(in) :: msym integer,intent(inout) :: nsym integer,intent(in) :: shubnikov integer,intent(in) :: spgaxor integer,intent(in) :: spgorig integer,intent(in) :: spgroup integer,intent(in) :: spgroupma integer,intent(inout) :: symafm(msym) integer,intent(inout) :: symrel(3,3,msym) real(dp),intent(out) :: tnons(3,msym) end subroutine symsgcube end interface interface subroutine symsghexa(brvltt,msym,nsym,shubnikov,spgaxor,spgorig,spgroup,& & spgroupma,symafm,symrel,tnons) use defs_basis implicit none integer,intent(inout) :: brvltt integer,intent(in) :: msym integer,intent(in) :: nsym integer,intent(in) :: shubnikov integer,intent(in) :: spgaxor integer,intent(in) :: spgorig integer,intent(in) :: spgroup integer,intent(in) :: spgroupma integer,intent(inout) :: symafm(msym) integer,intent(inout) :: symrel(3,3,msym) real(dp),intent(inout) :: tnons(3,msym) end subroutine symsghexa end interface interface subroutine symsgmono(brvltt,msym,nsym,shubnikov,spgaxor,spgorig,spgroup,& & spgroupma,symafm,symrel,tnons) use defs_basis implicit none integer,intent(inout) :: brvltt integer,intent(in) :: msym integer,intent(in) :: nsym integer,intent(in) :: shubnikov integer,intent(in) :: spgaxor integer,intent(in) :: spgorig integer,intent(in) :: spgroup integer,intent(in) :: spgroupma integer,intent(inout) :: symafm(msym) integer,intent(inout) :: symrel(3,3,msym) real(dp),intent(inout) :: tnons(3,msym) end subroutine symsgmono end interface interface subroutine symsgortho(msym,nsym,shubnikov,spgaxor,spgorig,spgroup,& & spgroupma,symafm,symrel,tnons) use defs_basis implicit none integer,intent(in) :: msym integer,intent(in) :: nsym integer,intent(in) :: shubnikov integer,intent(in) :: spgaxor integer,intent(in) :: spgorig integer,intent(in) :: spgroup integer,intent(in) :: spgroupma integer,intent(inout) :: symafm(msym) integer,intent(inout) :: symrel(3,3,msym) real(dp),intent(inout) :: tnons(3,msym) end subroutine symsgortho end interface interface subroutine symsgtetra(msym,nsym,shubnikov,spgaxor,spgorig,spgroup,& & spgroupma,symafm,symrel,tnons) use defs_basis implicit none integer,intent(in) :: msym integer,intent(in) :: nsym integer,intent(in) :: shubnikov integer,intent(in) :: spgaxor integer,intent(in) :: spgorig integer,intent(in) :: spgroup integer,intent(in) :: spgroupma integer,intent(inout) :: symafm(msym) integer,intent(inout) :: symrel(3,3,msym) real(dp),intent(inout) :: tnons(3,msym) end subroutine symsgtetra end interface interface subroutine symspgr(bravais,nsym,spgroup,symrel,tnons,tolsym) use defs_basis implicit none integer,intent(in) :: nsym integer,intent(out) :: spgroup real(dp),intent(in) :: tolsym integer,intent(in) :: bravais(11) integer,intent(in) :: symrel(3,3,nsym) real(dp),intent(inout) :: tnons(3,nsym) end subroutine symspgr end interface interface subroutine xcart2xred(natom,rprimd,xcart,xred) use defs_basis implicit none integer,intent(in) :: natom real(dp),intent(in) :: rprimd(3,3) real(dp),intent(in) :: xcart(3,natom) real(dp),intent(out) :: xred(3,natom) end subroutine xcart2xred end interface interface subroutine xred2xcart(natom,rprimd,xcart,xred) use defs_basis implicit none integer,intent(in) :: natom real(dp),intent(in) :: rprimd(3,3) real(dp),intent(out) :: xcart(3,natom) real(dp),intent(in) :: xred(3,natom) end subroutine xred2xcart end interface end module interfaces_41_geometry !!*** v_sim-3.8.0/lib/plug-ins/abinit/m_ab7_symmetry.F90000066400000000000000000001032711370110300500216210ustar00rootroot00000000000000!{\src2tex{textfont=tt}} !!****m* ABINIT/m_ab7_symmetry !! NAME !! m_ab7_symmetry !! !! FUNCTION !! !! COPYRIGHT !! Copyright (C) 2008-2016 ABINIT group (DC) !! This file is distributed under the terms of the !! GNU General Public License, see ~abinit/COPYING !! or http://www.gnu.org/copyleft/gpl.txt . !! !! PARENTS !! !! SOURCE #if defined HAVE_CONFIG_H #include "config.h" #endif #include "abi_common.h" module m_ab7_symmetry use defs_basis use m_profiling_abi implicit none private integer, parameter, public :: AB7_MAX_SYMMETRIES = 384 type, public :: symmetry_type ! The input characteristics real(dp) :: tolsym real(dp) :: rprimd(3,3), gprimd(3,3), rmet(3,3) integer :: nAtoms integer, pointer :: typeAt(:) real(dp), pointer :: xRed(:,:) logical :: withField real(dp) :: field(3) logical :: withJellium integer :: withSpin real(dp), pointer :: spinAt(:,:) logical :: withSpinOrbit integer :: vacuum(3) ! The output characteristics ! The bravais parameters integer :: nBravSym integer :: bravais(11), bravSym(3, 3, AB7_MAX_SYMMETRIES) ! The symmetry matrices logical :: auto integer :: nSym integer, pointer :: sym(:,:,:) real(dp), pointer :: transNon(:,:) integer, pointer :: symAfm(:) ! Some additional information integer :: multiplicity real(dp) :: genAfm(3) integer :: spaceGroup, pointGroupMagn integer, pointer :: indexingAtoms(:,:,:) end type symmetry_type ! We store here a list of symmetry objects to be able to ! call several symmetry operations on different objects. ! The simplest portable way to do it, is to create ! a list of Fortran structure and to use the list index ! as an identifier that can be given to the other languages. type, private :: symmetry_list integer :: id type(symmetry_list), pointer :: next type(symmetry_type) :: data end type symmetry_list type(symmetry_list), pointer :: my_symmetries integer :: n_symmetries = 0 logical, private, parameter :: AB_DBG = .false. public :: symmetry_new public :: symmetry_free public :: symmetry_set_tolerance public :: symmetry_set_lattice public :: symmetry_set_structure public :: symmetry_set_collinear_spin public :: symmetry_set_spin public :: symmetry_set_spin_orbit public :: symmetry_set_field public :: symmetry_set_jellium public :: symmetry_set_periodicity public :: symmetry_set_n_sym public :: symmetry_get_from_id public :: symmetry_get_n_atoms public :: symmetry_get_n_sym public :: symmetry_get_multiplicity public :: symmetry_get_bravais public :: symmetry_get_matrices public :: symmetry_get_matrices_p public :: symmetry_get_group public :: symmetry_get_equivalent_atom public :: symmetry_get_type contains subroutine new_item(token) !This section has been created automatically by the script Abilint (TD). !Do not modify the following lines by hand. #undef ABI_FUNC #define ABI_FUNC 'new_item' !End of the abilint section type(symmetry_list), pointer :: token ! We allocate a new list token and prepend it. if (AB_DBG) write(std_err,*) "AB symmetry: create a new token." ! Init case, very first call. if (n_symmetries == 0) then nullify(my_symmetries) end if ! Normal treatment. n_symmetries = n_symmetries + 1 ABI_DATATYPE_ALLOCATE(token,) token%id = n_symmetries call new_symmetry(token%data) token%next => my_symmetries my_symmetries => token if (AB_DBG) write(std_err,*) "AB symmetry: creation OK with id ", token%id end subroutine new_item subroutine free_item(token) !This section has been created automatically by the script Abilint (TD). !Do not modify the following lines by hand. #undef ABI_FUNC #define ABI_FUNC 'free_item' !End of the abilint section type(symmetry_list), pointer :: token type(symmetry_list), pointer :: tmp if (.not. associated(token)) then return end if call free_symmetry(token%data) if (AB_DBG) write(std_err,*) "AB symmetry: free request on token ", token%id ! We remove token from the list. if (my_symmetries%id == token%id) then my_symmetries => token%next else tmp => my_symmetries do if (.not.associated(tmp)) then return end if if (associated(tmp%next) .and. tmp%next%id == token%id) then exit end if tmp => tmp%next end do tmp%next => token%next end if ABI_DATATYPE_DEALLOCATE(token) if (AB_DBG) write(std_err,*) "AB symmetry: free done" end subroutine free_item subroutine get_item(token, id) !This section has been created automatically by the script Abilint (TD). !Do not modify the following lines by hand. #undef ABI_FUNC #define ABI_FUNC 'get_item' !End of the abilint section type(symmetry_list), pointer :: token integer, intent(in) :: id type(symmetry_list), pointer :: tmp if (AB_DBG) write(std_err,*) "AB symmetry: request list element ", id nullify(token) tmp => my_symmetries do if (.not. associated(tmp)) then exit end if if (tmp%id == id) then token => tmp return end if tmp => tmp%next end do end subroutine get_item subroutine symmetry_get_from_id(sym, id, errno) !This section has been created automatically by the script Abilint (TD). !Do not modify the following lines by hand. #undef ABI_FUNC #define ABI_FUNC 'symmetry_get_from_id' !End of the abilint section type(symmetry_type), pointer :: sym integer, intent(in) :: id integer, intent(out) :: errno type(symmetry_list), pointer :: token errno = AB7_NO_ERROR call get_item(token, id) if (associated(token)) then sym => token%data if (sym%nSym <= 0) then ! We do the computation of the matrix part. call compute_matrices(sym, errno) end if else errno = AB7_ERROR_OBJ nullify(sym) end if end subroutine symmetry_get_from_id subroutine new_symmetry(sym) !This section has been created automatically by the script Abilint (TD). !Do not modify the following lines by hand. #undef ABI_FUNC #define ABI_FUNC 'new_symmetry' !End of the abilint section type(symmetry_type), intent(out) :: sym if (AB_DBG) write(std_err,*) "AB symmetry: create a new symmetry object." nullify(sym%xRed) nullify(sym%spinAt) nullify(sym%typeAt) sym%tolsym = tol8 sym%auto = .true. sym%nSym = 0 nullify(sym%sym) nullify(sym%symAfm) nullify(sym%transNon) sym%nBravSym = -1 sym%withField = .false. sym%withJellium = .false. sym%withSpin = 1 sym%withSpinOrbit = .false. sym%multiplicity = -1 nullify(sym%indexingAtoms) sym%vacuum = 0 end subroutine new_symmetry subroutine free_symmetry(sym) !This section has been created automatically by the script Abilint (TD). !Do not modify the following lines by hand. #undef ABI_FUNC #define ABI_FUNC 'free_symmetry' !End of the abilint section type(symmetry_type), intent(inout) :: sym if (AB_DBG) write(std_err,*) "AB symmetry: free a symmetry." if (associated(sym%xRed)) then ABI_DEALLOCATE(sym%xRed) end if if (associated(sym%spinAt)) then ABI_DEALLOCATE(sym%spinAt) end if if (associated(sym%typeAt)) then ABI_DEALLOCATE(sym%typeAt) end if if (associated(sym%indexingAtoms)) then ABI_DEALLOCATE(sym%indexingAtoms) end if if (associated(sym%sym)) then ABI_DEALLOCATE(sym%sym) end if if (associated(sym%symAfm)) then ABI_DEALLOCATE(sym%symAfm) end if if (associated(sym%transNon)) then ABI_DEALLOCATE(sym%transNon) end if end subroutine free_symmetry subroutine symmetry_new(id) !This section has been created automatically by the script Abilint (TD). !Do not modify the following lines by hand. #undef ABI_FUNC #define ABI_FUNC 'symmetry_new' !End of the abilint section integer, intent(out) :: id type(symmetry_list), pointer :: token if (AB_DBG) write(std_err,*) "AB symmetry: call new symmetry." call new_item(token) id = token%id end subroutine symmetry_new subroutine symmetry_free(id) !This section has been created automatically by the script Abilint (TD). !Do not modify the following lines by hand. #undef ABI_FUNC #define ABI_FUNC 'symmetry_free' !End of the abilint section integer, intent(in) :: id type(symmetry_list), pointer :: token if (AB_DBG) write(std_err,*) "AB symmetry: call free symmetry." call get_item(token, id) if (associated(token)) then call free_item(token) end if end subroutine symmetry_free subroutine symmetry_set_tolerance(id, tolsym, errno) !This section has been created automatically by the script Abilint (TD). !Do not modify the following lines by hand. #undef ABI_FUNC #define ABI_FUNC 'symmetry_set_tolerance' !End of the abilint section integer, intent(in) :: id real(dp), intent(in) :: tolsym integer, intent(out) :: errno type(symmetry_list), pointer :: token if (AB_DBG) write(std_err,*) "AB symmetry: call set tolerance." errno = AB7_NO_ERROR call get_item(token, id) if (.not. associated(token)) then errno = AB7_ERROR_OBJ return end if token%data%tolsym = tolsym ! We unset all the computed symmetries token%data%nBravSym = -1 if (token%data%auto) then token%data%nSym = 0 end if end subroutine symmetry_set_tolerance subroutine symmetry_set_lattice(id, rprimd, errno) !This section has been created automatically by the script Abilint (TD). !Do not modify the following lines by hand. #undef ABI_FUNC #define ABI_FUNC 'symmetry_set_lattice' use interfaces_41_geometry !End of the abilint section integer, intent(in) :: id real(dp), intent(in) :: rprimd(3,3) integer, intent(out) :: errno type(symmetry_list), pointer :: token real(dp) :: ucvol real(dp) :: gmet(3,3) if (AB_DBG) write(std_err,*) "AB symmetry: call set lattice." if (AB_DBG) write(std_err, "(A,3F12.6,A)") " (", rprimd(:,1), ")" if (AB_DBG) write(std_err, "(A,3F12.6,A)") " (", rprimd(:,2), ")" if (AB_DBG) write(std_err, "(A,3F12.6,A)") " (", rprimd(:,3), ")" errno = AB7_NO_ERROR call get_item(token, id) if (.not. associated(token)) then errno = AB7_ERROR_OBJ return end if token%data%rprimd = rprimd call metric(gmet, token%data%gprimd, -1, token%data%rmet, rprimd, ucvol) ! We unset all the computed symmetries token%data%nBravSym = -1 if (token%data%auto) then token%data%nSym = 0 end if end subroutine symmetry_set_lattice subroutine symmetry_set_structure(id, nAtoms, typeAt, xRed, errno) !This section has been created automatically by the script Abilint (TD). !Do not modify the following lines by hand. #undef ABI_FUNC #define ABI_FUNC 'symmetry_set_structure' !End of the abilint section integer, intent(in) :: id integer, intent(in) :: nAtoms integer, intent(in) :: typeAt(nAtoms) real(dp), intent(in) :: xRed(3,nAtoms) integer, intent(out) :: errno type(symmetry_list), pointer :: token integer :: i if (AB_DBG) write(std_err,*) "AB symmetry: call set structure." if (AB_DBG) write(std_err, "(A,I3,A)") " ", nAtoms, " atoms" if (AB_DBG) then do i = 1, nAtoms, 1 if (AB_DBG) write(std_err,"(A,3F12.6,I3)") " ", xRed(:, i), typeAt(i) end do end if errno = AB7_NO_ERROR call get_item(token, id) if (.not. associated(token)) then errno = AB7_ERROR_OBJ return end if token%data%nAtoms = nAtoms ABI_ALLOCATE(token%data%typeAt,(nAtoms)) token%data%typeAt = typeAt ABI_ALLOCATE(token%data%xRed,(3, nAtoms)) token%data%xRed = xRed ! We unset only the symmetries if (token%data%auto) then token%data%nSym = 0 end if if (associated(token%data%indexingAtoms)) then ABI_DEALLOCATE(token%data%indexingAtoms) end if end subroutine symmetry_set_structure subroutine symmetry_set_spin(id, nAtoms, spinAt, errno) !This section has been created automatically by the script Abilint (TD). !Do not modify the following lines by hand. #undef ABI_FUNC #define ABI_FUNC 'symmetry_set_spin' !End of the abilint section integer, intent(in) :: id integer, intent(in) :: nAtoms real(dp), intent(in) :: spinAt(3,nAtoms) integer, intent(out) :: errno type(symmetry_list), pointer :: token integer :: i if (AB_DBG) write(std_err,*) "AB symmetry: call set spin." if (AB_DBG) then do i = 1, nAtoms, 1 if (AB_DBG) write(std_err,"(A,3F12.6)") " ", spinAt(:, i) end do end if errno = AB7_NO_ERROR call get_item(token, id) if (.not. associated(token)) then errno = AB7_ERROR_OBJ return end if if (token%data%nAtoms /= nAtoms) then errno = AB7_ERROR_ARG return end if token%data%withSpin = 4 ABI_ALLOCATE(token%data%spinAt,(3, nAtoms)) token%data%spinAt = spinAt ! We unset only the symmetries if (token%data%auto) then token%data%nSym = 0 end if end subroutine symmetry_set_spin subroutine symmetry_set_collinear_spin(id, nAtoms, spinAt, errno) !This section has been created automatically by the script Abilint (TD). !Do not modify the following lines by hand. #undef ABI_FUNC #define ABI_FUNC 'symmetry_set_collinear_spin' !End of the abilint section integer, intent(in) :: id integer, intent(in) :: nAtoms integer, intent(in) :: spinAt(nAtoms) integer, intent(out) :: errno type(symmetry_list), pointer :: token integer :: i if (AB_DBG) write(std_err,*) "AB symmetry: call set collinear spin." if (AB_DBG) then do i = 1, nAtoms, 1 if (AB_DBG) write(std_err,"(A,I3)") " ", spinAt(i) end do end if errno = AB7_NO_ERROR call get_item(token, id) if (.not. associated(token)) then errno = AB7_ERROR_OBJ return end if if (token%data%nAtoms /= nAtoms) then errno = AB7_ERROR_ARG return end if token%data%withSpin = 2 ABI_ALLOCATE(token%data%spinAt,(3,nAtoms)) token%data%spinAt = 0._dp token%data%spinAt(3, :) = real(spinAt) ! We unset only the symmetries if (token%data%auto) then token%data%nSym = 0 end if end subroutine symmetry_set_collinear_spin subroutine symmetry_set_spin_orbit(id, withSpinOrbit, errno) !This section has been created automatically by the script Abilint (TD). !Do not modify the following lines by hand. #undef ABI_FUNC #define ABI_FUNC 'symmetry_set_spin_orbit' !End of the abilint section integer, intent(in) :: id logical, intent(in) :: withSpinOrbit integer, intent(out) :: errno type(symmetry_list), pointer :: token if (AB_DBG) write(std_err,*) "AB symmetry: call set spin orbit." errno = AB7_NO_ERROR call get_item(token, id) if (.not. associated(token)) then errno = AB7_ERROR_OBJ return end if token%data%withSpinOrbit = withSpinOrbit ! We unset only the symmetries if (token%data%auto) then token%data%nSym = 0 end if end subroutine symmetry_set_spin_orbit subroutine symmetry_set_field(id, field, errno) !This section has been created automatically by the script Abilint (TD). !Do not modify the following lines by hand. #undef ABI_FUNC #define ABI_FUNC 'symmetry_set_field' !End of the abilint section integer, intent(in) :: id real(dp), intent(in) :: field(3) integer, intent(out) :: errno type(symmetry_list), pointer :: token if (AB_DBG) write(std_err,*) "AB symmetry: call set field." errno = AB7_NO_ERROR call get_item(token, id) if (.not. associated(token)) then errno = AB7_ERROR_OBJ return end if token%data%withField = .true. token%data%field = field ! We unset all the computed symmetries token%data%nBravSym = -1 if (token%data%auto) then token%data%nSym = 0 end if end subroutine symmetry_set_field subroutine symmetry_set_jellium(id, jellium, errno) !This section has been created automatically by the script Abilint (TD). !Do not modify the following lines by hand. #undef ABI_FUNC #define ABI_FUNC 'symmetry_set_jellium' !End of the abilint section integer, intent(in) :: id logical, intent(in) :: jellium integer, intent(out) :: errno type(symmetry_list), pointer :: token if (AB_DBG) write(std_err,*) "AB symmetry: call set jellium." errno = AB7_NO_ERROR call get_item(token, id) if (.not. associated(token)) then errno = AB7_ERROR_OBJ return end if token%data%withJellium = jellium ! We unset only the symmetries if (token%data%auto) then token%data%nSym = 0 end if end subroutine symmetry_set_jellium subroutine symmetry_set_periodicity(id, periodic, errno) !This section has been created automatically by the script Abilint (TD). !Do not modify the following lines by hand. #undef ABI_FUNC #define ABI_FUNC 'symmetry_set_periodicity' !End of the abilint section integer, intent(in) :: id logical, intent(in) :: periodic(3) integer, intent(out) :: errno type(symmetry_list), pointer :: token if (AB_DBG) write(std_err,*) "AB symmetry: call set periodicity." if (AB_DBG) write(std_err, "(A,3L1,A)") " (", periodic, ")" errno = AB7_NO_ERROR call get_item(token, id) if (.not. associated(token)) then errno = AB7_ERROR_OBJ return end if token%data%vacuum = 0 if (.not. periodic(1)) token%data%vacuum(1) = 1 if (.not. periodic(2)) token%data%vacuum(2) = 1 if (.not. periodic(3)) token%data%vacuum(3) = 1 end subroutine symmetry_set_periodicity subroutine symmetry_get_n_atoms(id, nAtoms, errno) !scalars !This section has been created automatically by the script Abilint (TD). !Do not modify the following lines by hand. #undef ABI_FUNC #define ABI_FUNC 'symmetry_get_n_atoms' !End of the abilint section integer, intent(in) :: id integer, intent(out) :: errno integer, intent(out) :: nAtoms type(symmetry_list), pointer :: token if (AB_DBG) write(std_err,*) "AB symmetry: call get nAtoms." errno = AB7_NO_ERROR call get_item(token, id) if (.not. associated(token)) then errno = AB7_ERROR_OBJ return end if nAtoms = token%data%nAtoms end subroutine symmetry_get_n_atoms subroutine compute_bravais(sym) !This section has been created automatically by the script Abilint (TD). !Do not modify the following lines by hand. #undef ABI_FUNC #define ABI_FUNC 'compute_bravais' use interfaces_41_geometry !End of the abilint section type(symmetry_type), intent(inout) :: sym integer :: berryopt ! We do the computation if (sym%withField) then berryopt = 4 else berryopt = 0 end if if (AB_DBG) write(std_err,*) "AB symmetry: call ABINIT symlatt." call symlatt(sym%bravais, AB7_MAX_SYMMETRIES, & & sym%nBravSym, sym%bravSym, sym%rprimd, sym%tolsym) if (AB_DBG) write(std_err,*) "AB symmetry: call ABINIT OK." if (AB_DBG) write(std_err, "(A,I3)") " nSymBrav :", sym%nBravSym if (AB_DBG) write(std_err, "(A,I3)") " holohedry:", sym%bravais(1) if (AB_DBG) write(std_err, "(A,I3)") " center :", sym%bravais(2) end subroutine compute_bravais subroutine symmetry_get_bravais(id, bravais, holohedry, center, & & nBravSym, bravSym, errno) !scalars !This section has been created automatically by the script Abilint (TD). !Do not modify the following lines by hand. #undef ABI_FUNC #define ABI_FUNC 'symmetry_get_bravais' !End of the abilint section integer, intent(in) :: id integer, intent(out) :: errno integer, intent(out) :: nBravSym, holohedry, center !arrays integer, intent(out) :: bravais(3,3), bravSym(3, 3, AB7_MAX_SYMMETRIES) type(symmetry_list), pointer :: token if (AB_DBG) write(std_err,*) "AB symmetry: call get bravais." errno = AB7_NO_ERROR call get_item(token, id) if (.not. associated(token)) then errno = AB7_ERROR_OBJ return end if if (token%data%nBravSym < 0) then ! We do the computation call compute_bravais(token%data) end if holohedry = token%data%bravais(1) center = token%data%bravais(2) bravais = reshape(token%data%bravais(3:11), (/ 3,3 /)) nBravSym = token%data%nBravSym bravSym(:, :, 1:nBravSym) = token%data%bravSym(:, :, 1:nBravSym) end subroutine symmetry_get_bravais subroutine compute_matrices(sym, errno) !This section has been created automatically by the script Abilint (TD). !Do not modify the following lines by hand. #undef ABI_FUNC #define ABI_FUNC 'compute_matrices' use interfaces_41_geometry !End of the abilint section type(symmetry_type), intent(inout) :: sym integer, intent(out) :: errno integer :: berryopt, jellslab, noncol integer :: use_inversion real(dp), pointer :: spinAt_(:,:) integer :: sym_(3, 3, AB7_MAX_SYMMETRIES) real(dp) :: transNon_(3, AB7_MAX_SYMMETRIES) integer :: symAfm_(AB7_MAX_SYMMETRIES) errno = AB7_NO_ERROR if (sym%nBravSym < 0) then ! We do the computation of the Bravais part. call compute_bravais(sym) end if if (sym%withField) then berryopt = 4 else berryopt = 0 end if if (sym%withJellium) then jellslab = 1 else jellslab = 0 end if if (sym%withSpin == 4) then noncol = 1 spinAt_ => sym%spinAt else if (sym%withSpin == 2) then noncol = 0 spinAt_ => sym%spinAt else noncol = 0 ABI_ALLOCATE(spinAt_,(3, sym%nAtoms)) spinAt_ = 0 end if if (sym%withSpinOrbit) then use_inversion = 0 else use_inversion = 1 end if if (sym%nsym == 0) then if (AB_DBG) write(std_err,*) "AB symmetry: call ABINIT symfind." call symfind(berryopt, sym%field, sym%gprimd, jellslab, AB7_MAX_SYMMETRIES, & & sym%nAtoms, noncol, sym%nBravSym, sym%nSym, sym%bravSym, spinAt_, & & symAfm_, sym_, transNon_, sym%tolsym, sym%typeAt, & & use_inversion, sym%xRed) if (AB_DBG) write(std_err,*) "AB symmetry: call ABINIT OK." if (AB_DBG) write(std_err, "(A,I3)") " nSym:", sym%nSym if (associated(sym%sym)) then ABI_DEALLOCATE(sym%sym) end if if (associated(sym%symAfm)) then ABI_DEALLOCATE(sym%symAfm) end if if (associated(sym%transNon)) then ABI_DEALLOCATE(sym%transNon) end if ABI_ALLOCATE(sym%sym,(3, 3, sym%nSym)) sym%sym(:,:,:) = sym_(:,:, 1:sym%nSym) ABI_ALLOCATE(sym%symAfm,(sym%nSym)) sym%symAfm(:) = symAfm_(1:sym%nSym) ABI_ALLOCATE(sym%transNon,(3, sym%nSym)) sym%transNon(:,:) = transNon_(:, 1:sym%nSym) else if (sym%nsym < 0) then sym%nsym = -sym%nsym sym_(:,:, 1:sym%nSym) = sym%sym(:,:,:) transNon_(:, 1:sym%nSym) = sym%transNon(:,:) symAfm_(1:sym%nSym) = sym%symAfm(:) end if if (sym%withSpin == 1) then ABI_DEALLOCATE(spinAt_) end if if (AB_DBG) write(std_err,*) "AB symmetry: call ABINIT symanal." call symanal(sym%bravais, 0, sym%genAfm, AB7_MAX_SYMMETRIES, sym%nSym, & & sym%pointGroupMagn, sym%rprimd, sym%spaceGroup, symAfm_, & & sym_, transNon_, sym%tolsym) if (AB_DBG) write(std_err,*) "AB symmetry: call ABINIT OK." sym%transNon(:,:) = transNon_(:, 1:sym%nSym) if (sym%bravais(1) < 0) then sym%multiplicity = 2 else sym%multiplicity = 1 end if if (AB_DBG) write(std_err, "(A,I3)") " multi:", sym%multiplicity if (AB_DBG) write(std_err, "(A,I3)") " space:", sym%spaceGroup end subroutine compute_matrices subroutine symmetry_get_n_sym(id, nSym, errno) !scalars !This section has been created automatically by the script Abilint (TD). !Do not modify the following lines by hand. #undef ABI_FUNC #define ABI_FUNC 'symmetry_get_n_sym' !End of the abilint section integer, intent(in) :: id integer, intent(out) :: errno integer, intent(out) :: nSym type(symmetry_list), pointer :: token if (AB_DBG) write(std_err,*) "AB symmetry: call get nSym." errno = AB7_NO_ERROR call get_item(token, id) if (.not. associated(token)) then errno = AB7_ERROR_OBJ return end if if (token%data%nSym <= 0) then ! We do the computation of the matrix part. call compute_matrices(token%data, errno) end if nSym = token%data%nSym end subroutine symmetry_get_n_sym subroutine symmetry_set_n_sym(id, nSym, sym, transNon, symAfm, errno) !scalars !This section has been created automatically by the script Abilint (TD). !Do not modify the following lines by hand. #undef ABI_FUNC #define ABI_FUNC 'symmetry_set_n_sym' !End of the abilint section integer, intent(in) :: id integer, intent(in) :: nSym integer, intent(in) :: sym(3, 3, nSym) real(dp), intent(in) :: transNon(3, nSym) integer, intent(in) :: symAfm(nSym) integer, intent(out) :: errno type(symmetry_list), pointer :: token if (AB_DBG) write(std_err,*) "AB symmetry: call get nSym." errno = AB7_NO_ERROR call get_item(token, id) if (.not. associated(token)) then errno = AB7_ERROR_OBJ return end if if (nSym <= 0) then errno = AB7_ERROR_ARG return else ABI_ALLOCATE(token%data%sym, (3, 3, nSym)) token%data%sym(:,:,:) = sym(:,:,:) ABI_ALLOCATE(token%data%symAfm, (nSym)) token%data%symAfm(:) = symAfm(:) ABI_ALLOCATE(token%data%transNon, (3, nSym)) token%data%transNon(:,:) = transNon(:,:) token%data%auto = .false. token%data%nsym = -nSym end if ! We do the computation of the matrix part. call compute_matrices(token%data, errno) end subroutine symmetry_set_n_sym subroutine symmetry_get_matrices(id, nSym, sym, transNon, symAfm, errno) !This section has been created automatically by the script Abilint (TD). !Do not modify the following lines by hand. #undef ABI_FUNC #define ABI_FUNC 'symmetry_get_matrices' !End of the abilint section integer, intent(in) :: id integer, intent(out) :: errno integer, intent(out) :: nSym integer, intent(out) :: sym(3, 3, AB7_MAX_SYMMETRIES) integer, intent(out) :: symAfm(AB7_MAX_SYMMETRIES) real(dp), intent(out) :: transNon(3, AB7_MAX_SYMMETRIES) type(symmetry_list), pointer :: token if (AB_DBG) write(std_err,*) "AB symmetry: call get matrices." errno = AB7_NO_ERROR call get_item(token, id) if (.not. associated(token)) then errno = AB7_ERROR_OBJ return end if if (token%data%nSym <= 0) then ! We do the computation of the matrix part. call compute_matrices(token%data, errno) end if nSym = token%data%nSym sym(:, :, 1:nSym) = token%data%sym(:, :,:) symAfm(1:nSym) = token%data%symAfm(:) transNon(:, 1:nSym) = token%data%transNon(:,:) end subroutine symmetry_get_matrices subroutine symmetry_get_matrices_p(id, nSym, sym, transNon, symAfm, errno) !This section has been created automatically by the script Abilint (TD). !Do not modify the following lines by hand. #undef ABI_FUNC #define ABI_FUNC 'symmetry_get_matrices_p' !End of the abilint section integer, intent(in) :: id integer, intent(out) :: errno integer, intent(out) :: nSym integer, pointer :: sym(:,:,:) integer, pointer :: symAfm(:) real(dp), pointer :: transNon(:,:) type(symmetry_list), pointer :: token if (AB_DBG) write(std_err,*) "AB symmetry: call get matrices as pointers." errno = AB7_NO_ERROR call get_item(token, id) if (.not. associated(token)) then errno = AB7_ERROR_OBJ return end if if (token%data%nSym <= 0) then ! We do the computation of the matrix part. call compute_matrices(token%data, errno) end if nSym = token%data%nSym sym => token%data%sym symAfm => token%data%symAfm transNon => token%data%transNon end subroutine symmetry_get_matrices_p subroutine symmetry_get_multiplicity(id, multiplicity, errno) !This section has been created automatically by the script Abilint (TD). !Do not modify the following lines by hand. #undef ABI_FUNC #define ABI_FUNC 'symmetry_get_multiplicity' !End of the abilint section integer, intent(in) :: id integer, intent(out) :: multiplicity, errno type(symmetry_list), pointer :: token if (AB_DBG) write(std_err,*) "AB symmetry: call get multiplicity." errno = AB7_NO_ERROR call get_item(token, id) if (.not. associated(token)) then errno = AB7_ERROR_OBJ return end if if (token%data%multiplicity < 0) then ! We do the computation of the matrix part. call compute_matrices(token%data, errno) end if multiplicity = token%data%multiplicity end subroutine symmetry_get_multiplicity subroutine symmetry_get_group(id, spaceGroup, spaceGroupId, & & pointGroupMagn, genAfm, errno) !This section has been created automatically by the script Abilint (TD). !Do not modify the following lines by hand. #undef ABI_FUNC #define ABI_FUNC 'symmetry_get_group' use interfaces_41_geometry !End of the abilint section integer, intent(in) :: id integer, intent(out) :: errno real(dp), intent(out) :: genAfm(3) character(len=15), intent(out) :: spaceGroup integer, intent(out) :: spaceGroupId, pointGroupMagn type(symmetry_list), pointer :: token integer :: sporder character(len=1) :: brvLattice character(len=15) :: ptintsb,ptschsb,schsb,spgrp character(len=35) :: intsbl if (AB_DBG) write(std_err,*) "AB symmetry: call get group." errno = AB7_NO_ERROR call get_item(token, id) if (.not. associated(token)) then errno = AB7_ERROR_OBJ return end if if (token%data%multiplicity < 0) then ! We do the computation of the matrix part. call compute_matrices(token%data, errno) end if if (token%data%multiplicity /= 1) then errno = AB7_ERROR_SYM_NOT_PRIMITIVE return end if call spgdata(brvLattice,spgrp,intsbl,ptintsb,ptschsb,& & schsb,1,token%data%spaceGroup,sporder,1) write(spaceGroup, "(3A)") brvLattice, " ", trim(spgrp(1:13)) pointGroupMagn = token%data%pointGroupMagn spaceGroupId = token%data%spaceGroup genAfm = token%data%genAfm end subroutine symmetry_get_group subroutine compute_equivalent_atoms(sym) !This section has been created automatically by the script Abilint (TD). !Do not modify the following lines by hand. #undef ABI_FUNC #define ABI_FUNC 'compute_equivalent_atoms' use interfaces_32_util use interfaces_41_geometry !End of the abilint section type(symmetry_type), intent(inout) :: sym integer, allocatable :: symrec(:,:,:) integer :: isym if (.not. associated(sym%indexingAtoms)) then ABI_ALLOCATE(sym%indexingAtoms,(4, sym%nSym, sym%nAtoms)) end if !Get the symmetry matrices in terms of reciprocal basis ABI_ALLOCATE(symrec,(3, 3, sym%nSym)) do isym = 1, sym%nSym, 1 call mati3inv(sym%sym(:,:,isym), symrec(:,:,isym)) end do !Obtain a list of rotated atom labels: call symatm(sym%indexingAtoms, sym%nAtoms, sym%nSym, symrec, & & sym%transNon, sym%tolsym, sym%typeAt, sym%xRed) ABI_DEALLOCATE(symrec) end subroutine compute_equivalent_atoms subroutine symmetry_get_equivalent_atom(id, equiv, iAtom, errno) !This section has been created automatically by the script Abilint (TD). !Do not modify the following lines by hand. #undef ABI_FUNC #define ABI_FUNC 'symmetry_get_equivalent_atom' !End of the abilint section integer, intent(in) :: id integer, intent(in) :: iAtom integer, intent(out) :: equiv(4, AB7_MAX_SYMMETRIES) integer, intent(out) :: errno type(symmetry_list), pointer :: token if (AB_DBG) write(std_err,*) "AB symmetry: call get equivalent." errno = AB7_NO_ERROR call get_item(token, id) if (.not. associated(token)) then errno = AB7_ERROR_OBJ return end if if (iAtom < 1 .or. iAtom > token%data%nAtoms) then errno = AB7_ERROR_ARG return end if if (.not. associated(token%data%indexingAtoms)) then ! We do the computation of the matrix part. call compute_equivalent_atoms(token%data) end if equiv(:, 1:token%data%nSym) = token%data%indexingAtoms(:,:,iAtom) end subroutine symmetry_get_equivalent_atom subroutine symmetry_get_type(id, iSym, label, type, errno) !This section has been created automatically by the script Abilint (TD). !Do not modify the following lines by hand. #undef ABI_FUNC #define ABI_FUNC 'symmetry_get_type' use interfaces_32_util use interfaces_41_geometry !End of the abilint section integer, intent(in) :: id, iSym character(len = 128), intent(out) :: label integer, intent(out) :: errno, type integer :: det type(symmetry_list), pointer :: token type(symmetry_type), pointer :: sym if (AB_DBG) write(std_err,*) "AB symmetry: call get type." errno = AB7_NO_ERROR call get_item(token, id) if (.not. associated(token)) then errno = AB7_ERROR_OBJ return end if sym => token%data if (iSym < 1 .or. iSym > sym%nSym) then errno = AB7_ERROR_ARG return end if if (sym%multiplicity < 0) then ! We do the computation of the matrix part. call compute_matrices(sym, errno) end if ! Calculate determinant. call mati3det(sym%sym(:,:,iSym),det) call symcharac(sym%bravais(2), det, sym%bravais(1), iSym, label, & sym%sym(:,:,iSym), sym%transNon(:, iSym), type) end subroutine symmetry_get_type end module m_ab7_symmetry !!*** v_sim-3.8.0/lib/plug-ins/abinit/m_build_info.F90000066400000000000000000000161531370110300500213130ustar00rootroot00000000000000!{\src2tex{textfont=tt}} !!****m* ABINIT/m_build_info !! NAME !! m_build_info !! !! FUNCTION !! This module contains information about this particular version of ABINIT !! and its build parameters (useful for debugging). !! !! COPYRIGHT !! Copyright (C) 2005-2016 ABINIT group (Yann Pouillon, Matteo Giantomassi) !! This file is distributed under the terms of the !! GNU General Public License, see ~abinit/COPYING !! or http://www.gnu.org/copyleft/gpl.txt . !! !! SOURCE #if defined HAVE_CONFIG_H #include "config.h" #endif module m_build_info implicit none ! Try to prevent problems with the length of the argument ! (should not exceed the line length of 132 character). ! So, always start the string to be replaced at the beginning of a line. ! Parameters set-up by Autoconf character(len=8),parameter :: abinit_version = & & "@VERSION@" character(len=*),parameter :: build_target = & & "@ABINIT_TARGET@" ! More info on current version character(len=*),parameter :: version_major = & & "@ABINIT_VERSION_MAJOR@" character(len=*),parameter :: version_minor = & & "@ABINIT_VERSION_MINOR@" character(len=*),parameter :: version_micro = & & "@ABINIT_VERSION_MICRO@" character(len=*),parameter :: version_build = & & "@ABINIT_VERSION_BUILD@" ! Info on compilers. Try to prevent problems with the length of the argument ! (should not exceed the line length of 132 character). character(len=*),parameter :: cc_info = & & "@abi_cc_vendor@@abi_cc_version@" character(len=*),parameter :: cxx_info = & & "@abi_cxx_vendor@@abi_cxx_version@" character(len=*),parameter :: fc_info = & & "@abi_fc_vendor@@abi_fc_version@" character(len=*),parameter :: cc_flags = & & "@CFLAGS@" character(len=*),parameter :: cxx_flags = & & "@CXXFLAGS@" character(len=*),parameter :: fc_flags = & & "@FCFLAGS@" character(len=*),parameter :: fc_ldflags = & & "@FC_LDFLAGS@" ! Info on optimizations character(len=*),parameter :: enable_debug = & & "@enable_debug@" character(len=*),parameter :: enable_optim = & & "@enable_optim@" character(len=*),parameter :: cpu_info = & & "@abi_cpu_vendor@_@abi_cpu_model@" ! Info on MPI character(len=*),parameter :: enable_mpi = & & "@enable_mpi@" character(len=*),parameter :: enable_mpi_io = & & "@enable_mpi_io@" ! Info on openMP character(len=*),parameter :: enable_openmp = & & "@enable_openmp@" ! Info on GPU character(len=*),parameter :: enable_gpu = & & "@enable_gpu@" ! Info on connectors / fallbacks character(len=*),parameter :: enable_connectors = & & "@enable_connectors@" character(len=*),parameter :: enable_fallbacks = & & "@enable_fallbacks@" character(len=*),parameter :: dft_flavor = & & "@lib_dft_flavor@" character(len=*),parameter :: fft_flavor = & & "@lib_fft_flavor@" character(len=*),parameter :: linalg_flavor = & & "@lib_linalg_flavor@" character(len=*),parameter :: math_flavor = & & "@lib_math_flavor@" character(len=*),parameter :: timer_flavor = & & "@lib_timer_flavor@" character(len=*),parameter :: trio_flavor = & & "@lib_trio_flavor@" ! Info on experimental features character(len=*),parameter :: enable_bindings = & & "@enable_bindings@" character(len=*),parameter :: enable_exports = & & "@enable_exports@" character(len=*),parameter :: enable_gw_dpc = & & "@enable_gw_dpc@" #if defined HAVE_BZR_BRANCH ! Info on Bazaar branch (if applies) character(len=*),parameter :: bzr_branch = & & "@bzr_branch@" character(len=*),parameter :: bzr_revno = & & "@bzr_revno@" character(len=*),parameter :: bzr_clean = & & "@bzr_clean@" #endif contains !=========================================================== !!*** !!****f* ABINIT/m_build_info/dump_config !! NAME !! dump_config !! !! FUNCTION !! Reports a printout of the information stored in m_build_info, !! useful for error messages and debugging. !! !! INPUTS !! my_unit= Fortran unit number !! !! OUTPUT !! Only printing !! !! PARENTS !! Will be filled automatically by the parent script !! !! CHILDREN !! Will be filled automatically by the parent script !! !! SOURCE subroutine dump_config(my_unit) implicit none !Arguments ------------------------------------ integer,intent(in) :: my_unit !Local variables------------------------------- ! ********************************************************************* ! TODO: things that might be added through preprocessing options, e.g. ! date and time of compilation write(my_unit,*) write(my_unit,'(1x,a)') repeat('+',78) write(my_unit,*) write(my_unit,'(a)' )' === Build Information === ' write(my_unit,'(2a)')' Version : ',trim(abinit_version) write(my_unit,'(2a)')' Build target : ',trim(build_target) write(my_unit,'(2a)')' Build date : ',trim(version_build) write(my_unit,*) write(my_unit,'(a)' )' === Compiler Suite === ' write(my_unit,'(2a)')' C compiler : ',trim(cc_info) write(my_unit,'(2a)')' C++ compiler : ',trim(cxx_info) write(my_unit,'(2a)')' Fortran compiler : ',trim(fc_info) write(my_unit,'(2a)')' CFLAGS : ',trim(cc_flags) write(my_unit,'(2a)')' CXXFLAGS : ',trim(cxx_flags) write(my_unit,'(2a)')' FCFLAGS : ',trim(fc_flags) write(my_unit,'(2a)')' FC_LDFLAGS : ',trim(fc_ldflags) write(my_unit,*) write(my_unit,'(a) ')' === Optimizations === ' write(my_unit,'(2a)')' Debug level : ',trim(enable_debug) write(my_unit,'(2a)')' Optimization level : ',trim(enable_optim) write(my_unit,'(2a)')' Architecture : ',trim(cpu_info) write(my_unit,*) write(my_unit,'(a) ')' === Multicore === ' write(my_unit,'(2a)')' Parallel build : ',trim(enable_mpi) write(my_unit,'(2a)')' Parallel I/O : ',trim(enable_mpi_io) write(my_unit,'(2a)')' openMP support : ',trim(enable_openmp) write(my_unit,'(2a)')' GPU support : ',trim(enable_gpu) write(my_unit,*) write(my_unit,'(a) ')' === Connectors / Fallbacks === ' write(my_unit,'(2a)')' Connectors on : ',trim(enable_connectors) write(my_unit,'(2a)')' Fallbacks on : ',trim(enable_fallbacks) write(my_unit,'(2a)')' DFT flavor : ',trim(dft_flavor) write(my_unit,'(2a)')' FFT flavor : ',trim(fft_flavor) write(my_unit,'(2a)')' LINALG flavor : ',trim(linalg_flavor) write(my_unit,'(2a)')' MATH flavor : ',trim(math_flavor) write(my_unit,'(2a)')' TIMER flavor : ',trim(timer_flavor) write(my_unit,'(2a)')' TRIO flavor : ',trim(trio_flavor) write(my_unit,*) write(my_unit,'(a)' )' === Experimental features === ' write(my_unit,'(2a)')' Bindings : ',trim(enable_bindings) write(my_unit,'(2a)')' Exports : ',trim(enable_exports) write(my_unit,'(2a)')' GW double-precision : ',trim(enable_gw_dpc) write(my_unit,*) #if defined HAVE_BZR_BRANCH write(my_unit,'(a)' )' === Bazaar branch information === ' write(my_unit,'(2a)')' Branch ID : ',trim(bzr_branch) write(my_unit,'(2a)')' Revision : ',trim(bzr_revno) write(my_unit,'(2a)')' Committed : ',trim(bzr_clean) write(my_unit,*) #endif write(my_unit,'(1x,a)') repeat('+',78) write(my_unit,*) end subroutine dump_config !!*** end module m_build_info !!*** v_sim-3.8.0/lib/plug-ins/abinit/m_cppopts_dumper.F90000066400000000000000000001201301370110300500222340ustar00rootroot00000000000000!{\src2tex{textfont=tt}} !!****m* ABINIT/m_cppopts_dumper !! NAME !! m_cppopts_dumper !! !! FUNCTION !! Displays preprocessing options activated at compile-time. !! !! COPYRIGHT !! Copyright (C) 2010-2016 ABINIT group (Yann Pouillon) !! This file is distributed under the terms of the !! GNU General Public License, see ~abinit/COPYING !! or http://www.gnu.org/copyleft/gpl.txt. !! !! NOTES !! This file was generated by make-cppopts-dumper, !! on 2016/07/21 07:23:54 +0000. !! Any modification will be lost. !! !! PARENTS !! !! CHILDREN !! !! SOURCE #if defined HAVE_CONFIG_H #include "config.h" #endif module m_cppopts_dumper implicit none public :: dump_cpp_options contains !!*** !!****f* ABINIT/m_cppopts_dumper/dump_cpp_options !! NAME !! dump_cpp_options !! !! FUNCTION !! Reports a printout of the CPP options used at compile-time, !! useful for error messages and debugging. !! !! INPUTS !! my_unit= Fortran unit number (optional, default is std_out) !! !! OUTPUT !! Only printing. !! !! PARENTS !! !! CHILDREN !! !! SOURCE subroutine dump_cpp_options(my_unit) use defs_basis !This section has been created automatically by the script Abilint (TD). !Do not modify the following lines by hand. #undef ABI_FUNC #define ABI_FUNC 'dump_cpp_options' !End of the abilint section implicit none !Arguments ------------------------------------- integer,intent(in) :: my_unit !Local variables ------------------------------- character(len=26) :: tmp character(len=80) :: msg integer :: msg_index ! ********************************************************************** write(my_unit,"(a,1x,a)") ch10,repeat("+",78) write(my_unit,"(1x,a,a)") "CPP options activated during the build:",ch10 msg_index = 0 msg = "" #if defined CC_COMPAQ write(tmp,"(1x,a25)") "CC_COMPAQ" msg = trim(msg)//trim(tmp) msg_index = msg_index + 1 if ( mod(msg_index,3) == 0 ) then msg = trim(msg)//ch10 write(my_unit,'(a)') msg msg = "" end if #endif #if defined CC_GNU write(tmp,"(1x,a25)") "CC_GNU" msg = trim(msg)//trim(tmp) msg_index = msg_index + 1 if ( mod(msg_index,3) == 0 ) then msg = trim(msg)//ch10 write(my_unit,'(a)') msg msg = "" end if #endif #if defined CC_IBM write(tmp,"(1x,a25)") "CC_IBM" msg = trim(msg)//trim(tmp) msg_index = msg_index + 1 if ( mod(msg_index,3) == 0 ) then msg = trim(msg)//ch10 write(my_unit,'(a)') msg msg = "" end if #endif #if defined CC_INTEL write(tmp,"(1x,a25)") "CC_INTEL" msg = trim(msg)//trim(tmp) msg_index = msg_index + 1 if ( mod(msg_index,3) == 0 ) then msg = trim(msg)//ch10 write(my_unit,'(a)') msg msg = "" end if #endif #if defined CC_OPEN64 write(tmp,"(1x,a25)") "CC_OPEN64" msg = trim(msg)//trim(tmp) msg_index = msg_index + 1 if ( mod(msg_index,3) == 0 ) then msg = trim(msg)//ch10 write(my_unit,'(a)') msg msg = "" end if #endif #if defined CC_PATHSCALE write(tmp,"(1x,a25)") "CC_PATHSCALE" msg = trim(msg)//trim(tmp) msg_index = msg_index + 1 if ( mod(msg_index,3) == 0 ) then msg = trim(msg)//ch10 write(my_unit,'(a)') msg msg = "" end if #endif #if defined CC_PGI write(tmp,"(1x,a25)") "CC_PGI" msg = trim(msg)//trim(tmp) msg_index = msg_index + 1 if ( mod(msg_index,3) == 0 ) then msg = trim(msg)//ch10 write(my_unit,'(a)') msg msg = "" end if #endif #if defined CC_SUN write(tmp,"(1x,a25)") "CC_SUN" msg = trim(msg)//trim(tmp) msg_index = msg_index + 1 if ( mod(msg_index,3) == 0 ) then msg = trim(msg)//ch10 write(my_unit,'(a)') msg msg = "" end if #endif #if defined CXX_COMPAQ write(tmp,"(1x,a25)") "CXX_COMPAQ" msg = trim(msg)//trim(tmp) msg_index = msg_index + 1 if ( mod(msg_index,3) == 0 ) then msg = trim(msg)//ch10 write(my_unit,'(a)') msg msg = "" end if #endif #if defined CXX_GNU write(tmp,"(1x,a25)") "CXX_GNU" msg = trim(msg)//trim(tmp) msg_index = msg_index + 1 if ( mod(msg_index,3) == 0 ) then msg = trim(msg)//ch10 write(my_unit,'(a)') msg msg = "" end if #endif #if defined CXX_IBM write(tmp,"(1x,a25)") "CXX_IBM" msg = trim(msg)//trim(tmp) msg_index = msg_index + 1 if ( mod(msg_index,3) == 0 ) then msg = trim(msg)//ch10 write(my_unit,'(a)') msg msg = "" end if #endif #if defined CXX_INTEL write(tmp,"(1x,a25)") "CXX_INTEL" msg = trim(msg)//trim(tmp) msg_index = msg_index + 1 if ( mod(msg_index,3) == 0 ) then msg = trim(msg)//ch10 write(my_unit,'(a)') msg msg = "" end if #endif #if defined CXX_OPEN64 write(tmp,"(1x,a25)") "CXX_OPEN64" msg = trim(msg)//trim(tmp) msg_index = msg_index + 1 if ( mod(msg_index,3) == 0 ) then msg = trim(msg)//ch10 write(my_unit,'(a)') msg msg = "" end if #endif #if defined CXX_PATHSCALE write(tmp,"(1x,a25)") "CXX_PATHSCALE" msg = trim(msg)//trim(tmp) msg_index = msg_index + 1 if ( mod(msg_index,3) == 0 ) then msg = trim(msg)//ch10 write(my_unit,'(a)') msg msg = "" end if #endif #if defined CXX_PGI write(tmp,"(1x,a25)") "CXX_PGI" msg = trim(msg)//trim(tmp) msg_index = msg_index + 1 if ( mod(msg_index,3) == 0 ) then msg = trim(msg)//ch10 write(my_unit,'(a)') msg msg = "" end if #endif #if defined CXX_SUN write(tmp,"(1x,a25)") "CXX_SUN" msg = trim(msg)//trim(tmp) msg_index = msg_index + 1 if ( mod(msg_index,3) == 0 ) then msg = trim(msg)//ch10 write(my_unit,'(a)') msg msg = "" end if #endif #if defined DEBUG_CONTRACT write(tmp,"(1x,a25)") "DEB*G_CONTRACT" msg = trim(msg)//trim(tmp) msg_index = msg_index + 1 if ( mod(msg_index,3) == 0 ) then msg = trim(msg)//ch10 write(my_unit,'(a)') msg msg = "" end if #endif #if defined DEBUG_MODE write(tmp,"(1x,a25)") "DEB*G_MODE" msg = trim(msg)//trim(tmp) msg_index = msg_index + 1 if ( mod(msg_index,3) == 0 ) then msg = trim(msg)//ch10 write(my_unit,'(a)') msg msg = "" end if #endif #if defined DEBUG_VERBOSE write(tmp,"(1x,a25)") "DEB*G_VERBOSE" msg = trim(msg)//trim(tmp) msg_index = msg_index + 1 if ( mod(msg_index,3) == 0 ) then msg = trim(msg)//ch10 write(my_unit,'(a)') msg msg = "" end if #endif #if defined FC_ABSOFT write(tmp,"(1x,a25)") "FC_ABSOFT" msg = trim(msg)//trim(tmp) msg_index = msg_index + 1 if ( mod(msg_index,3) == 0 ) then msg = trim(msg)//ch10 write(my_unit,'(a)') msg msg = "" end if #endif #if defined FC_COMPAQ write(tmp,"(1x,a25)") "FC_COMPAQ" msg = trim(msg)//trim(tmp) msg_index = msg_index + 1 if ( mod(msg_index,3) == 0 ) then msg = trim(msg)//ch10 write(my_unit,'(a)') msg msg = "" end if #endif #if defined FC_FUJITSU write(tmp,"(1x,a25)") "FC_FUJITSU" msg = trim(msg)//trim(tmp) msg_index = msg_index + 1 if ( mod(msg_index,3) == 0 ) then msg = trim(msg)//ch10 write(my_unit,'(a)') msg msg = "" end if #endif #if defined FC_G95 write(tmp,"(1x,a25)") "FC_G95" msg = trim(msg)//trim(tmp) msg_index = msg_index + 1 if ( mod(msg_index,3) == 0 ) then msg = trim(msg)//ch10 write(my_unit,'(a)') msg msg = "" end if #endif #if defined FC_GNU write(tmp,"(1x,a25)") "FC_GNU" msg = trim(msg)//trim(tmp) msg_index = msg_index + 1 if ( mod(msg_index,3) == 0 ) then msg = trim(msg)//ch10 write(my_unit,'(a)') msg msg = "" end if #endif #if defined FC_HITACHI write(tmp,"(1x,a25)") "FC_HITACHI" msg = trim(msg)//trim(tmp) msg_index = msg_index + 1 if ( mod(msg_index,3) == 0 ) then msg = trim(msg)//ch10 write(my_unit,'(a)') msg msg = "" end if #endif #if defined FC_IBM write(tmp,"(1x,a25)") "FC_IBM" msg = trim(msg)//trim(tmp) msg_index = msg_index + 1 if ( mod(msg_index,3) == 0 ) then msg = trim(msg)//ch10 write(my_unit,'(a)') msg msg = "" end if #endif #if defined FC_INTEL write(tmp,"(1x,a25)") "FC_INTEL" msg = trim(msg)//trim(tmp) msg_index = msg_index + 1 if ( mod(msg_index,3) == 0 ) then msg = trim(msg)//ch10 write(my_unit,'(a)') msg msg = "" end if #endif #if defined FC_MIPSPRO write(tmp,"(1x,a25)") "FC_MIPSPRO" msg = trim(msg)//trim(tmp) msg_index = msg_index + 1 if ( mod(msg_index,3) == 0 ) then msg = trim(msg)//ch10 write(my_unit,'(a)') msg msg = "" end if #endif #if defined FC_NAG write(tmp,"(1x,a25)") "FC_NAG" msg = trim(msg)//trim(tmp) msg_index = msg_index + 1 if ( mod(msg_index,3) == 0 ) then msg = trim(msg)//ch10 write(my_unit,'(a)') msg msg = "" end if #endif #if defined FC_OPEN64 write(tmp,"(1x,a25)") "FC_OPEN64" msg = trim(msg)//trim(tmp) msg_index = msg_index + 1 if ( mod(msg_index,3) == 0 ) then msg = trim(msg)//ch10 write(my_unit,'(a)') msg msg = "" end if #endif #if defined FC_PATHSCALE write(tmp,"(1x,a25)") "FC_PATHSCALE" msg = trim(msg)//trim(tmp) msg_index = msg_index + 1 if ( mod(msg_index,3) == 0 ) then msg = trim(msg)//ch10 write(my_unit,'(a)') msg msg = "" end if #endif #if defined FC_PGI write(tmp,"(1x,a25)") "FC_PGI" msg = trim(msg)//trim(tmp) msg_index = msg_index + 1 if ( mod(msg_index,3) == 0 ) then msg = trim(msg)//ch10 write(my_unit,'(a)') msg msg = "" end if #endif #if defined FC_SUN write(tmp,"(1x,a25)") "FC_SUN" msg = trim(msg)//trim(tmp) msg_index = msg_index + 1 if ( mod(msg_index,3) == 0 ) then msg = trim(msg)//ch10 write(my_unit,'(a)') msg msg = "" end if #endif #if defined HAVE_ALGO write(tmp,"(1x,a25)") "HAVE_ALGO" msg = trim(msg)//trim(tmp) msg_index = msg_index + 1 if ( mod(msg_index,3) == 0 ) then msg = trim(msg)//ch10 write(my_unit,'(a)') msg msg = "" end if #endif #if defined HAVE_ALGO_LEVMAR write(tmp,"(1x,a25)") "HAVE_ALGO_LEVMAR" msg = trim(msg)//trim(tmp) msg_index = msg_index + 1 if ( mod(msg_index,3) == 0 ) then msg = trim(msg)//ch10 write(my_unit,'(a)') msg msg = "" end if #endif #if defined HAVE_ALGO_MPI write(tmp,"(1x,a25)") "HAVE_ALGO_MPI" msg = trim(msg)//trim(tmp) msg_index = msg_index + 1 if ( mod(msg_index,3) == 0 ) then msg = trim(msg)//ch10 write(my_unit,'(a)') msg msg = "" end if #endif #if defined HAVE_ALGO_SERIAL write(tmp,"(1x,a25)") "HAVE_ALGO_SERIAL" msg = trim(msg)//trim(tmp) msg_index = msg_index + 1 if ( mod(msg_index,3) == 0 ) then msg = trim(msg)//ch10 write(my_unit,'(a)') msg msg = "" end if #endif #if defined HAVE_AVX_SAFE_MODE write(tmp,"(1x,a25)") "HAVE_AVX_SAFE_MODE" msg = trim(msg)//trim(tmp) msg_index = msg_index + 1 if ( mod(msg_index,3) == 0 ) then msg = trim(msg)//ch10 write(my_unit,'(a)') msg msg = "" end if #endif #if defined HAVE_BSE_UNPACKED write(tmp,"(1x,a25)") "HAVE_BSE_UNPACKED" msg = trim(msg)//trim(tmp) msg_index = msg_index + 1 if ( mod(msg_index,3) == 0 ) then msg = trim(msg)//ch10 write(my_unit,'(a)') msg msg = "" end if #endif #if defined HAVE_BZR_BRANCH write(tmp,"(1x,a25)") "HAVE_BZR_BRANCH" msg = trim(msg)//trim(tmp) msg_index = msg_index + 1 if ( mod(msg_index,3) == 0 ) then msg = trim(msg)//ch10 write(my_unit,'(a)') msg msg = "" end if #endif #if defined HAVE_CCLOCK write(tmp,"(1x,a25)") "HAVE_CCLOCK" msg = trim(msg)//trim(tmp) msg_index = msg_index + 1 if ( mod(msg_index,3) == 0 ) then msg = trim(msg)//ch10 write(my_unit,'(a)') msg msg = "" end if #endif #if defined HAVE_DFT_ATOMPAW write(tmp,"(1x,a25)") "HAVE_DFT_ATOMPAW" msg = trim(msg)//trim(tmp) msg_index = msg_index + 1 if ( mod(msg_index,3) == 0 ) then msg = trim(msg)//ch10 write(my_unit,'(a)') msg msg = "" end if #endif #if defined HAVE_DFT_BIGDFT write(tmp,"(1x,a25)") "HAVE_DFT_BIGDFT" msg = trim(msg)//trim(tmp) msg_index = msg_index + 1 if ( mod(msg_index,3) == 0 ) then msg = trim(msg)//ch10 write(my_unit,'(a)') msg msg = "" end if #endif #if defined HAVE_DFT_LIBXC write(tmp,"(1x,a25)") "HAVE_DFT_LIBXC" msg = trim(msg)//trim(tmp) msg_index = msg_index + 1 if ( mod(msg_index,3) == 0 ) then msg = trim(msg)//ch10 write(my_unit,'(a)') msg msg = "" end if #endif #if defined HAVE_DFT_WANNIER90 write(tmp,"(1x,a25)") "HAVE_DFT_WANNIER90" msg = trim(msg)//trim(tmp) msg_index = msg_index + 1 if ( mod(msg_index,3) == 0 ) then msg = trim(msg)//ch10 write(my_unit,'(a)') msg msg = "" end if #endif #if defined HAVE_DFT_WANNIER90_V1 write(tmp,"(1x,a25)") "HAVE_DFT_WANNIER90_V1" msg = trim(msg)//trim(tmp) msg_index = msg_index + 1 if ( mod(msg_index,3) == 0 ) then msg = trim(msg)//ch10 write(my_unit,'(a)') msg msg = "" end if #endif #if defined HAVE_FC_ALLOCATABLE_DTARRAYS write(tmp,"(1x,a25)") "HAVE_FC_ALLOCATABLE_DT..." msg = trim(msg)//trim(tmp) msg_index = msg_index + 1 if ( mod(msg_index,3) == 0 ) then msg = trim(msg)//ch10 write(my_unit,'(a)') msg msg = "" end if #endif #if defined HAVE_FC_ASYNC write(tmp,"(1x,a25)") "HAVE_FC_ASYNC" msg = trim(msg)//trim(tmp) msg_index = msg_index + 1 if ( mod(msg_index,3) == 0 ) then msg = trim(msg)//ch10 write(my_unit,'(a)') msg msg = "" end if #endif #if defined HAVE_FC_BACKTRACE write(tmp,"(1x,a25)") "HAVE_FC_BACKTRACE" msg = trim(msg)//trim(tmp) msg_index = msg_index + 1 if ( mod(msg_index,3) == 0 ) then msg = trim(msg)//ch10 write(my_unit,'(a)') msg msg = "" end if #endif #if defined HAVE_FC_COMMAND_ARGUMENT write(tmp,"(1x,a25)") "HAVE_FC_COMMAND_ARGUMENT" msg = trim(msg)//trim(tmp) msg_index = msg_index + 1 if ( mod(msg_index,3) == 0 ) then msg = trim(msg)//ch10 write(my_unit,'(a)') msg msg = "" end if #endif #if defined HAVE_FC_COMMAND_LINE write(tmp,"(1x,a25)") "HAVE_FC_COMMAND_LINE" msg = trim(msg)//trim(tmp) msg_index = msg_index + 1 if ( mod(msg_index,3) == 0 ) then msg = trim(msg)//ch10 write(my_unit,'(a)') msg msg = "" end if #endif #if defined HAVE_FC_CONTIGUOUS write(tmp,"(1x,a25)") "HAVE_FC_CONTIGUOUS" msg = trim(msg)//trim(tmp) msg_index = msg_index + 1 if ( mod(msg_index,3) == 0 ) then msg = trim(msg)//ch10 write(my_unit,'(a)') msg msg = "" end if #endif #if defined HAVE_FC_CPUTIME write(tmp,"(1x,a25)") "HAVE_FC_CPUTIME" msg = trim(msg)//trim(tmp) msg_index = msg_index + 1 if ( mod(msg_index,3) == 0 ) then msg = trim(msg)//ch10 write(my_unit,'(a)') msg msg = "" end if #endif #if defined HAVE_FC_ETIME write(tmp,"(1x,a25)") "HAVE_FC_ETIME" msg = trim(msg)//trim(tmp) msg_index = msg_index + 1 if ( mod(msg_index,3) == 0 ) then msg = trim(msg)//ch10 write(my_unit,'(a)') msg msg = "" end if #endif #if defined HAVE_FC_EXIT write(tmp,"(1x,a25)") "HAVE_FC_EXIT" msg = trim(msg)//trim(tmp) msg_index = msg_index + 1 if ( mod(msg_index,3) == 0 ) then msg = trim(msg)//ch10 write(my_unit,'(a)') msg msg = "" end if #endif #if defined HAVE_FC_FLUSH write(tmp,"(1x,a25)") "HAVE_FC_FLUSH" msg = trim(msg)//trim(tmp) msg_index = msg_index + 1 if ( mod(msg_index,3) == 0 ) then msg = trim(msg)//ch10 write(my_unit,'(a)') msg msg = "" end if #endif #if defined HAVE_FC_FLUSH_ write(tmp,"(1x,a25)") "HAVE_FC_FLUSH_" msg = trim(msg)//trim(tmp) msg_index = msg_index + 1 if ( mod(msg_index,3) == 0 ) then msg = trim(msg)//ch10 write(my_unit,'(a)') msg msg = "" end if #endif #if defined HAVE_FC_GAMMA write(tmp,"(1x,a25)") "HAVE_FC_GAMMA" msg = trim(msg)//trim(tmp) msg_index = msg_index + 1 if ( mod(msg_index,3) == 0 ) then msg = trim(msg)//ch10 write(my_unit,'(a)') msg msg = "" end if #endif #if defined HAVE_FC_GETENV write(tmp,"(1x,a25)") "HAVE_FC_GETENV" msg = trim(msg)//trim(tmp) msg_index = msg_index + 1 if ( mod(msg_index,3) == 0 ) then msg = trim(msg)//ch10 write(my_unit,'(a)') msg msg = "" end if #endif #if defined HAVE_FC_GETPID write(tmp,"(1x,a25)") "HAVE_FC_GETPID" msg = trim(msg)//trim(tmp) msg_index = msg_index + 1 if ( mod(msg_index,3) == 0 ) then msg = trim(msg)//ch10 write(my_unit,'(a)') msg msg = "" end if #endif #if defined HAVE_FC_IEEE_EXCEPTIONS write(tmp,"(1x,a25)") "HAVE_FC_IEEE_EXCEPTIONS" msg = trim(msg)//trim(tmp) msg_index = msg_index + 1 if ( mod(msg_index,3) == 0 ) then msg = trim(msg)//ch10 write(my_unit,'(a)') msg msg = "" end if #endif #if defined HAVE_FC_INT_QUAD write(tmp,"(1x,a25)") "HAVE_FC_INT_QUAD" msg = trim(msg)//trim(tmp) msg_index = msg_index + 1 if ( mod(msg_index,3) == 0 ) then msg = trim(msg)//ch10 write(my_unit,'(a)') msg msg = "" end if #endif #if defined HAVE_FC_IOMSG write(tmp,"(1x,a25)") "HAVE_FC_IOMSG" msg = trim(msg)//trim(tmp) msg_index = msg_index + 1 if ( mod(msg_index,3) == 0 ) then msg = trim(msg)//ch10 write(my_unit,'(a)') msg msg = "" end if #endif #if defined HAVE_FC_ISO_C_BINDING write(tmp,"(1x,a25)") "HAVE_FC_ISO_C_BINDING" msg = trim(msg)//trim(tmp) msg_index = msg_index + 1 if ( mod(msg_index,3) == 0 ) then msg = trim(msg)//ch10 write(my_unit,'(a)') msg msg = "" end if #endif #if defined HAVE_FC_ISO_FORTRAN_2008 write(tmp,"(1x,a25)") "HAVE_FC_ISO_FORTRAN_2008" msg = trim(msg)//trim(tmp) msg_index = msg_index + 1 if ( mod(msg_index,3) == 0 ) then msg = trim(msg)//ch10 write(my_unit,'(a)') msg msg = "" end if #endif #if defined HAVE_FC_LONG_LINES write(tmp,"(1x,a25)") "HAVE_FC_LONG_LINES" msg = trim(msg)//trim(tmp) msg_index = msg_index + 1 if ( mod(msg_index,3) == 0 ) then msg = trim(msg)//ch10 write(my_unit,'(a)') msg msg = "" end if #endif #if defined HAVE_FC_MACRO_NEWLINE write(tmp,"(1x,a25)") "HAVE_FC_MACRO_NEWLINE" msg = trim(msg)//trim(tmp) msg_index = msg_index + 1 if ( mod(msg_index,3) == 0 ) then msg = trim(msg)//ch10 write(my_unit,'(a)') msg msg = "" end if #endif #if defined HAVE_FC_MOVE_ALLOC write(tmp,"(1x,a25)") "HAVE_FC_MOVE_ALLOC" msg = trim(msg)//trim(tmp) msg_index = msg_index + 1 if ( mod(msg_index,3) == 0 ) then msg = trim(msg)//ch10 write(my_unit,'(a)') msg msg = "" end if #endif #if defined HAVE_FC_PRIVATE write(tmp,"(1x,a25)") "HAVE_FC_PRIVATE" msg = trim(msg)//trim(tmp) msg_index = msg_index + 1 if ( mod(msg_index,3) == 0 ) then msg = trim(msg)//ch10 write(my_unit,'(a)') msg msg = "" end if #endif #if defined HAVE_FC_PROTECTED write(tmp,"(1x,a25)") "HAVE_FC_PROTECTED" msg = trim(msg)//trim(tmp) msg_index = msg_index + 1 if ( mod(msg_index,3) == 0 ) then msg = trim(msg)//ch10 write(my_unit,'(a)') msg msg = "" end if #endif #if defined HAVE_FC_STREAM_IO write(tmp,"(1x,a25)") "HAVE_FC_STREAM_IO" msg = trim(msg)//trim(tmp) msg_index = msg_index + 1 if ( mod(msg_index,3) == 0 ) then msg = trim(msg)//ch10 write(my_unit,'(a)') msg msg = "" end if #endif #if defined HAVE_FC_SYSTEM write(tmp,"(1x,a25)") "HAVE_FC_SYSTEM" msg = trim(msg)//trim(tmp) msg_index = msg_index + 1 if ( mod(msg_index,3) == 0 ) then msg = trim(msg)//ch10 write(my_unit,'(a)') msg msg = "" end if #endif #if defined HAVE_FFT write(tmp,"(1x,a25)") "HAVE_FFT" msg = trim(msg)//trim(tmp) msg_index = msg_index + 1 if ( mod(msg_index,3) == 0 ) then msg = trim(msg)//ch10 write(my_unit,'(a)') msg msg = "" end if #endif #if defined HAVE_FFT_ASL write(tmp,"(1x,a25)") "HAVE_FFT_ASL" msg = trim(msg)//trim(tmp) msg_index = msg_index + 1 if ( mod(msg_index,3) == 0 ) then msg = trim(msg)//ch10 write(my_unit,'(a)') msg msg = "" end if #endif #if defined HAVE_FFT_DFTI write(tmp,"(1x,a25)") "HAVE_FFT_DFTI" msg = trim(msg)//trim(tmp) msg_index = msg_index + 1 if ( mod(msg_index,3) == 0 ) then msg = trim(msg)//ch10 write(my_unit,'(a)') msg msg = "" end if #endif #if defined HAVE_FFT_DFTI_MPI write(tmp,"(1x,a25)") "HAVE_FFT_DFTI_MPI" msg = trim(msg)//trim(tmp) msg_index = msg_index + 1 if ( mod(msg_index,3) == 0 ) then msg = trim(msg)//ch10 write(my_unit,'(a)') msg msg = "" end if #endif #if defined HAVE_FFT_DFTI_THREADS write(tmp,"(1x,a25)") "HAVE_FFT_DFTI_THREADS" msg = trim(msg)//trim(tmp) msg_index = msg_index + 1 if ( mod(msg_index,3) == 0 ) then msg = trim(msg)//ch10 write(my_unit,'(a)') msg msg = "" end if #endif #if defined HAVE_FFT_FFTW2 write(tmp,"(1x,a25)") "HAVE_FFT_FFTW2" msg = trim(msg)//trim(tmp) msg_index = msg_index + 1 if ( mod(msg_index,3) == 0 ) then msg = trim(msg)//ch10 write(my_unit,'(a)') msg msg = "" end if #endif #if defined HAVE_FFT_FFTW2_THREADS write(tmp,"(1x,a25)") "HAVE_FFT_FFTW2_THREADS" msg = trim(msg)//trim(tmp) msg_index = msg_index + 1 if ( mod(msg_index,3) == 0 ) then msg = trim(msg)//ch10 write(my_unit,'(a)') msg msg = "" end if #endif #if defined HAVE_FFT_FFTW3 write(tmp,"(1x,a25)") "HAVE_FFT_FFTW3" msg = trim(msg)//trim(tmp) msg_index = msg_index + 1 if ( mod(msg_index,3) == 0 ) then msg = trim(msg)//ch10 write(my_unit,'(a)') msg msg = "" end if #endif #if defined HAVE_FFT_FFTW3_MKL write(tmp,"(1x,a25)") "HAVE_FFT_FFTW3_MKL" msg = trim(msg)//trim(tmp) msg_index = msg_index + 1 if ( mod(msg_index,3) == 0 ) then msg = trim(msg)//ch10 write(my_unit,'(a)') msg msg = "" end if #endif #if defined HAVE_FFT_FFTW3_MPI write(tmp,"(1x,a25)") "HAVE_FFT_FFTW3_MPI" msg = trim(msg)//trim(tmp) msg_index = msg_index + 1 if ( mod(msg_index,3) == 0 ) then msg = trim(msg)//ch10 write(my_unit,'(a)') msg msg = "" end if #endif #if defined HAVE_FFT_FFTW3_THREADS write(tmp,"(1x,a25)") "HAVE_FFT_FFTW3_THREADS" msg = trim(msg)//trim(tmp) msg_index = msg_index + 1 if ( mod(msg_index,3) == 0 ) then msg = trim(msg)//ch10 write(my_unit,'(a)') msg msg = "" end if #endif #if defined HAVE_FFT_MLIB write(tmp,"(1x,a25)") "HAVE_FFT_MLIB" msg = trim(msg)//trim(tmp) msg_index = msg_index + 1 if ( mod(msg_index,3) == 0 ) then msg = trim(msg)//ch10 write(my_unit,'(a)') msg msg = "" end if #endif #if defined HAVE_FFT_MPI write(tmp,"(1x,a25)") "HAVE_FFT_MPI" msg = trim(msg)//trim(tmp) msg_index = msg_index + 1 if ( mod(msg_index,3) == 0 ) then msg = trim(msg)//ch10 write(my_unit,'(a)') msg msg = "" end if #endif #if defined HAVE_FFT_SERIAL write(tmp,"(1x,a25)") "HAVE_FFT_SERIAL" msg = trim(msg)//trim(tmp) msg_index = msg_index + 1 if ( mod(msg_index,3) == 0 ) then msg = trim(msg)//ch10 write(my_unit,'(a)') msg msg = "" end if #endif #if defined HAVE_FFT_SGIMATH write(tmp,"(1x,a25)") "HAVE_FFT_SGIMATH" msg = trim(msg)//trim(tmp) msg_index = msg_index + 1 if ( mod(msg_index,3) == 0 ) then msg = trim(msg)//ch10 write(my_unit,'(a)') msg msg = "" end if #endif #if defined HAVE_FORTRAN2003 write(tmp,"(1x,a25)") "HAVE_FORTRAN2003" msg = trim(msg)//trim(tmp) msg_index = msg_index + 1 if ( mod(msg_index,3) == 0 ) then msg = trim(msg)//ch10 write(my_unit,'(a)') msg msg = "" end if #endif #if defined HAVE_GPU write(tmp,"(1x,a25)") "HAVE_GPU" msg = trim(msg)//trim(tmp) msg_index = msg_index + 1 if ( mod(msg_index,3) == 0 ) then msg = trim(msg)//ch10 write(my_unit,'(a)') msg msg = "" end if #endif #if defined HAVE_GPU_CUDA write(tmp,"(1x,a25)") "HAVE_GPU_CUDA" msg = trim(msg)//trim(tmp) msg_index = msg_index + 1 if ( mod(msg_index,3) == 0 ) then msg = trim(msg)//ch10 write(my_unit,'(a)') msg msg = "" end if #endif #if defined HAVE_GPU_CUDA3 write(tmp,"(1x,a25)") "HAVE_GPU_CUDA3" msg = trim(msg)//trim(tmp) msg_index = msg_index + 1 if ( mod(msg_index,3) == 0 ) then msg = trim(msg)//ch10 write(my_unit,'(a)') msg msg = "" end if #endif #if defined HAVE_GPU_CUDA_DP write(tmp,"(1x,a25)") "HAVE_GPU_CUDA_DP" msg = trim(msg)//trim(tmp) msg_index = msg_index + 1 if ( mod(msg_index,3) == 0 ) then msg = trim(msg)//ch10 write(my_unit,'(a)') msg msg = "" end if #endif #if defined HAVE_GPU_CUDA_SP write(tmp,"(1x,a25)") "HAVE_GPU_CUDA_SP" msg = trim(msg)//trim(tmp) msg_index = msg_index + 1 if ( mod(msg_index,3) == 0 ) then msg = trim(msg)//ch10 write(my_unit,'(a)') msg msg = "" end if #endif #if defined HAVE_GPU_MPI write(tmp,"(1x,a25)") "HAVE_GPU_MPI" msg = trim(msg)//trim(tmp) msg_index = msg_index + 1 if ( mod(msg_index,3) == 0 ) then msg = trim(msg)//ch10 write(my_unit,'(a)') msg msg = "" end if #endif #if defined HAVE_GPU_SERIAL write(tmp,"(1x,a25)") "HAVE_GPU_SERIAL" msg = trim(msg)//trim(tmp) msg_index = msg_index + 1 if ( mod(msg_index,3) == 0 ) then msg = trim(msg)//ch10 write(my_unit,'(a)') msg msg = "" end if #endif #if defined HAVE_GW_DPC write(tmp,"(1x,a25)") "HAVE_GW_DPC" msg = trim(msg)//trim(tmp) msg_index = msg_index + 1 if ( mod(msg_index,3) == 0 ) then msg = trim(msg)//ch10 write(my_unit,'(a)') msg msg = "" end if #endif #if defined HAVE_LIBPAW_ABINIT write(tmp,"(1x,a25)") "HAVE_LIBPAW_ABINIT" msg = trim(msg)//trim(tmp) msg_index = msg_index + 1 if ( mod(msg_index,3) == 0 ) then msg = trim(msg)//ch10 write(my_unit,'(a)') msg msg = "" end if #endif #if defined HAVE_LIBTETRA_ABINIT write(tmp,"(1x,a25)") "HAVE_LIBTETRA_ABINIT" msg = trim(msg)//trim(tmp) msg_index = msg_index + 1 if ( mod(msg_index,3) == 0 ) then msg = trim(msg)//ch10 write(my_unit,'(a)') msg msg = "" end if #endif #if defined HAVE_LINALG write(tmp,"(1x,a25)") "HAVE_LINALG" msg = trim(msg)//trim(tmp) msg_index = msg_index + 1 if ( mod(msg_index,3) == 0 ) then msg = trim(msg)//ch10 write(my_unit,'(a)') msg msg = "" end if #endif #if defined HAVE_LINALG_ASL write(tmp,"(1x,a25)") "HAVE_LINALG_ASL" msg = trim(msg)//trim(tmp) msg_index = msg_index + 1 if ( mod(msg_index,3) == 0 ) then msg = trim(msg)//ch10 write(my_unit,'(a)') msg msg = "" end if #endif #if defined HAVE_LINALG_AXPBY write(tmp,"(1x,a25)") "HAVE_LINALG_AXPBY" msg = trim(msg)//trim(tmp) msg_index = msg_index + 1 if ( mod(msg_index,3) == 0 ) then msg = trim(msg)//ch10 write(my_unit,'(a)') msg msg = "" end if #endif #if defined HAVE_LINALG_ELPA write(tmp,"(1x,a25)") "HAVE_LINALG_ELPA" msg = trim(msg)//trim(tmp) msg_index = msg_index + 1 if ( mod(msg_index,3) == 0 ) then msg = trim(msg)//ch10 write(my_unit,'(a)') msg msg = "" end if #endif #if defined HAVE_LINALG_ELPA_2013 write(tmp,"(1x,a25)") "HAVE_LINALG_ELPA_2013" msg = trim(msg)//trim(tmp) msg_index = msg_index + 1 if ( mod(msg_index,3) == 0 ) then msg = trim(msg)//ch10 write(my_unit,'(a)') msg msg = "" end if #endif #if defined HAVE_LINALG_ELPA_2014 write(tmp,"(1x,a25)") "HAVE_LINALG_ELPA_2014" msg = trim(msg)//trim(tmp) msg_index = msg_index + 1 if ( mod(msg_index,3) == 0 ) then msg = trim(msg)//ch10 write(my_unit,'(a)') msg msg = "" end if #endif #if defined HAVE_LINALG_ELPA_2015 write(tmp,"(1x,a25)") "HAVE_LINALG_ELPA_2015" msg = trim(msg)//trim(tmp) msg_index = msg_index + 1 if ( mod(msg_index,3) == 0 ) then msg = trim(msg)//ch10 write(my_unit,'(a)') msg msg = "" end if #endif #if defined HAVE_LINALG_ELPA_2016 write(tmp,"(1x,a25)") "HAVE_LINALG_ELPA_2016" msg = trim(msg)//trim(tmp) msg_index = msg_index + 1 if ( mod(msg_index,3) == 0 ) then msg = trim(msg)//ch10 write(my_unit,'(a)') msg msg = "" end if #endif #if defined HAVE_LINALG_ESSL write(tmp,"(1x,a25)") "HAVE_LINALG_ESSL" msg = trim(msg)//trim(tmp) msg_index = msg_index + 1 if ( mod(msg_index,3) == 0 ) then msg = trim(msg)//ch10 write(my_unit,'(a)') msg msg = "" end if #endif #if defined HAVE_LINALG_GEMM3M write(tmp,"(1x,a25)") "HAVE_LINALG_GEMM3M" msg = trim(msg)//trim(tmp) msg_index = msg_index + 1 if ( mod(msg_index,3) == 0 ) then msg = trim(msg)//ch10 write(my_unit,'(a)') msg msg = "" end if #endif #if defined HAVE_LINALG_GPU write(tmp,"(1x,a25)") "HAVE_LINALG_GPU" msg = trim(msg)//trim(tmp) msg_index = msg_index + 1 if ( mod(msg_index,3) == 0 ) then msg = trim(msg)//ch10 write(my_unit,'(a)') msg msg = "" end if #endif #if defined HAVE_LINALG_MAGMA write(tmp,"(1x,a25)") "HAVE_LINALG_MAGMA" msg = trim(msg)//trim(tmp) msg_index = msg_index + 1 if ( mod(msg_index,3) == 0 ) then msg = trim(msg)//ch10 write(my_unit,'(a)') msg msg = "" end if #endif #if defined HAVE_LINALG_MAGMA_15 write(tmp,"(1x,a25)") "HAVE_LINALG_MAGMA_15" msg = trim(msg)//trim(tmp) msg_index = msg_index + 1 if ( mod(msg_index,3) == 0 ) then msg = trim(msg)//ch10 write(my_unit,'(a)') msg msg = "" end if #endif #if defined HAVE_LINALG_MKL_IMATCOPY write(tmp,"(1x,a25)") "HAVE_LINALG_MKL_IMATCOPY" msg = trim(msg)//trim(tmp) msg_index = msg_index + 1 if ( mod(msg_index,3) == 0 ) then msg = trim(msg)//ch10 write(my_unit,'(a)') msg msg = "" end if #endif #if defined HAVE_LINALG_MKL_OMATADD write(tmp,"(1x,a25)") "HAVE_LINALG_MKL_OMATADD" msg = trim(msg)//trim(tmp) msg_index = msg_index + 1 if ( mod(msg_index,3) == 0 ) then msg = trim(msg)//ch10 write(my_unit,'(a)') msg msg = "" end if #endif #if defined HAVE_LINALG_MKL_OMATCOPY write(tmp,"(1x,a25)") "HAVE_LINALG_MKL_OMATCOPY" msg = trim(msg)//trim(tmp) msg_index = msg_index + 1 if ( mod(msg_index,3) == 0 ) then msg = trim(msg)//ch10 write(my_unit,'(a)') msg msg = "" end if #endif #if defined HAVE_LINALG_MPI write(tmp,"(1x,a25)") "HAVE_LINALG_MPI" msg = trim(msg)//trim(tmp) msg_index = msg_index + 1 if ( mod(msg_index,3) == 0 ) then msg = trim(msg)//ch10 write(my_unit,'(a)') msg msg = "" end if #endif #if defined HAVE_LINALG_PLASMA write(tmp,"(1x,a25)") "HAVE_LINALG_PLASMA" msg = trim(msg)//trim(tmp) msg_index = msg_index + 1 if ( mod(msg_index,3) == 0 ) then msg = trim(msg)//ch10 write(my_unit,'(a)') msg msg = "" end if #endif #if defined HAVE_LINALG_SCALAPACK write(tmp,"(1x,a25)") "HAVE_LINALG_SCALAPACK" msg = trim(msg)//trim(tmp) msg_index = msg_index + 1 if ( mod(msg_index,3) == 0 ) then msg = trim(msg)//ch10 write(my_unit,'(a)') msg msg = "" end if #endif #if defined HAVE_LINALG_SERIAL write(tmp,"(1x,a25)") "HAVE_LINALG_SERIAL" msg = trim(msg)//trim(tmp) msg_index = msg_index + 1 if ( mod(msg_index,3) == 0 ) then msg = trim(msg)//ch10 write(my_unit,'(a)') msg msg = "" end if #endif #if defined HAVE_LINALG_ZDOTC_BUG write(tmp,"(1x,a25)") "HAVE_LINALG_ZDOTC_B*G" msg = trim(msg)//trim(tmp) msg_index = msg_index + 1 if ( mod(msg_index,3) == 0 ) then msg = trim(msg)//ch10 write(my_unit,'(a)') msg msg = "" end if #endif #if defined HAVE_LINALG_ZDOTU_BUG write(tmp,"(1x,a25)") "HAVE_LINALG_ZDOTU_B*G" msg = trim(msg)//trim(tmp) msg_index = msg_index + 1 if ( mod(msg_index,3) == 0 ) then msg = trim(msg)//ch10 write(my_unit,'(a)') msg msg = "" end if #endif #if defined HAVE_LOTF write(tmp,"(1x,a25)") "HAVE_LOTF" msg = trim(msg)//trim(tmp) msg_index = msg_index + 1 if ( mod(msg_index,3) == 0 ) then msg = trim(msg)//ch10 write(my_unit,'(a)') msg msg = "" end if #endif #if defined HAVE_MATH write(tmp,"(1x,a25)") "HAVE_MATH" msg = trim(msg)//trim(tmp) msg_index = msg_index + 1 if ( mod(msg_index,3) == 0 ) then msg = trim(msg)//ch10 write(my_unit,'(a)') msg msg = "" end if #endif #if defined HAVE_MATH_GSL write(tmp,"(1x,a25)") "HAVE_MATH_GSL" msg = trim(msg)//trim(tmp) msg_index = msg_index + 1 if ( mod(msg_index,3) == 0 ) then msg = trim(msg)//ch10 write(my_unit,'(a)') msg msg = "" end if #endif #if defined HAVE_MATH_MLIB write(tmp,"(1x,a25)") "HAVE_MATH_MLIB" msg = trim(msg)//trim(tmp) msg_index = msg_index + 1 if ( mod(msg_index,3) == 0 ) then msg = trim(msg)//ch10 write(my_unit,'(a)') msg msg = "" end if #endif #if defined HAVE_MATH_MPI write(tmp,"(1x,a25)") "HAVE_MATH_MPI" msg = trim(msg)//trim(tmp) msg_index = msg_index + 1 if ( mod(msg_index,3) == 0 ) then msg = trim(msg)//ch10 write(my_unit,'(a)') msg msg = "" end if #endif #if defined HAVE_MATH_SERIAL write(tmp,"(1x,a25)") "HAVE_MATH_SERIAL" msg = trim(msg)//trim(tmp) msg_index = msg_index + 1 if ( mod(msg_index,3) == 0 ) then msg = trim(msg)//ch10 write(my_unit,'(a)') msg msg = "" end if #endif #if defined HAVE_MEM_PROFILING write(tmp,"(1x,a25)") "HAVE_MEM_PROFILING" msg = trim(msg)//trim(tmp) msg_index = msg_index + 1 if ( mod(msg_index,3) == 0 ) then msg = trim(msg)//ch10 write(my_unit,'(a)') msg msg = "" end if #endif #if defined HAVE_MPI write(tmp,"(1x,a25)") "HAVE_MPI" msg = trim(msg)//trim(tmp) msg_index = msg_index + 1 if ( mod(msg_index,3) == 0 ) then msg = trim(msg)//ch10 write(my_unit,'(a)') msg msg = "" end if #endif #if defined HAVE_MPI1 write(tmp,"(1x,a25)") "HAVE_MPI1" msg = trim(msg)//trim(tmp) msg_index = msg_index + 1 if ( mod(msg_index,3) == 0 ) then msg = trim(msg)//ch10 write(my_unit,'(a)') msg msg = "" end if #endif #if defined HAVE_MPI2 write(tmp,"(1x,a25)") "HAVE_MPI2" msg = trim(msg)//trim(tmp) msg_index = msg_index + 1 if ( mod(msg_index,3) == 0 ) then msg = trim(msg)//ch10 write(my_unit,'(a)') msg msg = "" end if #endif #if defined HAVE_MPI2_INPLACE write(tmp,"(1x,a25)") "HAVE_MPI2_INPLACE" msg = trim(msg)//trim(tmp) msg_index = msg_index + 1 if ( mod(msg_index,3) == 0 ) then msg = trim(msg)//ch10 write(my_unit,'(a)') msg msg = "" end if #endif #if defined HAVE_MPI_IALLREDUCE write(tmp,"(1x,a25)") "HAVE_MPI_IALLREDUCE" msg = trim(msg)//trim(tmp) msg_index = msg_index + 1 if ( mod(msg_index,3) == 0 ) then msg = trim(msg)//ch10 write(my_unit,'(a)') msg msg = "" end if #endif #if defined HAVE_MPI_IALLTOALL write(tmp,"(1x,a25)") "HAVE_MPI_IALLTOALL" msg = trim(msg)//trim(tmp) msg_index = msg_index + 1 if ( mod(msg_index,3) == 0 ) then msg = trim(msg)//ch10 write(my_unit,'(a)') msg msg = "" end if #endif #if defined HAVE_MPI_IALLTOALLV write(tmp,"(1x,a25)") "HAVE_MPI_IALLTOALLV" msg = trim(msg)//trim(tmp) msg_index = msg_index + 1 if ( mod(msg_index,3) == 0 ) then msg = trim(msg)//ch10 write(my_unit,'(a)') msg msg = "" end if #endif #if defined HAVE_MPI_INCLUDED_ONCE write(tmp,"(1x,a25)") "HAVE_MPI_INCLUDED_ONCE" msg = trim(msg)//trim(tmp) msg_index = msg_index + 1 if ( mod(msg_index,3) == 0 ) then msg = trim(msg)//ch10 write(my_unit,'(a)') msg msg = "" end if #endif #if defined HAVE_MPI_INTEGER16 write(tmp,"(1x,a25)") "HAVE_MPI_INTEGER16" msg = trim(msg)//trim(tmp) msg_index = msg_index + 1 if ( mod(msg_index,3) == 0 ) then msg = trim(msg)//ch10 write(my_unit,'(a)') msg msg = "" end if #endif #if defined HAVE_MPI_IO write(tmp,"(1x,a25)") "HAVE_MPI_IO" msg = trim(msg)//trim(tmp) msg_index = msg_index + 1 if ( mod(msg_index,3) == 0 ) then msg = trim(msg)//ch10 write(my_unit,'(a)') msg msg = "" end if #endif #if defined HAVE_MPI_IO_DEFAULT write(tmp,"(1x,a25)") "HAVE_MPI_IO_DEFAULT" msg = trim(msg)//trim(tmp) msg_index = msg_index + 1 if ( mod(msg_index,3) == 0 ) then msg = trim(msg)//ch10 write(my_unit,'(a)') msg msg = "" end if #endif #if defined HAVE_MPI_TYPE_CREATE_STRUCT write(tmp,"(1x,a25)") "HAVE_MPI_TYPE_CREATE_S..." msg = trim(msg)//trim(tmp) msg_index = msg_index + 1 if ( mod(msg_index,3) == 0 ) then msg = trim(msg)//ch10 write(my_unit,'(a)') msg msg = "" end if #endif #if defined HAVE_NETCDF_DEFAULT write(tmp,"(1x,a25)") "HAVE_NETCDF_DEFAULT" msg = trim(msg)//trim(tmp) msg_index = msg_index + 1 if ( mod(msg_index,3) == 0 ) then msg = trim(msg)//ch10 write(my_unit,'(a)') msg msg = "" end if #endif #if defined HAVE_NUMPY write(tmp,"(1x,a25)") "HAVE_NUMPY" msg = trim(msg)//trim(tmp) msg_index = msg_index + 1 if ( mod(msg_index,3) == 0 ) then msg = trim(msg)//ch10 write(my_unit,'(a)') msg msg = "" end if #endif #if defined HAVE_OMP_COLLAPSE write(tmp,"(1x,a25)") "HAVE_OMP_COLLAPSE" msg = trim(msg)//trim(tmp) msg_index = msg_index + 1 if ( mod(msg_index,3) == 0 ) then msg = trim(msg)//ch10 write(my_unit,'(a)') msg msg = "" end if #endif #if defined HAVE_OPENMP write(tmp,"(1x,a25)") "HAVE_OPENMP" msg = trim(msg)//trim(tmp) msg_index = msg_index + 1 if ( mod(msg_index,3) == 0 ) then msg = trim(msg)//ch10 write(my_unit,'(a)') msg msg = "" end if #endif #if defined HAVE_OS_LINUX write(tmp,"(1x,a25)") "HAVE_OS_LINUX" msg = trim(msg)//trim(tmp) msg_index = msg_index + 1 if ( mod(msg_index,3) == 0 ) then msg = trim(msg)//ch10 write(my_unit,'(a)') msg msg = "" end if #endif #if defined HAVE_OS_MACOSX write(tmp,"(1x,a25)") "HAVE_OS_MACOSX" msg = trim(msg)//trim(tmp) msg_index = msg_index + 1 if ( mod(msg_index,3) == 0 ) then msg = trim(msg)//ch10 write(my_unit,'(a)') msg msg = "" end if #endif #if defined HAVE_OS_WINDOWS write(tmp,"(1x,a25)") "HAVE_OS_WINDOWS" msg = trim(msg)//trim(tmp) msg_index = msg_index + 1 if ( mod(msg_index,3) == 0 ) then msg = trim(msg)//ch10 write(my_unit,'(a)') msg msg = "" end if #endif #if defined HAVE_TIMER write(tmp,"(1x,a25)") "HAVE_TIMER" msg = trim(msg)//trim(tmp) msg_index = msg_index + 1 if ( mod(msg_index,3) == 0 ) then msg = trim(msg)//ch10 write(my_unit,'(a)') msg msg = "" end if #endif #if defined HAVE_TIMER_ABINIT write(tmp,"(1x,a25)") "HAVE_TIMER_ABINIT" msg = trim(msg)//trim(tmp) msg_index = msg_index + 1 if ( mod(msg_index,3) == 0 ) then msg = trim(msg)//ch10 write(my_unit,'(a)') msg msg = "" end if #endif #if defined HAVE_TIMER_MPI write(tmp,"(1x,a25)") "HAVE_TIMER_MPI" msg = trim(msg)//trim(tmp) msg_index = msg_index + 1 if ( mod(msg_index,3) == 0 ) then msg = trim(msg)//ch10 write(my_unit,'(a)') msg msg = "" end if #endif #if defined HAVE_TIMER_PAPI write(tmp,"(1x,a25)") "HAVE_TIMER_PAPI" msg = trim(msg)//trim(tmp) msg_index = msg_index + 1 if ( mod(msg_index,3) == 0 ) then msg = trim(msg)//ch10 write(my_unit,'(a)') msg msg = "" end if #endif #if defined HAVE_TIMER_SERIAL write(tmp,"(1x,a25)") "HAVE_TIMER_SERIAL" msg = trim(msg)//trim(tmp) msg_index = msg_index + 1 if ( mod(msg_index,3) == 0 ) then msg = trim(msg)//ch10 write(my_unit,'(a)') msg msg = "" end if #endif #if defined HAVE_TRIO_ETSF_IO write(tmp,"(1x,a25)") "HAVE_TRIO_ETSF_IO" msg = trim(msg)//trim(tmp) msg_index = msg_index + 1 if ( mod(msg_index,3) == 0 ) then msg = trim(msg)//ch10 write(my_unit,'(a)') msg msg = "" end if #endif #if defined HAVE_TRIO_NETCDF write(tmp,"(1x,a25)") "HAVE_TRIO_NETCDF" msg = trim(msg)//trim(tmp) msg_index = msg_index + 1 if ( mod(msg_index,3) == 0 ) then msg = trim(msg)//ch10 write(my_unit,'(a)') msg msg = "" end if #endif #if defined HAVE_TRIO_NETCDF_MPI write(tmp,"(1x,a25)") "HAVE_TRIO_NETCDF_MPI" msg = trim(msg)//trim(tmp) msg_index = msg_index + 1 if ( mod(msg_index,3) == 0 ) then msg = trim(msg)//ch10 write(my_unit,'(a)') msg msg = "" end if #endif #if defined HAVE_TRIO_PSML write(tmp,"(1x,a25)") "HAVE_TRIO_PSML" msg = trim(msg)//trim(tmp) msg_index = msg_index + 1 if ( mod(msg_index,3) == 0 ) then msg = trim(msg)//ch10 write(my_unit,'(a)') msg msg = "" end if #endif #if defined HAVE_TRIQS write(tmp,"(1x,a25)") "HAVE_TRIQS" msg = trim(msg)//trim(tmp) msg_index = msg_index + 1 if ( mod(msg_index,3) == 0 ) then msg = trim(msg)//ch10 write(my_unit,'(a)') msg msg = "" end if #endif #if defined HAVE_YAML write(tmp,"(1x,a25)") "HAVE_YAML" msg = trim(msg)//trim(tmp) msg_index = msg_index + 1 if ( mod(msg_index,3) == 0 ) then msg = trim(msg)//ch10 write(my_unit,'(a)') msg msg = "" end if #endif #if defined READ_FROM_FILE write(tmp,"(1x,a25)") "READ_FROM_FILE" msg = trim(msg)//trim(tmp) msg_index = msg_index + 1 if ( mod(msg_index,3) == 0 ) then msg = trim(msg)//ch10 write(my_unit,'(a)') msg msg = "" end if #endif #if defined USE_MACROAVE write(tmp,"(1x,a25)") "USE_MACROAVE" msg = trim(msg)//trim(tmp) msg_index = msg_index + 1 if ( mod(msg_index,3) == 0 ) then msg = trim(msg)//ch10 write(my_unit,'(a)') msg msg = "" end if #endif if ( mod(msg_index,3) /= 0 ) write(my_unit,'(a)') msg write(my_unit,"(1x,a,a)") repeat("+",78),ch10 end subroutine dump_cpp_options end module m_cppopts_dumper !!*** v_sim-3.8.0/lib/plug-ins/abinit/m_errors.F90000066400000000000000000001304451370110300500205160ustar00rootroot00000000000000!{\src2tex{textfont=tt}} !!****m* ABINIT/m_errors !! NAME !! m_errors !! !! FUNCTION !! This module contains low-level procedures to check assertions and handle errors. !! !! COPYRIGHT !! Copyright (C) 2008-2016 ABINIT group (MG,YP,NCJ,MT) !! This file is distributed under the terms of the !! GNU General Public License, see ~abinit/COPYING !! or http://www.gnu.org/copyleft/gpl.txt . !! !! PARENTS !! !! CHILDREN !! !! SOURCE #if defined HAVE_CONFIG_H #include "config.h" #endif #include "abi_common.h" MODULE m_errors use defs_basis use m_profiling_abi use m_xmpi #ifdef HAVE_TRIO_NETCDF use netcdf #endif #ifdef HAVE_TRIO_ETSF_IO use etsf_io_low_level use etsf_io #endif #ifdef HAVE_MPI2 use mpi #endif #ifdef FC_NAG use f90_unix_proc #endif #ifdef FC_INTEL use ifcore #endif use m_io_tools, only : flush_unit, lock_and_write, file_exists, num_opened_units, show_units, open_file use m_fstrings, only : toupper, basename, indent, lstrip, atoi, strcat, itoa use m_build_info, only : dump_config, abinit_version use m_cppopts_dumper, only : dump_cpp_options !use m_optim_dumper, only : dump_optim implicit none #if defined HAVE_MPI1 include 'mpif.h' #endif #ifdef FC_IBM include "fexcp.h" #endif private !!*** !Public procedures public :: assert_eq ! Report and die gracefully if integers not all equal (used for size checking). public :: assert ! Report and die if any logical is false (used for argument range checking). public :: sentinel ! Announce the entering or the exiting from a procedure. public :: die ! Stop execution in case of unexpected events. public :: msg_hndl ! Basic Error handlers. public :: netcdf_check ! Stop execution after a NetCDF I/O error public :: check_mpi_ierr ! Erro handler for MPI routines. public :: show_backtrace ! Shows a backtrace at an arbitrary place in user code. (Gfortran extension) public :: unused_var ! Helper function used to silence compiler warnings due to unused variables. #if defined HAVE_TRIO_ETSF_IO public :: abietsf_msg_hndl ! Error handler for ETSF-IO routines. public :: abietsf_warn ! Write warnings reported by ETSF-IO routines. #endif public :: bigdft_lib_error public :: xlf_set_sighandler public :: abinit_doctor ! Perform checks on memory leaks and leaking file descriptors ! at the end of the run. interface assert_eq module procedure assert_eq2 module procedure assert_eq3 module procedure assert_eq4 module procedure assert_eqn end interface assert_eq interface assert module procedure assert1 module procedure assert2 module procedure assert3 module procedure assert4 module procedure assert_v end interface assert interface unused_var module procedure unused_int module procedure unused_real_dp module procedure unused_real_sp module procedure unused_cplx_dpc module procedure unused_cplx_spc module procedure unused_logical module procedure unused_ch end interface unused_var CONTAINS !=========================================================== !!*** !---------------------------------------------------------------------- !!****f* m_errors/assert_eq2 !! NAME !! assert_eq2 !! !! FUNCTION !! Report and die gracefully if integers not all equal (used for size checking). !! !! INPUTS !! l1,l2,.. Integers to be checked (array version is also provided) !! message(len=*)=tag with additional information !! !! SOURCE function assert_eq2(l1,l2,message,file,line) !This section has been created automatically by the script Abilint (TD). !Do not modify the following lines by hand. #undef ABI_FUNC #define ABI_FUNC 'assert_eq2' !End of the abilint section implicit none !Arguments ------------------------------------ integer,intent(in) :: l1,l2 integer,optional,intent(in) :: line integer :: assert_eq2 character(len=*),intent(in) :: message character(len=*),optional,intent(in) :: file !Local variables------------------------------- integer :: f90line=0 character(len=500) :: f90name='Subroutine Unknown' ! ************************************************************************* if (l1==l2) then assert_eq2=l1 else if (PRESENT(line)) f90line=line if (PRESENT(file)) f90name= basename(file) call msg_hndl(message,'ERROR','PERS',f90name,line) end if end function assert_eq2 !!*** !---------------------------------------------------------------------- !!****f* m_errors/assert_eq3 !! NAME !! assert_eq3 !! !! FUNCTION !! Report and die gracefully if integers not all equal (used for size checking). !! !! INPUTS !! l1,l2,.. Integers to be checked (array version is also provided) !! message(len=*)=tag with additional information !! !! SOURCE function assert_eq3(l1,l2,l3,message,file,line) !This section has been created automatically by the script Abilint (TD). !Do not modify the following lines by hand. #undef ABI_FUNC #define ABI_FUNC 'assert_eq3' !End of the abilint section implicit none !Arguments ------------------------------------ integer,intent(in) :: l1,l2,l3 integer,optional,intent(in) :: line integer :: assert_eq3 character(len=*),intent(in) :: message character(len=*),optional,intent(in) :: file !Local variables------------------------------- integer :: f90line=0 character(len=500) :: f90name='Subroutine Unknown' ! ************************************************************************* if (l1==l2.and.l2==l3) then assert_eq3=l1 else if (PRESENT(line)) f90line=line if (PRESENT(file)) f90name= basename(file) call msg_hndl(message,'ERROR','PERS',f90name,line) end if end function assert_eq3 !!*** !---------------------------------------------------------------------- !!****f* m_errors/assert_eq4 !! NAME !! assert_eq4 !! !! FUNCTION !! Report and die gracefully if integers not all equal (used for size checking). !! !! INPUTS !! l1,l2,.. Integers to be checked (array version is also provided) !! message(len=*)=tag with additional information !! !! SOURCE function assert_eq4(l1,l2,l3,l4,message,file,line) !This section has been created automatically by the script Abilint (TD). !Do not modify the following lines by hand. #undef ABI_FUNC #define ABI_FUNC 'assert_eq4' !End of the abilint section implicit none !Arguments ------------------------------------ !scalars integer,intent(in) :: l1,l2,l3,l4 integer,optional,intent(in) :: line integer :: assert_eq4 character(len=*),intent(in) :: message character(len=*),optional,intent(in) :: file !Local variables------------------------------- integer :: f90line=0 character(len=500) :: f90name='Subroutine Unknown' ! ************************************************************************* if (l1==l2.and.l2==l3.and.l3==l4) then assert_eq4=l1 else if (PRESENT(line)) f90line=line if (PRESENT(file)) f90name= basename(file) call msg_hndl(message,'ERROR','PERS',f90name,line) end if end function assert_eq4 !!*** !---------------------------------------------------------------------- !!****f* m_errors/assert_eqn !! NAME !! assert_eqn !! !! FUNCTION !! Report and die gracefully if integers not all equal (used for size checking). !! !! SOURCE function assert_eqn(nn,message,file,line) !This section has been created automatically by the script Abilint (TD). !Do not modify the following lines by hand. #undef ABI_FUNC #define ABI_FUNC 'assert_eqn' !End of the abilint section implicit none !Arguments ------------------------------------ !scalars integer,optional,intent(in) :: line integer :: assert_eqn character(len=*),intent(in) :: message character(len=*),optional,intent(in) :: file !arrays integer,intent(in) :: nn(:) !Local variables------------------------------- integer :: f90line=0 character(len=500) :: f90name='Subroutine Unknown' ! ************************************************************************* if (ALL(nn(2:)==nn(1))) then assert_eqn=nn(1) else if (PRESENT(line)) f90line=line if (PRESENT(file)) f90name= basename(file) call msg_hndl(message,'ERROR','PERS',f90name,line) end if end function assert_eqn !!*** !---------------------------------------------------------------------- !!****f* m_errors/assert1 !! NAME !! assert1 !! !! FUNCTION !! Routines for argument checking and error handling. Report and die if !! any logical is false (used for arg range checking). !! !! INPUTS !! l1,l2,.. logical values to be checked (array version is also provided) !! message(len=*)=tag with additiona information !! !! PARENTS !! !! CHILDREN !! abimem_get_info,abimem_shutdown,show_units,wrtout !! !! SOURCE subroutine assert1(l1,message,file,line) !This section has been created automatically by the script Abilint (TD). !Do not modify the following lines by hand. #undef ABI_FUNC #define ABI_FUNC 'assert1' !End of the abilint section implicit none !Arguments ------------------------------------ integer,optional,intent(in) :: line character(len=*),intent(in) :: message character(len=*),optional,intent(in) :: file logical,intent(in) :: l1 !Local variables------------------------------- integer :: f90line=0 character(len=500) :: f90name='Subroutine Unknown' ! ************************************************************************* if (.not.l1) then if (PRESENT(line)) f90line=line if (PRESENT(file)) f90name= basename(file) call msg_hndl(message,'ERROR','PERS',f90name,f90line) end if end subroutine assert1 !!*** !---------------------------------------------------------------------- !!****f* m_errors/assert2 !! NAME !! assert2 !! !! FUNCTION !! Routines for argument checking and error handling. Report and die if ! any logical is false (used for arg range checking). !! !! INPUTS !! l1,l2,.. logical values to be checked (array version is also provided) !! message(len=*)=tag with additional information !! !! PARENTS !! !! CHILDREN !! abimem_get_info,abimem_shutdown,show_units,wrtout !! !! SOURCE subroutine assert2(l1,l2,message,file,line) !This section has been created automatically by the script Abilint (TD). !Do not modify the following lines by hand. #undef ABI_FUNC #define ABI_FUNC 'assert2' !End of the abilint section implicit none !Arguments ------------------------------------ integer,optional,intent(in) :: line character(len=*),intent(in) :: message character(len=*),optional,intent(in) :: file logical,intent(in) :: l1,l2 !Local variables------------------------------- integer :: f90line=0 character(len=500) :: f90name='Subroutine Unknown' ! ************************************************************************* if (.not.(l1.and.l2)) then if (PRESENT(line)) f90line=line if (PRESENT(file)) f90name= basename(file) call msg_hndl(message,'ERROR','PERS',f90name,f90line) end if end subroutine assert2 !!*** !---------------------------------------------------------------------- !!****f* m_errors/assert3 !! NAME !! assert3 !! !! FUNCTION !! Routines for argument checking and error handling. Report and die if !! any logical is false (used for arg range checking). !! !! INPUTS !! l1,l2,.. logical values to be checked (array version is also provided) !! message(len=*)=tag with additional information !! !! PARENTS !! !! CHILDREN !! abimem_get_info,abimem_shutdown,show_units,wrtout !! !! SOURCE subroutine assert3(l1,l2,l3,message,file,line) !This section has been created automatically by the script Abilint (TD). !Do not modify the following lines by hand. #undef ABI_FUNC #define ABI_FUNC 'assert3' !End of the abilint section implicit none !Arguments ------------------------------------ integer,optional,intent(in) :: line character(len=*),intent(in) :: message character(len=*),optional,intent(in) :: file logical,intent(in) :: l1,l2,l3 !Local variables------------------------------- integer :: f90line=0 character(len=500) :: f90name='Subroutine Unknown' ! ************************************************************************* if (.not.(l1.and.l2.and.l3)) then if (PRESENT(line)) f90line=line if (PRESENT(file)) f90name= basename(file) call msg_hndl(message,'ERROR','PERS',f90name,f90line) end if end subroutine assert3 !!*** !---------------------------------------------------------------------- !!****f* m_errors/assert4 !! NAME !! assert4 !! !! FUNCTION !! Routines for argument checking and error handling. Report and die if !! any logical is false (used for arg range checking). !! !! INPUTS !! l1,l2,.. logical values to be checked (array version is also provided) !! message(len=*)=tag with additional information !! !! PARENTS !! !! CHILDREN !! abimem_get_info,abimem_shutdown,show_units,wrtout !! !! SOURCE subroutine assert4(l1,l2,l3,l4,message,file,line) !This section has been created automatically by the script Abilint (TD). !Do not modify the following lines by hand. #undef ABI_FUNC #define ABI_FUNC 'assert4' !End of the abilint section implicit none !Arguments ------------------------------------ integer,optional,intent(in) :: line character(len=*),intent(in) :: message character(len=*),optional,intent(in) :: file logical,intent(in) :: l1,l2,l3,l4 !Local variables------------------------------- integer :: f90line=0 character(len=500) :: f90name='Subroutine Unknown' ! ************************************************************************* if (.not.(l1.and.l2.and.l3.and.l4)) then if (PRESENT(line)) f90line=line if (PRESENT(file)) f90name= basename(file) call msg_hndl(message,'ERROR','PERS',f90name,f90line) end if end subroutine assert4 !!*** !---------------------------------------------------------------------- !!****f* m_errors/assert_v !! NAME !! assert_v !! !! FUNCTION !! Routines for argument checking and error handling. Report and die if !! any logical is false (used for arg range checking). !! !! PARENTS !! !! CHILDREN !! abimem_get_info,abimem_shutdown,show_units,wrtout !! !! SOURCE subroutine assert_v(n,message,file,line) !This section has been created automatically by the script Abilint (TD). !Do not modify the following lines by hand. #undef ABI_FUNC #define ABI_FUNC 'assert_v' !End of the abilint section implicit none !Arguments ------------------------------------ integer,optional,intent(in) :: line character(len=*),intent(in) :: message character(len=*),optional,intent(in) :: file logical,intent(in) :: n(:) !Local variables------------------------------- integer :: f90line=0 character(len=500) :: f90name='Subroutine Unknown' ! ************************************************************************* if (.not.ALL(n)) then if (PRESENT(line)) f90line=line if (PRESENT(file)) f90name= basename(file) call msg_hndl(message,'ERROR','PERS',f90name,f90line) end if end subroutine assert_v !!*** !---------------------------------------------------------------------- !!****f* m_errors/netcdf_check !! NAME !! netcdf_check !! !! FUNCTION !! Error handler for Netcdf calls. !! !! INPUTS !! ncerr=Status error returned by the Netcdf library. !! msg=User-defined string with info on the action that was performed !! file= name of the file. !! line= line number. !! !! NOTES !! This routine is usually interfaced with the macros defined in abi_common.h !! !! PARENTS !! !! CHILDREN !! abimem_get_info,abimem_shutdown,show_units,wrtout !! !! SOURCE subroutine netcdf_check(ncerr,msg,file,line) !This section has been created automatically by the script Abilint (TD). !Do not modify the following lines by hand. #undef ABI_FUNC #define ABI_FUNC 'netcdf_check' !End of the abilint section implicit none !Arguments ------------------------------------ integer,intent(in) :: ncerr character(len=*),intent(in) :: msg character(len=*),optional,intent(in) :: file integer,optional,intent(in) :: line !Local variables------------------------------- integer :: f90line character(len=500) :: f90name character(len=1024) :: nc_msg character(len=2048) :: my_msg ! ************************************************************************* #ifdef HAVE_TRIO_NETCDF if (ncerr /= NF90_NOERR) then if (PRESENT(line)) then f90line=line else f90line=0 end if if (PRESENT(file)) then f90name = basename(file) else f90name='Subroutine Unknown' end if ! ! Append Netcdf string to user-defined message. write(nc_msg,'(a,2x,a)')' - NetCDF library returned:',TRIM(nf90_strerror(ncerr)) !write(std_out,*)TRIM(nf90_strerror(ncerr)) my_msg = TRIM(msg) // TRIM(nc_msg) call msg_hndl(my_msg,"ERROR","PERS",f90name,f90line) end if #endif end subroutine netcdf_check !!*** !---------------------------------------------------------------------- !!****f* m_errors/sentinel !! NAME !! sentinel !! !! FUNCTION !! Announce the entering and the exiting from a function. Useful for poor-man debugging. !! !! INPUTS !! level=1 when entering, 2 for exit. !! mode_paral= ['COLL'|'PERS'|'COLL_SILENT|PERS_SILENT'] !! 'COLL' and 'PERS' refer to the output mode used in wrtout to report the message. !! 'COLL_SILENT' and 'PERS_SILENT' can be used if the procedure is called several times inside a loop. !! In this case sentinel will report only the first entry and the first exit using either 'COLL' or 'PERS' mode. !! file=File name !! func=Name of the procedure to be tested (passed through ABI_FUNC macro) !! [line]=Line number. Defaults to 0. !! !! NOTES !! This routine is usually interfaced with the macros defined in abi_common.h !! !! PARENTS !! !! CHILDREN !! abimem_get_info,abimem_shutdown,show_units,wrtout !! !! SOURCE subroutine sentinel(level,mode_paral,file,func,line) !This section has been created automatically by the script Abilint (TD). !Do not modify the following lines by hand. #undef ABI_FUNC #define ABI_FUNC 'sentinel' use interfaces_14_hidewrite !End of the abilint section implicit none !Arguments ------------------------------------ integer,intent(in) :: level integer,optional,intent(in) :: line character(len=*),intent(in) :: mode_paral character(len=*),optional,intent(in) :: func character(len=*),optional,intent(in) :: file !Local variables------------------------------- integer,save :: level_save=0 integer :: ii integer :: f90line character(len=500),save :: func_save character(len=4) :: my_mode character(len=10) :: lnum character(len=500) :: my_func, my_file character(len=500) :: msg ! ********************************************************************* ! initialize the variable my_func = 'Function Unknown'; if (PRESENT(func)) my_func = basename(func) my_file = "File Unknown"; if (PRESENT(file)) my_file = basename(file) level_save=level; func_save=my_func f90line=0; if (PRESENT(line)) f90line=line if (toupper(mode_paral)=='COLL_SILENT'.or.toupper(mode_paral)=='PERS_SILENT') then ! * Silent mode, check if we are inside a loop. if (level==level_save .and. my_func==func_save) RETURN ii = index( toupper(mode_paral), '_SILENT') my_mode=toupper(mode_paral(1:ii-1)) else ! * Normal mode. my_mode=mode_paral end if if (my_mode/='COLL'.or.my_mode/='PERS') my_mode='COLL' write(lnum,"(i0)")f90line my_func= TRIM(my_func)//"@"//TRIM(my_file)//":"//TRIM(lnum) if (level==1) then msg = ' '//TRIM(my_func)//' >>>>> ENTER'//ch10 else if (level==2) then msg = ' '//TRIM(my_func)//' >>>>> EXIT '//ch10 else call die('Wrong level', & & __FILE__,& & __LINE__) end if call wrtout(std_out,msg,my_mode) call flush_unit(std_out) end subroutine sentinel !!*** !---------------------------------------------------------------------- !!****f* m_errors/die !! NAME !! die !! !! FUNCTION !! Stop smoothly the execution in case of unexpected events reporting the !! line number and the file name where the error occurred as well as the !! MPI rank of the processor. This routine is usually interfaced through !! some macro defined in abi_common.h !! !! INPUTS !! message=String containing additional information on the nature of the problem !! line=Line number of the file where problem occurred !! f90name=Name of the f90 file containing the caller !! !! PARENTS !! m_errors,m_xc_vdw !! !! CHILDREN !! abimem_get_info,abimem_shutdown,show_units,wrtout !! !! SOURCE subroutine die(message,file,line) !This section has been created automatically by the script Abilint (TD). !Do not modify the following lines by hand. #undef ABI_FUNC #define ABI_FUNC 'die' use interfaces_14_hidewrite use interfaces_16_hideleave !End of the abilint section implicit none !Arguments ------------------------------------ integer,optional,intent(in) :: line character(len=*),intent(in) :: message character(len=*),optional,intent(in) :: file !Local variables------------------------------- integer :: rank integer :: f90line=0 character(len=10) :: lnum,strank character(len=500) :: f90name='Subroutine Unknown' character(len=500) :: msg ! ********************************************************************* if (PRESENT(line)) f90line=line write(lnum,"(i0)")f90line ! === Determine my rank inside MPI_COMM_WORLD === rank = xmpi_comm_rank(xmpi_world) write(strank,"(i0)")rank if (PRESENT(file)) f90name= basename(file) msg=TRIM(f90name)//':'//TRIM(lnum)//' P'//TRIM(strank) write(msg,'(a,2x,2a,2x,a)')ch10,& & TRIM(msg),ch10,& & TRIM(message) call wrtout(std_out,msg,'PERS') call leave_new('PERS') end subroutine die !!*** !---------------------------------------------------------------------- !!****f* m_errors/msg_hndl !! NAME !! msg_hndl !! !! FUNCTION !! Basic error handler for abinit. This routine is usually interfaced through some macro defined in abi_common.h !! !! INPUTS !! message=string containing additional information on the nature of the problem !! level=string defining the type of problem. Possible values are !! COMMENT !! WARNING !! ERROR !! BUG !! line=line number of the file where problem occurred !! file=name of the f90 file containing the caller !! mode_paral=Either "COLL" or "PERS". !! NODUMP= (optional) if present dump config before stopping !! NOSTOP= (optional) if present don't stop even in the case of an error or a bug !! !! OUTPUT !! !! PARENTS !! m_errors !! !! CHILDREN !! abimem_get_info,abimem_shutdown,show_units,wrtout !! !! SOURCE subroutine msg_hndl(message,level,mode_paral,file,line,NODUMP,NOSTOP) !This section has been created automatically by the script Abilint (TD). !Do not modify the following lines by hand. #undef ABI_FUNC #define ABI_FUNC 'msg_hndl' use interfaces_14_hidewrite use interfaces_16_hideleave !End of the abilint section implicit none !Arguments ------------------------------------ integer,optional,intent(in) :: line logical,optional,intent(in) :: NODUMP,NOSTOP character(len=*),intent(in) :: level,message character(len=*),optional,intent(in) :: file character(len=*),intent(in) :: mode_paral !Local variables------------------------------- integer :: f90line,ierr character(len=10) :: lnum character(len=500) :: f90name character(len=LEN(message)) :: my_msg character(len=MAX(4*LEN(message),2000)) :: sbuf ! Increase size and keep fingers crossed! ! ********************************************************************* if (PRESENT(line)) then f90line=line else f90line=0 end if write(lnum,"(i0)")f90line if (PRESENT(file)) then f90name = basename(file) else f90name='Subroutine Unknown' end if my_msg = lstrip(message) select case (toupper(level)) case ('COMMENT','WARNING') write(sbuf,'(8a,i0,7a)')ch10,& "--- !",TRIM(level),ch10,& "src_file: ",TRIM(f90name),ch10,& "src_line: ",f90line,ch10,& "message: |",ch10,TRIM(indent(my_msg)),ch10,& "...",ch10 call wrtout(std_out,sbuf,mode_paral) ! ERROR' or 'BUG' case default if ((.not.present(NOSTOP)).and.(.not.present(NODUMP))) then call print_kinds() call xmpi_show_info() call dump_config(std_out) ! Dump the backtrace if the compiler supports it. call show_backtrace() end if write(sbuf,'(8a,i0,2a,i0,7a)')ch10,& "--- !",TRIM(level),ch10,& "src_file: ",TRIM(f90name),ch10,& "src_line: ",f90line,ch10,& "mpi_rank: ",xmpi_comm_rank(xmpi_world),ch10,& "message: |",ch10,TRIM(indent(my_msg)),ch10,& "...",ch10 call wrtout(std_out,sbuf,mode_paral) if (.not.present(NOSTOP)) then ! The first MPI proc that gets here, writes the ABI_MPIABORTFILE with the message! ! The file is written only if nprocs > 1. Do not change this behaviour! if (.not. file_exists(ABI_MPIABORTFILE) .and. xmpi_comm_size(xmpi_world) > 1) then call lock_and_write(ABI_MPIABORTFILE, sbuf, ierr) end if ! And now we die! call leave_new(mode_paral,print_config=.FALSE.) end if end select end subroutine msg_hndl !!*** !---------------------------------------------------------------------- !!****f* m_errors/show_backtrace !! NAME !! show_backtrace !! !! FUNCTION !! shows a backtrace at an arbitrary place in user code. !! Program execution continues normally afterwards. !! The backtrace information is printed to the unit corresponding to ERROR_UNIT in ISO_FORTRAN_ENV. !! This is a (Gfortran extension| Ifort Extension) !! !! PARENTS !! m_errors !! !! CHILDREN !! abimem_get_info,abimem_shutdown,show_units,wrtout !! !! SOURCE subroutine show_backtrace() !This section has been created automatically by the script Abilint (TD). !Do not modify the following lines by hand. #undef ABI_FUNC #define ABI_FUNC 'show_backtrace' !End of the abilint section #if defined FC_GNU && defined HAVE_FC_BACKTRACE call backtrace() ! Gfortran extension #elif defined FC_INTEL call TRACEBACKQQ(USER_EXIT_CODE=-1) ! Ifort extension #endif end subroutine show_backtrace !!*** !---------------------------------------------------------------------- !!****f* m_errors/check_mpi_ierr !! NAME !! check_mpi_ierr !! !! FUNCTION !! Basic error handler for MPI calls. This routine is usually interfaced through some macro defined in abi_common.h !! !! INPUTS !! ierr=Exit status reported by an MPI call. !! line=line number of the file where problem occurred !! file=name of the f90 file containing the caller !! !! OUTPUT !! Write error message thep stop execution. !! !! PARENTS !! !! CHILDREN !! abimem_get_info,abimem_shutdown,show_units,wrtout !! !! SOURCE subroutine check_mpi_ierr(ierr,msg,file,line) !This section has been created automatically by the script Abilint (TD). !Do not modify the following lines by hand. #undef ABI_FUNC #define ABI_FUNC 'check_mpi_ierr' !End of the abilint section implicit none !Arguments ------------------------------------ integer,intent(in) :: ierr integer,optional,intent(in) :: line character(len=*),intent(in) :: msg character(len=*),optional,intent(in) :: file !Local variables------------------------------- integer,parameter :: mpi_msg_len=1000 integer :: f90line,ilen,ierr2 character(len=500) :: f90name='Subroutine Unknown' character(len=mpi_msg_len) :: mpi_msg_error character(len=mpi_msg_len+500) :: my_msg ! ********************************************************************* #ifdef HAVE_MPI if (ierr==MPI_SUCCESS) RETURN call MPI_ERROR_STRING(ierr, mpi_msg_error, ilen, ierr2) #else ilen=0; ierr2=0 mpi_msg_error = " Check_mpi_ierr should not be called in non-MPI mode!" if (ierr==0) RETURN #endif if (ilen>mpi_msg_len) write(std_out,*)" Warning_ MPI message has been truncated!" if (ierr2/=0) write(std_out,*)" Warning: MPI_ERROR_STRING returned ierr2= ",ierr2 f90line=0; if (PRESENT(line)) f90line=line if (PRESENT(file)) f90name = basename(file) my_msg = TRIM(msg)//ch10//TRIM(mpi_msg_error) call msg_hndl(my_msg,"ERROR","PERS",file=f90name,line=f90line) end subroutine check_mpi_ierr !!*** !---------------------------------------------------------------------- !!****f* m_errors/unused_int !! NAME !! unused_int !! !! FUNCTION !! Helper function used to silence compiler warnings due to unused variables. !! Interfaced via the ABI_UNUSED macro. !! !! INPUTS !! var=Scalar integer value !! !! OUTPUT !! None !! !! PARENTS !! !! SOURCE elemental subroutine unused_int(var) !This section has been created automatically by the script Abilint (TD). !Do not modify the following lines by hand. #undef ABI_FUNC #define ABI_FUNC 'unused_int' !End of the abilint section implicit none !Arguments ------------------------------------ integer,intent(in) :: var !Local variables------------------------------- integer :: dummy ! ********************************************************************* dummy = var end subroutine unused_int !!*** !---------------------------------------------------------------------- !!****f* m_errors/unused_real_dp !! NAME !! unused_real_dp !! !! FUNCTION !! Helper function used to silence warning messages due to unused variables. !! Interfaced via the ABI_UNUSED macro. !! !! INPUTS !! var=Scalar real value. !! !! OUTPUT !! None !! !! PARENTS !! !! CHILDREN !! signal !! !! SOURCE elemental subroutine unused_real_dp(var) !This section has been created automatically by the script Abilint (TD). !Do not modify the following lines by hand. #undef ABI_FUNC #define ABI_FUNC 'unused_real_dp' !End of the abilint section implicit none !Arguments ------------------------------------ real(dp),intent(in) :: var !Local variables------------------------------- real(dp) :: dummy ! ********************************************************************* dummy = var end subroutine unused_real_dp !!*** !---------------------------------------------------------------------- !!****f* m_errors/unused_real_sp !! NAME !! unused_real_sp !! !! FUNCTION !! Helper function used to silence compiler warnings due to unused variables. !! Interfaced via the ABI_UNUSED macro. Target: one-dimensional real(dp) vector. !! !! SOURCE elemental subroutine unused_real_sp(var) !This section has been created automatically by the script Abilint (TD). !Do not modify the following lines by hand. #undef ABI_FUNC #define ABI_FUNC 'unused_real_sp' !End of the abilint section implicit none !Arguments ------------------------------------ real(sp),intent(in) :: var !Local variables------------------------------- real(sp) :: dummy ! ********************************************************************* dummy = var end subroutine unused_real_sp !!*** !---------------------------------------------------------------------- !!****f* m_errors/unused_cplx_spc !! NAME !! unused_cplx_spc !! !! FUNCTION !! Helper function used to silence compiler warnings due to unused variables. !! Interfaced via the ABI_UNUSED macro. !! !! INPUTS !! var=Scalar complex value !! !! OUTPUT !! None !! !! SOURCE elemental subroutine unused_cplx_spc(var) !This section has been created automatically by the script Abilint (TD). !Do not modify the following lines by hand. #undef ABI_FUNC #define ABI_FUNC 'unused_cplx_spc' !End of the abilint section implicit none !Arguments ------------------------------------ complex(spc),intent(in) :: var !Local variables------------------------------- complex(spc) :: dummy ! ********************************************************************* dummy = var end subroutine unused_cplx_spc !!*** !---------------------------------------------------------------------- !!****f* m_errors/unused_cplx_dpc !! NAME !! unused_cplx_dpc !! !! FUNCTION !! Helper function used to silence compiler warnings due to unused variables. !! Interfaced via the ABI_UNUSED macro. !! !! INPUTS !! var=Scalar complex value !! !! OUTPUT !! None !! !! PARENTS !! !! CHILDREN !! signal !! !! SOURCE elemental subroutine unused_cplx_dpc(var) !This section has been created automatically by the script Abilint (TD). !Do not modify the following lines by hand. #undef ABI_FUNC #define ABI_FUNC 'unused_cplx_dpc' !End of the abilint section implicit none !Arguments ------------------------------------ complex(dpc),intent(in) :: var !Local variables------------------------------- complex(dpc) :: dummy ! ********************************************************************* dummy = var end subroutine unused_cplx_dpc !!*** !---------------------------------------------------------------------- !!****f* m_errors/unused_logical !! NAME !! unused_logical !! !! FUNCTION !! Helper function used to silence compiler warnings due to unused variables. !! Interfaced via the ABI_UNUSED macro. !! !! INPUTS !! var=Scalar logical value !! !! OUTPUT !! None !! !! PARENTS !! !! CHILDREN !! signal !! !! SOURCE elemental subroutine unused_logical(var) !This section has been created automatically by the script Abilint (TD). !Do not modify the following lines by hand. #undef ABI_FUNC #define ABI_FUNC 'unused_logical' !End of the abilint section implicit none !Arguments ------------------------------------ logical,intent(in) :: var !Local variables------------------------------- logical :: dummy ! ********************************************************************* dummy = var end subroutine unused_logical !!*** !---------------------------------------------------------------------- !!****f* m_errors/unused_ch !! NAME !! unused_ch !! !! FUNCTION !! Helper function used to silence compiler warnings due to unused variables. !! Interfaced via the ABI_UNUSED macro. !! !! INPUTS !! var=Scalar character value !! !! OUTPUT !! None !! !! PARENTS !! !! CHILDREN !! signal !! !! SOURCE elemental subroutine unused_ch(var) !This section has been created automatically by the script Abilint (TD). !Do not modify the following lines by hand. #undef ABI_FUNC #define ABI_FUNC 'unused_ch' !End of the abilint section implicit none !Arguments ------------------------------------ character(len=*),intent(in) :: var !Local variables------------------------------- character(len=LEN(var)) :: dummy ! ********************************************************************* dummy = var end subroutine unused_ch !!*** !---------------------------------------------------------------------- !!****f* m_errors/abietsf_msg_hndl !! NAME !! abietsf_msg_hndl !! !! FUNCTION !! Wrapper to interface the abinint error handlers with the error handling routines used in etsf-io. !! It is usually interfaced via the macro ETSF_* defined in abi_common.h !! !! INPUTS !! lstat=Logical flag returned by etsf-io routines. !! Error_data=Structure storing the error returned by etsf-io calls. !! [line]=line number of the file where the problem occurred !! [file]=name of the f90 file containing the caller !! mode_paral=Either "COLL" or "PERS". !! !! OUTPUT !! Only writing, then the code is stopped. !! !! PARENTS !! !! CHILDREN !! abimem_get_info,abimem_shutdown,show_units,wrtout !! !! SOURCE #if defined HAVE_TRIO_ETSF_IO subroutine abietsf_msg_hndl(lstat,Error_data,mode_paral,file,line) !This section has been created automatically by the script Abilint (TD). !Do not modify the following lines by hand. #undef ABI_FUNC #define ABI_FUNC 'abietsf_msg_hndl' !End of the abilint section implicit none !Arguments ------------------------------------ integer,optional,intent(in) :: line character(len=*),optional,intent(in) :: file character(len=*),intent(in) :: mode_paral logical,intent(in) :: lstat type(ETSF_io_low_error),intent(in) :: Error_data !Local variables------------------------------- integer :: f90line=0 character(len=500) :: f90name='Subroutine Unknown' character(len=etsf_io_low_error_len) :: errmess ! ********************************************************************* if (lstat) RETURN if (PRESENT(line)) f90line=line if (PRESENT(file)) f90name = file call etsf_io_low_error_to_str(errmess,Error_data) call msg_hndl(errmess,"ERROR",mode_paral,f90name,f90line) end subroutine abietsf_msg_hndl !!*** !---------------------------------------------------------------------- !!****f* m_errors/abietsf_warn !! NAME !! abietsf_warn !! !! FUNCTION !! Wrapper to write warning messages, only used for ETSF_IO routines !! It is usually interfaced via the macro ETSF_WARN defined in abi_common.h !! !! INPUTS !! lstat=status error. !! Error_data=Structure storing the error returned by etsf-io calls. !! [line]=line number of the file where the problem occurred !! [file]=name of the f90 file containing the caller !! mode_paral=Either "COLL" or "PERS". !! !! OUTPUT !! Only writing. !! !! PARENTS !! !! CHILDREN !! abimem_get_info,abimem_shutdown,show_units,wrtout !! !! SOURCE subroutine abietsf_warn(lstat,Error_data,mode_paral,file,line) !This section has been created automatically by the script Abilint (TD). !Do not modify the following lines by hand. #undef ABI_FUNC #define ABI_FUNC 'abietsf_warn' !End of the abilint section implicit none !Arguments ------------------------------------ integer,optional,intent(in) :: line logical,intent(in) :: lstat character(len=*),optional,intent(in) :: file character(len=*),intent(in) :: mode_paral type(ETSF_io_low_error),intent(in) :: Error_data !Local variables------------------------------- integer :: f90line=0 character(len=500) :: f90name='Subroutine Unknown' character(len=etsf_io_low_error_len) :: errmess ! ********************************************************************* if (lstat) RETURN if (PRESENT(line)) f90line=line if (PRESENT(file)) f90name = file call etsf_io_low_error_to_str(errmess,Error_data) call msg_hndl(errmess,"WARNING",mode_paral,f90name,f90line) end subroutine abietsf_warn !!*** #endif !---------------------------------------------------------------------- !!****f* m_errors/bigdft_lib_error !! NAME !! bigdft_lib_error !! !! FUNCTION !! Stop the code if bigdft library has not been enabled. !! Interfaced with the CPP macro BIGDFT_NOTENABLED_ERROR !! !! INPUTS !! line=line number of the file where problem occurred !! file=name of the f90 file containing the caller !! !! PARENTS !! !! CHILDREN !! abimem_get_info,abimem_shutdown,show_units,wrtout !! !! SOURCE subroutine bigdft_lib_error(file,line) !This section has been created automatically by the script Abilint (TD). !Do not modify the following lines by hand. #undef ABI_FUNC #define ABI_FUNC 'bigdft_lib_error' !End of the abilint section implicit none !Arguments ------------------------------------ integer,optional,intent(in) :: line character(len=*),optional,intent(in) :: file !Local variables------------------------------- character(len=500) :: message ! ********************************************************************* write(message,'(4a)') ch10,& & ' BigDFT support has not been enabled.', ch10, & & ' Action, used the flag --enable-bigdft when configuring.' if (PRESENT(file) .and. PRESENT(line)) then call msg_hndl(message,"ERROR","PERS",file=file,line=line) else call msg_hndl(message,"ERROR", "PERS") end if end subroutine bigdft_lib_error !!*** !---------------------------------------------------------------------- !!****f* m_errors/xlf_set_sighandler !! NAME !! xlf_set_sighandler !! !! FUNCTION !! Set the signal handler for IBM XLF !! !! NOTES !! See http://publib.boulder.ibm.com/infocenter/compbgpl/v9v111/index.jsp?topic=/com.ibm.xlf111.bg.doc/xlfopg/fptrap.htm !! The XL Fortran exception handlers and related routines are: !! xl__ieee !! Produces a traceback and an explanation of the signal and continues execution by supplying the default IEEE result !! for the failed computation. This handler allows the program to produce the same results as if exception detection was not turned on. !! xl__trce !! Produces a traceback and stops the program. !! xl__trcedump !! Produces a traceback and a core file and stops the program. !! xl__sigdump !! Provides a traceback that starts from the point at which it is called and provides information about the signal. !! You can only call it from inside a user-written signal handler. !! It does not stop the program. To successfully continue, the signal handler must perform some cleanup after calling this subprogram. !! xl__trbk !! Provides a traceback that starts from the point at which it is called. !! You call it as a subroutine from your code, rather than specifying it with the -qsigtrap option. It requires no parameters. It does not stop the program. !! !! PARENTS !! !! CHILDREN !! abimem_get_info,abimem_shutdown,show_units,wrtout !! !! SOURCE subroutine xlf_set_sighandler() !This section has been created automatically by the script Abilint (TD). !Do not modify the following lines by hand. #undef ABI_FUNC #define ABI_FUNC 'xlf_set_sighandler' !End of the abilint section implicit none !This section has been created automatically by the script Abilint (TD). !Do not modify the following lines by hand. #undef ABI_FUNC #define ABI_FUNC 'xlf_set_sighandler' !End of the abilint section ! ************************************************************************* #ifdef FC_IBM call SIGNAL(SIGTRAP, xl__trcedump) call SIGNAL(SIGFPE, xl__trcedump) #endif end subroutine xlf_set_sighandler !!*** !---------------------------------------------------------------------- !!****f* m_errors/abinit_doctor !! NAME !! abinit_doctor !! !! FUNCTION !! Perform checks on memory leaks and leaking file descriptors at the end of the run. !! !! INPUTS !! prefix=Prefix for output file (usually "__nameofprogram" e.g. __cut3d) !! [print_mem_report]=0 to disable the test on memory leaks (used in Abinit if bigdft is activated). !! Default: 1, i.e. memory check is always activated. !! !! PARENTS !! abinit,anaddb,conducti,cut3d,fftprof,fold2Bloch,ioprof,lapackprof !! macroave,mrgddb,mrgdv,mrggkk,mrgscr,optic,ujdet,vdw_kernelgen !! !! CHILDREN !! abimem_get_info,abimem_shutdown,show_units,wrtout !! !! SOURCE subroutine abinit_doctor(prefix, print_mem_report) !This section has been created automatically by the script Abilint (TD). !Do not modify the following lines by hand. #undef ABI_FUNC #define ABI_FUNC 'abinit_doctor' use interfaces_14_hidewrite !End of the abilint section implicit none !Arguments ------------------------------------ integer,optional,intent(in) :: print_mem_report character(len=*),intent(in) :: prefix !Local variables------------------------------- !scalars integer,parameter :: master=0 integer :: do_mem_report, my_rank #ifdef HAVE_MEM_PROFILING integer :: ii,ierr,unt integer :: nalloc,ndealloc integer(kind=8) :: memtot character(len=fnlen) :: path character(len=500) :: msg character(len=2000) :: errmsg #endif ! ************************************************************************* do_mem_report = 1; if (present(print_mem_report)) do_mem_report = print_mem_report my_rank = xmpi_comm_rank(xmpi_world) #ifdef HAVE_MEM_PROFILING errmsg = ""; ierr = 0 ! Test on memory leaks. call abimem_get_info(nalloc, ndealloc, memtot) call abimem_shutdown() if (do_mem_report == 1) then if ((nalloc == ndealloc) .and. (memtot == 0)) then write(msg,'(3a,i0,a,i0,3a,i0)')& & '- MEMORY CONSUMPTION REPORT:',ch10, & & '- There were ',nalloc,' allocations and ',ndealloc,' deallocations',ch10, & & '- Remaining memory at the end of the calculation is ',memtot else ! This msg will make the test fail if the memory leak occurs on master (no dash in the first column) write(msg,'(3a,i0,a,i0,3a,i0,6a)') 'MEMORY CONSUMPTION REPORT :',ch10, & & ' There were ',nalloc,' allocations and ',ndealloc,' deallocations',ch10, & & ' Remaining memory at the end of the calculation is ',memtot,ch10, & & ' As a help for debugging, you might set call abimem_init(2) in the main program,', ch10,& & ' then use tests/Scripts/memcheck.py to analyse the file abimem_rank[num].mocc that has been created.',ch10,& ' Note that abimem files can easily be multiple GB in size so do not use this option normally!' ! And this will make the code call mpi_abort if the leak occurs on my_rank != master ierr = ierr + 1 errmsg = strcat(errmsg, ch10, msg) end if else write(msg,'(3a)')& & '- MEMORY CONSUMPTION REPORT :',ch10, & & '- Memory profiling is activated but not yet usable when bigdft is used' end if ! Test whether all logical units have been closed. ! If you wonder why I'm doing this, remember that there's a per-user ! limit on the maximum number of open file descriptors. Hence descriptors ! represent a precious resource and we should close them as soon as possible. ii = num_opened_units(ignore=[std_err, std_in, std_out, ab_out]) if (ii > 0) then path = strcat(prefix, "_lunits_rank", itoa(my_rank), ".flun") if (open_file(path, msg, newunit=unt) /= 0) then MSG_ERROR(msg) end if call show_units(unt) close(unt) write(msg, "(a,i0,2a)")"Leaking ",ii," Fortran logical units. See: ",trim(path) errmsg = strcat(errmsg, ch10, msg) ierr = ierr + 1 end if if (my_rank == master) then call wrtout(ab_out, msg) end if if (ierr /= 0) then MSG_ERROR(errmsg) end if #else ABI_UNUSED(prefix) #endif end subroutine abinit_doctor !!*** END MODULE m_errors !!*** v_sim-3.8.0/lib/plug-ins/abinit/m_fstrings.F90000066400000000000000000001275771370110300500210550ustar00rootroot00000000000000!{\src2tex{textfont=tt}} !!****m* ABINIT/m_fstrings !! NAME !! m_fstrings !! !! FUNCTION !! This module contains basic tools to operate on Fortran strings. !! !! COPYRIGHT !! Copyright (C) 2008-2016 ABINIT group (MG, XG, MT, DC) !! This file is distributed under the terms of the !! GNU General Public License, see ~abinit/COPYING !! or http://www.gnu.org/copyleft/gpl.txt . !! !! PARENTS !! !! CHILDREN !! !! SOURCE #if defined HAVE_CONFIG_H #include "config.h" #endif #include "abi_common.h" MODULE m_fstrings use defs_basis, only : dp, std_out, ch10 implicit none private public :: is_letter ! Returns .TRUE. if ch is a letter and .FALSE. otherwise public :: is_digit ! Returns .TRUE. if ch is a digit (0,1,...,9) and .FALSE. otherwise public :: upper ! Convert lower case letters to UPPER CASE public :: toupper ! Convert lower case letters to UPPER CASE (function version) public :: lower ! Convert UPPER CASE letters to lower case public :: tolower ! Convert UPPER CASE letters to lower case (function version) public :: removesp ! Removes spaces, tabs, and control characters in string str public :: replace_ch0 ! Replace final '\0' with whitespaces public :: lstrip ! Remove leading spaces from string public :: ljust ! Return a left-justified string of length width. public :: lpad ! Pad a string adding repeat characters fillchar on the left side. public :: quote ! Return a new string enclosed by quotation marks. public :: rmquotes ! Remove quotation marks from a string. Return new string public :: write_num ! Writes a number to a string using format fmt public :: trimzero ! Deletes nonsignificant trailing zeroes from a number string. public :: writeq ! Writes a string of the form = value to unit public :: strcat ! Concatenate strings (function version) public :: sjoin ! Joins strings with a space separator. public :: yesno ! Convert boolean to "yes", "no" public :: itoa ! Convert an integer into a string public :: ftoa ! Convert a float into a string public :: ktoa ! Convert a k-point into a string. public :: ltoa ! Convert a list into a string. public :: atoi ! Convert a string into a integer public :: basename ! Returns the final component of a pathname. public :: firstchar ! Returns .TRUE. is the first character in a string belongs to a gives set. public :: startswith ! Returns .TRUE. is the string starts with the specified prefix. public :: endswith ! Returns .True if the string ends with the specified suffix. public :: indent ! Indent text public :: prep_dash ! Prepend `-` to each line in a string. public :: int2char4 ! Convert a positive integer number (zero included) to a character(len=*) ! with trailing zeros if the number is <=9999 public :: int2char10 ! Convert a positive integer number (zero included) to a character(len=10) ! with trailing blanks public :: char_count ! Count the occurrences of a character in a string. !TODO method to center a string interface write_num module procedure write_rdp_0D module procedure write_int_0D end interface write_num interface writeq module procedure writeq_rdp_0D module procedure writeq_int_0D end interface writeq interface is_digit module procedure is_digit_0D end interface is_digit interface firstchar module procedure firstchar_0d module procedure firstchar_1d end interface firstchar interface sjoin module procedure sjoin_2 module procedure sjoin_3 module procedure sjoin_4 end interface sjoin interface strcat module procedure strcat_2 module procedure strcat_3 module procedure strcat_4 end interface strcat interface ltoa module procedure ltoa_int module procedure ltoa_dp end interface ltoa character(len=1),parameter :: BLANK=' ' character(len=1),parameter :: NCHAR = char(10) character(len=1),parameter :: DIR_SEPARATOR = '/' integer,parameter :: ASCII_A=ICHAR('A') integer,parameter :: ASCII_Z=ICHAR('Z') integer,parameter :: ASCII_aa=ICHAR('a') integer,parameter :: ASCII_zz=ICHAR('z') integer,parameter :: SHIFT=ASCII_aa-ASCII_A ! Capital letters have smaller Dec value in the ASCII table. integer,parameter :: ASCII_0=ICHAR('0') integer,parameter :: ASCII_9=ICHAR('9') integer,parameter :: MAX_SLEN=500 CONTAINS !=========================================================== !!*** !!****f* m_fstrings/is_letter !! NAME !! is_letter !! !! FUNCTION !! Returns .TRUE. if ch is a letter and .FALSE. otherwise. !! !! SOURCE pure function is_letter(ch) result(ans) !This section has been created automatically by the script Abilint (TD). !Do not modify the following lines by hand. #undef ABI_FUNC #define ABI_FUNC 'is_letter' !End of the abilint section character(len=1),intent(in) :: ch logical :: ans ! ********************************************************************* select case (ICHAR(ch)) case (ASCII_A:ASCII_Z,ASCII_aa:ASCII_zz) ans=.TRUE. case DEFAULT ans=.FALSE. end select end function is_letter !!*** !!****f* m_fstrings/is_digit_0D !! NAME !! is_digit_0D !! !! FUNCTION !! Returns .TRUE. if ch is a digit (0,1,...,9) and .FALSE. otherwise. !! !! SOURCE pure function is_digit_0D(ch) result(ans) !Arguments ------------------------------------ !This section has been created automatically by the script Abilint (TD). !Do not modify the following lines by hand. #undef ABI_FUNC #define ABI_FUNC 'is_digit_0D' !End of the abilint section character(len=1),intent(in) :: ch logical :: ans ! ********************************************************************* select case (ICHAR(ch)) case(ASCII_0:ASCII_9) ans=.TRUE. case default ans=.FALSE. end select end function is_digit_0D !!*** !!****f* m_fstrings/upper !! NAME !! upper !! !! FUNCTION !! Convert lower case letters to UPPER CASE. !! !! SOURCE pure subroutine upper(str) !This section has been created automatically by the script Abilint (TD). !Do not modify the following lines by hand. #undef ABI_FUNC #define ABI_FUNC 'upper' !End of the abilint section character(len=*),intent(inout) :: str !Local variables------------------------------- integer :: ic,iasc ! ********************************************************************* do ic=1,LEN_TRIM(str) iasc=IACHAR(str(ic:ic)) if (iasc>=ASCII_aa.and.iasc<=ASCII_zz) str(ic:ic)=ACHAR(iasc-SHIFT) end do end subroutine upper !!*** !---------------------------------------------------------------------- !!****f* m_fstrings/toupper !! NAME !! toupper !! !! FUNCTION !! Convert lower case letters to UPPER CASE (function version). !! !! SOURCE pure function toupper(str_in) result(str_out) !This section has been created automatically by the script Abilint (TD). !Do not modify the following lines by hand. #undef ABI_FUNC #define ABI_FUNC 'toupper' !End of the abilint section character(len=*),intent(in) :: str_in character(len=LEN_TRIM(str_in)) :: str_out !Local variables------------------------------- integer :: ic,iasc ! ********************************************************************* do ic=1,LEN_TRIM(str_in) iasc=IACHAR(str_in(ic:ic)) if (iasc>=ASCII_aa.and.iasc<=ASCII_zz) then str_out(ic:ic)=ACHAR(iasc-SHIFT) else str_out(ic:ic)=str_in(ic:ic) end if end do end function toupper !!*** !---------------------------------------------------------------------- !!****f* m_fstrings/lower !! NAME !! lower !! !! FUNCTION !! Convert UPPER CASE letters to lower case. !! !! PARENTS !! fftprof,ioprof,lapackprof !! !! CHILDREN !! !! SOURCE pure subroutine lower(str) !This section has been created automatically by the script Abilint (TD). !Do not modify the following lines by hand. #undef ABI_FUNC #define ABI_FUNC 'lower' !End of the abilint section character(len=*),intent(inout) :: str !Local variables------------------------------- integer :: ic,iasc ! ********************************************************************* do ic=1,LEN_TRIM(str) iasc=IACHAR(str(ic:ic)) if (iasc>=ASCII_A.and.iasc<=ASCII_Z) str(ic:ic)=ACHAR(iasc+SHIFT) end do end subroutine lower !!*** !---------------------------------------------------------------------- !!****f* m_fstrings/tolower !! NAME !! tolower !! !! FUNCTION !! Convert UPPER CASE letters to lower case (function version). !! !! SOURCE pure function tolower(str_in) result(str_out) !This section has been created automatically by the script Abilint (TD). !Do not modify the following lines by hand. #undef ABI_FUNC #define ABI_FUNC 'tolower' !End of the abilint section character(len=*),intent(in) :: str_in character(len=LEN_TRIM(str_in)) :: str_out !Local variables------------------------------- integer :: ic,iasc ! ********************************************************************* do ic=1,LEN_TRIM(str_in) iasc=IACHAR(str_in(ic:ic)) if (iasc>=ASCII_A.and.iasc<=ASCII_Z) then str_out(ic:ic)=ACHAR(iasc+SHIFT) else str_out(ic:ic)=str_in(ic:ic) end if end do end function tolower !!*** !---------------------------------------------------------------------- !!****f* m_fstrings/removesp !! NAME !! removesp !! !! FUNCTION !! Removes spaces, tabs, and control characters in string str. !! !! INPUTS !! !! OUTPUT !! !! PARENTS !! !! CHILDREN !! trimzero,write_num !! !! SOURCE subroutine removesp(str) !This section has been created automatically by the script Abilint (TD). !Do not modify the following lines by hand. #undef ABI_FUNC #define ABI_FUNC 'removesp' !End of the abilint section character(len=*),intent(inout) :: str !Local variables------------------------------- integer :: i,k,lenstr,ich character(len=1):: ch character(len=LEN_TRIM(str)):: outstr ! ********************************************************************* str=ADJUSTL(str) ; lenstr=LEN_TRIM(str) outstr=BLANK ; k=0 do i=1,lenstr ch=str(i:i) ich=IACHAR(ch) select case(ich) case(0:32) ! space, tab, or control character CYCLE case(33:) k=k+1 outstr(k:k)=ch end select end do str=ADJUSTL(outstr) end subroutine removesp !!*** !!****m* m_fstrings/replace_ch0 !! NAME !! replace_ch0 !! !! FUNCTION !! Little tool to change all final '\0' (end of string in C) characters to ' ' (space). !! !! SIDE EFFECTS !! * string = the string to convert. It is done in-place. !! !! SOURCE elemental subroutine replace_ch0(string) !This section has been created automatically by the script Abilint (TD). !Do not modify the following lines by hand. #undef ABI_FUNC #define ABI_FUNC 'replace_ch0' !End of the abilint section character(len=*), intent(inout) :: string integer :: i, l i = index(string, char(0)) if (i > 0) then l = len(string) string(i:l) = repeat(" ", l - i + 1) end if end subroutine replace_ch0 !!*** !---------------------------------------------------------------------- !!****f* m_fstrings/lstrip !! NAME !! lstrip !! !! FUNCTION !! Removes leading spaces from the input string. !! !! SOURCE pure function lstrip(istr) result(ostr) !This section has been created automatically by the script Abilint (TD). !Do not modify the following lines by hand. #undef ABI_FUNC #define ABI_FUNC 'lstrip' !End of the abilint section character(len=*),intent(in) :: istr character(len=len(istr)) :: ostr !Local variables------------------------------- integer :: ii,jj,lg ! ********************************************************************* lg=LEN(istr) do ii=1,lg if (istr(ii:ii)/=BLANK) EXIT end do ostr = " " do jj=1,lg-ii+1 ostr(jj:jj) = istr(ii:ii) ii=ii+1 end do end function lstrip !!*** !---------------------------------------------------------------------- !!****f* m_fstrings/ljust !! NAME !! ljust !! !! FUNCTION !! Return S left-justified in a string of length width. Padding is !! done using the specified fill character (default is a space). !! !! SOURCE pure function ljust(istr, width, fillchar) result(ostr) !This section has been created automatically by the script Abilint (TD). !Do not modify the following lines by hand. #undef ABI_FUNC #define ABI_FUNC 'ljust' !End of the abilint section character(len=*),intent(in) :: istr integer,intent(in) :: width character(len=width) :: ostr character(len=1),optional,intent(in) :: fillchar !Local variables------------------------------- integer :: ii ! ********************************************************************* ostr = ADJUSTL(istr) if (PRESENT(fillchar)) then do ii=LEN_TRIM(ostr)+1,width ostr(ii:ii) = fillchar end do end if end function ljust !!*** !---------------------------------------------------------------------- !!****f* m_fstrings/lpad !! NAME !! lpad !! !! FUNCTION !! Pad a string adding repeat characters fillchar on the left side. !! Padding is done using the specified fill character (default is a blanck character). !! !! INPUTS !! !! OUTPUT !! !! PARENTS !! !! CHILDREN !! !! SOURCE pure function lpad(istr, repeat, fillchar) result(ostr) !This section has been created automatically by the script Abilint (TD). !Do not modify the following lines by hand. #undef ABI_FUNC #define ABI_FUNC 'lpad' !End of the abilint section character(len=*),intent(in) :: istr integer,intent(in) :: repeat character(len=LEN_TRIM(istr) + repeat) :: ostr character(len=1),optional,intent(in) :: fillchar !Local variables------------------------------- integer :: ii character(len=1) :: ch ! ********************************************************************* ostr(repeat+1:) = TRIM(istr) ch = " "; if (PRESENT(fillchar)) ch = fillchar do ii=1,repeat ostr(ii:ii) = ch end do end function lpad !!*** !---------------------------------------------------------------------- !!****f* m_fstrings/quote !! NAME !! quote !! !! FUNCTION !! Return a new string enclosed by quotation marks. !! !! SOURCE pure function quote(istr) result(ostr) !This section has been created automatically by the script Abilint (TD). !Do not modify the following lines by hand. #undef ABI_FUNC #define ABI_FUNC 'quote' !End of the abilint section character(len=*),intent(in) :: istr character(len=LEN_TRIM(istr)+2) :: ostr !Local variables------------------------------- integer :: ii character(len=1) :: qq character(len=LEN(istr)+2) :: tmp ! ********************************************************************* do ii=1,LEN(istr) if (istr(ii:ii)/=BLANK) EXIT end do qq = istr(ii:ii) if (qq == "'" .or. qq == '"') then ! Don't add quotation marks if they already present. tmp = istr ii = LEN_TRIM(tmp) ! If the string is not closed, fix it. if (tmp(ii:ii) /= qq) tmp(ii+1:ii+1) = qq ostr = TRIM(tmp) else qq = '"' ostr(1:1) = qq ostr(2:) = TRIM(istr) ii = LEN_TRIM(ostr)+1 ostr(ii:ii) = qq end if end function quote !!*** !---------------------------------------------------------------------- !!****f* m_fstrings/rmquotes !! NAME !! rmquotes !! !! FUNCTION !! Remove quotation marks from a string. Return new string !! !! SOURCE pure function rmquotes(istr) result(ostr) !This section has been created automatically by the script Abilint (TD). !Do not modify the following lines by hand. #undef ABI_FUNC #define ABI_FUNC 'rmquotes' !End of the abilint section character(len=*),intent(in) :: istr character(len=len(istr)) :: ostr !Local variables------------------------------- integer :: ii,cnt ! ********************************************************************* ostr = ""; cnt = 0 do ii=1,len_trim(istr) if (any(istr(ii:ii) == ["'", '"'])) cycle cnt = cnt + 1 ostr(cnt:cnt) = istr(ii:ii) end do end function rmquotes !!*** !---------------------------------------------------------------------- !!****f* m_fstrings/write_rdp_0d !! NAME !! write_rdp_0d !! !! FUNCTION !! Writes a number to a string using format fmt. !! !! PARENTS !! !! CHILDREN !! trimzero,write_num !! !! SOURCE subroutine write_rdp_0d(rnum,str,fmt) !This section has been created automatically by the script Abilint (TD). !Do not modify the following lines by hand. #undef ABI_FUNC #define ABI_FUNC 'write_rdp_0d' !End of the abilint section implicit none !Arguments ------------------------------------ real(dp),intent(in) :: rnum character(len=*),intent(in) :: fmt character(len=*),intent(out) :: str !Local variables------------------------------- character(len=LEN(fmt)+2) :: formt ! ********************************************************************* formt='('//TRIM(fmt)//')' write(str,formt)rnum str=ADJUSTL(str) end subroutine write_rdp_0D !!*** !---------------------------------------------------------------------- !!****f* m_fstrings/write_int_0d !! NAME !! write_int_0d !! !! FUNCTION !! Writes a number to a string using format fmt. !! !! PARENTS !! !! CHILDREN !! trimzero,write_num !! !! SOURCE subroutine write_int_0D(inum,str,fmt) !Arguments ------------------------------------ !This section has been created automatically by the script Abilint (TD). !Do not modify the following lines by hand. #undef ABI_FUNC #define ABI_FUNC 'write_int_0D' !End of the abilint section integer,intent(in) :: inum character(len=*),intent(in) :: fmt character(len=*),intent(out) :: str !Local variables------------------------------- character(len=LEN(fmt)+2) :: formt ! ********************************************************************* formt='('//TRIM(fmt)//')' write(str,formt) inum str=ADJUSTL(str) end subroutine write_int_0D !!*** !---------------------------------------------------------------------- !!****f* m_fstrings/trimzero !! NAME !! trimzero !! !! FUNCTION !! Deletes nonsignificant trailing zeroes from number string str. If number !! string ends in a decimal point, one trailing zero is added. !! !! INPUTS !! !! OUTPUT !! !! PARENTS !! m_fstrings !! !! CHILDREN !! trimzero,write_num !! !! SOURCE ! NOT sure it will work subroutine trimzero(str) !This section has been created automatically by the script Abilint (TD). !Do not modify the following lines by hand. #undef ABI_FUNC #define ABI_FUNC 'trimzero' !End of the abilint section character(len=*),intent(inout) :: str !Local variables------------------------------- integer :: i,ipos,lstr character :: ch character(len=10) :: sexp ! ********************************************************************* ipos=SCAN(str,'eE') if (ipos>0) then sexp=str(ipos:) str=str(1:ipos-1) end if lstr=LEN_TRIM(str) do i=lstr,1,-1 ch=str(i:i) if (ch=='0') CYCLE if (ch=='.') then str=str(1:i)//'0' if (ipos>0) str=TRIM(str)//TRIM(sexp) EXIT end if str=str(1:i) EXIT end do if (ipos>0) str=TRIM(str)//TRIM(sexp) end subroutine trimzero !!*** !---------------------------------------------------------------------- !!****f* m_fstrings/writeq_rdp_0D !! NAME !! writeq_rdp_0D !! !! FUNCTION !! Writes a string of the form = value to unit. !! !! INPUTS !! !! OUTPUT !! !! PARENTS !! !! CHILDREN !! trimzero,write_num !! !! SOURCE subroutine writeq_rdp_0D(unit,namestr,value,fmt) !This section has been created automatically by the script Abilint (TD). !Do not modify the following lines by hand. #undef ABI_FUNC #define ABI_FUNC 'writeq_rdp_0D' !End of the abilint section real(dp),intent(in) :: value integer,intent(in) :: unit character(len=*),intent(in) :: fmt character(len=*),intent(in) :: namestr !Local variables------------------------------- character(len=32) :: tempstr ! ********************************************************************* call write_num(value,tempstr,fmt) call trimzero(tempstr) write(unit,*)TRIM(namestr)//' = '//TRIM(tempstr) end subroutine writeq_rdp_0D !!*** !---------------------------------------------------------------------- !!****f* m_fstrings/writeq_int_0D !! NAME !! writeq_int_0D !! !! FUNCTION !! Writes a string of the form = value to unit. !! !! INPUTS !! !! OUTPUT !! !! PARENTS !! !! CHILDREN !! trimzero,write_num !! !! SOURCE subroutine writeq_int_0D(unit,namestr,ivalue,fmt) !This section has been created automatically by the script Abilint (TD). !Do not modify the following lines by hand. #undef ABI_FUNC #define ABI_FUNC 'writeq_int_0D' !End of the abilint section integer,intent(in) :: ivalue integer,intent(in) :: unit character(len=*),intent(in) :: namestr character(len=*),intent(in) :: fmt !Local variables------------------------------- character(len=32) :: tempstr ! ********************************************************************* call write_num(ivalue,tempstr,fmt) call trimzero(tempstr) write(unit,*)TRIM(namestr)//' = '//TRIM(tempstr) end subroutine writeq_int_0D !!*** !---------------------------------------------------------------------- !!****f* m_fstrings/sjoin_2 !! NAME !! sjoin_2 !! !! FUNCTION !! Joins two strings with a space separator except if first string is empty. !! pure function sjoin_2(str1,str2) result(ostr) !This section has been created automatically by the script Abilint (TD). !Do not modify the following lines by hand. #undef ABI_FUNC #define ABI_FUNC 'sjoin_2' !End of the abilint section character(len=*),intent(in) :: str1,str2 character(len=LEN_TRIM(str1)+LEN_TRIM(str2)+1) :: ostr ! ********************************************************************* if (len_trim(str1) > 0) then ostr=TRIM(str1)//" "//TRIM(str2) else ostr=TRIM(str2) end if end function sjoin_2 !!*** !---------------------------------------------------------------------- !!****f* m_fstrings/sjoin_3 !! NAME !! sjoin_3 !! !! FUNCTION !! Joins three strings with a space separator. !! pure function sjoin_3(str1,str2,str3) result(ostr) !This section has been created automatically by the script Abilint (TD). !Do not modify the following lines by hand. #undef ABI_FUNC #define ABI_FUNC 'sjoin_3' !End of the abilint section character(len=*),intent(in) :: str1,str2,str3 character(len=LEN_TRIM(str1)+LEN_TRIM(str2)+LEN_TRIM(str3)+2) :: ostr ! ********************************************************************* ostr = sjoin_2(sjoin_2(str1, str2), str3) end function sjoin_3 !!*** !---------------------------------------------------------------------- !!****f* m_fstrings/sjoin_4 !! NAME !! sjoin_4 !! !! FUNCTION !! Joins three strings with a space separator. !! pure function sjoin_4(str1,str2,str3,str4) result(ostr) !This section has been created automatically by the script Abilint (TD). !Do not modify the following lines by hand. #undef ABI_FUNC #define ABI_FUNC 'sjoin_4' !End of the abilint section character(len=*),intent(in) :: str1,str2,str3,str4 character(len=LEN_TRIM(str1)+LEN_TRIM(str2)+LEN_TRIM(str3)+len_trim(str4)+3) :: ostr ! ********************************************************************* ostr = sjoin_2(str1, sjoin_3(str2, str3, str4)) end function sjoin_4 !!*** !---------------------------------------------------------------------- !!****f* m_fstrings/strcat_2 !! NAME !! strcat_2 !! !! FUNCTION !! Returns two concatenated strings. !! pure function strcat_2(str1,str2) result(ostr) !This section has been created automatically by the script Abilint (TD). !Do not modify the following lines by hand. #undef ABI_FUNC #define ABI_FUNC 'strcat_2' !End of the abilint section character(len=*),intent(in) :: str1,str2 character(len=LEN_TRIM(str1)+LEN_TRIM(str2)) :: ostr ! ********************************************************************* ostr=TRIM(str1)//TRIM(str2) end function strcat_2 !!*** !---------------------------------------------------------------------- !!****f* m_fstrings/strcat_3 !! NAME !! strcat_3 !! !! FUNCTION !! Concatenate 3 strings !! pure function strcat_3(str1, str2, str3) result(ostr) !This section has been created automatically by the script Abilint (TD). !Do not modify the following lines by hand. #undef ABI_FUNC #define ABI_FUNC 'strcat_3' !End of the abilint section character(len=*),intent(in) :: str1,str2,str3 character(len=LEN_TRIM(str1)+LEN_TRIM(str2)+LEN_TRIM(str3)) :: ostr ! ********************************************************************* ostr = TRIM(str1)//TRIM(str2)//TRIM(str3) end function strcat_3 !!*** !---------------------------------------------------------------------- !!****f* m_fstrings/strcat_4 !! NAME !! strcat_3 !! !! FUNCTION !! Concatenate 4 strings !! pure function strcat_4(str1, str2, str3, str4) result(ostr) !This section has been created automatically by the script Abilint (TD). !Do not modify the following lines by hand. #undef ABI_FUNC #define ABI_FUNC 'strcat_4' !End of the abilint section character(len=*),intent(in) :: str1,str2,str3,str4 character(len=LEN_TRIM(str1)+LEN_TRIM(str2)+LEN_TRIM(str3)+LEN_TRIM(str4)) :: ostr ! ********************************************************************* ostr = TRIM(str1)//TRIM(str2)//TRIM(str3)//TRIM(str4) end function strcat_4 !!*** !---------------------------------------------------------------------- !!****f* m_fstrings/yesno !! NAME !! yesno !! !! FUNCTION !! Convert boolean into "yes" or "no" !! character(len=3) pure function yesno(bool) !This section has been created automatically by the script Abilint (TD). !Do not modify the following lines by hand. #undef ABI_FUNC #define ABI_FUNC 'yesno' !End of the abilint section implicit none !This section has been created automatically by the script Abilint (TD). !Do not modify the following lines by hand. #undef ABI_FUNC #define ABI_FUNC 'atoi' !End of the abilint section !Arguments ------------------------------------ logical,intent(in) :: bool ! ********************************************************************* if (bool) then yesno = "yes" else yesno = "no" end if end function yesno !!*** !---------------------------------------------------------------------- !!****f* m_fstrings/atoi !! NAME !! atoi !! !! FUNCTION !! Convert a string into a integer !! function atoi(string) !Arguments ------------------------------------ !This section has been created automatically by the script Abilint (TD). !Do not modify the following lines by hand. #undef ABI_FUNC #define ABI_FUNC 'atoi' !End of the abilint section integer :: atoi character(len=*),intent(in) :: string ! ********************************************************************* read(string,*,err=10)atoi return 10 write(std_out,*)"Error while trying to convert string to integer. string: ",trim(string) end function atoi !!*** !---------------------------------------------------------------------- !!****f* m_fstrings/itoa !! NAME !! itoa !! !! FUNCTION !! Convert an integer into a string !! !! INPUTS !! value=The integer !! !! PARENTS !! !! CHILDREN !! pure function itoa(value) !This section has been created automatically by the script Abilint (TD). !Do not modify the following lines by hand. #undef ABI_FUNC #define ABI_FUNC 'itoa' !End of the abilint section integer,intent(in) :: value character(len=22) :: itoa ! ********************************************************************* ! len=22 is large enough to contain integer*8 write(itoa,"(i0)")value itoa = ADJUSTL(itoa) end function itoa !!*** !---------------------------------------------------------------------- !!****f* m_fstrings/ftoa !! NAME !! ftoa !! !! FUNCTION !! Convert an float into a string using format fmt (es16.6 if fmt is not given). !! !! PARENTS !! !! CHILDREN !! pure function ftoa(value,fmt) !This section has been created automatically by the script Abilint (TD). !Do not modify the following lines by hand. #undef ABI_FUNC #define ABI_FUNC 'ftoa' !End of the abilint section implicit none real(dp),intent(in) :: value character(len=*),optional,intent(in) :: fmt character(len=MAX_SLEN) :: ftoa ! ********************************************************************* if (present(fmt)) then write(ftoa,quote(fmt))value else write(ftoa,"(es16.6)")value end if ftoa = ADJUSTL(ftoa) end function ftoa !!*** !---------------------------------------------------------------------- !!****f* m_fstrings/ktoa !! NAME !! ktoa !! !! FUNCTION !! Convert an vector into a string using format fmt (es.16.6 if fmt is not given). !! !! PARENTS !! !! CHILDREN !! pure function ktoa(kpt,fmt) !This section has been created automatically by the script Abilint (TD). !Do not modify the following lines by hand. #undef ABI_FUNC #define ABI_FUNC 'ktoa' !End of the abilint section real(dp),intent(in) :: kpt(3) character(len=*),optional,intent(in) :: fmt character(len=MAX_SLEN) :: ktoa ! ********************************************************************* if (present(fmt)) then write(ktoa,quote(fmt))kpt else write(ktoa,"(a,3(es11.4,a))")"[",kpt(1),", ",kpt(2),", ",kpt(3),"]" end if ktoa = ADJUSTL(ktoa) end function ktoa !!*** !---------------------------------------------------------------------- !!****f* m_fstrings/ltoa_int !! NAME !! ltoa_int !! !! FUNCTION !! Convert a list of integers into a string. !! !! PARENTS !! !! CHILDREN pure function ltoa_int(list) result(str) !This section has been created automatically by the script Abilint (TD). !Do not modify the following lines by hand. #undef ABI_FUNC #define ABI_FUNC 'ltoa_int' !End of the abilint section implicit none integer,intent(in) :: list(:) character(len=MAX_SLEN) :: str !Local variables------------------------------- integer :: ii,base,sz character(len=MAX_SLEN) :: temp ! ********************************************************************* sz = size(list) if (any(sz == [0, 1])) then if (sz == 0) str = "[]" if (sz == 1) write(str, "(a,i0,a)")"[",list(1),"]" return end if str = ""; base = 1 do ii=1,sz ! Write to temp string and copy it to str if we have enough chars. ! Return if MAX_SLEN is too short. if (ii == 1) then write(temp, "(a,i0,a)")"[",list(1),"," else if (ii == sz) then write(temp, "(i0,a)")list(1),"]" else write(temp, "(i0,a)")list(ii),"," end if if (base + len_trim(temp) - 1 <= MAX_SLEN) then str(base:) = trim(temp) base = len_trim(str) + 1 else return end if end do end function ltoa_int !!*** !---------------------------------------------------------------------- !!****f* m_fstrings/ltoa_dp !! NAME !! ltoa_dp !! !! FUNCTION !! Convert a list of double precision numbers into a string. !! fmt specifies the format to be used ("es13.4" by default) !! !! PARENTS !! !! CHILDREN pure function ltoa_dp(list, fmt) result(str) !This section has been created automatically by the script Abilint (TD). !Do not modify the following lines by hand. #undef ABI_FUNC #define ABI_FUNC 'ltoa_dp' !End of the abilint section implicit none real(dp),intent(in) :: list(:) character(len=*),optional,intent(in) :: fmt character(len=MAX_SLEN) :: str !Local variables------------------------------- integer :: ii,base,sz character(len=MAX_SLEN) :: temp,myfmt,fa ! ********************************************************************* myfmt = "es13.4"; if (present(fmt)) myfmt = fmt sz = size(list) if (any(sz == [0, 1])) then if (sz == 0) str = "[]" if (sz == 1) write(str, sjoin("(a,",myfmt,",a)")) "[",list(1),"]" return end if str = ""; base = 1; fa = sjoin("(",myfmt,",a)") do ii=1,sz ! Write to temp string and copy it to str if we have enough chars. ! Return if MAX_SLEN is too short. if (ii == 1) then write(temp, sjoin("(a,",myfmt,",a)")) "[",list(1),"," else if (ii == sz) then write(temp, fa)list(1),"]" else write(temp, fa) list(ii),"," end if if (base + len_trim(temp) - 1 <= MAX_SLEN) then str(base:) = trim(temp) base = len_trim(str) + 1 else return end if end do end function ltoa_dp !!*** !---------------------------------------------------------------------- !!****f* m_fstring/basename !! NAME !! basename !! !! FUNCTION !! Returns the final component of a pathname. !! !! INPUTS !! string=The input string !! !! NOTES !! * If the input string in not a valid path to a file (i.e not in the form foo/name) !! a blank strink is returned !! * We do a backward search becase we want to optimize the algorithm for Fortran strings. !! !! SOURCE pure function basename(string) !This section has been created automatically by the script Abilint (TD). !Do not modify the following lines by hand. #undef ABI_FUNC #define ABI_FUNC 'basename' !End of the abilint section character(len=*),intent(in) :: string character(len=LEN_TRIM(string)) :: basename !Local variables------------------------------- integer :: ic,nch_trim,nch !************************************************************************ nch =LEN (string) nch_trim=LEN_TRIM(string) ic = INDEX (TRIM(string), DIR_SEPARATOR, back=.TRUE.) !write(*,*)'DEBUG ',TRIM(string),ic if (ic >= 1 .and. ic <= nch_trim-1) then ! there is stuff after the separator. basename = string(ic+1:nch_trim) return else if (ic==0 .or. ic == nch_trim+1) then ! no separator in string or zero length string, basename = TRIM(string) ! return trimmed string. return else ! (ic == nch_trim) separator is the last char. basename= BLANK ! This is not a valid path to a file, return blank. return end if end function basename !!*** !---------------------------------------------------------------------- !!****f* m_fstring/firstchar_0d !! NAME !! firstchar_0d !! !! FUNCTION !! Return True if string starts with the specified character !! !! INPUTS !! string=The string whose first character has to be cheched !! ch=Character !! [csens]=.TRUE. if comparison is done regardless of case. Defaults to .FALSE. !! !! PARENTS !! !! CHILDREN !! !! !! SOURCE pure function firstchar_0d(string,ch,csens) result(ans) !This section has been created automatically by the script Abilint (TD). !Do not modify the following lines by hand. #undef ABI_FUNC #define ABI_FUNC 'firstchar_0d' !End of the abilint section logical :: ans logical,optional,intent(in) :: csens character(len=*),intent(in) :: string character(len=1),intent(in) :: ch !Local variables------------------------------- logical :: my_csens !************************************************************************ my_csens=.FALSE.; if (PRESENT(csens)) my_csens = csens if (.not.my_csens) then ans = ( string(1:1) == ch) else ans = ( toupper(string(1:1)) == toupper(ch)) end if end function firstchar_0d !!*** !---------------------------------------------------------------------- !!****f* m_fstring/firstchar_1d !! NAME !! firstchar_1d !! !! FUNCTION !! Returns .TRUE. is the first character of the string belongs to a given list. !! !! INPUTS !! string=The string whose first character has to be cheched !! char_list=The list of characters. !! [csens]=.TRUE. if comparison is done regardless of case. Defaults to .FALSE. !! !! PARENTS !! !! CHILDREN !! !! !! SOURCE pure function firstchar_1d(string,char_list,csens) result(ans) !This section has been created automatically by the script Abilint (TD). !Do not modify the following lines by hand. #undef ABI_FUNC #define ABI_FUNC 'firstchar_1d' !End of the abilint section logical :: ans logical,optional,intent(in) :: csens character(len=*),intent(in) :: string character(len=1),intent(in) :: char_list(:) !Local variables------------------------------- integer :: ii logical :: my_csens character(len=1) :: first_ch !************************************************************************ my_csens=.FALSE.; if (PRESENT(csens)) my_csens = csens first_ch = string(1:1) ans=.FALSE. if (.not.my_csens) then do ii=1,SIZE(char_list) ans = ( first_ch == char_list(ii) ); if (ans) EXIT end do else do ii=1,SIZE(char_list) ans = ( toupper(first_ch) == toupper(char_list(ii)) ); if (ans) EXIT end do end if end function firstchar_1d !!*** !---------------------------------------------------------------------- !!****f* m_fstring/startswith !! NAME !! startswith !! !! FUNCTION !! Returns .TRUE. is the string starts with the specified prefix. !! !! SOURCE pure function startswith(string, prefix) result(ans) !This section has been created automatically by the script Abilint (TD). !Do not modify the following lines by hand. #undef ABI_FUNC #define ABI_FUNC 'startswith' !End of the abilint section logical :: ans character(len=*),intent(in) :: string character(len=*),intent(in) :: prefix !Local variables------------------------------- integer :: ii,lenstr,lenpre !************************************************************************ ans = .False. lenstr = len_trim(string); lenpre = len_trim(prefix) if (lenpre > lenstr) return do ii=1,lenpre if (prefix(ii:ii) /= string(ii:ii)) return end do ans = .True. end function startswith !!*** !---------------------------------------------------------------------- !!****f* m_fstring/endswith !! NAME !! endswith !! !! FUNCTION !! Returns .TRUE. is the string ends with the specified suffix !! !! SOURCE pure function endswith(string, suffix) result(ans) !This section has been created automatically by the script Abilint (TD). !Do not modify the following lines by hand. #undef ABI_FUNC #define ABI_FUNC 'endswith' !End of the abilint section logical :: ans character(len=*),intent(in) :: string character(len=*),intent(in) :: suffix !Local variables------------------------------- integer :: ii,p,lenstr,lensuf !************************************************************************ ans = .False. lenstr = len_trim(string); lensuf = len_trim(suffix) if (lensuf > lenstr) return do ii=1,lensuf p = lenstr - lensuf + ii if (suffix(ii:ii) /= string(p:p)) return end do ans = .True. end function endswith !!*** !---------------------------------------------------------------------- !!****f* m_fstrings/indent !! NAME !! indent !! !! FUNCTION !! Indent text !! !! INPUTS !! istr=Input string !! !! PARENTS !! !! CHILDREN !! !! SOURCE pure function indent(istr) result(ostr) !This section has been created automatically by the script Abilint (TD). !Do not modify the following lines by hand. #undef ABI_FUNC #define ABI_FUNC 'indent' !End of the abilint section character(len=*),intent(in) :: istr character(len=len(istr)*4+4) :: ostr !Local variables------------------------------- integer,parameter :: n=4 ! ostr is large enough to allocate all the possible indentations. integer :: ii,jj,kk character(len=1) :: ch ! ********************************************************************* ostr = " " jj = n do ii=1,LEN_TRIM(istr) ch = istr(ii:ii) jj = jj + 1 if (ch == NCHAR) then ostr(jj:jj) = NCHAR do kk=jj+1,jj+n ostr(kk:kk) = " " end do jj = jj+n else ostr(jj:jj) = ch end if end do !ostr(jj+1:) = "H" end function indent !!*** !---------------------------------------------------------------------- !!****f* m_fstrings/prep_dash !! NAME !! prep_dash !! !! FUNCTION !! Prepend `-` to each line in a string. !! !! INPUTS !! istr=Input string !! !! PARENTS !! !! CHILDREN !! !! SOURCE pure function prep_dash(istr) result(ostr) !This section has been created automatically by the script Abilint (TD). !Do not modify the following lines by hand. #undef ABI_FUNC #define ABI_FUNC 'prep_dash' !End of the abilint section character(len=*),intent(in) :: istr character(len=2*len(istr)) :: ostr !Local variables------------------------------- integer :: ii,jj character(len=1) :: ch ! ********************************************************************* ostr = "" jj = 1; ostr(jj:jj) = "-" !jj = 0 do ii=1,LEN_TRIM(istr) ch = istr(ii:ii) jj = jj + 1 if (ch == ch10) then ostr(jj:jj) = ch10 ostr(jj+1:jj+1) = "-" jj = jj+1 else ostr(jj:jj) = ch end if end do !ostr(jj+1:) = "H" end function prep_dash !!*** !---------------------------------------------------------------------- !!****f* m_fstrings/int2char4 !! NAME !! int2char4 !! !! FUNCTION !! Convert an integer number to ("2") a character(len=*) !! with trailing zeros if the number is <=9999. !! Exemple : 123 will be mapped to "0123" ; 12345 will be mapped to "12345" !! Makes sure that the integer fits the string length !! (ex.: between 0 and 99999 if the string is a character(len=5)). !! !! INPUTS !! iint=integer to be converted !! !! OUTPUT !! string=character string ('####...' if error) !! !! PARENTS !! aim,anaddb,dtfil_init1,gaus_dos,get_all_gkq,iofn1,m_atprj,m_green !! m_io_redirect,m_phonon_supercell,m_self,mrgscr,optic,pawmkaewf !! prtfatbands,read_wfrspa,scfcv,tetrahedron !! !! CHILDREN !! !! SOURCE pure subroutine int2char4(iint,string) !This section has been created automatically by the script Abilint (TD). !Do not modify the following lines by hand. #undef ABI_FUNC #define ABI_FUNC 'int2char4' !End of the abilint section implicit none !Arguments ------------------------------------ !scalars integer,intent(in) :: iint character(len=*),intent(out) :: string !Local variables------------------------------- integer :: lenstr ! ************************************************************************* lenstr=min(len(string),25) if(iint<0 .or. iint>10._dp**(lenstr-1))then string=repeat('#',lenstr) return end if if(iint<10)then write(string,'("000",i1)')iint else if(iint<100)then write(string,'("00",i2)')iint else if(iint<1000)then write(string,'("0",i3)')iint else if(iint<10000)then write(string,'(i4)')iint else if(iint<1.0d5)then write(string,'(i5)')iint else if(iint<1.0d6)then write(string,'(i6)')iint else if(iint<1.0d7)then write(string,'(i7)')iint else if(iint<1.0d8)then write(string,'(i8)')iint else if(iint<1.0d9)then write(string,'(i9)')iint else if(iint<1.0d9)then write(string,'(i10)')iint else string=repeat('#',lenstr) end if end subroutine int2char4 !!*** !---------------------------------------------------------------------- !!****f* m_fstrings/int2char10 !! NAME !! int2char10 !! !! FUNCTION !! Convert a positive integer number (zero included) to a character(len=10), !! with blanks to COMPLETE the string. !! Exemple : 1234 will be mapped to "1234 " !! Makes sure that the integer is between 0 and 9 999 999 999 !! Should be enough for integer*4 !! !! INPUTS !! iint=integer to be converted !! !! OUTPUT !! string=character string ('##########' if error) !! !! PARENTS !! handle_ncerr,m_esymm,m_dfti,m_dyson_solver,m_qparticles,m_wfd !! prt_cif,wffile !! !! CHILDREN !! !! SOURCE pure subroutine int2char10(iint,string) !This section has been created automatically by the script Abilint (TD). !Do not modify the following lines by hand. #undef ABI_FUNC #define ABI_FUNC 'int2char10' !End of the abilint section implicit none !Arguments ------------------------------------ !scalars integer,intent(in) :: iint character(len=10),intent(out) :: string ! ************************************************************************* !Note the use of floating numbers instead of large integers, for portability if(iint<0 .or. iint>=1.d10)then string='####' return end if if(iint<10)then write(string,'(i1,9x)')iint else if(iint<100)then write(string,'(i2,8x)')iint else if(iint<1.0d3)then write(string,'(i3,7x)')iint else if(iint<1.0d4)then write(string,'(i4,6x)')iint else if(iint<1.0d5)then write(string,'(i5,5x)')iint else if(iint<1.0d6)then write(string,'(i6,4x)')iint else if(iint<1.0d7)then write(string,'(i7,3x)')iint else if(iint<1.0d8)then write(string,'(i8,2x)')iint else if(iint<1.0d9)then write(string,'(i9,1x)')iint else write(string,'(i10)')iint end if end subroutine int2char10 !!*** !---------------------------------------------------------------------- !!****f* m_fstrings/char_count !! NAME !! chcount !! !! FUNCTION !! Count the occurrences of a character in a string. !! !! PARENTS !! !! SOURCE integer pure function char_count(string, char) !This section has been created automatically by the script Abilint (TD). !Do not modify the following lines by hand. #undef ABI_FUNC #define ABI_FUNC 'char_count' !End of the abilint section implicit none !Arguments ------------------------------------ !scalars character(len=*),intent(in) :: string character(len=1),intent(in) :: char integer :: i ! ************************************************************************* char_count = 0 do i=1,len(string) if (string(i:i) == char) char_count = char_count + 1 end do end function char_count !---------------------------------------------------------------------- END MODULE m_fstrings !!*** v_sim-3.8.0/lib/plug-ins/abinit/m_io_tools.F90000066400000000000000000001136731370110300500210350ustar00rootroot00000000000000!{\src2tex{textfont=tt}} !!****m* ABINIT/m_io_tools !! NAME !! m_io_tools !! !! FUNCTION !! This module contains basic tools to deal with Fortran IO !! !! COPYRIGHT !! Copyright (C) 2008-2016 ABINIT group (MG) !! This file is distributed under the terms of the !! GNU General Public License, see ~abinit/COPYING !! or http://www.gnu.org/copyleft/gpl.txt . !! !! PARENTS !! !! CHILDREN !! !! SOURCE #if defined HAVE_CONFIG_H #include "config.h" #endif #include "abi_common.h" MODULE m_io_tools use defs_basis implicit none private public :: get_unit ! Get a free unit if no argument is specified or report the unit associated to a file name public :: file_exists ! Return .TRUE. if file exists. public :: delete_file ! Delete a file if present. public :: is_open ! .TRUE. if file is open public :: is_connected ! .TRUE. if file is connected to a logical unit number public :: prompt ! Simple prompt public :: read_line ! Read line from unit ignoring blank lines and deleting comments beginning with ! public :: flush_unit ! Wrapper to the intrinsic flush routine, not implemented by every compiler public :: pick_aname ! Returns the name of a non-existent file to be used for temporary storage. public :: isncfile ! .TRUE. if we have a NETCDF file. public :: iomode_from_fname ! Automatic selection of the IO mode based on the file extension. public :: iomode2str ! Convert iomode to string public :: mvrecord ! Moves forward or backward in a Fortran binary file by nn records. public :: open_file ! Helper function to open a file in sequential mode with improved error handling. public :: close_unit ! Helper function to close a Fortran unit with improved error handling. public :: write_lines ! split a string in lines and output the text to the specified unit public :: lock_and_write ! Write a string to a file with locking mechanism. public :: num_opened_units ! Return the number of opened units. public :: show_units ! Print info on the logical units. interface get_unit module procedure get_free_unit module procedure get_unit_from_fname end interface interface is_open module procedure is_open_unit module procedure is_open_fname end interface interface prompt module procedure prompt_int0D module procedure prompt_rdp0D module procedure prompt_string module procedure prompt_int1D module procedure prompt_int2D module procedure prompt_rdp1D module procedure prompt_rdp2D end interface integer,parameter :: STDIN=std_in integer,parameter :: STDOUT=std_out_default integer,parameter :: MIN_UNIT_NUMBER=10 ! Fortran does not define the range for logical unit numbers (they not be negative) #ifdef FC_NAG integer,parameter :: MAX_UNIT_NUMBER=64 ! There's a serious problem in Nag6.0. In principle ! Maximum unit number: 2147483647 #else integer,parameter :: MAX_UNIT_NUMBER=1024 ! The following values should be safe #endif integer,parameter :: IO_MAX_LEN=500 character(len=1),parameter :: BLANK=' ' ! === For Interactive sessions === integer,parameter :: IO_EOT=-1 ! End of transmission i.e CTRL+D character(len=4),parameter :: PS1='>>> ' character(len=4),parameter :: PS2='??? ' integer,parameter :: IO_NO_AVAILABLE_UNIT =-1 ! No units are available for Fortran I/O integer,parameter :: IO_FILE_NOT_ASSOCIATED=-2 ! File is not associated with any unit !integer,save,public ABI_PROTECTED :: IO_MODE_DEFAULT=-1 CONTAINS !=========================================================== !!*** !!****f* m_io_tools/get_unit !! NAME !! get_unit !! !! FUNCTION !! Obtain a logical Fortran unit. !! A free unit is reported if no argument is specified. !! If the file name is supplied, the function reports the unit number !! associated to the file !! Note that GET_UNIT assumes that units 0, 5, 6 (stderr, stdin, std_out) !! are special, and will never return those values. !! !! TODO !! One should define an abinit-specific function with a list of reserved units! !! !! OUTPUT !! The unit number (free unit or unit associated to the file) !! Raises: !! IO_NO_AVAILABLE_UNIT if no logical unit is free (!) !! IO_FILE_NOT_ASSOCIATED if the file is not linked to a logical unit !! !! PARENTS !! !! SOURCE integer function get_free_unit() !This section has been created automatically by the script Abilint (TD). !Do not modify the following lines by hand. #undef ABI_FUNC #define ABI_FUNC 'get_free_unit' !End of the abilint section implicit none !This section has been created automatically by the script Abilint (TD). !Do not modify the following lines by hand. #undef ABI_FUNC #define ABI_FUNC 'get_free_unit' !End of the abilint section !Local variables------------------------------- integer :: iunt logical :: isopen ! ********************************************************************* do iunt=MAX_UNIT_NUMBER,MIN_UNIT_NUMBER,-1 if (any(iunt == [std_err, std_in, std_out])) cycle inquire(unit=iunt, opened=isopen) if (.not.isopen) then get_free_unit = iunt; return end if end do get_free_unit = IO_NO_AVAILABLE_UNIT end function get_free_unit !!*** !---------------------------------------------------------------------- !!****f* m_io_tools/get_unit_from_fname !! NAME !! get_unit_from_fname !! !! FUNCTION !! Returns the unit number associated to an open file whose name is fname. !! If the file is not connected to an unit number, returns IO_FILE_NOT_ASSOCIATED !! !! INPUTS !! !! OUTPUT !! !! PARENTS !! !! SOURCE integer function get_unit_from_fname(fname) !This section has been created automatically by the script Abilint (TD). !Do not modify the following lines by hand. #undef ABI_FUNC #define ABI_FUNC 'get_unit_from_fname' !End of the abilint section implicit none !This section has been created automatically by the script Abilint (TD). !Do not modify the following lines by hand. #undef ABI_FUNC #define ABI_FUNC 'get_unit_from_fname' !End of the abilint section !Arguments ------------------------------------ character(len=*),intent(in) :: fname !Local variables------------------------------- integer :: unit ! ********************************************************************* inquire(file=fname,number=unit) get_unit_from_fname=unit if (unit==-1) get_unit_from_fname=IO_FILE_NOT_ASSOCIATED end function get_unit_from_fname !!*** !---------------------------------------------------------------------- !!****f* m_io_tools/file_exists !! NAME !! file_exists !! !! FUNCTION !! Return .TRUE. if file existent (function version of inquire). !! !! INPUTS !! fname=The name of the file. !! !! PARENTS !! !! SOURCE logical function file_exists(fname) !This section has been created automatically by the script Abilint (TD). !Do not modify the following lines by hand. #undef ABI_FUNC #define ABI_FUNC 'file_exists' !End of the abilint section character(len=*),intent(in) :: fname ! ********************************************************************* inquire(file=fname,exist=file_exists) end function file_exists !!*** !---------------------------------------------------------------------- !!****f* m_io_tools/delete_file !! NAME !! delete_file !! !! FUNCTION !! Delete a file if present. !! !! INPUTS !! fname=The name of the file. !! !! OUTPUT !! ierr=Non-zero value indicates that a problem occured. !! 111 = To signal that the file does not exist. !! 112 = File exist, is open but no associated unit is found! !! Other values are system-dependent as the value is returned by a open or close !! instruction. !! !! SIDE EFFECTS !! The specified file is deleted. !! !! PARENTS !! abinit,ioprof,m_io_redirect,m_nctk,m_wfk,mlwfovlp !! !! CHILDREN !! !! SOURCE subroutine delete_file(fname,ierr) !This section has been created automatically by the script Abilint (TD). !Do not modify the following lines by hand. #undef ABI_FUNC #define ABI_FUNC 'delete_file' !End of the abilint section integer,intent(out) :: ierr character(len=*),intent(in) :: fname !Local variables------------------------------- integer :: tmp_unt logical :: exists ! ********************************************************************* ierr=0 inquire(file=fname,exist=exists) if (.not.exists) then ierr=111 write(std_out,*)" Asked to delete not existent file: ",TRIM(fname) RETURN end if if (is_open_fname(fname)) then tmp_unt = get_unit_from_fname(fname) if ( tmp_unt == IO_FILE_NOT_ASSOCIATED ) then write(std_out,*) "File is opened but no associated unit found!" ierr=112 RETURN end if close(tmp_unt) else tmp_unt = get_unit() end if ! Now close the file. open(unit=tmp_unt,file=trim(fname),status="OLD",iostat=ierr) if (ierr==0) close(unit=tmp_unt,status="DELETE",iostat=ierr) end subroutine delete_file !!*** !---------------------------------------------------------------------- !!****f* m_io_tools/is_connected !! NAME !! is_connected !! !! FUNCTION !! Returns .TRUE. if unit is connected to fname. !! !! INPUTS !! !! OUTPUT !! !! PARENTS !! !! SOURCE logical function is_connected(unit,fname) !This section has been created automatically by the script Abilint (TD). !Do not modify the following lines by hand. #undef ABI_FUNC #define ABI_FUNC 'is_connected' !End of the abilint section integer,intent(in) :: unit character(len=*),intent(in) :: fname !Local variables------------------------------- integer :: unt_found logical :: isopen ! ********************************************************************* inquire(file=fname,number=unt_found,opened=isopen) is_connected=(isopen.and.(unt_found==unit)) end function is_connected !!*** !---------------------------------------------------------------------- !!****f* m_io_tools/is_open !! NAME !! is_open !! !! FUNCTION !! Returns .TRUE. if unit is associated to an open file. !! !! INPUTS !! !! OUTPUT !! !! PARENTS !! !! SOURCE logical function is_open_unit(unit) !This section has been created automatically by the script Abilint (TD). !Do not modify the following lines by hand. #undef ABI_FUNC #define ABI_FUNC 'is_open_unit' !End of the abilint section integer,intent(in) :: unit ! ********************************************************************* inquire(unit=unit,opened=is_open_unit) end function is_open_unit !!*** !---------------------------------------------------------------------- !!****f* m_io_tools/is_open_fname !! NAME !! is_open_fname !! !! FUNCTION !! Returns .TRUE. if the file name fname is open. !! !! INPUTS !! !! OUTPUT !! !! PARENTS !! !! SOURCE logical function is_open_fname(fname) !This section has been created automatically by the script Abilint (TD). !Do not modify the following lines by hand. #undef ABI_FUNC #define ABI_FUNC 'is_open_fname' !End of the abilint section character(len=*),intent(in) :: fname ! ********************************************************************* inquire(file=fname,opened=is_open_fname) end function is_open_fname !!*** !---------------------------------------------------------------------- !!****f* m_io_tools/prompt_int0D !! NAME !! prompt_int0D !! !! FUNCTION !! A primitive prompt. Writes msg on STDOUT and reads the value entered by the user. !! !! INPUTS !! !! OUTPUT !! !! PARENTS !! !! CHILDREN !! !! SOURCE subroutine prompt_int0D(msg,ivalue) !This section has been created automatically by the script Abilint (TD). !Do not modify the following lines by hand. #undef ABI_FUNC #define ABI_FUNC 'prompt_int0D' !End of the abilint section character(len=*),intent(in) :: msg integer,intent(out) :: ivalue !Local variables------------------------------- integer :: ios character(len=4) :: PS ! ********************************************************************* ios=-1 ; PS=PS1 do while (ios/=0) write(STDOUT,'(a)',ADVANCE='NO')PS//TRIM(msg)//BLANK call flush_unit(STDOUT) read(STDIN,*,IOSTAT=ios)ivalue if (ios==IO_EOT) then call prompt_exit() endif PS=PS2 end do write(STDOUT,*) end subroutine prompt_int0D !!*** !---------------------------------------------------------------------- !!****f* m_io_tools/prompt_rdp0d !! NAME !! prompt_rdp0d !! !! FUNCTION !! A primitive prompt. Writes msg on STDOUT and reads the value entered by the user. !! !! INPUTS !! !! OUTPUT !! !! PARENTS !! !! CHILDREN !! !! SOURCE subroutine prompt_rdp0D(msg,rvalue) !This section has been created automatically by the script Abilint (TD). !Do not modify the following lines by hand. #undef ABI_FUNC #define ABI_FUNC 'prompt_rdp0D' !End of the abilint section character(len=*),intent(in) :: msg real(dp),intent(out) :: rvalue !Local variables------------------------------- integer :: ios character(len=4) :: PS ! ********************************************************************* ios=-1 ; PS=PS1 do while (ios/=0) write(STDOUT,'(a)',ADVANCE='NO')PS//TRIM(msg)//BLANK call flush_unit(STDOUT) read(STDIN,*,IOSTAT=ios)rvalue if (ios==IO_EOT) then call prompt_exit() endif PS=PS2 end do write(STDOUT,*) end subroutine prompt_rdp0D !!*** !---------------------------------------------------------------------- !!****f* m_io_tools/prompt_string !! NAME !! prompt_string !! !! FUNCTION !! A primitive prompt. Writes msg on STDOUT and reads the value entered by the user. !! If strip_comment is True (default), all the characters after "#" or "!" are ignored. !! !! INPUTS !! !! OUTPUT !! !! PARENTS !! !! CHILDREN !! !! SOURCE subroutine prompt_string(msg,string,strip_comment) !This section has been created automatically by the script Abilint (TD). !Do not modify the following lines by hand. #undef ABI_FUNC #define ABI_FUNC 'prompt_string' !End of the abilint section character(len=*),intent(in) :: msg logical,optional,intent(in) :: strip_comment character(len=*),intent(out) :: string !Local variables------------------------------- integer :: ios,ic logical :: do_strip character(len=4) :: PS !character(len=len(string)) :: tmps ! ********************************************************************* do_strip = .True.; if (present(strip_comment)) do_strip = strip_comment ios=-1 ; PS=PS1 do while (ios/=0) write(STDOUT,'(a)',ADVANCE='NO')PS//TRIM(msg)//BLANK call flush_unit(STDOUT) read(STDIN,'(a)',IOSTAT=ios)string if (ios==IO_EOT) call prompt_exit() PS=PS2 end do write(STDOUT,*) if (do_strip) then ic = INDEX(string, "#"); if (ic /= 0) string(:) = string(:ic-1) ic = INDEX(string, "!"); if (ic /= 0) string(:) = string(:ic-1) end if end subroutine prompt_string !!*** !---------------------------------------------------------------------- !!****f* m_io_tools/prompt_int1D !! NAME !! prompt_int1D !! !! FUNCTION !! A primitive prompt. Writes msg on STDOUT and reads the value entered by the user. !! !! INPUTS !! !! OUTPUT !! !! PARENTS !! !! CHILDREN !! !! SOURCE subroutine prompt_int1D(msg,ivect) !Arguments ------------------------------------ !This section has been created automatically by the script Abilint (TD). !Do not modify the following lines by hand. #undef ABI_FUNC #define ABI_FUNC 'prompt_int1D' !End of the abilint section character(len=*),intent(in) :: msg integer,intent(out) :: ivect(:) !Local variables------------------------------- integer :: ios character(len=4) :: PS ! ********************************************************************* ios=-1 ; PS=PS1 do while (ios/=0) write(STDOUT,'(a)',ADVANCE='NO')PS//TRIM(msg)//BLANK call flush_unit(STDOUT) read(STDIN,*,IOSTAT=ios)ivect(:) if (ios==IO_EOT) then call prompt_exit() endif PS=PS2 end do write(STDOUT,*) end subroutine prompt_int1D !!*** !---------------------------------------------------------------------- !!****f* m_io_tools/prompt_int2D !! NAME !! prompt_int2d !! !! FUNCTION !! A primitive prompt. Writes msg on STDOUT and reads the value entered by the user. !! !! INPUTS !! !! OUTPUT !! !! PARENTS !! !! CHILDREN !! !! SOURCE subroutine prompt_int2D(msg,iarr) !This section has been created automatically by the script Abilint (TD). !Do not modify the following lines by hand. #undef ABI_FUNC #define ABI_FUNC 'prompt_int2D' !End of the abilint section character(len=*),intent(in) :: msg integer,intent(out) :: iarr(:,:) !Local variables------------------------------- integer :: ios character(len=4) :: PS ! ********************************************************************* ios=-1 ; PS=PS1 do while (ios/=0) write(STDOUT,'(a)',ADVANCE='NO')PS//TRIM(msg)//BLANK call flush_unit(STDOUT) read(STDIN,*,IOSTAT=ios)iarr(:,:) if (ios==IO_EOT) then call prompt_exit() endif PS=PS2 end do write(STDOUT,*) end subroutine prompt_int2D !!*** !---------------------------------------------------------------------- !!****f* m_io_tools/prompt_rdp1D !! NAME !! prompt_rdp1D !! !! FUNCTION !! A primitive prompt. Writes msg on STDOUT and reads the value entered by the user. !! !! INPUTS !! !! OUTPUT !! !! PARENTS !! !! CHILDREN !! !! SOURCE subroutine prompt_rdp1D(msg,rvect) !Arguments ------------------------------------ !This section has been created automatically by the script Abilint (TD). !Do not modify the following lines by hand. #undef ABI_FUNC #define ABI_FUNC 'prompt_rdp1D' !End of the abilint section character(len=*),intent(in) :: msg real(dp),intent(out) :: rvect(:) character(len=4) :: PS !Local variables------------------------------- integer :: ios ! ********************************************************************* ios=-1 ; PS=PS1 do while (ios/=0) write(STDOUT,'(a)',ADVANCE='NO')PS//TRIM(msg)//BLANK call flush_unit(STDOUT) read(STDIN,*,IOSTAT=ios)rvect(:) if (ios==IO_EOT) then call prompt_exit() endif PS=PS2 end do write(STDOUT,*) end subroutine prompt_rdp1D !!*** !---------------------------------------------------------------------- !!****f* m_io_tools/prompt_rdp2D !! NAME !! prompt_rdp2D !! !! FUNCTION !! A primitive prompt. Writes msg on STDOUT and reads the value entered by the user. !! !! INPUTS !! !! OUTPUT !! !! PARENTS !! !! CHILDREN !! !! SOURCE subroutine prompt_rdp2D(msg,rarr) !This section has been created automatically by the script Abilint (TD). !Do not modify the following lines by hand. #undef ABI_FUNC #define ABI_FUNC 'prompt_rdp2D' !End of the abilint section character(len=*),intent(in) :: msg real(dp),intent(out) :: rarr(:,:) !Local variables------------------------------- integer :: ios character(len=4) :: PS ! ********************************************************************* ios=-1 ; PS=PS1 do while (ios/=0) write(STDOUT,'(a)',ADVANCE='NO')PS//TRIM(msg)//BLANK call flush_unit(STDOUT) read(STDIN,*,IOSTAT=ios)rarr(:,:) if (ios==IO_EOT) then call prompt_exit() endif PS=PS2 end do write(STDOUT,*) end subroutine prompt_rdp2D !!*** !---------------------------------------------------------------------- !!****f* m_io_tools/prompt_exit !! NAME !! prompt_exit !! !! FUNCTION !! A primitive prompt. Writes msg on STDOUT and reads the value entered by the user. !! !! INPUTS !! !! OUTPUT !! !! PARENTS !! m_io_tools !! !! CHILDREN !! !! SOURCE subroutine prompt_exit() !This section has been created automatically by the script Abilint (TD). !Do not modify the following lines by hand. #undef ABI_FUNC #define ABI_FUNC 'prompt_exit' !End of the abilint section integer,parameter :: NASK=5 integer :: ios,iask character(len=IO_MAX_LEN) :: ans ! ********************************************************************* write(STDOUT,*) ios=-1 ; iask=0 do while (ios/=0.or.(ans/='y'.or.ans/='n')) iask=iask+1 write(STDOUT,'(a)')' Do you really want to exit (y/n)? ' call flush_unit(STDOUT) read(STDIN,*,IOSTAT=ios)ans if (ans=='y'.or.iask>NASK) STOP if (ans=='n') RETURN end do end subroutine prompt_exit !!*** !---------------------------------------------------------------------- !!****f* m_io_tools/read_line !! NAME !! read_line !! !! FUNCTION !! Reads line from unit=std_in_ or unit if specified, ignoring blank lines !! and deleting comments beginning with ! !! !! INPUTS !! !! OUTPUT !! !! PARENTS !! !! CHILDREN !! !! SOURCE subroutine read_line(line,ios,unit,comment) !This section has been created automatically by the script Abilint (TD). !Do not modify the following lines by hand. #undef ABI_FUNC #define ABI_FUNC 'read_line' !End of the abilint section character(len=*),intent(out):: line character(len=1),optional,intent(in) :: comment integer,optional,intent(in) :: unit integer,intent(out) :: ios !Local variables------------------------------- integer :: ipos,unt ! ********************************************************************* unt=STDIN ; if (PRESENT(unit)) unt=unit do read(unt,'(a)',iostat=ios) line ! read input line if (ios/=0) RETURN line=ADJUSTL(line) if (PRESENT(comment)) then ipos=INDEX(line,comment) if (ipos==1) CYCLE if (ipos/=0) line=line(:ipos-1) end if if (LEN_TRIM(line)/=0) EXIT end do end subroutine read_line !!*** !---------------------------------------------------------------------- !!****f* m_io_tools/flush_unit !! NAME !! flush_unit !! !! FUNCTION !! Wrapper for the standard flush_unit routine !! !! INPUTS !! unit=Fortran logical Unit number !! !! OUTPUT !! !! NOTES !! Available only if the compiler implements this intrinsic procedure. !! !! PARENTS !! abinit,anaddb,bsepostproc,cchi0,cchi0q0,cut3d,fftprof,impurity_solve !! m_errors,m_hdr,m_io_redirect,m_io_tools,m_matlu,m_shirley,m_xc_vdw !! mrgddb,mrggkk,mrgscr,optic,pawmkaewf,prep_calc_ucrpa,qmc_prep_ctqmc !! scprqt,vdw_kernelgen,vtorho,wrtout !! !! CHILDREN !! !! SOURCE subroutine flush_unit(unit) !This section has been created automatically by the script Abilint (TD). !Do not modify the following lines by hand. #undef ABI_FUNC #define ABI_FUNC 'flush_unit' !End of the abilint section integer,intent(in) :: unit !Local variables------------------------------- logical :: isopen !************************************************************************ if (unit == dev_null) return inquire(unit=unit,opened=isopen) !FLUSH on unconnected unit is illegal: F95 std., 9.3.5. #if defined HAVE_FC_FLUSH if (isopen) then call flush(unit) endif #elif defined HAVE_FC_FLUSH_ if (isopen) then call flush_(unit) end if #endif end subroutine flush_unit !!*** !---------------------------------------------------------------------- !!****f* m_io_tools/pick_aname !! NAME !! pick_aname !! !! FUNCTION !! Returns the name of a non-existent file to be used for temporary storage. !! !! PARENTS !! !! SOURCE function pick_aname() result(aname) !This section has been created automatically by the script Abilint (TD). !Do not modify the following lines by hand. #undef ABI_FUNC #define ABI_FUNC 'pick_aname' !End of the abilint section character(len=fnlen) :: aname !Local variables------------------------------- integer :: ii,spt,ept real(dp) :: xrand(fnlen) !************************************************************************ aname="__TMP_FILE__" spt=LEN(aname); ept=spt do while (file_exists(aname)) call RANDOM_NUMBER(xrand(spt:ept)) xrand(spt:ept) = 64+xrand(spt:ept)*26 do ii=spt,ept aname(ii:ii) = ACHAR(NINT(xrand(ii))) end do ept = MIN(ept+1,fnlen) end do end function pick_aname !!*** !---------------------------------------------------------------------- !!****f* m_io_tools/isncfile !! NAME !! isncfile !! !! FUNCTION !! Return .TRUE. if fname is a NETCDF file. !! !! INPUTS !! fname(len=*)=The name of the file to be tested. !! !! NOTES !! The idea is extremely simple: a NETCDF file terminates with ".nc". !! Obviously this approach is not bulletproof but it will work !! provided that we continue to append the ".nc" string to any NETCDF !! file produced by abinit. !! !! PARENTS !! !! SOURCE pure logical function isncfile(fname) !This section has been created automatically by the script Abilint (TD). !Do not modify the following lines by hand. #undef ABI_FUNC #define ABI_FUNC 'isncfile' !End of the abilint section implicit none !Arguments ------------------------------------ !scalars character(len=*),intent(in) :: fname !Local variables------------------------------- !scalars integer :: ic,nch_trim ! ************************************************************************* nch_trim=LEN_TRIM(fname) ic = INDEX (TRIM(fname), ".", back=.TRUE.) isncfile=.FALSE. if (ic >= 1 .and. ic <= nch_trim-1) then ! there is stuff after the . isncfile = (fname(ic+1:nch_trim)=="nc") end if end function isncfile !!*** !---------------------------------------------------------------------- !!****f* m_io_tools/iomode_from_fname !! NAME !! iomode_from_fname !! !! FUNCTION !! Automatic selection of the IO mode based on the file extension. !! !! INPUTS !! fname = Name of the file. !! !! NOTES !! if fname has extension '.nc', IO_MODE_ETSF is used !! else: !! IO_MODE_MPI if available !! IO_MODE_FORTRAN if HAVE_MPI_IO is not defined. !! !! PARENTS !! !! SOURCE pure function iomode_from_fname(fname) result(iomode) !This section has been created automatically by the script Abilint (TD). !Do not modify the following lines by hand. #undef ABI_FUNC #define ABI_FUNC 'iomode_from_fname' !End of the abilint section implicit none !Arguments ------------------------------------ !scalars character(len=*),intent(in) :: fname integer :: iomode ! ************************************************************************* if (isncfile(fname)) then iomode = IO_MODE_ETSF else #ifdef HAVE_MPI_IO iomode = IO_MODE_MPI #else iomode = IO_MODE_FORTRAN #endif !if (IO_MODE_DEFAULT /= -1) iomode = IO_MODE_DEFAULT end if end function iomode_from_fname !!*** !---------------------------------------------------------------------- !!****f* m_io_tools/iomode2str !! NAME !! iomode2str !! !! FUNCTION !! Convert iomode to string !! !! PARENTS !! !! SOURCE pure function iomode2str(iomode) !This section has been created automatically by the script Abilint (TD). !Do not modify the following lines by hand. #undef ABI_FUNC #define ABI_FUNC 'iomode2str' !End of the abilint section implicit none !Arguments ------------------------------------ !scalars character(len=48) :: iomode2str integer,intent(in) :: iomode ! ************************************************************************* select case (iomode) case (IO_MODE_FORTRAN_MASTER) iomode2str = "IO_MODE_FORTRAN_MASTER" case (IO_MODE_FORTRAN) iomode2str = "IO_MODE_FORTRAN" case (IO_MODE_MPI) iomode2str = "IO_MODE_MPI" case (IO_MODE_NETCDF) iomode2str = "IO_MODE_NETCDF" case (IO_MODE_ETSF) iomode2str = "IO_MODE_ETSF" case default iomode2str = "Unknown!" end select end function iomode2str !!*** !---------------------------------------------------------------------- !!****f* m_io_tools/mvrecord !! NAME !! mvrecord !! !! FUNCTION !! This subroutine moves forward or backward in a Fortran binary file by nn records. !! !! INPUTS !! funt= Fortran file unit number !! nrec=number of records !! !! OUTPUT !! ierr=error code !! !! TODO !! One should treat the possible errors of backspace !! !! PARENTS !! m_wffile,m_wfk !! !! CHILDREN !! !! SOURCE subroutine mvrecord(funt,nrec,ierr) !This section has been created automatically by the script Abilint (TD). !Do not modify the following lines by hand. #undef ABI_FUNC #define ABI_FUNC 'mvrecord' !End of the abilint section implicit none !Arguments ------------------------------------ !scalars integer,intent(in) :: funt,nrec integer,intent(out) :: ierr !Local variables------------------------------- !scalars integer :: irec ! ************************************************************************* ierr = 0 if (nrec > 0) then ! Move forward nrec records do irec=1,nrec read(funt,iostat=ierr) if (ierr /= 0) EXIT end do else if (nrec < 0) then ! Move backward nrec records do irec=1,-nrec backspace (unit=funt,iostat=ierr) if (ierr /= 0) EXIT end do end if end subroutine mvrecord !!*** !---------------------------------------------------------------------- !!****f* m_io_tools/open_file !! NAME !! open_file !! !! FUNCTION !! Open a file in sequential mode and associate it to the unit number number. !! The main differences wrt the intrinsic open: !! !! * Function statement that returns the value of iostat !! * Emulate iomsg (F2003) !! * Accepts either unit (user-specified unit number, input) or !! newunit (free unit not associated to any file, output). !! The two options are mutually exclusive. !! !! See Fortran intrinsic for a more detailed description of the variables !! !! OUTPUT !! iostat=Exit status !! iomsg=Error message !! !! PARENTS !! !! SOURCE function open_file(file,iomsg,unit,newunit,form,status,action) result(iostat) !This section has been created automatically by the script Abilint (TD). !Do not modify the following lines by hand. #undef ABI_FUNC #define ABI_FUNC 'open_file' !End of the abilint section implicit none !Arguments ------------------------------------ !scalars character(len=*),intent(in) :: file character(len=*),optional,intent(in) :: form,status,action character(len=*),intent(out) :: iomsg integer,optional,intent(in) :: unit integer,optional,intent(out) :: newunit integer :: iostat !Local variables------------------------------- !scalars character(len=500) :: my_form,my_status,my_action,msg ! ************************************************************************* my_form = "formatted"; if (present(form)) my_form = form my_status = "unknown"; if (present(status)) my_status = status my_action = "readwrite"; if (present(action)) my_action = action ! default is system dependent. Enforce RW mode iomsg = "" ! iomsg is not changed if open succeeds if (present(unit)) then open(file=trim(file),unit=unit,form=my_form,status=my_status,access="sequential",iostat=iostat, iomsg=iomsg) if (present(newunit)) iostat = -666 ! wrong call else if (present(newunit)) then ! Get free unit (emulate newunit of F2008) newunit = get_unit() open(file=trim(file),unit=newunit,form=my_form,status=my_status,access="sequential",iostat=iostat, iomsg=iomsg) if (present(unit)) iostat = -666 ! wrong call else iomsg = "Either unit or newunit must be specified" iostat = -1 end if if (iostat /= 0) then write(msg, "(a,i0,2a)")"Fortran open returned iostat ",iostat," while opening: "//trim(file) iomsg = trim(msg)//ch10//"IOMSG: "//trim(iomsg) end if end function open_file !!*** !---------------------------------------------------------------------- !!****f* m_io_tools/close_unit !! NAME !! close_unit !! !! FUNCTION !! close a Fortran unit !! The main differences wrt the intrinsic close: !! !! * Function statement that returns the value of iostat !! * Emulate iomsg (F2003) !! !! See Fortran intrinsic for a more detailed description of the variables !! !! OUTPUT !! iostat=Exit status !! iomsg=Error message !! !! PARENTS !! !! SOURCE function close_unit(unit,iomsg,status) result(iostat) !This section has been created automatically by the script Abilint (TD). !Do not modify the following lines by hand. #undef ABI_FUNC #define ABI_FUNC 'close_unit' !End of the abilint section implicit none !Arguments ------------------------------------ !scalars integer,intent(inout) :: unit character(len=*),optional,intent(in) :: status character(len=*),intent(out) :: iomsg integer :: iostat !Local variables------------------------------- character(len=500) :: msg ! ************************************************************************* iomsg = "" ! iomsg is not changed if close succeeds if (.not.present(status)) then ! Use Fortran default e.g delete for scratch files. #ifdef HAVE_FC_IOMSG close(unit=unit,iostat=iostat,iomsg=iomsg) #else close(unit=unit,iostat=iostat) #endif else #ifdef HAVE_FC_IOMSG close(unit=unit,iostat=iostat,status=status,iomsg=iomsg) #else close(unit=unit,iostat=iostat,status=status) #endif end if ! TODO: Add more info for example the filename. if (iostat /= 0) then write(msg,'(2(a,i0),a)')"Fortran close returned iostat ",iostat," while closing unit: ",unit,ch10 iomsg = trim(msg)//ch10//"IOMSG: "//trim(msg) end if end function close_unit !!*** !---------------------------------------------------------------------- !!****f* m_io_tools/write_lines !! NAME !! write_lines !! !! FUNCTION !! This routine receives a string, split the message in lines according to the !! ch10 character and output the text to the specified unit !! !! INPUTS !! unit=unit number for writing !! message=(character(len=*)) message to be written !! !! OUTPUT !! Only writing. !! !! PARENTS !! m_io_tools,wrtout !! !! CHILDREN !! !! SOURCE subroutine write_lines(unit,message) !This section has been created automatically by the script Abilint (TD). !Do not modify the following lines by hand. #undef ABI_FUNC #define ABI_FUNC 'write_lines' !End of the abilint section implicit none !Arguments ------------------------------------ !scalars integer,intent(in) :: unit character(len=*),intent(in) :: message !Local variables------------------------------- !scalars integer :: msg_size,ii,jj,rtnpos !****************************************************************** msg_size = len_trim(message) if (msg_size == 0) then write(unit,*) return end if ! Here, split the message, according to the char(10) characters (carriage return). ! This technique is portable accross different OS. rtnpos = index(message,ch10) if (rtnpos == 0) then write(unit,"(a)")message(1:msg_size) return end if ii = 1; jj = rtnpos do if (ii == jj) then write(unit,*) else write(unit, '(a)' ) message(ii:jj-1) end if ii = jj + 1 if (ii > msg_size) exit jj = index(message(ii:msg_size),ch10) if (jj == 0) then ! Will write the last line at the next iteration and exit . jj = msg_size + 1 else jj = jj + ii - 1 end if !write(*,*)"ii, jj, msg_size",ii, jj, msg_size end do ! This is needed to preserve the od behaviour: a ch10 at the ! end of the string was causing an extra newline! if (message(msg_size:msg_size) == ch10) write(unit,*) end subroutine write_lines !!*** !!****f* m_io_tools/lock_and_write !! NAME !! lock_and_write !! !! FUNCTION !! Writes a string to filename with locking mechanism. !! !! INPUTS !! filename: Name of the file. !! string: Input string. !! ierr: Exit status, 0 is string has been written to filename. !! !! PARENTS !! m_errors !! !! CHILDREN !! !! SOURCE subroutine lock_and_write(filename, string, ierr) !This section has been created automatically by the script Abilint (TD). !Do not modify the following lines by hand. #undef ABI_FUNC #define ABI_FUNC 'lock_and_write' !End of the abilint section integer,intent(out) :: ierr character(len=*),intent(in) :: filename,string !Local variables------------------------------- integer :: lock_unit,file_unit character(len=len(filename) + 5) :: lock !character(len=500) :: msg ! ********************************************************************* ierr = 0 ! Try to acquire the lock. lock = trim(filename)//".lock" lock_unit = get_unit() open(unit=lock_unit, file=trim(lock), status='new', err=99) file_unit = get_unit() open(unit=file_unit, file=trim(filename), form="formatted") call write_lines(file_unit, string) close(lock_unit, status="delete") close(file_unit) return 99 ierr = 1 end subroutine lock_and_write !!*** !---------------------------------------------------------------------- !!****f* m_io_tools/num_opened_units !! NAME !! num_opened_units !! !! FUNCTION !! Return the number of opened units. !! Unit numbers listed in the optional argument `ignore` are not considered. !! !! PARENTS !! !! CHILDREN !! !! SOURCE integer function num_opened_units(ignore) result(nn) !This section has been created automatically by the script Abilint (TD). !Do not modify the following lines by hand. #undef ABI_FUNC #define ABI_FUNC 'num_opened_units' !End of the abilint section implicit none !This section has been created automatically by the script Abilint (TD). !Do not modify the following lines by hand. #undef ABI_FUNC #define ABI_FUNC 'show_units' !End of the abilint section !Arguments ------------------------------------ !scalars integer,optional,intent(in) :: ignore(:) !Local variables------------------------------- integer :: ii,iostat logical :: opened ! ********************************************************************* nn = 0 do ii=0, max_unit_number if (present(ignore)) then if (any(ii == ignore)) cycle end if inquire(ii, opened=opened, iostat=iostat) if (iostat == 0 .and. opened) nn = nn + 1 end do end function num_opened_units !!*** !---------------------------------------------------------------------- !!****f* m_io_tools/show_units !! NAME !! show_units !! !! FUNCTION !! Print info on the logical units !! !! PARENTS !! m_errors !! !! CHILDREN !! !! SOURCE subroutine show_units(ount) !This section has been created automatically by the script Abilint (TD). !Do not modify the following lines by hand. #undef ABI_FUNC #define ABI_FUNC 'show_units' !End of the abilint section implicit none !This section has been created automatically by the script Abilint (TD). !Do not modify the following lines by hand. #undef ABI_FUNC #define ABI_FUNC 'show_units' !End of the abilint section !Arguments ------------------------------------ !scalars integer,intent(in) :: ount !Local variables------------------------------- integer :: ii,iostat logical :: named, opened character(len=fnlen) :: filename,form ! ********************************************************************* write(ount,'(a)') '******** Fortran Logical Units ********' do ii=0,max_unit_number inquire(ii, opened=opened, named=named, name=filename, form=form, iostat=iostat) if (iostat == 0) then if (opened) then if (named) then write(ount,*)"unit: ", ii, "form: ", trim(form), ", filename: ", trim(filename) else write(ount,*)"unit: ", ii, "form: ",form, ', No name available' endif else !write(ount,*)"unit: ", ii, " is not opened" endif else write(ount,*)" unit: ", ii, ' Iostat error' endif end do end subroutine show_units !!*** !---------------------------------------------------------------------- END MODULE m_io_tools !!*** v_sim-3.8.0/lib/plug-ins/abinit/m_linalg_interfaces.F90000066400000000000000000002544261370110300500226610ustar00rootroot00000000000000!{\src2tex{textfont=tt}} !!****m* ABINIT/m_linalg_interfaces !! NAME !! m_linalg_interfaces !! !! FUNCTION !! Interfaces for the BLAS and LAPACK linear algebra routines. !! !! COPYRIGHT !! Copyright (C) 2011-2016 ABINIT group (Yann Pouillon) !! This file is distributed under the terms of the !! GNU General Public License, see ~abinit/COPYING !! or http://www.gnu.org/copyleft/gpl.txt . !! !! WARNING !! These routines are used both by real and complex arrays !! and are commented (no interface): !! - ztrsm, zgemm, zgemv, zhemm, zherk, zher, zgerc !! - zcopy, zaxpy, zdscal, zscal, zdotc !! - zhpev, zgsev, zheev, zgetrf, zpotrf, zhegv, zhpevx !! - zhpgv, zhegst !! !! SOURCE #if defined HAVE_CONFIG_H #include "config.h" #endif module m_linalg_interfaces implicit none interface subroutine caxpy(n,ca,cx,incx,cy,incy) implicit none integer :: incx integer :: incy integer :: n complex :: ca complex :: cx(*) complex :: cy(*) end subroutine caxpy end interface interface subroutine ccopy(n,cx,incx,cy,incy) implicit none integer, intent(in) :: incx, incy, n !vz_i complex, intent(in) :: cx(*) !vz_i complex, intent(inout) :: cy(*) !vz_i end subroutine ccopy end interface interface complex function cdotc(n,cx,incx,cy,incy) implicit none integer, intent(in) :: incx, incy, n !vz_i complex, intent(in) :: cx(*), cy(*) !vz_i end function cdotc end interface interface complex function cdotu(n,cx,incx,cy,incy) implicit none integer, intent(in) :: incx, incy, n !vz_i complex, intent(in) :: cx(*), cy(*) !vz_i end function cdotu end interface interface subroutine cgbmv ( TRANS, M, N, KL, KU, ALPHA, A, LDA, X, INCX,& BETA, Y, INCY ) implicit none integer :: INCX integer :: INCY integer :: KL integer :: KU integer :: LDA integer :: M integer :: N complex :: A( LDA, * ) complex :: ALPHA complex :: BETA character*1 :: TRANS complex :: X( * ) complex :: Y( * ) end subroutine cgbmv end interface interface subroutine cgemm ( TRANSA, TRANSB, M, N, K, ALPHA, A, LDA, B, LDB,& BETA, C, LDC ) implicit none integer,intent(in) :: K,lda,ldb,ldc,m,n !vz_i complex,intent(in) :: A( LDA, * ) !vz_i complex,intent(in) :: ALPHA !vz_i complex,intent(in) :: B( LDB, * ) !vz_i complex,intent(in) :: BETA !vz_i complex,intent(inout) :: C( LDC, * ) !vz_i character*1,intent(in) :: TRANSA !vz_i character*1,intent(in) :: TRANSB !vz_i end subroutine cgemm end interface interface subroutine cgemv ( TRANS, M, N, ALPHA, A, LDA, X, INCX,& BETA, Y, INCY ) implicit none integer, intent(in) :: INCX, incy, lda, m, n !vz_i complex, intent(in) :: A( LDA, * ) !vz_i complex, intent(in) :: ALPHA, beta !vz_i character*1, intent(in) :: TRANS !vz_i complex, intent(in) :: X( * ) !vz_i complex, intent(inout) :: Y( * ) !vz_i end subroutine cgemv end interface interface subroutine cgerc ( M, N, ALPHA, X, INCX, Y, INCY, A, LDA ) implicit none integer, intent(in) :: INCX, incy, lda, m, n !vz_i complex, intent(inout) :: A( LDA, * ) !vz_i complex, intent(in) :: ALPHA !vz_i complex, intent(in) :: X( * ), Y( * ) !vz_i end subroutine cgerc end interface interface subroutine cgeru ( M, N, ALPHA, X, INCX, Y, INCY, A, LDA ) implicit none integer :: INCX integer :: INCY integer :: LDA integer :: M integer :: N complex :: A( LDA, * ) complex :: ALPHA complex :: X( * ) complex :: Y( * ) end subroutine cgeru end interface interface subroutine chbmv ( UPLO, N, K, ALPHA, A, LDA, X, INCX,& BETA, Y, INCY ) implicit none integer :: INCX integer :: INCY integer :: K integer :: LDA integer :: N complex :: A( LDA, * ) complex :: ALPHA complex :: BETA character*1 :: UPLO complex :: X( * ) complex :: Y( * ) end subroutine chbmv end interface interface subroutine chemm ( SIDE, UPLO, M, N, ALPHA, A, LDA, B, LDB,& BETA, C, LDC ) implicit none integer :: LDA integer :: LDB integer :: LDC integer :: M integer :: N complex :: A( LDA, * ) complex :: ALPHA complex :: B( LDB, * ) complex :: BETA complex :: C( LDC, * ) character*1 :: SIDE character*1 :: UPLO end subroutine chemm end interface interface subroutine chemv ( UPLO, N, ALPHA, A, LDA, X, INCX,& BETA, Y, INCY ) implicit none integer :: INCX integer :: INCY integer :: LDA integer :: N complex :: A( LDA, * ) complex :: ALPHA complex :: BETA character*1 :: UPLO complex :: X( * ) complex :: Y( * ) end subroutine chemv end interface interface subroutine cher ( UPLO, N, ALPHA, X, INCX, A, LDA ) implicit none integer :: INCX integer :: LDA integer :: N complex :: A( LDA, * ) real :: ALPHA character*1 :: UPLO complex :: X( * ) end subroutine cher end interface interface subroutine cher2 ( UPLO, N, ALPHA, X, INCX, Y, INCY, A, LDA ) implicit none integer :: INCX integer :: INCY integer :: LDA integer :: N complex :: A( LDA, * ) complex :: ALPHA character*1 :: UPLO complex :: X( * ) complex :: Y( * ) end subroutine cher2 end interface interface subroutine cher2k( UPLO, TRANS, N, K, ALPHA, A, LDA, B, LDB,& BETA, C, LDC ) implicit none integer :: K integer :: LDA integer :: LDB integer :: LDC integer :: N complex :: A( LDA, * ) complex :: ALPHA complex :: B( LDB, * ) real :: BETA complex :: C( LDC, * ) character*1 :: TRANS character*1 :: UPLO end subroutine cher2k end interface interface subroutine cherk ( UPLO, TRANS, N, K, ALPHA, A, LDA,& BETA, C, LDC ) implicit none integer, intent(in) :: K,lda,ldc,n !vz_i complex,intent(in) :: A( LDA, * ) !vz_i real,intent(in) :: ALPHA !vz_i real,intent(in) :: BETA !vz_i complex,intent(inout) :: C( LDC, * ) !vz_i character*1,intent(in) :: TRANS !vz_i character*1,intent(in) :: UPLO !vz_i end subroutine cherk end interface interface subroutine chpmv ( UPLO, N, ALPHA, AP, X, INCX, BETA, Y, INCY ) implicit none integer :: INCX integer :: INCY integer :: N complex :: ALPHA complex :: AP( * ) complex :: BETA character*1 :: UPLO complex :: X( * ) complex :: Y( * ) end subroutine chpmv end interface interface subroutine chpr ( UPLO, N, ALPHA, X, INCX, AP ) implicit none integer :: INCX integer :: N real :: ALPHA complex :: AP( * ) character*1 :: UPLO complex :: X( * ) end subroutine chpr end interface interface subroutine chpr2 ( UPLO, N, ALPHA, X, INCX, Y, INCY, AP ) implicit none integer :: INCX integer :: INCY integer :: N complex :: ALPHA complex :: AP( * ) character*1 :: UPLO complex :: X( * ) complex :: Y( * ) end subroutine chpr2 end interface interface subroutine crotg(ca,cb,c,s) implicit none real :: c complex :: ca complex :: cb complex :: s end subroutine crotg end interface interface subroutine cscal(n,ca,cx,incx) implicit none integer :: incx integer :: n complex :: ca complex :: cx(*) end subroutine cscal end interface interface subroutine csrot (n,cx,incx,cy,incy,c,s) implicit none integer :: incx integer :: incy integer :: n real :: c real :: s complex :: cx(1) complex :: cy(1) end subroutine csrot end interface interface subroutine csscal(n,sa,cx,incx) implicit none integer :: incx integer :: n real :: sa complex :: cx(*) end subroutine csscal end interface interface subroutine cswap (n,cx,incx,cy,incy) implicit none integer :: incx integer :: incy integer :: n complex :: cx(*) complex :: cy(*) end subroutine cswap end interface interface subroutine csymm ( SIDE, UPLO, M, N, ALPHA, A, LDA, B, LDB,& BETA, C, LDC ) implicit none integer :: LDA integer :: LDB integer :: LDC integer :: M integer :: N complex :: A( LDA, * ) complex :: ALPHA complex :: B( LDB, * ) complex :: BETA complex :: C( LDC, * ) character*1 :: SIDE character*1 :: UPLO end subroutine csymm end interface interface subroutine csyr2k( UPLO, TRANS, N, K, ALPHA, A, LDA, B, LDB,& BETA, C, LDC ) implicit none integer :: K integer :: LDA integer :: LDB integer :: LDC integer :: N complex :: A( LDA, * ) complex :: ALPHA complex :: B( LDB, * ) complex :: BETA complex :: C( LDC, * ) character*1 :: TRANS character*1 :: UPLO end subroutine csyr2k end interface interface subroutine csyrk ( UPLO, TRANS, N, K, ALPHA, A, LDA,& BETA, C, LDC ) implicit none integer :: K integer :: LDA integer :: LDC integer :: N complex :: A( LDA, * ) complex :: ALPHA complex :: BETA complex :: C( LDC, * ) character*1 :: TRANS character*1 :: UPLO end subroutine csyrk end interface interface subroutine ctbmv ( UPLO, TRANS, DIAG, N, K, A, LDA, X, INCX ) implicit none integer :: INCX integer :: K integer :: LDA integer :: N complex :: A( LDA, * ) character*1 :: DIAG character*1 :: TRANS character*1 :: UPLO complex :: X( * ) end subroutine ctbmv end interface interface subroutine ctbsv ( UPLO, TRANS, DIAG, N, K, A, LDA, X, INCX ) implicit none integer :: INCX integer :: K integer :: LDA integer :: N complex :: A( LDA, * ) character*1 :: DIAG character*1 :: TRANS character*1 :: UPLO complex :: X( * ) end subroutine ctbsv end interface interface subroutine ctpmv ( UPLO, TRANS, DIAG, N, AP, X, INCX ) implicit none integer :: INCX integer :: N complex :: AP( * ) character*1 :: DIAG character*1 :: TRANS character*1 :: UPLO complex :: X( * ) end subroutine ctpmv end interface interface subroutine ctpsv ( UPLO, TRANS, DIAG, N, AP, X, INCX ) implicit none integer :: INCX integer :: N complex :: AP( * ) character*1 :: DIAG character*1 :: TRANS character*1 :: UPLO complex :: X( * ) end subroutine ctpsv end interface interface subroutine ctrmm ( SIDE, UPLO, TRANSA, DIAG, M, N, ALPHA, A, LDA,& B, LDB ) implicit none integer :: LDA integer :: LDB integer :: M integer :: N complex :: A( LDA, * ) complex :: ALPHA complex :: B( LDB, * ) character*1 :: DIAG character*1 :: SIDE character*1 :: TRANSA character*1 :: UPLO end subroutine ctrmm end interface interface subroutine ctrmv ( UPLO, TRANS, DIAG, N, A, LDA, X, INCX ) implicit none integer :: INCX integer :: LDA integer :: N complex :: A( LDA, * ) character*1 :: DIAG character*1 :: TRANS character*1 :: UPLO complex :: X( * ) end subroutine ctrmv end interface interface subroutine ctrsm ( SIDE, UPLO, TRANSA, DIAG, M, N, ALPHA, A, LDA,& B, LDB ) implicit none integer :: LDA integer :: LDB integer :: M integer :: N complex :: A( LDA, * ) complex :: ALPHA complex :: B( LDB, * ) character*1 :: DIAG character*1 :: SIDE character*1 :: TRANSA character*1 :: UPLO end subroutine ctrsm end interface interface subroutine ctrsv ( UPLO, TRANS, DIAG, N, A, LDA, X, INCX ) implicit none integer :: INCX integer :: LDA integer :: N complex :: A( LDA, * ) character*1 :: DIAG character*1 :: TRANS character*1 :: UPLO complex :: X( * ) end subroutine ctrsv end interface interface double precision function dasum(n,dx,incx) implicit none integer :: incx integer :: n double precision :: dx(*) end function dasum end interface interface subroutine daxpy(n,da,dx,incx,dy,incy) implicit none integer :: incx integer :: incy integer :: n double precision :: da double precision :: dx(*) double precision :: dy(*) end subroutine daxpy end interface interface double precision function dcabs1(z) implicit none double complex :: z end function dcabs1 end interface !interface ! subroutine dcopy(n,dx,incx,dy,incy) ! implicit none ! integer :: incx ! integer :: incy ! integer :: n ! double precision :: dx(*) ! double precision :: dy(*) ! end subroutine dcopy !end interface interface double precision function ddot(n,dx,incx,dy,incy) implicit none integer,intent(in) :: incx integer,intent(in) :: incy integer,intent(in) :: n double precision,intent(in) :: dx(*) double precision,intent(in) :: dy(*) end function ddot end interface interface subroutine dgbmv ( TRANS, M, N, KL, KU, ALPHA, A, LDA, X, INCX,& BETA, Y, INCY ) implicit none integer :: INCX integer :: INCY integer :: KL integer :: KU integer :: LDA integer :: M integer :: N double precision :: A( LDA, * ) double precision :: ALPHA double precision :: BETA character*1 :: TRANS double precision :: X( * ) double precision :: Y( * ) end subroutine dgbmv end interface interface subroutine dgemm ( TRANSA, TRANSB, M, N, K, ALPHA, A, LDA, B, LDB,& BETA, C, LDC ) implicit none integer,intent(in) :: K,lda,ldb,ldc,m,n !vz_i double precision, intent(in) :: A( LDA, * ) !vz_i double precision,intent(in) :: ALPHA !vz_i double precision,intent(in) :: B( LDB, * ) !vz_i double precision,intent(in) :: BETA !vz_i double precision,intent(inout) :: C( LDC, * ) !vz_i character*1,intent(in) :: TRANSA !vz_i character*1,intent(in) :: TRANSB !vz_i end subroutine dgemm end interface interface subroutine dgemv ( TRANS, M, N, ALPHA, A, LDA, X, INCX,& BETA, Y, INCY ) implicit none integer, intent(in) :: INCX,incy,lda,m,n !vz_i double precision, intent(in) :: A( LDA, * ) !vz_i double precision, intent(in) :: ALPHA !vz_i double precision, intent(in) :: BETA !vz_i character*1, intent(in) :: TRANS !vz_i double precision, intent(in) :: X( * ) !vz_i double precision, intent(inout) :: Y( * ) !vz_i end subroutine dgemv end interface interface subroutine dger ( M, N, ALPHA, X, INCX, Y, INCY, A, LDA ) implicit none integer :: INCX integer :: INCY integer :: LDA integer :: M integer :: N double precision :: A( LDA, * ) double precision :: ALPHA double precision :: X( * ) double precision :: Y( * ) end subroutine dger end interface interface double precision function dnrm2 ( N, X, INCX ) implicit none integer, intent(in) :: INCX, n !vz_i double precision,intent(in) :: X( * ) !vz_i end function dnrm2 end interface interface subroutine drot (n,dx,incx,dy,incy,c,s) implicit none integer :: incx integer :: incy integer :: n double precision :: c double precision :: s double precision :: dx(*) double precision :: dy(*) end subroutine drot end interface interface subroutine drotg(da,db,c,s) implicit none double precision :: c double precision :: da double precision :: db double precision :: s end subroutine drotg end interface interface subroutine drotm (N,DX,INCX,DY,INCY,DPARAM) implicit none integer :: INCX integer :: INCY integer :: N double precision :: DPARAM(5) double precision :: DX(1) double precision :: DY(1) end subroutine drotm end interface interface subroutine drotmg (DD1,DD2,DX1,DY1,DPARAM) implicit none double precision :: DD1 double precision :: DD2 double precision :: DPARAM(5) double precision :: DX1 double precision :: DY1 end subroutine drotmg end interface interface subroutine dsbmv ( UPLO, N, K, ALPHA, A, LDA, X, INCX,& BETA, Y, INCY ) implicit none integer :: INCX integer :: INCY integer :: K integer :: LDA integer :: N double precision :: A( LDA, * ) double precision :: ALPHA double precision :: BETA character*1 :: UPLO double precision :: X( * ) double precision :: Y( * ) end subroutine dsbmv end interface interface subroutine dscal(n,da,dx,incx) implicit none integer :: incx integer :: n double precision :: da double precision :: dx(*) end subroutine dscal end interface interface double precision function dsdot (N, SX, INCX, SY, INCY) implicit none integer :: INCX integer :: INCY integer :: N real :: SX(*) real :: SY(*) end function dsdot end interface interface subroutine dswap (n,dx,incx,dy,incy) implicit none integer :: incx integer :: incy integer :: n double precision :: dx(*) double precision :: dy(*) end subroutine dswap end interface interface subroutine dsymm ( SIDE, UPLO, M, N, ALPHA, A, LDA, B, LDB,& BETA, C, LDC ) implicit none integer :: LDA integer :: LDB integer :: LDC integer :: M integer :: N double precision :: A( LDA, * ) double precision :: ALPHA double precision :: B( LDB, * ) double precision :: BETA double precision :: C( LDC, * ) character*1 :: SIDE character*1 :: UPLO end subroutine dsymm end interface interface subroutine dsymv ( UPLO, N, ALPHA, A, LDA, X, INCX,& BETA, Y, INCY ) implicit none integer :: INCX integer :: INCY integer :: LDA integer :: N double precision :: A( LDA, * ) double precision :: ALPHA double precision :: BETA character*1 :: UPLO double precision :: X( * ) double precision :: Y( * ) end subroutine dsymv end interface interface subroutine dtrmm ( SIDE, UPLO, TRANSA, DIAG, M, N, ALPHA, A, LDA,& B, LDB ) implicit none integer :: LDA integer :: LDB integer :: M integer :: N double precision :: A( LDA, * ) double precision :: ALPHA double precision :: B( LDB, * ) character*1 :: DIAG character*1 :: SIDE character*1 :: TRANSA character*1 :: UPLO end subroutine dtrmm end interface interface subroutine dtrmv ( UPLO, TRANS, DIAG, N, A, LDA, X, INCX ) implicit none integer :: INCX integer :: LDA integer :: N double precision :: A( LDA, * ) character*1 :: DIAG character*1 :: TRANS character*1 :: UPLO double precision :: X( * ) end subroutine dtrmv end interface interface subroutine dtrsm ( SIDE, UPLO, TRANSA, DIAG, M, N, ALPHA, A, LDA,& B, LDB ) implicit none integer :: LDA integer :: LDB integer :: M integer :: N double precision :: A( LDA, * ) double precision :: ALPHA double precision :: B( LDB, * ) character*1 :: DIAG character*1 :: SIDE character*1 :: TRANSA character*1 :: UPLO end subroutine dtrsm end interface interface subroutine dtrsv ( UPLO, TRANS, DIAG, N, A, LDA, X, INCX ) implicit none integer :: INCX integer :: LDA integer :: N double precision :: A( LDA, * ) character*1 :: DIAG character*1 :: TRANS character*1 :: UPLO double precision :: X( * ) end subroutine dtrsv end interface interface double precision function dzasum(n,zx,incx) implicit none integer :: incx integer :: n double complex :: zx(*) end function dzasum end interface interface double precision function dznrm2( N, X, INCX ) implicit none integer, intent(in) :: INCX, n !vz_i complex*16,intent(in) :: X( * ) !vz_i end function dznrm2 end interface interface integer function icamax(n,cx,incx) implicit none integer :: incx integer :: n complex :: cx(*) end function icamax end interface interface integer function idamax(n,dx,incx) implicit none integer :: incx integer :: n double precision :: dx(*) end function idamax end interface interface integer function isamax(n,sx,incx) implicit none integer :: incx integer :: n real :: sx(*) end function isamax end interface interface integer function izamax(n,zx,incx) implicit none integer :: incx integer :: n double complex :: zx(*) end function izamax end interface interface real function sasum(n,sx,incx) implicit none integer :: incx integer :: n real :: sx(*) end function sasum end interface interface subroutine saxpy(n,sa,sx,incx,sy,incy) implicit none integer :: incx integer :: incy integer :: n real :: sa real :: sx(*) real :: sy(*) end subroutine saxpy end interface interface real function scasum(n,cx,incx) implicit none integer :: incx integer :: n complex :: cx(*) end function scasum end interface interface real function scnrm2( N, X, INCX ) implicit none integer, intent(in) :: INCX, n !vz_i complex, intent(in) :: X( * ) !vz_i end function scnrm2 end interface interface subroutine scopy(n,sx,incx,sy,incy) implicit none integer, intent(in) :: incx,incy,n !vz_i real, intent(in) :: sx(*) !vz_i real, intent(inout) :: sy(*) !vz_i end subroutine scopy end interface interface real function sdot(n,sx,incx,sy,incy) implicit none integer :: incx integer :: incy integer :: n real :: sx(*) real :: sy(*) end function sdot end interface interface real function sdsdot (N, SB, SX, INCX, SY, INCY) implicit none integer :: INCX integer :: INCY integer :: N real :: SB real :: SX(*) real :: SY(*) end function sdsdot end interface interface subroutine sgbmv ( TRANS, M, N, KL, KU, ALPHA, A, LDA, X, INCX,& BETA, Y, INCY ) implicit none integer :: INCX integer :: INCY integer :: KL integer :: KU integer :: LDA integer :: M integer :: N real :: A( LDA, * ) real :: ALPHA real :: BETA character*1 :: TRANS real :: X( * ) real :: Y( * ) end subroutine sgbmv end interface interface subroutine sgemm ( TRANSA, TRANSB, M, N, K, ALPHA, A, LDA, B, LDB,& BETA, C, LDC ) implicit none integer, intent(in) :: K,lda,ldb,ldc,m,n !vz_i real,intent(in) :: A( LDA, * ) !vz_i real,intent(in) :: ALPHA !vz_i real,intent(in) :: B( LDB, * ) !vz_i real,intent(in) :: BETA !vz_i real,intent(inout) :: C( LDC, * ) !vz_i character*1,intent(in) :: TRANSA !vz_i character*1,intent(in) :: TRANSB !vz_i end subroutine sgemm end interface interface subroutine sgemv ( TRANS, M, N, ALPHA, A, LDA, X, INCX,& BETA, Y, INCY ) implicit none integer,intent(in) :: INCX, incy, lda,m,n !vz_i real,intent(in) :: A( LDA, * ) !vz_i real,intent(in) :: ALPHA !vz_i real,intent(in) :: BETA !vz_i character*1,intent(in) :: TRANS !vz_i real,intent(in) :: X( * ) !vz_i real,intent(inout) :: Y( * ) !vz_i end subroutine sgemv end interface interface subroutine sger ( M, N, ALPHA, X, INCX, Y, INCY, A, LDA ) implicit none integer :: INCX integer :: INCY integer :: LDA integer :: M integer :: N real :: A( LDA, * ) real :: ALPHA real :: X( * ) real :: Y( * ) end subroutine sger end interface interface real function snrm2 ( N, X, INCX ) implicit none integer,intent(in) :: INCX,n !vz_i real,intent(in) :: X( * ) !vz_i end function snrm2 end interface interface subroutine srot (n,sx,incx,sy,incy,c,s) implicit none integer :: incx integer :: incy integer :: n real :: c real :: s real :: sx(*) real :: sy(*) end subroutine srot end interface interface subroutine srotg(sa,sb,c,s) implicit none real :: c real :: s real :: sa real :: sb end subroutine srotg end interface interface subroutine srotm (N,SX,INCX,SY,INCY,SPARAM) implicit none integer :: INCX integer :: INCY integer :: N real :: SPARAM(5) real :: SX(1) real :: SY(1) end subroutine srotm end interface interface subroutine srotmg (SD1,SD2,SX1,SY1,SPARAM) implicit none real :: SD1 real :: SD2 real :: SPARAM(5) real :: SX1 real :: SY1 end subroutine srotmg end interface interface subroutine ssbmv ( UPLO, N, K, ALPHA, A, LDA, X, INCX,& BETA, Y, INCY ) implicit none integer :: INCX integer :: INCY integer :: K integer :: LDA integer :: N real :: A( LDA, * ) real :: ALPHA real :: BETA character*1 :: UPLO real :: X( * ) real :: Y( * ) end subroutine ssbmv end interface interface subroutine sscal(n,sa,sx,incx) implicit none integer :: incx integer :: n real :: sa real :: sx(*) end subroutine sscal end interface interface subroutine sspmv ( UPLO, N, ALPHA, AP, X, INCX, BETA, Y, INCY ) implicit none integer :: INCX integer :: INCY integer :: N real :: ALPHA real :: AP( * ) real :: BETA character*1 :: UPLO real :: X( * ) real :: Y( * ) end subroutine sspmv end interface interface subroutine sspr ( UPLO, N, ALPHA, X, INCX, AP ) implicit none integer :: INCX integer :: N real :: ALPHA real :: AP( * ) character*1 :: UPLO real :: X( * ) end subroutine sspr end interface interface subroutine sspr2 ( UPLO, N, ALPHA, X, INCX, Y, INCY, AP ) implicit none integer :: INCX integer :: INCY integer :: N real :: ALPHA real :: AP( * ) character*1 :: UPLO real :: X( * ) real :: Y( * ) end subroutine sspr2 end interface interface subroutine sswap (n,sx,incx,sy,incy) implicit none integer :: incx integer :: incy integer :: n real :: sx(*) real :: sy(*) end subroutine sswap end interface interface subroutine ssymm ( SIDE, UPLO, M, N, ALPHA, A, LDA, B, LDB,& BETA, C, LDC ) implicit none integer :: LDA integer :: LDB integer :: LDC integer :: M integer :: N real :: A( LDA, * ) real :: ALPHA real :: B( LDB, * ) real :: BETA real :: C( LDC, * ) character*1 :: SIDE character*1 :: UPLO end subroutine ssymm end interface interface subroutine ssymv ( UPLO, N, ALPHA, A, LDA, X, INCX,& BETA, Y, INCY ) implicit none integer :: INCX integer :: INCY integer :: LDA integer :: N real :: A( LDA, * ) real :: ALPHA real :: BETA character*1 :: UPLO real :: X( * ) real :: Y( * ) end subroutine ssymv end interface interface subroutine ssyr ( UPLO, N, ALPHA, X, INCX, A, LDA ) implicit none integer :: INCX integer :: LDA integer :: N real :: A( LDA, * ) real :: ALPHA character*1 :: UPLO real :: X( * ) end subroutine ssyr end interface interface subroutine ssyr2 ( UPLO, N, ALPHA, X, INCX, Y, INCY, A, LDA ) implicit none integer :: INCX integer :: INCY integer :: LDA integer :: N real :: A( LDA, * ) real :: ALPHA character*1 :: UPLO real :: X( * ) real :: Y( * ) end subroutine ssyr2 end interface interface subroutine ssyr2k( UPLO, TRANS, N, K, ALPHA, A, LDA, B, LDB,& BETA, C, LDC ) implicit none integer :: K integer :: LDA integer :: LDB integer :: LDC integer :: N real :: A( LDA, * ) real :: ALPHA real :: B( LDB, * ) real :: BETA real :: C( LDC, * ) character*1 :: TRANS character*1 :: UPLO end subroutine ssyr2k end interface interface subroutine ssyrk ( UPLO, TRANS, N, K, ALPHA, A, LDA,& BETA, C, LDC ) implicit none integer :: K integer :: LDA integer :: LDC integer :: N real :: A( LDA, * ) real :: ALPHA real :: BETA real :: C( LDC, * ) character*1 :: TRANS character*1 :: UPLO end subroutine ssyrk end interface interface subroutine stbmv ( UPLO, TRANS, DIAG, N, K, A, LDA, X, INCX ) implicit none integer :: INCX integer :: K integer :: LDA integer :: N real :: A( LDA, * ) character*1 :: DIAG character*1 :: TRANS character*1 :: UPLO real :: X( * ) end subroutine stbmv end interface interface subroutine stbsv ( UPLO, TRANS, DIAG, N, K, A, LDA, X, INCX ) implicit none integer :: INCX integer :: K integer :: LDA integer :: N real :: A( LDA, * ) character*1 :: DIAG character*1 :: TRANS character*1 :: UPLO real :: X( * ) end subroutine stbsv end interface interface subroutine stpmv ( UPLO, TRANS, DIAG, N, AP, X, INCX ) implicit none integer :: INCX integer :: N real :: AP( * ) character*1 :: DIAG character*1 :: TRANS character*1 :: UPLO real :: X( * ) end subroutine stpmv end interface interface subroutine stpsv ( UPLO, TRANS, DIAG, N, AP, X, INCX ) implicit none integer :: INCX integer :: N real :: AP( * ) character*1 :: DIAG character*1 :: TRANS character*1 :: UPLO real :: X( * ) end subroutine stpsv end interface interface subroutine strmm ( SIDE, UPLO, TRANSA, DIAG, M, N, ALPHA, A, LDA,& B, LDB ) implicit none integer :: LDA integer :: LDB integer :: M integer :: N real :: A( LDA, * ) real :: ALPHA real :: B( LDB, * ) character*1 :: DIAG character*1 :: SIDE character*1 :: TRANSA character*1 :: UPLO end subroutine strmm end interface interface subroutine strmv ( UPLO, TRANS, DIAG, N, A, LDA, X, INCX ) implicit none integer :: INCX integer :: LDA integer :: N real :: A( LDA, * ) character*1 :: DIAG character*1 :: TRANS character*1 :: UPLO real :: X( * ) end subroutine strmv end interface interface subroutine strsm ( SIDE, UPLO, TRANSA, DIAG, M, N, ALPHA, A, LDA,& B, LDB ) implicit none integer :: LDA integer :: LDB integer :: M integer :: N real :: A( LDA, * ) real :: ALPHA real :: B( LDB, * ) character*1 :: DIAG character*1 :: SIDE character*1 :: TRANSA character*1 :: UPLO end subroutine strsm end interface interface subroutine strsv ( UPLO, TRANS, DIAG, N, A, LDA, X, INCX ) implicit none integer :: INCX integer :: LDA integer :: N real :: A( LDA, * ) character*1 :: DIAG character*1 :: TRANS character*1 :: UPLO real :: X( * ) end subroutine strsv end interface !interface ! subroutine zaxpy(n,za,zx,incx,zy,incy) ! implicit none ! integer :: incx ! integer :: incy ! integer :: n ! double complex :: za ! double complex :: zx(*) ! double complex :: zy(*) ! end subroutine zaxpy !end interface !interface ! subroutine zcopy(n,zx,incx,zy,incy) ! implicit none ! integer :: incx ! integer :: incy ! integer :: n ! double complex :: zx(*) ! double complex :: zy(*) ! end subroutine zcopy !end interface !interface ! double complex function zdotc(n,zx,incx,zy,incy) ! implicit none ! integer :: incx ! integer :: incy ! integer :: n ! double complex :: zx(*) ! double complex :: zy(*) ! end function zdotc !end interface interface double complex function zdotu(n,zx,incx,zy,incy) implicit none integer, intent(in) :: incx, incy, n !vz_i double complex, intent(in) :: zx(*), zy(*) !vz_i end function zdotu end interface interface subroutine zdrot( N, CX, INCX, CY, INCY, C, S ) implicit none integer :: INCX integer :: INCY integer :: N double precision :: C complex*16 :: CX( * ) complex*16 :: CY( * ) double precision :: S end subroutine zdrot end interface !interface ! subroutine zdscal(n,da,zx,incx) ! implicit none ! integer :: incx ! integer :: n ! double precision :: da ! double complex :: zx(*) ! end subroutine zdscal !end interface interface subroutine zgbmv ( TRANS, M, N, KL, KU, ALPHA, A, LDA, X, INCX,& BETA, Y, INCY ) implicit none integer :: INCX integer :: INCY integer :: KL integer :: KU integer :: LDA integer :: M integer :: N complex*16 :: A( LDA, * ) complex*16 :: ALPHA complex*16 :: BETA character*1 :: TRANS complex*16 :: X( * ) complex*16 :: Y( * ) end subroutine zgbmv end interface !interface ! subroutine zgemm ( TRANSA, TRANSB, M, N, K, ALPHA, A, LDA, B, LDB, BETA, C, LDC ) ! implicit none ! integer :: K ! integer :: LDA ! integer :: LDB ! integer :: LDC ! integer :: M ! integer :: N ! complex*16 :: A( LDA, * ) ! complex*16 :: ALPHA ! complex*16 :: B( LDB, * ) ! complex*16 :: BETA ! complex*16 :: C( LDC, * ) ! character*1 :: TRANSA ! character*1 :: TRANSB ! end subroutine zgemm !end interface !interface ! subroutine zgemv ( TRANS, M, N, ALPHA, A, LDA, X, INCX, BETA, Y, INCY ) ! implicit none ! integer :: INCX ! integer :: INCY ! integer :: LDA ! integer :: M ! integer :: N ! complex*16 :: A( LDA, * ) ! complex*16 :: ALPHA ! complex*16 :: BETA ! character*1 :: TRANS ! complex*16 :: X( * ) ! complex*16 :: Y( * ) ! end subroutine zgemv !end interface !interface ! subroutine zgerc ( M, N, ALPHA, X, INCX, Y, INCY, A, LDA ) ! implicit none ! integer :: INCX ! integer :: INCY ! integer :: LDA ! integer :: M ! integer :: N ! complex*16 :: A( LDA, * ) ! complex*16 :: ALPHA ! complex*16 :: X( * ) ! complex*16 :: Y( * ) ! end subroutine zgerc !end interface interface subroutine zgeru ( M, N, ALPHA, X, INCX, Y, INCY, A, LDA ) implicit none integer :: INCX integer :: INCY integer :: LDA integer :: M integer :: N complex*16 :: A( LDA, * ) complex*16 :: ALPHA complex*16 :: X( * ) complex*16 :: Y( * ) end subroutine zgeru end interface interface subroutine zhbmv ( UPLO, N, K, ALPHA, A, LDA, X, INCX,& BETA, Y, INCY ) implicit none integer :: INCX integer :: INCY integer :: K integer :: LDA integer :: N complex*16 :: A( LDA, * ) complex*16 :: ALPHA complex*16 :: BETA character*1 :: UPLO complex*16 :: X( * ) complex*16 :: Y( * ) end subroutine zhbmv end interface !interface ! subroutine zhemm ( SIDE, UPLO, M, N, ALPHA, A, LDA, B, LDB, BETA, C, LDC ) ! implicit none ! integer :: LDA ! integer :: LDB ! integer :: LDC ! integer :: M ! integer :: N ! complex*16 :: A( LDA, * ) ! complex*16 :: ALPHA ! complex*16 :: B( LDB, * ) ! complex*16 :: BETA ! complex*16 :: C( LDC, * ) ! character*1 :: SIDE ! character*1 :: UPLO ! end subroutine zhemm !end interface interface subroutine zhemv ( UPLO, N, ALPHA, A, LDA, X, INCX,& BETA, Y, INCY ) implicit none integer :: INCX integer :: INCY integer :: LDA integer :: N complex*16 :: A( LDA, * ) complex*16 :: ALPHA complex*16 :: BETA character*1 :: UPLO complex*16 :: X( * ) complex*16 :: Y( * ) end subroutine zhemv end interface !interface ! subroutine zher ( UPLO, N, ALPHA, X, INCX, A, LDA ) ! implicit none ! integer :: INCX ! integer :: LDA ! integer :: N ! complex*16 :: A( LDA, * ) ! double precision :: ALPHA ! character*1 :: UPLO ! complex*16 :: X( * ) ! end subroutine zher !end interface interface subroutine zher2 ( UPLO, N, ALPHA, X, INCX, Y, INCY, A, LDA ) implicit none integer :: INCX integer :: INCY integer :: LDA integer :: N complex*16 :: A( LDA, * ) complex*16 :: ALPHA character*1 :: UPLO complex*16 :: X( * ) complex*16 :: Y( * ) end subroutine zher2 end interface interface subroutine zher2k( UPLO, TRANS, N, K, ALPHA, A, LDA, B, LDB, BETA,& C, LDC ) implicit none integer :: K integer :: LDA integer :: LDB integer :: LDC integer :: N complex*16 :: A( LDA, * ) complex*16 :: ALPHA complex*16 :: B( LDB, * ) double precision :: BETA complex*16 :: C( LDC, * ) character :: TRANS character :: UPLO end subroutine zher2k end interface !interface ! subroutine zherk( UPLO, TRANS, N, K, ALPHA, A, LDA, BETA, C, LDC ) ! implicit none ! integer :: K ! integer :: LDA ! integer :: LDC ! integer :: N ! complex*16 :: A( LDA, * ) ! double precision :: ALPHA ! double precision :: BETA ! complex*16 :: C( LDC, * ) ! character :: TRANS ! character :: UPLO ! end subroutine zherk !end interface interface subroutine zhpmv ( UPLO, N, ALPHA, AP, X, INCX, BETA, Y, INCY ) implicit none integer :: INCX integer :: INCY integer :: N complex*16 :: ALPHA complex*16 :: AP( * ) complex*16 :: BETA character*1 :: UPLO complex*16 :: X( * ) complex*16 :: Y( * ) end subroutine zhpmv end interface interface subroutine zhpr ( UPLO, N, ALPHA, X, INCX, AP ) implicit none integer :: INCX integer :: N double precision :: ALPHA complex*16 :: AP( * ) character*1 :: UPLO complex*16 :: X( * ) end subroutine zhpr end interface interface subroutine zhpr2 ( UPLO, N, ALPHA, X, INCX, Y, INCY, AP ) implicit none integer :: INCX integer :: INCY integer :: N complex*16 :: ALPHA complex*16 :: AP( * ) character*1 :: UPLO complex*16 :: X( * ) complex*16 :: Y( * ) end subroutine zhpr2 end interface interface subroutine zrotg(ca,cb,c,s) implicit none double precision :: c double complex :: ca double complex :: cb double complex :: s end subroutine zrotg end interface !interface ! subroutine zscal(n,za,zx,incx) ! implicit none ! integer :: incx ! integer :: n ! double complex :: za ! double complex :: zx(*) ! end subroutine zscal !end interface interface subroutine zswap (n,zx,incx,zy,incy) implicit none integer :: incx integer :: incy integer :: n double complex :: zx(*) double complex :: zy(*) end subroutine zswap end interface interface subroutine zsymm ( SIDE, UPLO, M, N, ALPHA, A, LDA, B, LDB,& BETA, C, LDC ) implicit none integer :: LDA integer :: LDB integer :: LDC integer :: M integer :: N complex*16 :: A( LDA, * ) complex*16 :: ALPHA complex*16 :: B( LDB, * ) complex*16 :: BETA complex*16 :: C( LDC, * ) character*1 :: SIDE character*1 :: UPLO end subroutine zsymm end interface interface subroutine zsyr2k( UPLO, TRANS, N, K, ALPHA, A, LDA, B, LDB,& BETA, C, LDC ) implicit none integer :: K integer :: LDA integer :: LDB integer :: LDC integer :: N complex*16 :: A( LDA, * ) complex*16 :: ALPHA complex*16 :: B( LDB, * ) complex*16 :: BETA complex*16 :: C( LDC, * ) character*1 :: TRANS character*1 :: UPLO end subroutine zsyr2k end interface interface subroutine zsyrk ( UPLO, TRANS, N, K, ALPHA, A, LDA,& BETA, C, LDC ) implicit none integer :: K integer :: LDA integer :: LDC integer :: N complex*16 :: A( LDA, * ) complex*16 :: ALPHA complex*16 :: BETA complex*16 :: C( LDC, * ) character*1 :: TRANS character*1 :: UPLO end subroutine zsyrk end interface interface subroutine ztbmv ( UPLO, TRANS, DIAG, N, K, A, LDA, X, INCX ) implicit none integer :: INCX integer :: K integer :: LDA integer :: N complex*16 :: A( LDA, * ) character*1 :: DIAG character*1 :: TRANS character*1 :: UPLO complex*16 :: X( * ) end subroutine ztbmv end interface interface subroutine ztbsv ( UPLO, TRANS, DIAG, N, K, A, LDA, X, INCX ) implicit none integer :: INCX integer :: K integer :: LDA integer :: N complex*16 :: A( LDA, * ) character*1 :: DIAG character*1 :: TRANS character*1 :: UPLO complex*16 :: X( * ) end subroutine ztbsv end interface interface subroutine ztpmv ( UPLO, TRANS, DIAG, N, AP, X, INCX ) implicit none integer :: INCX integer :: N complex*16 :: AP( * ) character*1 :: DIAG character*1 :: TRANS character*1 :: UPLO complex*16 :: X( * ) end subroutine ztpmv end interface interface subroutine ztpsv ( UPLO, TRANS, DIAG, N, AP, X, INCX ) implicit none integer :: INCX integer :: N complex*16 :: AP( * ) character*1 :: DIAG character*1 :: TRANS character*1 :: UPLO complex*16 :: X( * ) end subroutine ztpsv end interface interface subroutine ztrmm ( SIDE, UPLO, TRANSA, DIAG, M, N, ALPHA, A, LDA,& B, LDB ) implicit none integer :: LDA integer :: LDB integer :: M integer :: N complex*16 :: A( LDA, * ) complex*16 :: ALPHA complex*16 :: B( LDB, * ) character*1 :: DIAG character*1 :: SIDE character*1 :: TRANSA character*1 :: UPLO end subroutine ztrmm end interface interface subroutine ztrmv ( UPLO, TRANS, DIAG, N, A, LDA, X, INCX ) implicit none integer :: INCX integer :: LDA integer :: N complex*16 :: A( LDA, * ) character*1 :: DIAG character*1 :: TRANS character*1 :: UPLO complex*16 :: X( * ) end subroutine ztrmv end interface !interface ! subroutine ztrsm ( SIDE, UPLO, TRANSA, DIAG, M, N, ALPHA, A, LDA, B, LDB ) ! implicit none ! integer :: LDA ! integer :: LDB ! integer :: M ! integer :: N ! complex*16 :: A( LDA, * ) ! complex*16 :: ALPHA ! complex*16 :: B( LDB, * ) ! character*1 :: DIAG ! character*1 :: SIDE ! character*1 :: TRANSA ! character*1 :: UPLO ! end subroutine ztrsm !end interface interface subroutine ztrsv ( UPLO, TRANS, DIAG, N, A, LDA, X, INCX ) implicit none integer :: INCX integer :: LDA integer :: N complex*16 :: A( LDA, * ) character*1 :: DIAG character*1 :: TRANS character*1 :: UPLO complex*16 :: X( * ) end subroutine ztrsv end interface interface subroutine cgetf2( M, N, A, LDA, IPIV, INFO ) implicit none integer :: INFO integer :: IPIV( * ) integer :: LDA integer :: M integer :: N complex :: A( LDA, * ) end subroutine cgetf2 end interface interface subroutine cgetrf( M, N, A, LDA, IPIV, INFO ) implicit none integer :: INFO integer :: IPIV( * ) integer :: LDA integer :: M integer :: N complex :: A( LDA, * ) end subroutine cgetrf end interface interface subroutine cgetri( N, A, LDA, IPIV, WORK, LWORK, INFO ) implicit none integer :: INFO integer :: IPIV( * ) integer :: LDA integer :: LWORK integer :: N complex :: A( LDA, * ) complex :: WORK( * ) end subroutine cgetri end interface interface subroutine chpev( JOBZ, UPLO, N, AP, W, Z, LDZ, WORK, RWORK,& INFO ) implicit none integer :: INFO integer :: LDZ integer :: N complex :: AP( * ) character :: JOBZ real :: RWORK( * ) character :: UPLO real :: W( * ) complex :: WORK( * ) complex :: Z( LDZ, * ) end subroutine chpev end interface interface subroutine chptrd( UPLO, N, AP, D, E, TAU, INFO ) implicit none integer :: INFO integer :: N complex :: AP( * ) real :: D( * ) real :: E( * ) complex :: TAU( * ) character :: UPLO end subroutine chptrd end interface interface complex function cladiv( X, Y ) implicit none complex :: X complex :: Y end function cladiv end interface interface real function clanhp( NORM, UPLO, N, AP, WORK ) implicit none integer :: N complex :: AP( * ) character :: NORM character :: UPLO real :: WORK( * ) end function clanhp end interface interface subroutine clarf( SIDE, M, N, V, INCV, TAU, C, LDC, WORK ) implicit none integer :: INCV integer :: LDC integer :: M integer :: N complex :: C( LDC, * ) character :: SIDE complex :: TAU complex :: V( * ) complex :: WORK( * ) end subroutine clarf end interface interface subroutine clarfg( N, ALPHA, X, INCX, TAU ) implicit none integer :: INCX integer :: N complex :: ALPHA complex :: TAU complex :: X( * ) end subroutine clarfg end interface interface subroutine clasr( SIDE, PIVOT, DIRECT, M, N, C, S, A, LDA ) implicit none integer :: LDA integer :: M integer :: N complex :: A( LDA, * ) real :: C( * ) character :: DIRECT character :: PIVOT real :: S( * ) character :: SIDE end subroutine clasr end interface interface subroutine classq( N, X, INCX, SCALE, SUMSQ ) implicit none integer :: INCX integer :: N real :: SCALE real :: SUMSQ complex :: X( * ) end subroutine classq end interface interface subroutine claswp( N, A, LDA, K1, K2, IPIV, INCX ) implicit none integer :: INCX integer :: IPIV( * ) integer :: K1 integer :: K2 integer :: LDA integer :: N complex :: A( LDA, * ) end subroutine claswp end interface interface subroutine clazro( M, N, ALPHA, BETA, A, LDA ) implicit none integer :: LDA integer :: M integer :: N complex :: A( LDA, * ) complex :: ALPHA complex :: BETA end subroutine clazro end interface interface subroutine csteqr( COMPZ, N, D, E, Z, LDZ, WORK, INFO ) implicit none integer :: INFO integer :: LDZ integer :: N character :: COMPZ real :: D( * ) real :: E( * ) real :: WORK( * ) complex :: Z( LDZ, * ) end subroutine csteqr end interface interface subroutine ctrtri( UPLO, DIAG, N, A, LDA, INFO ) implicit none integer :: INFO integer :: LDA integer :: N complex :: A( LDA, * ) character :: DIAG character :: UPLO end subroutine ctrtri end interface interface subroutine cung2l( M, N, K, A, LDA, TAU, WORK, INFO ) implicit none integer :: INFO integer :: K integer :: LDA integer :: M integer :: N complex :: A( LDA, * ) complex :: TAU( * ) complex :: WORK( * ) end subroutine cung2l end interface interface subroutine cung2r( M, N, K, A, LDA, TAU, WORK, INFO ) implicit none integer :: INFO integer :: K integer :: LDA integer :: M integer :: N complex :: A( LDA, * ) complex :: TAU( * ) complex :: WORK( * ) end subroutine cung2r end interface interface subroutine cupgtr( UPLO, N, AP, TAU, Q, LDQ, WORK, INFO ) implicit none integer :: INFO integer :: LDQ integer :: N complex :: AP( * ) complex :: Q( LDQ, * ) complex :: TAU( * ) character :: UPLO complex :: WORK( * ) end subroutine cupgtr end interface interface subroutine dbdsqr( UPLO, N, NCVT, NRU, NCC, D, E, VT, LDVT, U,& LDU, C, LDC, WORK, INFO ) implicit none integer :: INFO integer :: LDC integer :: LDU integer :: LDVT integer :: N integer :: NCC integer :: NCVT integer :: NRU double precision :: C( LDC, * ) double precision :: D( * ) double precision :: E( * ) double precision :: U( LDU, * ) character :: UPLO double precision :: VT( LDVT, * ) double precision :: WORK( * ) end subroutine dbdsqr end interface interface subroutine dgebd2( M, N, A, LDA, D, E, TAUQ, TAUP, WORK, INFO ) implicit none integer :: INFO integer :: LDA integer :: M integer :: N double precision :: A( LDA, * ) double precision :: D( * ) double precision :: E( * ) double precision :: TAUP( * ) double precision :: TAUQ( * ) double precision :: WORK( * ) end subroutine dgebd2 end interface interface subroutine dgebrd( M, N, A, LDA, D, E, TAUQ, TAUP, WORK, LWORK,& INFO ) implicit none integer :: INFO integer :: LDA integer :: LWORK integer :: M integer :: N double precision :: A( LDA, * ) double precision :: D( * ) double precision :: E( * ) double precision :: TAUP( * ) double precision :: TAUQ( * ) double precision :: WORK( * ) end subroutine dgebrd end interface interface subroutine dgelq2( M, N, A, LDA, TAU, WORK, INFO ) implicit none integer :: INFO integer :: LDA integer :: M integer :: N double precision :: A( LDA, * ) double precision :: TAU( * ) double precision :: WORK( * ) end subroutine dgelq2 end interface interface subroutine dgelqf( M, N, A, LDA, TAU, WORK, LWORK, INFO ) implicit none integer :: INFO integer :: LDA integer :: LWORK integer :: M integer :: N double precision :: A( LDA, * ) double precision :: TAU( * ) double precision :: WORK( * ) end subroutine dgelqf end interface interface subroutine dgelss( M, N, NRHS, A, LDA, B, LDB, S, RCOND, RANK,& WORK, LWORK, INFO ) implicit none integer :: INFO integer :: LDA integer :: LDB integer :: LWORK integer :: M integer :: N integer :: NRHS integer :: RANK double precision :: A( LDA, * ) double precision :: B( LDB, * ) double precision :: RCOND double precision :: S( * ) double precision :: WORK( * ) end subroutine dgelss end interface interface subroutine dgeqr2( M, N, A, LDA, TAU, WORK, INFO ) implicit none integer :: INFO integer :: LDA integer :: M integer :: N double precision :: A( LDA, * ) double precision :: TAU( * ) double precision :: WORK( * ) end subroutine dgeqr2 end interface interface subroutine dgeqrf( M, N, A, LDA, TAU, WORK, LWORK, INFO ) implicit none integer :: INFO integer :: LDA integer :: LWORK integer :: M integer :: N double precision :: A( LDA, * ) double precision :: TAU( * ) double precision :: WORK( * ) end subroutine dgeqrf end interface interface subroutine dgesvd( JOBU, JOBVT, M, N, A, LDA, S, U, LDU, VT, LDVT,& WORK, LWORK, INFO ) implicit none integer :: INFO integer :: LDA integer :: LDU integer :: LDVT integer :: LWORK integer :: M integer :: N double precision :: A( LDA, * ) character :: JOBU character :: JOBVT double precision :: S( * ) double precision :: U( LDU, * ) double precision :: VT( LDVT, * ) double precision :: WORK( * ) end subroutine dgesvd end interface interface subroutine dgetf2( M, N, A, LDA, IPIV, INFO ) implicit none integer :: INFO integer :: IPIV( * ) integer :: LDA integer :: M integer :: N double precision :: A( LDA, * ) end subroutine dgetf2 end interface interface subroutine dgetrf( M, N, A, LDA, IPIV, INFO ) implicit none integer :: INFO integer :: IPIV( * ) integer :: LDA integer :: M integer :: N double precision :: A( LDA, * ) end subroutine dgetrf end interface interface subroutine dgetri( N, A, LDA, IPIV, WORK, LWORK, INFO ) implicit none integer :: INFO integer :: IPIV( * ) integer :: LDA integer :: LWORK integer :: N double precision :: A( LDA, * ) double precision :: WORK( * ) end subroutine dgetri end interface interface subroutine dopgtr( UPLO, N, AP, TAU, Q, LDQ, WORK, INFO ) implicit none integer :: INFO integer :: LDQ integer :: N double precision :: AP( * ) double precision :: Q( LDQ, * ) double precision :: TAU( * ) character :: UPLO double precision :: WORK( * ) end subroutine dopgtr end interface interface subroutine dorg2l( M, N, K, A, LDA, TAU, WORK, INFO ) implicit none integer :: INFO integer :: K integer :: LDA integer :: M integer :: N double precision :: A( LDA, * ) double precision :: TAU( * ) double precision :: WORK( * ) end subroutine dorg2l end interface interface subroutine dorg2r( M, N, K, A, LDA, TAU, WORK, INFO ) implicit none integer :: INFO integer :: K integer :: LDA integer :: M integer :: N double precision :: A( LDA, * ) double precision :: TAU( * ) double precision :: WORK( * ) end subroutine dorg2r end interface interface subroutine dorgbr( VECT, M, N, K, A, LDA, TAU, WORK, LWORK, INFO ) implicit none integer :: INFO integer :: K integer :: LDA integer :: LWORK integer :: M integer :: N double precision :: A( LDA, * ) double precision :: TAU( * ) character :: VECT double precision :: WORK( * ) end subroutine dorgbr end interface interface subroutine dorgl2( M, N, K, A, LDA, TAU, WORK, INFO ) implicit none integer :: INFO integer :: K integer :: LDA integer :: M integer :: N double precision :: A( LDA, * ) double precision :: TAU( * ) double precision :: WORK( * ) end subroutine dorgl2 end interface interface subroutine dorglq( M, N, K, A, LDA, TAU, WORK, LWORK, INFO ) implicit none integer :: INFO integer :: K integer :: LDA integer :: LWORK integer :: M integer :: N double precision :: A( LDA, * ) double precision :: TAU( * ) double precision :: WORK( * ) end subroutine dorglq end interface interface subroutine dorgql( M, N, K, A, LDA, TAU, WORK, LWORK, INFO ) implicit none integer :: INFO integer :: K integer :: LDA integer :: LWORK integer :: M integer :: N double precision :: A( LDA, * ) double precision :: TAU( * ) double precision :: WORK( * ) end subroutine dorgql end interface interface subroutine dorgqr( M, N, K, A, LDA, TAU, WORK, LWORK, INFO ) implicit none integer :: INFO integer :: K integer :: LDA integer :: LWORK integer :: M integer :: N double precision :: A( LDA, * ) double precision :: TAU( * ) double precision :: WORK( * ) end subroutine dorgqr end interface interface subroutine dorgtr( UPLO, N, A, LDA, TAU, WORK, LWORK, INFO ) implicit none integer :: INFO integer :: LDA integer :: LWORK integer :: N double precision :: A( LDA, * ) double precision :: TAU( * ) character :: UPLO double precision :: WORK( LWORK ) end subroutine dorgtr end interface interface subroutine dorm2r( SIDE, TRANS, M, N, K, A, LDA, TAU, C, LDC,& WORK, INFO ) implicit none integer :: INFO integer :: K integer :: LDA integer :: LDC integer :: M integer :: N double precision :: A( LDA, * ) double precision :: C( LDC, * ) character :: SIDE double precision :: TAU( * ) character :: TRANS double precision :: WORK( * ) end subroutine dorm2r end interface interface subroutine dormbr( VECT, SIDE, TRANS, M, N, K, A, LDA, TAU, C,& LDC, WORK, LWORK, INFO ) implicit none integer :: INFO integer :: K integer :: LDA integer :: LDC integer :: LWORK integer :: M integer :: N double precision :: A( LDA, * ) double precision :: C( LDC, * ) character :: SIDE double precision :: TAU( * ) character :: TRANS character :: VECT double precision :: WORK( * ) end subroutine dormbr end interface interface subroutine dorml2( SIDE, TRANS, M, N, K, A, LDA, TAU, C, LDC,& WORK, INFO ) implicit none integer :: INFO integer :: K integer :: LDA integer :: LDC integer :: M integer :: N double precision :: A( LDA, * ) double precision :: C( LDC, * ) character :: SIDE double precision :: TAU( * ) character :: TRANS double precision :: WORK( * ) end subroutine dorml2 end interface interface subroutine dormlq( SIDE, TRANS, M, N, K, A, LDA, TAU, C, LDC,& WORK, LWORK, INFO ) implicit none integer :: INFO integer :: K integer :: LDA integer :: LDC integer :: LWORK integer :: M integer :: N double precision :: A( LDA, * ) double precision :: C( LDC, * ) character :: SIDE double precision :: TAU( * ) character :: TRANS double precision :: WORK( * ) end subroutine dormlq end interface interface subroutine dormqr( SIDE, TRANS, M, N, K, A, LDA, TAU, C, LDC,& WORK, LWORK, INFO ) implicit none integer :: INFO integer :: K integer :: LDA integer :: LDC integer :: LWORK integer :: M integer :: N double precision :: A( LDA, * ) double precision :: C( LDC, * ) character :: SIDE double precision :: TAU( * ) character :: TRANS double precision :: WORK( * ) end subroutine dormqr end interface interface subroutine dposv( UPLO, N, NRHS, A, LDA, B, LDB, INFO ) implicit none integer :: INFO integer :: LDA integer :: LDB integer :: N integer :: NRHS double precision :: A( LDA, * ) double precision :: B( LDB, * ) character :: UPLO end subroutine dposv end interface interface subroutine dpotf2( UPLO, N, A, LDA, INFO ) implicit none integer :: INFO integer :: LDA integer :: N double precision :: A( LDA, * ) character :: UPLO end subroutine dpotf2 end interface interface subroutine dpotrf( UPLO, N, A, LDA, INFO ) implicit none integer :: INFO integer :: LDA integer :: N double precision :: A( LDA, * ) character :: UPLO end subroutine dpotrf end interface interface subroutine dpotrs( UPLO, N, NRHS, A, LDA, B, LDB, INFO ) implicit none integer :: INFO integer :: LDA integer :: LDB integer :: N integer :: NRHS double precision :: A( LDA, * ) double precision :: B( LDB, * ) character :: UPLO end subroutine dpotrs end interface interface subroutine dpptrf( UPLO, N, AP, INFO ) implicit none integer :: INFO integer :: N double precision :: AP( * ) character :: UPLO end subroutine dpptrf end interface interface subroutine dspgst( ITYPE, UPLO, N, AP, BP, INFO ) implicit none integer :: INFO integer :: ITYPE integer :: N double precision :: AP( * ) double precision :: BP( * ) character :: UPLO end subroutine dspgst end interface interface subroutine dspgv( ITYPE, JOBZ, UPLO, N, AP, BP, W, Z, LDZ, WORK,& INFO ) implicit none integer :: INFO integer :: ITYPE integer :: LDZ integer :: N double precision :: AP( * ) double precision :: BP( * ) double precision :: W( * ) double precision :: WORK( * ) double precision :: Z( LDZ, * ) character :: JOBZ character :: UPLO end subroutine dspgv end interface interface subroutine drscl( N, SA, SX, INCX ) implicit none integer :: INCX integer :: N double precision :: SA double precision :: SX( * ) end subroutine drscl end interface interface subroutine dspev( JOBZ, UPLO, N, AP, W, Z, LDZ, WORK, INFO ) implicit none integer :: INFO integer :: LDZ integer :: N double precision :: AP( * ) character :: JOBZ character :: UPLO double precision :: W( * ) double precision :: WORK( * ) double precision :: Z( LDZ, * ) end subroutine dspev end interface interface subroutine dsptrd( UPLO, N, AP, D, E, TAU, INFO ) implicit none integer :: INFO integer :: N double precision :: AP( * ) double precision :: D( * ) double precision :: E( * ) double precision :: TAU( * ) character :: UPLO end subroutine dsptrd end interface interface subroutine dstebz( RANGE, ORDER, N, VL, VU, IL, IU, ABSTOL, D, E,& M, NSPLIT, W, IBLOCK, ISPLIT, WORK, IWORK,& INFO ) implicit none integer :: IBLOCK( * ) integer :: IL integer :: INFO integer :: ISPLIT( * ) integer :: IU integer :: IWORK( * ) integer :: M integer :: N integer :: NSPLIT double precision :: ABSTOL double precision :: D( * ) double precision :: E( * ) character :: ORDER character :: RANGE double precision :: VL double precision :: VU double precision :: W( * ) double precision :: WORK( * ) end subroutine dstebz end interface interface subroutine dsteqr( COMPZ, N, D, E, Z, LDZ, WORK, INFO ) implicit none integer :: INFO integer :: LDZ integer :: N character :: COMPZ double precision :: D( * ) double precision :: E( * ) double precision :: WORK( * ) double precision :: Z( LDZ, * ) end subroutine dsteqr end interface interface subroutine dsterf( N, D, E, INFO ) implicit none integer :: INFO integer :: N double precision :: D( * ) double precision :: E( * ) end subroutine dsterf end interface interface subroutine dsyev( JOBZ, UPLO, N, A, LDA, W, WORK, LWORK, INFO ) implicit none integer :: INFO integer :: LDA integer :: LWORK integer :: N double precision :: A( LDA, * ) character :: JOBZ character :: UPLO double precision :: W( * ) double precision :: WORK( * ) end subroutine dsyev end interface interface subroutine dsygs2( ITYPE, UPLO, N, A, LDA, B, LDB, INFO ) implicit none integer :: INFO integer :: ITYPE integer :: LDA integer :: LDB integer :: N double precision :: A( LDA, * ) double precision :: B( LDB, * ) character :: UPLO end subroutine dsygs2 end interface interface subroutine dsygst( ITYPE, UPLO, N, A, LDA, B, LDB, INFO ) implicit none integer :: INFO integer :: ITYPE integer :: LDA integer :: LDB integer :: N double precision :: A( LDA, * ) double precision :: B( LDB, * ) character :: UPLO end subroutine dsygst end interface interface subroutine dsygv( ITYPE, JOBZ, UPLO, N, A, LDA, B, LDB, W, WORK,& LWORK, INFO ) implicit none integer :: INFO integer :: ITYPE integer :: LDA integer :: LDB integer :: LWORK integer :: N double precision :: A( LDA, * ) double precision :: B( LDB, * ) character :: JOBZ character :: UPLO double precision :: W( * ) double precision :: WORK( * ) end subroutine dsygv end interface interface subroutine dsysv( UPLO, N, NRHS, A, LDA, IPIV, B, LDB, WORK,& LWORK, INFO ) implicit none integer :: INFO integer :: IPIV( * ) integer :: LDA integer :: LDB integer :: LWORK integer :: N integer :: NRHS double precision :: A( LDA, * ) double precision :: B( LDB, * ) character :: UPLO double precision :: WORK( * ) end subroutine dsysv end interface interface subroutine dsytd2( UPLO, N, A, LDA, D, E, TAU, INFO ) implicit none integer :: INFO integer :: LDA integer :: N double precision :: A( LDA, * ) double precision :: D( * ) double precision :: E( * ) double precision :: TAU( * ) character :: UPLO end subroutine dsytd2 end interface interface subroutine dsytf2( UPLO, N, A, LDA, IPIV, INFO ) implicit none integer :: INFO integer :: IPIV( * ) integer :: LDA integer :: N double precision :: A( LDA, * ) character :: UPLO end subroutine dsytf2 end interface interface subroutine dsytrd( UPLO, N, A, LDA, D, E, TAU, WORK, LWORK, INFO ) implicit none integer :: INFO integer :: LDA integer :: LWORK integer :: N double precision :: A( LDA, * ) double precision :: D( * ) double precision :: E( * ) double precision :: TAU( * ) character :: UPLO double precision :: WORK( * ) end subroutine dsytrd end interface interface subroutine dsytrf( UPLO, N, A, LDA, IPIV, WORK, LWORK, INFO ) implicit none integer :: INFO integer :: IPIV( * ) integer :: LDA integer :: LWORK integer :: N double precision :: A( LDA, * ) character :: UPLO double precision :: WORK( * ) end subroutine dsytrf end interface interface subroutine dsytrs( UPLO, N, NRHS, A, LDA, IPIV, B, LDB, INFO ) implicit none integer :: INFO integer :: IPIV( * ) integer :: LDA integer :: LDB integer :: N integer :: NRHS double precision :: A( LDA, * ) double precision :: B( LDB, * ) character :: UPLO end subroutine dsytrs end interface interface subroutine dtrti2( UPLO, DIAG, N, A, LDA, INFO ) implicit none integer :: INFO integer :: LDA integer :: N double precision :: A( LDA, * ) character :: DIAG character :: UPLO end subroutine dtrti2 end interface interface subroutine dtrtri( UPLO, DIAG, N, A, LDA, INFO ) implicit none integer :: INFO integer :: LDA integer :: N double precision :: A( LDA, * ) character :: DIAG character :: UPLO end subroutine dtrtri end interface interface double precision function dzsum1( N, CX, INCX ) implicit none integer :: INCX integer :: N complex*16 :: CX( * ) end function dzsum1 end interface interface integer function izmax1( N, CX, INCX ) implicit none integer :: INCX integer :: N complex*16 :: CX( * ) end function izmax1 end interface interface subroutine ssterf( N, D, E, INFO ) implicit none integer :: INFO integer :: N real :: D( * ) real :: E( * ) end subroutine ssterf end interface interface subroutine zbdsqr( UPLO, N, NCVT, NRU, NCC, D, E, VT, LDVT, U,& LDU, C, LDC, RWORK, INFO ) implicit none integer :: INFO integer :: LDC integer :: LDU integer :: LDVT integer :: N integer :: NCC integer :: NCVT integer :: NRU complex*16 :: C( LDC, * ) double precision :: D( * ) double precision :: E( * ) double precision :: RWORK( * ) complex*16 :: U( LDU, * ) character :: UPLO complex*16 :: VT( LDVT, * ) end subroutine zbdsqr end interface interface subroutine zgebak( JOB, SIDE, N, ILO, IHI, SCALE, M, V, LDV,& INFO ) implicit none integer :: IHI integer :: ILO integer :: INFO integer :: LDV integer :: M integer :: N character :: JOB double precision :: SCALE( * ) character :: SIDE complex*16 :: V( LDV, * ) end subroutine zgebak end interface interface subroutine zgebal( JOB, N, A, LDA, ILO, IHI, SCALE, INFO ) implicit none integer :: IHI integer :: ILO integer :: INFO integer :: LDA integer :: N complex*16 :: A( LDA, * ) character :: JOB double precision :: SCALE( * ) end subroutine zgebal end interface interface subroutine zgebd2( M, N, A, LDA, D, E, TAUQ, TAUP, WORK, INFO ) implicit none integer :: INFO integer :: LDA integer :: M integer :: N complex*16 :: A( LDA, * ) double precision :: D( * ) double precision :: E( * ) complex*16 :: TAUP( * ) complex*16 :: TAUQ( * ) complex*16 :: WORK( * ) end subroutine zgebd2 end interface interface subroutine zgebrd( M, N, A, LDA, D, E, TAUQ, TAUP, WORK, LWORK,& INFO ) implicit none integer :: INFO integer :: LDA integer :: LWORK integer :: M integer :: N complex*16 :: A( LDA, * ) double precision :: D( * ) double precision :: E( * ) complex*16 :: TAUP( * ) complex*16 :: TAUQ( * ) complex*16 :: WORK( * ) end subroutine zgebrd end interface interface subroutine zgees( JOBVS, SORT, SELECT, N, A, LDA, SDIM, W, VS,& LDVS, WORK, LWORK, RWORK, BWORK, INFO ) implicit none integer :: INFO integer :: LDA integer :: LDVS integer :: LWORK integer :: N integer :: SDIM complex*16 :: A( LDA, * ) logical :: BWORK( * ) character :: JOBVS double precision :: RWORK( * ) logical :: SELECT character :: SORT complex*16 :: VS( LDVS, * ) complex*16 :: W( * ) complex*16 :: WORK( * ) end subroutine zgees end interface interface subroutine zgeev( JOBVL, JOBVR, N, A, LDA, W, VL, LDVL, VR, LDVR,& WORK, LWORK, RWORK, INFO ) implicit none character :: JOBVL character :: JOBVR integer :: INFO integer :: LDA integer :: LDVL integer :: LDVR integer :: LWORK integer :: N double precision :: RWORK( * ) complex*16 :: A( LDA, * ) complex*16 :: VL( LDVL, * ) complex*16 :: VR( LDVR, * ) complex*16 :: W( * ) complex*16 :: WORK( * ) end subroutine zgeev end interface interface subroutine zgehd2( N, ILO, IHI, A, LDA, TAU, WORK, INFO ) implicit none integer :: IHI integer :: ILO integer :: INFO integer :: LDA integer :: N complex*16 :: A( LDA, * ) complex*16 :: TAU( * ) complex*16 :: WORK( * ) end subroutine zgehd2 end interface interface subroutine zgehrd( N, ILO, IHI, A, LDA, TAU, WORK, LWORK, INFO ) implicit none integer :: IHI integer :: ILO integer :: INFO integer :: LDA integer :: LWORK integer :: N complex*16 :: A( LDA, * ) complex*16 :: TAU( * ) complex*16 :: WORK( LWORK ) end subroutine zgehrd end interface interface subroutine zgelq2( M, N, A, LDA, TAU, WORK, INFO ) implicit none integer :: INFO integer :: LDA integer :: M integer :: N complex*16 :: A( LDA, * ) complex*16 :: TAU( * ) complex*16 :: WORK( * ) end subroutine zgelq2 end interface interface subroutine zgelqf( M, N, A, LDA, TAU, WORK, LWORK, INFO ) implicit none integer :: INFO integer :: LDA integer :: LWORK integer :: M integer :: N complex*16 :: A( LDA, * ) complex*16 :: TAU( * ) complex*16 :: WORK( * ) end subroutine zgelqf end interface interface subroutine zgeqr2( M, N, A, LDA, TAU, WORK, INFO ) implicit none integer :: INFO integer :: LDA integer :: M integer :: N complex*16 :: A( LDA, * ) complex*16 :: TAU( * ) complex*16 :: WORK( * ) end subroutine zgeqr2 end interface interface subroutine zgeqrf( M, N, A, LDA, TAU, WORK, LWORK, INFO ) implicit none integer :: INFO integer :: LDA integer :: LWORK integer :: M integer :: N complex*16 :: A( LDA, * ) complex*16 :: TAU( * ) complex*16 :: WORK( * ) end subroutine zgeqrf end interface !interface ! subroutine zgesv( N, NRHS, A, LDA, IPIV, B, LDB, INFO ) ! implicit none ! integer :: INFO ! integer :: IPIV( * ) ! integer :: LDA ! integer :: LDB ! integer :: N ! integer :: NRHS ! complex*16 :: A( LDA, * ) ! complex*16 :: B( LDB, * ) ! end subroutine zgesv !end interface interface subroutine zgesvd( JOBU, JOBVT, M, N, A, LDA, S, U, LDU, VT, LDVT,& WORK, LWORK, RWORK, INFO ) implicit none integer :: INFO integer :: LDA integer :: LDU integer :: LDVT integer :: LWORK integer :: M integer :: N complex*16 :: A( LDA, * ) character :: JOBU character :: JOBVT double precision :: RWORK( * ) double precision :: S( * ) complex*16 :: U( LDU, * ) complex*16 :: VT( LDVT, * ) complex*16 :: WORK( * ) end subroutine zgesvd end interface interface subroutine zgetf2( M, N, A, LDA, IPIV, INFO ) implicit none integer :: INFO integer :: IPIV( * ) integer :: LDA integer :: M integer :: N complex*16 :: A( LDA, * ) end subroutine zgetf2 end interface interface subroutine zgetri( N, A, LDA, IPIV, WORK, LWORK, INFO ) implicit none integer :: INFO integer :: LDA integer :: LWORK integer :: N integer :: IPIV( * ) complex*16 :: A( LDA, * ) complex*16 :: WORK( * ) end subroutine zgetri end interface !interface ! subroutine zgetrf( M, N, A, LDA, IPIV, INFO ) ! implicit none ! integer :: INFO ! integer :: IPIV( * ) ! integer :: LDA ! integer :: M ! integer :: N ! complex*16 :: A( LDA, * ) ! end subroutine zgetrf !end interface interface subroutine zgetrs( TRANS, N, NRHS, A, LDA, IPIV, B, LDB, INFO ) implicit none integer :: INFO integer :: IPIV( * ) integer :: LDA integer :: LDB integer :: N integer :: NRHS complex*16 :: A( LDA, * ) complex*16 :: B( LDB, * ) character :: TRANS end subroutine zgetrs end interface !interface ! subroutine zheev( JOBZ, UPLO, N, A, LDA, W, WORK, LWORK, RWORK, INFO ) ! implicit none ! integer :: INFO ! integer :: LDA ! integer :: LWORK ! integer :: N ! complex*16 :: A( LDA, * ) ! character :: JOBZ ! double precision :: RWORK( * ) ! character :: UPLO ! double precision :: W( * ) ! complex*16 :: WORK( * ) ! end subroutine zheev !end interface interface subroutine zhegs2( ITYPE, UPLO, N, A, LDA, B, LDB, INFO ) implicit none integer :: INFO integer :: ITYPE integer :: LDA integer :: LDB integer :: N complex*16 :: A( LDA, * ) complex*16 :: B( LDB, * ) character :: UPLO end subroutine zhegs2 end interface !interface ! subroutine zhegst( ITYPE, UPLO, N, A, LDA, B, LDB, INFO ) ! implicit none ! integer :: INFO ! integer :: ITYPE ! integer :: LDA ! integer :: LDB ! integer :: N ! complex*16 :: A( LDA, * ) ! complex*16 :: B( LDB, * ) ! character :: UPLO ! end subroutine zhegst !end interface !interface ! subroutine zhegv( ITYPE, JOBZ, UPLO, N, A, LDA, B, LDB, W, WORK,& ! LWORK, RWORK, INFO ) ! implicit none ! integer :: INFO ! integer :: ITYPE ! integer :: LDA ! integer :: LDB ! integer :: LWORK ! integer :: N ! complex*16 :: A( LDA, * ) ! complex*16 :: B( LDB, * ) ! character :: JOBZ ! double precision :: RWORK( * ) ! character :: UPLO ! double precision :: W( * ) ! complex*16 :: WORK( * ) ! end subroutine zhegv !end interface interface subroutine zhetd2( UPLO, N, A, LDA, D, E, TAU, INFO ) implicit none integer :: INFO integer :: LDA integer :: N complex*16 :: A( LDA, * ) double precision :: D( * ) double precision :: E( * ) complex*16 :: TAU( * ) character :: UPLO end subroutine zhetd2 end interface interface subroutine zhetrd( UPLO, N, A, LDA, D, E, TAU, WORK, LWORK, INFO ) implicit none integer :: INFO integer :: LDA integer :: LWORK integer :: N complex*16 :: A( LDA, * ) double precision :: D( * ) double precision :: E( * ) complex*16 :: TAU( * ) character :: UPLO complex*16 :: WORK( * ) end subroutine zhetrd end interface !interface ! subroutine zhpev( JOBZ, UPLO, N, AP, W, Z, LDZ, WORK, RWORK, INFO ) ! implicit none ! integer :: INFO ! integer :: LDZ ! integer :: N ! complex*16 :: AP( * ) ! character :: JOBZ ! double precision :: RWORK( * ) ! character :: UPLO ! double precision :: W( * ) ! complex*16 :: WORK( * ) ! complex*16 :: Z( LDZ, * ) ! end subroutine zhpev !end interface !interface ! subroutine zhpevx( JOBZ, RANGE, UPLO, N, AP, VL, VU, IL, IU,& ! ABSTOL, M, W, Z, LDZ, WORK, RWORK, IWORK,& ! IFAIL, INFO ) ! implicit none ! integer :: IFAIL( * ) ! integer :: IL ! integer :: INFO ! integer :: IU ! integer :: IWORK( * ) ! integer :: LDZ ! integer :: M ! integer :: N ! double precision :: ABSTOL ! complex*16 :: AP( * ) ! character :: JOBZ ! character :: RANGE ! double precision :: RWORK( * ) ! character :: UPLO ! double precision :: VL ! double precision :: VU ! double precision :: W( * ) ! complex*16 :: WORK( * ) ! complex*16 :: Z( LDZ, * ) ! end subroutine zhpevx !end interface interface subroutine zhpgst( ITYPE, UPLO, N, AP, BP, INFO ) implicit none integer :: INFO integer :: ITYPE integer :: N complex*16 :: AP( * ) complex*16 :: BP( * ) character :: UPLO end subroutine zhpgst end interface !interface ! subroutine zhpgv( ITYPE, JOBZ, UPLO, N, AP, BP, W, Z, LDZ, WORK,& ! RWORK, INFO ) ! implicit none ! integer :: INFO ! integer :: ITYPE ! integer :: LDZ ! integer :: N ! complex*16 :: AP( * ) ! complex*16 :: BP( * ) ! character :: JOBZ ! double precision :: RWORK( * ) ! character :: UPLO ! double precision :: W( * ) ! complex*16 :: WORK( * ) ! complex*16 :: Z( LDZ, * ) ! end subroutine zhpgv !end interface interface subroutine zhptrd( UPLO, N, AP, D, E, TAU, INFO ) implicit none integer :: INFO integer :: N complex*16 :: AP( * ) double precision :: D( * ) double precision :: E( * ) complex*16 :: TAU( * ) character :: UPLO end subroutine zhptrd end interface interface subroutine zhseqr( JOB, COMPZ, N, ILO, IHI, H, LDH, W, Z, LDZ,& WORK, LWORK, INFO ) implicit none integer :: IHI integer :: ILO integer :: INFO integer :: LDH integer :: LDZ integer :: LWORK integer :: N character :: COMPZ complex*16 :: H( LDH, * ) character :: JOB complex*16 :: W( * ) complex*16 :: WORK( * ) complex*16 :: Z( LDZ, * ) end subroutine zhseqr end interface interface subroutine zlabrd( M, N, NB, A, LDA, D, E, TAUQ, TAUP, X, LDX, Y,& LDY ) implicit none integer :: LDA integer :: LDX integer :: LDY integer :: M integer :: N integer :: NB complex*16 :: A( LDA, * ) double precision :: D( * ) double precision :: E( * ) complex*16 :: TAUP( * ) complex*16 :: TAUQ( * ) complex*16 :: X( LDX, * ) complex*16 :: Y( LDY, * ) end subroutine zlabrd end interface interface subroutine zlacgv( N, X, INCX ) implicit none integer :: INCX integer :: N complex*16 :: X( * ) end subroutine zlacgv end interface interface subroutine zlacon( N, V, X, EST, KASE ) implicit none integer :: KASE integer :: N double precision :: EST complex*16 :: V( N ) complex*16 :: X( N ) end subroutine zlacon end interface interface subroutine zlacpy( UPLO, M, N, A, LDA, B, LDB ) implicit none integer :: LDA integer :: LDB integer :: M integer :: N complex*16 :: A( LDA, * ) complex*16 :: B( LDB, * ) character :: UPLO end subroutine zlacpy end interface interface double complex function zladiv( X, Y ) implicit none complex*16 :: X complex*16 :: Y end function zladiv end interface interface subroutine zlahqr( WANTT, WANTZ, N, ILO, IHI, H, LDH, W, ILOZ,& IHIZ, Z, LDZ, INFO ) implicit none integer :: IHI integer :: IHIZ integer :: ILO integer :: ILOZ integer :: INFO integer :: LDH integer :: LDZ integer :: N complex*16 :: H( LDH, * ) complex*16 :: W( * ) logical :: WANTT logical :: WANTZ complex*16 :: Z( LDZ, * ) end subroutine zlahqr end interface interface subroutine zlahrd( N, K, NB, A, LDA, TAU, T, LDT, Y, LDY ) implicit none integer :: K integer :: LDA integer :: LDT integer :: LDY integer :: N integer :: NB complex*16 :: A( LDA, * ) complex*16 :: T( LDT, NB ) complex*16 :: TAU( NB ) complex*16 :: Y( LDY, NB ) end subroutine zlahrd end interface interface subroutine zlahr2( N, K, NB, A, LDA, TAU, T, LDT, Y, LDY ) implicit none integer :: K integer :: LDA integer :: LDT integer :: LDY integer :: N integer :: NB complex*16 :: A( LDA, * ) complex*16 :: T( LDT, NB ) complex*16 :: TAU( NB ) complex*16 :: Y( LDY, NB ) end subroutine zlahr2 end interface interface double precision function zlange( NORM, M, N, A, LDA, WORK ) implicit none integer :: LDA integer :: M integer :: N complex*16 :: A( LDA, * ) character :: NORM double precision :: WORK( * ) end function zlange end interface interface double precision function zlanhe( NORM, UPLO, N, A, LDA, WORK ) implicit none integer :: LDA integer :: N complex*16 :: A( LDA, * ) character :: NORM character :: UPLO double precision :: WORK( * ) end function zlanhe end interface interface double precision function zlanhp( NORM, UPLO, N, AP, WORK ) implicit none integer :: N complex*16 :: AP( * ) character :: NORM character :: UPLO double precision :: WORK( * ) end function zlanhp end interface interface double precision function zlanhs( NORM, N, A, LDA, WORK ) implicit none integer :: LDA integer :: N complex*16 :: A( LDA, * ) character :: NORM double precision :: WORK( * ) end function zlanhs end interface interface subroutine zlaqr0( WANTT, WANTZ, N, ILO, IHI, H, LDH, W, ILOZ,& IHIZ, Z, LDZ, WORK, LWORK, INFO ) implicit none integer :: IHI integer :: IHIZ integer :: ILO integer :: ILOZ integer :: INFO integer :: LDH integer :: LDZ integer :: LWORK integer :: N complex*16 :: H( LDH, * ) complex*16 :: W( * ) complex*16 :: WORK( * ) complex*16 :: Z( LDZ, * ) logical :: WANTT logical :: WANTZ end subroutine zlaqr0 end interface interface subroutine zlaqr1( N, H, LDH, S1, S2, V ) implicit none integer :: LDH integer :: N complex*16 :: S1 complex*16 :: S2 complex*16 :: H( LDH, * ) complex*16 :: V( * ) end subroutine zlaqr1 end interface interface subroutine zlaqr2( WANTT, WANTZ, N, KTOP, KBOT, NW, H, LDH, ILOZ,& IHIZ, Z, LDZ, NS, ND, SH, V, LDV, NH, T, LDT,& NV, WV, LDWV, WORK, LWORK ) implicit none integer :: IHIZ, ILOZ, KBOT, KTOP, LDH, LDT integer :: LDV, LDWV, LDZ, LWORK, N, ND, NH integer :: NS, NV, NW logical :: WANTT, WANTZ complex*16 :: H( LDH, * ), SH( * ), T( LDT, * ) complex*16 :: V( LDV, * ),WORK( * ), WV( LDWV, * ), Z( LDZ, * ) end subroutine zlaqr2 end interface interface subroutine zlaqr3( WANTT, WANTZ, N, KTOP, KBOT, NW, H, LDH, ILOZ,& IHIZ, Z, LDZ, NS, ND, SH, V, LDV, NH, T, LDT,& NV, WV, LDWV, WORK, LWORK ) implicit none integer :: IHIZ, ILOZ, KBOT, KTOP, LDH, LDT, LDV, LDWV integer :: LDZ, LWORK, N, ND, NH, NS, NV, NW logical :: WANTT, WANTZ complex*16 :: H( LDH, * ), SH( * ), T( LDT, * ) complex*16 :: V( LDV, * ),WORK( * ), WV( LDWV, * ), Z( LDZ, * ) end subroutine zlaqr3 end interface interface subroutine zlaqr4( WANTT, WANTZ, N, ILO, IHI, H, LDH, W, ILOZ,& IHIZ, Z, LDZ, WORK, LWORK, INFO ) implicit none integer :: IHI, IHIZ, ILO, ILOZ, INFO, LDH, LDZ, LWORK, N logical :: WANTT, WANTZ complex*16 :: H( LDH, * ), W( * ), WORK( * ), Z( LDZ, * ) end subroutine zlaqr4 end interface interface subroutine zlaqr5( WANTT, WANTZ, KACC22, N, KTOP, KBOT, NSHFTS, S,& H, LDH, ILOZ, IHIZ, Z, LDZ, V, LDV, U, LDU, NV,& WV, LDWV, NH, WH, LDWH ) implicit none integer :: IHIZ, ILOZ, KACC22, KBOT, KTOP, LDH, LDU, LDV integer :: LDWH, LDWV, LDZ, N, NH, NSHFTS, NV logical :: WANTT, WANTZ complex*16 :: H( LDH, * ), S( * ), U( LDU, * ), V( LDV, * ) complex*16 :: WH( LDWH, * ), WV( LDWV, * ), Z( LDZ, * ) end subroutine zlaqr5 end interface interface subroutine zlarf( SIDE, M, N, V, INCV, TAU, C, LDC, WORK ) implicit none integer :: INCV integer :: LDC integer :: M integer :: N complex*16 :: C( LDC, * ) character :: SIDE complex*16 :: TAU complex*16 :: V( * ) complex*16 :: WORK( * ) end subroutine zlarf end interface interface subroutine zlarfb( SIDE, TRANS, DIRECT, STOREV, M, N, K, V, LDV,& T, LDT, C, LDC, WORK, LDWORK ) implicit none integer :: K integer :: LDC integer :: LDT integer :: LDV integer :: LDWORK integer :: M integer :: N complex*16 :: C( LDC, * ) character :: DIRECT character :: SIDE character :: STOREV complex*16 :: T( LDT, * ) character :: TRANS complex*16 :: V( LDV, * ) complex*16 :: WORK( LDWORK, * ) end subroutine zlarfb end interface interface subroutine zlarfg( N, ALPHA, X, INCX, TAU ) implicit none integer :: INCX integer :: N complex*16 :: ALPHA complex*16 :: TAU complex*16 :: X( * ) end subroutine zlarfg end interface interface subroutine zlarft( DIRECT, STOREV, N, K, V, LDV, TAU, T, LDT ) implicit none integer :: K integer :: LDT integer :: LDV integer :: N character :: DIRECT character :: STOREV complex*16 :: T( LDT, * ) complex*16 :: TAU( * ) complex*16 :: V( LDV, * ) end subroutine zlarft end interface interface subroutine zlarfx( SIDE, M, N, V, TAU, C, LDC, WORK ) implicit none integer :: LDC integer :: M integer :: N complex*16 :: C( LDC, * ) character :: SIDE complex*16 :: TAU complex*16 :: V( * ) complex*16 :: WORK( * ) end subroutine zlarfx end interface interface subroutine zlartg( F, G, CS, SN, R ) implicit none double precision :: CS complex*16 :: F complex*16 :: G complex*16 :: R complex*16 :: SN end subroutine zlartg end interface interface subroutine zlascl( TYPE, KL, KU, CFROM, CTO, M, N, A, LDA, INFO ) implicit none integer :: INFO integer :: KL integer :: KU integer :: LDA integer :: M integer :: N complex*16 :: A( LDA, * ) double precision :: CFROM double precision :: CTO character :: TYPE end subroutine zlascl end interface interface subroutine zlaset( UPLO, M, N, ALPHA, BETA, A, LDA ) implicit none integer :: LDA integer :: M integer :: N complex*16 :: A( LDA, * ) complex*16 :: ALPHA complex*16 :: BETA character :: UPLO end subroutine zlaset end interface interface subroutine zlasr( SIDE, PIVOT, DIRECT, M, N, C, S, A, LDA ) implicit none integer :: LDA integer :: M integer :: N complex*16 :: A( LDA, * ) double precision :: C( * ) character :: DIRECT character :: PIVOT double precision :: S( * ) character :: SIDE end subroutine zlasr end interface interface subroutine zlassq( N, X, INCX, SCALE, SUMSQ ) implicit none integer :: INCX integer :: N double precision :: SCALE double precision :: SUMSQ complex*16 :: X( * ) end subroutine zlassq end interface interface subroutine zlaswp( N, A, LDA, K1, K2, IPIV, INCX ) implicit none integer :: INCX integer :: IPIV( * ) integer :: K1 integer :: K2 integer :: LDA integer :: N complex*16 :: A( LDA, * ) end subroutine zlaswp end interface interface subroutine zlatrd( UPLO, N, NB, A, LDA, E, TAU, W, LDW ) implicit none integer :: LDA integer :: LDW integer :: N integer :: NB complex*16 :: A( LDA, * ) double precision :: E( * ) complex*16 :: TAU( * ) character :: UPLO complex*16 :: W( LDW, * ) end subroutine zlatrd end interface interface subroutine zlatrs( UPLO, TRANS, DIAG, NORMIN, N, A, LDA, X, SCALE,& CNORM, INFO ) implicit none character :: DIAG, NORMIN, TRANS, UPLO integer :: INFO, LDA, N double precision :: SCALE double precision :: CNORM( * ) complex*16 :: A( LDA, * ), X( * ) end subroutine zlatrs end interface interface subroutine zlazro( M, N, ALPHA, BETA, A, LDA ) implicit none integer :: LDA integer :: M integer :: N complex*16 :: A( LDA, * ) complex*16 :: ALPHA complex*16 :: BETA end subroutine zlazro end interface interface subroutine zpotf2( UPLO, N, A, LDA, INFO ) implicit none integer :: INFO integer :: LDA integer :: N complex*16 :: A( LDA, * ) character :: UPLO end subroutine zpotf2 end interface !interface ! subroutine zpotrf( UPLO, N, A, LDA, INFO ) ! implicit none ! integer :: INFO ! integer :: LDA ! integer :: N ! complex*16 :: A( LDA, * ) ! character :: UPLO ! end subroutine zpotrf !end interface interface subroutine zpptrf( UPLO, N, AP, INFO ) implicit none integer :: INFO integer :: N complex*16 :: AP( * ) character :: UPLO end subroutine zpptrf end interface interface subroutine zrot( N, CX, INCX, CY, INCY, C, S ) implicit none integer :: INCX integer :: INCY integer :: N double precision :: C complex*16 :: CX( * ) complex*16 :: CY( * ) complex*16 :: S end subroutine zrot end interface interface subroutine ztrevc( SIDE, HOWMNY, SELECT, N, T, LDT, VL, LDVL, VR,& LDVR, MM, M, WORK, RWORK, INFO ) implicit none character :: HOWMNY, SIDE integer :: INFO, LDT, LDVL, LDVR, M, MM, N logical :: SELECT( * ) double precision :: RWORK( * ) complex*16 :: T( LDT, * ), VL( LDVL, * ), VR( LDVR, * ) complex*16 :: WORK( * ) end subroutine ztrevc end interface interface subroutine ztrexc( COMPQ, N, T, LDT, Q, LDQ, IFST, ILST, INFO ) implicit none integer :: IFST integer :: ILST integer :: INFO integer :: LDQ integer :: LDT integer :: N character :: COMPQ complex*16 :: Q( LDQ, * ) complex*16 :: T( LDT, * ) end subroutine ztrexc end interface interface subroutine ztrsen( JOB, COMPQ, SELECT, N, T, LDT, Q, LDQ, W, M, S,& SEP, WORK, LWORK, INFO ) implicit none integer :: INFO integer :: LDQ integer :: LDT integer :: LWORK integer :: M integer :: N character :: COMPQ character :: JOB complex*16 :: Q( LDQ, * ) double precision :: S logical :: SELECT( * ) double precision :: SEP complex*16 :: T( LDT, * ) complex*16 :: W( * ) complex*16 :: WORK( * ) end subroutine ztrsen end interface interface subroutine ztrsyl( TRANA, TRANB, ISGN, M, N, A, LDA, B, LDB, C,& LDC, SCALE, INFO ) implicit none integer :: INFO integer :: ISGN integer :: LDA integer :: LDB integer :: LDC integer :: M integer :: N complex*16 :: A( LDA, * ) complex*16 :: B( LDB, * ) complex*16 :: C( LDC, * ) double precision :: SCALE character :: TRANA character :: TRANB end subroutine ztrsyl end interface interface subroutine ztrti2( UPLO, DIAG, N, A, LDA, INFO ) implicit none character :: DIAG character :: UPLO integer :: INFO integer :: LDA integer :: N complex*16 :: A( LDA, * ) end subroutine ztrti2 end interface interface subroutine ztrtri( UPLO, DIAG, N, A, LDA, INFO ) implicit none character :: DIAG character :: UPLO integer :: INFO integer :: LDA integer :: N complex*16 :: A( LDA, * ) end subroutine ztrtri end interface interface subroutine zungqr( M, N, K, A, LDA, TAU, WORK, LWORK, INFO ) implicit none integer :: INFO, K, LDA, LWORK, M, N complex*16 :: A( LDA, * ), TAU( * ), WORK( * ) end subroutine zungqr end interface end module m_linalg_interfaces !!*** v_sim-3.8.0/lib/plug-ins/abinit/m_numeric_tools.F90000066400000000000000000003660221370110300500220660ustar00rootroot00000000000000!{\src2tex{textfont=tt}} !!****m* ABINIT/m_numeric_tools !! NAME !! m_numeric_tools !! !! FUNCTION !! This module contains basic tools for numeric computations. !! !! COPYRIGHT !! Copyright (C) 2008-2016 ABINIT group (MG, GMR, MJV, XG, MVeithen) !! This file is distributed under the terms of the !! GNU General Public License, see ~abinit/COPYING !! or http://www.gnu.org/copyleft/gpl.txt . !! !! PARENTS !! !! CHILDREN !! !! SOURCE #if defined HAVE_CONFIG_H #include "config.h" #endif #include "abi_common.h" MODULE m_numeric_tools use defs_basis use m_errors use m_profiling_abi use m_linalg_interfaces implicit none private public :: arth ! Return an arithmetic progression public :: geop ! Return a geometric progression public :: reverse ! Reverse a 1D array *IN PLACE* public :: set2unit ! Set the matrix to be a unit matrix (if it is square) public :: get_trace ! Calculate the trace of a square matrix public :: get_diag ! Return the diagonal of a matrix as a vector public :: isdiagmat ! True if matrix is diagonal public :: r2c,c2r ! Transfer complex data stored in a real array to a complex array and vice versa public :: iseven ! Return .TRUE. if int is even public :: isinteger ! Return .TRUE. if all elements of rr differ from an integer by less than tol public :: is_zero ! Return .TRUE. if all elements of rr differ from zero by less than tol public :: bisect ! Given a monotonic array A and x find j such that A(j)>x>A(j+1) using bisection public :: imax_loc ! Index of maxloc on an array returned as scalar instead of array-valued quantity public :: imin_loc ! Index of minloc on an array returned as scalar instead of array-valued quantity public :: lfind ! Find the index of the first occurrence of .True. in a logical array. public :: list2blocks ! Given a list of integers, find the number of contiguos groups of values. public :: mask2blocks ! Find groups of .TRUE. elements in a logical mask. public :: linfit ! Perform a linear fit, y=ax+b, of data public :: llsfit_svd ! Linear least squares fit with SVD of an user-defined set of functions public :: polyn_interp ! Polynomial interpolation with Nevilles"s algorithms, error estimate is reported public :: quadrature ! Driver routine for performing quadratures in finite domains using different algorithms public :: simpson_cplx ! Integrate a complex function via extended Simpson's rule. public :: hermitianize ! Force a square matrix to be hermitian public :: mkherm ! Make the complex array(2,ndim,ndim) hermitian, by adding half of it to its hermitian conjugate. public :: symmetrize ! Force a square matrix to be symmetric public :: print_arr ! Print a vector/array public :: pade,dpade ! Functions for Pade approximation (complex case) public :: newrap_step ! Apply single step Newton-Raphson method to find root of a complex function public :: OPERATOR(.x.) ! Cross product of two 3D vectors public :: l2norm ! Return the length (ordinary L2 norm) of a vector public :: remove_copies ! Find the subset of inequivalent items in a list. public :: denominator ! Return the denominator of a rational number. public :: mincm ! Return the minimum common multiple of two integers. public :: continued_fract ! Routine to calculate the continued fraction (see description). public :: cmplx_sphcart ! Convert an array of cplx numbers from spherical to Cartesian coordinates or vice versa. public :: pfactorize ! Factorize a number in terms of an user-specified set of prime factors. public :: isordered ! Check the ordering of a sequence. public :: wrap2_zero_one ! Transforms a real number in a reduced number in the interval [0,1[ where 1 is not included (tol12) public :: wrap2_pmhalf ! Transforms a real number in areduced number in the interval ]-1/2,1/2] where -1/2 is not included (tol12) public :: interpol3d ! Linear interpolation in 3D public :: interpol3d_indices ! Computes the indices in a cube which are neighbors to the point to be ! interpolated in interpol3d public :: simpson_int ! Simpson integral of a tabulated function. Returns arrays with integrated values public :: simpson ! Simpson integral of a tabulated function. Returns scalar with the integral on the full mesh. public :: rhophi ! Compute the phase and the module of a complex number. interface arth module procedure arth_int module procedure arth_rdp end interface arth interface reverse module procedure arth_int module procedure arth_rdp end interface reverse interface set2unit module procedure unit_matrix_int module procedure unit_matrix_rdp module procedure unit_matrix_cdp end interface set2unit interface get_trace module procedure get_trace_int module procedure get_trace_rdp module procedure get_trace_cdp end interface get_trace interface get_diag module procedure get_diag_rdp module procedure get_diag_cdp end interface get_diag interface isdiagmat module procedure isdiagmat_int module procedure isdiagmat_rdp !module procedure isdiagmat_cdp end interface isdiagmat interface r2c module procedure rdp2cdp_1D module procedure rdp2cdp_2D module procedure rdp2cdp_3D module procedure rdp2cdp_4D module procedure rdp2cdp_5D module procedure rdp2cdp_6D end interface r2c interface c2r module procedure cdp2rdp_1D module procedure cdp2rdp_2D module procedure cdp2rdp_3D module procedure cdp2rdp_4D module procedure cdp2rdp_5D end interface c2r interface isinteger module procedure is_integer_0d module procedure is_integer_1d end interface isinteger interface is_zero module procedure is_zero_rdp_0d module procedure is_zero_rdp_1d end interface is_zero interface bisect module procedure bisect_rdp module procedure bisect_int end interface bisect interface imax_loc module procedure imax_loc_int module procedure imax_loc_rdp end interface imax_loc interface imin_loc module procedure imin_loc_int module procedure imin_loc_rdp end interface imin_loc interface linfit module procedure linfit_rdp module procedure linfit_spc module procedure linfit_dpc end interface linfit interface hermitianize module procedure hermitianize_spc module procedure hermitianize_dpc end interface hermitianize interface symmetrize module procedure symmetrize_spc module procedure symmetrize_dpc end interface symmetrize interface print_arr !TODO add prtm module procedure print_arr1d_spc module procedure print_arr1d_dpc module procedure print_arr2d_spc module procedure print_arr2d_dpc end interface print_arr interface operator (.x.) module procedure cross_product_int module procedure cross_product_rdp end interface interface l2norm module procedure l2norm_rdp end interface l2norm interface isordered module procedure isordered_rdp end interface isordered !!*** !---------------------------------------------------------------------- !!****t* m_numeric_tools/stats_t !! NAME !! stats_t !! !! FUNCTION !! Statistical parameters of a data distribution. !! !! SOURCE type,public :: stats_t real(dp) :: mean real(dp) :: stdev real(dp) :: min real(dp) :: max end type stats_t public :: stats_eval ! Calculate the statistical parameters of a data distribution. !!*** !---------------------------------------------------------------------- !!****t* m_numeric_tools/vdiff_t !! NAME !! vdiff_t !! !! FUNCTION !! Estimate the "distance" between two functions tabulated on a homogeneous grid. !! Use `vidff` function to construct the object. !! !! SOURCE type,public :: vdiff_t real(dp) :: int_adiff ! \int |f1-f2| dr real(dp) :: mean_adiff ! Mean {|f1-f2|} real(dp) :: stdev_adiff ! Standard deviation of {|f1-f2|} real(dp) :: min_adiff ! Min {|f1-f2|} real(dp) :: max_adiff ! Max {|f1-f2|} real(dp) :: l1_rerr ! (\int |f1-f2| dr) / (\int |f2| dr) end type vdiff_t public :: vdiff_eval ! Estimate the "distance" between two functions tabulated on a homogeneous grid. public :: vdiff_print ! Print vdiff_t to formatted file. !!*** CONTAINS !=========================================================== !!*** !!****f* m_numeric_tools/arth_int !! NAME !! arth_int !! !! FUNCTION !! Returns an array of length nn containing an arithmetic progression whose !! starting value is start and whose step is step. !! !! INPUTS !! start=initial point !! step=the increment !! nn=the number of points !! !! OUTPUT !! arth(nn)=the progression !! !! SOURCE pure function arth_int(start,step,nn) !This section has been created automatically by the script Abilint (TD). !Do not modify the following lines by hand. #undef ABI_FUNC #define ABI_FUNC 'arth_int' !End of the abilint section implicit none !Arguments ------------------------------------ !scalars integer,intent(in) :: nn integer,intent(in) :: start,step integer :: arth_int(nn) !Local variables------------------------------- integer :: ii ! ********************************************************************* select case (nn) case (1:) arth_int(1)=start do ii=2,nn arth_int(ii)=arth_int(ii-1)+step end do case (0) RETURN end select end function arth_int !!*** !---------------------------------------------------------------------- !!****f* m_numeric_tools/arth_rdp !! NAME !! arth_rdp !! !! FUNCTION !! !! INPUTS !! !! OUTPUT !! !! SOURCE pure function arth_rdp(start,step,nn) !This section has been created automatically by the script Abilint (TD). !Do not modify the following lines by hand. #undef ABI_FUNC #define ABI_FUNC 'arth_rdp' !End of the abilint section implicit none !Arguments ------------------------------------ !scalars integer,intent(in) :: nn real(dp),intent(in) :: start,step real(dp) :: arth_rdp(nn) !Local variables------------------------------- integer :: ii ! ********************************************************************* select case (nn) case (1:) arth_rdp(1)=start do ii=2,nn arth_rdp(ii)=arth_rdp(ii-1)+step end do case (0) RETURN end select end function arth_rdp !!*** !---------------------------------------------------------------------- !!****f* m_numeric_tools/geop !! NAME !! geop !! !! FUNCTION !! Returns an array of length nn containing a geometric progression whose !! starting value is start and whose factor is factor! !! !! INPUTS !! start=initial point !! factor=the factor of the geometric progression !! nn=the number of points !! !! OUTPUT !! geop(nn)=the progression !! !! SOURCE pure function geop(start,factor,nn) result(res) !This section has been created automatically by the script Abilint (TD). !Do not modify the following lines by hand. #undef ABI_FUNC #define ABI_FUNC 'geop' !End of the abilint section implicit none !Arguments ------------------------------------ !scalars real(dp),intent(in) :: start,factor integer,intent(in) :: nn real(dp) :: res(nn) !Local variables------------------------------- integer :: ii ! ********************************************************************* if (nn>0) res(1)=start do ii=2,nn res(ii)=res(ii-1)*factor end do end function geop !!*** !---------------------------------------------------------------------- !!****f* m_numeric_tools/reverse_int !! NAME !! reverse_int !! !! FUNCTION !! Reverse a 1D array *IN PLACE*. Target: INT arrays !! !! PARENTS !! !! CHILDREN !! !! SOURCE subroutine reverse_int(arr) !This section has been created automatically by the script Abilint (TD). !Do not modify the following lines by hand. #undef ABI_FUNC #define ABI_FUNC 'reverse_int' !End of the abilint section implicit none !Arguments ------------------------------------ !scalars integer,intent(inout) :: arr(:) !arrays integer :: ii,nn,swap ! ************************************************************************* nn = SIZE(arr) if (nn <= 1) return do ii=1,nn/2 swap = arr(ii) arr(ii) = arr(nn-ii+1) arr(nn-ii+1) = swap end do end subroutine reverse_int !!*** !---------------------------------------------------------------------- !!****f* m_numeric_tools/reverse_rdp !! NAME !! reverse_rdp !! !! FUNCTION !! Reverse a 1D array *IN PLACE*. Target: DP arrays !! !! PARENTS !! !! CHILDREN !! !! SOURCE subroutine reverse_rdp(arr) !This section has been created automatically by the script Abilint (TD). !Do not modify the following lines by hand. #undef ABI_FUNC #define ABI_FUNC 'reverse_rdp' !End of the abilint section implicit none !Arguments ------------------------------------ !scalars real(dp),intent(inout) :: arr(:) !arrays integer :: ii,nn real(dp) :: swap ! ************************************************************************* nn = SIZE(arr) if (nn <= 1) return do ii=1,nn/2 swap = arr(ii) arr(ii) = arr(nn-ii+1) arr(nn-ii+1) = swap end do end subroutine reverse_rdp !!*** !---------------------------------------------------------------------- !!****f* m_numeric_tools/unit_matrix_int !! NAME !! unit_matrix_int !! !! FUNCTION !! Set the matrix matrix to be a unit matrix (if it is square). !! !! SIDE EFFECTS !! matrix(:,:)=set to unit on exit !! !! PARENTS !! !! CHILDREN !! !! SOURCE pure subroutine unit_matrix_int(matrix) !This section has been created automatically by the script Abilint (TD). !Do not modify the following lines by hand. #undef ABI_FUNC #define ABI_FUNC 'unit_matrix_int' !End of the abilint section implicit none !Arguments ------------------------------------ integer,intent(inout) :: matrix(:,:) !Local variables------------------------------- !scalars integer :: ii,nn ! ********************************************************************* nn=MIN(SIZE(matrix,DIM=1),SIZE(matrix,DIM=2)) matrix(:,:)=0 do ii=1,nn matrix(ii,ii)=1 end do end subroutine unit_matrix_int !!*** !---------------------------------------------------------------------- !!****f* m_numeric_tools/unit_matrix_rdp !! NAME !! unit_matrix_rdp !! !! FUNCTION !! Set the matrix matrix to be a unit matrix (if it is square). !! !! SIDE EFFECTS !! matrix(:,:)=set to unit on exit !! !! PARENTS !! !! CHILDREN !! !! SOURCE pure subroutine unit_matrix_rdp(matrix) !This section has been created automatically by the script Abilint (TD). !Do not modify the following lines by hand. #undef ABI_FUNC #define ABI_FUNC 'unit_matrix_rdp' !End of the abilint section implicit none !Arguments ------------------------------------ real(dp),intent(inout) :: matrix(:,:) !Local variables------------------------------- !scalars integer :: ii,nn ! ********************************************************************* nn=MIN(SIZE(matrix,DIM=1),SIZE(matrix,DIM=2)) matrix(:,:)=zero do ii=1,nn matrix(ii,ii)=one end do end subroutine unit_matrix_rdp !!*** !---------------------------------------------------------------------- !!****f* m_numeric_tools/unit_matrix_cdp !! NAME !! unit_matrix_cdp !! !! FUNCTION !! Set the matrix matrix to be a unit matrix (if it is square). !! !! SIDE EFFECTS !! matrix(:,:)=set to unit on exit !! !! PARENTS !! !! CHILDREN !! !! SOURCE pure subroutine unit_matrix_cdp(matrix) !This section has been created automatically by the script Abilint (TD). !Do not modify the following lines by hand. #undef ABI_FUNC #define ABI_FUNC 'unit_matrix_cdp' !End of the abilint section implicit none !Arguments ------------------------------------ complex(dpc),intent(inout) :: matrix(:,:) !Local variables------------------------------- !scalars integer :: ii,nn ! ********************************************************************* nn=MIN(SIZE(matrix,DIM=1),SIZE(matrix,DIM=2)) matrix=czero do ii=1,nn matrix(ii,ii)=cone end do end subroutine unit_matrix_cdp !!*** !---------------------------------------------------------------------- !!****f* m_numeric_tools/get_trace_int !! NAME !! get_trace_int !! !! FUNCTION !! Calculate the trace of a square matrix !! !! INPUTS !! matrix(:,:) !! !! OUTPUT !! trace=the trace !! !! SOURCE pure function get_trace_int(matrix) result(trace) !This section has been created automatically by the script Abilint (TD). !Do not modify the following lines by hand. #undef ABI_FUNC #define ABI_FUNC 'get_trace_int' !End of the abilint section implicit none !Arguments ------------------------------------ integer :: trace integer,intent(in) :: matrix(:,:) !Local variables------------------------------- !scalars integer :: ii ! ********************************************************************* trace=0 do ii=1,size(matrix,dim=1) trace=trace+matrix(ii,ii) end do end function get_trace_int !!*** !---------------------------------------------------------------------- !!****f* m_numeric_tools/get_trace_rdp !! NAME !! get_trace_int !! !! FUNCTION !! Calculate the trace of a square matrix (real(dp) version) !! !! INPUTS !! matrix(:,:) !! !! OUTPUT !! trace=the trace !! !! SOURCE pure function get_trace_rdp(matrix) result(trace) !This section has been created automatically by the script Abilint (TD). !Do not modify the following lines by hand. #undef ABI_FUNC #define ABI_FUNC 'get_trace_rdp' !End of the abilint section implicit none !Arguments ------------------------------------ real(dp) :: trace real(dp),intent(in) :: matrix(:,:) !Local variables------------------------------- !scalars integer :: ii ! ********************************************************************* trace=zero do ii=1,size(matrix,dim=1) trace=trace+matrix(ii,ii) end do end function get_trace_rdp !!*** !---------------------------------------------------------------------- !!****f* m_numeric_tools/get_trace_cdp !! NAME !! get_trace_cdp !! !! FUNCTION !! Calculate the trace of a square matrix (complex(dpc) version) !! !! INPUTS !! !! OUTPUT !! !! SOURCE pure function get_trace_cdp(matrix) result(trace) !This section has been created automatically by the script Abilint (TD). !Do not modify the following lines by hand. #undef ABI_FUNC #define ABI_FUNC 'get_trace_cdp' !End of the abilint section implicit none !Arguments ------------------------------------ complex(dpc) :: trace complex(dpc),intent(in) :: matrix(:,:) !Local variables------------------------------- !scalars integer :: ii ! ********************************************************************* trace=czero do ii=1,size(matrix,dim=1) trace=trace+matrix(ii,ii) end do end function get_trace_cdp !!*** !---------------------------------------------------------------------- !!****f* m_numeric_tools/get_diag_rdp !! NAME !! get_diag_rdp !! !! FUNCTION !! Return the trace of a square matrix as a vector !! !! INPUTS !! matrix(:,:) !! !! OUTPUT !! diag(:)=the diagonalr !! !! SOURCE function get_diag_rdp(mat) result(diag) !This section has been created automatically by the script Abilint (TD). !Do not modify the following lines by hand. #undef ABI_FUNC #define ABI_FUNC 'get_diag_rdp' !End of the abilint section implicit none !Arguments ------------------------------------ !scalars real(dp),intent(in) :: mat(:,:) real(dp) :: diag(SIZE(mat,1)) !Local variables------------------------------- integer :: ii ! ************************************************************************* ii=assert_eq(SIZE(mat,1),SIZE(mat,2),'Matrix not square',& & __FILE__,__LINE__) do ii=1,SIZE(mat,1) diag(ii)=mat(ii,ii) end do end function get_diag_rdp !!*** !---------------------------------------------------------------------- !!****f* m_numeric_tools/get_diag_cdp !! NAME !! get_diag_cdp !! !! FUNCTION !! !! INPUTS !! !! OUTPUT !! !! SOURCE function get_diag_cdp(cmat) result(cdiag) !Arguments ------------------------------------ !scalars !This section has been created automatically by the script Abilint (TD). !Do not modify the following lines by hand. #undef ABI_FUNC #define ABI_FUNC 'get_diag_cdp' !End of the abilint section complex(dpc),intent(in) :: cmat(:,:) complex(dpc) :: cdiag(SIZE(cmat,1)) !Local variables------------------------------- integer :: ii ! ************************************************************************* ii=assert_eq(SIZE(cmat,1),SIZE(cmat,2),'Matrix not square',& & __FILE__,__LINE__) do ii=1,SIZE(cmat,1) cdiag(ii)=cmat(ii,ii) end do end function get_diag_cdp !!*** !---------------------------------------------------------------------- !!****f* m_numeric_tools/isdiagmat_int !! NAME !! isdiagmat_int !! !! FUNCTION !! True if matrix mat is diagonal !! !! SOURCE pure logical function isdiagmat_int(mat) result(ans) !This section has been created automatically by the script Abilint (TD). !Do not modify the following lines by hand. #undef ABI_FUNC #define ABI_FUNC 'isdiagmat_int' !End of the abilint section implicit none !Arguments ------------------------------------ !scalars integer,intent(in) :: mat(:,:) !Local variables------------------------------- integer :: ii,jj ! ************************************************************************* ans = .True. do jj=1,size(mat,dim=2) do ii=1,size(mat,dim=1) if (ii == jj) cycle if (mat(ii,jj) /= 0) then ans = .False.; return end if end do end do end function isdiagmat_int !!*** !---------------------------------------------------------------------- !!****f* m_numeric_tools/isdiagmat_rdp !! NAME !! isdiagmat_rdp !! !! FUNCTION !! True if matrix mat is diagonal withing the given absolute tolerance (default: tol12) !! !! SOURCE pure logical function isdiagmat_rdp(mat, atol) result(ans) !This section has been created automatically by the script Abilint (TD). !Do not modify the following lines by hand. #undef ABI_FUNC #define ABI_FUNC 'isdiagmat_rdp' !End of the abilint section implicit none !This section has been created automatically by the script Abilint (TD). !Do not modify the following lines by hand. #undef ABI_FUNC #define ABI_FUNC 'isdiagmat_rdp' !End of the abilint section !Arguments ------------------------------------ !scalars real(dp),intent(in) :: mat(:,:) real(dp),optional,intent(in) :: atol !Local variables------------------------------- integer :: ii,jj real(dp) :: my_atol ! ************************************************************************* my_atol = tol12; if (present(atol)) my_atol = atol ans = .True. do jj=1,size(mat,dim=2) do ii=1,size(mat,dim=1) if (ii == jj) cycle if (abs(mat(ii,jj)) > my_atol) then ans = .False.; return end if end do end do end function isdiagmat_rdp !!*** !---------------------------------------------------------------------- !!****f* m_numeric_tools/rdp2cdp_1D !! NAME !! rdp2cdp_1D !! !! FUNCTION !! Create a complex array starting from a real array containing real and imaginary part !! !! INPUTS !! rr(:)=the real array !! !! OUTPUT !! cc(:)=the complex array !! !! SOURCE pure function rdp2cdp_1D(rr) result(cc) !This section has been created automatically by the script Abilint (TD). !Do not modify the following lines by hand. #undef ABI_FUNC #define ABI_FUNC 'rdp2cdp_1D' !End of the abilint section implicit none !Arguments ------------------------------------ !scalars real(dp),intent(in) :: rr(:,:) complex(dpc) :: cc(SIZE(rr,2)) ! ********************************************************************* cc(:)=CMPLX(rr(1,:),rr(2,:),kind=dpc) end function rdp2cdp_1D !!*** !---------------------------------------------------------------------- !!****f* m_numeric_tools/rdp2cdp_2D !! NAME !! rdp2cdp_2D !! !! FUNCTION !! !! INPUTS !! !! OUTPUT !! !! SOURCE pure function rdp2cdp_2D(rr) result(cc) !This section has been created automatically by the script Abilint (TD). !Do not modify the following lines by hand. #undef ABI_FUNC #define ABI_FUNC 'rdp2cdp_2D' !End of the abilint section implicit none !Arguments ------------------------------------ !scalars real(dp),intent(in) :: rr(:,:,:) complex(dpc) :: cc(SIZE(rr,2),SIZE(rr,3)) ! ********************************************************************* cc(:,:)=CMPLX(rr(1,:,:),rr(2,:,:), kind=dpc) end function rdp2cdp_2D !!*** !---------------------------------------------------------------------- !!****f* m_numeric_tools/rdp2cdp_3D !! NAME !! rdp2cdp_3D !! !! FUNCTION !! !! INPUTS !! !! OUTPUT !! !! SOURCE pure function rdp2cdp_3D(rr) result(cc) !This section has been created automatically by the script Abilint (TD). !Do not modify the following lines by hand. #undef ABI_FUNC #define ABI_FUNC 'rdp2cdp_3D' !End of the abilint section implicit none !Arguments ------------------------------------ !scalars real(dp),intent(in) :: rr(:,:,:,:) complex(dpc) :: cc(SIZE(rr,2),SIZE(rr,3),SIZE(rr,4)) ! ********************************************************************* cc(:,:,:)=CMPLX(rr(1,:,:,:),rr(2,:,:,:), kind=dpc) end function rdp2cdp_3D !!*** !---------------------------------------------------------------------- !!****f* m_numeric_tools/rdp2cdp_4D !! NAME !! rdp2cdp_4D !! !! FUNCTION !! !! INPUTS !! !! OUTPUT !! !! SOURCE pure function rdp2cdp_4D(rr) result(cc) !This section has been created automatically by the script Abilint (TD). !Do not modify the following lines by hand. #undef ABI_FUNC #define ABI_FUNC 'rdp2cdp_4D' !End of the abilint section implicit none !Arguments ------------------------------------ !scalars real(dp),intent(in) :: rr(:,:,:,:,:) complex(dpc) :: cc(SIZE(rr,2),SIZE(rr,3),SIZE(rr,4),SIZE(rr,5)) ! ********************************************************************* cc(:,:,:,:)=CMPLX(rr(1,:,:,:,:),rr(2,:,:,:,:), kind=dpc) end function rdp2cdp_4D !!*** !---------------------------------------------------------------------- !!****f* m_numeric_tools/rdp2cdp_5D !! NAME !! rdp2cdp_5D !! !! FUNCTION !! !! INPUTS !! !! OUTPUT !! !! SOURCE pure function rdp2cdp_5D(rr) result(cc) !This section has been created automatically by the script Abilint (TD). !Do not modify the following lines by hand. #undef ABI_FUNC #define ABI_FUNC 'rdp2cdp_5D' !End of the abilint section implicit none !Arguments ------------------------------------ !scalars real(dp),intent(in) :: rr(:,:,:,:,:,:) complex(dpc) :: cc(SIZE(rr,2),SIZE(rr,3),SIZE(rr,4),SIZE(rr,5),SIZE(rr,6)) ! ********************************************************************* cc(:,:,:,:,:)=CMPLX(rr(1,:,:,:,:,:),rr(2,:,:,:,:,:), kind=dpc) end function rdp2cdp_5D !!*** !---------------------------------------------------------------------- !!****f* m_numeric_tools/rdp2cdp_6D !! NAME !! rdp2cdp_6D !! !! FUNCTION !! !! INPUTS !! !! OUTPUT !! !! SOURCE pure function rdp2cdp_6D(rr) result(cc) !This section has been created automatically by the script Abilint (TD). !Do not modify the following lines by hand. #undef ABI_FUNC #define ABI_FUNC 'rdp2cdp_6D' !End of the abilint section implicit none !Arguments ------------------------------------ !scalars real(dp),intent(in) :: rr(:,:,:,:,:,:,:) complex(dpc) :: cc(SIZE(rr,2),SIZE(rr,3),SIZE(rr,4),SIZE(rr,5),SIZE(rr,6),SIZE(rr,7)) ! ********************************************************************* cc(:,:,:,:,:,:)=CMPLX(rr(1,:,:,:,:,:,:),rr(2,:,:,:,:,:,:), kind=dpc) end function rdp2cdp_6D !!*** !---------------------------------------------------------------------- !!****f* m_numeric_tools/cdp2rdp_1D !! NAME !! cdp2rdp_1D !! !! FUNCTION !! Create a real array containing real and imaginary part starting from a complex array !! !! INPUTS !! cc(:)=the input complex array !! !! OUTPUT !! rr(2,:)=the real array !! !! SOURCE pure function cdp2rdp_1D(cc) result(rr) !This section has been created automatically by the script Abilint (TD). !Do not modify the following lines by hand. #undef ABI_FUNC #define ABI_FUNC 'cdp2rdp_1D' !End of the abilint section implicit none !Arguments ------------------------------------ !scalars complex(dpc),intent(in) :: cc(:) real(dp) :: rr(2,SIZE(cc)) ! ********************************************************************* rr(1,:)=REAL (cc(:)) rr(2,:)=AIMAG(cc(:)) end function cdp2rdp_1D !!*** !---------------------------------------------------------------------- !!****f* m_numeric_tools/cdp2rdp_2D !! NAME !! cdp2rdp_2D !! !! FUNCTION !! !! INPUTS !! !! OUTPUT !! !! SOURCE pure function cdp2rdp_2D(cc) result(rr) !This section has been created automatically by the script Abilint (TD). !Do not modify the following lines by hand. #undef ABI_FUNC #define ABI_FUNC 'cdp2rdp_2D' !End of the abilint section implicit none !Arguments ------------------------------------ !scalars complex(dpc),intent(in) :: cc(:,:) real(dp) :: rr(2,SIZE(cc,1),SIZE(cc,2)) ! ********************************************************************* rr(1,:,:)=REAL (cc(:,:)) rr(2,:,:)=AIMAG(cc(:,:)) end function cdp2rdp_2D !!*** !---------------------------------------------------------------------- !!****f* m_numeric_tools/cdp2rdp_3D !! NAME !! cdp2rdp_3D !! !! FUNCTION !! !! INPUTS !! !! OUTPUT !! !! SOURCE pure function cdp2rdp_3D(cc) result(rr) !This section has been created automatically by the script Abilint (TD). !Do not modify the following lines by hand. #undef ABI_FUNC #define ABI_FUNC 'cdp2rdp_3D' !End of the abilint section implicit none !Arguments ------------------------------------ !scalars complex(dpc),intent(in) :: cc(:,:,:) real(dp) :: rr(2,SIZE(cc,1),SIZE(cc,2),SIZE(cc,3)) ! ********************************************************************* rr(1,:,:,:)=REAL (cc(:,:,:)) rr(2,:,:,:)=AIMAG(cc(:,:,:)) end function cdp2rdp_3D !!*** !---------------------------------------------------------------------- !!****f* m_numeric_tools/cdp2rdp_4D !! NAME !! cdp2rdp_4D !! !! FUNCTION !! !! INPUTS !! !! OUTPUT !! !! SOURCE pure function cdp2rdp_4D(cc) result(rr) !This section has been created automatically by the script Abilint (TD). !Do not modify the following lines by hand. #undef ABI_FUNC #define ABI_FUNC 'cdp2rdp_4D' !End of the abilint section implicit none !Arguments ------------------------------------ !scalars complex(dpc),intent(in) :: cc(:,:,:,:) real(dp) :: rr(2,SIZE(cc,1),SIZE(cc,2),SIZE(cc,3),SIZE(cc,4)) ! ********************************************************************* rr(1,:,:,:,:)=REAL (cc(:,:,:,:)) rr(2,:,:,:,:)=AIMAG(cc(:,:,:,:)) end function cdp2rdp_4D !!*** !---------------------------------------------------------------------- !!****f* m_numeric_tools/cdp2rdp_5D !! NAME !! cdp2rdp_5D !! !! FUNCTION !! !! INPUTS !! !! OUTPUT !! !! SOURCE pure function cdp2rdp_5D(cc) result(rr) !This section has been created automatically by the script Abilint (TD). !Do not modify the following lines by hand. #undef ABI_FUNC #define ABI_FUNC 'cdp2rdp_5D' !End of the abilint section implicit none !Arguments ------------------------------------ !scalars complex(dpc),intent(in) :: cc(:,:,:,:,:) real(dp) :: rr(2,SIZE(cc,1),SIZE(cc,2),SIZE(cc,3),SIZE(cc,4),SIZE(cc,5)) ! ********************************************************************* rr(1,:,:,:,:,:)=REAL (cc(:,:,:,:,:)) rr(2,:,:,:,:,:)=AIMAG(cc(:,:,:,:,:)) end function cdp2rdp_5D !!*** !---------------------------------------------------------------------- !!****f* m_numeric_tools/iseven !! NAME !! iseven !! !! FUNCTION !! Return .TRUE. if the given integer is even !! !! PARENTS !! !! CHILDREN !! !! SOURCE elemental function iseven(nn) !This section has been created automatically by the script Abilint (TD). !Do not modify the following lines by hand. #undef ABI_FUNC #define ABI_FUNC 'iseven' !End of the abilint section implicit none !Arguments ------------------------------------ !scalars integer,intent(in) :: nn logical :: iseven ! ********************************************************************* iseven=.FALSE.; if ((nn/2)*2==nn) iseven=.TRUE. end function iseven !!*** !---------------------------------------------------------------------- !!****f* m_numeric_tools/is_integer_0D !! NAME !! is_integer_0D !! !! FUNCTION !! Return .TRUE. if all elements differ from an integer by less that tol !! !! INPUTS !! rr=the set of real values to be checked !! tol=tolerance on the difference between real and integer !! !! SOURCE pure function is_integer_0d(rr,tol) result(ans) !This section has been created automatically by the script Abilint (TD). !Do not modify the following lines by hand. #undef ABI_FUNC #define ABI_FUNC 'is_integer_0d' !End of the abilint section implicit none !Arguments ------------------------------------ !scalars real(dp),intent(in) :: tol logical :: ans !arrays real(dp),intent(in) :: rr ! ************************************************************************* ans=(ABS(rr-NINT(rr))=AA(1)) ! ! === Initialize lower and upper limits === jl=0; ju=nn+1 do if (ju-jl<=1) EXIT jm=(ju+jl)/2 ! Compute a midpoint, if (ascnd.EQV.(xx>=AA(jm))) then jl=jm ! Replace lower limit else ju=jm ! Replace upper limit end if end do ! ! === Set the output, being careful with the endpoints === if (xx==AA(1)) then loc=1 else if (xx==AA(nn)) then loc=nn-1 else loc=jl end if end function bisect_rdp !!*** !---------------------------------------------------------------------- !!****f* m_numeric_tools/bisect_int !! NAME !! bisect_int !! !! FUNCTION !! Given an array AA(1:N), and a value x, returns the index j such that AA(j)<=x<= AA(j + 1). !! AA must be monotonic, either increasing or decreasing. j=0 or !! j=N is returned to indicate that x is out of range. !! !! INPUTS !! !! OUTPUT !! !! SOURCE pure function bisect_int(AA,xx) result(loc) !This section has been created automatically by the script Abilint (TD). !Do not modify the following lines by hand. #undef ABI_FUNC #define ABI_FUNC 'bisect_int' !End of the abilint section implicit none !Arguments ------------------------------------ !scalars integer,intent(in) :: AA(:) integer,intent(in) :: xx integer :: loc !Local variables------------------------------- integer :: nn,jl,jm,ju logical :: ascnd ! ********************************************************************* nn=SIZE(AA) ; ascnd=(AA(nn)>=AA(1)) ! ! === Initialize lower and upper limits === jl=0 ; ju=nn+1 do if (ju-jl<=1) EXIT jm=(ju+jl)/2 ! Compute a midpoint, if (ascnd.EQV.(xx>=AA(jm))) then jl=jm ! Replace lower limit else ju=jm ! Replace upper limit end if end do ! ! === Set the output, being careful with the endpoints === if (xx==AA(1)) then loc=1 else if (xx==AA(nn)) then loc=nn-1 else loc=jl end if end function bisect_int !!*** !---------------------------------------------------------------------- !!****f* m_numeric_tools/imax_loc_int !! NAME !! imax_loc_int !! !! FUNCTION !! Index of maxloc on an array returned as scalar instead of array-valued !! !! SOURCE pure function imax_loc_int(iarr,mask) !This section has been created automatically by the script Abilint (TD). !Do not modify the following lines by hand. #undef ABI_FUNC #define ABI_FUNC 'imax_loc_int' !End of the abilint section implicit none !Arguments ------------------------------------ !scalars integer :: imax_loc_int !arrays integer,intent(in) :: iarr(:) logical,optional,intent(in) :: mask(:) !Local variables------------------------------- integer :: imax(1) ! ************************************************************************* if (PRESENT(mask)) then imax=MAXLOC(iarr,MASK=mask) else imax=MAXLOC(iarr) end if imax_loc_int=imax(1) end function imax_loc_int !!*** !---------------------------------------------------------------------- !!****f* m_numeric_tools/imax_loc_rdp !! NAME !! imax_loc_rdp !! !! FUNCTION !! !! INPUTS !! !! OUTPUT !! !! SOURCE pure function imax_loc_rdp(arr,mask) !This section has been created automatically by the script Abilint (TD). !Do not modify the following lines by hand. #undef ABI_FUNC #define ABI_FUNC 'imax_loc_rdp' !End of the abilint section implicit none !Arguments ------------------------------------ !scalars integer :: imax_loc_rdp !arrays real(dp),intent(in) :: arr(:) logical,optional,intent(in) :: mask(:) !Local variables------------------------------- integer :: imax(1) ! ************************************************************************* if (PRESENT(mask)) then imax=MAXLOC(arr,MASK=mask) else imax=MAXLOC(arr) end if imax_loc_rdp=imax(1) end function imax_loc_rdp !!*** !---------------------------------------------------------------------- !!****f* m_numeric_tools/imin_loc_int !! NAME !! imin_loc_int !! !! FUNCTION !! Index of minloc on an array returned as scalar instead of array-valued !! !! SOURCE pure function imin_loc_int(arr,mask) !This section has been created automatically by the script Abilint (TD). !Do not modify the following lines by hand. #undef ABI_FUNC #define ABI_FUNC 'imin_loc_int' !End of the abilint section implicit none !Arguments ------------------------------------ !scalars integer :: imin_loc_int !arrays integer,intent(in) :: arr(:) logical,optional,intent(in) :: mask(:) !Local variables------------------------------- integer :: imin(1) ! ************************************************************************* if (PRESENT(mask)) then imin=MINLOC(arr,MASK=mask) else imin=MINLOC(arr) end if imin_loc_int=imin(1) end function imin_loc_int !!*** !---------------------------------------------------------------------- !!****f* m_numeric_tools/imin_loc_rdp !! NAME !! imin_loc_rdp !! !! FUNCTION !! !! INPUTS !! !! OUTPUT !! !! SOURCE pure function imin_loc_rdp(arr,mask) !This section has been created automatically by the script Abilint (TD). !Do not modify the following lines by hand. #undef ABI_FUNC #define ABI_FUNC 'imin_loc_rdp' !End of the abilint section implicit none !Arguments ------------------------------------ !scalars integer :: imin_loc_rdp !arrays real(dp),intent(in) :: arr(:) logical,optional,intent(in) :: mask(:) !Local variables------------------------------- integer :: imin(1) ! ************************************************************************* if (PRESENT(mask)) then imin=MINLOC(arr,MASK=mask) else imin=MINLOC(arr) end if imin_loc_rdp=imin(1) end function imin_loc_rdp !!*** !---------------------------------------------------------------------- !!****f* m_numeric_tools/lfind !! NAME !! lfind !! !! FUNCTION !! Find the index of the first occurrence of .True. in a logical array. !! Return -1 if not found. If back is True, the search starts from the !! last element of the array (default: False). !! !! INPUTS !! mask(:)=Input logical mask !! !! PARENTS !! !! CHILDREN !! !! SOURCE integer pure function lfind(mask, back) !This section has been created automatically by the script Abilint (TD). !Do not modify the following lines by hand. #undef ABI_FUNC #define ABI_FUNC 'lfind' !End of the abilint section implicit none !Arguments ------------------------------------ !scalars logical,intent(in) :: mask(:) logical,optional,intent(in) :: back !arrays !Local variables------------------------------- !scalars integer :: ii,nitems logical :: do_back !************************************************************************ do_back = .False.; if (present(back)) do_back = back lfind = -1; nitems = size(mask); if (nitems == 0) return if (do_back) then ! Backward search do ii=nitems,1,-1 if (mask(ii)) then lfind = ii; return end if end do else ! Forward search. do ii=1,nitems if (mask(ii)) then lfind = ii; return end if end do end if end function lfind !!*** !---------------------------------------------------------------------- !!****f* m_numeric_tools/list2blocks !! NAME !! list2blocks !! !! FUNCTION !! Given a list of integers, find the number of contiguos groups of values. !! and returns the set of indices that can be used to loop over these groups !! Example list = [1,2,3,5,6] --> blocks = [[1,3], [4,5]] !! !! INPUTS !! list(:)=List of integers !! !! OUTPUTS !! nblocks=Number of blocks !! blocks(2,nblocks)= !! allocatable array in input !! in output: !! blocks(1,i) gives the start of the i-th block !! blocks(2,i) gives the end of the i-th block !! !! PARENTS !! m_wfd !! !! CHILDREN !! !! SOURCE subroutine list2blocks(list,nblocks,blocks) !This section has been created automatically by the script Abilint (TD). !Do not modify the following lines by hand. #undef ABI_FUNC #define ABI_FUNC 'list2blocks' !End of the abilint section implicit none !Arguments ------------------------------------ !scalars integer,intent(out) :: nblocks integer,intent(in) :: list(:) !arrays integer,intent(out),allocatable :: blocks(:,:) !Local variables------------------------------- !scalars integer :: ii,nitems !arrays integer :: work(2,size(list)) !************************************************************************ nitems = size(list) ! Handle nitems == 1 case if (nitems == 1) then ABI_MALLOC(blocks, (2,1)) blocks = 1 return end if nblocks = 1; work(1,1) = 1 do ii=2,nitems if (list(ii) /= (list(ii-1) + 1)) then work(2,nblocks) = ii - 1 nblocks = nblocks + 1 work(1,nblocks) = ii end if end do work(2,nblocks) = nitems ABI_MALLOC(blocks, (2,nblocks)) blocks = work(:,1:nblocks) end subroutine list2blocks !!*** !---------------------------------------------------------------------- !!****f* m_numeric_tools/mask2blocks !! NAME !! mask2blocks !! !! FUNCTION !! Give a logical mask, find the number of contiguos groups of .TRUE. values. !! and return the set of indices that can be used to loop over these groups !! !! INPUTS !! mask(:)=Input logical mask !! !! OUTPUTS !! nblocks=Number of blocks !! !! SIDE EFFECTS !! blocks(:,:)= Null pointer in input. blocks(2,nblocks) in output where !! blocks(1,i) gives the start of the i-th block !! blocks(2,i) gives the end of the i-th block !! !! PARENTS !! m_wfk !! !! CHILDREN !! !! SOURCE subroutine mask2blocks(mask,nblocks,blocks) !This section has been created automatically by the script Abilint (TD). !Do not modify the following lines by hand. #undef ABI_FUNC #define ABI_FUNC 'mask2blocks' !End of the abilint section implicit none !Arguments ------------------------------------ !scalars integer,intent(out) :: nblocks logical,intent(in) :: mask(:) !arrays integer,allocatable :: blocks(:,:) !Local variables------------------------------- !scalars integer :: ii,nitems,start logical :: inblock !arrays integer :: work(2,SIZE(mask)) !************************************************************************ ! Find first element. nitems = size(mask); start = 0 do ii=1,nitems if (mask(ii)) then start = ii exit end if end do ! Handle no true element or just one. if (start == 0) then nblocks = 0 ABI_MALLOC(blocks, (0,0)) return end if if (start /= 0 .and. nitems == 1) then nblocks = 1 ABI_MALLOC(blocks, (2,1)) blocks(:,1) = [1,1] end if nblocks = 1; work(1,1) = start; inblock = .True. do ii=start+1,nitems if (.not.mask(ii)) then if (inblock) then inblock = .False. work(2,nblocks) = ii - 1 end if else if (.not. inblock) then inblock = .True. nblocks = nblocks + 1 work(1,nblocks) = ii end if end if end do if (mask(nitems) .and. inblock) work(2,nblocks) = nitems ABI_MALLOC(blocks, (2,nblocks)) blocks = work(:,1:nblocks) end subroutine mask2blocks !!*** !---------------------------------------------------------------------- !!****f* m_numeric_tools/linfit_rdp !! NAME !! linfit_rdp !! !! FUNCTION !! Perform a linear fit, y=ax+b, of data !! !! INPUTS !! xx(nn)=xx coordinates !! yy(nn)=yy coordinates !! !! OUTPUT !! aa=coefficient of linear term of fit !! bb=coefficient of constant term of fit !! function linfit=root mean square of differences between data and fit !! !! SOURCE function linfit_rdp(nn,xx,yy,aa,bb) result(res) !This section has been created automatically by the script Abilint (TD). !Do not modify the following lines by hand. #undef ABI_FUNC #define ABI_FUNC 'linfit_rdp' !End of the abilint section implicit none !This section has been created automatically by the script Abilint (TD). !Do not modify the following lines by hand. #undef ABI_FUNC #define ABI_FUNC 'linfit_rdp' !End of the abilint section !Arguments ------------------------------------ !scalars integer,intent(in) :: nn real(dp) :: res real(dp),intent(out) :: aa,bb !arrays real(dp),intent(in) :: xx(nn),yy(nn) !Local variables------------------------------- !scalars integer :: ii real(dp) :: msrt,sx2,sx,sxy,sy,tx,ty ! ************************************************************************* sx=zero ; sy=zero ; sxy=zero ; sx2=zero do ii=1,nn tx=xx(ii) ty=yy(ii) sx=sx+tx sy=sy+ty sxy=sxy+tx*ty sx2=sx2+tx*tx end do aa=(nn*sxy-sx*sy)/(nn*sx2-sx*sx) bb=sy/nn-sx*aa/nn msrt=zero do ii=1,nn tx=xx(ii) ty=yy(ii) msrt=msrt+(ty-aa*tx-bb)**2 end do msrt=SQRT(msrt/nn) ; res=msrt end function linfit_rdp !!*** !---------------------------------------------------------------------- !!****f* m_numeric_tools/linfit_spc !! NAME !! linfit_spc !! !! FUNCTION !! !! INPUTS !! !! OUTPUT !! !! SOURCE function linfit_spc(nn,xx,zz,aa,bb) result(res) !Arguments ------------------------------------ !scalars !This section has been created automatically by the script Abilint (TD). !Do not modify the following lines by hand. #undef ABI_FUNC #define ABI_FUNC 'linfit_spc' !End of the abilint section integer,intent(in) :: nn real(dp) :: res real(dp),intent(in) :: xx(nn) complex(spc),intent(in) :: zz(nn) complex(spc),intent(out) :: aa,bb !arrays !Local variables------------------------------- !scalars integer :: ii real(dp) :: sx,sx2,msrt complex(dpc) :: sz,sxz ! ************************************************************************* sx=zero ; sx2=zero ; msrt=zero sz=czero ; sxz=czero do ii=1,nn sx=sx+xx(ii) sz=sz+zz(ii) sxz=sxz+xx(ii)*zz(ii) sx2=sx2+xx(ii)*xx(ii) end do aa=(nn*sxz-sx*sz)/(nn*sx2-sx*sx) bb=sz/nn-sx*aa/nn do ii=1,nn msrt=msrt+ABS(zz(ii)-aa*xx(ii)-bb)**2 end do msrt=SQRT(msrt) ; res=msrt end function linfit_spc !!*** !---------------------------------------------------------------------- !!****f* m_numeric_tools/linfit_dpc !! NAME !! linfit_dpc !! !! FUNCTION !! !! INPUTS !! !! OUTPUT !! !! SOURCE function linfit_dpc(nn,xx,zz,aa,bb) result(res) !This section has been created automatically by the script Abilint (TD). !Do not modify the following lines by hand. #undef ABI_FUNC #define ABI_FUNC 'linfit_dpc' !End of the abilint section implicit none !Arguments ------------------------------------ !scalars integer,intent(in) :: nn real(dp) :: res real(dp),intent(in) :: xx(nn) complex(dpc),intent(in) :: zz(nn) complex(dpc),intent(out) :: aa,bb !arrays !Local variables------------------------------- !scalars integer :: ii real(dp) :: sx,sx2,msrt complex(dpc) :: sz,sxz ! ************************************************************************* sx=zero ; sx2=zero ; msrt=zero sz=czero ; sxz=czero do ii=1,nn sx=sx+xx(ii) sz=sz+zz(ii) sxz=sxz+xx(ii)*zz(ii) sx2=sx2+xx(ii)*xx(ii) end do aa=(nn*sxz-sx*sz)/(nn*sx2-sx*sx) bb=sz/nn-sx*aa/nn do ii=1,nn msrt=msrt+ABS(zz(ii)-aa*xx(ii)-bb)**2 end do msrt=SQRT(msrt) ; res=msrt end function linfit_dpc !!*** !---------------------------------------------------------------------- !!****f* m_numeric_tools/llsfit_svd !! NAME !! llsfit_svd !! !! FUNCTION !! Given a set of N data points (x,y) with individual standard deviations sigma_i, !! use chi-square minimization to determine the M coefficients, par, of a function that !! depends linearly on nfuncs functions, i.e f(x) = \sum_i^{nfuncs} par_i * func_i(x). !! Solve the fitting equations using singular value decomposition of the design matrix as in Eq 14.3.17 !! of Numerical Recipes. The program returns values for the M fit parameters par, and chi-square. !! The user supplies a subroutine funcs(x,nfuncs) that returns the M basis functions evaluated at xx. !! !! INPUTS !! !! OUTPUT !! !! PARENTS !! !! CHILDREN !! !! SOURCE subroutine llsfit_svd(xx,yy,sigma,nfuncs,funcs,chisq,par,var,cov,info) !This section has been created automatically by the script Abilint (TD). !Do not modify the following lines by hand. #undef ABI_FUNC #define ABI_FUNC 'llsfit_svd' !End of the abilint section implicit none !Arguments ------------------------------------ !scalars integer,intent(in) :: nfuncs integer,intent(out) :: info real(dp),intent(out) :: chisq !arrays real(dp),intent(in) :: xx(:),yy(:),sigma(:) real(dp),intent(out) :: par(:),var(:),cov(:,:) interface function funcs(xx,nf) use defs_basis implicit none real(dp),intent(in) :: xx integer,intent(in) :: nf real(dp) :: funcs(nf) end function funcs end interface !Local variables------------------------------- integer,parameter :: PAD_=50 integer :: ii,npts,lwork real(dp),parameter :: TOL_=1.0e-5_dp !arrays real(dp),dimension(SIZE(xx)) :: bb,sigm1 real(dp),dimension(SIZE(xx),nfuncs) :: dmat,dmat_save real(dp) :: tmp(nfuncs) real(dp),allocatable :: work(:),Vt(:,:),U(:,:),S(:) ! ************************************************************************* npts=assert_eq(SIZE(xx),SIZE(yy),SIZE(sigma),'Wrong size in xx,yy,sigma',& & __FILE__,__LINE__) call assert((npts>=nfuncs),'No. of functions must greater than no. of points',& & __FILE__,__LINE__) ii=assert_eq(nfuncs,SIZE(cov,1),SIZE(cov,2),SIZE(var),'Wrong size in covariance',& & __FILE__,__LINE__) ! ! === Calculate design matrix and b vector === ! * dmat_ij=f_j(x_i)/sigma_i, b_i=y_i/sigma_i sigm1(:)=one/sigma(:) ; bb(:)=yy(:)*sigm1(:) do ii=1,npts dmat_save(ii,:)=funcs(xx(ii),nfuncs) end do dmat=dmat_save*SPREAD(sigm1,DIM=2,ncopies=nfuncs) dmat_save(:,:)=dmat(:,:) ! ! === Singular value decomposition === lwork=MAX(3*MIN(npts,nfuncs)+MAX(npts,nfuncs),5*MIN(npts,nfuncs)-4)+PAD_ ABI_MALLOC(work,(lwork)) ABI_MALLOC(U,(npts,npts)) ABI_MALLOC(S,(nfuncs)) ABI_MALLOC(Vt,(nfuncs,nfuncs)) !call DGESVD('A','A',npts,nfuncs,dmat,npts,S,U,npts,Vt,nfuncs,work,lwork,info) ABI_FREE(work) GOTO 10 ! ! === Set to zero small singular values according to TOL_ and find coefficients === WHERE (S>TOL_*MAXVAL(S)) tmp=MATMUL(bb,U)/S ELSEWHERE S =zero tmp=zero END WHERE par(:)=MATMUL(tmp,Vt) ! ! === Evaluate chi-square === chisq=l2norm(MATMUL(dmat_save,par)-bb)**2 ! ! === Calculate covariance and variance === ! C_jk = V_ji V_ki / S_i^2 WHERE (S/=zero) S=one/(S*S) ! check this but should be correct cov(:,:)=Vt*SPREAD(S,DIM=2,ncopies=nfuncs) cov(:,:)=MATMUL(TRANSPOSE(Vt),cov) var(:)=SQRT(get_diag(cov)) 10 continue ABI_FREE(U) ABI_FREE(S) ABI_FREE(Vt) end subroutine llsfit_svd !!*** !---------------------------------------------------------------------- !!****f* m_numeric_tools/polyn_interp !! NAME !! polyn_interp !! !! FUNCTION !! Given arrays xa and ya of length N, and given a value x, return a value y, and an error estimate dy. !! If P(x) is the polynomial of degree N-1 such that P(xai)=yai, i=1,...,N, then the returned value y=P(x). !! !! INPUTS !! xa(:)=abscissas in ascending order !! ya(:)=ordinates !! x=the point where the set of data has to be interpolated !! !! OUTPUT !! y=the interpolated value !! dy=error estimate !! !! NOTES !! Based on the polint routine reported in Numerical Recipies !! !! PARENTS !! m_numeric_tools !! !! CHILDREN !! !! SOURCE subroutine polyn_interp(xa,ya,x,y,dy) !This section has been created automatically by the script Abilint (TD). !Do not modify the following lines by hand. #undef ABI_FUNC #define ABI_FUNC 'polyn_interp' !End of the abilint section implicit none !Arguments ------------------------------------ !scalars real(dp),intent(in) :: xa(:),ya(:) real(dp),intent(in) :: x real(dp),intent(out) :: y,dy !Local variables------------------------------- !scalars integer :: m,n,ns !arrays real(dp),dimension(SIZE(xa)) :: c,d,den,ho ! ************************************************************************* n=assert_eq(SIZE(xa),SIZE(ya),'Different size in xa and ya',& & __FILE__,__LINE__) ! === Initialize the tables of c and d === c(:)=ya(:) ; d(:)=ya(:) ; ho(:)=xa(:)-x ! === Find closest table entry and initial approximation to y === ns=imin_loc(ABS(x-xa)) ; y=ya(ns) ns=ns-1 ! ! === For each column of the tableau loop over current c and d and up-date them === do m=1,n-1 den(1:n-m)=ho(1:n-m)-ho(1+m:n) if (ANY(den(1:n-m)==zero)) then MSG_ERROR('Two input xa are identical') end if den(1:n-m)=(c(2:n-m+1)-d(1:n-m))/den(1:n-m) d(1:n-m)=ho(1+m:n)*den(1:n-m) ! Update c and d c(1:n-m)=ho(1:n-m)*den(1:n-m) if (2*ns0 (order 10 is hard-coded) !! 6 for Romberg integration with midpoint rule and extrapolation for h-->0 (order 10 is hard-coded) !! 7 for Gauss-Legendre !! !! OUTPUT !! quad=the integral !! ierr=0 if quadrature converged. !! !! PARENTS !! !! CHILDREN !! !! SOURCE recursive subroutine quadrature(func,xmin,xmax,qopt,quad,ierr,ntrial,accuracy,npts) !This section has been created automatically by the script Abilint (TD). !Do not modify the following lines by hand. #undef ABI_FUNC #define ABI_FUNC 'quadrature' use interfaces_28_numeric_noabirule !End of the abilint section implicit none !Arguments ------------------------------------ !scalars integer,intent(in) :: qopt integer,intent(out) :: ierr integer,optional,intent(in) :: ntrial,npts real(dp),intent(in) :: xmin,xmax real(dp),optional,intent(in) :: accuracy real(dp),intent(out) :: quad interface function func(x) use defs_basis real(dp),intent(in) :: x real(dp) :: func end function func end interface !interface ! function func(x) ! use defs_basis ! real(dp),intent(in) :: x(:) ! real(dp) :: func(SIZE(x)) ! end function func !end interface !Local variables------------------------------- !scalars integer :: K,KM,NT,NX,NX0,it,ix real(dp) :: EPS,old_st,st,old_quad,dqromb real(dp) :: TOL character(len=500) :: msg !arrays real(dp),allocatable :: h(:),s(:) real(dp),allocatable :: wx(:),xx(:) ! ************************************************************************* ierr = 0 TOL =tol12 EPS =tol6 ; if (PRESENT(accuracy)) EPS=accuracy NT =20 ; if (PRESENT(ntrial )) NT=ntrial quad =zero select case (qopt) case (1) ! === Trapezoidal, closed form, O(1/N^2) do it=1,NT call trapezoidal_(func,it,xmin,xmax,quad) if (it>5) then ! Avoid spurious early convergence if (ABS(quad-old_quad)5) then ! Avoid spurious early convergence if (ABS(quad-old_quad)4) then ! Avoid spurious early convergence if (ABS(quad-old_quad)4) then ! Avoid spurious early convergence if (ABS(quad-old_quad)=K) then call polyn_interp(h(it-KM:it),s(it-KM:it),zero,quad,dqromb) if (ABS(dqromb)=K) then call polyn_interp(h(it-KM:it),s(it-KM:it),zero,quad,dqromb) !write(std_out,*) quad,dqromb if (ABS(dqromb)1) then !write(std_out,*) quad if (ABS(quad-old_quad)nr) mr=nr write(fmth,*)'(6x,',mr,'(i2,6x))' write(fmt1,*)'(3x,',mr,'f8.3)' write(msg,fmth)(ii,ii=1,mr) call wrtout(unt,msg,mode) !header write(msg,fmt1)REAL (arr(1:mr)) call wrtout(unt,msg,mode) !real part write(msg,fmt1)AIMAG(arr(1:mr)) call wrtout(unt,msg,mode) !imag part end subroutine print_arr1d_spc !!*** !---------------------------------------------------------------------- !!****f* m_numeric_tools/print_arr1d_dpc !! NAME !! print_arr1d_dpc !! !! FUNCTION !! !! INPUTS !! !! OUTPUT !! !! PARENTS !! !! CHILDREN !! !! SOURCE subroutine print_arr1d_dpc(arr,max_r,unit,mode_paral) !This section has been created automatically by the script Abilint (TD). !Do not modify the following lines by hand. #undef ABI_FUNC #define ABI_FUNC 'print_arr1d_dpc' use interfaces_14_hidewrite !End of the abilint section implicit none !Arguments ------------------------------------ !scalars integer,optional,intent(in) :: unit,max_r character(len=4),optional,intent(in) :: mode_paral !arrays complex(dpc),intent(in) :: arr(:) !Local variables------------------------------- !scalars integer :: unt,ii,nr,mr character(len=4) :: mode character(len=500) :: msg character(len=100) :: fmth,fmt1 ! ************************************************************************* unt=std_out ; if (PRESENT(unit )) unt=unit mode='COLL' ; if (PRESENT(mode_paral)) mode=mode_paral mr=15 ; if (PRESENT(max_r )) mr=max_r if (mode/='COLL'.and.mode/='PERS') then write(msg,'(2a)')' Wrong value of mode_paral ',mode MSG_BUG(msg) end if ! ! === Print out matrix === nr=SIZE(arr,DIM=1) ; if (mr>nr) mr=nr write(fmth,*)'(6x,',mr,'(i2,6x))' write(fmt1,*)'(3x,',mr,'f8.3)' write(msg,fmth)(ii,ii=1,mr) call wrtout(unt,msg,mode) !header write(msg,fmt1)REAL (arr(1:mr)) call wrtout(unt,msg,mode) !real part write(msg,fmt1)AIMAG(arr(1:mr)) call wrtout(unt,msg,mode) !imag part end subroutine print_arr1d_dpc !!*** !---------------------------------------------------------------------- !!****f* m_numeric_tools/print_arr2d_spc !! NAME !! print_arr2d_spc !! !! FUNCTION !! !! INPUTS !! !! OUTPUT !! !! PARENTS !! !! CHILDREN !! !! SOURCE subroutine print_arr2d_spc(arr,max_r,max_c,unit,mode_paral) !This section has been created automatically by the script Abilint (TD). !Do not modify the following lines by hand. #undef ABI_FUNC #define ABI_FUNC 'print_arr2d_spc' use interfaces_14_hidewrite !End of the abilint section implicit none !Arguments ------------------------------------ !scalars integer,optional,intent(in) :: unit,max_r,max_c character(len=4),optional,intent(in) :: mode_paral !arrays complex(spc),intent(in) :: arr(:,:) !Local variables------------------------------- !scalars integer :: unt,ii,jj,nc,nr,mc,mr character(len=4) :: mode character(len=500) :: msg character(len=100) :: fmth,fmt1,fmt2 ! ************************************************************************* unt =std_out; if (PRESENT(unit )) unt =unit mode='COLL' ; if (PRESENT(mode_paral)) mode=mode_paral mc =9 ; if (PRESENT(max_c )) mc =max_c mr =9 ; if (PRESENT(max_r )) mr =max_r if (mode/='COLL'.and.mode/='PERS') then write(msg,'(2a)')'Wrong value of mode_paral ',mode MSG_BUG(msg) end if ! ! === Print out matrix === nr=SIZE(arr,DIM=1); if (mr>nr) mr=nr nc=SIZE(arr,DIM=2); if (mc>nc) mc=nc write(fmth,*)'(6x,',mc,'(i2,6x))' write(fmt1,*)'(3x,i2,',mc,'f8.3)' write(fmt2,*)'(5x ,',mc,'f8.3,a)' write(msg,fmth)(jj,jj=1,mc) call wrtout(unt,msg,mode) !header do ii=1,mr write(msg,fmt1)ii,REAL(arr(ii,1:mc)) call wrtout(unt,msg,mode) !real part write(msg,fmt2) AIMAG(arr(ii,1:mc)),ch10 call wrtout(unt,msg,mode) !imag part end do end subroutine print_arr2d_spc !!*** !---------------------------------------------------------------------- !!****f* m_numeric_tools/print_arr2d_dpc !! NAME !! print_arr2d_dpc !! !! FUNCTION !! !! INPUTS !! !! OUTPUT !! !! PARENTS !! !! CHILDREN !! !! SOURCE subroutine print_arr2d_dpc(arr,max_r,max_c,unit,mode_paral) !This section has been created automatically by the script Abilint (TD). !Do not modify the following lines by hand. #undef ABI_FUNC #define ABI_FUNC 'print_arr2d_dpc' use interfaces_14_hidewrite !End of the abilint section implicit none !Arguments ------------------------------------ !scalars integer,optional,intent(in) :: unit,max_r,max_c character(len=4),optional,intent(in) :: mode_paral !arrays complex(dpc),intent(in) :: arr(:,:) !Local variables------------------------------- !scalars integer :: unt,ii,jj,nc,nr,mc,mr character(len=4) :: mode character(len=500) :: msg character(len=100) :: fmth,fmt1,fmt2 ! ************************************************************************* unt =std_out; if (PRESENT(unit )) unt =unit mode='COLL' ; if (PRESENT(mode_paral)) mode=mode_paral mc =9 ; if (PRESENT(max_c )) mc =max_c mr =9 ; if (PRESENT(max_r )) mr =max_r if (mode/='COLL'.and.mode/='PERS') then write(msg,'(2a)')'Wrong value of mode_paral ',mode MSG_BUG(msg) end if ! ! === Print out matrix === nr=SIZE(arr,DIM=1); if (mr>nr) mr=nr nc=SIZE(arr,DIM=2); if (mc>nc) mc=nc write(fmth,*)'(6x,',mc,'(i2,6x))' write(fmt1,*)'(3x,i2,',mc,'f8.3)' write(fmt2,*)'(5x ,',mc,'f8.3,a)' write(msg,fmth)(jj,jj=1,mc) call wrtout(unt,msg,mode) !header do ii=1,mr write(msg,fmt1)ii,REAL(arr(ii,1:mc)) call wrtout(unt,msg,mode) !real part write(msg,fmt2) AIMAG(arr(ii,1:mc)),ch10 call wrtout(unt,msg,mode) !imag part end do end subroutine print_arr2d_dpc !!*** !---------------------------------------------------------------------- !!****f* m_numeric_tools/pade !! NAME !! pade !! !! FUNCTION !! Calculate the pade approximant in zz of the function f calculated at the n points z !! !! SOURCE function pade(n,z,f,zz) !This section has been created automatically by the script Abilint (TD). !Do not modify the following lines by hand. #undef ABI_FUNC #define ABI_FUNC 'pade' !End of the abilint section implicit none !Arguments ------------------------------------ !scalars integer,intent(in) :: n complex(dpc),intent(in) :: zz complex(dpc) :: pade !arrays complex(dpc),intent(in) :: z(n),f(n) !Local variables------------------------------- !scalars complex(dpc) :: a(n) complex(dpc) :: Az(0:n), Bz(0:n) integer :: i ! ************************************************************************* call calculate_pade_a(a,n,z,f) Az(0)=czero Az(1)=a(1) Bz(0)=cone Bz(1)=cone do i=1,n-1 Az(i+1)=Az(i)+(zz-z(i))*a(i+1)*Az(i-1) Bz(i+1)=Bz(i)+(zz-z(i))*a(i+1)*Bz(i-1) end do !write(std_out,*) 'Bz(n)',Bz(n) if (REAL(Bz(n))==zero.and.AIMAG(Bz(n))==zero) write(std_out,*) ' Bz(n) ',Bz(n) pade=Az(n)/Bz(n) !write(std_out,*) 'pade_approx ', pade_approx end function pade !!*** !---------------------------------------------------------------------- !!****f* m_numeric_tools/dpade !! NAME !! dpade !! !! FUNCTION !! Calculate the derivative of the pade approximant in zz of the function f calculated at the n points z !! !! SOURCE function dpade(n,z,f,zz) !This section has been created automatically by the script Abilint (TD). !Do not modify the following lines by hand. #undef ABI_FUNC #define ABI_FUNC 'dpade' !End of the abilint section implicit none !Arguments ------------------------------------ !scalars integer,intent(in) :: n complex(dpc),intent(in) :: zz complex(dpc) :: dpade !arrays complex(dpc),intent(in) :: z(n),f(n) !Local variables------------------------------- !scalars integer :: i !arrays complex(dpc) :: a(n) complex(dpc) :: Az(0:n), Bz(0:n) complex(dpc) :: dAz(0:n), dBz(0:n) ! ************************************************************************* call calculate_pade_a(a,n,z,f) Az(0)=czero Az(1)=a(1) Bz(0)=cone Bz(1)=cone dAz(0)=czero dAz(1)=czero dBz(0)=czero dBz(1)=czero do i=1,n-1 Az(i+1)=Az(i)+(zz-z(i))*a(i+1)*Az(i-1) Bz(i+1)=Bz(i)+(zz-z(i))*a(i+1)*Bz(i-1) dAz(i+1)=dAz(i)+a(i+1)*Az(i-1)+(zz-z(i))*a(i+1)*dAz(i-1) dBz(i+1)=dBz(i)+a(i+1)*Bz(i-1)+(zz-z(i))*a(i+1)*dBz(i-1) end do !write(std_out,*) 'Bz(n)', Bz(n) if (REAL(Bz(n))==zero.and.AIMAG(Bz(n))==zero) write(std_out,*) 'Bz(n)',Bz(n) !pade_approx = Az(n) / Bz(n) dpade=dAz(n)/Bz(n) -Az(n)*dBz(n)/(Bz(n)*Bz(n)) !write(std_out,*) 'pade_approx ', pade_approx end function dpade !!*** !---------------------------------------------------------------------- !!****f* m_numeric_tools/calculate_pade_a !! NAME !! calculate_pade_a !! !! FUNCTION !! !! INPUTS !! !! OUTPUT !! !! PARENTS !! m_numeric_tools !! !! CHILDREN !! !! SOURCE subroutine calculate_pade_a(a,n,z,f) !This section has been created automatically by the script Abilint (TD). !Do not modify the following lines by hand. #undef ABI_FUNC #define ABI_FUNC 'calculate_pade_a' !End of the abilint section implicit none !Arguments ------------------------------------ !scalars integer,intent(in) :: n complex(dpc),intent(in) :: z(n),f(n) complex(dpc),intent(out) :: a(n) !Local variables------------------------------- !scalars integer :: i,j !arrays complex(dpc) :: g(n,n) ! ************************************************************************* g(1,1:n)=f(1:n) do i=2,n do j=i,n if (REAL(g(i-1,j))==zero.and.AIMAG(g(i-1,j))==zero) write(std_out,*) 'g_i(z_j)',i,j,g(i,j) g(i,j)=(g(i-1,i-1)-g(i-1,j)) / ((z(j)-z(i-1))*g(i-1,j)) !write(std_out,*) 'g_i(z_j)',i,j,g(i,j) end do end do do i=1,n a(i)=g(i,i) end do !write(std_out,*) 'a ',a(:) end subroutine calculate_pade_a !!*** !---------------------------------------------------------------------- !!****f* m_numeric_tools/newrap_step !! NAME !! newrap_step !! !! FUNCTION !! Apply single step newton-raphson method to find the root of a complex function !! z_k+1=z_k-f(z_k)/(df/dz(z_k)) !! !! SOURCE function newrap_step(z,f,df) !This section has been created automatically by the script Abilint (TD). !Do not modify the following lines by hand. #undef ABI_FUNC #define ABI_FUNC 'newrap_step' !End of the abilint section implicit none !Arguments ------------------------------------ !scalars complex(dpc),intent(in) :: z,f,df complex(dpc) :: newrap_step !Local variables------------------------------- !scalars real(dp) :: dfm2 ! ************************************************************************* dfm2=ABS(df)*ABS(df) newrap_step= z - (f*CONJG(df))/dfm2 !& z-one/(ABS(df)*ABS(df)) * CMPLX( REAL(f)*REAL(df)+AIMAG(f)*AIMAG(df), -REAL(f)*AIMAG(df)+AIMAG(f)*EAL(df) ) end function newrap_step !!*** !---------------------------------------------------------------------- !!****f* m_numeric_tools/cross_product_int !! NAME !! cross_product_int !! !! FUNCTION !! Return the cross product of two vectors with integer components. !! pure function cross_product_int(vec1,vec2) result(res) !This section has been created automatically by the script Abilint (TD). !Do not modify the following lines by hand. #undef ABI_FUNC #define ABI_FUNC 'cross_product_int' !End of the abilint section implicit none !Arguments ------------------------------------ integer,intent(in) :: vec1(3),vec2(3) integer :: res(3) ! ************************************************************************* res(1)=vec1(2)*vec2(3)-vec1(3)*vec2(2) res(2)=vec1(3)*vec2(1)-vec1(1)*vec2(3) res(3)=vec1(1)*vec2(2)-vec1(2)*vec2(1) end function cross_product_int !!*** !---------------------------------------------------------------------- !!****f* m_numeric_tools/cross_product_rdp !! NAME !! cross_product_rdp !! !! FUNCTION !! Return the cross product of two vectors with real double precision components. !! pure function cross_product_rdp(vec1,vec2) result(res) !This section has been created automatically by the script Abilint (TD). !Do not modify the following lines by hand. #undef ABI_FUNC #define ABI_FUNC 'cross_product_rdp' !End of the abilint section implicit none !Arguments ------------------------------------ real(dp),intent(in) :: vec1(3),vec2(3) real(dp) :: res(3) ! ************************************************************************* res(1)=vec1(2)*vec2(3)-vec1(3)*vec2(2) res(2)=vec1(3)*vec2(1)-vec1(1)*vec2(3) res(3)=vec1(1)*vec2(2)-vec1(2)*vec2(1) end function cross_product_rdp !!*** !---------------------------------------------------------------------- !!****f* m_numeric_tools/l2norm_rdp !! NAME !! l2norm_rdp !! !! FUNCTION !! Return the length (ordinary L2 norm) of a vector. !! pure function l2norm_rdp(vec) result(res) !This section has been created automatically by the script Abilint (TD). !Do not modify the following lines by hand. #undef ABI_FUNC #define ABI_FUNC 'l2norm_rdp' !End of the abilint section implicit none !Arguments ------------------------------------ real(dp),intent(in) :: vec(:) real(dp) :: res ! ************************************************************************* res=SQRT(DOT_PRODUCT(vec,vec)) end function l2norm_rdp !!*** !---------------------------------------------------------------------- !!****f* m_numeric_tools/remove_copies !! NAME !! remove_copies !! !! FUNCTION !! Given an initial set of elements, set_in, return the subset of inequivalent items !! packed in the firt n_out positions of set_in. Use the logical function is_equal !! to define whether two items are equivalent. !! !! INPUTS !! n_in=Initial number of elements. !! is_equal=logical function used to discern if two items are equal. !! !! OUTPUT !! n_out=Number of inequivalent items found. !! !! SIDE EFFECTS !! set_in(3,n_in)= !! In input the initial set of n_in elements !! In output set_in(3,1:n_out) contains the inequivalent elements found. !! !! NOTES !! The routines only deals with arrays of 3D-vectors although generalizing the !! algorithm to nD-space is straightforward. !! !! PARENTS !! m_io_screening !! !! CHILDREN !! !! SOURCE subroutine remove_copies(n_in,set_in,n_out,is_equal) !This section has been created automatically by the script Abilint (TD). !Do not modify the following lines by hand. #undef ABI_FUNC #define ABI_FUNC 'remove_copies' !End of the abilint section implicit none !Arguments ------------------------------------ !scalars integer,intent(in) :: n_in integer,intent(out) :: n_out !arrays real(dp),target,intent(inout) :: set_in(3,n_in) interface function is_equal(k1,k2) use defs_basis real(dp),intent(in) :: k1(3),k2(3) logical :: is_equal end function is_equal end interface !Local variables------------------------------- !scalars integer :: ii,jj logical :: isnew !arrays type rdp1d_pt integer :: idx real(dp),pointer :: rpt(:) end type rdp1d_pt type(rdp1d_pt),allocatable :: Ap(:) ! ************************************************************************* ABI_DATATYPE_ALLOCATE(Ap,(n_in)) Ap(1)%idx = 1 Ap(1)%rpt => set_in(:,1) n_out=1 do ii=2,n_in isnew=.TRUE. do jj=1,n_out if (is_equal(set_in(:,ii),Ap(jj)%rpt(:))) then isnew=.FALSE. exit end if end do if (isnew) then n_out=n_out+1 Ap(n_out)%rpt => set_in(:,ii) Ap(n_out)%idx = ii end if end do ! The n_out inequivalent items are packed first. if (n_out/=n_in) then do ii=1,n_out jj=Ap(ii)%idx set_in(:,ii) = set_in(:,jj) !write(std_out,*) Ap(ii)%idx,Ap(ii)%rpt(:) end do end if ABI_DATATYPE_DEALLOCATE(Ap) end subroutine remove_copies !!*** !---------------------------------------------------------------------- !!****f* m_numeric_tools/denominator !! NAME !! denominator !! !! FUNCTION !! Return the denominator of the rational number dd, sign is not considered. !! !! INPUTS !! dd=The rational number !! tolerance=Absolute tolerance !! !! OUTPUT !! ierr=If /=0 the input number is not rational within the given tolerance. !! !! SOURCE integer function denominator(dd,ierr,tolerance) !This section has been created automatically by the script Abilint (TD). !Do not modify the following lines by hand. #undef ABI_FUNC #define ABI_FUNC 'denominator' !End of the abilint section implicit none !Arguments ------------------------------------ !scalars integer,intent(out) :: ierr real(dp),intent(in) :: dd real(dp),optional,intent(in) :: tolerance !Local variables ------------------------------ !scalars integer,parameter :: largest_integer = HUGE(1) integer :: ii real(dp) :: my_tol !************************************************************************ ii=1 my_tol=0.0001 ; if (PRESENT(tolerance)) my_tol=ABS(tolerance) do if (ABS(dd*ii-NINT(dd*ii)) No terminator. !! -1 --> Assume constant coefficients for a_i and b_i for i>nlev with a_inf = a(nlev) and b_inf = b(nleb) !! 1 --> Same as above but a_inf and b_inf are obtained by averaging over the nlev values. !! aa(nlev)=Set of a_i coefficients. !! bb(nlev)=Set of b_i coefficients. !! nz=Number of points on the z-mesh. !! zpts(nz)=z-mesh. !! !! OUTPUT !! spectrum(nz)=Contains f(z) on the input mesh. !! !! PARENTS !! bsepostproc,m_haydock !! !! CHILDREN !! !! SOURCE subroutine continued_fract(nlev,term_type,aa,bb,nz,zpts,spectrum) !This section has been created automatically by the script Abilint (TD). !Do not modify the following lines by hand. #undef ABI_FUNC #define ABI_FUNC 'continued_fract' !End of the abilint section implicit none !Arguments ------------------------------------ !scalars integer,intent(in) :: nlev,term_type,nz !arrays real(dp),intent(in) :: bb(nlev) complex(dpc),intent(in) :: aa(nlev) complex(dpc),intent(in) :: zpts(nz) complex(dpc),intent(out) :: spectrum(nz) !Local variables ------------------------------ !scalars integer :: it real(dp) :: bb_inf,bg,bu,swap complex(dpc) :: aa_inf character(len=500) :: msg !arrays complex(dpc),allocatable :: div(:),den(:) !************************************************************************ ABI_MALLOC(div,(nz)) ABI_MALLOC(den,(nz)) select case (term_type) case (0) ! No terminator. div=czero case (-1,1) if (term_type==-1) then bb_inf=bb(nlev) aa_inf=aa(nlev) else bb_inf=SUM(bb)/nlev aa_inf=SUM(aa)/nlev end if ! Be careful with the sign of the SQRT. div(:) = half*(bb(nlev)/(bb_inf))**2 * ( zpts-aa_inf - SQRT((zpts-aa_inf)**2 - four*bb_inf**2) ) case (2) MSG_ERROR("To be tested") div = zero if (nlev>4) then bg=zero; bu=zero do it=1,nlev,2 if (it+2 Cartesian fact = one if (PRESENT(units)) then if (units(1:1) == "D" .or. units(1:1) == "d") fact = two_pi/360_dp end if do jj=1,SIZE(carr,DIM=2) do ii=1,SIZE(carr,DIM=1) rho = DBLE(carr(ii,jj)) theta= AIMAG(carr(ii,jj)) * fact carr(ii,jj) = DCMPLX(rho*DCOS(theta), rho*DSIN(theta)) end do end do case ("C","c") ! Cartesian --> Spherical \theta = 2 arctan(y/(rho+x)) fact = one if (PRESENT(units)) then if (units(1:1) == "D" .or. units(1:1) == "d") fact = 360_dp/two_pi end if do jj=1,SIZE(carr,DIM=2) do ii=1,SIZE(carr,DIM=1) rho = SQRT(ABS(carr(ii,jj))) if (rho > tol16) then theta= two * ATAN( AIMAG(carr(ii,jj)) / (DBLE(carr(ii,jj)) + rho) ) else theta= zero end if carr(ii,jj) = DCMPLX(rho, theta*fact) end do end do case default msg = " Wrong value for from: "//TRIM(from) MSG_BUG(msg) end select end subroutine cmplx_sphcart !!*** !---------------------------------------------------------------------- !!****f* m_numeric_tools/pfactorize !! NAME !! pfactorize !! !! FUNCTION !! Factorize a number in terms of an user-specified set of prime factors !! nn = alpha * Prod_i p^i 1) !! !! INPUTS !! nn=The number to be factorized. !! nfactors=The number of factors !! pfactors(nfactors)=The list of prime number e.g. (/ 2, 3, 5, 7, 11 /) !! !! OUTPUT !! powers(nfactors+1)= !! The first nfactors entries are the powers i in Eq.1. powers(nfactors+1) is alpha. !! !! PARENTS !! !! CHILDREN !! !! SOURCE subroutine pfactorize(nn,nfactors,pfactors,powers) !This section has been created automatically by the script Abilint (TD). !Do not modify the following lines by hand. #undef ABI_FUNC #define ABI_FUNC 'pfactorize' !End of the abilint section implicit none !Arguments ------------------------------------ !scalars integer,intent(in) :: nn,nfactors integer,intent(in) :: pfactors(nfactors) integer,intent(out) :: powers (nfactors+1) !Local variables ------------------------------ !scalars integer :: tnn,ifc,fact,ipow,maxpwr ! ************************************************************************* powers=0; tnn=nn fact_loop: do ifc=1,nfactors fact = pfactors (ifc) maxpwr = NINT ( LOG(DBLE(tnn))/LOG(DBLE(fact) ) ) + 1 do ipow=1,maxpwr if (tnn==1) EXIT fact_loop if ( MOD(tnn,fact)==0 ) then tnn=tnn/fact powers(ifc)=powers(ifc) + 1 end if end do end do fact_loop if ( nn /= tnn * PRODUCT( pfactors**powers(1:nfactors)) ) then MSG_BUG('nn/=tnn!') end if powers(nfactors+1) = tnn end subroutine pfactorize !!*** !---------------------------------------------------------------------- !!****f* m_numeric_tools/isordered !! NAME !! isordered !! !! FUNCTION !! Return .TRUE. if values in array arr are ordered. !! Consider that two double precision numbers within tolerance tol are equal. !! !! INPUTS !! nn=Size of arr. !! arr(nn)=The array with real values to be tested. !! direction= ">" for ascending numerical order. !! ">" for decreasing numerical order. !! !! PARENTS !! !! CHILDREN !! !! SOURCE function isordered_rdp(nn,arr,direction,tol) result(isord) !This section has been created automatically by the script Abilint (TD). !Do not modify the following lines by hand. #undef ABI_FUNC #define ABI_FUNC 'isordered_rdp' !End of the abilint section implicit none !Arguments ------------------------------------ !scalars integer,intent(in) :: nn real(dp),intent(in) :: tol logical :: isord character(len=*),intent(in) :: direction !arrays real(dp),intent(in) :: arr(nn) !Local variables ------------------------------ !scalars integer :: ii real(dp) :: prev character(len=500) :: msg ! ************************************************************************* prev = arr(1); isord =.TRUE. SELECT CASE (direction(1:1)) CASE(">") ii=2; do while (ii<=nn .and. isord) if (ABS(arr(ii)-prev) > tol) isord = (arr(ii) >= prev) prev = arr(ii) ii = ii +1 end do CASE("<") ii=2; do while (ii<=nn .and. isord) if (ABS(arr(ii)-prev) > tol) isord = (arr(ii) <= prev) prev = arr(ii) ii = ii +1 end do CASE DEFAULT msg = "Wrong direction: "//TRIM(direction) MSG_ERROR(msg) END SELECT end function isordered_rdp !!*** !---------------------------------------------------------------------- !!****f* m_numeric_tools/stats_eval !! NAME !! stats_eval !! !! FUNCTION !! Helper function used to calculate the statistical parameters of a data set. !! !! INPUT !! arr(:)=Array with the values. !! !! OUTPUT !! stats=Data type storing the parameters of the data set. !! !! PARENTS !! m_shirley !! !! CHILDREN !! !! SOURCE pure function stats_eval(arr) result(stats) !This section has been created automatically by the script Abilint (TD). !Do not modify the following lines by hand. #undef ABI_FUNC #define ABI_FUNC 'stats_eval' !End of the abilint section implicit none !Arguments ------------------------------------ !scalars type(stats_t) :: stats !arrays real(dp),intent(in) :: arr(:) !Local variables ------------------------------ !scalars integer :: ii,nn real(dp) :: xx,x2_sum ! ************************************************************************* !@stats_t stats%min = +HUGE(one) stats%max = -HUGE(one) stats%mean = zero nn = SIZE(arr) do ii=1,nn xx = arr(ii) stats%max = MAX(stats%max, xx) stats%min = MIN(stats%min, xx) stats%mean = stats%mean + xx end do stats%mean = stats%mean/nn ! Two-pass algorithm for the variance (more stable than the single-pass one). x2_sum = zero do ii=1,nn xx = arr(ii) x2_sum = x2_sum + (xx - stats%mean)*(xx - stats%mean) end do if (nn>1) then stats%stdev = x2_sum/(nn-1) stats%stdev = SQRT(ABS(stats%stdev)) else stats%stdev = zero end if end function stats_eval !!*** !---------------------------------------------------------------------- !!****f* m_numeric_tools/wrap2_zero_one !! NAME !! wrap2_zero_one !! !! FUNCTION !! Transforms a real number (num) in its corresponding reduced number !! (red) in the interval [0,1[ where 1 is not included (tol12) !! num=red+shift !! !! INPUTS !! num=real number !! !! OUTPUT !! red=reduced number of num in the interval [0,1[ where 1 is not included !! shift=num-red !! !! PARENTS !! exc_plot,k_neighbors,lin_interpq_gam,m_nesting,m_paw_pwaves_lmn !! pawmkaewf !! !! CHILDREN !! !! SOURCE elemental subroutine wrap2_zero_one(num,red,shift) !This section has been created automatically by the script Abilint (TD). !Do not modify the following lines by hand. #undef ABI_FUNC #define ABI_FUNC 'wrap2_zero_one' !End of the abilint section implicit none !Arguments ------------------------------------ !scalars real(dp),intent(in) :: num real(dp),intent(out) :: red,shift ! ************************************************************************* if (num>zero) then red=mod((num+tol12),one)-tol12 else red=-mod(-(num-one+tol12),one)+one-tol12 end if if(abs(red)zero) then red=mod((num+half-tol12),one)-half+tol12 else red=-mod(-(num-half-tol12),one)+half+tol12 end if if(abs(red)nr1) ir1=ir1-nr1 if(ir2>nr2) ir2=ir2-nr2 if(ir3>nr3) ir3=ir3-nr3 if(pr1==0) pr1=nr1 if(pr2==0) pr2=nr2 if(pr3==0) pr3=nr3 end subroutine interpol3d_indices !!*** !---------------------------------------------------------------------- !!****f* m_numeric_tools/simpson_int !! NAME !! simpson_int !! !! FUNCTION !! Simpson integral of input function !! !! INPUTS !! npts=max number of points on grid for integral !! step = space between integral arguments !! values(npts)=integrand function. !! !! OUTPUT !! int_values(npts)=integral of values. !! !! PARENTS !! eliashberg_1d,evdw_wannier,kramerskronig,m_ebands,m_exc_spectra !! m_numeric_tools,m_phgamma,m_phonons,m_xc_vdw,mka2f,mka2fQgrid,mka2f_tr !! mka2f_tr_lova,mlwfovlp_projpaw,mlwfovlp_radial,outscfcv,radsintr !! !! CHILDREN !! !! SOURCE subroutine simpson_int(npts,step,values,int_values) !This section has been created automatically by the script Abilint (TD). !Do not modify the following lines by hand. #undef ABI_FUNC #define ABI_FUNC 'simpson_int' !End of the abilint section implicit none !Arguments ------------------------------------ !scalars integer,intent(in) :: npts real(dp),intent(in) :: step !arrays real(dp),intent(in) :: values(npts) real(dp),intent(out) :: int_values(npts) !Local variables ------------------------- !scalars integer :: ii real(dp),parameter :: coef1 = 0.375_dp !9.0_dp / 24.0_dp real(dp),parameter :: coef2 = 1.166666666666666666666666667_dp !28.0_dp / 24.0_dp real(dp),parameter :: coef3 = 0.958333333333333333333333333_dp !23.0_dp / 24.0_dp character(len=500) :: msg ! ********************************************************************* if (npts < 6) then write(msg,"(a,i0)")"Number of points in integrand function must be >=6 while it is: ",npts MSG_ERROR(msg) end if !----------------------------------------------------------------- !Simpson integral of input function !----------------------------------------------------------------- !first point is 0: don t store it !do integration equivalent to Simpson O(1/N^4) from NumRec in C p 134 NumRec in Fortran p 128 int_values(1) = coef1*values(1) int_values(2) = int_values(1) + coef2*values(2) int_values(3) = int_values(2) + coef3*values(3) do ii=4,npts-3 int_values(ii) = int_values(ii-1) + values(ii) end do int_values(npts-2) = int_values(npts-3) + coef3*values(npts-2) int_values(npts-1) = int_values(npts-2) + coef2*values(npts-1) int_values(npts ) = int_values(npts-1) + coef1*values(npts ) int_values(:) = int_values(:) * step end subroutine simpson_int !!*** !---------------------------------------------------------------------- !!****f* m_numeric_tools/simpson !! NAME !! simpson !! !! FUNCTION !! Simpson integral of input function !! !! INPUTS !! step = space between integral arguments !! values(npts)=integrand function. !! !! OUTPUT !! integral of values on the full mesh. !! !! PARENTS !! !! CHILDREN !! !! SOURCE function simpson(step,values) result(res) !This section has been created automatically by the script Abilint (TD). !Do not modify the following lines by hand. #undef ABI_FUNC #define ABI_FUNC 'simpson' !End of the abilint section implicit none !Arguments ------------------------------------ !scalars real(dp),intent(in) :: step real(dp) :: res !arrays real(dp),intent(in) :: values(:) !Local variables ------------------------- !scalars real(dp) :: int_values(size(values)) ! ********************************************************************* call simpson_int(size(values),step,values,int_values) res = int_values(size(values)) end function simpson !!*** !---------------------------------------------------------------------- !!****f* m_numeric_tools/rhophi !! NAME !! rhophi !! !! FUNCTION !! Compute the phase and the module of a complex number. !! The phase angle is fold into the interval [-pi,pi] !! !! INPUTS !! cx(2) = complex number !! !! OUTPUT !! phi = phase of cx fold into [-pi,pi] !! rho = modul of cx !! !! PARENTS !! berryphase_new,etheta,linemin !! !! SOURCE pure subroutine rhophi(cx,phi,rho) !This section has been created automatically by the script Abilint (TD). !Do not modify the following lines by hand. #undef ABI_FUNC #define ABI_FUNC 'rhophi' !End of the abilint section implicit none !Arguments ------------------------------------ !scalars real(dp),intent(out) :: phi,rho !arrays real(dp),intent(in) :: cx(2) ! *********************************************************************** rho = sqrt(cx(1)*cx(1) + cx(2)*cx(2)) if (abs(cx(1)) > tol8) then phi = atan(cx(2)/cx(1)) ! phi is an element of [-pi,pi] if (cx(1) < zero) then if (phi < zero) then phi = phi + pi else phi = phi - pi end if end if else if (cx(2) > tol8) then phi = pi*half else if (cx(2) < tol8) then phi = -0.5_dp*pi else phi = 0 end if end if end subroutine rhophi !!*** !---------------------------------------------------------------------- !!****f* m_numeric_tools/vdiff_eval !! NAME !! vdiff_eval !! !! FUNCTION !! Estimate the "distance" between two functions tabulated on a homogeneous grid. !! See vdiff_t !! !! INPUTS !! cplex=1 if f1 and f2 are real, 2 for complex. !! nr=Number of points in the mesh. !! f1(cplex,nr), f2(cplex,nr)=Vectors with values !! !! OUTPUT !! vdiff_t object !! !! PARENTS !! !! SOURCE pure function vdiff_eval(cplex,nr,f1,f2,volume) result(vd) !This section has been created automatically by the script Abilint (TD). !Do not modify the following lines by hand. #undef ABI_FUNC #define ABI_FUNC 'vdiff_eval' !End of the abilint section implicit none !Arguments ------------------------------------ !scalars integer,intent(in) :: cplex,nr real(dp),intent(in) :: volume type(vdiff_t) :: vd !arrays real(dp),intent(in) :: f1(cplex,nr),f2(cplex,nr) !Local variables------------------------------- !scalars integer :: ir real(dp) :: num,den,dr type(stats_t) :: stats !arrays real(dp) :: abs_diff(nr) ! ********************************************************************* dr = volume / nr if (cplex == 1) then abs_diff = abs(f1(1,:) - f2(1,:)) num = sum(abs_diff) den = sum(abs(f2(1,:))) else if (cplex == 2) then do ir=1,nr abs_diff(ir) = sqrt((f1(1,ir) - f2(1,ir))**2 + (f1(2,ir) - f2(2,ir))**2) end do num = sum(abs_diff) den = zero do ir=1,nr den = den + sqrt(f2(1,ir)**2 + f2(2,ir)**2) end do end if vd%int_adiff = num * dr vd%l1_rerr = num / den stats = stats_eval(abs_diff) vd%mean_adiff = stats%mean vd%stdev_adiff = stats%stdev vd%min_adiff = stats%min vd%max_adiff = stats%max end function vdiff_eval !!*** !---------------------------------------------------------------------- !!****f* m_numeric_tools/vdiff_print !! NAME !! vdiff_print !! !! FUNCTION !! Print vdiff_t to unit !! !! PARENTS !! m_dvdb,mrgdv !! !! CHILDREN !! !! SOURCE subroutine vdiff_print(vd,unit) !This section has been created automatically by the script Abilint (TD). !Do not modify the following lines by hand. #undef ABI_FUNC #define ABI_FUNC 'vdiff_print' !End of the abilint section implicit none !Arguments ------------------------------------ !scalars integer,optional,intent(in) :: unit type(vdiff_t),intent(in) :: vd !Local variables------------------------------- !scalars integer :: unt ! ********************************************************************* unt = std_out; if (present(unit)) unt = unit write(unt,"(2(a,es10.3))")" l1_rerr=",vd%l1_rerr,", \int|f1-f2|dr=",vd%int_adiff write(unt,"(4(a,es10.3))")" Max{|f1-f2|}=",vd%max_adiff,", min{|f1-f2|}=",vd%min_adiff,& ", Mean{|f1-f2|}=",vd%mean_adiff,", stdev{|f1-f2|}=",vd%stdev_adiff end subroutine vdiff_print !!*** !---------------------------------------------------------------------- END MODULE m_numeric_tools !!*** v_sim-3.8.0/lib/plug-ins/abinit/m_profiling_abi.F90000066400000000000000000000572661370110300500220170ustar00rootroot00000000000000!!****m* ABINIT/m_profiling_abi !! NAME !! m_profiling_abi !! !! FUNCTION !! This module is used for tracing memory allocations/deallocations !! when we compile the code with --enable-memory-profiling="yes" that, in turns, defines HAVE_MEM_PROFILE. !! !! COPYRIGHT !! Copyright (C) 2010-2016 ABINIT group (MG) !! This file is distributed under the terms of the !! GNU General Public License, see ~abinit/COPYING !! or http://www.gnu.org/copyleft/gpl.txt . !! !! NOTES !! * This module is not thread-safe. However, this should not represent !! a significant limitation since memory-tracing is only enabled in debug mode. #if defined HAVE_CONFIG_H #include "config.h" #endif #include "abi_common.h" module m_profiling_abi use defs_basis #ifdef HAVE_MPI2 use mpi #endif implicit none private !!*** #if defined HAVE_MPI1 include 'mpif.h' #endif #ifdef HAVE_MEM_PROFILING #define _ABORT(msg) call abimem_abort(msg, __FILE__, ABI_FUNC, __LINE__) public :: abimem_get_info public :: abimem_init public :: abimem_shutdown public :: abimem_set_opts public :: abimem_report public :: abimem_record ! Central routine to be used for allocation/deallocation !public :: abimem_enable !public :: abimem_disable !public :: abimem_reset integer,private,parameter :: slen = 500 !!****t* m_profiling_abi/abimem_t !! NAME !! minfo_t !! !! FUNCTION !! Store information on the memory allocated at run-time !! !! SOURCE !Memory profiling type :: abimem_t integer(kind=8) :: memory = int(0, kind=8) integer(kind=8) :: peak = int(0, kind=8) character(len=slen) :: func = "_func" character(len=slen) :: vname = "_vname" end type abimem_t !!*** ! PRIVATE STUFF ! Selective memory tracing character(fnlen),parameter :: NONE_STRING = "__NONE_STRING__" character(fnlen),save :: select_file = NONE_STRING character(fnlen),save :: select_func = NONE_STRING ! Save values for memocc_abi. real(dp),save :: abimem_limit = zero logical,save :: abimem_isinit = .False. integer,parameter :: logunt = 99 character(len=fnlen),save :: abimem_file type(abimem_t),save :: memloc_abi, memtot_abi integer,save :: num_alloc = 0 integer,save :: num_free = 0 integer,save :: my_rank = 0 !Debug option for memocc_abi, set in the input file !logical,parameter :: abimem_debug=.True. !logical,save :: abimem_ilog = .False. integer,save :: abimem_level = 0 !real(dp),private,save :: start_time ! Origin of time in seconds. real(dp),private,save :: last_snapshot = -one ! time of the last snapshot in seconds. real(dp),private,save :: dt_snapshot = -one ! time between two consecutive snapshots in seconds. contains !!****f* m_profiling_abi/abimem_init !! NAME !! abimem_init !! !! FUNCTION !! !! INPUT !! level = Integer selecting the operation mode: !! 0 no file abimem.mocc is created, only memory allocation counters running !! 1 file abimem.mocc is created in a light version (only current information is written) !! 2 file abimem.mocc is created with full information inside (default state if not specified) !! The status can only be downgraded. A stop signal is produced if status is increased !! [deltat] !! [filename] = If present, activate memory logging only inside filename. !! [funcname] = If present, activate memory logging only inside funcname. subroutine abimem_init(level, deltat, filename, funcname) !This section has been created automatically by the script Abilint (TD). !Do not modify the following lines by hand. #undef ABI_FUNC #define ABI_FUNC 'abimem_init' !End of the abilint section implicit none !This section has been created automatically by the script Abilint (TD). !Do not modify the following lines by hand. #undef ABI_FUNC #define ABI_FUNC 'abimem_init' !End of the abilint section !Arguments ------------------------------------ integer, intent(in) :: level real(dp),optional,intent(in) :: deltat character(len=*),optional,intent(in) :: filename, funcname !Local variables------------------------------- integer :: ierr logical :: file_exists ! ************************************************************************* !if (level > abimem_level) stop 'abimem_level can be only downgraded' abimem_level = level abimem_isinit = .True. !start_time = abimem_wtime() ! Build name of file used for logging. my_rank = 0 #if defined HAVE_MPI call MPI_COMM_RANK(MPI_COMM_WORLD, my_rank, ierr) #endif write(abimem_file,"(a,i0,a)")"abimem_rank",my_rank,".mocc" ! Optionally, selects functions or files to be profiled. if (present(filename)) then if (len_trim(filename) > 0) select_file = filename end if if (present(funcname)) then if (len_trim(funcname) > 0) select_func = funcname endif ! Clean the file if it already exists. ! The file should be deleted inquire(file=abimem_file, exist=file_exists) if (file_exists) then open(unit=logunt, file=abimem_file, status="old", iostat=ierr) if (ierr==0) close(unit=logunt, status="delete", iostat=ierr) end if ! Activate snapshots if (present(deltat)) then dt_snapshot = deltat last_snapshot = zero if (deltat < 1.0e-6) then _ABORT("deltat is too small") end if end if select case (level) case (0) ! No action required case (1) open(unit=logunt, file=abimem_file, status='unknown', action='write', iostat=ierr) if (ierr /= 0) then _ABORT("Opening abimem file") end if write(logunt,'(a,t60,a,t90,4(1x,a12))')& '(Data in KB) Routine','Array name ','Array size','Total Memory' case (2) open(unit=logunt, file=abimem_file, status='unknown', action='write', iostat=ierr) if (ierr /= 0) then _ABORT("Opening abimem file") end if write(logunt,'(a,t60,a,t90,4(1x,a12))')& '(Data in KB) Routine','Array name ','Array size','Total Memory' case default _ABORT("invalid abimem_level") end select end subroutine abimem_init !!*** !!****f* m_profiling_abi/abimem_shutdown !! NAME !! abimem_shutdowns !! !! FUNCTION !! Perform final cleanup of the module and close files. !! !! INPUT subroutine abimem_shutdown() !This section has been created automatically by the script Abilint (TD). !Do not modify the following lines by hand. #undef ABI_FUNC #define ABI_FUNC 'abimem_shutdown' !End of the abilint section implicit none !Local variables------------------------------- integer :: unt_found logical :: isopen ! ************************************************************************* abimem_level = 0; abimem_isinit = .False. ! Close the file if it's connected inquire(file=abimem_file, number=unt_found, opened=isopen) if (isopen .and. (unt_found==logunt)) close(logunt) end subroutine abimem_shutdown !!*** !!****f* m_profiling_abi/abimem_set_opts !! NAME !! abimem_set_opts !! !! FUNCTION !! !! INPUT !! level = Integer selecting the operation mode: !! 0 no file abimem.mocc is created, only memory allocation counters running !! 1 file abimem.mocc is created in a light version (only current information is written) !! 2 file abimem.mocc is created with full information inside (default state if not specified) !! The status can only be downgraded. A stop signal is produced if status is increased !! [limit]= Give a memory limit above which the code will stop properly. The unit is bytes. !! [filename] = If present, activate memory logging only inside filename. !! [funcname] = If present, activate memory logging only inside funcname. !! [deltat] subroutine abimem_set_opts(level, limit, deltat, filename, funcname) !This section has been created automatically by the script Abilint (TD). !Do not modify the following lines by hand. #undef ABI_FUNC #define ABI_FUNC 'abimem_set_opts' !End of the abilint section implicit none !This section has been created automatically by the script Abilint (TD). !Do not modify the following lines by hand. #undef ABI_FUNC #define ABI_FUNC 'abimem_setlogopts' !End of the abilint section !Arguments ------------------------------------ integer, intent(in) :: level real(dp),optional,intent(in) :: limit real(dp),optional,intent(in) :: deltat character(len=*),optional,intent(in) :: filename, funcname ! ************************************************************************* abimem_level = level ! Optionally, set max limit on total memory allocated if (present(limit)) abimem_limit = limit ! Optionally, selects functions or files to be profiles. if (present(filename)) then if (len_trim(filename) > 0) select_file = filename end if if (present(funcname)) then if (len_trim(funcname) > 0) select_func = funcname endif ! Activate snapshots if (present(deltat)) then dt_snapshot = deltat last_snapshot = zero if (deltat < 1.0e-6) then _ABORT("deltat is too small") end if end if end subroutine abimem_set_opts !!*** subroutine abimem_report(unit) !This section has been created automatically by the script Abilint (TD). !Do not modify the following lines by hand. #undef ABI_FUNC #define ABI_FUNC 'abimem_report' !End of the abilint section implicit none !This section has been created automatically by the script Abilint (TD). !Do not modify the following lines by hand. #undef ABI_FUNC #define ABI_FUNC 'abimem_report' !End of the abilint section !Arguments ------------------------------------ integer,optional,intent(in) :: unit !Local variables------------------------------- integer :: unt ! ************************************************************************* unt = std_out; if (present(unit)) unt = unit #if 0 if (trim(func)=='stop' .and. my_rank == 0) then if (abimem_level > 0) then if (abimem_level == 1) rewind(logunt) write(logunt,'(a,t60,a,t90,4(1x,i12))')& trim(memloc_abi%func),trim(memloc_abi%vname),& memloc_abi%memory/int(1024,kind=8),memloc_abi%peak/int(1024,kind=8),& memtot_abi%memory/int(1024,kind=8),& (memtot_abi%peak+memloc_abi%peak-memloc_abi%memory)/int(1024,kind=8) close(unit=logunt) end if write(unt,'(1x,a)')'-------------------------MEMORY CONSUMPTION REPORT-----------------------------' write(unt,'(1x,2(i0,a,1x),i0)')& num_alloc,' allocations and',num_free,' deallocations, remaining memory(B):',memtot_abi%memory write(unt,'(1x,a,i0,a)') 'memory occupation peak: ',memtot_abi%peak/int(1048576,kind=8),' MB' write(unt,'(4(1x,a))') 'for the variable ',trim(memtot_abi%vname),'in the function',trim(memtot_abi%func) !here we can add a func which open the abimem.mocc file in case of some !memory allocation problem, and which eliminates it for a successful run f (abimem_level == 1 .and. num_alloc == num_free .and. memtot_abi%memory==int(0,kind=8)) then !remove file should be put here open(unit=logunt,file=abimem_file,status='unknown',action='write') write(unit=logunt,fmt='()',advance='no') close(unit=logunt) else call abimem_check(num_alloc,num_free) end if else if (trim(func)/='stop') then write(unt,*) "memocc_abi: ",array," ",func write(unt,"(a,i0,a)") "Error[",my_rank,"]: Use memocc_abi and the word 'count' only with the word 'stop'." _ABORT("Exit requested by user") end if #endif end subroutine abimem_report !!*** !!****f* m_profiling_abi/abimem_get_info !! NAME !! abimem_get_info !! !! FUNCTION !! Function that returns the number of allocations and deallocations that have !! been done and the memory currently used !! !! OUTPUT !! nalloc number of allocations that have been done !! ndealloc number of deallocations that have been done !! allocmemory total memory used subroutine abimem_get_info(nalloc, ndealloc, allocmemory) !This section has been created automatically by the script Abilint (TD). !Do not modify the following lines by hand. #undef ABI_FUNC #define ABI_FUNC 'abimem_get_info' !End of the abilint section implicit none !This section has been created automatically by the script Abilint (TD). !Do not modify the following lines by hand. #undef ABI_FUNC #define ABI_FUNC 'abimem_get_info' !End of the abilint section !Arguments ------------------------------------ integer(kind=8), intent(out) :: allocmemory integer, intent(out) :: nalloc,ndealloc ! ************************************************************************* nalloc = num_alloc; ndealloc = num_free; allocmemory = memtot_abi%memory end subroutine abimem_get_info !!*** !!****f* m_profiling_abi/abimem_record !! NAME !! abimem_record !! !! FUNCTION !! Control the memory occupation by calculating the overall size of the allocated arrays !! !! At the end of the calculation a short report is printed on the screen, !! some information can be also written on disk following the needs !! !! The file abimem.mocc is not deleted if the final total memory is not equal to zero. !! abimem_debug (parameter) !! == .true. verbose format (useful with tests/scripts/abimem.py) !! then display a line per allocation or deallocation !! a routine at the end parses the file !! == .false. compact format !! !! PARENTS !! !! CHILDREN !! date_and_time,mpi_abort !! !! SOURCE subroutine abimem_record(istat, vname, addr, act, isize, file, func, line) !This section has been created automatically by the script Abilint (TD). !Do not modify the following lines by hand. #undef ABI_FUNC #define ABI_FUNC 'abimem_record' !End of the abilint section implicit none !Arguments ------------------------------------ integer, intent(in) :: istat,line integer(kind=8), intent(in) :: isize,addr character(len=*), intent(in) :: vname,act,file,func !Local variables------------------------------- integer :: ierr real(dp) :: now logical :: do_log character(len=500) :: msg ! ************************************************************************* ! Handle allocate/deallocate failures !if (istat /= 0) then ! write(msg,('(5a,i0,/,2a,/,a,i0,a)'))& ! 'Procedure: ',trim(funcname),"@",trim(filename),":",line,& ! 'problem of allocation of variable: ',trim(arr_name),& ! 'Error code = ',istat,' Aborting now...' ! call abimem_abort(istat, msg, filename, funcname, line) ! end if !control of the allocation/deallocation status if (istat /= 0) then if (isize >= 0) then write(msg,*)& trim(func),': problem of allocation of variable ',trim(vname),', error code= ',istat _ABORT(msg) else if (isize<0) then write(msg,*)& trim(func),': problem of deallocation of variable ',trim(vname),', error code= ',istat _ABORT(msg) end if end if ! total counter, for all the processes memtot_abi%memory = memtot_abi%memory + isize if (memtot_abi%memory > memtot_abi%peak) then memtot_abi%peak = memtot_abi%memory memtot_abi%func = func memtot_abi%vname = vname end if if (isize > 0) then num_alloc = num_alloc + 1 else if (isize < 0) then num_free = num_free + 1 end if ! This is the correct check but tests fail! !if (act == "A") then ! num_alloc = num_alloc + 1 !else if (act == "D") then ! num_free = num_free + 1 !else ! _ABORT("Wrong action: "//trim(act)) !end if ! Check on memory limit. if (abimem_limit /= zero .and. memtot_abi%memory > int(real(abimem_limit,kind=8)*1073741824.d0,kind=8)) then ! memory limit is in GB write(msg,'(a,f7.3,2(a,i0),a,2(a,i0))')& 'Memory limit of ',abimem_limit,' GB reached for rank ',my_rank,', total memory is ',memtot_abi%memory,' B.',& 'this happened for variable '//trim(memtot_abi%vname)//' in func '//trim(memtot_abi%func) _ABORT(msg) end if ! Selective memory tracing do_log = .True. if (select_file /= NONE_STRING) do_log = (select_file == file) if (select_func /= NONE_STRING) do_log = do_log .and. (select_func == func) !do_log = (do_log .and. my_rank == 0) ! Snapshot if (do_log .and. last_snapshot >= zero) then now = abimem_wtime() if ((now - last_snapshot) >= dt_snapshot) then last_snapshot = now else do_log = .False. end if end if if (do_log) then select case (abimem_level) case (0) ! No action required case (1) ! Compact format if (trim(memloc_abi%func) /= func) then if (memloc_abi%memory /= int(0,kind=8)) then rewind(logunt) write(logunt,'(a,t60,a,t90,4(1x,i12))')& trim(memloc_abi%func),trim(memloc_abi%vname),& memloc_abi%memory/int(1024,kind=8),memloc_abi%peak/int(1024,kind=8),& memtot_abi%memory/int(1024,kind=8),& (memtot_abi%memory+memloc_abi%peak-memloc_abi%memory)/int(1024,kind=8) end if memloc_abi%func = func memloc_abi%vname = vname memloc_abi%memory = isize memloc_abi%peak = isize else memloc_abi%memory=memloc_abi%memory+isize if (memloc_abi%memory > memloc_abi%peak) then memloc_abi%peak = memloc_abi%memory memloc_abi%vname = vname end if end if case (2) !to be used for inspecting a variable which is not deallocated write(logunt,'(a,t60,a,1x,2(i0,1x),2(a,1x),2(i0,1x))')& trim(vname), trim(act), addr, isize, trim(abimem_basename(file)), trim(func), line, memtot_abi%memory case default _ABORT("invalid abimem_level") end select end if end subroutine abimem_record !!*** !!****f* m_profiling_abi/abimem_check !! NAME !! abimem_check !! !! FUNCTION !! Check the abimem.mocc file (verbose format) !! !! PARENTS !! m_profiling_abi !! !! CHILDREN !! date_and_time,mpi_abort !! !! SOURCE subroutine abimem_check(nalloc, ndealloc) !This section has been created automatically by the script Abilint (TD). !Do not modify the following lines by hand. #undef ABI_FUNC #define ABI_FUNC 'abimem_check' !End of the abilint section implicit none !Arguments ------------------------------------ integer, intent(in) :: nalloc,ndealloc ! ************************************************************************* if (abimem_level==2 .and. nalloc /= ndealloc) then write(std_out,"(3a)") & "Use the python script 'abimem.py' in tests/scripts to check ",trim(abimem_file)," file" end if end subroutine abimem_check !!*** !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!! ! Private routine providing services already implemented in other higher level modules. !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!! !!****f* m_abimem/abimem_abort !! NAME !! abimem_abort !! !! FUNCTION !! Stop the code if an error occurs. !! !! INPUT !! msg=Error message !! file=File name !! func=Function name. !! line=Line number !! !! PARENTS !! !! CHILDREN !! date_and_time,mpi_abort !! !! SOURCE subroutine abimem_abort(msg, file, func, line) !This section has been created automatically by the script Abilint (TD). !Do not modify the following lines by hand. #undef ABI_FUNC #define ABI_FUNC 'abimem_abort' !End of the abilint section implicit none !Arguments ------------------------------------ integer,intent(in) :: line character(len=*),intent(in) :: msg,file,func !Local variables------------------------------- integer :: ierr !Local variables------------------------------- integer :: unt_found logical :: isopen ! ************************************************************************* write(std_out,*)msg,file,func,line ! Close abimem_file if it's connected to flush io buffers and avoid file corruption inquire(file=abimem_file, number=unt_found, opened=isopen) if (isopen .and. (unt_found == logunt)) close(unit=logunt) ierr = 0 #ifdef HAVE_MPI call MPI_ABORT(MPI_COMM_WORLD, MPI_ERR_UNKNOWN, ierr) #endif stop end subroutine abimem_abort !!*** !---------------------------------------------------------------------- !!****f* m_profiling_abi/abimem_basename !! NAME !! abimem_basename !! !! FUNCTION !! Returns the final component of a pathname. !! !! INPUTS !! string=The input string !! !! NOTES !! * If the input string in not a valid path to a file (i.e not in the form foo/name) !! a blank strink is returned !! * We do a backward search becase we want to optimize the algorithm for Fortran strings. !! !! SOURCE pure function abimem_basename(string) result(basename) !This section has been created automatically by the script Abilint (TD). !Do not modify the following lines by hand. #undef ABI_FUNC #define ABI_FUNC 'abimem_basename' !End of the abilint section character(len=*),intent(in) :: string character(len=LEN_TRIM(string)) :: basename !Local variables------------------------------- integer :: ic,nch_trim,nch character(len=1),parameter :: DIR_SEPARATOR = '/' character(len=1),parameter :: BLANK=' ' !************************************************************************ nch =LEN (string) nch_trim=LEN_TRIM(string) ic = INDEX (TRIM(string), DIR_SEPARATOR, back=.TRUE.) !write(*,*)'DEBUG ',TRIM(string),ic if (ic >= 1 .and. ic <= nch_trim-1) then ! there is stuff after the separator. basename = string(ic+1:nch_trim) return else if (ic==0 .or. ic == nch_trim+1) then ! no separator in string or zero length string, basename = TRIM(string) ! return trimmed string. return else ! (ic == nch_trim) separator is the last char. basename= BLANK ! This is not a valid path to a file, return blank. return end if end function abimem_basename !!*** !---------------------------------------------------------------------- !!****f* m_time/abimem_wtime !! NAME !! abimem_wtime !! !! FUNCTION !! Return wall clock time in seconds since some arbitrary start. !! Call the F90 intrinsic date_and_time . !! !! INPUTS !! (no inputs) !! !! OUTPUT !! wall= wall clock time in seconds !! !! PARENTS !! !! CHILDREN !! !! SOURCE function abimem_wtime() result(wall) !This section has been created automatically by the script Abilint (TD). !Do not modify the following lines by hand. #undef ABI_FUNC #define ABI_FUNC 'abimem_wtime' !End of the abilint section implicit none !Arguments ------------------------------------ !scalars real(dp) :: wall !Local variables------------------------------- !scalars #ifndef HAVE_MPI integer,parameter :: nday(24)=(/31,28,31,30,31,30,31,31,30,31,30,31,& & 31,28,31,30,31,30,31,31,30,31,30,31/) integer,save :: month_init,month_now,start=1,year_init integer :: months character(len=8) :: date character(len=10) :: time character(len=5) :: zone character(len=500) :: msg !arrays integer :: values(8) #endif ! ************************************************************************* #ifndef HAVE_MPI !The following section of code is standard F90, but it is useful only if the intrinsics !date_and_time is accurate at the 0.01 sec level, which is not the case for a P6 with the pghpf compiler ... !Year and month initialisation if(start==1)then start=0 call date_and_time(date,time,zone,values) year_init=values(1) month_init=values(2) end if !Uses intrinsic F90 subroutine Date_and_time for !wall clock (not correct when a change of year happen) call date_and_time(date,time,zone,values) !Compute first the number of seconds from the beginning of the month wall=(values(3)*24.0d0+values(5))*3600.0d0+values(6)*60.0d0+values(7)+values(8)*0.001d0 !If the month has changed, compute the number of seconds !to be added. This fails if the program ran one year !! month_now=values(2) if(month_now/=month_init)then if(year_init+1==values(1))then month_now=month_now+12 end if if(month_now<=month_init)then msg = 'Problem with month and year numbers.' _ABORT(msg) end if do months=month_init,month_now-1 wall=wall+86400.0d0*nday(months) end do end if !Now take into account bissextile years (I think 2000 is bissextile, but I am not sure ...) if(mod(year_init,4)==0 .and. month_init<=2 .and. month_now>2) wall=wall+3600.0d0 if(mod(values(1),4)==0 .and. month_init<=14 .and. month_now>14) wall=wall+3600.0d0 #else !Use the timer provided by MPI1. wall = MPI_WTIME() #endif end function abimem_wtime !!*** #endif ! HAVE_MEM_PROFILING end module m_profiling_abi !!*** v_sim-3.8.0/lib/plug-ins/abinit/m_xmpi.F90000066400000000000000000004236161370110300500201640ustar00rootroot00000000000000!{\src2tex{textfont=tt}} !!****m* ABINIT/m_xmpi !! NAME !! m_xmpi !! !! FUNCTION !! This module provides MPI named constants, tools for inquiring the MPI environment !! and a set of generic interfaces wrapping the most commonly used MPI primitives. !! !! COPYRIGHT !! Copyright (C) 2009-2016 ABINIT group (MG, MB, XG, YP, MT) !! This file is distributed under the terms of the !! GNU General Public License, see ~abinit/COPYING !! or http://www.gnu.org/copyleft/gpl.txt . !! !! PARENTS !! !! TODO !! Get rid of xmpi_paral. Sequential code is the **exception**. Developers should code parallel !! code or code that is compatible both with MPI and seq (thanks to the wrappers provided by this module) !! !! SOURCE #if defined HAVE_CONFIG_H #include "config.h" #endif #include "abi_common.h" MODULE m_xmpi use defs_basis use m_profiling_abi #ifdef HAVE_FC_ISO_FORTRAN_2008 use ISO_FORTRAN_ENV, only : int16,int32,int64 #endif #ifdef HAVE_MPI2 use mpi #endif #ifdef FC_NAG use f90_unix_proc #endif implicit none private !!*** #ifdef HAVE_MPI1 include 'mpif.h' #endif #ifndef HAVE_FC_ISO_FORTRAN_2008 integer,parameter :: int16=2,int32=4,int64=8 #endif #ifdef HAVE_MPI ! MPI constants used in abinit. Make sure that a corresponding fake value is provided for the sequential version. integer,public,parameter :: xmpi_world = MPI_COMM_WORLD integer,public,parameter :: xmpi_comm_self = MPI_COMM_SELF integer,public,parameter :: xmpi_undefined = MPI_UNDEFINED integer,public,parameter :: xmpi_undefined_rank = MPI_UNDEFINED ! MPI_UNDEFINED_RANK is not portable. integer,public,parameter :: xmpi_comm_null = MPI_COMM_NULL integer,public,parameter :: xmpi_group_null = MPI_GROUP_NULL integer,public,parameter :: xmpi_any_source = MPI_ANY_SOURCE integer,public,parameter :: xmpi_request_null = MPI_REQUEST_NULL integer,public,parameter :: xmpi_msg_len = MPI_MAX_ERROR_STRING ! Length of fortran string used to store MPI error strings. integer,public,parameter :: xmpi_paral = 1 integer,public,parameter :: xmpi_info_null = MPI_INFO_NULL #else ! Fake replacements for the sequential version. integer,public,parameter :: xmpi_world = 0 integer,public,parameter :: xmpi_comm_self = 0 integer,public,parameter :: xmpi_undefined =-32765 integer,public,parameter :: xmpi_undefined_rank =-32766 integer,public,parameter :: xmpi_comm_null = 0 integer,public,parameter :: xmpi_group_null = 0 integer,public,parameter :: xmpi_any_source = 0 integer,public,parameter :: xmpi_request_null = 738197504 integer,public,parameter :: xmpi_msg_len = 1000 integer,public,parameter :: xmpi_paral = 0 integer,public,parameter :: xmpi_info_null = 0 #endif integer,save,private :: xmpi_tag_ub=32767 ! The tag upper bound value must be at least 32767. An MPI implementation is free to make ! the value of MPI_TAG_UB larger than this hence xmpi_tag_ub is redefined when MPI is init in xmpi_init. ! Size in bytes of the entries used in MPI datatypes. integer,save, public ABI_PROTECTED:: xmpi_bsize_ch =0 integer,save, public ABI_PROTECTED:: xmpi_bsize_int=0 integer,save, public ABI_PROTECTED:: xmpi_bsize_sp =0 integer,save, public ABI_PROTECTED:: xmpi_bsize_dp =0 integer,save, public ABI_PROTECTED:: xmpi_bsize_spc=0 integer,save, public ABI_PROTECTED:: xmpi_bsize_dpc=0 ! kind of the offset used for MPI-IO. #ifdef HAVE_MPI_IO integer,public,parameter :: xmpi_offset_kind =MPI_OFFSET_KIND integer,public,parameter :: xmpi_address_kind=MPI_ADDRESS_KIND integer,public,parameter :: xmpi_mpiio=1 #else integer,public,parameter :: xmpi_offset_kind=i8b integer,public,parameter :: xmpi_address_kind=i8b integer,public,parameter :: xmpi_mpiio=0 #endif ! The byte size and the MPI type of the Fortran record marker. ! These quantities are compiler-dependent and are initalized here ! for selected compilers or in xmpio_get_info_frm that is called by xmpi_init (only if MPI-IO is on). #if defined HAVE_MPI && (defined FC_INTEL || defined FC_GNU || defined FC_IBM) integer,save,public ABI_PROTECTED :: xmpio_bsize_frm =4 integer,save,public ABI_PROTECTED :: xmpio_mpi_type_frm=MPI_INTEGER4 #else integer,save,public ABI_PROTECTED :: xmpio_bsize_frm =0 integer,save,public ABI_PROTECTED :: xmpio_mpi_type_frm=0 #endif integer,save, public ABI_PROTECTED :: xmpio_info = xmpi_info_null ! Global variable used to pass hints to the MPI-IO routines. integer(XMPI_OFFSET_KIND),public,parameter :: xmpio_chunk_bsize = 2000 * (1024.0_dp**2) ! Defines the chunk size (in bytes) used to (read|write) data in a single MPI-IO call. ! MPI-IO, indeed, crashes if we try to do the IO of a large array with a single call. ! We use a value <= 2 Gb to avoid wraparound errors with standard integers. ! Options used for the MPI-IO wrappers used in abinit. integer,public,parameter :: xmpio_single =1 ! Individual IO. integer,public,parameter :: xmpio_collective=2 ! Collective IO. !---------------------------------------------------------------------- !!*** ! Public procedures. public :: xmpi_init ! Initialize the MPI environment. public :: xmpi_end ! Terminate the MPI environment. public :: xmpi_abort ! Hides MPI_ABORT from MPI library. public :: xmpi_show_info ! Printout of the basic variables stored in this module (useful for debugging). public :: xmpi_group_free ! Hides MPI_GROUP_FREE from MPI library. public :: xmpi_group_incl ! Hides MPI_GROUP_INCL from MPI library. public :: xmpi_group_translate_ranks ! Hides MPI_GROUP_TRANSLATE_RANKS from MPI library. public :: xmpi_comm_create ! Hides MPI_COMM_CREATE from MPI library. public :: xmpi_comm_rank ! Hides MPI_COMM_RANK from MPI library. public :: xmpi_comm_size ! Hides MPI_COMM_SIZE from MPI library. public :: xmpi_comm_free ! Hides MPI_COMM_FREE from MPI library. public :: xmpi_comm_group ! Hides MPI_COMM_GROUP from MPI library. public :: xmpi_comm_translate_ranks ! Hides MPI_GROUP_TRANSLATE_RANKS from MPI library. public :: xmpi_comm_split ! Hides MPI_COMM_SPLIT from MPI library. public :: xmpi_subcomm ! Creates a sub-communicator from an input communicator. public :: xmpi_barrier ! Hides MPI_BARRIER from MPI library. public :: xmpi_name ! Hides MPI_NAME from MPI library. public :: xmpi_iprobe ! Hides MPI_IPROBE from MPI library. public :: xmpi_wait ! Hides MPI_WAIT from MPI library. public :: xmpi_waitall ! Hides MPI_WAITALL from MPI library. public :: xmpi_request_free ! Hides MPI_REQUEST_FREE from MPI library. public :: xmpi_comm_set_errhandler ! Hides MPI_COMM_SET_ERRHANDLER from MPI library. public :: xmpi_error_string ! Return a string describing the error from ierr. public :: xmpi_split_work public :: xmpi_distab public :: xmpi_distrib_with_replicas ! Distribute tasks among MPI ranks (replicas are allowed) interface xmpi_comm_free module procedure xmpi_comm_free_0D module procedure xmpi_comm_free_1D module procedure xmpi_comm_free_2D module procedure xmpi_comm_free_3D end interface xmpi_comm_free interface xmpi_split_work module procedure xmpi_split_work_i4b end interface xmpi_split_work public :: xmpi_split_work2_i4b public :: xmpi_split_work2_i8b !public :: xmpi_split_work2 ! ! g95@green v0.93 is not able to resolve the interface. ! For the time being, this generic interface has been disabled. !interface xmpi_split_work2 ! module procedure xmpi_split_work2_i4b ! module procedure xmpi_split_work2_i8b !end interface xmpi_split_work2 interface xmpi_distab module procedure xmpi_distab_4D end interface xmpi_distab !MPI generic interfaces. public :: xmpi_allgather public :: xmpi_allgatherv public :: xmpi_alltoall public :: xmpi_ialltoall public :: xmpi_alltoallv public :: xmpi_ialltoallv public :: xmpi_bcast public :: xmpi_exch public :: xmpi_gather public :: xmpi_gatherv public :: xmpi_max public :: xmpi_min public :: xmpi_recv public :: xmpi_irecv public :: xmpi_scatterv public :: xmpi_send public :: xmpi_isend public :: xmpi_sum_master public :: xmpi_sum public :: xmpi_isum public :: xmpi_land ! allreduce with MPI_LAND public :: xmpi_lor ! allreduce with MPI_LOR #ifdef HAVE_MPI_IO public :: xmpio_max_address ! Returns .TRUE. if offset cannot be stored in integer(kind=XMPI_ADDRESS_KIND). public :: xmpio_type_struct public :: xmpio_get_info_frm public :: xmpio_check_frmarkers public :: xmpio_read_frm public :: xmpio_read_int public :: xmpio_read_dp public :: xmpio_write_frm public :: xmpio_write_frmarkers public :: xmpio_create_fstripes public :: xmpio_create_fsubarray_2D public :: xmpio_create_fsubarray_3D public :: xmpio_create_fsubarray_4D public :: xmpio_create_fherm_packed public :: xmpio_create_coldistr_from_fpacked public :: xmpio_create_coldistr_from_fp3blocks !interface xmpio_read ! module procedure xmpio_read_int ! module procedure xmpio_read_dp !end interface xmpio_read ! !interface xmpio_write ! module procedure xmpio_write_int ! module procedure xmpio_write_dp !end interface xmpio_write #endif !---------------------------------------------------------------------- interface xmpi_allgather module procedure xmpi_allgather_int module procedure xmpi_allgather_char module procedure xmpi_allgather_int1d module procedure xmpi_allgather_dp1d module procedure xmpi_allgather_dp2d module procedure xmpi_allgather_dp3d module procedure xmpi_allgather_dp4d end interface xmpi_allgather !---------------------------------------------------------------------- interface xmpi_allgatherv module procedure xmpi_allgatherv_int2d module procedure xmpi_allgatherv_int module procedure xmpi_allgatherv_int1_dp1 module procedure xmpi_allgatherv_dp module procedure xmpi_allgatherv_dp2d module procedure xmpi_allgatherv_dp3d module procedure xmpi_allgatherv_dp4d module procedure xmpi_allgatherv_coeff2d module procedure xmpi_allgatherv_coeff2d_indx end interface xmpi_allgatherv !---------------------------------------------------------------------- ! blocking interface xmpi_alltoall module procedure xmpi_alltoall_int module procedure xmpi_alltoall_dp2d module procedure xmpi_alltoall_dp4d end interface xmpi_alltoall ! non-blocking version (requires MPI3) ! Prototype: ! ! call xmpi_ialltoall(xval, sendsize, recvbuf, recvsize, comm, request) ! ! If the MPI library does not provide ialltoall, we call the blocking version and ! we return xmpi_request_null (see xmpi_ialltoall.finc) ! Client code should always test/wait the request so that code semantics is preserved. interface xmpi_ialltoall module procedure xmpi_ialltoall_dp4d end interface xmpi_ialltoall !---------------------------------------------------------------------- interface xmpi_alltoallv module procedure xmpi_alltoallv_dp2d module procedure xmpi_alltoallv_int2d module procedure xmpi_alltoallv_dp1d module procedure xmpi_alltoallv_dp1d2 end interface xmpi_alltoallv !---------------------------------------------------------------------- ! non-blocking version (requires MPI3) ! Prototype: ! ! call xmpi_ialltoallv(xval,sendcnts,sdispls,recvbuf,recvcnts,rdispls,comm,request) ! ! If the MPI library does not provide ialltoallv, we call the blocking version and ! we return xmpi_request_null (see xmpi_ialltoallv.finc) ! Client code should always test/wait the request so that code semantics is preserved. interface xmpi_ialltoallv module procedure xmpi_ialltoallv_dp2d module procedure xmpi_ialltoallv_int2d module procedure xmpi_ialltoallv_dp1d2 end interface xmpi_ialltoallv !---------------------------------------------------------------------- interface xmpi_bcast module procedure xmpi_bcast_intv module procedure xmpi_bcast_int1d module procedure xmpi_bcast_int2d module procedure xmpi_bcast_int3d module procedure xmpi_bcast_dpv module procedure xmpi_bcast_dp1d module procedure xmpi_bcast_dp2d module procedure xmpi_bcast_dp3d module procedure xmpi_bcast_dp4d module procedure xmpi_bcast_spv module procedure xmpi_bcast_sp1d module procedure xmpi_bcast_sp2d module procedure xmpi_bcast_sp3d module procedure xmpi_bcast_sp4d module procedure xmpi_bcast_cplxv module procedure xmpi_bcast_cplx1d module procedure xmpi_bcast_cplx2d module procedure xmpi_bcast_cplx3d module procedure xmpi_bcast_cplx4d module procedure xmpi_bcast_dcv module procedure xmpi_bcast_dc1d module procedure xmpi_bcast_dc2d module procedure xmpi_bcast_dc3d module procedure xmpi_bcast_dc4d module procedure xmpi_bcast_ch0d module procedure xmpi_bcast_ch1d module procedure xmpi_bcast_log0d module procedure xmpi_bcast_coeffi2_1d module procedure xmpi_bcast_coeff2_1d end interface xmpi_bcast !---------------------------------------------------------------------- interface xmpi_exch module procedure xmpi_exch_intn module procedure xmpi_exch_int2d module procedure xmpi_exch_dpn module procedure xmpi_exch_dp2d module procedure xmpi_exch_dp3d module procedure xmpi_exch_dp4d_tag module procedure xmpi_exch_dp5d_tag module procedure xmpi_exch_spc_1d module procedure xmpi_exch_dpc_1d module procedure xmpi_exch_dpc_2d end interface xmpi_exch !---------------------------------------------------------------------- interface xmpi_gather module procedure xmpi_gather_int module procedure xmpi_gather_int2d module procedure xmpi_gather_dp module procedure xmpi_gather_dp2d module procedure xmpi_gather_dp3d module procedure xmpi_gather_dp4d end interface xmpi_gather !---------------------------------------------------------------------- interface xmpi_gatherv module procedure xmpi_gatherv_int module procedure xmpi_gatherv_int1_dp1 module procedure xmpi_gatherv_int2d module procedure xmpi_gatherv_dp module procedure xmpi_gatherv_dp2d module procedure xmpi_gatherv_dp3d module procedure xmpi_gatherv_dp4d end interface xmpi_gatherv !---------------------------------------------------------------------- interface xmpi_max module procedure xmpi_max_int0d_i4b module procedure xmpi_max_int0d_i8b module procedure xmpi_max_int module procedure xmpi_max_dpv module procedure xmpi_max_dp0d_ip end interface xmpi_max !---------------------------------------------------------------------- interface xmpi_min module procedure xmpi_min_intv module procedure xmpi_min_dpv end interface xmpi_min !---------------------------------------------------------------------- !interface xmpi_min_max ! module procedure xmpi_min_max_int0d_i4b !end interface xmpi_min_max !---------------------------------------------------------------------- interface xmpi_recv module procedure xmpi_recv_intv module procedure xmpi_recv_int1d module procedure xmpi_recv_int2d module procedure xmpi_recv_dp1d module procedure xmpi_recv_dp2d module procedure xmpi_recv_dp3d end interface xmpi_recv !---------------------------------------------------------------------- interface xmpi_irecv module procedure xmpi_irecv_intv module procedure xmpi_irecv_int1d module procedure xmpi_irecv_dp1d end interface xmpi_irecv !---------------------------------------------------------------------- interface xmpi_scatterv module procedure xmpi_scatterv_int module procedure xmpi_scatterv_int2d module procedure xmpi_scatterv_dp module procedure xmpi_scatterv_dp2d module procedure xmpi_scatterv_dp3d module procedure xmpi_scatterv_dp4d end interface xmpi_scatterv !---------------------------------------------------------------------- interface xmpi_isend module procedure xmpi_isend_int1d module procedure xmpi_isend_dp1d end interface xmpi_isend !---------------------------------------------------------------------- interface xmpi_send module procedure xmpi_send_intv module procedure xmpi_send_int1d module procedure xmpi_send_int2d module procedure xmpi_send_dp1d module procedure xmpi_send_dp2d module procedure xmpi_send_dp3d end interface xmpi_send !---------------------------------------------------------------------- interface xmpi_sum_master module procedure xmpi_sum_master_int module procedure xmpi_sum_master_int2d module procedure xmpi_sum_master_int4d module procedure xmpi_sum_master_dp1d module procedure xmpi_sum_master_dp2d module procedure xmpi_sum_master_dp3d module procedure xmpi_sum_master_dp4d module procedure xmpi_sum_master_dp5d module procedure xmpi_sum_master_dp6d module procedure xmpi_sum_master_dp7d module procedure xmpi_sum_master_c1cplx module procedure xmpi_sum_master_c2cplx module procedure xmpi_sum_master_c3cplx module procedure xmpi_sum_master_c4cplx module procedure xmpi_sum_master_c5cplx module procedure xmpi_sum_master_c1dpc module procedure xmpi_sum_master_c2dpc module procedure xmpi_sum_master_c3dpc module procedure xmpi_sum_master_c4dpc module procedure xmpi_sum_master_c5dpc end interface xmpi_sum_master !---------------------------------------------------------------------- !MG:TODO procedure marked with !? are considered obsolete. ! and will be removed in future versions. ! Please use interfaces where array dimensions are not passed explicitly. ! Rationale: The array descriptor is already passed to the routine ! so it does not make sense to pass the dimension explicitly. interface xmpi_sum module procedure xmpi_sum_int module procedure xmpi_sum_intv module procedure xmpi_sum_intv2 module procedure xmpi_sum_intn !? module procedure xmpi_sum_int2t !? module procedure xmpi_sum_int2d module procedure xmpi_sum_int3d module procedure xmpi_sum_int4d module procedure xmpi_sum_dp module procedure xmpi_sum_dpvt module procedure xmpi_sum_dpv module procedure xmpi_sum_dpn !? module procedure xmpi_sum_dp2d module procedure xmpi_sum_dp3d module procedure xmpi_sum_dp4d module procedure xmpi_sum_dp5d module procedure xmpi_sum_dp6d module procedure xmpi_sum_dp7d module procedure xmpi_sum_dp2t !? module procedure xmpi_sum_dp2d2t module procedure xmpi_sum_dp3d2t !? module procedure xmpi_sum_dp4d2t !? module procedure xmpi_sum_c0dc module procedure xmpi_sum_c1dc module procedure xmpi_sum_c2dc module procedure xmpi_sum_c3dc module procedure xmpi_sum_c4dc module procedure xmpi_sum_c5dc module procedure xmpi_sum_c6dc module procedure xmpi_sum_c7dc module procedure xmpi_sum_c1cplx module procedure xmpi_sum_c2cplx module procedure xmpi_sum_c3cplx module procedure xmpi_sum_c4cplx module procedure xmpi_sum_c5cplx module procedure xmpi_sum_c6cplx end interface xmpi_sum !!*** interface xmpi_isum module procedure xmpi_isum_int0d end interface xmpi_isum !!*** interface xmpi_land module procedure xmpi_land_log0d end interface xmpi_land !!*** interface xmpi_lor module procedure xmpi_lor_log1d module procedure xmpi_lor_log2d module procedure xmpi_lor_log3d end interface xmpi_lor !!!*** !---------------------------------------------------------------------- CONTAINS !=========================================================== !!*** !!****f* m_xmpi/xmpi_init !! NAME !! xmpi_init !! !! FUNCTION !! Hides MPI_INIT from MPI library. Perform the initialization of some basic variables !! used by the MPI routines employed in abinit. !! !! INPUTS !! None !! !! PARENTS !! abinit,aim,anaddb,band2eps,bsepostproc,conducti,cut3d,fftprof !! fold2Bloch,ioprof,lapackprof,macroave,mrgddb,mrgdv,mrggkk,mrgscr,optic !! ujdet,vdw_kernelgen !! !! CHILDREN !! mpi_type_commit,mpi_type_size,xmpi_abort,xmpio_type_struct !! !! SOURCE subroutine xmpi_init() !This section has been created automatically by the script Abilint (TD). !Do not modify the following lines by hand. #undef ABI_FUNC #define ABI_FUNC 'xmpi_init' !End of the abilint section implicit none !Local variables------------------- integer :: mpierr,ierr,unt logical :: exists,isopen #ifdef HAVE_MPI integer :: attribute_val,required,provided logical :: lflag #endif ! ************************************************************************* mpierr=0 #ifdef HAVE_MPI #ifndef HAVE_OPENMP call MPI_INIT(mpierr) #else required = MPI_THREAD_SINGLE !required = MPI_THREAD_FUNNELED !required = MPI_THREAD_SERIALIZED !required = MPI_THREAD_MULTIPLE call MPI_INIT_THREAD(required,provided,mpierr) if (provided /= required) then call xmpi_abort(msg="MPI_INIT_THREADS: provided /= required") end if #endif !%comm_world = xmpi_world ! Needed to bypass a bug in some OMPI implementations (intent(inout)) !%call xmpi_comm_set_errhandler(comm_world, MPI_ERRORS_RETURN, err_handler_sav, mpierr) ! Deprecated in MPI2 but not all MPI2 implementations provide MPI_Comm_get_attr ! call MPI_ATTR_GET(xmpi_world, MPI_TAG_UB, attribute_val, lflag, mpierr) !call MPI_Comm_get_attr(xmpi_world, MPI_TAG_UB, attribute_val, lflag, mpierr) if (lflag) xmpi_tag_ub = attribute_val ! Define type values. call MPI_TYPE_SIZE(MPI_CHARACTER,xmpi_bsize_ch,mpierr) call MPI_TYPE_SIZE(MPI_INTEGER,xmpi_bsize_int,mpierr) call MPI_TYPE_SIZE(MPI_REAL,xmpi_bsize_sp,mpierr) call MPI_TYPE_SIZE(MPI_DOUBLE_PRECISION,xmpi_bsize_dp,mpierr) call MPI_TYPE_SIZE(MPI_COMPLEX,xmpi_bsize_spc,mpierr) call MPI_TYPE_SIZE(MPI_DOUBLE_COMPLEX,xmpi_bsize_dpc,mpierr) ! Find the byte size of Fortran record marker used in MPI-IO routines. if (xmpio_bsize_frm == 0) then call xmpio_get_info_frm(xmpio_bsize_frm, xmpio_mpi_type_frm, xmpi_world) end if #endif ! Master Removes the ABI_MPIABORTFILE if present so that we start with a clean environment if (xmpi_comm_rank(xmpi_world) == 0) then inquire(file=ABI_MPIABORTFILE, exist=exists) if (exists) then ! Get free unit (emulate F2008 newunit for portability reasons) unt = xmpi_get_unit() if (unt == -1) call xmpi_abort(msg="Cannot find free unit!!") open(unit=unt, file=trim(ABI_MPIABORTFILE), status="old", iostat=ierr) if (ierr == 0) close(unit=unt, status="delete", iostat=ierr) if (ierr /= 0) call xmpi_abort(msg="Cannot remove ABI_MPIABORTFILE") end if end if end subroutine xmpi_init !!*** !---------------------------------------------------------------------- !!****f* m_xmpi/xmpi_get_unit !! NAME !! xmpi_get_unit !! !! FUNCTION !! Get free unit (emulate F2008 newunit for portability reasons) !! Return -1 if no unit is found. !! !! PARENTS !! !! CHILDREN !! !! SOURCE integer function xmpi_get_unit() result(unt) !This section has been created automatically by the script Abilint (TD). !Do not modify the following lines by hand. #undef ABI_FUNC #define ABI_FUNC 'xmpi_get_unit' !End of the abilint section implicit none !Local variables------------------- logical :: isopen ! ************************************************************************* do unt=1024,-1,-1 inquire(unit=unt, opened=isopen) if (.not.isopen) exit end do end function xmpi_get_unit !!*** !---------------------------------------------------------------------- !!****f* m_xmpi/xmpi_end !! NAME !! xmpi_end !! !! FUNCTION !! Hides MPI_FINALIZE from MPI library. !! !! INPUTS !! None !! !! PARENTS !! aim,anaddb,band2eps,bsepostproc,conducti,cut3d,fold2Bloch,lapackprof !! macroave,mrgddb,mrggkk,optic,ujdet,vdw_kernelgen !! !! CHILDREN !! mpi_type_commit,mpi_type_size,xmpi_abort,xmpio_type_struct !! !! SOURCE subroutine xmpi_end() !This section has been created automatically by the script Abilint (TD). !Do not modify the following lines by hand. #undef ABI_FUNC #define ABI_FUNC 'xmpi_end' !End of the abilint section implicit none !Local variables------------------- integer :: mpierr ! ************************************************************************* mpierr=0 #ifdef HAVE_MPI call MPI_BARRIER(MPI_COMM_WORLD,mpierr) ! Needed by some HPC architectures (MT, 20110315) call MPI_FINALIZE(mpierr) #endif end subroutine xmpi_end !!*** !---------------------------------------------------------------------- !!****f* m_xmpi/xmpi_abort !! NAME !! xmpi_abort !! !! FUNCTION !! Hides MPI_ABORT from MPI library. !! !! INPUTS !! [comm]=communicator of tasks to abort. !! [mpierr]=Error code to return to invoking environment. !! [msg]=User message !! [exit_status]=optional, shell return code, default 1 !! !! PARENTS !! initmpi_grid,leave_new,m_initcuda,m_libpaw_tools,m_xmpi,testkgrid !! !! CHILDREN !! mpi_type_commit,mpi_type_size,xmpi_abort,xmpio_type_struct !! !! SOURCE subroutine xmpi_abort(comm,mpierr,msg,exit_status) !This section has been created automatically by the script Abilint (TD). !Do not modify the following lines by hand. #undef ABI_FUNC #define ABI_FUNC 'xmpi_abort' !End of the abilint section implicit none !Arguments------------------------- integer,optional,intent(in) :: comm,mpierr,exit_status character(len=*),optional,intent(in) :: msg !Local variables------------------- integer :: ierr,my_comm,my_errorcode,ilen,ierr2 logical :: testopen character(len=xmpi_msg_len) :: mpi_msg_error ! ************************************************************************* ierr=0 my_comm = xmpi_world; if (PRESENT(comm)) my_comm = comm if (PRESENT(msg)) then write(std_out,'(2a)')"User message: ",TRIM(msg) end if ! Close std_out and ab_out inquire(std_out,opened=testopen) if (testopen) close(std_out) inquire(ab_out,opened=testopen) if (testopen) close(ab_out) #ifdef HAVE_MPI my_errorcode=MPI_ERR_UNKNOWN; if (PRESENT(mpierr)) my_errorcode=mpierr call MPI_ERROR_STRING(my_errorcode, mpi_msg_error, ilen, ierr2) !if (ilen>xmpi_msg_len) write(std_out,*)" WARNING: MPI message has been truncated!" !if (ierr2/=MPI_SUCCESS) then ! write(std_out,'(a,i0)')" WARNING: MPI_ERROR_STRING returned ierr2= ",ierr2 !else ! write(std_out,'(2a)')" MPI_ERROR_STRING: ",TRIM(mpi_msg_error) !end if call MPI_ABORT(my_comm,my_errorcode,ierr) #endif if (present(exit_status)) then call sys_exit(exit_status) else call sys_exit(1) end if end subroutine xmpi_abort !!*** !---------------------------------------------------------------------- !!****f* m_xmpi/sys_exit !! NAME !! sys_exit !! !! FUNCTION !! Routine for clean exit of f90 code by one processor !! !! INPUTS !! exit_status: !! return code. !! !! NOTES !! By default, it uses "call exit(1)", that is not completely portable. !! !! PARENTS !! m_xmpi !! !! CHILDREN !! mpi_type_commit,mpi_type_size,xmpi_abort,xmpio_type_struct !! !! SOURCE subroutine sys_exit(exit_status) !This section has been created automatically by the script Abilint (TD). !Do not modify the following lines by hand. #undef ABI_FUNC #define ABI_FUNC 'sys_exit' !End of the abilint section implicit none !Arguments ------------------------------------ !scalars integer,intent(in) :: exit_status ! ********************************************************************** #if defined FC_NAG call exit(exit_status) #elif defined HAVE_FC_EXIT call exit(exit_status) #else ! stop with exit_status ! MT 06-2013:stop function only accept parameters ! if (exit_status== 0) stop "0" if (exit_status== 1) stop "1" if (exit_status==-1) stop "-1" #endif stop 1 end subroutine sys_exit !!*** !---------------------------------------------------------------------- !!****f* m_xmpi/xmpi_show_info !! NAME !! xmpi_show_info !! !! FUNCTION !! Printout of the most important variables stored in this module (useful for debugging). !! !! INPUTS !! unt=Unit number for formatted output. !! !! PARENTS !! abinit,leave_new,m_errors !! !! CHILDREN !! mpi_type_commit,mpi_type_size,xmpi_abort,xmpio_type_struct !! !! SOURCE subroutine xmpi_show_info(unit) !This section has been created automatically by the script Abilint (TD). !Do not modify the following lines by hand. #undef ABI_FUNC #define ABI_FUNC 'xmpi_show_info' !End of the abilint section implicit none !Arguments------------------------- integer,optional,intent(in) :: unit !Local variables------------------- integer :: my_unt ! ************************************************************************* !@m_xmpi my_unt = std_out; if (PRESENT(unit)) my_unt=unit #ifdef HAVE_MPI1 write(my_unt,*)" ==== Using MPI-1 specifications ==== " #endif #ifdef HAVE_MPI2 write(my_unt,*)" ==== Using MPI-2 specifications ==== " #endif #ifdef HAVE_MPI_IO write(my_unt,*)" MPI-IO support is ON" #else write(my_unt,*)" MPI-IO support is OFF" #endif #ifdef HAVE_MPI write(my_unt,*)" xmpi_tag_ub ................ ",xmpi_tag_ub write(my_unt,*)" xmpi_bsize_ch .............. ",xmpi_bsize_ch write(my_unt,*)" xmpi_bsize_int ............. ",xmpi_bsize_int write(my_unt,*)" xmpi_bsize_sp .............. ",xmpi_bsize_sp write(my_unt,*)" xmpi_bsize_dp .............. ",xmpi_bsize_dp write(my_unt,*)" xmpi_bsize_spc ............. ",xmpi_bsize_spc write(my_unt,*)" xmpi_bsize_dpc ............. ",xmpi_bsize_dpc write(my_unt,*)" xmpio_bsize_frm ............ ",xmpio_bsize_frm write(my_unt,*)" xmpi_address_kind .......... ",xmpi_address_kind write(my_unt,*)" xmpi_offset_kind ........... ",xmpi_offset_kind write(my_unt,*)" MPI_WTICK .................. ",MPI_WTICK() #endif end subroutine xmpi_show_info !!*** !---------------------------------------------------------------------- !!****f* m_xmpi/xmpi_comm_rank !! NAME !! xmpi_comm_rank !! !! FUNCTION !! Hides MPI_COMM_RANK from MPI library. !! !! INPUTS !! comm=MPI communicator. !! !! OUTPUT !! xmpi_comm_rank=The rank of the node inside comm !! !! PARENTS !! !! SOURCE function xmpi_comm_rank(comm) !This section has been created automatically by the script Abilint (TD). !Do not modify the following lines by hand. #undef ABI_FUNC #define ABI_FUNC 'xmpi_comm_rank' !End of the abilint section implicit none !Arguments------------------------- integer,intent(in) :: comm integer :: xmpi_comm_rank !Local variables------------------- integer :: mpierr ! ************************************************************************* mpierr=0 #ifdef HAVE_MPI xmpi_comm_rank=-1 ! Return non-sense value if the proc does not belong to the comm if (comm/=xmpi_comm_null) then call MPI_COMM_RANK(comm,xmpi_comm_rank,mpierr) end if #else xmpi_comm_rank=0 #endif end function xmpi_comm_rank !!*** !---------------------------------------------------------------------- !!****f* m_xmpi/xmpi_comm_size !! NAME !! xmpi_comm_size !! !! FUNCTION !! Hides MPI_COMM_SIZE from MPI library. !! !! INPUTS !! comm=MPI communicator. !! !! OUTPUT !! xmpi_comm_size=The number of processors inside comm. !! !! PARENTS !! !! SOURCE function xmpi_comm_size(comm) !This section has been created automatically by the script Abilint (TD). !Do not modify the following lines by hand. #undef ABI_FUNC #define ABI_FUNC 'xmpi_comm_size' !End of the abilint section implicit none !Arguments------------------------- integer,intent(in) :: comm integer :: xmpi_comm_size !Local variables------------------------------- !scalars integer :: mpierr ! ************************************************************************* mpierr=0; xmpi_comm_size=1 #ifdef HAVE_MPI if (comm/=xmpi_comm_null) then call MPI_COMM_SIZE(comm,xmpi_comm_size,mpierr) end if #endif end function xmpi_comm_size !!*** !---------------------------------------------------------------------- !!****f* m_xmpi/xmpi_comm_free_0D !! NAME !! xmpi_comm_free_0D !! !! FUNCTION !! Hides MPI_COMM_FREE from MPI library. !! Does not abort MPI in case of an invalid communicator !! !! INPUTS !! comm=MPI communicator. !! !! PARENTS !! !! CHILDREN !! mpi_type_commit,mpi_type_size,xmpi_abort,xmpio_type_struct !! !! SOURCE subroutine xmpi_comm_free_0D(comm) !This section has been created automatically by the script Abilint (TD). !Do not modify the following lines by hand. #undef ABI_FUNC #define ABI_FUNC 'xmpi_comm_free_0D' !End of the abilint section implicit none !Arguments------------------------- integer,intent(inout) :: comm !Local variables------------------------------- !scalars #ifdef HAVE_MPI integer :: comm_world,err_handler_dum,err_handler_sav,ierr,mpierr,mpierr_class ! ************************************************************************* if (comm/=xmpi_comm_null.and.comm/=xmpi_world.and.comm/=xmpi_comm_self) then comm_world=xmpi_world ! Needed to bypass a bug in some OMPI implementations (intent(inout)) call xmpi_comm_set_errhandler(comm_world,MPI_ERRORS_RETURN,err_handler_sav,ierr) call MPI_COMM_FREE(comm,mpierr) call xmpi_comm_set_errhandler(comm_world,err_handler_sav,err_handler_dum,ierr) if (mpierr/=MPI_SUCCESS) then call MPI_ERROR_CLASS(mpierr,mpierr_class,ierr) if (mpierr_class/=MPI_ERR_COMM) then write(std_out,*)" WARNING: MPI_COMM_FREE returned ierr= ",mpierr end if end if end if #else if (.false.) write(std_out,*) comm #endif end subroutine xmpi_comm_free_0D !!*** !---------------------------------------------------------------------- !!****f* m_xmpi/xmpi_comm_free_1D !! NAME !! xmpi_comm_free_1D !! !! FUNCTION !! Hides MPI_COMM_FREE from MPI library. Target 1D arrays !! Does not abort MPI in case of an invalid communicator !! !! INPUTS !! comms(:)=MPI communicators !! !! PARENTS !! !! CHILDREN !! mpi_type_commit,mpi_type_size,xmpi_abort,xmpio_type_struct !! !! SOURCE subroutine xmpi_comm_free_1D(comms) !This section has been created automatically by the script Abilint (TD). !Do not modify the following lines by hand. #undef ABI_FUNC #define ABI_FUNC 'xmpi_comm_free_1D' !End of the abilint section implicit none !Arguments------------------------- integer,intent(inout) :: comms(:) !Local variables------------------------------- !scalars #ifdef HAVE_MPI integer :: comm_world,err_handler_dum,err_handler_sav,ii,mpierr ! ************************************************************************* comm_world=xmpi_world ! Needed to bypass a bug in some OMPI implementations (intent(inout)) call xmpi_comm_set_errhandler(comm_world,MPI_ERRORS_RETURN,err_handler_sav,mpierr) do ii=LBOUND(comms,DIM=1),UBOUND(comms,DIM=1) if (comms(ii)/=xmpi_comm_null.and.comms(ii)/=xmpi_world.and.comms(ii)/=xmpi_comm_self) then call MPI_COMM_FREE(comms(ii),mpierr) end if end do call xmpi_comm_set_errhandler(comm_world,err_handler_sav,err_handler_dum,mpierr) #else if (.false.) write(std_out,*) comms(1) #endif end subroutine xmpi_comm_free_1D !!*** !---------------------------------------------------------------------- !!****f* m_xmpi/xmpi_comm_free_2D !! NAME !! xmpi_comm_free_2D !! !! FUNCTION !! Hides MPI_COMM_FREE from MPI library. Target 2D arrays !! Does not abort MPI in case of an invalid communicator !! !! INPUTS !! comms=MPI communicator. !! !! PARENTS !! !! CHILDREN !! mpi_type_commit,mpi_type_size,xmpi_abort,xmpio_type_struct !! !! SOURCE subroutine xmpi_comm_free_2D(comms) !This section has been created automatically by the script Abilint (TD). !Do not modify the following lines by hand. #undef ABI_FUNC #define ABI_FUNC 'xmpi_comm_free_2D' !End of the abilint section implicit none !Arguments------------------------- integer,intent(inout) :: comms(:,:) !Local variables------------------------------- !scalars #ifdef HAVE_MPI integer :: comm_world,err_handler_dum,err_handler_sav,ii,jj,mpierr ! ************************************************************************* comm_world=xmpi_world ! Needed to bypass a bug in some OMPI implementations (intent(inout)) call xmpi_comm_set_errhandler(comm_world,MPI_ERRORS_RETURN,err_handler_sav,mpierr) do jj=LBOUND(comms,DIM=2),UBOUND(comms,DIM=2) do ii=LBOUND(comms,DIM=1),UBOUND(comms,DIM=1) if (comms(ii,jj)/=xmpi_comm_null.and.comms(ii,jj)/=xmpi_world.and. & & comms(ii,jj)/=xmpi_comm_self) then call MPI_COMM_FREE(comms(ii,jj),mpierr) end if end do end do call xmpi_comm_set_errhandler(comm_world,err_handler_sav,err_handler_dum,mpierr) #else if (.false.) write(std_out,*) comms(1,1) #endif end subroutine xmpi_comm_free_2D !!*** !---------------------------------------------------------------------- !!****f* m_xmpi/xmpi_comm_free_3D !! NAME !! xmpi_comm_free_3D !! !! FUNCTION !! Hides MPI_COMM_FREE from MPI library. Target 3D arrays !! Does not abort MPI in case of an invalid communicator !! !! INPUTS !! comms=MPI communicator. !! !! PARENTS !! !! CHILDREN !! mpi_type_commit,mpi_type_size,xmpi_abort,xmpio_type_struct !! !! SOURCE subroutine xmpi_comm_free_3D(comms) !This section has been created automatically by the script Abilint (TD). !Do not modify the following lines by hand. #undef ABI_FUNC #define ABI_FUNC 'xmpi_comm_free_3D' !End of the abilint section implicit none !Arguments------------------------- integer,intent(inout) :: comms(:,:,:) !Local variables------------------------------- !scalars #ifdef HAVE_MPI integer :: comm_world,err_handler_dum,err_handler_sav,ii,jj,kk,mpierr ! ************************************************************************* comm_world=xmpi_world ! Needed to bypass a bug in some OMPI implementations (intent(inout)) call xmpi_comm_set_errhandler(comm_world,MPI_ERRORS_RETURN,err_handler_sav,mpierr) do kk=LBOUND(comms,DIM=3),UBOUND(comms,DIM=3) do jj=LBOUND(comms,DIM=2),UBOUND(comms,DIM=2) do ii=LBOUND(comms,DIM=1),UBOUND(comms,DIM=1) if (comms(ii,jj,kk)/=xmpi_comm_null.and.comms(ii,jj,kk)/=xmpi_world.and. & & comms(ii,jj,kk)/=xmpi_comm_self) then call MPI_COMM_FREE(comms(ii,jj,kk),mpierr) end if end do end do end do call xmpi_comm_set_errhandler(comm_world,err_handler_sav,err_handler_dum,mpierr) #else if (.false.) write(std_out,*) comms(1,1,1) #endif end subroutine xmpi_comm_free_3D !!*** !---------------------------------------------------------------------- !!****f* m_xmpi/xmpi_group_free !! NAME !! xmpi_group_free !! !! FUNCTION !! Hides MPI_GROUP_FREE from MPI library. !! Does not abort MPI in case of an invalid group !! !! INPUTS !! spaceGroup=MPI group !! !! PARENTS !! m_wfd,m_xmpi,pawprt !! !! CHILDREN !! mpi_type_commit,mpi_type_size,xmpi_abort,xmpio_type_struct !! !! SOURCE subroutine xmpi_group_free(spaceGroup) !This section has been created automatically by the script Abilint (TD). !Do not modify the following lines by hand. #undef ABI_FUNC #define ABI_FUNC 'xmpi_group_free' !End of the abilint section implicit none !Arguments------------------------- integer,intent(inout) :: spaceGroup !Local variables------------------------------- !scalars #ifdef HAVE_MPI integer :: comm_world,err_handler_dum,err_handler_sav,ierr,mpierr,mpierr_class ! ************************************************************************* if (spaceGroup/=xmpi_group_null) then comm_world=xmpi_world ! Needed to bypass a bug in some OMPI implementations (intent(inout)) call xmpi_comm_set_errhandler(comm_world,MPI_ERRORS_RETURN,err_handler_sav,ierr) call MPI_GROUP_FREE(spaceGroup,mpierr) call xmpi_comm_set_errhandler(comm_world,err_handler_sav,err_handler_dum,ierr) if (mpierr/=MPI_SUCCESS) then call MPI_ERROR_CLASS(mpierr,mpierr_class,ierr) if (mpierr_class/=MPI_ERR_GROUP) then write(std_out,*)" WARNING: MPI_GROUP_FREE returned ierr= ",mpierr end if end if end if #else if (.false.) write(std_out,*) spaceGroup #endif end subroutine xmpi_group_free !!*** !---------------------------------------------------------------------- !!****f* m_xmpi/xmpi_group_incl !! NAME !! xmpi_group_incl !! !! FUNCTION !! Hides MPI_GROUP_INCL from MPI library. !! !! INPUTS !! group=input group !! nrank=number of elements in array ranks (size of newgroup) !! ranks=ranks of processes in group to appear in newgroup !! !! OUTPUT !! newgroup= new group derived from above, in the order defined by ranks !! !! PARENTS !! m_wfd !! !! CHILDREN !! mpi_type_commit,mpi_type_size,xmpi_abort,xmpio_type_struct !! !! SOURCE subroutine xmpi_group_incl(group,nranks,ranks,newgroup,mpierr) !This section has been created automatically by the script Abilint (TD). !Do not modify the following lines by hand. #undef ABI_FUNC #define ABI_FUNC 'xmpi_group_incl' !End of the abilint section implicit none !Arguments------------------------- !scalars integer,intent(in) :: group,nranks integer,intent(out) :: mpierr integer,intent(inout) :: newgroup !arrays integer,intent(in) :: ranks(nranks) ! ************************************************************************* mpierr=0 ; newgroup=xmpi_group_null #ifdef HAVE_MPI if (group/=xmpi_group_null) then call MPI_GROUP_INCL(group,nranks,ranks,newgroup,mpierr) end if #endif end subroutine xmpi_group_incl !!*** !---------------------------------------------------------------------- !!****f* m_xmpi/xmpi_comm_create !! NAME !! xmpi_comm_create !! !! FUNCTION !! Hides MPI_COMM_CREATE from MPI library. !! !! INPUTS !! comm=communicator !! group=group, which is a subset of the group of comm !! !! OUTPUT !! newcomm=new communicator !! !! PARENTS !! m_wfd !! !! CHILDREN !! mpi_type_commit,mpi_type_size,xmpi_abort,xmpio_type_struct !! !! SOURCE subroutine xmpi_comm_create(comm,group,newcomm,mpierr) !This section has been created automatically by the script Abilint (TD). !Do not modify the following lines by hand. #undef ABI_FUNC #define ABI_FUNC 'xmpi_comm_create' !End of the abilint section implicit none !Arguments------------------------- !scalars integer,intent(in) :: comm,group integer,intent(out) :: mpierr integer,intent(inout) :: newcomm ! ************************************************************************* mpierr=0 #ifdef HAVE_MPI if (group/=xmpi_group_null) then call MPI_comm_create(comm,group,newcomm,mpierr) else newcomm=xmpi_comm_null end if #else newcomm=xmpi_comm_self #endif end subroutine xmpi_comm_create !!*** !---------------------------------------------------------------------- !!****f* m_xmpi/xmpi_subcomm !! NAME !! xmpi_subcomm !! !! FUNCTION !! Return a sub-communicator from an input communicator and a given proc. ranks set. !! (hides subgroup creation/destruction) !! !! INPUTS !! comm=input communicator !! nrank=number of elements in array ranks (size of subcomm) !! ranks=ranks of processes in group to appear in subcomm !! !! OUTPUT !! [my_rank_in_group]=optional: my rank in the group of new sub-communicator !! xmpi_subcomm=new (sub-)communicator !! !! PARENTS !! !! SOURCE function xmpi_subcomm(comm,nranks,ranks,my_rank_in_group) !This section has been created automatically by the script Abilint (TD). !Do not modify the following lines by hand. #undef ABI_FUNC #define ABI_FUNC 'xmpi_subcomm' !End of the abilint section implicit none !Arguments------------------------- !scalars integer,intent(in) :: comm,nranks integer,intent(out),optional :: my_rank_in_group integer :: xmpi_subcomm !arrays integer,intent(in) :: ranks(nranks) !Local variables------------------------------- #ifdef HAVE_MPI integer :: group,ierr,subgroup #endif ! ************************************************************************* xmpi_subcomm=xmpi_comm_null if (present(my_rank_in_group)) my_rank_in_group=xmpi_undefined #ifdef HAVE_MPI if (comm/=xmpi_comm_null.and.nranks>=0) then call MPI_COMM_GROUP(comm,group,ierr) call MPI_GROUP_INCL(group,nranks,ranks,subgroup,ierr) call MPI_COMM_CREATE(comm,subgroup,xmpi_subcomm,ierr) if ( nranks == 0 )xmpi_subcomm=xmpi_comm_self if (present(my_rank_in_group)) then call MPI_Group_rank(subgroup,my_rank_in_group,ierr) end if call MPI_GROUP_FREE(subgroup,ierr) call MPI_GROUP_FREE(group,ierr) end if #else if (nranks>0) then if (ranks(1)==0) then xmpi_subcomm=xmpi_comm_self if (present(my_rank_in_group)) my_rank_in_group=0 end if end if #endif end function xmpi_subcomm !!*** !---------------------------------------------------------------------- !!****f* m_xmpi/xmpi_comm_group !! NAME !! xmpi_comm_group !! !! FUNCTION !! Hides MPI_COMM_GROUP from MPI library. !! !! INPUTS !! comm=MPI communicator. !! !! OUTPUT !! spaceGroup=The group associated to comm. !! mpierr=error code returned !! !! PARENTS !! m_wfd,m_xmpi,pawprt !! !! CHILDREN !! mpi_type_commit,mpi_type_size,xmpi_abort,xmpio_type_struct !! !! SOURCE subroutine xmpi_comm_group(comm,spaceGroup,mpierr) !This section has been created automatically by the script Abilint (TD). !Do not modify the following lines by hand. #undef ABI_FUNC #define ABI_FUNC 'xmpi_comm_group' !End of the abilint section implicit none !Arguments------------------------- integer,intent(in) :: comm integer,intent(out) :: mpierr,spaceGroup ! ************************************************************************* mpierr=0; spaceGroup=xmpi_group_null #ifdef HAVE_MPI if (comm/=xmpi_comm_null) then call MPI_COMM_GROUP(comm,spaceGroup,mpierr) end if #endif end subroutine xmpi_comm_group !!*** !---------------------------------------------------------------------- !!****f* m_xmpi/xmpi_comm_split !! NAME !! xmpi_comm_split !! !! FUNCTION !! Hides MPI_COMM_SPLIT from MPI library. !! !! INPUTS !! input_comm=Input MPI communicator (to be splitted) !! color=Control of subset assignment (nonnegative integer). !! Processes with the same color are in the same new communicator !! key=Ccontrol of rank assigment (integer) !! !! OUTPUT !! mpierr=error code returned !! output_comm=new splitted communicator !! !! PARENTS !! !! CHILDREN !! mpi_type_commit,mpi_type_size,xmpi_abort,xmpio_type_struct !! !! SOURCE subroutine xmpi_comm_split(input_comm,color,key,output_comm,mpierr) !This section has been created automatically by the script Abilint (TD). !Do not modify the following lines by hand. #undef ABI_FUNC #define ABI_FUNC 'xmpi_comm_split' !End of the abilint section implicit none !Arguments------------------------- !scalars integer,intent(in) :: color,input_comm,key integer,intent(out) :: mpierr,output_comm ! ************************************************************************* mpierr=0; output_comm=input_comm #ifdef HAVE_MPI if (input_comm/=xmpi_comm_null.and.input_comm/=xmpi_comm_self) then call MPI_COMM_SPLIT(input_comm,color,key,output_comm,mpierr) end if #endif end subroutine xmpi_comm_split !!*** !---------------------------------------------------------------------- !!****f* m_xmpi/xmpi_group_translate_ranks !! NAME !! xmpi_group_translate_ranks !! !! FUNCTION !! Hides MPI_GROUP_TRANSLATE_RANKS from MPI library. !! !! INPUTS !! nrank=number of ranks in ranks1 and ranks2 arrays !! ranks1(nrank)=array of zero or more valid ranks in group1 !! spaceGroup1=group1 !! spaceGroup2=group2 !! !! OUTPUT !! mpierr=error code returned !! ranks2(nrank)=array of corresponding ranks in group2, !! xmpi_undefined when no correspondence exists !! !! PARENTS !! m_xmpi,pawprt !! !! CHILDREN !! mpi_type_commit,mpi_type_size,xmpi_abort,xmpio_type_struct !! !! SOURCE subroutine xmpi_group_translate_ranks(spaceGroup1,nrank,ranks1,& & spaceGroup2,ranks2,mpierr) !This section has been created automatically by the script Abilint (TD). !Do not modify the following lines by hand. #undef ABI_FUNC #define ABI_FUNC 'xmpi_group_translate_ranks' !End of the abilint section implicit none !Arguments------------------------- !scalars integer,intent(in) :: nrank,spaceGroup1,spaceGroup2 integer,intent(out) :: mpierr !arrays integer,intent(in) :: ranks1(nrank) integer,intent(out) :: ranks2(nrank) ! ************************************************************************* mpierr=0; ranks2(:)=xmpi_undefined #ifdef HAVE_MPI if (spaceGroup1/=xmpi_group_null.and.spaceGroup2/=xmpi_group_null) then call MPI_GROUP_TRANSLATE_RANKS(spaceGroup1,nrank,ranks1,& & spaceGroup2,ranks2,mpierr) end if #else ranks2(1)=0 #endif end subroutine xmpi_group_translate_ranks !!*** !---------------------------------------------------------------------- !!****f* m_xmpi/xmpi_comm_translate_ranks !! NAME !! xmpi_comm_translate_ranks !! !! FUNCTION !! Helper function that translate the ranks from a communicator to another one. !! Wraps xmpi_group_translate_ranks but provides a more user-friendly interface !! !! INPUTS !! from_comm=MPI communicator where from_ranks are defined. !! nrank=number of ranks in from_ranks and to_ranks arrays !! from_ranks(nrank)=array of zero or more valid ranks in from_comm !! !! OUTPUT !! to_ranks(nrank)=array of corresponding ranks in to_comm !! xmpi_undefined when no correspondence exists !! !! PARENTS !! m_paral_pert !! !! CHILDREN !! mpi_type_commit,mpi_type_size,xmpi_abort,xmpio_type_struct !! !! SOURCE subroutine xmpi_comm_translate_ranks(from_comm,nrank,from_ranks,to_comm,to_ranks) !This section has been created automatically by the script Abilint (TD). !Do not modify the following lines by hand. #undef ABI_FUNC #define ABI_FUNC 'xmpi_comm_translate_ranks' !End of the abilint section implicit none !Arguments------------------------- !scalars integer,intent(in) :: nrank,from_comm,to_comm !arrays integer,intent(in) :: from_ranks(nrank) integer,intent(out) :: to_ranks(nrank) !Local variables------------------------------- !scalars integer :: ierr,from_group,to_group ! ************************************************************************* ! Get the groups call xmpi_comm_group(from_comm,from_group,ierr) call xmpi_comm_group(to_comm,to_group,ierr) call xmpi_group_translate_ranks(from_group,nrank,from_ranks,to_group,to_ranks,ierr) ! Release the groups call xmpi_group_free(from_group) call xmpi_group_free(to_group) end subroutine xmpi_comm_translate_ranks !!*** !---------------------------------------------------------------------- !!****f* m_xmpi/xmpi_barrier !! NAME !! xmpi_barrier !! !! FUNCTION !! Hides MPI_BARRIER from MPI library. !! !! INPUTS !! comm=MPI communicator !! !! PARENTS !! alloc_hamilt_gpu,atomden,calc_optical_mels,calc_ucrpa,chebfi,cohsex_me !! datafordmft,denfgr,dfpt_nselt,dfpt_nstpaw,dfpt_scfcv,exc_build_block !! fermisolverec,getcgqphase,gstateimg,iofn1,ks_ddiago,m_bse_io !! m_exc_diago,m_exc_itdiago,m_exc_spectra,m_green,m_haydock,m_hdr !! m_io_kss,m_io_redirect,m_ioarr,m_iowf,m_plowannier,m_slk,m_wfd,m_wffile !! m_wfk,mlwfovlp,mlwfovlp_pw,mover,outkss,pawmkaewf,qmc_prep_ctqmc,sigma !! tddft,vtorho,vtorhorec,wfk_analyze !! !! CHILDREN !! mpi_type_commit,mpi_type_size,xmpi_abort,xmpio_type_struct !! !! SOURCE subroutine xmpi_barrier(comm) !This section has been created automatically by the script Abilint (TD). !Do not modify the following lines by hand. #undef ABI_FUNC #define ABI_FUNC 'xmpi_barrier' !End of the abilint section implicit none !Arguments------------------------- integer,intent(in) :: comm !Local variables------------------- integer :: ier #ifdef HAVE_MPI integer :: nprocs #endif ! ************************************************************************* ier = 0 #ifdef HAVE_MPI if (comm/=xmpi_comm_null) then call MPI_COMM_SIZE(comm,nprocs,ier) if(nprocs>1)then call MPI_BARRIER(comm,ier) end if end if #endif end subroutine xmpi_barrier !!*** !---------------------------------------------------------------------- !!****f* m_xmpi/xmpi_name !! NAME !! xmpi_name !! !! FUNCTION !! Hides MPI_GET_PROCESSOR_NAME from MPI library. !! !! OUTPUT !! name= the host name transformed to integer variable. !! mpierr=Status error. !! !! PARENTS !! m_gpu_detect !! !! CHILDREN !! mpi_type_commit,mpi_type_size,xmpi_abort,xmpio_type_struct !! !! SOURCE subroutine xmpi_name(name_ch, mpierr) !This section has been created automatically by the script Abilint (TD). !Do not modify the following lines by hand. #undef ABI_FUNC #define ABI_FUNC 'xmpi_name' !End of the abilint section implicit none !Arguments------------------------- integer,intent(out) :: mpierr character(20),intent(out) :: name_ch !Local variables------------------- integer :: name,len ! character(len=MPI_MAX_PROCESSOR_NAME) :: name_ch ! ************************************************************************* !Get the name of this processor (usually the hostname) name = 0 mpierr = 0 #ifdef HAVE_MPI call MPI_GET_PROCESSOR_NAME(name_ch, len, mpierr) name_ch = trim(name_ch) #else name_ch ='0' #endif end subroutine xmpi_name !!*** !---------------------------------------------------------------------- !!****f* m_xmpi/xmpi_iprobe !! NAME !! xmpi_iprobe !! !! FUNCTION !! Hides MPI_IPROBE from MPI library. !! Nonblocking test for a message. !! !! INPUTS !! source= source processes !! tag= tag value !! mpicomm= communicator !! !! OUTPUT !! flag= True if a message with the specified source, tag, and communicator is available !! mpierr= status error !! !! PARENTS !! m_paw_an,m_paw_ij,m_pawfgrtab,m_pawrhoij !! !! CHILDREN !! mpi_type_commit,mpi_type_size,xmpi_abort,xmpio_type_struct !! !! SOURCE subroutine xmpi_iprobe(source,tag,mpicomm,flag,mpierr) !This section has been created automatically by the script Abilint (TD). !Do not modify the following lines by hand. #undef ABI_FUNC #define ABI_FUNC 'xmpi_iprobe' !End of the abilint section implicit none !Arguments------------------------- integer,intent(in) :: mpicomm,source,tag integer,intent(out) :: mpierr logical,intent(out) :: flag !Local variables------------------- #ifdef HAVE_MPI integer :: ier,status(MPI_STATUS_SIZE) #endif ! ************************************************************************* mpierr = 0 #ifdef HAVE_MPI call MPI_IPROBE(source,tag,mpicomm,flag,status,ier) mpierr=ier #endif end subroutine xmpi_iprobe !!*** !---------------------------------------------------------------------- !!****f* m_xmpi/xmpi_wait !! NAME !! xmpi_wait !! !! FUNCTION !! Hides MPI_WAIT from MPI library. !! Waits for an MPI request to complete. !! !! INPUTS !! request= MPI request handle to wait for !! !! OUTPUT !! mpierr= status error !! !! PARENTS !! dfpt_scfcv,m_fftw3,m_paw_an,m_paw_ij,m_pawfgrtab,m_pawrhoij,m_sg2002 !! mover,scfcv !! !! CHILDREN !! mpi_type_commit,mpi_type_size,xmpi_abort,xmpio_type_struct !! !! SOURCE subroutine xmpi_wait(request,mpierr) !This section has been created automatically by the script Abilint (TD). !Do not modify the following lines by hand. #undef ABI_FUNC #define ABI_FUNC 'xmpi_wait' !End of the abilint section implicit none !Arguments------------------------- integer,intent(out) :: mpierr integer,intent(inout) :: request !Local variables------------------- #ifdef HAVE_MPI integer :: ier,status(MPI_STATUS_SIZE) #endif ! ************************************************************************* mpierr = 0 #ifdef HAVE_MPI call MPI_WAIT(request,status,ier) mpierr=ier #endif end subroutine xmpi_wait !!*** !---------------------------------------------------------------------- !!****f* m_xmpi/xmpi_waitall !! NAME !! xmpi_waitall !! !! FUNCTION !! Hides MPI_WAITALL from MPI library. !! Waits for all given MPI Requests to complete. !! !! INPUTS !! array_of_requests= array of request handles !! !! OUTPUT !! mpierr= status error !! !! PARENTS !! m_paw_an,m_paw_ij,m_pawfgrtab,m_pawrhoij !! !! CHILDREN !! mpi_type_commit,mpi_type_size,xmpi_abort,xmpio_type_struct !! !! SOURCE subroutine xmpi_waitall(array_of_requests,mpierr) !This section has been created automatically by the script Abilint (TD). !Do not modify the following lines by hand. #undef ABI_FUNC #define ABI_FUNC 'xmpi_waitall' !End of the abilint section implicit none !Arguments------------------------- integer,intent(inout) :: array_of_requests(:) integer,intent(out) :: mpierr !Local variables------------------- #ifdef HAVE_MPI integer :: ier,status(MPI_STATUS_SIZE,size(array_of_requests)) #endif ! ************************************************************************* mpierr = 0 #ifdef HAVE_MPI call MPI_WAITALL(size(array_of_requests),array_of_requests,status,ier) mpierr=ier #endif end subroutine xmpi_waitall !!*** !---------------------------------------------------------------------- !!****f* m_xmpi/xmpi_request_free !! NAME !! xmpi_request_free !! !! FUNCTION !! Hides MPI_REQUEST_FREE from MPI library. !! Frees an array of communication request objects. !! !! INPUTS !! requests(:)= communication request array (array of handles) !! !! OUTPUT !! mpierr= status error !! !! PARENTS !! !! CHILDREN !! mpi_type_commit,mpi_type_size,xmpi_abort,xmpio_type_struct !! !! SOURCE subroutine xmpi_request_free(requests,mpierr) !This section has been created automatically by the script Abilint (TD). !Do not modify the following lines by hand. #undef ABI_FUNC #define ABI_FUNC 'xmpi_request_free' !End of the abilint section implicit none !Arguments------------------------- integer,intent(inout) :: requests(:) integer,intent(out) :: mpierr !Local variables------------------- #ifdef HAVE_MPI integer :: ier,ii #endif ! ************************************************************************* mpierr = 0 #ifdef HAVE_MPI do ii=1,size(requests) call MPI_REQUEST_FREE(requests(ii),ier) end do mpierr=ier #endif end subroutine xmpi_request_free !!*** !---------------------------------------------------------------------- !!****f* m_xmpi/xmpi_error_string !! NAME !! xmpi_error_string !! !! FUNCTION !! Hides MPI_ERROR_STRING from MPI library. !! !! INPUTS !! !! OUTPUT !! !! PARENTS !! !! CHILDREN !! mpi_type_commit,mpi_type_size,xmpi_abort,xmpio_type_struct !! !! SOURCE subroutine xmpi_error_string(mpierr,err_string,ilen,ierror) !This section has been created automatically by the script Abilint (TD). !Do not modify the following lines by hand. #undef ABI_FUNC #define ABI_FUNC 'xmpi_error_string' !End of the abilint section implicit none !Arguments------------------------- integer,intent(in) :: mpierr integer,intent(out) :: ilen,ierror character(len=*),intent(out) :: err_string ! ************************************************************************* ilen=0 #ifdef HAVE_MPI call MPI_Error_string(mpierr,err_string,ilen,ierror) #else ierror=1 err_string="Sorry, no MPI_Error_string routine is available to interpret the error message" #endif end subroutine xmpi_error_string !!*** !---------------------------------------------------------------------- !!****f* m_xmpi/xmpi_comm_set_errhandler !! NAME !! xmpi_set_errhandler !! !! FUNCTION !! Hides MPI_COMM_SET_ERRHANDLER from MPI library. !! !! INPUTS !! new_err_handler= new error handler !! !! OUTPUT !! ierror=error code !! old_err_handler= old error handler !! !! SIZE EFFECTS !! comm= communicator (should be intent(in) but is intent(inout) in some !! OMPI implementation ; known as a bug) !! !! PARENTS !! !! SOURCE subroutine xmpi_comm_set_errhandler(comm,new_err_handler,old_err_handler,ierror) !This section has been created automatically by the script Abilint (TD). !Do not modify the following lines by hand. #undef ABI_FUNC #define ABI_FUNC 'xmpi_comm_set_errhandler' !End of the abilint section implicit none !Arguments------------------------- integer,intent(in) :: new_err_handler integer,intent(in) :: comm integer,intent(out) :: ierror,old_err_handler !Local variables------------------------- integer :: mpierr1,mpierr2,my_comm ! ************************************************************************* ierror=0 my_comm = comm !should be intent(in) but is intent(inout) in some OMPI implementation ; known as a bug) #if defined HAVE_MPI mpierr1=MPI_SUCCESS; mpierr2=MPI_SUCCESS #if defined HAVE_MPI1 call MPI_Errhandler_get(my_comm,old_err_handler,mpierr1) call MPI_Errhandler_set(my_comm,new_err_handler,mpierr2) #endif #if defined HAVE_MPI2 call MPI_comm_get_Errhandler(my_comm,old_err_handler,mpierr1) call MPI_comm_set_Errhandler(my_comm,new_err_handler,mpierr2) #endif ierror=MPI_SUCCESS if (mpierr1/=MPI_SUCCESS) then ierror=mpierr1 else if (mpierr2/=MPI_SUCCESS) then ierror=mpierr2 end if #endif end subroutine xmpi_comm_set_errhandler !!*** !---------------------------------------------------------------------- !!****f* m_xmpi/xmpi_split_work_i4b !! NAME !! split_work_i4b !! !! FUNCTION !! Splits the number of tasks, ntasks, among nprocs processors. Used for the MPI parallelization of simple loops. !! !! INPUTS !! ntasks=number of tasks !! comm=MPI communicator. !! !! OUTPUT !! my_start,my_stop= indices defining the initial and final task for this processor !! warn_msg=String containing a possible warning message if the distribution is not optima. !! ierr=Error status !! +1 if ntasks is not divisible by nprocs. !! +2 if ntasks>nprocs. !! !! NOTES !! If nprocs>ntasks then : !! my_start=ntasks+1 !! my_stop=ntask !! !! In this particular case, loops of the form !! !! do ii=my_start,my_stop !! ... !! end do !! !! are not executed. Moreover allocation such as foo(my_start:my_stop) will generate a zero-sized array. !! !! PARENTS !! !! SOURCE subroutine xmpi_split_work_i4b(ntasks,comm,my_start,my_stop,warn_msg,ierr) !This section has been created automatically by the script Abilint (TD). !Do not modify the following lines by hand. #undef ABI_FUNC #define ABI_FUNC 'xmpi_split_work_i4b' !End of the abilint section implicit none !Arguments ------------------------------------ integer,intent(in) :: ntasks,comm integer,intent(out) :: my_start,my_stop,ierr character(len=500) :: warn_msg !Local variables------------------------------- integer :: res,nprocs,my_rank,block_p1,block ! ************************************************************************* nprocs = xmpi_comm_size(comm) my_rank = xmpi_comm_rank(comm) block = ntasks/nprocs res = MOD(ntasks,nprocs) block_p1= block+1 warn_msg = ""; ierr=0 if (res/=0) then write(warn_msg,'(4a,i0,a,i0)')ch10,& & 'xmpi_split_work: ',ch10,& & 'The number of tasks= ',ntasks,' is not divisible by nprocs= ',nprocs ierr=1 end if if (block==0) then write(warn_msg,'(4a,i0,a,i0,2a)')ch10,& & 'xmpi_split_work: ',ch10,& & 'The number of processors= ',nprocs,' is larger than number of tasks= ',ntasks,ch10,& & 'This is a waste ' ierr=2 end if if (my_rankntasks then : !! istart(rank+1)=ntasks+1 !! istop(rank+1)=ntask !! !! In this particular case, loops of the form !! !! do ii=istart(rank),istop(rank) !! ... !! end do !! !! are not executed. Moreover allocation such as foo(istart(rank):istop(rank)) !! will generate a zero-sized array !! !! INPUTS !! ntasks= number of tasks !! nprocs=Number of processors. !! !! OUTPUT !! istart(nprocs),istop(nprocs)= indices defining the initial and final task for each processor !! ierr=Error status. !! warn_msg=String containing the warning message. !! +1 if ntasks is not divisible by nprocs. !! +2 if ntasks>nprocs. !! !! PARENTS !! exc_build_block,m_screening,setup_screening !! !! CHILDREN !! mpi_type_commit,mpi_type_size,xmpi_abort,xmpio_type_struct !! !! SOURCE subroutine xmpi_split_work2_i4b(ntasks,nprocs,istart,istop,warn_msg,ierr) !This section has been created automatically by the script Abilint (TD). !Do not modify the following lines by hand. #undef ABI_FUNC #define ABI_FUNC 'xmpi_split_work2_i4b' !End of the abilint section implicit none !Arguments ------------------------------------ integer,intent(in) :: ntasks,nprocs integer,intent(out) :: ierr integer,intent(inout) :: istart(nprocs),istop(nprocs) character(len=500),intent(out) :: warn_msg !Local variables------------------------------- integer :: res,irank,block,block_tmp ! ************************************************************************* block_tmp = ntasks/nprocs res = MOD(ntasks,nprocs) block = block_tmp+1 warn_msg = ""; ierr=0 if (res/=0) then write(warn_msg,'(a,i0,a,i0,2a)')& & 'The number of tasks = ',ntasks,' is not divisible by nprocs = ',nprocs,ch10,& & 'parallelism is not efficient ' ierr=+1 end if if (block_tmp==0) then write(warn_msg,'(a,i0,a,i0,2a)')& & 'The number of processors = ',nprocs,' is larger than number of tasks =',ntasks,ch10,& & 'This is a waste ' ierr=+2 end if do irank=0,nprocs-1 if (iranknprocs. !! !! PARENTS !! exc_build_block,m_shirley !! !! CHILDREN !! mpi_type_commit,mpi_type_size,xmpi_abort,xmpio_type_struct !! !! SOURCE subroutine xmpi_split_work2_i8b(ntasks,nprocs,istart,istop,warn_msg,ierr) !This section has been created automatically by the script Abilint (TD). !Do not modify the following lines by hand. #undef ABI_FUNC #define ABI_FUNC 'xmpi_split_work2_i8b' !End of the abilint section implicit none !Arguments ------------------------------------ integer,intent(in) :: nprocs integer(i8b),intent(in) :: ntasks integer,intent(out) :: ierr integer(i8b),intent(inout) :: istart(nprocs),istop(nprocs) character(len=500),intent(out) :: warn_msg !Local variables------------------------------- integer(i8b) :: res,irank,block,block_tmp ! ************************************************************************* block_tmp = ntasks/nprocs res = MOD(ntasks,INT(nprocs,KIND=i8b)) block = block_tmp+1 warn_msg = ""; ierr=0 if (res/=0) then write(warn_msg,'(a,i0,a,i0,2a)')& & 'The number of tasks = ',ntasks,' is not divisible by nprocs = ',nprocs,ch10,& & 'parallelism is not efficient ' ierr=+1 end if ! if (block_tmp==0) then write(warn_msg,'(a,i0,a,i0,2a)')& & ' The number of processors = ',nprocs,' is larger than number of tasks =',ntasks,ch10,& & ' This is a waste ' ierr=+2 end if do irank=0,nprocs-1 if (irank ntasks do ii=1,ntasks list(ii) = ii-1 end do else ii=1 do irank=nprocs-1,0,-1 ! If remainder/=0, master will get less tasks. jj = ii+ntpblock-1 if (remainder>0) then jj=jj+1 remainder = remainder-1 end if list(ii:jj)=irank ii=jj+1 end do end if task_distrib = RESHAPE(list,(/n1,n2,n3,n4/)) if (ANY(task_distrib==-999)) then call xmpi_abort(msg="task_distrib == -999") end if ABI_DEALLOCATE(list) end subroutine xmpi_distab_4D !!*** !---------------------------------------------------------------------- !!****f* m_xmpi/xmpi_distrib_with_replicas !! NAME !! xmpi_distrib_with_replicas !! !! FUNCTION !! This function distributes the i-th task among `nprocs` inside a MPI communicator. !! If nprocs > ntasks, multiple MPI ranks will be assigned to a given task. !! !! INPUTS !! itask=Index of the task (must be <= ntasks) !! ntasks= number of tasks !! rank=MPI Rank of this processor !! nprocs=Number of processors in the MPI communicator. !! !! OUTPUT !! True if this node will treat itask (replicas are possible if nprocs > ntasks) !! !! PARENTS !! !! SOURCE pure function xmpi_distrib_with_replicas(itask,ntasks,rank,nprocs) result(bool) !This section has been created automatically by the script Abilint (TD). !Do not modify the following lines by hand. #undef ABI_FUNC #define ABI_FUNC 'xmpi_distrib_with_replicas' !End of the abilint section implicit none !Arguments ------------------------------------ !scalars integer,intent(in) :: itask,rank,nprocs,ntasks logical :: bool !Local variables------------------------------- !scalars integer :: ii,mnp_pool,rk_base ! ************************************************************************* ! If the number of processors is less than ntasks, we have max one task per processor, ! else we replicate the tasks inside a pool of max size mnp_pool if (nprocs <= ntasks) then bool = (MODULO(itask-1, nprocs)==rank) else mnp_pool = (nprocs / ntasks) !write(std_out,*)"Will duplicate itasks" !write(std_out,*)"mnp_pool",mnp_pool,"nprocs, ntasks",nprocs,ntasks rk_base = MODULO(itask-1, nprocs) bool = .False. do ii=1,mnp_pool+1 if (rank == rk_base + (ii-1) * ntasks) then bool = .True.; exit end if end do end if end function xmpi_distrib_with_replicas !!*** !---------------------------------------------------------------------- ! Include files providing wrappers for some of the most commonly used MPI primitives. #include "xmpi_allgather.finc" #include "xmpi_allgatherv.finc" #include "xmpi_alltoall.finc" #include "xmpi_ialltoall.finc" #include "xmpi_alltoallv.finc" #include "xmpi_ialltoallv.finc" #include "xmpi_bcast.finc" #include "xmpi_exch.finc" #include "xmpi_gather.finc" #include "xmpi_gatherv.finc" #include "xmpi_max.finc" #include "xmpi_min.finc" #include "xmpi_recv.finc" #include "xmpi_irecv.finc" #include "xmpi_scatterv.finc" #include "xmpi_send.finc" #include "xmpi_isend.finc" #include "xmpi_sum_master.finc" #include "xmpi_sum.finc" #include "xmpi_isum.finc" #include "xmpi_land_lor.finc" !------------------------------------------------------------------------------------ !!****f* m_xmpi/xmpio_type_struct !! NAME !! xmpio_type_struct !! !! FUNCTION !! Some highly non-standard MPI implementations support MPI-IO without !! implementing the full set of MPI-2 extensions. !! This wrapper will call the obsolete MPI_TYPE_STRUCT if MPI_TYPE_CREATE_STRUCT !! is not supported. Note that MPI_TYPE_STRUCT requires the displacement arrays !! to be an array of default integers whereas the argument block_displ is an array of kind XMPI_ADDRESS_KIND. !! The routine will abort if the displacement cannot be represented with a default integer. !! !! INPUTS !! ncount= number of blocks (integer) --- also number of entries in arrays array_of_types, array_of_displacements and array_of_blocklengths !! array_of_blocklength(ncount)=number of elements in each block (array of integer) !! array_of_displacements(ncount)=byte displacement of each block (array of integer) !! array_of_types(ncount)=type of elements in each block (array of handles to datatype objects) !! !! OUTPUT !! new_type=new datatype (handle) !! mpierr=MPI status error !! !! PARENTS !! m_slk,m_wffile,m_wfk,m_xmpi !! !! CHILDREN !! mpi_type_commit,mpi_type_size,xmpi_abort,xmpio_type_struct !! !! SOURCE #ifdef HAVE_MPI_IO subroutine xmpio_type_struct(ncount,block_length,block_displ,block_type,new_type,mpierr) !This section has been created automatically by the script Abilint (TD). !Do not modify the following lines by hand. #undef ABI_FUNC #define ABI_FUNC 'xmpio_type_struct' !End of the abilint section implicit none !Arguments ------------------------------------ !scalars integer,intent(in) :: ncount integer,intent(out) :: new_type,mpierr !arrays integer,intent(in) :: block_length(ncount),block_type(ncount) integer(XMPI_ADDRESS_KIND),intent(in) :: block_displ(ncount) !Local variables------------------- #ifndef HAVE_MPI_TYPE_CREATE_STRUCT integer,allocatable :: tmp_displ(:) #endif !************************************************************************ #ifdef HAVE_MPI_TYPE_CREATE_STRUCT call MPI_TYPE_CREATE_STRUCT(ncount,block_length,block_displ,block_type,new_type,mpierr) #else ABI_MALLOC(tmp_displ,(ncount)) tmp_displ = block_displ if (ANY(block_displ > HUGE(tmp_displ(1)) ))then call xmpi_abort(msg=" byte displacement cannot be represented with a default integer") end if call MPI_TYPE_STRUCT(ncount,block_length,block_displ,block_type,new_type,mpierr) ABI_FREE(tmp_displ) #endif end subroutine xmpio_type_struct !!*** #endif !---------------------------------------------------------------------- !!****f* m_xmpi/xmpio_get_info_frm !! NAME !! xmpio_marker_info !! !! FUNCTION !! Return the byte size of the Fortran record and its corresponding MPI_type (compiler-dependent). !! These two values are needed to access sequential binary Fortran files with MPI/IO routines where !! C-streams are used. !! !! INPUTS !! comm=MPI communicator. Only master will find the values for the record marker. The results !! are then broadcast to all the other nodes in comm. !! !! OUTPUT !! bsize_frm=Byte size of the Fortran record marker. !! mpi_type_frm=MPI type of the marker. !! !! PARENTS !! !! SOURCE subroutine xmpio_get_info_frm(bsize_frm,mpi_type_frm,comm) !This section has been created automatically by the script Abilint (TD). !Do not modify the following lines by hand. #undef ABI_FUNC #define ABI_FUNC 'xmpio_get_info_frm' !End of the abilint section implicit none !Arguments ------------------------------------ !scalars integer,intent(in) :: comm integer,intent(out) :: mpi_type_frm,bsize_frm !Local variables------------------------------- integer :: my_rank #ifdef HAVE_MPI_IO !scalars integer,parameter :: master=0 integer :: spt,ept,ii integer :: f90_unt,ierr,iimax,mpio_fh,bsize_int,mpierr integer(XMPI_OFFSET_KIND) :: offset,rml character(len=fnlen) :: fname character(len=500) :: errmsg logical :: file_exists !arrays integer :: xvals(2),ivals(100),read_5ivals(5),ref_5ivals(5) integer :: rm_lengths(4)=(/4,8,2,16/) integer :: statux(MPI_STATUS_SIZE) real(dp) :: xrand(fnlen) #endif !************************************************************************ bsize_frm=0; mpi_type_frm=0 my_rank = xmpi_comm_rank(comm) !; RETURN #ifdef HAVE_MPI_IO if ( my_rank == master ) then ! Fortran scratch files cannot have a name so have to generate a random one. ! cannot use pick_aname since it is higher level. fname = "__MPI_IO_FRM__" spt=LEN(trim(fname))+1; ept=spt inquire(file=trim(fname),exist=file_exists) do while (file_exists) call RANDOM_NUMBER(xrand(spt:ept)) xrand(spt:ept) = 64+xrand(spt:ept)*26 do ii=spt,ept fname(ii:ii) = ACHAR(NINT(xrand(ii))) end do ept = MIN(ept+1,fnlen) inquire(file=trim(fname),exist=file_exists) end do ! ! Write five integers on the binary file open in Fortran mode, then try ! to reread the values with MPI-IO using different offsets for the record marker. ! f90_unt = xmpi_get_unit() if (f90_unt == -1) call xmpi_abort(msg="Cannot find free unit!!") ! MT dec 2013: suppress the new attribute: often cause unwanted errors ! and theoretically useless because of the previous inquire open(unit=f90_unt,file=trim(fname),form="unformatted",err=10, iomsg=errmsg) ref_5ivals = (/(ii, ii=5,9)/) ivals = HUGE(1); ivals(5:9)=ref_5ivals write(f90_unt, err=10, iomsg=errmsg) ivals close(f90_unt, err=10, iomsg=errmsg) call MPI_FILE_OPEN(xmpi_comm_self, trim(fname), MPI_MODE_RDONLY, MPI_INFO_NULL, mpio_fh,mpierr) iimax=3 ! Define number of INTEGER types to be tested #ifdef HAVE_FC_INT_QUAD iimax=4 #endif ! ! Try to read ivals(5:9) from file. ii=0; bsize_frm=-1 call MPI_TYPE_SIZE(MPI_INTEGER,bsize_int,mpierr) do while (bsize_frm<=0 .and. ii for reading by current proc. !! xmpio_collective ==> for collective reading. !! offset=MPI/IO file pointer !! [advance]=By default the routine will move the file pointer to the next record. !! advance=.FALSE. can be used so that the next read will continue picking information !! off of the currect record. !! !! OUTPUT !! fmarker=Content of the Fortran record marker. !! mpierr= MPI error code !! !! SIDE EFFECTS !! offset= !! input: file pointer used to access the Fortran marker. !! output: new offset updated after the reading, depending on advance. !! !! PARENTS !! m_bse_io,m_exc_diago,m_exc_itdiago,m_hdr,m_io_screening,m_xmpi !! !! CHILDREN !! mpi_type_commit,mpi_type_size,xmpi_abort,xmpio_type_struct !! !! SOURCE #ifdef HAVE_MPI_IO subroutine xmpio_read_frm(fh,offset,sc_mode,fmarker,mpierr,advance) !This section has been created automatically by the script Abilint (TD). !Do not modify the following lines by hand. #undef ABI_FUNC #define ABI_FUNC 'xmpio_read_frm' !End of the abilint section implicit none !Arguments ------------------------------------ !scalars integer,intent(in) :: fh,sc_mode integer(XMPI_OFFSET_KIND),intent(inout) :: offset integer(XMPI_OFFSET_KIND),intent(out) :: fmarker integer,intent(out) :: mpierr logical,optional,intent(in) :: advance !Local variables------------------------------- !scalars integer :: bsize_frm,mpi_type_frm,myfh integer(kind=int16) :: delim_record2 integer(kind=int32) :: delim_record4 integer(kind=int64) :: delim_record8 #if defined HAVE_FC_INT_QUAD integer*16 :: delim_record16 #endif character(len=500) :: msg !arrays integer :: statux(MPI_STATUS_SIZE) !************************************************************************ !Workaround for XLF. myfh = fh bsize_frm = xmpio_bsize_frm ! Byte size of the Fortran record marker. mpi_type_frm = xmpio_mpi_type_frm ! MPI type of the record marker. SELECT CASE (sc_mode) CASE (xmpio_single) if (bsize_frm==4) then call MPI_FILE_READ_AT(myfh,offset,delim_record4,1,mpi_type_frm,statux,mpierr) fmarker = delim_record4 else if (bsize_frm==8) then call MPI_FILE_READ_AT(myfh,offset,delim_record8,1,mpi_type_frm,statux,mpierr) fmarker = delim_record8 #if defined HAVE_FC_INT_QUAD else if (bsize_frm==16) then call MPI_FILE_READ_AT(myfh,offset,delim_record16,1,mpi_type_frm,statux,mpierr) fmarker = delim_record16 #endif else if (bsize_frm==2) then call MPI_FILE_READ_AT(myfh,offset,delim_record2 ,1,mpi_type_frm,statux,mpierr) fmarker = delim_record2 else call xmpi_abort(msg='Wrong record marker length!') end if CASE (xmpio_collective) if (bsize_frm==4) then call MPI_FILE_READ_AT_ALL(myfh,offset,delim_record4 ,1,mpi_type_frm,statux,mpierr) fmarker = delim_record4 else if (bsize_frm==8) then call MPI_FILE_READ_AT_ALL(myfh,offset,delim_record8 ,1,mpi_type_frm,statux,mpierr) fmarker = delim_record8 #if defined HAVE_FC_INT_QUAD else if (bsize_frm==16) then call MPI_FILE_READ_AT_ALL(myfh,offset,delim_record16,1,mpi_type_frm,statux,mpierr) fmarker = delim_record16 #endif else if (bsize_frm==2) then call MPI_FILE_READ_AT_ALL(myfh,offset,delim_record2 ,1,mpi_type_frm,statux,mpierr) fmarker = delim_record2 else call xmpi_abort(msg='Wrong record marker length!') end if CASE DEFAULT write(msg,"(a,i0)")" Wrong value for sc_mode: ",sc_mode call xmpi_abort(msg=msg) END SELECT if (PRESENT(advance)) then if (advance) then offset = offset + fmarker + 2*bsize_frm ! Move the file pointer to the next record. else offset = offset + bsize_frm ! Move the pointer after the marker. end if else offset = offset + fmarker + 2*bsize_frm end if end subroutine xmpio_read_frm !!*** #endif !------------------------------------------------------------------------------------ !!****f* m_wffile/xmpio_write_frm !! NAME !! xmpio_write_frm !! !! FUNCTION !! Write a single record marker in a FORTRAN file at a given offset using MPI-IO. !! The file pointer is modified according to the value of advance. !! !! INPUTS !! fh=MPI-IO file handler. !! sc_mode= !! xmpio_single ==> for reading by current proc. !! xmpio_collective ==> for collective reading. !! fmarker=The content of the Fortran marker i.e. the size of the record in bytes. !! [advance]=By default the routine will move the file pointer to the next record. !! advance=.FALSE. can be used so that the next write will continue writing data !! on the currect record. !! !! OUTPUT !! mpierr= error code !! !! SIDE EFFECTS !! offset= !! input: offset of the Fortran marker. !! output: new offset updated after the writing, depending on advance. !! !! PARENTS !! m_ioarr !! !! CHILDREN !! mpi_type_commit,mpi_type_size,xmpi_abort,xmpio_type_struct !! !! SOURCE #ifdef HAVE_MPI_IO subroutine xmpio_write_frm(fh,offset,sc_mode,fmarker,mpierr,advance) !This section has been created automatically by the script Abilint (TD). !Do not modify the following lines by hand. #undef ABI_FUNC #define ABI_FUNC 'xmpio_write_frm' !End of the abilint section implicit none !Arguments ------------------------------------ !scalars integer,intent(in) :: fh,sc_mode integer(XMPI_OFFSET_KIND),intent(in) :: fmarker integer(XMPI_OFFSET_KIND),intent(inout) :: offset integer,intent(out) :: mpierr logical,optional,intent(in) :: advance !Local variables------------------------------- !scalars integer :: myfh,bsize_frm,mpi_type_frm integer(XMPI_OFFSET_KIND) :: last integer(kind=int16) :: delim_record2 integer(kind=int32) :: delim_record4 integer(kind=int64) :: delim_record8 #if defined HAVE_FC_INT_QUAD integer*16 :: delim_record16 #endif character(len=500) :: msg !arrays integer :: statux(MPI_STATUS_SIZE) !************************************************************************ ! Workaround for XLF myfh = fh bsize_frm = xmpio_bsize_frm ! Byte size of the Fortran record marker. mpi_type_frm = xmpio_mpi_type_frm ! MPI type of the record marker. last = offset + bsize_frm + fmarker ! position of the end marker SELECT CASE (sc_mode) CASE (xmpio_single) if (bsize_frm==4) then delim_record4 = fmarker call MPI_FILE_WRITE_AT(myfh,offset,delim_record4 ,1,mpi_type_frm,statux,mpierr) call MPI_FILE_WRITE_AT(myfh,last,delim_record4 ,1,mpi_type_frm,statux,mpierr) else if (bsize_frm==8) then delim_record8 = fmarker call MPI_FILE_WRITE_AT(myfh,offset,delim_record8 ,1,mpi_type_frm,statux,mpierr) call MPI_FILE_WRITE_AT(myfh,last,delim_record8 ,1,mpi_type_frm,statux,mpierr) #if defined HAVE_FC_INT_QUAD else if (bsize_frm==16) then delim_record16 = fmarker call MPI_FILE_WRITE_AT(myfh,offset,delim_record16,1,mpi_type_frm,statux,mpierr) call MPI_FILE_WRITE_AT(myfh,last,delim_record16 ,1,mpi_type_frm,statux,mpierr) #endif else if (bsize_frm==2) then delim_record2 = fmarker call MPI_FILE_WRITE_AT(myfh,offset,delim_record2, 1,mpi_type_frm,statux,mpierr) call MPI_FILE_WRITE_AT(myfh,last,delim_record2 ,1,mpi_type_frm,statux,mpierr) else call xmpi_abort(msg='Wrong record marker length!') end if CASE (xmpio_collective) if (bsize_frm==4) then delim_record4 = fmarker call MPI_FILE_WRITE_AT_ALL(myfh,offset,delim_record4 ,1,mpi_type_frm,statux,mpierr) call MPI_FILE_WRITE_AT_ALL(myfh,last,delim_record4 ,1,mpi_type_frm,statux,mpierr) else if (bsize_frm==8) then delim_record8 = fmarker call MPI_FILE_WRITE_AT_ALL(myfh,offset,delim_record8 ,1,mpi_type_frm,statux,mpierr) call MPI_FILE_WRITE_AT_ALL(myfh,last,delim_record8 ,1,mpi_type_frm,statux,mpierr) #if defined HAVE_FC_INT_QUAD else if (bsize_frm==16) then delim_record16 = fmarker call MPI_FILE_WRITE_AT_ALL(myfh,offset,delim_record16,1,mpi_type_frm,statux,mpierr) call MPI_FILE_WRITE_AT_ALL(myfh,last,delim_record16 ,1,mpi_type_frm,statux,mpierr) #endif else if (bsize_frm==2) then delim_record2 = fmarker call MPI_FILE_WRITE_AT_ALL(myfh,offset,delim_record2 ,1,mpi_type_frm,statux,mpierr) call MPI_FILE_WRITE_AT_ALL(myfh,last,delim_record2 ,1,mpi_type_frm,statux,mpierr) else call xmpi_abort(msg='Wrong record marker length!') end if CASE DEFAULT write(msg,"(a,i0)")" Wrong value for sc_mode: ",sc_mode call xmpi_abort(msg=msg) END SELECT if (PRESENT(advance)) then if (advance) then offset = offset + fmarker + 2*bsize_frm ! Move the file pointer to the next record. else offset = offset + bsize_frm ! Move the pointer after the marker. end if else offset = offset + fmarker + 2*bsize_frm end if end subroutine xmpio_write_frm !!*** #endif !------------------------------------------------------------------------------------ !!****f* m_xmpi/xmpio_create_fstripes !! NAME !! xmpio_create_fstripes !! !! FUNCTION !! Return a MPI type that can be used to (read|write) a set of interleaved Fortran records. !! !! type(1), type(1), ... ! size(1) elements !! type(2), type(2), ... ! size(2) elements !! type(1), type(1), ... ! size(1) elements !! .... !! !! INPUTS !! ncount = Number of records with elements of type types(1) to (read|write) !! sizes(1:2) = Number of elements of each type in the two sets of record !! type(1:2) = MPI Type of the elements in the first and in the second record. !! !! OUTPUT !! my_offpad=Offset to be added to the file pointer giving the position of the first Fortran record !! marker individuating the beginning of the matrix. (lets call it "base"). !! Each node should (read|write) using my_offset = base + my_offpad. !! my_offpad is used so that one can safely change the way the fileview is generated (for example !! to make it more efficient) without having to change the client code. !! new_type=New MPI type. !! mpierr= MPI error code !! !! PARENTS !! m_wfk !! !! CHILDREN !! mpi_type_commit,mpi_type_size,xmpi_abort,xmpio_type_struct !! !! SOURCE #ifdef HAVE_MPI_IO subroutine xmpio_create_fstripes(ncount,sizes,types,new_type,my_offpad,mpierr) !This section has been created automatically by the script Abilint (TD). !Do not modify the following lines by hand. #undef ABI_FUNC #define ABI_FUNC 'xmpio_create_fstripes' !End of the abilint section implicit none !Arguments ------------------------------------ !scalars integer,intent(in) :: ncount integer(XMPI_OFFSET_KIND),intent(out) :: my_offpad integer,intent(out) :: new_type,mpierr !arrays integer,intent(in) :: types(2),sizes(2) !Local variables------------------------------- !scalars integer :: type_x,type_y,bsize_frm,bsize_x,bsize_y,nx,ny,column_type integer(MPI_ADDRESS_KIND) :: stride !************************************************************************ ! Byte size of the Fortran record marker. bsize_frm = xmpio_bsize_frm ! Number of elements in the two stripes. nx = sizes(1) ny = sizes(2) type_x = types(1) type_y = types(2) ! Byte size of type_x and type_y call MPI_TYPE_SIZE(type_x,bsize_x,mpierr) ABI_HANDLE_MPIERR(mpierr) call MPI_TYPE_SIZE(type_y,bsize_y,mpierr) ABI_HANDLE_MPIERR(mpierr) ! The view starts at the first element of the first stripe. my_offpad = xmpio_bsize_frm call MPI_Type_contiguous(nx,type_x,column_type,mpierr) ABI_HANDLE_MPIERR(mpierr) ! Byte size of the Fortran record + the two markers. stride = nx*bsize_x + 2*bsize_frm + ny*bsize_y + 2*bsize_frm ! ncount colum_type separated by stride bytes call MPI_Type_create_hvector(ncount,1,stride,column_type,new_type,mpierr) ABI_HANDLE_MPIERR(mpierr) call MPI_TYPE_COMMIT(new_type,mpierr) ABI_HANDLE_MPIERR(mpierr) call MPI_TYPE_FREE(column_type,mpierr) ABI_HANDLE_MPIERR(mpierr) end subroutine xmpio_create_fstripes !!*** #endif !------------------------------------------------------------------------------------ !!****f* m_xmpi/xmpio_create_fsubarray_2D !! NAME !! xmpio_create_fsubarray_2D !! !! FUNCTION !! Return a MPI type that can be used to (read|write) a 2D matrix of elements of type old_type stored in a Fortran file. !! !! INPUTS !! sizes(2)=number of elements of type old_type in each dimension of the full array (array of positive integers) !! subsizes(2)=number of elements of type old_type in each dimension of the subarray (array of positive integers) !! array_of_starts(2)=starting coordinates of the subarray in each dimension (array of nonnegative integers >=1, <=sizes) !! old_type=Old MPI type. !! !! OUTPUT !! my_offpad=Offset to be added to the file pointer giving the position of the first Fortran record !! marker individuating the beginning of the matrix. (lets call it "base"). !! Each node should (read|write) using my_offset = base + my_offpad. !! my_offpad is used so that one can safely change the way the fileview is generated (for example !! to make it more efficient) without having to change the client code. !! new_type=New MPI type. !! mpierr= MPI error code !! !! PARENTS !! exc_build_block,m_exc_itdiago,m_mpiotk,m_wfk !! !! CHILDREN !! mpi_type_commit,mpi_type_size,xmpi_abort,xmpio_type_struct !! !! SOURCE #ifdef HAVE_MPI_IO subroutine xmpio_create_fsubarray_2D(sizes,subsizes,array_of_starts,old_type,new_type,my_offpad,mpierr) !This section has been created automatically by the script Abilint (TD). !Do not modify the following lines by hand. #undef ABI_FUNC #define ABI_FUNC 'xmpio_create_fsubarray_2D' !End of the abilint section implicit none !Arguments ------------------------------------ !scalars integer,intent(in) :: old_type integer(XMPI_OFFSET_KIND),intent(out) :: my_offpad integer,intent(out) :: mpierr,new_type !arrays integer,intent(in) :: sizes(2),subsizes(2),array_of_starts(2) !Local variables------------------------------- !scalars integer :: bsize_frm,bsize_old,nx,ny integer :: column_type,ldx integer(XMPI_OFFSET_KIND) :: st_x,st_y integer(MPI_ADDRESS_KIND) :: stride_x !character(len=500) :: msg !************************************************************************ ! Byte size of the Fortran record marker. bsize_frm = xmpio_bsize_frm ! Byte size of old_type. call MPI_TYPE_SIZE(old_type,bsize_old,mpierr) ABI_HANDLE_MPIERR(mpierr) ! ! Number of columns and rows of the submatrix. nx = subsizes(1) ny = subsizes(2) ldx = sizes(1) st_x = array_of_starts(1) st_y = array_of_starts(2) ! The view starts at the first element of the submatrix. my_offpad = (st_x-1)*bsize_old + (st_y-1)*(ldx*bsize_old+2*xmpio_bsize_frm) + xmpio_bsize_frm ! Byte size of the Fortran record + the two markers. stride_x = ldx*bsize_old + 2*bsize_frm call MPI_Type_contiguous(nx,old_type,column_type,mpierr) ABI_HANDLE_MPIERR(mpierr) call MPI_Type_create_hvector(ny,1,stride_x,column_type,new_type,mpierr) ABI_HANDLE_MPIERR(mpierr) call MPI_TYPE_COMMIT(new_type,mpierr) ABI_HANDLE_MPIERR(mpierr) call MPI_TYPE_FREE(column_type, mpierr) ABI_HANDLE_MPIERR(mpierr) end subroutine xmpio_create_fsubarray_2D !!*** #endif !------------------------------------------------------------------------------------ !!****f* m_xmpi/xmpio_create_fsubarray_3D !! NAME !! xmpio_create_fsubarray_3D !! !! FUNCTION !! Return a MPI type that can be used to (read|write) a 3D matrix of elements of type old_type stored in a Fortran file. !! !! INPUTS !! sizes(3)=number of elements of type old_type in each dimension of the full array (array of positive integers) !! subsizes(3)=number of elements of type old_type in each dimension of the subarray (array of positive integers) !! array_of_starts(3)=starting coordinates of the subarray in each dimension (array of nonnegative integers >=1, <=sizes) !! old_type=Old MPI type. !! !! OUTPUT !! my_offpad=Offset to be added to the file pointer giving the position of the first Fortran record !! marker individuating the beginning of the matrix. (lets call it "base"). !! Each node should (read|write) using my_offset = base + my_offpad. !! my_offpad is used so that one can safely change the way the fileview is generated (for example !! to make it more efficient) without having to change the client code. !! new_type=New MPI type. !! mpierr= MPI error code !! !! PARENTS !! m_mpiotk !! !! CHILDREN !! mpi_type_commit,mpi_type_size,xmpi_abort,xmpio_type_struct !! !! SOURCE #ifdef HAVE_MPI_IO subroutine xmpio_create_fsubarray_3D(sizes,subsizes,array_of_starts,old_type,new_type,my_offpad,mpierr) !This section has been created automatically by the script Abilint (TD). !Do not modify the following lines by hand. #undef ABI_FUNC #define ABI_FUNC 'xmpio_create_fsubarray_3D' !End of the abilint section implicit none !Arguments ------------------------------------ !scalars integer,intent(in) :: old_type integer,intent(out) :: mpierr,new_type integer(XMPI_OFFSET_KIND),intent(out) :: my_offpad !arrays integer,intent(in) :: sizes(3),subsizes(3),array_of_starts(3) !Local variables------------------------------- !scalars integer :: bsize_frm,bsize_old,nx,ny,nz integer :: column_type,plane_type,ldx,ldy,ldz integer(XMPI_OFFSET_KIND) :: st_x,st_y,st_z integer(MPI_ADDRESS_KIND) :: stride_x !character(len=500) :: msg !************************************************************************ bsize_frm = xmpio_bsize_frm ! Byte size of the Fortran record marker. ! Byte size of old_type. call MPI_TYPE_SIZE(old_type,bsize_old,mpierr) ABI_HANDLE_MPIERR(mpierr) ! ! Number of columns and rows of the submatrix. nx = subsizes(1) ny = subsizes(2) nz = subsizes(3) ldx = sizes(1) ldy = sizes(2) ldz = sizes(3) st_x = array_of_starts(1) st_y = array_of_starts(2) st_z = array_of_starts(3) ! The view starts at the first element of the submatrix. my_offpad = (st_x-1)*bsize_old + & & (st_y-1)* (ldx*bsize_old+2*xmpio_bsize_frm) + & & (st_z-1)*ldy*(ldx*bsize_old+2*xmpio_bsize_frm) + & & xmpio_bsize_frm ! Byte size of the Fortran record + the two markers. stride_x = ldx*bsize_old + 2*bsize_frm call MPI_Type_contiguous(nx,old_type,column_type,mpierr) ABI_HANDLE_MPIERR(mpierr) call MPI_Type_create_hvector(ny,1,stride_x,column_type,plane_type,mpierr) ABI_HANDLE_MPIERR(mpierr) call MPI_Type_create_hvector(nz,1,ldy*stride_x,plane_type,new_type,mpierr) ABI_HANDLE_MPIERR(mpierr) ! Commit the datatype call MPI_TYPE_COMMIT(new_type,mpierr) ABI_HANDLE_MPIERR(mpierr) ! Free memory call MPI_TYPE_FREE(plane_type, mpierr) ABI_HANDLE_MPIERR(mpierr) end subroutine xmpio_create_fsubarray_3D !!*** #endif !------------------------------------------------------------------------------------ !!****f* m_xmpi/xmpio_create_fsubarray_4D !! NAME !! xmpio_create_fsubarray_4D !! !! FUNCTION !! Return a MPI type that can be used to (read|write) a 2D matrix of elements of type old_type stored in a Fortran file. !! !! INPUTS !! sizes(4)=number of elements of type old_type in each dimension of the full array (array of positive integers) !! subsizes(4)=number of elements of type old_type in each dimension of the subarray (array of positive integers) !! array_of_starts(4)=starting coordinates of the subarray in each dimension (array of nonnegative integers >=1, <=sizes) !! old_type=Old MPI type. !! !! OUTPUT !! my_offpad=Offset to be added to the file pointer giving the position of the first Fortran record !! marker individuating the beginning of the matrix. (lets call it "base"). !! Each node should (read|write) using my_offset = base + my_offpad. !! my_offpad is used so that one can safely change the way the fileview is generated (for example !! to make it more efficient) without having to change the client code. !! new_type=New MPI type. !! mpierr= MPI error code !! !! PARENTS !! m_mpiotk !! !! CHILDREN !! mpi_type_commit,mpi_type_size,xmpi_abort,xmpio_type_struct !! !! SOURCE #ifdef HAVE_MPI_IO subroutine xmpio_create_fsubarray_4D(sizes,subsizes,array_of_starts,old_type,new_type,my_offpad,mpierr) !This section has been created automatically by the script Abilint (TD). !Do not modify the following lines by hand. #undef ABI_FUNC #define ABI_FUNC 'xmpio_create_fsubarray_4D' !End of the abilint section implicit none !Arguments ------------------------------------ !scalars integer,intent(in) :: old_type integer,intent(out) :: mpierr,new_type integer(XMPI_OFFSET_KIND),intent(out) :: my_offpad !arrays integer,intent(in) :: sizes(4),subsizes(4),array_of_starts(4) !Local variables------------------------------- !scalars integer :: bsize_frm,bsize_old,nx,ny,nz,na integer :: column_type,plane_type,ldx,ldy,ldz,lda,vol_type integer(XMPI_OFFSET_KIND) :: st_x,st_y,st_z,st_a integer(MPI_ADDRESS_KIND) :: stride_x !************************************************************************ bsize_frm = xmpio_bsize_frm ! Byte size of the Fortran record marker. ! Byte size of old_type. call MPI_TYPE_SIZE(old_type,bsize_old,mpierr) ABI_HANDLE_MPIERR(mpierr) ! ! Number of columns and rows of the submatrix. nx = subsizes(1) ny = subsizes(2) nz = subsizes(3) na = subsizes(4) ldx = sizes(1) ldy = sizes(2) ldz = sizes(3) lda = sizes(4) st_x = array_of_starts(1) st_y = array_of_starts(2) st_z = array_of_starts(3) st_a = array_of_starts(4) ! The view starts at the first element of the submatrix. my_offpad = (st_x-1)*bsize_old + & & (st_y-1)* (ldx*bsize_old+2*xmpio_bsize_frm) + & & (st_z-1)*ldy* (ldx*bsize_old+2*xmpio_bsize_frm) + & & (st_a-1)*lda*ldy*(ldx*bsize_old+2*xmpio_bsize_frm) + & & xmpio_bsize_frm ! Byte size of the Fortran record + the two markers. stride_x = ldx*bsize_old + 2*bsize_frm call MPI_Type_contiguous(nx,old_type,column_type,mpierr) ABI_HANDLE_MPIERR(mpierr) call MPI_Type_create_hvector(ny,1,stride_x,column_type,plane_type,mpierr) ABI_HANDLE_MPIERR(mpierr) call MPI_Type_create_hvector(nz,1,ldy*stride_x,plane_type,vol_type,mpierr) ABI_HANDLE_MPIERR(mpierr) call MPI_Type_create_hvector(na,1,ldz*ldy*stride_x,vol_type,new_type,mpierr) ABI_HANDLE_MPIERR(mpierr) ! Commit the datatype call MPI_TYPE_COMMIT(new_type,mpierr) ABI_HANDLE_MPIERR(mpierr) ! Free memory call MPI_TYPE_FREE(column_type, mpierr) ABI_HANDLE_MPIERR(mpierr) call MPI_TYPE_FREE(plane_type, mpierr) ABI_HANDLE_MPIERR(mpierr) call MPI_TYPE_FREE(vol_type, mpierr) ABI_HANDLE_MPIERR(mpierr) end subroutine xmpio_create_fsubarray_4D !!*** #endif !------------------------------------------------------------------------------------ !!****f* m_xmpi/xmpio_check_frmarkers !! NAME !! xmpio_check_frmarkers !! !! FUNCTION !! Check a set of Fortran record markers starting at a given offset using MPI-IO. !! !! INPUTS !! fh=MPI-IO file handler. !! offset=MPI-IO file pointer !! sc_mode=Option for individual or collective reading. !! nfrec=Number of Fortran records to be checked. !! bsize_frecord(nfrec)=Byte size of the Fortran records (markers are NOT included) !! These values will be compared with the markers reported in the file. !! !! OUTPUT !! ierr=A non-zero error code signals failure. !! !! PARENTS !! m_bse_io,m_exc_itdiago,m_slk,m_wfk !! !! CHILDREN !! mpi_type_commit,mpi_type_size,xmpi_abort,xmpio_type_struct !! !! SOURCE #ifdef HAVE_MPI_IO subroutine xmpio_check_frmarkers(fh,offset,sc_mode,nfrec,bsize_frecord,ierr) !This section has been created automatically by the script Abilint (TD). !Do not modify the following lines by hand. #undef ABI_FUNC #define ABI_FUNC 'xmpio_check_frmarkers' !End of the abilint section implicit none !Arguments ------------------------------------ !scalars integer,intent(in) :: fh,nfrec,sc_mode integer(XMPI_OFFSET_KIND),intent(in) :: offset integer,intent(out) :: ierr !arrays integer(XMPI_OFFSET_KIND),intent(in) :: bsize_frecord(nfrec) !Local variables------------------------------- !scalars integer :: nb,irec,frmarkers_type,jj,bsize_frm,mpi_type_frm,mpierr,myfh integer(XMPI_OFFSET_KIND) :: displ !arrays integer(kind=int16),allocatable :: bufdelim2(:) integer(kind=int32),allocatable :: bufdelim4(:) integer(kind=int64),allocatable :: bufdelim8(:) #ifdef HAVE_FC_INT_QUAD integer*16,allocatable :: bufdelim16(:) #endif !integer :: statux(MPI_STATUS_SIZE) integer,allocatable :: block_length(:),block_type(:) integer(XMPI_ADDRESS_KIND),allocatable :: block_displ(:) integer(XMPI_OFFSET_KIND),allocatable :: delim_record(:) !************************************************************************ ! Workaround for XLF myfh = fh ierr=0 bsize_frm = xmpio_bsize_frm ! Byte size of the Fortran record marker. mpi_type_frm = xmpio_mpi_type_frm ! MPI type of the record marker. ! ! Define the view for the file. nb=2*nfrec ABI_MALLOC(block_length,(nb+2)) ABI_MALLOC(block_displ,(nb+2)) ABI_MALLOC(block_type,(nb+2)) block_length(1)=1 block_displ (1)=0 block_type (1)=MPI_LB jj=2; displ=0 do irec=1,nfrec block_type (jj:jj+1) =mpi_type_frm block_length(jj:jj+1)=1 block_displ(jj ) = displ block_displ(jj+1) = bsize_frm + displ + bsize_frecord(irec) jj=jj+2 displ = displ + bsize_frecord(irec) + 2*bsize_frm ! Move to the beginning of the next column. if (xmpio_max_address(displ)) ierr=-1 ! Check for wraparound. end do block_length(nb+2)=1 block_displ (nb+2)=displ block_type (nb+2)=MPI_UB call xmpio_type_struct(nb+2,block_length,block_displ,block_type,frmarkers_type,mpierr) ABI_FREE(block_length) ABI_FREE(block_displ) ABI_FREE(block_type) call MPI_TYPE_COMMIT(frmarkers_type,mpierr) call MPI_FILE_SET_VIEW(myfh,offset,MPI_BYTE,frmarkers_type,"native",MPI_INFO_NULL,mpierr) jj=1 ABI_MALLOC(delim_record,(nb)) do irec=1,nfrec delim_record(jj:jj+1)=bsize_frecord(irec) jj=jj+2 end do ! Read markers according to the MPI type of the Fortran marker. SELECT CASE (bsize_frm) CASE (4) ABI_MALLOC(bufdelim4,(nb)) if (sc_mode==xmpio_single) then call MPI_FILE_READ (myfh,bufdelim4,2*nfrec,mpi_type_frm,MPI_STATUS_IGNORE,mpierr) else if (sc_mode==xmpio_collective) then call MPI_FILE_READ_ALL(myfh,bufdelim4,2*nfrec,mpi_type_frm,MPI_STATUS_IGNORE,mpierr) else ierr=2 end if if (ANY(bufdelim4/=delim_record)) ierr=1 !if (ierr==1) then ! do irec=1,2*nfrec ! write(std_out,*)"irec, bufdelim4, delim_record: ",irec,bufdelim4(irec),delim_record(irec) ! end do !end if ABI_FREE(bufdelim4) CASE (8) ABI_MALLOC(bufdelim8,(nb)) if (sc_mode==xmpio_single) then call MPI_FILE_READ (myfh,bufdelim8,2*nfrec,mpi_type_frm,MPI_STATUS_IGNORE,mpierr) else if (sc_mode==xmpio_collective) then call MPI_FILE_READ_ALL(myfh,bufdelim8,2*nfrec,mpi_type_frm,MPI_STATUS_IGNORE,mpierr) else ierr=2 end if if (ANY(bufdelim8/=delim_record)) ierr=1 ABI_FREE(bufdelim8) #ifdef HAVE_FC_INT_QUAD CASE (16) ABI_MALLOC(bufdelim16,(nb)) if (sc_mode==xmpio_single) then call MPI_FILE_READ (myfh,bufdelim16,2*nfrec,mpi_type_frm,MPI_STATUS_IGNORE,mpierr) else if (sc_mode==xmpio_collective) then call MPI_FILE_READ_ALL(myfh,bufdelim16,2*nfrec,mpi_type_frm,MPI_STATUS_IGNORE,mpierr) else ierr=2 end if if (ANY(bufdelim16/=delim_record)) ierr=1 ABI_FREE(bufdelim16) #endif CASE (2) ABI_MALLOC(bufdelim2,(nb)) if (sc_mode==xmpio_single) then call MPI_FILE_READ (myfh,bufdelim2,2*nfrec,mpi_type_frm,MPI_STATUS_IGNORE,mpierr) else if (sc_mode==xmpio_collective) then call MPI_FILE_READ_ALL(myfh,bufdelim2,2*nfrec,mpi_type_frm,MPI_STATUS_IGNORE,mpierr) else ierr=2 end if if (ANY(bufdelim2/=delim_record)) ierr=1 ABI_FREE(bufdelim2) CASE DEFAULT ierr=-2 END SELECT ! Free memory call MPI_TYPE_FREE(frmarkers_type,mpierr) ABI_FREE(delim_record) end subroutine xmpio_check_frmarkers !!*** #endif !---------------------------------------------------------------------- !!****f* m_xmpi/xmpio_read_int !! NAME !! xmpio_read_int !! !! FUNCTION !! Read the content of a single record marker in a FORTRAN file at a given offset using MPI-IO. !! the file pointer is modified according to the value of advance. !! target: integer array !! !! INPUTS !! fh=MPI-IO file handler. !! offset=MPI-IO file pointer !! sc_mode= !! xmpio_single ==> for reading by current proc. !! xmpio_collective ==> for collective reading. !! ncount=Number of elements in the buffer !! [advance]=By default the routine will move the file pointer to the next record. !! advance=.FALSE. can be used so that the next read will continue picking information !! off of the currect record. !! !! OUTPUT !! buf(ncount)=array with the values read from file !! fmarker=Content of the Fortran record marker. !! mpierr= MPI error code !! !! SIDE EFFECTS !! offset= !! input: file pointer used to access the Fortran marker. !! output: new offset updated after the reading, depending on advance. !! !! PARENTS !! !! CHILDREN !! mpi_type_commit,mpi_type_size,xmpi_abort,xmpio_type_struct !! !! SOURCE #ifdef HAVE_MPI_IO subroutine xmpio_read_int(fh,offset,sc_mode,ncount,buf,fmarker,mpierr,advance) !This section has been created automatically by the script Abilint (TD). !Do not modify the following lines by hand. #undef ABI_FUNC #define ABI_FUNC 'xmpio_read_int' !End of the abilint section implicit none !Arguments ------------------------------------ !scalars integer,intent(in) :: fh,sc_mode,ncount integer(XMPI_OFFSET_KIND),intent(inout) :: offset integer(XMPI_OFFSET_KIND),intent(out) :: fmarker integer,intent(out) :: mpierr logical,optional,intent(in) :: advance !arrays integer,intent(out) :: buf(ncount) !Local variables------------------------------- !scalars integer :: myfh,bsize_frm integer(XMPI_OFFSET_KIND) :: my_offset character(len=500) :: msg !arrays integer :: statux(MPI_STATUS_SIZE) !************************************************************************ ! Workaround for XLF myfh = fh my_offset = offset bsize_frm = xmpio_bsize_frm ! Byte size of the Fortran record marker. call xmpio_read_frm(myfh,my_offset,sc_mode,fmarker,mpierr,advance=.FALSE.) SELECT CASE (sc_mode) CASE (xmpio_single) call MPI_FILE_READ_AT(myfh, my_offset, buf, ncount, MPI_INTEGER, statux, mpierr) CASE (xmpio_collective) call MPI_FILE_READ_AT_ALL(myfh, my_offset, buf, ncount, MPI_INTEGER, statux, mpierr) CASE DEFAULT write(msg,"(a,i0)")" Wrong value for sc_mode: ",sc_mode call xmpi_abort(msg=msg) END SELECT if (PRESENT(advance)) then if (advance) then offset = offset + fmarker + 2*bsize_frm ! Move the file pointer to the next record. else offset = offset + bsize_frm ! Move the pointer after the marker. end if else offset = offset + fmarker + 2*bsize_frm end if end subroutine xmpio_read_int !!*** #endif !---------------------------------------------------------------------- !!****f* m_xmpi/xmpio_read_dp !! NAME !! xmpio_read_dp !! !! FUNCTION !! Read the content of a single record marker in a FORTRAN file at a given offset using MPI-IO. !! the file pointer is modified according to the value of advance. !! targer: double precision real array !! !! INPUTS !! fh=MPI-IO file handler. !! offset=MPI-IO file pointer !! sc_mode= !! xmpio_single ==> for reading by current proc. !! xmpio_collective ==> for collective reading. !! ncount=Number of elements in the buffer !! [advance]=By default the routine will move the file pointer to the next record. !! advance=.FALSE. can be used so that the next read will continue picking information !! off of the currect record. !! !! OUTPUT !! buf(ncount)=array with the values read from file !! fmarker=Content of the Fortran record marker. !! mpierr= MPI error code !! !! SIDE EFFECTS !! offset= !! input: file pointer used to access the Fortran marker. !! output: new offset updated after the reading, depending on advance. !! !! PARENTS !! !! CHILDREN !! mpi_type_commit,mpi_type_size,xmpi_abort,xmpio_type_struct !! !! SOURCE #ifdef HAVE_MPI_IO subroutine xmpio_read_dp(fh,offset,sc_mode,ncount,buf,fmarker,mpierr,advance) !This section has been created automatically by the script Abilint (TD). !Do not modify the following lines by hand. #undef ABI_FUNC #define ABI_FUNC 'xmpio_read_dp' !End of the abilint section implicit none !Arguments ------------------------------------ !scalars integer,intent(in) :: fh,sc_mode,ncount integer(XMPI_OFFSET_KIND),intent(inout) :: offset integer(XMPI_OFFSET_KIND),intent(out) :: fmarker integer,intent(out) :: mpierr logical,optional,intent(in) :: advance !arrays real(dp),intent(out) :: buf(ncount) !Local variables------------------------------- !scalars integer :: bsize_frm,myfh integer(XMPI_OFFSET_KIND) :: my_offset character(len=500) :: msg !arrays integer :: statux(MPI_STATUS_SIZE) !************************************************************************ ! Workaround for XLF myfh = fh my_offset = offset bsize_frm = xmpio_bsize_frm ! Byte size of the Fortran record marker. call xmpio_read_frm(myfh,my_offset,sc_mode,fmarker,mpierr,advance=.FALSE.) SELECT CASE (sc_mode) CASE (xmpio_single) call MPI_FILE_READ_AT(myfh, my_offset, buf, ncount, MPI_DOUBLE_PRECISION, statux, mpierr) CASE (xmpio_collective) call MPI_FILE_READ_AT_ALL(myfh, my_offset, buf, ncount, MPI_DOUBLE_PRECISION, statux, mpierr) CASE DEFAULT write(msg,"(a,i0)")" Wrong value for sc_mode: ",sc_mode call xmpi_abort(msg=msg) END SELECT if (PRESENT(advance)) then if (advance) then offset = offset + fmarker + 2*bsize_frm ! Move the file pointer to the next record. else offset = offset + bsize_frm ! Move the pointer after the marker. end if else offset = offset + fmarker + 2*bsize_frm end if end subroutine xmpio_read_dp !!*** #endif !------------------------------------------------------------------------------------ !!****f* m_xmpi/xmpio_max_address !! NAME !! xmpio_max_address !! !! FUNCTION !! Returns .TRUE. if offset cannot be stored in a Fortran integer of kind XMPI_ADDRESS_KIND. !! !! PARENTS !! !! SOURCE #ifdef HAVE_MPI_IO function xmpio_max_address(offset) !This section has been created automatically by the script Abilint (TD). !Do not modify the following lines by hand. #undef ABI_FUNC #define ABI_FUNC 'xmpio_max_address' !End of the abilint section implicit none !Arguments ------------------------------------ !scalars logical :: xmpio_max_address integer(XMPI_OFFSET_KIND),intent(in) :: offset !arrays !Local variables------------------------------- !scalars integer(XMPI_ADDRESS_KIND) :: address integer(XMPI_OFFSET_KIND),parameter :: max_address=HUGE(address)-100 !************************************************************************ xmpio_max_address = (offset >= max_address) end function xmpio_max_address !!*** #endif !------------------------------------------------------------------------------------ !!****f* m_xmpi/xmpio_write_frmarkers !! NAME !! xmpio_write_frmarkers !! !! FUNCTION !! Write a set of Fortran record markers starting at a given offset using MPI-IO. !! !! INPUTS !! fh=MPI-IO file handler. !! offset=MPI-IO file pointer !! sc_mode=Option for individual or collective reading. !! nfrec=Number of Fortran records to be written. !! bsize_frecord(nfrec)=Byte size of the Fortran records to be written (markers are NOT included in the size) !! !! OUTPUT !! ierr=A non-zero error code signals failure. !! !! PARENTS !! exc_build_block,m_exc_itdiago,m_ioarr,m_slk,m_wfk !! !! CHILDREN !! mpi_type_commit,mpi_type_size,xmpi_abort,xmpio_type_struct !! !! SOURCE #ifdef HAVE_MPI_IO subroutine xmpio_write_frmarkers(fh,offset,sc_mode,nfrec,bsize_frecord,ierr) !This section has been created automatically by the script Abilint (TD). !Do not modify the following lines by hand. #undef ABI_FUNC #define ABI_FUNC 'xmpio_write_frmarkers' !End of the abilint section implicit none !Arguments ------------------------------------ !scalars integer,intent(in) :: fh,nfrec,sc_mode integer(XMPI_OFFSET_KIND),intent(in) :: offset integer,intent(out) :: ierr !arrays integer(XMPI_OFFSET_KIND),intent(in) :: bsize_frecord(nfrec) !Local variables------------------------------- !scalars integer :: nb,irec,frmarkers_type,jj,bsize_frm,mpi_type_frm,mpierr,myfh integer(XMPI_OFFSET_KIND) :: displ,my_offset !character(len=500) :: msg !arrays integer(kind=int16),allocatable :: bufdelim2(:) integer(kind=int32),allocatable :: bufdelim4(:) integer(kind=int64),allocatable :: bufdelim8(:) #ifdef HAVE_FC_INT_QUAD integer*16,allocatable :: bufdelim16(:) #endif !integer :: statux(MPI_STATUS_SIZE) integer,allocatable :: block_length(:),block_type(:) integer(XMPI_ADDRESS_KIND),allocatable :: block_displ(:) integer(XMPI_OFFSET_KIND),allocatable :: delim_record(:) !************************************************************************ ! Workaround for XLF myfh = fh; ierr=0 !my_offset = offset !do irec=1,nfrec ! call xmpio_write_frm(myfh,my_offset,sc_mode,bsize_frecord(irec),mpierr) !end do !return ! FIXME: This is buggy bsize_frm = xmpio_bsize_frm ! Byte size of the Fortran record marker. mpi_type_frm = xmpio_mpi_type_frm ! MPI type of the record marker. ! Define the view for the file nb=2*nfrec ABI_MALLOC(block_length,(nb+2)) ABI_MALLOC(block_displ,(nb+2)) ABI_MALLOC(block_type,(nb+2)) block_length(1)=1 block_displ (1)=0 block_type (1)=MPI_LB jj=2; displ=0 do irec=1,nfrec block_type (jj:jj+1) = mpi_type_frm block_length(jj:jj+1) = 1 block_displ(jj ) = displ block_displ(jj+1) = displ + bsize_frm + bsize_frecord(irec) jj=jj+2 displ = displ + bsize_frecord(irec) + 2*bsize_frm ! Move to the beginning of the next column. if (xmpio_max_address(displ)) then ! Check for wraparound. ierr = -1; return end if end do block_length(nb+2) = 1 block_displ (nb+2) = displ block_type (nb+2) = MPI_UB call xmpio_type_struct(nb+2,block_length,block_displ,block_type,frmarkers_type,mpierr) ABI_FREE(block_length) ABI_FREE(block_displ) ABI_FREE(block_type) call MPI_TYPE_COMMIT(frmarkers_type,mpierr) call MPI_FILE_SET_VIEW(myfh,offset,MPI_BYTE,frmarkers_type,"native",MPI_INFO_NULL,mpierr) jj=1 ABI_MALLOC(delim_record,(nb)) do irec=1,nfrec delim_record(jj:jj+1)=bsize_frecord(irec) jj=jj+2 end do ! Write all markers according to the MPI type of the Fortran marker. SELECT CASE (bsize_frm) CASE (4) ABI_MALLOC(bufdelim4,(nb)) bufdelim4=delim_record if (sc_mode==xmpio_single) then call MPI_FILE_WRITE (myfh,bufdelim4,2*nfrec,mpi_type_frm,MPI_STATUS_IGNORE,mpierr) else if (sc_mode==xmpio_collective) then call MPI_FILE_WRITE_ALL(myfh,bufdelim4,2*nfrec,mpi_type_frm,MPI_STATUS_IGNORE,mpierr) else ierr=2 end if ABI_FREE(bufdelim4) CASE (8) ABI_MALLOC(bufdelim8,(nb)) bufdelim8=delim_record if (sc_mode==xmpio_single) then call MPI_FILE_WRITE (myfh,bufdelim8,2*nfrec,mpi_type_frm,MPI_STATUS_IGNORE,mpierr) else if (sc_mode==xmpio_collective) then call MPI_FILE_WRITE_ALL(myfh,bufdelim8,2*nfrec,mpi_type_frm,MPI_STATUS_IGNORE,mpierr) else ierr=2 end if ABI_FREE(bufdelim8) #ifdef HAVE_FC_INT_QUAD CASE (16) ABI_MALLOC(bufdelim16,(nb)) bufdelim16=delim_record if (sc_mode==xmpio_single) then call MPI_FILE_WRITE (myfh,bufdelim16,2*nfrec,mpi_type_frm,MPI_STATUS_IGNORE,mpierr) else if (sc_mode==xmpio_collective) then call MPI_FILE_WRITE_ALL(myfh,bufdelim16,2*nfrec,mpi_type_frm,MPI_STATUS_IGNORE,mpierr) else ierr=2 end if ABI_FREE(bufdelim16) #endif CASE (2) ABI_MALLOC(bufdelim2,(nb)) bufdelim2=delim_record if (sc_mode==xmpio_single) then call MPI_FILE_WRITE (myfh,bufdelim2,2*nfrec,mpi_type_frm,MPI_STATUS_IGNORE,mpierr) else if (sc_mode==xmpio_collective) then call MPI_FILE_WRITE_ALL(myfh,bufdelim2,2*nfrec,mpi_type_frm,MPI_STATUS_IGNORE,mpierr) else ierr=2 end if ABI_FREE(bufdelim2) CASE DEFAULT ierr=-2 END SELECT ! Free memory call MPI_TYPE_FREE(frmarkers_type,mpierr) ABI_FREE(delim_record) end subroutine xmpio_write_frmarkers #endif !!*** !------------------------------------------------------------------------------------ !!****f* m_xmpi/xmpio_create_fherm_packed !! NAME !! xmpio_create_fherm_packed !! !! FUNCTION !! Returns an MPI datatype that can be used to (read|write) with MPI-IO the columns of an !! Hermitian matrix whose upper triangle is written on a Fortran binary file. !! Note that the view assumes that the file pointer used to create the MPI-IO view !! points to the first element of the first column. In other words,the first Fortran record marker !! (if any) is not taken into account in the calculation of the displacements. !! !! INPUTS !! array_of_starts(2)=starting coordinates in the global Hermitian matrix !! (array of positive integers with jj>=ii, Fortran convention) !! array_of_ends(2)=final coordinates in the global Hermitian matrix !! (array of positive integers, jj>=ii, Fortran convention) !! is_fortran_file=.FALSE. is C stream is used. .TRUE. for writing Fortran binary files. !! old_type=MPI datatype of the elements of the matrix. !! !! OUTPUT !! my_offset=Offset relative to the beginning of the matrix in the file. !! hmat_type=New MPI type. !! offset_err= error code !! !! NOTES !! The matrix on file is written in the following FORTRAN format (let us assume a 3x3 matrix for simplicity) !! !! m (1,1) m !! m (1,2) (2,2) m !! m (1,3) (2,3) (3,3) m !! !! each Fortran record stores a column of the packed Hermitian matrix, "m" denotes the Fortran !! record marker that introduces holes in the MPI-IO file view. !! To read the columns from (1,2) up to (2,2) one should use array_of_starts=(1,2) and array_of_ends=(2,2). !! The MPI-IO file view should be created by moving the file pointer so that it points to the elements (1,2). !! !! NOTES !! File views for C-streams is not optimal since one can use a single slice of contigous data. !! !! PARENTS !! exc_build_block !! !! CHILDREN !! mpi_type_commit,mpi_type_size,xmpi_abort,xmpio_type_struct !! !! SOURCE #ifdef HAVE_MPI_IO subroutine xmpio_create_fherm_packed(array_of_starts,array_of_ends,is_fortran_file,my_offset,old_type,hmat_type,offset_err) !This section has been created automatically by the script Abilint (TD). !Do not modify the following lines by hand. #undef ABI_FUNC #define ABI_FUNC 'xmpio_create_fherm_packed' !End of the abilint section implicit none !Arguments ------------------------------------ !scalars integer,intent(in) :: old_type integer,intent(out) :: offset_err,hmat_type integer(XMPI_OFFSET_KIND),intent(out) :: my_offset logical,intent(in) :: is_fortran_file !arrays integer,intent(in) :: array_of_starts(2),array_of_ends(2) !Local variables------------------------------- !scalars integer :: nrow,my_ncol,ii,bsize_old,col,jj_glob,bsize_frm,prev_col,mpierr integer(XMPI_OFFSET_KIND) :: col_displ !arrays integer,allocatable :: col_type(:),block_length(:),block_type(:) integer(XMPI_ADDRESS_KIND),allocatable :: block_displ(:) !************************************************************************ offset_err=0 ! Byte size of old_type. call MPI_TYPE_SIZE(old_type,bsize_old,mpierr) bsize_frm=0; if (is_fortran_file) bsize_frm = xmpio_bsize_frm my_ncol = array_of_ends(2) - array_of_starts(2) + 1 ! ! Calculate my offset relative to the beginning of the matrix in the file. prev_col = array_of_starts(2)-1 my_offset = (prev_col*(prev_col+1)/2)*bsize_old + (array_of_starts(1)-1)*bsize_old + 2*prev_col*bsize_frm + bsize_frm ! ! col_type(col) describes the col-th column of the packed matrix. ! block_displ(col+1) stores its displacement taking into account the Fortran marker. ABI_MALLOC(col_type,(my_ncol)) ABI_MALLOC(block_displ,(my_ncol+2)) if (my_ncol>1) then col_displ=0 do col=1,my_ncol jj_glob = (col-1) + array_of_starts(2) nrow = jj_glob if (jj_glob==array_of_starts(2)) nrow = jj_glob - array_of_starts(1) + 1 ! First column treated by me. if (jj_glob==array_of_ends(2)) nrow = array_of_ends(1) ! Last column treated by me. call MPI_Type_contiguous(nrow,old_type,col_type(col),mpierr) ! if (xmpio_max_address(col_displ)) offset_err=1 ! Test for wraparounds block_displ(col+1) = col_displ col_displ = col_displ + nrow * bsize_old + 2 * bsize_frm ! Move to the next column. end do else if (my_ncol==1) then ! The case of a single column is treated separately. block_displ(2) = 0 nrow = array_of_ends(1) - array_of_starts(1) + 1 call MPI_Type_contiguous(nrow,old_type,col_type(2),mpierr) col_displ= nrow*bsize_old if (xmpio_max_address(col_displ)) offset_err=1 ! Test for wraparounds else call xmpi_abort(msg="my_ncol cannot be negative!") end if ABI_MALLOC(block_length,(my_ncol+2)) ABI_MALLOC(block_type,(my_ncol+2)) block_length(1)=1 block_displ (1)=0 block_type (1)=MPI_LB do ii=2,my_ncol+1 block_length(ii)=1 block_type(ii) =col_type(ii-1) !write(std_out,*)" ii-1, depl, length, type: ",ii-1,block_displ(ii),block_length(ii),block_type(ii) end do block_length(my_ncol+2)= 1 block_displ (my_ncol+2)= col_displ block_type (my_ncol+2)= MPI_UB call xmpio_type_struct(my_ncol+2,block_length,block_displ,block_type,hmat_type,mpierr) call MPI_TYPE_COMMIT(hmat_type,mpierr) ABI_FREE(block_length) ABI_FREE(block_displ) ABI_FREE(block_type) do col=1,my_ncol call MPI_TYPE_FREE(col_type(col),mpierr) end do ABI_FREE(col_type) end subroutine xmpio_create_fherm_packed !!*** #endif !------------------------------------------------------------------------------------ !!****f* m_xmpi/xmpio_create_coldistr_from_fpacked !! NAME !! xmpio_create_coldistr_from_fpacked !! !! FUNCTION !! Returns an MPI datatype that can be used to MPI-IO (read|write) the columns of an !! (Hermitian|Symmetric) matrix whose upper triangle is written on a Fortran binary file. !! Note that the view assumes that the file pointer used to instanciate the MPI-IO view !! points to the first element of the first column. In other words,the first Fortran record marker !! (if any) is not taken into account in the calculation of the displacements. !! !! INPUTS !! sizes(2)=Number of elements of type old_type in each dimension of the full array (array of positive integers) !! my_cols(2)=initial and final column to (read|write). Array of positive integers, Fortran convention. !! old_type=MPI datatype of the elements of the matrix. !! !! OUTPUT !! new_type=New MPI type that can be used to instanciate the MPI-IO view for the Fortran file. !! my_offpad=Offset to be added to the file pointer giving the position of the first Fortran record !! marker (lets call it "base"). Each node should (read|write) using my_offset = base + my_offpad. !! my_offpad is used so that one can safely change the way the fileview is generated (for example !! to make it more efficient) without having to change the client code. !! offset_err=Error code. A non-zero returned value signals that the global matrix is tool large !! for a single MPI-IO access (see notes below). !! !! NOTES !! 1) The matrix on file is written in the following FORTRAN format (let us assume a 3x3 matrix for simplicity) !! !! m (1,1) m !! m (1,2) (2,2) m !! m (1,3) (2,3) (3,3) m !! !! each Fortran record stores a column of the packed matrix, "m" denotes the Fortran !! record marker that introduces holes in the file view. !! !! 2) With (signed) Fortran integers, the maximum size of the file that !! that can be read in one-shot is around 2Gb when etype is set to byte. !! Using a larger etype might create portability problems (real data on machines using !! integer*16 for the marker) since etype must be a multiple of the Fortran record marker !! Due to the above reason, block_displ is given in bytes but it has to be defined as Fortran !! integer. If the displacement cannot be stored in a Fortran integer, the routine returns !! offset_err=1 so that the caller will know that several MPI-IO reads are nedded to !! read the file. !! !! PARENTS !! m_bse_io !! !! CHILDREN !! mpi_type_commit,mpi_type_size,xmpi_abort,xmpio_type_struct !! !! SOURCE #ifdef HAVE_MPI_IO subroutine xmpio_create_coldistr_from_fpacked(sizes,my_cols,old_type,new_type,my_offpad,offset_err) !This section has been created automatically by the script Abilint (TD). !Do not modify the following lines by hand. #undef ABI_FUNC #define ABI_FUNC 'xmpio_create_coldistr_from_fpacked' !End of the abilint section implicit none !Arguments ------------------------------------ !scalars integer,intent(in) :: old_type integer,intent(out) :: new_type,offset_err integer(XMPI_OFFSET_KIND),intent(out) :: my_offpad !arrays integer,intent(in) :: sizes(2),my_cols(2) !Local variables------------------------------- !scalars integer :: my_ncol,bsize_old,my_col integer :: my_nels,my_el,row_glob,ii_hpk,jj_hpk,col_glob,bsize_frm,mpierr integer(XMPI_OFFSET_KIND) :: my_offset,ijp_glob !character(len=500) :: msg !arrays integer,allocatable :: block_length(:),block_type(:) integer(XMPI_ADDRESS_KIND),allocatable :: block_displ(:) !************************************************************************ ! Byte size of the Fortran record marker. bsize_frm = xmpio_bsize_frm ! Byte size of old_type. call MPI_TYPE_SIZE(old_type,bsize_old,mpierr) ! my number of columns and total numer of elements to be read. my_ncol = my_cols(2) - my_cols(1) + 1 my_nels = my_ncol*sizes(1) ! ! block_displ(el+1) stores the displacement of the local element el taking into account the Fortran marker. ABI_MALLOC(block_displ,(my_nels+2)) ABI_MALLOC(block_length,(my_nels+2)) ABI_MALLOC(block_type,(my_nels+2)) block_length(1)=1 block_displ (1)=0 block_type (1)=MPI_LB ! ! * the view assumes that the file pointer used to instanciate the MPI-IO view ! points to the first element of the first column. In other words,the first Fortran record marker ! is not taken into account in the calculation of the displacements. my_offpad=xmpio_bsize_frm ! * Some matrix elements are read twice. This part has to be tested. offset_err=0; my_el=0 do my_col=1,my_ncol col_glob = (my_col-1) + my_cols(1) do row_glob=1,sizes(1) if (col_glob>=row_glob) then ii_hpk = row_glob jj_hpk = col_glob ijp_glob = row_glob + col_glob*(col_glob-1)/2 ! Index for packed form else ! Exchange the indeces as (jj,ii) will be read. ii_hpk = col_glob jj_hpk = row_glob ijp_glob = col_glob + row_glob*(row_glob-1)/2 ! Index for packed form end if my_el = my_el+1 my_offset = (ijp_glob-1)* bsize_old + (jj_hpk-1)*2*bsize_frm if (xmpio_max_address(my_offset)) offset_err=1 ! Check for wraparounds. block_displ (my_el+1)=my_offset block_length(my_el+1)=1 block_type (my_el+1)=old_type !write(std_out,*)" my_el, displ: ",my_el,block_displ(my_el+1) end do end do block_length(my_nels+2)=1 block_displ (my_nels+2)=my_offset block_type (my_nels+2)=MPI_UB call xmpio_type_struct(my_nels+2,block_length,block_displ,block_type,new_type,mpierr) call MPI_TYPE_COMMIT(new_type,mpierr) ABI_FREE(block_length) ABI_FREE(block_displ) ABI_FREE(block_type) end subroutine xmpio_create_coldistr_from_fpacked !!*** #endif !------------------------------------------------------------------------------------ !!****f* m_xmpi/xmpio_create_coldistr_from_fp3blocks !! NAME !! xmpio_create_coldistr_from_fp3blocks !! !! FUNCTION !! Returns an MPI datatype that can be used to MPI-IO (read|write) the columns of a !! matrix of the form M = (S1 F3) !! (F3^H S2) !! where S1 and S2 are square (symmetric|Hermitian) matrices whose upper triangle is stored on file !! while F3 is a generic matrix (not necessarily square) stored in full mode. !! The Fortran file contains the blocks in the following order. !! upper(S1) !! upper(S2) !! F3 !! INPUTS !! sizes(2)=Number of elements of type old_type in each dimension of the full array M (array of positive integers) !! my_cols(2)=initial and final column to (read|write). Array of positive integers, Fortran convention. !! block_sizes(2,3)=The sizes of S1, S2, F. !! old_type=MPI datatype of the elements of the matrix. !! !! OUTPUT !! new_type=New MPI type that can be used to instanciate the MPI-IO view for the Fortran file. !! my_offpad=Offset to be added to the file pointer giving the position of the first Fortran record !! marker (lets call it "base"). Each node should (read|write) using my_offset = base + my_offpad. !! my_offpad is used so that one can safely change the way the fileview is generated (for example !! to make it more efficient) without having to change the client code. !! offset_err=Error code. A non-zero returned value signals that the global matrix is tool large !! for a single MPI-IO access (see notes below). !! !! NOTES !! 1) block_displ is given in bytes due to the presence of the marker. !! If the displacement of an element is too large, the routine returns !! offset_err=1 so that the caller knows that several MPI-IO reads are required to (read| write) the file. !! !! PARENTS !! m_bse_io !! !! CHILDREN !! mpi_type_commit,mpi_type_size,xmpi_abort,xmpio_type_struct !! !! SOURCE #ifdef HAVE_MPI_IO subroutine xmpio_create_coldistr_from_fp3blocks(sizes,block_sizes,my_cols,old_type,new_type,my_offpad,offset_err) !This section has been created automatically by the script Abilint (TD). !Do not modify the following lines by hand. #undef ABI_FUNC #define ABI_FUNC 'xmpio_create_coldistr_from_fp3blocks' !End of the abilint section implicit none !Arguments ------------------------------------ !scalars integer,intent(in) :: old_type integer,intent(out) :: new_type,offset_err integer(XMPI_OFFSET_KIND),intent(out) :: my_offpad !arrays integer,intent(in) :: sizes(2),my_cols(2),block_sizes(2,3) !Local variables------------------------------- !scalars integer :: my_ncol,bsize_old,my_col,which_block,uplo,swap integer :: my_nels,my_el,row_glob,ii_hpk,jj_hpk,ii,jj integer :: col_glob,bsize_frm,mpierr,row_shift,col_shift,n1,n2 integer(XMPI_OFFSET_KIND) :: my_offset,ijp,bsize_tot,max_displ,min_displ integer(XMPI_ADDRESS_KIND) :: address !arrays integer,allocatable :: block_length(:),block_type(:) integer(XMPI_ADDRESS_KIND),allocatable :: block_displ(:) integer(XMPI_OFFSET_KIND) :: bsize_mat(2) !************************************************************************ if ( sizes(1) /= SUM(block_sizes(1,1:2)) .or. & & sizes(2) /= SUM(block_sizes(2,1:2)) ) then write(std_out,*)" xmpio_create_coldistr_from_fp3blocks: Inconsistency between block_sizes ans sizes " call xmpi_abort() end if if ( block_sizes(1,1)/=block_sizes(2,1) .or.& & block_sizes(1,2)/=block_sizes(2,2) ) then write(std_out,*)" xmpio_create_coldistr_from_fp3blocks: first two blocks must be square" call xmpi_abort() end if if ( block_sizes(2,3)/=block_sizes(2,2) .or.& & block_sizes(1,3)/=block_sizes(1,1) ) then write(std_out,*)" xmpio_create_coldistr_from_fp3blocks: Full matrix must be square" call xmpi_abort() end if write(std_out,*)" xmpio_create_coldistr_from_fp3blocks is still under testing" !call xmpi_abort() ! Byte size of the Fortran record marker. bsize_frm = xmpio_bsize_frm ! Byte size of old_type. call MPI_TYPE_SIZE(old_type,bsize_old,mpierr) ! my number of columns and total numer of elements to be read. my_ncol = my_cols(2) - my_cols(1) + 1 my_nels = sizes(1)*my_ncol ! ! block_displ(el+1) stores the displacement of the local element el taking into account the Fortran marker. ABI_MALLOC(block_displ,(my_nels+2)) ABI_MALLOC(block_length,(my_nels+2)) ABI_MALLOC(block_type,(my_nels+2)) ! ! * the view assumes that the file pointer used to instanciate the MPI-IO view ! points to the first element of the first column. In other words,the first Fortran record marker ! is not taken into account in the calculation of the displacements. my_offpad=xmpio_bsize_frm ! ! Byte size of the first two blocks including the markers. n1=block_sizes(1,1) bsize_mat(1) = (n1*(n1+1)/2)*bsize_old + 2*n1*bsize_frm n2=block_sizes(1,2) bsize_mat(2) = (n2*(n2+1)/2)*bsize_old + 2*n2*bsize_frm bsize_tot=SUM(bsize_mat) + PRODUCT(block_sizes(:,3))*bsize_old + block_sizes(2,3)*2*bsize_frm - bsize_frm write(std_out,*)"bsize_mat",bsize_mat,"bsize_tot",bsize_tot ! ! * Some matrix elements are read twice. This part has to be tested. offset_err=0; my_el=0; max_displ=0; min_displ=HUGE(address) do my_col=1,my_ncol col_glob = (my_col-1) + my_cols(1) do row_glob=1,sizes(1) ! which_block=3 if (row_glob<=block_sizes(1,1).and.col_glob<=block_sizes(2,1)) which_block=1 if (row_glob >block_sizes(1,1).and.col_glob >block_sizes(2,1)) which_block=2 if ( ANY(which_block == (/1,2/)) ) then ! S1 or S2 ! row_shift=(which_block-1)*block_sizes(1,1) col_shift=(which_block-1)*block_sizes(2,1) ii_hpk = row_glob - row_shift jj_hpk = col_glob - col_shift if (jj_hpkblock_sizes(1,1)) uplo=2 if (uplo==1) then row_shift=0 col_shift=block_sizes(2,1) else row_shift=block_sizes(1,1) col_shift=0 end if ii = row_glob - row_shift jj = col_glob - col_shift if (uplo==2) then ! Exchange the indeces since the symmetric element will be read. swap=jj jj =ii ii =swap end if my_offset = (ii-1)*bsize_old + (jj-1)*block_sizes(1,3)*bsize_old + (jj-1)*2*bsize_frm my_offset = my_offset + SUM(bsize_mat) !if (uplo==1) my_offset=my_offset + bsize_mat(1) !my_offset=0 !if (ii==1.and.jj==1) write(std_out,*)" (1,1) offset = ",my_offset !if (ii==block_sizes(1,3).and.jj==block_sizes(2,3)) write(std_out,*)" (n,n) offset =", my_offset if (my_offset>=bsize_tot-1*bsize_old) then write(std_out,*)"WARNING (my_offset>bsize_tot-bsize_old),",ii,jj,my_offset,bsize_tot end if end if if (xmpio_max_address(my_offset)) offset_err=1 ! Check for wraparounds. my_el = my_el+1 block_displ (my_el+1)=my_offset block_length(my_el+1)=1 block_type (my_el+1)=old_type max_displ = MAX(max_displ,my_offset) min_displ = MIN(min_displ,my_offset) !if (which_block==3) write(std_out,*)" my_el, which, displ: ",my_el,which_block,block_displ(my_el+1) end do end do write(std_out,*)" MAX displ = ",max_displ," my_nels = ",my_nels write(std_out,*)" MIN displ = ",MINVAL(block_displ(2:my_nels+1)) !block_displ (1)=max_displ ! Do not change this value. !if (min_displ>0) block_displ (1)=min_displ ! Do not change this value. block_displ (1)=min_displ block_displ (1)=0 block_length(1)=0 block_type (1)=MPI_LB block_length(my_nels+2)=0 !block_displ (my_nels+2)=bsize_tot block_displ (my_nels+2)=max_displ block_type (my_nels+2)=MPI_UB call xmpio_type_struct(my_nels+2,block_length,block_displ,block_type,new_type,mpierr) !call xmpio_type_struct(my_nels,block_length(2:),block_displ(2:),block_type(2:),new_type,mpierr) !call MPI_TYPE_CREATE_INDEXED_BLOCK(my_nels, block_length(2:), block_displ(2:), old_type, new_type, mpierr) call MPI_TYPE_COMMIT(new_type,mpierr) ABI_FREE(block_length) ABI_FREE(block_displ) ABI_FREE(block_type) end subroutine xmpio_create_coldistr_from_fp3blocks !!*** #endif END MODULE m_xmpi !!*** v_sim-3.8.0/lib/plug-ins/abinit/mati3det.F90000066400000000000000000000024501370110300500203720ustar00rootroot00000000000000!{\src2tex{textfont=tt}} !!****f* ABINIT/mati3det !! NAME !! mati3det !! !! FUNCTION !! COmpute the determinant of a 3x3 matrix of INTEGER elements. !! !! COPYRIGHT !! Copyright (C) 2016 ABINIT group (XG) !! This file is distributed under the terms of the !! GNU General Public License, see ~abinit/COPYING !! or http://www.gnu.org/copyleft/gpl.txt . !! !! INPUTS !! mm = integer matrix !! !! OUTPUT !! det = determinant of the matrix !! !! NOTES !! !! PARENTS !! get_kpt_fullbz,getspinrot,m_ab7_symmetry,symdet !! !! CHILDREN !! !! SOURCE #if defined HAVE_CONFIG_H #include "config.h" #endif #include "abi_common.h" subroutine mati3det(mm,det) use defs_basis !This section has been created automatically by the script Abilint (TD). !Do not modify the following lines by hand. #undef ABI_FUNC #define ABI_FUNC 'mati3det' !End of the abilint section implicit none !Arguments ------------------------------------ !arrays integer,intent(in) :: mm(3,3) integer,intent(out) :: det !Local variables------------------------------- !scalars ! ************************************************************************* det=mm(1,1)*(mm(2,2) * mm(3,3) - mm(3,2) * mm(2,3)) & & + mm(2,1)*(mm(3,2) * mm(1,3) - mm(1,2) * mm(3,3)) & & + mm(3,1)*(mm(1,2) * mm(2,3) - mm(2,2) * mm(1,3)) end subroutine mati3det !!*** v_sim-3.8.0/lib/plug-ins/abinit/mati3inv.F90000066400000000000000000000054551370110300500204220ustar00rootroot00000000000000!{\src2tex{textfont=tt}} !!****f* ABINIT/mati3inv !! NAME !! mati3inv !! !! FUNCTION !! Invert and transpose orthogonal 3x3 matrix of INTEGER elements. !! !! COPYRIGHT !! Copyright (C) 1998-2016 ABINIT group (DCA, XG, GMR) !! This file is distributed under the terms of the !! GNU General Public License, see ~abinit/COPYING !! or http://www.gnu.org/copyleft/gpl.txt . !! !! INPUTS !! mm = integer matrix to be inverted !! !! OUTPUT !! mit = inverse of mm input matrix !! !! NOTES !! Used for symmetry operations. !! This routine applies to ORTHOGONAL matrices only. !! Since these form a group, inverses are also integer !! arrays. Returned array is TRANSPOSE of inverse, as needed. !! Note use of integer arithmetic. !! Also: has been designed so that mit can be same storage space as m, in !! which case m is overwritten by resulting mit. !! !! PARENTS !! cg_rotate,chkgrp,classify_bands,debug_tools,dfpt_nstdy,get_full_kgrid !! get_npert_rbz,getkgrid,ingeo,m_ab7_symmetry,m_crystal,m_ddb,m_dvdb !! m_dynmat,m_fft_mesh,m_fock,m_ptgroups,matpointsym,memory_eval,optic !! read_gkk,setsym,strainsym,thmeig,wfconv !! !! CHILDREN !! !! SOURCE #if defined HAVE_CONFIG_H #include "config.h" #endif #include "abi_common.h" subroutine mati3inv(mm,mit) use defs_basis use m_profiling_abi use m_errors !This section has been created automatically by the script Abilint (TD). !Do not modify the following lines by hand. #undef ABI_FUNC #define ABI_FUNC 'mati3inv' !End of the abilint section implicit none !Arguments ------------------------------------ !arrays integer,intent(in) :: mm(3,3) integer,intent(out) :: mit(3,3) !Local variables------------------------------- !scalars integer :: dd character(len=500) :: message !arrays integer :: tt(3,3) ! ************************************************************************* tt(1,1) = mm(2,2) * mm(3,3) - mm(3,2) * mm(2,3) tt(2,1) = mm(3,2) * mm(1,3) - mm(1,2) * mm(3,3) tt(3,1) = mm(1,2) * mm(2,3) - mm(2,2) * mm(1,3) tt(1,2) = mm(3,1) * mm(2,3) - mm(2,1) * mm(3,3) tt(2,2) = mm(1,1) * mm(3,3) - mm(3,1) * mm(1,3) tt(3,2) = mm(2,1) * mm(1,3) - mm(1,1) * mm(2,3) tt(1,3) = mm(2,1) * mm(3,2) - mm(3,1) * mm(2,2) tt(2,3) = mm(3,1) * mm(1,2) - mm(1,1) * mm(3,2) tt(3,3) = mm(1,1) * mm(2,2) - mm(2,1) * mm(1,2) dd = mm(1,1) * tt(1,1) + mm(2,1) * tt(2,1) + mm(3,1) * tt(3,1) !Make sure matrix is not singular if (dd/=0) then mit(:,:)=tt(:,:)/dd else write(message, '(2a,2x,9i5,a)' )& & ' Attempting to invert integer array',ch10,& & mm(:,:),' ==> determinant is zero.' MSG_BUG(message) end if !If matrix is orthogonal, determinant must be 1 or -1 if (abs(dd)/=1) then write(message, '(2a,2x,9i5,a)' )& & ' Absolute value of determinant should be one',ch10,& & ' but determinant=',dd MSG_BUG(message) end if end subroutine mati3inv !!*** v_sim-3.8.0/lib/plug-ins/abinit/matr3inv.F90000066400000000000000000000052621370110300500204270ustar00rootroot00000000000000!{\src2tex{textfont=tt}} !!****f* ABINIT/matr3inv !! NAME !! matr3inv !! !! FUNCTION !! Invert and transpose general 3x3 matrix of real*8 elements. !! !! COPYRIGHT !! Copyright (C) 1998-2016 ABINIT group (DCA, XG, GMR) !! This file is distributed under the terms of the !! GNU General Public License, see ~abinit/COPYING !! or http://www.gnu.org/copyleft/gpl.txt . !! !! INPUTS !! aa = 3x3 matrix to be inverted !! !! OUTPUT !! ait = inverse of aa input matrix !! !! NOTES !! Returned array is TRANSPOSE of inverse, as needed to get g from r. !! !! PARENTS !! berryphase,chkdilatmx,conducti_nc,ddb_hybrid,dfpt_mkvxc,dfpt_mkvxcstr !! dfpt_symph,electrooptic,ep_el_weights,ep_fs_weights,ep_ph_weights !! get_kpt_fullbz,getghcnd,getkgrid,getspinrot,gstate,harmonic_thermo !! invars2,inwffil,m_cut3d,m_ddb,m_double_grid,m_dvdb,m_dynmat,m_ebands !! m_esymm,m_ewald,m_fock,m_ifc,m_phgamma,m_phonon_supercell,m_phonons !! m_psps,make_efg_el,make_efg_ion,metric,optic,outwant,pimd_langevin_npt !! prtxf,relaxpol,smpbz,stresssym,symbrav,symlatt,symmetrize_rprimd !! symrelrot,symrhg,tddft,testkgrid,tetrahedron,thmeig,uderiv,xcart2xred !! xfpack_x2vin !! !! CHILDREN !! !! SOURCE #if defined HAVE_CONFIG_H #include "config.h" #endif #include "abi_common.h" subroutine matr3inv(aa,ait) use defs_basis use m_errors !This section has been created automatically by the script Abilint (TD). !Do not modify the following lines by hand. #undef ABI_FUNC #define ABI_FUNC 'matr3inv' !End of the abilint section implicit none !Arguments ------------------------------------ !arrays real(dp),intent(in) :: aa(3,3) real(dp),intent(out) :: ait(3,3) !Local variables------------------------------- !scalars real(dp) :: dd,det,t1,t2,t3 character(len=500) :: message ! ************************************************************************* t1 = aa(2,2) * aa(3,3) - aa(3,2) * aa(2,3) t2 = aa(3,2) * aa(1,3) - aa(1,2) * aa(3,3) t3 = aa(1,2) * aa(2,3) - aa(2,2) * aa(1,3) det = aa(1,1) * t1 + aa(2,1) * t2 + aa(3,1) * t3 !Make sure matrix is not singular if (abs(det)>tol16) then dd=one/det else write(message, '(2a,2x,9es16.8,a,a,es16.8,a)' )& & ' Attempting to invert real(8) 3x3 array',ch10,& & aa(:,:),ch10,& & ' ==> determinant=',det,' is zero.' MSG_BUG(message) end if ait(1,1) = t1 * dd ait(2,1) = t2 * dd ait(3,1) = t3 * dd ait(1,2) = (aa(3,1)*aa(2,3)-aa(2,1)*aa(3,3)) * dd ait(2,2) = (aa(1,1)*aa(3,3)-aa(3,1)*aa(1,3)) * dd ait(3,2) = (aa(2,1)*aa(1,3)-aa(1,1)*aa(2,3)) * dd ait(1,3) = (aa(2,1)*aa(3,2)-aa(3,1)*aa(2,2)) * dd ait(2,3) = (aa(3,1)*aa(1,2)-aa(1,1)*aa(3,2)) * dd ait(3,3) = (aa(1,1)*aa(2,2)-aa(2,1)*aa(1,2)) * dd end subroutine matr3inv !!*** v_sim-3.8.0/lib/plug-ins/abinit/metric.F90000066400000000000000000000134371370110300500201520ustar00rootroot00000000000000!{\src2tex{textfont=tt}} !!****f* ABINIT/metric !! NAME metric !! metric !! !! FUNCTION !! Compute first dimensional primitive translation vectors in reciprocal space !! gprimd from rprimd, and eventually writes out. !! Then, computes metrics for real and recip space rmet and gmet using length !! dimensional primitive translation vectors in columns of rprimd(3,3) and gprimd(3,3). !! gprimd is the inverse transpose of rprimd. !! i.e. $ rmet_{i,j}= \sum_k ( rprimd_{k,i}*rprimd_{k,j} ) $ !! $ gmet_{i,j}= \sum_k ( gprimd_{k,i}*gprimd_{k,j} ) $ !! Also computes unit cell volume ucvol in $\textrm{bohr}^3$ !! !! COPYRIGHT !! Copyright (C) 1998-2016 ABINIT group (DCA, XG, GMR) !! This file is distributed under the terms of the !! GNU General Public License, see ~abinit/COPYING !! or http://www.gnu.org/copyleft/gpl.txt . !! !! INPUTS !! rprimd(3,3)=dimensional primitive translations for real space (bohr) !! iout=unit number of output file. If iout<0, do not write output. !! !! OUTPUT !! gmet(3,3)=reciprocal space metric ($\textrm{bohr}^{-2}$). !! gprimd(3,3)=dimensional primitive translations for reciprocal space ($\textrm{bohr}^{-1}$) !! rmet(3,3)=real space metric ($\textrm{bohr}^{2}$). !! ucvol=unit cell volume ($\textrm{bohr}^{3}$). !! !! PARENTS !! afterscfloop,bethe_salpeter,chkinp,clnup1,conducti_nc,conducti_paw !! conducti_paw_core,cut3d,d2frnl,dfpt_eltfrhar,dfpt_eltfrkin,dfpt_eltfrxc !! dfpt_looppert,dfpt_newvtr,dfpt_scfcv,dist2,elpolariz,emispec_paw,energy !! etotfor,extrapwf,fftprof,finddistrproc,forces,get_npert_rbz,getkgrid !! ingeo,initaim,initberry,inkpts,inqpt,invacuum,invars2m,ks_ddiago !! linear_optics_paw,m_ab7_symmetry,m_commutator_vkbr,m_crystal,m_cut3d !! m_ddb,m_fft,m_fft_prof,m_hamiltonian,m_io_kss,m_ioarr,m_mep,m_pawpwij !! m_pred_lotf,m_screening,m_use_ga,m_vcoul,m_wfk,mag_constr,mag_constr_e !! memory_eval,mkcore_wvl,mlwfovlp_qp,moddiel,mover,mpi_setup,mrgscr !! newrho,newvtr,nres2vres,odamix,optic,partial_dos_fractions,pawgrnl !! prcref,prcref_PMA,pred_bfgs,pred_delocint,pred_diisrelax !! pred_isokinetic,pred_isothermal,pred_langevin,pred_nose,pred_srkna14 !! pred_steepdesc,pred_verlet,prt_cif,prtefield,prtimg,psolver_rhohxc !! rhohxc,scfcv,screening,setup1,setup_bse,setup_screening,setup_sigma !! sigma,smallprim,stress,symmetrize_rprimd,testkgrid,tetrahedron,thmeig !! vdw_dftd2,vdw_dftd3,wrt_moldyn_netcdf,wvl_initro,xfpack_vin2x !! xfpack_x2vin !! !! CHILDREN !! matr3inv,wrtout !! !! SOURCE #if defined HAVE_CONFIG_H #include "config.h" #endif #include "abi_common.h" subroutine metric(gmet,gprimd,iout,rmet,rprimd,ucvol) use defs_basis use m_errors use m_profiling_abi !This section has been created automatically by the script Abilint (TD). !Do not modify the following lines by hand. #undef ABI_FUNC #define ABI_FUNC 'metric' use interfaces_14_hidewrite use interfaces_32_util !End of the abilint section implicit none !Arguments ------------------------------------ !scalars integer,intent(in) :: iout real(dp),intent(out) :: ucvol !arrays real(dp),intent(in) :: rprimd(3,3) real(dp),intent(out) :: gmet(3,3),gprimd(3,3),rmet(3,3) !Local variables------------------------------- !scalars integer :: nu character(len=500) :: message !arrays real(dp) :: angle(3) ! ************************************************************************* !Compute unit cell volume ucvol=rprimd(1,1)*(rprimd(2,2)*rprimd(3,3)-rprimd(3,2)*rprimd(2,3))+& & rprimd(2,1)*(rprimd(3,2)*rprimd(1,3)-rprimd(1,2)*rprimd(3,3))+& & rprimd(3,1)*(rprimd(1,2)*rprimd(2,3)-rprimd(2,2)*rprimd(1,3)) !Check that the input primitive translations are not linearly dependent (and none is zero); i.e. ucvol~=0 !Also ask that the mixed product is positive. if (abs(ucvol)=0) then write(message,'(2a)')' Real(R)+Recip(G) ','space primitive vectors, cartesian coordinates (Bohr,Bohr^-1):' call wrtout(iout,message,'COLL') do nu=1,3 write(message, '(1x,a,i1,a,3f11.7,2x,a,i1,a,3f11.7)' ) & & 'R(',nu,')=',rprimd(:,nu)+tol10,& & 'G(',nu,')=',gprimd(:,nu)+tol10 call wrtout(iout,message,'COLL') end do write(message,'(a,1p,e15.7,a)') ' Unit cell volume ucvol=',ucvol+tol10,' bohr^3' call wrtout(iout,message,'COLL') call wrtout(std_out,message,'COLL') end if !Compute real space metric. rmet = MATMUL(TRANSPOSE(rprimd),rprimd) !Compute reciprocal space metric. gmet = MATMUL(TRANSPOSE(gprimd),gprimd) !Write out the angles if (iout>=0) then angle(1)=acos(rmet(2,3)/sqrt(rmet(2,2)*rmet(3,3)))/two_pi*360.0d0 angle(2)=acos(rmet(1,3)/sqrt(rmet(1,1)*rmet(3,3)))/two_pi*360.0d0 angle(3)=acos(rmet(1,2)/sqrt(rmet(1,1)*rmet(2,2)))/two_pi*360.0d0 write(message, '(a,3es16.8,a)' )' Angles (23,13,12)=',angle(1:3),' degrees' call wrtout(iout,message,'COLL') call wrtout(std_out,message,'COLL') end if end subroutine metric !!*** v_sim-3.8.0/lib/plug-ins/abinit/smallprim.F90000066400000000000000000000201511370110300500206560ustar00rootroot00000000000000!{\src2tex{textfont=tt}} !!****f* ABINIT/smallprim !! !! NAME !! smallprim !! !! FUNCTION !! Find the smallest possible primitive vectors for an input lattice !! This algorithm is not as restrictive as the conditions mentioned at p.740 !! of the international tables for crystallography (1983). !! The final vectors form a right-handed basis, while their !! sign and ordering is chosen such as to maximize the overlap !! with the original vectors in order. !! !! COPYRIGHT !! Copyright (C) 2000-2016 ABINIT group (XG) !! This file is distributed under the terms of the !! GNU General Public License, see ~abinit/COPYING !! or http://www.gnu.org/copyleft/gpl.txt . !! For the initials of contributors, see ~abinit/doc/developers/contributors.txt . !! !! INPUTS !! rprimd(3,3)=primitive vectors !! !! OUTPUT !! metmin(3,3)=metric for the new (minimal) primitive vectors !! minim(3,3)=minimal primitive translations !! !! NOTES !! The routine might as well be defined without !! metmin as argument, but it is more convenient to have it !! !! PARENTS !! getkgrid,symlatt,testkgrid !! !! CHILDREN !! metric !! !! SOURCE #if defined HAVE_CONFIG_H #include "config.h" #endif #include "abi_common.h" subroutine smallprim(metmin,minim,rprimd) use defs_basis use m_errors use m_profiling_abi !This section has been created automatically by the script Abilint (TD). !Do not modify the following lines by hand. #undef ABI_FUNC #define ABI_FUNC 'smallprim' use interfaces_41_geometry, except_this_one => smallprim !End of the abilint section implicit none !Arguments ------------------------------------ !arrays real(dp),intent(in) :: rprimd(3,3) real(dp),intent(out) :: metmin(3,3),minim(3,3) !Local variables------------------------------- !scalars integer :: ia,ib,ii,itrial,minimal integer :: iiter, maxiter = 100000 real(dp) :: determinant,length2,metsum,ucvol character(len=500) :: message !arrays integer :: nvecta(3),nvectb(3) real(dp) :: gprimd(3,3),gmet(3,3),rmet(3,3),scprod(3),tmpvect(3) !************************************************************************** call metric(gmet,gprimd,-1,rmet,rprimd,ucvol) nvecta(1)=2 ; nvectb(1)=3 nvecta(2)=1 ; nvectb(2)=3 nvecta(3)=1 ; nvectb(3)=2 minim(:,:)=rprimd(:,:) metmin(:,:)=rmet(:,:) !DEBUG !write(std_out,*)' smallprim : starting values, rprim ' !write(std_out,'(3f16.8)' )rprimd(:,1) !write(std_out,'(3f16.8)' )rprimd(:,2) !write(std_out,'(3f16.8)' )rprimd(:,3) !write(std_out,*)' smallprim : starting values, rmet ' !write(std_out,'(3f16.8)' )rmet(:,1) !write(std_out,'(3f16.8)' )rmet(:,2) !write(std_out,'(3f16.8)' )rmet(:,3) !ENDDEBUG !Note this loop without index do iiter = 1, maxiter ! Will exit if minimal=1 is still valid after a trial ! to reduce the vectors of each of the three pairs minimal=1 do itrial=1,3 ia=nvecta(itrial) ; ib=nvectb(itrial) ! Make sure the scalar product is negative if(metmin(ia,ib)>tol8)then minim(:,ia)=-minim(:,ia) metmin(ia,ib)=-metmin(ia,ib) ; metmin(ib,ia)=-metmin(ib,ia) metmin(ia,itrial)=-metmin(ia,itrial) metmin(itrial,ia)=-metmin(itrial,ia) end if ! Compute the length of the sum vector length2=metmin(ia,ia)+2*metmin(ia,ib)+metmin(ib,ib) ! Replace the first vector by the sum vector if the latter is smaller if(length2/metmin(ia,ia) < one-tol8)then minim(:,ia)=minim(:,ia)+minim(:,ib) metmin(ia,ia)=length2 metmin(ia,ib)=metmin(ia,ib)+metmin(ib,ib) metmin(ia,itrial)=metmin(ia,itrial)+metmin(ib,itrial) metmin(ib,ia)=metmin(ia,ib) metmin(itrial,ia)=metmin(ia,itrial) minimal=0 ! Replace the second vector by the sum vector if the latter is smaller else if(length2/metmin(ib,ib) < one-tol8)then minim(:,ib)=minim(:,ia)+minim(:,ib) metmin(ib,ib)=length2 metmin(ia,ib)=metmin(ia,ib)+metmin(ia,ia) metmin(itrial,ib)=metmin(itrial,ib)+metmin(itrial,ia) metmin(ib,ia)=metmin(ia,ib) metmin(ib,itrial)=metmin(itrial,ib) minimal=0 end if end do if(minimal==1)exit end do if (iiter >= maxiter) then write(message,'(a,i0,a)') & & 'the loop has failed to find a set of minimal vectors in ',maxiter,' iterations.' MSG_BUG(message) end if !At this stage, the three vectors have angles between each other that are !comprised between 90 and 120 degrees. It might still be that minus the vector !that is the sum of the three vectors is smaller than the longest of these vectors do iiter = 1, maxiter ! Will exit if minimal=1 is still valid after a trial ! to replace each of the three vectors by minus the summ of the three vectors minimal=1 metsum=sum(metmin(:,:)) do itrial=1,3 ia=nvecta(itrial) ; ib=nvectb(itrial) if(metmin(ia,ia)/metsum > one + tol8)then minim(:,ia)=-minim(:,1)-minim(:,2)-minim(:,3) metmin(ia,ib)=-sum(metmin(:,ib)) metmin(ia,itrial)=-sum(metmin(:,itrial)) metmin(ia,ia)=metsum metmin(ib,ia)=metmin(ia,ib) metmin(itrial,ia)=metmin(ia,itrial) minimal=0 end if end do if(minimal==1)exit end do if (iiter >= maxiter) then write(message, '(a,i0,a)') & & 'the second loop has failed to find a set of minimal vectors in ',maxiter, 'iterations.' MSG_BUG(message) end if !DEBUG !write(std_out,'(a,3es14.6,a,3es14.6,a,3es14.6)')' rprimd=',& !& rprimd(:,1),ch10,rprimd(:,2),ch10,rprimd(:,3) !write(std_out,'(a,3es14.6,a,3es14.6,a,3es14.6)')' minim =',& !& minim(:,1),ch10,minim(:,2),ch10,minim(:,3) !ENDDEBUG !DEBUG !Change sign of the third vector if not right-handed basis !determinant=minim(1,1)*(minim(2,2)*minim(3,3)-minim(3,2)*minim(2,3))+& !& minim(2,1)*(minim(3,2)*minim(1,3)-minim(1,2)*minim(3,3))+& !& minim(3,1)*(minim(1,2)*minim(2,3)-minim(2,2)*minim(1,3)) !write(std_out,*)' smallprim: determinant=',determinant !ENDDEBUG !Choose the first vector !Compute the scalar product of the three minimal vectors !with the first original vector scprod(:)=zero do ii=1,3 scprod(:)=scprod(:)+minim(ii,:)*rprimd(ii,1) end do !Determine the vector with the maximal absolute overlap itrial=1 if(abs(scprod(2))>abs(scprod(1))+tol8)itrial=2 if(abs(scprod(3))>abs(scprod(itrial))+tol8)itrial=3 !Switch the vectors if needed if(itrial/=1)then tmpvect(:)=minim(:,1) minim(:,1)=minim(:,itrial) minim(:,itrial)=tmpvect(:) end if !Choose the sign if(scprod(itrial) symanal !End of the abilint section implicit none !Arguments ------------------------------------ !scalars integer,intent(in) :: chkprim,msym,nsym integer,intent(out) :: ptgroupma,spgroup real(dp),intent(in) :: tolsym !arrays integer,intent(out) :: bravais(11) integer,intent(in) :: symafm(msym),symrel(3,3,msym) real(dp),intent(in) :: rprimd(3,3) real(dp),intent(inout) :: tnons(3,msym) real(dp),intent(out) :: genafm(3) !Local variables------------------------------- !scalars integer :: iholohedry_nomagn,isym,isym_nomagn,multi integer :: nptsym,nsym_nomagn,shubnikov character(len=5) :: ptgroup,ptgroupha character(len=500) :: message !arrays integer :: identity(3,3) integer,allocatable :: ptsymrel(:,:,:),symrel_nomagn(:,:,:) real(dp),allocatable :: tnons_nomagn(:,:) ! ************************************************************************* !DEBUG !write(std_out,*)' symanal : enter ' !call flush(6) !stop !ENDDEBUG !This routine finds the Bravais characteristics, without actually !looking at the symmetry operations. ABI_ALLOCATE(ptsymrel,(3,3,msym)) call symlatt(bravais,msym,nptsym,ptsymrel,rprimd,tolsym) ABI_DEALLOCATE(ptsymrel) !Check whether the cell is primitive or not. call chkprimit(chkprim,multi,nsym,symafm,symrel) spgroup=0 ; ptgroupma=0 ; genafm(:)=zero if(multi>1)then ! Modify bravais if the cell is not primitive ; no determination of the space group bravais(1)=-bravais(1) else ! The cell is primitive, so that the space group can be ! determined. Need to distinguish Fedorov and Shubnikov groups. ! Do not distinguish Shubnikov types I and II. ! Also identify genafm, in case of Shubnikov type IV identity(:,:)=reshape((/1,0,0,0,1,0,0,0,1/),(/3,3/)) shubnikov=1 do isym=1,nsym if(symafm(isym)==-1)then shubnikov=3 if(sum(abs(symrel(:,:,isym)-identity(:,:)))==0)then shubnikov=4 genafm(:)=tnons(:,isym) ! DEBUG ! write(std_out,*)' isym=',isym ! write(std_out,*)' symrel(:,:,isym)',symrel(:,:,isym) ! write(std_out,*)' tnons(:,isym)',tnons(:,isym) ! write(std_out,*)' symafm(isym)',symafm(isym) ! ENDDEBUG exit end if end if end do if(shubnikov/=1)then if(shubnikov==3)write(message, '(a)' )' Shubnikov space group type III' if(shubnikov==4)write(message, '(a)' )' Shubnikov space group type IV' call wrtout(std_out,message,'COLL') end if if(shubnikov==1 .or. shubnikov==3)then ! Find the correct Bravais characteristics and point group ! Should also be used for Shubnikov groups of type IV ... call symbrav(bravais,msym,nsym,ptgroup,rprimd,symrel,tolsym) ! Find the space group call symspgr(bravais,nsym,spgroup,symrel,tnons,tolsym) end if if(shubnikov/=1)then ! Determine nonmagnetic symmetry operations nsym_nomagn=nsym/2 ABI_ALLOCATE(symrel_nomagn,(3,3,nsym_nomagn)) ABI_ALLOCATE(tnons_nomagn,(3,nsym_nomagn)) isym_nomagn=0 do isym=1,nsym if(symafm(isym)==1)then isym_nomagn=isym_nomagn+1 symrel_nomagn(:,:,isym_nomagn)=symrel(:,:,isym) tnons_nomagn(:,isym_nomagn)=tnons(:,isym) end if end do if(shubnikov==3)then ! DEBUG ! write(std_out,*)' symanal : will enter symbrav with halved symmetry set' ! write(std_out,*)' Describe the different symmetry operations (index,symrel,tnons,symafm)' ! do isym=1,nsym_nomagn ! write(std_out,'(i3,2x,9i3,3es12.2,i3)')isym,symrel_nomagn(:,:,isym),tnons_nomagn(:,isym) ! end do ! ENDDEBUG ! Find the point group of the halved symmetry set call symptgroup(iholohedry_nomagn,nsym_nomagn,ptgroupha,symrel_nomagn) ! Deduce the magnetic point group (ptgroupma) from ptgroup and ptgroupha call getptgroupma(ptgroup,ptgroupha,ptgroupma) else if(shubnikov==4)then ! Find the Fedorov space group of the halved symmetry set call symspgr(bravais,nsym_nomagn,spgroup,symrel_nomagn,tnons_nomagn,tolsym) ! The magnetic translation generator genafm has already been determined ! DEBUG ! write(std_out,*)' genafm =',genafm ! write(std_out,*)' spgroup=',spgroup ! ENDDEBUG end if ABI_DEALLOCATE(symrel_nomagn) ABI_DEALLOCATE(tnons_nomagn) end if ! Shubnikov groups end if end subroutine symanal !!*** v_sim-3.8.0/lib/plug-ins/abinit/symatm.F90000066400000000000000000000175731370110300500202060ustar00rootroot00000000000000!{\src2tex{textfont=tt}} !!****f* ABINIT/symatm !! NAME !! symatm !! !! FUNCTION !! This routine has been improved using ideas of p. 649 of notes, !! implementing suggestion of Andrew Horsfield: replace search for !! equivalent atoms using direct primitive cell translations by !! use of dot product relation which must produce an integer. !! Relation: $[inv(S(i))*(x(a)-tnons(i)) - x(inv(S)(i,a))] = integer$ !! where $S(i) =$ symmetry matrix in real space, tnons=nonsymmorphic translation !! (may be 0 0 0), and $x(inv(S)(i,a))$ is sought atom into which $x(a)$ gets !! rotated by $inv(S)$. Integer gives primitive translation coordinates to get !! back to original unit cell. !! Equivalent to $S*t(b)+tnons-x(a)=another$ $integer$ for $x(b)=x(inv(S))$. !! For each symmetry operation, find the number of the position to !! which each atom is sent in the unit cell by the INVERSE of the !! symmetry operation inv(symrel); i.e. this is the atom which, when acted !! upon by the given symmetry element isym, gets transformed into atom iatom. !! This routine uses the fact that inv(symrel)=trans(symrec), !! the inverse of the symmetry operation expressed in the basis of real !! space primitive translations equals the transpose of the same symmetry !! operation expressed in the basis of reciprocal space primitive transl. !! $xred(nu,indsym(4,isym,ia))=symrec(mu,nu,isym)*(xred(mu,ia)-tnons(mu,isym)) !! - transl(mu)$ where $transl$ is also a set of integers and !! where translation transl places coordinates within unit cell (note sign). !! Note that symrec is the set of arrays which are actually input here. !! These arrays have integer elements. !! tnons is the nonsymmorphic translation or else is zero. !! If nsym=1 (i.e. only the identity symmetry is present) then !! indsym merely takes each atom into itself. !! The array of integer translations "transl" gets included within array !! "indsym" as seen below. !! !! COPYRIGHT !! Copyright (C) 1998-2016 ABINIT group (DCA, XG, GMR) !! This file is distributed under the terms of the !! GNU General Public License, see ~abinit/COPYING !! or http://www.gnu.org/copyleft/gpl.txt . !! For the initials of contributors, see ~abinit/doc/developers/contributors.txt . !! !! INPUTS !! natom=number of atoms in cell. !! nsym=number of space group symmetries. !! symrec(3,3,nsym)=symmetries expressed in terms of their action on !! reciprocal space primitive translations (integer). !! tnons(3,nsym)=nonsymmorphic translations for each symmetry (would !! be 0 0 0 each for a symmorphic space group) !! typat(natom)=integer identifying type of atom. !! xred(3,natom)=reduced coordinates of atoms in terms of real space !! primitive translations !! tolsym=tolerance for the symmetries !! !! OUTPUT !! indsym(4,nsym,natom)=indirect indexing array described above: for each !! isym,iatom, fourth element is label of atom into !! which iatom is sent by INVERSE of symmetry operation !! isym; first three elements are the primitive !! translations which must be subtracted after the !! transformation to get back to the original unit cell. !! !! PARENTS !! get_npert_rbz,ingeo,initberry,m_ab7_symmetry,m_crystal,m_ddb,setsym !! thmeig !! !! CHILDREN !! symchk,wrtout !! !! SOURCE #if defined HAVE_CONFIG_H #include "config.h" #endif #include "abi_common.h" subroutine symatm(indsym,natom,nsym,symrec,tnons,tolsym,typat,xred) use defs_basis use m_errors use m_profiling_abi !This section has been created automatically by the script Abilint (TD). !Do not modify the following lines by hand. #undef ABI_FUNC #define ABI_FUNC 'symatm' use interfaces_14_hidewrite use interfaces_41_geometry, except_this_one => symatm !End of the abilint section implicit none !Arguments ------------------------------------ !scalars integer,intent(in) :: natom,nsym real(dp), intent(in) :: tolsym !arrays integer,intent(in) :: symrec(3,3,nsym),typat(natom) integer,intent(out) :: indsym(4,nsym,natom) real(dp),intent(in) :: tnons(3,nsym),xred(3,natom) !Local variables------------------------------- !scalars integer :: eatom,errout,iatom,ii,isym,mu real(dp) :: difmax,err character(len=500) :: message !arrays integer :: transl(3) real(dp) :: difmin(3),tratom(3) ! ************************************************************************* err=zero errout=0 do isym=1,nsym do iatom=1,natom do mu=1,3 ! Apply inverse transformation to original coordinates. Note transpose of symrec. tratom(mu) = dble(symrec(1,mu,isym))*(xred(1,iatom)-tnons(1,isym))& & +dble(symrec(2,mu,isym))*(xred(2,iatom)-tnons(2,isym))& & +dble(symrec(3,mu,isym))*(xred(3,iatom)-tnons(3,isym)) end do ! ! Find symmetrically equivalent atom call symchk(difmin,eatom,natom,tratom,transl,typat(iatom),typat,xred) ! ! Put information into array indsym: translations and label indsym(1,isym,iatom)=transl(1) indsym(2,isym,iatom)=transl(2) indsym(3,isym,iatom)=transl(3) indsym(4,isym,iatom)=eatom ! ! Keep track of maximum difference between transformed coordinates and ! nearest "target" coordinate difmax=max(abs(difmin(1)),abs(difmin(2)),abs(difmin(3))) err=max(err,difmax) if (difmax>tolsym) then ! Print warnings if differences exceed tolerance write(message, '(3a,i3,a,i6,a,i3,a,a,3es12.4,3a)' )& & 'Trouble finding symmetrically equivalent atoms',ch10,& & 'Applying inv of symm number',isym,' to atom number',iatom,' of typat',typat(iatom),ch10,& & 'gives tratom=',tratom(1:3),'.',ch10,& & 'This is further away from every atom in crystal than the allowed tolerance.' MSG_WARNING(message) write(message, '(a,3i3,a,a,3i3,a,a,3i3)' ) & & ' The inverse symmetry matrix is',symrec(1,1:3,isym),ch10,& & ' ',symrec(2,1:3,isym),ch10,& & ' ',symrec(3,1:3,isym) call wrtout(std_out,message,'COLL') write(message, '(a,3f13.7)' )' and the nonsymmorphic transl. tnons =',(tnons(mu,isym),mu=1,3) call wrtout(std_out,message,'COLL') write(message, '(a,1p,3e11.3,a,a,i5)' ) & & ' The nearest coordinate differs by',difmin(1:3),ch10,& & ' for indsym(nearest atom)=',indsym(4,isym,iatom) call wrtout(std_out,message,'COLL') ! ! Use errout to reduce volume of error diagnostic output if (errout==0) then write(message,'(6a)') ch10,& & ' This indicates that when symatm attempts to find atoms symmetrically',ch10, & & ' related to a given atom, the nearest candidate is further away than some',ch10,& & ' tolerance. Should check atomic coordinates and symmetry group input data.' call wrtout(std_out,message,'COLL') errout=1 end if end if !difmax>tol end do !iatom end do !isym if (.FALSE.) then do iatom=1,natom write(message, '(a,i0,a)' )' symatm: atom number ',iatom,' is reached starting at atom' call wrtout(std_out,message,'COLL') do ii=1,(nsym-1)/24+1 if(natom<100)then write(message, '(1x,24i3)' ) (indsym(4,isym,iatom),isym=1+(ii-1)*24,min(nsym,ii*24)) else write(message, '(1x,24i6)' ) (indsym(4,isym,iatom),isym=1+(ii-1)*24,min(nsym,ii*24)) end if call wrtout(std_out,message,'COLL') end do end do end if if (err>tolsym) then write(message, '(1x,a,1p,e14.5,a,e12.4)' )'symatm: maximum (delta t)=',err,' is larger than tol=',tolsym call wrtout(std_out,message,'COLL') end if !Stop execution if error is really big if (err>0.01d0) then write(message,'(5a)')& & 'Largest error (above) is so large (0.01) that either input atomic coordinates (xred)',ch10,& & 'are wrong or space group symmetry data is wrong.',ch10,& & 'Action : correct your input file.' MSG_ERROR(message) end if end subroutine symatm !!*** v_sim-3.8.0/lib/plug-ins/abinit/symaxes.F90000066400000000000000000000304311370110300500203510ustar00rootroot00000000000000!{\src2tex{textfont=tt}} !!****f* ABINIT/symaxes !! NAME !! symaxes !! !! FUNCTION !! Determines the type of symmetry operation, for !! the proper symmetries 2,2_1,3,3_1,3_2,4,4_1,4_2,4_3,6,6_1,...6_5 !! !! COPYRIGHT !! Copyright (C) 2000-2016 ABINIT group (RC, XG) !! This file is distributed under the terms of the !! GNU General Public License, see ~abinit/COPYING !! or http://www.gnu.org/copyleft/gpl.txt . !! For the initials of contributors, see ~abinit/doc/developers/contributors.txt . !! !! INPUTS !! center=type of bravais lattice centering !! center=0 no centering !! center=-1 body-centered !! center=-3 face-centered !! center=1 A-face centered !! center=2 B-face centered !! center=3 C-face centered !! iholohedry=type of holohedry !! iholohedry=1 triclinic 1bar !! iholohedry=2 monoclinic 2/m !! iholohedry=3 orthorhombic mmm !! iholohedry=4 tetragonal 4/mmm !! iholohedry=5 trigonal 3bar m (rhombohedral Bravais latt) !! iholohedry=6 hexagonal 6/mmm !! iholohedry=7 cubic m3bar m !! isym=number of the symmetry operation that is currently analyzed !! isymrelconv=symrel matrix for the particular operation, in conv. axes !! ordersym=order of the symmetry operation !! tnons_order=order of the screw translation !! trialt(3)=screw translation associated with the symmetry operation !! in conventional axes (all components in the range ]-1/2,1/2] ) !! !! OUTPUT !! label=a user friendly label for the rotation !! type_axis=type of the symmetry operation !! !! NOTES !! It is assumed that the symmetry operations will be entered in the !! symrel tnonsconv arrays, for the CONVENTIONAL cell. !! For proper symmetries (rotations), the !! associated translation is determined. !! !! There is a subtlety with translations associated with rotations : !! all the rotations with axis !! parallel to the one analysed do not all have the !! same translation characteristics. This is clearly seen !! in the extended Hermann-Mauguin symbols, see the international !! table for crystallography, chapter 4. !! In the treatment that we adopt, one will distinguish !! the cases of primitive Bravais lattices, and centered !! bravais lattices. In the latter case, in the present routine, !! at the exception of the trigonal axis for the !! cubic system, we explicitely generate the correct ratio of different !! translations, so that their type can be explicitely assigned, !! without confusion. By contrast, for primitive lattices, !! the "tnons" that has been transmitted to the present routine !! might be one of the few possible translations vectors, !! nearly at random. We deal with this case by the explicit !! examination of the system classes, and the identification !! of such a possibility. In particular: !! (1) for the trigonal axis in the rhombohedral Bravais lattice, !! or in the cubic system, there is an equal number of 3, 3_1, !! and 3_2 axes parallel to each other, in a cell that !! is primitive (as well as conventional). In this particular case, !! in the present !! routine, all 3, 3_1 and 3_2 axes are assigned to be 3 axes, !! independently of the centering. !! (2) for the 4- or 6- axes, no confusion is possible : !! in the primitive cell, there is only one possible translation, !! while in the centered cells, the correct ratio of translation !! vectors will be generated !! (3) for the binary axes, there is no problem when the cell !! is centered, but there are problems !! (3a) for the tP Bravais lattice, for an axis in a tertiary direction, !! (see the description of the lattice symmetry directions !! table 2.4.1 of the international tables for crystallography), !! where the family of axes is made equally of 2 and 2_1 axis. !! In this case, we attribute the binary axis to the specific class !! of "tertiary 2-axis". We keep track of the 2 or 2_1 !! characteristics of all other binary axes !! (3b) for the tI Bravais lattice, in all the directions, !! there is an equal number of 2 and 2_1 axes. We distinguish !! the primary and secondary family from the tertiary family. !! (3c) for the hP Bravais lattice, each binary axis can present !! no translation or be a screw axis (in the same direction). !! For primary axes, one need the "2" and "2_1" classification, !! while for secondary and tertiary axes, the associated !! translation vector will have not importance. !! However, one will need to distinguish secondary from !! tertiary, and these from primary axes. !! So, this is the most complicated case, for binary axes, !! with the following sets of binary axes : "2", "2_1", !! "secondary 2" and "tertiary 2". !! (3d) for the hR Bravais lattice, each binary axis can present !! no translation or be a screw axis (in the same direction). !! There is no distinction between tertiary axes and other, so that !! we simply assign a binary axis to "2-axis" !! (3e) for the cP lattice, the binary axes along tertiary directions !! can also have different translation vectors, while for the primary !! direction, there is no such ambiguity. So, we will attribute !! tertiary 2 axis to the "tertiary 2-axis" set (there are always 6), !! and attribute 2 and 2_1 primary axes to the corresponding sets. !! !! PARENTS !! symcharac !! !! CHILDREN !! wrtout !! !! SOURCE #if defined HAVE_CONFIG_H #include "config.h" #endif #include "abi_common.h" subroutine symaxes(center,iholohedry,isym,isymrelconv,label,ordersym,tnons_order,trialt,type_axis) use defs_basis use m_profiling_abi use m_errors !This section has been created automatically by the script Abilint (TD). !Do not modify the following lines by hand. #undef ABI_FUNC #define ABI_FUNC 'symaxes' use interfaces_14_hidewrite !End of the abilint section implicit none !Arguments ------------------------------------ !scalars integer,intent(in) :: center,iholohedry,isym,ordersym,tnons_order integer,intent(out) :: type_axis character(len=128),intent(out) :: label !arrays integer,intent(in) :: isymrelconv(3,3) real(dp),intent(in) :: trialt(3) !Local variables------------------------------- !scalars logical,parameter :: verbose=.FALSE. character(len=500) :: message integer :: direction,directiontype real(dp),parameter :: nzero=1.0d-6 !************************************************************************** !DEBUG !write(std_out,*)' symaxes : enter, isym=',isym !write(std_out,*)' symaxes : iholohedry, ',iholohedry !write(std_out,*)' symaxes : center, ',center !stop !ENDDEBUG select case(ordersym) case(2) ! point symmetry 2 ! Must characterize directiontype for cP, tP, tI, and hP Bravais lattices directiontype=1 if( iholohedry==4 .or. iholohedry==7) then ! tP or cP Bravais lattices if(abs(isymrelconv(1,1))+ & & abs(isymrelconv(2,2))+ & & abs(isymrelconv(3,3)) ==1) directiontype=3 else if(iholohedry==6)then ! hP Bravais lattice if(sum(isymrelconv(:,:))/=-1 )directiontype=2 if(sum(isymrelconv(:,:))==0 .or. sum(isymrelconv(:,:))==-3 )& & directiontype=3 ! directiontype=1 corresponds to a primary axis ! directiontype=2 corresponds to a tertiary axis ! directiontype=3 corresponds to a secondary axis end if ! DEBUG ! write(std_out,*)' directiontype=',directiontype ! write(std_out,'(a,3i6)' )' isymrelconv(1:3)=',isymrelconv(:,1) ! write(std_out,'(a,3i6)' )' isymrelconv(4:6)=',isymrelconv(:,2) ! write(std_out,'(a,3i6)' )' isymrelconv(7:9)=',isymrelconv(:,3) ! write(std_out,'(a,i)' )' tnons_order=',tnons_order ! ENDDEBUG ! Now, classify the 2 axes if(directiontype==2)then type_axis=4 ! secondary 2 (only in the hP Bravais latt case) write(label,'(a)') 'a secondary 2-axis ' else if(directiontype==3 .and. iholohedry==4)then type_axis=21 ! tertiary 2 write(label,'(a)') 'a tertiary 2-axis ' else if(directiontype==3 .and. & & center==0 .and. (iholohedry==6.or.iholohedry==7) )then type_axis=21 ! tertiary 2 write(label,'(a)') 'a tertiary 2-axis ' else if(tnons_order==1 .or. (iholohedry==4 .and. center==-1) .or. & & iholohedry==5)then type_axis=9 ! 2 write(label,'(a)') 'a 2-axis ' else type_axis=20 ! 2_1 write(label,'(a)') 'a 2_1-axis ' end if case(3) ! point symmetry 3 if(tnons_order==1)then type_axis=10 ! 3 write(label,'(a)') 'a 3-axis ' else if(iholohedry==5 .or. iholohedry==7)then ! This is a special situation : in the same family of parallel 3-axis, ! one will have an equal number of 3, 3_1 and 3_2 axes, so that ! it is non-sense to try to classify one of them. type_axis=10 ! 3, 3_1 or 3_2, undistinguishable write(label,'(a)') 'a 3, 3_1 or 3_2 axis ' else ! DEBUG ! write(std_out,*)'isymrelconv=',isymrelconv(:,:) ! write(std_out,*)'trialt=',trialt(:) ! ENDDEBUG ! Must recognize 3_1 or 3_2 if(isymrelconv(1,1)==0)then ! 3+ if(abs(trialt(3)-third) symbrav !End of the abilint section implicit none !Arguments ------------------------------------ !scalars integer,intent(in) :: msym,nsym real(dp),intent(in) :: tolsym character(len=5),intent(out) :: ptgroup !arrays integer,intent(in) :: symrel(3,3,msym) integer,optional,intent(out) :: axis(3) integer,intent(out) :: bravais(11) real(dp),intent(in) :: rprimd(3,3) !Local variables------------------------------- !scalars integer :: iaxis,ii,bravais1now,ideform,iholohedry,invariant,isym integer :: jaxis,next_stage,nptsym,problem real(dp) :: norm,scprod character(len=500) :: message !arrays integer :: identity(3,3),axis_trial(3),hexa_axes(3,7),ortho_axes(3,13) integer,allocatable :: ptsymrel(:,:,:),symrelconv(:,:,:) real(dp) :: axes(3,3),axis_cart(3),axis_red(3) real(dp) :: rprimdconv(3,3),rprimdtry(3,3),rprimdnow(3,3) real(dp) :: rprimdconv_invt(3,3) !************************************************************************** identity(:,:)=0 identity(1,1)=1 ; identity(2,2)=1 ; identity(3,3)=1 ortho_axes(:,:)=0 ortho_axes(1,1)=1 ortho_axes(2,2)=1 ortho_axes(3,3)=1 ortho_axes(:,4)=(/0,1,1/) ortho_axes(:,5)=(/1,0,1/) ortho_axes(:,6)=(/1,1,0/) ortho_axes(:,7)=(/0,1,-1/) ortho_axes(:,8)=(/-1,0,1/) ortho_axes(:,9)=(/1,-1,0/) ortho_axes(:,10)=(/1,1,1/) ortho_axes(:,11)=(/-1,1,1/) ortho_axes(:,12)=(/1,-1,1/) ortho_axes(:,13)=(/1,1,-1/) hexa_axes(:,:)=0 hexa_axes(1,1)=1 hexa_axes(2,2)=1 hexa_axes(3,3)=1 hexa_axes(:,4)=(/1,-1,0/) hexa_axes(:,5)=(/2,1,0/) hexa_axes(:,6)=(/1,1,0/) hexa_axes(:,7)=(/1,2,0/) !Determine the point group from the list of symmetry operations. !Also determine the holohedry, up to one undeterminacy : hR versus hP call symptgroup(iholohedry,nsym,ptgroup,symrel) !Loop over trial deformations !This is needed in case the Bravais lattice determination from the lattice vectors !has a higher holohedry than the real one, in which the symmetry !operations for the atoms (or electric field, etc) are taken into account iaxis=0 invariant=0 next_stage=0 rprimdnow(:,:)=rprimd(:,:) rprimdtry(:,:)=rprimd(:,:) ABI_ALLOCATE(symrelconv,(3,3,nsym)) !At most will have to try 65 deformations (13 axes, five stages) do ideform=1,65 ABI_ALLOCATE(ptsymrel,(3,3,msym)) call symlatt(bravais,msym,nptsym,ptsymrel,rprimdtry,tolsym) ABI_DEALLOCATE(ptsymrel) ! Examine the agreement with bravais(1) ! Warning : might change Bravais lattice hR to hP, if hexagonal axes problem=0 select case (bravais(1)) case(7) if(iholohedry<6)problem=1 if(iholohedry==6)problem=2 case(6) if(iholohedry<4)problem=1 if(iholohedry==7 .or. iholohedry==4)problem=2 ! Here, change hR into hP if(iholohedry==5)iholohedry=6 case(5) if(iholohedry<4)problem=1 if(iholohedry==7 .or. iholohedry==6 .or. iholohedry==4)problem=2 case(4) if(iholohedry<4)problem=1 if(iholohedry>4)problem=2 case(3) if(iholohedry<3)problem=1 if(iholohedry>3)problem=2 case(2) if(iholohedry<2)problem=1 if(iholohedry>2)problem=2 case(1) if(iholohedry>1)problem=2 end select ! This is the usual situation, in which the lattice belong to the same holohedry ! as the lattice+atoms (+electric field + ...) if(problem==0)exit if(problem==2)then if(iaxis==0)then write(message, '(3a,i3,3a,i3,7a)' )& & 'The Bravais lattice determined only from the primitive',ch10,& & 'vectors (rprim or angdeg), bravais(1)=',bravais(1),', is not compatible',ch10,& & 'with the real one, iholohedry=',iholohedry,', obtained by taking into',ch10,& & 'account the symmetry operations. This might be due to an insufficient',ch10,& & 'number of digits in the specification of rprim (at least 10),',ch10,& & 'or to an erroneous rprim or angdeg. If this is not the case, then ...' MSG_BUG(message) end if if(iaxis==1)then write(message, '(3a,3i3,2a,i3,2a,i3)' )& & 'Could not succeed to determine the bravais lattice',ch10,& & 'problem,iaxis,invariant=',problem,iaxis,invariant,ch10,& & 'bravais(1)=',bravais(1),ch10,& & 'iholohedry=',iholohedry MSG_BUG(message) end if end if if(problem==1)then ! One is left with the problem=1 case, basically iholohedry is lower than bravais(1) if(iaxis==0)then write(message, '(a,a,a,i3,a,a,a,i3,a,a,a)' )& & 'The Bravais lattice determined only from the primitive',ch10,& & 'vectors, bravais(1)=',bravais(1),', is more symmetric',ch10,& & 'than the real one, iholohedry=',iholohedry,', obtained by taking into',ch10,& & 'account the atomic positions. Start deforming the primitive vector set.' MSG_COMMENT(message) next_stage=1 else if(iaxis/=0)then if(bravais(1) symcharac !End of the abilint section implicit none !Arguments ------------------------------------ !scalars integer, intent(in) :: determinant, center, iholohedry, isym integer, intent(out) :: type_axis character(len = 128), intent(out) :: label !arrays integer,intent(in) :: symrel(3,3) real(dp),intent(in) :: tnons(3) !Local variables------------------------------- !scalars logical,parameter :: verbose=.FALSE. integer :: tnons_order, identified, ii, order, iorder character(len=500) :: message !arrays integer :: identity(3,3),matrix(3,3),trial(3,3) real(dp) :: reduced(3),trialt(3) !************************************************************************** identity(:,:)=0 identity(1,1)=1 ; identity(2,2)=1 ; identity(3,3)=1 trial(:,:)=identity(:,:) matrix(:,:)=symrel(:,:) order=0 do iorder=1,6 trial=matmul(matrix,trial) if(sum((trial-identity)**2)==0)then order=iorder exit end if if(sum((trial+identity)**2)==0)then order=iorder exit end if end do if(order==0)then type_axis = -2 return end if !Determination of the characteristics of proper symmetries (rotations) if(determinant==1)then ! Determine the translation vector associated to the rotations ! and its order : apply the symmetry operation ! then analyse the resulting vector. identified=0 trialt(:)=zero do ii=1,order trialt(:)=matmul(symrel(:,:),trialt(:))+tnons(:) end do ! Gives the associated translation, with components in the ! interval [-0.5,0.5] . reduced(:)=trialt(:)-nint(trialt(:)-tol6) if(sum(abs(reduced(:))) tolsym**2 ) cycle end if if (use_inversion==0) then det=ptsymrel(1,1,isym)*ptsymrel(2,2,isym)*ptsymrel(3,3,isym)+& & ptsymrel(2,1,isym)*ptsymrel(3,2,isym)*ptsymrel(1,3,isym)+& & ptsymrel(1,2,isym)*ptsymrel(2,3,isym)*ptsymrel(3,1,isym) - & & (ptsymrel(3,1,isym)*ptsymrel(2,2,isym)*ptsymrel(1,3,isym)+& & ptsymrel(2,1,isym)*ptsymrel(1,2,isym)*ptsymrel(3,3,isym)+& & ptsymrel(3,2,isym)*ptsymrel(2,3,isym)*ptsymrel(1,1,isym)) if(det==-1) cycle end if ! jellium slab case: if (jellslab/=0) then ! check whether symmetry operation produce a rotation only in the xy plane if( ptsymrel(1,3,isym)/=0 .or. ptsymrel(2,3,isym)/=0 .or. & & ptsymrel(3,1,isym)/=0 .or. ptsymrel(3,2,isym)/=0 ) cycle ! check whether symmetry operation does not change the z if( ptsymrel(3,3,isym)/=1 ) cycle end if ! Select a tentative set of associated translations ! First compute the symmetric of the first atom in the smallest class, ! using the point symmetry iatom0=class(1,iclass0) sxred0(:)=ptsymrel(:,1,isym)*xred(1,iatom0)+ & & ptsymrel(:,2,isym)*xred(2,iatom0)+ & & ptsymrel(:,3,isym)*xred(3,iatom0) ! From the set of possible images, deduce tentative translations, ! and magnetic factor then test whether it send each atom on a symmetric one ntrial=0 do ii=1,natom0 iatom1=class(ii,iclass0) ! The tentative translation is found trialnons(:)=xred(:,iatom1)-sxred0(:) trialafm=1 if(abs(spinat(3,iatom1)-spinat(3,iatom0))>tolsym)trialafm=-1 if(sum(abs(spinat(:,iatom1)*trialafm-spinat(:,iatom0)))>tolsym)then write(message,'(3a,3i5)')& & 'Problem with matching the spin part within a class.',ch10,& & 'isym,iatom0,iatom1=',isym,iatom0,iatom1 MSG_ERROR_CLASS(message, "TolSymError") end if ! jellium slab case: check whether symmetry operation has no translational ! component along z if( jellslab/=0 .and. abs(trialnons(3)) > tolsym ) cycle trialok=1 ! DEBUG ! write(std_out,*)' isym,trialnons(:),trialafm =',isym,trialnons(:),trialafm ! ENDDEBUG ! Loop over all classes, then all atoms in the class, ! to find whether they have a symmetric do iclass=1,nclass do jj=1,natomcl(iclass) iatom2=class(jj,iclass) ! Generate the tentative symmetric position of iatom2 symxred2(:)=ptsymrel(:,1,isym)*xred(1,iatom2)+ & & ptsymrel(:,2,isym)*xred(2,iatom2)+ & & ptsymrel(:,3,isym)*xred(3,iatom2)+ trialnons(:) ! Generate the tentative symmetric spinat of iatom2 if (noncoll==0) then symspinat2(:)=trialafm*spinat(:,iatom2) else symspinat2(:)=trialafm*(ptsymrel(:,1,isym)*spinatred(1,iatom2)+ & & ptsymrel(:,2,isym)*spinatred(2,iatom2)+ & & ptsymrel(:,3,isym)*spinatred(3,iatom2)) end if if(present(nucdipmom)) then ! Generate the tentative symmetric nuclear dipole moment of iatom2 symnucdipmom2(:)=(ptsymrel(:,1,isym)*nucdipmom(1,iatom2)+ & & ptsymrel(:,2,isym)*nucdipmom(2,iatom2)+ & & ptsymrel(:,3,isym)*nucdipmom(3,iatom2)) end if ! DEBUG ! write(std_out,'(a,3f12.4,a,3f12.4)') ' Send atom at xred=',xred(:,iatom2),' to ',symxred2(:) ! ENDDEBUG ! Check whether there exists an atom of the same class at the ! same location, with the correct spinat and nuclear dipole moment do kk=1,natomcl(iclass) found3=1 iatom3=class(kk,iclass) ! Check the location diff(:)=xred(:,iatom3)-symxred2(:) diff(:)=diff(:)-nint(diff(:)) if( (diff(1)**2+diff(2)**2+diff(3)**2) > tolsym**2 )found3=0 ! Check the spinat if (noncoll==0) then diff(:)=spinat(:,iatom3)-symspinat2(:) else diff(:)=spinatred(:,iatom3)-symspinat2(:) end if if( (diff(1)**2+diff(2)**2+diff(3)**2) > tolsym**2 )found3=0 if(present(nucdipmom)) then ! Check the nuclear dipole moment diff(:) = nucdipmom(:,iatom3) - symnucdipmom2(:) if(any(diff>tolsym))found3=0 end if if(found3==1)exit ! End loop over iatom3 end do if(found3==0)then trialok=0 exit end if ! End loop over iatom2 end do if(trialok==0)exit ! End loop over all classes end do if(trialok==1)then nsym=nsym+1 if(nsym>msym)then write(message,'(3a,i0,4a)')& & 'The number of symmetries (including non-symmorphic translations)',ch10,& & 'is larger than maxnsym=',msym,ch10,& & 'Action: increase maxnsym in the input, or take a cell that is primitive, ',ch10,& & 'or at least smaller than the present one.' MSG_ERROR(message) end if ntrial=ntrial+1 symrel(:,:,nsym)=ptsymrel(:,:,isym) symafm(nsym)=trialafm tnons(:,nsym)=trialnons(:)-nint(trialnons(:)-tolsym) end if ! End the loop on tentative translations end do ! End big loop over each symmetry operation of the Bravais lattice end do ABI_DEALLOCATE(class) ABI_DEALLOCATE(natomcl) ABI_DEALLOCATE(spinatcl) ABI_DEALLOCATE(typecl) if (noncoll==1) then ABI_DEALLOCATE(spinatred) end if !DEBUG !write(std_out,*)' symfind : exit, nsym=',nsym !write(std_out,*)' symrel matrices, symafm and tnons are :' !do isym=1,nsym !write(std_out,'(i4,4x,3i4,2x,3i4,2x,3i4,4x,i4,4x,3f8.4)' )isym,symrel(:,:,isym),symafm(isym),tnons(:,isym) !end do !stop !ENDDEBUG end subroutine symfind !!*** v_sim-3.8.0/lib/plug-ins/abinit/symlatt.F90000066400000000000000000001233421370110300500203610ustar00rootroot00000000000000!{\src2tex{textfont=tt}} !!****f* ABINIT/symlatt !! NAME !! symlatt !! !! FUNCTION !! From the unit cell vectors (rprimd) and the corresponding metric tensor, !! find the Bravais lattice and its symmetry operations (ptsymrel). !! 1) Find the shortest possible primitive vectors for the lattice !! 2) Determines the holohedral group of the lattice, and the !! axes to be used for the conventional cell !! (this is a delicate part, in which the centering of the !! reduced cell must be taken into account) !! The idea is to determine the basis vectors of the conventional !! cell from the reduced cell basis vectors. !! 3) Generate the symmetry operations of the holohedral group !! !! COPYRIGHT !! Copyright (C) 2000-2016 ABINIT group (XG) !! This file is distributed under the terms of the !! GNU General Public License, see ~abinit/COPYING !! or http://www.gnu.org/copyleft/gpl.txt . !! For the initials of contributors, see ~abinit/doc/developers/contributors.txt . !! !! INPUTS !! msym=default maximal number of symmetries !! rprimd(3,3)=dimensional primitive translations for real space (bohr) !! tolsym=tolerance for the symmetries !! !! OUTPUT !! bravais(11): bravais(1)=iholohedry !! bravais(2)=center !! bravais(3:11)=coordinates of rprim in the axes !! of the conventional bravais lattice (*2 if center/=0) !! nptsym=number of point symmetries of the Bravais lattice !! ptsymrel(3,3,1:msym)= nptsym point-symmetry operations !! of the Bravais lattice in real space in terms !! of primitive translations. !! !! NOTES !! WARNING: bravais(1) might be given a negative value in another !! routine, if the cell is non-primitive. !! The holohedral groups are numbered as follows !! (see international tables for crystallography (1983), p. 13) !! iholohedry=1 triclinic 1bar !! iholohedry=2 monoclinic 2/m !! iholohedry=3 orthorhombic mmm !! iholohedry=4 tetragonal 4/mmm !! iholohedry=5 trigonal 3bar m !! iholohedry=6 hexagonal 6/mmm !! iholohedry=7 cubic m3bar m !! Centering !! center=0 no centering !! center=-1 body-centered !! center=-3 face-centered !! center=1 A-face centered !! center=2 B-face centered !! center=3 C-face centered !! !! PARENTS !! ingeo,inqpt,m_ab7_symmetry,m_use_ga,symanal,symbrav,thmeig !! !! CHILDREN !! holocell,matr3inv,smallprim,symrelrot,wrtout !! !! SOURCE #if defined HAVE_CONFIG_H #include "config.h" #endif #include "abi_common.h" subroutine symlatt(bravais,msym,nptsym,ptsymrel,rprimd,tolsym) use defs_basis use m_errors use m_profiling_abi !This section has been created automatically by the script Abilint (TD). !Do not modify the following lines by hand. #undef ABI_FUNC #define ABI_FUNC 'symlatt' use interfaces_14_hidewrite use interfaces_32_util use interfaces_41_geometry, except_this_one => symlatt !End of the abilint section implicit none !Arguments ------------------------------------ !scalars integer,intent(in) :: msym integer,intent(out) :: nptsym real(dp),intent(in) :: tolsym !arrays integer,intent(out) :: bravais(11),ptsymrel(3,3,msym) real(dp),intent(in) :: rprimd(3,3) !Local variables------------------------------- !scalars integer,parameter :: mgen=4 integer :: center,fact,found,foundc,ia,ib,icase,igen,iholohedry,ii,index,isym integer :: itrial,jj,jsym,ngen=0,orthogonal,sign12,sign13,sign23,sumsign real(dp) :: determinant,norm2a,norm2b,norm2c,norm2trial,reduceda,reducedb,sca real(dp) :: scalarprod,scb,trace,val character(len=500) :: message !arrays integer,parameter :: list_holo(7)=(/7,6,4,3,5,2,1/) integer :: ang90(3),equal(3),gen(3,3,mgen),gen2xy(3,3),gen2y(3,3),gen2z(3,3) integer :: gen3(3,3),gen6(3,3),icoord(3,3),identity(3,3),nvecta(3),nvectb(3) integer :: order(mgen) real(dp) :: axes(3,3),axesinvt(3,3),cell_base(3,3),coord(3,3),metmin(3,3) real(dp) :: minim(3,3),scprods(3,3),vecta(3),vectb(3),vectc(3),vin1(3),vin2(3),vext(3) !************************************************************************** identity(:,:)=0 ; identity(1,1)=1 ; identity(2,2)=1 ; identity(3,3)=1 nvecta(1)=2 ; nvectb(1)=3 nvecta(2)=1 ; nvectb(2)=3 nvecta(3)=1 ; nvectb(3)=2 !-------------------------------------------------------------------------- !Reduce the input vectors to a set of minimal vectors call smallprim(metmin,minim,rprimd) !DEBUG !write(std_out,*)' symlatt : minim(:,1)=',minim(:,1) !write(std_out,*)' symlatt : minim(:,2)=',minim(:,2) !write(std_out,*)' symlatt : minim(:,3)=',minim(:,3) !ENDDEBUG !-------------------------------------------------------------------------- !Examine the angles and vector lengths ang90(:)=0 if(metmin(1,2)**2 symptgroup !End of the abilint section implicit none !Arguments ------------------------------------ !scalars integer,intent(in) :: nsym integer,intent(out) :: iholohedry character(len=5),intent(out) :: ptgroup !arrays integer,intent(in) :: symrel(3,3,nsym) !Local variables------------------------------- !scalars integer :: inversion,iorder,isym character(len=500) :: message !arrays integer :: identity(3,3),matrix(3,3),n_axes(-6:6),trial(3,3) integer,allocatable :: determinant(:),order(:),root_invers(:) character(len=2),allocatable :: ptsym(:) !************************************************************************** !DEBUG !write(std_out,*)' symptgroup : enter' !do isym=1,nsym !write(std_out,'(i3,2x,9i3)' )isym,symrel(:,:,isym) !end do !ENDDEBUG identity(:,:)=0 identity(1,1)=1 ; identity(2,2)=1 ; identity(3,3)=1 n_axes(:)=0 ABI_ALLOCATE(determinant,(nsym)) ABI_ALLOCATE(order,(nsym)) ABI_ALLOCATE(ptsym,(nsym)) ABI_ALLOCATE(root_invers,(nsym)) !Get the determinant call symdet(determinant,nsym,symrel) !Get the order of each the symmetry operation, as well as the maximal order !Also, examine whether each symmetry operation is the inversion, or a root !of the inversion (like -3) !Finally, decide which kind of point symmetry operation it is do isym=1,nsym trial(:,:)=identity(:,:) matrix(:,:)=symrel(:,:,isym) order(isym)=0 root_invers(isym)=0 do iorder=1,6 trial=matmul(matrix,trial) if(sum((trial-identity)**2)==0)then order(isym)=iorder exit end if if(sum((trial+identity)**2)==0)then root_invers(isym)=iorder if(iorder==1)inversion=isym end if end do if(order(isym)==0)then write(message, '(a,i0,a)' )' The symmetry operation number',isym,' is not a root of unity' MSG_BUG(message) end if ! determinant, order and root_invers are enough to determine the ! kind of symmetry operation ptsym(isym)='no' select case(order(isym)) case(1) ptsym(isym)=' 1' ; n_axes(1)=n_axes(1)+1 case(2) if(determinant(isym)== 1)then ptsym(isym)=' 2' ; n_axes(2)=n_axes(2)+1 else if(determinant(isym)==-1 .and. root_invers(isym)==1)then ptsym(isym)='-1' ; n_axes(-1)=n_axes(-1)+1 else if(determinant(isym)==-1 .and. root_invers(isym)==0)then ptsym(isym)='-2' ; n_axes(-2)=n_axes(-2)+1 end if case(3) ptsym(isym)=' 3' ; n_axes(3)=n_axes(3)+1 case(4) if(determinant(isym)== 1)then ptsym(isym)=' 4' ; n_axes(4)=n_axes(4)+1 else if(determinant(isym)==-1)then ptsym(isym)='-4' ; n_axes(-4)=n_axes(-4)+1 end if case(6) if(determinant(isym)== 1)then ptsym(isym)=' 6' ; n_axes(6)=n_axes(6)+1 else if(determinant(isym)==-1 .and. root_invers(isym)==3)then ptsym(isym)='-3' ; n_axes(-3)=n_axes(-3)+1 else if(determinant(isym)==-1 .and. root_invers(isym)==0)then ptsym(isym)='-6' ; n_axes(-6)=n_axes(-6)+1 end if end select if(ptsym(isym)=='no')then write(message,'(a,i4,a,a,a,i4,a,a,i4,a,a,i4)' )& & 'The symmetry operation number',isym,' could not be identified',ch10,& & 'order(isym) =',order(isym),ch10,& & 'determinant(isym)=',determinant(isym),ch10,& & 'root_invers(isym)=',root_invers(isym) MSG_BUG(message) end if end do iholohedry=0 if (sum((n_axes-(/0,0,0,0,0,0, 0 ,1,0,0,0,0,0/))**2)==0)then ptgroup=' 1' ; iholohedry=1 else if(sum((n_axes-(/0,0,0,0,0,1, 0 ,1,0,0,0,0,0/))**2)==0)then ptgroup=' -1' ; iholohedry=1 else if(sum((n_axes-(/0,0,0,0,0,0, 0 ,1,1,0,0,0,0/))**2)==0)then ptgroup=' 2' ; iholohedry=2 else if(sum((n_axes-(/0,0,0,0,1,0, 0 ,1,0,0,0,0,0/))**2)==0)then ptgroup=' -2' ; iholohedry=2 else if(sum((n_axes-(/0,0,0,0,1,1, 0 ,1,1,0,0,0,0/))**2)==0)then ptgroup=' 2/m' ; iholohedry=2 else if(sum((n_axes-(/0,0,0,0,0,0, 0 ,1,3,0,0,0,0/))**2)==0)then ptgroup=' 222' ; iholohedry=3 else if(sum((n_axes-(/0,0,0,0,2,0, 0 ,1,1,0,0,0,0/))**2)==0)then ptgroup=' mm2' ; iholohedry=3 else if(sum((n_axes-(/0,0,0,0,3,1, 0 ,1,3,0,0,0,0/))**2)==0)then ptgroup=' mmm' ; iholohedry=3 else if(sum((n_axes-(/0,0,0,0,0,0, 0 ,1,1,0,2,0,0/))**2)==0)then ptgroup=' 4' ; iholohedry=4 else if(sum((n_axes-(/0,0,2,0,0,0, 0 ,1,1,0,0,0,0/))**2)==0)then ptgroup=' -4' ; iholohedry=4 else if(sum((n_axes-(/0,0,2,0,1,1, 0 ,1,1,0,2,0,0/))**2)==0)then ptgroup=' 4/m' ; iholohedry=4 else if(sum((n_axes-(/0,0,0,0,0,0, 0 ,1,5,0,2,0,0/))**2)==0)then ptgroup=' 422' ; iholohedry=4 else if(sum((n_axes-(/0,0,0,0,4,0, 0 ,1,1,0,2,0,0/))**2)==0)then ptgroup=' 4mm' ; iholohedry=4 else if(sum((n_axes-(/0,0,2,0,2,0, 0 ,1,3,0,0,0,0/))**2)==0)then ptgroup=' -42m' ; iholohedry=4 else if(sum((n_axes-(/0,0,2,0,5,1, 0 ,1,5,0,2,0,0/))**2)==0)then ptgroup='4/mmm' ; iholohedry=4 else if(sum((n_axes-(/0,0,0,0,0,0, 0 ,1,0,2,0,0,0/))**2)==0)then ptgroup=' 3' ; iholohedry=5 else if(sum((n_axes-(/0,0,0,2,0,1, 0 ,1,0,2,0,0,0/))**2)==0)then ptgroup=' -3' ; iholohedry=5 else if(sum((n_axes-(/0,0,0,0,0,0, 0 ,1,3,2,0,0,0/))**2)==0)then ptgroup=' 32' ; iholohedry=5 else if(sum((n_axes-(/0,0,0,0,3,0, 0 ,1,0,2,0,0,0/))**2)==0)then ptgroup=' 3m' ; iholohedry=5 else if(sum((n_axes-(/0,0,0,2,3,1, 0 ,1,3,2,0,0,0/))**2)==0)then ptgroup=' -3m' ; iholohedry=5 else if(sum((n_axes-(/0,0,0,0,0,0, 0 ,1,1,2,0,0,2/))**2)==0)then ptgroup=' 6' ; iholohedry=6 else if(sum((n_axes-(/2,0,0,0,1,0, 0 ,1,0,2,0,0,0/))**2)==0)then ptgroup=' -6' ; iholohedry=6 else if(sum((n_axes-(/2,0,0,2,1,1, 0 ,1,1,2,0,0,2/))**2)==0)then ptgroup=' 6/m' ; iholohedry=6 else if(sum((n_axes-(/0,0,0,0,0,0, 0 ,1,7,2,0,0,2/))**2)==0)then ptgroup=' 622' ; iholohedry=6 else if(sum((n_axes-(/0,0,0,0,6,0, 0 ,1,1,2,0,0,2/))**2)==0)then ptgroup=' 6mm' ; iholohedry=6 else if(sum((n_axes-(/2,0,0,0,4,0, 0 ,1,3,2,0,0,0/))**2)==0)then ptgroup=' -62m' ; iholohedry=6 else if(sum((n_axes-(/2,0,0,2,7,1, 0 ,1,7,2,0,0,2/))**2)==0)then ptgroup='6/mmm' ; iholohedry=6 else if(sum((n_axes-(/0,0,0,0,0,0, 0 ,1,3,8,0,0,0/))**2)==0)then ptgroup=' 23' ; iholohedry=7 else if(sum((n_axes-(/0,0,0,8,3,1, 0 ,1,3,8,0,0,0/))**2)==0)then ptgroup=' m-3' ; iholohedry=7 else if(sum((n_axes-(/0,0,0,0,0,0, 0 ,1,9,8,6,0,0/))**2)==0)then ptgroup=' 432' ; iholohedry=7 else if(sum((n_axes-(/0,0,6,0,6,0, 0 ,1,3,8,0,0,0/))**2)==0)then ptgroup=' -43m' ; iholohedry=7 else if(sum((n_axes-(/0,0,6,8,9,1, 0 ,1,9,8,6,0,0/))**2)==0)then ptgroup=' m-3m' ; iholohedry=7 end if if(iholohedry==0)then MSG_ERROR_CLASS('Could not find the point group', "TolSymError") end if !DEBUG !do isym=1,nsym !write(std_out,'(a,3i5)' )& !& ' symptgroup : isym,determinant,order=',isym,determinant(isym),order(isym) !end do !write(std_out,'(a,13i3)' )' symptgroup : n_axes(-6:6)=',n_axes(-6:6) !write(std_out,*)' iholohedry, ptgroup=',iholohedry,',',ptgroup !ENDDEBUG ABI_DEALLOCATE(determinant) ABI_DEALLOCATE(order) ABI_DEALLOCATE(ptsym) ABI_DEALLOCATE(root_invers) end subroutine symptgroup !!*** v_sim-3.8.0/lib/plug-ins/abinit/symrelrot.F90000066400000000000000000000064741370110300500207320ustar00rootroot00000000000000!{\src2tex{textfont=tt}} !!****f* ABINIT/symrelrot !! NAME !! symrelrot !! !! FUNCTION !! Transform the symmetry matrices symrel expressed in the coordinate system rprimd, !! to symmetry matrices symrel expressed in the new coordinate system rprimd_new !! !! COPYRIGHT !! Copyright (C) 2000-2016 ABINIT group (XG) !! This file is distributed under the terms of the !! GNU General Public License, see ~abinit/COPYING !! or http://www.gnu.org/copyleft/gpl.txt . !! For the initials of contributors, see ~abinit/doc/developers/contributors.txt . !! !! INPUTS !! nsym=number of symmetries !! rprimd(3,3)=dimensional primitive translations for real space (bohr) !! rprimd_new(3,3)=new dimensional primitive translations for real space (bohr) !! !! OUTPUT !! (see side effects) !! !! SIDE EFFECTS !! Input/Output !! symrel(3,3,nsym)=symmetry operations in real space in terms !! of primitive translations rprimd at input and rprimd_new at output !! !! PARENTS !! ingeo,m_esymm,symbrav,symlatt,symspgr !! !! CHILDREN !! matr3inv !! !! SOURCE #if defined HAVE_CONFIG_H #include "config.h" #endif #include "abi_common.h" subroutine symrelrot(nsym,rprimd,rprimd_new,symrel,tolsym) use defs_basis use m_errors use m_profiling_abi !This section has been created automatically by the script Abilint (TD). !Do not modify the following lines by hand. #undef ABI_FUNC #define ABI_FUNC 'symrelrot' use interfaces_32_util !End of the abilint section implicit none !Arguments ------------------------------------ !scalars integer,intent(in) :: nsym real(dp),intent(in) :: tolsym !arrays integer,intent(inout) :: symrel(3,3,nsym) real(dp),intent(in) :: rprimd(3,3),rprimd_new(3,3) !Local variables------------------------------- !scalars integer :: ii,isym,jj real(dp) :: val character(len=500) :: message !arrays real(dp) :: coord(3,3),coordinvt(3,3),matr1(3,3),matr2(3,3),rprimd_invt(3,3) !************************************************************************** !Compute the coordinates of rprimd_new in the system defined by rprimd(:,:) call matr3inv(rprimd,rprimd_invt) do ii=1,3 coord(:,ii)=rprimd_new(1,ii)*rprimd_invt(1,:)+ & & rprimd_new(2,ii)*rprimd_invt(2,:)+ & & rprimd_new(3,ii)*rprimd_invt(3,:) end do !Transform symmetry matrices in the system defined by rprimd_new call matr3inv(coord,coordinvt) do isym=1,nsym do ii=1,3 matr1(:,ii)=symrel(:,1,isym)*coord(1,ii)+& & symrel(:,2,isym)*coord(2,ii)+& & symrel(:,3,isym)*coord(3,ii) end do do ii=1,3 matr2(:,ii)=coordinvt(1,:)*matr1(1,ii)+& & coordinvt(2,:)*matr1(2,ii)+& & coordinvt(3,:)*matr1(3,ii) end do ! Check that the new symmetry matrices are made of integers, and store them do ii=1,3 do jj=1,3 val=matr2(ii,jj) ! Need to allow for twice tolsym, in case of centered Bravais lattices (but do it for all lattices ...) if(abs(val-nint(val))>two*tolsym)then write(message,'(2a,a,i3,a,a,3es14.6,a,a,3es14.6,a,a,3es14.6)')& & 'One of the components of symrel is non-integer,',ch10,& & ' for isym=',isym,ch10,& & ' symrel=',matr2(:,1),ch10,& & ' ',matr2(:,2),ch10,& & ' ',matr2(:,3) MSG_ERROR_CLASS(message, "TolSymError") end if symrel(ii,jj,isym)=nint(val) end do end do ! End loop isym end do end subroutine symrelrot !!*** v_sim-3.8.0/lib/plug-ins/abinit/symspgr.F90000066400000000000000000000370461370110300500203750ustar00rootroot00000000000000!{\src2tex{textfont=tt}} !!****f* ABINIT/symspgr !! NAME !! symspgr !! !! FUNCTION !! Using the type of each symmetry operation (found in symplanes.f and symaxes.f): !! proper symmetries 1,2,2_1,3,3_1,3_2,4,4_1,4_2,4_3,6,6_1,...6_5 !! improper symmetries -1,m,a,b,c,d,n,g,-3,-4,-6 , !! build an array with the number of such operations. then, call symlist.f to identify the space group. !! The identification is not unambiguous still ... !! !! COPYRIGHT !! Copyright (C) 2000-2016 ABINIT group (RC, XG) !! This file is distributed under the terms of the !! GNU General Public License, see ~abinit/COPYING !! or http://www.gnu.org/copyleft/gpl.txt . !! For the initials of contributors, see ~abinit/doc/developers/contributors.txt . !! !! INPUTS !! bravais(11): bravais(1)=iholohedry !! bravais(2)=center !! bravais(3:11)=coordinates of rprimd in the axes !! of the conventional bravais lattice (*2 if center/=0) !! nsym=actual number of symmetries !! symrel(3,3,nsym)= nsym symmetry operations in real space in terms !! of primitive translations !! tnons(3,nsym)=nonsymmorphic translations for each symmetry (would !! be 0 0 0 each for a symmorphic space group) !! !! OUTPUT !! spgroup=symmetry space group number !! !! NOTES !! It is assumed that the symmetry operations will be entered in the !! symrel tnons arrays, for the PRIMITIVE cell. The matrix of transformation !! from the primitive cell to the conventional cell is described !! in the array "bravais" (see symlatt.F90). !! The present routine first make the transformation from the !! primitive coordinates to the conventional ones, then eventually !! generate additional symmetries, taking into account the !! centering translations. !! Then, the order and determinant of each symmetry operation !! is determined. !! !! For proper symmetries (rotations), the !! associated translation is also determined. !! However, left or right handed screw rotations are !! not (presently) distinguished, and will be attributed equally !! to left or right. !! !! For the detailed description of the labelling of the axes, !! see symaxes.f and symplanes.f !! !! PARENTS !! symanal !! !! CHILDREN !! spgdata,symcharac,symdet,symlist_bcc,symlist_fcc,symlist_others !! symlist_prim,symrelrot,wrtout,xred2xcart !! !! SOURCE #if defined HAVE_CONFIG_H #include "config.h" #endif #include "abi_common.h" subroutine symspgr(bravais,nsym,spgroup,symrel,tnons,tolsym) use defs_basis use m_errors use m_profiling_abi use m_numeric_tools, only : OPERATOR(.x.) !This section has been created automatically by the script Abilint (TD). !Do not modify the following lines by hand. #undef ABI_FUNC #define ABI_FUNC 'symspgr' use interfaces_14_hidewrite use interfaces_41_geometry, except_this_one => symspgr !End of the abilint section implicit none !Arguments ------------------------------------ !scalars integer,intent(in) :: nsym integer,intent(out) :: spgroup real(dp),intent(in) :: tolsym !arrays integer,intent(in) :: bravais(11),symrel(3,3,nsym) real(dp),intent(inout) :: tnons(3,nsym) !Local variables------------------------------- !scalars ! logical,parameter :: verbose=.FALSE. integer :: additional_info,brvltt,center,direction=0,found,iholohedry,ii integer :: ishift,isym,jj,nshift,nsymconv,spgaxor,spgorig,sporder character(len=1) :: brvsb character(len=15) :: intsb,ptintsb,ptschsb,schsb character(len=35) :: intsbl character(len=500) :: message character(len = 128) :: label !arrays integer :: n_axes(31),n_axest(31),prime(5),test_direction(3),symrel_uni(3,3) integer :: uniaxis(3),uniaxis_try(3) integer,allocatable :: determinant(:),symrelconv(:,:,:),t_axes(:) real(dp) :: axes(3,3),rprimdconv(3,3),trialt(3),vect(3,3) real(dp),allocatable :: shift(:,:),tnonsconv(:,:) !************************************************************************** DBG_ENTER("COLL") !Initialize brvltt, from bravais(2) and bravais(1) center=bravais(2) iholohedry=bravais(1) brvltt=1 if(center==-1)brvltt=2 ! Inner centering if(center==-3)brvltt=3 ! Face centering if(center==1)brvltt=5 ! A-Face centering if(center==2)brvltt=6 ! B-Face centering if(center==3)brvltt=4 ! C-Face centering if(iholohedry==5)brvltt=7 ! Rhombohedral !Produce the symmetry operations, in the axis of the conventional cell nsymconv=nsym if(center/=0)nsymconv=2*nsymconv if(center==-3)nsymconv=4*nsym ABI_ALLOCATE(symrelconv,(3,3,nsymconv)) ABI_ALLOCATE(tnonsconv,(3,nsymconv)) !Produce symrel and tnons in conventional axes, !name them symrelconv and tnonsconv rprimdconv(:,1)=bravais(3:5) rprimdconv(:,2)=bravais(6:8) rprimdconv(:,3)=bravais(9:11) if(center/=0)rprimdconv(:,:)=rprimdconv(:,:)*half axes(:,:)=zero axes(1,1)=one ; axes(2,2)=one ; axes(3,3)=one symrelconv(:,:,1:nsym)=symrel(:,:,1:nsym) !Note that the number of symmetry operations is still nsym call symrelrot(nsym,rprimdconv,axes,symrelconv,tolsym) call xred2xcart(nsym,rprimdconv,tnonsconv,tnons) !Gives the associated translation, with components in the !interval ]-0.5,0.5] . tnonsconv(:,1:nsym)=tnonsconv(:,1:nsym)-nint(tnonsconv(:,1:nsym)-tol6) !If the Bravais lattice is centered, duplicate or quadruplicate !the number of symmetry operations, using the Bravais !lattice shifts nshift=1 if(center/=0)nshift=2 if(center==-3)nshift=4 ABI_ALLOCATE(shift,(3,nshift)) shift(:,1)=zero if(center/=0 .and. center/=-3)then shift(:,2)=half if(center==1)shift(1,2)=zero if(center==2)shift(2,2)=zero if(center==3)shift(3,2)=zero else if(center==-3)then shift(:,2)=half ; shift(1,2)=zero shift(:,3)=half ; shift(2,3)=zero shift(:,4)=half ; shift(3,4)=zero end if ! center/=0 or -3 if(nshift/=1)then do ishift=2,nshift symrelconv(:,:,(ishift-1)*nsym+1:ishift*nsym)=symrelconv(:,:,1:nsym) do isym=1,nsym tnonsconv(:,(ishift-1)*nsym+isym)=tnonsconv(:,isym)+shift(:,ishift) end do end do ! ishift end if ! nshift/=1 !At this stage, all the symmetry operations are available, !expressed in the conventional axis, and also include !the Bravais lattive translations, and associated operations... n_axes(:)=0 ABI_ALLOCATE(determinant,(nsymconv)) !Get the determinant call symdet(determinant,nsymconv,symrelconv) !Get the order of each the symmetry operation, as well as the maximal order !Also, examine whether each symmetry operation is the inversion, or a root !of the inversion (like -3) !Decide which kind of point symmetry operation it is !Finally assign tnonsconv order and decide the space symmetry operation ABI_ALLOCATE(t_axes,(nsymconv)) do isym=1,nsymconv call symcharac(center, determinant(isym), iholohedry, isym, label, & symrelconv(:,:,isym), tnonsconv(:,isym), t_axes(isym)) if (t_axes(isym) == -1) then write(message, '(a,a,i3,a,3(a,3i4,a),a,3es22.12,a,a,3es22.12)' )ch10,& & ' symspgr : problem with isym=',isym,ch10,& & ' symrelconv(:,1,isym)=',symrelconv(:,1,isym),ch10,& & ' symrelconv(:,2,isym)=',symrelconv(:,2,isym),ch10,& & ' symrelconv(:,3,isym)=',symrelconv(:,3,isym),ch10,& & ' tnonsconv(:,isym)=',tnonsconv(:,isym),ch10,& & ' trialt(:)=',trialt(:) call wrtout(std_out,message,'COLL') write(message, '(a,i4,2a)' )& & 'The space symmetry operation number',isym,ch10,& & 'is not a (translated) root of unity' MSG_BUG(message) else if (t_axes(isym) == -2) then write(message, '(a,i0,a)' )'The symmetry operation number ',isym,' is not a root of unity' MSG_BUG(message) end if n_axes(t_axes(isym))=n_axes(t_axes(isym))+1 end do ! isym=1,nsymconv if (sum(n_axes)-nsymconv/=0) then write(message, '(7a)' )& & 'Not all the symmetries have been recognized. ',ch10,& & 'This might be due either to an error in the input file',ch10,& & 'or to a BUG in ABINIT',ch10,& & 'Please contact the ABINIT group.' MSG_WARNING(message) end if !DEBUG !write(std_out,*)' symspgr : brvltt,nsymconv=',brvltt,nsymconv !write(std_out,*)' n_axes(1:10)=',n_axes(1:10) !write(std_out,*)' n_axes(11:20)=',n_axes(11:20) !write(std_out,*)' n_axes(21:31)=',n_axes(21:31) !ENDDEBUG !Treat cases in which the space group cannot be identified on the !basis of n_axes one need additional informations if(brvltt==1)then ! If the bravais lattice is primitive if(nsymconv==4)then n_axest=(/0,0,0,0,0,0,0,1,1,0, 0,0,0,0,0,2,0,0,0,0, 0,0,0,0,0,0,0,0,0,0,0/) if(sum((n_axes-n_axest)**2)==0)then ! Spgroup 27 (Pcc2) or 32 (Pba2) write(std_out,*)' symspgr: 27 or 32' additional_info=2 ! Select binary axis do isym=1,nsymconv if(t_axes(isym)==8)then ! Find direction of binary axis if(symrelconv(1,1,isym)==1)direction=1 if(symrelconv(2,2,isym)==1)direction=2 if(symrelconv(3,3,isym)==1)direction=3 end if end do ! Examine the projection of the translation vector of the a, b or c mirror planes ! onto the binary axis do isym=1,nsymconv if(t_axes(isym)==16)then if(abs(tnonsconv(direction,isym))>tol8)additional_info=1 end if end do end if else if(nsymconv==8)then n_axest=(/0,0,0,0,1,0,0,1,1,0, 0,0,0,0,1,2,0,0,0,2, 0,0,0,0,0,0,0,0,0,0,0/) if(sum((n_axes-n_axest)**2)==0)then ! Spgroup 55 (Pbam) or 57 (Pbcm) write(std_out,*)' symspgr: 55 or 57' additional_info=1 ! Select mirror plane m do isym=1,nsymconv if(t_axes(isym)==15)then ! Find direction of mirror plane if(symrelconv(1,1,isym)==-1)direction=1 if(symrelconv(2,2,isym)==-1)direction=2 if(symrelconv(3,3,isym)==-1)direction=3 end if end do ! Examine the projection of the translation vector of the a, b, or c mirror planes ! onto the binary axis do isym=1,nsymconv if(t_axes(isym)==16)then if(abs(tnonsconv(direction,isym))>tol8)additional_info=2 end if end do end if n_axest=(/0,0,0,0,1,0,0,1,1,0, 0,0,0,0,0,2,0,1,0,2, 0,0,0,0,0,0,0,0,0,0,0/) if(sum((n_axes-n_axest)**2)==0)then ! Spgroup 56 (Pccn) or 60 (Pbcn) write(std_out,*)' symspgr: 56 or 60' additional_info=1 ! Select mirror plane n do isym=1,nsymconv if(t_axes(isym)==18)then ! Find direction of mirror plane if(symrelconv(1,1,isym)==-1)direction=1 if(symrelconv(2,2,isym)==-1)direction=2 if(symrelconv(3,3,isym)==-1)direction=3 end if end do ! Examine the projection of the translation vector of the a, b, or c mirror planes ! onto the binary axis do isym=1,nsymconv if(t_axes(isym)==16)then if(abs(tnonsconv(direction,isym))0) dd=displs(1)/sz1 cc=size(xval,2);if (size(recvcounts)>0) cc=recvcounts(1)/sz1 recvbuf(:,dd+1:dd+cc)=xval(:,1:cc) #if defined HAVE_MPI end if #endif end subroutine xmpi_allgatherv_int2d !!*** !!****f* ABINIT/xmpi_allgatherv_int !! NAME !! xmpi_allgatherv_int !! !! FUNCTION !! Gathers data from all tasks and delivers it to all. !! Target: one-dimensional integer arrays. !! !! INPUTS !! xval= buffer array !! recvcounts= number of received elements !! displs= relative offsets for incoming data !! nelem= number of elements !! spaceComm= MPI communicator !! !! OUTPUT !! ier= exit status, a non-zero value meaning there is an error !! !! SIDE EFFECTS !! recvbuf= received buffer !! !! PARENTS !! !! CHILDREN !! xmpi_allgatherv !! !! SOURCE subroutine xmpi_allgatherv_int(xval,nelem,recvbuf,recvcounts,displs,spaceComm,ier) !This section has been created automatically by the script Abilint (TD). !Do not modify the following lines by hand. #undef ABI_FUNC #define ABI_FUNC 'xmpi_allgatherv_int' !End of the abilint section implicit none !Arguments------------------------- integer, DEV_CONTARRD intent(in) :: xval(:) integer, DEV_CONTARRD intent(inout) :: recvbuf(:) integer, DEV_CONTARRD intent(in) :: recvcounts(:),displs(:) integer,intent(in) :: nelem,spaceComm integer,intent(out) :: ier !Local variables------------------- integer :: cc,dd ! ************************************************************************* ier=0 #if defined HAVE_MPI if (spaceComm /= MPI_COMM_SELF .and. spaceComm /= MPI_COMM_NULL) then call MPI_ALLGATHERV(xval,nelem,MPI_INTEGER,recvbuf,recvcounts,displs,& & MPI_INTEGER,spaceComm,ier) else if (spaceComm == MPI_COMM_SELF) then #endif dd=0;if (size(displs)>0) dd=displs(1) cc=size(xval);if (size(recvcounts)>0) cc=recvcounts(1) recvbuf(dd+1:dd+cc)=xval(1:cc) #if defined HAVE_MPI end if #endif end subroutine xmpi_allgatherv_int !!*** !!****f* ABINIT/xmpi_allgatherv_int1_dp1 !! NAME !! xmpi_allgatherv_int1_dp1 !! !! FUNCTION !! Gathers data from all tasks and delivers it to all. !! Target : one-dimensional integer arrray and one-dimensionnal dp array !! !! INPUTS !! buf_int=buffer integer array that is going to be gathered !! buf_int_size=size of buf_int array !! buf_dp=buffer dp array that is going to be gathered !! buf_dp_size=size of buf_dp array !! spaceComm=MPI communicator !! !! OUTPUT !! buf_int_all=buffer integer array gathered !! buf_int_size_all=size of buffer integer array gathered !! buf_dp_all=buffer dp array gathered !! buf_dp_size_all=size of buffer dp array gathered !! ier=exit status, a non-zero value meaning there is an error !! !! PARENTS !! !! CHILDREN !! xmpi_allgatherv !! !! SOURCE subroutine xmpi_allgatherv_int1_dp1(buf_int,buf_int_size,buf_dp,buf_dp_size,& & buf_int_all,buf_int_size_all,buf_dp_all,buf_dp_size_all,spaceComm,ier) !This section has been created automatically by the script Abilint (TD). !Do not modify the following lines by hand. #undef ABI_FUNC #define ABI_FUNC 'xmpi_allgatherv_int1_dp1' !End of the abilint section implicit none !Arguments------------------------- !scalars integer,intent(in) :: buf_dp_size,buf_int_size,spaceComm integer,intent(out) :: buf_dp_size_all,buf_int_size_all,ier !arrays integer, intent(in) :: buf_int(:) integer,allocatable,target,intent(out) :: buf_int_all(:) real(dp),intent(in) :: buf_dp(:) real(dp),allocatable,target,intent(out) :: buf_dp_all(:) !Local variables-------------- !scalars integer :: buf_pack_size,ierr,ii,iproc,istart_dp,istart_int,lg,lg1,lg2,lg_dp,lg_int integer :: n1,nproc,position,totalbufcount logical,parameter :: use_pack=.false. !arrays integer :: buf_size(2),pos(3) integer ,allocatable :: buf_int_size1(:),buf_dp_size1(:) integer,allocatable :: count_dp(:),count_int(:),count_size(:),counts(:) integer,allocatable :: disp_dp(:),disp_int(:),displ(:),displ_dp(:),displ_int(:) integer,allocatable :: pos_all(:) integer,pointer :: outbuf_int(:) real(dp),pointer:: outbuf_dp(:) character,allocatable :: buf_pack(:),buf_pack_tot(:) ! ************************************************************************* ier=0 #if defined HAVE_MPI if (spaceComm/=MPI_COMM_SELF.and.spaceComm/=MPI_COMM_NULL) then nproc=xmpi_comm_size(spaceComm) !First version: using 2 allgather (one for ints, another for reals) !------------------------------------------------------------------ if (.not.use_pack) then ! Prepare communications ABI_ALLOCATE(count_int,(nproc)) ABI_ALLOCATE(disp_int,(nproc)) ABI_ALLOCATE(count_dp,(nproc)) ABI_ALLOCATE(disp_dp,(nproc)) ABI_ALLOCATE(count_size,(2*nproc)) buf_size(1)=buf_int_size; buf_size(2)=buf_dp_size call xmpi_allgather(buf_size,2,count_size,spaceComm,ier) do iproc=1,nproc count_int(iproc)=count_size(2*iproc-1) count_dp(iproc)=count_size(2*iproc) end do disp_int(1)=0;disp_dp(1)=0 do ii=2,nproc disp_int(ii)=disp_int(ii-1)+count_int(ii-1) disp_dp (ii)=disp_dp (ii-1)+count_dp (ii-1) end do buf_int_size_all=sum(count_int) buf_dp_size_all =sum(count_dp) ABI_STAT_ALLOCATE(buf_int_all,(buf_int_size_all), ier) if (ier/=0) call xmpi_abort(msg='error allocating buf_int_all in xmpi_allgatherv') ABI_STAT_ALLOCATE(buf_dp_all ,(buf_dp_size_all), ierr) if (ier/=0) call xmpi_abort(msg='error allocating buf_dp_all in xmpi_allgatherv') ! Communicate (one call for integers, one call for reals) call xmpi_allgatherv(buf_int,buf_int_size,buf_int_all,count_int,disp_int,spaceComm,ierr) call xmpi_allgatherv(buf_dp,buf_dp_size,buf_dp_all,count_dp,disp_dp,spaceComm,ierr) ! Release the memory ABI_DEALLOCATE(count_int) ABI_DEALLOCATE(disp_int) ABI_DEALLOCATE(count_dp) ABI_DEALLOCATE(disp_dp) ABI_DEALLOCATE(count_size) !2nd version: using 1 allgather (with MPI_PACK) !----------------------------------------------------------------- else ! Compute size of message call MPI_PACK_SIZE(buf_int_size,MPI_INTEGER,spaceComm,lg1,ier) call MPI_PACK_SIZE(buf_dp_size,MPI_DOUBLE_PRECISION,spaceComm,lg2,ier) lg=lg1+lg2 ! Pack data to be sent position=0 ; buf_pack_size=lg1+lg2 ABI_ALLOCATE(buf_pack,(buf_pack_size)) call MPI_PACK(buf_int,buf_int_size,MPI_INTEGER,buf_pack,buf_pack_size,position,spaceComm,ier) call MPI_PACK(buf_dp,buf_dp_size,MPI_DOUBLE_PRECISION,buf_pack,buf_pack_size,position,spaceComm,ier) ! Gather size of all packed messages ABI_ALLOCATE(pos_all,(nproc*3)) ABI_ALLOCATE(counts,(nproc)) ABI_ALLOCATE(buf_int_size1,(nproc)) ABI_ALLOCATE(buf_dp_size1,(nproc)) ABI_ALLOCATE(displ,(nproc)) ABI_ALLOCATE(displ_int,(nproc)) ABI_ALLOCATE(displ_dp,(nproc)) pos(1)=position;pos(2)=buf_int_size;pos(3)=buf_dp_size call MPI_ALLGATHER(pos,3,MPI_INTEGER,pos_all,3,MPI_INTEGER,spaceComm,ier) ii=1 do iproc=1,nproc counts(iproc)=pos_all(ii);ii=ii+1 buf_int_size1(iproc)=pos_all(ii);ii=ii+1 buf_dp_size1(iproc)=pos_all(ii);ii=ii+1 end do displ(1)=0 ; displ_int(1)=0 ; displ_dp(1)=0 do iproc=2,nproc displ(iproc)=displ(iproc-1)+counts(iproc-1) displ_int(iproc)=displ_int(iproc-1)+buf_int_size1(iproc-1) displ_dp(iproc)=displ_dp(iproc-1)+buf_dp_size1(iproc-1) end do totalbufcount=displ(nproc)+counts(nproc) ABI_STAT_ALLOCATE(buf_pack_tot,(totalbufcount), ier) if (ier/= 0) call xmpi_abort(msg='error allocating totalbufcount in xmpi_allgatherv') buf_int_size_all=sum(buf_int_size1) buf_dp_size_all=sum(buf_dp_size1) ABI_STAT_ALLOCATE(buf_int_all,(buf_int_size_all), ier) if (ier/=0) call xmpi_abort(msg='error allocating buf_int_all in xmpi_allgatherv') ABI_STAT_ALLOCATE(buf_dp_all,(buf_dp_size_all), ier) if (ier/=0) call xmpi_abort(msg='error allocating buf_dp_size_all in xmpi_allgatherv') ! Gather all packed messages call MPI_ALLGATHERV(buf_pack,position,MPI_PACKED,buf_pack_tot,counts,displ,MPI_PACKED,spaceComm,ier) position=0 do iproc=1,nproc lg_int=buf_int_size1(iproc); lg_dp=buf_dp_size1(iproc) istart_int=displ_int(iproc); istart_dp=displ_dp(iproc) outbuf_int=>buf_int_all(istart_int+1:istart_int+lg_int) call MPI_UNPACK(buf_pack_tot,totalbufcount,position, outbuf_int,& & lg_int,MPI_INTEGER,spaceComm,ier) outbuf_dp=>buf_dp_all(istart_dp+1:istart_dp+lg_dp) call MPI_UNPACK(buf_pack_tot,totalbufcount,position,outbuf_dp,& & lg_dp,MPI_DOUBLE_PRECISION,spaceComm,ier) end do ! Release the memory ABI_DEALLOCATE(pos_all) ABI_DEALLOCATE(counts) ABI_DEALLOCATE(buf_int_size1) ABI_DEALLOCATE(buf_dp_size1) ABI_DEALLOCATE(displ) ABI_DEALLOCATE(displ_int) ABI_DEALLOCATE(displ_dp) ABI_DEALLOCATE(buf_pack_tot) ABI_DEALLOCATE(buf_pack) end if else if (spaceComm==MPI_COMM_SELF) then #endif !Sequential version ABI_STAT_ALLOCATE(buf_int_all,(buf_int_size), ier) if (ier/=0) call xmpi_abort(msg='error allocating buf_int_all in xmpi_allgatherv') ABI_STAT_ALLOCATE(buf_dp_all,(buf_dp_size), ier) if (ier/=0) call xmpi_abort(msg='error allocating buf_dp_all in xmpi_allgatherv') buf_int_all(:)=buf_int(:) buf_dp_all(:)=buf_dp(:) buf_int_size_all=buf_int_size buf_dp_size_all=buf_dp_size #if defined HAVE_MPI end if #endif end subroutine xmpi_allgatherv_int1_dp1 !!*** !!****f* ABINIT/xmpi_allgatherv_dp !! NAME !! xmpi_allgatherv_dp !! !! FUNCTION !! Gathers data from all tasks and delivers it to all. !! Target: one-dimensional double precision arrays. !! !! INPUTS !! xval= buffer array !! recvcounts= number of received elements !! displs= relative offsets for incoming data !! nelem= number of elements !! spaceComm= MPI communicator !! !! OUTPUT !! ier= exit status, a non-zero value meaning there is an error !! !! SIDE EFFECTS !! recvbuf= received buffer !! !! PARENTS !! !! CHILDREN !! xmpi_allgatherv !! !! SOURCE subroutine xmpi_allgatherv_dp(xval,nelem,recvbuf,recvcounts,displs,spaceComm,ier) !This section has been created automatically by the script Abilint (TD). !Do not modify the following lines by hand. #undef ABI_FUNC #define ABI_FUNC 'xmpi_allgatherv_dp' !End of the abilint section implicit none !Arguments------------------------- real(dp), DEV_CONTARRD intent(in) :: xval(:) real(dp), DEV_CONTARRD intent(inout) :: recvbuf(:) integer,intent(in) :: recvcounts(:),displs(:) integer,intent(in) :: nelem,spaceComm integer,intent(out) :: ier !Local variables-------------- integer :: cc,dd ! ************************************************************************* ier=0 #if defined HAVE_MPI if (spaceComm /= MPI_COMM_SELF .and. spaceComm /= MPI_COMM_NULL) then call MPI_ALLGATHERV(xval,nelem,MPI_DOUBLE_PRECISION,recvbuf,recvcounts,displs,& & MPI_DOUBLE_PRECISION,spaceComm,ier) else if (spaceComm == MPI_COMM_SELF) then #endif dd=0;if (size(displs)>0) dd=displs(1) cc=size(xval);if (size(recvcounts)>0) cc=recvcounts(1) recvbuf(dd+1:dd+cc)=xval(1:cc) #if defined HAVE_MPI end if #endif end subroutine xmpi_allgatherv_dp !!*** !!****f* ABINIT/xmpi_allgatherv_dp2d !! NAME !! xmpi_allgatherv_dp2d !! !! FUNCTION !! Gathers data from all tasks and delivers it to all. !! Target: double precision two-dimensional arrays. !! !! INPUTS !! xval= buffer array !! recvcounts= number of received elements !! displs= relative offsets for incoming data !! nelem= number of elements !! spaceComm= MPI communicator !! !! OUTPUT !! ier= exit status, a non-zero value meaning there is an error !! !! SIDE EFFECTS !! recvbuf= received buffer !! !! PARENTS !! !! CHILDREN !! xmpi_allgatherv !! !! SOURCE subroutine xmpi_allgatherv_dp2d(xval,nelem,recvbuf,recvcounts,displs,spaceComm,ier) !This section has been created automatically by the script Abilint (TD). !Do not modify the following lines by hand. #undef ABI_FUNC #define ABI_FUNC 'xmpi_allgatherv_dp2d' !End of the abilint section implicit none !Arguments------------------------- real(dp), DEV_CONTARRD intent(in) :: xval(:,:) real(dp), DEV_CONTARRD intent(inout) :: recvbuf(:,:) integer, DEV_CONTARRD intent(in) :: recvcounts(:),displs(:) integer,intent(in) :: nelem,spaceComm integer,intent(out) :: ier !Local variables-------------- integer :: cc,dd,sz1 ! ************************************************************************* ier=0 #if defined HAVE_MPI if (spaceComm /= MPI_COMM_SELF .and. spaceComm /= MPI_COMM_NULL) then call MPI_ALLGATHERV(xval,nelem,MPI_DOUBLE_PRECISION,recvbuf,recvcounts,displs,& & MPI_DOUBLE_PRECISION,spaceComm,ier) else if (spaceComm == MPI_COMM_SELF) then #endif sz1=size(xval,1) dd=0;if (size(displs)>0) dd=displs(1)/sz1 cc=size(xval,2);if (size(recvcounts)>0) cc=recvcounts(1)/sz1 recvbuf(:,dd+1:dd+cc)=xval(:,1:cc) #if defined HAVE_MPI end if #endif end subroutine xmpi_allgatherv_dp2d !!*** !!****f* ABINIT/xmpi_allgatherv_dp3d !! NAME !! xmpi_allgatherv_dp3d !! !! FUNCTION !! Gathers data from all tasks and delivers it to all. !! Target: double precision three-dimensional arrays. !! !! INPUTS !! xval= buffer array !! recvcounts= number of received elements !! displs= relative offsets for incoming data !! nelem= number of elements !! spaceComm= MPI communicator !! !! OUTPUT !! ier= exit status, a non-zero value meaning there is an error !! !! SIDE EFFECTS !! recvbuf= received buffer !! !! PARENTS !! !! CHILDREN !! xmpi_allgatherv !! !! SOURCE subroutine xmpi_allgatherv_dp3d(xval,nelem,recvbuf,recvcounts,displs,spaceComm,ier) !This section has been created automatically by the script Abilint (TD). !Do not modify the following lines by hand. #undef ABI_FUNC #define ABI_FUNC 'xmpi_allgatherv_dp3d' !End of the abilint section implicit none !Arguments------------------------- real(dp), DEV_CONTARRD intent(in) :: xval(:,:,:) real(dp), DEV_CONTARRD intent(inout) :: recvbuf(:,:,:) integer, DEV_CONTARRD intent(in) :: recvcounts(:),displs(:) integer,intent(in) :: nelem,spaceComm integer,intent(out) :: ier !Local variables-------------- integer :: cc,dd,sz12 ! ************************************************************************* ier=0 #if defined HAVE_MPI if (spaceComm /= MPI_COMM_SELF .and. spaceComm /= MPI_COMM_NULL) then call MPI_ALLGATHERV(xval,nelem,MPI_DOUBLE_PRECISION,recvbuf,recvcounts,displs,& & MPI_DOUBLE_PRECISION,spaceComm,ier) else if (spaceComm == MPI_COMM_SELF) then #endif sz12=size(xval,1)*size(xval,2) dd=0;if (size(displs)>0) dd=displs(1)/sz12 cc=size(xval,3);if (size(recvcounts)>0) cc=recvcounts(1)/sz12 recvbuf(:,:,dd+1:dd+cc)=xval(:,:,1:cc) #if defined HAVE_MPI end if #endif end subroutine xmpi_allgatherv_dp3d !!*** !!****f* ABINIT/xmpi_allgatherv_dp4d !! NAME !! xmpi_allgatherv_dp4d !! !! FUNCTION !! Gathers data from all tasks and delivers it to all. !! Target: double precision four-dimensional arrays. !! !! INPUTS !! xval= buffer array !! recvcounts= number of received elements !! displs= relative offsets for incoming data !! nelem= number of elements !! spaceComm= MPI communicator !! !! OUTPUT !! ier= exit status, a non-zero value meaning there is an error !! !! SIDE EFFECTS !! recvbuf= received buffer !! !! PARENTS !! !! CHILDREN !! xmpi_allgatherv !! !! SOURCE subroutine xmpi_allgatherv_dp4d(xval,nelem,recvbuf,recvcounts,displs,spaceComm,ier) !This section has been created automatically by the script Abilint (TD). !Do not modify the following lines by hand. #undef ABI_FUNC #define ABI_FUNC 'xmpi_allgatherv_dp4d' !End of the abilint section implicit none !Arguments------------------------- real(dp), DEV_CONTARRD intent(in) :: xval(:,:,:,:) real(dp), DEV_CONTARRD intent(inout) :: recvbuf(:,:,:,:) integer, DEV_CONTARRD intent(in) :: recvcounts(:),displs(:) integer,intent(in) :: nelem,spaceComm integer,intent(out) :: ier !Local variables------------------- integer :: cc,dd,sz123 ! ************************************************************************* ier=0 #if defined HAVE_MPI if (spaceComm /= MPI_COMM_SELF .and. spaceComm /= MPI_COMM_NULL) then call MPI_ALLGATHERV(xval,nelem,MPI_DOUBLE_PRECISION,recvbuf,recvcounts,displs,& & MPI_DOUBLE_PRECISION,spaceComm,ier) else if (spaceComm == MPI_COMM_SELF) then #endif sz123=size(xval,1)*size(xval,2)*size(xval,3) dd=0;if (size(displs)>0) dd=displs(1)/sz123 cc=size(xval,4);if (size(recvcounts)>0) cc=recvcounts(1)/sz123 recvbuf(:,:,:,dd+1:dd+cc)=xval(:,:,:,1:cc) #if defined HAVE_MPI end if #endif end subroutine xmpi_allgatherv_dp4d !!*** !!****f* ABINIT/xmpi_allgatherv_coeff2d !! NAME !! xmpi_allgatherv_coeff2d !! !! FUNCTION !! Gathers data from all tasks and delivers it to all. !! Target: coeff2_type 1D-structure !! !! INPUTS !! xval_in = coeff2d_type array structure !! spaceComm= MPI communicator !! !! OUTPUT !! xval_out = coeff2d_type array structure !! ier= exit status, a non-zero value meaning there is an error !! !! SIDE EFFECTS !! !! PARENTS !! !! CHILDREN !! xmpi_allgatherv !! !! SOURCE subroutine xmpi_allgatherv_coeff2d(xval_in,xval_out,spaceComm,ierr) !This section has been created automatically by the script Abilint (TD). !Do not modify the following lines by hand. #undef ABI_FUNC #define ABI_FUNC 'xmpi_allgatherv_coeff2d' !End of the abilint section implicit none !Arguments ------------------------------------ !scalars integer,intent(in) :: spaceComm integer,intent(out) :: ierr !arrays type(coeff2_type),intent(in) :: xval_in(:) type(coeff2_type),intent(out) :: xval_out(:) !Local variables------------------------------- !scalars integer :: ii,n1,n2 #if defined HAVE_MPI integer :: buf_int_size,buf_int_size_all,buf_dp_size,buf_dp_size_all integer :: i2,indx_int,indx_dp,nb,nb_out,nproc #endif !arrays #if defined HAVE_MPI integer, allocatable :: buf_int(:),buf_int_all(:) integer, allocatable :: dimxval(:,:) real(dp),allocatable :: buf_dp(:),buf_dp_all(:) #endif ! ************************************************************************* ierr=0 #if defined HAVE_MPI if (spaceComm /= MPI_COMM_NULL) then nproc=xmpi_comm_size(spaceComm) nb = size(xval_in,1) if (spaceComm==MPI_COMM_SELF.or.nproc==1) then do ii=1,nb n1=size(xval_in(ii)%value,1) n2=size(xval_in(ii)%value,2) if (allocated(xval_out(ii)%value)) then ABI_DEALLOCATE(xval_out(ii)%value) end if ABI_STAT_ALLOCATE(xval_out(ii)%value,(n1,n2), ierr) if (ierr/= 0) call xmpi_abort(msg='error allocating xval_out%value in xmpi_allgatherv') xval_out(ii)%value=xval_in(ii)%value end do return end if buf_dp_size=0 ABI_ALLOCATE(dimxval,(nb,2)) do ii=1,nb dimxval(ii,1)=size(xval_in(ii)%value,dim=1) dimxval(ii,2)=size(xval_in(ii)%value,dim=2) buf_dp_size=buf_dp_size+dimxval(ii,1)*dimxval(ii,2) end do buf_int_size=2*nb; ABI_STAT_ALLOCATE(buf_int,(buf_int_size), ierr) if (ierr/= 0) call xmpi_abort(msg='error allocating buf_int in xmpi_allgatherv') indx_int=1 do ii=1,nb buf_int(indx_int )=dimxval(ii,1) buf_int(indx_int+1)=dimxval(ii,2) indx_int=indx_int+2 end do ABI_STAT_ALLOCATE(buf_dp,(buf_dp_size) ,ierr) if (ierr/= 0) call xmpi_abort(msg='error allocating buf_dp_size in xmpi_allgatherv') indx_dp=1 do ii=1,nb n1=dimxval(ii,1); n2=dimxval(ii,2) do i2=1,n2 buf_dp(indx_dp:indx_dp+n1-1)=xval_in(ii)%value(1:n1,i2) indx_dp=indx_dp+n1 end do end do call xmpi_allgatherv(buf_int,buf_int_size,buf_dp,buf_dp_size,buf_int_all, & & buf_int_size_all,buf_dp_all,buf_dp_size_all,spaceComm,ierr) nb_out=buf_int_size_all/2 indx_int=1;indx_dp=1 do ii=1,nb_out n1=buf_int_all(indx_int) n2=buf_int_all(indx_int+1) indx_int=indx_int+2 if (allocated(xval_out(ii)%value)) then ABI_DEALLOCATE(xval_out(ii)%value) end if ABI_STAT_ALLOCATE(xval_out(ii)%value,(n1,n2), ierr) if (ierr/= 0) call xmpi_abort(msg='error allocating xval_out%value in xmpi_allgatherv') do i2=1,n2 xval_out(ii)%value(1:n1,i2)=buf_dp_all(indx_dp:indx_dp+n1-1) indx_dp=indx_dp+n1 end do end do ABI_DEALLOCATE(buf_dp_all) ABI_DEALLOCATE(buf_int_all) ABI_DEALLOCATE(buf_int) ABI_DEALLOCATE(buf_dp) ABI_DEALLOCATE(dimxval) end if #else do ii=1,size(xval_in,1) n1=size(xval_in(ii)%value,1) n2=size(xval_in(ii)%value,2) if (allocated(xval_out(ii)%value)) then ABI_DEALLOCATE(xval_out(ii)%value) end if ABI_STAT_ALLOCATE(xval_out(ii)%value,(n1,n2), ierr) if (ierr/= 0) call xmpi_abort(msg='error allocating xval_out%value in xmpi_allgatherv') xval_out(ii)%value=xval_in(ii)%value end do #endif end subroutine xmpi_allgatherv_coeff2d !!*** !!****f* ABINIT/xmpi_allgatherv_coeff2d_indx !! NAME !! xmpi_allgatherv_coeff2d_indx !! !! FUNCTION !! Gathers data from all tasks and delivers it to all. !! Target: coeff2_type 1D-structure !! use of an indirect index to sort data !! !! INPUTS !! xval_in = coeff2d_type array structure !! spaceComm= MPI communicator !! indx= gives the indexes of xval_in in xval_out. !! xval_in(i) will be transfered in xval_out(indx(i)) !! !! OUTPUT !! xval_out = coeff2d_type array structure !! ierr= exit status, a non-zero value meaning there is an error !! !! SIDE EFFECTS !! !! PARENTS !! !! CHILDREN !! xmpi_allgatherv !! !! SOURCE subroutine xmpi_allgatherv_coeff2d_indx(xval_in,xval_out,spaceComm,indx,ierr) !This section has been created automatically by the script Abilint (TD). !Do not modify the following lines by hand. #undef ABI_FUNC #define ABI_FUNC 'xmpi_allgatherv_coeff2d_indx' !End of the abilint section implicit none !Arguments ------------------------------------ !scalars integer,intent(in) :: spaceComm integer,intent(out) :: ierr !arrays integer,intent(in) :: indx(:) type(coeff2_type),intent(in) :: xval_in(:) type(coeff2_type),intent(out) :: xval_out(:) !Local variables------------------------------- !scalars integer :: ii,ival,n1,n2,nb #if defined HAVE_MPI integer :: buf_int_size,buf_int_size_all,buf_dp_size,buf_dp_size_all integer :: i2,indx_int,indx_dp,nb_out,nproc #endif !arrays #if defined HAVE_MPI integer, allocatable :: buf_int(:),buf_int_all(:) integer, allocatable :: dimxval(:,:) real(dp),allocatable :: buf_dp(:),buf_dp_all(:) #endif ! ************************************************************************* ierr=0 ; nb = size(xval_in,1) #if defined HAVE_MPI if (spaceComm == MPI_COMM_NULL) return nproc=xmpi_comm_size(spaceComm) if (spaceComm==MPI_COMM_SELF.or.nproc==1) then #endif do ii=1,nb n1=size(xval_in(ii)%value,1) n2=size(xval_in(ii)%value,2) ival=indx(ii) if (allocated(xval_out(ival)%value)) then ABI_DEALLOCATE(xval_out(ival)%value) end if ABI_STAT_ALLOCATE(xval_out(ival)%value,(n1,n2), ierr) if (ierr/= 0) call xmpi_abort(msg='error allocating xval_out%value in xmpi_allgatherv') xval_out(ii)%value=xval_in(ival)%value end do return #if defined HAVE_MPI end if buf_dp_size=0 ABI_STAT_ALLOCATE(dimxval,(nb,2), ierr) if (ierr/= 0) call xmpi_abort(msg='error allocating dimxval in xmpi_allgatherv') do ii=1,nb dimxval(ii,1)=size(xval_in(ii)%value,dim=1) dimxval(ii,2)=size(xval_in(ii)%value,dim=2) buf_dp_size=buf_dp_size+dimxval(ii,1)*dimxval(ii,2) end do buf_int_size=3*nb ABI_STAT_ALLOCATE(buf_int,(buf_int_size), ierr) if (ierr/= 0) call xmpi_abort(msg='error allocating buf_int in xmpi_allgatherv') indx_int=1 do ii=1,nb buf_int(indx_int )=dimxval(ii,1) buf_int(indx_int+1)=dimxval(ii,2) buf_int(indx_int+2)=indx(ii) indx_int=indx_int+3 end do ABI_STAT_ALLOCATE(buf_dp,(buf_dp_size), ierr) if (ierr/= 0) call xmpi_abort(msg='error allocating buf_dp in xmpi_allgatherv') indx_dp=1 do ii=1,nb n1=dimxval(ii,1); n2=dimxval(ii,2) do i2=1,n2 buf_dp(indx_dp:indx_dp+n1-1)=xval_in(ii)%value(1:n1,i2) indx_dp=indx_dp+n1 end do end do call xmpi_allgatherv(buf_int,buf_int_size,buf_dp,buf_dp_size,buf_int_all, & & buf_int_size_all,buf_dp_all,buf_dp_size_all,spaceComm,ierr) nb_out=buf_int_size_all/3 indx_int=1;indx_dp=1 do ii=1,nb_out n1=buf_int_all(indx_int) n2=buf_int_all(indx_int+1) ival=buf_int_all(indx_int+2) indx_int=indx_int+3 if (allocated(xval_out(ival)%value)) then ABI_DEALLOCATE(xval_out(ival)%value) end if ABI_STAT_ALLOCATE(xval_out(ival)%value,(n1,n2), ierr) if (ierr/= 0) call xmpi_abort(msg='error allocating xval_out%value in xmpi_allgatherv') do i2=1,n2 xval_out(ival)%value(1:n1,i2)=buf_dp_all(indx_dp:indx_dp+n1-1) indx_dp=indx_dp+n1 end do end do ABI_DEALLOCATE(buf_dp_all) ABI_DEALLOCATE(buf_int_all) ABI_DEALLOCATE(buf_int) ABI_DEALLOCATE(buf_dp) ABI_DEALLOCATE(dimxval) #endif end subroutine xmpi_allgatherv_coeff2d_indx !!*** v_sim-3.8.0/lib/plug-ins/abinit/xmpi_alltoall.finc000066400000000000000000000100521370110300500220770ustar00rootroot00000000000000!{\src2tex{textfont=tt}} !!****f* ABINIT/xmpi_alltoall !! NAME !! xmpi_alltoall !! !! FUNCTION !! This module contains functions that calls MPI routine, !! if we compile the code using the MPI CPP flags. !! xmpi_alltoall is the generic function. !! !! COPYRIGHT !! Copyright (C) 2001-2016 ABINIT group (AR,XG) !! This file is distributed under the terms of the !! GNU General Public License, see ~ABINIT/COPYING !! or http://www.gnu.org/copyleft/gpl.txt . !! !! SOURCE !!*** !!****f* ABINIT/xmpi_alltoall_int !! NAME !! xmpi_alltoall_int !! !! FUNCTION !! Sends data from all to all processes. !! Target: integer mono dimensional arrays. !! !! SOURCE subroutine xmpi_alltoall_int(xval, sendsize, recvbuf, recvsize, spaceComm, ier) !This section has been created automatically by the script Abilint (TD). !Do not modify the following lines by hand. #undef ABI_FUNC #define ABI_FUNC 'xmpi_alltoall_int' !End of the abilint section implicit none !Arguments------------------------- integer, DEV_CONTARRD intent(in) :: xval(:) integer, DEV_CONTARRD intent(inout) :: recvbuf(:) integer ,intent(in) :: sendsize, recvsize integer ,intent(in) :: spaceComm integer ,intent(out) :: ier !Local variables------------------- ! ************************************************************************* ier=0 #if defined HAVE_MPI if (spaceComm /= MPI_COMM_SELF .and. spaceComm /= MPI_COMM_NULL) then ! allgather xval on all proc. in spaceComm call MPI_ALLTOALL(xval, sendsize, MPI_INTEGER, recvbuf, & & recvsize, MPI_INTEGER, spaceComm, ier) else if (spaceComm == MPI_COMM_SELF) then recvbuf=xval end if #else recvbuf=xval #endif end subroutine xmpi_alltoall_int !!*** !!****f* ABINIT/xmpi_alltoall_dp2d !! NAME !! xmpi_alltoall_dp2d !! !! FUNCTION !! Sends data from all to all processes. !! Target: double precision two-dimensional arrays. !! !! SOURCE subroutine xmpi_alltoall_dp2d(xval, sendsize, recvbuf, recvsize, spaceComm, ier) !This section has been created automatically by the script Abilint (TD). !Do not modify the following lines by hand. #undef ABI_FUNC #define ABI_FUNC 'xmpi_alltoall_dp2d' !End of the abilint section implicit none !Arguments------------------------- real(dp), DEV_CONTARRD intent(in) :: xval(:,:) real(dp), DEV_CONTARRD intent(inout) :: recvbuf(:,:) integer ,intent(in) :: sendsize, recvsize integer ,intent(in) :: spaceComm integer ,intent(out) :: ier ! ************************************************************************* ier=0 #if defined HAVE_MPI if (spaceComm /= MPI_COMM_SELF .and. spaceComm /= MPI_COMM_NULL) then ! allgather xval on all proc. in spaceComm call MPI_ALLTOALL(xval, sendsize, MPI_DOUBLE_PRECISION, recvbuf, & & recvsize, MPI_DOUBLE_PRECISION, spaceComm, ier) else if (spaceComm == MPI_COMM_SELF) then recvbuf=xval end if #else recvbuf=xval #endif end subroutine xmpi_alltoall_dp2d !!*** !!****f* ABINIT/xmpi_alltoall_dp4d !! NAME !! xmpi_alltoall_dp4d !! !! FUNCTION !! Sends data from all to all processes. !! Target: double precision four-dimensional arrays. !! !! SOURCE subroutine xmpi_alltoall_dp4d(xval, sendsize, recvbuf, recvsize, spaceComm, ier) !This section has been created automatically by the script Abilint (TD). !Do not modify the following lines by hand. #undef ABI_FUNC #define ABI_FUNC 'xmpi_alltoall_dp4d' !End of the abilint section implicit none !Arguments------------------------- real(dp), DEV_CONTARRD intent(in) :: xval(:,:,:,:) real(dp), DEV_CONTARRD intent(inout) :: recvbuf(:,:,:,:) integer ,intent(in) :: sendsize, recvsize integer ,intent(in) :: spaceComm integer ,intent(out) :: ier ! ************************************************************************* ier=0 #if defined HAVE_MPI if (spaceComm /= MPI_COMM_SELF .and. spaceComm /= MPI_COMM_NULL) then ! allgather xval on all proc. in spaceComm call MPI_ALLTOALL(xval, sendsize, MPI_DOUBLE_PRECISION, recvbuf, & & recvsize, MPI_DOUBLE_PRECISION, spaceComm, ier) else if (spaceComm == MPI_COMM_SELF) then recvbuf=xval end if #else recvbuf=xval #endif end subroutine xmpi_alltoall_dp4d !!*** v_sim-3.8.0/lib/plug-ins/abinit/xmpi_alltoallv.finc000066400000000000000000000151411370110300500222710ustar00rootroot00000000000000!{\src2tex{textfont=tt}} !!****f* ABINIT/xmpi_alltoallv_dp2d !! NAME !! xmpi_alltoallv_dp2d !! !! FUNCTION !! This module contains functions calling the MPI routine ALLTOALLV !! xmpi_alltoallv is the generic function. !! !! COPYRIGHT !! Copyright (C) 2001-2016 ABINIT group (AR,XG) !! This file is distributed under the terms of the !! GNU General Public License, see ~ABINIT/COPYING !! or http://www.gnu.org/copyleft/gpl.txt . !! !! INPUTS !! xval= buffer array !! sendcnts= number of sent elements !! sdispls= postions of values sent by the processor !! rdispls= positions of values received by the processor !! recvcnts= number of received elements !! comm= MPI communicator !! !! OUTPUT !! ier= exit status, a non-zero value meaning there is an error !! !! SIDE EFFECTS !! recvbuf= received buffer !! !! PARENTS !! !! CHILDREN !! mpi_alltoallv !! !! SOURCE subroutine xmpi_alltoallv_dp2d(xval,sendcnts,sdispls,recvbuf,recvcnts,rdispls,comm,ier) !This section has been created automatically by the script Abilint (TD). !Do not modify the following lines by hand. #undef ABI_FUNC #define ABI_FUNC 'xmpi_alltoallv_dp2d' !End of the abilint section implicit none !Arguments------------------------- real(dp), DEV_CONTARRD intent(in) :: xval(:,:) real(dp), DEV_CONTARRD intent(inout) :: recvbuf(:,:) integer , DEV_CONTARRD intent(in) :: sendcnts(:),sdispls(:),rdispls(:),recvcnts(:) integer ,intent(in) :: comm integer ,intent(out) :: ier !Local variables------------------- integer :: sc,sds,sdr,sz1 ! ********************************************************************* ier=0 #if defined HAVE_MPI if (comm /= MPI_COMM_SELF .and. comm /= MPI_COMM_NULL) then ! allgather xval on all proc. in comm call MPI_ALLTOALLV(xval,sendcnts,sdispls,MPI_DOUBLE_PRECISION,recvbuf,& & recvcnts,rdispls,MPI_DOUBLE_PRECISION,comm,ier) else if (comm == MPI_COMM_SELF) then #endif sz1=size(xval,1) sds=0;if (size(sdispls)>0) sds=sdispls(1)/sz1 sdr=0;if (size(rdispls)>0) sdr=rdispls(1)/sz1 sc=size(xval,2);if (size(sendcnts)>0) sc=sendcnts(1)/sz1 recvbuf(:,sdr+1:sdr+sc)=xval(:,sds+1:sds+sc) #if defined HAVE_MPI end if #endif end subroutine xmpi_alltoallv_dp2d !!*** !!****f* ABINIT/xmpi_alltoallv_int2d !! NAME !! xmpi_alltoallv_int2d !! !! FUNCTION !! Sends data from all to all processes. !! Target: two-dimensional integer arrays. !! !! SOURCE subroutine xmpi_alltoallv_int2d(xval,sendcnts,sdispls,recvbuf,recvcnts,rdispls,comm,ier) !This section has been created automatically by the script Abilint (TD). !Do not modify the following lines by hand. #undef ABI_FUNC #define ABI_FUNC 'xmpi_alltoallv_int2d' !End of the abilint section implicit none !Arguments------------------------- integer, DEV_CONTARRD intent(in) :: xval(:,:) integer, DEV_CONTARRD intent(inout) :: recvbuf(:,:) integer, DEV_CONTARRD intent(in) :: sendcnts(:),sdispls(:),rdispls(:),recvcnts(:) integer,intent(in) :: comm integer,intent(out) :: ier !Local variables------------------- integer :: sc,sds,sdr,sz1 ! ********************************************************************* ier=0 #if defined HAVE_MPI if (comm /= MPI_COMM_SELF .and. comm /= MPI_COMM_NULL) then call MPI_ALLTOALLV(xval,sendcnts,sdispls,MPI_INTEGER,recvbuf,& & recvcnts,rdispls,MPI_INTEGER,comm,ier) else if (comm == MPI_COMM_SELF) then #endif sz1=size(xval,1) sds=0;if (size(sdispls)>0) sds=sdispls(1)/sz1 sdr=0;if (size(rdispls)>0) sdr=rdispls(1)/sz1 sc=size(xval,2);if (size(sendcnts)>0) sc=sendcnts(1)/sz1 recvbuf(:,sdr+1:sdr+sc)=xval(:,sds+1:sds+sc) #if defined HAVE_MPI end if #endif end subroutine xmpi_alltoallv_int2d !!*** !!****f* ABINIT/xmpi_alltoallv_dp1d !! NAME !! xmpi_alltoallv_dp1d !! !! FUNCTION !! Sends data from all to all processes. !! Target: double precision one-dimensional arrays. !! !! SOURCE subroutine xmpi_alltoallv_dp1d(xval,sendcnts,sdispls,recvbuf,recvcnts,rdispls,comm,ier) !This section has been created automatically by the script Abilint (TD). !Do not modify the following lines by hand. #undef ABI_FUNC #define ABI_FUNC 'xmpi_alltoallv_dp1d' !End of the abilint section implicit none !Arguments------------------------- real(dp), DEV_CONTARRD intent(in) :: xval(:) real(dp), DEV_CONTARRD intent(inout) :: recvbuf(:) integer, DEV_CONTARRD intent(in) :: sendcnts(:),sdispls(:),recvcnts(:) integer,intent(in) :: comm, rdispls integer,intent(out) :: ier !Local variables------------------- integer :: sc,sds,sdr #if defined HAVE_MPI integer, allocatable :: rdispls_on(:) #endif ! ********************************************************************* ier=0 #if defined HAVE_MPI if (comm /= MPI_COMM_SELF .and. comm /= MPI_COMM_NULL) then ABI_STAT_ALLOCATE(rdispls_on,(size(sendcnts)), ier) if (ier/= 0) call xmpi_abort(msg='error allocating rdispls_on in xmpi_alltoallv') rdispls_on = 0 call MPI_ALLTOALLV(xval,sendcnts,sdispls,MPI_DOUBLE_PRECISION,recvbuf,& & recvcnts,rdispls_on,MPI_DOUBLE_PRECISION,comm,ier) ABI_DEALLOCATE(rdispls_on) else if (comm == MPI_COMM_SELF) then #endif sdr=rdispls;sds=0;if (size(sdispls)>0) sds=sdispls(1) sc=size(xval);if (size(sendcnts)>0) sc=sendcnts(1) recvbuf(1:sc)=xval(sds+1:sds+sc) #if defined HAVE_MPI end if #endif end subroutine xmpi_alltoallv_dp1d !!*** !!****f* ABINIT/xmpi_alltoallv_dp1d2 !! NAME !! xmpi_alltoallv_dp1d2 !! !! FUNCTION !! Sends data from all to all processes. !! Target: double precision one-dimensional arrays. !! !! SOURCE subroutine xmpi_alltoallv_dp1d2(xval,sendcnts,sdispls,recvbuf,recvcnts,rdispls,comm,ier) !This section has been created automatically by the script Abilint (TD). !Do not modify the following lines by hand. #undef ABI_FUNC #define ABI_FUNC 'xmpi_alltoallv_dp1d2' !End of the abilint section implicit none !Arguments------------------------- real(dp), DEV_CONTARRD intent(in) :: xval(:) real(dp), DEV_CONTARRD intent(inout) :: recvbuf(:) integer, DEV_CONTARRD intent(in) :: sendcnts(:),sdispls(:),recvcnts(:),rdispls(:) integer,intent(in) :: comm integer,intent(out) :: ier !Local variables------------------- integer :: sc,sds,sdr ! ********************************************************************* ier=0 #if defined HAVE_MPI if (comm /= MPI_COMM_SELF .and. comm /= MPI_COMM_NULL) then call MPI_ALLTOALLV(xval,sendcnts,sdispls,MPI_DOUBLE_PRECISION,recvbuf,& & recvcnts,rdispls,MPI_DOUBLE_PRECISION,comm,ier) else if (comm == MPI_COMM_SELF) then #endif sds=0;if (size(sdispls)>0) sds=sdispls(1) sdr=0;if (size(rdispls)>0) sdr=rdispls(1) sc=size(xval);if (size(sendcnts)>0) sc=sendcnts(1) recvbuf(sdr+1:sdr+sc)=xval(sds+1:sds+sc) #if defined HAVE_MPI end if #endif end subroutine xmpi_alltoallv_dp1d2 !!*** v_sim-3.8.0/lib/plug-ins/abinit/xmpi_bcast.finc000066400000000000000000001124121370110300500213720ustar00rootroot00000000000000!{\src2tex{textfont=tt}} !!****f* ABINIT/xmpi_bcast_intv !! NAME !! xmpi_bcast_intv !! !! FUNCTION !! This module contains functions that calls MPI routine, !! if we compile the code using the MPI CPP flags. !! xmpi_bcast is the generic function. !! !! COPYRIGHT !! Copyright (C) 2001-2016 ABINIT group (Rshaltaf,AR,XG) !! This file is distributed under the terms of the !! GNU General Public License, see ~ABINIT/COPYING !! or http://www.gnu.org/copyleft/gpl.txt . !! !! SOURCE subroutine xmpi_bcast_intv(xval,master,spaceComm,ier) !This section has been created automatically by the script Abilint (TD). !Do not modify the following lines by hand. #undef ABI_FUNC #define ABI_FUNC 'xmpi_bcast_intv' !End of the abilint section implicit none !Arguments------------------------- integer,intent(inout) :: xval integer,intent(in) :: spaceComm,master integer,intent(out) :: ier ! ************************************************************************* ier=0 #if defined HAVE_MPI if (spaceComm /= MPI_COMM_SELF .and. spaceComm /= MPI_COMM_NULL) then call MPI_BCAST(xval,1,MPI_INTEGER,master,spaceComm,ier) end if #endif end subroutine xmpi_bcast_intv !!*** !!****f* ABINIT/xmpi_bcast_int1d !! NAME !! xmpi_bcast_int1d !! !! FUNCTION !! Broadcasts data from master to slaves. !! Target: one-dimensional integer arrays. !! !! INPUTS !! spaceComm= MPI communicator !! master= master MPI node !! !! OUTPUT !! ier= exit status, a non-zero value meaning there is an error !! !! SIDE EFFECTS !! xval= buffer array !! !! PARENTS !! !! CHILDREN !! mpi_bcast !! !! SOURCE subroutine xmpi_bcast_int1d(xval,master,spaceComm,ier) !This section has been created automatically by the script Abilint (TD). !Do not modify the following lines by hand. #undef ABI_FUNC #define ABI_FUNC 'xmpi_bcast_int1d' !End of the abilint section implicit none !Arguments ------------------------------------ integer, DEV_CONTARRD intent(inout) :: xval(:) integer,intent(in) :: spaceComm,master integer,intent(out) :: ier !Local variables------------------------------- integer :: n ! ************************************************************************* ier=0 #if defined HAVE_MPI if (spaceComm /= MPI_COMM_SELF .and. spaceComm /= MPI_COMM_NULL) then n=size(xval) call MPI_BCAST(xval,n,MPI_INTEGER,master,spaceComm,ier) end if #endif end subroutine xmpi_bcast_int1d !!*** !!****f* ABINIT/xmpi_bcast_int2d !! NAME !! xmpi_bcast_int2d !! !! FUNCTION !! Broadcasts data from master to slaves. !! Target: two-dimensional integer arrays. !! !! INPUTS !! spaceComm= MPI communicator !! master= master MPI node !! !! OUTPUT !! ier= exit status, a non-zero value meaning there is an error !! !! SIDE EFFECTS !! xval= buffer array !! !! PARENTS !! !! CHILDREN !! mpi_bcast !! !! SOURCE subroutine xmpi_bcast_int2d(xval,master,spaceComm,ier) !This section has been created automatically by the script Abilint (TD). !Do not modify the following lines by hand. #undef ABI_FUNC #define ABI_FUNC 'xmpi_bcast_int2d' !End of the abilint section implicit none !Arguments------------------------- integer, DEV_CONTARRD intent(inout) :: xval(:,:) integer,intent(in) :: spaceComm,master integer,intent(out) :: ier !Local variables------------------- #if defined HAVE_MPI integer :: n1,n2 #endif ! ************************************************************************* ier=0 #if defined HAVE_MPI if (spaceComm /= MPI_COMM_SELF .and. spaceComm /= MPI_COMM_NULL) then n1=size(xval,dim=1) n2=size(xval,dim=2) call MPI_BCAST(xval,n1*n2,MPI_INTEGER,master,spaceComm,ier) end if #endif end subroutine xmpi_bcast_int2d !!*** !!****f* ABINIT/xmpi_bcast_int3d !! NAME !! xmpi_bcast_int3d !! !! FUNCTION !! Broadcasts data from master to slaves. !! Target: three-dimensional integer arrays. !! !! INPUTS !! spaceComm= MPI communicator !! master= master MPI node !! !! OUTPUT !! ier= exit status, a non-zero value meaning there is an error !! !! SIDE EFFECTS !! xval= buffer array !! !! PARENTS !! !! CHILDREN !! mpi_bcast !! !! SOURCE subroutine xmpi_bcast_int3d(xval,master,spaceComm,ier) !This section has been created automatically by the script Abilint (TD). !Do not modify the following lines by hand. #undef ABI_FUNC #define ABI_FUNC 'xmpi_bcast_int3d' !End of the abilint section implicit none !Arguments------------------------- integer, DEV_CONTARRD intent(inout) :: xval(:,:,:) integer,intent(in) :: spaceComm,master integer,intent(out) :: ier !Local variables------------------------------- #if defined HAVE_MPI integer :: n1,n2,n3 #endif ! ************************************************************************* ier=0 #if defined HAVE_MPI if (spaceComm /= MPI_COMM_SELF .and. spaceComm /= MPI_COMM_NULL) then n1=size(xval,dim=1) n2=size(xval,dim=2) n3=size(xval,dim=3) call MPI_BCAST(xval,n1*n2*n3,MPI_INTEGER,master,spaceComm,ier) end if #endif end subroutine xmpi_bcast_int3d !!*** !!****f* ABINIT/xmpi_bcast_dpv !! NAME !! xmpi_bcast_dpv !! !! FUNCTION !! Broadcasts data from master to slaves. !! Target: scalar double precisions. !! !! INPUTS !! spaceComm= MPI communicator !! master= master MPI node !! !! OUTPUT !! ier= exit status, a non-zero value meaning there is an error !! !! SIDE EFFECTS !! xval= buffer array !! !! PARENTS !! !! CHILDREN !! mpi_bcast !! !! SOURCE subroutine xmpi_bcast_dpv(xval,master,spaceComm,ier) !This section has been created automatically by the script Abilint (TD). !Do not modify the following lines by hand. #undef ABI_FUNC #define ABI_FUNC 'xmpi_bcast_dpv' !End of the abilint section implicit none !Arguments ------------------------------------ real(dp),intent(inout) :: xval integer ,intent(in) :: spaceComm,master integer ,intent(out) :: ier !Local variables------------------------------- ! ************************************************************************* ier=0 #if defined HAVE_MPI if (spaceComm /= MPI_COMM_SELF .and. spaceComm /= MPI_COMM_NULL) then call MPI_BCAST(xval,1,MPI_DOUBLE_PRECISION,master,spaceComm,ier) end if #endif end subroutine xmpi_bcast_dpv !!*** !!****f* ABINIT/xmpi_bcast_dp1d !! NAME !! xmpi_bcast_dp1d !! !! FUNCTION !! Broadcasts data from master to slaves. !! Target: double precision one-dimensional arrays. !! !! INPUTS !! spaceComm= MPI communicator !! master= master MPI node !! !! OUTPUT !! ier= exit status, a non-zero value meaning there is an error !! !! SIDE EFFECTS !! xval= buffer array !! !! PARENTS !! !! CHILDREN !! mpi_bcast !! !! SOURCE subroutine xmpi_bcast_dp1d(xval,master,spaceComm,ier) !This section has been created automatically by the script Abilint (TD). !Do not modify the following lines by hand. #undef ABI_FUNC #define ABI_FUNC 'xmpi_bcast_dp1d' !End of the abilint section implicit none !Arguments------------------------- real(dp), DEV_CONTARRD intent(inout) :: xval(:) integer ,intent(in) :: spaceComm,master integer ,intent(out) :: ier !Local variables------------------- #if defined HAVE_MPI integer :: n #endif ! ************************************************************************* ier=0 #if defined HAVE_MPI if (spaceComm /= MPI_COMM_SELF .and. spaceComm /= MPI_COMM_NULL) then n=size(xval,dim=1) call MPI_BCAST(xval,n,MPI_DOUBLE_PRECISION,master,spaceComm,ier) end if #endif end subroutine xmpi_bcast_dp1d !!*** !!****f* ABINIT/xmpi_bcast_dp2d !! NAME !! xmpi_bcast_dp2d !! !! FUNCTION !! Broadcasts data from master to slaves. !! Target: double precision two-dimensional arrays. !! !! INPUTS !! spaceComm= MPI communicator !! master= master MPI node !! !! OUTPUT !! ier= exit status, a non-zero value meaning there is an error !! !! SIDE EFFECTS !! xval= buffer array !! !! SOURCE subroutine xmpi_bcast_dp2d(xval,master,spaceComm,ier) !This section has been created automatically by the script Abilint (TD). !Do not modify the following lines by hand. #undef ABI_FUNC #define ABI_FUNC 'xmpi_bcast_dp2d' !End of the abilint section implicit none !Arguments------------------------- real(dp), DEV_CONTARRD intent(inout) :: xval(:,:) integer ,intent(in) :: spaceComm,master integer ,intent(out) :: ier !Local variables------------------- #if defined HAVE_MPI integer :: n1,n2 #endif ! ************************************************************************* ier=0 #if defined HAVE_MPI if (spaceComm /= MPI_COMM_SELF .and. spaceComm /= MPI_COMM_NULL) then n1=size(xval,dim=1) n2=size(xval,dim=2) call MPI_BCAST(xval,n1*n2,MPI_DOUBLE_PRECISION,master,spaceComm,ier) end if #endif end subroutine xmpi_bcast_dp2d !!*** !!****f* ABINIT/xmpi_bcast_dp3d !! NAME !! xmpi_bcast_dp3d !! !! FUNCTION !! Broadcasts data from master to slaves. !! Target: double precision three-dimensional arrays. !! !! INPUTS !! spaceComm= MPI communicator !! master= master MPI node !! !! OUTPUT !! ier= exit status, a non-zero value meaning there is an error !! !! SIDE EFFECTS !! xval= buffer array !! !! SOURCE subroutine xmpi_bcast_dp3d(xval,master,spaceComm,ier) !This section has been created automatically by the script Abilint (TD). !Do not modify the following lines by hand. #undef ABI_FUNC #define ABI_FUNC 'xmpi_bcast_dp3d' !End of the abilint section implicit none !Arguments------------------------- real(dp), DEV_CONTARRD intent(inout) :: xval(:,:,:) integer ,intent(in) :: spaceComm,master integer ,intent(out) :: ier !Local variables------------------- #if defined HAVE_MPI integer :: n1,n2,n3 #endif ! ************************************************************************* ier=0 #if defined HAVE_MPI if (spaceComm /= MPI_COMM_SELF .and. spaceComm /= MPI_COMM_NULL) then n1=size(xval,dim=1) n2=size(xval,dim=2) n3=size(xval,dim=3) call MPI_BCAST(xval,n1*n2*n3,MPI_DOUBLE_PRECISION,master,spaceComm,ier) end if #endif end subroutine xmpi_bcast_dp3d !!*** !!****f* ABINIT/xmpi_bcast_dp4d !! NAME !! xmpi_bcast_dp4d !! !! FUNCTION !! Broadcasts data from master to slaves. !! Target: double precision four-dimensional arrays. !! !! INPUTS !! spaceComm= MPI communicator !! master= master MPI node !! !! OUTPUT !! ier= exit status, a non-zero value meaning there is an error !! !! SIDE EFFECTS !! xval= buffer array !! !! SOURCE subroutine xmpi_bcast_dp4d(xval,master,spaceComm,ier) !This section has been created automatically by the script Abilint (TD). !Do not modify the following lines by hand. #undef ABI_FUNC #define ABI_FUNC 'xmpi_bcast_dp4d' !End of the abilint section implicit none !Arguments------------------------- real(dp), DEV_CONTARRD intent(inout) :: xval(:,:,:,:) integer ,intent(in) :: spaceComm,master integer ,intent(out) :: ier !Local variables------------------- #if defined HAVE_MPI integer :: n1,n2,n3,n4 #endif ! ************************************************************************* ier=0 #if defined HAVE_MPI if (spaceComm /= MPI_COMM_SELF .and. spaceComm /= MPI_COMM_NULL) then n1=size(xval,dim=1) n2=size(xval,dim=2) n3=size(xval,dim=3) n4=size(xval,dim=4) call MPI_BCAST(xval,n1*n2*n3*n4,MPI_DOUBLE_PRECISION,master,spaceComm,ier) end if #endif end subroutine xmpi_bcast_dp4d !!*** !!****f* ABINIT/xmpi_bcast_spv !! NAME !! xmpi_bcast_spv !! !! FUNCTION !! Broadcasts data from master to slaves. !! Target: scalar single precisions. !! !! INPUTS !! spaceComm= MPI communicator !! master= master MPI node !! !! OUTPUT !! ier= exit status, a non-zero value meaning there is an error !! !! SIDE EFFECTS !! xval= buffer array !! !! SOURCE subroutine xmpi_bcast_spv(xval,master,spaceComm,ier) !This section has been created automatically by the script Abilint (TD). !Do not modify the following lines by hand. #undef ABI_FUNC #define ABI_FUNC 'xmpi_bcast_spv' !End of the abilint section implicit none !Arguments------------------------- real(sp),intent(inout) :: xval integer,intent(in) :: spaceComm,master integer,intent(out) :: ier ! ************************************************************************* ier=0 #if defined HAVE_MPI if (spaceComm /= MPI_COMM_SELF .and. spaceComm /= MPI_COMM_NULL) then call MPI_BCAST(xval,1,MPI_REAL,master,spaceComm,ier) end if #endif end subroutine xmpi_bcast_spv !!*** !!****f* ABINIT/xmpi_bcast_sp1d !! NAME !! xmpi_bcast_sp1d !! !! FUNCTION !! Broadcasts data from master to slaves. !! Target: one-dimensional single precision arrays. !! !! INPUTS !! spaceComm= MPI communicator !! master= master MPI node !! !! OUTPUT !! ier= exit status, a non-zero value meaning there is an error !! !! SIDE EFFECTS !! xval= buffer array !! !! SOURCE subroutine xmpi_bcast_sp1d(xval,master,spaceComm,ier) !This section has been created automatically by the script Abilint (TD). !Do not modify the following lines by hand. #undef ABI_FUNC #define ABI_FUNC 'xmpi_bcast_sp1d' !End of the abilint section implicit none !Arguments------------------------- real(sp), DEV_CONTARRD intent(inout) :: xval(:) integer ,intent(in) :: spaceComm,master integer ,intent(out) :: ier !Local variables------------------- #if defined HAVE_MPI integer :: n #endif ! ************************************************************************* ier=0 #if defined HAVE_MPI if (spaceComm /= MPI_COMM_SELF .and. spaceComm /= MPI_COMM_NULL) then n=size(xval,dim=1) call MPI_BCAST(xval,n,MPI_REAL,master,spaceComm,ier) end if #endif end subroutine xmpi_bcast_sp1d !!*** !!****f* ABINIT/xmpi_bcast_sp2d !! NAME !! xmpi_bcast_sp2d !! !! FUNCTION !! Broadcasts data from master to slaves. !! Target: two-dimensional single precision arrays. !! !! INPUTS !! spaceComm= MPI communicator !! master= master MPI node !! !! OUTPUT !! ier= exit status, a non-zero value meaning there is an error !! !! SIDE EFFECTS !! xval= buffer array !! !! SOURCE subroutine xmpi_bcast_sp2d(xval,master,spaceComm,ier) !This section has been created automatically by the script Abilint (TD). !Do not modify the following lines by hand. #undef ABI_FUNC #define ABI_FUNC 'xmpi_bcast_sp2d' !End of the abilint section implicit none !Arguments------------------------- real(sp), DEV_CONTARRD intent(inout) :: xval(:,:) integer ,intent(in) :: spaceComm,master integer ,intent(out) :: ier !Local variables------------------- #if defined HAVE_MPI integer :: n1,n2 #endif ! ************************************************************************* ier=0 #if defined HAVE_MPI if (spaceComm /= MPI_COMM_SELF .and. spaceComm /= MPI_COMM_NULL) then n1=size(xval,dim=1) n2=size(xval,dim=2) call MPI_BCAST(xval,n1*n2,MPI_REAL,master,spaceComm,ier) end if #endif end subroutine xmpi_bcast_sp2d !!*** !!****f* ABINIT/xmpi_bcast_sp3d !! NAME !! xmpi_bcast_sp3d !! !! FUNCTION !! Broadcasts data from master to slaves. !! Target: three-dimensional single precision arrays. !! !! INPUTS !! spaceComm= MPI communicator !! master= master MPI node !! !! OUTPUT !! ier= exit status, a non-zero value meaning there is an error !! !! SIDE EFFECTS !! xval= buffer array !! !! SOURCE subroutine xmpi_bcast_sp3d(xval,master,spaceComm,ier) !This section has been created automatically by the script Abilint (TD). !Do not modify the following lines by hand. #undef ABI_FUNC #define ABI_FUNC 'xmpi_bcast_sp3d' !End of the abilint section implicit none !Arguments------------------------- real(sp), DEV_CONTARRD intent(inout) :: xval(:,:,:) integer ,intent(in) :: spaceComm,master integer ,intent(out) :: ier !Local variables------------------- #if defined HAVE_MPI integer :: n1,n2,n3 #endif ! ************************************************************************* ier=0 #if defined HAVE_MPI if (spaceComm /= MPI_COMM_SELF .and. spaceComm /= MPI_COMM_NULL) then n1=size(xval,dim=1) n2=size(xval,dim=2) n3=size(xval,dim=3) call MPI_BCAST(xval,n1*n2*n3,MPI_REAL,master,spaceComm,ier) end if #endif end subroutine xmpi_bcast_sp3d !!*** !!****f* ABINIT/xmpi_bcast_sp4d !! NAME !! xmpi_bcast_sp4d !! !! FUNCTION !! Broadcasts data from master to slaves. !! Target: four-dimensional single precision arrays. !! !! INPUTS !! spaceComm= MPI communicator !! master= master MPI node !! !! OUTPUT !! ier= exit status, a non-zero value meaning there is an error !! !! SIDE EFFECTS !! xval= buffer array !! !! SOURCE subroutine xmpi_bcast_sp4d(xval,master,spaceComm,ier) !This section has been created automatically by the script Abilint (TD). !Do not modify the following lines by hand. #undef ABI_FUNC #define ABI_FUNC 'xmpi_bcast_sp4d' !End of the abilint section implicit none !Arguments------------------------- real(sp), DEV_CONTARRD intent(inout) :: xval(:,:,:,:) integer ,intent(in) :: spaceComm,master integer ,intent(out) :: ier !Local variables------------------- #if defined HAVE_MPI integer :: n1,n2,n3,n4 #endif ! ************************************************************************* ier=0 #if defined HAVE_MPI if (spaceComm /= MPI_COMM_SELF .and. spaceComm /= MPI_COMM_NULL) then n1=size(xval,dim=1) n2=size(xval,dim=2) n3=size(xval,dim=3) n4=size(xval,dim=4) call MPI_BCAST(xval,n1*n2*n3*n4,MPI_REAL,master,spaceComm,ier) end if #endif end subroutine xmpi_bcast_sp4d !!*** !!****f* ABINIT/xmpi_bcast_cplxv !! NAME !! xmpi_bcast_cplxv !! !! FUNCTION !! Broadcasts data from master to slaves. !! Target: scalar complexs. !! !! INPUTS !! spaceComm= MPI communicator !! master= master MPI node !! !! OUTPUT !! ier= exit status, a non-zero value meaning there is an error !! !! SIDE EFFECTS !! xval= buffer array !! !! PARENTS !! !! CHILDREN !! mpi_bcast !! !! SOURCE subroutine xmpi_bcast_cplxv(xval,master,spaceComm,ier) !This section has been created automatically by the script Abilint (TD). !Do not modify the following lines by hand. #undef ABI_FUNC #define ABI_FUNC 'xmpi_bcast_cplxv' !End of the abilint section implicit none !Arguments------------------------- complex(spc),intent(inout) :: xval integer ,intent(in) :: spaceComm,master integer ,intent(out) :: ier !Local variables------------------- ! ************************************************************************* ier=0 #if defined HAVE_MPI if (spaceComm /= MPI_COMM_SELF .and. spaceComm /= MPI_COMM_NULL) then call MPI_BCAST(xval,1,MPI_COMPLEX,master,spaceComm,ier) end if #endif end subroutine xmpi_bcast_cplxv !!*** !!****f* ABINIT/xmpi_bcast_cplx1d !! NAME !! xmpi_bcast_cplx1d !! !! FUNCTION !! Broadcasts data from master to slaves. !! Target: one-dimensional complex arrays. !! !! INPUTS !! spaceComm= MPI communicator !! master= master MPI node !! !! OUTPUT !! ier= exit status, a non-zero value meaning there is an error !! !! SIDE EFFECTS !! xval= buffer array !! !! PARENTS !! !! CHILDREN !! mpi_bcast !! !! SOURCE subroutine xmpi_bcast_cplx1d(xval,master,spaceComm,ier) !This section has been created automatically by the script Abilint (TD). !Do not modify the following lines by hand. #undef ABI_FUNC #define ABI_FUNC 'xmpi_bcast_cplx1d' !End of the abilint section implicit none !Arguments------------------------- complex(spc), DEV_CONTARRD intent(inout) :: xval(:) integer ,intent(in) :: spaceComm,master integer ,intent(out) :: ier !Local variables------------------- #if defined HAVE_MPI integer :: n #endif ! ************************************************************************* ier=0 #if defined HAVE_MPI if (spaceComm /= MPI_COMM_SELF .and. spaceComm /= MPI_COMM_NULL) then n=size(xval(:)) call MPI_BCAST(xval,n,MPI_COMPLEX,master,spaceComm,ier) end if #endif end subroutine xmpi_bcast_cplx1d !!*** !!****f* ABINIT/xmpi_bcast_cplx2d !! NAME !! xmpi_bcast_cplx2d !! !! FUNCTION !! Broadcasts data from master to slaves. !! Target: two-dimensional complex arrays. !! !! INPUTS !! spaceComm= MPI communicator !! master= master MPI node !! !! OUTPUT !! ier= exit status, a non-zero value meaning there is an error !! !! SIDE EFFECTS !! xval= buffer array !! !! SOURCE subroutine xmpi_bcast_cplx2d(xval,master,spaceComm,ier) !This section has been created automatically by the script Abilint (TD). !Do not modify the following lines by hand. #undef ABI_FUNC #define ABI_FUNC 'xmpi_bcast_cplx2d' !End of the abilint section implicit none !Arguments------------------------- complex(spc), DEV_CONTARRD intent(inout) :: xval(:,:) integer ,intent(in) :: spaceComm,master integer ,intent(out) :: ier !Local variables------------------- #if defined HAVE_MPI integer :: n1,n2 #endif ! ************************************************************************* ier=0 #if defined HAVE_MPI if (spaceComm /= MPI_COMM_SELF .and. spaceComm /= MPI_COMM_NULL) then n1=size(xval,dim=1) n2=size(xval,dim=2) call MPI_BCAST(xval,n1*n2,MPI_COMPLEX,master,spaceComm,ier) end if #endif end subroutine xmpi_bcast_cplx2d !!*** !!****f* ABINIT/xmpi_bcast_cplx3d !! NAME !! xmpi_bcast_cplx3d !! !! FUNCTION !! Broadcasts data from master to slaves. !! Target: three-dimensional complex arrays. !! !! INPUTS !! spaceComm= MPI communicator !! master= master MPI node !! !! OUTPUT !! ier= exit status, a non-zero value meaning there is an error !! !! SIDE EFFECTS !! xval= buffer array !! !! SOURCE subroutine xmpi_bcast_cplx3d(xval,master,spaceComm,ier) !This section has been created automatically by the script Abilint (TD). !Do not modify the following lines by hand. #undef ABI_FUNC #define ABI_FUNC 'xmpi_bcast_cplx3d' !End of the abilint section implicit none !Arguments------------------------- complex(spc), DEV_CONTARRD intent(inout) :: xval(:,:,:) integer ,intent(in) :: spaceComm,master integer ,intent(out) :: ier !Local variables------------------- #if defined HAVE_MPI integer :: n1,n2,n3 #endif ! ************************************************************************* ier=0 #if defined HAVE_MPI if (spaceComm /= MPI_COMM_SELF .and. spaceComm /= MPI_COMM_NULL) then n1=size(xval,dim=1) n2=size(xval,dim=2) n3=size(xval,dim=3) call MPI_BCAST(xval,n1*n2*n3,MPI_COMPLEX,master,spaceComm,ier) end if #endif end subroutine xmpi_bcast_cplx3d !!*** !!****f* ABINIT/xmpi_bcast_cplx4d !! NAME !! xmpi_bcast_cplx4d !! !! FUNCTION !! Broadcasts data from master to slaves. !! Target: four-dimensional complex arrays. !! !! INPUTS !! spaceComm= MPI communicator !! master= master MPI node !! !! OUTPUT !! ier= exit status, a non-zero value meaning there is an error !! !! SIDE EFFECTS !! xval= buffer array !! !! SOURCE subroutine xmpi_bcast_cplx4d(xval,master,spaceComm,ier) !This section has been created automatically by the script Abilint (TD). !Do not modify the following lines by hand. #undef ABI_FUNC #define ABI_FUNC 'xmpi_bcast_cplx4d' !End of the abilint section implicit none !Arguments------------------------- complex(spc), DEV_CONTARRD intent(inout) :: xval(:,:,:,:) integer ,intent(in) :: spaceComm,master integer ,intent(out) :: ier !Local variables------------------- #if defined HAVE_MPI integer :: n1,n2,n3,n4 #endif ! ************************************************************************* ier=0 #if defined HAVE_MPI if (spaceComm /= MPI_COMM_SELF .and. spaceComm /= MPI_COMM_NULL) then n1=size(xval,dim=1) n2=size(xval,dim=2) n3=size(xval,dim=3) n4=size(xval,dim=4) call MPI_BCAST(xval,n1*n2*n3*n4,MPI_COMPLEX,master,spaceComm,ier) end if #endif end subroutine xmpi_bcast_cplx4d !!*** !!****f* ABINIT/xmpi_bcast_dcv !! NAME !! xmpi_bcast_dcv !! !! FUNCTION !! Broadcasts data from master to slaves. !! Target: scalar double complexs. !! !! INPUTS !! spaceComm= MPI communicator !! master= master MPI node !! !! OUTPUT !! ier= exit status, a non-zero value meaning there is an error !! !! SIDE EFFECTS !! xval= buffer array !! !! SOURCE subroutine xmpi_bcast_dcv(xval,master,spaceComm,ier) !This section has been created automatically by the script Abilint (TD). !Do not modify the following lines by hand. #undef ABI_FUNC #define ABI_FUNC 'xmpi_bcast_dcv' !End of the abilint section implicit none !Arguments------------------------- complex(dpc),intent(inout):: xval integer ,intent(in) :: spaceComm,master integer ,intent(out) :: ier ! ************************************************************************* ier=0 #if defined HAVE_MPI if (spaceComm /= MPI_COMM_SELF .and. spaceComm /= MPI_COMM_NULL) then call MPI_BCAST(xval,1,MPI_DOUBLE_COMPLEX,master,spaceComm,ier) end if #endif end subroutine xmpi_bcast_dcv !!*** !!****f* ABINIT/xmpi_bcast_dc1d !! NAME !! xmpi_bcast_dc1d !! !! FUNCTION !! Broadcasts data from master to slaves. !! Target: one-dimensional double complex arrays. !! !! INPUTS !! spaceComm= MPI communicator !! master= master MPI node !! !! OUTPUT !! ier= exit status, a non-zero value meaning there is an error !! !! SIDE EFFECTS !! xval= buffer array !! !! SOURCE subroutine xmpi_bcast_dc1d(xval,master,spaceComm,ier) !This section has been created automatically by the script Abilint (TD). !Do not modify the following lines by hand. #undef ABI_FUNC #define ABI_FUNC 'xmpi_bcast_dc1d' !End of the abilint section implicit none !Arguments------------------------- complex(dpc), DEV_CONTARRD intent(inout):: xval(:) integer ,intent(in) :: spaceComm,master integer ,intent(out) :: ier !Local variables------------------- #if defined HAVE_MPI integer :: n #endif ! ************************************************************************* ier=0 #if defined HAVE_MPI if (spaceComm /= MPI_COMM_SELF .and. spaceComm /= MPI_COMM_NULL) then n=size(xval(:)) call MPI_BCAST(xval,n,MPI_DOUBLE_COMPLEX,master,spaceComm,ier) end if #endif end subroutine xmpi_bcast_dc1d !!*** !!****f* ABINIT/xmpi_bcast_dc2d !! NAME !! xmpi_bcast_dc2d !! !! FUNCTION !! Broadcasts data from master to slaves. !! Target: two-dimensional double complex arrays. !! !! INPUTS !! spaceComm= MPI communicator !! master= master MPI node !! !! OUTPUT !! ier= exit status, a non-zero value meaning there is an error !! !! SIDE EFFECTS !! xval= buffer array !! !! !! SOURCE subroutine xmpi_bcast_dc2d(xval,master,spaceComm,ier) !This section has been created automatically by the script Abilint (TD). !Do not modify the following lines by hand. #undef ABI_FUNC #define ABI_FUNC 'xmpi_bcast_dc2d' !End of the abilint section implicit none !Arguments------------------------- complex(dpc), DEV_CONTARRD intent(inout):: xval(:,:) integer ,intent(in) :: spaceComm,master integer ,intent(out) :: ier !Local variables------------------- #if defined HAVE_MPI integer :: n1,n2 #endif ! ************************************************************************* ier=0 #if defined HAVE_MPI if (spaceComm /= MPI_COMM_SELF .and. spaceComm /= MPI_COMM_NULL) then n1=size(xval,dim=1) n2=size(xval,dim=2) call MPI_BCAST(xval,n1*n2,MPI_DOUBLE_COMPLEX,master,spaceComm,ier) end if #endif end subroutine xmpi_bcast_dc2d !!*** !!****f* ABINIT/xmpi_bcast_dc3d !! NAME !! xmpi_bcast_dc3d !! !! FUNCTION !! Broadcasts data from master to slaves. !! Target: three-dimensional double complex arrays. !! !! INPUTS !! spaceComm= MPI communicator !! master= master MPI node !! !! OUTPUT !! ier= exit status, a non-zero value meaning there is an error !! !! SIDE EFFECTS !! xval= buffer array !! !! SOURCE subroutine xmpi_bcast_dc3d(xval,master,spaceComm,ier) !This section has been created automatically by the script Abilint (TD). !Do not modify the following lines by hand. #undef ABI_FUNC #define ABI_FUNC 'xmpi_bcast_dc3d' !End of the abilint section implicit none !Arguments------------------------- complex(dpc), DEV_CONTARRD intent(inout):: xval(:,:,:) integer ,intent(in) :: spaceComm,master integer ,intent(out) :: ier !Local variables------------------- #if defined HAVE_MPI integer :: n1,n2,n3 #endif ! ************************************************************************* ier=0 #if defined HAVE_MPI if (spaceComm /= MPI_COMM_SELF .and. spaceComm /= MPI_COMM_NULL) then n1=size(xval,dim=1) n2=size(xval,dim=2) n3=size(xval,dim=3) call MPI_BCAST(xval,n1*n2*n3,MPI_DOUBLE_COMPLEX,master,spaceComm,ier) end if #endif end subroutine xmpi_bcast_dc3d !!*** !!****f* ABINIT/xmpi_bcast_dc4d !! NAME !! xmpi_bcast_dc4d !! !! FUNCTION !! Broadcasts data from master to slaves. !! Target: four-dimensional complex arrays in double precision. !! !! INPUTS !! spaceComm= MPI communicator !! master= master MPI node !! !! OUTPUT !! ier= exit status, a non-zero value meaning there is an error !! !! SIDE EFFECTS !! xval= buffer array !! !! SOURCE subroutine xmpi_bcast_dc4d(xval,master,spaceComm,ier) !This section has been created automatically by the script Abilint (TD). !Do not modify the following lines by hand. #undef ABI_FUNC #define ABI_FUNC 'xmpi_bcast_dc4d' !End of the abilint section implicit none !Arguments------------------------- complex(dpc), DEV_CONTARRD intent(inout) :: xval(:,:,:,:) integer,intent(in) :: spaceComm,master integer,intent(out) :: ier !Local variables------------------- #if defined HAVE_MPI integer :: n1,n2,n3,n4 #endif ! ************************************************************************* ier=0 #if defined HAVE_MPI if (spaceComm /= MPI_COMM_SELF .and. spaceComm /= MPI_COMM_NULL) then n1=size(xval,dim=1) n2=size(xval,dim=2) n3=size(xval,dim=3) n4=size(xval,dim=4) call MPI_BCAST(xval,n1*n2*n3*n4,MPI_DOUBLE_COMPLEX,master,spaceComm,ier) end if #endif end subroutine xmpi_bcast_dc4d !!*** !!****f* ABINIT/xmpi_bcast_ch0d !! NAME !! xmpi_bcast_ch0d !! !! FUNCTION !! Broadcasts data from master to slaves. !! Target: character strings. !! !! INPUTS !! spaceComm= MPI communicator !! master= master MPI node !! !! OUTPUT !! ier= exit status, a non-zero value meaning there is an error !! !! SIDE EFFECTS !! xval= buffer array !! !! SOURCE subroutine xmpi_bcast_ch0d(xval,master,spaceComm,ier) !This section has been created automatically by the script Abilint (TD). !Do not modify the following lines by hand. #undef ABI_FUNC #define ABI_FUNC 'xmpi_bcast_ch0d' !End of the abilint section implicit none !Arguments------------------------- character(len=*),intent(inout) :: xval integer,intent(in) :: spaceComm,master integer,intent(out) :: ier !Local variables------------------------------- #if defined HAVE_MPI integer :: nch,rank #endif !************************************************************************* ier=0 #if defined HAVE_MPI if (spaceComm /= MPI_COMM_SELF .and. spaceComm /= MPI_COMM_NULL) then call MPI_COMM_RANK(spaceComm,rank,ier) if (rank==master) nch=len_trim(xval) call MPI_BCAST(nch,1,MPI_INTEGER,master,spaceComm,ier) call MPI_BCAST(xval,nch,MPI_CHARACTER,master,spaceComm,ier) if (rank/=master) xval(nch+1:)='' end if #endif end subroutine xmpi_bcast_ch0d !!*** !!****f* ABINIT/xmpi_bcast_ch1d !! NAME !! xmpi_bcast_ch1d !! !! FUNCTION !! Broadcasts data from master to slaves. !! Target: one-dimensional array of character stringss. !! !! INPUTS !! spaceComm= MPI communicator !! master= master MPI node !! !! OUTPUT !! ier= exit status, a non-zero value meaning there is an error !! !! SIDE EFFECTS !! xval= buffer array !! !! SOURCE subroutine xmpi_bcast_ch1d(xval,master,spaceComm,ier) !This section has been created automatically by the script Abilint (TD). !Do not modify the following lines by hand. #undef ABI_FUNC #define ABI_FUNC 'xmpi_bcast_ch1d' !End of the abilint section implicit none !Arguments------------------------- Character(len=*), DEV_CONTARRD intent(inout) :: xval(:) integer,intent(in) :: spaceComm,master integer,intent(out) :: ier !Local variables------------------------------- #if defined HAVE_MPI integer :: ii,nch #endif !************************************************************************* ier=0 #if defined HAVE_MPI if (spaceComm /= MPI_COMM_SELF .and. spaceComm /= MPI_COMM_NULL) then nch=0 do ii=1,size(xval) nch=nch+len(xval(ii)) end do call MPI_BCAST(xval,nch,MPI_CHARACTER,master,spaceComm,ier) end if #endif end subroutine xmpi_bcast_ch1d !!*** !!****f* ABINIT/xmpi_bcast_log0d !! NAME !! xmpi_bcast_log0d !! !! FUNCTION !! Broadcasts data from master to slaves. !! Target: logical scalar !! !! INPUTS !! spaceComm= MPI communicator !! master= master MPI node !! !! OUTPUT !! ier= exit status, a non-zero value meaning there is an error !! !! SOURCE subroutine xmpi_bcast_log0d(xval,master,spaceComm,ier) !This section has been created automatically by the script Abilint (TD). !Do not modify the following lines by hand. #undef ABI_FUNC #define ABI_FUNC 'xmpi_bcast_log0d' !End of the abilint section implicit none !Arguments------------------------- logical,intent(inout) :: xval integer,intent(in) :: spaceComm,master integer,intent(out) :: ier ! ************************************************************************* ier=0 #if defined HAVE_MPI if (spaceComm /= MPI_COMM_SELF .and. spaceComm /= MPI_COMM_NULL) then call MPI_BCAST(xval,1,MPI_LOGICAL,master,spaceComm,ier) end if #endif end subroutine xmpi_bcast_log0d !!*** !!****f* ABINIT/xmpi_bcast_coeffi2_1d !! NAME !! xmpi_bcast_coeffi2_1d !! !! FUNCTION !! Broadcasts data from master to slaves. !! Target: type(coeffi2) 1D-arrays. !! !! INPUTS !! spaceComm= MPI communicator !! master= master MPI node !! !! OUTPUT !! ier= exit status, a non-zero value meaning there is an error !! !! SIDE EFFECTS !! xval= buffer array !! !! SOURCE subroutine xmpi_bcast_coeffi2_1d(xval,master,spaceComm,ier) !This section has been created automatically by the script Abilint (TD). !Do not modify the following lines by hand. #undef ABI_FUNC #define ABI_FUNC 'xmpi_bcast_coeffi2_1d' !End of the abilint section implicit none !Arguments------------------------- type(coeffi2_type), intent(inout) :: xval(:) integer ,intent(in) :: spaceComm,master integer ,intent(out) :: ier !Local variables------------------- #if defined HAVE_MPI integer :: ii,jj,kk,me,n0,n1,n2,siztot integer,allocatable :: mpibuf(:),siz(:,:) #endif ! ************************************************************************* ier=0 #if defined HAVE_MPI if (spaceComm /= MPI_COMM_SELF .and. spaceComm /= MPI_COMM_NULL) then me=xmpi_comm_rank(spaceComm) ! Broadcast xval%value sizes n0=size(xval) ABI_STAT_ALLOCATE(siz,(2,n0), ier) if (ier/= 0) call xmpi_abort(msg='error allocating siz in xmpi_bcast') if (me==master) then do ii=1,n0 siz(1,ii)=size(xval(ii)%value,1) siz(2,ii)=size(xval(ii)%value,2) end do end if call MPI_BCAST(siz,2*n0,MPI_INTEGER,master,spaceComm,ier) siztot=0 do ii=1,n0 siztot=siztot+siz(1,ii)*siz(2,ii) end do ! Fill in the buffer ABI_STAT_ALLOCATE(mpibuf,(siztot), ier) if (ier/= 0) call xmpi_abort(msg='error allocating mpibuf in xmpi_bcast') if (me==master) then jj=0 do ii=1,n0 n1=siz(1,ii);n2=siz(2,ii) do kk=1,n2 mpibuf(jj+1:jj+n1)=xval(ii)%value(1:n1,kk) jj=jj+n1 end do end do end if ! Broadcast the data call MPI_BCAST(mpibuf,siztot,MPI_INTEGER,master,spaceComm,ier) ! Retrieve the buffer jj=0 do ii=1,n0 n1=siz(1,ii);n2=siz(2,ii) if (.not.allocated(xval(ii)%value)) then ABI_STAT_ALLOCATE(xval(ii)%value,(n1,n2), ier) if (ier/= 0) call xmpi_abort(msg='error allocating xval%value in xmpi_bcast') end if do kk=1,n2 xval(ii)%value(1:n1,kk)=mpibuf(jj+1:jj+n1) jj=jj+n1 end do end do ABI_DEALLOCATE(siz) ABI_DEALLOCATE(mpibuf) end if #endif end subroutine xmpi_bcast_coeffi2_1d !!*** !!****f* ABINIT/xmpi_bcast_coeff2_1d !! NAME !! xmpi_bcast_coeff2_1d !! !! FUNCTION !! Broadcasts data from master to slaves. !! Target: type(coeff2) 1D-arrays. !! !! INPUTS !! spaceComm= MPI communicator !! master= master MPI node !! !! OUTPUT !! ier= exit status, a non-zero value meaning there is an error !! !! SIDE EFFECTS !! xval= buffer array !! !! SOURCE subroutine xmpi_bcast_coeff2_1d(xval,master,spaceComm,ier) !This section has been created automatically by the script Abilint (TD). !Do not modify the following lines by hand. #undef ABI_FUNC #define ABI_FUNC 'xmpi_bcast_coeff2_1d' !End of the abilint section implicit none !Arguments------------------------- type(coeff2_type), intent(inout) :: xval(:) integer ,intent(in) :: spaceComm,master integer ,intent(out) :: ier !Local variables------------------- #if defined HAVE_MPI integer :: ii,jj,kk,me,n0,n1,n2,siztot integer,allocatable :: siz(:,:) real(dp),allocatable :: mpibuf(:) #endif ! ************************************************************************* ier=0 #if defined HAVE_MPI if (spaceComm /= MPI_COMM_SELF .and. spaceComm /= MPI_COMM_NULL) then me=xmpi_comm_rank(spaceComm) ! Broadcast xval%value sizes n0=size(xval) ABI_STAT_ALLOCATE(siz,(2,n0), ier) if (ier/= 0) call xmpi_abort(msg='error allocating siz in xmpi_bcast') if (me==master) then do ii=1,n0 siz(1,ii)=size(xval(ii)%value,1) siz(2,ii)=size(xval(ii)%value,2) end do end if call MPI_BCAST(siz,2*n0,MPI_INTEGER,master,spaceComm,ier) siztot=0 do ii=1,n0 siztot=siztot+siz(1,ii)*siz(2,ii) end do ! Fill in the buffer ABI_STAT_ALLOCATE(mpibuf,(siztot), ier) if (ier/= 0) call xmpi_abort(msg='error allocating mpibuf in xmpi_bcast') if (me==master) then jj=0 do ii=1,n0 n1=siz(1,ii);n2=siz(2,ii) do kk=1,n2 mpibuf(jj+1:jj+n1)=xval(ii)%value(1:n1,kk) jj=jj+n1 end do end do end if ! Broadcast the data call MPI_BCAST(mpibuf,siztot,MPI_DOUBLE_PRECISION,master,spaceComm,ier) ! Retrieve the buffer jj=0 do ii=1,n0 n1=siz(1,ii);n2=siz(2,ii) if (.not.allocated(xval(ii)%value)) then ABI_STAT_ALLOCATE(xval(ii)%value,(n1,n2), ier) if (ier/= 0) call xmpi_abort(msg='error allocating xval%value in xmpi_bcast') end if do kk=1,n2 xval(ii)%value(1:n1,kk)=mpibuf(jj+1:jj+n1) jj=jj+n1 end do end do ABI_DEALLOCATE(siz) ABI_DEALLOCATE(mpibuf) end if #endif end subroutine xmpi_bcast_coeff2_1d !!*** v_sim-3.8.0/lib/plug-ins/abinit/xmpi_exch.finc000066400000000000000000000403501370110300500212260ustar00rootroot00000000000000!{\src2tex{textfont=tt}} !!****f* ABINIT/xmpi_exch_intn !! NAME !! xmpi_exch_intn !! !! FUNCTION !! This module contains functions that calls MPI routine, !! if we compile the code using the MPI CPP flags. !! xmpi_exch is the generic function. !! Note that there exist two versions of the xmpi_exch, !! irrespective of the kind of data that is exchanged : in a first version, !! one suppose that there will be no confusion between different messages exchanged !! between a pair (sender,receiver), so that no message tag is to be specified !! (one tag will be automatically generated), while in the second version (safer !), !! a tag is specified. !! !! COPYRIGHT !! Copyright (C) 2001-2016 ABINIT group (MB) !! This file is distributed under the terms of the !! GNU General Public License, see ~ABINIT/COPYING !! or http://www.gnu.org/copyleft/gpl.txt . !! !! NOTE !! In the version with a tag automatically generated, the tag conforms !! to the MPI request that the tag is lower than 32768, by using a modulo call. !! !! SOURCE !-------------------------------------------------------------------- subroutine xmpi_exch_intn(vsend,n1,sender,vrecv,recever,spaceComm,ier) !This section has been created automatically by the script Abilint (TD). !Do not modify the following lines by hand. #undef ABI_FUNC #define ABI_FUNC 'xmpi_exch_intn' !End of the abilint section implicit none !Arguments---------------- integer,intent(in) :: n1 integer, DEV_CONTARRD intent(in) :: vsend(:) integer, DEV_CONTARRD intent(inout) :: vrecv(:) integer,intent(in) :: sender,recever,spaceComm integer,intent(out) :: ier !Local variables-------------- #if defined HAVE_MPI integer :: statux(MPI_STATUS_SIZE) integer :: tag,me #endif ! ************************************************************************* ier=0 #if defined HAVE_MPI if (sender==recever.or.spaceComm==MPI_COMM_NULL.or.(n1==0)) return call MPI_COMM_RANK(spaceComm,me,ier) tag = MOD(n1,xmpi_tag_ub) if (recever==me) then call MPI_RECV(vrecv,n1,MPI_INTEGER,sender,tag,spaceComm,statux,ier) end if if (sender==me) then call MPI_SEND(vsend,n1,MPI_INTEGER,recever,tag,spaceComm,ier) end if #endif end subroutine xmpi_exch_intn !!*** !-------------------------------------------------------------------- !!****f* ABINIT/xmpi_exch_int2d !! NAME !! xmpi_exch_int2d !! !! FUNCTION !! Sends and receives data. !! Target: two-dimensional integer arrays. !! !! INPUTS !! nt= vector length !! vsend= send buffer !! sender= node sending the data !! recever= node receiving the data !! spaceComm= MPI communicator !! !! OUTPUT !! ier= exit status, a non-zero value meaning there is an error !! !! SIDE EFFECTS !! vrecv= receive buffer !! !! SOURCE subroutine xmpi_exch_int2d(vsend,nt,sender,vrecv,recever,spaceComm,ier) !This section has been created automatically by the script Abilint (TD). !Do not modify the following lines by hand. #undef ABI_FUNC #define ABI_FUNC 'xmpi_exch_int2d' !End of the abilint section implicit none !Arguments---------------- integer,intent(in) :: nt integer, DEV_CONTARRD intent(in) :: vsend(:,:) integer, DEV_CONTARRD intent(inout) :: vrecv(:,:) integer,intent(in) :: sender,recever,spaceComm integer,intent(out) :: ier !Local variables-------------- #if defined HAVE_MPI integer :: statux(MPI_STATUS_SIZE) integer :: tag,me #endif ! ************************************************************************* ier=0 #if defined HAVE_MPI if (sender==recever.or.spaceComm==MPI_COMM_NULL.or.(nt==0)) return call MPI_COMM_RANK(spaceComm,me,ier) tag = MOD(nt, xmpi_tag_ub) if (recever==me) then call MPI_RECV(vrecv,nt,MPI_INTEGER,sender,tag,spaceComm,statux,ier) end if if (sender==me) then call MPI_SEND(vsend,nt,MPI_INTEGER,recever,tag,spaceComm,ier) end if #endif end subroutine xmpi_exch_int2d !!*** !-------------------------------------------------------------------- !!****f* ABINIT/xmpi_exch_dpn !! NAME !! xmpi_exch_dpn !! !! FUNCTION !! Sends and receives data. !! Target: one-dimensional double precision arrays. !! !! INPUTS !! n1= first dimension of the array !! vsend= send buffer !! sender= node sending the data !! recever= node receiving the data !! spaceComm= MPI communicator !! !! OUTPUT !! ier= exit status, a non-zero value meaning there is an error !! !! SIDE EFFECTS !! vrecv= receive buffer !! !! SOURCE subroutine xmpi_exch_dpn(vsend,n1,sender,vrecv,recever,spaceComm,ier) !This section has been created automatically by the script Abilint (TD). !Do not modify the following lines by hand. #undef ABI_FUNC #define ABI_FUNC 'xmpi_exch_dpn' !End of the abilint section implicit none !Arguments---------------- integer,intent(in) :: n1 real(dp), DEV_CONTARRD intent(in) :: vsend(:) real(dp), DEV_CONTARRD intent(inout) :: vrecv(:) integer,intent(in) :: sender,recever,spaceComm integer,intent(out) :: ier !Local variables-------------- #if defined HAVE_MPI integer :: statux(MPI_STATUS_SIZE) integer :: tag,me #endif ! ************************************************************************* ier=0 #if defined HAVE_MPI if (sender==recever.or.spaceComm==MPI_COMM_NULL.or.(n1==0)) return call MPI_COMM_RANK(spaceComm,me,ier) tag = MOD(n1, xmpi_tag_ub) if (recever==me) then call MPI_RECV(vrecv,n1,MPI_DOUBLE_PRECISION,sender,tag,spaceComm,statux,ier) end if if (sender==me) then call MPI_SEND(vsend,n1,MPI_DOUBLE_PRECISION,recever,tag,spaceComm,ier) end if #endif end subroutine xmpi_exch_dpn !!*** !-------------------------------------------------------------------- !!****f* ABINIT/xmpi_exch_dp2d !! NAME !! xmpi_exch_dp2d !! !! FUNCTION !! Sends and receives data. !! Target: double precision two-dimensional arrays. !! !! INPUTS !! nt= vector length !! vsend= send buffer !! sender= node sending the data !! recever= node receiving the data !! spaceComm= MPI communicator !! !! OUTPUT !! ier= exit status, a non-zero value meaning there is an error !! !! SIDE EFFECTS !! vrecv= receive buffer !! !! SOURCE subroutine xmpi_exch_dp2d(vsend,nt,sender,vrecv,recever,spaceComm,ier) !This section has been created automatically by the script Abilint (TD). !Do not modify the following lines by hand. #undef ABI_FUNC #define ABI_FUNC 'xmpi_exch_dp2d' !End of the abilint section implicit none !Arguments---------------- integer,intent(in) :: nt real(dp), DEV_CONTARRD intent(in) :: vsend(:,:) real(dp), DEV_CONTARRD intent(inout) :: vrecv(:,:) integer,intent(in) :: sender,recever,spaceComm integer,intent(out) :: ier !Local variables-------------- #if defined HAVE_MPI integer :: statux(MPI_STATUS_SIZE) integer :: tag,me #endif ! ************************************************************************* ier=0 #if defined HAVE_MPI if (sender==recever.or.spaceComm==MPI_COMM_NULL.or.(nt==0)) return call MPI_COMM_RANK(spaceComm,me,ier) tag=MOD(nt, xmpi_tag_ub) if (recever==me) then call MPI_RECV(vrecv,nt,MPI_DOUBLE_PRECISION,sender,tag,spaceComm,statux,ier) end if if (sender==me) then call MPI_SEND(vsend,nt,MPI_DOUBLE_PRECISION,recever,tag,spaceComm,ier) end if #endif end subroutine xmpi_exch_dp2d !!*** !-------------------------------------------------------------------- !!****f* ABINIT/xmpi_exch_dp3d !! NAME !! xmpi_exch_dp3d !! !! FUNCTION !! Sends and receives data. !! Target: double precision three-dimensional arrays. !! !! INPUTS !! nt= vector length !! vsend= send buffer !! sender= node sending the data !! recever= node receiving the data !! spaceComm= MPI communicator !! !! OUTPUT !! ier= exit status, a non-zero value meaning there is an error !! !! SIDE EFFECTS !! vrecv= receive buffer !! !! SOURCE subroutine xmpi_exch_dp3d(vsend,nt,sender,vrecv,recever,spaceComm,ier) !This section has been created automatically by the script Abilint (TD). !Do not modify the following lines by hand. #undef ABI_FUNC #define ABI_FUNC 'xmpi_exch_dp3d' !End of the abilint section implicit none !Arguments---------------- integer,intent(in) :: nt real(dp), DEV_CONTARRD intent(in) :: vsend(:,:,:) real(dp), DEV_CONTARRD intent(inout) :: vrecv(:,:,:) integer,intent(in) :: sender,recever,spaceComm integer,intent(out) :: ier !Local variables-------------- #if defined HAVE_MPI integer :: statux(MPI_STATUS_SIZE) integer :: tag,me #endif ! ************************************************************************* ier=0 #if defined HAVE_MPI if (sender==recever.or.spaceComm==MPI_COMM_NULL.or.(nt==0)) return call MPI_COMM_RANK(spaceComm,me,ier) tag=MOD(nt, xmpi_tag_ub) if (recever==me) then call MPI_RECV(vrecv,nt,MPI_DOUBLE_PRECISION,sender,tag,spaceComm,statux,ier) end if if (sender==me) then call MPI_SEND(vsend,nt,MPI_DOUBLE_PRECISION,recever,tag,spaceComm,ier) end if #endif end subroutine xmpi_exch_dp3d !!*** !-------------------------------------------------------------------- !!****f* ABINIT/xmpi_exch_dp4d_tag !! NAME !! xmpi_exch_dp4d_tag !! !! FUNCTION !! Sends and receives data. !! Target: double precision four-dimensional arrays. !! !! INPUTS !! mtag= message tag !! vsend= send buffer !! sender= node sending the data !! recever= node receiving the data !! spaceComm= MPI communicator !! !! OUTPUT !! ier= exit status, a non-zero value meaning there is an error !! !! SIDE EFFECTS !! vrecv= receive buffer !! !! SOURCE subroutine xmpi_exch_dp4d_tag(vsend,mtag,sender,vrecv,recever,spaceComm,ier) !This section has been created automatically by the script Abilint (TD). !Do not modify the following lines by hand. #undef ABI_FUNC #define ABI_FUNC 'xmpi_exch_dp4d_tag' !End of the abilint section implicit none !Arguments---------------- integer,intent(in) :: mtag real(dp), DEV_CONTARRD intent(in) :: vsend(:,:,:,:) real(dp), DEV_CONTARRD intent(inout) :: vrecv(:,:,:,:) integer,intent(in) :: sender,recever,spaceComm integer,intent(out) :: ier !Local variables-------------- #if defined HAVE_MPI integer :: statux(MPI_STATUS_SIZE) integer :: me,n1,n2,n3,n4,tag #endif ! ************************************************************************* ier=0 #if defined HAVE_MPI if (sender==recever.or.spaceComm==MPI_COMM_NULL) return call MPI_COMM_RANK(spaceComm,me,ier) n1 =size(vsend,dim=1) n2 =size(vsend,dim=2) n3 =size(vsend,dim=3) n4 =size(vsend,dim=4) tag = MOD(mtag, xmpi_tag_ub) if (recever==me) then call MPI_RECV(vrecv,n1*n2*n3*n4,MPI_DOUBLE_PRECISION,sender,tag,spaceComm,statux,ier) end if if (sender==me) then call MPI_SEND(vsend,n1*n2*n3*n4,MPI_DOUBLE_PRECISION,recever,tag,spaceComm,ier) end if #endif end subroutine xmpi_exch_dp4d_tag !!*** !-------------------------------------------------------------------- !!****f* ABINIT/xmpi_exch_dp5d_tag !! NAME !! xmpi_exch_dp5d_tag !! !! FUNCTION !! Sends and receives data. !! Target: double precision five-dimensional arrays. !! !! INPUTS !! mtag= message tag !! vsend= send buffer !! sender= node sending the data !! recever= node receiving the data !! spaceComm= MPI communicator !! !! OUTPUT !! ier= exit status, a non-zero value meaning there is an error !! !! SIDE EFFECTS !! vrecv= receive buffer !! !! SOURCE subroutine xmpi_exch_dp5d_tag(vsend,mtag,sender,vrecv,recever,spaceComm,ier) !This section has been created automatically by the script Abilint (TD). !Do not modify the following lines by hand. #undef ABI_FUNC #define ABI_FUNC 'xmpi_exch_dp5d_tag' !End of the abilint section implicit none !Arguments---------------- integer,intent(in) ::mtag real(dp), DEV_CONTARRD intent(in) :: vsend(:,:,:,:,:) real(dp), DEV_CONTARRD intent(inout) :: vrecv(:,:,:,:,:) integer,intent(in) :: sender,recever,spaceComm integer,intent(out) :: ier !Local variables-------------- #if defined HAVE_MPI integer :: me,n1,n2,n3,n4,n5,tag integer :: statux(MPI_STATUS_SIZE) #endif ! ************************************************************************* ier=0 #if defined HAVE_MPI if (sender==recever.or.spaceComm==MPI_COMM_NULL) return call MPI_COMM_RANK(spaceComm,me,ier) n1 =size(vsend,dim=1) n2 =size(vsend,dim=2) n3 =size(vsend,dim=3) n4 =size(vsend,dim=4) n5 =size(vsend,dim=5) tag = MOD(mtag,xmpi_tag_ub) if (recever==me) then call MPI_RECV(vrecv,n1*n2*n3*n4*n5,MPI_DOUBLE_PRECISION,sender,tag,spaceComm,statux,ier) end if if (sender==me) then call MPI_SEND(vsend,n1*n2*n3*n4*n5,MPI_DOUBLE_PRECISION,recever,tag,spaceComm,ier) end if #endif end subroutine xmpi_exch_dp5d_tag !!*** !-------------------------------------------------------------------- !!****f* ABINIT/xmpi_exch_spc_1d !! NAME !! xmpi_exch_spc_1d !! !! FUNCTION !! Sends and receives data. !! Target: one-dimensional single precision complex arrays. !! !! SOURCE subroutine xmpi_exch_spc_1d(vsend,n1,sender,vrecv,recever,spaceComm,ier) !This section has been created automatically by the script Abilint (TD). !Do not modify the following lines by hand. #undef ABI_FUNC #define ABI_FUNC 'xmpi_exch_spc_1d' !End of the abilint section implicit none !Arguments---------------- integer,intent(in) :: n1 complex(spc), DEV_CONTARRD intent(in) :: vsend(:) complex(spc), DEV_CONTARRD intent(inout) :: vrecv(:) integer,intent(in) :: sender,recever,spaceComm integer,intent(out) :: ier !Local variables-------------- #if defined HAVE_MPI integer :: statux(MPI_STATUS_SIZE) integer :: tag,me #endif ! ************************************************************************* ier=0 #if defined HAVE_MPI if (sender==recever.or.spaceComm==MPI_COMM_NULL.or.(n1==0)) return call MPI_COMM_RANK(spaceComm,me,ier) tag= MOD(n1, xmpi_tag_ub) if (recever==me) then call MPI_RECV(vrecv,n1,MPI_COMPLEX,sender, tag,spaceComm,statux,ier) end if if (sender==me) then call MPI_SEND(vsend,n1,MPI_COMPLEX,recever,tag,spaceComm,ier) end if #endif end subroutine xmpi_exch_spc_1d !!*** !-------------------------------------------------------------------- !!****f* ABINIT/xmpi_exch_dpc_1d !! NAME !! xmpi_exch_dpc_1d !! !! FUNCTION !! Sends and receives data. !! Target: one-dimensional double precision complex arrays. !! !! SOURCE subroutine xmpi_exch_dpc_1d(vsend,n1,sender,vrecv,recever,spaceComm,ier) !This section has been created automatically by the script Abilint (TD). !Do not modify the following lines by hand. #undef ABI_FUNC #define ABI_FUNC 'xmpi_exch_dpc_1d' !End of the abilint section implicit none !Arguments---------------- integer,intent(in) :: n1 complex(dpc), DEV_CONTARRD intent(in) :: vsend(:) complex(dpc), DEV_CONTARRD intent(inout) :: vrecv(:) integer,intent(in) :: sender,recever,spaceComm integer,intent(out) :: ier !Local variables-------------- #if defined HAVE_MPI integer :: statux(MPI_STATUS_SIZE) integer :: tag,me #endif ! ************************************************************************* ier=0 #if defined HAVE_MPI if (sender==recever.or.spaceComm==MPI_COMM_NULL.or.(n1==0)) return call MPI_COMM_RANK(spaceComm,me,ier) tag = MOD(n1, xmpi_tag_ub) if (recever==me) then call MPI_RECV(vrecv,n1,MPI_DOUBLE_COMPLEX,sender, tag,spaceComm,statux,ier) end if if (sender==me) then call MPI_SEND(vsend,n1,MPI_DOUBLE_COMPLEX,recever,tag,spaceComm,ier) end if #endif end subroutine xmpi_exch_dpc_1d !!*** !-------------------------------------------------------------------- !!****f* ABINIT/xmpi_exch_dpc_2d !! NAME !! xmpi_exch_dpc_2d !! !! FUNCTION !! Sends and receives data. !! Target: two-dimensional double precision complex arrays. !! !! SOURCE subroutine xmpi_exch_dpc_2d(vsend,nt,sender,vrecv,recever,spaceComm,ier) !This section has been created automatically by the script Abilint (TD). !Do not modify the following lines by hand. #undef ABI_FUNC #define ABI_FUNC 'xmpi_exch_dpc_2d' !End of the abilint section implicit none !Arguments---------------- integer,intent(in) :: nt complex(dpc), DEV_CONTARRD intent(in) :: vsend(:,:) complex(dpc), DEV_CONTARRD intent(inout) :: vrecv(:,:) integer,intent(in) :: sender,recever,spaceComm integer,intent(out) :: ier !Local variables-------------- #if defined HAVE_MPI integer :: statux(MPI_STATUS_SIZE) integer :: tag,me #endif ! ************************************************************************* ier=0 #if defined HAVE_MPI if (sender==recever.or.spaceComm==MPI_COMM_NULL.or.(nt==0)) return call MPI_COMM_RANK(spaceComm,me,ier) tag=MOD(nt, xmpi_tag_ub) if (recever==me) then call MPI_RECV(vrecv,nt,MPI_DOUBLE_COMPLEX,sender, tag,spaceComm,statux,ier) end if if (sender==me) then call MPI_SEND(vsend,nt,MPI_DOUBLE_COMPLEX,recever,tag,spaceComm,ier) end if #endif end subroutine xmpi_exch_dpc_2d !!*** v_sim-3.8.0/lib/plug-ins/abinit/xmpi_gather.finc000066400000000000000000000220641370110300500215530ustar00rootroot00000000000000!{\src2tex{textfont=tt}} !!****f* ABINIT/xmpi_gather !! NAME !! xmpi_gather !! !! FUNCTION !! This module contains functions that calls MPI routine, !! if we compile the code using the MPI CPP flags. !! xmpi_gather is the generic function. !! !! COPYRIGHT !! Copyright (C) 2001-2016 ABINIT group (MT) !! This file is distributed under the terms of the !! GNU General Public License, see ~ABINIT/COPYING !! or http://www.gnu.org/copyleft/gpl.txt . !! !! SOURCE !!*** !!****f* ABINIT/xmpi_gather_int !! NAME !! xmpi_gather_int !! !! FUNCTION !! Gathers data from all tasks and delivers it to all. !! Target: one-dimensional integer arrays. !! !! INPUTS !! xval= buffer array !! sendcont= number of sent elements !! recvcount= number of received elements !! root= rank of receiving process !! spaceComm= MPI communicator !! !! OUTPUT !! ier= exit status, a non-zero value meaning there is an error !! !! SIDE EFFECTS !! recvbuf= received buffer !! !! SOURCE subroutine xmpi_gather_int(xval,sendcount,recvbuf,recvcount,root,spaceComm,ier) !This section has been created automatically by the script Abilint (TD). !Do not modify the following lines by hand. #undef ABI_FUNC #define ABI_FUNC 'xmpi_gather_int' !End of the abilint section implicit none !Arguments------------------------- integer,intent(in) :: sendcount,recvcount integer, DEV_CONTARRD intent(in) :: xval(:) integer, DEV_CONTARRD intent(inout) :: recvbuf(:) integer,intent(in) :: root,spaceComm integer,intent(out) :: ier ! ************************************************************************* ier=0 #if defined HAVE_MPI if (spaceComm /= MPI_COMM_SELF .and. spaceComm /= MPI_COMM_NULL) then call MPI_gather(xval,sendcount,MPI_INTEGER,recvbuf,recvcount,MPI_INTEGER,root,spaceComm,ier) else if (spaceComm == MPI_COMM_SELF) then recvbuf=xval end if #else recvbuf=xval #endif end subroutine xmpi_gather_int !!*** !!****f* ABINIT/xmpi_gather_int2d !! NAME !! xmpi_gather_int2d !! !! FUNCTION !! Gathers data from all tasks and delivers it to all. !! Target: two-dimensional integer arrays. !! !! INPUTS !! xval= buffer array !! sendcont= number of sent elements !! recvcount= number of received elements !! root= rank of receiving process !! spaceComm= MPI communicator !! !! OUTPUT !! ier= exit status, a non-zero value meaning there is an error !! !! SIDE EFFECTS !! recvbuf= received buffer !! !! SOURCE subroutine xmpi_gather_int2d(xval,sendcount,recvbuf,recvcount,root,spaceComm,ier) !This section has been created automatically by the script Abilint (TD). !Do not modify the following lines by hand. #undef ABI_FUNC #define ABI_FUNC 'xmpi_gather_int2d' !End of the abilint section implicit none !Arguments------------------------- integer,intent(in) :: sendcount,recvcount integer, DEV_CONTARRD intent(in) :: xval(:,:) integer, DEV_CONTARRD intent(inout) :: recvbuf(:,:) integer,intent(in) :: root,spaceComm integer,intent(out) :: ier ! ************************************************************************* ier=0 #if defined HAVE_MPI if (spaceComm /= MPI_COMM_SELF .and. spaceComm /= MPI_COMM_NULL) then call MPI_gather(xval,sendcount,MPI_INTEGER,recvbuf,recvcount,MPI_INTEGER,root,spaceComm,ier) else if (spaceComm == MPI_COMM_SELF) then recvbuf=xval end if #else recvbuf=xval #endif end subroutine xmpi_gather_int2d !!*** !!****f* ABINIT/xmpi_gather_dp !! NAME !! xmpi_gather_dp !! !! FUNCTION !! Gathers data from all tasks and delivers it to all. !! Target: one-dimensional real arrays. !! !! INPUTS !! xval= buffer array !! sendcont= number of sent elements !! recvcount= number of received elements !! root= rank of receiving process !! spaceComm= MPI communicator !! !! OUTPUT !! ier= exit status, a non-zero value meaning there is an error !! !! SIDE EFFECTS !! recvbuf= received buffer !! !! SOURCE subroutine xmpi_gather_dp(xval,sendcount,recvbuf,recvcount,root,spaceComm,ier) !This section has been created automatically by the script Abilint (TD). !Do not modify the following lines by hand. #undef ABI_FUNC #define ABI_FUNC 'xmpi_gather_dp' !End of the abilint section implicit none !Arguments------------------------- integer,intent(in) :: sendcount,recvcount real(dp), DEV_CONTARRD intent(in) :: xval(:) real(dp), DEV_CONTARRD intent(inout) :: recvbuf(:) integer,intent(in) :: root,spaceComm integer,intent(out) :: ier ! ************************************************************************* ier=0 #if defined HAVE_MPI if (spaceComm /= MPI_COMM_SELF .and. spaceComm /= MPI_COMM_NULL) then call MPI_gather(xval,sendcount,MPI_DOUBLE_PRECISION,recvbuf,recvcount,MPI_DOUBLE_PRECISION,& & root,spaceComm,ier) else if (spaceComm == MPI_COMM_SELF) then recvbuf=xval end if #else recvbuf=xval #endif end subroutine xmpi_gather_dp !!*** !!****f* ABINIT/xmpi_gather_dp2d !! NAME !! xmpi_gather_dp2d !! !! FUNCTION !! Gathers data from all tasks and delivers it to all. !! Target: two-dimensional real arrays. !! !! INPUTS !! xval= buffer array !! sendcont= number of sent elements !! recvcount= number of received elements !! root= rank of receiving process !! spaceComm= MPI communicator !! !! OUTPUT !! ier= exit status, a non-zero value meaning there is an error !! !! SIDE EFFECTS !! recvbuf= received buffer !! !! SOURCE subroutine xmpi_gather_dp2d(xval,sendcount,recvbuf,recvcount,root,spaceComm,ier) !This section has been created automatically by the script Abilint (TD). !Do not modify the following lines by hand. #undef ABI_FUNC #define ABI_FUNC 'xmpi_gather_dp2d' !End of the abilint section implicit none !Arguments------------------------- integer,intent(in) :: sendcount,recvcount real(dp), DEV_CONTARRD intent(in) :: xval(:,:) real(dp), DEV_CONTARRD intent(inout) :: recvbuf(:,:) integer,intent(in) :: root,spaceComm integer,intent(out) :: ier ! ************************************************************************* ier=0 #if defined HAVE_MPI if (spaceComm /= MPI_COMM_SELF .and. spaceComm /= MPI_COMM_NULL) then call MPI_gather(xval,sendcount,MPI_DOUBLE_PRECISION,recvbuf,recvcount,MPI_DOUBLE_PRECISION,& & root,spaceComm,ier) else if (spaceComm == MPI_COMM_SELF) then recvbuf=xval end if #else recvbuf=xval #endif end subroutine xmpi_gather_dp2d !!*** !!****f* ABINIT/xmpi_gather_dp3d !! NAME !! xmpi_gather_dp3d !! !! FUNCTION !! Gathers data from all tasks and delivers it to all. !! Target: three-dimensional real arrays. !! !! INPUTS !! xval= buffer array !! sendcont= number of sent elements !! recvcount= number of received elements !! root= rank of receiving process !! spaceComm= MPI communicator !! !! OUTPUT !! ier= exit status, a non-zero value meaning there is an error !! !! SIDE EFFECTS !! recvbuf= received buffer !! !! SOURCE subroutine xmpi_gather_dp3d(xval,sendcount,recvbuf,recvcount,root,spaceComm,ier) !This section has been created automatically by the script Abilint (TD). !Do not modify the following lines by hand. #undef ABI_FUNC #define ABI_FUNC 'xmpi_gather_dp3d' !End of the abilint section implicit none !Arguments------------------------- integer,intent(in) :: sendcount,recvcount real(dp), DEV_CONTARRD intent(in) :: xval(:,:,:) real(dp), DEV_CONTARRD intent(inout) :: recvbuf(:,:,:) integer,intent(in) :: root,spaceComm integer,intent(out) :: ier ! ************************************************************************* ier=0 #if defined HAVE_MPI if (spaceComm /= MPI_COMM_SELF .and. spaceComm /= MPI_COMM_NULL) then call MPI_gather(xval,sendcount,MPI_DOUBLE_PRECISION,recvbuf,recvcount,MPI_DOUBLE_PRECISION,& & root,spaceComm,ier) else if (spaceComm == MPI_COMM_SELF) then recvbuf=xval end if #else recvbuf=xval #endif end subroutine xmpi_gather_dp3d !!*** !!****f* ABINIT/xmpi_gather_dp4d !! NAME !! xmpi_gather_dp4d !! !! FUNCTION !! Gathers data from all tasks and delivers it to all. !! Target: four-dimensional real arrays. !! !! INPUTS !! xval= buffer array !! sendcont= number of sent elements !! recvcount= number of received elements !! root= rank of receiving process !! spaceComm= MPI communicator !! !! OUTPUT !! ier= exit status, a non-zero value meaning there is an error !! !! SIDE EFFECTS !! recvbuf= received buffer !! !! SOURCE subroutine xmpi_gather_dp4d(xval,sendcount,recvbuf,recvcount,root,spaceComm,ier) !This section has been created automatically by the script Abilint (TD). !Do not modify the following lines by hand. #undef ABI_FUNC #define ABI_FUNC 'xmpi_gather_dp4d' !End of the abilint section implicit none !Arguments------------------------- integer,intent(in) :: sendcount,recvcount real(dp), DEV_CONTARRD intent(in) :: xval(:,:,:,:) real(dp), DEV_CONTARRD intent(inout) :: recvbuf(:,:,:,:) integer,intent(in) :: root,spaceComm integer,intent(out) :: ier ! ************************************************************************* ier=0 #if defined HAVE_MPI if (spaceComm /= MPI_COMM_SELF .and. spaceComm /= MPI_COMM_NULL) then call MPI_gather(xval,sendcount,MPI_DOUBLE_PRECISION,recvbuf,recvcount,MPI_DOUBLE_PRECISION,& & root,spaceComm,ier) else if (spaceComm == MPI_COMM_SELF) then recvbuf=xval end if #else recvbuf=xval #endif end subroutine xmpi_gather_dp4d !!*** v_sim-3.8.0/lib/plug-ins/abinit/xmpi_gatherv.finc000066400000000000000000000454731370110300500217520ustar00rootroot00000000000000!{\src2tex{textfont=tt}} !!****f* ABINIT/xmpi_gatherv !! NAME !! xmpi_gatherv !! !! FUNCTION !! This module contains functions that calls MPI routine, !! if we compile the code using the MPI CPP flags. !! xmpi_gatherv is the generic function. !! !! COPYRIGHT !! Copyright (C) 2001-2016 ABINIT group (MT,GG) !! This file is distributed under the terms of the !! GNU General Public License, see ~ABINIT/COPYING !! or http://www.gnu.org/copyleft/gpl.txt . !! !! SOURCE !!*** !!****f* ABINIT/xmpi_gatherv_int !! NAME !! xmpi_gatherv_int !! !! FUNCTION !! Gathers data from all tasks and delivers it to all. !! Target: one-dimensional integer arrays. !! !! INPUTS !! xval= buffer array !! recvcounts= number of received elements !! displs= relative offsets for incoming data !! nelem= number of elements !! root= rank of receiving process !! spaceComm= MPI communicator !! !! OUTPUT !! ier= exit status, a non-zero value meaning there is an error !! !! SIDE EFFECTS !! recvbuf= received buffer !! !! SOURCE subroutine xmpi_gatherv_int(xval,nelem,recvbuf,recvcounts,displs,root,spaceComm,ier) !This section has been created automatically by the script Abilint (TD). !Do not modify the following lines by hand. #undef ABI_FUNC #define ABI_FUNC 'xmpi_gatherv_int' !End of the abilint section implicit none !Arguments------------------------- integer, DEV_CONTARRD intent(in) :: xval(:) integer, DEV_CONTARRD intent(inout) :: recvbuf(:) integer, DEV_CONTARRD intent(in) :: recvcounts(:),displs(:) integer,intent(in) :: nelem,root,spaceComm integer,intent(out) :: ier !Local variables------------------- integer :: cc,dd ! ************************************************************************* ier=0 #if defined HAVE_MPI if (spaceComm /= MPI_COMM_SELF .and. spaceComm /= MPI_COMM_NULL) then call MPI_gatherV(xval,nelem,MPI_INTEGER,recvbuf,recvcounts,displs,& & MPI_INTEGER,root,spaceComm,ier) else if (spaceComm == MPI_COMM_SELF) then #endif dd=0;if (size(displs)>0) dd=displs(1) cc=size(xval);if (size(recvcounts)>0) cc=recvcounts(1) recvbuf(dd+1:dd+cc)=xval(1:cc) #if defined HAVE_MPI end if #endif end subroutine xmpi_gatherv_int !!*** !!****f* ABINIT/xmpi_gatherv_int1_dp1 !! NAME !! xmpi_gatherv_int1_dp1 !! !! FUNCTION !! Gathers data from all tasks and delivers it to all. !! Target : one-dimensional integer arrray and one-dimensionnal dp array !! !! INPUTS !! buf_int=buffer integer array that is going to be gathered !! buf_int_size=size of buf_int array !! buf_dp=buffer dp array that is going to be gathered !! buf_dp_size=size of buf_dp array !! spaceComm=MPI communicator to be gathered on it !! root=rank of receiving process !! spaceComm=MPI communicator !! !! OUTPUT !! buf_int_all=buffer integer array gathered !! buf_int_size_all=size of buffer integer array gathered !! buf_dp_all=buffer dp array gathered !! buf_dp_size_all=size of buffer dp array gathered !! ier=exit status, a non-zero value meaning there is an error !! !! SOURCE subroutine xmpi_gatherv_int1_dp1(buf_int,buf_int_size,buf_dp,buf_dp_size, & & buf_int_all,buf_int_size_all,buf_dp_all,buf_dp_size_all,root,& & spaceComm,ier) !This section has been created automatically by the script Abilint (TD). !Do not modify the following lines by hand. #undef ABI_FUNC #define ABI_FUNC 'xmpi_gatherv_int1_dp1' !End of the abilint section implicit none !Arguments------------------------- !scalars integer,intent(in) :: buf_int_size,buf_dp_size,root,spaceComm integer,intent(out) :: buf_int_size_all,buf_dp_size_all,ier !arrays integer,intent(in) :: buf_int(:) integer,allocatable,target,intent(out) :: buf_int_all(:) real(dp),intent(in) :: buf_dp(:) real(dp),allocatable,target, intent(out) :: buf_dp_all(:) !Local variables-------------- !scalars integer :: buf_pack_size,ierr,ii,iproc,istart_dp,istart_int integer :: lg,lg1,lg2,lg_int,lg_dp,me,n1,nproc,position integer :: totalbufcount logical,parameter :: use_pack=.false. !arrays integer :: buf_size(2),pos(3) integer,allocatable :: buf_dp_size1(:),buf_int_size1(:) integer,allocatable :: count_dp(:),count_int(:),count_size(:),counts(:) integer,allocatable :: disp_dp(:),disp_int(:),displ(:),displ_dp(:),displ_int(:) integer,allocatable :: pos_all(:) integer,pointer:: outbuf_int(:) real(dp ) :: tsec(2) real(dp),pointer :: outbuf_dp(:) character,allocatable :: buf_pack(:),buf_pack_tot(:) ! ************************************************************************* ier=0 #if defined HAVE_MPI if (spaceComm/=MPI_COMM_SELF.and.spaceComm/=MPI_COMM_NULL) then nproc=xmpi_comm_size(spaceComm) !First version: using 2 allgather (one for ints, another for reals) !------------------------------------------------------------------ if (.not.use_pack) then ! Prepare communications ABI_ALLOCATE(count_int,(nproc)) ABI_ALLOCATE(disp_int,(nproc)) ABI_ALLOCATE(count_dp,(nproc)) ABI_ALLOCATE(disp_dp,(nproc)) ABI_ALLOCATE(count_size,(2*nproc)) buf_size(1)=buf_int_size;buf_size(2)=buf_dp_size call xmpi_allgather(buf_size,2, count_size,spaceComm,ier) do iproc=1,nproc count_int(iproc)=count_size(2*iproc-1) count_dp(iproc)=count_size(2*iproc) end do disp_int(1)=0;disp_dp(1)=0 do ii=2,nproc disp_int(ii)=disp_int(ii-1)+count_int(ii-1) disp_dp (ii)=disp_dp (ii-1)+count_dp (ii-1) end do buf_int_size_all=sum(count_int) buf_dp_size_all =sum(count_dp) ABI_STAT_ALLOCATE(buf_int_all,(buf_int_size_all), ier) if (ier/= 0) call xmpi_abort(msg='error allocating buf_int_all in xmpi_gatherv') ABI_STAT_ALLOCATE(buf_dp_all ,(buf_dp_size_all), ier) if (ier/= 0) call xmpi_abort(msg='error allocating buf_dp_all in xmpi_gatherv') ! Communicate (one call for integers, one call for reals) call xmpi_gatherv(buf_int,buf_int_size,buf_int_all,count_int,disp_int,root,spaceComm,ierr) call xmpi_gatherv(buf_dp,buf_dp_size,buf_dp_all,count_dp,disp_dp,root,spaceComm,ierr) ! Release the memory ABI_DEALLOCATE(count_int) ABI_DEALLOCATE(disp_int) ABI_DEALLOCATE(count_dp) ABI_DEALLOCATE(disp_dp) ABI_DEALLOCATE(count_size) !2nd version: using 1 allgather (with MPI_PACK) !----------------------------------------------------------------- else me=xmpi_comm_rank(spaceComm) ! Compute size of message call MPI_PACK_SIZE(buf_int_size,MPI_INTEGER,spaceComm,lg1,ier) call MPI_PACK_SIZE(buf_dp_size,MPI_DOUBLE_PRECISION,spaceComm,lg2,ier) lg=lg1+lg2 ! Pack data to be sent position=0;buf_pack_size=lg1+lg2 ABI_STAT_ALLOCATE(buf_pack,(buf_pack_size), ier) if (ier/= 0) call xmpi_abort(msg='error allocating buf_pack xmpi_gatherv') call MPI_PACK(buf_int,buf_int_size,MPI_INTEGER,buf_pack,buf_pack_size,position,spaceComm,ier) call MPI_PACK(buf_dp,buf_dp_size,MPI_DOUBLE_PRECISION,buf_pack,buf_pack_size,position,spaceComm,ier) ! Gather size of all packed messages ABI_ALLOCATE(pos_all,(nproc*3)) ABI_ALLOCATE(counts,(nproc)) ABI_ALLOCATE(buf_int_size1,(nproc)) ABI_ALLOCATE(buf_dp_size1,(nproc)) ABI_ALLOCATE(displ,(nproc)) ABI_ALLOCATE(displ_int,(nproc)) ABI_ALLOCATE(displ_dp,(nproc)) pos(1)=position;pos(2)=buf_int_size;pos(3)=buf_dp_size call MPI_ALLGATHER(pos,3,MPI_INTEGER,pos_all,3,MPI_INTEGER,spaceComm,ier) ii=1 do iproc=1,nproc counts(iproc)=pos_all(ii);ii=ii+1 buf_int_size1(iproc)=pos_all(ii);ii=ii+1 buf_dp_size1(iproc)=pos_all(ii);ii=ii+1 end do displ(1)=0 ; displ_int(1)=0 ; displ_dp(1)=0 do iproc=2,nproc displ(iproc)=displ(iproc-1)+counts(iproc-1) displ_int(iproc)=displ_int(iproc-1)+buf_int_size1(iproc-1) displ_dp(iproc)=displ_dp(iproc-1)+buf_dp_size1(iproc-1) end do totalbufcount=displ(nproc)+counts(nproc) ABI_STAT_ALLOCATE(buf_pack_tot,(totalbufcount), ier) if (ier/= 0) call xmpi_abort(msg='error allocating buf_pack_tot in xmpi_gatherv') buf_int_size_all=sum(buf_int_size1) buf_dp_size_all=sum(buf_dp_size1) if (me==root) then ABI_STAT_ALLOCATE(buf_int_all,(buf_int_size_all), ier) if (ier/= 0) call xmpi_abort(msg='error allocating buf_int_all in xmpi_gatherv') ABI_STAT_ALLOCATE(buf_dp_all,(buf_dp_size_all), ier) if (ier/= 0) call xmpi_abort(msg='error allocating buf_int_all in xmpi_gatherv') else ABI_STAT_ALLOCATE(buf_int_all,(1), ier) if (ier/= 0) call xmpi_abort(msg='error allocating buf_int_all in xmpi_gatherv') ABI_STAT_ALLOCATE(buf_dp_all,(1), ier) if (ier/= 0) call xmpi_abort(msg='error allocating buf_int_all in xmpi_gatherv') end if ! Gather all packed messages call MPI_GATHERV(buf_pack,position,MPI_PACKED,buf_pack_tot,counts,displ,MPI_PACKED,root,spaceComm,ier) if (me==root) then position=0 do iproc=1,nproc lg_int=buf_int_size1(iproc); lg_dp=buf_dp_size1(iproc) istart_int=displ_int(iproc); istart_dp=displ_dp(iproc) outbuf_int=>buf_int_all(istart_int+1:istart_int+lg_int) call MPI_UNPACK(buf_pack_tot,totalbufcount,position, outbuf_int, & & lg_int, MPI_INTEGER,spaceComm,ier) outbuf_dp=>buf_dp_all(istart_dp+1:istart_dp+lg_dp) call MPI_UNPACK(buf_pack_tot,totalbufcount,position,outbuf_dp, & & lg_dp, MPI_DOUBLE_PRECISION,spaceComm,ier) end do end if ! Release the memory ABI_DEALLOCATE(pos_all) ABI_DEALLOCATE(counts) ABI_DEALLOCATE(buf_int_size1) ABI_DEALLOCATE(buf_dp_size1) ABI_DEALLOCATE(displ) ABI_DEALLOCATE(displ_int) ABI_DEALLOCATE(displ_dp) ABI_DEALLOCATE(buf_pack_tot) ABI_DEALLOCATE(buf_pack) end if else if (spaceComm == MPI_COMM_SELF) then #endif !Sequential version ABI_STAT_ALLOCATE(buf_int_all,(buf_int_size), ier) if (ier/= 0) call xmpi_abort(msg='error allocating buf_int_all in xmpi_gatherv') ABI_STAT_ALLOCATE(buf_dp_all,(buf_dp_size), ier) if (ier/= 0) call xmpi_abort(msg='error allocating buf_dp_all in xmpi_gatherv') buf_int_all(:)=buf_int(:) buf_dp_all(:)=buf_dp(:) buf_int_size_all=buf_int_size buf_dp_size_all=buf_dp_size #if defined HAVE_MPI end if #endif end subroutine xmpi_gatherv_int1_dp1 !!*** !!****f* ABINIT/xmpi_gatherv_int2d !! NAME !! xmpi_gatherv_int2d !! !! FUNCTION !! This module contains functions that calls MPI routine, !! if we compile the code using the MPI CPP flags. !! xmpi_gatherv is the generic function. !! !! INPUTS !! xval= buffer array !! recvcounts= number of received elements !! displs= relative offsets for incoming data !! nelem= number of elements !! root= rank of receiving process !! spaceComm= MPI communicator !! !! OUTPUT !! ier= exit status, a non-zero value meaning there is an error !! !! SIDE EFFECTS !! recvbuf= received buffer !! !! SOURCE subroutine xmpi_gatherv_int2d(xval,nelem,recvbuf,recvcounts,displs,root,spaceComm,ier) !This section has been created automatically by the script Abilint (TD). !Do not modify the following lines by hand. #undef ABI_FUNC #define ABI_FUNC 'xmpi_gatherv_int2d' !End of the abilint section implicit none !Arguments------------------------- integer, DEV_CONTARRD intent(in) :: xval(:,:) integer, DEV_CONTARRD intent(inout) :: recvbuf(:,:) integer, DEV_CONTARRD intent(in) :: recvcounts(:),displs(:) integer,intent(in) :: nelem,root,spaceComm integer,intent(out) :: ier !Local variables-------------- integer :: cc,dd,sz1 ! ************************************************************************* ier=0 #if defined HAVE_MPI if (spaceComm /= MPI_COMM_SELF .and. spaceComm /= MPI_COMM_NULL) then call MPI_gatherV(xval,nelem,MPI_INTEGER,recvbuf,recvcounts,displs,& & MPI_INTEGER,root,spaceComm,ier) else if (spaceComm == MPI_COMM_SELF) then #endif sz1=size(xval,1) dd=0;if (size(displs)>0) dd=displs(1)/sz1 cc=size(xval,2);if (size(recvcounts)>0) cc=recvcounts(1)/sz1 recvbuf(:,dd+1:dd+cc)=xval(:,1:cc) #if defined HAVE_MPI end if #endif end subroutine xmpi_gatherv_int2d !!*** !!****f* ABINIT/xmpi_gatherv_dp !! NAME !! xmpi_gatherv_dp !! !! FUNCTION !! Gathers data from all tasks and delivers it to all. !! Target: one-dimensional double precision arrays. !! !! INPUTS !! xval= buffer array !! recvcounts= number of received elements !! displs= relative offsets for incoming data !! nelem= number of elements !! root= rank of receiving process !! spaceComm= MPI communicator !! !! OUTPUT !! ier= exit status, a non-zero value meaning there is an error !! !! SIDE EFFECTS !! recvbuf= received buffer !! !! SOURCE subroutine xmpi_gatherv_dp(xval,nelem,recvbuf,recvcounts,displs,root,spaceComm,ier) !This section has been created automatically by the script Abilint (TD). !Do not modify the following lines by hand. #undef ABI_FUNC #define ABI_FUNC 'xmpi_gatherv_dp' !End of the abilint section implicit none !Arguments------------------------- real(dp), DEV_CONTARRD intent(in) :: xval(:) real(dp), DEV_CONTARRD intent(inout) :: recvbuf(:) integer, DEV_CONTARRD intent(in) :: recvcounts(:),displs(:) integer,intent(in) :: nelem,root,spaceComm integer,intent(out) :: ier !Local variables-------------- integer :: cc,dd ! ************************************************************************* ier=0 #if defined HAVE_MPI if (spaceComm /= MPI_COMM_SELF .and. spaceComm /= MPI_COMM_NULL) then call MPI_gatherV(xval,nelem,MPI_DOUBLE_PRECISION,recvbuf,recvcounts,displs,& & MPI_DOUBLE_PRECISION,root,spaceComm,ier) else if (spaceComm == MPI_COMM_SELF) then #endif dd=0;if (size(displs)>0) dd=displs(1) cc=size(xval);if (size(recvcounts)>0) cc=recvcounts(1) recvbuf(dd+1:dd+cc)=xval(1:cc) #if defined HAVE_MPI end if #endif end subroutine xmpi_gatherv_dp !!*** !!****f* ABINIT/xmpi_gatherv_dp2d !! NAME !! xmpi_gatherv_dp2d !! !! FUNCTION !! Gathers data from all tasks and delivers it to all. !! Target: double precision two-dimensional arrays. !! !! INPUTS !! xval= buffer array !! recvcounts= number of received elements !! displs= relative offsets for incoming data !! nelem= number of elements !! root= rank of receiving process !! spaceComm= MPI communicator !! !! OUTPUT !! ier= exit status, a non-zero value meaning there is an error !! !! SIDE EFFECTS !! recvbuf= received buffer !! !! SOURCE subroutine xmpi_gatherv_dp2d(xval,nelem,recvbuf,recvcounts,displs,root,spaceComm,ier) !This section has been created automatically by the script Abilint (TD). !Do not modify the following lines by hand. #undef ABI_FUNC #define ABI_FUNC 'xmpi_gatherv_dp2d' !End of the abilint section implicit none !Arguments------------------------- real(dp), DEV_CONTARRD intent(in) :: xval(:,:) real(dp), DEV_CONTARRD intent(inout) :: recvbuf(:,:) integer, DEV_CONTARRD intent(in) :: recvcounts(:),displs(:) integer,intent(in) :: nelem,root,spaceComm integer,intent(out) :: ier !Local variables-------------- integer :: cc,dd,sz1 ! ************************************************************************* ier=0 #if defined HAVE_MPI if (spaceComm /= MPI_COMM_SELF .and. spaceComm /= MPI_COMM_NULL) then call MPI_gatherV(xval,nelem,MPI_DOUBLE_PRECISION,recvbuf,recvcounts,displs,& & MPI_DOUBLE_PRECISION,root,spaceComm,ier) else if (spaceComm == MPI_COMM_SELF) then #endif sz1=size(xval,1) dd=0;if (size(displs)>0) dd=displs(1)/sz1 cc=size(xval,2);if (size(recvcounts)>0) cc=recvcounts(1)/sz1 recvbuf(:,dd+1:dd+cc)=xval(:,1:cc) #if defined HAVE_MPI end if #endif end subroutine xmpi_gatherv_dp2d !!*** !!****f* ABINIT/xmpi_gatherv_dp3d !! NAME !! xmpi_gatherv_dp3d !! !! FUNCTION !! Gathers data from all tasks and delivers it to all. !! Target: double precision three-dimensional arrays. !! !! INPUTS !! xval= buffer array !! recvcounts= number of received elements !! displs= relative offsets for incoming data !! nelem= number of elements !! root= rank of receiving process !! spaceComm= MPI communicator !! !! OUTPUT !! ier= exit status, a non-zero value meaning there is an error !! !! SIDE EFFECTS !! recvbuf= received buffer !! !! SOURCE subroutine xmpi_gatherv_dp3d(xval,nelem,recvbuf,recvcounts,displs,root,spaceComm,ier) !This section has been created automatically by the script Abilint (TD). !Do not modify the following lines by hand. #undef ABI_FUNC #define ABI_FUNC 'xmpi_gatherv_dp3d' !End of the abilint section implicit none !Arguments------------------------- real(dp), DEV_CONTARRD intent(in) :: xval(:,:,:) real(dp), DEV_CONTARRD intent(inout) :: recvbuf(:,:,:) integer, DEV_CONTARRD intent(in) :: recvcounts(:),displs(:) integer,intent(in) :: nelem,root,spaceComm integer,intent(out) :: ier !Local variables-------------- integer :: cc,dd,sz12 ! ************************************************************************* ier=0 #if defined HAVE_MPI if (spaceComm /= MPI_COMM_SELF .and. spaceComm /= MPI_COMM_NULL) then call MPI_gatherV(xval,nelem,MPI_DOUBLE_PRECISION,recvbuf,recvcounts,displs,& & MPI_DOUBLE_PRECISION,root,spaceComm,ier) else if (spaceComm == MPI_COMM_SELF) then #endif sz12=size(xval,1)*size(xval,2) dd=0;if (size(displs)>0) dd=displs(1)/sz12 cc=size(xval,3);if (size(recvcounts)>0) cc=recvcounts(1)/sz12 recvbuf(:,:,dd+1:dd+cc)=xval(:,:,1:cc) #if defined HAVE_MPI end if #endif end subroutine xmpi_gatherv_dp3d !!*** !!****f* ABINIT/xmpi_gatherv_dp4d !! NAME !! xmpi_gatherv_dp4d !! !! FUNCTION !! Gathers data from all tasks and delivers it to all. !! Target: double precision four-dimensional arrays. !! !! INPUTS !! xval= buffer array !! recvcounts= number of received elements !! displs= relative offsets for incoming data !! nelem= number of elements !! root= rank of receiving process !! spaceComm= MPI communicator !! !! OUTPUT !! ier= exit status, a non-zero value meaning there is an error !! !! SIDE EFFECTS !! recvbuf= received buffer !! !! SOURCE subroutine xmpi_gatherv_dp4d(xval,nelem,recvbuf,recvcounts,displs,root,spaceComm,ier) !This section has been created automatically by the script Abilint (TD). !Do not modify the following lines by hand. #undef ABI_FUNC #define ABI_FUNC 'xmpi_gatherv_dp4d' !End of the abilint section implicit none !Arguments------------------------- real(dp), DEV_CONTARRD intent(in) :: xval(:,:,:,:) real(dp), DEV_CONTARRD intent(inout) :: recvbuf(:,:,:,:) integer, DEV_CONTARRD intent(in) :: recvcounts(:),displs(:) integer,intent(in) :: nelem,root,spaceComm integer,intent(out) :: ier !Local variables------------------- integer :: cc,dd,sz123 ! ************************************************************************* ier=0 #if defined HAVE_MPI if (spaceComm /= MPI_COMM_SELF .and. spaceComm /= MPI_COMM_NULL) then call MPI_gatherV(xval,nelem,MPI_DOUBLE_PRECISION,recvbuf,recvcounts,displs,& & MPI_DOUBLE_PRECISION,root,spaceComm,ier) else if (spaceComm == MPI_COMM_SELF) then #endif sz123=size(xval,1)*size(xval,2)*size(xval,3) dd=0;if (size(displs)>0) dd=displs(1)/sz123 cc=size(xval,4);if (size(recvcounts)>0) cc=recvcounts(1)/sz123 recvbuf(:,:,:,dd+1:dd+cc)=xval(:,:,:,1:cc) #if defined HAVE_MPI end if #endif end subroutine xmpi_gatherv_dp4d !!*** v_sim-3.8.0/lib/plug-ins/abinit/xmpi_ialltoall.finc000066400000000000000000000036361370110300500222620ustar00rootroot00000000000000!{\src2tex{textfont=tt}} !!****f* ABINIT/xmpi_ialltoall !! NAME !! xmpi_ialltoall !! !! FUNCTION !! This module contains functions that calls MPI routine, !! if we compile the code using the MPI CPP flags. !! xmpi_ialltoall is the generic function. !! !! COPYRIGHT !! Copyright (C) 2001-2016 ABINIT group (MG) !! This file is distributed under the terms of the !! GNU General Public License, see ~ABINIT/COPYING !! or http://www.gnu.org/copyleft/gpl.txt . !! !! SOURCE !!*** !!****f* ABINIT/xmpi_ialltoall_dp4d !! NAME !! xmpi_ialltoall_dp4d !! !! FUNCTION !! Sends data from all to all processes. !! Target: double precision four-dimensional arrays. !! Non-blocking version. !! !! INPUTS !! !! OUTPUT !! !! PARENTS !! !! CHILDREN !! mpi_alltoall !! !! SOURCE subroutine xmpi_ialltoall_dp4d(xval, sendsize, recvbuf, recvsize, comm, request) !This section has been created automatically by the script Abilint (TD). !Do not modify the following lines by hand. #undef ABI_FUNC #define ABI_FUNC 'xmpi_alltoall_dp4d' !End of the abilint section implicit none !Arguments------------------------- real(dp) ABI_ASYNC, intent(in) :: xval(:,:,:,:) real(dp) ABI_ASYNC, intent(inout) :: recvbuf(:,:,:,:) integer,intent(in) :: sendsize,recvsize,comm integer,intent(out) :: request !Local variables------------------- integer :: ierr ! ************************************************************************* #ifdef HAVE_MPI_IALLTOALL ! Requires MPI3 if (comm /= MPI_COMM_SELF .and. comm /= MPI_COMM_NULL) then call MPI_IALLTOALL(& & xval, sendsize, MPI_DOUBLE_PRECISION,& & recvbuf,recvsize, MPI_DOUBLE_PRECISION, comm, request, ierr) return end if return #endif ! Call the blocking version and return null request. ! write(*,*)"will block here and return fake request" call xmpi_alltoall(xval, sendsize, recvbuf, recvsize, comm, ierr) request = xmpi_request_null end subroutine xmpi_ialltoall_dp4d !!*** v_sim-3.8.0/lib/plug-ins/abinit/xmpi_ialltoallv.finc000066400000000000000000000113461370110300500224450ustar00rootroot00000000000000!{\src2tex{textfont=tt}} !!****f* ABINIT/xmpi_ialltoallv_dp2d !! NAME !! xmpi_ialltoallv_dp2d !! !! FUNCTION !! This module contains functions calling the non-blocking MPI routine IALLTOALLV !! xmpi_ialltoallv is the generic function. !! !! COPYRIGHT !! Copyright (C) 2001-2016 ABINIT group (MG) !! This file is distributed under the terms of the !! GNU General Public License, see ~ABINIT/COPYING !! or http://www.gnu.org/copyleft/gpl.txt . !! !! INPUTS !! xval= buffer array !! sendcnts= number of sent elements !! sdispls= postions of values sent by the processor !! rdispls= positions of values received by the processor !! recvcnts= number of received elements !! comm= MPI communicator !! !! OUTPUT !! request= MPI request !! !! SIDE EFFECTS !! recvbuf= received buffer !! !! PARENTS !! !! CHILDREN !! mpi_ialltoallv !! !! SOURCE subroutine xmpi_ialltoallv_dp2d(xval,sendcnts,sdispls,recvbuf,recvcnts,rdispls,comm,request) !This section has been created automatically by the script Abilint (TD). !Do not modify the following lines by hand. #undef ABI_FUNC #define ABI_FUNC 'xmpi_ialltoallv_dp2d' !End of the abilint section implicit none !Arguments------------------------- real(dp) ABI_ASYNC, intent(in) :: xval(:,:) real(dp) ABI_ASYNC, intent(inout) :: recvbuf(:,:) integer ABI_ASYNC, intent(in) :: sendcnts(:),sdispls(:),rdispls(:),recvcnts(:) integer ,intent(in) :: comm integer ,intent(out) :: request !Local variables------------------- integer :: ierr ! ********************************************************************* #ifdef HAVE_MPI_IALLTOALLV if (comm /= MPI_COMM_SELF .and. comm /= MPI_COMM_NULL) then call MPI_IALLTOALLV(xval,sendcnts,sdispls,MPI_DOUBLE_PRECISION,recvbuf,& & recvcnts,rdispls,MPI_DOUBLE_PRECISION,comm,request,ierr) return end if #endif ! Call the blocking version and return null request. call xmpi_alltoallv(xval,sendcnts,sdispls,recvbuf,recvcnts,rdispls,comm,ierr) request = xmpi_request_null end subroutine xmpi_ialltoallv_dp2d !!*** !!****f* ABINIT/xmpi_ialltoallv_int2d !! NAME !! xmpi_ialltoallv_int2d !! !! FUNCTION !! Sends data from all to all processes. !! Target: two-dimensional integer arrays. !! !! PARENTS !! !! CHILDREN !! mpi_ialltoallv !! !! SOURCE subroutine xmpi_ialltoallv_int2d(xval,sendcnts,sdispls,recvbuf,recvcnts,rdispls,comm,request) !This section has been created automatically by the script Abilint (TD). !Do not modify the following lines by hand. #undef ABI_FUNC #define ABI_FUNC 'xmpi_ialltoallv_int2d' !End of the abilint section implicit none !Arguments------------------------- integer ABI_ASYNC, intent(in) :: xval(:,:) integer ABI_ASYNC, intent(inout) :: recvbuf(:,:) integer ABI_ASYNC, intent(in) :: sendcnts(:),sdispls(:),rdispls(:),recvcnts(:) integer,intent(in) :: comm integer,intent(out) :: request !Local variables------------------- integer :: ierr ! ********************************************************************* #ifdef HAVE_MPI_IALLTOALLV if (comm /= MPI_COMM_SELF .and. comm /= MPI_COMM_NULL) then call MPI_IALLTOALLV(xval,sendcnts,sdispls,MPI_INTEGER,recvbuf,& & recvcnts,rdispls,MPI_INTEGER,comm,request,ierr) return end if #endif ! Call the blocking version and return null request. call xmpi_alltoallv(xval,sendcnts,sdispls,recvbuf,recvcnts,rdispls,comm,ierr) request = xmpi_request_null end subroutine xmpi_ialltoallv_int2d !!*** !!****f* ABINIT/xmpi_ialltoallv_dp1d2 !! NAME !! xmpi_ialltoallv_dp1d2 !! !! FUNCTION !! Sends data from all to all processes. !! Target: double precision one-dimensional arrays. !! !! PARENTS !! !! CHILDREN !! mpi_ialltoallv !! !! SOURCE subroutine xmpi_ialltoallv_dp1d2(xval,sendcnts,sdispls,recvbuf,recvcnts,rdispls,comm,request) !This section has been created automatically by the script Abilint (TD). !Do not modify the following lines by hand. #undef ABI_FUNC #define ABI_FUNC 'xmpi_ialltoallv_dp1d2' !End of the abilint section implicit none !Arguments------------------------- real(dp) ABI_ASYNC, intent(in) :: xval(:) real(dp) ABI_ASYNC, intent(inout) :: recvbuf(:) integer ABI_ASYNC, intent(in) :: sendcnts(:),sdispls(:),recvcnts(:),rdispls(:) integer,intent(in) :: comm integer,intent(out) :: request !Local variables------------------- integer :: ierr ! ********************************************************************* #ifdef HAVE_MPI_IALLTOALLV if (comm /= MPI_COMM_SELF .and. comm /= MPI_COMM_NULL) then call MPI_IALLTOALLV(xval,sendcnts,sdispls,MPI_DOUBLE_PRECISION,recvbuf,& & recvcnts,rdispls,MPI_DOUBLE_PRECISION,comm,request,ierr) return end if #endif ! Call the blocking version and return null request. call xmpi_alltoallv(xval,sendcnts,sdispls,recvbuf,recvcnts,rdispls,comm,ierr) request = xmpi_request_null end subroutine xmpi_ialltoallv_dp1d2 !!*** v_sim-3.8.0/lib/plug-ins/abinit/xmpi_irecv.finc000066400000000000000000000113461370110300500214120ustar00rootroot00000000000000!{\src2tex{textfont=tt}} !!****f* ABINIT/xmpi_irecv !! NAME !! xmpi_irecv !! !! FUNCTION !! This module contains functions that call MPI routine MPI_IRECV, !! to receive data on one processor sent by another, !! if we compile the code using the MPI CPP flags. !! xmpi_irecv is the generic function. !! !! COPYRIGHT !! Copyright (C) 2001-2016 ABINIT group !! This file is distributed under the terms of the !! GNU General Public License, see ~ABINIT/COPYING !! or http://www.gnu.org/copyleft/gpl.txt . !! !! TODO !! !! SOURCE !!*** !!****f* ABINIT/xmpi_irecv_intv !! NAME !! xmpi_irecv_intv !! !! FUNCTION !! Receives data from one processor sent by another. !! Target: single integer. !! !! INPUTS !! source :: rank of source process !! tag :: integer message tag !! spaceComm :: MPI communicator !! !! OUTPUT !! ierr= exit status, a non-zero value meaning there is an error !! !! SIDE EFFECTS !! xval= buffer array !! !! NOTES !! status of MPI_IRECV is explicitly ignored !! !! PARENTS !! !! CHILDREN !! mpi_irecv !! !! SOURCE subroutine xmpi_irecv_intv(xval,source,tag,spaceComm,request,ierr) !This section has been created automatically by the script Abilint (TD). !Do not modify the following lines by hand. #undef ABI_FUNC #define ABI_FUNC 'xmpi_irecv_intv' !End of the abilint section implicit none !Arguments------------------------- integer ABI_ASYNC, intent(inout) :: xval integer,intent(in) :: source,tag,spaceComm integer,intent(out) :: ierr integer, intent(out) :: request !Local variables------------------- #if defined HAVE_MPI integer :: ier,my_tag #endif ! ************************************************************************* ierr=0 #if defined HAVE_MPI if (spaceComm /= MPI_COMM_SELF .and. spaceComm /= MPI_COMM_NULL) then my_tag=MOD(tag,xmpi_tag_ub) call MPI_IRECV(xval,1,MPI_INTEGER,source,my_tag,spaceComm,request,ier) ierr=ier end if #endif end subroutine xmpi_irecv_intv !!*** !!****f* ABINIT/xmpi_irecv_int1d !! NAME !! xmpi_irecv_int1d !! !! FUNCTION !! Sends data from one processor to another. !! Target: integer one-dimensional arrays. !! !! INPUTS !! dest :: rank of destination process !! tag :: integer message tag !! spaceComm :: MPI communicator !! !! OUTPUT !! ierr= exit status, a non-zero value meaning there is an error !! !! SIDE EFFECTS !! xval= buffer array !! !! PARENTS !! !! CHILDREN !! mpi_irecv !! !! SOURCE subroutine xmpi_irecv_int1d(xval,source,tag,spaceComm,request,ierr) !This section has been created automatically by the script Abilint (TD). !Do not modify the following lines by hand. #undef ABI_FUNC #define ABI_FUNC 'xmpi_irecv_int1d' !End of the abilint section implicit none !Arguments------------------------- integer ABI_ASYNC, intent(inout) :: xval(:) integer,intent(in) :: source,tag,spaceComm integer, intent(out) :: request integer,intent(out) :: ierr !Local variables------------------- #if defined HAVE_MPI integer :: ier,n1,my_tag #endif ! ************************************************************************* ierr=0 #if defined HAVE_MPI if (spaceComm /= MPI_COMM_SELF .and. spaceComm /= MPI_COMM_NULL) then my_tag=MOD(tag,xmpi_tag_ub) n1=size(xval) call MPI_IRECV(xval,n1,MPI_INTEGER,source,my_tag,spaceComm,request,ier) ierr=ier end if #endif end subroutine xmpi_irecv_int1d !!*** !!****f* ABINIT/xmpi_irecv_dp1d !! NAME !! xmpi_irecv_dp1d !! !! FUNCTION !! Receives data from one proc sent by another. !! Target: double precision one-dimensional arrays. !! !! INPUTS !! source :: rank of source process !! tag :: integer message tag !! spaceComm :: MPI communicator !! !! OUTPUT !! ierr= exit status, a non-zero value meaning there is an error !! !! SIDE EFFECTS !! xval= buffer array !! !! NOTES !! status of MPI_IRECV is explicitly ignored !! !! PARENTS !! !! CHILDREN !! mpi_irecv !! !! SOURCE subroutine xmpi_irecv_dp1d(xval,source,tag,spaceComm,request,ierr) !This section has been created automatically by the script Abilint (TD). !Do not modify the following lines by hand. #undef ABI_FUNC #define ABI_FUNC 'xmpi_irecv_dp1d' !End of the abilint section implicit none !Arguments------------------------- real(dp) ABI_ASYNC, intent(inout) :: xval(:) integer, intent(in) :: source,tag,spaceComm integer, intent(out) :: ierr integer, intent(out) :: request !Local variables------------------- #if defined HAVE_MPI integer :: ier,my_tag,n1 #endif ! ************************************************************************* ierr=0 #if defined HAVE_MPI if (spaceComm /= MPI_COMM_SELF .and. spaceComm /= MPI_COMM_NULL) then n1=size(xval,dim=1) my_tag=MOD(tag,xmpi_tag_ub) call MPI_IRECV(xval,n1,MPI_DOUBLE_PRECISION,source,my_tag,spaceComm,request,ier) ierr=ier end if #endif end subroutine xmpi_irecv_dp1d !!*** v_sim-3.8.0/lib/plug-ins/abinit/xmpi_isend.finc000066400000000000000000000062631370110300500214060ustar00rootroot00000000000000!{\src2tex{textfont=tt}} !!****f* ABINIT/xmpi_isend !! NAME !! xmpi_isend !! !! FUNCTION !! This module contains functions that calls MPI routine MPI_ISEND, !! to send data from one processor to another, !! if we compile the code using the MPI CPP flags. !! xmpi_isend is the generic function. !! !! COPYRIGHT !! Copyright (C) 2001-2016 ABINIT group !! This file is distributed under the terms of the !! GNU General Public License, see ~ABINIT/COPYING !! or http://www.gnu.org/copyleft/gpl.txt . !! !! TODO !! !! SOURCE !!*** !!****f* ABINIT/xmpi_isend_int1d !! NAME !! xmpi_isend_int1d !! !! FUNCTION !! Sends data from one processor to another. !! Target: integer one-dimensional arrays. !! !! INPUTS !! dest :: rank of destination process !! tag :: integer message tag !! spaceComm :: MPI communicator !! !! OUTPUT !! ierr= exit status, a non-zero value meaning there is an error !! !! SIDE EFFECTS !! xval= buffer array !! !! SOURCE subroutine xmpi_isend_int1d(xval,dest,tag,spaceComm,request,ierr) !This section has been created automatically by the script Abilint (TD). !Do not modify the following lines by hand. #undef ABI_FUNC #define ABI_FUNC 'xmpi_isend_int1d' !End of the abilint section implicit none !Arguments------------------------- integer ABI_ASYNC, intent(inout) :: xval(:) integer, intent(in) :: dest,tag,spaceComm integer, intent(out) :: ierr integer, intent(out) :: request !Local variables------------------- #if defined HAVE_MPI integer :: ier,my_tag,n1 #endif ! ************************************************************************* ierr=0 #if defined HAVE_MPI if (spaceComm /= MPI_COMM_SELF .and. spaceComm /= MPI_COMM_NULL) then n1=size(xval,dim=1) my_tag = MOD(tag,xmpi_tag_ub) call MPI_ISEND(xval,n1,MPI_INTEGER,dest,my_tag,spaceComm,request,ier) ierr=ier end if #endif end subroutine xmpi_isend_int1d !!*** !!****f* ABINIT/xmpi_isend_dp1d !! NAME !! xmpi_isend_dp1d !! !! FUNCTION !! Sends data from one proc to another. !! Target: double precision two-dimensional arrays. !! !! INPUTS !! dest :: rank of destination process !! tag :: integer message tag !! spaceComm :: MPI communicator !! !! OUTPUT !! ierr= exit status, a non-zero value meaning there is an error !! !! SIDE EFFECTS !! xval= buffer array !! !! SOURCE subroutine xmpi_isend_dp1d(xval,dest,tag,spaceComm,request,ierr) !This section has been created automatically by the script Abilint (TD). !Do not modify the following lines by hand. #undef ABI_FUNC #define ABI_FUNC 'xmpi_isend_dp1d' !End of the abilint section implicit none !Arguments------------------------- real(dp) ABI_ASYNC, intent(inout) :: xval(:) integer, intent(in) :: dest,tag,spaceComm integer, intent(out) :: ierr integer, intent(out) :: request !Local variables------------------- #if defined HAVE_MPI integer :: ier,my_tag,n1 #endif ! ************************************************************************* ierr=0 #if defined HAVE_MPI if (spaceComm /= MPI_COMM_SELF .and. spaceComm /= MPI_COMM_NULL) then n1=size(xval) my_tag = MOD(tag,xmpi_tag_ub) call MPI_ISEND(xval,n1,MPI_DOUBLE_PRECISION,dest,my_tag,spaceComm,request,ier) ierr=ier end if #endif end subroutine xmpi_isend_dp1d !!*** v_sim-3.8.0/lib/plug-ins/abinit/xmpi_isum.finc000066400000000000000000000040171370110300500212540ustar00rootroot00000000000000!{\src2tex{textfont=tt}} !!****f* ABINIT/xmpi_isum !! NAME !! xmpi_isum !! !! FUNCTION !! This module contains functions that calls MPI routine, !! if we compile the code using the MPI CPP flags. !! xmpi_isum is the generic function. !! !! COPYRIGHT !! Copyright (C) 2001-2016 ABINIT group (MG) !! This file is distributed under the terms of the !! GNU General Public License, see ~ABINIT/COPYING !! or http://www.gnu.org/copyleft/gpl.txt . !! !! NOTES !! MPI_IALLREDUCE(SENDBUF, RECVBUF, COUNT, DATATYPE, OP, COMM, REQUEST, IERROR) !! SENDBUF(*), RECVBUF(*) !! INTEGER COUNT, DATATYPE, OP, COMM, REQUEST, IERROR !! !! SOURCE !!*** !!****f* ABINIT/xmpi_isum_int0d !! NAME !! xmpi_isum_int0d !! !! FUNCTION !! Combines values from all processes and distribute !! the result back to all processes. !! Target: scalar integers. !! Non-blocking version. !! !! INPUTS !! !! OUTPUT !! !! SOURCE subroutine xmpi_isum_int0d(xval, xsum, comm, request, ierr) !This section has been created automatically by the script Abilint (TD). !Do not modify the following lines by hand. #undef ABI_FUNC #define ABI_FUNC 'xmpi_alltoall_dp4d' !End of the abilint section implicit none !Arguments------------------------- integer, intent(in) :: xval integer ABI_ASYNC, intent(out) :: xsum integer,intent(in) :: comm integer,intent(out) :: ierr, request !Local variables------------------- integer :: itmp ! ************************************************************************* #ifdef HAVE_MPI_IALLREDUCE if (comm /= MPI_COMM_SELF .and. comm /= MPI_COMM_NULL) then call MPI_IALLREDUCE(xval, xsum, 1, MPI_INTEGER, MPI_SUM, comm, request,ierr) !write(std_out,*)"After MPI_IALLREDUCE" return end if xsum = xval; request = xmpi_request_null return #endif ! Call the blocking version and return null request. !write(std_out,*)"will block here and return fake request" itmp = xval call xmpi_sum(itmp, comm, ierr) xsum = itmp; request = xmpi_request_null end subroutine xmpi_isum_int0d !!*** v_sim-3.8.0/lib/plug-ins/abinit/xmpi_land_lor.finc000066400000000000000000000125001370110300500220650ustar00rootroot00000000000000!{\src2tex{textfont=tt}} !!****f* ABINIT/xmpi_land_log0d !! NAME !! xmpi_land_log0d !! !! FUNCTION !! Logical OR accross the nodes. !! Combines value from all processes and distribute the result back to all processes. !! Target: logical scalar !! !! SOURCE subroutine xmpi_land_log0d(xval, comm) !This section has been created automatically by the script Abilint (TD). !Do not modify the following lines by hand. #undef ABI_FUNC #define ABI_FUNC 'xmpi_land_log0d' !End of the abilint section implicit none !Arguments ------------------------------------ logical,intent(inout) :: xval integer,intent(in) :: comm #ifdef HAVE_MPI !Local variables------------------------------- integer :: ierr logical :: out_val ! ************************************************************************* if (comm /= MPI_COMM_SELF .and. comm /= MPI_COMM_NULL) then call MPI_ALLREDUCE(xval, out_val, 1, MPI_LOGICAL, MPI_LAND, comm, ierr) xval = out_val end if #endif end subroutine xmpi_land_log0d !!*** !---------------------------------------------------------------------- !!****f* ABINIT/xmpi_lor_log1d !! NAME !! xmpi_lor_log1d !! !! FUNCTION !! Combines values from all processes and distribute !! the result back to all processes. !! Target: one-dimensional logical arrays. !! !! INPUTS !! comm= MPI communicator !! !! SIDE EFFECTS !! xval= buffer array !! !! SOURCE subroutine xmpi_lor_log1d(xval,comm) !This section has been created automatically by the script Abilint (TD). !Do not modify the following lines by hand. #undef ABI_FUNC #define ABI_FUNC 'xmpi_lor_log1d' !End of the abilint section implicit none !Arguments ------------------------------------ integer,intent(in) :: comm logical, DEV_CONTARRD intent(inout) :: xval(:) !Local variables------------------------------- #if defined HAVE_MPI integer :: ierr,n1 logical,allocatable :: xsum(:) #endif ! ************************************************************************* #if defined HAVE_MPI if (comm /= MPI_COMM_SELF .and. comm /= MPI_COMM_NULL) then ! Accumulate xval on all proc. in comm n1 = size(xval) ABI_STAT_ALLOCATE(xsum,(n1), ierr) if (ierr/= 0) call xmpi_abort(msg='error allocating xsum in xmpi_lor_log1d') call MPI_ALLREDUCE(xval,xsum,n1,MPI_LOGICAL,MPI_LOR,comm,ierr) xval (:) = xsum(:) ABI_DEALLOCATE(xsum) end if #endif end subroutine xmpi_lor_log1d !!*** !---------------------------------------------------------------------- !!****f* ABINIT/xmpi_lor_log2d !! NAME !! xmpi_lor_log2d !! !! FUNCTION !! Combines values from all processes and distribute !! the result back to all processes. !! Target: two-dimensional logical arrays. !! !! INPUTS !! comm= MPI communicator !! !! SIDE EFFECTS !! xval= buffer array !! !! SOURCE subroutine xmpi_lor_log2d(xval,comm) !This section has been created automatically by the script Abilint (TD). !Do not modify the following lines by hand. #undef ABI_FUNC #define ABI_FUNC 'xmpi_lor_log2d' !End of the abilint section implicit none !Arguments ------------------------------------ integer,intent(in) :: comm logical, DEV_CONTARRD intent(inout) :: xval(:,:) !Local variables------------------------------- #if defined HAVE_MPI integer :: n1,n2,ierr logical,allocatable :: xsum(:,:) #endif ! ************************************************************************* #if defined HAVE_MPI if (comm /= MPI_COMM_SELF .and. comm /= MPI_COMM_NULL) then ! Accumulate xval on all proc. in comm n1 = size(xval,1) n2 = size(xval,2) ABI_STAT_ALLOCATE(xsum,(n1,n2), ierr) if (ierr/= 0) call xmpi_abort(msg='error allocating xsum in xmpi_lor_log2d') call MPI_ALLREDUCE(xval,xsum,n1*n2,MPI_LOGICAL,MPI_LOR,comm,ierr) xval (:,:) = xsum(:,:) ABI_DEALLOCATE(xsum) end if #endif end subroutine xmpi_lor_log2d !!*** !---------------------------------------------------------------------- !!****f* ABINIT/xmpi_lor_log3d !! NAME !! xmpi_lor_log3d !! !! FUNCTION !! Combines values from all processes and distribute !! the result back to all processes. !! Target: three-dimensional logical arrays. !! !! INPUTS !! comm= MPI communicator !! !! SIDE EFFECTS !! xval= buffer array !! !! SOURCE subroutine xmpi_lor_log3d(xval,comm) !This section has been created automatically by the script Abilint (TD). !Do not modify the following lines by hand. #undef ABI_FUNC #define ABI_FUNC 'xmpi_lor_log3d' !End of the abilint section implicit none !Arguments ------------------------------------ integer,intent(in) :: comm logical, DEV_CONTARRD intent(inout) :: xval(:,:,:) !Local variables------------------------------- #if defined HAVE_MPI integer :: n1,n2,n3,ierr logical,allocatable :: xsum(:,:,:) #endif ! ************************************************************************* #if defined HAVE_MPI if (comm /= MPI_COMM_SELF .and. comm /= MPI_COMM_NULL) then ! Accumulate xval on all proc. in comm n1 = size(xval,1) n2 = size(xval,2) n3 = size(xval,3) ! #if defined HAVE_MPI2 && defined HAVE_MPI2_INPLACE ! call MPI_ALLREDUCE(MPI_IN_PLACE,xval,n1*n2*n3,MPI_LOGICAL,MPI_LOR,comm,ierr) ! #else ABI_STAT_ALLOCATE(xsum,(n1,n2,n3), ierr) if (ierr/= 0) call xmpi_abort(msg='error allocating xsum in xmpi_lor_log3d') call MPI_ALLREDUCE(xval,xsum,n1*n2*n3,MPI_LOGICAL,MPI_LOR,comm,ierr) xval (:,:,:) = xsum(:,:,:) ABI_DEALLOCATE(xsum) ! #endif end if #endif end subroutine xmpi_lor_log3d !!*** v_sim-3.8.0/lib/plug-ins/abinit/xmpi_max.finc000066400000000000000000000131701370110300500210640ustar00rootroot00000000000000!{\src2tex{textfont=tt}} !!****f* ABINIT/xmpi_max_int0d_i4b !! NAME !! xmpi_max_int0d_i4b !! !! FUNCTION !! This module contains functions that calls MPI routine, !! if we compile the code using the MPI CPP flags. !! xmpi_max is the generic function. !! !! COPYRIGHT !! Copyright (C) 2001-2016 ABINIT group (AR,XG,MB) !! This file is distributed under the terms of the !! GNU General Public License, see ~ABINIT/COPYING !! or http://www.gnu.org/copyleft/gpl.txt . !! !! CHILDREN !! mpi_allreduce !! !! SOURCE subroutine xmpi_max_int0d_i4b(xval,xmax,comm,ier) !This section has been created automatically by the script Abilint (TD). !Do not modify the following lines by hand. #undef ABI_FUNC #define ABI_FUNC 'xmpi_max_int0d_i4b' !End of the abilint section implicit none !Arguments------------------------- integer ,intent(in) :: xval integer, intent(out) :: xmax integer ,intent(in) :: comm integer ,intent(out) :: ier !Local variables------------------- integer :: arr_xval(1),arr_xmax(1) ! ************************************************************************* ier=0 #if defined HAVE_MPI if (comm /= MPI_COMM_SELF .and. comm /= MPI_COMM_NULL) then arr_xval(1) = xval call MPI_ALLREDUCE(arr_xval,arr_xmax,1,MPI_INTEGER,MPI_MAX,comm,ier) xmax = arr_xmax(1) else #endif xmax=xval #if defined HAVE_MPI end if #endif end subroutine xmpi_max_int0d_i4b !!*** !!****f* ABINIT/xmpi_max_int0d_i8b !! NAME !! xmpi_max_int0d_i8b !! !! FUNCTION !! !! CHILDREN !! mpi_allreduce !! !! SOURCE subroutine xmpi_max_int0d_i8b(xval,xmax,comm,ier) !This section has been created automatically by the script Abilint (TD). !Do not modify the following lines by hand. #undef ABI_FUNC #define ABI_FUNC 'xmpi_max_int0d_i8b' !End of the abilint section implicit none !Arguments------------------------- integer(i8b) ,intent(in) :: xval integer(i8b), intent(out) :: xmax integer ,intent(in) :: comm integer ,intent(out) :: ier !Local variables------------------- integer(i8b) :: arr_xval(1),arr_xmax(1) ! ************************************************************************* ier=0 #if defined HAVE_MPI if (comm /= MPI_COMM_SELF .and. comm /= MPI_COMM_NULL) then arr_xval(1) = xval call MPI_ALLREDUCE(arr_xval,arr_xmax,1,MPI_INTEGER8,MPI_MAX,comm,ier) xmax = arr_xmax(1) else #endif xmax=xval #if defined HAVE_MPI end if #endif end subroutine xmpi_max_int0d_i8b !!*** !!****f* ABINIT/xmpi_max_int !! NAME !! xmpi_max_int !! !! SOURCE subroutine xmpi_max_int(xval,xmax,comm,ier) !This section has been created automatically by the script Abilint (TD). !Do not modify the following lines by hand. #undef ABI_FUNC #define ABI_FUNC 'xmpi_max_int' !End of the abilint section implicit none !Arguments------------------------- integer, DEV_CONTARRD intent(in) :: xval(:) integer, DEV_CONTARRD intent(out):: xmax(:) integer ,intent(in) :: comm integer ,intent(out) :: ier !Local variables------------------- integer :: s1 ! ************************************************************************* ier=0 s1 =SIZE(xval) #if defined HAVE_MPI if (comm /= MPI_COMM_SELF .and. comm /= MPI_COMM_NULL) then call MPI_ALLREDUCE(xval,xmax,s1,MPI_INTEGER,MPI_MAX,comm,ier) else #endif xmax=xval #if defined HAVE_MPI end if #endif end subroutine xmpi_max_int !!*** !!****f* ABINIT/xmpi_max_dpv !! NAME !! xmpi_max_dpv !! !! FUNCTION !! Combines values from all processes and distribute !! the result back to all processes. !! Target: scalar double precisions. !! !! INPUTS !! comm= MPI communicator !! !! OUTPUT !! ier= exit status, a non-zero value meaning there is an error !! !! SIDE EFFECTS !! xval= buffer array !! xmax= number of elements in send buffer !! !! SOURCE subroutine xmpi_max_dpv(xval,xmax,comm,ier) !This section has been created automatically by the script Abilint (TD). !Do not modify the following lines by hand. #undef ABI_FUNC #define ABI_FUNC 'xmpi_max_dpv' !End of the abilint section implicit none !Arguments------------------------- real(dp),intent(in) :: xval real(dp),intent(out) :: xmax integer ,intent(in) :: comm integer ,intent(out) :: ier ! ************************************************************************* ier=0 #if defined HAVE_MPI if (comm /= MPI_COMM_SELF .and. comm /= MPI_COMM_NULL) then call MPI_ALLREDUCE(xval,xmax,1,MPI_DOUBLE_PRECISION,MPI_MAX,comm,ier) else #endif xmax=xval #if defined HAVE_MPI end if #endif end subroutine xmpi_max_dpv !!*** !!****f* ABINIT/xmpi_max_dp0d_ip !! NAME !! xmpi_max_dp0d_ip !! !! FUNCTION !! Combines values from all processes and distribute !! the result back to all processes. !! Target: scalar double precisions. In place operation !! !! INPUTS !! comm= MPI communicator !! !! OUTPUT !! ier= exit status, a non-zero value meaning there is an error !! !! SIDE EFFECTS !! xval= !! in input: the value on the local processor !! in output: the maximum inside the given communicator. !! !! SOURCE subroutine xmpi_max_dp0d_ip(ioval,comm,ier) !This section has been created automatically by the script Abilint (TD). !Do not modify the following lines by hand. #undef ABI_FUNC #define ABI_FUNC 'xmpi_max_dpv' !End of the abilint section implicit none !Arguments------------------------- real(dp),intent(inout) :: ioval integer ,intent(in) :: comm integer ,intent(out) :: ier !Local variables------------------- real(dp) :: xmax ! ************************************************************************* ier=0 #if defined HAVE_MPI if (comm /= MPI_COMM_SELF .and. comm /= MPI_COMM_NULL) then call MPI_ALLREDUCE(ioval,xmax,1,MPI_DOUBLE_PRECISION,MPI_MAX,comm,ier) ioval = xmax end if #endif end subroutine xmpi_max_dp0d_ip !!*** v_sim-3.8.0/lib/plug-ins/abinit/xmpi_min.finc000066400000000000000000000053501370110300500210630ustar00rootroot00000000000000!{\src2tex{textfont=tt}} !!****f* ABINIT/xmpi_min_intv !! NAME !! xmpi_min_intv !! !! FUNCTION !! This module contains functions that calls MPI routine, !! if we compile the code using the MPI CPP flags. !! xmpi_min is the generic function. !! !! COPYRIGHT !! Copyright (C) 2001-2016 ABINIT group (AR,XG,MB) !! This file is distributed under the terms of the !! GNU General Public License, see ~ABINIT/COPYING !! or http://www.gnu.org/copyleft/gpl.txt . !! !! PARENTS !! !! CHILDREN !! mpi_allreduce !! !! SOURCE subroutine xmpi_min_intv(xval,xmin,spaceComm,ier) !This section has been created automatically by the script Abilint (TD). !Do not modify the following lines by hand. #undef ABI_FUNC #define ABI_FUNC 'xmpi_min_intv' !End of the abilint section implicit none !Arguments------------------------- integer ,intent(in) :: xval integer ,intent(out) :: xmin integer ,intent(in) :: spaceComm integer ,intent(out) :: ier !Local variables------------------- integer :: arr_xval(1),arr_xmin(1) ! ************************************************************************* ier=0 #if defined HAVE_MPI if (spaceComm /= MPI_COMM_SELF .and. spaceComm /= MPI_COMM_NULL) then arr_xval(1) = xval call MPI_ALLREDUCE(arr_xval,arr_xmin,1,MPI_INTEGER,MPI_MIN,spaceComm,ier) xmin = arr_xmin(1) else #endif xmin=xval #if defined HAVE_MPI end if #endif end subroutine xmpi_min_intv !!*** !!****f* ABINIT/xmpi_min_dpv !! NAME !! xmpi_min_dpv !! !! FUNCTION !! Combines values from all processes and distribute !! the result back to all processes. !! Target: scalar double precisions. !! !! INPUTS !! spaceComm= MPI communicator !! !! OUTPUT !! ier= exit status, a non-zero value meaning there is an error !! !! SIDE EFFECTS !! xval= buffer array !! xmin= number of elements in send buffer !! !! PARENTS !! !! CHILDREN !! mpi_allreduce !! !! SOURCE subroutine xmpi_min_dpv(xval,xmin,spaceComm,ier) !This section has been created automatically by the script Abilint (TD). !Do not modify the following lines by hand. #undef ABI_FUNC #define ABI_FUNC 'xmpi_min_dpv' !End of the abilint section implicit none !Arguments------------------------- real(dp),intent(in) :: xval real(dp),intent(out) :: xmin integer ,intent(in) :: spaceComm integer ,intent(out) :: ier !Local variables------------------- real(dp) :: arr_xval(1),arr_xmin(1) ! ************************************************************************* ier=0 #if defined HAVE_MPI if (spaceComm /= MPI_COMM_SELF .and. spaceComm /= MPI_COMM_NULL) then arr_xval(1) = xval call MPI_ALLREDUCE(arr_xval,arr_xmin,1,MPI_DOUBLE_PRECISION,MPI_MIN,spaceComm,ier) xmin = arr_xmin(1) else #endif xmin=xval #if defined HAVE_MPI end if #endif end subroutine xmpi_min_dpv !!*** v_sim-3.8.0/lib/plug-ins/abinit/xmpi_recv.finc000066400000000000000000000221131370110300500212330ustar00rootroot00000000000000!{\src2tex{textfont=tt}} !!****f* ABINIT/xmpi_recv !! NAME !! xmpi_recv !! !! FUNCTION !! This module contains functions that call MPI routine MPI_RECV, !! to receive data on one processor sent by another, !! if we compile the code using the MPI CPP flags. !! xmpi_recv is the generic function. !! !! COPYRIGHT !! Copyright (C) 2001-2016 ABINIT group !! This file is distributed under the terms of the !! GNU General Public License, see ~ABINIT/COPYING !! or http://www.gnu.org/copyleft/gpl.txt . !! !! TODO !! !! SOURCE !!*** !!****f* ABINIT/xmpi_recv_intv !! NAME !! xmpi_recv_intv !! !! FUNCTION !! Receives data from one processor sent by another. !! Target: single integer. !! !! INPUTS !! source :: rank of source process !! tag :: integer message tag !! spaceComm :: MPI communicator !! !! OUTPUT !! ier= exit status, a non-zero value meaning there is an error !! !! SIDE EFFECTS !! xval= buffer array !! !! NOTES !! status of MPI_RECV is explicitly ignored !! !! SOURCE subroutine xmpi_recv_intv(xval,source,tag,spaceComm,ier) !This section has been created automatically by the script Abilint (TD). !Do not modify the following lines by hand. #undef ABI_FUNC #define ABI_FUNC 'xmpi_recv_intv' !End of the abilint section implicit none !Arguments------------------------- integer,intent(inout) :: xval integer,intent(in) :: source,tag,spaceComm integer,intent(out) :: ier !Local variables------------------- #if defined HAVE_MPI integer :: my_tag #endif ! ************************************************************************* ier=0 #if defined HAVE_MPI if (spaceComm /= MPI_COMM_SELF .and. spaceComm /= MPI_COMM_NULL) then my_tag=MOD(tag,xmpi_tag_ub) call MPI_RECV(xval,1,MPI_INTEGER,source,my_tag,spaceComm,MPI_STATUS_IGNORE,ier) end if #endif end subroutine xmpi_recv_intv !!*** !!****f* ABINIT/xmpi_recv_int1d !! NAME !! xmpi_recv_int1d !! !! FUNCTION !! Receives data from one proc sent by another. !! Target: integer one-dimensional arrays. !! !! INPUTS !! source :: rank of source process !! tag :: integer message tag !! spaceComm :: MPI communicator !! !! OUTPUT !! ier= exit status, a non-zero value meaning there is an error !! !! SIDE EFFECTS !! xval= buffer array !! !! NOTES !! status of MPI_RECV is explicitly ignored !! !! !! INPUTS !! source :: rank of source process !! tag :: integer message tag !! spaceComm :: MPI communicator !! !! OUTPUT !! ier= exit status, a non-zero value meaning there is an error !! !! SIDE EFFECTS !! xval= buffer array !! !! NOTES !! status of MPI_RECV is explicitly ignored !! !! SOURCE subroutine xmpi_recv_int1d(xval,source,tag,spaceComm,ier) !This section has been created automatically by the script Abilint (TD). !Do not modify the following lines by hand. #undef ABI_FUNC #define ABI_FUNC 'xmpi_recv_int1d' !End of the abilint section implicit none !Arguments------------------------- integer, DEV_CONTARRD intent(inout) :: xval(:) integer,intent(in) :: source,tag,spaceComm integer,intent(out) :: ier !Local variables------------------- #if defined HAVE_MPI integer :: my_tag, n1 #endif ! ************************************************************************* ier=0 #if defined HAVE_MPI if (spaceComm /= MPI_COMM_SELF .and. spaceComm /= MPI_COMM_NULL) then n1=size(xval,dim=1) my_tag = MOD(tag,xmpi_tag_ub) call MPI_RECV(xval,n1,MPI_INTEGER,source,my_tag,spaceComm,MPI_STATUS_IGNORE,ier) end if #endif end subroutine xmpi_recv_int1d !!*** !!****f* ABINIT/xmpi_recv_int2d !! NAME !! xmpi_recv_int2d !! !! FUNCTION !! Receives data from one proc sent by another. !! Target: integer two-dimensional arrays. !! !! INPUTS !! source :: rank of source process !! tag :: integer message tag !! spaceComm :: MPI communicator !! !! OUTPUT !! ier= exit status, a non-zero value meaning there is an error !! !! SIDE EFFECTS !! xval= buffer array !! !! NOTES !! status of MPI_RECV is explicitly ignored !! !! PARENTS !! !! CHILDREN !! mpi_recv !! !! SOURCE subroutine xmpi_recv_int2d(xval,source,tag,spaceComm,ier) use defs_basis #if defined HAVE_MPI2 && ! defined HAVE_MPI_INCLUDED_ONCE use mpi #endif !This section has been created automatically by the script Abilint (TD). !Do not modify the following lines by hand. #undef ABI_FUNC #define ABI_FUNC 'xmpi_recv_int2d' !End of the abilint section implicit none #if defined HAVE_MPI1 include 'mpif.h' #endif !Arguments------------------------- integer,intent(inout) :: xval(:,:) integer ,intent(in) :: source,tag,spaceComm integer ,intent(out) :: ier !Local variables------------------- #if defined HAVE_MPI integer :: n1,n2,my_tag #endif ! ************************************************************************* ier=0 #if defined HAVE_MPI if (spaceComm /= MPI_COMM_SELF .and. spaceComm /= MPI_COMM_NULL) then n1=size(xval,dim=1) n2=size(xval,dim=2) my_tag=MOD(tag,xmpi_tag_ub+1) call MPI_RECV(xval,n1*n2,MPI_INTEGER,source,my_tag,spaceComm,MPI_STATUS_IGNORE,ier) end if #endif end subroutine xmpi_recv_int2d !!*** !!****f* ABINIT/xmpi_recv_dp1d !! NAME !! xmpi_recv_dp1d !! !! FUNCTION !! Receives data from one proc sent by another. !! Target: double precision one-dimensional arrays. !! !! INPUTS !! source :: rank of source process !! tag :: integer message tag !! spaceComm :: MPI communicator !! !! OUTPUT !! ier= exit status, a non-zero value meaning there is an error !! !! SIDE EFFECTS !! xval= buffer array !! !! NOTES !! status of MPI_RECV is explicitly ignored !! !! SOURCE subroutine xmpi_recv_dp1d(xval,source,tag,spaceComm,ier) !This section has been created automatically by the script Abilint (TD). !Do not modify the following lines by hand. #undef ABI_FUNC #define ABI_FUNC 'xmpi_recv_dp1d' !End of the abilint section implicit none !Arguments------------------------- real(dp), DEV_CONTARRD intent(inout) :: xval(:) integer ,intent(in) :: source,tag,spaceComm integer ,intent(out) :: ier !Local variables------------------- #if defined HAVE_MPI integer :: n1,my_tag #endif ! ************************************************************************* ier=0 #if defined HAVE_MPI if (spaceComm /= MPI_COMM_SELF .and. spaceComm /= MPI_COMM_NULL) then n1=size(xval,dim=1) my_tag = MOD(tag,xmpi_tag_ub) call MPI_RECV(xval,n1,MPI_DOUBLE_PRECISION,source,my_tag,spaceComm,MPI_STATUS_IGNORE,ier) end if #endif end subroutine xmpi_recv_dp1d !!*** !!****f* ABINIT/xmpi_recv_dp2d !! NAME !! xmpi_recv_dp2d !! !! FUNCTION !! Receives data from one proc sent by another. !! Target: double precision two-dimensional arrays. !! !! INPUTS !! source :: rank of source process !! tag :: integer message tag !! spaceComm :: MPI communicator !! !! OUTPUT !! ier= exit status, a non-zero value meaning there is an error !! !! SIDE EFFECTS !! xval= buffer array !! !! NOTES !! status of MPI_RECV is explicitly ignored !! !! SOURCE subroutine xmpi_recv_dp2d(xval,source,tag,spaceComm,ier) !This section has been created automatically by the script Abilint (TD). !Do not modify the following lines by hand. #undef ABI_FUNC #define ABI_FUNC 'xmpi_recv_dp2d' !End of the abilint section implicit none !Arguments------------------------- real(dp), DEV_CONTARRD intent(inout) :: xval(:,:) integer ,intent(in) :: source,tag,spaceComm integer ,intent(out) :: ier !Local variables------------------- #if defined HAVE_MPI integer :: n1,n2,my_tag #endif ! ************************************************************************* ier=0 #if defined HAVE_MPI if (spaceComm /= MPI_COMM_SELF .and. spaceComm /= MPI_COMM_NULL) then n1=size(xval,dim=1) n2=size(xval,dim=2) my_tag=MOD(tag,xmpi_tag_ub) call MPI_RECV(xval,n1*n2,MPI_DOUBLE_PRECISION,source,my_tag,spaceComm,MPI_STATUS_IGNORE,ier) end if #endif end subroutine xmpi_recv_dp2d !!*** !!****f* ABINIT/xmpi_recv_dp3d !! NAME !! xmpi_recv_dp3d !! !! FUNCTION !! Receives data from one proc sent by another. !! Target: double precision three-dimensional arrays. !! !! INPUTS !! source :: rank of source process !! tag :: integer message tag !! spaceComm :: MPI communicator !! !! OUTPUT !! ier= exit status, a non-zero value meaning there is an error !! !! SIDE EFFECTS !! xval= buffer array !! !! NOTES !! status of MPI_RECV is explicitly ignored !! !! SOURCE subroutine xmpi_recv_dp3d(xval,source,tag,spaceComm,ier) !This section has been created automatically by the script Abilint (TD). !Do not modify the following lines by hand. #undef ABI_FUNC #define ABI_FUNC 'xmpi_recv_dp3d' !End of the abilint section implicit none !Arguments------------------------- real(dp), DEV_CONTARRD intent(inout) :: xval(:,:,:) integer ,intent(in) :: source,tag,spaceComm integer ,intent(out) :: ier !Local variables------------------- #if defined HAVE_MPI integer :: n1,n2,n3,my_tag #endif ! ************************************************************************* ier=0 #if defined HAVE_MPI if (spaceComm /= MPI_COMM_SELF .and. spaceComm /= MPI_COMM_NULL) then n1=size(xval,dim=1) n2=size(xval,dim=2) n3=size(xval,dim=3) my_tag=MOD(tag,xmpi_tag_ub) call MPI_RECV(xval,n1*n2*n3,MPI_DOUBLE_PRECISION,source,my_tag,spaceComm,MPI_STATUS_IGNORE,ier) end if #endif end subroutine xmpi_recv_dp3d !!*** v_sim-3.8.0/lib/plug-ins/abinit/xmpi_scatterv.finc000066400000000000000000000254711370110300500221410ustar00rootroot00000000000000!{\src2tex{textfont=tt}} !!****f* ABINIT/xmpi_scatterv !! NAME !! xmpi_scatterv !! !! FUNCTION !! This module contains functions that calls MPI routine, !! if we compile the code using the MPI CPP flags. !! xmpi_scatterv is the generic function. !! !! COPYRIGHT !! Copyright (C) 2001-2016 ABINIT group (MT) !! This file is distributed under the terms of the !! GNU General Public License, see ~ABINIT/COPYING !! or http://www.gnu.org/copyleft/gpl.txt . !! !! SOURCE !!*** !!****f* ABINIT/xmpi_scatterv_int !! NAME !! xmpi_scatterv_int !! !! FUNCTION !! Gathers data from all tasks and delivers it to all. !! Target: one-dimensional integer arrays. !! !! INPUTS !! xval= buffer array !! recvcount= number of received elements !! displs= relative offsets for incoming data (array) !! sendcounts= number of sent elements (array) !! root= rank of receiving process !! spaceComm= MPI communicator !! !! OUTPUT !! ier= exit status, a non-zero value meaning there is an error !! !! SIDE EFFECTS !! recvbuf= received buffer !! !! !! SOURCE subroutine xmpi_scatterv_int(xval,sendcounts,displs,recvbuf,recvcount,root,spaceComm,ier) !This section has been created automatically by the script Abilint (TD). !Do not modify the following lines by hand. #undef ABI_FUNC #define ABI_FUNC 'xmpi_scatterv_int' !End of the abilint section implicit none !Arguments------------------------- integer, DEV_CONTARRD intent(in) :: xval(:) integer, DEV_CONTARRD intent(inout) :: recvbuf(:) integer, DEV_CONTARRD intent(in) :: sendcounts(:),displs(:) integer,intent(in) :: recvcount,root,spaceComm integer,intent(out) :: ier !Local variables------------------- integer :: dd ! ************************************************************************* ier=0 #if defined HAVE_MPI if (spaceComm /= MPI_COMM_SELF .and. spaceComm /= MPI_COMM_NULL) then call MPI_SCATTERV(xval,sendcounts,displs,MPI_INTEGER,recvbuf,recvcount,& & MPI_INTEGER,root,spaceComm,ier) else if (spaceComm == MPI_COMM_SELF) then #endif dd=0;if (size(displs)>0) dd=displs(1) recvbuf(1:recvcount)=xval(dd+1:dd+recvcount) #if defined HAVE_MPI end if #endif end subroutine xmpi_scatterv_int !!*** !!****f* ABINIT/xmpi_scatterv_int2d !! NAME !! xmpi_scatterv_int2d !! !! FUNCTION !! Gathers data from all tasks and delivers it to all. !! Target: two-dimensional integer arrays. !! !! INPUTS !! xval= buffer array !! recvcount= number of received elements !! displs= relative offsets for incoming data (array) !! sendcounts= number of sent elements (array) !! root= rank of receiving process !! spaceComm= MPI communicator !! !! OUTPUT !! ier= exit status, a non-zero value meaning there is an error !! !! SIDE EFFECTS !! recvbuf= received buffer !! !! SOURCE subroutine xmpi_scatterv_int2d(xval,sendcounts,displs,recvbuf,recvcount,root,spaceComm,ier) !This section has been created automatically by the script Abilint (TD). !Do not modify the following lines by hand. #undef ABI_FUNC #define ABI_FUNC 'xmpi_scatterv_int2d' !End of the abilint section implicit none !Arguments------------------------- integer, DEV_CONTARRD intent(in) :: xval(:,:) integer, DEV_CONTARRD intent(inout) :: recvbuf(:,:) integer, DEV_CONTARRD intent(in) :: sendcounts(:),displs(:) integer,intent(in) :: recvcount,root,spaceComm integer,intent(out) :: ier !Local variables------------------- integer :: cc,dd,sz1 ! ************************************************************************* ier=0 #if defined HAVE_MPI if (spaceComm /= MPI_COMM_SELF .and. spaceComm /= MPI_COMM_NULL) then call MPI_SCATTERV(xval,sendcounts,displs,MPI_INTEGER,recvbuf,recvcount,& & MPI_INTEGER,root,spaceComm,ier) else if (spaceComm == MPI_COMM_SELF) then #endif sz1=size(recvbuf,1);cc=recvcount/sz1 dd=0;if (size(displs)>0) dd=displs(1)/sz1 recvbuf(:,1:cc)=xval(:,dd+1:dd+cc) #if defined HAVE_MPI end if #endif end subroutine xmpi_scatterv_int2d !!*** !!****f* ABINIT/xmpi_scatterv_dp !! NAME !! xmpi_scatterv_dp !! !! FUNCTION !! Gathers data from all tasks and delivers it to all. !! Target: one-dimensional real arrays. !! !! INPUTS !! xval= buffer array !! recvcount= number of received elements !! displs= relative offsets for incoming data (array) !! sendcounts= number of sent elements (array) !! root= rank of receiving process !! spaceComm= MPI communicator !! !! OUTPUT !! ier= exit status, a non-zero value meaning there is an error !! !! SIDE EFFECTS !! recvbuf= received buffer !! !! SOURCE subroutine xmpi_scatterv_dp(xval,sendcounts,displs,recvbuf,recvcount,root,spaceComm,ier) !This section has been created automatically by the script Abilint (TD). !Do not modify the following lines by hand. #undef ABI_FUNC #define ABI_FUNC 'xmpi_scatterv_dp' !End of the abilint section implicit none !Arguments------------------------- real(dp), DEV_CONTARRD intent(in) :: xval(:) real(dp), DEV_CONTARRD intent(inout) :: recvbuf(:) integer, DEV_CONTARRD intent(in) :: sendcounts(:),displs(:) integer,intent(in) :: recvcount,root,spaceComm integer,intent(out) :: ier !Local variables------------------- integer :: dd ! ************************************************************************* ier=0 #if defined HAVE_MPI if (spaceComm /= MPI_COMM_SELF .and. spaceComm /= MPI_COMM_NULL) then call MPI_SCATTERV(xval,sendcounts,displs,MPI_DOUBLE_PRECISION,recvbuf,recvcount,& & MPI_DOUBLE_PRECISION,root,spaceComm,ier) else if (spaceComm == MPI_COMM_SELF) then #endif dd=0;if (size(displs)>0) dd=displs(1) recvbuf(1:recvcount)=xval(dd+1:dd+recvcount) #if defined HAVE_MPI end if #endif end subroutine xmpi_scatterv_dp !!*** !!****f* ABINIT/xmpi_scatterv_dp2d !! NAME !! xmpi_scatterv_dp2d !! !! FUNCTION !! Gathers data from all tasks and delivers it to all. !! Target: two-dimensional real arrays. !! !! INPUTS !! xval= buffer array !! recvcount= number of received elements !! displs= relative offsets for incoming data (array) !! sendcounts= number of sent elements (array) !! root= rank of receiving process !! spaceComm= MPI communicator !! !! OUTPUT !! ier= exit status, a non-zero value meaning there is an error !! !! SIDE EFFECTS !! recvbuf= received buffer !! !! SOURCE subroutine xmpi_scatterv_dp2d(xval,sendcounts,displs,recvbuf,recvcount,root,spaceComm,ier) !This section has been created automatically by the script Abilint (TD). !Do not modify the following lines by hand. #undef ABI_FUNC #define ABI_FUNC 'xmpi_scatterv_dp2d' !End of the abilint section implicit none !Arguments------------------------- real(dp), DEV_CONTARRD intent(in) :: xval(:,:) real(dp), DEV_CONTARRD intent(inout) :: recvbuf(:,:) integer, DEV_CONTARRD intent(in) :: sendcounts(:),displs(:) integer,intent(in) :: recvcount,root,spaceComm integer,intent(out) :: ier !Local variables------------------- integer :: cc,dd,sz1 ! ************************************************************************* ier=0 #if defined HAVE_MPI if (spaceComm /= MPI_COMM_SELF .and. spaceComm /= MPI_COMM_NULL) then call MPI_SCATTERV(xval,sendcounts,displs,MPI_DOUBLE_PRECISION,recvbuf,recvcount,& & MPI_DOUBLE_PRECISION,root,spaceComm,ier) else if (spaceComm == MPI_COMM_SELF) then #endif sz1=size(recvbuf,1);cc=recvcount/sz1 dd=0;if (size(displs)>0) dd=displs(1)/sz1 recvbuf(:,1:cc)=xval(:,dd+1:dd+cc) #if defined HAVE_MPI end if #endif end subroutine xmpi_scatterv_dp2d !!*** !!****f* ABINIT/xmpi_scatterv_dp3d !! NAME !! xmpi_scatterv_dp3d !! !! FUNCTION !! Gathers data from all tasks and delivers it to all. !! Target: three-dimensional real arrays. !! !! INPUTS !! xval= buffer array !! recvcount= number of received elements !! displs= relative offsets for incoming data (array) !! sendcounts= number of sent elements (array) !! root= rank of receiving process !! spaceComm= MPI communicator !! !! OUTPUT !! ier= exit status, a non-zero value meaning there is an error !! !! SIDE EFFECTS !! recvbuf= received buffer !! !! SOURCE subroutine xmpi_scatterv_dp3d(xval,sendcounts,displs,recvbuf,recvcount,root,spaceComm,ier) !This section has been created automatically by the script Abilint (TD). !Do not modify the following lines by hand. #undef ABI_FUNC #define ABI_FUNC 'xmpi_scatterv_dp3d' !End of the abilint section implicit none !Arguments------------------------- real(dp), DEV_CONTARRD intent(in) :: xval(:,:,:) real(dp), DEV_CONTARRD intent(inout) :: recvbuf(:,:,:) integer, DEV_CONTARRD intent(in) :: sendcounts(:),displs(:) integer,intent(in) :: recvcount,root,spaceComm integer,intent(out) :: ier !Local variables------------------- integer :: cc,dd,sz12 ! ************************************************************************* ier=0 #if defined HAVE_MPI if (spaceComm /= MPI_COMM_SELF .and. spaceComm /= MPI_COMM_NULL) then call MPI_SCATTERV(xval,sendcounts,displs,MPI_DOUBLE_PRECISION,recvbuf,recvcount,& & MPI_DOUBLE_PRECISION,root,spaceComm,ier) else if (spaceComm == MPI_COMM_SELF) then #endif sz12=size(recvbuf,1)*size(recvbuf,2);cc=recvcount/sz12 dd=0;if (size(displs)>0) dd=displs(1)/sz12 recvbuf(:,:,1:cc)=xval(:,:,dd+1:dd+cc) #if defined HAVE_MPI end if #endif end subroutine xmpi_scatterv_dp3d !!*** !!****f* ABINIT/xmpi_scatterv_dp4d !! NAME !! xmpi_scatterv_dp4d !! !! FUNCTION !! Gathers data from all tasks and delivers it to all. !! Target: four-dimensional real arrays. !! !! INPUTS !! xval= buffer array !! recvcount= number of received elements !! displs= relative offsets for incoming data (array) !! sendcounts= number of sent elements (array) !! root= rank of receiving process !! spaceComm= MPI communicator !! !! OUTPUT !! ier= exit status, a non-zero value meaning there is an error !! !! SIDE EFFECTS !! recvbuf= received buffer !! !! SOURCE subroutine xmpi_scatterv_dp4d(xval,sendcounts,displs,recvbuf,recvcount,root,spaceComm,ier) !This section has been created automatically by the script Abilint (TD). !Do not modify the following lines by hand. #undef ABI_FUNC #define ABI_FUNC 'xmpi_scatterv_dp4d' !End of the abilint section implicit none !Arguments------------------------- real(dp), DEV_CONTARRD intent(in) :: xval(:,:,:,:) real(dp), DEV_CONTARRD intent(inout) :: recvbuf(:,:,:,:) integer, DEV_CONTARRD intent(in) :: sendcounts(:),displs(:) integer,intent(in) :: recvcount,root,spaceComm integer,intent(out) :: ier !Local variables------------------- integer :: cc,dd,sz123 ! ************************************************************************* ier=0 #if defined HAVE_MPI if (spaceComm /= MPI_COMM_SELF .and. spaceComm /= MPI_COMM_NULL) then call MPI_SCATTERV(xval,sendcounts,displs,MPI_DOUBLE_PRECISION,recvbuf,recvcount,& & MPI_DOUBLE_PRECISION,root,spaceComm,ier) else if (spaceComm == MPI_COMM_SELF) then #endif sz123=size(recvbuf,1)*size(recvbuf,2)*size(recvbuf,2);cc=recvcount/sz123 dd=0;if (size(displs)>0) dd=displs(1)/sz123 recvbuf(:,:,:,1:cc)=xval(:,:,:,dd+1:dd+cc) #if defined HAVE_MPI end if #endif end subroutine xmpi_scatterv_dp4d !!*** v_sim-3.8.0/lib/plug-ins/abinit/xmpi_send.finc000066400000000000000000000204351370110300500212320ustar00rootroot00000000000000!{\src2tex{textfont=tt}} !!****f* ABINIT/xmpi_send !! NAME !! xmpi_send !! !! FUNCTION !! This module contains functions that calls MPI routine MPI_SEND, !! to send data from one processor to another, !! if we compile the code using the MPI CPP flags. !! xmpi_send is the generic function. !! !! COPYRIGHT !! Copyright (C) 2001-2016 ABINIT group !! This file is distributed under the terms of the !! GNU General Public License, see ~ABINIT/COPYING !! or http://www.gnu.org/copyleft/gpl.txt . !! !! SOURCE !!*** !!****f* ABINIT/xmpi_send_intv !! NAME !! xmpi_send_intv !! !! FUNCTION !! Sends data from one processor to another. !! Target: single integer. !! !! INPUTS !! dest :: rank of destination process !! tag :: integer message tag !! spaceComm :: MPI communicator !! !! OUTPUT !! ier= exit status, a non-zero value meaning there is an error !! !! SIDE EFFECTS !! xval= buffer array !! !! SOURCE subroutine xmpi_send_intv(xval,dest,tag,spaceComm,ier) !This section has been created automatically by the script Abilint (TD). !Do not modify the following lines by hand. #undef ABI_FUNC #define ABI_FUNC 'xmpi_send_intv' !End of the abilint section implicit none !Arguments------------------------- integer,intent(inout) :: xval integer,intent(in) :: dest,tag,spaceComm integer,intent(out) :: ier !Local variables------------------- #if defined HAVE_MPI integer :: my_tag #endif ! ************************************************************************* ier=0 #if defined HAVE_MPI if (spaceComm /= MPI_COMM_SELF .and. spaceComm /= MPI_COMM_NULL) then my_tag = MOD(tag,xmpi_tag_ub) call MPI_SEND(xval,1,MPI_INTEGER,dest,my_tag,spaceComm,ier) end if #endif end subroutine xmpi_send_intv !!*** !!****f* ABINIT/xmpi_send_int1d !! NAME !! xmpi_send_int1d !! !! FUNCTION !! Sends data from one processor to another. !! Target: integer one-dimensional arrays. !! !! INPUTS !! dest :: rank of destination process !! tag :: integer message tag !! spaceComm :: MPI communicator !! !! OUTPUT !! ier= exit status, a non-zero value meaning there is an error !! !! SIDE EFFECTS !! xval= buffer array !! !! SOURCE subroutine xmpi_send_int1d(xval,dest,tag,spaceComm,ier) !This section has been created automatically by the script Abilint (TD). !Do not modify the following lines by hand. #undef ABI_FUNC #define ABI_FUNC 'xmpi_send_int1d' !End of the abilint section implicit none !Arguments------------------------- integer, DEV_CONTARRD intent(inout) :: xval(:) integer,intent(in) :: dest,tag,spaceComm integer,intent(out) :: ier !Local variables------------------- #if defined HAVE_MPI integer :: my_tag, n1 #endif ! ************************************************************************* ier=0 #if defined HAVE_MPI if (spaceComm /= MPI_COMM_SELF .and. spaceComm /= MPI_COMM_NULL) then n1=size(xval,dim=1) my_tag = MOD(tag,xmpi_tag_ub) call MPI_SEND(xval,n1,MPI_INTEGER,dest,my_tag,spaceComm,ier) end if #endif end subroutine xmpi_send_int1d !!*** !!****f* ABINIT/xmpi_send_int2d !! NAME !! xmpi_send_int2d !! !! FUNCTION !! Sends data from one proc to another. !! Target: integer two-dimensional arrays. !! !! INPUTS !! dest :: rank of destination process !! tag :: integer message tag !! spaceComm :: MPI communicator !! !! OUTPUT !! ier= exit status, a non-zero value meaning there is an error !! !! SIDE EFFECTS !! xval= buffer array !! !! PARENTS !! !! CHILDREN !! mpi_send !! !! SOURCE subroutine xmpi_send_int2d(xval,dest,tag,spaceComm,ier) use defs_basis #if defined HAVE_MPI2 && ! defined HAVE_MPI_INCLUDED_ONCE use mpi #endif !This section has been created automatically by the script Abilint (TD). !Do not modify the following lines by hand. #undef ABI_FUNC #define ABI_FUNC 'xmpi_send_int2d' !End of the abilint section implicit none #if defined HAVE_MPI1 include 'mpif.h' #endif !Arguments------------------------- integer,intent(inout) :: xval(:,:) integer ,intent(in) :: dest,tag,spaceComm integer ,intent(out) :: ier !Local variables------------------- #if defined HAVE_MPI integer :: n1,n2,my_tag #endif ! ************************************************************************* ier=0 #if defined HAVE_MPI if (spaceComm /= MPI_COMM_SELF .and. spaceComm /= MPI_COMM_NULL) then n1=size(xval,dim=1) n2=size(xval,dim=2) my_tag = MOD(tag,xmpi_tag_ub+1) call MPI_SEND(xval,n1*n2,MPI_INTEGER,dest,my_tag,spaceComm,ier) end if #endif end subroutine xmpi_send_int2d !!*** !!****f* ABINIT/xmpi_send_dp1d !! NAME !! xmpi_send_dp1d !! !! FUNCTION !! Sends data from one proc to another. !! Target: double precision one-dimensional arrays. !! !! INPUTS !! dest :: rank of destination process !! tag :: integer message tag !! spaceComm :: MPI communicator !! !! OUTPUT !! ier= exit status, a non-zero value meaning there is an error !! !! SIDE EFFECTS !! xval= buffer array !! !! SOURCE subroutine xmpi_send_dp1d(xval,dest,tag,spaceComm,ier) !This section has been created automatically by the script Abilint (TD). !Do not modify the following lines by hand. #undef ABI_FUNC #define ABI_FUNC 'xmpi_send_dp1d' !End of the abilint section implicit none !Arguments------------------------- real(dp), DEV_CONTARRD intent(inout) :: xval(:) integer ,intent(in) :: dest,tag,spaceComm integer ,intent(out) :: ier !Local variables------------------- #if defined HAVE_MPI integer :: n1,my_tag #endif ! ************************************************************************* ier=0 #if defined HAVE_MPI if (spaceComm /= MPI_COMM_SELF .and. spaceComm /= MPI_COMM_NULL) then n1=size(xval,dim=1) my_tag = MOD(tag,xmpi_tag_ub) call MPI_SEND(xval,n1,MPI_DOUBLE_PRECISION,dest,my_tag,spaceComm,ier) end if #endif end subroutine xmpi_send_dp1d !!*** !!****f* ABINIT/xmpi_send_dp2d !! NAME !! xmpi_send_dp2d !! !! FUNCTION !! Sends data from one proc to another. !! Target: double precision two-dimensional arrays. !! !! INPUTS !! dest :: rank of destination process !! tag :: integer message tag !! spaceComm :: MPI communicator !! !! OUTPUT !! ier= exit status, a non-zero value meaning there is an error !! !! SIDE EFFECTS !! xval= buffer array !! !! SOURCE subroutine xmpi_send_dp2d(xval,dest,tag,spaceComm,ier) !This section has been created automatically by the script Abilint (TD). !Do not modify the following lines by hand. #undef ABI_FUNC #define ABI_FUNC 'xmpi_send_dp2d' !End of the abilint section implicit none !Arguments------------------------- real(dp), DEV_CONTARRD intent(inout) :: xval(:,:) integer ,intent(in) :: dest,tag,spaceComm integer ,intent(out) :: ier !Local variables------------------- #if defined HAVE_MPI integer :: n1,n2,my_tag #endif ! ************************************************************************* ier=0 #if defined HAVE_MPI if (spaceComm /= MPI_COMM_SELF .and. spaceComm /= MPI_COMM_NULL) then n1=size(xval,dim=1) n2=size(xval,dim=2) my_tag = MOD(tag,xmpi_tag_ub) call MPI_SEND(xval,n1*n2,MPI_DOUBLE_PRECISION,dest,my_tag,spaceComm,ier) end if #endif end subroutine xmpi_send_dp2d !!*** !!****f* ABINIT/xmpi_send_dp3d !! NAME !! xmpi_send_dp3d !! !! FUNCTION !! Sends data from one proc to another. !! Target: double precision three-dimensional arrays. !! !! INPUTS !! dest :: rank of destination process !! tag :: integer message tag !! spaceComm :: MPI communicator !! !! OUTPUT !! ier= exit status, a non-zero value meaning there is an error !! !! SIDE EFFECTS !! xval= buffer array !! !! SOURCE subroutine xmpi_send_dp3d(xval,dest,tag,spaceComm,ier) !This section has been created automatically by the script Abilint (TD). !Do not modify the following lines by hand. #undef ABI_FUNC #define ABI_FUNC 'xmpi_send_dp3d' !End of the abilint section implicit none !Arguments------------------------- real(dp), DEV_CONTARRD intent(inout) :: xval(:,:,:) integer ,intent(in) :: dest,tag,spaceComm integer ,intent(out) :: ier !Local variables------------------- #if defined HAVE_MPI integer :: n1,n2,n3,my_tag #endif ! ************************************************************************* ier=0 #if defined HAVE_MPI if (spaceComm /= MPI_COMM_SELF .and. spaceComm /= MPI_COMM_NULL) then n1=size(xval,dim=1) n2=size(xval,dim=2) n3=size(xval,dim=3) my_tag = MOD(tag,xmpi_tag_ub) call MPI_SEND(xval,n1*n2*n3,MPI_DOUBLE_PRECISION,dest,my_tag,spaceComm,ier) end if #endif end subroutine xmpi_send_dp3d !!*** ! v_sim-3.8.0/lib/plug-ins/abinit/xmpi_sum.finc000066400000000000000000001720011370110300500211020ustar00rootroot00000000000000!{\src2tex{textfont=tt}} !!****f* ABINIT/xmpi_sum_int !! NAME !! xmpi_sum_int !! !! FUNCTION !! This module contains functions that calls MPI routine, !! if we compile the code using the MPI CPP flags. !! xmpi_sum is the generic function. !! !! COPYRIGHT !! Copyright (C) 2001-2016 ABINIT group (AR,XG,MB) !! This file is distributed under the terms of the !! GNU General Public License, see ~ABINIT/COPYING !! or http://www.gnu.org/copyleft/gpl.txt . !! !! NOTES !! MPI2 defines an option MPI_IN_PLACE to do the SUM in-place in the case of intra-communicators. !! The additional array xsum is therefore not needed if MPI_INPLACE is defined. !! !! PARENTS !! !! CHILDREN !! mpi_allreduce,xmpi_abort !! !! SOURCE subroutine xmpi_sum_int(xval,comm,ier) !This section has been created automatically by the script Abilint (TD). !Do not modify the following lines by hand. #undef ABI_FUNC #define ABI_FUNC 'xmpi_sum_int' !End of the abilint section implicit none !Arguments ------------------------------------ integer, DEV_CONTARRD intent(inout) :: xval(:) integer,intent(in) :: comm integer,intent(out) :: ier !Local variables------------------------------- #if defined HAVE_MPI integer :: n1 integer,allocatable :: xsum(:) #endif ! ************************************************************************* ier=0 #if defined HAVE_MPI if (comm /= MPI_COMM_SELF .and. comm /= MPI_COMM_NULL) then ! Accumulate xval on all proc. in comm n1 = size(xval) #if defined HAVE_MPI2 && defined HAVE_MPI2_INPLACE call MPI_ALLREDUCE(MPI_IN_PLACE,xval,n1,MPI_INTEGER,MPI_SUM,comm,ier) #else ABI_STAT_ALLOCATE(xsum,(n1), ier) if (ier/= 0) call xmpi_abort(msg='error allocating xsum in xmpi_sum_int') call MPI_ALLREDUCE(xval,xsum,n1,MPI_INTEGER,MPI_SUM,comm,ier) xval (:) = xsum(:) ABI_DEALLOCATE(xsum) #endif end if #endif end subroutine xmpi_sum_int !!*** !---------------------------------------------------------------------- !!****f* ABINIT/xmpi_sum_intv !! NAME !! xmpi_sum_intv !! !! FUNCTION !! Combines values from all processes and distribute !! the result back to all processes. !! Target: scalar integers. !! !! INPUTS !! comm= MPI communicator !! !! OUTPUT !! ier= exit status, a non-zero value meaning there is an error !! !! SIDE EFFECTS !! xval= buffer array !! !! SOURCE subroutine xmpi_sum_intv(xval,comm,ier) !This section has been created automatically by the script Abilint (TD). !Do not modify the following lines by hand. #undef ABI_FUNC #define ABI_FUNC 'xmpi_sum_intv' !End of the abilint section implicit none !Arguments---------------------- integer,intent(inout) :: xval integer,intent(in) :: comm integer,intent(out) :: ier !Local variables---------------- #if defined HAVE_MPI integer :: xsum #endif ! ************************************************************************* ier=0 #if defined HAVE_MPI if (comm /= MPI_COMM_SELF .and. comm /= MPI_COMM_NULL) then ! Accumulate xval on all proc. in comm call MPI_ALLREDUCE(xval,xsum,1,MPI_INTEGER,MPI_SUM,comm,ier) xval = xsum end if #endif end subroutine xmpi_sum_intv !!*** !---------------------------------------------------------------------- !!****f* ABINIT/xmpi_sum_intv2 !! NAME !! xmpi_sum_intv2 !! !! FUNCTION !! Combines values from all processes and distribute !! the result back to all processes. !! Target: scalar integer without transfers. !! !! INPUTS !! comm= MPI communicator !! !! OUTPUT !! ier= exit status, a non-zero value meaning there is an error !! !! SIDE EFFECTS !! xval= buffer array !! xsum= receive buffer !! !! SOURCE subroutine xmpi_sum_intv2(xval,xsum,comm,ier) !This section has been created automatically by the script Abilint (TD). !Do not modify the following lines by hand. #undef ABI_FUNC #define ABI_FUNC 'xmpi_sum_intv2' !End of the abilint section implicit none !Arguments--------------------- integer,intent(inout) :: xval,xsum integer,intent(in) :: comm integer,intent(out) :: ier ! ************************************************************************* ier=0 #if defined HAVE_MPI if (comm /= MPI_COMM_SELF .and. comm /= MPI_COMM_NULL) then ! Accumulate xval on all proc. in comm call MPI_ALLREDUCE(xval,xsum,1,MPI_INTEGER,MPI_SUM,comm,ier) else #endif xsum=xval #if defined HAVE_MPI end if #endif end subroutine xmpi_sum_intv2 !!*** !!****f* ABINIT/xmpi_sum_intn !! NAME !! xmpi_sum_intn !! !! FUNCTION !! Combines values from all processes and distribute !! the result back to all processes. !! Target: one-dimensional integer arrays. !! !! INPUTS !! n1= first dimension of the array !! comm= MPI communicator !! !! OUTPUT !! ier= exit status, a non-zero value meaning there is an error !! !! SIDE EFFECTS !! xval= buffer array !! !! SOURCE subroutine xmpi_sum_intn(xval,n1,comm,ier) !This section has been created automatically by the script Abilint (TD). !Do not modify the following lines by hand. #undef ABI_FUNC #define ABI_FUNC 'xmpi_sum_intn' !End of the abilint section implicit none !Arguments------------------------- integer, DEV_CONTARRD intent(inout) :: xval(:) integer,intent(in) :: n1 integer,intent(in) :: comm integer,intent(out) :: ier !Local variables------------------- #if defined HAVE_MPI integer :: nproc_space_comm integer , allocatable :: xsum(:) #endif ! ************************************************************************* ier=0 #if defined HAVE_MPI !Accumulate xval on all proc. in comm if (comm /= MPI_COMM_SELF .and. comm /= MPI_COMM_NULL) then call MPI_COMM_SIZE(comm,nproc_space_comm,ier) if (nproc_space_comm /= 1) then #if defined HAVE_MPI2 && defined HAVE_MPI2_INPLACE call MPI_ALLREDUCE(MPI_IN_PLACE,xval,n1,MPI_INTEGER,MPI_SUM,comm,ier) #else ABI_STAT_ALLOCATE(xsum,(n1), ier) if (ier/= 0) call xmpi_abort(msg='error allocating xsum in xmpi_sum_intn') call MPI_ALLREDUCE(xval,xsum,n1,MPI_INTEGER,MPI_SUM,comm,ier) xval (:) = xsum(:) ABI_DEALLOCATE(xsum) #endif end if end if #endif end subroutine xmpi_sum_intn !!*** !---------------------------------------------------------------------- !!****f* ABINIT/xmpi_sum_int2t !! NAME !! xmpi_sum_int2t !! !! FUNCTION !! Combines values from all processes and distribute !! the result back to all processes. !! Target: one-dimensional integer array without transfers. !! !! INPUTS !! n1= first dimension of the array !! comm= MPI communicator !! !! OUTPUT !! ier= exit status, a non-zero value meaning there is an error !! !! SIDE EFFECTS !! xval= buffer array !! xsum= receive buffer !! !! SOURCE subroutine xmpi_sum_int2t(xval,xsum,n1,comm,ier) !This section has been created automatically by the script Abilint (TD). !Do not modify the following lines by hand. #undef ABI_FUNC #define ABI_FUNC 'xmpi_sum_int2t' !End of the abilint section implicit none !Arguments------------------------- integer, DEV_CONTARRD intent(inout) :: xval(:),xsum(:) integer,intent(in) :: n1 integer,intent(in) :: comm integer,intent(out) :: ier ! ************************************************************************* ier=0 #if defined HAVE_MPI if (comm /= MPI_COMM_SELF .and. comm /= MPI_COMM_NULL) then ! Accumulate xval on all proc. in comm call MPI_ALLREDUCE(xval,xsum,n1,MPI_INTEGER,MPI_SUM,comm,ier) else #endif xsum=xval #if defined HAVE_MPI end if #endif end subroutine xmpi_sum_int2t !!*** !---------------------------------------------------------------------- !!****f* ABINIT/xmpi_sum_int2d !! NAME !! xmpi_sum_int2d !! !! FUNCTION !! Combines values from all processes and distribute !! the result back to all processes. !! Target: two-dimensional integer arrays. !! !! INPUTS !! comm= MPI communicator !! !! OUTPUT !! ier= exit status, a non-zero value meaning there is an error !! !! SIDE EFFECTS !! xval= buffer array !! !! SOURCE subroutine xmpi_sum_int2d(xval,comm,ier) !This section has been created automatically by the script Abilint (TD). !Do not modify the following lines by hand. #undef ABI_FUNC #define ABI_FUNC 'xmpi_sum_int2d' !End of the abilint section implicit none !Arguments------------------------- integer, DEV_CONTARRD intent(inout) :: xval(:,:) integer,intent(in) :: comm integer,intent(out) :: ier !Local variables------------------- #if defined HAVE_MPI integer :: n1,n2, nproc_space_comm integer,allocatable :: xsum(:,:) #endif ! ************************************************************************* ier=0 #if defined HAVE_MPI if (comm /= MPI_COMM_SELF .and. comm /= MPI_COMM_NULL) then call MPI_COMM_SIZE(comm,nproc_space_comm,ier) if (nproc_space_comm /= 1) then ! Accumulate xval on all proc. in comm n1 =size(xval,dim=1) n2 =size(xval,dim=2) #if defined HAVE_MPI2 && defined HAVE_MPI2_INPLACE call MPI_ALLREDUCE(MPI_IN_PLACE,xval,n1*n2,MPI_INTEGER,MPI_SUM,comm,ier) #else ABI_STAT_ALLOCATE(xsum,(n1,n2), ier) if (ier/=0) call xmpi_abort(msg='error allocating xsum in xmpi_sum_int2d') call MPI_ALLREDUCE(xval,xsum,n1*n2,MPI_INTEGER,MPI_SUM,comm,ier) xval (:,:) = xsum(:,:) ABI_DEALLOCATE(xsum) #endif end if end if #endif end subroutine xmpi_sum_int2d !!*** !---------------------------------------------------------------------- !!****f* ABINIT/xmpi_sum_int3d !! NAME !! xmpi_sum_int3d !! !! FUNCTION !! Combines values from all processes and distribute !! the result back to all processes. !! Target: three-dimensional integer arrays. !! !! INPUTS !! comm= MPI communicator !! !! OUTPUT !! ier= exit status, a non-zero value meaning there is an error !! !! SIDE EFFECTS !! xval= buffer array !! !! SOURCE subroutine xmpi_sum_int3d(xval,comm,ier) !This section has been created automatically by the script Abilint (TD). !Do not modify the following lines by hand. #undef ABI_FUNC #define ABI_FUNC 'xmpi_sum_int3d' !End of the abilint section implicit none !Arguments------------------------- integer, DEV_CONTARRD intent(inout) :: xval(:,:,:) integer,intent(in) :: comm integer,intent(out) :: ier !Local variables------------------- #if defined HAVE_MPI integer :: n1,n2,n3,nproc_space_comm integer,allocatable :: xsum(:,:,:) #endif ! ************************************************************************* ier=0 #if defined HAVE_MPI !Accumulate xval on all proc. in comm if (comm /= MPI_COMM_SELF .and. comm /= MPI_COMM_NULL) then call MPI_COMM_SIZE(comm,nproc_space_comm,ier) if (nproc_space_comm /= 1) then n1 =size(xval,dim=1) n2 =size(xval,dim=2) n3 =size(xval,dim=3) #if defined HAVE_MPI2 && defined HAVE_MPI2_INPLACE call MPI_ALLREDUCE(MPI_IN_PLACE,xval,n1*n2*n3,MPI_INTEGER,MPI_SUM,comm,ier) #else ABI_STAT_ALLOCATE(xsum,(n1,n2,n3), ier) if (ier/= 0) call xmpi_abort(msg='error allocating xsum in xmpi_sum_int3d') call MPI_ALLREDUCE(xval,xsum,n1*n2*n3,MPI_INTEGER,MPI_SUM,comm,ier) xval (:,:,:) = xsum(:,:,:) ABI_DEALLOCATE(xsum) #endif end if end if #endif end subroutine xmpi_sum_int3d !!*** !---------------------------------------------------------------------- !!****f* ABINIT/xmpi_sum_int4d !! NAME !! xmpi_sum_int4d !! !! FUNCTION !! Combines values from all processes and distribute !! the result back to all processes. !! Target: four-diemnsional integer arrays. !! !! INPUTS !! comm= MPI communicator !! !! OUTPUT !! ier= exit status, a non-zero value meaning there is an error !! !! SIDE EFFECTS !! xval= buffer array !! !! SOURCE subroutine xmpi_sum_int4d(xval,comm,ier) !This section has been created automatically by the script Abilint (TD). !Do not modify the following lines by hand. #undef ABI_FUNC #define ABI_FUNC 'xmpi_sum_int4d' !End of the abilint section implicit none !Arguments------------------------- integer, DEV_CONTARRD intent(inout) :: xval(:,:,:,:) integer,intent(in) :: comm integer,intent(out) :: ier !Local variables------------------- #if defined HAVE_MPI integer :: n1,n2,n3,n4 integer :: nproc_space_comm integer,allocatable :: xsum(:,:,:,:) #endif ! ************************************************************************* ier=0 #if defined HAVE_MPI !Accumulate xval on all proc. in comm if (comm /= MPI_COMM_SELF .and. comm /= MPI_COMM_NULL) then call MPI_COMM_SIZE(comm,nproc_space_comm,ier) if (nproc_space_comm /= 1) then n1 =size(xval,dim=1) n2 =size(xval,dim=2) n3 =size(xval,dim=3) n4 =size(xval,dim=4) #if defined HAVE_MPI2 && defined HAVE_MPI2_INPLACE call MPI_ALLREDUCE(MPI_IN_PLACE,xval,n1*n2*n3*n4,MPI_INTEGER,MPI_SUM,comm,ier) #else ABI_STAT_ALLOCATE(xsum,(n1,n2,n3,n4), ier) if (ier/= 0) call xmpi_abort(msg='error allocating xsum in xmpi_sum_int4d') call MPI_ALLREDUCE(xval,xsum,n1*n2*n3*n4,MPI_INTEGER,MPI_SUM,comm,ier) xval (:,:,:,:) = xsum(:,:,:,:) ABI_DEALLOCATE(xsum) #endif end if end if #endif end subroutine xmpi_sum_int4d !!*** !---------------------------------------------------------------------- !!****f* ABINIT/xmpi_sum_dp !! NAME !! xmpi_sum_dp !! !! FUNCTION !! Combines values from all processes and distribute !! the result back to all processes. !! Target: one-dimensional double precision arrays. !! !! INPUTS !! comm= MPI communicator !! !! OUTPUT !! ier= exit status, a non-zero value meaning there is an error !! !! SIDE EFFECTS !! xval= buffer array !! !! SOURCE subroutine xmpi_sum_dp(xval,comm,ier) !This section has been created automatically by the script Abilint (TD). !Do not modify the following lines by hand. #undef ABI_FUNC #define ABI_FUNC 'xmpi_sum_dp' !End of the abilint section implicit none !Arguments------------------------- real(dp), DEV_CONTARRD intent(inout) :: xval(:) integer,intent(in) :: comm integer,intent(out) :: ier !Local variables------------------- #if defined HAVE_MPI integer :: n1,nproc_space_comm real(dp),allocatable :: xsum(:) #endif ! ************************************************************************* ier=0 #if defined HAVE_MPI if (comm /= MPI_COMM_SELF .and. comm /= MPI_COMM_NULL) then ! Accumulate xval on all proc. in comm call MPI_COMM_SIZE(comm,nproc_space_comm,ier) if (nproc_space_comm /= 1) then n1 = size(xval) #if defined HAVE_MPI2 && defined HAVE_MPI2_INPLACE call MPI_ALLREDUCE(MPI_IN_PLACE,xval,n1,MPI_DOUBLE_PRECISION,MPI_SUM,comm,ier) #else ABI_STAT_ALLOCATE(xsum,(n1), ier) if (ier/= 0) call xmpi_abort(msg='error allocating xsum in xmpi_sum_dp') call MPI_ALLREDUCE(xval,xsum,n1,MPI_DOUBLE_PRECISION,MPI_SUM,comm,ier) xval (:) = xsum(:) ABI_DEALLOCATE(xsum) #endif end if end if #endif end subroutine xmpi_sum_dp !!*** !---------------------------------------------------------------------- !!****f* ABINIT/xmpi_sum_dpvt !! NAME !! xmpi_sum_dpvt !! !! FUNCTION !! Combines values from all processes and distribute !! the result back to all processes. !! Target: scalar double precisions. !! !! INPUTS !! xval= buffer array !! comm= MPI communicator !! !! OUTPUT !! xsum= receive buffer !! ier= exit status, a non-zero value meaning there is an error !! !! SIDE EFFECTS !! None !! !! SOURCE subroutine xmpi_sum_dpvt(xval,xsum,comm,ier) !This section has been created automatically by the script Abilint (TD). !Do not modify the following lines by hand. #undef ABI_FUNC #define ABI_FUNC 'xmpi_sum_dpvt' !End of the abilint section implicit none !Arguments------------------------- real(dp),intent(in) :: xval real(dp),intent(out) :: xsum integer ,intent(in) :: comm integer ,intent(out) :: ier !Local variables------------------- #if defined HAVE_MPI integer :: nproc_space_comm #endif ! ************************************************************************* ier=0 #if defined HAVE_MPI !Accumulate xval on all proc. in comm if (comm /= MPI_COMM_SELF .and. comm /= MPI_COMM_NULL) then call MPI_COMM_SIZE(comm,nproc_space_comm,ier) if (nproc_space_comm /= 1) then call MPI_ALLREDUCE(xval,xsum,1,MPI_DOUBLE_PRECISION,MPI_SUM,comm,ier) else xsum=xval end if else #endif xsum=xval #if defined HAVE_MPI end if #endif end subroutine xmpi_sum_dpvt !!*** !---------------------------------------------------------------------- !!****f* ABINIT/xmpi_sum_dpv !! NAME !! xmpi_sum_dpv !! !! FUNCTION !! Combines values from all processes and distribute !! the result back to all processes. !! Target: scalar double precisions. !! !! INPUTS !! comm= MPI communicator !! !! OUTPUT !! ier= exit status, a non-zero value meaning there is an error !! !! SIDE EFFECTS !! xval= buffer array !! !! SOURCE subroutine xmpi_sum_dpv(xval,comm,ier) !This section has been created automatically by the script Abilint (TD). !Do not modify the following lines by hand. #undef ABI_FUNC #define ABI_FUNC 'xmpi_sum_dpv' !End of the abilint section implicit none !Arguments------------------------- real(dp),intent(inout) :: xval integer ,intent(in) :: comm integer ,intent(out) :: ier !Local variables------------------- #if defined HAVE_MPI integer :: nproc_space_comm real(dp) :: xsum #endif ! ************************************************************************* ier=0 #if defined HAVE_MPI !Accumulate xval on all proc. in comm if (comm /= MPI_COMM_SELF .and. comm /= MPI_COMM_NULL) then call MPI_COMM_SIZE(comm,nproc_space_comm,ier) if (nproc_space_comm /= 1) then call MPI_ALLREDUCE(xval,xsum,1,MPI_DOUBLE_PRECISION,MPI_SUM,comm,ier) xval = xsum end if end if #endif end subroutine xmpi_sum_dpv !!*** !---------------------------------------------------------------------- !!****f* ABINIT/xmpi_sum_dpn !! NAME !! xmpi_sum_dpn !! !! FUNCTION !! Combines values from all processes and distribute !! the result back to all processes. !! Target: one-dimensional double precision arrays. !! !! INPUTS !! n1= first dimension of the array !! comm= MPI communicator !! !! OUTPUT !! ier= exit status, a non-zero value meaning there is an error !! !! SIDE EFFECTS !! xval= buffer array !! !! SOURCE subroutine xmpi_sum_dpn(xval,n1,comm,ier) !This section has been created automatically by the script Abilint (TD). !Do not modify the following lines by hand. #undef ABI_FUNC #define ABI_FUNC 'xmpi_sum_dpn' !End of the abilint section implicit none !Arguments------------------------- real(dp), DEV_CONTARRD intent(inout) :: xval(:) integer ,intent(in) :: n1 integer ,intent(in) :: comm integer ,intent(out) :: ier !Local variables------------------- #if defined HAVE_MPI integer :: nproc_space_comm real(dp) , allocatable :: xsum(:) #endif ! ************************************************************************* ier=0 #if defined HAVE_MPI if (comm /= MPI_COMM_SELF .and. comm /= MPI_COMM_NULL) then ! Accumulate xval on all proc. in comm call MPI_COMM_SIZE(comm,nproc_space_comm,ier) if (nproc_space_comm /= 1) then #if defined HAVE_MPI2 && defined HAVE_MPI2_INPLACE call MPI_ALLREDUCE(MPI_IN_PLACE,xval,n1,MPI_DOUBLE_PRECISION,MPI_SUM,comm,ier) #else ABI_STAT_ALLOCATE(xsum,(n1), ier) if (ier/= 0) call xmpi_abort(msg='error allocating xsum in xmpi_sum_dpn') call MPI_ALLREDUCE(xval,xsum,n1,MPI_DOUBLE_PRECISION,MPI_SUM,comm,ier) xval (:) = xsum(:) ABI_DEALLOCATE(xsum) #endif end if end if #endif end subroutine xmpi_sum_dpn !!*** !---------------------------------------------------------------------- !!****f* ABINIT/xmpi_sum_dp2d !! NAME !! xmpi_sum_dp2d !! !! FUNCTION !! Combines values from all processes and distribute !! the result back to all processes. !! Target: double precision two-dimensional arrays. !! !! INPUTS !! comm= MPI communicator !! !! OUTPUT !! ier= exit status, a non-zero value meaning there is an error !! !! SIDE EFFECTS !! xval= buffer array !! !! SOURCE subroutine xmpi_sum_dp2d(xval,comm,ier) !This section has been created automatically by the script Abilint (TD). !Do not modify the following lines by hand. #undef ABI_FUNC #define ABI_FUNC 'xmpi_sum_dp2d' !End of the abilint section implicit none !Arguments------------------------- real(dp), DEV_CONTARRD intent(inout) :: xval(:,:) integer ,intent(in) :: comm integer ,intent(out) :: ier !Local variables------------------- #if defined HAVE_MPI integer :: n1,n2,nproc_space_comm real(dp),allocatable :: xsum(:,:) #endif ! ************************************************************************* ier=0 #if defined HAVE_MPI if (comm /= MPI_COMM_SELF .and. comm /= MPI_COMM_NULL) then call MPI_COMM_SIZE(comm,nproc_space_comm,ier) if (nproc_space_comm /= 1) then n1 = size(xval,dim=1) n2 = size(xval,dim=2) ! Accumulate xval on all proc. in comm #if defined HAVE_MPI2 && defined HAVE_MPI2_INPLACE call MPI_ALLREDUCE(MPI_IN_PLACE,xval,n1*n2,MPI_DOUBLE_PRECISION,MPI_SUM,comm,ier) #else ABI_STAT_ALLOCATE(xsum,(n1,n2), ier) if (ier/= 0) call xmpi_abort(msg='error allocating xsum in xmpi_sum_dp2d') call MPI_ALLREDUCE(xval,xsum,n1*n2,MPI_DOUBLE_PRECISION,MPI_SUM,comm,ier) xval (:,:) = xsum(:,:) ABI_DEALLOCATE(xsum) #endif end if end if #endif end subroutine xmpi_sum_dp2d !!*** !---------------------------------------------------------------------- !!****f* ABINIT/xmpi_sum_dp3d !! NAME !! xmpi_sum_dp3d !! !! FUNCTION !! Combines values from all processes and distribute !! the result back to all processes. !! Target: double precision three-dimensional arrays. !! !! INPUTS !! comm= MPI communicator !! !! OUTPUT !! ier= exit status, a non-zero value meaning there is an error !! !! SIDE EFFECTS !! xval= buffer array !! !! SOURCE subroutine xmpi_sum_dp3d(xval,comm,ier) !This section has been created automatically by the script Abilint (TD). !Do not modify the following lines by hand. #undef ABI_FUNC #define ABI_FUNC 'xmpi_sum_dp3d' !End of the abilint section implicit none !Arguments------------------------- real(dp), DEV_CONTARRD intent(inout) :: xval(:,:,:) integer ,intent(in) :: comm integer ,intent(out) :: ier !Local variables------------------- #if defined HAVE_MPI integer :: n1,n2,n3,nproc_space_comm real(dp),allocatable :: xsum(:,:,:) #endif ! ************************************************************************* ier=0 #if defined HAVE_MPI if (comm /= MPI_COMM_SELF .and. comm /= MPI_COMM_NULL) then call MPI_COMM_SIZE(comm,nproc_space_comm,ier) if (nproc_space_comm /= 1) then n1 = size(xval,dim=1) n2 = size(xval,dim=2) n3 = size(xval,dim=3) ! Accumulate xval on all proc. in comm #if defined HAVE_MPI2 && defined HAVE_MPI2_INPLACE call MPI_ALLREDUCE(MPI_IN_PLACE,xval,n1*n2*n3,MPI_DOUBLE_PRECISION,MPI_SUM,comm,ier) #else ABI_STAT_ALLOCATE(xsum,(n1,n2,n3), ier) if (ier/= 0) call xmpi_abort(msg='error allocating xsum in xmpi_sum_dp3d') call MPI_ALLREDUCE(xval,xsum,n1*n2*n3,MPI_DOUBLE_PRECISION,MPI_SUM,comm,ier) xval (:,:,:) = xsum(:,:,:) ABI_DEALLOCATE(xsum) #endif end if end if #endif end subroutine xmpi_sum_dp3d !!*** !---------------------------------------------------------------------- !!****f* ABINIT/xmpi_sum_dp4d !! NAME !! xmpi_sum_dp4d !! !! FUNCTION !! Combines values from all processes and distribute !! the result back to all processes. !! Target: double precision four-dimensional arrays. !! !! INPUTS !! comm= MPI communicator !! !! OUTPUT !! ier= exit status, a non-zero value meaning there is an error !! !! SIDE EFFECTS !! xval= buffer array !! !! SOURCE subroutine xmpi_sum_dp4d(xval,comm,ier) !This section has been created automatically by the script Abilint (TD). !Do not modify the following lines by hand. #undef ABI_FUNC #define ABI_FUNC 'xmpi_sum_dp4d' !End of the abilint section implicit none !Arguments------------------------- real(dp),DEV_CONTARRD intent(inout) :: xval(:,:,:,:) integer ,intent(in) :: comm integer ,intent(out) :: ier !Local variables------------------- #if defined HAVE_MPI integer :: n1,n2,n3,n4,nproc_space_comm real(dp),allocatable :: xsum(:,:,:,:) #endif ! ************************************************************************* ier=0 #if defined HAVE_MPI if (comm /= MPI_COMM_SELF .and. comm /= MPI_COMM_NULL) then call MPI_COMM_SIZE(comm,nproc_space_comm,ier) if (nproc_space_comm /= 1) then n1 = size(xval,dim=1) n2 = size(xval,dim=2) n3 = size(xval,dim=3) n4 = size(xval,dim=4) ! Accumulate xval on all proc. in comm #if defined HAVE_MPI2 && defined HAVE_MPI2_INPLACE call MPI_ALLREDUCE(MPI_IN_PLACE,xval,n1*n2*n3*n4,MPI_DOUBLE_PRECISION,MPI_SUM,comm,ier) #else ABI_STAT_ALLOCATE(xsum,(n1,n2,n3,n4), ier) if (ier/= 0) call xmpi_abort(msg='error allocating xsum in xmpi_sum_dp4d') call MPI_ALLREDUCE(xval,xsum,n1*n2*n3*n4,MPI_DOUBLE_PRECISION,MPI_SUM,comm,ier) xval (:,:,:,:) = xsum(:,:,:,:) ABI_DEALLOCATE(xsum) #endif end if end if #endif end subroutine xmpi_sum_dp4d !!*** !---------------------------------------------------------------------- !!****f* ABINIT/xmpi_sum_dp5d !! NAME !! xmpi_sum_dp5d !! !! FUNCTION !! Combines values from all processes and distribute !! the result back to all processes. !! Target: double precision five-dimensional arrays. !! !! INPUTS !! comm= MPI communicator !! !! OUTPUT !! ier= exit status, a non-zero value meaning there is an error !! !! SIDE EFFECTS !! xval= buffer array !! !! SOURCE subroutine xmpi_sum_dp5d(xval,comm,ier) !This section has been created automatically by the script Abilint (TD). !Do not modify the following lines by hand. #undef ABI_FUNC #define ABI_FUNC 'xmpi_sum_dp5d' !End of the abilint section implicit none !Arguments------------------------- real(dp), DEV_CONTARRD intent(inout) :: xval(:,:,:,:,:) integer ,intent(in) :: comm integer ,intent(out) :: ier !Local variables------------------- #if defined HAVE_MPI integer :: n1,n2,n3,n4,n5,nproc_space_comm real(dp),allocatable :: xsum(:,:,:,:,:) #endif ! ************************************************************************* ier=0 #if defined HAVE_MPI if (comm /= MPI_COMM_SELF .and. comm /= MPI_COMM_NULL) then call MPI_COMM_SIZE(comm,nproc_space_comm,ier) if (nproc_space_comm /= 1) then n1 = size(xval,dim=1) n2 = size(xval,dim=2) n3 = size(xval,dim=3) n4 = size(xval,dim=4) n5 = size(xval,dim=5) ! Accumulate xval on all proc. in comm #if defined HAVE_MPI2 && defined HAVE_MPI2_INPLACE call MPI_ALLREDUCE(MPI_IN_PLACE,xval,n1*n2*n3*n4*n5,MPI_DOUBLE_PRECISION,MPI_SUM,comm,ier) #else ABI_STAT_ALLOCATE(xsum,(n1,n2,n3,n4,n5), ier) if (ier/= 0) call xmpi_abort(msg='error allocating xsum in xmpi_sum_dp5d') call MPI_ALLREDUCE(xval,xsum,n1*n2*n3*n4*n5,MPI_DOUBLE_PRECISION,MPI_SUM,comm,ier) xval (:,:,:,:,:) = xsum(:,:,:,:,:) ABI_DEALLOCATE(xsum) #endif end if end if #endif end subroutine xmpi_sum_dp5d !!*** !---------------------------------------------------------------------- !!****f* ABINIT/xmpi_sum_dp6d !! NAME !! xmpi_sum_dp6d !! !! FUNCTION !! Combines values from all processes and distribute !! the result back to all processes. !! Target: double precision six-dimensional arrays. !! !! INPUTS !! comm= MPI communicator !! !! OUTPUT !! ier= exit status, a non-zero value meaning there is an error !! !! SIDE EFFECTS !! xval= buffer array !! !! SOURCE subroutine xmpi_sum_dp6d(xval,comm,ier) !This section has been created automatically by the script Abilint (TD). !Do not modify the following lines by hand. #undef ABI_FUNC #define ABI_FUNC 'xmpi_sum_dp6d' !End of the abilint section implicit none !Arguments------------------------- real(dp), DEV_CONTARRD intent(inout) :: xval(:,:,:,:,:,:) integer ,intent(in) :: comm integer ,intent(out) :: ier !Local variables------------------- #if defined HAVE_MPI integer :: n1,n2,n3,n4,n5,n6,nproc_space_comm real(dp), allocatable :: xsum(:,:,:,:,:,:) #endif ! ************************************************************************* ier=0 #if defined HAVE_MPI if (comm /= MPI_COMM_SELF .and. comm /= MPI_COMM_NULL) then call MPI_COMM_SIZE(comm,nproc_space_comm,ier) if (nproc_space_comm /= 1) then n1 = size(xval,dim=1) n2 = size(xval,dim=2) n3 = size(xval,dim=3) n4 = size(xval,dim=4) n5 = size(xval,dim=5) n6 = size(xval,dim=6) ! Accumulate xval on all proc. in comm #if defined HAVE_MPI2 && defined HAVE_MPI2_INPLACE call MPI_ALLREDUCE(MPI_IN_PLACE,xval,n1*n2*n3*n4*n5*n6,MPI_DOUBLE_PRECISION,MPI_SUM,comm,ier) #else ABI_STAT_ALLOCATE(xsum,(n1,n2,n3,n4,n5,n6), ier) if (ier/=0) call xmpi_abort(msg='error allocating xsum in xmpi_sum_dp6d') call MPI_ALLREDUCE(xval,xsum,n1*n2*n3*n4*n5*n6,MPI_DOUBLE_PRECISION,MPI_SUM,comm,ier) xval (:,:,:,:,:,:) = xsum(:,:,:,:,:,:) ABI_DEALLOCATE(xsum) #endif end if end if #endif end subroutine xmpi_sum_dp6d !!*** !---------------------------------------------------------------------- !!****f* ABINIT/xmpi_sum_dp7d !! NAME !! xmpi_sum_dp7d !! !! FUNCTION !! Combines values from all processes and distribute !! the result back to all processes. !! Target: double precision six-dimensional arrays. !! !! INPUTS !! comm= MPI communicator !! !! OUTPUT !! ier= exit status, a non-zero value meaning there is an error !! !! SIDE EFFECTS !! xval= buffer array !! !! SOURCE subroutine xmpi_sum_dp7d(xval,comm,ier) !This section has been created automatically by the script Abilint (TD). !Do not modify the following lines by hand. #undef ABI_FUNC #define ABI_FUNC 'xmpi_sum_dp7d' !End of the abilint section implicit none !Arguments------------------------- real(dp), DEV_CONTARRD intent(inout) :: xval(:,:,:,:,:,:,:) integer ,intent(in) :: comm integer ,intent(out) :: ier !Local variables------------------- #if defined HAVE_MPI integer :: n1,n2,n3,n4,n5,n6,n7,nproc_space_comm real(dp),allocatable :: xsum(:,:,:,:,:,:,:) #endif ! ************************************************************************* ier=0 #if defined HAVE_MPI if (comm /= MPI_COMM_SELF .and. comm /= MPI_COMM_NULL) then call MPI_COMM_SIZE(comm,nproc_space_comm,ier) if (nproc_space_comm /= 1) then n1 = size(xval,dim=1) n2 = size(xval,dim=2) n3 = size(xval,dim=3) n4 = size(xval,dim=4) n5 = size(xval,dim=5) n6 = size(xval,dim=6) n7 = size(xval,dim=7) ! Accumulate xval on all proc. in comm #if defined HAVE_MPI2 && defined HAVE_MPI2_INPLACE call MPI_ALLREDUCE(MPI_IN_PLACE,xval,n1*n2*n3*n4*n5*n6*n7,MPI_DOUBLE_PRECISION,MPI_SUM,comm,ier) #else ABI_STAT_ALLOCATE(xsum,(n1,n2,n3,n4,n5,n6,n7), ier) if (ier/= 0) call xmpi_abort(msg='error allocating xsum in xmpi_sum_dp7d') call MPI_ALLREDUCE(xval,xsum,n1*n2*n3*n4*n5*n6*n7,MPI_DOUBLE_PRECISION,MPI_SUM,comm,ier) xval (:,:,:,:,:,:,:) = xsum(:,:,:,:,:,:,:) ABI_DEALLOCATE(xsum) #endif end if end if #endif end subroutine xmpi_sum_dp7d !!*** !---------------------------------------------------------------------- !!****f* ABINIT/xmpi_sum_dp2t !! NAME !! xmpi_sum_dp2t !! !! FUNCTION !! Combines values from all processes and distribute !! the result back to all processes. !! Target: double precision one-dimensional array without transfers. !! !! INPUTS !! n1= first dimension of the array !! comm= MPI communicator !! !! OUTPUT !! ier= exit status, a non-zero value meaning there is an error !! !! SIDE EFFECTS !! xval= buffer array !! xsum= receive buffer !! !! SOURCE subroutine xmpi_sum_dp2t(xval,xsum,n1,comm,ier) !This section has been created automatically by the script Abilint (TD). !Do not modify the following lines by hand. #undef ABI_FUNC #define ABI_FUNC 'xmpi_sum_dp2t' !End of the abilint section implicit none !Arguments------------------------- real(dp), DEV_CONTARRD intent(inout) :: xval(:),xsum(:) integer ,intent(in) :: n1 integer ,intent(in) :: comm integer ,intent(out) :: ier ! ************************************************************************* ier=0 #if defined HAVE_MPI if (comm /= MPI_COMM_SELF .and. comm /= MPI_COMM_NULL) then ! Accumulate xval on all proc. in comm call MPI_ALLREDUCE(xval,xsum,n1,MPI_DOUBLE_PRECISION,MPI_SUM,comm,ier) else #endif xsum=xval #if defined HAVE_MPI end if #endif end subroutine xmpi_sum_dp2t !!*** !---------------------------------------------------------------------- !!****f* ABINIT/xmpi_sum_dp2d2t !! NAME !! xmpi_sum_dp2d2t !! !! FUNCTION !! Combines values from all processes and distribute !! the result back to all processes. !! Target: double precisions bi-dimensional array !! !! INPUTS !! n = total send size !! xval= buffer array !! spaceComm= MPI communicator !! !! OUTPUT !! xsum= receive buffer !! ier= exit status, a non-zero value meaning there is an error !! !! SOURCE subroutine xmpi_sum_dp2d2t(xval,xsum,n,spaceComm,ier) !This section has been created automatically by the script Abilint (TD). !Do not modify the following lines by hand. #undef ABI_FUNC #define ABI_FUNC 'xmpi_sum_dp2d2t' !End of the abilint section implicit none !Arguments------------------------- real(dp), DEV_CONTARRD intent(in) :: xval(:,:) real(dp), DEV_CONTARRD intent(out) :: xsum(:,:) integer ,intent(in) :: n integer ,intent(in) :: spaceComm integer ,intent(out) :: ier !Local variables------------------- #if defined HAVE_MPI integer :: nproc_space_comm #endif ! ************************************************************************* ier=0 #if defined HAVE_MPI !Accumulate xval on all proc. in spaceComm if (spaceComm /= MPI_COMM_SELF .and. spaceComm /= MPI_COMM_NULL) then call MPI_ALLREDUCE(xval,xsum,n,MPI_DOUBLE_PRECISION,MPI_SUM,spaceComm,ier) else #endif xsum=xval #if defined HAVE_MPI end if #endif end subroutine xmpi_sum_dp2d2t !!*** !---------------------------------------------------------------------- !!****f* ABINIT/xmpi_sum_dp3d2t !! NAME !! xmpi_sum_dp3d2t !! !! FUNCTION !! Combines values from all processes and distribute !! the result back to all processes. !! Target: double precision three-dimensional array without transfers. !! !! INPUTS !! n1= first dimension of the array !! comm= MPI communicator !! !! OUTPUT !! ier= exit status, a non-zero value meaning there is an error !! !! SIDE EFFECTS !! xval= buffer array !! xsum= receive buffer !! !! SOURCE subroutine xmpi_sum_dp3d2t(xval,xsum,n1,comm,ier) !This section has been created automatically by the script Abilint (TD). !Do not modify the following lines by hand. #undef ABI_FUNC #define ABI_FUNC 'xmpi_sum_dp3d2t' !End of the abilint section implicit none !Arguments------------------------- real(dp), DEV_CONTARRD intent(inout) :: xval(:,:,:),xsum(:,:,:) integer ,intent(in) :: n1 integer ,intent(in) :: comm integer ,intent(out) :: ier ! ************************************************************************* ier=0 #if defined HAVE_MPI if (comm /= MPI_COMM_SELF .and. comm /= MPI_COMM_NULL) then ! Accumulate xval on all proc. in comm call MPI_ALLREDUCE(xval,xsum,n1,MPI_DOUBLE_PRECISION,MPI_SUM,comm,ier) else #endif xsum=xval #if defined HAVE_MPI end if #endif end subroutine xmpi_sum_dp3d2t !!*** !---------------------------------------------------------------------- !!****f* ABINIT/xmpi_sum_dp4d2t !! NAME !! xmpi_sum_dp4d2t !! !! FUNCTION !! Combines values from all processes and distribute !! the result back to all processes. !! Target: double precision four-dimensional array without transfers. !! !! INPUTS !! n1= first dimension of the array !! comm= MPI communicator !! !! OUTPUT !! ier= exit status, a non-zero value meaning there is an error !! !! SIDE EFFECTS !! xval= buffer array !! xsum= receive buffer !! !! SOURCE subroutine xmpi_sum_dp4d2t(xval,xsum,n1,comm,ier) !This section has been created automatically by the script Abilint (TD). !Do not modify the following lines by hand. #undef ABI_FUNC #define ABI_FUNC 'xmpi_sum_dp4d2t' !End of the abilint section implicit none !Arguments------------------------- real(dp), DEV_CONTARRD intent(inout) :: xval(:,:,:,:),xsum(:,:,:,:) integer ,intent(in) :: n1 integer ,intent(in) :: comm integer ,intent(out) :: ier ! ************************************************************************* ier=0 #if defined HAVE_MPI if (comm /= MPI_COMM_SELF .and. comm /= MPI_COMM_NULL) then ! Accumulate xval on all proc. in comm call MPI_ALLREDUCE(xval,xsum,n1,MPI_DOUBLE_PRECISION,MPI_SUM,comm,ier) else #endif xsum=xval #if defined HAVE_MPI end if #endif end subroutine xmpi_sum_dp4d2t !!*** !---------------------------------------------------------------------- !!****f* ABINIT/xmpi_sum_c0dc !! NAME !! xmpi_sum_c0dc !! !! FUNCTION !! Combines values from all processes and distribute the result back to all processes. !! Target: double complex scalar !! !! INPUTS !! comm= MPI communicator !! !! OUTPUT !! ier= exit status, a non-zero value meaning there is an error !! !! SIDE EFFECTS !! xval= scalar to be summed. !! !! SOURCE subroutine xmpi_sum_c0dc(xval,comm,ier) !This section has been created automatically by the script Abilint (TD). !Do not modify the following lines by hand. #undef ABI_FUNC #define ABI_FUNC 'xmpi_sum_c0dc' !End of the abilint section implicit none !Arguments------------------------- complex(dpc),intent(inout) :: xval integer,intent(in) :: comm integer,intent(out) :: ier !Local variables------------------- #if defined HAVE_MPI integer :: nproc_space_comm complex(dpc) :: xsum #endif ! ************************************************************************* ier=0 #if defined HAVE_MPI if (comm /= MPI_COMM_SELF .and. comm /= MPI_COMM_NULL) then call MPI_COMM_SIZE(comm,nproc_space_comm,ier) if (nproc_space_comm /= 1) then ! Accumulate xval on all proc. in comm call MPI_ALLREDUCE(xval,xsum,1,MPI_DOUBLE_COMPLEX,MPI_SUM,comm,ier) xval = xsum end if end if #endif end subroutine xmpi_sum_c0dc !!*** !---------------------------------------------------------------------- !!****f* ABINIT/xmpi_sum_c1dc !! NAME !! xmpi_sum_c1dc !! !! FUNCTION !! Combines values from all processes and distribute !! the result back to all processes. !! Target: one-dimensional double complex arrays. !! !! INPUTS !! comm= MPI communicator !! !! OUTPUT !! ier= exit status, a non-zero value meaning there is an error !! !! SIDE EFFECTS !! xval= buffer array !! !! SOURCE subroutine xmpi_sum_c1dc(xval,comm,ier) !This section has been created automatically by the script Abilint (TD). !Do not modify the following lines by hand. #undef ABI_FUNC #define ABI_FUNC 'xmpi_sum_c1dc' !End of the abilint section implicit none !Arguments------------------------- complex(dpc), DEV_CONTARRD intent(inout) :: xval(:) integer,intent(in) :: comm integer,intent(out) :: ier !Local variables------------------- #if defined HAVE_MPI integer :: n1,nproc_space_comm complex(dpc) , allocatable :: xsum(:) #endif ! ************************************************************************* ier=0 #if defined HAVE_MPI if (comm /= MPI_COMM_SELF .and. comm /= MPI_COMM_NULL) then call MPI_COMM_SIZE(comm,nproc_space_comm,ier) if (nproc_space_comm /= 1) then ! Accumulate xval on all proc. in comm n1 =size(xval,dim=1) #if defined HAVE_MPI2 && defined HAVE_MPI2_INPLACE call MPI_ALLREDUCE(MPI_IN_PLACE,xval,n1,MPI_DOUBLE_COMPLEX,MPI_SUM,comm,ier) #else ABI_STAT_ALLOCATE(xsum,(n1), ier) if (ier/= 0) call xmpi_abort(msg='error allocating xsum in xmpi_sum_c1dc') call MPI_ALLREDUCE(xval,xsum,n1,MPI_DOUBLE_COMPLEX,MPI_SUM,comm,ier) xval (:) = xsum(:) ABI_DEALLOCATE(xsum) #endif end if end if #endif end subroutine xmpi_sum_c1dc !!*** !---------------------------------------------------------------------- !!****f* ABINIT/xmpi_sum_c2dc !! NAME !! xmpi_sum_c2dc !! !! FUNCTION !! Combines values from all processes and distribute !! the result back to all processes. !! Target: two-dimensional double complex arrays. !! !! INPUTS !! comm= MPI communicator !! !! OUTPUT !! ier= exit status, a non-zero value meaning there is an error !! !! SIDE EFFECTS !! xval= buffer array !! !! SOURCE subroutine xmpi_sum_c2dc(xval,comm,ier) !This section has been created automatically by the script Abilint (TD). !Do not modify the following lines by hand. #undef ABI_FUNC #define ABI_FUNC 'xmpi_sum_c2dc' !End of the abilint section implicit none !Arguments------------------------- complex(dpc), DEV_CONTARRD intent(inout) :: xval(:,:) integer,intent(in) :: comm integer,intent(out) :: ier !Local variables------------------- #if defined HAVE_MPI integer :: n1,n2, nproc_space_comm complex(dpc),allocatable :: xsum(:,:) #endif ! ************************************************************************* ier=0 #if defined HAVE_MPI if (comm /= MPI_COMM_SELF .and. comm /= MPI_COMM_NULL) then call MPI_COMM_SIZE(comm,nproc_space_comm,ier) if (nproc_space_comm /= 1) then ! Accumulate xval on all proc. in comm n1 =size(xval,dim=1) n2 =size(xval,dim=2) #if defined HAVE_MPI2 && defined HAVE_MPI2_INPLACE call MPI_ALLREDUCE(MPI_IN_PLACE,xval,n1*n2,MPI_DOUBLE_COMPLEX,MPI_SUM,comm,ier) #else ABI_STAT_ALLOCATE(xsum,(n1,n2), ier) if (ier/= 0) call xmpi_abort(msg='error allocating xsum in xmpi_sum_c2dc') call MPI_ALLREDUCE(xval,xsum,n1*n2,MPI_DOUBLE_COMPLEX,MPI_SUM,comm,ier) xval (:,:) = xsum(:,:) ABI_DEALLOCATE(xsum) #endif end if end if #endif end subroutine xmpi_sum_c2dc !!*** !---------------------------------------------------------------------- !!****f* ABINIT/xmpi_sum_c3dc !! NAME !! xmpi_sum_c3dc !! !! FUNCTION !! Combines values from all processes and distribute !! the result back to all processes. !! Target: three-dimensional double complex arrays. !! !! INPUTS !! comm= MPI communicator !! !! OUTPUT !! ier= exit status, a non-zero value meaning there is an error !! !! SIDE EFFECTS !! xval= buffer array !! !! SOURCE subroutine xmpi_sum_c3dc(xval,comm,ier) !This section has been created automatically by the script Abilint (TD). !Do not modify the following lines by hand. #undef ABI_FUNC #define ABI_FUNC 'xmpi_sum_c3dc' !End of the abilint section implicit none !Arguments------------------------- complex(dpc), DEV_CONTARRD intent(inout) :: xval(:,:,:) integer,intent(in) :: comm integer,intent(out) :: ier !Local variables------------------- #if defined HAVE_MPI integer :: n1,n2,n3,nproc_space_comm complex(dpc),allocatable :: xsum(:,:,:) #endif ! ************************************************************************* ier=0 #if defined HAVE_MPI if (comm /= MPI_COMM_SELF .and. comm /= MPI_COMM_NULL) then call MPI_COMM_SIZE(comm,nproc_space_comm,ier) if (nproc_space_comm /= 1) then ! Accumulate xval on all proc. in comm n1 =size(xval,dim=1) n2 =size(xval,dim=2) n3 =size(xval,dim=3) #if defined HAVE_MPI2 && defined HAVE_MPI2_INPLACE call MPI_ALLREDUCE(MPI_IN_PLACE,xval,n1*n2*n3,MPI_DOUBLE_COMPLEX,MPI_SUM,comm,ier) #else ABI_STAT_ALLOCATE(xsum,(n1,n2,n3), ier) if (ier/= 0) call xmpi_abort(msg='error allocating xsum in xmpi_sum_c3dc') call MPI_ALLREDUCE(xval,xsum,n1*n2*n3,MPI_DOUBLE_COMPLEX,MPI_SUM,comm,ier) xval (:,:,:) = xsum(:,:,:) ABI_DEALLOCATE(xsum) #endif end if end if #endif end subroutine xmpi_sum_c3dc !!*** !---------------------------------------------------------------------- !!****f* ABINIT/xmpi_sum_c4dc !! NAME !! xmpi_sum_c4dc !! !! FUNCTION !! Combines values from all processes and distribute !! the result back to all processes. !! Target: four-dimensional double complex arrays. !! !! INPUTS !! comm= MPI communicator !! !! OUTPUT !! ier= exit status, a non-zero value meaning there is an error !! !! SIDE EFFECTS !! xval= buffer array !! !! SOURCE subroutine xmpi_sum_c4dc(xval,comm,ier) !This section has been created automatically by the script Abilint (TD). !Do not modify the following lines by hand. #undef ABI_FUNC #define ABI_FUNC 'xmpi_sum_c4dc' !End of the abilint section implicit none !Arguments------------------------- complex(dpc), DEV_CONTARRD intent(inout) :: xval(:,:,:,:) integer,intent(in) :: comm integer,intent(out) :: ier !Local variables------------------- #if defined HAVE_MPI integer :: n1,n2,n3,n4,nproc_space_comm complex(dpc),allocatable :: xsum(:,:,:,:) #endif ! ************************************************************************* ier=0 #if defined HAVE_MPI if (comm /= MPI_COMM_SELF .and. comm /= MPI_COMM_NULL) then call MPI_COMM_SIZE(comm,nproc_space_comm,ier) if (nproc_space_comm /= 1) then ! Accumulate xval on all proc. in comm n1 =size(xval,dim=1) n2 =size(xval,dim=2) n3 =size(xval,dim=3) n4 =size(xval,dim=4) #if defined HAVE_MPI2 && defined HAVE_MPI2_INPLACE call MPI_ALLREDUCE(MPI_IN_PLACE,xval,n1*n2*n3*n4,MPI_DOUBLE_COMPLEX,MPI_SUM,comm,ier) #else ABI_STAT_ALLOCATE(xsum,(n1,n2,n3,n4), ier) if (ier/= 0) call xmpi_abort(msg='error allocating xsum in xmpi_sum_c4dc') call MPI_ALLREDUCE(xval,xsum,n1*n2*n3*n4,MPI_DOUBLE_COMPLEX,MPI_SUM,comm,ier) xval (:,:,:,:) = xsum(:,:,:,:) ABI_DEALLOCATE(xsum) #endif end if end if #endif end subroutine xmpi_sum_c4dc !!*** !---------------------------------------------------------------------- !!****f* ABINIT/xmpi_sum_c5dc !! NAME !! xmpi_sum_c5dc !! !! FUNCTION !! Combines values from all processes and distribute the result back to all processes. !! Target: five-dimensional double precision complex arrays. !! !! INPUTS !! comm= MPI communicator !! !! OUTPUT !! ier= exit status, a non-zero value meaning there is an error !! !! SIDE EFFECTS !! xval= buffer array !! !! SOURCE subroutine xmpi_sum_c5dc(xval,comm,ier) !This section has been created automatically by the script Abilint (TD). !Do not modify the following lines by hand. #undef ABI_FUNC #define ABI_FUNC 'xmpi_sum_c5dc' !End of the abilint section implicit none !Arguments------------------------- complex(dpc), DEV_CONTARRD intent(inout) :: xval(:,:,:,:,:) integer,intent(in) :: comm integer,intent(out) :: ier !Local variables------------------- #if defined HAVE_MPI integer :: n1,n2,n3,n4,n5,nproc_space_comm complex(dpc),allocatable :: xsum(:,:,:,:,:) #endif ! ************************************************************************* ier=0 #if defined HAVE_MPI if (comm /= MPI_COMM_SELF .and. comm /= MPI_COMM_NULL) then call MPI_COMM_SIZE(comm,nproc_space_comm,ier) if (nproc_space_comm /= 1) then !Accumulate xval on all proc. in comm n1 =size(xval,dim=1) n2 =size(xval,dim=2) n3 =size(xval,dim=3) n4 =size(xval,dim=4) n5 =size(xval,dim=5) #if defined HAVE_MPI2 && defined HAVE_MPI2_INPLACE call MPI_ALLREDUCE(MPI_IN_PLACE,xval,n1*n2*n3*n4*n5,MPI_DOUBLE_COMPLEX,MPI_SUM,comm,ier) #else ABI_STAT_ALLOCATE(xsum,(n1,n2,n3,n4,n5), ier) if (ier/=0) call xmpi_abort(comm,msg='error allocating xsum in xmpi_sum_c5dc') call MPI_ALLREDUCE(xval,xsum,n1*n2*n3*n4*n5,MPI_DOUBLE_COMPLEX,MPI_SUM,comm,ier) xval (:,:,:,:,:) = xsum(:,:,:,:,:) ABI_DEALLOCATE(xsum) #endif end if end if #endif end subroutine xmpi_sum_c5dc !!*** !---------------------------------------------------------------------- !!****f* ABINIT/xmpi_sum_c6dc !! NAME !! xmpi_sum_c6dc !! !! FUNCTION !! Combines values from all processes and distribute the result back to all processes. !! Target: six-dimensional double precision complex arrays. !! !! INPUTS !! comm= MPI communicator !! !! OUTPUT !! ier= exit status, a non-zero value meaning there is an error !! !! SIDE EFFECTS !! xval= buffer array !! !! SOURCE subroutine xmpi_sum_c6dc(xval,comm,ier) !This section has been created automatically by the script Abilint (TD). !Do not modify the following lines by hand. #undef ABI_FUNC #define ABI_FUNC 'xmpi_sum_c6dc' !End of the abilint section implicit none !Arguments------------------------- complex(dpc), DEV_CONTARRD intent(inout) :: xval(:,:,:,:,:,:) integer,intent(in) :: comm integer,intent(out) :: ier !Local variables------------------- #if defined HAVE_MPI integer :: n1,n2,n3,n4,n5,n6,nproc_space_comm complex(dpc),allocatable :: xsum(:,:,:,:,:,:) #endif ! ************************************************************************* ier=0 #if defined HAVE_MPI if (comm /= MPI_COMM_SELF .and. comm /= MPI_COMM_NULL) then call MPI_COMM_SIZE(comm,nproc_space_comm,ier) if (nproc_space_comm /= 1) then !Accumulate xval on all proc. in comm n1 =size(xval,dim=1) n2 =size(xval,dim=2) n3 =size(xval,dim=3) n4 =size(xval,dim=4) n5 =size(xval,dim=5) n6 =size(xval,dim=6) #if defined HAVE_MPI2 && defined HAVE_MPI2_INPLACE call MPI_ALLREDUCE(MPI_IN_PLACE,xval,n1*n2*n3*n4*n5*n6,MPI_DOUBLE_COMPLEX,MPI_SUM,comm,ier) #else ABI_STAT_ALLOCATE(xsum,(n1,n2,n3,n4,n5,n6), ier) if (ier/=0) call xmpi_abort(msg='error allocating xsum in xmpi_sum_c6dc') call MPI_ALLREDUCE(xval,xsum,n1*n2*n3*n4*n5*n6,MPI_DOUBLE_COMPLEX,MPI_SUM,comm,ier) xval = xsum ABI_DEALLOCATE(xsum) #endif end if end if #endif end subroutine xmpi_sum_c6dc !!*** !---------------------------------------------------------------------- !!****f* ABINIT/xmpi_sum_c7dc !! NAME !! xmpi_sum_c7dc !! !! FUNCTION !! Combines values from all processes and distribute the result back to all processes. !! Target: six-dimensional double precision complex arrays. !! !! INPUTS !! comm= MPI communicator !! !! OUTPUT !! ier= exit status, a non-zero value meaning there is an error !! !! SIDE EFFECTS !! xval= buffer array !! !! SOURCE subroutine xmpi_sum_c7dc(xval,comm,ier) !This section has been created automatically by the script Abilint (TD). !Do not modify the following lines by hand. #undef ABI_FUNC #define ABI_FUNC 'xmpi_sum_c7dc' !End of the abilint section implicit none !Arguments------------------------- complex(dpc), DEV_CONTARRD intent(inout) :: xval(:,:,:,:,:,:,:) integer,intent(in) :: comm integer,intent(out) :: ier !Local variables------------------- #if defined HAVE_MPI integer :: n1,n2,n3,n4,n5,n6,n7,nproc_space_comm complex(dpc),allocatable :: xsum(:,:,:,:,:,:,:) #endif ! ************************************************************************* ier=0 #if defined HAVE_MPI if (comm /= MPI_COMM_SELF .and. comm /= MPI_COMM_NULL) then call MPI_COMM_SIZE(comm,nproc_space_comm,ier) if (nproc_space_comm /= 1) then !Accumulate xval on all proc. in comm n1 =size(xval,dim=1) n2 =size(xval,dim=2) n3 =size(xval,dim=3) n4 =size(xval,dim=4) n5 =size(xval,dim=5) n6 =size(xval,dim=6) n7 =size(xval,dim=7) #if defined HAVE_MPI2 && defined HAVE_MPI2_INPLACE call MPI_ALLREDUCE(MPI_IN_PLACE,xval,n1*n2*n3*n4*n5*n6*n7,MPI_DOUBLE_COMPLEX,MPI_SUM,comm,ier) #else ABI_STAT_ALLOCATE(xsum,(n1,n2,n3,n4,n5,n6,n7),ier) if (ier/=0) then call xmpi_abort(comm=comm,msg='error allocating xsum in xmpi_sum_c7dc') end if call MPI_ALLREDUCE(xval,xsum,n1*n2*n3*n4*n5*n6*n7,MPI_DOUBLE_COMPLEX,MPI_SUM,comm,ier) xval = xsum ABI_DEALLOCATE(xsum) #endif end if end if #endif end subroutine xmpi_sum_c7dc !!*** !---------------------------------------------------------------------- !!****f* ABINIT/xmpi_sum_c1cplx !! NAME !! xmpi_sum_c1cplx !! !! FUNCTION !! Combines values from all processes and distribute !! the result back to all processes. !! Target: one-dimensional complex arrays. !! !! INPUTS !! comm= MPI communicator !! !! OUTPUT !! ier= exit status, a non-zero value meaning there is an error !! !! SIDE EFFECTS !! xval= buffer array !! !! SOURCE subroutine xmpi_sum_c1cplx(xval,comm,ier) !This section has been created automatically by the script Abilint (TD). !Do not modify the following lines by hand. #undef ABI_FUNC #define ABI_FUNC 'xmpi_sum_c1cplx' !End of the abilint section implicit none !Arguments---------------- complex(spc), DEV_CONTARRD intent(inout) :: xval(:) integer,intent(in) :: comm integer,intent(out) :: ier !Local variables-------------- #if defined HAVE_MPI integer :: n1,nproc_space_comm complex(spc),allocatable :: xsum(:) #endif ! ************************************************************************* ier=0 #if defined HAVE_MPI if (comm /= MPI_COMM_SELF .and. comm /= MPI_COMM_NULL) then call MPI_COMM_SIZE(comm,nproc_space_comm,ier) if (nproc_space_comm /= 1) then ! Accumulate xval on all proc. in comm n1 =size(xval,dim=1) #if defined HAVE_MPI2 && defined HAVE_MPI2_INPLACE call MPI_ALLREDUCE(MPI_IN_PLACE,xval,n1,MPI_COMPLEX,MPI_SUM,comm,ier) #else ABI_STAT_ALLOCATE(xsum,(n1), ier) if (ier/= 0) call xmpi_abort(msg='error allocating xsum in xmpi_sum_c1cplx') call MPI_ALLREDUCE(xval,xsum,n1,MPI_COMPLEX,MPI_SUM,comm,ier) xval (:) = xsum(:) ABI_DEALLOCATE(xsum) #endif end if end if #endif end subroutine xmpi_sum_c1cplx !!*** !---------------------------------------------------------------------- !!****f* ABINIT/xmpi_sum_c2cplx !! NAME !! xmpi_sum_c2cplx !! !! FUNCTION !! Combines values from all processes and distribute !! the result back to all processes. !! Target: two-dimensional complex arrays. !! !! INPUTS !! comm= MPI communicator !! !! OUTPUT !! ier= exit status, a non-zero value meaning there is an error !! !! SIDE EFFECTS !! xval= buffer array !! !! SOURCE subroutine xmpi_sum_c2cplx(xval,comm,ier) !This section has been created automatically by the script Abilint (TD). !Do not modify the following lines by hand. #undef ABI_FUNC #define ABI_FUNC 'xmpi_sum_c2cplx' !End of the abilint section implicit none !Arguments---------------- complex(spc), DEV_CONTARRD intent(inout) :: xval(:,:) integer,intent(in) :: comm integer,intent(out) :: ier !Local variables-------------- #if defined HAVE_MPI integer :: n1,n2,nproc_space_comm complex(spc), allocatable :: xsum(:,:) #endif ! ************************************************************************* ier=0 #if defined HAVE_MPI if (comm /= MPI_COMM_SELF .and. comm /= MPI_COMM_NULL) then call MPI_COMM_SIZE(comm,nproc_space_comm,ier) if (nproc_space_comm /= 1) then ! Accumulate xval on all proc. in comm n1 =size(xval,dim=1) n2 =size(xval,dim=2) #if defined HAVE_MPI2 && defined HAVE_MPI2_INPLACE call MPI_ALLREDUCE(MPI_IN_PLACE,xval,n1*n2,MPI_COMPLEX,MPI_SUM,comm,ier) #else ABI_STAT_ALLOCATE(xsum,(n1,n2), ier) if (ier/= 0) call xmpi_abort(msg='error allocating xsum in xmpi_sum_c2cplx') call MPI_ALLREDUCE(xval,xsum,n1*n2,MPI_COMPLEX,MPI_SUM,comm,ier) xval (:,:) = xsum(:,:) ABI_DEALLOCATE(xsum) #endif end if end if #endif end subroutine xmpi_sum_c2cplx !!*** !---------------------------------------------------------------------- !!****f* ABINIT/xmpi_sum_c3cplx !! NAME !! xmpi_sum_c3cplx !! !! FUNCTION !! Combines values from all processes and distribute !! the result back to all processes. !! Target: three-dimensional complex arrays. !! !! INPUTS !! comm= MPI communicator !! !! OUTPUT !! ier= exit status, a non-zero value meaning there is an error !! !! SIDE EFFECTS !! xval= buffer array !! !! PARENTS !! !! CHILDREN !! mpi_allreduce,xmpi_abort !! !! SOURCE subroutine xmpi_sum_c3cplx(xval,comm,ier) !This section has been created automatically by the script Abilint (TD). !Do not modify the following lines by hand. #undef ABI_FUNC #define ABI_FUNC 'xmpi_sum_c3cplx' !End of the abilint section implicit none !Arguments---------------- complex(spc), DEV_CONTARRD intent(inout) :: xval(:,:,:) integer,intent(in) :: comm integer,intent(out) :: ier !Local variables-------------- #if defined HAVE_MPI integer :: n1,n2,n3,nproc_space_comm complex(spc), allocatable :: xsum(:,:,:) #endif ! ************************************************************************* ier=0 #if defined HAVE_MPI if (comm /= MPI_COMM_SELF .and. comm /= MPI_COMM_NULL) then call MPI_COMM_SIZE(comm,nproc_space_comm,ier) if (nproc_space_comm /= 1) then ! Accumulate xval on all proc. in comm n1 =size(xval,dim=1) n2 =size(xval,dim=2) n3 =size(xval,dim=3) #if defined HAVE_MPI2 && defined HAVE_MPI2_INPLACE call MPI_ALLREDUCE(MPI_IN_PLACE,xval,n1*n2*n3,MPI_COMPLEX,MPI_SUM,comm,ier) #else ABI_STAT_ALLOCATE(xsum,(n1,n2,n3), ier) if (ier/= 0) call xmpi_abort(msg='error allocating xsum in xmpi_sum_c3cplx') call MPI_ALLREDUCE(xval,xsum,n1*n2*n3,MPI_COMPLEX,MPI_SUM,comm,ier) xval (:,:,:) = xsum(:,:,:) ABI_DEALLOCATE(xsum) #endif end if end if #endif end subroutine xmpi_sum_c3cplx !!*** !---------------------------------------------------------------------- !!****f* ABINIT/xmpi_sum_c4cplx !! NAME !! xmpi_sum_c4cplx !! !! FUNCTION !! Combines values from all processes and distribute !! the result back to all processes. !! Target: four-dimensional complex arrays. !! !! INPUTS !! comm= MPI communicator !! !! OUTPUT !! ier= exit status, a non-zero value meaning there is an error !! !! SIDE EFFECTS !! xval= buffer array !! !! PARENTS !! !! CHILDREN !! mpi_allreduce,xmpi_abort !! !! SOURCE subroutine xmpi_sum_c4cplx(xval,comm,ier) !This section has been created automatically by the script Abilint (TD). !Do not modify the following lines by hand. #undef ABI_FUNC #define ABI_FUNC 'xmpi_sum_c4cplx' !End of the abilint section implicit none !Arguments---------------- complex(spc), DEV_CONTARRD intent(inout) :: xval(:,:,:,:) integer,intent(in) :: comm integer,intent(out) :: ier !Local variables-------------- #if defined HAVE_MPI integer :: n1,n2,n3,n4,nproc_space_comm complex(spc),allocatable :: xsum(:,:,:,:) #endif ! ************************************************************************* ier=0 #if defined HAVE_MPI if (comm /= MPI_COMM_SELF .and. comm /= MPI_COMM_NULL) then call MPI_COMM_SIZE(comm,nproc_space_comm,ier) if (nproc_space_comm /= 1) then ! Accumulate xval on all proc. in comm n1 =size(xval,dim=1) n2 =size(xval,dim=2) n3 =size(xval,dim=3) n4 =size(xval,dim=4) #if defined HAVE_MPI2 && defined HAVE_MPI2_INPLACE call MPI_ALLREDUCE(MPI_IN_PLACE,xval,n1*n2*n3*n4,MPI_COMPLEX,MPI_SUM,comm,ier) #else ABI_STAT_ALLOCATE(xsum,(n1,n2,n3,n4), ier) if (ier/= 0) call xmpi_abort(msg='error allocating xsum in xmpi_sum_c4cplx') call MPI_ALLREDUCE(xval,xsum,n1*n2*n3*n4,MPI_COMPLEX,MPI_SUM,comm,ier) xval (:,:,:,:) = xsum(:,:,:,:) ABI_DEALLOCATE(xsum) #endif end if end if #endif end subroutine xmpi_sum_c4cplx !!*** !---------------------------------------------------------------------- !!****f* ABINIT/xmpi_sum_c5cplx !! NAME !! xmpi_sum_c5cplx !! !! FUNCTION !! Combines values from all processes and distribute !! the result back to all processes. !! Target: five-dimensional complex arrays. !! !! INPUTS !! comm= MPI communicator !! !! OUTPUT !! ier= exit status, a non-zero value meaning there is an error !! !! SIDE EFFECTS !! xval= buffer array !! !! SOURCE subroutine xmpi_sum_c5cplx(xval,comm,ier) !This section has been created automatically by the script Abilint (TD). !Do not modify the following lines by hand. #undef ABI_FUNC #define ABI_FUNC 'xmpi_sum_c5cplx' !End of the abilint section implicit none !Arguments---------------- complex(spc), DEV_CONTARRD intent(inout) :: xval(:,:,:,:,:) integer,intent(in) :: comm integer,intent(out) :: ier !Local variables-------------- #if defined HAVE_MPI integer :: n1,n2,n3,n4,n5,nproc_space_comm complex(spc),allocatable :: xsum(:,:,:,:,:) #endif ! ************************************************************************* ier=0 #if defined HAVE_MPI if (comm /= MPI_COMM_SELF .and. comm /= MPI_COMM_NULL) then call MPI_COMM_SIZE(comm,nproc_space_comm,ier) if (nproc_space_comm /= 1) then ! Accumulate xval on all proc. in comm n1 =size(xval,dim=1) n2 =size(xval,dim=2) n3 =size(xval,dim=3) n4 =size(xval,dim=4) n5 =size(xval,dim=5) #if defined HAVE_MPI2 && defined HAVE_MPI2_INPLACE call MPI_ALLREDUCE(MPI_IN_PLACE,xval,n1*n2*n3*n4*n5,MPI_COMPLEX,MPI_SUM,comm,ier) #else ABI_STAT_ALLOCATE(xsum,(n1,n2,n3,n4,n5), ier) if (ier/= 0) call xmpi_abort(msg='error allocating xsum in xmpi_sum_c5cplx') call MPI_ALLREDUCE(xval,xsum,n1*n2*n3*n4*n5,MPI_COMPLEX,MPI_SUM,comm,ier) xval (:,:,:,:,:) = xsum(:,:,:,:,:) ABI_DEALLOCATE(xsum) #endif end if end if #endif end subroutine xmpi_sum_c5cplx !!*** !---------------------------------------------------------------------- !!****f* ABINIT/xmpi_sum_c6cplx !! NAME !! xmpi_sum_c6cplx !! !! FUNCTION !! Combines values from all processes and distribute the result back to all processes. !! Target: six-dimensional complex arrays. !! !! INPUTS !! comm= MPI communicator !! !! OUTPUT !! ier= exit status, a non-zero value meaning there is an error !! !! SIDE EFFECTS !! xval= buffer array !! !! SOURCE subroutine xmpi_sum_c6cplx(xval,comm,ier) !This section has been created automatically by the script Abilint (TD). !Do not modify the following lines by hand. #undef ABI_FUNC #define ABI_FUNC 'xmpi_sum_c6cplx' !End of the abilint section implicit none !Arguments---------------- complex(spc), DEV_CONTARRD intent(inout) :: xval(:,:,:,:,:,:) integer,intent(in) :: comm integer,intent(out) :: ier !Local variables-------------- #if defined HAVE_MPI integer :: n1,n2,n3,n4,n5,n6,nproc_space_comm complex(spc),allocatable :: xsum(:,:,:,:,:,:) #endif ! ************************************************************************* ier=0 #if defined HAVE_MPI if (comm /= MPI_COMM_SELF .and. comm /= MPI_COMM_NULL) then call MPI_COMM_SIZE(comm,nproc_space_comm,ier) if (nproc_space_comm /= 1) then ! Accumulate xval on all proc. in comm n1 =size(xval,dim=1) n2 =size(xval,dim=2) n3 =size(xval,dim=3) n4 =size(xval,dim=4) n5 =size(xval,dim=5) n6 =size(xval,dim=6) #if defined HAVE_MPI2 && defined HAVE_MPI2_INPLACE call MPI_ALLREDUCE(MPI_IN_PLACE,xval,n1*n2*n3*n4*n5*n6,MPI_COMPLEX,MPI_SUM,comm,ier) #else ABI_STAT_ALLOCATE(xsum,(n1,n2,n3,n4,n5,n6), ier) if (ier/= 0) call xmpi_abort(msg='error allocating xsum in xmpi_sum_c6cplx') call MPI_ALLREDUCE(xval,xsum,n1*n2*n3*n4*n5*n6,MPI_COMPLEX,MPI_SUM,comm,ier) xval = xsum ABI_DEALLOCATE(xsum) #endif end if end if #endif end subroutine xmpi_sum_c6cplx !!*** v_sim-3.8.0/lib/plug-ins/abinit/xmpi_sum_master.finc000066400000000000000000001036671370110300500224710ustar00rootroot00000000000000!{\src2tex{textfont=tt}} !!****f* ABINIT/xmpi_sum_master !! NAME !! xmpi_sum_master !! !! FUNCTION !! This module contains functions that calls MPI routine, !! if we compile the code using the MPI CPP flags. !! xmpi_sum_master is the generic function. !! !! COPYRIGHT !! Copyright (C) 2001-2016 ABINIT group (AR,XG,MB) !! This file is distributed under the terms of the !! GNU General Public License, see ~ABINIT/COPYING !! or http://www.gnu.org/copyleft/gpl.txt . !! !! SOURCE !!*** !!****f* ABINIT/xmpi_sum_master_int !! NAME !! xmpi_sum_master_int !! !! FUNCTION !! Reduces values on all processes to a single value. !! Target: integer scalars. !! !! INPUTS !! master= master MPI node !! spaceComm= MPI communicator !! !! OUTPUT !! ier= exit status, a non-zero value meaning there is an error !! !! SIDE EFFECTS !! xval= buffer array !! !! SOURCE subroutine xmpi_sum_master_int(xval,master,spaceComm,ier) !This section has been created automatically by the script Abilint (TD). !Do not modify the following lines by hand. #undef ABI_FUNC #define ABI_FUNC 'xmpi_sum_master_int' !End of the abilint section implicit none !Arguments------------------------- integer,intent(inout) :: xval integer ,intent(in) :: master integer ,intent(in) :: spaceComm integer ,intent(out) :: ier !Local variables------------------- #if defined HAVE_MPI integer :: xsum integer :: nproc_space_comm #endif ! ************************************************************************* ier=0 #if defined HAVE_MPI if (spaceComm /= MPI_COMM_NULL) then call MPI_COMM_SIZE(spaceComm,nproc_space_comm,ier) if (nproc_space_comm /= 1) then ! Accumulate xval on all proc. in spaceComm call MPI_REDUCE(xval,xsum,1,MPI_INTEGER,MPI_SUM,master,spaceComm,ier) xval = xsum end if end if #endif end subroutine xmpi_sum_master_int !!*** !!****f* ABINIT/xmpi_sum_master_int2d !! NAME !! xmpi_sum_master_int2d !! !! FUNCTION !! Reduces values on all processes to a single value. !! Target: two-dimensional integer arrays. !! !! INPUTS !! master= master MPI node !! spaceComm= MPI communicator !! !! OUTPUT !! ier= exit status, a non-zero value meaning there is an error !! !! SIDE EFFECTS !! xval= buffer array !! !! SOURCE subroutine xmpi_sum_master_int2d(xval,master,spaceComm,ier) !This section has been created automatically by the script Abilint (TD). !Do not modify the following lines by hand. #undef ABI_FUNC #define ABI_FUNC 'xmpi_sum_master_int2d' !End of the abilint section implicit none !Arguments ------------------------------------ integer, DEV_CONTARRD intent(inout) :: xval(:,:) integer,intent(in) :: master,spaceComm integer,intent(out) :: ier !Local variables------------------------------- #if defined HAVE_MPI integer :: n1,n2 integer, allocatable :: xsum(:,:) integer :: nproc_space_comm #endif ! ************************************************************************* ier=0 #if defined HAVE_MPI if (spaceComm /= MPI_COMM_NULL) then call MPI_COMM_SIZE(spaceComm,nproc_space_comm,ier) if (nproc_space_comm /= 1) then n1 = size(xval,dim=1) n2 = size(xval,dim=2) ! Accumulate xval on all proc. in spaceComm ABI_STAT_ALLOCATE(xsum,(n1,n2), ier) if (ier /= 0) call xmpi_abort(msg='error allocating xsum') call MPI_reduce(xval,xsum,n1*n2,MPI_INTEGER,MPI_SUM,master,spaceComm,ier) xval = xsum ABI_DEALLOCATE(xsum) end if end if #endif end subroutine xmpi_sum_master_int2d !!*** !!****f* ABINIT/xmpi_sum_master_dp1d !! NAME !! xmpi_sum_master_dp1d !! !! FUNCTION !! Reduces values on all processes to a single value. !! Target: double precision one-dimensional arrays. !! !! INPUTS !! master= master MPI node !! spaceComm= MPI communicator !! !! OUTPUT !! ier= exit status, a non-zero value meaning there is an error !! !! SIDE EFFECTS !! xval= buffer array !! !! SOURCE subroutine xmpi_sum_master_dp1d(xval,master,spaceComm,ier) !This section has been created automatically by the script Abilint (TD). !Do not modify the following lines by hand. #undef ABI_FUNC #define ABI_FUNC 'xmpi_sum_master_dp1d' !End of the abilint section implicit none !Arguments------------------------- real(dp), DEV_CONTARRD intent(inout) :: xval(:) integer ,intent(in) :: master integer ,intent(in) :: spaceComm integer ,intent(out) :: ier !Local variables------------------- #if defined HAVE_MPI integer :: n1 real(dp) , allocatable :: xsum(:) integer :: nproc_space_comm #endif ! ************************************************************************* ier=0 #if defined HAVE_MPI if (spaceComm /= MPI_COMM_NULL) then call MPI_COMM_SIZE(spaceComm,nproc_space_comm,ier) if (nproc_space_comm /= 1) then n1 = size(xval,dim=1) ! Accumulate xval on all proc. in spaceComm ABI_STAT_ALLOCATE(xsum,(n1), ier) if (ier /= 0) call xmpi_abort(msg='error allocating xsum') call MPI_REDUCE(xval,xsum,n1,MPI_DOUBLE_PRECISION,MPI_SUM,master,spaceComm,ier) xval (:) = xsum(:) ABI_DEALLOCATE(xsum) end if end if #endif end subroutine xmpi_sum_master_dp1d !!*** !!****f* ABINIT/xmpi_sum_master_dp2d !! NAME !! xmpi_sum_master_dp2d !! !! FUNCTION !! Reduces values on all processes to a single value. !! Target: double precision two-dimensional arrays. !! !! INPUTS !! master= master MPI node !! spaceComm= MPI communicator !! !! OUTPUT !! ier= exit status, a non-zero value meaning there is an error !! !! SIDE EFFECTS !! xval= buffer array !! !! SOURCE subroutine xmpi_sum_master_dp2d(xval,master,spaceComm,ier) !This section has been created automatically by the script Abilint (TD). !Do not modify the following lines by hand. #undef ABI_FUNC #define ABI_FUNC 'xmpi_sum_master_dp2d' !End of the abilint section implicit none !Arguments------------------------- real(dp), DEV_CONTARRD intent(inout) :: xval(:,:) integer ,intent(in) :: master integer ,intent(in) :: spaceComm integer ,intent(out) :: ier !Local variables------------------- #if defined HAVE_MPI integer :: n1,n2 real(dp) , allocatable :: xsum(:,:) integer :: nproc_space_comm #endif ! ************************************************************************* ier=0 #if defined HAVE_MPI if (spaceComm /= MPI_COMM_NULL) then call MPI_COMM_SIZE(spaceComm,nproc_space_comm,ier) if (nproc_space_comm /= 1) then n1 = size(xval,dim=1) n2 = size(xval,dim=2) ! Accumulate xval on all proc. in spaceComm ABI_STAT_ALLOCATE(xsum,(n1,n2), ier) if (ier /= 0) call xmpi_abort(msg='error allocating xsum') call MPI_REDUCE(xval,xsum,n1*n2,MPI_DOUBLE_PRECISION,MPI_SUM,master,spaceComm,ier) xval (:,:) = xsum(:,:) ABI_DEALLOCATE(xsum) end if end if #endif end subroutine xmpi_sum_master_dp2d !!*** !!****f* ABINIT/xmpi_sum_master_dp3d !! NAME !! xmpi_sum_master_dp3d !! !! FUNCTION !! Reduces values on all processes to a single value. !! Target: double precision three-dimensional arrays. !! !! INPUTS !! master= master MPI node !! spaceComm= MPI communicator !! !! OUTPUT !! ier= exit status, a non-zero value meaning there is an error !! !! SIDE EFFECTS !! xval= buffer array !! !! SOURCE subroutine xmpi_sum_master_dp3d(xval,master,spaceComm,ier) !This section has been created automatically by the script Abilint (TD). !Do not modify the following lines by hand. #undef ABI_FUNC #define ABI_FUNC 'xmpi_sum_master_dp3d' !End of the abilint section implicit none !Arguments------------------------- real(dp), DEV_CONTARRD intent(inout) :: xval(:,:,:) integer ,intent(in) :: master integer ,intent(in) :: spaceComm integer ,intent(out) :: ier !Local variables------------------- #if defined HAVE_MPI integer :: n1,n2,n3 real(dp) , allocatable :: xsum(:,:,:) integer :: nproc_space_comm #endif ! ************************************************************************* ier=0 #if defined HAVE_MPI if (spaceComm /= MPI_COMM_NULL) then call MPI_COMM_SIZE(spaceComm,nproc_space_comm,ier) if (nproc_space_comm /= 1) then n1 = size(xval,dim=1) n2 = size(xval,dim=2) n3 = size(xval,dim=3) ! Accumulate xval on all proc. in spaceComm ABI_STAT_ALLOCATE(xsum,(n1,n2,n3), ier) if (ier /= 0) call xmpi_abort(msg='error allocating xsum') call MPI_REDUCE(xval,xsum,n1*n2*n3,MPI_DOUBLE_PRECISION,MPI_SUM,master,spaceComm,ier) xval (:,:,:) = xsum(:,:,:) ABI_DEALLOCATE(xsum) end if end if #endif end subroutine xmpi_sum_master_dp3d !!*** !!****f* ABINIT/xmpi_sum_master_dp4d !! NAME !! xmpi_sum_master_dp4d !! !! FUNCTION !! Reduces values on all processes to a single value. !! Target: double precision four-dimensional arrays. !! !! INPUTS !! master= master MPI node !! spaceComm= MPI communicator !! !! OUTPUT !! ier= exit status, a non-zero value meaning there is an error !! !! SIDE EFFECTS !! xval= buffer array !! !! SOURCE subroutine xmpi_sum_master_dp4d(xval,master,spaceComm,ier) !This section has been created automatically by the script Abilint (TD). !Do not modify the following lines by hand. #undef ABI_FUNC #define ABI_FUNC 'xmpi_sum_master_dp4d' !End of the abilint section implicit none !Arguments------------------------- real(dp), DEV_CONTARRD intent(inout) :: xval(:,:,:,:) integer ,intent(in) :: master integer ,intent(in) :: spaceComm integer ,intent(out) :: ier !Local variables------------------- #if defined HAVE_MPI integer :: n1,n2,n3,n4 real(dp) , allocatable :: xsum(:,:,:,:) integer :: nproc_space_comm #endif ! ************************************************************************* ier=0 #if defined HAVE_MPI if (spaceComm /= MPI_COMM_NULL) then call MPI_COMM_SIZE(spaceComm,nproc_space_comm,ier) if (nproc_space_comm /= 1) then n1 = size(xval,dim=1) n2 = size(xval,dim=2) n3 = size(xval,dim=3) n4 = size(xval,dim=4) ! Accumulate xval on all proc. in spaceComm ABI_STAT_ALLOCATE(xsum,(n1,n2,n3,n4), ier) if (ier /= 0) call xmpi_abort(msg='error allocating xsum') call MPI_REDUCE(xval,xsum,n1*n2*n3*n4,MPI_DOUBLE_PRECISION,MPI_SUM,master,spaceComm,ier) xval (:,:,:,:) = xsum(:,:,:,:) ABI_DEALLOCATE(xsum) end if end if #endif end subroutine xmpi_sum_master_dp4d !!*** !!****f* ABINIT/xmpi_sum_master_dp5d !! NAME !! xmpi_sum_master_dp5d !! !! FUNCTION !! Reduces values on all processes to a single value. !! Target: double precision five-dimensional arrays. !! !! INPUTS !! master= master MPI node !! spaceComm= MPI communicator !! !! OUTPUT !! ier= exit status, a non-zero value meaning there is an error !! !! SIDE EFFECTS !! xval= buffer array !! !! SOURCE subroutine xmpi_sum_master_dp5d(xval,master,spaceComm,ier) !This section has been created automatically by the script Abilint (TD). !Do not modify the following lines by hand. #undef ABI_FUNC #define ABI_FUNC 'xmpi_sum_master_dp5d' !End of the abilint section implicit none !Arguments ------------------------------------ real(dp), DEV_CONTARRD intent(inout) :: xval(:,:,:,:,:) integer ,intent(in) :: master integer ,intent(in) :: spaceComm integer ,intent(out) :: ier !Local variables------------------------------- #if defined HAVE_MPI integer :: n1,n2,n3,n4,n5 real(dp), allocatable :: xsum(:,:,:,:,:) integer :: nproc_space_comm #endif ! ************************************************************************* ier=0 #if defined HAVE_MPI if (spaceComm /= MPI_COMM_NULL) then call MPI_COMM_SIZE(spaceComm,nproc_space_comm,ier) if (nproc_space_comm /= 1) then n1 = size(xval,dim=1) n2 = size(xval,dim=2) n3 = size(xval,dim=3) n4 = size(xval,dim=4) n5 = size(xval,dim=5) ! Accumulate xval on all proc. in spaceComm ABI_STAT_ALLOCATE(xsum,(n1,n2,n3,n4,n5), ier) if (ier /= 0) call xmpi_abort(msg='error allocating xsum') call MPI_reduce(xval,xsum,n1*n2*n3*n4*n5,MPI_DOUBLE_PRECISION,MPI_SUM,master,spaceComm,ier) xval (:,:,:,:,:) = xsum(:,:,:,:,:) ABI_DEALLOCATE(xsum) end if end if #endif end subroutine xmpi_sum_master_dp5d !!*** !!****f* ABINIT/xmpi_sum_master_dp6d !! NAME !! xmpi_sum_master_dp6d !! !! FUNCTION !! Reduces values on all processes to a single value. !! Target: double precision six-dimensional arrays. !! !! INPUTS !! master= master MPI node !! spaceComm= MPI communicator !! !! OUTPUT !! ier= exit status, a non-zero value meaning there is an error !! !! SIDE EFFECTS !! xval= buffer array !! !! SOURCE subroutine xmpi_sum_master_dp6d(xval,master,spaceComm,ier) !This section has been created automatically by the script Abilint (TD). !Do not modify the following lines by hand. #undef ABI_FUNC #define ABI_FUNC 'xmpi_sum_master_dp6d' !End of the abilint section implicit none !Arguments ------------------------------------ real(dp), DEV_CONTARRD intent(inout) :: xval(:,:,:,:,:,:) integer ,intent(in) :: master integer ,intent(in) :: spaceComm integer ,intent(out) :: ier !Local variables------------------------------- #if defined HAVE_MPI integer :: n1,n2,n3,n4,n5,n6 real(dp), allocatable :: xsum(:,:,:,:,:,:) integer :: nproc_space_comm #endif ! ************************************************************************* ier=0 #if defined HAVE_MPI if (spaceComm /= MPI_COMM_NULL) then call MPI_COMM_SIZE(spaceComm,nproc_space_comm,ier) if (nproc_space_comm /= 1) then n1 = size(xval,dim=1) n2 = size(xval,dim=2) n3 = size(xval,dim=3) n4 = size(xval,dim=4) n5 = size(xval,dim=5) n6 = size(xval,dim=6) ! Accumulate xval on all proc. in spaceComm ABI_STAT_ALLOCATE(xsum,(n1,n2,n3,n4,n5,n6), ier) if (ier /= 0) call xmpi_abort(msg='error allocating xsum') call MPI_reduce(xval,xsum,n1*n2*n3*n4*n5*n6,MPI_DOUBLE_PRECISION,MPI_SUM,master,spaceComm,ier) xval (:,:,:,:,:,:) = xsum(:,:,:,:,:,:) ABI_DEALLOCATE(xsum) end if end if #endif end subroutine xmpi_sum_master_dp6d !!*** !!****f* ABINIT/xmpi_sum_master_dp7d !! NAME !! xmpi_sum_master_dp7d !! !! FUNCTION !! Reduces values on all processes to a single value. !! Target: double precision seven-dimensional arrays. !! !! INPUTS !! master= master MPI node !! spaceComm= MPI communicator !! !! OUTPUT !! ier= exit status, a non-zero value meaning there is an error !! !! SIDE EFFECTS !! xval= buffer array !! !! SOURCE subroutine xmpi_sum_master_dp7d(xval,master,spaceComm,ier) !This section has been created automatically by the script Abilint (TD). !Do not modify the following lines by hand. #undef ABI_FUNC #define ABI_FUNC 'xmpi_sum_master_dp7d' !End of the abilint section implicit none !Arguments ------------------------------------ real(dp), DEV_CONTARRD intent(inout) :: xval(:,:,:,:,:,:,:) integer ,intent(in) :: master integer ,intent(in) :: spaceComm integer ,intent(out) :: ier !Local variables------------------------------- #if defined HAVE_MPI integer :: n1,n2,n3,n4,n5,n6,n7 real(dp), allocatable :: xsum(:,:,:,:,:,:,:) integer :: nproc_space_comm #endif ! ************************************************************************* ier=0 #if defined HAVE_MPI if (spaceComm /= MPI_COMM_NULL) then call MPI_COMM_SIZE(spaceComm,nproc_space_comm,ier) if (nproc_space_comm /= 1) then n1 = size(xval,dim=1) n2 = size(xval,dim=2) n3 = size(xval,dim=3) n4 = size(xval,dim=4) n5 = size(xval,dim=5) n6 = size(xval,dim=6) n7 = size(xval,dim=7) ! Accumulate xval on all proc. in spaceComm ABI_STAT_ALLOCATE(xsum,(n1,n2,n3,n4,n5,n6,n7), ier) if (ier /= 0) call xmpi_abort(msg='error allocating xsum') call MPI_reduce(xval,xsum,n1*n2*n3*n4*n5*n6*n7,MPI_DOUBLE_PRECISION,MPI_SUM,master,spaceComm,ier) xval (:,:,:,:,:,:,:) = xsum(:,:,:,:,:,:,:) ABI_DEALLOCATE(xsum) end if end if #endif end subroutine xmpi_sum_master_dp7d !!*** !!****f* ABINIT/xmpi_sum_master_int4d !! NAME !! xmpi_sum_master_int4d !! !! FUNCTION !! Reduces values on all processes to a single value. !! Target: four-diemnsional integer arrays. !! !! INPUTS !! master= master MPI node !! spaceComm= MPI communicator !! !! OUTPUT !! ier= exit status, a non-zero value meaning there is an error !! !! SIDE EFFECTS !! xval= buffer array !! !! SOURCE subroutine xmpi_sum_master_int4d(xval,master,spaceComm,ier) !This section has been created automatically by the script Abilint (TD). !Do not modify the following lines by hand. #undef ABI_FUNC #define ABI_FUNC 'xmpi_sum_master_int4d' !End of the abilint section implicit none !Arguments ------------------------------------ integer, DEV_CONTARRD intent(inout) :: xval(:,:,:,:) integer,intent(in) :: master integer,intent(in) :: spaceComm integer,intent(out) :: ier !Local variables------------------------------- #if defined HAVE_MPI integer :: n1,n2,n3,n4 integer, allocatable :: xsum(:,:,:,:) integer :: nproc_space_comm #endif ! ************************************************************************* ier=0 #if defined HAVE_MPI if (spaceComm /= MPI_COMM_NULL) then call MPI_COMM_SIZE(spaceComm,nproc_space_comm,ier) if (nproc_space_comm /= 1) then n1 = size(xval,dim=1) n2 = size(xval,dim=2) n3 = size(xval,dim=3) n4 = size(xval,dim=4) ! Accumulate xval on all proc. in spaceComm ABI_STAT_ALLOCATE(xsum,(n1,n2,n3,n4), ier) if (ier /= 0) call xmpi_abort(msg='error allocating xsum') call MPI_reduce(xval,xsum,n1*n2*n3*n4,MPI_INTEGER,MPI_SUM,master,spaceComm,ier) xval (:,:,:,:) = xsum(:,:,:,:) ABI_DEALLOCATE(xsum) end if end if #endif end subroutine xmpi_sum_master_int4d !!*** !!****f* ABINIT/xmpi_sum_master_c1cplx !! NAME !! xmpi_sum_master_c1cplx !! !! FUNCTION !! Reduces values on all processes to a single value. !! Target: one-dimensional complex arrays. !! !! INPUTS !! master= master MPI node !! spaceComm= MPI communicator !! !! OUTPUT !! ier= exit status, a non-zero value meaning there is an error !! !! SIDE EFFECTS !! xval= buffer array !! !! SOURCE subroutine xmpi_sum_master_c1cplx(xval,master,spaceComm,ier) !This section has been created automatically by the script Abilint (TD). !Do not modify the following lines by hand. #undef ABI_FUNC #define ABI_FUNC 'xmpi_sum_master_c1cplx' !End of the abilint section implicit none !Arguments------------------------- complex(spc), DEV_CONTARRD intent(inout) :: xval(:) integer ,intent(in) :: master integer ,intent(in) :: spaceComm integer ,intent(out) :: ier !Local variables------------------- #if defined HAVE_MPI integer :: n1,nproc_space_comm complex(spc),allocatable :: xsum(:) #endif ! ************************************************************************* ier=0 #if defined HAVE_MPI if (spaceComm /= MPI_COMM_NULL) then call MPI_COMM_SIZE(spaceComm,nproc_space_comm,ier) if (nproc_space_comm /= 1) then n1 = size(xval,dim=1) ! Collect xval from processors on master in spaceComm ABI_STAT_ALLOCATE(xsum,(n1), ier) if (ier /= 0) call xmpi_abort(msg='error allocating xsum') call MPI_REDUCE(xval,xsum,n1,MPI_COMPLEX,MPI_SUM,master,spaceComm,ier) xval = xsum ABI_DEALLOCATE(xsum) end if end if #endif end subroutine xmpi_sum_master_c1cplx !!*** !!****f* ABINIT/xmpi_sum_master_c2cplx !! NAME !! xmpi_sum_master_c2cplx !! !! FUNCTION !! Reduces values on all processes to a single value. !! Target: two-dimensional complex arrays. !! !! INPUTS !! master= master MPI node !! spaceComm= MPI communicator !! !! OUTPUT !! ier= exit status, a non-zero value meaning there is an error !! !! SIDE EFFECTS !! xval= buffer array !! !! SOURCE subroutine xmpi_sum_master_c2cplx(xval,master,spaceComm,ier) !This section has been created automatically by the script Abilint (TD). !Do not modify the following lines by hand. #undef ABI_FUNC #define ABI_FUNC 'xmpi_sum_master_c2cplx' !End of the abilint section implicit none !Arguments------------------------- complex(spc), DEV_CONTARRD intent(inout) :: xval(:,:) integer,intent(in) :: master integer,intent(in) :: spaceComm integer,intent(out) :: ier !Local variables------------------- #if defined HAVE_MPI integer :: n1,n2 integer :: nproc_space_comm complex(spc),allocatable :: xsum(:,:) #endif ! ************************************************************************* ier=0 #if defined HAVE_MPI if (spaceComm /= MPI_COMM_NULL) then call MPI_COMM_SIZE(spaceComm,nproc_space_comm,ier) if (nproc_space_comm /= 1) then n1 = size(xval,dim=1) n2 = size(xval,dim=2) ! Collect xval from processors on master in spaceComm ABI_STAT_ALLOCATE(xsum,(n1,n2), ier) if (ier /= 0) call xmpi_abort(msg='error allocating xsum') call MPI_REDUCE(xval,xsum,n1*n2,MPI_COMPLEX,MPI_SUM,master,spaceComm,ier) xval (:,:) = xsum(:,:) ABI_DEALLOCATE(xsum) end if end if #endif end subroutine xmpi_sum_master_c2cplx !!*** !!****f* ABINIT/xmpi_sum_master_c3cplx !! NAME !! xmpi_sum_master_c3cplx !! !! FUNCTION !! Reduces values on all processes to a single value. !! Target: three-dimensional complex arrays. !! !! INPUTS !! master= master MPI node !! spaceComm= MPI communicator !! !! OUTPUT !! ier= exit status, a non-zero value meaning there is an error !! !! SIDE EFFECTS !! xval= buffer array !! !! SOURCE subroutine xmpi_sum_master_c3cplx(xval,master,spaceComm,ier) !This section has been created automatically by the script Abilint (TD). !Do not modify the following lines by hand. #undef ABI_FUNC #define ABI_FUNC 'xmpi_sum_master_c3cplx' !End of the abilint section implicit none !Arguments------------------------- complex(spc), DEV_CONTARRD intent(inout) :: xval(:,:,:) integer,intent(in) :: master integer,intent(in) :: spaceComm integer,intent(out) :: ier !Local variables------------------- #if defined HAVE_MPI integer :: n1,n2,n3 complex(spc), allocatable :: xsum(:,:,:) integer :: nproc_space_comm #endif ! ************************************************************************* ier=0 #if defined HAVE_MPI if (spaceComm /= MPI_COMM_NULL) then call MPI_COMM_SIZE(spaceComm,nproc_space_comm,ier) if (nproc_space_comm /= 1) then n1 = size(xval,dim=1) n2 = size(xval,dim=2) n3 = size(xval,dim=3) ! Collect xval from processors on master in spaceComm ABI_STAT_ALLOCATE(xsum,(n1,n2,n3), ier) if (ier /= 0) call xmpi_abort(msg='error allocating xsum') call MPI_REDUCE(xval,xsum,n1*n2*n3,MPI_COMPLEX,MPI_SUM,master,spaceComm,ier) xval (:,:,:) = xsum(:,:,:) ABI_DEALLOCATE(xsum) end if end if #endif end subroutine xmpi_sum_master_c3cplx !!*** !!****f* ABINIT/xmpi_sum_master_c4cplx !! NAME !! xmpi_sum_master_c4cplx !! !! FUNCTION !! Reduces values on all processes to a single value. !! Target: four-dimensional complex arrays. !! !! INPUTS !! master= master MPI node !! spaceComm= MPI communicator !! !! OUTPUT !! ier= exit status, a non-zero value meaning there is an error !! !! SIDE EFFECTS !! xval= buffer array !! !! SOURCE subroutine xmpi_sum_master_c4cplx(xval,master,spaceComm,ier) !This section has been created automatically by the script Abilint (TD). !Do not modify the following lines by hand. #undef ABI_FUNC #define ABI_FUNC 'xmpi_sum_master_c4cplx' !End of the abilint section implicit none !Arguments------------------------- complex(spc), DEV_CONTARRD intent(inout) :: xval(:,:,:,:) integer,intent(in) :: master integer,intent(in) :: spaceComm integer,intent(out) :: ier !Local variables------------------- #if defined HAVE_MPI integer :: n1,n2,n3,n4 integer :: nproc_space_comm complex(spc), allocatable :: xsum(:,:,:,:) #endif ! ************************************************************************* ier=0 #if defined HAVE_MPI if (spaceComm /= MPI_COMM_NULL) then call MPI_COMM_SIZE(spaceComm,nproc_space_comm,ier) if (nproc_space_comm /= 1) then n1 = size(xval,dim=1) n2 = size(xval,dim=2) n3 = size(xval,dim=3) n4 = size(xval,dim=4) ! Collect xval from processors on master in spaceComm ABI_STAT_ALLOCATE(xsum,(n1,n2,n3,n4), ier) if (ier /= 0) call xmpi_abort(msg='error allocating xsum') call MPI_REDUCE(xval,xsum,n1*n2*n3*n4,MPI_COMPLEX,MPI_SUM,master,spaceComm,ier) xval (:,:,:,:) = xsum(:,:,:,:) ABI_DEALLOCATE(xsum) end if end if #endif end subroutine xmpi_sum_master_c4cplx !!*** !---------------------------------------------------------------------- !!****f* ABINIT/xmpi_sum_master_c5cplx !! NAME !! xmpi_sum_master_c5cplx !! !! FUNCTION !! Reduces values on all processes to a single value. !! Target: five-dimensional single precision complex arrays. !! !! INPUTS !! master= master MPI node !! spaceComm= MPI communicator !! !! OUTPUT !! ier= exit status, a non-zero value meaning there is an error !! !! SIDE EFFECTS !! xval= buffer array !! !! SOURCE subroutine xmpi_sum_master_c5cplx(xval,master,spaceComm,ier) !This section has been created automatically by the script Abilint (TD). !Do not modify the following lines by hand. #undef ABI_FUNC #define ABI_FUNC 'xmpi_sum_master_c5cplx' !End of the abilint section implicit none !Arguments------------------------- complex(spc), DEV_CONTARRD intent(inout) :: xval(:,:,:,:,:) integer,intent(in) :: master integer,intent(in) :: spaceComm integer,intent(out) :: ier !Local variables------------------- #if defined HAVE_MPI integer :: n1,n2,n3,n4,n5 complex(spc),allocatable :: xsum(:,:,:,:,:) integer :: nproc_space_comm #endif ! ************************************************************************* ier=0 #if defined HAVE_MPI if (spaceComm /= MPI_COMM_NULL) then call MPI_COMM_SIZE(spaceComm,nproc_space_comm,ier) if (nproc_space_comm /= 1) then n1 = size(xval,dim=1) n2 = size(xval,dim=2) n3 = size(xval,dim=3) n4 = size(xval,dim=4) n5 = size(xval,dim=5) ! Collect xval from processors on master in spaceComm ABI_STAT_ALLOCATE(xsum,(n1,n2,n3,n4,n5), ier) if (ier /= 0) call xmpi_abort(msg='error allocating xsum') call MPI_REDUCE(xval,xsum,n1*n2*n3*n4*n5,MPI_COMPLEX,MPI_SUM,master,spaceComm,ier) xval = xsum ABI_DEALLOCATE(xsum) end if end if #endif end subroutine xmpi_sum_master_c5cplx !!*** !!****f* ABINIT/xmpi_sum_master_c1dpc !! NAME !! xmpi_sum_master_c1dpc !! !! FUNCTION !! Reduces values on all processes to a single value. !! Target: one-dimensional double complex arrays. !! !! INPUTS !! master= master MPI node !! spaceComm= MPI communicator !! !! OUTPUT !! ier= exit status, a non-zero value meaning there is an error !! !! SIDE EFFECTS !! xval= buffer array !! !! SOURCE subroutine xmpi_sum_master_c1dpc(xval,master,spaceComm,ier) !This section has been created automatically by the script Abilint (TD). !Do not modify the following lines by hand. #undef ABI_FUNC #define ABI_FUNC 'xmpi_sum_master_c1dpc' !End of the abilint section implicit none !Arguments------------------------- complex(dpc), DEV_CONTARRD intent(inout) :: xval(:) integer,intent(in) :: master integer,intent(in) :: spaceComm integer,intent(out) :: ier !Local variables------------------- #if defined HAVE_MPI integer :: n1 integer :: nproc_space_comm complex(dpc),allocatable :: xsum(:) #endif ! ************************************************************************* ier=0 #if defined HAVE_MPI if (spaceComm /= MPI_COMM_NULL) then call MPI_COMM_SIZE(spaceComm,nproc_space_comm,ier) if (nproc_space_comm /= 1) then n1 = size(xval,dim=1) ! Collect xval from processors on master in spaceComm ABI_STAT_ALLOCATE(xsum,(n1), ier) if (ier /= 0) call xmpi_abort(msg='error allocating xsum') call MPI_REDUCE(xval,xsum,n1,MPI_DOUBLE_COMPLEX,MPI_SUM,master,spaceComm,ier) xval (:) = xsum(:) ABI_DEALLOCATE(xsum) end if end if #endif end subroutine xmpi_sum_master_c1dpc !!*** !!****f* ABINIT/xmpi_sum_master_c2dpc !! NAME !! xmpi_sum_master_c2dpc !! !! FUNCTION !! Reduces values on all processes to a single value. !! Target: two-dimensional double complex arrays. !! !! INPUTS !! master= master MPI node !! spaceComm= MPI communicator !! !! OUTPUT !! ier= exit status, a non-zero value meaning there is an error !! !! SIDE EFFECTS !! xval= buffer array !! !! SOURCE subroutine xmpi_sum_master_c2dpc(xval,master,spaceComm,ier) !This section has been created automatically by the script Abilint (TD). !Do not modify the following lines by hand. #undef ABI_FUNC #define ABI_FUNC 'xmpi_sum_master_c2dpc' !End of the abilint section implicit none !Arguments------------------------- complex(dpc), DEV_CONTARRD intent(inout) :: xval(:,:) integer ,intent(in) :: master integer ,intent(in) :: spaceComm integer ,intent(out) :: ier !Local variables------------------- #if defined HAVE_MPI integer :: n1,n2 complex(dpc) , allocatable :: xsum(:,:) integer :: nproc_space_comm #endif ! ************************************************************************* ier=0 #if defined HAVE_MPI if (spaceComm /= MPI_COMM_NULL) then call MPI_COMM_SIZE(spaceComm,nproc_space_comm,ier) if (nproc_space_comm /= 1) then n1 = size(xval,dim=1) n2 = size(xval,dim=2) ! Collect xval from processors on master in spaceComm ABI_STAT_ALLOCATE(xsum,(n1,n2), ier) if (ier /= 0) call xmpi_abort(msg='error allocating xsum') call MPI_REDUCE(xval,xsum,n1*n2,MPI_DOUBLE_COMPLEX,MPI_SUM,master,spaceComm,ier) xval (:,:) = xsum(:,:) ABI_DEALLOCATE(xsum) end if end if #endif end subroutine xmpi_sum_master_c2dpc !!*** !!****f* ABINIT/xmpi_sum_master_c3dpc !! NAME !! xmpi_sum_master_c3dpc !! !! FUNCTION !! Reduces values on all processes to a single value. !! Target: three-dimensional double complex arrays. !! !! INPUTS !! master= master MPI node !! spaceComm= MPI communicator !! !! OUTPUT !! ier= exit status, a non-zero value meaning there is an error !! !! SIDE EFFECTS !! xval= buffer array !! !! SOURCE subroutine xmpi_sum_master_c3dpc(xval,master,spaceComm,ier) !This section has been created automatically by the script Abilint (TD). !Do not modify the following lines by hand. #undef ABI_FUNC #define ABI_FUNC 'xmpi_sum_master_c3dpc' !End of the abilint section implicit none !Arguments------------------------- complex(dpc), DEV_CONTARRD intent(inout) :: xval(:,:,:) integer,intent(in) :: master integer,intent(in) :: spaceComm integer,intent(out) :: ier !Local variables------------------- #if defined HAVE_MPI integer :: n1,n2,n3 complex(dpc) , allocatable :: xsum(:,:,:) integer :: nproc_space_comm #endif ! ************************************************************************* ier=0 #if defined HAVE_MPI if (spaceComm /= MPI_COMM_NULL) then call MPI_COMM_SIZE(spaceComm,nproc_space_comm,ier) if (nproc_space_comm /= 1) then n1 = size(xval,dim=1) n2 = size(xval,dim=2) n3 = size(xval,dim=3) ! Collect xval from processors on master in spaceComm ABI_STAT_ALLOCATE(xsum,(n1,n2,n3), ier) if (ier /= 0) call xmpi_abort(msg='error allocating xsum') call MPI_REDUCE(xval,xsum,n1*n2*n3,MPI_DOUBLE_COMPLEX,MPI_SUM,master,spaceComm,ier) xval (:,:,:) = xsum(:,:,:) ABI_DEALLOCATE(xsum) end if end if #endif end subroutine xmpi_sum_master_c3dpc !!*** !!****f* ABINIT/xmpi_sum_master_c4dpc !! NAME !! xmpi_sum_master_c4dpc !! !! FUNCTION !! Reduces values on all processes to a single value. !! Target: four-dimensional double complex arrays. !! !! INPUTS !! master= master MPI node !! spaceComm= MPI communicator !! !! OUTPUT !! ier= exit status, a non-zero value meaning there is an error !! !! SIDE EFFECTS !! xval= buffer array !! !! SOURCE subroutine xmpi_sum_master_c4dpc(xval,master,spaceComm,ier) !This section has been created automatically by the script Abilint (TD). !Do not modify the following lines by hand. #undef ABI_FUNC #define ABI_FUNC 'xmpi_sum_master_c4dpc' !End of the abilint section implicit none !Arguments------------------------- complex(dpc), DEV_CONTARRD intent(inout) :: xval(:,:,:,:) integer,intent(in) :: master integer,intent(in) :: spaceComm integer,intent(out) :: ier !Local variables------------------- #if defined HAVE_MPI integer :: n1,n2,n3,n4 complex(dpc) , allocatable :: xsum(:,:,:,:) integer :: nproc_space_comm #endif ! ************************************************************************* ier=0 #if defined HAVE_MPI if (spaceComm /= MPI_COMM_NULL) then call MPI_COMM_SIZE(spaceComm,nproc_space_comm,ier) if (nproc_space_comm /= 1) then n1 = size(xval,dim=1) n2 = size(xval,dim=2) n3 = size(xval,dim=3) n4 = size(xval,dim=4) ! Collect xval from processors on master in spaceComm ABI_STAT_ALLOCATE(xsum,(n1,n2,n3,n4), ier) if (ier /= 0) call xmpi_abort(msg='error allocating xsum') call MPI_REDUCE(xval,xsum,n1*n2*n3*n4,MPI_DOUBLE_COMPLEX,MPI_SUM,master,spaceComm,ier) xval (:,:,:,:) = xsum(:,:,:,:) ABI_DEALLOCATE(xsum) end if end if #endif end subroutine xmpi_sum_master_c4dpc !!*** !!****f* ABINIT/xmpi_sum_master_c5dpc !! NAME !! xmpi_sum_master_c5dpc !! !! FUNCTION !! Reduces values on all processes to a single value. !! Target: five-dimensional double complex arrays. !! !! INPUTS !! master= master MPI node !! spaceComm= MPI communicator !! !! OUTPUT !! ier= exit status, a non-zero value meaning there is an error !! !! SIDE EFFECTS !! xval= buffer array !! !! SOURCE subroutine xmpi_sum_master_c5dpc(xval,master,spaceComm,ier) !This section has been created automatically by the script Abilint (TD). !Do not modify the following lines by hand. #undef ABI_FUNC #define ABI_FUNC 'xmpi_sum_master_c5dpc' !End of the abilint section implicit none !Arguments------------------------- complex(dpc), DEV_CONTARRD intent(inout) :: xval(:,:,:,:,:) integer,intent(in) :: master integer,intent(in) :: spaceComm integer,intent(out) :: ier !Local variables------------------- #if defined HAVE_MPI integer :: n1,n2,n3,n4,n5 complex(dpc),allocatable :: xsum(:,:,:,:,:) integer :: nproc_space_comm #endif ! ************************************************************************* ier=0 #if defined HAVE_MPI if (spaceComm /= MPI_COMM_NULL) then call MPI_COMM_SIZE(spaceComm,nproc_space_comm,ier) if (nproc_space_comm /= 1) then n1 = size(xval,dim=1) n2 = size(xval,dim=2) n3 = size(xval,dim=3) n4 = size(xval,dim=4) n5 = size(xval,dim=5) ! Collect xval from processors on master in spaceComm ABI_STAT_ALLOCATE(xsum,(n1,n2,n3,n4,n5), ier) if (ier /= 0) call xmpi_abort(msg='error allocating xsum') call MPI_REDUCE(xval,xsum,n1*n2*n3*n4*n5,MPI_DOUBLE_COMPLEX,MPI_SUM,master,spaceComm,ier) xval (:,:,:,:,:) = xsum(:,:,:,:,:) ABI_DEALLOCATE(xsum) end if end if #endif end subroutine xmpi_sum_master_c5dpc !!*** v_sim-3.8.0/lib/plug-ins/abinit/xred2xcart.F90000066400000000000000000000053761370110300500207600ustar00rootroot00000000000000!{\src2tex{textfont=tt}} !!****f* ABINIT/xred2xcart !! NAME !! xred2xcart !! !! FUNCTION !! Convert from dimensionless reduced coordinates xred(3,natom) !! to cartesian coordinates xcart(3,natom) in bohr by using !! xcart(mu,ia)=rprimd(mu,1)*xred(1,ia) !! +rprimd(mu,2)*xred(2,ia) !! +rprimd(mu,3)*xred(3,ia) !! Note that the reverse operation is done by xcart2xred.F90 !! !! !! COPYRIGHT !! Copyright (C) 1998-2016 ABINIT group (DCA, XG, GMR) !! This file is distributed under the terms of the !! GNU General Public License, see ~abinit/COPYING !! or http://www.gnu.org/copyleft/gpl.txt . !! For the initials of contributors, see ~abinit/doc/developers/contributors.txt . !! !! INPUTS !! natom=number of atoms in unit cell !! rprimd(3,3)=dimensional real space primitive translations (bohr) !! xred(3,natom)=dimensionless reduced coordinates of atoms !! !! OUTPUT !! xcart(3,natom)=cartesian coordinates of atoms (bohr) !! !! SIDE EFFECTS !! !! PARENTS !! afterscfloop,berryphase,berryphase_new,bonds_lgth_angles,constrf,cut3d !! denfgr,driver,evdw_wannier,ingeo,ionion_realspace,ionion_surface !! m_crystal,m_ddb,m_mep,m_pred_lotf,m_results_img,make_efg_el !! make_efg_ion,mkcore_inner,mkcore_paw,mkcore_wvl,mkgrid_fft,mklocl !! mklocl_realspace,mlwfovlp_projpaw,mover,out1dm,outqmc,outvar_o_z,outxml !! pimd_langevin_npt,pimd_langevin_nvt,pimd_nosehoover_npt !! pimd_nosehoover_nvt,pred_bfgs,pred_isokinetic,pred_isothermal !! pred_langevin,pred_nose,pred_srkna14,pred_verlet,prtimg,prtspgroup !! randomcellpos,rhotov,setvtr,spin_current,symspgr,thmeig !! vso_realspace_local,vtorho,wrt_moldyn_netcdf,wvl_denspot_set,wvl_initro !! wvl_memory,wvl_nhatgrid,wvl_projectors_set,wvl_rwwf,wvl_setboxgeometry !! wvl_wfs_set,wvl_wfsinp_reformat,wvl_wfsinp_scratch,xfh_recover_deloc !! !! CHILDREN !! !! SOURCE #if defined HAVE_CONFIG_H #include "config.h" #endif #include "abi_common.h" subroutine xred2xcart(natom,rprimd,xcart,xred) use defs_basis use m_errors use m_profiling_abi !This section has been created automatically by the script Abilint (TD). !Do not modify the following lines by hand. #undef ABI_FUNC #define ABI_FUNC 'xred2xcart' !End of the abilint section implicit none !Arguments ------------------------------------ !scalars integer,intent(in) :: natom !arrays real(dp),intent(in) :: rprimd(3,3),xred(3,natom) real(dp),intent(out) :: xcart(3,natom) !Local variables------------------------------- !scalars integer :: iatom,mu !arrays ! ************************************************************************* do iatom=1,natom do mu=1,3 xcart(mu,iatom)=rprimd(mu,1)*xred(1,iatom)+rprimd(mu,2)*xred(2,iatom)+rprimd(mu,3)*xred(3,iatom) end do end do end subroutine xred2xcart !!*** v_sim-3.8.0/lib/plug-ins/archives/000077500000000000000000000000001370110300500167355ustar00rootroot00000000000000v_sim-3.8.0/lib/plug-ins/archives/Makefile.am000066400000000000000000000013211370110300500207660ustar00rootroot00000000000000## Process this file with automake to produce Makefile.in vpath %.h $(top_srcdir)/src if PLATFORM_WIN32 cflagWin = -mms-bitfields -mno-cygwin endif libarchives_la_SOURCES = archives.c libarchives_la_LIBADD = $(top_builddir)/src/libv_sim-3.la \ @LIB_ARCHIVE_LIBS@ @GLIB_LIBS@ libarchives_la_LDFLAGS = -module @EXTRA_LDFLAGS@ -version-info $(lib_v_sim_version) if HAVE_LIB_ARCHIVE ARCHIVES_LIB = libarchives.la ARCHIVES_EXAMPLE = ARCHIVES_PIX = archives.png endif v_simplugins_LTLIBRARIES = \ $(ARCHIVES_LIB) AM_CPPFLAGS = \ -I$(top_srcdir)/src \ @GLIB_CFLAGS@ AM_CFLAGS = $(cflagWin) @LIB_ARCHIVE_CFLAGS@ v_simexamples_DATA = $(ARCHIVES_EXAMPLE) v_simpixmaps_DATA = $(ARCHIVES_PIX) EXTRA_DIST = archives.png v_sim-3.8.0/lib/plug-ins/archives/archives.c000066400000000000000000000174221370110300500207130ustar00rootroot00000000000000/* EXTRAITS DE LA LICENCE Copyright CEA, contributeurs : Luc BILLARD et Damien CALISTE, laboratoire L_Sim, (2001-2005) Adresse mèl : BILLARD, non joignable par mèl ; CALISTE, damien P caliste AT cea P fr. Ce logiciel est un programme informatique servant à visualiser des structures atomiques dans un rendu pseudo-3D. Ce logiciel est régi par la licence CeCILL soumise au droit français et respectant les principes de diffusion des logiciels libres. Vous pouvez utiliser, modifier et/ou redistribuer ce programme sous les conditions de la licence CeCILL telle que diffusée par le CEA, le CNRS et l'INRIA sur le site "http://www.cecill.info". Le fait que vous puissiez accéder à cet en-tête signifie que vous avez pris connaissance de la licence CeCILL, et que vous en avez accepté les termes (cf. le fichier Documentation/licence.fr.txt fourni avec ce logiciel). */ /* LICENCE SUM UP Copyright CEA, contributors : Luc BILLARD et Damien CALISTE, laboratoire L_Sim, (2001-2005) E-mail address: BILLARD, not reachable any more ; CALISTE, damien P caliste AT cea P fr. This software is a computer program whose purpose is to visualize atomic configurations in 3D. This software is governed by the CeCILL license under French law and abiding by the rules of distribution of free software. You can use, modify and/ or redistribute the software under the terms of the CeCILL license as circulated by CEA, CNRS and INRIA at the following URL "http://www.cecill.info". The fact that you are presently reading this means that you have had knowledge of the CeCILL license and that you accept its terms. You can find a copy of this licence shipped with this software at Documentation/licence.en.txt. */ #include #include #include #include #include #include #define ARCHIVES_DESCRIPTION _("" \ "This plug-in adds support for\n" \ "compressed input files\n" \ "(see http://code.google.com/p/libarchive/).") #define ARCHIVES_AUTHORS "Caliste Damien" /* Local methods */ static void archivesStructuralInit(); static gboolean loadArchivesIn(VisuDataLoader *self, VisuDataLoadable *data, guint type, guint nSet, GCancellable *cancel, GError **error); /* Local variables */ static gchar *iconPath; static VisuDataLoader *archLoader = NULL; /* Required methods for a loadable module. */ gboolean archivesInit() { DBG_fprintf(stderr, "Archives: loading plug-in 'archives'...\n"); iconPath = g_build_filename(V_SIM_PIXMAPS_DIR, "archives.png", NULL); DBG_fprintf(stderr, "Archives: declare a new rendering load method.\n"); archivesStructuralInit(); return TRUE; } const char* archivesGet_description() { return ARCHIVES_DESCRIPTION; } const char* archivesGet_authors() { return ARCHIVES_AUTHORS; } const char* archivesGet_icon() { return iconPath; } static void archivesStructuralInit() { const gchar *type[] = {"*.gz", "*.bz2", "*.zip", "*.iso", (char*)0}; archLoader = visu_data_loader_new(_("Compressed file formats"), type, FALSE, loadArchivesIn, 25); visu_data_atomic_class_addLoader(archLoader); } #if ARCHIVE_VERSION_NUMBER < 3000000 #define archive_read_support_filter_all(a) archive_read_support_compression_all(a) #define archive_read_free(a) archive_read_finish(a) #endif static gboolean loadArchivesIn(VisuDataLoader *self _U_, VisuDataLoadable *data, guint type, guint nSet, GCancellable *cancel, GError **error) { struct archive *a; struct archive_entry *entry; int r; guint nSets; GList *lst, *tmpLst; const void *buff; size_t size, wsize; off_t offset; GIOChannel *tmpFile; gchar *tmpFilename, *tmpBasename; gboolean res; a = archive_read_new(); archive_read_support_filter_all(a); archive_read_support_format_all(a); DBG_fprintf(stderr, "Archives: try to open file with libarchive.\n"); r = archive_read_open_filename(a, visu_data_loadable_getFilename(data, type), 10240); DBG_fprintf(stderr, " | %d %d\n", r, ARCHIVE_OK); if (r != ARCHIVE_OK) { if (archive_read_free(a)) g_warning("Can't finish the archive file '%s'.", visu_data_loadable_getFilename(data, type)); return FALSE; } nSets = 0; lst = (GList*)0; while (archive_read_next_header(a, &entry) == ARCHIVE_OK) if (archive_entry_size(entry) > 0) { lst = g_list_prepend(lst, g_strdup(archive_entry_pathname(entry))); DBG_fprintf(stderr, " | entry '%s' size %ld in '%s'.\n", archive_entry_pathname(entry), archive_entry_size(entry), visu_data_loadable_getFilename(data, type)); if (nSets == (guint)nSet) { /* We create a temp file a extract the data to it. */ tmpBasename = g_path_get_basename(archive_entry_pathname(entry)); tmpFilename = g_build_filename(g_get_tmp_dir(), tmpBasename, NULL); g_free(tmpBasename); DBG_fprintf(stderr, "Archives: create a temporary file '%s' for entry %d.\n", tmpFilename, nSet); tmpFile = g_io_channel_new_file(tmpFilename, "w", error); if (!tmpFile) { g_free(tmpFilename); if (archive_read_free(a)) g_warning("Can't finish the archive file '%s'.", visu_data_loadable_getFilename(data, type)); return TRUE; } while (archive_read_data_block(a, &buff, &size, &offset) == ARCHIVE_OK) { if (g_io_channel_write_chars(tmpFile, buff, size, &wsize, error) != G_IO_STATUS_NORMAL || wsize != size) { g_free(tmpFilename); if (archive_read_free(a)) g_warning("Can't finish the archive file '%s'.", visu_data_loadable_getFilename(data, type)); return TRUE; } } if (g_io_channel_shutdown(tmpFile, TRUE, error) != G_IO_STATUS_NORMAL) { g_free(tmpFilename); if (archive_read_free(a)) g_warning("Can't finish the archive file '%s'.", visu_data_loadable_getFilename(data, type)); return TRUE; } /* We try to load the file. */ res = visu_data_atomic_loadAt(VISU_DATA_ATOMIC(data), tmpFilename, 0, cancel, error); /* We erase the file after use. */ g_unlink(tmpFilename); g_free(tmpFilename); if (!res) { if (archive_read_free(a)) g_warning("Can't finish the archive file '%s'.", visu_data_loadable_getFilename(data, type)); return TRUE; } } nSets += 1; } if (nSets == 0) { if (archive_read_free(a)) g_warning("Can't finish the archive file '%s'.", visu_data_loadable_getFilename(data, type)); return FALSE; } /* Need to copy the node array. */ visu_data_loadable_setNSets(data, nSets); for (tmpLst = lst; tmpLst; tmpLst = g_list_next(tmpLst)) { nSets -= 1; visu_data_loadable_setSetLabel(data, (gchar*)tmpLst->data, nSets); g_free(tmpLst->data); } g_list_free(lst); if (archive_read_free(a)) g_warning("Can't finish the archive file '%s'.", visu_data_loadable_getFilename(data, type)); return TRUE; } v_sim-3.8.0/lib/plug-ins/archives/archives.png000066400000000000000000000042121370110300500212460ustar00rootroot00000000000000PNG  IHDR szzbKGDC pHYsHHFk> vpAg IDATXå[Uk߹f:Br0'b FM|񁨼 >/&bB+&>DM!B(-BRڂS3NvΜ9]>|gn-__{#?scXfWfhY*seĆ|Ap"4cXƁcmÂ}/x)>w@XZkZ\P, ^:]l/4Lֶ\b\.6l4idRxy'mMO2DdRKGmr_xkl1kf2<%L4r\#oVX(TЍw\QZasOso̠cI ePG OSM|'-v/-E(D)D9(:7a4G8P% 5Aƒ7'[͗zk|wefQ^"Y0JDLD)EPc?4qNb-qwj}(LWK3?`zSr Vρ(R*Z (ϿOgI% -..(gs^EaF:ޒbt.+bٲzCk쯀Ũ rEQvz,%l"ݵ`̹u&B@FbvJ㧎 sS"B"X%VgigSF_9`3QQ,M8Ϧt5|5p1RND(R֨".瘮NS Fz2.Q.k%иc@-jcore&>tgz%,fEF Jm{iit k4XFW6F!: a/s:LM;5:zv^%H:1u\\7N!ahxOG^VSj'ψ5=kdz_=y&wJc* [bmc :)[1g``}@Z[=WVU on=X֛ez|pW kȵ|'FbV/=?d?Cߦ7;'M]t"^HӦk/?a֝˶3 gl#-IckOU\x%a(VJ/R6rP +qnuX+QlfK]\T,D At158Ήdf؍P@R{5A93%9X~ջњ|?uR`>cܡrx/5wzɱY (Q@>MIa %d? יF,p̩ nDkX#L8%tEXtdate:create2011-06-07T15:09:54+02:00gS:%tEXtdate:modify2011-06-07T15:09:54+02:00IENDB`v_sim-3.8.0/lib/plug-ins/bigdft/000077500000000000000000000000001370110300500163705ustar00rootroot00000000000000v_sim-3.8.0/lib/plug-ins/bigdft/Makefile.am000066400000000000000000000013661370110300500204320ustar00rootroot00000000000000## Process this file with automake to produce Makefile.in vpath %.h $(top_srcdir)/src libbigdftplug_la_SOURCES = bigdft.c bigdft_run.c bigdft_system.c bigdftplug.h libbigdftplug_la_LIBADD = $(top_builddir)/src/libv_sim-3.la \ @GLIB_LIBS@ @GTKS_LIBS@ @BIGDFT_LIBS@ $(FCLIBS) libbigdftplug_la_LDFLAGS = -module @EXTRA_LDFLAGS@ -version-info $(lib_v_sim_version) if HAVE_BIGDFT BigDFT_LIB = libbigdftplug.la BigDFT_EXAMPLE = BigDFT_PIX = bigdft.png stock-bigdft_20.png endif v_simplugins_LTLIBRARIES = $(BigDFT_LIB) AM_CPPFLAGS = \ -I$(top_srcdir)/src \ @BIGDFT_CPPFLAGS@ \ @GLIB_CFLAGS@ \ @GTKS_CFLAGS@ AM_CFLAGS = @EXTRA_CFLAGS@ v_simexamples_DATA = $(BigDFT_EXAMPLE) v_simpixmaps_DATA = $(BigDFT_PIX) EXTRA_DIST = bigdft.png stock-bigdft_20.png v_sim-3.8.0/lib/plug-ins/bigdft/bigdft.c000066400000000000000000001527551370110300500200120ustar00rootroot00000000000000/* EXTRAITS DE LA LICENCE Copyright CEA, contributeurs : Damien CALISTE, laboratoire L_Sim, (2001-2011) Adresse ml : CALISTE, damien P caliste AT cea P fr. Ce logiciel est un programme informatique servant visualiser des structures atomiques dans un rendu pseudo-3D. Ce logiciel est rgi par la licence CeCILL soumise au droit franais et respectant les principes de diffusion des logiciels libres. Vous pouvez utiliser, modifier et/ou redistribuer ce programme sous les conditions de la licence CeCILL telle que diffuse par le CEA, le CNRS et l'INRIA sur le site "http://www.cecill.info". Le fait que vous puissiez accder cet en-tte signifie que vous avez pris connaissance de la licence CeCILL, et que vous en avez accept les termes (cf. le fichier Documentation/licence.fr.txt fourni avec ce logiciel). */ /* LICENCE SUM UP Copyright CEA, contributors: Damien CALISTE, L_Sim laboratory, (2001-2011) E-mail address: CALISTE, damien P caliste AT cea P fr. This software is a computer program whose purpose is to visualize atomic configurations in 3D. This software is governed by the CeCILL license under French law and abiding by the rules of distribution of free software. You can use, modify and/ or redistribute the software under the terms of the CeCILL license as circulated by CEA, CNRS and INRIA at the following URL "http://www.cecill.info". The fact that you are presently reading this means that you have had knowledge of the CeCILL license and that you accept its terms. You can find a copy of this licence shipped with this software at Documentation/licence.en.txt. */ #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include "bigdftplug.h" #define BIGDFT_DESCRIPTION _("" \ "This plug-in adds support for specific\n" \ "capabilities of BigDFT.") #define BIGDFT_AUTHORS "Caliste Damien" #define FLAG_PARAMETER_BIGDFT "bigdft_use_parser" #define DESC_PARAMETER_BIGDFT "Use or not the BigDFT parser for known files ; a boolean (0 or 1)" static gboolean bigdftDensityLoad(VisuScalarFieldMethod *meth, const gchar *filename, GList **fieldList, GError **error); static gboolean bigdftTestWaveFile(const gchar *filename); extern void FC_FUNC_(memocc_report, MEMOCC_REPORT)(); /* Local variables */ static gchar *iconPath; static VisuScalarFieldMethod *fmtBigDFT; static VisuDataLoader *wvlLoader = NULL; static gboolean isPanelInitialised; static gboolean useCGrid, useFGrid, useLoadWithGrid; static GtkWidget *lblCGrid, *lblFGrid; static GtkTextBuffer *bufMemory; static GtkWidget *entryHgrid[3], *entryCrmult, *entryFrmult, *entryIxc; static GtkWidget *entryRadius[2], *cbRadEle[2]; enum { RADII_VALUE_FILE, RADII_VALUE_COMPUTED, RADII_VALUE_EDITED }; static gchar *radiiIcons[3] = {GTK_STOCK_FILE, GTK_STOCK_EXECUTE, GTK_STOCK_EDIT}; static gboolean disableCallbacks; /* Local methods. */ static void updateGridLabels(VisuData *dataObj); static void initialisePanel(VisuUiPanel *panel); static gboolean loadBigDFTIn(VisuDataLoader *self, const gchar* filename, VisuData *data, guint nSet, GCancellable *cancel, GError **error); static void update_memory_estimation(VisuData *data); static int redirect_init(int out_pipe[2]); static void redirect_dump(int out_pipe[2], int stdout_fileno_old); static void exportParameters(GString *data, VisuData *dataObj); /* Callbacks. */ static gboolean onFieldChooserHook(GSignalInvocationHint *ihint, guint nvalues, const GValue *param_values, gpointer data); static void onBand(GtkSpinButton *spin, gpointer data); static void onKpt(GtkSpinButton *spin, gpointer data); static void onSpin(GtkComboBox *combo, gpointer data); static void onSpinor(GtkComboBox *combo, gpointer data); static void onDataNew(GObject *obj, VisuData *dataObj, gpointer data); static void onDataReady(GObject *obj, VisuData *dataObj, gpointer data); static void onFilesChanged(VisuData *dataObj, guint kind, gpointer data); static void onPanelEnter(VisuUiPanel *panel, gpointer data); static void onToggleGrid(GtkToggleButton *toggle, gpointer data); static void onToggleLoad(GtkToggleButton *toggle, gpointer data); static void onHgrid(VisuUiNumericalEntry *entry, gdouble old_value, gpointer data); static void onRmult(VisuUiNumericalEntry *entry, gdouble old_value, gpointer data); static void onRadius(VisuUiNumericalEntry *entry, gdouble old_value, gpointer data); static void onIxc(VisuUiNumericalEntry *entry, gdouble old_value, gpointer data); static void onEleChanged(GtkComboBox *combo, gpointer data); static void onNproc(GtkSpinButton *spin, gpointer data); /* Includes. */ GtkWidget* bdft_run_tab(guint nEle, BigDFT_Wf *wf); void bdft_run_init(); GtkWidget* bdft_system_tab(BigDFT_Lzd *lzd); void bdft_system_init(); gboolean bigdftplugInit() { const gchar *typeBigDFT[] = {"*.etsf", "wavefunction-*", "minBasis-*", (char*)0}; const gchar *typeWvl[] = {"*.xyz", "*.ascii", "*.yaml", (char*)0}; VisuConfigFileEntry *resourceEntry; fmtBigDFT = visu_scalar_field_method_new(_("Wavefunction file from BigDFT"), typeBigDFT, bigdftDensityLoad, G_PRIORITY_HIGH - 4); tool_file_format_setValidator(TOOL_FILE_FORMAT(fmtBigDFT), bigdftTestWaveFile); wvlLoader = visu_data_loader_new(_("BigDFT wavelet boxes"), typeWvl, FALSE, loadBigDFTIn, 22); visu_data_atomic_class_addLoader(wvlLoader); tool_file_format_addPropertyDouble(fmtWvl, "hx", _("Hgrid along x"), 0.45); tool_file_format_addPropertyDouble(fmtWvl, "hy", _("Hgrid along y"), 0.45); tool_file_format_addPropertyDouble(fmtWvl, "hz", _("Hgrid along z"), 0.45); tool_file_format_addPropertyDouble(fmtWvl, "crmult", _("Coarse grid multiplier"), 5.); tool_file_format_addPropertyDouble(fmtWvl, "frmult", _("Fine grid multiplier"), 8.); tool_file_format_addPropertyInt(fmtWvl, "ixc", _("Exchange-correlation functional code"), 1); tool_file_format_addPropertyInt(fmtWvl, "nproc", _("Number of processors for memory estimation"), 1); iconPath = g_build_filename(V_SIM_PIXMAPS_DIR, "bigdft.png", NULL); useCGrid = FALSE; useFGrid = FALSE; useLoadWithGrid = FALSE; disableCallbacks = FALSE; lblCGrid = (GtkWidget*)0; lblFGrid = (GtkWidget*)0; entryHgrid[0] = (GtkWidget*)0; entryHgrid[1] = (GtkWidget*)0; entryHgrid[2] = (GtkWidget*)0; entryCrmult = (GtkWidget*)0; entryFrmult = (GtkWidget*)0; entryRadius[0] = (GtkWidget*)0; entryRadius[1] = (GtkWidget*)0; cbRadEle[0] = (GtkWidget*)0; cbRadEle[1] = (GtkWidget*)0; entryIxc = (GtkWidget*)0; bufMemory = gtk_text_buffer_new((GtkTextTagTable*)0); gtk_text_buffer_create_tag(bufMemory, "typewriter", "family", "monospace", "scale", PANGO_SCALE_SMALL, NULL); isPanelInitialised = FALSE; g_signal_connect(VISU_OBJECT_INSTANCE, "dataNew", G_CALLBACK(onDataNew), NULL); g_signal_connect(VISU_OBJECT_INSTANCE, "dataRendered", G_CALLBACK(onDataReady), NULL); bdft_run_init(); bdft_system_init(); visu_config_file_addKnownTag("bigdft"); resourceEntry = visu_config_file_addBooleanEntry(VISU_CONFIG_FILE_PARAMETER, FLAG_PARAMETER_BIGDFT, DESC_PARAMETER_BIGDFT, &useLoadWithGrid, FALSE); visu_config_file_entry_setVersion(resourceEntry, 3.7f); visu_config_file_addExportFunction(VISU_CONFIG_FILE_PARAMETER, exportParameters); return TRUE; } gboolean bigdftplugInitGtk() { DBG_fprintf(stderr, "BigDFT: init Gtk stuff.\n"); panelBigDFT = visu_ui_panel_newWithIconFromPath("Panel_BigDFT", _("BigDFT settings"), "BigDFT", "stock-bigdft_20.png"); visu_ui_panel_setDockable(VISU_UI_PANEL(panelBigDFT), TRUE); visu_ui_panel_attach(VISU_UI_PANEL(panelBigDFT), visu_ui_panel_class_getCommandPanel()); g_signal_connect(G_OBJECT(panelBigDFT), "page-entered", G_CALLBACK(onPanelEnter), (gpointer)0); g_signal_add_emission_hook(g_signal_lookup("validate", VISU_TYPE_UI_FIELD_CHOOSER), 0, onFieldChooserHook, (gpointer)0, (GDestroyNotify)0); return TRUE; } const char* bigdftplugGet_description() { return BIGDFT_DESCRIPTION; } const char* bigdftplugGet_authors() { return BIGDFT_AUTHORS; } const char* bigdftplugGet_icon() { return iconPath; } static gboolean bigdftTestWaveFile(const gchar *filename) { g_return_val_if_fail(filename, FALSE); return bigdft_read_wave_descr(filename, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL); } static void initialisePanel(VisuUiPanel *panel) { GtkWidget *vbox, *hbox, *wd, *ct, *vbox2, *ntbk; VisuData *dataObj; GArray *radii; guint *radiiStatus; guint nEle; BigDFT_Wf *wf; g_return_if_fail(!isPanelInitialised); dataObj = visu_ui_panel_getData(panel); if (dataObj) { radii = (GArray*)g_object_get_data(G_OBJECT(dataObj), "BigDFT_radii"); radiiStatus = (guint*)g_object_get_data(G_OBJECT(dataObj), "BigDFT_radiiStatus"); nEle = GPOINTER_TO_INT(g_object_get_data(G_OBJECT(dataObj), "BigDFT_ntypes")); wf = (BigDFT_Wf*)g_object_get_data(G_OBJECT(dataObj), "BigDFT_wf"); } else { radii = (GArray*)0; radiiStatus = (guint*)0; nEle = 0; wf = (BigDFT_Wf*)0; } vbox = gtk_vbox_new(FALSE, 0); gtk_container_add(GTK_CONTAINER(panel), vbox); wd = gtk_label_new(_("BigDFT specific parameters")); gtk_label_set_use_markup(GTK_LABEL(wd), TRUE); gtk_misc_set_alignment(GTK_MISC(wd), 0., 0.5); gtk_widget_set_name(wd, "label_head"); gtk_box_pack_start(GTK_BOX(vbox), wd, FALSE, FALSE, 0); hbox = gtk_hbox_new(FALSE, 5); gtk_box_pack_start(GTK_BOX(vbox), hbox, FALSE, FALSE, 3); wd = gtk_check_button_new_with_mnemonic(_("use BigDFT to load xyz and ASCII files")); gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON(wd), useLoadWithGrid); g_signal_connect(G_OBJECT(wd), "toggled", G_CALLBACK(onToggleLoad), GINT_TO_POINTER(0)); gtk_box_pack_start(GTK_BOX(hbox), wd, TRUE, TRUE, 0); /* Hgrid and ixc line. */ hbox = gtk_hbox_new(FALSE, 2); gtk_box_pack_start(GTK_BOX(vbox), hbox, FALSE, FALSE, 0); wd = gtk_label_new(_("hgrids:")); gtk_misc_set_alignment(GTK_MISC(wd), 1., 0.5); gtk_box_pack_start(GTK_BOX(hbox), wd, TRUE, TRUE, 0); entryHgrid[0] = visu_ui_numerical_entry_new(GET_OPT_DBL(fmtWvl, "hx")); gtk_entry_set_width_chars(GTK_ENTRY(entryHgrid[0]), 8); g_signal_connect(G_OBJECT(entryHgrid[0]), "value-changed", G_CALLBACK(onHgrid), GINT_TO_POINTER(0)); gtk_box_pack_start(GTK_BOX(hbox), entryHgrid[0], FALSE, FALSE, 0); entryHgrid[1] = visu_ui_numerical_entry_new(GET_OPT_DBL(fmtWvl, "hy")); gtk_entry_set_width_chars(GTK_ENTRY(entryHgrid[1]), 8); g_signal_connect(G_OBJECT(entryHgrid[1]), "value-changed", G_CALLBACK(onHgrid), GINT_TO_POINTER(1)); gtk_box_pack_start(GTK_BOX(hbox), entryHgrid[1], FALSE, FALSE, 0); entryHgrid[2] = visu_ui_numerical_entry_new(GET_OPT_DBL(fmtWvl, "hz")); gtk_entry_set_width_chars(GTK_ENTRY(entryHgrid[2]), 8); g_signal_connect(G_OBJECT(entryHgrid[2]), "value-changed", G_CALLBACK(onHgrid), GINT_TO_POINTER(2)); gtk_box_pack_start(GTK_BOX(hbox), entryHgrid[2], FALSE, FALSE, 0); wd = gtk_label_new(_("ixc:")); gtk_misc_set_alignment(GTK_MISC(wd), 1., 0.5); gtk_box_pack_start(GTK_BOX(hbox), wd, TRUE, TRUE, 0); entryIxc = visu_ui_numerical_entry_new(GET_OPT_INT(fmtWvl, "ixc")); gtk_entry_set_width_chars(GTK_ENTRY(entryIxc), 6); g_signal_connect(G_OBJECT(entryIxc), "value-changed", G_CALLBACK(onIxc), (gpointer)0); gtk_box_pack_start(GTK_BOX(hbox), entryIxc, FALSE, FALSE, 0); /* The coarse grid parameters. */ hbox = gtk_hbox_new(FALSE, 5); gtk_box_pack_start(GTK_BOX(vbox), hbox, FALSE, FALSE, 0); wd = gtk_check_button_new_with_mnemonic(_("show _coarse grid")); gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON(wd), useCGrid); g_signal_connect(G_OBJECT(wd), "toggled", G_CALLBACK(onToggleGrid), GINT_TO_POINTER(0)); gtk_box_pack_start(GTK_BOX(hbox), wd, TRUE, TRUE, 0); lblCGrid = gtk_label_new(""); gtk_box_pack_end(GTK_BOX(hbox), lblCGrid, FALSE, FALSE, 0); hbox = gtk_hbox_new(FALSE, 5); gtk_box_pack_start(GTK_BOX(vbox), hbox, FALSE, FALSE, 0); wd = gtk_label_new(_("radius of ele.")); gtk_misc_set_alignment(GTK_MISC(wd), 1., 0.5); gtk_box_pack_start(GTK_BOX(hbox), wd, TRUE, TRUE, 0); cbRadEle[0] = visu_ui_element_combobox_new(FALSE, FALSE, (const gchar*)0); g_signal_connect(G_OBJECT(cbRadEle[0]), "changed", G_CALLBACK(onEleChanged), GINT_TO_POINTER(0)); gtk_box_pack_start(GTK_BOX(hbox), cbRadEle[0], FALSE, FALSE, 0); if (radii && radiiStatus) { entryRadius[0] = visu_ui_numerical_entry_new(g_array_index(radii, double, 0)); gtk_entry_set_icon_from_stock(GTK_ENTRY(entryRadius[0]), GTK_ENTRY_ICON_SECONDARY, radiiIcons[radiiStatus[0]]); } else entryRadius[0] = visu_ui_numerical_entry_new(-1.); gtk_entry_set_width_chars(GTK_ENTRY(entryRadius[0]), 10); g_signal_connect(G_OBJECT(entryRadius[0]), "value-changed", G_CALLBACK(onRadius), GINT_TO_POINTER(0)); gtk_box_pack_start(GTK_BOX(hbox), entryRadius[0], FALSE, FALSE, 0); wd = gtk_label_new("\303\227 (crmult:"); gtk_box_pack_start(GTK_BOX(hbox), wd, FALSE, FALSE, 0); entryCrmult = visu_ui_numerical_entry_new(GET_OPT_DBL(fmtWvl, "crmult")); gtk_entry_set_width_chars(GTK_ENTRY(entryCrmult), 3); g_signal_connect(G_OBJECT(entryCrmult), "value-changed", G_CALLBACK(onRmult), GINT_TO_POINTER(0)); gtk_box_pack_start(GTK_BOX(hbox), entryCrmult, FALSE, FALSE, 0); wd = gtk_label_new(")"); gtk_box_pack_start(GTK_BOX(hbox), wd, FALSE, FALSE, 0); /* The fine grid parameters. */ hbox = gtk_hbox_new(FALSE, 5); gtk_box_pack_start(GTK_BOX(vbox), hbox, FALSE, FALSE, 0); wd = gtk_check_button_new_with_mnemonic(_("show _fine grid")); gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON(wd), useFGrid); g_signal_connect(G_OBJECT(wd), "toggled", G_CALLBACK(onToggleGrid), GINT_TO_POINTER(1)); gtk_box_pack_start(GTK_BOX(hbox), wd, TRUE, TRUE, 0); lblFGrid = gtk_label_new(""); gtk_box_pack_end(GTK_BOX(hbox), lblFGrid, FALSE, FALSE, 0); updateGridLabels(visu_ui_panel_getData(panel)); hbox = gtk_hbox_new(FALSE, 5); gtk_box_pack_start(GTK_BOX(vbox), hbox, FALSE, FALSE, 0); wd = gtk_label_new(_("radius of ele.")); gtk_misc_set_alignment(GTK_MISC(wd), 1., 0.5); gtk_box_pack_start(GTK_BOX(hbox), wd, TRUE, TRUE, 0); cbRadEle[1] = visu_ui_element_combobox_new(FALSE, FALSE, (const gchar*)0); g_signal_connect(G_OBJECT(cbRadEle[1]), "changed", G_CALLBACK(onEleChanged), GINT_TO_POINTER(1)); gtk_box_pack_start(GTK_BOX(hbox), cbRadEle[1], FALSE, FALSE, 0); if (radii && radiiStatus) { entryRadius[1] = visu_ui_numerical_entry_new(g_array_index(radii, double, nEle)); gtk_entry_set_icon_from_stock(GTK_ENTRY(entryRadius[1]), GTK_ENTRY_ICON_SECONDARY, radiiIcons[radiiStatus[nEle]]); } else entryRadius[1] = visu_ui_numerical_entry_new(-1.); gtk_entry_set_width_chars(GTK_ENTRY(entryRadius[1]), 10); g_signal_connect(G_OBJECT(entryRadius[1]), "value-changed", G_CALLBACK(onRadius), GINT_TO_POINTER(1)); gtk_box_pack_start(GTK_BOX(hbox), entryRadius[1], FALSE, FALSE, 0); wd = gtk_label_new("\303\227 (frmult:"); gtk_box_pack_start(GTK_BOX(hbox), wd, FALSE, FALSE, 0); entryFrmult = visu_ui_numerical_entry_new(GET_OPT_DBL(fmtWvl, "frmult")); gtk_entry_set_width_chars(GTK_ENTRY(entryFrmult), 3); g_signal_connect(G_OBJECT(entryFrmult), "value-changed", G_CALLBACK(onRmult), GINT_TO_POINTER(1)); gtk_box_pack_start(GTK_BOX(hbox), entryFrmult, FALSE, FALSE, 0); wd = gtk_label_new(")"); gtk_box_pack_start(GTK_BOX(hbox), wd, FALSE, FALSE, 0); wd = gtk_label_new("Powered by BigDFT " BIGDFT_STRING_VERSION ""); gtk_misc_set_alignment(GTK_MISC(wd), 1., 0.5); gtk_label_set_use_markup(GTK_LABEL(wd), TRUE); gtk_box_pack_end(GTK_BOX(vbox), wd, FALSE, FALSE, 0); /* The BigDFT tab. */ ntbk = gtk_notebook_new(); gtk_box_pack_start(GTK_BOX(vbox), ntbk, TRUE, TRUE, 0); /* The memory estimation. */ vbox2 = gtk_vbox_new(FALSE, 2); gtk_notebook_append_page(GTK_NOTEBOOK(ntbk), vbox2, gtk_label_new(_("Memory estimation"))); hbox = gtk_hbox_new(FALSE, 2); gtk_box_pack_start(GTK_BOX(vbox2), hbox, FALSE, FALSE, 0); wd = gtk_label_new(_("Memory estimation for")); gtk_misc_set_alignment(GTK_MISC(wd), 0., 0.5); gtk_box_pack_start(GTK_BOX(hbox), wd, TRUE, TRUE, 0); wd = gtk_spin_button_new_with_range(1, 4096, 1); g_signal_connect(G_OBJECT(wd), "value-changed", G_CALLBACK(onNproc), (gpointer)0); gtk_box_pack_start(GTK_BOX(hbox), wd, FALSE, FALSE, 0); wd = gtk_label_new(_("core(s)")); gtk_box_pack_start(GTK_BOX(hbox), wd, FALSE, FALSE, 0); ct = gtk_scrolled_window_new((GtkAdjustment*)0, (GtkAdjustment*)0); gtk_scrolled_window_set_policy(GTK_SCROLLED_WINDOW(ct), GTK_POLICY_AUTOMATIC, GTK_POLICY_NEVER); gtk_scrolled_window_set_shadow_type(GTK_SCROLLED_WINDOW(ct), GTK_SHADOW_ETCHED_IN); gtk_box_pack_start(GTK_BOX(vbox2), ct, TRUE, TRUE, 0); wd = gtk_text_view_new_with_buffer(bufMemory); gtk_text_view_set_editable(GTK_TEXT_VIEW(wd), FALSE); gtk_text_view_set_cursor_visible(GTK_TEXT_VIEW(wd), FALSE); gtk_container_add(GTK_CONTAINER(ct), wd); /* The system tab. */ vbox2 = bdft_system_tab((wf)?wf->lzd:NULL); gtk_notebook_append_page(GTK_NOTEBOOK(ntbk), vbox2, gtk_label_new(_("Basis set"))); /* The run tab. */ vbox2 = bdft_run_tab(nEle, wf); gtk_notebook_append_page(GTK_NOTEBOOK(ntbk), vbox2, gtk_label_new(_("Running BigDFT"))); gtk_widget_show_all(vbox); isPanelInitialised = TRUE; } static void onPanelEnter(VisuUiPanel *panel, gpointer data _U_) { DBG_fprintf(stderr, "Panel BigDFT: caught the 'page-entered' signal %d.\n", isPanelInitialised); if (!isPanelInitialised) initialisePanel(panel); } static gboolean loadGrids(gpointer data) { VisuData *dataObj; VisuGlView *view; GArray *grid; const gchar *gridNames[] = {"BigDFT_coarse_grid", "BigDFT_fine_grid"}; const gchar *eleNames[] = {"g", "G"}; guint iGrid = GPOINTER_TO_INT(data); gboolean* usage[] = {&useCGrid, &useFGrid}; dataObj = visu_ui_panel_getData(VISU_UI_PANEL(panelBigDFT)); view = visu_ui_panel_getView(VISU_UI_PANEL(panelBigDFT)); if (!dataObj || !view) return FALSE; DBG_fprintf(stderr, "Panel BigDFT: load grid for object %p.\n", (gpointer)dataObj); grid = (GArray*)g_object_get_data(G_OBJECT(dataObj), gridNames[iGrid]); bigdft_show_grid(dataObj, (*(usage[iGrid]))?grid:(GArray*)0, eleNames[iGrid], 0); VISU_REDRAW_ADD; return FALSE; } static void onToggleGrid(GtkToggleButton *toggle, gpointer data) { gboolean* usage[] = {&useCGrid, &useFGrid}; guint iGrid = GPOINTER_TO_INT(data); DBG_fprintf(stderr, "Panel BigDFT: toggle grid.\n"); *(usage[iGrid]) = gtk_toggle_button_get_active(toggle); g_idle_add(loadGrids, data); } static gboolean bigdftDensityLoad(VisuScalarFieldMethod *meth, const gchar *filename, GList **fieldList, GError **error) { int norbu, norbd, nkpt, nspinor, iorbp; int iorbf, ispinf, ikptf, ispinorf; int ntot, i, iorb, ispin, ikpt, ispinor; guint n[3]; VisuScalarField *field; ToolOption *opt; double h[3]; double box[3][3]; double *data; f90_pointer_double_4D *psiscf; GArray *wrap; VisuBox *boxObj; g_return_val_if_fail(filename, FALSE); g_return_val_if_fail(*fieldList == (GList*)0, FALSE); g_return_val_if_fail(error && (*error == (GError*)0), FALSE); DBG_fprintf(stderr, "BigDFT: test file '%s' as a BigDFT wavefunction file.\n", filename); if (!bigdft_read_wave_descr(filename, &norbu, &norbd, &nkpt, &nspinor, &iorbf, &ispinf, &ikptf, &ispinorf)) /* The file is not a BigDFT file. */ return FALSE; /* Get orbital from option table if the file contains several. */ if (norbu > 0 || norbd > 0) { iorb = norbu; ispin = 1; ikpt = 1; ispinorf = 0; opt = tool_file_format_getPropertyByName(TOOL_FILE_FORMAT(meth), "i-band"); if (opt) iorb = g_value_get_int(tool_option_getValue(opt)); opt = tool_file_format_getPropertyByName(TOOL_FILE_FORMAT(meth), "i-spin"); if (opt) ispin = g_value_get_int(tool_option_getValue(opt)); opt = tool_file_format_getPropertyByName(TOOL_FILE_FORMAT(meth), "i-kpt"); if (opt) ikpt = g_value_get_int(tool_option_getValue(opt)); ispin = CLAMP(ispin, 1, (norbd > 0)?2:1); iorb = CLAMP(iorb, 1, (ispin == 1)?norbu:norbd); ikpt = CLAMP(ikpt, 1, nkpt); } else { iorb = iorbf; ispin = ispinf; ikpt = ikptf; } /* Build the iorbp value from this. */ iorbp = (ikpt - 1) * (norbu + norbd) + (ispin - 1) * norbu + iorb; /* Special treatment for i-complex. */ opt = tool_file_format_getPropertyByName(TOOL_FILE_FORMAT(meth), "i-complex"); if (opt) ispinor = g_value_get_int(tool_option_getValue(opt)); else ispinor = ispinorf; ispinor = CLAMP(ispinor, 0, nspinor); /* We read the wavefunction. */ psiscf = bigdft_read_wave_to_isf(filename, iorbp, h, (int*)n, &nspinor); if (!psiscf) { g_set_error(error, TOOL_FILE_FORMAT_ERROR, TOOL_FILE_FORMAT_ERROR_FORMAT, _("Can't read wavefunction %d from file '%s'."), iorbp, filename); return TRUE; } /* Choose the real, imag or partial density values. */ ntot = n[0] * n[1] * n[2]; if (ispinor == 0) { data = g_malloc(sizeof(double) * ntot); for (i = 0; i < ntot; i++) data[i] = psiscf->data[i] * psiscf->data[i]; if (nspinor == 2) for (i = 0; i < ntot; i++) data[i] += psiscf->data[i + ntot] * psiscf->data[i + ntot]; } else if (ispinor == 2 && nspinor == 2) data = psiscf->data + ntot; else data = psiscf->data; /* Create the scalar field. */ field = visu_scalar_field_new(filename); if (!field) g_warning("impossible to create a VisuScalarField object."); else { memset(box, 0, sizeof(double) * 9); box[0][0] = h[0] * n[0]; box[1][1] = h[1] * n[1]; box[2][2] = h[2] * n[2]; boxObj = visu_box_new_full(box, VISU_BOX_PERIODIC); visu_boxed_setBox(VISU_BOXED(field), VISU_BOXED(boxObj)); g_object_unref(boxObj); visu_scalar_field_setGridSize(field, n); DBG_fprintf(stderr, "BigDFT: transfer density into field object.\n"); wrap = g_array_new(FALSE, FALSE, sizeof(double)); wrap->data = (gchar*)data; wrap->len = ntot; visu_scalar_field_setData(field, wrap, TRUE); g_array_free(wrap, FALSE); /* Add options to the field. */ opt = tool_option_new("i-band", _("orbital id"), G_TYPE_INT); g_value_set_int(tool_option_getValue(opt), iorb); visu_scalar_field_addOption(field, opt); opt = tool_option_new("i-spin", _("spin id"), G_TYPE_STRING); if (ispin == 2) g_value_set_string(tool_option_getValue(opt), "down"); else if (ispin == 1 && norbd > 0) g_value_set_string(tool_option_getValue(opt), "up"); else g_value_set_string(tool_option_getValue(opt), "none"); visu_scalar_field_addOption(field, opt); opt = tool_option_new("i-kpt", _("k-point id"), G_TYPE_INT); g_value_set_int(tool_option_getValue(opt), ikpt); visu_scalar_field_addOption(field, opt); opt = tool_option_new("i-complex", _("real/imag or partial density"), G_TYPE_STRING); if (ispinor == 2) g_value_set_string(tool_option_getValue(opt), "imag"); else if (ispinor == 1) g_value_set_string(tool_option_getValue(opt), "real"); else g_value_set_string(tool_option_getValue(opt), "partial density"); visu_scalar_field_addOption(field, opt); *fieldList = g_list_append(*fieldList, (gpointer)field); } if (ispinor == 0) g_free(data); bigdft_free_wave_to_isf(psiscf); *error = (GError*)0; return TRUE; } static gboolean onFieldChooserHook(GSignalInvocationHint *ihint _U_, guint nvalues _U_, const GValue *param_values, gpointer data _U_) { GtkWidget *hbox, *lbl, *sp, *cb; int norbu, norbd, nkpt, nspinor; int iorbf, ispinf, ikptf, ispinorf; gchar *filename; if (g_value_get_object(param_values + 1) != G_OBJECT(fmtBigDFT)) return FALSE; DBG_fprintf(stderr, "BigDFT: hook on wavefunction selection.\n"); filename = gtk_file_chooser_get_filename(GTK_FILE_CHOOSER(g_value_get_object(param_values))); if (!bigdft_read_wave_descr(filename, &norbu, &norbd, &nkpt, &nspinor, &iorbf, &ispinf, &ikptf, &ispinorf)) { g_warning("Can't read file '%s'.", filename); g_free(filename); return TRUE; } g_free(filename); /* Build the widgets. */ hbox = gtk_hbox_new(FALSE, 0); lbl = gtk_label_new(_("Choose orbital:")); gtk_misc_set_alignment(GTK_MISC(lbl), 0., 0.5); gtk_box_pack_start(GTK_BOX(hbox), lbl, TRUE, TRUE, 0); lbl = gtk_label_new(_("band id:")); gtk_box_pack_start(GTK_BOX(hbox), lbl, TRUE, TRUE, 0); gtk_misc_set_alignment(GTK_MISC(lbl), 1., 0.5); if (norbu > 0) sp = gtk_spin_button_new_with_range(1, norbu, 1); else sp = gtk_spin_button_new_with_range(iorbf, iorbf, 1); g_signal_connect(G_OBJECT(sp), "value-changed", G_CALLBACK(onBand), (gpointer)0); gtk_box_pack_start(GTK_BOX(hbox), sp, FALSE, FALSE, 0); lbl = gtk_label_new(_("spin:")); gtk_misc_set_alignment(GTK_MISC(lbl), 1., 0.5); gtk_box_pack_start(GTK_BOX(hbox), lbl, TRUE, TRUE, 0); cb = gtk_combo_box_text_new(); if ((norbu > 0 || norbd > 0) && norbu == norbd) gtk_combo_box_text_append_text(GTK_COMBO_BOX_TEXT(cb), _("none")); else { gtk_combo_box_text_append_text(GTK_COMBO_BOX_TEXT(cb), _("up")); gtk_combo_box_text_append_text(GTK_COMBO_BOX_TEXT(cb), _("down")); } gtk_combo_box_set_active(GTK_COMBO_BOX(cb), ispinf - 1); g_signal_connect(G_OBJECT(cb), "changed", G_CALLBACK(onSpin), (gpointer)sp); g_object_set_data(G_OBJECT(cb), "norbu", GINT_TO_POINTER(norbu)); g_object_set_data(G_OBJECT(cb), "norbd", GINT_TO_POINTER(norbd)); gtk_box_pack_start(GTK_BOX(hbox), cb, FALSE, FALSE, 0); lbl = gtk_label_new(_("k-point:")); gtk_misc_set_alignment(GTK_MISC(lbl), 1., 0.5); gtk_box_pack_start(GTK_BOX(hbox), lbl, TRUE, TRUE, 0); if (nkpt > 0) sp = gtk_spin_button_new_with_range(1, nkpt, 1); else sp = gtk_spin_button_new_with_range(ikptf, ikptf, 1); g_signal_connect(G_OBJECT(sp), "value-changed", G_CALLBACK(onKpt), (gpointer)0); gtk_box_pack_start(GTK_BOX(hbox), sp, FALSE, FALSE, 0); lbl = gtk_label_new(_("representation:")); gtk_misc_set_alignment(GTK_MISC(lbl), 1., 0.5); gtk_box_pack_start(GTK_BOX(hbox), lbl, TRUE, TRUE, 0); cb = gtk_combo_box_text_new(); gtk_combo_box_text_append_text(GTK_COMBO_BOX_TEXT(cb), _("partial density")); gtk_combo_box_text_append_text(GTK_COMBO_BOX_TEXT(cb), _("real part")); if (nspinor > 1) gtk_combo_box_text_append_text(GTK_COMBO_BOX_TEXT(cb), _("imaginary part")); g_signal_connect(G_OBJECT(cb), "changed", G_CALLBACK(onSpinor), (gpointer)0); gtk_combo_box_set_active(GTK_COMBO_BOX(cb), ispinorf); gtk_box_pack_start(GTK_BOX(hbox), cb, FALSE, FALSE, 0); visu_ui_field_chooser_setOptions(VISU_UI_FIELD_CHOOSER(g_value_get_object(param_values)), hbox); return TRUE; } static void onBand(GtkSpinButton *spin, gpointer data _U_) { tool_file_format_addPropertyInt(TOOL_FILE_FORMAT(fmtBigDFT), "i-band", _("orbital id"), (int)gtk_spin_button_get_value(spin)); } static void onKpt(GtkSpinButton *spin, gpointer data _U_) { tool_file_format_addPropertyInt(TOOL_FILE_FORMAT(fmtBigDFT), "i-kpt", _("k-point id"), (int)gtk_spin_button_get_value(spin)); } static void onSpin(GtkComboBox *combo, gpointer data) { gint ispin; ispin = gtk_combo_box_get_active(combo) + 1; tool_file_format_addPropertyInt(TOOL_FILE_FORMAT(fmtBigDFT), "i-spin", _("spin id"), ispin); if (ispin == 1) gtk_spin_button_set_range(GTK_SPIN_BUTTON(data), 1, GPOINTER_TO_INT(g_object_get_data(G_OBJECT(combo), "norbu"))); else gtk_spin_button_set_range(GTK_SPIN_BUTTON(data), 1, GPOINTER_TO_INT(g_object_get_data(G_OBJECT(combo), "norbd"))); } static void onSpinor(GtkComboBox *combo, gpointer data _U_) { tool_file_format_addPropertyInt(TOOL_FILE_FORMAT(fmtBigDFT), "i-complex", _("real/imag or partial density"), gtk_combo_box_get_active(combo)); } static void onDataNew(GObject *obj _U_, VisuData *dataObj, gpointer data _U_) { g_signal_connect(G_OBJECT(dataObj), "FilesChanged", G_CALLBACK(onFilesChanged), (gpointer)0); } static void onDataReady(GObject *obj _U_, VisuData *dataObj, gpointer data _U_) { GArray *radii; guint *radiiStatus; guint nEle; gint iEle; BigDFT_Wf *wf; BigDFT_Inputs *in; DBG_fprintf(stderr, "Panel BigDFT: caught 'dataRendered' signal.\n"); if (isPanelInitialised) { updateGridLabels(dataObj); if (dataObj) { radii = (GArray*)g_object_get_data(G_OBJECT(dataObj), "BigDFT_radii"); radiiStatus = (guint*)g_object_get_data(G_OBJECT(dataObj), "BigDFT_radiiStatus"); } else { radii = (GArray*)0; radiiStatus = (guint*)0; } disableCallbacks = TRUE; visu_ui_numerical_entry_setValue(VISU_UI_NUMERICAL_ENTRY(entryHgrid[0]), GET_OPT_DBL(fmtWvl, "hx")); visu_ui_numerical_entry_setValue(VISU_UI_NUMERICAL_ENTRY(entryHgrid[1]), GET_OPT_DBL(fmtWvl, "hy")); visu_ui_numerical_entry_setValue(VISU_UI_NUMERICAL_ENTRY(entryHgrid[2]), GET_OPT_DBL(fmtWvl, "hz")); visu_ui_numerical_entry_setValue(VISU_UI_NUMERICAL_ENTRY(entryCrmult), GET_OPT_DBL(fmtWvl, "crmult")); visu_ui_numerical_entry_setValue(VISU_UI_NUMERICAL_ENTRY(entryFrmult), GET_OPT_DBL(fmtWvl, "frmult")); visu_ui_numerical_entry_setValue(VISU_UI_NUMERICAL_ENTRY(entryIxc), GET_OPT_INT(fmtWvl, "ixc")); if (radii && radiiStatus) { nEle = GPOINTER_TO_INT(g_object_get_data(G_OBJECT(dataObj), "BigDFT_ntypes")); DBG_fprintf(stderr, "Panel BigDFT: setup radius combo for %d elements.\n", nEle); iEle = gtk_combo_box_get_active(GTK_COMBO_BOX(cbRadEle[0])); DBG_fprintf(stderr, " | %d element (coarse).\n", iEle); if (iEle >= 0) { visu_ui_numerical_entry_setValue(VISU_UI_NUMERICAL_ENTRY(entryRadius[0]), g_array_index(radii, double, iEle)); gtk_entry_set_icon_from_stock(GTK_ENTRY(entryRadius[0]), GTK_ENTRY_ICON_SECONDARY, radiiIcons[radiiStatus[iEle]]); } iEle = gtk_combo_box_get_active(GTK_COMBO_BOX(cbRadEle[1])); DBG_fprintf(stderr, " | %d element (fine).\n", iEle); if (iEle >= 0) { visu_ui_numerical_entry_setValue(VISU_UI_NUMERICAL_ENTRY(entryRadius[1]), g_array_index(radii, double, nEle + iEle)); gtk_entry_set_icon_from_stock(GTK_ENTRY(entryRadius[1]), GTK_ENTRY_ICON_SECONDARY, radiiIcons[radiiStatus[nEle + iEle]]); } } disableCallbacks = FALSE; } if (dataObj) { wf = (BigDFT_Wf*)g_object_get_data(G_OBJECT(dataObj), "BigDFT_wf"); in = (BigDFT_Inputs*)g_object_get_data(G_OBJECT(dataObj), "BigDFT_inputs"); if (wf && in) { /* We create the orbital descriptors here already for memory estimation or later run. */ DBG_fprintf(stderr, "Panel BigDFT: set-up Lzd.\n"); bigdft_wf_define(wf, in, 0, 1); /* We do the memory estimation for this run. */ DBG_fprintf(stderr, "Panel BigDFT: do memory estimation.\n"); update_memory_estimation(dataObj); } } DBG_fprintf(stderr, "Panel BigDFT: 'DataReady' signal OK.\n"); } static void updateGridLabels(VisuData *dataObj) { GArray *grid; guint cgrid, fgrid; gchar *cgridText, *fgridText; DBG_fprintf(stderr, "Panel BigDFT: update grid labels.\n"); cgrid = 0; fgrid = 0; if (dataObj) { grid = (GArray*)g_object_get_data(G_OBJECT(dataObj), "BigDFT_coarse_grid"); cgrid = (grid)?grid->len:0; grid = (GArray*)g_object_get_data(G_OBJECT(dataObj), "BigDFT_fine_grid"); fgrid = (grid)?grid->len:0; } if (cgrid) cgridText = g_strdup_printf(_("%d grid points"), cgrid); else cgridText = g_strdup(_("no grid")); gtk_label_set_text(GTK_LABEL(lblCGrid), cgridText); g_free(cgridText); if (fgrid) fgridText = g_strdup_printf(_("%d grid points"), fgrid); else fgridText = g_strdup(_("no grid")); gtk_label_set_text(GTK_LABEL(lblFGrid), fgridText); g_free(fgridText); } /* Grid related routines. */ void bigdft_show_grid(VisuData *dataObj, GArray *grid, const gchar *gG, guint id) { VisuElement *ele; guint i; GArray *eleArr, *nEleArr; gboolean newEle; gchar *lbl; float rgba_y[4] = {1.000, 0.750, 0.040, 1.000}; float rgba_b[4] = {0.600, 0.600, 1.000, 1.000}; /* We check that gG is not currently used by dataObj. */ lbl = (id)?g_strdup_printf("%%%s_%d", gG, id):g_strdup(gG); DBG_fprintf(stderr, "BigDFT: show/hide grid '%s' with %d elements on object %p.\n", lbl, (grid)?grid->len:0, (gpointer)dataObj); ele = visu_element_retrieveFromName(lbl, &newEle); g_free(lbl); if (newEle) { visu_rendering_atomic_setRadius(ele, (gG[0] == 'g')?0.5:1.); visu_rendering_atomic_setShape(ele, VISU_RENDERING_ATOMIC_POINT); if (!strcmp(gG, "g")) visu_element_setAllRGBValues(ele, rgba_y); else if (!strcmp(gG, "G")) visu_element_setAllRGBValues(ele, rgba_b); else visu_element_setAllRGBValues(ele, (float*)tool_color_new_bright(id - 1)->rgba); } /* Remove possible old gG nodes. */ visu_node_array_removeNodesOfElement(VISU_NODE_ARRAY(dataObj), ele); /* Allocate space for new gG element. */ if (grid && grid->len > 0) { eleArr = g_array_sized_new(FALSE, FALSE, sizeof(VisuElement*), 1); g_array_append_val(eleArr, ele); nEleArr = g_array_sized_new(FALSE, FALSE, sizeof(guint), 1); g_array_append_val(nEleArr, grid->len); visu_node_array_allocate(VISU_NODE_ARRAY(dataObj), eleArr, nEleArr); g_array_free(eleArr, TRUE); g_array_free(nEleArr, TRUE); /* Add the coordinates. */ for (i = 0; i < grid->len; i++) visu_data_addNodeFromElement(dataObj, ele, ((float*)grid->data) + (3 * i), TRUE, (i == (grid->len - 1))); } } /* Structural loading. */ static gboolean loadBigDFTIn(VisuDataLoader *self, const gchar* filename, VisuData *data, guint nSet _U_, GCancellable *cancel _U_, GError **error) { BigDFT_Locreg *glr; BigDFT_Atoms *atoms; BigDFT_Inputs *in; BigDFT_Wf *wf; GArray *eles, *nEle, *gcoord_c, *gcoord_f; double box[6], h[3], crmult, frmult; GArray *radii; guint i, j, k, grid[3], iGrid, nbGrid; VisuElement *ele; float xyz[3], vect[3]; gboolean *cgrid, *fgrid; guint *radiiStatus; int ixc; gchar *dirname, *cwd; gboolean newAt; VisuBox *boxObj; VisuNodeValuesString *labels; /* gboolean valid; */ /* BigDFT_LocregIter iter; */ g_return_val_if_fail(error && *error == (GError*)0, FALSE); g_return_val_if_fail(data && filename, FALSE); if (!useLoadWithGrid) { DBG_fprintf(stderr, "BigDFT: format disabled.\n"); return FALSE; } /* We change the current working dir to allow BigDFT to look for input files and pseudos. */ dirname = g_path_get_dirname(filename); cwd = g_get_current_dir(); g_chdir(dirname); g_free(dirname); /* Get the input parameters. */ in = g_object_get_data(G_OBJECT(data), "BigDFT_inputs"); if (!in) { g_chdir(cwd); g_free(cwd); return FALSE; } /* See If we have a atoms in cache. */ newAt = FALSE; wf = (BigDFT_Wf*)g_object_get_data(G_OBJECT(data), "BigDFT_wf"); if (!wf) { wf = bigdft_wf_new(in->inputPsiId); if (!bigdft_atoms_set_structure_from_file(BIGDFT_ATOMS(wf->lzd), filename)) { DBG_fprintf(stderr, "BigDFT: '%s' is not a BigDFT file.\n", filename); g_object_unref(G_OBJECT(wf)); wf = (BigDFT_Wf*)0; } else g_object_set_data_full(G_OBJECT(data), "BigDFT_wf", wf, (GDestroyNotify)g_object_unref); newAt = TRUE; } if (!wf) { g_chdir(cwd); g_free(cwd); return FALSE; } atoms = BIGDFT_ATOMS(wf->lzd); /* We get the symmetries and the atom displacements, if any. */ if (newAt) { bigdft_atoms_set_displacement(atoms, in->randdis); bigdft_atoms_set_symmetries(atoms, !in->disableSym, -1., in->elecfield); bigdft_inputs_parse_additional(in, atoms); } /* We get some input parameters. */ ixc = GET_OPT_INT(self, "ixc"); h[0] = GET_OPT_DBL(self, "hx"); h[1] = GET_OPT_DBL(self, "hy"); h[2] = GET_OPT_DBL(self, "hz"); crmult = GET_OPT_DBL(self, "crmult"); frmult = GET_OPT_DBL(self, "frmult"); /* We set up the population. */ eles = g_array_sized_new(FALSE, FALSE, sizeof(VisuElement*), atoms->ntypes); for (i = 0; i < atoms->ntypes; i++) { ele = visu_element_retrieveFromName(atoms->atomnames[i], (gboolean*)0); g_array_insert_val(eles, i, ele); } nEle = g_array_sized_new(FALSE, TRUE, sizeof(guint), atoms->ntypes); g_array_set_size(nEle, atoms->ntypes); for (i = 0; i < atoms->nat; i++) *(&g_array_index(nEle, guint, atoms->iatype[i] - 1)) += 1; visu_node_array_allocate(VISU_NODE_ARRAY(data), eles, nEle); g_array_free(eles, TRUE); g_array_free(nEle, TRUE); /* Radii may already been set for this dataObj. */ radii = (GArray*)g_object_get_data(G_OBJECT(data), "BigDFT_radii"); /* We compute the localisation region and the new coordinates. */ if (newAt) bigdft_atoms_set_psp(atoms, ixc, in->nspin, (const gchar*)0); if (!radii) { radii = bigdft_atoms_get_radii(atoms, crmult, frmult, 0.); g_array_ref(radii); g_object_set_data_full(G_OBJECT(data), "BigDFT_radii", radii, (GDestroyNotify)g_array_unref); radiiStatus = g_malloc0(sizeof(guint) * atoms->ntypes * 3); for (i = 0; i < atoms->ntypes; i++) { radiiStatus[i] = (g_array_index(radii, double, i) == atoms->radii_cf[i])? RADII_VALUE_FILE:RADII_VALUE_COMPUTED; radiiStatus[atoms->ntypes + i] = (g_array_index(radii, double, atoms->ntypes + i) == atoms->radii_cf[atoms->ntypes + i])? RADII_VALUE_FILE:RADII_VALUE_COMPUTED; } g_object_set_data_full(G_OBJECT(data), "BigDFT_radiiStatus", radiiStatus, g_free); g_object_set_data(G_OBJECT(data), "BigDFT_ntypes", GINT_TO_POINTER(atoms->ntypes)); } bigdft_locreg_set_radii(BIGDFT_LOCREG(wf->lzd), radii); bigdft_locreg_set_size(BIGDFT_LOCREG(wf->lzd), h, crmult, frmult); bigdft_lzd_init_d(wf->lzd); bigdft_lzd_set_irreductible_zone(wf->lzd, in->nspin); bigdft_locreg_init_wfd(BIGDFT_LOCREG(wf->lzd)); glr = BIGDFT_LOCREG(wf->lzd); /* We have finished here with BigDFT, we set back the current working dir. */ g_chdir(cwd); g_free(cwd); for (i = 0; i < atoms->nat; i++) { xyz[0] = atoms->rxyz.data[3 * i + 0]; xyz[1] = atoms->rxyz.data[3 * i + 1]; xyz[2] = atoms->rxyz.data[3 * i + 2]; visu_data_addNodeFromIndex(data, atoms->iatype[i] - 1, xyz, FALSE, FALSE); } /* We finish with the box geometry. */ box[0] = atoms->alat[0]; box[1] = 0.; box[2] = atoms->alat[1]; box[3] = 0.; box[4] = 0.; box[5] = atoms->alat[2]; switch (atoms->geocode) { case 'P': boxObj = visu_box_new(box, VISU_BOX_PERIODIC); grid[0] = glr->n[0] + 1; grid[1] = glr->n[1] + 1; grid[2] = glr->n[2] + 1; break; case 'S': boxObj = visu_box_new(box, VISU_BOX_SURFACE_ZX); grid[0] = glr->n[0] + 1; grid[1] = glr->n[1]; grid[2] = glr->n[2] + 1; break; case 'F': boxObj = visu_box_new(box, VISU_BOX_FREE); grid[0] = glr->n[0]; grid[1] = glr->n[1]; grid[2] = glr->n[2]; break; default: g_warning("Unknown geocode."); boxObj = visu_box_new(box, VISU_BOX_PERIODIC); grid[0] = glr->n[0] + 1; grid[1] = glr->n[1] + 1; grid[2] = glr->n[2] + 1; } visu_boxed_setBox(VISU_BOXED(data), VISU_BOXED(boxObj)); g_object_unref(boxObj); visu_box_setMargin(boxObj, visu_node_array_getMaxElementSize(VISU_NODE_ARRAY(data)) + visu_data_getAllNodeExtens(data, boxObj), TRUE); visu_box_setUnit(boxObj, TOOL_UNITS_BOHR); /* Update h values with the possibly computed values of glr. */ SET_OPT_DBL(format, "hx", glr->h[0]); SET_OPT_DBL(format, "hy", glr->h[1]); SET_OPT_DBL(format, "hz", glr->h[2]); /* Additional data. */ nbGrid = (glr->n[0] + 1) * (glr->n[1] + 1) * (glr->n[2] + 1); cgrid = bigdft_locreg_get_grid(glr, GRID_COARSE); gcoord_c = g_array_sized_new(FALSE, FALSE, sizeof(gfloat) * 3, nbGrid); iGrid = 0; for (k = 0; k <= glr->n[2]; k++) for (j = 0; j <= glr->n[1]; j++) for (i = 0; i <= glr->n[0]; i++) { if (cgrid[iGrid] != 0) { vect[0] = (float)i / (float)grid[0]; vect[1] = (float)j / (float)grid[1]; vect[2] = (float)k / (float)grid[2]; g_array_append_val(gcoord_c, vect); } iGrid += 1; } /* gcoord_c = g_array_sized_new(FALSE, FALSE, sizeof(gfloat) * 3, glr->nseg_f); */ /* for (valid = bigdft_locreg_iter_new(glr, &iter, GRID_FINE); valid; */ /* valid = bigdft_locreg_iter_next(&iter)) */ /* { */ /* vect[0] = iter.x0; */ /* vect[1] = iter.y; */ /* vect[2] = iter.z; */ /* g_array_append_val(gcoord_c, vect); */ /* if (iter.x1 != iter.x0) */ /* { */ /* vect[0] = iter.x1; */ /* vect[1] = iter.y; */ /* vect[2] = iter.z; */ /* g_array_append_val(gcoord_c, vect); */ /* } */ /* } */ DBG_fprintf(stderr, "BigDFT: have %d coarse grid points.\n", gcoord_c->len); g_object_set_data_full(G_OBJECT(data), "BigDFT_coarse_grid", (gpointer)gcoord_c, (GDestroyNotify)g_array_unref); g_free(cgrid); if (gcoord_c->len > 0 && useCGrid) bigdft_show_grid(data, gcoord_c, "g", 0); fgrid = bigdft_locreg_get_grid(glr, GRID_FINE); gcoord_f = g_array_sized_new(FALSE, FALSE, sizeof(gfloat) * 3, nbGrid); iGrid = 0; for (k = 0; k <= glr->n[2]; k++) for (j = 0; j <= glr->n[1]; j++) for (i = 0; i <= glr->n[0]; i++) { if (fgrid[iGrid] != 0) { vect[0] = (float)i / (float)grid[0]; vect[1] = (float)j / (float)grid[1]; vect[2] = (float)k / (float)grid[2]; g_array_append_val(gcoord_f, vect); } iGrid += 1; } DBG_fprintf(stderr, "BigDFT: have %d fine grid points.\n", gcoord_f->len); if (gcoord_f->len > 0) g_object_set_data_full(G_OBJECT(data), "BigDFT_fine_grid", (gpointer)gcoord_f, (GDestroyNotify)g_array_unref); else g_array_free(gcoord_f, TRUE); if (gcoord_f->len > 0 && useFGrid) bigdft_show_grid(data, gcoord_f, "G", 0); g_free(fgrid); /* Possible label. */ labels = visu_data_getNodeLabels(data); for (i = 0; i < atoms->nat; i++) visu_node_values_string_setAt (labels, visu_node_array_getFromId(VISU_NODE_ARRAY(data), i), bigdft_atoms_get_extra_as_label(BIGDFT_ATOMS(wf->lzd), i)); return TRUE; } static void onToggleLoad(GtkToggleButton *toggle, gpointer data _U_) { VisuData *dataObj; useLoadWithGrid = gtk_toggle_button_get_active(toggle); dataObj = visu_ui_panel_getData(VISU_UI_PANEL(panelBigDFT)); if (!dataObj) return; visu_ui_rendering_window_reload(visu_ui_main_class_getDefaultRendering()); } static void onHgrid(VisuUiNumericalEntry *entry, gdouble old_value _U_, gpointer data) { gdouble value; const gchar *hgrid[] = {"hx", "hy", "hz"}; VisuBox *boxObj; if (disableCallbacks) return; boxObj = visu_boxed_getBox(visu_ui_panel_getFocused(VISU_UI_PANEL(panelBigDFT))); if (!boxObj) return; value = CLAMP(visu_ui_numerical_entry_getValue(entry), 0.1, 1.); disableCallbacks = TRUE; if (visu_box_getBoundary(boxObj) == VISU_BOX_FREE) { visu_ui_numerical_entry_setValue(VISU_UI_NUMERICAL_ENTRY(entryHgrid[0]), value); visu_ui_numerical_entry_setValue(VISU_UI_NUMERICAL_ENTRY(entryHgrid[1]), value); visu_ui_numerical_entry_setValue(VISU_UI_NUMERICAL_ENTRY(entryHgrid[2]), value); } else visu_ui_numerical_entry_setValue(entry, value); disableCallbacks = FALSE; if (visu_box_getBoundary(boxObj) == VISU_BOX_FREE) { SET_OPT_DBL(fmtWvl, hgrid[0], value); SET_OPT_DBL(fmtWvl, hgrid[1], value); SET_OPT_DBL(fmtWvl, hgrid[2], value); } else SET_OPT_DBL(fmtWvl, hgrid[GPOINTER_TO_INT(data)], value); if (useLoadWithGrid) visu_ui_rendering_window_reload(visu_ui_main_class_getDefaultRendering()); } static void onRmult(VisuUiNumericalEntry *entry, gdouble old_value _U_, gpointer data) { gdouble value; const gchar *mult[] = {"crmult", "frmult"}; if (disableCallbacks) return; value = CLAMP(visu_ui_numerical_entry_getValue(entry), 1., 20.); disableCallbacks = TRUE; visu_ui_numerical_entry_setValue(entry, value); disableCallbacks = FALSE; SET_OPT_DBL(fmtWvl, mult[GPOINTER_TO_INT(data)], value); if (useLoadWithGrid && visu_ui_panel_getData(VISU_UI_PANEL(panelBigDFT))) visu_ui_rendering_window_reload(visu_ui_main_class_getDefaultRendering()); } static void onRadius(VisuUiNumericalEntry *entry, gdouble old_value _U_, gpointer data) { GArray *radii; double value; guint nEle, iEle; guint *radiiStatus; VisuData *dataObj; if (disableCallbacks) return; dataObj = visu_ui_panel_getData(VISU_UI_PANEL(panelBigDFT)); value = CLAMP(visu_ui_numerical_entry_getValue(entry), 0., 15.); disableCallbacks = TRUE; visu_ui_numerical_entry_setValue(entry, value); disableCallbacks = FALSE; if (!dataObj) return; radii = (GArray*)g_object_get_data(G_OBJECT(dataObj), "BigDFT_radii"); radiiStatus = (guint*)g_object_get_data(G_OBJECT(dataObj), "BigDFT_radiiStatus"); g_return_if_fail(radii && radiiStatus); nEle = GPOINTER_TO_INT(g_object_get_data(G_OBJECT(dataObj), "BigDFT_ntypes")); iEle = gtk_combo_box_get_active(GTK_COMBO_BOX(cbRadEle[GPOINTER_TO_INT(data)])); g_array_insert_val(radii, nEle * GPOINTER_TO_INT(data) + iEle, value); radiiStatus[nEle * GPOINTER_TO_INT(data) + iEle] = RADII_VALUE_EDITED; gtk_entry_set_icon_from_stock(GTK_ENTRY(entry), GTK_ENTRY_ICON_SECONDARY, radiiIcons[RADII_VALUE_EDITED]); if (useLoadWithGrid) visu_ui_rendering_window_reload(visu_ui_main_class_getDefaultRendering()); } static void onEleChanged(GtkComboBox *combo, gpointer data) { GArray *radii; guint nEle, iEle; guint *radiiStatus; VisuData *dataObj; disableCallbacks = TRUE; dataObj = visu_ui_panel_getData(VISU_UI_PANEL(panelBigDFT)); if (!dataObj) return; radii = (GArray*)g_object_get_data(G_OBJECT(dataObj), "BigDFT_radii"); radiiStatus = (guint*)g_object_get_data(G_OBJECT(dataObj), "BigDFT_radiiStatus"); if (!radii || !radiiStatus) return; nEle = GPOINTER_TO_INT(g_object_get_data(G_OBJECT(dataObj), "BigDFT_ntypes")); iEle = gtk_combo_box_get_active(combo); if (iEle >= nEle) gtk_combo_box_set_active(combo, nEle - 1); else { visu_ui_numerical_entry_setValue (VISU_UI_NUMERICAL_ENTRY(entryRadius[GPOINTER_TO_INT(data)]), g_array_index(radii, double, nEle * GPOINTER_TO_INT(data) + iEle)); gtk_entry_set_icon_from_stock(GTK_ENTRY(entryRadius[GPOINTER_TO_INT(data)]), GTK_ENTRY_ICON_SECONDARY, radiiIcons[radiiStatus[nEle * GPOINTER_TO_INT(data) + iEle]]); } disableCallbacks = FALSE; } static void onIxc(VisuUiNumericalEntry *entry, gdouble old_value _U_, gpointer data _U_) { if (disableCallbacks) return; SET_OPT_INT(fmtWvl, "ixc", visu_ui_numerical_entry_getValue(entry)); if (useLoadWithGrid && visu_ui_panel_getData(VISU_UI_PANEL(panelBigDFT))) visu_ui_rendering_window_reload(visu_ui_main_class_getDefaultRendering()); } static void onFilesChanged(VisuData *dataObj, guint kind, gpointer data _U_) { BigDFT_Inputs *in; gchar *basename, *ptr, *dirname, *cwd; DBG_fprintf(stderr, "Panel BigDFT: test input from (%d) '%s'.\n", kind, visu_data_getFile(dataObj, 0, (ToolFileFormat**)0)); if (kind != 0 || !useLoadWithGrid || !tool_file_format_match(fmtWvl, visu_data_getFile(dataObj, 0, (ToolFileFormat**)0))) return; /* We change the current working dir to allow BigDFT to look for input files and pseudos. */ dirname = g_path_get_dirname(visu_data_getFile(dataObj, 0, (ToolFileFormat**)0)); cwd = g_get_current_dir(); g_chdir(dirname); g_free(dirname); basename = g_path_get_basename(visu_data_getFile(dataObj, 0, (ToolFileFormat**)0)); ptr = strrchr(basename, '.'); if (ptr) *ptr = '\0'; DBG_fprintf(stderr, "Panel BigDFT: read input files for '%s'.\n", basename); if (strcmp(basename, "posinp")) in = bigdft_inputs_new(basename); else in = bigdft_inputs_new((const gchar*)0); g_free(basename); /* We store the input parameters for future use with this dataObj. */ g_object_set_data_full(G_OBJECT(dataObj), "BigDFT_inputs", in, (GDestroyNotify)bigdft_inputs_free); if (in->files & BIGDFT_INPUTS_DFT) { SET_OPT_DBL(fmtWvl, "hx", in->h[0]); SET_OPT_DBL(fmtWvl, "hy", in->h[1]); SET_OPT_DBL(fmtWvl, "hz", in->h[2]); SET_OPT_DBL(fmtWvl, "crmult", in->crmult); SET_OPT_DBL(fmtWvl, "frmult", in->frmult); SET_OPT_INT(fmtWvl, "ixc", in->ixc); } /* We have finished here with BigDFT, we set back the current working dir. */ g_chdir(cwd); g_free(cwd); } static void onNproc(GtkSpinButton *spin, gpointer data _U_) { SET_OPT_INT(fmtWvl, "nproc", gtk_spin_button_get_value(spin)); update_memory_estimation(visu_ui_panel_getData(VISU_UI_PANEL(panelBigDFT))); } static void update_memory_estimation(VisuData *data) { BigDFT_Inputs *in; BigDFT_Wf *wf; BigDFT_Proj *proj; double frmult; int out_pipe[2], stdout_fileno_old; if (!data) return; wf = (BigDFT_Wf*)g_object_get_data(G_OBJECT(data), "BigDFT_wf"); in = (BigDFT_Inputs*)g_object_get_data(G_OBJECT(data), "BigDFT_inputs"); if (!in || !wf) return; frmult = GET_OPT_DBL(fmtWvl, "frmult"); proj = bigdft_proj_new(BIGDFT_LOCREG(wf->lzd), BIGDFT_ORBS(wf), frmult); stdout_fileno_old = redirect_init(out_pipe); bigdft_memory_get_peak(GET_OPT_INT(fmtWvl, "nproc"), BIGDFT_LOCREG(wf->lzd), in, BIGDFT_ORBS(wf), proj); redirect_dump(out_pipe, stdout_fileno_old); bigdft_proj_free(proj); } static int redirect_init(int out_pipe[2]) { int stdout_fileno_old; /* Flush before redirecting. */ fflush(stdout); /* Make a pipe to redirect stdout. */ stdout_fileno_old = dup(STDOUT_FILENO); #ifndef _WIN32 g_return_val_if_fail((pipe(out_pipe) == 0), stdout_fileno_old); dup2(out_pipe[1], STDOUT_FILENO); #endif return stdout_fileno_old; } #define MAX_FORTRAN_OUTPUT 4096 static void redirect_dump(int out_pipe[2], int stdout_fileno_old) { gchar foutput[MAX_FORTRAN_OUTPUT]; ssize_t ncount; long flags; GtkTextIter startIter; /* Flush before reconnecting. */ fflush(stdout); /* Reconnect stdout. */ dup2(stdout_fileno_old, STDOUT_FILENO); #ifndef _WIN32 /* Make the reading pipe non blocking. */ flags = fcntl(out_pipe[0], F_GETFL); flags |= O_NONBLOCK; fcntl(out_pipe[0], F_SETFL, flags); /* Write Fortran output with prefix... */ foutput[0] = '\0'; ncount = read(out_pipe[0], foutput, MAX_FORTRAN_OUTPUT); foutput[ncount] = '\0'; gtk_text_buffer_set_text(bufMemory, "", -1); gtk_text_buffer_get_start_iter(bufMemory, &startIter); gtk_text_buffer_insert_with_tags_by_name(bufMemory, &startIter, foutput, -1, "typewriter", NULL); /* Close the pipes. */ close(out_pipe[0]); close(out_pipe[1]); #endif } static void exportParameters(GString *data, VisuData *dataObj _U_) { g_string_append_printf(data, "# %s\n", DESC_PARAMETER_BIGDFT); g_string_append_printf(data, "%s[bigdft]: %d\n\n", FLAG_PARAMETER_BIGDFT, useLoadWithGrid); } v_sim-3.8.0/lib/plug-ins/bigdft/bigdft.png000066400000000000000000000110301370110300500203300ustar00rootroot00000000000000PNG  IHDR  i+ pHYsHHFk> vpAg SBIDATXMXw\TWӞ[/H' X QhcCy?cI4G1XbAԈш"R®}o=/{sgΙ33#F$#ąC'q=K@,8%1({,ژ(buIDӡDrψ:D$P'kxt!""6nmviۥRĐL"H9dcz"wƷ# "oa5?Qn&^("",ȁr\VFq^BUbNuX&#Xr\=[E׾rS7--6$$wxԞs|J}z >((;`4<]Isৰ({~(u\r (zv3d#c["IpC: 8Ѕ#MQju[y:;op-PT)QY wn<ܛ'ŝE֘Q e.G=hAҹXa ^B.(=⊹x|R?Q”sOġѺ]l)vD 5 =u/e  - , . i')lJIMI)BWa  ):.۳lOdjວJ ڠ\skbʏrrıv0V!+d-@#w{IiN?kT[rKErզKiYSF$KDD< 3~ J:-~˖2=%~^3mϴQQZ>ck{֞_{pkkţ6.T<Jq<GaRP̐ r_P SV(Hwgړ OJI'3Sf>#w_ajidA3L35hm4]JeQYTt}m}; ,2,Raפkҵ+rQ\|$> (k,4%;9qEgSL333մfUd.}x~RNrך?sle6 {nC4‹DO[IqrCUrLBIO&=VӹL}>lu@yEGگֺJS0̳mChyו6ǥ$5W]ܮtFj]Fdf}Y$_G.g7P\waPf^Ae1[bvhvܳϟ^G{TaQǁL9~Cj)e`3)a8L%SB}S.]m/OCw0sSPr15+G+:3cy~j.IocXfKFˏ-17Wld?Qi G9\h ӓ Q} L6۔iB&?ܯstJY,e*/Fз U**vI=FP)0üBmc?b?wXorțU}nЙit8\l9GQuj8tC'1P69BHp)~/ne8 Ц)oPބ]RaY6K BPF-Ҩ4qȲeli&QCDJ `lku1)+,jh~drU"44K^viL.󍢛*tߑ7;aM*G6YZAF07MV;K,E"*)93>f|Ʈ][^W !C& XWo9d9dVjH-Wx|ver I&t2ekiL-Ԭ-2Kc +(+ r(yN2)C|}3HvTPzEY{O;>}x 9YVkǿ4Tf4e4v>07zM՛,CsYy`Iպu;JeܢEO"|0p3E$<!vYqBzaJdm=%3,Uwug~~vm^U[o5%pJ`oo) &mHڐRΨ.~fc8|ߑxςowlpmlɂ$DA[B!?YxEum;ũ&Ǔv7^T6s}Q"TG:޽K.BTή#jDXwD讃 5'>'ҾRuus!D:$Y$ IHN\X(&i"J^xki:;(J9 i0 61r TY,JrV91-kZ,EzPT$/,ڑ./Knx1K>gx u|fW"7gغce DŽ ˧<0t$2g@yqx"2O %kP+I F 9t2MlCJ'ՠq zxs e%rZrt_HJWI ccl֠=W`^DYp- &DRgGkʻ}WxtJɒQ/&uqI<,y#TWu'79[cݺj 0_6_viZc2uү8  :7PP~ =W%d7O-h*Իߤsҷݩ![H"%SRLpɴcl/Nn)mh sTlq/s/cR W+0ayl[bxoAX_^@D(d1DP9KZj߇%Z\"&9wBX톴i3X35?C:ntZC_dg((_KK5hn5??Vy) r:e2m54xiRӺtia5-8pGdk# \"\KD3P ѵJ$;TK8;IL^w EϼTH̆ LQE]˽).UxqWqA. $Aנ}d4VPZr\9>Vq@ra (ޒE/-D3{ #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include "bigdftplug.h" static GtkWidget *btRun = NULL, *btSCF = NULL; static GtkWidget *btVext, *btDens, *cbOrbsu, *cbOrbsd; #if GTK_MINOR_VERSION > 19 || GTK_MAJOR_VERSION > 2 static GtkWidget *spRun; #endif static gulong sigDens, sigVext; static GtkWidget *cbKpt, *cbWf; enum { LABEL, ACTIVATED, VALUE, N_COLUMNS }; static GtkListStore *orbsd_kpt, *orbsd_spu, *orbsd_spd; typedef struct _StoredWfData { gulong signal; const VisuSurface *surf; } StoredWfData; enum { SCF_ITER, SCF_TYPE, SCF_LABEL, SCF_IKPT, SCF_IORB, SCF_ISPIN, SCF_NSPINOR, SCF_EVAL, SCF_OCCUP, SCF_TOL, SCF_MEMORY, SCF_DATA, SCF_OBJECT, SCF_GLR, SCF_N_COLUMNS }; enum { SCF_TYPE_WF, SCF_TYPE_V_EXT, SCF_TYPE_DENSITY, SCF_TYPE_ITER_HAM, SCF_TYPE_ITER_SUB, SCF_TYPE_ITER_WFN }; static GtkTreeStore *scfdata; struct _socketStuff { BigDFT_SignalsClient *client; GCancellable *cancellable; GAsyncQueue *message; BigDFT_Wf *wf; BigDFT_LocalFields *denspot; BigDFT_Energs *energs; BigDFT_OptLoop *optloop; }; /* Local methods. */ static void update_orbsd(const VisuData *dataObj); static void treeGetSCFIter(GtkTreeIter *parent, guint iscf, BigDFT_OptLoop *loop); /* Callbacks. */ static void onRunBigDFT(GtkToggleButton *bt, gpointer data); static void onCheckDens(GtkToggleButton *bt, gpointer data); static void onCheckVext(GtkToggleButton *bt, gpointer data); static void onOrbsdToggled(GtkComboBox *cb, gpointer user_data); static void ptInfos(GtkTreeViewColumn *tree_column, GtkCellRenderer *cell, GtkTreeModel *tree_model, GtkTreeIter *iter, gpointer data); static void onGetSCF(GtkButton *bt, gpointer data); static gboolean onTreeViewClicked(GtkWidget *widget, GdkEventButton *event, gpointer user_data); static void onVextReady(BigDFT_LocalFields *denspot, gpointer data); static void onDensityReady(BigDFT_LocalFields *denspot, guint iter, gpointer data); static void onIter(BigDFT_OptLoop *optloop, BigDFT_Energs *energs, gpointer data); static void onDone(BigDFT_OptLoop *optloop, BigDFT_Energs *energs, gpointer data); static void onPsiReady(BigDFT_Wf *wf, guint iter, gpointer data); static void onOneWaveReady(BigDFT_Wf *wf, guint iter, GArray *psic, BigDFT_PsiId ipsi, guint ikpt, guint iorb, guint ispin, gpointer data); static void onSocketClose(gpointer data); static void onDataReady(GObject *obj, VisuData *dataObj, gpointer data); void bdft_run_init() { cbKpt = (GtkWidget*)0; cbWf = (GtkWidget*)0; orbsd_kpt = gtk_list_store_new(N_COLUMNS, G_TYPE_STRING, G_TYPE_BOOLEAN, G_TYPE_UINT); orbsd_spu = gtk_list_store_new(N_COLUMNS, G_TYPE_STRING, G_TYPE_BOOLEAN, G_TYPE_UINT); orbsd_spd = gtk_list_store_new(N_COLUMNS, G_TYPE_STRING, G_TYPE_BOOLEAN, G_TYPE_UINT); scfdata = gtk_tree_store_new(SCF_N_COLUMNS, G_TYPE_UINT, G_TYPE_UINT, G_TYPE_STRING, G_TYPE_UINT, G_TYPE_UINT, G_TYPE_UINT, G_TYPE_UINT, G_TYPE_DOUBLE, G_TYPE_DOUBLE, G_TYPE_DOUBLE, G_TYPE_UINT, G_TYPE_ARRAY, G_TYPE_OBJECT, G_TYPE_OBJECT); sigDens = 0; sigVext = 0; g_signal_connect(VISU_OBJECT_INSTANCE, "dataRendered", G_CALLBACK(onDataReady), NULL); } static void onDataReady(GObject *obj _U_, VisuData *dataObj, gpointer data _U_) { double *radii; guint *radiiStatus; /* We update the combos. */ DBG_fprintf(stderr, "BigDFT Run: caught 'dataRendered' signal.\n"); update_orbsd(dataObj); gtk_tree_store_clear(scfdata); if (!btRun || !btSCF) return; gtk_widget_set_sensitive(btRun, FALSE); gtk_widget_set_sensitive(btSCF, FALSE); if (dataObj) { radii = (double*)g_object_get_data(G_OBJECT(dataObj), "BigDFT_radii"); radiiStatus = (guint*)g_object_get_data(G_OBJECT(dataObj), "BigDFT_radiiStatus"); } else { radii = (double*)0; radiiStatus = (guint*)0; } if (radii && radiiStatus) gtk_widget_set_sensitive(btRun, TRUE); DBG_fprintf(stderr, "BigDFT run: 'DataReady' signal OK.\n"); } GtkWidget* bdft_run_tab(guint nEle, BigDFT_Wf *wf) { GtkWidget *hbox, *wd, *ct, *vbox2; GtkCellRenderer *render; GtkTreeViewColumn *col; /* Running BigDFT. */ vbox2 = gtk_vbox_new(FALSE, 2); /* The run line. */ hbox = gtk_hbox_new(FALSE, 2); gtk_box_pack_start(GTK_BOX(vbox2), hbox, FALSE, FALSE, 0); wd = gtk_combo_box_text_new_with_entry(); gtk_combo_box_text_append(GTK_COMBO_BOX_TEXT(wd), "local", _("Run locally")); gtk_combo_box_text_append(GTK_COMBO_BOX_TEXT(wd), "localhost", g_get_host_name()); gtk_combo_box_set_active(GTK_COMBO_BOX(wd), 0); gtk_box_pack_start(GTK_BOX(hbox), wd, FALSE, FALSE, 0); btRun = gtk_toggle_button_new_with_label(_("Go go go...")); gtk_widget_set_sensitive(btRun, (nEle > 0)); g_signal_connect(G_OBJECT(btRun), "toggled", G_CALLBACK(onRunBigDFT), (gpointer)wd); gtk_box_pack_end(GTK_BOX(hbox), btRun, FALSE, FALSE, 0); #if GTK_MINOR_VERSION > 19 || GTK_MAJOR_VERSION > 2 spRun = gtk_spinner_new(); gtk_widget_set_no_show_all(GTK_WIDGET(spRun), TRUE); gtk_box_pack_end(GTK_BOX(hbox), spRun, FALSE, FALSE, 0); #endif /* The denspot line. */ hbox = gtk_hbox_new(FALSE, 2); gtk_box_pack_start(GTK_BOX(vbox2), hbox, FALSE, FALSE, 0); wd = gtk_label_new(_("Rho / V:")); gtk_misc_set_alignment(GTK_MISC(wd), 0., 0.5); gtk_box_pack_start(GTK_BOX(hbox), wd, TRUE, TRUE, 0); btDens = gtk_check_button_new_with_mnemonic(_("_Density")); g_signal_connect(G_OBJECT(btDens), "toggled", G_CALLBACK(onCheckDens), (gpointer)0); gtk_box_pack_start(GTK_BOX(hbox), btDens, FALSE, FALSE, 0); btVext = gtk_check_button_new_with_mnemonic(_("V_ext")); g_signal_connect(G_OBJECT(btVext), "toggled", G_CALLBACK(onCheckVext), (gpointer)0); /* gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON(btVext), TRUE); */ gtk_box_pack_start(GTK_BOX(hbox), btVext, FALSE, FALSE, 0); wd = gtk_check_button_new_with_mnemonic(_("V_hartr")); gtk_widget_set_sensitive(wd, FALSE); gtk_box_pack_start(GTK_BOX(hbox), wd, FALSE, FALSE, 0); wd = gtk_check_button_new_with_mnemonic(_("V_xc")); gtk_widget_set_sensitive(wd, FALSE); gtk_box_pack_start(GTK_BOX(hbox), wd, FALSE, FALSE, 0); /* The wf lines. */ hbox = gtk_hbox_new(FALSE, 2); gtk_box_pack_start(GTK_BOX(vbox2), hbox, FALSE, FALSE, 0); wd = gtk_label_new(_("Wavefunctions:")); gtk_misc_set_alignment(GTK_MISC(wd), 0., 0.5); gtk_box_pack_start(GTK_BOX(hbox), wd, TRUE, TRUE, 0); wd = gtk_label_new(_("up")); gtk_box_pack_start(GTK_BOX(hbox), wd, FALSE, FALSE, 0); cbOrbsu = gtk_combo_box_new_with_model(GTK_TREE_MODEL(orbsd_spu)); render = gtk_cell_renderer_toggle_new(); g_signal_connect(G_OBJECT(cbOrbsu), "changed", G_CALLBACK(onOrbsdToggled), (gpointer)orbsd_spu); gtk_cell_layout_pack_start(GTK_CELL_LAYOUT(cbOrbsu), render, FALSE); gtk_cell_layout_add_attribute(GTK_CELL_LAYOUT(cbOrbsu), render, "active", ACTIVATED); render = gtk_cell_renderer_text_new(); gtk_cell_layout_pack_start(GTK_CELL_LAYOUT(cbOrbsu), render, FALSE); gtk_cell_layout_add_attribute(GTK_CELL_LAYOUT(cbOrbsu), render, "text", LABEL); gtk_box_pack_start(GTK_BOX(hbox), cbOrbsu, FALSE, FALSE, 0); wd = gtk_label_new(_("down")); gtk_box_pack_start(GTK_BOX(hbox), wd, FALSE, FALSE, 0); cbOrbsd = gtk_combo_box_new_with_model(GTK_TREE_MODEL(orbsd_spd)); render = gtk_cell_renderer_toggle_new(); g_signal_connect(G_OBJECT(cbOrbsd), "changed", G_CALLBACK(onOrbsdToggled), (gpointer)orbsd_spd); gtk_cell_layout_pack_start(GTK_CELL_LAYOUT(cbOrbsd), render, FALSE); gtk_cell_layout_add_attribute(GTK_CELL_LAYOUT(cbOrbsd), render, "active", ACTIVATED); render = gtk_cell_renderer_text_new(); gtk_cell_layout_pack_start(GTK_CELL_LAYOUT(cbOrbsd), render, FALSE); gtk_cell_layout_add_attribute(GTK_CELL_LAYOUT(cbOrbsd), render, "text", LABEL); gtk_box_pack_start(GTK_BOX(hbox), cbOrbsd, FALSE, FALSE, 0); hbox = gtk_hbox_new(FALSE, 2); gtk_box_pack_start(GTK_BOX(vbox2), hbox, FALSE, FALSE, 0); wd = gtk_label_new(_("for k-point(s)")); gtk_misc_set_alignment(GTK_MISC(wd), 1., 0.5); gtk_box_pack_start(GTK_BOX(hbox), wd, TRUE, TRUE, 0); cbKpt = gtk_combo_box_new_with_model(GTK_TREE_MODEL(orbsd_kpt)); render = gtk_cell_renderer_toggle_new(); g_signal_connect(G_OBJECT(cbKpt), "changed", G_CALLBACK(onOrbsdToggled), (gpointer)orbsd_kpt); gtk_cell_layout_pack_start(GTK_CELL_LAYOUT(cbKpt), render, FALSE); gtk_cell_layout_add_attribute(GTK_CELL_LAYOUT(cbKpt), render, "active", ACTIVATED); render = gtk_cell_renderer_text_new(); gtk_cell_layout_pack_start(GTK_CELL_LAYOUT(cbKpt), render, FALSE); gtk_cell_layout_add_attribute(GTK_CELL_LAYOUT(cbKpt), render, "text", LABEL); if (wf && BIGDFT_ORBS(wf)->nkpts ==1) gtk_combo_box_set_active(GTK_COMBO_BOX(cbKpt), 0); gtk_box_pack_start(GTK_BOX(hbox), cbKpt, FALSE, FALSE, 0); /* The treeview. */ ct = gtk_scrolled_window_new((GtkAdjustment*)0, (GtkAdjustment*)0); gtk_scrolled_window_set_policy(GTK_SCROLLED_WINDOW(ct), GTK_POLICY_AUTOMATIC, GTK_POLICY_AUTOMATIC); gtk_scrolled_window_set_shadow_type(GTK_SCROLLED_WINDOW(ct), GTK_SHADOW_ETCHED_IN); gtk_box_pack_start(GTK_BOX(vbox2), ct, TRUE, TRUE, 0); wd = gtk_tree_view_new_with_model(GTK_TREE_MODEL(scfdata)); gtk_tree_view_set_headers_visible(GTK_TREE_VIEW(wd), FALSE); gtk_container_add(GTK_CONTAINER(ct), wd); /* Columns. */ render = gtk_cell_renderer_text_new(); col = gtk_tree_view_column_new_with_attributes("", render, "markup", SCF_LABEL, NULL); gtk_tree_view_column_set_expand(col, TRUE); gtk_tree_view_append_column(GTK_TREE_VIEW(wd), col); render = gtk_cell_renderer_text_new(); col = gtk_tree_view_column_new_with_attributes("", render, NULL); gtk_tree_view_column_set_cell_data_func(col, render, ptInfos, (gpointer)0, (GDestroyNotify)0); g_signal_connect(G_OBJECT(wd), "button-release-event", G_CALLBACK(onTreeViewClicked), (gpointer)col); gtk_tree_view_append_column(GTK_TREE_VIEW(wd), col); /* Action buttons. */ hbox = gtk_hbox_new(FALSE, 2); gtk_box_pack_start(GTK_BOX(vbox2), hbox, FALSE, FALSE, 0); btSCF = gtk_button_new_with_label(_("retrieve selection")); gtk_widget_set_sensitive(btSCF, FALSE); g_signal_connect(G_OBJECT(btSCF), "clicked", G_CALLBACK(onGetSCF), (gpointer)wd); gtk_box_pack_end(GTK_BOX(hbox), btSCF, FALSE, FALSE, 0); wd = gtk_label_new(_("Wfn. repr.:")); gtk_box_pack_start(GTK_BOX(hbox), wd, FALSE, FALSE, 0); cbWf = gtk_combo_box_text_new(); gtk_combo_box_text_append_text(GTK_COMBO_BOX_TEXT(cbWf), _("real part")); gtk_combo_box_text_append_text(GTK_COMBO_BOX_TEXT(cbWf), _("imaginary part")); gtk_combo_box_text_append_text(GTK_COMBO_BOX_TEXT(cbWf), _("partial density")); gtk_combo_box_set_active(GTK_COMBO_BOX(cbWf), 0); gtk_box_pack_start(GTK_BOX(hbox), cbWf, FALSE, FALSE, 0); return vbox2; } static void onOrbsdToggled(GtkComboBox *cb, gpointer data) { GtkTreeIter iter; GtkTreeModel *model; gboolean valid; VisuData *dataObj; BigDFT_Wf *wf; guint i, j, val; gchar *name; StoredWfData *dt; if (!gtk_combo_box_get_active_iter(cb, &iter)) return; gtk_tree_model_get(GTK_TREE_MODEL(data), &iter, ACTIVATED, &valid, VALUE, &val, -1); gtk_list_store_set(GTK_LIST_STORE(data), &iter, ACTIVATED, !valid, -1); /* Connect or disconnect the one-wave-ready signals. */ dataObj = visu_ui_panel_getData(VISU_UI_PANEL(panelBigDFT)); if (!dataObj) return; wf = (BigDFT_Wf*)g_object_get_data(G_OBJECT(dataObj), "BigDFT_wf"); dt = (StoredWfData*)g_object_get_data(G_OBJECT(dataObj), "BigDFT_storedWf"); if (!dt || !wf) return; if (valid) { /* We remove all signals according to val. */ if (cb == GTK_COMBO_BOX(cbOrbsd)) val += BIGDFT_ORBS(wf)->norbu; for (i = 0; i < (cb == GTK_COMBO_BOX(cbKpt))?BIGDFT_ORBS(wf)->norb: BIGDFT_ORBS(wf)->nkpts; i++) { if (cb == GTK_COMBO_BOX(cbKpt)) j = val * BIGDFT_ORBS(wf)->norb + i; else j = i * BIGDFT_ORBS(wf)->norb + val; if (dt[j].signal) g_signal_handler_disconnect(G_OBJECT(wf), dt[j].signal); dt[j].signal = 0; } } else { /* We add signals to each checked values. */ for (i = 0; i < ((cb == GTK_COMBO_BOX(cbKpt))?BIGDFT_ORBS(wf)->norb: BIGDFT_ORBS(wf)->nkpts); i++) { if (cb == GTK_COMBO_BOX(cbKpt) && i < BIGDFT_ORBS(wf)->norbu) { model = GTK_TREE_MODEL(orbsd_spu); j = BIGDFT_ORBS(wf)->norbu - i - 1; } else if (cb == GTK_COMBO_BOX(cbKpt)) { model = GTK_TREE_MODEL(orbsd_spd); j = BIGDFT_ORBS(wf)->norb - i - 1; } else { model = GTK_TREE_MODEL(orbsd_kpt); j = i; } if (gtk_tree_model_iter_nth_child(model, &iter, NULL, j)) { gtk_tree_model_get(model, &iter, ACTIVATED, &valid, VALUE, &j, -1); if (valid) { if (cb == GTK_COMBO_BOX(cbOrbsu)) { name = g_strdup_printf("one-wave-ready::%d-%d-up", j + 1, val + 1); j = j * BIGDFT_ORBS(wf)->norb + val; } else if (cb == GTK_COMBO_BOX(cbOrbsd)) { name = g_strdup_printf("one-wave-ready::%d-%d-down", j + 1, val + 1); j = j * BIGDFT_ORBS(wf)->norb + val; } else if (i < BIGDFT_ORBS(wf)->norbu) { name = g_strdup_printf("one-wave-ready::%d-%d-up", val + 1, j + 1); j = val * BIGDFT_ORBS(wf)->norb + j; } else { name = g_strdup_printf("one-wave-ready::%d-%d-down", val + 1, j + 1); j = val * BIGDFT_ORBS(wf)->norb + j; } DBG_fprintf(stderr, "BigDFT Run: adding '%s' signal.\n", name); dt[j].signal = g_signal_connect(G_OBJECT(wf), name, G_CALLBACK(onOneWaveReady), (gpointer)0); g_free(name); } } } } } static void ptInfos(GtkTreeViewColumn *tree_column, GtkCellRenderer *cell, GtkTreeModel *tree_model, GtkTreeIter *iter, gpointer data _U_) { double eval, occ, fact, tol; gchar *lbl; guint kind, units; gpointer unitsFact; const gchar *unitsLbl[] = {"Ht", "eV"}; units = GPOINTER_TO_INT(g_object_get_data(G_OBJECT(tree_column), "units")); unitsFact = g_object_get_data(G_OBJECT(tree_column), "unitsFact"); if (unitsFact) fact = *(double*)unitsFact; else fact = 1.; gtk_tree_model_get(tree_model, iter, SCF_EVAL, &eval, SCF_OCCUP, &occ, SCF_TYPE, &kind, SCF_TOL, &tol, -1); switch (kind) { case SCF_TYPE_WF: lbl = g_strdup_printf("%5.5f | %3.3f", eval * fact, occ); break; case SCF_TYPE_ITER_WFN: if (eval != 0.) if (tol > 0. && occ < tol) lbl = g_strdup_printf("%10.10f %s (%2.2e)", eval * fact, unitsLbl[units], occ); else if (tol > 0. && occ >= tol) lbl = g_strdup_printf("%10.10f %s (%2.2e)", eval * fact, unitsLbl[units], occ); else lbl = g_strdup_printf("%10.10f %s (%2.2e)", eval * fact, unitsLbl[units], occ); else lbl = g_strdup(""); break; default: lbl = g_strdup(""); } g_object_set(G_OBJECT(cell), "markup", lbl, NULL); g_free(lbl); } static void onGetSCF(GtkButton *bt _U_, gpointer user_data) { GtkTreeIter iter; GtkTreeModel *model; GArray *psic, *wrap; double *data, *data2; const BigDFT_Locreg *glr; BigDFT_Wf *wf; BigDFT_LocalFields *denspot; VisuScalarField *field; gchar *lbl, *str; double box[3][3]; float shift[3]; guint kind, istep, ikpt, iorb, ispin, nspinor, psiSize, i; const VisuSurface *surf; float *isoValues; VisuData *dataObj; StoredWfData *dt; const gchar *names; VisuBox *boxObj; if (!gtk_tree_selection_get_selected (gtk_tree_view_get_selection(GTK_TREE_VIEW(user_data)), &model, &iter)) return; dataObj = visu_ui_panel_getData(VISU_UI_PANEL(panelBigDFT)); if (!dataObj) return; gtk_tree_model_get(model, &iter, SCF_TYPE, &kind, -1); dt = (StoredWfData*)0; surf = (const VisuSurface*)0; switch (kind) { case SCF_TYPE_WF: gtk_tree_model_get(model, &iter, SCF_DATA, &psic, SCF_LABEL, &str, SCF_ITER, &istep, SCF_GLR, &glr, SCF_OBJECT, &wf, SCF_IKPT, &ikpt, SCF_IORB, &iorb, SCF_NSPINOR, &nspinor, SCF_ISPIN, &ispin, SCF_MEMORY, &psiSize, -1); if (gtk_combo_box_get_active(GTK_COMBO_BOX(cbWf)) == BIGDFT_PARTIAL_DENSITY) lbl = g_strdup_printf(_("partial density (iter: %d)\n ikpt: %d, " "iorb: %d"), istep, ikpt + 1, iorb + 1); else lbl = g_strdup_printf(_("wavefunction (iter: %d)\n ikpt: %d, " "iorb: %d"), istep, ikpt + 1, iorb + 1); /* Depending on the spinor representation, we work on data. */ data = (double*)0; if (gtk_combo_box_get_active(GTK_COMBO_BOX(cbWf)) == BIGDFT_REAL || gtk_combo_box_get_active(GTK_COMBO_BOX(cbWf)) == BIGDFT_PARTIAL_DENSITY) data = bigdft_locreg_convert_to_isf(glr, (double*)psic->data); else if (nspinor == 2) data = bigdft_locreg_convert_to_isf(glr, ((double*)psic->data) + psiSize / 2); else visu_ui_raiseWarning(_("Retrieve wavefunction"), _("Wavefunction has no imaginary part"), NULL); if (gtk_combo_box_get_active(GTK_COMBO_BOX(cbWf)) == BIGDFT_PARTIAL_DENSITY && nspinor == 1) for (i = 0; i < glr->ni[0] * glr->ni[1] * glr->ni[2]; i++) data[i] = data[i] * data[i]; if (gtk_combo_box_get_active(GTK_COMBO_BOX(cbWf)) == BIGDFT_PARTIAL_DENSITY && nspinor == 2) { data2 = bigdft_locreg_convert_to_isf(glr, ((double*)psic->data) + psiSize / 2); for (i = 0; i < glr->ni[0] * glr->ni[1] * glr->ni[2]; i++) data[i] = data[i] * data[i] + data2[i] * data2[i]; g_free(data2); } g_array_unref(psic); g_free(str); /* We get the surface of the first wavefunction drawn. */ dt = (StoredWfData*)g_object_get_data(G_OBJECT(dataObj), "BigDFT_storedWf"); surf = (dt)?dt[ikpt * BIGDFT_ORBS(wf)->norb + iorb + ((ispin == BIGDFT_SPIN_DOWN)?BIGDFT_ORBS(wf)->norbu:0)].surf: (const VisuSurface*)0; break; case SCF_TYPE_V_EXT: gtk_tree_model_get(model, &iter, SCF_OBJECT, &denspot, SCF_GLR, &glr, -1); data = denspot->v_ext; lbl = g_strdup(_("external potential")); break; case SCF_TYPE_DENSITY: gtk_tree_model_get(model, &iter, SCF_DATA, &psic, SCF_GLR, &glr, SCF_OBJECT, &denspot, SCF_ITER, &istep, -1); data = (double*)psic->data; lbl = g_strdup_printf(_("electronic density (iter: %d)"), istep); break; default: glr = (const BigDFT_Locreg*)0; data = (double*)0; psic = (GArray*)0; break; } if (!data || !glr) return; field = visu_scalar_field_new(lbl); g_free(lbl); if (!field) g_warning("impossible to create a VisuScalarField object."); else { memset(box, 0, sizeof(double) * 9); box[0][0] = glr->h[0] * glr->ni[0] * 0.5; box[1][1] = glr->h[1] * glr->ni[1] * 0.5; box[2][2] = glr->h[2] * glr->ni[2] * 0.5; boxObj = visu_box_new_full(box, (BIGDFT_ATOMS(glr)->geocode != 'F')?VISU_BOX_PERIODIC:VISU_BOX_FREE); visu_boxed_setBox(VISU_BOXED(field), VISU_BOXED(boxObj)); g_object_unref(boxObj); visu_scalar_field_setGridSize(field, glr->ni); shift[0] = glr->h[0] * (glr->ni[0] - 2 * glr->n[0] - 2) * 0.25 - glr->h[0] * glr->ns[0]; shift[1] = glr->h[1] * (glr->ni[1] - 2 * glr->n[1] - 2) * 0.25 - glr->h[1] * glr->ns[1]; shift[2] = glr->h[2] * (glr->ni[2] - 2 * glr->n[2] - 2) * 0.25 - glr->h[2] * glr->ns[2]; if (BIGDFT_ATOMS(glr)->geocode == 'S') shift[1] = glr->h[1] * (glr->ni[1] - 2 * glr->n[1] - 3) * 0.25 - glr->h[1] * glr->ns[1]; visu_scalar_field_setOriginShift(field, shift); wrap = g_array_new(FALSE, FALSE, sizeof(double)); wrap->data = (gchar*)data; wrap->len = glr->ni[0] * glr->ni[1] * glr->ni[2]; visu_scalar_field_setData(field, wrap, TRUE); g_array_free(wrap, FALSE); visu_scalarfield_set_add(visu_scalarfield_set_getDefault(), lbl, field); visu_ui_panel_surfaces_setUsed(TRUE); if (surf) { isoValues = visu_surface_getPropertyFloat((VisuSurface*)surf, VISU_SURFACE_PROPERTY_POTENTIAL); names = visu_surface_resource_getLabel(visu_surface_getResource((VisuSurface*)surf)); visu_ui_panel_surfaces_compute(field, isoValues, &names, 1); } else visu_ui_panel_surfaces_computeAuto(field); } g_object_unref(G_OBJECT(glr)); switch (kind) { case SCF_TYPE_WF: if (dt) dt[ikpt * BIGDFT_ORBS(wf)->norb + iorb + ((ispin == BIGDFT_SPIN_DOWN)?BIGDFT_ORBS(wf)->norbu:0)].surf = surf; g_object_unref(wf); g_free(data); break; case SCF_TYPE_DENSITY: g_array_unref(psic); case SCF_TYPE_V_EXT: g_object_unref(G_OBJECT(denspot)); break; default: break; } } static void onUnitSetHt(GtkCheckMenuItem *item, gpointer data) { static double fact = 1.; if (!gtk_check_menu_item_get_active(item)) return; g_object_set_data(G_OBJECT(data), "unitsFact", &fact); g_object_set_data(G_OBJECT(data), "units", GINT_TO_POINTER(0)); } static void onUnitSeteV(GtkCheckMenuItem *item, gpointer data) { static double fact = 27.2113834; if (!gtk_check_menu_item_get_active(item)) return; g_object_set_data(G_OBJECT(data), "unitsFact", &fact); g_object_set_data(G_OBJECT(data), "units", GINT_TO_POINTER(1)); } static void onSaveFile(GtkMenuItem *item _U_, gpointer data) { GtkTreeIter iter; GtkTreeModel *model; guint kind, ikpt, iorb, ispin; GArray *psic; BigDFT_Wf *wf; if (!gtk_tree_selection_get_selected (gtk_tree_view_get_selection(GTK_TREE_VIEW(data)), &model, &iter)) return; gtk_tree_model_get(model, &iter, SCF_TYPE, &kind, -1); switch (kind) { case SCF_TYPE_WF: gtk_tree_model_get(model, &iter, SCF_DATA, &psic, SCF_OBJECT, &wf, SCF_IKPT, &ikpt, SCF_IORB, &iorb, SCF_ISPIN, &ispin, -1); bigdft_wf_write_psi_compress(wf, "wfn", BIGDFT_WF_FORMAT_BINARY, (double*)psic->data, ikpt + 1, iorb + 1, ispin, psic->len / BIGDFT_ORBS(wf)->nspinor); break; case SCF_TYPE_V_EXT: break; case SCF_TYPE_DENSITY: break; default: break; } } static gboolean onTreeViewClicked(GtkWidget *widget, GdkEventButton *event, gpointer user_data) { GtkWidget *menu, *item; GSList *group; guint units, kind; gboolean sensitive; GtkTreeIter iter; GtkTreeModel *model; if (event->button != 3) return FALSE; DBG_fprintf(stderr, "BigDFT: right clic detected.\n"); units = GPOINTER_TO_INT(g_object_get_data(G_OBJECT(user_data), "units")); menu = gtk_menu_new(); item = gtk_radio_menu_item_new_with_mnemonic((GSList*)0, _("Energies in _Ht")); group = gtk_radio_menu_item_get_group(GTK_RADIO_MENU_ITEM(item)); g_signal_connect(G_OBJECT(item), "toggled", G_CALLBACK(onUnitSetHt), user_data); gtk_menu_shell_append(GTK_MENU_SHELL(menu), item); item = gtk_radio_menu_item_new_with_mnemonic(group, _("Energies in _eV")); if (units == 1) gtk_check_menu_item_set_active(GTK_CHECK_MENU_ITEM(item), TRUE); g_signal_connect(G_OBJECT(item), "toggled", G_CALLBACK(onUnitSeteV), user_data); gtk_menu_shell_append(GTK_MENU_SHELL(menu), item); item = gtk_separator_menu_item_new(); gtk_menu_shell_append(GTK_MENU_SHELL(menu), item); /* See if we have a save item. */ sensitive = FALSE; if (gtk_tree_selection_get_selected (gtk_tree_view_get_selection(GTK_TREE_VIEW(widget)), &model, &iter)) { gtk_tree_model_get(model, &iter, SCF_TYPE, &kind, -1); sensitive = (kind == SCF_TYPE_WF); } item = gtk_image_menu_item_new_from_stock(GTK_STOCK_SAVE, NULL); gtk_widget_set_sensitive(item, sensitive); g_signal_connect(G_OBJECT(item), "activate", G_CALLBACK(onSaveFile), widget); gtk_menu_shell_append(GTK_MENU_SHELL(menu), item); gtk_widget_show_all(menu); gtk_menu_popup(GTK_MENU(menu), NULL, NULL, NULL, NULL, 3, event->time); return FALSE; } static void onVextReady(BigDFT_LocalFields *denspot, gpointer data) { GtkTreeIter parent, child; guint vSize; gchar *lbl, *lblSize; DBG_fprintf(stderr, "BigDFT (%p): get V_ext ready signal.\n", (gpointer)g_thread_self()); if (!gtk_toggle_button_get_active(GTK_TOGGLE_BUTTON(btVext))) return; gtk_widget_set_sensitive(btSCF, TRUE); treeGetSCFIter(&parent, 0, NULL); vSize = denspot->ni[0] * denspot->ni[1] * denspot->ni[2] * sizeof(double); #if GLIB_MINOR_VERSION < 30 lblSize = g_format_size_for_display((goffset)vSize); #else lblSize = g_format_size((guint64)vSize); #endif lbl = g_strdup_printf("external potential " "- %s", lblSize); gtk_tree_store_insert(scfdata, &child, &parent, -1); gtk_tree_store_set(scfdata, &child, SCF_ITER, 0, SCF_TYPE, SCF_TYPE_V_EXT, SCF_LABEL, lbl, SCF_MEMORY, vSize, SCF_OBJECT, denspot, SCF_GLR, G_OBJECT(data), -1); g_free(lblSize); g_free(lbl); } static void onDensityReady(BigDFT_LocalFields *denspot, guint iter, gpointer data) { GtkTreeIter parent, child; guint vSize; gchar *lbl, *lblSize; GArray *dens; DBG_fprintf(stderr, "BigDFT (%p): get density ready signal.\n", (gpointer)g_thread_self()); if (!gtk_toggle_button_get_active(GTK_TOGGLE_BUTTON(btDens))) return; gtk_widget_set_sensitive(btSCF, TRUE); treeGetSCFIter(&parent, iter, NULL); vSize = denspot->ni[0] * denspot->ni[1] * denspot->ni[2]; #if GLIB_MINOR_VERSION < 30 lblSize = g_format_size_for_display((goffset)(vSize * sizeof(double))); #else lblSize = g_format_size((guint64)(vSize * sizeof(double))); #endif lbl = g_strdup_printf("electronic density " "- %s", lblSize); dens = g_array_sized_new(FALSE, FALSE, sizeof(double), vSize); memcpy(dens->data, denspot->rhov, sizeof(double) * vSize); dens = g_array_set_size(dens, vSize); gtk_tree_store_insert(scfdata, &child, &parent, -1); gtk_tree_store_set(scfdata, &child, SCF_ITER, iter, SCF_TYPE, SCF_TYPE_DENSITY, SCF_LABEL, lbl, SCF_MEMORY, vSize, SCF_DATA, dens, SCF_OBJECT, denspot, SCF_GLR, G_OBJECT(data), -1); g_free(lblSize); g_free(lbl); g_array_unref(dens); } static void onIter(BigDFT_OptLoop *optloop, BigDFT_Energs *energs, gpointer data _U_) { GtkTreeIter parent; DBG_fprintf(stderr, "BigDFT (%p): get iter signal.\n", (gpointer)g_thread_self()); treeGetSCFIter(&parent, optloop->iter, optloop); gtk_tree_store_set(scfdata, &parent, SCF_EVAL, energs->eKS, SCF_OCCUP, optloop->gnrm, -1); } static void onDone(BigDFT_OptLoop *optloop, BigDFT_Energs *energs, gpointer data _U_) { GtkTreeIter parent; DBG_fprintf(stderr, "BigDFT (%p): get done signal.\n", (gpointer)g_thread_self()); treeGetSCFIter(&parent, optloop->iter, optloop); gtk_tree_store_set(scfdata, &parent, SCF_EVAL, energs->eKS, SCF_OCCUP, optloop->gnrm, SCF_TOL, optloop->gnrm_cv, -1); } static void psiInsert(BigDFT_Wf *wf, GArray *psic, BigDFT_PsiId ipsi, guint ikpt, guint iorb, BigDFT_Spin spin, guint iscf, GtkTreeIter *parent) { BigDFT_Orbs *orbs; gchar *lbl, *lblSize; const gchar *lblSpin[3] = {"\342\206\221", "\342\206\223", "\342\207\265"}, *lblPsi[2] = {"|\316\250", "H|\316\250"}; GtkTreeIter child; double eval; guint iorbp; #if GLIB_MINOR_VERSION < 30 lblSize = g_format_size_for_display((goffset)(psic->len * sizeof(double))); #else lblSize = g_format_size((guint64)(psic->len * sizeof(double))); #endif orbs = BIGDFT_ORBS(wf); iorbp = ikpt * orbs->norb + iorb; if (!bigdft_orbs_get_linear(orbs)) lbl = g_strdup_printf("%s%sikpt: %d, iorb: %d" "\342\237\251 (%s)", lblPsi[ipsi], lblSpin[(BIGDFT_ORBS(wf)->nspin == 1)?2:spin], ikpt + 1, iorb + 1, lblSize); else lbl = g_strdup_printf("%s%sikpt: %d, iorb: %d" "\342\237\251 ilr: %d " "(%s)", lblPsi[ipsi], lblSpin[(BIGDFT_ORBS(wf)->nspin == 1)?2:spin], ikpt + 1, iorb + 1, orbs->inwhichlocreg[iorbp], lblSize); eval = (orbs->eval)?orbs->eval[iorbp]:0.; gtk_tree_store_insert(scfdata, &child, parent, -1); gtk_tree_store_set(scfdata, &child, SCF_ITER, iscf, SCF_TYPE, SCF_TYPE_WF, SCF_LABEL, lbl, SCF_MEMORY, psic->len, SCF_IKPT, ikpt, SCF_IORB, iorb, SCF_ISPIN, spin, SCF_NSPINOR, orbs->nspinor, SCF_EVAL, eval, SCF_OCCUP, orbs->occup[iorbp], SCF_DATA, psic, SCF_OBJECT, wf, SCF_GLR, bigdft_wf_get_locreg(wf, ikpt + 1, iorb + 1, spin, 0), -1); g_free(lblSize); g_free(lbl); } static gboolean psiAdd(BigDFT_Wf *wf, guint iscf, BigDFT_PsiId ipsi, guint ikpt, BigDFT_Spin spin, GtkTreeIter *parent, gboolean init) { GtkTreeIter iter; guint iorb, psiSize; gboolean valid, checked; const double *psic; GArray *psic_; GtkTreeModel *orbsd_spin; if (spin == BIGDFT_SPIN_UP) orbsd_spin = GTK_TREE_MODEL(orbsd_spu); else orbsd_spin = GTK_TREE_MODEL(orbsd_spd); for (valid = gtk_tree_model_get_iter_first(orbsd_spin, &iter); valid; valid = gtk_tree_model_iter_next(orbsd_spin, &iter)) { gtk_tree_model_get(orbsd_spin, &iter, ACTIVATED, &checked, VALUE, &iorb, -1); if (checked) { if (!init) { treeGetSCFIter(parent, iscf, NULL); gtk_widget_set_sensitive(btSCF, TRUE); init = TRUE; } DBG_fprintf(stderr, "BigDFT: greping compressed wfn %d %d %d.\n", ikpt, iorb, spin); psic = bigdft_wf_get_psi_compress(wf, ikpt + 1, iorb + 1, spin, BIGDFT_PARTIAL_DENSITY, &psiSize, 0); psic_ = g_array_sized_new(FALSE, FALSE, sizeof(double), psiSize); memcpy(psic_->data, psic, sizeof(double) * psiSize); psic_ = g_array_set_size(psic_, psiSize); DBG_fprintf(stderr, " | storage size is %d.\n", psiSize); psiInsert(wf, psic_, ipsi, ikpt, iorb, spin, iscf, parent); g_array_unref(psic_); } } return init; } static void onPsiReady(BigDFT_Wf *wf, guint iscf, gpointer data _U_) { GtkTreeIter iter, parent; guint ikpt; gboolean init, valid, checked; init = FALSE; DBG_fprintf(stderr, "BigDFT (%p): get psi ready signal.\n", (gpointer)g_thread_self()); for (valid = gtk_tree_model_get_iter_first(GTK_TREE_MODEL(orbsd_kpt), &iter); valid; valid = gtk_tree_model_iter_next(GTK_TREE_MODEL(orbsd_kpt), &iter)) { gtk_tree_model_get(GTK_TREE_MODEL(orbsd_kpt), &iter, ACTIVATED, &checked, VALUE, &ikpt, -1); if (checked) { init = psiAdd(wf, iscf, BIGDFT_PSI, ikpt, BIGDFT_SPIN_UP, &parent, init); init = psiAdd(wf, iscf, BIGDFT_PSI, ikpt, BIGDFT_SPIN_DOWN, &parent, init); } } } static void onOneWaveReady(BigDFT_Wf *wf, guint iter, GArray *psic, BigDFT_PsiId ipsi, guint ikpt, guint iorb, guint ispin, gpointer data _U_) { GtkTreeIter parent; DBG_fprintf(stderr, "BigDFT (%p): get one-wave ready signal (%d %d %d -> %d)" " at iter %d.\n", (gpointer)g_thread_self(), ikpt, iorb, ispin, psic->len, iter); treeGetSCFIter(&parent, iter, NULL); psiInsert(wf, psic, ipsi, ikpt - 1, iorb - 1, ispin, iter, &parent); gtk_widget_set_sensitive(btSCF, TRUE); } static void onSocketClose(gpointer data) { struct _socketStuff *ct = (struct _socketStuff*)data; g_object_unref(G_OBJECT(ct->denspot)); g_object_unref(G_OBJECT(ct->wf)); g_object_unref(G_OBJECT(ct->energs)); g_object_unref(G_OBJECT(ct->optloop)); g_object_unref(G_OBJECT(ct->cancellable)); bigdft_signals_client_free(ct->client); g_async_queue_unref(ct->message); g_free(ct); g_object_set_data(G_OBJECT(btRun), "ct", (gpointer)0); gtk_widget_set_sensitive(btRun, TRUE); gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON(btRun), FALSE); #if GTK_MINOR_VERSION > 19 || GTK_MAJOR_VERSION > 2 gtk_widget_hide(spRun); gtk_spinner_stop(GTK_SPINNER(spRun)); #endif } static void onRunBigDFT(GtkToggleButton *bt, gpointer data) { VisuData *dataObj; BigDFT_Inputs *in; BigDFT_Wf *wf, *wf_; BigDFT_Proj *proj; BigDFT_LocalFields *denspot; BigDFT_Energs *energs; BigDFT_OptLoop *optloop; double frmult; gchar *host; GError *error; struct _socketStuff *ct; if (!gtk_toggle_button_get_active(bt)) { ct = (struct _socketStuff *)g_object_get_data(G_OBJECT(bt), "ct"); if (!ct) return; g_cancellable_cancel(ct->cancellable); gtk_widget_set_sensitive(btRun, FALSE); return; } dataObj = visu_ui_panel_getData(VISU_UI_PANEL(panelBigDFT)); if (!dataObj) return; wf = (BigDFT_Wf*)g_object_get_data(G_OBJECT(dataObj), "BigDFT_wf"); in = (BigDFT_Inputs*)g_object_get_data(G_OBJECT(dataObj), "BigDFT_inputs"); if (!in || !wf) return; wf_ = (BigDFT_Wf*)g_object_get_data(G_OBJECT(bt), "BigDFT_wf"); if (wf != wf_) gtk_tree_store_clear(scfdata); frmult = GET_OPT_DBL(fmtWvl, "frmult"); proj = bigdft_proj_new(BIGDFT_LOCREG(wf->lzd), BIGDFT_ORBS(wf), frmult); denspot = bigdft_localfields_new(wf->lzd, in, 0, 1); energs = bigdft_energs_new(); optloop = bigdft_optloop_new(); sigDens = g_signal_connect(G_OBJECT(denspot), "density-ready", G_CALLBACK(onDensityReady), BIGDFT_LOCREG(wf->lzd)); if (!gtk_toggle_button_get_active(GTK_TOGGLE_BUTTON(btDens))) g_signal_handler_block(G_OBJECT(denspot), sigDens); sigVext = g_signal_connect(G_OBJECT(denspot), "v-ext-ready", G_CALLBACK(onVextReady), BIGDFT_LOCREG(wf->lzd)); if (!gtk_toggle_button_get_active(GTK_TOGGLE_BUTTON(btVext))) g_signal_handler_block(G_OBJECT(denspot), sigVext); g_signal_connect(G_OBJECT(wf), "psi-ready", G_CALLBACK(onPsiReady), (gpointer)0); g_signal_connect(G_OBJECT(optloop), "iter-wavefunctions", G_CALLBACK(onIter), (gpointer)0); g_signal_connect(G_OBJECT(optloop), "done-wavefunctions", G_CALLBACK(onDone), (gpointer)0); if (gtk_combo_box_get_active(GTK_COMBO_BOX(data)) == 0) { bigdft_wf_optimization(wf, proj, denspot, energs, optloop, in, TRUE, 0, 1); gtk_widget_set_sensitive(GTK_WIDGET(bt), FALSE); } else { ct = g_malloc0(sizeof(struct _socketStuff)); /* host = gtk_combo_box_text_get_active_text(GTK_COMBO_BOX_TEXT(data)); */ host = g_strdup(gtk_entry_get_text(GTK_ENTRY(gtk_bin_get_child(GTK_BIN(data))))); DBG_fprintf(stderr, "BigDFT: try to connect to '%s'.\n", host); error = (GError*)0; ct->client = bigdft_signals_client_new(host, NULL, &error); g_free(host); if (!ct->client) { visu_ui_raiseWarning(_("Running BigDFT on a host"), error->message, NULL); g_error_free(error); gtk_toggle_button_set_active(bt, FALSE); g_free(ct); } else { #if GTK_MINOR_VERSION > 19 || GTK_MAJOR_VERSION > 2 gtk_spinner_start(GTK_SPINNER(spRun)); gtk_widget_show(spRun); #endif ct->message = g_async_queue_new(); ct->wf = wf; ct->denspot = denspot; ct->energs = energs; ct->optloop = optloop; ct->cancellable = g_cancellable_new(); g_object_ref(G_OBJECT(denspot)); g_object_ref(G_OBJECT(wf)); g_object_ref(G_OBJECT(energs)); g_object_ref(G_OBJECT(optloop)); g_object_set_data(G_OBJECT(bt), "ct", ct); bigdft_signals_client_create_thread (ct->client, ct->energs, ct->wf, ct->denspot, ct->optloop, ct->cancellable, onSocketClose, ct); } DBG_fprintf(stderr, "BigDFT: connexion done.\n"); } g_object_set_data(G_OBJECT(bt), "BigDFT_wf", wf); g_object_unref(G_OBJECT(denspot)); g_object_unref(G_OBJECT(proj)); g_object_unref(G_OBJECT(energs)); g_object_unref(G_OBJECT(optloop)); DBG_fprintf(stderr, "BigDFT (%p): now running.\n", (gpointer)g_thread_self()); } static void treeInsertIter(GtkTreeIter *iter, GtkTreeIter *parent, guint iLoop, const gchar *label, guint type) { gchar *lbl; /* We need to create a root node for this iteration. */ lbl = (iLoop == 0)? g_strdup_printf(_("%s"), label): g_strdup_printf("%s %3d", label, iLoop); gtk_tree_store_insert(scfdata, iter, parent, -1); gtk_tree_store_set(scfdata, iter, SCF_LABEL, lbl, SCF_ITER, iLoop, SCF_TYPE, type, -1); g_free(lbl); } static void treeGetIter(GtkTreeIter *iter, GtkTreeIter *parent, guint iLoop, const gchar *label, guint type, guint iLoopChild) { gboolean valid; guint ival, ivalChild; GtkTreeIter child; if (iLoop > 0) for (valid = gtk_tree_model_iter_nth_child(GTK_TREE_MODEL(scfdata), iter, parent, 0); valid; valid = gtk_tree_model_iter_next(GTK_TREE_MODEL(scfdata), iter)) { gtk_tree_model_get(GTK_TREE_MODEL(scfdata), iter, SCF_ITER, &ival, -1); if (ival == iLoop) break; } else { ival = 0; /* Get the last one if his children SCF_ITER are below iLoopChild. */ if (gtk_tree_model_iter_n_children(GTK_TREE_MODEL(scfdata), parent) > 0) valid = gtk_tree_model_iter_nth_child (GTK_TREE_MODEL(scfdata), iter, parent, gtk_tree_model_iter_n_children(GTK_TREE_MODEL(scfdata), parent) - 1); else valid = FALSE; if (valid) { gtk_tree_model_get(GTK_TREE_MODEL(scfdata), iter, SCF_ITER, &ival, -1); valid = (ival > 0); if (valid && iLoopChild > 0) { for (valid = gtk_tree_model_iter_nth_child(GTK_TREE_MODEL(scfdata), &child, iter, 0); valid; valid = gtk_tree_model_iter_next(GTK_TREE_MODEL(scfdata), &child)) { gtk_tree_model_get(GTK_TREE_MODEL(scfdata), &child, SCF_ITER, &ivalChild, -1); if (ivalChild > iLoopChild) break; } valid = (ivalChild <= iLoopChild); } } } if (!valid) treeInsertIter(iter, parent, (iLoop == 0)?ival + 1:iLoop, label, type); } static void treeGetSCFIter(GtkTreeIter *parent, guint iscf, BigDFT_OptLoop *loop) { GtkTreeIter iterHam, iterSub; if (iscf > 0) { treeGetIter(&iterHam, NULL, (loop)?loop->itrp:0, _("Hamiltonian optimisation"), SCF_TYPE_ITER_HAM, 0); treeGetIter(&iterSub, &iterHam, (loop)?loop->itrep:0, _("Sub-space optimisation"), SCF_TYPE_ITER_SUB, iscf); treeGetIter(parent, &iterSub, iscf, _("Wfn iteration"), SCF_TYPE_ITER_WFN, 0); } else { if (!gtk_tree_model_get_iter_first(GTK_TREE_MODEL(scfdata), parent)) treeInsertIter(parent, NULL, 0, _("Initial stage"), SCF_TYPE_ITER_WFN); } } static void update_orbsd(const VisuData *dataObj) { BigDFT_Wf *wf; guint i; GtkTreeIter iter; gchar *lbl; StoredWfData *dt; gtk_list_store_clear(orbsd_kpt); gtk_list_store_clear(orbsd_spu); gtk_list_store_clear(orbsd_spd); if (!dataObj) return; wf = (BigDFT_Wf*)g_object_get_data(G_OBJECT(dataObj), "BigDFT_wf"); if (!wf) return; for (i = 0; i < BIGDFT_ORBS(wf)->nkpts; i++) { lbl = g_strdup_printf(_("kpt %d (%3.3f,%3.3f,%3.3f - %3.3f)"), i + 1, BIGDFT_ORBS(wf)->kpts[i * 3 + 0], BIGDFT_ORBS(wf)->kpts[i * 3 + 1], BIGDFT_ORBS(wf)->kpts[i * 3 + 2], BIGDFT_ORBS(wf)->kwgts[i]); gtk_list_store_append(orbsd_kpt, &iter); gtk_list_store_set(orbsd_kpt, &iter, LABEL, lbl, ACTIVATED, FALSE, VALUE, i, -1); g_free(lbl); } for (i = 0; i < BIGDFT_ORBS(wf)->norbu; i++) { lbl = g_strdup_printf(_("orb. %d"), BIGDFT_ORBS(wf)->norbu - i); gtk_list_store_append(orbsd_spu, &iter); gtk_list_store_set(orbsd_spu, &iter, LABEL, lbl, ACTIVATED, FALSE, VALUE, BIGDFT_ORBS(wf)->norbu - i - 1, -1); g_free(lbl); } for (i = 0; i < BIGDFT_ORBS(wf)->norbd; i++) { lbl = g_strdup_printf(_("orb. %d"), BIGDFT_ORBS(wf)->norbd - i); gtk_list_store_append(orbsd_spd, &iter); gtk_list_store_set(orbsd_spd, &iter, LABEL, lbl, ACTIVATED, FALSE, VALUE, BIGDFT_ORBS(wf)->norbd - i - 1, -1); g_free(lbl); } if (cbKpt) gtk_combo_box_set_active(GTK_COMBO_BOX(cbKpt), 0); dt = g_malloc0(sizeof(StoredWfData) * BIGDFT_ORBS(wf)->norb * BIGDFT_ORBS(wf)->nkpts); g_object_set_data_full(G_OBJECT(dataObj), "BigDFT_storedWf", dt, (GDestroyNotify)g_free); } static void onCheckDens(GtkToggleButton *bt _U_, gpointer data _U_) { } static void onCheckVext(GtkToggleButton *bt _U_, gpointer data _U_) { } v_sim-3.8.0/lib/plug-ins/bigdft/bigdft_system.c000066400000000000000000000206701370110300500214040ustar00rootroot00000000000000/* EXTRAITS DE LA LICENCE Copyright CEA, contributeurs : Damien CALISTE, laboratoire L_Sim, (2001-2011) Adresse mèl : CALISTE, damien P caliste AT cea P fr. Ce logiciel est un programme informatique servant à visualiser des structures atomiques dans un rendu pseudo-3D. Ce logiciel est régi par la licence CeCILL soumise au droit français et respectant les principes de diffusion des logiciels libres. Vous pouvez utiliser, modifier et/ou redistribuer ce programme sous les conditions de la licence CeCILL telle que diffusée par le CEA, le CNRS et l'INRIA sur le site "http://www.cecill.info". Le fait que vous puissiez accéder à cet en-tête signifie que vous avez pris connaissance de la licence CeCILL, et que vous en avez accepté les termes (cf. le fichier Documentation/licence.fr.txt fourni avec ce logiciel). */ /* LICENCE SUM UP Copyright CEA, contributors: Damien CALISTE, L_Sim laboratory, (2001-2011) E-mail address: CALISTE, damien P caliste AT cea P fr. This software is a computer program whose purpose is to visualize atomic configurations in 3D. This software is governed by the CeCILL license under French law and abiding by the rules of distribution of free software. You can use, modify and/ or redistribute the software under the terms of the CeCILL license as circulated by CEA, CNRS and INRIA at the following URL "http://www.cecill.info". The fact that you are presently reading this means that you have had knowledge of the CeCILL license and that you accept its terms. You can find a copy of this licence shipped with this software at Documentation/licence.en.txt. */ #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include "bigdftplug.h" enum { LR_OBJECT, LR_LABEL, LR_ID, LR_SHOW_GRID_C, LR_SHOW_GRID_F, LR_COLOR, LR_N_COLUMNS }; static GtkListStore *lrdata; /* Local methods. */ static void update_lzd(BigDFT_Lzd *lzd); /* Callbacks. */ static void onDataLoaded(GObject *obj, VisuData *dataObj, gpointer data); static void onGridToggled(GtkCellRendererToggle *cell_renderer, gchar *path, gpointer user_data); void bdft_system_init() { lrdata = gtk_list_store_new(LR_N_COLUMNS, G_TYPE_OBJECT, G_TYPE_STRING, G_TYPE_UINT, G_TYPE_BOOLEAN, G_TYPE_BOOLEAN, GDK_TYPE_PIXBUF); g_signal_connect(VISU_OBJECT_INSTANCE, "dataLoaded", G_CALLBACK(onDataLoaded), NULL); } static void onLzdDefined(BigDFT_Lzd *lzd, gpointer data _U_) { update_lzd(lzd); } static void onDataLoaded(GObject *obj _U_, VisuData *dataObj, gpointer data _U_) { BigDFT_Wf *wf; if (!dataObj) return; wf = (BigDFT_Wf*)g_object_get_data(G_OBJECT(dataObj), "BigDFT_wf"); update_lzd(NULL); if (wf) g_signal_connect(G_OBJECT(wf->lzd), "defined", G_CALLBACK(onLzdDefined), (gpointer)0); DBG_fprintf(stderr, "BigDFT system: 'DataLoaded' signal OK.\n"); } GtkWidget* bdft_system_tab(BigDFT_Lzd *lzd) { GtkWidget *wd, *ct, *vbox; GtkCellRenderer *render; GtkTreeViewColumn *col; vbox = gtk_vbox_new(FALSE, 2); ct = gtk_scrolled_window_new((GtkAdjustment*)0, (GtkAdjustment*)0); gtk_scrolled_window_set_policy(GTK_SCROLLED_WINDOW(ct), GTK_POLICY_AUTOMATIC, GTK_POLICY_AUTOMATIC); gtk_scrolled_window_set_shadow_type(GTK_SCROLLED_WINDOW(ct), GTK_SHADOW_ETCHED_IN); gtk_box_pack_start(GTK_BOX(vbox), ct, TRUE, TRUE, 0); wd = gtk_tree_view_new_with_model(GTK_TREE_MODEL(lrdata)); gtk_tree_view_set_headers_visible(GTK_TREE_VIEW(wd), FALSE); gtk_container_add(GTK_CONTAINER(ct), wd); /* Columns. */ render = gtk_cell_renderer_text_new(); col = gtk_tree_view_column_new_with_attributes("", render, "markup", LR_LABEL, NULL); gtk_tree_view_column_set_expand(col, TRUE); render = gtk_cell_renderer_pixbuf_new(); gtk_tree_view_column_pack_end(col, render, FALSE); gtk_tree_view_column_add_attribute(col, render, "pixbuf", LR_COLOR); gtk_tree_view_append_column(GTK_TREE_VIEW(wd), col); render = gtk_cell_renderer_toggle_new(); g_signal_connect(G_OBJECT(render), "toggled", G_CALLBACK(onGridToggled), (gpointer)LR_SHOW_GRID_C); col = gtk_tree_view_column_new_with_attributes("", render, "active", LR_SHOW_GRID_C, NULL); gtk_tree_view_append_column(GTK_TREE_VIEW(wd), col); render = gtk_cell_renderer_toggle_new(); g_signal_connect(G_OBJECT(render), "toggled", G_CALLBACK(onGridToggled), (gpointer)LR_SHOW_GRID_F); col = gtk_tree_view_column_new_with_attributes("", render, "active", LR_SHOW_GRID_F, NULL); gtk_tree_view_append_column(GTK_TREE_VIEW(wd), col); update_lzd(lzd); return vbox; } static void update_lzd(BigDFT_Lzd *lzd) { GtkTreeIter iter; gchar *lbl; guint i; GdkPixbuf *pixbuf; gtk_list_store_clear(lrdata); if (!lzd) return; /* Global region. */ lbl = g_strdup_printf("Global region\n" " %d / %d (coarse / fine grid pts)", lzd->parent.nvctr_c, lzd->parent.nvctr_f); gtk_list_store_append(lrdata, &iter); gtk_list_store_set(lrdata, &iter, LR_OBJECT, &lzd->parent, LR_LABEL, lbl, LR_ID, 0, LR_SHOW_GRID_C, FALSE, LR_SHOW_GRID_F, FALSE, -1); g_free(lbl); /* Local regions. */ if (lzd->nlr > 1) for (i = 0; i < lzd->nlr; i++) { lbl = g_strdup_printf("Local region %d\n" " %d / %d (coarse / fine grid pts)", i + 1, lzd->Llr[i]->nvctr_c, lzd->Llr[i]->nvctr_f); pixbuf = tool_color_get_stamp(tool_color_new_bright(i), FALSE); gtk_list_store_append(lrdata, &iter); gtk_list_store_set(lrdata, &iter, LR_OBJECT, lzd->Llr[i], LR_LABEL, lbl, LR_ID, i + 1, LR_COLOR, pixbuf, LR_SHOW_GRID_C, FALSE, LR_SHOW_GRID_F, FALSE, -1); g_free(lbl); g_object_unref(pixbuf); } } static void onGridToggled(GtkCellRendererToggle *cell_renderer, gchar *path, gpointer user_data) { GtkTreePath* tpath = gtk_tree_path_new_from_string(path); GtkTreeIter iter; gboolean valid; BigDFT_Locreg *lr; GArray *gcoord; BigDFT_Wf *wf; BigDFT_LocregIter iseg; float vect[3]; guint nseg, tseg, ilr; VisuData *dataObj; VisuGlView *view; gchar *lbl; valid = gtk_tree_model_get_iter(GTK_TREE_MODEL(lrdata), &iter, tpath); gtk_tree_path_free(tpath); g_return_if_fail(valid); dataObj = visu_ui_panel_getData(VISU_UI_PANEL(panelBigDFT)); view = visu_ui_panel_getView(VISU_UI_PANEL(panelBigDFT)); g_return_if_fail(dataObj && view); wf = (BigDFT_Wf*)g_object_get_data(G_OBJECT(dataObj), "BigDFT_wf"); g_return_if_fail(wf); gtk_tree_model_get(GTK_TREE_MODEL(lrdata), &iter, LR_OBJECT, &lr, LR_ID, &ilr, -1); if (GPOINTER_TO_INT(user_data) == LR_SHOW_GRID_C) { nseg = lr->nseg_c; tseg = GRID_COARSE; lbl = "g"; } else { nseg = lr->nseg_f; tseg = GRID_FINE; lbl = "G"; } valid = !gtk_cell_renderer_toggle_get_active(cell_renderer); gtk_list_store_set(lrdata, &iter, GPOINTER_TO_INT(user_data), valid, -1); if (valid) { gcoord = g_array_sized_new(FALSE, FALSE, sizeof(gfloat) * 3, 2 * nseg); for (valid = bigdft_lzd_iter_new(wf->lzd, &iseg, tseg, ilr); valid; valid = bigdft_lzd_iter_next(&iseg)) { vect[0] = iseg.x0; vect[1] = iseg.y; vect[2] = iseg.z; g_array_append_val(gcoord, vect); if (iseg.x1 != iseg.x0) { vect[0] = iseg.x1; vect[1] = iseg.y; vect[2] = iseg.z; g_array_append_val(gcoord, vect); } } } else gcoord = g_array_sized_new(FALSE, FALSE, sizeof(gfloat) * 3, 1); bigdft_show_grid(dataObj, gcoord, lbl, ilr); g_array_unref(gcoord); g_object_unref(lr); VISU_REDRAW_ADD; } v_sim-3.8.0/lib/plug-ins/bigdft/bigdftplug.h000066400000000000000000000046461370110300500207020ustar00rootroot00000000000000/* EXTRAITS DE LA LICENCE Copyright CEA, contributeurs : Damien CALISTE, laboratoire L_Sim, (2001-2011) Adresse mèl : CALISTE, damien P caliste AT cea P fr. Ce logiciel est un programme informatique servant à visualiser des structures atomiques dans un rendu pseudo-3D. Ce logiciel est régi par la licence CeCILL soumise au droit français et respectant les principes de diffusion des logiciels libres. Vous pouvez utiliser, modifier et/ou redistribuer ce programme sous les conditions de la licence CeCILL telle que diffusée par le CEA, le CNRS et l'INRIA sur le site "http://www.cecill.info". Le fait que vous puissiez accéder à cet en-tête signifie que vous avez pris connaissance de la licence CeCILL, et que vous en avez accepté les termes (cf. le fichier Documentation/licence.fr.txt fourni avec ce logiciel). */ /* LICENCE SUM UP Copyright CEA, contributors: Damien CALISTE, L_Sim laboratory, (2001-2011) E-mail address: CALISTE, damien P caliste AT cea P fr. This software is a computer program whose purpose is to visualize atomic configurations in 3D. This software is governed by the CeCILL license under French law and abiding by the rules of distribution of free software. You can use, modify and/ or redistribute the software under the terms of the CeCILL license as circulated by CEA, CNRS and INRIA at the following URL "http://www.cecill.info". The fact that you are presently reading this means that you have had knowledge of the CeCILL license and that you accept its terms. You can find a copy of this licence shipped with this software at Documentation/licence.en.txt. */ #ifndef BIGDFTPLUG_H #define BIGDFTPLUG_H #include #include #include GtkWidget *panelBigDFT; ToolFileFormat *fmtWvl; #define GET_OPT_INT(f, n) g_value_get_int(tool_option_getValue(tool_file_format_getPropertyByName(TOOL_FILE_FORMAT(f), n))) #define GET_OPT_DBL(f, n) g_value_get_double(tool_option_getValue(tool_file_format_getPropertyByName(TOOL_FILE_FORMAT(f), n))) #define SET_OPT_INT(f, n, v) g_value_set_int(tool_option_getValue(tool_file_format_getPropertyByName(TOOL_FILE_FORMAT(f), n)), v) #define SET_OPT_DBL(f, n, v) g_value_set_double(tool_option_getValue(tool_file_format_getPropertyByName(TOOL_FILE_FORMAT(f), n)), v) void bigdft_show_grid(VisuData *dataObj, GArray *grid, const gchar *gG, guint id); #endif v_sim-3.8.0/lib/plug-ins/bigdft/stock-bigdft_20.png000066400000000000000000000021621370110300500217600ustar00rootroot00000000000000PNG  IHDRoUtsRGB pHYs  tIME ;86RIDAT8]OlTe{o^;PZbԴN0hŸbB + # M`Dn,\hpC""PMŠqj(_[ әc:fu1.nr{sPVlj&x\Q1"`+؊ bC=( 1jTlxRxB[xbz"&F8Z."YpUP0; Df+.e0mИO&*%"Wc[-qŁNu&AaN 2h-$Gi ZjwfMKT_AʀByD64Bj! Gə((W$A h+\gADQz6RT8}s:ͮ^: vxw 2и7fKfʁĩAp)k*k QHtÃ?A08vczx=;p6y,c8&B_ ywnh}ǡg/UkfK3 p:JqD< zjSx ߀Pvpq#4߼cTo`}XMծI| r? A7]!تEy%~oɿL{tk{Q(ՠ &ʂjEb hsFrzrrDj,%Pσ 0!$ sD&mCm :ӻy6$j #include #include #include #include #include #include #include #define CUBE_DESCRIPTION _("" \ "This plug-in reads Cube" \ " files (see \n" \ "http://local.wasp.uwa.edu.au/\n" \ "~pbourke/dataformats/cube/" \ "),\nboth structural and" \ " and volumetric data.") #define CUBE_AUTHORS "Caliste Damien" /* http://local.wasp.uwa.edu.au/~pbourke/dataformats/cube/ */ struct cube_reader { const gchar *filename; GString *line; gchar *comment; double box[3][3]; float shift[3]; guint natom; VisuDataLoaderIter *iter; VisuElement **nodeTypes; float *coords; guint mesh[3]; GArray *density; VisuScalarFieldData *field; GIOStatus status; ToolFiles *flux; GCancellable *cancel; }; static gboolean cubeAtomicLoad(VisuDataLoader *self, VisuDataLoadable *data, guint type, guint nSet, GCancellable *cancel, GError **error); static gboolean cubeDensityLoad(VisuScalarFieldMethod *meth, VisuScalarFieldMethodData *data, GCancellable *cancel, GError **error); /* static gboolean xvAtomicLoad(VisuData *data, const gchar* filename, */ /* ToolFileFormat *format, int nSet, GError **error); */ /* Local variables */ static gchar *iconPath; static VisuDataLoader *cubeLoader = NULL; gboolean cubeInit() { const gchar *typeCube[] = {"*.cube", "*.cub", (char*)0}; /* char *typeXV[] = {"*.XV", "*.STRUCT_OUT", (char*)0}; */ /* char *nameXV = "Siesta output format"; */ /* char *descrXV = _("Siesta geometric output format"); */ cubeLoader = visu_data_loader_new(_("Gaussian structural/volumetric format"), typeCube, FALSE, cubeAtomicLoad, 60); visu_data_atomic_class_addLoader(cubeLoader); visu_scalar_field_method_new(_("Gaussian structural/volumetric format"), typeCube, cubeDensityLoad, G_PRIORITY_HIGH - 10); /* fmt = tool_file_format_new(descrXV, typeXV); */ /* meth = g_malloc(sizeof(VisuRenderingFormatLoad)); */ /* meth->name = nameXV; */ /* meth->fmt = fmt; */ /* meth->priority = 61; */ /* meth->load = xvAtomicLoad; */ /* visu_rendering_atomic_addLoadMethod(meth); */ iconPath = g_build_filename(V_SIM_PIXMAPS_DIR, "cube.png", NULL); return TRUE; } const char* cubeGet_description() { return CUBE_DESCRIPTION; } const char* cubeGet_authors() { return CUBE_AUTHORS; } const char* cubeGet_icon() { return iconPath; } static void reader_free(struct cube_reader *rd) { DBG_fprintf(stderr, "Cube: free the reader structure.\n"); g_string_free(rd->line, TRUE); if (rd->comment) g_free(rd->comment); visu_data_loader_iter_unref(rd->iter); if (rd->nodeTypes) g_free(rd->nodeTypes); if (rd->coords) g_free(rd->coords); if (rd->density) g_array_unref(rd->density); if (rd->field) g_object_unref(rd->field); g_object_unref(rd->flux); } static gboolean read_line(struct cube_reader *rd, GError **error) { rd->status = tool_files_read_line_string(rd->flux, rd->line, NULL, error); return (rd->status == G_IO_STATUS_NORMAL); } static gboolean read_comment(struct cube_reader *rd, GError **error) { /* Read the two comment line. */ if (!read_line(rd, error)) { *error = g_error_new(VISU_DATA_LOADABLE_ERROR, DATA_LOADABLE_ERROR_FORMAT, _("Wrong Cube format, missing comment lines.\n")); return FALSE; } g_strstrip(rd->line->str); rd->comment = g_strdup(rd->line->str); if (!read_line(rd, error)) { *error = g_error_new(VISU_DATA_LOADABLE_ERROR, DATA_LOADABLE_ERROR_FORMAT, _("Wrong Cube format, missing comment lines.\n")); return FALSE; } g_strstrip(rd->line->str); g_string_prepend(rd->line, " "); g_string_prepend(rd->line, rd->comment); g_free(rd->comment); rd->comment = g_strdup(rd->line->str); DBG_fprintf(stderr, "Cube: comment '%s'.\n", rd->comment); return TRUE; } static gboolean read_natom(struct cube_reader *rd, GError **error) { /* Read the number of atoms. */ if (!read_line(rd, error)) { *error = g_error_new(VISU_DATA_LOADABLE_ERROR, DATA_LOADABLE_ERROR_FORMAT, _("Wrong Cube format, missing the atom line.\n")); return FALSE; } if (sscanf(rd->line->str, "%u %f %f %f", &rd->natom, rd->shift, rd->shift + 1, rd->shift + 2) != 4) { *error = g_error_new(VISU_DATA_LOADABLE_ERROR, DATA_LOADABLE_ERROR_FORMAT, _("Wrong Cube format, missing the number of" " atoms on the third line.\n")); return FALSE; } DBG_fprintf(stderr, "Cube: number of atoms %d.\n", rd->natom); return TRUE; } static gboolean read_box(struct cube_reader *rd, GError **error) { int i; gchar dir[3] = "XYZ"; /* Read the box definition. */ for (i = 0; i < 3; i++) { if (!read_line(rd, error)) { *error = g_error_new(VISU_DATA_LOADABLE_ERROR, DATA_LOADABLE_ERROR_FORMAT, _("Wrong Cube format, missing the %d box line.\n"), i + 1); return FALSE; } if (sscanf(rd->line->str, "%u %lf %lf %lf\n", rd->mesh + i, rd->box[i], rd->box[i] + 1, rd->box[i] + 2) != 4) { *error = g_error_new(VISU_DATA_LOADABLE_ERROR, DATA_LOADABLE_ERROR_FORMAT, _("Wrong Cube format, missing float values" " for box definition.\n")); return FALSE; } if (rd->mesh[i] <= 0) { *error = g_error_new(VISU_DATA_LOADABLE_ERROR, DATA_LOADABLE_ERROR_FORMAT, _("Wrong Cube format, wrong mesh" " size in %c direction.\n"), dir[i]); return FALSE; } rd->box[i][0] *= rd->mesh[i]; rd->box[i][1] *= rd->mesh[i]; rd->box[i][2] *= rd->mesh[i]; } DBG_fprintf(stderr, "Cube: read box %8g %8g %8g\n" " %8g %8g %8g\n" " %8g %8g %8g\n", rd->box[0][0], rd->box[0][1], rd->box[0][2], rd->box[1][0], rd->box[1][1], rd->box[1][2], rd->box[2][0], rd->box[2][1], rd->box[2][2]); return TRUE; } static gboolean read_coords(struct cube_reader *rd, GError **error) { guint i, zele, nb; float rcov, trash; gchar *name, *ptChar; VisuElement *type; gboolean new; rd->nodeTypes = g_malloc(sizeof(VisuElement*) * rd->natom); rd->coords = g_malloc(sizeof(float) * 3 * rd->natom); DBG_fprintf(stderr, "Cube: read coordinates.\n"); for (i = 0; i < rd->natom; i++) { if (g_cancellable_set_error_if_cancelled(rd->cancel, error)) return FALSE; if (!read_line(rd, error)) { *error = g_error_new(VISU_DATA_LOADABLE_ERROR, DATA_LOADABLE_ERROR_FORMAT, _("Wrong Cube format, missing" " line %d with coordinates.\n"), i + 1); return FALSE; } nb = sscanf(rd->line->str, "%u %f %f %f %f\n", &zele, &trash, rd->coords + 3 * i, rd->coords + 3 * i + 1, rd->coords + 3 * i + 2); if (nb != 5) { *error = g_error_new(VISU_DATA_LOADABLE_ERROR, DATA_LOADABLE_ERROR_FORMAT, _("Wrong Cube format, can't read coordinates.\n")); return FALSE; } /* rd->coords[3 * i + 0] -= rd->shift[0]; */ /* rd->coords[3 * i + 1] -= rd->shift[1]; */ /* rd->coords[3 * i + 2] -= rd->shift[2]; */ /* Try to find a z number instead of a name. */ rcov = -1.f; if (!tool_physic_getSymbolFromZ(&ptChar, &rcov, (float*)0, zele)) { *error = g_error_new(VISU_DATA_LOADABLE_ERROR, DATA_LOADABLE_ERROR_FORMAT, _("Wrong Cube format, one atomic number is 0 or lower," " or greater than 103, check your input file.\n")); return FALSE; } name = g_strdup(ptChar); /* adding nomloc to the hashtable */ type = visu_element_retrieveFromName(name, &new); if (new && rcov > 0.f) visu_element_atomic_setRadius(visu_element_atomic_getFromPool(type), rcov * 0.52917720859); g_return_val_if_fail(type, FALSE); rd->nodeTypes[i] = type; visu_data_loader_iter_addNode(rd->iter, type); } DBG_fprintf(stderr, " | read OK.\n"); return TRUE; } static gboolean read_density(struct cube_reader *rd, GError **error) { int i, j, n; gchar **tokens; #if DEBUG == 1 GTimer *timer; gulong fractionTimer; #endif #if DEBUG == 1 timer = g_timer_new(); g_timer_start(timer); #endif n = rd->mesh[0] * rd->mesh[1] * rd->mesh[2]; rd->density = g_array_sized_new(FALSE, FALSE, sizeof(double), n); g_array_set_size(rd->density, n); DBG_fprintf(stderr, "Cube: read density (%gMo).\n", sizeof(double) * n / 1024. / 1024.); i = 0; do { if (g_cancellable_set_error_if_cancelled(rd->cancel, error)) return FALSE; if (!read_line(rd, error)) { *error = g_error_new(VISU_DATA_LOADABLE_ERROR, DATA_LOADABLE_ERROR_FORMAT, _("Wrong Cube format, missing density lines.\n")); return FALSE; } tokens = g_strsplit(rd->line->str, " ", 0); for (j = 0; tokens[j] && i < n; j++) if (tokens[j][0]) { if (sscanf(tokens[j], "%lf", &g_array_index(rd->density, double, i)) != 1) { *error = g_error_new(VISU_DATA_LOADABLE_ERROR, DATA_LOADABLE_ERROR_FORMAT, _("Wrong Cube format, unreadable float value" " %d for density.\n"), i); g_strfreev(tokens); return FALSE; } i += 1; } g_strfreev(tokens); } while(i < n && rd->status == G_IO_STATUS_NORMAL); #if DEBUG == 1 g_timer_stop(timer); fprintf(stderr, "Cube: density parsed in %g milli-s.\n", g_timer_elapsed(timer, &fractionTimer)/1e-3); g_timer_destroy(timer); fprintf(stderr, " | %d elements.\n", rd->density->len); #endif if (rd->status != G_IO_STATUS_NORMAL) { *error = g_error_new(VISU_DATA_LOADABLE_ERROR, DATA_LOADABLE_ERROR_FORMAT, _("Wrong Cube format, missing float values" " for density (%d read, %d awaited).\n"), i, rd->mesh[0] * rd->mesh[1] * rd->mesh[2]); return FALSE; } return TRUE; } static int read_cube_file(struct cube_reader *rd, GCancellable *cancel, GError **error, VisuScalarFieldMethodData *data) { VisuBox *boxObj; /* We read every line that corresponds to this schema : "%s %f %f %f" */ DBG_fprintf(stderr, "Cube: reading file as a cube file.\n"); /* The storage for read line. */ rd->line = g_string_new(""); rd->comment = (gchar*)0; rd->cancel = cancel; /* Storage of number of elements per types. */ rd->iter = visu_data_loader_iter_new(); rd->nodeTypes = (VisuElement**)0; rd->coords = (float*)0; rd->density = (GArray*)0; rd->field = (VisuScalarFieldData*)0; /* We read the all the file. */ if (!read_comment(rd, error)) { DBG_fprintf(stderr, "Cube: no comment, not a cube file.\n"); return -1; } if (!read_natom(rd, error)) { DBG_fprintf(stderr, "Cube: no number of atoms, not a cube file.\n"); return -1; } if (!read_box(rd, error)) { DBG_fprintf(stderr, "Cube: no box, not a cube file.\n"); return -1; } if (data) { rd->field = g_object_new(VISU_TYPE_SCALAR_FIELD_DATA, "label", rd->filename, NULL); g_object_ref(rd->field); visu_scalar_field_setCommentary(VISU_SCALAR_FIELD(rd->field), rd->comment); boxObj = visu_box_new_full(rd->box, VISU_BOX_PERIODIC); visu_box_setMargin(boxObj, 0.f, FALSE); visu_boxed_setBox(VISU_BOXED(rd->field), VISU_BOXED(boxObj)); g_object_unref(boxObj); visu_scalar_field_method_data_addField(data, VISU_SCALAR_FIELD(rd->field)); visu_scalar_field_method_data_ready(data); } if (!read_coords(rd, error)) return 1; if (rd->field) { if (!read_density(rd, error)) return 1; } return 0; } static gboolean cubeAtomicLoad(VisuDataLoader *self _U_, VisuDataLoadable *data, guint type, guint nSet _U_, GCancellable *cancel, GError **error) { int res; guint iNodes; struct cube_reader rd; gboolean *flag; VisuBox *boxObj; float xyz[3]; g_return_val_if_fail(error && *error == (GError*)0, FALSE); rd.filename = visu_data_loadable_getFilename(data, type); rd.flux = tool_files_new(); if (!tool_files_open(rd.flux, rd.filename, error)) { g_object_unref(rd.flux); return FALSE; } res = read_cube_file(&rd, cancel, error, NULL); if (res == 0) { /* Allocate the space for the nodes. */ visu_data_loader_iter_allocate(rd.iter, VISU_NODE_ARRAY(data)); DBG_fprintf(stderr, " | begin to transfer data to VisuData.\n"); /* Store the coordinates */ boxObj = visu_box_new_full(rd.box, VISU_BOX_PERIODIC); if (visu_box_getGeometry(boxObj, VISU_BOX_DXX) != G_MAXFLOAT) visu_boxed_setBox(VISU_BOXED(data), VISU_BOXED(boxObj)); else { *error = g_error_new(VISU_DATA_LOADABLE_ERROR, DATA_LOADABLE_ERROR_FORMAT, _("Wrong Cube format, basis-set is degenerated.\n")); res = +1; } g_object_unref(boxObj); if (res == 0) { for(iNodes = 0; iNodes < rd.natom; iNodes++) { visu_box_convertFullToCell(boxObj, xyz, rd.coords + 3 * iNodes); visu_data_addNodeFromElement(VISU_DATA(data), rd.nodeTypes[iNodes], xyz, FALSE); } visu_box_setOrigin(boxObj, rd.shift); visu_data_setDescription(VISU_DATA(data), rd.comment); flag = g_malloc(sizeof(gboolean)); *flag = TRUE; g_object_set_data_full(G_OBJECT(data), VISU_SCALAR_FIELD_DEFINED_IN_STRUCT_FILE, (gpointer)flag, g_free); } } /* Free the local data. */ reader_free(&rd); if (res < 0) /* The file is not a Cube file. */ return FALSE; else if (res > 0) /* The file is a Cube file but some errors occured. */ return TRUE; /* Everything is OK. */ *error = (GError*)0; return TRUE; } static gboolean cubeDensityLoad(VisuScalarFieldMethod *meth _U_, VisuScalarFieldMethodData *data, GCancellable *cancel, GError **error) { int res; struct cube_reader rd; float shift[3]; g_return_val_if_fail(data, FALSE); g_return_val_if_fail(!error || (*error == (GError*)0), FALSE); rd.filename = visu_scalar_field_method_data_getFilename(data); rd.flux = tool_files_new(); if (!tool_files_open(rd.flux, rd.filename, error)) { g_object_unref(rd.flux); return FALSE; } res = read_cube_file(&rd, cancel, error, data); if (res == 0) { visu_scalar_field_setGridSize(VISU_SCALAR_FIELD(rd.field), rd.mesh); shift[0] = - rd.shift[0]; shift[1] = - rd.shift[1]; shift[2] = - rd.shift[2]; visu_pointset_setTranslation(VISU_POINTSET(rd.field), shift, TRUE); DBG_fprintf(stderr, "Cube: transfer density into field object.\n"); visu_scalar_field_data_set(rd.field, rd.density, VISU_SCALAR_FIELD_DATA_ZYX); } /* Free the local data. */ reader_free(&rd); if (res < 0) /* The file is not a Cube file. */ return FALSE; else if (res > 0) /* The file is a Cube file but some errors occured. */ return TRUE; /* Everything is OK. */ *error = (GError*)0; return TRUE; } /* static gboolean xvAtomicLoad(VisuData *data, const gchar* filename, */ /* ToolFileFormat *format, int nSet, GError **error) */ /* { */ /* GIOChannel *flux; */ /* GIOStatus status; */ /* GString *line; */ /* int i, n; */ /* double cart[3][3]; */ /* float box[6]; */ /* g_return_val_if_fail(error && *error == (GError*)0, FALSE); */ /* g_return_val_if_fail(data && filename, FALSE); */ /* flux = g_io_channel_new_file(filename, "r", error); */ /* if (!flux) */ /* return FALSE; */ /* for (i = 0; i < 3; i++) */ /* { */ /* status = g_io_channel_read_line_string(flux, line, NULL, error); */ /* if (status != G_IO_STATUS_NORMAL) */ /* { */ /* *error = g_error_new(VISU_DATA_LOADABLE_ERROR, DATA_LOADABLE_ERROR_FORMAT, */ /* _("Wrong Siesta format, missing the %d box line.\n"), */ /* i + 1); */ /* return FALSE; */ /* } */ /* g_strstrip(line->str); */ /* if (sscanf(line->str, "%lf %lf %lf\n", */ /* cart[i], cart[i] + 1, cart[i] + 2) != 4) */ /* { */ /* *error = g_error_new(VISU_DATA_LOADABLE_ERROR, DATA_LOADABLE_ERROR_FORMAT, */ /* _("Wrong Siesta format, missing float values" */ /* " for box definition.\n")); */ /* return FALSE; */ /* } */ /* } */ /* DBG_fprintf(stderr, "Siesta: read box %8g %8g %8g\n" */ /* " %8g %8g %8g\n" */ /* " %8g %8g %8g\n", */ /* cart[0][0], cart[0][1], cart[0][2], */ /* cart[1][0], cart[1][1], cart[1][2], */ /* cart[2][0], cart[2][1], cart[2][2]); */ /* status = g_io_channel_read_line_string(flux, line, NULL, error); */ /* if (status != G_IO_STATUS_NORMAL) */ /* { */ /* *error = g_error_new(VISU_DATA_LOADABLE_ERROR, DATA_LOADABLE_ERROR_FORMAT, */ /* _("Wrong Siesta format, missing the number" */ /* " of elements line.\n")); */ /* return FALSE; */ /* } */ /* g_strstrip(line->str); */ /* if (sscanf(line->str, "%d\n", &n)) */ /* { */ /* *error = g_error_new(VISU_DATA_LOADABLE_ERROR, DATA_LOADABLE_ERROR_FORMAT, */ /* _("Wrong Siesta format, missing the number" */ /* " of elements.\n")); */ /* return FALSE; */ /* } */ /* if (!tool_matrix_reducePrimitiveVectors(box, cart)) */ /* { */ /* *error = g_error_new(VISU_DATA_LOADABLE_ERROR, DATA_LOADABLE_ERROR_FORMAT, */ /* _("Wrong Siesta format, primitive vectors are not 3D.\n")); */ /* return FALSE; */ /* } */ /* if (g_io_channel_shutdown(flux, FALSE, (GError**)0) != G_IO_STATUS_NORMAL) */ /* g_warning("Cube: can't close file."); */ /* } */ v_sim-3.8.0/lib/plug-ins/cube/cube.png000066400000000000000000000043611370110300500174770ustar00rootroot00000000000000PNG  IHDR  pHYs  tIME 1tEXtCommentCreated with The GIMPd%ngIDATHmVmpT~{wIDI@mhBKW?AtvC00: iZ J5PMMv{9]B0MM%ϗ"?fNgDcG&&'xEf+)O/=p=P1A=QU 0::ǣh*5K/>ㄐ>t3L&&֭[7j"2 3fAjxjGyĶ-˲듉D.]z) AM%32ff zf:w֝o|j_ fm *-"_UMM X;{l0 Wĸ3ydlWyDdwV{},%&?őo͊w^wELm䆍O 5A E`-~G◿'p`+??҅0t* ;sBp2|i ΖL4MG;RJ;vD"4Ow466^*mmmoF._<.\޽pqQǎ:zl劕U<ZkN8[*ϥLf6O HxB!|>#6f.b1bYں~u˷QIgggyq'NMͼn__߇~yu՘8p`PJ B]vmذpm۶ٳ6l s*>}; 0PfbGܸq͛hֳZMb/BD\׵mzK7d2HJ9.\AYܜ9F(Wu?`LN_IENDB`v_sim-3.8.0/lib/plug-ins/cube/h2o-dens.cube.bz2000066400000000000000000004137541370110300500210400ustar00rootroot00000000000000BZh91AY&SYo}_p@ ! ?'ch(PJ%THAJ(P@H Q@R(P$HP $EH(UPE(P@(@U)T@((*RJ( B* ((U@Q@( @Q JH"( `@ (R{eA@T )E( E1H1E$ $% )EIRERH"I)E%"D( QJRJ@I$IE !%PcI%%()Q@J (hJQA%)MTP$ JJI"J*Sl%QRR$AcI R f PREI("(T*@J4ʒ% H%JJ$JTUI$i@HJ% )* R J)@R*JU **JDf RPUIBIT J(V!*RH()Jm@E2UR@HRT T*V(MT(hRP"QR DEPR(&H5@)V*U)hU$ (R@P U$ )IJ($RP6I@ e(h@@҅T jRQ@( R@l)J P @(*A@D"hh%P @ -T%(k@ J(H$(TPUR((TClT)@h hiIJ%H*T)[e +FJ@  (֨( T(H $ k @(m @@UJ "$UPP@ ( % (@ JIО4dd3A*aU@2F ɡ$ڦh@P 4@ xM4 KߥQoܢJG%2qObX5|Ab Lr4 Z!l8,[!%ĭHA䤄0 L‹bLaRZ5)BP Z+je J)HCq WҘʖF-o DKUR"PZT! KL B]Uj% BQK$lCEbR BKD̡kS6**B kؖ|jB$cbY,SsZ- S,&IPK*K\FS%hB)B1kj҆1$!v5 4bRYubJJV-I-J)ZJqi8_V-,!*!R%i}bP )_RƭhR҄!ZŨկ)iaZ)Z֥!2!,OnjRַUĔ)0k>ĩJԔĚ-BҔjR$I KBT2VŤ1i-[R-,JT1K[SLR~1*ZIJ !Iýŭ )/ZԹ(8ħ5 5-1 S%-BRJX-LiJZ-G1Y?[]5LRI.R jRJB%(bVb%[PbЧcemZB(Ԥ bRJԺi(ȔJbClJBiJ-,SJO !KqKZThR$6 [MRУaВQiJZBVQ6J☵bL)M)iCh]j}4 5lı5 SZNʔbЦ꘴}q*S>$! Zײ%$IHJH) ST!(BNS]!I*ARִYzIIĥZ%,RX*~>-Ib6Z Z2 J)Zq1mjS bҴJZ)JE%ZX a*)(QųljY|%dBeR_ev֥)KRJ,Y1hҒ.ȴiIJ)ZJ-Tg]RB%kJR)%HJYZ%JciӒiuEJ%+BJHԒڒekOBkY,JԔkY) b6{uq O4%+J]B]|߭ \1bڔ$RR)ladJTҘRB!HA)ZT)AĨ$"2i- S,%mKV)hD)i+%)J 09 1e!h!KJţ-l[KB,JRL۷iR$Ř.(S1jTKRo"6ԭI1$CkRcZujZYBcJ-K4)iCP߭iV*AlU) [>jiAj- BBJJHjK%A(JҷԔ H)bE!_v a6% )8д%)jZu)Bֆ-hX-OIb.Z%lMwmԶ)D.R%icJrR,I0 R%5jJIJI)& %)lJ%k؂P!H:-!GR(B>IZ☔QRťkbRBQ BвAjiIKN+ JIJT[D[)BHBbSFJUlbJRE%,! %)J! ZؤDZbbP BZP!Il[[V8q CKV%-TKEE%,akbVVZi4֤RSF1:ԡAk%6BPųRRVҥbJZbZJRuQKQHKkjVC-JZҔtZQcmD)ƥkBKJZJ[ȊJRJ[he%*Q))\iIZF.5b4K~Xŵ⚖%z҄)RbRaIDRTvV)ZZإhƗD1+BYI-.0%RP#i(BbL[LbѨQEŰ)i$JJҧJRȉ%-Ԃ-)jJif1 %$ [- $5kY(Y}HGjBTLZ"R%HA V[Z>TRB IIA )թ!Bܥ}M!B-K!l%%IbR֥,KR0&4Ԙ) aHJVbB)/rJťġKcŨ)oRHJD*RJBŭ bT$T) b!?-$%tbR"խEU! JT-b>!&'m1qVSJmM2IEXV%lJ BRHU)9- BLRJFZTť+)&QE!(^R,Ѕ[! )kTB RaB/ AbHZ AhZJ*RU)֕ƬbIq3!,JKBRq!2$QJZVAJ-lLJQҊRҥMRejjkPIZ_jL-JҿkJU18ؕ1hF>8*K-1Z~jKm,JLbmM'[\E! d)-RRВ#1ZR%i[RIC.VŘZPIjRЕ.ab1*RNZ$%$JTm&7)ZJ%*JT-"8-Z#iCBQ*LVH]YlStTJUkZYR516J&%*Jkj-*lhZX̡HBbRJ LTA B5 BZҥ B\1HZXaiJD!PD1KQ R bԂbiJP6b*tb$SqdS)(q5 M).ԕ\)*&bfiII3%11IL]J\*D+6uJV!Q!- E$-Rĩn! Lp+r؉dvĖRRZL})Hjj)ccA{ŐKJa_Җ1iBE-L-Irܢf*&XSKm)1meaJ)JYr)nT)F!} )-6e,ZؕEJZZ5*Q 1]_vy10JB}VTkZ05GJZ%iKS Z/!&5RũhQ [!Yl1IJqip!H%F8WJqiZV) RYJԴ?-J- Bh┆Ե1OV15)a1mk7cgj5d W[k Z*Z b!"BPRVTs%%S5/)H9Qjjtb-+b> B-K%z;jҕ.ԿTI..S*Je B)TOZRc6ı+JPBQB%K@nq5 mMIcBL{ɵ-7fiqM0"T!)(1iqf+[IBBBBR(BV,bPԱW JTqJZք-,}-kKKN&1%*uŷ RөV%-RaW}CYoBSZXĒƥ$1Z! \-ZVKK!JRTSZV+LRR_%iZT1q-b,19 bcYJR؞9 2\cZLAJq cjկRR]C) Qĕmq+l(],%b!P RJx!kAMjeKS%55IBԐ1 KiH[M)s J[H[V7WԶgؔҘeiĩ-B]qύC\JRJi1R R~) e:ZB)u+)lL%ooB\/+%JB,ZGjҴsP,Z-2TĦ,)+Zؔ%+qS\!ZT(qkJjBo$>[HcRR-mq-/5E$BZqoZڴUym\ R~Д(bC%Sq-ju$JRZJJ2ARXmmҗmN4K%EF)*kcS>-8)}֨E8VҔ-J%ujqvL1M(Z-JZTS,k\Zu i78t58ԗ }n&B\Q[RZ! *5M[PV Bj!.b!JԺYĦNiqjĘ$5mb-)B]bB]:P b!D:(էRZSjujm)bQi[)%NqqMiK,iY,R*If%k5b%IK TĔq ,֭+RC> CP1PBTŸcP j>q-hR҄5I 1*cPT=Nҵ}vZQ-bjZhJdJHJkiZD!(-UƳjc7ε&ۅ*DJKmJk ZP\$N)u*RRKJG[բDV!D!K b8#Z҄%i}%k/SBRJJֵKP[Z.u*bR_Ҥ,In-8kYIG֤KJ~sBkbLjRRIy;.5c;-_8S) K)-.ZzbRJ3h>I[S)lR\jհ|- %[TiY-R^%-hBTZ1 ur?[ZRؔ14)+Oص-/XCIBߥ*JbPTB)I)A RZ]Ec7c[cT PjІ CRV) RXԩj[Pe) BKj؆5j bXD jӨK_jR-+!cCSV A1ISe%SCSjЇRŸbTű+q bQ,!jCTJ%}BԶmًFҸD񥶕-e1[KLJ1Q)1JQƧ_Yi-k*d-*-*Z )hJ>J8ԩK-eM%h8!o[VZғiTJԆ$11\IB\D(bJ $LKcI6"QjZ*,%!Q}l)LZ6[XOڕ5QKQ)%I RZ1B֤BKhR17& LQ,J\)JqHZT1%lOٌZЂRũ1,RڒuF)i% [Scq J85 RX mr%[m2k^;բҵbZظR5bOmJJXFl!e%RTÍZڕK8┲Zı}TYLJIJ)KZ֜RQ(AjBĭĩk!)JZJ֔$,RHZԄ7mIBЄFjADb^ABԔ5%;%jbVRZK}[ؖ!j%MZSɖ, Y+y$OZ*%RV2(81Cd-%Iq1 -)+YM)m,K[bJR$աi}MB[Y1>uoCX؆-R} S!KRԥ-HZ-fV[K1ORjRCMҘġC&1/-jJ6ƶ4[LR9*vYZާ[q,TCPTBZ B֕jk\K>)Kd>) ba,qTR~)lSXƱ Jĥ ZN5JRV$յ-!+uI[Kq-c☵Lb jTc-R:!f%,Cb]KkP8JY Z>-jԔ!3>)JRPB8!djN-BKB늷o&#[-nXbCRĖZ[%f-[4>ջŭ,RXkiN1aB!%jBŭ1KRYԭۥ)kJ` RI- }hSR1[IZ-/҆)i%5IjԄ!kMRQĊTJQQm-QMjRҕCZJ/JIfm^1ZR:1),GӋqHCTHY+BD1N%-Z~g:1IB\Iu w!jBkbZJӫKƩBIBCq8%V&T1 RԷj %JJKV)DMiI*%JUOiG[֤18% ZJRI5K1mB})BTԱ*ZI Q JJ-[դ(mծ!,WRpZէCZդmRHjj!}cX a*77u9&.RbRuKZJbT-#nƔpgR[KijZ2.LH$u*AlWRM .RPËRJJBԦ [[u*6UlbTjcwq-Z5 YJZP!%!M) zI!A SZ0! JLRRB%qCN!mbqKBRQR5B CLC-)R_cĜB֡tꚔ! ukg Y RXաbԾ56#bԤ) ZLS"TKjm1M% 1NQISVZ1 Rq! !h- KZ J!)KbRdB *Z֢KF,Q.}kQ OZ[1)q (N1oLAD!$dIJTZ 1NpLlIbR0}.kZjԩJJŒťFC)I!JT-*BjT)*)dIb TdŵijBҶ%BX1/䡯šHZ-*%kRPjBQJZT(rTZIRZV8Jj- A)U*ڥ(֡}\jԔ-q+kRH4-jB I*KZZ12V\)KB1ZiCA($П[PSTbЏ+JPTkvť.S*-Jˋ)Jֵ-()-JmննShJRƺ_FBIB%BuHBhm5 ZJRHaܖkc[BVRS EAN/hj8'Sŭ%$%J-bВҒؔ))EZERRRW%i-kJ-11XIb )0ũZSj\9ZI%hBRY(biD ZjZߪ%B 1LulRRѥfQ%iIQ$VRЄ+c[ 5C!R>tgR--hY)K/夷!5KHAi0-iB(ZJд)B&!L )$!X9 !• C1!dLcb]SAHw[[ ZV&Vd)+RR)(bTIT>)-)cS%J\Rť Zd%-8@TbJRq0ıRԶ184- Zhҩ1Q:T4ŴTS{N!#]Y[b!LYjԕڅ5,}(Z'% u-jP9MR%(Z) S-Q)Y)jjժQJjZ1%BqhRST|R␩B҇R<- %*V![ai%JҤiJ6VJ1&) [Sm&D%+Qi))IiMI*XSL#JaMSV)Z1,˜.ibԄ812Z┎%lBT !+jZԄ+)Dd)hZ5_жaLk[BZ\jP6B>cK)-Na Gԧ"4%Rbԭ6jm kbm)+)J)q!KKBKLZ֕|YzFֲVVZTRM)|աd8ԩ)JRkb˔[(M*)K!_BPi$nFJ԰EJIRS2CV }'K\K%cbV)5IBR)O(ZҿK)8K6ڿbJ}JJФu SJHBĖPKk)ĥbRJR BXOشd-/e! Re(-*!(QN(!Mcu,!Ƙ}ZRڄ Tҋl-LBBIbN1lQT) -*%N)o% Lb5b+-kN-j (W}Rډc!u B!)܃`)D-Ғ5ԩؖPX7RD)kBd#)Q bbTA i[5h]J Ԕ!h,ىC S% qb}RTIa!hB$CԇŢy qiRJ}jS5 bIkC}hBGέlbRYjB51iZ%:Z-d-k%kjԿ|Xj Jm)j1n4`\q CII BԒ~vT))JWh$KXVn㮥Q()JlĮ%Q(*}$4&%)HjR [.khSV1R)R՞aHB5LRTRZm+[S02% 1[KhLjؖ3iM[ Hj_Z!jXT5R֝BS+Ř!$e-cĭ 0-jcuq SNAhZY-խ!rɈԩ ZPR!P$-b֔Е1(cT-bSlZK-L%qEJIJb,KZ!Ie8bп"eMvqb ťH܆!iJI[>JĔ!+R촥f>Zif(RR}{\ZQlKj(j1-CqMqd&Ԫ&688!8BX\LC[R-(J-J)*RRBmRY+KgjB[}o KT.!h}hK- @%J-hZԔ*ԘPV%ǹh-rPRSC]KC5[b!)Zx$!KX5QYpCPISԥ jMZ! AKRpj﵅)Oq81tZQIKJTb֊"ƒAIZPRBYHb֕k1X”Kŵek%*JŦ>\B1 8NhҊKJԴ&ZMbJ҃jGԕ-JT8ϵĭlb% Z1-I$(i}i[J BQ q.5t)ZS&Mi*eڕhj5bR j1,RikJKcLu$IR\IZ֥jRQPibqH5g},–IY k1 IIbKjҴK[}mj!iKV$,BIOF[! BRhR꘾!M8Ҷlb% jbŴ-_қKME%luեjqLBҥ(%IZ-iZbx֢jƩDƢKuPUTcCJ>nn8%MJZ)!}JIbje)J-m)jҥi050. BXCjbf% RbB1(cOe,BjS q6VRGЃ\SXJJA%Z_% cVZ\bPLqı JVSQCT% [-ۮbj$$SR֥ZS n3\GĚBRS)jE1n$MZ_Id!I% A)KıI[1 5)B)bXJTZJV(b%BYbЄmb_caHb⯘#q1?u' CP)$8IE’LCPp,bH)mbPcSHf)Hrϭ%qHRRҌRIXZyMŤhҩ4>CBV꘥Z% c~Q a)qv-)6 6S}Qj)kDn8-(J~Z[Pqu%L1ie$rRЕ!*% Q*uSY8,5tl!cLJϺjt)!)S Q5)o-% }HkYjBYK8ZR)jR؄)J֕ J CX$!}MZ51(bq%E-I4#(KIZbZKB!J8m)RbCJؕJiKqVHA 5LJT)i ZФIJWť S!kBHcZ' BRQMBIhe2KAY)X8LcotIq r'~-iCYJ5*CP[%fjRTZ!e)-$ĩ BK5B RbLbIKRK Z)i%,b RkAiBRֵ.}&X5CM4Z[IʒL[b!IkFRbV5ZJ_1jJ/Sĥb -Bnš1nIIKkZy ebB:%hZWFhSеba&)rꚅ )!1ԦBV)Dq bRB1L% q)0mjKBƭ-qKLCQ̶) biVS\bjd8)ŖH-BU- ZaMk)RԭnpҘm)ĥISn#!gR%HJmxօ8KGA}JZkZ,IhbԂP Z_c)C[ŐT&Ҥ!IRR5ŭr4%!%$ĕdiiq(ũ.IY)SbңPB1rkk)j%)qM1ƒ7 KIIBLa1 !(CeZΨZKL-6ţ[j)k)K-j[Wж)qbEN8-)Z\l%4HuHLJVJԧq,jBTcjYm#iRғ–Y%8 .~!+)d[+HRJ[J4*ĥIKR1KZu,)%HjWB1 % ]! %hEPjR,҈Wűj' !q*\SJsִ!JBBT(B%*%!Rз)*[]qkS-NыiLiR:1b1 ZJ$heĬBq$(i-b_R-fl\Q%|,թ-JKRԩҔi-Rak1IABJ(ġD*J\JbOT)1.5bIBp KJ!RĔ-+J~%NC!8jJ_[Q+jRش 5I BHbԴ+IkRZZֵVĪ"ĵbajib Z RŖ)bZTjB5 ZRJ[1% q [-D>eJjA Y)$}}m)kcZ8Qq B"M41+S,Ke0)iKWY4,)HBj!ae-hb!B.bm*(1..!,CkcZRBS_AIcY`*P!XSĤ1+QI-ni/8 %%%*B8mDBP\R %'i֭!V% kU-n! qmR7 )F5%N JRЩZ!bZ]Q7U BP+Rű)!12 ť)R҆%!ŵICRW'Ԓ֦%%4'Z!Ũl)mK(jckZJ饭IL)/5+m(SjVZ)^$mTY8Pq$A y!(%'T-daPSCb)CZ1[}[KDRҥ"ا ,i) JVֈ})Eb%XϱZ.%)JT}%LZ%)B,0%(Ze R-*-d,J RГi$1[ZeK)j %(PҾKPK-a-)B؏JЖ-е1ef<Ԣf!ae--&%(C>A-E1 bXKeFi:ZVJԖim(ʅŭ)RK))B Wگ:)J[#jֺjbأJ%*! w-H[KJĒjYKKYKCBeLA>RRX;ZPRqn8-cXKRlsTcR%[1d)J}N!kyS~9% -ZRap'ĥ!hB؟($X- ZPXjֱ !*1yn!4օ)RBMbb|*B!hbXP1kR>JBVkV!KRZV*Z}RZ%R>%ΨZ)MD%%iQ BJԥ%oKRթ*$%Rؔ9*>!,ա CcƱJJbR.9 BRեB 6qĐ&Z%1JRݍiBaf RB)+֜BBԴ)RPb2%1*bP$ʐ-J!)kR[ bV)f&KZV!m)KQ6Dbu:jJҔ1 R}QKV}MIiBN&!qN%(l!) ZKťhcJjQ-IBIDMZSCZ-e)IBSu[N%g!,u>RԔ81 AJR5If YShe) q qY?5iZR1K[qֵ!iE)F>()kHj BBRR!ZTV%֩!5ZEbbZBֳZ$BbҢԄ-Kc)+J3A5 u8⒍BLE)^-9Z$(Z!jJE)jZ! ))J4i\bJh Ŗ 0qo BBZ}[KR!,B]ŭ/ \)J5 J>jZPD-J SP!&(cVbBՔZ)Je$)!J,jRb }*UmcAj_R/Z).5%*jе J!iR҄1Pg(CIIZPRb~PԬ'T%Rԕ(!+ZJŹ a\-rAlŵ$S\g-}SZu1֥bΖ1ICCV1\i6-JZiRB֢hQ؄%1ZqJU%nܖ8Z؄%)%ZRV7mRRT*԰ƩK)ĬW1.1KQB%J ZXh}ĵ B!}RP+)٢҅ĩŴ붷S򒤣1K-dj[Z-qk)kYil-RR4KY Sqr5hCq)B{xŵ8#Hjm-lZ(BK-ZWjAR!k1(1(])ZI}DiZY8i&)j.ۈRV1BԶ 2-wRT~d -a}HbTbd-;kC5D4P*j:҅JX)*iM5)Mtm)|bVBJY(Ŵ)[!|K\cjPIJZԎn8i8Q)} R%%IZ-!(B[ Qn[)kq*VZ!kkq1N- BhY -H-G! Y*Zyh[M1b^BJqbB䩨1HJ8; v\uQ#渆(ZPBm-1DZ\KKRX%rRZԭmRJԕ#~T&ŵk B)+RPJW"i)J q,!ejbqiJJc[5-R!$$! 9 cBIBN$ƭHJhY BjGT))! bДbR)B )*ִJ)e/,bŔCBZJ1+1Jb) 0RVSqe1X!r,aMRCI-JZc-CT!d)J1,q*R!h6 RV_bV1-)LZmZ֕f}jMRd1 CZťJT#VaKK!jLZRDqq+浨Ze C J-YiQ,i5ӌBV|xI%IFDBS#Bb֥څ[S-jĬ$o+R) C0 ZPK%)JRДE!*gض!}YIJԦ5Űbf&,SSġi[\cYZqAfJ1IBԄ*-d KűD)*1%!(JZ1,4Ŧ-*\J1(jJZX!L$) RTT-Feq,*cm%nZPZibrQmB- [j-))*D2+qŵ k1)J) )$% IBTbc%n)-A,N!JIKR–(j,8)d8ض-hbKi)TƩlwƑI%IETֵ, bԥCcl!PJKưbbX1<;q,sTcb[R5*J)dJDIpmJKS!&!1K^RRKA%JZҦ JVJ) T$%lI% b(n-}Z)RPBBZ1SV ihBN!(BJԤ+sSBAm}RTO}J)HR ZR%եcJjPRcjcT)qiR+:堾1ošX.1 9lR%HZPթj~4P)M(KIŶ.T1jJarӫQH}td)ϡqJqCICiRYR,)PBk:!j_RNJ -,䰗R+bkRݢBQHicB%!oڳZB1sXVKku jІ-iSRjԵR84)ID}fY1B؝-%'D5)Zq bԔ!)kP}LbBVk aV91IbRiR 'bRD)H)K|ֱ|b%ƭ)iBBش-.8bb~SƱ/LFԥ$-inhb kP9 :(B E,M1Դ҉Y-%i"ZVJhBdꖆ%yJ%8/[HJmbcոXR\!k$!(ZAФb`mR-,FJRIңHc Jŕq9jLlD.J6mOr [uji 1NVBS B KՋB%n%*l!/iRÉBqR!!m%+qYH-I^1K bVkX֒WBQQ5ki j-bbT }LBiJSBRu-)iZ$vġ(cP)FB-I-$ % RQ %-bN)+IM1kRi[bKMK}1Zb -BZ1kRFҔa Bе1;rVԜJPT- Y Z)KA [%HCZ\ShkX )Km1I1ZIK}(%J-+BIS1T1)ZVjևԅF$XcP&MbֲЂUJB1 JK%Kj PbxVm4KE%M"ؕSkV5 Ce,.:) BP>uԫR5*QR~Lƭk!I!R>9,yT(K 5i}+8,|ĒꖲĔbЕRД(KUR:)pr5HBÎ-2B],-i-jB8X%VLZ JԶK>T!n%(BUp85N ZTIR%$"Y,K-+JS ZB$Ҙ\ԩlbҕ!h )LmjqHB-m a$1)XҴ-k~ܥmRP\)ZD8!(ĢԒKCIC\j1K ZP$jR-[ƚ!JR!2Ԕ! IG)1:䬤8RiRP&0cqOKSvԩ(!IB jť*R R(ťd-$TYO)*_Ѕ,K}lKT!R-hq51Zb%IR SHJARjPlkB88JjR-5(AI ! BҕBЧ)j45RIcYSa q i!hF$.֥Zm1&7嚽!K)ZJ](jZ)+վ[(J*ZbL}I- C-8kZ%!"HBRb֔44[iJԊBQwX[ Bľ%HRҒV,qC-hZR%%IZ)LB UCT-0-LR[1$|K&oŚҔ1Ɛ,) T Bև)J1*XXXAZCI}(RTJ1(b}))&[ZӏZunIJu֭)i-qN-Cҕ5BP LIqlBأ%%E8} cXVXd% %))kuGj%ŭ )mK@ BaH!q$RZHB %MCT1$-)BԚRR-)Rrj-($!m!K#HeR)[).!%hF5+I_RPb%+))IKulYS%JCKZKkP4)) 5Z)j [ )e!ib*R JiЄ-MZhb$8*K-BY jJ)5)ZPKV!-+!Hc)jjX-Iֺ%*RKŠSZPӭb]cc_Jaթ_CP!n1H%haZ% Rօ-Hqa&%HRX%jBIJRš!)1f5%)[!l)Z,%MZ[[LBqFR!hBTKBY*RA KrQBIHRTCqL-cVBBu,bji*b\[Z1J$ilqRjJRе)KR-rI-š[RMj%-N9G\J- J՘)IRZ-,RXd JKZHBT!ehZ6J_qRKZTrSBP<\!-O,RPZ- JT CʗQ qjش,)*SHBָCPyGu&|1%)*KZlB)- !Z%-Q R-)qRB\)&Z1lJ J%McAK Zխϓk! B-DP q$4ִf-mZT[%Ɩ+J).qiiF""Ԕ-Ai5jK!Jn83MCZ9x5)}R bJtT.4VdjMqjST-(!-b J0ĭhBTGR/Je 1KIf)$ZPj Z)+Rk k\-jQ,R(Z\BԧTbjcԵD;-Z\SĒR>ֱlJBYhJS(ZTn% zK}*o,ZZ51_Cj҄1}%Ru(!!*RHj)|Jc0 ZV%("RIhBcRb8rjVrԾR%,[:Tu AšMbփj-!І)[KZbR-mSjҖ*JBn,ԱSI !e ZIMY-j_R5C~n%M}jV*+KZk[ZTĵ-K[aMBUKsq֥ qInP$ձ CPBP]%Wu Y l1iULYڄ)e5i!BSjUեkbJS(;L-nD%ZIh!uk[>V :!n:!!'Z!lSĩTZĩiJ q_qA)Zd/K5Z!b1[S<-,BBԋZZJԼSaԔP>b|jqZڲ kP>Rڢئ!j)*r1N)j1ŕƓũ*ZkRRVT\բBq5 !Jڶ1ZE!LcTe-H5$qh]!-b%K-}jBVH.I*-"5jWΡKűxŭH)OֻJ ŭIBRj aiBJSJLZԥ'[lFڕ-)5Ʃ)b!*RΡaLCKRũh(!ij⒂ԏ j!$-HZ_J1cT))l*j(Ѕ}iRIZRvRC7Bض ֱ ,! b! -kQ$%-SZRqiBV0imF-%a*brR8RS!+Gԥ!K! J>%*"PBXZƩE.%O b~х,>Ju+BEk}ĥjbYoSA-I(*ڙ+b%l-YY I)%1N%0%ձlZN!)lJԥqKZ]Z\kKSJRħN҆miJ;O)M0֒թKqRlԸ1-Zuk(ߡmZVIcWw1(8-kKT\jśJSk)n4m-ťjZ%-DJmBm4!4qISՐT[TTQ [a+&]jBc,RTA I\}u)Ԕձ-Z) JX%Pbҏ(UZI BFLTQ+NcӊZ.S%L%IAmKRXIRĚ!1 JRYZXkb!d-I݃T1IS*GAqhj S J1HK/RaHZLRLq[HQ KOՈZPRPCRP)D(R2BT%2HC?RbdK[%K*jZI-e!43$ŬlIHKά)E)Cq)bDc-HyJԩ%lBV-kJW} B!H%JB%1jCK1NhcjKC>a-,RTҧ!JKqJSZ Y jVFY:q JPVRRT7ʹJm%JRRwi[b֥)ZP)R-hK)]+屋BP%!Ib1bST$%7T%x-f5RbR E) %d)&˜ғ(2Tr c֜C}WM)[ŭ,i+-IZbRԅbV-jE-zu\/Sp))-EFq,ԩJRmJJPZk[T%ҕ%-%n!%%)R(Z1$ CZ XiZZ:TnhuMBf88) Bض#QJq,cmQIqX:$1+gZ鋷4'K[jZq8ibT25ijR;ID5.c-Ž*01j%iDWjRš׵1ZSԔb3⾤Jq -hkWiBVBT+-\RZDk% b*Y?Z BҘ!%KZX޺)*BJi %+JR5BҖ%_؆1TZq 8]RXZC$JKC CPĩC>9)icR88iIKH% K1j,pXְ*!(E;)R\gd!ISP-Y4bŭkZ_R:) !J%-EhbLJ\js"Zl/5O)N-&XǞ5j>W)YIyJ0P8KRUiiwNkJ Z1 #)GTrR-i-%CVzk(ZR؊I)qmIYIijJԷ!, Rئ32& ZԉJZ)cD%1p1/JIIK$kBƷbTŠ%-kRQؤWǓ,5JշRK ž-jijJi&Z(Ғi-IL\hƗԖKLE))_ҷP-J5֥0R&PĢYIy K,yLB Z)ġ R4,5*,5iy.:8r-JS!Hc‹F1*bK ZҔ8 )LJ֔ !kRZJN)nkC\Bp!V[XJũkZ Ya+ib5&% BbnӰZ qűIZ}UM a(b z1ĸťK!(!j- JT)1N-D 됮85HbLiĮs %eNb--E)qJKiRibbcWBQ/)?%LbROزШ10l1ĽչuN:c(CZbabT6Z1e8!L::%2KN4[IZWƒF)I:-2$[ͦ1lYikqjK jV-[P5%ԥ*B-RSIJUZm.ٲV!%8V%9ľĤ5ԭb)$1,JطmmǵEZB5RICL[X1S\!1Q3qԥShj1 gؔ(q Z߭q5Z_%_J l)8WBS>(.9)*J)Sm16Ԧb%b88%*BZ1 -?KZЂ(cR BP1dХjB!lJ[I! k! iq(3qBGZҎ5'C\bn8HBZ.5i.88CߩfJJRŵJcXƥ1q8Z! BBT.ִ!,KXǞq; ypIR}u!H3yAԥ)!(JG8[J1%%atKKX(8y Z>JZ]BbP>%&5Z1>kZ }(Br%Rl!hu|ĥNjZ o]MGҔ!+- TRKRmycƩH)h LhBRYjSJPġI(RPX6Ҏ-JAI8ո(uKF5q,a-ք!-BJqiSI]!)Z[QiLi)*%K-lRXmĥk[SmCT$8Y5(j(iJCST[k -)<:KrinZ jSkRֱ(Rꚧ֤/_ކ/7ؘRBkTDKj&)')D 1 b(b2ű ST,Z- KXkL)ÌR] } BR8ZŭjCYKQ)Hb%I+R! j[0MJRJ*14R$–KR JQJҶKHCek)ZS>ġ(JKj cfҎ!o8RJSyiCJjR)IRR| BKN)-6T-ISֵh4JPV1TY%JI</-gTwLCRŭϱkY0ı*RT-jJ1KQ ZPlYJ)EZ5 R1)!CJ*A'#cJ1nBBH%-)lB%(I5ք>icb)!I!+]dBB)/5!ťh[TTb~IBԤ BjYHRRBkZU%kj1KX(b0ı1cւKJԆGuK[!tZT gҵK\Kj2J~-Q)E|[%)Su qj6X)mŦ#DJT<ǩw0DDg|7D""?S""B!&PB&&!1R !pCLB"DDD" B&`"L L!D"1"  D!TDL!&HD&aDB(D@!m )`)-Bi Lrbc R JҮ5LkT cT&եeuKSTii[Zq.8n()kR!Kw q{k^jc*bՖΝ9Ը+BƭBkPƼuƭO0%bا5> Զ!*w-b-vR%䧭y]Aن[.Qj6 Cm %-N%H}-ZVu7BĩOP) Z8[F5%ߺBbyJ\A,JL b-.5"^$J]R_Gmם[BKy)T8CZR-OƵIK^bZԥuR\q*qսc)ǝu.!LJXq G!q5)5Kq%򚧞ZBb8)o}jp<!JVHB! xkA-BPK! KCKkΩcC\bumtڴ㚗 m)WfqFC<8K\])RQQŸ)8K![n)>~JHJ`"!) Q;)HJP%oSTHI.BոTK͌U%E%}zJX% ZҔRqSBZڶybXRJyxjIKIu/[:O)Jaֱl[I ֭Vql1jss! A)Cbb@ A CiZ-(yO5nrEAIJ)B*BзBǜ9CK8CoچB)h}Nyv) WmSR?i kJ^3BҤq[JAqLy8< t/qBЖ[XKR)LB][S})g׶'2Mґ>~[[OXE511ZSV)<ZҦ;ORBBjZy.!)cMCBF%IYVۮ2)Rq :ּ]S[ּSV G%$E%VR|!pBJ^u$ST-Z* 6ii$ LbkҔ}oS]GD@|I%Iu4i%.1ԥ>ԔR)0!)1Hun {*1JCJR)$)*!KbԦ aIG qJyZk:%!5Z5J%î1Mb{K]!%J%Rqq}/![JLKcb[I_b><-$ q} 1q [5k[8[JYcT뮵1%7q)Cy(b\ON8[5QI)ǐ)T!nO#y׊qU) KbCK C\jб KP+q )Iy甗9KĥУ#IZ[b]qh\Z\AՔjP뎦㮵ZR YE%:Դq K8!o:b^bc-(R jr),kqE ZkjϸUA!HR FC_ؤq2ϣ5'P<-$ҳ3}DDqR})"C!,Zv^S[J[4iIj!-)SB5 ~HIQhjq u-qSB]qk)kuǔ}k qkjSKXZBVƴ,}LK-5+J֩:b~mN-VTQ[҄N|, KCVcC]yV3fӥ:4kk[D\[ӆ<Ե%88\t:ƚy.uJuo%^Rj1)Q4 [(ה kWƸJ֧Q:X!'N<^gxІi[u]I􅵎n_[!<}6-iqgc[V S% 꾧yB؆pnYqgyJqȇ5mROju;|^D 8Ң<%_Rb--SbCT’z1Ժm-%SS8%)Bk-I8N-lR[ųs庒 C)Kq.;qT֗Jyq-1.:ێ֢a%(q/H-1,jk\ZRε/%y- -jJaT>mOck)LRcc5:yjP5J~,źj-)BԤ!ÎRQ^\-kjLjTxӫy,\B[Q+sNy jK IļJBy>[ZYƩN6%)[RW%BĚkkyo:.<iyǚizy(jW!'ԩjԶּX}ĸZbji:]u+rZ !<[jKxJڧֹuǺqձ BBзZ-1lBBHuIq^wƥiy:Ц~Ki K1HcSPTZġR" j82š0S\KqIq(y]iơ[Y}>\b AmLu<אb)Х1u-k<֧!%g^qiSZך!)koqO!kZ\CRyyļոJCZ8\Ru)H丶qռmJYZw)JR)HnXߵ昵Ty/8yn ZWytq58Υ.ּ<ZB\yJ-Y)*H3 f22a!у0S0b$pi挬&DOHܯib,80q-1LB[.O") p5溴8m jФЦ1-% L-8\[ε.-5yk:qPqmkVس%f.>k5n%~k[C1ejCu[BQcsy- q+b֡խLe5nǔVW~bu%%N\q[1ƤơǚcT֔-jP\Jڷ0>u*kڔ:kqqN}.f%NymkkX)]ХR,EfnPٕB${/ ffxw{vd{D$i,H4FΌ^O! go:(icKZ bVj J1Z-L\5ly-S’t8\T8Z?:O6TPļԭnn kq~JMuL~A$Xa?5-1I3c6n!y؁C>f}kZZI]?ZԿ!NKbIO:ŽDEXgQVB9#%ڭÏ, SiŽ_>y%.ku;#..:ԣ JZ#jahERҸIT S ǔwnRQũD<~y uRKH!m5S""4LB%b%!F%Pï74D%KmHj^!ZX"-^K'[-.:ȈyZiuN+B6qn#jTD-KJK"%m)S.qļ[i_yI*JZ".PR%WL\K0Ai6M8KTqKqmhi\Ao>b4BJJDE|%Ii[DkK[y1aT]k(ukIQ)Ʃ?-i[XZVI)TLKymbCR!\!nK1O:KVN<)Kqu^S? D4ĭLd"q;#KP1eڕmqƒ[ly_^y q8x΢Ǘƭ!Q\CbRZn[yyykKZ^c뮩9渕1ny ST]C Sc5ũFSuג:┄mSXJKz-uP<֡5S199B^Q Cӫyo%jcoזKbHq:ZR)N;g2&*\qqq_lob KJc % ֦%IZ}:Jؒ1ǘb^jByiKZ[bjxl)ϘQ-CjK%ƼkT(v}y|2"i,Ki|D)(F Ӌ\""msit>mmӒi/lȄؗJVZBGSqX# g*Էļ){nS6UHmeD#M\"3,暂9["yաݞ-v+KЎ)VGh%$8kTגԩ K_LSzZL[i,juKqky Iy!Sh\%)B޼<׵}%.5nʧϾL8M\D$LD%O*"-EA)m*JI R:u--éuS8bRَGcZ'ʈFҗ˂-mhG1N:Ê}me06θbK1f)/-c=qޭcʲűi b<6DC7Q*>(#yJ} NRA.kkehqURm1()<Ƣb44U u!é:yטڼJ")hFȦԄy\ bZZ!q--OYM!mBպk8?|-bЕ$TD:u#J>i>jDIX qi.N)撣ռ}1ʈZ.!("b!.!b28"6\Ѝ1hKռ:~KS1l{"!E--D)CgU &""XDC:uƘin(JQhqJֱώT ck-"ڢ"$:iHSilӪlҵZwb>'D;lY RTmAŴq&ŪRcCZd?8\Cq uy<"Q=q6߭(z-J^JKSu jV5?=+RRjPnǘb1Rֵ6uZc} b>uľ[jVպ-5)811מqnj[8Z-n-?G˵<[SV:뮰-yKSKYD%y!.)(qO-ԥ<#u+quZ5RǔƱy)ukSq)cα5)L7N1u."|1ōQ1B1ͱ1Kn)qc%n:ĭ RmT!->Ƣ#FJu˷qi-}ky%NSR|J=nmZ u*DGK1ƚR*qC%ĔRR~ic[1ǟmŭ!m458$D,p8T?-i1ojuס*m|`uhG#ID-O-5?yiuRۯIkDC1piH= yb2$DPC?(}o5~YO[ΩoO5 |F)[S\kOK:JS?8Kpqiac?"8y.,D)OBLZ[slD-n5?YJJߘKqJkGSKdA֛qc:yAJjc8ġ–I%ջrYմF}ik6հŪDIy W)kXZ~yPҊul%?15bF6J#Da "7MPE<N%KVHJeDKJGdD%f.4l>qj|CKmcbqD<%,tZR%Ժ)[ڎS>ZNrÎ(qmŐқJhi&)dY(["R c~"jĥO_Ajcԭ~ST|΢cmB4Fj-4ƕlFi!+F-o(A cuU =W[() RZ\q..-ig:hA5Mc^y%%+8K5(Ky,SkZTזZ.,Iulp-Hyӯ8V:Ƽ֥k-z"5NSΡu sykcCZjS^Sp^y+}S- Kq!1K K~ bjSKMVtL4$k{Xa@B%o-J#hȄbX[Pbq-uKK?| Ip͐TCN8CM#Z q#KQcld"Q>Tk]y(1HZ]kRu sKo>TDtuPDȨqXF7َ<_KRSX%εnM5cA%qq"c"Co1WikJ֤DZy,[q.:TBS<4!ԋmŢ=ıTQ*RE@ҢڈRtZĥo~w]u.- JR'qN崈pꐍ<ۉdCLqhHQA/1O%㎭~R~KSĶJ^DFJ uHm>uӥ&:"1u"%ϒqQ qԌyO1N}*Xu矾}$=6ۍy:Z2q%$C*պC01/c4ҷ iD):R-QƖ|XBM9"#m-Nu>tc5 o]-:O^y y:V RyG^C1uRũ)Sb#!J"j\DYXh%qjc1LRG+XVCZ1A.)6 cM:-Ο6iD_>|Ŷ)jbSVPK~y &=VDVŐꑥ3"FҨF6́namқD\DVSFM~cŭn5j"]y|qbcb"XdDK)h8)H9Mqǖ[<Ԯڥ4KS ڜm4FqhҐJ'F'ˁKbZ!k6ShER uZS|! qJq t폔y|:H$2 4Mj!Ÿ"!juC)_|Ky?)L%f(-o+s)||D1O@ŔF>jS,ҥZeq4qji)Kp]~|qm0J)+D["l`K->ZuLDdYH:yg9SͱS4능%’յםqoǺǼ&<\dILAO:먗XKZVRe%O)vIsV<%5.b\u [y-MSYRB՞q:ƝkjO%)\jg\J0XWBW W|۩ȉSp%G6mq#ikLmOq~uRy| %HH[N)dFKi|b"VbRS [Lnq>"]qqPSS8|Cm!ے#T n<[߼:>ZRb!|""X{LiXGlSM-㭥q(6[SCoKiy+|}ï!HJ4m5b"TPS_6 n;uq$J*\Zi,S)QG[)!+yak6TqAŭp%'-R:JZuKX~xGֆR/ |#TA1oh+Um%&֥8ڧϟ!kYԵj%_lĩuyuǭJS)[ZR:JġJ[q[i yBB[TDihhuբ&|ŵuN\iIyd8SEȴTDuLyQJUKGK)aO>Rd}1nSj!ON^BZߎ:RTǒpju):Թ cVĻJJuP-pKX\jۯ58,%jq\UmKz0)HR>dإ%+_1i|1ג<זOR)[O9%ՌJ"(ANhZH-[XKSKcJ>8co)k[ZJ1M|&1%"%Oޙb#%kR,ZLK:ũ;-~y Cj⒍'[}}#"*"NaP4cG4D5uuթN>+jKu5EeP-%,iM")=;Pώ,ƬicyiRZku.!lun7!,Y*|<ѷ̄1 4MyR4BLu6ql|AjqN%/|)yƩ5)zz"6mb4RZRiDJ""<:1(C53)k^pJ!Q4# 48pŌIgg JpijKjP:1Nԩ/=\[CKZ-b]cg48dj"V[_[,ǚr伥:󘗌-\%’-N1 j1:V%y.ź{q.Լ8%hC8Zyc{ cS85kcK[!mEq BQԭ1hu)JS<5uhR]KX֨558SbR)O8BVJ^ZKqSP\kO1qޔ1 j:յ CCb[XkkB#N8RN74% kJ5mR :JZR1Kc1LcSKkqlqZZO5ybC-Pu{V ycKqkBc/!6%Iy8u:1-bR8^qb$<<17v5+u弔:}k%N:b1{1Kj i g8|lաUUɻم9vqF ,>EZMŔ 8vnaj8BסZ) {LBԺeXjZaԴM0^Ll3pK:rζF IyN@Ia!zI$[81P)VמT59kמy%ybPJyxu-qCJlkɆ-אϭCL<%ױ*u5<󮭎Op>,8ȂmZQA,J1ZolAm%/μ?c~bzkRz"i"(>Kk8ŶR!V"VR cT-Ʊ:Vz3ƥM-oDqNb"]1IRӉKxER"bȖDB^"4[K8M:}-8%N?5+߅qa(_XJTP<[Js![|iĵ!ז1~wRj?1 #,)n,m"-iBZT#[l&IkP:[N䐧[nSZ"((-FcTDScvۍ3_-Ŵ-RZ!cK1G_k<׋sAı'IC1N!bZkTꚇHk)ձHq׎ǝjZןjyn[J҆)ג:R򖷉Kymuո/Jj\[KJ=Z\yyXNڄ% S>1->BqrBb[T).88%ԩ8C;-QޱڷP1ly%*)jy1}mBʨ-5%)M|ҡLC%D%(ե?Iט<%/HISTDc:"#M8XғQDi%aSHm][c|U/-N[8N84ښ%1*:ؕ>iƐY)piJbIq1o%JU)O5uiah1-8.!Pڠa um1mXYҭe1Nk8[-Ou<}N-M41ԈKg1OjZÌs!_bXhKd0㎩R1L-o8:j\kP#ykgRk)$<ťbc8CcΝGb]qZy:Z!yǜj uqO:zPsT^O;nSΒㆠnLuŵ.ub^C5)TZ[kR|Z[JЙCδ<ƚ|E$D^ʈx뭭1--\~uiunn>|"ޅ49CZ :up\uHKǝoϵ~km꒖%y6!M:E-oikHuLq4Fl]CΩļtJNRT16% zqP0"KiHSKOj!*4)Y'زZz7NvZM>AiȸыK*"YIkGb}LOKc:!/[Zk]kWם{4DSRUWqjATEqq yCa¥5 J1nX~uW^ 9 :|[l\C)- ]rZT|㸦1ԭKBNn,in-R\|Ȍvm6a(44_3ƛM5N1gֶ%9Xֵ8KMo)M1Bm":bQ&:( {"әň BJԅ11k8qO!GTՖNIjZ޼n#!.1jSJc:Z<եNǔԱ%k[qPĭ)uIKź!-Je)y(y/-+y^oPj_S:&l<< k[ bkk8Vu$bPPֺlcNkj\i)jԴ맖N1}GZJB>1APƜiLSVĸȆ$%Ko- -_ܦ?%ֵn<qQ-[M.)qjSڗX^B"b1n)%/IJԭJj>l-Ţ>db#+#mU:p$ĺm[4qi. imb7FOQC[u oVs_y.?)ű鵵RzIm2#qT!L|ђIEtĨߒ}j=jcĤı8 $["'"8Ī!J1K|b(umbkKZZ"ZRB<#JQyՍb-IMq<ե Z-(K\ayBQ:jd,E1 )*E!q_zy-k-bTꏭhj<\~`q(Pe2D㮼4%U\yL4RGt98-# "JKk[\ [N4q4CCy uR:|,!"M\FQ1y.eq o5α[-(_T܎y"8Ӯp\Dm#IdBšN.S!ĞKε<ռ3JObآ[C:cy!+q弃Z҃\aƵƱ(j_~O&R\<װ\%4-N&>*=yPڋ6Ǯ 8e"$҃KJ!,_WQuVl~Q/gemǑ:q \ ulb#|ER)/]еu"yLҞyO-/-aiSB&hG:Z[mLR"\P%F7qkSL~0c)t%V-pBIAT6Fma m[M"j伳yǖyl~Sq=8/>4i-ĺŒH1HiS:)矘K]!GX~>!-4m(6+J^YͰ#lKn8[NXձbR]gyP([|:cHXDQLQٴ^KZ%%yձuhU8\q cbPQ"[O+Gu4adH4ĭ%mS~8塩~rW1yռ|R)Ibе!*sXi!UXж%SnKZe-7y]{c9o(j_!<>Cι 6E+kщ%&qjyVGRi݄l<)-1BK5 %ա.")0qHi$i6_1u_~1ĺ a?>~yZ%(Zޤ m٤JbThmFS]#Ny)~JR▗X$T>IėaӫDm[(umȈ;.1uQ/V!qĥnG"ea)*N(C~[(-2k|8~ųbVs inՔjb4:R۩*lu#JKABTym)2qN SuԷbTSLKU.} 8{!o)לҘ1V\Cya>|R^]yo}ĺjuN5T|omҝlŭ珘T(ۈʈԅn8i%ƐBѧX:cm%??)l}OBYtj}8"-ԭKF1i#Lckdm_1!be$((Dc1Lq-n:~~Y#<:V8ܤˍ11U)rL#F;k!溴~{:lGq0[喍<6EgRDJ)6"qռ[/%Oθ0S%JU3fAR-NR-m)oY1j}O?u؈PδAh|R*|5Z)p1KVPDd8% %N!hSm6ڙƑ_b؃K_)!Ź,q۾<%M 8R1m:Rq#8BC[P6Y6ڈ!-R5ԩ.J☲XZBS_WmLBǖU:4FEi%[SBS[cZyRc #eD: F>y:bRUqMJK:PXՖC57qyh~u+MY)Q ZJuK}N8ŵ-.)-RRǞj+SV51ź[::,QLsCNPVƵ-K%hy-Bq-J]qLyqlqf1Ty琖)[ R q,qCPckTQ ByT pƺ[JO~?8Lupq8dkcuZxP/5/-*CR4Rz8p!J\uzSz>^BPSKcI2xĩ`3Ah0g4[TPPy/-,[P%*k51 u^8k>gBX1rRU%>KkJQ@"}F#) ф^bu)7Ex]lŠ:x*G3Uȉ:]+ .ɡYis_kFSn׮5+DimKEZ\Z"Z"+IRq'o䭎1J~ZI9 qc̈-1QYm[Jy!nkT!Nu%JjQLy1!O;8K~5[> 1N1ERu1 jJE%K%[TykO 8Ը8Zҵm ^- ukSkhbDk!([xyOeKV_inפֿu}ǒĥPp$ͩQ yIqoKh>uL};(bӬ\G q-ĥΘ% qjS C- ,տ-(Roym~Op[ZHjJIvL4aۗy?!OκS|qőf$%0JRQJJ,lqm*Zp⟚kyN:b!(8- 4ڸBm6KŜR[~Iqc~Oe]ZR5JRRZx#Af>\>Pj8ӊBFؗ[[\lE%n>[ԗR.aE88yƵך뮩䭉qc(Sv]kq)R<5?xN: y.,q5[1q-mk5IjaKCBЦלS[R5Ljc]ku]^"qԈJu)bq!j5 uu֥ u%5.1iSPԭjcPST򒤼-:Z,!%fd1(Sn-nJ[yJum;dDr5HR1O嚔PP_yLy Y bSRu1u԰n) Lb-Kynu\j8S qťg~K,JTҖ1bj5Yn8q~J(Hh-nuG[umd-<{u!!-Bxi:Xg|9y'\DR,3RD塌i4Q"i\J][P)dJJ%֩G*qh|;o#+yҔN*bxE1m܁lbJyHSyN1uiQJK彐SjRҵ)u.C1m%"ؕ!M>ێ>sMZ+IKSW#R-D]i4GTC54IDSyLG:bǒ)Y-yh|m:jqq^Y$ڑʉW^RukY%RT)Srۅ!nxZX֚ylJZu(jq^}ky,JYJuCXj:-iKN73n8 :%j])*ykqK8)ǒ--Kq ck [Pk >YjJuo>%Btc_=⼒;dFJ-DKi%iĥ8[)o>RR_y%LCKS%$ Xkŵ,u)y:N{%5DqmOnТZ#JyLdDcKZ[nE!m_C?Z&1]hiR4Ho6Sh84Ȇ҆\uԔ15BPԨOjvV婈XQ2>-8ş)(UM5bũ?DjwSŸ8Z]k!qk jWjPԼKu9e:jAԡżjԣR<Ÿ:Œ 8y5kR\ky-N%թK^CcmלUS8KMZԩn5)[B)[qۮ8ּ!jC![*!N1 kz"eCQ-N%i*Q1BEG\E<4]m/-FTq,u_y8_kugjD W%rť=CvߏZC~R][[:96󏏚Dziqţb%k| yS<qqNPܧЗ]C_jVӭqy8)(åZH~c|U:urb\!j,R 4mո)N9㪅o-k-DQyo\cV<[%}Q?>-ם%m֡?5<ל_}%5C$c> Jqwʹ;ҤHŬcؓ(y%]KƼԵ:qO8R%C1GVKS^cuLy2pQ'EXFqcݲ>. qǔBYO)iZ؎__kT~!ҎvŴcmHR#kjXƒ|鵵q:gCÎW%+I,up&8q֖HX11ԵLC<ԇLj1qLZTBRSE")k\Yoy<󭰧8ť/-u/O~%󫟟R\So͚J,UqƖ)Z5=c)FZXiIu_"*7VyBAyCձ,~q=G_1KqXͱfZRZғ8qj[Zֱ8TOZ_:\㭕^-S4:E)hL#O%n-Xk jHGuRƱ):]~RqXո)&.uǘSR~+}Kqbҕb-BO-㮺JRK%nOj:%C[o-ƥG1甗x~ZŒK8Bj\cQS8-(J>?WukP+\j5μռ)U5jvT<uc85/) kulĘnLIR8یjS%LiQ~u۽u/1Lc>T5%P)BKqJR`%m溅*%2ױ8q %yhhQH- h1 W䠜kCRӎbq(rX1 )C$cM<4-aƔ1-(!ĺ)#% $S͵%-k)Iabm'ӭbd!,QTK::p3n6mhZb RT(T*bLE$Z CK5漒N!Kuֿ=]u8=(Zyz\qcTԭ=ylK֚ĵֵ:MS\qլRVN1 iy]I B!Ox)q:m'㮻.%ZϠ!j!(ŵ),JB)nG*bքCS8-bKyZX)թ-:R)kqZX!R:1Kuiq.ĥkwq!,$[KgDKj[Ly!jJC?)q ~yqPRx>[!2!JQ):㫃MubKqKKdu/,~CRISyLKkDDi$KMQԼDER4qGy1-S5k5h[dBƘE<Ѧ"Kj)Cq+cT߉K8X(RDQR#)qǖI8k쩐K5ƺ>qKQRc͐e6^/?%歉xO-C>N'JžRpZҤ)#iYXR<ţXK\R]uq/-.mimk؉Q)q !ҐmJբ1?4Z,yZ]qu1Jc5IKMg䣏Z1-)$2_-).\F1xK-BTZ˷qJ\yEZ4 6m-[kJO|1.kBy C!cֵmJgyqֱ:*hZSC,Xypf O F37ޢ$E&R|SjZ}[r[:w[RyZ|yj#M:imiֈZ>b.[ԺBC)uƿS)Z։[ˈm,y.6͘)C\Zҡ) Ru)Py(jcԴHyK??,)MSqB\q/8eMy5hK%o%:5)\C[[i!_Zj! [qƵKpD)CΜKu<I!ԵKS,V SuJ\Sq('c^8uĭ<5PqZbN%(%kTNjjZb:מaŒy/tռN)CyE!jASJJJyo5<][SJqGcBT\bЇ yiyqiCTגǞqlp-)Ա2ű%uהBZЦnN:!]8\u!+y9kZu喆:XI%.8qNuZRuך+1)k1Lkq q[Pռ8::-n${ڧi:}Z[}N& !m:G Ùht mꤜ^iKMi8u:J)JFISk%S)^Q0 L4C(kT㭧ĸ!K]Mjeġcqu yƽq!KSsG\yjҥb we!<8EBIkrVSN!y-CPB#?5 qJZk!/V-kSMSPR!TMܲK(:XK,ZT58]BaJ!o)lbKAN81<}*KySΖ!W]Fϡ/пnIHj/OV伴/)&)c~~Ë[uSԱ|` ; 7>Q`":Ӈ;4eV0r4Ų 84'd]|Z\Zcӟq7"bGA7v*8Ŵڈ,ER]6W,K04֗KSE|G+Pi\4pKs 1żVcЕS-y]8cZN؅FKo2-YԌuħs[?8-ǟCqt"TF_<>I) %NPSIm4OJVTպ ~puJV'S5ƩK>X㶈;d8bJ%jF68q8-mb\mc[<5‘ImeSZb֞} K!O--cMT8ĒCʇG-c21b]e-Xu ),qJy :SKMpג>y R*-du屧[S -KF䶗n~K~uq˜ cQ)q"֗$!%)`F-Q|y8JߝS~zJq5hM5o(-ũkP)l1Pֱqkuo5h8)kKT:o:Ry:X7K[8~uqԩc1ո1֡Zz$yJ,֎؈"uqQjRQmkRSTO?5XjV8K1hm}%va&&!(qY[ci[BLKIy5XJ^jy.ر%HͭuMZ1RccIX)qu)A-Xڒě%B~TEF6qipS4JcKtNb-?8RX9[J:Ĺǚc%/GԇuE餭 SN1 qkqu C__yO!-n>z")/)i)աiض-Ǝ&"mZinySjfPITBMG_)qDJb-6F+LqiÎk^[X:!ŚdclE-Ci,ȍ-HR  $ ( A4kK8QN1I:P^GQƥJc:t-5Ʊ;ՐRYNטRP]yS[RP1}ëq= Z KCXy"8ߞb IvJڕ-L8JԄ1xuԹוu xZJm<:XY,qk 1 [R-:]vV>s&֩8fhRTi)L*R\k\S5gr.:ͥbDt!\Z#Z6kKELYԊ&"MucKHb uej!bH-`JD-?}JҖ?88zJVbRz<-h|Iڢ4<y[KZߜSRXk>~8])q/9qsrƚu.CI1ť[ZT>qKqn5.^RPN5 w!VT)ZbÄi2"N8~8WYg8͵`ZncKc]MR_iWRX~q楋RT1uOkY䔨6Ĥe>i],:ğa(cj<5 Y+C:֧]4)}cзR/XqGŷ uZI-a*GY-6jxR[q5IK])q R5Bun;Mt%eYT:ZcZ<ԩ-}u\OΪRR"\uN-zEk|ZcRZ!i8ZÍu c.mCq55JqK[R\wטĦ ם{Tֺu!ҖƭMgTK|W;Dz.PSu|q >ڇc孭:1ŭ bWd%)枤KVZԵZ!~FuG͋SvxQlu!:-,sifjDfTC%/~kSRҺE%P>OhZDn DEqEi:1 yqjZg>c#Q:m#lt B%1jߖ-%D8b8㍱<l~~yƤ8Q85/q ZO: Rڬk~8Ը<өqMyN,Mqn[<ţd>y5(^8>yo5c^sWĭn5(} gk~b[>I)~-"Ze meԝ[}ëBԥKRRn$-ccw"Ԟ1kZSģKZZ5Ŝ~Kbjeiy'~q.!H]ŧRl"bN,cK䩆%b}GXֺ"_qqOP)oDxǴ8֖%eMky,EmpRdqi^܏İı*uS8~yb1)qh!5#84D-&شb:ȤK yKR]k~y.!kgu5lwN֡cN5dꚳ!)8ku:ǝc[^x:Ї%ŖB>+R]~Rĵ 6SRx "IG\QcUO)g(Z!ֹaN; ~SK%.5/(qjCX<.b1q-+BT1e"۬c"qq 6u*Kҕ1?:škp]ii)#b[Vַ8 KkL֕1*B)Kg|?-ŢT:T┉JZR)kR4>sm4if;D퇟88%7u kzX2$* QKikcvmqd[[eKiyu,y-ۮB"7R4[FQj)HI#u]]%N%O[8Vԝ|"82NR)(Kqo>q-ı/)C(ߟO}cvE1)TDSj_5O8K˗ı.S>i'\Qy"(Rԍ0F<1oCPHSKKZQyyW-e%HRUcG48 q֗1SjCԵmIyռr>JqO.!m#u*(PkuN-%ե,J um8VTb[tĸqט<: :TRyIm()0*!5Ωy[!Է^kֵKt↡Zj--)q RP>Yym((~Z~y1 EKmCSʂqMzE-#M.O)ՔZߊbHT1+y/:٤uRYjRp1JE\wf6n#n(\E1-:Rۏ8qM6-f>z$u.4hґjSTB%%Ԕ~k5%l~%ı?[~Z_j~bacqՉcPPDczk~SR1ָZSyY~y)~J-Jc0`QƌDH9ql;8뮼16b\kRJ֦-jkq}N):RckZy8IOڵա)![dkZ-%]Enֺf) 5 S):JP/R5 [8-,RC0V8Fv[ Gs-dkrXΫMBWRU]uҧxWU88?>u6F:ZqHKj5D8~~ZRb_:|m4ԩ*8hZJ^bZ i+Sa0[l[pK^bV[^=C1N,mk$㫈b:mh16~[O]be(~ qiQLD%N<-gTjbIj9ĥdKS) SͭLqǖlҌE>ipkv#ITi(-&>ueaSmYJmdhn6i0QN4唋|q1C%uDםRcVqo5 J]qG)M im*Zv$8F~[-Hbԩš*wOI/-n,쥑չmǖ-iTmuz-N*)j5N% /J1(*q<-kqk9~ycI(}uF8`d8R3%hbXkbx- u)e8ִ*qKZj<4ylD~>1adhGkVԼRjPձKu u<>q]qJq u1IRy$뮭HKJ)VԵiJ\y҅uJ<\yR[}[+/!LuO5KRߵ\q*y :Rq SqKbu1f)n -Kl8Sŭ}JuꚔ5%nTRڝjCS5--u k\qKy:խHjЦOYMkykx\[Kq+bRPZu*RN<8B1Ƙ_cR򘤵1Thp"/QG,2DiAn5盈_ }Bi)1W0Zy ScV%'YZ+K>%#@KYY&(ј1o ƒͱB81-;5V8խ!ucGԥ=Cu[9uJCiy7Ց<ԥơPyƻo) sy) )A]ux8yt<)5R\Sc+ߝkVO\(aPbRXZCD<ꔔ$!⒧buĭ2o),t5,%l8!!!&]u)NO;<JcWy:yjqAũ1k8[^J^qkk^u/5Ƶa!=zK y [~8]Zh:5$%-KQc1<:͢u^kκy%)kΒ:2cD!5kȴc]kZymHq) cJa%V%7iź5亦|ZRd!pBR^zRS)]zMX[<]j>:^uS)(I))%]S:<]i)CuԿJVO1XRuY-co~1gISP6<ƥ8VyjP5N1(BY)YHS)!o)ڶ51~!AIJIR:|ōR4yM:QuGuĵKCIKu>>yK1f!%n%oJK-mkFin9~ߎcBkR[q'dDZQLZaQm):ڰ }Zq)j䭯K~jbT#XQyM+|mA|%y)yiCLq.B\a^u8Tb$LLiLUSM)F5cLc:85J{Mmh. -I$IJRTS16ґZx~uǒ~8θ+qS%Ƨ0ršƱמ51j]IMiV!KaĴQ cεRTǜ[8ЏRTV:8طj֩C!rC<1␷TBi%Ǻ򷨟ű&M+b]Cm5-JTÈc)qӎ:b) u]%;OOy⚧t>ךy)=syBq:cVSkV֡C>< ^c(}Gh 0LN5 8LkVQ#8ǜb<)xҔu$YEGZщE%6Z%WT*CzcZ^5ΖW,\[LaKZ#0}lASךP)cPpii4|^F4q֌>K)Ԙ`1ŝbD#3 (~F|XYEYgwMcL-SgҁŸJ_ūXվj\c~bZ-5B֯%,R\Sm"WL+MS-o%TlZ*i_8*qώ)HvM׶-n#dXO9l[_;)Ƶ8[K(C~b)S[[QO8LkkX?1 jZb"KDZ>hӍe"P>KqdSVJ1kߚI~SuמCiIiLakFm.4QzTbԥ5Cuά%N?1kkK5Luk !)Kx85 JVZر従KR%QN%Dy1SHjK_SkXCy"ڷ^RV?q>9m<}:|ыSL1Ɨm_,m."RO[p>yئD@`ac4f15c-H[}bZZ)hyC1֥<男TbǜQF4*qK[Ib-mQ-[?%Zź!iZ\ojPIckH" F B0CcMc$e☄'XvZK )1*qƱ.1 ui5Cu b^[qqZX¾MLDu*ZR>ߥlB)jbԏ<\y:ZĽV%iIԭKqkKvyLSuW֋C5:εޥ-!5<:KX]n>x- RTb@Z:PjSjQ[~y% -JZG_-iybڣT-X~%)~kRϖSz4VGq-kWŵ֎8iI(ϒ:mO-ףl4śR#NqjE1Pi5/~OاB/8ǝ[lcKqĶ%LP-䘦 Y*|XjY!Q*KJqTOO>|ѴȦߌ~g~[%|T-coԟV,q,J؄C%K R}ĥ5&5I5o~~aǜJJ->-qǚ-h!*u%~~R Su.q4b\y m%1ku[eK唵 ]ǝyԺߩSj_ku#KRV)D)F|dCNcڽ5:[?5o5qM% f-* L]ͭPbP5!^-gj[B[[uO8unZPԥJ[!qdKyטkSjqZLA$Vӫ)5qkqYWFr*^rʵ5SlBε\K^BX5N!eByq唗X RPǼ^C0[ c)K}ԡ~}6+ 皦-mJwgFZqCiNijqR1N1/~Q1 '1M]~}ZMj֯Zߝ[}cDHҚKlE-uq%(yu AkC[qIR4ЕZX-ūk\Z"Z[hi8Bqpu[bߘRWa$4Y[!eB՚SԼlЧǏ:4ߞ[Z>[qհۋYrKjBGRqJGYI֚cŸbZO1ψbTK[Y)i1 QkLcC[:!BSV)GCxBC[W߾-վqb\uT)Im.!][y۬y-qkqǚqMo*$PuFZ͝u|%MKc ZqX[iTC> uj3]C>KR*iCy5OεTy%C>Sž%Nխzcq!מbϣb-k_|ZbS_K\u(3KZ-Ǚ !uemEX-C$X[RR?< [ZOk8%Kyl#CQOϵY)T\y Jq]_C_q:-RTէm:Eז*ID+km5qFbVbQm5NJ1))!bO)BRżm*)kSL:!(siw5~c~S^aKKSZ߿1TT)Zi%P1LbRCTJkV%,YԵ8%i[1u3k‰iF~j?0ǶiՖi,ԍ2{SlOÍi.8buRS\ce~A!iK->mF>SVB^yjy\[Z^QkS㮥6_<[#gZJbuӰy(ޫR+RQIc^1=y Ժ~u_}/?(:DF:$Y5j\S~V1KkZZ~vMN:yԿ%1 KRչjY?-?7y5[JT1P֭5}muǖ]KJqkcHJbX:OCexqj=W%,i(S:t%1G)u BT8KZႽ0#׾c1AA"(E5K.^[<,"g{#|`ȑ2߬QG8uom-N!Mq甤yjk[u c-1hC8^Cu-w%*]SiJq qkuC[ ABXq8?[5סT<ꒇo1<ˈyֵN[Ru*ua]KơBgXZjR8yqmZSSV bJ{Kquǚj~ykq<4]%k\C)IB5_vcɴ}|V-,7yyjqyL[|;疣/18k:.$R)ŵSTך>\S::1Լq)y^ZҤļ%XPyָZpơN5.p:ϭĝyZzbcP][Z:ֽN<%Ը:ũ}[TjC#ZLK%^BR%SkyNǘ1yZ\Z[q)KuO!KqiS%,kLC]cRcKV<-i%jl.uĞZ^cSZZ%iK8bB05H!e)*qK;I8S]k!kk81Ĵy,qJKIlK%ޭ| kHy,!lc:,cNiXRPY3Ě`2kl:&v+.cXqghiҋ#'FkS:[~STK:~[KR\:r:%>5[u}1wzمZ>d4H(M2}"JO[RaECVךw8]uKiﺓL%2 Q%W ڊeӎl7Ԉ8f&gd5/S=K%u꒷^yKuԺT)CT,iCq:hF2jyդjuH^)YVߥ[p!m:Hg:RZ:ӎ񮱋-cJXǒXGVRut[~!b qqyǵ1GZPůZǐ!) K<֥gڳjo~%bc:O1,q;ŭ:TJ}<ԥΞkc['uŕJuoڧ%N,-}~:cc2Ħ"Vڞbb%V[imèu!5KY7>ȴV1i9j$ґJZiN%qǘqlJ[S98~1z-nJMmNl8Tc% ~KN-6Ӆ<>TDiK)eJ_-HeJSc%\yNK[mcֶq#Z4:ۖqΩ~{!\CWCZ }Kե CBVub[~aZ_)[<ռ>bkT)5o]?y::j_u}Js5:ζ騎[Z~LZ-kΞsyix㏧]JFdZ]R^qK]pԸcU:qĩ/,<jy/-KAҜCjRVB ĸ8֭Z\y-:ƭ/%<%VԸמZJj1n(.M5CΡ*q%2)1Rn<[OڧyiI5q/<1!-Ls!!璆˔d!KBykCqj5<B-nԇCXKμީu%kJKXm]81ԄC^K#u_-O1! <1qOZ8-6+qJKdRMy8qnyהV8u-SZqy)R8^uo1ʏQS~KXRSzgT~ZݳR6KKQǔ:(p?BX(HyL[C)LBߐ.kKg~C)<ZD1k?ycbD8~嬋OФqũ(GWRA䥏xjպκ<1.)bUJ" uմj5gڤ8l_Aż>R1oK[CZnj8쒶-uSd-Ky+68[ߐX/P֩d?-GJaR%/-k-lbA BZL~c^Ck_Ky?5ě|cHO2#W)+[RR8G_:yCKמH~P矐_:5H-)L4KFH[4w1Ω+k:.?u+Aquձ Ʃ)mKq)Ruǖ\SuMJמbڕ:-hKD-\uM{?L:ƱR뮬%K.!r+nn>KRFaK-KuŢZ Q+oNiN4?%גqIjKu B-.Iy|DbѶ6CjDոZR]T5V)UKK^;9ީnSַ޼Cu1hHEDK2|~ue%YI[Yhih~Z0Kp>^D5bvպIqX[l\EcqORu-}[[R,uLJ,yk|i q,tykTĻcִSip1BSUo k$uTֱ5h~+^uo:Ƶ??%-IBzR/J}y-bT:έj[c!,4RJqe)k;zY1>i%jrSc>qKXhqjtBgļQQN%ȏbcq:KyMuţ!pXQHqϼҋR,x:DKyVBXbǔϿCkPKP"x~Z!N)Zˎ1O-cCyJP8ġžĥ$TCA C[թĵm[mK!m!ck% q)bZP$kʟy5ZJ gJ\!u 8q0aJcRTlq8:!cuyǒj5/R-,AD%)Z bZ5o5hCZ[PlB1hr^1,SqNa9 6ypQjb-j{&q5!)I9^yc8V!*jCLc˪R^uIJRFТxҕV%jcZ<1uqF-lJw%yjKÌZ'ImKK1.~%.KZYk~>SC[?,V-H'cq~K:-B8ƭJ4T1HcZ5L[źc} k5 q1 rcViXuoҕ-?ka֖6(g*jԴ"-徕n?!zR-k]qyjucŴQ>Y>RB֕&|]YgSX_zqkJc؇Qn6qƠN-*m0 iZ1,ζV}<S5\I%b1(N-nK uKXbҗǜ85 IxO<\:Rŭ >ZϔcJ-e)$WS!ƸRY'y}KJ]b -N_y-y8}L)yKR2\~yG\BRB5\} -/)--LC:ƩSuԸ^JZؿ8i[ct8ZƼyjRғ^j)5︗=!un؇RAX1%XR K5mBqR\ָH.C)qZ;4'SB8Ja<:뤼1O-LBPqgKK^{CBǑ:RKNԗ:}= bTuR˳ZR^^_<\k~c-myԭg_&ASR(qyB qlt-ZĩgSu!ZkbSNj8-ljZSڵu:c! bإ8X%bu:5ZT:1-.[橩C}ccT)Kı,BqQ-^JTμג-hQ!K{Rǩŧ\oSuLJ$㌄a֔mMiuSn&Vq1K b_E>|aN%/b6ӋeB\PlFqm. Sm%gwRW)%c^N?>>jy i>1nBV.,q.6ֵ8qZ-k%?Saq/+1CjسR:cƺu9!1嵌qKZ>UO$>\jCX1.:]'1+%&X-jk[P }IB]d8VKu)8ڏ4[B\R]N<<맞jTĩ+qN-z5ϩGyh5K<YDiSSLq1PP[ƱT]zߠ!v?,B sW]~JЅ5y ~[Tޡ(S% qĬǏS*S ~qJ1[8B^~ZJJ^XTҗ^SK)0OΩiS嬅:K[έյLbԇ!Ƨ0qiZT?!O)Jcbϝq6E<ӭiԡǒԷ1GyjZ^zХ$֭o}).1:CBЅ-)ymcV%R]YTԎ%o<[HjbSqLZ5qҞq]RJ]a%-rk\bP%l%{% epuyi1HtXkc88-o$Zu/ZcxìGҷqMuSJz\wSd-8ֺԵkjRZ1n[ J\-lCP:x:mjB0ОļԥդQq) Q<\cKZ82t1\yyoRXcN?%ƩšR~yI[b Y.!qo5gV<ǜyƵq琔.QN8C,1nƼ\5z)]uPZЦuJc<Ր)ޥmy亇kb-%ؒjӊCK kbkV[[s{QƂ,pѣ,ÆA,1G%DC/Anuxݵ]M-丈1BLteG&J9^b7R֡ CKu1)y uymB^S\ziZXc),bڔR1=sSxp⡐]yP,2zM=k1ơo:]y=V1{3֡+n;8#ƭ%׎-֧]q[J[; {\JXf:REeo\q_x%JPbȍ8bc T[KZn_k-(KcMq8)xK>Bu%C5 BR ZZRiŹ&))-RiJEiqq8!KQgq}~kC\q,~ZBRzS>j -/Ir^GKRcBXϡIy&>Jĭ.؎]N1DiuJj~-Pu,bySXźM!?%nš+S1IS8}o1[d-Vǜiu֐՝ϡIZq?yԭ/6c%7ǚ㎶.ȥXmF-V.#اx)-|mIR-Gn>ZF)IRTҜ[Ͷn?K?jOj_#RYag{ŘpALAGYd9ŸXSpvKZ-yHcqyJjWЧiJKZ[yqơה!Tpf%LcTSR8]CԻ]S4)Kb5+Z\[:jfuN-TcSC8bZ!*qKpqHKjC]=V!ŵ:Tq漅Ѕ #@Ϩ> ÍTy(:]niJQ(ң uunTU4|%YI!,QKOoX1VӮgߜ~CDlb- ))T%OBʜ6 Iiyԝ~~Zbj)֟B1֩ǝ(v`QBR0XJ_%qJ ~XY,qj~)im)>qK!%%7\j^J%/>ڷVHqkCuז=b:󧘥<%cCT-K󰗜t%:<Kc}>ə#;0/NWk5 zT-kN* 1*|J1jCJԗӮ5h~uıLkV:Jf"ԧ<[Ldաq~B#$BC\<~SOpS\ui*uKStXWo8-y~ Gz1%CT%&J<-/ImԾJŶLq)iM-MJtG|ea.RQlmxGR86֥jC-O1%mj+Bq5~qlBOq>II-.[:%Nέ8yh)/% yCR暔b-PZy<Jqu/[[^[SĔ|Nzc|%K/:[)RRűαSZcp~uLuMD<򔥭/bPk) bVbV:3PRjB֛iyHGɅGJcVՋSVZT*y8!yF$%?)?$ꐉCҷSZt/RTSo-jmzXĔV!(R.1Hq/b^O+qJiYEqHSƘȋ41,G {iy*u[m-/_jP)%Zn6clQN88Ҍbqj5%RB1hq_p1([ ~yLcK>Z~y.by [O-k nm GP5>+Vu[:9%<8$~KthyGy_!)mky :Ô8pu!ձIu)~Z%hI[Y-$0 ~~K]K,}M[TǜS~.%mqlqѴ] KSS,)N u)twTuj4'IJV6Ǐ5!ukbZƝR*ϒ+"ZKX[i4IF yH|^y-bߒʚ8(_ZD5LcխBTkˆ5?}RC-.Zj}F_TtK]OҥJ} J$-似b8-<돢㮬m F1IBB~S!~~y-և)%TKR-M]C)!3k[ui>c-qQ(X˄?}m%_i+ZӋ[CR%*CRǒ8ԱִjO:bũJև7-}mZbECZKY>0۟@@c0bҢ\Bg85/cKqo-֠kZj^[l:}R]BcK>b~c[B y䔗\tº)1 [T=RǼ~ߵ)SVƺqcuԡ:!/) uN6q׭NRAojM0>^je SǚԵjZUBw5ڕ5K(oe8! y/q1JS!TYipqS8[X5)Gqך! &#mm6ib5TyFxZV[Vq-!n!\ J{u\RalGi%mcHӫu-I}NmվF ZOaHԢV D+e%)RZqgR[ؤ,)+5*?)J պ֨Iq0+ֻo5!:-+d?!8-SvyY-FSlq(ƊIkȵ4ŧn-.*)0un#kV-*%h(+-6Xե$1iyJYm>Fqe2qn mjrZ՞Sk )!C^BE>Ԛy%kS'R)ֆR?(uĭZXyŠ8ꐧ1|[%TJT[Zj6EaOSqBBżIZqu)qZZSjqNI7A伤bXjtD֥/<)qB5yæu1ǐה:! K1wq^_؍qOX\q%Iknp \.ZMSJqKjRS)זa^ws)}-1=#|֡)sԮ1.}cJ5[Z!VSijRַG%TV1my瘄:-NWX]_ǘV6Zk%%Ǟq SX%[Ky8!j]cc! 5!+-BV(|!)bړ F!4e3q^AMyKu88ﭫC[uXq}IB5ԥnR]$ֵ C[u1--njKTזpP<-גšqe,BCZΡ/! u:]Ai漆H84uhKBZJKuRT5ζCs)-B#KXckSfL?!?=:!ļi1)oJG^[!-T$q<:%ZEȑaC8L{ C[ڽBVy5Xq-JJjy !\CILkBT[Rk!.!+c\S}uKZi-q*ZKq$%*RbQꘇu1խHq5+cq}ı|y1J_ǔcζpu--Y+J!G)LI)žZμI5n%ujulKqθב)Ej(ԡIRšϸ:α ~[^c<ԗJű,Bcǝئ%L[ySIy+bR[[1 ?-jj~[:5Q1[ihȉ1亷U;JiXy7MTJEiF4l\mQ(!+bqŚc\k>:B}5!/5/[1)IKZ&VTgRP:~jZ(ukk!座]R:-!N%-)Z ZO8:MK K<\cu1NlKRڥ5[^q/:6PxJTZ#1j[ykR^klca8Ԝy.1y%KεIb!Hq|j:2q3=foYyh+lb<ͭ,c2_1JCPĸ-C%}~CMQpd|%R)~SK_K[F)ZOaǝSO:Z)%[%>TKkS)DSZޒ[-.k[~b~b JQNG jIkx2Xq)٣Lʲ!AH{RZ%(H-c[~R?8RJq/#owT.4V[kbL/5N15+cտ<:Vz)h\iV)伱Pqno)טm/#q[Tv-}nZKZ%ǐ1xSyƥbYMb/iZƸ$ZXlA yǛ㭗SO:cЯm,i+Z8o5.zD[:樢Є q.1ֱ?;^SSJV)Q~^cJKW_uRKu q._BN"29QOA/Zy?:Ĺ8cyQ#K$ط[KBCu 8]B|qS?%*Bڧ^b\j1.[α uq!NHK8q%<ǘ]o:VS8yn/țu>gqo%n8<Ժ1!IiN%Y.SS.!Kod5{ZZJy))(kXCϱ1KǞKRֱLZ:uX^kM1wQ$h,A1"Fo3t(0Ic(̈a"yQ$͸Eu!(uO)juZŭT<)-85fѮClykJ[Z?}Mtl2m5KnZXסm[:[JZן׏|Vu RПWCԶ8R\SR8kT%n%:;E%X1||iP"cXQ?F9վB_% k8Z"JZ"?3vHLjVZߔZRXⅬupҜkS!VjZpZ-)[ǒaN%V$)o4ha/)?5}Sy8(RBy (ήLEBߜSq*TS?)*5GH-KYhY߸ǥ?:$IJĚQo-HcR>%j[`mK<ƭkֹ]+8!KBBbߡsCj1j[֮Zxy)ISuKP[8⚳ΐ5cc).\yZijbCө}[8]u){RqK[^yQk+'q,MI RCyֵ5JSC:לn8yıMKBFqN8V꒥amw.bu(~yP{cKqyI.-kZ11iy}qœi'汌bZ%_CZp6|Q<-Ĕik%璦WBur_甶qO88y.}ï!)yXa<[ա1~~kKZЅ~F,id<Ԛ%nRb)]Ŭ]~~Q/%*B[1y.D/}c5SiY]j\c~ZB+jX꘤NKkϞ~} KH,[![>-\k4S?!y%.~:)!- ZbwR1i/%t%jaJI=,C1(S\BZ61:8JVaמ1%~ulviiy_SQ8qK $hT՝u%?5]j<[XKuo:ĵcC<- RIW+cJC~K~uN![qh★>C)ؕ%:]yOGԷ?%)>&R/ )+ϓZP>VYַZcTbߖq%Z yˇ[QJq]ueǽ:?!]B>JԶCIcoj~$-%:P֧$ԩ䩿yQȧV{ %hv):ROcRCšCqj۫x+5)lV(JTԭuOΥ+kb$ c4iY3,Х(IkQNb])b}$|hTϒVK|uk搥::N#R(}Ɣ??)N<߱ĥibh[zNj}u+QK焦3XTr%q C5Ժ<լ8鎩:uc3܋4Xթ^!ϭ*c]ct:R]kR j<ڗqJS>qqBJVc^Z٨R7gߟy jciY_8IdqN[]EΩNJSTQA8j[KuQZ|8R{ST%H~k8-^i~C?)J[Bʐ8KK0XVԦ5 F?8bp}%R0뿐8%%ĭH~b~:Đu_yob_1ujyKN-kVxո jIbSn.XYyűLxSi[b^<έob1cJyKy(JGԡ'v%֭N8 q\y:%b6Vj\j1Y"VWĺƥ~b[885N<뮭ymuo;JXV1)!kKK[)Lcby*bi9BЗ\S-X׍8e!3J8R|թTY Jk SVZ[!qšY!N 4G^%Q+ZK]߸ƭԸ>ևԸ ?11 R=Ɠim.EQ1[I'"yHLTN5!Ji So8PHyK bVKTDZ:[RcaZ滏5cJc5jߚ5QICg֤oq,cu.y~?! ~pm_?:cRR5ϼJkyiKϔ+R.,֔c1."M6J8iZ8ڴ5(y֫8cLJ&"8yi)cT%q-SqNy?!!o(m6[GLjRۉJxb_;o-ɌE6Ӈ蒚upq-3RSjZ<~{5y"[,X1-J]>J\qڇZKPq-4Kihݤ[LJ,aHS]/k5,S^bƺ<<ĭ!~\Z yqq JTyhqZJBP8jP88SQ!Sxı.5ߵ uϺ֥mu)k5jR]u]8ĥ!L1ǞYj-ƨ-u J>!iRS\ZI)KkbHAԵZZ>5ikqO3μ񨣉jw) Yg% cqա5,yT[C!V<)%J[j SBȈSKB8XcRĸqy]dڐj%%eD%<& J%8󮐇 BmKJŬZQjQu<,T0SijN1K_S -kS4mldRSkujkΥ([S$!--[JIvKue[OإX-K~CRֵ!թ)O<cBCԱrԼN7^BO-S:ZߔipK(ꒅI_ ǖ 1+RRRO~c~BXky;1|,嚷^ws8kS8ĥ5%:~-Î:j8^kXa SRšP:IuZzƱu֖VbQŵŞcTjZun.!mq;xq}MOh[J뮲Xҵ-\-15q."(Gƺ[!pu+yLqJjs!޹iVT!']Cpؔ fAic1IgèN8ĵ)ط҄%KuؗV5:%q7ՠb-e)+Cohiq*K,cSa亅1.)ZV-|>&"K[[SowKKP>NV8]uP yc_[NZiMK串_FHu*xj՘_B\))5yGm.R6\m,ujۯ?cuŵkRSyo){X}Ic %Sk*֒Wj%Zj?!i~-bGsxĩj[]R\Oز~kb9 ~b_[V)C'%K~Y*ZN%F~y1:N#~c%y/J?3B+8jk\s㮥oqa*J:%™Mc"ZutZd:\5mqĚq)!OCjZKBc!myyImKy5u,CZd5C!G~~Cyv_y.)O5kKƾagqbRش1/8S^kBƺBR%-AuƥXռ]S8ŸJKK{M ԡJ1 )jXּ:Jun! jT\y!T):Vbi/K1 kkqhcZ_UspƩjRZb!.Nĸź03"2FQ|ejV=ZZSUFyִ.}Zah%8 BR~?1ֵ)LZQL1KdJcבZ1 _֕-5t2[YOo(y֡~kSv-J~E-O:HMƝ[Rm1!ĭ)NԿ: ~ X1_B~> cYLG҆1խ&TJN<~҉8Xy*0mlPb [Jy!Kq*kyAmSSu,ƺy<q+SCw\uMOڥf?0Zǐy ӯP8qkkR1V!ֵ.8]b~]q y5]qSSέ.4:K:%N)R^N^a)y8cVin)'aN%l}<&޾򚷖tX GJR)KulunCVb׎ߚJUvPS)N1OJucJX\u?c!JAJykzO|ŔԺ8PCq_KZZ!~BqZ^;+y41n59-)ן!bc3GX[\qJb^ϛiZJ:iRё--םbTq)KM58%58%:%N-qդ֩ǔҧV-GXq y u˜YZuAB$$1i FXsyպ:5f<ĥn'%-.[uN%KwC^Rk8qTOTκǖ1.X/% R[Syp5ŵ%(% s31yLy=1+R!֡G(Z-]Vnrjk}OR^K_[uT߼b]q䱏R<%kq ))yĒ]tCaա:KZi&1Z$w"8Æ2OKX(:1NCZPu!Ƽ-yub:!թy8-%U!Iqj1kR<qIZPԵ XBqnIJ%|j^SZ5IuRRμ֭.Kj:!R1C!-vN!uq*cCc)1ŻbuŵCN:SO<%o-Թ#\BJK%j-%ǘCXx0ؤ:VcyG.) u-kKKb<]c5c\CcJ}yN EyǚIKyy׋y*CYJkjkKjJT1.%%jS:ה8ByX c!ԥ)Aq-BK\c<]B^SgR ΃ oA%*Ydvί?8j`ڭ`[ڛ清Kq_ST5yhT녰Z8)KR<>%BJZ<]wq'|1/%)D$ڦ1)&X[)\mjhOKiIq]GVq ġy.,&]yz5Hqx\K,u8ZR֥k KCΡHy[q,1Ե8R%!N%kqX!!Sq(1KB1uZSqit.8yR8^CVK])/5LuyԵb![%+B!8㉗Q琇qc[\cα)c+帒؄}+B\tթPS<--B%瘔1ŜYNHbLK8P!uRc]qN)iBZ(TqκĥyhS1:\{^B\cabTa+tԷ]kciQ)׋SZy!KZ%8]bqmgqbqJMgqo1׎1RPuƺP򔖬ڶ%buqy+JҴ:]-/1:RRP8☒VqK$8J^u0*Е5疒.ZR̤)NhvuXB!-k)lKDq*u8^Cv\)䘵:BkKb5d=!iI-My)c- RBq8ġy-:R( YN qcCR;ǔռmqqZ>)X,cbCKkPVuƭCuĵCZqL[)յ [4)Kq [C\CVc1]y8:D'BJ^bUmm)8]u:V%O-n: Bq5l1O4)9KZRq5婨qLy-H1u[N.Z]R-PP1q奉SJ ZKǍuTS BLJ^QBҥbbK:n:~Ʊj1 u5HJ8!q|]JLj(I/)nJ$8j[yָbԆu K!u~ZCyy53y5 bXZ- %ֱҐRšn:Sט5[%:זX%CԝOHcp8ִq֥qgZڦ%zbֱ50Z8QԩLbTM5ֱֺĬ1 y1VǝVPJ^rV)+SGO8␴Jש'|ZX>V5kqN[:BJ[έ8ך\yKkN<[ϵF) b{yLCRuq boV8ǝBqSj\J☪co[ե CB؄[j\Q琴:ZC-)o<J<kK%)աt% yj!NSY\1/%ǒs[%מ[ykR R1jcPBĺVl%Żռ-ΩS1խO8105ÍbKcZP JO)RjZ8!ĺĪԇSb1mcAJT^Yju. BB؄ǞuRSRS bSBn1Hc֥屮1JBXƸǔyHuDN^k~ [ SN.<]yKMqO) RZZS8q)CPkT3qOi>][JqKqH}bZC}/-R𧐧[Jݵb!mj^KPuKl\KyκIO:yb!X^Cu&)nck%6Z-cpǏ:ky&qpy_RTNcS8]kP%HB'qhqLJHjb؃PcJTyO%]Zơ jjΩ!jyP<[\QƼŵGJ!y tYmcRxR\cXǚ^yKqc)5ť,uZ-<-HpKx-y:XZ8-n؏5jKŽ5]!bךV8ǖCq^!o-qn2j:Sxԩ(y:ZBkmo-+RBRj1-umIGRBPǚ֧yƴ8Еl[KqKByÞbTԱ.1kjԲN!Ct8[Pyuj^RJJf-q1Yk:1KRǝKJw-u[^-Nз]B_[CPP-ļƺ)5oKCꔴ8iyXג1.!5B-5 S8K.ꚵ%(qJ^1K1My]JyU,KKkqםyiǖ-[C^JCϸƻ:Ck<)k!o-8^:qǒ1kZ\u–Sy.]}k}+RRX<8SuON:(%)[:הCSK\q%85 Rt8)Ccy/):[88瘶q815Hq՝cq/1PB cVCVR8מCCCV%O(JXX֭u.)5.\yiY!ӍbyQ%Қ֧T<}yֵ'O7[JSuMuזM[q[[>ı Sy1uk8֐!JڅPז!-$jV)ICqCkRLS1yjkC3qĸxHJZ^sCuo8ԥ%SB}֥%ĥyBӫbങ[JC:c(PTq cX5ǔ5ԐuAMq5[qƸμB18%*ךR! C8Zq8myRB˴)N!ԩ,RαCI cXO5ua Bg% JZVRc[qiqF8T$JC80^5Ky/:kX[ZbΩ-?5JV)8<Œd:-ƫpZY䩪;ӌySǖuĩzA%)nօ)_iuK/-: R: 8T8B5ĵ IMjB]qCKζuKKPA(Z⥬q t kk[.!lSZqեĸZ!֡ǞZ[Nd8b^ZLj]C-FC5-u)5kRj<5ƥiu(uy2ZJ^cۯ! qiu5.y qZ8ycu(K]} a-) QkulFnԱKjyenBy.%SBθ!ibPơ,jPΥ漗IkjלZjBؖ5qך[SP9liL;]tqNlî h# KĜ%)fT Çf6s8$礸G4-Q$8ӷOFm"4ENhpQFOq^E琧jRG۪crjceoިS=~[N:W<^9έhAdi,4J(͂4vH> ms˨4oSPť]qkB؇sC\s5y j]bkbvY-%IqRu=g0 3 ,gu\.uM%U% M! nJ2ЄA( _%NԏZZ'mHΗb4kڒq\eljҮ5Jb>vqǒ}nkR(qR1=]c{}mq/\aq9 K.4XamR6#z2T!ַqKR{x[uםJCߨR3,GR$4f%ƺÄc)ľֶkj\\ubXR')\qhƥ()vnqR)Ju%%]q1_Z5tIc`#ʄo`Ee0>VZVOWkcNs<1 Sǖ]\բS[UG^oޗY:uM[חg2ZjRXjش<ĭļJQO8bR<ָ}-r'PKVC\^1kqI.<-/5(s1yhk3-! [#1.bXĘ㸆ǐԴ8Z8h Bh(FםykZQuC–Co1!! iO! Z:O1 q WԸ%icR\JcCCZ#IyKk-%/!)֥BCPwR3OԹbS8n]CթIqÉjO)zJq1sqHkY%Xg/9%5jy8[zp!C1tϩ<גL[uk8ךRTkZڷa,\quVun1MRZRֺ]y\\Kk r^k1VB]BmTKiyƩ-Bք^[\:CZ~Xc!wZVHro%hQObЧ~iTJLQΕ4Fk\3yC-R)utגVO5{SuÈ[tZ:Ǚǝq:㍶%ǔq_iź\<#%<1B'Ab@8abzիJVR:K[x$溇c!R.^CxPǚ^uXM1[8t~[%n1gXgWj3qjC|-/1MjYť5y jqHS~:ԣ8ꐗRݥƜyJX1C)Lj)<Ƽc!ϥ+Bbcq?nkpCjCZCG8ԗMlSK IkK[ָ:%IZV]uqKKCBCju)o)ZC:ǐ qR/%k}Ժ(%e!o%q-RgyXC7y5q8[QZ#Jkud^y,ylqNKZ%; qqϨ›/:8[պ^us\q%\PQF"0c5ǜcXtqky-漶-q [b)KJ-)?Kտ:IN)֐qRք:ЋCVJy%1o'j[!hc!.X$b%1 Aг5-aO%ƱJZqb[h[R]u֘uqSckSзcqZRK!%S)SSKq屦J]qաƔS8K/KjRR~>inSkkVNa1+%KRNI*zX%+)*cT!vj!8!-1 XRyyԱ%BRS.1)nR\jRRڢ嘆:]b [^jJSjTBSkBҦ1o!\y,jjucbkR:%ĵjKT50\u瘶)%Yu y4<B\c\N!%O%MqJkZX7[ZqkTSlk[]jƸbnB>jԖubx8ӇPĭzq;8=5q:1).<%TSbqq ƸGK\85E9bב-K7Ҙ^y ]Sy q1)t- j-(8V؃%MZRuHJKu!U槪Su)=kԵǟCJSx1+ByrqëZ)\bqCqHSo1uԡhJy}8ŵkqfh1y%)y#YlSi:Xy-n:.cS]u/8CZũZ8]ޭrjIOWuuzNJֵumj}+[!KqS]kR}X]RZө"jqı5氷YRNה!R]kSZ!quCRZmP-Nӯ-Ÿ8W KטSq1 uiBCR ]Z]qcJۋ%6jպxꎥjN!5 oMCPV8㮳.C-Ow<8y $jJ#yĹ:ִ[帞&ێQm^-'KִJ-_c+xme-B)LBaBϥIV}d=4RYu%;;Ruמtc9 mi̢̭8xRǫqղ^q b҅'0;-kL_q+!םBXuN%׊M-qSSSql8/]v\cOtN1f#^T}V&:Ku vv;;4:5EWDH#ʲp΃YY8vQJ !`,X/@cWXa8ayJ>Z?(BZAL9̹E %4!xB::Qt]pTs]dYjes$8N^5w?!Pꬬ\=6 YclYSɐ#]45BTPJ%( v) g-J&?l33V6x>V8y 7Ze8~S/mvrȬWk=|#$ I+KsEFHģ)z-u꼼tܤ3m"uh* Jn;@^-؏b+W:~'i7orm*; kp8@wXM˔ G> k_nh! eYV<J`X!N>`8Қ RɈ$M;ʲ5*8!Gq%qZe<+ɲ kAkVL5[xN*LHE+!<$esqgR ޓ QBi6w:t;G^-˒$/:]uzSұ%tEXtdate:create2013-09-27T16:29:46+02:00`X %tEXtdate:modify2013-09-27T16:29:46+02:00IENDB`v_sim-3.8.0/lib/plug-ins/fpcrystal/fpcrystal.cpp000066400000000000000000000253231370110300500216600ustar00rootroot00000000000000#include "fpcrystal.h" #include #include #include #include extern "C" { gboolean crystalfpInit(); const char* crystalfpGet_description(); const char* crystalfpGet_authors(); const char* crystalfpGet_icon(); } #define CRYSTALFP_DESCRIPTION _("" \ "a wrapper around CrystalFp.") #define CRYSTALFP_AUTHORS _("Caliste Damien:\n wrapper.") /* Local variables. */ static gchar *iconPath; /* Local methods. */ /* Required methods for a loadable module. */ gboolean crystalfpInit() { DBG_fprintf(stderr, "Crystalfp: loading plug-in 'crystalfp'...\n"); iconPath = g_build_filename(V_SIM_PIXMAPS_DIR, "crystalfp.png", NULL); return TRUE; } const char* crystalfpGet_description() { return CRYSTALFP_DESCRIPTION; } const char* crystalfpGet_authors() { return CRYSTALFP_AUTHORS; } const char* crystalfpGet_icon() { return (char*)iconPath; } /** * VisuCrystalfpClass: * @parent: the parent class; * * A short way to identify #_VisuCrystalfpClass structure. * * Since: 3.8 */ /** * VisuCrystalfp: * * An opaque structure. * * Since: 3.8 */ /** * VisuCrystalfpPrivate: * * Private fields for #VisuCrystalfp objects. * * Since: 3.8 */ struct _VisuCrystalfpPrivate { gboolean dispose_has_run; gboolean fp_are_ready; VisuCrystalfpDistanceMethod distMeth; GHashTable *structures; cfp::CrystalFp *cfp; }; /* Local routines. */ static void visu_crystalfp_dispose (GObject* obj); static void visu_crystalfp_finalize(GObject* obj); G_DEFINE_TYPE(VisuCrystalfp, visu_crystalfp, G_TYPE_OBJECT) static void visu_crystalfp_class_init(VisuCrystalfpClass *klass) { DBG_fprintf(stderr, "Visu Crystalfp: creating the class of the object.\n"); /* DBG_fprintf(stderr, " - adding new signals ;\n"); */ /* Connect the overloading methods. */ G_OBJECT_CLASS(klass)->dispose = visu_crystalfp_dispose; G_OBJECT_CLASS(klass)->finalize = visu_crystalfp_finalize; g_type_class_add_private(klass, sizeof(VisuCrystalfpPrivate)); } static void visu_crystalfp_init(VisuCrystalfp *obj) { DBG_fprintf(stderr, "Visu Crystalfp: initializing a new object (%p).\n", (gpointer)obj); obj->priv = G_TYPE_INSTANCE_GET_PRIVATE(obj, VISU_TYPE_CRYSTALFP, VisuCrystalfpPrivate); obj->priv->dispose_has_run = FALSE; obj->priv->fp_are_ready = FALSE; obj->priv->cfp = new cfp::CrystalFp(2); obj->priv->cfp->setFingerprintMethod(VISU_CRYSTALFP_PER_ELEMENT_DIFFRACTION); obj->priv->cfp->setDistanceMethod(VISU_CRYSTALFP_DISTANCE_COSINE); obj->priv->structures = g_hash_table_new_full(g_direct_hash, g_direct_equal, g_object_unref, NULL); obj->priv->distMeth = VISU_CRYSTALFP_DISTANCE_COSINE; } /* This method can be called several times. It should unref all of its reference to GObjects. */ static void visu_crystalfp_dispose(GObject* obj) { VisuCrystalfp *fp; DBG_fprintf(stderr, "Visu Crystalfp: dispose object %p.\n", (gpointer)obj); fp = VISU_CRYSTALFP(obj); if (fp->priv->dispose_has_run) return; fp->priv->dispose_has_run = TRUE; /* Chain up to the parent class */ G_OBJECT_CLASS(visu_crystalfp_parent_class)->dispose(obj); } /* This method is called once only. */ static void visu_crystalfp_finalize(GObject* obj) { VisuCrystalfpPrivate *fp; g_return_if_fail(obj); DBG_fprintf(stderr, "Visu Crystalfp: finalize object %p.\n", (gpointer)obj); fp = VISU_CRYSTALFP(obj)->priv; delete(fp->cfp); g_hash_table_destroy(fp->structures); /* Chain up to the parent class */ DBG_fprintf(stderr, "Visu Crystalfp: chain to parent.\n"); G_OBJECT_CLASS(visu_crystalfp_parent_class)->finalize(obj); DBG_fprintf(stderr, "Visu Crystalfp: freeing ... OK.\n"); } /** * visu_crystalfp_new: * * * Since: 3.8 * * Returns: a pointer to the VisuGlExt it created or * NULL otherwise. */ VisuCrystalfp* visu_crystalfp_new(void) { VisuCrystalfp *fp; fp = VISU_CRYSTALFP(g_object_new(VISU_TYPE_CRYSTALFP, NULL)); return fp; } static void computeFingerprints(VisuCrystalfp *fp) { g_return_if_fail(VISU_IS_CRYSTALFP(fp)); if (fp->priv->cfp->getCutoffDistance() == 0.f) fp->priv->cfp->setCutoffDistance(fp->priv->cfp->computeCutoffDistance()); fp->priv->cfp->computeFingerprints(); fp->priv->fp_are_ready = TRUE; } /** * visu_crystalfp_addStructure: * @data: a #VisuData object. * * * Since: 3.8 */ void visu_crystalfp_addStructure(VisuCrystalfp *fp, VisuData *data) { VisuNodeArrayIter iter; guint i; float *aCoords; unsigned int *aZ, *zEle; float cell[16]; double matrix[3][3]; gdouble energy; guint id; g_return_if_fail(VISU_IS_CRYSTALFP(fp)); visu_node_array_iter_new(VISU_NODE_ARRAY(data), &iter); zEle = (unsigned int*)g_malloc0(sizeof(unsigned int) * iter.nElements); for (visu_node_array_iterStart(VISU_NODE_ARRAY(data), &iter); iter.node; visu_node_array_iterNextElement(VISU_NODE_ARRAY(data), &iter, TRUE)) if (!tool_physic_getZFromSymbol((int*)zEle + iter.iElement, (float*)0, (gchar*)iter.element->name)) g_warning("No such element '%s'.", iter.element->name); aCoords = (float*)g_malloc(sizeof(float) * 3 * iter.nAllStoredNodes); aZ = (unsigned int*)g_malloc0(sizeof(unsigned int) * iter.nAllStoredNodes); for (visu_node_array_iterStart(VISU_NODE_ARRAY(data), &iter), i = 0; iter.node; visu_node_array_iterNext(VISU_NODE_ARRAY(data), &iter), i += 1) { visu_data_getNodePosition(data, iter.node, aCoords + 3 * i); aZ[i] = zEle[iter.iElement]; } g_free(zEle); visu_box_getCellMatrix(visu_boxed_getBox(VISU_BOXED(data)), matrix); cell[ 0] = matrix[0][0]; cell[ 1] = matrix[0][1]; cell[ 2] = matrix[0][2]; cell[ 3] = 0.f; cell[ 4] = matrix[1][0]; cell[ 5] = matrix[1][1]; cell[ 6] = matrix[1][2]; cell[ 7] = 0.f; cell[ 8] = matrix[2][0]; cell[ 9] = matrix[2][1]; cell[10] = matrix[2][2]; cell[11] = 0.f; cell[12] = 0.f; cell[13] = 0.f; cell[14] = 0.f; cell[15] = 1.f; g_object_get(G_OBJECT(data), "totalEnergy", &energy, NULL); id = g_hash_table_size(fp->priv->structures) + 1; fp->priv->cfp->addStructure(id, iter.nAllStoredNodes, aCoords, aZ, cell, (energy != G_MAXFLOAT), energy, FALSE); g_free(aCoords); g_free(aZ); if (visu_box_getBoundary(visu_boxed_getBox(VISU_BOXED(data))) == VISU_BOX_FREE) fp->priv->cfp->setNanoclusterStructureType(); g_object_ref(data); g_hash_table_insert(fp->priv->structures, data, GINT_TO_POINTER(id)); fp->priv->fp_are_ready = FALSE; } float visu_crystalfp_computeCutoffDistance(VisuCrystalfp *fp, float margin) { g_return_val_if_fail(VISU_IS_CRYSTALFP(fp), -1.f); if (margin > 0.f) return fp->priv->cfp->computeCutoffDistance(margin); else return fp->priv->cfp->computeCutoffDistance(); } /** * visu_crystalfp_getFingerprint: * @fp: * @data: * * * * Since: 3.8 * * Returns: (transfer full) (element-type float): **/ GArray* visu_crystalfp_getFingerprint(VisuCrystalfp *fp, VisuData *data) { size_t id; guint nSections, secLength; GArray *arr; g_return_val_if_fail(VISU_IS_CRYSTALFP(fp), (GArray*)0); id = GPOINTER_TO_INT(g_hash_table_lookup(fp->priv->structures, data)); if (!id) { visu_crystalfp_addStructure(fp, data); id = GPOINTER_TO_INT(g_hash_table_lookup(fp->priv->structures, data)); } if (!fp->priv->fp_are_ready) computeFingerprints(fp); nSections = fp->priv->cfp->getFingerprintNumSections(); secLength = fp->priv->cfp->getFingerprintSectionLen(); arr = g_array_sized_new(FALSE, FALSE, sizeof(gfloat), nSections * secLength); g_array_set_size(arr, nSections * secLength); memcpy(arr->data, fp->priv->cfp->getFingerprint(id - 1), sizeof(gfloat) * nSections * secLength); return arr; } static void computeDistances(VisuCrystalfp *fp, VisuCrystalfpDistanceMethod meth) { g_return_if_fail(VISU_IS_CRYSTALFP(fp)); if (!fp->priv->fp_are_ready) computeFingerprints(fp); if (fp->priv->distMeth != meth) { fp->priv->cfp->setDistanceMethod(meth); fp->priv->distMeth = meth; fp->priv->cfp->computeDistanceMatrix(); } if (!fp->priv->cfp->hasDistanceMatrix()) fp->priv->cfp->computeDistanceMatrix(); } float visu_crystalfp_getDistance(VisuCrystalfp *fp, VisuData *data1, VisuData *data2, VisuCrystalfpDistanceMethod meth) { size_t id1, id2; g_return_val_if_fail(VISU_IS_CRYSTALFP(fp), -1.f); id1 = GPOINTER_TO_INT(g_hash_table_lookup(fp->priv->structures, data1)); id2 = GPOINTER_TO_INT(g_hash_table_lookup(fp->priv->structures, data2)); if (!id1 || !id2) { g_warning("Unregistered structures."); return -1.f; } computeDistances(fp, meth); return fp->priv->cfp->getDistance(id1 - 1, id2 - 1); } #include /** * visu_crystalfp_get2DPlot: * @fp: * * * * Returns: (transfer full) (element-type VisuCrystalfp2DPlot): **/ GArray* visu_crystalfp_get2DPlot(VisuCrystalfp *fp, guint retries, guint maxIter, float min_energy, float timestep) { cfp::CrystalFpScatterplot plot; size_t s; guint i, j; float *coords, *vals, *vals_p, *vals_s, energy; GArray *arr; VisuCrystalfp2DPlot plt; g_return_val_if_fail(VISU_IS_CRYSTALFP(fp), (GArray*)0); computeDistances(fp, fp->priv->distMeth); s = plot.initScatterplot(fp->priv->cfp); coords = (float*)g_malloc(sizeof(float) * s * 2); vals = (float*)g_malloc(sizeof(float) * s); vals_p = (float*)g_malloc(sizeof(float) * s); vals_s = (float*)g_malloc(sizeof(float) * s); for (i = 0; i < retries; i++) { for (j = 0; j < maxIter; j++) { energy = plot.stepScatterplot(timestep); fprintf(stderr, "%g\n", energy); // plot.getPoints(coords); // plot.getValues(vals, cfp::CrystalFpScatterplot::VAL_TOTAL_ENERGY); if (energy < min_energy) break; } plot.perturbPositions(); // plot.getPoints(coords); // plot.getValues(vals, cfp::CrystalFpScatterplot::VAL_TOTAL_ENERGY); } plot.getPoints(coords); plot.getValues(vals, cfp::CrystalFpScatterplot::VAL_TOTAL_ENERGY); plot.getValues(vals_p, cfp::CrystalFpScatterplot::VAL_PER_ATOM_ENERGY); plot.getValues(vals_s, cfp::CrystalFpScatterplot::VAL_STRESS); arr = g_array_sized_new(FALSE, FALSE, sizeof(VisuCrystalfp2DPlot), s); for (i = 0; i < s; i++) { plt.x = coords[i * 2 + 0]; plt.y = coords[i * 2 + 1]; plt.totalEnergy = vals[i]; plt.perAtEnergy = vals_p[i]; plt.stress = vals_s[i]; g_array_insert_vals(arr, i, &plt, 1); } g_free(coords); g_free(vals); g_free(vals_p); g_free(vals_s); return arr; } v_sim-3.8.0/lib/plug-ins/fpcrystal/fpcrystal.h000066400000000000000000000060171370110300500213240ustar00rootroot00000000000000#include #include G_BEGIN_DECLS /** * VISU_TYPE_CRYSTALFP: * * return the type of #VisuCrystalfp. * * Since: 3.8 */ #define VISU_TYPE_CRYSTALFP (visu_crystalfp_get_type ()) /** * VISU_CRYSTALFP: * @obj: a #GObject to cast. * * Cast the given @obj into #VisuCrystalfp type. * * Since: 3.8 */ #define VISU_CRYSTALFP(obj) (G_TYPE_CHECK_INSTANCE_CAST(obj, VISU_TYPE_CRYSTALFP, VisuCrystalfp)) /** * VISU_CRYSTALFP_CLASS: * @klass: a #GObjectClass to cast. * * Cast the given @klass into #VisuCrystalfpClass. * * Since: 3.8 */ #define VISU_CRYSTALFP_CLASS(klass) (G_TYPE_CHECK_CLASS_CAST(klass, VISU_TYPE_CRYSTALFP, VisuCrystalfpClass)) /** * VISU_IS_CRYSTALFP: * @obj: a #GObject to test. * * Test if the given @ogj is of the type of #VisuCrystalfp object. * * Since: 3.8 */ #define VISU_IS_CRYSTALFP(obj) (G_TYPE_CHECK_INSTANCE_TYPE(obj, VISU_TYPE_CRYSTALFP)) /** * VISU_IS_CRYSTALFP_CLASS: * @klass: a #GObjectClass to test. * * Test if the given @klass is of the type of #VisuCrystalfpClass class. * * Since: 3.8 */ #define VISU_IS_CRYSTALFP_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE(klass, VISU_TYPE_CRYSTALFP)) /** * VISU_CRYSTALFP_GET_CLASS: * @obj: a #GObject to get the class of. * * It returns the class of the given @obj. * * Since: 3.8 */ #define VISU_CRYSTALFP_GET_CLASS(obj) (G_TYPE_INSTANCE_GET_CLASS(obj, VISU_TYPE_CRYSTALFP, VisuCrystalfpClass)) typedef struct _VisuCrystalfp VisuCrystalfp; typedef struct _VisuCrystalfpPrivate VisuCrystalfpPrivate; typedef struct _VisuCrystalfpClass VisuCrystalfpClass; struct _VisuCrystalfp { GObject parent; VisuCrystalfpPrivate *priv; }; struct _VisuCrystalfpClass { GObjectClass parent; }; typedef enum { VISU_CRYSTALFP_PER_ELEMENT_DIFFRACTION } VisuCrystalfpMethod; typedef enum { VISU_CRYSTALFP_DISTANCE_COSINE, VISU_CRYSTALFP_DISTANCE_EUCLIDEAN, VISU_CRYSTALFP_DISTANCE_MINKOWSKI_ONE_THIRD } VisuCrystalfpDistanceMethod; /** * VisuCrystalfp2DPlot: * @x: * @y: * @totalEnergy: * @perAtEnergy: * @stress: * * Since: 3.8 */ typedef struct _VisuCrystalfp2DPlot VisuCrystalfp2DPlot; struct _VisuCrystalfp2DPlot { float x, y; float totalEnergy, perAtEnergy, stress; }; /** * visu_crystalfp_get_type: * * This method returns the type of #VisuCrystalfp, use * VISU_TYPE_CRYSTALFP instead. * * Since: 3.8 * * Returns: the type of #VisuCrystalfp. */ GType visu_crystalfp_get_type(void); VisuCrystalfp* visu_crystalfp_new(); void visu_crystalfp_addStructure(VisuCrystalfp *fp, VisuData *data); float visu_crystalfp_computeCutoffDistance(VisuCrystalfp *fp, float margin); GArray* visu_crystalfp_getFingerprint(VisuCrystalfp *fp, VisuData *data); float visu_crystalfp_getDistance(VisuCrystalfp *fp, VisuData *data1, VisuData *data2, VisuCrystalfpDistanceMethod meth); GArray* visu_crystalfp_get2DPlot(VisuCrystalfp *fp, guint retries, guint maxIter, float min_energy, float timestep); G_END_DECLS v_sim-3.8.0/lib/plug-ins/msym/000077500000000000000000000000001370110300500161165ustar00rootroot00000000000000v_sim-3.8.0/lib/plug-ins/msym/Makefile.am000066400000000000000000000020731370110300500201540ustar00rootroot00000000000000## Process this file with automake to produce Makefile.in vpath %.h $(top_srcdir)/src if PLATFORM_WIN32 cflagWin = -mms-bitfields -mno-cygwin endif if BUILTIN_MSYM EXTRA_libplugmsym_la_DEPENDENCIES = builtin/libmsym.a BUILTIN_EXPORTS = builtin/msym_EXPORTS.h endif libplugmsym_la_SOURCES = msym.c sym.h sym.c libplugmsym_la_LIBADD = $(top_builddir)/src/libv_sim-3.la \ @GLIB_LIBS@ @MSYM_LIBS@ libplugmsym_la_LDFLAGS = -module @EXTRA_LDFLAGS@ -version-info $(lib_v_sim_version) if HAVE_MSYM MSYM_LIB = libplugmsym.la MSYM_PIX = msym.png endif v_simplugins_LTLIBRARIES = $(MSYM_LIB) AM_CPPFLAGS = \ -I$(top_srcdir)/src \ @MSYM_CPPFLAGS@ \ @GLIB_CFLAGS@ \ @GTKS_CFLAGS@ AM_CFLAGS = $(cflagWin) v_simpixmaps_DATA = $(MSYM_PIX) EXTRA_DIST = msym.png CLEANFILES = log clean-local: rm -rf builtin msym.c sym.c: $(BUILTIN_EXPORTS) builtin/libmsym.a: builtin/Makefile cd builtin && make builtin/msym_EXPORTS.h: builtin/Makefile builtin/Makefile: $(srcdir)/libmsym/CMakeLists.txt if ! test -d builtin; then mkdir builtin; fi && cd builtin && cmake ../$(srcdir)/libmsym v_sim-3.8.0/lib/plug-ins/msym/libmsym/000077500000000000000000000000001370110300500175725ustar00rootroot00000000000000v_sim-3.8.0/lib/plug-ins/msym/libmsym/CMakeLists.txt000066400000000000000000000100361370110300500223320ustar00rootroot00000000000000cmake_minimum_required (VERSION 2.8.11) #project(libmsym C) # unfortunately GenerateExportHeader doesn't support C projects, which sort of makes this project reqire c++ =/ project(libmsym) option(MSYM_BUILD_EXAMPLES "Build example executables" OFF) option(MSYM_BUILD_PYTHON "Build python binding" OFF) include (GenerateExportHeader) set(LIBMSYM_MAJOR_VERSION 0) set(LIBMSYM_MINOR_VERSION 2) set(LIBMSYM_PATCH_VERSION 4) set(LIBMSYM_VERSION ${LIBMSYM_MAJOR_VERSION}.${LIBMSYM_MINOR_VERSION}.${LIBMSYM_PATCH_VERSION}) set(CMAKE_POSITION_INDEPENDENT_CODE ON) set(INSTALL_LIB_DIR lib CACHE PATH "Installation directory for msym library") set(INSTALL_INCLUDE_DIR include CACHE PATH "Installation directory for header files") if(WIN32 AND NOT CYGWIN) set(DEF_INSTALL_CMAKE_DIR CMake) else() set(DEF_INSTALL_CMAKE_DIR lib/cmake/libmsym) endif() set(INSTALL_CMAKE_DIR ${DEF_INSTALL_CMAKE_DIR} CACHE PATH "Installation directory for CMake files") foreach(p LIB BIN INCLUDE CMAKE) set(var INSTALL_${p}_DIR) if(NOT IS_ABSOLUTE "${${var}}") set(${var} "${CMAKE_INSTALL_PREFIX}/${${var}}") endif() endforeach() include_directories("${PROJECT_SOURCE_DIR}") file (GLOB source src/*.c) add_library (msym ${source}) if (BUILD_SHARED_LIBS) set_target_properties(msym PROPERTIES POSITION_INDEPENDENT_CODE TRUE C_VISIBILITY_PRESET hidden VISIBILITY_INLINES_HIDDEN 1) else() set_target_properties(msym PROPERTIES COMPILE_FLAGS -DMSYM_EXPORTS_BUILT_AS_STATIC) endif () include_directories("${PROJECT_BINARY_DIR}") set_target_properties(msym PROPERTIES VERSION ${LIBMSYM_VERSION}) set_target_properties(msym PROPERTIES SOVERSION ${LIBMSYM_MAJOR_VERSION}.${LIBMSYM_MINOR_VERSION}) generate_export_header(msym BASE_NAME msym EXPORT_MACRO_NAME MSYM_EXPORT EXPORT_FILE_NAME msym_EXPORTS.h STATIC_DEFINE MSYM_EXPORTS_BUILT_AS_STATIC) set (CMAKE_C_FLAGS "${CMAKE_C_FLAGS} -std=c99") #set_target_properties (msym PROPERTIES # C_STANDARD 99 # C_STANDARD_REQUIRED ON) #set (CMAKE_C_FLAGS "${CMAKE_C_FLAGS} -std=c99 -flto") #set (CMAKE_EXE_LINKER_FLAGS "${CMAKE_EXE_LINKER_FLAGS} -flto" ) #set (CMAKE_C_FLAGS "${CMAKE_C_FLAGS} -std=c99 -fsanitize=address -fno-omit-frame-pointer") #set (CMAKE_C_FLAGS "${CMAKE_C_FLAGS} -std=c99 -fsanitize=memory -fno-omit-frame-pointer -fsanitize-memory-track-origins") set (CMAKE_C_FLAGS_DEBUG "${CMAKE_C_FLAGS_DEBUG} -Wall -DLIBMSYM_DEBUG") set_target_properties(msym PROPERTIES PUBLIC_HEADER "src/msym.h;src/msym_error.h") if(UNIX) target_link_libraries(msym m) endif(UNIX) export(TARGETS msym FILE "${PROJECT_BINARY_DIR}/libmsymTargets.cmake") export(PACKAGE libmsym) file(RELATIVE_PATH REL_INCLUDE_DIR "${INSTALL_CMAKE_DIR}" "${INSTALL_INCLUDE_DIR}") set(CONF_INCLUDE_DIRS "${PROJECT_SOURCE_DIR}" "${PROJECT_BINARY_DIR}") configure_file(libmsymConfig.cmake.in "${PROJECT_BINARY_DIR}/libmsymConfig.cmake" @ONLY) set(CONF_INCLUDE_DIRS "\${LIBMSYM_CMAKE_DIR}/${REL_INCLUDE_DIR}") configure_file(libmsymConfig.cmake.in "${PROJECT_BINARY_DIR}${CMAKE_FILES_DIRECTORY}/libmsymConfig.cmake" @ONLY) configure_file(libmsymConfigVersion.cmake.in "${PROJECT_BINARY_DIR}/libmsymConfigVersion.cmake" @ONLY) install(FILES "${PROJECT_BINARY_DIR}${CMAKE_FILES_DIRECTORY}/libmsymConfig.cmake" "${PROJECT_BINARY_DIR}/libmsymConfigVersion.cmake" DESTINATION "${INSTALL_CMAKE_DIR}") # EXPORT HEADER install(FILES "${PROJECT_BINARY_DIR}/msym_EXPORTS.h" DESTINATION "${INSTALL_INCLUDE_DIR}/libmsym") install(TARGETS msym EXPORT libmsymTargets RUNTIME DESTINATION "${INSTALL_BIN_DIR}" ARCHIVE DESTINATION "${INSTALL_LIB_DIR}" PUBLIC_HEADER DESTINATION "${INSTALL_INCLUDE_DIR}/libmsym" LIBRARY DESTINATION "${INSTALL_LIB_DIR}" ) install(EXPORT libmsymTargets DESTINATION "${INSTALL_CMAKE_DIR}") if(MSYM_BUILD_EXAMPLES) add_subdirectory(examples) endif() if(MSYM_BUILD_PYTHON) if(BUILD_SHARED_LIBS) add_subdirectory(bindings/python) else() message(SEND_ERROR "python requires libmsym to be built as a shared library, use -DBUILD_SHARED_LIBS:BOOL=ON") endif() endif() v_sim-3.8.0/lib/plug-ins/msym/libmsym/LICENSE000066400000000000000000000020741370110300500206020ustar00rootroot00000000000000The MIT License (MIT) Copyright (c) 2015 Marcus Johansson Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions: The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software. THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. v_sim-3.8.0/lib/plug-ins/msym/libmsym/README.md000066400000000000000000000040201370110300500210450ustar00rootroot00000000000000# libmsym v0.2.2 libmsym is a C library dealing with point group symmetry in molecules. ## molecules Determine, symmetrize and generate molecules of any point group as well determine/select subgroups. Get symmetrically equivalent elements and symmetrize translation of any any element in a molecule. ## character tables Generate character tables for any point group (complex characters form reducible representations) ## wave functions Generate SALCs of real spherical harmonics with any angular momentum for point groups with real characters (Ci, Cs, Cnv, Dn, Dnh, Dnd, Td, O, Oh, I and Ih), as well as symmetrize orbitals, determine partner functions etc. ## installing ```shell git clone https://github.com/mcodev31/libmsym.git cd libmsym mkdir build cd build # build as shared library; build examples (built in ./examples, not installed) cmake -DBUILD_SHARED_LIBS:BOOL=ON -DMSYM_BUILD_EXAMPLES:BOOL=ON ../. make # sudo only required if installing in directory not owned by user # use -DCMAKE_INSTALL_PREFIX:PATH= to change sudo make install # run examples ./examples/msym_example ./examples/msym_tex D13h D13h.tex ``` ### python The libmsym module requires python 3. If you have installed the libmsym library in a location that can be found by your loader (e.g. ldconfig): ```shell cd ../bindings/python # install libmsym module in user site python setup.py install --user # run example python ./examples/msympy_example.py ``` If you want to install libmsym in a custom directory, the easies way it to use cmake: ```shell # install libmsym shared library in $HOME/lib and the python module in the user site cmake -DMSYM_BUILD_PYTHON:BOOL=ON -DBUILD_SHARED_LIBS:BOOL=ON -DCMAKE_INSTALL_PREFIX=$HOME/lib -DMSYM_PYTHON_INSTALL_OPTS=--user ../. make install # run example python ../bindings/python/examples/msympy_example.py ``` methods dealing with SALCs etc. require numpy to be installed ## notes v0.1.0 is not compatible with v0.2.0 v_sim-3.8.0/lib/plug-ins/msym/libmsym/bindings/000077500000000000000000000000001370110300500213675ustar00rootroot00000000000000v_sim-3.8.0/lib/plug-ins/msym/libmsym/bindings/python/000077500000000000000000000000001370110300500227105ustar00rootroot00000000000000v_sim-3.8.0/lib/plug-ins/msym/libmsym/bindings/python/.gitignore000066400000000000000000000000301370110300500246710ustar00rootroot00000000000000/build *.swp .DS_Store v_sim-3.8.0/lib/plug-ins/msym/libmsym/bindings/python/CMakeLists.txt000066400000000000000000000035051370110300500254530ustar00rootroot00000000000000cmake_minimum_required (VERSION 2.8.11) find_program(PYTHON "python") if (PYTHON) set(MSYM_PYTHON_PACKAGE_DIR "${CMAKE_CURRENT_BINARY_DIR}/libmsym") set(MSYM_PYTHON_SETUP_IN "${CMAKE_CURRENT_SOURCE_DIR}/cmake/setup.py.in") set(MSYM_PYTHON_INIT_C_IN "${CMAKE_CURRENT_SOURCE_DIR}/cmake/__init__.py.in") set(MSYM_PYTHON_CODE_IN "${CMAKE_CURRENT_SOURCE_DIR}/libmsym/libmsym.py") set(MSYM_PYTHON_SETUP "${CMAKE_CURRENT_BINARY_DIR}/setup.py") set(MSYM_PYTHON_INIT_G_IN "${CMAKE_CURRENT_BINARY_DIR}/__init__.py.in") set(MSYM_PYTHON_INIT "${MSYM_PYTHON_PACKAGE_DIR}/__init__.py") set(MSYM_PYTHON_CODE "${MSYM_PYTHON_PACKAGE_DIR}/libmsym.py") set(MSYM_PYTHON_STAMP "${CMAKE_CURRENT_BINARY_DIR}/build/timestamp") set(MSYM_PYTHON_INSTALL_OPTS "" CACHE STRING "install options for setup.py") # There simply has to be a better way to get distutils to install a shared library # from a custom path without overriding all of the command classes, # get cmake to tell me where the library is located in a less convoluted way # or get python to use other means than ldconfig to load shared libraries... this is ridiculous configure_file(${MSYM_PYTHON_SETUP_IN} ${MSYM_PYTHON_SETUP}) configure_file(${MSYM_PYTHON_INIT_C_IN} ${MSYM_PYTHON_INIT_G_IN}) file(GENERATE OUTPUT ${MSYM_PYTHON_INIT} INPUT ${MSYM_PYTHON_INIT_G_IN}) file(COPY ${MSYM_PYTHON_CODE_IN} DESTINATION ${MSYM_PYTHON_PACKAGE_DIR}) add_custom_command(OUTPUT ${MSYM_PYTHON_STAMP} COMMAND ${PYTHON} ${MSYM_PYTHON_SETUP} build COMMAND ${CMAKE_COMMAND} -E touch ${MSYM_PYTHON_STAMP} DEPENDS ${MSYM_PYTHON_INIT_IN} ${MSYM_PYTHON_SETUP_IN} ${MSYM_PYTHON_CODE_IN}) add_custom_target(target ALL DEPENDS ${MSYM_PYTHON_STAMP}) install(CODE "execute_process(COMMAND ${PYTHON} ${MSYM_PYTHON_SETUP} install ${MSYM_PYTHON_INSTALL_OPTS})") endif() v_sim-3.8.0/lib/plug-ins/msym/libmsym/bindings/python/README.md000066400000000000000000000003351370110300500241700ustar00rootroot00000000000000# libmsym libmsym is a python module c binding for libmsym that uses ctypes. It requires numpy for some functionality. See project README.md for installation instructions and the ./examples/ directory for usage examples v_sim-3.8.0/lib/plug-ins/msym/libmsym/bindings/python/cmake/000077500000000000000000000000001370110300500237705ustar00rootroot00000000000000v_sim-3.8.0/lib/plug-ins/msym/libmsym/bindings/python/cmake/__init__.py.in000066400000000000000000000005511370110300500265070ustar00rootroot00000000000000import os __all__ = [] _libmsym_install_location = os.path.join('${INSTALL_LIB_DIR}','$') if len(_libmsym_install_location) == 0 or _libmsym_install_location[0] == '$': _libmsym_install_location = None def export(defn): globals()[defn.__name__] = defn __all__.append(defn.__name__) return defn from . import libmsym v_sim-3.8.0/lib/plug-ins/msym/libmsym/bindings/python/cmake/setup.py.in000066400000000000000000000012741370110300500261130ustar00rootroot00000000000000# # setup.py # libmsym # # Created by Marcus Johansson on 07/10/15. # Copyright (c) 2015 Marcus Johansson. # # Distributed under the MIT License ( See LICENSE file or copy at http://opensource.org/licenses/MIT ) # from distutils.core import setup import sys if (not sys.version_info[0] is 3): sys.exit('libmsym module requires python 3') setup(name='libmsym', version='${LIBMSYM_VERSION}', description = 'libmsym python binding', license='MIT', author='Marcus Johansson', author_email='mcodev31@gmail.com', url='https://github.com/mcodev31/libmsym', package_dir={ 'libmsym': '${MSYM_PYTHON_PACKAGE_DIR}' }, packages=['libmsym'] ) v_sim-3.8.0/lib/plug-ins/msym/libmsym/bindings/python/examples/000077500000000000000000000000001370110300500245265ustar00rootroot00000000000000v_sim-3.8.0/lib/plug-ins/msym/libmsym/bindings/python/examples/msympy_example.py000077500000000000000000000102041370110300500301510ustar00rootroot00000000000000#!/usr/bin/python import libmsym as msym, numpy as np, argparse, random, sys def read_xyz(fin): length = int(fin.readline()) comment = fin.readline()[:-1] elements = [] for i in range(0,length): line = fin.readline().split() elements.append(msym.Element(name = line[0], coordinates = map(float, line[1:4]))) return (elements, comment) def write_xyz(fout, elements, comment): fout.write("%d\n%s\n" % (len(elements), comment)) for e in elements: v = e.coordinates fout.write("%s %.14f %.14f %.14f\n" % (e.name, *v)) parser = argparse.ArgumentParser() parser.add_argument('infile', type=argparse.FileType('r')) parser.add_argument('outfile', type=argparse.FileType('w')) args = parser.parse_args() (elements, comment) = read_xyz(args.infile) def set_basis(element): basis_function = msym.RealSphericalHarmonic(element = element, name = "1s") element.basis_functions = [basis_function] return basis_function basis_functions = [set_basis(e) for e in elements] #msym.init(library_location='/path_to_libmsym_library/libmsym.dylib') # e.g. for OS X without libmsym in dload path #with msym.Context() as ctx: # ctx.elements = elements # point_group = ctx.find_symmetry() # selements = ctx.symmetrize_elements() # write_xyz(args.outfile, selements, comment + " symmetrized by libmsym according to point group " + point_group) with msym.Context(elements = elements, basis_functions = basis_functions) as ctx: point_group = ctx.find_symmetry() selements = ctx.symmetrize_elements() write_xyz(args.outfile, selements, comment + " symmetrized by libmsym according to point group " + point_group) ctx.symmetry_operations #symmetry operations ctx.subrepresentation_spaces # subspace ctx.subrepresentation_spaces[0].symmetry_species #symmetry species of space (index into character table) ctx.subrepresentation_spaces[0].salcs # salcs that span space ctx.subrepresentation_spaces[0].salcs[0].basis_functions # basis functions for salc ctx.subrepresentation_spaces[0].salcs[0].partner_functions # numpy array of partner functions expressed in terms of basis_functions coefficients ctx.character_table.table # table as numpy array ctx.character_table.symmetry_operations # representative symmetry operations ctx.character_table.symmetry_species # symmetry species ctx.character_table.symmetry_species[0].dim # dimensionality of symmetry species ctx.character_table.symmetry_species[0].name # name of symmetry species e.g. A2g somefunc = np.zeros((len(basis_functions)),dtype=np.float64) for i in range(0,len(somefunc)): somefunc[i] = i species_components = ctx.symmetry_species_components(somefunc) species = ctx.character_table.symmetry_species print(somefunc) for i, c in enumerate(species_components): print(str(c) + species[i].name) #matrix version of the above, as well as wave function symmetrization (matrix, species, partners) = ctx.salcs (d,d) = matrix.shape print(matrix) print(species) print([(p.index, p.dim) for p in partners]) indexes = [x for x in range(0,d)] random.shuffle(indexes) matrix = matrix[indexes,:] matrix += 0.01 print(matrix) (_same_matrix, species,partners) = ctx.symmetrize_wavefunctions(matrix) print(matrix) print(species) print([(p.index, p.dim) for p in partners]) #generating elements ctx.point_group = "D6h" gen_elements = [msym.Element(name = "C", coordinates = [1.443524, 0.0,0.0]), msym.Element(name = "H", coordinates = [2.568381, 0.0, 0.0])] benzene = ctx.generate_elements(gen_elements) maxcomp = max([max(e.coordinates) for e in benzene]) print(len(benzene),"\nbenzene") for e in benzene: vec = np.asarray(e.coordinates) vec[vec < maxcomp*sys.float_info.epsilon] = 0 print(e.name, vec[0],vec[1],vec[2]) #with msym.Context(elements = elements, point_group = "T") as ctx: # point_group = ctx.point_group # selements = ctx.symmetrize_elements() # write_xyz(args.outfile, selements, comment + " symmetrized by libmsym according to point group " + point_group) v_sim-3.8.0/lib/plug-ins/msym/libmsym/bindings/python/libmsym/000077500000000000000000000000001370110300500243645ustar00rootroot00000000000000v_sim-3.8.0/lib/plug-ins/msym/libmsym/bindings/python/libmsym/.gitignore000066400000000000000000000000361370110300500263530ustar00rootroot00000000000000/__pycache__ *.swp .DS_Store v_sim-3.8.0/lib/plug-ins/msym/libmsym/bindings/python/libmsym/__init__.py000066400000000000000000000002601370110300500264730ustar00rootroot00000000000000__all__ = [] _libmsym_install_location = None def export(defn): globals()[defn.__name__] = defn __all__.append(defn.__name__) return defn from . import libmsym v_sim-3.8.0/lib/plug-ins/msym/libmsym/bindings/python/libmsym/libmsym.py000066400000000000000000000527601370110300500264240ustar00rootroot00000000000000# # libmsym.py # libmsym # # Created by Marcus Johansson on 07/10/15. # Copyright (c) 2015 Marcus Johansson. # # Distributed under the MIT License ( See LICENSE file or copy at http://opensource.org/licenses/MIT ) # from ctypes import * from ctypes.util import find_library from enum import Enum from copy import copy from . import _libmsym_install_location, export _lib = None @export class Error(Exception): def __init__(self, value, details=""): super().__init__(value) self.value=value self.details=details def __str__(self): return repr(self.value) + ": " + repr(self.details) def __repr__(self): return self.__str__() try: import numpy as np except ImportError: np = None @export class SymmetryOperation(Structure): NONE = 0, HORIZONTAL = 1 VERTICAL = 2 DIHEDRAL = 3 IDENTITY = 0, PROPER_ROTATION = 1 IMPROPER_ROTATION = 2 REFLECTION = 3 INVERSION = 4 _names = ["E","C","S","\u03C3","i"] _proper_rotation_type_names = ["", "", "'", "''"] _reflection_type_names = ["", "h", "v", "d"] _fields_ = [("type", c_int), ("order", c_int), ("power", c_int), ("orientation", c_int), ("_v", (c_double*3)), ("conjugacy_class", c_int)] @property def vector(self): return self._v[0:3] def __str__(self): orientation = "" order = "" power = "" axis = "" if self.type == self.PROPER_ROTATION and self.order == 2: orientation = self._proper_rotation_type_names[self.orientation] elif self.type == self.REFLECTION: orientation = self._reflection_type_names[self.orientation] axis = " with normal vector " + repr(self.vector) if self.type in [self.PROPER_ROTATION, self.IMPROPER_ROTATION]: order = str(self.order) power = "^" + str(self.power) axis = " around " + repr(self.vector) return __name__ + "." + self.__class__.__name__ + "( " + self._names[self.type] + order + orientation + power + axis + ", conjugacy class: " + str(self.conjugacy_class) + " )" def __repr__(self): return self.__str__() @export class Element(Structure): _fields_ = [("_id", c_void_p), ("mass", c_double), ("_v", c_double*3), ("charge", c_int), ("_name",c_char*4)] @property def coordinates(self): return self._v[0:3] @coordinates.setter def coordinates(self, coordinates): self._v = (c_double*3)(*coordinates) @property def name(self): return self._name.decode() @name.setter def name(self, name): self._name = name.encode('ascii') class _RealSphericalHarmonic(Structure): _fields_ = [("n", c_int), ("l", c_int), ("m", c_int)] class _BasisFunctionUnion(Union): _fields_ = [("_rsh", _RealSphericalHarmonic)] @export class BasisFunction(Structure): _fields_ = [("_id", c_void_p), ("_type", c_int), ("_element", POINTER(Element)), ("_f", _BasisFunctionUnion), ("_name",c_char*8)] def __init__(self, element=None): if element == None: raise Error("Basis function requires an element") super().__init__() self.element = element def _set_element_pointer(self, element): self._element = pointer(element) @property def name(self): return self._name.decode() @name.setter def name(self, name): self._name = name.encode('ascii') @export class RealSphericalHarmonic(BasisFunction): def __init__(self, element=None, n=0, l=0, m=0, name=""): super().__init__(element=element) self._type = 0 self._f._rsh.n = n self._f._rsh.l = l self._f._rsh.m = m self.name = name @property def n(self): return self._f._rsh.n @n.setter def n(self, n): self._f._rsh.n = n @property def l(self): return self._f._rsh.l @l.setter def l(self, n): self._f._rsh.n = l @property def m(self): return self._f._rsh.m @m.setter def m(self, n): self._f._rsh.n = m class SALC(Structure): _fields_ = [("_d", c_int), ("_fl", c_int), ("_pf", POINTER(c_double)), ("_f", POINTER(POINTER(BasisFunction)))] _pf_array = None basis_functions = [] def _update_basis_functions(self, basis_function_addresses, basis): self.basis_functions = [basis[basis_function_addresses.index(addressof(p.contents))] for p in self._f[0:self._fl]] #@property #def partner_functions(self): # if self._pf_array is None: # pf = cast(self._pf,POINTER(c_double*self._fl)) # self._pf_array = [f[0:self._fl] for f in pf[0:self._d]] # # return self._pf_array @property def partner_functions(self): if np is None: raise ImportError("numpy is not available.") if self._pf_array is None: self._pf_array = np.ctypeslib.as_array(self._pf, shape = (self._d,self._fl)) return self._pf_array @export class SubrepresentationSpace(Structure): _fields_ = [("symmetry_species", c_int), ("_salc_length", c_int), ("_salcs", POINTER(SALC))] _salcarray = None @property def salcs(self): if self._salcarray is None: self._salcarray = self._salcs[0:self._salc_length] return self._salcarray @export class PartnerFunction(Structure): _fields_ = [("index", c_int), ("dim",c_int)] @export class SymmetrySpecies(Structure): _fields_ = [("_d", c_int), ("_r", c_int), ("_name",c_char*8)] @property def dim(self): return self._d @property def reducible(self): return self._r > 1 @property def name(self): return self._name.decode() class _Thresholds(Structure): _fields_ = [("zero", c_double), ("geometry", c_double), ("angle", c_double), ("equivalence", c_double), ("eigfact", c_double), ("permutation", c_double), ("orthogonalization", c_double)] @export class CharacterTable(Structure): _fields_ = [("_d", c_int), ("_classc", POINTER(c_int)), ("_sops", POINTER(POINTER(SymmetryOperation))), ("_s", POINTER(SymmetrySpecies)), ("_table", POINTER(c_double))] _table_array = None _class_count_array = None _symmetry_species = None @property def table(self): if np is None: raise ImportError("numpy is not available.") if self._table_array is None: self._table_array = np.ctypeslib.as_array(self._table, shape = (self._d,self._d)) return self._table_array @property def class_count(self): if self._class_count_array is None: self._class_count_array = self._classc[0:self._d] return self._class_count_array def _update_symmetry_operations(self, symmetry_operations): addresses = [addressof(sop) for sop in symmetry_operations] self.symmetry_operations = [symmetry_operations[addresses.index(addressof(sop.contents))] for sop in self._sops[0:self._d]] @property def symmetry_species(self): if self._symmetry_species is None: self._symmetry_species = self._s[0:self._d] return self._symmetry_species class _ReturnCode(c_int): SUCCESS = 0 INVALID_INPUT = -1 INVALID_CONTEXT = -2 INVALID_THRESHOLD = -3 INVALID_ELEMENTS = -4 INVALID_BASIS = -5 INVALID_POINT_GROUP = -6 INVALID_EQUIVALENCE_SET = -7 INVALID_PERMUTATION = -8 INVALID_GEOMETRY = -9 INVALID_CHARACTER_TABLE = -10 INVALID_SUBSPACE = -11 INVALID_SUBGROUPS = -12 INVALID_AXES = -13 SYMMETRY_ERROR = -14 PERMUTATION_ERROR = -15 POINT_GROUP_ERROR = -16 SYMMETRIZATION_ERROR = -17 SUBSPACE_ERROR = -18 def __str__(self): #init is not called on the return type so we can't contruct data on creation, don't decode details here, may be too late error_string = _lib.msymErrorString(self.value).decode() return repr(error_string) def __repr__(self): return self.__str__() def init(library_location=None): if(library_location is None): raise Error("Cannot find libmsym shared library") global _lib _lib = CDLL(library_location) _Context = POINTER(type('msym_context', (Structure,), {})) _lib.msymErrorString.argtypes = [c_int] _lib.msymErrorString.restype = c_char_p _lib.msymCreateContext.restype = _Context _lib.msymCreateContext.argtypes = [] _lib.msymGetDefaultThresholds.restype = POINTER(_Thresholds) _lib.msymGetDefaultThresholds.argtypes = [] _lib.msymSetThresholds.restype = _ReturnCode _lib.msymSetThresholds.argtypes = [_Context, POINTER(_Thresholds)] _lib.msymReleaseContext.restype = _ReturnCode _lib.msymReleaseContext.argtypes = [_Context] _lib.msymGetErrorDetails.restype = c_char_p _lib.msymGetErrorDetails.argtypes = [] _lib.msymFindSymmetry.restype = _ReturnCode _lib.msymFindSymmetry.argtypes = [_Context] _lib.msymSetPointGroupByName.restype = _ReturnCode _lib.msymSetPointGroupByName.argtypes = [_Context, c_char_p] _lib.msymGetPointGroupName.restype = _ReturnCode _lib.msymGetPointGroupName.argtypes = [_Context, c_int, c_char_p] _lib.msymSetElements.restype = _ReturnCode _lib.msymSetElements.argtypes = [_Context, c_int, POINTER(Element)] _lib.msymGenerateElements.restype = _ReturnCode _lib.msymGenerateElements.argtypes = [_Context, c_int, POINTER(Element)] _lib.msymGetElements.restype = _ReturnCode _lib.msymGetElements.argtypes = [_Context, POINTER(c_int), POINTER(POINTER(Element))] _lib.msymGetSymmetryOperations.restype = _ReturnCode _lib.msymGetSymmetryOperations.argtypes = [_Context, POINTER(c_int), POINTER(POINTER(SymmetryOperation))] _lib.msymSymmetrizeElements.restype = _ReturnCode _lib.msymSymmetrizeElements.argtypes = [_Context] _lib.msymSetBasisFunctions.restype = _ReturnCode _lib.msymSetBasisFunctions.argtypes = [_Context, c_int, POINTER(BasisFunction)] _lib.msymGetBasisFunctions.restype = _ReturnCode _lib.msymGetBasisFunctions.argtypes = [_Context, POINTER(c_int), POINTER(POINTER(BasisFunction))] _lib.msymGetSubrepresentationSpaces.restype = _ReturnCode _lib.msymGetSubrepresentationSpaces.argtypes = [_Context, POINTER(c_int), POINTER(POINTER(SubrepresentationSpace))] _lib.msymGetCharacterTable.restype = _ReturnCode _lib.msymGetCharacterTable.argtypes = [_Context, POINTER(POINTER(CharacterTable))] if np is None: _SALCsMatrix = c_void_p _SALCsSpecies = POINTER(c_int) _NPDArray = POINTER(c_double) else: _SALCsMatrix = np.ctypeslib.ndpointer(dtype=np.float64, ndim=2, flags='C_CONTIGUOUS') _SALCsSpecies = np.ctypeslib.ndpointer(dtype=np.int32, ndim=1, flags='C_CONTIGUOUS') _NPDArray = np.ctypeslib.ndpointer(dtype=np.float64, ndim=1, flags='C_CONTIGUOUS') _lib.msymSymmetrySpeciesComponents.restype = _ReturnCode _lib.msymSymmetrySpeciesComponents.argtypes = [_Context, c_int, _NPDArray, c_int, _NPDArray] _lib.msymGetSALCs.restype = _ReturnCode _lib.msymGetSALCs.argtypes = [_Context, c_int, _SALCsMatrix, _SALCsSpecies, POINTER(PartnerFunction)] _lib.msymSymmetrizeWavefunctions.restype = _ReturnCode _lib.msymSymmetrizeWavefunctions.argtypes = [_Context, c_int, _SALCsMatrix, _SALCsSpecies, POINTER(PartnerFunction)] _libmsym_location = find_library('msym') if _libmsym_location is None: _libmsym_location = _libmsym_install_location if not (_libmsym_location is None): init(_libmsym_location) @export class Context(object): _ctx = None def __init__(self, elements=[], basis_functions=[], point_group=""): if(_lib is None): raise Error("Shared library not loaded") self._elements = [] self._basis_functions = [] self._point_group = None self._subrepresentation_spaces = None self._character_table = None self._ctx = _lib.msymCreateContext() if not self._ctx: raise RuntimeError('Failed to create libmsym context') pthresholds = _lib.msymGetDefaultThresholds() default_thresholds = pthresholds.contents if default_thresholds is None: raise RuntimeError('Failed get libmsym default thresholds') self._thresholds = copy(default_thresholds) if len(elements) > 0: self._set_elements(elements) if len(basis_functions) > 0: self._set_basis_functions(basis_functions) if len(point_group) > 0: self._set_point_group(point_group) self.find_symmetry() def __del__(self): self._destruct() def __enter__(self): return self def __exit__(self, exc_type, exc_value, traceback): self._destruct() def _destruct(self): if self._ctx: _lib.msymReleaseContext(self._ctx) self._ctx = None @staticmethod def _assert_success(error): if not error.value == _ReturnCode.SUCCESS: raise Error(error, details = _lib.msymGetErrorDetails().decode()) def _get_basis_function_addresses(self): if not self._ctx: raise RuntimeError cbfs = POINTER(BasisFunction)() csize = c_int(0) self._assert_success(_lib.msymGetBasisFunctions(self._ctx,byref(csize),byref(cbfs))) return [addressof(bf) for bf in cbfs[0:csize.value]] def _set_elements(self, elements): if not self._ctx: raise RuntimeError self._subrepresentation_spaces = None self._character_table = None self._salcs = None self._basis_functions = [] size = len(elements) element_array = (Element*size)(*elements) self._assert_success(_lib.msymSetElements(self._ctx, size, element_array)) self._element_array = element_array self._elements = elements def _set_point_group(self, point_group): if not self._ctx: raise RuntimeError self._subrepresentation_spaces = None self._character_table = None self._salcs = None cname = c_char_p(point_group.encode('ascii')) self._assert_success(_lib.msymSetPointGroupByName(self._ctx, cname)) self._update_symmetry_operations() def _set_basis_functions(self, basis_functions): if not self._ctx: raise RuntimeError self._subrepresentation_spaces = None self._salcs = None size = len(basis_functions) for bf in basis_functions: bf._set_element_pointer(self._element_array[self._elements.index(bf.element)]) self._assert_success(_lib.msymSetBasisFunctions(self._ctx, size, (BasisFunction*size)(*basis_functions))) self._basis_functions = basis_functions if not self._point_group is None: self._update_symmetry_operations() self._update_character_table() def _update_elements(self): if not self._ctx: raise RuntimeError celements = POINTER(Element)() csize = c_int(0) self._assert_success(_lib.msymGetElements(self._ctx,byref(csize),byref(celements))) self._elements_array = celements self._elements = celements[0:csize.value] def _update_symmetry_operations(self): if not self._ctx: raise RuntimeError csops = POINTER(SymmetryOperation)() csize = c_int(0) self._assert_success(_lib.msymGetSymmetryOperations(self._ctx,byref(csize),byref(csops))) self._symmetry_operations = csops[0:csize.value] def _update_point_group(self): if not self._ctx: raise RuntimeError cname = (c_char*8)() self._assert_success(_lib.msymGetPointGroupName(self._ctx,sizeof(cname),cname)) self._point_group = cname.value.decode() def _update_subrepresentation_spaces(self): if not self._ctx: raise RuntimeError basis_function_addresses = self._get_basis_function_addresses() csrs = POINTER(SubrepresentationSpace)() csize = c_int(0) self._assert_success(_lib.msymGetSubrepresentationSpaces(self._ctx,byref(csize),byref(csrs))) srs = csrs[0:csize.value] for s in srs: for salc in s.salcs: salc._update_basis_functions(basis_function_addresses, self._basis_functions) self._subrepresentation_spaces = srs def _update_character_table(self): if not self._ctx: raise RuntimeError cct = POINTER(CharacterTable)() self._assert_success(_lib.msymGetCharacterTable(self._ctx,byref(cct))) self._character_table = cct.contents self._character_table._update_symmetry_operations(self._symmetry_operations) def _update_salcs(self): if not self._ctx: raise RuntimeError if np is None: raise ImportError("numpy is not available.") csize = len(self._basis_functions) partner_functions = (PartnerFunction*csize)() salcs = np.zeros((csize,csize),dtype=np.float64) species = np.zeros((csize),dtype=np.int32) self._assert_success(_lib.msymGetSALCs(self._ctx,csize,salcs,species,partner_functions)) self._salcs = (salcs, species, partner_functions[0:csize]) def set_thresholds(self, **kwargs): for key in kwargs.keys(): if not key in ['zero','geometry','angle','equivalence', 'eigfact','permutation','orthogonalization']: raise Error('Unrecognized threshold argument') setattr(self._thresholds, key, kwargs[key]) self._assert_success(_lib.msymSetThresholds(self._ctx, pointer(self._thresholds))) @property def elements(self): return self._elements @elements.setter def elements(self, elements): self._set_elements(elements) @property def basis_functions(self): return self._basis_functions @basis_functions.setter def basis_functions(self, basis_functions): self._set_basis_functions(basis_functions) @property def point_group(self): return self._point_group @point_group.setter def point_group(self, point_group): self._set_point_group(point_group) @property def symmetry_operations(self): return self._symmetry_operations def find_symmetry(self): if not self._ctx: raise RuntimeError self._assert_success(_lib.msymFindSymmetry(self._ctx)) self._update_point_group() self._update_symmetry_operations() return self._point_group def symmetrize_elements(self): if not self._ctx: raise RuntimeError cerror = c_double(0) self._assert_success(_lib.msymSymmetrizeElements(self._ctx, byref(cerror))) self._update_elements() return self._elements @property def subrepresentation_spaces(self): if self._subrepresentation_spaces is None: self._update_subrepresentation_spaces() return self._subrepresentation_spaces @property def character_table(self): if self._character_table is None: self._update_character_table() return self._character_table @property def salcs(self): if self._salcs is None: self._update_salcs() return self._salcs def symmetrize_wavefunctions(self,m): if not self._ctx: raise RuntimeError if np is None: raise ImportError("numpy is not available.") csize = len(self._basis_functions) (d1,d2) = m.shape if not (d1 == csize and d2 == csize): raise ValueError("Must provide a " + str(csize) + "x" + str(csize)) wf = np.ascontiguousarray(m, dtype=np.float64) partner_functions = (PartnerFunction*csize)() species = np.zeros((csize),dtype=np.int32) self._assert_success(_lib.msymSymmetrizeWavefunctions(self._ctx,csize,wf,species,partner_functions)) return (wf, species, partner_functions[0:csize]) def generate_elements(self, elements): if not self._ctx: raise RuntimeError self._subrepresentation_spaces = None self._character_table = None self._salcs = None self._element_array = None self._basis_functions = [] self._elements = [] size = len(elements) element_array = (Element*size)(*elements) self._assert_success(_lib.msymGenerateElements(self._ctx, size, element_array)) self._update_elements() return self._elements def symmetry_species_components(self, wf): wf_size = len(wf) if not wf_size == len(self.basis_functions): raise ValueError("Must provide an array of length " + str(len(self.basis_functions))) species_size = self.character_table._d species = np.zeros((species_size),dtype=np.float64) wf = np.ascontiguousarray(wf, dtype=np.float64) self._assert_success(_lib.msymSymmetrySpeciesComponents(self._ctx, wf_size, wf, species_size, species)) return species v_sim-3.8.0/lib/plug-ins/msym/libmsym/bindings/python/setup.py000066400000000000000000000011601370110300500244200ustar00rootroot00000000000000# # setup.py # libmsym # # Created by Marcus Johansson on 07/10/15. # Copyright (c) 2015 Marcus Johansson. # # Distributed under the MIT License ( See LICENSE file or copy at http://opensource.org/licenses/MIT ) # from distutils.core import setup import sys if (not sys.version_info[0] is 3): sys.exit('libmsym module requires python 3') setup(name='libmsym', version='0.2.4', description = 'libmsym python binding', license='MIT', author='Marcus Johansson', author_email='mcodev31@gmail.com', url='https://github.com/mcodev31/libmsym', packages=['libmsym'] ) v_sim-3.8.0/lib/plug-ins/msym/libmsym/examples/000077500000000000000000000000001370110300500214105ustar00rootroot00000000000000v_sim-3.8.0/lib/plug-ins/msym/libmsym/examples/CMakeLists.txt000066400000000000000000000014421370110300500241510ustar00rootroot00000000000000cmake_minimum_required (VERSION 2.8.11) include_directories(${PROJECT_BINARY_DIR} "${PROJECT_SOURCE_DIR}/src") set (CMAKE_C_FLAGS "${CMAKE_C_FLAGS} -std=c99") #set_target_properties (msym PROPERTIES # C_STANDARD 99 # C_STANDARD_REQUIRED ON) #set (CMAKE_C_FLAGS "${CMAKE_C_FLAGS} -std=c99 -flto") #set (CMAKE_C_FLAGS "${CMAKE_C_FLAGS} -std=c99 -fsanitize=address -fno-omit-frame-pointer") #set (CMAKE_C_FLAGS "${CMAKE_C_FLAGS} -std=c99 -fsanitize=memory -fno-omit-frame-pointer -fsanitize-memory-track-origins") #set (CMAKE_EXE_LINKER_FLAGS "${CMAKE_EXE_LINKER_FLAGS} -flto" ) add_executable (msym_example msym_example.c example.c) add_executable (msym_tex tex_character_table) target_link_libraries (msym_example LINK_PUBLIC msym) target_link_libraries (msym_tex LINK_PUBLIC msym) v_sim-3.8.0/lib/plug-ins/msym/libmsym/examples/example.c000066400000000000000000000534661370110300500232250ustar00rootroot00000000000000// // example.c // libmsym // // Created by Marcus Johansson on 24/04/15. // Copyright (c) 2015 Marcus Johansson. // // Distributed under the MIT License ( See LICENSE file or copy at http://opensource.org/licenses/MIT ) // #include #include #include #include #include "example.h" int read_xyz(const char *name, msym_element_t **ratoms); void printSALC(msym_salc_t *salc, msym_element_t *melements){ double (*space)[salc->fl] = (double (*)[salc->fl]) salc->pf; for(int d = 0;d < salc->d;d++){ if(salc->d > 1) printf("Component %d:\n",d+1); for(int line = 0; line < salc->fl; line+=6){ for(int i = line;i < line + 6 && i < salc->fl;i++){ msym_basis_function_t *bf = salc->f[i]; printf(" %d%s %-8s\t",(int)(bf->element-melements)+1, bf->element->name,bf->name); } printf("\n"); for(int i = line;i < line + 6 && i < salc->fl;i++){ printf("%10.7lf\t", space[d][i]); } printf("\n\n"); } printf("\n"); } } int example(const char* in_file, msym_thresholds_t *thresholds){ msym_error_t ret = MSYM_SUCCESS; msym_element_t *elements = NULL; const char *error = NULL; char point_group[6]; double cm[3], radius = 0.0, symerr = 0.0; /* Do not free these variables */ msym_element_t *melements = NULL; msym_basis_function_t *mbfs = NULL; /* these are not mutable */ const msym_symmetry_operation_t *msops = NULL; const msym_subgroup_t *msg = NULL; const msym_subrepresentation_space_t *msrs = NULL; const msym_character_table_t *mct = NULL; const msym_equivalence_set_t *mes = NULL; int mesl = 0; double *irrep = NULL; msym_basis_function_t *bfs = NULL; int msgl = 0, msopsl = 0, mlength = 0, msrsl = 0, mbfsl = 0, bfsl = 0; /* This function reads xyz files. * It initializes an array of msym_element_t to 0, * then sets the coordinates and name of the elements */ int length = read_xyz(in_file, &elements); if(length <= 0) return -1; double (*psalcs)[bfsl] = NULL; // SALCs in matrix form, and input for symmetrization double *pcmem = NULL; // Some temporary memory int *pspecies = NULL; msym_partner_function_t *ppf = NULL; /* Create a context */ msym_context ctx = msymCreateContext(); if(NULL != thresholds){ if(MSYM_SUCCESS != (ret = msymSetThresholds(ctx, thresholds))) goto err; } /* Use default thresholds otherwise call: * msymSetThresholds(msym_context ctx, msym_thresholds_t *thresholds); */ /* Set elements */ if(MSYM_SUCCESS != (ret = msymSetElements(ctx, length, elements))) goto err; /* Get elements msym elements */ if(MSYM_SUCCESS != (ret = msymGetElements(ctx, &mlength, &melements))) goto err; /* These are no longer needed, internal versions of these are kept in the context, * They are indexed in the same way that they have been allocated. * I.e. during orbital symmetrization or when getting the symmetrized LCAO, * the coefficients will correspond to the same indexing as "orbitals", * this is the main reason for the two levels of indirection */ free(elements); elements = NULL; /* Some trivial information */ if(MSYM_SUCCESS != (ret = msymGetCenterOfMass(ctx,cm))) goto err; if(MSYM_SUCCESS != (ret = msymGetRadius(ctx,&radius))) goto err; printf("Molecule has center of mass [%lf; %lf; %lf] " "and a radius of %lf\n",cm[0],cm[1],cm[2],radius); /* Find molecular symmetry */ if(MSYM_SUCCESS != (ret = msymFindSymmetry(ctx))) goto err; /* Get the point group name */ if(MSYM_SUCCESS != (ret = msymGetPointGroupName(ctx, sizeof(char[6]), point_group))) goto err; if(MSYM_SUCCESS != (ret = msymGetSubgroups(ctx, &msgl, &msg))) goto err; printf("Found point group [0] %s with %d subgroups:\n",point_group, msgl); printf("\t [0] %s\n\t -------\n", point_group); for(int i = 0; i < msgl;i++) printf("\t [%d] %s\n",i+1,msg[i].name); int ssg = 0; do {printf("\nChoose point group to use [0-%d]:",msgl);} while(scanf(" %d", &ssg) <= 0 || ssg < 0 || ssg > msgl); if(ssg > 0){ ssg--; printf("Selected point group %s\n",msg[ssg].name); if(MSYM_SUCCESS != (ret = msymSelectSubgroup(ctx, &msg[ssg]))) goto err; if(MSYM_SUCCESS != (ret = msymGetPointGroupName(ctx, sizeof(char[6]), point_group))) goto err; } char yn = 'n'; printf("\nWould you like to add basis functions? [y/N]:"); if(scanf(" %c", &yn) > 0 && (yn | 0x60) == 'y'){ int sel_es = 0; if(MSYM_SUCCESS != (ret = msymGetEquivalenceSets(ctx, &mesl, &mes))) goto err; do { int sel_n = 0, sel_l = 0, ele_bfsl = 0; printf("Basis functions can be added to entire molecule [0] or any of %d symmetrically equivalent sets:\n",mesl); printf("\t [0] Entire molecule\n"); for(int i = 0; i < mesl;i++) printf("\t [%d] %d%s\n",i+1,mes[i].length, mes[i].elements[0]->name); do {printf("\nChoose set of elements [0-%d]:",mesl);} while(scanf(" %d", &sel_es) <= 0 || sel_es < 0 || sel_es > mesl); do { //z functions should be enough for an example printf("\nSelect principal quantum number (n) [1-21]:"); } while (scanf(" %d", &sel_n) <= 0 || sel_n < 1 || sel_n > 21); do { printf("\nSelect angular momentum quantum number (l) [0-%d]:",sel_n-1); } while (scanf(" %d", &sel_l) <= 0 || sel_l < 0 || sel_l >= sel_n); ele_bfsl = (2*sel_l+1); if(sel_es > 0){ const msym_equivalence_set_t *smes = &mes[sel_es-1]; int nbfsl = smes->length*ele_bfsl; bfs = realloc(bfs, bfsl*sizeof(*bfs) + nbfsl*sizeof(*bfs)); memset(&bfs[bfsl], 0, nbfsl*sizeof(*bfs)); for(int i = 0;i < smes->length;i++){ for(int m = -sel_l;m <= sel_l;m++){ bfs[bfsl].element = smes->elements[i]; bfs[bfsl].type = MSYM_BASIS_TYPE_REAL_SPHERICAL_HARMONIC; bfs[bfsl].f.rsh.n = sel_n; bfs[bfsl].f.rsh.l = sel_l; bfs[bfsl].f.rsh.m = m; bfsl++; } } printf("Will add %d real spherical harmonics basis functions with n=%d l=%d m=[%d,%d]to equivalence set %d\n", nbfsl, sel_n, sel_l, -sel_l, sel_l, sel_es); } else { int nbfsl = mlength*ele_bfsl; bfs = realloc(bfs, bfsl*sizeof(*bfs) + nbfsl*sizeof(*bfs)); memset(&bfs[bfsl], 0, nbfsl*sizeof(*bfs)); for(int i = 0;i < mlength;i++){ for(int m = -sel_l;m <= sel_l;m++){ // You can use either melements or your initial elements here, but melements is "more correct" bfs[bfsl].element = &melements[i]; bfs[bfsl].type = MSYM_BASIS_TYPE_REAL_SPHERICAL_HARMONIC; bfs[bfsl].f.rsh.n = sel_n; bfs[bfsl].f.rsh.l = sel_l; bfs[bfsl].f.rsh.m = m; bfsl++; } } printf("Will add %d real spherical harmonics basis functions with n=%d l=%d m=[%d,%d] to entire molecule\n", nbfsl, sel_n, sel_l, -sel_l, sel_l); } printf("\nWould you like to add more basis functions? [y/N]:"); } while(scanf(" %c", &yn) > 0 && (yn | 0x60) == 'y'); printf("Adding %d basis functions\n",bfsl); if(MSYM_SUCCESS != (ret = msymSetBasisFunctions(ctx, bfsl, bfs))) goto err; msym_point_group_type_t mtype; int mn; if(MSYM_SUCCESS != (ret = msymGetPointGroupType(ctx, &mtype, &mn))) goto err; /* Equivalence sets, subgroups and symmetry elements are updated when setting basis functions on linear groups. * Take care to update them (you can always update after setting basis functions, it's just a pointer update) */ if((MSYM_POINT_GROUP_TYPE_Dnh == mtype || MSYM_POINT_GROUP_TYPE_Cnv == mtype) && 0 == mn){ if(MSYM_SUCCESS != (ret = msymGetSubgroups(ctx, &msgl, &msg))) goto err; printf("Your selecton of basis functions resulted in new relevant subgroups\n"); printf("Can now use [0] %s or any of %d subgroups:\n",point_group, msgl); printf("\t [0] %s\n\t -------\n", point_group); for(int i = 0; i < msgl;i++) printf("\t [%d] %s\n",i+1,msg[i].name); int ssg = 0; do {printf("\nChoose point group to use [0-%d]:",msgl);} while(scanf(" %d", &ssg) <= 0 || ssg < 0 || ssg > msgl); if(ssg > 0){ ssg--; printf("Selected point group %s\n",msg[ssg].name); if(MSYM_SUCCESS != (ret = msymSelectSubgroup(ctx, &msg[ssg]))) goto err; if(MSYM_SUCCESS != (ret = msymGetPointGroupName(ctx, sizeof(char[6]), point_group))) goto err; } if(MSYM_SUCCESS != (ret = msymGetEquivalenceSets(ctx, &mesl, &mes))) goto err; } } /* Get elements msym elements */ if(MSYM_SUCCESS != (ret = msymGetSymmetryOperations(ctx, &msopsl, &msops))) goto err; /* Set pointgroup to the C3v subgroup if it has XXX symmetry * using the same alignment as the original. * If specific axes are wanted the alignment axes/transform can be set using: * msym Get/Set Alignment Transform/Axes */ if(0 == strncmp(point_group, "XXX", 3) && ssg == 0){ //double transform[3][3]; printf("Changing pointgroup from XXX -> C3v\n"); //if(MSYM_SUCCESS != (ret = msymGetAlignmentTransform(ctx, transform))) goto err; if(MSYM_SUCCESS != (ret = msymSetPointGroupByType(ctx, MSYM_POINT_GROUP_TYPE_Cnv,3))) goto err; //if(MSYM_SUCCESS != (ret = msymSetAlignmentTransform(ctx, transform))) goto err; if(MSYM_SUCCESS != (ret = msymFindSymmetry(ctx))) goto err; if(MSYM_SUCCESS != (ret = msymGetPointGroupName(ctx, sizeof(char[6]), point_group))) goto err; } /* Retreive the symmetry operations */ if(MSYM_SUCCESS != (ret = msymGetSymmetryOperations(ctx, &msopsl, &msops))) goto err; printf("\nWould you like to print the symmetry elements? [y/N]:"); if(scanf(" %c", &yn) > 0 && (yn | 0x60) == 'y'){ for(int i = 0; i < msopsl;i++){ const msym_symmetry_operation_t *sop = &msops[i]; char *rn = ""; char *cn = ""; switch(sop->orientation){ case MSYM_SYMMETRY_OPERATION_ORIENTATION_HORIZONTAL : rn = "h"; break; case MSYM_SYMMETRY_OPERATION_ORIENTATION_VERTICAL : rn = "v"; cn = "'"; break; case MSYM_SYMMETRY_OPERATION_ORIENTATION_DIHEDRAL : rn = "d"; cn = "''"; break; default: break; } switch (sop->type) { case MSYM_SYMMETRY_OPERATION_TYPE_PROPER_ROTATION : if(sop->order == 2) printf("C%d%s",sop->order,cn); else printf("C%d%s^%d",sop->order,cn,sop->power); printf(" around [%lf %lf %lf]\n", sop->v[0],sop->v[1],sop->v[2]); break; case MSYM_SYMMETRY_OPERATION_TYPE_IMPROPER_ROTATION : printf("S%d^%d",sop->order,sop->power); printf(" around [%lf %lf %lf]\n", sop->v[0],sop->v[1],sop->v[2]); break; case MSYM_SYMMETRY_OPERATION_TYPE_REFLECTION : printf("R%s",rn); printf(" with normal vector [%lf %lf %lf]\n", sop->v[0],sop->v[1],sop->v[2]); break; case MSYM_SYMMETRY_OPERATION_TYPE_INVERSION : printf("i\n"); break; case MSYM_SYMMETRY_OPERATION_TYPE_IDENTITY : printf("E\n"); break; default : printf("?"); break; } } } if(bfsl > 0){ // Just keeping memory in context of error handling double (*salcs)[bfsl] = psalcs = calloc(bfsl, sizeof(*salcs)); // SALCs in matrix form, and input for symmetrization double *cmem = pcmem = calloc(bfsl, sizeof(*cmem)); // Some temporary memory int *species = pspecies = calloc(bfsl, sizeof(*species)); msym_partner_function_t *pf = ppf = calloc(bfsl, sizeof(*pf)); if(MSYM_SUCCESS != (ret = msymGetBasisFunctions(ctx, &mbfsl, &mbfs))) goto err; if(MSYM_SUCCESS != (ret = msymGetSubrepresentationSpaces(ctx, &msrsl, &msrs))) goto err; if(MSYM_SUCCESS != (ret = msymGetCharacterTable(ctx, &mct))) goto err; irrep = calloc(mct->d, sizeof(*irrep)); printf("\nGenerated SALCs from %d basis functions of %d symmetry species.\nWould you like to view them? [y/N]:", mbfsl, mct->d); if(scanf(" %c", &yn) > 0 && (yn | 0x60) == 'y'){ do{ int sel_ss = 0, sel_salc = 0; for(int i = 0; i < msrsl;i++){ if(msrs[i].salcl > 0) printf("\t [%d] %s (%d SALCs with %d partner functions each)\n",i, mct->s[msrs[i].s].name, msrs[i].salcl, mct->s[msrs[i].s].d); else printf("\t [-] %s (no SALCs of this symmetry species)\n",mct->s[msrs[i].s].name); } do {printf("\nChoose subspace [0-%d]:",msrsl-1);} while(scanf(" %d", &sel_ss) <= 0 || sel_ss < 0 || sel_ss >= msrsl || msrs[sel_ss].salcl <= 0); int salcl = msrs[sel_ss].salcl; for(int i = 0; i < salcl;i++){ char *type = ""; msym_salc_t *salc = &msrs[sel_ss].salc[i]; msym_basis_function_t *bf = salc->f[0]; const msym_equivalence_set_t *salces = NULL; if(MSYM_SUCCESS != (ret = msymGetEquivalenceSetByElement(ctx, bf->element, &salces))) goto err; if(bf->type == MSYM_BASIS_TYPE_REAL_SPHERICAL_HARMONIC) type = "real spherical harmonic "; printf("\t [%d] SALC constructed from %d %sbasis on equivalence set %d with n=%d and l=%d\n",i,salc->fl,type,(int) (salces - mes),bf->f.rsh.n,bf->f.rsh.l); } do {printf("\nChoose SALC [0-%d]:",salcl-1);} while(scanf(" %d", &sel_salc) <= 0 || sel_salc < 0 || sel_salc > salcl); msym_salc_t *salc = &msrs[sel_ss].salc[sel_salc]; printSALC(salc, melements); printf("\nWould you like to view more SALCs? [y/N]:"); } while(scanf(" %c", &yn) > 0 && (yn | 0x60) == 'y'); } printf("\nWould you like to test wavefunction symmetrization and component determination? [y/N]:"); if(scanf(" %c", &yn) > 0 && (yn | 0x60) == 'y'){ printf("Scrambling and adding noise to SALCS to use for symmetrization\n"); if(MSYM_SUCCESS != (ret = msymGetSALCs(ctx, bfsl, salcs, species, pf))) goto err; /* Reorder the SALCs */ for(int i = 0;i < bfsl;i++){ int ni = i*i % bfsl; if(ni != i){ memcpy(cmem, salcs[i], sizeof(double[bfsl])); memcpy(salcs[i], salcs[ni], sizeof(double[bfsl])); memcpy(salcs[ni], cmem, sizeof(double[bfsl])); } } /* Add some noise */ srand((unsigned)time(NULL)); for(int i = 0;i < bfsl;i++){ for(int j = 0;j < bfsl;j++){ double r = ((double) (rand() - (RAND_MAX >> 1)))/RAND_MAX; double x = i % 2 == 0 ? -1.0 : 1.0; salcs[i][j] += r*1.0e-5; salcs[i][j] *= x; } } /* Symmetrize wavefunctions */ if(MSYM_SUCCESS != (ret = msymSymmetrizeWavefunctions(ctx, bfsl, salcs, species, pf))) goto err; printf("Wave function symmetrization returned new linear combinations:\n"); for(int i = 0;i < bfsl;i++){ int s = species[i]; printf("\t wf:%d is of symmetry species %s",i,mct->s[s].name); if(mct->s[s].d > 1){ printf(" partner function %d to wf:%d",pf[i].d, pf[i].i); } printf("\n"); } for(int i = 0; i < bfsl;i++) cmem[i] = 1; if(MSYM_SUCCESS != (ret = msymSymmetrySpeciesComponents(ctx, bfsl, cmem, mct->d, irrep))) goto err; printf("Test wavefunction 1,1... components\n"); printf("%lf%s", irrep[0], mct->s[0].name); for(int j = 1;j < mct->d;j++){ printf(" + %lf%s", irrep[j], mct->s[j].name); } printf("\n"); } } int symprint = 0; printf("\nWould you like to symmetrize the molecule? [y/N]:"); if(scanf(" %c", &yn) > 0 && (yn | 0x60) == 'y'){ symprint = 1; /* Symmetrize the molecule. * You can do this before orbital symmetrization as well, * but the permutations are already built, so you don't need to */ if(MSYM_SUCCESS != (ret = msymSymmetrizeElements(ctx, &symerr))) goto err; printf("Molecule has been symmetrized to point group %s " "with an error of %lf\n",point_group, symerr); } printf("\nWould you like to align it to the xyz axis? [y/N]:"); if(scanf(" %c", &yn) > 0 && (yn | 0x60) == 'y'){ symprint = 1; /* Aligning axes prior to orbital symmetrization will * change the orientation of orbitals with l >= 1 * relative to the molecular orientation */ if(MSYM_SUCCESS != (ret = msymAlignAxes(ctx))) goto err; printf("Molecule has been aligned to the xyz axes\n"); } if(symprint){ if(MSYM_SUCCESS != (ret = msymGetElements(ctx, &mlength, &melements))) goto err; if(mlength != length){ printf("Not possible!\n"); goto err;} printf("New element coordinates:\n%d\n\n",mlength); for(int i = 0;i < mlength;i++){ printf("%s %12.9lf %12.9lf %12.9lf\n", melements[i].name, melements[i].v[0], melements[i].v[1], melements[i].v[2]); } } /* Make a new element with the same type as the first one we read */ msym_element_t myelement; memset(&myelement,0,sizeof(msym_element_t)); myelement.n = melements[0].n; myelement.v[0] = melements[0].v[0]; myelement.v[1] = melements[0].v[1]; myelement.v[2] = melements[0].v[2]; printf("\nWould you like generate a new molecule based on %s at [%lf %lf %lf]? [y/N]:", melements[0].name, melements[0].v[0], melements[0].v[1], melements[0].v[2]); if(scanf(" %c", &yn) > 0 && (yn | 0x60) == 'y'){ /* Generate some new elements of the same point group */ if(MSYM_SUCCESS != (ret = msymGenerateElements(ctx,1,&myelement))) goto err; /* This is not a memory leak, context keeps track of melements, * and it should never be freed, msymReleaseContext does this. */ if(MSYM_SUCCESS != (ret = msymGetElements(ctx, &mlength, &melements))) goto err; printf("\n\nGenerated element coordinates based on %s at [%lf %lf %lf]:\n%d\n\n",melements[0].name, melements[0].v[0], melements[0].v[1], melements[0].v[2], mlength); for(int i = 0;i < mlength;i++){ printf("%s %12.9lf %12.9lf %12.9lf\n", melements[i].name, melements[i].v[0], melements[i].v[1], melements[i].v[2]); } } msymReleaseContext(ctx); printf("We're done!\n"); free(psalcs); free(pcmem); free(pspecies); free(ppf); free(bfs); free(elements); free(irrep); return ret; err: free(psalcs); free(pcmem); free(pspecies); free(ppf); free(bfs); free(elements); free(irrep); error = msymErrorString(ret); fprintf(stderr,"Error %s: ",error); error = msymGetErrorDetails(); fprintf(stderr,"%s\n",error); msymReleaseContext(ctx); return ret; } int read_xyz(const char *name, msym_element_t **ratoms) { FILE *fp = fopen(name,"r"); msym_element_t *a; int l; char buf[1024]; if(NULL == fp){ fprintf(stderr, "could not open file: %s\n",name); return -1; } if (NULL == fgets(buf, sizeof(buf), fp) || sscanf(buf," %d ",&l) != 1){ fprintf(stderr,"Unable to read file %s\n",name); fclose(fp); return -1; } if(l < 300000) { a = malloc(l*sizeof(msym_element_t)); memset(a,0,l*sizeof(msym_element_t)); } else { fprintf(stderr, "Too many elements in file %d\n",l); fclose(fp); return -1; } //char * fgets ( comment, sizeof(comment), fp ); if(NULL != fgets(buf, sizeof(buf), fp)){ printf("Comment: %.*s", (int)sizeof(buf), buf); } for (int i = 0; i < l && fgets(buf, sizeof(buf), fp) && sscanf(buf, "%s %lf %lf %lf", a[i].name, &(a[i].v[0]), &(a[i].v[1]), &(a[i].v[2])) == 4 && i < l; i++) {} *ratoms = a; fclose(fp); return l; } v_sim-3.8.0/lib/plug-ins/msym/libmsym/examples/example.h000066400000000000000000000006301370110300500232130ustar00rootroot00000000000000// // example.h // libmsym // // Created by Marcus Johansson on 24/04/15. // Copyright (c) 2015 Marcus Johansson. // // Distributed under the MIT License ( See LICENSE file or copy at http://opensource.org/licenses/MIT ) // // Use if installed #include "msym.h" int example(const char* in_file, msym_thresholds_t *thresholds); int read_xyz(const char *name, msym_element_t **ratoms); v_sim-3.8.0/lib/plug-ins/msym/libmsym/examples/msym_example.c000066400000000000000000000007651370110300500242640ustar00rootroot00000000000000// // msym_example.c // libmsym // // Created by Marcus Johansson on 10/09/15. // Copyright (c) 2015 Marcus Johansson. // // Distributed under the MIT License ( See LICENSE file or copy at http://opensource.org/licenses/MIT ) // #include #include "example.h" int main(int argc, const char * argv[]) { int ret = 1; if(argc == 2){ ret = example(argv[1],NULL); fflush(stdout); } else { printf("usage msym_example "); } return ret; } v_sim-3.8.0/lib/plug-ins/msym/libmsym/examples/tex_character_table.c000066400000000000000000000221751370110300500255460ustar00rootroot00000000000000// // tex_character_table.c // libmsym // // Created by Marcus Johansson on 12/09/15. // Copyright (c) 2015 Marcus Johansson. // // Distributed under the MIT License ( See LICENSE file or copy at http://opensource.org/licenses/MIT ) // #include #include #include #include // Use if installed #include "msym.h" void characterTableToTex(FILE *fp, msym_point_group_type_t type, int n, const char *name, const msym_character_table_t *ct); void pointGroupToTex(FILE *fp, msym_point_group_type_t type, int n, int l, char buf[l]); void symmetryOperationToTex(FILE *fp, msym_symmetry_operation_t *sop, int l, char buf[l]); void symmetrySpeciesToTex(FILE *fp, msym_symmetry_species_t *s); void characterToTex(FILE *fp,int n, const msym_character_table_t *ct, int i, int j, int mode); int main(int argc, const char * argv[]) { msym_error_t ret = MSYM_SUCCESS; const char *error = NULL; msym_context ctx = msymCreateContext(); if(argc >= 3){ int l = -1; FILE *fp = fopen(argv[2],"w"); if(!fp) { fprintf(stderr,"unable to open file %s for writing\n",argv[2]); return 1; } const msym_character_table_t *ct = NULL; msym_point_group_type_t pg_type = MSYM_POINT_GROUP_TYPE_Kh; int pg_n = 0; if(MSYM_SUCCESS != (ret = msymSetPointGroupByName(ctx, argv[1]))) goto err; if(MSYM_SUCCESS != (ret = msymGetPointGroupType(ctx, &pg_type, &pg_n))) goto err; if(argc >= 4){ l = argv[3][0] - '0'; if(l < 0 || l > 9) l = -1; } if(pg_n == 0 && (pg_type == MSYM_POINT_GROUP_TYPE_Cnv || pg_type == MSYM_POINT_GROUP_TYPE_Dnh) && l >= 0){ msym_element_t element = {.v = {0,0,0}, .m = 0.0, .n = 1, .name = {'\0'}}; if(MSYM_SUCCESS != (ret = msymSetElements(ctx, 1, &element))) goto err; msym_basis_function_t *basis = calloc(2*l+1,sizeof(*basis)); for(int m = -l; m <= l;m++){ int i = m+l; basis[i].type = MSYM_BASIS_TYPE_REAL_SPHERICAL_HARMONIC; basis[i].element = &element; basis[i].f.rsh.n = l+1; basis[i].f.rsh.l = l; basis[i].f.rsh.m = m; } if(MSYM_SUCCESS != (ret = msymSetBasisFunctions(ctx, 2*l+1, basis))) { free(basis); goto err; } free(basis); } if(MSYM_SUCCESS != (ret = msymGetCharacterTable(ctx, &ct))) goto err; characterTableToTex(fp,pg_type,pg_n,argv[1],ct); } else { fprintf(stderr, "usage msym_tex [angular momentum]"); } msymReleaseContext(ctx); return 0; err: error = msymErrorString(ret); fprintf(stderr,"Error %s: ",error); error = msymGetErrorDetails(); fprintf(stderr,"%s\n",error); msymReleaseContext(ctx); return ret; } void characterTableToTex(FILE *fp, msym_point_group_type_t type, int n, const char *name, const msym_character_table_t *ct){ char buf[256]; pointGroupToTex(fp,type,n,sizeof(buf),buf); fprintf(fp,"\\documentclass{article}\n\ \\usepackage{tabu}\n\ \\usepackage{adjustbox}\n\ \\begin{document}\n\ \\begin{table}[h]\n\ \\caption{$%s$ character table, where $\\theta = \\frac{2\\pi}{%d}$}\n\ \\label{tab:%s_character_table}\n\ \\begin{center}\n\ \\begin{adjustbox}{max width=\\textwidth}",buf,n,name); fprintf(fp,"\\begin{tabular}{ l | "); for(int i = 0;i < ct->d;i++) fprintf(fp,"r "); fprintf(fp,"}\n$%s$ ",buf); for(int i = 0;i < ct->d;i++){ symmetryOperationToTex(fp,ct->sops[i],sizeof(buf),buf); if(ct->classc[i] > 1) fprintf(fp,"& $%d %s$ ", ct->classc[i],buf); else fprintf(fp,"& $%s$ ", buf); } fprintf(fp,"\\\\ \\hline\n"); for(int i = 0;i < ct->d;i++){ symmetrySpeciesToTex(fp,&ct->s[i]); for(int j = 0;j < ct->d;j++){ characterToTex(fp,n,ct,i,j,2); } fprintf(fp,"\\\\\n"); } fprintf(fp,"\\end{tabular}\n\ \\end{adjustbox}\n\ \\end{center}\n\ \\end{table}\n\ \\end{document}\n"); } #ifndef M_PI #define M_PI 3.14159265358979323846264338327950288419716939937510582 #endif #define CHARACTER_EQUAL 1.0e-7 void characterToTex(FILE *fp,int n, const msym_character_table_t *ct, int i, int j, int mode){ double (*table)[ct->d] = (double (*)[ct->d]) ct->table; double c = table[i][j]; if(mode == 0){ fprintf(fp,"& $%.3lf$ ",c); return; } if(mode >= 1){ for(int k = 0;k < 5;k++){ if(fabs(round(c) - c) < CHARACTER_EQUAL){ fprintf(fp,"& $%d$ ",(int) round(c)); return; } } } double theta = (2*M_PI)/n; if(mode == 2 && n){ for(int k = 1;k < n;k++){ if(fabs(c - 2*cos(k*theta)) < CHARACTER_EQUAL){ if(k == 1) fprintf(fp,"& $2\\cos(\\theta)$ "); else fprintf(fp,"& $2\\cos(%d \\theta)$ ",k); return; } else if(fabs(c + 2*cos(k*theta)) < CHARACTER_EQUAL){ if(k == 1) fprintf(fp,"& $-2\\cos(\\theta)$ "); else fprintf(fp,"& $-2\\cos(%d \\theta)$ ",k); return; } } } fprintf(fp,"& $%.3lf$ ",c); } void symmetrySpeciesToTex(FILE *fp, msym_symmetry_species_t *s){ char *name = s->name; int prim = 0; fprintf(fp,"$"); if(s->r > 1){ fprintf(fp,"^{%d}",s->r); } fprintf(fp,"%c",name[0]); int sub = name[1] != '\0' && name[1] != '\''; if(sub) fprintf(fp,"_{"); for(int i = 1;name[i] != '\0';i++){ if(name[i] == '\'') prim++; else fprintf(fp,"%c",name[i]); } if(sub) fprintf(fp,"}"); if(prim) { fprintf(fp,"^{"); for(int i = 0;i < prim;i++) fprintf(fp,"\\prime"); fprintf(fp,"}"); } fprintf(fp,"$"); } void pointGroupToTex(FILE *fp, msym_point_group_type_t type, int n, int l, char buf[l]){ switch(type){ case MSYM_POINT_GROUP_TYPE_Ci : snprintf(buf,l,"C_{i}"); break; case MSYM_POINT_GROUP_TYPE_Cs : snprintf(buf,l,"C_{s}"); break; case MSYM_POINT_GROUP_TYPE_Cn : snprintf(buf,l,"C_{%d}",n); break; case MSYM_POINT_GROUP_TYPE_Cnh : snprintf(buf,l,"C_{%dh}",n); break; case MSYM_POINT_GROUP_TYPE_Cnv : if(n == 0) snprintf(buf,l,"C_{\\infty v}"); else snprintf(buf,l,"C_{%dv}",n); break; case MSYM_POINT_GROUP_TYPE_Dn : snprintf(buf,l,"D_{%d}",n); break; case MSYM_POINT_GROUP_TYPE_Dnh : if(n == 0) snprintf(buf,l,"D_{\\infty h}"); else snprintf(buf,l,"D_{%dh}",n); break; case MSYM_POINT_GROUP_TYPE_Dnd : snprintf(buf,l,"D_{%dd}",n); break; case MSYM_POINT_GROUP_TYPE_Sn : snprintf(buf,l,"S_{%d}",n); break; case MSYM_POINT_GROUP_TYPE_T : snprintf(buf,l,"T"); break; case MSYM_POINT_GROUP_TYPE_Td : snprintf(buf,l,"T_{d}"); break; case MSYM_POINT_GROUP_TYPE_Th : snprintf(buf,l,"T_{h}"); break; case MSYM_POINT_GROUP_TYPE_O : snprintf(buf,l,"O"); break; case MSYM_POINT_GROUP_TYPE_Oh : snprintf(buf,l,"O_{h}"); break; case MSYM_POINT_GROUP_TYPE_I : snprintf(buf,l,"I"); break; case MSYM_POINT_GROUP_TYPE_Ih : snprintf(buf,l,"I_{h}"); break; default : snprintf(buf,l,"?"); } } void symmetryOperationToTex(FILE *fp, msym_symmetry_operation_t *sop, int l, char buf[l]){ switch(sop->type){ case MSYM_SYMMETRY_OPERATION_TYPE_IDENTITY : snprintf(buf,l,"\\hat{E}"); break; case MSYM_SYMMETRY_OPERATION_TYPE_PROPER_ROTATION : if(sop->order == 2){ char *sup = NULL; switch(sop->orientation){ case MSYM_SYMMETRY_OPERATION_ORIENTATION_VERTICAL : sup = "^{\\prime}"; break; case MSYM_SYMMETRY_OPERATION_ORIENTATION_DIHEDRAL : sup = "^{\\prime\\prime}"; break; default : sup = ""; break; } snprintf(buf,l,"\\hat{C}_{%d}%s",sop->order,sup); } else if(sop->power == 1) { snprintf(buf,l,"\\hat{C}_{%d}",sop->order); } else { snprintf(buf,l,"\\hat{C}_{%d}^{%d}",sop->order,sop->power); } break; case MSYM_SYMMETRY_OPERATION_TYPE_IMPROPER_ROTATION : if(sop->power == 1) { snprintf(buf,l,"\\hat{S}_{%d}",sop->order); } else { snprintf(buf,l,"\\hat{S}_{%d}^{%d}",sop->order,sop->power); } break; case MSYM_SYMMETRY_OPERATION_TYPE_INVERSION : {snprintf(buf,l,"\\hat{\\imath}"); break;} case MSYM_SYMMETRY_OPERATION_TYPE_REFLECTION : { char *sub = NULL; switch(sop->orientation){ case MSYM_SYMMETRY_OPERATION_ORIENTATION_HORIZONTAL : sub = "_{h}"; break; case MSYM_SYMMETRY_OPERATION_ORIENTATION_VERTICAL : sub = "_{v}"; break; case MSYM_SYMMETRY_OPERATION_ORIENTATION_DIHEDRAL : sub = "_{d}"; break; default : sub = ""; break; } snprintf(buf,l,"\\hat{\\sigma}%s",sub); break; } } } v_sim-3.8.0/lib/plug-ins/msym/libmsym/libmsymConfig.cmake.in000066400000000000000000000010171370110300500240020ustar00rootroot00000000000000# LIBMSYM_INCLUDE_DIRS - include directories for FooBar # LIBMSYM_LIBRARIES - libraries to link against # Compute paths get_filename_component(LIBMSYM_CMAKE_DIR "${CMAKE_CURRENT_LIST_FILE}" PATH) set(LIBMSYM_INCLUDE_DIRS "@CONF_INCLUDE_DIRS@") # Our library dependencies (contains definitions for IMPORTED targets) if(NOT TARGET msym AND NOT LIBMSYM_BINARY_DIR) include("${LIBMSYM_CMAKE_DIR}/libmsymTargets.cmake") endif() # These are IMPORTED targets created by libmsymTargets.cmake set(LIBMSYM_LIBRARIES msym) v_sim-3.8.0/lib/plug-ins/msym/libmsym/libmsymConfigVersion.cmake.in000066400000000000000000000005741370110300500253570ustar00rootroot00000000000000set(PACKAGE_VERSION "@LIBMSYM_VERSION@") # Check whether the requested PACKAGE_FIND_VERSION is compatible if("${PACKAGE_VERSION}" VERSION_LESS "${PACKAGE_FIND_VERSION}") set(PACKAGE_VERSION_COMPATIBLE FALSE) else() set(PACKAGE_VERSION_COMPATIBLE TRUE) if ("${PACKAGE_VERSION}" VERSION_EQUAL "${PACKAGE_FIND_VERSION}") set(PACKAGE_VERSION_EXACT TRUE) endif() endif() v_sim-3.8.0/lib/plug-ins/msym/libmsym/src/000077500000000000000000000000001370110300500203615ustar00rootroot00000000000000v_sim-3.8.0/lib/plug-ins/msym/libmsym/src/basis_function.c000066400000000000000000000051561370110300500235420ustar00rootroot00000000000000// // basis_function.c // libmsym // // Created by Marcus Johansson on 07/11/14. // Copyright (c) 2014 Marcus Johansson. // // Distributed under the MIT License ( See LICENSE file or copy at http://opensource.org/licenses/MIT ) // #include #include #include "basis_function.h" //These are real shperical harmonics cannot handle complex msym_error_t basisFunctionFromQuantumNumbers(int n, int l, int m, msym_basis_function_t *bf){ if(l > n || abs(m) > l) goto err; bf->f.rsh.n = n; bf->f.rsh.l = l; bf->f.rsh.m = m; memset(bf->name,0,sizeof(bf->name)); switch(l) { case 0 : snprintf(bf->name, sizeof(bf->name), "%ds",n); break; case 1 : { char *d = "?"; switch(m) { case -1 : d = "y"; break; case 1 : d = "x"; break; case 0 : d = "z"; break; } snprintf(bf->name, sizeof(bf->name), "%dp%s",n,d); break; } case 2 : { char *d = (m < 0 ? "-" : "+"); snprintf(bf->name, sizeof(bf->name), "%dd%d%s",n,abs(m),d); break; } default : { char t = l <= 20 ? ('f' - 3 + l + (l >= 7) + (l >= 12) + (l >= 14)) : '?'; char *d = (m == 0 ? "" : m < 0 ? "-" : "+"); snprintf(bf->name, sizeof(bf->name), "%d%c%d%s",n,t,abs(m),d); } } return MSYM_SUCCESS; err: msymSetErrorDetails("Invalid orbital quantum numbers n:%d l:%d m:%d",n,l,m); return MSYM_INVALID_BASIS_FUNCTIONS; } msym_error_t basisFunctionFromName(char *name, msym_basis_function_t *bf){ int n, l, m; char cl, cm1 = '\0', cm2 = '\0'; sscanf(name,"%d%c%c%c",&n,&cl,&cm1,&cm2); switch(cl) { case 's' : l = m = 0; break; case 'p' : { l = 1; switch(cm1) { case 'x' : m = 1; break; case 'y' : m = -1; break; case 'z' : m = 0; break; default : goto err; } break; } default : if(cl < 'd' || cl == 'e' || cl == 'j' || cl > 'z') goto err; l = cl - 'd' + 2 - (cl > 'e') - (cl > 'j') - (cl > 'p') - (cl > 's'); m = (cm1 - (int)'0')*(cm2 == '-' ? -1 : 1); } return basisFunctionFromQuantumNumbers(n,l,m,bf); err: msymSetErrorDetails("Invalid orbital name %s",name); return MSYM_INVALID_BASIS_FUNCTIONS; } v_sim-3.8.0/lib/plug-ins/msym/libmsym/src/basis_function.h000066400000000000000000000010551370110300500235410ustar00rootroot00000000000000// // basis_function.h // libmsym // // Created by Marcus Johansson on 07/11/14. // Copyright (c) 2014 Marcus Johansson. // // Distributed under the MIT License ( See LICENSE file or copy at http://opensource.org/licenses/MIT ) // #ifndef __MSYM__BASIS_FUNCTION_h #define __MSYM__BASIS_FUNCTION_h #include #include "msym.h" msym_error_t basisFunctionFromName(char *, msym_basis_function_t *bf); msym_error_t basisFunctionFromQuantumNumbers(int n, int l, int m, msym_basis_function_t *bf); #endif /* defined(__MSYM__BASIS_FUNCTION_h) */ v_sim-3.8.0/lib/plug-ins/msym/libmsym/src/character_table.c000066400000000000000000001116131370110300500236330ustar00rootroot00000000000000// // character_table.c // libmsym // // Created by Marcus Johansson on 28/11/14. // Copyright (c) 2014 Marcus Johansson. // // Distributed under the MIT License ( See LICENSE file or copy at http://opensource.org/licenses/MIT ) // #include #include #include #include "character_table.h" #include "point_group.h" #include "debug.h" #ifndef M_PI #define M_PI 3.14159265358979323846264338327950288419716939937510582 #endif typedef struct _msym_representation { enum {IRREDUCIBLE = 1, REDUCIBLE = 2} type; int d; struct { int p, v, h, i, l; } eig; char name[8]; } msym_representation_t; msym_error_t verifyCharacterTable(msym_character_table_t *ct); msym_error_t setRepresentationName(msym_representation_t *rep); msym_error_t representationCharacter(int n, msym_symmetry_operation_t *sop, msym_representation_t *rep, double *c); msym_error_t getRepresentationsCi(int n, int rl, msym_representation_t rep[rl]); msym_error_t getRepresentationsCs(int n, int rl, msym_representation_t rep[rl]); msym_error_t getRepresentationsCn(int n, int rl, msym_representation_t rep[rl]); msym_error_t getRepresentationsCnh(int n, int rl, msym_representation_t rep[rl]); msym_error_t getRepresentationsCnv(int n, int rl, msym_representation_t rep[rl]); msym_error_t getRepresentationsSn(int n, int rl, msym_representation_t rep[rl]); msym_error_t getRepresentationsDn(int n, int rl, msym_representation_t rep[rl]); msym_error_t getRepresentationsDnh(int n, int rl, msym_representation_t rep[rl]); msym_error_t getRepresentationsDnd(int n, int rl, msym_representation_t rep[rl]); msym_error_t getCharacterTableT(int sopsl, msym_symmetry_operation_t sops[sopsl], msym_character_table_t *ct); msym_error_t getCharacterTableTd(int sopsl, msym_symmetry_operation_t sops[sopsl], msym_character_table_t *ct); msym_error_t getCharacterTableTh(int sopsl, msym_symmetry_operation_t sops[sopsl], msym_character_table_t *ct); msym_error_t getCharacterTableO(int sopsl, msym_symmetry_operation_t sops[sopsl], msym_character_table_t *ct); msym_error_t getCharacterTableOh(int sopsl, msym_symmetry_operation_t sops[sopsl], msym_character_table_t *ct); msym_error_t getCharacterTableI(int sopsl, msym_symmetry_operation_t sops[sopsl], msym_character_table_t *ct); msym_error_t getCharacterTableIh(int sopsl, msym_symmetry_operation_t sops[sopsl], msym_character_table_t *ct); msym_error_t getCharacterTableUnknown(int sopsl, msym_symmetry_operation_t sops[sopsl], msym_character_table_t *ct); msym_error_t getPredefinedCharacterTable(int sopsl, msym_symmetry_operation_t sops[sopsl], int l, const msym_symmetry_operation_t tsops[l], const char *tname[l], const int tdim[l], const int tred[l], const double (*table)[l], msym_character_table_t *ct); msym_error_t getRepresentationName(msym_point_group_type_t type, int n, msym_representation_t *rep, int l, char name[l]); void decomposeRepresentation(msym_character_table_t *ct, double rspan[ct->d], double dspan[ct->d]){ int order = 0; double (*ctable)[ct->d] = ct->table; memset(dspan,0, sizeof(double[ct->d])); for(int k = 0;k < ct->d;k++){ order += ct->classc[k]; for(int j = 0; j < ct->d;j++) dspan[k] += ct->classc[j]*rspan[j]*ctable[k][j]; } for(int k = 0;k < ct->d;k++) dspan[k] /= order; } void directProduct(int l, double irrep1[l], double irrep2[l], double pspan[l]){ for(int i = 0;i < l;i++) pspan[i] = irrep1[i]*irrep2[i]; } msym_error_t generateCharacterTable(msym_point_group_type_t type, int n, int sopsl, msym_symmetry_operation_t sops[sopsl], msym_character_table_t **oct){ msym_error_t ret = MSYM_SUCCESS; int d = sops[sopsl-1].cla + 1; //max cla int linear = n == 0 && ((MSYM_POINT_GROUP_TYPE_Dnh == type && sopsl == 4) || (MSYM_POINT_GROUP_TYPE_Cnv == type && sopsl == 2)); msym_character_table_t *ct = calloc(1, sizeof(msym_character_table_t) + sizeof(int[d]) + sizeof(msym_symmetry_species_t[d]) + sizeof(msym_symmetry_operation_t*[d]) + sizeof(double[d][d])); ct->table = (double (*)[d])(ct + 1); ct->s = (msym_symmetry_species_t*)((double (*)[d])ct->table + d); ct->sops = (msym_symmetry_operation_t **)(ct->s + d); ct->classc = (int *)(ct->sops + d); ct->d = d; msym_representation_t *rep = calloc(ct->d, sizeof(msym_representation_t));; double (*table)[ct->d] = (double (*)[ct->d]) ct->table; const struct _fmap { msym_point_group_type_t type; enum {REP, TAB} c; union { msym_error_t (*fr)(int, int, msym_representation_t *); msym_error_t (*ft)(int, msym_symmetry_operation_t *, msym_character_table_t *); } f; } fmap[18] = { [ 0] = {MSYM_POINT_GROUP_TYPE_Ci, REP, .f.fr = getRepresentationsCi}, [ 1] = {MSYM_POINT_GROUP_TYPE_Cs, REP, .f.fr = getRepresentationsCs}, [ 2] = {MSYM_POINT_GROUP_TYPE_Cn, REP, .f.fr = getRepresentationsCn}, [ 3] = {MSYM_POINT_GROUP_TYPE_Cnh, REP, .f.fr = getRepresentationsCnh}, [ 4] = {MSYM_POINT_GROUP_TYPE_Cnv, REP, .f.fr = getRepresentationsCnv}, [ 5] = {MSYM_POINT_GROUP_TYPE_Dn, REP, .f.fr = getRepresentationsDn}, [ 6] = {MSYM_POINT_GROUP_TYPE_Dnh, REP, .f.fr = getRepresentationsDnh}, [ 7] = {MSYM_POINT_GROUP_TYPE_Dnd, REP, .f.fr = getRepresentationsDnd}, [ 8] = {MSYM_POINT_GROUP_TYPE_Sn, REP, .f.fr = getRepresentationsSn}, [ 9] = {MSYM_POINT_GROUP_TYPE_T, TAB, .f.ft = getCharacterTableT}, [10] = {MSYM_POINT_GROUP_TYPE_Td, TAB, .f.ft = getCharacterTableTd}, [11] = {MSYM_POINT_GROUP_TYPE_Th, TAB, .f.ft = getCharacterTableTh}, [12] = {MSYM_POINT_GROUP_TYPE_O, TAB, .f.ft = getCharacterTableO}, [13] = {MSYM_POINT_GROUP_TYPE_Oh, TAB, .f.ft = getCharacterTableOh}, [14] = {MSYM_POINT_GROUP_TYPE_I, TAB, .f.ft = getCharacterTableI}, [15] = {MSYM_POINT_GROUP_TYPE_Ih, TAB, .f.ft = getCharacterTableIh}, [16] = {MSYM_POINT_GROUP_TYPE_K, TAB, .f.ft = getCharacterTableUnknown}, [17] = {MSYM_POINT_GROUP_TYPE_Kh, TAB, .f.ft = getCharacterTableUnknown} }; int fi, fil = sizeof(fmap)/sizeof(fmap[0]); for(fi = 0; fi < fil;fi++){ if(fmap[fi].type == type) { if(MSYM_SUCCESS != (ret = fmap[fi].c == REP ? fmap[fi].f.fr(n,ct->d,rep) : fmap[fi].f.ft(sopsl,sops,ct))) goto err; break; } } if(fi == fil){ msymSetErrorDetails("Unknown point group when generating character table"); ret = MSYM_POINT_GROUP_ERROR; goto err; } for(int i = 0; i < sopsl;i++){ ct->classc[sops[i].cla]++; } if(fmap[fi].c == REP){ for(int i = 0;i < ct->d;i++){ if(MSYM_SUCCESS != (ret = getRepresentationName(type, n, &rep[i], sizeof(ct->s[i].name), ct->s[i].name))) goto err; ct->s[i].d = rep[i].d; ct->s[i].r = rep[i].type; int nc = -1; for(int j = 0;j < sopsl;j++){ if(nc < sops[j].cla){ nc = sops[j].cla; if(MSYM_SUCCESS != (ret = representationCharacter(n,&sops[j],&rep[i],&table[i][nc]))) goto err; } } } } for (int i = 0; i < ct->d; i++) { for(int j = 0;j < sopsl;j++){ if(sops[j].cla == i){ ct->sops[i] = &sops[j]; break; } } } debug_printCharacterTable(ct); if(!linear && MSYM_SUCCESS != (ret = verifyCharacterTable(ct))) goto err; *oct = ct; free(rep); return ret; err: free(rep); free(ct); return ret; } #define CHARACTER_TABLE_VERIFICATION_THRESHOLD 1e-10 msym_error_t verifyCharacterTable(msym_character_table_t *ct){ msym_error_t ret = MSYM_SUCCESS; double (*table)[ct->d] = (double (*)[ct->d]) ct->table; for(int i = 0;i < ct->d && ret == MSYM_SUCCESS;i++){ for(int j = i+1;j < ct->d;j++){ double r = 0.0; for(int k = 0;k < ct->d;k++){ r += ct->classc[k]*table[i][k]*table[j][k]; } if(r > CHARACTER_TABLE_VERIFICATION_THRESHOLD){ msymSetErrorDetails("Character table verification failed irrep %s(%d) and %s(%d) are not orthogonal, product %e > %e",ct->s[i].name,i,ct->s[j].name,j,r,CHARACTER_TABLE_VERIFICATION_THRESHOLD); ret = MSYM_INVALID_CHARACTER_TABLE; } } } return ret; } msym_error_t getRepresentationsCi(int n, int rl, msym_representation_t rep[rl]){ msym_error_t ret = MSYM_SUCCESS; int r = 0; rep[r].type = IRREDUCIBLE; rep[r].d = 1; rep[r].eig.p = rep[r].eig.l = rep[r].eig.v = rep[r].eig.h = rep[r].eig.i = 1; r++; rep[r].type = IRREDUCIBLE; rep[r].d = 1; rep[r].eig.p = rep[r].eig.l = rep[r].eig.v = rep[r].eig.h = 1; rep[r].eig.i = -1; r++; return ret; //err: // return ret; } msym_error_t getRepresentationsCs(int n, int rl, msym_representation_t rep[rl]){ msym_error_t ret = MSYM_SUCCESS; int r = 0; rep[r].type = IRREDUCIBLE; rep[r].d = 1; rep[r].eig.p = rep[r].eig.l = rep[r].eig.v = rep[r].eig.h = rep[r].eig.i = 1; r++; rep[r].type = IRREDUCIBLE; rep[r].d = 1; rep[r].eig.p = rep[r].eig.l = rep[r].eig.v = rep[r].eig.i = 1; rep[r].eig.h = -1; r++; return ret; //err: // return ret; } msym_error_t getRepresentationsCn(int n, int rl, msym_representation_t rep[rl]){ msym_error_t ret = MSYM_SUCCESS; int r = 0; rep[r].type = IRREDUCIBLE; rep[r].d = 1; rep[r].eig.p = rep[r].eig.l = rep[r].eig.v = rep[r].eig.h = rep[r].eig.i = 1; r++; if(!(n & 1)){ rep[r].type = IRREDUCIBLE; rep[r].d = 1; rep[r].eig.l = rep[r].eig.v = rep[r].eig.h = rep[r].eig.i = 1; rep[r].eig.p = -1; r++; } for(int i = 1;r < rl;i++, r++){ rep[r].type = REDUCIBLE; rep[r].d = 2; rep[r].eig.l = i; rep[r].eig.p = rep[r].eig.v = rep[r].eig.h = rep[r].eig.i = 1; } return ret; //err: // return ret; } msym_error_t getRepresentationsCnh(int n, int rl, msym_representation_t rep[rl]){ msym_error_t ret = MSYM_SUCCESS; int r = 0; rep[r].type = IRREDUCIBLE; rep[r].d = 1; rep[r].eig.p = rep[r].eig.l = rep[r].eig.v = rep[r].eig.h = rep[r].eig.i = 1; r++; rep[r].type = IRREDUCIBLE; rep[r].d = 1; rep[r].eig.p = rep[r].eig.l = rep[r].eig.v = 1; rep[r].eig.h = rep[r].eig.i = -1; r++; if(!(n & 1)){ rep[r].type = IRREDUCIBLE; rep[r].d = 1; rep[r].eig.l = rep[r].eig.v = rep[r].eig.i = 1; rep[r].eig.p = -1; rep[r].eig.h = 1 - (n & 2); r++; rep[r].type = IRREDUCIBLE; rep[r].d = 1; rep[r].eig.l = rep[r].eig.v = 1; rep[r].eig.p = rep[r].eig.i = -1; rep[r].eig.h = -1 + (n & 2); r++; } for(int i = 1;r < rl;i++){ rep[r].type = REDUCIBLE; rep[r].d = 2; rep[r].eig.l = i; rep[r].eig.p = rep[r].eig.v = rep[r].eig.h = 1; rep[r].eig.i = 1 - ((i & 1) << 1); r++; rep[r].type = REDUCIBLE; rep[r].d = 2; rep[r].eig.l = i; rep[r].eig.p = rep[r].eig.v = 1; rep[r].eig.h = -1; rep[r].eig.i = -1 + ((i & 1) << 1); r++; } return ret; //err: // return ret; } msym_error_t getRepresentationsCnv(int n, int rl, msym_representation_t rep[rl]){ msym_error_t ret = MSYM_SUCCESS; int r = 0; rep[r].type = IRREDUCIBLE; rep[r].d = 1; rep[r].eig.p = rep[r].eig.l = rep[r].eig.v = rep[r].eig.h = rep[r].eig.i = 1; r++; rep[r].type = IRREDUCIBLE; rep[r].d = 1; rep[r].eig.p = rep[r].eig.l = rep[r].eig.h = rep[r].eig.i = 1; rep[r].eig.v = -1; r++; if(n && !(n & 1)){ rep[r].type = IRREDUCIBLE; rep[r].d = 1; rep[r].eig.l = rep[r].eig.v = rep[r].eig.i = rep[r].eig.h = 1; rep[r].eig.p = -1; r++; rep[r].type = IRREDUCIBLE; rep[r].d = 1; rep[r].eig.l = rep[r].eig.h = rep[r].eig.i = 1 ; rep[r].eig.p = rep[r].eig.v = -1; r++; } for(int i = 1;r < rl;i++, r++){ rep[r].type = (n == 0 && (r == rl - 1)) ? REDUCIBLE : IRREDUCIBLE; rep[r].d = 2; rep[r].eig.l = i; rep[r].eig.p = rep[r].eig.v = rep[r].eig.h = rep[r].eig.i = 1; } return ret; //err: // return ret; } msym_error_t getRepresentationsSn(int n, int rl, msym_representation_t rep[rl]){ msym_error_t ret = MSYM_SUCCESS; int r = 0; rep[r].type = IRREDUCIBLE; rep[r].d = 1; rep[r].eig.p = rep[r].eig.l = rep[r].eig.v = rep[r].eig.h = rep[r].eig.i = 1; r++; rep[r].type = IRREDUCIBLE; rep[r].d = 1; rep[r].eig.p = rep[r].eig.l = rep[r].eig.v = 1; rep[r].eig.h = rep[r].eig.i = -1; r++; if(!((n >> 1) & 1)){ for(int i = 1;r < rl;i++, r++){ rep[r].type = REDUCIBLE; rep[r].d = 2; rep[r].eig.l = i; rep[r].eig.p = rep[r].eig.v = rep[r].eig.h = rep[r].eig.i = 1; } } else { for(int i = 1;r < rl;i++){ rep[r].type = REDUCIBLE; rep[r].d = 2; rep[r].eig.l = i; rep[r].eig.p = rep[r].eig.v = rep[r].eig.i = 1; rep[r].eig.h = 1 - ((i % 2) << 1); r++; rep[r].type = REDUCIBLE; rep[r].d = 2; rep[r].eig.l = i; rep[r].eig.p = rep[r].eig.v = 1; rep[r].eig.h = -1 + ((i % 2) << 1); rep[r].eig.i = -1; r++; } } return ret; //err: // return ret; } msym_error_t getRepresentationsDn(int n, int rl, msym_representation_t rep[rl]){ msym_error_t ret = MSYM_SUCCESS; int r = 0; rep[r].type = IRREDUCIBLE; rep[r].d = 1; rep[r].eig.p = rep[r].eig.l = rep[r].eig.v = rep[r].eig.h = rep[r].eig.i = 1; r++; rep[r].type = IRREDUCIBLE; rep[r].d = 1; rep[r].eig.p = rep[r].eig.l = rep[r].eig.h = rep[r].eig.i = 1; rep[r].eig.v = -1; r++; if(~n & 1){ rep[r].type = IRREDUCIBLE; rep[r].d = 1; rep[r].eig.l = rep[r].eig.v = rep[r].eig.i = rep[r].eig.h = 1; rep[r].eig.p = -1; r++; rep[r].type = IRREDUCIBLE; rep[r].d = 1; rep[r].eig.l = rep[r].eig.h = rep[r].eig.i = 1 ; rep[r].eig.p = rep[r].eig.v = -1; r++; } for(int i = 1;r < rl;i++, r++){ rep[r].type = IRREDUCIBLE; rep[r].d = 2; rep[r].eig.l = i; rep[r].eig.p = rep[r].eig.v = rep[r].eig.h = rep[r].eig.i = 1; } return ret; //err: // return ret; } msym_error_t getRepresentationsDnh(int n, int rl, msym_representation_t rep[rl]){ msym_error_t ret = MSYM_SUCCESS; int r = 0; rep[r].type = IRREDUCIBLE; rep[r].d = 1; rep[r].eig.p = rep[r].eig.l = rep[r].eig.v = rep[r].eig.h = rep[r].eig.i = 1; r++; rep[r].type = IRREDUCIBLE; rep[r].d = 1; rep[r].eig.p = rep[r].eig.l = rep[r].eig.h = rep[r].eig.i = 1; rep[r].eig.v = -1; r++; rep[r].type = IRREDUCIBLE; rep[r].d = 1; rep[r].eig.p = rep[r].eig.l = rep[r].eig.v = 1; rep[r].eig.h = rep[r].eig.i = -1; r++; rep[r].type = IRREDUCIBLE; rep[r].d = 1; rep[r].eig.p = rep[r].eig.l = 1; rep[r].eig.h = rep[r].eig.i = rep[r].eig.v = -1; r++; if(n && !(n & 1)){ rep[r].type = IRREDUCIBLE; rep[r].d = 1; rep[r].eig.l = rep[r].eig.v = rep[r].eig.i = 1; rep[r].eig.p = -1; rep[r].eig.h = 1 - (n & 2); r++; rep[r].type = IRREDUCIBLE; rep[r].d = 1; rep[r].eig.l = rep[r].eig.v = 1; rep[r].eig.p = rep[r].eig.i = -1; rep[r].eig.h = -1 + (n & 2); r++; rep[r].type = IRREDUCIBLE; rep[r].d = 1; rep[r].eig.l = rep[r].eig.i = 1; rep[r].eig.p = rep[r].eig.v = -1; rep[r].eig.h = 1 - (n & 2); r++; rep[r].type = IRREDUCIBLE; rep[r].d = 1; rep[r].eig.l = 1; rep[r].eig.p = rep[r].eig.v = rep[r].eig.i = -1; rep[r].eig.h = -1 + (n & 2); r++; } for(int i = 1;r < rl;i++){ rep[r].type = (n == 0 && (r == rl - 2)) ? REDUCIBLE : IRREDUCIBLE; rep[r].d = 2; rep[r].eig.l = i; rep[r].eig.p = rep[r].eig.v = rep[r].eig.h = 1; rep[r].eig.i = 1 - ((i & 1) << 1); r++; rep[r].type = (n == 0 && (r == rl - 1)) ? REDUCIBLE : IRREDUCIBLE; rep[r].d = 2; rep[r].eig.l = i; rep[r].eig.p = rep[r].eig.v = 1; rep[r].eig.h = -1; rep[r].eig.i = -1 + ((i & 1) << 1); r++; } return ret; //err: // return ret; } msym_error_t getRepresentationsDnd(int n, int rl, msym_representation_t rep[rl]){ msym_error_t ret = MSYM_SUCCESS; int r = 0; rep[r].type = IRREDUCIBLE; rep[r].d = 1; rep[r].eig.p = rep[r].eig.l = rep[r].eig.v = rep[r].eig.h = rep[r].eig.i = 1; r++; rep[r].type = IRREDUCIBLE; rep[r].d = 1; rep[r].eig.p = rep[r].eig.l = rep[r].eig.h = rep[r].eig.i = 1; rep[r].eig.v = -1; r++; if(!(n & 1)){ rep[r].type = IRREDUCIBLE; rep[r].d = 1; rep[r].eig.l = rep[r].eig.v = rep[r].eig.i = rep[r].eig.p = 1; rep[r].eig.h = -1; r++; rep[r].type = IRREDUCIBLE; rep[r].d = 1; rep[r].eig.l = rep[r].eig.i = rep[r].eig.p = 1 ; rep[r].eig.h = rep[r].eig.v = -1; r++; for(int i = 1;r < rl;i++, r++){ rep[r].type = IRREDUCIBLE; rep[r].d = 2; rep[r].eig.l = i; rep[r].eig.p = rep[r].eig.v = rep[r].eig.h = rep[r].eig.i = 1; } } else { rep[r].type = IRREDUCIBLE; rep[r].d = 1; rep[r].eig.l = rep[r].eig.v = rep[r].eig.p = 1; rep[r].eig.h = rep[r].eig.i = -1; r++; rep[r].type = IRREDUCIBLE; rep[r].d = 1; rep[r].eig.l = rep[r].eig.p = 1 ; rep[r].eig.h = rep[r].eig.i = rep[r].eig.v = -1; r++; for(int i = 1;r < rl;i++){ rep[r].type = IRREDUCIBLE; rep[r].d = 2; rep[r].eig.l = i; rep[r].eig.p = rep[r].eig.v = rep[r].eig.i = 1; rep[r].eig.h = 1 - ((i % 2) << 1); r++; rep[r].type = IRREDUCIBLE; rep[r].d = 2; rep[r].eig.l = i; rep[r].eig.p = rep[r].eig.v = 1; rep[r].eig.h = -1 + ((i % 2) << 1); rep[r].eig.i = -1; r++; } } return ret; //err: // return ret; } msym_error_t representationCharacter(int n, msym_symmetry_operation_t *sop, msym_representation_t *rep, double *c){ msym_error_t ret = MSYM_SUCCESS; double x = 0; if(sop->orientation == HORIZONTAL){ switch(rep->d) { case 1: { switch (sop->type) { case IDENTITY : x = 1; break; case REFLECTION : x = rep->eig.h; break; case INVERSION : x = rep->eig.i; break; case PROPER_ROTATION : x = !n || ((n/sop->order) & 1) ? rep->eig.p : 1 ; break; case IMPROPER_ROTATION : x = rep->eig.h*(!n || ((n/sop->order) & 1) ? rep->eig.p : 1); break; default : ret = MSYM_INVALID_CHARACTER_TABLE; msymSetErrorDetails("Invalid symmetry operation when building character table"); goto err; } break; } case 2 : { switch (sop->type) { case IDENTITY : x = 2; break; case REFLECTION : x = 2*rep->eig.h; break; case INVERSION : x = 2*rep->eig.i; break; case PROPER_ROTATION : x = 2*cos(2*rep->eig.l*sop->power*(M_PI/sop->order)); break; case IMPROPER_ROTATION : x = rep->eig.h*2*cos(2*rep->eig.l*sop->power*(M_PI/sop->order)); break; default : ret = MSYM_INVALID_CHARACTER_TABLE; msymSetErrorDetails("Invalid symmetry operation when building character table"); goto err; } break; } default : ret = MSYM_INVALID_CHARACTER_TABLE; msymSetErrorDetails("Invalid dimension (%d) of irreducible representation for point group",rep->d); goto err; } } else { switch(rep->d) { case 1: { switch (sop->type) { case IDENTITY : x = 1; break; case INVERSION : x = rep->eig.i; break; case REFLECTION : x = sop->orientation == VERTICAL ? rep->eig.v*rep->eig.h : rep->eig.p*rep->eig.v*rep->eig.h; break; case PROPER_ROTATION : x = sop->orientation == VERTICAL ? rep->eig.v : rep->eig.p*rep->eig.v; break; case IMPROPER_ROTATION : default : ret = MSYM_INVALID_CHARACTER_TABLE; msymSetErrorDetails("Invalid symmetry operation when building character table"); goto err; } break; } case 2 : { switch (sop->type) { case IDENTITY : x = 2; break; case REFLECTION : x = 0; break; case INVERSION : x = 2*rep->eig.i; break; case PROPER_ROTATION : x = 0; break; case IMPROPER_ROTATION : default : ret = MSYM_INVALID_CHARACTER_TABLE; msymSetErrorDetails("Invalid symmetry operation when building character table"); goto err; } break; } default : ret = MSYM_INVALID_CHARACTER_TABLE; msymSetErrorDetails("Invalid dimension (%d) of irreducible representation for point group",rep->d); goto err; } } *c = x; err: return ret; } msym_error_t getCharacterTableUnknown(int sopsl, msym_symmetry_operation_t sops[sopsl], msym_character_table_t *ct){ msym_error_t ret = MSYM_SUCCESS; msymSetErrorDetails("Character table NYI"); ret = MSYM_INVALID_CHARACTER_TABLE; //err: return ret; } msym_error_t getCharacterTableT(int sopsl, msym_symmetry_operation_t sops[sopsl], msym_character_table_t *ct){ msym_error_t ret = MSYM_SUCCESS; const msym_symmetry_operation_t tsops[3] = { [0] = {.type = IDENTITY, .order = 1, .power = 1, .orientation = NONE}, [1] = {.type = PROPER_ROTATION, .order = 3, .power = 1, .orientation = NONE}, [2] = {.type = PROPER_ROTATION, .order = 2, .power = 1, .orientation = HORIZONTAL} }; const char *tname[3] = {"A","E","T"}; const int tdim[3] = {1,2,3}; const int tred[3] = {1,2,1}; const double table[][3] = { [0] = {1, 1, 1}, [1] = {2, -1, 2}, // Reducible to {1 e e* 1},{1 e* e 1} where e = e^(i2pi/3) [2] = {3, 0, -1} }; if(MSYM_SUCCESS != (ret = getPredefinedCharacterTable(sopsl, sops, 3, tsops, tname, tdim, tred, table, ct))) goto err; err: return ret; } msym_error_t getCharacterTableTd(int sopsl, msym_symmetry_operation_t sops[sopsl], msym_character_table_t *ct){ msym_error_t ret = MSYM_SUCCESS; const msym_symmetry_operation_t tsops[5] = { [0] = {.type = IDENTITY, .order = 1, .power = 1, .orientation = NONE}, [1] = {.type = PROPER_ROTATION, .order = 2, .power = 1, .orientation = HORIZONTAL}, [2] = {.type = PROPER_ROTATION, .order = 3, .power = 1, .orientation = NONE}, [3] = {.type = IMPROPER_ROTATION, .order = 4, .power = 1, .orientation = HORIZONTAL}, [4] = {.type = REFLECTION, .order = 1, .power = 1, .orientation = DIHEDRAL}, }; const char *tname[5] = {"A1","A2","E","T1","T2"}; const int tdim[5] = {1,1,2,3,3}; const int tred[5] = {1,1,1,1,1}; const double table[][5] = { [0] = {1, 1, 1, 1, 1}, [1] = {1, 1, 1, -1, -1}, [2] = {2, 2, -1, 0, 0}, [3] = {3, -1, 0, 1, -1}, [4] = {3, -1, 0, -1, 1} }; if(MSYM_SUCCESS != (ret = getPredefinedCharacterTable(sopsl, sops, 5, tsops, tname, tdim, tred, table, ct))) goto err; err: return ret; } msym_error_t getCharacterTableTh(int sopsl, msym_symmetry_operation_t sops[sopsl], msym_character_table_t *ct){ msym_error_t ret = MSYM_SUCCESS; const msym_symmetry_operation_t tsops[6] = { [0] = {.type = IDENTITY, .order = 1, .power = 1, .orientation = NONE}, [1] = {.type = PROPER_ROTATION, .order = 3, .power = 1, .orientation = NONE}, [2] = {.type = PROPER_ROTATION, .order = 2, .power = 1, .orientation = HORIZONTAL}, [3] = {.type = INVERSION, .order = 1, .power = 1, .orientation = NONE}, [4] = {.type = IMPROPER_ROTATION, .order = 6, .power = 1, .orientation = NONE}, [5] = {.type = REFLECTION, .order = 1, .power = 1, .orientation = HORIZONTAL} }; const char *tname[6] = {"Ag","Au","Eg","Eu","Tg","Tu"}; const int tdim[6] = {1,1,2,2,3,3}; const int tred[6] = {1,1,2,2,1,1}; const double table[][6] = { [0] = {1, 1, 1, 1, 1, 1}, [1] = {1, 1, 1, -1, -1, -1}, [2] = {2, -1, 2, 2, -1, 2}, [3] = {2, -1, 2, -2, 1, -2}, [4] = {3, 0, -1, 3, 0, -1}, [5] = {3, 0, -1, -3, 0, 1} }; if(MSYM_SUCCESS != (ret = getPredefinedCharacterTable(sopsl, sops, 6, tsops, tname, tdim, tred, table, ct))) goto err; err: return ret; } msym_error_t getCharacterTableO(int sopsl, msym_symmetry_operation_t sops[sopsl], msym_character_table_t *ct){ msym_error_t ret = MSYM_SUCCESS; const msym_symmetry_operation_t tsops[5] = { [0] = {.type = IDENTITY, .order = 1, .power = 1, .orientation = NONE}, [1] = {.type = PROPER_ROTATION, .order = 3, .power = 1, .orientation = NONE}, [2] = {.type = PROPER_ROTATION, .order = 2, .power = 1, .orientation = VERTICAL}, [3] = {.type = PROPER_ROTATION, .order = 4, .power = 1, .orientation = HORIZONTAL}, [4] = {.type = PROPER_ROTATION, .order = 2, .power = 1, .orientation = HORIZONTAL} }; const double table[][5] = { [0] = {1, 1, 1, 1, 1}, [1] = {1, 1, -1, -1, 1}, [2] = {2, -1, 0, 0, 2}, [3] = {3, 0, -1, 1, -1}, [4] = {3, 0, 1, -1, -1} }; const char *tname[5] = {"A1","A2","E","T1","T2"}; const int tdim[5] = {1,1,2,3,3}; const int tred[5] = {1,1,1,1,1}; if(MSYM_SUCCESS != (ret = getPredefinedCharacterTable(sopsl, sops, 5, tsops, tname, tdim, tred, table, ct))) goto err; err: return ret; } msym_error_t getCharacterTableOh(int sopsl, msym_symmetry_operation_t sops[sopsl], msym_character_table_t *ct){ msym_error_t ret = MSYM_SUCCESS; const msym_symmetry_operation_t tsops[10] = { [0] = {.type = IDENTITY, .order = 1, .power = 1, .orientation = NONE}, [1] = {.type = PROPER_ROTATION, .order = 4, .power = 1, .orientation = HORIZONTAL}, [2] = {.type = PROPER_ROTATION, .order = 2, .power = 1, .orientation = HORIZONTAL}, [3] = {.type = PROPER_ROTATION, .order = 3, .power = 1, .orientation = NONE}, [4] = {.type = PROPER_ROTATION, .order = 2, .power = 1, .orientation = VERTICAL}, [5] = {.type = INVERSION, .order = 1, .power = 1, .orientation = NONE}, [6] = {.type = IMPROPER_ROTATION, .order = 4, .power = 1, .orientation = HORIZONTAL}, [7] = {.type = IMPROPER_ROTATION, .order = 6, .power = 1, .orientation = NONE}, [8] = {.type = REFLECTION, .order = 1, .power = 1, .orientation = HORIZONTAL}, [9] = {.type = REFLECTION, .order = 1, .power = 1, .orientation = DIHEDRAL} }; const double table[][10] = { [0] = {1, 1, 1, 1, 1, 1, 1, 1, 1, 1}, [1] = {1, 1, 1, 1, 1, -1, -1, -1, -1, -1}, [2] = {1, -1, 1, 1, -1, 1, -1, 1, 1, -1}, [3] = {1, -1, 1, 1, -1, -1, 1, -1, -1, 1}, [4] = {2, 0, 2, -1, 0, 2, 0, -1, 2, 0}, [5] = {2, 0, 2, -1, 0, -2, 0, 1, -2, 0}, [6] = {3, 1, -1, 0, -1, 3, 1, 0, -1, -1}, [7] = {3, 1, -1, 0, -1, -3, -1, 0, 1, 1}, [8] = {3, -1, -1, 0, 1, 3, -1, 0, -1, 1}, [9] = {3, -1, -1, 0, 1, -3, 1, 0, 1, -1} }; const char *tname[10] = {"A1g", "A1u", "A2g", "A2u", "Eg", "Eu", "T1g", "T1u", "T2g", "T2u"}; const int tdim[10] = {1,1,1,1,2,2,3,3,3,3}; const int tred[10] = {1,1,1,1,1,1,1,1,1,1}; if(MSYM_SUCCESS != (ret = getPredefinedCharacterTable(sopsl, sops, 10, tsops, tname, tdim, tred, table, ct))) goto err; err: return ret; } #define C4PI (-1.61803398874989484820458683436563811772030917980576286213544) //(2*cos(4*M_PI/5)) #define C2PI (0.618033988749894848204586834365638117720309179805762862135448) //(2*cos(2*M_PI/5)) msym_error_t getCharacterTableI(int sopsl, msym_symmetry_operation_t sops[sopsl], msym_character_table_t *ct){ msym_error_t ret = MSYM_SUCCESS; const msym_symmetry_operation_t tsops[5] = { [0] = {.type = IDENTITY, .order = 1, .power = 1, .orientation = NONE}, [1] = {.type = PROPER_ROTATION, .order = 2, .power = 1, .orientation = NONE}, [2] = {.type = PROPER_ROTATION, .order = 3, .power = 1, .orientation = NONE}, [3] = {.type = PROPER_ROTATION, .order = 5, .power = 1, .orientation = NONE}, [4] = {.type = PROPER_ROTATION, .order = 5, .power = 2, .orientation = NONE}, }; const char *tname[5] = {"A","T1","T2","G","H"}; const int tdim[5] = {1,3,3,4,5}; const int tred[5] = {1,1,1,1,1}; // E C2 C3 C5 C52 const double table[][5] = { [0] = {1, 1, 1, 1, 1}, [1] = {3, -1, 0, -C4PI, -C2PI}, [2] = {3, -1, 0, -C2PI, -C4PI}, [3] = {4, 0, 1, -1, -1}, [4] = {5, 1, -1, 0, 0} }; if(MSYM_SUCCESS != (ret = getPredefinedCharacterTable(sopsl, sops, 5, tsops, tname, tdim, tred, table, ct))) goto err; err: return ret; } msym_error_t getCharacterTableIh(int sopsl, msym_symmetry_operation_t sops[sopsl], msym_character_table_t *ct){ msym_error_t ret = MSYM_SUCCESS; const msym_symmetry_operation_t tsops[10] = { [0] = {.type = IDENTITY, .order = 1, .power = 1, .orientation = NONE}, [1] = {.type = PROPER_ROTATION, .order = 2, .power = 1, .orientation = NONE}, [2] = {.type = REFLECTION, .order = 1, .power = 1, .orientation = NONE}, [3] = {.type = IMPROPER_ROTATION, .order = 6, .power = 1, .orientation = NONE}, [4] = {.type = PROPER_ROTATION, .order = 5, .power = 1, .orientation = NONE}, [5] = {.type = IMPROPER_ROTATION, .order = 10, .power = 1, .orientation = NONE}, [6] = {.type = PROPER_ROTATION, .order = 5, .power = 2, .orientation = NONE}, [7] = {.type = INVERSION, .order = 1, .power = 1, .orientation = NONE}, [8] = {.type = PROPER_ROTATION, .order = 3, .power = 1, .orientation = NONE}, [9] = {.type = IMPROPER_ROTATION, .order = 10, .power = 3, .orientation = NONE}, }; const char *tname[10] = {"Ag","Au","T1g","T1u","T2g","T2u","Gg","Gu","Hg","Hu"}; const int tdim[10] = {1,1,3,3,3,3,4,4,5,5}; const int tred[10] = {1,1,1,1,1,1,1,1,1,1}; // E C2 R S6 C5 S10 C52 i C3 S103 static const double table[][10] = { [0] = {1, 1, 1, 1, 1, 1, 1, 1, 1, 1 }, [1] = {1, 1, -1, -1, 1, -1, 1, -1, 1, -1 }, [2] = {3, -1, -1, 0, -C4PI, -C2PI, -C2PI, 3, 0, -C4PI }, [3] = {3, -1, 1, 0, -C4PI, C2PI, -C2PI, -3, 0, C4PI }, [4] = {3, -1, -1, 0, -C2PI, -C4PI, -C4PI, 3, 0, -C2PI }, [5] = {3, -1, 1, 0, -C2PI, C4PI, -C4PI, -3, 0, C2PI }, [6] = {4, 0, 0, 1, -1, -1, -1, 4, 1, -1 }, [7] = {4, 0, 0, -1, -1, 1, -1, -4, 1, 1 }, [8] = {5, 1, 1, -1, 0, 0, 0, 5, -1, 0 }, [9] = {5, 1, -1, 1, 0, 0, 0, -5, -1, 0 } }; if(MSYM_SUCCESS != (ret = getPredefinedCharacterTable(sopsl, sops, 10, tsops, tname, tdim, tred, table, ct))) goto err; err: return ret; } msym_error_t getPredefinedCharacterTable(int sopsl, msym_symmetry_operation_t sops[sopsl], int l, const msym_symmetry_operation_t tsops[l], const char *tname[l], const int tdim[l], const int tred[l], const double (*table)[l], msym_character_table_t *ct){ msym_error_t ret = MSYM_SUCCESS; double (*ctable)[l] = ct->table; if(ct->d != l){ msymSetErrorDetails("Unexpected size of character table %d != %d",l,ct->d); ret = MSYM_INVALID_CHARACTER_TABLE; goto err; } for(int i = 0; i < l;i++){ ct->s[i].d = tdim[i]; ct->s[i].r = tred[i]; snprintf(ct->s[i].name, sizeof(ct->s[i].name), "%s",tname[i]); msym_symmetry_operation_t *sop = NULL; for(sop = sops;sop < (sops + sopsl);sop++){ if(tsops[i].type == sop->type && tsops[i].order == sop->order && tsops[i].power == sop->power && tsops[i].orientation == sop->orientation){ int cla = sop->cla; if(cla >= l){ msymSetErrorDetails("Conjugacy class exceeds character table size %d >= %d",sop->cla,l); ret = MSYM_INVALID_CHARACTER_TABLE; goto err; } for(int j = 0;j < l;j++){ ctable[j][cla] = table[j][i]; } break; } } if(sop >= (sops + sopsl)){ msymSetErrorDetails("Could not find representative symmetry operation when generating character table"); ret = MSYM_INVALID_CHARACTER_TABLE; goto err; } } err: return ret; } msym_error_t getRepresentationName(msym_point_group_type_t type, int n, msym_representation_t *rep, int l, char name[l]){ msym_error_t ret = MSYM_SUCCESS; if(rep->d < 1 || rep->d > 5 || abs(rep->eig.p) > 1 || abs(rep->eig.v) > 1 || abs(rep->eig.h) > 1 || abs(rep->eig.i) > 1) { ret = MSYM_INVALID_CHARACTER_TABLE; msymSetErrorDetails("Invalid character table represenation"); goto err; } int eindex[4] = {rep->eig.p, rep->eig.h,rep->eig.v,rep->eig.i}; switch (type) { case MSYM_POINT_GROUP_TYPE_Ci : eindex[1] = eindex[2] = 0; break; case MSYM_POINT_GROUP_TYPE_Cs : eindex[2] = eindex[3] = 0; break; case MSYM_POINT_GROUP_TYPE_Cn : eindex[1] = eindex[2] = eindex[3] = 0; break; case MSYM_POINT_GROUP_TYPE_Cnv : eindex[1] = eindex[3] = 0; break; case MSYM_POINT_GROUP_TYPE_Cnh : if(n & 1){eindex[3] = 0;} else {eindex[1] = 0;} eindex[2] = 0; break; case MSYM_POINT_GROUP_TYPE_Sn : if(!((n >> 1) & 1)){eindex[3] = 0; eindex[0] = rep->eig.h;} eindex[1] = eindex[2] = 0; break; break; case MSYM_POINT_GROUP_TYPE_Dn : if(n == 2 && eindex[0]+eindex[2] == 0){ eindex[0] = eindex[0]*eindex[2]; eindex[2] = ((eindex[2] + 1) >> 1) + 1; } eindex[1] = 0; eindex[3] = 0; break; case MSYM_POINT_GROUP_TYPE_Dnd : if(!(n & 1)){eindex[3] = 0; eindex[0] = rep->eig.h;} eindex[1] = 0; break; case MSYM_POINT_GROUP_TYPE_Dnh : if(n == 2 && eindex[0]+eindex[2] == 0){ eindex[0] = eindex[0]*eindex[2]; eindex[2] = ((eindex[2] + 1) >> 1) + 1; } if(n & 1){eindex[3] = 0;} else {eindex[1] = 0;} break; default: break; } char types[] = {'A','B','E','T','G','H'}, *si[] = {"u","","g"}, *sv[] = {"2", "", "1", "3"}, *sh[] = {"''", "", "'"}; char rtype = rep->d == 1 ? types[(1 - eindex[0]) >> 1] : types[rep->d]; if(rep->d == 1){ snprintf(name,sizeof(char[l]),"%c%s%s%s",rtype,sv[eindex[2]+1],si[eindex[3]+1],sh[eindex[1]+1]); } else if (rep->eig.l > 0){ snprintf(name,sizeof(char[l]),"%c%d%s%s",rtype,rep->eig.l,si[eindex[3]+1],sh[eindex[1]+1]); } else { snprintf(name,sizeof(char[l]),"%c%s%s",rtype,si[eindex[3]+1],sh[eindex[1]+1]); } err: return ret; } v_sim-3.8.0/lib/plug-ins/msym/libmsym/src/character_table.h000066400000000000000000000013341370110300500236360ustar00rootroot00000000000000// // character_table.h // libmsym // // Created by Marcus Johansson on 28/11/14. // Copyright (c) 2014 Marcus Johansson. // // Distributed under the MIT License ( See LICENSE file or copy at http://opensource.org/licenses/MIT ) // #ifndef __MSYM__CHARACTER_TABLE_h #define __MSYM__CHARACTER_TABLE_h #include "msym.h" #include "symop.h" void decomposeRepresentation(msym_character_table_t *ct, double rspan[ct->d], double dspan[ct->d]); void directProduct(int l, double irrep1[l], double irrep2[l], double pspan[l]); msym_error_t generateCharacterTable(msym_point_group_type_t type, int n, int sopsl, msym_symmetry_operation_t sops[sopsl], msym_character_table_t **ct); #endif /* defined(__MSYM__CHARACTER_TABLE_h) */ v_sim-3.8.0/lib/plug-ins/msym/libmsym/src/context.c000066400000000000000000000703331370110300500222170ustar00rootroot00000000000000// // context.c // libmsym // // Created by Marcus Johansson on 30/01/15. // Copyright (c) 2015 Marcus Johansson. // // Distributed under the MIT License ( See LICENSE file or copy at http://opensource.org/licenses/MIT ) // #include #include #include #include "msym.h" #include "context.h" #include "elements.h" #include "equivalence_set.h" #include "geometry.h" #include "linalg.h" #include "subspace.h" #include "debug.h" const msym_thresholds_t default_thresholds = { .zero = DEFAULT_ZERO_THRESHOLD, .geometry = DEFAULT_GEOMETRY_THRESHOLD, .angle = DEFAULT_ANGLE_THRESHOLD, .equivalence = DEFAULT_EQUIVALENCE_THRESHOLD, .eigfact = DEFAULT_EIGFACT_THRESHOLD, .permutation = DEFAULT_PERMUTATION_THRESHOLD, .orthogonalization = DEFAULT_ORTHOGONALIZATION_THRESHOLD }; struct _msym_context { msym_thresholds_t *thresholds; msym_element_t *elements; msym_element_t **pelements; msym_basis_function_t *basis; msym_equivalence_set_t *es; msym_permutation_t **es_perm; msym_subrepresentation_space_t *srs; msym_basis_function_t **srsbf; int *srs_span; unsigned long int flags; int elementsl; int basisl; int esl; int srsl; int es_perml; int sgl; msym_point_group_t *pg; msym_subgroup_t *sg; double cm[3]; msym_geometry_t geometry; double eigval[3]; double eigvec[3][3]; struct _external_data { msym_equivalence_set_t **eesmap; msym_element_t *set_elements_ptr; msym_element_t *elements; msym_equivalence_set_t *es; } ext; }; /*********************** * Public API ***********************/ msym_context msymCreateContext(){ msym_context ctx = malloc(sizeof(struct _msym_context)); msym_thresholds_t *threshols = malloc(sizeof(msym_thresholds_t)); //Don't generally handle allocation errors... if(ctx == NULL) {msymSetErrorDetails("Context memory allocation failed"); goto err;} if(threshols == NULL) {msymSetErrorDetails("Thresholds memory allocation failed"); goto err;} memset(ctx, 0, sizeof(struct _msym_context)); ctx->geometry = MSYM_GEOMETRY_UNKNOWN; ctx->thresholds = threshols; msymSetThresholds(ctx, &default_thresholds); return ctx; err : free(ctx); free(threshols); return NULL; } const msym_thresholds_t *msymGetDefaultThresholds(){ return &default_thresholds; } msym_error_t msymSetThresholds(msym_context ctx, const msym_thresholds_t *thresholds){ msym_error_t ret = MSYM_SUCCESS; if(NULL == ctx) {ret = MSYM_INVALID_CONTEXT;goto err;} if(NULL != thresholds && thresholds->angle < 1.0 && !signbit(thresholds->angle) && thresholds->equivalence < 1.0 && !signbit(thresholds->equivalence) && thresholds->geometry < 1.0 && !signbit(thresholds->geometry) && !signbit(thresholds->eigfact) && !signbit(thresholds->orthogonalization) && !signbit(thresholds->zero) && !signbit(thresholds->permutation)){ if(ctx->thresholds != thresholds) memcpy(ctx->thresholds, thresholds, sizeof(msym_thresholds_t)); } else { ret = MSYM_INVALID_THRESHOLD; goto err; } err: return ret; } msym_error_t msymGetThresholds(msym_context ctx, const msym_thresholds_t **thresholds){ msym_error_t ret = MSYM_SUCCESS; if(ctx == NULL) {ret = MSYM_INVALID_CONTEXT; return ret;} if(ctx->thresholds == NULL) ret = MSYM_INVALID_THRESHOLD; *thresholds = ctx->thresholds; err: return ret; } msym_error_t msymSetElements(msym_context ctx, int length, msym_element_t *elements){ msym_error_t ret = MSYM_SUCCESS; if(ctx == NULL) {ret = MSYM_INVALID_CONTEXT; return ret;} /* Allow manual setting of point group before elements */ if(NULL != ctx->es) ctxDestroyPointGroup(ctx); return ctxSetElements(ctx, length, elements); err: return ret; } msym_error_t msymGetElements(msym_context ctx, int *length, msym_element_t **elements){ msym_error_t ret = MSYM_SUCCESS; msym_element_t *relements = NULL; if(ctx == NULL) {ret = MSYM_INVALID_CONTEXT; return ret;} if(ctx->elements == NULL || ctx->ext.elements == NULL) {ret = MSYM_INVALID_ELEMENTS;goto err;} *elements = ctx->ext.elements; *length = ctx->elementsl; return ret; err: free(relements); *elements = NULL; *length = 0; return ret; } msym_error_t msymGetEquivalenceSets(msym_context ctx, int *length, const msym_equivalence_set_t **es){ msym_error_t ret = MSYM_SUCCESS; if(ctx->ext.es == NULL){ret = MSYM_INVALID_EQUIVALENCE_SET;goto err;} *es = ctx->ext.es; *length = ctx->esl; err: return ret; } msym_error_t msymGetBasisFunctions(msym_context ctx, int *length, msym_basis_function_t **basis){ msym_error_t ret = MSYM_SUCCESS; if(ctx == NULL) {ret = MSYM_INVALID_CONTEXT; return ret;} if(ctx->basis == NULL) { msymSetErrorDetails("Found no basis functions"); ret = MSYM_INVALID_BASIS_FUNCTIONS; goto err; } *length = ctx->basisl; *basis = ctx->basis; err: return ret; } msym_error_t msymSetBasisFunctions(msym_context ctx, int length, msym_basis_function_t *basis){ msym_error_t ret = MSYM_SUCCESS; if(ctx == NULL) {ret = MSYM_INVALID_CONTEXT; return ret;} if(ctx->elements == NULL) {ret = MSYM_INVALID_ELEMENTS;goto err;} ctxDestroyBasisFunctions(ctx); ctx->basis = malloc(sizeof(msym_basis_function_t[length])); memcpy(ctx->basis, basis, sizeof(msym_basis_function_t[length])); for(int i = 0;i < length;i++){ msym_basis_function_t *bf = &ctx->basis[i]; if(bf->element >= ctx->ext.set_elements_ptr && bf->element < ctx->ext.set_elements_ptr + ctx->elementsl){ bf->element = bf->element - ctx->ext.set_elements_ptr + ctx->ext.elements; } else if(!(bf->element >= ctx->ext.elements && ctx->basis[i].element < ctx->ext.elements + ctx->elementsl)){ ret = MSYM_INVALID_BASIS_FUNCTIONS; msymSetErrorDetails("Basis function element not set correctly should be within [%p,%p) or [%p,%p) but is at %p",ctx->ext.set_elements_ptr,ctx->ext.set_elements_ptr + ctx->elementsl,ctx->ext.elements,ctx->ext.elements + ctx->elementsl, bf->element); goto err; } if(bf->type != MSYM_BASIS_TYPE_REAL_SPHERICAL_HARMONIC){ msymSetErrorDetails("Only supported basis function type a is real spherical harmonic"); ret = MSYM_INVALID_BASIS_FUNCTIONS; goto err; } msym_real_spherical_harmonic_t *sh = &bf->f.rsh; if(sh->n <= 0){ if(MSYM_SUCCESS != (ret = basisFunctionFromName(bf->name,bf))) goto err; } else { if(MSYM_SUCCESS != (ret = basisFunctionFromQuantumNumbers(sh->n, sh->l, sh->m, bf))) goto err; } } ctx->basisl = length; if(NULL != ctx->pg && isLinearPointGroup(ctx->pg)){ free(ctx->pg->ct); ctx->pg->ct = NULL; if(MSYM_SUCCESS != (ret = msymFindSymmetry(ctx))) goto err; // This will only do eq set building and linear reduction } return ret; err: free(ctx->basis); ctx->basisl = 0; ctx->basis = NULL; return ret; } msym_error_t msymGetPointGroupName(msym_context ctx, int l, char buf[l]){ msym_error_t ret = MSYM_SUCCESS; if(ctx == NULL) {ret = MSYM_INVALID_CONTEXT; return ret;} if(ctx->pg == NULL) {ret = MSYM_INVALID_POINT_GROUP;goto err;} snprintf(buf, l, "%s",ctx->pg->name); err: return ret; } msym_error_t msymGetPointGroupType(msym_context ctx, msym_point_group_type_t *t, int *n){ msym_error_t ret = MSYM_SUCCESS; if(ctx == NULL) {ret = MSYM_INVALID_CONTEXT; return ret;} if(ctx->pg == NULL) {ret = MSYM_INVALID_POINT_GROUP;goto err;} *t = ctx->pg->type; *n = ctx->pg->n; err: return ret; } msym_error_t msymGetSubgroups(msym_context ctx, int *sgl, const msym_subgroup_t **sg){ msym_error_t ret = MSYM_SUCCESS; msym_subgroup_t *gsg = NULL; int gsgl = 0; if(ctx == NULL) {ret = MSYM_INVALID_CONTEXT; return ret;} if(ctx->pg == NULL) {ret = MSYM_INVALID_POINT_GROUP;goto err;} if(ctx->pg->perm == NULL && !(isLinearPointGroup(ctx->pg) && !isLinearSubgroup(ctx->pg))) { ret = MSYM_INVALID_PERMUTATION; goto err; } if(ctx->sg == NULL && (!isLinearPointGroup(ctx->pg) || isLinearSubgroup(ctx->pg))){ int sgmax = numberOfSubgroups(ctx->pg); if(MSYM_SUCCESS != (ret = findPermutationSubgroups(ctx->pg->order, ctx->pg->perm, sgmax, ctx->pg->sops, &gsgl, &gsg))) goto err; if(isLinearSubgroup(ctx->pg)){ gsg = realloc(gsg, (gsgl+1)*sizeof(*gsg)); memset(&gsg[gsgl], 0, sizeof(*gsg)); gsg[gsgl].n = ctx->pg->n; gsg[gsgl].order = ctx->pg->order; gsg[gsgl].sops = calloc(gsg[gsgl].order, sizeof(*gsg[gsgl].sops)); for(int i = 0;i < ctx->pg->order;i++){ gsg[gsgl].sops[i] = &ctx->pg->sops[i]; } gsgl++; } ctx->sg = gsg; ctx->sgl = gsgl; for(int i = 0;i < ctx->sgl;i++){ if(MSYM_SUCCESS != (ret = findSubgroup(&ctx->sg[i], ctx->thresholds))) goto err; } } *sgl = ctx->sgl; *sg = ctx->sg; return ret; err: for(int i = 0;NULL != gsg && i < gsgl;i++){ free(gsg[i].sops); } free(gsg); return ret; } msym_error_t msymGetSubrepresentationSpaces(msym_context ctx, int *l, const msym_subrepresentation_space_t **srs){ msym_error_t ret = MSYM_SUCCESS; if(NULL == ctx) {ret = MSYM_INVALID_CONTEXT;goto err;} if(NULL == ctx->srs){ if(MSYM_SUCCESS != (ret = msymGenerateSubrepresentationSpaces(ctx))) goto err; if(NULL == ctx->srs){ msymSetErrorDetails("Found no subrepresentation spaces"); ret = MSYM_INVALID_BASIS_FUNCTIONS; goto err; } } *srs = ctx->srs; *l = ctx->srsl; return ret; err: return ret; } msym_error_t msymGetCharacterTable(msym_context ctx, const msym_character_table_t **ct){ msym_error_t ret = MSYM_SUCCESS; if(NULL == ctx) {ret = MSYM_INVALID_CONTEXT;goto err;} if(NULL == ctx->pg){ret = MSYM_INVALID_POINT_GROUP;goto err;} if(NULL == ctx->pg->ct){ msym_point_group_t *pg = ctx->pg; if(MSYM_SUCCESS != (ret = generateCharacterTable(pg->type, pg->n, pg->order, pg->sops, &pg->ct))) goto err; } *ct = ctx->pg->ct; err: return ret; } msym_error_t msymGetCenterOfMass(msym_context ctx, double v[3]){ msym_error_t ret = MSYM_SUCCESS; if(ctx == NULL) {ret = MSYM_INVALID_CONTEXT; return ret;} if(ctx->elements == NULL) {ret = MSYM_INVALID_ELEMENTS;goto err;} vcopy(ctx->cm, v); err: return ret; } msym_error_t msymSetCenterOfMass(msym_context ctx, double cm[3]){ msym_error_t ret = MSYM_SUCCESS; if(ctx == NULL) {ret = MSYM_INVALID_CONTEXT; goto err;} vcopy(cm,ctx->cm); if(MSYM_SUCCESS != (ret = ctxUpdateExternalElementCoordinates(ctx))) goto err; err: return ret; } msym_error_t msymGetGeometry(msym_context ctx, msym_geometry_t *geometry){ msym_error_t ret = MSYM_SUCCESS; if(ctx == NULL) {ret = MSYM_INVALID_CONTEXT; return ret;} if(ctx->elements == NULL) {ret = MSYM_INVALID_ELEMENTS;goto err;} if(ctx->geometry == MSYM_GEOMETRY_UNKNOWN) {ret = MSYM_INVALID_GEOMETRY;goto err;} *geometry = ctx->geometry; err: return ret; } msym_error_t msymGetPrincipalMoments(msym_context ctx, double eigval[3]){ msym_error_t ret = MSYM_SUCCESS; if(ctx == NULL) {ret = MSYM_INVALID_CONTEXT; return ret;} if(ctx->elements == NULL) {ret = MSYM_INVALID_ELEMENTS;goto err;} vcopy(ctx->eigval, eigval); err: return ret; } msym_error_t msymGetPrincipalAxes(msym_context ctx, double eigvec[3][3]){ msym_error_t ret = MSYM_SUCCESS; if(ctx == NULL) {ret = MSYM_INVALID_CONTEXT; return ret;} if(ctx->elements == NULL) {ret = MSYM_INVALID_ELEMENTS;goto err;} mcopy(ctx->eigvec, eigvec); err: return ret; } msym_error_t msymGetRadius(msym_context ctx, double *radius){ msym_error_t ret = MSYM_SUCCESS; if(ctx == NULL) {ret = MSYM_INVALID_CONTEXT; return ret;} if(ctx->elements == NULL) {ret = MSYM_INVALID_ELEMENTS;goto err;} double r = 0.0; for(int i = 0;i < ctx->elementsl;i++){ double abs = vabs(ctx->elements[i].v); r = r > abs ? r : abs; } *radius = r; err: return ret; } msym_error_t msymGetSymmetryOperations(msym_context ctx, int *sopsl, const msym_symmetry_operation_t **sops){ msym_error_t ret = MSYM_SUCCESS; msym_symmetry_operation_t *rsops = NULL; if(ctx == NULL) {ret = MSYM_INVALID_CONTEXT; return ret;} if(ctx->pg == NULL || ctx->pg->sops == NULL) {ret = MSYM_INVALID_POINT_GROUP;goto err;} *sops = ctx->pg->sops; *sopsl = ctx->pg->order; return ret; err: free(rsops); *sops = NULL; *sopsl = 0; return ret; } msym_error_t msymReleaseContext(msym_context ctx){ msym_error_t ret = MSYM_SUCCESS; if(ctx == NULL) {ret = MSYM_INVALID_CONTEXT; return ret;} free(ctx->thresholds); ctxDestroyElements(ctx); ctxDestroyPointGroup(ctx); free(ctx); //err: return ret; } /*********************** * Private API ***********************/ msym_error_t ctxSetElements(msym_context ctx, int length, msym_element_t elements[length]){ msym_error_t ret = MSYM_SUCCESS; msym_thresholds_t *thresholds = NULL; if(ctx == NULL) {ret = MSYM_INVALID_CONTEXT; return ret;} ctxDestroyElements(ctx); if(MSYM_SUCCESS != (ret = ctxGetThresholds(ctx, &thresholds))) goto err; ctx->elements = malloc(sizeof(msym_element_t[length])); ctx->pelements = malloc(sizeof(msym_element_t *[length])); memcpy(ctx->elements, elements, sizeof(msym_element_t[length])); ctx->elementsl = length; for(int i = 0;i < length;i++){ ctx->pelements[i] = &(ctx->elements[i]); if(MSYM_SUCCESS != (ret = complementElementData(ctx->pelements[i]))) goto err; } if(MSYM_SUCCESS != (ret = findCenterOfMass(ctx->elementsl,ctx->pelements,ctx->cm))) goto err; for(msym_element_t *a = ctx->elements; a < (ctx->elements+length); a++){ vsub(a->v,ctx->cm,a->v); } double zero[3] = {0,0,0}; if(MSYM_SUCCESS != (ret = findGeometry(length, ctx->pelements, zero, thresholds, &ctx->geometry, ctx->eigval, ctx->eigvec))) goto err; ctx->ext.elements = malloc(sizeof(msym_element_t[length])); memcpy(ctx->ext.elements, ctx->elements, sizeof(msym_element_t[length])); ctx->ext.set_elements_ptr = elements; return ret; err: free(ctx->elements); free(ctx->pelements); free(ctx->ext.elements); ctx->ext.elements = NULL; ctx->elements = NULL; ctx->pelements = NULL; ctx->elementsl = 0; return ret; } msym_error_t ctxGetThresholds(msym_context ctx, msym_thresholds_t **thresholds){ msym_error_t ret = MSYM_SUCCESS; if(ctx == NULL) {ret = MSYM_INVALID_CONTEXT; return ret;} if(ctx->thresholds == NULL) {ret = MSYM_INVALID_THRESHOLD; goto err;} msym_thresholds_t *t = ctx->thresholds; if(t->angle < 1.0 && !signbit(t->angle) && t->equivalence < 1.0 && !signbit(t->equivalence) && t->geometry < 1.0 && !signbit(t->geometry) && !signbit(t->eigfact) && !signbit(t->orthogonalization) && !signbit(t->zero) && !signbit(t->permutation)){ *thresholds = t; } else { ret = MSYM_INVALID_THRESHOLD; goto err; } err: return ret; } msym_error_t ctxGetElements(msym_context ctx, int *l, msym_element_t **elements){ msym_error_t ret = MSYM_SUCCESS; if(ctx == NULL) {ret = MSYM_INVALID_CONTEXT; return ret;} if(ctx->elements == NULL) {ret = MSYM_INVALID_ELEMENTS; goto err;} *elements = (msym_element_t *) ctx->elements; *l = ctx->elementsl; err: return ret; } msym_error_t ctxGetExternalElements(msym_context ctx, int *l, msym_element_t **elements){ msym_error_t ret = MSYM_SUCCESS; if(ctx == NULL) {ret = MSYM_INVALID_CONTEXT; return ret;} if(ctx->ext.elements == NULL) {ret = MSYM_INVALID_ELEMENTS; goto err;} *elements = (msym_element_t *) ctx->ext.elements; *l = ctx->elementsl; err: return ret; } msym_error_t ctxUpdateExternalElementCoordinates(msym_context ctx){ msym_error_t ret = MSYM_SUCCESS; if(NULL == ctx) {ret = MSYM_INVALID_CONTEXT;goto err;} if(NULL == ctx->elements || NULL == ctx->ext.elements) {ret = MSYM_INVALID_ELEMENTS; goto err;} msym_element_t *internal = ctx->elements, *external = ctx->ext.elements; for(int i = 0; i < ctx->elementsl;i++){ vadd(internal[i].v, ctx->cm, external[i].v); } err: return ret; } msym_error_t ctxGetInternalElement(msym_context ctx, msym_element_t *ext, msym_element_t **element){ msym_error_t ret = MSYM_SUCCESS; if(ctx == NULL) {ret = MSYM_INVALID_CONTEXT; return ret;} if(ctx->ext.elements == NULL) {ret = MSYM_INVALID_ELEMENTS;goto err;} if(ext < ctx->ext.elements || ext >= ctx->ext.elements+ctx->elementsl){ msymSetErrorDetails("Element pointer (%p) outside memory block (%p -> %p)", ext, ctx->ext.elements, ctx->ext.elements + ctx->elementsl); ret = MSYM_INVALID_ELEMENTS; goto err; } *element = ext - ctx->ext.elements + ctx->elements; err: return ret; } msym_error_t ctxGetSubgroups(msym_context ctx, int *sgl, msym_subgroup_t **sg){ msym_error_t ret = MSYM_SUCCESS; if(ctx == NULL) {ret = MSYM_INVALID_CONTEXT; return ret;} if(ctx->sg == NULL) {ret = MSYM_INVALID_SUBGROUPS;goto err;} *sg = ctx->sg; *sgl = ctx->sgl; err: return ret; } msym_error_t ctxSetSubgroups(msym_context ctx, int sgl, msym_subgroup_t *sg){ msym_error_t ret = MSYM_SUCCESS; if(ctx == NULL) {ret = MSYM_INVALID_CONTEXT; return ret;} ctxDestroySubgroups(ctx); ctx->sg = sg; ctx->sgl = sgl; err: return ret; } msym_error_t ctxGetElementPtrs(msym_context ctx, int *l, msym_element_t ***pelements){ msym_error_t ret = MSYM_SUCCESS; if(ctx == NULL) {ret = MSYM_INVALID_CONTEXT; return ret;} if(ctx->pelements == NULL) {ret = MSYM_INVALID_ELEMENTS; goto err;} *pelements = (msym_element_t **) ctx->pelements; *l = ctx->elementsl; err: return ret; } msym_error_t ctxGetBasisFunctions(msym_context ctx, int *l, msym_basis_function_t **basis){ msym_error_t ret = MSYM_SUCCESS; if(ctx == NULL) {ret = MSYM_INVALID_CONTEXT; goto err;} if(ctx->basis == NULL) { msymSetErrorDetails("Found no subrepresentation spaces in context"); ret = MSYM_INVALID_BASIS_FUNCTIONS; goto err; } *basis = (msym_basis_function_t *) ctx->basis; *l = ctx->basisl; err: return ret; } msym_error_t ctxSetPointGroup(msym_context ctx, msym_point_group_t *pg){ msym_error_t ret = MSYM_SUCCESS; if(MSYM_SUCCESS != (ret = ctxDestroyPointGroup(ctx))) goto err; ctx->pg = pg; err: return ret; } msym_error_t ctxReduceLinearPointGroup(msym_context ctx){ msym_error_t ret = MSYM_SUCCESS; if(ctx == NULL) {ret = MSYM_INVALID_CONTEXT; goto err;} if(ctx->pg == NULL) {ret = MSYM_INVALID_POINT_GROUP; goto err;} if(isLinearPointGroup(ctx->pg) && NULL != ctx->basis && 0 != ctx->basisl){ int lmax = 0; for(int i = 0;i < ctx->basisl;i++) lmax = lmax > ctx->basis[i].f.rsh.l ? lmax : ctx->basis[i].f.rsh.l; if(MSYM_SUCCESS != (ret = reduceLinearPointGroup(ctx->pg, 2*lmax, ctx->thresholds))) goto err; ctxDestroySubgroups(ctx); } err: return ret; } msym_error_t ctxGetPointGroup(msym_context ctx, msym_point_group_t **pg){ msym_error_t ret = MSYM_SUCCESS; if(ctx == NULL) {ret = MSYM_INVALID_CONTEXT; goto err;} if(ctx->pg == NULL) {ret = MSYM_INVALID_POINT_GROUP; goto err;} *pg = ctx->pg; err: return ret; } msym_error_t ctxSetEquivalenceSets(msym_context ctx, int esl, msym_equivalence_set_t *es){ msym_error_t ret = MSYM_SUCCESS; int el = 0; msym_element_t *elements = NULL; if(MSYM_SUCCESS != (ret = ctxDestroyEquivalcenceSets(ctx))) goto err; if(MSYM_SUCCESS != (ret = msymGetElements(ctx, &el, &elements))) goto err; //a bit lazy if(MSYM_SUCCESS != (ret = copyEquivalenceSets(esl,es,&ctx->ext.es))) goto err; for(int i = 0; i < esl;i++){ for(int j = 0;j < es[i].length;j++){ ctx->ext.es[i].elements[j] = ctx->ext.es[i].elements[j] - ctx->elements + elements; } } ctx->ext.eesmap = calloc(ctx->elementsl, sizeof(msym_equivalence_set_t *)); for(int i = 0;i < esl;i++){ for(int j = 0;j < ctx->ext.es[i].length;j++){ ctx->ext.eesmap[ctx->ext.es[i].elements[j] - ctx->ext.elements] = &ctx->ext.es[i]; } } for(int i = 0; i < ctx->elementsl;i++){ if(!ctx->ext.eesmap[i]){ ret = MSYM_INVALID_EQUIVALENCE_SET; msymSetErrorDetails("Element %d does not map to any equivalence set",i); goto err; } } ctx->es = es; ctx->esl = esl; return ret; err: free(ctx->ext.es); free(ctx->ext.eesmap); ctx->ext.es = NULL; ctx->ext.eesmap = NULL; return ret; } msym_error_t ctxGetEquivalenceSets(msym_context ctx, int *esl, msym_equivalence_set_t **es){ msym_error_t ret = MSYM_SUCCESS; if(ctx == NULL) {ret = MSYM_INVALID_CONTEXT; goto err;} if(ctx->es == NULL) {ret = MSYM_INVALID_EQUIVALENCE_SET;goto err;} *es = ctx->es; *esl = ctx->esl; err: return ret; } msym_error_t msymGetEquivalenceSetByElement(msym_context ctx, msym_element_t *element, const msym_equivalence_set_t **es){ msym_error_t ret = MSYM_SUCCESS; if(ctx == NULL) {ret = MSYM_INVALID_CONTEXT; goto err;} if(ctx->es == NULL) {ret = MSYM_INVALID_EQUIVALENCE_SET;goto err;} if(element >= ctx->ext.set_elements_ptr && element < ctx->ext.set_elements_ptr + ctx->elementsl){ element = element - ctx->ext.set_elements_ptr + ctx->ext.elements; } else if(!(element >= ctx->ext.elements && element < ctx->ext.elements + ctx->elementsl)){ ret = MSYM_INVALID_ELEMENTS; msymSetErrorDetails("Element not within [%p,%p) or [%p,%p) but is at %p",ctx->ext.set_elements_ptr,ctx->ext.set_elements_ptr + ctx->elementsl,ctx->ext.elements,ctx->ext.elements + ctx->elementsl, element); goto err; } msym_equivalence_set_t **eesmap = NULL; if(MSYM_SUCCESS != (ret = ctxGetExternalElementEquivalenceSetMap(ctx, &eesmap))) goto err; *es = eesmap[element - ctx->ext.elements]; err: return ret; } msym_error_t ctxGetExternalEquivalenceSets(msym_context ctx, int *esl, msym_equivalence_set_t **es){ msym_error_t ret = MSYM_SUCCESS; if(ctx->ext.es == NULL){ret = MSYM_INVALID_EQUIVALENCE_SET;goto err;} *es = ctx->ext.es; *esl = ctx->esl; err: return ret; } msym_error_t ctxGetExternalElementEquivalenceSetMap(msym_context ctx, msym_equivalence_set_t ***eesmap){ msym_error_t ret = MSYM_SUCCESS; if(ctx == NULL) {ret = MSYM_INVALID_CONTEXT; goto err;} if(ctx->ext.eesmap == NULL) {ret = MSYM_INVALID_EQUIVALENCE_SET;goto err;} *eesmap = ctx->ext.eesmap; err: return ret; } msym_error_t ctxSetEquivalenceSetPermutations(msym_context ctx, int r, int c, msym_permutation_t **perm){ msym_error_t ret = MSYM_SUCCESS; if(MSYM_SUCCESS != (ret = ctxDestroyEquivalcenceSetPermutations(ctx))) goto err; if(r != ctx->esl || ctx->pg == NULL || c != ctx->pg->order){ret = MSYM_INVALID_PERMUTATION; goto err;} ctx->es_perm = perm; ctx->es_perml = c; err: return ret; } msym_error_t ctxGetEquivalenceSetPermutations(msym_context ctx, int *r, int *c, msym_permutation_t ***perm){ msym_error_t ret = MSYM_SUCCESS; if(ctx == NULL) {ret = MSYM_INVALID_CONTEXT; goto err;} if(ctx->es == NULL || ctx->es_perml == 0 || ctx->es_perm == NULL){ret = MSYM_INVALID_PERMUTATION;goto err;} *r = ctx->esl; *c = ctx->es_perml; *perm = ctx->es_perm; err: return ret; } msym_error_t ctxGetSubrepresentationSpaces(msym_context ctx, int *srsl, msym_subrepresentation_space_t **srs, int **span){ msym_error_t ret = MSYM_SUCCESS; if(ctx == NULL) {ret = MSYM_INVALID_CONTEXT; goto err;} if(ctx->srs == NULL) {ret = MSYM_INVALID_SUBSPACE; goto err;} *srsl = ctx->srsl; *srs = ctx->srs; *span = ctx->srs_span; err: return ret; } msym_error_t ctxSetSubrepresentationSpaces(msym_context ctx, int srsl, msym_subrepresentation_space_t *srs, msym_basis_function_t **srsbf, int *span){ msym_error_t ret = MSYM_SUCCESS; if(MSYM_SUCCESS != (ret = ctxDestroySubrepresentationSpaces(ctx))) goto err; ctx->srsl = srsl; ctx->srs = srs; ctx->srsbf = srsbf; ctx->srs_span = span; err: return ret; } msym_error_t ctxUpdateGeometry(msym_context ctx){ msym_error_t ret = MSYM_SUCCESS; if(ctx == NULL) {ret = MSYM_INVALID_CONTEXT; goto err;} double zero[3] = {0,0,0}; if(MSYM_SUCCESS != (ret = findGeometry(ctx->elementsl, ctx->pelements, zero, ctx->thresholds, &ctx->geometry, ctx->eigval, ctx->eigvec))) goto err; err: return ret; } msym_error_t ctxGetGeometry(msym_context ctx, msym_geometry_t *g, double eigval[3], double eigvec[3][3]){ msym_error_t ret = MSYM_SUCCESS; if(ctx == NULL) {ret = MSYM_INVALID_CONTEXT; goto err;} if(ctx->geometry == MSYM_GEOMETRY_UNKNOWN) {ret = MSYM_INVALID_GEOMETRY; goto err;} *g = ctx->geometry; mcopy(ctx->eigvec, eigvec); vcopy(ctx->eigval, eigval); err: return ret; } msym_error_t ctxDestroyElements(msym_context ctx){ msym_error_t ret = MSYM_SUCCESS; if(ctx == NULL) {ret = MSYM_INVALID_CONTEXT; goto err;} ctxDestroyEquivalcenceSets(ctx); ctxDestroySubrepresentationSpaces(ctx); ctxDestroyBasisFunctions(ctx); free(ctx->elements); free(ctx->pelements); free(ctx->ext.eesmap); free(ctx->ext.elements); ctx->ext.set_elements_ptr = NULL; ctx->elements = NULL; ctx->pelements = NULL; ctx->ext.eesmap = NULL; ctx->ext.elements = NULL; ctx->elementsl = 0; ctx->geometry = MSYM_GEOMETRY_UNKNOWN; memset(ctx->eigvec,0,sizeof(ctx->eigvec)); memset(ctx->eigval,0,sizeof(ctx->eigval)); memset(ctx->cm,0,sizeof(ctx->cm)); err: return ret; } msym_error_t ctxDestroyEquivalcenceSets(msym_context ctx){ msym_error_t ret = MSYM_SUCCESS; if(ctx == NULL) {ret = MSYM_INVALID_CONTEXT; goto err;} ctxDestroyEquivalcenceSetPermutations(ctx); free(ctx->ext.eesmap); free(ctx->es); free(ctx->ext.es); ctx->ext.eesmap = NULL; ctx->ext.es = NULL; ctx->es = NULL; ctx->esl = 0; err: return ret; } msym_error_t ctxDestroyEquivalcenceSetPermutations(msym_context ctx){ msym_error_t ret = MSYM_SUCCESS; if(ctx == NULL) {ret = MSYM_INVALID_CONTEXT; goto err;} for(int i = 0; i < ctx->esl;i++){ for(int j = 0;j< ctx->es_perml;j++){ freePermutationData(&ctx->es_perm[i][j]); } } free(ctx->es_perm); ctx->es_perm = NULL; ctx->es_perml = 0; err: return ret; } msym_error_t ctxDestroyPointGroup(msym_context ctx){ msym_error_t ret = MSYM_SUCCESS; if(ctx == NULL) {ret = MSYM_INVALID_CONTEXT; goto err;} if(ctx->pg == NULL) goto err; ctxDestroyEquivalcenceSets(ctx); ctxDestroySubgroups(ctx); for(int i = 0;i < ctx->pg->order && ctx->pg->perm != NULL;i++){ freePermutationData(&ctx->pg->perm[i]); } free(ctx->pg->perm); free(ctx->pg->ct); free(ctx->pg->sops); free(ctx->pg); ctx->pg = NULL; err: return ret; } msym_error_t ctxDestroySubgroups(msym_context ctx){ msym_error_t ret = MSYM_SUCCESS; for(int i = 0;i < ctx->sgl;i++){ free(ctx->sg[i].sops); } free(ctx->sg); ctx->sg = NULL; ctx->sgl = 0; //err: return ret; } msym_error_t ctxDestroyBasisFunctions(msym_context ctx){ msym_error_t ret = MSYM_SUCCESS; if(ctx == NULL) {ret = MSYM_INVALID_CONTEXT; goto err;} ctxDestroySubrepresentationSpaces(ctx); free(ctx->basis); ctx->basis = NULL; ctx->basisl = 0; err: return ret; } msym_error_t ctxDestroySubrepresentationSpaces(msym_context ctx){ msym_error_t ret = MSYM_SUCCESS; if(ctx == NULL) {ret = MSYM_INVALID_CONTEXT; goto err;} freeSubrepresentationSpaces(ctx->srsl, ctx->srs); free(ctx->srsbf); free(ctx->srs_span); ctx->srs = NULL; ctx->srsbf = NULL; ctx->srs_span = NULL; ctx->srsl = 0; err: return ret; } v_sim-3.8.0/lib/plug-ins/msym/libmsym/src/context.h000066400000000000000000000065471370110300500222320ustar00rootroot00000000000000// // context.h // libmsym // // Created by Marcus Johansson on 30/01/15. // Copyright (c) 2015 Marcus Johansson. // // Distributed under the MIT License ( See LICENSE file or copy at http://opensource.org/licenses/MIT ) // #ifndef __MSYM__CONTEXT_h #define __MSYM__CONTEXT_h #include #include "msym.h" #include "point_group.h" #include "basis_function.h" #define DEFAULT_ZERO_THRESHOLD 1.0e-3 #define DEFAULT_GEOMETRY_THRESHOLD 1.0e-3 #define DEFAULT_ANGLE_THRESHOLD 1.0e-3 #define DEFAULT_EQUIVALENCE_THRESHOLD 5.0e-4 #define DEFAULT_EIGFACT_THRESHOLD 1.0e-3 #define DEFAULT_PERMUTATION_THRESHOLD 5.0e-3 #define DEFAULT_ORTHOGONALIZATION_THRESHOLD 1.0e-2 msym_error_t ctxGetThresholds(msym_context ctx, msym_thresholds_t **thresholds); msym_error_t ctxSetElements(msym_context ctx, int length, msym_element_t *elements); msym_error_t ctxGetElements(msym_context, int *l, msym_element_t **elements); msym_error_t ctxGetExternalElements(msym_context ctx, int *l, msym_element_t **elements); msym_error_t ctxUpdateExternalElementCoordinates(msym_context ctx); msym_error_t ctxGetElementPtrs(msym_context ctx, int *l, msym_element_t ***pelements); msym_error_t ctxGetInternalElement(msym_context ctx, msym_element_t *ext, msym_element_t **element); msym_error_t ctxGetInternalSubgroup(msym_context ctx, msym_subgroup_t *ext, msym_subgroup_t **sg); msym_error_t ctxSetPointGroup(msym_context ctx, msym_point_group_t *pg); msym_error_t ctxGetPointGroup(msym_context ctx, msym_point_group_t **pg); msym_error_t ctxReduceLinearPointGroup(msym_context ctx); msym_error_t ctxSetSubgroups(msym_context ctx, int sgl, msym_subgroup_t *sg); msym_error_t ctxGetSubgroups(msym_context ctx, int *sgl, msym_subgroup_t **sg); msym_error_t ctxSetEquivalenceSets(msym_context ctx, int esl, msym_equivalence_set_t *es); msym_error_t ctxGetEquivalenceSets(msym_context ctx, int *esl, msym_equivalence_set_t **es); msym_error_t ctxGetExternalEquivalenceSets(msym_context ctx, int *esl, msym_equivalence_set_t **es); msym_error_t ctxGetExternalElementEquivalenceSetMap(msym_context ctx, msym_equivalence_set_t ***eesmap); msym_error_t ctxSetEquivalenceSetPermutations(msym_context ctx, int r, int c, msym_permutation_t **perm); msym_error_t ctxGetEquivalenceSetPermutations(msym_context ctx, int *r, int *c, msym_permutation_t ***perm); msym_error_t ctxGetBasisFunctions(msym_context ctx, int *l, msym_basis_function_t **basis); msym_error_t ctxGetSubrepresentationSpaces(msym_context ctx, int *srsl, msym_subrepresentation_space_t **srs, int **span); msym_error_t ctxSetSubrepresentationSpaces(msym_context ctx, int srsl, msym_subrepresentation_space_t *srs, msym_basis_function_t **srsbf, int *span); msym_error_t ctxUpdateGeometry(msym_context ctx); msym_error_t ctxGetGeometry(msym_context ctx, msym_geometry_t *g, double eigval[3], double eigvec[3][3]); msym_error_t ctxDestroyElements(msym_context ctx); msym_error_t ctxDestroyEquivalcenceSets(msym_context ctx); msym_error_t ctxDestroyEquivalcenceSetPermutations(msym_context ctx); msym_error_t ctxDestroyPointGroup(msym_context ctx); msym_error_t ctxDestroySubgroups(msym_context ctx); msym_error_t ctxDestroyBasisFunctions(msym_context ctx); msym_error_t ctxDestroyOrbitalSubspaces(msym_context ctx); msym_error_t ctxDestroyDisplacementSubspaces(msym_context ctx); msym_error_t ctxDestroySubrepresentationSpaces(msym_context ctx); #endif /* defined(__MSYM__CONTEXT_h) */ v_sim-3.8.0/lib/plug-ins/msym/libmsym/src/debug.c000066400000000000000000000074501370110300500216210ustar00rootroot00000000000000// // debug.c // libmsym // // Created by Marcus Johansson on 25/10/15. // Copyright (c) 2015 Marcus Johansson. // // Distributed under the MIT License ( See LICENSE file or copy at http://opensource.org/licenses/MIT ) // #include "debug.h" #ifdef LIBMSYM_DEBUG #include #include #include #include #include #include void tabPrintTransform(int r, int c, double M[r][c],int indent); void tabprintf(char *format, int indent, ...); void tabprintf(char *format, int indent, ...){ for(int i = 0; i < indent;i++) printf("\t"); va_list args; va_start (args, indent); vprintf (format, args); va_end (args); } void tabPrintTransform(int r, int c, double M[r][c],int indent) { if(r == 0 || c == 0) {tabprintf("[]\n",indent);return;} //printf("\n"); tabprintf("[",indent); for(int i = 0;i < r;i++){ for(int j = 0;js[srs[k].s].name); for(int i = 0;i < srs[k].salcl;i++){ for(int j = 0;j < srs[k].salc[i].fl;j++){ msym_basis_function_t *bf = srs[k].salc[i].f[j]; if(bf == NULL){ printf("error bf\n"); exit(1); } printf("\t %s%s\t\t",bf->element->name,bf->name); } printf("\n"); double (*space)[srs[k].salc[i].fl] = (double (*)[srs[k].salc[i].fl]) srs[k].salc[i].pf; if(space == NULL){ printf("error space\n"); exit(1); } tabPrintTransform(srs[k].salc[i].d,srs[k].salc[i].fl,space,1); } } } void printPermutation(msym_permutation_t *perm){ int l = perm->p_length; printf("("); for(int j = 0; j < l; j++){ printf(j == l -1 ? "%d" : "%d\t",j); } printf(")\n("); for(int j = 0; j < l; j++){ printf(j == l -1 ? "%d" : "%d\t",perm->p[j]); } printf(")\n"); for(msym_permutation_cycle_t* c = perm->c; c < (perm->c + perm->c_length);c++){ printf("("); for(int next = c->s, j = 0;j < c->l;j++){ printf(j == c->l -1 ? "%d" : "%d ",next); next = perm->p[next]; } printf(")"); } printf("\n"); } void printCharacterTable(msym_character_table_t *ct){ msym_symmetry_operation_t **sops = ct->sops; int sopsl = ct->d; double (*table)[ct->d] = (double (*)[ct->d]) ct->table; printf("\t"); for(int j = 0;j < sopsl;j++){ char buf[12]; symmetryOperationName(sops[j], 12, buf); printf("%d%s",ct->classc[sops[j]->cla],buf); printf("\t\t"); } printf("\n"); for(int i = 0;i < ct->d;i++){ printf("%s\t",ct->s[i].name); for(int j = 0;j < ct->d;j++){ printf("% .3lf\t\t",table[i][j]); } printf("\n"); } } #endif v_sim-3.8.0/lib/plug-ins/msym/libmsym/src/debug.h000066400000000000000000000024171370110300500216240ustar00rootroot00000000000000// // debug.h // libmsym // // Created by Marcus Johansson on 07/11/14. // Copyright (c) 2014 Marcus Johansson. // // Distributed under the MIT License ( See LICENSE file or copy at http://opensource.org/licenses/MIT ) // #ifndef __MSYM__DEBUG_h #define __MSYM__DEBUG_h #include "msym.h" #ifdef LIBMSYM_DEBUG #include #include "permutation.h" #define clean_debug_printf(...) fprintf (stderr, __VA_ARGS__) #define debug_printTransform(R,C,M) do { printTransform((R),(C),(M)); } while(0) #define debug_printSubspace(C,L,S) do { printSubspace((C),(L),(S)); } while(0) #define debug_printPermutation(P) do { printPermutation((P)); } while(0) #define debug_printCharacterTable(C) do { printCharacterTable((C)); } while(0) void printTransform(int r, int c, double M[r][c]); void printPermutation(msym_permutation_t *perm); void printSubspace(msym_character_table_t *ct, int l, msym_subrepresentation_space_t srs[l]); void printCharacterTable(msym_character_table_t *ct); #else #define clean_debug_printf(fmt, ...) do{} while(0) #define debug_printTransform(R,C,M) do {} while(0) #define debug_printSubspace(C,L,S) do {} while(0) #define debug_printPermutation(P) do {} while(0) #define debug_printCharacterTable(C) do {} while(0) #endif #endif /* defined(__MSYM__DEBUG_h) */ v_sim-3.8.0/lib/plug-ins/msym/libmsym/src/elements.c000066400000000000000000000150741370110300500223500ustar00rootroot00000000000000// // elements.c // libmsym // // Created by Marcus Johansson on 17/02/15. // Copyright (c) 2015 Marcus Johansson. // // Distributed under the MIT License ( See LICENSE file or copy at http://opensource.org/licenses/MIT ) // #include #include #include "elements.h" #include "debug.h" const struct _periodic_table { int n; char *name; int massnr; } periodic_table[] = { { 1, "H", 1 }, { 1, "D", 2 }, { 1, "T", 3 }, { 2, "He", 4 }, { 3, "Li", 7 }, { 4, "Be", 9 }, { 5, "B", 11 }, { 6, "C", 12 }, { 7, "N", 14 }, { 8, "O", 16 }, { 9, "F", 19 }, { 10, "Ne", 20 }, { 11, "Na", 23 }, { 12, "Mg", 24 }, { 13, "Al", 27 }, { 14, "Si", 28 }, { 15, "P", 31 }, { 16, "S", 32 }, { 17, "Cl", 35 }, { 18, "Ar", 40 }, { 19, "K", 39 }, { 20, "Ca", 40 }, { 21, "Sc", 45 }, { 22, "Ti", 48 }, { 23, "V", 51 }, { 24, "Cr", 52 }, { 25, "Mn", 55 }, { 26, "Fe", 56 }, { 27, "Co", 58 }, { 28, "Ni", 58 }, { 29, "Cu", 64 }, { 30, "Zn", 65 }, { 31, "Ga", 70 }, { 32, "Ge", 73 }, { 33, "As", 75 }, { 34, "Se", 79 }, { 35, "Br", 80 }, { 36, "Kr", 84 }, { 37, "Rb", 85 }, { 38, "Sr", 88 }, { 39, "Y", 89 }, { 40, "Zr", 91 }, { 41, "Nb", 93 }, { 42, "Mo", 96 }, { 43, "Tc", 98 }, { 44, "Ru", 101 }, { 45, "Rh", 103 }, { 46, "Pd", 106 }, { 47, "Ag", 108 }, { 48, "Cd", 112 }, { 49, "In", 115 }, { 50, "Sn", 119 }, { 51, "Sb", 122 }, { 52, "Te", 128 }, { 53, "I", 127 }, { 54, "Xe", 131 }, { 55, "Cs", 133 }, { 56, "Ba", 137 }, { 57, "La", 139 }, { 58, "Ce", 140 }, { 59, "Pr", 141 }, { 60, "Nd", 144 }, { 61, "Pm", 145 }, { 62, "Sm", 150 }, { 63, "Eu", 152 }, { 64, "Gd", 157 }, { 65, "Tb", 159 }, { 66, "Dy", 163 }, { 67, "Ho", 165 }, { 68, "Er", 167 }, { 69, "Tm", 169 }, { 70, "Yb", 173 }, { 71, "Lu", 175 }, { 72, "Hf", 178 }, { 73, "Ta", 181 }, { 74, "W", 184 }, { 75, "Re", 186 }, { 76, "Os", 190 }, { 77, "Ir", 192 }, { 78, "Pt", 195 }, { 79, "Au", 197 }, { 80, "Hg", 201 }, { 81, "Tl", 204 }, { 82, "Pb", 207 }, { 83, "Bi", 209 }, { 84, "Po", 209 }, { 85, "At", 210 }, { 86, "Rn", 222 }, { 87, "Fr", 223 }, { 88, "Ra", 226 }, { 89, "Ac", 227 }, { 90, "Th", 232 }, { 91, "Pa", 231 }, { 92, "U", 238 }, { 93, "Np", 237 }, { 94, "Pu", 244 }, { 95, "Am", 243 }, { 96, "Cm", 247 }, { 97, "Bk", 247 }, { 98, "Cf", 251 }, { 99, "Es", 252 }, { 100, "Fm", 257 }, { 101, "Md", 258 }, { 102, "No", 259 }, { 103, "Lr", 262 }, { 104, "Rf", 261 }, { 105, "Db", 268 }, { 106, "Sg", 263 }, { 107, "Bh", 264 }, { 108, "Hs", 269 }, { 109, "Mt", 268 }, { 110, "Ds", 272 }, { 111, "Rg", 273 }, { 112, "Uub", 277 }, { 113, "Uut", 286 }, { 114, "Uuq", 289 }, { 115, "Uup", 288 }, { 116, "Uuh", 292 }, { 117, "Uus", 292 }, { 118, "Uuo", 293 } }; void printElement(msym_element_t *element){ clean_debug_printf("%s (nuclear charge:%d, mass:%lf) [%lf;%lf;%lf]\n",element->name, element->n, element->m, element->v[0], element->v[1], element->v[2]); } msym_error_t complementElementData(msym_element_t *element){ msym_error_t ret = MSYM_SUCCESS; element->name[sizeof(element->name)-1] = '\0'; size_t strl = strlen(element->name); if(strl <= 0 && element->n <= 0 && element->m <= 0.0){ msymSetErrorDetails("Element has no mass, name or nuclear charge"); ret = MSYM_INVALID_ELEMENTS; goto err; } if(element->n >= sizeof(periodic_table)/sizeof(periodic_table[0]) && element->m <= 0.0 && strl <= 0){ msymSetErrorDetails("Element has no mass or name and a nuclear charge of %d",element->n); ret = MSYM_INVALID_ELEMENTS; goto err; } if(element->n > 0 && (element->m <= 0.0 || strl <= 0)){ int fi, fil = sizeof(periodic_table)/sizeof(periodic_table[0]); for(fi = 0; fi < fil;fi++){ if(periodic_table[fi].n == element->n) { if(element->m <= 0.0) element->m = (double) periodic_table[fi].massnr; if(strl <= 0) snprintf(element->name, sizeof(element->name), "%s",periodic_table[fi].name); break; } } if(fi == fil){ msymSetErrorDetails("Unknown element with nuclear charge %d",fi); ret = MSYM_INVALID_ELEMENTS; goto err; } } else if(strl > 0 && (element->m <= 0.0 || element->n <= 0)){ int fi, fil = sizeof(periodic_table)/sizeof(periodic_table[0]); for(fi = 0; fi < fil;fi++){ int stre = 0; for(int i = 0;i < sizeof(element->name) && i < sizeof(periodic_table[fi].name);i++){ char ec = element->name[i], ep = periodic_table[fi].name[i]; char cmp[2] = { ec >= 'A' && ec <= 'Z' ? ec | 0x60 : ec, ep >= 'A' && ep <= 'Z' ? ep | 0x60 : ep }; if(cmp[0] != cmp[1]){ stre = cmp[0] - cmp[1]; break; } else if (cmp[0] == '\0'){ break; } } //if(0 == strncmp(periodic_table[fi].name, element->name, strnlen(periodic_table[fi].name, sizeof(element->name)))) { if(0 == stre){ if(element->m <= 0.0) element->m = (double) periodic_table[fi].massnr; if(element->n <= 0) element->n = periodic_table[fi].n; break; } } if(fi == fil){ char buf[sizeof(element->name)]; snprintf(buf, sizeof(element->name), "%s",element->name); //in case someone forgets to null terminate msymSetErrorDetails("Unknown element with name %s",buf); ret = MSYM_INVALID_ELEMENTS; goto err; } } else if(element->m > 0.0 && (strl <= 0 || element->n <= 0)){ int fim = 0, fil = sizeof(periodic_table)/sizeof(periodic_table[0]); double last = -1.0; for(int fi = 0; fi < fil;fi++){ double diff = fabs(periodic_table[fi].massnr - element->m); if(diff < last || last < 0.0){ last = diff; fim = fi; } } if(strl <= 0) snprintf(element->name, sizeof(element->name), "%s",periodic_table[fim].name); if(element->n <= 0) element->n = periodic_table[fim].n; } err: return ret; } v_sim-3.8.0/lib/plug-ins/msym/libmsym/src/elements.h000066400000000000000000000007311370110300500223470ustar00rootroot00000000000000// // elements.h // libmsym // // Created by Marcus Johansson on 17/02/15. // Copyright (c) 2015 Marcus Johansson. // // Distributed under the MIT License ( See LICENSE file or copy at http://opensource.org/licenses/MIT ) // #ifndef __MSYM__ELEMENTS_h #define __MSYM__ELEMENTS_h #include #include "msym.h" void printElement(msym_element_t *element); msym_error_t complementElementData(msym_element_t *element); #endif /* defined(__MSYM__ELEMENTS_h) */ v_sim-3.8.0/lib/plug-ins/msym/libmsym/src/equivalence_set.c000066400000000000000000000405071370110300500237070ustar00rootroot00000000000000// // equivalence_set.c // libmsym // // Created by Marcus Johansson on 08/02/15. // Copyright (c) 2015 Marcus Johansson. // // Distributed under the MIT License ( See LICENSE file or copy at http://opensource.org/licenses/MIT ) // #include #include #include #include #include "equivalence_set.h" #include "linalg.h" #include "context.h" #include "elements.h" #include "debug.h" #define SQR(x) ((x)*(x)) msym_error_t partitionEquivalenceSets(int length, msym_element_t *elements[length], msym_element_t *pelements[length], msym_geometry_t g, int *esl, msym_equivalence_set_t **es, msym_thresholds_t *thresholds); msym_error_t partitionPointGroupEquivalenceSets(msym_point_group_t *pg, int length, msym_element_t *elements[length], msym_element_t *pelements[length], int *esl, msym_equivalence_set_t **es, msym_thresholds_t *thresholds); msym_error_t copyEquivalenceSets(int length, msym_equivalence_set_t es[length], msym_equivalence_set_t **ces){ msym_error_t ret = MSYM_SUCCESS; int el = 0; for(int i = 0;i < length;i++) el += es[i].length; msym_equivalence_set_t *nes = malloc(sizeof(msym_equivalence_set_t[length]) + sizeof(msym_element_t *[el])); msym_element_t **ep = (msym_element_t **) &es[length]; msym_element_t **nep = (msym_element_t **) &nes[length]; memcpy(nes, es, sizeof(msym_equivalence_set_t[length]) + sizeof(msym_element_t *[el])); for(int i = 0;i < length;i++) nes[i].elements = nes[i].elements - ep + nep; *ces = nes; //err: return ret; } //TODO: Use a preallocated pointer array instead of multiple mallocs msym_error_t generateEquivalenceSet(msym_point_group_t *pg, int length, msym_element_t elements[length], double cm[3], int *glength, msym_element_t **gelements, int *esl, msym_equivalence_set_t **es,msym_thresholds_t *thresholds){ msym_error_t ret = MSYM_SUCCESS; msym_element_t *ge = calloc(length,sizeof(msym_element_t[pg->order])); msym_equivalence_set_t *ges = calloc(length,sizeof(msym_equivalence_set_t)); int gel = 0; int gesl = 0; if(pg->order <= 0){ ret = MSYM_INVALID_POINT_GROUP; msymSetErrorDetails("Point group of zero order when determining equivalence set"); goto err; } for(int i = 0;i < length;i++){ double ev[3]; vsub(elements[i].v, cm, ev); msym_equivalence_set_t *aes = NULL; int f; for(f = 0;f < gel;f++){ if(ge[f].n == elements[i].n && ge[f].m == elements[i].m && 0 == strncmp(ge[f].name, elements[i].name, sizeof(ge[f].name)) && vequal(ge[f].v, ev, thresholds->permutation)){ break; } } if(f == gel){ aes = &ges[gesl++]; aes->elements = calloc(pg->order,sizeof(msym_element_t*)); aes->length = 0; } else { continue; } for(msym_symmetry_operation_t *s = pg->sops;s < (pg->sops + pg->order);s++){ double v[3]; applySymmetryOperation(s, ev, v); for(f = 0;f < gel;f++){ if(ge[f].n == elements[i].n && ge[f].m == elements[i].m && 0 == strncmp(ge[f].name, elements[i].name, sizeof(ge[f].name)) && vequal(ge[f].v, v, thresholds->permutation)){ break; } } if(f == gel){ memcpy(&ge[gel],&elements[i],sizeof(msym_element_t)); ge[gel].id = NULL; vcopy(v, ge[gel].v); aes->elements[aes->length++] = &ge[gel++]; } } if(!aes->length || (pg->order % aes->length != 0)){ msymSetErrorDetails("Equivalence set length (%d) not a divisor of point group order (%d)",pg->order); ret = MSYM_INVALID_EQUIVALENCE_SET; goto err; } aes->elements = realloc(aes->elements,sizeof(msym_element_t*[aes->length])); } msym_element_t *geo = ge; ge = realloc(ge,sizeof(msym_element_t[gel])); ges = realloc(ges,sizeof(msym_equivalence_set_t[gesl]) + sizeof(msym_element_t *[gel])); msym_element_t **ep = (msym_element_t **) &ges[gesl]; for(int i = 0;i < gesl;i++){ msym_element_t **tep = ep; for(int j = 0;j < ges[i].length;j++){ *ep = ges[i].elements[j] - geo + ge; ep++; } free(ges[i].elements); ges[i].elements = tep; } *glength = gel; *gelements = ge; *es = ges; *esl = gesl; return ret; err: free(ge); for(int i = 0; i < gesl;i++) free(ges[i].elements); free(ges); return ret; } msym_error_t splitPointGroupEquivalenceSets(msym_point_group_t *pg, int esl, msym_equivalence_set_t es[esl], int *sesl, msym_equivalence_set_t **ses, msym_thresholds_t *thresholds){ msym_error_t ret = MSYM_SUCCESS; int length = 0, gesl = 0; for(int i = 0;i < esl;i++) length += es[i].length; msym_equivalence_set_t *ges = NULL; msym_element_t **pelements = calloc(length,sizeof(msym_element_t*)); msym_element_t **ep = (msym_element_t **) &es[esl]; for(int i = 0; i < esl;i++){ msym_equivalence_set_t *pes = NULL; int pesl = 0; if(MSYM_SUCCESS != (ret = partitionPointGroupEquivalenceSets(pg, es[i].length, es[i].elements, es[i].elements - ep + pelements, &pesl, &pes, thresholds))) goto err; ges = realloc(ges, sizeof(msym_equivalence_set_t[gesl+pesl])); memcpy(&ges[gesl], pes, sizeof(msym_equivalence_set_t[pesl])); free(pes); gesl += pesl; } ges = realloc(ges, sizeof(msym_equivalence_set_t[gesl]) + sizeof(msym_element_t *[length])); ep = (msym_element_t **) &ges[gesl]; memcpy(ep, pelements, sizeof(msym_element_t *[length])); for(int i = 0;i < gesl;i++){ ges[i].elements = ep; ep += ges[i].length; } *sesl = gesl; *ses = ges; free(pelements); return ret; err: free(ges); free(pelements); return ret; } msym_error_t findPointGroupEquivalenceSets(msym_point_group_t *pg, int length, msym_element_t *elements[length], int *esl, msym_equivalence_set_t **es, msym_thresholds_t *thresholds){ msym_error_t ret = MSYM_SUCCESS; msym_equivalence_set_t *ges = NULL; msym_element_t **pelements = calloc(length,sizeof(msym_element_t*)); int gesl = 0; if(MSYM_SUCCESS != (ret = partitionPointGroupEquivalenceSets(pg, length, elements, pelements, &gesl, &ges, thresholds))) goto err; ges = realloc(ges,sizeof(msym_equivalence_set_t[gesl]) + sizeof(msym_element_t *[length])); msym_element_t **ep = (msym_element_t **) &ges[gesl]; msym_element_t **epo = ep; memcpy(ep, pelements, sizeof(msym_element_t *[length])); for(int i = 0;i < gesl;i++){ if(ep > epo + length){ msymSetErrorDetails("Equivalence set pointer (%ld) extends beyond number of elements (%d)",ep-epo,length); ret = MSYM_INVALID_EQUIVALENCE_SET; goto err; } ges[i].elements = ep; ep += ges[i].length; } *es = ges; *esl = gesl; free(pelements); return ret; err: free(ges); free(pelements); return ret; } msym_error_t partitionPointGroupEquivalenceSets(msym_point_group_t *pg, int length, msym_element_t *elements[length], msym_element_t *pelements[length], int *esl, msym_equivalence_set_t **es, msym_thresholds_t *thresholds){ msym_error_t ret = MSYM_SUCCESS; msym_equivalence_set_t *ges = calloc(length,sizeof(msym_equivalence_set_t)); int *eqi = malloc(sizeof(int[length])); memset(eqi,-1,sizeof(int[length])); int gesl = 0, pelementsl = 0; for(int i = 0;i < length;i++){ if(eqi[i] >= 0) continue; if(pelementsl >= length){ msymSetErrorDetails("Size of equivalence sets (%d) larger than number of elements (%d)",pelementsl,length); ret = MSYM_INVALID_EQUIVALENCE_SET; goto err; } msym_equivalence_set_t *aes = &ges[gesl++]; aes->elements = &pelements[pelementsl]; for(msym_symmetry_operation_t *s = pg->sops;s < (pg->sops + pg->order);s++){ double v[3]; int f; applySymmetryOperation(s, elements[i]->v, v); for(f = 0;f < length;f++){ if(elements[f]->n == elements[i]->n && elements[f]->m == elements[i]->m && 0 == strncmp(elements[f]->name, elements[i]->name, sizeof(elements[f]->name)) && vequal(elements[f]->v, v, thresholds->permutation)){ break; } } if(f < length && eqi[f] >= 0 && eqi[f] != gesl-1){ char buf[64]; symmetryOperationName(s, 64, buf); msymSetErrorDetails("Symmetry operation %s on element %d yeilded element (%d) in two diffenrent equivalence sets (%d and %d)",buf,i,f,eqi[f],gesl-1); ret = MSYM_INVALID_EQUIVALENCE_SET; goto err; } else if(f < length && eqi[f] == gesl-1){ //clean_debug_printf("element[%d] %s belongs to equivalence set %d, but already added\n",f,elements[f]->name, eqi[f]); } else if(f < length){ eqi[f] = gesl - 1; aes->elements[aes->length++] = elements[f]; //clean_debug_printf("element[%d] %s belongs to equivalence set %d, adding\n",f,elements[f]->name, eqi[f]); } else { char buf[64]; symmetryOperationName(s, 64, buf); msymSetErrorDetails("Cannot find permutation for %s when determining equivalence set from point group %s",buf,pg->name); ret = MSYM_INVALID_EQUIVALENCE_SET; goto err; } } //printf("generated equivalance set %d of length %d\n",gesl-1,aes->length); pelementsl += aes->length; } if(pelementsl != length){ msymSetErrorDetails("Size of equivalence sets (%d) is not equal to number of elements (%d)",pelementsl,length); ret = MSYM_INVALID_EQUIVALENCE_SET; goto err; } *es = ges; *esl = gesl; free(eqi); return ret; err: free(eqi); free(ges); return ret; } msym_error_t findEquivalenceSets(int length, msym_element_t *elements[length], msym_geometry_t g, int *esl, msym_equivalence_set_t **es, msym_thresholds_t *thresholds) { msym_error_t ret = MSYM_SUCCESS; int sesl = 0; msym_equivalence_set_t *ses = NULL; msym_element_t **pelements = calloc(length,sizeof(msym_element_t *)); if(MSYM_SUCCESS != (ret = partitionEquivalenceSets(length, elements,pelements,g,&sesl,&ses,thresholds))) goto err; if(sesl > 1){ for(int i = 0; i < sesl;i++){ int rsesl = 0; msym_equivalence_set_t *rses = NULL; if(MSYM_SUCCESS != (ret = partitionEquivalenceSets(ses[i].length, ses[i].elements,ses[i].elements,g, &rsesl,&rses,thresholds))) goto err; if(rsesl > 1){ ses[i].elements = rses[0].elements; ses[i].length = rses[0].length; ses = realloc(ses, sizeof(msym_equivalence_set_t[sesl+rsesl-1])); memcpy(&ses[sesl], &rses[1], sizeof(msym_equivalence_set_t[rsesl-1])); sesl += rsesl-1; i--; } free(rses); } } ses = realloc(ses, sizeof(msym_equivalence_set_t[sesl]) + sizeof(msym_element_t *[length])); msym_element_t **ep = (msym_element_t **) &ses[sesl]; for(int i = 0;i < sesl;i++){ memcpy(ep, ses[i].elements, sizeof(msym_element_t *[ses[i].length])); ses[i].elements = ep; ep += ses[i].length; } *esl = sesl; *es = ses; free(pelements); return ret; err: free(pelements); free(ses); return ret; } msym_error_t partitionEquivalenceSets(int length, msym_element_t *elements[length], msym_element_t *pelements[length], msym_geometry_t g, int *esl, msym_equivalence_set_t **es, msym_thresholds_t *thresholds) { int ns = 0, gd = geometryDegenerate(g); double *e = calloc(length,sizeof(double)); double *s = calloc(length,sizeof(double)); int *sp = calloc(length,sizeof(int)); //set partition int *ss = calloc(length,sizeof(int)); //set size double (*ev)[3] = calloc(length,sizeof(double[3])); double (*ep)[3] = calloc(length,sizeof(double[3])); double (*vec)[3] = calloc(length, sizeof(double[3])); double *m = calloc(length, sizeof(double)); for(int i = 0;i < length;i++){ vcopy(elements[i]->v, vec[i]); m[i] = elements[i]->m; } for(int i=0; i < length; i++){ for(int j = i+1; j < length;j++){ double w = m[i]*m[j]/(m[i]+m[j]); double dist; double v[3]; double proji[3], projj[3]; vnorm2(vec[i],v); vproj_plane(vec[j], v, proji); vscale(w, proji, proji); vadd(proji,ep[i],ep[i]); vnorm2(vec[j],v); vproj_plane(vec[i], v, projj); vscale(w, projj, projj); vadd(projj,ep[j],ep[j]); vsub(vec[j],vec[i],v); dist = vabs(v); vscale(w/dist,v,v); vadd(v,ev[i],ev[i]); vsub(ev[j],v,ev[j]); double dij = w*dist; //This is sqrt(I) for a diatomic molecule along an axis perpendicular to the bond with O at center of mass. e[i] += dij; e[j] += dij; s[i] += SQR(dij); s[j] += SQR(dij); } vsub(vec[i],ev[i],ev[i]); } for(int i = 0; i < length; i++){ double v[3]; double w = m[i]/2.0; double dist = vabs(elements[i]->v); double dii = w*dist; vscale(w,elements[i]->v,v); vsub(ev[i],v,ev[i]); // Plane projection can't really differentiate certain types of structures when we add the initial vector, // but not doing so will result in huge cancellation errors on degenerate point groups, // also large masses will mess up the eq check when this is 0. if(gd) vadd(ep[i],v,ep[i]); e[i] += dii; s[i] += SQR(dii); } for(int i = 0; i < length; i++){ if(e[i] >= 0.0){ sp[i] = i; for(int j = i+1; j < length;j++){ if(e[j] >= 0.0){ double vabsevi = vabs(ev[i]), vabsevj = vabs(ev[j]), vabsepi = vabs(ep[i]), vabsepj = vabs(ep[j]); double eep = 0.0, eev = fabs((vabsevi)-(vabsevj))/((vabsevi)+(vabsevj)), ee = fabs((e[i])-(e[j]))/((e[i])+(e[j])), es = fabs((s[i])-(s[j]))/((s[i])+(s[j])); if(!(vabsepi < thresholds->zero && vabsepj < thresholds->zero)){ eep = fabs((vabsepi)-(vabsepj))/((vabsepi)+(vabsepj)); } double max = fmax(eev,fmax(eep,fmax(ee, es))); if(max < thresholds->equivalence && elements[i]->n == elements[j]->n){ e[j] = max > 0.0 ? -max : -1.0; sp[j] = i; } } } e[i] = -1.0; } } for(int i = 0; i < length;i++){ int j = sp[i]; ns += (ss[j] == 0); ss[j]++; } msym_equivalence_set_t *eqs = calloc(ns,sizeof(msym_equivalence_set_t)); msym_element_t **lelements = elements; msym_element_t **pe = pelements; if(elements == pelements){ lelements = malloc(sizeof(msym_element_t *[length])); memcpy(lelements, elements, sizeof(msym_element_t *[length])); } for(int i = 0, ni = 0; i < length;i++){ if(ss[i] > 0){ int ei = 0; eqs[ni].elements = pe; eqs[ni].length = ss[i]; for(int j = 0; j < length;j++){ if(sp[j] == i){ double err = (e[j] > -1.0) ? fabs(e[j]) : 0.0; eqs[ni].err = fmax(eqs[ni].err,err); eqs[ni].elements[ei++] = lelements[j]; } } pe += ss[i]; ni++; } } if(elements == pelements){ free(lelements); } free(m); free(vec); free(s); free(e); free(sp); free(ss); free(ev); free(ep); *es = eqs; *esl = ns; return MSYM_SUCCESS; } v_sim-3.8.0/lib/plug-ins/msym/libmsym/src/equivalence_set.h000066400000000000000000000024211370110300500237050ustar00rootroot00000000000000// // equivalence_set.h // libmsym // // Created by Marcus Johansson on 08/02/15. // Copyright (c) 2015 Marcus Johansson. // // Distributed under the MIT License ( See LICENSE file or copy at http://opensource.org/licenses/MIT ) // #ifndef __MSYM__EQUIVALENCE_SET_h #define __MSYM__EQUIVALENCE_SET_h #include #include "msym.h" #include "point_group.h" msym_error_t copyEquivalenceSets(int length, msym_equivalence_set_t es[length], msym_equivalence_set_t **ces); msym_error_t findEquivalenceSets(int length, msym_element_t *elements[length], msym_geometry_t g, int *esl, msym_equivalence_set_t **es, msym_thresholds_t *thresholds); msym_error_t findPointGroupEquivalenceSets(msym_point_group_t *pg, int length, msym_element_t *elements[length], int *esl, msym_equivalence_set_t **es, msym_thresholds_t *thresholds); msym_error_t splitPointGroupEquivalenceSets(msym_point_group_t *pg, int esl, msym_equivalence_set_t es[esl], int *sesl, msym_equivalence_set_t **ses, msym_thresholds_t *thresholds); msym_error_t generateEquivalenceSet(msym_point_group_t *pg, int length, msym_element_t elements[length], double cm[3], int *glength, msym_element_t **gelements, int *esl, msym_equivalence_set_t **es,msym_thresholds_t *thresholds); #endif /* defined(__MSYM__EQUIVALENCE_SET_h) */ v_sim-3.8.0/lib/plug-ins/msym/libmsym/src/geometry.c000066400000000000000000000114341370110300500223630ustar00rootroot00000000000000// // geometry.c // libmsym // // Created by Marcus Johansson on 28/11/14. // Copyright (c) 2014 Marcus Johansson. // // Distributed under the MIT License ( See LICENSE file or copy at http://opensource.org/licenses/MIT ) // #include #include #include "msym.h" #include "geometry.h" #include "linalg.h" #include "debug.h" #define SQR(x) ((x)*(x)) void inertialTensor(int length, msym_element_t *elements[length], double cm[3], double e[3], double v[3][3], msym_thresholds_t *thresholds); msym_geometry_t eigenvaluesToGeometry(double e[3], msym_thresholds_t *thresholds); msym_error_t findGeometry(int length, msym_element_t *elements[length], double cm[3], msym_thresholds_t *thresholds, msym_geometry_t *g, double e[3], double v[3][3]){ inertialTensor(length, elements, cm, e, v, thresholds); *g = eigenvaluesToGeometry(e,thresholds); return MSYM_SUCCESS; } msym_error_t findCenterOfMass(int length, msym_element_t *elements[length], double v[3]){ msym_error_t ret = MSYM_SUCCESS; double t = 0; v[0] = v[1] = v[2] = 0.0; for(int i = 0; i < length; i++){ msym_element_t *a = elements[i]; v[0] += a->v[0]*a->m; v[1] += a->v[1]*a->m; v[2] += a->v[2]*a->m; t += a->m; } if(t <= 0.0 || t != t){ msymSetErrorDetails("Invalid element mass sum: %lf",t); ret = MSYM_INVALID_ELEMENTS; } else { v[0] /= t; v[1] /= t; v[2] /= t; } return ret; } #define EQUAL(A,B,T) ((fabs(((A)-(B)))) < (T)) #define EQUAL_REL(A,B,T) (fabs(((A)-(B))/((A)+(B))) < T) //Lookup table would look alot nicer msym_geometry_t eigenvaluesToGeometry(double e[3], msym_thresholds_t *thresholds){ int e01 = EQUAL(0.0, e[0], thresholds->geometry); int e12, e23, planar; if(e[1] > 1.0){ //If the eigenvalues are large we want a relative value (can't always use since they may be 0, and very small values will give massive errors with division) e12 = EQUAL_REL(e[0], e[1], thresholds->geometry); } else { e12 = EQUAL(e[0], e[1], thresholds->geometry); } if(e[2] > 1.0){ e23 = EQUAL_REL(e[1], e[2], thresholds->geometry); planar = EQUAL_REL((e[0]+e[1]),e[2],thresholds->geometry); } else { e23 = EQUAL(e[1], e[2], thresholds->geometry); planar = EQUAL(e[0]+e[1],e[2],thresholds->geometry); } if(e12 && e23) { return MSYM_GEOMETRY_SPHERICAL; } else if (e01 && e23) { return MSYM_GEOMETRY_LINEAR; } else if (planar) { if(e12){ return MSYM_GEOMETRY_PLANAR_REGULAR; } else { return MSYM_GEOMETRY_PLANAR_IRREGULAR; } } else if (e12) { return MSYM_GEOMETRY_POLYHEDRAL_OBLATE; } else if (e23) { return MSYM_GEOMETRY_POLYHEDRAL_PROLATE; } else { return MSYM_GEOMETRY_ASSYMETRIC; } } int geometryDegenerate(msym_geometry_t g){ return !(g == MSYM_GEOMETRY_PLANAR_IRREGULAR || g == MSYM_GEOMETRY_ASSYMETRIC) && g != MSYM_GEOMETRY_UNKNOWN; } void inertialTensor(int length, msym_element_t *elements[length], double cm[3], double e[3], double v[3][3], msym_thresholds_t *thresholds){ double Ixx = 0, Iyy = 0, Izz = 0, Ixy = 0, Ixz = 0, Iyz = 0; for(int i = 0; i < length; i++){ msym_element_t *a = elements[i]; Ixx += a->m*(SQR(a->v[1]-cm[1])+SQR(a->v[2]-cm[2])); Iyy += a->m*(SQR(a->v[0]-cm[0])+SQR(a->v[2]-cm[2])); Izz += a->m*(SQR(a->v[0]-cm[0])+SQR(a->v[1]-cm[1])); Ixy -= a->m*(a->v[0]-cm[0])*(a->v[1]-cm[1]); Ixz -= a->m*(a->v[0]-cm[0])*(a->v[2]-cm[2]); Iyz -= a->m*(a->v[1]-cm[1])*(a->v[2]-cm[2]); } double I[6] = {Ixx,Ixy,Ixz,Iyy,Iyz,Izz}, ev[3][3], ei[3]; jacobi(I,ei,ev,thresholds->eigfact); int m = ((((ei[0] < ei[1]) << 1) | (ei[1] < ei[2])) << 1) | (ei[2] < ei[0]); int min[7] = {0,2,1,1,0,2,0}, mid[7] = {1,1,0,2,2,0,1}, max[7] = {2,0,2,0,1,1,2}; int o[3] = {min[m],mid[m],max[m]}; for(int i = 0; i < 3;i++){ e[i] = ei[o[i]]; for(int j = 0; j < 3;j++){ v[i][j] = ev[j][o[i]]; } } } void printGeometry(msym_geometry_t g){ char *s; switch(g) { case MSYM_GEOMETRY_SPHERICAL : s = "spherical"; break; case MSYM_GEOMETRY_LINEAR : s = "linear"; break; case MSYM_GEOMETRY_PLANAR_REGULAR : s = "planar regular polygon"; break; case MSYM_GEOMETRY_PLANAR_IRREGULAR : s = "planar irregular polygon"; break; case MSYM_GEOMETRY_POLYHEDRAL_PROLATE : s = "prolate symmetric polyhedron"; break; case MSYM_GEOMETRY_POLYHEDRAL_OBLATE : s = "oblate symmetric polyhedron"; break; case MSYM_GEOMETRY_ASSYMETRIC : s = "assymetric polyhedron"; break; default : s = "unknown geometry"; } clean_debug_printf("%s\n",s); } v_sim-3.8.0/lib/plug-ins/msym/libmsym/src/geometry.h000066400000000000000000000013021370110300500223610ustar00rootroot00000000000000// // geometry.h // libmsym // // Created by Marcus Johansson on 28/11/14. // Copyright (c) 2014 Marcus Johansson. // // Distributed under the MIT License ( See LICENSE file or copy at http://opensource.org/licenses/MIT ) // #ifndef __MSYM__GEOMETRY_h #define __MSYM__GEOMETRY_h #include #include "msym.h" msym_error_t findGeometry(int length, msym_element_t *elements[length], double cm[3], msym_thresholds_t *thresholds, msym_geometry_t *g, double e[3], double v[3][3]); msym_error_t findCenterOfMass(int length, msym_element_t *elements[length], double v[3]); int geometryDegenerate(msym_geometry_t g); void printGeometry(msym_geometry_t g); #endif /* defined(__MSYM__GEOMETRY_h) */ v_sim-3.8.0/lib/plug-ins/msym/libmsym/src/linalg.c000066400000000000000000000424571370110300500220070ustar00rootroot00000000000000// // linalg.c // libmsym // // Created by Marcus Johansson on 12/04/14. // Copyright (c) 2014 Marcus Johansson. // // Distributed under the MIT License ( See LICENSE file or copy at http://opensource.org/licenses/MIT ) // // Simple linear algebra functions #include #include #include #include #include #include "linalg.h" #include "debug.h" #ifndef M_PI #define M_PI 3.14159265358979323846264338327950288419716939937510582 #endif #define SQR(x) ((x)*(x)) #define CUBE(x) ((x)*(x)*(x)) void mleye(int l, double E[l][l]){ memset(E, 0, sizeof(double[l][l])); for(int i = 0;i < l;i++){ E[i][i] = 1.0; } } //#define EQUAL(A,B,T) ((fabs(((A)-(B)))) < (T)) //#define LT(A,B,T) ((B) - (A) > (T)) //#define VEQUAL(v1,v2) ((EQUAL((v1)[0],(v2)[0],2ERO_THRESHOLD)) && (EQUAL((v1)[1],(v2)[1],2ERO_THRESHOLD)) && (EQUAL((v1)[2],(v2)[2],2ERO_THRESHOLD))) //Stop using this //#define S2ERO(v) (EQUAL((v),0.0,2ERO_THRESHOLD)) //#define PARALLEL(v1,v2) (S2ERO(fabs(vdot((v1),(v2)))-1.0)) //#define PERPENDICULAR(v1,v2) (S2ERO(vdot((v1),(v2)))) void vrotate(double theta, const double v[3], const double axis[3], double vr[3]){ double m[3][3]; mrotate(theta,axis,m); mvmul(v,m,vr); } /* //v_reflected = v − 2n * dot(v,n) where n is the normal vector to the plane (assuming through origo) void vreflect(double v[3], double plane[3], double vr[3]){ double vp[3]; double dot = vdot(v,plane); vscale(2*dot,plane,vp); vsub(v,vp,vr); } */ void vreflect(double const v[3], const double axis[3], double vr[3]){ double m[3][3]; mreflect(axis,m); mvmul(v,m,vr); } // skew symmetric matrix of axb = S -> // T = I+S+(1-a.b/(||axb||^2))*S^2 void malign(const double v[3], const double axis[3], double m[3][3]){ double vn[3], axisn[3], cross[3], dot, skew[3][3], across, k; vnorm2(v, vn); vnorm2(axis, axisn); dot = vdot(vn,axisn); if(dot >= 1.0){ mleye(3,m); //m[0][0] = m[1][1] = m[2][2] = 1.0; //m[0][1] = m[0][2] = m[1][0] = m[1][2] = m[2][0] = m[2][1] = 0.0; } else if(dot <= -1.0){ vcomplement(axis, cross); mrotate(M_PI, cross, m); } else { vcross(vn,axisn,cross); across = vabs(cross); k = (1-dot)/(SQR(across)); skew[0][0] = 0.0; skew[0][1] = -cross[2]; skew[0][2] = cross[1]; skew[1][0] = cross[2]; skew[1][1] = 0.0; skew[1][2] = -cross[0]; skew[2][0] = -cross[1]; skew[2][1] = cross[0]; skew[2][2] = 0.0; mleye(3,m); madd(m,skew,m); mmmul(skew,skew,skew); mscale(k,skew,skew); madd(m,skew,m); } } void mrotate(double theta, const double axis[3], double m[3][3]){ double c = cos(theta); double s = sin(theta); //rotation matrix about an axis m[0][0] = c + (1 - c) * SQR(axis[0]); m[0][1] = (1 - c) * axis[0] * axis[1] - s * axis[2]; m[0][2] = (1 - c) * axis[0] * axis[2] + s * axis[1]; m[1][0] = (1 - c) * axis[0] * axis[1] + s * axis[2]; m[1][1] = c + (1 - c) * axis[1] * axis[1]; m[1][2] = (1 - c) * axis[2] * axis[1] - s * axis[0]; m[2][0] = (1 - c) * axis[0] * axis[2] - s * axis[1]; m[2][1] = (1 - c) * axis[1] * axis[2] + s * axis[0]; m[2][2] = c + (1 - c) * axis[2] * axis[2]; } void mreflect(double const axis[3], double m[3][3]){ m[0][0] = 1 - 2*(SQR(axis[0])); m[1][1] = 1 - 2*(SQR(axis[1])); m[2][2] = 1 - 2*(SQR(axis[2])); m[0][1] = m[1][0] = -2*axis[0]*axis[1]; m[0][2] = m[2][0] = -2*axis[0]*axis[2]; m[1][2] = m[2][1] = -2*axis[1]*axis[2]; } int vzero(const double v[3], double t){ return vabs(v) <= t; } int vparallel(const double v1[3], const double v2[3], double t){ double tv1[3], tv2[3]; vnorm2(v1,tv1); vnorm2(v2,tv2); return fabs(fabs(vdot(tv1,tv2))-1.0) <= t; } int vperpendicular(const double v1[3], const double v2[3], double t){ double tv1[3], tv2[3]; vnorm2(v1,tv1); vnorm2(v2,tv2); return fabs(vdot(tv1,tv2)) <= t; } double vlsum(int l, double v[l]){ double sum = 0.0; for(int i = 0;i < l;i++) sum += v[i]; return sum; } double vlsumsqr(int l, double v[l]){ double sum = 0.0; for(int i = 0;i < l;i++) sum += SQR(v[i]); return sum; } int vequal(const double v1[3], const double v2[3], double t){ double vs[3], va[3]; vsub(v1,v2,vs); vadd(v1,v2,va); return (vabs(vs) <= t && vabs(va) <= t)|| (vabs(vs)/vabs(va) <= t); } int vequalold(double v1[3],double v2[3], double t){ int e = 1; for(int i = 0;i < 3;i++){ e &= (fabs(v1[i] - v2[i]) <= t); } return e; } //v_projected = v - dot(v, n) * n where n is the normal vector to the plane (assuming through origo) void vproj_plane(double v[3], double plane[3], double proj[3]){ double vp[3], nplane[3]; vnorm2(plane,nplane); double dot = vdot(v,nplane); vscale(dot,nplane,vp); vsub(v,vp,proj); } void vproj(const double v[3], const double u[3], double vo[3]){ vlproj(3, v, u, vo); } void vlproj(int l, const double v[l], const double u[l], double vo[l]){ vlscale(vldot(l,u,v)/vldot(l,u,u),l,u,vo); } void vcomplement(const double v1[3], double v2[3]){ double c[2][3] = {{v1[2],v1[2],-v1[0]-v1[1]},{-v1[1]-v1[2],v1[0],v1[0]}}; int i = ((v1[2] != 0.0) && (-v1[0] != v1[1])); vcopy(c[i], v2); vnorm(v2); } double vangle(const double v1[3], const double v2[3]){ double c = vdot(v1,v2)/(vabs(v1)*vabs(v2)); if(c > 1.0) c = 1.0; if(c < -1.0) c = -1.0; return acos(c); } void vcross(const double v1i[3], const double v2i[3], double vr[3]) { double v1[3], v2[3]; //use copies so we can do vcross(a,b,a); vcopy(v1i,v1); vcopy(v2i,v2); vr[0] = v1[1]*v2[2]-v1[2]*v2[1]; vr[1] = v1[2]*v2[0]-v1[0]*v2[2]; vr[2] = v1[0]*v2[1]-v1[1]*v2[0]; } double vcrossnorm(const double v1i[3], const double v2i[3], double vr[3]) { vcross(v1i,v2i,vr); return vnorm(vr); } double vdot(const double v1[3], const double v2[3]) { return v1[0]*v2[0]+v1[1]*v2[1]+v1[2]*v2[2]; } double vldot(int l, const double v1[l], const double v2[l]) { double d = 0; for(int i = 0; i < l; i++) d+= v1[i]*v2[i]; return d; } void vadd(const double v1[3], const double v2[3], double vr[3]){ vr[0] = v1[0] + v2[0]; vr[1] = v1[1] + v2[1]; vr[2] = v1[2] + v2[2]; } void vladd(int l, const double v1[l], const double v2[l], double vr[l]){ for(int i = 0; i < l;i++) vr[i] = v1[i] + v2[i]; } void vscale(double s, const double v[3], double vr[3]){ vr[0] = s*v[0]; vr[1] = s*v[1]; vr[2] = s*v[2]; } void vlscale(double s,int l, const double v[l], double vr[l]){ for(int i = 0;i < l;i++) vr[i] = s*v[i]; } void mscale(double s, const double m[3][3], double mr[3][3]){ for(int i=0; i<3; ++i){ for(int j=0; j<3; ++j){ mr[i][j] = s*m[i][j]; } } } void mlscale(double s,int l, const double m[l][l], double mr[l][l]){ for(int i=0; i= t){ t *= ts; vlnorm(l, o[n]); n++; } } } return n; } void jacobi(double m[6], double e[3], double ev[3][3], double threshold){ double err = 1.0; e[0] = m[0]; e[1] = m[3]; e[2] = m[5]; mleye(3,ev); while(err > 0){ err = 0.0; for(int od = 0;od < 3;od++){ int i = 1 << od, row = od >> 1, col = 1 + (od >> (od >> 1)); double ami = fabs(m[i]), eps = ami/threshold; if(fabs(e[row]) + eps == fabs(e[row]) && fabs(e[col]) + eps == fabs(e[col])){ m[i] = 0.0; } else if(ami > 0.0) { err = fmax(ami, err); double d = e[col] - e[row], t = copysign(2,d)*m[i]/(fabs(d) + sqrt(SQR(d)+4*SQR(m[i]))), c = 1/sqrt(1+SQR(t)), s = c*t; e[row] -= t * m[i]; e[col] += t * m[i]; m[i] = 0.0; /* rotate eigenvectors */ for (int k = 0; k < 3; k++){ double evr = ev[k][row], evc = ev[k][col]; ev[k][row] = c*evr - s*evc; ev[k][col] = s*evr + c*evc; } /* rotate index */ int ix = col ^ 3, iy = 4 >> row; double mix = m[ix], miy = m[iy]; m[ix] = c*mix - s*miy; m[iy] = s*mix + c*miy; } } } } void madd(const double A[3][3], const double B[3][3], double C[3][3]){ for(int i=0; i<3; ++i){ for(int j=0; j<3; ++j){ C[i][j] = A[i][j] + B[i][j]; } } } void mladd(int l, const double A[l][l], const double B[l][l], double C[l][l]){ for(int i=0; i>= 1; b *= b; } return r; } v_sim-3.8.0/lib/plug-ins/msym/libmsym/src/linalg.h000066400000000000000000000077161370110300500220130ustar00rootroot00000000000000// // linalg.h // libmsym // // Created by Marcus Johansson on 13/04/14. // Copyright (c) 2014 Marcus Johansson. // // Distributed under the MIT License ( See LICENSE file or copy at http://opensource.org/licenses/MIT ) // #ifndef __MSYM_LINALG_h #define __MSYM_LINALG_h void mleye(int l, double E[l][l]); int vzero(const double v[3], double t); int vparallel(const double v1[3], const double v2[3], double t); int vperpendicular(const double v1[3], const double v2[3], double t); double vnorm(double v[3]); double vnorm2(const double v1[3],double v2[3]); double vlnorm(int l, double v[l]); double vlnorm2(int l, const double v1[l], double v2[l]); double vabs(const double v[3]); double vlabs(int l, const double v[l]); void vinv(double v[3]); void vcopy(const double vi[3], double vo[3]); void vlcopy(int l, const double vi[l], double vo[l]); void vcross(const double v1i[3], const double v2i[3], double vr[3]); double vcrossnorm(const double[3],const double[3], double[3]); double vdot(const double[3], const double[3]); double vldot(int l, const double v1[l], const double v2[l]); int vequal(const double v1[3], const double v2[3], double t); void vadd(const double[3], const double[3], double[3]); void vladd(int l, const double v1[l], const double v2[l], double vr[l]); void madd(const double A[3][3], const double B[3][3], double C[3][3]); void mladd(int l, const double A[l][l], const double B[l][l], double C[l][l]); double vlsum(int l, double v[l]); double vlsumsqr(int l, double v[l]); void vsub(const double[3], const double[3], double[3]); void vlsub(int l, const double v1[l], const double v2[l], double vr[l]); void vscale(double, const double[3], double[3]); void vlscale(double s,int l, const double v[l], double vr[l]); void mscale(double s,const double m[3][3], double mr[3][3]); void mlscale(double s,int l, const double m[l][l], double mr[l][l]); void vproj_plane(double v[3], double plane[3], double proj[3]); void vproj(const double v[3], const double u[3], double vo[3]); void vlproj(int l, const double v[l], const double u[l], double vo[l]); void vcomplement(const double v1[3], double v2[3]); double vangle(const double[3], const double[3]); void vrotate(double theta, const double v[3], const double axis[3], double vr[3]); void mrotate(double theta, const double axis[3], double m[3][3]); void vreflect(const double v[3], const double axis[3], double vr[3]); void mreflect(const double axis[3], double m[3][3]); void mvmul(const double v[3], const double m[3][3], double r[3]); void mvlmul(int r, int c, const double M[r][c], const double v[c], double vo[r]); void mmmul(const double A[3][3], const double B[3][3], double C[3][3]); void mmlmul(int rla, int cla, const double A[rla][cla], int clb, const double B[cla][clb], double C[rla][clb]); void mmtlmul(int rla, int cla, const double A[rla][cla], int rlb, const double B[rlb][cla], double C[rla][rlb]); void mmlsymmul(int dim, const double m1[dim][dim], const double m2[dim][dim], double mr[dim][dim]); void minv(const double M[3][3], double I[3][3]); double mdet(const double M[3][3]); void mcopy(const double A[3][3], double B[3][3]); void mlcopy(int l, const double A[l][l], double B[l][l]); void mtranspose(const double A[3][3], double B[3][3]); void mltranspose(int rl, int cl, const double A[rl][cl], double B[cl][rl]); double mltrace(int l, const double M[l][l]); int mequal(const double A[3][3], const double B[3][3], double t); void malign(const double v[3], const double axis[3], double m[3][3]); int ipow(int b, int e); int mgs(int l, const double M[l][l], double O[l][l], int n, double t); int mgs2(int l, int lm, const double m[l][l], double o[l][l], int n, double t); void kron(int al, const double A[al][al], int bl, const double B[bl][bl], int cl, double C[cl][cl]); void kron2(int ar, int ac, const double A[ar][ac], int br, int bc, const double B[br][bc], double C[ar*br][ac*bc]); void mlFilterSmall(int l, double A[l][l]); void jacobi(double m[6], double e[3], double ev[3][3], double threshold); #endif /* defined(__MSYM_LINALG_h) */ v_sim-3.8.0/lib/plug-ins/msym/libmsym/src/msym.c000066400000000000000000000630311370110300500215150ustar00rootroot00000000000000// // msym.c // libmsym // // Created by Marcus Johansson on 30/01/15. // Copyright (c) 2015 Marcus Johansson. // // Distributed under the MIT License ( See LICENSE file or copy at http://opensource.org/licenses/MIT ) // #include #include #include #include "msym.h" #include "context.h" #include "symmetry.h" #include "equivalence_set.h" #include "point_group.h" #include "symmetrize.h" #include "linalg.h" #include "subspace.h" #include "debug.h" msym_error_t msymFindSymmetry(msym_context ctx){ msym_error_t ret = MSYM_SUCCESS; int elementsl = 0, esl = 0; msym_element_t *elements = NULL; msym_thresholds_t *t = NULL; msym_equivalence_set_t *es = NULL, *des = NULL;; msym_point_group_t *pg = NULL; int sopsl = 0; msym_symmetry_operation_t *sops = NULL; msym_equivalence_set_t *ses = NULL; int sesl = 0; msym_point_group_t *fpg = NULL; if(MSYM_SUCCESS != (ret = ctxGetElements(ctx, &elementsl, &elements))) goto err; if(MSYM_SUCCESS != (ret = ctxGetThresholds(ctx, &t))) goto err; if(MSYM_SUCCESS != (ret = ctxGetEquivalenceSets(ctx, &esl, &des))){ if(MSYM_SUCCESS != (ret = msymFindEquivalenceSets(ctx))) goto err; } if(MSYM_SUCCESS != (ret = ctxGetEquivalenceSets(ctx, &esl, &es))) goto err; if(MSYM_SUCCESS != (ret = ctxGetPointGroup(ctx, &pg))){ if(MSYM_SUCCESS != (ret = findSymmetryOperations(esl,es,t,&sopsl,&sops))) goto err; if(MSYM_SUCCESS != (ret = findPointGroup(sopsl, sops, t, &fpg))) goto err; pg = fpg; if(MSYM_SUCCESS != (ret = ctxSetPointGroup(ctx, pg))) { free(pg); goto err; } } if(NULL != fpg || isLinearPointGroup(pg)){ // Reuild equivalence sets after determining poing group in case they are very similar if(MSYM_SUCCESS != (ret = ctxReduceLinearPointGroup(ctx))) goto err; if(MSYM_SUCCESS != (ret = splitPointGroupEquivalenceSets(pg, esl, es, &sesl, &ses, t))) goto err; if(MSYM_SUCCESS != (ret = ctxSetEquivalenceSets(ctx, sesl, ses))) goto err; ses = NULL; sesl = 0; if(MSYM_SUCCESS != (ret = ctxGetEquivalenceSets(ctx, &esl, &es))) goto err; } if(MSYM_SUCCESS != (ret = msymFindEquivalenceSetPermutations(ctx))) goto err; if(MSYM_SUCCESS != (ret = ctxGetEquivalenceSets(ctx, &esl, &es))) goto err; //This is only for printing, since permutation may regenerate sets free(sops); return ret; err: free(ses); free(sops); if(des == NULL) { ctxDestroyEquivalcenceSets(ctx); } return ret; } msym_error_t msymSetPointGroupByName(msym_context ctx, const char *name){ msym_error_t ret = MSYM_SUCCESS; msym_point_group_t *pg = NULL, *ppg = NULL; msym_thresholds_t *t = NULL; if(MSYM_SUCCESS != (ret = ctxGetThresholds(ctx, &t))) goto err; if(MSYM_SUCCESS != (ret = ctxGetPointGroup(ctx, &ppg))){ double transform[3][3]; mleye(3,transform); if(MSYM_SUCCESS != (ret = generatePointGroupFromName(name, transform, t, &pg))) goto err; } else if(MSYM_SUCCESS != (ret = generatePointGroupFromName(name, ppg->transform, t, &pg))) goto err; if(MSYM_SUCCESS != (ret = ctxSetPointGroup(ctx, pg))) goto err; return ret; err: free(pg); return ret; } msym_error_t msymSetPointGroupByType(msym_context ctx, msym_point_group_type_t type, int n){ msym_error_t ret = MSYM_SUCCESS; msym_point_group_t *pg = NULL, *ppg = NULL; msym_thresholds_t *t = NULL; if(MSYM_SUCCESS != (ret = ctxGetThresholds(ctx, &t))) goto err; if(MSYM_SUCCESS != (ret = ctxGetPointGroup(ctx, &ppg))){ double transform[3][3]; mleye(3,transform); if(MSYM_SUCCESS != (ret = generatePointGroupFromType(type, n, transform, t, &pg))) goto err; } else if(MSYM_SUCCESS != (ret = generatePointGroupFromType(type, n, ppg->transform, t, &pg))) goto err; if(MSYM_SUCCESS != (ret = ctxSetPointGroup(ctx, pg))) goto err; return ret; err: free(pg); return ret; } msym_error_t msymGenerateElements(msym_context ctx, int length, msym_element_t elements[length]){ msym_error_t ret = MSYM_SUCCESS; msym_point_group_t *pg = NULL; msym_thresholds_t *t = NULL; msym_element_t *gelements = NULL; msym_equivalence_set_t *es = NULL; msym_element_t **pelements = NULL; double err = 0.0; double cm[3]; int glength = 0, plength = 0, esl = 0; if(MSYM_SUCCESS != (ret = ctxGetThresholds(ctx, &t))) goto err; if(MSYM_SUCCESS != (ret = msymGetCenterOfMass(ctx, cm))) goto err; if(MSYM_SUCCESS != (ret = ctxGetPointGroup(ctx, &pg))) goto err; if(MSYM_SUCCESS != (ret = generateEquivalenceSet(pg, length, elements, cm, &glength, &gelements, &esl, &es,t))) goto err; if(MSYM_SUCCESS != (ret = ctxSetElements(ctx, glength, gelements))) goto err; if(MSYM_SUCCESS != (ret = ctxGetElementPtrs(ctx, &plength, &pelements))) goto err; if(plength != glength){ ret = MSYM_INVALID_ELEMENTS; msymSetErrorDetails("Inconsistency detected when setting elements"); goto err; } for(int i = 0;i < esl;i++){ for(int j = 0;j < es[i].length;j++){ long int index = es[i].elements[j] - gelements; es[i].elements[j] = pelements[index]; } } if(MSYM_SUCCESS != (ret = ctxSetEquivalenceSets(ctx, esl, es))) goto err; es = NULL; esl = 0; if(MSYM_SUCCESS != (ret = msymFindEquivalenceSetPermutations(ctx))) goto err; if(MSYM_SUCCESS != (ret = msymSymmetrizeElements(ctx, &err))) goto err; if(MSYM_SUCCESS != (ret = msymSetCenterOfMass(ctx, cm))) goto err; free(gelements); return ret; err: free(gelements); free(es); return ret; } msym_error_t msymFindEquivalenceSets(msym_context ctx){ msym_error_t ret = MSYM_SUCCESS; int pelementsl = 0; msym_element_t **pelements = NULL; msym_thresholds_t *t = NULL; msym_point_group_t *pg = NULL; msym_geometry_t g = MSYM_GEOMETRY_UNKNOWN; double eigvec[3][3]; double eigval[3]; int esl = 0; msym_equivalence_set_t *es; if(MSYM_SUCCESS != (ret = ctxGetElementPtrs(ctx, &pelementsl, &pelements))) goto err; if(MSYM_SUCCESS != (ret = ctxGetThresholds(ctx, &t))) goto err; if(MSYM_SUCCESS != (ret = ctxGetPointGroup(ctx, &pg))) { if(MSYM_SUCCESS != (ret = ctxGetGeometry(ctx, &g, eigval, eigvec))) goto err; if(MSYM_SUCCESS != (ret = findEquivalenceSets(pelementsl, pelements, g, &esl, &es, t))) goto err; } else { if(MSYM_SUCCESS != (ret = findPointGroupEquivalenceSets(pg, pelementsl, pelements, &esl, &es, t))) goto err; } if(MSYM_SUCCESS != (ret = ctxSetEquivalenceSets(ctx, esl, es))) goto err; err: return ret; } msym_error_t msymAlignAxes(msym_context ctx){ msym_error_t ret = MSYM_SUCCESS; msym_element_t *elements = NULL; msym_point_group_t *pg; int elementsl = 0; double zero[3] = {0,0,0}; if(MSYM_SUCCESS != (ret = ctxGetElements(ctx, &elementsl, &elements))) goto err; if(MSYM_SUCCESS != (ret = ctxGetPointGroup(ctx, &pg))) goto err; if(pg->sops == NULL || pg->order == 0){ msymSetErrorDetails("No symmetry operations in point group"); ret = MSYM_INVALID_POINT_GROUP; goto err; } if(MSYM_SUCCESS != (ret = msymSetCenterOfMass(ctx, zero))) goto err; for(int i = 0; i < elementsl;i++) mvmul(elements[i].v, pg->transform, elements[i].v); for(int i = 0; i < pg->order;i++) mvmul(pg->sops[i].v, pg->transform, pg->sops[i].v); mleye(3,pg->transform); if(MSYM_SUCCESS != (ret = ctxUpdateExternalElementCoordinates(ctx))) goto err; err: return ret; } msym_error_t msymGetAlignmentAxes(msym_context ctx, double primary[3], double secondary[3]){ msym_error_t ret = MSYM_SUCCESS; msym_point_group_t *pg; if(MSYM_SUCCESS != (ret = ctxGetPointGroup(ctx, &pg))) goto err; double m[3][3], x[3] = {1,0,0}, z[3] = {0,0,1}; minv(pg->transform,m); mvmul(z, m, primary); mvmul(x, m, secondary); err: return ret; } msym_error_t msymGetAlignmentTransform(msym_context ctx, double transform[3][3]){ msym_error_t ret = MSYM_SUCCESS; msym_point_group_t *pg; if(MSYM_SUCCESS != (ret = ctxGetPointGroup(ctx, &pg))) goto err; mcopy(pg->transform, transform); err: return ret; } msym_error_t msymSetAlignmentTransform(msym_context ctx, double transform[3][3]){ msym_error_t ret = MSYM_SUCCESS; msym_point_group_t *pg; msym_element_t *elements = NULL; msym_thresholds_t *t = NULL; msym_equivalence_set_t *es = NULL; int elementsl = 0, esl = 0; double m[3][3]; if(MSYM_SUCCESS != (ret = ctxGetThresholds(ctx, &t))) goto err; if(MSYM_SUCCESS != (ret = ctxGetElements(ctx, &elementsl, &elements))){ elements = NULL; elementsl = 0; } if(MSYM_SUCCESS != (ret = ctxGetEquivalenceSets(ctx, &esl, &es))){ es = NULL; esl = 0; } if(MSYM_SUCCESS != (ret = ctxGetPointGroup(ctx, &pg))) goto err; if(pg->sops == NULL || pg->order == 0){ msymSetErrorDetails("No symmetry operations in point group for setting alignment transform"); ret = MSYM_INVALID_POINT_GROUP; goto err; } /* Don't transform elements if we don't have an equivalence set the current pg is set manually */ if(NULL != es){ for(int i = 0; i < elementsl;i++) mvmul(elements[i].v, pg->transform, elements[i].v); } for(int i = 0; i < pg->order;i++) mvmul(pg->sops[i].v, pg->transform, pg->sops[i].v); minv(transform,m); mcopy(transform, pg->transform); if(NULL != es){ for(int i = 0; i < elementsl;i++) mvmul(elements[i].v, m, elements[i].v); } for(int i = 0; i < pg->order;i++) mvmul(pg->sops[i].v, m, pg->sops[i].v); err: return ret; } msym_error_t msymSetAlignmentAxes(msym_context ctx, double primary[3], double secondary[3]){ msym_error_t ret = MSYM_SUCCESS; msym_point_group_t *pg; msym_element_t *elements = NULL; msym_thresholds_t *t = NULL; msym_equivalence_set_t *es = NULL; int elementsl = 0, esl = 0; double x[3] = {1,0,0}, z[3] = {0,0,1}, m[3][3], p[3], s[3]; vnorm2(primary, p); vnorm2(secondary,s); if(MSYM_SUCCESS != (ret = ctxGetThresholds(ctx, &t))) goto err; if(MSYM_SUCCESS != (ret = ctxGetElements(ctx, &elementsl, &elements))){ elements = NULL; elementsl = 0; } if(MSYM_SUCCESS != (ret = ctxGetEquivalenceSets(ctx, &esl, &es))){ es = NULL; esl = 0; } if(MSYM_SUCCESS != (ret = ctxGetPointGroup(ctx, &pg))) goto err; if(pg->sops == NULL || pg->order == 0){ msymSetErrorDetails("No symmetry operations in point group for setting alignment axes"); ret = MSYM_INVALID_POINT_GROUP; goto err; } if(!vperpendicular(primary, secondary, t->angle)) { msymSetErrorDetails("Alignment axes are not orthogonal"); ret = MSYM_INVALID_AXES; goto err; } /* Don't transform elements if we don't have an equivalence set the current pg is set manually */ if(NULL != es){ for(int i = 0; i < elementsl;i++) mvmul(elements[i].v, pg->transform, elements[i].v); } for(int i = 0; i < pg->order;i++) mvmul(pg->sops[i].v, pg->transform, pg->sops[i].v); vproj_plane(s, p, s); malign(p,z,pg->transform); mvmul(s, pg->transform, s); malign(s,x,m); mmmul(m,pg->transform,pg->transform); minv(pg->transform,m); if(NULL != es){ for(int i = 0; i < elementsl;i++) mvmul(elements[i].v, m, elements[i].v); } for(int i = 0; i < pg->order;i++) mvmul(pg->sops[i].v, m, pg->sops[i].v); err: return ret; } msym_error_t msymSelectSubgroup(msym_context ctx, const msym_subgroup_t *sg){ msym_error_t ret = MSYM_SUCCESS; msym_subgroup_t *sgs; msym_point_group_t *pg; msym_thresholds_t *t = NULL; int sgl = 0; if(MSYM_SUCCESS != (ret = ctxGetSubgroups(ctx, &sgl, &sgs))) goto err; if(sg < sgs || sg >= sgs + sgl){ msymSetErrorDetails("Subgroup not available in current context"); ret = MSYM_INVALID_SUBGROUPS; goto err; } if(MSYM_SUCCESS != (ret = ctxGetThresholds(ctx, &t))) goto err; if(MSYM_SUCCESS != (ret = pointGroupFromSubgroup(sg, t, &pg))) goto err; if(MSYM_SUCCESS != (ret = ctxSetPointGroup(ctx, pg))) goto err; if(MSYM_SUCCESS != (ret = msymFindEquivalenceSets(ctx))) goto err; if(MSYM_SUCCESS != (ret = msymFindEquivalenceSetPermutations(ctx))) goto err; err: return ret; } msym_error_t msymSymmetrizeElements(msym_context ctx, double *oerr){ msym_error_t ret = MSYM_SUCCESS; msym_point_group_t *pg = NULL; msym_equivalence_set_t *es = NULL; msym_element_t *elements = NULL; msym_permutation_t **perm = NULL; msym_thresholds_t *t = NULL; double error = 0.0; int perml = 0, esl = 0, elementsl = 0, sopsl = 0; if(MSYM_SUCCESS != (ret = ctxGetThresholds(ctx, &t))) goto err; if(MSYM_SUCCESS != (ret = ctxGetElements(ctx, &elementsl, &elements))) goto err; if(MSYM_SUCCESS != (ret = ctxGetPointGroup(ctx, &pg))) goto err; if(MSYM_SUCCESS != (ret = ctxGetEquivalenceSets(ctx, &esl, &es))){ if(MSYM_SUCCESS != (ret = msymFindEquivalenceSets(ctx))) goto err; if(MSYM_SUCCESS != (ret = msymFindEquivalenceSetPermutations(ctx))) goto err; if(MSYM_SUCCESS != (ret = ctxGetEquivalenceSets(ctx, &esl, &es))) goto err; } if(MSYM_SUCCESS != (ret = ctxGetEquivalenceSetPermutations(ctx, &perml, &sopsl, &perm))) goto err; if(sopsl != pg->order || perml != esl) { msymSetErrorDetails("Detected inconsistency between point group, equivalence sets and permutaions"); ret = MSYM_INVALID_PERMUTATION; goto err; } if(MSYM_SUCCESS != (ret = symmetrizeElements(pg, esl, es, perm, t, &error))) goto err; if(MSYM_SUCCESS != (ret = ctxUpdateGeometry(ctx))) goto err; if(MSYM_SUCCESS != (ret = ctxUpdateExternalElementCoordinates(ctx))) goto err; *oerr = error; err: return ret; } msym_error_t msymApplyTranslation(msym_context ctx, msym_element_t *ext, double v[3]){ msym_error_t ret = MSYM_SUCCESS; msym_point_group_t *pg; msym_equivalence_set_t *es, *ees; msym_element_t *eelements; msym_equivalence_set_t **eesmap = NULL; msym_permutation_t **perm; msym_thresholds_t *t = NULL; int perml = 0, esl = 0, eesl = 0, eelementsl = 0, sopsl = 0; if(MSYM_SUCCESS != (ret = ctxGetThresholds(ctx, &t))) goto err; if(MSYM_SUCCESS != (ret = ctxGetPointGroup(ctx, &pg))) goto err; if(MSYM_SUCCESS != (ret = ctxGetExternalElements(ctx, &eelementsl, &eelements))) goto err; if(MSYM_SUCCESS != (ret = ctxGetEquivalenceSets(ctx, &esl, &es))){ if(MSYM_SUCCESS != (ret = msymFindEquivalenceSets(ctx))) goto err; if(MSYM_SUCCESS != (ret = msymFindEquivalenceSetPermutations(ctx))) goto err; if(MSYM_SUCCESS != (ret = ctxGetEquivalenceSets(ctx, &esl, &es))) goto err; } if(MSYM_SUCCESS != (ret = ctxGetExternalEquivalenceSets(ctx, &eesl, &ees))) goto err; if(MSYM_SUCCESS != (ret = ctxGetExternalElementEquivalenceSetMap(ctx, &eesmap))) goto err; if(MSYM_SUCCESS != (ret = ctxGetEquivalenceSetPermutations(ctx, &perml, &sopsl, &perm))) goto err; if(sopsl != pg->order || perml != esl) { msymSetErrorDetails("Detected inconsistency between point group, equivalence sets and permutaions"); ret = MSYM_INVALID_PERMUTATION; goto err; } int esmi = (int)(ext - eelements); if(esmi > eelementsl) { msymSetErrorDetails("Element outside of memory block of external elements"); ret = MSYM_INVALID_ELEMENTS; goto err; } int fesi = (int)(eesmap[esmi] - ees); msym_equivalence_set_t *fes = eesmap[esmi]; int fi = 0; for(fi = 0;fi < fes->length;fi++){ if(fes->elements[fi] == ext) break; } if(fi >= fes->length){ msymSetErrorDetails("Could not find index of element %s in equivalence set %d", ext->name, fesi); ret = MSYM_INVALID_ELEMENTS; goto err; } if(MSYM_SUCCESS != (ret = symmetrizeTranslation(pg, &es[fesi], perm[fesi], fi, v))) goto err; if(MSYM_SUCCESS != (ret = ctxUpdateExternalElementCoordinates(ctx))) goto err; return ret; err: return ret; } msym_error_t msymGenerateSubrepresentationSpaces(msym_context ctx){ msym_error_t ret = MSYM_SUCCESS; msym_point_group_t *pg = NULL; msym_basis_function_t *basis = NULL; msym_equivalence_set_t *es = NULL; msym_equivalence_set_t **eesmap = NULL; msym_permutation_t **perm = NULL; msym_thresholds_t *t = NULL; msym_subrepresentation_space_t *srs = NULL; msym_basis_function_t **srsbf = NULL; msym_element_t *elements = NULL; const msym_subgroup_t *sg = NULL; int *span = NULL; int basisl = 0, esl = 0, perml = 0, sopsl = 0, srsl = 0, elementsl = 0, sgl = 0; if(MSYM_SUCCESS != (ret = ctxGetThresholds(ctx, &t))) goto err; if(MSYM_SUCCESS != (ret = ctxGetExternalElements(ctx, &elementsl, &elements))) goto err; if(MSYM_SUCCESS != (ret = ctxGetPointGroup(ctx, &pg))) goto err; if(pg->ct == NULL){ if(MSYM_SUCCESS != (ret = generateCharacterTable(pg->type, pg->n, pg->order, pg->sops, &pg->ct))) goto err; } if(MSYM_SUCCESS != (ret = ctxGetExternalEquivalenceSets(ctx, &esl, &es))) goto err; if(MSYM_SUCCESS != (ret = ctxGetExternalElementEquivalenceSetMap(ctx, &eesmap))) goto err; if(MSYM_SUCCESS != (ret = ctxGetBasisFunctions(ctx, &basisl, &basis))) goto err; if(MSYM_SUCCESS != (ret = ctxGetEquivalenceSetPermutations(ctx, &perml, &sopsl, &perm))) goto err; if(sopsl != pg->order || perml != esl) {ret = MSYM_INVALID_PERMUTATION; goto err;} if(MSYM_SUCCESS != (ret = msymGetSubgroups(ctx, &sgl, &sg))) goto err; if(MSYM_SUCCESS != (ret = generateSubrepresentationSpaces(pg, sgl, sg, esl, es, perm, basisl, basis, elements, eesmap, t, &srsl, &srs, &srsbf, &span))) goto err; if(MSYM_SUCCESS != (ret = ctxSetSubrepresentationSpaces(ctx,srsl,srs,srsbf,span))) goto err; return ret; err: freeSubrepresentationSpaces(srsl, srs); free(srs); free(span); return ret; } msym_error_t msymGetSALCs(msym_context ctx, int l, double c[l][l], int species[l], msym_partner_function_t pf[l]){ msym_error_t ret = MSYM_SUCCESS; msym_subrepresentation_space_t *srs = NULL; msym_basis_function_t *basis = NULL; int *span = NULL; int srsl = 0, basisl = 0; if(MSYM_SUCCESS != (ret = ctxGetBasisFunctions(ctx, &basisl, &basis))) goto err; if(MSYM_SUCCESS != (ret = ctxGetSubrepresentationSpaces(ctx, &srsl, &srs, &span))){ if(MSYM_SUCCESS != (ret = msymGenerateSubrepresentationSpaces(ctx))) goto err; if(MSYM_SUCCESS != (ret = ctxGetSubrepresentationSpaces(ctx, &srsl, &srs, &span))) goto err; } if(l != basisl){ ret = MSYM_INVALID_INPUT; msymSetErrorDetails("Supplied SALC matrix size (%dx%d) does not match number of basis functions (%d)",l,l,basisl); goto err; } memset(c,0,sizeof(double[l][l])); int wf = 0; for(int i = 0;i < srsl;i++){ int s = srs[i].s; for(int j = 0;j < srs[i].salcl;j++){ int pwf = wf; double (*mpf)[srs[i].salc[j].fl] = srs[i].salc[j].pf; for(int d = 0;d < srs[i].salc[j].d;d++){ if(wf >= basisl){ ret = MSYM_INVALID_SUBSPACE; msymSetErrorDetails("Generated more SALCs than the number of basis functions (%d)", basisl); goto err; } for(int f = 0;f < srs[i].salc[j].fl;f++){ int index = (int)(srs[i].salc[j].f[f] - basis); c[wf][index] = mpf[d][f]; } if(NULL != pf){ pf[wf].i = pwf; pf[wf].d = d; } if(NULL != species) species[wf] = s; wf++; } } } if(wf != basisl){ ret = MSYM_INVALID_BASIS_FUNCTIONS; msymSetErrorDetails("Number of generated SALC wavefunctions (%d) does not match orbital basis (%d)",wf,basisl); goto err; } err: return ret; } msym_error_t msymSymmetrySpeciesComponents(msym_context ctx, int wfl, double *wf, int sl, double *s){ msym_error_t ret = MSYM_SUCCESS; msym_point_group_t *pg = NULL; msym_subrepresentation_space_t *srs = NULL; msym_basis_function_t *basis = NULL; int *span = NULL; int srsl = 0, basisl = 0; if(MSYM_SUCCESS != (ret = ctxGetPointGroup(ctx, &pg))) goto err; if(pg->ct == NULL){ if(MSYM_SUCCESS != (ret = generateCharacterTable(pg->type, pg->n, pg->order, pg->sops, &pg->ct))) goto err; } if(MSYM_SUCCESS != (ret = ctxGetBasisFunctions(ctx, &basisl, &basis))) goto err; if(basisl != wfl) { ret = MSYM_INVALID_INPUT; msymSetErrorDetails("Supplied coefficient vector size (%d) does not match number of basis functions (%d)",wfl,basisl); goto err; } if(sl != pg->ct->d) { ret = MSYM_INVALID_INPUT; msymSetErrorDetails("Supplied symmetry species vector size (%d) does not match character table (%d)",sl,pg->ct->d); goto err; } if(MSYM_SUCCESS != (ret = ctxGetSubrepresentationSpaces(ctx, &srsl, &srs, &span))){ if(MSYM_SUCCESS != (ret = msymGenerateSubrepresentationSpaces(ctx))) goto err; if(MSYM_SUCCESS != (ret = ctxGetSubrepresentationSpaces(ctx, &srsl, &srs, &span))) goto err; } if(MSYM_SUCCESS != (ret = symmetrySpeciesComponents(pg, srsl, srs, basisl, basis, wf, s))) goto err; err: return ret; } msym_error_t msymSymmetrizeWavefunctions(msym_context ctx, int l, double c[l][l], int species[l], msym_partner_function_t pf[l]){ msym_error_t ret = MSYM_SUCCESS; msym_point_group_t *pg = NULL; msym_subrepresentation_space_t *srs = NULL; msym_basis_function_t *basis = NULL; int *span = NULL; int srsl = 0, basisl = 0; if(MSYM_SUCCESS != (ret = ctxGetPointGroup(ctx, &pg))) goto err; if(pg->ct == NULL){ if(MSYM_SUCCESS != (ret = generateCharacterTable(pg->type, pg->n, pg->order, pg->sops, &pg->ct))) goto err; } if(MSYM_SUCCESS != (ret = ctxGetBasisFunctions(ctx, &basisl, &basis))) goto err; if(basisl != l) { ret = MSYM_INVALID_INPUT; msymSetErrorDetails("Supplied wavefunction matrix size (%d) does not match number of basis functions (%d)",l,basisl); goto err; } if(MSYM_SUCCESS != (ret = ctxGetSubrepresentationSpaces(ctx, &srsl, &srs, &span))){ if(MSYM_SUCCESS != (ret = msymGenerateSubrepresentationSpaces(ctx))) goto err; if(MSYM_SUCCESS != (ret = ctxGetSubrepresentationSpaces(ctx, &srsl, &srs, &span))) goto err; } if(MSYM_SUCCESS != (ret = symmetrizeWavefunctions(pg, srsl, srs, span, basisl, basis, c , c, species, pf))) goto err; err: return ret; } msym_error_t msymFindEquivalenceSetPermutations(msym_context ctx) { msym_error_t ret = MSYM_SUCCESS; //We can't allocate this as a double[][] unless we typecast it every time, since the compiler doesn't have the indexing information in the context msym_permutation_t **perm = NULL; msym_permutation_t *bperm = NULL; msym_point_group_t *pg = NULL; msym_equivalence_set_t *es = NULL; msym_thresholds_t *t = NULL; double (**esv)[3] = NULL; int esl = 0; if(MSYM_SUCCESS != (ret = ctxGetThresholds(ctx, &t))) goto err; if(MSYM_SUCCESS != (ret = ctxGetPointGroup(ctx, &pg))) goto err; if(MSYM_SUCCESS != (ret = ctxGetEquivalenceSets(ctx, &esl, &es))) goto err; perm = (msym_permutation_t**)malloc(esl*sizeof(msym_permutation_t*) + esl*pg->order*sizeof(msym_permutation_t)); bperm = (msym_permutation_t*)(perm + esl); memset(bperm,0,esl*pg->order*sizeof(msym_permutation_t)); for(int i = 0; i < esl;i++){ perm[i] = bperm + i*pg->order; if(es[i].length > pg->order){ msymSetErrorDetails("Equivalence set has more elements (%d) than the order of the point group %s (%d)",es[i].length,pg->name,pg->order); ret = MSYM_INVALID_EQUIVALENCE_SET; goto err; } } /* if(perm == NULL){ perm = (msym_permutation_t**)malloc(esl*sizeof(msym_permutation_t*) + esl*pg->sopsl*sizeof(msym_permutation_t)); bperm = (msym_permutation_t*)(perm + esl); memset(bperm,0,esl*pg->sopsl*sizeof(msym_permutation_t)); for(int i = 0; i < esl;i++){ //This really shouldn't happen perm[i] = bperm + i*pg->sopsl; if(es[i].length > pg->order){ msymSetErrorDetails("Equivalence set has more elements (%d) than the order of the point group %s (%d)",es[i].length,pg->name,pg->order); ret = MSYM_INVALID_EQUIVALENCE_SET; goto err; } } }*/ esv = malloc(sizeof(double (*[pg->order])[3])); for(int i = 0; i < esl;i++){ for(int j = 0; j < es[i].length;j++){ esv[j] = &es[i].elements[j]->v; } for(int j = 0; j < pg->order;j++){ if(MSYM_SUCCESS != (ret = findPermutation(&pg->sops[j], es[i].length, esv, t, &perm[i][j]))) goto err; } } if(MSYM_SUCCESS != (ret = ctxSetEquivalenceSetPermutations(ctx, esl, pg->order, perm))) goto err; free(esv); return ret; err: free(esv); free(perm); return ret; } v_sim-3.8.0/lib/plug-ins/msym/libmsym/src/msym.h000066400000000000000000000253531370110300500215270ustar00rootroot00000000000000// // msym.h // libmsym // // Created by Marcus Johansson on 30/01/15. // Copyright (c) 2015 Marcus Johansson. // // Distributed under the MIT License ( See LICENSE file or copy at http://opensource.org/licenses/MIT ) // #ifndef __MSYM_H #define __MSYM_H #ifdef __cplusplus extern "C" { #endif #include "msym_EXPORTS.h" // automatically generated by cmake #include "msym_error.h" typedef struct _msym_context * msym_context; typedef enum _msym_geometry { MSYM_GEOMETRY_UNKNOWN = 0, MSYM_GEOMETRY_SPHERICAL = 1, MSYM_GEOMETRY_LINEAR = 2, MSYM_GEOMETRY_PLANAR_REGULAR = 3, MSYM_GEOMETRY_PLANAR_IRREGULAR = 4, MSYM_GEOMETRY_POLYHEDRAL_PROLATE = 5, MSYM_GEOMETRY_POLYHEDRAL_OBLATE = 6, MSYM_GEOMETRY_ASSYMETRIC = 7 } msym_geometry_t; typedef struct _msym_symmetry_operation { enum _msym_symmetry_operation_type { MSYM_SYMMETRY_OPERATION_TYPE_IDENTITY = 0, MSYM_SYMMETRY_OPERATION_TYPE_PROPER_ROTATION = 1, MSYM_SYMMETRY_OPERATION_TYPE_IMPROPER_ROTATION = 2, MSYM_SYMMETRY_OPERATION_TYPE_REFLECTION = 3, MSYM_SYMMETRY_OPERATION_TYPE_INVERSION = 4 } type; int order; // Order of proper/improper rotation int power; // Power (e.g. C2^2 = I) enum _msym_symmetry_operation_orientation { MSYM_SYMMETRY_OPERATION_ORIENTATION_NONE = 0, MSYM_SYMMETRY_OPERATION_ORIENTATION_HORIZONTAL = 1, MSYM_SYMMETRY_OPERATION_ORIENTATION_VERTICAL = 2, MSYM_SYMMETRY_OPERATION_ORIENTATION_DIHEDRAL = 3 } orientation; double v[3]; // Proper/improper rotation vector or reflection plane normal int cla; // Class of symmetry operation (point group dependant) } msym_symmetry_operation_t; typedef enum _msym_point_group_type { MSYM_POINT_GROUP_TYPE_Kh = 0, MSYM_POINT_GROUP_TYPE_K = 1, MSYM_POINT_GROUP_TYPE_Ci = 2, MSYM_POINT_GROUP_TYPE_Cs = 3, MSYM_POINT_GROUP_TYPE_Cn = 4, MSYM_POINT_GROUP_TYPE_Cnh = 5, MSYM_POINT_GROUP_TYPE_Cnv = 6, MSYM_POINT_GROUP_TYPE_Dn = 7, MSYM_POINT_GROUP_TYPE_Dnh = 8, MSYM_POINT_GROUP_TYPE_Dnd = 9, MSYM_POINT_GROUP_TYPE_Sn = 10, MSYM_POINT_GROUP_TYPE_T = 11, MSYM_POINT_GROUP_TYPE_Td = 12, MSYM_POINT_GROUP_TYPE_Th = 13, MSYM_POINT_GROUP_TYPE_O = 14, MSYM_POINT_GROUP_TYPE_Oh = 15, MSYM_POINT_GROUP_TYPE_I = 16, MSYM_POINT_GROUP_TYPE_Ih = 17 } msym_point_group_type_t; typedef struct _msym_subgroup { msym_point_group_type_t type; int n; int order; msym_symmetry_operation_t *primary; msym_symmetry_operation_t **sops; struct _msym_subgroup *generators[2]; char name[8]; } msym_subgroup_t; typedef struct _msym_thresholds { double zero; // For determining if something is zero (e.g. vectors close to center of mass) double geometry; // For translating inertial tensor eigenvalues to geometric structures double angle; // For determining angles, (e.g. if vectors are parallel) double equivalence; // Equivalence test threshold double eigfact; // Jacobi eigenvalue algorithm threshold double permutation; // Equality test when determining permutation for symmetry operation double orthogonalization; // For orthogonalizing orbital subspaces } msym_thresholds_t; typedef struct _msym_element { void *id; // custom identifier double m; // Mass double v[3]; // Position int n; // Nuclear charge char name[4]; // Name } msym_element_t; typedef struct _msym_equivalence_set { msym_element_t **elements; // Pointers to elements double err; // Maximum error when detecting this equivalence set int length; // Number of elements } msym_equivalence_set_t ; typedef struct _msym_real_spherical_harmonic { int n; // Principal int l; // Azimuthal int m; // Liniear combination of magnetic quantum number (e.g. 2pz = 0, 2px = 1, 2py = -1) } msym_real_spherical_harmonic_t; typedef struct _msym_basis_function { void *id; // custom identifier enum _msym_basis_type { MSYM_BASIS_TYPE_REAL_SPHERICAL_HARMONIC = 0, MSYM_BASIS_TYPE_CARTESIAN = 1 } type; msym_element_t *element; union { msym_real_spherical_harmonic_t rsh; // Atomic orbital basis } f; char name[8]; } msym_basis_function_t; typedef struct _msym_partner_function { int i; // index of partner 0 int d; // component (dimension) } msym_partner_function_t; typedef struct _msym_salc { int d; // dimension of space (same as msym_character_table_t.s[msym_subrepresentation_space_t.s].d) int fl; // number of basis functions void *pf; // partner functions double[d][fl] msym_basis_function_t **f; } msym_salc_t; typedef struct _msym_subrepresentation_space { int s; // symmetry species int salcl; // nr of SALCs msym_salc_t *salc; } msym_subrepresentation_space_t; typedef struct _msym_symmetry_species { int d; // dimensionality of a (ir)reducible representation of this species int r; // sum over all x ct->classc[x]*ct->table[i][x]^2/pg->order (can be decomposed into r irreducible representations) char name[8]; } msym_symmetry_species_t; typedef struct _msym_character_table { int d; int *classc; msym_symmetry_operation_t **sops; msym_symmetry_species_t *s; void *table; //double[d][d] } msym_character_table_t; msym_context MSYM_EXPORT msymCreateContext(); msym_error_t MSYM_EXPORT msymReleaseContext(msym_context ctx); const msym_thresholds_t MSYM_EXPORT *msymGetDefaultThresholds(); msym_error_t MSYM_EXPORT msymSetThresholds(msym_context ctx, const msym_thresholds_t *thresholds); msym_error_t MSYM_EXPORT msymGetThresholds(msym_context ctx, const msym_thresholds_t **thresholds); msym_error_t MSYM_EXPORT msymSetElements(msym_context ctx, int length, msym_element_t *elements); msym_error_t MSYM_EXPORT msymGetElements(msym_context ctx, int *length, msym_element_t **elements); msym_error_t MSYM_EXPORT msymSetBasisFunctions(msym_context ctx, int length, msym_basis_function_t *basis); msym_error_t MSYM_EXPORT msymGetBasisFunctions(msym_context ctx, int *length, msym_basis_function_t **basis); msym_error_t MSYM_EXPORT msymGetPointGroupType(msym_context ctx, msym_point_group_type_t *t, int *n); msym_error_t MSYM_EXPORT msymSetPointGroupByName(msym_context ctx, const char *name); msym_error_t MSYM_EXPORT msymSetPointGroupByType(msym_context ctx, msym_point_group_type_t type, int n); msym_error_t MSYM_EXPORT msymGetPointGroupName(msym_context ctx, int l, char *buf); msym_error_t MSYM_EXPORT msymGetSubgroups(msym_context ctx, int *l, const msym_subgroup_t **subgroups); msym_error_t MSYM_EXPORT msymSelectSubgroup(msym_context ctx, const msym_subgroup_t *subgroup); msym_error_t MSYM_EXPORT msymGetSymmetryOperations(msym_context ctx, int *sopsl, const msym_symmetry_operation_t **sops); msym_error_t MSYM_EXPORT msymGetEquivalenceSets(msym_context ctx, int *l, const msym_equivalence_set_t **es); msym_error_t MSYM_EXPORT msymGetEquivalenceSetByElement(msym_context ctx, msym_element_t *element, const msym_equivalence_set_t **es); msym_error_t MSYM_EXPORT msymGetSubrepresentationSpaces(msym_context ctx, int *l, const msym_subrepresentation_space_t **srs); msym_error_t MSYM_EXPORT msymGetCharacterTable(msym_context ctx, const msym_character_table_t **ct); msym_error_t MSYM_EXPORT msymFindEquivalenceSets(msym_context ctx); msym_error_t MSYM_EXPORT msymFindEquivalenceSetPermutations(msym_context ctx); msym_error_t MSYM_EXPORT msymFindSymmetry(msym_context ctx); msym_error_t MSYM_EXPORT msymSymmetrizeElements(msym_context context, double *err); msym_error_t MSYM_EXPORT msymApplyTranslation(msym_context ctx, msym_element_t *element, double v[3]); #ifdef __cplusplus msym_error_t MSYM_EXPORT msymSymmetrizeWavefunctions(msym_context ctx, int l, void *c, int *species, msym_partner_function_t *pf); msym_error_t MSYM_EXPORT msymGetSALCs(msym_context ctx, int l, void *c, int *species, msym_partner_function_t *pf); #else msym_error_t MSYM_EXPORT msymSymmetrizeWavefunctions(msym_context ctx, int l, double c[l][l], int species[l], msym_partner_function_t pf[l]); msym_error_t MSYM_EXPORT msymGetSALCs(msym_context ctx, int l, double c[l][l], int species[l], msym_partner_function_t pf[l]); #endif msym_error_t MSYM_EXPORT msymSymmetrySpeciesComponents(msym_context ctx, int wfl, double *wf, int sl, double *s); msym_error_t MSYM_EXPORT msymGenerateElements(msym_context ctx, int length, msym_element_t *elements); msym_error_t MSYM_EXPORT msymGenerateSubrepresentationSpaces(msym_context ctx); msym_error_t MSYM_EXPORT msymAlignAxes(msym_context ctx); msym_error_t MSYM_EXPORT msymGetCenterOfMass(msym_context ctx, double v[3]); msym_error_t MSYM_EXPORT msymSetCenterOfMass(msym_context ctx, double v[3]); msym_error_t MSYM_EXPORT msymGetRadius(msym_context ctx, double *radius); msym_error_t MSYM_EXPORT msymGetGeometry(msym_context ctx, msym_geometry_t *geometry); msym_error_t MSYM_EXPORT msymGetPrincipalMoments(msym_context ctx, double eigval[3]); msym_error_t MSYM_EXPORT msymGetPrincipalAxes(msym_context ctx, double eigvec[3][3]); msym_error_t MSYM_EXPORT msymGetAlignmentAxes(msym_context ctx, double primary[3], double secondary[3]); msym_error_t MSYM_EXPORT msymSetAlignmentAxes(msym_context ctx, double primary[3], double secondary[3]); msym_error_t MSYM_EXPORT msymGetAlignmentTransform(msym_context ctx, double transform[3][3]); msym_error_t MSYM_EXPORT msymSetAlignmentTransform(msym_context ctx, double transform[3][3]); #ifdef __cplusplus } #endif #endif /* defined(__MSYM_H) */ v_sim-3.8.0/lib/plug-ins/msym/libmsym/src/msym_error.c000066400000000000000000000045631370110300500227330ustar00rootroot00000000000000// // msym_error.c // libmsym // // Created by Marcus Johansson on 30/01/15. // Copyright (c) 2015 Marcus Johansson. // // Distributed under the MIT License ( See LICENSE file or copy at http://opensource.org/licenses/MIT ) // #include #include #include "msym_error.h" #define MSYM_ERROR_DETAILS_MAX_LENGTH 1024 const char * invalid = "Invalid error code"; char err_details[MSYM_ERROR_DETAILS_MAX_LENGTH]; char err_details_ext[MSYM_ERROR_DETAILS_MAX_LENGTH]; const struct _errordesc { msym_error_t code; char *message; } error_desc[] = { { MSYM_SUCCESS, "Success" }, { MSYM_INVALID_INPUT, "Invalid input" }, { MSYM_INVALID_CONTEXT, "Invalid context" }, { MSYM_INVALID_THRESHOLD, "Invalid threshold" }, { MSYM_INVALID_ELEMENTS, "Invalid elements" }, { MSYM_INVALID_BASIS_FUNCTIONS, "Invalid basis functions" }, { MSYM_INVALID_POINT_GROUP, "Invalid point group" }, { MSYM_INVALID_PERMUTATION, "Invalid permutation" }, { MSYM_INVALID_EQUIVALENCE_SET, "Invalid equivalence set" }, { MSYM_INVALID_GEOMETRY, "Invalid geometry" }, { MSYM_INVALID_CHARACTER_TABLE, "Invalid character table" }, { MSYM_INVALID_SUBSPACE, "Invalid subspace" }, { MSYM_INVALID_SUBGROUPS, "Invalid subgroups" }, { MSYM_INVALID_AXES, "Invalid axes" }, { MSYM_SYMMETRY_ERROR, "Error determining symmetry operations" }, { MSYM_PERMUTATION_ERROR, "Error determining permutation" }, { MSYM_POINT_GROUP_ERROR, "Error determining point group" }, { MSYM_SYMMETRIZATION_ERROR, "Error symmetrizing molecule/orbtials" }, { MSYM_SUBSPACE_ERROR, "Error generating subspaces" }, { MSYM_MEMORY_ERROR, "Error allocating memory" } }; void msymSetErrorDetails(const char *format, ...){ va_list args; va_start(args, format); vsnprintf(err_details, sizeof(err_details), format, args); va_end(args); } const char MSYM_EXPORT *msymGetErrorDetails(){ snprintf(err_details_ext, sizeof(err_details_ext), "%s",err_details); // Not really neccessary msymSetErrorDetails(""); return err_details_ext; } const char MSYM_EXPORT *msymErrorString(msym_error_t error){ const char *ret = invalid; int length = sizeof(error_desc) / sizeof(error_desc[0]); for(int i = 0; i < length;i++){ if(error == error_desc[i].code){ ret = error_desc[i].message; break; } } return ret; } v_sim-3.8.0/lib/plug-ins/msym/libmsym/src/msym_error.h000066400000000000000000000026421370110300500227340ustar00rootroot00000000000000// // msym_error.h // libmsym // // Created by Marcus Johansson on 30/01/15. // Copyright (c) 2015 Marcus Johansson. // // Distributed under the MIT License ( See LICENSE file or copy at http://opensource.org/licenses/MIT ) // #ifndef __MSYM__ERROR_H #define __MSYM__ERROR_H #include "msym_EXPORTS.h" // automatically generated by cmake #ifdef __cplusplus extern "C" { #endif enum _msym_error { MSYM_SUCCESS = 0, MSYM_INVALID_INPUT = -1, MSYM_INVALID_CONTEXT = -2, MSYM_INVALID_THRESHOLD = -3, MSYM_INVALID_ELEMENTS = -4, MSYM_INVALID_BASIS_FUNCTIONS = -5, MSYM_INVALID_POINT_GROUP = -6, MSYM_INVALID_EQUIVALENCE_SET = -7, MSYM_INVALID_PERMUTATION = -8, MSYM_INVALID_GEOMETRY = -9, MSYM_INVALID_CHARACTER_TABLE = -10, MSYM_INVALID_SUBSPACE = -11, MSYM_INVALID_SUBGROUPS = -12, MSYM_INVALID_AXES = -13, MSYM_SYMMETRY_ERROR = -14, MSYM_PERMUTATION_ERROR = -15, MSYM_POINT_GROUP_ERROR = -16, MSYM_SYMMETRIZATION_ERROR = -17, MSYM_SUBSPACE_ERROR = -18, MSYM_MEMORY_ERROR = -128 }; typedef enum _msym_error msym_error_t; const char *msymErrorString(msym_error_t error); void msymSetErrorDetails(const char *format, ...); const char *msymGetErrorDetails(); #ifdef __cplusplus } #endif #endif /* defined(__MSYM__ERROR_H) */ v_sim-3.8.0/lib/plug-ins/msym/libmsym/src/permutation.c000066400000000000000000000232131370110300500230750ustar00rootroot00000000000000// // permutation.c // Symmetry // // Created by Marcus Johansson on 01/02/15. // Copyright (c) 2015 Marcus Johansson. // // Distributed under the MIT License ( See LICENSE file or copy at http://opensource.org/licenses/MIT ) // #include #include #include "msym.h" #include "permutation.h" #include "linalg.h" #include "debug.h" msym_error_t setPermutationCycles(msym_permutation_t *perm); void freePermutationData(msym_permutation_t *perm){ if(perm != NULL){ free(perm->c); free(perm->p); } } msym_error_t findPermutation(msym_symmetry_operation_t *sop, int l, double (*v[l])[3], msym_thresholds_t *t, msym_permutation_t *perm){ msym_error_t ret = MSYM_SUCCESS; double m[3][3]; symmetryOperationMatrix(sop, m); perm->p = malloc(sizeof(int[l])); memset(perm->p, -1, sizeof(int[l])); //TODO: 2s complement perm->p_length = l; for(int i = 0; i < l;i++){ int j; double r[3]; mvmul(*v[i], m, r); for(j = 0;j < l;j++){ if(vequal(r, *v[j],t->permutation)){ perm->p[i] = j; break; } } if(j == l) { char buf[16]; symmetryOperationName(sop, sizeof(buf), buf); msymSetErrorDetails("Unable to determine permutation for symmetry operation %s",buf); ret = MSYM_PERMUTATION_ERROR; goto err; } } if(MSYM_SUCCESS != (ret = setPermutationCycles(perm))) goto err; return ret; err: free(perm->p); return ret; } typedef struct _perm_subgroup { int sopsl; int *sops; int subgroup[2]; } perm_subgroup_t; msym_error_t findPermutationSubgroups(int l, msym_permutation_t perm[l], int sgmax, msym_symmetry_operation_t *sops, int *subgroupl, msym_subgroup_t **subgroup){ msym_error_t ret = MSYM_SUCCESS; perm_subgroup_t *group = calloc(l, sizeof(perm_subgroup_t)); int *isops = malloc(sizeof(int[l])); int *msops = malloc(sizeof(int[l])); int gl = 0, glm = 0; for(int i = 0;i < l;i++){ if((sops[i].power == 1 && (sops[i].type == PROPER_ROTATION || sops[i].type == IMPROPER_ROTATION)) || sops[i].type == INVERSION || sops[i].type == REFLECTION){ msym_permutation_cycle_t* c = perm[i].c; glm = gl; memset(msops, 0, sizeof(int[l])); group[gl].sopsl = c->l; group[gl].sops = realloc(group[gl].sops, sizeof(int[c->l])); memset(group[gl].sops,0,sizeof(int[c->l])); //group[gl].sops = calloc(c->l, sizeof(int)); group[gl].subgroup[0] = group[gl].subgroup[1] = -1; for(int next = c->s, j = 0;j < c->l;j++){ msops[next] = 1; group[gl].sops[j] = next; next = perm[i].p[next]; } int n = 0; for(int k = 0;k < l && n < l;k++){ if(msops[k]){ group[gl].sops[n] = k; n++; } } gl += n < l; } } if(glm == gl){ free(group[gl].sops); } for(int i = 0;i < gl && gl < sgmax;i++){ for(int j = i+1;j < gl && gl < sgmax;j++){ int minl = group[i].sopsl < group[j].sopsl ? group[i].sopsl : group[j].sopsl; if(0 == memcmp(group[i].sops,group[j].sops,sizeof(int[minl]))) continue; int n = 0; memset(isops, 0, sizeof(int[l])); memset(msops, 0, sizeof(int[l])); for(int k = 0;k < group[i].sopsl;k++){ int s = group[i].sops[k]; msops[s] = 1; isops[k] = s; } n = group[i].sopsl; for(int k = 0;k < group[j].sopsl;k++){ int s = group[j].sops[k]; if(msops[s] == 0){ msops[s] = 1; isops[n] = s; n++; } } for(int p = 0;p < n && n < l;p++){ for(int q = 0;q < n && n < l;q++){ int next = perm[isops[p]].p[isops[q]]; if(msops[next] == 0){ msops[next] = 1; isops[n] = next; n++; } } } if(n < l && n > 1) { n = 0; memset(isops, 0, sizeof(int[l])); for(int k = 0;k < l;k++){ if(msops[k]){ isops[n] = k; n++; } } int f; for(f = 0;f < gl;f++){ if(group[f].sopsl == n && 0 == memcmp(group[f].sops, isops, sizeof(int[n]))){ break; } } if(f == gl){ group = realloc(group, sizeof(perm_subgroup_t[gl+1])); group[gl].sopsl = n; group[gl].sops = malloc(sizeof(int[n])); memcpy(group[gl].sops, isops, sizeof(int[n])); group[gl].subgroup[0] = i; group[gl].subgroup[1] = j; gl++; } } } } msym_subgroup_t *mgroup = calloc(gl, sizeof(msym_subgroup_t)); for(int i = 0;i < gl;i++){ mgroup[i].sops = calloc(group[i].sopsl, sizeof(msym_symmetry_operation_t *)); mgroup[i].order = group[i].sopsl; mgroup[i].generators[0] = group[i].subgroup[0] < 0 ? NULL : &mgroup[group[i].subgroup[0]]; mgroup[i].generators[1] = group[i].subgroup[1] < 0 ? NULL : &mgroup[group[i].subgroup[1]]; for(int j = 0;j < group[i].sopsl;j++){ mgroup[i].sops[j] = &sops[group[i].sops[j]]; } } *subgroup = mgroup; *subgroupl = gl; //err: for(int i = 0;i < gl;i++){ free(group[i].sops); } free(group); free(isops); free(msops); return ret; } msym_error_t findSymmetryOperationPermutations(int l, msym_symmetry_operation_t sops[l], msym_thresholds_t *t, msym_permutation_t **rperm){ msym_error_t ret = MSYM_SUCCESS; //Don't block allocate this, it's a pain to keep track of the pointers msym_permutation_t *permutations = malloc(sizeof(msym_permutation_t[l])); for(int i = 0; i < l;i++){ permutations[i].p = malloc(sizeof(int[l])); memset(permutations[i].p, -1, sizeof(int[l])); permutations[i].p_length = l; } double (*msops)[3][3] = malloc(sizeof(double[l][3][3])); for(int i = 0; i < l;i++){ symmetryOperationMatrix(&sops[i], msops[i]); } for(int i = 0; i < l;i++){ if((sops[i].type == PROPER_ROTATION && sops[i].order == 0) || sops[i].type == IDENTITY){ for(int j = 0;j < l;j++) permutations[i].p[j] = j; } else { for(int j = 0; j < l;j++){ int k; double rsop[3][3]; mmmul(msops[i], msops[j], rsop); for(k = 0;k < l;k++){ if(mequal(rsop,msops[k],t->permutation)){ permutations[i].p[j] = k; break; } } if(k == l){ char buf1[16]; char buf2[16]; symmetryOperationName(&sops[i], sizeof(buf1), buf1); symmetryOperationName(&sops[j], sizeof(buf2), buf2); msymSetErrorDetails("Unable to determine permutation for symmetry operation %s and %s",buf1, buf2); ret = MSYM_PERMUTATION_ERROR; goto err; } } } } for(int i = 0; i < l;i++){ if(MSYM_SUCCESS != (ret = setPermutationCycles(&permutations[i]))) goto err; } free(msops); *rperm = permutations; return ret; err: free(msops); for(int i = 0; i < l;i++){ free(permutations[i].p); } free(permutations); *rperm = NULL; return ret; } msym_error_t setPermutationCycles(msym_permutation_t *perm){ msym_error_t ret = MSYM_SUCCESS; int l = perm->p_length; int *icycle = malloc(sizeof(int[l])); int *pcycle = malloc(sizeof(int[l])); int *lcycle = malloc(sizeof(int[l])); int cl = 0; memset(icycle, -1,sizeof(int[l])); //TODO: 2s complement memset(lcycle, 0,sizeof(int[l])); perm->c = NULL; perm->c_length = 0; for(int i = 0; i < l;i++){ if(icycle[i] >= 0) continue; lcycle[cl] = 1; pcycle[cl] = i; icycle[i] = cl; for(int next = perm->p[i], loop = 0; next != i;next = perm->p[next]){ if(loop++ > l) { msymSetErrorDetails("Encountered loop when determining permutation cycle"); ret = MSYM_PERMUTATION_ERROR; goto err; } icycle[next] = cl; lcycle[cl]++; }; cl++; } perm->c_length = cl; perm->c = malloc(sizeof(msym_permutation_cycle_t[cl])); for(int c = 0; c < cl;c++){ perm->c[c].l = lcycle[c]; perm->c[c].s = pcycle[c]; } err: free(icycle); free(pcycle); free(lcycle); return ret; } //We need these as doubles later, so might as well, even though we could represent these with ALOT less memory void permutationMatrix(msym_permutation_t *perm, double m[perm->p_length][perm->p_length]){ memset(m, 0, sizeof(double[perm->p_length][perm->p_length])); for(int i = 0;i < perm->p_length;i++){ //m[i][perm->p[i]] = 1.0; m[perm->p[i]][i] = 1.0; } } v_sim-3.8.0/lib/plug-ins/msym/libmsym/src/permutation.h000066400000000000000000000031241370110300500231010ustar00rootroot00000000000000// // permutation.h // Symmetry // // Created by Marcus Johansson on 01/02/15. // Copyright (c) 2015 Marcus Johansson. // // Distributed under the MIT License ( See LICENSE file or copy at http://opensource.org/licenses/MIT ) // #ifndef __MSYM__PERMUTATION_h #define __MSYM__PERMUTATION_h #include #include "symop.h" #include "msym_error.h" //There are better ways of representing a permutation (lika a Lehmer code) but I'll leave that for later typedef struct _msym_permutation_cycle_t { int l; int s; } msym_permutation_cycle_t; typedef struct _msym_permutation { int *p; int p_length; msym_permutation_cycle_t *c; int c_length; } msym_permutation_t; typedef struct _msym_permutation_morphism { enum {BIJECTION, SURJECTION} type; msym_permutation_t *domain; msym_permutation_t *codomain; int l; union { int *bijection; msym_permutation_cycle_t *surjection; } function; } msym_permutation_morphism_t; msym_error_t findSymmetryOperationPermutations(int l, msym_symmetry_operation_t sops[l], msym_thresholds_t *t, msym_permutation_t **ret); msym_error_t findPermutation(msym_symmetry_operation_t *sop, int l, double (*v[l])[3], msym_thresholds_t *t, msym_permutation_t *perm); void freePermutationData(msym_permutation_t *perm); void permutationMatrix(msym_permutation_t *perm, double m[perm->p_length][perm->p_length]); msym_error_t findPermutationSubgroups(int l, msym_permutation_t perm[l], int sgmax, msym_symmetry_operation_t *sops, int *subgroupl, msym_subgroup_t **subgroup); #endif /* defined(__MSYM__PERMUTATION_h) */ v_sim-3.8.0/lib/plug-ins/msym/libmsym/src/point_group.c000066400000000000000000002532441370110300500231040ustar00rootroot00000000000000// // point_group.c // Symmetry // // Created by Marcus Johansson on 14/04/14. // Copyright (c) 2014 Marcus Johansson. // // Distributed under the MIT License ( See LICENSE file or copy at http://opensource.org/licenses/MIT ) // #include #include #include #include #include #include "symmetry.h" #include "linalg.h" #include "point_group.h" #include "permutation.h" #include "debug.h" #define PHI 1.618033988749894848204586834 #ifndef M_PI #define M_PI 3.14159265358979323846264338327950288419716939937510582 #endif #ifndef M_PI_2 #define M_PI_2 (M_PI/2) #endif #define CLASSIFICATION_THRESHOLD 0.01 msym_error_t determinePointGroup(int sopsl, msym_symmetry_operation_t *sops, msym_thresholds_t *thresholds, msym_point_group_t *pg); msym_error_t generatePointGroup(msym_point_group_type_t type, int n, msym_symmetry_operation_t *primary, int sopsl, msym_symmetry_operation_t sops[sopsl], msym_thresholds_t *thresholds, msym_point_group_t **opg); msym_error_t reorientAxes(msym_symmetry_operation_t *primary, int sopsl, msym_symmetry_operation_t sops[sopsl], msym_thresholds_t *thresholds); msym_error_t transformAxes(msym_point_group_type_t type, int n, msym_symmetry_operation_t *primary, int sopsl, msym_symmetry_operation_t sops[sopsl], msym_thresholds_t *thresholds, double transform[3][3]); msym_error_t transformPrimary(msym_symmetry_operation_t *primary, int sopsl, msym_symmetry_operation_t sops[sopsl], msym_thresholds_t *thresholds, double transform[3][3]); msym_error_t transformSecondary(msym_point_group_type_t type, msym_symmetry_operation_t *primary, int sopsl, msym_symmetry_operation_t sops[sopsl], msym_thresholds_t *thresholds, double transform[3][3]); msym_error_t getPointGroupOrder(msym_point_group_type_t type, int n, int *order); msym_error_t getPointGroupName(msym_point_group_type_t type, int n, size_t max, char name[max]); msym_error_t findSecondaryAxisSigma(msym_symmetry_operation_t *primary, int sopsl, msym_symmetry_operation_t sops[sopsl], msym_thresholds_t *thresholds, double r[3]); msym_error_t findSecondaryAxisC2(msym_symmetry_operation_t *primary, int sopsl, msym_symmetry_operation_t sops[sopsl], msym_thresholds_t *thresholds, double r[3]); msym_error_t findSecondaryAxisC4(msym_symmetry_operation_t *primary, int sopsl, msym_symmetry_operation_t sops[sopsl], msym_thresholds_t *thresholds, double r[3]); msym_error_t findSecondaryAxisC2C5(msym_symmetry_operation_t *primary, int sopsl, msym_symmetry_operation_t sops[sopsl], msym_thresholds_t *thresholds, double r[3]); msym_error_t generateSymmetryOperations(msym_point_group_type_t type, int n, int order, msym_symmetry_operation_t **osops); msym_error_t generateSymmetryOperationsImpliedRot(int sopsl, msym_symmetry_operation_t sops[sopsl], int order, msym_thresholds_t *thresholds, int *osopsl); msym_error_t generateSymmetryOperationsCs(int n, int l, msym_symmetry_operation_t sops[l], int *pk, int *pcla); msym_error_t generateSymmetryOperationsCi(int n, int l, msym_symmetry_operation_t sops[l], int *pk, int *pcla); msym_error_t generateSymmetryOperationsDn(int n, int l, msym_symmetry_operation_t sops[l], int *pk, int *pcla); msym_error_t generateSymmetryOperationsDnd(int n, int l, msym_symmetry_operation_t sops[l], int *pk, int *pcla); msym_error_t generateSymmetryOperationsDnh(int n, int l, msym_symmetry_operation_t sops[l], int *pk, int *pcla); msym_error_t generateSymmetryOperationsSn(int n, int l, msym_symmetry_operation_t sops[l], int *pk, int *pcla); msym_error_t generateSymmetryOperationsCn(int n, int l, msym_symmetry_operation_t sops[l], int *pk, int *pcla); msym_error_t generateSymmetryOperationsCnv(int n, int l, msym_symmetry_operation_t sops[l], int *pk, int *pcla); msym_error_t generateSymmetryOperationsCnh(int n, int l, msym_symmetry_operation_t sops[l], int *pk, int *pcla); msym_error_t generateSymmetryOperationsT(int n, int l, msym_symmetry_operation_t sops[l], int *pk, int *pcla); msym_error_t generateSymmetryOperationsTd(int n, int l, msym_symmetry_operation_t sops[l], int *pk, int *pcla); msym_error_t generateSymmetryOperationsTh(int n, int l, msym_symmetry_operation_t sops[l], int *pk, int *pcla); msym_error_t generateSymmetryOperationsO(int n, int l, msym_symmetry_operation_t sops[l], int *pk, int *pcla); msym_error_t generateSymmetryOperationsOh(int n, int l, msym_symmetry_operation_t sops[l], int *pk, int *pcla); msym_error_t generateSymmetryOperationsI(int n, int l, msym_symmetry_operation_t sops[l], int *pk, int *pcla); msym_error_t generateSymmetryOperationsIh(int n, int l, msym_symmetry_operation_t sops[l], int *pk, int *pcla); msym_error_t generateSymmetryOperationsTetrahedral(int l, msym_symmetry_operation_t sops[l], int c2l, msym_symmetry_operation_t c2[c2l], int csl, msym_symmetry_operation_t cs[csl], int c3l, msym_symmetry_operation_t c3[c3l], int *pk); msym_error_t generateSymmetryOperationsOctahedral(int l, msym_symmetry_operation_t sops[l], int c2l, msym_symmetry_operation_t c2[c2l], int c3l, msym_symmetry_operation_t c3[c3l], int c4l, msym_symmetry_operation_t c4[c4l], int *pk); msym_error_t generateSymmetryOperationsIcosahedral(int l, msym_symmetry_operation_t sops[l], int c2l, msym_symmetry_operation_t c2[c2l], int c3l, msym_symmetry_operation_t c3[c3l], int c5l, msym_symmetry_operation_t c5[c5l], int *pk); msym_error_t generateReflectionPlanes(int n, int l, msym_symmetry_operation_t sops[l], int *pk, int *pcla); msym_error_t generateC2Axes(int n, int l, msym_symmetry_operation_t sops[l], int *pk, int *pcla); msym_error_t generateSymmetryOperationsUnknown(int n, int l, msym_symmetry_operation_t sops[l], int *pk, int *pcla); msym_error_t pointGroupFromName(const char *name, msym_point_group_t *pg); msym_error_t pointGroupFromType(msym_point_group_type_t type, int n, msym_point_group_t *pg); msym_error_t generatePointGroupFromStruct(msym_point_group_t *pg, double transform[3][3], msym_thresholds_t *thresholds); int classifySymmetryOperations(msym_point_group_t *pg); void sortSymmetryOperations(msym_point_group_t *pg, int classes); msym_error_t generatePointGroupFromType(msym_point_group_type_t type, int n, double transform[3][3], msym_thresholds_t *thresholds, msym_point_group_t **opg){ msym_error_t ret = MSYM_SUCCESS; msym_point_group_t *pg = calloc(1,sizeof(msym_point_group_t)); if(MSYM_SUCCESS != (ret = pointGroupFromType(type,n,pg))) goto err; if(MSYM_SUCCESS != (ret = generatePointGroupFromStruct(pg, transform, thresholds))) goto err; *opg = pg; return ret; err: free(pg); return ret; } msym_error_t generatePointGroupFromName(const char *name, double transform[3][3], msym_thresholds_t *thresholds, msym_point_group_t **opg){ msym_error_t ret = MSYM_SUCCESS; msym_point_group_t *pg = calloc(1,sizeof(msym_point_group_t)); if(MSYM_SUCCESS != (ret = pointGroupFromName(name,pg))) goto err; if(MSYM_SUCCESS != (ret = generatePointGroupFromStruct(pg, transform, thresholds))) goto err; *opg = pg; return ret; err: free(pg); return ret; } msym_error_t generatePointGroupFromStruct(msym_point_group_t *pg, double transform[3][3], msym_thresholds_t *thresholds){ msym_error_t ret = MSYM_SUCCESS; if(MSYM_SUCCESS != (ret = generateSymmetryOperations(pg->type, pg->n, pg->order, &pg->sops))) goto err; if(isLinearPointGroup(pg)){ pg->perm = NULL; } else { if(MSYM_SUCCESS != (ret = findSymmetryOperationPermutations(pg->order,pg->sops, thresholds, &pg->perm))) goto err; } memcpy(pg->transform, transform, sizeof(double[3][3])); double T[3][3]; minv(pg->transform, T); for(msym_symmetry_operation_t *s = pg->sops;s < (pg->sops + pg->order);s++){ if(pg->primary == NULL || (s->type == PROPER_ROTATION && s->order > pg->primary->order)) pg->primary = s; mvmul(s->v,T,s->v); } return ret; err: free(pg->sops); pg->sops = NULL; // Need to free findSymmetryOperationPermutations if there is ever a possibility of an error after that call return ret; } msym_error_t pointGroupFromType(msym_point_group_type_t type, int n, msym_point_group_t *pg){ msym_error_t ret = MSYM_SUCCESS; pg->type = type; switch (pg->type) { case MSYM_POINT_GROUP_TYPE_Cs: case MSYM_POINT_GROUP_TYPE_Ci: n = 1; break; case MSYM_POINT_GROUP_TYPE_T: case MSYM_POINT_GROUP_TYPE_Td: case MSYM_POINT_GROUP_TYPE_Th: n = 3; break; case MSYM_POINT_GROUP_TYPE_O: case MSYM_POINT_GROUP_TYPE_Oh: n = 4; break; case MSYM_POINT_GROUP_TYPE_I: case MSYM_POINT_GROUP_TYPE_Ih: n = 5; break; default: break; } pg->n = n; if(MSYM_SUCCESS != (ret = getPointGroupOrder(pg->type, pg->n, &pg->order))) goto err; if(MSYM_SUCCESS != (ret = getPointGroupName(pg->type, pg->n, sizeof(pg->name)/sizeof(char), pg->name))) goto err; err: return ret; } msym_error_t pointGroupFromName(const char *name, msym_point_group_t *pg){ msym_error_t ret = MSYM_SUCCESS; int n = 0, gi = 0, ri = 0;; char g = 0, r = 0; int map[7][6]; struct _pg_map { int i; msym_point_group_type_t type; } pg_map[] = { {1, MSYM_POINT_GROUP_TYPE_Cn}, {2, MSYM_POINT_GROUP_TYPE_Cnv}, {3, MSYM_POINT_GROUP_TYPE_Cnh}, {4, MSYM_POINT_GROUP_TYPE_Ci}, {5, MSYM_POINT_GROUP_TYPE_Cs}, {6, MSYM_POINT_GROUP_TYPE_Dn}, {7, MSYM_POINT_GROUP_TYPE_Dnh}, {8, MSYM_POINT_GROUP_TYPE_Dnd}, {9, MSYM_POINT_GROUP_TYPE_Sn}, {10, MSYM_POINT_GROUP_TYPE_T}, {11, MSYM_POINT_GROUP_TYPE_Th}, {12, MSYM_POINT_GROUP_TYPE_Td}, {13, MSYM_POINT_GROUP_TYPE_O}, {14, MSYM_POINT_GROUP_TYPE_Oh}, {15, MSYM_POINT_GROUP_TYPE_I}, {16, MSYM_POINT_GROUP_TYPE_Ih}, {17, MSYM_POINT_GROUP_TYPE_K}, {18, MSYM_POINT_GROUP_TYPE_Kh} }; memset(map,0,sizeof(int[7][6])); map[0][0] = 1; map[0][1] = 2; map[0][2] = 3; map[0][4] = 4; map[0][5] = 5; map[1][0] = 6; map[1][2] = 7; map[1][3] = 8; map[2][0] = 9; map[3][0] = 10; map[3][2] = 11; map[3][3] = 12; map[4][0] = 13; map[4][2] = 14; map[5][0] = 15; map[5][2] = 16; map[6][0] = 17; map[6][2] = 18; if(sscanf(name,"%c%d%c",&g,&n,&r) < 2 && sscanf(name,"%c%c",&g,&r) < 1){ ret = MSYM_INVALID_POINT_GROUP; msymSetErrorDetails("Invalid point group name %s",name); goto err; } if(n < 0) { ret = MSYM_INVALID_POINT_GROUP; msymSetErrorDetails("Invalid point group order %d",n); goto err; } switch(g){ case 'C' : gi = 0; break; case 'D' : gi = 1; break; case 'S' : { if(n < 4 || n % 2 != 0){ ret = MSYM_INVALID_POINT_GROUP; msymSetErrorDetails("Improper rotation order (%d) must be even and >= 4",n); goto err; } gi = 2; break; } case 'T' : gi = 3; break; case 'O' : gi = 4; break; case 'I' : gi = 5; break; case 'K' : gi = 6; break; default : ret = MSYM_INVALID_POINT_GROUP; msymSetErrorDetails("Invalid point group type %c",g); goto err; } switch(r){ case 0 : ri = 0; break; case 'v' : ri = 1; break; case 'h' : ri = 2; break; case 'd' : ri = 3; break; case 'i' : ri = 4; break; case 's' : ri = 5; break; default : ret = MSYM_INVALID_POINT_GROUP; msymSetErrorDetails("Invalid point group subtype %c",r); goto err; } int fi, fil = sizeof(pg_map)/sizeof(pg_map[0]); for(fi = 0;fi < fil;fi++){ if(pg_map[fi].i == map[gi][ri]) break; } if(fi == fil){ ret = MSYM_INVALID_POINT_GROUP; msymSetErrorDetails("Cannot find point group %s",name); goto err; } return pointGroupFromType(pg_map[fi].type, n, pg); err: return ret; } msym_error_t getPointGroupName(msym_point_group_type_t type, int n, size_t max, char name[max]){ msym_error_t ret = MSYM_SUCCESS; switch(type) { case MSYM_POINT_GROUP_TYPE_Ci : snprintf(name,max,"Ci"); break; case MSYM_POINT_GROUP_TYPE_Cs : snprintf(name,max,"Cs"); break; case MSYM_POINT_GROUP_TYPE_Cn : snprintf(name,max,"C%d",n); break; case MSYM_POINT_GROUP_TYPE_Cnh : snprintf(name,max,"C%dh",n); break; case MSYM_POINT_GROUP_TYPE_Cnv : snprintf(name,max,"C%dv",n); break; case MSYM_POINT_GROUP_TYPE_Dn : snprintf(name,max,"D%d",n); break; case MSYM_POINT_GROUP_TYPE_Dnh : snprintf(name,max,"D%dh",n); break; case MSYM_POINT_GROUP_TYPE_Dnd : snprintf(name,max,"D%dd",n); break; case MSYM_POINT_GROUP_TYPE_Sn : snprintf(name,max,"S%d",n); break; case MSYM_POINT_GROUP_TYPE_T : snprintf(name,max,"T"); break; case MSYM_POINT_GROUP_TYPE_Td : snprintf(name,max,"Td"); break; case MSYM_POINT_GROUP_TYPE_Th : snprintf(name,max,"Th"); break; case MSYM_POINT_GROUP_TYPE_O : snprintf(name,max,"O"); break; case MSYM_POINT_GROUP_TYPE_Oh : snprintf(name,max,"Oh"); break; case MSYM_POINT_GROUP_TYPE_I : snprintf(name,max,"I"); break; case MSYM_POINT_GROUP_TYPE_Ih : snprintf(name,max,"Ih"); break; case MSYM_POINT_GROUP_TYPE_K : snprintf(name,max,"K"); break; case MSYM_POINT_GROUP_TYPE_Kh : snprintf(name,max,"Kh"); break; default : msymSetErrorDetails("Unknown point group when determining name"); ret = MSYM_POINT_GROUP_ERROR; goto err; } err: return ret; } msym_error_t generatePointGroup(msym_point_group_type_t type, int n, msym_symmetry_operation_t *primary, int sopsl, msym_symmetry_operation_t sops[sopsl], msym_thresholds_t *thresholds, msym_point_group_t **opg){ msym_error_t ret = MSYM_SUCCESS; msym_point_group_t *pg = calloc(1,sizeof(msym_point_group_t)); pg->type = type; pg->n = n; if(MSYM_SUCCESS != (ret = getPointGroupName(type,n,sizeof(pg->name)/sizeof(char),pg->name))) goto err; if(MSYM_SUCCESS != (ret = getPointGroupOrder(type, n, &pg->order))) goto err; if(pg->order < sopsl){ ret = MSYM_POINT_GROUP_ERROR; msymSetErrorDetails("More symmetry operations than order of point group (%s). Order: %d Number of operations: %d",pg->name, pg->order,sopsl); goto err; } //TODO: this may still be needed, in broken symmetry //if(MSYM_SUCCESS != (ret = generateSymmetryOperationsImpliedRot(sopsl, sops, pg->order, thresholds, &sopsl))) goto err; if(MSYM_SUCCESS != (ret = transformAxes(type, n, primary, sopsl, sops, thresholds, pg->transform))) goto err; if(MSYM_SUCCESS != (ret = generateSymmetryOperations(type, n, pg->order, &pg->sops))) goto err; if(isLinearPointGroup(pg)){ pg->perm = NULL; } else { if(MSYM_SUCCESS != (ret = findSymmetryOperationPermutations(pg->order,pg->sops, thresholds, &pg->perm))) goto err; } double T[3][3]; minv(pg->transform, T); for(int i = 0; i < pg->order;i++){ mvmul(pg->sops[i].v,T,pg->sops[i].v); if(pg->sops[i].type == PROPER_ROTATION){ if(pg->primary == NULL || pg->sops[i].order > pg->primary->order) pg->primary = &(pg->sops[i]); } } for(int i = 0;i < pg->order;i++){ printSymmetryOperation(&pg->sops[i]); } *opg = pg; return ret; err: if(pg) free(pg->sops); free(pg); return ret; } msym_error_t getPointGroupOrder(msym_point_group_type_t type, int n, int *order){ msym_error_t ret = MSYM_SUCCESS; switch (type) { case (MSYM_POINT_GROUP_TYPE_Cs) : case (MSYM_POINT_GROUP_TYPE_Ci) : *order = 2; break; case (MSYM_POINT_GROUP_TYPE_Cn) : case (MSYM_POINT_GROUP_TYPE_Sn) : *order = n; break; case (MSYM_POINT_GROUP_TYPE_Cnh) : case (MSYM_POINT_GROUP_TYPE_Dn) : *order = 2*n; break; case (MSYM_POINT_GROUP_TYPE_Cnv) : *order = (n == 0 ? 2 : 2*n); break; case (MSYM_POINT_GROUP_TYPE_Dnh) : *order = (n == 0 ? 4 : 4*n); break; case (MSYM_POINT_GROUP_TYPE_Dnd) : *order = 4*n; break; case (MSYM_POINT_GROUP_TYPE_T) : *order = 12; break; case (MSYM_POINT_GROUP_TYPE_Td) : case (MSYM_POINT_GROUP_TYPE_Th) : case (MSYM_POINT_GROUP_TYPE_O) : *order = 24; break; case (MSYM_POINT_GROUP_TYPE_Oh) : *order = 48; break; case (MSYM_POINT_GROUP_TYPE_I) : *order = 60; break; case (MSYM_POINT_GROUP_TYPE_Ih) : *order = 120; break; case (MSYM_POINT_GROUP_TYPE_K) : case (MSYM_POINT_GROUP_TYPE_Kh) : *order = 0; default : msymSetErrorDetails("Point group has no primary axis for reorientation"); goto err; } err: return ret; } msym_error_t findPointGroup(int sopsl, msym_symmetry_operation_t *sops, msym_thresholds_t *thresholds, msym_point_group_t **pg){ msym_error_t ret = MSYM_SUCCESS; msym_point_group_t tpg = {.type = MSYM_POINT_GROUP_TYPE_Kh, .n = 0, .primary = NULL}; msym_symmetry_operation_t *tsops = NULL; int tsopsl = sopsl; if(MSYM_SUCCESS != (ret = determinePointGroup(sopsl, sops, thresholds, &tpg))) goto err; if(MSYM_SUCCESS != (ret = getPointGroupOrder(tpg.type, tpg.n, &tpg.order))) goto err; if(tpg.order < sopsl){ int length = 2*sopsl > 121 ? 2*sopsl : 121; tsops = calloc(length, sizeof(msym_symmetry_operation_t)); memcpy(tsops, sops, sizeof(msym_symmetry_operation_t[sopsl])); if(MSYM_SUCCESS != (ret = generateSymmetryOperationsImpliedRot(tsopsl, tsops, length, thresholds, &tsopsl))) goto err; tpg.primary = NULL; tpg.n = 0; tpg.type = MSYM_POINT_GROUP_TYPE_Kh; if(MSYM_SUCCESS != (ret = determinePointGroup(tsopsl, tsops, thresholds, &tpg))) goto err; if(MSYM_SUCCESS != (ret = getPointGroupOrder(tpg.type, tpg.n, &tpg.order))) goto err; if(tpg.order < tsopsl){ char buf[4] = {0,0,0,0}; getPointGroupName(tpg.type, tpg.n, sizeof(buf),buf); ret = MSYM_POINT_GROUP_ERROR; msymSetErrorDetails("More symmetry operations than order of point group (%s). Order: %d Number of operations: %d", buf, tpg.order,tsopsl); goto err; } if(MSYM_SUCCESS != (ret = generatePointGroup(tpg.type, tpg.n, tpg.primary, tsopsl, tsops, thresholds, pg))) goto err; } else { if(MSYM_SUCCESS != (ret = generatePointGroup(tpg.type, tpg.n, tpg.primary, sopsl, sops, thresholds, pg))) goto err; } err: free(tsops); return ret; } msym_error_t determinePointGroup(int sopsl, msym_symmetry_operation_t *sops, msym_thresholds_t *thresholds, msym_point_group_t *pg){ msym_error_t ret = MSYM_SUCCESS; int inversion = 0, sigma = 0, nC[6] = {0,0,0,0,0,0}, linear = 0; msym_symmetry_operation_t *primary = NULL; msym_symmetry_operation_t *s = NULL; for(int i = 0;i < sopsl;i++){ if(sops[i].type == PROPER_ROTATION && sops[i].order == 0){ linear = 1; break; } else if (sops[i].type == PROPER_ROTATION && sops[i].order > 2){ break; } } if(!linear){ for(int i = 0;i < sopsl;i++){ switch(sops[i].type){ case PROPER_ROTATION : if(primary == NULL || sops[i].order > primary->order) primary = &(sops[i]); if(sops[i].order <= 5) nC[sops[i].order]++; break; case INVERSION : inversion = 1; break; case REFLECTION : sigma = 1; break; case IMPROPER_ROTATION : if(s == NULL || sops[i].order > s->order) s = &(sops[i]); break; default : break; } } pg->n = NULL == primary ? 1 : primary->order; pg->primary = primary; if(nC[3] >= 2) { if(nC[5] >= 2){ if(inversion){ pg->type = MSYM_POINT_GROUP_TYPE_Ih; } else { pg->type = MSYM_POINT_GROUP_TYPE_I; } } else if (nC[4] >= 2) { if(inversion){ pg->type = MSYM_POINT_GROUP_TYPE_Oh; } else { pg->type = MSYM_POINT_GROUP_TYPE_O; } } else if (sigma){ if(inversion){ pg->type = MSYM_POINT_GROUP_TYPE_Th; } else { pg->type = MSYM_POINT_GROUP_TYPE_Td; } } else { pg->type = MSYM_POINT_GROUP_TYPE_T; } } else if (primary == NULL){ if(sigma){ pg->type = MSYM_POINT_GROUP_TYPE_Cs; pg->n = 1; } else if(inversion){ pg->type = MSYM_POINT_GROUP_TYPE_Ci; pg->n = 1; } else { pg->type = MSYM_POINT_GROUP_TYPE_Cn; pg->n = 1; pg->sops = NULL; pg->order = 0; } } else { int nC2 = 0; int sigma_h = 0; int nsigma_v = 0; //Special case for D2d if(primary->order == 2 && s != NULL && !vparallel(primary->v, s->v, thresholds->angle)){ for(int i = 0; i < sopsl;i++){ if(sops[i].type == PROPER_ROTATION && sops[i].order == 2 && vparallel(sops[i].v, s->v, thresholds->angle)){ primary = &sops[i]; break; } } } for(int i = 0; i < sopsl;i++){ nC2 += sops[i].type == PROPER_ROTATION && sops[i].order == 2 && vperpendicular(primary->v,sops[i].v, thresholds->angle); sigma_h = sigma_h || (sops[i].type == REFLECTION && vparallel(primary->v,sops[i].v,thresholds->angle)); nsigma_v += (sops[i].type == REFLECTION && vperpendicular(primary->v,sops[i].v,thresholds->angle)); } pg->n = primary->order; pg->primary = primary; if(nC2){ //actually nC2 == primary->order but less is acceptable here since we can generate the rest if(sigma_h){ pg->type = MSYM_POINT_GROUP_TYPE_Dnh; } else if (nsigma_v){ //actually nsigma_v == primary->order but less is acceptable here since we can generate the rest pg->type = MSYM_POINT_GROUP_TYPE_Dnd; } else { pg->type = MSYM_POINT_GROUP_TYPE_Dn; } } else if (sigma_h) { pg->type = MSYM_POINT_GROUP_TYPE_Cnh; } else if(nsigma_v) { //actually nsigma_v == primary->order but less is acceptable here since we can generate the rest pg->type = MSYM_POINT_GROUP_TYPE_Cnv; } else if(s != NULL){ pg->n = s->order; pg->type = MSYM_POINT_GROUP_TYPE_Sn; } else { pg->type = MSYM_POINT_GROUP_TYPE_Cn; } } } else { for(int i = 0; i < sopsl;i++){ inversion = inversion || sops[i].type == INVERSION; if(sops[i].type == PROPER_ROTATION && (sops[i].order == 0 || primary == NULL)){ primary = &(sops[i]); } } pg->n = primary->order; pg->primary = primary; if(inversion){ pg->type = MSYM_POINT_GROUP_TYPE_Dnh; } else { pg->type = MSYM_POINT_GROUP_TYPE_Cnv; } } return ret; //err: // return ret; } msym_error_t findSubgroup(msym_subgroup_t *subgroup, msym_thresholds_t *thresholds){ msym_error_t ret = MSYM_SUCCESS; int inversion = 0, sigma = 0, nC[6] = {0,0,0,0,0,0}, linear = 0; msym_symmetry_operation_t *primary = NULL; msym_symmetry_operation_t *s = NULL, *sop = NULL;; for(int i = 0;i < subgroup->order;i++){ if(subgroup->sops[i]->type == PROPER_ROTATION && subgroup->sops[i]->order == 0){ linear = 1; break; } else if (subgroup->sops[i]->type == PROPER_ROTATION && subgroup->sops[i]->order > 2){ break; } } if(!linear){ for(int i = 0;i < subgroup->order;i++){ sop = subgroup->sops[i]; if(sop->power > 1) continue; switch(subgroup->sops[i]->type){ case PROPER_ROTATION : if(primary == NULL || sop->order > primary->order) primary = sop; if(sop->order <= 5) nC[sop->order]++; break; case INVERSION : inversion = 1; break; case REFLECTION : sigma = 1; break; case IMPROPER_ROTATION : if(s == NULL || sop->order > s->order) s = sop; break; default : break; } } if(nC[3] >= 2) { if(nC[5] >= 2){ if(inversion){ subgroup->type = MSYM_POINT_GROUP_TYPE_Ih; subgroup->n = primary->order; } else { subgroup->type = MSYM_POINT_GROUP_TYPE_I; subgroup->n = primary->order; } } else if (nC[4] >= 2) { if(inversion){ subgroup->type = MSYM_POINT_GROUP_TYPE_Oh; subgroup->n = primary->order; } else { subgroup->type = MSYM_POINT_GROUP_TYPE_O; subgroup->n = primary->order; } } else if (sigma){ if(inversion){ subgroup->type = MSYM_POINT_GROUP_TYPE_Th; subgroup->n = primary->order; } else { subgroup->type = MSYM_POINT_GROUP_TYPE_Td; subgroup->n = primary->order; } } else { subgroup->type = MSYM_POINT_GROUP_TYPE_T; subgroup->n = primary->order; } } else if (primary == NULL){ if(sigma){ subgroup->type = MSYM_POINT_GROUP_TYPE_Cs; subgroup->n = 1; } else if(inversion){ subgroup->type = MSYM_POINT_GROUP_TYPE_Ci; subgroup->n = 1; } else { subgroup->type = MSYM_POINT_GROUP_TYPE_Cn; subgroup->n = 1; } } else { int nC2 = 0; int sigma_h = 0; int nsigma_v = 0; if(primary->order == 2 && s != NULL && !vparallel(primary->v, s->v, thresholds->angle)){ for(int i = 0; i < subgroup->order;i++){ sop = subgroup->sops[i]; if(sop->power > 1) continue; if(sop->type == PROPER_ROTATION && sop->order == 2 && vparallel(sop->v, s->v, thresholds->angle)){ primary = sop; break; } } } for(int i = 0; i < subgroup->order;i++){ sop = subgroup->sops[i]; if(sop->power > 1) continue; nC2 += sop->type == PROPER_ROTATION && sop->order == 2 && vperpendicular(primary->v,sop->v, thresholds->angle); sigma_h = sigma_h || (sop->type == REFLECTION && vparallel(primary->v,sop->v,thresholds->angle)); nsigma_v += (sop->type == REFLECTION && vperpendicular(primary->v,sop->v,thresholds->angle)); } if(nC2 == primary->order){ if(sigma_h){ subgroup->type = MSYM_POINT_GROUP_TYPE_Dnh; subgroup->n = primary->order; } else if (nsigma_v == primary->order){ subgroup->type = MSYM_POINT_GROUP_TYPE_Dnd; subgroup->n = primary->order; } else { subgroup->type = MSYM_POINT_GROUP_TYPE_Dn; subgroup->n = primary->order; } } else if (sigma_h) { subgroup->type = MSYM_POINT_GROUP_TYPE_Cnh; subgroup->n = primary->order; } else if(nsigma_v == primary->order) { subgroup->type = MSYM_POINT_GROUP_TYPE_Cnv; subgroup->n = primary->order; } else if(s != NULL){ subgroup->type = MSYM_POINT_GROUP_TYPE_Sn; subgroup->n = s->order; } else { subgroup->type = MSYM_POINT_GROUP_TYPE_Cn; subgroup->n = primary->order; } } } else { for(int i = 0; i < subgroup->order;i++){ inversion = inversion || subgroup->sops[i]->type == INVERSION; if(subgroup->sops[i]->type == PROPER_ROTATION && (subgroup->sops[i]->order == 0 || primary == NULL)){ primary = subgroup->sops[i]; } } if(inversion){ subgroup->type = MSYM_POINT_GROUP_TYPE_Dnh; subgroup->n = primary->order; } else { subgroup->type = MSYM_POINT_GROUP_TYPE_Cnv; subgroup->n = primary->order; } } subgroup->primary = primary; if(MSYM_SUCCESS != (ret = getPointGroupName(subgroup->type, subgroup->n, sizeof(subgroup->name)/sizeof(char), subgroup->name))) goto err; return ret; err: return ret; } msym_error_t transformAxes(msym_point_group_type_t type, int n, msym_symmetry_operation_t *primary, int sopsl, msym_symmetry_operation_t sops[sopsl], msym_thresholds_t *thresholds, double transform[3][3]){ msym_error_t ret = MSYM_SUCCESS; switch (type){ case (MSYM_POINT_GROUP_TYPE_Ci) : case (MSYM_POINT_GROUP_TYPE_K) : case (MSYM_POINT_GROUP_TYPE_Kh) : break; case (MSYM_POINT_GROUP_TYPE_Cs) : for(primary = sops; primary < (primary + sopsl) && primary->type != REFLECTION; primary++){}; case (MSYM_POINT_GROUP_TYPE_Cn) : case (MSYM_POINT_GROUP_TYPE_Cnh) : case (MSYM_POINT_GROUP_TYPE_Sn) : if(MSYM_SUCCESS != (ret = reorientAxes(primary, sopsl, sops, thresholds))) goto err; if(MSYM_SUCCESS != (ret = transformPrimary(primary, sopsl, sops, thresholds, transform))) goto err; break; case (MSYM_POINT_GROUP_TYPE_Cnv) : case (MSYM_POINT_GROUP_TYPE_Dnh) : if(MSYM_SUCCESS != (ret = reorientAxes(primary, sopsl, sops, thresholds))) goto err; if(MSYM_SUCCESS != (ret = transformPrimary(primary, sopsl, sops, thresholds, transform))) goto err; if(n > 0){ if(MSYM_SUCCESS != (ret = transformSecondary(type, primary, sopsl, sops, thresholds, transform))) goto err; } break; case (MSYM_POINT_GROUP_TYPE_Dn) : case (MSYM_POINT_GROUP_TYPE_Dnd) : case (MSYM_POINT_GROUP_TYPE_O) : case (MSYM_POINT_GROUP_TYPE_Oh) : if(MSYM_SUCCESS != (ret = reorientAxes(primary, sopsl, sops, thresholds))) goto err; if(MSYM_SUCCESS != (ret = transformPrimary(primary, sopsl, sops, thresholds, transform))) goto err; if(MSYM_SUCCESS != (ret = transformSecondary(type, primary, sopsl, sops, thresholds, transform))) goto err; break; case (MSYM_POINT_GROUP_TYPE_T) : case (MSYM_POINT_GROUP_TYPE_Td) : case (MSYM_POINT_GROUP_TYPE_Th) : case (MSYM_POINT_GROUP_TYPE_I) : case (MSYM_POINT_GROUP_TYPE_Ih) : { msym_symmetry_operation_t *dprimary = NULL; msym_symmetry_operation_t *sop; double z = -2.0; for(sop = sops; sop < (sops + sopsl); sop++){ if(sop->type == PROPER_ROTATION && sop->order == 2){ double v[3]; vnorm2(sop->v,v); if(v[2] > z || dprimary == NULL) { dprimary = sop; z = sop->v[2]; } } } if(dprimary == NULL) { msymSetErrorDetails("Cannot find C2 axis for point group symmetrization of polyhedral point group"); ret = MSYM_POINT_GROUP_ERROR; goto err; } if(MSYM_SUCCESS != (ret = reorientAxes(dprimary, sopsl, sops, thresholds))) goto err; if(MSYM_SUCCESS != (ret = transformPrimary(dprimary, sopsl, sops, thresholds, transform))) goto err; if(MSYM_SUCCESS != (ret = transformSecondary(type, dprimary, sopsl, sops, thresholds, transform))) goto err; break; } } err: return ret; } int isLinearPointGroup(msym_point_group_t *pg){ return 0 == pg->n && (MSYM_POINT_GROUP_TYPE_Dnh == pg->type || MSYM_POINT_GROUP_TYPE_Cnv == pg->type); } int isLinearSubgroup(msym_point_group_t *pg){ int sub = 0; switch(pg->type){ case MSYM_POINT_GROUP_TYPE_Cnv: sub = pg->n == 0 && pg->order > 2; break; case MSYM_POINT_GROUP_TYPE_Dnh: sub = pg->n == 0 && pg->order > 4; break; default: break; } return sub; } msym_error_t reduceLinearPointGroup(msym_point_group_t *pg, int n, msym_thresholds_t *thresholds){ msym_error_t ret = MSYM_SUCCESS; int order = 0; msym_permutation_t *perm = NULL; msym_symmetry_operation_t *sops = NULL; msym_symmetry_operation_t *primary = NULL; if(!isLinearPointGroup(pg)){ msymSetErrorDetails("Trying to reduce non linear point group"); ret = MSYM_POINT_GROUP_ERROR; goto err; } if(n == 0) n = 2; if(MSYM_SUCCESS != (ret = getPointGroupOrder(pg->type, n, &order))) goto err; if(MSYM_SUCCESS != (ret = generateSymmetryOperations(pg->type, 0, order, &sops))) goto err; for(int i = 0;i < order;i++){ if(PROPER_ROTATION == sops[i].type && n == sops[i].order && HORIZONTAL == sops[i].orientation && 1 == sops[i].power){ primary = &sops[i]; break; } } if(NULL == primary){ msymSetErrorDetails("Cannot find primary axis when reducing linear group"); ret = MSYM_POINT_GROUP_ERROR; goto err; } double T[3][3]; minv(pg->transform, T); for(int i = 0; i < order;i++){ mvmul(sops[i].v,T,sops[i].v); } if(MSYM_SUCCESS != (ret = findSymmetryOperationPermutations(order,sops, thresholds, &perm))) goto err; for(int i = 0;i < pg->order && pg->perm != NULL;i++){ freePermutationData(&pg->perm[i]); } free(pg->sops); pg->sops = sops; pg->order = order; pg->perm = perm; pg->primary = primary; return ret; err: free(sops); return ret; } /* Really should split the orientation and class from the symmetry operation * and move it to the group so we don't have to regenerate */ msym_error_t pointGroupFromSubgroup(const msym_subgroup_t *sg, msym_thresholds_t *thresholds, msym_point_group_t **opg){ msym_error_t ret = MSYM_SUCCESS; *opg = calloc(1,sizeof(msym_point_group_t)); msym_point_group_t *pg = *opg; pg->type = sg->type; pg->n = sg->n; pg->sops = malloc(sizeof(msym_symmetry_operation_t[sg->order])); memcpy(pg->name,sg->name,sizeof(pg->name)); if(MSYM_SUCCESS != (ret = getPointGroupOrder(pg->type, pg->n, &pg->order))) goto err; if(pg->order != sg->order){ msymSetErrorDetails("Point group order %d does not equal nuber of operations in subgroup %d for point gropu %s",pg->order,sg->order,pg->name); ret = MSYM_POINT_GROUP_ERROR; goto err; } for(int i = 0;i < sg->order;i++){ if(sg->primary == sg->sops[i]) pg->primary = &pg->sops[i]; memcpy(&pg->sops[i], sg->sops[i], sizeof(msym_symmetry_operation_t)); } mleye(3, pg->transform); if(MSYM_SUCCESS != (ret = transformAxes(pg->type, pg->n, pg->primary, pg->order, pg->sops, thresholds, pg->transform))) goto err; /* Unfortunately we need to regenerate these as they need a specific * class ordering for orbital symmetrization */ free(pg->sops); pg->sops = NULL; pg->primary = NULL; if(MSYM_SUCCESS != (ret = generateSymmetryOperations(pg->type, pg->n, pg->order, &pg->sops))) goto err; if(isLinearPointGroup(pg)){ pg->perm = NULL; } else { if(MSYM_SUCCESS != (ret = findSymmetryOperationPermutations(pg->order,pg->sops, thresholds, &pg->perm))) goto err; } double T[3][3]; minv(pg->transform, T); for(int i = 0; i < pg->order;i++){ // vector and orientation may not be equal if(NULL != sg->primary && NULL == pg->primary && pg->sops[i].type == sg->primary->type && pg->sops[i].order == sg->primary->order && pg->sops[i].power == sg->primary->power){ pg->primary = &pg->sops[i]; } mvmul(pg->sops[i].v,T,pg->sops[i].v); } return ret; err: *opg = NULL; free(pg->sops); free(pg); return ret; } /* Point primary axes above xy plane and all symops above the primary plane. * Not really needed but we may not have to deal with transforms that flip things over * This could be improved with some thresholds, since some things lie in the plane * and get flipped. Should try to align with x as well */ msym_error_t reorientAxes(msym_symmetry_operation_t *primary, int sopsl, msym_symmetry_operation_t sops[sopsl], msym_thresholds_t *thresholds ){ double x[3] = {1.0,0.0,0.0}, y[3] = {0.0,1.0,0.0}, z[3] = {0.0, 0.0, 1.0}; if(primary == NULL) goto err; if(vdot(primary->v,z) < 0.0) vinv(primary->v); for(msym_symmetry_operation_t *sop = sops; sop < (sops + sopsl); sop++){ if(vperpendicular(sop->v, z, thresholds->angle)){ double proj = vdot(sop->v, y)/vabs(sop->v); if(fabs(fabs(proj)-1.0) < thresholds->angle && proj < 0.0) { //along y axis vinv(sop->v); } else if (vdot(sop->v,x) < 0.0){ //in xy-plane not in y axis, reorient to positive x vinv(sop->v); } } else if(vdot(primary->v,sop->v) < 0.0) vinv(sop->v); //not in xy-plane reorient to positive along primary axiz } return MSYM_SUCCESS; err: msymSetErrorDetails("Point group has no primary axis for reorientation"); return MSYM_POINT_GROUP_ERROR; } msym_error_t transformPrimary(msym_symmetry_operation_t *primary, int sopsl, msym_symmetry_operation_t sops[sopsl], msym_thresholds_t *thresholds, double transform[3][3]){ msym_error_t ret = MSYM_SUCCESS; if(primary != NULL){ double z[3] = {0.0, 0.0, 1.0}; malign(primary->v,z,transform); for(msym_symmetry_operation_t *sop = sops; sop < (sops + sopsl); sop++){ mvmul(sop->v,transform,sop->v); } vcopy(z,primary->v); // get rid of small errors } else { msymSetErrorDetails("Point group has no primary axis for transformation"); ret = MSYM_POINT_GROUP_ERROR; } return ret; } msym_error_t transformSecondary(msym_point_group_type_t type, msym_symmetry_operation_t *primary, int sopsl, msym_symmetry_operation_t sops[sopsl], msym_thresholds_t *thresholds, double transform[3][3]){ msym_error_t ret = MSYM_SUCCESS; double axis[3], x[3] = {1.0,0.0,0.0}; switch(type){ case (MSYM_POINT_GROUP_TYPE_Cnv) : if(MSYM_SUCCESS != (ret = findSecondaryAxisSigma(primary, sopsl, sops, thresholds, axis))) goto err; break; case (MSYM_POINT_GROUP_TYPE_O) : case (MSYM_POINT_GROUP_TYPE_Oh) : if(MSYM_SUCCESS != (ret = findSecondaryAxisC4(primary, sopsl, sops, thresholds, axis))) goto err; break; case (MSYM_POINT_GROUP_TYPE_Dn) : case (MSYM_POINT_GROUP_TYPE_Dnh) : case (MSYM_POINT_GROUP_TYPE_Dnd) : case (MSYM_POINT_GROUP_TYPE_T) : case (MSYM_POINT_GROUP_TYPE_Td) : case (MSYM_POINT_GROUP_TYPE_Th) : if(MSYM_SUCCESS != (ret = findSecondaryAxisC2(primary, sopsl, sops, thresholds, axis))) goto err; break; case (MSYM_POINT_GROUP_TYPE_I) : case (MSYM_POINT_GROUP_TYPE_Ih) : if(MSYM_SUCCESS != (ret = findSecondaryAxisC2C5(primary, sopsl, sops, thresholds, axis))) goto err; break; default : msymSetErrorDetails("Unknown point group when determining secondary axis"); ret = MSYM_POINT_GROUP_ERROR; goto err; } double m[3][3]; malign(axis, x, m); for(msym_symmetry_operation_t *sop = sops; sop < (sops + sopsl); sop++){ mvmul(sop->v,m,sop->v); } mmmul(m,transform,transform); err: return ret; } /* For point groups where we use a perpendicular reflection plane to indicate direction. We use a vector where the the xy-plane and reflection plane cross */ msym_error_t findSecondaryAxisSigma(msym_symmetry_operation_t *primary, int sopsl, msym_symmetry_operation_t sops[sopsl], msym_thresholds_t *thresholds, double r[3]){ msym_error_t ret = MSYM_SUCCESS; msym_symmetry_operation_t *sop = NULL; for(sop = sops; sop < (sops + sopsl); sop++){ if(sop->type == REFLECTION){ vcross(sop->v, primary->v, r); vnorm(r); break; } } if(sop == (sops + sopsl)){ msymSetErrorDetails("Can't find secondary reflection plane when symmetrizing point group"); ret = MSYM_POINT_GROUP_ERROR; goto err; } err: return ret; } /* For point groups where we use a perpendicular C2 axis to indicate direction. Adjusted to make sure it's perfectly in the xy-plane. */ msym_error_t findSecondaryAxisC2(msym_symmetry_operation_t *primary, int sopsl, msym_symmetry_operation_t sops[sopsl], msym_thresholds_t *thresholds, double r[3]){ msym_error_t ret = MSYM_SUCCESS; msym_symmetry_operation_t *sop = NULL; for(msym_symmetry_operation_t *sop = sops; sop < (sops + sopsl); sop++){ //Choose a C2 perpendicular to the primary axis, it'll make things relatively easy if(sop != primary && sop->type == PROPER_ROTATION && sop->order == 2 && vperpendicular(sop->v, primary->v,thresholds->angle)){ vproj_plane(sop->v, primary->v, r); vnorm(r); break; } } if(sop == (sops + sopsl)){ msymSetErrorDetails("Can't find secondary C2 axis when symmetrizing point group"); ret = MSYM_POINT_GROUP_ERROR; goto err; } err: return ret; } msym_error_t findSecondaryAxisC2C5(msym_symmetry_operation_t *primary, int sopsl, msym_symmetry_operation_t sops[sopsl], msym_thresholds_t *thresholds, double r[3]){ msym_error_t ret = MSYM_SUCCESS; msym_symmetry_operation_t *c2[2], *c5 = NULL; int c2i = 0; for(msym_symmetry_operation_t *sop = sops; sop < (sops + sopsl) && (c5 == NULL || c2i < 2); sop++){ if(vperpendicular(sop->v, primary->v,thresholds->angle)){ if(sop->type == PROPER_ROTATION && sop->order == 2){ //printf("Found perpendicular C2\n"); c2[c2i++] = sop; } else if (sop->type == PROPER_ROTATION && sop->order == 5){ //printf("Found perpendicular C5\n"); c5 = sop; } } } if(c5 == NULL || c2i < 2) { msymSetErrorDetails("Can't find secondary C2 axis when symmetrizing point group: (%s %s)",c5 == NULL ? "C5 axis missing" : "", c2i < 2 ? "C2 axis missing" : ""); ret = MSYM_POINT_GROUP_ERROR; goto err; } if(fabs(vdot(c5->v, c2[0]->v)) > fabs(vdot(c5->v, c2[1]->v))){ vproj_plane(c2[0]->v, primary->v, r); } else { vproj_plane(c2[1]->v, primary->v, r); } err: return ret; } // Same as C2 msym_error_t findSecondaryAxisC4(msym_symmetry_operation_t *primary, int sopsl, msym_symmetry_operation_t sops[sopsl], msym_thresholds_t *thresholds, double r[3]){ msym_error_t ret = MSYM_SUCCESS; msym_symmetry_operation_t *sop = NULL; for(sop = sops; sop < (sops + sopsl); sop++){ //Choose a C2 perpendicular to the primary axis, it'll make things relatively easy if(sop != primary && sop->type == PROPER_ROTATION && sop->order == 4 && vperpendicular(sop->v, primary->v,thresholds->angle)){ vproj_plane(sop->v, primary->v, r); vnorm(r); break; } } if(sop == (sops + sopsl)){ msymSetErrorDetails("Can't find secondary C4 axis when symmetrizing point group"); ret = MSYM_POINT_GROUP_ERROR; goto err; } err: return ret; } msym_error_t generateSymmetryOperationsImpliedRot(int sopsl, msym_symmetry_operation_t sops[sopsl], int order, msym_thresholds_t *thresholds, int *osopsl){ int isopsl = sopsl; for(msym_symmetry_operation_t *sopi = sops; sopi < (sops + sopsl) && isopsl < order; sopi++){ if(sopi->type == PROPER_ROTATION){ for(msym_symmetry_operation_t *sopj = sops; sopj < (sops + sopsl); sopj++){ int istype = (sopj->type == REFLECTION || sopj->type == IMPROPER_ROTATION || (sopj->type == PROPER_ROTATION)); if(sopi != sopj && istype && !vparallel(sopi->v, sopj->v,thresholds->angle)){ copySymmetryOperation(&(sops[isopsl]), sopj); applySymmetryOperation(sopi,sops[isopsl].v,sops[isopsl].v); isopsl += !findSymmetryOperation(&(sops[isopsl]), sops, isopsl,thresholds); if(isopsl > order) goto err; } } } } *osopsl = isopsl; return MSYM_SUCCESS; err: msymSetErrorDetails("Generation of implied symmetry operations by rotation resulted in more operations than point group order"); return MSYM_POINT_GROUP_ERROR; } msym_error_t generateSymmetryOperations(msym_point_group_type_t type, int n, int order, msym_symmetry_operation_t **osops){ msym_error_t ret = MSYM_SUCCESS; msym_symmetry_operation_t *sops = calloc(order, sizeof(msym_symmetry_operation_t)); sops[0].cla = 0; sops[0].type = IDENTITY; sops[0].power = 1; sops[0].order = 1; sops[0].orientation = NONE; int cla = 1, gsopsl = 1; const struct _fmap { msym_point_group_type_t type; msym_error_t (*f)(int, int, msym_symmetry_operation_t *, int *, int *); } fmap[18] = { [ 0] = {MSYM_POINT_GROUP_TYPE_Ci, generateSymmetryOperationsCi}, [ 1] = {MSYM_POINT_GROUP_TYPE_Cs, generateSymmetryOperationsCs}, [ 2] = {MSYM_POINT_GROUP_TYPE_Cn, generateSymmetryOperationsCn}, [ 3] = {MSYM_POINT_GROUP_TYPE_Cnh, generateSymmetryOperationsCnh}, [ 4] = {MSYM_POINT_GROUP_TYPE_Cnv, generateSymmetryOperationsCnv}, [ 5] = {MSYM_POINT_GROUP_TYPE_Dn, generateSymmetryOperationsDn}, [ 6] = {MSYM_POINT_GROUP_TYPE_Dnh, generateSymmetryOperationsDnh}, [ 7] = {MSYM_POINT_GROUP_TYPE_Dnd, generateSymmetryOperationsDnd}, [ 8] = {MSYM_POINT_GROUP_TYPE_Sn, generateSymmetryOperationsSn}, [ 9] = {MSYM_POINT_GROUP_TYPE_T, generateSymmetryOperationsT}, [10] = {MSYM_POINT_GROUP_TYPE_Td, generateSymmetryOperationsTd}, [11] = {MSYM_POINT_GROUP_TYPE_Th, generateSymmetryOperationsTh}, [12] = {MSYM_POINT_GROUP_TYPE_O, generateSymmetryOperationsO}, [13] = {MSYM_POINT_GROUP_TYPE_Oh, generateSymmetryOperationsOh}, [14] = {MSYM_POINT_GROUP_TYPE_I, generateSymmetryOperationsI}, [15] = {MSYM_POINT_GROUP_TYPE_Ih, generateSymmetryOperationsIh}, [16] = {MSYM_POINT_GROUP_TYPE_K, generateSymmetryOperationsUnknown}, [17] = {MSYM_POINT_GROUP_TYPE_Kh, generateSymmetryOperationsUnknown} }; int fi, fil = sizeof(fmap)/sizeof(fmap[0]); for(fi = 0; fi < fil;fi++){ if(fmap[fi].type == type) { if(MSYM_SUCCESS != (ret = fmap[fi].f(n,order,sops,&gsopsl,&cla))) goto err; break; } } if(fi == fil){ msymSetErrorDetails("Unknown point group when generating symmetry operations"); ret = MSYM_POINT_GROUP_ERROR; goto err; } if(gsopsl != order){ msymSetErrorDetails("Generated incorrect number of symmetry operations %d != %d",gsopsl,order); ret = MSYM_INVALID_POINT_GROUP; goto err; } for(int i = 0;i < order;i++) printSymmetryOperation(&sops[i]); *osops = sops; return ret; err: free(sops); return ret; } msym_error_t generateSymmetryOperationsUnknown(int n, int l, msym_symmetry_operation_t sops[l], int *pk, int *pcla){ msymSetErrorDetails("Generating symmetry operations for unknown point group"); return MSYM_POINT_GROUP_ERROR; } msym_error_t generateSymmetryOperationsSn(int n, int l, msym_symmetry_operation_t sops[l], int *pk, int *pcla){ msym_error_t ret = MSYM_SUCCESS; int k = *pk, cla = *pcla, m = (n << (n & 1)); double z[3] = {0.0,0.0,1.0}; msym_symmetry_operation_t sn = {.type = IMPROPER_ROTATION, .order = n, .power = 1, .orientation = HORIZONTAL}; vcopy(z,sn.v); if(k + m - 1 > l){ret = MSYM_POINT_GROUP_ERROR; msymSetErrorDetails("Too many operations when generating S%d symmetry operations",n); goto err;} for(int i = 1;i <= m >> 1;i++){ int index = k + ((i-1) << 1); symopPow(&sn, i, &sops[index]); sops[index].cla = cla + i - 1; clean_debug_printf("i = %d m = %d index = %d ",i,m,index); printSymmetryOperation(&sops[index]); } /* int ri = k + (((m >> 1)-1) << 1); sops[ri].cla = cla + (m >> 1) - 1; sops[ri].power = 1; sops[ri].p.orientation = HORIZONTAL; sops[ri].type = REFLECTION; vcopy(z,sops[ri].v); clean_debug_printf("replacing symmetry operation %d\n",ri); printSymmetryOperation(&sops[ri]);*/ for(int i = 1;i < m >> 1;i++){ int index = k + 1 + ((i-1) << 1); symopPow(&sn, m-i, &sops[index]); sops[index].cla = cla + i - 1; clean_debug_printf("i = %d m = %d index = %d ",i,m,index); printSymmetryOperation(&sops[index]); } k += m - 1; cla += m >> 1; clean_debug_printf("------ Sn %d operations %d classes------\n",k-*pk, cla-*pcla); *pk = k; *pcla = cla; return ret; err: return ret; } msym_error_t generateSymmetryOperationsCs(int n, int l, msym_symmetry_operation_t sops[l], int *pk, int *pcla){ msym_error_t ret = MSYM_SUCCESS; int k = *pk, cla = *pcla; if(k > l){ret = MSYM_POINT_GROUP_ERROR; msymSetErrorDetails("Too many operations when generating Cs symmetry operations"); goto err;} msym_symmetry_operation_t sigma = {.type = REFLECTION, .orientation = HORIZONTAL, .order = 1, .power = 1, .cla = cla, .v = {0,0,1}}; memcpy(&(sops[k]), &sigma, sizeof(msym_symmetry_operation_t)); k++; cla++; clean_debug_printf("------ Cs %d operations %d classes------\n",k-*pk, cla-*pcla); *pk = k; *pcla = cla; return ret; err: return ret; } msym_error_t generateSymmetryOperationsCi(int n, int l, msym_symmetry_operation_t sops[l], int *pk, int *pcla){ msym_error_t ret = MSYM_SUCCESS; int k = *pk, cla = *pcla; if(k > l){ret = MSYM_POINT_GROUP_ERROR; msymSetErrorDetails("Too many operations when generating Ci symmetry operations"); goto err;} msym_symmetry_operation_t inv = {.type = INVERSION, .orientation = NONE, .order = 1, .power = 1, .cla = cla, .v = {0,0,0}}; memcpy(&(sops[k]), &inv, sizeof(msym_symmetry_operation_t)); k++; cla++; clean_debug_printf("------ Ci %d operations %d classes------\n",k-*pk, cla-*pcla); *pk = k; *pcla = cla; return ret; err: return ret; } msym_error_t generateSymmetryOperationsCn(int n, int l, msym_symmetry_operation_t sops[l], int *pk, int *pcla){ msym_error_t ret = MSYM_SUCCESS; int k = *pk, cla = *pcla; double z[3] = {0.0,0.0,1.0}; msym_symmetry_operation_t cn = {.type = PROPER_ROTATION, .order = n, .power = 1, .orientation = HORIZONTAL}; if(k + n - 1 > l){ret = MSYM_POINT_GROUP_ERROR; msymSetErrorDetails("Too many operations when generating C%d symmetry operations",n); goto err;} vcopy(z,cn.v); for(int i = 1;i <= (n >> 1);i++){ int index = k + (i << 1) - 2; symopPow(&cn, i, &sops[index]); sops[index].cla = cla + (index >> 1); clean_debug_printf("i = %d index = %d ",i,index); printSymmetryOperation(&sops[index]); } for(int i = 1;i < (n >> 1) + (n & 1);i++){ int index = k + (i << 1) - 1; symopPow(&cn, n-i, &sops[index]); sops[index].cla = cla + ((index - 1) >> 1); clean_debug_printf("i = %d index = %d ",i,index); printSymmetryOperation(&sops[index]); } k += n - 1; cla += n >> 1; clean_debug_printf("------ Cn %d operations %d classes------\n",k-*pk, cla-*pcla); *pk = k; *pcla = cla; return ret; err: return ret; } msym_error_t generateSymmetryOperationsCnh(int n, int l, msym_symmetry_operation_t sops[l], int *pk, int *pcla){ msym_error_t ret = MSYM_SUCCESS; int k = *pk, cla = *pcla, s = 0; double z[3] = {0.0,0.0,1.0}; msym_symmetry_operation_t cn = {.type = PROPER_ROTATION, .order = n, .power = 1, .orientation = HORIZONTAL}; msym_symmetry_operation_t sn = {.type = IMPROPER_ROTATION, .order = n, .power = 1, .orientation = HORIZONTAL}; if(k + (n << 1) - 1 > l){ret = MSYM_POINT_GROUP_ERROR; msymSetErrorDetails("Too many operations when generating C%dh symmetry operations",n); goto err;} vcopy(z,cn.v); vcopy(z,sn.v); for(s = n;s % 2 == 0;s = s >> 1){ cn.order = s; for(int i = 1;i <= s >> 1;i += 2){ int index = k + ((i >> 1) << 1); symopPow(&cn, i, &sops[index]); sops[index].cla = cla + (i >> 1); printSymmetryOperation(&sops[index]); } for(int i = 1;i < s >> 1;i += 2){ int index = k + 1 + ((i >> 1) << 1); symopPow(&cn, s-i, &sops[index]); sops[index].cla = cla + (i >> 1); printSymmetryOperation(&sops[index]); } k += (s >> 1); cla += (s >> 2) + ((s >> 1) & 1); sn.order = s; for(int i = 1;i <= s >> 1;i += 2){ int index = k + ((i >> 1) << 1); symopPow(&sn, i, &sops[index]); sops[index].cla = cla + (i >> 1); printSymmetryOperation(&sops[index]); } for(int i = 1;i < s >> 1;i += 2){ int index = k + 1 + ((i >> 1) << 1); symopPow(&sn, s-i, &sops[index]); sops[index].cla = cla + (i >> 1); printSymmetryOperation(&sops[index]); } k += (s >> 1); cla += (s >> 2) + ((s >> 1) & 1); } if(MSYM_SUCCESS != (ret = generateSymmetryOperationsSn(s,l,sops,&k,&cla))) goto err; clean_debug_printf("------ Cnh %d operations %d classes------\n",k-*pk, cla-*pcla); *pk = k; *pcla = cla; return ret; err: return ret; } msym_error_t generateSymmetryOperationsCnv(int n, int l, msym_symmetry_operation_t sops[l], int *pk, int *pcla){ msym_error_t ret = MSYM_SUCCESS; int k = *pk, cla = *pcla; if(n == 0 && l == 2){ // normal c0v if(k + 1 > l){ ret = MSYM_POINT_GROUP_ERROR; msymSetErrorDetails("Too many operations when generating C%dv symmetry operations",n); goto err; } msym_symmetry_operation_t c0 = {.type = PROPER_ROTATION, .order = n, .power = 1, .orientation = HORIZONTAL, .cla = cla, .v = {0,0,1}}; memcpy(&sops[k], &c0, sizeof(msym_symmetry_operation_t)); k += 1; cla += 1; } else if(n == 0){ // c0v represented by a subclass cnv where n is even int n0 = l/2; double z[3] = {0,0,1}; if(n0 & 1){ ret = MSYM_POINT_GROUP_ERROR; msymSetErrorDetails("Cannot generate an odd representative (C%dv) of C0v",n0); goto err; } if(MSYM_SUCCESS != (ret = generateSymmetryOperationsCn(n0,l,sops,&k,&cla))) goto err; if(k + n0 > l){ ret = MSYM_POINT_GROUP_ERROR; msymSetErrorDetails("Too many operations when generating D0h (D%dh) symmetry operations",n0); goto err; } // Can't use generateReflectionPlanes they'll generate vertical and dihedral msym_symmetry_operation_t sigma = {.type = REFLECTION, .power = 1, .order = 1, .orientation = VERTICAL, .v = {0,1,0}}; for(int i = 0;i < n0;i++){ int index = k+i; memcpy(&(sops[index]), &sigma, sizeof(msym_symmetry_operation_t)); vrotate(i*M_PI/n0, sigma.v, z, sops[index].v); sops[index].cla = cla; } k += n0; cla += 1; clean_debug_printf("\n------ C0v %d operations %d classes------\n",k-*pk, cla-*pcla); } else { if(k + (n << 1) - 1 > l){ ret = MSYM_POINT_GROUP_ERROR; msymSetErrorDetails("Too many operations when generating C%dv symmetry operations",n); goto err; } if(MSYM_SUCCESS != (ret = generateSymmetryOperationsCn(n,l,sops,&k,&cla))) goto err; if(MSYM_SUCCESS != (ret = generateReflectionPlanes(n,l,sops,&k,&cla))) goto err; clean_debug_printf("------ Cnv %d operations %d classes------\n",k-*pk, cla-*pcla); } *pk = k; *pcla = cla; return ret; err: return ret; } msym_error_t generateSymmetryOperationsDn(int n, int l, msym_symmetry_operation_t sops[l], int *pk, int *pcla){ msym_error_t ret = MSYM_SUCCESS; int k = *pk, cla = *pcla; if(k + (n << 1) - 1 > l){ret = MSYM_POINT_GROUP_ERROR; msymSetErrorDetails("Too many operations when generating D%d symmetry operations",n); goto err;} //k += (n << 1) - 1; //cla = sops[k-1].cla + 1; if(MSYM_SUCCESS != (ret = generateSymmetryOperationsCn(n,l,sops,&k,&cla))) goto err; //k += n; //cla = sops[k-1].cla + 1; if(MSYM_SUCCESS != (ret = generateC2Axes(n,l,sops,&k,&cla))) goto err; //k += n; //cla = sops[k-1].cla + 1; clean_debug_printf("\n------ Dn %d operations %d classes------\n",k-*pk, cla-*pcla); *pk = k; *pcla = cla; return ret; err: return ret; } msym_error_t generateSymmetryOperationsDnh(int n, int l, msym_symmetry_operation_t sops[l], int *pk, int *pcla){ msym_error_t ret = MSYM_SUCCESS; int k = *pk, cla = *pcla; if(n == 0 && l == 4){ // standard d0h if(k + 3 > l){ ret = MSYM_POINT_GROUP_ERROR; msymSetErrorDetails("Too many operations when generating D%dh symmetry operations",n); goto err; } if(MSYM_SUCCESS != (ret = generateSymmetryOperationsCnv(n,2,sops,&k,&cla))) goto err; msym_symmetry_operation_t sigma = {.type = REFLECTION, .order = 1, .power = 1, .orientation = HORIZONTAL, .cla = cla, .v = {0,0,1}}; msym_symmetry_operation_t inversion = {.type = INVERSION, .order = 1, .power = 1, .orientation = NONE, .cla = cla+1, .v = {0,0,1}}; memcpy(&sops[k], &sigma, sizeof(msym_symmetry_operation_t)); memcpy(&sops[k+1], &inversion, sizeof(msym_symmetry_operation_t)); k += 2; cla += 2; } else if(n == 0){ // d0h represented by a subclass cnv where n is even int n0 = l/4; double z[3] = {0,0,1}; if(n0 & 1){ ret = MSYM_POINT_GROUP_ERROR; msymSetErrorDetails("Cannot generate an odd representative (D%dh) of D0h",n0); goto err; } if(MSYM_SUCCESS != (ret = generateSymmetryOperationsCnh(n0,l,sops,&k,&cla))) goto err; if(k + (n0 << 1) > l){ ret = MSYM_POINT_GROUP_ERROR; msymSetErrorDetails("Too many operations when generating D0h (D%dh) symmetry operations",n0); goto err; } // Can't use generateReflectionPlanes/generateC2Axes they'll generate vertical and dihedral msym_symmetry_operation_t c2 = {.type = PROPER_ROTATION, .power = 1, .order = 2, .orientation = VERTICAL, .v = {1,0,0}}; msym_symmetry_operation_t sigma = {.type = REFLECTION, .power = 1, .order = 1, .orientation = VERTICAL, .v = {0,1,0}}; for(int i = 0;i < n0;i++){ int index = k+i; memcpy(&(sops[index]), &sigma, sizeof(msym_symmetry_operation_t)); vrotate(i*M_PI/n0, sigma.v, z, sops[index].v); sops[index].cla = cla; clean_debug_printf("generated sigma at %d\n",index); index += n0; memcpy(&(sops[index]), &c2, sizeof(msym_symmetry_operation_t)); vrotate(i*M_PI/n0, c2.v, z, sops[index].v); sops[index].cla = cla+1; } k += n0 << 1; cla += 2; clean_debug_printf("\n------ D0h %d operations %d classes------\n",k-*pk, cla-*pcla); } else { if(k + (n << 2) - 1 > l){ ret = MSYM_POINT_GROUP_ERROR; msymSetErrorDetails("Too many operations when generating D%dh symmetry operations",n); goto err; } if(MSYM_SUCCESS != (ret = generateSymmetryOperationsCnh(n,l,sops,&k,&cla))) goto err; if(MSYM_SUCCESS != (ret = generateReflectionPlanes(n,l,sops,&k,&cla))) goto err; if(MSYM_SUCCESS != (ret = generateC2Axes(n,l,sops,&k,&cla))) goto err; clean_debug_printf("\n------ Dnh %d operations %d classes------\n",k-*pk, cla-*pcla); } *pk = k; *pcla = cla; return ret; err: return ret; } msym_error_t generateSymmetryOperationsDnd(int n, int l, msym_symmetry_operation_t sops[l], int *pk, int *pcla){ msym_error_t ret = MSYM_SUCCESS; int k = *pk, cla = *pcla; double x[3] = {1.0,0.0,0.0}, y[3] = {0.0,1.0,0.0}, z[3] = {0.0,0.0,1.0}; msym_symmetry_operation_t sigma = {.type = REFLECTION, .orientation = DIHEDRAL, .power = 1}; msym_symmetry_operation_t c2 = {.type = PROPER_ROTATION, .order = 2, .power = 1, .orientation = VERTICAL}; if(k + (n << 2) - 1 > l){ret = MSYM_POINT_GROUP_ERROR; msymSetErrorDetails("Too many operations when generating D%dd symmetry operations",n); goto err;} vcopy(x,c2.v); vrotate(M_PI_2/n, y, z, sigma.v); if(MSYM_SUCCESS != (ret = generateSymmetryOperationsSn((n << 1),l,sops, &k, &cla))) goto err; for(int i = 0;i < n;i++){ memcpy(&(sops[k+i]), &sigma, sizeof(msym_symmetry_operation_t)); vrotate(i*M_PI/n, sigma.v, z, sops[k+i].v); sops[k+i].cla = cla; } k += n; cla += 1; for(int i = 0;i < n;i++){ memcpy(&(sops[k+i]), &c2, sizeof(msym_symmetry_operation_t)); vrotate(i*M_PI/n, c2.v, z, sops[k+i].v); sops[k+i].cla = cla; } k += n; cla += 1; clean_debug_printf("\n------ Dnd %d operations %d classes------\n",k-*pk, cla-*pcla); *pk = k; *pcla = cla; return ret; err: return ret; } msym_error_t generateSymmetryOperationsT(int n, int l, msym_symmetry_operation_t sops[l], int *pk, int *pcla){ msym_error_t ret = MSYM_SUCCESS; int k = *pk, cla = *pcla; msym_symmetry_operation_t c2[1] = { [0] = {.type = PROPER_ROTATION, .order = 2, .power = 1, .cla = cla, .orientation = HORIZONTAL} }; msym_symmetry_operation_t c3[2] = { [0] = {.type = PROPER_ROTATION, .order = 3, .power = 1, .cla = cla+1, .orientation = NONE}, [1] = {.type = PROPER_ROTATION, .order = 3, .power = 2, .cla = cla+1, .orientation = NONE} }; if(MSYM_SUCCESS != (ret = generateSymmetryOperationsTetrahedral(l,sops, 1, c2, 0, NULL, 2, c3, &k))) goto err; cla += 2; clean_debug_printf("------ T %d operations %d classes------\n",k-*pk, cla-*pcla); *pk = k; *pcla = cla; return ret; err: return ret; } msym_error_t generateSymmetryOperationsTd(int n, int l, msym_symmetry_operation_t sops[l], int *pk, int *pcla){ msym_error_t ret = MSYM_SUCCESS; int k = *pk, cla = *pcla; msym_symmetry_operation_t c2[3] = { [0] = {.type = PROPER_ROTATION, .order = 2, .power = 1, .cla = cla, .orientation = HORIZONTAL}, [1] = {.type = IMPROPER_ROTATION, .order = 4, .power = 1, .cla = cla+1, .orientation = HORIZONTAL}, [2] = {.type = IMPROPER_ROTATION, .order = 4, .power = 3, .cla = cla+1, .orientation = HORIZONTAL} }; msym_symmetry_operation_t cs[4] = { [0] = {.type = REFLECTION, .order = 1, .power = 1, .cla = cla+2, .orientation = DIHEDRAL}, }; msym_symmetry_operation_t c3[2] = { [0] = {.type = PROPER_ROTATION, .order = 3, .power = 1, .cla = cla+3, .orientation = NONE}, [1] = {.type = PROPER_ROTATION, .order = 3, .power = 2, .cla = cla+3, .orientation = NONE} }; if(MSYM_SUCCESS != (ret = generateSymmetryOperationsTetrahedral(l,sops, 3, c2, 1, cs, 2, c3, &k))) goto err; cla += 4; clean_debug_printf("------ Td %d operations %d classes------\n",k-*pk, cla-*pcla); *pk = k; *pcla = cla; return ret; err: return ret; } msym_error_t generateSymmetryOperationsTh(int n, int l, msym_symmetry_operation_t sops[l], int *pk, int *pcla){ msym_error_t ret = MSYM_SUCCESS; int k = *pk, cla = *pcla; msym_symmetry_operation_t c2[2] = { [0] = {.type = PROPER_ROTATION, .order = 2, .power = 1, .cla = cla, .orientation = HORIZONTAL}, [1] = {.type = REFLECTION, .order = 1, .power = 1, .cla = cla+1, .orientation = HORIZONTAL} }; msym_symmetry_operation_t c3[4] = { [0] = {.type = PROPER_ROTATION, .order = 3, .power = 1, .cla = cla+2, .orientation = NONE}, [1] = {.type = PROPER_ROTATION, .order = 3, .power = 2, .cla = cla+2, .orientation = NONE}, [2] = {.type = IMPROPER_ROTATION, .order = 6, .power = 1, .cla = cla+3, .orientation = NONE}, [3] = {.type = IMPROPER_ROTATION, .order = 6, .power = 5, .cla = cla+3, .orientation = NONE} }; if(MSYM_SUCCESS != (ret = generateSymmetryOperationsTetrahedral(l,sops, 2, c2, 0, NULL, 4, c3, &k))) goto err; if(k - 1 > l){ret = MSYM_POINT_GROUP_ERROR; msymSetErrorDetails("Too many operations when generating Th operations %d >= %d",k, l); goto err;} sops[k].type = INVERSION; sops[k].power = 1; sops[k].order = 1; sops[k].orientation = NONE; sops[k].cla = cla+4; k++; cla += 5; clean_debug_printf("------ Th %d operations %d classes------\n",k-*pk, cla-*pcla); *pk = k; *pcla = cla; return ret; err: return ret; } msym_error_t generateSymmetryOperationsO(int n, int l, msym_symmetry_operation_t sops[l], int *pk, int *pcla){ msym_error_t ret = MSYM_SUCCESS; int k = *pk, cla = *pcla; msym_symmetry_operation_t c2[1] = { [0] = {.type = PROPER_ROTATION, .order = 2, .power = 1, .cla = cla, .orientation = VERTICAL} }; msym_symmetry_operation_t c3[2] = { [0] = {.type = PROPER_ROTATION, .order = 3, .power = 1, .cla = cla+1, .orientation = NONE}, [1] = {.type = PROPER_ROTATION, .order = 3, .power = 2, .cla = cla+1, .orientation = NONE} }; msym_symmetry_operation_t c4[4] = { [0] = {.type = PROPER_ROTATION, .order = 2, .power = 1, .cla = cla+2, .orientation = HORIZONTAL}, [1] = {.type = PROPER_ROTATION, .order = 4, .power = 1, .cla = cla+3, .orientation = HORIZONTAL}, [2] = {.type = PROPER_ROTATION, .order = 4, .power = 3, .cla = cla+3, .orientation = HORIZONTAL} }; if(MSYM_SUCCESS != (ret = generateSymmetryOperationsOctahedral(l,sops, 1, c2, 2, c3, 3, c4, &k))) goto err; cla += 4; clean_debug_printf("------ O %d operations %d classes------\n",k-*pk, cla-*pcla); *pk = k; *pcla = cla; return ret; err: return ret; } msym_error_t generateSymmetryOperationsOh(int n, int l, msym_symmetry_operation_t sops[l], int *pk, int *pcla){ msym_error_t ret = MSYM_SUCCESS; int k = *pk, cla = *pcla; msym_symmetry_operation_t c2[2] = { [0] = {.type = PROPER_ROTATION, .order = 2, .power = 1, .cla = cla, .orientation = VERTICAL}, [1] = {.type = REFLECTION, .order = 1, .power = 1, .cla = cla+1, .orientation = DIHEDRAL} }; msym_symmetry_operation_t c3[4] = { [0] = {.type = PROPER_ROTATION, .order = 3, .power = 1, .cla = cla+2, .orientation = NONE}, [1] = {.type = PROPER_ROTATION, .order = 3, .power = 2, .cla = cla+2, .orientation = NONE}, [2] = {.type = IMPROPER_ROTATION, .order = 6, .power = 1, .cla = cla+3, .orientation = NONE}, [3] = {.type = IMPROPER_ROTATION, .order = 6, .power = 5, .cla = cla+3, .orientation = NONE} }; msym_symmetry_operation_t c4[6] = { [0] = {.type = PROPER_ROTATION, .order = 2, .power = 1, .cla = cla+4, .orientation = HORIZONTAL}, [1] = {.type = PROPER_ROTATION, .order = 4, .power = 1, .cla = cla+5, .orientation = HORIZONTAL}, [2] = {.type = PROPER_ROTATION, .order = 4, .power = 3, .cla = cla+5, .orientation = HORIZONTAL}, [3] = {.type = IMPROPER_ROTATION, .order = 4, .power = 1, .cla = cla+6, .orientation = HORIZONTAL}, [4] = {.type = IMPROPER_ROTATION, .order = 4, .power = 3, .cla = cla+6, .orientation = HORIZONTAL}, [5] = {.type = REFLECTION, .order = 1, .power = 1, .cla = cla+7, .orientation = HORIZONTAL} }; if(MSYM_SUCCESS != (ret = generateSymmetryOperationsOctahedral(l,sops, 2, c2, 4, c3, 6, c4, &k))) goto err; if(k - 1 > l){ret = MSYM_POINT_GROUP_ERROR; msymSetErrorDetails("Too many operations when generating Oh operations %d >= %d",k, l); goto err;} sops[k].type = INVERSION; sops[k].power = 1; sops[k].order = 1; sops[k].orientation = NONE; sops[k].cla = cla+8; k++; cla += 9; clean_debug_printf("------ O %d operations %d classes------\n",k-*pk, cla-*pcla); *pk = k; *pcla = cla; return ret; err: return ret; } msym_error_t generateSymmetryOperationsI(int n, int l, msym_symmetry_operation_t sops[l], int *pk, int *pcla){ msym_error_t ret = MSYM_SUCCESS; int k = *pk, cla = *pcla; msym_symmetry_operation_t c2[1] = { [0] = {.type = PROPER_ROTATION, .order = 2, .power = 1, .cla = cla, .orientation = NONE} }; msym_symmetry_operation_t c3[2] = { [0] = {.type = PROPER_ROTATION, .order = 3, .power = 1, .cla = cla+1, .orientation = NONE}, [1] = {.type = PROPER_ROTATION, .order = 3, .power = 2, .cla = cla+1, .orientation = NONE} }; msym_symmetry_operation_t c4[4] = { [0] = {.type = PROPER_ROTATION, .order = 5, .power = 1, .cla = cla+2, .orientation = NONE}, [1] = {.type = PROPER_ROTATION, .order = 5, .power = 4, .cla = cla+2, .orientation = NONE}, [2] = {.type = PROPER_ROTATION, .order = 5, .power = 2, .cla = cla+3, .orientation = NONE}, [3] = {.type = PROPER_ROTATION, .order = 5, .power = 3, .cla = cla+3, .orientation = NONE} }; if(MSYM_SUCCESS != (ret = generateSymmetryOperationsIcosahedral(l,sops, 1, c2, 2, c3, 4, c4, &k))) goto err; cla += 4; clean_debug_printf("------ I %d operations %d classes------\n",k-*pk, cla-*pcla); *pk = k; *pcla = cla; return ret; err: return ret; } msym_error_t generateSymmetryOperationsIh(int n, int l, msym_symmetry_operation_t sops[l], int *pk, int *pcla){ msym_error_t ret = MSYM_SUCCESS; int k = *pk, cla = *pcla; msym_symmetry_operation_t c2[2] = { [0] = {.type = PROPER_ROTATION, .order = 2, .power = 1, .cla = cla, .orientation = NONE}, [1] = {.type = REFLECTION, .order = 1, .power = 1, .cla = cla+1, .orientation = NONE} }; msym_symmetry_operation_t c3[4] = { [0] = {.type = PROPER_ROTATION, .order = 3, .power = 1, .cla = cla+2, .orientation = NONE}, [1] = {.type = PROPER_ROTATION, .order = 3, .power = 2, .cla = cla+2, .orientation = NONE}, [2] = {.type = IMPROPER_ROTATION, .order = 6, .power = 1, .cla = cla+3, .orientation = NONE}, [3] = {.type = IMPROPER_ROTATION, .order = 6, .power = 5, .cla = cla+3, .orientation = NONE} }; msym_symmetry_operation_t c5[8] = { [0] = {.type = PROPER_ROTATION, .order = 5, .power = 1, .cla = cla+4, .orientation = NONE}, [1] = {.type = PROPER_ROTATION, .order = 5, .power = 4, .cla = cla+4, .orientation = NONE}, [2] = {.type = PROPER_ROTATION, .order = 5, .power = 2, .cla = cla+5, .orientation = NONE}, [3] = {.type = PROPER_ROTATION, .order = 5, .power = 3, .cla = cla+5, .orientation = NONE}, [4] = {.type = IMPROPER_ROTATION, .order = 10, .power = 1, .cla = cla+6, .orientation = NONE}, [5] = {.type = IMPROPER_ROTATION, .order = 10, .power = 9, .cla = cla+6, .orientation = NONE}, [6] = {.type = IMPROPER_ROTATION, .order = 10, .power = 3, .cla = cla+7, .orientation = NONE}, [7] = {.type = IMPROPER_ROTATION, .order = 10, .power = 7, .cla = cla+7, .orientation = NONE}, }; if(MSYM_SUCCESS != (ret = generateSymmetryOperationsIcosahedral(l,sops, 2, c2, 4, c3, 8, c5, &k))) goto err; if(k - 1 > l){ret = MSYM_POINT_GROUP_ERROR; msymSetErrorDetails("Too many operations when generating Ih operations %d >= %d",k + 12, l); goto err;} sops[k].type = INVERSION; sops[k].power = 1; sops[k].order = 1; sops[k].orientation = NONE; sops[k].cla = cla+8; k++; cla += 9; clean_debug_printf("------ Ih %d operations %d classes------\n",k-*pk, cla-*pcla); *pk = k; *pcla = cla; return ret; err: return ret; } msym_error_t generateSymmetryOperationsTetrahedral(int l, msym_symmetry_operation_t sops[l], int c2l, msym_symmetry_operation_t c2[c2l], int csl, msym_symmetry_operation_t cs[csl], int c3l, msym_symmetry_operation_t c3[c3l], int *pk){ msym_error_t ret = MSYM_SUCCESS; int k = *pk; if(k + c2l*3 + csl*6 + c3l*4 > l){ret = MSYM_POINT_GROUP_ERROR; msymSetErrorDetails("Too many operations when generating tetrahedral operations %d >= %d",k + c2l*3 + csl*6 + c3l*4, l); goto err;} const double v2[3][3] = { { 1, 0, 0}, { 0, 1, 0}, { 0, 0, 1}, }; const double vs[6][3] = { { 1, 0, 1}, { 0, 1, 1}, {-1, 0, 1}, { 0,-1, 1}, { 1, 1, 0}, { 1,-1, 0} }; const double v3[4][3] = { {1,1,1}, {-1,1,1}, {1,-1,1}, {-1,-1,1} }; for(int i = 0;i < c2l;i++){ for(int j = 0; j < 3;j++){ memcpy(&sops[k], &c2[i], sizeof(msym_symmetry_operation_t)); vnorm2(v2[j],sops[k].v); k++; } } for(int i = 0;i < csl;i++){ for(int j = 0; j < 6;j++){ memcpy(&sops[k], &cs[i], sizeof(msym_symmetry_operation_t)); vnorm2(vs[j],sops[k].v); k++; } } for(int i = 0;i < c3l;i++){ for(int j = 0; j < 4;j++){ memcpy(&sops[k], &c3[i], sizeof(msym_symmetry_operation_t)); vnorm2(v3[j],sops[k].v); k++; } } clean_debug_printf("------ Tetra %d operations 0 classes------\n",k-*pk); *pk = k; return ret; err: return ret; } msym_error_t generateSymmetryOperationsOctahedral(int l, msym_symmetry_operation_t sops[l], int c2l, msym_symmetry_operation_t c2[c2l], int c3l, msym_symmetry_operation_t c3[c3l], int c4l, msym_symmetry_operation_t c4[c4l], int *pk){ msym_error_t ret = MSYM_SUCCESS; int k = *pk; if(k + c2l*6 + c3l*4 + c4l*3 > l){ret = MSYM_POINT_GROUP_ERROR; msymSetErrorDetails("Too many operations when generating octahedral operations %d >= %d",k + c2l*6 + c3l*4 + c4l*3, l); goto err;} const double v2[6][3] = { { 1, 0, 1}, { 0, 1, 1}, {-1, 0, 1}, { 0,-1, 1}, { 1, 1, 0}, { 1,-1, 0} }; const double v3[4][3] = { {1,1,1}, {-1,1,1}, {1,-1,1}, {-1,-1,1} }; const double v4[3][3] = { { 1, 0, 0}, { 0, 1, 0}, { 0, 0, 1}, }; for(int i = 0;i < c2l;i++){ for(int j = 0; j < 6;j++){ memcpy(&sops[k], &c2[i], sizeof(msym_symmetry_operation_t)); vnorm2(v2[j],sops[k].v); k++; } } for(int i = 0;i < c3l;i++){ for(int j = 0; j < 4;j++){ memcpy(&sops[k], &c3[i], sizeof(msym_symmetry_operation_t)); vnorm2(v3[j],sops[k].v); k++; } } for(int i = 0;i < c4l;i++){ for(int j = 0; j < 3;j++){ memcpy(&sops[k], &c4[i], sizeof(msym_symmetry_operation_t)); vnorm2(v4[j],sops[k].v); k++; } } clean_debug_printf("------ Octa %d operations 0 classes------\n",k-*pk); *pk = k; return ret; err: return ret; } msym_error_t generateSymmetryOperationsIcosahedral(int l, msym_symmetry_operation_t sops[l], int c2l, msym_symmetry_operation_t c2[c2l], int c3l, msym_symmetry_operation_t c3[c3l], int c5l, msym_symmetry_operation_t c5[c5l], int *pk){ msym_error_t ret = MSYM_SUCCESS; int k = *pk; if(k + c2l*15 + c3l*10 + c5l*6 > l){ret = MSYM_POINT_GROUP_ERROR; msymSetErrorDetails("Too many operations when generating icosahedral operations %d >= %d",k + c2l*15 + c3l*10 + c5l*6, l); goto err;} const double v2[15][3] = { {0,0,1}, {1,0,0}, {0,1,0}, {PHI,-(PHI+1),1}, {(PHI+1),1,-PHI}, {1,PHI,(PHI+1)}, {PHI,(PHI+1),1}, {(PHI+1),-1,-PHI}, {-1,PHI,-(PHI+1)}, {(PHI+1),1,PHI}, {1,PHI,-(PHI+1)}, {-PHI,(PHI+1),1}, {1,-PHI,-(PHI+1)}, {PHI,(PHI+1),-1}, {(PHI+1),-1,PHI} }; const double v3[10][3] = { {1,1,1}, {-1,1,1}, {1,-1,1}, {-1,-1,1}, {(PHI+1),0,1}, {0,-1,(PHI+1)}, {-1,-(PHI+1),0}, {-1,(PHI+1),0}, {0,1,(PHI+1)}, {(PHI+1),0,-1} }; const double v5[6][3] = { {PHI,1,0}, {-PHI,1,0}, {0,PHI,1}, {0,-PHI,1}, {1,0,PHI}, {1,0,-PHI} }; for(int i = 0;i < c2l;i++){ for(int j = 0; j < 15;j++){ memcpy(&sops[k], &c2[i], sizeof(msym_symmetry_operation_t)); vnorm2(v2[j],sops[k].v); k++; } } for(int i = 0;i < c3l;i++){ for(int j = 0; j < 10;j++){ memcpy(&sops[k], &c3[i], sizeof(msym_symmetry_operation_t)); vnorm2(v3[j],sops[k].v); k++; } } for(int i = 0;i < c5l;i++){ for(int j = 0; j < 6;j++){ memcpy(&sops[k], &c5[i], sizeof(msym_symmetry_operation_t)); vnorm2(v5[j],sops[k].v); k++; } } clean_debug_printf("------ Icosa %d operations 0 classes------\n",k-*pk); *pk = k; return ret; err: return ret; } msym_error_t generateReflectionPlanes(int n, int l, msym_symmetry_operation_t sops[l], int *pk, int *pcla){ msym_error_t ret = MSYM_SUCCESS; int k = *pk, cla = *pcla; double z[3] = {0.0,0.0,1.0}, y[3] = {0.0,1.0,0.0}; msym_symmetry_operation_t sigma = {.type = REFLECTION, .power = 1, .order = 1}; if(k + n > l){ret = MSYM_POINT_GROUP_ERROR; msymSetErrorDetails("Too many operations when generating reflection planes"); goto err;} vcopy(y,sigma.v); enum _msym_symmetry_operation_orientation orientation[2] = {VERTICAL, DIHEDRAL}; for(int i = 0;i < n;i++){ int e = 1 & ~n, ie = ((i & e)), index = k + (i >> e) + (ie ? (n >> 1) : 0); //power = 1 - (ie << 1), memcpy(&(sops[index]), &sigma, sizeof(msym_symmetry_operation_t)); vrotate(i*M_PI/n, sigma.v, z, sops[index].v); //sops[index].power = power; // Used the finding of eigenvalues for character tables sops[index].orientation = orientation[ie]; sops[index].cla = cla + ie; } k += n; cla += 1 << (~n & 1); //1 or 2 added classes clean_debug_printf("------ R %d operations %d classes------\n",k-*pk, cla-*pcla); *pk = k; *pcla = cla; return ret; err: return ret; } msym_error_t generateC2Axes(int n, int l, msym_symmetry_operation_t sops[l], int *pk, int *pcla){ msym_error_t ret = MSYM_SUCCESS; int k = *pk, cla = *pcla; double z[3] = {0.0,0.0,1.0}, x[3] = {1.0,0.0,0.0}; msym_symmetry_operation_t c2 = {.type = PROPER_ROTATION, .order = 2, .power = 1}; if(k + n > l){ret = MSYM_POINT_GROUP_ERROR; msymSetErrorDetails("Too many operations when generating C2 axes"); goto err;} vcopy(x,c2.v); enum _msym_symmetry_operation_orientation orientation[2] = {VERTICAL, DIHEDRAL}; for(int i = 0;i < n;i++){ int e = 1 & ~n, ie = ((i & e)), index = k + (i >> e) + (ie ? (n >> 1) : 0); memcpy(&(sops[index]), &c2, sizeof(msym_symmetry_operation_t)); vrotate(i*M_PI/n, c2.v, z, sops[index].v); //sops[index].power = power; // Used the finding of eigenvalues for character tables sops[index].orientation = orientation[ie]; sops[index].cla = cla + ie; } k += n; cla += 1 << (~n & 1); //1 or 2 added classes clean_debug_printf("------ C2 %d operations %d classes------\n",k-*pk, cla-*pcla); *pk = k; *pcla = cla; return ret; err: return ret; } int classifySymmetryOperations(msym_point_group_t *pg){ int c = 1; double (*mop)[3][3] = malloc(sizeof(double[pg->order][3][3])); double (*imop)[3][3] = malloc(sizeof(double[pg->order][3][3])); //There may be a better way to do this for(int i = 0; i < pg->order;i++){ if(pg->sops[i].type == IDENTITY){ pg->sops[i].cla = 0; } else { pg->sops[i].cla = -1; } msym_symmetry_operation_t isop; invertSymmetryOperation(&(pg->sops[i]), &isop); symmetryOperationMatrix(&(pg->sops[i]), mop[i]); symmetryOperationMatrix(&isop, imop[i]); } for(int i = 0; i < pg->order;i++){ if(pg->sops[i].cla < 0){ pg->sops[i].cla = c; for(int j = 0; j < pg->order;j++){ double m[3][3]; mmmul(mop[i], imop[j], m); mmmul(mop[j],m,m); for(int k = 0; k < pg->order;k++){ if(mequal(mop[k],m,CLASSIFICATION_THRESHOLD)){ //Don't need to be dynamic, this is done on generated point groups (always the same) pg->sops[k].cla = c; } } } c++; } } free(mop); free(imop); return c; } //cant be bothereed writing an efficient sorting alg for this void sortSymmetryOperations(msym_point_group_t *pg, int classes){ msym_symmetry_operation_t *tmp = malloc(pg->order*sizeof(msym_symmetry_operation_t)); int n = 0; for(int c = 0; c < classes;c++){ for(int i = 0; i < pg->order;i++){ if(pg->sops[i].cla == c){ copySymmetryOperation(&tmp[n], &pg->sops[i]); n++; } } } memcpy(pg->sops, tmp,pg->order*sizeof(msym_symmetry_operation_t)); free(tmp); } int numberOfSubgroups(msym_point_group_t *pg){ int n = pg->n; int size = 0, ndiv = n >= 2, sdiv = 0, nodd = 0, sodd = 0, neven = 0, seven = 0; if(isLinearSubgroup(pg)){ switch (pg->type) { case MSYM_POINT_GROUP_TYPE_Cnv : n = pg->order / 4; break; case MSYM_POINT_GROUP_TYPE_Dnh : n = pg->order / 2; break; default: break; } } switch (pg->type) { case MSYM_POINT_GROUP_TYPE_Kh : size = -1; break; case MSYM_POINT_GROUP_TYPE_K : size = -1; break; case MSYM_POINT_GROUP_TYPE_Ih : size = 162; break; case MSYM_POINT_GROUP_TYPE_I : size = 57; break; case MSYM_POINT_GROUP_TYPE_Oh : size = 96; break; case MSYM_POINT_GROUP_TYPE_O : size = 28; break; case MSYM_POINT_GROUP_TYPE_Th : size = 24; break; case MSYM_POINT_GROUP_TYPE_Td : size = 28; break; case MSYM_POINT_GROUP_TYPE_T : size = 9; break; case MSYM_POINT_GROUP_TYPE_Ci : size = 0; break; case MSYM_POINT_GROUP_TYPE_Cs : size = 0; break; default: { for(int i = 2; i < n;i++){ if(n % i == 0){ ndiv++; sdiv += i; } } for(int i = 3; i < n;i += 2){ if(n % i == 0){ nodd++; sodd += i;} } for(int i = 4; i <= n;i += 2){ if(n % i == 0){ neven++; seven += (n << 1)/i; } } switch (pg->type) { case MSYM_POINT_GROUP_TYPE_Cnh : { size = 2*ndiv; if(n % 2 == 0){ int n2 = n >> 1; for(int i = 2; i < n2;i++){ if(n2 % i == 0){ size++;} } size += 1 + (n2 >= 2); } break; } case MSYM_POINT_GROUP_TYPE_Dn : case MSYM_POINT_GROUP_TYPE_Cnv : size = n + ndiv + sdiv; break; case MSYM_POINT_GROUP_TYPE_Cn : size = ndiv - 1; break; case MSYM_POINT_GROUP_TYPE_Dnh : { if(n % 2 == 0) size = 4*n + 2*ndiv + 3*sdiv + 4 + neven + seven; else size = 3*(n+sdiv+1) + 2*ndiv; break; } case MSYM_POINT_GROUP_TYPE_Dnd : { if(n % 2 == 0) size = 2*n + 3 + ndiv + 2*sdiv + nodd + sodd; else size = 3*(n+sdiv+1) + 2*ndiv; break; } case MSYM_POINT_GROUP_TYPE_Sn : size = ndiv - 1; break; default : break; } } } return size; } v_sim-3.8.0/lib/plug-ins/msym/libmsym/src/point_group.h000066400000000000000000000032111370110300500230740ustar00rootroot00000000000000// // point_group.h // Symmetry // // Created by Marcus Johansson on 28/11/14. // Copyright (c) 2014 Marcus Johansson. // // Distributed under the MIT License ( See LICENSE file or copy at http://opensource.org/licenses/MIT ) // #ifndef __MSYM__POINT_GROUP_h #define __MSYM__POINT_GROUP_h #include "msym.h" #include "symop.h" #include "geometry.h" #include "character_table.h" #include "permutation.h" typedef struct { msym_point_group_type_t type; int n; int order; msym_symmetry_operation_t *primary; msym_symmetry_operation_t *sops; msym_permutation_t *perm; double transform[3][3]; msym_character_table_t *ct; char name[8]; } msym_point_group_t; int isLinearPointGroup(msym_point_group_t *pg); int isLinearSubgroup(msym_point_group_t *pg); msym_error_t findPointGroup(int sopsl, msym_symmetry_operation_t *sops, msym_thresholds_t *thresholds, msym_point_group_t **pg); msym_error_t findSubgroup(msym_subgroup_t *subgroup, msym_thresholds_t *thresholds); msym_error_t findCharacterTable(msym_point_group_t *pg); msym_error_t generatePointGroupFromName(const char *name, double transform[3][3], msym_thresholds_t *thresholds, msym_point_group_t **opg); msym_error_t generatePointGroupFromType(msym_point_group_type_t type, int n, double transform[3][3], msym_thresholds_t *thresholds, msym_point_group_t **opg); msym_error_t pointGroupFromSubgroup(const msym_subgroup_t *sg, msym_thresholds_t *thresholds, msym_point_group_t **opg); msym_error_t reduceLinearPointGroup(msym_point_group_t *pg, int n, msym_thresholds_t *thresholds); int numberOfSubgroups(msym_point_group_t *pg); #endif /* defined(__MSYM__POINT_GROUP_h) */ v_sim-3.8.0/lib/plug-ins/msym/libmsym/src/rsh.c000066400000000000000000000145471370110300500213340ustar00rootroot00000000000000// // rsh.c // libmsym // // Created by Marcus Johansson on 21/10/15. // Copyright (c) 2015 Marcus Johansson. // // Distributed under the MIT License ( See LICENSE file or copy at http://opensource.org/licenses/MIT ) // // Ref: // // J. Ivanic and K. Ruedenberg, "Rotation Matrices for Real Spherical Harmonics. Direct Determination by Recursion", // J. Phys. Chem., vol. 100, no. 15, pp. 6342-6347, 1996. http://pubs.acs.org/doi/pdf/10.1021/jp953350u #include #include #include #include #include #include "rsh.h" #include "linalg.h" #include "symop.h" #define SQR(x) ((x)*(x)) #ifndef M_SQRT2 #define M_SQRT2 1.41421356237309504880 #endif void rshSymmetryOperationRepresentation(msym_symmetry_operation_t *sops, int index, int l, rsh_representations_t *lts); void rshCalculateUVWCoefficients(int l, int m1, int m2, double* u, double* v, double* w); void rshRotationRepresentation(int index, int l, rsh_representations_t *lrs); double rshRotationP(int index, int l, int i, int m1, int m2, rsh_representations_t *lrs); double rshRotationU(int index, int l, int m1, int m2, rsh_representations_t *lrs); double rshRotationV(int index, int l, int m1, int m2, rsh_representations_t *lrs); double rshRotationW(int index, int l, int m1, int m2, rsh_representations_t *lrs); msym_error_t generateRSHRepresentations(int sopsl, msym_symmetry_operation_t sops[sopsl], int lmax, rsh_representations_t *lrs){ msym_error_t ret = MSYM_SUCCESS; for(int l = 0;l <= lmax;l++){ if(lrs[l].d != 2*l+1){ ret = MSYM_INVALID_BASIS_FUNCTIONS; msymSetErrorDetails("Invalid dimension of real spherical harmonic (expected %d, got %d)",2*l+1, lrs[l].d); goto err; } for(int i = 0; i < sopsl;i++){ rshSymmetryOperationRepresentation(sops,i,l,lrs); } } err: return ret; } void rshSymmetryOperationRepresentation(msym_symmetry_operation_t *sops, int index, int l, rsh_representations_t *lrs){ if(0 == l){ int d = lrs[0].d; double (*st)[d][d] = lrs[0].t; st[index][0][0] = 1; } else if(1 == l){ int d = lrs[1].d; double (*st)[d][d] = lrs[1].t; double (*r)[d] = st[index]; double t[3][3]; symmetryOperationMatrix(&sops[index], t); // x,y,z -> py, pz, px r[0][0] = t[1][1]; r[0][1] = t[1][2]; r[0][2] = t[1][0]; r[1][0] = t[2][1]; r[1][1] = t[2][2]; r[1][2] = t[2][0]; r[2][0] = t[0][1]; r[2][1] = t[0][2]; r[2][2] = t[0][0]; } else { int d = lrs[l].d; double (*st)[d][d] = lrs[l].t; double (*r)[d] = st[index]; switch (sops[index].type) { case INVERSION: if(l & 1){ memset(r,0,sizeof(double[d][d])); for(int i = 0;i < d;i++) r[i][i] = -1; break; } //fallthrough case IDENTITY: mleye(d,r); break; case REFLECTION: case IMPROPER_ROTATION: case PROPER_ROTATION: default: rshRotationRepresentation(index, l, lrs); break; } } } double rshRotationP(int index, int l, int i, int m1, int m2, rsh_representations_t *lrs){ int d1 = lrs[1].d, dl = lrs[l-1].d, ol = (dl - 1)/2; double (*st1)[d1][d1] = lrs[1].t, (*stl)[dl][dl] = lrs[l-1].t; double (*r1)[d1] = st1[index], (*rl)[dl] = stl[index]; double ret = 0; if (m2 == l) { ret = r1[i + 1][2]*rl[m1 + ol][l - 1 + ol] - r1[i + 1][0]*rl[m1 + ol][1 - l + ol]; } else if (m2 == -l) { ret = r1[i + 1][2]*rl[m1 + ol][1 - l + ol] + r1[i + 1][0]*rl[m1 + ol][l - 1 + ol]; } else { ret = r1[i + 1][1]*rl[m1 + ol][m2 + ol]; } return ret; } double rshRotationU(int index, int l, int m1, int m2, rsh_representations_t *lrs){ return rshRotationP(index, l, 0, m1, m2, lrs); } double rshRotationV(int index, int l, int m1, int m2, rsh_representations_t *lrs){ double ret = 0; if (m1 == 0) { ret = rshRotationP(index, l, 1, 1, m2, lrs) + rshRotationP(index, l, -1, -1, m2, lrs); } else if (m1 == 1){ ret = M_SQRT2*rshRotationP(index, l, 1, 0, m2, lrs); } else if (m1 == -1){ ret = M_SQRT2*rshRotationP(index, l, -1, 0, m2, lrs); } else if (m1 > 0){ ret = rshRotationP(index, l, 1, m1 - 1, m2, lrs) - rshRotationP(index,l, -1, -m1 + 1, m2, lrs); } else { ret = rshRotationP(index, l, 1, m1 + 1, m2, lrs) + rshRotationP(index,l, -1, -m1 - 1, m2, lrs); } return ret; } double rshRotationW(int index, int l, int m1, int m2, rsh_representations_t *lrs){ double ret = 0; if (m1 > 0) { ret = rshRotationP(index, l, 1, m1 + 1, m2, lrs) + rshRotationP(index, l, -1, -m1 - 1, m2, lrs); } else { ret = rshRotationP(index, l, 1, m1 - 1, m2, lrs) - rshRotationP(index, l, -1, -m1 + 1, m2, lrs); } return ret; } void rshRotationRepresentation(int index, int l, rsh_representations_t *lrs){ int d = lrs[l].d; double (*st)[d][d] = lrs[l].t; double (*r)[d] = st[index]; for (int m1 = -l; m1 <= l; m1++) { for (int m2 = -l; m2 <= l; m2++) { double u, v, w; rshCalculateUVWCoefficients(l, m1, m2, &u, &v, &w); if(u != 0){ u *= rshRotationU(index, l, m1, m2, lrs); } if(v != 0){ v *= rshRotationV(index, l, m1, m2, lrs); } if(w != 0){ w *= rshRotationW(index, l, m1, m2, lrs); } r[m1 + l][m2 + l] = u + v + w; } } } void rshCalculateUVWCoefficients(int l, int m1, int m2, double *u, double *v, double *w) { if(m1 == 0){ // d = 1 if(abs(m2) == l){ *u = sqrt(l/(4*l - 2.0)); *v = -0.5*sqrt((l - 1.0)/(2*l - 1.0)); } else { double m22 = SQR(m2), l2 = SQR(l), l2m22 = l2 - m22; *u = sqrt(l2/l2m22); *v = -0.5*sqrt(2*(l2 - l)/l2m22); } *w = 0; } else { // d = 0 double am1 = abs(m1); double div = (abs(m2) == l ? 2.0*l*(2.0*l - 1) : (l + m2)*(l - m2)); *u = sqrt((l + m1)*(l - m1)/div); *v = 0.5*sqrt((l + am1 - 1)*(l + am1)/div); *w = -0.5*sqrt((l - am1 - 1)*(l - am1)/div); } } v_sim-3.8.0/lib/plug-ins/msym/libmsym/src/rsh.h000066400000000000000000000007161370110300500213320ustar00rootroot00000000000000// // rsh.h // libmsym // // Created by Marcus Johansson on 21/10/15. // Copyright (c) 2015 Marcus Johansson. // // Distributed under the MIT License ( See LICENSE file or copy at http://opensource.org/licenses/MIT ) // #include "msym.h" typedef struct _rsh_representations { int d; void *t; } rsh_representations_t; msym_error_t generateRSHRepresentations(int sopsl, msym_symmetry_operation_t sops[sopsl], int lmax, rsh_representations_t *lrs); v_sim-3.8.0/lib/plug-ins/msym/libmsym/src/subspace.c000066400000000000000000002310511370110300500223340ustar00rootroot00000000000000// // subspace.c // libmsym // // Created by Marcus Johansson on 28/05/15. // Copyright (c) 2014 Marcus Johansson. // // Distributed under the MIT License ( See LICENSE file or copy at http://opensource.org/licenses/MIT ) // #include #include #include #include #include "msym.h" #include "linalg.h" #include "subspace.h" #include "permutation.h" #include "rsh.h" #include "debug.h" #define SQR(x) ((x)*(x)) #define PARTNER_THRESHOLD 1.0e-6 msym_error_t projectLinearlyIndependent(int dim, int vdim, double v[vdim][dim], int udim, double u[udim][dim], msym_thresholds_t *thresholds, double cmem[dim], double mem[dim][dim], double o[dim][dim], int *oirl); void decomposeSubRepresentation(msym_point_group_t *pg, const msym_subgroup_t **rsg, double (*sgc)[5][pg->order], int span[pg->ct->d], int (*sgd)[5]){ msym_character_table_t *ct = pg->ct; msym_symmetry_operation_t *sops = pg->sops; int sopsl = pg->order; int icosahedral = MSYM_POINT_GROUP_TYPE_I == pg->type || MSYM_POINT_GROUP_TYPE_Ih == pg->type; double (*ctable)[ct->d] = ct->table; memset(sgd, 0, ct->d*sizeof(*sgd)); for(int ck = 0;ck < ct->d;ck++){ for(int sk = 0;sk < ct->d;sk++){ if(NULL == rsg[sk]) continue; int irrepd = ct->s[sk].d; if(!(icosahedral && irrepd == 5)){ for(int d = 0; d < irrepd;d++){ double prod = 0; for(int s = 0; s < sopsl;s++){ prod += sgc[sk][d][s]*ctable[ck][sops[s].cla]; } //printf("decomposition of irrep %s into subdimension %d irrep %d = %lf\n",ct->s[ck].name, d, sk, prod/rsg[sk]->order); sgd[sk][d] += (int) round(span[ck]*prod/rsg[sk]->order); } } else { int o = rsg[sk]->order; int order[] = {o,o,o,2,2}; int dim[] = {1,2,2,1,1}; for(int d = 0; d < irrepd;d++){ double prod = 0; for(int s = 0; s < sopsl;s++){ prod += dim[d]*sgc[sk][d][s]*ctable[ck][sops[s].cla]; } //printf("decomposition of irrep %s into subdimension %d irrep %d = %lf\n",ct->s[ck].name, d, sk, prod/order[d]); sgd[sk][d] += (int) round(span[ck]*prod/order[d]); } } } } } msym_error_t generateBasisRepresentations(int n, int sopsl, msym_symmetry_operation_t sops[sopsl], int lmax, rsh_representations_t *lrsh){ msym_error_t ret = MSYM_SUCCESS; for(int l = 0;l <= lmax;l++){ int d = 2*l+1; lrsh[l].d = d; lrsh[l].t = malloc(sizeof(double[n][d][d])); } if(MSYM_SUCCESS != (ret = generateRSHRepresentations(sopsl, sops, lmax, lrsh))) goto err; return ret; err: for(int l = 0;l <= lmax;l++){ free(lrsh[l].t); lrsh[l].t = NULL; lrsh[l].d = 0; } return ret; } msym_error_t generateProjectionOperator(int d, int sopsl, double c[sopsl], msym_permutation_t perm[sopsl], int ld, double (*lsops)[ld][ld], double proj[perm->p_length*ld][perm->p_length*ld]){ msym_error_t ret = MSYM_SUCCESS; int pd = perm->p_length; memset(proj,0,sizeof(double[pd*ld][pd*ld])); for(int s = 0;s < sopsl;s++){ if(c[s] == 0) continue; for(int pi = 0, po = 0;pi < pd;pi++, po += ld){ int pr = perm[s].p[pi]*ld; for(int li = 0;li < ld;li++){ int r = pr + li; for(int lj = 0;lj < ld;lj++){ proj[r][po+lj] += lsops[s][li][lj]*c[s]; } } } } mlscale(((double)d)/sopsl, pd*ld, proj, proj); return ret; } msym_error_t generatePermutationSubspaces(msym_point_group_t *pg, msym_permutation_t perm[pg->order], int span[pg->ct->d], msym_thresholds_t *thresholds, double pmem[4][perm->p_length][perm->p_length], double (**pss)[pg->ct->d], double ss[perm->p_length][perm->p_length]){ msym_error_t ret = MSYM_SUCCESS; int dim = perm->p_length, sopsl = pg->order; msym_character_table_t *ct = pg->ct; msym_symmetry_operation_t *sops = pg->sops; double (*ctable)[ct->d] = ct->table; double (*proj)[dim] = pmem[0]; memset(ss, 0, dim*sizeof(*ss)); memset(pss, 0, ct->d*sizeof(*pss)); for(int k = 0, oirl = 0, nirl = 0;k < ct->d;k++, oirl = nirl){ int irrepd = ct->s[k].d, vspan = irrepd*span[k]; if(vspan == 0) continue; memset(proj,0,dim*sizeof(*proj)); for(int s = 0;s < sopsl;s++){ double c = ctable[k][sops[s].cla]; if(c == 0) continue; for(int i = 0;i < dim;i++){ proj[perm[s].p[i]][i] += c; } } nirl = mgs2(dim, vspan,proj, ss, oirl, thresholds->orthogonalization); if(nirl - oirl != vspan){ debug_printTransform(dim, dim, ss); ret = MSYM_SUBSPACE_ERROR; msymSetErrorDetails("Ortogonal permutation subspace of dimension (%d) inconsistent with span (%d) in %s",nirl - oirl,vspan,ct->s[k].name); goto err; } pss[k] = &ss[oirl]; } //for(int i = 0; i < dim;i++) vlnorm(dim, ss[i]); err: return ret; } msym_error_t generateSubspaces(msym_point_group_t *pg, msym_permutation_t perm[pg->order], int ld, double (*lrsops)[ld][ld], int span[pg->ct->d], double (*sgc)[5][pg->order], int (*sgd)[5], msym_thresholds_t *thresholds, double cmem[pg->order], double pmem[4][perm->p_length*ld][perm->p_length*ld], double (*(*pss)[5])[pg->ct->d], double ss[perm->p_length*ld][perm->p_length*ld]){ msym_error_t ret = MSYM_SUCCESS; int pd = perm->p_length, dim = pd*ld; msym_character_table_t *ct = pg->ct; double (*ctable)[ct->d] = ct->table; double (*proj)[dim] = pmem[0], (*sspg)[dim] = pmem[1], (*sssg)[dim] = pmem[2], (*mem)[dim] = pmem[3]; msym_symmetry_operation_t *sops = pg->sops; int sopsl = pg->order; int icosahedral = MSYM_POINT_GROUP_TYPE_I == pg->type || MSYM_POINT_GROUP_TYPE_Ih == pg->type; memset(ss, 0, dim*sizeof(*ss)); memset(pss, 0, ct->d*sizeof(*pss)); for(int k = 0, oirl = 0, nirl = 0;k < ct->d;k++, oirl = nirl){ int irrepd = ct->s[k].d, pgvspan = irrepd*span[k]; if(pgvspan == 0) continue; for(int s = 0;s < pg->order;s++) cmem[s] = ctable[k][sops[s].cla]; if(MSYM_SUCCESS != (ret = generateProjectionOperator(irrepd,sopsl,cmem,perm,ld,lrsops,proj))) goto err; if(irrepd == 1){ nirl = mgs2(dim, pgvspan, proj, ss, oirl, thresholds->orthogonalization); if(nirl - oirl != pgvspan){ debug_printTransform(dim, dim, ss); ret = MSYM_SUBSPACE_ERROR; msymSetErrorDetails("Ortogonal subspace of dimension (%d) inconsistent with span (%d) in %s",nirl - oirl,pgvspan,ct->s[k].name); goto err; } pss[k][0] = &ss[oirl]; } else if(!(icosahedral && irrepd == 5)){ int pgnirl = mgs2(dim, pgvspan, proj, sspg, 0, thresholds->orthogonalization); for(int d = 0; d < irrepd;d++,oirl = nirl){ if(MSYM_SUCCESS != (ret = generateProjectionOperator(1,sopsl,sgc[k][d],perm,ld,lrsops,proj))) goto err; int sgnirl = mgs2(dim, sgd[k][d], proj, sssg, 0, thresholds->orthogonalization); if(MSYM_SUCCESS != (ret = projectLinearlyIndependent(dim, pgnirl, sspg, sgnirl, sssg, thresholds, cmem, mem, ss, &nirl))) goto err; if(nirl - oirl != span[k]){ ret = MSYM_SUBSPACE_ERROR; msymSetErrorDetails("Ortogonal subsubspace of dimension (%d) inconsistent with span (%d) in %s",nirl - oirl,span[k],ct->s[k].name); goto err; } pss[k][d] = &ss[oirl]; } } else { int idim[] = {1,2,2}, sdim[] = {3,4}, ssd = 0; int pgnirl = mgs2(dim, pgvspan, proj, sspg, 0, thresholds->orthogonalization); for(int d = 0; d < 3;d++,oirl = nirl){ if(MSYM_SUCCESS != (ret = generateProjectionOperator(idim[d],sopsl,sgc[k][d],perm,ld,lrsops,proj))) goto err; int sgnirl = mgs2(dim, sgd[k][d], proj, sssg, 0, thresholds->orthogonalization); int id = idim[d]; if(id > 1){ int n = 0; if(MSYM_SUCCESS != (ret = projectLinearlyIndependent(dim, pgnirl, sspg, sgnirl, sssg, thresholds, cmem, mem, sssg, &n))) goto err; sgnirl = n; for(int sd = 0; sd < id;sd++,oirl = nirl){ int sid = sdim[sd]; if(MSYM_SUCCESS != (ret = generateProjectionOperator(1,sopsl,sgc[k][sid],perm,ld,lrsops,proj))) goto err; // sspg, sssg and proj are taken, use mem, and take proj as mem after int ignirl = mgs2(dim, sgd[k][sid], proj, mem, 0, thresholds->orthogonalization); if(MSYM_SUCCESS != (ret = projectLinearlyIndependent(dim, sgnirl, sssg, ignirl, mem, thresholds, cmem, proj, ss, &nirl))) goto err; if(nirl - oirl != span[k]){ debug_printTransform(sgnirl, dim, sssg); ret = MSYM_SUBSPACE_ERROR; msymSetErrorDetails("Ortogonal icosahedral subsubspace of dimension (%d) inconsistent with span (%d) in %s",nirl - oirl,span[k],ct->s[k].name); goto err; } pss[k][ssd] = &ss[oirl]; ssd++; } } else { if(MSYM_SUCCESS != (ret = projectLinearlyIndependent(dim, pgnirl, sspg, sgnirl, sssg, thresholds, cmem, mem, ss, &nirl))) goto err; if(nirl - oirl != span[k]){ debug_printTransform(dim, dim, ss); ret = MSYM_SUBSPACE_ERROR; msymSetErrorDetails("Ortogonal icosahedral subspace of dimension (%d) inconsistent with span (%d) in %s",nirl - oirl,span[k],ct->s[k].name); goto err; } pss[k][d] = &ss[oirl]; ssd++; } } } } //for(int i = 0; i < dim;i++) vlnorm(dim, ss[i]); err: return ret; } msym_error_t generateSubspacesMatrix(msym_point_group_t *pg, msym_permutation_t perm[pg->order], int ld, double (*lrsops)[ld][ld], int span[pg->ct->d], double (*sgc)[5][pg->order], msym_thresholds_t *thresholds, double cmem[pg->order], double pmem[4][perm->p_length*ld][perm->p_length*ld], double (*(*pss)[5])[pg->ct->d], double ss[perm->p_length*ld][perm->p_length*ld]){ msym_error_t ret = MSYM_SUCCESS; int pd = perm->p_length, dim = pd*ld; msym_character_table_t *ct = pg->ct; double (*ctable)[ct->d] = ct->table; double (*projpg)[dim] = pmem[0], (*projsg)[dim] = pmem[1], (*projig)[dim] = pmem[2], (*mem)[dim] = pmem[3]; double trace = 0.0; msym_symmetry_operation_t *sops = pg->sops; int sopsl = pg->order; int icosahedral = MSYM_POINT_GROUP_TYPE_I == pg->type || MSYM_POINT_GROUP_TYPE_Ih == pg->type; memset(ss, 0, dim*sizeof(*ss)); memset(pss, 0, ct->d*sizeof(*pss)); for(int k = 0, oirl = 0, nirl = 0;k < ct->d;k++, oirl = nirl){ int irrepd = ct->s[k].d, pgvspan = irrepd*span[k]; if(pgvspan == 0) continue; for(int s = 0;s < pg->order;s++) cmem[s] = ctable[k][sops[s].cla]; if(MSYM_SUCCESS != (ret = generateProjectionOperator(irrepd,sopsl,cmem,perm,ld,lrsops,projpg))) goto err; if(irrepd == 1){ nirl = mgs2(dim, pgvspan, projpg, ss, oirl, thresholds->orthogonalization); if(nirl - oirl != pgvspan){ debug_printTransform(dim, dim, ss); ret = MSYM_SUBSPACE_ERROR; msymSetErrorDetails("Ortogonal subspace of dimension (%d) inconsistent with span (%d) in %s",nirl - oirl,pgvspan,ct->s[k].name); goto err; } pss[k][0] = &ss[oirl]; } else if(!(icosahedral && irrepd == 5)){ for(int d = 0; d < irrepd;d++,oirl = nirl){ if(MSYM_SUCCESS != (ret = generateProjectionOperator(1,sopsl,sgc[k][d],perm,ld,lrsops,projsg))) goto err; clean_debug_printf("mmlmul %dx%d %d\n",dim,dim,__LINE__); mmlsymmul(dim, projsg, projpg, mem); //mmlmul(dim, dim, projsg, dim, projpg, mem); clean_debug_printf("done mmlmul %d\n",__LINE__); trace = mltrace(dim, mem); mlscale(span[k]/trace, dim, mem, mem); nirl = mgs2(dim, span[k], mem, ss, oirl, thresholds->orthogonalization); if(nirl - oirl != span[k]){ debug_printTransform(dim, dim, ss); ret = MSYM_SUBSPACE_ERROR; msymSetErrorDetails("Ortogonal subsubspace of dimension (%d) inconsistent with span (%d) in %s",nirl - oirl,span[k],ct->s[k].name); goto err; } pss[k][d] = &ss[oirl]; } } else { int idim[] = {1,2,2}, sdim[] = {3,4}, ssd = 0; for(int d = 0; d < 3;d++,oirl = nirl){ if(MSYM_SUCCESS != (ret = generateProjectionOperator(idim[d],sopsl,sgc[k][d],perm,ld,lrsops,projsg))) goto err; clean_debug_printf("mmlmul %d\n",__LINE__); mmlsymmul(dim, projsg, projpg, projig); //mmlmul(dim, dim, projsg, dim, projpg, projig); clean_debug_printf("done mmlmul %d\n",__LINE__); int id = idim[d]; if(id > 1){ for(int sd = 0; sd < id;sd++,oirl = nirl){ int sid = sdim[sd]; if(MSYM_SUCCESS != (ret = generateProjectionOperator(1,sopsl,sgc[k][sid],perm,ld,lrsops,projsg))) goto err; clean_debug_printf("mmlmul %d\n",__LINE__); mmlsymmul(dim, projsg, projig, mem); //mmlmul(dim, dim, projsg, dim, projig, mem); clean_debug_printf("done mmlmul %d\n",__LINE__); trace = mltrace(dim, mem); mlscale(span[k]/trace, dim, mem, mem); // We might have small components in these subspaces nirl = mgs2(dim, span[k], mem, ss, oirl, thresholds->orthogonalization); if(nirl - oirl != span[k]){ debug_printTransform(dim, dim, mem); ret = MSYM_SUBSPACE_ERROR; msymSetErrorDetails("Ortogonal icosahedral subsubspace of dimension (%d) inconsistent with span (%d) in %s",nirl - oirl,span[k],ct->s[k].name); goto err; } pss[k][ssd] = &ss[oirl]; ssd++; } } else { nirl = mgs2(dim, span[k], projig, ss, oirl, thresholds->orthogonalization); if(nirl - oirl != span[k]){ debug_printTransform(dim, dim, ss); ret = MSYM_SUBSPACE_ERROR; msymSetErrorDetails("Ortogonal icosahedral subspace of dimension (%d) inconsistent with span (%d) in %s",nirl - oirl,span[k],ct->s[k].name); goto err; } pss[k][d] = &ss[oirl]; ssd++; } } } } //for(int i = 0; i < dim;i++) vlnorm(dim, ss[i]); err: return ret; } msym_error_t findSplittingFieldSubgroup(msym_point_group_t *pg, int irrep, int sgl, const msym_subgroup_t sg[sgl], msym_thresholds_t *thresholds, const msym_subgroup_t **osg){ msym_error_t ret = MSYM_SUCCESS; *osg = NULL; msym_character_table_t *ct = pg->ct; switch(ct->s[irrep].d){ case 2 : { //2-dimensional switch(pg->type){ case MSYM_POINT_GROUP_TYPE_Cnv : case MSYM_POINT_GROUP_TYPE_Td : { for(int i = 0;i < sgl;i++){ if(sg[i].type == MSYM_POINT_GROUP_TYPE_Cs){ *osg = &sg[i]; break; } } break; } case MSYM_POINT_GROUP_TYPE_Dn : case MSYM_POINT_GROUP_TYPE_Dnd : case MSYM_POINT_GROUP_TYPE_Dnh : case MSYM_POINT_GROUP_TYPE_O : case MSYM_POINT_GROUP_TYPE_Oh : { for(int i = 0;i < sgl;i++){ if(sg[i].type == MSYM_POINT_GROUP_TYPE_Cn && sg[i].n == 2){ int h = 0; for(int j = 0;j < sg[i].order;j++){ msym_symmetry_operation_t *sop = sg[i].sops[j]; if(sop->type == PROPER_ROTATION && sop->order == 2 && sop->orientation == HORIZONTAL){ h = 1; break; } } if(!h){ *osg = &sg[i]; break; } } } break; } case MSYM_POINT_GROUP_TYPE_Cn : case MSYM_POINT_GROUP_TYPE_Cnh : case MSYM_POINT_GROUP_TYPE_T : case MSYM_POINT_GROUP_TYPE_Th : { ret = MSYM_SUBSPACE_ERROR; msymSetErrorDetails("Cannot construct splitting field, point group %s has complex characters in symmetry species %s",pg->name, ct->s[irrep].name); goto err; } default: break; } break; } case 3 :{ //3-dimensional switch(pg->type){ case MSYM_POINT_GROUP_TYPE_T : case MSYM_POINT_GROUP_TYPE_Td : case MSYM_POINT_GROUP_TYPE_Th : case MSYM_POINT_GROUP_TYPE_O : case MSYM_POINT_GROUP_TYPE_Oh : case MSYM_POINT_GROUP_TYPE_I : case MSYM_POINT_GROUP_TYPE_Ih : { for(int i = 0;i < sgl;i++){ if(sg[i].type == MSYM_POINT_GROUP_TYPE_Dn && sg[i].n == 2){ int h = 1; for(int j = 0; j < sg[i].order; j++){ msym_symmetry_operation_t *sop = sg[i].sops[j]; if(!(sop->orientation == HORIZONTAL || sop->orientation == NONE)){ h = 0; break; } } if(h){ *osg = &sg[i]; break; } } } } default: break; } break; } case 4 : { //4-dimensional if(!(MSYM_POINT_GROUP_TYPE_I == pg->type || MSYM_POINT_GROUP_TYPE_Ih == pg->type)){ ret = MSYM_SUBSPACE_ERROR; msymSetErrorDetails("Invalid irrep dimension (4) when getting splitting field subgroup for non icosahedral point group %s", pg->name); goto err; } for(int i = 0;i < sgl;i++){ if(sg[i].type == MSYM_POINT_GROUP_TYPE_Dn && sg[i].n == 2){ *osg = &sg[i]; break; } } break; } case 5 : { //5-dimensional if(!(MSYM_POINT_GROUP_TYPE_I == pg->type || MSYM_POINT_GROUP_TYPE_Ih == pg->type)){ ret = MSYM_SUBSPACE_ERROR; msymSetErrorDetails("Invalid irrep dimension (5) when getting splitting field subgroup for non icosahedral point group %s", pg->name); goto err; } for(int i = 0;i < sgl;i++){ if(sg[i].type == MSYM_POINT_GROUP_TYPE_Dn && sg[i].n == 5){ *osg = &sg[i]; } } break; } default : break; } if(*osg == NULL){ ret = MSYM_SUBSPACE_ERROR; msymSetErrorDetails("Could not find splitting filed subgroup in dimension %d for point group %s symmetry species %s",ct->s[irrep].d, pg->name, ct->s[irrep].name); } err: return ret; } #define PHI 1.618033988749894848204586834 msym_error_t getSplittingFieldCharacters(msym_point_group_t *pg, const msym_subgroup_t *sg, double (*c)[pg->order], int *cd){ msym_error_t ret = MSYM_SUCCESS; int e = 0; for(int i = 0;i < 5;i++){cd[i] = 1;} if((sg->type == MSYM_POINT_GROUP_TYPE_Cs) || (sg->type == MSYM_POINT_GROUP_TYPE_Cn && sg->n == 2)){ int faxis = 0; memset(c, 0, sizeof(double[pg->order])); for(int s = 0;s < pg->order && !(e && faxis);s++){ for(int i = 0;i < sg->order;i++){ if(&pg->sops[s] != sg->sops[i]) continue; if(pg->sops[s].type == IDENTITY){ e = 1; c[0][s] = c[1][s] = 1; if(faxis) break; } else { faxis = 1; c[0][s] = 1; c[1][s] = -1; if(e) break; } } } } else if(sg->type == MSYM_POINT_GROUP_TYPE_Dn && sg->n == 2){ int index = 0; double d2c[4][3] = { [0] = { 1, -1, -1}, [1] = {-1, -1, 1}, [2] = {-1, 1, -1}, [3] = { 1, 1, 1} }; memset(c, 0, sizeof(double[3][pg->order])); for(int s = 0;s < pg->order && !((index == 3) && e);s++){ for(int i = 0;i < sg->order;i++){ if(&pg->sops[s] != sg->sops[i]) continue; if(index == 3 && e) break; if(pg->sops[s].type == IDENTITY){ e = 1; c[0][s] = c[1][s] = c[2][s] = c[3][s] = 1; if(index == 3) break; } else { c[0][s] = d2c[0][index]; c[1][s] = d2c[1][index]; c[2][s] = d2c[2][index]; c[3][s] = d2c[3][index]; index++; if(index == 3 && e) break; } } } } else if (sg->type == MSYM_POINT_GROUP_TYPE_Dn && sg->n == 5){ int sfound = 0, found = 0; msym_subgroup_t *ssg = NULL; for(int i = 0;i < 2; i++){ if(sg->generators[i]->type == MSYM_POINT_GROUP_TYPE_Cn && sg->generators[i]->order == 2){ ssg = sg->generators[i]; break; } } if(NULL == ssg){ ret = MSYM_INVALID_CHARACTER_TABLE; msymSetErrorDetails("Cannot find C2 subgroup of D5 %s"); goto err; } cd[1] = cd[2] = 2; double d5c[2][5]= { [0] = {1, 1/PHI, -PHI}, [1] = {1, -PHI, 1/PHI} }; double d2c[5] = {1,0,0}; double c2c[5] = {1,-1}; for(int s = 0;s < pg->order && (found < 10 || !sfound);s++){ for(int i = 0;i < ssg->order && !sfound;i++){ if(&pg->sops[s] != ssg->sops[i]) continue; if(pg->sops[s].type == PROPER_ROTATION && pg->sops[s].order == 2){ c[3][s] = c2c[0]; c[4][s] = c2c[1]; break; } } for(int i = 0;i < sg->order;i++){ if(&pg->sops[s] != sg->sops[i]) continue; if(pg->sops[s].type == IDENTITY){ c[0][s] = c[3][s] = c[4][s] = 1; c[1][s] = c[2][s] = 2; found++; } else if (pg->sops[s].type == PROPER_ROTATION && pg->sops[s].order == 5) { int index = (pg->sops[s].power >> 1) & 1; //2 and 3 -> index 1 c[0][s] = d5c[index][0]; c[1][s] = d5c[index][1]; c[2][s] = d5c[index][2]; found++; } else if(pg->sops[s].type == PROPER_ROTATION && pg->sops[s].order == 2){ c[0][s] = d2c[0]; c[1][s] = d2c[1]; c[2][s] = d2c[2]; found++; } } } } else { ret = MSYM_INVALID_CHARACTER_TABLE; msymSetErrorDetails("Cannot determine splitting field characters of subgroup %s",sg->name); goto err; } err: return ret; } msym_error_t projectLinearlyIndependent(int dim, int vdim, double v[vdim][dim], int udim, double u[udim][dim], msym_thresholds_t *thresholds, double cmem[dim], double mem[dim][dim], double o[dim][dim], int *oirl){ msym_error_t ret = MSYM_SUCCESS; memset(mem, 0, dim*sizeof(*mem)); for(int vd = 0; vd < vdim;vd++){ for(int ud = 0; ud < udim; ud++){ double c = vldot(dim, v[vd], u[ud]); vlscale(c, dim, u[ud], cmem); vladd(dim, cmem, mem[vd], mem[vd]); } } int mdim = vdim > udim ? udim : vdim; int nirl = mgs2(dim, mdim, mem, o, *oirl, thresholds->orthogonalization/sqrt(dim)); for(int i = *oirl; i < nirl;i++) vlnorm(dim, o[i]); *oirl = nirl; return ret; } msym_error_t generateSplittingOperation(msym_point_group_t *pg, msym_permutation_t perm[pg->order], int ld, double (*lrsops)[ld][ld], int sgl, const msym_subgroup_t *sg, const msym_subgroup_t **rsg, double rsop[perm->p_length*ld][perm->p_length*ld], msym_symmetry_operation_t **osop){ msym_error_t ret = MSYM_SUCCESS; int pd = perm->p_length, dim = pd*ld; msym_symmetry_operation_t *sop = NULL; switch(pg->type){ case MSYM_POINT_GROUP_TYPE_Cs : case MSYM_POINT_GROUP_TYPE_Ci : case MSYM_POINT_GROUP_TYPE_T : case MSYM_POINT_GROUP_TYPE_Td : case MSYM_POINT_GROUP_TYPE_Th : case MSYM_POINT_GROUP_TYPE_O : case MSYM_POINT_GROUP_TYPE_Oh : break; case MSYM_POINT_GROUP_TYPE_Cnv : case MSYM_POINT_GROUP_TYPE_Dn : case MSYM_POINT_GROUP_TYPE_Dnh : case MSYM_POINT_GROUP_TYPE_Dnd : { if(pg->n > 2){ sop = pg->primary; if(NULL == sop){ ret = MSYM_SUBSPACE_ERROR; msymSetErrorDetails("Cannot determine splitting operation for point group %s", pg->name); goto err; } } break; } case MSYM_POINT_GROUP_TYPE_I : case MSYM_POINT_GROUP_TYPE_Ih : { for(int i = 0;i < sgl;i++){ int f = 0; for(f = 0; f < pg->ct->d && &sg[i] != rsg[f];f++); if(f == pg->ct->d && MSYM_POINT_GROUP_TYPE_Dn == sg[i].type && sg[i].n == 5){ msym_symmetry_operation_t **sgsops = sg[i].sops; for(int j = 0; j < sg[i].order; j++){ if(PROPER_ROTATION == sgsops[j]->type && 5 == sgsops[j]->order && 1 == sgsops[j]->power){ sop = sgsops[j]; break; } } break; } } if(NULL == sop){ ret = MSYM_SUBSPACE_ERROR; msymSetErrorDetails("Cannot determine splitting operation for point group %s", pg->name); goto err; } break; } case MSYM_POINT_GROUP_TYPE_Cn : case MSYM_POINT_GROUP_TYPE_Cnh : if(2 == pg->n) break; // fallthrough case MSYM_POINT_GROUP_TYPE_Sn : case MSYM_POINT_GROUP_TYPE_K : case MSYM_POINT_GROUP_TYPE_Kh : ret = MSYM_SUBSPACE_ERROR; msymSetErrorDetails("Point group %s has no splitting operation", pg->name); goto err; } *osop = sop; if(NULL != sop){ int s = (int) (sop - pg->sops); memset(rsop, 0, dim*sizeof(*rsop)); for(int pi = 0, po = 0;pi < pd;pi++, po += ld){ int pr = perm[s].p[pi]*ld; for(int li = 0;li < ld;li++){ int r = pr + li; for(int lj = 0;lj < ld;lj++){ rsop[r][po+lj] += lrsops[s][li][lj]; } } } } err: return ret; } msym_error_t determinePartnerFunctionsSearch(msym_point_group_t *pg, msym_permutation_t perm[pg->order], int ld, double (*lrsops)[ld][ld], int dim, int sd, int sspan, double (*sdss)[dim], int sdvi[5], double (*split)[dim], double (*mem)[dim], int *li, double (*pf)[dim]){ msym_error_t ret = MSYM_SUCCESS; int pd = perm->p_length; //need at least 3 dimensions double *f = mem[0]; double *proj = mem[1]; if(sd == 1){ memcpy(pf, sdss, sspan*sizeof(*pf)); return ret; } if(dim < 2){ ret = MSYM_SUBSPACE_ERROR; msymSetErrorDetails("Unexpected dimension %d < 2 when determining partner functions", dim); goto err; } memset(pf, 0, dim*sizeof(*pf)); for(int i = 0;i < sspan;i++){ int found[5] = {1,0,0,0,0}; int s = 0; for(s = 0; s < pg->order;s++){ int df = 0; for(int d = 0; d < sd; d++) df += found[d]; if(df == sd) break; if(IDENTITY == pg->sops[s].type) continue; // build symmetry operation memset(split, 0, dim*sizeof(*split)); for(int pi = 0, po = 0;pi < pd;pi++, po += ld){ int pr = perm[s].p[pi]*ld; for(int li = 0;li < ld;li++){ int r = pr + li; for(int lj = 0;lj < ld;lj++){ split[r][po+lj] += lrsops[s][li][lj]; } } } memcpy(pf[i*sd], sdss[i], dim*sizeof(*sdss[i])); mvlmul(dim, dim, split, sdss[i], f); for(int d = 1; d < sd; d++){ if(found[d]) continue; int pfi = i*sd+d; for(int j = 0; j < sspan;j++){ int pi = sdvi[d] + j; vlproj(dim, f, sdss[pi], proj); vladd(dim, proj, pf[pfi], pf[pfi]); } if(vlabs(dim, pf[pfi]) >= PARTNER_THRESHOLD){ vlnorm(dim, pf[pfi]); found[d] = 1; } } } if(s == pg->order){ ret = MSYM_SUBSPACE_ERROR; msymSetErrorDetails("Could not find partner functions in %d dimensional space", sd); goto err; } } err: return ret; } msym_error_t determinePartnerFunctions(msym_point_group_t *pg, int r, msym_permutation_t perm[pg->order], int ld, double (*lrsops)[ld][ld], int dim, int sd, int sspan, double (*sdss)[dim], int sdvi[5], double (*split)[dim], msym_symmetry_operation_t *splitop, double (*mem)[dim], int *li, double (*pf)[dim]){ msym_error_t ret = MSYM_SUCCESS; if(sd/r == 1){ memcpy(pf, sdss, r*sspan*sizeof(*pf)); return ret; } if(NULL == splitop) return determinePartnerFunctionsSearch(pg, perm, ld, lrsops, dim, sd, sspan, sdss, sdvi, split, mem, li, pf); //need at least 3 dimensions double *f = mem[0]; double *proj = mem[1]; if(dim < 2){ ret = MSYM_SUBSPACE_ERROR; msymSetErrorDetails("Unexpected dimension %d < 2 when determining partner functions", dim); goto err; } memset(pf, 0, dim*sizeof(*pf)); for(int i = 0;i < sspan;i++){ memcpy(pf[i*sd], sdss[i], dim*sizeof(*sdss[i])); mvlmul(dim, dim, split, sdss[i], f); for(int d = 1; d < sd; d++){ int pfi = i*sd+d; for(int j = 0; j < sspan;j++){ int pi = sdvi[d] + j; vlproj(dim, f, sdss[pi], proj); vladd(dim, proj, pf[pfi], pf[pfi]); } if(vlabs(dim, pf[pfi]) < PARTNER_THRESHOLD){ ret = MSYM_SUBSPACE_ERROR; msymSetErrorDetails("Could not determine partner functions in %d dimensional space", sd); goto err; } vlnorm(dim, pf[pfi]); } } err: return ret; } msym_error_t symmetrySpeciesComponents(msym_point_group_t *pg, int srsl, msym_subrepresentation_space_t *srs, int basisl, msym_basis_function_t *basis, double *wf, double *s){ msym_error_t ret = MSYM_SUCCESS; if(srsl != pg->ct->d){ ret = MSYM_SUBSPACE_ERROR; msymSetErrorDetails("Unexpected subspace length (expected %d got %d)",pg->ct->d, srsl); goto err; } for(int k = 0;k < srsl;k++){ double kcomp = 0.0; for(int s = 0;s < srs[k].salcl;s++){ msym_salc_t *salc = &srs[k].salc[s]; double (*space)[salc->fl] = (double (*)[salc->fl]) salc->pf; for(int d = 0;d < salc->d;d++){ double c = 0.0; for(int j = 0; j < salc->fl;j++){ c += wf[salc->f[j] - basis]*space[d][j]; } kcomp += SQR(c); } } s[k] = sqrt(kcomp); } err: return ret; } msym_error_t generateSubrepresentationSpaces(msym_point_group_t *pg, int sgl, const msym_subgroup_t sg[sgl], int esl, msym_equivalence_set_t *es, msym_permutation_t **perm, int basisl, msym_basis_function_t basis[basisl], msym_element_t *elements, msym_equivalence_set_t **esmap, msym_thresholds_t *thresholds, int *osrsl, msym_subrepresentation_space_t **osrs, msym_basis_function_t ***osrsbf, int **ospan){ msym_error_t ret = MSYM_SUCCESS; msym_character_table_t *ct = pg->ct; int lmax = -1, nmax = 0, eslmax = 0; enum _msym_basis_type ftype = basis[0].type; for(int i = 0;i < basisl;i++){ if(basis[i].type != ftype) {nmax = -1; break;} lmax = basis[i].f.rsh.l > lmax ? basis[i].f.rsh.l : lmax; nmax = basis[i].f.rsh.n > nmax ? basis[i].f.rsh.n : nmax; } for(int i = 0;i < esl;i++){ eslmax = es[i].length > eslmax ? es[i].length : eslmax; } if(lmax < 0 || nmax < 1){ if(nmax == -1) msymSetErrorDetails("Basis functions are not of the same type"); else msymSetErrorDetails("Invalid sperical harmonics quantum numbers"); ret = MSYM_INVALID_BASIS_FUNCTIONS; return ret; } else if (ftype != MSYM_BASIS_TYPE_REAL_SPHERICAL_HARMONIC){ msymSetErrorDetails("Basis function type not supported"); ret = MSYM_INVALID_BASIS_FUNCTIONS; return ret; } int projm = (2*lmax+1)*eslmax; double (*pmem)[projm][projm] = calloc(7, sizeof(*pmem)); // Memory for calculating projection operatorsle if(NULL == pmem){ ret = MSYM_MEMORY_ERROR; msymSetErrorDetails("Could not allocate %ld bytes of memory for SALC generation", 7*sizeof(*pmem)); return ret; } double (*bspan)[ct->d] = calloc(lmax+1, sizeof(*bspan)); // span of individual basis functions double (*pspan)[ct->d] = calloc(esl, sizeof(*pspan)); // span of permutation operators double *rspan = calloc(ct->d, sizeof(*rspan)); // total direct product symmetrized basis double *dspan = calloc(ct->d, sizeof(*dspan)); // decoposed total span of symmetrized basis (double) double (*sdssmem)[projm] = pmem[1]; double (*dssmem)[projm] = pmem[2]; double (*pssmem)[pg->order] = pmem[3]; double (*ssmem)[projm] = pmem[4]; double (*pfmem)[projm] = pmem[5]; double (*splitmem)[projm] = pmem[6]; double *cmem = calloc(pg->order*(2*lmax+1), sizeof(*cmem)); // Don't change this to elsmax*(2*lmax+1) needed for sops double (*(*sspmem)[5])[pg->order*(lmax+1)] = calloc(ct->d, sizeof(*sspmem)); double (**psspmem)[pg->order] = calloc(ct->d, sizeof(*psspmem)); double (*(*lssp)[ct->d])[2*lmax+1] = calloc(lmax+1, sizeof(*lssp)); double *mspan = calloc(ct->d, sizeof(double)); // span decomposition memory double (*sgc)[5][pg->order] = calloc(ct->d,sizeof(*sgc)); const msym_subgroup_t **rsg = calloc(ct->d, sizeof(*rsg)); int (*sgd)[5] = calloc(ct->d,sizeof(*sgd)); int *ispan = calloc(ct->d, sizeof(*ispan)); // decoposed total span of symmetrized basis (int) int (*iespan)[lmax+1][ct->d] = calloc(esl, sizeof(*iespan)); int (*ipspan)[ct->d] = calloc(esl, sizeof(*ipspan)); // span of permutation operators int (*ibspan)[ct->d] = calloc(lmax+1, sizeof(*ibspan)); int *isalc = calloc(ct->d, sizeof(*isalc)); // number of added salcs to irrep int *esnmax = calloc(esl, sizeof(*esnmax)); // max n in eqset msym_basis_function_t *(*esbfmap)[pg->order][nmax+1][lmax+1][2*lmax+1] = calloc(esl,sizeof(*esbfmap)); msym_basis_function_t *(*srsbf) = calloc(basisl, sizeof(*srsbf)); int (*srsbfmap)[nmax+1][lmax+1] = calloc(esl,sizeof(*srsbfmap)); rsh_representations_t *lts = calloc(lmax+1,sizeof(*lts)); // transformation matrices for rsh basis functions int (*les)[lmax+1] = calloc(esl, sizeof(*les)); // number of l-type basis functions in each ES msym_basis_function_t dbf = {.type = ftype}; double (*ctable)[ct->d] = ct->table; msym_subrepresentation_space_t *srs = calloc(ct->d, sizeof(*srs)); /* determine number of l-type basis functions in each ES */ for(int o = 0;o < basisl;o++){ les[esmap[basis[o].element - elements] - es][basis[o].f.rsh.l] += basis[o].f.rsh.m == 0; } if(MSYM_SUCCESS != (ret = generateBasisRepresentations(pg->order+1, pg->order, pg->sops, lmax, lts))) goto err; for(int k = 0; k < ct->d;k++){ if(ct->s[k].d > 1){ if(MSYM_SUCCESS != (ret = findSplittingFieldSubgroup(pg, k, sgl, sg, thresholds, &rsg[k]))) goto err; if(MSYM_SUCCESS != (ret = getSplittingFieldCharacters(pg, rsg[k], sgc[k], sgd[k]))) goto err; //TODO: remove sgd } } for(int o = 0;o < basisl;o++){ msym_basis_function_t *bf = &basis[o]; int ei = (int)(bf->element - elements), esi = 0; msym_equivalence_set_t *e = esmap[ei]; for(esi = 0;esi < e->length && e->elements[esi] != bf->element;esi++){}; //could improve perf with a map here if(esi >= e->length){ ret = MSYM_INVALID_BASIS_FUNCTIONS; msymSetErrorDetails("Basis function does not map to any equivalence set"); goto err; } if(bf->f.rsh.n > esnmax[e - es]) esnmax[e - es] = bf->f.rsh.n; esbfmap[e - es][esi][bf->f.rsh.n][bf->f.rsh.l][bf->f.rsh.m+bf->f.rsh.l] = bf; } int srsbfi = 0; for(int i = 0;i < esl;i++){ for(int n = 0;n <= nmax;n++){ for(int l = 0;l <= lmax;l++){ srsbfmap[i][n][l] = srsbfi; for(int e = 0;e < es[i].length;e++){ msym_basis_function_t *lbf = esbfmap[i][e][n][l][0]; for(int m = -l;m <= l;m++){ msym_basis_function_t *bf = esbfmap[i][e][n][l][m+l]; if((NULL == bf && NULL != lbf) || (NULL == lbf && NULL != bf)) { lbf = NULL == lbf ? bf : lbf; ret = MSYM_INVALID_BASIS_FUNCTIONS; msymSetErrorDetails("Found basis function %s but function where m = %d is missing on element %d of equivalence set %d",lbf->name,m,e,i); goto err; } if(NULL != bf){ lbf = bf; srsbf[srsbfi] = bf; srsbfi++; } } } //when this is moved to a separate function it can be used and availability check (replace esbfmap) //if(srsbfmap[i][n][l] == srsbfi) srsbfmap[i][n][l] = -1; } } } if(srsbfi != basisl){ ret = MSYM_SUBSPACE_ERROR; msymSetErrorDetails("Unexpected number of basis functions in subrepresentation map (expected %d, got %d)",basisl, srsbfi); goto err; } /* calculate span of irreducible representations for basis functions and permutations */ for(int s = 0; s < pg->order;s++){ for(int l = 0; l <= lmax;l++){ dbf.f.rsh.l = l; //TODO: function type based double c = symmetryOperationCharacter(&pg->sops[s], &dbf); for(int k = 0;k < ct->d;k++){ bspan[l][k] += c*ctable[k][pg->sops[s].cla]; } } for(int i = 0;i < esl;i++){ int uma = 0; for(int j = 0; j < perm[i][s].c_length;j++) uma += perm[i][s].c[j].l == 1; //this is why we loop over irreps twice for(int k = 0;k < ct->d;k++){ pspan[i][k] += uma*ctable[k][pg->sops[s].cla]; } } } /* scale reducible representations */ for(int k = 0;k < ct->d;k++){ double r = ct->s[k].r; if(r > 1){ for(int l = 0; l <= lmax;l++) bspan[l][k] /= r; for(int i = 0;i < esl;i++) pspan[i][k] /= r; } } /* scale basis span, calculate basis function transforms and symmetry species vectors */ for(int l = 0;l <= lmax;l++){ int d = lts[l].d; double (*lproj)[d] = pmem[0]; double (*lscal)[d] = pmem[1]; vlscale(1.0/pg->order, ct->d, bspan[l], bspan[l]); double (*st)[d][d] = lts[l].t; memset(st[pg->order], 0, sizeof(double[d][d])); for(int k = 0, oirl = 0, nirl = 0;k < ct->d;k++, oirl = nirl){ int vspan = ct->s[k].d*((int) round(bspan[l][k])); if(vspan == 0) continue; ibspan[l][k] = (int) round(bspan[l][k]); memset(lproj, 0, sizeof(double[d][d])); for(int s = 0;s < pg->order;s++){ double c = ctable[k][pg->sops[s].cla]; if(c != 0){ mlscale(ctable[k][pg->sops[s].cla], d, st[s], lscal); mladd(d, lscal, lproj, lproj); } } nirl = mgs2(d, vspan,lproj, st[pg->order], oirl, thresholds->orthogonalization); if(nirl - oirl != vspan){ debug_printTransform(d, d, st[pg->order]); ret = MSYM_SUBSPACE_ERROR; msymSetErrorDetails("Ortogonal subspace of dimension (%d) inconsistent with span (%d) in %s",nirl - oirl,vspan,ct->s[k].name); goto err; } lssp[l][k] = &st[pg->order][oirl]; } for(int i = 0; i < d;i++) vlnorm(d, st[pg->order][i]); } /* scale permutation span and calculate total basis function span on each ES */ for(int i = 0;i < esl;i++){ vlscale(1.0/pg->order, ct->d, pspan[i], pspan[i]); for(int l = 0; l <= lmax;l++){ if(les[i][l] == 0) continue; les[i][l] /= es[i].length; memset(dspan, 0, sizeof(double[ct->d])); for(int k = 0;k < ct->d;k++){ for(int j = 0;j < ct->d && round(pspan[i][k]) > 0;j++){ directProduct(ct->d, ctable[k], ctable[j], mspan); vlscale(pspan[i][k]*bspan[l][j], ct->d, mspan, mspan); vladd(ct->d, mspan, dspan, dspan); } } decomposeRepresentation(ct, dspan, mspan); for(int k = 0;k < ct->d;k++){ iespan[i][l][k] = (int)round(mspan[k]/ct->s[k].r); ispan[k] += les[i][l]*iespan[i][l][k]; } } for(int k = 0;k < ct->d;k++) ipspan[i][k] = (int)round(pspan[i][k]); } for(int k = 0;k < ct->d;k++){ srs[k].s = k; srs[k].salcl = ispan[k]; srs[k].salc = calloc(srs[k].salcl, sizeof(msym_salc_t)); } clean_debug_printf("decomposed %d\n", ct->d); for(int prk = 0;prk < ct->d;prk++){ if(prk < ct->d - 1) clean_debug_printf("%d%s + ", ispan[prk], ct->s[prk].name); else clean_debug_printf("%d%s\n", ispan[prk], ct->s[prk].name); } int dbasisl = 0; for(int k = 0;k < ct->d;k++){ dbasisl += ct->s[k].d*ispan[k]; } if(dbasisl != basisl){ ret = MSYM_SUBSPACE_ERROR; msymSetErrorDetails("Unexpected number of basis functions in decomposition (expected %d, got %d)",basisl,dbasisl); goto err; } for(int i = 0;i < esl;i++){ for(int l = 0;l <= lmax;l++){ if(les[i][l] == 0) continue; int ld = lts[l].d, esd = es[i].length, dim = esd*ld, li = 0; double (*lrsops)[ld][ld] = lts[l].t; double (*(*ssp)[5])[dim] = sspmem; double (*ss)[dim] = ssmem; double (**pssp)[esd] = psspmem; double (*pss)[esd] = pssmem; double (*split)[dim] = splitmem; msym_symmetry_operation_t *splitop = NULL; clean_debug_printf("e decomposed %d\n", ct->d); for(int prk = 0;prk < ct->d;prk++){ if(prk < ct->d - 1) clean_debug_printf("%d%s + ", iespan[i][l][prk], ct->s[prk].name); else clean_debug_printf("%d%s\n", iespan[i][l][prk], ct->s[prk].name); } decomposeSubRepresentation(pg, rsg, sgc, iespan[i][l], sgd); if(MSYM_SUCCESS != (ret = generateSplittingOperation(pg, perm[i], ld, lrsops, sgl, sg, rsg, split, &splitop))) goto err; if(MSYM_SUCCESS != (ret = generateSubspaces(pg, perm[i], ld, lrsops, iespan[i][l], sgc, sgd, thresholds, cmem, pmem, ssp, ss))) goto err; // Must be done after generateSubspaces since memory overlaps with pss for icosahedral groups if(MSYM_SUCCESS != (ret = generatePermutationSubspaces(pg, perm[i], ipspan[i], thresholds, pmem, pssp, pss))) goto err; for(int pk = 0;pk < ct->d;pk++){ int pvspan = ipspan[i][pk]*ct->s[pk].d; if(pvspan == 0) continue; for(int lk = 0;lk < ct->d;lk++){ int lvspan = ibspan[l][lk]*ct->s[lk].d, vspan = pvspan*lvspan; if(lvspan == 0) continue; double (*dss)[dim] = dssmem; kron2(pvspan, esd, pssp[pk], lvspan, ld, lssp[l][lk], dss); directProduct(ct->d, ctable[pk], ctable[lk], rspan); vlscale(pspan[i][pk]*bspan[l][lk], ct->d, rspan, rspan); decomposeRepresentation(ct, rspan, mspan); for(int dk = 0; dk < ct->d; dk++){ int sspan = (int) round(mspan[dk]/ct->s[dk].r); if(sspan == 0) continue; double (*sdss)[dim] = sdssmem; int sd = ct->s[dk].d; int sdvi[5] = {-1,-1,-1,-1,-1}; for(int d = 0, oirl = 0, nirl = 0; d < sd;d++, oirl = nirl){ if(MSYM_SUCCESS != (ret = projectLinearlyIndependent(dim, vspan, dss, iespan[i][l][dk], ssp[dk][d], thresholds, cmem, pmem[0], sdss, &nirl))) goto err; int sdvl = nirl - oirl; sdvi[d] = oirl; if(sdvl != sspan){ debug_printTransform(vspan, dim, dss); ret = MSYM_SUBSPACE_ERROR; msymSetErrorDetails("Linear projection subspace of dimension (%d) inconsistent with span (%d) in %s component %d",sdvl,sspan,ct->s[dk].name,d); goto err; } } double (*pf)[dim] = pfmem; if(MSYM_SUCCESS != (ret = determinePartnerFunctions(pg, ct->s[dk].r, perm[i], ld, lrsops, dim, sd, sspan, sdss, sdvi, split, splitop, pmem[0], &li, pf))) goto err; for(int si = 0, pfi = 0; si < sspan;si++){ for(int n = l+1; n <= esnmax[i];n++){ if(esbfmap[i][0][n][l][0] == NULL) continue; if(isalc[dk] >= ispan[dk]){ ret = MSYM_SUBSPACE_ERROR; msymSetErrorDetails("Exceeded calculated number of SALCs %d >= %d",isalc[dk],ispan[dk]); goto err; } msym_salc_t *salc = &srs[dk].salc[isalc[dk]]; salc->d = sd; // Add basis function and permutation irrep here double (*salcpf)[dim] = calloc(salc->d,sizeof(*salcpf)); memcpy(salcpf, pf[pfi], sd*sizeof(*salcpf)); salc->pf = (double*) salcpf; salc->fl = dim; salc->f = &srsbf[srsbfmap[i][n][l]]; isalc[dk]++; } pfi += sd; } } } } } } debug_printSubspace(ct,ct->d,srs); *ospan = ispan; *osrsl = ct->d; *osrs = srs; *osrsbf = srsbf; free(pmem); free(bspan); free(pspan); free(rspan); free(dspan); free(mspan); free(cmem); free(iespan); free(ipspan); free(ibspan); free(sspmem); free(psspmem); free(lssp); free(rsg); free(sgc); free(sgd); free(isalc); free(esnmax); free(esbfmap); for(int l = 0;l <= lmax;l++){ free(lts[l].t); } free(lts); free(les); free(srsbfmap); return ret; err: free(pmem); free(bspan); free(pspan); free(rspan); free(dspan); free(mspan); free(cmem); free(iespan); free(ipspan); free(ibspan); free(sspmem); free(psspmem); free(lssp); free(rsg); free(sgc); free(sgd); free(ispan); free(isalc); free(esnmax); free(esbfmap); for(int l = 0;l <= lmax;l++){ free(lts[l].t); } free(lts); free(les); free(srsbfmap); for(int k = 0;k < ct->d;k++){ for(int i = 0;i < srs[k].salcl;i++){ free(srs[k].salc[i].pf); } free(srs[k].salc); } free(srs); free(srsbf); return ret; } msym_error_t generateSubrepresentationSpacesLowMem(msym_point_group_t *pg, int sgl, const msym_subgroup_t sg[sgl], int esl, msym_equivalence_set_t *es, msym_permutation_t **perm, int basisl, msym_basis_function_t basis[basisl], msym_element_t *elements, msym_equivalence_set_t **esmap, msym_thresholds_t *thresholds, int *osrsl, msym_subrepresentation_space_t **osrs, msym_basis_function_t ***osrsbf, int **ospan){ msym_error_t ret = MSYM_SUCCESS; msym_character_table_t *ct = pg->ct; int lmax = -1, nmax = 0; enum _msym_basis_type ftype = basis[0].type; for(int i = 0;i < basisl;i++){ if(basis[i].type != ftype) {nmax = -1; break;} lmax = basis[i].f.rsh.l > lmax ? basis[i].f.rsh.l : lmax; nmax = basis[i].f.rsh.n > nmax ? basis[i].f.rsh.n : nmax; } if(lmax < 0 || nmax < 1){ if(nmax == -1) msymSetErrorDetails("Basis functions are not of the same type"); else msymSetErrorDetails("Invalid sperical harmonics quantum numbers"); ret = MSYM_INVALID_BASIS_FUNCTIONS; return ret; } else if (ftype != MSYM_BASIS_TYPE_REAL_SPHERICAL_HARMONIC){ msymSetErrorDetails("Basis function type not supported"); ret = MSYM_INVALID_BASIS_FUNCTIONS; return ret; } int projm = (2*lmax+1)*pg->order; double (*bspan)[ct->d] = calloc(lmax+1, sizeof(*bspan)); // span of individual basis functions double (*pspan)[ct->d] = calloc(esl, sizeof(*pspan)); // span of permutation operators double (*lspan)[ct->d] = calloc(esl, sizeof(*lspan)); // total span of basis function on each ES double *rspan = calloc(ct->d, sizeof(*rspan)); // total direct product symmetrized basis double *dspan = calloc(ct->d, sizeof(*dspan)); // decoposed total span of symmetrized basis (double) double *mspan = calloc(ct->d, sizeof(double)); // span decomposition memory double (*mproj)[projm] = calloc(projm, sizeof(*mproj)); // projection operator memory double (*mscal)[projm] = calloc(projm, sizeof(*mscal)); // projection scaling memory double (*mpih)[projm] = calloc(projm, sizeof(*mpih)); // icosahedral projection memory double (*mperm)[pg->order] = calloc(pg->order, sizeof(*mperm)); // permutation memory double (*morth)[pg->order] = calloc(pg->order, sizeof(*morth)); // permutation orthoginalization memory double (*mbasis)[projm] = calloc(basisl, sizeof(*mbasis)); // basis function coefficients double (*mdec)[projm] = calloc(basisl, sizeof(*mdec)); // directo product decomposition memory double (*sgc)[5][pg->order] = calloc(ct->d,sizeof(*sgc)); const msym_subgroup_t **rsg = calloc(ct->d, sizeof(*rsg)); double *mdcomp = NULL; double *mdproj = NULL; int *mdfound = NULL; int (*sgd)[5] = calloc(ct->d,sizeof(*sgd)); int *ispan = calloc(ct->d, sizeof(int)); // decoposed total span of symmetrized basis (int) int *isalc = calloc(ct->d, sizeof(int)); // number of added salcs to irrep int *esnmax = calloc(esl, sizeof(int)); // max n in eqset msym_basis_function_t *(*esbfmap)[pg->order][nmax+1][lmax+1][2*lmax+1] = calloc(esl,sizeof(*esbfmap)); msym_basis_function_t *(*srsbf) = calloc(basisl, sizeof(*srsbf)); int (*srsbfmap)[nmax+1][lmax+1] = calloc(esl,sizeof(*srsbfmap)); rsh_representations_t *lts = calloc(lmax+1,sizeof(*lts)); // transformation matrices for rsh basis functions int (*les)[lmax+1] = calloc(esl, sizeof(*les)); // number of l-type basis functions in each ES msym_basis_function_t dbf = {.type = ftype}; double (*ctable)[ct->d] = ct->table; msym_subrepresentation_space_t *srs = calloc(ct->d, sizeof(*srs)); /* determine number of l-type basis functions in each ES */ for(int o = 0;o < basisl;o++){ les[esmap[basis[o].element - elements] - es][basis[o].f.rsh.l] += basis[o].f.rsh.m == 0; } if(MSYM_SUCCESS != (ret = generateBasisRepresentations(pg->order+1, pg->order, pg->sops, lmax, lts))) goto err; for(int k = 0; k < ct->d;k++){ if(ct->s[k].d > 1){ if(MSYM_SUCCESS != (ret = findSplittingFieldSubgroup(pg, k, sgl, sg, thresholds, &rsg[k]))) goto err; if(MSYM_SUCCESS != (ret = getSplittingFieldCharacters(pg, rsg[k], sgc[k], sgd[k]))) goto err; } } for(int o = 0;o < basisl;o++){ msym_basis_function_t *bf = &basis[o]; int ei = (int)(bf->element - elements), esi = 0; msym_equivalence_set_t *e = esmap[ei]; for(esi = 0;esi < e->length && e->elements[esi] != bf->element;esi++){}; //could improve perf with a map here if(esi >= e->length){ ret = MSYM_INVALID_BASIS_FUNCTIONS; msymSetErrorDetails("Basis function does not map to any equivalence set"); goto err; } if(bf->f.rsh.n > esnmax[e - es]) esnmax[e - es] = bf->f.rsh.n; esbfmap[e - es][esi][bf->f.rsh.n][bf->f.rsh.l][bf->f.rsh.m+bf->f.rsh.l] = bf; } int srsbfi = 0; for(int i = 0;i < esl;i++){ for(int n = 0;n <= nmax;n++){ for(int l = 0;l <= lmax;l++){ srsbfmap[i][n][l] = srsbfi; for(int e = 0;e < es[i].length;e++){ msym_basis_function_t *lbf = esbfmap[i][e][n][l][0]; for(int m = -l;m <= l;m++){ msym_basis_function_t *bf = esbfmap[i][e][n][l][m+l]; if((NULL == bf && NULL != lbf) || (NULL == lbf && NULL != bf)) { lbf = NULL == lbf ? bf : lbf; ret = MSYM_INVALID_BASIS_FUNCTIONS; msymSetErrorDetails("Found basis function %s but function where m = %d is missing on element %d of equivalence set %d",lbf->name,m,e,i); goto err; } if(NULL != bf){ lbf = bf; srsbf[srsbfi] = bf; srsbfi++; } } } //when this is moved to a separate function it can be used and availability check (replace esbfmap) //if(srsbfmap[i][n][l] == srsbfi) srsbfmap[i][n][l] = -1; } } } if(srsbfi != basisl){ ret = MSYM_SUBSPACE_ERROR; msymSetErrorDetails("Unexpected number of basis functions in subrepresentation map (expected %d, got %d)",basisl, srsbfi); goto err; } /* calculate span of irreducible representations for basis functions and permutations */ for(int s = 0; s < pg->order;s++){ for(int l = 0; l <= lmax;l++){ dbf.f.rsh.l = l; //TODO: function type based double c = symmetryOperationCharacter(&pg->sops[s], &dbf); for(int k = 0;k < ct->d;k++){ bspan[l][k] += c*ctable[k][pg->sops[s].cla]; } } for(int i = 0;i < esl;i++){ int uma = 0; for(int j = 0; j < perm[i][s].c_length;j++) uma += perm[i][s].c[j].l == 1; //this is why we loop over irreps twice for(int k = 0;k < ct->d;k++){ pspan[i][k] += uma*ctable[k][pg->sops[s].cla]; } } } /* scale reducible representations */ for(int k = 0;k < ct->d;k++){ double r = ct->s[k].r; if(r > 1){ for(int l = 0; l <= lmax;l++) bspan[l][k] /= r; for(int i = 0;i < esl;i++) pspan[i][k] /= r; } } /* scale basis span, calculate basis function transforms and symmetry species vectors */ for(int l = 0;l <= lmax;l++){ int d = lts[l].d; double (*lproj)[d] = mproj; double (*lscal)[d] = mscal; vlscale(1.0/pg->order, ct->d, bspan[l], bspan[l]); double (*st)[d][d] = lts[l].t; memset(st[pg->order], 0, sizeof(double[d][d])); for(int k = 0, oirl = 0, nirl = 0;k < ct->d;k++, oirl = nirl){ int vspan = ct->s[k].d*((int) round(bspan[l][k])); if(vspan == 0) continue; memset(lproj, 0, sizeof(double[d][d])); for(int s = 0;s < pg->order;s++){ mlscale(ctable[k][pg->sops[s].cla], d, st[s], lscal); mladd(d, lscal, lproj, lproj); } mlscale(((double) ct->s[k].d)/pg->order, d, lproj, lproj); nirl = mgs(d, lproj, st[pg->order], oirl, thresholds->orthogonalization/basisl); if(nirl - oirl != vspan){ debug_printTransform(d, d, st[pg->order]); ret = MSYM_SUBSPACE_ERROR; msymSetErrorDetails("Ortogonal subspace of dimension (%d) inconsistent with span (%d) in %s",nirl - oirl,vspan,ct->s[k].name); goto err; } } for(int i = 0; i < d;i++) vlnorm(d, st[pg->order][i]); } /* scale permutation span and calculate total basis function span on each ES */ for(int i = 0;i < esl;i++){ vlscale(1.0/pg->order, ct->d, pspan[i], pspan[i]); for(int l = 0; l <= lmax;l++){ if(les[i][l] == 0) continue; les[i][l] /= es[i].length; vlscale((double) les[i][l], ct->d, bspan[l], mspan); vladd(ct->d, mspan, lspan[i], lspan[i]); } } /* calculate direct product of irreducible representations spanned by basis functions and permutations on each ES (don't really need to do this) */ for(int i = 0;i < esl;i++){ for(int k = 0;k < ct->d;k++){ for(int j = 0;j < ct->d && round(pspan[i][k]) > 0;j++){ if(round(lspan[i][j]) == 0) continue; directProduct(ct->d, ctable[k], ctable[j], mspan); vlscale(pspan[i][k]*lspan[i][j], ct->d, mspan, mspan); vladd(ct->d, mspan, rspan, rspan); } } } /* decompose direct product into irreducible representations */ decomposeRepresentation(ct, rspan, dspan); int ddim_max = 0; for(int k = 0;k < ct->d;k++){ ispan[k] = (int)round(dspan[k]/ct->s[k].r); ddim_max = ddim_max > ispan[k] ? ddim_max : ispan[k]; srs[k].s = k; srs[k].salcl = ispan[k]; srs[k].salc = calloc(srs[k].salcl, sizeof(msym_salc_t)); } mdcomp = malloc(sizeof(double[5][ddim_max][ddim_max])); mdproj = malloc(sizeof(double[projm][projm])); mdfound = malloc(sizeof(int[5][ddim_max])); clean_debug_printf("decomposed %d\n", ct->d); for(int prk = 0;prk < ct->d;prk++){ if(prk < ct->d - 1) clean_debug_printf("%d%s + ", ispan[prk], ct->s[prk].name); else clean_debug_printf("%d%s\n", ispan[prk], ct->s[prk].name); } int dbasisl = 0; for(int k = 0;k < ct->d;k++){ dbasisl += ct->s[k].d*ispan[k]; } if(dbasisl != basisl){ ret = MSYM_SUBSPACE_ERROR; msymSetErrorDetails("Unexpected number of basis functions in decomposition (expected %d, got %d)",basisl,dbasisl); goto err; } for(int i = 0; i < esl; i++){ int d = es[i].length; double (*pproj)[d] = mproj, (*pscal)[d] = mscal, (*porth)[d] = morth; memset(porth, 0, sizeof(double[d][d])); for(int k = 0, oirl = 0, nirl = 0;k < ct->d;k++, oirl = nirl){ int vspan = ct->s[k].d*((int) round(pspan[i][k])); if(vspan == 0) continue; memset(pproj, 0, sizeof(double[d][d])); for(int s = 0;s < pg->order;s++){ if(ctable[k][pg->sops[s].cla] == 0) continue; permutationMatrix(&perm[i][s], mperm); mlscale(ctable[k][pg->sops[s].cla], d, mperm, pscal); mladd(d, pscal, pproj, pproj); } mlscale(((double) ct->s[k].d)/pg->order, d, pproj, pproj); nirl = mgs(d, pproj, porth, oirl, thresholds->orthogonalization/basisl); if(nirl - oirl != vspan){ ret = MSYM_SUBSPACE_ERROR; msymSetErrorDetails("Ortogonal ES subspace of dimension (%d) inconsistent with span (%d) in %s",nirl - oirl,vspan,ct->s[k].name); goto err; } for(int oi = oirl; oi < nirl;oi++) vlnorm(d, porth[oi]); for(int l = 0;l <= lmax;l++){ if(les[i][l] <= 0) continue; int li = 0, ld = lts[l].d; double (*lst)[ld][ld] = lts[l].t; for(int lk = 0;lk < ct->d;lk++){ int lvspan = ct->s[lk].d*((int) round(bspan[l][lk])), dd = d*ld; if(lvspan == 0) continue; kron2(vspan, d, &porth[oirl], lvspan, ld, &lst[pg->order][li], mbasis); li += lvspan; directProduct(ct->d, ctable[k], ctable[lk], rspan); vlscale(pspan[i][k]*bspan[l][lk], ct->d, rspan, rspan); decomposeRepresentation(ct, rspan, mspan); for(int dk = 0; dk < ct->d; dk++) mspan[dk] /= ct->s[dk].r; if(ct->s[k].d > 1 && ct->s[lk].d > 1){ memcpy(mdec, mbasis, sizeof(double[vspan*lvspan][dd])); memset(mbasis, 0, sizeof(double[vspan*lvspan][dd])); for(int dk = 0, doirl = 0, dnirl = 0;dk < ct->d;dk++, doirl = dnirl){ int dvspan = ct->s[dk].d*((int) round(mspan[dk])); if(dvspan == 0) continue; double (*dproj)[dd] = mproj; // projection operator for direct product double (*dscal)[dd] = mscal; memset(dproj, 0, sizeof(double[dd][dd])); for(int s = 0;s < pg->order;s++){ if(ctable[dk][pg->sops[s].cla] == 0) continue; permutationMatrix(&perm[i][s], mperm); kron(d, mperm, ld, lst[s], dd, dscal); mlscale(ctable[dk][pg->sops[s].cla], dd, dscal, dscal); mladd(dd, dscal, dproj, dproj); } mlscale(((double) ct->s[dk].d)/pg->order, dd, dproj, dproj); mmtlmul(dd,dd,dproj,vspan*lvspan,mdec,dscal); memset(dproj, 0, sizeof(double[dd][dd])); mltranspose(dd, vspan*lvspan, dscal, dproj); dnirl = mgs(dd, dproj, mbasis, doirl, thresholds->orthogonalization/basisl); if(dnirl - doirl != dvspan){ ret = MSYM_SUBSPACE_ERROR; msymSetErrorDetails("Ortogonal subspace decomposition of dimension (%d) inconsistent with span (%d) in %s",dnirl - doirl,vspan,ct->s[dk].name); goto err; } } } for(int sk = 0,si=0;sk < ct->d;sk++){ int svspan = ct->s[sk].d*((int) round(mspan[sk])), dd = d*ld; if(svspan == 0) continue; double (*sbasis)[dd] = mbasis; double (*sdec)[dd] = mdec; if(ct->s[sk].d > 1){ //icosahedral symmetry map (dependant on getSplittingFieldCharacters) int ihdim[] = {0,1,1,2,2}; int ihsub[] = {0,3,4,3,4}; double (*ihproj)[dd] = mpih; double (*dproj)[dd] = mproj; // projection operator for direct product double (*dscal)[dd] = mscal; memset(dproj, 0, sizeof(double[dd][dd])); memset(mdec, 0, sizeof(double[vspan*lvspan][dd])); for(int dim = 0, doirl = 0, dnirl = 0;dim < ct->s[sk].d;dim++, doirl = dnirl){ int pdim = ct->s[sk].d == 5 ? ihdim[dim] : dim; //icosahedral symmetry has split character table memset(dproj, 0, sizeof(double[dd][dd])); for(int s = 0;s < pg->order;s++){ if(sgc[sk][pdim][s] == 0) continue; // we really should have precomputed this by now, it's the third time, // or a better approach would be a an optimized function permutationMatrix(&perm[i][s], mperm); kron(d, mperm, ld, lst[s], dd, dscal); mlscale(sgc[sk][pdim][s], dd, dscal, dscal); mladd(dd, dscal, dproj, dproj); } if(sgd[sk][pdim] == 2){ // only icosahedral int c2dim = ihsub[dim]; memset(ihproj, 0, sizeof(double[dd][dd])); //getting rediculous for(int s = 0;s < pg->order;s++){ if(sgc[sk][c2dim][s] == 0) continue; permutationMatrix(&perm[i][s], mperm); kron(d, mperm, ld, lst[s], dd, dscal); mlscale(sgc[sk][c2dim][s], dd, dscal, dscal); mladd(dd, dscal, ihproj, ihproj); } mmlmul(dd, dd, ihproj, dd, dproj, dscal); //avoid the mul malloc memcpy(dproj, dscal, sizeof(double[dd][dd])); } mlscale(1.0/rsg[sk]->order, dd, dproj, dproj); //printf("constructed subgroup projection operator %s\n",cs_name[dim]); //debug_printTransform(dd, dd, dproj); mmtlmul(dd,dd,dproj,svspan,&sbasis[si],dscal); memset(dproj, 0, sizeof(double[dd][dd])); mltranspose(dd, svspan, dscal, dproj); dnirl = mgs(dd, dproj, sdec, doirl, thresholds->orthogonalization/basisl); if(dnirl - doirl != round(mspan[sk])){ ret = MSYM_SUBSPACE_ERROR; msymSetErrorDetails("Multi-dimensional subspace decomposition of %s dimension (%d) inconsistent with representaion (%d) in subgroup irrep %d",ct->s[sk].name, dnirl - doirl,(int) round(mspan[sk]),dim); goto err; } for(int oi = doirl; oi < dnirl;oi++) vlnorm(dd, sdec[oi]); } //do apply symmetry here memcpy(&sbasis[si], sdec, sizeof(double[svspan][dd])); int mdim = round(mspan[sk]); int (*found)[mdim] = (int (*)[mdim]) mdfound; double (*g)[mdim][mdim] = (double (*)[mdim][mdim]) mdcomp; double (*mt)[mdim] = (double (*)[mdim]) mdproj; memset(found,0,sizeof(int[ct->s[sk].d][mdim])); for(int s = 0;s < pg->order ;s++){ permutationMatrix(&perm[i][s], mperm); kron(d, mperm, ld, lst[s], dd, dscal); for(int dim = 0;dim < mdim;dim++){ for(int sg = 1;sg < ct->s[sk].d;sg++){ if(found[sg][dim]) continue; mmtlmul(dd, dd, dscal, mdim, &sdec[sg*mdim], mt); mmlmul(1,dd,&sdec[dim], mdim, mt, &g[sg][dim]); if(vlabs(mdim, g[sg][dim]) > thresholds->zero) found[sg][dim] = 1; } } } for(int cdim = 0;cdim < mdim;cdim++){ vlnorm2(dd, sdec[cdim], sbasis[si+ct->s[sk].d*cdim]); } for(int dim = 1; dim < ct->s[sk].d;dim++){ mmlmul(mdim, mdim, g[dim], dd, &sdec[dim*mdim], dproj); for(int cdim = 0;cdim < mdim;cdim++){ vlnorm2(dd, dproj[cdim], sbasis[si+dim+ct->s[sk].d*cdim]); } } } for(int ir = 0;ir < svspan;ir += ct->s[sk].d){ for(int n = l+1; n <= esnmax[i];n++){ if(esbfmap[i][0][n][l][0] == NULL) continue; if(isalc[sk] >= ispan[sk]){ ret = MSYM_SUBSPACE_ERROR; msymSetErrorDetails("Exceeded calculated number of SALCs %d >= %d",isalc[sk],ispan[sk]); goto err; } //printf("adding salc %d of %d %d\n",isalc[sk],ispan[sk],sk); msym_salc_t *salc = &srs[sk].salc[isalc[sk]]; salc->d = ct->s[sk].d; double (*pf)[dd] = calloc(salc->d,sizeof(double[dd])); for(int dim = 0; dim < salc->d;dim++){ vlnorm2(dd, sbasis[si+dim+ir], pf[dim]); } salc->pf = (double*) pf; salc->fl = dd; salc->f = &srsbf[srsbfmap[i][n][l]]; isalc[sk]++; } } si += svspan; } } } } } debug_printSubspace(ct,ct->d,srs); *ospan = ispan; *osrsl = ct->d; *osrs = srs; *osrsbf = srsbf; free(bspan); free(pspan); free(lspan); free(rspan); free(dspan); free(mspan); free(mproj); free(mscal); free(mpih); free(mperm); free(morth); free(mbasis); free(mdec); free(rsg); free(sgc); free(sgd); free(mpih); free(mdcomp); free(mdproj); free(mdfound); free(isalc); free(esnmax); free(esbfmap); for(int l = 0;l <= lmax;l++){ free(lts[l].t); } free(lts); free(les); free(srsbfmap); return ret; err: free(bspan); free(pspan); free(lspan); free(rspan); free(dspan); free(mspan); free(mproj); free(mscal); free(mperm); free(morth); free(mbasis); free(mdec); free(rsg); free(sgc); free(sgd); free(mpih); free(mdcomp); free(mdproj); free(mdfound); free(ispan); free(isalc); free(esnmax); free(esbfmap); for(int l = 0;l <= lmax;l++){ free(lts[l].t); } free(lts); free(les); free(srsbfmap); for(int k = 0;k < ct->d;k++){ for(int i = 0;i < srs[k].salcl;i++){ free(srs[k].salc[i].pf); } free(srs[k].salc); } free(srs); free(srsbf); return ret; } void freeSubrepresentationSpaces(int srsl, msym_subrepresentation_space_t *srs){ for(int i = 0;i < srsl && NULL != srs;i++){ for(int j = 0;j < srs[i].salcl;j++){ free(srs[i].salc[j].pf); } free(srs[i].salc); } free(srs); } v_sim-3.8.0/lib/plug-ins/msym/libmsym/src/subspace.h000066400000000000000000000020771370110300500223450ustar00rootroot00000000000000// // subspace.h // libmsym // // Created by Marcus Johansson on 28/05/15. // Copyright (c) 2014 Marcus Johansson. // // Distributed under the MIT License ( See LICENSE file or copy at http://opensource.org/licenses/MIT ) // #ifndef __MSYM__SUBSPACE_h #define __MSYM__SUBSPACE_h #include #include "msym.h" #include "character_table.h" #include "point_group.h" void freeSubrepresentationSpaces(int srsl, msym_subrepresentation_space_t *srs); msym_error_t generateSubrepresentationSpaces(msym_point_group_t *pg, int sgl, const msym_subgroup_t sg[sgl], int esl, msym_equivalence_set_t *es, msym_permutation_t **perm, int basisl, msym_basis_function_t basis[basisl], msym_element_t *elements, msym_equivalence_set_t **esmap, msym_thresholds_t *thresholds, int *osrsl, msym_subrepresentation_space_t **osrs, msym_basis_function_t ***osrsbf, int **ospan); msym_error_t symmetrySpeciesComponents(msym_point_group_t *pg, int srsl, msym_subrepresentation_space_t *srs, int basisl, msym_basis_function_t *basis, double *wf, double *s); #endif /* defined(__MSYM__SUBSPACE_h) */ v_sim-3.8.0/lib/plug-ins/msym/libmsym/src/symmetrize.c000066400000000000000000000266261370110300500227510ustar00rootroot00000000000000// // symmetrize.c // Symmetry // // Created by Marcus Johansson on 04/02/15. // Copyright (c) 2015 Marcus Johansson. // // Distributed under the MIT License ( See LICENSE file or copy at http://opensource.org/licenses/MIT ) // #include #include #include #include #include "symmetrize.h" #include "linalg.h" #include "debug.h" #define SQR(x) ((x)*(x)) /* This is a projection into the fully symmetric space. * A little more computation than if we just recreate it from one atom, * but it is independant of the chosen atom and we can get the size * of the fully symmetric component. * The sizes of the individual equivalence sets are rather small anyways. */ msym_error_t symmetrizeElements(msym_point_group_t *pg, int esl, msym_equivalence_set_t *es, msym_permutation_t **perm, msym_thresholds_t *thresholds, double *err){ msym_error_t ret = MSYM_SUCCESS; double e = 0.0; double (*v)[3] = malloc(sizeof(double[pg->order][3])); for(int i = 0; i < esl;i++){ if(es[i].length > pg->order){ ret = MSYM_SYMMETRIZATION_ERROR; msymSetErrorDetails("Equivalence set (%d elements) larger than order of point group (%d)",es[i].length,pg->order); goto err; } memset(v, 0, sizeof(double[pg->order][3])); for(int j = 0; j < pg->order;j++){ for(int k = 0; k < es[i].length;k++){ int p = perm[i][j].p[k]; double sv[3]; applySymmetryOperation(&pg->sops[j], es[i].elements[k]->v, sv); vadd(sv, v[p], v[p]); } } double sl = 0.0, ol = 0.0; for(int j = 0; j < es[i].length;j++){ ol += vdot(es[i].elements[j]->v,es[i].elements[j]->v); sl += vdot(v[j],v[j]); vscale(1.0/((double)pg->order), v[j], es[i].elements[j]->v); } sl /= SQR((double)pg->order); if(!(es[i].length == 1 && ol <= thresholds->zero)) e += (ol-sl)/ol; //e = fmax(e,(ol-sl)/ol); } *err = sqrt(fmax(e,0.0)); //should never be < 0, but it's a dumb way to die err: free(v); return ret; } msym_error_t symmetrizeWavefunctions(msym_point_group_t *pg, int srsl, msym_subrepresentation_space_t *srs, int *span, int basisl, msym_basis_function_t basis[basisl], double wf[basisl][basisl], double symwf[basisl][basisl], int specieso[basisl], msym_partner_function_t pfo[basisl]){ msym_error_t ret = MSYM_SUCCESS; if(srsl != pg->ct->d){ ret = MSYM_SYMMETRIZATION_ERROR; msymSetErrorDetails("Unexpected subspace length (expected %d got %d)",pg->ct->d, srsl); return ret; } int *ispan = calloc(pg->ct->d,sizeof(*ispan)); int *species = (NULL == specieso ? malloc(sizeof(int[basisl])) : specieso); memset(species,0,sizeof(int[basisl])); if(NULL != pfo) memset(pfo,0,sizeof(msym_partner_function_t[basisl])); int md = 1; //could deduce from pg type but can't be bothered for(int k = 0;k < pg->ct->d;k++) md = (md > pg->ct->s[k].d ? md : pg->ct->s[k].d); int (*pf)[md] = calloc(basisl+1,sizeof(*pf)); int psalcl = 0; int *psalck = calloc(pg->ct->d, sizeof(*psalck)); for(int i = 0;i < srsl;i++){ psalck[i] = psalcl; psalcl += srs[i].salcl; } /* This is a bit of overkill since we only need the sign of the component * We could just as well have used a basis change, but the sign in degenerate * representations can't be used for partner function determination, * and this is a sparce matrix */ double (*psalc)[basisl][psalcl] = calloc(md+1,sizeof(*psalc)); double (*bfd)[md] = calloc(basisl+1, sizeof(*bfd)); double *dmpf = bfd[basisl]; /* Determine salc components, and build information vectors (e.g. indexing/offsets/irreps) */ for(int o = 0;o < basisl;o++){ double mcomp = -1.0; int psalci = 0; for(int k = 0;k < srsl;k++){ double mabs = 0.0; for(int s = 0;s < srs[k].salcl;s++){ msym_salc_t *salc = &srs[k].salc[s]; double (*space)[salc->fl] = (double (*)[salc->fl]) salc->pf; double psalcabs = 0.0; for(int d = 0;d < salc->d;d++){ double c = 0.0; for(int j = 0; j < salc->fl;j++){ c += wf[o][salc->f[j] - basis]*space[d][j]; } double c2 = SQR(c); psalc[d][o][psalci] = c; //Won't thrash the cache too bad since d is small psalcabs += c2; bfd[o][d] += c2; } mabs += psalcabs; psalc[md][o][psalci] = sqrt(psalcabs); psalci++; } if(mabs > mcomp){ species[o] = k; mcomp = mabs; } } ispan[species[o]]++; } for(int k = 0;k < pg->ct->d;k++){ if(ispan[k] != span[k]*pg->ct->s[k].d){ msymSetErrorDetails("Projected orbitals do not span the expected irredicible representations. Expected %d%s, got %d",span[k],pg->ct->s[k].name,ispan[k]); ret = MSYM_SYMMETRIZATION_ERROR; goto err; } } /* Find parner functions */ for(int o = 0;o < basisl;o++){ int ko = species[o], dim = pg->ct->s[ko].d; struct _fpf {int i; int j;} fpf = {.i = 0, .j = 0}; for(int i = 1;i < md;i++){ pf[o][i] = -1; pf[basisl][i] = -1; }; if(dim <= 1) continue; /* check if this functions has alredy been assigned partners */ for(int i = 0;i < o && !fpf.j;i++){ for(int j = 1;j < md;j++){ if(pf[i][j] == o){ fpf.i = i; fpf.j = j; break; } } } if(fpf.j){ for(int i = 1; i < fpf.j;i++){ pf[pf[fpf.i][i]][0]--; } pf[o][0] -= fpf.j; continue; } for(int i = 0;i < md;i++){dmpf[i] = DBL_MAX;} for(int po = 0; po < basisl;po++){ if(species[po] != ko || o == po || abs(pf[po][0]) == dim - 1) continue; double c = 0, mc = 0; /* length of v1-v2 */ for(int i = 0;i < psalcl;i++){ double sub = psalc[md][o][i] - psalc[md][po][i]; c += SQR(sub); } c = sqrt(c); /* find the smallest diffs */ int mic = 0; for(int i = 1;i < dim;i++){ double diff = fabs(dmpf[i] - c); if(c < dmpf[i] && (diff > mc)){ mic = i; mc = diff; } } if(mic > 0){ dmpf[mic] = c; pf[o][mic] = po; pf[basisl][mic] = po; } } for(int i = 1;i < dim;i++){ pf[o][0] += pf[basisl][i] > 0; } } /* verify that we have partners for everything */ for(int o = 0;o < basisl;o++){ int dim = pg->ct->s[species[o]].d; if(abs(pf[o][0])+1 != dim){ for(int i = 0;i < md;i++) clean_debug_printf("%d = %d\n",i,pf[o][i]); msymSetErrorDetails("Unexpected number of partner functions for wave function %d in %s (expected %d got %d)", o, pg->ct->s[species[o]].name, dim, abs(pf[o][0])+1); ret = MSYM_SYMMETRIZATION_ERROR; goto err; } for(int i = 0;pf[o][0] >= 0 && i < dim;i++){ if(pf[o][i] == -1){ msymSetErrorDetails("Could not determine partner function %d of wave function %d",i, o); ret = MSYM_SYMMETRIZATION_ERROR; goto err; } } } memset(symwf,0,sizeof(double[basisl][basisl])); for(int o = 0;o < basisl;o++){ int k = species[o]; int dim = pg->ct->s[k].d; if(pf[o][0] < 0) continue; pf[o][0] = o; for(int i = 0;i < dim;i++) pf[basisl][i] = -1; /* Get the unique dimensions for each partner function in which they have the largest component. * This is only needed when the symmetry is really broken but the degenerate functions can be averaged, * but it also keeps the ordering intact. * This is could be improved with a best match algorithm */ for(int i = 0;i < dim;i++){ double cmax = 0.0; for(int d = 0;d < dim;d++){ double c = bfd[pf[o][i]][d]; //component of i:th partner in dimension d if(c > cmax){ int found = 0; for(int j = 0;j < i;j++){ if(pf[basisl][j] == d){ found = 1; break; } } if(!found){ pf[basisl][i] = d; cmax = c; } } } } /*for(int i = 0;i < dim;i++){ clean_debug_printf("partner function %d has maximum component in dimension %d\n",i,pf[basisl][i]); }*/ /* calculate average component in each salc subspace and rotate onto the partner functions with largest component */ for(int s = 0;s < srs[k].salcl;s++){ int psalci = psalck[k] + s, pfmin = 0; double avg = 0; for(int d = 0;d < dim;d++){ int wfi = pf[o][d]; avg += psalc[md][wfi][psalci]; if(pf[basisl][d] == 0) pfmin = wfi; } avg /= dim; //printf("average component in salc %d(%s) for wf %d = %lf\n",psalci,pg->ct->s[k].name,o,avg); msym_salc_t *salc = &srs[k].salc[s]; double (*space)[salc->fl] = (double (*)[salc->fl]) salc->pf; for(int d = 0; d < dim;d++){ int wfi = pf[o][d], di = pf[basisl][d]; /* use the sign of the projection onto the largest component */ double c = copysign(avg,psalc[di][wfi][psalci]); for(int j = 0; j < salc->fl;j++){ symwf[wfi][salc->f[j] - basis] += c*space[di][j]; } if(NULL != pfo){ pfo[wfi].d = di; pfo[wfi].i = pfmin; } } } } err: if(species != specieso) free(species); free(ispan); free(pf); free(psalc); free(bfd); free(psalck); return ret; } msym_error_t symmetrizeTranslation(msym_point_group_t *pg, msym_equivalence_set_t *es, msym_permutation_t *perm, int pi, double translation[3]){ msym_error_t ret = MSYM_SUCCESS; double (*v)[3] = calloc(es->length,sizeof(double[3])); for(int j = 0; j < pg->order;j++){ int p = perm[j].p[pi]; double stranslation[3]; applySymmetryOperation(&pg->sops[j], translation, stranslation); vadd(stranslation, v[p], v[p]); } double scale = ((double)es->length)/pg->order; for(int i = 0;i < es->length;i++){ vscale(scale, v[i], v[i]); vadd(es->elements[i]->v,v[i],es->elements[i]->v); } //err: free(v); return ret; } v_sim-3.8.0/lib/plug-ins/msym/libmsym/src/symmetrize.h000066400000000000000000000023451370110300500227460ustar00rootroot00000000000000// // symmetrize.h // Symmetry // // Created by Marcus Johansson on 04/02/15. // Copyright (c) 2015 Marcus Johansson. // // Distributed under the MIT License ( See LICENSE file or copy at http://opensource.org/licenses/MIT ) // #ifndef __MSYM__SYMMETRIZE_h #define __MSYM__SYMMETRIZE_h #include #include "msym.h" #include "point_group.h" #include "permutation.h" msym_error_t symmetrizeElements(msym_point_group_t *pg, int esl, msym_equivalence_set_t *es, msym_permutation_t **perm, msym_thresholds_t *thresholds, double *err); //msym_error_t symmetrizeOrbitals(msym_point_group_t *pg, int ssl, msym_subspace_t *ss, int *span, int basisl, msym_orbital_t basis[basisl], msym_thresholds_t *thresholds, double orb[basisl][basisl],double symorb[basisl][basisl]); msym_error_t symmetrizeTranslation(msym_point_group_t *pg, msym_equivalence_set_t *es, msym_permutation_t *perm, int pi, double translation[3]); msym_error_t symmetrizeWavefunctions(msym_point_group_t *pg, int srsl, msym_subrepresentation_space_t *srs, int *span, int basisl, msym_basis_function_t basis[basisl], double wf[basisl][basisl], double symwf[basisl][basisl], int species[basisl], msym_partner_function_t pfo[basisl]); #endif /* defined(__MSYM__SYMMETRIZE_h) */ v_sim-3.8.0/lib/plug-ins/msym/libmsym/src/symmetry.c000066400000000000000000001331701370110300500224230ustar00rootroot00000000000000// // symmetry.c // libmsym // // Created by Marcus Johansson on 12/04/14. // Copyright (c) 2014 Marcus Johansson. // // Distributed under the MIT License ( See LICENSE file or copy at http://opensource.org/licenses/MIT ) // #include "symmetry.h" #include "msym.h" #include "linalg.h" #include "symop.h" #include "geometry.h" #include "equivalence_set.h" #include #include #include #include //Special case of less than (basically with some margin) #define LT(A,B,T) ((B) - (A) > (T)) #ifndef M_PI #define M_PI 3.14159265358979323846264338327950288419716939937510582 #endif int divisors(int n, int* div); msym_error_t findEquivalenceSetSymmetryOperations(msym_equivalence_set_t *es, msym_thresholds_t *t, int *lsops, msym_symmetry_operation_t **sops); msym_error_t findSymmetryLinear(msym_equivalence_set_t *es, double cm[3], double ev[3][3], msym_thresholds_t *thresholds, int *rsopsl, msym_symmetry_operation_t **rsops); msym_error_t findSymmetryPlanarRegular(msym_equivalence_set_t *es, double cm[3], double ev[3][3], msym_thresholds_t *t, int *rsopsl, msym_symmetry_operation_t **rsops); msym_error_t findSymmetryPlanarIrregular(msym_equivalence_set_t *es, double cm[3], double ev[3][3], msym_thresholds_t *thresholds, int *rsopsl, msym_symmetry_operation_t **rsops); msym_error_t findSymmetryPolyhedralProlate(msym_equivalence_set_t *es, double cm[3], double ev[3][3], msym_thresholds_t *thresholds, int *rsopsl, msym_symmetry_operation_t **rsops); msym_error_t findSymmetryPolyhedralOblate(msym_equivalence_set_t *es, double cm[3], double ev[3][3], msym_thresholds_t *thresholds, int *rsopsl, msym_symmetry_operation_t **rsops); msym_error_t findSymmetrySymmetricPolyhedron(msym_equivalence_set_t *es, double cm[3], double ev[3][3], msym_thresholds_t *thresholds, int prim, int *rsopsl, msym_symmetry_operation_t **rsops); msym_error_t findSymmetryAsymmetricPolyhedron(msym_equivalence_set_t *es, double cm[3], double ev[3][3], msym_thresholds_t *thresholds, int *rsopsl, msym_symmetry_operation_t **rsops); msym_error_t findSymmetrySpherical(msym_equivalence_set_t *es, double cm[3], double ev[3][3], msym_thresholds_t *thresholds, int *rsopsl, msym_symmetry_operation_t **rsops); msym_error_t findSymmetryCubic(msym_equivalence_set_t *es, double cm[3], double ev[3][3], msym_thresholds_t *thresholds, int *rsopsl, msym_symmetry_operation_t **rsops); msym_error_t findSymmetryUnknown(msym_equivalence_set_t *es, double cm[3], double ev[3][3], msym_thresholds_t *t, int *rsopsl, msym_symmetry_operation_t **rsops); msym_error_t reduceSymmetry(int sopsl, msym_symmetry_operation_t sops[sopsl], msym_thresholds_t *thresholds, int *isopsl, msym_symmetry_operation_t **isops); msym_error_t filterSymmetryOperations(int sopsl, msym_symmetry_operation_t sops[sopsl], msym_thresholds_t *thresholds, int *isopsl, msym_symmetry_operation_t **isops); msym_error_t findSymmetryOperations(int esl, msym_equivalence_set_t es[esl], msym_thresholds_t *t, int *lsops, msym_symmetry_operation_t **sops){ msym_error_t ret = MSYM_SUCCESS; msym_symmetry_operation_t *rsops = NULL; int lrsops = 0; for(int i = 0; i < esl;i++){ int llsops = lrsops; if(MSYM_SUCCESS != (ret = findEquivalenceSetSymmetryOperations(&es[i], t, &lrsops, &rsops))) goto err; if(llsops > 0 && lrsops == 0) { free(rsops); rsops = NULL; break; } } for(int i = 0;i < lrsops;i++){ vnorm(rsops[i].v); } *lsops = lrsops; *sops = rsops; return ret; err: free(rsops); *sops = NULL; *lsops = 0; return ret; } msym_error_t findEquivalenceSetSymmetryOperations(msym_equivalence_set_t *es, msym_thresholds_t *t, int *lsops, msym_symmetry_operation_t **sops){ //function pointer syntax is a little ambiguous, this is technically less correct, but nicer to read const struct _fmap { msym_geometry_t g; msym_error_t (*f)(msym_equivalence_set_t*,double[3],double[3][3],msym_thresholds_t*,int*,msym_symmetry_operation_t**); } fmap[8] = { [0] = {MSYM_GEOMETRY_SPHERICAL, findSymmetrySpherical}, [1] = {MSYM_GEOMETRY_LINEAR, findSymmetryLinear}, [2] = {MSYM_GEOMETRY_PLANAR_REGULAR, findSymmetryPlanarRegular}, [3] = {MSYM_GEOMETRY_PLANAR_IRREGULAR, findSymmetryPlanarIrregular}, [4] = {MSYM_GEOMETRY_POLYHEDRAL_PROLATE, findSymmetryPolyhedralProlate}, [5] = {MSYM_GEOMETRY_POLYHEDRAL_OBLATE, findSymmetryPolyhedralOblate}, [6] = {MSYM_GEOMETRY_ASSYMETRIC, findSymmetryAsymmetricPolyhedron}, [7] = {MSYM_GEOMETRY_UNKNOWN, findSymmetryUnknown} }; msym_error_t ret = MSYM_SUCCESS; msym_symmetry_operation_t *fsops = NULL; int lfsops = 0; double cm[3]; msym_geometry_t g; double eigvec[3][3]; double eigval[3]; if(MSYM_SUCCESS != (ret = findCenterOfMass(es->length, es->elements, cm))) goto err; if(MSYM_SUCCESS != (ret = findGeometry(es->length, es->elements, cm, t, &g, eigval, eigvec))) goto err; int fi, fil = sizeof(fmap)/sizeof(fmap[0]); for(fi = 0; fi < fil;fi++){ if(fmap[fi].g == g) { if(MSYM_SUCCESS != (ret = fmap[fi].f(es,cm,eigvec,t,&lfsops,&fsops))) goto err; break; } } if(fi == fil){ msymSetErrorDetails("Unknown geometry of equivalence set"); ret = MSYM_SYMMETRY_ERROR; goto err; } if(*sops == NULL){ *sops = fsops; *lsops = lfsops; } else if (lfsops != 0) { if(MSYM_SUCCESS != (ret = reduceSymmetry(lfsops, fsops, t, lsops, sops))) goto err; free(fsops); } else if (fsops == 0 && es->length > 1) { msymSetErrorDetails("No symmetry operations found in equivalence set with %d elements",es->length); ret = MSYM_SYMMETRY_ERROR; goto err; } else { free(fsops); } return ret; err: free(fsops); return ret; } msym_error_t findSymmetryUnknown(msym_equivalence_set_t *es, double cm[3], double ev[3][3], msym_thresholds_t *thresholds, int *rsopsl, msym_symmetry_operation_t **rsops){ return MSYM_INVALID_GEOMETRY; } msym_error_t findSymmetryLinear(msym_equivalence_set_t *es, double cm[3], double ev[3][3], msym_thresholds_t *thresholds, int *rsopsl, msym_symmetry_operation_t **rsops){ msym_error_t ret = MSYM_SUCCESS; int prim = 0, sopsl = 0; msym_symmetry_operation_t *sops = NULL; if(es->length != 2){ msymSetErrorDetails("Expected two elements in linear equivalence set, got %d",es->length); ret = MSYM_SYMMETRY_ERROR; goto err; } if(vzero(cm,thresholds->zero)){ double t[3], v[3]; vnorm2(es->elements[0]->v,v); vnorm2(es->elements[1]->v,t); vadd(v,t,t); vscale(0.5, t, t); vsub(v,t,v); vnorm(v); sopsl = 3; sops = malloc(sopsl*sizeof(msym_symmetry_operation_t)); vcopy(v,sops[0].v); vcopy(v,sops[1].v); sops[0].type = PROPER_ROTATION; sops[0].order = 0; sops[0].power = 1; sops[1].type = REFLECTION; sops[1].order = 1; sops[1].power = 1; sops[2].type = INVERSION; sops[2].order = 1; sops[2].power = 1; sops[2].v[0] = sops[2].v[1] = sops[2].v[2] = 0; } else { sopsl = 3; sops = malloc(sopsl*sizeof(msym_symmetry_operation_t)); vcopy(cm,sops[0].v); vnorm(sops[0].v); vcopy(ev[prim],sops[1].v); vnorm(sops[1].v); vcrossnorm(sops[0].v,sops[1].v,sops[2].v); sops[0].type = PROPER_ROTATION; sops[0].order = 2; sops[0].power = 1; sops[1].type = REFLECTION; sops[2].type = REFLECTION; } *rsops = sops; *rsopsl = sopsl; err: return ret; } msym_error_t findSymmetryPlanarRegular(msym_equivalence_set_t *es, double cm[3], double ev[3][3], msym_thresholds_t *thresholds, int *rsopsl, msym_symmetry_operation_t **rsops){ msym_error_t ret = MSYM_SUCCESS; int sigma_h = vzero(cm,thresholds->zero), order = es->length, prim = 2, div_len, even, inversion, n = 0, split = 0; int *div, sopsl; double v0[3], v0_proj[3], v_init[3], theta; msym_symmetry_operation_t *sops = NULL; vnorm2(es->elements[0]->v,v0); vproj_plane(v0, ev[prim], v0_proj); vnorm(v0_proj); vcopy(v0_proj,v_init); for(int i = 1; i < es->length;i++){ double vi[3], vi_proj[3]; vcopy(es->elements[i]->v,vi); vproj_plane(vi, ev[prim], vi_proj); vnorm(vi); vnorm(vi_proj); theta = vangle(v0_proj,vi_proj); if(LT(theta,2*M_PI/es->length,asin(thresholds->angle)) && es->length % 2 == 0){ order = es->length/2; split = 1; vadd(v0_proj, vi_proj, v_init); vnorm(v_init); break; } } div = malloc(order*sizeof(int)); div_len = divisors(order,div); even = order % 2 == 0; inversion = even && sigma_h; sopsl = (div_len + sigma_h + order + order*sigma_h + inversion + sigma_h*(div_len - even)); sops = malloc(sopsl*sizeof(msym_symmetry_operation_t)); for(; n < div_len; n++){ sops[n].type = PROPER_ROTATION; sops[n].order = div[n]; sops[n].power = 1; vcopy(ev[prim],sops[n].v); } if(sigma_h) { sops[n].type = REFLECTION; vcopy(ev[prim],sops[n].v); n++; for(int s = 0; s < div_len; s++){ if(div[s] > 2){ sops[n].type = IMPROPER_ROTATION; sops[n].order = div[s]; sops[n].power = 1; vcopy(ev[prim],sops[n].v); n++; } } } if(inversion){ sops[n].order = 1; sops[n].power = 1; sops[n].type = INVERSION; sops[n].v[0] = sops[n].v[1] = sops[n].v[2] = 0; n++; } theta = M_PI/order; for (int i = 0; i < order && n < sopsl; i++) { double r[3]; vrotate(i*theta, v_init, ev[prim], r); vnorm(r); //Not really nessecary vcrossnorm(r,ev[prim],sops[n].v); sops[n].type = REFLECTION; if(!findSymmetryOperation(&sops[n], sops, n, thresholds)){ n++; if(sigma_h){ vcopy(r,sops[n].v); sops[n].type = PROPER_ROTATION; sops[n].order = 2; sops[n].power = 1; n++; } } } free(div); if(n != sopsl) { msymSetErrorDetails("Unexpected number of generated symmetry operations in planar regular polygon. Got %d expected %d",n,sopsl); ret = MSYM_SYMMETRY_ERROR; goto err; } *rsops = sops; *rsopsl = sopsl; return ret; err: free(sops); return ret; } msym_error_t findSymmetryPlanarIrregular(msym_equivalence_set_t *es, double cm[3], double ev[3][3], msym_thresholds_t *thresholds, int *rsopsl, msym_symmetry_operation_t **rsops){ msym_error_t ret = MSYM_SUCCESS; int sopsl = 0; msym_symmetry_operation_t *sops = NULL; if(es->length != 4){ msymSetErrorDetails("Unexpected number of elements (%d) in planar irregular polygon",es->length); ret = MSYM_SYMMETRY_ERROR; goto err; } int iscm = vzero(cm,thresholds->zero); if(iscm){ //3xC2 + 3xSigma + inversion sopsl = 7; sops = malloc(sopsl*sizeof(msym_symmetry_operation_t)); } else { // 2xSigma + 1xC2 sopsl = 3; sops = malloc(sopsl*sizeof(msym_symmetry_operation_t)); } //The CM vector must be pointing in the same direction as the largest moment ov inertia vector, otherwise these would not be equal. vcopy(ev[2],sops[0].v); vnorm(sops[0].v); sops[0].type = PROPER_ROTATION; sops[0].order = 2; sops[0].power = 1; vcopy(ev[1],sops[1].v); vnorm(sops[1].v); sops[1].type = REFLECTION; vcopy(ev[0],sops[2].v); vnorm(sops[2].v); sops[2].type = REFLECTION; if(iscm){ vcopy(sops[0].v, sops[3].v); sops[3].type = REFLECTION; vcopy(sops[1].v, sops[4].v); sops[4].type = PROPER_ROTATION; sops[4].order = 2; sops[4].power = 1; vcopy(sops[2].v, sops[5].v); sops[5].type = PROPER_ROTATION; sops[5].order = 2; sops[5].power = 1; sops[6].type = INVERSION; sops[6].order = 1; sops[6].power = 1; sops[6].v[0] = sops[6].v[1] = sops[6].v[2] = 0; } *rsopsl = sopsl; *rsops = sops; return ret; err: return ret; } msym_error_t findSymmetryPolyhedralProlate(msym_equivalence_set_t *es, double cm[3], double ev[3][3], msym_thresholds_t *thresholds, int *rsopsl, msym_symmetry_operation_t **rsops){ return findSymmetrySymmetricPolyhedron(es,cm,ev,thresholds,0,rsopsl,rsops); } msym_error_t findSymmetryPolyhedralOblate(msym_equivalence_set_t *es, double cm[3], double ev[3][3], msym_thresholds_t *thresholds, int *rsopsl, msym_symmetry_operation_t **rsops){ return findSymmetrySymmetricPolyhedron(es,cm,ev,thresholds,2,rsopsl,rsops); } msym_error_t findSymmetrySymmetricPolyhedron(msym_equivalence_set_t *es, double cm[3], double ev[3][3], msym_thresholds_t *thresholds, int prim, int *rsopsl, msym_symmetry_operation_t **rsops){ msym_error_t ret = MSYM_SUCCESS; int sopsl = 0; msym_symmetry_operation_t *sops = NULL; int sigma_h = 0, staggered = 0, split = 0, order = es->length/2, even, inversion, div_len; int *div = NULL; int n = 0; double v0[3], v0_proj[3], v_init[3], dot0, theta, theta_C2 = 0.0, theta_sigma = 0.0; if(!(vzero(cm,thresholds->zero))){ msymSetErrorDetails("Symmetric polyhedron not at center of mass. Vector length: %e > %e (zero threshold)", vabs(cm),thresholds->zero); ret = MSYM_SYMMETRY_ERROR; goto err; } vcopy(es->elements[0]->v,v0); dot0 = vdot(v0,ev[prim]); vproj_plane(v0, ev[prim], v0_proj); vnorm(v0); vnorm(v0_proj); vcopy(v0_proj,v_init); for(int i = 1; i < es->length;i++){ double vi[3], vi_proj[3], v0i[3], doti; vcopy(es->elements[i]->v,vi); doti = vdot(vi,ev[prim]); vproj_plane(vi,ev[prim], vi_proj); vnorm(vi); vnorm(vi_proj); vsub(v0,vi, v0i); vnorm(v0i); theta = vangle(v0_proj, vi_proj); if(theta < asin(thresholds->angle)){ sigma_h = 1; staggered = 0; } if(dot0*doti > 0.0){ theta_sigma = theta/2; if(LT(theta, 4*M_PI/es->length, asin(thresholds->angle)) && es->length % 4 == 0){ vadd(v0,vi,v_init); vproj_plane(v_init, ev[prim], v_init); vnorm(v_init); order = es->length/4; even = order % 2 == 0; split = 1; //theta_split = theta; } } else { //This can potentially find a staggered form if split by equal amounts (should be ok, TODO: check) if(fabs(theta - 2*M_PI/es->length) < asin(thresholds->angle)){ staggered = 1; } // if we have not yet found that we are are staggerd/eclipsed or split this will either be over-written or this is a C2 axis for Dn if(!split && !staggered && !sigma_h){ if(LT(theta, 2*M_PI/es->length, asin(thresholds->angle))){ vadd(v0_proj, vi_proj, v_init); vnorm(v_init); } } } } if(split){ staggered = !sigma_h; } even = order % 2 == 0; inversion = (staggered && !even) || (sigma_h && even); div = malloc(order*sizeof(int)); div_len = divisors(order,div); //Symmetry operations: //Primary rotation and all divisors //sigma_h if eclipsed //n x C2 //n x sigma_v if we are in staggered or eclipsed form //Possible inversion (see above) //Smax*2 if staggerd Sn (n > 2) for sigma_h sopsl = (div_len + sigma_h + order + order*(sigma_h || staggered) + inversion + staggered + sigma_h*(div_len - even)); sops = malloc(sopsl*sizeof(msym_symmetry_operation_t)); int max; for(max = 0; n < div_len; n++){ if(div[n] > max){ max = div[n]; } sops[n].type = PROPER_ROTATION; sops[n].order = div[n]; sops[n].power = 1; vcopy(ev[prim],sops[n].v); } if(sigma_h) { sops[n].type = REFLECTION; vcopy(ev[prim],sops[n].v); n++; for(int s = 0; s < div_len; s++){ if(div[s] > 2){ sops[n].type = IMPROPER_ROTATION; sops[n].order = div[s]; sops[n].power = 1; vcopy(ev[prim],sops[n].v); n++; } } } if(inversion){ sops[n].type = INVERSION; sops[n].order = 1; sops[n].power = 1; sops[n].v[0] = sops[n].v[1] = sops[n].v[2] = 0; n++; } //PI/order angle between C2 & sigma_v //PI/(2*order) start angle if split & staggered //start angle if not split & staggered //0 start angle if sigma_h if(staggered){ theta_C2 = M_PI/(2*order); sops[n].type = IMPROPER_ROTATION; sops[n].order = 2*max; sops[n].power = 1; vcopy(ev[prim],sops[n].v); n++; } theta = M_PI/order; for (int i = 0; i < order; i++) { vrotate(theta_C2 + i*theta, v_init, ev[prim], sops[n].v); vnorm(sops[n].v); //Not really nessecary sops[n].type = PROPER_ROTATION; sops[n].order = 2; sops[n].power = 1; n++; if(staggered || sigma_h){ vrotate(i*theta, v_init,ev[prim], sops[n].v); vcrossnorm(sops[n].v,ev[prim],sops[n].v); sops[n].type = REFLECTION; n++; } } if(n != sopsl){ msymSetErrorDetails("Unexpected number of generated symmetry operations in symmetric polyhedron. Got %d expected %d",n,sopsl); ret = MSYM_SYMMETRY_ERROR; goto err; } free(div); *rsopsl = sopsl; *rsops = sops; return ret; err: free(div); free(sops); *rsops = NULL; *rsopsl = 0; return ret; } msym_error_t findSymmetryAsymmetricPolyhedron(msym_equivalence_set_t *es, double cm[3], double ev[3][3], msym_thresholds_t *thresholds, int *rsopsl, msym_symmetry_operation_t **rsops){ msym_error_t ret = MSYM_SUCCESS; int sopsl = 0; msym_symmetry_operation_t *sops = NULL; if(es->length == 4){ //Only C2 axis sopsl = 3; } else if(es->length == 8){ sopsl = 7; } else { msymSetErrorDetails("Unexpected number of elements (%d) in asymmetric polyhedron",es->length); ret = MSYM_SYMMETRY_ERROR; goto err; } if(!(vzero(cm,thresholds->zero))){ msymSetErrorDetails("Asymmetric polyhedron not at center of mass. Vector length: %e > %e (zero threshold)", vabs(cm),thresholds->zero); ret = MSYM_SYMMETRY_ERROR; goto err; } sops = malloc(sopsl*sizeof(msym_symmetry_operation_t)); vcopy(ev[0], sops[0].v); vcopy(ev[1], sops[1].v); vcopy(ev[2], sops[2].v); vnorm(sops[0].v); vnorm(sops[1].v); vnorm(sops[2].v); sops[0].type = PROPER_ROTATION; sops[0].order = 2; sops[0].power = 1; sops[1].type = PROPER_ROTATION; sops[1].order = 2; sops[1].power = 1; sops[2].type = PROPER_ROTATION; sops[2].order = 2; sops[2].power = 1; if(es->length == 8){ vcopy(sops[0].v,sops[3].v); vcopy(sops[1].v,sops[4].v); vcopy(sops[2].v,sops[5].v); sops[3].type = REFLECTION; sops[3].order = 1; sops[3].power = 1; sops[4].type = REFLECTION; sops[4].order = 1; sops[4].power = 1; sops[5].type = REFLECTION; sops[5].order = 1; sops[5].power = 1; sops[6].type = INVERSION; sops[6].order = 1; sops[6].power = 1; sops[6].v[0] = sops[6].v[1] = sops[6].v[2] = 0; } *rsopsl = sopsl; *rsops = sops; return ret; err: free(sops); *rsops = NULL; *rsopsl = 0; return ret; } msym_error_t findSymmetrySpherical(msym_equivalence_set_t *es, double cm[3], double ev[3][3], msym_thresholds_t *thresholds, int *rsopsl, msym_symmetry_operation_t **rsops){ msym_error_t ret = MSYM_SUCCESS; int sopsl = 0; msym_symmetry_operation_t *sops = NULL; if(es->length == 1){ if(!(vzero(cm,thresholds->zero))){ double t[3]; vcopy(es->elements[0]->v,t); sopsl = 1; sops = malloc(sopsl*sizeof(msym_symmetry_operation_t)); vcopy(t,sops[0].v); vnorm(sops[0].v); sops[0].type = PROPER_ROTATION; sops[0].order = 0; sops[0].power = 1; } *rsopsl = sopsl; *rsops = sops; } else { ret = findSymmetryCubic(es,cm,ev,thresholds,rsopsl,rsops); } return ret; //err: // return ret; } msym_error_t findSymmetryCubic(msym_equivalence_set_t *es, double cm[3], double ev[3][3], msym_thresholds_t *thresholds, int *rsopsl, msym_symmetry_operation_t **rsops){ msym_error_t ret = MSYM_SUCCESS; /*struct _pair { msym_element_t *e[2]; double d; } *pairs = malloc(sizeof(struct _pair[150]));*/ double c2d = 0, c4d = 0, sigmad = 0; int found = 0, nsigma = 0, esigma = 0, inversion = 0, nc[6] = {0,0,0,0,0,0}, ec[6] = {0,0,0,0,0,0}, *ncb = &nsigma, *nc3b = &nsigma; msym_symmetry_operation_t **(ac[6]); double thetac[6] = {0.0,M_PI,M_PI/2,M_PI/3,M_PI/4,M_PI/5}; msym_symmetry_operation_t *sops = malloc(sizeof(msym_symmetry_operation_t[120])); int sopsl = 0; double (**esv)[3] = malloc(sizeof(double (*[es->length])[3])); msym_symmetry_operation_t **sigma = malloc(16*sizeof(msym_symmetry_operation_t*)); //only 15, but we can overflow msym_symmetry_operation_t **c3b = NULL; msym_symmetry_operation_t **cb = sigma; msym_permutation_t perm; msym_symmetry_operation_t sopc = {.type = PROPER_ROTATION, .order = 2, .power = 1}; msym_symmetry_operation_t sopsigma = {.type = REFLECTION, .order = 1, .power = 1}; msym_symmetry_operation_t sopinversion = {.type = INVERSION, .order = 1, .power = 1, .v = {0,0,0}}; //15 C2 (I), 10 C3 (I), 3 C4 (O), 6 C5 (I) ac[0] = malloc((15+10+3+6)*sizeof(msym_symmetry_operation_t*)); ac[1] = ac[0]; ac[2] = ac[1]; ac[3] = ac[2] + 15; ac[4] = ac[3] + 10; ac[5] = ac[4] + 3; for(int i = 0; i < es->length;i++){ esv[i] = &es->elements[i]->v; } for(int i = 0; i < es->length && !found;i++){ for(int j = i+1;j < es->length;j++){ if(vparallel(es->elements[i]->v, es->elements[j]->v, thresholds->angle)) continue; double d; int psopsl = sopsl; vsub(es->elements[i]->v,es->elements[j]->v,sopsigma.v); d = vabs(sopsigma.v); vadd(es->elements[i]->v,es->elements[j]->v,sopc.v); vnorm(sopc.v); //vsub(es->elements[i]->v,es->elements[j]->v,sopsigma.v); vnorm(sopsigma.v); //Do this first, otherwise we might find a c2, at this distance and not look for more. if(es->length % 5 != 0 && (c4d == 0 || fabs(d - c4d)/(d + c4d) < thresholds->equivalence)){ sopc.order = 4; if(!findSymmetryOperation(&sopc, sops, sopsl, thresholds)){ if(MSYM_SUCCESS == findPermutation(&sopc, es->length, esv, thresholds, &perm)){ c4d = d; copySymmetryOperation(&sops[sopsl], &sopc); (ac[4])[nc[4]++] = &sops[sopsl++]; free(perm.p); free(perm.c); sopc.order = 2; if(!findSymmetryOperation(&sopc, sops, sopsl, thresholds)){ copySymmetryOperation(&sops[sopsl], &sopc); (ac[2])[nc[2]++] = &sops[sopsl++]; } } if(!findSymmetryOperation(&sopsigma, sops, sopsl, thresholds)){ if(MSYM_SUCCESS == findPermutation(&sopsigma, es->length, esv, thresholds, &perm)){ //sigmad = d; //This is a bit dangerous, but the C2 axes dhould generate the rest copySymmetryOperation(&sops[sopsl], &sopsigma); sigma[nsigma++] = &sops[sopsl++]; free(perm.p); free(perm.c); } } } sopc.order = 2; } if(c2d == 0 || fabs(d - c2d)/(d + c2d) < thresholds->equivalence){ if(!findSymmetryOperation(&sopc, sops, sopsl, thresholds)){ if(MSYM_SUCCESS == findPermutation(&sopc, es->length, esv, thresholds, &perm)){ c2d = d; copySymmetryOperation(&sops[sopsl], &sopc); (ac[2])[nc[2]++] = &sops[sopsl++]; free(perm.p); free(perm.c); } } } if(sigmad == 0 || fabs(d - sigmad)/(d + sigmad) < thresholds->equivalence){ if(!findSymmetryOperation(&sopsigma, sops, sopsl, thresholds)){ if(MSYM_SUCCESS == findPermutation(&sopsigma, es->length, esv, thresholds, &perm)){ sigmad = d; copySymmetryOperation(&sops[sopsl], &sopsigma); sigma[nsigma++] = &sops[sopsl++]; free(perm.p); free(perm.c); } } } //we have generated something, we have more than 2 operations if(sopsl > psopsl && sopsl >= 2 && !(nsigma == 15 && nc[2] == 0) && !(nsigma == 0 && nc[2] == 15)){ for(msym_symmetry_operation_t *sopi = sops; sopi < (sops + sopsl);sopi++){ for(msym_symmetry_operation_t *sopj = sops; sopj < (sops + sopsl); sopj++){ if(sopi == sopj) continue; if(sopi->type == PROPER_ROTATION && sopj->type == PROPER_ROTATION && sopj->order == 2 && vperpendicular(sopi->v, sopj->v, thresholds->angle)){ copySymmetryOperation(&sops[sopsl], sopj); vcrossnorm(sopi->v, sopj->v, sops[sopsl].v); if(!findSymmetryOperation(&sops[sopsl], sops, sopsl,thresholds)){ (ac[2])[nc[2]++] = &sops[sopsl++]; } } else if(!vparallel(sopi->v, sopj->v,thresholds->angle)){ copySymmetryOperation(&sops[sopsl], sopj); applySymmetryOperation(sopi,sops[sopsl].v,sops[sopsl].v); if(!findSymmetryOperation(&sops[sopsl], sops, sopsl,thresholds)){ if(sopj->type == REFLECTION){ sigma[nsigma++] = &sops[sopsl++]; } else { (ac[sopj->order])[nc[sopj->order]++] = &sops[sopsl++]; } } } if(nsigma > 15 || nc[2] > 15){ ret = MSYM_SYMMETRY_ERROR; msymSetErrorDetails("Inconsistency when generating symmetry axes for cubic point group, %d C2 axes, %d reflection planes",nc[2],nsigma); goto err; } } } } //A little speedup, I point group may require up to 5 iterations, to check if it might be an I if(((nsigma >= 3 || (nc[2] >= 3 && nsigma == 0)) && nc[4] == 0 && i > 3 && es->length % 5 != 0) || ((nsigma >= 9 || (nc[2] >= 9 && nsigma == 0)) && i > 0) || (nsigma == 15 && nc[2] == 15)){ found = 1; break; } if(nsigma == 0 && nc[2] == 0 && nc[4] == 0 && i > 3 && es->length > 120){ ret = MSYM_SYMMETRY_ERROR; msymSetErrorDetails("Found no symmetry operations in cubic group of size %d, thresholds are too high ",es->length); goto err; } } } if(MSYM_SUCCESS == findPermutation(&sopinversion, es->length, esv, thresholds, &perm)){ inversion = 1; copySymmetryOperation(&sops[sopsl++], &sopinversion); free(perm.p); free(perm.c); } esigma = (((nsigma+2) / 3) + (nsigma / 10) - (nsigma / 13))*3; esigma = esigma == 1 ? 0 : esigma; //We cannot generate the remaining axes from one sigma try to generate from C2 switch(esigma) { case 15 : ec[5] = 6; ec[3] = 10; ec[2] = 15; break; //Ih case 9 : ec[4] = 3; ec[3] = 4; ec[2] = 9; break; //Oh case 6 : { //Td or Oh (a cube won't generate the pair reflection planes, but we can look for inversion) if(inversion){ int gsigma = 0; ec[4] = 3; ec[3] = 4; ec[2] = 9; for(int i = 0; i < nsigma && gsigma < 3;i++){ for(int j = i+1; j < nsigma && gsigma < 3;j++){ double theta = vangle(sigma[i]->v, sigma[j]->v); if(fabs(theta - M_PI/2) < asin(thresholds->angle)){ sops[sopsl].type = REFLECTION; vadd(sigma[i]->v, sigma[j]->v, sops[sopsl].v); vnorm(sops[sopsl].v); if(!findSymmetryOperation(&(sops[sopsl]), sops, sopsl,thresholds)){ sigma[nsigma+gsigma++] = &(sops[sopsl++]); //gsigma++; //sopsl++; } if(gsigma < 3){ sops[sopsl].type = REFLECTION; vsub(sigma[i]->v, sigma[j]->v, sops[sopsl].v); vnorm(sops[sopsl].v); if(!findSymmetryOperation(&(sops[sopsl]), sops, sopsl,thresholds)){ sigma[nsigma+gsigma++] = &(sops[sopsl++]); //gsigma++; //sopsl++; } } } } } nsigma += gsigma; break; } else { ec[3] = 4; ec[2] = 3; break; } } case 3 : ec[3] = 4; ec[2] = 3; c3b = sigma; nc3b = &nsigma; break; //Th case 0 : { ec[2] = ((nc[2] > 0) + ((nc[2] > 3) << 1) + ((nc[2] > 9) << 1))*3; switch(ec[2]){ case 3 : ec[3] = 4; ec[2] = 3; c3b = ac[2]; nc3b = &(nc[2]); break; case 9 : ec[4] = 3; ec[3] = 4; ec[2] = 9; for(int i = 0; i < nc[2] && nc[4] < 3; i++){ //This should not happen anymore, but it may segfault on an error, so keep it for now int p = 0; for(int j = 0; j < nc[2] && nc[4] < 3; j++){ p += vperpendicular((ac[2])[i]->v, (ac[2])[j]->v,thresholds->angle); } if(p == 4){ sops[sopsl].type = PROPER_ROTATION; sops[sopsl].order = 4; sops[sopsl].power = 1; vcopy((ac[2])[i]->v,sops[sopsl].v); if(!findSymmetryOperation(&sops[sopsl], sops, sopsl,thresholds)){ (ac[4])[nc[4]] = &(sops[sopsl++]); nc[4]++; } } } c3b = ac[4]; nc3b = &(nc[4]); break; //Look for C2 that have 4 other perpendicular C2 this will be a C4 case 15 : ec[5] = 6; ec[3] = 10; ec[2] = 15; ncb = &(nc[2]); cb = ac[2]; break; default : msymSetErrorDetails("Unexpected number of C2 axes (%d) in cubic point group",ec[2]); ret = MSYM_SYMMETRY_ERROR; goto err; } break; } default : msymSetErrorDetails("Unexpected number of reflection planes (%d) in cubic point group",nsigma); ret = MSYM_SYMMETRY_ERROR; goto err; } //In a Th, we might not find the C3 axes so we generated them from the 3 reflection planes. //In the T, O, groups we generate them from C2 and C4 axes resp. //In I they will be generated later by the c2 axis (cbase = C2 in that case) if(c3b != NULL && nc[3] == 0 && *nc3b >= 3){ vadd(c3b[0]->v,c3b[1]->v,sops[sopsl].v); vadd(sops[sopsl].v,c3b[2]->v,sops[sopsl].v); vnorm(sops[sopsl].v); sops[sopsl].type = PROPER_ROTATION; sops[sopsl].order = 3; sops[sopsl].power = 1; (ac[3])[nc[3]] = &(sops[sopsl++]); //sopsl++; nc[3]++; vadd(c3b[0]->v,c3b[1]->v,sops[sopsl].v); vsub(sops[sopsl].v,c3b[2]->v,sops[sopsl].v); vnorm(sops[sopsl].v); sops[sopsl].type = PROPER_ROTATION; sops[sopsl].order = 3; sops[sopsl].power = 1; (ac[3])[nc[3]] = &(sops[sopsl++]); //sopsl++; nc[3]++; vadd(c3b[0]->v,c3b[2]->v,sops[sopsl].v); vsub(sops[sopsl].v,c3b[1]->v,sops[sopsl].v); vnorm(sops[sopsl].v); sops[sopsl].type = PROPER_ROTATION; sops[sopsl].order = 3; sops[sopsl].power = 1; (ac[3])[nc[3]] = &(sops[sopsl++]); //sopsl++; nc[3]++; vsub(c3b[0]->v,c3b[1]->v,sops[sopsl].v); vsub(sops[sopsl].v,c3b[2]->v,sops[sopsl].v); vnorm(sops[sopsl].v); sops[sopsl].type = PROPER_ROTATION; sops[sopsl].order = 3; sops[sopsl].power = 1; (ac[3])[nc[3]] = &(sops[sopsl++]); //sopsl++; nc[3]++; } found = nc[2] == ec[2] && nc[3] == ec[3] && nc[4] == ec[4] && nc[5] == ec[5]; for(int i = 0; i < *ncb && !found && sopsl < 120;i++){ for(int j = i+1; j < *ncb && !found;j++){ double theta = fabs(vangle(cb[i]->v, cb[j]->v)); if(theta > M_PI/2){ theta = M_PI - theta; } for(int k = 2; k < 6;k++){ if(fabs(theta - thetac[k]) < asin(thresholds->angle)){ vcrossnorm(cb[i]->v, cb[j]->v, sops[sopsl].v); sops[sopsl].type = PROPER_ROTATION; sops[sopsl].order = k; sops[sopsl].power = 1; if(!findSymmetryOperation(&(sops[sopsl]), sops, sopsl,thresholds)){ (ac[k])[nc[k]] = &(sops[sopsl]); sopsl++; nc[k]++; } break; } } found = nc[2] == ec[2] && nc[3] == ec[3] && nc[4] == ec[4] && nc[5] == ec[5]; } } int nS = 0; if(nsigma > 0){ for(int i = 0; i < sopsl && sopsl < 120;i++){ if(sops[i].type == PROPER_ROTATION){ //Td if(!inversion && sops[i].order == 2){ vcopy(sops[i].v, sops[sopsl].v); sops[sopsl].type = IMPROPER_ROTATION; sops[sopsl].order = 4; sops[sopsl].power = 1; sopsl++; nS++; } else if (inversion && sops[i].order > 2) { vcopy(sops[i].v, sops[sopsl].v); sops[sopsl].type = IMPROPER_ROTATION; sops[sopsl].order = sops[i].order + (sops[i].order % 2)*sops[i].order; sops[sopsl].power = 1; sopsl++; nS++; } } } } if(sopsl > 63) { msymSetErrorDetails("Generated more than 63 symmetry operations (%d) in cubic point group, not including powers",sopsl); ret = MSYM_SYMMETRY_ERROR; goto err; } *rsopsl = sopsl; *rsops = sops; free(esv); free(ac[0]); free(sigma); return ret; err: free(ac[0]); free(sigma); free(sops); free(esv); *rsopsl = 0; *rsops = NULL; return ret; } msym_error_t reduceSymmetry(int sopsl, msym_symmetry_operation_t sops[sopsl], msym_thresholds_t *thresholds, int *isopsl, msym_symmetry_operation_t **isops){ msym_error_t ret = MSYM_SUCCESS; int rsopsl = *isopsl; msym_symmetry_operation_t *rsops = *isops; msym_symmetry_operation_t *cinf[2] = {NULL,NULL}; int inv[2] = {0,0}; int inversion = 0; for(int i = 0;i < rsopsl;i++){ if(!((rsops[i].type == PROPER_ROTATION && rsops[i].order == 0) || rsops[i].type == INVERSION || rsops[i].type == REFLECTION)) break; if(inv[0] && cinf[0] != NULL) break; inv[0] = inv[0] || rsops[i].type == INVERSION; if(rsops[i].type == PROPER_ROTATION && rsops[i].order == 0) cinf[0] = &rsops[i]; } for(int i = 0;i < sopsl;i++){ if(!((sops[i].type == PROPER_ROTATION && sops[i].order == 0) || sops[i].type == INVERSION || sops[i].type == REFLECTION)) break; if(inv[1] && cinf[1] != NULL) break; inv[1] = inv[1] || sops[i].type == INVERSION; if(sops[i].type == PROPER_ROTATION && sops[i].order == 0) cinf[1] = &sops[i]; } inversion = inv[0] && inv[1]; if(cinf[0] != NULL && cinf[1] != NULL){ double cross[3]; int perpendicular = vperpendicular(cinf[0]->v,cinf[1]->v,thresholds->angle); int parallel = vparallel(cinf[0]->v,cinf[1]->v,thresholds->angle); vcrossnorm(cinf[0]->v, cinf[1]->v, cross); if(inversion && perpendicular){ double v[3]; vcopy(cinf[0]->v, v); rsops = realloc(rsops, sizeof(msym_symmetry_operation_t[7])); rsopsl = 7; rsops[0].type = INVERSION; rsops[0].v[0] = rsops[0].v[1] = rsops[0].v[2] = 0; rsops[0].order = 1; rsops[0].power = 1; rsops[1].type = REFLECTION; rsops[1].order = 1; rsops[1].power = 1; rsops[2].type = REFLECTION; rsops[2].order = 1; rsops[2].power = 1; rsops[3].type = REFLECTION; rsops[3].order = 1; rsops[3].power = 1; rsops[4].type = PROPER_ROTATION; rsops[4].order = 2; rsops[4].power = 1; rsops[5].type = PROPER_ROTATION; rsops[5].order = 2; rsops[5].power = 1; rsops[6].type = PROPER_ROTATION; rsops[6].order = 2; rsops[6].power = 1; vcopy(v, rsops[1].v); vcopy(cinf[1]->v, rsops[2].v); vcopy(cross, rsops[3].v); vcopy(v, rsops[4].v); vcopy(cinf[1]->v, rsops[5].v); vcopy(cross, rsops[6].v); } else if (inversion & !parallel){ rsops = realloc(rsops, sizeof(msym_symmetry_operation_t[3])); rsopsl = 3; rsops[0].type = INVERSION; rsops[0].v[0] = rsops[0].v[1] = rsops[0].v[2] = 0; rsops[0].order = 1; rsops[0].power = 1; rsops[1].type = REFLECTION; rsops[1].order = 1; rsops[1].power = 1; rsops[2].type = PROPER_ROTATION; rsops[2].order = 2; rsops[2].power = 1; vcopy(cross, rsops[1].v); vcopy(cross, rsops[2].v); } else if(perpendicular && !inv[0] && !inv[1]){ rsops = realloc(rsops, sizeof(msym_symmetry_operation_t[1])); rsopsl = 1; rsops[0].type = REFLECTION; vcopy(cross, rsops[0].v); } else if (perpendicular){ int index = inv[0] ? 0 : 1; double v[2][3]; vcopy(cinf[0]->v, v[0]); vcopy(cinf[1]->v, v[1]); rsops = realloc(rsops, sizeof(msym_symmetry_operation_t[3])); rsopsl = 3; rsops[0].type = REFLECTION; rsops[1].type = REFLECTION; rsops[2].type = PROPER_ROTATION; rsops[2].order = 2; rsops[2].power = 1; vcopy(cross, rsops[0].v); vcopy(v[index], rsops[1].v); vcopy(v[(index+1)%2], rsops[2].v); } else if (parallel){ if(MSYM_SUCCESS != (ret = filterSymmetryOperations(sopsl,sops,thresholds,&rsopsl,&rsops))) goto err; } else { rsops = realloc(rsops, sizeof(msym_symmetry_operation_t[1])); rsopsl = 1; rsops[0].type = REFLECTION; vcopy(cross, rsops[0].v); } } else if (cinf[0] != NULL){ double v[3]; vcopy(cinf[0]->v, v); for(int i = 0;i < sopsl;i++){ int add = 0; if(sops[i].type == IMPROPER_ROTATION){ add = vparallel(sops[i].v,v,thresholds->angle); } else if(sops[i].type == PROPER_ROTATION){ if(sops[i].order != 2){ add = vparallel(sops[i].v,v,thresholds->angle); } else { add = vparallel(sops[i].v,v,thresholds->angle) || (vperpendicular(sops[i].v,cinf[0]->v,thresholds->angle) && inv[0]); } } else if(sops[i].type == REFLECTION){ add = vperpendicular(sops[i].v,v,thresholds->angle); } if(add){ rsops = realloc(rsops, sizeof(msym_symmetry_operation_t[rsopsl+1])); copySymmetryOperation(&rsops[rsopsl], &sops[i]); rsopsl++; } } if(MSYM_SUCCESS != (ret = filterSymmetryOperations(sopsl,sops,thresholds,&rsopsl,&rsops))) goto err; } else if (cinf[1] != NULL){ for(int i = 0;i < rsopsl && rsopsl > 0;i++){ msym_symmetry_operation_t *fsop = findSymmetryOperation(&rsops[i], sops, sopsl,thresholds); if(!fsop){ int remove = 1; if(rsops[i].type == IMPROPER_ROTATION){ remove = !vparallel(rsops[i].v,cinf[1]->v,thresholds->angle); } else if(rsops[i].type == PROPER_ROTATION){ if(rsops[i].order != 2){ remove = !vparallel(rsops[i].v,cinf[1]->v,thresholds->angle); } else { remove = !(vparallel(rsops[i].v,cinf[1]->v,thresholds->angle) || (vperpendicular(rsops[i].v,cinf[1]->v,thresholds->angle) && inv[1])); } } else if(rsops[i].type == REFLECTION){ remove = !vperpendicular(rsops[i].v,cinf[1]->v,thresholds->angle); } if(remove){ rsopsl--; copySymmetryOperation(&rsops[i], &rsops[rsopsl]); rsops = realloc(rsops, sizeof(msym_symmetry_operation_t[rsopsl])); i--; } else if(vparallel(rsops[i].v,cinf[1]->v,thresholds->angle)){ if(vdot(rsops[i].v,cinf[1]->v) < 0){ vsub(rsops[i].v,cinf[1]->v,rsops[i].v); } else { vadd(rsops[i].v,cinf[1]->v,rsops[i].v); } } } } } else { if(MSYM_SUCCESS != (ret = filterSymmetryOperations(sopsl,sops,thresholds, &rsopsl,&rsops))) goto err; } *isopsl = rsopsl; *isops = rsops; return ret; err: return ret; } msym_error_t filterSymmetryOperations(int sopsl, msym_symmetry_operation_t sops[sopsl], msym_thresholds_t *thresholds, int *isopsl, msym_symmetry_operation_t **isops){ msym_error_t ret = MSYM_SUCCESS; int rsopsl = *isopsl; msym_symmetry_operation_t *rsops = *isops; for(int i = 0;i < rsopsl && rsopsl > 0;i++){ msym_symmetry_operation_t *fsop = findSymmetryOperation(&rsops[i], sops, sopsl,thresholds); if(!fsop){ rsopsl--; copySymmetryOperation(&rsops[i], &rsops[rsopsl]); rsops = realloc(rsops, sizeof(msym_symmetry_operation_t[rsopsl])); i--; } else if (rsops[i].type == PROPER_ROTATION || rsops[i].type == IMPROPER_ROTATION || rsops[i].type == REFLECTION){ if(vdot(rsops[i].v,fsop->v) < 0){ vsub(rsops[i].v,fsop->v,rsops[i].v); } else { vadd(rsops[i].v,fsop->v,rsops[i].v); } } } *isopsl = rsopsl; *isops = rsops; return ret; //err: // return ret; } int divisors(int n, int* div){ int max = floor(sqrt(n)); div[0] = n; int l = 1; for(int i = 2; i <= max;i++) { if(n % i == 0){ int fact = n/i; div[l++] = i; if(i != fact){ div[l++] = n/i; } } } return l; } v_sim-3.8.0/lib/plug-ins/msym/libmsym/src/symmetry.h000066400000000000000000000007761370110300500224350ustar00rootroot00000000000000// // symmetry.h // libmsym // // Created by Marcus Johansson on 12/04/14. // Copyright (c) 2014 Marcus Johansson. // // Distributed under the MIT License ( See LICENSE file or copy at http://opensource.org/licenses/MIT ) // #ifndef __MSYM_SYMMETRY_h #define __MSYM_SYMMETRY_h #include "msym.h" #include "symop.h" msym_error_t findSymmetryOperations(int esl, msym_equivalence_set_t es[esl], msym_thresholds_t *t, int *lsops, msym_symmetry_operation_t **sops); #endif /* defined(__MSYM_SYMMETRY_h) */ v_sim-3.8.0/lib/plug-ins/msym/libmsym/src/symop.c000066400000000000000000000243551370110300500217050ustar00rootroot00000000000000// // symop.c // Symmetry // // Created by Marcus Johansson on 30/10/14. // Copyright (c) 2014 Marcus Johansson. // // Distributed under the MIT License ( See LICENSE file or copy at http://opensource.org/licenses/MIT ) // #include #include #include "msym.h" #include "context.h" #include "symop.h" #include "linalg.h" #include "debug.h" #ifndef M_PI #define M_PI 3.14159265358979323846264338327950288419716939937510582 #endif int igcd(int a, int b); void symopPow(msym_symmetry_operation_t *A, int pow, msym_symmetry_operation_t *O){ double origo[3] = {0.0,0.0,0.0}; int apow, gcd; O->power = 1; O->orientation = A->orientation; switch (A->type){ case IDENTITY : O->type = IDENTITY; O->order = 0; vcopy(origo,O->v); break; case REFLECTION : case INVERSION : if(pow % 2 == 0){ O->type = IDENTITY; O->order = 0; vcopy(origo,O->v); } else { O->type = A->type; O->order = 0; vcopy(A->v,O->v); } break; case PROPER_ROTATION : // A->power = 0 is assumed to be uninitialized and set to 1 apow = A->power == 0 ? pow % A->order : (A->power*pow) % A->order; gcd = igcd(apow, A->order); if(apow == 0){ O->type = IDENTITY; O->order = 0; vcopy(origo,O->v); } else { O->type = PROPER_ROTATION; O->order = A->order/gcd; O->power = apow/gcd; vcopy(A->v,O->v); } break; case IMPROPER_ROTATION : A->type = PROPER_ROTATION; symopPow(A, pow, O); A->type = IMPROPER_ROTATION; apow = A->power == 0 ? pow % (2*A->order) : A->power*pow % (2*A->order); if(O->type == IDENTITY && pow == 0){} // Do nothing else if(O->type == IDENTITY && A->order % 2 == 1 && apow == A->order){ O->type = REFLECTION; O->order = 0; vcopy(A->v,O->v); } else { if (apow > A->order && A->order % 2 == 1 && apow % 2 == 1){ //if (apow > O->order && O->order % 2 == 1 && apow % 2 == 1){ O->power += A->order; O->power %= 2*O->order; } if(apow % 2 == 1){ O->type = IMPROPER_ROTATION; } if(O->type == IMPROPER_ROTATION && O->order == 2){ O->type = INVERSION; O->power = 1; } } default: break; } } #define PHI 1.618033988749894848204586834 double symmetryOperationCharacter(msym_symmetry_operation_t *sop, msym_basis_function_t *f){ double c = 0.0; switch (f->type) { case MSYM_BASIS_TYPE_REAL_SPHERICAL_HARMONIC: c = symmetryOperationYCharacter(sop,f->f.rsh.l); break; case MSYM_BASIS_TYPE_CARTESIAN : c = symmetryOperationCartesianCharacter(sop); break; default: break; } return c; } double symmetryOperationCartesianCharacter(msym_symmetry_operation_t *sop){ double x = 0.0; switch (sop->type) { case IDENTITY : x = 3; break; case INVERSION : x = -3; break; case REFLECTION : x = 1; break; case PROPER_ROTATION : x = 2*cos(sop->power*2*M_PI/sop->order) + 1; break; case IMPROPER_ROTATION : x = 2*cos(sop->power*2*M_PI/sop->order) - 1; break; default: break; } return x; } /* character of spherical harmonics basis */ double symmetryOperationYCharacter(msym_symmetry_operation_t *sop, int l){ double x = 0.0, a = sop->power*2*M_PI/sop->order; switch (sop->type) { case IDENTITY : x = 2*l+1; break; case INVERSION : x = (2*l+1)*(1 - ((l & 1) << 1)); break; case REFLECTION : x = 1; break; case PROPER_ROTATION : x = sin((l+0.5)*a)/sin(a/2); break; case IMPROPER_ROTATION : x = cos((l+0.5)*a)/cos(a/2); break; default: break; } return x; } void symmetryOperationName(msym_symmetry_operation_t* sop, int l, char buf[l]){ char *rn = ""; char *cn = ""; switch(sop->orientation){ case HORIZONTAL : rn = "h"; break; case VERTICAL : rn = "v"; cn = "'"; break; case DIHEDRAL : rn = "d"; cn = "''"; break; default: break; } switch (sop->type) { case PROPER_ROTATION : if(sop->order == 2) snprintf(buf, l, "C%d%s",sop->order,cn); else snprintf(buf, l, "C%d%s^%d",sop->order,cn,sop->power); break; case IMPROPER_ROTATION : snprintf(buf, l, "S%d^%d",sop->order,sop->power); break; case REFLECTION : snprintf(buf, l, "R%s",rn); break; case INVERSION : snprintf(buf, l, "i"); break; case IDENTITY : snprintf(buf, l, "E"); break; default : snprintf(buf, l, "?"); break; } } void symmetryOperationShortName(msym_symmetry_operation_t* sop, int l, char buf[l]){ switch (sop->type) { case PROPER_ROTATION : snprintf(buf, l, "C%d",sop->order); break; case IMPROPER_ROTATION : snprintf(buf, l, "S%d",sop->order); break; case REFLECTION : snprintf(buf, l, "R"); break; case INVERSION : snprintf(buf, l, "i"); break; case IDENTITY : snprintf(buf, l, "E"); break; default : snprintf(buf, l, "?"); break; } } void applySymmetryOperation(msym_symmetry_operation_t *sop,double iv[3], double ov[3]){ switch (sop->type) { case PROPER_ROTATION : { if(sop->order){ double theta = sop->power*2*M_PI/sop->order; vrotate(theta, iv, sop->v, ov); } else { // Treat C0 as a sum over all Cn operations i.e. a projection vproj(iv, sop->v, ov); } break; } case IMPROPER_ROTATION : { double theta = sop->power*2*M_PI/sop->order; vrotate(theta, iv, sop->v, ov); vreflect(ov, sop->v, ov); break; } case REFLECTION : vreflect(iv, sop->v, ov); break; case INVERSION : ov[0] = -iv[0]; ov[1] = -iv[1]; ov[2] = -iv[2]; break; case IDENTITY : ov[0] = iv[0]; ov[1] = iv[1]; ov[2] = iv[2]; break; default : fprintf(stderr,"UNKNOWN OPERATION\n"); //should never happen so will not handle this error atm } } void invertSymmetryOperation(msym_symmetry_operation_t *sop, msym_symmetry_operation_t *isop){ copySymmetryOperation(isop, sop); switch (sop->type) { case PROPER_ROTATION : { isop->power = sop->order - sop->power; break; } case IMPROPER_ROTATION : { if(sop->order % 2 == 0) isop->power = sop->order - sop->power; else isop->power = 2*sop->order - sop->power; break; } case REFLECTION : case INVERSION : case IDENTITY : break; default : fprintf(stderr,"UNKNOWN OPERATION\n"); //should never happen so will not handle this error atm } } void symmetryOperationMatrix(msym_symmetry_operation_t *sop, double m[3][3]){ switch (sop->type) { case PROPER_ROTATION : { if(sop->order){ double theta = sop->power*2*M_PI/sop->order; mrotate(theta, sop->v, m); } else { // Treat C0 as a sum over all Cn operations i.e. a projection kron2(3, 1, &sop->v, 1, 3, &sop->v, m); } break; } case IMPROPER_ROTATION : { double theta = sop->power*2*M_PI/sop->order; double m1[3][3], m2[3][3]; mrotate(theta, sop->v, m1); mreflect(sop->v, m2); mmmul(m2, m1, m); break; } case REFLECTION : mreflect(sop->v, m); break; case INVERSION : //TODO: fix this for(int i = 0; i < 3; i++){ for(int j = 0; j < 3; j++){ m[i][j] = -(i == j); } } break; case IDENTITY : for(int i = 0; i < 3; i++){ for(int j = 0; j < 3; j++){ m[i][j] = (i == j); } } break; default : fprintf(stderr,"UNKNOWN OPERATION\n"); //should never happen so will not handle this error atm } } void copySymmetryOperation(msym_symmetry_operation_t *dst, msym_symmetry_operation_t *src){ dst->type = src->type; dst->order = src->order; dst->power = src->power; dst->cla = src->cla; dst->orientation = src->orientation; vcopy(src->v, dst->v); } msym_symmetry_operation_t *findSymmetryOperation(msym_symmetry_operation_t *sop, msym_symmetry_operation_t *sops, int l, msym_thresholds_t *thresholds){ msym_symmetry_operation_t *fsop = NULL; for(msym_symmetry_operation_t* s = sops; s < (sops + l);s++){ if((s->type == INVERSION && sop->type == INVERSION) || (s->type == IDENTITY && sop->type == IDENTITY)){ fsop = s; break; } else if(s->type == sop->type && ((sop->type != PROPER_ROTATION && sop->type != IMPROPER_ROTATION) || (s->order == sop->order && s->power == sop->power)) && vparallel(s->v, sop->v,thresholds->angle)){ fsop = s; break; } } return fsop; } void printSymmetryOperation(msym_symmetry_operation_t *sop){ char buf[12]; symmetryOperationName(sop, 12, buf); if(sop->type == INVERSION || sop->type == IDENTITY) clean_debug_printf("%s(%d)\n",buf,sop->cla); else clean_debug_printf("%s(%d) [%lf;%lf;%lf]\n",buf,sop->cla, sop->v[0],sop->v[1],sop->v[2]); } int igcd(int a, int b) { int c; while (a) { c = a; a = b % a; b = c; } return abs(b); } v_sim-3.8.0/lib/plug-ins/msym/libmsym/src/symop.h000066400000000000000000000037551370110300500217130ustar00rootroot00000000000000// // symop.h // libmsym // // See accompanying file LICENSE // // Created by Marcus Johansson on 30/10/14. // Copyright (c) 2014 Marcus Johansson. // // Distributed under the MIT License ( See LICENSE file or copy at http://opensource.org/licenses/MIT ) // #ifndef __MSYM__SYMOP_h #define __MSYM__SYMOP_h #include "msym.h" /* external names make the code unreadable */ #define IDENTITY MSYM_SYMMETRY_OPERATION_TYPE_IDENTITY #define REFLECTION MSYM_SYMMETRY_OPERATION_TYPE_REFLECTION #define INVERSION MSYM_SYMMETRY_OPERATION_TYPE_INVERSION #define PROPER_ROTATION MSYM_SYMMETRY_OPERATION_TYPE_PROPER_ROTATION #define IMPROPER_ROTATION MSYM_SYMMETRY_OPERATION_TYPE_IMPROPER_ROTATION #define NONE MSYM_SYMMETRY_OPERATION_ORIENTATION_NONE #define HORIZONTAL MSYM_SYMMETRY_OPERATION_ORIENTATION_HORIZONTAL #define VERTICAL MSYM_SYMMETRY_OPERATION_ORIENTATION_VERTICAL #define DIHEDRAL MSYM_SYMMETRY_OPERATION_ORIENTATION_DIHEDRAL void symopPow(msym_symmetry_operation_t *A, int pow, msym_symmetry_operation_t *O); void applySymmetryOperation(msym_symmetry_operation_t *sop,double iv[3], double ov[3]); void symmetryOperationMatrix(msym_symmetry_operation_t *sop, double m[3][3]); double symmetryOperationCharacter(msym_symmetry_operation_t *sop, msym_basis_function_t *f); void copySymmetryOperation(msym_symmetry_operation_t *dst, msym_symmetry_operation_t *src); msym_symmetry_operation_t *findSymmetryOperation(msym_symmetry_operation_t*, msym_symmetry_operation_t*, int, msym_thresholds_t *thresholds); void invertSymmetryOperation(msym_symmetry_operation_t *sop, msym_symmetry_operation_t *isop); double symmetryOperationCartesianCharacter(msym_symmetry_operation_t *sop); double symmetryOperationYCharacter(msym_symmetry_operation_t *sop, int l); void symmetryOperationName(msym_symmetry_operation_t* sop, int l, char buf[l]); void symmetryOperationShortName(msym_symmetry_operation_t* sop, int l, char buf[l]); void printSymmetryOperation(msym_symmetry_operation_t *sop); #endif /* defined(__MSYM__SYMOP_h) */ v_sim-3.8.0/lib/plug-ins/msym/msym.c000066400000000000000000000221401370110300500172460ustar00rootroot00000000000000/* EXTRAITS DE LA LICENCE Copyright CEA, contributeurs : Damien CALISTE, laboratoire L_Sim, (2017) Adresse ml : CALISTE, damien P caliste AT cea P fr. Ce logiciel est un programme informatique servant visualiser des structures atomiques dans un rendu pseudo-3D. Ce logiciel est rgi par la licence CeCILL soumise au droit franais et respectant les principes de diffusion des logiciels libres. Vous pouvez utiliser, modifier et/ou redistribuer ce programme sous les conditions de la licence CeCILL telle que diffuse par le CEA, le CNRS et l'INRIA sur le site "http://www.cecill.info". Le fait que vous puissiez accder cet en-tte signifie que vous avez pris connaissance de la licence CeCILL, et que vous en avez accept les termes (cf. le fichier Documentation/licence.fr.txt fourni avec ce logiciel). */ /* LICENCE SUM UP Copyright CEA, contributors : Damien CALISTE, laboratoire L_Sim, (2017) E-mail address: CALISTE, damien P caliste AT cea P fr. This software is a computer program whose purpose is to visualize atomic configurations in 3D. This software is governed by the CeCILL license under French law and abiding by the rules of distribution of free software. You can use, modify and/ or redistribute the software under the terms of the CeCILL license as circulated by CEA, CNRS and INRIA at the following URL "http://www.cecill.info". The fact that you are presently reading this means that you have had knowledge of the CeCILL license and that you accept its terms. You can find a copy of this licence shipped with this software at Documentation/licence.en.txt. */ #include #include #include #include "support.h" #include "visu_tools.h" #include "visu_basic.h" #include "visu_data.h" #include "sym.h" #include "gtk_pick.h" #include "gtk_main.h" #include "extraGtkFunctions/gtk_numericalEntryWidget.h" #define MSYM_DESCRIPTION _("" \ "This plug-in introduces support for\n" \ "point group symmetry detection \n" \ "thanks to MSYM library (see \n" \ "http://github.com/mcodev31/libmsym).") #define MSYM_AUTHORS "Caliste Damien" #define MSYM_INFO \ _("left-button\t\t: select one atom to get the equivalent ones\n" \ "right-button\t\t: switch to observe") /* Local methods */ static void onSymClicked(VisuMolSymmetry *symmetry, GtkWidget *source); /* Local variables */ static gchar *iconPath; static VisuMolSymmetry *symmetry = NULL; /* Required methods for a loadable module. */ gboolean plugmsymInit() { DBG_fprintf(stderr, "Msym: loading plug-in 'plugmsym'...\n"); iconPath = g_build_filename(V_SIM_PIXMAPS_DIR, "msym.png", NULL); return TRUE; } static gboolean _toLblType(GBinding *bind _U_, const GValue *from, GValue *to, gpointer data _U_) { if (g_value_get_string(from)) g_value_take_string(to, g_strdup_printf(_("point group symmetry: %s"), g_value_get_string(from))); else g_value_set_static_string(to, ""); return TRUE; } static gboolean _toVisible(GBinding *bind _U_, const GValue *from, GValue *to, gpointer data _U_) { g_value_set_boolean(to, (g_value_get_string(from) && g_value_get_string(from)[0] != '\0')); return TRUE; } gboolean plugmsymInitGtk() { GtkWidget *bt; DBG_fprintf(stderr, "Msym: create a symmetry object.\n"); symmetry = visu_mol_symmetry_new(); g_object_bind_property(visu_ui_interactive_pick_getSelection(), "model", symmetry, "data", G_BINDING_SYNC_CREATE); g_object_bind_property(visu_ui_interactive_pick_getSelection(), "selection", symmetry, "nodes", G_BINDING_SYNC_CREATE); bt = gtk_button_new_with_label(""); gtk_button_set_relief(GTK_BUTTON(bt), GTK_RELIEF_NONE); gtk_box_pack_start(GTK_BOX(visu_ui_interactive_pick_getSelectionLabel()), bt, TRUE, FALSE, 0); gtk_widget_set_halign(bt, 0.5); g_object_bind_property_full(symmetry, "type", bt, "label", G_BINDING_SYNC_CREATE, _toLblType, NULL, (gpointer)0, (GDestroyNotify)0); g_object_bind_property_full(symmetry, "type", bt, "visible", G_BINDING_SYNC_CREATE, _toVisible, NULL, (gpointer)0, (GDestroyNotify)0); g_signal_connect_swapped(bt, "clicked", G_CALLBACK(onSymClicked), symmetry); return TRUE; } const char* plugmsymGet_description() { return MSYM_DESCRIPTION; } const char* plugmsymGet_authors() { return MSYM_AUTHORS; } const char* plugmsymGet_icon() { return iconPath; } void plugmsymFree(void) { if (symmetry) g_object_unref(symmetry); } static void _addThreshold(GtkBox *vbox, VisuMolSymmetry *symmetry, const gchar *label, const gchar *property) { GtkWidget *hbox, *wd; hbox = gtk_box_new(GTK_ORIENTATION_HORIZONTAL, 0); gtk_box_pack_start(vbox, hbox, FALSE, FALSE, 0); gtk_box_pack_start(GTK_BOX(hbox), gtk_label_new(label), FALSE, FALSE, 0); wd = visu_ui_numerical_entry_new(0.); gtk_entry_set_width_chars(GTK_ENTRY(wd), 6); g_object_bind_property(symmetry, property, wd, "value", G_BINDING_SYNC_CREATE | G_BINDING_BIDIRECTIONAL); gtk_box_pack_end(GTK_BOX(hbox), wd, FALSE, FALSE, 0); } static void _removePlane(VisuPlane *plane) { VisuGlNodeScene *scene; scene = visu_ui_rendering_window_getGlScene(visu_ui_main_class_getDefaultRendering()); if (scene) visu_plane_set_remove(visu_gl_node_scene_addPlanes(scene)->planes, plane); } static GtkWidget* _addSym(gpointer item, gpointer data _U_) { GtkWidget *hbox, *wd; gchar *lbl; VisuPlane *plane; float normal[3]; VisuMolSymmetryOp *op = VISU_MOL_SYMMETRY_OP(item); VisuGlNodeScene *scene; hbox = gtk_box_new(GTK_ORIENTATION_HORIZONTAL, 0); gtk_widget_set_margin_top(hbox, 2); gtk_widget_set_margin_bottom(hbox, 2); gtk_widget_set_margin_start(hbox, 10); gtk_widget_set_margin_end(hbox, 10); switch (visu_mol_symmetry_op_getType(op)) { case OPERATION_IDENTITY: gtk_box_pack_start(GTK_BOX(hbox), gtk_label_new(_("Identity")), FALSE, FALSE, 0); break; case OPERATION_ROTATION: gtk_box_pack_start(GTK_BOX(hbox), gtk_label_new(_("Rotation")), FALSE, FALSE, 0); break; case OPERATION_ROTATION_REFLEXION: gtk_box_pack_start(GTK_BOX(hbox), gtk_label_new(_("Rotation + reflexion")), FALSE, FALSE, 0); break; case OPERATION_REFLEXION: gtk_box_pack_start(GTK_BOX(hbox), gtk_label_new(_("Reflexion")), FALSE, FALSE, 0); plane = visu_mol_symmetry_op_getReflexion(op); visu_plane_getNVectUser(plane, normal); lbl = g_strdup_printf(_("Plane (%4.2f ; %4.2f ; %4.2f)"), normal[0], normal[1], normal[2]); wd = gtk_toggle_button_new_with_label(lbl); g_free(lbl); g_object_bind_property(plane, "rendered", wd, "active", G_BINDING_SYNC_CREATE | G_BINDING_BIDIRECTIONAL); gtk_box_pack_end(GTK_BOX(hbox), wd, FALSE, FALSE, 0); scene = visu_ui_rendering_window_getGlScene(visu_ui_main_class_getDefaultRendering()); visu_plane_set_add(visu_gl_node_scene_addPlanes(scene)->planes, plane); g_signal_connect_swapped(wd, "destroy", G_CALLBACK(_removePlane), plane); break; case OPERATION_INVERSION: gtk_box_pack_start(GTK_BOX(hbox), gtk_label_new(_("Inversion")), FALSE, FALSE, 0); break; } gtk_widget_show_all(hbox); return hbox; } static void _setHeader(GtkListBoxRow *row, GtkListBoxRow *before, gpointer data) { gchar *hd, *type; guint n; GtkWidget *lbl; if (before) return; g_object_get(data, "n-symmetries", &n, "type", &type, NULL); hd = g_strdup_printf(_("%d symmetries (%s)"), n, type); lbl = gtk_label_new(hd); gtk_label_set_use_markup(GTK_LABEL(lbl), TRUE); gtk_widget_set_margin_top(lbl, 5); gtk_list_box_row_set_header(row, lbl); g_free(hd); g_free(type); } static void onSymClicked(VisuMolSymmetry *symmetry, GtkWidget *source) { GtkWidget *pop, *vbox, *wd; pop = gtk_popover_new(source); gtk_popover_set_modal(GTK_POPOVER(pop), TRUE); vbox = gtk_box_new(GTK_ORIENTATION_VERTICAL, 0); gtk_container_add(GTK_CONTAINER(pop), vbox); gtk_container_set_border_width(GTK_CONTAINER(pop), 5); _addThreshold(GTK_BOX(vbox), symmetry, _("Geometry threshold:"), "threshold-geometry"); _addThreshold(GTK_BOX(vbox), symmetry, _("Angle threshold:"), "threshold-angle"); wd = gtk_list_box_new(); gtk_box_pack_start(GTK_BOX(vbox), wd, TRUE, TRUE, 0); gtk_list_box_set_selection_mode(GTK_LIST_BOX(wd), GTK_SELECTION_MULTIPLE); gtk_list_box_bind_model(GTK_LIST_BOX(wd), G_LIST_MODEL(symmetry), _addSym, (gpointer)0, (GDestroyNotify)0); gtk_list_box_set_header_func(GTK_LIST_BOX(wd), _setHeader, symmetry, (GDestroyNotify)0); gtk_widget_show_all(pop); } v_sim-3.8.0/lib/plug-ins/msym/msym.png000066400000000000000000000022301370110300500176060ustar00rootroot00000000000000PNG  IHDR VόsBIT|d pHYs}xtEXtSoftwarewww.inkscape.org<IDATHWML#e~f:3"(IeJ;O hlȁxMyo{bt^p\ @Fuu˕rЕ$y@]D@WW] Xuβeem/EQ(Mk$@8KT #ȳw1I]6e_(*Ayx !].Wj}}=iW@RQDQ+QB!NS3_|[ Ṫ*$Ix\b)_dqX .~6Sk~c1IENDB`v_sim-3.8.0/lib/plug-ins/msym/sym.c000066400000000000000000000576321370110300500171070ustar00rootroot00000000000000/* EXTRAITS DE LA LICENCE Copyright CEA, contributeurs : Damien CALISTE, laboratoire L_Sim, (2017) Adresse mèl : CALISTE, damien P caliste AT cea P fr. Ce logiciel est un programme informatique servant à visualiser des structures atomiques dans un rendu pseudo-3D. Ce logiciel est régi par la licence CeCILL soumise au droit français et respectant les principes de diffusion des logiciels libres. Vous pouvez utiliser, modifier et/ou redistribuer ce programme sous les conditions de la licence CeCILL telle que diffusée par le CEA, le CNRS et l'INRIA sur le site "http://www.cecill.info". Le fait que vous puissiez accéder à cet en-tête signifie que vous avez pris connaissance de la licence CeCILL, et que vous en avez accepté les termes (cf. le fichier Documentation/licence.fr.txt fourni avec ce logiciel). */ /* LICENCE SUM UP Copyright CEA, contributors : Damien CALISTE, laboratoire L_Sim, (2017) E-mail address: CALISTE, damien P caliste AT cea P fr. This software is a computer program whose purpose is to visualize atomic configurations in 3D. This software is governed by the CeCILL license under French law and abiding by the rules of distribution of free software. You can use, modify and/ or redistribute the software under the terms of the CeCILL license as circulated by CEA, CNRS and INRIA at the following URL "http://www.cecill.info". The fact that you are presently reading this means that you have had knowledge of the CeCILL license and that you accept its terms. You can find a copy of this licence shipped with this software at Documentation/licence.en.txt. */ #include "sym.h" #include #include #include /** * SECTION:mol_symmetry * @short_description: * */ struct _VisuMolSymmetryOpPrivate { gboolean dispose_has_run; guint id; VisuMolSymmetry *parent; msym_symmetry_operation_t op; VisuPlane *plane; }; struct _VisuMolSymmetryPrivate { gboolean dispose_has_run; VisuData *data; gulong popInc, popDec, posChg; GArray *nodes; msym_context ctx; msym_thresholds_t thresholds; GArray *syms; gboolean dirtyCtx; gboolean lock; }; enum { PROP_0, DATA_PROP, NODES_PROP, TYPE_PROP, THRESH_GEO_PROP, THRESH_ANG_PROP, NSYM_PROP, SYMS_PROP, LOCK_PROP, N_PROP }; static GParamSpec *_properties[N_PROP]; static void visu_mol_symmetry_dispose (GObject* obj); static void visu_mol_symmetry_get_property(GObject* obj, guint property_id, GValue *value, GParamSpec *pspec); static void visu_mol_symmetry_set_property(GObject* obj, guint property_id, const GValue *value, GParamSpec *pspec); static void visu_list_model_interface_init(GListModelInterface *iface); static GType _getItemType(GListModel *list); static guint _getNItems(GListModel *list); static gpointer _getItem(GListModel *list, guint at); G_DEFINE_TYPE_WITH_CODE(VisuMolSymmetry, visu_mol_symmetry, VISU_TYPE_OBJECT, G_ADD_PRIVATE(VisuMolSymmetry) G_IMPLEMENT_INTERFACE(G_TYPE_LIST_MODEL, visu_list_model_interface_init)) /* Local callbacks. */ static void _positionChanged(VisuMolSymmetry *symmetry, GArray *ids); /* Local routines. */ static gchar* _groupLabel(VisuMolSymmetry *symmetry); static void _symmetrize(VisuMolSymmetry *symmetry, const gchar *group); static void _setThresholds(VisuMolSymmetry *symmetry); static void visu_mol_symmetry_class_init(VisuMolSymmetryClass *klass) { DBG_fprintf(stderr, "Visu MolSymmetry: creating the class of the object.\n"); /* DBG_fprintf(stderr, " - adding new signals ;\n"); */ /* Connect the overloading methods. */ G_OBJECT_CLASS(klass)->dispose = visu_mol_symmetry_dispose; G_OBJECT_CLASS(klass)->set_property = visu_mol_symmetry_set_property; G_OBJECT_CLASS(klass)->get_property = visu_mol_symmetry_get_property; /** * VisuMolSymmetry::data: * * The #VisuData this symmetry is operating on. * * Since: 3.8 */ _properties[DATA_PROP] = g_param_spec_object ("data", "Data", "data model.", VISU_TYPE_DATA, G_PARAM_READWRITE); /** * VisuMolSymmetry::nodes: (element-type uint): * * The ids of selected nodes. * * Since: 3.8 */ _properties[NODES_PROP] = g_param_spec_boxed ("nodes", "Nodes", "ids of selected nodes.", G_TYPE_ARRAY, G_PARAM_READWRITE); /** * VisuMolSymmetry::type: * * The point group type. * * Since: 3.8 */ _properties[TYPE_PROP] = g_param_spec_string ("type", "Type", "point group type.", "", G_PARAM_READWRITE); /** * VisuMolSymmetry::threshold-geometry: * * The geometry threshold. * * Since: 3.8 */ _properties[THRESH_GEO_PROP] = g_param_spec_double ("threshold-geometry", "Geometry threshold", "threshold for geometry structures.", 0., 1., 0., G_PARAM_READWRITE); /** * VisuMolSymmetry::threshold-angle: * * The angle threshold for parallelism. * * Since: 3.8 */ _properties[THRESH_ANG_PROP] = g_param_spec_double ("threshold-angle", "Angle threshold", "threshold for parallelism.", 0., 1., 0., G_PARAM_READWRITE); /** * VisuMolSymmetry::n-symmetries: * * The number of symmetry operations. * * Since: 3.8 */ _properties[NSYM_PROP] = g_param_spec_uint ("n-symmetries", "N symmetries", "number of symmetry operations.", 0, G_MAXUINT, 0, G_PARAM_READABLE); /** * VisuMolSymmetry::symmetry-operations: (element-type VisuMolSymmetryOp*): * * The symmetry operations. * * Since: 3.8 */ _properties[SYMS_PROP] = g_param_spec_boxed ("symmetry-operations", "Symmetry operations", "symmetry operations.", G_TYPE_ARRAY, G_PARAM_READABLE); /** * VisuMolSymmetry::lock-geometry: * * Wether the node geometry should be locked to given symmetry. * * Since: 3.8 */ _properties[LOCK_PROP] = g_param_spec_boolean ("lock-geometry", "Lock geometry", "lock node geometry in the given symmetry.", FALSE, G_PARAM_READWRITE); g_object_class_install_properties(G_OBJECT_CLASS(klass), N_PROP, _properties); } static void visu_list_model_interface_init(GListModelInterface *iface) { iface->get_item_type = _getItemType; iface->get_n_items = _getNItems; iface->get_item = _getItem; } static void visu_mol_symmetry_init(VisuMolSymmetry *list) { DBG_fprintf(stderr, "Visu MolSymmetry: initializing a new object (%p).\n", (gpointer)list); list->priv = visu_mol_symmetry_get_instance_private(list); list->priv->dispose_has_run = FALSE; list->priv->data = (VisuData*)0; list->priv->nodes = (GArray*)0; list->priv->ctx = NULL; list->priv->syms = (GArray*)0; list->priv->lock = TRUE; } static void visu_mol_symmetry_dispose(GObject* obj) { VisuMolSymmetry *list; DBG_fprintf(stderr, "Visu MolSymmetry: dispose object %p.\n", (gpointer)obj); list = VISU_MOL_SYMMETRY(obj); if (list->priv->dispose_has_run) return; list->priv->dispose_has_run = TRUE; visu_mol_symmetry_setData(list, (VisuData*)0); visu_mol_symmetry_setNodes(list, (GArray*)0); /* Chain up to the parent class */ G_OBJECT_CLASS(visu_mol_symmetry_parent_class)->dispose(obj); } static void visu_mol_symmetry_get_property(GObject* obj, guint property_id, GValue *value, GParamSpec *pspec) { VisuMolSymmetry *self = VISU_MOL_SYMMETRY(obj); DBG_fprintf(stderr, "Visu MolSymmetry: get property '%s' -> ", g_param_spec_get_name(pspec)); switch (property_id) { case DATA_PROP: g_value_set_object(value, self->priv->data); DBG_fprintf(stderr, "%p.\n", g_value_get_object(value)); break; case NODES_PROP: g_value_set_boxed(value, self->priv->nodes); DBG_fprintf(stderr, "%p.\n", g_value_get_boxed(value)); break; case TYPE_PROP: g_value_take_string(value, _groupLabel(self)); DBG_fprintf(stderr, "%s.\n", g_value_get_string(value)); break; case THRESH_GEO_PROP: g_value_set_double(value, self->priv->thresholds.geometry); DBG_fprintf(stderr, "%g.\n", g_value_get_double(value)); break; case THRESH_ANG_PROP: g_value_set_double(value, self->priv->thresholds.angle); DBG_fprintf(stderr, "%g.\n", g_value_get_double(value)); break; case NSYM_PROP: g_value_set_uint(value, self->priv->syms ? self->priv->syms->len : 0); DBG_fprintf(stderr, "%d.\n", g_value_get_uint(value)); break; case SYMS_PROP: g_value_set_boxed(value, self->priv->syms); DBG_fprintf(stderr, "%p.\n", g_value_get_boxed(value)); break; case LOCK_PROP: g_value_set_boolean(value, self->priv->lock); DBG_fprintf(stderr, "%d.\n", g_value_get_boolean(value)); break; default: /* We don't have any other property... */ G_OBJECT_WARN_INVALID_PROPERTY_ID(obj, property_id, pspec); break; } } static void visu_mol_symmetry_set_property(GObject* obj, guint property_id, const GValue *value, GParamSpec *pspec) { VisuMolSymmetry *self = VISU_MOL_SYMMETRY(obj); DBG_fprintf(stderr, "Visu MolSymmetry: set property '%s'.\n", g_param_spec_get_name(pspec)); switch (property_id) { case DATA_PROP: visu_mol_symmetry_setData(self, VISU_DATA(g_value_get_object(value))); break; case NODES_PROP: visu_mol_symmetry_setNodes(self, (GArray*)g_value_get_boxed(value)); break; case TYPE_PROP: _symmetrize(self, g_value_get_string(value)); break; case THRESH_GEO_PROP: self->priv->thresholds.geometry = g_value_get_double(value); _setThresholds(self); break; case THRESH_ANG_PROP: self->priv->thresholds.angle = g_value_get_double(value); _setThresholds(self); break; case LOCK_PROP: visu_mol_symmetry_lock(self, g_value_get_boolean(value)); break; default: /* We don't have any other property... */ G_OBJECT_WARN_INVALID_PROPERTY_ID(obj, property_id, pspec); break; } } /** * visu_mol_symmetry_new: * * Create a new #GtkListStore to store planes. * * Since: 3.8 * * Returns: a newly created object. **/ VisuMolSymmetry* visu_mol_symmetry_new() { VisuMolSymmetry *list; list = VISU_MOL_SYMMETRY(g_object_new(VISU_TYPE_MOL_SYMMETRY, NULL)); return list; } static void _releaseContext(VisuMolSymmetry *symmetry) { guint nold; g_return_if_fail(VISU_IS_MOL_SYMMETRY_TYPE(symmetry)); if (symmetry->priv->ctx) { msymReleaseContext(symmetry->priv->ctx); symmetry->priv->ctx = NULL; } nold = 0; if (symmetry->priv->syms) { nold = symmetry->priv->syms->len; g_array_unref(symmetry->priv->syms); } symmetry->priv->syms = (GArray*)0; if (nold) g_list_model_items_changed(G_LIST_MODEL(symmetry), 0, nold, 0); } static void _setContext(VisuMolSymmetry *symmetry) { msym_element_t *elems; guint i; VisuNode *node; const gchar *name; msym_error_t err; float mass; const msym_thresholds_t *thresholds; g_return_if_fail(VISU_IS_MOL_SYMMETRY_TYPE(symmetry)); _releaseContext(symmetry); if (!symmetry->priv->data || !symmetry->priv->nodes || symmetry->priv->nodes->len < 3) { g_object_notify_by_pspec(G_OBJECT(symmetry), _properties[TYPE_PROP]); return; } symmetry->priv->ctx = msymCreateContext(); g_return_if_fail(symmetry->priv->ctx); elems = g_malloc(sizeof(msym_element_t) * symmetry->priv->nodes->len); for (i = 0; i < symmetry->priv->nodes->len; i++) { float xyz[3]; node = visu_node_array_getFromId(VISU_NODE_ARRAY(symmetry->priv->data), g_array_index(symmetry->priv->nodes, guint, i)); g_return_if_fail(node); name = visu_element_getName(visu_node_array_getElement(VISU_NODE_ARRAY(symmetry->priv->data), node)); visu_data_getNodePosition(symmetry->priv->data, node, xyz); elems[i].v[0] = xyz[0]; elems[i].v[1] = xyz[1]; elems[i].v[2] = xyz[2]; tool_physic_getZFromSymbol(&elems[i].n, NULL, &mass, name); elems[i].m = mass; strncpy(elems[i].name, name, 3); elems[i].name[3] = '\0'; } if ((err = msymSetElements(symmetry->priv->ctx, symmetry->priv->nodes->len, elems)) != MSYM_SUCCESS) goto error; elems = NULL; if ((err = msymGetThresholds(symmetry->priv->ctx, &thresholds)) != MSYM_SUCCESS) goto error; symmetry->priv->thresholds = *thresholds; symmetry->priv->dirtyCtx = TRUE; g_object_notify_by_pspec(G_OBJECT(symmetry), _properties[TYPE_PROP]); return; error: g_warning("%s: %s.", msymErrorString(err), msymGetErrorDetails()); g_free(elems); msymReleaseContext(symmetry->priv->ctx); symmetry->priv->ctx = NULL; return; } static gboolean _resetContext(gpointer symmetry) { _setContext(VISU_MOL_SYMMETRY(symmetry)); return G_SOURCE_REMOVE; } /** * visu_mol_symmetry_setData: * @selection: a #VisuMolSymmetry object. * @data: (allow-none): a #VisuData object. * * Bind the @set object to @list. * * Returns: TRUE if @set is changed **/ gboolean visu_mol_symmetry_setData(VisuMolSymmetry *symmetry, VisuData *data) { g_return_val_if_fail(VISU_IS_MOL_SYMMETRY_TYPE(symmetry), FALSE); if (symmetry->priv->data == data) return FALSE; _releaseContext(symmetry); if (symmetry->priv->data) { g_signal_handler_disconnect(symmetry->priv->data, symmetry->priv->popInc); g_signal_handler_disconnect(symmetry->priv->data, symmetry->priv->popDec); g_signal_handler_disconnect(symmetry->priv->data, symmetry->priv->posChg); g_object_unref(symmetry->priv->data); } symmetry->priv->data = data; if (data) { g_object_ref(data); symmetry->priv->popInc = g_signal_connect_swapped (data, "PopulationIncrease", G_CALLBACK(_setContext), symmetry); symmetry->priv->popDec = g_signal_connect_swapped (data, "PopulationDecrease", G_CALLBACK(_setContext), symmetry); symmetry->priv->posChg = g_signal_connect_swapped (data, "position-changed", G_CALLBACK(_positionChanged), symmetry); _setContext(symmetry); } return TRUE; } /** * visu_mol_symmetry_setData: * @selection: a #VisuMolSymmetry object. * @data: (allow-none): a #VisuData object. * * Bind the @set object to @list. * * Returns: TRUE if @set is changed **/ gboolean visu_mol_symmetry_setNodes(VisuMolSymmetry *symmetry, GArray *nodes) { g_return_val_if_fail(VISU_IS_MOL_SYMMETRY_TYPE(symmetry), FALSE); if (symmetry->priv->nodes) { g_array_unref(symmetry->priv->nodes); } symmetry->priv->nodes = nodes; if (nodes) { g_array_ref(nodes); } _setContext(symmetry); return TRUE; } static void _clearSyms(gpointer *item) { g_object_unref(*item); } static void _compute(VisuMolSymmetry *symmetry) { msym_error_t err; guint nold; int i, nsym; const msym_symmetry_operation_t *syms; VisuMolSymmetryOp *op; g_return_if_fail(VISU_IS_MOL_SYMMETRY_TYPE(symmetry)); if (!symmetry->priv->ctx) return; DBG_fprintf(stderr, "Msym: computing symmetries.\n"); if ((err = msymFindSymmetry(symmetry->priv->ctx)) != MSYM_SUCCESS) g_message("%s: %s.", msymErrorString(err), msymGetErrorDetails()); if ((err = msymGetSymmetryOperations(symmetry->priv->ctx, &nsym, &syms)) != MSYM_SUCCESS) g_message("%s: %s.", msymErrorString(err), msymGetErrorDetails()); nold = 0; if (symmetry->priv->syms) { nold = symmetry->priv->syms->len; g_array_unref(symmetry->priv->syms); } symmetry->priv->syms = g_array_sized_new(FALSE, FALSE, sizeof(VisuMolSymmetryOp*), nsym); g_array_set_clear_func(symmetry->priv->syms, (GDestroyNotify)_clearSyms); for (i = 0; i < nsym; i++) { op = g_object_new(VISU_TYPE_MOL_SYMMETRY_OP, NULL); op->priv->id = (guint)i; op->priv->parent = g_object_ref(symmetry); op->priv->op = syms[i]; g_array_append_val(symmetry->priv->syms, op); } if ((err = msymFindEquivalenceSets(symmetry->priv->ctx)) != MSYM_SUCCESS) g_message("%s: %s.", msymErrorString(err), msymGetErrorDetails()); symmetry->priv->dirtyCtx = FALSE; g_object_notify_by_pspec(G_OBJECT(symmetry), _properties[NSYM_PROP]); g_list_model_items_changed(G_LIST_MODEL(symmetry), 0, nold, nsym); } static gchar* _groupLabel(VisuMolSymmetry *symmetry) { msym_error_t err; char buf[256]; g_return_val_if_fail(VISU_IS_MOL_SYMMETRY_TYPE(symmetry), (gchar*)0); if (!symmetry->priv->ctx) return (gchar*)0; if (symmetry->priv->dirtyCtx) _compute(symmetry); if ((err = msymGetPointGroupName(symmetry->priv->ctx, 256, buf)) != MSYM_SUCCESS) { g_message("%s: %s.", msymErrorString(err), msymGetErrorDetails()); return (gchar*)0; } return g_strdup(buf); } static void _setThresholds(VisuMolSymmetry *symmetry) { msym_error_t err; g_return_if_fail(VISU_IS_MOL_SYMMETRY_TYPE(symmetry)); if (!symmetry->priv->ctx) return; if ((err = msymSetThresholds(symmetry->priv->ctx, &symmetry->priv->thresholds)) != MSYM_SUCCESS) g_message("%s: %s.", msymErrorString(err), msymGetErrorDetails()); symmetry->priv->dirtyCtx = TRUE; g_object_notify_by_pspec(G_OBJECT(symmetry), _properties[TYPE_PROP]); } static void _symmetrize(VisuMolSymmetry *symmetry, const gchar *group) { msym_error_t err; double max; guint i; VisuNode *node; GArray *xyz; int nelems; msym_element_t *elems; g_return_if_fail(VISU_IS_MOL_SYMMETRY_TYPE(symmetry)); if (!symmetry->priv->ctx) return; if ((err = msymSetPointGroupByName(symmetry->priv->ctx, group)) != MSYM_SUCCESS) { g_message("here"); g_message("%s: %s.", msymErrorString(err), msymGetErrorDetails()); return; } if ((err = msymSymmetrizeElements(symmetry->priv->ctx, &max)) != MSYM_SUCCESS) { g_message("there"); g_message("%s: %s.", msymErrorString(err), msymGetErrorDetails()); g_idle_add(_resetContext, symmetry); return; } if ((err = msymGetElements(symmetry->priv->ctx, &nelems, &elems)) != MSYM_SUCCESS) { g_message("%s: %s.", msymErrorString(err), msymGetErrorDetails()); return; } g_return_if_fail((guint)nelems == symmetry->priv->nodes->len); g_message("Max error when symmetrizing: %g.\n", max); xyz = g_array_new(FALSE, FALSE, sizeof(float) * 3 * symmetry->priv->nodes->len); for (i = 0; i < symmetry->priv->nodes->len; i++) { node = visu_node_array_getFromId(VISU_NODE_ARRAY(symmetry->priv->data), g_array_index(symmetry->priv->nodes, guint, i)); g_return_if_fail(node); g_array_index(xyz, float, 3 * i + 0) = elems[i].v[0]; g_array_index(xyz, float, 3 * i + 1) = elems[i].v[1]; g_array_index(xyz, float, 3 * i + 2) = elems[i].v[2]; } visu_node_array_moveNodes(VISU_NODE_ARRAY(symmetry->priv->data), symmetry->priv->nodes, xyz); g_array_unref(xyz); } static GType _getItemType(GListModel *list _U_) { return VISU_TYPE_MOL_SYMMETRY_OP; } static guint _getNItems(GListModel *list) { VisuMolSymmetry *self = VISU_MOL_SYMMETRY(list); return self && self->priv->syms ? self->priv->syms->len : 0; } static gpointer _getItem(GListModel *list, guint at) { VisuMolSymmetry *self = VISU_MOL_SYMMETRY(list); return self && self->priv->syms && at < self->priv->syms->len ? g_object_ref(g_array_index(self->priv->syms, gpointer, at)) : (gpointer)0; } static void visu_mol_symmetry_op_dispose(GObject* obj); G_DEFINE_TYPE_WITH_CODE(VisuMolSymmetryOp, visu_mol_symmetry_op, VISU_TYPE_OBJECT, G_ADD_PRIVATE(VisuMolSymmetryOp)) static void visu_mol_symmetry_op_class_init(VisuMolSymmetryOpClass *klass) { DBG_fprintf(stderr, "Visu MolSymmetryOp: creating the class of the object.\n"); G_OBJECT_CLASS(klass)->dispose = visu_mol_symmetry_op_dispose; } static void visu_mol_symmetry_op_init(VisuMolSymmetryOp *list) { DBG_fprintf(stderr, "Visu MolSymmetryOp: initializing a new object (%p).\n", (gpointer)list); list->priv = visu_mol_symmetry_op_get_instance_private(list); list->priv->dispose_has_run = FALSE; list->priv->parent = (VisuMolSymmetry*)0; list->priv->plane = (VisuPlane*)0; } static void visu_mol_symmetry_op_dispose(GObject* obj) { VisuMolSymmetryOp *list; DBG_fprintf(stderr, "Visu MolSymmetryOp: dispose object %p.\n", (gpointer)obj); list = VISU_MOL_SYMMETRY_OP(obj); if (list->priv->dispose_has_run) return; list->priv->dispose_has_run = TRUE; if (list->priv->parent) g_object_unref(list->priv->parent); if (list->priv->plane) g_object_unref(list->priv->plane); G_OBJECT_CLASS(visu_mol_symmetry_op_parent_class)->dispose(obj); } VisuMolSymmetryOpTypes visu_mol_symmetry_op_getType(const VisuMolSymmetryOp *op) { g_return_val_if_fail(VISU_IS_MOL_SYMMETRY_OP_TYPE(op), OPERATION_IDENTITY); return op->priv->op.type; } VisuPlane* visu_mol_symmetry_op_getReflexion(const VisuMolSymmetryOp *op) { double cm[3]; float normal[3], origin[3]; g_return_val_if_fail(VISU_IS_MOL_SYMMETRY_OP_TYPE(op), (VisuPlane*)0); if (op->priv->op.type != MSYM_SYMMETRY_OPERATION_TYPE_REFLECTION) return (VisuPlane*)0; if (op->priv->plane) return op->priv->plane; msymGetCenterOfMass(op->priv->parent->priv->ctx, cm); op->priv->plane = visu_plane_newUndefined(); normal[0] = op->priv->op.v[0]; normal[1] = op->priv->op.v[1]; normal[2] = op->priv->op.v[2]; visu_plane_setNormalVector(op->priv->plane, normal); origin[0] = cm[0]; origin[1] = cm[1]; origin[2] = cm[2]; visu_plane_setOrigin(op->priv->plane, origin); visu_plane_setColor(op->priv->plane, tool_color_new_bright(op->priv->id)); visu_plane_setRendered(op->priv->plane, FALSE); return op->priv->plane; } gboolean visu_mol_symmetry_op_getRotation(const VisuMolSymmetryOp *op, float *angle, float axis[3], float origin[3]) { double cm[3]; g_return_val_if_fail(VISU_IS_MOL_SYMMETRY_OP_TYPE(op), FALSE); if (op->priv->op.type != MSYM_SYMMETRY_OPERATION_TYPE_PROPER_ROTATION) return FALSE; msymGetCenterOfMass(op->priv->parent->priv->ctx, cm); origin[0] = cm[0]; origin[1] = cm[1]; origin[2] = cm[2]; *angle = 360 / op->priv->op.order; axis[0] = op->priv->op.v[0]; axis[1] = op->priv->op.v[1]; axis[2] = op->priv->op.v[2]; return TRUE; } static void _symmetrise(VisuMolSymmetry *symmetry) { msym_error_t err; double delta; if ((err = msymSymmetrizeElements(symmetry->priv->ctx, &delta)) != MSYM_SUCCESS) g_message("%s: %s.", msymErrorString(err), msymGetErrorDetails()); /* g_signal_handler_block(symmetry->priv->data, symmetry->priv->posChg); */ /* g_signal_emit_by_name(symmetry->priv->data, "position-changed", */ /* symmetry->priv->nodes); */ /* g_signal_handler_unblock(symmetry->priv->data, symmetry->priv->posChg); */ } static void _positionChanged(VisuMolSymmetry *symmetry, GArray *ids) { gboolean reset; guint i, j; g_return_if_fail(VISU_IS_MOL_SYMMETRY_TYPE(symmetry)); if (ids && symmetry->priv->nodes) { reset = FALSE; for (i = 0; i < ids->len && !reset; i++) for (j = 0; j < symmetry->priv->nodes->len && !reset; j++) reset = (g_array_index(ids, guint, i) == g_array_index(symmetry->priv->nodes, guint, j)); } else reset = TRUE; if (!reset) return; DBG_fprintf(stderr, "Plugin Sym: got position-changed.\n"); if (symmetry->priv->lock) _symmetrise(symmetry); else _setContext(symmetry); } gboolean visu_mol_symmetry_lock(VisuMolSymmetry *symmetry, gboolean status) { g_return_val_if_fail(VISU_IS_MOL_SYMMETRY_TYPE(symmetry), FALSE); if (symmetry->priv->lock == status) return FALSE; symmetry->priv->lock = status; g_object_notify_by_pspec(G_OBJECT(symmetry), _properties[LOCK_PROP]); return TRUE; } v_sim-3.8.0/lib/plug-ins/msym/sym.h000066400000000000000000000157141370110300500171070ustar00rootroot00000000000000/* EXTRAITS DE LA LICENCE Copyright CEA, contributeurs : Damien CALISTE, laboratoire L_Sim, (2017) Adresse mèl : CALISTE, damien P caliste AT cea P fr. Ce logiciel est un programme informatique servant à visualiser des structures atomiques dans un rendu pseudo-3D. Ce logiciel est régi par la licence CeCILL soumise au droit français et respectant les principes de diffusion des logiciels libres. Vous pouvez utiliser, modifier et/ou redistribuer ce programme sous les conditions de la licence CeCILL telle que diffusée par le CEA, le CNRS et l'INRIA sur le site "http://www.cecill.info". Le fait que vous puissiez accéder à cet en-tête signifie que vous avez pris connaissance de la licence CeCILL, et que vous en avez accepté les termes (cf. le fichier Documentation/licence.fr.txt fourni avec ce logiciel). */ /* LICENCE SUM UP Copyright CEA, contributors : Damien CALISTE, laboratoire L_Sim, (2017) E-mail address: CALISTE, damien P caliste AT cea P fr. This software is a computer program whose purpose is to visualize atomic configurations in 3D. This software is governed by the CeCILL license under French law and abiding by the rules of distribution of free software. You can use, modify and/ or redistribute the software under the terms of the CeCILL license as circulated by CEA, CNRS and INRIA at the following URL "http://www.cecill.info". The fact that you are presently reading this means that you have had knowledge of the CeCILL license and that you accept its terms. You can find a copy of this licence shipped with this software at Documentation/licence.en.txt. */ #ifndef VISU_MOL_SYMMETRY_H #define VISU_MOL_SYMMETRY_H #include #include #include #include #include /***************/ /* Public part */ /***************/ /** * VISU_TYPE_MOL_SYMMETRY: * * return the type of #VisuMolSymmetry. */ #define VISU_TYPE_MOL_SYMMETRY (visu_mol_symmetry_get_type ()) /** * VISU_MOL_SYMMETRY: * @obj: a #GObject to cast. * * Cast the given @obj into #VisuMolSymmetry type. */ #define VISU_MOL_SYMMETRY(obj) (G_TYPE_CHECK_INSTANCE_CAST(obj, VISU_TYPE_MOL_SYMMETRY, VisuMolSymmetry)) /** * VISU_MOL_SYMMETRY_CLASS: * @klass: a #GObjectClass to cast. * * Cast the given @klass into #VisuMolSymmetryClass. */ #define VISU_MOL_SYMMETRY_CLASS(klass) (G_TYPE_CHECK_CLASS_CAST(klass, VISU_TYPE_MOL_SYMMETRY, VisuMolSymmetryClass)) /** * VISU_IS_MOL_SYMMETRY_TYPE: * @obj: a #GObject to test. * * Test if the given @ogj is of the type of #VisuMolSymmetry object. */ #define VISU_IS_MOL_SYMMETRY_TYPE(obj) (G_TYPE_CHECK_INSTANCE_TYPE(obj, VISU_TYPE_MOL_SYMMETRY)) /** * VISU_IS_MOL_SYMMETRY_CLASS: * @klass: a #GObjectClass to test. * * Test if the given @klass is of the type of #VisuMolSymmetryClass class. */ #define VISU_IS_MOL_SYMMETRY_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE(klass, VISU_TYPE_MOL_SYMMETRY)) /** * VISU_MOL_SYMMETRY_GET_CLASS: * @obj: a #GObject to get the class of. * * It returns the class of the given @obj. */ #define VISU_MOL_SYMMETRY_GET_CLASS(obj) (G_TYPE_INSTANCE_GET_CLASS(obj, VISU_TYPE_MOL_SYMMETRY, VisuMolSymmetryClass)) /** * VisuMolSymmetryPrivate: * * Private data for #VisuMolSymmetry objects. */ typedef struct _VisuMolSymmetryPrivate VisuMolSymmetryPrivate; /** * VisuMolSymmetry: * * Common name to refer to a #_VisuMolSymmetry. */ typedef struct _VisuMolSymmetry VisuMolSymmetry; struct _VisuMolSymmetry { VisuObject parent; VisuMolSymmetryPrivate *priv; }; /** * VisuMolSymmetryClass: * @parent: private. * * Common name to refer to a #_VisuMolSymmetryClass. */ typedef struct _VisuMolSymmetryClass VisuMolSymmetryClass; struct _VisuMolSymmetryClass { VisuObjectClass parent; }; /** * visu_mol_symmetry_get_type: * * This method returns the type of #VisuMolSymmetry, use * VISU_TYPE_MOL_SYMMETRY instead. * * Since: 3.8 * * Returns: the type of #VisuMolSymmetry. */ GType visu_mol_symmetry_get_type(void); VisuMolSymmetry* visu_mol_symmetry_new(); gboolean visu_mol_symmetry_setData(VisuMolSymmetry *symmetry, VisuData *data); gboolean visu_mol_symmetry_setNodes(VisuMolSymmetry *symmetry, GArray *nodes); gboolean visu_mol_symmetry_lock(VisuMolSymmetry *symmetry, gboolean status); /** * VISU_TYPE_MOL_SYMMETRY_OP: * * return the type of #VisuMolSymmetryOp. */ #define VISU_TYPE_MOL_SYMMETRY_OP (visu_mol_symmetry_op_get_type ()) /** * VISU_MOL_SYMMETRY_OP: * @obj: a #GObject to cast. * * Cast the given @obj into #VisuMolSymmetryOp type. */ #define VISU_MOL_SYMMETRY_OP(obj) (G_TYPE_CHECK_INSTANCE_CAST(obj, VISU_TYPE_MOL_SYMMETRY_OP, VisuMolSymmetryOp)) /** * VISU_MOL_SYMMETRY_OP_CLASS: * @klass: a #GObjectClass to cast. * * Cast the given @klass into #VisuMolSymmetryOpClass. */ #define VISU_MOL_SYMMETRY_OP_CLASS(klass) (G_TYPE_CHECK_CLASS_CAST(klass, VISU_TYPE_MOL_SYMMETRY_OP, VisuMolSymmetryOpClass)) /** * VISU_IS_MOL_SYMMETRY_OP_TYPE: * @obj: a #GObject to test. * * Test if the given @ogj is of the type of #VisuMolSymmetryOp object. */ #define VISU_IS_MOL_SYMMETRY_OP_TYPE(obj) (G_TYPE_CHECK_INSTANCE_TYPE(obj, VISU_TYPE_MOL_SYMMETRY_OP)) /** * VISU_IS_MOL_SYMMETRY_OP_CLASS: * @klass: a #GObjectClass to test. * * Test if the given @klass is of the type of #VisuMolSymmetryOpClass class. */ #define VISU_IS_MOL_SYMMETRY_OP_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE(klass, VISU_TYPE_MOL_SYMMETRY_OP)) /** * VISU_MOL_SYMMETRY_OP_GET_CLASS: * @obj: a #GObject to get the class of. * * It returns the class of the given @obj. */ #define VISU_MOL_SYMMETRY_OP_GET_CLASS(obj) (G_TYPE_INSTANCE_GET_CLASS(obj, VISU_TYPE_MOL_SYMMETRY_OP, VisuMolSymmetryOpClass)) typedef struct _VisuMolSymmetryOpPrivate VisuMolSymmetryOpPrivate; /** * VisuMolSymmetryOp: * * Common name to refer to a #_VisuMolSymmetryOp. */ typedef struct _VisuMolSymmetryOp VisuMolSymmetryOp; struct _VisuMolSymmetryOp { VisuObject parent; VisuMolSymmetryOpPrivate *priv; }; /** * VisuMolSymmetryOpClass: * @parent: private. * * Common name to refer to a #_VisuMolSymmetryOpClass. */ typedef struct _VisuMolSymmetryOpClass VisuMolSymmetryOpClass; struct _VisuMolSymmetryOpClass { VisuObjectClass parent; }; GType visu_mol_symmetry_op_get_type(void); typedef enum _VisuMolSymmetryOpTypes { OPERATION_IDENTITY, OPERATION_ROTATION, OPERATION_ROTATION_REFLEXION, OPERATION_REFLEXION, OPERATION_INVERSION } VisuMolSymmetryOpTypes; typedef enum _VisuMolSymmetryOpOrientations { ORIENTATION_NONE, ORIENTATION_HORIZONTAL, ORIENTATION_VERTICAL, ORIENTATION_DIHEDRAL } VisuMolSymmetryOpOrientations; VisuMolSymmetryOpTypes visu_mol_symmetry_op_getType(const VisuMolSymmetryOp *op); VisuPlane* visu_mol_symmetry_op_getReflexion(const VisuMolSymmetryOp *op); gboolean visu_mol_symmetry_op_getRotation(const VisuMolSymmetryOp *op, float *angle, float axis[3], float origin[3]); #endif v_sim-3.8.0/lib/plug-ins/nanoquanta-netcdf/000077500000000000000000000000001370110300500205375ustar00rootroot00000000000000v_sim-3.8.0/lib/plug-ins/nanoquanta-netcdf/Makefile.am000066400000000000000000000016021370110300500225720ustar00rootroot00000000000000## Process this file with automake to produce Makefile.in vpath %.h $(top_srcdir)/src if PLATFORM_WIN32 cflagWin = -mms-bitfields -mno-cygwin endif libetsf_la_SOURCES = nq_basic.c nq_basic.h \ nq_structure.c nq_structure.h \ nq_density.c nq_density.h libetsf_la_LIBADD = $(top_builddir)/src/libv_sim-3.la \ $(NC_LDFLAGS) $(NC_LIBS) @GLIB_LIBS@ libetsf_la_LDFLAGS = -module @EXTRA_LDFLAGS@ -version-info $(lib_v_sim_version) if HAVE_ETSF NQ_LIB = libetsf.la NQ_EXAMPLE = nq-netcdf.nc \ nq-netcdf.cdl \ silane.nc \ si1002x1-o_DS1_DEN-etsf.nc NQ_PIX = nanoquanta.png endif v_simplugins_LTLIBRARIES = \ $(NQ_LIB) AM_CPPFLAGS = \ -I$(top_srcdir)/src \ @GLIB_CFLAGS@ \ $(NC_NETCDF_3_CPPFLAG) AM_CFLAGS = $(cflagWin) v_simexamples_DATA = $(NQ_EXAMPLE) v_simpixmaps_DATA = $(NQ_PIX) EXTRA_DIST = nq-netcdf.nc \ nq-netcdf.cdl \ silane.nc \ si1002x1-o_DS1_DEN-etsf.nc \ nanoquanta.png v_sim-3.8.0/lib/plug-ins/nanoquanta-netcdf/nanoquanta.png000066400000000000000000000025131370110300500234130ustar00rootroot00000000000000PNG  IHDR jMbKGD pHYsHHFk>IDATHǭ]lUt:;ݖ.&+ IkFDKĢ1~h|P!5QQk_QAPj?H-4Xڲi'ត{s?WǏ |>XD\ԀiٶFet'?ӧ5oSU\ܭ a>:&]Dֶ׵փbo%%%m[: I&Ǎ#*DIUiDi3[>_)**Pbf{…yJ,^,kh= ]#K"W6XyTۥY()HWsw$NJ4YL( Ȅ(Hiye$X+- 8KYFaj? 4`LS0[1O,8RTs~( 6w[xGccV3{HUW'O GUU N:u6_4:bd5@׵Z7_@eX'Ef0lqvٶI? 3q{{(ccc30 k0|$084M0=vNF !eY&;Wl8v;ZKe=m)raX뺟#]]]x 088e,H$JJJ>z455+]ys w0omk]:̅F ">Ed UboދO4 2:::qmx<~0<<ȌH`(z?`|ςL jfAĹBfKfsh8g7?}`[1zTXtCommentxs.JM,IMQ(,PHUp P03RHTp lIENDB`v_sim-3.8.0/lib/plug-ins/nanoquanta-netcdf/nq-netcdf.cdl000066400000000000000000000015701370110300500231050ustar00rootroot00000000000000netcdf Test { dimensions: number_of_atom_species = 2; number_of_atoms = 5; character_string_length = 80; number_of_reduced_dimensions = 3; number_of_vectors = 3; variables: char atom_species_names(number_of_atom_species, character_string_length); int atom_species(number_of_atoms); double reduced_atom_positions(number_of_atoms, number_of_reduced_dimensions); double primitive_vectors(number_of_vectors, number_of_reduced_dimensions); // Global attributes :file_format = "ETSF Nanoquanta"; :tool_file_format_version = 1.2; :Conventions = "http://www.etsf.eu/fileformats"; :title = "Silane molecule generated by ncgen."; data: atom_species_names = "Si", "H"; atom_species = 1, 2, 2, 2, 2; reduced_atom_positions = 0.5, 0.5, 0.5, 0.6, 0.6, 0.6, 0.4, 0.4, 0.6, 0.6, 0.4, 0.4, 0.4, 0.6, 0.4; primitive_vectors = 10., 0., 0., 0., 10., 0., 0., 0., 10.; } v_sim-3.8.0/lib/plug-ins/nanoquanta-netcdf/nq-netcdf.nc000066400000000000000000000017041370110300500227420ustar00rootroot00000000000000CDF number_of_atom_speciesnumber_of_atomscharacter_string_lengthPnumber_of_reduced_dimensionsnumber_of_vectors  file_formatETSF Nanoquantafile_format_version?333333 Conventionshttp://www.etsf.eu/fileformatstitle#Silane molecule generated by ncgen. atom_species_namesP atom_speciesreduced_atom_positionsxprimitive_vectorsH|SiH????333333?333333?333333?ٙ?ٙ?333333?333333?ٙ?ٙ?ٙ?333333?ٙ@$@$@$v_sim-3.8.0/lib/plug-ins/nanoquanta-netcdf/nq_basic.c000066400000000000000000000235141370110300500224670ustar00rootroot00000000000000/* EXTRAITS DE LA LICENCE Copyright CEA, contributeurs : Luc BILLARD et Damien CALISTE, laboratoire L_Sim, (2001-2005) Adresse ml : BILLARD, non joignable par ml ; CALISTE, damien P caliste AT cea P fr. Ce logiciel est un programme informatique servant visualiser des structures atomiques dans un rendu pseudo-3D. Ce logiciel est rgi par la licence CeCILL soumise au droit franais et respectant les principes de diffusion des logiciels libres. Vous pouvez utiliser, modifier et/ou redistribuer ce programme sous les conditions de la licence CeCILL telle que diffuse par le CEA, le CNRS et l'INRIA sur le site "http://www.cecill.info". Le fait que vous puissiez accder cet en-tte signifie que vous avez pris connaissance de la licence CeCILL, et que vous en avez accept les termes (cf. le fichier Documentation/licence.fr.txt fourni avec ce logiciel). */ /* LICENCE SUM UP Copyright CEA, contributors : Luc BILLARD et Damien CALISTE, laboratoire L_Sim, (2001-2005) E-mail address: BILLARD, not reachable any more ; CALISTE, damien P caliste AT cea P fr. This software is a computer program whose purpose is to visualize atomic configurations in 3D. This software is governed by the CeCILL license under French law and abiding by the rules of distribution of free software. You can use, modify and/ or redistribute the software under the terms of the CeCILL license as circulated by CEA, CNRS and INRIA at the following URL "http://www.cecill.info". The fact that you are presently reading this means that you have had knowledge of the CeCILL license and that you accept its terms. You can find a copy of this licence shipped with this software at Documentation/licence.en.txt. */ #include #include #include "nq_basic.h" #include "nq_structure.h" #include "nq_density.h" #include #include #include #define NANOQUANTA_DESCRIPTION _("" \ "This plug-in introduces support for\n" \ "ETSF file format defined by the\n" \ "European network NANOQUANTA.") #define NANOQUANTA_AUTHORS _("Caliste Damien:\n structure/density loading.") static gchar *iconPath; /* Required methods for a loadable module. */ gboolean etsfInit() { DBG_fprintf(stderr, "ETSF: loading plug-in 'nanoquanta'...\n"); DBG_fprintf(stderr, "ETSF: declare a new rendering load method.\n"); visu_data_atomic_class_addLoader(visu_data_loader_ETSF_getStatic()); iconPath = g_build_filename(V_SIM_PIXMAPS_DIR, "nanoquanta.png", NULL); DBG_fprintf(stderr, "ETSF: declare a new density load method.\n"); nqDensityInit(); return TRUE; } const char* etsfGet_description() { return NANOQUANTA_DESCRIPTION; } const char* etsfGet_authors() { return NANOQUANTA_AUTHORS; } const char* etsfGet_icon() { return iconPath; } GQuark nqError_quark() { return g_quark_from_static_string("nanoquanta"); } gboolean nqOpen_netcdfFile(const char* filename, int *netcdfId, GError **error) { int status, i; char *varsNames[3] = {"file_format", "file_format_version", "Conventions"}; nc_type varsType[3] = {NC_CHAR, NC_FLOAT, NC_CHAR}; nc_type altVarsType[3] = {NC_CHAR, NC_DOUBLE, NC_CHAR}; size_t varsLength[3] = {80, 1, 80}; nc_type readType; size_t readLength[3]; char format[256]; float version; g_return_val_if_fail(error && *error == (GError*)0, FALSE); g_return_val_if_fail(netcdfId && filename, FALSE); DBG_fprintf(stderr, "NQ Basic: opening file '%s' as a NetCDF file.\n", filename); /* Open the file as a NETCDF file. */ status = nc_open(filename, NC_NOWRITE, netcdfId); if (status != NC_NOERR) { DBG_fprintf(stderr, " | not a NetCDF file, can't open.\n"); *error = g_error_new(NQ_ERROR, NQ_ERROR_FILE_OPEN, "%s", nc_strerror(status)); return FALSE; } /* From here, the file is opened. */ /* Grep the header variables to check that it is a NETCDF file following rules of NANOQUANTA specifications. */ DBG_fprintf(stderr, "NQ Basic: checking header of file '%s'.\n", filename); /* Check lengths and types. */ for (i = 0; i < 3; i++) { status = nc_inq_att(*netcdfId, NC_GLOBAL, varsNames[i], &readType, readLength + i); if (status != NC_NOERR) { DBG_fprintf(stderr, " | cannot read header element %d (%s).\n", i, nc_strerror(status)); *error = g_error_new(NQ_ERROR, NQ_ERROR_FILE_HEADER, "inquiring global attribute '%s' raises: %s", varsNames[i], nc_strerror(status)); nqClose_netcdfFile(*netcdfId); return FALSE; } DBG_fprintf(stderr, " | header '%s' : type %d (%d), length %d (%d).\n", varsNames[i], (int)readType, (int)varsType[i], (int)readLength[i], (int)varsLength[i]); if ((readType != varsType[i] && readType != altVarsType[i]) || readLength[i] > varsLength[i]) { DBG_fprintf(stderr, " | header not valid.\n"); *error = g_error_new(NQ_ERROR, NQ_ERROR_FILE_HEADER, _("Global attribute '%s' has a wrong " "length or type.\n"), varsNames[i]); nqClose_netcdfFile(*netcdfId); return FALSE; } } /* Check values. */ status = nc_get_att_text(*netcdfId, NC_GLOBAL, varsNames[0], format); if (status != NC_NOERR) { DBG_fprintf(stderr, " | cannot read format.\n"); *error = g_error_new(NQ_ERROR, NQ_ERROR_FILE_HEADER, "reading global attribute '%s' raises: %s", varsNames[0], nc_strerror(status)); nqClose_netcdfFile(*netcdfId); return FALSE; } format[readLength[0]] = '\0'; DBG_fprintf(stderr, " | header '%s' value '%s'.\n", varsNames[0], format); if (strcmp(format, "ETSF Nanoquanta")) { DBG_fprintf(stderr, " | wrong format '%s'.\n", format); *error = g_error_new(NQ_ERROR, NQ_ERROR_FILE_HEADER, _("Variable 'file_format' should be " "'ETSF Nanoquanta' but is '%s'.\n"), format); nqClose_netcdfFile(*netcdfId); return FALSE; } status = nc_get_att_float(*netcdfId, NC_GLOBAL, varsNames[1], &version); if (status != NC_NOERR) { DBG_fprintf(stderr, " | cannot read version.\n"); *error = g_error_new(NQ_ERROR, NQ_ERROR_FILE_HEADER, "reading global attribute '%s' raises: %s", varsNames[1], nc_strerror(status)); nqClose_netcdfFile(*netcdfId); return FALSE; } DBG_fprintf(stderr, " | header '%s' value %f.\n", varsNames[1], version); if (version < 1.2) { DBG_fprintf(stderr, " | version too small (%f).\n", version); *error = g_error_new(NQ_ERROR, NQ_ERROR_FILE_HEADER, _("Supported version are 1.2 and over but" " this file is only %f.\n"), version); nqClose_netcdfFile(*netcdfId); return FALSE; } return TRUE; } gboolean nqClose_netcdfFile(int netcdfId) { int status; status = nc_close(netcdfId); if (status != NC_NOERR) { g_warning("%s", nc_strerror(status)); return FALSE; } return TRUE; } static gboolean nqErrorReport(GError **error, const char *message, ...) { va_list args; gchar *formatted; if (error) { va_start(args, message); formatted = g_strdup_vprintf(message, args); va_end(args); *error = g_error_new(NQ_ERROR, NQ_ERROR_FILE_FORMAT, "%s", formatted); g_free(formatted); } return FALSE; } gboolean nqGetDim(int netcdfId, GError **error, char *name, int *varId, size_t *value) { int status; /* Grep the number of elements. */ status = nc_inq_dimid(netcdfId, name, varId); if (status != NC_NOERR) return nqErrorReport(error, _("Reading '%s': %s."), name, nc_strerror(status)); status = nc_inq_dimlen(netcdfId, *varId, value); if (status != NC_NOERR) return nqErrorReport(error, _("Retrieve value for variable '%s': %s."), name, nc_strerror(status)); return TRUE; } gboolean nqCheckVar(int netcdfId, GError **error, char *name, int *varId, nc_type ncType, int nbDims, size_t *nbEleDims) { int status; nc_type localType; char *typeNames[] = {"NAT", "BYTE", "CHAR", "SHORT", "INT", "FLOAT", "DOUBLE"}; int localDims; int *localNbDims; int i; size_t dimSize; status = nc_inq_varid(netcdfId, name, varId); if (status != NC_NOERR) return nqErrorReport(error, _("Reading '%s': %s."), name, nc_strerror(status)); status = nc_inq_vartype(netcdfId, *varId, &localType); if (status != NC_NOERR) return nqErrorReport(error, _("Checking variable '%s': %s."), name, nc_strerror(status)); if (localType != ncType) return nqErrorReport(error, _("Variable '%s' should be of type '%s'."), name, typeNames[ncType]); status = nc_inq_varndims(netcdfId, *varId, &localDims); if (status != NC_NOERR) return nqErrorReport(error, _("Checking variable '%s': %s."), name, nc_strerror(status)); if (localDims != nbDims) return nqErrorReport(error, _("Variable '%s' should be a %d dimension array."), name, nbDims); localNbDims = g_malloc(sizeof(int) * nbDims); status = nc_inq_vardimid(netcdfId, *varId, localNbDims); if (status != NC_NOERR) { g_free(localNbDims); return nqErrorReport(error, _("Checking variable '%s': %s."), name, nc_strerror(status)); } for (i = 0; i< nbDims; i++) { status = nc_inq_dimlen(netcdfId, localNbDims[i], &dimSize); if (status != NC_NOERR) { g_free(localNbDims); return nqErrorReport(error, _("Checking dimension ID %d: %s."), localNbDims[i], nc_strerror(status)); } if (dimSize != nbEleDims[i]) { g_free(localNbDims); return nqErrorReport(error, _("Variable '%s' is not consistent with" " declaration of dimensions."), name); } } g_free(localNbDims); return TRUE; } v_sim-3.8.0/lib/plug-ins/nanoquanta-netcdf/nq_basic.h000066400000000000000000000102731370110300500224720ustar00rootroot00000000000000/* EXTRAITS DE LA LICENCE Copyright CEA, contributeurs : Luc BILLARD et Damien CALISTE, laboratoire L_Sim, (2001-2005) Adresse ml : BILLARD, non joignable par ml ; CALISTE, damien P caliste AT cea P fr. Ce logiciel est un programme informatique servant visualiser des structures atomiques dans un rendu pseudo-3D. Ce logiciel est rgi par la licence CeCILL soumise au droit franais et respectant les principes de diffusion des logiciels libres. Vous pouvez utiliser, modifier et/ou redistribuer ce programme sous les conditions de la licence CeCILL telle que diffuse par le CEA, le CNRS et l'INRIA sur le site "http://www.cecill.info". Le fait que vous puissiez accder cet en-tte signifie que vous avez pris connaissance de la licence CeCILL, et que vous en avez accept les termes (cf. le fichier Documentation/licence.fr.txt fourni avec ce logiciel). */ /* LICENCE SUM UP Copyright CEA, contributors : Luc BILLARD et Damien CALISTE, laboratoire L_Sim, (2001-2005) E-mail address: BILLARD, not reachable any more ; CALISTE, damien P caliste AT cea P fr. This software is a computer program whose purpose is to visualize atomic configurations in 3D. This software is governed by the CeCILL license under French law and abiding by the rules of distribution of free software. You can use, modify and/ or redistribute the software under the terms of the CeCILL license as circulated by CEA, CNRS and INRIA at the following URL "http://www.cecill.info". The fact that you are presently reading this means that you have had knowledge of the CeCILL license and that you accept its terms. You can find a copy of this licence shipped with this software at Documentation/licence.en.txt. */ #ifndef NQ_BASIC_H #define NQ_BASIC_H #include #include #define NQ_ERROR nqError_quark() GQuark nqError_quark(void); enum { NQ_ERROR_FILE_OPEN, /* Error when opening. */ NQ_ERROR_FILE_UNKNOWN, /* Wrong or unknown headers. */ NQ_ERROR_FILE_HEADER, /* Wrong header value. */ NQ_ERROR_FILE_FORMAT /* Wrong syntax (missing variables... */ }; /** * nqOpen_netcdfFile: * @filename: a path to the file to load ; * @netcdfId: a pointer to store the id returned by netcdf ; * @error: a pointer to store possible error. * * Open a file supposed to be a NETCDF file following the Nanoquanta * specifications. The @netcdfId argument will store the integer id used by * netcdf in future calls if the given @filename has a right header. * * Returns: TRUE if the file is a valid NETCDF file, if FALSE, no file * is opened. */ gboolean nqOpen_netcdfFile(const char* filename, int *netcdfId, GError **error); /** * nqClose_netcdfFile: * @netcdfId: a netcdf identifier ; * * Close the file that is currently opened by Netcdf. * * Returns: TRUE if the file is succesfully closed. */ gboolean nqClose_netcdfFile(int netcdfId); /** * nqGetDim: * @netcdfId: a netcdf identifier ; * @error: a location to store an error (target should NULL on enter) ; * @name: the name of the dimension to get the value from ; * @varId: a location to store the id used to identify this dimension ; * @value: a location to store the returned value. * * Inquire the given @netcdfId file to read the value of the given dimension. * * Returns: TRUE if the dimension exists and the value is readable. */ gboolean nqGetDim(int netcdfId, GError **error, char *name, int *varId, size_t *value); /** * nqCheckVar: * @netcdfId: a netcdf identifier ; * @error: a location to store an error (target should NULL on enter) ; * @name: the name of the value to check the definition of ; * @varId: a location to store the id used to identify this variable ; * @ncType: the supposed type of the variable ; * @nbDims: the supposed number of dimenions of the variable ; * @nbEleDims: an array of size @nbDims with the supposed size of each * dimenion; * * Inquire the given @netcdfId file to read the variable definition * and check that it matches with the given arguments. * * Returns: TRUE if the variable exists and match the given definition. */ gboolean nqCheckVar(int netcdfId, GError **error, char *name, int *varId, nc_type ncType, int nbDims, size_t *nbEleDims); #endif v_sim-3.8.0/lib/plug-ins/nanoquanta-netcdf/nq_density.c000066400000000000000000000265401370110300500230670ustar00rootroot00000000000000/* EXTRAITS DE LA LICENCE Copyright CEA, contributeurs : Luc BILLARD, Damien CALISTE, Olivier D'Astier, laboratoire L_Sim, (2001-2005) Adresses mèl : BILLARD, non joignable par mèl ; CALISTE, damien P caliste AT cea P fr. D'ASTIER, dastier AT iie P cnam P fr. Ce logiciel est un programme informatique servant à visualiser des structures atomiques dans un rendu pseudo-3D. Ce logiciel est régi par la licence CeCILL soumise au droit français et respectant les principes de diffusion des logiciels libres. Vous pouvez utiliser, modifier et/ou redistribuer ce programme sous les conditions de la licence CeCILL telle que diffusée par le CEA, le CNRS et l'INRIA sur le site "http://www.cecill.info". Le fait que vous puissiez accéder à cet en-tête signifie que vous avez pris connaissance de la licence CeCILL, et que vous en avez accepté les termes (cf. le fichier Documentation/licence.fr.txt fourni avec ce logiciel). */ /* LICENCE SUM UP Copyright CEA, contributors : Luc BILLARD and Damien CALISTE and Olivier D'Astier, laboratoire L_Sim, (2001-2005) E-mail addresses : BILLARD, not reachable any more ; CALISTE, damien P caliste AT cea P fr. D'ASTIER, dastier AT iie P cnam P fr. This software is a computer program whose purpose is to visualize atomic configurations in 3D. This software is governed by the CeCILL license under French law and abiding by the rules of distribution of free software. You can use, modify and/ or redistribute the software under the terms of the CeCILL license as circulated by CEA, CNRS and INRIA at the following URL "http://www.cecill.info". The fact that you are presently reading this means that you have had knowledge of the CeCILL license and that you accept its terms. You can find a copy of this licence shipped with this software at Documentation/licence.en.txt. */ #include "nq_basic.h" #include "nq_density.h" #include #include #include #include #include #include #include #include /* Local methods. */ gboolean nqDensityLoad(VisuScalarFieldMethod *meth, VisuScalarFieldMethodData *data, GCancellable *cancel, GError **error); void nqDensityInit() { const gchar *type[] = {"*.nc", "*-etsf.nc", (char*)0}; const gchar *descr = _("Nanoquanta NETCDF format"); VisuScalarFieldMethod *meth; meth = visu_scalar_field_method_new(descr, type, nqDensityLoad, G_PRIORITY_HIGH); tool_file_format_addPropertyInt(TOOL_FILE_FORMAT(meth), "number_of_components", _("spin channel (or -1 for all)"), -1); tool_file_format_addPropertyInt(TOOL_FILE_FORMAT(meth), "real_or_complex", _("real or complex values (or -1 for all)"), -1); } gboolean nqDensityLoad(VisuScalarFieldMethod *meth _U_, VisuScalarFieldMethodData *data, GCancellable *cancel _U_, GError **error) { gboolean res; int netcdfId, varId, status, i, j; size_t gridSize[3]; size_t spinDim; size_t realOrComplex; int varIdRprimd; size_t dimsRprimd[2]; double rprimd[3][3]; size_t start[] = {0, 0}; size_t startDensity[] = {0, 0, 0, 0, 0}; int varIdDensity; size_t dimsDensity[5]; GArray *density; double boxGeometry[6]; VisuBox *box; guint size[3]; int option_spin, option_realOrComplex; ToolOption *option; VisuScalarFieldData *field; nc_type ncType; size_t sizeTitle; char title[256]; gchar *comment; GList *fields, *lst; #if DEBUG == 1 GTimer *timer; gulong fractionTimer; #endif g_return_val_if_fail(data, FALSE); g_return_val_if_fail(!error || *error == (GError*)0, FALSE); res = nqOpen_netcdfFile(visu_scalar_field_method_data_getFilename(data), &netcdfId, error); if (!res) return FALSE; #if DEBUG == 1 timer = g_timer_new(); g_timer_start(timer); #endif /* ToolOptional elements. */ comment = (gchar*)0; status = nc_inq_att(netcdfId, NC_GLOBAL, "title", &ncType, &sizeTitle); if (status == NC_NOERR && ncType == NC_CHAR && sizeTitle < 255) { status = nc_get_att_text(netcdfId, NC_GLOBAL, "title", title); if (status == NC_NOERR) { title[sizeTitle] = '\0'; comment = g_locale_to_utf8(title, -1, NULL, NULL, NULL); } } /* We parse a first time the options, if given. */ option_spin = tool_file_format_getPropertyInt(TOOL_FILE_FORMAT(meth), "number_of_components"); option_realOrComplex = tool_file_format_getPropertyInt(TOOL_FILE_FORMAT(meth), "real_or_complex"); /* We now have a valid NetCDF file. We check the existence and the shape of all required variables and dimensions. */ /* Get the grid size dimensions. */ if (!nqGetDim(netcdfId, error, "number_of_grid_points_vector1", &varId, gridSize)) { nqClose_netcdfFile(netcdfId); return TRUE; } if (!nqGetDim(netcdfId, error, "number_of_grid_points_vector2", &varId, gridSize + 1)) { nqClose_netcdfFile(netcdfId); return TRUE; } if (!nqGetDim(netcdfId, error, "number_of_grid_points_vector3", &varId, gridSize + 2)) { nqClose_netcdfFile(netcdfId); return TRUE; } size[0] = (int)gridSize[0]; size[1] = (int)gridSize[1]; size[2] = (int)gridSize[2]; /* Get the spin dimension. */ if (!nqGetDim(netcdfId, error, "number_of_components", &varId, &spinDim)) { nqClose_netcdfFile(netcdfId); return TRUE; } /* Get real or complex. */ if (!nqGetDim(netcdfId, error, "real_or_complex_density", &varId, &realOrComplex)) { nqClose_netcdfFile(netcdfId); return TRUE; } /* Check values for spin and realOrComplex. */ if (option_spin >= (int)spinDim) { g_warning("Requested value (%d) of spin component is out of range ([0;%d[).", option_spin, (int)spinDim); option_spin = 0; } if (option_realOrComplex >= (int)realOrComplex) { g_warning("Requested value (%d) of real or complex part is out of range ([0;%d[).", option_realOrComplex, (int)realOrComplex); option_realOrComplex = 0; } DBG_fprintf(stderr, "NQ Density : read dimensions.\n"); DBG_fprintf(stderr, " | grid size (%d ; %d ; %d).\n", size[0], size[1], size[2]); DBG_fprintf(stderr, " | spin components %d.\n", (int)spinDim); DBG_fprintf(stderr, " | real or complex %d.\n", (int)realOrComplex); /* Check the rprimd matrix. */ dimsRprimd[0] = 3; dimsRprimd[1] = 3; if (!nqCheckVar(netcdfId, error, "primitive_vectors", &varIdRprimd, NC_DOUBLE, 2, dimsRprimd)) { nqClose_netcdfFile(netcdfId); return TRUE; } /* Check the density values. */ dimsDensity[0] = spinDim; dimsDensity[1] = gridSize[2]; dimsDensity[2] = gridSize[1]; dimsDensity[3] = gridSize[0]; dimsDensity[4] = realOrComplex; if (!nqCheckVar(netcdfId, error, "density", &varIdDensity, NC_DOUBLE, 5, dimsDensity)) { nqClose_netcdfFile(netcdfId); return TRUE; } /* Ok, everything is OK in the file. We can load it. */ /* Grep the box definition. */ status = nc_get_vara_double(netcdfId, varIdRprimd, start, dimsRprimd, &rprimd[0][0]); if (status != NC_NOERR) { *error = g_error_new(NQ_ERROR, NQ_ERROR_FILE_FORMAT, _("Retrieve value for variable 'primitive_vectors': %s."), nc_strerror(status)); nqClose_netcdfFile(netcdfId); return TRUE; } res = tool_matrix_reducePrimitiveVectors(boxGeometry, rprimd); if (!res) { *error = g_error_new(NQ_ERROR, NQ_ERROR_FILE_FORMAT, _("The variable 'primitive_vectors' is not well formed" " (the basis is not 3D).")); nqClose_netcdfFile(netcdfId); return TRUE; } /* Get one part of the density. */ density = g_array_sized_new(FALSE, FALSE, sizeof(double), gridSize[2] * gridSize[1] * gridSize[0]); density = g_array_set_size(density, gridSize[2] * gridSize[1] * gridSize[0]); fields = (GList*)0; for (i = (option_spin < 0)?0:option_spin ; i < ((option_spin < 0)?(int)spinDim:option_spin + 1) ; i++) for (j = (option_realOrComplex < 0)?0:option_realOrComplex ; j < ((option_realOrComplex < 0)?(int)realOrComplex:option_realOrComplex + 1) ; j++) fields = g_list_append(fields, g_object_new(VISU_TYPE_SCALAR_FIELD_DATA, "label", visu_scalar_field_method_data_getFilename(data), NULL)); for (lst = fields; lst; lst = g_list_next(lst)) visu_scalar_field_method_data_addField(data, VISU_SCALAR_FIELD(g_object_ref(lst->data))); visu_scalar_field_method_data_ready(data); lst = fields; for (i = (option_spin < 0)?0:option_spin ; i < ((option_spin < 0)?(int)spinDim:option_spin + 1) ; i++) for (j = (option_realOrComplex < 0)?0:option_realOrComplex ; j < ((option_realOrComplex < 0)?(int)realOrComplex:option_realOrComplex + 1) ; j++) { startDensity[0] = i; startDensity[4] = j; dimsDensity[0] = 1; dimsDensity[4] = 1; status = nc_get_vara_double(netcdfId, varIdDensity, startDensity, dimsDensity, (double*)density->data); if (status != NC_NOERR) { *error = g_error_new(NQ_ERROR, NQ_ERROR_FILE_FORMAT, _("Retrieve value for variable 'density': %s."), nc_strerror(status)); nqClose_netcdfFile(netcdfId); g_array_unref(density); g_list_free_full(fields, g_object_unref); return TRUE; } /* Ok, now everything is in memory, we can populate the field object. */ field = VISU_SCALAR_FIELD_DATA(lst->data); g_return_val_if_fail(field, FALSE); visu_scalar_field_setCommentary(VISU_SCALAR_FIELD(field), comment); box = visu_box_new(boxGeometry, VISU_BOX_PERIODIC); visu_box_setMargin(box, 0.f, FALSE); visu_boxed_setBox(VISU_BOXED(field), VISU_BOXED(box)); g_object_unref(box); visu_scalar_field_setGridSize(VISU_SCALAR_FIELD(field), size); DBG_fprintf(stderr, "NQ Density : transfer density into field object.\n"); visu_scalar_field_data_set(field, density, VISU_SCALAR_FIELD_DATA_XYZ); if ((int)spinDim == 1) option = tool_option_new("number_of_components", _("1, no spin information"), G_TYPE_INT); else if ((int)spinDim == 2) option = tool_option_new("number_of_components", _("1, spin-up ; 2, spin-down"), G_TYPE_INT); else if ((int)spinDim == 4) option = tool_option_new("number_of_components", _("1, average density ; " "[2;4], magnetisation vector"), G_TYPE_INT); else option = tool_option_new("number_of_components", _("unknown value"), G_TYPE_INT); g_value_set_int(tool_option_getValue(option), i + 1); visu_scalar_field_addOption(VISU_SCALAR_FIELD(field), option); lst = g_list_next(lst); } g_array_unref(density); if (comment) g_free(comment); g_list_free_full(fields, g_object_unref); #if DEBUG == 1 g_timer_stop(timer); fprintf(stderr, "ETSF: density parsed in %g milli-s.\n", g_timer_elapsed(timer, &fractionTimer)/1e-3); g_timer_destroy(timer); #endif nqClose_netcdfFile(netcdfId); return TRUE; } v_sim-3.8.0/lib/plug-ins/nanoquanta-netcdf/nq_density.h000066400000000000000000000037421370110300500230730ustar00rootroot00000000000000/* EXTRAITS DE LA LICENCE Copyright CEA, contributeurs : Luc BILLARD, Damien CALISTE, Olivier D'Astier, laboratoire L_Sim, (2001-2005) Adresses mèl : BILLARD, non joignable par mèl ; CALISTE, damien P caliste AT cea P fr. D'ASTIER, dastier AT iie P cnam P fr. Ce logiciel est un programme informatique servant à visualiser des structures atomiques dans un rendu pseudo-3D. Ce logiciel est régi par la licence CeCILL soumise au droit français et respectant les principes de diffusion des logiciels libres. Vous pouvez utiliser, modifier et/ou redistribuer ce programme sous les conditions de la licence CeCILL telle que diffusée par le CEA, le CNRS et l'INRIA sur le site "http://www.cecill.info". Le fait que vous puissiez accéder à cet en-tête signifie que vous avez pris connaissance de la licence CeCILL, et que vous en avez accepté les termes (cf. le fichier Documentation/licence.fr.txt fourni avec ce logiciel). */ /* LICENCE SUM UP Copyright CEA, contributors : Luc BILLARD and Damien CALISTE and Olivier D'Astier, laboratoire L_Sim, (2001-2005) E-mail addresses : BILLARD, not reachable any more ; CALISTE, damien P caliste AT cea P fr. D'ASTIER, dastier AT iie P cnam P fr. This software is a computer program whose purpose is to visualize atomic configurations in 3D. This software is governed by the CeCILL license under French law and abiding by the rules of distribution of free software. You can use, modify and/ or redistribute the software under the terms of the CeCILL license as circulated by CEA, CNRS and INRIA at the following URL "http://www.cecill.info". The fact that you are presently reading this means that you have had knowledge of the CeCILL license and that you accept its terms. You can find a copy of this licence shipped with this software at Documentation/licence.en.txt. */ #ifndef NQ_DENSITY_H /** * nqDensityInit: * * Routine used to declare the density file format to V_Sim. */ void nqDensityInit(); #endif v_sim-3.8.0/lib/plug-ins/nanoquanta-netcdf/nq_structure.c000066400000000000000000000326361370110300500234530ustar00rootroot00000000000000#include "nq_basic.h" #include "nq_structure.h" #include #include #include #include #include #include #include /* Local methods */ static VisuDataLoader *nqLoader = NULL; static gboolean loadNQETSF(VisuDataLoader *self, VisuDataLoadable *data, guint type, guint nSet, GCancellable *cancel, GError **error); VisuDataLoader* visu_data_loader_ETSF_getStatic(void) { const gchar *type[] = {"*.nc", "*-etsf.nc", (char*)0}; if (nqLoader) return nqLoader; return nqLoader = visu_data_loader_new(_("ETSF file format"), type, FALSE, loadNQETSF, 5); } static gboolean loadNQETSF(VisuDataLoader *self _U_, VisuDataLoadable *data, guint type, guint nSet _U_, GCancellable *cancel _U_, GError **error) { gboolean res; int netcdfId, status; guint i; int varId; size_t dimSize; char* varNbElement = "number_of_atom_species"; guint nbEle; char* varNbNode = "number_of_atoms"; guint nbNode; char* varAtomsNames = "atom_species_names"; int varIdSymbols; size_t dimsSymbols[2]; char* symbols; char* varNodeToEle = "atom_species"; int varIdNodeToEle; size_t dimsNodeToEle; guint *nodeToEle; char* varCoord = "reduced_atom_positions"; int varIdCoord; size_t dimsCoord[2]; double* coord; char *varRprimd = "primitive_vectors"; int varIdRprimd; size_t dimsRprimd[2]; double rprimd[3][3]; size_t start[] = {0, 0, 0}; char *varTitle = "title"; size_t sizeTitle; char title[256]; VisuElement *ele; GArray *visuEle, *nbNodesPerEle, *gcoord_c, *gcoord_f; float vect[3]; nc_type ncType; gchar *infoUTF8, *name; gboolean *flag; guint nbGrid, nbFGrid, grid[3], *cGrid, *nGrid; size_t dimsGrid[3], dimsNGrid[2]; int varIdGrid, varIdNGrid; VisuBox *box; g_return_val_if_fail(error && *error == (GError*)0, FALSE); res = nqOpen_netcdfFile(visu_data_loadable_getFilename(data, type), &netcdfId, error); if (!res) return FALSE; /* From now on, the file is a NETCDF valid file, so we return TRUE, but errrors can still occurs. */ /********************************/ /* Retrieve the numeral values. */ /********************************/ /* Grep the number of elements. */ if (!nqGetDim(netcdfId, error, varNbElement, &varId, &dimSize)) { nqClose_netcdfFile(netcdfId); return TRUE; } nbEle = (int)dimSize; /* Grep the number of nodes. */ if (!nqGetDim(netcdfId, error, varNbNode, &varId, &dimSize)) { nqClose_netcdfFile(netcdfId); return TRUE; } nbNode = (int)dimSize; /**************************************************************/ /* Check the conformance of the arrays to the specifications. */ /**************************************************************/ /* Check the names of elements. */ dimsSymbols[0] = nbEle; dimsSymbols[1] = 80; if (!nqCheckVar(netcdfId, error, varAtomsNames, &varIdSymbols, NC_CHAR, 2, dimsSymbols)) { g_error_free(*error); *error = (GError*)0; dimsSymbols[1] = 2; if (!nqCheckVar(netcdfId, error, "chemical_symbols", &varIdSymbols, NC_CHAR, 2, dimsSymbols)) { nqClose_netcdfFile(netcdfId); return TRUE; } } /* Check the 'node to element'array. */ dimsNodeToEle = nbNode; if (!nqCheckVar(netcdfId, error, varNodeToEle, &varIdNodeToEle, NC_INT, 1, &dimsNodeToEle)) { nqClose_netcdfFile(netcdfId); return TRUE; } /* Check the reduce coordinates array. */ dimsCoord[0] = nbNode; dimsCoord[1] = 3; if (!nqCheckVar(netcdfId, error, varCoord, &varIdCoord, NC_DOUBLE, 2, dimsCoord)) { nqClose_netcdfFile(netcdfId); return TRUE; } /* Check the rprimd matrix. */ dimsRprimd[0] = 3; dimsRprimd[1] = 3; if (!nqCheckVar(netcdfId, error, varRprimd, &varIdRprimd, NC_DOUBLE, 2, dimsRprimd)) { nqClose_netcdfFile(netcdfId); return TRUE; } /****************************/ /* Retrieve now the arrays. */ /****************************/ /* Grep the names of elements. */ dimsSymbols[0] = 1; symbols = g_malloc(sizeof(char) * (dimsSymbols[1] + 1) * nbEle); for (i = 0; i < nbEle; i++) { start[0] = i; status = nc_get_vara_text(netcdfId, varIdSymbols, start, dimsSymbols, symbols + i * (dimsSymbols[1] + 1)); if (status != NC_NOERR) { *error = g_error_new(NQ_ERROR, NQ_ERROR_FILE_FORMAT, _("Retrieve value for variable '%s': %s."), varAtomsNames, nc_strerror(status)); nqClose_netcdfFile(netcdfId); g_free(symbols); return TRUE; } symbols[(i + 1) * (dimsSymbols[1] + 1) - 1] = '\0'; } dimsSymbols[0] = nbEle; start[0] = 0; /* Grep table from 'node to element'. */ nodeToEle = g_malloc(sizeof(int) * nbNode); status = nc_get_vara_int(netcdfId, varIdNodeToEle, start, &dimsNodeToEle, (int*)nodeToEle); if (status != NC_NOERR) { *error = g_error_new(NQ_ERROR, NQ_ERROR_FILE_FORMAT, _("Retrieve value for variable '%s': %s."), varNodeToEle, nc_strerror(status)); nqClose_netcdfFile(netcdfId); g_free(symbols); g_free(nodeToEle); return TRUE; } for (i = 0; i < nbNode; i++) { /* Specifications 1.3 says that the values range from 1. So we remove 1 to be coherent with C numbering. */ nodeToEle[i] -= 1; if (nodeToEle[i] >= nbEle) { *error = g_error_new(NQ_ERROR, NQ_ERROR_FILE_FORMAT, _("Error in indexing array '%s', index out of bounds."), varNodeToEle); nqClose_netcdfFile(netcdfId); g_free(symbols); g_free(nodeToEle); return TRUE; } } /* Grep the reduced coordinates. */ coord = g_malloc(sizeof(double) * 3 * nbNode); status = nc_get_vara_double(netcdfId, varIdCoord, start, dimsCoord, coord); if (status != NC_NOERR) { *error = g_error_new(NQ_ERROR, NQ_ERROR_FILE_FORMAT, _("Retrieve value for variable '%s': %s."), varCoord, nc_strerror(status)); nqClose_netcdfFile(netcdfId); g_free(symbols); g_free(nodeToEle); g_free(coord); return TRUE; } /* Grep the box definition. */ status = nc_get_vara_double(netcdfId, varIdRprimd, start, dimsRprimd, &rprimd[0][0]); if (status != NC_NOERR) { *error = g_error_new(NQ_ERROR, NQ_ERROR_FILE_FORMAT, _("Retrieve value for variable '%s': %s."), varRprimd, nc_strerror(status)); nqClose_netcdfFile(netcdfId); g_free(symbols); g_free(nodeToEle); g_free(coord); return TRUE; } /* Prepare the arrays for memory allocation in the VisuData object. */ box = visu_box_new_full(rprimd, VISU_BOX_PERIODIC); if (visu_box_getGeometry(box, VISU_BOX_DXX) == G_MAXFLOAT) { *error = g_error_new(NQ_ERROR, NQ_ERROR_FILE_FORMAT, _("Wrong ETSF format, basis-set is degenerated.\n")); g_object_unref(box); nqClose_netcdfFile(netcdfId); g_free(symbols); g_free(nodeToEle); g_free(coord); return TRUE; } visu_box_setUnit(box, TOOL_UNITS_BOHR); visu_boxed_setBox(VISU_BOXED(data), VISU_BOXED(box)); g_object_unref(box); nbNodesPerEle = g_array_sized_new(FALSE, TRUE, sizeof(guint), nbEle); g_array_set_size(nbNodesPerEle, nbEle); for (i = 0; i < nbNode; i++) g_array_index(nbNodesPerEle, guint, nodeToEle[i]) += 1; visuEle = g_array_sized_new(FALSE, FALSE, sizeof(VisuElement*), nbEle); for (i = 0; i < nbEle; i++) { name = g_strstrip(symbols + i * (dimsSymbols[1] + 1)); ele = visu_element_retrieveFromName(name, (gboolean*)0); g_array_append_val(visuEle, ele); } DBG_fprintf(stderr, "NQ structure : File '%s' parsed.\n", visu_data_loadable_getFilename(data, type)); DBG_fprintf(stderr, " | box definition : ( %f %f %f )\n", rprimd[0][0], rprimd[0][1], rprimd[0][2]); DBG_fprintf(stderr, " | ( %f %f %f )\n", rprimd[1][0], rprimd[1][1], rprimd[1][2]); DBG_fprintf(stderr, " | ( %f %f %f )\n", rprimd[2][0], rprimd[2][1], rprimd[2][2]); DBG_fprintf(stderr, " | number of nodes per element (%d):\n", nbEle); for (i = 0; i < nbEle ; i++) DBG_fprintf(stderr, " | %d nodes for '%s' (%p)\n", g_array_index(nbNodesPerEle, guint, i), g_array_index(visuEle, VisuElement*, i)->name, g_array_index(visuEle, gpointer, i)); g_free(symbols); visu_node_array_allocate(VISU_NODE_ARRAY(data), visuEle, nbNodesPerEle); for (i = 0; i < nbNode; i++) { vect[0] = coord[3 * i + 0]; vect[1] = coord[3 * i + 1]; vect[2] = coord[3 * i + 2]; visu_data_addNodeFromElement(VISU_DATA(data), g_array_index(visuEle, VisuElement*, nodeToEle[i]), vect, TRUE); } g_free(nodeToEle); g_free(coord); g_array_free(nbNodesPerEle, TRUE); g_array_free(visuEle, TRUE); /**********************/ /* Optional elements. */ /**********************/ status = nc_inq_att(netcdfId, NC_GLOBAL, varTitle, &ncType, &sizeTitle); if (status == NC_NOERR && ncType == NC_CHAR && sizeTitle < 255) { status = nc_get_att_text(netcdfId, NC_GLOBAL, varTitle, title); if (status == NC_NOERR) { title[sizeTitle] = '\0'; infoUTF8 = g_locale_to_utf8(title, -1, NULL, NULL, NULL); if (infoUTF8) { visu_data_setDescription(VISU_DATA(data), infoUTF8); g_free(infoUTF8); } else g_warning("Can't convert '%s' to UTF8.\n", title); } } /* Support for BigDFT grid points. */ nbGrid = 0; grid[0] = 0; grid[1] = 0; grid[2] = 0; if (nqGetDim(netcdfId, (GError**)0, "max_number_of_basis_grid_points", &varId, &dimSize)) { nbGrid = (guint)dimSize; if (nqGetDim(netcdfId, (GError**)0, "number_of_grid_points_vector1", &varId, &dimSize)) grid[0] = (guint)dimSize; if (nqGetDim(netcdfId, (GError**)0, "number_of_grid_points_vector2", &varId, &dimSize)) grid[1] = (guint)dimSize; if (nqGetDim(netcdfId, (GError**)0, "number_of_grid_points_vector3", &varId, &dimSize)) grid[2] = (guint)dimSize; if (!grid[0] || !grid[1] || !grid[2]) nbGrid = 0; DBG_fprintf(stderr, "NQ structure: grid is defined (%d) in %dx%dx%d.\n", nbGrid, grid[0], grid[1], grid[2]); dimsGrid[0] = 1; dimsGrid[1] = nbGrid; dimsGrid[2] = 3; if (!nqCheckVar(netcdfId, (GError**)0, "coordinates_of_basis_grid_points", &varIdGrid, NC_INT, 3, dimsGrid)) nbGrid = 0; dimsNGrid[0] = 1; dimsNGrid[1] = nbGrid; if (!nqCheckVar(netcdfId, (GError**)0, "number_of_coefficients_per_grid_point", &varIdNGrid, NC_INT, 2, dimsNGrid)) nbGrid = 0; DBG_fprintf(stderr, "NQ structure: grid is present %d and valid.\n", nbGrid); } if (nbGrid) { nbFGrid = 0; cGrid = g_malloc(sizeof(guint) * nbGrid * 3); nGrid = (guint*)0; status = nc_get_vara_int(netcdfId, varIdGrid, start, dimsGrid, (int*)cGrid); if (status != NC_NOERR) { g_free(cGrid); nbGrid = 0; } else { nGrid = g_malloc(sizeof(guint) * nbGrid); status = nc_get_vara_int(netcdfId, varIdNGrid, start, dimsNGrid, (int*)nGrid); if (status != NC_NOERR) { g_free(cGrid); g_free(nGrid); nbGrid = 0; } else { /* Calculate the number of fine grid points. */ nbFGrid = 0; for (i = 0; i < nbGrid; i++) if (nGrid[i] > 1) nbFGrid += 1; } } DBG_fprintf(stderr, "NQ structure: grid has been read.\n"); if (cGrid && nGrid) { /* Add the grid nodes. */ gcoord_c = g_array_sized_new(FALSE, FALSE, sizeof(gfloat) * 3, nbGrid); gcoord_f = (GArray*)0; if (nbFGrid > 0) gcoord_f = g_array_sized_new(FALSE, FALSE, sizeof(gfloat) * 3, nbFGrid); for (i = 0; i < nbGrid; i++) { vect[0] = (float)cGrid[i * 3 + 0] / (float)grid[0]; vect[1] = (float)cGrid[i * 3 + 1] / (float)grid[1]; vect[2] = (float)cGrid[i * 3 + 2] / (float)grid[2]; g_array_append_val(gcoord_c, vect); if (nGrid[i] > 1) g_array_append_val(gcoord_f, vect); } g_free(cGrid); g_free(nGrid); g_object_set_data_full(G_OBJECT(data), "BigDFT_coarse_grid", (gpointer)gcoord_c, (GDestroyNotify)g_array_unref); if (nbFGrid > 0) g_object_set_data_full(G_OBJECT(data), "BigDFT_fine_grid", (gpointer)gcoord_f, (GDestroyNotify)g_array_unref); } } nqClose_netcdfFile(netcdfId); /******************************************/ /* Add some flags to the VisuData object. */ /******************************************/ flag = g_malloc(sizeof(gboolean)); *flag = TRUE; g_object_set_data_full(G_OBJECT(data), VISU_SCALAR_FIELD_DEFINED_IN_STRUCT_FILE, (gpointer)flag, g_free); return TRUE; } v_sim-3.8.0/lib/plug-ins/nanoquanta-netcdf/nq_structure.h000066400000000000000000000004461370110300500234520ustar00rootroot00000000000000#ifndef NQ_STRUCTURE_H #define NQ_STRUCTURE_H #include /** * nqStructuralInit: * * Routine used to create a new loading method for the ETSF file * format. * * Returns: a newly created rendering method. */ VisuDataLoader* visu_data_loader_ETSF_getStatic(); #endif v_sim-3.8.0/lib/plug-ins/nanoquanta-netcdf/si1002x1-o_DS1_DEN-etsf.nc000066400000000000000000014755101370110300500246150ustar00rootroot00000000000000CDF character_string_lengthPmax_number_of_angular_momentamax_number_of_coefficients max_number_of_projectorsmax_number_of_states3number_of_atomsnumber_of_atom_speciesnumber_of_cartesian_directionsnumber_of_componentsnumber_of_grid_points_vector1lnumber_of_grid_points_vector2number_of_grid_points_vector3number_of_kpointsnumber_of_localisation_regionsnumber_of_reduced_dimensionsnumber_of_spinor_componentsnumber_of_spinsnumber_of_symmetry_operationsnumber_of_vectorsreal_or_complex_density symbol_lengthnpsp codvsnlen rhoijdim1 psptitlen  file_formatETSF Nanoquantafile_format_version@ff Conventionshttp://www.etsf.eu/fileformats/title Density filehistory%File generated by ABINIT with ETSF_IO 5 space_groupprimitive_vectorsHreduced_symmetry_matrices  symmorphicyes0reduced_symmetry_translations` atom_species` reduced_atom_positions@valence_chargesatomic_numbersatom_species_namesPchemical_symbols pseudopotential_typesP$number_of_electronst fermi_energy units atomic unitsscale_to_atomic_units?xsmearing_schemePsmearing_width units atomic unitsscale_to_atomic_units?number_of_states  eigenvalues  units atomic unitsscale_to_atomic_units?` occupations `Hreduced_coordinates_of_kpoints ` kpoint_weights  ! basis_setP!(kinetic_energy_cutoff units atomic unitsscale_to_atomic_units?!xnumber_of_coefficients  k_dependentyes!date!codvsn!ecut_eff!ecutsm!etot!headform!fform!intxc!ixc!occopt!pertcase!residm!stmbias!tphysel!tsmear!ecutdg!usepaw!pspcod!pspdat!pspso"pspxc"qptn"so_typat" symafm"$title"4znuclpsp"lmn_size"rhoij"usewvl'Ddensity  units atomic unitsscale_to_atomic_units?T'H @IsnP@,'/@'/333333333333??????????333333?333333?aQ]7V޺o>BAeI~SlBc~m?J??IǞYr7,YOʭ?[d>IǞ?Yr7,?YOʭ? ivC%??Ah?[E??AeI~Sl?Bc~m??JB@@,SiSiSilicon, fhi98PP : BHS-type, LDA PZ, l=2 local`?^)none?zG{3333GGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGG@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@????????????plane_waves@   2AD5.5.0@WqrhLT,4>1t8?zG{@%Silicon, fhi98PP : BHS-type, LDA PZ, l=2 local @,GGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGG?z%?|ޱ?0t%?tC!??[t6?aqx?)?[X?`Q?S=?O?WD?OD{Ig?JK>?^I?YBQ3?f?aߕ0?4(6v?oT0?yl0b?kq?Bb$q?r' ?8?O½p?"?8Kw?*AZX?Gtw? CDg>"dU>;P%>ubB<>AW*>9>zj]$>U!> "y>KL>6m>>U\XA>/>U\G:>>62>KMV> " >U!E$>zj핒>9S>AW+L>ubB? >;P->"dT? CDg?Gt$?*AZ?8KZ?G];e>#?W2̵L?f[v&&?uĹ]˼?8*?ZL[?]?OD{If?WD?O?S=?`P?[X?)?aq~?[t6??tC&?0t+?|ޱ?zޓ ?xʽ>?ydW #?~?t^:W?&>?8ltA?L޼t?|< ?=x?v>5}W^>޷! >ζgo>>_n>\Ğ}+>e|>;t>U>̴S>_e)&>kXn>>t*>G >KX]>\1!j>|u$>Дkj>+Gne>\>xǖ?BZH?٧hK?"=/?1 ?Ac{B?Q *I?a?pp)??u?Zt?n'*s?]S?|?@5X????rmp?h\X?)Mxr?2* ?Oͤ|?~ %;?@wr#?sI?On?o?MW~?<\?][+(? BQ?.'hY?t?l?B? H[?<bp>f>Q]{\>ԇ9c܇X>>U.؛>jjV> e>9V>ݶSW>Ɍ>G >>ql>Y'>0)>C^;^>¥>̴3+>'V1>uU>n>)>/>Vxɼ>@(@? A ?2b'0?(e' ?8OeGL?I$"ɤ?Yv-?h) .?w]l?/P?q?*R?VHk?*({F?]?C ?eW?8!3a?09l ?hPhm ?o(?y=?u*y?vm^?}J?a0?kt,'?p(?{?r$?o ?c8@m?p?#b?‹?;o%?\?^R?{ ?F?/&Q?|%?k?tH9?p{?p]@N?s o?|Q\{u+?S?3 ܵ?w ?T_?Zh??r+?/?;?6j?i0??@?T;?k?>??F]?;#KW3?BH̆?g"ވ ?./?E?0"?sDfr?(6ڃ?W?9^@?B\?@b?|&?x}ʋ?kSc?\ L?Mi`} I??9Z?1є#?#*ls?i {p?{">þ0>M;>#x%>r*$Z>8fV>D7U>H'a<>Wtm>LZ>C9{~>y;%>c(>]dD>M}b>_<>ÓyS>c'>bf>>^̴'4> 9hO>ڔ~>i- >OJL?@г?ciZB?!h?0Džo?Aݱt?R%^j?a X`?oRȤ ?}(xh?9Av>?)?ImQѺ?~u?ø?Rp?Hcb2?yl,?O7??}#TR?tRm?qLu?qg=?v֤?ep8?zy<䦦>:eB >+L>hFhjO>Óu@>8h&4>>@>$2~f>X>Dž>3ӼF">@E7>'9~TH>:dWr>nv>T=U>G;ut>V`N>~>+m(>ʂ8|>;Tԅ`>>hf`>m? W?:5?'ea?7+)N?H\ɗvp?WZ P?e ?r5h?=S_g?n3?:?;,2?-B}?M{0^7?!} @?"Kw??WKʙ"?x,?rd?p-B?q?v?挮?p%?Baa?Rox?I#v?F5pl?!@"?K!W?n*?m>?)ya?Xb?ʳ?CZ^er?gg?Zz?|\7t?tٵ?qn?r,_4z?vfĸ/l?V_.??K`?z֓F?%ቾ?)ov?&kp&?%5?NʿW? ?,YE??%հi?nP"?W ?ku&OZ?XLt_?eO? ? L .?L*?7?R5lU?4=c?hp/?0jĢ??ϛ%?Kn?궴??ج:H?F!t?L?xBT?j,y?\k=?Mlͷ;f?= ?/r? ul[̬v?H1;?#>5菿V>Z~k>H/>緖>;R>:^tf> > c)>.E9>^f>=J >?VP̍>x.>嫇.><)$>p;@b>c+kR>,LC0>ٺ]>ȇ#>A|X>ث] LY@>昐$>4?S/?X0KP? | T?0N8Dp?@_g`?N{|q?[g-* ?gEY?s$S?}TrTo?p,ٮ?e?J?GW\4? ߭?UJ?!en?|MB ?vZI??s4纏?rcg9?uBI?{ő?x ?`NB?Av=?l! !?L]W? ?CvgLc$? o̜m?zuŷ?JfB? _? @?qP?bX?ſd? k$bw?A?{I5`?vZ?viwd?y %t>>垪O] >yY>ɛ5=>ACc>M͌>i./A>+Oj>n#>Yo>D<>9B>I>/=>ϔ>uS,>uLp$>t0>\ >źExJ>c>МdFP>ቿ`z>ҝB ?j: ? 90@? b ?&eT?5 }n ?CO@?Q>n%?\`P?fv;b/?6;'ѓ:?1ׁ>B8">D>W[3>̑TN>J>ڵr>~e3'j>OQ~>V̂%>Ds>YCA>>>Qѕ >y+as>Eo>kN$>>H4H>C/&>9Xb>Մ>~<>'{^>qI?0"vi?ww? pUM|?- [<`?9=@?E}#`?QRuː?Ze0?c?k9?qDT?t,(?vZ&D|?w0v^?v3A?v#9u"?v}?xU6?}s ?Mj??mƢ?3Dwd?8Џj?C:?{ ?|37?ؓ?~B"? lp# ?8x?`Z?T[o*?m*?(?)=?/Wf?? y>M?NW?x^? K.?{RL?lj6G:?\#D?J荔?9?* 8>?ԏ:? %86>CfPƜl>/s>!>.[ļ>(>!'~8>P#>0`,+>5qݕ>s] ST>d>u>t>"{I>z>>>x?v>x>>WT0>4 `>kLP>Fk1p>!B} >m%!{?mr ?N?&?'?^MH?2Ȁg /?=(x#]?Es?P1D!&?W?=n`?_c.?drD+S@?hwS0H?l9xa?o/˓?q#?s_&?wP C?}'?#ڭ3?*g?_Ma?l?&?׿B&?1;?Iq^?nb[{?&.?iSa?4>?p??d?Zߺ ? %?w|M?XM"E?~OC?zF&+)?{ ]?ml'?rZ4\>{>ݵ>Z]>.`>~>֦>Yhg2>_ h>rk>8¼"V>[GǾ>~L'>G> gXl>>>B >VQ>(m7Y]>S٦>|k>b\AyX>2㤠>F0d`?&-v`? p[Ȁ?1М ?&?'5d7?0ϛa?7tiJ?@)\臠?F9z?Nר?Tw ?YfC.?_U/F?c x*?g lΗ?lk݋?rl?y+O,Y5?3 ?s4?ԝӭ&?LEG?Zl?R's?|˒W?Ӵ:_QG?$?&&D?{KV(?aq?{?#K ?#̴_??*z??-^?B?yIB?vieÈ?vje ?|O?5 &?= ?vTW?v6J ? 3{??l6?$;0?(ч?z?lE?#+M?K?zgT?j? [{r?v?on*?^ҳc3y>A>6>ΝY >rEe&#>'^ b>Z,L>i>p?,>"2> 'Q>1v{>|j>-iT>R>8>]~>,8F>V>ޭ^X>X0n>;|>`)>'? X?"KQ ??%0i?-J ?304?:g S@?A!9l>N>7dV>,E>GE>#>ӂC>y!G>N/>d>Dx,>*S P>= ?>]6d>ؿ[7'#>=Эm>2.>v> Z>AA>w5@f>}% >3B?ZW|.W?s? 1[4a?(,q?1ؒ]?7~?@WQ-?E֟`?J2~!?O?QZ+h?SE<f@?Uߥ2 @?Wc?\ ]w?b=G?iv[?rsŐ?|gUO? z?$Qe?-?FOV ?L܆9?׃춺?wV0?12? L?ۭ?hle?Pٻ?sY*?p?IN?}MΝ?w,?q=`{֕?nkU?oǡϟ?t U?|.tq?༤Y<?Ҟ??8;d?8+?\y?HzC?T; |?Jy?R bh'>d>m)Z>݊im>| >6Q> > eo >#>B >F9i>Q.->Y>r40>Nh >4W>l>9|>վmx>\1S>8>.ڦ\?Zh?S eM/? ؠ?*2 ?4TCr??*MU`?FdJP?ONHx?T?X0?[~Ԑ@?]ʁw8?^tq?^~j^ ?_*m ?auo?dW߀?j΅v?rU6?|/.ب?!T%?DȈ:?r&)-?Iw?sy߾?ژ?׿n)?4?Fi@r?"]?zn;?1II?>d?GX?݂꿃?z4:?xɻb?rxwtj?pϝʼn?pp 5?tbr.w?{+}A?e?b=VW?OM(?IRc?T$|?1 ?.?Y5?4[?Ut{??W?:I?Ć"?K>C?L%??M^^?hJ$?x#(y?tɾ& ?s'(?t)6M?yiaKB?~k?k!?sۻ|*??a3WXTO?WP ?K?ݞ?㸪U??rK?lA/,?~j?`?~F=?p -?a=:?R>V`:b?AGl?1el ?"y 3G?/D4l?퐚b>HK#>s'd>Q>p=>0b>d,*p> s>&>ܠ%<>Z(QT>Ѿ10>v>`~>(e0>ON>o%J>^sr >0rߧ>6iv>o!(l>WNVx>( B'?V?)sF? X :~?+NGK?6?B#?M\I?VQN?_$w?daXG?hJw @?j\?kdE?kD@?jwnq?iЏ/8?i dl?jr6~?njp?seAw^?z\"u?K7 ?jAP?+.?Gj!P=?w^ ?tW-?:n?)??R"?>*?{Zg}?4@?)^?k?W?N9t?yye [?t?s ?uܬE?{ p؅?p?ɼ?&?}( ?b=?6׹Q?0yI?=9?Ia?DB?V2\Cޤ?DD?XUz?|@ ?ڜqA?x?a?1?i,?}|n?xr?vԮ?w9W`?{l1T, ?zr?1^?^RT?c=?|G&?ˠa?LjȓC?? ?Ģ(?և?`?BZ4?sI%?f5Q?X#hJ?IƵ&?:@D?+?HL? ZjD>Čn>}[a>z8U?>Ub>[= >Sh[>34P>|ՠX>{G]>u4@v>" vA>r>fB%>.>Yw>/hO>ɫ >H>NBϘ>v >_B>[ zk?q?rh?(Y@?5ުUuS?CZ~?Pق?[?M?e0(?n-`\?tp?xx[~?{t#N"?|YsR?{Pણ?yxV0?v|?t+8q?sW"?sh ?ta?xKM ?DJ?  ?Iv?G?)Ԣ?k;7֊?<`r?d &?~6 ?ӕZ '?fX?ڑ?gT!Q_?ڛj?3DO?vR0N?i7v?ds?'%lSTL?ym:?xKTj]?zG'?|q? ]?)5 d??c!?b~?U,SH?~9?pkv7 ?TY?# ?nDو? Ld?pgc?Lm+?m@?u )?JBM͢?H#?:?m?z>ج0?w*?w=y&?y.?|AR,?+4?Ԃ?ę:P?i3~r?G9?r3T??-il?|*?s $ؒ?h yN?\\?P yD?A&,?2mh+?$u4 >=~Zx>KTb>>~>>[>+z>՜#>&5>3NE> >3ND>&՛ >+Y>&>F>>KTb=?>=~Z{>u4?Hحp?kV?$ج,?m?-?H"?JBM͛?u &?m@?Lm(?pgc? Ld?nDو?# ?TY?pkv7 ?~9?U,SH?b~?c!?)5 dB? a?|q?{ p؅?xKTj`?ym9?'%lST@?ds?i7v?vR0G?3DJ?ڛj?gT!Q_?ڑ?fY?ӕZ '?~6 ?d %?<`q?k;7֌?)ԧ?G?I|?  ?DJ?xKM?ta?sh?sW"?t+8q?vr?yxV0?{Pણ?|YsR?{t#N"?xx[앂?tp?n-`\?e0(?[?M?Pق?CZ~?5ުUu)?(YB?r4?q<>[ x>_B\>v >NBϾa>>ɫ>/hȿ >YwwN>/;>fBI>r%>" u>u4@`>{GM>|ՠ\>>34t>SgȦ>[= >T>z8>>}[f>Čp? Zj?HL,?+%?:@D?IƵ&?X#hJ?f5Q?sI%?BZ6?`?և?Ģ)?? ?LjȓI?ˠc?|G(?c=?^RV?1h?zr?{l1T, ?w9W`?vԮ?xr?}|n?i,?a?1?x?ڜq*?R"??)?:n?tW.?w^?Gj!P=?+2?jAU?K7 ?z\"u?seAwh?njx?jr6~?i d?iЏ/8?jwnq?kDH?kdE?j[?hJw @?daXG?_$w?VQN?M\[?B#?6?+NGK? X :h?)sI?V>( B){>WNVx">o!(d>6>0s>^sN>o&>Ov>`~>(>vҫo>Ѿ1 >Z(t>ܠ%X>> >d,*o>0a6>p=V>>s's>HK#8?퐚a ?/D4n?"y 3~?1el?AGo?R>V`:i?a=0?p ,?~F=?`?~g?lA/,?rK?㸪U??ݞ?K?WP?a3WXTR??sۻ|8?k!?~k ?yiaKN?t)6U?s'(?tɾ%?x#(y?hJ$?M^^?L%=?K>C?Ć!?:I?W?Ut{??4[?Y5?.?1 ?T$}?IRc?OM*?b=V^?g?|.tq?tbr.v?pp 2?pϝņ?rxwt[?xɻb?z4/?݂|?G[?>d?1II?zn;?"]?Fi@n?4?׿n$?ژ?sy߾?Iw?r&)/?DȈ.ڦj>>>\1^>վmx>9 >*,>4W{>Nh Ɉ>r5dp>Y>Q.L>F9'>As>#> enU6> G>6Q>| p>݊imE>m>i>bh?n9y!2?U?&kJ?5vD?F!˟&?WT?g6e?vퟥ?!As"?%NX*?ٖ?y6?4\?z264?(~R?犘t?d׼S}?+R?5^˾?u?nDЛW?ыI?{c$n?tt;?pE‰?na;j?qiG3R?w206?/nB?^p?j(?,?i.?v<?R =?Jy?T; {?HzC$?\y?8+?8;c??Ҟ?༤Y<?|ް ,L?t U?oǡϒ?nkU?q=`{֔?w&?}MΙ?IN?p?sY*?Pٻ?hle?ۭ? L?12?wV0?׃춺?L܆8?FOV"?-?$Qf? z?|gUO?rsŐ?iv[?b=Gh?\ ]w?Wc?Uߥ2 `?SE<f?QZ+i?O?J2~!?E֟0?@WQ.?7~?1ؒ]?(,q0? 1[4bL?s?ZW|.^>3M,>}% >>w5@l>A\8> h>w>2>=вN>ؿ[8G >]6d>= >*S k~>DxB]>db>NݖI>y >ӂC>#%>GEN>,E>7>N >!9k?: X?QeK?)K[*?9Ces 9?Jdh b?\EQi?lH+~?{I/?oq4w?GM|?0sX1?y\?[ ?R}4?^?Dpl?t?fץL?z M?S;:?5?%Հk?}G?tҼ2׊b?oa@s?lܴT?oםp?ueb?~A'>`5>H@>X0m>ޭzH>$>,8>]x>8>R>-i>|s>1v{X> 'Q>">p?j>i=>Z,LS>'^  >rEd>ΝY*>>A #>c1? '!01?ve@˼?*:OsB]?;)ߑ9?M??^ҳTW?tr&?;F?vH3?qER?pi?rAM?xK;?%R"?%??u\?MOV?fRp?ǸKR?M@?8?xT7?x#??'\_X?vF0n`>2>b\A>|kX>S٧->(m7Y@>VQCD>B &@>͖>:> gXX|>G@>~L'4>[G>8¼>rki>_ >Yhc>~>֦*G>.j>Z]B>ݵF>p>rZ4]? ;HZ7?z r?+I ?;Mә@>?M[?^,"{G?o\QKn?~sD ?od?E.R0?g?B?R?-L?LjB?m?KlO?9;0w!a?pdh?xLG?XH[o?(~P1N?^T 1?jY?%`?U??iSa?&.?nb[{?Iq^?1m%!`>!B}>FkO>kt>4>WT>>p>x?>^ >>"{z>t\>!>dS>s] >5q->0`,%w>Pa>!'~8Q>>.[or>!c>/sz>CfPơ? %8?ԏ?* 8I?9?J荔?\#D?lj6G:?{RL? K.?x_?NW? y>M??/Wf?)=?( ?m*?T[o*?`Z?8z? lp# ?~B"?ؖ?|37?{ ?C:?8Џe?3Dwb?mƦ?@?k?WI%?bx?JFBY?\?jXo?q?uk?ʣ%?]#X?і)f?˖?܁T?~D?zw|X!?N? ihr?˚Ë?)S{i?Yw2?{^?'UPY?F?g?o?~\i?Lh?8q?b??s7?*f? ?qI>'{^>~<>ՄS>9Xa>C/+>H4%>>kړ>F)>y+b=>Qѕ!> >>YBl>D>Vˬ >OPT>~e2>ڵ֭>z>̑T>W[>D>B8v?1ԏ?6;'ѓ?'n>,?6SV݈?GK-2# ?XZ=?h4?vò?s? ?sa?rsnP?g1h@l?UZ? z+?Y2?hjJ?9O?]?#X?vq|?m;@?qk:5~?Ն1;X?]@;?Ń?o}?6r`1?=u?Cv1L?4'0?*?6}?w9?tn$?CO@?5 }m?&eU? b? 90?j: >ҝIP>ቿ`p>Мd>cE>źEx[>\&`>tX>uL>u >ȱ>/= >A>9Bmf>D<>Xr>l>*͖>i..>M9">ABU>ɛ5;>xv>垪OM>%tA?6Ĝ?]FmE4`>昐7>ث] L>A|C>ȇ#Θ>ٺ]0>,L>c+n>p;@d><)/Q>嫇~~>xb/>?VP_>=Jk>^o>.E> c> J>:]&>;Q>緖>>H/֪>ZtX>5菿-?#?H1? ul[̪?/r?= ?Mlͷ;:?\k=?j,y?xBT?L?F!l?ج:E?궴??Kn?ϛ$??0jĢ?hp/?4=c?R5lU?7?L*"? L .? ?eP?XLtb?ku&OZ?W ?nP#?%հi?,YE;? ?NʿV?%5?&kp&?)ov?%ቾ?z֓H??K`?V_0?vfĸ/m?r,_4z?qn?tٵ?|?j:?Zz?gg?CZ^er?ʳ?Xb?)y]?m>?n*?K!X?!@"?F5po?I#v?Rox?Baa?p'?振?v?q?p-B?rd?x-?WKʙ$??"Ky?!} B?M{0^;?-B}?;,2?:?nE?=S_g?r5|?e ?WZ ?H\ɗv`?7+)N?'ea?:3? W>m>hf)>>;T|>ʂ8P>+>> >V`Np>G;F>T>rc>n(>:dVL>'9~TQ>@>3ӻ>Džk>Xܡ>$2~"a>>,|>8gr>Óu8>hFhj*>+B>:eB>y< ? Y?l ?(֨Tv?7$$x?E]`?T tYz?cˋ?rޟ*H?^?G2?-?!ʉA?Z3? ~s?a w)?eM?*u(?$\\?C!3Q?bjRY?FT?\NIj?kD? ?K?eq?#?R+g? f0?:?l?f?j|;?c?H2? ٱ?XkM?בֿOJL>i- π>ڔ~v> 9hP&$>^̴FH>zh>bh >c >Ózy>_<>M}b.>]>cQ>>y;U>C9>Lx%>Wt~Z>H'`>D7UY>8@>r*#>#x>MV>þ0?{"?i {?#*lqD?1є"w??9?Mi`} U?\ L?kSc?x}ʎ?|?@b?B\?9^@?W?(6ڃ?sDfq?0"?E?.-?g"ވ ?BH̆?;#KW3?F]?>??T;?k?@??i0?6j?;?/?r+??Zh?T_?w ?3 ܵ?S?|Q\{u/?s o"?p]@M?p{?tH9?{!1K?/&O?A?{?^R?\?;o"?‹?#b?p?c8@n?o ?r#?{?p+?kt,'?a0?}J?vmo?u*y&?yB?o(?hPhm?09l ?8!3b?eW?C ?]?*({H?VHk?*R?q?/T?w]l?h) .$?Yv-?I$"ɠ?8OeF?(e' H?2b'? A>@5>Vx@>/\>)>n0X>uVF>'V>̴->¦Ɵ>C^;I>0)>Y' >qj> j>G >ɌƊ>ݶS>9W> >j_>>U.>ԇ9c_>Q]>”>bp? Cx?8.*?*abn?7ȣ"9?EhCo?Tw x*?da ?s6?}?{Թ?p ?a܏?/ c?fJ?2x>\:>+Gn`z>Дkr >|v>\1!l+>KX>G\B>t>G)>kXo>_e)&q>˔Q>U>;>eG>\Ğ|C>_`> >ζgo>޷!2>5}WV>vw?fZCn?Ofդ?#ED?1f?@:bn?NϫC:I?^| ?m9Ә?|-?Mﴉ ?^ b?΂?ʚD?:?_?Π.\`?=V?HP'?ݴFĺ?|4,n0?&?Cu?ڈ??a@l_?eF ?9{?/kX?(}H?xqe?ߧqf?&ȼ?L?p??t^:Z?~?ydW #?xʽA?}[N]?L}Q,?ve'?M 8A ?x׌ST?!?Ff?7jO?)]UHKi>Kn_>Xj`>[>]~$-> >F">E(>X؟>L`>]o_E>˥X >]nI>+>X0H>E򹫉>Fͷ>s>]~$>[(n>Xjm>Kl2>HKƐ? f"ڛ?XFת~?)]U?e ?t-? ^ڕ?q=?i?HP^I?݇_?a >#9>ވj>J4\>Τy>\4>lj>zIL>vĵ<>8k>"I>5R>hxo>{Rzi5>Mѷ>￵>h\U>xr">cGq>*12>UbT>nG>. P>oMj?{j?dw@l?"(l&W?1 @f?@d.`?Q;Ȭ?`l2V?oj'?P?rt?h;?Kbs?%k?`Q(8T?pz?8ߋO?Wg+?C:?:"r?c%2g??i50@4? V?EE5?|E?|44A?0B:?OYJJ?{޸a??NG駮?2N@?d?E?!q?%COm?35n?-?'+M?7$?~`C?~Oe?x.ޏ6s?u8?v{!?{~RTQ?Q? *w?Ac?$WU?W?9?FQ :m?4;OJ?@=?tL?T ?[U? 48 ?g?##ε?}N{?zp4?`?ߔ5?_?Y$/G?=ܱ^?s@Ģ?9?1\|L?DQN?0: ?`@Kcd?Ԏl$?>#?r6bO_>->X>ԳZ!Fr>/Jzd >C>`ol>cإ>p/]>M>?~>dIe>ɋ}`>oadK> >sij>fj>x 2>-Id:>,Fp>́O>հZM>\>ya B`>d!݌? \?t?'4D?7 x?HI?Xu?gvn,?vgU@?K, ?Gf$?Jt\?'mZ?eF?lEl?7Kp}?B?3=L?&C Z?ݘd?lXe-h?{(|?wq#%k?x-,J?~fb?-PQ{?H?e3}?2nGzp?aX ?;6?w5?Ct܋?nliu?m? lE?G מ ??F?{?F&\? %?Q[#J?v-Fe?1?rNH(?q-b?tT@)?|(j?_1M?P_?eE?~ o?+0?8?RvN?/3?AdӶ8?:츌V?L/?}|?SP??-J?W+6 N?M??3*'?-M?>0''L?ȃ?di8?H:?DP ?"͇h?*?[X?V ~?wnvD?jcs9?[U4E?Lj]t?>srH ?1O)c?"-HJj?>+8?0]/D>+$ >a> >̟dBR>[>i<,>Y"k>ca>?>mV>>|˚4i>L'hL>`W3>vD+>ll>hF->6\g>{ P>M8Z>=>񱓚 >4X(>x8>HGD?V.?,(8? ij?0?AQ>+pm8?QtI?`_ }d?o.T1?}bR,?[͘ j?oyJ?{&t? [.=??z%U?YN;I?>I?71z?dI?@`?wf8?rʭu?r^?vdB(?bG?dbV?:V@?t'l{?$U?[ ?|,4?7+j?|C?^y?R@?Amy?R?TB ?&D?g!H?WTI?vc,?q ف?pSvx?sp1 A*?zȅ:iA?΍&?E=+?_㷀?_~?N?M?R6?p)'?(?Ǝ߇?>h?Mjc?mUO|?X..?v?qQDG?7Do?h{?mq1?if >?[.?4?1p?m#nA?x\b?pY\~?ټ?BՍRh?b@0k?~#Pp|2?qC [?bҷ?S#T?$?D2R+?6v1J?(1G?[w? zG[D>0f, >%.ɒ>_]V>b>ä}>{(s>A>}*`1>3>=n5J>|0.>āL>֍^>WP` >Pd> ŸF>K>8_:>L.&>u,>X>Բ> [> c>1l? q?1?'R®?7ް?GhICP@?W&[ ?dfl ?r T?YY?. ?*A?fe4?2/y?œc@-?<^۹?\,GV?cJ ?0E|ɩ?{Wi`v?t'ܰ$?q?qxz?v6]?[n']?˕?dVXo?.v?/{?8!'O(?P^1?R^q&?(?7L[??D%?]eol?I9?k5?^ k? ?=n?!?h.r?u= ?Q?{?I&w?U%j=$?h(S~T?$[V?g?BI?ET`? h?J?([!d?C*?!ɳ%?Q^X~?vm^?i|.,8 ?[qO?LSuk?<4.l#?.>I? ?b'?3S6>_>W2jV>՘>ƮM(I>#ލ*>/L*3$>t^h B>X>yN[<%>`)>L>W^*w>d:>sJ">c!Lf>m>>٤:>>лYC> ]>iw3>Yrֶ?$?LP?! RR?0#F٠P??-?Nn?[vUw0?g c?sj?*_?~?)1?=L?i???KY.h??J?uz?y RO0?uIA{A?t9=?vIS?{D>BD?@I?Hm?ê?⭺=X? ?-rk?S&<}?)u?[~Y?P?$?R8uѵ?4?w??/Wg?~xe?y5:?x}j?zi V?0h?gx:?W?kfM?&+S8?㥣+&.?T`?J:~:!?6@-Y+?\?Z?K;?>#S?:??tX??sq?u&X?]%JO??HU˜?2J+6??0"?Խy??r=H?+?N??V[/>?U׬?b[+?`~V?~BM?p.6-U?bA6?RDX[W?BM=?2};ij?#[2I?.[5?t>󎬦>5 B>{x >I4>Ve >}f>DD>> !Q>K/ؓ>G2h'^>۳JQ>I. >#2@#>BE>]>,Z߃>ߥ|>kܿj4>畆>Ȭ&>baLI>5z >ۈ!>KN[?3R$? )5?=c?& ?5#?C[X@?QV\?]YW@]?gA\?qe5#D?yL?4"g?^5*?ݛc?nV:?? Ƶ?{V ?y2 ZR?y{ ?{CpسI?^_?5 h?k?/?FT?͈?~?N(o?U 'e?z2Z?R ;e]?K?w`.?8YMT?%xJ?XHq;?1UI>d?Fv?^?$?u^T?;h@?Dp?6+?z~,?cG?uͅᆰ?gҲT߾?W[nc,?Fjk?5]f ?&ᤰ}h?`z?͞>W> >n[->l(>Iub>P->-H>pC=->>Dēk>9>3>-I>ʦv:>ֵ>Op>T>9S>yh>oN3>S3 >uF8`>P(;P>Z@?:|3? ui`? `?-aV?9 TY?E&c ?Q?\qp`?eg9(?m_h](?rvَ?va*lL?xhU?yir?yH}?yB?y??{,?(.c? Ȅ[ ?l?}K?bIQ??J?;N7?x?Lid?:L?=v8~e?N?cp?4FR?G$?Qz]B?c?=C$-?DM?A`2?}LB?ͽx?_1?U-Ϟ?P? 0?k+?n1f'?*QQ?j?T,FF?- ?-}?¾Ī?Y8N?E7P?&c]?mB?7:m??Y$?~r.n2L?A?Oh6v-?t0?Z.?jm??Y:?ή?DsB ?mˀ?=;?%m?]Vn?@,"?8n@?U9?zMD?k+"WL?[Qvʋ?I]!?8ZeN?)k?7 ::?Lʧ>كE>\>>A =r>=N>ʸO>0>J>$`[H>Br>%Y`>H}>'x>756>>vCNp>H’>x>w>*mAp>e>; >ڪQvz>u 𒕰>5 >#K?<?+pF?W_ ?'mvI@?2 ?=]E?Fo]&>q s>򯺡S>g R>Mf>#|>L>+>8rqc>E0x>͙W@>) =T>SiC&>=Y>Ǝ}>ܣ >jzqZ>AI>m-x>d>~[B>vw;`>UQ >4\q> ? ?:m@?E(W?`b?' {v3?0I`@?8c?@ޱ i?Gw8`k?PFȪ`?Uj5?[?aqV?eۍק?jMA5f?pbܳP?u gP?|WK?C?u#?O4?rGDI? " ??9?JKwdV?73?ydp?$?o}?Z7?P֥?me=,?hcWV?!?3 ?;}?{(~?x,?yRg] =?at? H?ּ6?R0?!'Mgo?̡ ???N?\ ?W>F?Ji҆i?55? Gj?& ?H;VR?> e4 ?o?ٝ&?yUӼh?tu?rE΀?s+ï?y oo?o4?O'+D?iE?fGۉH?76?GG|(?4??n3?->X-?,?ASh? t?Nd?Qox?<?}y6?mU`r?]H.?Kex?:QgX]~?*Wudd?V? .K>غ|kX>U/>x0">e|>@X>$N># )>h}U>)]>fC->4x/E>K}>bnG9>2g,>sT?>=%d&>GhMW>\(yS>O>r8”\> x>;9&>e@GP?>vhX?x!HH>?O(i?$Fe?,%U[?3˞8@?:8Ŏ@?A5?FO%d@?Km8?Q5ɠ?U p?Zxy$>0?aa'?f8?mx?td=)?~uoV?M4?Ǯ7:?R}?h? ;?ё?I^?B_?Dg?v&\?*cK?ٽzN?m9:4e?Hai?FP?/~#*?|Pq?v4E{?ssKP?sw?wOhal? {@H?zL?IBD?w1f:?1Z?^ ?+4?17#Xt?98=?y{#g???H?Uބ?2@?0|ji`?~bޜ?uU_0K?p?o?qd,:y?w$D]?}?=m?-LR?bL?s򆹓?hX}j?K[?-(M??_PX?cBa0?kC[? pa?ɐG)z?2=?.?z9T?kT&?[ "?IrKl?8}RL?(h&?ы&>&/[>n$p>}Ū>VoO;> "4>Z6hf>h,W>޼Tx>T+'~>wVm>n݃>D39>S m>Î)j>/[b>~ > j>We>ڮg^>w8>+=H>+[|?ۚ?E?4o`?'Sa?0KQR@?7 ??eQ,?D:,L0?Iظ$?NmT*@?Qv[?S<?U#?Yns>&>ض9QH]>MP>Aٲ>:24>3>t4>K2 Cz>YHQ> (>~>~4>[Ÿ>&3>o®>>ɣ >!7>✎y46>>{?{C;?Ꭸ,? zQ8c?)ڷ7xt?3< ?>! R L?Fi?Ng,?S8"A?XBw8?[;~D?]^W?^hP ?_ϙ@~?aQP`?cVtXy?gmH?no|H?uY.?{r.?]A?1g?@)C?\&ڞ?W#[[?tX?&|j=?4; ?OY?g׼֑6?QCغ? Q?C;E?6[*;?|?M`?x+}?sII= ?qcO2Tl?r[q?vIJI?2n g?g/?> u?DrmX ?;?M.rP?y!V?J-?yU({?ۚW?yK?> S?Si?b B?u ?oO|?_:Z^?.{?y6#z?uʬӺD?u4$sZ?wR$z?| ?]\ ?TG?קH[?WI>䕸(+>,p^w:>Ǎ*D>%T<>P_B>.J>>4>^,M<>2i7>2H>!3`>>]>hk>̦@Y>s6M>T=M>5>=2kR>H?R8?n4T? F?*I?5bͿ?Bk:?Lao>?U?^jSC?c?gs-D?j*/d?k?kփrԊ?kٲM>?kWdd?l vP(?n2y@ P?qm/T$?v J-?~tIq?qiǪ?J,d?\ ?q? V_Z?6f:?bM?MJ?plN?ARr!?9»9?/i5->-$R]>+>;Œ+>Ď"XP:\>4,{>ǥ>H>y~$>1V:I8>Rh>4̓>Ms;r>5N>1l>H >=bX>iOP>ּ^紟>o> <>9? ?ݤEGr?w~vٙ?v1)?udm?u 0?wwkp?|/c|?!%?8?2 ?{ݕ ?Gh1?~!i?zםO(?zJ)?| x*?_:Uh? ?/J?UP?%i??fD9?:Fˬ?y|??<\=?{?RLϹ?r0ufH,?g`R ?[N?N 8ʐ?@@J>?1==$>ʕl>Ow0̞>+B>& ?>rљ>9d>U y>R[X>.}]Y>L|½>.}]Wv>R[k>U %>9R>rљR>& >+BˠN>Ow0[>ʙQ>=.?`?D}N!?#̗v?1=?@@Jp?N 8ʢ?[N?g`R&?r0ufH*?{?RL?<\C?y|C?:F˻?fD=??%i?/J?UL? ?_:Uh?| x*?zJ) ?zםO(?~!i?Gh1?{ݕ?8?2 ?^T>%?EJH?B?2ew?Y_D?r[i?|_?|L</?u, ͆?^vo?["[z?:?%PP???^X?/_֢­??~C/? ?{w낄?|{?x?< vs?ze? 0?_?(x?U}8> E>oެ>ּ^չ>iOPy>=r4>H҈>2W>5N/$>Ms@>4̈́>R>1V:F">y~>>!>4,I'>Ď"XP@>;fY>+9>-$Ra>5-J? 1%Ҵ?"`?*؍D?9crO?Hc!C?WqW'?eɳg^?rӅPǰ??z^,?Eo9?WR?N -?%Z?f^? $G? SN?0,t?0پ?kփrԊ?k?j*/d?gs-D?c?^jSC?U?Lao>?Bk:x?5bR?*I? F?n4W?R8$>H>=2kF>),>T=d$>s6Nd>̦Pn>hk>].>U>!4H>2n2>2i>^)>=(>.=>P_R>%(>Ǎ*D>,p^U>䕸(6>h?[2?D?"HSp6?1gG5?A6QK,*?QA(j?a*g`?o1Ury?} -% U? S?yJ?ۚW?yU(y?J-?y!W?M.rQ?;?DrmX ?> w?g.?f!f?vIJI?r[q?qcO2Tk?sII=$?x+}?MX?|?6[*;?C;E? P?QCغ?g׼֑5?OY?4; ?&|j! R 8?3>ˤ>✎y+:>!6^>ɣ v>>o¦ >&>[T>~4>~> )>YHQ>K2 AL>t4՛>3͘>:24_>Ad>MP>ض9QHD>ϯ>ns?rL?tΩ}P?% n?5Q#NN?EFyת?V|_!?f!sk?uk9v?\n?EsV?Cq?Mj?۶\Fnn?V@s?Z?.K?Y?}]? n1?2f??3W ?~w''y?vYꔭ?r"2o?pމ)֑?rU͏ ?wgG%X?X4!?7D\??3~o?X?WOz?6o5nh?z7p?v 1{?n?oT'?g4?]ۇ?^mj~?YC?@?8̰H? {@H?va pwx?qIo?pW?qkbn?w"X@:?|yv?'?c!h?s&?`* ?peh|C?<^A?Ո߁Bf?2,v[?ȷw%?Cs?a?n᷈x?E?mO}b?fEݜ^?@}?ufbq?l?e'·?`008$?Y+[X>+=H>w(>ڮg>WK> ߭>~&>/[f>Î)ԯ>S =>D3ȗ>n݄z0>wVo>T+>޼R>h,Vv>Z6h> >Vo!Z>}Ř0>n$p>&/U>ы%?V??ɐG){? pa?kCZ?cBa2??_PU?-(M?K[?hX}l?s򆹖?bM?-LR?=m ?}?w$D] ?qd,:~?o?p?uU_0>?~bޜ'?0|jid?2@?Uބ?H???y{#h?980?U p?Q5ɠ?Km8?FO%d?A5?:8Ŏ?3˞7?,%U[ ?$Fe?O(hP?x!HH=?>vip>e@G>;9,> >r8”]>O>\(y2>GhLn>=%d><`>sT?x>3+>bnFٽ>K}0>4x0޺>fI>)] >h}Us># G>$MY>@>e|>x0P>U"h>غ|h? .KA?V`?*WucR?:QgX\]?KeJ?]HB?mU`j?}y6?<?Qox?Ne? t?ASh?,?->X- ?n3?4? ?GG|(?77?fGۉH?iB?O'+F?o4?y or?s+ð?rE΀?tu?yUӼd?ٝ&?v?> e4?H;VT?& ? Gk?55?Ji҆k?W>F?\ ??N?̡ ??!'Mgo?R2?ּ6? H?~Q-J?yRg] >?x, ?{(~?;}?3 ?!?hcWU?me=,?P֥?Z7?o}?$?ydp ?73?JKwdW?9? " ??rGDI?O3?u#?C?|WK?u gP?pbܳP?jMA5f?eۍר?aqV?[?Uj5?PFȪĠ?Gw8`k`?@ޱ h?8c@?0I`?' {v3?`b`?E(W? ?:j`> @>4\q>U^@>vw;@>~[Jx>dh>m-h>A>jz/d>ܣ >Ǝ黏B>=>SiCQN>) =T>͙W{>E0w>8rqbz3>+^>>#>MfU|>gO>򯺡&>q _>S? (7 }?G z8?*osV?:roɜ?K,?]?m0+p?}VZMԂ?迄`?8,'?kK?@9jQ?@?v.?àm??/{b?q8h?34פ?{!?R#њ3?ɛR?ThkbT?{a?x1_?xBWS?|R㫿?0C}?y#O >5>u >ڪQv >; P>eP>*m>x>cT>H“>CNp&T>v V>756>'>bc>%Y㟴>Br%>$`N>0>ʸN>=NOu>A =VX>Ӷ>>كG>?L?7 :?)k=?8Ze0?I]?[Qvʋ?k+"WL?zMD?U8?8n@?@,!?]Vn?%m?=;?m˂?DsB ?ή?Y @>ZP(;>uF970>S3>oN3>y#@>9ST>UEz>O>ֶH.>ʦv;>-q>>$>DĒ<>ٕ>pC=a>-HH$>O>Iu}>l(Z>nZ>>Wd?͞?`?&ᤰz?5]f?FjkH?W[nc:?gҲT߮?uͅᆰ?cG?z~,?6+?Dn?;hB?u^V?$?^?Fv?1UI>f?XHq;?%xI?8YMT?w`6?K?R ;e`?z2Z?U 'e?N(p?~?r`>͋?ݲ? x? qv??IΆ?~m?BY D?b |??U?:?U;o?.D?&?Q2?}\4#g?~xf?[ |?vK?H?N?e— ?j?~{?Ë?r{`?ޚ]Nw? `m?Fv?KN[" >ۈ!>5ǭ>baLXp>Ȭ&>b8>kܿjƼ>ߥ~>,Z>]u>B >#2@>I-+>۳x>G2h&.>K/OK> !P>DC[>}|>VeD>I>{w>5>󎬦?t$?.[6 ?#[2F?2};ih?BM?RDX[\?bA?p.6-U?~BM?`~V?b[+?U׬?V[/#U?K;?Z?\?6@-Y)?J:~: ?T_?㥣+&.?&+S8?kfM?W?gx2?0h?zi Q?x}j?y53?=BP?vIS?t9=?uIA{A?y RO3?u~?J??KY.t?"?i??=X?)8?~?sj?*_z?g c(?[vUw ?Nn??,?0#F٠P?! RR0?Lp?$>Yr`>iwR> ]>лYC`>>٤#>A,>m>c!L|>sK#>>W^*ٗ*>LZ>`))>[>yN:>XD>t^h F>/L* >#<>ƮM('>՘>W2^>_?3Rb?b'?  ?.>I~?<4.k9?LSuf?[qO?i|.,8?vm^?Q^X{?!ɳ%?C*?([!c?K? f?ETb?BJ?g?$[V?h(S~V?U%j=%?I&w?Q?{?u= ?h.r?!?>p? ?/wBt?(L?dfLL}?`R?~+ "?W0?STw?U"?Ú6?nPiY?v7?,?w?WTI? ?^ h?k5?I9?]eol?D$?7L[1lP> ̈́0> m>Բ>Xu>u޾l>L.>8_`>K"> ŸC>Pd>WP`_>֍t>āL>z>=l>3>})P>>{(>ä\>b>_]E>%.ϖ>0f, $? zG[?[ ?(1G?6v1I?D2R%?S#T>?bҷ?qC [?~#Pp|(?b@0k?BՍRf?ټ?pY\}?x\a?m#nA?1p?4?[.?if ??mq1?h{?7Dx?qQDD?v?X..?mUO}?Mjc?>h?Ǝ߇?%?p)'?R4?L?N?_~?_}?E=0?΍)?zȅ:iK?sp1 A)?pSvx ?q |?vc"?Q[#H?g!L?&A?TB ?R?Amy?R@?^y?|D?7+j?|,4?[ ?$U?t'l{?:VD?dbV?bH?vdB5?r^?rʭu?wfA?@b?dI?71y?>I?YN;K?z%U?? [.=?{&x?oyT?[͘ j?}bR@?o.T1?`_ }?QtI?AQ>+pm8?0 ? ij?,((?V4>HGU >܊>4X>񱓙>>M8K>{ QH>6\]L>hF>lmC>vDӇ>`>L'h+>|˙>m1E>?>c`V>Y!N>i;#>3>̟dBR> $>b>+$ ?0]/B`?>+3]?"-HH^?1O)b?>srH?Lj]?[U4E?jcs8?wnvD?V y?[X?*?"͇h?DP?H:?di6?Ȃ?>0''J?-J?3*'??M?W+6 K?-J??SP?}|?L0?:츌W?AdӶ9?/3?RvN?8?+1?~ m?eE?P_?_1M?|(j?tT@)?q-b?rNH(?v-Fe?$?~Oe? %?F&\?{??F?G מ? lE?m?nliu?Ct܏?w5?;6?aX ?2nGzq?e3?H?-PQ{?~fq?x-,T?wq#%n?{(|?lXe-j?ݘ_?&C Y?3=L?B?7Kp}?lEo?eF?'mZ?Jtb?Gf&?K, ?vgU>?gvnD?Xu?HI?7 ?'4 ?? c>d!>ya B>\`>հZL>́O?h>,Fh>-Id;>x M>f>sij> 6k>oae7>ɋ}(>dIb>?}>M|>p.d>cѽ>`o>Cg>/Jzc>ԳZ!>X>+->OZ? 9'^?{kW?*5ca?7 \ȊN?D?S[c?czPN%?r6b#?Ԏl$?`@Kcd?0:?DQJ?1\|H?9?s@Ġ?=ܱ^?Y$/F?^?ߔ8?`?zp4?}N{?##δ?g? 48 ?[V?T ?tL?@@?4;OI?FQ :m?:?W ?$WV?Af? *?Q?{~RTQ?v{-?u8?x.ޏ6e?}qL"?~`C?7$?'+M?-?35l?%COk?!q?E?d?2N@?NG駮??{޸b?OYJN?0B>?|44B?|E?EEo[l>. P>nFܘ>Ub>*1^>c3>xr"Q>h\n>￷!n>M >{R{1r>hxo>5R>"I4>8k1>vD>zG>lI>\>Τy>J4\PZ>ވj)>#޲>a ¨?jַ ^?k߆V?#3sN?1][S%?? U3-?M!?]DS?kPD2W?z?cx-,?ibǜ?׮o`&? >? ^>|o˺u>J~5>ռX> j>f7zd>ߌV>#`>`H@>0Uq>p>Jڼ>ʀ|>JŶK>phi>0U)3>`H@[>&>ߍ>f7y> dh>ռXb>J>|o˺> ? r(?CLV?'9N?5}[p?D+$?T2] ?cFs 7FA'>?4}>݈m$٘>%7>ft4>W#1>Ii >d6&>m.qb>zgN>ۢƭ z>Ӕ#>TZ>Nuہ>S>/Փ >`H<0>d[)L>p)1>V$=>α>ro>C/ל=>N>?fZ? Hٸ|? 8M?/44?>n8l?O3p?{}N?~O܆)6?;k'M?gP̖?8^;&?=&s??37 ?2y?z~?j?BG?ix9D@?N?rf5?3g>?* ?ZU?M?̾?It ?L? ؠqyV?LO?ܰD? ]?yv?B(:?k~z?Skі?HNO_?C#vh`?|n.?ov6O8?a t?Q(?B>7?5N$z?(--?P ? oyw>w{6>E]I|>%q">k{Kj>ŵ_$>CWYB>23o'>$Y;>QU{.>O5>{lq}> &A>C> >*=>U(2> F>|+>ϑ#>3V&>\ <> X;H>~Wx&>O51>)B>dJWP? nؘX?3?&x0ј?6\`?G1o?V0?eGr"?t|j?h?z?In? kG?N^?O;?ޭ)?AX$??se?9="2?G+?p6T?E0R?,93?5?}$1'?{h;(?kghL?Fy#?A?{c_R?Ϫi"?JQH÷?6d_?Ol?1IQL?+N*{?D? ?0xi?o?|di^??(ܦ?Ȳox?` ?xJ-?uӍj@?v߿W?{æy?1:hx7?Tt?kY?ݓ ??"~:^?8j,?4?+sF?syN?LJ?uyCoi?D}?XjBJ?tJ{&?f.C?XEl?IxL(?)dղ>S7t>ڣ$7u>˘ >q>jq>z>YY>leZ8u>߉8l>@1>ď9/>> $>:'>1֡>,Ɲ><ξ>?T>Af1c>xMɈ>)q>+m>H?и?O? K8?/\lP?@]{?Pr?_&V?mڢ?|FP `?iq?Yw ??DE@? f?U>S.}?ՐEDt?3XK?l? J3?XB?}`b?wdFS5?u{R?w8?~~0R?6(iwI?'e?r?ݸ?R?ʈ/v? i#?驓%`?3 ?{\.?Qrh?N?[_?jud?&?#p?~5?wo-+7?t*jL?u{[]\Y?z@IYw?#,^_?n ?Cԕ8l?p0 2?.I?N#B?~H?a?Gs7g?e}F?5#? v?G?ָܥ]?N?rb? ?QNj?j̒\? w]8?pvo?Y?t ?̤?ta ?ts?Q?qLx?tW:?yP?mۦ?`~*?Q_?Bֵ?48?&\o W?ٮ? jW&>N>L(>_,>$|q>']Ύ>уFk>ݿ9>u+Z>p;H>47>o|>^?C>>">Ca6 >F=1kb>:Vj>8>Nji 3R>z[]>D^>ȕ2h>XjOK$H>u x>Gm@>j+q? mW@?Z_`?'J^?6٭T0v?F[?VB Z?dБZh?rm&(? ?H<?;&?*rAE?ϲf)?9ȭw??qd?Iih ?ı%?رdhA?gֿ|?(k?c`^,?1?W=:? 9?_V$C?o”?z Q"zO=?x/yc?y,m?[6j?{*Oy?Tfɔ?=?z"?A?sY`? ҟ[?i?d!F?:}@e?i1|q?Z;?pD?8S ?+Q?ݞ!7?r[?Ѯ?)ǵ0%?9X_?>%??+<B? &?4>\Gp>9 >[9X>PM)V >g<>O>3J>-âN>\&>>>q(>Zw@> $q> =>ιUf>c+3>Wb>aƮqx>Jé>ʌh>K!;x>Ы?^>7+5V >K!T @>UI`?? M`?!18 ?0&7wv??)w@?Mr{?[E ?hw]cH?tV}?xm?{Ѻ?7)?<^5N ? l?-?iJ?D!>r?s?0`"?{?yM>%蒐>׎{>$Ձ5?>@8>9"c>^N >yD5>|P>t>$>e.TI>է"[>,.>5r>0.sb>7oD>gT>ݲtM(>MM>isp>e#0>;l]@>o7|>O? ރ`?"ῠ?''ĺ?5._?Cq?Q*SY?_ X?iƺFj`?t3P{?|l?L?ݤ ۖ?~?"?OV?נ? dr?ML{|?7R?Gy$r;?}I0?0|?j0 ?Nz7?Cu1%U??3͔?j"t?HV}?xz?P]ý?ɋ2?[h?Aa?vGU?ѐPi?}?yH?[_DL?Q @?KM?,?>&i?KX?C[:b?핂WZ?#h&q?GG?rGʹi?U ?:eE6?/f2?c?dC?И?U??rstf?dC$S0?TuwZ?D ?4L]}?%J9?Y|>K:>q|^>W\T>OձZ>ް۸>`eĵ>R E>SΟԻ`>ƖH>~śy>˅>.B>G~>evC>z?>!">%C2>'.>LVи>o@>Np>[>n >{)?C?dRԩ?!1`(?.@?9N?F=ڼZ*@?R?_'MP?h[~J ?qn*H?v^@4?{FD? ?z2W?T;C?Ax?n?'?& ?F?׏w1?udjX? F?IO?pֆyD?IX>~鄴>胍>p _>H~>A >t&q>aH>yOiC>Qb`>P_)>dR> N-`>K&I>~P><"M>Opܭ>IuF>5%y]\>8XXP>H2(>g'P>+@>1W4>s%}>JA?t??Xʜ?'i?3yf@?>9?Guv?RԟD ?\z ~?dAM?k<%p?q5|?tí4?xxom?{+]\?`&?ok ړ?00?n0@x?y]?{ue??"4gb?41?(q_%?]@D?UÃ?e5:?O?FЋs?vz?//v?o|o&O?Ju?6+?#q?\9$?Še?d?s?])_?}H?kU?w?`~A?Q.E?)>E?׹Y?8T3?܋R?g?F*SBw?J~S?z/?K\=??8?l?8Ǚ!8? m?v?:{A&??CAc?s.>&?hŵF?= ?rl:?Z[Ζ?TC+?x\9?8E?iV?#?ۖ|hp??Г?I0?y!a?i90?Z @*?HQd?8n?(CU?|fx?\2>qL>x{Uª>ݡbn>΋Ś>R\>Tai>t̷=>v>i>N>># L> XU>oj >>Q%mG>P !>>wbP>BB@> dh> >q(h>8>)>;ў+U> )Ѐ>Ѯ1>>+0`?"p?'h ?ԯ`?&ٷ?0c?8l|u?A.?IA%?RYjcg?Y|bp?a:=?f̂h?mBP?rpT%?wQ]Rҁ?}'1? 4"?¢W?.T!u?Ȧq?LZI?UΤF?wd#-?Wt?Kr'??^X?2pT?rg(T?F$?1B?Q*;>ey\|>݊oH>Π>7[>p1>꫼w>:t>ǎdc?>sYI>RQ>a#>U SS>OV>CɈ>BZ>FO>՟|x>xj>n>.Wl@p>g4b>Qcx>w?S"p?>B?q@`?#&ž?+ԏ ?3Y ?9L`?AB".?Fƣ҈?M}?SQ?YHP?a3; ?gDU?o$U?t2(wwl?}X9?/ز?)JdB?N`C?x?^Nc?0zq?r/ċ?}ܬx?~ $N?&y C?RvV?0pwU?b4"?n?U ߿?0ŶD?ִ ?|r?xO>v?xMuJk?z,?IO?1\?yN”@?6?u jf?wNg?R;J\ ?~ H ?*Cp?Sy`?-lں??r#y?J?RF@.?Ԉ?`g?g?/56Bu?^>얜?D~?v??gȅ?W>{?F5s?6b& ?'t>?r? ^> f<>p{r܃>ۻ|l>̺C>,>`>j_p>nƊ>ŗd(>} Y> 0iQ2'>HB>?%H>D6˖9>E>(>mؔ>ëlD>bH>ڗܢP>y)0>#BB>BNIx?_UtFT?$?{l"\?% Ύ}X?.4y@?5r۔`?=T`?CT]⍀?HQjdP?MrՅ@?Qeݥ4ސ?Tn @?Ydą?`.Xm?e++]?m;N*?tDqۊ?}pGd?Ee?l?ةNk?[V?!Z?*,ޱ?4q?`?W$?}?On?g ,? [.-?GS?C^Br?c@_?_m}?~T3?wmUI?tK0gЅ?t_Y?wnҠ5?~1??1)`Ca?9Gp?MD53?oO?ݤ? m8-?.D?w?.Q]?@_?c)G?@s)?ޤ< ? ? 0j?L?LM?x.?u"-- ?uMډ0?x/)Q?~Bs?s}!O?r3#,??q%6?}?)0?@y?I8x?W7 Zh?#?~h?sc?^rk?K%~?G|z?r>{/?c߯V?T& ?CT5?3@m?$kHc?$>Gv??>b[2>|CY%s>$/>8Ơ>$z>cGL>jā> >&`< >Py>:>fV>xK >Ԋ>!i>pzD)>)>٠>%T>^f=->fv>4h!u?UyS?W?ϳ1r?'VX?21@HVp?;W *?D\5?Ku7?R ?VDH?YZƠ@?\jyq?_3?am5?df-,?i\ u?0 />"?!mzQ?b'?Gn>S>,|>!t=:+>YD6>D>>s>">Oz>>2u>,{IO>.{t>6>[#> >/q>G1%>B>g+>>?G?5vxn?(?(5?3,?@5=M3=?IԲ)'?SI<_?[I:E?aOX?eH8D8?hN=4?j/6H?l$Ӆ?m'?oa}d8?qST 4?t-G1?xC(s X?/p8?.{K?_']?ʼ?Oi̵>?=`ӕ^?lk%?B"?9?<?=en^T?y?) ?k3~?l*i1?z$v?⾻*?Eu??}(p>?{0=̚?|yl?J?ho?Ab?W`@͢?7e%U?iV?#r@?S?0#?`&?P^?&?qwB?#e?"6\?8? Y?.kn?rt(\?N`?jq?{9?wP%C? P8?7MFN??2\"? F Z?¨?8=Ɍ?-?`?sl?@^F?K?Ff:?h t?{86Z?pw*?cE*D?U5Cy;?F3T!r?7 *?("~?Sי? *P,n>7>b3>Cn7>һ+8>dO>I>>sp> =z>L>zQ8>[Ik>c(5U>``*>?&l>x >4MM>L>ȾZ>lx>a_OH>A?:]>Li{k? Y;?"?&pp?3MR 5?@7b?Lzׯ?Wb?b"ӯ?iꜜ?p^?tۇ,?x#+_?z1 4HP?zτf`?z,0p?z} ^?z?{r s?}lZ ? ?@ ֕ ?VQ(?\"?J?a ?)C?^?OY?7i}?i?_ga51a?Rs?tOz{?fmØ?2c?5M?/4?nٵ?QYhm? U@-V}?X6U?WI? ?Fm{?ZPzl?]k?^EΙW?Tۣ?.*@!O?#A?Wn?il??A2"Z?♤G??Lv]?T??SWC?AT?pB5?{`?yg)? %w^5?`y?EBv?~x%Sl?9Z?>Ze?ޓ(?_Fp?,5 ?<2?]j4?Ѽ?뎼u?'g?'@?b?w ?o塶ֶ?dvkg?X\sb?Ki~?=D~d?0n; ?"#G???(r78\>ɣb>%ﲥ>ܙ״>">LCç>+F<>*eZz>ߍ9>L->H?j~LV>l>H?j~>L->ߍ'>*eP4>+F>LC>"v>ܙ״>%ﲋ<>ɴ?(r78??P?"#?0n;  ?=D~0?Ki(?X\sb?dvkg?o塶ֶ?w ?b?'@?'g?뎼v?Ѽ?]j4?<2$?,5*?_Fr?ޓ(?>Zf?9Z?~x%Si?EBt?`y? %w^,?yg)v?{`?pB3?AT?SWB?T??Lvb??♤G??A2"[?il?Wn?#E?.*@!P?Tۣ?^EΙ\?]m?ho?Fmy?WI? ?X6S? U@-V|?QYhm?n٬?/4?5I?2c?fm×?tOzw?Rs?_ga51c?i?7i~?OZ?c?)M?J?a'?\"?VQ(#?@ ֕? ?}lZ ?{r s?z?z} ^?z,0`?zτfLi{d>A?,`>a_f>lr>ȾZ+a>L>4M>™>?&>``5>c(>[} >zQz>LJ> $>tK>b>dO>|;>һ+͛w>Cq>b3>7*? *P28?Sי?("?7 o?F3T!J?U5CyP?cE*B?pw*?{86`?h }?Ff:?K?@^L?sl?`?1?8=ɔ?©? F `?2\?7MFNA? P8?wP%??{6?jc?N`?rt(\?.kn? T?8?"6Y?#d?qwB?'?P^ ?`&?0%?S?#r@?iV?7e%X?W`@ͦ?Ab?s 8?J?|yl?{0=̕?}(p>??Eu?⾻'?z$u?l*i0?k3~?) ?y?=en^S?<?9?B#?lk%?=`ӕc?Oi̵D?ʿ?_']?.{R?/p:?xC(s \?t-G1?qST (?oa}d(?m'?l$Ӆp?j/6?hN=4?eH8D?aO(?[I:E?SI<]?IԲ)(?@5=M3=>g>a>G>0> >[>6ت>.{>,{I>2u΍>+Y>O>b>s>">DG>YD\>!t<>,>S8?Gw?b''?!my?0 />m?> v?O71V?^VCL?k9G?xđ?^ç?bPI=?#9? k#m?Y3f?8K^M?'Q7G?.݃?o4?6?9hP%?W ֆ?4h(>fB>^f=->%e>=>>);>pzDP>">>xK &>f6)>:>Py>&` !>jv6>cHZ>$z>8>#>|CY)p>b[???$>G?$kH?3@m ?CT5?T& ?c߯V?r>{0?G|z?K%?^rk?sc ?~h?#?W7 Zj?I8|?@y?)0?}?q%6??r3#,?s}!O?~Bs?x/)Q?uMډ?u"-- ?x.?LM?L? 0j? ?ޤ< ?@s,?c)G?@]?.Q]?.D?w? m8.?ݣ?oO?MD54?9Gp?1)`Cb?1\?~1?wnҠ0?t_X?tK0g?wmUI?~T-?_m}?c@^?C^Br?GS? [.*?g ,?On?}?W$?`?4q?*,ޱ?!Z?[W?ةNk?Ee?q?}pGb?tDqۊ?m;N*?e++]?`.Xn?Ydą`?Tn ?Qeݥ4 ?MrՅ?HQjd?CT]?=T ?5r۔?.4yp?% Ύ}`?{l"|?$?_UtK>BNV>#I`>y)ؐ>ڗܢ >bW>ëڹ}>mؕYD>(>6>D6˞>?%2>H> 0iQ>} YH>ŗ>nƊ>j_pz>`)>^>̺m|>ۻ|2>>p{r܃P> f.? ?r?'t>?6b& k?F5~?W>S?gȅ?v??D~?^>얝?/56Bu?`g?g?Ԉ?RF@.?J?r#y??-lں?Syb?*Cp?~ H ?R;J\ ?wNh?u jg?w@l>?teFA?s(N?vh%&Ȭ?} }?;J?)?۰^?j{$|5?Zş?Dؽ[?g V?֢B?f\3?Nr.?Pk?D? g3?6v?|r?ִ?0ŶD?U ߾?n"?b4#?0pwT?RvW?&y C?~ $N?}ܬv?r/Ċ?0zo?^Nb?x?N`C?)JdB?/ز ?}X9?t2(wwn?o$U?gDU?a3;0?YHP?SQ?M}?Fƣ҈ ?AB".ˀ?9L?3Y ?+ԏ`?#&ž?q@?>B?S">w>Qc(>g4mt>.Wl_L>n>x>՟>FP:>BZ>CɈ>Oe>U T>a>R>sZ>ǎdSF>9X>꫼K{>p2>6n>Πm>݊oq>ey\e>Q*;D? ^_,?'?(UZE?88?H?Zl?i1?y@A?(7B?D?I-Z2 ?@ ?۰pt?X}R?N=??NBm>+0€`>Ѯ7 > )>;ў+\`>)`>q(h0>X> c$>BBT>wbQ>P !f>Q%mT>oj x> X># >>i?4`><7>tC>TK>R>>΋V>ݡbF>x{UŸ>qL?\j?|f&??CAc?:{A(?v? m?8Ǚ!7?l??8?K\=?z7?J~S~?F*SBw?g?܋R?8T3?׹Y?)>H?Q.B?`~A?w?kU?}H?])_?s?E9V?Še?\9$?#q?6,?Ju?o|o&P?//y?v{?FЋs?O?e5;?UÄ?]@C?(q_#?41 ?"4g^??{uc?y]?n0@u?00?ok ڐ?`&?{+]j?xxom?tíH?q5|?k<%ˀ?dAM?\z ~P?RԟDP?Guv?>9?3yf`?'i`?Xʜ@??n>JA>s%>1W4>+>g2@>H2( >8XY >5%x >IuΖ>Opܭ><">~V>K'> N>dR>>P_*_>Q[>yOh\>a!>t& >A>HQX>p >胍>~~?I&4?pֆx4?'3m%&?6|?G&I?X Fw?gq-.j?vEuO?tc?n}&?_{5ۅL?1k?*b?B0?r@"B?_c2?z?U u?' g?tD?_쪬?Il?k3t:?ы?cm?ضJ{+ >n >U>N|0>P0>LV>'/IX>%B̜>!G >z?EX>ew>Fv>.Я">>~Ś>Ǝ>SΟԓ>R 򐇼>`d>ްی>OK>W\ܪl>q|H9>K:@>9?V?*n'Z?y?%J[? ?8A$&i?,?KM?YW?[_DL?yG?}?ѐPi?vGV?Aa?[h?ɋ2?P]ÿ?xz?HV{?j"t?3͔??Cu1%M?Nz7?j0 ?0{?}I0?Gy$r=?7R?ML{~? dv?נ?OV?~?"?ݤ ۨ?L?|t?t3P{?iƺFj?_ X@?Q*SY?Cq?5._?''ĺ?"`? ރ >R >o7|p>;l]>e#ر>isp>MMp8>ݲt@>gS,>7p\>0.>5>,N>է#4V>e.T`>ǫM>t"c>|(>yDH>]Ne>9">?}>$Ձ5I>׎{w>%蒍>M~q?B ?9q?"?]?04H?@}Ԏ?Po "?`&F?mzm#?zFɡ?VO?砀w ?M?$?NO] ?a61?v<*?ܸ?ϫ2?|?Yy ?SGP?n?\?9AkI?Ɓ?<DŽc?H]x=e?4Jc??R#?!)?͒5y?hZN?m̽?R?x#?+2?( uN!?S!3?UZ?:7 A?sBQ?HB?_|?ZӒJ?_V$C?+q? _?qI?m?( =[x2?əi?9x? V5?x3eD=?rye? m?OVPC?-6}u?A[?}ZN?\UK?| 1 ?xC+cQ?yy?iN?-? v?<^5N?7)?{Ѻ ?xm?tV}?hw]cP?[E?Mr{??)v?0&7wv?!180? M`P?>UIp>K!S>7+5?@>Ы?0>K!;w>ʍ>J_d>aƯ<>;|>c+/>ιSѮ> => $r>Zw>p>z>̅>[>-âNHZ>3X>g<>3>PM)Us>[9>9 >\Gp ?4? ?+<M?:;\>?IVХsQ?XG&DI?fUC_T?s5U6? 4|sb?iJֿU?H??cV*??v?Ph?_6<,?%?9X`?)ǵ0%?ѱ?rd?ݞ!;?+Q?8S ?pE?Z??i1|q?:}@f?d!F?i? ҟZ?sYa?@?z"?=?Tfɔ?{*O?[6j?y,n?x/yi?z Q"zOC?o˜?#p? :?W=7?1?c`^+?(l?gֿ|?رdh??ı%?Iih ??qd?9ȭu?ϲf(?*rAE?;&? :?}tz?vσ?t)F?uoeD(?{s?]qI?^ƀ?E ?z\?H<j+q@>Gm@>u Ҡ>XjOJ>ȕ2=>D_>z[ >Nji >>:V>F=1j>Ca=>>"ð>^v>o{0>4A>p;PX>u6>ݿ9q>уF#>']w>$|qD>_, >L(>NB? jW?ٮH?&\o U?4?Bֵb?Q_?`~*?mۦ?yP?tW:?qLs?Q?ts~?ta ?̤?t ?Y?pvo? w]:?j̒\?QNj?$?rb?N?ָܥ^?G? v?5$?e}G?Gs7e?_?~H?N#B?.I?p0 2?Cԕ8k?n ?#,^_?z@IYp?u{[]\[?t*jL?wo-+7?~5?Ȳow?&?jua?[_?N?Qrh?{\+?3?驓%`? i'?ʈ/x?Q?ݸ?r?'h?6(iwF?~~0J?wL?u{R?wdFS6?}`b?XD? J3?l?3XL?ՐEDv?U>S.? i?DE@??Yw #?iq?|FP `?mڢ?_&V(?Pr?@]{?/\l? K8?O?p>H>+h>)q٠>xM+>Af1>?[><οW>,Ɲp>1Gi>:'}> ">q>ď9>@1Ao>߉7>leXp>YL>zU>jqI7>q>˘ r>ڣ$7>S7tp)>)d ?;|bMz? ?!@=և?/KPx? ?y?zY?^??%J?|WA?m? f?lAe?,!F?L)7? A?a?w_"Ak??i?ݓ9?kY?Tz?1:hx=?{æy?v߿`?uӍj@?xJ-?` ?JǚՂ?(ܦ??|diW?n?0xf??D?+N*{?1IQO?Ol?6d_?JQH÷?Ϫi%?{c_R?H?Fy#{?kghL?{h;( ?}$1'?5?,93?E0Q?p6T?G,?9="6?se ?AX$A?ޭ+?N^?O?? kM?In?z?t|j?^?eGr6?V0?G1o?6\`?&x0ї@?3H? nؔ>dJW>)B>O5#>~WxS> X>\ >3VD>ϑ>|> E>U(2H>*? >B$> &>{l=>O4)>QTy>$Y;>23n >CW/>ŵ_$>k{Kl >%q>E]ST>w{ƹ? oyu?P?(--`?5N$?B>7?Q(?a t?ov6O0?|n.~?C#vh\?HNO_?Skі?k~v?B(;?yu? ]?ܰD?LN? ؠqyV?L?It?̾?M?ZU?* ?3g>?rf5?N?ix9D??BG?j?z~?2y??37 ?=&v?8^;+?gP̢?;k'J?~O܆)9?{}N?|>p?j?}= ?[%-?)?j}?V%?"1m?t$?2Z܊?a[o?6??~?I?I[(?~ }~?oB7N?C?%s ?yYm?J!?oŅ?/?Hה?5ևGV?ե??s?,?!?Z ?T?8?MĶ? =?`?|4?ls߹?^,*&?O36?>n8?/4? 8M? Hٶ?fZ>Nb>C/ל4>r*h>α>V$M3>p)^>d[>`H<ː>/ՒB_>SHX>Nuۃ%>TXu>Ӕ#e>ۢƭq>zgL>m.q+>d6&od>Ii۹>W#1>ftʀ>%>݈m$;>?4> 7F:?<[?.?(U?! Y2?0 iއ.D?<_v{wD?Ji!?YsP?h2?w^D7?M`?NI&-N?^S?#w?Tb$?~?RD?*l ?/g?kX2?f??Mߩ?u a?RI?fL?y-?Llcν'?kr?*?~P?9&?hc?Q ?Zڨ4?;DD?C?_!f?//S|?ίr?]#? *sr?Ko`َ?θb?*}?FSKE'?\k>?VWZ?? I?^N?\.?GX? tQJ?l?he1?~ ?A+?U`?w(!?b?Ma|H?~W? E?z?)?l$2?˩td6?_)?l}(j? fH?|Ţ?n#Df?`GZ]O?Q)D ?A+?2˿ H?$(AM?G?Kg?HOB>P >9F>IG>/]4Fҡ>#$>m;젨>+)>>;>bT>^c%L>>7;)(>JZὈ>7;)*>N>^c%KZ>bT >;J>+>m;/$>#$ 1>/]4F>II@>9G>P b?+c?"_}?mJZ`)??=??FSKE+?*}?!?1eo?,ۆ?h,h?}W-d?e ]@?UO?M?Y4?P+.??k"I?ļc%?8۾We?k0?좨 ?ZǷ}?k??T`i~?nMP(?ex?}=?c*?T$HA?jc ?A$#zf?-q^?PO<^?,!y?VO;h?$⸴?|?>d?r_˺h?d.U?Ua8P?Fza$g=?8;9?,??_h~?+7BV?Ǹ':>xP>J~>}hN>̵o >.ޒV >!_]#>j>Ep>&OAT>6l>Ѕ^>k`*>j3>l>޳> m1,(>0 W>|6>J>2D>ݬZ>1>&+>c,؊3?P{}Y?"G R?*gEQ`?+(?; a*D?K )?Z3q J#?hH7[?wb]~t?A:?Ӯu?8 ? &?e?x+??[?nW?V0?b??!h+D?@ti"?R~:? P?klm?IJH?nj`f}?=?[̄?צ?M)?ߑVΕ ?f ?^Ǝt?k??Z,^?w xr?|Kw?WL?J?ᳺO=?!,и?r?+*Q?R(}<?F;w? V?1? *Gѧ?6hr.?f?P@P{?? +u?#}?y5?eN?4 2nv? #In?$Ae?16uO?Dz: s?9R?C@Y?+Z4:?sFo?3?Ƭ?$,?&d?NbS?^9? o-k??v`~+?ijuh2?[T}?M$ֱ?@?2Yy?%4%W?(a3f?z;S>P8XF>S%B>᧫zf>"4>ĵ*>a>':a>6>Q8 >8?>z>>v:8>>fY>h*2>ή1I>zCo>KEN\>W޳r>Ӱ>;2>'>'2B>f7>1|?1r_?'z$?$yԄ?4̢]?Dvko\?T^s6#U`?cy ?r{mW*? |?E?)?֯?`X'?gJh?NYm?*n0?R4?6'bH??uh&?8ck?&Z?F3 ? @? f ?XfXxb^?1?3}?(?Y?pF ?/b;[~?Nl#?҅?*R?L).ң?j y?$I`u?<.?}(?zq^?|)q/Q?Vj?sh?]x?,?"2?'e?xB? 7$?qp?_kI?eH?nÈQ?|2?H?)9? ?ӟuY7?D*s?Q1?j:>8?y?#ŹT ?yШ{?P?%G[?|J,?. L?ku=VB?E uh?{h?pw?bS ?SF,?Es\?8|Z?+1-B?ANyJ?o\#G?0pba>09>]ko^~>؋>&2t>/>8f>MF>pё>R'>++`>atZ> >ف>D>AG>NEt>@PQ/>}-\ D>AE">CO>Cgdp>SlE(>B><9,G??!?lkg?@z(?-y0?=8?N4`?]J΀?l?ڋ+d?z@?rIى;&?? .?p?|h%\?H"?Vsġ?v@S?8j?n?z ?_?Sb?Xj?z]*?y~_?|N ?Jo1 m? ?Fy4K5?FV?8t1?SvYv?:Y?,?)\ ? W ?g?bΉC?O!?X}r-N?4? ?H"??W ?{ ^P?y$O*?zm@!?L7?M]?~7XK>W&>+v>nef>VՀ%>VLb,>s2W >q2m>d1@>Ɔfh>b>lT!>L,Lo`>գ#>A_ή>w\%[>R\ >9d->>n>7\ih>ҪK>f8\p>z>>=\dP? ?֝?&adFy1 ?5Ā?E'2?UP,?d|?rU*N?ǖ?ʑ}`?9?u5???J}?\A^?nW{??B[d?aCJ?yBl? ?Duǣ?j+c?\E?-]%?>򴫙S?)^md?W<@?6 e?~Ap1?֤i䮏?*15p?X/H? 5to? j?h:N?88?YJ?Xww?Zn`?xY4z?䖫:1>mp>þޤ>Stz>. w>$UWƤ>M*J>UJ>ك>l>S>$>ER~ >j>c7kM>u>#&>[1 >B: >]"Q9><\>ϣ5>-0>pܯP@>:.?}?EzEd?!.}@?0u``?>]?M]5?\5 ?i/`?vcSyx?U?W9Z?cq#h?ɆY?ጷg7?dk[{5?؅ .?[W?+?'x?Z;_? ?}-uZ?}ɑ,?/c?%ˣv?BCq?V^?ez@?46v?^)?bφ?Ty?N? ?yj?.g? 6^?)n?mgD?yH?bE? q?]?I7?Kv4?P/p?R҂?}?o W??k2?i^ ?יq?-?r=:'?8gWJ?Gv?3r?\wJ?Uka\?H?/'??;_?s;Q?b_vs$?)l\M?ĝQ:6?"%'R^?Xb{*?o U?O_x?nA??Rda?4fk?x>v?hp ?t$~?gE'?Zc?Kx@rZ?<k_?-lr3 ? F?xƪ!?y1N>_I\a>Π%>ֲ9!>w%>+[Z>1Guu>bm^R>DeG>taj>RG~>TNR>wn>D>>{:>F̊>K9I:7>Ų /`>%k>Jݶ>«ڈ>t)m>DJP>ZJ=p>œ&>/M ? nG@?c?'?`?5SA?C==R ?R^!S?`ӭ`?l``?v?x@?-#?" ?-:^? ?ܨR?_{?C3fQ?_ɪ?@H?sS?2?AK+N? -i??cH<?0U(?8r?9~?FS? 3pP?)go?Ő_?kȀ+R?K]~?nI_?;Jt?xm=?izb?F-i?-?;N?I? w(xY?0 Ʃo?U[0?LUv?uXB?~I2?]3",?=z܌?0`?)E?6~$ᾧ)l >wdEb>y+/8>G]>'3~S>_L>L>u~Q>~N>5>PVK>,G>6!f_5V>^7>ҙ6>c!>]>c_)&p>E>4~H>BT`>)܄ݕ>ph<>G @>ՙ*wv@?p?tN?|3ה?v -?@eb?+:&G?ۖ?l̕f? ?`]j?N=v?o?yo퀓?$JE ?a=x?[G7?LG0?\g*{? /?xf?}c? K? ?+=|:?y^?T_w?Yl?RX?VJeI?7?o7S ?2?32Gt?W_fH?ƈ]L?P?ψ(?0? e?bG?M)d?BX? ?gƄl?= ??WJO?w d?Wʰ? 2 ?%j?.u8y?ΒD~c?bH??`˿z?mp?:X-q\?V x\?wӯ?o?fəR?Sy=M?=Z(?Cd?:@X?Rl?gVA?qup?cf=?ȘN?C]t?3 ?% 5?Fa3?hP>d9)Q>T>"I~rKI>R>W݆>:l{>3_Ś> 1>b$>fmԴ2>ɪu>/WI>&J>..w>6׳f>8V>i>*Q>۝g?>•@>z.>kL >cA >{IH>8??k?/oS?(g:?3B@?@.'I?J%t?U `?aX?i*2X?qd?w -\?~Z??4+?r UЪ?V8?!-?xJ?(+j?&r?͖o?a>>!<>kK> ;/b>͟aR q;>N5> B6k>K=>5+͗-A>- >%:*>:t>D`,T>ǒ#>x)>">>7zi>It>T>ph>S>v)jS>k&@e>$3>G4+>#-h?a9K/?S7P??& 2 ?0;?F?9c<8?C@8u@?M[>Do?UࢧK?`8?fuvP?o?uŠ|?|QAT ?RI@? Fؘ?a#X7?[vI?\bh,( O(>|`\dF>eM x>AĿ9>W>->!fu>y >jtA*>f>J>O_"t>T"/r>7F>Sl>sN>lmZX>>E8">ĔGI>f4j>s۲$>V3d>ܪ ]w>xtf?0?3=x?[0?"6?*?2Q#u`?9sK ?AP?HCg?PaͰ?Wf}p?`.Y?hY ?p?wƧ?i ?963_{?4`^?&!?66?wo{?PT?[h?T\N?lէ?s;'?Vה^ƒ?O+=ˏ?sR?M+?%2Y1?__E?ڴ?7Nؔ?}?}PwK?aK>?y?GRq?B;?t2?T\e5?N!z?5[ ߂?HԬJ?t֭&f?b8?hߛ?Qʃ(?"*Z ??4pBG?ڨ,N?vMem?3wp?{9?xj?x㟤sN?|&? S?Kc ?@j?Qf?*wI?o?wu?G ?? ? ?|15f?ڜ1?̗O?? g.X? j.?r"A"- ?cd@ $R>椣_p+>Ʋ>jʞKDt>퇗:>KmAL>nu>h7>[s >.>f>mۓ>]PG>)XI>^3̪>jZZ>kLV>j8>I>&= H>فM>FR1(D>{]2>4L?3?k5:??#9&8} ?+Zpx?3;7?:xT_?AyH?Fap?Li _=@?Q Fc?V2x0?_;e`?e׍?o%>F8?vnfű?B&q?Ц>A?^?rg 1?An8?k??Z+W?~-=?71Z?ZZZK? ˹?#"?q+?!iW? ,?% `?1a?+ ?|Z?xR7?xGGɈ?{2x?[я?FR37?p4?yQ?^m?`Z?y,6 ?7%Lo?ڿu?Nj='?bA?I?}=!?Wz?Iڴw?fXu? h}?@?/?j?`?&(?s(K!? q(?z~g?n 9@?`C7X{T?P&YMI?@z,tX?1y`?"D W>?%$?nFD>/[T><ԫ>ؚ>|,PN>pp!><.phM>skJ>nV>r1^>>u0&>{{><$>6J>'y>4dw>2>8'P>8k[$>- ^>ꢀ>R?22? {?I ?%GU9ό?/ I3L?7tC?A3!?G;g?Od ?Syր:P?WSn;?[w ?`S!0?d,-p]?j,+&Z<0?qz?)? z?y*?<p?~/j*?z$Go?yv^&?},?K(?,Ȱ?ԵZف?U?&{? 䮕?+>v ?񾣆?.?Z?gT?p ?? V߾?g?ߠ*?'y2*?9 0?" ?CJl?s v?s?rX?%*{+?tҸ?'<o?Ǣl?X,N?$3?:=?<}R?Q%n[B?w)[\?m@^?HS-4?>?a}?>}?h?s;K?fR[?XP7?IAP?:J?,<=j?/1 ?M>-lz7>A)P>>8>wm9N>DpL>:}>Ubo^>hF6> I#>BzX>*va>in=82>⚠>[m>?N>!YG>;e^">l$v>=!o>܋B܀>>?ӧ?P?>?%y?1>#?;z&`܅?E ?P`y?V f?]o0z?bv4k?e_ 4?i;0b?l]1?pf6L?sT ?wp*.?}7*,?`ۻw?"/=?')s(?ⰌN?6#氣?l$V?#g? tR=E?)a:?kZ?6~9?Qߪ?m0V?%]ă?EB`/?J8?@&?LD\?&l??\kP?E)t6?{Q?ͮ|d6?ړh?p??qTc?{Ev?R?3锯?n(?@N?Eee@?i7|?uTxΈ?jsB?_U?Qx ?Bl */?3)H?&(ѵG?!.?:i~>6՘>lp">4ݤ>E>IC6W>|>Fid|>:*τ> `y>py0>^f>>-k>}4ua><>F%B>K>\A>_N >>q> ub? ,,N?T4}?$h?0wx?<=(?HI?SŽh`?^YO?e2G d?lsp?qO'?uLqe]N?x sD?zd  ?|u^C?<?b^.??Ev?=x]?V(,?o;}?Bm?8|x?-;1V?<*m?m?Lɷ?{85?M'3"?o%?DefKY?LOr?3@!?XrXp|?4J?,h?N0s?Rz7?}Q?bub{?ie3?ק?P?"F>?)y? `6J ?]?Ӷ ?״?gXL? ?@#?_]*>?qh?! |?s#V:?ArA?" ?z cE ?rژ?i.?`ޫ 9?TD۲?F«ބ?9*4O?,_L? >c??yl`>m>Px> D>ə`X>Si>Rv8>" E >I6r> >*w>X>*w&>A >I6r>" D>R.>S]>ə`> 0d>Px>m?yl`L?? >cO?,_L?9*4O?F«ބL?TD۲?`ޫ 7?i.?rژ?z cE ?" ?ArA?s#VF?! ?qh?_]*>?@#? ?gXL?״?Ӷ ?]? `6J?)y?"F1?P?ק?ie,?bubx?}Q?Rz8?N0s?,h?4L?XrXp~?3@#?LOy?DefKa?o%?M'3&?{89?Lɷ?:¦?<*m?-;1U?8|n?Bh?>;h?Q?,so?4?z#?ZpՋ?nd;7?֢Y?p ?@?'?|ޣk ?\c ^?ǩ/ ?6\zj?saj?o ua8>q>~>_N >\mr>K>F%.><Ü >}4I>,>>^f`h>pyo> `z>:*E>Fide>|۸>IC6>!>4͸>lp>6ՙ?:iy?!.?&(ѵG5?3)H?Bl */?Qx?_U?jsB?uTxΈ?i7?EeeH?@N?n(?3锵?R?{Ev?qTc??p?ړh?ͮ|d8?{Q?i>.?Gߝ|$T?%y???d?ӧ(>>R>܋B>=!o4>l$y.>;e^$P>!Z1G>?Oa>[u\>6^>in=8>* 6>Bz[q> I$>hF >Ubl>:}ׯ>Dpw>wm7>>8>A)X\>-lv?M?/.|?,<=?:J?IAP?XP7?fR[?s;K?h?>}?a}?>?HS-6?m@a?w)[\?Q%n[D?<}V?:=?$3?X,N?Ǣm?'<o?tҸ?%*{$?rC?s?s v?CJl?"?9 0x?'y2,?ߠ*?g?? V߿?p ?gT?Z?0?񾣆?+>v ? 䮕?&{?Y?p4?,Ȱ?K(?},?yv^?z$Go?~/j?<l?y(? z?r>"?c1p?uGO,p?p_`?ybHA?ܣSM?蝎$P?5C?u?f?~3?<Ųd?Nbm?c?l*|Q?wDB?qz?R >ꢀס>- ^>8k[>8's>2>4dv>'>6HN><|>{{>u0&>>r1_n>nc>skJ`><.pe>pp>|,K>ؚc><>/[V?nA?%Ȕ?"D V5?1y?@z,tX?P&YMW?`C7X{A?n 9@?z~g? q(?s(K!?&(?`?j?2?@? h~?fXy?Iڴz?Wz?}=!?I?Y>bB?P\?dޡl?}i?y/?yLQ?}tޜ?ܜ{?̜1?aTsף?T ?ϛ?h Az?1?A?B&s?vnfű?o%>F8?e׍?_;e0?V2x?Q Fc?Li _4>{]2>FR1/d>فMʆ>&= l>1O>jԪ>kLVx>j>^4>)Y8>]Ps>mۓ>.> >[tis>h`t>nud>Km&>P>jʞKƲ>椣_c> $X?Qj? Tޢ?$'sr?3k04 ?C;%?p?S2jd?cd@.?r"A"- ? j-? g.X??̗O?ڜ1?|15f? ? ??G ?wu?o?*wI?Qf?@j?Kc ? N?|?x㟤sH?xj~?{9?3wp?vMeb?ڨ,O?4pBI??"*Z ?Qʃ&?hߛ?b8?t֭&g?HԬJ?5[ ߃?N!z?T\e7?t2?/4 `?GRp?y?aK>?}PwK?}?7Nؘ?ڴ?__xtfp>ܪ ]>V3 >s۲3>f40>ĔGG(>>E>lmZƍ>sǵ>S>7>T#&>O`>J~>fr>jtC>y a>!f,>V>xB>AĿ%>eM k*>|`\Z>,( U^?rnuC2?n?%(M?4[;?D]`D?Uk<֚?e \?s<҅?Ѝ ?y^R?#nfx?qW???]Q?Blލ? :L?fn?|;? M?@?`O?=t?K?!2???[]{?8?;H?Ȓ?%ğN?m?RIDo?C@8u?9c<8?0;?E?& 1`? ?S7?a9K.>#-l>G42h>$3>k&@t>v)jT8>S>pL>It>&>7z>>"Ҁ>xj$>Ǔ>D`..G>>%:>->5+͖9v>KG> B6>N5->͟aR L> ;/>kK>>!(*?D'?UlHi?e&?s2)?Z?C+?[0H_?:|!?Dubz?cl՚?G&R?}{a?BBt?O^?zWV? )x?#뗃?d?D?[07 ?PĚ?Y~?2#?FA?*s?z{?6u?Е?6?}\?nk:L?m?`ZC?,]e?iT?49?8q_?o7S?-?x'?Oh3F?W֎0?-g6?)U%?|?:3G!?uf?Yq??`;?(y??8>{IM>cA>kL߰>z. >•!>۝gx>*Q[>i7>8`>6 r>./n>&>/WKB>ɪ*>fm,>b > ~Q>3_X>:l>WS>R>"I~r<2>T>d9)?h8?Fa?% 5?3 ?C]w?ȘN?cf=?quq?gVA?Rl?:@X?Cd?=Z(?Sy=M?fəR?o?wӰ?V x[?:X-q\?mp?`˿z?bH??ΒD~f?.u8y%?%i? 2?Wʰ?w d?WJO??= ?gƄl? ?BX?M)b?bG? e?0?ψ(?P?ƈ]L?W_fH?32Gt?0?͒E@?7?VJeK?RX?Yl?T_w?y`?+=|=? ? O?}c?xf? /?\g*y?LG/?[G7?a=u?$JE?yo퀎?o?N=v?`]j? ?l̕j?ۢ?+:&J?@et?v -?|3׈?tN?l>p?aJF?T3b`?GV N?:^7?.^=?!LK ?)ɠ?ՙ*ww>G >phP>)܄ʰ>BT>4n(>E°`>c_) >]N>c!-b>қ:>^&l>6!f_>,>PVz>5Gl>b >u~Q>Lf>_Ȍ>'2w>G]>y+.>wdEbL>ᾧ)o8?,؉?.l?"y?1{c~/?@~Yl?Q(ND?`1xe?n2?z#H\\^?o iv?iMy?yp_ R?!1\w?Bjz!?|S#X ?6~$?ξM?+ ?flә?󛔕_?bF?[[כ?s?Cz$?鯈e?Wl$?;a?R+v~?T;?lFy\?Bm?9/J>œ&>ZJJp>DJ->t)m0>«>Jj>%k>Ų .B>K9I:'>F̋>{;n>D0>&>T>RF>t*>DeEU>bm]>1F>+ >w%m>ֲ9!&>Π%&>_I\:?y1E?xƪ#~? F?-lr3?<k_ ?Kx@rL?Zc?gE'?t$~?hp"?x>r?4fk?Rda??n>?O_x?o U?Xb{*?"%'R\?ĝQ:7?)l\K?b_vs&?s;Q??;a?/'?O?Uka\?\wQ?3r?Gz?8gWM?r=:+?יq?-?i^ ?k2??o W?}?RҀ?P/p?Kv4?I7?]? q?>򴫙S?yH?mgD?)n? 6^?.g? ?yk?N?Ty?bψ?^)?46v?ezA?V^?BCt?%ˣv?/c?}ɑ,?}-uY? ?Z;_?'x?+?[Y?؅ .?dk[{;?ጷgA?Ɇ_?cq#e?W9Z?U.?vcSyp?i/`?\5@?M]5?>]?0u``?!.}@?EzEb`?} P>:.>pܯP>-P>ϣ5sP><>>]"Q >B?$>[0'>#>uxn>c7kM>>ERx>$H'>S}>l >فz>UI/>M*e>$UWM,>. wX>St>þ/>m >䖫:#? L]h? lW?(3=\`p>zF>f8k`>ҪK>7\i`>nt>*>9d>R\>w\F>A` >գz>L,L;>lTA>bB>Ɔ'#>d1>q0>s1>VLbf>Va>ne>+>W&|>XKy?}? m2?#H0h?1KB?@ A‚2?MKKP?Z\?grRU?tf@ ?C&?kъ?X?Js&?dz*~?1fP?LҀ?V?]f?2]6?+c?m~b9?kHZ?S4fh??3"'?]l+?YTڧ? ?|?(H?j]"?Za Q?k?[?0 P^?~7<9,N>P>Sl.>Cgd>CO>AE">}-\ n6>@Pӷ>N>Am^>D&>ـ>>at>++`u>>R'] >p>M>8q>/>&nY>؋ꖎ>]koWL>)?0pbT?o\#G?ANy>?+1-?8|Z?Es?SF,z?bS?p|?{h?E uk?ku=VC?. L?|J,?%G]?R?yШ{?#ŹT ?y?j:>9?Q1?D*t?ӟuY7? ?H?)9?|2?nÈP?eH?_kI?qo? 7#?xB?'e?"2?,?]x?sn?Vj?|)q/Q?zq^?}(?<.?$I`u?ᳺO=?L).ҡ?*Rz?҂?Nl!?/b;[y?pF ?Y?(?3}?1?XfXxb^? f ? >?F3?&d?8ck?uh&??6'bH"?R4?*n0?NYm?gJh?`X'?֯?)?E? ~?'>W.?{*ˢ ?VV@? @du?r{m8?cy ?T^s6#U2?DvkoT?4̢]?$yԄ?'z?1r_<>1X>fP>'2">'l>m>Ӱ>W1>KENЮ>zC >ήKC>hq>fU>>v:>z>z>8?>Q6>6s!>':>a>ĵj>"4 >᧫zX>SP>P8XLc?z;Ky?(a1*?%4%W?2Yy?@H?M$ֱh?[T}?ijuh2?v`~$?? o-i?^9?NbS?&g?$.?Ƭ?3?sFo?+Z4:?C@Y?9R?Dz: q?16uN?$Ae? #Ii?4 2ns?eN?y3?#}? +u??P@Pz?f?6hr.? *Gѧ?1? V?F;?R(}<?+*S?r?!,е?!?J?WL?|Kw ?w xp?Z,^?k:?^Ǝt?f?ߑVΕ?M)?צ?[̄?=?nj`f?IJM?klg? P?R~:?@ti7?!h+L??b?V/?nW?[??x-?e? &?8 ?Ӯu?A:?wb]~t?hH7^?Z3q I?K )?; a*r?+V?*gEQ?"G TY?P{}`>c,؊C>&+>1R>ݬ>2A>տ>|6>0 > m17>vr>>j3b >k_>Ї>6i>&O@>EpQ>j8>!_>.ޒVd>̵ >}hMK>JY>xP?Ǹ'l?+7d?|?$⸰?VO;f?,!y?PO<_?-q`?A$#zh?jc ?T$HA?c,?}>?ex?nMP)?T`iv??k?ZǷ}?좨 ?k0 ?8۾We?ļc%?k"G??P+1?Y:?M?UX?e ]U?}W-i?h,p?,ۆ?1ep?Nh8 H?V??^ ֬?Q-]?8 ?6=A?d%*v?]?{?[?m?c_?~o]? /?. 44?MOת?>??Dp?5h?N>?)ir? Y\?p?3rM+ ?P521e>˱>O">`-K>Rm3x>τ>MZ>/ D>]#4T>:Ԛ>ӀC>!/M>GC>!.ff>ӀD>:N>]#4(>/ DEz>M>τۖ>Rm3F>`>O>˱>521T?i.? ?!3I?/T.h?=?5d?Dp?>??MOס?. 40? /?~o]?c_?m ?{?a?]?d%*v?6=G?8 ?Q-]?^ ֬?V? ?ᅺ?y|8? kq?z7h?)? AT?l$Zj?4?۞a?v<3?g] ?t?]PEZ?ԭ)Eh?p&?iE?x[KM?k׮n?_<>囌?P「{?B#e?4?'19 ?8;rb? NNH6>RO> /E>4>iZ9Q>ʉmY4> ?y>5 ">$C!>_L>-3->e>:/>5%g>nxkp> L >lL[>Jq=߹>"xZ>P>|> >p>ح>^flR>qs}> J? 7hF?&`e?(5?60m?FS?U^tՃ?d7$)?oCY?֠?!??4?4L?BJ?RO?o?R\[a?#?B7?TK3? /C?Ά?}7M? }p?&?7/)?tܣ}Q?I ;W)?VY}b?N5??ȻFaX?׎? 4>?@?{nT2?֪R?UgJQ?yIG3_?{V?pi&ä"?cɁ?TTN:?F6?:]M]?/_BJ=?!2ڐ?͸?<>2k>aF>nb}>[~@>Qf$*>o9a>q (y>o9&X1>RalG>1>QZ2>p> מ">K>Z|/>s>t9JԿB>v_>VK>Ū^6>ѩWώ>||>@E@>y2?qw(\?(b/?"C偋?1(u?A N?Q}?a$Bb+?pH̑?[W?="V?jd?6[?5R? ?WF-;?L?Ry Zj?TB?4?|?ޜ߅+?:NО?sV{? ?q:`?`:?k屶?z~{?h?T_k?~w?Vj.?}(?~Dt?G2)?Xr?Ԡ1\p?ҹ?E =h9?JY?-?L+ ?Qܞ?Zw?ki?dш?$;Z?ZGM'?P?JrI?yn@fT?`yWڔ?=k,OJ">M> f0E>ճM>C%f<>PO>z.:rq>L>TiM<>S׿~>[>pd>L L>]~,>p8k^>ɼ1)а>StU8>f2g>I:f>gcx>>ʳn1X>p>Ǽ>3mFe?R,?{?2{-?+@#J?::T?Joͨ?[d1?j +?y Im?d"x?c8r9?eJ-?Jde?è ?P ?0d?- ?0?pZ?&S?Ԩ?4 ? ?|8WO?{Wտd?~hcDf?N1?%Û?$? ?#|23u?]̠L ?L ?W$?tЮ?e?P?BH}#?̼eR?*#+@/?oC!e?Abq?ğ7? fٔ?6{?fjFA?~88?{^}zcm?|wX~?i̱7+?򸐎ʯ?S?vWi&?ُ>mV>?>ڤmN >SX>q8>옎w>~>n<l>  V>zbG>(ȳ CE>8> T>^ŭ>3>9SM>sj>.>.+z>ۊŬ> VuGo>Ѧ`!>W7>ʹ`>߆B?hY8?ƹx?%y?4?K)?D$ᬦ=@?TLB?d*wM?r˸?$(u$?S*?,=~?*?s?)ڣ?Gkp? /;? 5?h!^?Y(s#(?]xX? M?zOu"?zho?yMp?|£C?(yg?>6=?[9??cƴv?d ?ǿ?*?joH?n8[? Ⅶ?3R_m?f il?cĂ?ۨ?SN6`?G'gdlZ? ?{9?ѷf? ݠ?FaSa?aA?i]u?>U3?;zlE?@!%?SH ?BJ@?e?g?jdi6?{i?U|? w]?h:|r?Ǐ??"AZk?/?v?TX" ?CQ?Pf;E?YT?l/?;s ?VB?}\)'4>?riG|?g9[a?[i8'(1?NHn?@Mz ?2]0?$ZFÜ?F?nk?ہ.b>d> o^>U$o>ͩDl>ćc|>âB>N>°>8MQZ>bͳt)> H1C> >fO>B2>KJO>濧>7;>٭bqc>}c>ԯ >ۄ>KVp>ץU@>=Ɖ>]\Jh?."?i9Z? Lj ?/eǼ0?=$P?L8Gtp?\U?k)b* 5?ƒ\a?ޑ?8`? 1? ?,v?,h?'jd,ƶ?d?@M-,?Er#L1???hM? 68?W*?+  c?s>?Ļ:?Ntcd?@??q&?{ ?Vi?,.i?x`J?n!X?bW;j?TEAF?E5z%A?6< >}?)*T˶?GU%? =^i>{>"M>'>{Ƙq>ǁ z>ŹJ>cT6J>?sRL>l,>8x˳>ar~>>S$.>Mnop>^xN>5>>=laZl>a4>D>IT>b=`>˂DR>7 >>`>Z/S6>'9? "2??'(Y?5@?DÀTK?SJ0?b'"bR?o1Cx?zs?5z;?p?z6?(1?&?V~?l?>i^n?ҟ$?v`dT?[g?[.:4?U1?&HT`!?tW5?E͈"?ٚ6?]i1]?`\E?.jk?3 2?E(?4<%?$4zJ?fԗ?5 ?˞A"?\Y?C?xw?f3m?Vo?phop?zMDB?o E? ?d˜?S?r ?ٴ@?E$y?|]L?PpB?sPS?f7z?YH)J?Jj?;,"?-Zi[V? KMM?C1?kqzz>I>ٽz@ݡ>m >}ճ.CR>W>, >`$I3>>Wi.>_8>C>>jr\>+Z0>p8<>y_^>1GJ>`xF>|& >JAt$>:s|]7>i>Bg6 >Փ0 >"G8>tB>C?:'e?e0?"0}w/?/ש?;ط*?IX!t?W/9-X?d>r,X?p5?yJ?Lʱb ?g\? } K?łӪ_$?0~0ʒZ?D?n?]tHt?wYY?Ԧ?٧sn?;CF%?8>?7i?Pl#?¼ԡ?&GQs?]F?R3"T??#]?q4!?4?P? ?9yP?N??uO?qnV'O?b@?C?+&?C?&$[?Xˆ?Fuy%?-D?J!?)Nc-?! "?;Gv?.?sE?4R?0ۺ?urd?UY'38?Ihp_??Ojz?( i\?edVz?XO*s3?-&b?c)V f?8MX?pnJ?e??A|g?mÇ :?A='?56?wB ?jR ?]6刌?Nd ?>楎S>?0_i?" o`H?N?р>,KV>D>=Wŝ>65P;>*hSzk> 4#>Rl>q7l>0j.̥>NM>ǝ /I>/ J>J+ի>><)D>E'\L>ϳ'>۹H8>pD>T1%$>̜8xЭ>LM>b+>Dd >?L$t?dto?dj?(4?4_;?A^ ?I=?NtEK ?Yx-\`?dxr?ol?wm*P?k?)VkA?aJ$?gTc>ǖ >ّJ M>Rg>OgN>ğ E:>yۧU>D}>~Y>Ct>"n>JT>^P?s>$$>Nl>3I>z>5-f>&Z>Ǒ(p>52>,H>M`>qJ> g@?˂)Q%? h?֨+?&)5(?1";hsP?:R?EVD3 ?Q[y^EH?Zﮟ`?d-=d?nM?vS*,?e?9*;e?TJN?8?fF*? v?/? ;E?}i?i ?0v>U?=D?|Yp?ԫd?ʍH? ?y?)F?zf3?T?+@W@?cԋy?;>?+?g_e??b? , a? W|?u(T?7jA?.a?7 F?j ??.J kZ?Ac*?B ?aYX?;cO?n ?$3s?+t?{g>C?rx?ui2O?&a?Qٲ?c,?(xy?)?je?/5%? ?47n ?"kf?e]%?O?y?_?å?vuҰ?(?z _a?mi|0!w@?`A4 ?P~uا?@x/?19Ck?"ϢD?xP o?*fy>6Jb$>ύ>ْO\>b>(e>2 X >#>I^G5>WYrk>?>u>{n>{nYH>*kn,S>KF*>~ȗ>X>YvJ>~>u\ɳ>&&ä>-<>윩Q>|È?5H? hX?cƆb? $[s?(NÝ?1~n-T?9#5oP?B B?Jj^#0?Sh&l?]O/?f ")?ppO?xGr? "?c ? u"?-B?@$?s]&2\?l??t?/J?⫙o?}W?_طXL%?e]"?q*̒?d:Βĺ?k&&?Sp8Čf?}B1?g푑?0a}g?$?"7?7Էt?K䥺?Z}?YGF?cƐ?kv-?E]@?`~i? ?IN9?ݬ?c&?{-?SQ?//>?+?Kg_?M+>?Ki?g0n'l?7^?w \t?kkI?]d!R?Nc?>-p?0*L?!%n?-4ǟ?gTS>$>{fp>p\w>ɮHy>~`3=>>>ޭpu>3f@!>rq~MN >Q|_:->M^>Ï>{>Q'&8>979>snh> l#>ʲlL>א ,a>&_>m">ܳC?:F2?C)?= '?dex?;"ڮ??f/OS.?svZ.*?fTtt?X>8?IrԔ5?:k=y?,W?~>Me?DY>֋>?#>N%!>֛P/5>I%j>u%<>Fty>O:R>:p>-R>*6d*u>>$->ZP>uK>ʱu͗>̬>C)>>Jy >ݜ`9>1auY8>[U>?}? Z 8?,0?"A\&?*L&?3.@̠?? \>v>ma>gwh>FH>]fJA>J{>.>sM>H>""4Z>F"" >["\>K> >z`=>S kk>>F>K"H>ٹV>zF6>b:RR>uD? m"y?>?"?,-'=?6H)њ N?AOI?IG'>/?R=Xz%?X8 ?^ `?cQƀ?gi H?m##qnx?rYB?w޳/???k, ?ճ-s?O9?.m6B?en#?4N?Zl?i? q?/օ?l,?2@Z?5GF?އ?'D?2Z?|POo?}W8?rc?LcD?qDVn?} k?:,?KRm?!zU!?2t$?޳tf? :t?oe?-?tR?򙒔?CG?V9{?S'u?p+9?=LJsQ?pe?#Rb??S{?u?V K?b@,_?tCVi?+Y?+x8? ?&^?(Ν?r?):u?w-Q?oFo)?dOj ?X^f?KB?=D,*?0^8!?" ,?<까? jc/x>讦/v>2} >vJXI>ƒД0>,{>7A>v~; >Լ->1,>0jO>٘>С >5vUW>xWJ>\(>ޅc]>A|i>>7]>dO`>|Y H> r?2zv??!,U?+&?6j~?B;Y?N I7?WqH1?`P ?f>˘?lŘI( ?q k?u*n ?yG\?~cT?Wh ?Ii8?Clg?a?h ?5?S-$?Dek?E|W}?贈\?N\9? l۴?ʝ q?fs5~W2?%=e??hqAc?p^*?~L?!ն?f?}G5?{r?(#ke?$?z>d>5v>r:l>ؿ&>iu>@>P;Ξ>B>:"q>e>^7'>>_W>^7&8>e4>:">B2>P< >@>iv5>ؿ¦o>r:T>5v>d*??$_?(#ke?4k-> ?Ao?Op#?ZU@?cQ?l̞=?s(?zJcV?b8?BX?KCB?-B?.,?w:l?yt?uD?fn?YH?o+?-ʚͤ?C?|%T ?Lx~?b?*1?EL?0z?}?L? 6?u~,P)?? ?OxZ?sJ?')?g1?Hel?s?rc?UD?Ct?);?,B?{r˘?`P?WqH0?N I7?B;?6j~c?+&?!,ݬ?#?2zv> u>|Yl>dOd>>7>A|>ޅc]Z>\>xWc >5vTP >С{A>ٙŞ>0~>>Լ->v~G&>7Aߒ>,>ƒЌ>vJXk>2} >讦/6>c/̩? j=(?<깇?" ,n?0^8"?=D,ܯ?K?X^b?dOj ?oFo.?w-Z?):u?r?(Ν?&^? ?+xGF ?Ns+?&~|j?0]Bl?d?1[[?:Q?5?w޳/?rYB?m##qnP?gi G?cQƀ?^ ,?X8 ¦?R=Xz?IG'>0?AOI?6H)њ ?,-'=?"?>? m"{ >uD,>b:Y>zF6#8>ٹVc>K"$>>Ff>S kJ>z`gU>W>KTo>[!>F"#Y>""32>H>r>>J&>]fJQ>F>g>ma>ʞ>? ? J?tȺ{x?'٪ɐ?5]3H?DB26D?S)a٤?a]Ը*?mD"j?wu՘?2?Bv:?rt?d? ڴwP?"pj?~U? 4? p*?؋*,?\[?br ?+s?ԮfI?z6$U?]-Y.?;? 6o?JL?ES J=?WZ?Dm?}OM??QGfe?a?Z&? v-6?#? e.?y ?`?=?B?Z/Ԇ6?sp:8?0?͖=?簐uz?7вH&?=#?{ڟl!?{`?#?|[ ?*??\?u?a ?kzՎ??yJv?M?u+mf?b;(\?$8rb?&D9?a ?q2ĉ?79J ~?V=?r;?x?e/p?q #k#,?g#;,8?a{Sl?Ze?Uy=| ?P/դ?J"}CO\?CY?e>[U(>1au>ݜe>Jy>C)>->E>ʱǘ>uKx>Z>$->y>*6b>->:>O:>F̴>u%>>I%SY>֛P/K9>N%>?#>֋?DYe?~>H?,W?:k=yP?Irԓ?X>8?fTtt?svZ.)?f/OS0??;"گ?dex?= '?*U~Թ>?VX)a?i$?ka?8R?MCk?o^?_17?Ԥ#e?Դ,=C?CK*?r+?D2e,q?|bK1?{sE ?R??/r^?ԏA? A?}RR5?RW; ?NYi?̜З`?1Fh?2~ݸ?_t$?ە?2U?p;-I?CD$?Z}?ȵA^?47O?SĉIC?}b&X?y9!.?y肜?}N?"ʍ?qVK?/H ?vPl?y?m̀8t?_6h7?7+?:O?v*J?'hS?$y%? 8(n?,w?wĪi?h}4?d?5,?v|΢?nq?cy2^?Zة?R8?Kuː?D5y??x6E?7eu?0RK?'{d? bd8?*&ceV?C- ?:F6>ܳCʄ>m#L>A>א ]>ʲlL> l5>sn>9W>Q'->{>>M^J8>Q|_Q>rq~K>3fAN>ޭs> F>>~`3U>ɮ&P>p\̇a>{fV>!?gTS?-4ǟ|?!%lC?0*Lw?>-?Nc?]d!R?kkI?w \s?7^?g0n'l?Ki ?M+>?Kg_?+?//>?SP?>-?De?b-?R~F?W)$|p>윩Q(>->&&>u\>~>Yu,>Wx>~x>Kt8>*kmu>{nYI`>|>u>?>WYrl>I^Fk>#y>2 u>('>>ْO>x>6J`?*eg?xP n?"ϢD?19Ck ?@x/?P~uا?`A4 ?mi|0!wD?z _a?,?vuҰ?å?_?y?O?e]%?"kf?47n ? ?/5&?je?*?(xy?c0?Qٶ?&a?ui2[?rx?{g>C?+t?$3s ?n?;cP?aYX?B ?Ac*?.J kZ??j?7 F?.a?7jA?u(U? W}?,Gׅ'??b?g_e?+?;??cԋ~?+@W>?T ?zf3?)H?y??ʍH?ԫc?|Yp?=@?0v>U?i ?}i? ;D?/? v?fF+?8?TJN?9*;n?e?vS*>?nM?d-=d?Zﮟ0?Q[y^E?EVD2?:R0?1";hs?&)5'?֨*? hP?˂)Q&p> l>qR>M`x>,H/x>52ΰ>Ǒ(oX>&[>5-f>K>3Iw>Nz>$>^P>JŁ->">Ct9>~E>D|tF>yUj>ğ F,>OgNۛ~>R3G>ّJ >ǖ>gT`?Np L?!D?"]g?1JDqsQ?@z?P~D?` 5`?m<w?y@&?p2]?0Z?CB-?W 7?eL?9lђ?UwF?}6?z8?̂B?+ea"Q?.?2%t?Q̥F?P =?c㘠?1jٻ?[HH? 8}}?T?\u?|Wx ?BFH?;a5?d9E?Fe/?7?3?.b?RaF?#L? 1V?-?X8?=?uO?b?BR}?3?ɒ:? 02?R?\i ? 9ڣ?*Nى?P?4?ah?e< s7E?9b"W?)sF?fS=4?oC&r?$3{ި? ~PՅ?zj?L[O?OB\?}lBh? >Dd >b+>Lc>̜8x>T1%>q>۹>ϳ'>E'B>>J+,>/ OT>ǝ 0>NM(>0j.>q7g>(> >*hS >65P>=WŖ>Dʹ>,G,?·??" o_?0_i?>楎S*?Nd l?]6列?jR?wB ?5?;CF%?٧sn?Ԧ?wYY?]tHr?l?D?0~0ʒY?łӪ_*? } P?g\?Lʱb?yJ?p5?d>r,X?W/9-X?IX!tP?;ط*?/ש`?"0}w/?e?:'c>CÀ>tB0>"A>Փ0#`>Bg6>j#>:s|]+H>JAtS>|&>`xF>1G.>yv>p8<>+Z>jr[>C>>@>Wd>:>`$J?>W>+>}ճ.s>m|>ٽz@j>-?kqv?Cһ? KMd?-Zi[Vx?;,"?Jjn?YH)J?f7z?sPS?PpL?|]H?E$y?ٴC?r?S?dš?> ?C?w?nƈ?(/?b|?*?f\"kD1?o;Z?|$%m?(ؤ ?Au?? 7/?Y(?p?\B?c4}?m4 ?C4¸?]f?".'[8?i^l?l?V~?&?(7?z6?p?5z;?zs?o1Cx?b'"bR?SJ?DÀTK?5?P?'(Z?? "2>'9@>Z/S1`>8>7 >˂DdP>b=4@>IT>D>a->=la(>6 >^c>Mno5<>S$ъ>s->ar>8x>l(>?s7>cT65I>ŸҶ>ǁ zIN>{Ƙh>'>"B>{D? =TP?GU#p?)*T>?6< >}?+  `?W*? 68?hN???>L/?Er# 5?U ?|CNh?1 ?*w\?,5?m/,?@?ۨ?QCV~?-;?r|ȼ?WHC?dX*?!ƙ?-U??ev??=r?Vd?]ڙa?Z AP?4Ă>?@ND?k?Gdu79?nO?)?zkM_?)?,{}?ojt?P|?W?!1i?7\?τb?0={?/C6?w턊]?k)b*]\J>=ƅ>ץU°>KF>ۜ>ԯ X>}x>٭bp>7;>)>KJO}|>B2|>fҋ>p> H1>bͳt}>8Ki>°ʅ$>y>á>ćc>ͩDm0>U$> n|>?ہ.X?F?nP?$ZF?2]0?@Mz z?NHn?[i8'(1?g9[a?riG|?}\)'46?VF?;s ?l/?YR?Pf;H?CQ?TX" ?v?/?"AZk??ǎ?h:|r? w]?U|?{h?jdi6?g?e?BJA?SH ?@!&?;zlD?>U3?i]u?aA?FaSS? ݠ?ѷf?{7? ?G'gdlR?SN6_?ğ7?cĂ?f il?3R_m? Ⅶ?n8[?joH?*?ǿ?d ?cƴw??[7?>6B?(yg?|£\?yMr?zho?zOu"? M?]xX?Y(s#%?h!_? 5? /߆;>ʹ>WR>Ѧ`!> VuG>ۊ >.+y>묦>s>9SM2>>^V>pA>8'>(ȳ h>zb_> r>n<w>>?>q>SwT>ڤmN>?>mV?ن?vWi? cP?-+z[?:3 :]-?GmH?TJc #?aD^W?m#"?wH^?-?͹B ?Hp֘?~U?H?ta?~ݣĆ?9l? =n`?t y?!ȖL?8?Фvc?K|?4ԀV? ?#`?cv? }?B%? eX?k7 E?]+O? r?S=?򸐎ʬ?i̱7'?|wX~?{^}zct?~84?fjFA?6{? fٓ?d?Abq?oC!e?*#+@.?̼eP?BH}!?e?N?tЮ?W"?L ?]̠L ?#|23u?$? ?%Ý?NC?~hcDf?{Wտd?|8W\??4 ?ԩ?&Q?pZ?0?- ?0e?P ?è?Jde?eJ/?c8r9?d"x?y Im?j +?[d1?Jox?::T?+@#Jp?2{+?{?R,޸>3mFf>H>p>ʳnh>">gc>I:f>f2@>StV>ɼ1)8>p8jw>]~->L M8>p`>>S׿3>Ti>L>z.:V>">C%f>ճM> f0 >(>J? Μn?|:?'a 4?4G?A5{q5?N ` ?Z@_?gI~?sJe?~?%?=k,OB?H>ڑ?NߧF?Vj???nb?_u ?`yW=?yn@fT?JrI?P?ZGM'?$;Z?dш?ki?Zw?Qܞ?L+ ?-?JY?E =h8?ҹ?Ԡ1\s?Xv?G2 ?~Dt?}(?$>j2?6Y?J3B?t?2_W?g*A4.?F,5F??B8?yR?n͖&?ogm\?'s?Vy54>@EbH>||>ѩW>Ū_#>Vm>v>9JԿ]B>ts>Z|ٯ|>Kd> >eF>QZM>1P>Ral>o9&Rg>q J>o9Y>Qf|>[~>nb}}>aF>2k??׎?ȻFaY?N5??VY}b?I ;W)?tܣ}Q?7/(?&? }p?}7M?Ά? /C?TK3?B4?#?R\[^?o?RO?BJ?4L?4??!?֠?oCY?>7$+?ᅺ?k?x}?O#g#?laa??S16?h?28?jd6?⠗F}?3x-?zt:6?miQ ?"Ғ?Fqf? Iv?δ8r?ğx?1YQ?~?J?%U Mh>qs֏>^fe>حؚ>p1> Ҧ>{>O>"x2>Jq=&>lK> Ll>nxl>5>:.>ef>-3>_z>$ь>5 > >ʉmY7P>iZ9] >4 > +.>R ? NNHN?8;ra囏?k׮n?x[KM?iE?p#?ԭ)Ec?]PE\?t?g] ?v<3?۞e?6?l$Zk? AT?,?B>h??u20?,&ʷr)?]o?gZ E?\7Xd??~1?O?nH4?'Ky?~qx?ˤj?LMdQ?N? 6l?z7=? kr?y|;?? ?}??^%??3zX?az?=Pr60?}@E?c?uvF?4?rX6Ɣ>!&> %>Qj)D>F9 {>AV\>#>1d[>7Tv>B">9%T>#b9>$>#bi>9%ⴉ>B,>7V_>1d\E>#kw>A6=>F9 7>Qj> >! >rX6?ɑ]?HD,?\ ?*9ӟ?7:m?E??TpL?b$ ?pn#̄?~k? 6 ?'tA?^b?S?|5?n;?ŗ?Lj?Mt?X?F9`n?i΅?vI:?ye?8?Vu+?g?Lv X?j{?hW8˂f?#%T>so>h>WD\> K;)>ILU>%:>LW8B>p|#8>NH>* 2>{> F>mcL/>pCl>L[$>Br,><*B">Tj>Шܞ>u >yc>Հ;p>\>-3>0 =?|{Sh?_:`?$z "?3+$?BX&?Q?|?ay?pD?}9?[?UMH)?<_%v ?@2>? m#?S?-EY?AqU?}>ђ?Z?qrN?|8?-Z;??u?wǩ(?f?1?dp?F?S?=#p?? }ԟ?P?pڥ?v!?CL@?*?;nN?ug?N507[?dD?_?cep?D4?sΡ?SSJ?ϏK?kV?!I?r?|vNX ?n5?Qt(5?w;F?}e/???n?9?0&?a (W?\9?R9?-?co?':?YC?@b=??, P?BL?1N?8pv?~v?r2R?g]oB?[ ?N>?AFkٚ?5?Nf?){% ?|Ͱ?Gta?"ަD>A>a^>Tm>3>*T>ʡ>J4B>{>f|^>U5Йm>\>{Y >c'>m`q+>f\󵇃>Ðb>/SC>^ u>>_qZ>*. >ZKK<>ETs>X?E`?F_>? Ev?.lӜ?=zi(?Mqe?]>8^h?m z?{2i*?@d?_??]$]?U(m?dYR. N?*F̭t??,eD?u?FWc?cx?zu~?AP?Ʌ?#'[h?$M?&E;Vx??+#t4?شu?`l?l?g&ؿ"?0h ?+1b?[ l?b8?!8R?_^}?Z6j?%ظb? ¿?:^?ܶ?tt?oXW?~w7?{xD^?|pX'?f$ M/?Yvli?{ݥ[?~>8&/>/>*m > 'S>͍0->.>Td>ސ >@v&e>">xaᚚ>UfX>L5vm>FCC>7>XDQ#>Kw>s\ǽ0>?[A">D>~'>Հn@\>L_eD,>@M7>z? q-?[hC?)O?8*~ @?G-_5?X4#?h$u?w["?(QK@ ?b׷@?,x?*xEy?S1t?]?|v?RNk0?p?EI?C)֠?: ٸ?%?? oB?rK?zl(wc?y?{Gt?[ >Z?w]T?o?d{=?X>6?Mq<&?AITY?4:?(%8?Z? m9~?K8̾ik>|>佞;>ΧQ@> L >+N$X>j:R>K6l̍>S"i>,>dfU>Xg.A|>C&Z>rJBV>&X>|>nn-R>[>K{>4->~O>Ĺ) H>&7h>ܕ^A}X>oqx>(?}O?]-K?$ڛ?3_&Ց?B%?SE ?cn?rV_?|A?WDڢ?zYݶ?%ǟ?B?Ǔ ?)l?16?!?2Q?xy{?+~6?>(mjD?wAi?}W7m?xl?w5('?zANs?djP?&}?9@FP1?Ys-?f?\}?S-I?`E!?f)7X?vyq{?RQu?]9@?S&/?{_R?7f?>?`?L?! ?DFD?AȮ6?R)!?8?A2?VG\?~y?P:g?.tE?$6?ᯤc?8VL??z3?)( M?ޖI?Ax.?4s*?[? ? h!2?O?J[vU?C?1Q3?'K?q ?R 4?{ŒI;?saa?i^T?`Xd?S&`?G47?:7ŝc?-)bqx?!2 ?J?`Z5t>I/>觀Z%.> x>u>ēZ\>N>C(KL>X2~>o[@>zޛ'>BF>kl=>Bˀ>;^>Z>4':>,i>F>IţX><k{L>lғP>W&Aq>XIČ>!p>涋`?ޒx}(? 0? ^;p?.{@?=2.kX?Lְ?]wq@?k2$?yC =r?VC ?JEȺ?ID?/W7d?O;?m5F]?dLA?ѐb`?%*GV?h#?,*=?=J?}a?i}v?}4?|=eV?~J1a3?Xi?>x?.!?6? ?+?@RI?p??w,?A:h?υdG?w?S}&?uI+V?Vw?D9?gqNȞ?*0?4|?G_??:I|?Gde+0?ie?XI2?]s|?uL_?v"?'?uhٛ?*?~>D?u?/;6?h?jWv/?W,?E%?a))??>U,??8ٓ?7B?0w/*?pOj?L:?bЂ?x]gO?pM?e#>^?Y"?MKn?@_KR?26μ4V?$*P?:?]pԹ>hFn>)`>FN>,>;ܲߌ>'HJ>]n ]>.IO>!>;ձ.>-(;ݨ>]ι|>w+s>2%l>~s+>g0ch> !H>oI|>=>@@>T@*0>Լm>TRCtX>d> ,΀? `YtR`?\5?'e:?5N8?D?THC8IX`?cP y( ?qb?~5)oT?J?}i?۷\Q?gض??>?~*?]e`?x6?1:҅?Oe?eZr?0%v?Bx?x"?90?YN? ~B?a?(%?U.?GVv ?֫7=?}jy4?m6?I?D*JA?Sϖ0?+jH؈?<p?-1?0G(c??l06?kQ[07?W>n?ħ%?H7*?&e,%? Ӹx?J??PA\?z;cm?j]?hb`L?4 ?Lc's?,rj1?]C^?©fI?g!F?`O? LD?yiv?9dOkk?3dl?Qh?*2?V-mjZ?6g&??L`?Dn?t 8?jSMj?`z@?R[vEu?C裢+j?5mO7h?(,Iч?mD? GJG>&]^>>F j~>h_>Ȉc>l>oU:>60>;꾶>dak>r>mϑ:>gZ>KO>>$?>zm>?P>^FA>ybt>B_7x>c,.ʱp>*M>pp>%J>]knP?|G? ; ?"<3$?08h/Ø?=[SۊG`?K~{1h?YYy ?f]wP?s/2&@?=?t̉?#Jv?E0?r#+? ?mx?A8_‚??0=?i#X?^c'?S#jPf?X?s?J)?[xQOz?Iu`?P?ޣ9? *,?UbV& ?T+*?*9?HȊN?^/)?'{?WRw?,h'?pNUi?;K)?{~?7 ߶?OB::?8)?38??5%? '? Y=?ñ?~Np?p?^Z^z?bZ? *n?[I?1Ӽb?A$G?U ? 0ni?o?q8^8?8?M?::7?C"x? ?S$?Z?rh??rN9?URZ?#]h?xlMͦ?o<Z>?bS?UZH,?F*/?8\& ?*ݷE"?;?0bQ>#8)R>lB>GuJj>|#F>ȷ%>rE'>' N>xC >DD;9@i>66,>&0>KQ`>[P>N>"XgH>8>@>Ar>]s>S>< >n猳fH>գ(j> #'~>%6@>Jj?ɵ2y?CL0?" ``?(d2?5`H~?B>x?P"(?]9G?h,?s^Lcp?~L?>?z--?~̇?2콩?ݠ?{?!s? r¢?eW۽?5GHuh?_s~?d| j?fl?D0O?֧?`?M~?;(j?rz=?#P?1?{;#N?N{?5t?|#7 p4?q=G?d&DK,?W'@֪?H\q ?9?,&Y6ne?td?e`L?9^[I7>k70e>6;(>֧i>>Ȁ4>HN">)9L> 3>`4>ވY> l>dL>>}k1T>oC|8>N{>O>!W>J >WrY,>.g^>с>0x>E.Fp>>B ?nR~x?.7_@?3r`?%i^*X?1R8?<J6k@?G#eh?Sl0l?_e?h l?sȎ?~d$?e9?`(?Oe?r?=4?oID?'?ƚ ?t4j? )?RU*?հv?qȊ1?_$\?y_?>:?mC-?3%?I?1?'t=j?C?_? ?I"?9\Z#?x@?kHb?=r?J??*?n7?ڨa?Q2h?nU?ެ[?91?_h5>yϳ>֪F> X\V>hޡ>%Ӥ>->CW>n>7/U>>!Q?>SҤE>0>ٸ8>i"YT>{UD> B>æD6>/>כ%4>kq>-Ս>{+DX?xP? sX?F*0?b2?&pдX?0[b?8O?B;?Lφu;?Vk}!OP?aÐCf?lshi?1C]?d*A?o6U?Zm/?V^]A? ]f?Muŀo>%.>FNF>~U:>h>cGĩ>a`1>hyx>H&΀>w, >p>N\>->˯U>>$>zDc>f>_& 42>Ȉ#j>Լt>߹JX>6eW>L• >Õ ? jPL?2T\?Nִ?$.ݰL?-3+v?4x$'s?<(Bh?CwmP?rF?C@i ?$ ?AKv?b]kJ?>r?Aj?.Aa ?|Rl7?z&x+?z.pC??!?-wK?5 ?9R??͹{&?.$7?Ӎ?g?CI?~6?-y? N?@qZ?'59?uT|?j)>흽dLo$>*_:>~K{%f>|PK>1鐌>bȖZ>d>G>/]>}>4d#e >ag"y>cn\8>Us> f)7>D.>8>Ъ'>Uy>Uhq>pEF>D? Y3?YuT?v?& ?/O??6ֿ??zw-?EZ?Lh?S&%X?ZNbPX?bQ]?lk#?uô?A gj?DK??(?9-9Z?6_?*z"?M4??PBO?HW?ݵ?, 1?|s?j?VRΩ?)I?8"?|]v?yJBo/?yٮId'?~9tL?r+0|?1G?h[nȺ?8G?;гf?v?с K?YJ=?$C?M ?45Bp?`0?$ M?Lu?qBh?@CL?s?L(zGd?>]ܖ\?1 aZX?#6? ?6گGy>Kv>JTF> !o>|^o>Č[Qk>U>D1}@>C%Bx>L >Vi\>1K>q>ݱ>o62>lŸp>D.e+7>y "R>|da>-Ġn>Qwb5>␏;>E+>?UD]yq?h}Y?`?'y8S)j?1Ĥ?:w,r?C!1?K(If?R?m?YX1p?`߭p?fR,?m-?t~T?}@ϡ?LTz?_ɂ?H Z?c,?I?!xl?l~E ?.^?.If??8)W{?-U}?dS`?-ob?UZ?o?ԫGh9??a?搱?S{?:/v?;}ٹ?d?`b)zK?Hz.?sؓ ?8Pd?{DN?_Z?v#?Wh]Z?O-?uG? ?IL?>P$?;?{Ļ?j(?w?P %?UkK?k !?.I?X6:B?lS??;?yR N?!.i?kFW?u]eO?mU.?j2? ,?x @ '?p:/A?fp+?]PV?Q˩>2?D:?6k~?*Q?Пf?pJ ?F(p>7+=Aa>7of@>TvC>DŽB>*%>2>w >ZF(>7TP><5>_>gϭ>>~>2Ǩ>T>]V%; >]_l>}>󎴭A> >LMF?W !?0=?ns^?&j?2 U„$?='l?G|=?QVx[?XŁ<$?a?g /C?nT"?s]?yYK  ?-?"?;? ؋H?zR愧?BmT?[{?\e?Iw/v?Z)]@?t?a=9B? ?& 顴?{治?򹟾?5v??3'? Mf?ĭ,2?cc1?\,?}T? w@w?YC?5W2?X=?M ?),2d?mI%?a?5#{?{ )>?z3ԁ? i!-?{D>?q?o3?*???b z?Vf ?)h>Wi?bj?k9?& G]?s,?Z;?@?c?9ngH?]X?zqm3B?w?~>?wW1?-ؖ?JlP8 ??zIџ#?tR6?ml:\?dAa0G?]Մ\&?S B%?G[~"?;rM?0GMJ?#M9?s? oi+F>Q_>-2>+<>&+i(>i5<>lgw>񉔳/>Jk6Jt&>LX>֝ o>l!>֝ n`8>M>Jk6K>񉔴$>lgwa>i5>&+i$>+>>-5>Q_ ? oi(?p+?#M9~?0GMJ?;rM?G[~?S B&?]Մ\7?dAa0R?ml:\?tR6?zIџ#??JlP8#?-ؔ?wW1?~C?w ?zqm3C?]X?9ngH?@?a?Z;?s,?& GT?k.?bj?)h>Wf?Vf ?b z???*?o3?q?{D>? i!-?z3ԁ?{ )>?5#{?e?mI%?),2f?;}ٺ?X=?5W3?YC? w@w?}O?\,?cc1?ĭ,2? M_?3'??5v?򹟾?{治?& 顷? ?a=9G?t?Z)]@?Iw/v?\g?[{?BmT?zR愧? ؋C?;?"?-?yYK ?s]?nT?g /8?a?XŁ<$?QVx[?G|=?='?2 Uƒ?&j?ns`LME8> ˦>󎴭>j>]_L>]V$>Tb>2#>~6>Ш>gϭm>_Z^><#>7>ZF >w X>j>*v>DŽ>Tv+>7oeO>7+=O?F(q?pJ?П?*Qz?6k?D:?Q˩>2?]PV?fp+?p:/B?x @ +? ,?j2?mU.?u]eO?kFR?!.i?yR P??=?lS?X6:C?.I?k  ?UkI?P %?w?j(?{Ļ?ͷ?>P$?IL??uE?O-?Wh]Z?v#?_Z?{DP?8Pd?sؓ ?Hz3?`b)zM?d?r+0|?of>v?HH?+e?#(#?߆a?Ļh G?:/>E+>␏;>Qwb>-ĠnL>|da5>y>D.e>lŷi>o>ܶ>q>1K3>Vg>LB>C$ >D1>V >Č[Ql >|^O> !o>JT d>Kⅰ?6گG??#9?1 aZX?>]ܖ?L(zGd?Yj>R?dj7[?p8#?x#>??r8?&Py_?l?C?6W?ϝA,?"$|?¥?ȡ S?᩾?p?=F?vt?4S?~?O?u~??с M?v?;гf?8G?h[nȺ?1G?|?>L? 7ƥ[?dk?h?~9tD >pEP?>Uhx >Uy:>Ъ'D>8Œ>Dn> f(>Us>cn[l\>ag#>4d#d>} >/X>>dz>bȖH>1>|PKU>~K{)>*R>흽dLn\>)ͺ? Tc ??`?'я ?46ӿ?C=Ҕ?R%%?`:%?j?zE?p?b]kI?AKw?$!?C@i ?rH?,3>?Lb?5?ݗd? ?uP?K2{j?lb?U?!w?|47P/?x =ڠ?w&T?zf/1~;?Aݜ?2"?j04?c*?eIi?m5ż?ꂒ?f;?/'T ?G#P?( Py?yc ?nǃ?~={O?q.F?T$?s=^?/p&E?s֗H?h?_)??T*f0?KmQ?CwmP<,?<(B?4x$'r?-3+u?$.ݰL?N״?2Sz? jP>Õ>L• >6eWה>߹J>Լ0>Ȉ>_& 4S>f<>zD,>$>O>˯V/>M5>N]>pt>w,|b>H&'R>hy2>a`1>cG >hz>~S0>FN<>%.>Muŋ?!?v)z?*\\?7bVa?FD?Ur ?c0C ?ppi+?z9%=4?9C?/jE ?[V?{)K?5xX)? x?IpTl?Ǘ3?;?85"6?)L.t? e?R ? 2>?/P?2?sk?" 4J?z,?y~H?{#+?-"6??em?ۧ2s???x@?\L?MDo?9Ű{+R>-Ս>kq/>כ%d>04>æD~>]B>{UD>i"YQ>ٸ5">}]>Sҥ`>!Qc>>7 >ז>CWWT>->%Ӥ7>h޼j> X\)`>֪>y>h7@?Bv?Lv?Ed(z^?,??9ug]J?HYN?W;?dy#Y1?qpE:h?|^?Y݋?"(=#?5/ݜ^?x&N?[<?rX?9ԃ^?Gi?+DC?Bb|?+7z4?]|x?)@V?P\Z?qR G?|GnC?1;#?)qߺ?G`U?֢??79?/~y?_:?y_?_$V?qȊ1?հr?RU(? )?t4f?ƚ ?'?oID?=4?r?Oe?`(?e9?~d.?st?h l4?_e?Sl0p?G#e?<J6k?1R?%i^*?3r`?.7_P?nR~u>B@>>E.n>cx>с>.gzT>Wrh>I>!>>N{>oC|b>}kE>X>eF> e>ކ>_> 3>)9A >HN"~>Ȁ>֧i9>6?>k72?9^[I:?e`K.?tc?,&Y6m?92?H\q ?W'@֫?d&DK(?q=G?|#7 p>?5t?N{?{;#Q?1?#P?rz=?A>(l?=?3?Gnv?UWDy?ebF?k?W?׊L>?2hi?*; ?1w3?*5qm?IAjj?=* _7?'j?j&j?C)R#?dmJ?S3,?]O?k?=5D? {K5?lXR?%S`K?щ ?-~1U ?;K*?NiR?Xr?~\?xW@?/ ?iI8?b$+?%ތ??;B?M~?`?֧?D0K?fh?d| c?_s~ ?5GHuc?eWۺ? r ?!s?{?ݠ?2콬?~̇ ?z--?>?~L?s^Lc|?hD?]9G?P"?B>X?5`H~?(d10?" ``?CL?ɵ2v>Jj0>%6@P> #'>գ(j`>n猳x>< >S>]sP6>Alt>~>>"X0>NC>[Px>KQ`֒>&0>662>DD;8>xB>' />r6>ȷ%r>|#>GuQ>lC>#8,?0bQW?;?*ݷE!?P?Iu`?[xQOp?J)?s?X?S#jP]?^c'?i#X?0?mx? ?r#+?E8?#Jz?t̉?=?s/2&R?f]w\?YYy?K~{1h?=[SۊG?08h/¨?"<3$? ; P?|C>]kp>%V>pp>*Mp>c,. >B_7@>ybt>^F>>>z>$v>>K.>>mЅ>rG>daϭ>>;̏>5 >oU?>lL>Ȉc>h_t>F p>>&]? GJC?mB?(,Iч?5mO6?C裢+`?R[vEv?`z@?jSMg?t E?Dn?L`??6g#?V-mjV?*2?Qd?3dl?9dOki?yiv? LD?`O?g!F?©fJ?]C^?,rj1?Lc'v?4 ?hb`Q?j`?z;cq?PA\??J? Ӹx?&e,%?H7*?ħ%?W>e?kQ[03?l05??0G(c?-1?Vw?+jH؈?Sϖ0?D*JA?I ?m6?}jy7?֫7=?GVv ?U.?(%?a? ~B?YN?90?x?Bx?0%u?eZi?Oe?1:҅?x6?]e`?~)?>??gض?۷\Q?}l?J?~5)ol?qb?cP y( ?THC8IX`?D?5N0?'e:?\5p? `YtMP> ,Π>dP>TRC{>Լm">T@+>@<>=x>oI> D>g0>~r>2"V>wq<>]κ,>-(;)>;k> zT>.IOv>]m>'H>;ܲ׳>,>FSr>)>hFm?]pԴ?:Z?$* ?26μ3c?@_KR?MK?Y"?e#>\?pM?x]gO?bЄ?L:?pOf?0w/(?7??8َ??>U,??a)*?E%?W,?jWv.?h?/;9?u?~>D?*?uhٛ?'?v#?uL`?]s|?XI1?ie?Gde+6?:I??G_?4|?*0?gqNș?D9?{_R?uI+T?S}&?w?υdG?A:h?w,?p??@RH? ?+?6?.!?>x?Xj?~J1a3?|=eV?}4?i}~?}a?=C?,*=?h#?%*GV?ѐb`?dLA?m5F^?O;?/W7g?ID?JEȺ?VC ?yC =r?k2$?]wq@?Lր?=2.jX?.{ ? ^;? `?ޒx|P>涋>!>XIČ>W&A\p>lҒ><kC`>IţD>Fe>,i>4'>4@>;_>B>kl?w>BF />zޛ%>o[?>X1&>C(>GD>ēZ>u> y>觀Z%>I,?`Z5oj?J~?!2 n?-)bqvE?:7ŝ?G47&?S&V?`Xd?i^h?saa?{ŒI;?R ;?q ?'K?1Q3?C?J[vR?O? h!2? ?[?4s*?Ax-?ޖI?)( L?z3? ?8VN?ᯤd?$6?.tF?P:g?~y?VG\?A2??7f??S&-?]9??RQu?vyqz?f)7X?`E!?S-I?\}?f?Ys-?9@FP3?&}?djP?zANs ?w5('?xl ?}W7m)?wAi?>(mjE?+~4?xyz?2Q? ?16?)l ?Ǔ?B?%Ǡ?zYݶ?WDڵ?|A?rV_?cn?SE ?B% ?3_&Ց?$ڛ ?]-KP?}O>(>op>ܕ^AyX>&7hp>Ĺ) 8>~>4&>KQP>[݃>nn,>|N>&R\>rJ/>C(X >Xg-;>dd>,D>S"iĔ3>K6ľ\>j:7>+N*f> L@>ΧQP>佞P>|?K8̾f+? m9{?ZL?(%8S?4:?AIT`?Mq<?X>6?d{=?o?w]T?[ >`?>Gt? !v?N?^ir?[&w?b?ŏ3zx?f~?07?W_z >@M:l>L_eG>Հn@X>~&>D>?[;J>s\Ǽт>KO>XDP>7?I>FCD5>L5vmH>Vy>xa4;>"XI>@vo<>ސ >T>.*>͍0`W> '׭)>*md>)>8&>~5?@?ؗ?#{C?0OC?:O?Fg5?S6qv?`tg熤?j351?tHhZ?~f};Y? S!5?arҭ?q?am\?nA:??0 0*?";-?kd?؁?%A1?d?d<9?b8?ʇi?_?黖a?gI@?dk1?Koӧ?8^?Mqe~?=zi0?.l(? Ev?F^?E`H>>ETs`>ZK7>*-v>_qcp>Þ>^ D>/SK>Ðb>f\|>m`qx>c'>{[&n>[ >U5И>fN>z">J4C(>>*T?>4!>Tn>a^+>A)?"ަB?Gta?|?){%?5?NE?AFk\?N>?[ ?g]oD?r2R%?~v?8ps?1N?BN?, P??@b=?YF?':?cq?-?R9?\:?a (T?0&?9?l???}e/?w;F?Qt(1?n5?|vNX?r?!O?kV?ϏM?SSJ?sΦ?D0?cep?e%t?dB?N507Y?ub?;nM?%?CLђ?AqU?-EY?S? m#?@2>?<_%v?UMH-?}9?\?pD?ay?Q?|?BX&?3+Ć?$z "8?_::?|{Sl >0 =>-31>\u>Հ;pj>y|>u >Ш.>T><*BsL>Br[z>Lg>p~>mcLj> 6>z* 3>N5>p}>LW8bx>%;{>IL> K;g>W3>hd>sr>#%N?3UuC?qn)r?#{5O?0Z?<3K?Iu5D?WC{;?d\|y?qD`n?~?8XI?΍E?@30?]?'A? ^$N?Ry$?< Z?1-?qN:?e57?i-F&?D5?e?cXKX?'bK?mj2?yBgz?"g*?Q%y?!@6O?g:?ȱ2?t*?u;?u^P3?hqP?I?4 9Nj?o?LczCI?-_T?'mY?J?ZJ?W>%?%/i?qO;,-?k-?[t?-?CB?[|?KP?UZ?Lh?1Q6?q EF?EyL?y# ͝?@?<*]`?sE5p?h0P?=+&?Z?h?CV?>e?Dh?̥?f)?0egB6?w.F?jiS?]O?Oԧ?Ak^?3u!?%.TͰ?.`t? B^>@>$=h>̓>G~ͅX>F>ñG>tKr>'U>᪜b>a@>]I">qt>M5i> >M5H)>q"5>]I#d>L>᪜#>'>tK->ñHm#>F8>G~q>̓>$=h>@(? B^H?.`r@?%.T?3u~?Akb?Oԧ?]O?jiS?w.F?0egB6?f'?̥?Dg?>h?CV?h?Z?=+&?h0P?sE5p?<*]`?@?y# ͙?EyL?q EC?1Q6?Lf?UZ?KN?[|?CB?-?[t?k2?qO;,-?%/i?W>%?ZJ?K?'mZ?bR~?;|uv?"΁l?CY?{Ν@?$Ub?vt?m˶??<ֽ? _gA?3>6*?^z+?JDf?1 v??s"?Mۚ#?%!?b?~?{P?2:t>? $}?l4?1?'/y?*? |?%Xl?a?cB%?v^G?ji퀞?^KlM^ ?QW}l?C "?77G?+045?Y@?hdS?H*>*J>)Ag>>+|p>ySл'> )>.z숮>w[^>ۿ>[i>}>dz>ԝ['>Q >b>]!>2kM>=P>pV>V,U>3t->,и:>RȲ1> y :>"?>dp#3V@ V?Lؒ$?[xP?je_(|?x\?X?U? YP?( ?AqR?Qu?Ci?$J?=繀?ќ5R|?se?UF?]i???Oc?j~?yz?ǫb??|t?^Ș?I}|?u8֠?hYa?X&?x?k[?_?5a?RI?t?}?@?B?'-*?{%?oLM ?}x?}I*?NT?K7ڃ?Qg'7? - ?e9q*?pY&R? KS?l1QU?[J[ 6?oD?_s:?NT? ;Co?ө?S?5+d?AN ?b?XD;?K#!$?e׭\?=)46?sں?t3&7}~?j MH?`wS?ST|=5c?Fx/e?;hbj?0j]u\?$r%?mX?p(C? f>z>qs>hV7> U c9>3ԋ>p;>#uRm$>ۭ}>xw>>HD>>>>M> Yj>){ͺ>]7>|cY>G|>4m>ʊ`~>s>->̈́g>LGЯ8>D34>>7L?-G?G ?q426l?+$?:<xE?Ij,H?Y+ ?iK@(+?x e?{fr?#Rt?x~b?M!?Y~X?ѓ?#t?5"oe_u?gnaW?\q?<^w%?2?<M{?LD H?F ^?C>H?|~??7? M?v?Z?Rs?ԹY5?n 図?Ea B? (|?A4?#P?St?LJ??|J[V?t P ?kc֔?a=?V1?KiNR?A 8 Ԑ?5C=s1?*09`d3>lG/Q[>> >і(; >ű `[>:> Yz>v>,@@> :^>Sg>u6><# >#̥>"+x>lF>f>2 ^E>u`+> d>!m9> Af >Ӕz>@g>0U`>ARH? H?|8K`?'2P?6a.>Jl?E^?VRl?f d?u~^?32c?c?6F?X`p?A:A?"YC??~z?O_?byq.?:ˁz?hҧ?^Ȅ?BV?f?؄}?zt(?v P;?u81P?we,?}W0?h2?~5j?gm?@4?]?JE?zѻ3?xO1?Ơ$?FXA? S?INmډ?z!F?Ef?;5 ?r-?V樔?x%`=?u|w ?v%4Д?{W?/g?䩽Ix_?,ǡP^?Xa?Dj??U?>5W|?gҏ?0Mk?|.rx?ut)J?n|?e Ѳf?[Fmr?QAKB?EH?:.f?0zǨ?#I8?tۋ ? ,>Jۇl> >プ5l>KbH>,T? >,mV>0\(>>O+At>Q7>U!yZQ>~>SA> ?$>z>Q5:>Y>֙;k>|qH>gz>IIF> ޽>D>ĝ>>ETqͅ8>M>"h>P C?$*?^?#5T?2|F?B%*e?Rs|[ ?bkE?r4?Jɞg? ̦?b?{;?*~?V?N1?L ?uX? ??]%?kV?V U&?E~?lFl?x9ܺ?t'6?s}=?vS?|=d^?Zo gwD?Pg?+ka?Hݿ?̡?Lp@?o'L%?AE?ID?$`*?|`?ȳ?5 TQ*?Rv ? )W?%Fa?4ɛS?}JR?y=}u?yS] ?}8?M#^c?ӱ%K?Rv?Z ?iýX?]ŏ?b(1?P;_>q?DN?$w"+?a??\g q?=hQ?df?S +?m~x?4F8B?,_S0N?[?=P?\ 81?x(?kIzC?qi?ii&q{?aYTbS?VsŹ5?LSk]M?A*‘?4?(x 1?_3Eu?f6?g>ڟ@:>7 r><+>s>5]թ>ׇ>n>@qq>o#>b꯷>) 9>ހ:>?|Qc>x4v>j>o%Kk>at`>v0>g>B>;v>C>2:w>>A3X>|,?o?. Ix?.Hwm?= ?L=Z`>j@>_m>2q>Pg!>ux>C> _ >>No]> ͺo>ݐ>z >Dβo>#%i>d*e >1?#>dZ>U~VB>rBD>@ֻ>V>,'>j|F>NCyx>~.0@>u)@?7c?Zz?'_?6; ć?E6(?UCtI?dBP?rH?Ed`k?/1?P?DR ?}brڊ?{I?GA?;tM? l?ߚYیT?q~?WoY?Rb?^?$?פ?x1=?~ 9?}X{?/Kצ?c@?aE1y?Ej??{ "ʟm?yw?Vڀq?1AO?*?BQy~?\E??9 y?/^?B%k??B\G?a}R?2?^?J-I?fm ?Q?Pː?g {?؄0?>8#?;#T?a?I86?bi?;YU?I2? z?}֒=?͔],?FE\Q? ?th2? I?S4?ElbJ?cbC?<{FE?c%5?v?nX?|I?sF&-6?k?aJ"\ ?VvԪ?J?@?=ۘ>?1> Wb~g>d<>)t>ҤE>([>rC߶>0>{v>2JW>Ւ> > ߐ>fpph>wi2>?F0>.o,S >/Q>v[>Q'b>mc> >6l4=>`>]HH> >T.?gYn?D=?" t?0ME?>ϼa?MT4u?[Į?h++?uj?p|?bV.7?jR?O)?D0J?,c?2 +?A8?d4J?xn{?7ģj:?ș?Xx{Xt?z?6@?ʸ˘>?f"Z?Wџ*?SA?_?loF?nw?ȟB?]? \VW?QSiS?uO%?<`?澜 /?"ըv???,e|?މͷV?O?k{?'??+{??L%*z'?:Na?jl>?Ms?Dy?{2?*Y1?1?(??ͳ?譓S$?dߞO?^ 7 ?chvk?YH?f 8?nR?:Lrt?u?fq ?Dؼ?h?hqoB?"R?x oQ?p (w?e￐?Z-ޯ?NDA?@KL?3,ĵb?&%,5?6h? %K>ju>jh>3M>.1>-Ry>YTO>ru0.>*-ڨY>>=l>ٲ>Q>ȋ>g>-̲u>4w>]s<>vM>.-C>ϗɚ>j rE>a>۸>Evvr>Җ>ĭ#>>:{@>UZ ?/w?3?q( ?(v*0?6@ ?DZSKT?RtGP?`\#m$?k2Yn?w,sFӷ?TDK ~?r?:y?""F?T[~?a"p??oY?SN?F/{]\?Y+zH?=P~j?B ?n?;H.?B?jw$?ǵ?@%1&?K-?ǭ@Ô?{!? [W?VnK?EY0d?M? ? Q?,yk ?OFC?wv ?ύd?xDn?Ȼg?jr2.?aԳЛ?}tf?Nhq>??*? `uD?&o?V ? ?z?D:?jϹ?n^?[4E?B "??9AL?JfC?8H?& ?h?+%?/?niXi?.*@Ua?1X?2?n0?{-u?qzw?g$+{?\z|?P]t9=E?B`x?44q|H?':,?ft? ϑb>e >ͩ>≔&o>GD>{oe>Q2>;i>fe>WIF>&a>N)c-> *N %Q>w>}$>Hz3f>#>߇x>P=>;FH>g. 5> Y>I9>ة[>Jj8>1P>NOVT?j%p??@H?$}*H?0]?=l?I{~ ?U vT?a1?mOޖ?xI ?O?87p!?Ԕ4p?mo?18?`@-w?2?e=?:bH[?o^'?8gR? [?lE:?C ?ƙ|?rO? _?b}(G?~f{?J@͠A?ua2?ke]?.&jMp?3[YN?}iY?|r?#TB?X?֓?t QU?kݿ? Hs?ĐN~?܃>h?p? k?7h? km67?[tn?0Ԫ?{TQڪ?zy⟲^?},R?j-?9ǡ?̨?$T?z̈́v?W?cH>?iy7??IӤ?~,y.? 8J*?U?C:?JԻl?d8T?IR?U{?|^?r]n#h6?gk@ѿ?\@?PpG;?B 8Zy?4*??'?eEUl>ߓ)P> ݃9>-P>4>mv>Qs_>C `_^>w)>O2o>c딴>>R>GGS>:C>jrUp>ő>'ИL>9/=N>j3H6>>d\n>K4\>C5\>nXn>O?`?FN ?1Dp?$q?/*:=?81$?C33-|?O O{?YC)-)X?dޓQ?qR8vND?|# { ?:14?::: f?5y?Gb?=V>s>ƥ >ႜ>Wܜc2>_;>(˴>Zӽ>VN>~ȹ>OC> >">%Q>qKt>c>'q-F>.ךb>>΂ dx>_s>ݦ.L>RXv>rp>9F?m:?xф??0&V?pcWt?L/9]?Z?eˬBX?V\9,?}?q'TCe?C*{?B0.^?1#|? Ń?(X;?yK+? w5?ae@T_?|.(h78?v;Z?sQW?sio?w_k?~?, [.?r?[MI&?~?Mi?=c"G?'X?5<2E?lp8?)m?t/?tz??_3u>?_?6E_?TG@?{_c?}l8h?wKV?uxNݚ?vr:I?zy?? dbw?!$2f?4) e?џS#? b?T?\?Ή?9(~? L˟?8?X?ˍR?ZLZ?B U?Y`?D ?v5zsC?lۘT?b}$?V{U?J>V?=%{r?0q?#oZ?P&U?x=R>K.g^>%c->˿O>dfe>ð>]?~>W !> I>)v>:p ><[>qI>Tl]>>d 8+%>,>@K9J>š֜*>83>mSȵ>y`>w0al> x> ?#o?}3 ?5?"b[?*h?2ݣ?:?$Ղ ?AH b?H׌I?Qg ?Z;BS?d_2Ջj?phJV_?zp/?g+Ѡ?QS?_Ʒ?Sxڜ?C^W0?~Vw2 ?x?%g$Aż?f)J?(g%?J?=[?}?bކ?xS?K])%@?}&*?wAZ%?t?uLL6?xÕ?x- i9? E?lx:?OlmKd?Dzt?1M1S??R=,?XQAx?7L?C@e? b?F?̉:6&?{\}?kzf@?Y'??.n?>q+?{D%J% ?z$?|ھgH?17?}^q? L?9#X?RoZ{t?uUM?%?5?Ț6t?&;*]?\^nG\?*؇ ?5?~]?;S?lY?Nҕ?y0a/?pv?fF?\>܈?QIZlo?D?7eL?+aX? bMٓ? ^?B!P'>/Y%x>*%N>d\lK>Kwq6#t>®*}>V!EK>J`R>5~0f>`>-ax> ~M >QX>&>L?4>䟻> 1>YΛ>̪U>MQ,>=>qFx>R>!`?R]?Ѥl?hۥ,?#O 犼?,3ci?5Pz0=?>$37B?EM{?M7?TÕ?]-nn2?dOR?mhj?vk?oު[\?z7??tSb? DE~?h_J0?8?ҌIW?|?MlO?*?y|?b̤yd??/?lu?%?ڪ??&Os?{X誨h+?zOkQ?|5NI?V&Oy?l?F۟?s%?|uw ? ?mx5?:iO"?v*V?s?WӺ?0q%0?%acQ ?<)?$?dF=u_?-?_NO?Q;?!G4?^&xC?I;BT?|IM;?S?oL?)V?uu骗?xpyĺ?qCCq?g?_e?TPet?IKw?>v,?2J7?%|?ϔ? ّV>fV>n+>zξ>hs>8AQW>n>T9>oTSz>J;j>S5_>)z>D>uXUX> >4>>5N>4!QU*>^O= >py>)xE>s>cRnѾ>lFX? 6M=?^B)J?"g?-"n?62R?AN95S06?Ie[mN?R/GeX?YB%gH?bU9B?iuE?q?xm[?e?W =4?$|D?ct??$dǎ?0?H&?cՇ&?Q?t?ȁؘ~?QlU?/št?#â\?ɡy?F8?I[+?l A?ee>F? yd2b?s[3?Y6?@o?(?X;Xڿ?.h$? |8;H?1_8?1/Vx?䃭["?!H?mH?k:ab?=?,4C+?޲?#?ِ\? Y(??m?lp?ke?3? Kc?fL:]?H}o? C:?+U?aJA?n?g?xht?ҍ?{Ym?k? &泾?ˑ"l?~= W?uC>}?o &~?eXbg?^=];n?T?KqD8?At2~?5{CGB?*w~? bƌ?qfF8?B5>aYY>0_>XB>ԌC6>B#>gC>k&c>z>|S@>B1>tv> 3N@>tv?I>B1ē>|S>z[>k>h'&>B#>ԌC!>XB>0_>aT?B?qfF,? bƴ?*w~?5{CGT?At2?KqD.?T?^=];?eXbg?o &~?uC>?~= O?ˑ"f? &泼?k?{Yr?ҍ?xht?g?n?aJ@?+U? C:?H}k?fL:V? Kc?3?ke?lp??m? Y&?ِ`?#?޳?,4C.?=?k:ab?mF?!H?䃭[#?1/Vx?mx4? |8;F?.h$?X;Xڼ?(?@o?Y6?s[3? yd2_?ee>C?l A?I[/?F9?ɡy?#â\?/šx?QlU?ȁؘ?t?S?cՇ&?H&?0?$dǍ??ct?$|@?W =+?e?xm^?q?iuE?bU9B?YB%g?R/Ge?Ie[mF?AN95S0>?62I?-"J?"gN?^B)? 6M9V>lF^<>cRn >s\>)xH>py]>^O=>4!QT>5>>4M>">uXdk>>)zè>S5\>JoTTNz>T>n>8A^>hƤ>zξ>nu>a? ّ?ϖ?%|r?2J7Y?>v-?IKw?TPet?_e?g?qCCy?xpyĺ?uu骗?)V?oK?>S?Y?q͙?w:?|4L?:.Y?\? g?Jb?T?+`5?$374?5Pz0=?,3ci?#O 犻?hۥ.?Ѧ?RY>!`>R>qF҆>=>M>̪>YÃ> 1 >m>L?!>&>QYl>  >-ayI>>5~1kw>J>V!E>®*>Kwq6,C>d\|>*%A>/Y*F?B!M}? ^? bMٔ.?+a(?7e?D$?QIZlo?\>܈?fF?pv?y0a/?Nҕ?lY?;S?~]?5?*؇ ?\^nG^?&;*[?Ț6u?5?%?uUK?RoZ{t?9#W? L?}^q?19?|ھgq+??.n?Y'?kzfD?{\~?̉:6)?F? b?C@b?7L?XQAx??R=.?=c"G?Dzt?OlmKd?lx:? E?x- i:?xÕ?uLL6?t?wAZ%?}&*?K])%D?xW?bވ?}?=[?J?(g%?f)J?%g$Aź?x?~Vw2?C^W/?Sxڜ?_Ʋ?QP?g+ї?zp/?phJVQ?d_2Ջ?Z;BS?Qg ?H׌I?AH F?:?$Ձ8?2ݣ?*h?"b[?5F?}4X?#⍻>B> x/>w0ZA>y^>mSȼ>8z>š֜z>@K>+v>d 8v>>Tm>qI9><8>:pa@>)젃> I>Wz>]?l?>ð>df>˿]>%c>K.g?x:?P&U?#oZ?0q?=%{?J>V?V{U?b}$?lۘT?v5zsQ?D ?YZ?B R?ZLW?ˍR?8?V? Lˠ?9(~?Ήȿ?[?T? b?џS#?4) f?!$2d? dbt??zy?vr:I?uxNݚt?wK\?}l8h?{_c?TG@?6E`?_?_3u??tz??t/?)k?lp8?5<2G?'X?P_ă?Mi?~?[MI&?r?~?, [*?w_k?sio?sQW?v;Z?|.(h70?ae@T_? w5?yK+?(X;? Ń?1#|?B0.^?C*{?q'TCf?}?V\9+?eˬBX?Z?L/9`?pcWt?0&V?xфC?m,?as7>T?U6WV2?K70?B~?9#sr?29!?)fCX?!X?PHf?}zM?g[ >AD>r僌>RX>ݦ.<>_s->΂ d>M>.ך]j>'q,>}>qLgV>%f>k> >O>~M >VM>Zӽq>( >_<>WܜwC>ႜ~>ƥ>s>=Vc? Lr®?;YI?%a?2v«?@πPD?N~?Zqc?eb ?qL?zLk?Z!V?<;?D$?zAh?`x?nYuxt0?p?t{?FB?A?x?Ve??bD`_?T'?.?Hp~?,?)U?;Hj ?{<?vj?uu*`e?w}[J?}֠{{?o7"?PgU?Bv ? o?,?+?d:z[?: 3t?e"c(?F_?4-?X?*{p?`W?%~$?k-霟?ki?|Gaܐf?w™6s?w c%?x}?}p:c?FZA?ZO?y:?Vy?Jx#?̷?딌?8ګz?dx?Y&L?z͗/?O>nXv`>C5~>KB>d\e> >j3HE>9/=+>'Й">ő>jrS>:}>GGS>>>c1i>O >w)*>C ` 9>Qs/>mvr>>-`;> ݃;>)\z>ߓ6d>EUl`? 思e?e1?'?4*?h?B 8Zyc?PpGH?\@?gk@ѿ?r]n#h6?|j?Uy?IR?d8T?JԻl ?C:?U? 8J*?~,y0?IӤ??iy7?cH>?W?z̈́v?$T?̨?9ǣ?j3?},R?zy⟲U?{TQڪ?0ԥ?[ti? km60?7h? k?p?܃>f?ĐN~? Hs?kݿ?t QU?֓?,yk ?#T@?|u?}iY?3[YO?.&jMw?ke]?ua2?J@͠6?~f{ ?b}(G? _?rO?ƙ|?C ?lE:? [?8gN?o^'?:bHX?e=?2?`@-y?18?mo?Ԕ4s?87p!?O?xI ?mOި?a1?U vT?I{~ p?=l?0]t?$}*Hp?@8??j%>NOV[>1Z0>Jj3@>ة[p>I9> Z>g. QT>;FG7L>Pp>߆k>#T>Hy>}$H>w(> *N >N)ʬ>&c>WI;>fen^>;i_d>Q>{o,>GBz>≔&>ͩt>e#? ϑ?ft?':,*?44q|?B`=?P]t9=^?\z|?g$+{?qzz?{-?n0?2?1T?.*@Ua?niXi?/?+%?h?& ?8I?JfC?9AN??B $?[4I?n^?jϹ?D:?|? ?V ?&o? `u=??%?Nhq=?}tf?aԳЙ?jr2+?Ȼg?xDn?ύd?wv ?OFC?"ըv? Q? ?M?EY0d?VnR? [W?{?ǭ@Ó?K*?@%1%?ǵ?jw%?B?;H,?n?B ?=P~g?Y+zB?F/{]Z?SN?oY? ?a"q?T[?""F?:?r?TDK z?w,sF?k2Y?`\#m6?RtG4?DZSKT?6@?(v)P?q(0?2?/tX>UZ>:{>ĭ#<8>Җ>Evv>۸ >a*>j rD>ϗɰ>.,>vLt >]>4>-̲ >ȉb> >۳>>`J>*-ڐ>ru1A >YT>-R>.1>3M>jh^>ju>? %K?6m?&%,5"?3,ĵb?@KLj?ND?Z-ޯ?e￐?p (w?x oQ?"R?hqoB?h?Dز?fq |?u?:Lrq?nR?f 7?YH?chvk?^ 7 ?dߞO?譓S'?ͳ??(?1?*Y1?{2?Dy?Ms?jl9?:N^?L%*z'?+{???'?k{?O?މͷV?,e|???/^?澜 -?<`?uO%?QSiT? \VY?]?ȟB?nw?loF?_?SA?Wџ+?f"Z?ʸ˘??6B?z?Xx{Xn?ș?7ģj6?xn{?d4J?A8?2 +?,c?D0J?O)?jT?bV.=?p|?u~?h++?[Įȸ?MT4u?>ϼ`?0ME?" t?D=H?gYj>T4@> >]H >>6l4X>x>mc>Q_@>v[+>/Qx>.o+!>?E'>wi>fo> ߎVb> )>?>2JW>{v>HN>rC5>([i>ҤE>)ь>d~g?z/a?AU/n*?$ c?1> WbI?=ۘ?J?@1?VvԪ?aJ"\ ?k?sF&-L?|I?nX?vw?c%,?<{FE?cbC?ElbF?S0? I?th0? ?FE\P?͔],?}֒>? z?I8?;YU?bk?I87?a?;#T?>8$?؄0?g ~?Q?P˓?fm?J-K?^?-?a}R?B\G??B%m?,?9 y?\E??BQy~?*?1AT?Vڀt?yw?{ "ʟm?Ej??aE1?c@?/Kצ?}X{?~ 9?x1=?$?ר?^?Rb?WoT?q~?ߚYیS? j?;tM?GA?{I?}brڋ?DR?S?/1?Ed`v?rL?dBP?UCtI?E5?6; ćP?'_?Zx?7_>u.>~.$0>NCy>j|F>,'߀>Vu>@ּX>rB7@>U~Vr(>d>1=>d)P>#%i1>D7>xJO>> ͺ4e>No]N(> ^>>uxO>Pg!ث>2>ܖp>j>=T?pR?So?!@Z?-L?9#0v[:?E@S25?R1!4?]%lfR?e'D?owZ?v tI?}e??v?@geE?q\??5w?zY?$?mD?o`?{ɵI?44q?g3u?N8:u?k ?Ww?2b?ՙ;>?bT{?KYlk?3?O}?&̏?U ?rS;v{?#Bl@?ڹt?e7YT?=غNV?jt?l "?3w/?ȳ?.?r9[?~OT?Jm?6~?'?GJe?I?n?8? y.?}aܢ?xd΁h?v 5?wT+%?|K?ʛ?9?ŧQj2?##B??7?,an?EX?'܂??P\|?I\?$̘.?|sc\?y\pP?z? ?lsf?] ̀j$?L?=?.Hwm?. H?o>|,>A3>ې>2:w>Cx>;Kt>C8>>y>a&>o%J)>>x48z>?|>U>) >b->o">@qD>v>ׇگ,>5^C>s~>7 $>ڟ7?gE?f6?_3E?(x ₘ?4r?b(1?]ŏ?iý]?Z ?Rv?ӱ%K?M#^c?}8?yS]?y=}x?}JH?4ɛP?%Fc? )W?Rv?5 TQ+?INmډ?|`|?$`*?ID?AF?o'L%?LpA?̢?Hݿ?+k`?Pl?Zo gwH?|=d^?vS?s}=?t'6?x9ܺ?lFl?E~?V U&?kV?]%? ??uV?L ?N1?V?*~?{;?b? ̦?Jɞh?r4?bk4?Rs|[ 2?B%*ev?2|F?#4?^?$*p>P C{0>"(>M>ETq͏H>ĝ>$> ޽>>I|>gz>|qfl>֘V>YW>Q4)>z> ?~ >S>~}*>U!x>Q7rw>>O*;>04$>,ms>,T>KbQ>プ5iZ> ҡ>Jۇx? ,?tۋ ?#I~?0zǨ?:.?EH?QAKB?[Fm|?e Ѳ?n|?ut)O?|.rx?0Mk?gҏ?>5W|?U?Dj??Xa?>P[?ȉ-?]$?o@x?%kۻ:?Q1?,b}?H&h]?4|?9?T?}J`?,ǡJj?'2P?|8K? l>AR<>0U[>@^>Ӕz> Af$>!m҆> g>u`k>2 =>A>lB>"+x"U>#̥M><#pj>u5>SQ> :1>,@@ >vU_> YP>:.>ű 9c>і(v>> |>lG/QD>`d3?uG9U0?L?d?*09;?5C=s1?A 8 Ԑ ?KiNR?V1?a=?kc֬?t P ?|J[V??LF?Sz?#R?A4? (|?Ea G?n 図?ԹY5?Rs?Z ?v? M?7??|~?C>H?F ^?LD F?R>Mz?7b7?|>7~>D33>LGЯ2>̈́g}@>-:>>ʊ+>4>F0>|ba>]7&>){+>> Y>T>>~>C>Hh>xw)U>܇>#uR]>p#>3ԋ> U \>hV!>qsJ>q? f9?mX?p':?$r%'?0j]u\?;hb^?Fx/i?ST|=5n?`wu?j Mh?t3&7}~?sں?=)46?e׭\?K#!%?XD;?b?AN?5+d?S?ө? ;Co?NU?_s:?oD?[J[ 6?l1QU? KS?pY&R?e9q*? - ?Qg'0?K7ڃ?NU?}I.?}x?oLM?{*?'-!?B?A?}?bR~?RH?5a?_?k\?x?X$?hYa?u8֞?I}u?^ȕ?|w??ǫb?yz!?j?Oc???]i?UG?se!?ќ5Rz?=繀?$J?Ci?Qu?AqQ?( ? YR?W?X?x\?je_(^?[xPr?Lؒ$ ?>V@ N?0ys!8?! .?/&A?u\w*p>dp#.>"?Z> y>RȲ6>,иl:>3t-Qg>V,U6>o7>=P85>2k>]#>bR>QH>ԝZ>੎>}>\u>ۿۼ2>w[F&>.z> )n>yS]>+|}>h>):>*Jj?H?hc?Y?+045?77G?C "?QW}w?^KlM^t?ji퀾?v^G?cB&?a?%Xm? ~?*?'/|?1?l4? $}?2:t=?{P?~?b?%!?Mۚ#?s!??1 v?JDc?^z(?3>6*? _gA?<ֽ??m˶?vt?$Ub?{Ν@?CY?"΁l?;|uv?uж?Hv?R;?WK7?Z?%H? 70?XMA?t+h?w ȮL?$=紨>ߡ> c9>#l0>°2`r>(DBI>oVj>QϿVY8>?]L{>ǣ>>h۷>G >Fƙ>G<>h?D>ǣ1>?]N>QϿX?>oVƛ>(D>°2`>>#l0j> c%><׼>ߜp>=H??x^>Q?"fb?1- 5]?=+r\H?JG",?X4D?fmh~I?t)d?z! ?7JSV?J4"`?5yW?n)j?ؼ? ?^~?%o_?"DĂ6?R;? N?-]V?*B?R`??./$ݣ9?45W?&(J?MD0?ic֍?$>ec>ߍ^>& >;_>.L >EO>X>+Q>rtHS>}q>*M4>Cgl>ؠs>JQa>4L0>Yh><>n> s>16>%$N>i貆&>ޚ(r&>Ɯkp>#1?xUT?[C?+j?-Me?:p•?Hj?Wp:z?gh%EH?u%b?;zi)?}*ɯ?|b9?0,4 ?$?@`??zA:?qmt?e!?۩p/? "=??YO?!?4j[B?o=oN?1k?}/]g?|V9?} c?En?z(??8V?=ܢP? ?Afq?~2ZP?O[Bh?J*?wz>f?(sR?"c?讹L?IXj?V??mҳ7?^%?z41?wH/w=?wt?|@! !??Ƶ7_K?XV4?U.Ew?|DYZ?kV"9?}?1rg?Ob?HT??:? ^?ИΑ?;j'?)cV?ʐl?GfXf?,U?]°?wo?n?c{")?X 4?Ma<@?B ś;?7;6?,S"JV@? ̟מ?f٤?G<(>[(f>B78/>x[)>װ¨>,<~>I]`P>r?>v!6>oνz_>aHtH>R&>!夘>P*>Tপ>pG,>a8>Z'V>VRD>Y]{Z><>^䊮d>~j>|2>( M:>1Fc>ܞ>#? ;ly{?]ֲKl^?*`r$?8MEXI?F״Hx?VٚGW?gA?vd?[L z?f? ?vq!?5 ?>[a~?=8?N ?0%*S?IF}m ;?V.sO?Œ%?|"69?u?,_?l<?{$ u!?w=4?vԎN ?w{X0?}P4?9޹|?jM?!k?I1?n}?tE:?'?K?>?H߮?NCf?[=?k??%6(U??ӂ?x,Z6?sbo?rC?u?{BM?*?7 ?:Tq?9F.G?m%?K="?$Ԧ? -eɡ?+:?Φ*?ەQK?*5?l?81?%Fi?=M? q\W? g>YvH>ꔪ[]>\˥>šAo>Atפ>ݍ ">$j>44\I>#ǩ<2>C/M>P>r֮h}>ӭ>_>Rb'>3,>~'ov>QCr}>@q>|iG>9(yz>ǧ18 `>]0 1>Wb->uQn>0%6Yd?]]?!w?&:?5&l?D?TA?e&V?t.?/^ꬵ?RڡL?[?x[<? R?i6e.?dϲB?-;>x?Ȧ?ĺ6b?#;?u^{b]?i9[^?x"?UVm?zoR۳?tFL?qYp?qä!,?uq U;?}Ib*?A?V M?M^&+?Ӕ?=v?_g"?A?k_?zn??v- ? ~ta?ȑ?OCZ?>xL]>ʚc>PZ >f>qRJ>ghU0>|*>#ؕF>w÷>ag>W)AV> 5R>zFd>ĎR>s.>W+>?qV>}1bD>pCf>h>eL>Zz`(>~O`>{\AN>>&G ?"x`?0]8?#BgX=X?2 L?Aڱ?Qyg(S>q>r r>_k%>Y6F>\h>{;>b7>i#>MX*>b/>*!B>þGD>-ݔ5>YSj>dK>0YJ>]y%>>,ضX>E >˿ɚwx>4;>/>ވtgA>C? ךVp?&ա8?.J`p?=r8,?MR ?]4 B?l67?zu,?踠Ou?ݒ??0:$?S?2`_/?I8a?âf?X?3@oG?s>?<&?f3?UӕZ?|-?uAl7?rRwX?rVz?u _?|רk?C?Zy?nX?ҡ\C?uX/6?ˈ#?Bs$?=P-?7?%?dx?W)?z?Ʌ`9 ?Zj?G9}?V2 ?\"Il?{9I\@?zba?}^:X?|n:G?ȶ"2?aL^?3r?p{?WU?،f)?'."}?'B?t???ESy?-Er?¹?TX?Mf7?Sv]?Gg?Ǭ?h2)?|MSW?uA͓?o+ ?f` P?_t ?U-F8$?K 8?@SH ?4¿?)qV?#H3?SA? A>lN>Tu$>H~>r0~`>1!T>_D>!>4Ξ>t>Q5>)ME>JrX>Vf>r&S`2>@> #Z>8H> $W>ƣL>R<4>BVF@>|P>kI>l%)h>0 ?0>j?%[p?JKH?'qz#?6|rD?FnP?V%?d:?so^S[?4?45d?}H?>3?]:?Ը{ 3?Mm?}ub`??3I?#U&l?WD1?|"%7?z?՛9(?Eu?w&?|^݆?N+s?b}?Ea>y?%d?3Yk?/?8?-k?ct?_6?,?zI?&M ?J\?nUC?S\u?z|k?3?!J:? NR?lwj?;ZM?\_?EUU?QYv??Jk7i?N):+/?B7* ?O?zOJ;{?x T?IwmF?d84?h ?6Ԫ?ɜ?{TP?sՔl?l(}ڹ?cmڎ>f>BD>Ц!:5>WOdU>Kn9>(傮>egF>Ёc>3>IWp> w՚>U7>g)s?>`Qh2>pZ>@c>7S:>%K>5t0>ϿE8>1>֮U$> Xnp>!TQZb>Q??KxA?}Ő?!ԊՐ?0F?@+JX?Oo4 O?]l|?jVZ?w+_?ce?f)?? މ2?XFE?ˢdJ?j {?ߘ8?Zm~?6fX?Gk?ZM?>'^X?#ZW??D?=-\?C $??xS?q#xY?g"?^q9?R?F#et?;,!cn?0qPO?#I!dc?\6=n?(JI>8\>p5>x}>1 ՞>sznj>vB5 >zE>ZKn>wH}>>"t>۬S>+$>T<~>V>GX>b,>vۜ}.>s>vY >y|0>Fo0>ҳ-0>6 *>X!C>/:?CdL?ȝ"<?E_8?(0?6+'L?EsQ$?S0 ?a{?ngZ?z z*?L* ?%??Zz?yC~?Zo?ɍiU_?YJ?{jљ?{M D?~" ?9c?v؏?% 1~?/O#d0? p;?sY?S4c?R$M?28??_LW?%Ib?vT?l?i:1b?5w?wW?~zm?c\?~=o#?{x.?|Z\u?D;?Ajk?JU`> ?Ob6?!=#q>kx^>Au%!*\>  >һ">{WqM?>Uu>ÄI>zf!=^>ڀr>S$Rd>f A>(_SD>Ԩu>w "~?>6Ӟ>3 >[Z#>Ok>0Uf->v>)xd>C1>fI>klTx>DG>հ?1&ę? c:H?92H?#{g`6X>?D}ȸ>*>`>#>j>OnXfI>S \$>Ü,>~c>k Dn >uq>@A7>4h>n>>]\k>?4'cp> Ӆ>#>>XW>ʐ!]>Գ!F>߫.W\X>Q>hgo>"W?g?}?v ?#[>ŨP?-B);?76b{Ѿ9s> !X>yRw>mt> hG]>rS>R.ُ>DR>m Ո>~>l>o'r>(h>};5>[`>P ><.O>jW>*7 M>Ł >ѷܽ >*0L>`>_0d?5l? -Ӌp?D" f? F*?'Գ$?06|?8<P֯?BEi?L1Fל?W[2?cR?p!F?|T/?RHN?:?WE'\?J23?# ?P1 !?hKg?|˷?UH؇?k??S]?.;~?0$?n|?}AyS> ε_> a>ϻ?>fY>Z>v&>w>^>a$Fx>7ȮJ>W.>Sڿ>BG> >uh^>R6sa>˥{x>)Ѓ>xq>؋8>7*>Q??M|? 9L?^Ir? ۓ?'_m'?0 j?7 Q??̯??Fg$?Q ?Zsw_?e_`i?rr6?~ s?;aO?TV?.(?鰓?S[!Qc?$&9?|j?#jLK?+բ}?֒ 6/?nr=?x8?% oX?HJ$?e!?}4p?uC*?qBSyH?p ?r>J?xaYh?耻?E?,Q1a?%Qe? h?3.X#?dSb?L&v?fĢx?4?;'hd?F?|?rEF?0=.?6-?| ?F(?vևM+x?t=$X?upb?yZ?J?HM??%?'a/?0[?Qh|?-rDR?zq>?|R_?:?|*+?RPol?|0f?aB?fC?>ܼ?|Gy1?s)瘊N?i+1?`M?TB?J_};|?@16?3%S.[?(%^}\?*@n????YL> 1:>r-O >V4F>cz>93<>>Fc>x>멕C>rxP>*63>" *>2$v`@>!G>M@6>4EԨ>"|g>?ی>ll>fo>ᆽM%><|>]'3?qs~#? BFj?{%? ?)#?2P_c?9mF?A .?H;]?QM?ZG\$\?c?n2{?xPFRǞ?'_?TMP?޸zX?co\?F6?ĺlh?[v6Y?|"/E?"?QЌM?jZκ?k?AD?y?,^?(ڲ? >k?|{=T?vb?t#?uH̲?yZs`?s+\? ؠ=c`?,?\0~?z ?+:#Ȕ?\?zzE?f ?F?;ė?15V ?,^? QK?d2j?UK~?~?謊&?|<?ysK?zOt)sQ?~Rٷh?EF+Pt?D5H?ةÿ?\$?xu!?_,?wMq?0'H`h?0O?U?j\?uz?5?j^0?6}8?j6?W7dx?NF?C[48?8&L?/S?#ȟ?.'Z?f{'>DT |4L>Kl>v8>בN>d >2o>` >,6>zVU>!ab>b7>^@ i>tL;> ᘋE>Λ>pkJ>ZM. >>|i%>̓Q֏z>ږI>1>rDqU>v?"˭E?$l? i ?)2Ek?3,q?<B侷?C ?L1 h0?TI ?^O ~?f&2?p6>SH?x`)_&'?NB?n?p>?xjM?:>i? &?M`tQR?VRyJ?}Ț?!O?$ti?jm?x?vO?uqg`?ئ?ip0?{Ҡs5)?y*p5?zR嵾?/ n?Ƚ?~<ɶ?lE@??E5?!\d2H?y"x-?gtCF?*ũ?T>?T<?/&Q?.{U?bn@?DC3Bu\?u!/?|?oϡ?}}?{o>o?}DHE?Qw'c?qeK?Q\ʫ?H?]8` "?[?/Q?SDs?T?LVE?E"? O? ?o-?ҷH2?N?{: ?{]~?r%~?ic t?a:LJ?V2M?Nξc?EZ86?< N?2,>?&i@S?.8Y?:t!?qb> >Z>Aw F>Xl>R>wN>Pfh>nl-w>W#Sr>Oѫ]H>ڈ%N>bR>ڈѱL>OѬ/j>W#>nmi>PN >w>>Xfu>Aw ->Z^> ?qb?:t?.8?&i@S?2,?< ?EZ8:?Nο?V2MÃ?a:Lg?ic x?r%?{]~?{: ?N?ҷH2?o.? ? O?E"?LVD?T?SDt?/Q?[?]8` "?H?Q\ʫ?qeK?Qw'^?}DHE?{o>m?}?oϡ?|?u!/?DC3Bu]?bnB?.{U?/&R?T<?T>?\?gtCF?y"x-?!\d2F?E7?lE@;?~<ɶ?Ƚ?/ n?zR嵾?y*p5?{Ҡs5)?ip0?ئ?uqg`?vO?x?jr?$ti?!N?}Ț?VRyH?M`tQR? &?:>i?xjM?p>?h?NB?x`)_&?p6>SR?f&2?^O ~?TH?L1 hT?C ?<B侰?3,q,?)2ElV? i ?$k?"˴j>v?>rDq>1>ږ_>̓Q֏m.>|i>v>ZM.Kx>pkHX|>!> r>tL=>^@ i>b7>!ac">zWz>,6V>`x>2>`>d9>בNr>v8x>Kk>DT |5^?f{'>?.' ?#Ƞ?/S?8&*?C[4&?NF?W7dxj?a{?j!͛4?sTy?} ' ?j6<_?6}8?j^0?5?u|?j\?T?0N?0'H`f?wMq?_,?xu!?\$}?ةÿ?D5H?EF+Pn?~Rٷn?zOt)sG?ysK?|<?~?謊'?UK|?d2f? QL?,^?15V!?;ė?H?f ?zzE?3.X#?+:#Ȓ?z ?\0~?,? ؠ=cY?s+\?yZs`?uH̲?t#?vg?|{=T? >k?(ڴ?y?,^?AD?k?jZκ?QЌL?"?|"/D?[v6W?ĺli?F6?co\?޸zV?TMP?'_?xPFRǞ?n2|?c?ZG\$>?QM?H;]C?A?9mE{?2P_c?)#],,><|~>ᆽM0g>fކ->lIP>?J>"|_u>4EM<>M@au>!GFj>2$v_>"P>*6>rx[>멕7>xݐ>G>Z>93>c\)>V4">r-O> 1:*??YN??c?*@?(%^}$?3%S.,?@16?J_};g?TB?`M?i+1?s)瘊N?|Gy1?>ܼ?f@?aB?|0e?RPol?|*+?:?|R_?zqJ ?p ?qBSy??uC-?}4p?e!?HJ&?% oZ?x8?nrQP>7*5>؋80>x>)>˥{{>R6saX>u> n>BG(>SH>W04>75>a$DJ>c>w8>w">Za>f}d>ϻ?v> a Z> ε>AyS?R1$?BW=D? T$?,?7716?C-T?P$?Z&o7o?dB@D?pDU?x=?@F?fvgk?ڏe$? ;?F%qE?e!?hY*-?T?HoL?;|#?sOz?U_'n ?sqg??2$?!?5Un?zG?te솪?qDHx?qх_?uj2?}K4?2lyu?4$%?{??2A 8?`ל?vBf?GpBxR??|+?j*&?Ƕ,??d;-?4o?3;W?@ ??9_?vs%v?q_s[̻?o$ ?pU?tP6F?}_0d>` >*0v>ܽ >ѷŁ >*7 zJ>j*>P >[=>}E>'s>o">l>|bV>m >DS>R.s >rU> hGv>m>yGk> >{Ѿ9*?VB7?3?"&l8?0,U?;oy?FwY?S\lE?_h@(_E?h\?s$ ?|<|?vR?.$C??:B't?}Y?BXl?ү+?p"? ? /K?N]]K?ʑ?sK?Ɋ/?*6?#:WN?{7n Q?t"[#G?q?r?u*g?~5[{??#C?Al??L`M?Ke?xH5?=Ux??7?ჿ?]?98?c\?h'?5 ?n?!j'? ?{_]?u"{c?r{D|(o?r|Px?u]#?|6 ",?앥?TP'L? ?aUB?z.dJ?H)6? g8??N4?ee?Ȼz?Ѻ,v?7XYL?[z?~L]Z?Lj0?s?g/Q?[]wS?PW0?CC?76a?-B)8?#[>Ŧ?v p?~,?f>"W>hgn>Q8>߫.Ws>Գ!H>ʐ!>XW>>#> >?4'>]\*>n=]>4h>@A7>uqn>k B>ɽl>ÜS>S :>OnX4>jѮ>`>>*">?D}>`5? [?Ti\?$L?1.J?d?<׎?H'6e?TQ@D?`*Z4?jEfGp!?t(U'?~nqJ?b?u~WY?0#/F?m41?|?- ?^?$R?.b?7i??\? ?fb?ӯT?3-F?cp?{9@Bљ?va0c?uuD?wȿi?~W×?~Fс?j*s?'?i?I:?zn%?bP?IU ?g??28?S?qԫ)8?VM8?2t? 1T?m)=?LSֶy?ys^?wHIKR?w aw?{?Hi-I?tPbH?LaN?oe?xޛ?K鈡#?rr8?-F?N~Z?Hm?(I0>DG`>klv>fI>C18>)xt>v>0Uf-4>Oj>[Z>3wd>6Ӝl>w >Ԩ؇>(_>f 1>S$W>ڀ7i>zf!i>ÄJr >V>{WqL>һ"> >Au%!>kx\?!=" ?Ob|?$>>?1Ej? z*?\4}L?c'?)9?%H?5J+d?y?{?u ?7$#?z/

    e,;:hO4\OK9GEuM Y ਹw[)h`urh CFa}kM~uƼf(^EX!s`$h'}ۘc㤲r U꧃-RMVtҦ2>Tï1b Vܕ7g"|7#p.촋SՐDv$$C#Bm-s .= JrVӼPp ]K#ai;V<Ӆ}&@B1e}3lN\ 9$#='Y..DwnX"^}:ҬPA/K4dk7}өar/(,zөo-Y^3V}bƗ`PczS/2%m+ث׺ :C{L3&fI NsY詞mv;[gVB0PcE5gg0.j aVWs!!/*r`{w&cD{kx Wu4ߙ"W].paCj5&fFd%Ëa`GIf 'olU2`qLFC[N?'!*xgʗ^ouA. ?r| R k}7"_hvIwӋnuK]:UPl|_b4@9Ih`;voپ7 c$oe9ݷm rKH*[3gґuv7B<6d :0vO<s\ɝ}ż#($=VK{C\1~Ggdѭkɚqqb4t9W+8ꤶEai}=~;|z:nvl0\ 4x)_Ip-|S{>"r_oT:J~eyy\^"'Y@b%פnݚ7h=߄Aq 顚>ZBg^8˂8Hw.2 &s 9[SukߪU8S޾S?}wy*E>a*"{9mo>zʐE@0Ea먓`ʴhbLУ8˴8JF7{8`(jZF1QJc!u!X):[S$^l!>t,V+ȼI" wSJ.7$4$$ HV!2E&+Mu @/=bUҍY&+'%1yZ4,H8-@iVdآE4dcho> Q#:훈v[3gY:( z+ (Z}vNo2@dYY-kՆl͸j,B!JDPz#8ö9jqx7$L赛fiU)IJ4Vb+pxO9s%qZnb;M$eIYճ#J3`Y͟yv$h+zft!2O7MKѠ gI ܉HZ{N4]wz'֬Tp9<厩G30$ B+[bd$WaVAIq9󓝷^ ,ض+0;7F3o9}/~禽OCFI>x} ^UM3pG3dDF֓ץc4 eZ "|dDf$PWuN," <([zXunj,RDc&^@FGu +IVG#5x5_ݸDPC8QY_{rPD=wUUpbuimu\ʊ5F1rcʋ˴戏-J5m)yx#CYV҈a^'yk}#p@(jJɥBWvnGbd<0eCĀdxqrh"vHL&:$Y8sP." ^` 5/%Ig>Z7c8n*"m@L<.~>yy{ĂxeMCל=*b |oͼlm3X] hHnQsnr!*gܬ\jGS}!NRΪ3{~;ΘVq'ٴG^Ʉ oeGN'/7kM9}f]p>c(!*R6ݨYפEe]xҲG5|n.4Om34BV*)~Rc%汶ƽV-ɴrrIw;DXS;yʠ3ex TEpm1{ͭ EDt1y$`Q[TלW܀&SE Щ6,;i ]JFZiË*V} Mo3{B b"YZV]SޭڭT/K ۶HQHT 0]65vTX(@\x" "-8SC߲w8PG){ Hi2 4Z1b+8qˆDYxxx }IV-Af/ZnU ˰ D: P"0Hvtf96i㢰YW~֌l;f+ۓŤL@y'k3"Y&P/,V{[hNz8WP|}BqκQkŠl &#!5λ瑿-wh) `" VAvr/vqēMsS,3h>\ mվcfu:z2`N/X6x51_;θ(KFcV2_aPUΐyǑd{sTeL"cU37=ͧQ9 uqמv޳G[݅ d2qD3wRi7&1DsUy\}(lry®0j3`/{~bhˇ^$yٰ#{|=%;2^':Y ܖȂvq>Vr_Y4'(v0iZz|'zt5xs/QzNk)g.^q_lˇlMKAr-~Yv{';+-e=i7^t>캐ZPu0Ig{텅/"Qfxk>zȉbAK83{{zՇj\wXveɔlx 6A=,Uj9WXA\29JZv |ٲ 1dݒtJ{9ҥ<ۜ<3[N`T6L3x^YVdx )͕B wm'a\AP eٖy4n!llzK'Y>'dY\P䯋&[pÇrʒYm3kSƆйBؽtx`f]xpڦN 5owa3wN}{ٞWH=it"lZ_37c6hW& vU1x-W!}mW6fSLq峼r`Ό1Um˳eʳ(cpw".r ,6H<Ʀ_^W.*39/wCo%ww|2 lRfd!d)7R),͚O< MS/)Q;l5Q22B20:y͙R1"G=K5h~-^ګW>ac"GP쪈!hB-k̻Y1Kp:k޻C"65vI^]y 2D&^6v-E(pq"[͙yvY"fnhhɤk.L; 97n3[F4{Auk+kVXIfCع[("<tᵑ;Y;/7$_ ҽC]&p!y ӨQ=#+N5`rn: #1vH`hrkj;^ճW5R_ C=V `c/:F" kW+tUNX4Ǭv8Wq|4 ŠBa'n'l؍*?:Q:V {(3N@*  }욗]ٻ"^yw5-߭gYWr)nY7 ;Њ9zР0,#6-R},U ]1y/,#6 RlTJݽ Y4}MJnIXQ\!<4ao=I{7,/+ݮmP,ދe외Hi^4o'8}5 ^¼X gi~߯y6`ݷ:{{kVob$s\׻I$:{D[˾է6!&uTo+s$%3|N;JЅ=. AO4pV٩ކo/I{8qyFv=KZhۋ-cIf3 -f"T5AРյkX⫩a/A*֓@È-,t)쓯͜H#sNZ532Zh{ᚳlOmGбyWWɀP;4!7<,ڠYOIa\Xo{.ӑ(F?v (̂{CÕ=LRHc/p] θǝ^1/%CoMm))Զ.h~mQY=q6oʶDΆ`0Tɚ&&\& kḧnXHnuA60!]vbg(OZrlk+-;<_J}ǧ,AU{>s+dwCby& 闢X}RJJ;.Y̡:\|s{EW׮^n+}Ë{}dHzO٩XHL%ӋkfFQ  ʺwÍ& ʪYӵ8ܛ:6冃h:wu' ZnZR8HKv^Ț1p.iBuuvɞ]cO-GgJuGǸgAN\:9KfEՇg"25 NB"nセ|w<=vz'0s}WC3%ɬOJ[ײ`0v&G,.R^,HCigf\chAX"dfV8Ɲ\EwzFɲB5q{Gs㞲rEoF`QC.:)GICΌF:eseSx<5|OʲLjN}yZ%c7vI6ļȭo|*Ԗ ^{O <=F˼`̇D睼s8m=vq|4ePJֵ MCkqAQvHXGm̋76a[E._MY-4Δ@@i ynJs1QM:vW:?=/XLC`IQBKV{pEU7i4ꃠNe|!O$jq~}o=gyxϟ3:Ϙ,Z-,6,URE`9eV(Ph ŋ, ~ nuJ۝|R,:K_B*v??-v-חgۯsm9}oL*]JQ":lO(CR@)KZF[V< ^1Fς 2$@Q eS%xi[i9' @`M{,551yVlܵk7*FcIaG3Xu9b[^r׏'[ZTRdoF{ϓ]G}qY$$^$AZ.J8Tv mX%$rߎu~94.·ј.3f1X89"cB7qh"pTUCL$ΚP2`ݽ)QtT{ˆFA?$%t]q ,>d+$U|ʊAB0wx&,Qxm9D`{rw^h;N[LaZ)bB@̇-;Q!<G,bU[yd{f R(i +Xۃh,pBaCN ^ $|NԢe ɬ0OP56C>}5 Zecv}bL|*KZ?wݾ{wg]ȌXu8_nE?ݷ#cPVLI$s1(0Myx%RG<9RDߩ+r'^5×EO:{N`5H]&AD̀i'و3qU [%`#~yLR #:4_FZZWj^l[PC !$0#N%wupJ_|+R-B)[d^[`ֵef #2<$UT5!6XͶLW6F0\uT`Ǭ;JuX6ڤ6$"ΨF2E~nw /%e@p=eKeUD,)$z}qB]"01fO$4ujZ*0" ŖQ\֭67"4FRR*Zhk_$!PU@o} TTbE xd5Z9/͹jd1׎~ny%(ҝ~N<9|yM{@AME01V+y^ S$~x!dB ;m|yFbi-4]p4b^v#RH;z 7ڽNZ{B,%d$Ih)$! r,X Wx0|`/; wv,^YA{qR.\Ja/-Yt6 r@?{JPeq_e]1э*Fh  h:mʿ !R{igMxrLr׀$HǫNղ+߻]A>oԱV>zUN0~`pIEJ-ՓQE_q-+O("u,R}I׬^*ȲlHk#j+tnwH nIi`g ^;tC}民}ȡx6i2` K)TƱmsp<[:ߨA}3L>]Y9+> ]H35l}^b{k6]5}ޙ gd^DӅXFU [`mb9ۛ/j'k8 w/Fۅ'(]K;ap3Vio0e,uas]WX޻tS X5,[/C`13>F8yݥkm۷1/͈*F,__=z_EAp.]ķyr֫A -~=}^Ƀ^Y]gރ~^t WB @j3q[{Y4_{hP*<:~צm zO=]JyMOT5^!:*7޶eG4xɑFrNI4(9"t/t֎dzũqW*>,'v˾޲ͱPVe'6pW)#yg=NިpZvK<ٲxsr]DǮ;m q-҅Kآnئz*м:(Oef`'E#2gnyځ4%rLR^Aa$ri7x|bYϼQ"Cu:}6Xx+'s=6{ǬhfĦVU*07xg7j֐C?wڸ[Hw qKu4!oXDlձ 50=] CgU+z~Ig0;mI"ηC.8v&T컼}/&6 {4}?|&]u|"stnvKx#uD;qu}ls;{o?Xcy (!p+=p!rXw^^H EkGd筎gh¢'M@i /7Fvz.1ǚPX&9w+sMV%QFa$3nqP/FY};G]s]D>rTpS檑9am"<\-ow-oPny(ZGsQ4r宽[~;:9#jC%G=QӠ?N.s=*zjŘ,JײbOv LHϙ׹o*]tb]>ɖiq+<ƬFU᭍@_짷qI <_+{EE.«w/Rfwk=I-LFq~"̓ޫ4ގ+Fg:*C-=ƒTTCQjzz3x=g9(͙B>iWc^or~CP{{tT`rƵ:Op?&4=ڈlG|rU[ÝyOe$_B5Dνw^e|Vs!jUqn#3V0.qE.3_vz@Y}?lrq«y T2ko9_Z^n{q(4Zgleg7FMkG̈;}ZU9ŃIqj3PqgfꗌǏ^:MgveWN 4-!;L2{ud'K&{<<-=nYlA{͸{D{\4ˁ4IeCLLﮓ[xZx` PkʹJfs[[6+؛1'P-)8/=f%:ie:{K;s1zh9ٖZ`D g_erP(nw $<2^q=m»Z?g+/bwY몶n Yz!m_HyQ>z JNxXdF>(s߷]XpBF 0`bDH0"Ctǀxɗc$u4daAgi{cs(^s>Ї2Npo=߸s§)CjW[/帑ID_.뿕͹~#ԯ,1TTSQ}@Y(9N@1Ilo֓pVE5.n"h#+fFM8ǡ%cЫ40Ugbx}pe64li⚾I|D@D"Ҍ%%Mra`e[pjQ2dˤӟou=UT˿zyR(3ܤb54jTcn^pǖׂyGRCȂ|I&3ö an<5<\ܼA EĉԊ=$Oϻ:9R3aVf8*%VkZ j&nf!QӦGl6u*4"6]sfVʫ Q¶3ns_)8e+' ֫#*|N>Cw:)TFor-sk;DIwBzNrrDPׅT^(ʏ]-HZ4'җSsss;SY HBmF[U|>OB4`*9dmnAg6<~~ T,V@i᳖d "Ȱ)Tly5E3 ~ljucͲ3u8wnV cXVV CW2J>m REP[{*V:0~9̷քi,.k>rq|o!W#vHT@xf6ܱl|9hدwÍ( 5^EPp\:(h]Be35|x{ðxr ,2t<ݢ@Z %Eeьx)MA FaB7M!aCbus\tFg߹_`j@XfD߻;z֯kΰ+Z5F餿QoUXUPPyl.gSEjB4Yh.2E^t!*{u4@p{p`t/ABٯpc"26؜LS/=lXw%{Nq 1~p [ tw^WPґ˾~ϣ QӜzwۮ^}[ V*Mjy$%`9\H5y.`X9҇ t[QxcD ~OJ~& i%J(ؤ&<zy2oJctψ VQv%Z"\ |རۋnn&ǂviy1}yC>"'܁j/TR^M|5ÍukU xˌlxY Q;'ۜjSC]@R "!V$,"b|8EA1upH"bUBn-Bߤ|YjDAn ?B/o&+d[<Ow|"5$OZh/ڇM&;S9=k0"Yg_{`ju!8rĊ34ƣ d`QGREF1KjKĽ ،PX&`8Bkg;At˧"+EHyj!IбUT A9dxib#6ոsY43I'SZИ ma̕WVSlG̋МL0MI'2UK}}~rΰ@'ϐ `qU寕zە4h J^wX]*)wDGmShh)P_Ž []]9_[M7| ^̽e(ϋkpb<0Kfh# ' ޗCu5غxkL:][( 2{1Ti]・Ik_o糼wOLш3Wg/YJku S$1o?<1"^Wu=Nk7׼u&l7c0ToiZ^.t<HrAuid?) ܻ ϼ{Nuss83"pbxƍ̜5?TM#&_ ]݅S1;I,Aܷs^>4bv+֧We=7IT^A\m~4k}I d&r1rο[VśCޫ~yܷa{_k#*A:=gc%YO61k^kyEh׎ٵ}wLDN r:<'c޸˟M{ RbnjfiBo!):GwJysH6u(g3Ҡxk/EbcjH/RViJu7hϒʂ",!'b}J6/4+g)l=!-3uvyp`o, 5gw=FŸz쾻x(5nrOs#vֆm|V6HQn|w-;xZ>#vo>J@ElU޲T9|0:0.mYWns>ӝt89NԹ9cA=zǟPۛS`@}Uʉ754Z)I-wIiT(rqnFe:mxǵnopO˱20T{ҙS*.? CsN, nj w=ȢŹB>c&s{{mا,@EF-Zy?o%sXz_K=촫FH"e<cٺ ~N\혏}-ˣV9䘤͞eqSJr [i{\z2AWR&>5K5iC7F]]D2vPVh7q0Gw*n=Å; ^ku w̍yۜD &"vY5yb EXŐPr ãE5lTo GlISRWq3qٵsU0E8Z)vaKRʧpZ:\n4E>_1wy%ouLћw{^i^)K :ef_?2M*Ͻ98^G-,sZN>óŽĭc\]L:/a0qN* v-ô#xRr uڙ-lsl^j48)~Z.XZ`ъEfc;=\S.;|}=_|wWwz3nˮ9O J\㜮xyQqp{;*o!S!gS㽒 үf8,8by[N<'b'7L,}'îM7/ Le>`ދ,GhE^Z~pN"qtQR)$圍gABj롔ee>&h1镝^›`E=eZ-UgYi(V7B/tԋ0o z bسy#Vf%ȫ8#ceŸ1b[ry:#?J]{}&SkmоQ}A3+XqH]}9;<1x`X'XSTEyp=Su}+ ;긮ؖhQ6\)t w3ӓeE}׵Q~ 1_!M%x%DsҵIv˯Lڶ{ǞgEI5||ԯhкcbF)Y%6u<#MlPuc&h;{=X<ۢgIn:e1H Z_;3_X{Y;f+4;`3κgmcr#\tlN=/-ušuTm5g[췷iXgspYB BA_R=E/'҈*zƮ=3\ެk6)R=<^d;Xfsèʹ._,n>X.6r=޼܂qim3=7EmQL;O9p1=v"t*sۉoNtv,V ur>h[^Y,+N^Nj宷F1\LB]^9UboդAtm!ٳ=LoeN/XjXa[n@ R'j }f~:}*urwҖv:q0M u]yxD=~'Jnnv ;tw0rk{ gD=K0vڙ3yV=UBW?! #샆M,KgIl5̚ڝ+&ۀxjr\J~Ap^2 |,‘kzA.J: [yxk.toXGe G,ـi]fs}ox / "J{H[ޝppśD]z5I g^QX]ݿN{[yD8ƦV1H<38lP/{B܈5UNo_W[ nSsw2W; /hz{nշXO!m9plwTuo%C{FJ_wxFUGxQؠmawLԅ•@Uѱ܈GR 7Fu2'/HԬYӎfѺ0EhkFNѹ]|)ׯۛ&Y pfwT5TsDx Y=f+q\^z.Ih`cRDPɞ1 yy0BgO?#3z{^%)z[sq/klY˜I)} hDm+۲`״l%9 5ǒ^fj(B}Z't}`d{.Q>̎p=`J Ւ{mCy%B<prnإmʤnp-9u>E{}QPgLzd@kr,WUJ[f]^. ^9zr*uf&q_{p+=jz‹|K(Iteћ9B򺏗>eJHBdˡ)c{92yp|!g5/`je+ԧ(017Y.;/qfChA7 Jt)a]hM-ag dTG3ڇ'z,]-i`0Vg } ^`3o3Ӕ7uBki*}竓.Q5z;ye6٦c]5 GNjozTܿX+3M}/4}`7d|\t}/_Df+l3ZD>*lZ{43ՎnЎƙXlQws|zn@/skD#v,aꅟeOriެ`2ץd#@1.{p6{^8L^dv2fr:Z[FV3LW+׼7wƌWr(wGK8J[J [Kq28 nXŝMOnar=O4BqcT"Ӈ,r۾; q<:1zaDB@{ٷ ;|ny3a/xoޖh`#}8wE u. dUyv1}3vA0d/ǫ5ժ3Ir221;nyC1qQݾs41nS9wlɛy|";`>ݺ7=6ϪXiڑR~A0v;onB,pw ^˹(۳`n%6Ɣ໹Z={of2Tm+Rpݰ]:U{DaC>yD9džLa^m@u=D' ~js0۶q${gv>i)+< %T}{ӅɿpspAŽGyPl¹HSDPj޺=_/IfҐaec;^S]_a BRh=dػ6KR͌ٚ=KC2!LUڏ h4o G(OsOLopA{_'hFcƠ'Ǽ7tY{5bo5/n-ۻ56Nu 嘮E)zmPlgj޲>^x(FaX3VX rی{}w+yճ $ EWܮ̲AFo; @"jwH>Ao8Sajo32AѻɋsK+֓9wCp NѹILSnYt _!N>vGb=fx.&xk9VfΉة>K \='л ^ mr,[(O_z=;a|z9$FszK-jbTáf gPӖ/~֦ԍrsgvS VXp`!Sq1 ,w%|B+C[}$jNq~wmcDorx9.xd:хt;8ޘ 6㸐#x7ѝz7Fl̢yNq$4_KiӒ%sܯ=[o\B\f [NoT 7fIQ~ͺvuڞ\cb;xuԪ E w^U^ O{G4io{vr,Ѹd!&,6BZ(z8jMA6r?#o%2L_zjv_KZ:`‡F]; 1jf }Gz:kc`9~= 6z (ȫWҼ/m4h"teq 'fZ;*Q 9C; g'Kq j {u0n_\wc;޻f诠̻6&= vhsOԚX-kVŗ|bQ@j;L())M ֥4tfW'q;/)Nu cgK'(^r1{=K{NCb5:PXySw5d~U꽆J=^K}}V٭r;,|Lrw\uU`;n@XŚR!f\]v6>dsrr*)ƏiWԼ=GJ֢5OfZ(F(ڢcM jXn :/O snwTipdY~S m\;*Z~hY~c)B|q{.y<Q=v:i&>~郘tg MJt9x ,p-_~kU"{7e=Xz07 9+N3qqL7{sFI+AlɧŒz\91Si{l]o&wOo'o:ĨzhB,ˈs+Oܙ:d>M5 9yط;;rfѻ.GY;{Fơ|/n:#^<WtW ݭ/'MV,A)vlofK5&}W8crHrCd=odBuMv7U.R,W7_w~e,bĥJ0 qy HEj3bT6viy)^] SYMמٌ pxKï] c<,q]-1,I8ex߼7}D{ѧni6k ;qyuzX47͗{DM.p.<"74 ZMK OzξtZ|/[ݠ`t 3ھ'. ܺuX\] ifzY{[f_i(HcafzzwmnmfNb>]-V{ث~g45_|KH՛Tg{If7s]e#VE/MY,wtCM\:eȾ'yl:,=2W>xWN[xgPT1)3,gK5I IιnP2=88sJw{;|G{˻Ag5 tPyRά`xNoMSt\iδguc{E'nUwj4)J4p1_PιrՋłe<9:wc8,Ԕۨh?h&%H)[ܧa>4b`>AI~6O׼ b64W;w?v@,^<N޵p9v<X귱M ̟n\=7٣ٸc<uˉb}/zc86?nU/M^*X"y۵w5J;xy^;''K_%ϩGoA1*AsuQޓq=p ]mO. #{=fm1yie˦9ezjq[)faSswx,C d8v#>v;{Z|߭#* ҽ~[[ה(2p9w>6O&mmuO5}>:sx˾r p[ߵ@Cm[|{z#ýqu%WgB\Cѡv랅j2V[1Rsen\1 rop݄wI}pFyUSWerTL|G<뀣 ~sLK3̙! 5kƇWG {ܸ{Pi`.n0\oy7NfmW\KM^7|oe2wn"g82A["{,.+)gt=>6{'=uv&palqu" i!`WE=U;{n;%۳:# A=D&I}l춦7w`lpeȳ\iw\lG(^IWs9z$spfM*oGĂݝC=W)Z5ΤK<'Ykju2e[|e[О;=n;dWj_:"ɹ߫;]$.60U>.bJCYWWָf:+[JǺ}׬{Z/X@g!2y+ݯ5c˻;go*d70iݓ{87ƿY^u\ wkW?.=orvĹuH|ݜyi9-3{Vja.#UX:`|k3+GwV)HƒQ'F^J@.M03h^}Չj -K+ޓ6dsu.qz\z9yW{ݚ~ 1mKv8zB\zG&"]J^7y9Jƙv\ئ%ƻXxڞOyxhyYκ/+E]ᣮ2T7t)-.l}K.=A޹Y6_xo0) hǔtw+,5/Op_˫XG\/(%Nxkۛ܂\"ZBPdf/]c2,Jm}tswX`oe;>fwͱ~= YyC|s_Np¾R|YW(8ݱ f-B[ldUy{q>hb78WADуf._/;}(}{Zup7GyzR|u_xYrĭ*ۚXGNmo6qh 13i|M:|9J=n&GqAa[LKX7{|Pu%j1$ \I@{XB\e2Loesb7 y-sThwn(k/tj`Sϧ;&{(l6{o:M=%UEq2a 4zxaio uz C{DTPQng^kspXѳ7fK Wn^)qy}CQ;&yvu VM==Z t-W$G7JȌ0jH7|k[&ŵF½S:jB=%CI({M˄Oa5Yx"6,A=;b[w s_bp,^ιcn{=SR QOl$w&q֐dqy|Tӹ}6,RDe3MԤ&r,KXgqy~bKOZ\6sbKbL;5eʂ7ަ,83]8dN5fcU͘WsPԤ/c-uDNԂ vdɖ#g;W&ᆹv|AI>xy =<9Mg}j}a(.QgVO{gi=WםǠA;WON8=4eg+;$k7@^":k΍@yE{R[Va nhgn=;{]A.R!Vw#NipdN_(Xb'h~H^VQu%bS+M!d=\KF,ްZ{G tgL:=+ ˢOv}Ǖ`"K~*Mh]w<a|&d?Xn /V1JGv;jSNH./˛U N9PW{ :_qtqY_]6|A!x=~E''Osv8ʯ^ /d>Cg"i [g0'ވ啻|{DzKJY~O*WVS Y޾mRE Gz4mk.G~{Ūq 5:-yݛ0p!KZ43\|#Yjڤhnl/.S<'џ<(; t8h&ya$֟m7kx܋"9]xQfz%bvwNwc7:Y~ 䦌=}}=!mq osK e2<ۡEY^8m'=8R2nt n`XK=}fxǠ;b_xX%%l̳t>fT{mC{'c{㝹ϖϳF_=\q*AoVc yz+PtI"Oi1czc1`鉮]#t|cԪ->) CKp9}64+#_{=ȋ&uDwS-}.xB6j3hDyW2^?!-{jK"ɍ՜aΨ,}`o2[WxIm]}}b㫋lխf]9ml|HFe1 C(Ag-@%2trUUGzlKP龵ݖK$"y]a#.7[9#u/p,F"V8ow 5q!(l VCXFrYiȜuo92x1|OD7K~D2齓=|'o+OdnX/nֿmL| /H!_S~YscѝU_/ _9Fh i;¤%6ҼFZIqn/r*# j΃bK,>nnI.\jd}'x7Am\9gx*Ccs/-{U Ķr,\`ì>ūCuIM] /ݞh:5UM0&ǖ,!;֒ɾl{΋Ub9e#s/\8YF᝹{o/@Ǝr*;fzZxtSMlj^}齞śH:tвw%`$+b9[)h?xTIgQ&kyTJn7Nx}vdi~K707 O fU@3gWpIy o RsX6 /MfƾL{/|ñQQ]ݹ$xzC uG][M^x1iKކG&G{ůr7ڼ^:򧺳җ2t{O ,ًN=˔hRZm=VV = z' p3ks,cnwSZf ZǼpt&nIFUSXKiz8~2d=L6z BWcvxuLڀ應-j×x )؊Y1c!>qXEuq$1׾pZ0n8 WxasH22<==h(^xûK{bw]C gQWl ޷|^G#WEsG^d]9է}5 zUgp 9ޛNŸFie:o;Oyc3yvxvL2Xvxh$xoHydw=;^ۂo1@{G+{˯{j=tօ;J{ZGy(T=^].^Y ^e]32&K:)ivx&e}npv^D~J͵>R<2(@=3վi~[lNjOcrYRe#:Q9U+.;cy ۦvc||]+K'].yRzM++3Qz^BɹDt9c>h{t eZ pm.Aʽ"E nf%ifQwCUPvu ʧN>\u9l}\ӻ6OW)v_$2t 䙘@{JJ=ɲb|6)cvC`QumO`Sg9>*ָ =(͞:}+F@HsZ4e.ޮ;T C*}~ӆ$iŷv&h _YrS<ΐh;Uз{4 Wې|h|>ә~Bu zJw5iԲ`gvꮮ:ׅɆ`Wté]@V=eH0 r*Xgνh>^7 'Lǖsx ە .X1<=&{m^im:ޜUƯ8.zFV&4]{nIolrd4. 099x"r"G3:lVˣwXnxݰα!ewEmɩ ]-Y1JuZ}T_@M Rr|}#uoє9:nU8jzgX3^|y&fSw<ӯPαHa->pZ͈z79W !/8>[cJyFw /{ܤ>$Gʇ=VX܈_djGzz*Yzoq }x5x<}]s:=Ozx_:AZкf;|mt6bX*k}ȁG=^yE]U}&+=těbE4g;KQI0xUOlǢHȳsPxa7(},^cӱ$o#~oj"fg&~z=6rdz 9U{ܙQza^1v,oq*q1fF۠'E]K&C;crLͳfLq_it'7n浇obl] T0fu`Ǡ8*ղ=ͦwDp͠koѦF=/eh3=V&Dny g>?`Lxsad5~O+^=M)tt2 ;;;壳Pέ'١y\ܸ}Z){Ao#opo_D1ѷQz`j3ے $/^Ii׋nQ\"OD?Q7ݸ{ XSݐ"%7{ϷxŠr098;nyOcQyPOzI >xѮ;1:(#9/]{{{CXZ^:զ';(Z"t [-L߽uɭ7^E{jMP_ g7ϯΝo/?b` X>u8՞ { ٫XVux5峫^TtMʮtNK{s-]d> *+=jބoJ9̘JBIc:>h)!r\;˹8=zd.4w9 $teAgq/˅_O{X=#)CҼ-p6t|t+zRB]ǂCt/Iw~Cr)b;-Ȭx۵z|Szi etkcmg,pf ѹfySAsc.ksI>nL{}=}!3R^*Y4`O78ƊO 8:NK.XGev57Ym,C{/s [{Ş=Z2)eo5_gv!x^^p|sL\0+p8˂6B#iy0$x|9^R\9%nɑSz i4qm9sօ{2[{,.ĵ[kuKs.w3i߷{֑\{u='xpLS[7+fhgҿjf@XwQut{W^kb,{*ZKǧLLSlzX3aI _܅ލSԖa>ĦY q {ӆNXnte؋ʹOc G@3G)I\؉}N( \g[N3E &`á1Wn@yZ=ͼbypdd,U$ qjeؙ>MeӹY7}Q+x0SƪmzLnm EjƵ섢f}=n="Y3m?/n6@4>;$;yֺ*q}g]9bv{WG.KLwUBw$Z3{3۶0pjc0[Y^Q/ǽ7z8Wsů$kQ7c$zqwT* \$fJAx4 NxSF_pir`BrdXp],Ew{wdTح_r||ZAkb2K7's^xltW:NΣX9M(]k5#]<M3s645=a]@VZgwܰ{,kُ*7hnw]s`w`סF{( xXzN;7c|r@˭rTV lOar!vroZQ8f0U))(A{4\0 Ӛɦx{xXN\y+xO*ysB>Bz1ޓ)΂HRg3>z]J ,K\^}ݭJxgy;s/ j3BdH|XLidziöh΍]tJu:zenʊ>@ GO]>sˍbz[(NMxTr!6;V\iJїa\T [YO1i۽wuݕ6*h'u}`wFLJnq(_Skoc{btyM=FYc<峷|[݋Fʮ!C\>L:G܈:kռk%9o`Ȟ_V޺j915xgqtR{;p!}{ڎ^{yт>3~÷8ۖؤ3ulHӶ#h=d"&#WCٷzQ$꯾3]bVoMBy!R!|'CEmݡ1^vw|P2 ݝO0[ RkwB[}n{R_>"X n9'oso/" 3[P;v =\6G\d:5X-cxyWl24Dv93j[Es=Woն]"wYTX41ӾȱCoя$Z*8b<@Q|ǠIg!1&Ֆ|so0/=nTw{׎{fu2ObEQMGoh9h{|z ZXNv p8=%,7t"CCz` WajۆpUoGE}}ǽb|{\ ;o2t9})h6IfZ4Lzg(J.$ISW̼V\}7_I]]yܵq 9uX8z__j {,ͨO{I̸vf+(u ܼoYu(} OE?cE|Լ;}ק_i*5~}gf4texW˦oz9Ww)2f=&_](;o)Hڽxt:.xAݪ5s2xt4ؽ32Iސ\MU+'<✉4` WEcG3*n]_jF+EʺR@csŽAEzfz053{|C^/ W27zm[y;1`kA59';`[-Iu=ySV4p7yaOؙЗ»5h.`z  &5tq# x\3kc=Q.w[GM_1=4Cq,{֤`&\Klx|=HdS=&9]H R}f;D+ U8wƼBG;Q> 7ˠd{ @|54e*/gD,6nv:B/DOwW/zOzR]oKc3{`͚[C˚oqQ8LAj\Ao zUv$%:|tћzVhl%G6|u7ϕAʉm5a^N7̦ DX|>>:i[`7rp\=:3걛vF/nF2l28u((SXud}5i.,aD˗*]&/}n ~jйW8EZwqosF!]qb{׃ΞZ(({f-dpoIgOK /&q'bݑ(? f#=Tdy;՞_Os} !5h7a37M=|ou3lm)s,BpW+y}2#X9K^{y̺&UC%3j 5t-9ϵBZ9EgZ]<7gFCW{u;;= Gіd1_M<\"Q׸F.g˽)OܯD,?R{,ƊYdww}9)Onlf N:7<x|m9cFN}7ݏd>,} T]F-uo(uؠ{URx=+Yڦ0@mxb~éz9xUI G-5R^L澦 <Lj{&م*&nw ̫bs(_f0h {^䥋! qY}ӻ(SkȘ|:%;m87f!}gnF/Qt[D`MvQ$*f+}B?j}P![{Ak&=|;{,{'x}xozG;s] 6yaW'R(o缕dj杋C%sXfon4b,7">&CnAQ\rKA_58}M'{9OUyvrz׼Ssk2&.|͡{gUf=F[{z==١纥%GTWhg70o>'^|Ґ>,s䎚 g9}6,f,q|'edsz\/qs$ >"Aw"q;?К~);6{y {ԣ9P1hY\s8P P6`XgdwXxˋ~nzHn-p^xkݝs<#[};&gS*_MՎrea|ְf> N{7"t=hmXɡ[pNeLahy&Fxaxo kɕKIBݲ;꧓b<ܗ!2@3.X̏UJJo`tW+_>Q\Axv!.Rr/J^*4Ͳa%M5QdZ2RVPדO~YN.%B5q9dlL^7۸VKFy-#3E݃I *spD8 ]'TOgCwV>ޣo `z m$q2v;ٰ6x3f;_qj_:1[B-x\zzϛO=<'S}jÔ}6:@#ROoJ Z!X=`׭]xޛ|0m&z,b¶՗(6lVw|>(a "W1_^26j5'ZF8M=ڵzuNtT/0Ε;p7vVT~QM:}'55y̼{q_6P=U"{ޝ ^4>S+c<x|~ī륁wyn{]H=똯|]K蘾6E󢻗#y3p2W+5aۂ</~<6#cgmF[_[9q]}|މ+=gdx-Rbp\&NL^s/s݊oLSqW6~>/k}yHgyX1{q{{f"ô3{&^ s5ѕpaá 3WW֯oNG$԰YƜ^9ޒֻK%.n^wpU]Q0E*Pl+lv8YzǞN£t˗oN)C2%/tzU9ݓL J zfӎ {jEkM%rb`;uޣ{: 4^ΣMPv\p`)u g + $k]GxVDV={Sezj^V|1F<. ѷ͎,` Ywx9Kqh^T禴(:x\jΟ/ U_PD" +K<#6ڲGظ&=`鲄<кK67yg>BVVe#m&=Yca9{`i%z$uJ6^7]ƣ==|p qu2SQCXI;䧫rRS{Ά IbIl^Ufa7o&>|dr!y L7tgowU^_0xtCri~;'uŻn qyUBsVw7qW=6Roc'mCy{Ixِ}ype倭݄xLz隐4iӤxfYd{܈.K,0KvǑ.c/`ECE󾊑^7 ͫd=t^W?SS Ӌy,1Wz$g>IJmk3"s\x%D v@ùCp| {7<({%nO/fw=ݰx%9雳p˼r uZn+98{f6By;\ɇLxGDvs8"4nי ;3#xe#ecym'W2+pJ՝+,ͨ9GK?g/cd Ǜ[n!u+"'q&/?~2{T3õ9nW⣵{+3.}{dKkfl0\/Zz)374n]ϯ.ccg#AWѡVqotL;p Gxu(am tDk*uӯzkͰ^L ({|zW"~*qwm(poz먫1 \_x X٭̌Q^&^ _,~f'\=cbw{[ hѠӉD2$&mq F.1izϑRgR:Fัͨ\$y{lOهzCړ_&]Y,[ɯBw[VIK G -[&]}y?]v ڗn ~c >f{*Hyӥ2@vK MnV=Y/{F ;Lun0֣6gв,Z|C1{+=͛squUܐّ|f~S_G-)IݐW}ӴknoKI*9<&{qbm4rNz\U*w`+ X 3}OQW!'+x8j? EH83Wq񷓌3n371;׼SPˆ}jӹ<݆ EɚRBsjHxOL(LtEgiaW[;Xw,Nr/fe)[̫ѯ'W VQe yJ-7OY;Vuz}^åq?trq~~ǁ+.ƵAYݘȼZ!JRʱp^#o$;"Cr7gIHBFpW*ae: gU{u A' ش9oQr.#%WKz)~>@dQ8/}瓕W=/(?w=s0׃7@Ҳ΍Wt;*%_rA[%Z0S޷gk!&@2;\:c[\W9 TG5}##c18\GL,רodzM+z)ZeĬCi{`x1;/sSfްzO4C׽;qH,Koxc TDjv7<[زoY;FU WQjӹjxW!r'rZt1ج콷*'?qv\ qݽm"͕ {+;^ 4Tv]Yۣ ODNn#@\ 9:ӒDn5"bq}zvNe)jD*ݞ>]':U,{8'AzEkSLw(:ouL["51wpZع^Cro9WIœM…ʗP, |׼X)au,+[s:Q,p;: 9jڐޝ7.U&[=':]ާמrex<ų{Λy4"ȍB=ضxsQvB̚1K]]_%%yӻ<-L{١_kgs5ǽnwu [n[3wJܩ1z00?usǸ[3iؐimwC+!eqO1w\9igByziV?7osRz˚;ō.U~]¿r }ӈ68zNkLݸBΨ^^(CchuYr}f͚o{ J|1_=7gb;zoW{619m:\򗧰7eLLi63u:6{k]cٷVGz!ҜIsw7ndN,4GwEv_>aaF9,A,~֘ɂ5Jzp޴ǓMڹiw! E^2%C&]wЅ|^sm kZ7L?@ϻ*.)n|t5v[3zR<@tyT|ybBxf'W'@Sy ; /P7|M&65K,sAFդﳦX7W?}ƐOF`XQk|{+$X0+[n_>*Ub0‚2~z+5g[r4k_Y8/>Z޴d,f]>Uw%T|<#L6N<܈Y=\hM9 2xkjw+5͝uaA:D4rm~^}ghɸ'_Xm;p=*/ˮi&꺡o3r'Dv0d̓=Lp808F˸U5̠vU憂 Rd3Pΐllq_x_X,>o>w-ߛM佯v[{DfomŴwK-ȝ}ؾ>ZO[o/ ywT^tY^+x8!i,?nlca^}}Ȕ+#dh͖4bp,rc}s͙NtztR@_=v L-o%c4qxWȻp }MƝ38v:2{N/{ӌrµ z_8gY/r=xG'\=;OO_;ݛ'@9FIJk6&(df>>f$vm,ci2ޚurӊ~ sw|ws|e+ 4Rf۶ekត:s^< zGw< |<^W]#fS=4͏C2՚v0 (畎oqy cp_gUB-+o{c#5m:/u܍\L \'7bu=3.9}#s\|Ml.\;LaAVMGYFf%/`dj{ݏ8}dxpt\2o= ]:ܒ4~9}W :Džף/Yw:pJ۠L3C\R[}2j2wv,e iaCXt^Ѥ弄1Rקw;H&N]1F|p9V{4[߫[#\}y:M-=/|7E$Iǐ0tU}(b3x#2i @狪e{sSkIޠD|yS;or9MH%+Lh>9BPtkl0Lļl8ٻ2r/dᗣBU'%㝗sލ̬ig:B C';t?%{8L75L[iG!y& |ܞ[~ުVa׫w:\'It,j`PIY-wq3ZOs%DcJ/K($"Б/>h79ڴt x#>^dExe{<} ߡ4Q .w/mW L}㧡yg5[zXoT;,۞wiו#nb c4BN&v|pK',dVY>0pج1TK zAt)̞^{αd'wF6gD]%z :{^ؽ>o TowM,}RIOepe(]-׷I w͑rS}yWmtl/;7=^|6'&o[ ڈ eOLv;O# lOb@xeͨ[7|PGS4B޾ Wj+ft 5q^뵞5}ٺ}tn n/Y{(Fzcˎe}^c--ey_qUPE671ד@{SE\81޻B=n}7W,p|Gjgsg@7=T3-q{˅Sr}FּC02_DW \~r}!tO-5Gx;vw<{\WX/X7hr/1eŸYgq[lG?lm}h4=1ٚ@]7;&n x^ l3w +։k=q[Y9{˚l_se8ܶiMg]ÚZAK:<jGQ˹'tik/ou春7ʮ2~;s|[ȅYO+=YIoڽٝhoMXwӻͮfUgz#9s4g;A\1wg33_ꪹ{#<=ꗱ<:Aܽ dǾV{E{_ `쁯[1ӄrn24`Hv:xe; ȁmIgMʹH"-B;&m^ٍxaiaA'z0[zKBA&wӹ;Ӭz!= ٽ⳵3Uڱg1MM1-6!ϗQs񆑗VȕwW~G{6]9oPdIU9nnřytr ŧ]dF\4=SUt"r)}p"~Ruт]cuQW,8rMV| Ҏ@Fq͙ g=}[ ;5IGxĝGzeV1R.n w/|בvX ۖ_j&4lshq͆ WNW:Dr:0s2]^0Weh_ ^'x&/uqqhݕhٻQdpU6It& H8wlU4 <G&l>\\#NW{V&UJw qr玔|gy/]aÕzc|X)7'nfFN\!͸uI]HZ@S6{+ܧSӷ.wҞ';5i>/AѽEH&;i}Vקqs}KeUg\[ó[޼3i@v;GrjWp,ױLͳo,Ӯ^Ʌs'm7.exnޤGy{&e<{Oז[{Ɓ9rR<<K5ZOf8Vj?Ly!+fST͞2Zg/'ZLx<c 68~ M$L#C#=u|aԝ;ruBq/lT9?LX7fZ]U֝4ҫ .ĥ[1=s9o7rJM$ѴK'J|=ya어~ݎJ^X]QbfCt+aetZʺb,Y6g.99Y+ ;pKǞ c_zqť|ڭx2d3+lOAId\ewDT([,y3{O.X0!et)/S~kv+ûlՂ 9nҝz#.4WKHk[n7^TQU3~Zgq|G_WY+ٞ#74l:[}gʶU|nYl0*Ɂþ)ua{LjmTj0Nyó4Ҝ۹GK}Kǃpct.m-^sa MO11^ boE Esl}W^4kX3/l);Z% CEb Ǟ%`O _ Y]=k<3eNiY>>G[xGo.'Į^+;Y5بjWzx>}½*4 Vy{^9J{$:p7*ۼ@2l|9\+x虧9֍3>F&n'^YFk/ObX'N\v =뷂sF@m|CQvfwf[R)G [7;Jxc۴/z3qK¦St[Ys-]a87X,郻ŤRx󷱾JHw1^YMD8XŸwgp8ܳ3[O;b>))@׳j޹ld K)vx˯6]V/ ģk1:Y+c ב{xgdFaEU_n xergNJtGu˦{W hݸcz݋jq{ho)fMMh< ]7S[^s˾ؑދ)n\1GfEr4 YuiPz^ {{Ź⶜L6)}"1L3j݂:kײN yL|-pT_SsPTɝl<1ؿ!8u6.B$nʏqu:I<p|jy /WB:mLu7օO:Ev)4@hgT']v3kFO^7n;S`]k- ^=s6 lٲަ-{ӟwL,Fܫrnp{8-1j)h^sPT?#^:+ػR]LWҘ“oH:b;Y5vʔk۽aW?'pU:v1ܓ*̑O{]9%mtntPckc.ˢ"13S k5G=AC}YVӊwN^7H$ϤOL#KkzuKIJ?s+2E{|quf}Bq`WNrN4n'oc:tU+]a &z{յ;ݰ4i7nߗwO{O j=s }ޓ.aP,=wH-Q@H>N7[Pvc g{^EZR)fr'$P!UJ݈bYoQ|/Q=H::t߻`;11&Ъ-¨ܹ'tb-Ǖ5r85y Iͮ~h^-{ٴ}WKl'ݐ/e\0 άܜC̃=xûiV#f\hO g3ޓ{bulFr"_3z.٬n_l} |Sz)aޞZ~;uwr;dV{N^"o>{;'"Vy5i^>ZN\3ψ g&՛#{Ҙ&o'EnM ;1D/rFl уן9NW^evk.ƶ=Zr /LKuW32*s==0M6Q}vwY's]7:r;wqgdj\BhdWfY'=c" 5 =X' ͪ"6/Pga̶em㏖kF s{vK'e&wpݘRbTηHBƐ.vPji#tnoz"3Iy.?LycgL䳽S:g +mp`$JXFu@-so^deӤ C.Jz`fcۥ&ˤ!w(ѣWJfgM#]ؤ,ڳ?(Շh<Bun&ہ6#md+2aGi9^8]ŤaSDS{r)9<&w ;9`6&Gζux!=c\Xry=8f z# tgT!fm/>G07s.9p(Q(lFwvΜʫY Mffnq2w*:r|U]5ҧUWyf!]xgr*tymZ^lȯޥO)Z.2| VDOos1uLs٪,J\)ӨMTF'>;˦Ug6.;F|;-q BW͋1>&eČTS0ixhӬ62z3f^Aw?EgwvYE-!xҁz珋KdH<6*=O)cU%f\&>St^CI½ohǺe>TW4o2u%w-=re7;v|+ۗx7_ʏp ԻbL[ ) ||=PRRHT8 $H E(P@()@*@ P @ ( @@( (A@(QBB@P B HA@QU*P H(h+# S+dTbtrݡtB-)X[ }Ek5ZuKu^ 5)Uڐ]+VM)jլmK Vк9].Ⱦ}ݛ{ͽM%LM(ty_>Zc$jڨ6JͨȻwut: vatk-wu5spd{Ƽ0ĬAqh6JGJNFTf6k&C&vmڶUk&hmQ;ws}ӱM;PӬ-.irN]nv]صm[Fs"ŲvZ[[c4*#Aʩ۝ipm;Ļ1cO'ۨI1j Qzaw Pmmeq2MvݶM) MmVՃiuZ]u[ۧ8vsݫ94ngnZͲ2vĵfnڸ6\%vػ5Z(]`˸ʻEc7wI{Ϭ37{q->&fv|5al6&Zs;]*lpfέ3CfiҚESeJUW3vvo{Lv:5scs˩5lV#mղa[yWfimmlgN5v[Zٷ\Nͭ,Zi@Pdk u >z*IZ]g^=kvyLՖ֛j2-]m´&۪mkm5֚lf5kWuڎt=:;֑f{s}V3UK \NW(\nJ-mmֶlVvmeJSjU%lVFJŬҶE)R3Cl$me ,6lV٭Z(w9FVdP mB,ț&-laf&glc25֭P5ڬPldW]յ&SXWsm0UPVѶ5eZFX(d-kCELڪhfح.ζڱL6JY-*k-4--%jʖbUj- kL6lhnY%Pjk1e-k[mLښhllY&kmZbi Ͷͨc+U$MQ[m̈́M2hhVYmf[uF*V ٗfIZHm%0iJIlڵJ֑li6$JM2d[VhԶ,ٶmRSFmj-%ݤU2h֬ūAVHmOMR~L$5=2hR@j{H2OT6T &hTd~WVLv̥Dd5BįŒFb0TQ~_%5iQ~޽ݿt)GHDQI׼~Wc XIE{/ؽQc6ؒ^QIcfj(Q%rOTQXh-O҇Y41b`{__ͷAh4a׷/Kfj( b-o}/^ݗJV(mT_odmEhtJ_ɿ1Ebы!W&_͢52lF#^{'EFƂQh׷~[oTlm{~O#dQ(߷hרFm)E_4QmKD~M~EmdElD5"IӧCVN( "N?Лmc~z$cEA[~tҡAXDd;͋L1bƱm{OobW4PR,!kI{I戱cŪ,~_obgٽɶ*5ojd1Qߟ~+6ш,~^دmbkEM qPP9 5, , t*CYlOuԽǬת5wW?uX*5N5YXzwaZ(o^޳76ؐ4P$@RE,NS2ua":w;4RBE:ΚN@;ӧC M" 47$Sy5 8N·IY!;ӡ;&NarI5 7ttjIӳ'RDaCިt:" !vhhXB{އT)!4Ӛ5zE w4TBu!NI $:M9 4T",!;9 '4&$&n98N:u8jӧ{5@BMT6qHa &0Ő&r@adiN: " CBAH'xNI:އM!P@;7gBs'!2!L0 $9hn Ct٧$9!8s8 Nnl- Hp'I8'N:4 JBn&a $! dg'6r!-I7wM6lٳTn@l(Is&8 e0ӓ M '4`y4Hm9BNyr L yIÇd'{ӽ swWwaprro998Hndr6l9Ä$ 9M8rp`9C ӁN` d!B 9MI,`C XP  nLSgw99 9 s$RC(ÓP3&@3&C432Im )' o6 0~^A @3Sa p00C2a8s09ɒpJ HfL8p,0p88X2Hp08d9ȤL Ʉ9H^r'89-Aas3 8a [,)`s8spPᙁp$Ü3$s)la0'l6/0Crn8rs–Ns -lݓ3 8qa090s !C9 p+8s Ü Ʌ 0 ش yЯyw&&fsɼt3 )-N19p-397&Ld&2Rmxi0.#\ݮeY]pv9w6W5C$5XtܨVV BխIX l*UUs¹]t'UÕˎv&pr[%4͹7*qk >0JJ7ԩ;cTfAcwE wK.ι%BlKU mS'qw+5pʼn\LȮWu 78XJ:ʕmVUQ-cե=F="2H ck;sv[FEdFw;c9ѝӻwv%HJѢ)JKJkKJ\\-&R\sr1v"9vt*.Stbsnsou>(oۛ^.rtsfѧdnqwtq|֐-XcvsuE;ws( 7w g;lWLb.ܹsP['.ln[ԑb(Mn/7|;b]sk]ܑ::d,EFرIiӶ']tEnrEw]͹Q\csrw7.3wv w]u;CQ[㝙!rGL}ӏ7i_[sW^M'.kv*4bMX\rtѮBw\-wtww$nurQn\]"2-nW.F\nngu˛9b.tt].^ݛ}􌻮jܱ.b$Xi,o8ww\خKu3ww:8r99&vû.s:]].ENvWwnm˛%sWNq($'v7thNGmww \w[ѱAt$98 tpXUB(6¢6sJL릠l;ɔNnth.w]N]˝ +k;F]nۜuآl JrwsNu&QTRQ":G;;r,Qs6b"hwtRi(3;7:[VQAme_c!;p1v⻮+mE)`ыdexdrܦFs""+:t.\ܙwqs)Wuܣ;vmnF+]ېPlrwjwnL4\˻pKFժoOw1ޙۧ:r;5_CZZŠukau7#ҹ\w\QԱ mE)RB[F2\ւJܹMt6(g0*Y=c+W8&O;ruvRd yntع]۔79Ww1 t]qqDrd]64D]1F#]ݣW6IinC}YB%OJ 5)c@of9>솋`EF׋+ ݻ5$sGwb"#A˗.]s.\2s*Tm[KmTamH#.G$0lK,*,!R+Zմ *%=yJY2!vܺi8N;Fu|Mjmwv\r9.vn5ҺS2Mrkr74]Q\t9v\1ˮ #*.bܺ]%FܮR>ɸ7S֥2&hj(bŶ0R9aRJh  +53wnr2$n\ەː&6Z4iKY)K+Y+%t3f7X[-Ugp0)ZDb"󺻺\.W.fPw%wusn$S\ܣE#BrsrTiv\ƈsW59 m˕b+YCU_7-j{Wpݫkhyڋ捱&9W .nr(wEwvvs\Mѳgp:5TlbNܱwtnnnh6"wmsAJO"E1ѭ^2me%RZ5^ njܷCDQÔ]RYs'wLݹٝݹIW* u˺tۛSJqnEʹݹvbb \_ oLYE]www.+j%FЛF.Ir̺HTFMۛDkspu wv9ی.t˕tL+7H71re R7׉|G'iѽ\5E5\Ѹ\#rwm-ȱ.t p+#͹v(ʎW"Y]6*4RsdhJv7}xwi_vlͼQuQr;9tq7kbTV*-v$t5\.n\ۆ.cG s˝w&5wvS4X;[k2QlrMtʓQXd `1h\VeWٖ+ElnţVd:Z77h9rZ]ݓr%.nk;53Qktܷ nN`P]T ݛ{}y,}&6TX;75|Xkc#V6g]Ң `+wwbkwB6TF-V6ȲѴa븹*9˚ ,ȨnrKQY*yaT뒺wr5ms9QDpɫ\.N96.n\1 rۛ\ʹfi]3ӺlTlnZV&Eslwv>'.+w󮻭\E/ܜ%ۜ]j5[fk-w`d[s%\ф.rܕsW4wcXأh#mܩn[&V*-'"(oX4/^+NJoƋmXk+wnF.9]!˨Esr3lFMrLnW#Erֻ$պX]Pr e+|1, *2eVVjU@d+ȕʹ5ܢыw]DDrmv1B]΢˜EpܙQrgp"'|iRҔBtss%]9[Jwur\F+,J‰Z2[jT.krw\w]bƨK%`I[T(Ugho֨]\Qb%9wuu)9rE"4h0iwc]wncPEt `1LŔڑ\EUR,Nq,(ztWr.隒njEt\c#;F)ds+pƣX$crrs7 w]56&W.E`\(>n_sͻΧ_K4xq(ݷvm|d5w(#%d0j"t鹺뫦MW7k\n\W7:\rM7vmK3F6؍9*YjxeL-[F肘1BA[Z5W\54kѨ wlQ(h6f,bWM˻!u̔T뜣RY-AX_ZOQ=,}1f_ۅ5\5st]j\5e;C`cEs\.mݫY5+F*uHCRnmÛcX)Fwn$#sx˷|eIRzЭeT+,H*ENwsQe;pw!gvM`PDlhѱQYQEԼۺɍs^#ćUZƤ4Tj#&unXrRPl$Dsm[͹Q%F(5WIL_x㯥pW4;k <0Qsݮ3chͮ@IHU͹+*ԔI4"95ȣ{k߷]+v_/F)7dxXl[FfѢAQ]%c4uQEe+j!&DT3E755+uں_'+]^E+oƢcFѬIXѣW:l"tcɫW.Tj幣A9r9sn]9+V1cW#O02 ,EUEAd1KB[kir,b1FIhѤPۑѨeX.] klFk}uq5n׭wu*EsFCFZ(B2wqH6s[&eHX P5_Pge'[ W)A-|FW.h r(,ɃrṸWu wj4\܋7#]ˋݷ7MTgѾoX5&ٗ:5ms DQܷwQssQk-(,hh9fF1RF-XLJdy8am⤷#s]j,PTh\#rr*h&j怤m}ϔ+Y쨑l;jm-ŵy\@F5rB2F;R\r-F44d4.>>arMzcvo1KPLȇ,DArZ6(Xdh1`W,I$r4b]s/4ޫ%NKUrJ5W*#1l@fY"l&S1pb,UlIc/~e6_n{wnnkk;Dd56#q3.G8V(hFLPPUpI&Ll\1g6'oWLE$W.UFḥAF&L(\ƱRIE.ъ29ʯWqxysbw&UW(f%rHh4QeF"&;3HTTX d7.J14ae%AQG]WʱW)-$Qͱrwd,cEFflX(4k%lZ5}};tʓK skW6(0ŋLZQF (whƱP͸Ʊ2F x65Kռ[ZmxA s6s%\h +ھ9LP0}eVE+c&*#QDhɐ-E,PTmw7w\M#v6+\"VFBlF*(r* E4dElן_M:oz+svվ^BlNq+nF+s4ыج$MۑDmȱ5!^QxŃ!Ve;i1Z1ɣR(-LБcokƏcvFŊ#`FTZ5&E53L(Ɖ}]}.h(׽۶*Qˑb6!"",\MI *1U뛑9F "/kx\& d&֝bؒ_TObK깠&(&cQ Q(50Vyxc ϺmE\;m]1D"lQhB#${k{+oo$hŒ61!ZJ7b "K}E}e*^&j5ɀTdbbƀ(ݷ^]HiVZ-2Q,FɴQŊ}\ok_ZޥVFd ة5-h/y+${.bEX0I`,TQ֍b}4hZ60h c0i(S^ۉuěmú܋b lEuF *+}}-ۑuAlR`֌lFddѫ۽z-Dd׶Ċ D**3 4`bSTb,1l}4m{tQ(+lgˮWnmg[ɌldQnnj6 a"}ں}W6[t6Ra*,l$ɢ[ߍpߧulXh!&(h؋Ư~(h,b L` DT6*K1IWCjDa1hAƴQ|_k׌o~TjAcdф0Xh}>UkIJ,Y#lh-Qu_\اbƆ#A$PjLkrBUN@"i4bRF@-{z^穮^4DZ=\ljQ%&$%H4j?c?QoſW-˫W#b6Q&(( E{{=x.FZ巊7:F1*1"IhdUnkߛmcQ`(6fZBb|J\_7HŃcb3#HBbz$$l"El*(o~ֻ\h "c%l&ɋo'׹*{jE,͹QDDlkTlmDAFn *钫[RlEd֐QIF#EW W% 4c4$Ooy5׺޼]jcEEE(4X)ڝ:bmZ؍Q`{wo}Fmx-EcFѢbJ(}䏾kδY2mu֮hb"4HhؒD15ﷇ-l^ *CcDdԔd %L أi,QQ&FM!H(_؍{of2nYH &hɢ#c:KmrH3*0- Fɽ툽=ՂD eQ3b2,k{={c^`cEhb4QAkXunVI  ) T6'2.^{[sXF тܒX{tƊ{d#0#clX} _nEkoI(TEQ_m>[ƣstبd qymbj#EFђo}מU5[!QFOq% D06űe{WѽmmS^x{1KE5IQCױ^= ^\1 -x+*OmD"bAAI$ou^H*"F s=oo{Z$ѩRj(ؐƁ@pcbEDX3{x[Tk0 KF%侹t=!2#2جQovkݵȲXFh$)"(͆ɤ4(A# І^{1= WTţ^׵{FsFZ`h`oؽk.mEEDbgO*zWIDQ ɒDhڌ\F\-E6%\kkBZ4j *B1/}ڽ׊Ȓ"Q{m7kBōE7{[kRe %"x~_o3*5(O%Dk\"VTj"F{{b"4b'_qJW3Z1$j[rnhlaEPU41M&0Sd "l*&Z" Ưjݖ2FŠSeaSAHdX-IE^'K搽\4m%Dۘ+ڹcFd&,m'{WGcnQ` $s{12LH!cYSHTR bmܯ[-c^{ZJe"M{W{k{pѣIDF*# D6+ *Dؤ%$b=unDk $T`i&AvQ ( JK_~W+ITQY1 rEQ5G7{jۖDt_-?mH( &&!6YDlm]/yul#hH.heJ i ",dR"l2(ě{^=TjKIQb_~ڸf4bUX dPEM~oۄWW6~\_X66{^=+ݸʽPfՎ E~݋sEF#F/wLQ`" b3hllDb~ƒչG9F-&1oo|/^=uA9u{[[ E?O߭3b(k/nE۔ЬoK~d~( F2~1UȢ ti inX{{oW"=ہ$Z ؍E_ڿk"hv?R~ۑdZ#jI~ƏJ~&XAT*iI(Hb^{D_ms64cE%_~X'H^{g{\䚣!kݮbEO}u{[)Ѷ$i/qvTX) `&soHA~_("6ihFEH_ȿmsQ5FM X%t*BzמWPi6M{ӠlF߶?W ?FHB(,bN͘ + Yw?k]hf @("(-]?s?X񫤔*LIk(F  l4]@TAqAga~##" ;l vMB)3n~k(Q~~ md +HPH 4 PVi'jD_\ؘXş~+?m&߷&~DD;à=;J d] 6TtXĀ:c:NÌRDT4 hИB(l6M&e1fU4*l+a١ڱAbCkdPk??l_?iHw/yw({/uvqNB, ^'tq1DX)ކ=pz )lbiM&ʛ*6BRAbņLGW`] 5fjhi ;;ӰSd:PQTjM#/߫~osi+rZ1m dX6QX( :6Bj,m5v+ !QaӹfuI ٦ÈhUCEQTJSJV %q^{/w=潮l&tawb 1]Zi*Q,XSK]Z!Xl6pfʬ4T"vc)%FQU6t*MWGMAa6EPu رCar"T6tl(LN;+سA݆ 6JMfFՀtPЙl!;vJ`(('!R !jlÂiM ŎR E͆XX ;ӌgH`łfC"#xA`"&H,$DS;'Hu:TY)ءЬ;X""mf :٤*EjXl͋QECq6Qv(ͅ`N*vttXU`"iCG 4%bN½C׵+^dVEaqT8X :d :iqX,Rmv1ЬUwzvw jwR SQxTX0}wd ދ;:vT(<8()4;dYRUal[I/;+MFʪ;i  mBj]Jhl[*aWHNC/Jbf&VTU&3 &@&DE4*]IJPmAgwv rW䨫$ن&lPf͓ciXM4N@ LctYP4AMٰ](hbm 4Ѷ+*TM8TdXhiBJ$DMݖAN(r$DPݛdءN=(*p)rJʒ6l(6h5&1vM(6QUQGfv(( 8` )I,4"(iҮ´E/vg^WqNLNX \#7CT48bA ZQg$8!V(r^D@;ZV"ݚ]]^C/$*hqlȜ qVMʏmAjCkCf#ɌuЮ`B'*/E8c"lv,RٲsJtu&͆.XX4lӌm4ڂh)L٥aeݬ]+Pz=  8;R"4a]M!k٦lPv laZ&* uSʽMO=CJt靇Keat/5CN'X'466 ^p,td,-f8qrp |Ev i׷*)Pzx45p%<=7ap5T:yXG'Cc*Oi # 8$m*,:]ꜥQY5S`is[gzww tM㳦wit`({wk=,:>(=ꈝ9`t]٩ʜeQnzEٯhEsoEOwzvaѕjjk5=:tFx=:"vN;4t͖NlXhv'}-1٧-5,u٨鎭| %8HM}%ZM͙+NϟWtY=tXi5faeE;*q޺qX'(%zoӸ(u};סӠ[,Nsz*ҕT{6wD%w;zOv3booN Xju:q{^mgEj[ӲѽSbvUW Q'!Y=a"Qt;4Vv/o{N#aZ l^[Vrn%CmTޔSNK:tNA"yӁ5z8[Q!OoGӧB;tC!uE E'S FgNꚏS{Wޘg)U|NV/K>C=NO>\%tǐblg{Jz*zұUnLAJ{{:`_^:9c'EAzu"/QtzBctY{z%w )ZۆX6+Soz]*YzY qmlGM!4Y5tUq4FO)ݩluM*qKۡ҈3.SY+-y0TԩY] Ӏ蝶CLJK3mWjkJ\ 6(iL8UUT{KX)-WoeEAF;Dٱ^!8UKJsì:ZiݙopPew՝YmqQ 7bYSnʆ!t5"&j+ }31b'y)j84YeLhTSZm_tNJ}DX躡4RZxïQڥ^-:1cUNCB|ou'am l++NNRPvՂZ ;xO>d=KQ{ҴQx٦=DPZ[z4GF=O8斑lQmӸ 3 %-A^㨇XYmlRކgTFP(#ǖ#(ҩt4ZRTgl6Z0^o:xzrPbѦ%i[ihgsNJ_>l[=ޣśKkeDQG^jHJ>,(+g7mhZ,b2Zwۨü(1)lV|tGT]ÜϾ}{F(޹X"NJPՉ|{`N%FJʋ~!HHI!$!@?1X?̅ǟ)5} Pf3ocpI?Var󇰨߇#p]Jr`Pzsت5M31 \_ 1~usqţTs]f3=<6|jEDYN}g>ejPntCk+oŷo%QLnr#sH0G#׎e%J&ZlFRS%󮔐r4@qYmd1uߒN!u EHICK3:nc |RUB i[: n^olMZ*.dEPm(+*5ޡ8iǏ>h=crk lAd X)ϼ@-ܶ5Wc0&Ʊ Q˺ƓLXTTJ')LctΣDl]{DTQ,yÜUm-e7iyǏuP'_R &q**0|T_!uX}lY Eq GU\9kjuT^M;{g;aYYYκ ~y0ۦY6[ ?"L1PWD;r9д;lk6kwv6!޸14Eq>xf4vU;yDW* Jw&Z>dukj҉HI!X$PZ~O>AnouE[jxSZZ UZۼ*yx>e-LF~Vݻ֫ƉP  K;Ns;! | `, jJV*Ж1/=b)&z!FD>dX]8ťh$h2o0wģ4ȣW{y$r*ms:6*)ɊNjkcbPImEF^>ko`aɍ"+v-^V0h~Pj3cB0eL*O!| T3|Ϙ;bjC,ra=M rڛn]y9tp CnbH()QI>+L}p8 I>Hv并RTq(6,i(؄ ci\t퍮\*f4XQO9hVXv낰X8^<)NVSF .]Z3!YM;|~A`BP>K{ c=Ͻvϵ^.߳Omw>CͭKZ]XֹPfء wQm[kVwR\A~y$QZ}r>wwBpZcJ8 YtNEC4ƿwn}6>aY'P Xk<\fQOђ<뢐$ j' *匟7* Xh1jR܈q7R)jZ01ʬEN1 |dC+-BW7asV <A;آݺxX7R߄dV5tУIQ(4Qv!%Gn˷-RI;3VҺv ĝ҅Ly'"J탏RܺZhBkPG||'Y̦ ,, WcTThE2\)4yX9i" ! kKlRZȲPzؠ^YCʹFk"UTh[y&9T~T]p>8l$[_ͭʯ.D\F}M N:]vEOZƖ{} }^i$䂕{%Nӵc9Mv\ 5/~,̢$z/s:Ƽ\~ZFحv UAJ% YĎ8)lws O2IěT675RfQ\׍r$`g+1\f\xjQg:b""zӯͶ45 V ]R4gbd,֤YkK*޹킯4F5n\ZRηf`ьlaD}[.}'MJIU x|8i2bu:ѡ8z]4qsL/=Qlj>@ d>T],P=ig'*W6Z(ѷ\nد~4Y-6o:;(љchs6wmgݾ wYTȭ*T j E:tV}%l%E,' &}@';a&3JU@EDy]%o$^aDi AWgZ6GAfv;Ģ{V87g WSsD񙩚ңׇnpc_c,)sRSAH QUZ8*P]ػ1MsKj=`)5w/)[CށPL >nf;QXgzZ>pu7/-۞;KރQ,9|C8ª V,=c})ꯈ$:N[ !M*tJ R 14WUwދ 5s1WQl]؞+GeO8F:Wz= u Lnp\,QKo0\wNSE,;v9Fnio ͮˏ;`}0\'7JMFqu0wr -z.:] kM雀g)oK2cgcSr |Y4wnIlJOyt[ߝSl1c'}Oa >j9l73U`V5.ȏ^u ٗ0o2u(-[&XwQ }Z!`Qt~zm\ӪB߅S>Q-su8OykBńnE Ų\΅jK&?`+ihXa Ec&KBܺ"!**6à 0\3YWk+)&Kވܙ(j/&>wW>vR1lW$q:)mVtP!k}3:F\؝6ԬkYNlM0& YQ*g*g H7\1Q,麤Ҥ #r(N0nnkT@p;&}{1d|ѫRk қ]Ŋfr3M˸`yzY{<|-Z.O(ྥ(lj6}b!P)ܹ0C+خ 0[iniKѪU. +Y7AKxvagVvB2RZL{y E^q7THI 8z63wuqSid :@S9DcV%#ha+$IVQ=^0fyā#U/GiEsOIAbu])N0=壔QFeYF'L=`v2o9e83yడ! D ^ZNH] [{`xU1.엇sܮT ٛ5onWjzQܚݞc yBC]&&gH\&\ut? p&z  S.NznQ|n9 Nw!##4k⏶쨢e/mL|w7U[v0md& )UݧP׍T9!Z× u9k.zZxAd^-|>Y9:vp=`qnH[e;#zq{b~eAq\/a\G&59=žڦNf߰_.0F.l<"'rzi&OݴOggEOG7՝Yb=ǥ祽 AVVļv': !aj12xȓgvUI8C7TaܺAqwtm JWfHXĢo]3'S{kZoún͎::gnMn86Gw[=۶R"!hV^ش˪4-cc [pڼyI&|r;õ{pffӖtuJx+7돝Gۻ;m+.^"gNbEə'_y&P{L xg]kȱu'-q#w&OQgtBg}v*ft`x-ж= ny1 l--:}:J«zK&Ÿv[3q?6fg}X }#oA\E<8: 5!a\n DtlMnt;֬sxA/v"X0qo2Ո9;7aۇn nBL[ڂ`WTq1j-ڭXxpSK~un~'[nvjJף )^X<=! ?W}f\O()_k^Z4>)t0g-A^v YyosϝQ,=-Am z15Xʃv (L_6tE 2)Iiͷ $g8νzÂts8Byl:Xrmɽ<^r("&/ܽr}c$ICPXFűrQ&|fBsH "<بܽȡd* 6\iY&PAH׬ۦ$<, Z惖bbLj`bbC EEҿNOǨ-W8Oח֞LkSwp!+{~]'HC{aU{gU#![˖39㭀b ƜO0Rι\j2T/X5OָX7"ɕ|Mvxyj=bXݲcnmWhmxۅַ*(rHd$8$[svUq(.R,^RY xAALEudɜhp-mepeCAI!RWrI!!EPA'8,FN&~Scv; 6oi+n\Er~͋ Ya/gn>srme*=(Oݑ#s(r=~ֹӷ]oVͣTjHms~ǟY~Y&0&2)'ܡd  ғAh͹_욒M0)dJwj V-U2 DEK+,QUR)hHSmT ¡R$@ y'zsw)aͲܞEp?S~9˥C>fTQZb +tҍ)nud}G)q2Ȏ'uMtnUsDEI*tn=" Z嫕cjkoj޷ccF5L|ܢv &,dsN7ޯ8Z(6DujXZ=mUʌߕ["Z$# TPnoзk56#XBSyL`T9#Z(,X(ŇB8QeMqtJ@()Fj}Xn&>(=~k+r r7͍akޯX+Ie'ExmstNu!C * QE!ҋYÜ@Xybs,Ą PlN0%PPb6sPEͮ(k~1 (1D!5f"TH QMm?'PQ+EjQ0VgN]qpC__7u؆Z$QO$s7 nTUq<.`:@oEΟT橮=wo1E[l)kȷ$OZ2y. ]YQUx[&{D o2C|0/=/߹^|TUWmʣbUlFѥ"DDM!j/26w]"oxo_YyLLE1)Vj **1)~JOSxR*h9#"nLUU#ƵXC'z.V @C~nn?fq/FeBUbtqeaSͩb˙i}fLaaXZoQMj 4JFywI_rMwFu:ZsKcyЙR|iD;A7CXM!Kl?s37hT)Nzr(&KvY1_fcҡ׽ * p_xA{J[Xb3.[yi>;F"`qAWKUs{]Q&;P w7zt=1n%vzf{\k׆o{6u/G<JS'U$xp$^4s#"R^XvsZ9&@C1#r74y)wȰBM*_=?{fmzh<.KPp(֥e`F>ieW {P w}=O9a cqX͠Y.ͧO{)ei ;b܄w48ϗ] g s"e՝ K>9nd;ԬVvs1V2w`ܭ~jk#Ƚ'Dcl.d m{l^1qk!OeΏ˦jn(c;qe/adgaP=POUKNA=s*]j q(c#64  QY127hEK"0dFi/@tJGH6#mߨnOQ`q )xo1 .R0isGL$uBei |C4- 6>N'8 |6) zrʱH+DQT*0U8d"#庲^g0x&Y )|zIUcc/s|r!y"*nǡzfj\RF 4xیU~{j_Eo׻qji, OqnAC\}guD]/!t*`˯M+I0xui2E{U!%ża*:b)>ιxboP@̒wMKw}udaz 9z>);-|;}9;n3w=:y:T1w/UNp@7"O}:gz'Mw$뺭9zT{Azp7+s=&\jp}1oܖ[ _IIJwi5[& CuABSz~]Ƥ^|pMSxhz>Z&O?{iC|]}- =gwS:Ơ\st>[udo ‚7e1f1C}2#7D=!^rz\-wg#)|tՔM >%cs^ureFùeW!]^f,bH78롏N4w=Γ^=[;a(Rve gob<(DQ~H(\,_0@.D:g|^̞XϧԳ5΃ fe*֝D)B#Pc_Oi㲃f$`8Rf=Շ75]e9wg7}9er$>nMU=;(y #eA4[%suTRX)vez}KަXc7c| *ܽAsu#l @?'rי^#6 U0 ne)J^[<*y8|uzrf9̊~4~~ l)΢V73}E`TUDgO ikf0|C B@!R-Za2Ps,dp]Ŕ5˘(:خnF}*'iyhrZS]:bP$4"xb]Ϧe2,82O2CU(* ~}T|oˡ'f7qN!cGmSz5R~Cׇ&Ж-qH;Gŭ"l}):֑' _ ;#9I*T-GWd]o湵2A3kϻrOMjK1 JvEbY!Y@Dۈ`)&"(ls 5Tqsi>]; I"EQ[VANssІ$ԁ2O+ZzծTZ+&" wjw$;!BڣS2bVP0Q'UZ-V`_0F9D㕾ҟaRC(Ǭ*iQBO?8Ryyx@,(0uF/c")0䭦q=Q̲oړ m_ݛ<<ߓz*cIDAޅw.isjb> ??!F!нk/T9EjU\mEEQX-\أ%WFhs77Q.WQ;\.b"uV+Td\@8[鬞ʈa^ s 4;FfWi}o4s5G<ӳsdkjBYvvmc` HCbv`xp6.H9S':xX!iFIm5vi^ŕ{+r YWi=wp9xwvwVBaN-,=9ssԓn8!+"Xc\Ũ-%ca Dd뉴_˔ s1+ ֶRc8[ ssgہ%lDӧ,c/A>6@exyC "j$$>d堺|TUfyKmqŹЊ0Bnǩ: cV '6.7:ǫ{jGxҴ '46M:hS]+ܗH}w3ۻC A~`YO7;m0"O! IVQ1i6&M1WOnk͉]Υq1!<CՒmA6^t$Qj^*+_-+[Uʨ,R&?;$3z<ѢHso1|'"'̥Sb8;j8PBF]_T+tvSq&*I_2C0)H@ ݷ5S_>C꘱kܹ9Yc֒+T,)U^F1FAk7޿o1̀b(J/l$̰X@XHd66 `x/J;^E5p#^RggeOcH]FP#}H&C',zdY^^ؘwV}JlzۇٛyuoUL9Lf3oJ*01$"oVPמN]qyݼʷgr ؋78kŴ 2')D^L`w{'QTBZbNfzgUЋhPYt1Xd-*Ț:&:kbݭ: kHW[*KJso,]}fo[yzOBݽ 9POws^ F](E (Ĭ6Y9^^L~tX$5uR˜pN0!CXxR}m~o;Dql}ynNwMɏ+Nboc^<0k=zt;b _]|.7i\۬bvR"'JDTNeA(u da*mmL@Y9Q*[Mp݈StaKuTaMW(nnJ&A5>.TŜgC1Q]K! !3kS1\DZ*cS3qV k>rOXllj=cMDw{(D=>O\' 5.WDȫ;6EJfR/ă WPa 6GHRy#xQGYl"%+kJĭ0&; LHM\o.+ D}plqڄq IHYې׾PΆ)ں-6ÁȭL?pxNע\7t<9k癣 a~)"LTwbtu[{ΟvmVl;Os{2>C!Y.Qtb洑6ю"oAr(xO:LܺCȖK)8w?mFcL$>-l,f*" ~kgK`]q$NOb%<):sӤũyusU±koNg]th5Hw)%a@vXi8wP<#oM- [beKܣ{ONB1Kp\ӎԊe1_ }58j*eaKD#%δx*a ǩG[\Zaz8g`>٧;T7hɡ6ehV6Zq= CݐTK]G_% Ok>櫦CG(}/KH+~{LF{'F2C5sfh"7i$b5 ˇm=i4dɩL3QG!;S c5e5]rvNgh;i.:n{= b.Pd5"t01:r\:PI>[uc2«W YpnsֵuSrߊAc7n!T;:ֻN /oU48yrjzdy*ތ /Jy^iFc W+&CKP;wYXoZx2\C0>/z6NZ++5Ew;gnˊb'nx<f9;'gU!Grwl{w!63|dK;/厝ssx8(P1vHZwq6LȽ/f 9SzN,^$[/:#%ؗRt("A7;ڧZs> П=js0Fqf:no98^^ն\}kǹ˓`6yo@>W[Gz뗬ȷ]=1?F#OBE%َ/ggy\Uݿ.3BŔy-Ôp@wNU:!4/U؉oyޖNq\Yz]:b0d7-^r[-CnDCݯf!$oCjnh".ؒrҁ] 4mj)~hvf=l* l`[u;-٬1ffU L&Jmnޕ ԇ xCQ}FE;/Y* 4{4$KpmK:k)\ /WdZ7=߄kfTQR{mg iOg*nώNq]u~1cUmyS0Q-7lO^S0W@dS.K>.~RL>>e}C:.KɁ} ڲ+rp{5on$L"B컨10q E|l⎃'"S.i6JBdY"bDvA^b;R"9RSjݯ60o7Ɖa6WJ;vGPP1[{ʕUFDfQIHTi{yo9R>-ގv[/wU2ԾJYˎ0F}`]w>Z]<(ȁFY|/}y=b+K8Y7 pF_|d: An:LRǵ%Y},qyg/=TleXߩ(+#ݻ嬂NWf%,LzI9h/˧9޹eWW_Z4.癏:/6R3 Zߥ+nN<C}r,:jݾŸzߒVD9n+&:6O0!>a8,!NeU dbB),?wqPw3+`DTjTPZ>"1s&&e(CqQ(,5/E_|lI( 9+c%K!$6OȌ)$ʈT'J 5N T8M%XWf{ԵmLv /ջ6SEk8Q6o kӮ#sO!N T(?4NC\ˆ|}|us)8'*վW-ᢉ+I~ꈈR"AScs9G[=1Mzܥ{OWȤemevKj3)IB}&KoUUsQmE*sEh6$e1#]+ÊR7rCZV*ABcFR;aEutx_!ub$>(LjUbE"?!ZxKUzaЊ'tʞU3Oz4WO9yü~r[o_!ٌ:Tm-pQr)xPi:a%Hu져>;{Ci76k_Wۘb+*ŋDt. .Ub-VJ_a0ƖACVցt94$ ] X&&j::8 T+XڴaB͑AW?4^Ϊdd ,+;TכuԔ~NaXJh%;5r!DG! XMt!-VVxLsmBy^`P^XK.8s}׍JeIaVWmTX6IךP#`)wWRk\zp;~ (E#^݇n: 5STtU M&ӃrURf|֟H.\NtI~(La+ 8C3,AE$RE2EdLP&ky +9eIR|2R#^yAk+ܱJq$˙E#ҩF#! '~*~rׅ0J:'R#.k|cPJ*5 @A+Zulm1[0PCJ hsXbt);6z|dDKIw$!#l>qWڱmbՍۆ6k%ѢGw(l#$fc9عt#Kmpu*pwБkS/-% GZ|0Zm9-XV K'H@7V9컛ޝŵoֲxj5o;~x}m9ۂ/_q;Ó{yg'IadQmq+֡e{~5Yc v[6ъZ- W# tوi}sYiPS%1#+Kabxe[7sDo*?w(B b!R,?$#ְZCBDs,-yj7hZ4V᥷7i^p*`ܹTlq1QU#mKP:8.{BH/"".˹bPPIHICU!Xō~]A{o1 ]v.M$uݷwm|H~N**5Mx)~8-*#6Ѕ3^ViO_3 Z0RCk'"L^cW'nr]B9 W1_}%&;uμv=6v||Qd(=|vOc^t';KػL &3f#Z͉SnF-Mh0nzVi{ś]˄/#t"~tMw5reykpVߩ5qnEK`}R"(xl:ՈYo3 ,1U@E(L VZʯ(A6Z!CŰ1m t aOwnNqO{Uvoj?|O0r.Ѳ/<@ ӺpC 8],D3\ˀ'$ޡ(xoIz" +IȰY [wMX:`ȳyL XtQS9FE<0P Tr6bv݄I@!%O17j5s캧b*.PNe +̭?#ϒ>||Ӱpǚ˅WBrߢWZSTMw4.v7%׽Z+Œha.)EjUG%B)$ka8Y'w%c!wŠf2&M(MuG_(כ Sr]4 VB#eH@)eiU_DFH*&mҪ y)R)dަ 8:`/T]fĥ‚*n͝i.כ*DdײzvV֩MKYŇ56~w}ݹ+k+V4T|9X; XrMkN,5Ӱ`1]6Wap7Kirk}F+!bLo"emj{34qE{m8.*&HйZ{U3FKu-D賔vӘ#Ox 9zRcӐP2ZھNSHכ5LqY4{μE*-# XnbqTS &#,Kԁ}fuչA7Tbj7p}J5[M0yR$ S?`pJ5b9sQF zgw6|".)N4N2nrgv@,˞9ǔfm ^np Y.]uʞ.Z;?{>ڀI+fzUҺFe rY3ӥBWkȌ`m!tUC8l61VdΓ©R [j}K@Xodx%٠tr)ۤ͝n-*jEs:Dٚs"jMܽ0Y78vOB{=q;y+Y:p yz[sD8Ln>s"y[NΣxntEJ`fxfuǕ&;e}prr\,^cV;+`z1\d`K $>i{:qDJu`kJyN]Sd9wGGda=tMTz=ZwUxRiOg8g^v<L.ΐ;כ g8OM[[tz(snyofY"piȰ}<}觢YShǼ=Gt)h- q4gOy7(ׁ[~^6;oˌݝd:S;!slYTzDxfU7=녥1IBA~ܼ̓a^%kCE%N,eb2DE?mt9f֣^^Xx8w|DyA3d O}}޾3>9$oQO.|m67C^{n9yUI/sr΋FOiR-pPDsgR0BʚjBN\;\B.W kY>}3/[[O{CM]&b^w^BH*c)+ӑ8<<=~xwa(ЬƖbخ1<` )hz~ ۼY@oЍ]WQAZa\f]3C#4PS RQxmPsDz6٣M9fNԵU&]ǛS9x#ڪ9{ ׻f#  Ojp1wdTm[o3DS Z;J7Uo]MXveGdk#g|ۧGKR(KDL= QZrIl/{G!C̜E;mWd_=E[Z-S.=A!`61zyk]T}hSEnM>aoՋMbj'>i_[m({;L6^7雄02E"֫ے{-*]ǹ)  AdygXIRI M@+^+Qi bomU>JYAJԬATHo]wVNG9bk#2WVbVPi_I sE^<~G>f2ܦ֖R[BD̰ Ƚ 8`&9ޘu_b ߧɼ] YSJߖlaxοozZ[#UrhTsVlhѨ1gƃ%1Wn똍w8rwe9e88Ŏ۴c.R1d:`%Qhl[nQ]^-W92Ȋ{y3$uݣg\:OtRsy.#9^]ҿ%sJoQ[$_L!Eü|]z ybpc^6 mQJ%nLrH`[-O|9n=;]ZPcuI&}r^=2&0P!_$1qg,o;Uzo[ccbܭA6r -\ @dduҼ2wI"R &p:J48D[_[JUvފc45MS p=' |Ciktt(k UnK+nݦ/p"Ì}g\zrwro^; jJ5r֤G~!!8MƯkx54X*֙Thߚd+w?xUԪ'ye['"BpR[FTHiyp \TQY\Kn·$:~`~~p﹔hiwjy 6ĀЀ(`X~,i.Bo9_qQ3!*mCm& ,WIauV^!*ONz{㞰 Q>N2b@h~Uͨڒ1؏+xNYXAb,ZʞʎLmRU'r ANrCm '!_xi:,UBҢ{[[hlRyKjՆQJ Eg5*TڦnFqmje(i^.:\:ǖֽQF?ʻ{O5{ m *W6*^6ۑQ_\6dC!L^u&I1ZhLFQL[[08Zg٘Srn7[.?*^ɩ;VѴfV)M/ c=r2k]zeߏ6:SYoܠ׎#s(aG7W!]8~< ԯ/,{5*zITeBSSXW >^0Ē,jd10X4&LqAUb{K&Zk0E1R4Vc+}N:is9PWU(v;] jW2{>6QP׎#Yp$!"p=nZoN,X\qU aa)kQs5dÛ8wqYu`X(lGSy=`qoͶUTlkն5TkdڒDh,Rl`ܽr&[ jb(Qni1>n *2ܫ~JǸ= 5U9ı?y{Y &AJRh<|2Y^e[Jt{0y2.kt7@):FC̭*v,^4mBS{9 \hp+ qw]El>dd5$!Y`c.Xɍwt#Ox#m1@r<:Aj7a|u+13&S#א"TƩ׼7k'Yy}es[-j4{\vC Z*Y1TUSMB@kG/w9]P`\gO8^ pV3=Cvvc,mj!F98+n9vZ{# Auȹ.47}ףaF=2|+e% {0ͯ#`;KF^NMѠuxN Yg8v-:񃞾lDoQV>۰Oe.4*saa8:RW_yXF\]'v/(}9>J$Nw0{<)MS|BGU}xr& \|Fjq/ 馻0': ,חQ= nkUGn,; rKtefIC rqk]%J\"O:F'{g  ͽd.lnX`t8_9Sϫ=dUx#{~NdIdCs[rTJ =ȇLE#cfmy6_| /[v:y!T b 24?P.MLΫʮ7|wNwr)MyC厜^VUHuupd dro{#:K};,!vR|>Ƿ,pߦӃ9L &IphHj*cN cҗnHzj`nq˹N)\TrJ{2͂mu^z7Wmvqn,lvn5M^.ѽ8Nmodψ._46)l \HfWDe% 㦃vIf/{ʹ\N_9\.LXT PUL<]JN/v.kuVN; cv#{ Y\Y$s{fKCv)v372|]-qPyqCpwKH'Ur#f5% |,.qXhsj)xB7 ʶ!NVȳ`|_Xכw mkc@~lL*5;yw{.i=g v.MpL p18i1?4h ;^o>:;e1QVKxU 5hi_ I۹9;!pFuWcolCZSVFl>9i5._C,-%<3G2gm!"Mg {sBk#CNQ.编lʌ`5~ XOeE9ˎfjQ\s:KF#eiݙV#fv\|A$"85.j:Oݓ!zˤ.cpb[Tqrj*]-TVfe(;)@r㼸3*ql܁6s19ccg<*AV!D &3ej{@BЧt# %aIU:XXs0b2t- K pTTo|=u2ɣnH`< n{{'8Ƞ>xoJF*\'3fst+4c<3wRu=y9ڊN=%G%yb}H̏4Abǀ/.j5ٚ_hZefw &׸ {ڝ/g`yO|`kIn<[gp4ND]|Wo Ujo7HU'z[^ꌔ4N ut)24/z O51LY7*əz{"{8%\)Sx4] 81 !p72f8޸P[^ LYea ]f,vd-1kk)"O'e1`&t/.QVqC]9vc7kEL_2͑Fj]ɹqӻڴTLo+/uAQ}YOpn9Rkz r=R.o-Ő k\ՠ ||Xrz}J͚bkѸ'8ZJ9 ;b#cU,uD55d`niva%K=uV $4lm'5֯iө);Ϻb~Ui)=Uy,͸l'dDy9i .Y;]ރ|zlILM(uft: !pۢozq0{ F 8AN/p缎5I<i>pY*1z8t%QvD@90ٗElvvkm4% pu`w0m޾6O]!ե zg'lK6dC{xYA^R11it;bDV7&D˶wUPfVʊ} t=H)gP_3,d9Oa‡5MФ"ejw(%% Na;al?O)FA5E*Sn ' a9/@2tµn#J%Q|^SuDܸVi0h|TQe ysjc[ TMmF:㎎LI$HK O󯔖IGB6Ʒ[C4M* Saz(هO)l^oMO'Nҙ7CTYdTԩSQg:c2(AdĀTSbů;Dlok)ܮW.dmZVVc*|sLƱ-ڗ3 1BN}o_ͿYwYb-Ѫ. lpc kXߥ)e+u@"J"4ߔkANoíNU,Ϝ˙aZ@P !Ģqg5OC$_*Ad&1 $Ā Q+5DBwxu|淗dݤ4 >J֨M4b ':vJ*6Z mmJO n" qp̉El\'TNmdַ u8M8-NRrV,76v㻙gHN[{ܾe@>$+T *\mch*(n,*B(Ɋ|yBrgu;>5nږD{Z(W*ynٸS3~!*pg#5 H ` dIĒxoъRC'Ø 9K!PU ą5*0MMAcݚ 0ڹ2qaׂ> Vjڈ/B@䟔/~$^Ks[9AmޣOVS&g(~Hy3^Uw{;FOD}z>xtR,QeZj#Zr} k$!Xƃj-|sd nj*Rҥ+J-(da]ɘFcһ)IQcƼˉ. '-A +ӯZ_hO1$x OT"9wI+AY G&a’yď+ (PhL5f(Kt+$N߼D) z+kroN>0 PROtK9݅IJaH;k\+^6ޭE[ܹg[l]"+wؼJ奦Zf%nc]UF1ϯS}{v ( 6NTlZks9$>I1%@N%E#~ϷЕI3'-B-(Ku燠}\}Ý 9d]|Q؟\oH;%Td yb(ʐOOt6m,^Y$n9ܐͲ{M]C UOgd^2GE=q>;t ccq nxTޥj{;`Q5s;yd>!ʗ6qG>ܝqTw?eMod'+|V7SkcWħ5*1f|xVmcmnu){'?M [و6z 6ےABụ̈̄5p\T|fӧPy 3E溲vhTw(ᒭ<.S^yz3U{Gy%3\kU=e|Ưz6&./Yd]_.[lI{LRW-U9gqR/'y 9)pp۸3Q0vsYn;!RiL,3&s:9ffi$0k* u|){f\.hR=޷sF<+|Jcτp2-kHq#+.oDUzɦ!c9>WRG {W/MF;^X;CM-k3#_#(+WF$i]8@#8:8$fMzVT3ۈk[v019"OM.A~‹ RH+_S@PZ<," ! \P0z!ΣDᥒ^G5%JATqE]Q;"NŒ^b{pћB UqG$ol b%f<Њwll8\Άi,hQE6+źdQpaC#B]7qGN*KˍW[2@ݪbI 8h; (-ۛ2BC;Z/ %8FdWOnnPDG.kL?i+#Bf%S@ڭʨ&`$ek[e!Qv6Fu$ޤU3gX;K>[m8-1@lx rTe}KAnc2F4A^hk@, [92!fo"Q "vz/Y_n=\|b #Y/_f^)F=ѳ`(Bqg_wlvqD↕ eNnsT~HhWcsj_a'zgN+}oqz ly>5UX]Ս(2  r0[}\.~']C;ٹѾBZ-IJs,"׌s 8Xzw/%V}Z]r{W^Z6fkH@z9yGP]Pa5YΠp" Dq[4 A;19 p#~Su;WX~'Ew}|sٍt.w8U6h)| 医|KTnYrォ eٻپ}tstdÊm- PaǞ 7Z`>Umo;]ī9/^33p:ImAZ>:/JvuUh(0\uvAQiUIz?/\f3ĺq{n Un8/GQ1Ȧi( p;Uqy'w1հs)mY o_e}yNMBalW.ןozdwU&mT}84"+wF\vrj.aҌ 7ӞY &7p;T$4FnX_C݊[pFHRCGnt!IcvV-s{D@7B#}EQls9lz0k$ @ Sڕq> u-}f *[x@\aM6g7DzYqwaɷ2݅}|RD?˺-&~i;ݫG TMBӸ10r/JWBRZ1no >4G|~D349oҌK  kމVfF7\)wF^;uRi }F.ꍋñFz/ʅUH7n9HLYé lgC}]74)}!KtaI`o^=`p8MNIh0͞9|1.x[ zSyBf1y{@ʘoVkW>v'0',yF^@AM5 Id.3%]s;I S I}vuyanRNMsݫTzC~恘JmcMߜ:U[s/|wIY12@AC!ToWʫ6S1x6,s)D$E}׍a̭c |Ø}u?-}jɔD͸ָ1F!$!V-k+x.j(sAUmȩ{fYU(c="aL%˩A-E~@oh&ըqyjz|O "1QrUi7n^-sZ/_,[Qb׎g:ƍQE<%$D롎Ghewn]>o;獘xw:%$])ŷ[n;O3Ѕrhш/;u _b۾̜{x  S G1 ʛbl9YW=dG@D Ԭ:H A0(`*,U$ : S܄AA^ Ҵ4qU;Hz]nj"Čꡎȴ*k+PGQkv a\ɜ*ikIxiy`Q_ӗg9":oͭrEEWʹph( W9C<2+UU1SsUQBG<Cȥ_f`(HN7L-X00AןdG~9uT|je}3[/6[U,A7j%ö=NGpjGڒQ+ ۋ:q*ަa<Ȱ曓C&N!V_5v*Mb*5\VFe7FQ-ee%;SO[NG.Dӏ52Mw$Ҽ8ALj[ˎ+ Vs3+Rc=M?퀿/L7j<1DC.&QT4"r&nᛕKxh6[ŤV?q8Ȣ[ Vf{^ eaY $_nQDUF -Er$urB+*|Q+bR1'6QT"sTt@4HJk%T 10I6~df~w;=!:=hȝMMȆT1ɷM5K`G{! SZS.`w9: H *Bd` rW}vsW$wn&SW9F488ӈqAA*Мu:03Hb goG!g4hO֪~u,93ۓ# `($^fmV+Md Ar Ɛ쏝~e)A6<-yMaHd1Tm_,$5qsTZZ1,X%sKr9RU->n6+mSs~D1̓v&zΣnRSkUC-j?Cۘe_pЩᒃBmఅPMn1/B3#r}A$4=FtUpvR!Y(AQ3WoI^ '{<-cXh"F UbZ*LXUjT] wJʄ:]VZz53󼖕*,UDDLwxϿ}p !iЕ]YB;"(t7|.@M;yyJN=Q}8s3x{u{ !|4/mve7sj=gS;o(+z[Nsj}^c՛ ȥƮaǂe47=GLpk:BREڧI)4gp/G1.8>ɪ3^ݹvt6$_1豥2a)xᢓS(0PF'{عw2}ӄw!&Z55>TɝluϸmI snw6Q'A,w:Kbc{Gv&+.x]MYH`v"7]p.p{UNy!,0ɽסfW7CQ?Vm+φ1λ;^fpZ˥y7'7 u]CCL T^ ]rz780BB'vtdȭ*¦k4VK9z[j跔7v'}= w6pc`_7]f$Cyl^<2/A=z.-BZɵ80'Jo:v{Ӟ!ߔ"۶^6*86ρҹ:e] Q|[ :Qk/quƠ1 Z_mpc^`ޢ1GVo N&0DsMH /vX59%Ġۿa *;)|*@.sf<=#AA֡ )OoYlPE798y3^i޲^_M6Dvnjʆ-б5͌Bj a{,7qphע4$1տ'. TlX#1ss@W.nk@i;u'i/"S_n\-W|xgwtKnY:ckRّ&wۓܳd3w'ɟ46q[<14{8w#rC=Y/>2{]KZ}=7MAl=Z4*z#3)0\pnO ^h 'ds&V^nb֜ f&GڸIruw:v%2Hި&<VW4dM\2`1]EjUdf~ܶ·`^o2{iY77~͙Vzp|˛GÒdV&jHd(FhfҨ N9*=u{ L߀)sH̜nfJ0%.>QyEJ*: e4*!Ww;F<,EQ{:fՐ, ! _![~bXR0HB#_V%DcTYT.!](@{5=p()CizmG?9]΁x _ A yTG7D:)DOZ:Iz@P!VHg$K:("2ͫHNR̢e\Q[nY2'bTE,'Ytvm |Kq| { **,Y# M"r&#Yކ*.,)62 @T0(Rwvbۧ ;ga/)2MqzUzѝt KB ajHbMR0ߩp呜Roޫ=`7m&{ AaBIvxL!} ;G0וd1xXA]h7;̉m@(F]FSuxҏk,X@XE;'FYa]7.1nRA!m.(,Ֆ%\O ͂5k7pA r3郆I_[`|όwv8ڧ ǬCs"J5Y{F<;Et[v?ε9\i#PVhgJ9iu$aǢ 8{h%n:Q/kO8tEa|Dxi5MsFmŨmK@P7N%cӅ,MT9݆69bw5剾1nslLjϖkc3}cı uvf|:@{,!ӛ淽gEk=pdC$g>؆@+f&<M#[@IRUi^띝'-I!!Lk]wǠKwfjH.}d} tI=W60u)IIn8w+9s*'7|yNEoG/Yc%BWbևFVXypu$KE^ 4lLF\Ē lа]'`]L{ԯCI^V;vkJ_Eh[ 5`/p9s7~ObN(fҬ,*[@ow^1ySnq zeTg%؄^\{=b:;}kppkFxw-6@ g|{VdAz2C $mK],4M9Jl3RO׮X#oL&g) $wd7&ݝshN2{u=oGw>9/}E+{4WLՒ!$vbc fyq=*7sD{:ި{\A0{utuRW[ayde^_r"0qF W#}Mqڴ,g %lZ[gS;!~ *u{aӦ{^_(WVKzP7rvnRãi-u;N-wcbVD^N>WHj UL:3c)i9 z)}nǾ*E]}*U)DXw}˕r^dcs ᝦҘozb>ۚ2DR&wOL=[:GݢwSzi)9FF2^#3VDsDx拉׾r9u1XRG{Q3aR5o;v#j-3Jۘ@$f Z Ȳ^x+.{C^֑vb(c#ۏ @!5 3&^\܇PN01$ 巋hmP4I;yܮcLci+wHIUHM7ίhO)yw^p,bF5(mU)PGp4kvD ^eKQ\ mJcmVQ;V {V"6WJۜ繟n{l6 )Kˉ}ǰd>dI$XdU%dvڏ"M EˇqwJns["LcCQܹ;/]}d+`{k*V L` $>J\ t%L;խzLd^_2fOanmM@ =۫wSum)jU_ ~m?n+uBApzd2^WlULmjjXL[uN\]yi'k.nH斎ss>2%d ])PZkի}xUV*(j+%&2)vʪJ 6UhΔϨ+ )L^rs\N>Ө,We-BELxr֛Wg҈y]HQSUՉx!>H>FF$kNUV P"EڞGgmfݎELH`(z2`TgP3hq! jS娴cdwd8-"ԣƢ8̊?Z%!z*x!IT_.նuwi 3dgK ǹ(0[BNfʔFJd+!ā d 1kw[ rbT]apy^<2Z4bT۪pv(ӫ B}i:kPE3-8G=Oq=rڤ T4o G-::G^- q|zrwlZ %bi0Bm,>$ ,3Γxj5׿ZmAѶ-cb3NYAqYP>hfYҊ{MF9眹Zej\ʘQ?Is﮹J7"tt \gL?,ˊd ^fLߦ<Ϋ*"}×`k$:UQG֩9'Lj,E*MdzRU~[F-jbQgyUD~'P׋dԫumNVŸmJf/@2\*C|ηGw xC̚{'\j7l~4GʠA%,M! C2DDϾxn۷f1$5qeןtY-[EhhFm~[CX1}}sP=fsT0J$I iM<\*\1Nbן]9p)YT*-似ZqC7Z˩TV&-]|Ejz AQBxB◷9<+j \xUԺty8e=eeHE$DE3Ϸ(bk12@ R+\EWQ,m5 c}JEy4n6k֕Lޗ}ytET }&uE eh2daqf [л~}nyqfzK㒗){ tm{y|#XQ?zj];@C8XqLMmfj$uF0tb{730'8nvo { y۱b%}.w"kIJ җmG_HO0m6'+;Xg^ZҦ2'lWnB*ExHqj or@7=ܓ#ۏ>"p>mni|ǬB3o=7h?Fɷ \klf *޴(廢<8\=62\ӝw(L޻ݲÛot'ݳ}KfSf.# =ۜݛY'cLݝ3w9 KYR6}YNzz94<zs:g[V(&=|s) }͘); xxT;TW0yWa>c(Ȃw{to9gndeB;]Lfvw6Y:5&G=.Dn_maT#ktrd{ifkA(dK[wHźNo_d{.jIqB-V7F{w&1m7obԨPBt/0faƸo?#.gX^S;(Ouчei;nNr89^i_2c:\/ncl>JXI:ř3.j\xȲۿxե 7uH7|^Q=K^U\yO>?y@8kZ^G:.<ӡY}q#_JɇHExp^9cTw{(Nze+^9CC/) 'w"J_=TWՈY۬M/m %~%=zj&v,o XMZsxjGT(z>)]ϫfNP=I֜SBmF(YhItjM9"99[مfy'Lw ub9W:5Њ].ݯ6^LI4z Q4~FFtΣ;5>#%J}|:ZD\0ouhαrx|B͝ڜYuIBsz|h9!L;qZdBu\fqzt[wMkSsϽwHt tkxqsמ;QGmVF{p14XkxdkAb5 sx4[[(K u*bJd[5ILVYEjHҌ0aL}RQUmpuMSu]q8SV3ѷTԂbRݷյr(U*(T zgZiy\.?1rɚ֪IryExKа8DN7ǏXf,C\-c*Yv<އ5.3kE7d7P^b\DWNެDN5/YE jgy(a єԵӴlМ(dY <ɻH::a'J]9Ұ~edήxo X 0r!D- 糔:6yJHmz*TWjad}l6hRHͼ`V<״4MUyӡ<^Hր(]9F(ua-;ǮɔӇ똷A־S}hf%Obpd4*S{rdg6 T&:\RxQ3vƀok3 < 11MMMߗhQt"Wtwa-c<׆MŇQUvi9T䡱uB#/f85qP=\>_[P+KliYVuviݕ-r&a0>^jYͪ&3x0gi|g3YSft0{}_v*+g4/'IQ+7*@]yS]+U(Iuh L=Nk %5)6,5n )="U@v8]dh&6+1;WebmUӺu/ QM)Hp=vKRЁ/;> O#}2B,.8 k2 uBq2ّҭd^NkHV%v+xo-y;c-5{{Vgq.2gP<5՛ [{OОщAkx(gt[[`^}n ou~ )qԄF$:8cS棒#QgjT_[[y`&z3BwU+wu" CSg.?yE%1Px_,HJx[18j$1n$kt#6q$_b泇Qqz#O2@w=~^T$>r^$^ξ8F0'Cy-XE&Fn&ʤ$EVq{Yʑ;O%B$2kod[Sλ@M`a(h` 5vrN4X4.䖐A/,BZMYͪ5[M-"O)qSS;3J#C'%1GsΚ} Z$>xө96d/`Dm{Nc4Igȇg:c0c.,M\-'g;7eX-9î3T9IՑ0|$q \tw =mG;O$T8\oK3t5eEX^A&ԙ:mw{qбff;G۳">7;._CZn<[*hՑ.ʙ˯D֨nfg{M;[bcB0C^sBs+q mQ&u9͓FvXrkğ$1"*Q-J9xR1dBJT젡'DPS2\YLdrT`Z [n}CFZݱuk_7JSƢ u1JSFe)@~mr~)\t=YTjyҳlÃÛ&Ԟ{Sζ=~M5pgS<3{ws9iqw>L@+2) )W+#І7EQQ-Lq!k򣦕61Ivy*KIl&ZkƝJöh j2ƶW@gh:ZqO/ +eA׳.Ѥ"Ώropgf(Rsc^W3 |溿'eA|ԠUD_[ :1ayI%HC%CP*ETWDV9]/[65䨣ib/ۓ^rܶڊX,QG [>ە}/>8{{>A{L[Kո  -XЯ/+ 8ϴyN+t梨@ݧ,iF.VӉ}s]{umD|Z}vorI!Rƨ^;hE" a켥QbDʎ9 YUSģqBdnPhG%lM6̈UESVe$ i: }9.8. 66UhL\ MuP#Tvo8L[սGՆ>pDUsqi\mr87Bo^=&2on^ TjI]sXsThV)}HaC`+12Mɮxa O6tͪmF.2w3j5(ȉXRZ8~$g^ahOMf;Wt{lYk}-ߎBfo 5O![ɆrO2uڱ;1|!C IRP%I%-XS ^~ƃ^_V/J,YiqqܲjM<(*0&%0sGs[jABdP"r @ rq}7^{X}ȉntRiV{7k[Jptuꫵ.BBVebQ`w |䐢 f7-̖9DO;Db}hmQuc6%R#rg_ܓc:ho8;uf0%¸Ag@쟔gOF}R 377=]tHHYDx~Y$97ҧ&>=KBXD^GYex<<Ƕ楗rz"0Y%>tQII&0ѱ㋖[Nqib PZ`;nbQhcmQ+T4¶'!\J|nb{~~\hUh{ꮭ(6m!kp [[J!c*iᶅP>P[%ER"{_Ϩ dP!a~vh>̂;^Sל-*ڕlvs뮫ª\U6[9nQ)FE,ЈkPl$k7qDpՏ.Zy%EXZ%h. k:/9oN &`uXVmԧ7w+^'V[cQxWk7.$lRb. ;3I?JXLm 'RG.)FݒqkASELmAxl[ bZFE֧u}{ߓs.^kl-޹ML7Yp'e_YA=C[wevwV;fHI>u)\X_KQkM^8-h'br|`g{۬j#Q|E!tϥVsr,t`H]ήѕbpXfkrn _>}'8#=m=%C*E7e/a37i&g}/uZmbszrیVF!8)k)̛F4-5aZIݽ $vZj>@mɕW`4=u1$W nW*+Wt9z:ǁ4LN^Gnk#!-rх=y.Afs(۶U`-Beû| C_gWH;nZkoǞ8}zRw{c[$azhe_}rfo|!BDםhX.ߦ}ДsG̙PaU fCCbed0ɗqնن+s&\:w*eBR W/p+2ղQvvGuDv)x4qoqӕ%q}<kj{Q37!;(d|%_3bc|2Ljȅv{<9v(8iլUxVoȜj9Jwz^殜xw}tQzpCvN8 3^%]J7 q{iKЀP;4@׮36_GwIzЫ9!Sx%ǢSܡ&I=, .{&.q{=\%{c9.nxhW2mbeQC+]EC0FU&yR^yL Sb鮴T/2i(w\$4hyݷ7((8߫йt]U^34~,32G\YvvAX.6Y 0ۺ onTͻjTS> i793C=2k&:nHsdq|);5&£eܨwһ.a%Hԍ]f"ȠL9,wrLV=rqڕIw^a8u-+o.ˎ+OTV0FbwsT1Q&u4qO!Rx|{Y|vLIۥ ̑"%ל*zӸnUG,z`"a2wj˥>8ŐM>F Z-TQ D3iԨ3 %Ar_\]=OYF%CQd&vV&x6G϶2Xi^\O>tg,& <*i~кmwU:z`#+Uۋ$G}AQ'gBa_Ei.vf2RБ6*m&+\ۛ ˼M硽.M'toVٴruШgwލwm8fp&ZXؘq6th F9Rj^sl@GmDxbi.>"tN?}=04"-l]PX>dw$pϻQ"XߑYPƖ,!DGtWglcM?KĤݣ.EUL5lU9J[4 6dP.pY鮢td/"96lVؽtz0 _y-HOO; ;u7* sI[zzXoǐj̗HW5Oik,EgKo9ڽ1)<_lV[ mDkD|8qtm^7VGw9j'yD*?ez 9xwjMbǔÇiefAXӊVcnD.-xiw/g-Ll5)sˉg{m];`˼ǂy E& OMT;{:m"y^BH"%ދg0z$afo*lE N⳷l#ȫFJ,eLMv"TJn/ttwS j5?7ۆNyXtp|1oek:9y)g'׼ m""mJ Y.. o /8>l#!Ws>l}AZ3@ώLy%d:f/{n<̣, >s)ak"y<)[}[G>dG_-G̠3X.GHT /"| nD3v8Vю__D5ex5$S +u5nx|&끁9\q/_ `7n˝@>rdI80G5n]Zn웒/ we=bCdTm Ȋ@ J!˹44.sYwH6$ ={xt*ΚwbDM34+!F 媧bmsSwZ>@Y;ETonq{wO^w濆oͭ~X޹x5x#?Vs iKb֮e7.ĪηE5[Ë́" (jQ-+1n('BHiD4\ezc|*RtV2nc pOm:?z:O!TUN'нX,5'wN^{l Aqk$L6 ȡ$+*4DKkACG*nq5E'K%(.ʍ^t;_<2 sIۉP<obC ܤc|~{TYs̐F16%5zzzWTQm_`0r j2ТgN{;*._C\L *Cy pֲ*&YE-R*UT$[ӺH`.ji-Ik9<( ;ru*v5;u.{[cVO$ ѷ>i$:N^G*e$O@C̮bѴ$tTVTg JQ[V\HsiI >xy߹.\Z,W qD`TaJ@'aڷj-S![XnAm斻uHqՂ}料=e39{`PmXw+{>@A~aQADE-Wo>x"dƣjbsQ$)(ZPmT5 QͶ.U&[DfSK*SyPA/u2>gKϹhƖV(V/Zb6'.c!;~ffe3닗1%C8]K1nߊ4U[޼>VΧQk93sd=Ҁ}K7gtH|kշʱ1XŌ3w.+ Ymwf mu8+nZ'){ɈbsuKmwg̠Le꭬=bPi;2[6A5&2iz\=SdwG<8[%6IkQÿzv;ǬeEI}eEYi jޮ?xc%vZY2U[q:<6ƹqQX)Xe[vs*~lX˄COALe\=`=ܰe9mo͢ſv,Q:%<ԍ zTɑs8%TDR'V"0YkOzg]raDcRAŃ*Uk2;(}ϒM쾨cJwCMUxo'Me_krQjWjƢIa5{x4pD!m H(Ԋ)4.~av(Vxj?ZfMS rNJre;e94\{&_ܙ2ya5B>܌kZNc*;n6@v,ס,{xeN3Ԍ&Elr/)ymvi唏v)^ϽH{:ᆩS`p V/tVbͻ'wJ]{קyl@vM>'G](s}:;!I}D,({DNswʅqdd}y˗bOnj>cpx:8/m,2F(NH~1AHQ;cF1 ؒ2p3!%pc.Bf\wKJ;W·ov 1wױ GjƮC: "|)zX٢R{yΩk:nP: \3M pM%˷[OF _4V>DQ(v̔)*ֽ2<)f=GU<c!E@[qwQSׯKf;RlE3CBrzuǾ3Kco"(hh\;Nhx*A ݱ$פ/>Xx]6)v*ƃEufqZ6@vۨF.6VL'DKt bT"^ΏtN<;uW)ݽ:-6I+UK.XӗƸ`3-BD *Y9Ei =œ?Ԧ?bM|hywV5yQhCz ghbΨo8j3eUެGp:.s}%!%i̜ l^1svPw$(ldo޿yO/FX{nkλMƷއ|'淥p{dćiYAk n`UWFͅ<#8<ͫ]TZk Ƅߣu/2,p?VQ/5 ) 5n3~_fnOg\n7E5٫/သ%qzj r @vͨ\ ;z54}a }ܚ|V=əl7^ :Aьv?vqкH~=`ǂn5}=/Olؽ :N77Vkpo7'Bym69qԺpfCG퓕{ǽwy NŚs-)U, 3s"<SO1ݯɳ<6˂U[ŦҞN䛂sJåӾˋvFvcEO[̓0\w:gr^uOpǨPpZ­uJfLjr9Mg5 =z瑩|@}gL;a:g֌ #jKnևN&|BsŶIF#9(=} (2=GD{J -]5@ʐGHMܽۙǜt8SjmAUn|<]HK bvfI'Nml.'0 wWŭݍUM]~gsXIiv-RHA)jyn(. ]UILwdtb ٺ=, OGÉ3p/MYwGиok{ATūPwh#wi/1//7vqíɐ?{ 9 FD5\*+|{(zت;F’(V Hc/.wpތxlQzKi`J5nt֗|H-D1sf ئvܵ Ͳ+slV^"]]Ze "o 7j| )C8o[;sQ$zu'Z/c1Ebu6F4:a.͠x/GeއaVWuhO Qח\ _Pdz2tw0oNl/~Wy0'i>Yu%[F_niP=HѪIWY6X3\-JjpvwħuWhu4|q~I><-5X.ؖŏn2KqP77AK .9[- oތOxM2J  eerIhsz9PxޜauF+*Ai{!3ݩ6=7SʶX{ALxn Nκ|f=i+;5}dI6sSr>.K^ۀFk>1 ) ׺%,`V.`l5!FL%0%{nMFvļN<~"]Yco᫭ŚoM9aL0WBsJIy۞PH k0aۤo!.Nbv贱ZD#50z=6Ey=K>Lܦ~qo箨I)j gwc&sYmݗ;x-ڽ!MIOH7 [=,ޞı&XN$ȷxdסLs >yXb0:xk9TBod|);9o#yY*'z%]:io;5!ʱ{՘F|rWS=K; xNΔu}[w1n=zJu^0u>ʒGOƸ9Zck8L?=6A Ԟǚv3aNz 0n}ϯ'gF^ CgW4oleVi1p.5-w!R5Í{`~<<1jӨ=BƄM%\T1 j;!쁎Λ;n0[#4K{f#mUxy1Tݹs9s޻:QKڅ"CM}z wB$\cW|}eLCjgxk*2$"oӍg=q{֩ãURlZׅ5qֶh/W}@]27wL;LqCsw7p#p)f|7hkC&;FnPE%<7ˆ،ktaX]<[ZS}zWKa3j ;4Xlۗ;K6:繃d`\|mc(<nW=10M8e/E'ޭ*9S:,ܼ=oޭqg 2Kˈ)v'U{!oI7;/&Y;y%씺1;irG7b홇|횓9/a=ۺ{Oz.`Mfcy-4֯k>^3~Ok c"*aGڏ?~oF+OR`ka\xѤhY|816 fYx7<]k.,8>S7ӷѓJ{%ڽ4LKJ6{r|ri_nw.}eݾ<'O :^Fxgwn.:nyQ  r[ hUz^goEg M+/v1ggYtI=7&C2rٽt,gpx]IUG;nU96lJn+!-;̪\^#Bv(y\5둭Gc_JY#oqu皚NVZdy0#_mZ}MGG|a>p"yG4,ms#wO jey7iCLkDUSdWuA\݃e3pg1(mW-IYJ41sЭW}n;4WFw۝_iCϪ{g=O꒕9G Cmdшnfzp& \c; nK'/si !>.}q_ rNm׆~J 4vE}3ތ ^UH:4D.v)} 9Gb-=3)pli[ ИN'Xw>y8Ul흲 t =bEۉM\fRCHYR+k6G78_/PcUQ9[mSc^aT>|{$]+՞?ic}ch-Trzˈd^WiV9~[>WxЃS[6  ޯ-g{p=^ 1tn.x\)Lλ\*ql5w =]~ǥ])lNpv']οok;*9DD:[R+CNN"U33kEptg4;]=Oc͕(+=kc'655M]7`4$sV:`_cpl0c/ے( wnnӜHw|TY;g9޵dzevm>65H.oTu5h'{ᢽ(}u鶙nۗL"W$]GA}'p?pN${k28ϽMi9:7b17i2dRxawX;ޢѫG wҳ θ gCIMڨKVP';QiC۝ۃTɪ?5=6}n8uT&{;N4TȐ"u9'\@xMEo]G7?e=+A|6=`& ]U9,Wr\RE m<nv!bm/kXDw^sJ"N:P^QvD% &{7фoXN$KYۢOqr*XsctĸמN]nwo |* ~Qdvcr yZ:v m=6cl/YuBf9}z Oe\)_fq<=ۺ@=n,>-dl*\Ho˽R̽vm_xN(fcNDoS@V-_&w*gz dٱ(Kay,[ݐd]֬UX^a厵խ׃2rk nºt)aojÍu+z退 Bpݍ[>;Awd#`7;bL~#-XAdCXe}o[ ː# Yq6%^{F6ݽ>>xgD'9eErbxuWCa~_^{ԩñSěNX֕3#weyp͇GZ:`7ѓBĜ279x.' ˸z27<ɇ=}[ hGg N7x"|h|)k*WlwYϴ#(3538;5猂<{o8Jw=ZjdXňXyʆ`egD:HA`~$:1կo>$ޑJs[OF}NH $(xZwbh:%6, d6%8gwJ`>ܷY"?vi,K`=[sL*Ɲ;N+hee:ˆq8x}lk.s99Nht]c}2k&Og$")Z#alя{nҗ0un/ޟog=QT_{=cqMT­mMџE; lgrUI@æ?!dJ^+c]:5]x2]⼉z. ^+H7]qCjKҎx<,`&\$/K離 P d-Jmf1GՁMzwwḛVrg:}ws4{n x}"D ށ1}FG7srtegy?͞Og^UD-=جs/;{}t778 ̨6I/,Zo_A-|}Lqo,&:&%cd IcPVkK`WcoMLtY.}؂^S.=HvmUç8&St흢x== x`ZvلΆ Xw9 ѯ{ A8w8ɸn!Z[,/Rdp´$dU-\"vܱ|AԚq1ap)=ѾiCHy>$SudTN:^Zrwf_vŊTZL>ֻ00ٷ:v'#] ':-t^3%<<:[nذb\h ^뽝ko$G͜.9|vYbо3mtdW;܇ݝCU2y+좂K=y[_D=w $Z#dji :Tm0 s b^cޜ^zYê [oTH-+v>FDoW7=ӥ{ %ͷ=2QC }yŦ:{y Jr@Sc2VU0[y )7FQ\8\=Gtq"{%g&t} l8]2Z/os͔}I<36G|MIܵ+ǥ'2B}= Iݧ,<{&}t`ot GwtA}yʇA~w5.a+Ǝ_q;eOhu1]ǻ6%7u3=4Yvy@C{2jǞx_mr^F,哳79h gz;װl/xYOTL6fZ yf]F!V/b}5_;,wĕ% ;ٽ1tSZ#")ýPޔRna6,6Ѝ_=<[Z<(ؾ,^Iiް6쭏kދ6霹Lۛ^?ykׁkicԫӄy|kʨ:[Mg#7hDp> |t.$(˃l^|3ɓÞSwNrӐ'ȵ*Uxcg7[ 㑾XṾcśje+%݄5wiAs@zO)yAc"M|T&yªoM[m Uj(S+>qƸ9r_gGʷz>ԵntzBOHKup6Ffdq>f뷑vz/9*.BS<VҀCs0i[NOOS?bE hbmr?4]QN2VFw&:+tdW %&*1xkOO[΋Wwؙ JNZ7]ĸUݓJ-Ħ.O j-- P12A81b5gfy yZg{v{{Gmhxዥ9}ыWW)O,@ךBzJv|zP:0Iw>{.՘` s޽:]&O{dVsPgrr\zQ;Gf#%CӱB|{I{5D~4_W1 xPepӛy ѝq~HwhFvm[p^=<fN|0Xz1zy{//`7b+d=簥E7.T(K(XԽx\9i_r̛k'zG!@gʷӳ꛺ߺ; =ކ ˓z_u->pY6sYL!f)ڽգOt͗Ҍ6YE9\ Ul&]r[zh^ jl(aunKBRJFmt{},b~(ԗav:0{1{ۇë_NY9 ` qYEmǗg:vMd"ROz6ܗH GzyM) kz͙x%ӽO.Y9dNN-k76qZ'{9cxٱ_3{Z[M DL :#[:nM2G֨̃k2\A熝rGZZ}NE\I'aUzf/|+e޾lX;S~w<$}[h(OR.۵4nԼS2Xr5Gv.l=kuA$7qyA5`m1*%~05 %悔f!7T6VE죷.IҒҦc)0?}X<-mX\clJ }^co}sg}Œ;9_uWga]؞ ^ry8wg2w=ZϵImxC;q$_;myP)B d]"f.4s iS;ø:(4;| w@In523Tx*/ylgi܄&x\9^Ryuilѳ^jX&AXsGV&WxsAuD;k[q攰m/d޿vȑh};<']cb>MZ:3رs+*pm }#;38ޜsvd=um良`:\)&v3ԡvz֌: 5]7hs{]l xf22cszߓ-ŝg=REOXJ7q8v &'{^+-8>WuR]^y Ӑ}t4=4g1M8s@^j wڌgytgp}뜶< ōm܎<fNisjrX9Rr0Ɂd_dEO\%{A.<\ ?9,r':KҷЩ]~:}a>#lXP&y TQޙsIsz,•Dwx4-oR&8 ^by ;wo!czLt{Ӌ9ˉbIp>TLx95tW}.cW:>C>fƚ 5;l%gM`GBK{ɹj|>vz^}O[,Czs-oRr_{ɞ޹UegmX(LsFdur('&QŸ, i2c{8N{#Q1Lx-'= 7tpiB`\aA*΋7/wIfg%C"U_ F<cч]>wKngPiՏ}}5/x^MT"N?B|I\^{B-'׼wh|t ի̰qIvpM^F\EU/qt Na6( ŜV7Q:n5bcG%?y׽np])p>莿{M_` Lq)|Nڏ ziZ5Լqr-⇫*}UGg=sr x=^ D|Bz ѤTi:r=ϟEsv燭|- 54@vWQ#Vq[ ^T??v畊C~[8{)nr~^btI+|E..v3q8tòr|ͨv嫽&ƙr83">=WOzrWkEwNy-25Q=о?#-.Uo|L13wIץ/uH7}^y&xE[6ۗwp9[Wq{n Mfᠨws/3R]pѦjj8p⒊^dԥ` 6PcH?72t3`19 Y|D'P)5T=N^jtq]=֟w5ALǷKZoC#gvՋȺuȦ">W{bXVKRjNڙ]xiT+/栫Cv qjB J\UkB%s3Ω%˞+Ͻv2DdM.>˥9[G }>!s}nNgko"p;|Ōbw9#(cCv3w}C;sgV$s73T7gIo;J c/pdh)jbbTr) 49K)\97og&RroӟE&djtyqL%$`̪B=3rVAn}U[zy[Pڳ + XU(xFu.k?*H{$K~!%.bĆ^X.yrWYecgb3 ~>PzKvDo@=Yݽv TY1m^*Qެx{6_w\$Y]܈E0_\0]ms?M"]Y]BE@̘ʇ-ͱכޗKG 8,~֣٣øsӽwcܚqsk]|ݒN6}Z;HVdpS#=<&zL^}{hWJϛ>XXd;8szJ9> e(){De꘳׻ htOTVoM7570pg'|t__(ŷx9M?NfvAb^ޞsSub3r/M,-KiG_wvS_\bvY9-w>%nӡlʿ{#??GKt9FGcp}a V^$勬sM<]8Xu.厽EoexsXLB~&,dr.b֚v>(nLm}B=;i۞LD\f^{;6=N;sNM\=q\>K3pgi @x,wBr"oUcQ=WK3|scgdf(g @u'gF!/_QƃD2=yPcvzW$aizfT⧺/^n_D+; UOy-QH^!2mq^I}Ϗ\ĐBwfK:K=&U%j:kpŶ4qT'fό>D#F{t+)$oL-| <ފ{_  ً [mkضfhUUcP > ;8Drnʒq vǖZ;i>r~)Ltw5t4)*ɱC۩n|s{^;9Bdl,+/@x^h%LxG E~ţ-MHgُ7*tS@p7!Lsɉ=VtC!ʲ;"#{w.^簧J"nE+3Vг| !%㷂uePPJBV2E!Mw !|-`S.a~#)CiÓqE;̢#:gN*_gxxA!ňli<g c7Vt>g7H[(|LH1wfy*p;l㖺xؔH3…h*x x0/gQ1ߍ[av ʰ(:?hES;k"j G 0{fAϞ#d"I7hjs݇P1)snL[gݳvmOO]P@ڼߋS;נz9 Pk.pwo й\ 9lubmgH̎poi\`!\i[۲'>$G.Avn];`AN0u|KlTܗ,s[J۰B'Yj3o 0pym/H'iS |җm )Kz9=B uM#_&t2$: αfQ1QDz` 8뙘n`t; މ-^VepzDLQ4̾z_Tv3N\{nt$~7cr7 m\An}'%R{PFAoHK, f؏Uy ڊ+\U/vXH['m ǒՑ{ {}նYU@(fjf$Zt 9=>& |VwĈN۩u-Q0r]nC=='N>}6 }7O\ӶJq&^܎a!0v<}=]]WZj9ۺEUtM}z*KZ˙t>Z}f}y7x@eLD)t'{zV$wI5 CzY#4v7#C7og*Хq;ŵKlN40/1v2}ʸo0]!a:if}ލ'>+tcr9tkpKXQεRMOݢA}tu{{*_L>;>1 y;ިa/jF@yWw!&Zf-;Ew}` vwMpZ^ Bhq 4!sz^syGt_\v7K s-@lXn'VwuuR#ʨ|}'ޱWI6_" qMg9:Z_EyH](}pqܰ0K8W1SYGv+跹я<*]䊢kEZôI;,Q}i=H;qϥB/Lo_^gշ nm$z ds#N̑{ q62Ի|'JfK^R<6 vtNvk:Ǐ pL}+0]lܩ)_yDc9+Ӛ_[q냦5Y&u>ˇ8͐{*X7 q.ir, e6kA؄Θ7ib9rXHܓ~ mR>%cZJݴlxB>{1ǽ擏Q{Ėچ#ܞ יطU wz؜螇Nav_Edew\EՉfy8h|rH!=phTՒt݇tbƹ]1O%0? -7Mv/m͘sc8S #n:1ߍӊya=yTػ[؞@ C{rcTE 65ή\FI9?}NJmپ8 W;O_O,|,|2l߼^mN=zCJNվ OO^/کՇ|E谈&xcpzF= hۓHͫALg0nmƎk7w%چ[F_l\~\s<ނ[vmk.wldeΤ6G{/,xq"hV;h%w.ڧ'.,<8Wj{Dҋ_G'(5WV7zfsaˢqa][۞ Ww!zg?¿tTg|b`c5-4x]1/s_\L9޾,'$aSlzݲSMlbxM;}6; M7(@U~ghg&f= 9BۻTONe^7w̏,IzX}nmZ;vx~} m={x8)61zNMa˹.[ oݛ\R T-Oy;))s:I2`qe6}AbI?N9\a,kͦ&A|:9`\&#Aa%0cf#}mvhb9[6msV* ^ :k=;'2 :Eұ-*T;g%kx%D2w{j]>Iž`CWkDgymoi '_puٹ=^S8oAǓp}&to7j^X\x8wNxU{Bݭc=1~^s H?bew$\Cq˶N]P׵C{|R)"xuwUs#_o܇s<QPޙ%t5 6{:Z'7Qq)ݷ/kX;!3gp+7$ }P'=/XIhV)0a^0QI_˺!tx T I'MK&Tt;dmtwch6ŝhJtzxsSȎ@}*AeAZ4f5q ׃+;P ɔs8Zb/Ul7xQB5װTwk.!FO)Ƒ]BWW#ٻL.xI`Px޲hm~>sѭ:s&~;<.<$">Hw ;6JۗNo΄`Sä8jĵ}Noyq$YdI:{HXY=iV`wD'/kG_N;-9[Z8=xr՟9u,2ïn·엻q^Fr|xk<(8gj/=*).yzcXqW\y87!%חw<6>OnIw MdwX;\ =(8)wXSpSef&qGo}/Ci8! iUdvHZ&< oZR3v. s%j2yj=Pcxpq[_{=I^neic5ٓټwjy PDKXHKewYar ۍk+d޷9:`VрmgIm~uagj=RQaKW3_zYug1p)%A"N_oV Tɭw1+M̋WGt]A0j1ks rEf#Zɞ/cIO;fS5KUf 糷ј fsh ʽ<put%9I0Q}1*GU2D ;1Fpyۑ{܇Dۂq ^) ۶F W†Kp\ފwvlF7)pyB@.yssUsp4Á<}eX7.ܢ#XG/ ZqJ*6Uwv>xW{:V k]ʕ&f3ݧlqmn4E\ G<2w^%OV/.SoSNw׀G\ǝC.mao/' )+.9u9 낯B|:] R:4t5Dp/H'q-f]3PC$ +ڤZTN|-W?v:wdYgv׏t1}tdE z҆MJa]yѦ%;-:{ o|Q^fqzVzL h_/sy{1pqH\}.^xu8i0߼bLF=\Ϲo[W-;_o^ :&M91})!z4d:7sˮnL|+FN.XUȆn饸_x O۽Rꄳ`ٚ#j^X:W|Ny+,@UlqH͌•ʵ-Cr7yx9T}frOPn+{ ]׉uSQػ+=zaKaCc'NZvbHq͎ Fes_{%"ׇԬ/ Fޏᕍ?"lAvoEΧatIWm]\($o^*r1 9=x M׻ؾL9YƂ{ޫdpGq]+hb˷H=زnC·׳{NE2u{ӗ4레*"M<3r!KOdS;qxز$Ov  5ʗ=fSl7 +DZ)gwʳk->vqc=`m{ӗ) (xeIM:=g,6e;j#|G} . FGf_xrʤc*ŏ3ڼk u);r^sj}ү*Oճ(Qi-2Vz{7sF-K5cbup)h2F{}[&5itO *5HS87oYͅꚫ}jr9} հ\~n^ J̕b{FOoMeu 78ؽ'$[Gy|sSoQǴȹٝ|ђNV^І ك:Wۣ*LjKʍÂLHؙ`ns萻Gg2q-ѭp)_n㾒 LuVkξݓF\@y`)A8P<&s >UAk;N;o îIwcALuvϷ;VK"!= zl; ])_>46j},>ќDux/SAo[}眲ܤ^#}#M/I"gnX{}l҆ܲ_D8DrL+Scj.Q[Gp'gw.3 s#&]ϙz^  dw08s0JX$c%h͜&%Bj*gX<h얽0LM!G =\~&s6,\9Dv':0<;=0鸯/r I{.6s= Ŧw^,Uk+P޽o7 '6l|:s-Qu`b|*"Θ lx$w ::d6fr/s=%[wڭAo/=ξgnHݾ՝mCoBWUC0^^"U֙6|UgFw-$Pz_oS۲)sEÍKTʆICNesm8.҈uMu[k ː2Vbv_2=)YW:M{q"a,ef?YDh!K߷V"ϟLTg4f]St|ɏw\]~R5aU-̝-͖I3r(Woג1!Bl;^:KTjҚ!`wy4twΒj 3tۧ2^,o= Y0㌷;Wg 7;{tP ¬gpy*1DgLݦewbtwtzϹS%{B$}^Ui=/_6i+Fe+ 4^P6QsUB#>}*8&6Dhe+7s*zO=Ӟ`:WxKX&κ -`0Z 4':kF}&*$(eːBLэD:7ݺ/c>q :=}G,P=D_yUJ_O_O#z'6k } g圵܁ueh{ӏI;!~nYrȶ6˾q(e^̛B] R %ҕɉnϧKi\Գ1зt]UkbYnqcC+t-C<%nIz|lCf9\İaٷT==m<Nf 8Sڙzۜ,N]gKS §mR.{ì 8RmKxBT w$7xxD^]a~Q_+f Κ2+ۯWz>;ge1:g%oZ֫{.Pۍ=Ƿ* `"mI+u23J~|6<+NLս) 0Ns?O)"ww-|=],~}>sQtl|*e1e|t=͊g.[ϪYrٗ xQ^]}gc?wy#}K#67Hq}+wM_J͙,A BsqM;țP> r;oo{\uP}Dx]X|,!T5Q:bQк0^Î*6sWa?gK՗׽z A Կ;~.;b0]""=v}v4;hSЋr+!Z&=Q5!\9jvTɟckxA1תG;6FtTV|H7%RƻRIp_KY\'fygMο/g%"s-wt59G2A`,'PؖR-+eN;`*W^umh$O8#׹颤@mY{ձּ} "J/u"j@ b[:]%OH[TSoRcȯ(L o78phq546v[sػ'ʜXS56lAf=;bzr{kQ3 -%߼yǒv,aj*B{;Y`A^@"B' n}ѼAuw.yl^2yb*7YWE{R}dznlGki<Œ=:L&t0pɕۼcnyRSs}-4t Er8'dSKm^0zigl=\|{Adv7GHD $svucFI=@"T?D!_q6ܯEy W=,A@PI֐y^Ŭ#n3\ ,NendcG.y[[9C6Rxdwf+ sH^ܹ*|'28b\ZNV[Xs$gHZ_E Iۑϱ̺}3<4vHXdZ;PRkRݎ ׻cTZZd5ҲeZl\{[{ zNڌ*b\ e훺X!gN \Lj㗉{}BW$;f3_SK"!: ! L/vd;ny3~6*C'$sQnyTូՌ93{WLi}\ 1FRi6H'B9&nܡ_1M]5ۚW;9o7&۽iN!$>]6~KGC׽ =$![Xl=atK28.JZ[ctk "y16 \-yomWBHڗ" LXm=`}O;]MtojaڟnXfx`֧'ԫ]e=SU[=ޝswL0<) AӪf٥ 0##9NƸBKK˲zbkv(rY8Yyua@ڄ:A ixJZyV@gh`nнXqJ=4v햱"6U6܇ vSO}r/r(5?,=*zKJ67v>\y穓7FY*lV3Ȭս] (2HM̂KR7mf }V -x#.>&4tGM{R6n.+K>"+Uxe6wϲ#C|/>k*): l<&E6ӡw[뤌<9Y?:7w K#{RQGk!۬]~(C;t{|m;tdӚ^xL!;Xv&Ȱ]ePy&9tV%fJ|磛~U |Hp@:E;1<+߶o L ;=;&l f.YE| snMFʬS8^B1>n?o{6wdzr6'y]JkeH('S*;sS' ~îx6OuQ A"flF؍M٫@xj2= 漗=vr/jݗu90^޴=0Tx|u2es9ypɃxy(!i{/1r5 {+I-B]>xySd#6Ldwe9/hj* xZEaXb utL#ˉIQԏӒ#狴uno.7uAL&JDyt邌DCcWoZ"ehKE3;E ʬ3qƻ~Cz" 65H*7V{!n idq^3eqe_M;Hh9#X^.{'QGtKl = ʗm[w*FBsmRԜ(47&}.8e  TI둓1tih׃HlgSĮ;<2>1wZὗ/I\3ز9>eΕ|B}zЇs|=w[Js*w6`$ 8neQ͠];+8D}_ l%*18_"osa'y2k`/>+==ˣ؛w,ijqOVy.(VʞL8ǗYǍ Bݓ"D>٭iq-P 3Tܘ9z-;MGWص=r{Qr]dp%͠nq`+| {6]#}NZ.]1ѷf=y3^ǂ='ҷu;cȓ,Ͱwnc; (&n .LXH0{(u87+~Mg'w`95vk)=eJh*wij5ɛBBO_8h{*>/Uvēfݧ7M/S="-tdnùxA^cy|ւ'{r+pɾY.kJ|!M[~t9OS ids\eγ2[|dWfƼz }b*JqC8l;ގ.{"f0oOB#}dnlp{ @uʭ)Ӻj/"d{x`s{8p4Y/Xp|:V1,#+̨Cڻ =IJ2q9\l.m=}Wszc o>.稛;N 1ͶkԽ.tGo =@>eXݫno[pz>K=o^❢́EsyRW{AyJ8#Ҟty91˕"wd:,-#jk #o!DqyU^~'%N*hH }ǞЮs԰-r'^=xeuv>عzrc/JzJ쥙o̾Vz=An/Kql𫚮*|͛z5u#!elw!V i+z~rv>"d L׻&q<{:Y9+-;^iY^ɽ'AH!9Jt+DSyXqϋe^p}bK/x{/*Nn^k{"͸+^8<2֜Kh{h,utu)ݓ_QDyW7{xby+QWӄ"f=jl1@t+tՆ*jчnH)%**Tfp>ɽ66S6‡N 6on[vqbPͼƲ}Y}Dpgd!]e2^Y U{{zTSeZWz&Id x{<՗^qzaM<@^n al-}CQerN7{}g.I8M-G1Ӧ{Gxޛh&oُuws_JJ6'|}8Bn\[s؉gӴyWSpՎ&zF%cf_"<-UDiMˡLB] GU/;Eyu6tڠPON8yw:?x^0(sztFdtRq*Z^c_Kܻ;uĊ=Gjt"\p ^Ÿ!/Y6vaD!uB+xP0vfTFն5;IP.XʽX/X=vۗs%Q0/mH=-郕[G }\fxuu1 qZXUF(;XHH (t u?'3>#.pA/u[=xoۚUd۝{עU07}fkM݉MZMMa@'Y^]7r.kc˺X;Ⱦˑ..S<r97_ y#פ3p#+Uپ'Hؽ"_XlBW>iz:C*%kq^ٹޛImKL~4x>R RT'}H+6Yv.| SDNf'!۪CEqKVN}oMvodvd7!:Ogh.v;Cm/xBKPO|S~9MYq N[wft7p-Kw Y vJ;+wX.,jV4;{2ދNm}8P{c. bvDvLF^ɷrEd?LYSuFnVqt&BVL 4GYp hU#. ',ᔐ!@6Ayb8]١9JL]oiX43)ݬ|smVǢbx=^.GLOi9pz/gZC^:=&*yl.[{6Ȳ}Q|^~,Ox 3H95 ߴ7η9!FiQԲW䏖pOTq!e0 vɆ*~bSd:y}d6gvWgOhmm^xuAҟ3-9} * Y9/@76) DkW[{WPg^ks3vjݾȖNK^4ÑA+)Giu(k7K2XmC5&kXC7I6dO5jfh.Hs}2FUӇӆj)$;hN D +;4r_ΔeO3vD՛EZ˱ګY'眫.{[V ]aiz`זKtݼvty<]!첋܄Kw,ŕy5Gw:By+{˯+)o^3fn}ۘꙦr{+2kc9[msPߵ9|^.h߷:.N^7}U|~ro=އɆ Îkyx\T˺}=EB#1o8>|zgzd'BtTp3tGέqq M8Yc'F=}串;Ȅ5eTu#J"8ÌU坋rvh; O;U1>:9v3Q=vnVxRjՊc[xfb։ D3FYv7sFL!?3ݷs6;B'B|%<5!<^;l>=Վ[ʛ$}5DyUmƨ{!ݡ ͒>oٗgL(>v2QD˵>]eWXIXVOq\q>:Z"0}e3sqb9r6"׺)>f|<$bf)6!5l&VگsE4HSëoa%*up秌xp\\*R-asA?P{Vϴb|4*$\ӻυ\ЉmǮ_Pq aΰ=Noy;+VRrgN5z%gǫ]Z\en7ë_"@O__f7\jݭj0&n^nk{EC{F&\>}a,J{=eoh/:S&簬ٽ=<|4זVs{woD/oJ#;g(|+{ >ۜ* Ad*햛|fn6wS^}Zݐ%=GY9xJo?\)۲n<-=!9Gnw!^Oge;gյ1Dj:yn穆%`h_"9zzsg5_=ء v[GǔAx6 VenS{U\f 2'],ܕ@UQ5`sU޽d^K ܍NfO{q5dө2 PpYgԅh&u;zDS._x =7hQDdU=JfΌ>O ̝/[ 1tnA־a~ck#zdY@;ƌ bY\Ѕ Xj<7s-JxQ^~Vq+}ъAG/h,eʜ cW\#kՊ%`|rtîm^0wvݼ[lFS-xOt=-l9ųgiഊl`7`HLxTyt-BA!.9֭Swr[v65w._ ApOvݻY69[٫4wjwvD &-Z6[\滄/6᫢ =9&1;D=>:$)Bd(ErwDQtpw%EG%]tGqT]Qu%]AQ\PP T44B4+KH * H"HRM-4%Ȕ,Hr%qr(w_H3`6&;N|0qM#fnI(5e&v#EzGEM#i\1ɭ0μrNmڈYK:9'eZnG14skL쒛iۼK͵Ys69uYՔw,vs[fleZNkUD]giZMݙZɵajٹՇ^fwntfk[n쎈ugdX;6mi]gvVt6 ڷgenvu͖\h\w%ڎɳ[fj8+lgRZqڃ+;;m#8M[[uqfw'vgifmsh*"Ι&՝vgqƝfF\qdgqЅEbȳ:N@mmه!\ڲmQ쬨㈂HmqV%Q6mrkQtrvv5;쬬;Hn㌺*ˎN:f;m:+:+J*܎m.+*;:εYqienGdwZwcn6,Y# ;utQe nVGugEfڰֶpwgU'I6N\wvf'Zl69tP]VdtGYQu5 ˰(.쬭FvtUpw6.˰ :v'eGY8˻:.2Γ*CƻK2"(miGEVRRWea֕wt$qeeGeqVuvVDuGsqZ˱#.;+ NYr]d۳); .8N636ՕXvu8]uuHvփnuwXYqEur\uq]vsgmg]qCnhZH+.:#:YPwQwwAvwTZ9"; ᛺p㻊 #+(룢::CȎ8J:$:*##$;J'.㎈"$訊*8:8mQGQruuIEG%vUgQwQ EU 4г-upqܗ rGQqwpw%EIQCQ--SM%%4\wHqI%rE%W!AQI quQtGQWGQGA\QEtwAGGurq)hZ%((HEqGu@'q$]E9twEIQGR!M%4 4R4!0:8(:㺊(98!J໎.⠨ꊊej+-ms6qv٘gln,mLN֭%k6AFj찠,f CiZk8If6,jಌLbV Ys [me܎:nlmȐeɺ٭ ͭNrKجO=lktZͦ͛YMZfNLݖ[mvZIՉvv'm-zmMgeelg4ѝEYh浭㶶V%[vqtd(6lucjl-kRDDCj? ,۾rs4&( Z"~6rAo2 A)J((NCr9c܍܎YyIϽA&*ȓ~rqP4ҩu v= eNPb hؓ2iJX\+7Q`?MsH.( oftC\/ށ5R1H(}Q!D(7fVAM o p9-zzt"؟ʵLiͫ-98n_m;K#ڥ EA&SG xh/x(mTe"$#_1S%HībW#}YLkǘ$zמ|}D,9'$}ן^h:Dy ,we:qPMb\ŵ\V 7'9O<.Iv[uޅY$Jsk\6elXKy29a$iӁNyCOv=ff[Rn*g9JiYdьZvla 9oQtll:T|%pSJ5bA x笾R"=0n0UrH`Y -IZ<'tnpt*vߏxx0F"4AH;Q}w`T&AUL}#)W; @| T5H!5y)eCqT YJy7t!9aP "{Qed"A(ET-϶s(" 0WNx'آ7oB.BU@>MQo0֍lA2((~g{]8I  7_GtȾd /-BoYE21ƪHF^5ߔ"E|qY0iR VT4Qf\..\RNc`zhќMt<8ɋOIs/6@9oou*}|+mɺP_pKc3UL3j%} ےG<.pS0jI %b`Yk}uF={ o,=,tqNOfMLN"}heʴYMr7ݳCC/Y"[@I@ƍfwwljV. p+\qu%]V^>ئ ~r(Z,<@t (g߿zW'hM\ҟ5fCD ISIAH;G|`lq _~z_>|\ )0O_7g3j ;o4 F(E|<{W"{f?Fh2p>HZмL j#?~ywB( Yy0`@4J ]nI9UZRh, NPےï2o!Lnsܥ,F"~FQ(V K*C Ζ`fL0iZ&[E2X$)a٧,dHck) fFX Ƃr}$/Yy-/ SJnIˌ iqS[d/!˷nY;{Q+ 7${gaU2bږA3l,D%u ug'&B3&ș[@t>p%}1%y!n99k-ΐl}eP&kadն03{\|4N^ MeσYTJRq`=u,y%MuJǕF2t_(ܫ^w}<˟y\ : u7-yNM30{(;vrxh4M%؁70shj|wùU]s@<|+7Io]A%*DP}Wz| CR~@Mۄ^CUV9x?H4;3yvrP<q@2 '|ȍWF)^ā DwWPB\.[6\OwOo[GB/ $$LH@Qԍ `ӹb,w:F L!'^6bs`:)r fʓa:=PC &Kۮ jw5Ozr.kN恼[72 挡8AWT U^t\Zyr-2Xahe&Gx0llELE槗t2vOjS1R U돳/7J{ےwFV*GkM(ƽh &3&y5Fy;81^Vv?]S2 !"}U|XUmOټ@0wݺ99f±BߋwW.I8x{w, oR8FS".AUhDIkP"H(`2!Dr̀A&S2rLƠd?-1a"Fiy%`wf^5dH{:II-:);CK8d4*i`QpdzD+s p[7[;NPP$5bH5-Υ{AE'Mb6abI<"ĶYar-[OXn#B {yn^D iݒε;jd~Wbn\tBsj%Gw/( ˜Le;މߙ;j) ~+;˾JrNc4vw-wkfwP%7c=HxJ%1E#<8qL*xs}{2hA,xsv QE$TFS߷l;NCE.;S;L@>ʃ4}4Q}}lߓ H3qGhh$v^su0{ #7^QϯH3ޭK,/ưI][n͇Y VJ>N*VفbdžPh" H*Wh<u-Fvf9Tkf|s1*8R\v…u*ǐ3:oaXyI~[,u(Ap,? 9ǻR o{rhaze D|H= Ҟ1ԙ[Iy}1{L\;wzGnvc3]X: Fix0-<";|N={J=k 6y~J"& :6;(>ޡC )K!U5%TV׵|tVm;cꘙnHK`'.bQspѱox;g[dtz{*xX+8>]6jVbBl6 A@K'L0& ĝ-4x˻wSoWa(Dlp.lMS: } PCNep 6&>ww/qGm;5t/(3s3FUG80 p=}N{*ȭz}93[mvwǼdӵM9\:ӱ D]y߃rK՘w s$&'ԭW)bvJrp'wE# dZHR#l$B%0:6y5} p##.TI2BLJ@-38J)Ī9A+V](#Z֫_Մ$l &X0(Ű[/v)̚FlZG%\|`uTFvgUg9JOk;ܦ%i^ ժʩ ɲ^l{{1RA C2Ԭ+Ǎ%ռow4ܖVܩKq}b$R2Gtq̮F!ò&_f$pďRm"r!yϳ㯿h;Q*`^οXyfW|Hyްd+wf: Ms~[XfXmGq;Ao ؏Ё(2,jءQ}dZ \A8GPweU>>"/KZ~9QS˹ݏ,vS6#H24a*^cYArY8ImT- %ZGi=Bk9yBpƾ3&d nAQ:9%ea2_T" eWX`KCe k41}JVMk!A{b&.:yXQ _cu\nt&( N"zs9r뙸lr:`mu^6bfM`rrf5NԻ6CȘy@> pR\39 0,{rqw^=(kyFD;z| }n$@E\e Io<|8*ӒZ[ֶGz]<܌;ǚxUGyeQ`[ys.+QT^/&.˺W8:;CTSg<.bgs kZl)2;qE,tf%Pۙsg vn.am < ̬0<+E~:ᶰHC7OΣC/ n2r )W)އۆrR ()mXi@AD"Th7zs! A@Y#ВM^A.PjFkrl0QS#Xs8( ;",{H|xġ߆!lؙA9;g`{q.w4d+zRR?_{ogn~ZI}ԁ<>ƅ=#v\=:q^oY/8ꆏ=ܜ͐x\489.YBw5M'ytjmogY{qy]`x(>7#KvS.YyOUfyW}sN5",2Ki6o3Rٹ q,ʇմ8+F5 ӻYDuEpƇq=R3-4}Jҕޅzyo1^I`.Pgk#4ǾuGk0ooē,s5gvI.aˮe.+!Hr~\wI虜>-gtE6Mi#CtELm6ɬw|'[|kf/K6X#/yT‡GwNX⁗̙[EbMs|ە34|6OT=dwQY\qiJ9jTlS-Ԯƭ)ۀ(5ۑ[~^ZܥzwaՍqI>1VQԂ QVJ!)^4Ʀ[2ir SIThK2z 3Ҵ4SB® :9i6q;I1i5^iб<R[ӧ<t_p=jttt(.:l8}@HwA<+yGq>%w⾣Y{Bm GmjF:Nk5)Uٵ3^^[)+RBL7p-@$GU4Xoxm;<6z>OX픆2+-fuXo}p[*t@W0vz Y7nIݍMu5sH-qDI^wK9 }=出Kq aל<#mvSŦGb0LKz4x-}ϕ< ݍ2u&Hv^:M s~s%Z"LZ-}gelc85gÃ)Zl>^n+7L NxJgmwNBT rd~{d"G=JvxvKTM1̓L_/a5.\A [+p.ɕ2ݷʖmw,g\$I.yM8Sў,j>of'fZE]@h{Q]ﻴрnl2_#v?h i)xj$棥"7'v8=W^pt޺)4  ʗ0r(j|5;~ͪғ.^m}NTnHVw,Ż{%^dQ݌ź4 ll%.Z n{AK{Ͳy*ٖr{L}ʐ=1&5b6wppRv8P}^ړmwy/r')yKuՀ-`#- "t\ˎdj;dxno_4.0t3xǔwVuxԞ*\ zMfzWc󎻟CF:Ж[ƙP Le}+W9;'5`8FA!) F!BSlX!αr[Vܤx4glX°%ҥyE9^A9,nqN鴣u*ib8bH+5woD4w{D~f.rlKnZW)8˷"b6]kb{՝w [N0!RF Nw!$.:Ϭy Xp4rC*a =e'Y0n}vs|V%h>{0ɛbxlex{+Hzyv<>ݶ IE*'^00ysmcڵ=4S.]|5!QMSy=AQk0o>b%j/qr:6o4=(;>vT[xJXy V[;Ns-]Z ={|0I4޻} 351r' 2,{*=[|I )r ^w7iKz4$1*xwƆυ~j,ww{ʅ].oh,F zb -fq|]@r3@,lgN:3ѻpnU"#E^V#!"Ɩ`%a&lX=^6m17v4daqYՈ`GG}i@uԾm 0?[>^׃PLu@ӲP{ݻ27)hY868%ϼr <zOd{XtǠ x?;ϜTONGh7Iy4@')thط{@򳽓wOyν&a)3o79oFP#-nuw.b%+@[Ș/Wb3\9l ]mz*/֥C1xbWTxp<$+Ub}nGB64>J'Snm{Kpؚ-ל8㰮DvC0ĪXvW^RH2w3znǡ'6.b_ OW -g{|7ms+ҏz&6^"$I>A8.d]h9|qO]2)<0; ,j>336񴆋$˷{`>Ge0wE1ӵ6u $hG [PUqg31)Z&[u j&Qj:,jd Fp&'ƟN wdͫylKwflk25 齻vU'/o9%N(&pKKK\R~8UH;އ*eRptØTt#쭓\[ \:cGpI{Jc;}_B|Ca\eƙ,r2͇f[Tcv .,ըVNt ۪[ ;TfvvOk{O{]ڀ{1A='țCHpab˂H V\ v_sim-3.8.0/lib/plug-ins/xsf/xsf.c000066400000000000000000000416371370110300500167100ustar00rootroot00000000000000/* EXTRAITS DE LA LICENCE Copyright CEA, contributeurs : Luc BILLARD et Damien CALISTE, laboratoire L_Sim, (2001-2005) Adresse ml : BILLARD, non joignable par ml ; CALISTE, damien P caliste AT cea P fr. Ce logiciel est un programme informatique servant visualiser des structures atomiques dans un rendu pseudo-3D. Ce logiciel est rgi par la licence CeCILL soumise au droit franais et respectant les principes de diffusion des logiciels libres. Vous pouvez utiliser, modifier et/ou redistribuer ce programme sous les conditions de la licence CeCILL telle que diffuse par le CEA, le CNRS et l'INRIA sur le site "http://www.cecill.info". Le fait que vous puissiez accder cet en-tte signifie que vous avez pris connaissance de la licence CeCILL, et que vous en avez accept les termes (cf. le fichier Documentation/licence.fr.txt fourni avec ce logiciel). */ /* LICENCE SUM UP Copyright CEA, contributors : Luc BILLARD et Damien CALISTE, laboratoire L_Sim, (2001-2005) E-mail address: BILLARD, not reachable any more ; CALISTE, damien P caliste AT cea P fr. This software is a computer program whose purpose is to visualize atomic configurations in 3D. This software is governed by the CeCILL license under French law and abiding by the rules of distribution of free software. You can use, modify and/ or redistribute the software under the terms of the CeCILL license as circulated by CEA, CNRS and INRIA at the following URL "http://www.cecill.info". The fact that you are presently reading this means that you have had knowledge of the CeCILL license and that you accept its terms. You can find a copy of this licence shipped with this software at Documentation/licence.en.txt. */ #include "xsf.h" #include "xsf_density.h" #include #include #include #include #include #include #include #define XSF_DESCRIPTION _("" \ "This plug-in reads XSF" \ " input files\n (position, forces and densities).") #define XSF_AUTHORS "Caliste Damien" /* Local methods */ static gboolean loadXsfIn(VisuDataLoader *self, VisuDataLoadable *data, guint type, guint nSet, GCancellable *cancel, GError **error); static gboolean loadXsfSpin(VisuDataLoader *self, VisuDataLoadable *data, guint type, guint nSet, GCancellable *cancel, GError **error); static int read_xsf_file(VisuDataLoadable *data, guint type, int nSet, GError **error); static void xsfStructuralInit(); static void xsfSpinInit(); /* Local variables */ static gchar *iconPath; static VisuDataLoader *xsfLoader = NULL; static VisuDataLoader *spinLoader = NULL; /* Required methods for a loadable module. */ gboolean xsfInit() { DBG_fprintf(stderr, "XSF: loading plug-in 'xsf'...\n"); DBG_fprintf(stderr, "XSF: declare a new rendering load method.\n"); xsfStructuralInit(); DBG_fprintf(stderr, "XSF: declare a new spin load method.\n"); xsfSpinInit(); iconPath = g_build_filename(V_SIM_PIXMAPS_DIR, "xsf.png", NULL); DBG_fprintf(stderr, "XSF: declare a new density load method.\n"); xsfDensityInit(); return TRUE; } const char* xsfGet_description() { return XSF_DESCRIPTION; } const char* xsfGet_authors() { return XSF_AUTHORS; } const char* xsfGet_icon() { return iconPath; } static void xsfStructuralInit() { const gchar *type[] = {"*.xsf", "*.axsf", (char*)0}; xsfLoader = visu_data_loader_new(_("XCrysDen Structure File format"), type, FALSE, loadXsfIn, 70); visu_data_atomic_class_addLoader(xsfLoader); } static gboolean loadXsfIn(VisuDataLoader *self _U_, VisuDataLoadable *data, guint type, guint nSet, GCancellable *cancel _U_, GError **error) { int res; g_return_val_if_fail(error && *error == (GError*)0, FALSE); res = read_xsf_file(data, type, nSet, error); if (res < 0) /* The file is not a XSF file. */ return FALSE; else if (res > 0) /* The file is a XSF file but some errors occured. */ return TRUE; /* Everything is OK. */ *error = (GError*)0; return TRUE; } void xsf_reader_new(struct xsf_reader *rd) { /* The storage for read line. */ rd->flux = tool_files_new(); rd->line = g_string_new(""); /* Storage of number of elements per types. */ rd->iter = visu_data_loader_iter_new(); rd->nodeTypes = (VisuElement**)0; rd->bc = VISU_BOX_FREE; rd->coords = (float*)0; rd->forces = (GArray*)0; /* rd->lst = (GList*)0; */ } void xsf_reader_free(struct xsf_reader *rd) { /* GList *tmpLst; */ visu_data_loader_iter_unref(rd->iter); if (rd->nodeTypes) g_free(rd->nodeTypes); if (rd->coords) g_free(rd->coords); if (rd->forces) g_array_free(rd->forces, TRUE); /* if (rd->lst) */ /* { */ /* tmpLst = rd->lst; */ /* while (tmpLst) */ /* { */ /* g_free(tmpLst->data); */ /* tmpLst = g_list_next(tmpLst); */ /* } */ /* g_list_free(rd->lst); */ /* } */ g_string_free(rd->line, TRUE); if (rd->flux) g_object_unref(rd->flux); } gboolean xsf_reader_skip_comment(struct xsf_reader *rd, GError **error) { /* Eat blank or commentary lines. */ do { rd->status = tool_files_read_line_string(rd->flux, rd->line, NULL, error); if (rd->status != G_IO_STATUS_NORMAL && rd->status != G_IO_STATUS_EOF) return FALSE; g_strstrip(rd->line->str); } while (rd->status != G_IO_STATUS_EOF && (rd->line->str[0] == '#' || rd->line->str[0] == '!' || rd->line->str[0] == '\0')); return TRUE; } gboolean xsf_reader_get_flag(struct xsf_reader *rd, gboolean *found, const gchar *flag, int *value, gboolean mandatory, GError **error) { size_t len; *found = FALSE; len = strlen(flag); g_strstrip(rd->line->str); if (!strncmp(rd->line->str, flag, len)) { if (mandatory && sscanf(rd->line->str + len, "%d", value) != 1 && *value <= 0) { *error = g_error_new(VISU_DATA_LOADABLE_ERROR, DATA_LOADABLE_ERROR_FORMAT, _("Wrong XSF format, '%s' flag has a" " wrong value.\n"), flag); return FALSE; } else if (!mandatory && sscanf(rd->line->str + len, "%d", value) == 1) { if (*value <= 0) { *error = g_error_new(VISU_DATA_LOADABLE_ERROR, DATA_LOADABLE_ERROR_FORMAT, _("Wrong XSF format, '%s' flag has a" " wrong value.\n"), flag); return FALSE; } } *found = TRUE; } if (*found) return xsf_reader_skip_comment(rd, error); else return TRUE; } static gboolean read_periodicity(struct xsf_reader *rd, GError **error) { gboolean found; if (!xsf_reader_get_flag(rd, &found, "MOLECULE", (int*)0, FALSE, error)) return FALSE; if (found) rd->bc = VISU_BOX_FREE; if (!xsf_reader_get_flag(rd, &found, "SLAB", (int*)0, FALSE, error)) return FALSE; if (found) rd->bc = VISU_BOX_SURFACE_XY; if (!xsf_reader_get_flag(rd, &found, "CRYSTAL", (int*)0, FALSE, error)) return FALSE; if (found) rd->bc = VISU_BOX_PERIODIC; return TRUE; } gboolean xsf_reader_get_box(struct xsf_reader *rd, double cart[3][3], GError **error) { int i; for (i = 0; i < 3; i++) { if (sscanf(rd->line->str, "%lf %lf %lf\n", cart[i], cart[i] + 1, cart[i] + 2) != 3) { *error = g_error_new(VISU_DATA_LOADABLE_ERROR, DATA_LOADABLE_ERROR_FORMAT, _("Wrong XSF format, missing float values" " after tag '%s'.\n"), "PRIMVEC"); return FALSE; } if (!xsf_reader_skip_comment(rd, error)) return FALSE; } DBG_fprintf(stderr, "XSF: read box %8g %8g %8g\n" " %8g %8g %8g\n" " %8g %8g %8g\n", cart[0][0], cart[0][1], cart[0][2], cart[1][0], cart[1][1], cart[1][2], cart[2][0], cart[2][1], cart[2][2]); return TRUE; } static gboolean read_coords(struct xsf_reader *rd, GError **error) { int i, zele, nb; float rcov, f[3]; gchar *name, *ptChar; VisuElement *type; if (sscanf(rd->line->str, "%d", &rd->nNodes) != 1 && rd->nNodes <= 0) { *error = g_error_new(VISU_DATA_LOADABLE_ERROR, DATA_LOADABLE_ERROR_FORMAT, _("Wrong XSF format, missing or wrong integer values" " after tag '%s'.\n"), "PRIMCOORD"); return FALSE; } if (!xsf_reader_skip_comment(rd, error)) return FALSE; rd->nodeTypes = g_malloc(sizeof(VisuElement*) * rd->nNodes); rd->coords = g_malloc(sizeof(float) * 3 * rd->nNodes); DBG_fprintf(stderr, "XSF: read coordinates.\n"); for (i = 0; i < rd->nNodes; i++) { name = g_strdup(rd->line->str); g_strstrip(name); ptChar = strchr(name, ' '); if (!ptChar) { *error = g_error_new(VISU_DATA_LOADABLE_ERROR, DATA_LOADABLE_ERROR_FORMAT, _("Wrong XSF format, can't read coordinates at line '%s'.\n"), name); return FALSE; } *ptChar = '\0'; /* The first three values are coordinates. Possible three others are forces. */ nb = sscanf(ptChar + 1, "%f %f %f %f %f %f\n", rd->coords + 3 * i, rd->coords + 3 * i + 1, rd->coords + 3 * i + 2, f + 0, f + 1, f + 2); if (nb != 3 && nb != 6) { *error = g_error_new(VISU_DATA_LOADABLE_ERROR, DATA_LOADABLE_ERROR_FORMAT, _("Wrong XSF format, can't read coordinates from '%s' (only %d read).\n"), ptChar + 1, nb); return FALSE; } if (nb == 6) { /* If forces where not used, we allocate then now. */ if (!rd->forces) rd->forces = g_array_sized_new(FALSE, FALSE, sizeof(float), rd->nNodes * 3); g_array_insert_vals(rd->forces, 3 * i, f, 3); } /* Try to find a z number instead of a name. */ rcov = -1.f; if (sscanf(name, "%d", &zele) == 1 && tool_physic_getSymbolFromZ(&ptChar, &rcov, (float*)0, zele)) { g_free(name); name = g_strdup(ptChar); } /* adding nomloc to the hashtable */ type = visu_element_retrieveFromName(name, (gboolean*)0); rd->nodeTypes[i] = type; visu_data_loader_iter_addNode(rd->iter, type); if (!xsf_reader_skip_comment(rd, error)) return FALSE; } DBG_fprintf(stderr, " | read OK.\n"); return TRUE; } static int read_xsf_file(VisuDataLoadable *data, guint type, int nSet, GError **error) { struct xsf_reader rd; gboolean found; int valInt; double box[3][3]; int nSets, iNodes; VisuBox *boxObj; float xyz[3]; /* We read every line that corresponds to this schema : "%s %f %f %f" */ DBG_fprintf(stderr, "XSF: reading file as an xsf file.\n"); xsf_reader_new(&rd); if (!tool_files_open(rd.flux, visu_data_loadable_getFilename(data, type), error)) { xsf_reader_free(&rd); return -1; } /* We read the file completely to find the number of sets of points and we store only the one corresponding to @nSet. */ nSets = -1; if (!xsf_reader_skip_comment(&rd, error)) { xsf_reader_free(&rd); return -1; } do { /* Test the periodicity mode. */ if (!read_periodicity(&rd, error)) { xsf_reader_free(&rd); return 1; } /* If ANIMSTEPS is found, we are in animated mode. */ if (!xsf_reader_get_flag(&rd, &found, "ANIMSTEPS", &valInt, TRUE, error)) { xsf_reader_free(&rd); return 1; } if (found) { DBG_fprintf(stderr, "XSF: found the 'ANIMSTEPS' flag (%d).\n", valInt); if (nSets > 0) { *error = g_error_new(VISU_DATA_LOADABLE_ERROR, DATA_LOADABLE_ERROR_FORMAT, _("Wrong XSF format, '%s' tag already" " defined.\n"), "ANIMSTEPS"); xsf_reader_free(&rd); return 1; } else nSets = valInt; } /* fprintf(stderr, "'%s'\n", rd.line->str); */ /* If PRIMVEC is found, we store the box. */ valInt = -1; if (!xsf_reader_get_flag(&rd, &found, "PRIMVEC", &valInt, FALSE, error)) { xsf_reader_free(&rd); return 1; } if (found && (valInt < 0 || (valInt - 1) == nSet)) { if (rd.bc == VISU_BOX_FREE) { *error = g_error_new(VISU_DATA_LOADABLE_ERROR, DATA_LOADABLE_ERROR_FORMAT, _("Wrong XSF format, primitive vectors found" " with free boundary conditions.\n")); xsf_reader_free(&rd); return 1; } DBG_fprintf(stderr, "XSF: found the 'PRIMVEC' flag (%d).\n", valInt); /* We read the box. */ if (!xsf_reader_get_box(&rd, box, error)) { xsf_reader_free(&rd); return 1; } /* We set nSets to 1 if not already set. */ if (nSets < 0) nSets = 1; } /* fprintf(stderr, "'%s'\n", rd.line->str); */ /* If PRIMCOORD is found, we store the coordinates. */ valInt = -1; if (!xsf_reader_get_flag(&rd, &found, "PRIMCOORD", &valInt, FALSE, error)) { xsf_reader_free(&rd); return 1; } if (found && (valInt < 0 || (valInt - 1) == nSet)) { if (rd.bc == VISU_BOX_FREE) { *error = g_error_new(VISU_DATA_LOADABLE_ERROR, DATA_LOADABLE_ERROR_FORMAT, _("Wrong XSF format, primitive coordinates found" " with free boundary conditions.\n")); xsf_reader_free(&rd); return 1; } DBG_fprintf(stderr, "XSF: found the 'PRIMCOORD' flag (%d).\n", valInt); /* We read the coords. */ if (!read_coords(&rd, error)) { xsf_reader_free(&rd); return 1; } /* We set nSets to 1 if not already set. */ if (nSets < 0) nSets = 1; } /* If ATOMS is found, we store the coordinates. */ valInt = -1; if (!xsf_reader_get_flag(&rd, &found, "ATOMS", &valInt, FALSE, error)) { xsf_reader_free(&rd); return 1; } if (found && (valInt < 0 || (valInt - 1) == nSet)) { if (rd.bc != VISU_BOX_FREE) { *error = g_error_new(VISU_DATA_LOADABLE_ERROR, DATA_LOADABLE_ERROR_FORMAT, _("Wrong XSF format, atom coordinates found" " with free boundary conditions.\n")); xsf_reader_free(&rd); return 1; } DBG_fprintf(stderr, "XSF: found the 'ATOMS' flag (%d).\n", valInt); /* We read the coords. */ if (!read_coords(&rd, error)) { xsf_reader_free(&rd); return 1; } /* We set nSets to 1 if not already set. */ if (nSets < 0) nSets = 1; } /* We go on. */ if (!xsf_reader_skip_comment(&rd, error)) { xsf_reader_free(&rd); return 1; } /* fprintf(stderr, "'%s'\n", rd.line->str); */ } while(rd.status != G_IO_STATUS_EOF && rd.coords == (float*)0); /* Begin the storage into VisuData. */ if (!visu_data_loader_iter_allocate(rd.iter, VISU_NODE_ARRAY(data))) { xsf_reader_free(&rd); return -1; } /* Allocate the space for the nodes. */ visu_data_loadable_setNSets(data, nSets); boxObj = visu_box_new_full(box, rd.bc); if (visu_box_getGeometry(boxObj, VISU_BOX_DXX) == G_MAXFLOAT) { *error = g_error_new(VISU_DATA_LOADABLE_ERROR, DATA_LOADABLE_ERROR_FORMAT, _("Wrong XSF format, basis-set is degenerated.\n")); g_object_unref(boxObj); xsf_reader_free(&rd); return 1; } visu_box_setUnit(boxObj, TOOL_UNITS_ANGSTROEM); visu_boxed_setBox(VISU_BOXED(data), VISU_BOXED(boxObj)); g_object_unref(boxObj); for(iNodes = 0; iNodes < rd.nNodes; iNodes++) { visu_box_convertFullToCell(boxObj, xyz, rd.coords + 3 * iNodes); visu_data_addNodeFromElement(VISU_DATA(data), rd.nodeTypes[iNodes], xyz, FALSE); } /* We store the forces as a property to be used later by the spin loading method. */ if (rd.forces) visu_node_values_vector_set (visu_data_atomic_getForces(VISU_DATA_ATOMIC(data), TRUE), rd.forces); /* Free the local data. */ xsf_reader_free(&rd); return 0; } static void xsfSpinInit() { const gchar *type[] = {"*.xsf", "*.axsf", (char*)0}; spinLoader = visu_data_loader_new(_("XCrysDen Structure File format"), type, FALSE, loadXsfSpin, 40); visu_data_spin_class_addLoader(spinLoader); } static gboolean loadXsfSpin(VisuDataLoader *self _U_, VisuDataLoadable *data, guint type _U_, guint nSet _U_, GCancellable *cancel _U_, GError **error) { VisuNodeValuesVector *forces; VisuNodeValuesIter iter; gboolean valid; float vals[3], *fxyz; g_return_val_if_fail(error && *error == (GError*)0, FALSE); forces = visu_data_atomic_getForces(VISU_DATA_ATOMIC(data), FALSE); if (!forces) return FALSE; /* We check that spin and position are the same. */ /* TODO... */ for (valid = visu_node_values_iter_new(&iter, ITER_NODES_BY_TYPE, VISU_NODE_VALUES(forces)); valid; valid = visu_node_values_iter_next(&iter)) { fxyz = (float*)g_value_get_pointer(&iter.value); visu_box_convertFullToCell(visu_boxed_getBox(VISU_BOXED(data)), vals, fxyz); visu_data_spin_setAt(VISU_DATA_SPIN(data), iter.iter.node, vals); } /* Everything is OK. */ *error = (GError*)0; return TRUE; } v_sim-3.8.0/lib/plug-ins/xsf/xsf.h000066400000000000000000000047511370110300500167110ustar00rootroot00000000000000/* EXTRAITS DE LA LICENCE Copyright CEA, contributeurs : Luc BILLARD et Damien CALISTE, laboratoire L_Sim, (2001-2005) Adresse ml : BILLARD, non joignable par ml ; CALISTE, damien P caliste AT cea P fr. Ce logiciel est un programme informatique servant visualiser des structures atomiques dans un rendu pseudo-3D. Ce logiciel est rgi par la licence CeCILL soumise au droit franais et respectant les principes de diffusion des logiciels libres. Vous pouvez utiliser, modifier et/ou redistribuer ce programme sous les conditions de la licence CeCILL telle que diffuse par le CEA, le CNRS et l'INRIA sur le site "http://www.cecill.info". Le fait que vous puissiez accder cet en-tte signifie que vous avez pris connaissance de la licence CeCILL, et que vous en avez accept les termes (cf. le fichier Documentation/licence.fr.txt fourni avec ce logiciel). */ /* LICENCE SUM UP Copyright CEA, contributors : Luc BILLARD et Damien CALISTE, laboratoire L_Sim, (2001-2005) E-mail address: BILLARD, not reachable any more ; CALISTE, damien P caliste AT cea P fr. This software is a computer program whose purpose is to visualize atomic configurations in 3D. This software is governed by the CeCILL license under French law and abiding by the rules of distribution of free software. You can use, modify and/ or redistribute the software under the terms of the CeCILL license as circulated by CEA, CNRS and INRIA at the following URL "http://www.cecill.info". The fact that you are presently reading this means that you have had knowledge of the CeCILL license and that you accept its terms. You can find a copy of this licence shipped with this software at Documentation/licence.en.txt. */ #ifndef XSF_H #define XSF_H #include #include #include #include struct xsf_reader { GString *line; GIOStatus status; ToolFiles *flux; /* GList *lst; */ VisuDataLoaderIter *iter; VisuElement **nodeTypes; int nNodes; float *coords; GArray *forces; VisuBoxBoundaries bc; }; void xsf_reader_new(struct xsf_reader *rd); void xsf_reader_free(struct xsf_reader *rd); gboolean xsf_reader_skip_comment(struct xsf_reader *rd, GError **error); gboolean xsf_reader_get_flag(struct xsf_reader *rd, gboolean *found, const gchar *flag, int *value, gboolean mandatory, GError **error); gboolean xsf_reader_get_box(struct xsf_reader *rd, double cart[3][3], GError **error); #endif v_sim-3.8.0/lib/plug-ins/xsf/xsf.png000066400000000000000000000045741370110300500172510ustar00rootroot00000000000000PNG  IHDR szzbKGD pHYs  tIME  XtEXtCommentCreated with The GIMPd%nIDATXõkU>;w^<H$Bcc#OFtP8  3 :::@,zW0RJRH!R|/6wg>TEIgKApl@bxTMCWm4PGUBlp(erA EQPw3>a| XygYD{kBd*˥Kߴ`Je#/Ng ,<#BW z%çW:woLjkt72ǣJ,VE6' yL&*<ϣP,1;&_(led2yc߿uKKbgOToX~0bX4}kfJgBR"=ɜmyЮ"CcAv9 ySq<&i69&Y|+=`L|gR@yS( <*1χIC\e0gByAoL'J"p=JZi_|%PߐW R\8|`񣟢V3ʋ~U!xX gNܐLPGi$( <0Ք+0Cͦ 2PU6X q)00ӓ7R(躆U\w\)*P tPBٸcS\Ne7o[x9 9GO%Ľ>Wu=TUo$6D=+|$FNp*ZAٶC'OL~a#6L5:X]wز)~?MK8ӇV/aAka+53Gv~C{w>U5?[LLi}_@.}EsQAﮦusj(0 A'G'y7IBade_o =`0H[ĄC31NF &+Zǰ,p8Hô>xҙOHV,nӣt'DS[+t~/H,D4 vK[Xz;ٹf{NFm܆vq}Tt'0$? Cup$$g?8E-–-O=%XBSAU!RI`UWQ| Vusrl_JDK [>!߾k뢴=Ô;pMQ)4tXR.GGNCJ(R]mQU t9HbSGeh5ֺzD>491rK5L1[$tѤʼJ'L~Nmmc]xHdUz\rb#՟(Ec_AyDsɰ.y|j5--MM `뜚4;צ˗pbxh(ȲǺ^lz"Umpnzf+h.:MrY8f Po"hk!*iAϨdQC5O2 XJa8 oH1I/}Blb0$D4дRGi@m%CH7{us7#pB*GGyzU<۾O<lw^˅qь@3 9)H"55HIg*N P@ڇs]gN@!(ږ !H* |NOT01=FrwT9DI>Γq?re9Z[T|ϝBm]jH&Ǘ<\* Gq¡;%<<):ƥ 'D"j+ aho;3$Ӓ14:V8;IENDB`v_sim-3.8.0/lib/plug-ins/xsf/xsf_density.c000066400000000000000000000202271370110300500204370ustar00rootroot00000000000000/* EXTRAITS DE LA LICENCE Copyright CEA, contributeurs : Luc BILLARD, Damien CALISTE, Olivier D'Astier, laboratoire L_Sim, (2001-2011) Adresses mèl : BILLARD, non joignable par mèl ; CALISTE, damien P caliste AT cea P fr. Ce logiciel est un programme informatique servant à visualiser des structures atomiques dans un rendu pseudo-3D. Ce logiciel est régi par la licence CeCILL soumise au droit français et respectant les principes de diffusion des logiciels libres. Vous pouvez utiliser, modifier et/ou redistribuer ce programme sous les conditions de la licence CeCILL telle que diffusée par le CEA, le CNRS et l'INRIA sur le site "http://www.cecill.info". Le fait que vous puissiez accéder à cet en-tête signifie que vous avez pris connaissance de la licence CeCILL, et que vous en avez accepté les termes (cf. le fichier Documentation/licence.fr.txt fourni avec ce logiciel). */ /* LICENCE SUM UP Copyright CEA, contributors : Luc BILLARD and Damien CALISTE and Olivier D'Astier, laboratoire L_Sim, (2001-2011) E-mail addresses : BILLARD, not reachable any more ; CALISTE, damien P caliste AT cea P fr. This software is a computer program whose purpose is to visualize atomic configurations in 3D. This software is governed by the CeCILL license under French law and abiding by the rules of distribution of free software. You can use, modify and/ or redistribute the software under the terms of the CeCILL license as circulated by CEA, CNRS and INRIA at the following URL "http://www.cecill.info". The fact that you are presently reading this means that you have had knowledge of the CeCILL license and that you accept its terms. You can find a copy of this licence shipped with this software at Documentation/licence.en.txt. */ #include "xsf.h" #include "xsf_density.h" #include #include /* Local methods. */ static gboolean xsfDensityLoad(VisuScalarFieldMethod *meth, VisuScalarFieldMethodData *data, GCancellable *cancel, GError **error); void xsfDensityInit() { const gchar *type[] = {"*.xsf", "*.axsf", (char*)0}; visu_scalar_field_method_new(_("XCrysDen density file format"), type, xsfDensityLoad, G_PRIORITY_HIGH - 5); } static gboolean read_values(struct xsf_reader *rd, guint mesh[3], GArray **values, GError **error) { int i, j, n; gchar **tokens; GArray *density; #if DEBUG == 1 GTimer *timer; gulong fractionTimer; #endif #if DEBUG == 1 timer = g_timer_new(); g_timer_start(timer); #endif n = mesh[0] * mesh[1] * mesh[2]; density = g_array_sized_new(FALSE, FALSE, sizeof(double), n); density = g_array_set_size(density, n); DBG_fprintf(stderr, "XSF: read density (%gMo).\n", sizeof(double) * n / 1024. / 1024.); i = 0; do { tokens = g_strsplit(rd->line->str, " ", 0); for (j = 0; tokens[j] && i < n; j++) if (tokens[j][0]) { if (sscanf(tokens[j], "%lf", &g_array_index(density, double, i)) != 1) { *error = g_error_new(TOOL_FILE_FORMAT_ERROR, TOOL_FILE_FORMAT_ERROR_FORMAT, _("Wrong XSF format, unreadable float value" " %d for density.\n"), i); g_strfreev(tokens); g_array_unref(density); return FALSE; } i += 1; } g_strfreev(tokens); if (!xsf_reader_skip_comment(rd, error)) { *error = g_error_new(TOOL_FILE_FORMAT_ERROR, TOOL_FILE_FORMAT_ERROR_FORMAT, _("Wrong XSF format, missing density lines.\n")); g_array_unref(density); return FALSE; } } while(i < n && rd->status == G_IO_STATUS_NORMAL); #if DEBUG == 1 g_timer_stop(timer); fprintf(stderr, "XSF: density parsed in %g milli-s.\n", g_timer_elapsed(timer, &fractionTimer)/1e-3); g_timer_destroy(timer); #endif if (rd->status != G_IO_STATUS_NORMAL) { *error = g_error_new(TOOL_FILE_FORMAT_ERROR, TOOL_FILE_FORMAT_ERROR_FORMAT, _("Wrong XSF format, missing float values" " for density (%d read, %d awaited).\n"), i, mesh[0] * mesh[1] * mesh[2]); g_array_unref(density); return FALSE; } *values = density; return TRUE; } static gboolean read_one_density(struct xsf_reader *rd, VisuScalarFieldData *field, GError **error) { VisuBox *boxObj; gchar *comment; gboolean found; int valInt; guint mesh[3]; float trans[3]; double box[3][3]; GArray *values; /* Read the comment and the flag. */ comment = g_strdup(rd->line->str); g_strstrip(comment); visu_scalar_field_setCommentary(VISU_SCALAR_FIELD(field), comment); g_free(comment); if (!xsf_reader_skip_comment(rd, error)) return FALSE; if (!xsf_reader_get_flag(rd, &found, "BEGIN_DATAGRID_3D", &valInt, FALSE, error)) return FALSE; /* Read the mesh size. */ if (sscanf(rd->line->str, "%u %u %u", mesh, mesh + 1, mesh + 2) != 3) { g_set_error(error, TOOL_FILE_FORMAT_ERROR, TOOL_FILE_FORMAT_ERROR_FORMAT, _("Wrong XSF format, missing or wrong mesh size" " after tag '%s'.\n"), "BEGIN_DATAGRID_3D"); return FALSE; } if (!xsf_reader_skip_comment(rd, error)) return FALSE; visu_scalar_field_setGridSize(VISU_SCALAR_FIELD(field), mesh); /* Read the translation. */ if (sscanf(rd->line->str, "%f %f %f", trans, trans + 1, trans + 2) != 3) { g_set_error(error, TOOL_FILE_FORMAT_ERROR, TOOL_FILE_FORMAT_ERROR_FORMAT, _("Wrong XSF format, missing or wrong translation definition.")); return FALSE; } if (!xsf_reader_skip_comment(rd, error)) return FALSE; /* visu_pointset_setTranslation(VISU_POINTSET(field), trans, TRUE); */ /* Read the box. */ if (!xsf_reader_get_box(rd, box, error)) return FALSE; boxObj = visu_box_new_full(box, VISU_BOX_PERIODIC); visu_box_setMargin(boxObj, 0.f, FALSE); visu_boxed_setBox(VISU_BOXED(field), VISU_BOXED(boxObj)); g_object_unref(boxObj); /* Read the values. */ if (!read_values(rd, mesh, &values, error)) return FALSE; DBG_fprintf(stderr, "XSF: transfer density into field object.\n"); visu_scalar_field_data_set(field, values, VISU_SCALAR_FIELD_DATA_XYZ); g_array_unref(values); return TRUE; } static gboolean xsfDensityLoad(VisuScalarFieldMethod *meth _U_, VisuScalarFieldMethodData *data, GCancellable *cancel _U_, GError **error) { struct xsf_reader rd; gboolean flag; int valInt; VisuScalarFieldData *field; g_return_val_if_fail(data, FALSE); g_return_val_if_fail(!error || *error == (GError*)0, FALSE); xsf_reader_new(&rd); if (!tool_files_open(rd.flux, visu_scalar_field_method_data_getFilename(data), error)) { xsf_reader_free(&rd); return FALSE; } field = (VisuScalarFieldData*)0; /* We read all the file. */ if (!xsf_reader_skip_comment(&rd, error)) { xsf_reader_free(&rd); return FALSE; } do { /* If BLOCK_DATAGRID_3D is found, we store the densities. */ if (!xsf_reader_get_flag(&rd, &flag, "BEGIN_BLOCK_DATAGRID_3D", &valInt, FALSE, error)) { xsf_reader_free(&rd); return FALSE; } if (flag) { DBG_fprintf(stderr, "XSF: found the 'BEGIN_BLOCK_DATAGRID_3D' flag.\n"); field = g_object_new(VISU_TYPE_SCALAR_FIELD_DATA, "label", visu_scalar_field_method_data_getFilename(data), NULL); g_object_ref(field); visu_scalar_field_method_data_addField(data, VISU_SCALAR_FIELD(field)); visu_scalar_field_method_data_ready(data); if (!read_one_density(&rd, field, error)) { g_object_unref(field); xsf_reader_free(&rd); return TRUE; } g_object_unref(field); } /* We go on. */ if (!xsf_reader_skip_comment(&rd, error)) { xsf_reader_free(&rd); return field != (VisuScalarFieldData*)0; } } while(rd.status != G_IO_STATUS_EOF); xsf_reader_free(&rd); return field != (VisuScalarFieldData*)0; } v_sim-3.8.0/lib/plug-ins/xsf/xsf_density.h000066400000000000000000000035211370110300500204420ustar00rootroot00000000000000/* EXTRAITS DE LA LICENCE Copyright CEA, contributeurs : Luc BILLARD, Damien CALISTE, Olivier D'Astier, laboratoire L_Sim, (2001-2011) Adresses mèl : BILLARD, non joignable par mèl ; CALISTE, damien P caliste AT cea P fr. Ce logiciel est un programme informatique servant à visualiser des structures atomiques dans un rendu pseudo-3D. Ce logiciel est régi par la licence CeCILL soumise au droit français et respectant les principes de diffusion des logiciels libres. Vous pouvez utiliser, modifier et/ou redistribuer ce programme sous les conditions de la licence CeCILL telle que diffusée par le CEA, le CNRS et l'INRIA sur le site "http://www.cecill.info". Le fait que vous puissiez accéder à cet en-tête signifie que vous avez pris connaissance de la licence CeCILL, et que vous en avez accepté les termes (cf. le fichier Documentation/licence.fr.txt fourni avec ce logiciel). */ /* LICENCE SUM UP Copyright CEA, contributors : Luc BILLARD and Damien CALISTE and Olivier D'Astier, laboratoire L_Sim, (2001-2011) E-mail addresses : BILLARD, not reachable any more ; CALISTE, damien P caliste AT cea P fr. This software is a computer program whose purpose is to visualize atomic configurations in 3D. This software is governed by the CeCILL license under French law and abiding by the rules of distribution of free software. You can use, modify and/ or redistribute the software under the terms of the CeCILL license as circulated by CEA, CNRS and INRIA at the following URL "http://www.cecill.info". The fact that you are presently reading this means that you have had knowledge of the CeCILL license and that you accept its terms. You can find a copy of this licence shipped with this software at Documentation/licence.en.txt. */ #ifndef XSF_DENSITY_H #define XSF_DENSITY_H void xsfDensityInit(); #endif v_sim-3.8.0/lib/python/000077500000000000000000000000001370110300500147145ustar00rootroot00000000000000v_sim-3.8.0/lib/python/Makefile.am000066400000000000000000000010621370110300500167470ustar00rootroot00000000000000if PYTHON_MODULE PYTHON_LIB = v_sim.la PYTHON_EXAMPLE = example.py abinitParser.py endif v_simplugins_LTLIBRARIES = $(PYTHON_LIB) AM_CPPFLAGS = \ @PYGTK_CFLAGS@ $(PYTHON_INCLUDES) @GTKS_CFLAGS@ -I$(top_srcdir)/src v_sim_la_SOURCES = visu_py.c plane_py.c v_sim_la_CFLAGS = v_sim_la_LIBADD = $(top_builddir)/src/lib@PACKAGE_TARNAME@.la @GTKS_LIBS@ @PYGTK_LIBS@ v_sim_la_LDFLAGS = -module -avoid-version v_simexamples_DATA = $(PYTHON_EXAMPLE) EXTRA_DIST = example.py abinitParser.py #v_sim.la: $(v_sim_la_SOURCES) $(top_builddir)/src/lib@PACKAGE_TARNAME@.la v_sim-3.8.0/lib/python/abinitParser.py000077500000000000000000000276521370110300500177300ustar00rootroot00000000000000#!/usr/bin/env python import abinit import numpy import pygtk, gtk, gobject import re, sys, os import ElementTree import v_sim def delete_event(widget, event, data=None): return False def destroy(widget, data=None): gtk.main_quit() def loadData(widget, response_id, window): if (response_id != gtk.RESPONSE_ACCEPT): return if (widget is not window.get_data("fileSel")): widget.hide() # Remove old columns. view = window.get_data("treeview") for col in view.get_columns()[1:]: view.remove_column(col) wd = window.get_data("hboxResults") wd.set_sensitive(False) window.set_data("dtsets", None) v_sim.set(None) # We parse the file. try: toto = abinit.Dtsets(widget.get_filename()) except Exception, err: window.get_data("fileSel").unselect_all() wd = gtk.MessageDialog(window, gtk.DIALOG_MODAL, gtk.MESSAGE_ERROR, gtk.BUTTONS_OK, err.msg) wd.run() wd.destroy() return window.set_data("dtsets", toto) wd = window.get_data("hboxResults") wd.set_sensitive(True) # Create a new model. args = "gtk.ListStore(gobject.TYPE_STRING" for i in range(toto.get_ndtset()): args += ", gobject.TYPE_STRING, gobject.TYPE_STRING" args += ")" model = eval(args) modelFilter = model.filter_new() window.set_data("model", model) modelFilter.set_visible_func(hideCycleIter, window) modelSort = gtk.TreeModelSort(modelFilter) modelSort.set_sort_column_id(0, gtk.SORT_ASCENDING) view.set_model(modelSort) for strId in abinit.get_ids().iterkeys(): iter = model.append() model.set(iter, 0, strId) default = toto.get(strId, 0) for i in range(toto.get_ndtset()): val = toto.get(strId, i + 1) if (numpy.all(val == default)): misc = "#505050" else: misc = "blue" if (val is None): val = "Unsupported type" model.set(iter, 2 * i + 1, val.__str__(), 2 * i + 2, misc) # Add the column to the tree view. for i in range(1, toto.get_ndtset() + 1): col = view.insert_column_with_attributes(-1, "Value dtset %d" % i, \ gtk.CellRendererText(), \ markup = 2 * i - 1, foreground = 2 * i) col.set_resizable(True) col.set_sort_column_id(i) # Adapt the range for the spDtSets button. window.get_data("spDtSets").set_range(1, toto.get_ndtset() + 1) def renderDtSet(widget, window): dtset = window.get_data("dtsets") iSet = int(window.get_data("spDtSets").get_value()) znucl = dtset.get("znucl", iSet) pop = {} eles = [] for i in znucl: ele = v_sim.element(int(i)) pop[ele] = 0 eles.append(ele) print pop typat = dtset.get("typat", iSet) for i in typat: pop[eles[i - 1]] += 1 data = v_sim.data() data.setPopulation(pop) rprimd = dtset.get("rprimd_orig", iSet) coord = dtset.get("xred_orig", iSet) i = 0 for xyz in coord: c = (rprimd[0][0] * xyz[0] + rprimd[0][1] * xyz[1] + rprimd[0][2] * xyz[2], \ rprimd[1][0] * xyz[0] + rprimd[1][1] * xyz[1] + rprimd[1][2] * xyz[2], \ rprimd[2][0] * xyz[0] + rprimd[2][1] * xyz[1] + rprimd[2][2] * xyz[2]) data.addNode(eles[typat[i] - 1], c) i += 1 box = rprimd.tolist() data.setBox((tuple(box[0]), tuple(box[1]), tuple(box[2])), True) v_sim.set(data) def hideCycleIter(model, iter, window): (strId,) = model.get(iter, 0) if (strId is None): return False if (window.get_data("hideDefault").get_active()): dtsets = window.get_data("dtsets") hide = True for i in range(dtsets.get_ndtset()): (color,) = model.get(iter, 2 * i + 2) hide = hide and (color != "blue") else: hide = False return (not(hide) and re.match(window.get_data("filter"), strId) is not None) def applyFilter(widget, window, entry): patStr = entry.get_text() if (patStr[-1] != "$"): patStr += "$" pat = re.compile(patStr) if (pat is not None): window.set_data("filter", pat) window.get_data("treeview").get_model().get_model().refilter() def applyHide(widget, window): window.get_data("treeview").get_model().get_model().refilter() def withArg(argv, window): fileSel = window.get_data("fileSel") fileSel.set_filename(os.path.abspath(sys.argv[1])) while (gtk.events_pending()): gtk.main_iteration() if (fileSel.get_filename() is not None): loadData(fileSel, gtk.RESPONSE_ACCEPT, window) else: raise ValueError("No file '%s'." % os.path.abspath(sys.argv[1])) return False def XMLGetText(var): if (var is None): return "" if (var.text is not None): text = var.text.strip().replace("\n", " ") + " " else: text = "" for child in var.getchildren(): if (child.tag == "p"): text += XMLGetText(child) + "\n" elif (child.tag == "ul"): text += "\n" + XMLGetText(child) elif (child.tag == "li"): text += " * " + XMLGetText(child) + "\n" elif (child.tag == "br"): text += "\n" else: text += XMLGetText(child) if (var.tail is not None): text += var.tail.strip().replace("\n", " ") + " " return re.sub(" *", " ", text) def selectAtt(selection, window): (model, iter) = selection.get_selected() if (iter is None): return iSets = [] (att,) = model.get(iter, 0) window.get_data("lblKeyword").set_markup("" + att + "") window.get_data("lblMnemonic").set_markup("") window.get_data("lblCategory").set_markup("") window.get_data("lblType").set_markup("") window.get_data("lblDefault").set_markup("") window.get_data("description").set_text("") varlist = window.get_data("varlist") for var in varlist: if (var.find("keyword").text == att): window.get_data("lblMnemonic").set_markup(XMLGetText(var.find("mnemonics"))) window.get_data("lblCategory").set_markup(XMLGetText(var.find("categories"))) window.get_data("lblType").set_markup(XMLGetText(var.find("type"))) window.get_data("lblDefault").set_markup(XMLGetText(var.find("default"))) window.get_data("description").set_text(XMLGetText(var.find("description"))) break if __name__ == "__main__": window = gtk.Window(gtk.WINDOW_TOPLEVEL) window.set_border_width(5) window.connect("delete_event", delete_event) window.connect("destroy", destroy) vbox = gtk.VBox() window.add(vbox) hbox = gtk.HBox() vbox.pack_start(hbox, False, False, 5) wd = gtk.Label("Analysing data file:") wd.set_use_markup(True) wd.set_alignment(0., 0.5) wd.set_padding(10, 0) hbox.pack_start(wd, False, False, 0) wd = gtk.FileChooserDialog(title = "Choose an ABINIT data file", \ buttons = (gtk.STOCK_CANCEL, gtk.RESPONSE_REJECT, gtk.STOCK_OPEN, gtk.RESPONSE_ACCEPT)) wd.connect("response", loadData, window) fileSel = gtk.FileChooserButton(wd) window.set_data("fileSel", fileSel) hbox.pack_start(fileSel, True, True, 5) hbox = gtk.VPaned() hbox.set_sensitive(False) window.set_data("hboxResults", hbox) vbox.pack_start(hbox, True, True, 0) wd = gtk.VBox() hbox.pack1(wd, True, False) scroll = gtk.ScrolledWindow() scroll.set_policy(gtk.POLICY_AUTOMATIC, gtk.POLICY_AUTOMATIC) scroll.set_shadow_type(gtk.SHADOW_ETCHED_OUT) wd.pack_start(scroll, True, True, 0) view = gtk.TreeView() wd.set_size_request(-1, 400) view.set_rules_hint(True) view.set_grid_lines(gtk.TREE_VIEW_GRID_LINES_VERTICAL) view.get_selection().set_mode(gtk.SELECTION_SINGLE) view.get_selection().connect("changed", selectAtt, window) window.set_data("treeview", view) scroll.add(view) col = view.insert_column_with_attributes(-1, "Attribute", \ gtk.CellRendererText(), \ markup=0) col.set_sort_column_id(0) hbox2 = gtk.HBox() wd.pack_start(hbox2, False, False, 0) entry = gtk.Entry() entry.set_text(".*") window.set_data("filter", re.compile(".*")) entry.connect("activate", applyFilter, window, entry) bt1 = gtk.Button(label="Filter") bt1.connect("clicked", applyFilter, window, entry) bt2 = gtk.ToggleButton(label="Hide defaults") bt2.connect("toggled", applyHide, window) window.set_data("hideDefault", bt2) hbox2.pack_end(bt2, False, False, 0) hbox2.pack_end(bt1, False, False, 0) hbox2.pack_end(entry, False, False, 0) pane = gtk.HPaned() hbox.pack2(pane, True, True) render = v_sim.main(width=400, height=400) pane.pack2(render, True, True) table = gtk.Table(6, 4) table.set_row_spacings(10); align = gtk.Alignment(xalign=1) table.attach(align, 0, 4, 5, 6, yoptions = gtk.SHRINK, xoptions = gtk.FILL | gtk.EXPAND, ypadding=5) wd = gtk.HBox() align.add(wd) lb = gtk.Label("Render dtset:") wd.pack_start(lb, False, False, 0) sp = gtk.SpinButton() window.set_data("spDtSets", sp) wd.pack_start(sp, False, False, 0) bt = gtk.Button(stock = gtk.STOCK_GO_FORWARD) bt.connect("clicked", renderDtSet, window) wd.pack_start(bt, False, False, 10) pane.pack1(table, True, False) wd = gtk.Label("Keyword:") wd.set_use_markup(True) wd.set_alignment(1., 0.5) table.attach(wd, 0, 1, 0, 1, xoptions = gtk.SHRINK | gtk.FILL, yoptions = gtk.SHRINK) wd = gtk.Label("") wd.set_alignment(0., 0.5) table.attach(wd, 1, 2, 0, 1, yoptions = gtk.SHRINK, xpadding = 5) window.set_data("lblKeyword", wd) wd = gtk.Label("Mnemonic:") wd.set_use_markup(True) wd.set_alignment(1., 0.5) table.attach(wd, 2, 3, 0, 1, xoptions = gtk.SHRINK | gtk.FILL, yoptions = gtk.SHRINK) wd = gtk.Label("") wd.set_line_wrap(True) wd.set_alignment(0., 0.5) table.attach(wd, 3, 4, 0, 1, yoptions = gtk.SHRINK, xpadding = 5) window.set_data("lblMnemonic", wd) wd = gtk.Label("Found in:") wd.set_use_markup(True) wd.set_alignment(1., 0.5) table.attach(wd, 0, 1, 1, 2, xoptions = gtk.SHRINK | gtk.FILL, yoptions = gtk.SHRINK) wd = gtk.Label("") wd.set_alignment(0., 0.5) table.attach(wd, 1, 2, 1, 2, yoptions = gtk.SHRINK, xpadding = 5) window.set_data("lblFound", wd) wd = gtk.Label("Category:") wd.set_use_markup(True) wd.set_alignment(1., 0.5) table.attach(wd, 2, 3, 1, 2, xoptions = gtk.SHRINK | gtk.FILL, yoptions = gtk.SHRINK) wd = gtk.Label("") wd.set_alignment(0., 0.5) table.attach(wd, 3, 4, 1, 2, yoptions = gtk.SHRINK, xpadding = 5) window.set_data("lblCategory", wd) wd = gtk.Label("Type:") wd.set_use_markup(True) wd.set_alignment(1., 0.5) table.attach(wd, 0, 1, 2, 3, xoptions = gtk.SHRINK | gtk.FILL, yoptions = gtk.SHRINK) wd = gtk.Label("") wd.set_line_wrap(True) wd.set_alignment(0., 0.5) table.attach(wd, 1, 2, 2, 3, yoptions = gtk.SHRINK, xpadding = 5) window.set_data("lblType", wd) wd = gtk.Label("Default:") wd.set_use_markup(True) wd.set_alignment(1., 0.5) table.attach(wd, 2, 3, 2, 3, xoptions = gtk.SHRINK | gtk.FILL, yoptions = gtk.SHRINK) wd = gtk.Label("") wd.set_line_wrap(True) wd.set_alignment(0., 0.5) table.attach(wd, 3, 4, 2, 3, yoptions = gtk.SHRINK, xpadding = 5) window.set_data("lblDefault", wd) wd = gtk.Label("Description:") wd.set_use_markup(True) wd.set_alignment(1., 0.5) table.attach(wd, 0, 1, 3, 4, gtk.SHRINK | gtk.FILL, yoptions = gtk.SHRINK) scroll = gtk.ScrolledWindow() scroll.set_policy(gtk.POLICY_NEVER, gtk.POLICY_AUTOMATIC) scroll.set_shadow_type(gtk.SHADOW_ETCHED_OUT) table.attach(scroll, 0, 4, 4, 5, xpadding = 5) buf = gtk.TextBuffer() window.set_data("description", buf) wd = gtk.TextView(buf) wd.set_editable(False) wd.set_wrap_mode(gtk.WRAP_WORD) wd.set_size_request(400, -1) scroll.add(wd) window.show_all() if (len(sys.argv) > 1): gobject.idle_add(withArg, sys.argv, window) # We parse the variable defs. varlist = ElementTree.parse("varlists.xml").findall("list/variable") window.set_data("varlist", varlist) gtk.main() v_sim-3.8.0/lib/python/example.py000077500000000000000000000106131370110300500167250ustar00rootroot00000000000000#!/usr/bin/env python import math, random import gobject import gtk, v_sim def delete_event(widget, event, data=None): return False def destroy(widget, data=None): gtk.main_quit() def reset(widget, v_sim, handles): stop(widget, handles) v_sim.set(None) def stop(widget, handles): if (handles[0] is not None): gobject.source_remove(handles[0]) if (handles[1] is not None): gobject.source_remove(handles[1]) handles[0] = None handles[1] = None def load(widget, v_sim, data, nodes, C, angle, handles): if (handles[0] is not None): gobject.source_remove(handles[0]) if (handles[1] is not None): gobject.source_remove(handles[1]) v_sim.set(data) handles[0] = gobject.timeout_add(10, turn, angle, v_sim, data, nodes) handles[1] = gobject.timeout_add(1000, add, data, angle, C, nodes) def turn(angle, v_sim, data, nodes): angle[1] = math.pi * 2 / 3 + 0.5 * math.sin(angle[0] * 2) nodes[0].set(coord=(1.2 * math.sin(angle[1]) * (math.cos(angle[0])) + 2.5, \ 1.2 * math.sin(angle[1]) * (math.sin(angle[0])) + 2.5, \ 1.2 * math.cos(angle[1]) + 2)) nodes[1].set(coord=(1.2 * math.sin(angle[1]) * (math.cos(angle[0] + math.pi)) + 2.5, \ 1.2 * math.sin(angle[1]) * (math.sin(angle[0] + math.pi)) + 2.5, \ 1.2 * math.cos(angle[1]) + 2), emit = True) if (nodes[2].isValid()): nodes[2].set(coord=(2.5, 2.5, 4 + math.sin(angle[1] + math.pi/4))) data.createAllNodes() v_sim.redraw() angle[0] += math.pi / 100 if (angle[0] > 2 * math.pi): angle[0] = 0 print data.getPopulation() return True def add(data, angle, C, nodes): if (nodes[2].isValid()): data.delNodes(nodes[2]) else: nodes[2] = data.addNode(C, (2.5, 2.5, 4. + math.sin(angle[1] + math.pi/4)), emit = True) return True def start(window, handles): render = v_sim.main(width=400) window.get_data("hbox").pack_start(render, False, False, 0) angle = [0., math.pi * 2 / 3] O = v_sim.element("O", rgba=(1., 0.2, 0., 1.)) #O.set(rendered = False) H = v_sim.element("H", rgba=(0.2, 0.4, 0.5, 0.3)) C = v_sim.element("C", rgba=(0.1, 0.1, 0.1, 1.)) data = v_sim.data() data.setPopulation({O:1, H:2, C:1}) data.addNode(O, (2.5, 2.5, 2)) nodes = [] nodes.append(data.addNode(H, (1.5, 2.5, 1))) nodes.append(data.addNode(H, (3.5, 2.5, 1))) nodes.append(v_sim.node(data, 3)) data.setBox((5., 0., 5., 0., 0., 5.), True) plane = v_sim.plane(normal = (1,0,0), distance = 3, rgba = (1,0.5,0.5,1)) data.setPlanes((plane,)) window.get_data("play").connect("clicked", load, v_sim, data, nodes, C, angle, handles) window.get_data("stop").connect("clicked", stop, handles) window.get_data("reset").connect("clicked", reset, v_sim, handles) return False bouncing = """ O = v_sim.element("O", rgba=(1., 0.2, 0., 1.)) #O.set(rendered = False) H = v_sim.element("H", rgba=(0.2, 0.4, 0.5, 0.3)) C = v_sim.element("C", rgba=(0.1, 0.1, 0.1, 1.)) data = v_sim.data() data.setPopulation({O:1, H:2, C:1}) data.addNode(O, (2.5, 2.5, 2)) data.addNode(H, (1.5, 2.5, 1)) data.addNode(H, (3.5, 2.5, 1)) data.setBox((5., 0., 5., 0., 0., 5.), True) """ handles = [None, None] # Set the GTK interface. window = gtk.Window(gtk.WINDOW_TOPLEVEL) window.connect("delete_event", delete_event) window.connect("destroy", destroy) hbox = gtk.HBox() window.add(hbox) vbox = gtk.VBox() vbox.set_border_width(7) hbox.pack_start(vbox, True, True, 0) wd = gtk.Label("Demonstrate Python bindings for V_Sim:") wd.set_use_markup(True) wd.set_padding(10, 0) vbox.pack_start(wd, False, False, 20) scroll = gtk.ScrolledWindow() scroll.set_policy(gtk.POLICY_AUTOMATIC, gtk.POLICY_ALWAYS) scroll.set_shadow_type(gtk.SHADOW_ETCHED_OUT) vbox.pack_start(scroll, True, True, 0) buf = gtk.TextBuffer() buf.set_text(bouncing) wd = gtk.TextView(buf) wd.set_size_request(300, -1) wd.set_editable(False) scroll.add(wd) com = gtk.HBox() vbox.pack_end(com, False, False, 5) wd = gtk.Button(stock = gtk.STOCK_MEDIA_PLAY) window.set_data("play", wd) com.pack_end(wd, False, False, 0) wd = gtk.Button(stock = gtk.STOCK_MEDIA_STOP) window.set_data("stop", wd) com.pack_end(wd, False, False, 0) wd = gtk.Button(stock = gtk.STOCK_REMOVE) com.pack_start(wd, False, False, 0) window.set_data("reset", wd) window.set_data("hbox", hbox) window.show_all() gobject.idle_add(start, window, handles) gtk.main() v_sim-3.8.0/lib/python/plane_py.c000066400000000000000000000202001370110300500166610ustar00rootroot00000000000000/* EXTRAITS DE LA LICENCE Copyright CEA, contributeurs : Damien CALISTE, laboratoire L_Sim, (2001-2008) Adresse ml : CALISTE, damien P caliste AT cea P fr. Ce logiciel est un programme informatique servant visualiser des structures atomiques dans un rendu pseudo-3D. Ce logiciel est rgi par la licence CeCILL soumise au droit franais et respectant les principes de diffusion des logiciels libres. Vous pouvez utiliser, modifier et/ou redistribuer ce programme sous les conditions de la licence CeCILL telle que diffuse par le CEA, le CNRS et l'INRIA sur le site "http://www.cecill.info". Le fait que vous puissiez accder cet en-tte signifie que vous avez pris connaissance de la licence CeCILL, et que vous en avez accept les termes (cf. le fichier Documentation/licence.fr.txt fourni avec ce logiciel). */ /* LICENCE SUM UP Copyright CEA, contributors: Damien CALISTE, laboratoire L_Sim, (2001-2008) E-mail address: CALISTE, damien P caliste AT cea P fr. This software is a computer program whose purpose is to visualize atomic configurations in 3D. This software is governed by the CeCILL license under French law and abiding by the rules of distribution of free software. You can use, modify and/ or redistribute the software under the terms of the CeCILL license as circulated by CEA, CNRS and INRIA at the following URL "http://www.cecill.info". The fact that you are presently reading this means that you have had knowledge of the CeCILL license and that you accept its terms. You can find a copy of this licence shipped with this software at Documentation/licence.en.txt. */ #include "plane_py.h" #include static int planePy_init (VisuPlanePy *self, PyObject *args, PyObject *kwds); static PyObject* planePy_new (PyTypeObject *type, PyObject *args, PyObject *kwds); static void planePy_free (VisuPlanePy* self); static PyObject* planePy_set (PyObject *obj, PyObject *args, PyObject *kwds); static PyObject* planePy_getRGBA(PyObject *obj, PyObject *args); static PyMethodDef VisuPlanePyMethods[] = { {"set", (PyCFunction)planePy_set, METH_VARARGS | METH_KEYWORDS, "Change the characteristics of a VisuPlane.\n\n" "Keyword arguments:\n" "rgba (optional) -- a tuple of four floats values between 0 and 1\n" " describing the RGBA colour of the plane.\n" "normal (optional) -- a tuple of three floats values representing the\n" " normal vector of the plane.\n" "distance (optional) -- a float value with the distance of the plane to\n" " the origin of the basis set.\n" "rendered (optional) -- a boolean to say if the plane is drawn or not.\n" "hide (optional) -- an integer value taking -1, 0 or +1 values\n" " specifying the hiding effect of the plane. With\n" " a value of 0, there is no masking, with +1, nodes\n" " after the plane are hidden and with -1, the ones\n" " before the plane."}, {"getRGBA", (PyCFunction)planePy_getRGBA, METH_NOARGS, "Retrieve the colour of a plane.\n\n" "Returns: a tuple of four floats values between 0 and 1\n" " describing the RGBA colour of the plane."}, {NULL, NULL, 0, NULL} }; static PyTypeObject VisuPlanePyType = { PyObject_HEAD_INIT(NULL) 0, /*ob_size*/ "v_sim.VisuPlanePy", /*tp_name*/ sizeof(VisuPlanePy), /*tp_basicsize*/ 0, /*tp_itemsize*/ (destructor)planePy_free, /*tp_dealloc*/ 0, /*tp_print*/ 0, /*tp_getattr*/ 0, /*tp_setattr*/ 0, /*tp_compare*/ 0, /*tp_repr*/ 0, /*tp_as_number*/ 0, /*tp_as_sequence*/ 0, /*tp_as_mapping*/ 0, /*tp_hash */ 0, /*tp_call*/ 0, /*tp_str*/ 0, /*tp_getattro*/ 0, /*tp_setattro*/ 0, /*tp_as_buffer*/ Py_TPFLAGS_DEFAULT | Py_TPFLAGS_BASETYPE, /*tp_flags*/ "Ploum", /* tp_doc */ 0, /* tp_traverse */ 0, /* tp_clear */ 0, /* tp_richcompare */ 0, /* tp_weaklistoffset */ 0, /* tp_iter */ 0, /* tp_iternext */ VisuPlanePyMethods, /* tp_methods */ 0, /* tp_members */ 0, /* tp_getset */ 0, /* tp_base */ 0, /* tp_dict */ 0, /* tp_descr_get */ 0, /* tp_descr_set */ 0, /* tp_dictoffset */ (initproc)planePy_init, /* tp_init */ 0, /* tp_alloc */ planePy_new, /* tp_new */ /* 0, */ /* 0, */ /* 0, */ /* 0, */ /* 0, */ /* 0, */ /* 0, */ /* 0 */ }; static int planePy_init(VisuPlanePy *self _U_, PyObject *args _U_, PyObject *kwds _U_) { return 0; } static PyObject* planePy_new(PyTypeObject *type, PyObject *args, PyObject *kwds) { VisuPlanePy *self; self = (VisuPlanePy*)type->tp_alloc(type, 0); if (self != NULL) { DBG_fprintf(stderr, "Visu Python: new VisuPlane object %p.\n", self); self->obj = visu_plane_newUndefined(); if (!self->obj) { Py_DECREF(self); return NULL; } } else return NULL; /* We call the set method. */ if (!planePy_set((PyObject*)self, args, kwds)) { Py_DECREF(self); return NULL; } /* Py_INCREF(self); */ return (PyObject *)self; } static void planePy_free(VisuPlanePy* self) { DBG_fprintf(stderr, "Visu Python: deallocate a VisuPlane object %p.\n", self); if (self->obj) g_object_unref(G_OBJECT(self->obj)); self->ob_type->tp_free((PyObject*)self); } static PyObject* planePy_set(PyObject *obj, PyObject *args, PyObject *kwds) { VisuPlanePy *self; static char *kwlist[] = {"rgba", "normal", "distance", "rendered", "hide", NULL}; PyObject *rgbPy = NULL, *vectPy = NULL, *rendered = Py_True; ToolColor *color; float rgb[4] = {-1.f, -1.f, -1.f, -1.f}; float vect[3] = {-123456.f, -1.f, -1.f}; float dist = -12345.f; int res, hide = -2; self = (VisuPlanePy*)obj; DBG_fprintf(stderr, "Visu Python: set values for VisuPlane %p object %p.\n", self->obj, obj); if (! PyArg_ParseTupleAndKeywords(args, kwds, "|O!O!fO!i", kwlist, &PyTuple_Type, &rgbPy, &PyTuple_Type, &vectPy, &dist, &PyBool_Type, &rendered, &hide)) return NULL; if (rgbPy) { if (! PyArg_ParseTuple(rgbPy, "ffff", rgb, rgb + 1, rgb + 2, rgb + 3)) return NULL; } if (vectPy) { if (! PyArg_ParseTuple(vectPy, "fff", vect, vect + 1, vect + 2)) return NULL; } res = 0; if (rgb[0] >= 0.f) { color = tool_color_addFloatRGBA(rgb, NULL); res = visu_plane_setColor(self->obj, color) || res; } if (vect[0] != -123456.f) res = visu_plane_setNormalVector(self->obj, vect) || res; if (dist != -12345.f) res = visu_plane_setDistanceFromOrigin(self->obj, dist) || res; res = visu_plane_setRendered(self->obj, (rendered == Py_True)) || res; if (hide != -2) res = visu_plane_setHiddenState(self->obj, hide) || res; if (res) { Py_INCREF(Py_True); return Py_True; } else { Py_INCREF(Py_False); return Py_False; } } static PyObject* planePy_getRGBA(PyObject *obj, PyObject *args) { VisuPlanePy *self; PyObject *ret; ToolColor *color; self = (VisuPlanePy*)obj; DBG_fprintf(stderr, "Visu Python: get RGBA for VisuPlane %p object %p.\n", self->obj, obj); visu_plane_getColor(self->obj, &color); ret = Py_BuildValue("(ffff)", color->rgba[0], color->rgba[1], color->rgba[2], color->rgba[3]); Py_INCREF(ret); return ret; } PyTypeObject* planePyGet_type() { return &VisuPlanePyType; } v_sim-3.8.0/lib/python/plane_py.h000066400000000000000000000035031370110300500166750ustar00rootroot00000000000000/* EXTRAITS DE LA LICENCE Copyright CEA, contributeurs : Damien CALISTE, laboratoire L_Sim, (2001-2008) Adresse ml : CALISTE, damien P caliste AT cea P fr. Ce logiciel est un programme informatique servant visualiser des structures atomiques dans un rendu pseudo-3D. Ce logiciel est rgi par la licence CeCILL soumise au droit franais et respectant les principes de diffusion des logiciels libres. Vous pouvez utiliser, modifier et/ou redistribuer ce programme sous les conditions de la licence CeCILL telle que diffuse par le CEA, le CNRS et l'INRIA sur le site "http://www.cecill.info". Le fait que vous puissiez accder cet en-tte signifie que vous avez pris connaissance de la licence CeCILL, et que vous en avez accept les termes (cf. le fichier Documentation/licence.fr.txt fourni avec ce logiciel). */ /* LICENCE SUM UP Copyright CEA, contributors: Damien CALISTE, laboratoire L_Sim, (2001-2008) E-mail address: CALISTE, damien P caliste AT cea P fr. This software is a computer program whose purpose is to visualize atomic configurations in 3D. This software is governed by the CeCILL license under French law and abiding by the rules of distribution of free software. You can use, modify and/ or redistribute the software under the terms of the CeCILL license as circulated by CEA, CNRS and INRIA at the following URL "http://www.cecill.info". The fact that you are presently reading this means that you have had knowledge of the CeCILL license and that you accept its terms. You can find a copy of this licence shipped with this software at Documentation/licence.en.txt. */ #include #include typedef struct _VisuPlanePy { PyObject_HEAD VisuPlane *obj; } VisuPlanePy; PyTypeObject* planePyGet_type(); #define PLANEPY_TYPE planePyGet_type() v_sim-3.8.0/lib/python/visu_py.c000066400000000000000000001045771370110300500165740ustar00rootroot00000000000000/* EXTRAITS DE LA LICENCE Copyright CEA, contributeurs : Damien CALISTE, laboratoire L_Sim, (2001-2008) Adresse m�l : CALISTE, damien P caliste AT cea P fr. Ce logiciel est un programme informatique servant � visualiser des structures atomiques dans un rendu pseudo-3D. Ce logiciel est r�gi par la licence CeCILL soumise au droit fran�ais et respectant les principes de diffusion des logiciels libres. Vous pouvez utiliser, modifier et/ou redistribuer ce programme sous les conditions de la licence CeCILL telle que diffus�e par le CEA, le CNRS et l'INRIA sur le site "http://www.cecill.info". Le fait que vous puissiez acc�der � cet en-t�te signifie que vous avez pris connaissance de la licence CeCILL, et que vous en avez accept� les termes (cf. le fichier Documentation/licence.fr.txt fourni avec ce logiciel). */ /* LICENCE SUM UP Copyright CEA, contributors: Damien CALISTE, laboratoire L_Sim, (2001-2008) E-mail address: CALISTE, damien P caliste AT cea P fr. This software is a computer program whose purpose is to visualize atomic configurations in 3D. This software is governed by the CeCILL license under French law and abiding by the rules of distribution of free software. You can use, modify and/ or redistribute the software under the terms of the CeCILL license as circulated by CEA, CNRS and INRIA at the following URL "http://www.cecill.info". The fact that you are presently reading this means that you have had knowledge of the CeCILL license and that you accept its terms. You can find a copy of this licence shipped with this software at Documentation/licence.en.txt. */ #include #include #include #include #include #include #include #include #include #include #include #include #include #include "plane_py.h" typedef struct _VisuElementPy { PyObject_HEAD VisuElement *obj; gboolean ownByVSim; } VisuElementPy; static int visuElementPy_init(VisuElementPy *self, PyObject *args, PyObject *kwds); static PyObject* visuElementPy_new(PyTypeObject *type, PyObject *args, PyObject *kwds); static void visuElementPy_free(VisuElementPy* self); static PyObject* visuElementPy_set(PyObject *obj, PyObject *args, PyObject *kwds); /* We define here all the methods of the dtsets class. */ static PyMethodDef VisuElementPyMethods[] = { {"set", (PyCFunction)visuElementPy_set, METH_VARARGS | METH_KEYWORDS, "Change values for a VisuElement."}, /* {"get", (PyCFunction)dtsets_get, METH_VARARGS, */ /* "Return the valus of an attribute."}, */ {NULL, NULL, 0, NULL} }; /* static PyMemberDef VisuElementPyMembers[] = */ /* { */ /* {"dt", T_OBJECT_EX, offsetof(Dtsets, dt), READONLY, */ /* "Internal identifier for Fortran calls."}, */ /* {NULL, 0, 0, 0, NULL} */ /* }; */ static PyTypeObject VisuElementPyType = { PyObject_HEAD_INIT(NULL) 0, /*ob_size*/ "v_sim.VisuElementPy", /*tp_name*/ sizeof(VisuElementPy), /*tp_basicsize*/ 0, /*tp_itemsize*/ (destructor)visuElementPy_free, /*tp_dealloc*/ 0, /*tp_print*/ 0, /*tp_getattr*/ 0, /*tp_setattr*/ 0, /*tp_compare*/ 0, /*tp_repr*/ 0, /*tp_as_number*/ 0, /*tp_as_sequence*/ 0, /*tp_as_mapping*/ 0, /*tp_hash */ 0, /*tp_call*/ 0, /*tp_str*/ 0, /*tp_getattro*/ 0, /*tp_setattro*/ 0, /*tp_as_buffer*/ Py_TPFLAGS_DEFAULT | Py_TPFLAGS_BASETYPE, /*tp_flags*/ "Ploum", /* tp_doc */ 0, /* tp_traverse */ 0, /* tp_clear */ 0, /* tp_richcompare */ 0, /* tp_weaklistoffset */ 0, /* tp_iter */ 0, /* tp_iternext */ VisuElementPyMethods, /* tp_methods */ 0, /* tp_members */ 0, /* tp_getset */ 0, /* tp_base */ 0, /* tp_dict */ 0, /* tp_descr_get */ 0, /* tp_descr_set */ 0, /* tp_dictoffset */ (initproc)visuElementPy_init, /* tp_init */ 0, /* tp_alloc */ visuElementPy_new, /* tp_new */ /* 0, */ /* 0, */ /* 0, */ /* 0, */ /* 0, */ /* 0, */ /* 0, */ /* 0 */ }; typedef struct _VisuDataPy VisuDataPy; typedef struct _VisuNodePy { PyObject_HEAD guint nodeId; VisuDataPy *parent; } VisuNodePy; static int visuNodePy_init(VisuNodePy *self, PyObject *args, PyObject *kwds); static PyObject* visuNodePy_new(PyTypeObject *type, PyObject *args, PyObject *kwds); static void visuNodePy_free(VisuNodePy* self); static PyObject* visuNodePy_isValid(PyObject *obj); static PyObject* visuNodePy_set(PyObject *obj, PyObject *args, PyObject *kwds); /* We define here all the methods of the dtsets class. */ static PyMethodDef VisuNodePyMethods[] = { {"set", (PyCFunction)visuNodePy_set, METH_VARARGS | METH_KEYWORDS, "Change values for a VisuNode."}, {"isValid", (PyCFunction)visuNodePy_isValid, METH_NOARGS, "Test if the given node still exist or has been deleted."}, /* {"get", (PyCFunction)dtsets_get, METH_VARARGS, */ /* "Return the valus of an attribute."}, */ {NULL, NULL, 0, NULL} }; /* static PyMemberDef VisuNodePyMembers[] = */ /* { */ /* {"dt", T_OBJECT_EX, offsetof(Dtsets, dt), READONLY, */ /* "Internal identifier for Fortran calls."}, */ /* {NULL, 0, 0, 0, NULL} */ /* }; */ static PyTypeObject VisuNodePyType = { PyObject_HEAD_INIT(NULL) 0, /*ob_size*/ "v_sim.VisuNodePy", /*tp_name*/ sizeof(VisuNodePy), /*tp_basicsize*/ 0, /*tp_itemsize*/ (destructor)visuNodePy_free, /*tp_dealloc*/ 0, /*tp_print*/ 0, /*tp_getattr*/ 0, /*tp_setattr*/ 0, /*tp_compare*/ 0, /*tp_repr*/ 0, /*tp_as_number*/ 0, /*tp_as_sequence*/ 0, /*tp_as_mapping*/ 0, /*tp_hash */ 0, /*tp_call*/ 0, /*tp_str*/ 0, /*tp_getattro*/ 0, /*tp_setattro*/ 0, /*tp_as_buffer*/ Py_TPFLAGS_DEFAULT | Py_TPFLAGS_BASETYPE, /*tp_flags*/ "Ploum", /* tp_doc */ 0, /* tp_traverse */ 0, /* tp_clear */ 0, /* tp_richcompare */ 0, /* tp_weaklistoffset */ 0, /* tp_iter */ 0, /* tp_iternext */ VisuNodePyMethods, /* tp_methods */ 0, /* tp_members */ 0, /* tp_getset */ 0, /* tp_base */ 0, /* tp_dict */ 0, /* tp_descr_get */ 0, /* tp_descr_set */ 0, /* tp_dictoffset */ (initproc)visuNodePy_init, /* tp_init */ 0, /* tp_alloc */ visuNodePy_new, /* tp_new */ /* 0, */ /* 0, */ /* 0, */ /* 0, */ /* 0, */ /* 0, */ /* 0, */ /* 0 */ }; struct _VisuDataPy { PyObject_HEAD VisuData *obj; PyObject *planes; int planesId; }; static int visuDataPy_init(VisuDataPy *self, PyObject *args, PyObject *kwds); static PyObject* visuDataPy_new(PyTypeObject *type, PyObject *args, PyObject *kwds); static void visuDataPy_free(VisuDataPy* self); static PyObject* visuDataPy_addFile(PyObject *self, PyObject *args, PyObject *kwds); static PyObject* visuDataPy_setPopulation(PyObject *self, PyObject *args, PyObject *kwds); static PyObject* visuDataPy_getPopulation(PyObject *self); static PyObject* visuDataPy_createAllNodes(PyObject *self); static PyObject* visuDataPy_setBox(PyObject *self, PyObject *args, PyObject *kwds); static PyObject* visuDataPy_addNode(PyObject *self, PyObject *args, PyObject *kwds); static PyObject* visuDataPy_delNodes(PyObject *self, PyObject *args); static PyObject* visuDataPy_setVisuPlanes(PyObject *self, PyObject *planes); /* We define here all the methods of the dtsets class. */ static PyMethodDef VisuDataPyMethods[] = { {"addFile", (PyCFunction)visuDataPy_addFile, METH_VARARGS | METH_KEYWORDS, "Associate a file name to a file type."}, {"setPopulation", (PyCFunction)visuDataPy_setPopulation, METH_VARARGS | METH_KEYWORDS, "Allocate the size to store nodes."}, {"getPopulation", (PyCFunction)visuDataPy_getPopulation, METH_NOARGS, "get a dictionnary with the description of the population."}, {"createAllNodes", (PyCFunction)visuDataPy_createAllNodes, METH_NOARGS, "Create the OpenGL rendering for all the nodes."}, {"setBox", (PyCFunction)visuDataPy_setBox, METH_VARARGS | METH_KEYWORDS, "Set the box size."}, {"addNode", (PyCFunction)visuDataPy_addNode, METH_VARARGS | METH_KEYWORDS, "Set the coordinates of a new node for the given element."}, {"delNodes", (PyCFunction)visuDataPy_delNodes, METH_VARARGS, "Delete the given nodes."}, {"setVisuPlanes", (PyCFunction)visuDataPy_setVisuPlanes, METH_O, "Draw the given planes inside the box of the given data."}, {NULL, NULL, 0, NULL} }; /* static PyMemberDef VisuDataPyMembers[] = */ /* { */ /* {"dt", T_OBJECT_EX, offsetof(Dtsets, dt), READONLY, */ /* "Internal identifier for Fortran calls."}, */ /* {NULL, 0, 0, 0, NULL} */ /* }; */ static PyTypeObject VisuDataPyType = { PyObject_HEAD_INIT(NULL) 0, /*ob_size*/ "v_sim.VisuDataPy", /*tp_name*/ sizeof(VisuDataPy), /*tp_basicsize*/ 0, /*tp_itemsize*/ (destructor)visuDataPy_free, /*tp_dealloc*/ 0, /*tp_print*/ 0, /*tp_getattr*/ 0, /*tp_setattr*/ 0, /*tp_compare*/ 0, /*tp_repr*/ 0, /*tp_as_number*/ 0, /*tp_as_sequence*/ 0, /*tp_as_mapping*/ 0, /*tp_hash */ 0, /*tp_call*/ 0, /*tp_str*/ 0, /*tp_getattro*/ 0, /*tp_setattro*/ 0, /*tp_as_buffer*/ Py_TPFLAGS_DEFAULT | Py_TPFLAGS_BASETYPE, /*tp_flags*/ "Ploum", /* tp_doc */ 0, /* tp_traverse */ 0, /* tp_clear */ 0, /* tp_richcompare */ 0, /* tp_weaklistoffset */ 0, /* tp_iter */ 0, /* tp_iternext */ VisuDataPyMethods, /* tp_methods */ 0, /* tp_members */ 0, /* tp_getset */ 0, /* tp_base */ 0, /* tp_dict */ 0, /* tp_descr_get */ 0, /* tp_descr_set */ 0, /* tp_dictoffset */ (initproc)visuDataPy_init, /* tp_init */ 0, /* tp_alloc */ visuDataPy_new, /* tp_new */ /* 0, */ /* 0, */ /* 0, */ /* 0, */ /* 0, */ /* 0, */ /* 0, */ /* 0 */ }; static int visuElementPy_init(VisuElementPy *self _U_, PyObject *args _U_, PyObject *kwds _U_) { return 0; } static PyObject* visuElementPy_new(PyTypeObject *type, PyObject *args, PyObject *kwds) { VisuElementPy *self; char *name; gchar *eleName; PyObject *argsPy = NULL, *namePy; name = (char*)0; eleName = (gchar*)0; namePy = PyTuple_GetItem(args, 0); if (! PyObject_TypeCheck(namePy, &PyString_Type) && ! PyObject_TypeCheck(namePy, &PyInt_Type)) { PyErr_SetString(PyExc_TypeError, "first argument must be a string or a Z number."); return NULL; } else { if (PyObject_TypeCheck(namePy, &PyString_Type)) name = PyString_AsString(namePy); else if (PyObject_TypeCheck(namePy, &PyInt_Type)) { if (!tool_physic_getSymbolFromZ(&eleName, (float*)0, ((PyIntObject*)namePy)->ob_ival)) PyErr_SetString(PyExc_ValueError, "Unknown element."); name = eleName; } } if (!name) return NULL; argsPy = PyTuple_GetSlice(args, 1, PyTuple_Size(args)); self = (VisuElementPy*)type->tp_alloc(type, 0); if (self != NULL) { DBG_fprintf(stderr, "Visu Python: new VisuElement object %p.\n", self); self->obj = visu_element_getFromName(name); if (self->obj) self->ownByVSim = TRUE; else { self->obj = visu_element_new(name); self->ownByVSim = FALSE; } } else { Py_DECREF(argsPy); return NULL; } if (! visuElementPy_set((PyObject*)self, argsPy, kwds)) { Py_DECREF(argsPy); return NULL; } Py_DECREF(argsPy); return (PyObject *)self; } static void visuElementPy_free(VisuElementPy* self) { DBG_fprintf(stderr, "Visu Python: deallocate a VisuElement object %p.\n", self); if (!self->ownByVSim) visuElementFree(self->obj); self->ob_type->tp_free((PyObject*)self); } static PyObject* visuElementPy_set(PyObject *obj, PyObject *args, PyObject *kwds) { VisuElementPy *self; static char *kwlist[] = {"rgba", "material", "rendered", "hidden", NULL}; PyObject *rgbPy = NULL, *matPy = NULL, *rendered = Py_True, *hidden = Py_True; float rgb[4] = {-1.f, -1.f, -1.f, -1.f}; float mat[5] = {-0.2f, -1.f, -0.5f, -0.5f, -0.f}; DBG_fprintf(stderr, "Visu Python: set values for VisuElement '%s' object %p.\n", ((VisuElementPy*)obj)->obj->name, obj); if (! PyArg_ParseTupleAndKeywords(args, kwds, "|O!O!O!O!", kwlist, &PyTuple_Type, &rgbPy, &PyTuple_Type, &matPy, &PyBool_Type, &rendered, &PyBool_Type, &hidden)) return NULL; if (rgbPy) { if (! PyArg_ParseTuple(rgbPy, "ffff", rgb, rgb + 1, rgb + 2, rgb + 3)) return NULL; } if (matPy) { if (! PyArg_ParseTuple(matPy, "fffff", mat, mat + 1, mat + 2, mat + 3, mat + 4)) return NULL; } self = (VisuElementPy*)obj; if (rgb[0] >= 0.f && mat[0] >= 0.f) visuElementSet_allColorValues(self->obj, rgb, mat); else if (rgb[0] >= 0.f) visuElementSet_allRGBValues(self->obj, rgb); else if (mat[0] >= 0.f) visuElementSet_allToolMaterialIdsValues(self->obj, mat); visuElementSet_rendered(self->obj, (rendered == Py_True)); visuElementSet_sensitiveToVisuPlanes(self->obj, (hidden == Py_True)); Py_INCREF(Py_None); return Py_None; } static int visuNodePy_init(VisuNodePy *self _U_, PyObject *args _U_, PyObject *kwds _U_) { return 0; } static PyObject* visuNodePy_new(PyTypeObject *type, PyObject *args, PyObject *kwds _U_) { VisuNodePy *self; guint id; PyObject *parentPy; if (! PyArg_ParseTuple(args, "O!I", &VisuDataPyType, &parentPy, &id)) return NULL; self = (VisuNodePy*)type->tp_alloc(type, 0); if (self == NULL) return NULL; DBG_fprintf(stderr, "Visu Python: new VisuNode object %p.\n", self); Py_INCREF(parentPy); self->nodeId = id; self->parent = (VisuDataPy*)parentPy; return (PyObject *)self; } static void visuNodePy_free(VisuNodePy* self) { DBG_fprintf(stderr, "Visu Python: deallocate a VisuNode object %p.\n", self); Py_DECREF(self->parent); self->ob_type->tp_free((PyObject*)self); } static PyObject* visuNodePy_set(PyObject *obj, PyObject *args, PyObject *kwds) { VisuNodePy *self; static char *kwlist[] = {"coord", "translation", "rendered", "emit", NULL}; PyObject *coordPy = NULL, *transPy = NULL, *rendered = Py_None, *emit = Py_False; gboolean coordSet = FALSE, transSet = FALSE; float coord[3] = {-1.f, -1.f, -1.f}; float trans[3] = {-1.f, -1.f, -1.f}; VisuNode *node; gboolean emitPos; DBG_fprintf(stderr, "Visu Python: set values for VisuNode %d object %p.\n", ((VisuNodePy*)obj)->nodeId, obj); if (! PyArg_ParseTupleAndKeywords(args, kwds, "|O!O!O!O!", kwlist, &PyTuple_Type, &coordPy, &PyTuple_Type, &transPy, &PyBool_Type, &rendered, &PyBool_Type, &emit)) return NULL; if (coordPy) { if (! PyArg_ParseTuple(coordPy, "fff", coord, coord + 1, coord + 2)) return NULL; coordSet = TRUE; } if (transPy) { if (! PyArg_ParseTuple(transPy, "fff", trans, trans + 1, trans + 2)) return NULL; transSet = TRUE; } self = (VisuNodePy*)obj; node = visuDataGet_nodeFromNumber(self->parent->obj, self->nodeId); if (!node) { PyErr_SetString(PyExc_RuntimeError, "not a VisuNode anymore."); return NULL; } emitPos = FALSE; if (coordSet) { node->xyz[0] = coord[0]; node->xyz[1] = coord[1]; node->xyz[2] = coord[2]; emitPos = (emit == Py_True); } if (transSet) { node->translation[0] = coord[0]; node->translation[1] = coord[1]; node->translation[2] = coord[2]; emitPos = (emit == Py_True); } if (rendered != Py_None && visuNodeSet_visibility(node, (rendered == Py_True)) && emit == Py_True) visuDataEmit_nodeRenderedChange(self->parent->obj); if (emitPos) visuDataEmit_nodePositionChanged(self->parent->obj); Py_INCREF(Py_None); return Py_None; } static PyObject* visuNodePy_isValid(PyObject *obj) { VisuNodePy *self; VisuNode *node; self = (VisuNodePy*)obj; node = visuDataGet_nodeFromNumber(self->parent->obj, self->nodeId); if (node) { Py_INCREF(Py_True); return Py_True; } else { Py_INCREF(Py_False); return Py_False; } } static void _onAskForHide(VisuData *visuData, gboolean *redraw, VisuDataPy *self); static void _onPositionChanged(VisuData *dataObj, VisuDataPy *self); static int visuDataPy_init(VisuDataPy *self, PyObject *args _U_, PyObject *kwds _U_) { self->planes = (PyObject*)0; self->planesId = 0; return 0; } static PyObject* visuDataPy_new(PyTypeObject *type, PyObject *args, PyObject *kwds _U_) { VisuDataPy *self; PyObject *parentPy = NULL; self = (VisuDataPy*)type->tp_alloc(type, 0); if (self != NULL) DBG_fprintf(stderr, "Visu Python: new VisuData object %p.\n", self); if (!PyArg_ParseTuple(args, "|O!", &VisuDataPyType, &parentPy)) return NULL; if (parentPy) self->obj = visuDataNew_withVisuGlView(visuDataGet_openGLView(((VisuDataPy*)parentPy)->obj)); else self->obj = visuDataNew(); g_object_ref(G_OBJECT(self->obj)); g_object_set_data(G_OBJECT(self->obj), "selfPython", self); g_signal_connect(G_OBJECT(self->obj), "AskForShowHide", G_CALLBACK(_onAskForHide), self); g_signal_connect(G_OBJECT(self->obj), "PositionChanged", G_CALLBACK(_onPositionChanged), self); return (PyObject *)self; } static void visuDataPy_free(VisuDataPy* self) { DBG_fprintf(stderr, "Visu Python: deallocate a VisuData object %p.\n", self); g_object_unref(G_OBJECT(self->obj)); self->ob_type->tp_free((PyObject*)self); } static PyObject* visuDataPy_addFile(PyObject *self, PyObject *args, PyObject *kwds) { char *filename; int type; static char *kwlist[] = {"filename", "type", NULL}; if (! PyArg_ParseTupleAndKeywords(args, kwds, "si", kwlist, &filename, &type)) return NULL; visuDataAdd_file(((VisuDataPy*)self)->obj, filename, type, (ToolFileFormat*)0); Py_INCREF(Py_None); return Py_None; } static PyObject* visuDataPy_getPopulation(PyObject *self) { PyObject* dict, *nb; const char *ele; VisuNodeArray *nodes; guint i; dict = PyDict_New(); if (!dict) return NULL; nodes = visu_data_getNodeArray(((VisuDataPy*)self)->obj); if (nodes) for (i = 0; i < nodes->ntype; i++) { nb = PyInt_FromLong((long)nodes->nStoredNodesPerEle[i]); ele = ((VisuDataPy*)self)->obj->fromIntToVisuElement[i]->name; PyDict_SetItemString(dict, ele, nb); } Py_INCREF(dict); return dict; } static PyObject* visuDataPy_setPopulation(PyObject *self, PyObject *args, PyObject *kwds) { static char *kwlist[] = {"population", "iSet", NULL}; guint ntypes, i, iSet; VisuElement **visuElementUsed; guint *nbOfNodesPerVisuElement; PyObject *dict, *key, *value; #if PY_MINOR_VERSION > 4 Py_ssize_t pos = 0; #else int pos = 0; #endif iSet = 0; if (! PyArg_ParseTupleAndKeywords(args, kwds, "O!|I", kwlist, &PyDict_Type, &dict, &iSet)) return NULL; ntypes = (guint)PyDict_Size(dict); if (ntypes == 0) { PyErr_SetString(PyExc_ValueError, "dictionary of elements must not be empty."); return NULL; } visuElementUsed = g_malloc(sizeof(VisuElement*) * ntypes); nbOfNodesPerVisuElement = g_malloc(sizeof(guint) * ntypes); visuDataFree_population(((VisuDataPy*)self)->obj); pos = 0; i = 0; while (PyDict_Next(dict, &pos, &key, &value)) { if (! PyObject_TypeCheck(key, &VisuElementPyType)) { PyErr_SetString(PyExc_TypeError, "keys must be VisuElementPy."); g_free(visuElementUsed); g_free(nbOfNodesPerVisuElement); return NULL; } if (! PyInt_Check(value) || ((PyIntObject*)value)->ob_ival <= 0) { PyErr_SetString(PyExc_TypeError, "values must be positive integer."); g_free(visuElementUsed); g_free(nbOfNodesPerVisuElement); return NULL; } Py_INCREF(key); visuElementUsed[i] = ((VisuElementPy*)key)->obj; nbOfNodesPerVisuElement[i] = (int) ((PyIntObject*)value)->ob_ival; i += 1; } if (i != ntypes) { PyErr_SetString(PyExc_RuntimeError, "can't browse the population dictionnary."); g_free(visuElementUsed); g_free(nbOfNodesPerVisuElement); return NULL; } visu_data_setPopulation(((VisuDataPy*)self)->obj, ntypes, nbOfNodesPerVisuElement, visuElementUsed); visuDataSet_setId(((VisuDataPy*)self)->obj, iSet); g_free(visuElementUsed); g_free(nbOfNodesPerVisuElement); Py_INCREF(Py_None); return Py_None; } static PyObject* visuDataPy_createAllNodes(PyObject *self) { visuData_createAllNodes(((VisuDataPy*)self)->obj); Py_INCREF(Py_None); return Py_None; } static PyObject* visuDataPy_setBox(PyObject *self, PyObject *args, PyObject *kwds) { static char *kwlist[] = {"box", "periodic", "scale", NULL}; float box[6], size; double rprimd[3][3]; PyObject *bool, *boxPy; size = 0.f; if (! PyArg_ParseTupleAndKeywords(args, kwds, "O!|O!f", kwlist, &PyTuple_Type, &boxPy, &PyBool_Type, &bool, &size)) return NULL; if (PyTuple_Size(boxPy) == 6 && ! PyArg_ParseTuple(boxPy, "ffffff", box, box + 1, box + 2, box + 3, box + 4, box + 5)) return NULL; if (PyTuple_Size(boxPy) == 3 && ! PyArg_ParseTuple(boxPy, "(ddd)(ddd)(ddd)", rprimd[0], rprimd[0] + 1, rprimd[0] + 2, rprimd[1], rprimd[1] + 1, rprimd[1] + 2, rprimd[2], rprimd[2] + 1, rprimd[2] + 2)) return NULL; if (PyTuple_Size(boxPy) == 3) tool_matrix_reducePrimitiveVectors(box, rprimd); visu_data_setBoxGeometry(((VisuDataPy*)self)->obj, box, (bool == Py_True)); visu_data_applyBoxGeometry(((VisuDataPy*)self)->obj); Py_INCREF(Py_None); return Py_None; } static PyObject* visuDataPy_addNode(PyObject *self, PyObject *args, PyObject *kwds) { float xyz[3]; static char *kwlist[] = {"element", "coord", "emit", NULL}; PyObject *ele, *emitPy = Py_False, *xyzPy; VisuNode *node; VisuNodePy *nodePy; if (! PyArg_ParseTupleAndKeywords(args, kwds, "O!O!|O!", kwlist, &VisuElementPyType, &ele, &PyTuple_Type, &xyzPy, &PyBool_Type, &emitPy)) return NULL; if (! PyArg_ParseTuple(xyzPy, "fff", xyz, xyz + 1, xyz + 2)) return NULL; node = visu_data_addNodeFromElement(((VisuDataPy*)self)->obj, ((VisuElementPy*)ele)->obj, xyz, (emitPy == Py_True)); if (!node) { PyErr_SetString(PyExc_ValueError, "can't add new node."); return NULL; } DBG_fprintf(stderr, "Visu Python: create a new object for node %d %p.\n", node->number, node); nodePy = (VisuNodePy*)PyObject_New(VisuNodePy, &VisuNodePyType); if (nodePy == NULL) return NULL; Py_INCREF(self); nodePy->nodeId = node->number; nodePy->parent = (VisuDataPy*)self; Py_INCREF(nodePy); return (PyObject *)nodePy; } static PyObject* visuDataPy_delNodes(PyObject *self, PyObject *args) { PyObject *nodesPy, *nodePy; int *nodes, n, i; if (! PyArg_ParseTuple(args, "O", &nodesPy)) return NULL; nodes = (int*)0; if (PyObject_TypeCheck(nodesPy, &PyInt_Type)) { nodes = g_malloc(sizeof(int) * 2); nodes[0] = (int) ((PyIntObject*)nodesPy)->ob_ival; if (nodes[0] < 0) { PyErr_SetString(PyExc_ValueError, "Only positive numbers identify nodes."); g_free(nodes); return NULL; } nodes[1] = -1; } else if (PyObject_TypeCheck(nodesPy, &VisuNodePyType)) { nodes = g_malloc(sizeof(int) * 2); nodes[0] = ((VisuNodePy*)nodesPy)->nodeId; nodes[1] = -1; } else if (PyObject_TypeCheck(nodesPy, &PyTuple_Type)) { n = PyTuple_GET_SIZE(nodesPy); nodes = g_malloc(sizeof(int) * (n + 1)); for (i = 0; i < n; i++) { nodePy = PyTuple_GET_ITEM(nodesPy, i); if (! PyObject_TypeCheck(nodePy, &PyInt_Type) && ! PyObject_TypeCheck(nodePy, &VisuNodePyType)) { PyErr_SetString(PyExc_TypeError, "Arguments should be integers or VisuNodePy."); g_free(nodes); return NULL; } if (PyObject_TypeCheck(nodePy, &PyInt_Type)) { nodes[i] = (int) ((PyIntObject*)nodePy)->ob_ival; if (nodes[i] < 0) { PyErr_SetString(PyExc_ValueError, "Only positive numbers identify nodes."); g_free(nodes); return NULL; } } else nodes[i] = ((VisuNodePy*)nodePy)->nodeId; } nodes[n] = -1; } else { PyErr_SetString(PyExc_TypeError, "Argument must be tuple, integer or VisuNodePy."); return NULL; } visuDataRemove_nodes(((VisuDataPy*)self)->obj, nodes); g_free(nodes); Py_INCREF(Py_None); return Py_None; } static VisuPlane** _buildArrayOfVisuPlanes(VisuDataPy *self) { int i, n; VisuPlane **planes; n = PyTuple_GET_SIZE(self->planes); planes = g_malloc(sizeof(VisuPlane*) * (n + 1)); for (i = 0; i < n; i++) planes[i] = ((VisuPlanePy*)PyTuple_GET_ITEM(self->planes, i))->obj; planes[n] = (VisuPlane*)0; return planes; } static void _rebuildVisuPlanes(VisuData *dataObj) { VisuPlane **planes; VisuDataPy *self; self = (VisuDataPy*)g_object_get_data(G_OBJECT(dataObj), "selfPython"); if (!self) return; planes = _buildArrayOfVisuPlanes(self); DBG_fprintf(stderr, "Visu Python: create OpenGL list for planes.\n"); visu_plane_class_drawList(planes, self->planesId); DBG_fprintf(stderr, " | OK\n"); g_free(planes); } static void _onVisuPlaneMoved(VisuPlane *plane _U_, VisuDataPy *self) { _rebuildVisuPlanes(self->obj); } static void _onAskForHide(VisuData *visuData, gboolean *redraw, VisuDataPy *self) { VisuPlane **planes; if (!self->planes) return; DBG_fprintf(stderr, "Visu Python: caught the 'AskForShowHide' signal for" " VisuData %p.\n", (gpointer)visuData); planes = _buildArrayOfVisuPlanes(self); *redraw = visu_plane_class_showHideAll(visuData, planes) || *redraw; g_free(planes); } static void _onPositionChanged(VisuData *dataObj, VisuDataPy *self) { gboolean redraw; DBG_fprintf(stderr, "Visu Python: caught the 'PositionChanged' signal," " recalculating masking properties.\n"); if (self->planes) { visuDataEmit_askForShowHideNodes(dataObj, &redraw); if (redraw) visuDataEmit_nodeRenderedChange(dataObj); } } static PyObject* visuDataPy_setVisuPlanes(PyObject *obj, PyObject *planes) { VisuDataPy *self = (VisuDataPy*)obj; int i; PyObject *plane; float vertices[8][3]; VisuPlane *planeObj; VisuGlExt *planeExt; if (!PyObject_TypeCheck(planes, &PyTuple_Type)) { PyErr_SetString(PyExc_TypeError, "Argument must be tuple of v_sim.plane."); return NULL; } for (i = 0; i < PyTuple_GET_SIZE(planes); i++) { plane = PyTuple_GET_ITEM(planes, i); if (! PyObject_TypeCheck(plane, PLANEPY_TYPE)) { PyErr_SetString(PyExc_TypeError, "Tuple argument must contain v_sim.plane objects."); return NULL; } } Py_XDECREF(self->planes); Py_INCREF(planes); self->planes = planes; /* We compute the plane intersections with this VisuData box, and connect the change signals. */ visuDataGet_boxVertices(self->obj, vertices, TRUE); for (i = 0; i < PyTuple_GET_SIZE(self->planes); i++) { planeObj = ((VisuPlanePy*)PyTuple_GET_ITEM(self->planes, i))->obj; g_signal_connect(G_OBJECT(planeObj), "moved", G_CALLBACK(_onVisuPlaneMoved), (gpointer)self); visu_plane_setBox(planeObj, vertices); } /* We create an OpenGL extension to draw the planes if not already done. */ if (!self->planesId) { self->planesId = visu_gl_objectlist_new(1); planeExt = visu_gl_ext_new("VisuPlanes", "VisuPlanes", (char*)0, self->planesId, _rebuildVisuPlanes); planeExt->used = 1; visu_gl_ext_setSensitiveToRenderingMode(planeExt, TRUE); visu_gl_ext_setPriority(planeExt, VISU_GL_EXT_PRIORITY_LOW + 1); visu_gl_ext_register(planeExt); } _rebuildVisuPlanes(self->obj); Py_INCREF(Py_None); return Py_None; } static int width, height; static void _createMain(GtkWindow **panel, GtkWindow **render) { GtkWidget *renderingWindow; /* Force the creation of the Scale class. */ DBG_fprintf(stderr,"Visu Python: create a rendering window (%dx%d).\n", width, height); renderingWindow = visu_ui_rendering_window_new(width, height, TRUE, FALSE); visuVisuUiRenderingWindowSet_default(renderingWindow); *panel = (GtkWindow*)0; *render = (GtkWindow*)0; return; } static gboolean _parseFiles(gpointer data _U_) { GString *message; message = visu_basic_parseConfigFiles(); if (message) { g_string_free(message, TRUE); } } static PyObject* visuPyMain(PyObject *self _U_, PyObject *args, PyObject *kwds) { PyObject *me; static char *kwlist[] = {"width", "height", NULL}; GtkWidget *renderingWindow; width = 600; height = 600; /* Try to get the width and the height. */ if (! PyArg_ParseTupleAndKeywords(args, kwds, "|ii", kwlist, &width, &height)) return NULL; /* Force the creation of the Scale class. */ DBG_fprintf(stderr,"Visu Python: create a rendering window (%dx%d).\n", width, height); renderingWindow = visu_ui_rendering_window_new(width, height, TRUE, FALSE); visuVisuUiRenderingWindowSet_default(renderingWindow); g_idle_add(_parseFiles, (gpointer)0); me = pygobject_new(G_OBJECT(renderingWindow)); Py_INCREF(me); return me; } static PyObject* visuPyLoad(PyObject *self _U_, PyObject *args, PyObject *kwds) { PyObject *obj; int iSet; PyObject *bool; static char *kwlist[] = {"data", "iSet", "internal", NULL}; GError *error; gboolean res; /* Try to get the width and the height. */ iSet = 0; if (! PyArg_ParseTupleAndKeywords(args, kwds, "O!|iO!", kwlist, &VisuDataPyType, &obj, &iSet, &PyBool_Type, &bool)) return NULL; DBG_fprintf(stderr,"Visu Python: load VisuData from %p (%p).\n", obj, ((VisuDataPy*)obj)->obj); if ((bool == Py_False)) visuGtkLoad_file(((VisuDataPy*)obj)->obj, iSet); else { error = (GError*)0; res = visu_object_load(((VisuDataPy*)obj)->obj, (ToolFileFormat*)0, iSet, &error); if (error) { PyErr_SetString(PyExc_TypeError, error->message); g_error_free(error); return NULL; } visuVisuUiRenderingWindowSet_visuData (VISU_UI_RENDERING_WINDOW(visuVisuUiRenderingWindowGet_current()), ((VisuDataPy*)obj)->obj); /* We release a ref on obj, since visu_ui_rendering_window_setData has increased it. */ g_object_unref(G_OBJECT(((VisuDataPy*)obj)->obj)); visuData_createAllNodes(((VisuDataPy*)obj)->obj); } Py_INCREF(Py_None); return Py_None; } static PyObject* visuPySet(PyObject *self _U_, PyObject *data) { if (! PyObject_TypeCheck(data, &VisuDataPyType) && data != Py_None) { PyErr_SetString(PyExc_TypeError, "argument must be of type VisuDataPy or None."); return NULL; } if (data != Py_None) { visu_ui_rendering_window_setData(VISU_UI_RENDERING_WINDOW(visuVisuUiRenderingWindowGet_current()), ((VisuDataPy*)data)->obj); rebuildAllExtensionsLists(((VisuDataPy*)data)->obj); } else visu_ui_rendering_window_setData(VISU_UI_RENDERING_WINDOW(visuVisuUiRenderingWindowGet_current()), (VisuData*)0); g_idle_add(visu_object_redraw, (gpointer)0); Py_INCREF(Py_None); return Py_None; } static PyObject* visuPyRedraw(PyObject *self _U_) { g_idle_add(visu_object_redraw, (gpointer)0); Py_INCREF(Py_None); return Py_None; } /* We define here all the methods of the module. */ static PyMethodDef ModuleMethods[] = { {"main", (PyCFunction)visuPyMain, METH_VARARGS | METH_KEYWORDS, "Start a V_Sim run and open an empty rendering window."}, {"load", (PyCFunction)visuPyLoad, METH_VARARGS | METH_KEYWORDS, "Load the given data."}, {"set", (PyCFunction)visuPySet, METH_O, "Associate a VisuData to a rendering area."}, {"redraw", (PyCFunction)visuPyRedraw, METH_NOARGS, "Redraw the rendering area."}, {NULL, NULL, 0, NULL} }; /* The name initv_sim is mandatory, do not change it! */ PyMODINIT_FUNC initv_sim(void) { PyObject *module; if (PyType_Ready(&VisuDataPyType) < 0) return; if (PyType_Ready(&VisuElementPyType) < 0) return; if (PyType_Ready(&VisuNodePyType) < 0) return; if (PyType_Ready(PLANEPY_TYPE) < 0) return; module = Py_InitModule("v_sim", ModuleMethods); if (module == NULL) return; Py_INCREF(&VisuDataPyType); PyModule_AddObject(module, "data", (PyObject*)&VisuDataPyType); Py_INCREF(&VisuElementPyType); PyModule_AddObject(module, "element", (PyObject*)&VisuElementPyType); Py_INCREF(&VisuNodePyType); PyModule_AddObject(module, "node", (PyObject*)&VisuNodePyType); Py_INCREF(PLANEPY_TYPE); PyModule_AddObject(module, "plane", (PyObject*)PLANEPY_TYPE); init_pygobject(); init_pygtk(); /* Set the static paths for V_Sim. */ visuBasicSet_paths((const gchar*)0); visu_basic_init(); } v_sim-3.8.0/m4/000077500000000000000000000000001370110300500131455ustar00rootroot00000000000000v_sim-3.8.0/m4/abinit.m4000066400000000000000000000113451370110300500146610ustar00rootroot00000000000000AC_DEFUN([AC_CHECK_ABINIT], [ AC_MSG_CHECKING([for Abinit support]) AC_ARG_WITH([abinit], [AS_HELP_STRING([--with-abinit=ARG],[ABINIT directory (with include and lib subdirs)])], [AB_PATH=$withval], [AB_PATH="no"]) AC_ARG_WITH([abinit_include], [AS_HELP_STRING([--with-abinit-include=ARG],[specific ABINIT include directory])], [AB_PATH_INC=$withval], [AB_PATH_INC=""]) AC_ARG_WITH([abinit_libdir], [AS_HELP_STRING([--with-abinit-libdir=ARG],[specific ABINIT library directory])], [AB_PATH_LIBDIR=$withval], [AB_PATH_LIBDIR=""]) AC_MSG_RESULT($AB_PATH) dnl In case ABINIT is demanded, we test Lapack first. if test "z$AB_PATH" != "zno" ; then AC_REQUIRE([ACX_LAPACK]) if test x"$acx_lapack_ok" = xno; then AC_WARN([ABINIT support has been disabled since Lapack is not available.]) AB_PATH="no" fi fi dnl We also test ETSF_IO if test "z$AB_PATH" != "zno" ; then AC_REQUIRE([AC_CHECK_ETSF_IO]) if test x"$ac_etsf_io_ok" = xno; then AC_WARN([ABINIT support may not compile since ETSF_IO is not available.]) fi fi dnl We also test LibXC if test "z$AB_PATH" != "zno" ; then AC_REQUIRE([AC_CHECK_LIBXC]) if test x"$ac_libxc_ok" = xno; then AC_WARN([ABINIT support may not compile since LibXC is not available.]) fi fi if test "z$AB_PATH" != "zno" ; then AS_IF([test "z$AB_PATH" = "zyes"],[AB_PATH="/opt/etsf/abinit"]) AS_IF([test "z$AB_PATH_LIBDIR" = "z"],[AB_PATH_LIBDIR="$AB_PATH/lib"]) AS_IF([test "z$AB_PATH_INC" = "z"],[AB_PATH_INC="$AB_PATH/include"]) dnl First thing is to test the header files. CPPFLAGS_SVG=$CPPFLAGS CPPFLAGS="$CPPFLAGS -I$AB_PATH_INC" AC_CHECK_HEADER([ab6_invars.h], [ac_abinit_parser_header="ab6_invars.h"], [ac_abinit_parser_header="no"]) if test $ac_abinit_parser_header = "no" ; then AC_CHECK_HEADER([ab7_invars.h], [ac_abinit_parser_header="ab7_invars.h"], [ac_abinit_parser_header="no"]) fi CPPFLAGS=$CPPFLAGS_SVG dnl Try to guess the lib name. AB_LIBRARY="abinis" AB_LIBRARY_VERSION=6 if test -f $AB_PATH_LIBDIR/libabinit6.a ; then AB_LIBRARY="abinit6" fi if test -f $AB_PATH_LIBDIR/libabinit7.a ; then AB_LIBRARY="abinit7" AB_LIBRARY_VERSION=7 fi dnl Try to find the missing dependencies in libabinis.a. AC_FC_WRAPPERS() AC_FC_FUNC([wrtout]) AC_FC_FUNC([leave_new]) AC_FC_FUNC([timab]) AC_FC_FUNC([psp_from_data]) AC_LANG_PUSH([C]) LIBS_SVG=$LIBS LIBS="$LIBS_SVG -L$AB_PATH_LIBDIR -l$AB_LIBRARY $ETSF_IO_LIBS $LIBXC_LIBS $LAPACK_LIBS $BLAS_LIBS $FCLIBS" CFLAGS_SVG=$CFLAGS CFLAGS="$CFLAGS -Wno-error" dnl Look for the parser in libabinis. AC_MSG_CHECKING([for parser capabilities in lib$AB_LIBRARY.a from $AB_PATH_LIBDIR]) AC_LINK_IFELSE([AC_LANG_SOURCE([ void $wrtout() { } void $leave_new() { } void $timab() { } void $psp_from_data() { } int main(int argc, const char **argv) { ab${AB_LIBRARY_VERSION}_invars_new_from_file(); return 0; } ])], [ac_abinit_parser_ok=yes], [ac_abinit_parser_ok=no]) AC_MSG_RESULT([$ac_abinit_parser_ok]) dnl Look for specific functions in the parser routines. if test $ac_abinit_parser_ok = "yes" ; then AC_MSG_CHECKING([for invars.new_from_file_with_pseudo() routine in lib$AB_LIBRARY.a]) AC_LINK_IFELSE([AC_LANG_SOURCE([ void $wrtout() { } void $leave_new() { } void $timab() { } void $psp_from_data() { } int main(int argc, const char **argv) { ab${AB_LIBRARY_VERSION}_invars_new_from_file_with_pseudo(); return 0; } ])], [ac_abinit_invars_has_new_with_pseudo=yes], [ac_abinit_invars_has_new_with_pseudo=no]) AC_MSG_RESULT([$ac_abinit_invars_has_new_with_pseudo]) AC_DEFINE([HAVE_NEW_WITH_PSEUDO], [], [If set, we can call ab_invars_new_from_file_with_pseudo()]) fi LIBS=$LIBS_SVG CFLAGS=$CFLAGS_SVG AC_LANG_POP([C]) AS_IF([test "z$ac_abinit_parser_header" != "zno" -a "z$ac_abinit_parser_ok" = "zyes"], [ac_abinit_parser=yes], [ac_abinit_parser=no]) AS_IF([test "z$ac_abinit_parser" = "zyes"], [AB_LIBS="-L$AB_PATH_LIBDIR -l$AB_LIBRARY $LIBXC_LIBS $ETSF_IO_LIBS $LAPACK_LIBS $BLAS_LIBS"; AB_CPPFLAGS="-I$AB_PATH_INC"], []) dnl For buit-in symmetry routines. ABI_FC_MODULE_MANGLING() ac_abinit=yes else ac_abinit=no fi ]) v_sim-3.8.0/m4/ax_check_gl.m4000066400000000000000000000060261370110300500156420ustar00rootroot00000000000000##### http://autoconf-archive.cryp.to/ax_check_gl.html # # SYNOPSIS # # AX_CHECK_GL # # DESCRIPTION # # Check for an OpenGL implementation. If GL is found, the required # compiler and linker flags are included in the output variables # "GL_CFLAGS" and "GL_LIBS", respectively. This macro adds the # configure option "--with-apple-opengl-framework", which users can # use to indicate that Apple's OpenGL framework should be used on Mac # OS X. If Apple's OpenGL framework is used, the symbol # "HAVE_APPLE_OPENGL_FRAMEWORK" is defined. If no GL implementation # is found, "no_gl" is set to "yes". # # LAST MODIFICATION # # 2004-11-15 # # COPYLEFT # # Copyright (c) 2004 Braden McDaniel # # Copying and distribution of this file, with or without # modification, are permitted in any medium without royalty provided # the copyright notice and this notice are preserved. AC_DEFUN([AX_CHECK_GL], [AC_REQUIRE([AC_PATH_X])dnl #AC_REQUIRE([ACX_PTHREAD])dnl # # There isn't a reliable way to know we should use the Apple OpenGL framework # without a configure option. A Mac OS X user may have installed an # alternative GL implementation (e.g., Mesa), which may or may not depend on X. # AC_ARG_WITH([apple-opengl-framework], [AC_HELP_STRING([--with-apple-opengl-framework], [use Apple OpenGL framework (Mac OS X only)])]) if test "X$with_apple_opengl_framework" = "Xyes"; then AC_DEFINE([HAVE_APPLE_OPENGL_FRAMEWORK], [1], [Use the Apple OpenGL framework.]) GL_LIBS="-framework OpenGL" else AC_LANG_PUSH(C) AX_LANG_COMPILER_MS if test X$ax_compiler_ms = Xno; then GL_CFLAGS="${PTHREAD_CFLAGS}" GL_LIBS="${PTHREAD_LIBS} -lm" fi # # Use x_includes and x_libraries if they have been set (presumably by # AC_PATH_X). # if test "X$no_x" != "Xyes"; then if test -n "$x_includes"; then GL_CFLAGS="-I${x_includes} ${GL_CFLAGS}" fi if test -n "$x_libraries"; then GL_LIBS="-L${x_libraries} -lX11 ${GL_LIBS}" fi fi AC_CHECK_HEADERS([windows.h]) AC_CACHE_CHECK([for OpenGL library], [ax_cv_check_gl_libgl], [ax_cv_check_gl_libgl="no" ax_save_CPPFLAGS="${CPPFLAGS}" CPPFLAGS="${GL_CFLAGS} ${CPPFLAGS}" ax_save_LIBS="${LIBS}" LIBS="" ax_check_libs="-lopengl32 -lGL" for ax_lib in ${ax_check_libs}; do if test X$ax_compiler_ms = Xyes; then ax_try_lib=`echo $ax_lib | sed -e 's/^-l//' -e 's/$/.lib/'` else ax_try_lib="${ax_lib}" fi LIBS="${ax_try_lib} ${GL_LIBS} ${ax_save_LIBS}" AC_LINK_IFELSE( [AC_LANG_PROGRAM([[ # if HAVE_WINDOWS_H && defined(_WIN32) # include # endif # include ]], [[glBegin(0)]])], [ax_cv_check_gl_libgl="${ax_try_lib}"; break]) done LIBS=${ax_save_LIBS} CPPFLAGS=${ax_save_CPPFLAGS}]) if test "X${ax_cv_check_gl_libgl}" = "Xno"; then no_gl="yes" GL_CFLAGS="" GL_LIBS="" else GL_LIBS="${ax_cv_check_gl_libgl} ${GL_LIBS}" fi AC_LANG_POP(C) fi AC_SUBST([GL_CFLAGS]) AC_SUBST([GL_LIBS]) ])dnl v_sim-3.8.0/m4/ax_check_glu.m4000066400000000000000000000047241370110300500160320ustar00rootroot00000000000000##### http://autoconf-archive.cryp.to/ax_check_glu.html # # SYNOPSIS # # AX_CHECK_GLU # # DESCRIPTION # # Check for GLU. If GLU is found, the required preprocessor and # linker flags are included in the output variables "GLU_CFLAGS" and # "GLU_LIBS", respectively. This macro adds the configure option # "--with-apple-opengl-framework", which users can use to indicate # that Apple's OpenGL framework should be used on Mac OS X. If # Apple's OpenGL framework is used, the symbol # "HAVE_APPLE_OPENGL_FRAMEWORK" is defined. If no GLU implementation # is found, "no_glu" is set to "yes". # # LAST MODIFICATION # # 2004-11-15 # # COPYLEFT # # Copyright (c) 2004 Braden McDaniel # # Copying and distribution of this file, with or without # modification, are permitted in any medium without royalty provided # the copyright notice and this notice are preserved. AC_DEFUN([AX_CHECK_GLU], [AC_REQUIRE([AX_CHECK_GL])dnl AC_REQUIRE([AC_PROG_CXX])dnl GLU_CFLAGS="${GL_CFLAGS}" if test "X${with_apple_opengl_framework}" != "Xyes"; then AC_CACHE_CHECK([for OpenGL Utility library], [ax_cv_check_glu_libglu], [ax_cv_check_glu_libglu="no" ax_save_CPPFLAGS="${CPPFLAGS}" CPPFLAGS="${GL_CFLAGS} ${CPPFLAGS}" ax_save_LIBS="${LIBS}" LIBS="" ax_check_libs="-lglu32 -lGLU" for ax_lib in ${ax_check_libs}; do if test X$ax_compiler_ms = Xyes; then ax_try_lib=`echo $ax_lib | sed -e 's/^-l//' -e 's/$/.lib/'` else ax_try_lib="${ax_lib}" fi LIBS="${ax_try_lib} ${GL_LIBS} ${ax_save_LIBS}" # # libGLU typically links with libstdc++ on POSIX platforms. However, # setting the language to C++ means that test program source is named # "conftest.cc"; and Microsoft cl doesn't know what to do with such a # file. # AC_LANG_PUSH([C++]) if test X$ax_compiler_ms = Xyes; then AC_LANG_PUSH([C]) fi AC_LINK_IFELSE( [AC_LANG_PROGRAM([[ # if HAVE_WINDOWS_H && defined(_WIN32) # include # endif # include ]], [[gluBeginCurve(0)]])], [ax_cv_check_glu_libglu="${ax_try_lib}"; break]) if test X$ax_compiler_ms = Xyes; then AC_LANG_POP([C]) fi AC_LANG_POP([C++]) done LIBS=${ax_save_LIBS} CPPFLAGS=${ax_save_CPPFLAGS}]) if test "X${ax_cv_check_glu_libglu}" = "Xno"; then no_glu="yes" GLU_CFLAGS="" GLU_LIBS="" else GLU_LIBS="${ax_cv_check_glu_libglu} ${GL_LIBS}" fi fi AC_SUBST([GLU_CFLAGS]) AC_SUBST([GLU_LIBS]) ]) v_sim-3.8.0/m4/ax_lang_compiler_ms.m4000066400000000000000000000017241370110300500174150ustar00rootroot00000000000000##### http://autoconf-archive.cryp.to/ax_lang_compiler_ms.html # # SYNOPSIS # # AX_LANG_COMPILER_MS # # DESCRIPTION # # Check whether the compiler for the current language is Microsoft. # # This macro is modeled after _AC_LANG_COMPILER_GNU in the GNU # Autoconf implementation. # # LAST MODIFICATION # # 2004-11-15 # # COPYLEFT # # Copyright (c) 2004 Braden McDaniel # # Copying and distribution of this file, with or without # modification, are permitted in any medium without royalty provided # the copyright notice and this notice are preserved. AC_DEFUN([AX_LANG_COMPILER_MS], [AC_CACHE_CHECK([whether we are using the Microsoft _AC_LANG compiler], [ax_cv_[]_AC_LANG_ABBREV[]_compiler_ms], [AC_COMPILE_IFELSE([AC_LANG_PROGRAM([], [[#ifndef _MSC_VER choke me #endif ]])], [ax_compiler_ms=yes], [ax_compiler_ms=no]) ax_cv_[]_AC_LANG_ABBREV[]_compiler_ms=$ax_compiler_ms ])]) v_sim-3.8.0/m4/ax_lapack.m4000066400000000000000000000126431370110300500153400ustar00rootroot00000000000000AC_DEFUN([ACX_BLAS], [ AC_PREREQ(2.50) AC_REQUIRE([AC_F77_LIBRARY_LDFLAGS]) acx_blas_ok=no AC_ARG_WITH(blas, [AC_HELP_STRING([--with-blas=<lib>], [use BLAS library <lib>])]) case $with_blas in yes | "") ;; no) acx_blas_ok=disable ;; -* | */* | *.a | *.so | *.so.* | *.o) BLAS_LIBS="$with_blas" ;; *) BLAS_LIBS="-l$with_blas" ;; esac # Get fortran linker names of BLAS functions to check for. AC_F77_FUNC(sgemm) AC_F77_FUNC(dgemm) acx_blas_save_LIBS="$LIBS" LIBS="$LIBS $FLIBS" # First, check BLAS_LIBS environment variable if test $acx_blas_ok = no; then if test "x$BLAS_LIBS" != x; then save_LIBS="$LIBS"; LIBS="$BLAS_LIBS $LIBS" AC_MSG_CHECKING([for $sgemm in $BLAS_LIBS]) AC_TRY_LINK_FUNC($sgemm, [acx_blas_ok=yes], [BLAS_LIBS=""]) AC_MSG_RESULT($acx_blas_ok) LIBS="$save_LIBS" fi fi # BLAS linked to by default? (happens on some supercomputers) if test $acx_blas_ok = no; then save_LIBS="$LIBS"; LIBS="$LIBS" AC_CHECK_FUNC($sgemm, [acx_blas_ok=yes]) LIBS="$save_LIBS" fi # BLAS in ATLAS library? (http://math-atlas.sourceforge.net/) if test $acx_blas_ok = no; then AC_CHECK_LIB(atlas, ATL_xerbla, [AC_CHECK_LIB(f77blas, $sgemm, [AC_CHECK_LIB(cblas, cblas_dgemm, [acx_blas_ok=yes BLAS_LIBS="-lcblas -lf77blas -latlas"], [], [-lf77blas -latlas])], [], [-latlas])]) fi # BLAS in PhiPACK libraries? (requires generic BLAS lib, too) if test $acx_blas_ok = no; then AC_CHECK_LIB(blas, $sgemm, [AC_CHECK_LIB(dgemm, $dgemm, [AC_CHECK_LIB(sgemm, $sgemm, [acx_blas_ok=yes; BLAS_LIBS="-lsgemm -ldgemm -lblas"], [], [-lblas])], [], [-lblas])]) fi # BLAS in Alpha CXML library? if test $acx_blas_ok = no; then AC_CHECK_LIB(cxml, $sgemm, [acx_blas_ok=yes;BLAS_LIBS="-lcxml"]) fi # BLAS in Alpha DXML library? (now called CXML, see above) if test $acx_blas_ok = no; then AC_CHECK_LIB(dxml, $sgemm, [acx_blas_ok=yes;BLAS_LIBS="-ldxml"]) fi # BLAS in Sun Performance library? if test $acx_blas_ok = no; then if test "x$GCC" != xyes; then # only works with Sun CC AC_CHECK_LIB(sunmath, acosp, [AC_CHECK_LIB(sunperf, $sgemm, [BLAS_LIBS="-xlic_lib=sunperf -lsunmath" acx_blas_ok=yes],[],[-lsunmath])]) fi fi # BLAS in SCSL library? (SGI/Cray Scientific Library) if test $acx_blas_ok = no; then AC_CHECK_LIB(scs, $sgemm, [acx_blas_ok=yes; BLAS_LIBS="-lscs"]) fi # BLAS in SGIMATH library? if test $acx_blas_ok = no; then AC_CHECK_LIB(complib.sgimath, $sgemm, [acx_blas_ok=yes; BLAS_LIBS="-lcomplib.sgimath"]) fi # BLAS in IBM ESSL library? (requires generic BLAS lib, too) if test $acx_blas_ok = no; then AC_CHECK_LIB(blas, $sgemm, [AC_CHECK_LIB(essl, $sgemm, [acx_blas_ok=yes; BLAS_LIBS="-lessl -lblas"], [], [-lblas $FLIBS])]) fi # Generic BLAS library? if test $acx_blas_ok = no; then AC_CHECK_LIB(blas, $sgemm, [acx_blas_ok=yes; BLAS_LIBS="-lblas"]) fi AC_SUBST(BLAS_LIBS) LIBS="$acx_blas_save_LIBS" # Finally, execute ACTION-IF-FOUND/ACTION-IF-NOT-FOUND: if test x"$acx_blas_ok" = xyes; then ifelse([$1],,AC_DEFINE(HAVE_BLAS,1,[Define if you have a BLAS library.]),[$1]) : else acx_blas_ok=no $2 fi ])dnl ACX_BLAS AC_DEFUN([ACX_LAPACK], [ AC_REQUIRE([ACX_BLAS]) acx_lapack_ok=no AC_ARG_WITH(lapack, [AC_HELP_STRING([--with-lapack=<lib>], [use LAPACK library <lib>])]) case $with_lapack in yes | "") ;; no) acx_lapack_ok=disable ;; -* | */* | *.a | *.so | *.so.* | *.o) LAPACK_LIBS="$with_lapack" ;; *) LAPACK_LIBS="-l$with_lapack" ;; esac # Get fortran linker name of LAPACK function to check for. AC_F77_FUNC(cheev) # We cannot use LAPACK if BLAS is not found if test "x$acx_blas_ok" != xyes; then acx_lapack_ok=noblas fi # First, check LAPACK_LIBS environment variable if test "x$LAPACK_LIBS" != x; then save_LIBS="$LIBS"; LIBS="$LAPACK_LIBS $BLAS_LIBS $LIBS $FLIBS" AC_MSG_CHECKING([for $cheev in $LAPACK_LIBS]) AC_TRY_LINK_FUNC($cheev, [acx_lapack_ok=yes], [LAPACK_LIBS=""]) AC_MSG_RESULT($acx_lapack_ok) LIBS="$save_LIBS" if test acx_lapack_ok = no; then LAPACK_LIBS="" fi fi # LAPACK linked to by default? (is sometimes included in BLAS lib) if test $acx_lapack_ok = no; then save_LIBS="$LIBS"; LIBS="$LIBS $BLAS_LIBS $FLIBS" AC_CHECK_FUNC($cheev, [acx_lapack_ok=yes]) LIBS="$save_LIBS" fi # Generic LAPACK library? for lapack in lapack lapack_rs6k; do if test $acx_lapack_ok = no; then save_LIBS="$LIBS"; LIBS="$BLAS_LIBS $LIBS" AC_CHECK_LIB($lapack, $cheev, [acx_lapack_ok=yes; LAPACK_LIBS="-l$lapack"], [], [$FLIBS]) LIBS="$save_LIBS" fi done AC_SUBST(LAPACK_LIBS) # Finally, execute ACTION-IF-FOUND/ACTION-IF-NOT-FOUND: if test x"$acx_lapack_ok" = xyes; then ifelse([$1],,AC_DEFINE(HAVE_LAPACK,1,[Define if you have LAPACK library.]),[$1]) : else acx_lapack_ok=no $2 fi ])dnl ACX_LAPACK v_sim-3.8.0/m4/bigdft.m4000066400000000000000000000043421370110300500146510ustar00rootroot00000000000000AC_DEFUN([AX_CHECK_BIGDFT], [ AC_MSG_CHECKING([for BigDFT support]) AC_ARG_WITH([bigdft], [AS_HELP_STRING([--with-bigdft=ARG],[BigDFT directory (with include and lib subdirs)])], [BIGDFT_PATH=$withval], [BIGDFT_PATH="no"]) AC_ARG_WITH([bigdft_include], [AS_HELP_STRING([--with-bigdft-include=ARG],[specific BigDFT include directory])], [BIGDFT_PATH_INC=$withval], [BIGDFT_PATH_INC=""]) AC_ARG_WITH([bigdft_libdir], [AS_HELP_STRING([--with-bigdft-libdir=ARG],[specific BigDFT library directory])], [BIGDFT_PATH_LIBDIR=$withval], [BIGDFT_PATH_LIBDIR=""]) AC_MSG_RESULT($BIGDFT_PATH) if test "z$BIGDFT_PATH" != "zno" ; then AS_IF([test "z$BIGDFT_PATH" = "zyes"],[BIGDFT_PATH="/opt/etsf/bigdft"]) AS_IF([test "z$BIGDFT_PATH_LIBDIR" = "z"],[BIGDFT_PATH_LIBDIR="$BIGDFT_PATH/lib"]) AS_IF([test "z$BIGDFT_PATH_INC" = "z"],[BIGDFT_PATH_INC="$BIGDFT_PATH/include"]) PKG_CHECK_MODULES(GLIB_BIGDFT, glib-2.0 gobject-2.0 gthread-2.0 gio-2.0 >= 2.22) dnl First thing is to test the header file. CPPFLAGS_SVG=$CPPFLAGS CPPFLAGS="$CPPFLAGS -I$BIGDFT_PATH_INC $GLIB_BIGDFT_CFLAGS" AC_CHECK_HEADER([bigdft.h], [ac_bigdft_header="yes"], [ac_bigdft_header="no"]) CPPFLAGS=$CPPFLAGS_SVG dnl Try to find the missing dependencies in libabinis.a. AC_FC_WRAPPERS() AC_LANG_PUSH([C]) dnl Look for the wavefunction functions in libbigdft.a. AC_MSG_CHECKING([for wavefunctions in libbigdft-1.so from $BIGDFT_PATH_LIBDIR]) CFLAGS_SVG=$CFLAGS CFLAGS="$CFLAGS -Wno-error" LIBS_SVG=$LIBS BIGDFT_LIBS="-L$BIGDFT_PATH_LIBDIR -lbigdft-1" LIBS="$LIBS_SVG $BIGDFT_LIBS" AC_LINK_IFELSE([AC_LANG_SOURCE([ int main(int argc, const char **argv) { bigdft_read_wave_descr(); return 0; } ])], [ac_bigdft_ok=yes], [ac_bigdft_ok=no]) LIBS=$LIBS_SVG CFLAGS=$CFLAGS_SVG AC_MSG_RESULT([$ac_bigdft_ok]) AC_LANG_POP([C]) AS_IF([test "z$ac_bigdft_header" = "zyes" -a "z$ac_bigdft_ok" = "zyes"], [ac_bigdft=yes; BIGDFT_CPPFLAGS="-I$BIGDFT_PATH_INC"], [ac_bigdft=no; BIGDFT_LIBS=""]) else ac_bigdft=no fi ]) v_sim-3.8.0/m4/bind-fortran.m4000066400000000000000000000102421370110300500157730ustar00rootroot00000000000000# -*- Autoconf -*- # # Copyright (C) 2010-2016 ABINIT Group (Damien Caliste, Yann Pouillon) # # This file is part of the ABINIT software package. For license information, # please see the COPYING file in the top-level directory of the ABINIT source # distribution. # # # Fortran bindings # # ABI_FC_MODULE_MANGLING() # ------------------------ # # Determines the Fortran module name-mangling scheme. # AC_DEFUN([ABI_FC_MODULE_MANGLING],[ dnl Init abi_fc_module_ok="no" dnl Preserve environment dnl ABI_ENV_BACKUP abi_saved_LIBS="${LIBS}" AC_LANG_PUSH([Fortran]) dnl Compile a simple module AC_COMPILE_IFELSE(dnl [[ module conftest contains subroutine foobar() return end subroutine foobar end module conftest ]], [abi_fc_module_ok="yes"; mv conftest.${ac_objext} cfortran_test.${ac_objext}]) dnl Check that we got the information we need if test "${abi_fc_module_ok}" = "no"; then AC_MSG_FAILURE([cannot compile a simple Fortran program]) fi dnl Extract information from the object file LIBS="cfortran_test.${ac_objext} ${LIBS} $[]_AC_LANG_PREFIX[]LIBS" dnl Look at the output of AC_FC_FUNC tmp_success="no" AC_LANG_PUSH([C]) AC_FC_FUNC([foobar]) for tmp_mod in "conftest" "CONFTEST" "foobar" "FOOBAR" "${foobar}" ; do for tmp_sub in "foobar" "FOOBAR" "${foobar}" "conftest" "CONFTEST" ; do for tmp_begin in "__" "" ; do for tmp_middle in "__" "_MOD_" "_MP_" "_mp_" ".in." "." "_" ; do tmp_func="${tmp_begin}${tmp_mod}${tmp_middle}${tmp_sub}" AC_LINK_IFELSE([AC_LANG_CALL([], [${tmp_func}])], [tmp_success="yes"; break 4]) done done done done AC_LANG_POP([C]) dnl Define first concatenation symbol only if tmp_begin is not empty if test "${tmp_begin}" = ""; then tmp_bc="" else tmp_bc="##" fi dnl Define macro in config.h if test "${tmp_success}" = "yes"; then AH_TEMPLATE(ABI_FC_MOD,[Fortran module name mangling macro.]) case "${tmp_mod}x${tmp_sub}" in conftestxfoobar) AC_DEFINE_UNQUOTED(ABI_FC_MOD(mod,MOD,sub,SUB), [${tmp_begin} ${tmp_bc} mod ## ${tmp_middle} ## sub]) ;; conftestxFOOBAR) AC_DEFINE_UNQUOTED(ABI_FC_MOD(mod,MOD,sub,SUB), [${tmp_begin} ${tmp_bc} mod ## ${tmp_middle} ## SUB]) ;; conftestx${foobar}) AC_DEFINE_UNQUOTED(ABI_FC_MOD(mod,MOD,sub,SUB), [${tmp_begin} ${tmp_bc} mod ## ${tmp_middle} ## FC_FUNC(sub,SUB)]) ;; CONFTESTxfoobar) AC_DEFINE_UNQUOTED(ABI_FC_MOD(mod,MOD,sub,SUB), [${tmp_begin} ${tmp_bc} MOD ## ${tmp_middle} ## sub]) ;; CONFTESTxFOOBAR) AC_DEFINE_UNQUOTED(ABI_FC_MOD(mod,MOD,sub,SUB), [${tmp_begin} ${tmp_bc} MOD ## ${tmp_middle} ## SUB]) ;; CONFTESTx${foobar}) AC_DEFINE_UNQUOTED(ABI_FC_MOD(mod,MOD,sub,SUB), [${tmp_begin} ${tmp_bc} MOD ## ${tmp_middle} ## FC_FUNC(sub,SUB)]) ;; foobarxconftest) AC_DEFINE_UNQUOTED(ABI_FC_MOD(mod,MOD,sub,SUB), [${tmp_begin} ${tmp_bc} sub ## ${tmp_middle} ## mod]) ;; foobarxCONFTEST) AC_DEFINE_UNQUOTED(ABI_FC_MOD(mod,MOD,sub,SUB), [${tmp_begin} ${tmp_bc} sub ## ${tmp_middle} ## MOD]) ;; ${foobar}xconftest) AC_DEFINE_UNQUOTED(ABI_FC_MOD(mod,MOD,sub,SUB), [${tmp_begin} ${tmp_bc} FC_FUNC(sub,SUB) ## ${tmp_middle} ## mod]) ;; ${foobar}xCONFTEST) AC_DEFINE_UNQUOTED(ABI_FC_MOD(mod,MOD,sub,SUB), [${tmp_begin} ${tmp_bc} FC_FUNC(sub,SUB) ## ${tmp_middle} ## MOD]) ;; FOOBARxconftest) AC_DEFINE_UNQUOTED(ABI_FC_MOD(mod,MOD,sub,SUB), [${tmp_begin} ${tmp_bc} SUB ## ${tmp_middle} ## mod]) ;; FOOBARxCONFTEST) AC_DEFINE_UNQUOTED(ABI_FC_MOD(mod,MOD,sub,SUB), [${tmp_begin} ${tmp_bc} SUB ## ${tmp_middle} ## MOD]) ;; esac abi_fc_mod_name="${tmp_begin}module${tmp_middle}subroutine" else abi_fc_mod_name="unknown" fi dnl Display final result AC_MSG_CHECKING([for the Fortran module name-mangling scheme]) AC_MSG_RESULT([${abi_fc_mod_name}]) dnl Restore environment AC_LANG_POP([Fortran]) dnl ABI_ENV_RESTORE LIBS="${abi_saved_LIBS}" rm -f cfortran_test* conftest* ]) # ABI_FC_MODULE_MANGLING v_sim-3.8.0/m4/etsf_io.m4000066400000000000000000000055221370110300500150430ustar00rootroot00000000000000dnl example of use dnl AC_CHECK_ETSF_IO( dnl [ dnl LIBS="$LIBS $ETSF_IO_LIBS" dnl LDFLAGS="$LDFLAGS $ETSF_IO_LDFLAGS" dnl CPPFLAGS="$CPPFLAGS $ETSF_IO_CPPFLAGS" dnl ], dnl [ dnl echo "*** Use --with-etsf-io for the root etsf_io directory." dnl echo "*** Otherwise use --with-etsf-io-include switch for includes directory" dnl echo "*** and --with-etsf-io-libdir switch for libraries directory." dnl AC_MSG_ERROR([etsf_io library and etsf_io headers are required.]) dnl ] dnl ) # Check for the etsf_io library. # AC_CHECK_ETSF_IO([ACTION-IF-FOUND],[ACTION-IF-NOT-FOUND],[INTERFACE-NR]) # if interface number is given, check for a specific interface # sets ETSF_IO_LDFLAGS, ETSF_IO_LIBS, and, by calling other macros # ETSF_IO_CPPFLAGS and maybe ETSF_IO_ETSF_IO_3_CPPFLAG AC_DEFUN([AC_CHECK_ETSF_IO], [ AC_REQUIRE([AC_CHECK_NETCDF]) AC_ARG_WITH([etsf_io], [AS_HELP_STRING([--with-etsf-io=ARG],[etsf_io directory])], [ETSF_IO_PATH=$withval], [ETSF_IO_PATH=""]) AC_ARG_WITH([etsf_io_include], [AS_HELP_STRING([--with-etsf-io-include=ARG],[etsf_io include directory])], [ETSF_IO_PATH_INC=$withval], [ETSF_IO_PATH_INC=""]) AC_ARG_WITH([etsf_io_libdir], [AS_HELP_STRING([--with-etsf-io-libdir=ARG],[etsf_io library directory])], [ETSF_IO_PATH_LIBDIR=$withval], [ETSF_IO_PATH_LIBDIR=""]) AS_IF([test "z$ETSF_IO_PATH" != "z"],[ AS_IF([test "z$ETSF_IO_PATH_LIBDIR" = "z"],[ETSF_IO_PATH_LIBDIR="$ETSF_IO_PATH/lib"]) AS_IF([test "z$ETSF_IO_PATH_INC" = "z"],[ETSF_IO_PATH_INC="$ETSF_IO_PATH/include"]) ]) ac_etsf_io_ok='no' ETSF_IO_LIBS= AC_LANG_PUSH(Fortran) AC_FC_SRCEXT(f90) LDFLAGS_SVG="$LDFLAGS" LIBS_SVG="$LIBS" FCFLAGS_SVG="$FCFLAGS" AS_IF([test -n "$ETSF_IO_PATH_LIBDIR"], [LDFLAGS="$LDFLAGS -L$ETSF_IO_PATH_LIBDIR"]) AS_IF([test -n "$ETSF_IO_PATH_INC"], [FCFLAGS="$FCFLAGS -I$ETSF_IO_PATH_INC"]) AS_IF([test -n "$NC_LDFLAGS"], [LDFLAGS="$LDFLAGS $NC_LDFLAGS"]) AS_IF([test -n "$NC_CPPFLAGS"], [FCFLAGS="$FCFLAGS $NC_CPPFLAGS"]) LIBS="$LIBS -letsf_io -lnetcdff $NC_LIBS" AC_MSG_CHECKING([for ETSF_IO library]) AC_LINK_IFELSE([[ program main use etsf_io type(etsf_groups_flags) :: groups type(etsf_dims) :: dims logical :: lstat type(etsf_io_low_error) :: error_data call etsf_io_data_init("test", groups, dims, "test", "", lstat, error_data) end]], ac_etsf_io_ok=yes, ac_etsf_io_ok=no) AC_MSG_RESULT([$ac_etsf_io_ok]) LIBS="$LIBS_SVG" LDFLAGS="$LDFLAGS_SVG" FCFLAGS="$FCFLAGS_SVG" if test "$ac_etsf_io_ok" = "yes"; then ETSF_IO_LIBS="-letsf_io_utils -letsf_io -lnetcdff $NC_LIBS" AS_IF([test -n "$ETSF_IO_PATH_LIBDIR"], [ETSF_IO_LIBS="-L$ETSF_IO_PATH_LIBDIR $ETSF_IO_LIBS"]) AC_SUBST([ETSF_IO_LIBS]) fi AC_LANG_POP(Fortran) ]) v_sim-3.8.0/m4/libxc.m4000066400000000000000000000047061370110300500145170ustar00rootroot00000000000000dnl example of use dnl AC_CHECK_LIBXC( dnl [ dnl LIBS="$LIBS $LIBXC_LIBS" dnl LDFLAGS="$LDFLAGS $LIBXC_LDFLAGS" dnl CPPFLAGS="$CPPFLAGS $LIBXC_CPPFLAGS" dnl ], dnl [ dnl echo "*** Use --with-libxc for the root libxc directory." dnl echo "*** Otherwise use --with-libxc-include switch for includes directory" dnl echo "*** and --with-libxc-libdir switch for libraries directory." dnl AC_MSG_ERROR([libxc library and libxc headers are required.]) dnl ] dnl ) # Check for the libxc library. # AC_CHECK_LIBXC([ACTION-IF-FOUND],[ACTION-IF-NOT-FOUND],[INTERFACE-NR]) # if interface number is given, check for a specific interface # sets LIBXC_LDFLAGS, LIBXC_LIBS, and, by calling other macros # LIBXC_CPPFLAGS and maybe LIBXC_LIBXC_3_CPPFLAG AC_DEFUN([AC_CHECK_LIBXC], [ AC_ARG_WITH([libxc], [AS_HELP_STRING([--with-libxc=ARG],[libxc directory])], [LIBXC_PATH=$withval], [LIBXC_PATH=""]) AC_ARG_WITH([libxc_include], [AS_HELP_STRING([--with-libxc-include=ARG],[libxc include directory])], [LIBXC_PATH_INC=$withval], [LIBXC_PATH_INC=""]) AC_ARG_WITH([libxc_libdir], [AS_HELP_STRING([--with-libxc-libdir=ARG],[libxc library directory])], [LIBXC_PATH_LIBDIR=$withval], [LIBXC_PATH_LIBDIR=""]) AS_IF([test "z$LIBXC_PATH" != "z"],[ AS_IF([test "z$LIBXC_PATH_LIBDIR" = "z"],[LIBXC_PATH_LIBDIR="$LIBXC_PATH/lib"]) AS_IF([test "z$LIBXC_PATH_INC" = "z"],[LIBXC_PATH_INC="$LIBXC_PATH/include"]) ]) ac_libxc_ok='no' LIBXC_LIBS= AC_LANG_PUSH(Fortran) AC_FC_SRCEXT(f90) LDFLAGS_SVG="$LDFLAGS" LIBS_SVG="$LIBS" FCFLAGS_SVG="$FCFLAGS" AS_IF([test -n "$LIBXC_PATH_LIBDIR"], [LDFLAGS="$LDFLAGS -L$LIBXC_PATH_LIBDIR"]) AS_IF([test -n "$LIBXC_PATH_INC"], [FCFLAGS="$FCFLAGS -I$LIBXC_PATH_INC"]) AS_IF([test -n "$NC_LDFLAGS"], [LDFLAGS="$LDFLAGS $NC_LDFLAGS"]) AS_IF([test -n "$NC_CPPFLAGS"], [FCFLAGS="$FCFLAGS $NC_CPPFLAGS"]) LIBS="$LIBS -lxc" AC_MSG_CHECKING([for LIBXC library]) AC_LINK_IFELSE([[ program main call xc_f90_family_from_id() end]], ac_libxc_ok=yes, ac_libxc_ok=no) AC_MSG_RESULT([$ac_libxc_ok]) LIBS="$LIBS_SVG" LDFLAGS="$LDFLAGS_SVG" FCFLAGS="$FCFLAGS_SVG" if test "$ac_libxc_ok" = "yes"; then LIBXC_LIBS="-lxc" AS_IF([test -n "$LIBXC_PATH_LIBDIR"], [LIBXC_LIBS="-L$LIBXC_PATH_LIBDIR $LIBXC_LIBS"]) AC_SUBST([LIBXC_LIBS]) fi AC_LANG_POP(Fortran) ]) v_sim-3.8.0/m4/msym.m4000066400000000000000000000034361370110300500144020ustar00rootroot00000000000000AC_DEFUN([AC_CHECK_MSYM], [ AC_MSG_CHECKING([for libmsym support]) AC_ARG_WITH([msym], [AS_HELP_STRING([--with-msym=ARG],[MSYM directory (with include and lib subdirs)])], [MSYM_PATH=$withval], [MSYM_PATH="no"]) AC_ARG_WITH([msym_inc], [AS_HELP_STRING([--with-msym-inc=ARG],[specific MSYM include directive])], [MSYM_INC=$withval], [MSYM_INC=""]) AC_ARG_WITH([msym_lib], [AS_HELP_STRING([--with-msym-lib=ARG],[specific MSYM library directive])], [MSYM_LIB=$withval], [MSYM_LIB=""]) AC_MSG_RESULT($MSYM_PATH) ac_msym="no" if test "z$MSYM_PATH" != "zno" ; then AS_IF([test "z$MSYM_PATH" = "zyes"],[MSYM_PATH="/usr"]) AS_IF([test "z$MSYM_LIB" = "z"],[MSYM_LIB="-L$MSYM_PATH/lib -lmsym"]) AS_IF([test "z$MSYM_INC" = "z"],[MSYM_INC="-I$MSYM_PATH/include"]) ac_msym="yes" fi if test "z$MSYM_PATH" == "zbuiltin" ; then ac_msym="builtin" AC_PATH_PROG([CMAKE], [cmake], [ac_msym="no"]) fi dnl Builtin case if test "z$ac_msym" == "zbuiltin" ; then MSYM_CPPFLAGS="-I\$(srcdir)/libmsym/src -Ibuiltin" MSYM_LIBS="builtin/libmsym.a -lm" fi dnl First thing is to test the header files. if test "z$ac_msym" == "zyes" ; then CPPFLAGS_SVG=$CPPFLAGS CPPFLAGS="$CPPFLAGS $MSYM_INC" AC_CHECK_HEADER([msym.h], [MSYM_CPPFLAGS="$MSYM_INC"], [ac_msym="no"]) CPPFLAGS=$CPPFLAGS_SVG fi dnl Look for the context in libmsym. if test "z$ac_msym" == "zyes" ; then AC_LANG_PUSH([C]) LIBS_SVG=$LIBS LIBS="$LIBS $MSYM_LIB" AC_CHECK_LIB(msym, msymCreateContext, [MSYM_LIBS="$MSYM_LIB -lm"], [ac_msym="no"], [-lm]) LIBS=$LIBS_SVG AC_LANG_POP([C]) fi ]) v_sim-3.8.0/m4/netcdf.m4000066400000000000000000000171431370110300500146600ustar00rootroot00000000000000dnl example of use dnl AC_CHECK_NETCDF( dnl [ dnl LIBS="$LIBS $NC_LIBS" dnl LDFLAGS="$LDFLAGS $NC_LDFLAGS" dnl CPPFLAGS="$CPPFLAGS $NC_CPPFLAGS" dnl ], dnl [ dnl echo "*** Use --with-netcdf for the root netcdf directory." dnl echo "*** Otherwise use --with-netcdf-include switch for includes directory" dnl echo "*** and --with-netcdf-libdir switch for libraries directory." dnl AC_MSG_ERROR([netcdf library and netcdf headers are required.]) dnl ] dnl ) # Check for the netcdf library. # AC_CHECK_NETCDF([ACTION-IF-FOUND],[ACTION-IF-NOT-FOUND],[INTERFACE-NR]) # if interface number is given, check for a specific interface # sets NC_LDFLAGS, NC_LIBS, and, by calling other macros # NC_CPPFLAGS and maybe NC_NETCDF_3_CPPFLAG AC_DEFUN([AC_CHECK_NETCDF], [ AC_ARG_WITH([netcdf], [AS_HELP_STRING([--with-netcdf=ARG],[netcdf directory])], [NC_PATH=$withval], [NC_PATH=""]) AC_ARG_WITH([netcdf_include], [AS_HELP_STRING([--with-netcdf-include=ARG],[netcdf include directory])], [NC_PATH_INC=$withval], [NC_PATH_INC=""]) AC_ARG_WITH([netcdf_libdir], [AS_HELP_STRING([--with-netcdf-libdir=ARG],[netcdf library directory])], [NC_PATH_LIBDIR=$withval], [NC_PATH_LIBDIR=""]) AS_IF([test "z$NC_PATH" != "z"], [ AS_IF([test "z$NC_PATH_LIBDIR" = "z"],[NC_PATH_LIBDIR="$NC_PATH/lib"]) AS_IF([test "z$NC_PATH_INC" = "z"],[NC_PATH_INC="$NC_PATH/include"]) ]) ac_netcdf_ok='no' NC_LIBS= NC_LDFLAGS= ac_nc_save_LDFLAGS=$LDFLAGS ac_nc_save_LIBS=$LIBS ac_check_nc_func_checked='ncopen' ac_check_nc_interface= dnl the interface number isn't quoted with "" otherwise a newline dnl following the number isn't stripped. m4_if([$3],[],[ac_check_nc_interface=2],[ac_check_nc_interface=$3]) AS_IF([test "z$ac_check_nc_interface" = 'z3'], [ac_check_nc_func_checked='nc_open']) AS_IF([test "z$NC_PATH_LIBDIR" != "z"], [ NC_LDFLAGS="-L$NC_PATH_LIBDIR" LDFLAGS="$LDFLAGS $NC_LDFLAGS" dnl the autoconf internal cache isn't avoided because we really check for dnl libnetcdf, other libraries that implement the same api have other names dnl AC_LINK_IFELSE([AC_LANG_CALL([],[$ac_check_func_checked])], AC_CHECK_LIB([netcdf],[$ac_check_nc_func_checked], [ NC_LIBS='-lnetcdf' ac_netcdf_ok='yes' ]) ], [ for ac_netcdf_libdir in "" \ /usr/local/netcdf-${ac_check_nc_interface}/lib \ /opt/netcdf-${ac_check_nc_interface}/lib \ /usr/netcdf-${ac_check_nc_interface}/lib \ /usr/local/lib/netcdf-${ac_check_nc_interface} \ /opt/lib/netcdf-${ac_check_nc_interface} \ /usr/lib/netcdf-${ac_check_nc_interface} \ /usr/local/netcdf/lib /opt/netcdf/lib \ /usr/netcdf/lib /usr/local/lib/netcdf /opt/lib/netcdf \ /usr/lib/netcdf ; do AS_IF([test "z$ac_netcdf_libdir" = 'z'], [NC_LDFLAGS=], [ AC_MSG_CHECKING([for netcdf libraries in $ac_netcdf_libdir]) NC_LDFLAGS="-L$ac_netcdf_libdir" ]) LDFLAGS="$LDFLAGS $NC_LDFLAGS" LIBS="$LIBS -lnetcdf" dnl we have to avoid the autoconf internal cache in that case AC_LINK_IFELSE([AC_LANG_CALL([],[$ac_check_nc_func_checked])], [ NC_LIBS='-lnetcdf' ac_netcdf_ok='yes' AS_IF([test "z$ac_netcdf_libdir" != 'z'],[AC_MSG_RESULT([yes])]) ], [ AS_IF([test "z$ac_netcdf_libdir" != 'z'],[AC_MSG_RESULT([no])]) ]) AS_IF([test $ac_netcdf_ok = 'yes'],[break]) LDFLAGS=$ac_nc_save_LDFLAGS LIBS=$ac_nc_save_LIBS done ]) LDFLAGS=$ac_nc_save_LDFLAGS LIBS=$ac_nc_save_LIBS AC_SUBST([NC_LDFLAGS]) AC_SUBST([NC_LIBS]) ac_netcdf_header='no' AS_IF([test "z$NC_PATH_INC" != "z"], [ AC_CHECK_NETCDF_HEADER([$NC_PATH_INC], [ac_netcdf_header='yes'], [ac_netcdf_header='no'], [$ac_check_nc_interface]) ], [ for ac_netcdf_incdir in "" \ /usr/local/netcdf-${ac_check_nc_interface}/include \ /opt/netcdf-${ac_check_nc_interface}/include \ /usr/netcdf-${ac_check_nc_interface}/include \ /usr/local/include/netcdf-${ac_check_nc_interface} \ /opt/include/netcdf-${ac_check_nc_interface} \ /usr/include/netcdf-${ac_check_nc_interface} \ /usr/local/netcdf/include \ /opt/netcdf/include /usr/netcdf/include /usr/local/include/netcdf \ /opt/include/netcdf /usr/include/netcdf ; do AC_MSG_NOTICE([searching netcdf includes in $ac_netcdf_incdir]) AC_CHECK_NETCDF_HEADER([$ac_netcdf_incdir],[ac_netcdf_header='yes'], [ac_netcdf_header='no'],[$ac_check_nc_interface]) AS_IF([test $ac_netcdf_header = 'yes'],[break]) done ]) AS_IF([test "$ac_netcdf_ok" = 'no' -o "$ac_netcdf_header" = 'no'], [m4_if([$2], [], [:], [$2])], [m4_if([$1], [], [:], [$1])]) ]) # Check for the netcdf header. # AC_CHECK_NETCDF_HEADER([INCLUDE-DIR],[ACTION-IF-FOUND], # [ACTION-IF-NOT-FOUND],[INTERFACE-NR]) # if interface number is given, check for a specific interface # sets NC_CPPFLAGS and maybe NC_NETCDF_3_CPPFLAG AC_DEFUN([AC_CHECK_NETCDF_HEADER], [ NC_CPPFLAGS= ac_netcdf_h='no' ac_netcdf_h_compile='no' ac_netcdf_h_preproc='no' ac_nc_include_dir= ac_nc_header_interface= ac_nc_save_CPPFLAGS=$CPPFLAGS m4_if([$1],[],[:],[ ac_nc_include_dir="$1" AS_IF([test "z$ac_nc_include_dir" != "z"], [CPPFLAGS="$CPPFLAGS -I$ac_nc_include_dir"]) ]) m4_if([$4],[],[:],[ac_nc_header_interface=$4]) dnl dont use AC_CHECK_HEADERS to avoid autoconf internal caching AC_MSG_CHECKING([for netcdf.h with compiler]) AC_COMPILE_IFELSE([AC_LANG_SOURCE([[#include ]])], [ AC_MSG_RESULT([yes]) ac_netcdf_h_compile='yes' ], [ AC_MSG_RESULT([no]) ac_netcdf_h_compile='no' ]) AC_MSG_CHECKING([for netcdf.h with preprocessor]) AC_PREPROC_IFELSE([AC_LANG_SOURCE([[#include ]])], [ AC_MSG_RESULT([yes]) ac_netcdf_h_preproc='yes' ], [ AC_MSG_RESULT([no]) ac_netcdf_h_preproc='no' ]) CPPFLAGS="$ac_nc_save_CPPFLAGS" AS_IF([test $ac_netcdf_h_compile = 'yes'], [ac_netcdf_h='yes' AS_IF([test "z$ac_nc_header_interface" = 'z3'], [AC_CHECK_NETCDF_3_HEADER([$1], [ac_netcdf_h='yes'],[ac_netcdf_h='no'])]) ]) AS_IF([test "$ac_netcdf_h" = 'yes'], [ AS_IF([test "z$ac_nc_include_dir" != "z"], [NC_CPPFLAGS="-I$ac_nc_include_dir"]) m4_if([$2], [], [:], [$2]) ], [m4_if([$3], [], [:], [$3])]) AC_SUBST([NC_CPPFLAGS]) ]) AC_DEFUN([AC_CHECK_NETCDF_3_HEADER], [ NC_NETCDF_3_CPPFLAG= ac_check_netcdf_3_include= ac_check_netcdf_3_header='no' ac_nc_save_CPPFLAGS=$CPPFLAGS AC_MSG_CHECKING([for netcdf 3 interface]) m4_if([$1],[],[:],[ ac_check_netcdf_3_include="$1" ]) AS_IF([test "z$ac_check_netcdf_3_include" != "z"], [CPPFLAGS="$CPPFLAGS -I$ac_check_netcdf_3_include"]) AC_COMPILE_IFELSE([AC_LANG_PROGRAM([[#include ]], [[int status; int ncid; status = nc_open("foo.nc", 0, &ncid); char vernum; vernum = *nc_inq_libvers();]])], [ AS_IF([test "z$ac_check_netcdf_3_include" != "z"], [NC_NETCDF_3_CPPFLAG="-I$ac_check_netcdf_3_include"]) ac_check_netcdf_3_header='yes' ],[ac_check_netcdf_3_header='no']) CPPFLAGS=$ac_nc_save_CPPFLAGS AS_IF([test "$ac_check_netcdf_3_header" = 'yes'], [ AC_MSG_RESULT([yes]) m4_if([$2], [], [:], [$2]) ], [ AC_MSG_RESULT([no]) m4_if([$3], [], [:], [$3]) ]) AC_SUBST([NC_NETCDF_3_CPPFLAG]) ]) v_sim-3.8.0/m4/python.m4000066400000000000000000000036141370110300500147340ustar00rootroot00000000000000## this one is commonly used with AM_PATH_PYTHONDIR ... dnl AM_CHECK_PYMOD(MODNAME [,SYMBOL [,ACTION-IF-FOUND [,ACTION-IF-NOT-FOUND]]]) dnl Check if a module containing a given symbol is visible to python. AC_DEFUN([AM_CHECK_PYMOD], [AC_REQUIRE([AM_PATH_PYTHON]) py_mod_var=`echo $1['_']$2 | sed 'y%./+-%__p_%'` AC_MSG_CHECKING(for ifelse([$2],[],,[$2 in ])python module $1) AC_CACHE_VAL(py_cv_mod_$py_mod_var, [ ifelse([$2],[], [prog=" import sys try: import $1 except ImportError: sys.exit(1) except: sys.exit(0) sys.exit(0)"], [prog=" import $1 $1.$2"]) if $PYTHON -c "$prog" 1>&AC_FD_CC 2>&AC_FD_CC then eval "py_cv_mod_$py_mod_var=yes" else eval "py_cv_mod_$py_mod_var=no" fi ]) py_val=`eval "echo \`echo '$py_cv_mod_'$py_mod_var\`"` if test "x$py_val" != xno; then AC_MSG_RESULT(yes) ifelse([$3], [],, [$3 ])dnl else AC_MSG_RESULT(no) ifelse([$4], [],, [$4 ])dnl fi ]) dnl a macro to check for ability to create python extensions dnl AM_CHECK_PYTHON_HEADERS([ACTION-IF-POSSIBLE], [ACTION-IF-NOT-POSSIBLE]) dnl function also defines PYTHON_INCLUDES AC_DEFUN([AM_CHECK_PYTHON_HEADERS], [AC_REQUIRE([AM_PATH_PYTHON]) AC_MSG_CHECKING(for headers required to compile python extensions) dnl deduce PYTHON_INCLUDES py_prefix=`$PYTHON -c "import sys; print sys.prefix"` py_exec_prefix=`$PYTHON -c "import sys; print sys.exec_prefix"` if test -x "$PYTHON-config"; then PYTHON_INCLUDES=`$PYTHON-config --includes 2>/dev/null` else PYTHON_INCLUDES="-I${py_prefix}/include/python${PYTHON_VERSION}" if test "$py_prefix" != "$py_exec_prefix"; then PYTHON_INCLUDES="$PYTHON_INCLUDES -I${py_exec_prefix}/include/python${PYTHON_VERSION}" fi fi AC_SUBST(PYTHON_INCLUDES) dnl check if the headers exist: save_CPPFLAGS="$CPPFLAGS" CPPFLAGS="$CPPFLAGS $PYTHON_INCLUDES" AC_TRY_CPP([#include ],dnl [AC_MSG_RESULT(found) $1],dnl [AC_MSG_RESULT(not found) $2]) CPPFLAGS="$save_CPPFLAGS" ]) v_sim-3.8.0/m4/yaml.m4000066400000000000000000000056241370110300500143600ustar00rootroot00000000000000# -*- Autoconf -*- # # Copyright (c) 2014 BigDFT Group (Damien Caliste) # All rights reserved. # # This file is part of the BigDFT software package. For license information, # please see the COPYING file in the top-level directory of the BigDFT source # distribution. # AC_DEFUN([AX_YAML], [dnl C-level YAML support. AC_ARG_WITH([yaml-path], AS_HELP_STRING([--with-yaml-path], [give a path to find libyaml.]), [ax_yaml_path=$withval]) if test x"$ax_yaml_path" == x"" ; then ax_yaml_path="/usr" fi CPPFLAGS_SVG=$CPPFLAGS CPPFLAGS="$CPPFLAGS -I$ax_yaml_path/include" AC_LANG_PUSH(C) AC_CHECK_HEADER([yaml.h], [ax_have_yaml="yes"], [ax_have_yaml="no"]) if test x"$ax_have_yaml" = x"yes"; then if test x"$ax_yaml_path" != x"/usr" ; then LIB_YAML_CFLAGS="-I$ax_yaml_path/include" else for path in ${C_INCLUDE_PATH//:/ }; do LIB_YAML_CFLAGS="$LIB_YAML_CFLAGS -I$path" done fi else AC_MSG_ERROR([libyaml is not available, install YAML and provide path --with-yaml-path.]) fi CPPFLAGS=$CPPFLAGS_SVG LDFLAGS_SVG="$LDFLAGS" LDFLAGS="$LDFLAGS -L$ax_yaml_path/lib" AC_CHECK_LIB([yaml], [yaml_parser_parse], [ax_have_yaml=yes], [ax_have_yaml=no]) if test x"$ax_have_yaml" = x"yes"; then if test x"$ax_yaml_path" != x"/usr" ; then LIB_YAML_LIBS="-L$ax_yaml_path/lib " fi LIB_YAML_LIBS=$LIB_YAML_LIBS"-lyaml" else AC_MSG_ERROR([libyaml is not available, install YAML and provide path --with-yaml-path.]) fi AC_LANG_POP(C) LDFLAGS="$LDFLAGS_SVG" AC_SUBST(LIB_YAML_CFLAGS) AC_SUBST(LIB_YAML_LIBS) ]) AC_DEFUN([AX_PYYAML], [dnl Test for libXC dnl Python itself (set to ":" if not present). AC_REQUIRE([AM_PATH_PYTHON]) AC_ARG_WITH([pyyaml-path], AS_HELP_STRING([--with-pyyaml-path], [give a path to find YAML python module.]), [AX_PYYAML_PATH=$withval], [AX_PYYAML_PATH=$pyexecdir]) ax_have_pyyaml="no" if test "$PYTHON" != ":" ; then AC_MSG_CHECKING([for PyYAML and CLoader from]) cat > pytest << EOF import sys sys.path.insert(0, "$AX_PYYAML_PATH") try: import yaml try: l = yaml.CLoader print "0" except: print "2" except: print "1" EOF eval=$($PYTHON pytest) rm -f pytest case "$eval" in "0") AC_MSG_RESULT([$AX_PYYAML_PATH]) ax_have_pyyaml="yes" ;; "2") AC_MSG_RESULT([no]) AC_MSG_WARN([CLoader not available, check that the PyYAML python module was linked with the C-level YAML implementation.]) ax_have_pyyaml="yes" ;; *) AC_MSG_RESULT([no]) AC_MSG_WARN([PyYAML not available, use --with-pyyaml-path to specify the module location.]) ax_have_pyyaml="no" ;; esac fi AM_CONDITIONAL(HAVE_PYYAML, test x"$ax_have_pyyaml" = x"yes") AC_SUBST(AX_PYYAML_PATH) ]) v_sim-3.8.0/pixmaps/000077500000000000000000000000001370110300500143065ustar00rootroot00000000000000v_sim-3.8.0/pixmaps/16x16/000077500000000000000000000000001370110300500150735ustar00rootroot00000000000000v_sim-3.8.0/pixmaps/16x16/v_sim.png000066400000000000000000000020101370110300500167070ustar00rootroot00000000000000PNG  IHDRabKGD pHYsHHFk>IDAT8EKL\e޹wf@c4(MäiUCR5IbE]i@S]h*EѤ%JXԅ4a<{xp̽w!ēmNR`63񸿯epaƋGWl)W B+ Bn'x`ϭ[m|$Rp75 w$R*Em]ETu}>gYw*RJ>v%\rZYy A*axE|E^sc};:wٙolo)~N1ux<g`px,Lm{ҩCCBEu(P]HE!eQkj^_FֶQe "p>F˶70[׮ieȸkp0#%9ҲpIɐXYA\GO>kk9R6(E#@WUPrSS(;095UJ[;FzoU)L1?=͎i"4 w0H^YN!~$ڮlvszq00vX?х)<ҙ @f1Id"AYIɂz0n$ .ǙM1M(,Idpt%VnիWOW`3v KI&[XSU03WQi#˿hj~uVkvxŹyLGwk?~Сgnڻ;sNrGǎJ;icg߽'ZZg=:Wё6/R|DKrg'o^``V|\DTǏk7Qyzwf2OۦT*xh^ KJEQLJeo)%0?y]T{a 3$C}1>1;$QHE̼>r?|Z8}|KJk- j)`.ΟǽxaJ߶ 5iN9_=xD (8Z `<]ssb}; z- I~FGUWagRE#54ZEjRRc WD!~Ac^?v]##  јy=ӮT5@PcuX K6MH?`::x;q4囏>JT+5acOSiJ*Ԥ,% aºuHg'M[ȹYq2ZqٵM8B:"8XKV,  >M(I?Q8ju /[{DўZd6KK,WƐ0OONLjA@q_^>ӄtf,.]5 9r{GH80J[[Q2+W/a`/^Y#rC}kK0$Xim o؀."ΙޣTC]^~fIrLN+DȈXKf=©Sjy c7L!+}s(wtJ g|,"س/NNM}m~/!X{ P`0P35DopA#yn0yQzE0X "3XR(Q݌;z<wJ9κ/ȚW$y7fVoR\9\0wmIENDB`v_sim-3.8.0/pixmaps/24x24/000077500000000000000000000000001370110300500150715ustar00rootroot00000000000000v_sim-3.8.0/pixmaps/24x24/v_sim.png000066400000000000000000000030121370110300500167100ustar00rootroot00000000000000PNG  IHDRw=sBIT|d pHYsZtEXtSoftwarewww.inkscape.org<IDATHmlg==-mZi{J7J)X\kf6T >0 -11$~g| FIƸ-4&Ľdm0J ЁPkiOs@[Sur܏*wR"bjrG84|`̋F${Y++Һq~hLWl}`W3 NP? ى/a~0vٶ{~;WUE%껷rN 噧ŋCCCԩ@i>Fnw_zGGwCC#iGJ佳557dT8& Cڱܿ/}fj?Pf塺7Vkj#-uО=,/>MǤqLxW}}vc[}@W[,Jrv##TMM|v\! C0$ jvr,PUVb)0,Ƹbx&AŲ8$QDE?Z˲sں:<G(0ӪL:.AQ+^#xhϟ' Pe*Q'T5^sˢ*QaD20nvYR.K|]FqrpMx9رc2n0fCQmO,#CH5b,IdrLyn{a9Μ5u㭢Hn` R -Dºztn6ٲ߿ξU͎PѱB& n$U2_"Gb{6vj&u٘5޶!/ R-!̡@)hx>޸Oj\HˮR`SmȹhcK{{KI&l.mSt]nv*NyͼSdPM,"N #ó{.@˅BkR^ߏSL&5y1yŞ>RE+QHL+W^h%Ͽ5OƷER7nTs3IB $FD!ϣ4(uhHJ!J?4tqg&k!Y;'H\ڵnnA |*͎C $ea Q$W]!Re ,[g;v ðM.վh8i&mL D-,M }K0owwq(-[ 83B!k7n$ ^2jMX.3Sw]f>@FfR#yy0d^k+'M1EDڸls3`ee\("_(u}ʾWSR0w/N#:}#X%%Qg'>4A7݄(2 >9UA^r ݂eː88M_߯J2Ibol͛=xuVa)8J&G=v R01S(b10y8<2I}*j()R؆A֛&C,]|DsgyX*P@&A~vo]]Jf@-ؾIWZBϒ\s>jZE'L؈H91:Q,ᵴоw<:WUaD2Go "%(H$8˱wc=79)mH+E6;HUJQ a[r9:2d{'ONٳ*G,[.B` 0ƮBQ ^`gkDiQ8~mYވ~oIDAThkpTe9t҉e-qaJRtU#EX˸LZNtL1(슊` 8!#\:nt>d@ZxCw~yskvͮw@2\888DPX4S%0 k"drastLӴ Rʫ!PJQeD9rWiaZ<'#"Dž8 |8R[[K k%i~8mmmS&f6#$CgΰsNye.Z[[WW_};v裏uVt]8* hi~B$Roc|@ϡC$?i(BQSoj"V[K(< === x8L&oӣ{o% "!NooPeq&a4Ds3~w^;F"`ƍJ{M-[~kX^UEUS3V$H78twu #)\&=4D>i,bK/zz ]יmc6]'J12< /@2dҥM恦JI,0g2bKix(`x=~r%'Owf !4tWヒf;$t(EY>RIEPJ.׋S.8,ၺz:ĭmm44]'WB@GUM=F<RաBH$_ :MQ`iʅŲE㥘HY6ޱ1Qd>/qdw\,Xmiᜀ?X,馫.b`xh~@0.H=ǕוB@p 2 b|q>ۗ/Ep-CJx|F|~?,'{zTHMÖ`I%% B@rtulظY/\ߧP(pz`wŒ;n7/cJgzzZ6ǘH!p* %M 2Ŷm 9lD:ю~NTuuūfqw#P;޳wY)B<mmm3 Pb!:4H.q@˨r3siR`(bIChT"駠-uk2qx<ieǁz<ӗ8ҕV XR UI&@:-,-@:0Pu~?R SJ RutH{kr/졻;B]l{/T*Mx P؎_ЄR Ҡ %RJ\ǃy lY؎t9Pz7x 矣"immwf-sGsE"*8XfB.K1(Ҳ+%"Duw#D A @8k8tl(x( < .[nEJRe˖{nH3М ͝Kd8%v!4Xrʥ6_2!BJMC:0Ъ(&fo/T,ZDS?<\".J)\ץh4JMM ӆH47Ӵz5'N08єV oER'U(_e7@;-@ o(D9?z."iXl6K\\@[￟/CR\z!pK)/TUL]bT.Ћ Οb7Z/ΞDTW3kٶmGH)Ybw簾bH\]jl_dD|BUcRr% %2›N#D(P 'zMAJhJaa˖-u]h6 D<' Q*xS,1nW zP^[˂~Sf_y/JۘmSSj!}}}d2ۯ eZx#_&Յ(R AI6RQ5մv?زU/S' n:;;QJA,r=p3g\/JؤOIP$VJC'j$ vmiF_5Lhl(iMo8#Z2hmRMV J6Y)&+d@hmRMV J6Y)&+d@#U!ip?3%pAK)rI%= ޺ֳ~]jۇT$'S@IrcgKNj k08 0po卬`?^R"!ۏWx*6 K%]P$FHh`A^`ЛEul{UA iw"NかGYYj$ %lZ+t:Il?΢\lF`rDEZ^Ns_\ N@YYQ }{( `;p:edQ.WIn["jIz51F lBљ+lo'zHMHz6`8A(#n-ΕtˊdlJFuOhZEDb/EKGjH@n`?Iٳv7\CD~˒"zT0h-Y RkZV٬㶏 mn* I]}h:thGr,0p!&SASV8n!KR0 E w8>̭sA<1!  Nd-55C%i ѽ_q'I.zl- o<+bĬ8'DxV# `ז+آfk)jZgI|<(reMeb1pvIZ/ XK Eק!B&')U L7N` },a8)<7x,>D8Y0dYu2ֳ|4p90>C Y+dJ,tW( ]bBNf 1VXoN? < AҲ~\=_8UҜ:Tʹڈu}|v~{Cأi&@Ov# MNzK}t` 8I1!q3Rԣ+ S~V&]$@B`UN&BJ>Z$\`9s^dVCrrjkHH6&ؾ6g&קp[NuګlDKf*9/>j'fI,7Vm3E[ Wd!ؿZeYhā-:a"*FUFxۈLbzJ:|DjX*ioDN)9|$t 0=P'L{-֍ ;l&\/57}YۓlU$l]BB гY*a$1-PFdte+%ĉ]g6,f*K#=^oJ$IENDB`v_sim-3.8.0/pixmaps/axes-box.png000066400000000000000000000047071370110300500165520ustar00rootroot00000000000000PNG  IHDRKWLZ sBIT|d pHYs]ztEXtSoftwarewww.inkscape.org< DIDATx{U?_ ax)0SDEGAЄaP ƔSyXTNV:(!CcȀI Mo/ AQy(d~cs:s~y̝wkgZ'$|??pkh^P#ۀ ߯=hW >W ވ%I"Ir;3mo]qP ` pY%iQ5UTu͒x 8 V̀P\ <׭jJ UW5 *****m,#ѕmm,'Jh;d4J*hdmhczYU0K+ɒN :I'WJUC4Yl{W5 _2f%i˩qɒ:WX ̖tPٸdBm | *lLnHKZ ܘTm.Ӏ[t%p5 )jI/.՞~BD|+㽧D)''KjOVJEg8b :D*ICIڒ9 0|W(() d{[g%3pSkeRۙP˄4^ gw+L@߸Q1``g|X0=5U `K/%j "$jlWxx%z B t'S:_zŸ>Ka4<[ٕ7kmiۥ[{J"kVT74;RqN#K-G0J]_ V&b>hw IK 1f:Xe=*, lo} xMҲ%@`[5f6l84UR% '6BV@YQzl/t]⢶I5OpJǗp @!%v')y ?eȣ᥆]?}gOw&?v%x23+$^ ,'BA+p㗌I.I_ΘЅJ+ ً#@o}Jt`a@*%e^"lu.!a7㐚I^jLtaSydNMJ̹s .&R3b~(_'\x?fIf" 8$2X!\nY8PB29sҐ.)q[%彲!i+W$xHRyOi ɎƥT̬6N&n"kYyݢ\j<)Wev #!zuC^%zCrF= 5QhfLhNJcᨓh 5\K8P@]k -`iP2aY6izii$lU4iO碚d5n7,IV; IV7u "EIENDB`v_sim-3.8.0/pixmaps/axes-button.png000066400000000000000000000012101370110300500172570ustar00rootroot00000000000000PNG  IHDR sBIT|d pHYs<ԃtEXtSoftwarewww.inkscape.org<IDAT(}SAQ4hشk{EJ/fInIox",^IEKibfǿ.:=?{`^<WR $N$;8%b‚q5j^;+14+U?lYoos7g3gΙsfd<@M)׵K@y! @=?i@I%Ly V6\Lu׷?UPD1h"R` TWcUdslhY2Z߀τsI.ۿji2`h>% ~]X aE@Y7gJTBۦa)l?)i^au$ɽ '#3zI$(Y%1,鰶$!7ӰwWHb{oY~^7۹䞬X+ Qdپ<E흶BVJvǑU"c-ɲ X<ly5E2dS,i(0*PtȪS'$膻,ۿ.'}la9,iɷ\H/m+ɒX!~ݮ$X!/(*{F,no?K]IMb 1k]G#uYm^஬mwΒ4 jpMo%NFא%H~`pbeSbŪ KhK0 ^~Ǔ%i GL:,Ic@ U^ǮN(^`JV9$&D=9#5BnǍ,IDΒ*8 6:jdID^`?Wn0:,I 5 ꯭CG끑"۵F1rO#zfvdK NM{Zȉ_TPtt1(3A+wdI#K\;k#"Kt݄zAM[C?VIRz#$ l~4PK.?3Rr ȉOGW݃,b 7nҚB"pGV[$|F5iT "p{dIz? v^i׀gk|EF ^ Dq5;rvnE.qeV> lru, AYۏWY ^ZIݒ>S# HHZPNJ9By.j9F?t]zʒReߪA2 qqY:}D0" %`rzv{%&d۫e l&PyĪ]sVM|7[O* IyXf6I$]i{Oz+z$}D,?I ,#Q8.+Xl i2s~UgyxCǸ?}\\A:~ ,$ }qRۏ^9C|gp<w{Sc(2Jө.O@IJ\ዤM&Em/*j{S`Vҹ;ӎl01>IDAT8EKL\e޹wf@c4(MäiUCR5IbE]i@S]h*EѤ%JXԅ4a<{xp̽w!ēmNR`63񸿯epaƋGWl)W B+ Bn'x`ϭ[m|$Rp75 w$R*Em]ETu}>gYw*RJ>v%\rZYy A*axE|E^sc};:wٙolo)~N1ux<g`px,Lm{ҩCCBEu(P]HE!eQkj^_FֶQe "p>F˶70[׮ieȸkp0#%9ҲpIɐXYA\GO>kk9R6(E#@WUPrSS(;095UJ[;FzoU)L1?=͎i"4 w0H^YN!~$ڮlvszq00vX?х)<ҙ @f1Id"AYIɂz0n$ .ǙM1M(,Idpt%VnիWOW`3v KI&[XSU03WQi#˿hj~uVkvxŹy07@rw`HҍXȘIENDB`v_sim-3.8.0/pixmaps/icone-observe.png000066400000000000000000000011351370110300500175540ustar00rootroot00000000000000PNG  IHDRabKGD}D pHYs  tIME7p#IDAT8˥kQ?wӋI[MaC RZ7qPpRuRD*tP*jA ^H&rpIlK,Aӗ~Ia)k-q, r2tPT*e("!=+"U E$\H_MflD>R_ሿP$8 s/?EM:nѶ*<5IO$J4th}YpLD6&C&NyksFv3RPrKh(իyt{x3.àsoYÓŎ׶Mf@O5kNn}Wh$߼E2k c #D9B9D3", ", c #D9C5D5", "' c #D9D1D7", ") c #D9D5D8", "! c #DA7EC8", "~ c #DA97CC", "{ c #D9AFD1", "] c #D9ACD0", "^ c #D9CAD5", "/ c #D9CDD6", "( c #DA87C9", "_ c #B2B5B9", ": c #8BB2A0", "< c #A7C5B6", "[ c #DA91CB", "} c #47956B", "| c #2F9562", "1 c #46946A", "2 c #3E8B5F", "3 c #725C4D", "4 c #816E62", "5 c #96797C", "6 c #C6BBBD", "7 c #CED1CF", "8 c #9BB0A5", "9 c #83A091", "0 c #ADBCB4", "a c #DA8ECB", "b c #699779", "c c #748771", "d c #C6C2BF", "e c #9F938B", "f c #876B68", "g c #725B4D", "h c #665E4D", "i c #316347", "j c #235F40", "k c #628A76", "l c #7B6759", "m c #CFCCCB", "n c #A4A9A0", "o c #2B5B3E", "p c #215D3D", "q c #9B8A84", "r c #766759", "s c #515642", "t c #D9B2D1", "u c #BD9FAF", "v c #836762", "w c #816460", "x c #695142", "y c #837064", "z c #BDB7B3", "A c #95877D", "B c #654C3C", "C c #C3CBC7", "D c #486E55", "E c #265F40", "F c #43533B", "G c #B4C0BA", "H c #1F5E3E", "I c #3D6F54", "J c #5D8771", "K c #2D6749", "L c #819F90", ".+@#$$%&*=-;->,'", ".)!~-;{#]^'.....", "./(_:<..>'......", ".'[}|1..>'......", ".'[}|234567890..", "..a'nopk..", "..a..qq'{'rs90..", "tt(ttuv>~wx.....", "..a...yzAB>.....", "..a..CDEF.'t....", "..a..GHHI...t...", "..a..CJKL....t'.", "..a...........>'", "..a............>", "..a............."}; v_sim-3.8.0/pixmaps/illustration/000077500000000000000000000000001370110300500170375ustar00rootroot00000000000000v_sim-3.8.0/pixmaps/illustration/axesDefinition.svg000066400000000000000000000474261370110300500225460ustar00rootroot00000000000000 image/svg+xml φ θ x y z x y z x y z v_sim-3.8.0/pixmaps/illustration/axesTransform.png000066400000000000000000000057611370110300500224120ustar00rootroot00000000000000PNG  IHDRsBIT|dtEXtSoftwarewww.inkscape.org< IDATxy\E?B#B8*$@D(b<,JB,@r$Ja @ H *A`J?7Y̛jkwfoݯG6eGҷ'olYHh2pWE c*VrQz ipS`. @``ER&ZF Se(3VIH:hYJIӀǀi;v&+Q9)}}rZD6$hs9IڜmNR6')@I $hs9IڜmNR6')@I $hs9I2@xIoޖ&ty}5P'O'Ia2\ V^ۥ͠خ"I cFV'Ȇ2;EYS|=Gqn'p 06Z$鼑?N-m<)@H4XLAof[~H`۳l?_<ޗM!"BGlI#?kk,Q8 9o"dv0K {V'Iv:ۏ%7~Y)A^!d6m/h`W/rsyq1 K*mll |-7CCRjX i,0xUjK%E BREQWߐt8h* ~\7dg9m-L%ISd_ 0x`"Y:AحlWP} Y:8s%*J,@9m ')@ D9U_;@)Gbd9= >NvIU;I~v'U}$ P%6I>I#ߵKVl$ PI;'~50غqReG i[@J-"3u_{GؾZBi)`0x; I{Sm~'xm Q#W?[I ?AMO[U%*5GЌ]o ^u#Z].ި!`[2w5Vi8y`1ЙIӟ{҆M{ lk;cg%޲&5VXl ,u=P3U j# p5VV{Im(==]( C~5Gl?LH?$۬4YR)[Z"cF$iXS@ `T0 2?6f"i;J`AL^lw;,~ov+u9 >wW`Ϝb3_W]? 떵1a,`gSáE-@=%H@$l RL`HD.['O&‘MKXXLjo*X)94g$m\YGy&Ā">V{m %p !U*^ت1*nGz 48 X|y0X')ӺU2 "a+VdHjjbmW Bm@ߓ9ZI:_}2$,F|&7oB+ICm8, n^@Xos=_ )29.򽁧Kg$ f[o[1 yEfx"IO/.t0G,ƒE0 ت{$F+#/H:a&rn\I5TiֈՄ%Ӂl*]zp`tn$!+g0?% ? 6^W p`]ہ%¦K;yN2BPҼPj@҇mV@œnSb8`kDy6Da4D=ڍ>\sk; M'veN} EӔ?G i&񻁩 hD4Y]eф!gTBW;)Ҽ]>D_h* L鯊uB]?^w?}j4 :w.ŭ+ikn2a^ 4D΅eEǂPc_gͽqH ;_rr ¡R^# =na p!|^Q4u UIp%kmL+ZlX )@҉ۏ"@$~k;G_`U s,o=$./Mrh ^k5pscIXDQ=2AÎwbS&74Pgy7!|D&94) :^fؾ5&x㽴IS@'ѹ3=zIGl"Puu"iΝ3 MbOڞ[,0 ΢svJEL?Uҩ1h#E&(@tKpPB-DMQ@mz2Wt.2Tˮ; Li)@لLM'1)t&a!ɡ}%S d`a;>G S7)@6c)p8LLշ n P`}rREO;wS(8+r rjIL Fδ}uIL@BK#N"oVܙMUmDeRX~}\:wڑG8yw;wڍ,tE-Eg$Co 0PRxBKMK aΉGgPLq~ù(<= image/svg+xml φ θ x y z M(x,y,z) v_sim-3.8.0/pixmaps/illustration/icons.svg000066400000000000000000001537561370110300500207140ustar00rootroot00000000000000 image/svg+xml v_sim-3.8.0/pixmaps/liaison-bandeau.png000066400000000000000000000243251370110300500200550ustar00rootroot00000000000000PNG  IHDR@bKGD pHYs.#.#x?vtIME  1tEXtCommentCration Damien Caliste l'aide du Gimp.]I IDATx}yx\ŕ}{UZ-vK,Yn汄 Lx!|ffc&dI߹9ל8obѬJ@}}=.\ <0X6,;]j>)IY^p,~WEEYTHu@?c'tq @uufK]{ŊYb1UUiݺuP#͚VYY@.`ܚbZ!h*lZr%-53V\.{)o/;'?nZs3I@/83O])` j9 hjw^@`aV~: 0gP(Gv5ev{#ʘ(:5K^z)аyެ1`q|+&W袋02:ʢ. kW/|c9*PWWW 6 \s ) Z\Unr& ,E,n\q3UuuuT#@EArN`0h ]g(/9sδ9O7~O"۶mKUHTTTխo]X0SW. =A_th+vZ|߇iX~=mٲ6lPq,QY#H2邫l۹\=^/m۶`]㦋{p7| Bhgw6l@^x>9*`WB؊'^\s|',n6ٷvᢿ3qlxwŸ`IUx/ ߹6b OBӴE?aiQ9tMPQxc .Ŭ`w;h֭r1"!S:40;8~!o#~?۴itw3xY-ftXXyΥl\ڄr2204ЋCl.v!lذ_e j^}ǎ %?~xvI7_C73/K"74\/f:pB@$ DH@8 M0: 0P,kڲepp۶LJ`ɒ%I✃:~} `l6  oC=n6͊9W^w}qh}h6 `c%I2\&4M4} Moƞ{'"bk/b]_a4 YH 1ƀCsbcxST_@*/YJuxDD\ 6[/P`|\7֜|:=en]y!v˽zTi-.YtB!< "h~с8q[ow_No~g` Voܘj0`yk(B~ި]!hh͜:٬,tk ߅?SOmo u|ZwY`  nfa ۿm,0P#E`láJD b1 GBh$fk/Y qPpApoD,f !TTTpUUӁ" E5r!dp>66&dy"U^uu`q9CAD~?YjRE4PL6wbhpPLVtע oL81>>K;vc!$+p"`/B9lHPaASdJ_m߾8kc$% SFfF\΄~A(ڻHW_DDh^_,Ep1&82 <=۷?=/d2L@ooľ)ܱcnji=gqCBǐHwJIB6["n$]B ՕR"'+&]rΡ( %Cv/]~ҲJj1.W۬/[¹628{$ǽp)I׉\jȁ"s֣r+0ho_j 4AK\,t8je~E]1-s`:,?h޼oԯ[Km6#Q$ eEih8iׇ`.HD %)-fƔs;w3idu3&Qyy1) @0 84 ː$XqWyvPi('5uDsUnX(B|%)Yej~]W$Owy%j QoRNMM gvp饗amq!xȚ!f f% h UDf޾%wtbɲx!ɮJ =u@a7^~m>kkI9p!I ""5K s?]J$-5X $sN0) HzW "=ۘj>1?묛{w}4 K?"ïy} Q`|Νn)2櫄I;ccN2VӅ7Ͻ,-xL>$զlcA IRdO." bV*Nk7 SfǣthmG;r$h<јg3&aur &$ǁH,Wt0I1KAQ}9=3:4-6֦g9c|y<jool:wO,> Pww7"\8V@a&$Y QwA1HowQGlR)}{wf5$IxWiΝ}@sBvݸqӌD]<jNNKOhhk&Q txʝO oIʾ&y{80fO ^#(/8ʭyF(5Mb_&c z/=  ~Yݻa-QX* t띷̐m ^*;aώ<#{EUUٹ,;x< Cjp4h>2\7".x*h&@"tHI:J˖, $.EЭG|.r\M ?SӻDST~9Hz2uOIJjUE(}zg3m\mEce57t-[FlDg3|ag"hB`L44 !GtD4 Q1!Rj>M"C78t#!i_o;H"GL>jr_? OukQ;nHn hu<6&&e*SXNB̿9jFZuu֖.'}/Iz']{K%ь;PW_}u9$/A~QBD:8A !W$A!Ec,4* i"Cq:(&8vysTU}}HUTHV*)Pt4ԸH5p7g/Бp*X\2HDAg"A1͆]a4OMvCVkVG7E{zQu,7 xQNwKm6?Af|yxw6Q BHO&I1p" /A,%0.eu8p> T(Y.#mWU WVb)`^o}6ړ1,X_Q$?c `yί_K}0?wA{ު?<}[i?fׅX L؆Kn:G7^ b~/V]Ԟn Xs"ۿ Y6Z730> < MD`#C;. ! ϓ4S* IZQ5-? ,"0K `H<``||iرҴ2|9{b0}$I,|kֈ}G(fUjq䫝`W×/l'U R=mI|ns v)-[LJ;v k8mB9">߽_͞/͟{ė_NmMI@ψpյr p،rS"#S`'srFt'RXɄ`,6i2KJIdFFH8dćg/$QpZ PՄ$.?q88N:w:D FOD$'Ii 7:p9v&b'=̒MA cB9c,?YRL?7]'dYdәq^8?g>xVTdY,xT*7qBB3[@H4ą@ThB&4`H~ `I" xR,+.rD"$%A rG%J H ':)y|e59cB .bD Xr⌥/3h|x^5%̙Ϛ!al!KO63ڝo +G2 ̠$\,[|槁o\i%CӄPɑ ]W31HALbJOǵ4-6E4'q$I+Ţz%FIУε|KG")xwnY'^ŘljKcf= ҉@4"Ĉ%t e: ^1/ٜd H$z I`!cIH$wrg¾"bTѥq'aκQ瑃him$NSji8R 1Ρ_Jh@t*"beq@ε4RDV/`P}(1[HńShtXhYoB4eon7¡,¡qh ύ`=jF4q"B@<=3[j7Pd` 5~\Ki $C}_Xv 8+@B+iʜU?,fDcYe6[E @`f" P8eb6"S4fG-5WG R*H/c˖-8S*!Z-8U͚bUY#&UT$O d~q &IzgDy È$xfͧY$vR]vASiq-^R׀ a҆OCEd -^ٴ`*r%b-Zz2`񒓘Ya}#(r3><裏`00R7RL6%Zjqw5p8*p^sZh3 3,{B$ M ZVȌ!9oYohUH16{Hc[`>&ں&+ n%Wf% E ,ǶUߨl%V̤bfC-[~̪c}b=LE>ܵ,{Dڇ@DzIA ),\&q^"15`@T0DI2f*󲰦s舀 V"Ge f~=JǎjAnَ힙!$⪫JJeDձb055X  IJPШ("31%A!]OA~MW9 q QQDci UfhlE &2&K4- C!hzE%]hn`p$:,adD H$\EsY t?B:E2ˀ$c93gzGl5s=bc^La~) I1!/*:gi WHT㺞4iIXK|%9CUCppyLJ$9VWڵC EkǢʡf /_G!/;y|`FO=XV1F Xxz1ԮXˌG 5g_H}1 TQ=/:s."ٹy/D*F@HyZQYT}f~qoZtwJ#PVa3'DJCcRVIv |c~C(d`S":5-w</%j,SjtHh"˗VcGupWU-(a^Q-*6X pjD&AzDblt@7˄z*ЈFeN* # ;,"`;_g?&b_w,LQ`eX2cOft~Y 6Ob p& D6-_JZmw7fi/3 LEg> r/X&C20$<ۭ;{&%ԱiFIGӯ;m2<~V *3^5ǡ cR)ȩ(`̢+ʆD)O RAy8Gӥ~ѽ@ `+N93o|Zk b1Oi0mݵp)<_HUe(L?s1p4 #!+a^lȤ׃3;*0 BӴ¨6_(FKzѯH$$ωwvښ/F%ײ-B7;s6*4+[(+R̃DܹJF+\騞!i35@*̫x(|*AS_JG1Pߋ3설DznњT! *}܌̷oBL^ݓ"{-E$)_+rrHhS| Vn@4eojkk!%VL汩X7, ]6aP5gj8ZɷbHGkh EG?qqyF~\z1'3(y<!tR؜g(  FIDAT9y^Eu}3j*Y |!V0 0gUUWE02C}^4j= Ç|ڇkeff_|EڶmN=T+x{=,KW^y*Y82;_SWOy"e+a6"* o~t?ŋg ?ʷtWNY$9D\{{x3OChx퍷o>;HZ`<ۼ= 9_=><8gYttBLM?Cpkg߂4HUFHğLb$ `L$g ;_.͹пuͅxP۝?H䭷ނri|Y8'M7^!to0dqu[ yM@9k OwGK?C#wwb1%sw=~ O3qmk/uk?û3wavHqfAՉ٪UXSS86IIt s+>mp8L~"[JD֮Fn72TU߆K3o~AطJq/Ph5~ȯs鵍p,>7Mۋ!V@+QٚH4Uu$H*勡Op09УhIABXVZ|W_άfz4JxfF.o| Vۂh4h48'IL}7{8&13.đwcs} |J' g{p7}wZZiB3*H"džT$(9̡0$M9YC*;Q1$9H17m;OHj/b6X$rU8qŨ:͡P<Ic\s5Ws TBZŻ>Wo]f5uudu"8=<ؾ׋Kɫr le4q%2UU,ieF_ISҥj 1E/*J`Q4MvKS 'yWU>s# A^;U'^uuđ{a)QP"x KL˗ 8' JBnG"QbQ٣?ѡ ЉD@bBeE@1@RӴץ?3ITBs{1 _s=:> |֎}o&aIENDB`v_sim-3.8.0/pixmaps/logo/000077500000000000000000000000001370110300500152465ustar00rootroot00000000000000v_sim-3.8.0/pixmaps/logo/bandeau-liaison.xcf000066400000000000000000001225141370110300500210100ustar00rootroot00000000000000gimp xcf file@CCE gimp-comment,Création Damien Caliste à l'aide du Gimp.n gimp-comment,Création Damien Caliste à l'aide du Gimp.gimp-image-grid (style intersections) (fgcolor (color-rgba 0.000000 0.000000 0.000000 1.000000)) (bgcolor (color-rgba 1.000000 1.000000 1.000000 1.000000)) (xspacing 10.000000) (yspacing 10.000000) (spacing-unit points) (xoffset 0.000000) (yoffset 0.000000) (offset-unit millimeters) 2*g)@Arrière-plan     @@K@>=============================================================??>=============================================================@@ @masque Arrière-plan @&@:f>======} |vpje^YSMHB=71+%|vqkf_YTNHC=71+&  }wrkf`ZTNIC>72,&! ý}xrlf`[UOID=82,'! þ~xsmfa\VPJD>93-'" þ~ysmhb\VQJE?:4-(" ľztnhc\WQKE@:5.)# ſztoic]WQLF@;5/)# zuoid^XRMFA;6/*$ {uojd^XRMGA<60*% |vpke_YTMHB<61+% |vqke`YSNIB=72+&  }wqle`ZTOIC=81,&  ½}wrmf`[UPJD>82-&! ý~xrmga[UOJD?93.(" ľxsmgb\VPJE?94.(" Ŀytnhb\VQKF?:4/(# ſztoib]XRLF@;5/*# {unid]WRMGA;5/*$ {vojc^YSMGA<60*% {vpjd_YSNHB<60*% |wqke_ZTNHB<72+&  ¼}wqlf`ZUOIC=71-'  ý~wrlga[UPID=83-&! ý}xrmga[UPJD>83-'" þ~ysmgb\VQKE?94.(" Ŀysmhb]VQKE?:4.(# ſyunhc]WQLE@:5.)# ztojd]XRLGA;5/*$ {uojd^YSMGA<60+$|upje_YSMGB=71*&|vqke`ZTNHC=71+&  ¼}wqlf`[TOHC=82,'  ý}wrlf`ZUOID>83,'! þ~xrlga[UPJD>93-'" Ľyrmgb\VPKE?:3.(" ľytmhb\VQKE@:4/)# ſztnhc]WRLF@;5/)# ƿzuoic^XRLFA;5/)$ {upid^XSMGB<60+%{vpjd_YSNGB<61*%|vpke_ZTNHB=71+&  ¼|wqlf`ZTOHC=72,&! ý}wrlf`[UOJD>82,'! ý}xrmga[VPJD?93-'" þysmha[VPJE?:3.(" Ŀytnhb]VQKF?:4/)# Ŀytoic]WRKF@:5/)# zuoic]WRLGA;50*$ {upjd^XSMGA;60+$|vpke_YSMGB<61+% »|vpke_ZTNHB=72,%  ¼}vqle`ZTOIC>82,&! ¼}wrlfa[UPJD=82-'! ý~xrmga\VPJD?83-(" ľxsmgb[VPKE?93.(" ľytmhb\WQLE?94/(# ſztnic]WRLF@;5/*# ſztnic]XRLGA;6/)$  zuoid_YRMGB;60*% |upjd^YSMHB<71+%  |vpke_YTNHC<71+&   ¼}wqkf`ZTNHC>71,&   ü}wrlga[TOID>82,'!  @ D@Nouveau calque      lD@*D@* 53󣵪2򪽜1𞜈ð/~ǵ.{~ʺ-~z{̾,~zz|ð+}zz|Ǵ*|zz{~ʹ+z{}̾ z}° z|ƴ z{~ɹ򛝞z{~ 𛝟z} z|Ⱥ{zz{~ z{~ġzz} ݞ{  򤫻ĝ͢ɾϭöϦ˼ŷ󹲳 }|||}{z~Ͻ֣z z{κ丣z z{̹࿥z z{}ʺ玲֩zz󦬵*ئ*ݻ,Ͷó,.ֹ0ȴ0ུ0϶0´0񛤚0񟥐0򣟇0񜥖0񡤌0򤜄0񞥑0򢡈00񠤍0򤝅0񝥓000񟥏0򣟆0񚥕0򕚋"53󣵪2򪽜1𞜈ð/~ǵ.{~ʺ-~z{̾,~zz|ð+}zz|Ǵ*|zz{~ʹ+z{}̾ z}° z|ƴrU z{~ɹ^XV򛝞z{~̞\ZYW 𛝟z}{_ZYW z|t~dZYXUXYYZYYX񊜜{zz{~mJVuj[ZXWWXWV]z{~iBFJRkq\YTTUVUVWYz_9=AEINczXQQPQPQSUVXXWXYZ[zuO237<@DHL\OMMOQSUWXYYXZZr{51126;?CGKVUJJLNQSUWXYZZYZY[125:>BFHFFGIKNPT]a\YZZYYX^148=DDCCEHJMP`z}XUUW13>D??ADGILQkbSRR311;C<<=@CFHKPimllkkuDAA<989;?BDGIL\^[\]^_JD?:757:=@CEHJO@??@zHB=95358;>ADFIJ::oF@;731369=?BEGI866j }|E?:521258;=@BEG922Y||}{z~D>9411259<>ACE@11>z z{C>8311369<>ACE711^z z{=73112469<>@BC92112^z z{}<82112469;>?ACDEB@31Uzz93112469;=>?AA@?*OD21123579;<<;*SPF84211245677,PO>67;:6112-PJ:69=@DE@:6311.QPB86;>BEGJKKI0ON<68<@CFHJKJG0PG96:=ADGIKKI0ZP?77;?CEHJKJH0r<69=@DFIKKJ0񛤚uL;>BEGIKKI0񟥐{aJFHJKJG0򣟇~jZQO00񡤌0򤜄0񞥑0򢡈00񠤍0򤝅0񝥓000񟥏0򣟆0񚥕0򕚋"64320/.-,+,  U dXV \ZYW {_ZYW ~dZYXUXYYZYYXJVuj[ZXWWXWVhٟCFJRkq\YTTUVUVWY9=AEINczXQQPQPQSUVXXWXYZ]r237<@DHL\OMMOQSUWXYYXZZ91126;?CGKVUJJLNQSUWXYZZYZYb125:>BFHFFGIKNPT]a\YZZYYXi 148=DDCCEHJMP`z}XUUZ13>D??ADGILQkbSRR 311;C<<=@CFHKPimllkk DAA<989;?BDGIL\^[\]^_ JD?:757:=@CEHJO@??@HB=95358;>ADFIJ::F@;731369=?BEGI866E?:521258;=@BEG922D>9411259<>ACE@11M C>8311369<>ACE711 =73112469<>@BC92114 <82112469;>?ACDEB@31~93112469;=>?AA@?*OD21123579;<<;*SPF84211245677,PO>67;:6112-PJ:69=@DE@:6311.QPB86;>BEGJKKI0ON<68<@CFHJKJG0PG96:=ADGIKKI0fP?77;?CEHJKJH0=69=@DFIKKJ0f<>BEGIKKI0NjTFHJKJG0ǗoYV000000000000000" uQ5" 3 (2rK1 x/ . $- E,=r+ *~+I@Wӻ~ $l"N  E1 ~I<  %f 3 5 "]_b &} J&m%$ |TKX++&%' ({&&&&&&n&%AEE`hhqu[9*eZ* ;++ , _ - K0V 0 0!&0 0 [0G 0 0 .0r 0 e08 0 0 @0` 0 y0*0 0 P0Q 0 0&0S "_֝Ĵҿzq_֝Ĵҿzq_q_&Rq" o>Calque Copié#1     +Ko>+Ko>+>P31330433043 3-433?? sRuTC]`|₵ dK$z^쒴^Ș݂ Ó^q|^ 겪^(^j uY Y31330433043 3-433=@33,5334I43 3,53 3-433^3N_33,533e53y33,53 3-4339{|[b3;Z3 3,533i~}s333k33,533wzsQ33-433DggPb3Gh@336A33@733,533gga33:dP33,533go33-433D33bJD33?:˓33,533338\33,53333C33-433Dٯxbt_33JQ33,5333Bw33,53333433-433D33bpvD3?33QS33,53333Bsr\3?33,53335S33-433DΗkbIJ333PU33,533轗37l333,533ї33-4335KK@9<3>JC53B3 3,533EKKH3B39HH83B33,533JKH=22-322+522,42 2-322+422,422101102110211?0}xvvy}} pZIEp}’₸ }fP)vcWු 絠uuyq 窸pjgdi uOħ ճ??u8r֮ƔD̰ƒ͞ђђ&xѣחգӏӏǿӎҎӍȋ˥ͱϺƝ˸ًʲۑs >?? sPzIC]`₵ wfL$z^ą^ 곤^u^ ꪸ^.^g sL ۽Y31330433043 3-433@>33,5338F3 3,53 3-433R3N_33,533vp43y33,53 3-4339{{[b3>K3 3,533i|s333xu33,533wzpM33-433DggPb3Lf=336A33@733,533gga33x?u?s sPNC\`₵ qgS$z^|ԅ^Ⴔ ꬪr^~^‚ ꩻ^>^o wB վY373~33_3$3~3D3?MF?O37IM<3FFM;39KG36FL93=MG43 3ݮ3:\Փ33՚53_383 3ݮ3;a333Hkv3>6@<73w3d53 3ݫ34Qm353u333@=83pj3Oj;3 3h3:3333353]3:3 343B3>IA3;J38IFE3B33B38GD35CJ>3=IB43 3]2.1.0.}],  }u|or{ufŘyyڃĜšlfo⨻yrǛ͗{e⽠xvՈɚ}~xuywvs}vvjuܵ߳۳..., 򝩧ß УѯЩУʛͥ͜Ȗկĥѣ⸰̔ϫ˓ř⭻˖̣ő͑˵˷˞ΐƮǸɦ˷̞з̏뚭....],  {trsytzf}›xw؅Ǜkck⨻yrǛּ͗zm⾟xvևɚzuvxum~ywulu߽343~33_3$3m3D4BMC?O39KL93HIL83;LD37IK73AMD43 3ݬ3<\Փ33Ә83sy383 3ݭ3=|[333Mmw387C793|y3^53 3ݧ35Uq343~v333B8:3xql3Sn;3 3X3:3333383o393 343B4AI>3?K3;JED3B33B3:HA36EI<3@I@3 3]2.1.0.}], ڥ sy~e|pr{wf⭰v܁˓igo⤿ysŞ˘߻p⩷x{ɘÞpwu͂vvsuvvvwcuԴس׳г..., 򛧢 ̚ԠН̚Ö⵳̔ȨԣОⷫʐͩǏÕⳮʏȦˍŲʴɔ̎ù˝ɴʙʴɔҳʋ뚪....], ڠ rwgzoqxre⫴w~ʕick⤿ysŞ˘ֵy⪶x|ɗžnu~tvmowsswd~uٽݼּܼ343~33_3$3a3D4EM??O3;LK83IJK63=L@38KI63DMA3 3ݜ3=\Փ3o3іk;3c383 3ݫ3=yS333So|36JBC3B33B3;I>37FH:3BI=3 3]2.1.0.}], ʴ s~gvwssf⨸wȘhgpzxşǜ߭r⦼yĚƜfqv{|stltu|}buuͳҴܳѴȴ..., 򍚒 Ǿÿ͊ǽƈǾͲ⭤ă͋Ȏ⮟€Ýú}}⫟}}}~}}}}˻}}|||ŁîȅĪÂ||ͩ||z{yyzyyzyzyzyy{yy.x.u.s.], ʯ t{gtutoe⧻xǛgblzxşǜ֩z⦼yœƜfzvx~mvjsuxaquԽؽֽϽ b7o>masque Calque Copié#1 LUo>Lmgo>L\|{xutromkigeb~|{xvtqpmkifeb}{xvtqpmkifdb~}{xvsromkifdb|{xvtromkigdb|zxvsrpmjhfdb|{xvtromkigdb}zxvtromkhfdb|zxvtqomkigdb~|{xvsqomkifeb|{xvsqomkigeb~|zxutqomkhfda|zxvtqpmkhfdb~|zxvtqomkifdb|zxvtromkifeb~}zxvsromkigda~|zxvsqomkifdb~}zxutqomjifdb|zxutqpmkifdb|zxvsqomkifdb~|zxusqomkhfdb~}zwvsqomjhgda|zxvsqolkhfdb~|zxutroljhfda|zxusqpmkhfdb|zxvsromkhgdb~}zxvtqomkhfda~|zxvtqomkhgdb|zxutromjhfda|zxvtqomkhfdb~|zxvsqomkigca|zxvtromjhfdb~}zxutqoljhgdb~|zxusqomjhfda~|yxvsqomkhfcb|zxvtqnmkhfca|yxusqnmkhfda|zxvsqoljifdb~|ywutqomjhfdb~|zxusqolkhfdb~|zxusqomjhfdb~|zwusqolkifcb~|zwusqomjhfdb~|zwvsqomjhfdb~|zxusqomjhfca~|zxusqoljhfda|zxvsqnljifdb~{zxusqomkhfca~|zwvsqoljhfca~|zwuspomjhfcb~{zxusqoljhfda~|zwusqomjhfdb~{zwusqnlkhfdb~|zwvsqoljhfda~|zwusqnmjhecb~|zxuspoljhfda~|ywusqnmjhfdb~|zwuspnljheca~{yxuspolkhedb~{zwusqoljhfda~|zwusqnmjheca~{zxusqoljhfca`][YWTSPOLJHFCA>=;8642/-+)'$"  `^[YWUSPNLJGEDA?<:8531/.+)&$"  `][YWURPNLJHECA><:8642/-+(&%"  `^[YWUSPNLIHFCA?=;8642/-+('$"  `^[YWUSPNLJHFCA><:8632/-+)&%"  `^\YWURPNLIGFCA><:8632/-+)'$"  `^[YWUSQNLJHECA><:8531/-+)'$" `^\YWUSPOLJGECA?=;8641/-+)'$"  `][YWURPOLJGFCA>=:8541/-*)'%" `][ZWURQNLJGECA?=:8541/-*(&$"  `][ZWUSPNLJGECA?<:8641/-+(&$"  _^[ZWUSPNLJGFCA?=:8631/-*)&$"  _^[YWTRPNLJGEC@?<:86410-*)&%" `^[YVTRPNLIGECA><:8631/-*)&$"  `^[YWUSQNLIHFC@?=;7632/-+)'$"  _^[YWTSPNLIGECA><:8631/-+)&$" `^[YWTSPNLIGECA?<:8532/-+)'%"  `^[YWURPNLJHECA?<:86310-*('$"  `^\ZWTRPNLIGECA?=:7641/,*(&$" `^[YVTRPNKJGECA?=:8541/-+(&$"  _^\YVURPNLJHECA?<:8642/-*)'$" `][YVTRQNLIHECA?<:8541/-+)&$"  `][YWURPNKIHEC@><:7641/-+(&$"  _][YWTRPNLJGEB@?<:8631/,*)'#" _][YVURPNLJGFC@?<:8631/-+(&$" _][YWTRPNKIGFCA?<:8631/,*(&$! `][YWTRPNKIGECA?<:7531/-+(&$" _][YWTSPNLIGEBA?<:8641/-*(&#" `]\YVUSQNLJHEC@?=:8631/-*)&$"  `][YWTRPNKJHECA><:8541/-+(&$!  `][YWTRPNKJHECA?<:8631/,*)&$! _][YVURPNKJHECA><98531/-*(&$! _][YVURPNLJHEC@?<:8531/-*(&$"  `][XWTRPNKIHDBA?<:7531/-*(&#! `^[YVURPNKIGEC@><:8531/-*(&#" _][YVURPNKJHEC@><:7641/,+)&$! `][YVTRPNLIGECA><:7631/,+)&$! `][YWUSPNKIHEC@?<:8631/,*(&#"  _][YWURPNLIGEC@><97631/,*(&#" _][YVURPMKIGEB@><:8531/-*(&$! _][YVTRPNLIGECA><:7531/-+(&#" `]ZYVURONLIGEB@><:7541/-+(&#!  _^[YWTRPNKIGEBA><:8531/-*(&$" `][XVTRPMKIGEB@><:7531/-+(&#" _][XWTROMKIGEC@?;97531/-*(&#! _^ZXVURPMLIGECA><:8631/-*(&#"  _][YVTRPMKJGEC@><:7531.-+(&$! _][YVTRPNKIGDBA><:8631/,*(%#! _][YVTRPMKIGEB@><:7631/,+(&#"  _][YVURPNLIGDB@>;:7531/,*(&$" _][YWTROMKIGDC@><:7531/,+(&$" _][XVTRPNKIFDC@><:7531/,*(&$! _][YVTRPNLIGDB@><:8631/,*(&$! _][XVURPNKIGEBA><:7531/,*'&#! _]ZYWTRPMLIGDCA><97531.-*(&$! _]ZXVTRPNLIGEC@><97531.,*(%$! _][XVTRPMKIFDB@><98531/-*(&#! `][XWTRPMKIFEB@=<:7531.,*(&#! _][YVTRPNKIGEB@=<98530.,*(&#! _\[XWTRPMKIGDB@><:8631.-*(%#! _][XVTRPMKIGDB@>;:7521.,*(&#! _][XVTRONKIGEC@><97531/,*(&$" 7@Calque Copié      hB+@hZ@hnx??F?4D32%323.043#3/433.04334sb433/4334lh63 3.0433OV33Y33/433J]43d33.0433[\\U3b33;33/433X\\X3p33:33.04333b33J{633/4333p33Gx33.043333b3D;33uS33;33/43333p3A33.043333b9c33k=333/43333p6{d33.04333bNq\w33>33/4333pCt\33.043333bQ۵33T33/43333pE޷33.043333bBx:H\3333Y33/43333p<;33.04333b4Zr33339N33/4333p4T33.043#3/433.03$3/4332.032#2./322.032#2./3221?(???|;|:x΅ȭ²F Ę~ֶлҦѮըʵٮЬڲɳЫ ȲϪ򸬖ȱҭگΨ۴ǰmm9????%%%%q%ՄgD6WK:ZTpŊp֐]gqfdfgskmƶZgĐX2g4|yqgpr㰕 %%%%%???4D32%323.043#3/433.04336xS33/4335q[43 3.0433bH33Y33/433YM33d33.0433[\\U3b33@x33/433X\\X3p33?33.04333b33Zo533/4333p33Up33.043333b3Kz533uS33;33/43333p3G33.043333bAcx33k=333/43333p;c33.04333bSa\y33>33/4333pFa\33.043333bT߯33T33/43333pF䯭33.043333bJd8Qf3333Y33/43333pAi933.04333b6hҹh33339N33/4333p5b33.043#3/433.03$3/4332.032#2./322.032#2./3221?(???v;v:xƩFϽ ~ખٰßЫǠȲӢϩԦǰߎΨ ưͧ򱤐ƮΡՠ֥ͥŭff9????%%%%j%~gx>8bD;eTSzg~DgXibigtjoıpngӿ}k6g8ogzk۩%%%%%??F?4D32%323.043#3/433.0433>{M33/43333/4333pF^\33.043333bT஭33T33/43333pG宭33.043333bPV8Zr3333Y33/43333pDZ833.04333b9tҮ]33339N33/4333p6n33.043#3/433.03$3/4332.032#2./322.032#2./3221?(?x??k;o:xy툕FyƱ ǵ~y؟yݯɞնyȍȝʑy}~~~ǜ~ ~~~y|||Ǜ||򡒀|y{{ˋ{ƚ{{͐{]];y?x?v?t?s%%%%c%xgyj;33ȭL5W33Da3333*533A34DX?3rV?????YV=A]\D ϥv t2}rMOhi _hOvhhb 7mt9 rv: wu=5 vv3(32 ulD6 rvs lc@t tUvb aEEUt|s 箠ϣ ˟筡@ą,???4G313=3*53<3*53<3*534333*5336\\ZUD53<335R3 3933*533A魫d533<3 3533*533A35BxT:3KE_4R83td63P`33hV4:q\3333*533A33:r?3`[]\B8l`3exNGe3fgITlf33n33*533A334w?3fM8<33AV[c3[34X]833\^[Sz[>3333*533A33?p?3C]<3373W33X^633L8d33Kl3333*533A35JK?3fM@x<:3:V={3W33XR`;g3@?????ߑ{o}fe _iNvcg_ <sB> l~v]K f56 wv*032 W77 qvM y~X^Q ~|Hvm p(a7WVe{y ৣà ݦ@[,[-??F?4G313=3*53<3*53<3*5343i33*5336\\ZSA43<335R3 3633*533A魫[433<3 3t433*533A36FC:3Wx>_4^53Y44XN35tN3>L33W33*533A33Ef?3bb]\B8gcb3cEP~i3d=Vfm33|33*533A336u?3bH5<334GW[j3Y37W^533\fWUtX83333*533A33K`?3NQ<3383W33X^433L;qy33Tx3333*533A37P>?3\EJp<63:JA3W33XYQ?x3;AyG?]9w33b3333*533AѽI3?3uϚF:n7ɐ3W33Xy?x?v?t?s?EZ Աv hcfph߻e akWveg] S:c iWvEp ya4; xv)23. V5A pnv? h]Gt qAvz| Z;a/fjbt} أ բ@@ @masque Calque Copié  @@~{zwusqoljhfda_][YWURPNK~|zwusqnljhfda_]ZYWTRPNL~|zwusqnljgfda_][YVTRPNK¿~{zwvsqnljhedb_][YVTRPMK~|zwusqomjhfca`][YVURPMK~{ywusqnmkhfca_]ZYVTROMK}{zwusqnljhfdb_][XWTRPML}|ywuspnmjhfca_][YVTROMK~|zwusqnljhfda`\[XVTRPNK~|zxusqomjhfda_\ZXVTRPMK}|yxuspnmjhfca_]ZYVTQONL~|ywusqnljgfda_\ZYVTRPNK~|ywusqnljgfda_]ZXVTROMK}|yxusqoljhfca_]ZYVTRPML~{yxuspnljhfda_\[XWTRPNK}|yxurpnljgfca_]ZXVTRPNK¿~{ywusqoljgfca_][XVTROMK¿~{ywusqnljgfca_][YVTRONK}|ywusqnljheda_]ZXVTRPMK¿~{ywusqoljhecb_][YWTRPMK~{zwtspnljhecb_][XVTQPMK~{zwurpolihfca_\[XVTRONL}{ywtrqnljhfca_][XVTROMK~{zwuspnljhfca_\ZXVTQOMK~|zwtrpnliheca_]ZXVSQOMK}{zwusqnliheda_\ZXVTQOMK~{ywusqnljgfca_\[XVTQPMK¿~{ywuspnljheca_\ZYVTRONJ~{yvuspoljgfda_][XVSQOMK¿}{ywuspnljhfca_]ZXUTQPNK¿}|yvuspoligfca_]ZXVTQOMK}|zwusqnljgeca_\ZXUSROMK~{zwtsqnljgfca^]ZXUTQOMK}|ywurqnkjhfca^]ZXUTQOMJ}{ywtspnljheca_\ZXVTQOMK}{ywurpnligeca^]ZXVSQONK}{ywurpnljgec`^\[XVTROMK~{ywurpnligec`_\ZXVTQOMJ¿~{ywtrpnkigeca_\ZXVSQOMJ}{yvtrpnkjgec`^]ZXVTROMK¿~{ywtrpmkjgec`_\ZXUSQPMK}|yvurpnkigeca^\ZXVSRPLK}{ywtrpnljgeca_\ZXVSQOLK¿}{ywtrpnkiheb`_]ZXVSQOMJ}|ywurpnljheca_\ZXUSQOMK}{ywurpnkigec`^\ZXUTROMK}{ywurpmkigeb`_\ZXUSQOLK¿}{ywuspmljheba_\ZXUSQOMJ~{xwtrpnligeca^\ZXUSQOMJ¿}{yvurpnkigeb`_\YXVSQOMJ}{xwurpmljgeb`_\ZXVTQOMJ~{xwurpmligeba_\ZXUTQOMK}zywurpnkigec`^\ZXVSQOLJ}{yvtrpmligdca_\ZXVSQOMK}{xvtrpnkigeca_\ZXUSQNMJ}{yvtrpnligec`^\YWVTQOLJ¿}{ywtrpnljgec`_\ZWUSQNLJ}{ywtromligeb`^\ZWUTQOMK}{yvtrpmkigec`^\ZXUSQOMK}{yvtrpnligeca^\ZXUSQNMK}{ywtrpmkjgdb`^\YXUSQOMJ}{yvtrpmkigeca_\YWVSQOMK}{xvtronligec`_\YXVTQNLK}{yvtrpnkigec`^\YWVSQOLJIGECA><:8541/-*(&$" IGDB@><98541.,+(&#"  IGDC@><:8631/,+(&$"  IGDCA?<97531/,*(&$! IGEB@><:7531/-*)&$! IGEBA?<98641/-+(&$"  IFECA><:8531/,+(&$" IGEB@><:8531/,*(&$"  IGEB@><:7531/,*(&$"  IGEBA><:8530.,*(%#" IGDB@><:7631/-*(&$"  IGEB@><:7541/-*(&$! IGEC@>;:8631/,*(&#" IGEC@><:8531.,+(&#!  IGEB@><98531/-*(&#"  IGEC@><:7530/,*(&#" HFDB@><:8531/,*(&$! IFEC@=<:7531.,*(%$!  IFDB@=;97531/-+(&$!  IFDB@><:7631/,*(&#! IFDB@>;97521.,*(%$" HGEB@><:8531/-*(%$! IGDC@><:7530/-*(%#! HGEB@>;97530.,*(&#! IFEB@><:7530/,+(&$! IFDC@><97631.,*(&$" HFEB@><:7531.,*(%$! HFDB@=;:7521/,*'%#! IFEB@>;97531.,*(%#! IGEB@>;97530/,*(%#! HFEB@><97531/,*(%#! IGEB@=;:8420.,*'%#! IGDB@=<97531.,*(&#! IFDB@>;:8420/,*(&#" IGEB@=<97420.,*(&#! HFDB@=;97530.,*(%#! IFDB?><:7521/,*'%#! IGDB@>;97520/-)'%$! IFDB@><97420.,*'%#! IGDB?><97531.,)'%#! HFDA@>;97521.,*'%$! HFDB?=;97531.,*(%#! HFDB@=;97531.,*(%#! HFDB@=;97430.,*'%#! HFDB@=<97530.,*(&#! IFDB@><97530/+)(%#! HFDB?=<97531.,*(&#! IGDA@><97530.,)'%#! HFDB@>;97530.,)'%#! HGDB?>;97420.,)'&#! HGDB@=<97431.,)'&#  HFDB?>;96420.,*(%#  HFDB?=;97520-,)'%#! IFDA@=;97420.+*'%#  HFDA?=;96430.+*'%#! HFDB?=;97530.+)'%#  HFDB@=;97430.,*(%#! IFDA?=;96420-,*'%#  HFDA?>;97420.+*'%"! HFCA@=;97520.+)'%#! HFDB?=;97430.+)'&#! HFDB?=;86530.,)'%#! HFDA?=;96420.,)(%#  HFCA?=;96530-+*'%#! @ @Copie de Masque de sélection @@@ @>=============================================================??>=============================================================@@ v_sim-3.8.0/pixmaps/logo/icone-rotate.svg000066400000000000000000000372131370110300500203660ustar00rootroot00000000000000 image/svg+xml v_sim-3.8.0/pixmaps/logo/logo-1.0.svg000066400000000000000000001035111370110300500172240ustar00rootroot00000000000000 image/svg+xml v_sim-3.8.0/pixmaps/logo/logo-2.0.svg000066400000000000000000000713121370110300500172300ustar00rootroot00000000000000 image/svg+xml v_sim-3.8.0/pixmaps/logo/logo-2.1.svg000066400000000000000000000726551370110300500172440ustar00rootroot00000000000000 image/svg+xml v_sim-3.8.0/pixmaps/logo/logo-2.2.svg000066400000000000000000000726511370110300500172410ustar00rootroot00000000000000 image/svg+xml v_sim-3.8.0/pixmaps/logo/logo-2.3.svg000066400000000000000000000732111370110300500172330ustar00rootroot00000000000000 image/svg+xml v_sim-3.8.0/pixmaps/logo/logo-small-2.3.svg000066400000000000000000000617361370110300500203520ustar00rootroot00000000000000 image/svg+xml v_sim-3.8.0/pixmaps/logo_grey.png000066400000000000000000000225701370110300500170100ustar00rootroot00000000000000PNG  IHDR݆bKGD̿ pHYs  tIME U IDATxi\u-==+f4$B$EY,ےEʲ䲒HJJGT>rRqRr"EbWIr-l q H 0{o{w{{{N͠s9\A1=ba{bD,2 OiKA>\=}g/Od.)SQK@'#nIӐ<ο:od:s,z*|ْ'N2=س=3[6f ǖ=ᴣް='[<=j˚.u&[6zfRk<Z2Li{{:,jqmmcxws7}mp\70?eJ;.M0۸~CW*p9/ |jñySؖ_9o(nj.{yѶqpc-ެB OiUSr@9=!?ozFmOvuU*[zG3Gyq״fame%Y`YT|[" e65Hu ]:˓c[ws<DH?u !Y`vQ`bgxj/ml_2fq'*8x 9g8~0KN ~ݢ~G-3n=#y8OYճNbG ."88#}~;dn2 s'PfCH"B<MJ}"u% `$,"g[]}M$ .E2~"WeG q g凜< k- øp@@n42\e_*"HXdX6yӯ@$8EP+Yh0\<\FaC\ϣk]YkDH6c0iٵ,Zw@ka">. iG( D+[rY2W_9pQ q.GI@@^2[-bVuG %EjPXbu7,}uIUL"ZO ;SbȰ~K ,ڿzY=́(}uv2) Q|NMNjKÆ8r:G5hiPĤ2cI .?}9<@'O7Ue2 .d!H"/q:4$X!q8vG1K*ك+QÔ3rތG7[| Cj_M( Js{;kg7,wn C+ q XVi⥃Ϙ\:\#(sBUOʪjJL#tbM޷)qEF%@0 (@;v @$SPĕYV-j?X) e$8Zg%$K|mSHmY!E;+K3E"Y"B_~˜К0Lhnms-by钞s2NY9.  %H Yiq!=ayc=Ji i43z&a8<EeBDT[G,\yRɘDXk=apTVQ2CV6bdX`n}o(} "P7<w s59)+7VnLd % ASlN}Sšϓ:E~jWf6{s!/2B49"Ym #:*'ylᰕg~$G`5ӛ`bBق*urvQUִ JRֶcW7Oq1g%\ @cqRxjmDAJ]G&pikoG[9']ewƤv{KRCLs!\ @bbu>&9 vk!EÝ˒I$@%)D|U943[6X5 BCe*L=][S -EeV)*B\`Z¥ȷ*aT90 ܖn 8jEJߔTE+:̕xGJ2}9Y&y p81E~nȇV@r⨹eИT ֗DHT)@x,rHvQGC¯zD*hT""Bj**Nyv%RЫX봾9i8A:4+1y (* ޴Q]YvxRe=Y" Q'deVQFCC6RO2Vuk7QVx铹t}Fy\--JB0eAo-KL1=e{T4W[>XC7oYOqȒЖQfQ@*R^nb_rH`0R[mBءH%\M cg/8(_R^L}hTsyI}k7D2 N#]Jj0u ͉WP!dǭZ-R*Yŗ   !F)-:db1aB1Oa.Wmi.b&k$7b[#!iժSW.V@US C,]D-`&?҇~CyxRiwic"zK[Bw)a:+1{1РRzj] }R^ȅDR0\ \nIt;!U_e-|4c [f 3&1H[ݶC&%V S5ΦmI-PLl$ü]EJvrH}3򐆥Uy%+z۬p[}V?e#'[읕5'F&aYf{ RV9[Y$U9CQͅtx |#Y K (S 9=RZdr9H0ӛl}idteS9UoYt$ySnj2+-619C8m*EJ1恨Uf}>R14TTR@FdIWBNӰ钛!c/AD$w7)$'dٶ)XwTȰVTdE6rN0nglt٧?Ƈ:1:e;2%;Js,XDwi:F>v$SEl;UF Fʢ~&[ x+z%!"saUx* Il [[7E@R0]S-Fnc6q5)IpX[/ enֵY; l`5XQ^lZ !X34n[P~u+Ȗ(@`<.8b JY9+RK ȔiqIj|KPӗOG !*G3,X mVk )m]:!Lnx9&zCk\P VUQKުG""7p=O ]hzHnʘJv*7lcވ S/SDi ݕLF t\oقZV]|~/r,_j@wP/^RbEM@b>wq( cnh.T @2U)Rϒq嚛LQ(S`#-:]+C}|]|0OpoX\i7D4-A44jl҉ D^"eRՈ]p 37yJdH8RX+:9h?gwu_y! "um$hdѰ!L:s3 F-b=~nTs[ Iz Rw};>+_q!$WW)s:9HD#X7 ׭Haؾܗ1SEԻ-\kEE'u#XBB/㕿ټYX,2߻9 v87[ljv_vx{= @v#Bh ih/!*m[dnj͕?ƭƮ,AYG,/3kx*xuuwT;@E5шd4Tפu7\n"y)(+?$,R|ج{ P]:+"sQ%[ Kn ɒROg$UPGr ɾIZe eNl0J/52#ۏ( W.5hmRRёN+<H N)C[>˽ƩXH5.#Ba@\&ubeDL@`}޲BVYmIzwe‚N-mw-iH.c§I[{LlX>f5%ݜ'VEi^e jul\KR|ພb*K*igNirq %3{xXe8juUm%o"/uI\4@vRѤR7QgˌLG`dnNJv)i yF:Dz4sQ>FWyJs@C'Z=q.E<<$uV|fAR) E3xv`h7d,yw֝ ?d"=< ,!PI~|4EbM6]J _~$ dw(tj?ٗ@Vwe>5m :A% JV[6ٷS-jY=Gbe&ux.rC~&m}mYT69*8J5 qq!'+F:ԙl{ѠE.m*s_fҬwCfqjNAQdƈ{VuJQ7n<AWXb%* SR-}qVWfn:Iv;*8ov#;eILph`"X1s@ '@WXVԩ#UQoVlf)l)_q{ExWY mHPTlkdy\@*8?Jl %T(@_l#(3C:'&0I[}o*qlE,vc\|VW ` d@uZbdj1ޗB|z z84$++qHbt,}Z3THâ:hBnRIH_(S\A]f$T[7%+p,j]frW>cc~cvrJ p;:3y(r-j`G4{C#"Ԩ+6-T,z] LGG9CD uQ'*V X-O)ƆUsxOpVIh:u@PM;cf#(ef8@@zrLVA.6z%⻬RFJꖮrQHrYRݤY\!wE*R0Ϫ.s`<|-YS{7`;܅ ɷhPԹ~]BQu}+d2W 2êeW_[^GvLC9/3G:>ڍ.A6eE]j*'51L`*;,X;㮲ռ@{Y`Ej{lKIR7>Ew b&f0C*,Ll73ړ$!V~³ RqthkIsfکNIλJ X"T>|!uNqyXp0@A@ SM:s@" RaigXc/W2>^7N뱄,3:j tR=;{÷!5Xd S)sYhƞi^H5% WNnA`bXfe깪""{}?f{珙eqFx*R% A8{!4(p#ܳN~7\+dd%7KαUUdD*ȧkŢ@Yittn͟;^q7sۚ׿q\9:$o2j1bF,r1<[(͛$Pz!Pѩ.M%&i+|fH\k~ fRӵXla.7 %^c6>DOYpIORS]GH i89 o=* /L0~mY I޾ZȆyE3HA\C[ 窏Gqdcŵgܨq9^ y/whq g8aye3AefҁRRdF1hr}B*rl(~n6 P#\$PYJ4 dG UTWg_9NG6r%U)x*@SɾP)勬Q~D ~ew8c:!;)tW&16M[V քoPdy|ɯ@Y5wc?Dj v{**ok` J:UPPfKROϞ 0FuF{믨<יeQ8 QE]mEq:3m1@r?k-s3 %$SW[ȥDĵRVY]=ɦ̣rD o3VN~weAPM/W;ƬP<c wDkLqDb.z湱6Kl8xE P*i#<&b!5uo6Ml#>Ǎ0Uzg[ m{>ĊxZ;a92ӡ|+XwzGAEfY6*8D"bc#gXQ{Ϸ-nn0ї. [7>Xf?&?6c&Ϻ-]R=^ϧu,[ƌÉ }ɤ:[*O,^|G6՞v9ͫvGIu[jxy[J_1/O6H^d>yUXhZ|}d!o࿿ͩ+ԪSӟ߷~]=3>;d#́MOKWYcNŮ1Ss|lMK|jj.*ԘzO#ȶf|r* Mk)>cHnh>MG?>WREczswZ;os~<}7=bٲؿo#bYfxMM_q `IENDB`v_sim-3.8.0/pixmaps/logo_petit.png000066400000000000000000000043021370110300500171600ustar00rootroot00000000000000PNG  IHDR ˞nsBIT|dtEXtSoftwarewww.inkscape.org<TIDATHk3^u ]`Y]/A()bZ!V1UZkkM*T Ik[k,JS4Z[mmK1qFˢa ̗yO73Bk牴ߨuR2lvKvB}}ȡSq-[~ZB|BB3Ke$22,0⿼/sM rByʕ+I6G=iiݻskۉ|p rwO<-ci]9A\̕r_ 3f,ɩZB!E |5W^x9MzA@yxyu[lyL`NͰm}2b# 0yt>aJ(1a}=" O=E{.>ߺm6&ѕi!.4oXҢΥ.$kdm~!XJE, gy,?7~w\ mO׭3°}LszZkڥ||~SR֚(`3uR"bTk Ǐ"J OtsO>I2N%n!f۪Q7[փ!͆P(lٹ9&ѦmN6=JԄd C^ܱoWbZ^@EAO4񡢈i 2MF|8f (.a`[VnScJ2--~0cTGtكN RJٳQR77#ز};aQ[Sn\OIENDB`v_sim-3.8.0/pixmaps/logo_rectangle.png000066400000000000000000000207641370110300500200110ustar00rootroot00000000000000PNG  IHDRdO`sBIT|dtEXtSoftwarewww.inkscape.org< IDATxytŵ?UݳI]dyd}?!`C$cIHBx$ Y$ǖlf1fKpl0`x! oڥiٺ~tX#Ȗ_G^u{ou c ׭[wb 0?#zƘ-Z4 nݺIR{1}e-ڑݗ!dˀ@TV.\P?!=9R )g`Yg^5\"JQRQ,"--O2;|/+Ņ@eT,^eQZR¿{r~Y;:+E\kƠo !ǡuulټW$Sw~ӟ7)r\ Y~=O<\v ֜@QU!Ǐ|4|c>lSNa9%S)x1J)ZW(Cm0v,֯ghT?ѹpB-[vMrD7B.b/[Ɣ;L)f|TBQrd>V_τ *B!sNdT}=of@Ͼ"76bIm ~=2Jp1S, QVoX oJK)<A ZcA+ `0&l|{3Z)@g cm i!5)@kJ~xǎW_<2 5F;3,]ʙ( ԶP@]M5_JZIZ퀔S$-W__%߈o|_}^&SNp<YQg\H{hMHkp=tzPJq 7 jbDyg;DRR Q7iPtP @Q~?uu OM4BA*Mhv8 c \>_=ws/7uH` qFx%Jk|J1wl<}}%%%?:"/|s RRS0ќL2:p"F'6)1(+.3g9yx"1ОekAz:)8(bq&EE9euvOfq fqI1%eL~ԔsqoXiX8&BYh)BPdۜЀ,ގF3H_ZJQI+ ~ˢ0LQUc)lH`GX~9[f CJ_z֚GZm 7@OOONsK/=&:*/rTjEE N3&BkCW\LA ƥRh!ƠAkB (8ѠA BJ.?+ӞϱF5%KXd41a=dl|mג)+C w7GQQ46, ֞% eA e4W9׼[l޾3f=@k,!<7ni~8).cRr뭷iF&}32` jI"'"VTD½$t-~AIc H2{wEA4 %Bɓٽ?{{f_gdo qH)eۨ 57cij`, y0K/=.|0,Bl®9*lˢĶ),4kT !KRhD,XCRhN#R)B5eZi6D{{/3<$qBx"lǠDam3o>MEȍ^dǡԶ1PRR@q 1im9iZI:¦&mߏ  !\G5v2[qJA0H< pU|||T5a(\/5'HcQBM-ZӪ8T7nѴ1#oBRlܴ6RXERBۦжQ:AU<晠)H(M\c(W T)GCa(Dy0HKsU=şq\=5@lD;I+JKJXwx]Ν;v1memذ"ǡ\Jz wRYv0 v>) 6E֌N&ѵk L5!@fPʧ&Օ3P̎S&r[ot2_ î(.,9o^y%R8}c~A^=;"gmc l23+[JJ|>;τ%6Z+!ABu!C 7e پ{w<5w=(7]s ZYqBOYaqR~0 /B^(J$j[*֚T GRI*|>RIE@m$u;v2qF)WIzܸ{rcнqvxn'qzie`iLeY}=vc#!! AHロ20'B~_7{6Z+!%^VF$[nɫΝL,ڴF|tӌºQqG!i>%.!;B{xuG#${{ fr &H ȊQRңRJB`i~{wiyfOe]vs"dseQ)%\(?nZP|8]ٖ OʃJҌN"T**.&9ewb9u,(ŧ/f|mm6/DH_xD:ĉ~p}믳vڑ#R)1P$%tX*(yFw{,0@"9'm8m Adu_() \ϹJ`().{tww+K!w6m@|!T'm LPeQ'q(Ֆ?+ڊt)x=OJ2A)0>B¡ݽW|)/.x&#JH)uuŘ;w.;wYMzYx1weC^We1 8JQ׺2^hN$⎢;B}aYi Iz,, ˶/]z/@(7ִb?_4GR Dp8LO-dz̙3^xad47I!<~D%O!J )\Sˢ [J|`3ى²,s@Jلg;((*-Wڵ̾k.` ϙ) % ܧ|ꩧ8ygŊTTT3RmYsgrJ֮]W_}A{{)4L&]E{ @Ge 7!Dy thڻjn"eÛeQ%D Ai.,rO~!%6OG޽9S]9~(p3NHJ;s^㢋.bÆ ޽+իW3}#ŋYr%_8k@:OdB:T)EχNe,FEW(TSFEK --75Qv ΄l fҁ.=1/kd!%T(xA6PUU /Eioog\2y2~ڌTJlQi24xo/즫c'N\՝4v,~̜81c+TSPQ:;wؘӠN:*dm%Ne` 줴 ˶)b$@9fbhvѺ&U*B !J J&== *-X 0^x,%htpOц  i.+Ο?ݻwqnb^L}:˖-cժUH)='/S$We2sZZ|9cB~RP4%@6 ho ?\S)ǺD&928BYFkv!H;;krfRm۶/|ȺY}ˁCdz!ƍ hL$,(CT8HCS| lolH$hom%퍜{%Db/9IsI5M˸Wx=HDh/% )T*ł ӟ4׈ .`w`AHQqQөh&0 fOx!%Kl;;2I'm݆cة-++n0=H$VZZ%FXd|_\ɿ$)AiTf,"{i!4LIx L c BDq1t={ݹX[8>)4651τS!eeeGQCFIR)ϛٳgaYh`Uin(DN#5x:vСSX(*B++@ @Ν{/BbYT --ϝKRC{y󭭭3f}Yt)o>,QEݞ~g8 ~(\} KJ((.&#-+ )^ګV F$-P`YXJQt( 1BϏ̩O---f K.gd߾}tɰNeYW_}}圓/!#]VVƆ7ޠ{A$%EBЊFx԰KAÅЬ4]FՊkCH,IܞN~yxuVjjjY\\/ĵW_< ךR$,C6pn "*, bZ49Ba v{>!и$]FQfS#hLxDJXDD,㥗^O*~{7[nsS)FKI\ Eed%P&%>@`P14<ޭ5aKxdU B %ڰUVƋ/RWW7^xRmsYg yq+5kXW]&5mhE\+QZ;AJ@]%(Lvsue2֓JZ17PYgƶmLFcc#{aϞ=466}O?  rRqn,;t{{YhhrZ¶\!Rzog1^c޸'#\KR ǻb#L^xQ]3twq\gnI)W]L*nx2yR0ϲ$%$(~a)qrƐ6醃CBPmI[27m**eæMLƉ'8O>ys<uge˖ŕ!bݺu9mۜvY񨽽W<QF0WJFY@$RUn Rhq(śMm3yq\p#:{ncK.T _ r뭷r 7P[[ˁry)ч+VimZk IJKx,|BgizIDATKkZ&n `O30uLַ8s0O|u|e 0Bl\m6kv??n8:::;;ٺu+;w7dݴ57RSDʊ jkk3yS0yT&NȬY>e5eY! r+[q')֯_3ٳgsGpuV8'|r!^ZM ٵk1?3f î]$1?x7&|RNxAנ2<#1_|q$?Zmd0*m!^>3ΰ|u *#z֗ZxK.]u#|g_͎.\3GV2!^6, 'jG\-AF9-sIENDB`v_sim-3.8.0/pixmaps/observe-bandeau.png000066400000000000000000000777501370110300500200760ustar00rootroot00000000000000PNG  IHDR@^5bKGDC pHYs.#.#x?vtIME&!cN1tEXtCommentCration Damien Caliste l'aide du Gimp.]I IDATxydWqs\*k_{Ui b^3of2 3c?#bBI[RZ{WUWWUVev9qoVgxtvVge޺'N7ވ8^Z4x/Y_KI_0u`c^׀^)^2>2'Q^ `e,K/%ȵR6w\Q 9 n?%:TZXpV *+LTG6ܨPZ 7 ВTEE&U V XeEi$LvF L׶*VuEbѴ\kW|bxHa@᫡hdTe2p ]k5~J',D( * CM<`eDr-kDO\`AnU؁蓂,(,PxЈPӸ~98!E6aJpKWC"ut >0W 5v2O9C1) 8'ٱL{ŋ&k*t[A+Oo(U UI,c Qa 7v \h ֙<}|6Ѭ&kE4c68QP8+K L+t#ΈJ_bD&wlMn|}rQ~iZDcU|',,D xMN8Oz @PrP4D*R6S 0 rC.$C!dnY 9? f8-椢ܬYp@tL% Td/Elk Pp؀sB BQxB` xOp1w>-}>jHHR H[ gGrK>sz oit!!S-䠢SYeuY%"O~vK=R6XRX },td@9-T&^O= xHKbl@a%yFT[9 0*g_-Xu3TZǏcYpA&7}@ϢIM0C|,1kC} & !,0Z} <3# &>^CZ/)9&=d^Za6ys٧hUYAE(w- M$:%vyA0#~RPYDIL1n}+l'IhWgA.!z@T̐Qu"*(nx=B\j5z<0Cb(A}$s&p0}/;9A|$ y _%mIlr^_μO*F_֑3 )өh r0!0OXM*Nua妔#ρ|22\I(FjOg$nIِnK%eO)@dU"NU+ aK$*W*l(ˬXd'# 0ihs UXnkYQT#ZM&jX`.MDU1j#$ݑ= @+TG$)Q+W.*ԡIdžB&MXϝ>3+J&)jn;[b~(Ixc0g]G*-՚vyP?q>>l/ ZEHJ9Oѓ ȴ@W>kЭǙ%4 9zy4!tBt"I_}1z UͰ笚#LZZ< r pPs`sRiQ46z =2 ,QW MBI-'\Zi~W=A%N9PF=RLYRxV?^uV423s\@,hɓX (py-R$,~ 77+X 'Q3䐩 g=Eɦ@*Ty% R(b4P>o, D\A9'gݩVu>uxi9#Rnb=-H(u&2<' prYZsT22nƏU.L eVńdYt8ey p}Y9Xes! jsSZII'_@/q3 Ҙ+FtS9pKD9 3OiI#h:&(NTPk#Հ C'}x0'N`3`0CxZ&ŋRI:~`Y7]gy5 }L!吡(E3iiP z:R␍W} TH?!yh"+x248>wu4[^C@hQ"^PXH!([ps 8?nnX0VLs0 TD5ܝ[ɴsۡ.Vy([dZڅ S[ ѯκ~†MЊkE>Mآ @Bd~L8\) Y,?'.vr&TY@ aH'C >M1:rLth(t;-O(ksJN4hP_<9m7iYd8GQ9AELQE$KݐSW8jѭ<ae< ,ք6D#qRk LrYE*ǜJ=Aw*`rSQ9Q52@N8\R/s Q4Y=:6z2h@=})@,- #GQLt/v('S1z%4"Qp*|fHS~Fa@^?4ۀA%5}WdbaR]VhLRSy$I!YQ 2'A #LN/n=y(}^Z#wzȲnvO- 98B?#Fs'e+:xHOfMn(]) GtoWp,~1fȀBk<$<kg8I|bT~Y6yiHkT!U-/b$}"r}*/䄮HZ}V~aJ"_Q9CX馋ňKy Z9;M&* <T 28,0nk(iZڌyXt64}b*B+rr&%3/L=,ߛDP Ƒ nr!yBʼnyIj#;}8vgȞklJ6-/Zѿ4Ia6Ho~\pjŚ>?\w~T>lK/RY\ FnG1E$=C:Da6yɈMpZ3dB)z=ΙSaf#^/Ϣo ­ަ;J9SʱWdh@3Fޣ:рGÀIlYjeNmY[|v `K{nc+woYqbC0>rcH}'~E4S爝Zr WM'D? |,Ԫ怷{tK߫x,x,~A1CV@(I΁&oII<&bI+T@6F:C| g M<}9Eb K5 jubt3`IMnNQ`;w)g0/=c՚T|W*娌%|و+d]i7}rt& ,D57$cL&.R0%k ̟_0;nv[n 4;toQY[ywuՙ=ۗdg]^cWg>rX%N8E;6αə&tԢ {,: UW'd|~{]fHn4g'ؚ߻g+?pXKy .as`o>>tq*y"bϓ(.~ɤTVDE/9 kؒȋָ R-9Xt7~׽岋z ry,@Z4wX l7 cCL Ow?u9`@ Y !hn['XZV?.`=TZ3ZnԵԢτQ99<1m !S*$o5c1ZnYa xF(gNzmP-@='N}l~|b,`UKfj.QWۑ˔ 0hm-ΎzK>g39ctQW{Twt,֢9I M7I:>DB mB䏥uk$6*I3D$5nn! g0=b.#nv9Uc=dZ\clԐ!EF% 8jY( L`Ls`˩uUv|llN2( iQ'FWvUd{[\ȉ L/LQi+b}Fuޚ5G~$46T`V+QN }&R2xxx/"()73Ouj=XMkSw%Knrv4p2"p{+-((Vk~e:2؊5^N(-BS)Īq U%Sz<`Lřdo ,9`;8q6,rL,@xZY'03wܘ#λˎ}>\ 400[mĉc`"*HmۄH#g|Sj%uȺX2eks"usigeZ|ǭٰ.B9fV;; T0zht<9;o?sG8Oz> )O6N\_oeKz=[B#62N5LNB}\5&/ Zӑϭ&:6tjni{MUjVtT]c=݅|9!hR#ãsO]8UJO9izι6w|+>(1nf QmmOTtj.[*|n"􌝮T:&6{lv*yqZm)6S֒q읚.w )NzV.!`v:wN cDq{db%_NewkQuޥskt+lIs779vzL7(YldLlm\""^]j0ZDEQx^SgQFCT# "yFL ukũt'bF\JLEONLv EQ6ύ8oxIEdRQI#=#!0J0Qg|VV[AP̤Mo=,<WQ!Rg ^eン#mZMBXVtwjUUu5u&^6տy@(RΗ4;M3;"崈~Oˁ(rb<9|.7@Zg3aȁ0 Vq0y0 'ǫBqp[~f%+]|Esh;w(ɔ7Ud2J^&:'Wh?yAc$rI3RJ;4~|/G s4=jF0$`&H$|[|)e:kg2ۏMR{bD7%ݤMFP#~m/ 7gs}_@9Sݿtw;FWl:&gh:{.&y^͓,X\a3 ^`ٕ|?s6ل1acкuŊazQGaR"qu= >|?x>֥zMҲowuf6CH@4F@֓R[G&gWA=b?U(F)āZP밑ƊG0uQ''A<ZZW }皯7RZ[V-x7ojd%81 b?3ABƈ%ٶcα1K̻ZE)ocmmKo2Bw8p׼׍m{tlq_a/̭k5gtTgUw[*hfys2S݆ږɩ%SPضs?kߺG/@h,'ZTZҳSͿukWݶk޵d=G/ ctr<nVbN8{Z u Jyfph.`۪c ǒ˖.>xr|E-*Eqx};3a`EI1 .xΡ<}߅UyfͦE=mK#&{=5 + IDAT^[o)+X!6+}M#'*m{p4 ar]ݲ݋#=/ovv'K}x^0+ksFvY-wwO6xᛥɋJ:Z[G -)!y/H.3sx6aB3>?q)d3TRQoo>]*m?79EI}"pz{ '9+W?=♤KOO+^yŘ6V¶BN'>xGW9;_\S[C&[l&S6FD{>_eF7rlljZ> t([۲sx\>rbR\ݭ;892:vu7)'$ H`{b@`HXw} $xAP"wZ扉y`خq5^vCBqʄAMn\) d <=f4$qPm|K4+.^[2w6'0#\9<,ZS)stwѓ {(5nB)"(9N?8K ΦvhHgN8,i1qYH/.VTGgױKW{ .p(q"NЃ4dK1|Bpq:NgHYxê2Cc\&2pb@q33HkJЩViý;rw-'r̍\pFIp`&`zb:S=;l찱KnCUWwhd5F@:ƶ=ڔ|Deä!ƠmiǮ'םFv.WW3ؿRmpMŒhAhlMjYi8G PJeKzK 9e^O-5km+Gu~+F3? nXcUM"M_!hW xwϥw{?/bk+NNjPZ{w*d>&z<9:{?:d'U H. *IUQUaPvkԫz卵9r?6xgs0oؚ# =Hq'&Y2׶PU_֫.&Y |?@Tcv3{kt|Oew+uy֎U{/PΈZ`Eb?jLD'ګW~أŝ0}-dٞyyE/Y1?3~z:kq6*ft $ fez"F>Q*+o}ro ہ iM wbG{e:ב sPC oZdq{#GGd[ZdZ,+`~>FxF^9>>4ykݳ@BWf Tۿ.哩欋)=eodw+>'[pfz{t'n.%mcE|+Ao[;:U&`3x.}Z&kZF@=+؜` xBO`r4sͪ#ľļ?s")dN|)}o{[|JC|%'T.z*iԮ~dCXo qX7^z<B{^# cQ u1Sd&MXdPIqjET Q%VY3q}>~`-×w^y16mD68:Yx~' oF\_[o>xW?;^j(J|Z{I-j*E) K8*V8U㬋չȳq-BAQOP6m].r<?5xTl{вzl:vu˞>g+N9{=`٪_ *Og]r >koz{J!Ӊ@>4.ZMJj$/$tZߓJF)z^ds0C09碒::73t+^փ͛m_zx*:8^0ؘ9H+d<`ߩ&5FAn$uA:U5gvܸIq@ﰱn52Cg W?ቮSS=/9&zݫ?޽{IfW-ׅ13&D -W^ۣ쪑U:6U.cqNDDz6oι&xF1xI1!LZ痭պRv*eȨmY@x{{8y~Ĭ R:k,3 @!T9%O"{+ppJ "υ3" 厗Ks *F4Jrd+<~s!k9n1=-w ac.P!HC9VlR4UZcNן}y3^O`t#luܴbDl2WX15ů(i%WO{ңe-9u;?q%i|{Vy .ejԣss؃ ~x^,irÝ90{ ^3)iZ#p^V==jl&,he[<$DU"c> ݣ{ٖSЈA+qҽۮvʅn7B ;;^(ptLGϪS:?'XO~j 椧 NX953ZM**M4j!WW4ɞ uu;̻`ǥo$lXoM*w(aB3)4}Tz&-6⥲qjWdsF>iW wΕOZ}6vO>0'>T%ŕZyyMD*Ǐ>=c޶ΫC1y$z&Fq/(UY^ 1+c;`[ju_׳mov֦&̔6 i9we;ߙR0;P@+l0sjs]mo{0ѹ#7@ٶ񳇾_hxB-bgE1&,d{'{]|emz $y4<4pW޴_hSF~xơ.fy}|w:ԩD\s?|qO~3kHDeW)0AjWȘ]yu8Kxb] ۲ #O;/fi@C6BG7ɽǟMHAqy^v>ʁ=⋗w/"AA7qm9g?>ekOMCٓcih=_gqoؑ#zڲDQ~a/Y>2>]Gg^tIHj\xŠS{\-L&lm(z"bMyԙ֙7_YRۮkm_sUW*[Zur>;`!+qO\?3+uc5acu.q 7F/Vg7߷XcW,,|)լDsϻ=/UT.5kN*bf`N_/8Ug16_"Z׮ _`g;z-|Ŗc@gLMU5Fȩu5}٩kV,j;M_U/CNseXǿA&[SFE_#ƗŲ z[+\0HYɼdpiQի޶<ȿ[;,::._梹K?| }bs"H+ǧc̯V/[dk]$5+{M)}{_+W~p.˗oyjVvtFaM1㇏,ynKUW ^Rlw ԱG|2& 6~}R?qDJ_2DQOAPDZӕIqc`GG9V<]'Ԟ9W@<" ^eͭK /5h9P FuXW 1ygne$}kXXTT:S(@G_̦ծL\׳eZJ0,9])w'qRFVz6( jy9t2W ztX-JC~WVX)cʁ{O&Z}PZlEfիoƪ\gͥkV/KrqBC~6j~u,˱z75ݝfʥ\.W r{*0t*UsRZ:.=,_}J[|P"1/ LUxVP(U}d9@:0ToWnLX^ؾvO͒]{mE'/8w#f9!Ճ'bx)\j[%Sݹ\~ NfRP__t2o:f,V.\8j-^&v&Ym  jX8NzZa03R;.; zryC`:]VXVJ#r l>o8(Kǩ`XKIKx2RzQgqlZ!cn9+'䡍6a_hK֮pUttt ։fCunmȒ.~qRV C D-Q тuS v`|Xr eKyzOE7fyRq {=%E; ʈ,+=́C3UQ5{s5_ Mp.߫ ȅjQO`PA F$  j:s7sX,OPǧ\ .rHHtηc/L+^0Afy}+״࡟IT5%P8 dTT c<៑c1Fn8.]{`½cJ̢g/ibkњkX\(xa>[L8BcP8"e$dPF;aU[3FESm Ǐ}ⵖH܀Fi,WTyu|MGYͰij z뙪Ox2p*?/aBV| Nu0M#gFGE~p-f" "|g ٥!fnnC`,e>4!V(!cZEK!SmHvv7*Z 1|E \ & D :%)rC5a)љ^j] :@k sO*kj|- IDATRz(CcDh-0׾fUtS- a,BPڻOlxU Z<{#䀄#+MA݁rjݶƴ6C^"Lݼa׮GJrEgݰn^HrXv),A0a5ƛy%ACǫ Pn YCZJ]S 45KPS"8גON.*ADjh4u"CTA8[L1B{]A4Fna~v@x+mA57WU )3JuNjԪc,ZzQNMMRHŚXPDґb2DX#zpՒOr(vbrsMQw{O>o :fW_bj%^ /<Ӂ-=+D$WJqb~ilS213J8B$t?42y뷔>g7< 2{B-~B),^#tۜÄD|bmL1*\X8@2 :7RZ6{$~D(/_8Z[Is5GjcJ?SZWŘX)>Jddž>UVBr66,Y?E*&g8s )s!AϽpβn7%veJS"wfzgNc¤"t £LQza-z: u[_! ڌuH`a'wj>yXr'VRQXRp_Wkp[w~q)0_-dGw+P ') `NS)Qw @p?(T7m_VшNN|)CU>Mr!+_orqO MN!h]<茽2Y0풦4Zevo|χZC}u~}*FV*$L (O'r[t+ DY.YfӪJwpm@5Z*2l[ﳾОF[',1 TXߘSΌaYtkqi [^cc{%m~!PC:\e ^~9]ݛI9C¢QΰD3RmhA*@@ buY?otOK9_,4Qlg^xiUozz0K,'QȌӽaCt֭D&p0pU ڝv(t+$.K鱥R+0WWY>o(lpH'B%LPVWFiD熯skO!:vO)JSf AOȳAUKc3Dz4 /f U82d$#BWW(ZkP[uO QQYv²4͌0T&y)[r~W'm849$-H;BtBk-B KOD*Bqu|Ƕjf.ٮOoVEl'[6acVJiF*њWeZ# ڌ1[ZǴ`]\~48gO_SI%oAׁ*ecaf(/ ӌHEg#s 0xc=s?ho)To!vd Bu.fJG,!F!r# E{CMHr~Xw}| n)h,ϯ? X=g%~)a[B\; ڰ$ A7tVi5UNt?p&`gFLtaEr?. i~?C_̘hzʚފ&W rV G5'Ε#!ذ}#۟o8Z(G=B5&q5%Blr2\ּIkV$0cM} =gѿaW*Q}dࡂ㷼6>#(,GN4#a|F^5m @6 sa6`Қ(i&NPǠaaXE8AevbaR~IfOME9w\s:FKLϴ%ý-v܈+5aQx^8#1jAHIM_% Ji qp.GIƧM) ł3bc,|?q7ҕ}/o^Jw''ڱJMƘK3㓪)D6>Ǖn^t*fv R:Us+xh,䦆qa,cW^9 Pd5XgK㇈QUZ+CgB'PG'If[#0/Ege-јoX!,n 43ɒŶ1^8W͹\@_KaVB{>P7&֠化jz@Epjc2R Tj.p+1_(z&i*G񼱐?Ws4!9λ{m6lgp(H=hs_pϙأeoJ_% _%C5IUjafy%U+'SwR su w .$ݔ'(# pىΩKEGcQ61#H)UR*Yyjq#ޑXc΀1s(Tw^xsSN0rMqe?T-0Z#MPsy4EWRɥ:;E|zˆ{<2yBk3kG|S` &%53:59?ҔU]F`5MeRE, ]A*iT<Խs5 ˧CϭeX/{|b1`ačrY{-5YN(z J3̰n` A6V2ZBi~mr`uϔdpNO}!~˘سi?qz?-wLL\|h\ XVXCsrJ3#T-m9JE#,t=wFBr- | |Rjjw+tw2i&-rYLcu([=0yh)B%:YBhҠ ]u0K|I&gqقSXV_Jk66n xɁjlzjOwx|*  ։l"ٖ(NM3e&TjĔ?s}RP0+5VkVRz$|5/`hZu d9Vƴ!l :m6G&RRP`\tɕ@ό.H\-!"c}Pcgz{َtHVpBFv%86y[%a2)?Vl J6l|E?:H$ɋR.7<"q&>Iuc{"{@G}yNMXl6sD;eSće'ꤗNΒ尜_nKOI((Lj,̦]'Iߵh2_ ^bwс L>T,YW+bP6&A><&%>URx\Q|i5M+Ƨ7m2[7JY<j3U^qSYuZ6]$BE嚊ٟ|׾b 4DB poM̈́N[.' tʧE5lKD E7\{e6#M#$xxԻݠ.yo XupBo e{oko'OO|Dk:Tq!Wq x\ n2|!bcE`ѭShGH}:I 92"f ^a$XED} RffT;kvf`_x~?wL7/,)k >l ԡ||yۚa8-?tz {p4ilb׽,z/ fIjru-#[FH <"U7L-SvOޔ2iX"A'Ȉ[_-8X'5K?:dXF=/!86"X 9J~0\x!JM.Y>L:Lj )SRb ~L5*S![=O/֛.K)[,Nsׯ>YKܚwϭY)5giLo ij`*Jrsn1ϐE*h !5[!nXfK||+cZL@{f MbTv 'Z@c? S ftg.Qox.fF*5T`Ȋ9:Ko#p3L_|Uo۴`c-{g VgY0/)R1gzY?shc0rS#iȪ18ZFnBiWΒ`K fM+ڲB @2*ܮ. +l|qٜ@Ӟ~ Z 6QT%d7&[T+pk^j.:Jsd(?)09ܑU%N(D\VOq?}kiVXe!lCj/n bZ]a4+6P(|Dif)v(0MUD|́Ǣ|+@atsD'OT$}l"iPTJywkLI(ucN#9"f$>팑a]?o_@dFĔUF4h4YO] a!)- rS1F(ݔI]wUFC۠JNȮwE3+:@uӤ]\%5ٲ&0XqVJtާ_#LtOFG`ߜ+zK|-#zP ';O!dDFy=ǹl[laf t@~ ?ZG#Q)`Dk&_e* ?>:|$7 Hzdly\1IDATK+xk4XB -u睿 >rsq tV %F⺄ŏ*i"r<;[13aŗiUIxc\1a!H^G[#j|:n19#9Y\m1.4 N=pe}.>yNF~8y^=/o/p5KiqyI|Dm c y𱾁yk`9ÃuZwt2H7{d̰zg^ &.?mf6=2߫3I`j&ޠ-Cs^7Y{0vR> "c]пz\,5I}w-y08s+&׽tj?~gW??NBڍ l 4 ~>{k* @4;M9'i& mg}ՙaZfƲc9/~~sIeVqV`[V/ ;hČs22m[iZB-B xm;H3:Bs8M؛uݕbOw=}iv,u'd(LS+'SL{,bߎ]?-;NV2Rte,h>G±ےeג\v(i "etPIfɠGY"Hګp|fRʏQ{Y5NkNFF`Q /tf*Rfo]5K~0k=Exi R(UONn.Gh,n+4(t|7 Y6}I17].ÊtZl.B*[58mxRL4SUkN"Vєϧ %X&MV/凔mRn,'KN1Sltgj]{ז*|pz@$]kza3|;v$V`6Xf{[ --l3@(45K# #g7Za Ep;ɝ+>1u8ۛ'tc93Pmk{os "ifA*0SçsͬűmJyIDH\eȢHfk+QtdM$ >B607p,Qŷ=24l+ð3V':|''@0uA7ˆVT}Jц:59YEGv-PD (.qF*+<^m-s_Qe3R*9LaVPGi<^O-uB^ ݈W5-)&Z(3_QBKjdZPcOXgf~vuU9 o.ŲRV* L͢+_{v[&ᇪE2qhjU]H2HQ&Z@ 4,j7\x79385}x+_Hif0Qa8^Km`KKES eIwCgT=|eA? 30gulZh@#@v1sl0Ȕ$ؼv}#~F_r),s'z4Uϖ\7KRHy>Mף`>9ADogsxn!f8ON9efLi5^ClYRQV-"gS,WSI^!f؎-鸨[ %_j8fk[' yK9cEBv;(hEe|kmWh7|ssr5N] Sdʐ-Yj5: \s| ȵ ޲y'kS Aoyթ2*gӊzI ϓ?We1rZ/$Q$\>hRNC`"t((g VG)&Ʃ |K[Z+5Ba9"0~̇jJSy#a"ixkRC)]U c5Z( aCdW:Vf3`C0E&};\꯴Nao}mWꇾ2uS׼f$>gI+Q<ӅoQJ7$r(t6C_!)%)18>W S;(3+s%g\p=V#*q!yJ-83M8[?H,6]+1ۮE;-zy0ID9Yy]DƈJWڋ|UTGʕ 8^A_*8plqL·hi-Ew7{(wZ%^3MfVg^ՅWuޮ<Nz^mbΑϏK.rڂe6<|m9B{FsmV'[KB X>1z [uHyNg_&Ze ioH S`.4Z3=*4̓Q2VCVY]/|̒33[(rӤ2c 5e.beG6\v&+]}j}qޱP"M@r Xv7`O^swT} pkyJ՝[Y8s-GM(Heq҃pxF g ^7O\9HbgC JYaۙ0:AV _Je؛ф2jgVݕTDXm eϾbοɑm$&haQ35B H') d+X}cg0@56+38n3m2{ y%\.M"!?#b&HC4$hWxN<@dux~MbHx Z#s|w )ɂʁ>;'5c 2ȑ:o`{*a:@OEnȈQF#LCh-8n%QP UAfY `!OW|R)_NnSddL ɑC3 &0A ,0?!0ϦOh[NM6:A)::kplc/<}9p#؛4ej0#>92;Fw~{Ezf@ZC-!"#$`mHy7 ؿ2Zs5_ɊfKh[jf)ƫ]Ah\ @K  BlW\:=jZL@SӠE-%M?/߻㻳.+%19#A-zJPՙ>~ˀ͝nr4Kp5Hdg^6Gaӟgk)("v΄Vތ-pnמE,2U8ֲkmxw_"FbOivzӰ1M; D}yhq቟P$zcLerչP#Ye V\p Eq5ed]#7h00 !P"\ 0NALNxzƓ"܋A ϟB ZaB&8da} ά"ZGEٟX7_ hєiݢx<Sn\3Z5%È޳c;F?K[5;qwUd|A"kI p 0ː B0yWcƒ}3|4Bݣ+&h[#Ph+ g|!y?=Y&Y,PH7`#[|** ҚzJ#8 :i0V]V$>X BQA3˰ >eϿ|se ٞ4^U&.ٶE$Ek~`2iHN=hu947j{!t9k uyWs#xVV*idžW m_U$,'{9o]&P}E cnXX{Sqp:S,vzBO1s­W'zf%MڏrҼ?a2G䎋`w>&/.m)47cՂj:*Wr?0SH%k[/?x %Z}/>})RlDiPډ.!M @E@<%m4~x;{{,N3l]}v-#Z!s|[~ 2@>Z OOO3 _cyCHj2p6wkk{EP7m[UpxҒl$NƲ9_?s $r>R!u> ^qz=I P"Hjژ-6qtG [FzE!EsnRݸ5LʮCc̞$qrXvβ\`Y b3nO|)ߩ*D=l/iL?)`9͵:T-KID܊~n/'}˅MŲs y`ކU+\\ ٕA653۷@?8X'u#}3{ET.< !.{L_࢛GeiPϻجSTy\ore_~r}s5Spf]J]q`s,{Ez#2zQO徶("XФEA>XA|IZq(>.(h H &kn6f^f&;l>> ˲.̜9s_ivwYk4*Hɽ}(^86fxiX+*A_W%GJ%B}ڒwc%PBǺ}~tQ7mc ¥󷋝Dwzlk8DFI$e [daXF0Cy]3&omNQ ]iMI ip,GI9`uZcx&ߏ-C_ٿCj͡=c*3a/&~1zF&{wa;/?9νox]<.^[2QF&fG)H |*‰.{8p"a  ?zz-]8k ERGsGȘ=0J푚r@еiƼf՘Ґ$p Io9iD~0޲7z( yF {`QbiDKJ k-Bvqv{GR*NfG+pl &DYs.L'ɶtJ0͐;L\j[(x\m"rur73je0&I(+J/'ׅ90 Z9a,#ssks4MJw,S[2{^ 4mZ,rگdMS^)`URe07W4"S1`M^ܸ^!,O{6k E}U#5!`MxfRNZ&2XQ3L<;6߂X(-=I nl7aT}D:ČKgY\͓iΑJ0VN+ G,@U=M{  &b)P~\qBeKR4$Ϻ 3_Or#2-:8!-v5gcI*պJa,PMSAn! EIENDB`v_sim-3.8.0/pixmaps/save-bandeau.png000066400000000000000000000520431370110300500173530ustar00rootroot00000000000000PNG  IHDR@FYHbKGD pHYsutIME(4< IDATx}wxVE33@ !** ZW]qwm+kW\( "RR $!y{=eGH!~Ϲs9̹3[-~Ko[-&cL6B3܉!O{X|XmZ`Z'@]qK.0&Q0Ç m׆ucXkxm30c u<.ph:&c,5(-5Qei4B2޽z#E1]3BEW^`t`tYΤ$3w_C3M;.z-ĄdFzǞ`S6c)enW,#A-zMpq(6y8:yq x9v"˗/'._"$''[d[z5޿po1crJrW^`aɅY:J!8N=wtC8 Tk s8: ;½|X9P߂xspK|@ 8: 69!Ǡи~C4糳`0ѣiW6 q0qqqFsrr( .R`h-|M)S'2CrrYܦ^5&@U5-Xn Ng1Ç={kE=C01V1x rFs) l q)I뉍< h O'6p=7޿?2]9sX4 vmɓ'z7gɺ? 馛{JKTo޳gv ]T:= `={”4{l _jqycRGg2NKOF=|@hRC'&x[4ix⚮&P=0N!fpZj8M٨*<`.#$ :86;pd~GK>=Ѩmh{h@Rn믿^Ɖsp8Si<&ַ!tZۆuA6DF'kta5'x"umג$]vqIFn78RRRE op-{NٳM}#ט&t>h877WڌQJٳgǎ~v٨SS>;bۖ]sA?nn;*D"O'\_7!6"{H΅O)SsM;#G>hg}v9mnEL&StڴiZ|OƳT :0\;ُ^ hݺu_^:L9L+ĨB?~8[{,a7t0w–-[Q?!隠y.\tMf{[SGTeXǑM.ve7԰`mPf]pf$KWse46y,t7:yH]]ڳsz. Zo}JB*;.6s8q&u鋗%?J]|6 D d8Eґ bBapGXnc6gJDEk֬1͝;CCCܹsϟ??=-)N3s}wfFT֨ѩfi[xƲe,<O[ZZn۵`a-f#V9shzÞ*I&'NZtc,رc† Lmh+_8_~rɖpM/ڦ۴H7`АСC#.,_r-~AݏE 猱Z'TЭ]ij ?\e`+*:K"ϰs:Vruɞ͛7`s1 'N7o^<&>{QGOu#aW7*=zsnx,̿nj9iy>xҍXs*u\`0uu [7o4mپ G Yغyiۮ@Xn9Bd5}Ĭ e<;S^qyt%>ށ=W7e[]LŽc+ҕ[oƁݼ90º_;ܹOe3ê** ~xgܞ&ȵ]wsjD==&fݯƌM jaܩ>_loKԖw_K^M'Yk||r5Yiו82VGTₜiST<ʹ %j/ Q!LYRt6\%S,Vz%J( eJ+!*䚕d,/$p&uFMnpbo!GuO0)`k 3%xxQ/h䙮#[E?dy9Bl<[&R!f 0q+9xc_sbE;gݕׯ_$&&DIJT$*K~f>WW޹+--5}qq_~{[5qDSył'{]_۰P1w=rusZq}Z8%mӧG_&կ(/k}M <;,X  ֮]{˖-I[lIr:?]T󵙺2g_}C4}Ւ)v 3OԮomK.#Ӊ&MnrJǬYj5[.]*ٚ3:jsсX'_|n*f-J yѾb%Y"ı.\<E{afgZU%voy'/ej4h?:ʃ~_>g`u[ŷ=>]W;Lnȏ?8[#a4㳝\(!-LyskO[c a.?ac<>־^(pQ`ނ@ pʂKKy?Rq&^յ / k$1@]iپtk41=/?~硘p֐LZ/o7!;7kVia g'Z-jIEK}W 4W+-K-n sS.$J巗|9grACVb/j%rC_cN!j|YsIg7򎱬ȥWL 7-ׇ_I)/-.IoG<2cz6*8gy'Q3RENu9Rh|S)8{c@|\ p-q 1 `tC>s'sn4I#h&2XPXCooINu1g8%݂hm-R'($.Pָ@z!-ɑ} ަcz Bޮ;?V,Mc@͢>N9"EvXO txӆF_(kx}l#W_h(v-X;QD}8HջWqng@芹 B0w޵a-~lt$*.[gN/eW>:{Iy vYz,i<~_~&'L \3:ᨫX37D9KzoW̽bx~@ΪJN3h{|Ck^qǓڭijEc3:PڙR[gID-z@LPTC=~+)8ҹvshI_V_f?~7~7~7~5`u53,2_-zR@Go%x׿9@;r|wYYd4/ +Hg [\1B._sxE>tO)Q>\vM^c>ؒ Y-Iavޚ ય@Ct"OZyo`.>ө#B8hk6^}yym44r6Hܶ䦆zKxDQ ( 꼊2~cHZ k޽zuqk'"&x߉dЉ@5t[tG[mp0H5Ҷ^ooеP V4$'&;.QE^c/EA6kouB Ɣ8#:ޒ=_x&#\pExۺB `Q0^0qܘ[d kܺ>Z #|U>هnZ琈c yJO\Ff{o~ <ͽò TN߿ӥ%Op5խs[8|2cm|:zc"+Bmt_/Y+/y烁8)sߵ#ۍ:ͮ fU(6>7eDi?r<׿8<\gtnᨺ7Wn2wK3ou;_\擿#QE0]/?.wo?MJdυTCx`QCanԊ^~?<랿g'bR@|v.!H² T6v6*Ȫ#c@h[gi# 3/BjӺڈnфr,.Bݳ-#]7<Ƥ3:'r0EۣYev?Y- y;֬諿a}Skrs蛫&x+G$a:aֈk ~g>ܳ~w>u(_|"/(q:(F^R, IDATpѷʾ.yg_yp0Q%j1Jh승W 3Q%U3F;~\veqZ7:X[޶ns^ t͍8Ά7.:`tgêPM%@52d`Y inn69N4DE=)AӁ  16Km+0 8!\ cXS! @Q5qTU'R `B(0dK|D 0(2qTbVN\:s=@(ӻildABQf0k3W jvZW^{dsS'mFn=qc1FNe`Czok3|Yie"T` i`afoA1H[ץ'HcqSV˺S3s.T`}?g!*@N@dg3pFȹz{ wu h? @ yT 'IWښ^Wtfsw^b9ζOw q=kLc{No'SއF-H_~x~k8ep8=6J{=a{Z !BQ?`9f3@VT (% ,PV#'XNT`!``AY9R3A,VFP91<L@Rr/0 Ѕwkl1]%:`8 (4: 2#A;B-dM_EU^-o?zVDwl6-nWQ(?VaJi(r%sȡT:Z~\45d.OMaq>`4Tx8."¢#1LM[汙 :RXW1ts#3":5ȴ&*YDC:(eXb_<¦-Gn< cò)_nEĬQy|'X-oDc`6hAX*sX[GDO$(e S;40NzC~I|]?^eawMB^'Xo^IA$%V=SN"&sб}pmZ#W C|@t1QYY뫬mAʁZo@a`ʌ#Ҡ6|# wd>g7XE $ԫ|A;ת6frMsiMB6l:!& Ǎc/ &Nrdgv0UP\L,2ֲۘ WW&J 'A]maSmX2C` L:bMtҘ&ƥ P5 uN~L'< e@+P"N~ga$Q6zHo?@1--5Y\NzrdBvvpiU9rI}Fr㬡.iU`f'M2@r8-v!Ƽ^ p@cWLR뚣ql\btl[q5WC{Ԩ (5d^`ɤo%@&+@4Ev&c`Qi0ϝ`@S4 h1D~Y4 c@@U (UU`0PUh( =Qxt;icQJF($B-D I j4BB.d=^H'{<ǧ4$BdD4c$t5%TDAtzH#TSI$P5JԨL $%$nSn9"pou~S13N4ᎱH44Y0S(!F`O(@ i'DU <~/t:a4?PP`@J%,, XF1A4 "(? /1QP +(xI?6n̿&٤*C0fNk 7 ɅFxݏ♻YrEDn:?&GUabswri}bn,M2v;3֦0Ƹ}RϬw2 1Έz1%$UM`ChZ2l07Asarno<`XFT[\xUU% xN8`׹[IGvU#f _2ԭm qp'E9pD45d) r푦F24S`O/}w2N8Puori(=9A1u `>ʪItӮp$dfTg7?#6Cj~*ˏ5Rё%KZ`ɝBE`< dYi 4*$ă/A?&(X b[`` +*DUR` ZGNdR 1~(蝘a9ӗQhl Bu~#%MпOhUN=;^|XFVd2Go3T!' Ty *`5.J7} B+0HDTU[I!.pj^$Ћ頡%q B,&xLi !dUp6uM~Hp9&]k$u% TNI0F!-vVZKU1M84a`yY p̐M3? B 6A0$CbX^0 Vu Y@0tPϞXxqsCi(1 fLp3(,vB< ]uI lR0@STA``4"TJ) ԳPP֘y j*/׽;w " \e߾0낉x'Z.8j M>&1v8ģ0G:?r=O>URٍs/qqʟ_x3.Z*GMٓ=no\аG348#Lj}'Dhʻ=ȧ9}]7>rgo9ᅯlJ?4]/Ns][.sl)'&l)LNd92G<5wvv_3ۚo|Sp$>|ĝ&B55ܷ^s^ϔ:,yP2IDvjqYuJhleJklgڂ0A&YZx>ĸ4ؿ}?:rbv_D$MGpi:*ʌ鶮S&z If*8`_WPv RxpKB+V-=S~(bdNtx=Љ]IVE-͵>{x[Ǣߋ9#ھ& 䍙៓#[*GHOՆ ؒw^Lto!.mo|ܬH=e'ǬKwjK;3zS؟xZ[Oe!cDž[?|B9&m杆ϾYon+{ˆ!gMI6vtxVÿ?JF3vdG_.3#`_~&}Ӊw?eL8 &~}="&'_WƐAEQu}W伡jWa OTJ}Za"cS_ ?>o(U |a#$w=3&{ |ΰ8-/,S$ii12A j4ë``ñ^o4@uM=Ǥ60'= Hii i)iQ*5pj81=#($XP͠"!8.+,ֻC1wtW5@ce- 𢕇ti&%6">@#: ig 9J QFɑ@<"2[[6%l1h -6Cl1czOe 헛65Ya=C:5-MnkTTB lWEsMklR I!ga;T868/gUHL`'Jja, 4Fd@+p l|wVF*uya{M̳8.jƆSrzCq"I1]Wg@O _j/@_MēOCw7g@T0(7kVH`>^]͏][37nضr֑,!֮onR^ßo>.㯾+sΐcx] 8%+M9"@Ҍ+Bw'uKEG΀Fr0ɒ|XڷBG=q(9&sݜrIԶxu)V:rp]!0rQdE>00"D{m6ǭWl2 (;985Ҹz%h3#UC%';H0S_ݞA&޼uݾ>ЌY!LFpYQir)2),n MI;K*Ę$'D5"Y` &n:CˎKArԄhD1I *ězH`187!ZTX"4T_92x¨``n3"*ALN;x8l׮]m\@Ӵx> \.+AK*M`@zl+(AoJO&䥟JU # @(X "SP㘡I mg!J1ۗ$SM;n˩Qhj0ҋ8LkO6 @2SXe&Ðxp*0vSB`7o&N˧j"<#̌'OaCdhƯK( 9FF8\億X;PE#Ab\, uNJ^`HVJ[⬭r\mMכL F _;! eEGsc͵> >2|y\3 }5[ԬyvɵƏuMI2#6Ω:oluFb[⾹ﺹٷ}LVce\jH8mVf7e{]_rK/{'-E# )c˥#3#8~=6C#t%;ۑM/mkcݽY7NN~BCO| A-a=7(&A09*(ҵm0@)6SVH-Hu4M8Np'DXyJzqbMI@AcLQ^^E`i BR8AP4.]@~j[xmv[tG\0.jy[D0,b xȚFqۛZ;% $e.W<lj02l<8l XVG6 <6DEUSL< "a$$Y3 @JH,MBMϯ68ۓ-X\&زb5L}cn=W))"GA_.[5lcML'>7:frnvD"6l8bGOVb"i}|qgǍVW 5>B0+-EMARt0̐B V(5SxR<dñ$4EoCN$IPeR< $ `nCס* *ISXrL3Pe &>4 h 0ta$!ɺ*J09HcHb4 'Sf瑊AP$UVA0Ȓ 1)PR3I*퀪BSt5()$HB )-Zۑ X MQʘ>el$Ibh & )0< %M!&EhCW(-ডiHE`mv $CbhC@qքT$j"0t) 3GH)9`B orK+qI*A$(2$ޖf~V3ӫ CHękFOͻe|?æsͭڲnu⨫:i|'dz}6mϾ}1j-NCS' ȾΤ'[SqԷF%-sG,Pk}/]% zj oow'ϲGN2-3}2cB])Y..i˗R d6sq*4s|w'hS p>pS)Wmecubn=pmJM(*~]T3U Kivv5NOYgV|^egΘ6)6u䉳繿O) gzC)\|tkZ58l&$N C+ ` [&I;qzp*).zUÜ9sK#O}4#   2:p F?_m:d:k1T%I6;faS4ylqi8uZiMU;>uGR Nl[u*?7V@Evؙĵ%$A{%0tbuf7$>j60t@$#(ZKi ܞͅR H E.wL0/1lHb6Pu^s+shhwyrOCסj 1ؕ&lrphpia2蔑`^kC[C\vQ:I/#BqPsqnuIs@ݙKz`Q?D`  sx{u$A`OyJϭ%E(R7=Yj&-[ ҋ r)c&]TϯLFIѠ%DbzaX^2]y}:7Ň[Ϸek't:XefCPxW@//VkG` xϏMX&[w՟_x _wVR>8dn5־ޓKϱ{gt1R__a]:1[cĪ#ͯl)l}ޝdغ3l2 ܰѵPZ|IWKHn)HRu<۫TFǟyk"_\ Yr1?8{yD=P):f*4Jǥf &ϧO-/a=zh?J2.-IENDB`v_sim-3.8.0/pixmaps/stock-atomic.png000066400000000000000000000014271370110300500174150ustar00rootroot00000000000000PNG  IHDRabKGD pHYs  tIME 1tEXtCommentCration Damien Caliste l'aide du Gimp.]IgIDAT8˥kTW73I&qSX`YELeZFMw"1H0N'Λ}tabv#p=?CQ)cb++Ɨi7Oj*c5;Բ{dkڗWGזi]Ӛ3i7qh#H-}HwY8_̀e*]AbQzy;_Ae?Ƹ T=1:B舕8hSN!6sXPs(cA(8p>YOL[~0.P0|TG!{p8t^63I&ɽׇHa;s߁xAp4&~~+  4T"j+wRٯ)K]m*!a% AEQXw(79.WY8~0LQ`#(˲Tjo\X/??CVY׀ӀVH%툰z!Ŀ,]ΉYL>C_@<,D륅il6i\=ǔ^x rs{ SH]q?t鉉%UUFFr <$P "6@Xyu(s7ޞe@qA{e[oVj .A2 (`%dO.'f-SfQ]&ߣ7A,B" ok `y:MZG81&aV.-/d0zC ڄo%Q'q!lzfFuztL6E{bdq+:[[2-rnn_`2`1>..;)XR'i~Gu ՍD=yr#a;qeLS^lm 9X*Koq.^{nk6oW)0`$Z-Lf}Hf}Ҁ6 ѸCxE C0밶Va}$!3:Cn#XXP()Q(#˥V 2=N8?O2MxIENDB`v_sim-3.8.0/pixmaps/stock-browser_20.png000066400000000000000000000011611370110300500201200ustar00rootroot00000000000000PNG  IHDRZ pHYs9rtIME  {IDAT8˥T1@( Fi,BX) #^#Z 6b%h,RX;AŠ\nmvg];nO&P($?1N2 STʲzeYF,fEQ `~E]./vv{6a7 |?e7ͷ NӴz1Nd0a8l|Ft:SSι\yB4St:t: ]VV8P(E@&jlKS~ǰpXeQ/zyXie_:S6% *o:FEQ{Zb" ,˪*B$ ME4 IvFr< ø\.zZ4M[GrߧR)4lBLF$u^m ' bB;׀3gIENDB`v_sim-3.8.0/pixmaps/stock-data_20.png000066400000000000000000000020701370110300500173460ustar00rootroot00000000000000PNG  IHDR bKGD pHYs9rtIME MIDAT8˭mHU?/^ҫ \t&:Ѩsb kDE0* z(^DDZ/zSGIN"N5ݫ⺹l{9@`Kn.Āv u\.^ ӠiRpVԩ, OZ0[3հu8FSף]-:@n1vz-%G+UHPvWF9{ދK@a%S)$~Tg ?}~墰$/N̬A 9 #Scn>w?o6&z'JP]5 LΟ%aϵVF{q )zy:&뚕DUIM =d󋠌X^(,((hm|7pӹ/l{V^8ov/v$ $0P))bVݵYRnrN J(Oy,5C/rV&I !RB0 /;ʄB8b!J*-&CܑGLu ݺe>g!X ⶜hK|F`CxIEqyҖgz.䶦WT]e(u H"k("erFrӴV+z*̍A[)λ:RR&){7N1LN9*ɸoψ8PhjA(0Fc, r"宍 .~2B2>֊KN@f\N"5D( hSdx_?CBIENDB`v_sim-3.8.0/pixmaps/stock-elements_20.png000066400000000000000000000016501370110300500202540ustar00rootroot00000000000000PNG  IHDR bKGD pHYs9rtIME6~5IDAT8ˍMhe󱳙l6ۤDcB-:hւ JB~"x=K&)"APCVPtU1C$$Mcfgq"-^x.q@$vBB@r&[?k , 27=[7R$' v?_|G$~3OF[$gGc<~̹8u 1#89n(.r=CԮsDWzX<fx .Fp>D~N3@؟!0 @h%#XB8yX}yenN`lok3J TT@׬UȌ wjsV4l'qì ,?V>vFe'!,]ls#Gt R}+y}wwMUh0`?WLMpaiaB6zl.@ŴdI" {;ǝbԜeF RqCB*̾{Vhy$]#OKD]J%iUֹL&h4sx/=^cbKZyfҾD'JQLθ+J0 S0Hj1ʸ PbV2zaMaeq\],l?=(PO8V1lof {x 4vs`P(< :? b߀$ z8A C8+7ks_ *` d^O<9I_tQ<;ịsE'V{;VIENDB`v_sim-3.8.0/pixmaps/stock-four-lights_20.png000066400000000000000000000022641370110300500207050ustar00rootroot00000000000000PNG  IHDR sBIT|dtEXtSoftwarewww.inkscape.org<FIDAT8[h\U\2d2iR4I/Ic1$6J/JX bЂ""B}iB-"5 VkKՖd2cK2Idf2s\9{ _En^sc[w̌8_KjB_6ñx]jc>BDO!%&w:k1t=x#f/_󓟭=]==ѶSկ*ԇc?h06x|SC mAv2hBkSY9r}j?9k`nUp ߼TZxet|wk^j47e@ۖ'RU,]O2^.`,Pd-u@JXz5b#Sa֡3/&'lh,\B pe.[滳nm(oGӧӪvf@Bi9eדZ]m̮[y^ї߹ghK B* AaկI)dq$a.kK e=hjy%]o6W*KSj dBxf)Y86"]ɥ*L%*A%:AJ`nh@2,GP@WePW9^ȯH8_ɜaر2 BCTB%bEQ@ @F>rl|PD ŷV @>_ꫫ ՗MRU<&bG`٤\_~|ac]ځNF䦐鲛 f't*dUVMphn}a5fY)=ď474v,pGAt&T<,@1g,ۻ50m럕UQ(:iMA|T0]#LƆϿHUiE" ;i?}Pwlu\\=ǟ\?2TǮ'o?RUvXMe ?C;'tp<~cr8 gS)3+aKpmj>P2&"3|hg@Kؖfޓ 5It:pIENDB`v_sim-3.8.0/pixmaps/stock-geometry_20.png000066400000000000000000000017221370110300500202730ustar00rootroot00000000000000PNG  IHDR sRGBbKGD pHYs  tIME .>0tEXtCommentCreated with The GIMPd%n)IDAT8˭mhSW^5ִ6Z&mRŶT* ,H'EEi(͗/P`E[$[0El(Z51!1/t?9GL>#pM.cadL.1BAFId:ښB jj0 +68]H$mpLȊB!*|5w+IPA2 L;x^Eu:W"#=v"xof,#2xԗ/!yzW.?4mYxeKpOlJ 0M4Ym>yG8~s)_ ;m{XQh/g/]eÁ$|$^S ,Dr>[̷e5~w6EAss;hzNNj@tŽNʂ㱴l,Mg*@©޴B"nkld AEXY`CIW ʪW3eJڮ](h`PӶ̻+ R nfa $q4]GUGMMM{Ҹӷ̴&.doӦOfCuo7n& ;E?}“Ǐevh/pձk$! x-X |CTyoσTUREԆ-穗0H&s {z ͛dž}Yc>0tEE$Z-o֕\؜fl> "IENDB`v_sim-3.8.0/pixmaps/stock-go-and-back.png000066400000000000000000000011241370110300500201760ustar00rootroot00000000000000PNG  IHDR$sBIT|dtEXtSoftwarewww.inkscape.org<IDAT8kA?owմ11)*/RC-VPŢ(\~7%-U(tXTr⛡^-"l BWA_hLԪ;-ȉX6%3ߟO}}~iUVxaQ`1K@5D.C@Pt. IJS=+3|IENDB`v_sim-3.8.0/pixmaps/stock-go-once.png000066400000000000000000000007631370110300500174720ustar00rootroot00000000000000PNG  IHDR kT2sBIT|d pHYs~~*tEXtSoftwarewww.inkscape.org<pIDAT(;Q᧦{pp`4 3/0.,ʎ" F}c=438Łs*EJɬQmIPDa{޳,-]\MӯuN;x#ڄ #:)%reve#8G)+&r= .̥oa/> wy*l ml9>Ve*MM!h/qkUYp""1y,aUYH)nR]?΃nvuaG \!#MB+8mgag{f˷z8^Ob>//cE2NChQIENDB`v_sim-3.8.0/pixmaps/stock-inter.png000066400000000000000000000012051370110300500172540ustar00rootroot00000000000000PNG  IHDR;֕JsBIT|dtEXtSoftwarewww.inkscape.org<IDAT(uOHTQ͛{DZqw̌BBi6"ʊ\*ERmZ&Dj!(DP ?TٿI\gۢgS~m9{Xk|FJ(p M~`zxU}`u`)Z+QJk%J,…VbV⚵px\ g;v>#|gcu-^AhU 4/LYTiZ콝,RIwI@$FG+qufYK42Jsh( ˁ{*{I`3p7z {:)# 3^ IENDB`v_sim-3.8.0/pixmaps/stock-isosurfaces_20.png000066400000000000000000000021761370110300500207720ustar00rootroot00000000000000PNG  IHDR bKGD pHYs9rtIME 0I9 IDAT8˭MlTU{޹vfGmK4& !hB.LD" 7+]1#&* B@i m{萌Յ ۜ㵄B/ BLJ] )P>Rfnf&Sݱ#\jr^JeA>5@܄/:EJT\7fׯ15Rno/ 0Zu!tdZݳg?jWC =%{w_өS^7snF)TtuJ$k[ tǏܥTZ o~3 P^Y]{;IuR@ ["\^i"h9]ȅև.j%ワ QCvZF۲[y^œM$d~|pGY9a!";\i:'FcccowvvfQpthjxQũS=>Vw)J!^T/pߘYF%4vB8wu^t'J&4|t>;bX6f@飣TX(M3xxzn < ۷?mەX,Vlii!7Ͳg57wXպo_O 0|07M2-HӍP=7aXXtu ߭T$_f UڤK Ujڗ ?"OJmJ?3"gCajH9@W !63߂@p2֠IM=^Z ͶhKYZoX. x#ݕW߃utIENDB`v_sim-3.8.0/pixmaps/stock-map_20.png000066400000000000000000000016411370110300500172150ustar00rootroot00000000000000PNG  IHDR bKGD pHYs9rtIME 3tEXtCommentCreated with The GIMPd%nIDAT8˭Mluvپ`[j)hQLJ⡞1LO$&o荘ٓ"MT"j$@Z"m}$d= 7<+ iCh >feTQC FR6t 0J5:VYq#$ D)@욿P}؋W+.SF&PP/}Кcu5n$ ]Uc:Dг\(p:I 8);Z]1Iz>奚iN0刉FRBfLjC:J;^ l!o ˱қta~+POp2}EaꑚA3N=[xٜI'F`#fpk-EnNVR3@ԑ"alf hؙ&ZEIՈ+b%DK($_h|QKhE!QD{Lof`EIj\3qrȘx't̯{\ =Lwk/W;wGPU s;u`oVH+{e&֗uswj4 #s+ڝxs]{dҪp h.dBq]S[f^zƤ6猺kZ,]~͌I[XhS,` u3q6Qۧ zԿr.IENDB`v_sim-3.8.0/pixmaps/stock-masking.png000066400000000000000000000013141370110300500175650ustar00rootroot00000000000000PNG  IHDR "asBIT|d pHYsC5.tEXtSoftwarewww.inkscape.org<IIDAT(eRKTa=7ߛǠ3fI1j8J4ƕ 7AA.J!VSDQ.22B7=7w[L݅sÈ B3>9c7 #YADQUӴ3M/F/W`4KiNCeܹ] Մ(gr"`a/I1"q˚ Oc⭅0 %\,\U5{7l!h9@JHoeolօt7Ζ;p~"ZTF?mLHUhf'O{Ϸ;;?/$v @W׹i?ͫ7i"JT*50r*]7"KK~]XeEQz]=MDmaIsRIENDB`v_sim-3.8.0/pixmaps/stock-menu-detach.png000066400000000000000000000004201370110300500203230ustar00rootroot00000000000000PNG  IHDR bKGD pHYs.#.#x?vtIME *;oIym\֤/[u0[ t t* C 링WbEutnTADvÕh'f6m׼i$%]RDw ճ8EKuCxUl "+, B'I`%dst)Qb Xh L%q[ÄU=}3q覉EBBa.ro :ޅ}}}BFJh..K K2j!^`(F3&dp{{YMCDD@L9E0=QCx"ưdwҗ1 @v/E/Z)<@C\("{CNk~tis?K{mg[g]knWgZlcJ?% R-UK:MCIGT`<0D&+Ul7\}WS7 4r;$Zł(}D$|]7e[P: sgb:<EOJ6:Qf瓣yɡ@vk4R^yWfL@ 1#;8HCbB]+u2@Z8:W ͭĮzm X6 `- OֱclӾvIY29L`U[pnS\> [m kМL+ЈI^5dOž6|>~+ 7u=Re0y;''߻& 0f|4s4Q n5֓K"|&4'Sbr>&R҈/Fl(7?gvW)E =-9mn[d4GYp,h Kf_OCn0dJQ Az.Ǡz 1,X0W)PIjIENDB`v_sim-3.8.0/pixmaps/stock-one-light_20.png000066400000000000000000000017461370110300500203340ustar00rootroot00000000000000PNG  IHDRfsBIT|dtEXtSoftwarewww.inkscape.org<xIDAT8]h\Eg&wofRHCAR`-/5AD,R">O("m bl-Rih6Yɶ7{{|jҚM 3?s3Wwvҹe ̌ܠ(Z㑇sphwBmݭF\7pk@[bUץ'3[4榭Cwߦc/7˗+8~*un}}/a" @y[oRr|]{oz;_r_#Y Q<>zM(.L]}pX\y$B[7&u j~0 @B?6 OW- +>HJͯ>c{¾`gh xA]BD-U/Í`#(78zhpG[]Z@,eFm (PlE- L׻)KAE\4AdddrIf_ _r0؅o2 sU*/hc*B|M A(\6TIDkny|=ɡNHJGHhAבNxVY-F '"ER$DrKE[rУa }t?tq"*d*_^ ^.˲X)R(+*âbEX;~4vfέ.a[H^A#%3 |rˢ%t\mKYRKv|p-0܊ %˳!se3SsSWsnM6"zHz~aɋ:e$}"֬U{>N_[w IENDB`v_sim-3.8.0/pixmaps/stock-opengl_20.png000066400000000000000000000015061370110300500177240ustar00rootroot00000000000000PNG  IHDR bKGD pHYs  tIME 57tEXtCommentCreated with The GIMPd%nIDAT8MhSA}/FkѦm@DAc "R%)"Z=( TP(CQOh5VkR i|O;; >Hw⿁ـ60m)e] ~BP($u]pXj&UU>7tt]jڹq±ds#k$ s@Hڀ;e ^.˗pff)7U[$Mig\[}(]S,))B ʁ@w^L6}ruE*0؛H7a^C@+V y&M/bˇXf˜\,h ΃I`z}ޛm?V#`}uLguE4V<@->Zƃ?CyI]o`Rx@p2pV-*6h4t?{֚E/ߴO1zg]=ڴ[w@Kmu^dg,vyj TKV~4M 4Mu])YUU|ǽ~;&^ӃjhmF" H088 d(IRS6'9^毫Wj؎ /UUeyy1’DEdYF.\m2I$ЪUX A$ Qfnnjm"@<]]]E6m4MjDE<$033lu (*J8it]G4DQ =,/?l"jAIENDB`v_sim-3.8.0/pixmaps/stock-planes_20.png000066400000000000000000000022721370110300500177230ustar00rootroot00000000000000PNG  IHDR bKGD pHYs9rtIME !oyIGIDAT8˭KlTe3v.L;0#R0-^uax!q l+  ,k B/3tkOϜ`Zk;Ϳ _+Vz:CsKα/ [SZBS*syRš  k4F mݶ\=Xm_z]koݻ^3R,wún(|)ض'-S)[yT/>D!gCtV3!3&S;@-#}~|Ծ8{Γwh㶡,;(%FP&nVRIrXhlNs51DYoKJ:7]%5JiOMa۵Ht:ÐOҡS\sYV4|`͉8sc|^Ӯ&TBfD_' bXأNDO`w5l/R7X.]9{/)[dgA^(g`8ge1ʛ7BnY2Y*w0 |e!#[{ > Hݲ$'pN},!g2с~kiRp' Nlo|(V^<,ձ}گD[G. u^b kWc @Xf AФR0EaoGGc#qM ٿ74Jm'<ݵ蘱<NOj3|uL=p4dc͉ľ)){! Hz*my+:L taM(bf':)@˙e"y=m40۟O*!)N,n'f 4 (u"w~C{ J4]rxxّ'm%# /*@ng>=\ԩDV;>*k:9jYYQH`,`= 5g;Pceϓ L]ȔYR4D\*Z/JwpAsX? Ul h@tIENDB`v_sim-3.8.0/pixmaps/stock-select-all_20.png000066400000000000000000000017201370110300500204630ustar00rootroot00000000000000PNG  IHDR sBIT|dtEXtSoftwarewww.inkscape.org<bIDAT8YLTg3ۙ0SQQ:ZКFbk&F[qF.\ mZhӤMШ!.h*KȰ ,ъ{[5+nfpҲ w6c4ǃ0 ?-}"6J|9?>Qe`dF0<"2&gyn{Lo##whbzHDKۇR? /k +-;[=:M=ѐ oBr7IK{?ҒШXSpO4\["FZZZG!LPXHe'.K.0ggtr<fͨkle'k_o\n[T.fzlWowxB0 ym$syt_Қ LVhߵ*Uө3}b; {C_G?6- כ E]#tToMYQ(VQ| hchǩkz"HXI{T?4$SXx hM&զh9v`מ`fn:mVzBE .wK@'i߻^zmOnrZbLg/pF2|$gr// z EOޘ$XՁ2sޢEuj+N3Ή+rB:8u,rM*-6"vz ?n󢲡\Eeտu0o+<MtQ\oêWnbɛXV]^[Q݀Շ@0iF1Q0-Ɉ<0jjv #q͞lۺ6UB^W{.{C1bIENDB`v_sim-3.8.0/pixmaps/stock-spin.png000066400000000000000000000010071370110300500171040ustar00rootroot00000000000000PNG  IHDRabKGD pHYs  :ݙtIME'8uݚtEXtCommentCreated with The GIMPd%nkIDAT8œ=K\QuDwՕY4ܟ`R,IAK,BX(F1Ecޙyy}o*ll3~} Zb5syb槝;{c5uo@Wv*>huN-晳<@{HAVɏl~ < >"H( !-:#=!`\*hhD*0F<F2? 9nl}(vs;g('3 ֶ$,̄:^3Z /ʬ 0e:MۺnNܽe]Ȣ9;E\)vb-94OW_W$(L[1޸|*:42G3[T|P}( s1o\yvi}53dU/-m]7cdwtOj2] f<11N`jG ܴ^YUBzOFݜH'whx~I I.ҵV%.{[7y4<6I$U,,m~)JK{ =Y{r^&+oJJJ,(DQYr_t@y'ۚC^[6k-ݖnKIkn[@'''G7͊;Y& ޭ3?]zQ x`@AAw<!rJ(|3Qj0 T SI=n Du9+=Ut tkDiTMkU!P&Vzjfճ3(oos/QJZnUWAoSP񂼨{ Σ1?m^IENDB`v_sim-3.8.0/pixmaps/stock_effects-object-colorize_20.png000066400000000000000000000007771370110300500232420ustar00rootroot00000000000000PNG  IHDR bKGD pHYs  tIME uIDAT8˭M/Q[JذXV"V XZFT"DPL0smnNGoo9#]*5@U=Ut("TE ESVùYB>0L_Hn, F@%% Y Gv8k|\1v 6pl1bX6 `:ʘ+,Td8a~+.Zt\DtKX:MQY v۶*S:W) _=c՞=*Qw*br89FUJ"?EFc,n=N27lR+~ %s-׌Cyw^9: W?mdޠQ L ڐ-|ʹIENDB`v_sim-3.8.0/pixmaps/stock_media-play.png000066400000000000000000000005761370110300500202510ustar00rootroot00000000000000PNG  IHDRw=gAMA abKGDC pHYs  ~tIME!%9XxIDATxA.QzӼX !Lwp $CvBf9[W_UŘa6af͢IZ!fbbҍaý 1"4G:%7nFbIENDB`v_sim-3.8.0/pixmaps/stock_rotate_20.png000066400000000000000000000023751370110300500200250ustar00rootroot00000000000000PNG  IHDR sBIT|dtEXtSoftwarewww.inkscape.org<IDAT8H[W{h_b|R\ mkč MXϔBeG0*J@mL/3!X $1gIhj~X\\9{=@5^;7oD ^>>>Fr:!Lv? !=b0],..2 3ɓ ̷Tfbff&gmm6B<66ȕ#7lsccc._lsFz/N %BQ`6Ej" N.ǃ  J3[ZZ>i$O$&i.p8Bي+u ǿ|>`0|U{ JEjo1 !G\rEyܹ/H+q<ͥ^DVUUm Bx!}bbBD$zp_yC`pp0+--;{fQQQ$eM 8.D-P*hmm###₂NNN~jwJKKC?&u~T&s\@ HEQ-K 8T*c 7Vog~!n[@d"eddcVF`jll$SBZӚWp[ZZry<$cZI)\^^NaY6!NsgggsLNMŗ&)MmJ$x8Qwxx:ţG##Bj 4Mju̙3~Hܹ1x엺\H#N"9DDqJ0Y>o$4b1lj8XJBeYVQ^ ˲q\.'eJh4?FcleeeD"dccBC4LƇFQ 0whIENDB`v_sim-3.8.0/pixmaps/v_sim.svg000077700000000000000000000000001370110300500210602logo/logo-2.3.svgustar00rootroot00000000000000v_sim-3.8.0/pixmaps/v_sim.xpm000066400000000000000000000233451370110300500161600ustar00rootroot00000000000000/* XPM */ static char * v_sim_xpm[] = { "32 32 483 2", " c None", ". c #1C0000", "+ c #220101", "@ c #130A0A", "# c #312929", "$ c #817070", "% c #978383", "& c #857676", "* c #000000", "= c #1D0000", "- c #350404", "; c #620909", "> c #850B0B", ", c #864141", "' c #010000", ") c #2B2727", "! c #C8B7B7", "~ c #D1C2C2", "{ c #D5CCCC", "] c #BEAEAE", "^ c #8A7B7B", "/ c #190000", "( c #3D0505", "_ c #8B1414", ": c #9D2D2D", "< c #AE3E3F", "[ c #A96F70", "} c #B99B9B", "| c #4A3F3F", "1 c #817575", "2 c #CBBBBB", "3 c #D2C7C7", "4 c #DBD3D3", "5 c #E5DFDF", "6 c #C9BCBC", "7 c #200202", "8 c #700A0A", "9 c #A02D2D", "0 c #CE5E5F", "a c #DD6969", "b c #B76F70", "c c #B38F8F", "d c #B69696", "e c #A98F8F", "f c #0A0809", "g c #151212", "h c #C4B3B3", "i c #D3C4C4", "j c #D6CBCB", "k c #DED7D7", "l c #EAE4E4", "m c #EDE8E8", "n c #9F9090", "o c #260101", "p c #8E1515", "q c #C94F4F", "r c #DC6969", "s c #D66566", "t c #BD6262", "u c #AD7475", "v c #E16D6D", "w c #D7696A", "x c #C16465", "y c #665656", "z c #605757", "A c #D0BEBE", "B c #D6C8C8", "C c #DCD0D0", "D c #E1DBDB", "E c #ECE8E8", "F c #F6F3F3", "G c #AB9B9B", "H c #220202", "I c #871111", "J c #D96061", "K c #DD696A", "L c #E76F6F", "M c #DF6A6B", "N c #AC7373", "O c #AD7171", "P c #B96969", "Q c #BB686A", "R c #B27474", "S c #B39596", "T c #1B1717", "U c #060505", "V c #B0A0A0", "W c #D1C0C1", "X c #D8CBCB", "Y c #DFD4D4", "Z c #EFECEC", "` c #F8F6F6", " . c #998A8A", ".. c #770B0B", "+. c #CE4C4C", "@. c #DA6869", "#. c #DE696A", "$. c #DA6868", "%. c #BA6565", "&. c #B86363", "*. c #C46262", "=. c #BA6667", "-. c #B26D6D", ";. c #AE8787", ">. c #B49394", ",. c #816C6C", "'. c #3E3838", "). c #CCBABA", "!. c #DACDCD", "~. c #E1D7D7", "{. c #E8E3E3", "]. c #F3F0F0", "^. c #F3EFEF", "/. c #070707", "(. c #440505", "_. c #A82A2A", ":. c #E76E6E", "<. c #EC7172", "[. c #EB7071", "}. c #A56666", "|. c #F06D6D", "1. c #F47576", "2. c #EA7374", "3. c #DD6C6E", "4. c #A98282", "5. c #B18E8E", "6. c #B59595", "7. c #332B2B", "8. c #928383", "9. c #CEBDBD", "0. c #D5C6C6", "a. c #DCCFCF", "b. c #AB8A8A", "c. c #764343", "d. c #210303", "e. c #230101", "f. c #901111", "g. c #E66666", "h. c #D76666", "i. c #E16C6D", "j. c #E06B6C", "k. c #CE6868", "l. c #A66666", "m. c #C85E5E", "n. c #CA6060", "o. c #CB6263", "p. c #C06162", "q. c #A77778", "r. c #BD5E5F", "s. c #B75B5C", "t. c #A84F50", "u. c #651D1E", "v. c #211D1D", "w. c #C6B3B3", "x. c #CFBEBF", "y. c #782121", "z. c #510E0F", "A. c #6B0C0C", "B. c #080202", "C. c #400505", "D. c #A62727", "E. c #E96D6D", "F. c #F57575", "G. c #F07374", "H. c #E86E6F", "I. c #C96161", "J. c #C96566", "K. c #C06565", "L. c #B96567", "M. c #AE6565", "N. c #A67A7B", "O. c #AA6B6D", "P. c #CA5F61", "Q. c #C05758", "R. c #B54B4C", "S. c #9A3536", "T. c #6F6262", "U. c #C8B3B3", "V. c #CFBEBE", "W. c #D8CACA", "X. c #713737", "Y. c #4F0B0C", "Z. c #2C0505", "`. c #665959", " + c #6C0909", ".+ c #A13132", "++ c #E26B6C", "@+ c #D96567", "#+ c #C25D5F", "$+ c #A67879", "%+ c #A56E6F", "&+ c #AF6162", "*+ c #AB6565", "=+ c #A96668", "-+ c #9E6263", ";+ c #0C0A0A", ">+ c #0D0B0B", ",+ c #B39E9E", "'+ c #CBB7B7", ")+ c #B2A5A5", "!+ c #040404", "~+ c #262626", "{+ c #E5DDDD", "]+ c #2C0303", "^+ c #7C0C0D", "/+ c #C24848", "(+ c #E66B6B", "_+ c #E26C6D", ":+ c #D76667", "<+ c #E56E6E", "[+ c #BD5E60", "}+ c #A36B6C", "|+ c #AB6163", "1+ c #A96363", "2+ c #A86465", "3+ c #9A5959", "4+ c #975757", "5+ c #634D4D", "6+ c #4E4444", "7+ c #C5B0B0", "8+ c #3A3535", "9+ c #A5A2A2", "0+ c #F0ECEC", "a+ c #3B0404", "b+ c #730C0D", "c+ c #E06262", "d+ c #F97575", "e+ c #D96667", "f+ c #D56566", "g+ c #D06363", "h+ c #CD5F61", "i+ c #B15B5C", "j+ c #AC5F60", "k+ c #D46768", "l+ c #C65A5B", "m+ c #9F2B2B", "n+ c #941B1B", "o+ c #941C1C", "p+ c #9D7878", "q+ c #461313", "r+ c #5D0909", "s+ c #650A0A", "t+ c #852020", "u+ c #600A0A", "v+ c #413D3D", "w+ c #DCD6D6", "x+ c #968585", "y+ c #490707", "z+ c #760C0D", "A+ c #DB6161", "B+ c #B55E60", "C+ c #B35C5C", "D+ c #C85859", "E+ c #982121", "F+ c #931A1A", "G+ c #931B1B", "H+ c #976E6E", "I+ c #823737", "J+ c #7F0D0D", "K+ c #7C0D0D", "L+ c #030202", "M+ c #B5A8A8", "N+ c #D5CECE", "O+ c #E2DBDB", "P+ c #A39090", "Q+ c #4D0707", "R+ c #6E0D0E", "S+ c #D55656", "T+ c #EA6E6E", "U+ c #E66E6E", "V+ c #D46465", "W+ c #AF5E5F", "X+ c #9C5252", "Y+ c #8A3333", "Z+ c #893636", "`+ c #8B3B3B", " @ c #8D4040", ".@ c #8F4545", "+@ c #976B6B", "@@ c #974B4B", "#@ c #861212", "$@ c #790C0C", "%@ c #510808", "&@ c #594B4B", "*@ c #CBBABA", "=@ c #CEC6C6", "-@ c #DAD2D2", ";@ c #AA9696", ">@ c #460606", ",@ c #600B0C", "'@ c #C64848", ")@ c #DB6768", "!@ c #DB6969", "~@ c #C65859", "{@ c #8A292A", "]@ c #822525", "^@ c #832828", "/@ c #852D2D", "(@ c #873131", "_@ c #893333", ":@ c #8D5151", "<@ c #9A6D6D", "[@ c #986868", "}@ c #875F5F", "|@ c #040303", "1@ c #110E0E", "2@ c #B59E9E", "3@ c #C7BEBE", "4@ c #D4CACA", "5@ c #988282", "6@ c #440606", "7@ c #610B0C", "8@ c #9A2C2C", "9@ c #C84F4F", "0@ c #981616", "a@ c #8A0E0E", "b@ c #930F0F", "c@ c #893E3E", "d@ c #966767", "e@ c #9C7070", "f@ c #9F7878", "g@ c #715353", "h@ c #4C2B2B", "i@ c #8B6363", "j@ c #BBA1A1", "k@ c #BDABAB", "l@ c #C1B6B6", "m@ c #CEC2C3", "n@ c #7A6464", "o@ c #6F0D0D", "p@ c #751010", "q@ c #E56767", "r@ c #E86F6F", "s@ c #D26364", "t@ c #DA6162", "u@ c #B33535", "v@ c #883939", "w@ c #8C4040", "x@ c #922828", "y@ c #931F1F", "z@ c #951D1D", "A@ c #961F1F", "B@ c #9C4D4D", "C@ c #B69999", "D@ c #B5A4A4", "E@ c #BAAEAE", "F@ c #C8BABA", "G@ c #240202", "H@ c #7B0C0C", "I@ c #610C0D", "J@ c #C44040", "K@ c #F47474", "L@ c #D75758", "M@ c #A42B2B", "N@ c #8D0E0E", "O@ c #8B0E0E", "P@ c #830D0D", "Q@ c #833333", "R@ c #8E3030", "S@ c #941D1D", "T@ c #951E1E", "U@ c #9A4F4F", "V@ c #B19393", "W@ c #AD9C9D", "X@ c #A69191", "Y@ c #BEB2B2", "Z@ c #610808", "`@ c #490A0B", " # c #801011", ".# c #9D1D1D", "+# c #853333", "@# c #8C2A2A", "## c #912121", "$# c #902C2C", "%# c #933B3B", "&# c #954B4B", "*# c #965858", "=# c #7F3333", "-# c #832627", ";# c #7D393A", "># c #967F7F", ",# c #380404", "'# c #6E0B0C", ")# c #590D0F", "!# c #820D0D", "~# c #8E0E0E", "{# c #864D4D", "]# c #884C4C", "^# c #8A4747", "/# c #8D4242", "(# c #915555", "_# c #803C3C", ":# c #500F10", "<# c #681416", "[# c #895758", "}# c #620808", "|# c #570B0C", "1# c #700E0F", "2# c #900E0E", "3# c #811010", "4# c #910E0E", "5# c #8D4949", "6# c #542D2D", "7# c #703B3C", "8# c #865C5C", "9# c #854B4B", "0# c #320404", "a# c #780909", "b# c #4D0C0D", "c# c #770E0E", "d# c #850D0D", "e# c #734142", "f# c #6C3C3D", "g# c #602223", "h# c #724545", "i# c #360303", "j# c #6F0C0C", "k# c #4F0D0F", "l# c #660D0D", "m# c #840D0D", "n# c #8C0E0E", "o# c #800E0F", "p# c #5F0E10", "q# c #5C0E10", "r# c #560F0F", "s# c #651616", "t# c #2F1A1A", "u# c #680B0C", "v# c #4C0C0E", "w# c #540D0D", "x# c #830F0F", "y# c #920E0E", "z# c #910F0F", "A# c #781011", "B# c #611012", "C# c #530D0E", "D# c #530E0E", "E# c #370404", "F# c #7D0A0A", "G# c #540B0D", "H# c #4B0C0D", "I# c #600E0F", "J# c #740E0F", "K# c #820E0E", "L# c #870E0E", "M# c #7D0E0F", "N# c #6F0E0F", "O# c #690E0F", "P# c #5E0F11", "Q# c #570E10", "R# c #4F0D0E", "S# c #5B0C0D", "T# c #1D0101", "U# c #2D0303", "V# c #650909", "W# c #610C0C", "X# c #4B0B0D", "Y# c #560E0F", "Z# c #530E0F", "`# c #5D0F10", " $ c #5C0F11", ".$ c #550E0F", "+$ c #580E0F", "@$ c #4F0C0D", "#$ c #630B0C", "$$ c #490606", "%$ c #550707", "&$ c #68090A", "*$ c #580B0D", "=$ c #4C0C0D", "-$ c #4D0D0E", ";$ c #4E0D0E", ">$ c #4E0C0D", ",$ c #5C0C0D", "'$ c #600909", ")$ c #410505", "!$ c #270303", "~$ c #230202", "{$ c #3D0404", "]$ c #400303", "^$ c #420505", "/$ c #3E0404", "($ c #320303", " ", " . + @ # $ % & * * ", " = - ; > , ' * ) ! ~ { ] ^ * * * ", " / ( _ : < [ } | * * 1 2 3 4 5 6 * * * ", " 7 8 9 0 a b c d e f * g h i j k l m n * * * ", " o p q r s t u v w x y * * z A B C D E F G * * * ", " H I J K L M N O P Q R S T * U V W X Y 5 Z ` . * * * ", " = ..+.@.#.$.%.&.*.=.-.;.>.,.* * '.).i !.~.{.].^./.* * ", " (._.:.<.[.L }.|.1.2.3.4.5.6.7.* * 8.9.0.a.C b.c.d.* * ", " e.f.g.h.i.j.k.l.m.n.o.p.q.r.s.t.u.* v.w.x.B i y.z.A.B. ", " C.D.E.F.G.H.I.J.K.L.M.N.O.P.Q.R.S.* * T.U.V.W.X.Y.Z.`. ", " +.+E.F.G.[.$.++a @+#+$+%+&+*+=+-+;+* >+,+'+)+!+* ~+{+ ", "]+^+/+(+:._+:+<+++a @+[+}+|+1+2+3+4+5+* * 6+7+8+* * 9+0+ ", "a+b+c+d+F.G.e+$.f+g+h+i+j+k+l+m+n+o+p+q+r+s+t+u+* v+w+{.x+ ", "y+z+A+d+F.G.#.L ++a @+B+C+D+E+F+G+o+H+I+J+J+J+K+L+M+N+O+P+ ", "Q+R+S+T+U+i.V+U+++a @+W+X+Y+Z+`+ @.@+@@@#@$@s+%@&@*@=@-@;@ ", ">@,@'@d+F.G.)@!@f+g+~@{@]@^@/@(@_@:@<@[@}@|@* 1@2@h 3@4@5@ ", "6@7@8@d+F.G.#.L ++9@0@a@b@b@b@b@b@c@d@e@f@g@h@i@j@k@l@m@n@ ", "( o@p@q@r@_+s@t@u@b@b@a@b@b@b@b@b@v@w@x@y@z@A@B@C@D@E@F@ ", "G@H@I@J@K@L@M@N@O@O@O@P@a@a@a@a@a@Q@R@F+n+S@T@U@V@W@X@Y@ ", " Z@`@ #.#b@a@b@b@b@b@a@b@b@b@b@b@+#@###$#%#&#*#=#-#;#># ", " ,#'#)#O@a@!#a@a@~#b@a@b@b@b@b@b@Q@{#]#^#/#(#_#:#<#[# ", " }#|#1#b@a@b@b@2#a@!#a@a@a@a@a@3#a@4#b@b@5#6#7#8#9# ", " 0#a#b#c#d#b@b@b@b@a@b@b@b@b@b@a@b@b@b@N@e#f#g#h# ", " i#j#k#l#!#a@a@a@!#a@a@a@a@a@m#n#n#o#p#q#r#s#t# ", " C.u#v#w#x#b@b@2#N@b@b@b@y#n#z#A#B#C#D#u+= ", " E#F#G#H#I#J#K#J+a@L#M#N#O#P#Q#R#S#; T# ", " U#V#W#X#R#Y#Z#`# $ $.$+$Z#@$#$$$ ", " ( %$&$*$=$=$-$;$>$,$'$)$!$ ", " ~$E#{$]$^$)$/$($ ", " ", " "}; v_sim-3.8.0/po/000077500000000000000000000000001370110300500132435ustar00rootroot00000000000000v_sim-3.8.0/po/ChangeLog000066400000000000000000000000001370110300500150030ustar00rootroot00000000000000v_sim-3.8.0/po/LINGUAS000066400000000000000000000000031370110300500142610ustar00rootroot00000000000000fr v_sim-3.8.0/po/POTFILES.in000066400000000000000000000323241370110300500150240ustar00rootroot00000000000000src/gtk_pick.h src/visu_pairset.c src/visu_dataloader.c src/opengl.h src/loaders/atomic_d3.c src/loaders/atomic_xyz.c src/loaders/atomic_yaml.c src/loaders/atomic_ascii.h src/loaders/atomic_yaml.h src/loaders/atomic_ascii.c src/loaders/atomic_d3.h src/loaders/atomic_xyz.h src/iface_boxed.c src/visu_main.c src/visu_gtk.h src/uiElements/ui_selection.c src/uiElements/ui_boxTransform.c src/uiElements/ui_scale.c src/uiElements/ui_pairtree.c src/uiElements/ui_link.c src/uiElements/ui_atomic.h src/uiElements/ui_elements.c src/uiElements/ui_scale.h src/uiElements/ui_pairtree.h src/uiElements/ui_spin.h src/uiElements/ui_atomic.c src/uiElements/ui_properties.h src/uiElements/ui_spin.c src/uiElements/ui_axes.h src/uiElements/ui_link.h src/uiElements/ui_box.c src/uiElements/ui_axes.c src/uiElements/ui_planetree.c src/uiElements/ui_planetree.h src/uiElements/ui_elements.h src/uiElements/ui_selection.h src/uiElements/ui_box.h src/uiElements/ui_boxTransform.h src/uiElements/ui_properties.c src/visu_pairset.h src/renderingBackend/visu_actionInterface.h src/renderingBackend/visu_action_gdk.c src/renderingBackend/visu_windowX11.c src/gtk_save.c src/visu_nodes.c src/visu_animation.h src/visu_basic.c src/interface.h src/gtk_renderingWindowWidget.h src/iface_pointset.h src/gtk_move.h src/visu_elements.c src/visu_glnodescene.c src/visu_dataloadable.h src/gtk_pick.c src/visu_test.c src/visu_animation.c src/gtk_openGLWidget.c src/gtk_renderingWindowWidget.c src/visu_pairs.h src/visu_nodes.h src/visu_basic.h src/visu_extension.c src/iface_nodemasker.c src/visu_data.h src/visu_extset.c src/visu_gtk.c src/visu_tools.c src/extraGtkFunctions/gtk_curveWidget.h src/extraGtkFunctions/gtk_lineObjectWidget.h src/extraGtkFunctions/gtk_dataChooser.c src/extraGtkFunctions/gtk_elementComboBox.c src/extraGtkFunctions/gtk_colorComboBoxWidget.h src/extraGtkFunctions/gtk_numericalEntryWidget.h src/extraGtkFunctions/gtk_shadeComboBoxWidget.h src/extraGtkFunctions/gtk_stippleComboBoxWidget.h src/extraGtkFunctions/gtk_orientationChooser.h src/extraGtkFunctions/gtk_toolPanelWidget.c src/extraGtkFunctions/gtk_colorComboBoxWidget.c src/extraGtkFunctions/gtk_dumpDialogWidget.c src/extraGtkFunctions/gtk_lineObjectWidget.c src/extraGtkFunctions/gtk_stippleComboBoxWidget.c src/extraGtkFunctions/gtk_curveWidget.c src/extraGtkFunctions/gtk_toolPanelWidget.h src/extraGtkFunctions/gtk_numericalEntryWidget.c src/extraGtkFunctions/gtk_fieldChooser.h src/extraGtkFunctions/gtk_dataChooser.h src/extraGtkFunctions/gtk_elementComboBox.h src/extraGtkFunctions/gtk_fieldChooser.c src/extraGtkFunctions/gtk_dumpDialogWidget.h src/extraGtkFunctions/gtk_valueIOWidget.h src/extraGtkFunctions/gtk_orientationChooser.c src/extraGtkFunctions/gtk_valueIOWidget.c src/extraGtkFunctions/gtk_shadeComboBoxWidget.c src/renderingMethods/iface_nodeArrayRenderer.h src/renderingMethods/elementAtomic.h src/renderingMethods/spinMethod.h src/renderingMethods/elementRenderer.h src/renderingMethods/elementRenderer.c src/renderingMethods/elementAtomic.c src/renderingMethods/spinMethod.c src/renderingMethods/elementSpin.h src/renderingMethods/elementSpin.c src/renderingMethods/iface_nodeArrayRenderer.c src/iface_nodemasker.h src/visu_extension.h src/visu_dataatomic.c src/visu_configFile.c src/visu_extset.h src/visu_configFile.h src/visu_dataspin.h src/extensions/mapset.c src/extensions/node_vectors.h src/extensions/box.h src/extensions/box_legend.c src/extensions/mapset.h src/extensions/fogAndBGColor.c src/extensions/box.c src/extensions/surfs.c src/extensions/paths.h src/extensions/forces.h src/extensions/maps.c src/extensions/infos.c src/extensions/infos.h src/extensions/geodiff.c src/extensions/legend.h src/extensions/legend.c src/extensions/scale.h src/extensions/iface_lined.h src/extensions/pairs.c src/extensions/nodes.h src/extensions/shade.c src/extensions/planes.c src/extensions/node_vectors.c src/extensions/axes.c src/extensions/box_legend.h src/extensions/pairs.h src/extensions/geodiff.h src/extensions/fogAndBGColor.h src/extensions/forces.c src/extensions/shade.h src/extensions/iface_lined.c src/extensions/axes.h src/extensions/maps.h src/extensions/paths.c src/extensions/nodes.c src/extensions/scale.c src/extensions/planes.h src/extensions/frame.h src/extensions/vibrations.h src/extensions/marks.c src/extensions/surfs.h src/extensions/vibrations.c src/extensions/rings.h src/extensions/frame.c src/extensions/marks.h src/extensions/rings.c src/dumpModules/fileDump.c src/dumpModules/dumpToSVG.c src/dumpModules/dumpToXyz.c src/dumpModules/dumpToYaml.c src/dumpModules/dumpToPsAndPdf.h src/dumpModules/externalDumpModules.h src/dumpModules/dumpToABINIT.h src/dumpModules/dumpToAscii.c src/dumpModules/dumpToTiff.c src/dumpModules/glDump.h src/dumpModules/dumpToPsAndPdf.c src/dumpModules/glDump.c src/dumpModules/dumpToXyz.h src/dumpModules/dumpToGif.h src/dumpModules/dumpToTiff.h src/dumpModules/dumpThroughGdkPixbuf.c src/dumpModules/dumpToSVG.h src/dumpModules/dumpToABINIT.c src/dumpModules/dumpThroughGdkPixbuf.h src/dumpModules/dumpToAscii.h src/dumpModules/dumpToGif.c src/dumpModules/fileDump.h src/dumpModules/dumpToYaml.h src/visu_elements.h src/visu_dataatomic.h src/visu_plugins.c src/iface_maskable.c src/visu_pairs.c src/visu_box.c src/visu_dump.c src/gtk_openGLWidget.h src/visu_dataloader.h src/gtk_pairs.h src/opengl.c src/OSOpenGL/visu_openGL.h src/OSOpenGL/visu_GLX.c src/OSOpenGL/visu_WGL.c src/OSOpenGL/visu_GtkGlExt.c src/visu_commandLine.c src/support.h src/iface_boxed.h src/coreTools/toolDbg.h src/coreTools/toolOptions.h src/coreTools/toolPhysic.c src/coreTools/toolShade.h src/coreTools/toolPool.h src/coreTools/toolArray.c src/coreTools/toolFileFormat.h src/coreTools/toolFortran.h src/coreTools/toolOptions.c src/coreTools/atoms_yaml.c src/coreTools/toolFiles.h src/coreTools/toolColor.h src/coreTools/toolColor.c src/coreTools/toolFiles.c src/coreTools/toolPhysic.h src/coreTools/toolShade.c src/coreTools/toolDbg.c src/coreTools/toolMatrix.h src/coreTools/toolMatrix.c src/coreTools/atoms_yaml.h src/coreTools/toolConfigFile.h src/coreTools/toolFileFormat.c src/coreTools/toolConfigFile.c src/coreTools/toolPool.c src/coreTools/toolFortran.c src/coreTools/toolArray.h src/visu_glnodescene.h src/iface_pointset.c src/gtk_main.c src/visu_plugins.h src/interface.c src/visu_data.c src/iface_animatable.h src/visu_tools.h src/gtk_save.h src/gtk_interactive.c src/visu_dataspin.c src/visu_box.h src/extraFunctions/fragProp.c src/extraFunctions/surfaces.c src/extraFunctions/nodeProp.c src/extraFunctions/sfieldbinary.h src/extraFunctions/pot2surf.h src/extraFunctions/vibration.h src/extraFunctions/scalarFieldSet.c src/extraFunctions/map.c src/extraFunctions/isoline.h src/extraFunctions/vectorProp.h src/extraFunctions/floatProp.c src/extraFunctions/mover.h src/extraFunctions/coordProp.c src/extraFunctions/gdiff.h src/extraFunctions/colorizer.h src/extraFunctions/scalarFieldSet.h src/extraFunctions/mover.c src/extraFunctions/pot2surf.c src/extraFunctions/floatProp.h src/extraFunctions/scalarFields.c src/extraFunctions/surfaces_tests.c src/extraFunctions/isoline.c src/extraFunctions/map.h src/extraFunctions/typeProp.h src/extraFunctions/surfaces_resources.c src/extraFunctions/plane.h src/extraFunctions/rotate.h src/extraFunctions/rotate.c src/extraFunctions/surfaces.h src/extraFunctions/colorizer.c src/extraFunctions/plane.c src/extraFunctions/idProp.h src/extraFunctions/scalarFields.h src/extraFunctions/planeset.c src/extraFunctions/geometry.c src/extraFunctions/dataFile.c src/extraFunctions/vectorProp.c src/extraFunctions/coordProp.h src/extraFunctions/vectColorizer.c src/extraFunctions/fragProp.h src/extraFunctions/surfaces_points.h src/extraFunctions/stringProp.c src/extraFunctions/shellProp.h src/extraFunctions/surfaces_resources.h src/extraFunctions/translate.c src/extraFunctions/neighbours.h src/extraFunctions/planeset.h src/extraFunctions/shellProp.c src/extraFunctions/finder.c src/extraFunctions/vibration.c src/extraFunctions/fragColorizer.h src/extraFunctions/vectColorizer.h src/extraFunctions/sfielddata.h src/extraFunctions/translate.h src/extraFunctions/neighbours.c src/extraFunctions/sfielddata.c src/extraFunctions/surfaces_points.c src/extraFunctions/idProp.c src/extraFunctions/gdiff.c src/extraFunctions/fragColorizer.c src/extraFunctions/typeProp.c src/extraFunctions/dataFile.h src/extraFunctions/geometry.h src/extraFunctions/finder.h src/extraFunctions/nodeProp.h src/extraFunctions/sfieldbinary.c src/extraFunctions/stringProp.h src/pairsModeling/iface_wire.h src/pairsModeling/iface_cylinder.h src/pairsModeling/link.c src/pairsModeling/linkRenderer.h src/pairsModeling/link.h src/pairsModeling/linkRenderer.c src/pairsModeling/iface_wire.c src/pairsModeling/iface_cylinder.c src/pairsModeling/cylinder_renderer.c src/pairsModeling/cylinder_renderer.h src/pairsModeling/wire_renderer.h src/pairsModeling/wire_renderer.c src/visu_dataloadable.c src/gtk_about.h src/gtk_main.h src/panelModules/panelOpenGL.c src/panelModules/panelVibration.h src/panelModules/panelAxes.c src/panelModules/panelElements.c src/panelModules/panelConfig.c src/panelModules/panelMap.c src/panelModules/panelMethod.h src/panelModules/panelGeometry.c src/panelModules/panelAxes.h src/panelModules/panelSurfacesTools.c src/panelModules/panelSurfaces.c src/panelModules/panelConfig.h src/panelModules/panelDataFile.c src/panelModules/externalModules.h src/panelModules/panelSurfaces.h src/panelModules/panelGeometry.h src/panelModules/panelPlanes.c src/panelModules/panelVibration.c src/panelModules/gtkSpin.h src/panelModules/gtkSpin.c src/panelModules/gtkAtomic.h src/panelModules/panelFogBgColor.h src/panelModules/panelSurfacesTools.h src/panelModules/panelBrowser.h src/panelModules/panelBrowser.c src/panelModules/panelMethod.c src/panelModules/panelPlanes.h src/panelModules/panelOpenGL.h src/panelModules/panelFogBgColor.c src/panelModules/panelDataFile.h src/panelModules/panelElements.h src/panelModules/panelMap.h src/panelModules/gtkAtomic.c src/gtk_interactive.h src/openGLFunctions/view.h src/openGLFunctions/renderingMode.c src/openGLFunctions/renderingMode.h src/openGLFunctions/text.h src/openGLFunctions/view.c src/openGLFunctions/interactive.c src/openGLFunctions/light.h src/openGLFunctions/interactive.h src/openGLFunctions/objectList.h src/openGLFunctions/objectList.c src/openGLFunctions/light.c src/openGLFunctions/text.c src/visu_dump.h src/gtk_move.c src/gtk_pairs.c src/support.c src/iface_animatable.c src/visu_commandLine.h src/gtk_about.c src/iface_maskable.h lib/plug-ins/nanoquanta-netcdf/nq-netcdf.cdl lib/plug-ins/nanoquanta-netcdf/nq_structure.h lib/plug-ins/nanoquanta-netcdf/nq_basic.c lib/plug-ins/nanoquanta-netcdf/nq_structure.c lib/plug-ins/nanoquanta-netcdf/nq_density.c lib/plug-ins/nanoquanta-netcdf/nq_basic.h lib/plug-ins/nanoquanta-netcdf/nq_density.h lib/plug-ins/msym/sym.h lib/plug-ins/msym/msym.c lib/plug-ins/msym/libmsym/libmsymConfigVersion.cmake.in lib/plug-ins/msym/libmsym/examples/msym_example.c lib/plug-ins/msym/libmsym/examples/example.h lib/plug-ins/msym/libmsym/examples/tex_character_table.c lib/plug-ins/msym/libmsym/examples/example.c lib/plug-ins/msym/libmsym/src/permutation.c lib/plug-ins/msym/libmsym/src/symmetry.h lib/plug-ins/msym/libmsym/src/basis_function.c lib/plug-ins/msym/libmsym/src/permutation.h lib/plug-ins/msym/libmsym/src/elements.h lib/plug-ins/msym/libmsym/src/equivalence_set.h lib/plug-ins/msym/libmsym/src/symop.c lib/plug-ins/msym/libmsym/src/symmetrize.c lib/plug-ins/msym/libmsym/src/elements.c lib/plug-ins/msym/libmsym/src/msym.h lib/plug-ins/msym/libmsym/src/context.c lib/plug-ins/msym/libmsym/src/rsh.h lib/plug-ins/msym/libmsym/src/character_table.h lib/plug-ins/msym/libmsym/src/debug.h lib/plug-ins/msym/libmsym/src/msym.c lib/plug-ins/msym/libmsym/src/msym_error.c lib/plug-ins/msym/libmsym/src/msym_error.h lib/plug-ins/msym/libmsym/src/point_group.c lib/plug-ins/msym/libmsym/src/symop.h lib/plug-ins/msym/libmsym/src/linalg.c lib/plug-ins/msym/libmsym/src/basis_function.h lib/plug-ins/msym/libmsym/src/debug.c lib/plug-ins/msym/libmsym/src/subspace.c lib/plug-ins/msym/libmsym/src/geometry.c lib/plug-ins/msym/libmsym/src/equivalence_set.c lib/plug-ins/msym/libmsym/src/character_table.c lib/plug-ins/msym/libmsym/src/linalg.h lib/plug-ins/msym/libmsym/src/symmetry.c lib/plug-ins/msym/libmsym/src/rsh.c lib/plug-ins/msym/libmsym/src/context.h lib/plug-ins/msym/libmsym/src/point_group.h lib/plug-ins/msym/libmsym/src/symmetrize.h lib/plug-ins/msym/libmsym/src/subspace.h lib/plug-ins/msym/libmsym/src/geometry.h lib/plug-ins/msym/libmsym/libmsymConfig.cmake.in lib/plug-ins/msym/sym.c lib/plug-ins/archives/archives.c lib/plug-ins/python-gi/pythongi.c lib/plug-ins/xsf/xsf.c lib/plug-ins/xsf/xsf.h lib/plug-ins/xsf/xsf_density.h lib/plug-ins/xsf/xsf_density.c lib/plug-ins/abinit/ab7_symmetry.h lib/plug-ins/abinit/ab_symmetry.h lib/plug-ins/abinit/abinit.h lib/plug-ins/abinit/abinit.c lib/plug-ins/abinit/ab7_base.c lib/plug-ins/abinit/ab7_base.h lib/plug-ins/abinit/ab7_symmetry.c lib/plug-ins/abinit/ab7_symmetry.fortran.h lib/plug-ins/abinit/abi_common.h lib/plug-ins/abinit/ab_symmetry.c lib/plug-ins/fpcrystal/fpcrystal.h lib/plug-ins/fpcrystal/fpcrystal.cpp lib/plug-ins/OpenBabel-wrapper/ob_basic.cpp lib/plug-ins/cube/h2o-dens.cube.bz2 lib/plug-ins/cube/cube.c lib/plug-ins/bigdft/bigdft.c lib/plug-ins/bigdft/bigdft_run.c lib/plug-ins/bigdft/bigdftplug.h lib/plug-ins/bigdft/bigdft_system.c lib/python/plane_py.c lib/python/plane_py.h lib/python/visu_py.c v_sim-3.8.0/po/POTFILES.skip000066400000000000000000000000261370110300500153560ustar00rootroot00000000000000src/glade/v_sim.glade v_sim-3.8.0/po/fr.po000066400000000000000000006167661370110300500142400ustar00rootroot00000000000000# translation of fr.po to Caliste Damien # This file is distributed under the same license as the PACKAGE package. # Copyright (C) YEAR THE PACKAGE'S COPYRIGHT HOLDER. # Caliste , 2006. # #, fuzzy msgid "" msgstr "" "Project-Id-Version: fr\n" "Report-Msgid-Bugs-To: \n" "POT-Creation-Date: 2020-07-07 15:41+0200\n" "PO-Revision-Date: 2011-06-10 12:39+0200\n" "Last-Translator: Damien Caliste \n" "Language-Team: \n" "Language: \n" "MIME-Version: 1.0\n" "Content-Type: text/plain; charset=UTF-8\n" "Content-Transfer-Encoding: 8bit\n" #: ../src/visu_pairset.c:653 ../src/renderingMethods/elementRenderer.c:815 #: ../src/renderingMethods/elementAtomic.c:976 #: ../src/renderingMethods/elementSpin.c:810 #, c-format msgid "'%s' wrong element name" msgstr "« %s » n'est pas un élément connu" #: ../src/visu_pairset.c:661 #, c-format msgid "2 elements should appear here but %d has been found" msgstr "2 éléments sont attendus ici mais %d ont été lus" #: ../src/visu_pairset.c:672 #, c-format msgid "'%s' wrong floating point value" msgstr "« %s » mauvaise valeur réelle" #: ../src/visu_pairset.c:680 #, c-format msgid "2 floating point values should appear here but %d has been found" msgstr "2 valeurs réelles sont attendues alors que %d ont été lues" #: ../src/visu_dataloader.c:238 msgid "Loading..." msgstr "Chargement…" #: ../src/loaders/atomic_d3.c:93 msgid "Native binary format" msgstr "Format binaire natif" #: ../src/loaders/atomic_d3.c:192 #, c-format msgid "unknwon peridicity flag '%s'" msgstr "périodicité « %s » inconnue" #: ../src/loaders/atomic_d3.c:298 msgid "wrong d3 syntax, awaiting Nat and Ntypes." msgstr "syntaxe d3 incorrecte, il manque Nat et Ntypes." #: ../src/loaders/atomic_d3.c:350 #, c-format msgid "wrong d3 syntax, sum of nattyp (%d) is not equal to nat (%d)\n" msgstr "syntaxe d3 incorrecte, la somme des nattyp (%d) est différente de nat (%d).\n" #: ../src/loaders/atomic_d3.c:445 #, c-format msgid "input file has no dataset number %d (%d have been read).\n" msgstr "" "le fichier d'entrée n'a pas de série de données numéro %d (alors que %d ont " "été lues).\n" #: ../src/loaders/atomic_xyz.c:103 msgid "'Element x y z' format" msgstr "Format du type « élément x y z »" #: ../src/loaders/atomic_xyz.c:260 #, c-format msgid "Wrong XYZ format, 'Atom X Y Z' awaited." msgstr "" "Mauvais format XYZ, le schéma par ligne est le suivant : « Atome X Y Z »." #: ../src/loaders/atomic_xyz.c:267 #, c-format msgid "Wrong XYZ + vibration format, 'Atom X Y Z vx vy vz' awaited." msgstr "" "Mauvais format XYZ + vibration, le schéma par ligne est le suivant : « Atome " "X Y Z vx vy vz »." #: ../src/loaders/atomic_xyz.c:324 #, c-format msgid "Missing forces (%d read but %d declared).\n" msgstr "Forces manquantes (%d données lues avec %d attendues).\n" #: ../src/loaders/atomic_xyz.c:333 #, c-format msgid "Cannot read forces in '%s'.\n" msgstr "Impossible de lire les forces depuis « %s ».\n" #: ../src/loaders/atomic_xyz.c:435 #, c-format msgid "" "Wrong XYZ format, no number of atoms on line.\n" " '%s'" msgstr "" "Mauvais format XYZ, il manque un entier sur la première ligne.\n" " « %s »" #: ../src/loaders/atomic_xyz.c:491 #, c-format msgid "Missing coordinates (%d read but %d declared).\n" msgstr "Coordonnées manquantes (%d données lues avec %d attendues).\n" #: ../src/loaders/atomic_xyz.c:561 ../src/loaders/atomic_ascii.c:473 #, c-format msgid "The file contains no atom coordinates.\n" msgstr "Le fichier ne contient pas de coordonnées atomiques.\n" #: ../src/loaders/atomic_yaml.c:97 msgid "BigDFT YAML format" msgstr "format YAML de BigDFT" #: ../src/loaders/atomic_yaml.c:127 ../src/loaders/atomic_yaml.c:162 #: ../src/loaders/atomic_yaml.c:438 ../src/loaders/atomic_yaml.c:444 #: ../src/visu_glnodescene.c:2298 #: ../lib/plug-ins/OpenBabel-wrapper/ob_basic.cpp:267 #: ../lib/plug-ins/OpenBabel-wrapper/ob_basic.cpp:385 msgid "Fragment" msgstr "Fragment" #: ../src/loaders/atomic_yaml.c:370 ../src/loaders/atomic_ascii.c:491 #, c-format msgid "" "Wrong (ab) angle, should be different from 0[pi].\n" "\n" " Quoting '%g'.\n" msgstr "" "Erreur sur l'angle (ab), il devrait être différent de 0[pi].\n" "\n" " Citant '%g'.\n" #: ../src/loaders/atomic_yaml.c:413 #, c-format msgid "Unsupported boundary conditions.\n" msgstr "conditions aux bords invalides.\n" #: ../src/loaders/atomic_yaml.c:444 msgid "External potential" msgstr "Potentiel exterieur" #: ../src/loaders/atomic_yaml.c:451 msgid "sigma" msgstr "sigma" #: ../src/loaders/atomic_yaml.c:457 msgid "poles" msgstr "pôles" #: ../src/loaders/atomic_yaml.c:504 msgid "Pole" msgstr "Pôle" #: ../src/loaders/atomic_yaml.c:584 #, c-format msgid "Unsupported units.\n" msgstr "unité non supportée.\n" #: ../src/loaders/atomic_ascii.c:109 msgid "'x y z Element' format" msgstr "Format du type « x y z élément »" #: ../src/loaders/atomic_ascii.c:372 #, c-format msgid "Cannot read dxx dyx dyy on 2nd line of ASCII file.\n" msgstr "Impossible de lire dxx dyx et dyy sur la deuxième ligne.\n" #: ../src/loaders/atomic_ascii.c:393 #, c-format msgid "Cannot read dzx dzy dzz on 3rd line of ASCII file.\n" msgstr "Impossible de lire dzx dzy et dzz sur la troisième ligne.\n" #: ../src/loaders/atomic_ascii.c:447 #, c-format msgid "" "Cannot read x, y, z, name in ASCII file at line %d.\n" "\n" "Quoting '%s'.\n" msgstr "" "Impossible de lire « x y z nom » dans le fichier ASCI à la ligne %d.\n" "\n" " Extrait « %s ».\n" #: ../src/visu_main.c:149 msgid "Visualise atomic simulations" msgstr "Visualise des simulations atomiques" #: ../src/uiElements/ui_boxTransform.c:242 msgid "non periodic data" msgstr "données non-périodiques" #: ../src/uiElements/ui_boxTransform.c:246 msgid "(wire X)" msgstr "(filaire X)" #: ../src/uiElements/ui_boxTransform.c:249 msgid "(wire Y)" msgstr "(filaire Y)" #: ../src/uiElements/ui_boxTransform.c:252 msgid "(wire Z)" msgstr "(filaire Z)" #: ../src/uiElements/ui_boxTransform.c:255 msgid "(surface XY)" msgstr "(surface XY)" #: ../src/uiElements/ui_boxTransform.c:258 msgid "(surface YZ)" msgstr "(surface YZ)" #: ../src/uiElements/ui_boxTransform.c:261 msgid "(surface ZX)" msgstr "(surface ZX)" #: ../src/uiElements/ui_boxTransform.c:264 msgid "(periodic)" msgstr "(périodique)" #: ../src/uiElements/ui_boxTransform.c:267 msgid "unknown periodicity" msgstr "périodicité inconnue" #: ../src/uiElements/ui_boxTransform.c:304 ../src/interface.c:642 #: ../src/panelModules/panelGeometry.c:198 msgid "dx:" msgstr "dx :" #: ../src/uiElements/ui_boxTransform.c:305 ../src/interface.c:668 #: ../src/panelModules/panelGeometry.c:199 msgid "dy:" msgstr "dy :" #: ../src/uiElements/ui_boxTransform.c:306 #: ../src/panelModules/panelGeometry.c:200 msgid "dz:" msgstr "dz :" #: ../src/uiElements/ui_boxTransform.c:331 msgid "Periodic operations" msgstr "Transformations périodiques" #: ../src/uiElements/ui_boxTransform.c:355 msgid "_Translations" msgstr "_Translations" #: ../src/uiElements/ui_boxTransform.c:357 msgid "Translations are given in box coordinates." msgstr "Les translations sont données en coordonnées réduites." #: ../src/uiElements/ui_boxTransform.c:361 msgid "_Put in the box" msgstr "_Déplacer dans la boîte" #: ../src/uiElements/ui_boxTransform.c:363 msgid "Nodes are automatically translated back into the bounding box." msgstr "Les nœuds sont automatiquement translatés à l'intérieur de la boîte." #: ../src/uiElements/ui_boxTransform.c:393 msgid "_Expand nodes" msgstr "_Étend les nœuds" #: ../src/uiElements/ui_boxTransform.c:395 msgid "" "The size of the expansion is given in box coordinates. Nodes are " "automatically translated back into the new defined area. The drawn bounding " "box is kept to the original size." msgstr "" "La taille de l'expansion est donnée en coordonnées de la boîte. Les nœuds " "sont automatiquement positionnés dans le nouvel espace par translation " "depuis les positions initiales. La taille de la boîte reste inchangée." #. The rendering parameters. #: ../src/uiElements/ui_boxTransform.c:403 msgid "param.:" msgstr "param. :" #: ../src/uiElements/ui_boxTransform.c:437 msgid "Box settings" msgstr "Options pour la boite" #: ../src/uiElements/ui_boxTransform.c:448 msgid "Set the unit of the file:" msgstr "Change l'unité du fichier :" #: ../src/uiElements/ui_boxTransform.c:463 msgid "Hide nodes with respect to box:" msgstr "Cache les nœuds selon la boite :" #: ../src/uiElements/ui_boxTransform.c:468 ../src/panelModules/gtkSpin.c:241 msgid "never" msgstr "jamais" #: ../src/uiElements/ui_boxTransform.c:470 msgid "outside" msgstr "en dehors" #: ../src/uiElements/ui_boxTransform.c:472 msgid "inside" msgstr "à l'intérieur" #: ../src/uiElements/ui_scale.c:156 msgid "" "Several scales are defined from resource files, but only one is " "editable." msgstr "" "Plusieurs échelles sont définies dans le fichier ressources,\n" "mais une seule est éditable." #: ../src/uiElements/ui_scale.c:165 msgid "Legend:" msgstr "Légende :" #: ../src/uiElements/ui_scale.c:170 msgid "Default legend displays the length." msgstr "La légende par défaut affiche la longueur." #: ../src/uiElements/ui_scale.c:173 msgid "Use blank legend to print the default value with the distance." msgstr "" "Ne pas écrire de légende pour obtenir la valeur par défaut avec la distance." #: ../src/uiElements/ui_scale.c:179 msgid "Length:" msgstr "Longueur :" #: ../src/uiElements/ui_scale.c:191 msgid "Origin:" msgstr "Origine :" #: ../src/uiElements/ui_scale.c:208 msgid "Orientation:" msgstr "Orientation :" #: ../src/uiElements/ui_scale.c:238 ../src/coreTools/toolFileFormat.c:168 #: ../src/visu_data.c:1690 msgid "Label" msgstr "Étiquette" #: ../src/uiElements/ui_pairtree.c:381 msgid "Pair" msgstr "Liaison" #: ../src/uiElements/ui_pairtree.c:399 msgid "From" msgstr "De" #: ../src/uiElements/ui_pairtree.c:409 msgid "To" msgstr "À" #: ../src/uiElements/ui_pairtree.c:419 msgid "Lg." msgstr "Lg." #: ../src/uiElements/ui_pairtree.c:426 ../src/uiElements/ui_planetree.c:659 msgid "Parameters" msgstr "Paramètres" #. px is for pixels and pat. for pattern. #: ../src/uiElements/ui_pairtree.c:650 msgid "wire:" msgstr "ligne :" #. px for pixel. #: ../src/uiElements/ui_pairtree.c:652 #: ../src/extraGtkFunctions/gtk_dumpDialogWidget.c:312 #: ../src/extraGtkFunctions/gtk_dumpDialogWidget.c:327 #: ../src/extraGtkFunctions/gtk_lineObjectWidget.c:405 msgid "px" msgstr "px" #: ../src/uiElements/ui_pairtree.c:652 msgid "pattern:" msgstr "motif :" #. a.u. is for arbitrary units. #: ../src/uiElements/ui_pairtree.c:659 ../src/uiElements/ui_pairtree.c:663 msgid "radius:" msgstr "rayon :" #: ../src/uiElements/ui_pairtree.c:660 msgid "a.u." msgstr "u.a." #: ../src/uiElements/ui_pairtree.c:1013 msgid "Manage links: " msgstr "Liaisons : " #: ../src/uiElements/ui_pairtree.c:1029 msgid "Show/hide the undrawn pairs." msgstr "Masque/affiche les liaisons non-dessinées." #. Create the part for the link parameters. #: ../src/uiElements/ui_link.c:298 msgid "" "Link parameters:\t (apply to one or more " "selected rows)" msgstr "" "Paramètres :\t (s'appliquent sur une ou " "plusieurs lignes)" #: ../src/uiElements/ui_link.c:313 ../src/panelModules/panelPlanes.c:229 msgid "From: " msgstr "De : " #: ../src/uiElements/ui_link.c:322 msgid " to: " msgstr "à : " #: ../src/uiElements/ui_link.c:331 msgid "_Auto set" msgstr "_Automatique" #: ../src/uiElements/ui_link.c:336 msgid "" "Set the distance criterion to select the first pick in the distance " "distribution between all nodes of the selected types." msgstr "" "Change les critères de distance pour sélectionner le premier pic dans le " "distributuion des distances entre tous les nœuds de types sélectionnés." #: ../src/uiElements/ui_link.c:362 msgid "Thickness:" msgstr "Épaisseur :" #: ../src/uiElements/ui_link.c:370 msgid "Pattern:" msgstr "Motif :" #: ../src/uiElements/ui_link.c:384 msgid "Color _varies with length:" msgstr "Faire _varier la couleur avec la longueur :" #: ../src/uiElements/ui_link.c:395 ../src/uiElements/ui_atomic.c:169 msgid "Radius:" msgstr "Rayon :" #: ../src/uiElements/ui_link.c:407 ../src/panelModules/panelFogBgColor.c:298 msgid "Color:" msgstr "Couleur :" #: ../src/uiElements/ui_link.c:411 msgid "_user defined" msgstr "_utilisateur" #: ../src/uiElements/ui_link.c:417 msgid "_elements" msgstr "_éléments" #: ../src/uiElements/ui_link.c:430 msgid "_nodes" msgstr "_nœuds :" #: ../src/uiElements/ui_elements.c:206 msgid "Set caracteristics of: " msgstr "Caractéristiques pour : " #. We create the tree widget that show the methods. #: ../src/uiElements/ui_elements.c:212 #, c-format msgid "Element '%s'" msgstr "Élément « %s »" #: ../src/uiElements/ui_elements.c:219 msgid "Standard resources" msgstr "Ressources standards" #: ../src/uiElements/ui_elements.c:231 msgid "rendered" msgstr "affiché" #: ../src/uiElements/ui_elements.c:240 msgid "Make nodes sensitive to a colorization effect." msgstr "Applique les effets de colorisation sur les nœuds." #: ../src/uiElements/ui_elements.c:242 msgid "colorizable" msgstr "colorisation" #: ../src/uiElements/ui_elements.c:245 msgid "Make nodes sensitive to the masking effect of planes." msgstr "Applique les effets masquant des plans sur les nœuds." #: ../src/uiElements/ui_elements.c:250 msgid "Rendering specific resources" msgstr "Paramètres particuliers" #: ../src/uiElements/ui_atomic.c:178 ../src/uiElements/ui_spin.c:206 msgid "Shape: " msgstr "Forme :" #: ../src/uiElements/ui_atomic.c:192 msgid "Parameters for elipsoid shape" msgstr "Paramètres pour la forme ellipsoïdale" #: ../src/uiElements/ui_atomic.c:197 msgid "Ratio: " msgstr "Rapport : " #: ../src/uiElements/ui_atomic.c:205 msgid "Phi: " msgstr "Phi : " #: ../src/uiElements/ui_atomic.c:213 msgid "Theta: " msgstr "Théta : " #: ../src/uiElements/ui_spin.c:218 msgid "Size and color properties:" msgstr "Taille des formes et propriété de couleur :" #: ../src/uiElements/ui_spin.c:231 msgid "Hat length:" msgstr "Long. (pointe) :" #: ../src/uiElements/ui_spin.c:239 msgid "Tail length:" msgstr "Long. (tige) :" #: ../src/uiElements/ui_spin.c:247 msgid "Hat radius:" msgstr "Rayon (pointe) :" #: ../src/uiElements/ui_spin.c:255 msgid "Tail radius:" msgstr "Rayon (tige) :" #: ../src/uiElements/ui_spin.c:263 msgid "Use element color on:" msgstr "Utilise la couleur d'élément sur :" #: ../src/uiElements/ui_spin.c:266 msgid " tail" msgstr " queue" #: ../src/uiElements/ui_spin.c:268 msgid " hat" msgstr " pointe" #: ../src/uiElements/ui_spin.c:280 msgid "A axis: " msgstr "Axe A :" #: ../src/uiElements/ui_spin.c:288 msgid "B axis: " msgstr "Axe B :" #: ../src/uiElements/ui_spin.c:294 msgid "Use element color" msgstr "Utiliser la couleur de l'élément" #. Atomic options. #: ../src/uiElements/ui_spin.c:298 msgid "Atomic rendering options" msgstr "Options de rendu atomique" #: ../src/uiElements/ui_spin.c:305 msgid "Enable the atomic rendering in the method tab." msgstr "Cocher le rendu atomique dans l'onglet méthode." #: ../src/uiElements/ui_box.c:202 msgid "Show box _lengths" msgstr "ffiche les _longueurs de la boîte" #: ../src/uiElements/ui_box.c:208 msgid "x pos." msgstr "pos. x" #: ../src/uiElements/ui_box.c:213 msgid "y pos." msgstr "pos. y" #: ../src/uiElements/ui_box.c:241 msgid "Bounding box" msgstr "Boîte" #: ../src/uiElements/ui_axes.c:140 msgid "Use _box basis-set" msgstr "Le repère suit la _boîte" #: ../src/uiElements/ui_axes.c:142 msgid "size: " msgstr "taille : " #: ../src/uiElements/ui_axes.c:147 msgid "x pos.: " msgstr "pos. x : " #: ../src/uiElements/ui_axes.c:150 msgid "y pos.: " msgstr "pos. y : " #: ../src/uiElements/ui_axes.c:155 msgid "Axis labels: " msgstr "Étiquettes des axes : " #: ../src/uiElements/ui_axes.c:177 ../lib/plug-ins/bigdft/bigdft.c:438 msgid "Basis set" msgstr "Repère" #: ../src/uiElements/ui_planetree.c:566 #, c-format msgid "" "norm.: (%3d;%3d;%3d)\n" "distance: %6.2f" msgstr "" "norm. :(%3d;%3d;%3d)\n" "distance : %6.2f" #: ../src/uiElements/ui_planetree.c:653 msgid "Drawn" msgstr "Affiche" #: ../src/uiElements/ui_planetree.c:669 msgid "Mask" msgstr "Masquage" #: ../src/uiElements/ui_planetree.c:679 msgid "Invert" msgstr "Inverse" #: ../src/uiElements/ui_planetree.c:685 ../src/panelModules/panelSurfaces.c:682 msgid "Color" msgstr "Couleur" #: ../src/uiElements/ui_planetree.c:714 msgid "align" msgstr "aligner" #: ../src/uiElements/ui_planetree.c:717 msgid "Set the camera to look in the direction normal to the selected plane." msgstr "Tourner la caméra dans une direction normale au plan sélectionné." #: ../src/uiElements/ui_planetree.c:978 msgid "Hiding mode: " msgstr "Type de masquage : " #: ../src/uiElements/ui_planetree.c:983 msgid "Hide all elements that are hidden by at least one plane." msgstr "Masque tous les éléments étant masqués par au moins un plan." #: ../src/uiElements/ui_planetree.c:984 msgid "Union" msgstr "Union" #: ../src/uiElements/ui_planetree.c:987 msgid "Hide elements only if they are hidden by all planes." msgstr "Masque les éléments qui sont masqués par tous les plans." #: ../src/uiElements/ui_planetree.c:988 msgid "Intersection" msgstr "Intersection" #. VisuPlanes parameters #: ../src/uiElements/ui_planetree.c:1065 msgid "Normal: " msgstr "Normale :" #: ../src/uiElements/ui_planetree.c:1078 msgid "Distance from origin: " msgstr "Distance à l'origine :" #: ../src/uiElements/ui_planetree.c:1087 #: ../src/panelModules/panelSurfaces.c:687 msgid "Color: " msgstr "Couleur :" #: ../src/gtk_save.c:255 msgid "" "A description of all resource markups is available on:\n" " " msgstr "" "Une description de toutes les ressources est disponible à :\n" " " #: ../src/gtk_save.c:275 msgid "Export all resource descriptions to an _XML file" msgstr "Exporte toutes les ressources dans un fichier _XML" #: ../src/gtk_save.c:284 msgid "Export all parameter descriptions to an _XML file" msgstr "Exporte tous les paramètres dans un fichier _XML" #: ../src/gtk_save.c:292 msgid "Export all command line _options to an XML file" msgstr "Exporte toutes les options de ligne de commande dans un fichier XML" #: ../src/gtk_save.c:306 msgid "Append all settings in a single XML file (including planes, surfaces…)" msgstr "" "Ajoute tous les paramètres dans un fichier XML unique (incluant les plans, " "les surfaces…" #: ../src/gtk_save.c:315 msgid "" "A description of all parameter markups is available on:\n" " " msgstr "" "Une description de tous les paramètres est disponible à :\n" " " #: ../src/gtk_save.c:381 ../src/gtk_renderingWindowWidget.c:2282 #: ../src/panelModules/panelSurfacesTools.c:322 #: ../src/panelModules/panelSurfacesTools.c:639 #: ../src/panelModules/panelSurfacesTools.c:659 #: ../src/panelModules/panelSurfacesTools.c:682 #: ../src/panelModules/panelSurfacesTools.c:702 #: ../src/panelModules/panelSurfacesTools.c:1069 #: ../src/panelModules/panelSurfacesTools.c:1082 #: ../src/panelModules/panelSurfacesTools.c:1093 #: ../src/panelModules/panelSurfacesTools.c:1110 #: ../src/panelModules/panelSurfacesTools.c:1564 #: ../src/panelModules/panelSurfacesTools.c:1571 #: ../src/panelModules/panelSurfacesTools.c:1834 #: ../src/panelModules/panelSurfacesTools.c:1842 #: ../src/panelModules/panelSurfacesTools.c:1854 #: ../src/panelModules/panelSurfacesTools.c:1867 #: ../src/panelModules/panelSurfacesTools.c:1884 #: ../src/panelModules/panelSurfaces.c:1088 #: ../src/panelModules/panelSurfaces.c:1121 #: ../src/panelModules/panelBrowser.c:1359 #: ../src/panelModules/panelBrowser.c:1380 msgid "Loading a file" msgstr "Chargement d'un fichier" #: ../src/gtk_save.c:390 #, c-format msgid "File '%s' succesfully loaded." msgstr "Fichier « %s » chargé avec succès." #: ../src/gtk_save.c:392 #, c-format msgid "File '%s' not or partially loaded." msgstr "Le fichier « %s » n'a pas été chargé." #: ../src/gtk_save.c:411 msgid "Choose a filename with '.xml' to append other settings." msgstr "" "Entrez un nom de fichier en « .xml » pour ajouter à d'autres paramètres" #. Autodetect failed, no format match the given filename #: ../src/gtk_save.c:512 ../src/gtk_renderingWindowWidget.c:2495 #: ../src/extraGtkFunctions/gtk_dumpDialogWidget.c:507 #: ../src/extraGtkFunctions/gtk_dumpDialogWidget.c:529 ../src/gtk_main.c:1003 #: ../src/gtk_main.c:1015 ../src/gtk_main.c:1025 ../src/gtk_main.c:1046 #: ../src/gtk_main.c:1067 ../src/panelModules/panelSurfacesTools.c:737 #: ../src/panelModules/panelSurfacesTools.c:750 #: ../src/panelModules/panelSurfacesTools.c:1606 #: ../src/panelModules/panelSurfacesTools.c:1612 #: ../src/panelModules/panelSurfacesTools.c:1618 #: ../src/panelModules/panelSurfacesTools.c:1706 #: ../src/panelModules/panelSurfacesTools.c:1712 #: ../src/panelModules/panelSurfacesTools.c:1718 #: ../src/panelModules/panelSurfacesTools.c:1744 msgid "Saving a file" msgstr "Enregistrement d'un fichier" #: ../src/gtk_save.c:520 #, c-format msgid "File '%s' succesfully written (%d lines)." msgstr "Fichier « %s » écrit avec succès (%d lignes)." #: ../src/gtk_save.c:523 #, c-format msgid "File '%s' not written." msgstr "Le fichier « %s » n'a pas été écrit." #: ../src/visu_basic.c:355 #, c-format msgid "The format can't be found from the filename '%s' entered.\n" msgstr "" "Le format de fichier ne peut être déduit du nom de fichier « %s » fourni.\n" #: ../src/visu_basic.c:357 #, c-format msgid "" "Use -o fileFormatId=id to specify a file format when the autodetection " "fails. Get a list of ids with option -o list:\n" "\n" msgstr "" "Utilisez -o fileFormatId=id pour choisir un format de fichier quand l'auto-" "détection échoue. On peut obtenir une liste des formats de fichiers avec " "l'option -o list :\n" "\n" #: ../src/visu_basic.c:377 msgid "a file to render is mandatory with the '--export' option." msgstr "un fichier à dessiner est nécessaire avec l'option « --export »." #: ../src/visu_basic.c:489 #, c-format msgid "" "\n" "#%2d - exportation file format '%s':\n" msgstr "" "\n" "#%2d - format de fichier d'exportation « %s » :\n" #: ../src/visu_basic.c:499 ../src/visu_basic.c:531 msgid "integer" msgstr "entier" #: ../src/visu_basic.c:502 ../src/visu_basic.c:534 msgid "boolean" msgstr "booléen" #: ../src/visu_basic.c:505 ../src/visu_basic.c:537 msgid "string" msgstr "chaîne" #: ../src/visu_basic.c:515 ../src/visu_basic.c:547 #, c-format msgid "No option for this file format.\n" msgstr "Pas d'option pour ce format de fichier.\n" #: ../src/visu_basic.c:521 #, c-format msgid "" "\n" "#%2d - input file format '%s':\n" msgstr "" "\n" "#%2d - format de fichier d'importation « %s » :\n" #: ../src/visu_glnodescene.c:2547 msgid "" "option '--build-map' has been given but no plane is available (use '--" "planes')." msgstr "" "l'option « --build-map » nécessite d'avoir un plan (utilisez l'option « --" "planes »)." #: ../src/visu_glnodescene.c:2550 msgid "" "option '--build-map' has been given but no scalar field is available (use '--" "scalar-field')." msgstr "" "l'option « --build-map » nécessite d'avoir un champ scalaire (utilisez " "l'option « --scalar-field »)." #: ../src/visu_glnodescene.c:2553 msgid "" "option '--build-map' has been given but no shade is available (use '--color-" "preset')." msgstr "" "l'option « --build-map » nécessite d'avoir un dégradé (utilisez l'option « --" "color-preset »)." #. * #. * SECTION: gtk_pick #. * @short_description: The pick and measurement tab in the interactive #. * dialog. #. * #. * This action tab provides widgets to display information about #. * selected atoms, like distances or angles. In addition, measured #. * distances and angles are kept in a list when new files are #. * loaded. #. * With the list of selected nodes, one can modify properties #. * associated to nodes like their coordinates, the value of #. * colourisation if any, the forces on them, if any... One can also #. * decide to display information directly on nodes. #. #: ../src/gtk_pick.c:80 msgid "" "left-button\t\t\t: standard pick\n" "control-left-button\t\t: toggle highlihgt node\n" "middle-button\t\t: measure node neighbouring\n" "shift-middle-button\t: pick 1st reference\n" "ctrl-middle-button\t\t: pick 2nd reference\n" "drag-left-button\t\t: make a rectangular selection\n" "right-button\t\t\t: switch to observe" msgstr "" "bouton gauche\t\t : sélection standard\n" "control bouton gauche\t : change la mise en évidence\n" "bouton du milieu\t\t : mesure le voisinage\n" "shift bouton du milieu\t : choix de la 1ère référence\n" "ctrl bouton du milieu\t : choix de la 2nde référence\n" "glisser bouton de gauche\t : sélection rectangulaire\n" "bouton droit\t\t\t : passer en mode d'observation" #: ../src/gtk_pick.c:169 #, c-format msgid "Highlights (%d):" msgstr "Met en évidence (%d) :" #: ../src/gtk_pick.c:171 ../src/interface.c:787 msgid "Highlights (none):" msgstr "Met en évidence (aucun) :" #: ../src/gtk_pick.c:181 #, c-format msgid "List of %d node(s):" msgstr "Liste de %d nœud(s) :" #: ../src/gtk_pick.c:183 msgid "List of nodes (none):" msgstr "Liste de nœuds (aucun) :" #: ../src/gtk_pick.c:292 msgid "" "Values in blue are " "editable" msgstr "" "Les valeurs en bleu sont " "modifiables." #: ../src/gtk_pick.c:332 msgid "Set / unset highlight status following selection." msgstr "Ajoute / enlève la mise en évidence suivant la sélection." #: ../src/gtk_pick.c:340 msgid "Empty the selection list." msgstr "Vider la liste de sélection." #: ../src/gtk_pick.c:346 msgid "Draw data on nodes" msgstr "Affiche les informations sur les nœuds" #: ../src/gtk_pick.c:354 ../src/extraFunctions/nodeProp.c:439 #: ../src/extraFunctions/nodeProp.c:525 ../lib/plug-ins/bigdft/bigdft.c:675 msgid "none" msgstr "aucun" #: ../src/gtk_pick.c:362 msgid "listed" msgstr "listé(s)" #: ../src/gtk_pick.c:376 msgid "all" msgstr "tout" #: ../src/gtk_pick.c:412 msgid "Import picked nodes from an existing XML file." msgstr "Importe les nœuds sélectionnés depuis un fichier XML existant." #: ../src/gtk_pick.c:413 msgid "Export listed picked nodes to the current XML file." msgstr "Exporte la liste des nœuds sélectionnés dans le fichier XML courant." #: ../src/gtk_pick.c:414 msgid "Export listed picked nodes to a new XML file." msgstr "Exporte la liste des nœuds sélectionnés dans un nouveau fichier XML." #: ../src/gtk_pick.c:456 msgid "Hide nodes depending on highlight status." msgstr "Masque les nœud selon leur mise en évidence." #: ../src/gtk_pick.c:465 msgid "_h." msgstr "_h." #: ../src/gtk_pick.c:469 msgid "Hide button will hide highlighted nodes." msgstr "Cache tous les nœuds mis en évidence." #: ../src/gtk_pick.c:474 msgid "_non-h." msgstr "_non-h." #: ../src/gtk_pick.c:478 msgid "Hide button will hide non-highlighted nodes." msgstr "Cache tous les nœuds non mis en évidence." #: ../src/gtk_pick.c:560 #, c-format msgid "" "Reference node\t #%d\n" " ( x = %7.3f ; y = %7.3f ; " "z = %7.3f)\n" "" msgstr "" "Référence\t\t #%d\n" " ( x = %7.3f ; y = %7.3f ; " "z = %7.3f)\n" "" #: ../src/gtk_pick.c:576 #, c-format msgid "" "2nd Reference node\t #%d\t (i.e. " "dr = %7.3f)\n" " ( x = %7.3f ; y = %7.3f ; " "z = %7.3f)\n" " (δx = %7.3f ; δy = %7.3f ; δz = %7.3f)\n" "" msgstr "" "Seconde référence\t #%d\t (i.e. " "dr = %7.3f)\n" " ( x = %7.3f ; y = %7.3f ; " "z = %7.3f)\n" " (δx = %7.3f ; δy = %7.3f ; δz = %7.3f)\n" "" #: ../src/gtk_pick.c:588 #, c-format msgid "" "Newly picked node\t #%d\n" " ( x = %7.3f ; y = %7.3f ; " "z = %7.3f)\n" "" msgstr "" "Nouvelle sélection\t #%d\n" " ( x = %7.3f ; y = %7.3f ; " "z = %7.3f)\n" "" #: ../src/gtk_pick.c:604 #, c-format msgid "" "Newly picked node\t #%d\t (i.e. " "dr = %7.3f)\n" " ( x = %7.3f ; y = %7.3f ; " "z = %7.3f)\n" " (δx = %7.3f ; δy = %7.3f ; δz = %7.3f)\n" "" msgstr "" "Nouvelle sélection\t #%d\t (i.e. " "dr = %7.3f)\n" " ( x = %7.3f ; y = %7.3f ; " "z = %7.3f)\n" " (δx = %7.3f ; δy = %7.3f ; δz = %7.3f)\n" "" #: ../src/gtk_pick.c:627 #, c-format msgid "" "Newly picked node\t #%d\t (i.e. " "dr = %7.3f)\n" " ( x = %7.3f ; y = %7.3f ; " "z = %7.3f)\n" " (δx1 = %7.3f ; δy1 = %7.3f ; δz1 = %7.3f)\n" " (δx2 = %7.3f ; δy2 = %7.3f ; δz2 = %7.3f)\n" msgstr "" "Nouvelle sélection\t #%d\t (i.e. " "dr = %7.3f)\n" " ( x = %7.3f ; y = %7.3f ; " "z = %7.3f)\n" " (δx1 = %7.3f ; δy1 = %7.3f ; δz1 = %7.3f)\n" " (δx2 = %7.3f ; δy2 = %7.3f ; δz2 = %7.3f)\n" #: ../src/gtk_pick.c:640 #, c-format msgid " angle (Ref-Ref2, Ref-New) = %5.2f degrees" msgstr " angle (Ref.-Ref.2, Ref.-Sél.) = %5.2f degrés" #: ../src/gtk_pick.c:644 #, c-format msgid "Unset reference %d." msgstr "Désélection de la référence %d." #: ../src/gtk_pick.c:683 ../src/gtk_renderingWindowWidget.c:1463 msgid "No node has been selected." msgstr "Pas de noud sélectionné." #: ../src/gtk_pick.c:686 msgid "Picked reference and second reference are the same." msgstr "La référence choisie et la seconde référence sont les mêmes." #: ../src/gtk_pick.c:690 msgid "Can't pick a second reference without any existing first one." msgstr "" "On ne peut définir une seconde référence sans avoir défini de première " "référence." #: ../src/gtk_pick.c:694 ../src/gtk_renderingWindowWidget.c:1475 msgid "Can't remove first reference before removing the second one." msgstr "" "On ne peut retirer la première référence sans avoir retirer la seconde." #: ../src/gtk_pick.c:743 ../src/gtk_pick.c:789 #: ../src/extraGtkFunctions/gtk_dataChooser.c:527 #: ../src/extraGtkFunctions/gtk_dataChooser.c:533 #: ../src/extraGtkFunctions/gtk_dataChooser.c:572 #: ../src/extraGtkFunctions/gtk_dataChooser.c:582 #: ../src/extraGtkFunctions/gtk_elementComboBox.c:493 #: ../src/panelModules/panelSurfaces.c:2296 msgid "None" msgstr "Aucun" #: ../src/gtk_pick.c:801 msgid "Reading values" msgstr "Lecture des valeurs" #: ../src/gtk_pick.c:802 msgid "" "Wrong format. Impossible to parse the data associated to the selected node." msgstr "" "Format invalid. Impossible d'analyser les données associées au nœud " "sélectionné." #: ../src/gtk_renderingWindowWidget.c:161 msgid "No description is available" msgstr "Aucune description" #: ../src/gtk_renderingWindowWidget.c:162 msgid "Nothing is loaded" msgstr "Rien n'est chargé" #: ../src/gtk_renderingWindowWidget.c:370 msgid "" "Rotate with left b., pick with right b., setup ref. with or " " b." msgstr "" "Tourne avec le bouton g., sélectionne avec le bouton d., choisi des réf. " "avec ou bouton d." #: ../src/gtk_renderingWindowWidget.c:706 msgid "No file loaded" msgstr "Aucun fichier chargé" #: ../src/gtk_renderingWindowWidget.c:708 msgid "No filename" msgstr "Aucun nom de fichier" #: ../src/gtk_renderingWindowWidget.c:985 ../src/support.h:60 msgid "_Close" msgstr "_Fermer" #: ../src/gtk_renderingWindowWidget.c:996 msgid "Toggle highlight for node: " msgstr "Change la mise en évidence pour le nœud :" #: ../src/gtk_renderingWindowWidget.c:1048 msgid "" "Click here to get the list of saved camera positions.\n" "Use 's' and 'r' keys to save and restore camera settings. + 's' " "remove the current camera from the list." msgstr "" "Cliquer ici pour afficher la liste des positions enregistrées de la caméra.\n" "« s » et « r » servent de raccoursis claviers pour sauver ou restaurer une " "configuration de la caméra. + « s » retire la caméra sélectionnée de " "la liste." #: ../src/gtk_renderingWindowWidget.c:1077 msgid "Open Ctrl+o" msgstr "Ouvrir Ctrl+o" #: ../src/gtk_renderingWindowWidget.c:1091 msgid "Reload the current file Ctrl+r" msgstr "Recharge le fichier courant Ctrl+r" #: ../src/gtk_renderingWindowWidget.c:1107 msgid "Export Ctrl+s" msgstr "Exportation du fichier Ctrl+s" #: ../src/gtk_renderingWindowWidget.c:1121 msgid "" "Raise the command panel window.\n" " Use as key binding." msgstr "" "Afficher le panneau principal.\n" " Raccoursis clavier : ." #: ../src/gtk_renderingWindowWidget.c:1154 ../src/support.h:57 #: ../src/interface.c:1650 msgid "_Cancel" msgstr "_Annuler" #: ../src/gtk_renderingWindowWidget.c:1179 msgid "Measure / remove information for the selected node." msgstr "Mesure / retire les informations autour du nœud sélectionné." #: ../src/gtk_renderingWindowWidget.c:1194 msgid "Remove all measurement marks." msgstr "Retirer toutes les marques de mesures." #: ../src/gtk_renderingWindowWidget.c:1202 msgid "Use the 'open' button to render a file." msgstr "Cliquer sur le bouton « ouvrir » pour charger un fichier." #: ../src/gtk_renderingWindowWidget.c:1359 msgid "Drag and drop" msgstr "Déplacer et déposer" #: ../src/gtk_renderingWindowWidget.c:1359 msgid "Too many dropped files." msgstr "Trop de fichiers déposés." #: ../src/gtk_renderingWindowWidget.c:1383 msgid "Selected node number " msgstr "Nœud sélectionné : " #: ../src/gtk_renderingWindowWidget.c:1425 msgid "Distance between nodes " msgstr "Distances entre les nœuds " #: ../src/gtk_renderingWindowWidget.c:1430 #, c-format msgid "%d and %d : %7.3f" msgstr "%d et %d : %7.3f" #: ../src/gtk_renderingWindowWidget.c:1437 msgid " right-click on background to unset reference." msgstr " clic-droit sur le fond pour déselectionner la référence." #: ../src/gtk_renderingWindowWidget.c:1443 msgid " right-click on background to unset second reference." msgstr "" " clic-droit sur le fond pour déselectionner la seconde référence." #: ../src/gtk_renderingWindowWidget.c:1466 msgid "Picked node is already used as a reference." msgstr "Le nœud sélectionné est déjà utilisé comme référence." #: ../src/gtk_renderingWindowWidget.c:1470 msgid "" "Can't pick a second reference without any first one (use right-" "click)." msgstr "" "On ne peut sélectionner une seconde référence sans avoir sélectionné une " "première (en utilisant clic-droit)." #: ../src/gtk_renderingWindowWidget.c:1743 msgid "Restore saved camera position." msgstr "Retourne à la position enregistrée." #: ../src/gtk_renderingWindowWidget.c:1746 #: ../src/gtk_renderingWindowWidget.c:2036 msgid "No saved camera. Use 's' to save one." msgstr "" "Pas de caméra enregistrée. La touche « s » peut être utilisée pour ce faire." #: ../src/gtk_renderingWindowWidget.c:1751 msgid "Save current camera position." msgstr "Sauvegarde la position courante." #: ../src/gtk_renderingWindowWidget.c:1754 msgid "Pop current camera position." msgstr "Passe à la position précédente." #: ../src/gtk_renderingWindowWidget.c:1758 msgid "Align camera with X box axis." msgstr "Aligne la caméra avec l'axe X de la boite." #: ../src/gtk_renderingWindowWidget.c:1762 msgid "Align camera with Y box axis." msgstr "Aligne la caméra avec l'axe Y de la boite." #: ../src/gtk_renderingWindowWidget.c:1766 msgid "Align camera with Z box axis." msgstr "Aligne la caméra avec l'axe Z de la boite." #: ../src/gtk_renderingWindowWidget.c:1943 msgid "Size:" msgstr "Taille :" #. Set a title. #: ../src/gtk_renderingWindowWidget.c:2005 msgid "Camera menu (saved in 'v_sim.par'):" msgstr "Menu de la caméra (enregistré dans le fichier « v_sim.par ») :" #: ../src/gtk_renderingWindowWidget.c:2012 #, c-format msgid "" "save current camera:\n" "(θ %6.1f° ; φ %6.1f° ; ω %6.1f°) dx %4.1f dy %4.1f" msgstr "" "sauver la caméra courante :\n" "(θ %6.1f° ; φ %6.1f° ; ω %6.1f°) dx %4.1f dy %4.1f" #. Put an option to open the view selector. #: ../src/gtk_renderingWindowWidget.c:2025 msgid "select precisely a camera view" msgstr "sélection précise d'une orientation de caméra" #: ../src/gtk_renderingWindowWidget.c:2041 msgid "List of saved cameras:" msgstr "Liste des cameras enregistrées :" #: ../src/gtk_renderingWindowWidget.c:2050 #, c-format msgid "(θ %6.1f° ; φ %6.1f° ; ω %6.1f°) dx %4.1f dy %4.1f" msgstr "(θ %6.1f° ; φ %6.1f° ; ω %6.1f°) dx %4.1f dy %4.1f" #: ../src/gtk_renderingWindowWidget.c:2217 msgid "Loading file..." msgstr "Chargement d'un fichier…" #: ../src/gtk_renderingWindowWidget.c:2229 msgid "Cancellation request, waiting for reply..." msgstr "Annulation demandée, en attente…" #: ../src/gtk_renderingWindowWidget.c:2385 msgid "Reloading file" msgstr "Rechargement d'un fichier" #: ../src/gtk_renderingWindowWidget.c:2412 msgid "Nb nodes:" msgstr "Nb nœuds :" #: ../src/gtk_renderingWindowWidget.c:2437 msgid "Saving image..." msgstr "Enregistrement de l'image…" #: ../src/gtk_renderingWindowWidget.c:2480 #: ../src/panelModules/panelBrowser.c:987 msgid "Waiting for generating image in memory..." msgstr "En attente, création de l'image en mémoire…" #: ../src/visu_gtk.c:123 msgid "V_Sim error message" msgstr "Message d'erreur de V_Sim" #: ../src/visu_gtk.c:165 msgid "Output errors:" msgstr "Sortie d'erreur :" #: ../src/visu_gtk.c:305 msgid "Loading plug-ins" msgstr "Chargement des greffons" #: ../src/visu_gtk.c:312 msgid "Reading the configuration files" msgstr "Lecture des fichiers de configuration" #: ../src/visu_gtk.c:339 msgid "Parsing command line" msgstr "Analyse de la ligne de commande" #: ../src/visu_gtk.c:368 ../src/extraGtkFunctions/gtk_dataChooser.c:447 msgid "All supported formats" msgstr "Tous formats supportés" #: ../src/visu_gtk.c:376 ../src/extraGtkFunctions/gtk_dataChooser.c:455 msgid "No description" msgstr "Sans description" #: ../src/visu_gtk.c:393 ../src/extraGtkFunctions/gtk_dataChooser.c:467 #: ../src/extraGtkFunctions/gtk_valueIOWidget.c:277 #: ../src/extraGtkFunctions/gtk_valueIOWidget.c:527 #: ../src/panelModules/panelDataFile.c:742 msgid "All files" msgstr "Tous les fichiers" #: ../src/visu_gtk.c:435 #, c-format msgid "failed to load pixbuf file '%s': %s\n" msgstr "échec à la lecture du fichier image « %s » : %s\n" #: ../src/extraGtkFunctions/gtk_dataChooser.c:176 msgid "Load session" msgstr "Chargement" #: ../src/extraGtkFunctions/gtk_dataChooser.c:194 msgid "Rendering method:" msgstr "Méthode de rendu :" #: ../src/extraGtkFunctions/gtk_dataChooser.c:199 msgid "display node as atoms" msgstr "afficher les nœuds comme des atomes" #: ../src/extraGtkFunctions/gtk_dataChooser.c:201 msgid "display node as spins" msgstr "afficher les nœuds comme des spins" #: ../src/extraGtkFunctions/gtk_dataChooser.c:211 msgid "_Preview:" msgstr "_Prévisualisation :" #: ../src/extraGtkFunctions/gtk_dataChooser.c:262 msgid "Box composition:" msgstr "Composition de la boîte :" #: ../src/extraGtkFunctions/gtk_dataChooser.c:271 #, c-format msgid "%s:" msgstr "%s :" #: ../src/extraGtkFunctions/gtk_dataChooser.c:281 #, c-format msgid "%d nodes" msgstr "%d nœuds" #: ../src/extraGtkFunctions/gtk_dataChooser.c:284 msgid "1 node" msgstr "1 nœud" #: ../src/extraGtkFunctions/gtk_dataChooser.c:295 msgid "Description:" msgstr "Description :" #: ../src/extraGtkFunctions/gtk_dataChooser.c:363 msgid "Not a V_Sim file" msgstr "Fichier V_Sim incorrect" #: ../src/extraGtkFunctions/gtk_dataChooser.c:375 msgid "This file has errors" msgstr "Ce fichier a des erreurs" #. Position button. #: ../src/extraGtkFunctions/gtk_dataChooser.c:515 msgid "Positions:" msgstr "Position :" #: ../src/extraGtkFunctions/gtk_dataChooser.c:522 msgid "Spins:" msgstr "Fichiers de spin :" #: ../src/extraGtkFunctions/gtk_elementComboBox.c:495 msgid "All elements" msgstr "Tous les éléments" #: ../src/extraGtkFunctions/gtk_toolPanelWidget.c:198 ../src/gtk_main.c:326 msgid "Command panel" msgstr "Panneau de commande" #: ../src/extraGtkFunctions/gtk_toolPanelWidget.c:512 msgid "Manage this subpanel: attach/detach or hide it." msgstr "Gestion de cet onglet : l'attacher, le détache ou le masquer." #: ../src/extraGtkFunctions/gtk_toolPanelWidget.c:791 #, c-format msgid "Send to '%s'" msgstr "Envoyer dans « %s »" #. Create a new dock window. #: ../src/extraGtkFunctions/gtk_toolPanelWidget.c:807 msgid "New dock" msgstr "Nouvelle boîte à outils" #. Remove the current tool panel. #: ../src/extraGtkFunctions/gtk_toolPanelWidget.c:812 #, c-format msgid "Hide tool '%s'" msgstr "Masquer l'outil « %s »" #: ../src/extraGtkFunctions/gtk_toolPanelWidget.c:845 #, c-format msgid "Dock window (%d)" msgstr "Fenêtre d'outils (%d)" #: ../src/extraGtkFunctions/gtk_toolPanelWidget.c:1131 #: ../src/extraGtkFunctions/gtk_toolPanelWidget.c:1159 #, c-format msgid "Show '%s'" msgstr "Montrer « %s »" #: ../src/extraGtkFunctions/gtk_toolPanelWidget.c:1143 msgid "No hidden tool" msgstr "Aucun outil masqué" #: ../src/extraGtkFunctions/gtk_toolPanelWidget.c:1170 msgid "No hidden dock" msgstr "Aucune boîte à outils masquée" #. Hide action #: ../src/extraGtkFunctions/gtk_toolPanelWidget.c:1180 msgid "Hide dock" msgstr "Masquer la boîte à outils" #: ../src/extraGtkFunctions/gtk_toolPanelWidget.c:1541 msgid "" "Raise the rendering window.\n" " Use as key binding." msgstr "" "Affiche la fenêtre de rendu.\n" " Raccoursis clavier : ." #. The Label to introduce the combo list. #: ../src/extraGtkFunctions/gtk_toolPanelWidget.c:1545 msgid "Tool: " msgstr "Outil : " #: ../src/extraGtkFunctions/gtk_toolPanelWidget.c:1579 msgid "Manage hidden subpanels and dock windows." msgstr "Gestion des onglets masqués et des fenêtres d'utilitaires." #: ../src/extraGtkFunctions/gtk_toolPanelWidget.c:1585 msgid "" "Positions, sizes, names, contains... of dock windows are stored in the " "parameters file, see the 'Config. files' button on the command panel." msgstr "" "La position, la taille, le nom et le contenu des fenêtres d'outils sont " "sauvegardés dans le fichier de paramètres, voir le bouton « Fichiers de " "conf. » du panneau de commande." #. Labels for the ranges part. #: ../src/extraGtkFunctions/gtk_colorComboBoxWidget.c:129 #: ../src/extraGtkFunctions/gtk_lineObjectWidget.c:426 #: ../src/panelModules/panelFogBgColor.c:144 msgid "R:" msgstr "R :" #: ../src/extraGtkFunctions/gtk_colorComboBoxWidget.c:130 #: ../src/extraGtkFunctions/gtk_lineObjectWidget.c:427 #: ../src/panelModules/panelFogBgColor.c:145 msgid "G:" msgstr "V :" #: ../src/extraGtkFunctions/gtk_colorComboBoxWidget.c:131 #: ../src/extraGtkFunctions/gtk_lineObjectWidget.c:428 #: ../src/panelModules/panelFogBgColor.c:146 msgid "B:" msgstr "B :" #: ../src/extraGtkFunctions/gtk_colorComboBoxWidget.c:132 msgid "Alph:" msgstr "Alpha :" #: ../src/extraGtkFunctions/gtk_colorComboBoxWidget.c:133 msgid "amb:" msgstr "amb. :" #: ../src/extraGtkFunctions/gtk_colorComboBoxWidget.c:134 msgid "dif:" msgstr "dif. :" #: ../src/extraGtkFunctions/gtk_colorComboBoxWidget.c:135 msgid "shi:" msgstr "bri. :" #: ../src/extraGtkFunctions/gtk_colorComboBoxWidget.c:136 msgid "spe:" msgstr "spé. :" #: ../src/extraGtkFunctions/gtk_colorComboBoxWidget.c:137 msgid "emi:" msgstr "émi. :" #: ../src/extraGtkFunctions/gtk_colorComboBoxWidget.c:292 #: ../src/extraGtkFunctions/gtk_colorComboBoxWidget.c:293 msgid "New / modify" msgstr "Nouvelle/modif." #: ../src/extraGtkFunctions/gtk_colorComboBoxWidget.c:513 #: ../src/panelModules/panelDataFile.c:474 msgid "More options" msgstr "Plus d'options" #. Create the selection. #: ../src/extraGtkFunctions/gtk_colorComboBoxWidget.c:776 msgid "Select a color" msgstr "Sélectionner une couleur" #: ../src/extraGtkFunctions/gtk_dumpDialogWidget.c:224 msgid "Export to a file (image, atomic structures...)" msgstr "Exporte dans un fichier (image, structure atomique…)" #. Label to introduce the combobox which allow to choose the format #: ../src/extraGtkFunctions/gtk_dumpDialogWidget.c:273 msgid "Choose the file format : " msgstr "Choix du format de fichier : " #: ../src/extraGtkFunctions/gtk_dumpDialogWidget.c:279 msgid "Autodetect format" msgstr "Autodétection par l'extension" #. Add an expander for file format options. #: ../src/extraGtkFunctions/gtk_dumpDialogWidget.c:282 msgid "File format option:" msgstr "Option du format de fichier : " #: ../src/extraGtkFunctions/gtk_dumpDialogWidget.c:295 msgid "Add extension" msgstr "Ajouter l'extension" #: ../src/extraGtkFunctions/gtk_dumpDialogWidget.c:301 msgid "Width: " msgstr "Larg. :" #: ../src/extraGtkFunctions/gtk_dumpDialogWidget.c:316 msgid "Height: " msgstr "Haut. :" #. Label to introduce the progress bar #: ../src/extraGtkFunctions/gtk_dumpDialogWidget.c:340 msgid "Dump progress : " msgstr "Avancement : " #: ../src/extraGtkFunctions/gtk_dumpDialogWidget.c:352 msgid "" "Current box has translations applied, do you want to proceed to exportation " "anyway?" msgstr "" "La boite courante a des translations, voulez-vous quand même exporter les " "positions courantes ?" #: ../src/extraGtkFunctions/gtk_dumpDialogWidget.c:508 #: ../src/extraGtkFunctions/gtk_fieldChooser.c:267 msgid "No filename chosen." msgstr "Aucun nom de fichier sélctionné." #: ../src/extraGtkFunctions/gtk_dumpDialogWidget.c:530 msgid "The filename doesn't match any known format." msgstr "Le nom de fichier fourni ne correspond à aucun format connu." #: ../src/extraGtkFunctions/gtk_lineObjectWidget.c:374 msgid "expand for options" msgstr "affiche les options" #. The label. #: ../src/extraGtkFunctions/gtk_lineObjectWidget.c:391 msgid "Line style:" msgstr "Style de ligne :" #. The scale width spin button. #: ../src/extraGtkFunctions/gtk_lineObjectWidget.c:396 msgid "width:" msgstr "Larg. :" #: ../src/extraGtkFunctions/gtk_lineObjectWidget.c:447 msgid "color:" msgstr "Couleur :" #: ../src/extraGtkFunctions/gtk_lineObjectWidget.c:461 msgid "(preset)" msgstr "(prédéfinie)" #: ../src/extraGtkFunctions/gtk_curveWidget.c:109 #: ../lib/plug-ins/python-gi/pythongi.c:260 msgid "All" msgstr "Tout" #: ../src/extraGtkFunctions/gtk_fieldChooser.c:183 msgid "Isosurfaces files" msgstr "Fichier d'iso-surfaces" #: ../src/extraGtkFunctions/gtk_fieldChooser.c:192 msgid "Open a surface/density file" msgstr "Ouvrir un fichier de surface/densité" #: ../src/extraGtkFunctions/gtk_fieldChooser.c:208 msgid "Keep surface box as defined" msgstr "Garder la boîte des surfaces" #: ../src/extraGtkFunctions/gtk_fieldChooser.c:210 msgid "Don't modify the surface coordinates." msgstr "Ne pas modifier les coordonnées des surfaces." #: ../src/extraGtkFunctions/gtk_fieldChooser.c:212 msgid "Fit surfaces to box" msgstr "Adapter la taille des surfaces à la boîte de rendu." #: ../src/extraGtkFunctions/gtk_fieldChooser.c:214 msgid "Makes surfaces fit to the current loaded bounding box." msgstr "" "Modifie les surfaces pour les faire correspondre à la boîte de rendu " "atomique." #: ../src/extraGtkFunctions/gtk_fieldChooser.c:217 msgid "Fit box to surfaces" msgstr "Adapter la la boîte de rendu à la définition des surfaces." #: ../src/extraGtkFunctions/gtk_fieldChooser.c:219 msgid "Makes the current bounding box fit to the surfaces." msgstr "" "Modifie la définition de la boîte de rendu atomique pour lui faire " "correspondre celle des surfaces." #. Autodetect failed, no format match the given filename #: ../src/extraGtkFunctions/gtk_fieldChooser.c:266 msgid "Opening a file" msgstr "Ouverture d'un fichier" #: ../src/extraGtkFunctions/gtk_orientationChooser.c:288 msgid "Update values on the fly." msgstr "Met les données à jour à la volée." #: ../src/extraGtkFunctions/gtk_orientationChooser.c:348 msgid "Choose an orientation" msgstr "Choix d'une orientation" #: ../src/extraGtkFunctions/gtk_orientationChooser.c:365 msgid "On an orthonormal basis set" msgstr "Dans un repère orthonormal" #: ../src/extraGtkFunctions/gtk_orientationChooser.c:390 msgid "Following the box basis set" msgstr "Selon le repère de la boîte" #: ../src/extraGtkFunctions/gtk_orientationChooser.c:414 msgid "On a spherical basis set" msgstr "Dans un repère sphérique" #: ../src/extraGtkFunctions/gtk_valueIOWidget.c:274 msgid "V_Sim value file (*.xml)" msgstr "Fichier de valeurs V_Sim (*.xml)" #: ../src/extraGtkFunctions/gtk_valueIOWidget.c:280 #: ../src/extraGtkFunctions/gtk_valueIOWidget.c:286 msgid "Open a V_Sim value file" msgstr "Ouvre un fichier de données V_Sim" #. The label. #: ../src/extraGtkFunctions/gtk_valueIOWidget.c:308 msgid "I/O:" msgstr "E/S :" #: ../src/extraGtkFunctions/gtk_valueIOWidget.c:436 msgid "Import V_Sim values from a file." msgstr "Importe des données V_Sim depuis un fichier XML existant." #: ../src/extraGtkFunctions/gtk_valueIOWidget.c:509 #: ../src/extraGtkFunctions/gtk_valueIOWidget.c:561 #: ../src/extraGtkFunctions/gtk_valueIOWidget.c:667 msgid "Export V_Sim values to a file." msgstr "Exporte les données V_Sim dans un fichier." #: ../src/extraGtkFunctions/gtk_valueIOWidget.c:523 msgid "V_Sim value files (*.xml)" msgstr "Fichier de valeurs V_Sim (*.xml)" #: ../src/extraGtkFunctions/gtk_valueIOWidget.c:533 msgid "values.xml" msgstr "valeurs.xml" #: ../src/renderingMethods/elementAtomic.c:255 msgid "Sphere" msgstr "Sphère" #: ../src/renderingMethods/elementAtomic.c:256 msgid "Cube" msgstr "Cube" #: ../src/renderingMethods/elementAtomic.c:257 #: ../src/renderingMethods/elementSpin.c:779 msgid "Elipsoid" msgstr "Ellipsoïde" #: ../src/renderingMethods/elementAtomic.c:258 msgid "Point" msgstr "Point" #: ../src/renderingMethods/elementAtomic.c:259 #: ../src/renderingMethods/elementSpin.c:780 msgid "Torus" msgstr "Tore" #: ../src/renderingMethods/spinMethod.c:131 msgid "Theta angle" msgstr "Théta" #: ../src/renderingMethods/spinMethod.c:132 msgid "The theta angle to orientate the colourisation cone." msgstr "L'angle théta permettant d'orienter le cone de colorisation." #: ../src/renderingMethods/spinMethod.c:142 msgid "Phi angle" msgstr "Phi" #: ../src/renderingMethods/spinMethod.c:143 msgid "The phi angle to orientate the colourisation cone." msgstr "L'angle phi permettant d'orienter le cone de colorisation." #: ../src/renderingMethods/spinMethod.c:153 msgid "Omega angle" msgstr "Oméga" #: ../src/renderingMethods/spinMethod.c:154 msgid "The omega angle to orientate the colourisation cone." msgstr "L'angle oméga permettant d'orienter le cone de colorisation." #: ../src/renderingMethods/spinMethod.c:164 msgid "Hiding policy for null modulus" msgstr "Mode de masquage lorsque le spin est de module nul" #: ../src/renderingMethods/spinMethod.c:165 msgid "The hiding policy for spin with a null modulus." msgstr "Le mode de masquage lorsque le spin est de module nul." #: ../src/renderingMethods/spinMethod.c:176 msgid "Scaling of spin depending on modulus value" msgstr "Mise à l'échelle selon le module du spin" #: ../src/renderingMethods/spinMethod.c:177 msgid "The scaling policy based on modulus value." msgstr "Le mode de mise à l'échelle suivant le module du spin." #: ../src/renderingMethods/spinMethod.c:188 msgid "Use atomic rendering" msgstr "Utilisation du rendu atomique" #: ../src/renderingMethods/spinMethod.c:189 msgid "If atomic rendering is used in addition to spin rendering." msgstr "Le rendu atomique est utilisé en plus du spin." #: ../src/renderingMethods/spinMethod.c:531 #, c-format msgid "Unknown flag '%s', value ignored." msgstr "Étiquette « %s » inconnue, valeur ignorée." #: ../src/renderingMethods/elementSpin.c:777 msgid "Rounded arrow" msgstr "Flèches arrondies" #: ../src/renderingMethods/elementSpin.c:778 msgid "Edged arrow" msgstr "Flèches carrées" #: ../src/visu_dataatomic.c:261 msgid "Position files" msgstr "Fichiers de position" #: ../src/visu_dataatomic.c:375 ../src/visu_dataspin.c:372 #, c-format msgid "Impossible to load '%s', unrecognised format.\n" msgstr "Impossible d'ouvrir le fichier « %s », format non reconnu.\n" #: ../src/visu_dataatomic.c:428 ../src/visu_dataatomic.c:432 msgid "Forces" msgstr "Forces" #: ../src/visu_configFile.c:1031 #, c-format msgid "%d boolean value(s) should appear here" msgstr "%d valeur(s) booléenne(s) sont attendue(s)" #: ../src/visu_configFile.c:1040 #, c-format msgid "%d boolean value(s) should appear here but %d has been found" msgstr "%d valeur(s) booléenne(s) sont attendue(s) mais %d ont été lues" #: ../src/visu_configFile.c:1082 #, c-format msgid "%d integer value(s) should appear here" msgstr "%d valeur(s) entière(s) sont attendue(s)" #: ../src/visu_configFile.c:1091 #, c-format msgid "%d integer value(s) should appear here but %d has been found" msgstr "%d valeur(s) entière(s) sont attendue(s) mais %d ont été lues" #: ../src/visu_configFile.c:1100 #, c-format msgid "wrong range (%d <= v <= %d) for the %s markup" msgstr "mauvais encadrement (%d <= v <= %d) pour le marqueur %s" #: ../src/visu_configFile.c:1175 #, c-format msgid "%d floating point values should appear here" msgstr " %d valeurs réelles sont attendues" #: ../src/visu_configFile.c:1184 #, c-format msgid "%d floating point value(s) should appear here but %d has been found" msgstr "%d valeurs réelles sont attendues alors que %d ont été lues" #: ../src/visu_configFile.c:1193 #, c-format msgid "wrong range (%g <= v <= %g) for the %s markup" msgstr "mauvais encadrement (%g <= v <= %g) pour le marqueur %s" #: ../src/visu_configFile.c:1226 #, c-format msgid "missing string for %s markup" msgstr "chaîne manquante pour le marqueur %s" #: ../src/visu_configFile.c:1232 #, c-format msgid "'%s' is not a valid value for %s markup" msgstr "« %s » n'est pas une valeur admises pour le marqueur %s" #: ../src/visu_configFile.c:1307 #, c-format msgid "Parse error at line %d, the tag '%s' is not closed.\n" msgstr "" "Erreur de lecture à la ligne %d : le marqueur « %s » n'est pas fermé.\n" #: ../src/visu_configFile.c:1325 #, c-format msgid "Parse error at line %d, '%s' is an unknown markup.\n" msgstr "Erreur de lecture à la ligne %d : « %s » est un marqueur inconnu.\n" #: ../src/visu_configFile.c:1329 #, c-format msgid "Markup '%s' is obsolete, replaced by '%s'." msgstr "le marqueur « %s » est obsolète, remplacé par « %s »." #: ../src/visu_configFile.c:1339 #, c-format msgid " read line (%s) : '%s'\n" msgstr " lecture de « %s » : « %s »\n" #: ../src/visu_configFile.c:1341 #, c-format msgid " read line : '%s'\n" msgstr " lecture : « %s »\n" #: ../src/visu_configFile.c:1365 #, c-format msgid "Parse error at line %d, %s.\n" msgstr "Erreur de lecture à la ligne %d, %s.\n" #: ../src/visu_configFile.c:1461 #, c-format msgid "Parse error at line %d, '%s' needs %d lines but only %d were read.\n" msgstr "" "Erreur de lecture à la ligne %d : « %s » nécessite %d lignes mais seulement " "%d ont été lues.\n" #: ../src/visu_configFile.c:1488 #, c-format msgid "" "Parse error at line %d, cannot find parenthesis containing the description " "of a shade.\n" msgstr "" "Erreur de lecture à la ligne %d, impossible de trouver les parenthèses " "délimitant la définition d'un dégradé.\n" #: ../src/visu_configFile.c:2347 #, c-format msgid "Parse error at line %d: '%s' is not a valid value for %s markup.\n" msgstr "" "Erreur de lecture à la ligne %d : « %s » est une valeur inconnue pour le " "marqueur %s.\n" #: ../src/visu_configFile.c:2367 #, c-format msgid "" "Parse error at line %d: 1 string value must appear after the %s markup.\n" msgstr "" "Erreur de lecture à la ligne %d : une chaîne de caractères est attendue " "après le marqueur « %s ».\n" #: ../src/visu_configFile.c:2396 #, c-format msgid "" "Parse error at line %d: %d integer values(%d <= v <= %d) must appear after " "the %s markup.\n" msgstr "" "Erreur de lecture à la ligne %d : %d entier(s) (%d <= v <= %d) sont " "attendu(s) après le marqueur « %s ».\n" #: ../src/visu_configFile.c:2427 #, c-format msgid "" "Parse error at line %d: %d floating points (%g <= v <= %g) must appear after " "the %s markup. Read line was '%s'.\n" msgstr "" "Erreur de lecture à la ligne %d: %d valeurs réelles (%g < v <= %g) sont " "attendues après le marqueur « %s ». La ligne lues était « %s ».\n" #: ../src/extensions/mapset.c:548 msgid "Drawing extension for mapSet." msgstr "Extension de dessin pour la carte des couleurs." #: ../src/extensions/box_legend.c:202 msgid "Draw informations related to the box." msgstr "Affiche des informations sur la boîte." #: ../src/extensions/box_legend.c:215 msgid "Box lengths" msgstr "Longueurs des côtés" #: ../src/extensions/fogAndBGColor.c:323 msgid "Set an image as background." msgstr "Dessine l'image fournie en fond." #: ../src/extensions/box.c:456 msgid "Draw a box representing the limit of the area." msgstr "Dessine la boîte entourant les éléments." #: ../src/extensions/box.c:982 #, c-format msgid "x: %7.3f" msgstr "x : %7.3f" #: ../src/extensions/box.c:992 #, c-format msgid "y: %7.3f" msgstr "y : %7.3f" #: ../src/extensions/box.c:1001 #, c-format msgid "z: %7.3f" msgstr "z : %7.3f" #. Long description #: ../src/extensions/surfs.c:570 ../src/panelModules/panelSurfaces.c:2603 msgid "Drawing iso-surfaces" msgstr "Dessiner des iso-surfaces" #: ../src/extensions/maps.c:306 msgid "Drawing extension for maps." msgstr "Extension de dessin pour la carte des couleurs." #: ../src/extensions/infos.c:299 msgid "Draw informations on nodes." msgstr "Affiche des informations sur les nœuds." #: ../src/extensions/geodiff.c:172 msgid "Draw geodiff with vectors." msgstr "Dessine les différences avec des vecteurs." #: ../src/extensions/legend.c:193 msgid "Draw the name and the shape of available elements on screen." msgstr "Dessine le nom des éléments à l'écran." #: ../src/extensions/pairs.c:136 msgid "Bonds" msgstr "Liaisons" #: ../src/extensions/pairs.c:439 msgid "Draw pairs between elements with a criterion of distance." msgstr "Dessine des liaisons selon un critère de distance." #: ../src/extensions/pairs.c:732 #, c-format msgid "the method '%s' is unknown" msgstr "la méthode « %s » est inconnue" #: ../src/extensions/shade.c:259 msgid "Draw the legend of a color shade." msgstr "Dessine la légende pour un dégradé." #: ../src/extensions/planes.c:198 msgid "Draw some planes." msgstr "Dessine des plans." #: ../src/extensions/node_vectors.c:324 msgid "Draw vectors on each nodes." msgstr "Dessine des vecteurs à chaque nœud." #: ../src/extensions/axes.c:738 msgid "Draw {x,y,z} axes." msgstr "Dessine un repère {x, y, z}." #: ../src/extensions/axes.c:1460 msgid "front" msgstr "avant" #: ../src/extensions/axes.c:1474 msgid "back" msgstr "envers" #: ../src/extensions/forces.c:139 msgid "Draw forces with vectors." msgstr "Dessine les forces avec des vecteurs." #: ../src/extensions/paths.c:176 msgid "Representation of paths." msgstr "Repésentation de chemins." #: ../src/extensions/nodes.c:322 msgid "Draw all the nodes." msgstr "Dessiner tous les nœuds." #: ../src/extensions/scale.c:96 #, c-format msgid "Length: %6.2f" msgstr "Longueur : %6.2f" #: ../src/extensions/scale.c:608 msgid "Draw scales in the rendering area." msgstr "Dessine des étiquettes dans la fenêtre de rendu." #: ../src/extensions/marks.c:462 msgid "Draw some marks on element in video inverse." msgstr "Dessine des marques sur les éléments en vidéo inversée." #: ../src/extensions/marks.c:2175 ../src/extraFunctions/pot2surf.c:1781 #: ../src/extraFunctions/geometry.c:683 #, c-format msgid "DTD error: element '%s' should appear only once." msgstr "Erreur de DTD : l'élément « %s » ne peut apparaître qu'une seule fois." #: ../src/extensions/marks.c:2195 ../src/extensions/marks.c:2206 #: ../src/extensions/marks.c:2232 ../src/extensions/marks.c:2266 #: ../src/extensions/marks.c:2277 ../src/extensions/marks.c:2306 #: ../src/extensions/marks.c:2317 ../src/extensions/marks.c:2328 #: ../src/extraFunctions/geometry.c:698 ../src/extraFunctions/geometry.c:732 #: ../src/extraFunctions/geometry.c:793 #, c-format msgid "DTD error: attribute '%s' has an unknown value '%s'." msgstr "Erreur de DTD : l'attribut « %s » a une valeur inconnue « %s »." #: ../src/extensions/marks.c:2218 ../src/extensions/marks.c:2252 #: ../src/extensions/marks.c:2292 ../src/extraFunctions/pot2surf.c:1851 #: ../src/extraFunctions/pot2surf.c:1889 ../src/extraFunctions/planeset.c:977 #: ../src/extraFunctions/planeset.c:1020 ../src/extraFunctions/geometry.c:713 #: ../src/extraFunctions/geometry.c:763 #, c-format msgid "DTD error: parent element '%s' of element '%s' is missing." msgstr "" "Erreur de DTD : l'élément parent « %s » de l'élément « %s » est manquant." #: ../src/extensions/marks.c:2344 ../src/extraFunctions/pot2surf.c:1932 #: ../src/extraFunctions/planeset.c:1046 ../src/extraFunctions/geometry.c:818 #, c-format msgid "Unexpected element '%s'." msgstr "Élément « %s » inattendu." #: ../src/extensions/marks.c:2429 #, c-format msgid "No picked node found." msgstr "Aucun nœud sélectionné" #: ../src/extensions/marks.c:2625 msgid "Marks - classical" msgstr "Marques (normales)" #: ../src/extensions/marks.c:2626 msgid "Draw some marks on element." msgstr "Dessine des marques sur les éléments." #: ../src/extensions/vibrations.c:96 msgid "Draw vibrations with vectors." msgstr "Dessine les vibrations avec des vecteurs." #: ../src/dumpModules/dumpToSVG.c:157 msgid "Scalar Vector Graphic (SVG) file" msgstr "Fichier vectoriel (SVG)" #: ../src/dumpModules/dumpToSVG.c:165 ../src/dumpModules/dumpToSVG.c:182 msgid "Use flat colours for scheme rendering" msgstr "Utilise un rendu plat de couleurs" #: ../src/dumpModules/dumpToSVG.c:174 msgid "Portable Document Format (PDF) file" msgstr "Fichier Portable Document Format (PDF)" #: ../src/dumpModules/dumpToXyz.c:71 msgid "Xyz file (current positions)" msgstr "Fichier xyz (positions courantes)" #: ../src/dumpModules/dumpToXyz.c:79 msgid "Expand the bounding box" msgstr "Étend la boîte" #: ../src/dumpModules/dumpToXyz.c:81 ../src/dumpModules/dumpToYaml.c:86 #: ../src/dumpModules/dumpToAscii.c:90 msgid "Export nodes sorted by elements" msgstr "Exporte les nœuds triés par éléments" #: ../src/dumpModules/dumpToYaml.c:70 msgid "YAML file (current positions)" msgstr "Fichier YAML (positions courantes)" #: ../src/dumpModules/dumpToYaml.c:78 ../src/dumpModules/dumpToAscii.c:80 msgid "Don't output hidden nodes" msgstr "Ne pas exporter les nœuds cachés" #: ../src/dumpModules/dumpToYaml.c:80 ../src/dumpModules/dumpToAscii.c:82 msgid "Comment hidden nodes (if output)" msgstr "Exporte les nœuds cachés sous forme de commentaires" #: ../src/dumpModules/dumpToYaml.c:82 ../src/dumpModules/dumpToAscii.c:84 msgid "Keep primitive box (in case of node expansion)" msgstr "Conserve la boîte d'origine (dans le cas d'extension de la boîte)" #: ../src/dumpModules/dumpToYaml.c:84 ../src/dumpModules/dumpToAscii.c:86 #: ../src/dumpModules/dumpToABINIT.c:79 msgid "Export positions in reduced coordinates" msgstr "Exporte les positions en coordonnées réduites" #: ../src/dumpModules/dumpToAscii.c:72 msgid "ASCII file (current positions)" msgstr "Fichier ASCII (positions courantes)" #: ../src/dumpModules/dumpToAscii.c:88 ../src/dumpModules/dumpToABINIT.c:81 msgid "Export box as lengths and angles" msgstr "Exporte la boîte en longueurs et angles" #: ../src/dumpModules/dumpToTiff.c:76 msgid "Tiff file" msgstr "Format Tiff" #: ../src/dumpModules/dumpToTiff.c:682 ../src/dumpModules/dumpToPsAndPdf.c:346 #: ../src/dumpModules/dumpToPsAndPdf.c:481 #: ../src/dumpModules/dumpThroughGdkPixbuf.c:138 #: ../src/dumpModules/dumpToGif.c:842 #, c-format msgid "Can't dump OpenGL area to data.\n" msgstr "Impossible de copier la zone OpenGL vers un tampon de données.\n" #: ../src/dumpModules/dumpToTiff.c:698 ../src/dumpModules/dumpToPsAndPdf.c:386 #: ../src/dumpModules/dumpToPsAndPdf.c:496 #: ../src/dumpModules/dumpToPsAndPdf.c:655 ../src/dumpModules/dumpToGif.c:856 #, c-format msgid "Cannot open file (to write in)." msgstr "Impossible d'ouvrir le fichier en écriture." #: ../src/dumpModules/dumpToPsAndPdf.c:107 msgid "Bitmap in a postscript (v3.0) file" msgstr "Image dans un Postscript (v3.0)" #: ../src/dumpModules/dumpToPsAndPdf.c:118 msgid "Use a reduced colormap (256 colors)" msgstr "Réduction du nombre de couleur (256 couleurs)" #: ../src/dumpModules/dumpToPsAndPdf.c:126 msgid "Bitmap in a PDF (v. 1.2)" msgstr "Image dans un PDF (v1.2)" #: ../src/dumpModules/dumpThroughGdkPixbuf.c:80 msgid "Png file" msgstr "Fichier PNG" #: ../src/dumpModules/dumpThroughGdkPixbuf.c:95 msgid "Jpeg file" msgstr "Fichiers JPEG" #: ../src/dumpModules/dumpThroughGdkPixbuf.c:98 msgid "Compression ratio (given in percent)" msgstr "Taux de compression (en pourcent)" #: ../src/dumpModules/dumpThroughGdkPixbuf.c:154 #, c-format msgid "Cannot convert pixmap to pixbuf." msgstr "Impossible de convertir le pixmap en pixbuf." #: ../src/dumpModules/dumpToABINIT.c:71 msgid "ABINIT file (crystal only)" msgstr "Fichier ABINIT (partie cristal)" #: ../src/dumpModules/dumpToGif.c:225 #, c-format msgid "Unable to quantize image, initialisation failed for node child %d." msgstr "Impossible de passer en couleurs indexées pour le nœud fils %d." #: ../src/dumpModules/dumpToGif.c:452 #, c-format msgid "Unable to quantize image, initialisation failed." msgstr "Impossible de passer en couleurs indexées, erreur à l'initialisation." #: ../src/dumpModules/dumpToGif.c:812 msgid "Gif (256 colors) file" msgstr "Gif (256 couleurs)" #: ../src/dumpModules/dumpToGif.c:930 #, c-format msgid "Fail to compress the GIF file." msgstr "Impossible de compresser le fichier GIF." #: ../src/visu_commandLine.c:198 msgid "" "V_Sim is a software to visualize atomic structures with OpenGl rendering.\n" "\n" msgstr "" "V_Sim est un outil de visualisation des structures atomiques utilisant un " "rendu OpenGL.\n" "\n" #: ../src/visu_commandLine.c:200 msgid "usage:" msgstr "utilisation :" #: ../src/visu_commandLine.c:233 #, c-format msgid "" "(Default value: %s)\n" "\n" msgstr "" "(Valeur par défaut : %s)\n" "\n" #: ../src/visu_commandLine.c:235 msgid "" "(Default value: unset)\n" "\n" msgstr "" "(Valeur par défaut : non définie)\n" "\n" #: ../src/visu_commandLine.c:269 msgid "" "make an image from the fileToRender argument. The format is specified " "through the extension of the argument or by the -o fileFormatId=id option " "(get the id of available file formats with -o list)." msgstr "" "créer une image depuis l'argument fileToRender. Le format est spécifié grâce " "à l'extension du fichier file passé en paramètre ou par l'option -o " "fileFormatId=id (la liste des formats de fichiers est donnée par -o list)." #: ../src/visu_commandLine.c:273 ../src/visu_commandLine.c:277 #: ../src/visu_commandLine.c:290 ../src/visu_commandLine.c:335 #: ../src/visu_commandLine.c:351 ../src/visu_commandLine.c:376 #: ../src/visu_commandLine.c:397 ../src/visu_commandLine.c:415 msgid "file" msgstr "fichier" #: ../src/visu_commandLine.c:275 msgid "" "load the given resources file on startup instead of looking for a valid " "resources file in the standard locations." msgstr "" "charge le fichier de ressources indiqué à la place d'en chercher un parmi " "les emplacements habituels." #: ../src/visu_commandLine.c:279 msgid "show this little help." msgstr "affiche cette petite aide." #: ../src/visu_commandLine.c:282 msgid "" "specify the size of the rendering window, the size argument must have the " "following format: x with positive non null values." msgstr "" "indique la taille de la fenêtre de rendu, l'argument taille doit avoir le " "format suivant : x avec des valeurs strictement positives." #: ../src/visu_commandLine.c:285 msgid "x" msgstr "x" #: ../src/visu_commandLine.c:287 msgid "" "use the given argument as a spin indicator. If this option is used, V_Sim " "switches automatically to spin rendering whatever method is specified in the " "parameter file." msgstr "" "utilise le fichier fourni comme descriptif du spin. Lorsque cette option est " "utilisée, V_Sim passe automatiquement en mode spin qu'elle que soit la " "méthode de rendue spécifiée dans le fichier de paramètre." #: ../src/visu_commandLine.c:292 msgid "" "policy used to show or not null modulus spins possible values are positives." msgstr "" "comportement de traitement des spins de module nul (les valeurs attendues " "sont positives)." #. make and add the first column to the view #: ../src/visu_commandLine.c:294 ../src/visu_commandLine.c:316 #: ../src/visu_commandLine.c:362 ../src/visu_commandLine.c:412 #: ../src/panelModules/panelVibration.c:220 msgid "id" msgstr "id" #: ../src/visu_commandLine.c:296 msgid "" "always draws atomic rendering on node position in addition to spin rendering." msgstr "toujours dessiner les atomes en plus du rendu de spin." #: ../src/visu_commandLine.c:300 msgid "" "the argument fileToRender must be called, then the given file of the option " "is used to colorize the elements. If argument is starting with 'property#', " "colorization data are taken from node property propName." msgstr "" "l'argument fichierÀDessiner doit être présent, ensuite, l'argument fichier " "est utilisé pour coloriser les éléments. Si l'argument commence par " "« property# », la colorisation est faite à partir de la propriété nommée " "nomProp." #: ../src/visu_commandLine.c:304 msgid "{file,property#propName}" msgstr "{fichier,property#nomProp}" #: ../src/visu_commandLine.c:306 msgid "" "it specifies the columns to use from the data file for the three colour " "channels [l;m;n]. Columns are counted from 1. Use -3, -2, -1 and 0 to use " "the special values, constant 1, coord. x, coord. y, and coord. z, " "respectively." msgstr "" "l, m et n correspondent aux numéros des colonnes à utiliser depuis le " "fichier de données pour les trois canaux de couleur. Les colonnes sont " "numérotées depuis 1. Utilisez -3, -2, -1 et 0 pour obtenir des valeurs " "particulières, la constante 1., coord. x, coord. y et coord. z " "respectivement." #: ../src/visu_commandLine.c:312 msgid "" "this option can be used with the '--colorize' one or the '--build-map' one. " "It chooses a preset color scheme. The id argument is an integer that " "corresponds to a defined color shade (ranging from 0)." msgstr "" "l'option « --colorize » doit être présente, ou bien l'option « --build-map " "». Cette option permet de choisir un dégradé. L'argument id est un entier " "correspondant à un dégradé pré-défini (numéroté depuis 0)." #: ../src/visu_commandLine.c:318 msgid "" "a file must be loaded. It applies the given translations to the loaded file. " "The units are those of the file. This is available for periodic file formats " "only." msgstr "" "l'argument fichierÀDessiner doit être présent, la translation donnée est " "alors appliquée. L'unité utilisée est celle contenu dans le fichier à " "dessiner. Les translations ne sont possibles que pour les formats " "périodiques." #: ../src/visu_commandLine.c:323 msgid "" "a file must be loaded. It applies the given translations to the loaded file. " "The translation is applied along box axis, normalised to 1. This is " "available for periodic file formats only." msgstr "" "l'argument fichierÀDessiner doit être présent, la translation donnée est " "alors appliquée. La translation est appliquée le long des axes de la boîte " "en coordonnées réduites. Les translations ne sont possibles que pour les " "formats périodiques." #: ../src/visu_commandLine.c:328 msgid "" "a file must be loaded. It applies the given expansion to the loaded file. " "The values are given in box coordinates. This is available for periodic file " "formats only." msgstr "" "l'argument fichierÀDessiner doit être présent, l'expansion donnée est alors " "appliquée. Les valeurs sont données en unité de boîte. Les translations ne " "sont possibles que pour les formats périodiques." #: ../src/visu_commandLine.c:333 msgid "" "the argument fileToRender must be called, then the given file of the option " "is parsed as a list of planes and they are rendered." msgstr "" "l'argument fichierÀDessiner doit être présent, l'argument fichier est alors " "analysé comme une liste de plans devant être dessinée." #: ../src/visu_commandLine.c:337 msgid "" "the argument fileToRender must be called, then the given file of the option " "is parsed as a scalar field and loaded. Use '.' as a special value to reuse " "the main filename." msgstr "" "l'argument fichierÀDessiner doit être présent, l'argument file est alors " "chargé en tant que champ scalaire. On peut utiliser le « . » pour " "indiquerd'utiliser le fichier principal." #: ../src/visu_commandLine.c:340 msgid "{file,.}" msgstr "{fichier,.}" #: ../src/visu_commandLine.c:342 msgid "" "must be used with the '--scalar-field' option, then the given surfaces are " "built and rendered. If a name is appended to a value using '#' as a " "separator, this name is used as the name for the iso-surface (i.e. " "0.25#Blue). Use specific value 'auto' to compute isosurfaces at half max and " "min value." msgstr "" "doit être utilisé avec l'option '--scalar-field', dans ce cas, les surfaces " "correspondantes sont générées et affichées. Si une chaîne est ajoutée après " "une valeur à la suite d'un caractère '#' séparateur, cette chaîne est " "utilisée pour nommer la surface (et appliquer éventuellement un style), par " "exemple 0.25#Bleu. La valeur particulière « auto » peut être utilisée " "pour calculer des isosurfaces dont la valeur est la moyenne du min et du max." #: ../src/visu_commandLine.c:349 msgid "" "the argument fileToRender must be given, then the given file of the option " "is parsed and surfaces are rendered." msgstr "" "l'argument fichierÀDessiner doit être présent, l'argument file est alors " "chargé en tant que liste de surfaces." #: ../src/visu_commandLine.c:353 msgid "" "the argument fileToRender must be given, as the '--planes', '--color-preset' " "and '--scalar-field' options used, then the given plane 'id' is replaced by " "a coloured map using given scalar field and shade. 'id' ranges from 0. If " "several ids are given, several maps are built." msgstr "" "l'argument fichierÀDessiner doit être présent, tout comme les arguments '--" "planes', '--color-preset' et '--scalar-field', dans ce cas, le plan 'id' par " "une carte de couleur représentant le champ scalaire fourni dans le dégradé " "spécifié. 'id' varie de 0 au nombre de plans moins 1. Si plusieurs id " "sontdonnés, plusieurs cartes seront dessinées." #: ../src/visu_commandLine.c:358 msgid "id[:id]" msgstr "id[:id]" #: ../src/visu_commandLine.c:360 msgid "" "select the scaling method to use with gradients (0: linear, 1: log scaled " "and 2 is zero-centred log scale), default is linear scale." msgstr "" "choix de la méthode de mise à l'échelle pour les dégradés (0 : linéaire, 1 : " "logarithmique et 2 : logarithmique centré sur zéro), la valeur par défaut " "est linéaire." #: ../src/visu_commandLine.c:364 msgid "when positive, val isolines are plotted on the coloured map." msgstr "" "si la valeur est positive, val isolignes sont tracées sur la carte des " "couleurs." #: ../src/visu_commandLine.c:365 ../src/visu_commandLine.c:373 msgid "val" msgstr "val" #: ../src/visu_commandLine.c:367 msgid "" "when given, generated iso-lines are colourised [R:G:B] or auto with the " "values. The specific value 'auto' will produced iso-lines in inversed " "colours." msgstr "" "lorsqu'elle est utilisée, cette option permet de choisir la couleur [R:V:B] " "des iso-lignes tracées. La valeur particulière « auto » permet de tracer ces " "iso-lignes en couleurs inverses." #: ../src/visu_commandLine.c:370 msgid "[R:G:B] or auto" msgstr "[R:V:B] ou auto" #: ../src/visu_commandLine.c:372 msgid "if val is not TRUE, the surfaces use their own bounding box." msgstr "" "si la valeur n'est pas TRUE, les surfaces utilisent leur propre boîte (la " "valeur par défault est TRUE)." #: ../src/visu_commandLine.c:375 msgid "draw the given image on the background." msgstr "dessine l'image fournie en fond." #: ../src/visu_commandLine.c:378 msgid "" "this is a generic way to give extended option. to V_Sim. As much as -o can " "be used. Each one store a key and its value (boolean, integer or float)." msgstr "" "c'est une façon générique de fournir une option à V_Sim. On peut utiliser " "autant de -o que nécessaire, chacune associe une valeur (entière, booléenne " "ou flottante) à une clef." #: ../src/visu_commandLine.c:381 msgid "id=value" msgstr "id=valeur" #: ../src/visu_commandLine.c:383 msgid "" "used to choose the windowing mode. By default the command panel and the " "rendering window are separated. In the 'oneWindow' mode they are joined. In " "the 'renderOnly' mode, the command panel is not used." msgstr "" "cette option est utilisée pour choisir le mode de fenêtrage. Par défaut, la " "fenêtre de rendu et le panneau de commande sont séparées. Dans le mode " "« oneWindow », elles sont communes. Dans le mode « renderOnly », le panneau " "de commande n'est pas utilisé." #: ../src/visu_commandLine.c:387 ../src/visu_commandLine.c:418 #: ../src/panelModules/panelOpenGL.c:344 msgid "mode" msgstr "mode" #: ../src/visu_commandLine.c:389 msgid "" "this flag is used to choose the id of the loaded file if the format has " "support for multiple ids in one file (see XYZ format or -posi.d3 ones)." msgstr "" "cette option est utilisée pour choisir la série de données à charger lorsque " "le format de fichier d'entrée permet plusieurs séries de données (comme le " "format XYZ ou les fichiers -posi.d3)." #: ../src/visu_commandLine.c:392 msgid "i" msgstr "i" #: ../src/visu_commandLine.c:394 msgid "" "specify an XML file with some value information for V_Sim, like a list of " "planes, highlighted nodes... It replaces and extend the previous --planes " "option." msgstr "" "définit un fichier XML à charger contenant plusieurs informations pour " "V_Sim, comme une liste de plans, les nœuds mis en évidence… Elle remplace et " "étend les possibilités de l'option --planes." #: ../src/visu_commandLine.c:399 msgid "Give the precision in percent to render the coloured map." msgstr "Donne la précision en pourcent pour le dessin des cartes de couleur." #: ../src/visu_commandLine.c:400 msgid "prec" msgstr "préc" #: ../src/visu_commandLine.c:402 msgid "Set the minimum and maximum values for the coloured map rendering." msgstr "" "Choisi les valeurs minimum et maximum pour la mise à l'échelle des valeurs " "des cartes de couleurs." #: ../src/visu_commandLine.c:403 msgid "min:max or auto" msgstr "min:max ou auto" #: ../src/visu_commandLine.c:405 msgid "" "Range to adjust values into for colourisation. col specifiesthe column to " "apply the range to. Use -2, -1 and 0 for x, yand z directions respectively." msgstr "" "Encadrement pour ajuster les valeurs de colorisation. col permet de donner " "l'identifiant de la colonne à utiliser. -2, -1 et 0 servent respectivement " "pour les directions x, y et z." #: ../src/visu_commandLine.c:408 msgid "col#min:max or auto" msgstr "col#min:max ou auto" #: ../src/visu_commandLine.c:410 msgid "" "used with a data file (see -c), it specifies the column id to be used to " "scale the nodes." msgstr "" "utilisé avec un fichier de colorisation (voir -c), spécifie la colonne à " "utiliser pour faire varier la taille des nœuds." #: ../src/visu_commandLine.c:414 msgid "Compute the geometric difference between load file and this argument." msgstr "" "Calcule les différences de géométrie entre le fichier chargé et cet argument." #: ../src/visu_commandLine.c:417 msgid "Load the given phonon mode." msgstr "Charge le mode phonon indiqué." #: ../src/visu_commandLine.c:420 msgid "Displace nodes according to phonons at the given reduced time in [0;1]." msgstr "" "Déplace les nœuds suivant le mode de phonon au temps réduit donné dans [0;1]." #: ../src/visu_commandLine.c:421 msgid "offset" msgstr "décalage" #: ../src/visu_commandLine.c:423 msgid "Maximum displacement for phonons." msgstr "Déplacement maximum des phonons." #: ../src/visu_commandLine.c:424 msgid "ampl" msgstr "ampl." #: ../src/support.h:58 msgid "_Save" msgstr "_Sauvegarde" #: ../src/support.h:59 msgid "_Open" msgstr "_Ouvrir" #: ../src/coreTools/toolArray.c:193 msgid "" "Can't find any columns with numbers.\n" "Valid format are as much numbers as desired, separated by any of the " "following characters : [ ;:\\t].\n" msgstr "" "Le nombre de colonnes est impossible à déterminé.\n" "Une ligne valide contient autant d'informations numériques que nécessaire, " "séparées par les caractères suivants : [ ;:\\t].\n" #: ../src/coreTools/toolArray.c:230 #, c-format msgid "There is a different number of data (%d) compared to expected (%d).\n" msgstr "" "Il y a une différence entre le nombre de données (%d) et la valeur attendues " "(%d).\n" #: ../src/coreTools/toolColor.c:388 ../src/coreTools/toolShade.c:838 #, c-format msgid "cannot read a color from '%s' (name, #rgb, #rrggbb ... awaited).\n" msgstr "" "impossible de lire une couleur depuis « %s » (nom, #rgb, #rrggbb … " "attendus).\n" #: ../src/coreTools/toolFiles.c:197 #, c-format msgid "cannot read next archive entry.\n" msgstr "impossible de lire l'entrée suivante de l'archive.\n" #: ../src/coreTools/toolFiles.c:212 #, c-format msgid "Format not supported." msgstr "" #: ../src/coreTools/toolFiles.c:268 #, c-format msgid "read error from archive.\n" msgstr "erreur de lecture de l'archive.\n" #: ../src/coreTools/toolFiles.c:346 ../src/coreTools/toolFiles.c:403 #: ../src/coreTools/toolFiles.c:492 ../src/coreTools/toolFiles.c:527 #, c-format msgid "file not opened.\n" msgstr "fichier non ouvert.\n" #: ../src/coreTools/toolShade.c:705 msgid "blue to red" msgstr "du bleu au rouge" #: ../src/coreTools/toolShade.c:716 msgid "hot color" msgstr "couleurs chaudes" #: ../src/coreTools/toolShade.c:727 msgid "blue to yellow" msgstr "du bleu au jaune" #: ../src/coreTools/toolShade.c:738 msgid "zero centred dark" msgstr "centré en zéro, sombre" #. Create a blue and red shade with withe zero centred. #: ../src/coreTools/toolShade.c:743 msgid "zero centred light" msgstr "centré en zéro, claire" #: ../src/coreTools/toolShade.c:748 msgid "zero centred coloured" msgstr "centré en zéro, coloré" #: ../src/coreTools/toolShade.c:760 msgid "green to red" msgstr "du vert au rouge" #: ../src/coreTools/toolShade.c:771 msgid "light green to red" msgstr "du vert pâle au rouge" #: ../src/coreTools/toolShade.c:782 msgid "black to white" msgstr "du noir au blanc" #: ../src/coreTools/toolShade.c:793 msgid "white to black" msgstr "du blanc au noir" #: ../src/coreTools/toolShade.c:804 msgid "purple color" msgstr "couleur mauve" #. Create the so-called Jet colour map. #: ../src/coreTools/toolShade.c:809 msgid "Jet map" msgstr "dégradé Jet" #: ../src/coreTools/toolShade.c:826 #, c-format msgid "1 floating point value should start a step '%s'.\n" msgstr "une valeur réelle doit démarer une étape « %s ».\n" #: ../src/coreTools/toolFileFormat.c:157 ../src/gtk_about.c:354 msgid "Name" msgstr "Nom" #: ../src/coreTools/toolFileFormat.c:157 msgid "File format description." msgstr "Description du format de fichier." #: ../src/coreTools/toolFileFormat.c:168 msgid "Label used to show the file pattern." msgstr "Étiquette utilisée pour représenter le format de fichier." #: ../src/coreTools/toolFileFormat.c:180 msgid "Ignore file patterns" msgstr "Ignore le format de fichier." #: ../src/coreTools/toolFileFormat.c:181 msgid "Don't restrict file matching to the given patterns." msgstr "Ne limite pas la recherche au format de fichier donné." #: ../src/coreTools/toolConfigFile.c:109 #, c-format msgid "Parse error at line %d, %d floating point values should appear here.\n" msgstr "Erreur de lecture à la ligne %d : %d valeurs réelles sont attendues.\n" #: ../src/coreTools/toolConfigFile.c:122 #, c-format msgid "" "Parse error at line %d, %d floating point value(s) should appear here but %d " "has been found.\n" msgstr "" "Erreur de lecture à la ligne %d : %d valeurs réelles sont attendues alors " "que %d ont été lues.\n" #: ../src/coreTools/toolConfigFile.c:193 #, c-format msgid "Parse error at line %d, %d boolean values should appear here.\n" msgstr "" "Erreur de lecture à la ligne %d : %d valeur(s) booléenne(s) sont " "attendue(s).\n" #: ../src/coreTools/toolConfigFile.c:206 #, c-format msgid "" "Parse error at line %d, %d boolean(s) values should appear here but %d has " "been found.\n" msgstr "" "Erreur de lecture à la ligne %d : %d valeur(s) booléenne(s) sont attendue(s) " "mais %d ont été lues.\n" #: ../src/coreTools/toolConfigFile.c:278 ../src/coreTools/toolConfigFile.c:332 #, c-format msgid "" "Parse error at line %d, %d string(s) should appear here but %d has been " "found.\n" msgstr "" "Erreur de lecture à la ligne %d : %d chaînes de caractères sont attendues " "mais %d ont été lues.\n" #: ../src/coreTools/toolConfigFile.c:383 ../src/coreTools/toolConfigFile.c:432 #, c-format msgid "" "Parse error at line %d, a label should appear here but none has been found.\n" msgstr "" "Erreur de lecture à la ligne %d : une étiquette devrait être placée là, mais " "aucune n'a été trouvée.\n" #: ../src/coreTools/toolConfigFile.c:504 #, c-format msgid "Parse error at line %d, %d integer values should appear here.\n" msgstr "" "Erreur de lecture à la ligne %d : %d valeur(s) entière(s) sont attendue(s).\n" #: ../src/coreTools/toolConfigFile.c:517 #, c-format msgid "" "Parse error at line %d, %d integer(s) values should appear here but %d has " "been found.\n" msgstr "" "Erreur de lecture à la ligne %d : %d valeur(s) entière(s) sont attendue(s) " "mais %d ont été lues.\n" #: ../src/coreTools/toolFortran.c:444 #, c-format msgid "wrong fortran syntax, flag size unmatched (%ld != %ld).\n" msgstr "syntaxe Fortran incorrecte, la taille des repères diffère (%ld != %ld).\n" #: ../src/gtk_main.c:361 msgid "Actions" msgstr "Actions" #: ../src/gtk_main.c:375 msgid "Select a file to render." msgstr "Ouvrir un fichier." #: ../src/gtk_main.c:386 msgid "Check to draw pairs between elements." msgstr "Cocher cette case pour dessiner des liaisons entre les éléments" #: ../src/gtk_main.c:393 msgid "Configure parameters for bindings such as color, thickness..." msgstr "Configurer les paramètres des liaisons (couleurs…)" #: ../src/gtk_main.c:401 msgid "_Pairs" msgstr "_Liaisons" #: ../src/gtk_main.c:409 msgid "Use the mouse to change the view and get position informations." msgstr "Sélectionner les éléments et changer la vue grâce à la souris." #: ../src/gtk_main.c:417 msgid "Mouse _actions" msgstr "_Interactions" #: ../src/gtk_main.c:427 msgid "Click to save the parameters or the resources." msgstr "Enregistrer la configuration ou les ressources." #: ../src/gtk_main.c:435 msgid "_Config. files" msgstr "Fichiers de _conf." #: ../src/gtk_main.c:445 msgid "V_Sim program. Written by L. Billard, modified by D. Caliste." msgstr "V_Sim, écrit par L. Billard et modifié par D. Caliste." #: ../src/gtk_main.c:689 msgid "Choose a directory" msgstr "Sélectionner un répertoire" #: ../src/gtk_main.c:707 msgid "" "Choose several directories using the Control key." msgstr "" "Sélectionnez plusieurs répertoires en utilisant la " "touche Control." #. Failed. #: ../src/gtk_main.c:1101 msgid "I/O" msgstr "E/S" #: ../src/gtk_main.c:1102 msgid "Can't create the directory '$XDG_CONFIG_HOME/v_sim'." msgstr "Impossible de créer le répertoire « $XDG_CONFIG_HOME/v_sim »." #: ../src/gtk_main.c:1238 #, c-format msgid "Parse error at line %d: awaited 'id visible pos size'.\n" msgstr "" "Erreur de lecture à la ligne %d : « id visible pos. taille » est attendu.\n" #: ../src/gtk_main.c:1249 #, c-format msgid "" "Parse error at line %d: can't read dock characteristic values from '%s'.\n" msgstr "" "Erreur de lecture à la ligne %d : impossible de lire les caractéristiques " "de l'onglet depuis « %s ».\n" #: ../src/gtk_main.c:1337 msgid "Command line actions" msgstr "Actions en ligne de commande" #: ../src/gtk_main.c:1338 ../src/panelModules/panelSurfaces.c:1089 msgid "Unknown error" msgstr "Erreur inconnue" #: ../src/interface.c:79 msgid "Save session" msgstr "Sauvegarder la configuration" #: ../src/interface.c:110 msgid "Manage configuration files" msgstr "" "Gestion des fichiers de configuration" #: ../src/interface.c:135 msgid "Load from file" msgstr "Charger depuis un fichier" #: ../src/interface.c:164 ../src/interface.c:239 msgid "Save to file" msgstr "Enregistrer dans un fichier" #: ../src/interface.c:186 msgid "Export resources related to rendered file only" msgstr "Exporter uniquement les ressources rattachées au fichier rendu" #: ../src/interface.c:221 msgid "" "Resources (values related to rendering " "aspects)" msgstr "" "Ressources (valeurs relatives aux aspects " "de rendu)" #: ../src/interface.c:275 msgid "" "Parameters (Interface options)" msgstr "" "Paramètres (Options de l'interface)" #: ../src/interface.c:288 msgid "" "When saving, if you just specify a directory 'dir/', it will be save to 'dir/v_sim.[res][par]' by default, ortherwise speficy a " "full path." msgstr "" "Si le nom d'un répertoire « rép/» est donné, les sauvegardes seront faites dans les fichiers " "suivants : « rép/v_sim.[res/par] ». " "Sinon, l'enregistrement est effectué dans le chemin complet fourni." #: ../src/interface.c:297 msgid "" "Tips: think to create a $XDG_CONFIG_HOME/v_sim directory and put your resource " "and parameter files in it. It is scanned at startup." msgstr "" "Astuce : pensez à créer un répertoire nommé " "$XDG_CONFIG_HOME/v_sim et à y placer vos " "fichiers de configuration. Ce répertoire est lu au démarrage." #: ../src/interface.c:315 ../src/interface.c:1024 ../src/interface.c:1645 msgid "Help" msgstr "Aide" #: ../src/interface.c:494 msgid "Pick and observe session" msgstr "Observation ou sélection" #: ../src/interface.c:541 msgid "Observe" msgstr "Observation" #: ../src/interface.c:553 msgid "constrained" msgstr "contraint" #: ../src/interface.c:556 msgid "" "Movement are along meridians when the mouse is dragged along y axis and " "along parallels when the movement is along x axis." msgstr "" "Les mouvements ont lieu le long des méridiens lorsque la souris se déplace " "sur l'axe des y et le long des parallèles lorsque les mouvements de la " "souris sont sur l'axe des x." #: ../src/interface.c:560 msgid "walker" msgstr "marcheur" #: ../src/interface.c:563 msgid "" "Movements are those of a walking ant on a sphere, when mouse move along y " "axis, the ant goes strait on, when mouse is dragged along x axis, the ant " "translates on its right or on its left." msgstr "" "Les mouvements de la caméra suivent ce que verrait une fourmie se déplaçant " "sur une sphère : un mouvement vertical de la souris fait avancer ou reculer " "la caméra alors qu'un mouvement horizontal entraine une translation gauche/" "droite de la caméra." #: ../src/interface.c:578 msgid "Translations" msgstr "Translations" #: ../src/interface.c:584 msgid "Scale" msgstr "Échelle" #: ../src/interface.c:630 msgid "omega:" msgstr "oméga :" #: ../src/interface.c:636 msgid "phi:" msgstr "phi :" #: ../src/interface.c:648 msgid "zoom:" msgstr "zoom :" #: ../src/interface.c:654 msgid "theta:" msgstr "théta :" #: ../src/interface.c:674 msgid "persp.:" msgstr "persp. :" #: ../src/interface.c:725 ../src/interface.c:821 msgid "Pick" msgstr "Sélection à la souris" #: ../src/interface.c:772 msgid "Persistent measures" msgstr "Affiche les mesures" #: ../src/interface.c:780 msgid "Remove all drawn measurements." msgstr "Retirer toutes les mesures affichées." #: ../src/interface.c:801 msgid "Add highlighted nodes to the list below." msgstr "Ajoute les nœuds en évidence à la liste ci-dessous." #: ../src/interface.c:810 msgid "Remove all highlight marks." msgstr "Retire toutes les mise en évidence." #: ../src/interface.c:843 msgid "Modify nodes (position, numbers...)" msgstr "Modification des nœuds (position, nombre…)" #: ../src/interface.c:857 msgid "Move or delete:" msgstr "Déplace ou suppr. :" #: ../src/interface.c:863 msgid "picked _node" msgstr "un _nœud" #: ../src/interface.c:869 msgid "_selected nodes" msgstr "les nœuds _sél." #: ../src/interface.c:881 msgid "" "(selected nodes are listed in the pick tab)" msgstr "" "(les nœuds sélectionnés sont répertoriés dans " "l'onglet de sélection)" #: ../src/interface.c:893 msgid "Specific moving axis:" msgstr "Axe de déplacement particulier :" #: ../src/interface.c:922 msgid "Current pos./trans.:" msgstr "Pos./trans. courante :" #: ../src/interface.c:950 msgid "Add a new node:" msgstr "Ajoute un nouveau nœud :" #: ../src/interface.c:961 msgid "position:" msgstr "position :" #: ../src/interface.c:971 msgid "Screen basis set:" msgstr "Repère de l'écran :" #: ../src/interface.c:977 msgid "horiz." msgstr "horiz." #: ../src/interface.c:988 msgid "vert." msgstr "vert." #: ../src/interface.c:999 msgid "Geometry changes" msgstr "Modifications de géométrie" #: ../src/interface.c:1041 msgid "Back to command panel" msgstr "Retour au panneau principal" #: ../src/interface.c:1190 msgid "About V_Sim" msgstr "À propos de V_Sim" #: ../src/interface.c:1227 msgid "Version :" msgstr "Version :" #: ../src/interface.c:1233 msgid "Release Date :" msgstr "Date de sortie :" #: ../src/interface.c:1239 msgid "Web site :" msgstr "Site web :" #: ../src/interface.c:1286 msgid "Readme" msgstr "Lisez-moi" #: ../src/interface.c:1305 ../src/gtk_about.c:370 msgid "Authors" msgstr "Auteurs" #: ../src/interface.c:1323 msgid "License" msgstr "Licence" #: ../src/interface.c:1331 msgid "Loaded plug-ins:" msgstr "Greffons chargés :" #: ../src/interface.c:1342 msgid "Plug-ins" msgstr "Greffons" #: ../src/interface.c:1360 msgid "Changelog" msgstr "Changements" #: ../src/interface.c:1432 msgid "set and customize pairs" msgstr "Choix et réglage des liaisons." #: ../src/interface.c:1455 msgid "Set parameters for pairs" msgstr "Paramètres des liaisons" #: ../src/interface.c:1492 msgid "Pairs" msgstr "Liaisons" #: ../src/interface.c:1501 msgid "Distances" msgstr "Distances" #: ../src/interface.c:1559 msgid "Quit V_Sim" msgstr "Quitter V_Sim" #: ../src/interface.c:1581 msgid "Quit V_Sim?" msgstr "Quitter V_Sim?" #: ../src/interface.c:1587 msgid "Don't show this warning again." msgstr "Ne plus afficher ce message." #: ../src/interface.c:1599 msgid "" "Can't find a local configuration directory " "$XDG_CONFIG_HOME/v_sim. Should one be added?" msgstr "" "Impossible de trouver le répertoire local de configuration $XDG_CONFIG_HOME/v_sim. Doit-il être ajouté?" #: ../src/interface.c:1618 msgid "" "Can't find a v_sim.par file with " "enough write permissions to store the preference, neither in the " "installation directory nor in the " "$XDG_CONFIG_HOME/v_sim one." msgstr "" "Impossible de trouver un fichier v_sim.par avec des permissions en écriture suffisantes pour enregistrer la " "préférence, ni dans le répertoire d'installation, ni dans le répertoire " "$XDG_CONFIG_HOME/v_sim." #: ../src/interface.c:1629 msgid "" "If you check the above box but you want to have this " "warning dialog again before closing, you can change this by editing the " "parameter file (v_sim.par). The option is " "called 'main_confirmQuit'." msgstr "" "Si après avoir coché la case ci-dessus vous souhaitez " "retrouver ce message d'avertissement, l'option est enregistrée dans le " "fichier de configuration v_sim.par. Elle " "s'appelle « main_confirmQuit »." #: ../src/visu_data.c:1776 msgid "option '--phonon-mode' has been given but no phonons are available." msgstr "l'option « --phonon-mode » nécessite d'avoir des phonons chargés." #: ../src/visu_data.c:1783 msgid "option '--time-opffset' has been given but no phonons are available." msgstr "l'option « --time-offset » nécessite d'avoir des phonons chargés." #: ../src/visu_data.c:1788 msgid "" "option '--phonon-amplitude' has been given but no phonons are available." msgstr "l'option « --phonon-amplitude » nécessite d'avoir des phonons chargés." #. Help message used in the help area. #: ../src/gtk_interactive.c:127 msgid "" "left-[control]-button\t\t\t: rotations (θ, φ, [control]ω)\n" "shift-left-button\t\t\t\t: translations (dx, dy)\n" "middle-[shift]-button or wheel\t: zoom or [shift]perspective\n" "key 's' / 'r'\t\t\t\t\t: save/restore camera position\n" "right-button\t\t\t\t\t: switch to current tabbed action" msgstr "" "[control] bouton gauche\t\t : rotations (θ, φ, [Control]ω)\n" "shift + bouton gauche\t\t\t : translations (dx, dy)\n" "[shift] b. du milieu ou roulette\t : zoom ou [Shift]perspective\n" "touche « s » / « r »\t\t\t\t : sauve/rétablit la vue\n" "bouton droit\t\t\t\t\t : passer à l'action de l'onglet courant" #: ../src/gtk_interactive.c:271 msgid "_Ok" msgstr "_Ok" #. * #. * SECTION: visu_dataspin #. * @short_description: a class of nodes representing spin data and #. * providing associated loading methods. #. * #. * This class provides #VisuDataLoader for spin data representation. #. #: ../src/visu_dataspin.c:55 msgid "Spin (θ, φ, mod.)" msgstr "Spin (θ, φ, mod.)" #: ../src/visu_dataspin.c:105 msgid "Ascii spin files" msgstr "Fichiers ASCII de spin" #: ../src/visu_dataspin.c:108 msgid "Binary spin files" msgstr "Fichiers binaires de spin" #: ../src/visu_dataspin.c:287 msgid "Spin files" msgstr "Fichiers de spin" #: ../src/visu_dataspin.c:519 #, c-format msgid "impossible to open this spin file.\n" msgstr "impossible d'ouvrir ce fichier de spin.\n" #: ../src/visu_dataspin.c:528 #, c-format msgid "spin file should have one line at least.\n" msgstr "un fichier de spin doit contenir au moins une ligne.\n" #: ../src/visu_dataspin.c:614 #, c-format msgid "number of spin differs from number of nodes.\n" msgstr "le nombre de spins est différent du nombre de nœuds.\n" #: ../src/extraFunctions/surfaces.c:702 ../src/extraFunctions/surfaces.c:723 #, c-format msgid "Line %d doesn't match the [float, float, float] pattern." msgstr "La ligne %d ne correspond pas à la forme [réel, réel, réel]." #: ../src/extraFunctions/surfaces.c:746 #, c-format msgid "Line %d doesn't match the [int > 0, int > 0, int > 0] pattern." msgstr "" "La ligne %d ne correspond pas à la forme [entier > 0, entier > 0, entier > " "0]." #: ../src/extraFunctions/surfaces.c:811 #, c-format msgid "Line %d doesn't match the [int > 0, int > 0] pattern." msgstr "La ligne %d ne correspond pas à la forme [entier > 0, entier > 0]." #: ../src/extraFunctions/surfaces.c:825 #, c-format msgid "Error on line %d. Declared number of polygons reached." msgstr "Erreur à la ligne %d. Le nombre de polygones déclaré a été atteint." #: ../src/extraFunctions/surfaces.c:839 #, c-format msgid "Error on line %d. Declared number of points reached." msgstr "Erreur à la ligne %d. Le nombre de points déclaré a été atteint." #: ../src/extraFunctions/surfaces.c:882 #, c-format msgid "Line %dmust begin by an int." msgstr "La ligne %d doit dommencer par un entier." #: ../src/extraFunctions/surfaces.c:899 #, c-format msgid "Line %d doesn't match the [int > 3, ...] required pattern." msgstr "La ligne %d ne correspond pas à la forme [entier > 3, …]." #: ../src/extraFunctions/surfaces.c:943 #, c-format msgid "Line %d doesn't match the [float x 6] required pattern." msgstr "La ligne %d ne correspond pas à la forme [réel x 6]" #: ../src/extraFunctions/nodeProp.c:427 ../src/extraFunctions/nodeProp.c:504 msgid "T" msgstr "V" #: ../src/extraFunctions/nodeProp.c:429 ../src/extraFunctions/nodeProp.c:506 msgid "F" msgstr "F" #: ../src/extraFunctions/coordProp.c:122 msgid "Coord. (x, y, z)" msgstr "Coord. (x, y, z)" #: ../src/extraFunctions/pot2surf.c:990 #, c-format msgid "Negative (%d)" msgstr "Négatif (%d)" #: ../src/extraFunctions/pot2surf.c:1003 #, c-format msgid "Positive (%d)" msgstr "Positif (%d)" #: ../src/extraFunctions/pot2surf.c:1773 ../src/extraFunctions/pot2surf.c:1823 #: ../src/extraFunctions/pot2surf.c:1873 ../src/extraFunctions/pot2surf.c:1921 #: ../src/extraFunctions/planeset.c:891 ../src/extraFunctions/planeset.c:922 #: ../src/extraFunctions/planeset.c:968 ../src/extraFunctions/planeset.c:1010 #: ../src/extraFunctions/planeset.c:1040 #, c-format msgid "Unexpected attribute '%s' for element '%s'." msgstr "Attribut « %s » inattendu pour l'élément « %s »." #: ../src/extraFunctions/pot2surf.c:1811 ../src/extraFunctions/pot2surf.c:1818 #: ../src/extraFunctions/pot2surf.c:1868 ../src/extraFunctions/pot2surf.c:1903 #: ../src/extraFunctions/pot2surf.c:1914 ../src/extraFunctions/planeset.c:916 #: ../src/extraFunctions/planeset.c:953 ../src/extraFunctions/planeset.c:962 #: ../src/extraFunctions/planeset.c:994 ../src/extraFunctions/planeset.c:1005 #: ../src/extraFunctions/planeset.c:1033 #, c-format msgid "Invalid value '%s' for attribute '%s'." msgstr "Valeur incorrecte (« %s ») pour l'attribut « %s »." #: ../src/extraFunctions/pot2surf.c:1836 ../src/extraFunctions/pot2surf.c:1878 #, c-format msgid "Missing attribute '%s' for element '%s'." msgstr "Attribut « %s » manquant pour l'élément « %s »." #: ../src/extraFunctions/pot2surf.c:2022 #, c-format msgid "No iso-value found." msgstr "Aucune iso-valeur trouvée." #: ../src/extraFunctions/planeset.c:939 #, c-format msgid "DTD error : parent element '%s' of element '%s' is missing." msgstr "" "Erreur de DTD : l'élément parent « %s » de l'élément « %s » est manquant." #: ../src/extraFunctions/planeset.c:1068 ../src/extraFunctions/planeset.c:1076 #, c-format msgid "DTD error: missing or wrong child element '%s'." msgstr "Erreur de DTD : élément fils « %s » manquant ou inapproprié." #: ../src/extraFunctions/planeset.c:1143 #, c-format msgid "The file contains no plane.\n" msgstr "Le fichier ne contient pas de plan.\n" #: ../src/extraFunctions/geometry.c:740 ../src/extraFunctions/geometry.c:801 #, c-format msgid "DTD error: element '%s' have missing mandatory attributes." msgstr "Erreur de DTD : l'élément « %s » a des attributs manquants." #: ../src/extraFunctions/geometry.c:871 #, c-format msgid "No paths found." msgstr "Aucun chemin trouvé." #: ../src/extraFunctions/dataFile.c:1464 #, c-format msgid "Colorization from a non existing node property '%s'." msgstr "Colorisation depuis une propriétés inconnues « %s »." #: ../src/extraFunctions/dataFile.c:1468 msgid "Colorization from a node property that is not a float array." msgstr "" "Colorisation depuis une propriété qui n'est pas un tableau de valeurs " "réelles." #: ../src/extraFunctions/dataFile.c:1485 #, c-format msgid "" "Assign a column data without specifying a data file. Use -c option or change " "the value %d." msgstr "" "Fournit une colonne de données sans fichier de colorisation. Utilisez " "l'option -c ou changer la valeur %d." #: ../src/extraFunctions/shellProp.c:234 #, c-format msgid "shell %d" msgstr "voisinage %d" #: ../src/extraFunctions/shellProp.c:236 msgid "root" msgstr "origine" #: ../src/extraFunctions/sfielddata.c:86 msgid "Potential/density files" msgstr "Fichiers potentiel/densité" #: ../src/extraFunctions/sfielddata.c:415 #, c-format msgid "impossible to open the file.\n" msgstr "impossible d'ouvrir ce fichier.\n" #: ../src/extraFunctions/sfielddata.c:502 #, c-format msgid "wrong '%s' value for flag '%s'.\n" msgstr "mauvaise valeur « %s » pour la balise « %s ».\n" #: ../src/extraFunctions/sfielddata.c:523 #, c-format msgid "not enough meshx values.\n" msgstr "données de meshx manquantes.\n" #: ../src/extraFunctions/sfielddata.c:533 #, c-format msgid "impossible to read meshx values.\n" msgstr "impossible de lire la valeur d'iso-densité.\n" #: ../src/extraFunctions/sfielddata.c:562 #: ../src/extraFunctions/sfielddata.c:598 #, c-format msgid "not enough density values.\n" msgstr "pas assez de valeurs de densité.\n" #: ../src/extraFunctions/sfielddata.c:574 #: ../src/extraFunctions/sfielddata.c:608 #, c-format msgid "impossible to read density values.\n" msgstr "impossible de lire la valeur d'iso-densité.\n" #: ../src/extraFunctions/sfielddata.c:878 #, c-format msgid "unknown density/potential format.\n" msgstr "format de potentiel/densité inconnu.\n" #: ../src/extraFunctions/idProp.c:92 ../lib/plug-ins/abinit/ab_symmetry.c:223 msgid "Id" msgstr "Id" #: ../src/extraFunctions/typeProp.c:131 msgid "Type" msgstr "Type" #. * #. * VISU_COLORIZATION_LABEL: #. * #. * Default label used to name colourisation data. #. #: ../src/extraFunctions/dataFile.h:100 msgid "Colorization data" msgstr "Données de colorisation" #: ../src/pairsModeling/iface_wire.c:205 #, c-format msgid "shade id must be in [%d;%d]" msgstr "l'identifiant de dégradé doit être dans [%d;%d]" #: ../src/pairsModeling/cylinder_renderer.c:168 msgid "Cylinder pairs" msgstr "Liaisons cylindriques" #: ../src/pairsModeling/cylinder_renderer.c:168 msgid "Pairs are rendered by cylinders. The color and the width can by chosen." msgstr "" "Les liaisons sont dessinées par des cylindres de couleurs et de rayons " "variables." #: ../src/pairsModeling/wire_renderer.c:94 msgid "Wire pairs" msgstr "Liaisons filaires" #: ../src/pairsModeling/wire_renderer.c:95 msgid "" "Pairs are rendered by flat lines. The color and the width can by chosen." msgstr "" "Les liaisons sont dessinées par des traits de couleurs et d'épaisseurs " "variables." #: ../src/visu_dataloadable.c:131 msgid "No input files" msgstr "Aucun fichier d'entrée" #: ../src/visu_dataloadable.c:200 msgid "No file" msgstr "Aucun fichier" #: ../src/visu_dataloadable.c:368 #, c-format msgid "No filename available." msgstr "Aucun nom de fichier disponible." #: ../src/visu_dataloadable.c:375 #, c-format msgid "File '%s' is not a regular file or may not exist." msgstr "Le fichier « %s » n'est pas lisible ou n'existe pas." #: ../src/visu_dataloadable.c:383 #, c-format msgid "File '%s' is empty." msgstr "Le fichier « %s » est vide." #: ../src/panelModules/panelOpenGL.c:77 msgid "Follow global setting" msgstr "Suit les choix généraux" #: ../src/panelModules/panelOpenGL.c:97 msgid "Set OpenGL parameters" msgstr "Paramètres OpenGL" #: ../src/panelModules/panelOpenGL.c:98 ../src/panelModules/panelOpenGL.c:368 msgid "OpenGL" msgstr "OpenGL" #: ../src/panelModules/panelOpenGL.c:232 msgid "Use" msgstr "Active" #: ../src/panelModules/panelOpenGL.c:242 msgid "x" msgstr "x" #: ../src/panelModules/panelOpenGL.c:250 msgid "y" msgstr "y" #: ../src/panelModules/panelOpenGL.c:258 msgid "z" msgstr "z" #: ../src/panelModules/panelOpenGL.c:266 msgid "power" msgstr "intensité" #: ../src/panelModules/panelOpenGL.c:333 msgid "name of extension" msgstr "nom de l'extension" #: ../src/panelModules/panelOpenGL.c:369 msgid "" "The maximm number of lights allowed by OpenGL has been reached, can't add " "more." msgstr "" "Le nombre maximum de sources lumineuses autorisées est atteint, impossible " "d'en ajouter d'avantage." #: ../src/panelModules/panelOpenGL.c:501 msgid "Rendering options:" msgstr "Options de rendu :" #: ../src/panelModules/panelOpenGL.c:513 ../src/panelModules/panelMap.c:451 msgid "Precision:" msgstr "Précision :" #: ../src/panelModules/panelOpenGL.c:533 msgid "Mode:" msgstr "Rendu :" #: ../src/panelModules/panelOpenGL.c:538 msgid "Antialiase lines:" msgstr "Lissage des lignes :" #: ../src/panelModules/panelOpenGL.c:549 msgid "Enhanced transparency:" msgstr "Transparence améliorée :" #: ../src/panelModules/panelOpenGL.c:555 msgid "Use stereo rendering:" msgstr "Rendu stéréo :" #. Degrees. #: ../src/panelModules/panelOpenGL.c:562 ../src/panelModules/gtkSpin.c:225 msgid "deg." msgstr "deg." #: ../src/panelModules/panelOpenGL.c:568 msgid "angle:" msgstr "angle :" #: ../src/panelModules/panelOpenGL.c:575 msgid "Per extension rendering mode:" msgstr "Choix d'une méthode de rendu par extension :" #: ../src/panelModules/panelOpenGL.c:591 msgid "Redraw immediately after changes:" msgstr "Appliquer les changements à la volée :" #. ******************* #. VisuGlLight parameters. #. ******************* #: ../src/panelModules/panelOpenGL.c:605 msgid "Light sources:" msgstr "Sources lumineuses :" #: ../src/panelModules/panelAxes.c:94 msgid "Box, axes and labels" msgstr "Boîte, axes et légendes" #: ../src/panelModules/panelAxes.c:95 msgid "Frames/labels" msgstr "Traits / lignes" #. The label. #: ../src/panelModules/panelAxes.c:216 msgid "Legend" msgstr "Légende" #: ../src/panelModules/panelElements.c:81 msgid "Set elements caracteristics" msgstr "Paramètres des éléments" #: ../src/panelModules/panelElements.c:82 msgid "Elements" msgstr "Éléments" #: ../src/panelModules/panelConfig.c:127 msgid "Configure the interface" msgstr "Configuration" #: ../src/panelModules/panelConfig.c:128 msgid "Configuration" msgstr "Config." #: ../src/panelModules/panelConfig.c:216 msgid "Always show _labels in tabs" msgstr "Toujours _afficher les noms des onglets" #: ../src/panelModules/panelConfig.c:223 msgid "Automatic _refresh" msgstr "Rechargement automatique" #: ../src/panelModules/panelConfig.c:229 msgid " s" msgstr " s" #: ../src/panelModules/panelConfig.c:234 msgid "period:" msgstr "Période de rechargement :" #: ../src/panelModules/panelConfig.c:239 msgid "Remember _windows positions" msgstr "Conserver la position des fenêtres" #: ../src/panelModules/panelConfig.c:244 msgid "Display _coordinates in reduce" msgstr "Affiche les _coordonnées en réduit" #: ../src/panelModules/panelConfig.c:251 msgid "Set the prefered unit:" msgstr "Choix de l'unité préférée :" #. String used to labelled planes, dist. means 'distance' and #. norm. means 'normal' (50 chars max). #: ../src/panelModules/panelMap.c:93 #, c-format msgid "plane (%2d;%2d;%2d - %4.1f)" msgstr "plan (%2d;%2d;%2d - %4.1f)" #: ../src/panelModules/panelMap.c:184 #, c-format msgid "norm.: (%3d;%3d;%3d) dist.: %6.2f" msgstr "" "norm. :(%3d;%3d;%3d)\n" "dist. : %6.2f" #: ../src/panelModules/panelMap.c:279 msgid "not plane based" msgstr "ne repose pas sur un plan" #: ../src/panelModules/panelMap.c:314 msgid "Map sources" msgstr "Description de la carte" #: ../src/panelModules/panelMap.c:324 msgid "missing elements" msgstr "éléments manquants" #: ../src/panelModules/panelMap.c:331 msgid "Cutting plane:" msgstr "Plan de coupe :" #: ../src/panelModules/panelMap.c:335 msgid "Create elements in the 'planes' tab" msgstr "Créé depuis l'onglet « plans »" #: ../src/panelModules/panelMap.c:375 msgid "Scalar field:" msgstr "Champ scalaire :" #: ../src/panelModules/panelMap.c:379 msgid "Import fields in the 'isosurfaces' tab" msgstr "" "Chargé depuis l'onglet « isosurfaces »" #: ../src/panelModules/panelMap.c:414 msgid "Shade:" msgstr "Dégradé :" #: ../src/panelModules/panelMap.c:418 msgid "with _transparency" msgstr "avec _transparence" #: ../src/panelModules/panelMap.c:436 msgid "Options" msgstr "Options" #: ../src/panelModules/panelMap.c:458 msgid "Scale:" msgstr "Échelle :" #: ../src/panelModules/panelMap.c:462 msgid "_linear" msgstr "_linéaire" #: ../src/panelModules/panelMap.c:470 msgid "lo_g." msgstr "lo_g." #: ../src/panelModules/panelMap.c:478 msgid "_zero centred log." msgstr "log. centré en _zéro" #: ../src/panelModules/panelMap.c:489 msgid "Number of isolines:" msgstr "Nombre d'isolignes :" #: ../src/panelModules/panelMap.c:499 msgid "_colour:" msgstr "_couleur :" #: ../src/panelModules/panelMap.c:520 msgid "Normalise:" msgstr "Normalisation :" #: ../src/panelModules/panelMap.c:523 ../src/panelModules/panelDataFile.c:370 msgid "auto" msgstr "auto." #: ../src/panelModules/panelMap.c:530 ../src/panelModules/panelDataFile.c:375 #: ../src/panelModules/gtkAtomic.c:213 msgid "manual" msgstr "manuelle" #: ../src/panelModules/panelMap.c:566 msgid "List of maps:" msgstr "Liste des cartes :" #: ../src/panelModules/panelMap.c:845 msgid "Export to SVG or PDF." msgstr "Exporte en PDF ou en SVG." #: ../src/panelModules/panelMap.c:856 msgid "PDF document (*.pdf)" msgstr "Document PDF (*.pdf)" #: ../src/panelModules/panelMap.c:860 msgid "SVG document (*.svg)" msgstr "Document SVG (*.svg)" #: ../src/panelModules/panelMap.c:874 msgid "map.pdf" msgstr "carte.pdf" #: ../src/panelModules/panelMap.c:902 msgid "Export a coloured map" msgstr "Exporte la carte de couleurs" #. Long description #: ../src/panelModules/panelMap.c:940 msgid "Map projections" msgstr "Cartes de couleur" #. Short description #: ../src/panelModules/panelMap.c:942 msgid "Maps" msgstr "Cartes de couleur" #: ../src/panelModules/panelGeometry.c:85 msgid "No stored path" msgstr "Aucun chemin" #: ../src/panelModules/panelGeometry.c:86 #, c-format msgid "Path has %d step(s)" msgstr "Le chemin a %d étape(s)" #: ../src/panelModules/panelGeometry.c:116 msgid "Geometry operations" msgstr "Opérations de géométrie" #: ../src/panelModules/panelGeometry.c:117 msgid "Geometry" msgstr "Géométrie" #: ../src/panelModules/panelGeometry.c:126 msgid "Paste and align" msgstr "Colle et aligne" #. ********************** #. The multifile stuff. #. ********************** #: ../src/panelModules/panelGeometry.c:218 msgid "Multi file actions" msgstr "Actions multi-fichiers" #: ../src/panelModules/panelGeometry.c:229 msgid "Automatic zoom _adjustment on file loading" msgstr "Zoom _automatique lors du chargement d'un fichier" #: ../src/panelModules/panelGeometry.c:237 msgid "with re_ordering" msgstr "ré_ordonne" #: ../src/panelModules/panelGeometry.c:241 msgid "On load of a new file, reorder the nodes to minimize displacements." msgstr "" "Au chargement d'un fichier, réordonne les nœuds pour minimiser les " "déplacements." #: ../src/panelModules/panelGeometry.c:244 msgid "Show node _displacements" msgstr "Visualise les _déplacements des nœuds" #: ../src/panelModules/panelGeometry.c:248 msgid "" "When a new file is loaded, draw arrows on nodes that represent their " "displacements with respect to their previous positions." msgstr "" "Lorsqu'un nouveau fichier est chargé, dessine des flèches sur les nœuds pour " "représenter leur déplacement par rapport à leur position précédente." #: ../src/panelModules/panelGeometry.c:274 msgid "Use _paths" msgstr "_Afficher les chemins" #: ../src/panelModules/panelGeometry.c:278 msgid "Store differences between files and plot them as lines." msgstr "" "Stocke les différences de positions entre les fichiers et les représente par " "des lignes." #: ../src/panelModules/panelGeometry.c:291 msgid "When toggled, store differences between files as paths through nodes.." msgstr "" "Quand c'est activé, les différences entre fichiers sont stockées et tracées " "comme des chemins entre les nœuds." #: ../src/panelModules/panelGeometry.c:303 msgid "Remove all stored paths." msgstr "Retirer tous les chemins." #: ../src/panelModules/panelGeometry.c:316 msgid "colourise with: " msgstr "Colorisation :" #: ../src/panelModules/panelGeometry.c:317 msgid "" "If energy information was present when loading file, colourise the paths " "with shading colours." msgstr "" "Si l'énergie totale est définie dans le fichier, colorise le chemin avec un " "dégradé." #: ../src/panelModules/panelGeometry.c:334 msgid "Read a set of paths from a file and add them to the current set." msgstr "Lit un jeu de chemins depuis un fichier et l'ajoute au jeu courant." #: ../src/panelModules/panelGeometry.c:343 msgid "Save the current set of paths to an XML file." msgstr "Exporte le jeu courant de chemins dans un fichier XML." #: ../src/panelModules/panelGeometry.c:445 #, c-format msgid "Displacement field match %d node(s)." msgstr "Les déplacements s'alignent sur %d nœud(s)." #: ../src/panelModules/panelGeometry.c:516 msgid "Drag the displacement field." msgstr "Déplacer les déplacements." #: ../src/panelModules/panelGeometry.c:564 msgid "Recording paths" msgstr "Enregistre des chemins" #: ../src/panelModules/panelGeometry.c:580 #: ../src/panelModules/panelGeometry.c:606 msgid "Export current set of paths." msgstr "Export le jeu courant de chemins" #: ../src/panelModules/panelGeometry.c:586 msgid "paths.xml" msgstr "chemins.xml" #: ../src/panelModules/panelGeometry.c:627 #: ../src/panelModules/panelGeometry.c:648 msgid "Load a set of paths." msgstr "Charge un jeu de chemins." #: ../src/panelModules/panelSurfacesTools.c:232 msgid "Found different dxx, ..., dzz" msgstr "Les valeurs dxx, …, dzz trouvées sont différentes" #: ../src/panelModules/panelSurfacesTools.c:235 msgid "Keep current values" msgstr "Conserver les valeurs actuelles" #: ../src/panelModules/panelSurfacesTools.c:236 msgid "Change values to new ones" msgstr "Changer les valeurs pour de nouvelles" #: ../src/panelModules/panelSurfacesTools.c:239 msgid "" "Current dxx, ..., dzz, doesn't match the ones used in the file you are " "trying to load. Do you want to keep old dxx, ..., dzz ? (if you don't know " "exactly what you're doing, just cancel and load another file)" msgstr "" "Les valeurs dxx, …, dzz actuelles ne correspondent pas à celles utilisées " "dans le fichier qui est en train d'être chargé. Souhaitez-vous conserver les " "anciennes valeurs dxx, …, dzz? (Si vous ne savez pas, il est préférable " "d'annuler et de choisir un autre fichier)" #: ../src/panelModules/panelSurfacesTools.c:323 msgid "Unable to parse the selected file." msgstr "Impossible d'analyser le fichier sélectionné." #: ../src/panelModules/panelSurfacesTools.c:471 #: ../src/panelModules/panelSurfacesTools.c:1370 msgid "Surface name" msgstr "Nom de la surface" #: ../src/panelModules/panelSurfacesTools.c:493 msgid "New name" msgstr "Nouveau nom" #: ../src/panelModules/panelSurfacesTools.c:501 msgid "old name" msgstr "ancien nom" #: ../src/panelModules/panelSurfacesTools.c:507 msgid "from file" msgstr "à partir du fichier" #: ../src/panelModules/panelSurfacesTools.c:640 #: ../src/panelModules/panelSurfacesTools.c:660 #: ../src/panelModules/panelSurfacesTools.c:683 #: ../src/panelModules/panelSurfacesTools.c:703 msgid "An unknown error occured. Your surf file is corrupted.\n" msgstr "" "Une erreur inattendue est survenue, le fichier « .surf » est probablement " "corrompu.\n" #: ../src/panelModules/panelSurfacesTools.c:738 msgid "Please choose a surf file to write\n" msgstr "Choisissez un fichier « .surf » dans lequel écrire\n" #: ../src/panelModules/panelSurfacesTools.c:751 msgid "No surface to write\n" msgstr "Aucune surface à écrire\n" #: ../src/panelModules/panelSurfacesTools.c:798 msgid "Target info : " msgstr "Information sur la cible :" #: ../src/panelModules/panelSurfacesTools.c:799 msgid "Source info : " msgstr "Information sur la source :" #: ../src/panelModules/panelSurfacesTools.c:841 msgid "Build specified new .surf file" msgstr "Construire le nouveau fichier « .surf »" #: ../src/panelModules/panelSurfacesTools.c:843 msgid "Contains the full path to the currently .surf selected file" msgstr "Contient le chemin d'accès complet au fichier « .surf » sélectionné" #: ../src/panelModules/panelSurfacesTools.c:845 #: ../src/panelModules/panelSurfacesTools.c:2044 msgid "Contains the full path to the .surf file you want to build" msgstr "Contient le chemin d'accès complet au fichier « .surf » à construire" #: ../src/panelModules/panelSurfacesTools.c:847 msgid "Allows you to select a .surf file" msgstr "Permet de sélectionner un fichier « .surf »" #: ../src/panelModules/panelSurfacesTools.c:849 #: ../src/panelModules/panelSurfacesTools.c:2064 msgid "Selects the .surf file to write" msgstr "Choix du fichier « .surf » dans lequel écrire" #: ../src/panelModules/panelSurfacesTools.c:851 msgid "Moves selected surface to the list of surfaces to build" msgstr "" "Déplace la surface sélectionnée dans la liste des surfaces à construire" #: ../src/panelModules/panelSurfacesTools.c:853 #: ../src/panelModules/panelSurfacesTools.c:2058 msgid "Moves down selected surface in the list of surfaces to build" msgstr "" "Descend la surface sélectionnée dans la liste des surfaces à construire" #: ../src/panelModules/panelSurfacesTools.c:855 #: ../src/panelModules/panelSurfacesTools.c:2060 msgid "Moves up selected surface in the list of surfaces to build" msgstr "Monte la surface sélectionnée dans la liste des surfaces à construire" #: ../src/panelModules/panelSurfacesTools.c:857 #: ../src/panelModules/panelSurfacesTools.c:2056 msgid "Removes selected surface from the list of surfaces to build" msgstr "Retire la surface sélectionnée de la liste des surfaces à construire" #: ../src/panelModules/panelSurfacesTools.c:866 msgid "The d__ of the current selected file" msgstr "Le paramètre d__ du fichier courant." #: ../src/panelModules/panelSurfacesTools.c:875 msgid "The d__ of the file to build" msgstr "Le paramètre d__ du fichier à écrire." #: ../src/panelModules/panelSurfacesTools.c:892 msgid "Current file : " msgstr "Fichier courant :" #: ../src/panelModules/panelSurfacesTools.c:949 msgid "Target file : " msgstr "Fichier cible :" #. Create a new dialog window for the scrolled window to be #. * packed into. #: ../src/panelModules/panelSurfacesTools.c:1023 msgid "pot2surf_help" msgstr "pot2surf_help" #: ../src/panelModules/panelSurfacesTools.c:1070 msgid "Can't open given file for reading" msgstr "Impossible d'ouvrir en lecture le fichier donné." #: ../src/panelModules/panelSurfacesTools.c:1083 #: ../src/panelModules/panelSurfacesTools.c:1111 msgid "This file doesn't seem to be a correct pot file" msgstr "Ce fichier ne semble pas être un fichier pot valide." #: ../src/panelModules/panelSurfacesTools.c:1094 msgid "Second line seem to contain incorrect values" msgstr "La seconde ligne contient des données incorrectes." #: ../src/panelModules/panelSurfacesTools.c:1373 msgid "Pot value" msgstr "Valeur du potentiel" #: ../src/panelModules/panelSurfacesTools.c:1565 msgid "Please select an instruc file to write" msgstr "Choisissez un fichier « .instruc » dans lequel écrire" #: ../src/panelModules/panelSurfacesTools.c:1572 msgid "Can't open selected instruc file for writing" msgstr "Impossible d'ouvrir le fichier « .instruc » en écriture" #: ../src/panelModules/panelSurfacesTools.c:1607 #: ../src/panelModules/panelSurfacesTools.c:1707 msgid "Please specify surfaces to draw" msgstr "Choisissez les surfaces à dessiner" #: ../src/panelModules/panelSurfacesTools.c:1613 #: ../src/panelModules/panelSurfacesTools.c:1713 msgid "Please select a source pot file" msgstr "Choisissez un fichier « .pot » source" #: ../src/panelModules/panelSurfacesTools.c:1619 #: ../src/panelModules/panelSurfacesTools.c:1719 msgid "Please select a target surf file" msgstr "Choisissez un fichier « .surf » de destination" #: ../src/panelModules/panelSurfacesTools.c:1745 msgid "Error" msgstr "Erreur" #: ../src/panelModules/panelSurfacesTools.c:1835 msgid "Can't open selected file" msgstr "Impossible d'ouvrir le fichier sélectionné." #: ../src/panelModules/panelSurfacesTools.c:1843 msgid "Line 1 must contain the full path to the .pot file to read\n" msgstr "" "La première ligne doit obligatoirement contenir le chemin d'accès au fichier " "pot à lire\n" #: ../src/panelModules/panelSurfacesTools.c:1855 msgid "Line 2 must contain the full path to the .surf file to read\n" msgstr "" "La seconde ligne doit obligatoirement contenir le chemin d'accès au fichier " "surf\n" #: ../src/panelModules/panelSurfacesTools.c:1868 msgid "Line 3 must contain the number of surfaces to build\n" msgstr "" "La troisième ligne doit obligatoirement contenir le nombre de surfaces à " "modéliser\n" #: ../src/panelModules/panelSurfacesTools.c:1885 msgid "Lines must contain the value of the surface to build and its name\n" msgstr "" "Les lignes suivantes doivent contenir le numéro de la surface à modéliser et " "son nom\n" #: ../src/panelModules/panelSurfacesTools.c:1998 msgid "Build" msgstr "Modéliser" #: ../src/panelModules/panelSurfacesTools.c:1999 msgid "Autoload in V_Sim" msgstr "Chargement automatique dans V_Sim" #: ../src/panelModules/panelSurfacesTools.c:2040 msgid "If checked, autoloads newly built file in V_Sim" msgstr "Charge automatiquement les surfaces modélisées dans V_Sim." #: ../src/panelModules/panelSurfacesTools.c:2042 msgid "Contains the full path to the currently .pot selected file" msgstr "Contient le chemin d'accès au fichier .pot sélectionné" #: ../src/panelModules/panelSurfacesTools.c:2046 msgid "Contains the minimal value found in the selected .pot file" msgstr "Contient la valeur minimale trouvée dans le fichier .pot sélectionné" #: ../src/panelModules/panelSurfacesTools.c:2048 msgid "Contains the maximal value found in the selected .pot file" msgstr "Contient la valeur maximale trouvée dans le fichier .pot sélectionné" #: ../src/panelModules/panelSurfacesTools.c:2050 msgid "Tries to build specified .surf file using specified parameters" msgstr "" "Tente de construire le fichier .surf spécifié à partir des paramètres fournis" #: ../src/panelModules/panelSurfacesTools.c:2052 msgid "Adds a new surface to the list of surfaces to build" msgstr "Ajoute une nouvelle surface à la liste des surfaces à construire" #: ../src/panelModules/panelSurfacesTools.c:2054 msgid "Adds many surfaces to the list of surfaces to build" msgstr "Ajoute plusieurs surfaces à la liste des surfaces à construire" #: ../src/panelModules/panelSurfacesTools.c:2062 msgid "Selects the .pot file to use" msgstr "Choix du fichier .pot à utiliser" #: ../src/panelModules/panelSurfacesTools.c:2066 msgid "Opens a .instruc file" msgstr "Ouvre un fichier .instruc" #: ../src/panelModules/panelSurfacesTools.c:2068 msgid "Saves current settings as .instruc file" msgstr "Sauvegarde les paramètres courants dans un fichier .instruc" #: ../src/panelModules/panelSurfacesTools.c:2070 msgid "Show help" msgstr "Affiche de l'aide" #: ../src/panelModules/panelSurfacesTools.c:2103 msgid "Source .pot file :" msgstr "Fichier .pot original :" #: ../src/panelModules/panelSurfacesTools.c:2107 msgid "Target .surf file :" msgstr "Fichier .surf de destination :" #: ../src/panelModules/panelSurfacesTools.c:2117 msgid "Pot min : " msgstr "Pot. min. : " #: ../src/panelModules/panelSurfacesTools.c:2120 msgid "Pot max : " msgstr "Pot. max. : " #: ../src/panelModules/panelSurfacesTools.c:2174 msgid "Merge" msgstr "Mélange (surf. + surf.)" #: ../src/panelModules/panelSurfacesTools.c:2175 msgid "pot2surf" msgstr "Création (pot. -> surf.)" #: ../src/panelModules/panelSurfaces.c:666 msgid "Edit surface properties" msgstr "Réglage des propriétés des surfaces" #: ../src/panelModules/panelSurfaces.c:714 msgid "Shade" msgstr "Dégradé" #: ../src/panelModules/panelSurfaces.c:716 msgid "Apply a shade to the current surfaces of the selected scalar field." msgstr "" "Applique un dégradé à l'ensemble des surfaces du champ scalaire sélectionné." #: ../src/panelModules/panelSurfaces.c:725 msgid "ToolShade: " msgstr "Dégradé : " #: ../src/panelModules/panelSurfaces.c:898 #, c-format msgid "" "%s\n" " no data" msgstr "" "%s\n" " aucune donnée" #: ../src/panelModules/panelSurfaces.c:904 #, c-format msgid "" "%s\n" " Den./pot. data (min|max)\n" " %g | %g" msgstr "" "%s\n" " Fichier den./pot. (min|max)\n" " %g | %g" #: ../src/panelModules/panelSurfaces.c:1035 #, c-format msgid "" "%s\n" " Surfaces data" msgstr "" "%s\n" " Fichier de surfaces" #: ../src/panelModules/panelSurfaces.c:1256 #: ../src/panelModules/panelSurfaces.c:1549 msgid "Play" msgstr "Défiler" #: ../src/panelModules/panelSurfaces.c:1268 msgid "Stop" msgstr "Stop" #: ../src/panelModules/panelSurfaces.c:1386 msgid "File / label" msgstr "Fichier / nom" #: ../src/panelModules/panelSurfaces.c:1409 msgid "Value" msgstr "Valeur" #: ../src/panelModules/panelSurfaces.c:1568 msgid "_Use isosurfaces" msgstr "_Utiliser les iso-surfaces" #: ../src/panelModules/panelSurfaces.c:1582 msgid "Auto _load data file" msgstr "_Chargement automatique" #: ../src/panelModules/panelSurfaces.c:1586 msgid "" "Try to load a data file whenever a new V_Sim file is loaded. If the new file " "contains a scalar field, it is loaded, otherwise a surface file is tested " "using a .surf extension on the file name." msgstr "" "Essaye de charger un fichier de données lorsqu'un fichier de structure est " "chargé. Si ce nouveau fichier contient un champ scalaire, il est chargé " "automatiquement, sinon un fichier de surface avec un nom basé sur le nom du " "fichier de structure est testé." #: ../src/panelModules/panelSurfaces.c:1591 msgid "_Convert" msgstr "_Convertir" #: ../src/panelModules/panelSurfaces.c:1592 msgid "Load a surface file or a potential/density file." msgstr "Charge un fihier de surface ou un potentiel/densité." #: ../src/panelModules/panelSurfaces.c:1596 msgid "Several built-in tools to create .surf files." msgstr "Plusieurs outils permettant de créer des fichiers « .surf »." #: ../src/panelModules/panelSurfaces.c:1606 msgid "_Reorder on the fly" msgstr "_Réordonne à la volée" #: ../src/panelModules/panelSurfaces.c:1642 msgid "Hides all surfaces" msgstr "Cacher toutes les surfaces" #: ../src/panelModules/panelSurfaces.c:1644 msgid "Shows all surfaces" msgstr "Affiche toutes les surfaces" #: ../src/panelModules/panelSurfaces.c:1648 msgid "Change color and material properties." msgstr "Change les propriétés de couleur." #: ../src/panelModules/panelSurfaces.c:1655 msgid "Add a new surface." msgstr "Ajoute une nouvelle surface." #: ../src/panelModules/panelSurfaces.c:1665 msgid "Add many surfaces to the list of surfaces." msgstr "Ajoute plusieurs surfaces à la liste des surfaces." #: ../src/panelModules/panelSurfaces.c:1676 msgid "Remove selected surface or file." msgstr "Retire la surface ou le fichier sélectionné." #: ../src/panelModules/panelSurfaces.c:1685 msgid "Starts/stops showing isosurfaces at specified rate" msgstr "Arrêter/démarrer le défilement des surfaces" #: ../src/panelModules/panelSurfaces.c:1687 msgid "@" msgstr "@" #: ../src/panelModules/panelSurfaces.c:1688 msgid "Selects rate to show isosurfaces" msgstr "Choix de la période de défilement" #: ../src/panelModules/panelSurfaces.c:1691 msgid "ms" msgstr "ms" #: ../src/panelModules/panelSurfaces.c:1694 msgid "Import iso-values from an existing XML file." msgstr "Importe des iso-valeurs depuis un fichier XML existant." #: ../src/panelModules/panelSurfaces.c:1695 msgid "Export iso-values to the current XML file." msgstr "Exporte les iso-valeurs dans le fichier XML courant." #: ../src/panelModules/panelSurfaces.c:1696 msgid "Export iso-values to a new XML file." msgstr "Exporte les iso-valeurs dans un nouveau fichier XML." #: ../src/panelModules/panelSurfaces.c:1707 msgid "Draw _intra surfaces" msgstr "Dessiner l'_intérieur" #: ../src/panelModules/panelSurfaces.c:1709 msgid "Draw the interior of iso-surfaces with the complementary colour." msgstr "Dessine l'intérieur des iso-surfaces avec une couleur complémentaire." #: ../src/panelModules/panelSurfaces.c:1717 msgid "" "Automatically re-orders surfaces in back to front order whenever camera is " "modified (can be slow but get rid of transparency problems). This has no " "effect if the transparency option of the OpenGL panel is set" msgstr "" "Reordonne automatiquement du fond vers l'avant les iso-surfaces à chaque " "mouvement de la caméra (peut s'avérer lent). Ceci n'a pas d'effet si la " "transparenceaméliorée est utilisée." #: ../src/panelModules/panelSurfaces.c:2289 msgid "Comment:" msgstr "Commentaire:" #: ../src/panelModules/panelSurfaces.c:2454 msgid "Generate iso-values" msgstr "Génère des valeurs d'iso-surfaces" #: ../src/panelModules/panelSurfaces.c:2457 msgid "Generate" msgstr "Générer" #: ../src/panelModules/panelSurfaces.c:2483 msgid "Number of steps:" msgstr "Nombre d'étapes :" #: ../src/panelModules/panelSurfaces.c:2490 msgid "Delta of steps:" msgstr "Variation par étape :" #: ../src/panelModules/panelSurfaces.c:2504 #: ../src/panelModules/panelFogBgColor.c:265 msgid "Start:" msgstr "Début :" #: ../src/panelModules/panelSurfaces.c:2505 #: ../src/panelModules/panelFogBgColor.c:280 msgid "End:" msgstr "Fin :" #: ../src/panelModules/panelSurfaces.c:2508 msgid "Name (optional):" msgstr "Nom (en option) :" #: ../src/panelModules/panelDataFile.c:80 msgid "R" msgstr "R" #: ../src/panelModules/panelDataFile.c:81 msgid "G" msgstr "V" #: ../src/panelModules/panelDataFile.c:82 msgid "B" msgstr "B" #: ../src/panelModules/panelDataFile.c:83 msgid "H" msgstr "T" #: ../src/panelModules/panelDataFile.c:84 msgid "S" msgstr "S" #: ../src/panelModules/panelDataFile.c:85 msgid "V" msgstr "V" #: ../src/panelModules/panelDataFile.c:91 msgid "coord. x" msgstr "coord. x" #: ../src/panelModules/panelDataFile.c:92 msgid "coord. y" msgstr "coord. y" #: ../src/panelModules/panelDataFile.c:93 msgid "coord. z" msgstr "coord. z" #: ../src/panelModules/panelDataFile.c:103 msgid "No data file loaded" msgstr "Aucun fichier de données" #: ../src/panelModules/panelDataFile.c:104 msgid "No data file" msgstr "Aucun fichier de données" #: ../src/panelModules/panelDataFile.c:203 msgid "Colorize with data" msgstr "Colorisation" #: ../src/panelModules/panelDataFile.c:204 msgid "Data color" msgstr "Colorisation" #: ../src/panelModules/panelDataFile.c:298 msgid "_Use color scheme" msgstr "_Utiliser de la colorisation" #: ../src/panelModules/panelDataFile.c:323 msgid "_Auto load data" msgstr "Chargement _auto." #: ../src/panelModules/panelDataFile.c:326 msgid "" "Try to load a data file whenever a new V_Sim file is loaded. For example, if " "'example.ascii' has just been opened, V_Sim will look for 'example.dat' and " "will apply it." msgstr "" "Tente de charger un fichier de données lorsqu'un fichier V_Sim est affiché." "Par exemple, à l'ouverture d'un fichier « exemple.ascii », V_Sim recherche " "un fichier de données nommé « exemple.dat » et l'applique." #: ../src/panelModules/panelDataFile.c:338 msgid "Load data file" msgstr "Charger un fichier de données" #: ../src/panelModules/panelDataFile.c:351 msgid "Choose a file to read the colorization data from." msgstr "Choix du fichier de données de colorisation." #: ../src/panelModules/panelDataFile.c:356 msgid "" "File extension used for the autoload option, its value is saved in the " "parameter file (see 'dataFile_fileExt')." msgstr "" "Extension de fichier utilisée par l'option de rechargement automatique, sa " "valeur est sauvegardée dans le fichier de paramètres (mot-clef « " "dataFile_fileExt »)." #: ../src/panelModules/panelDataFile.c:365 msgid "Normalize input: " msgstr "Normalisation des entrées : " #: ../src/panelModules/panelDataFile.c:380 msgid "More information" msgstr "Plus d'informations" #: ../src/panelModules/panelDataFile.c:401 msgid "Input data bounds:" msgstr "Encadrement manuel : " #: ../src/panelModules/panelDataFile.c:434 msgid "Min:" msgstr "Min :" #: ../src/panelModules/panelDataFile.c:438 msgid "Max:" msgstr "Max :" #: ../src/panelModules/panelDataFile.c:442 msgid "Col.:" msgstr "Col. :" #. ********************* #. Transformation part #. ********************* #: ../src/panelModules/panelDataFile.c:453 msgid "Define the color scheme:" msgstr "Schéma de couleurs :" #: ../src/panelModules/panelDataFile.c:485 msgid "Color space: " msgstr "Espace colorimétrique : " #: ../src/panelModules/panelDataFile.c:490 msgid "RGB" msgstr "RVB" #: ../src/panelModules/panelDataFile.c:495 msgid "HSV" msgstr "TSV" #: ../src/panelModules/panelDataFile.c:592 msgid "Color range preview: " msgstr "Échelle colorée : " #: ../src/panelModules/panelDataFile.c:604 msgid "No preview available" msgstr "Aucun aperçu possible" #: ../src/panelModules/panelDataFile.c:612 msgid "Display the colour range." msgstr "Affiche la légende de colorisation." #. g_object_bind_property_full(visu_gl_node_scene_getColorization(scene), #. "single-param", checkLegend, "sensitive", #. G_BINDING_SYNC_CREATE, fromSingle, NULL, NULL, NULL); #. ********************* #. Post treatment part #. ********************* #: ../src/panelModules/panelDataFile.c:624 msgid "Post processing:" msgstr "Post-traitement :" #: ../src/panelModules/panelDataFile.c:637 msgid "_Hide elements" msgstr "_Masque les éléments" #: ../src/panelModules/panelDataFile.c:641 msgid " whose value from" msgstr " dont la donnée lue à" #: ../src/panelModules/panelDataFile.c:647 msgid "col. " msgstr "la colonne " #: ../src/panelModules/panelDataFile.c:655 msgid " is lower than " msgstr " est inférieure à " #: ../src/panelModules/panelDataFile.c:665 msgid "_Scale shape according to " msgstr "_Ajuste la taille suivant " #: ../src/panelModules/panelDataFile.c:677 msgid "_Restrict colourisation to values in range." msgstr "_Restreint la colorisation dans l'encadrement." #: ../src/panelModules/panelDataFile.c:692 msgid "Description of loaded data file." msgstr "Description du fichier de données." #: ../src/panelModules/panelDataFile.c:732 msgid "Data files" msgstr "Fichiers de données" #: ../src/panelModules/panelDataFile.c:784 #, c-format msgid "" "Reading data file '%s' reports:\n" "\t%s" msgstr "" "Lors de la lecture du fichier de paramètres « %s » :\n" "\t%s" #: ../src/panelModules/panelDataFile.c:786 msgid "Loading a data file" msgstr "Chargement d'un fichier de données" #: ../src/panelModules/panelDataFile.c:817 #, c-format msgid "%s: %d column(s)" msgstr "%s : %d colonne(s)" #: ../src/panelModules/panelDataFile.c:820 #, c-format msgid "%s: file error" msgstr "%s : erreur de fichier" #: ../src/panelModules/panelDataFile.c:830 #, c-format msgid "%d column(s)" msgstr "%d colonne(s)" #: ../src/panelModules/panelDataFile.c:1298 #, c-format msgid "Col. %d" msgstr "Col. %d" #. label = gtk_label_new(_("Column number")); #. gtk_widget_set_name(label, "label_head"); #. gtk_table_attach(GTK_TABLE(table), label, 0, 1, 0, 1, GTK_SHRINK, GTK_SHRINK, 2, 0); #: ../src/panelModules/panelDataFile.c:1336 msgid "Min value" msgstr "Valeur min." #: ../src/panelModules/panelDataFile.c:1340 msgid "Max value" msgstr "Valeur max." #: ../src/panelModules/panelDataFile.c:1349 #, c-format msgid "Column %d" msgstr "Colonne %d" #. * #. * SECTION: panelPlanes #. * @short_description: The tab where planes are defined. #. * #. * It is possible to get the list of planes using #. * visu_ui_panel_planes_getModel(). One can also access to the list #. * store hosting the planes by calling visu_ui_panel_planes_getList(). #. #: ../src/panelModules/panelPlanes.c:72 msgid "none" msgstr "aucun" #. Long description #: ../src/panelModules/panelPlanes.c:116 msgid "Drawing planes" msgstr "Dessiner des plans" #. Short description #: ../src/panelModules/panelPlanes.c:118 msgid "Planes" msgstr "Plans" #: ../src/panelModules/panelPlanes.c:143 msgid "Import planes from an existing XML file." msgstr "Importe des plans depuis un fichier XML existant." #: ../src/panelModules/panelPlanes.c:144 msgid "Export planes to the current XML file." msgstr "Exporte les plans dans le fichier XML courant." #: ../src/panelModules/panelPlanes.c:145 msgid "Export planes to a new XML file." msgstr "Exporte les plans dans un nouveau fichier XML." #: ../src/panelModules/panelPlanes.c:201 msgid "_Use planes" msgstr "_Utiliser les plans" #: ../src/panelModules/panelPlanes.c:215 msgid "Simple tools" msgstr "Base" #: ../src/panelModules/panelPlanes.c:220 msgid "Advanced tools" msgstr "Avancé" #: ../src/panelModules/panelPlanes.c:223 msgid "Change selected plane distance" msgstr "Modifie la distance du plan sélectionné" #: ../src/panelModules/panelPlanes.c:235 msgid "to: " msgstr "vers : " #: ../src/panelModules/panelPlanes.c:241 msgid "step: " msgstr "Incrément : " #: ../src/panelModules/panelPlanes.c:250 ../src/panelModules/panelBrowser.c:556 msgid "Play at " msgstr "Lire à " #. Units: milliseconds #: ../src/panelModules/panelPlanes.c:257 ../src/panelModules/panelBrowser.c:566 msgid " ms" msgstr " ms" #: ../src/panelModules/panelPlanes.c:262 msgid "Change the distance parameter of he selected file at the given rate." msgstr "" "Modifie le paramètre de distance du plan sélectionné à la vitesse indiquée." #: ../src/panelModules/panelVibration.c:112 #: ../src/panelModules/panelVibration.c:113 msgid "Phonons" msgstr "Phonons" #: ../src/panelModules/panelVibration.c:126 msgid "with _arrow" msgstr "avec des _flèches" #: ../src/panelModules/panelVibration.c:129 msgid "use _fixed frequency" msgstr "utilise une _fréquence fixée" #: ../src/panelModules/panelVibration.c:196 msgid "Draw arrows on nodes that represent their displacements." msgstr "Dessine des flèches sur les nœuds pour représenter leur déplacements." #. make and add the second column to the view #: ../src/panelModules/panelVibration.c:225 msgid "q point" msgstr "point q" #. make and add the third column to the view #: ../src/panelModules/panelVibration.c:230 msgid "energy" msgstr "énergie" #. the timer #: ../src/panelModules/panelVibration.c:252 msgid "Freq.: " msgstr "Fréq. : " #. the amplitude #: ../src/panelModules/panelVibration.c:258 msgid "Ampl.: " msgstr "Ampl. :" #: ../src/panelModules/panelVibration.c:267 msgid "Stop the nodes at their given positions." msgstr "Arrête les nœuds à leur position courante." #: ../src/panelModules/panelVibration.c:275 msgid "Move the nodes according to their phonon vibration." msgstr "Déplace les nœuds selon leur mode de vibration." #. reset button #: ../src/panelModules/panelVibration.c:281 msgid "Reset" msgstr "Raz" #: ../src/panelModules/panelVibration.c:284 msgid "Reset the node positions to input file coordinates." msgstr "Ramène les positions atomiques à celles du fichier d'origine." #: ../src/panelModules/panelVibration.c:459 msgid "Vibration file reloading" msgstr "Rechargement du fichier de vibrations" #. * #. * SECTION:gtkSpin #. * @short_description: The gtk interface elements that can interfere #. * with renderingSpin parameters. #. * #. * This is the gtk interface for all #VisuDataSpin module #. * parameters. They are split in two parts. The first part is placed #. * under the config tab and allows the user to modify the "global #. * properties" of the renderingSpin module such as cone's axe #. * orientation, and color repartition. The second part is under the #. * element panel and allows to modify each element resource. Size of #. * the arrows, and their shape can be modified. #. #: ../src/panelModules/gtkSpin.c:80 msgid "Shape size and color properties:" msgstr "Taille des formes et propriété de couleur :" #: ../src/panelModules/gtkSpin.c:81 msgid "Drawing policy for spins with null modulus:" msgstr "Type de rendu pour les spins de module nul :" #: ../src/panelModules/gtkSpin.c:134 msgid "x:" msgstr "x :" #: ../src/panelModules/gtkSpin.c:135 msgid "y:" msgstr "y :" #: ../src/panelModules/gtkSpin.c:136 msgid "z:" msgstr "z :" #: ../src/panelModules/gtkSpin.c:181 msgid "Set ortho." msgstr "Rendre ortho." #: ../src/panelModules/gtkSpin.c:183 msgid "Set the cone orientation to be orthogonal to the screen." msgstr "" "Oriente le cône des couleurs de telle sorte qu'il soit orthogonal au plan de " "l'écran." #: ../src/panelModules/gtkSpin.c:214 msgid "Rotate color wheel:" msgstr "Tourner la roue des couleurs :" #: ../src/panelModules/gtkSpin.c:237 msgid "always" msgstr "toujours" #: ../src/panelModules/gtkSpin.c:245 msgid "atomic" msgstr "atomique" #: ../src/panelModules/gtkSpin.c:372 msgid "Color cone orientation:" msgstr "Orientation du cône des couleurs :" #: ../src/panelModules/gtkSpin.c:382 msgid "Spin lenght is proportional to modulus: " msgstr "La longueur des spins est prop. au module :" #: ../src/panelModules/gtkSpin.c:390 msgid "per node type" msgstr "type par nœud" #: ../src/panelModules/gtkSpin.c:396 msgid "globaly" msgstr "général" #: ../src/panelModules/gtkSpin.c:408 msgid "Use atomic rendering in addition to spin: " msgstr "Rendu atomique en plus du spin : " #: ../src/panelModules/gtkSpin.c:426 msgid "Color distribution options:" msgstr "Options de colorisation :" #: ../src/panelModules/panelBrowser.c:213 #: ../src/panelModules/panelBrowser.c:214 msgid "Browser" msgstr "Navigateur" #. This is a label in the browser panel to introduce the #. entry that allows to enter a filter for files shown. #: ../src/panelModules/panelBrowser.c:323 msgid "Filter: " msgstr "Filtre : " #: ../src/panelModules/panelBrowser.c:331 msgid "atomic rendering" msgstr "rendu atomique" #: ../src/panelModules/panelBrowser.c:333 msgid "spin rendering" msgstr "rendu de spin" #: ../src/panelModules/panelBrowser.c:335 msgid "atomic part" msgstr "partie atomique" #: ../src/panelModules/panelBrowser.c:337 msgid "spin part" msgstr "partie de spin" #: ../src/panelModules/panelBrowser.c:353 msgid "Choose a different directory." msgstr "Choisir un répertoire." #: ../src/panelModules/panelBrowser.c:360 msgid "Rescan current directory." msgstr "Relit le répertoire courant." #: ../src/panelModules/panelBrowser.c:369 msgid "Read directories recursively." msgstr "Lecture récursive des répertoires." #: ../src/panelModules/panelBrowser.c:395 msgid "Dir.:" msgstr "Rép. :" #: ../src/panelModules/panelBrowser.c:427 msgid "Double click on a file to render it." msgstr "Double-cliquer pour charger un fichier." #: ../src/panelModules/panelBrowser.c:442 msgid "File" msgstr "Fichier" #: ../src/panelModules/panelBrowser.c:460 msgid "Date" msgstr "Date" #: ../src/panelModules/panelBrowser.c:476 msgid "Unselect all files." msgstr "Tout désélectionner." #: ../src/panelModules/panelBrowser.c:482 msgid "Select all files." msgstr "Sélectionner tous les fichiers." #: ../src/panelModules/panelBrowser.c:492 msgid "Export the rendering of all selected files in other formats." msgstr "Exporte le rendu de chaque fichier sélectionné dans un autre format." #: ../src/panelModules/panelBrowser.c:498 msgid "Render the next selected file." msgstr "Afficher le fichier suivant sélectionné" #: ../src/panelModules/panelBrowser.c:505 msgid "Render the previous selected file." msgstr "Afficher le fichier précédent sélectionné" #: ../src/panelModules/panelBrowser.c:512 msgid "Current dir.: " msgstr "Rép. courant: " #: ../src/panelModules/panelBrowser.c:571 msgid "Cycle through the selected files at the given rate." msgstr "" "Parcours l'ensemble des fichiers sélectionnés suivant la vitesse indiquées." #: ../src/panelModules/panelBrowser.c:902 #, c-format msgid "foo%02d.png" msgstr "toto%02d.png" #: ../src/panelModules/panelBrowser.c:922 msgid "Dumping all selected files to images," msgstr "Exporter tous les fichiers sélectionnés en image." #: ../src/panelModules/panelBrowser.c:923 #, c-format msgid "" " format '%s'.\n" "\n" msgstr "" " format '%s'.\n" "\n" #: ../src/panelModules/panelBrowser.c:932 #, c-format msgid "Error! The numbering pattern is wrong.\n" msgstr "Erreur! Le motif pour la numérotation est incorrect.\n" #: ../src/panelModules/panelBrowser.c:942 #, c-format msgid "Error! Only one '%s' character is allowed in the file name.\n" msgstr "Erreur! Un seul symbole « %s » est autorisé dans le nom de fichier.\n" #: ../src/panelModules/panelBrowser.c:952 #, c-format msgid "Error! Missing pattern in the filename.\n" msgstr "" "Erreur! Le nom de fichier ne contient pas de motif pour la numérotation.\n" #: ../src/panelModules/panelBrowser.c:957 #, c-format msgid "" "\n" "Help : you must specify '%s' in the filename, where 'x' is a number [|1;9|]. " "This allows V_Sim to number the dumped files.\n" "\n" " For example, with a pattern like this : 'foo%s.pdf', dumped files will be " "named : foo00.pdf, foo01.pdf..." msgstr "" "\n" "Aide : la chaîne « %s » doit apparaître dans le nom du fichier, avec « x » " "un nombre compris entre 1 et 9. Ceci permet à V_Sim de numéroter les fichier " "lors de l'exportation.\n" "\n" "Par exemple, avec le motif suivant : « toto%s.pdf », les fichiers exportés " "seront nommés « toto01.pdf », « toto02.pdf »…" #: ../src/panelModules/panelBrowser.c:964 #: ../src/panelModules/panelBrowser.c:1024 msgid "Exporting files" msgstr "Exportation de fichiers" #: ../src/panelModules/panelBrowser.c:998 #, c-format msgid "Write to file %d ..." msgstr "Écriture du fichier %d…" #: ../src/panelModules/panelBrowser.c:1009 #, c-format msgid " error\n" msgstr " erreur\n" #: ../src/panelModules/panelBrowser.c:1011 #, c-format msgid " OK\n" msgstr " OK\n" #: ../src/panelModules/panelBrowser.c:1055 msgid "Abortion request, please wait..." msgstr "Annulation en cours, veuillez patienter…" #: ../src/panelModules/panelBrowser.c:1360 msgid "" "Can't load this file through the browser because it requires to read several " "files. You should use the 'Open' button on the main panel and then use the " "browser to vary one kind of file at a time." msgstr "" "Le chargement de ce fichier n'est pas possible car il nécessite plusieurs " "chargements. Commencer par utiliser le bouton « ouvrir » du panneau de " "commande avant de pouvoir utiliser le navigateur de fichier." #. We create the new ones. #: ../src/panelModules/panelBrowser.c:1422 #, c-format msgid "data set %s0%dd" msgstr "données %s0%dd" #: ../src/panelModules/panelBrowser.c:1907 msgid "Browsing a directory" msgstr "Parcours d'un répertoire" #: ../src/panelModules/panelBrowser.c:1908 msgid "The specified directory is unreadable." msgstr "Le répertoire indiqué n'est pas lisible." #: ../src/panelModules/panelBrowser.c:1971 msgid "%Y-%m-%d %H:%M" msgstr "%d/%m/%Y %H:%M" #: ../src/panelModules/panelBrowser.c:2076 #: ../src/panelModules/panelBrowser.c:2102 #, c-format msgid "%4d files found." msgstr "%4d fichiers parcourrus." #: ../src/panelModules/panelBrowser.c:2210 #, c-format msgid "%s" msgstr "%s" #: ../src/panelModules/panelMethod.c:85 msgid "Rendering method" msgstr "Méthode de rendu" #: ../src/panelModules/panelMethod.c:86 msgid "Draw" msgstr "Rendu" #: ../src/panelModules/panelMethod.c:120 msgid "Input method:" msgstr "Méthode de rendu :" #: ../src/panelModules/panelMethod.c:138 msgid "Options:" msgstr "Options :" #: ../src/panelModules/panelMethod.c:188 msgid "Spin visualisation" msgstr "Visualisation de spins" #: ../src/panelModules/panelMethod.c:191 msgid "It draws arrows at given positions to represent an atom and its spin." msgstr "" "Dessine des flèches aux positions indiquées pour représenter des spins." #: ../src/panelModules/panelMethod.c:199 msgid "Atom visualisation" msgstr "Visualisation atomique" #: ../src/panelModules/panelMethod.c:202 msgid "" "It draws spheres at specified positions to represent atoms. The radius of " "the sphere can vary." msgstr "" "Dessine des sphères (de rayons variables) aux positions indiquées pour " "représenter des atomes" #: ../src/panelModules/panelFogBgColor.c:99 msgid "Fog and background color" msgstr "Brouillard et fond" #: ../src/panelModules/panelFogBgColor.c:100 msgid "Fog & bg" msgstr "Fond" #: ../src/panelModules/panelFogBgColor.c:147 msgid "A:" msgstr "A :" #: ../src/panelModules/panelFogBgColor.c:178 msgid "Background:" msgstr "Couleur du fond :" #: ../src/panelModules/panelFogBgColor.c:197 msgid "Insert an image:" msgstr "Insérer une image :" #: ../src/panelModules/panelFogBgColor.c:199 msgid "Choose a background image" msgstr "Choix d'une image de fond" #: ../src/panelModules/panelFogBgColor.c:233 msgid "Remove the background image." msgstr "Retire l'image de fond." #: ../src/panelModules/panelFogBgColor.c:241 msgid "_follow camera" msgstr "_suivre la caméra" #: ../src/panelModules/panelFogBgColor.c:245 msgid "_display filename" msgstr "_Affiche le nom de fichier" #: ../src/panelModules/panelFogBgColor.c:253 msgid "Use fog:" msgstr "Utiliser du brouillard :" #: ../src/panelModules/panelFogBgColor.c:300 msgid "background color" msgstr "couleur du fond" #: ../src/panelModules/panelFogBgColor.c:306 msgid "specific color" msgstr "couleur originale" #: ../src/panelModules/panelFogBgColor.c:387 msgid "Load image file" msgstr "Charge une image" #: ../src/panelModules/gtkAtomic.c:81 msgid "(No force data)" msgstr "(Aucune force)" #: ../src/panelModules/gtkAtomic.c:86 #, c-format msgid "(max. force is %.4g)" msgstr "(force max. de %.4g)" #: ../src/panelModules/gtkAtomic.c:190 msgid "Display _forces (if available)" msgstr "Dessine les forces (si disponibles)" #: ../src/panelModules/gtkAtomic.c:197 msgid "Policy to scale arrows:" msgstr "Choix de la mise à l'échelle des flèches :" #: ../src/panelModules/gtkAtomic.c:204 msgid "automatic" msgstr "auto." #: ../src/openGLFunctions/renderingMode.c:84 msgid "Wireframe" msgstr "Fil de fer" #: ../src/openGLFunctions/renderingMode.c:85 msgid "Flat" msgstr "Facetté" #: ../src/openGLFunctions/renderingMode.c:86 msgid "Smooth" msgstr "Lissé (meilleur)" #: ../src/openGLFunctions/renderingMode.c:87 msgid "Smooth & edge" msgstr "Lissé & bords" #: ../src/gtk_move.c:100 msgid "" "left-button\t\t\t\t: drag node(s) in the screen plane\n" "middle-button (wheel)\t\t: drag node(s) along specific axis\n" "shift-left-button\t\t\t: drag node(s) along x axis\n" "control-left-button\t\t\t: drag node(s) along y axis\n" "control-shift-left-button\t: drag node(s) along z axis\n" "right-button\t\t\t\t: switch to observe" msgstr "" "bouton gauche\t\t\t: déplace le(s) nœud(s) dans le plan de l'écran\n" "bouton du milieu (molette)\t: déplace le(s) nœud(s) selon l'axe choisi\n" "shift bouton gauche\t\t: déplace le(s) nœud(s) selon l'axe x\n" "control bouton gauche\t\t: déplace le(s) nœud(s) selon l'axe y\n" "shift control bouton gauche\t: déplace le(s) nœud(s) selon l'axe z\n" "bouton droit\t\t\t: passer en mode d'observation" #: ../src/gtk_move.c:111 msgid "(none)" msgstr "(aucun)" #: ../src/gtk_move.c:176 #, c-format msgid "(node %d)" msgstr "(nœud %d)" #: ../src/gtk_move.c:181 #, c-format msgid "(%d nodes)" msgstr "(%d nœuds)" #: ../src/gtk_move.c:264 msgid "Pick a node with the mouse" msgstr "Choisit un nœud à la souris" #: ../src/gtk_move.c:281 msgid "Suppress node (either picked one or selected ones)." msgstr "Supprime les nœuds (soit celui choisi, soit ceux sélectionnés)." #: ../src/gtk_move.c:342 msgid "Capture the perpendicular axis to the current view." msgstr "Récupère la direction perpendiculaire à la vue courante." #: ../src/gtk_move.c:351 msgid "Apply translation values to coordinates." msgstr "Applique les translations aux coordonnées." #: ../src/gtk_move.c:360 msgid "Return coordinates to initial values." msgstr "Retourne aux coordonnées initiales." #: ../src/gtk_move.c:387 msgid "Add a new node." msgstr "Ajoute un nouveau nœud." #: ../src/gtk_move.c:397 msgid "Duplicate nodes:" msgstr "Duplique les nœuds :" #: ../src/gtk_move.c:401 msgid "(the nodes listed in the pick tab)" msgstr "" "(les nœuds sélectionnés dans l'onglet de sélection)" #: ../src/gtk_move.c:410 msgid "du_plicate nodes as they are" msgstr "du_pplique les nœuds comme tels" #: ../src/gtk_move.c:414 msgid " or as new: " msgstr " ou comme nouveaux" #: ../src/gtk_move.c:423 msgid "_duplicate" msgstr "_duplique" #: ../src/gtk_move.c:431 msgid "Change the basis set:" msgstr "Change le repère :" #: ../src/gtk_move.c:460 msgid "Select node by picking it on the rendering area." msgstr "Choisi un nœud en le sélectionnant à l'écran." #: ../src/gtk_move.c:464 msgid "_Apply" msgstr "_Appliquer" #: ../src/gtk_move.c:872 msgid "The new basis set will be indirect." msgstr "La nouvelle base sera indirecte." #: ../src/gtk_move.c:954 msgid "Cannot change the basis: given matrix is singular." msgstr "Impossible de changer la base, la matrice donnée est singulière." #: ../src/gtk_pairs.c:85 msgid "" "Modifications, as color or wire width, are applied only to selected rows. " "Use to select more than one row at a time." msgstr "" "Les modifications effectuées sur la taille ou la couleur par exemple, ne " "sont appliquées qu'aux lignes sélectionnées. Utilisez la touche " "pour choisir plus d'une ligne à la fois." #: ../src/gtk_pairs.c:86 msgid "No distance analysis" msgstr "Pas d'analyse sur les distances" #: ../src/gtk_pairs.c:87 #, c-format msgid "• there are %.3f neighbours per '%s'" msgstr "• il y a %.3f voisin(s) pour « %s »" #: ../src/gtk_pairs.c:90 #, c-format msgid "• mean distance is %.3f" msgstr "• la distance moyenne est %.3f" #: ../src/gtk_pairs.c:192 msgid "filter: " msgstr "filtre : " #: ../src/gtk_pairs.c:211 msgid "Parameters:" msgstr "Paramètres :" #: ../src/gtk_pairs.c:217 msgid "min:" msgstr "min. :" #: ../src/gtk_pairs.c:225 msgid "max:" msgstr "max. :" #: ../src/gtk_pairs.c:233 msgid "step size:" msgstr "incrément :" #: ../src/gtk_pairs.c:240 msgid "Measurement tools:" msgstr "Outils de mesure :" #: ../src/gtk_pairs.c:246 msgid "Range" msgstr "Intervale" #: ../src/gtk_pairs.c:286 msgid "_Highlight nodes in range" msgstr "Met en _évidence les nœud dans l'intervale" #: ../src/support.c:90 ../src/support.c:114 #, c-format msgid "Couldn't find pixmap file: %s" msgstr "Impossible de trouver l'image %s" #. * #. * SECTION: gtk_about #. * @short_description: The about dialog with a readme, the copyright, #. * the author list, the plug-in list and the version notes. #. * #. * The about dialog window is activated when clicking on the V_Sim #. * icon on bottom right part of the command panel. It contains a #. * summary of V_Sim purpose and capabilities, the list of authors, the #. * list of loaded plug-ins, the list of changes since the previous #. * version, and the licence file. It displays also the version of #. * V_Sim and provide a link to the web site. #. #: ../src/gtk_about.c:69 msgid "licence.en.txt" msgstr "licence.fr.txt" #. Translate if there is a authors file in another language. #: ../src/gtk_about.c:71 msgid "authors" msgstr "authors" #. Translate if there is a readme file in another language. #: ../src/gtk_about.c:73 msgid "readme" msgstr "readme" #. Translate if there is a readme file in another language. #: ../src/gtk_about.c:75 msgid "ChangeLog.en" msgstr "ChangeLog.fr" #: ../src/gtk_about.c:362 msgid "Description" msgstr "Description" #: ../src/gtk_about.c:461 msgid "" ":\n" "\n" msgstr "" " :\n" "\n" #: ../src/gtk_about.c:483 msgid ": " msgstr " : " #: ../lib/plug-ins/nanoquanta-netcdf/nq_basic.c:55 msgid "" "This plug-in introduces support for\n" "ETSF file format defined by the\n" "European network NANOQUANTA." msgstr "" "Ce greffon permet la lecture des fichiers\n" "ETSF suivant le format défini par le\n" "réseau européen NANOQUANTA." #: ../lib/plug-ins/nanoquanta-netcdf/nq_basic.c:59 msgid "" "Caliste Damien:\n" " structure/density loading." msgstr "" "Caliste Damien:\n" " lecture structure/densité." #: ../lib/plug-ins/nanoquanta-netcdf/nq_basic.c:153 #, c-format msgid "Global attribute '%s' has a wrong length or type.\n" msgstr "L'attribut global « %s » un une longueur ou un type erroné.\n" #: ../lib/plug-ins/nanoquanta-netcdf/nq_basic.c:176 #, c-format msgid "Variable 'file_format' should be 'ETSF Nanoquanta' but is '%s'.\n" msgstr "" "La varibale « file_format » devrait contenir « ETSF Nanoquanta » mais est « " "%s ».\n" #: ../lib/plug-ins/nanoquanta-netcdf/nq_basic.c:196 #, c-format msgid "Supported version are 1.2 and over but this file is only %f.\n" msgstr "" "Le support fonctionne pour les fichier au format 1.2 ou supérieur mais celui " "-ci n'est que %f.\n" #: ../lib/plug-ins/nanoquanta-netcdf/nq_basic.c:245 #: ../lib/plug-ins/nanoquanta-netcdf/nq_basic.c:267 #, c-format msgid "Reading '%s': %s." msgstr "Lecture de « %s » : %s" #: ../lib/plug-ins/nanoquanta-netcdf/nq_basic.c:249 #: ../lib/plug-ins/nanoquanta-netcdf/nq_structure.c:162 #: ../lib/plug-ins/nanoquanta-netcdf/nq_structure.c:179 #: ../lib/plug-ins/nanoquanta-netcdf/nq_structure.c:208 #: ../lib/plug-ins/nanoquanta-netcdf/nq_structure.c:221 #, c-format msgid "Retrieve value for variable '%s': %s." msgstr "Lecture de la valeur de la variable « %s » : %s." #: ../lib/plug-ins/nanoquanta-netcdf/nq_basic.c:271 #: ../lib/plug-ins/nanoquanta-netcdf/nq_basic.c:278 #: ../lib/plug-ins/nanoquanta-netcdf/nq_basic.c:289 #, c-format msgid "Checking variable '%s': %s." msgstr "Vérification de la variable « %s » : %s" #: ../lib/plug-ins/nanoquanta-netcdf/nq_basic.c:274 #, c-format msgid "Variable '%s' should be of type '%s'." msgstr "La variable « %s » devrait être de type « %s »." #: ../lib/plug-ins/nanoquanta-netcdf/nq_basic.c:282 #, c-format msgid "Variable '%s' should be a %d dimension array." msgstr "La variable « %s » devrait être un tableau à %d dimension(s)." #: ../lib/plug-ins/nanoquanta-netcdf/nq_basic.c:298 #, c-format msgid "Checking dimension ID %d: %s." msgstr "Vérification de la dimension d'id %d : %s." #: ../lib/plug-ins/nanoquanta-netcdf/nq_basic.c:305 #, c-format msgid "Variable '%s' is not consistent with declaration of dimensions." msgstr "La variable « %s » ne correspond pas à sa déclaration." #: ../lib/plug-ins/nanoquanta-netcdf/nq_structure.c:27 msgid "ETSF file format" msgstr "Format de fichier ETSF" #: ../lib/plug-ins/nanoquanta-netcdf/nq_structure.c:194 #, c-format msgid "Error in indexing array '%s', index out of bounds." msgstr "Erreur d'indexation du tableau « %s », index hors limites." #: ../lib/plug-ins/nanoquanta-netcdf/nq_structure.c:235 #, c-format msgid "Wrong ETSF format, basis-set is degenerated.\n" msgstr "Mauvais format ETSF,la base est dégénérée.\n" #: ../lib/plug-ins/nanoquanta-netcdf/nq_density.c:68 msgid "Nanoquanta NETCDF format" msgstr "Format NetCDF Nanoquanta" #: ../lib/plug-ins/nanoquanta-netcdf/nq_density.c:73 msgid "spin channel (or -1 for all)" msgstr "canal de spin (ou -1 pour tous)" #: ../lib/plug-ins/nanoquanta-netcdf/nq_density.c:75 msgid "real or complex values (or -1 for all)" msgstr "valeurs réelles ou complexes (ou -1 pour toutes)" #: ../lib/plug-ins/nanoquanta-netcdf/nq_density.c:225 #, c-format msgid "Retrieve value for variable 'primitive_vectors': %s." msgstr "Lecture de la valeur pour la variable « primitive_vectors » : %s." #: ../lib/plug-ins/nanoquanta-netcdf/nq_density.c:234 #, c-format msgid "" "The variable 'primitive_vectors' is not well formed (the basis is not 3D)." msgstr "" "La variable « primitive_vectors » n'est pas bien définie (la base n'est pas " "3D)." #: ../lib/plug-ins/nanoquanta-netcdf/nq_density.c:271 #, c-format msgid "Retrieve value for variable 'density': %s." msgstr "Lecture de la valeur pour la variable « density » : %s." #: ../lib/plug-ins/nanoquanta-netcdf/nq_density.c:292 msgid "1, no spin information" msgstr "1, aucune information de spin" #: ../lib/plug-ins/nanoquanta-netcdf/nq_density.c:295 msgid "1, spin-up ; 2, spin-down" msgstr "1, haut-spin ; 2, bas-spin" #: ../lib/plug-ins/nanoquanta-netcdf/nq_density.c:298 msgid "1, average density ; [2;4], magnetisation vector" msgstr "1, densité moyenne ; [2;4], vecteur de magnétisation" #: ../lib/plug-ins/nanoquanta-netcdf/nq_density.c:302 msgid "unknown value" msgstr "valeur inconnue" #: ../lib/plug-ins/msym/msym.c:57 msgid "" "This plug-in introduces support for\n" "point group symmetry detection \n" "thanks to MSYM library (see \n" "http://github.com/mcodev31/libmsym)." msgstr "" "Ce greffon ajoute le support\n" "des symétries du point grace à la bibliothèque MSYM\n" "(voir http://github.com/mcodev31/libmsym)." "" #: ../lib/plug-ins/msym/msym.c:65 ../lib/plug-ins/abinit/ab_symmetry.c:61 msgid "" "left-button\t\t: select one atom to get the equivalent ones\n" "right-button\t\t: switch to observe" msgstr "" "bouton gauche\t: sélectionne un nœud pour obtenir ses équivalents par " "symétrie\n" "bouton droit\t: passer en mode d'observation" #: ../lib/plug-ins/msym/msym.c:88 #, c-format msgid "point group symmetry: %s" msgstr "symétrie du point : %s" #: ../lib/plug-ins/msym/msym.c:190 msgid "Identity" msgstr "Identité" #: ../lib/plug-ins/msym/msym.c:193 msgid "Rotation" msgstr "Rotation" #: ../lib/plug-ins/msym/msym.c:196 msgid "Rotation + reflexion" msgstr "Rotation + réflexion" #: ../lib/plug-ins/msym/msym.c:199 msgid "Reflexion" msgstr "Réflexion" #: ../lib/plug-ins/msym/msym.c:202 #, c-format msgid "Plane (%4.2f ; %4.2f ; %4.2f)" msgstr "Plan (%4.2f ; %4.2f ; %4.2f)" #: ../lib/plug-ins/msym/msym.c:214 msgid "Inversion" msgstr "Inversion" #: ../lib/plug-ins/msym/msym.c:233 #, c-format msgid "%d symmetries (%s)" msgstr "%d symétries (%s)" #: ../lib/plug-ins/msym/msym.c:254 msgid "Geometry threshold:" msgstr "Précision sur la géométrie :" #: ../lib/plug-ins/msym/msym.c:256 msgid "Angle threshold:" msgstr "Précision sur les angles :" #: ../lib/plug-ins/archives/archives.c:54 msgid "" "This plug-in adds support for\n" "compressed input files\n" "(see http://code.google.com/p/libarchive/)." msgstr "" "Ce greffon ajoute le support\n" "des fichiers d'entrées compressés\n" "(voir http://code.google.com/p/libarchive/)." #: ../lib/plug-ins/archives/archives.c:101 msgid "Compressed file formats" msgstr "Format de fichiers compressés" #: ../lib/plug-ins/python-gi/pythongi.c:61 msgid "" "This plug-in allows to execute\n" "Python scripts using GObject\n" "introspection." msgstr "" "Ce greffon permet de lancer\n" "des scripts Python en utilisant GObject\n" "introspection." #. Long description #: ../lib/plug-ins/python-gi/pythongi.c:165 msgid "Python scripting" msgstr "Scripts Python" #. Short description #: ../lib/plug-ins/python-gi/pythongi.c:167 msgid "Python" msgstr "Python" #: ../lib/plug-ins/python-gi/pythongi.c:254 msgid "Python scripts for V_Sim" msgstr "Scripts Python pour V_Sim" #: ../lib/plug-ins/python-gi/pythongi.c:308 msgid "Scripts loaded on startup" msgstr "Scripts lancés au démarrage" #: ../lib/plug-ins/python-gi/pythongi.c:328 msgid "This list is saved with the parameter file." msgstr "Cette liste est sauvée dans le fichier de paramètres." #: ../lib/plug-ins/python-gi/pythongi.c:366 msgid "Interactive scripting" msgstr "Script en interactif" #: ../lib/plug-ins/python-gi/pythongi.c:374 msgid "Load:" msgstr "Charge :" #: ../lib/plug-ins/python-gi/pythongi.c:377 #: ../lib/plug-ins/python-gi/pythongi.c:515 #: ../lib/plug-ins/python-gi/pythongi.c:541 msgid "Choose a Python script" msgstr "Sélectionner un script Python" #: ../lib/plug-ins/python-gi/pythongi.c:422 msgid "Clear Python output." msgstr "Efface la sortie Python." #: ../lib/plug-ins/python-gi/pythongi.c:433 msgid "" "Get the current VisuData object as 'data' variable and the current " "VisuGlView as 'view'." msgstr "" "Associe l'object VisuData courant à la variable « data » et l'object " "VisuGlView courant à « view »." #: ../lib/plug-ins/python-gi/pythongi.c:438 msgid "Python interactive command line" msgstr "Ligne de commande intéractive en Python" #: ../lib/plug-ins/python-gi/pythongi.c:487 msgid "Load a Python script" msgstr "Charge un script Python" #: ../lib/plug-ins/python-gi/pythongi.c:496 #, c-format msgid "Load script \"%s\"\n" msgstr "Charge le script « %s »\n" #: ../lib/plug-ins/python-gi/pythongi.c:516 msgid "Not a regular file." msgstr "Fichier incorrect." #: ../lib/plug-ins/xsf/xsf.c:58 msgid "" "This plug-in reads XSF input files\n" " (position, forces and densities)." msgstr "" "Ce greffon lit les fichiers d'entrée XSF\n" " (positions, forces et densités)." #: ../lib/plug-ins/xsf/xsf.c:117 ../lib/plug-ins/xsf/xsf.c:560 msgid "XCrysDen Structure File format" msgstr "Format de fichier XCrysDen" #: ../lib/plug-ins/xsf/xsf.c:217 ../lib/plug-ins/xsf/xsf.c:226 #, c-format msgid "Wrong XSF format, '%s' flag has a wrong value.\n" msgstr "Mauvais format XSF, la balise « %s » a une mauvaise valeur.\n" #: ../lib/plug-ins/xsf/xsf.c:271 #, c-format msgid "Wrong XSF format, missing float values after tag '%s'.\n" msgstr "Mauvais format XSF, il manque un réel après la balise « %s ».\n" #: ../lib/plug-ins/xsf/xsf.c:297 #, c-format msgid "Wrong XSF format, missing or wrong integer values after tag '%s'.\n" msgstr "" "Mauvais format XSF, il manque un entier ou celui-ci est erroné après la " "balise « %s ».\n" #: ../lib/plug-ins/xsf/xsf.c:314 #, c-format msgid "Wrong XSF format, can't read coordinates at line '%s'.\n" msgstr "" "Mauvais format XSF, impossible de lire les coordonnées depuis « %s ».\n" #: ../lib/plug-ins/xsf/xsf.c:326 #, c-format msgid "Wrong XSF format, can't read coordinates from '%s' (only %d read).\n" msgstr "" "Mauvais format XSF, impossible de lire les coordonnées depuis " "« %s » (seulement %d ont été lues).\n" #: ../lib/plug-ins/xsf/xsf.c:407 #, c-format msgid "Wrong XSF format, '%s' tag already defined.\n" msgstr "Mauvais format XSF, la balise « %s » est déjà définie.\n" #: ../lib/plug-ins/xsf/xsf.c:429 #, c-format msgid "" "Wrong XSF format, primitive vectors found with free boundary conditions.\n" msgstr "" "Mauvais format XSF, des vecteurs primitifs sont donnés pour un système " "isolé.\n" #: ../lib/plug-ins/xsf/xsf.c:459 #, c-format msgid "" "Wrong XSF format, primitive coordinates found with free boundary " "conditions.\n" msgstr "" "Mauvais format XSF, des vecteurs primitifs sont donnés pour un système " "isolé.\n" #: ../lib/plug-ins/xsf/xsf.c:488 #, c-format msgid "" "Wrong XSF format, atom coordinates found with free boundary conditions.\n" msgstr "Mauvais format XSF, impossible de lire les coordonnées.\n" #: ../lib/plug-ins/xsf/xsf.c:529 #, c-format msgid "Wrong XSF format, basis-set is degenerated.\n" msgstr "Mauvais format XSF, la base est dégénérée.\n" #: ../lib/plug-ins/xsf/xsf_density.c:61 msgid "XCrysDen density file format" msgstr "Format de densité XCrysDen" #: ../lib/plug-ins/xsf/xsf_density.c:98 #, c-format msgid "Wrong XSF format, unreadable float value %d for density.\n" msgstr "Mauvais format XSF, valeur de densité %d illisible.\n" #: ../lib/plug-ins/xsf/xsf_density.c:110 #, c-format msgid "Wrong XSF format, missing density lines.\n" msgstr "Mauvais format XYZ, il manque des lignes pour la densité.\n" #: ../lib/plug-ins/xsf/xsf_density.c:124 #, c-format msgid "" "Wrong XSF format, missing float values for density (%d read, %d awaited).\n" msgstr "" "Mauvais format XSF, il manque des valeurs de densité (%d lues, %d " "attendues).\n" #: ../lib/plug-ins/xsf/xsf_density.c:159 #, c-format msgid "Wrong XSF format, missing or wrong mesh size after tag '%s'.\n" msgstr "" "Mauvais format XSF, la taille du maillage est manquante ou mauvaise après le " "marqueur « %s ».\n" #: ../lib/plug-ins/xsf/xsf_density.c:171 #, c-format msgid "Wrong XSF format, missing or wrong translation definition." msgstr "Mauvais format XSF, mauvaise définition de translation." #: ../lib/plug-ins/abinit/abinit.c:72 msgid "" "This plug-in introduces support for\n" "crystallographic structures in\n" "ABINIT input files." msgstr "" "Ce greffon apporte la lecture des\n" "données atomiques des fichiers d'entrée\n" "d'ABINIT." #: ../lib/plug-ins/abinit/abinit.c:150 ../lib/plug-ins/abinit/abinit.c:783 msgid "ABINIT input file format" msgstr "Format de fichier d'ABINIT" #: ../lib/plug-ins/abinit/abinit.c:723 #, c-format msgid "" "Abinit loader report error:\n" " basis-set is degenerated.\n" msgstr "Le chargeur Abinit rapporte une erreur : la base est dégénérée.\n" #: ../lib/plug-ins/abinit/ab_symmetry.c:127 msgid "Symmetries" msgstr "Symétries" #: ../lib/plug-ins/abinit/ab_symmetry.c:146 msgid "Analyse the symmetries" msgstr "Analyse des symétries" #: ../lib/plug-ins/abinit/ab_symmetry.c:151 msgid "Compute symmetries" msgstr "Calcul des symétries" #. A message for ABINIT. #: ../lib/plug-ins/abinit/ab_symmetry.c:173 msgid "" "The symmetry routines are provided by ABINIT (http://www.abinit.org)." msgstr "" "Les routines de calcul des symétries sont fournies " "par ABINIT (http://www.abinit." "org)." #: ../lib/plug-ins/abinit/ab_symmetry.c:184 msgid "Space group:" msgstr "Groupe d'espace :" #: ../lib/plug-ins/abinit/ab_symmetry.c:188 msgid "" "http://en.wikipedia.org/wiki/" "Space_group" msgstr "" "http://en.wikipedia.org/wiki/" "Space_group" #: ../lib/plug-ins/abinit/ab_symmetry.c:197 msgid "Crystal system:" msgstr "Système cristallin :" #: ../lib/plug-ins/abinit/ab_symmetry.c:202 msgid "space group:" msgstr "groupe d'espace :" #: ../lib/plug-ins/abinit/ab_symmetry.c:208 msgid "" "Warning: the Bravais lattice determined from the " "primitive vectors is more symmetric than the real one obtained from " "coordinates (printed)." msgstr "" "Attention : le réseau de Bravais déterminé à " "partir des vecteurs primitifs est plus symétrique que celui obtenu (et " "affiché) à partir des coordonnées." #: ../lib/plug-ins/abinit/ab_symmetry.c:213 msgid "List of symmetry operations:" msgstr "Liste des opérations de symétrie :" #: ../lib/plug-ins/abinit/ab_symmetry.c:228 msgid "operation" msgstr "opération" #: ../lib/plug-ins/abinit/ab_symmetry.c:236 msgid "translation" msgstr "translation" #: ../lib/plug-ins/abinit/ab_symmetry.c:243 msgid "comment" msgstr "commentaire" #. The interface to choose one atom to select. #: ../lib/plug-ins/abinit/ab_symmetry.c:248 msgid "Equivalent atoms:" msgstr "Atomes équivalents :" #: ../lib/plug-ins/abinit/ab_symmetry.c:255 msgid "Visualise the equivalent nodes of node:" msgstr "Visualise les nœuds équivalents au nœud :" #: ../lib/plug-ins/abinit/ab_symmetry.c:261 msgid " or pick directly." msgstr "ou par sélection directe" #: ../lib/plug-ins/abinit/ab_symmetry.c:615 msgid "not primitive" msgstr "non primitive" #: ../lib/plug-ins/abinit/ab_symmetry.c:641 msgid "ABINIT symmetry calculation" msgstr "Calcul des symétries par ABINIT" #: ../lib/plug-ins/abinit/ab_symmetry.c:668 msgid "Unknown symmetry" msgstr "Symétrie inconnue" #: ../lib/plug-ins/fpcrystal/fpcrystal.cpp:18 msgid "a wrapper around CrystalFp." msgstr "un wrapper autour de CrystalFp" #: ../lib/plug-ins/fpcrystal/fpcrystal.cpp:20 #: ../lib/plug-ins/OpenBabel-wrapper/ob_basic.cpp:46 msgid "" "Caliste Damien:\n" " wrapper." msgstr "" "Caliste Damien:\n" " wrapper." #: ../lib/plug-ins/OpenBabel-wrapper/ob_basic.cpp:42 msgid "" "This plug-in wraps the OpenBabel\n" "library (visit the home page at URL\n" "http://www.openbabel.org)." msgstr "" "Ce greffon utilise la bibliothèque OpenBabel\n" "(voir http://www.openbabel.org/)." #: ../lib/plug-ins/OpenBabel-wrapper/ob_basic.cpp:73 msgid "OpenBabel known formats" msgstr "Formats connus d'OpenBabel" #: ../lib/plug-ins/OpenBabel-wrapper/ob_basic.cpp:76 msgid "Add implicit hydrogens" msgstr "Ajoute les hydrogènes implicites" #. Declare the output using OpenBabel. #: ../lib/plug-ins/OpenBabel-wrapper/ob_basic.cpp:83 msgid "OpenBabel output formats" msgstr "Formats d'exportation d'OpenBabel" #: ../lib/plug-ins/OpenBabel-wrapper/ob_basic.cpp:140 #: ../lib/plug-ins/OpenBabel-wrapper/ob_basic.cpp:352 #, c-format msgid "'%s' doesn't match any file format." msgstr "« %s » ne correspond à aucun format connu." #: ../lib/plug-ins/OpenBabel-wrapper/ob_basic.cpp:147 #: ../lib/plug-ins/OpenBabel-wrapper/ob_basic.cpp:359 #, c-format msgid "format of '%s' is not a readable one." msgstr "le format de « %s » n'est pas lisible." #: ../lib/plug-ins/OpenBabel-wrapper/ob_basic.cpp:171 #, c-format msgid "The given file doesn't match the format '%s'." msgstr "Le fichier fourni ne correspond pas au format « %s »." #: ../lib/plug-ins/OpenBabel-wrapper/ob_basic.cpp:196 #, c-format msgid "Wrong OpenBabel format, basis-set is degenerated.\n" msgstr "Mauvais format OpenBabel, la base est dénégérée.\n" #: ../lib/plug-ins/OpenBabel-wrapper/ob_basic.cpp:279 msgid "Implicit H" msgstr "H implicites" #: ../lib/plug-ins/OpenBabel-wrapper/ob_basic.cpp:424 #, c-format msgid "Unable to write the file." msgstr "Impossible d'écrire le fichier." #: ../lib/plug-ins/cube/cube.c:51 msgid "" "This plug-in reads Cube files (see \n" "http://local.wasp.uwa.edu.au/\n" "~pbourke/dataformats/cube/),\n" "both structural and and volumetric data." msgstr "" "Ce greffon lit les fichiers Cube (cf.\n" "http://local.wasp.uwa.edu.au/\n" "~pbourke/dataformats/cube/),\n" "données de structure ou densités." #. char *typeXV[] = {"*.XV", "*.STRUCT_OUT", (char*)0}; #. char *nameXV = "Siesta output format"; #. char *descrXV = _("Siesta geometric output format"); #: ../lib/plug-ins/cube/cube.c:101 ../lib/plug-ins/cube/cube.c:105 msgid "Gaussian structural/volumetric format" msgstr "Format de structure/densités de Gaussian" #: ../lib/plug-ins/cube/cube.c:169 ../lib/plug-ins/cube/cube.c:177 #, c-format msgid "Wrong Cube format, missing comment lines.\n" msgstr "Mauvais format Cube, il manque la ligne de commentaire.\n" #: ../lib/plug-ins/cube/cube.c:195 #, c-format msgid "Wrong Cube format, missing the atom line.\n" msgstr "Mauvais format Cube, il manque la ligne des atomes.\n" #: ../lib/plug-ins/cube/cube.c:202 #, c-format msgid "Wrong Cube format, missing the number of atoms on the third line.\n" msgstr "" "Mauvais format Cube, il manque le nombre d'atomes sur la troisième ligne.\n" #: ../lib/plug-ins/cube/cube.c:221 #, c-format msgid "Wrong Cube format, missing the %d box line.\n" msgstr "Mauvais format Cube, il manque la ligne %d de la boîte.\n" #: ../lib/plug-ins/cube/cube.c:229 #, c-format msgid "Wrong Cube format, missing float values for box definition.\n" msgstr "" "Mauvais format Cube, il manque des valeurs pour la définition de la boîte.\n" #: ../lib/plug-ins/cube/cube.c:236 #, c-format msgid "Wrong Cube format, wrong mesh size in %c direction.\n" msgstr "" "Mauvais format Cube, incorrecte taille de maillage pour la direction %c.\n" #: ../lib/plug-ins/cube/cube.c:272 #, c-format msgid "Wrong Cube format, missing line %d with coordinates.\n" msgstr "Mauvais format Cube, la ligne %d avec les coordonnées est manquante.\n" #: ../lib/plug-ins/cube/cube.c:282 #, c-format msgid "Wrong Cube format, can't read coordinates.\n" msgstr "Mauvais format Cube, impossible de lire les coordonnées.\n" #: ../lib/plug-ins/cube/cube.c:293 #, c-format msgid "" "Wrong Cube format, one atomic number is 0 or lower, or greater than 103, " "check your input file.\n" msgstr "" "Mauvais format Cube, un numéro atomique est 0 ou plus petit, ou plus grand " "que 103, vérifiez votre fichier.\n" #: ../lib/plug-ins/cube/cube.c:339 #, c-format msgid "Wrong Cube format, missing density lines.\n" msgstr "Mauvais format Cube, il manque un entier sur la première ligne.\n" #: ../lib/plug-ins/cube/cube.c:350 #, c-format msgid "Wrong Cube format, unreadable float value %d for density.\n" msgstr "Mauvais format Cube, la valeur %f de densité est illisible.\n" #: ../lib/plug-ins/cube/cube.c:369 #, c-format msgid "" "Wrong Cube format, missing float values for density (%d read, %d awaited).\n" msgstr "" "Mauvais format Cube, il manque des valeurs de densités (%d lues, %d " "attendues).\n" #: ../lib/plug-ins/cube/cube.c:474 #, c-format msgid "Wrong Cube format, basis-set is degenerated.\n" msgstr "Mauvais format Cube, la base est dénégérée.\n" #: ../lib/plug-ins/bigdft/bigdft.c:69 msgid "" "This plug-in adds support for specific\n" "capabilities of BigDFT." msgstr "" "Ce greffon ajoute des fonctions\n" "spécifiques en rapport avec BigDFT." #: ../lib/plug-ins/bigdft/bigdft.c:146 msgid "Wavefunction file from BigDFT" msgstr "Fichier de fontions d'ondes de BigDFT" #: ../lib/plug-ins/bigdft/bigdft.c:150 msgid "BigDFT wavelet boxes" msgstr "boîte d'ondelettes de BigDFT" #: ../lib/plug-ins/bigdft/bigdft.c:153 msgid "Hgrid along x" msgstr "Hgrid le long de x" #: ../lib/plug-ins/bigdft/bigdft.c:154 msgid "Hgrid along y" msgstr "Hgrid le long de y" #: ../lib/plug-ins/bigdft/bigdft.c:155 msgid "Hgrid along z" msgstr "Hgrid le long de z" #: ../lib/plug-ins/bigdft/bigdft.c:156 msgid "Coarse grid multiplier" msgstr "Facteur grille grossière" #: ../lib/plug-ins/bigdft/bigdft.c:157 msgid "Fine grid multiplier" msgstr "Facteur grille fine" #: ../lib/plug-ins/bigdft/bigdft.c:158 msgid "Exchange-correlation functional code" msgstr "Code de fonctionnelle d'échange et corrélation" #: ../lib/plug-ins/bigdft/bigdft.c:159 msgid "Number of processors for memory estimation" msgstr "Nombre de processus pour l'estimation mémoire" #: ../lib/plug-ins/bigdft/bigdft.c:207 msgid "BigDFT settings" msgstr "Paramètres de BigDFT" #: ../lib/plug-ins/bigdft/bigdft.c:272 msgid "BigDFT specific parameters" msgstr "Paramètres particuliers à BigDFT" #: ../lib/plug-ins/bigdft/bigdft.c:280 msgid "use BigDFT to load xyz and ASCII files" msgstr "utiliser BigDFT pour charger les fichiers xyz et ASCII" #: ../lib/plug-ins/bigdft/bigdft.c:289 msgid "hgrids:" msgstr "hgrids :" #: ../lib/plug-ins/bigdft/bigdft.c:307 msgid "ixc:" msgstr "ixc :" #: ../lib/plug-ins/bigdft/bigdft.c:319 msgid "show _coarse grid" msgstr "montrer la grille _grossière" #: ../lib/plug-ins/bigdft/bigdft.c:328 ../lib/plug-ins/bigdft/bigdft.c:370 msgid "radius of ele." msgstr "rayon des élé." #: ../lib/plug-ins/bigdft/bigdft.c:360 msgid "show _fine grid" msgstr "montrer la grille _fine" #: ../lib/plug-ins/bigdft/bigdft.c:412 msgid "Memory estimation" msgstr "Estimation mémoire" #: ../lib/plug-ins/bigdft/bigdft.c:415 msgid "Memory estimation for" msgstr "Estimation mémoire pour" #: ../lib/plug-ins/bigdft/bigdft.c:422 msgid "core(s)" msgstr "cœur(s)" #: ../lib/plug-ins/bigdft/bigdft.c:443 msgid "Running BigDFT" msgstr "Lancer BigDFT" #: ../lib/plug-ins/bigdft/bigdft.c:558 #, c-format msgid "Can't read wavefunction %d from file '%s'." msgstr "Impossible de lire la fonction d'onde %d depuis le fichier « %s »." #. Add options to the field. #: ../lib/plug-ins/bigdft/bigdft.c:598 ../lib/plug-ins/bigdft/bigdft.c:720 msgid "orbital id" msgstr "id d'orbital" #: ../lib/plug-ins/bigdft/bigdft.c:601 ../lib/plug-ins/bigdft/bigdft.c:733 msgid "spin id" msgstr "id de spin" #: ../lib/plug-ins/bigdft/bigdft.c:609 ../lib/plug-ins/bigdft/bigdft.c:725 msgid "k-point id" msgstr "id du point-k" #: ../lib/plug-ins/bigdft/bigdft.c:612 ../lib/plug-ins/bigdft/bigdft.c:745 msgid "real/imag or partial density" msgstr "réelle/imaginaire ou densité partielle" #: ../lib/plug-ins/bigdft/bigdft.c:655 msgid "Choose orbital:" msgstr "Choix de l'orbitale :" #: ../lib/plug-ins/bigdft/bigdft.c:659 msgid "band id:" msgstr "id de bande" #: ../lib/plug-ins/bigdft/bigdft.c:670 msgid "spin:" msgstr "spin :" #: ../lib/plug-ins/bigdft/bigdft.c:678 ../lib/plug-ins/bigdft/bigdft_run.c:260 msgid "up" msgstr "up" #: ../lib/plug-ins/bigdft/bigdft.c:679 ../lib/plug-ins/bigdft/bigdft_run.c:274 msgid "down" msgstr "down" #: ../lib/plug-ins/bigdft/bigdft.c:688 msgid "k-point:" msgstr "point-k :" #: ../lib/plug-ins/bigdft/bigdft.c:699 msgid "representation:" msgstr "représentation :" #: ../lib/plug-ins/bigdft/bigdft.c:703 ../lib/plug-ins/bigdft/bigdft_run.c:344 msgid "partial density" msgstr "densité partielle" #: ../lib/plug-ins/bigdft/bigdft.c:704 ../lib/plug-ins/bigdft/bigdft_run.c:342 msgid "real part" msgstr "partie réelle" #: ../lib/plug-ins/bigdft/bigdft.c:706 ../lib/plug-ins/bigdft/bigdft_run.c:343 msgid "imaginary part" msgstr "partie imaginaire" #: ../lib/plug-ins/bigdft/bigdft.c:851 ../lib/plug-ins/bigdft/bigdft.c:858 #, c-format msgid "%d grid points" msgstr "%d points de grille" #: ../lib/plug-ins/bigdft/bigdft.c:853 ../lib/plug-ins/bigdft/bigdft.c:860 msgid "no grid" msgstr "pas de grille" #: ../lib/plug-ins/bigdft/bigdft_run.c:217 msgid "Run locally" msgstr "Lancer en local" #: ../lib/plug-ins/bigdft/bigdft_run.c:221 msgid "Go go go..." msgstr "C'est parti !" #: ../lib/plug-ins/bigdft/bigdft_run.c:235 msgid "Rho / V:" msgstr "Rho / V :" #: ../lib/plug-ins/bigdft/bigdft_run.c:238 msgid "_Density" msgstr "_Densité" #: ../lib/plug-ins/bigdft/bigdft_run.c:242 msgid "V_ext" msgstr "V_ext" #: ../lib/plug-ins/bigdft/bigdft_run.c:247 msgid "V_hartr" msgstr "H_hartr" #: ../lib/plug-ins/bigdft/bigdft_run.c:250 msgid "V_xc" msgstr "V_xc" #: ../lib/plug-ins/bigdft/bigdft_run.c:257 msgid "Wavefunctions:" msgstr "Fonctions d'ondes :" #: ../lib/plug-ins/bigdft/bigdft_run.c:290 msgid "for k-point(s)" msgstr "pour les point(s)-k" #: ../lib/plug-ins/bigdft/bigdft_run.c:334 msgid "retrieve selection" msgstr "récupérer la sélection" #: ../lib/plug-ins/bigdft/bigdft_run.c:339 msgid "Wfn. repr.:" msgstr "Repr. des f. d'ondes :" #: ../lib/plug-ins/bigdft/bigdft_run.c:538 #, c-format msgid "" "partial density (iter: %d)\n" " ikpt: %d, iorb: %d" msgstr "" "densité partielle (itération : %d)\n" " ikpt: %d, iorb: %d" #: ../lib/plug-ins/bigdft/bigdft_run.c:541 #, c-format msgid "" "wavefunction (iter: %d)\n" " ikpt: %d, iorb: %d" msgstr "" "fonction d'onde (itération : %d)\n" " ikpt: %d, iorb: %d" #: ../lib/plug-ins/bigdft/bigdft_run.c:551 msgid "Retrieve wavefunction" msgstr "Récupérer les fonctions d'ondes" #: ../lib/plug-ins/bigdft/bigdft_run.c:552 msgid "Wavefunction has no imaginary part" msgstr "La fonction d'onde n'a pas de partie imaginaire" #: ../lib/plug-ins/bigdft/bigdft_run.c:576 msgid "external potential" msgstr "potentiel exterieur" #: ../lib/plug-ins/bigdft/bigdft_run.c:582 #, c-format msgid "electronic density (iter: %d)" msgstr "densité électronique (itération : %d)" #: ../lib/plug-ins/bigdft/bigdft_run.c:724 msgid "Energies in _Ht" msgstr "Énergies en _Ht" #: ../lib/plug-ins/bigdft/bigdft_run.c:729 msgid "Energies in _eV" msgstr "Énergies en _eV" #: ../lib/plug-ins/bigdft/bigdft_run.c:1074 msgid "Running BigDFT on a host" msgstr "Lancer BigDFT sur un hôte" #: ../lib/plug-ins/bigdft/bigdft_run.c:1122 #, c-format msgid "%s" msgstr "%s" #: ../lib/plug-ins/bigdft/bigdft_run.c:1180 msgid "Hamiltonian optimisation" msgstr "Optimisation de l'hamiltonien" #: ../lib/plug-ins/bigdft/bigdft_run.c:1182 msgid "Sub-space optimisation" msgstr "Optimisation du sous-espace" #: ../lib/plug-ins/bigdft/bigdft_run.c:1184 msgid "Wfn iteration" msgstr "Itération de f. d'ondes" #: ../lib/plug-ins/bigdft/bigdft_run.c:1189 msgid "Initial stage" msgstr "Étape initiale" #: ../lib/plug-ins/bigdft/bigdft_run.c:1213 #, c-format msgid "kpt %d (%3.3f,%3.3f,%3.3f - %3.3f)" msgstr "kpt %d (%3.3f,%3.3f,%3.3f - %3.3f)" #: ../lib/plug-ins/bigdft/bigdft_run.c:1224 #: ../lib/plug-ins/bigdft/bigdft_run.c:1232 #, c-format msgid "orb. %d" msgstr "orb. %d" #~ msgid "WARNING : wrong fortran syntax, flag size unmatched.\n" #~ msgstr "" #~ "AVERTISSEMENT! Syntaxe Fortran incorrecte, la taille des repères " #~ "diffère.\n" #~ msgid "Impossible to open this file." #~ msgstr "Impossible d'ouvrir ce fichier." #~ msgid "Remove all highlight marks for the nodes of the list." #~ msgstr "Retire toutes les mises en évidence des nœuds de la liste." #~ msgid "Put a highlight mark on all the nodes of the list." #~ msgstr "Met en évidence tous les nœuds de la liste." #~ msgid "Dump object signals and properties for introspection." #~ msgstr "Export les signaux et les propriétés pour l'introspection." #~ msgid "fileToDump" #~ msgstr "fichierExport" #~ msgid "impossible to read Fortran flag, '%s' error.\n" #~ msgstr "impossible de lire le flag Fortran, erreur dans « %s ».\n" #~ msgid "flag size unmatch, '%s' error.\n" #~ msgstr "incohérence sur la taille des repères, erreur dans « %s ».\n" #~ msgid "" #~ "impossible to read %d characters (%d read, feof: %d, ferror: %d), '%s' " #~ "error.\n" #~ msgstr "" #~ "impossible de lire %d caractères (%d lus, feof: %d, ferror: %d), erreur « " #~ "%s ».\n" #~ msgid "" #~ "impossible to read %d integers (%d read, feof: %d, ferror: %d), '%s' " #~ "error.\n" #~ msgstr "" #~ "impossible de lire %d entiers (%d read, feof: %d, ferror: %d), erreur « " #~ "%s ».\n" #~ msgid "" #~ "impossible to read %d real (%d read, feof: %d, ferror: %d), '%s' error.\n" #~ msgstr "" #~ "impossible de lire %d nombres réels (%d read, feof: %d, ferror: %d), " #~ "erreur « %s ».\n" #~ msgid "" #~ "impossible to read %d double (%d read, feof: %d, ferror: %d), '%s' " #~ "error.\n" #~ msgstr "" #~ "impossible de lire %d nombres réels double précision (%d read, feof: %d, " #~ "ferror: %d), erreur « %s ».\n" #~ msgid "Background: %s" #~ msgstr "Fond : %s" #~ msgid "List of nodes (none)" #~ msgstr "Liste de nœuds (aucun)" #~ msgid "Capture the perpendicular to the current view." #~ msgstr "Récupère la direction perpendiculaire à la vue courante." #~ msgid "Model: " #~ msgstr "Modèle : " #~ msgid "not enough meshy values.\n" #~ msgstr "données de meshy manquantes.\n" #~ msgid "impossible to read meshy values.\n" #~ msgstr "impossible de lire la valeur d'iso-densité.\n" #~ msgid "not enough meshz values.\n" #~ msgstr "données de meshz manquantes.\n" #~ msgid "impossible to read meshz values.\n" #~ msgstr "impossible de lire la valeur d'iso-densité.\n" #~ msgid "" #~ "While parsing parameter file '%s':\n" #~ "\n" #~ "%s" #~ msgstr "" #~ "Lors de la lecture du fichier de paramètres « %s » :\n" #~ "\n" #~ "%s" #~ msgid "" #~ "While parsing resource file '%s':\n" #~ "\n" #~ "%s" #~ msgstr "" #~ "Lors de la lecture du fichier de ressources « %s » :\n" #~ "\n" #~ "%s" #~ msgid "" #~ "While parsing command line options:\n" #~ "\n" #~ "%s" #~ msgstr "" #~ "Lors de la lecture des options en ligne de commande :\n" #~ "\n" #~ "%s" #~ msgid "Node" #~ msgstr "Nœud" #~ msgid "List of nodes (%d):" #~ msgstr "Liste de nœuds (%d) :" #~ msgid "Units and lengths" #~ msgstr "Unités et longueurs" #~ msgid "Loading a scalar field file" #~ msgstr "Chargement d'un fichier de données volumiques" #~ msgid "Loading a value file" #~ msgstr "Chargement d'un fichier de données" #~ msgid "Loading the reference file" #~ msgstr "Chargement d'un fichier de référence" #~ msgid "Translation in data grid is an unsupported feature of XSF files." #~ msgstr "Les translations des grilles de données ne sont pas supportées." #~ msgid "Description:" #~ msgstr "Description :" #~ msgid "None" #~ msgstr "Aucun" #~ msgid "File tools" #~ msgstr "Fichiers" #~ msgid "Load a plane list:" #~ msgstr "Charger une liste de plans :" #~ msgid "Current loaded list:" #~ msgstr "Liste actuellement chargée :" #~ msgid "Choose a file with a list of planes" #~ msgstr "Choix d'un fichier contenant une liste de plans" #~ msgid "Plane description (*.xml)" #~ msgstr "Description de plans (*.xml)" #~ msgid "Image size & position _follow the camera" #~ msgstr "La taille et la position de l'image _suit la camera" #~ msgid "Selected files are used for:" #~ msgstr "Les fichiers sélectionnés sont utilisés pour :" #~ msgid "position" #~ msgstr "position" #~ msgid "spin" #~ msgstr "spin" #~ msgid "Set the selected file as position to load." #~ msgstr "Choisi le fichier sélectionné comme fichier de positions." #~ msgid "Set the selected file as spin to load." #~ msgstr "Choisi le fichier sélectionné comme fichier de spin." #~ msgid "Spin shape:" #~ msgstr "Forme des spins :" #~ msgid "selected surface" #~ msgstr "sélectionnées" #~ msgid "all surfaces" #~ msgstr "toutes" #~ msgid "Plane masking" #~ msgstr "Masquage des plans" #~ msgid "Internal error, cannot create type for '%s'." #~ msgstr "Erreur interne, impossible de créer le type « %s »." #~ msgid "Parse error at line %d, the shape '%s' is unknown.\n" #~ msgstr "Erreur de lecture à la ligne %d : la forme '%s' est inconnue.\n" #~ msgid "Parse error at line %d, the hiding mode '%s' is unknown.\n" #~ msgstr "" #~ "Erreur de lecture à la ligne %d : le mode de masquage '%s' est inconnu.\n" #~ msgid "Parse error at line %d, the modulus mode '%d' is unknown.\n" #~ msgstr "" #~ "Erreur de lecture à la ligne %d : le mode de module '%s' est inconnu.\n" #~ msgid "" #~ "Parse error at line %d: a shape with 4 floating points and 2 booleans " #~ "must appear after the %s markup.\n" #~ msgstr "" #~ "Erreur de lecture à la ligne %d: une forme suivie de 4 flottants et deux " #~ "booléen est attendues après le marqueur « %s ».\n" #~ msgid "Parse error at line %d: the shape '%s' is unknown.\n" #~ msgstr "Erreur de lecture à la ligne %d: la forme '%s' est inconnue.\n" #~ msgid "Parse error at line %d: the sphere method '%s' is unknown.\n" #~ msgstr "Erreur de lecture à la ligne %d : la méthode « %s » est inconnue.\n" #~ msgid "Can't parse resource '%s' of iso-surfaces on line %d.\n" #~ msgstr "" #~ "Impossible d'analyser les ressources « %s » d'une iso-surface à la ligne " #~ "%d.\n" #~ msgid "Can't find any column of data in the given file.\n" #~ msgstr "" #~ "Impossible de rouver de données en colonne dans le fichier fourni.\n" #~ msgid "There are more nodes than data.\n" #~ msgstr "Il y a plus de données que de nœuds.\n" #~ msgid "No data" #~ msgstr "Aucune donnée" #~ msgid "cyl.:" #~ msgstr "cyl. :" #~ msgid "Parse error at line %d: stipple must be in 1-65535.\n" #~ msgstr "" #~ "Erreur de lecture à la ligne %d: the schéma de ligne doit être dans " #~ "0-65535.\n" #~ msgid "Parse error at line %d: width must be in %d-%d.\n" #~ msgstr "Erreur de lecture à la ligne %d: la largeur doit être dans %d-%d.\n" #~ msgid "Parse error at line %d: radius (%g) must be in %g-%g.\n" #~ msgstr "Erreur de lecture à la ligne %d : le rayon doit être dans %g/%g.\n" #~ msgid "Parse error at line %d: radius must be in %g-%g.\n" #~ msgstr "Erreur de lecture à la ligne %d : le rayon doit être dans %g/%g.\n" #~ msgid "pat." #~ msgstr "motif" #~ msgid "Set the color of the background." #~ msgstr "Change la coleur du fond." #~ msgid "" #~ "Parse error at line %d, 1 string value must appear after the %s markup.\n" #~ msgstr "" #~ "Erreur de lecture à la ligne %d : une chaîne de caractères est attendue " #~ "après le marqueur « %s ».\n" #~ msgid "" #~ "Parse error at line %d, given distance are out of bounds (should be " #~ "positive).\n" #~ msgstr "" #~ "Erreur de lecture à la ligne %d : la distance donnée est hors limites " #~ "(valeur positive attendue).\n" #~ msgid "" #~ "Parse error at line %d, 3 floating points(0 <= v <= 1) must appear after " #~ "the %s markup.\n" #~ msgstr "" #~ "Erreur de lecture à la ligne %d : 3 valeurs réelles (0. < v <= 1.) sont " #~ "attendues après le marqueur « %s ».\n" #~ msgid "" #~ "Parse error at line %d, 5 floating points must appear after the %s " #~ "markup.\n" #~ msgstr "" #~ "Erreur de lecture à la ligne %d : 5 valeurs réelles sont attendues après " #~ "le marqueur « %s ».\n" #~ msgid "" #~ "Parse error at line %d: 4 floating points(0 <= v <= 1) must appear after " #~ "the %s markup.\n" #~ msgstr "" #~ "Erreur de lecture à la ligne %d: 4 valeurs réelles (0. < v <= 1.) sont " #~ "attendues après le marqueur « %s ».\n" #~ msgid "" #~ "Parse error at line %d: 1 floating point(1 <= v <= 10) must appear after " #~ "the %s markup.\n" #~ msgstr "" #~ "Erreur de lecture à la ligne %d: une valeur réelle (0. < v <= 10) est " #~ "attendue après le marqueur « %s ».\n" #~ msgid "Parse error at line %d: prefered shade must be positive.\n" #~ msgstr "" #~ "Erreur de lecture à la ligne %d : le dégradé préféré doit être positif.\n" #~ msgid "Remove a link definition." #~ msgstr "Retire la définition de liaison sélectionnée." #~ msgid "" #~ "Add a new link definition using (0., 0.) if it does not already exist." #~ msgstr "" #~ "Ajoute une nouvelle définition de liaison en utilisant (0., 0.) si celle-" #~ "ci n'existe pas déjà." #~ msgid "from %7.3f to %7.3f" #~ msgstr "de %7.3f à %7.3f" #~ msgid "Parse error at line %d: angle must be positive.\n" #~ msgstr "" #~ "Erreur de lecture à la ligne %d : les angles doivent être positif.\n" #~ msgid "unknown shade id (max is %d)." #~ msgstr "identifiant de dégradé inconnu (%d maximum)." #~ msgid "Name of the method." #~ msgstr "Nom de la méthode." #~ msgid "Label of the method." #~ msgstr "Nom affiché de la méthode." #~ msgid "Description of the method." #~ msgstr "Description de la méthode." #~ msgid "Required number of input files to read to load a data." #~ msgstr "Nombre de fichiers à lire pour charger une configuration." #~ msgid "The specified file is an empty file." #~ msgstr "Le fichier indiqué est vide." #~ msgid "Parse error at line %d: there is no specified method.\n" #~ msgstr "" #~ "Erreur de lecture à la ligne %d : il n'y a pas de méthode spécifiée.\n" #~ msgid "Parse error at line %d: the specified method (%s) is unknown.\n" #~ msgstr "" #~ "Erreur de lecture à la ligne %d : la méthode de rendu spécifiée (« %s ») " #~ "est inconnue.\n" #~ msgid "Parse error at line %d: the extension '%s' is unknown.\n" #~ msgstr "Erreur de lecture à la ligne %d : l'extension '%s' est inconnue.\n" #~ msgid "Parse error at line %d: the rendering mode '%s' is unknown.\n" #~ msgstr "" #~ "Erreur de lecture à la ligne %d : le mode de rendu '%s' est inconnue.\n" #~ msgid "" #~ "Internal error,\n" #~ "no preview available" #~ msgstr "" #~ "Erreur interne,\n" #~ "pas de prévisualisation" v_sim-3.8.0/po/v_sim.pot000066400000000000000000004161601370110300500151140ustar00rootroot00000000000000# SOME DESCRIPTIVE TITLE. # Copyright (C) YEAR THE PACKAGE'S COPYRIGHT HOLDER # This file is distributed under the same license as the PACKAGE package. # FIRST AUTHOR , YEAR. # #, fuzzy msgid "" msgstr "" "Project-Id-Version: PACKAGE VERSION\n" "Report-Msgid-Bugs-To: \n" "POT-Creation-Date: 2020-07-07 15:41+0200\n" "PO-Revision-Date: YEAR-MO-DA HO:MI+ZONE\n" "Last-Translator: FULL NAME \n" "Language-Team: LANGUAGE \n" "Language: \n" "MIME-Version: 1.0\n" "Content-Type: text/plain; charset=UTF-8\n" "Content-Transfer-Encoding: 8bit\n" #: ../src/visu_pairset.c:653 ../src/renderingMethods/elementRenderer.c:815 #: ../src/renderingMethods/elementAtomic.c:976 #: ../src/renderingMethods/elementSpin.c:810 #, c-format msgid "'%s' wrong element name" msgstr "" #: ../src/visu_pairset.c:661 #, c-format msgid "2 elements should appear here but %d has been found" msgstr "" #: ../src/visu_pairset.c:672 #, c-format msgid "'%s' wrong floating point value" msgstr "" #: ../src/visu_pairset.c:680 #, c-format msgid "2 floating point values should appear here but %d has been found" msgstr "" #: ../src/visu_dataloader.c:238 msgid "Loading..." msgstr "" #: ../src/loaders/atomic_d3.c:93 msgid "Native binary format" msgstr "" #: ../src/loaders/atomic_d3.c:192 #, c-format msgid "unknwon peridicity flag '%s'" msgstr "" #: ../src/loaders/atomic_d3.c:298 msgid "wrong d3 syntax, awaiting Nat and Ntypes." msgstr "" #: ../src/loaders/atomic_d3.c:350 #, c-format msgid "wrong d3 syntax, sum of nattyp (%d) is not equal to nat (%d)\n" msgstr "" #: ../src/loaders/atomic_d3.c:445 #, c-format msgid "input file has no dataset number %d (%d have been read).\n" msgstr "" #: ../src/loaders/atomic_xyz.c:103 msgid "'Element x y z' format" msgstr "" #: ../src/loaders/atomic_xyz.c:260 #, c-format msgid "Wrong XYZ format, 'Atom X Y Z' awaited." msgstr "" #: ../src/loaders/atomic_xyz.c:267 #, c-format msgid "Wrong XYZ + vibration format, 'Atom X Y Z vx vy vz' awaited." msgstr "" #: ../src/loaders/atomic_xyz.c:324 #, c-format msgid "Missing forces (%d read but %d declared).\n" msgstr "" #: ../src/loaders/atomic_xyz.c:333 #, c-format msgid "Cannot read forces in '%s'.\n" msgstr "" #: ../src/loaders/atomic_xyz.c:435 #, c-format msgid "" "Wrong XYZ format, no number of atoms on line.\n" " '%s'" msgstr "" #: ../src/loaders/atomic_xyz.c:491 #, c-format msgid "Missing coordinates (%d read but %d declared).\n" msgstr "" #: ../src/loaders/atomic_xyz.c:561 ../src/loaders/atomic_ascii.c:473 #, c-format msgid "The file contains no atom coordinates.\n" msgstr "" #: ../src/loaders/atomic_yaml.c:97 msgid "BigDFT YAML format" msgstr "" #: ../src/loaders/atomic_yaml.c:127 ../src/loaders/atomic_yaml.c:162 #: ../src/loaders/atomic_yaml.c:438 ../src/loaders/atomic_yaml.c:444 #: ../src/visu_glnodescene.c:2298 #: ../lib/plug-ins/OpenBabel-wrapper/ob_basic.cpp:267 #: ../lib/plug-ins/OpenBabel-wrapper/ob_basic.cpp:385 msgid "Fragment" msgstr "" #: ../src/loaders/atomic_yaml.c:370 ../src/loaders/atomic_ascii.c:491 #, c-format msgid "" "Wrong (ab) angle, should be different from 0[pi].\n" "\n" " Quoting '%g'.\n" msgstr "" #: ../src/loaders/atomic_yaml.c:413 #, c-format msgid "Unsupported boundary conditions.\n" msgstr "" #: ../src/loaders/atomic_yaml.c:444 msgid "External potential" msgstr "" #: ../src/loaders/atomic_yaml.c:451 msgid "sigma" msgstr "" #: ../src/loaders/atomic_yaml.c:457 msgid "poles" msgstr "" #: ../src/loaders/atomic_yaml.c:504 msgid "Pole" msgstr "" #: ../src/loaders/atomic_yaml.c:584 #, c-format msgid "Unsupported units.\n" msgstr "" #: ../src/loaders/atomic_ascii.c:109 msgid "'x y z Element' format" msgstr "" #: ../src/loaders/atomic_ascii.c:372 #, c-format msgid "Cannot read dxx dyx dyy on 2nd line of ASCII file.\n" msgstr "" #: ../src/loaders/atomic_ascii.c:393 #, c-format msgid "Cannot read dzx dzy dzz on 3rd line of ASCII file.\n" msgstr "" #: ../src/loaders/atomic_ascii.c:447 #, c-format msgid "" "Cannot read x, y, z, name in ASCII file at line %d.\n" "\n" "Quoting '%s'.\n" msgstr "" #: ../src/visu_main.c:149 msgid "Visualise atomic simulations" msgstr "" #: ../src/uiElements/ui_boxTransform.c:242 msgid "non periodic data" msgstr "" #: ../src/uiElements/ui_boxTransform.c:246 msgid "(wire X)" msgstr "" #: ../src/uiElements/ui_boxTransform.c:249 msgid "(wire Y)" msgstr "" #: ../src/uiElements/ui_boxTransform.c:252 msgid "(wire Z)" msgstr "" #: ../src/uiElements/ui_boxTransform.c:255 msgid "(surface XY)" msgstr "" #: ../src/uiElements/ui_boxTransform.c:258 msgid "(surface YZ)" msgstr "" #: ../src/uiElements/ui_boxTransform.c:261 msgid "(surface ZX)" msgstr "" #: ../src/uiElements/ui_boxTransform.c:264 msgid "(periodic)" msgstr "" #: ../src/uiElements/ui_boxTransform.c:267 msgid "unknown periodicity" msgstr "" #: ../src/uiElements/ui_boxTransform.c:304 ../src/interface.c:642 #: ../src/panelModules/panelGeometry.c:198 msgid "dx:" msgstr "" #: ../src/uiElements/ui_boxTransform.c:305 ../src/interface.c:668 #: ../src/panelModules/panelGeometry.c:199 msgid "dy:" msgstr "" #: ../src/uiElements/ui_boxTransform.c:306 #: ../src/panelModules/panelGeometry.c:200 msgid "dz:" msgstr "" #: ../src/uiElements/ui_boxTransform.c:331 msgid "Periodic operations" msgstr "" #: ../src/uiElements/ui_boxTransform.c:355 msgid "_Translations" msgstr "" #: ../src/uiElements/ui_boxTransform.c:357 msgid "Translations are given in box coordinates." msgstr "" #: ../src/uiElements/ui_boxTransform.c:361 msgid "_Put in the box" msgstr "" #: ../src/uiElements/ui_boxTransform.c:363 msgid "Nodes are automatically translated back into the bounding box." msgstr "" #: ../src/uiElements/ui_boxTransform.c:393 msgid "_Expand nodes" msgstr "" #: ../src/uiElements/ui_boxTransform.c:395 msgid "" "The size of the expansion is given in box coordinates. Nodes are " "automatically translated back into the new defined area. The drawn bounding " "box is kept to the original size." msgstr "" #. The rendering parameters. #: ../src/uiElements/ui_boxTransform.c:403 msgid "param.:" msgstr "" #: ../src/uiElements/ui_boxTransform.c:437 msgid "Box settings" msgstr "" #: ../src/uiElements/ui_boxTransform.c:448 msgid "Set the unit of the file:" msgstr "" #: ../src/uiElements/ui_boxTransform.c:463 msgid "Hide nodes with respect to box:" msgstr "" #: ../src/uiElements/ui_boxTransform.c:468 ../src/panelModules/gtkSpin.c:241 msgid "never" msgstr "" #: ../src/uiElements/ui_boxTransform.c:470 msgid "outside" msgstr "" #: ../src/uiElements/ui_boxTransform.c:472 msgid "inside" msgstr "" #: ../src/uiElements/ui_scale.c:156 msgid "" "Several scales are defined from resource files, but only one is " "editable." msgstr "" #: ../src/uiElements/ui_scale.c:165 msgid "Legend:" msgstr "" #: ../src/uiElements/ui_scale.c:170 msgid "Default legend displays the length." msgstr "" #: ../src/uiElements/ui_scale.c:173 msgid "Use blank legend to print the default value with the distance." msgstr "" #: ../src/uiElements/ui_scale.c:179 msgid "Length:" msgstr "" #: ../src/uiElements/ui_scale.c:191 msgid "Origin:" msgstr "" #: ../src/uiElements/ui_scale.c:208 msgid "Orientation:" msgstr "" #: ../src/uiElements/ui_scale.c:238 ../src/coreTools/toolFileFormat.c:168 #: ../src/visu_data.c:1690 msgid "Label" msgstr "" #: ../src/uiElements/ui_pairtree.c:381 msgid "Pair" msgstr "" #: ../src/uiElements/ui_pairtree.c:399 msgid "From" msgstr "" #: ../src/uiElements/ui_pairtree.c:409 msgid "To" msgstr "" #: ../src/uiElements/ui_pairtree.c:419 msgid "Lg." msgstr "" #: ../src/uiElements/ui_pairtree.c:426 ../src/uiElements/ui_planetree.c:659 msgid "Parameters" msgstr "" #. px is for pixels and pat. for pattern. #: ../src/uiElements/ui_pairtree.c:650 msgid "wire:" msgstr "" #. px for pixel. #: ../src/uiElements/ui_pairtree.c:652 #: ../src/extraGtkFunctions/gtk_dumpDialogWidget.c:312 #: ../src/extraGtkFunctions/gtk_dumpDialogWidget.c:327 #: ../src/extraGtkFunctions/gtk_lineObjectWidget.c:405 msgid "px" msgstr "" #: ../src/uiElements/ui_pairtree.c:652 msgid "pattern:" msgstr "" #. a.u. is for arbitrary units. #: ../src/uiElements/ui_pairtree.c:659 ../src/uiElements/ui_pairtree.c:663 msgid "radius:" msgstr "" #: ../src/uiElements/ui_pairtree.c:660 msgid "a.u." msgstr "" #: ../src/uiElements/ui_pairtree.c:1013 msgid "Manage links: " msgstr "" #: ../src/uiElements/ui_pairtree.c:1029 msgid "Show/hide the undrawn pairs." msgstr "" #. Create the part for the link parameters. #: ../src/uiElements/ui_link.c:298 msgid "" "Link parameters:\t (apply to one or more " "selected rows)" msgstr "" #: ../src/uiElements/ui_link.c:313 ../src/panelModules/panelPlanes.c:229 msgid "From: " msgstr "" #: ../src/uiElements/ui_link.c:322 msgid " to: " msgstr "" #: ../src/uiElements/ui_link.c:331 msgid "_Auto set" msgstr "" #: ../src/uiElements/ui_link.c:336 msgid "" "Set the distance criterion to select the first pick in the distance " "distribution between all nodes of the selected types." msgstr "" #: ../src/uiElements/ui_link.c:362 msgid "Thickness:" msgstr "" #: ../src/uiElements/ui_link.c:370 msgid "Pattern:" msgstr "" #: ../src/uiElements/ui_link.c:384 msgid "Color _varies with length:" msgstr "" #: ../src/uiElements/ui_link.c:395 ../src/uiElements/ui_atomic.c:169 msgid "Radius:" msgstr "" #: ../src/uiElements/ui_link.c:407 ../src/panelModules/panelFogBgColor.c:298 msgid "Color:" msgstr "" #: ../src/uiElements/ui_link.c:411 msgid "_user defined" msgstr "" #: ../src/uiElements/ui_link.c:417 msgid "_elements" msgstr "" #: ../src/uiElements/ui_link.c:430 msgid "_nodes" msgstr "" #: ../src/uiElements/ui_elements.c:206 msgid "Set caracteristics of: " msgstr "" #. We create the tree widget that show the methods. #: ../src/uiElements/ui_elements.c:212 #, c-format msgid "Element '%s'" msgstr "" #: ../src/uiElements/ui_elements.c:219 msgid "Standard resources" msgstr "" #: ../src/uiElements/ui_elements.c:231 msgid "rendered" msgstr "" #: ../src/uiElements/ui_elements.c:240 msgid "Make nodes sensitive to a colorization effect." msgstr "" #: ../src/uiElements/ui_elements.c:242 msgid "colorizable" msgstr "" #: ../src/uiElements/ui_elements.c:245 msgid "Make nodes sensitive to the masking effect of planes." msgstr "" #: ../src/uiElements/ui_elements.c:250 msgid "Rendering specific resources" msgstr "" #: ../src/uiElements/ui_atomic.c:178 ../src/uiElements/ui_spin.c:206 msgid "Shape: " msgstr "" #: ../src/uiElements/ui_atomic.c:192 msgid "Parameters for elipsoid shape" msgstr "" #: ../src/uiElements/ui_atomic.c:197 msgid "Ratio: " msgstr "" #: ../src/uiElements/ui_atomic.c:205 msgid "Phi: " msgstr "" #: ../src/uiElements/ui_atomic.c:213 msgid "Theta: " msgstr "" #: ../src/uiElements/ui_spin.c:218 msgid "Size and color properties:" msgstr "" #: ../src/uiElements/ui_spin.c:231 msgid "Hat length:" msgstr "" #: ../src/uiElements/ui_spin.c:239 msgid "Tail length:" msgstr "" #: ../src/uiElements/ui_spin.c:247 msgid "Hat radius:" msgstr "" #: ../src/uiElements/ui_spin.c:255 msgid "Tail radius:" msgstr "" #: ../src/uiElements/ui_spin.c:263 msgid "Use element color on:" msgstr "" #: ../src/uiElements/ui_spin.c:266 msgid " tail" msgstr "" #: ../src/uiElements/ui_spin.c:268 msgid " hat" msgstr "" #: ../src/uiElements/ui_spin.c:280 msgid "A axis: " msgstr "" #: ../src/uiElements/ui_spin.c:288 msgid "B axis: " msgstr "" #: ../src/uiElements/ui_spin.c:294 msgid "Use element color" msgstr "" #. Atomic options. #: ../src/uiElements/ui_spin.c:298 msgid "Atomic rendering options" msgstr "" #: ../src/uiElements/ui_spin.c:305 msgid "Enable the atomic rendering in the method tab." msgstr "" #: ../src/uiElements/ui_box.c:202 msgid "Show box _lengths" msgstr "" #: ../src/uiElements/ui_box.c:208 msgid "x pos." msgstr "" #: ../src/uiElements/ui_box.c:213 msgid "y pos." msgstr "" #: ../src/uiElements/ui_box.c:241 msgid "Bounding box" msgstr "" #: ../src/uiElements/ui_axes.c:140 msgid "Use _box basis-set" msgstr "" #: ../src/uiElements/ui_axes.c:142 msgid "size: " msgstr "" #: ../src/uiElements/ui_axes.c:147 msgid "x pos.: " msgstr "" #: ../src/uiElements/ui_axes.c:150 msgid "y pos.: " msgstr "" #: ../src/uiElements/ui_axes.c:155 msgid "Axis labels: " msgstr "" #: ../src/uiElements/ui_axes.c:177 ../lib/plug-ins/bigdft/bigdft.c:438 msgid "Basis set" msgstr "" #: ../src/uiElements/ui_planetree.c:566 #, c-format msgid "" "norm.: (%3d;%3d;%3d)\n" "distance: %6.2f" msgstr "" #: ../src/uiElements/ui_planetree.c:653 msgid "Drawn" msgstr "" #: ../src/uiElements/ui_planetree.c:669 msgid "Mask" msgstr "" #: ../src/uiElements/ui_planetree.c:679 msgid "Invert" msgstr "" #: ../src/uiElements/ui_planetree.c:685 ../src/panelModules/panelSurfaces.c:682 msgid "Color" msgstr "" #: ../src/uiElements/ui_planetree.c:714 msgid "align" msgstr "" #: ../src/uiElements/ui_planetree.c:717 msgid "Set the camera to look in the direction normal to the selected plane." msgstr "" #: ../src/uiElements/ui_planetree.c:978 msgid "Hiding mode: " msgstr "" #: ../src/uiElements/ui_planetree.c:983 msgid "Hide all elements that are hidden by at least one plane." msgstr "" #: ../src/uiElements/ui_planetree.c:984 msgid "Union" msgstr "" #: ../src/uiElements/ui_planetree.c:987 msgid "Hide elements only if they are hidden by all planes." msgstr "" #: ../src/uiElements/ui_planetree.c:988 msgid "Intersection" msgstr "" #. VisuPlanes parameters #: ../src/uiElements/ui_planetree.c:1065 msgid "Normal: " msgstr "" #: ../src/uiElements/ui_planetree.c:1078 msgid "Distance from origin: " msgstr "" #: ../src/uiElements/ui_planetree.c:1087 #: ../src/panelModules/panelSurfaces.c:687 msgid "Color: " msgstr "" #: ../src/gtk_save.c:255 msgid "" "A description of all resource markups is available on:\n" " " msgstr "" #: ../src/gtk_save.c:275 msgid "Export all resource descriptions to an _XML file" msgstr "" #: ../src/gtk_save.c:284 msgid "Export all parameter descriptions to an _XML file" msgstr "" #: ../src/gtk_save.c:292 msgid "Export all command line _options to an XML file" msgstr "" #: ../src/gtk_save.c:306 msgid "Append all settings in a single XML file (including planes, surfaces…)" msgstr "" #: ../src/gtk_save.c:315 msgid "" "A description of all parameter markups is available on:\n" " " msgstr "" #: ../src/gtk_save.c:381 ../src/gtk_renderingWindowWidget.c:2282 #: ../src/panelModules/panelSurfacesTools.c:322 #: ../src/panelModules/panelSurfacesTools.c:639 #: ../src/panelModules/panelSurfacesTools.c:659 #: ../src/panelModules/panelSurfacesTools.c:682 #: ../src/panelModules/panelSurfacesTools.c:702 #: ../src/panelModules/panelSurfacesTools.c:1069 #: ../src/panelModules/panelSurfacesTools.c:1082 #: ../src/panelModules/panelSurfacesTools.c:1093 #: ../src/panelModules/panelSurfacesTools.c:1110 #: ../src/panelModules/panelSurfacesTools.c:1564 #: ../src/panelModules/panelSurfacesTools.c:1571 #: ../src/panelModules/panelSurfacesTools.c:1834 #: ../src/panelModules/panelSurfacesTools.c:1842 #: ../src/panelModules/panelSurfacesTools.c:1854 #: ../src/panelModules/panelSurfacesTools.c:1867 #: ../src/panelModules/panelSurfacesTools.c:1884 #: ../src/panelModules/panelSurfaces.c:1088 #: ../src/panelModules/panelSurfaces.c:1121 #: ../src/panelModules/panelBrowser.c:1359 #: ../src/panelModules/panelBrowser.c:1380 msgid "Loading a file" msgstr "" #: ../src/gtk_save.c:390 #, c-format msgid "File '%s' succesfully loaded." msgstr "" #: ../src/gtk_save.c:392 #, c-format msgid "File '%s' not or partially loaded." msgstr "" #: ../src/gtk_save.c:411 msgid "Choose a filename with '.xml' to append other settings." msgstr "" #. Autodetect failed, no format match the given filename #: ../src/gtk_save.c:512 ../src/gtk_renderingWindowWidget.c:2495 #: ../src/extraGtkFunctions/gtk_dumpDialogWidget.c:507 #: ../src/extraGtkFunctions/gtk_dumpDialogWidget.c:529 ../src/gtk_main.c:1003 #: ../src/gtk_main.c:1015 ../src/gtk_main.c:1025 ../src/gtk_main.c:1046 #: ../src/gtk_main.c:1067 ../src/panelModules/panelSurfacesTools.c:737 #: ../src/panelModules/panelSurfacesTools.c:750 #: ../src/panelModules/panelSurfacesTools.c:1606 #: ../src/panelModules/panelSurfacesTools.c:1612 #: ../src/panelModules/panelSurfacesTools.c:1618 #: ../src/panelModules/panelSurfacesTools.c:1706 #: ../src/panelModules/panelSurfacesTools.c:1712 #: ../src/panelModules/panelSurfacesTools.c:1718 #: ../src/panelModules/panelSurfacesTools.c:1744 msgid "Saving a file" msgstr "" #: ../src/gtk_save.c:520 #, c-format msgid "File '%s' succesfully written (%d lines)." msgstr "" #: ../src/gtk_save.c:523 #, c-format msgid "File '%s' not written." msgstr "" #: ../src/visu_basic.c:355 #, c-format msgid "The format can't be found from the filename '%s' entered.\n" msgstr "" #: ../src/visu_basic.c:357 #, c-format msgid "" "Use -o fileFormatId=id to specify a file format when the autodetection " "fails. Get a list of ids with option -o list:\n" "\n" msgstr "" #: ../src/visu_basic.c:377 msgid "a file to render is mandatory with the '--export' option." msgstr "" #: ../src/visu_basic.c:489 #, c-format msgid "" "\n" "#%2d - exportation file format '%s':\n" msgstr "" #: ../src/visu_basic.c:499 ../src/visu_basic.c:531 msgid "integer" msgstr "" #: ../src/visu_basic.c:502 ../src/visu_basic.c:534 msgid "boolean" msgstr "" #: ../src/visu_basic.c:505 ../src/visu_basic.c:537 msgid "string" msgstr "" #: ../src/visu_basic.c:515 ../src/visu_basic.c:547 #, c-format msgid "No option for this file format.\n" msgstr "" #: ../src/visu_basic.c:521 #, c-format msgid "" "\n" "#%2d - input file format '%s':\n" msgstr "" #: ../src/visu_glnodescene.c:2547 msgid "" "option '--build-map' has been given but no plane is available (use '--" "planes')." msgstr "" #: ../src/visu_glnodescene.c:2550 msgid "" "option '--build-map' has been given but no scalar field is available (use '--" "scalar-field')." msgstr "" #: ../src/visu_glnodescene.c:2553 msgid "" "option '--build-map' has been given but no shade is available (use '--color-" "preset')." msgstr "" #. * #. * SECTION: gtk_pick #. * @short_description: The pick and measurement tab in the interactive #. * dialog. #. * #. * This action tab provides widgets to display information about #. * selected atoms, like distances or angles. In addition, measured #. * distances and angles are kept in a list when new files are #. * loaded. #. * With the list of selected nodes, one can modify properties #. * associated to nodes like their coordinates, the value of #. * colourisation if any, the forces on them, if any... One can also #. * decide to display information directly on nodes. #. #: ../src/gtk_pick.c:80 msgid "" "left-button\t\t\t: standard pick\n" "control-left-button\t\t: toggle highlihgt node\n" "middle-button\t\t: measure node neighbouring\n" "shift-middle-button\t: pick 1st reference\n" "ctrl-middle-button\t\t: pick 2nd reference\n" "drag-left-button\t\t: make a rectangular selection\n" "right-button\t\t\t: switch to observe" msgstr "" #: ../src/gtk_pick.c:169 #, c-format msgid "Highlights (%d):" msgstr "" #: ../src/gtk_pick.c:171 ../src/interface.c:787 msgid "Highlights (none):" msgstr "" #: ../src/gtk_pick.c:181 #, c-format msgid "List of %d node(s):" msgstr "" #: ../src/gtk_pick.c:183 msgid "List of nodes (none):" msgstr "" #: ../src/gtk_pick.c:292 msgid "" "Values in blue are " "editable" msgstr "" #: ../src/gtk_pick.c:332 msgid "Set / unset highlight status following selection." msgstr "" #: ../src/gtk_pick.c:340 msgid "Empty the selection list." msgstr "" #: ../src/gtk_pick.c:346 msgid "Draw data on nodes" msgstr "" #: ../src/gtk_pick.c:354 ../src/extraFunctions/nodeProp.c:439 #: ../src/extraFunctions/nodeProp.c:525 ../lib/plug-ins/bigdft/bigdft.c:675 msgid "none" msgstr "" #: ../src/gtk_pick.c:362 msgid "listed" msgstr "" #: ../src/gtk_pick.c:376 msgid "all" msgstr "" #: ../src/gtk_pick.c:412 msgid "Import picked nodes from an existing XML file." msgstr "" #: ../src/gtk_pick.c:413 msgid "Export listed picked nodes to the current XML file." msgstr "" #: ../src/gtk_pick.c:414 msgid "Export listed picked nodes to a new XML file." msgstr "" #: ../src/gtk_pick.c:456 msgid "Hide nodes depending on highlight status." msgstr "" #: ../src/gtk_pick.c:465 msgid "_h." msgstr "" #: ../src/gtk_pick.c:469 msgid "Hide button will hide highlighted nodes." msgstr "" #: ../src/gtk_pick.c:474 msgid "_non-h." msgstr "" #: ../src/gtk_pick.c:478 msgid "Hide button will hide non-highlighted nodes." msgstr "" #: ../src/gtk_pick.c:560 #, c-format msgid "" "Reference node\t #%d\n" " ( x = %7.3f ; y = %7.3f ; " "z = %7.3f)\n" "" msgstr "" #: ../src/gtk_pick.c:576 #, c-format msgid "" "2nd Reference node\t #%d\t (i.e. " "dr = %7.3f)\n" " ( x = %7.3f ; y = %7.3f ; " "z = %7.3f)\n" " (δx = %7.3f ; δy = %7.3f ; δz = %7.3f)\n" "" msgstr "" #: ../src/gtk_pick.c:588 #, c-format msgid "" "Newly picked node\t #%d\n" " ( x = %7.3f ; y = %7.3f ; " "z = %7.3f)\n" "" msgstr "" #: ../src/gtk_pick.c:604 #, c-format msgid "" "Newly picked node\t #%d\t (i.e. " "dr = %7.3f)\n" " ( x = %7.3f ; y = %7.3f ; " "z = %7.3f)\n" " (δx = %7.3f ; δy = %7.3f ; δz = %7.3f)\n" "" msgstr "" #: ../src/gtk_pick.c:627 #, c-format msgid "" "Newly picked node\t #%d\t (i.e. " "dr = %7.3f)\n" " ( x = %7.3f ; y = %7.3f ; " "z = %7.3f)\n" " (δx1 = %7.3f ; δy1 = %7.3f ; δz1 = %7.3f)\n" " (δx2 = %7.3f ; δy2 = %7.3f ; δz2 = %7.3f)\n" msgstr "" #: ../src/gtk_pick.c:640 #, c-format msgid " angle (Ref-Ref2, Ref-New) = %5.2f degrees" msgstr "" #: ../src/gtk_pick.c:644 #, c-format msgid "Unset reference %d." msgstr "" #: ../src/gtk_pick.c:683 ../src/gtk_renderingWindowWidget.c:1463 msgid "No node has been selected." msgstr "" #: ../src/gtk_pick.c:686 msgid "Picked reference and second reference are the same." msgstr "" #: ../src/gtk_pick.c:690 msgid "Can't pick a second reference without any existing first one." msgstr "" #: ../src/gtk_pick.c:694 ../src/gtk_renderingWindowWidget.c:1475 msgid "Can't remove first reference before removing the second one." msgstr "" #: ../src/gtk_pick.c:743 ../src/gtk_pick.c:789 #: ../src/extraGtkFunctions/gtk_dataChooser.c:527 #: ../src/extraGtkFunctions/gtk_dataChooser.c:533 #: ../src/extraGtkFunctions/gtk_dataChooser.c:572 #: ../src/extraGtkFunctions/gtk_dataChooser.c:582 #: ../src/extraGtkFunctions/gtk_elementComboBox.c:493 #: ../src/panelModules/panelSurfaces.c:2296 msgid "None" msgstr "" #: ../src/gtk_pick.c:801 msgid "Reading values" msgstr "" #: ../src/gtk_pick.c:802 msgid "" "Wrong format. Impossible to parse the data associated to the selected node." msgstr "" #: ../src/gtk_renderingWindowWidget.c:161 msgid "No description is available" msgstr "" #: ../src/gtk_renderingWindowWidget.c:162 msgid "Nothing is loaded" msgstr "" #: ../src/gtk_renderingWindowWidget.c:370 msgid "" "Rotate with left b., pick with right b., setup ref. with or " " b." msgstr "" #: ../src/gtk_renderingWindowWidget.c:706 msgid "No file loaded" msgstr "" #: ../src/gtk_renderingWindowWidget.c:708 msgid "No filename" msgstr "" #: ../src/gtk_renderingWindowWidget.c:985 ../src/support.h:60 msgid "_Close" msgstr "" #: ../src/gtk_renderingWindowWidget.c:996 msgid "Toggle highlight for node: " msgstr "" #: ../src/gtk_renderingWindowWidget.c:1048 msgid "" "Click here to get the list of saved camera positions.\n" "Use 's' and 'r' keys to save and restore camera settings. + 's' " "remove the current camera from the list." msgstr "" #: ../src/gtk_renderingWindowWidget.c:1077 msgid "Open Ctrl+o" msgstr "" #: ../src/gtk_renderingWindowWidget.c:1091 msgid "Reload the current file Ctrl+r" msgstr "" #: ../src/gtk_renderingWindowWidget.c:1107 msgid "Export Ctrl+s" msgstr "" #: ../src/gtk_renderingWindowWidget.c:1121 msgid "" "Raise the command panel window.\n" " Use as key binding." msgstr "" #: ../src/gtk_renderingWindowWidget.c:1154 ../src/support.h:57 #: ../src/interface.c:1650 msgid "_Cancel" msgstr "" #: ../src/gtk_renderingWindowWidget.c:1179 msgid "Measure / remove information for the selected node." msgstr "" #: ../src/gtk_renderingWindowWidget.c:1194 msgid "Remove all measurement marks." msgstr "" #: ../src/gtk_renderingWindowWidget.c:1202 msgid "Use the 'open' button to render a file." msgstr "" #: ../src/gtk_renderingWindowWidget.c:1359 msgid "Drag and drop" msgstr "" #: ../src/gtk_renderingWindowWidget.c:1359 msgid "Too many dropped files." msgstr "" #: ../src/gtk_renderingWindowWidget.c:1383 msgid "Selected node number " msgstr "" #: ../src/gtk_renderingWindowWidget.c:1425 msgid "Distance between nodes " msgstr "" #: ../src/gtk_renderingWindowWidget.c:1430 #, c-format msgid "%d and %d : %7.3f" msgstr "" #: ../src/gtk_renderingWindowWidget.c:1437 msgid " right-click on background to unset reference." msgstr "" #: ../src/gtk_renderingWindowWidget.c:1443 msgid " right-click on background to unset second reference." msgstr "" #: ../src/gtk_renderingWindowWidget.c:1466 msgid "Picked node is already used as a reference." msgstr "" #: ../src/gtk_renderingWindowWidget.c:1470 msgid "" "Can't pick a second reference without any first one (use right-" "click)." msgstr "" #: ../src/gtk_renderingWindowWidget.c:1743 msgid "Restore saved camera position." msgstr "" #: ../src/gtk_renderingWindowWidget.c:1746 #: ../src/gtk_renderingWindowWidget.c:2036 msgid "No saved camera. Use 's' to save one." msgstr "" #: ../src/gtk_renderingWindowWidget.c:1751 msgid "Save current camera position." msgstr "" #: ../src/gtk_renderingWindowWidget.c:1754 msgid "Pop current camera position." msgstr "" #: ../src/gtk_renderingWindowWidget.c:1758 msgid "Align camera with X box axis." msgstr "" #: ../src/gtk_renderingWindowWidget.c:1762 msgid "Align camera with Y box axis." msgstr "" #: ../src/gtk_renderingWindowWidget.c:1766 msgid "Align camera with Z box axis." msgstr "" #: ../src/gtk_renderingWindowWidget.c:1943 msgid "Size:" msgstr "" #. Set a title. #: ../src/gtk_renderingWindowWidget.c:2005 msgid "Camera menu (saved in 'v_sim.par'):" msgstr "" #: ../src/gtk_renderingWindowWidget.c:2012 #, c-format msgid "" "save current camera:\n" "(θ %6.1f° ; φ %6.1f° ; ω %6.1f°) dx %4.1f dy %4.1f" msgstr "" #. Put an option to open the view selector. #: ../src/gtk_renderingWindowWidget.c:2025 msgid "select precisely a camera view" msgstr "" #: ../src/gtk_renderingWindowWidget.c:2041 msgid "List of saved cameras:" msgstr "" #: ../src/gtk_renderingWindowWidget.c:2050 #, c-format msgid "(θ %6.1f° ; φ %6.1f° ; ω %6.1f°) dx %4.1f dy %4.1f" msgstr "" #: ../src/gtk_renderingWindowWidget.c:2217 msgid "Loading file..." msgstr "" #: ../src/gtk_renderingWindowWidget.c:2229 msgid "Cancellation request, waiting for reply..." msgstr "" #: ../src/gtk_renderingWindowWidget.c:2385 msgid "Reloading file" msgstr "" #: ../src/gtk_renderingWindowWidget.c:2412 msgid "Nb nodes:" msgstr "" #: ../src/gtk_renderingWindowWidget.c:2437 msgid "Saving image..." msgstr "" #: ../src/gtk_renderingWindowWidget.c:2480 #: ../src/panelModules/panelBrowser.c:987 msgid "Waiting for generating image in memory..." msgstr "" #: ../src/visu_gtk.c:123 msgid "V_Sim error message" msgstr "" #: ../src/visu_gtk.c:165 msgid "Output errors:" msgstr "" #: ../src/visu_gtk.c:305 msgid "Loading plug-ins" msgstr "" #: ../src/visu_gtk.c:312 msgid "Reading the configuration files" msgstr "" #: ../src/visu_gtk.c:339 msgid "Parsing command line" msgstr "" #: ../src/visu_gtk.c:368 ../src/extraGtkFunctions/gtk_dataChooser.c:447 msgid "All supported formats" msgstr "" #: ../src/visu_gtk.c:376 ../src/extraGtkFunctions/gtk_dataChooser.c:455 msgid "No description" msgstr "" #: ../src/visu_gtk.c:393 ../src/extraGtkFunctions/gtk_dataChooser.c:467 #: ../src/extraGtkFunctions/gtk_valueIOWidget.c:277 #: ../src/extraGtkFunctions/gtk_valueIOWidget.c:527 #: ../src/panelModules/panelDataFile.c:742 msgid "All files" msgstr "" #: ../src/visu_gtk.c:435 #, c-format msgid "failed to load pixbuf file '%s': %s\n" msgstr "" #: ../src/extraGtkFunctions/gtk_dataChooser.c:176 msgid "Load session" msgstr "" #: ../src/extraGtkFunctions/gtk_dataChooser.c:194 msgid "Rendering method:" msgstr "" #: ../src/extraGtkFunctions/gtk_dataChooser.c:199 msgid "display node as atoms" msgstr "" #: ../src/extraGtkFunctions/gtk_dataChooser.c:201 msgid "display node as spins" msgstr "" #: ../src/extraGtkFunctions/gtk_dataChooser.c:211 msgid "_Preview:" msgstr "" #: ../src/extraGtkFunctions/gtk_dataChooser.c:262 msgid "Box composition:" msgstr "" #: ../src/extraGtkFunctions/gtk_dataChooser.c:271 #, c-format msgid "%s:" msgstr "" #: ../src/extraGtkFunctions/gtk_dataChooser.c:281 #, c-format msgid "%d nodes" msgstr "" #: ../src/extraGtkFunctions/gtk_dataChooser.c:284 msgid "1 node" msgstr "" #: ../src/extraGtkFunctions/gtk_dataChooser.c:295 msgid "Description:" msgstr "" #: ../src/extraGtkFunctions/gtk_dataChooser.c:363 msgid "Not a V_Sim file" msgstr "" #: ../src/extraGtkFunctions/gtk_dataChooser.c:375 msgid "This file has errors" msgstr "" #. Position button. #: ../src/extraGtkFunctions/gtk_dataChooser.c:515 msgid "Positions:" msgstr "" #: ../src/extraGtkFunctions/gtk_dataChooser.c:522 msgid "Spins:" msgstr "" #: ../src/extraGtkFunctions/gtk_elementComboBox.c:495 msgid "All elements" msgstr "" #: ../src/extraGtkFunctions/gtk_toolPanelWidget.c:198 ../src/gtk_main.c:326 msgid "Command panel" msgstr "" #: ../src/extraGtkFunctions/gtk_toolPanelWidget.c:512 msgid "Manage this subpanel: attach/detach or hide it." msgstr "" #: ../src/extraGtkFunctions/gtk_toolPanelWidget.c:791 #, c-format msgid "Send to '%s'" msgstr "" #. Create a new dock window. #: ../src/extraGtkFunctions/gtk_toolPanelWidget.c:807 msgid "New dock" msgstr "" #. Remove the current tool panel. #: ../src/extraGtkFunctions/gtk_toolPanelWidget.c:812 #, c-format msgid "Hide tool '%s'" msgstr "" #: ../src/extraGtkFunctions/gtk_toolPanelWidget.c:845 #, c-format msgid "Dock window (%d)" msgstr "" #: ../src/extraGtkFunctions/gtk_toolPanelWidget.c:1131 #: ../src/extraGtkFunctions/gtk_toolPanelWidget.c:1159 #, c-format msgid "Show '%s'" msgstr "" #: ../src/extraGtkFunctions/gtk_toolPanelWidget.c:1143 msgid "No hidden tool" msgstr "" #: ../src/extraGtkFunctions/gtk_toolPanelWidget.c:1170 msgid "No hidden dock" msgstr "" #. Hide action #: ../src/extraGtkFunctions/gtk_toolPanelWidget.c:1180 msgid "Hide dock" msgstr "" #: ../src/extraGtkFunctions/gtk_toolPanelWidget.c:1541 msgid "" "Raise the rendering window.\n" " Use as key binding." msgstr "" #. The Label to introduce the combo list. #: ../src/extraGtkFunctions/gtk_toolPanelWidget.c:1545 msgid "Tool: " msgstr "" #: ../src/extraGtkFunctions/gtk_toolPanelWidget.c:1579 msgid "Manage hidden subpanels and dock windows." msgstr "" #: ../src/extraGtkFunctions/gtk_toolPanelWidget.c:1585 msgid "" "Positions, sizes, names, contains... of dock windows are stored in the " "parameters file, see the 'Config. files' button on the command panel." msgstr "" #. Labels for the ranges part. #: ../src/extraGtkFunctions/gtk_colorComboBoxWidget.c:129 #: ../src/extraGtkFunctions/gtk_lineObjectWidget.c:426 #: ../src/panelModules/panelFogBgColor.c:144 msgid "R:" msgstr "" #: ../src/extraGtkFunctions/gtk_colorComboBoxWidget.c:130 #: ../src/extraGtkFunctions/gtk_lineObjectWidget.c:427 #: ../src/panelModules/panelFogBgColor.c:145 msgid "G:" msgstr "" #: ../src/extraGtkFunctions/gtk_colorComboBoxWidget.c:131 #: ../src/extraGtkFunctions/gtk_lineObjectWidget.c:428 #: ../src/panelModules/panelFogBgColor.c:146 msgid "B:" msgstr "" #: ../src/extraGtkFunctions/gtk_colorComboBoxWidget.c:132 msgid "Alph:" msgstr "" #: ../src/extraGtkFunctions/gtk_colorComboBoxWidget.c:133 msgid "amb:" msgstr "" #: ../src/extraGtkFunctions/gtk_colorComboBoxWidget.c:134 msgid "dif:" msgstr "" #: ../src/extraGtkFunctions/gtk_colorComboBoxWidget.c:135 msgid "shi:" msgstr "" #: ../src/extraGtkFunctions/gtk_colorComboBoxWidget.c:136 msgid "spe:" msgstr "" #: ../src/extraGtkFunctions/gtk_colorComboBoxWidget.c:137 msgid "emi:" msgstr "" #: ../src/extraGtkFunctions/gtk_colorComboBoxWidget.c:292 #: ../src/extraGtkFunctions/gtk_colorComboBoxWidget.c:293 msgid "New / modify" msgstr "" #: ../src/extraGtkFunctions/gtk_colorComboBoxWidget.c:513 #: ../src/panelModules/panelDataFile.c:474 msgid "More options" msgstr "" #. Create the selection. #: ../src/extraGtkFunctions/gtk_colorComboBoxWidget.c:776 msgid "Select a color" msgstr "" #: ../src/extraGtkFunctions/gtk_dumpDialogWidget.c:224 msgid "Export to a file (image, atomic structures...)" msgstr "" #. Label to introduce the combobox which allow to choose the format #: ../src/extraGtkFunctions/gtk_dumpDialogWidget.c:273 msgid "Choose the file format : " msgstr "" #: ../src/extraGtkFunctions/gtk_dumpDialogWidget.c:279 msgid "Autodetect format" msgstr "" #. Add an expander for file format options. #: ../src/extraGtkFunctions/gtk_dumpDialogWidget.c:282 msgid "File format option:" msgstr "" #: ../src/extraGtkFunctions/gtk_dumpDialogWidget.c:295 msgid "Add extension" msgstr "" #: ../src/extraGtkFunctions/gtk_dumpDialogWidget.c:301 msgid "Width: " msgstr "" #: ../src/extraGtkFunctions/gtk_dumpDialogWidget.c:316 msgid "Height: " msgstr "" #. Label to introduce the progress bar #: ../src/extraGtkFunctions/gtk_dumpDialogWidget.c:340 msgid "Dump progress : " msgstr "" #: ../src/extraGtkFunctions/gtk_dumpDialogWidget.c:352 msgid "" "Current box has translations applied, do you want to proceed to exportation " "anyway?" msgstr "" #: ../src/extraGtkFunctions/gtk_dumpDialogWidget.c:508 #: ../src/extraGtkFunctions/gtk_fieldChooser.c:267 msgid "No filename chosen." msgstr "" #: ../src/extraGtkFunctions/gtk_dumpDialogWidget.c:530 msgid "The filename doesn't match any known format." msgstr "" #: ../src/extraGtkFunctions/gtk_lineObjectWidget.c:374 msgid "expand for options" msgstr "" #. The label. #: ../src/extraGtkFunctions/gtk_lineObjectWidget.c:391 msgid "Line style:" msgstr "" #. The scale width spin button. #: ../src/extraGtkFunctions/gtk_lineObjectWidget.c:396 msgid "width:" msgstr "" #: ../src/extraGtkFunctions/gtk_lineObjectWidget.c:447 msgid "color:" msgstr "" #: ../src/extraGtkFunctions/gtk_lineObjectWidget.c:461 msgid "(preset)" msgstr "" #: ../src/extraGtkFunctions/gtk_curveWidget.c:109 #: ../lib/plug-ins/python-gi/pythongi.c:260 msgid "All" msgstr "" #: ../src/extraGtkFunctions/gtk_fieldChooser.c:183 msgid "Isosurfaces files" msgstr "" #: ../src/extraGtkFunctions/gtk_fieldChooser.c:192 msgid "Open a surface/density file" msgstr "" #: ../src/extraGtkFunctions/gtk_fieldChooser.c:208 msgid "Keep surface box as defined" msgstr "" #: ../src/extraGtkFunctions/gtk_fieldChooser.c:210 msgid "Don't modify the surface coordinates." msgstr "" #: ../src/extraGtkFunctions/gtk_fieldChooser.c:212 msgid "Fit surfaces to box" msgstr "" #: ../src/extraGtkFunctions/gtk_fieldChooser.c:214 msgid "Makes surfaces fit to the current loaded bounding box." msgstr "" #: ../src/extraGtkFunctions/gtk_fieldChooser.c:217 msgid "Fit box to surfaces" msgstr "" #: ../src/extraGtkFunctions/gtk_fieldChooser.c:219 msgid "Makes the current bounding box fit to the surfaces." msgstr "" #. Autodetect failed, no format match the given filename #: ../src/extraGtkFunctions/gtk_fieldChooser.c:266 msgid "Opening a file" msgstr "" #: ../src/extraGtkFunctions/gtk_orientationChooser.c:288 msgid "Update values on the fly." msgstr "" #: ../src/extraGtkFunctions/gtk_orientationChooser.c:348 msgid "Choose an orientation" msgstr "" #: ../src/extraGtkFunctions/gtk_orientationChooser.c:365 msgid "On an orthonormal basis set" msgstr "" #: ../src/extraGtkFunctions/gtk_orientationChooser.c:390 msgid "Following the box basis set" msgstr "" #: ../src/extraGtkFunctions/gtk_orientationChooser.c:414 msgid "On a spherical basis set" msgstr "" #: ../src/extraGtkFunctions/gtk_valueIOWidget.c:274 msgid "V_Sim value file (*.xml)" msgstr "" #: ../src/extraGtkFunctions/gtk_valueIOWidget.c:280 #: ../src/extraGtkFunctions/gtk_valueIOWidget.c:286 msgid "Open a V_Sim value file" msgstr "" #. The label. #: ../src/extraGtkFunctions/gtk_valueIOWidget.c:308 msgid "I/O:" msgstr "" #: ../src/extraGtkFunctions/gtk_valueIOWidget.c:436 msgid "Import V_Sim values from a file." msgstr "" #: ../src/extraGtkFunctions/gtk_valueIOWidget.c:509 #: ../src/extraGtkFunctions/gtk_valueIOWidget.c:561 #: ../src/extraGtkFunctions/gtk_valueIOWidget.c:667 msgid "Export V_Sim values to a file." msgstr "" #: ../src/extraGtkFunctions/gtk_valueIOWidget.c:523 msgid "V_Sim value files (*.xml)" msgstr "" #: ../src/extraGtkFunctions/gtk_valueIOWidget.c:533 msgid "values.xml" msgstr "" #: ../src/renderingMethods/elementAtomic.c:255 msgid "Sphere" msgstr "" #: ../src/renderingMethods/elementAtomic.c:256 msgid "Cube" msgstr "" #: ../src/renderingMethods/elementAtomic.c:257 #: ../src/renderingMethods/elementSpin.c:779 msgid "Elipsoid" msgstr "" #: ../src/renderingMethods/elementAtomic.c:258 msgid "Point" msgstr "" #: ../src/renderingMethods/elementAtomic.c:259 #: ../src/renderingMethods/elementSpin.c:780 msgid "Torus" msgstr "" #: ../src/renderingMethods/spinMethod.c:131 msgid "Theta angle" msgstr "" #: ../src/renderingMethods/spinMethod.c:132 msgid "The theta angle to orientate the colourisation cone." msgstr "" #: ../src/renderingMethods/spinMethod.c:142 msgid "Phi angle" msgstr "" #: ../src/renderingMethods/spinMethod.c:143 msgid "The phi angle to orientate the colourisation cone." msgstr "" #: ../src/renderingMethods/spinMethod.c:153 msgid "Omega angle" msgstr "" #: ../src/renderingMethods/spinMethod.c:154 msgid "The omega angle to orientate the colourisation cone." msgstr "" #: ../src/renderingMethods/spinMethod.c:164 msgid "Hiding policy for null modulus" msgstr "" #: ../src/renderingMethods/spinMethod.c:165 msgid "The hiding policy for spin with a null modulus." msgstr "" #: ../src/renderingMethods/spinMethod.c:176 msgid "Scaling of spin depending on modulus value" msgstr "" #: ../src/renderingMethods/spinMethod.c:177 msgid "The scaling policy based on modulus value." msgstr "" #: ../src/renderingMethods/spinMethod.c:188 msgid "Use atomic rendering" msgstr "" #: ../src/renderingMethods/spinMethod.c:189 msgid "If atomic rendering is used in addition to spin rendering." msgstr "" #: ../src/renderingMethods/spinMethod.c:531 #, c-format msgid "Unknown flag '%s', value ignored." msgstr "" #: ../src/renderingMethods/elementSpin.c:777 msgid "Rounded arrow" msgstr "" #: ../src/renderingMethods/elementSpin.c:778 msgid "Edged arrow" msgstr "" #: ../src/visu_dataatomic.c:261 msgid "Position files" msgstr "" #: ../src/visu_dataatomic.c:375 ../src/visu_dataspin.c:372 #, c-format msgid "Impossible to load '%s', unrecognised format.\n" msgstr "" #: ../src/visu_dataatomic.c:428 ../src/visu_dataatomic.c:432 msgid "Forces" msgstr "" #: ../src/visu_configFile.c:1031 #, c-format msgid "%d boolean value(s) should appear here" msgstr "" #: ../src/visu_configFile.c:1040 #, c-format msgid "%d boolean value(s) should appear here but %d has been found" msgstr "" #: ../src/visu_configFile.c:1082 #, c-format msgid "%d integer value(s) should appear here" msgstr "" #: ../src/visu_configFile.c:1091 #, c-format msgid "%d integer value(s) should appear here but %d has been found" msgstr "" #: ../src/visu_configFile.c:1100 #, c-format msgid "wrong range (%d <= v <= %d) for the %s markup" msgstr "" #: ../src/visu_configFile.c:1175 #, c-format msgid "%d floating point values should appear here" msgstr "" #: ../src/visu_configFile.c:1184 #, c-format msgid "%d floating point value(s) should appear here but %d has been found" msgstr "" #: ../src/visu_configFile.c:1193 #, c-format msgid "wrong range (%g <= v <= %g) for the %s markup" msgstr "" #: ../src/visu_configFile.c:1226 #, c-format msgid "missing string for %s markup" msgstr "" #: ../src/visu_configFile.c:1232 #, c-format msgid "'%s' is not a valid value for %s markup" msgstr "" #: ../src/visu_configFile.c:1307 #, c-format msgid "Parse error at line %d, the tag '%s' is not closed.\n" msgstr "" #: ../src/visu_configFile.c:1325 #, c-format msgid "Parse error at line %d, '%s' is an unknown markup.\n" msgstr "" #: ../src/visu_configFile.c:1329 #, c-format msgid "Markup '%s' is obsolete, replaced by '%s'." msgstr "" #: ../src/visu_configFile.c:1339 #, c-format msgid " read line (%s) : '%s'\n" msgstr "" #: ../src/visu_configFile.c:1341 #, c-format msgid " read line : '%s'\n" msgstr "" #: ../src/visu_configFile.c:1365 #, c-format msgid "Parse error at line %d, %s.\n" msgstr "" #: ../src/visu_configFile.c:1461 #, c-format msgid "Parse error at line %d, '%s' needs %d lines but only %d were read.\n" msgstr "" #: ../src/visu_configFile.c:1488 #, c-format msgid "" "Parse error at line %d, cannot find parenthesis containing the description " "of a shade.\n" msgstr "" #: ../src/visu_configFile.c:2347 #, c-format msgid "Parse error at line %d: '%s' is not a valid value for %s markup.\n" msgstr "" #: ../src/visu_configFile.c:2367 #, c-format msgid "" "Parse error at line %d: 1 string value must appear after the %s markup.\n" msgstr "" #: ../src/visu_configFile.c:2396 #, c-format msgid "" "Parse error at line %d: %d integer values(%d <= v <= %d) must appear after " "the %s markup.\n" msgstr "" #: ../src/visu_configFile.c:2427 #, c-format msgid "" "Parse error at line %d: %d floating points (%g <= v <= %g) must appear after " "the %s markup. Read line was '%s'.\n" msgstr "" #: ../src/extensions/mapset.c:548 msgid "Drawing extension for mapSet." msgstr "" #: ../src/extensions/box_legend.c:202 msgid "Draw informations related to the box." msgstr "" #: ../src/extensions/box_legend.c:215 msgid "Box lengths" msgstr "" #: ../src/extensions/fogAndBGColor.c:323 msgid "Set an image as background." msgstr "" #: ../src/extensions/box.c:456 msgid "Draw a box representing the limit of the area." msgstr "" #: ../src/extensions/box.c:982 #, c-format msgid "x: %7.3f" msgstr "" #: ../src/extensions/box.c:992 #, c-format msgid "y: %7.3f" msgstr "" #: ../src/extensions/box.c:1001 #, c-format msgid "z: %7.3f" msgstr "" #. Long description #: ../src/extensions/surfs.c:570 ../src/panelModules/panelSurfaces.c:2603 msgid "Drawing iso-surfaces" msgstr "" #: ../src/extensions/maps.c:306 msgid "Drawing extension for maps." msgstr "" #: ../src/extensions/infos.c:299 msgid "Draw informations on nodes." msgstr "" #: ../src/extensions/geodiff.c:172 msgid "Draw geodiff with vectors." msgstr "" #: ../src/extensions/legend.c:193 msgid "Draw the name and the shape of available elements on screen." msgstr "" #: ../src/extensions/pairs.c:136 msgid "Bonds" msgstr "" #: ../src/extensions/pairs.c:439 msgid "Draw pairs between elements with a criterion of distance." msgstr "" #: ../src/extensions/pairs.c:732 #, c-format msgid "the method '%s' is unknown" msgstr "" #: ../src/extensions/shade.c:259 msgid "Draw the legend of a color shade." msgstr "" #: ../src/extensions/planes.c:198 msgid "Draw some planes." msgstr "" #: ../src/extensions/node_vectors.c:324 msgid "Draw vectors on each nodes." msgstr "" #: ../src/extensions/axes.c:738 msgid "Draw {x,y,z} axes." msgstr "" #: ../src/extensions/axes.c:1460 msgid "front" msgstr "" #: ../src/extensions/axes.c:1474 msgid "back" msgstr "" #: ../src/extensions/forces.c:139 msgid "Draw forces with vectors." msgstr "" #: ../src/extensions/paths.c:176 msgid "Representation of paths." msgstr "" #: ../src/extensions/nodes.c:322 msgid "Draw all the nodes." msgstr "" #: ../src/extensions/scale.c:96 #, c-format msgid "Length: %6.2f" msgstr "" #: ../src/extensions/scale.c:608 msgid "Draw scales in the rendering area." msgstr "" #: ../src/extensions/marks.c:462 msgid "Draw some marks on element in video inverse." msgstr "" #: ../src/extensions/marks.c:2175 ../src/extraFunctions/pot2surf.c:1781 #: ../src/extraFunctions/geometry.c:683 #, c-format msgid "DTD error: element '%s' should appear only once." msgstr "" #: ../src/extensions/marks.c:2195 ../src/extensions/marks.c:2206 #: ../src/extensions/marks.c:2232 ../src/extensions/marks.c:2266 #: ../src/extensions/marks.c:2277 ../src/extensions/marks.c:2306 #: ../src/extensions/marks.c:2317 ../src/extensions/marks.c:2328 #: ../src/extraFunctions/geometry.c:698 ../src/extraFunctions/geometry.c:732 #: ../src/extraFunctions/geometry.c:793 #, c-format msgid "DTD error: attribute '%s' has an unknown value '%s'." msgstr "" #: ../src/extensions/marks.c:2218 ../src/extensions/marks.c:2252 #: ../src/extensions/marks.c:2292 ../src/extraFunctions/pot2surf.c:1851 #: ../src/extraFunctions/pot2surf.c:1889 ../src/extraFunctions/planeset.c:977 #: ../src/extraFunctions/planeset.c:1020 ../src/extraFunctions/geometry.c:713 #: ../src/extraFunctions/geometry.c:763 #, c-format msgid "DTD error: parent element '%s' of element '%s' is missing." msgstr "" #: ../src/extensions/marks.c:2344 ../src/extraFunctions/pot2surf.c:1932 #: ../src/extraFunctions/planeset.c:1046 ../src/extraFunctions/geometry.c:818 #, c-format msgid "Unexpected element '%s'." msgstr "" #: ../src/extensions/marks.c:2429 #, c-format msgid "No picked node found." msgstr "" #: ../src/extensions/marks.c:2625 msgid "Marks - classical" msgstr "" #: ../src/extensions/marks.c:2626 msgid "Draw some marks on element." msgstr "" #: ../src/extensions/vibrations.c:96 msgid "Draw vibrations with vectors." msgstr "" #: ../src/dumpModules/dumpToSVG.c:157 msgid "Scalar Vector Graphic (SVG) file" msgstr "" #: ../src/dumpModules/dumpToSVG.c:165 ../src/dumpModules/dumpToSVG.c:182 msgid "Use flat colours for scheme rendering" msgstr "" #: ../src/dumpModules/dumpToSVG.c:174 msgid "Portable Document Format (PDF) file" msgstr "" #: ../src/dumpModules/dumpToXyz.c:71 msgid "Xyz file (current positions)" msgstr "" #: ../src/dumpModules/dumpToXyz.c:79 msgid "Expand the bounding box" msgstr "" #: ../src/dumpModules/dumpToXyz.c:81 ../src/dumpModules/dumpToYaml.c:86 #: ../src/dumpModules/dumpToAscii.c:90 msgid "Export nodes sorted by elements" msgstr "" #: ../src/dumpModules/dumpToYaml.c:70 msgid "YAML file (current positions)" msgstr "" #: ../src/dumpModules/dumpToYaml.c:78 ../src/dumpModules/dumpToAscii.c:80 msgid "Don't output hidden nodes" msgstr "" #: ../src/dumpModules/dumpToYaml.c:80 ../src/dumpModules/dumpToAscii.c:82 msgid "Comment hidden nodes (if output)" msgstr "" #: ../src/dumpModules/dumpToYaml.c:82 ../src/dumpModules/dumpToAscii.c:84 msgid "Keep primitive box (in case of node expansion)" msgstr "" #: ../src/dumpModules/dumpToYaml.c:84 ../src/dumpModules/dumpToAscii.c:86 #: ../src/dumpModules/dumpToABINIT.c:79 msgid "Export positions in reduced coordinates" msgstr "" #: ../src/dumpModules/dumpToAscii.c:72 msgid "ASCII file (current positions)" msgstr "" #: ../src/dumpModules/dumpToAscii.c:88 ../src/dumpModules/dumpToABINIT.c:81 msgid "Export box as lengths and angles" msgstr "" #: ../src/dumpModules/dumpToTiff.c:76 msgid "Tiff file" msgstr "" #: ../src/dumpModules/dumpToTiff.c:682 ../src/dumpModules/dumpToPsAndPdf.c:346 #: ../src/dumpModules/dumpToPsAndPdf.c:481 #: ../src/dumpModules/dumpThroughGdkPixbuf.c:138 #: ../src/dumpModules/dumpToGif.c:842 #, c-format msgid "Can't dump OpenGL area to data.\n" msgstr "" #: ../src/dumpModules/dumpToTiff.c:698 ../src/dumpModules/dumpToPsAndPdf.c:386 #: ../src/dumpModules/dumpToPsAndPdf.c:496 #: ../src/dumpModules/dumpToPsAndPdf.c:655 ../src/dumpModules/dumpToGif.c:856 #, c-format msgid "Cannot open file (to write in)." msgstr "" #: ../src/dumpModules/dumpToPsAndPdf.c:107 msgid "Bitmap in a postscript (v3.0) file" msgstr "" #: ../src/dumpModules/dumpToPsAndPdf.c:118 msgid "Use a reduced colormap (256 colors)" msgstr "" #: ../src/dumpModules/dumpToPsAndPdf.c:126 msgid "Bitmap in a PDF (v. 1.2)" msgstr "" #: ../src/dumpModules/dumpThroughGdkPixbuf.c:80 msgid "Png file" msgstr "" #: ../src/dumpModules/dumpThroughGdkPixbuf.c:95 msgid "Jpeg file" msgstr "" #: ../src/dumpModules/dumpThroughGdkPixbuf.c:98 msgid "Compression ratio (given in percent)" msgstr "" #: ../src/dumpModules/dumpThroughGdkPixbuf.c:154 #, c-format msgid "Cannot convert pixmap to pixbuf." msgstr "" #: ../src/dumpModules/dumpToABINIT.c:71 msgid "ABINIT file (crystal only)" msgstr "" #: ../src/dumpModules/dumpToGif.c:225 #, c-format msgid "Unable to quantize image, initialisation failed for node child %d." msgstr "" #: ../src/dumpModules/dumpToGif.c:452 #, c-format msgid "Unable to quantize image, initialisation failed." msgstr "" #: ../src/dumpModules/dumpToGif.c:812 msgid "Gif (256 colors) file" msgstr "" #: ../src/dumpModules/dumpToGif.c:930 #, c-format msgid "Fail to compress the GIF file." msgstr "" #: ../src/visu_commandLine.c:198 msgid "" "V_Sim is a software to visualize atomic structures with OpenGl rendering.\n" "\n" msgstr "" #: ../src/visu_commandLine.c:200 msgid "usage:" msgstr "" #: ../src/visu_commandLine.c:233 #, c-format msgid "" "(Default value: %s)\n" "\n" msgstr "" #: ../src/visu_commandLine.c:235 msgid "" "(Default value: unset)\n" "\n" msgstr "" #: ../src/visu_commandLine.c:269 msgid "" "make an image from the fileToRender argument. The format is specified " "through the extension of the argument or by the -o fileFormatId=id option " "(get the id of available file formats with -o list)." msgstr "" #: ../src/visu_commandLine.c:273 ../src/visu_commandLine.c:277 #: ../src/visu_commandLine.c:290 ../src/visu_commandLine.c:335 #: ../src/visu_commandLine.c:351 ../src/visu_commandLine.c:376 #: ../src/visu_commandLine.c:397 ../src/visu_commandLine.c:415 msgid "file" msgstr "" #: ../src/visu_commandLine.c:275 msgid "" "load the given resources file on startup instead of looking for a valid " "resources file in the standard locations." msgstr "" #: ../src/visu_commandLine.c:279 msgid "show this little help." msgstr "" #: ../src/visu_commandLine.c:282 msgid "" "specify the size of the rendering window, the size argument must have the " "following format: x with positive non null values." msgstr "" #: ../src/visu_commandLine.c:285 msgid "x" msgstr "" #: ../src/visu_commandLine.c:287 msgid "" "use the given argument as a spin indicator. If this option is used, V_Sim " "switches automatically to spin rendering whatever method is specified in the " "parameter file." msgstr "" #: ../src/visu_commandLine.c:292 msgid "" "policy used to show or not null modulus spins possible values are positives." msgstr "" #. make and add the first column to the view #: ../src/visu_commandLine.c:294 ../src/visu_commandLine.c:316 #: ../src/visu_commandLine.c:362 ../src/visu_commandLine.c:412 #: ../src/panelModules/panelVibration.c:220 msgid "id" msgstr "" #: ../src/visu_commandLine.c:296 msgid "" "always draws atomic rendering on node position in addition to spin rendering." msgstr "" #: ../src/visu_commandLine.c:300 msgid "" "the argument fileToRender must be called, then the given file of the option " "is used to colorize the elements. If argument is starting with 'property#', " "colorization data are taken from node property propName." msgstr "" #: ../src/visu_commandLine.c:304 msgid "{file,property#propName}" msgstr "" #: ../src/visu_commandLine.c:306 msgid "" "it specifies the columns to use from the data file for the three colour " "channels [l;m;n]. Columns are counted from 1. Use -3, -2, -1 and 0 to use " "the special values, constant 1, coord. x, coord. y, and coord. z, " "respectively." msgstr "" #: ../src/visu_commandLine.c:312 msgid "" "this option can be used with the '--colorize' one or the '--build-map' one. " "It chooses a preset color scheme. The id argument is an integer that " "corresponds to a defined color shade (ranging from 0)." msgstr "" #: ../src/visu_commandLine.c:318 msgid "" "a file must be loaded. It applies the given translations to the loaded file. " "The units are those of the file. This is available for periodic file formats " "only." msgstr "" #: ../src/visu_commandLine.c:323 msgid "" "a file must be loaded. It applies the given translations to the loaded file. " "The translation is applied along box axis, normalised to 1. This is " "available for periodic file formats only." msgstr "" #: ../src/visu_commandLine.c:328 msgid "" "a file must be loaded. It applies the given expansion to the loaded file. " "The values are given in box coordinates. This is available for periodic file " "formats only." msgstr "" #: ../src/visu_commandLine.c:333 msgid "" "the argument fileToRender must be called, then the given file of the option " "is parsed as a list of planes and they are rendered." msgstr "" #: ../src/visu_commandLine.c:337 msgid "" "the argument fileToRender must be called, then the given file of the option " "is parsed as a scalar field and loaded. Use '.' as a special value to reuse " "the main filename." msgstr "" #: ../src/visu_commandLine.c:340 msgid "{file,.}" msgstr "" #: ../src/visu_commandLine.c:342 msgid "" "must be used with the '--scalar-field' option, then the given surfaces are " "built and rendered. If a name is appended to a value using '#' as a " "separator, this name is used as the name for the iso-surface (i.e. " "0.25#Blue). Use specific value 'auto' to compute isosurfaces at half max and " "min value." msgstr "" #: ../src/visu_commandLine.c:349 msgid "" "the argument fileToRender must be given, then the given file of the option " "is parsed and surfaces are rendered." msgstr "" #: ../src/visu_commandLine.c:353 msgid "" "the argument fileToRender must be given, as the '--planes', '--color-preset' " "and '--scalar-field' options used, then the given plane 'id' is replaced by " "a coloured map using given scalar field and shade. 'id' ranges from 0. If " "several ids are given, several maps are built." msgstr "" #: ../src/visu_commandLine.c:358 msgid "id[:id]" msgstr "" #: ../src/visu_commandLine.c:360 msgid "" "select the scaling method to use with gradients (0: linear, 1: log scaled " "and 2 is zero-centred log scale), default is linear scale." msgstr "" #: ../src/visu_commandLine.c:364 msgid "when positive, val isolines are plotted on the coloured map." msgstr "" #: ../src/visu_commandLine.c:365 ../src/visu_commandLine.c:373 msgid "val" msgstr "" #: ../src/visu_commandLine.c:367 msgid "" "when given, generated iso-lines are colourised [R:G:B] or auto with the " "values. The specific value 'auto' will produced iso-lines in inversed " "colours." msgstr "" #: ../src/visu_commandLine.c:370 msgid "[R:G:B] or auto" msgstr "" #: ../src/visu_commandLine.c:372 msgid "if val is not TRUE, the surfaces use their own bounding box." msgstr "" #: ../src/visu_commandLine.c:375 msgid "draw the given image on the background." msgstr "" #: ../src/visu_commandLine.c:378 msgid "" "this is a generic way to give extended option. to V_Sim. As much as -o can " "be used. Each one store a key and its value (boolean, integer or float)." msgstr "" #: ../src/visu_commandLine.c:381 msgid "id=value" msgstr "" #: ../src/visu_commandLine.c:383 msgid "" "used to choose the windowing mode. By default the command panel and the " "rendering window are separated. In the 'oneWindow' mode they are joined. In " "the 'renderOnly' mode, the command panel is not used." msgstr "" #: ../src/visu_commandLine.c:387 ../src/visu_commandLine.c:418 #: ../src/panelModules/panelOpenGL.c:344 msgid "mode" msgstr "" #: ../src/visu_commandLine.c:389 msgid "" "this flag is used to choose the id of the loaded file if the format has " "support for multiple ids in one file (see XYZ format or -posi.d3 ones)." msgstr "" #: ../src/visu_commandLine.c:392 msgid "i" msgstr "" #: ../src/visu_commandLine.c:394 msgid "" "specify an XML file with some value information for V_Sim, like a list of " "planes, highlighted nodes... It replaces and extend the previous --planes " "option." msgstr "" #: ../src/visu_commandLine.c:399 msgid "Give the precision in percent to render the coloured map." msgstr "" #: ../src/visu_commandLine.c:400 msgid "prec" msgstr "" #: ../src/visu_commandLine.c:402 msgid "Set the minimum and maximum values for the coloured map rendering." msgstr "" #: ../src/visu_commandLine.c:403 msgid "min:max or auto" msgstr "" #: ../src/visu_commandLine.c:405 msgid "" "Range to adjust values into for colourisation. col specifiesthe column to " "apply the range to. Use -2, -1 and 0 for x, yand z directions respectively." msgstr "" #: ../src/visu_commandLine.c:408 msgid "col#min:max or auto" msgstr "" #: ../src/visu_commandLine.c:410 msgid "" "used with a data file (see -c), it specifies the column id to be used to " "scale the nodes." msgstr "" #: ../src/visu_commandLine.c:414 msgid "Compute the geometric difference between load file and this argument." msgstr "" #: ../src/visu_commandLine.c:417 msgid "Load the given phonon mode." msgstr "" #: ../src/visu_commandLine.c:420 msgid "Displace nodes according to phonons at the given reduced time in [0;1]." msgstr "" #: ../src/visu_commandLine.c:421 msgid "offset" msgstr "" #: ../src/visu_commandLine.c:423 msgid "Maximum displacement for phonons." msgstr "" #: ../src/visu_commandLine.c:424 msgid "ampl" msgstr "" #: ../src/support.h:58 msgid "_Save" msgstr "" #: ../src/support.h:59 msgid "_Open" msgstr "" #: ../src/coreTools/toolArray.c:193 msgid "" "Can't find any columns with numbers.\n" "Valid format are as much numbers as desired, separated by any of the " "following characters : [ ;:\\t].\n" msgstr "" #: ../src/coreTools/toolArray.c:230 #, c-format msgid "There is a different number of data (%d) compared to expected (%d).\n" msgstr "" #: ../src/coreTools/toolColor.c:388 ../src/coreTools/toolShade.c:838 #, c-format msgid "cannot read a color from '%s' (name, #rgb, #rrggbb ... awaited).\n" msgstr "" #: ../src/coreTools/toolFiles.c:197 #, c-format msgid "cannot read next archive entry.\n" msgstr "" #: ../src/coreTools/toolFiles.c:212 #, c-format msgid "Format not supported." msgstr "" #: ../src/coreTools/toolFiles.c:268 #, c-format msgid "read error from archive.\n" msgstr "" #: ../src/coreTools/toolFiles.c:346 ../src/coreTools/toolFiles.c:403 #: ../src/coreTools/toolFiles.c:492 ../src/coreTools/toolFiles.c:527 #, c-format msgid "file not opened.\n" msgstr "" #: ../src/coreTools/toolShade.c:705 msgid "blue to red" msgstr "" #: ../src/coreTools/toolShade.c:716 msgid "hot color" msgstr "" #: ../src/coreTools/toolShade.c:727 msgid "blue to yellow" msgstr "" #: ../src/coreTools/toolShade.c:738 msgid "zero centred dark" msgstr "" #. Create a blue and red shade with withe zero centred. #: ../src/coreTools/toolShade.c:743 msgid "zero centred light" msgstr "" #: ../src/coreTools/toolShade.c:748 msgid "zero centred coloured" msgstr "" #: ../src/coreTools/toolShade.c:760 msgid "green to red" msgstr "" #: ../src/coreTools/toolShade.c:771 msgid "light green to red" msgstr "" #: ../src/coreTools/toolShade.c:782 msgid "black to white" msgstr "" #: ../src/coreTools/toolShade.c:793 msgid "white to black" msgstr "" #: ../src/coreTools/toolShade.c:804 msgid "purple color" msgstr "" #. Create the so-called Jet colour map. #: ../src/coreTools/toolShade.c:809 msgid "Jet map" msgstr "" #: ../src/coreTools/toolShade.c:826 #, c-format msgid "1 floating point value should start a step '%s'.\n" msgstr "" #: ../src/coreTools/toolFileFormat.c:157 ../src/gtk_about.c:354 msgid "Name" msgstr "" #: ../src/coreTools/toolFileFormat.c:157 msgid "File format description." msgstr "" #: ../src/coreTools/toolFileFormat.c:168 msgid "Label used to show the file pattern." msgstr "" #: ../src/coreTools/toolFileFormat.c:180 msgid "Ignore file patterns" msgstr "" #: ../src/coreTools/toolFileFormat.c:181 msgid "Don't restrict file matching to the given patterns." msgstr "" #: ../src/coreTools/toolConfigFile.c:109 #, c-format msgid "Parse error at line %d, %d floating point values should appear here.\n" msgstr "" #: ../src/coreTools/toolConfigFile.c:122 #, c-format msgid "" "Parse error at line %d, %d floating point value(s) should appear here but %d " "has been found.\n" msgstr "" #: ../src/coreTools/toolConfigFile.c:193 #, c-format msgid "Parse error at line %d, %d boolean values should appear here.\n" msgstr "" #: ../src/coreTools/toolConfigFile.c:206 #, c-format msgid "" "Parse error at line %d, %d boolean(s) values should appear here but %d has " "been found.\n" msgstr "" #: ../src/coreTools/toolConfigFile.c:278 ../src/coreTools/toolConfigFile.c:332 #, c-format msgid "" "Parse error at line %d, %d string(s) should appear here but %d has been " "found.\n" msgstr "" #: ../src/coreTools/toolConfigFile.c:383 ../src/coreTools/toolConfigFile.c:432 #, c-format msgid "" "Parse error at line %d, a label should appear here but none has been found.\n" msgstr "" #: ../src/coreTools/toolConfigFile.c:504 #, c-format msgid "Parse error at line %d, %d integer values should appear here.\n" msgstr "" #: ../src/coreTools/toolConfigFile.c:517 #, c-format msgid "" "Parse error at line %d, %d integer(s) values should appear here but %d has " "been found.\n" msgstr "" #: ../src/coreTools/toolFortran.c:444 #, c-format msgid "wrong fortran syntax, flag size unmatched (%ld != %ld).\n" msgstr "" #: ../src/gtk_main.c:361 msgid "Actions" msgstr "" #: ../src/gtk_main.c:375 msgid "Select a file to render." msgstr "" #: ../src/gtk_main.c:386 msgid "Check to draw pairs between elements." msgstr "" #: ../src/gtk_main.c:393 msgid "Configure parameters for bindings such as color, thickness..." msgstr "" #: ../src/gtk_main.c:401 msgid "_Pairs" msgstr "" #: ../src/gtk_main.c:409 msgid "Use the mouse to change the view and get position informations." msgstr "" #: ../src/gtk_main.c:417 msgid "Mouse _actions" msgstr "" #: ../src/gtk_main.c:427 msgid "Click to save the parameters or the resources." msgstr "" #: ../src/gtk_main.c:435 msgid "_Config. files" msgstr "" #: ../src/gtk_main.c:445 msgid "V_Sim program. Written by L. Billard, modified by D. Caliste." msgstr "" #: ../src/gtk_main.c:689 msgid "Choose a directory" msgstr "" #: ../src/gtk_main.c:707 msgid "" "Choose several directories using the Control key." msgstr "" #. Failed. #: ../src/gtk_main.c:1101 msgid "I/O" msgstr "" #: ../src/gtk_main.c:1102 msgid "Can't create the directory '$XDG_CONFIG_HOME/v_sim'." msgstr "" #: ../src/gtk_main.c:1238 #, c-format msgid "Parse error at line %d: awaited 'id visible pos size'.\n" msgstr "" #: ../src/gtk_main.c:1249 #, c-format msgid "" "Parse error at line %d: can't read dock characteristic values from '%s'.\n" msgstr "" #: ../src/gtk_main.c:1337 msgid "Command line actions" msgstr "" #: ../src/gtk_main.c:1338 ../src/panelModules/panelSurfaces.c:1089 msgid "Unknown error" msgstr "" #: ../src/interface.c:79 msgid "Save session" msgstr "" #: ../src/interface.c:110 msgid "Manage configuration files" msgstr "" #: ../src/interface.c:135 msgid "Load from file" msgstr "" #: ../src/interface.c:164 ../src/interface.c:239 msgid "Save to file" msgstr "" #: ../src/interface.c:186 msgid "Export resources related to rendered file only" msgstr "" #: ../src/interface.c:221 msgid "" "Resources (values related to rendering " "aspects)" msgstr "" #: ../src/interface.c:275 msgid "" "Parameters (Interface options)" msgstr "" #: ../src/interface.c:288 msgid "" "When saving, if you just specify a directory 'dir/', it will be save to 'dir/v_sim.[res][par]' by default, ortherwise speficy a " "full path." msgstr "" #: ../src/interface.c:297 msgid "" "Tips: think to create a $XDG_CONFIG_HOME/v_sim directory and put your resource " "and parameter files in it. It is scanned at startup." msgstr "" #: ../src/interface.c:315 ../src/interface.c:1024 ../src/interface.c:1645 msgid "Help" msgstr "" #: ../src/interface.c:494 msgid "Pick and observe session" msgstr "" #: ../src/interface.c:541 msgid "Observe" msgstr "" #: ../src/interface.c:553 msgid "constrained" msgstr "" #: ../src/interface.c:556 msgid "" "Movement are along meridians when the mouse is dragged along y axis and " "along parallels when the movement is along x axis." msgstr "" #: ../src/interface.c:560 msgid "walker" msgstr "" #: ../src/interface.c:563 msgid "" "Movements are those of a walking ant on a sphere, when mouse move along y " "axis, the ant goes strait on, when mouse is dragged along x axis, the ant " "translates on its right or on its left." msgstr "" #: ../src/interface.c:578 msgid "Translations" msgstr "" #: ../src/interface.c:584 msgid "Scale" msgstr "" #: ../src/interface.c:630 msgid "omega:" msgstr "" #: ../src/interface.c:636 msgid "phi:" msgstr "" #: ../src/interface.c:648 msgid "zoom:" msgstr "" #: ../src/interface.c:654 msgid "theta:" msgstr "" #: ../src/interface.c:674 msgid "persp.:" msgstr "" #: ../src/interface.c:725 ../src/interface.c:821 msgid "Pick" msgstr "" #: ../src/interface.c:772 msgid "Persistent measures" msgstr "" #: ../src/interface.c:780 msgid "Remove all drawn measurements." msgstr "" #: ../src/interface.c:801 msgid "Add highlighted nodes to the list below." msgstr "" #: ../src/interface.c:810 msgid "Remove all highlight marks." msgstr "" #: ../src/interface.c:843 msgid "Modify nodes (position, numbers...)" msgstr "" #: ../src/interface.c:857 msgid "Move or delete:" msgstr "" #: ../src/interface.c:863 msgid "picked _node" msgstr "" #: ../src/interface.c:869 msgid "_selected nodes" msgstr "" #: ../src/interface.c:881 msgid "" "(selected nodes are listed in the pick tab)" msgstr "" #: ../src/interface.c:893 msgid "Specific moving axis:" msgstr "" #: ../src/interface.c:922 msgid "Current pos./trans.:" msgstr "" #: ../src/interface.c:950 msgid "Add a new node:" msgstr "" #: ../src/interface.c:961 msgid "position:" msgstr "" #: ../src/interface.c:971 msgid "Screen basis set:" msgstr "" #: ../src/interface.c:977 msgid "horiz." msgstr "" #: ../src/interface.c:988 msgid "vert." msgstr "" #: ../src/interface.c:999 msgid "Geometry changes" msgstr "" #: ../src/interface.c:1041 msgid "Back to command panel" msgstr "" #: ../src/interface.c:1190 msgid "About V_Sim" msgstr "" #: ../src/interface.c:1227 msgid "Version :" msgstr "" #: ../src/interface.c:1233 msgid "Release Date :" msgstr "" #: ../src/interface.c:1239 msgid "Web site :" msgstr "" #: ../src/interface.c:1286 msgid "Readme" msgstr "" #: ../src/interface.c:1305 ../src/gtk_about.c:370 msgid "Authors" msgstr "" #: ../src/interface.c:1323 msgid "License" msgstr "" #: ../src/interface.c:1331 msgid "Loaded plug-ins:" msgstr "" #: ../src/interface.c:1342 msgid "Plug-ins" msgstr "" #: ../src/interface.c:1360 msgid "Changelog" msgstr "" #: ../src/interface.c:1432 msgid "set and customize pairs" msgstr "" #: ../src/interface.c:1455 msgid "Set parameters for pairs" msgstr "" #: ../src/interface.c:1492 msgid "Pairs" msgstr "" #: ../src/interface.c:1501 msgid "Distances" msgstr "" #: ../src/interface.c:1559 msgid "Quit V_Sim" msgstr "" #: ../src/interface.c:1581 msgid "Quit V_Sim?" msgstr "" #: ../src/interface.c:1587 msgid "Don't show this warning again." msgstr "" #: ../src/interface.c:1599 msgid "" "Can't find a local configuration directory " "$XDG_CONFIG_HOME/v_sim. Should one be added?" msgstr "" #: ../src/interface.c:1618 msgid "" "Can't find a v_sim.par file with " "enough write permissions to store the preference, neither in the " "installation directory nor in the " "$XDG_CONFIG_HOME/v_sim one." msgstr "" #: ../src/interface.c:1629 msgid "" "If you check the above box but you want to have this " "warning dialog again before closing, you can change this by editing the " "parameter file (v_sim.par). The option is " "called 'main_confirmQuit'." msgstr "" #: ../src/visu_data.c:1776 msgid "option '--phonon-mode' has been given but no phonons are available." msgstr "" #: ../src/visu_data.c:1783 msgid "option '--time-opffset' has been given but no phonons are available." msgstr "" #: ../src/visu_data.c:1788 msgid "" "option '--phonon-amplitude' has been given but no phonons are available." msgstr "" #. Help message used in the help area. #: ../src/gtk_interactive.c:127 msgid "" "left-[control]-button\t\t\t: rotations (θ, φ, [control]ω)\n" "shift-left-button\t\t\t\t: translations (dx, dy)\n" "middle-[shift]-button or wheel\t: zoom or [shift]perspective\n" "key 's' / 'r'\t\t\t\t\t: save/restore camera position\n" "right-button\t\t\t\t\t: switch to current tabbed action" msgstr "" #: ../src/gtk_interactive.c:271 msgid "_Ok" msgstr "" #. * #. * SECTION: visu_dataspin #. * @short_description: a class of nodes representing spin data and #. * providing associated loading methods. #. * #. * This class provides #VisuDataLoader for spin data representation. #. #: ../src/visu_dataspin.c:55 msgid "Spin (θ, φ, mod.)" msgstr "" #: ../src/visu_dataspin.c:105 msgid "Ascii spin files" msgstr "" #: ../src/visu_dataspin.c:108 msgid "Binary spin files" msgstr "" #: ../src/visu_dataspin.c:287 msgid "Spin files" msgstr "" #: ../src/visu_dataspin.c:519 #, c-format msgid "impossible to open this spin file.\n" msgstr "" #: ../src/visu_dataspin.c:528 #, c-format msgid "spin file should have one line at least.\n" msgstr "" #: ../src/visu_dataspin.c:614 #, c-format msgid "number of spin differs from number of nodes.\n" msgstr "" #: ../src/extraFunctions/surfaces.c:702 ../src/extraFunctions/surfaces.c:723 #, c-format msgid "Line %d doesn't match the [float, float, float] pattern." msgstr "" #: ../src/extraFunctions/surfaces.c:746 #, c-format msgid "Line %d doesn't match the [int > 0, int > 0, int > 0] pattern." msgstr "" #: ../src/extraFunctions/surfaces.c:811 #, c-format msgid "Line %d doesn't match the [int > 0, int > 0] pattern." msgstr "" #: ../src/extraFunctions/surfaces.c:825 #, c-format msgid "Error on line %d. Declared number of polygons reached." msgstr "" #: ../src/extraFunctions/surfaces.c:839 #, c-format msgid "Error on line %d. Declared number of points reached." msgstr "" #: ../src/extraFunctions/surfaces.c:882 #, c-format msgid "Line %dmust begin by an int." msgstr "" #: ../src/extraFunctions/surfaces.c:899 #, c-format msgid "Line %d doesn't match the [int > 3, ...] required pattern." msgstr "" #: ../src/extraFunctions/surfaces.c:943 #, c-format msgid "Line %d doesn't match the [float x 6] required pattern." msgstr "" #: ../src/extraFunctions/nodeProp.c:427 ../src/extraFunctions/nodeProp.c:504 msgid "T" msgstr "" #: ../src/extraFunctions/nodeProp.c:429 ../src/extraFunctions/nodeProp.c:506 msgid "F" msgstr "" #: ../src/extraFunctions/coordProp.c:122 msgid "Coord. (x, y, z)" msgstr "" #: ../src/extraFunctions/pot2surf.c:990 #, c-format msgid "Negative (%d)" msgstr "" #: ../src/extraFunctions/pot2surf.c:1003 #, c-format msgid "Positive (%d)" msgstr "" #: ../src/extraFunctions/pot2surf.c:1773 ../src/extraFunctions/pot2surf.c:1823 #: ../src/extraFunctions/pot2surf.c:1873 ../src/extraFunctions/pot2surf.c:1921 #: ../src/extraFunctions/planeset.c:891 ../src/extraFunctions/planeset.c:922 #: ../src/extraFunctions/planeset.c:968 ../src/extraFunctions/planeset.c:1010 #: ../src/extraFunctions/planeset.c:1040 #, c-format msgid "Unexpected attribute '%s' for element '%s'." msgstr "" #: ../src/extraFunctions/pot2surf.c:1811 ../src/extraFunctions/pot2surf.c:1818 #: ../src/extraFunctions/pot2surf.c:1868 ../src/extraFunctions/pot2surf.c:1903 #: ../src/extraFunctions/pot2surf.c:1914 ../src/extraFunctions/planeset.c:916 #: ../src/extraFunctions/planeset.c:953 ../src/extraFunctions/planeset.c:962 #: ../src/extraFunctions/planeset.c:994 ../src/extraFunctions/planeset.c:1005 #: ../src/extraFunctions/planeset.c:1033 #, c-format msgid "Invalid value '%s' for attribute '%s'." msgstr "" #: ../src/extraFunctions/pot2surf.c:1836 ../src/extraFunctions/pot2surf.c:1878 #, c-format msgid "Missing attribute '%s' for element '%s'." msgstr "" #: ../src/extraFunctions/pot2surf.c:2022 #, c-format msgid "No iso-value found." msgstr "" #: ../src/extraFunctions/planeset.c:939 #, c-format msgid "DTD error : parent element '%s' of element '%s' is missing." msgstr "" #: ../src/extraFunctions/planeset.c:1068 ../src/extraFunctions/planeset.c:1076 #, c-format msgid "DTD error: missing or wrong child element '%s'." msgstr "" #: ../src/extraFunctions/planeset.c:1143 #, c-format msgid "The file contains no plane.\n" msgstr "" #: ../src/extraFunctions/geometry.c:740 ../src/extraFunctions/geometry.c:801 #, c-format msgid "DTD error: element '%s' have missing mandatory attributes." msgstr "" #: ../src/extraFunctions/geometry.c:871 #, c-format msgid "No paths found." msgstr "" #: ../src/extraFunctions/dataFile.c:1464 #, c-format msgid "Colorization from a non existing node property '%s'." msgstr "" #: ../src/extraFunctions/dataFile.c:1468 msgid "Colorization from a node property that is not a float array." msgstr "" #: ../src/extraFunctions/dataFile.c:1485 #, c-format msgid "" "Assign a column data without specifying a data file. Use -c option or change " "the value %d." msgstr "" #: ../src/extraFunctions/shellProp.c:234 #, c-format msgid "shell %d" msgstr "" #: ../src/extraFunctions/shellProp.c:236 msgid "root" msgstr "" #: ../src/extraFunctions/sfielddata.c:86 msgid "Potential/density files" msgstr "" #: ../src/extraFunctions/sfielddata.c:415 #, c-format msgid "impossible to open the file.\n" msgstr "" #: ../src/extraFunctions/sfielddata.c:502 #, c-format msgid "wrong '%s' value for flag '%s'.\n" msgstr "" #: ../src/extraFunctions/sfielddata.c:523 #, c-format msgid "not enough meshx values.\n" msgstr "" #: ../src/extraFunctions/sfielddata.c:533 #, c-format msgid "impossible to read meshx values.\n" msgstr "" #: ../src/extraFunctions/sfielddata.c:562 #: ../src/extraFunctions/sfielddata.c:598 #, c-format msgid "not enough density values.\n" msgstr "" #: ../src/extraFunctions/sfielddata.c:574 #: ../src/extraFunctions/sfielddata.c:608 #, c-format msgid "impossible to read density values.\n" msgstr "" #: ../src/extraFunctions/sfielddata.c:878 #, c-format msgid "unknown density/potential format.\n" msgstr "" #: ../src/extraFunctions/idProp.c:92 ../lib/plug-ins/abinit/ab_symmetry.c:223 msgid "Id" msgstr "" #: ../src/extraFunctions/typeProp.c:131 msgid "Type" msgstr "" #. * #. * VISU_COLORIZATION_LABEL: #. * #. * Default label used to name colourisation data. #. #: ../src/extraFunctions/dataFile.h:100 msgid "Colorization data" msgstr "" #: ../src/pairsModeling/iface_wire.c:205 #, c-format msgid "shade id must be in [%d;%d]" msgstr "" #: ../src/pairsModeling/cylinder_renderer.c:168 msgid "Cylinder pairs" msgstr "" #: ../src/pairsModeling/cylinder_renderer.c:168 msgid "Pairs are rendered by cylinders. The color and the width can by chosen." msgstr "" #: ../src/pairsModeling/wire_renderer.c:94 msgid "Wire pairs" msgstr "" #: ../src/pairsModeling/wire_renderer.c:95 msgid "" "Pairs are rendered by flat lines. The color and the width can by chosen." msgstr "" #: ../src/visu_dataloadable.c:131 msgid "No input files" msgstr "" #: ../src/visu_dataloadable.c:200 msgid "No file" msgstr "" #: ../src/visu_dataloadable.c:368 #, c-format msgid "No filename available." msgstr "" #: ../src/visu_dataloadable.c:375 #, c-format msgid "File '%s' is not a regular file or may not exist." msgstr "" #: ../src/visu_dataloadable.c:383 #, c-format msgid "File '%s' is empty." msgstr "" #: ../src/panelModules/panelOpenGL.c:77 msgid "Follow global setting" msgstr "" #: ../src/panelModules/panelOpenGL.c:97 msgid "Set OpenGL parameters" msgstr "" #: ../src/panelModules/panelOpenGL.c:98 ../src/panelModules/panelOpenGL.c:368 msgid "OpenGL" msgstr "" #: ../src/panelModules/panelOpenGL.c:232 msgid "Use" msgstr "" #: ../src/panelModules/panelOpenGL.c:242 msgid "x" msgstr "" #: ../src/panelModules/panelOpenGL.c:250 msgid "y" msgstr "" #: ../src/panelModules/panelOpenGL.c:258 msgid "z" msgstr "" #: ../src/panelModules/panelOpenGL.c:266 msgid "power" msgstr "" #: ../src/panelModules/panelOpenGL.c:333 msgid "name of extension" msgstr "" #: ../src/panelModules/panelOpenGL.c:369 msgid "" "The maximm number of lights allowed by OpenGL has been reached, can't add " "more." msgstr "" #: ../src/panelModules/panelOpenGL.c:501 msgid "Rendering options:" msgstr "" #: ../src/panelModules/panelOpenGL.c:513 ../src/panelModules/panelMap.c:451 msgid "Precision:" msgstr "" #: ../src/panelModules/panelOpenGL.c:533 msgid "Mode:" msgstr "" #: ../src/panelModules/panelOpenGL.c:538 msgid "Antialiase lines:" msgstr "" #: ../src/panelModules/panelOpenGL.c:549 msgid "Enhanced transparency:" msgstr "" #: ../src/panelModules/panelOpenGL.c:555 msgid "Use stereo rendering:" msgstr "" #. Degrees. #: ../src/panelModules/panelOpenGL.c:562 ../src/panelModules/gtkSpin.c:225 msgid "deg." msgstr "" #: ../src/panelModules/panelOpenGL.c:568 msgid "angle:" msgstr "" #: ../src/panelModules/panelOpenGL.c:575 msgid "Per extension rendering mode:" msgstr "" #: ../src/panelModules/panelOpenGL.c:591 msgid "Redraw immediately after changes:" msgstr "" #. ******************* #. VisuGlLight parameters. #. ******************* #: ../src/panelModules/panelOpenGL.c:605 msgid "Light sources:" msgstr "" #: ../src/panelModules/panelAxes.c:94 msgid "Box, axes and labels" msgstr "" #: ../src/panelModules/panelAxes.c:95 msgid "Frames/labels" msgstr "" #. The label. #: ../src/panelModules/panelAxes.c:216 msgid "Legend" msgstr "" #: ../src/panelModules/panelElements.c:81 msgid "Set elements caracteristics" msgstr "" #: ../src/panelModules/panelElements.c:82 msgid "Elements" msgstr "" #: ../src/panelModules/panelConfig.c:127 msgid "Configure the interface" msgstr "" #: ../src/panelModules/panelConfig.c:128 msgid "Configuration" msgstr "" #: ../src/panelModules/panelConfig.c:216 msgid "Always show _labels in tabs" msgstr "" #: ../src/panelModules/panelConfig.c:223 msgid "Automatic _refresh" msgstr "" #: ../src/panelModules/panelConfig.c:229 msgid " s" msgstr "" #: ../src/panelModules/panelConfig.c:234 msgid "period:" msgstr "" #: ../src/panelModules/panelConfig.c:239 msgid "Remember _windows positions" msgstr "" #: ../src/panelModules/panelConfig.c:244 msgid "Display _coordinates in reduce" msgstr "" #: ../src/panelModules/panelConfig.c:251 msgid "Set the prefered unit:" msgstr "" #. String used to labelled planes, dist. means 'distance' and #. norm. means 'normal' (50 chars max). #: ../src/panelModules/panelMap.c:93 #, c-format msgid "plane (%2d;%2d;%2d - %4.1f)" msgstr "" #: ../src/panelModules/panelMap.c:184 #, c-format msgid "norm.: (%3d;%3d;%3d) dist.: %6.2f" msgstr "" #: ../src/panelModules/panelMap.c:279 msgid "not plane based" msgstr "" #: ../src/panelModules/panelMap.c:314 msgid "Map sources" msgstr "" #: ../src/panelModules/panelMap.c:324 msgid "missing elements" msgstr "" #: ../src/panelModules/panelMap.c:331 msgid "Cutting plane:" msgstr "" #: ../src/panelModules/panelMap.c:335 msgid "Create elements in the 'planes' tab" msgstr "" #: ../src/panelModules/panelMap.c:375 msgid "Scalar field:" msgstr "" #: ../src/panelModules/panelMap.c:379 msgid "Import fields in the 'isosurfaces' tab" msgstr "" #: ../src/panelModules/panelMap.c:414 msgid "Shade:" msgstr "" #: ../src/panelModules/panelMap.c:418 msgid "with _transparency" msgstr "" #: ../src/panelModules/panelMap.c:436 msgid "Options" msgstr "" #: ../src/panelModules/panelMap.c:458 msgid "Scale:" msgstr "" #: ../src/panelModules/panelMap.c:462 msgid "_linear" msgstr "" #: ../src/panelModules/panelMap.c:470 msgid "lo_g." msgstr "" #: ../src/panelModules/panelMap.c:478 msgid "_zero centred log." msgstr "" #: ../src/panelModules/panelMap.c:489 msgid "Number of isolines:" msgstr "" #: ../src/panelModules/panelMap.c:499 msgid "_colour:" msgstr "" #: ../src/panelModules/panelMap.c:520 msgid "Normalise:" msgstr "" #: ../src/panelModules/panelMap.c:523 ../src/panelModules/panelDataFile.c:370 msgid "auto" msgstr "" #: ../src/panelModules/panelMap.c:530 ../src/panelModules/panelDataFile.c:375 #: ../src/panelModules/gtkAtomic.c:213 msgid "manual" msgstr "" #: ../src/panelModules/panelMap.c:566 msgid "List of maps:" msgstr "" #: ../src/panelModules/panelMap.c:845 msgid "Export to SVG or PDF." msgstr "" #: ../src/panelModules/panelMap.c:856 msgid "PDF document (*.pdf)" msgstr "" #: ../src/panelModules/panelMap.c:860 msgid "SVG document (*.svg)" msgstr "" #: ../src/panelModules/panelMap.c:874 msgid "map.pdf" msgstr "" #: ../src/panelModules/panelMap.c:902 msgid "Export a coloured map" msgstr "" #. Long description #: ../src/panelModules/panelMap.c:940 msgid "Map projections" msgstr "" #. Short description #: ../src/panelModules/panelMap.c:942 msgid "Maps" msgstr "" #: ../src/panelModules/panelGeometry.c:85 msgid "No stored path" msgstr "" #: ../src/panelModules/panelGeometry.c:86 #, c-format msgid "Path has %d step(s)" msgstr "" #: ../src/panelModules/panelGeometry.c:116 msgid "Geometry operations" msgstr "" #: ../src/panelModules/panelGeometry.c:117 msgid "Geometry" msgstr "" #: ../src/panelModules/panelGeometry.c:126 msgid "Paste and align" msgstr "" #. ********************** #. The multifile stuff. #. ********************** #: ../src/panelModules/panelGeometry.c:218 msgid "Multi file actions" msgstr "" #: ../src/panelModules/panelGeometry.c:229 msgid "Automatic zoom _adjustment on file loading" msgstr "" #: ../src/panelModules/panelGeometry.c:237 msgid "with re_ordering" msgstr "" #: ../src/panelModules/panelGeometry.c:241 msgid "On load of a new file, reorder the nodes to minimize displacements." msgstr "" #: ../src/panelModules/panelGeometry.c:244 msgid "Show node _displacements" msgstr "" #: ../src/panelModules/panelGeometry.c:248 msgid "" "When a new file is loaded, draw arrows on nodes that represent their " "displacements with respect to their previous positions." msgstr "" #: ../src/panelModules/panelGeometry.c:274 msgid "Use _paths" msgstr "" #: ../src/panelModules/panelGeometry.c:278 msgid "Store differences between files and plot them as lines." msgstr "" #: ../src/panelModules/panelGeometry.c:291 msgid "When toggled, store differences between files as paths through nodes.." msgstr "" #: ../src/panelModules/panelGeometry.c:303 msgid "Remove all stored paths." msgstr "" #: ../src/panelModules/panelGeometry.c:316 msgid "colourise with: " msgstr "" #: ../src/panelModules/panelGeometry.c:317 msgid "" "If energy information was present when loading file, colourise the paths " "with shading colours." msgstr "" #: ../src/panelModules/panelGeometry.c:334 msgid "Read a set of paths from a file and add them to the current set." msgstr "" #: ../src/panelModules/panelGeometry.c:343 msgid "Save the current set of paths to an XML file." msgstr "" #: ../src/panelModules/panelGeometry.c:445 #, c-format msgid "Displacement field match %d node(s)." msgstr "" #: ../src/panelModules/panelGeometry.c:516 msgid "Drag the displacement field." msgstr "" #: ../src/panelModules/panelGeometry.c:564 msgid "Recording paths" msgstr "" #: ../src/panelModules/panelGeometry.c:580 #: ../src/panelModules/panelGeometry.c:606 msgid "Export current set of paths." msgstr "" #: ../src/panelModules/panelGeometry.c:586 msgid "paths.xml" msgstr "" #: ../src/panelModules/panelGeometry.c:627 #: ../src/panelModules/panelGeometry.c:648 msgid "Load a set of paths." msgstr "" #: ../src/panelModules/panelSurfacesTools.c:232 msgid "Found different dxx, ..., dzz" msgstr "" #: ../src/panelModules/panelSurfacesTools.c:235 msgid "Keep current values" msgstr "" #: ../src/panelModules/panelSurfacesTools.c:236 msgid "Change values to new ones" msgstr "" #: ../src/panelModules/panelSurfacesTools.c:239 msgid "" "Current dxx, ..., dzz, doesn't match the ones used in the file you are " "trying to load. Do you want to keep old dxx, ..., dzz ? (if you don't know " "exactly what you're doing, just cancel and load another file)" msgstr "" #: ../src/panelModules/panelSurfacesTools.c:323 msgid "Unable to parse the selected file." msgstr "" #: ../src/panelModules/panelSurfacesTools.c:471 #: ../src/panelModules/panelSurfacesTools.c:1370 msgid "Surface name" msgstr "" #: ../src/panelModules/panelSurfacesTools.c:493 msgid "New name" msgstr "" #: ../src/panelModules/panelSurfacesTools.c:501 msgid "old name" msgstr "" #: ../src/panelModules/panelSurfacesTools.c:507 msgid "from file" msgstr "" #: ../src/panelModules/panelSurfacesTools.c:640 #: ../src/panelModules/panelSurfacesTools.c:660 #: ../src/panelModules/panelSurfacesTools.c:683 #: ../src/panelModules/panelSurfacesTools.c:703 msgid "An unknown error occured. Your surf file is corrupted.\n" msgstr "" #: ../src/panelModules/panelSurfacesTools.c:738 msgid "Please choose a surf file to write\n" msgstr "" #: ../src/panelModules/panelSurfacesTools.c:751 msgid "No surface to write\n" msgstr "" #: ../src/panelModules/panelSurfacesTools.c:798 msgid "Target info : " msgstr "" #: ../src/panelModules/panelSurfacesTools.c:799 msgid "Source info : " msgstr "" #: ../src/panelModules/panelSurfacesTools.c:841 msgid "Build specified new .surf file" msgstr "" #: ../src/panelModules/panelSurfacesTools.c:843 msgid "Contains the full path to the currently .surf selected file" msgstr "" #: ../src/panelModules/panelSurfacesTools.c:845 #: ../src/panelModules/panelSurfacesTools.c:2044 msgid "Contains the full path to the .surf file you want to build" msgstr "" #: ../src/panelModules/panelSurfacesTools.c:847 msgid "Allows you to select a .surf file" msgstr "" #: ../src/panelModules/panelSurfacesTools.c:849 #: ../src/panelModules/panelSurfacesTools.c:2064 msgid "Selects the .surf file to write" msgstr "" #: ../src/panelModules/panelSurfacesTools.c:851 msgid "Moves selected surface to the list of surfaces to build" msgstr "" #: ../src/panelModules/panelSurfacesTools.c:853 #: ../src/panelModules/panelSurfacesTools.c:2058 msgid "Moves down selected surface in the list of surfaces to build" msgstr "" #: ../src/panelModules/panelSurfacesTools.c:855 #: ../src/panelModules/panelSurfacesTools.c:2060 msgid "Moves up selected surface in the list of surfaces to build" msgstr "" #: ../src/panelModules/panelSurfacesTools.c:857 #: ../src/panelModules/panelSurfacesTools.c:2056 msgid "Removes selected surface from the list of surfaces to build" msgstr "" #: ../src/panelModules/panelSurfacesTools.c:866 msgid "The d__ of the current selected file" msgstr "" #: ../src/panelModules/panelSurfacesTools.c:875 msgid "The d__ of the file to build" msgstr "" #: ../src/panelModules/panelSurfacesTools.c:892 msgid "Current file : " msgstr "" #: ../src/panelModules/panelSurfacesTools.c:949 msgid "Target file : " msgstr "" #. Create a new dialog window for the scrolled window to be #. * packed into. #: ../src/panelModules/panelSurfacesTools.c:1023 msgid "pot2surf_help" msgstr "" #: ../src/panelModules/panelSurfacesTools.c:1070 msgid "Can't open given file for reading" msgstr "" #: ../src/panelModules/panelSurfacesTools.c:1083 #: ../src/panelModules/panelSurfacesTools.c:1111 msgid "This file doesn't seem to be a correct pot file" msgstr "" #: ../src/panelModules/panelSurfacesTools.c:1094 msgid "Second line seem to contain incorrect values" msgstr "" #: ../src/panelModules/panelSurfacesTools.c:1373 msgid "Pot value" msgstr "" #: ../src/panelModules/panelSurfacesTools.c:1565 msgid "Please select an instruc file to write" msgstr "" #: ../src/panelModules/panelSurfacesTools.c:1572 msgid "Can't open selected instruc file for writing" msgstr "" #: ../src/panelModules/panelSurfacesTools.c:1607 #: ../src/panelModules/panelSurfacesTools.c:1707 msgid "Please specify surfaces to draw" msgstr "" #: ../src/panelModules/panelSurfacesTools.c:1613 #: ../src/panelModules/panelSurfacesTools.c:1713 msgid "Please select a source pot file" msgstr "" #: ../src/panelModules/panelSurfacesTools.c:1619 #: ../src/panelModules/panelSurfacesTools.c:1719 msgid "Please select a target surf file" msgstr "" #: ../src/panelModules/panelSurfacesTools.c:1745 msgid "Error" msgstr "" #: ../src/panelModules/panelSurfacesTools.c:1835 msgid "Can't open selected file" msgstr "" #: ../src/panelModules/panelSurfacesTools.c:1843 msgid "Line 1 must contain the full path to the .pot file to read\n" msgstr "" #: ../src/panelModules/panelSurfacesTools.c:1855 msgid "Line 2 must contain the full path to the .surf file to read\n" msgstr "" #: ../src/panelModules/panelSurfacesTools.c:1868 msgid "Line 3 must contain the number of surfaces to build\n" msgstr "" #: ../src/panelModules/panelSurfacesTools.c:1885 msgid "Lines must contain the value of the surface to build and its name\n" msgstr "" #: ../src/panelModules/panelSurfacesTools.c:1998 msgid "Build" msgstr "" #: ../src/panelModules/panelSurfacesTools.c:1999 msgid "Autoload in V_Sim" msgstr "" #: ../src/panelModules/panelSurfacesTools.c:2040 msgid "If checked, autoloads newly built file in V_Sim" msgstr "" #: ../src/panelModules/panelSurfacesTools.c:2042 msgid "Contains the full path to the currently .pot selected file" msgstr "" #: ../src/panelModules/panelSurfacesTools.c:2046 msgid "Contains the minimal value found in the selected .pot file" msgstr "" #: ../src/panelModules/panelSurfacesTools.c:2048 msgid "Contains the maximal value found in the selected .pot file" msgstr "" #: ../src/panelModules/panelSurfacesTools.c:2050 msgid "Tries to build specified .surf file using specified parameters" msgstr "" #: ../src/panelModules/panelSurfacesTools.c:2052 msgid "Adds a new surface to the list of surfaces to build" msgstr "" #: ../src/panelModules/panelSurfacesTools.c:2054 msgid "Adds many surfaces to the list of surfaces to build" msgstr "" #: ../src/panelModules/panelSurfacesTools.c:2062 msgid "Selects the .pot file to use" msgstr "" #: ../src/panelModules/panelSurfacesTools.c:2066 msgid "Opens a .instruc file" msgstr "" #: ../src/panelModules/panelSurfacesTools.c:2068 msgid "Saves current settings as .instruc file" msgstr "" #: ../src/panelModules/panelSurfacesTools.c:2070 msgid "Show help" msgstr "" #: ../src/panelModules/panelSurfacesTools.c:2103 msgid "Source .pot file :" msgstr "" #: ../src/panelModules/panelSurfacesTools.c:2107 msgid "Target .surf file :" msgstr "" #: ../src/panelModules/panelSurfacesTools.c:2117 msgid "Pot min : " msgstr "" #: ../src/panelModules/panelSurfacesTools.c:2120 msgid "Pot max : " msgstr "" #: ../src/panelModules/panelSurfacesTools.c:2174 msgid "Merge" msgstr "" #: ../src/panelModules/panelSurfacesTools.c:2175 msgid "pot2surf" msgstr "" #: ../src/panelModules/panelSurfaces.c:666 msgid "Edit surface properties" msgstr "" #: ../src/panelModules/panelSurfaces.c:714 msgid "Shade" msgstr "" #: ../src/panelModules/panelSurfaces.c:716 msgid "Apply a shade to the current surfaces of the selected scalar field." msgstr "" #: ../src/panelModules/panelSurfaces.c:725 msgid "ToolShade: " msgstr "" #: ../src/panelModules/panelSurfaces.c:898 #, c-format msgid "" "%s\n" " no data" msgstr "" #: ../src/panelModules/panelSurfaces.c:904 #, c-format msgid "" "%s\n" " Den./pot. data (min|max)\n" " %g | %g" msgstr "" #: ../src/panelModules/panelSurfaces.c:1035 #, c-format msgid "" "%s\n" " Surfaces data" msgstr "" #: ../src/panelModules/panelSurfaces.c:1256 #: ../src/panelModules/panelSurfaces.c:1549 msgid "Play" msgstr "" #: ../src/panelModules/panelSurfaces.c:1268 msgid "Stop" msgstr "" #: ../src/panelModules/panelSurfaces.c:1386 msgid "File / label" msgstr "" #: ../src/panelModules/panelSurfaces.c:1409 msgid "Value" msgstr "" #: ../src/panelModules/panelSurfaces.c:1568 msgid "_Use isosurfaces" msgstr "" #: ../src/panelModules/panelSurfaces.c:1582 msgid "Auto _load data file" msgstr "" #: ../src/panelModules/panelSurfaces.c:1586 msgid "" "Try to load a data file whenever a new V_Sim file is loaded. If the new file " "contains a scalar field, it is loaded, otherwise a surface file is tested " "using a .surf extension on the file name." msgstr "" #: ../src/panelModules/panelSurfaces.c:1591 msgid "_Convert" msgstr "" #: ../src/panelModules/panelSurfaces.c:1592 msgid "Load a surface file or a potential/density file." msgstr "" #: ../src/panelModules/panelSurfaces.c:1596 msgid "Several built-in tools to create .surf files." msgstr "" #: ../src/panelModules/panelSurfaces.c:1606 msgid "_Reorder on the fly" msgstr "" #: ../src/panelModules/panelSurfaces.c:1642 msgid "Hides all surfaces" msgstr "" #: ../src/panelModules/panelSurfaces.c:1644 msgid "Shows all surfaces" msgstr "" #: ../src/panelModules/panelSurfaces.c:1648 msgid "Change color and material properties." msgstr "" #: ../src/panelModules/panelSurfaces.c:1655 msgid "Add a new surface." msgstr "" #: ../src/panelModules/panelSurfaces.c:1665 msgid "Add many surfaces to the list of surfaces." msgstr "" #: ../src/panelModules/panelSurfaces.c:1676 msgid "Remove selected surface or file." msgstr "" #: ../src/panelModules/panelSurfaces.c:1685 msgid "Starts/stops showing isosurfaces at specified rate" msgstr "" #: ../src/panelModules/panelSurfaces.c:1687 msgid "@" msgstr "" #: ../src/panelModules/panelSurfaces.c:1688 msgid "Selects rate to show isosurfaces" msgstr "" #: ../src/panelModules/panelSurfaces.c:1691 msgid "ms" msgstr "" #: ../src/panelModules/panelSurfaces.c:1694 msgid "Import iso-values from an existing XML file." msgstr "" #: ../src/panelModules/panelSurfaces.c:1695 msgid "Export iso-values to the current XML file." msgstr "" #: ../src/panelModules/panelSurfaces.c:1696 msgid "Export iso-values to a new XML file." msgstr "" #: ../src/panelModules/panelSurfaces.c:1707 msgid "Draw _intra surfaces" msgstr "" #: ../src/panelModules/panelSurfaces.c:1709 msgid "Draw the interior of iso-surfaces with the complementary colour." msgstr "" #: ../src/panelModules/panelSurfaces.c:1717 msgid "" "Automatically re-orders surfaces in back to front order whenever camera is " "modified (can be slow but get rid of transparency problems). This has no " "effect if the transparency option of the OpenGL panel is set" msgstr "" #: ../src/panelModules/panelSurfaces.c:2289 msgid "Comment:" msgstr "" #: ../src/panelModules/panelSurfaces.c:2454 msgid "Generate iso-values" msgstr "" #: ../src/panelModules/panelSurfaces.c:2457 msgid "Generate" msgstr "" #: ../src/panelModules/panelSurfaces.c:2483 msgid "Number of steps:" msgstr "" #: ../src/panelModules/panelSurfaces.c:2490 msgid "Delta of steps:" msgstr "" #: ../src/panelModules/panelSurfaces.c:2504 #: ../src/panelModules/panelFogBgColor.c:265 msgid "Start:" msgstr "" #: ../src/panelModules/panelSurfaces.c:2505 #: ../src/panelModules/panelFogBgColor.c:280 msgid "End:" msgstr "" #: ../src/panelModules/panelSurfaces.c:2508 msgid "Name (optional):" msgstr "" #: ../src/panelModules/panelDataFile.c:80 msgid "R" msgstr "" #: ../src/panelModules/panelDataFile.c:81 msgid "G" msgstr "" #: ../src/panelModules/panelDataFile.c:82 msgid "B" msgstr "" #: ../src/panelModules/panelDataFile.c:83 msgid "H" msgstr "" #: ../src/panelModules/panelDataFile.c:84 msgid "S" msgstr "" #: ../src/panelModules/panelDataFile.c:85 msgid "V" msgstr "" #: ../src/panelModules/panelDataFile.c:91 msgid "coord. x" msgstr "" #: ../src/panelModules/panelDataFile.c:92 msgid "coord. y" msgstr "" #: ../src/panelModules/panelDataFile.c:93 msgid "coord. z" msgstr "" #: ../src/panelModules/panelDataFile.c:103 msgid "No data file loaded" msgstr "" #: ../src/panelModules/panelDataFile.c:104 msgid "No data file" msgstr "" #: ../src/panelModules/panelDataFile.c:203 msgid "Colorize with data" msgstr "" #: ../src/panelModules/panelDataFile.c:204 msgid "Data color" msgstr "" #: ../src/panelModules/panelDataFile.c:298 msgid "_Use color scheme" msgstr "" #: ../src/panelModules/panelDataFile.c:323 msgid "_Auto load data" msgstr "" #: ../src/panelModules/panelDataFile.c:326 msgid "" "Try to load a data file whenever a new V_Sim file is loaded. For example, if " "'example.ascii' has just been opened, V_Sim will look for 'example.dat' and " "will apply it." msgstr "" #: ../src/panelModules/panelDataFile.c:338 msgid "Load data file" msgstr "" #: ../src/panelModules/panelDataFile.c:351 msgid "Choose a file to read the colorization data from." msgstr "" #: ../src/panelModules/panelDataFile.c:356 msgid "" "File extension used for the autoload option, its value is saved in the " "parameter file (see 'dataFile_fileExt')." msgstr "" #: ../src/panelModules/panelDataFile.c:365 msgid "Normalize input: " msgstr "" #: ../src/panelModules/panelDataFile.c:380 msgid "More information" msgstr "" #: ../src/panelModules/panelDataFile.c:401 msgid "Input data bounds:" msgstr "" #: ../src/panelModules/panelDataFile.c:434 msgid "Min:" msgstr "" #: ../src/panelModules/panelDataFile.c:438 msgid "Max:" msgstr "" #: ../src/panelModules/panelDataFile.c:442 msgid "Col.:" msgstr "" #. ********************* #. Transformation part #. ********************* #: ../src/panelModules/panelDataFile.c:453 msgid "Define the color scheme:" msgstr "" #: ../src/panelModules/panelDataFile.c:485 msgid "Color space: " msgstr "" #: ../src/panelModules/panelDataFile.c:490 msgid "RGB" msgstr "" #: ../src/panelModules/panelDataFile.c:495 msgid "HSV" msgstr "" #: ../src/panelModules/panelDataFile.c:592 msgid "Color range preview: " msgstr "" #: ../src/panelModules/panelDataFile.c:604 msgid "No preview available" msgstr "" #: ../src/panelModules/panelDataFile.c:612 msgid "Display the colour range." msgstr "" #. g_object_bind_property_full(visu_gl_node_scene_getColorization(scene), #. "single-param", checkLegend, "sensitive", #. G_BINDING_SYNC_CREATE, fromSingle, NULL, NULL, NULL); #. ********************* #. Post treatment part #. ********************* #: ../src/panelModules/panelDataFile.c:624 msgid "Post processing:" msgstr "" #: ../src/panelModules/panelDataFile.c:637 msgid "_Hide elements" msgstr "" #: ../src/panelModules/panelDataFile.c:641 msgid " whose value from" msgstr "" #: ../src/panelModules/panelDataFile.c:647 msgid "col. " msgstr "" #: ../src/panelModules/panelDataFile.c:655 msgid " is lower than " msgstr "" #: ../src/panelModules/panelDataFile.c:665 msgid "_Scale shape according to " msgstr "" #: ../src/panelModules/panelDataFile.c:677 msgid "_Restrict colourisation to values in range." msgstr "" #: ../src/panelModules/panelDataFile.c:692 msgid "Description of loaded data file." msgstr "" #: ../src/panelModules/panelDataFile.c:732 msgid "Data files" msgstr "" #: ../src/panelModules/panelDataFile.c:784 #, c-format msgid "" "Reading data file '%s' reports:\n" "\t%s" msgstr "" #: ../src/panelModules/panelDataFile.c:786 msgid "Loading a data file" msgstr "" #: ../src/panelModules/panelDataFile.c:817 #, c-format msgid "%s: %d column(s)" msgstr "" #: ../src/panelModules/panelDataFile.c:820 #, c-format msgid "%s: file error" msgstr "" #: ../src/panelModules/panelDataFile.c:830 #, c-format msgid "%d column(s)" msgstr "" #: ../src/panelModules/panelDataFile.c:1298 #, c-format msgid "Col. %d" msgstr "" #. label = gtk_label_new(_("Column number")); #. gtk_widget_set_name(label, "label_head"); #. gtk_table_attach(GTK_TABLE(table), label, 0, 1, 0, 1, GTK_SHRINK, GTK_SHRINK, 2, 0); #: ../src/panelModules/panelDataFile.c:1336 msgid "Min value" msgstr "" #: ../src/panelModules/panelDataFile.c:1340 msgid "Max value" msgstr "" #: ../src/panelModules/panelDataFile.c:1349 #, c-format msgid "Column %d" msgstr "" #. * #. * SECTION: panelPlanes #. * @short_description: The tab where planes are defined. #. * #. * It is possible to get the list of planes using #. * visu_ui_panel_planes_getModel(). One can also access to the list #. * store hosting the planes by calling visu_ui_panel_planes_getList(). #. #: ../src/panelModules/panelPlanes.c:72 msgid "none" msgstr "" #. Long description #: ../src/panelModules/panelPlanes.c:116 msgid "Drawing planes" msgstr "" #. Short description #: ../src/panelModules/panelPlanes.c:118 msgid "Planes" msgstr "" #: ../src/panelModules/panelPlanes.c:143 msgid "Import planes from an existing XML file." msgstr "" #: ../src/panelModules/panelPlanes.c:144 msgid "Export planes to the current XML file." msgstr "" #: ../src/panelModules/panelPlanes.c:145 msgid "Export planes to a new XML file." msgstr "" #: ../src/panelModules/panelPlanes.c:201 msgid "_Use planes" msgstr "" #: ../src/panelModules/panelPlanes.c:215 msgid "Simple tools" msgstr "" #: ../src/panelModules/panelPlanes.c:220 msgid "Advanced tools" msgstr "" #: ../src/panelModules/panelPlanes.c:223 msgid "Change selected plane distance" msgstr "" #: ../src/panelModules/panelPlanes.c:235 msgid "to: " msgstr "" #: ../src/panelModules/panelPlanes.c:241 msgid "step: " msgstr "" #: ../src/panelModules/panelPlanes.c:250 ../src/panelModules/panelBrowser.c:556 msgid "Play at " msgstr "" #. Units: milliseconds #: ../src/panelModules/panelPlanes.c:257 ../src/panelModules/panelBrowser.c:566 msgid " ms" msgstr "" #: ../src/panelModules/panelPlanes.c:262 msgid "Change the distance parameter of he selected file at the given rate." msgstr "" #: ../src/panelModules/panelVibration.c:112 #: ../src/panelModules/panelVibration.c:113 msgid "Phonons" msgstr "" #: ../src/panelModules/panelVibration.c:126 msgid "with _arrow" msgstr "" #: ../src/panelModules/panelVibration.c:129 msgid "use _fixed frequency" msgstr "" #: ../src/panelModules/panelVibration.c:196 msgid "Draw arrows on nodes that represent their displacements." msgstr "" #. make and add the second column to the view #: ../src/panelModules/panelVibration.c:225 msgid "q point" msgstr "" #. make and add the third column to the view #: ../src/panelModules/panelVibration.c:230 msgid "energy" msgstr "" #. the timer #: ../src/panelModules/panelVibration.c:252 msgid "Freq.: " msgstr "" #. the amplitude #: ../src/panelModules/panelVibration.c:258 msgid "Ampl.: " msgstr "" #: ../src/panelModules/panelVibration.c:267 msgid "Stop the nodes at their given positions." msgstr "" #: ../src/panelModules/panelVibration.c:275 msgid "Move the nodes according to their phonon vibration." msgstr "" #. reset button #: ../src/panelModules/panelVibration.c:281 msgid "Reset" msgstr "" #: ../src/panelModules/panelVibration.c:284 msgid "Reset the node positions to input file coordinates." msgstr "" #: ../src/panelModules/panelVibration.c:459 msgid "Vibration file reloading" msgstr "" #. * #. * SECTION:gtkSpin #. * @short_description: The gtk interface elements that can interfere #. * with renderingSpin parameters. #. * #. * This is the gtk interface for all #VisuDataSpin module #. * parameters. They are split in two parts. The first part is placed #. * under the config tab and allows the user to modify the "global #. * properties" of the renderingSpin module such as cone's axe #. * orientation, and color repartition. The second part is under the #. * element panel and allows to modify each element resource. Size of #. * the arrows, and their shape can be modified. #. #: ../src/panelModules/gtkSpin.c:80 msgid "Shape size and color properties:" msgstr "" #: ../src/panelModules/gtkSpin.c:81 msgid "Drawing policy for spins with null modulus:" msgstr "" #: ../src/panelModules/gtkSpin.c:134 msgid "x:" msgstr "" #: ../src/panelModules/gtkSpin.c:135 msgid "y:" msgstr "" #: ../src/panelModules/gtkSpin.c:136 msgid "z:" msgstr "" #: ../src/panelModules/gtkSpin.c:181 msgid "Set ortho." msgstr "" #: ../src/panelModules/gtkSpin.c:183 msgid "Set the cone orientation to be orthogonal to the screen." msgstr "" #: ../src/panelModules/gtkSpin.c:214 msgid "Rotate color wheel:" msgstr "" #: ../src/panelModules/gtkSpin.c:237 msgid "always" msgstr "" #: ../src/panelModules/gtkSpin.c:245 msgid "atomic" msgstr "" #: ../src/panelModules/gtkSpin.c:372 msgid "Color cone orientation:" msgstr "" #: ../src/panelModules/gtkSpin.c:382 msgid "Spin lenght is proportional to modulus: " msgstr "" #: ../src/panelModules/gtkSpin.c:390 msgid "per node type" msgstr "" #: ../src/panelModules/gtkSpin.c:396 msgid "globaly" msgstr "" #: ../src/panelModules/gtkSpin.c:408 msgid "Use atomic rendering in addition to spin: " msgstr "" #: ../src/panelModules/gtkSpin.c:426 msgid "Color distribution options:" msgstr "" #: ../src/panelModules/panelBrowser.c:213 #: ../src/panelModules/panelBrowser.c:214 msgid "Browser" msgstr "" #. This is a label in the browser panel to introduce the #. entry that allows to enter a filter for files shown. #: ../src/panelModules/panelBrowser.c:323 msgid "Filter: " msgstr "" #: ../src/panelModules/panelBrowser.c:331 msgid "atomic rendering" msgstr "" #: ../src/panelModules/panelBrowser.c:333 msgid "spin rendering" msgstr "" #: ../src/panelModules/panelBrowser.c:335 msgid "atomic part" msgstr "" #: ../src/panelModules/panelBrowser.c:337 msgid "spin part" msgstr "" #: ../src/panelModules/panelBrowser.c:353 msgid "Choose a different directory." msgstr "" #: ../src/panelModules/panelBrowser.c:360 msgid "Rescan current directory." msgstr "" #: ../src/panelModules/panelBrowser.c:369 msgid "Read directories recursively." msgstr "" #: ../src/panelModules/panelBrowser.c:395 msgid "Dir.:" msgstr "" #: ../src/panelModules/panelBrowser.c:427 msgid "Double click on a file to render it." msgstr "" #: ../src/panelModules/panelBrowser.c:442 msgid "File" msgstr "" #: ../src/panelModules/panelBrowser.c:460 msgid "Date" msgstr "" #: ../src/panelModules/panelBrowser.c:476 msgid "Unselect all files." msgstr "" #: ../src/panelModules/panelBrowser.c:482 msgid "Select all files." msgstr "" #: ../src/panelModules/panelBrowser.c:492 msgid "Export the rendering of all selected files in other formats." msgstr "" #: ../src/panelModules/panelBrowser.c:498 msgid "Render the next selected file." msgstr "" #: ../src/panelModules/panelBrowser.c:505 msgid "Render the previous selected file." msgstr "" #: ../src/panelModules/panelBrowser.c:512 msgid "Current dir.: " msgstr "" #: ../src/panelModules/panelBrowser.c:571 msgid "Cycle through the selected files at the given rate." msgstr "" #: ../src/panelModules/panelBrowser.c:902 #, c-format msgid "foo%02d.png" msgstr "" #: ../src/panelModules/panelBrowser.c:922 msgid "Dumping all selected files to images," msgstr "" #: ../src/panelModules/panelBrowser.c:923 #, c-format msgid "" " format '%s'.\n" "\n" msgstr "" #: ../src/panelModules/panelBrowser.c:932 #, c-format msgid "Error! The numbering pattern is wrong.\n" msgstr "" #: ../src/panelModules/panelBrowser.c:942 #, c-format msgid "Error! Only one '%s' character is allowed in the file name.\n" msgstr "" #: ../src/panelModules/panelBrowser.c:952 #, c-format msgid "Error! Missing pattern in the filename.\n" msgstr "" #: ../src/panelModules/panelBrowser.c:957 #, c-format msgid "" "\n" "Help : you must specify '%s' in the filename, where 'x' is a number [|1;9|]. " "This allows V_Sim to number the dumped files.\n" "\n" " For example, with a pattern like this : 'foo%s.pdf', dumped files will be " "named : foo00.pdf, foo01.pdf..." msgstr "" #: ../src/panelModules/panelBrowser.c:964 #: ../src/panelModules/panelBrowser.c:1024 msgid "Exporting files" msgstr "" #: ../src/panelModules/panelBrowser.c:998 #, c-format msgid "Write to file %d ..." msgstr "" #: ../src/panelModules/panelBrowser.c:1009 #, c-format msgid " error\n" msgstr "" #: ../src/panelModules/panelBrowser.c:1011 #, c-format msgid " OK\n" msgstr "" #: ../src/panelModules/panelBrowser.c:1055 msgid "Abortion request, please wait..." msgstr "" #: ../src/panelModules/panelBrowser.c:1360 msgid "" "Can't load this file through the browser because it requires to read several " "files. You should use the 'Open' button on the main panel and then use the " "browser to vary one kind of file at a time." msgstr "" #. We create the new ones. #: ../src/panelModules/panelBrowser.c:1422 #, c-format msgid "data set %s0%dd" msgstr "" #: ../src/panelModules/panelBrowser.c:1907 msgid "Browsing a directory" msgstr "" #: ../src/panelModules/panelBrowser.c:1908 msgid "The specified directory is unreadable." msgstr "" #: ../src/panelModules/panelBrowser.c:1971 msgid "%Y-%m-%d %H:%M" msgstr "" #: ../src/panelModules/panelBrowser.c:2076 #: ../src/panelModules/panelBrowser.c:2102 #, c-format msgid "%4d files found." msgstr "" #: ../src/panelModules/panelBrowser.c:2210 #, c-format msgid "%s" msgstr "" #: ../src/panelModules/panelMethod.c:85 msgid "Rendering method" msgstr "" #: ../src/panelModules/panelMethod.c:86 msgid "Draw" msgstr "" #: ../src/panelModules/panelMethod.c:120 msgid "Input method:" msgstr "" #: ../src/panelModules/panelMethod.c:138 msgid "Options:" msgstr "" #: ../src/panelModules/panelMethod.c:188 msgid "Spin visualisation" msgstr "" #: ../src/panelModules/panelMethod.c:191 msgid "It draws arrows at given positions to represent an atom and its spin." msgstr "" #: ../src/panelModules/panelMethod.c:199 msgid "Atom visualisation" msgstr "" #: ../src/panelModules/panelMethod.c:202 msgid "" "It draws spheres at specified positions to represent atoms. The radius of " "the sphere can vary." msgstr "" #: ../src/panelModules/panelFogBgColor.c:99 msgid "Fog and background color" msgstr "" #: ../src/panelModules/panelFogBgColor.c:100 msgid "Fog & bg" msgstr "" #: ../src/panelModules/panelFogBgColor.c:147 msgid "A:" msgstr "" #: ../src/panelModules/panelFogBgColor.c:178 msgid "Background:" msgstr "" #: ../src/panelModules/panelFogBgColor.c:197 msgid "Insert an image:" msgstr "" #: ../src/panelModules/panelFogBgColor.c:199 msgid "Choose a background image" msgstr "" #: ../src/panelModules/panelFogBgColor.c:233 msgid "Remove the background image." msgstr "" #: ../src/panelModules/panelFogBgColor.c:241 msgid "_follow camera" msgstr "" #: ../src/panelModules/panelFogBgColor.c:245 msgid "_display filename" msgstr "" #: ../src/panelModules/panelFogBgColor.c:253 msgid "Use fog:" msgstr "" #: ../src/panelModules/panelFogBgColor.c:300 msgid "background color" msgstr "" #: ../src/panelModules/panelFogBgColor.c:306 msgid "specific color" msgstr "" #: ../src/panelModules/panelFogBgColor.c:387 msgid "Load image file" msgstr "" #: ../src/panelModules/gtkAtomic.c:81 msgid "(No force data)" msgstr "" #: ../src/panelModules/gtkAtomic.c:86 #, c-format msgid "(max. force is %.4g)" msgstr "" #: ../src/panelModules/gtkAtomic.c:190 msgid "Display _forces (if available)" msgstr "" #: ../src/panelModules/gtkAtomic.c:197 msgid "Policy to scale arrows:" msgstr "" #: ../src/panelModules/gtkAtomic.c:204 msgid "automatic" msgstr "" #: ../src/openGLFunctions/renderingMode.c:84 msgid "Wireframe" msgstr "" #: ../src/openGLFunctions/renderingMode.c:85 msgid "Flat" msgstr "" #: ../src/openGLFunctions/renderingMode.c:86 msgid "Smooth" msgstr "" #: ../src/openGLFunctions/renderingMode.c:87 msgid "Smooth & edge" msgstr "" #: ../src/gtk_move.c:100 msgid "" "left-button\t\t\t\t: drag node(s) in the screen plane\n" "middle-button (wheel)\t\t: drag node(s) along specific axis\n" "shift-left-button\t\t\t: drag node(s) along x axis\n" "control-left-button\t\t\t: drag node(s) along y axis\n" "control-shift-left-button\t: drag node(s) along z axis\n" "right-button\t\t\t\t: switch to observe" msgstr "" #: ../src/gtk_move.c:111 msgid "(none)" msgstr "" #: ../src/gtk_move.c:176 #, c-format msgid "(node %d)" msgstr "" #: ../src/gtk_move.c:181 #, c-format msgid "(%d nodes)" msgstr "" #: ../src/gtk_move.c:264 msgid "Pick a node with the mouse" msgstr "" #: ../src/gtk_move.c:281 msgid "Suppress node (either picked one or selected ones)." msgstr "" #: ../src/gtk_move.c:342 msgid "Capture the perpendicular axis to the current view." msgstr "" #: ../src/gtk_move.c:351 msgid "Apply translation values to coordinates." msgstr "" #: ../src/gtk_move.c:360 msgid "Return coordinates to initial values." msgstr "" #: ../src/gtk_move.c:387 msgid "Add a new node." msgstr "" #: ../src/gtk_move.c:397 msgid "Duplicate nodes:" msgstr "" #: ../src/gtk_move.c:401 msgid "(the nodes listed in the pick tab)" msgstr "" #: ../src/gtk_move.c:410 msgid "du_plicate nodes as they are" msgstr "" #: ../src/gtk_move.c:414 msgid " or as new: " msgstr "" #: ../src/gtk_move.c:423 msgid "_duplicate" msgstr "" #: ../src/gtk_move.c:431 msgid "Change the basis set:" msgstr "" #: ../src/gtk_move.c:460 msgid "Select node by picking it on the rendering area." msgstr "" #: ../src/gtk_move.c:464 msgid "_Apply" msgstr "" #: ../src/gtk_move.c:872 msgid "The new basis set will be indirect." msgstr "" #: ../src/gtk_move.c:954 msgid "Cannot change the basis: given matrix is singular." msgstr "" #: ../src/gtk_pairs.c:85 msgid "" "Modifications, as color or wire width, are applied only to selected rows. " "Use to select more than one row at a time." msgstr "" #: ../src/gtk_pairs.c:86 msgid "No distance analysis" msgstr "" #: ../src/gtk_pairs.c:87 #, c-format msgid "• there are %.3f neighbours per '%s'" msgstr "" #: ../src/gtk_pairs.c:90 #, c-format msgid "• mean distance is %.3f" msgstr "" #: ../src/gtk_pairs.c:192 msgid "filter: " msgstr "" #: ../src/gtk_pairs.c:211 msgid "Parameters:" msgstr "" #: ../src/gtk_pairs.c:217 msgid "min:" msgstr "" #: ../src/gtk_pairs.c:225 msgid "max:" msgstr "" #: ../src/gtk_pairs.c:233 msgid "step size:" msgstr "" #: ../src/gtk_pairs.c:240 msgid "Measurement tools:" msgstr "" #: ../src/gtk_pairs.c:246 msgid "Range" msgstr "" #: ../src/gtk_pairs.c:286 msgid "_Highlight nodes in range" msgstr "" #: ../src/support.c:90 ../src/support.c:114 #, c-format msgid "Couldn't find pixmap file: %s" msgstr "" #. * #. * SECTION: gtk_about #. * @short_description: The about dialog with a readme, the copyright, #. * the author list, the plug-in list and the version notes. #. * #. * The about dialog window is activated when clicking on the V_Sim #. * icon on bottom right part of the command panel. It contains a #. * summary of V_Sim purpose and capabilities, the list of authors, the #. * list of loaded plug-ins, the list of changes since the previous #. * version, and the licence file. It displays also the version of #. * V_Sim and provide a link to the web site. #. #: ../src/gtk_about.c:69 msgid "licence.en.txt" msgstr "" #. Translate if there is a authors file in another language. #: ../src/gtk_about.c:71 msgid "authors" msgstr "" #. Translate if there is a readme file in another language. #: ../src/gtk_about.c:73 msgid "readme" msgstr "" #. Translate if there is a readme file in another language. #: ../src/gtk_about.c:75 msgid "ChangeLog.en" msgstr "" #: ../src/gtk_about.c:362 msgid "Description" msgstr "" #: ../src/gtk_about.c:461 msgid "" ":\n" "\n" msgstr "" #: ../src/gtk_about.c:483 msgid ": " msgstr "" #: ../lib/plug-ins/nanoquanta-netcdf/nq_basic.c:55 msgid "" "This plug-in introduces support for\n" "ETSF file format defined by the\n" "European network NANOQUANTA." msgstr "" #: ../lib/plug-ins/nanoquanta-netcdf/nq_basic.c:59 msgid "" "Caliste Damien:\n" " structure/density loading." msgstr "" #: ../lib/plug-ins/nanoquanta-netcdf/nq_basic.c:153 #, c-format msgid "Global attribute '%s' has a wrong length or type.\n" msgstr "" #: ../lib/plug-ins/nanoquanta-netcdf/nq_basic.c:176 #, c-format msgid "Variable 'file_format' should be 'ETSF Nanoquanta' but is '%s'.\n" msgstr "" #: ../lib/plug-ins/nanoquanta-netcdf/nq_basic.c:196 #, c-format msgid "Supported version are 1.2 and over but this file is only %f.\n" msgstr "" #: ../lib/plug-ins/nanoquanta-netcdf/nq_basic.c:245 #: ../lib/plug-ins/nanoquanta-netcdf/nq_basic.c:267 #, c-format msgid "Reading '%s': %s." msgstr "" #: ../lib/plug-ins/nanoquanta-netcdf/nq_basic.c:249 #: ../lib/plug-ins/nanoquanta-netcdf/nq_structure.c:162 #: ../lib/plug-ins/nanoquanta-netcdf/nq_structure.c:179 #: ../lib/plug-ins/nanoquanta-netcdf/nq_structure.c:208 #: ../lib/plug-ins/nanoquanta-netcdf/nq_structure.c:221 #, c-format msgid "Retrieve value for variable '%s': %s." msgstr "" #: ../lib/plug-ins/nanoquanta-netcdf/nq_basic.c:271 #: ../lib/plug-ins/nanoquanta-netcdf/nq_basic.c:278 #: ../lib/plug-ins/nanoquanta-netcdf/nq_basic.c:289 #, c-format msgid "Checking variable '%s': %s." msgstr "" #: ../lib/plug-ins/nanoquanta-netcdf/nq_basic.c:274 #, c-format msgid "Variable '%s' should be of type '%s'." msgstr "" #: ../lib/plug-ins/nanoquanta-netcdf/nq_basic.c:282 #, c-format msgid "Variable '%s' should be a %d dimension array." msgstr "" #: ../lib/plug-ins/nanoquanta-netcdf/nq_basic.c:298 #, c-format msgid "Checking dimension ID %d: %s." msgstr "" #: ../lib/plug-ins/nanoquanta-netcdf/nq_basic.c:305 #, c-format msgid "Variable '%s' is not consistent with declaration of dimensions." msgstr "" #: ../lib/plug-ins/nanoquanta-netcdf/nq_structure.c:27 msgid "ETSF file format" msgstr "" #: ../lib/plug-ins/nanoquanta-netcdf/nq_structure.c:194 #, c-format msgid "Error in indexing array '%s', index out of bounds." msgstr "" #: ../lib/plug-ins/nanoquanta-netcdf/nq_structure.c:235 #, c-format msgid "Wrong ETSF format, basis-set is degenerated.\n" msgstr "" #: ../lib/plug-ins/nanoquanta-netcdf/nq_density.c:68 msgid "Nanoquanta NETCDF format" msgstr "" #: ../lib/plug-ins/nanoquanta-netcdf/nq_density.c:73 msgid "spin channel (or -1 for all)" msgstr "" #: ../lib/plug-ins/nanoquanta-netcdf/nq_density.c:75 msgid "real or complex values (or -1 for all)" msgstr "" #: ../lib/plug-ins/nanoquanta-netcdf/nq_density.c:225 #, c-format msgid "Retrieve value for variable 'primitive_vectors': %s." msgstr "" #: ../lib/plug-ins/nanoquanta-netcdf/nq_density.c:234 #, c-format msgid "" "The variable 'primitive_vectors' is not well formed (the basis is not 3D)." msgstr "" #: ../lib/plug-ins/nanoquanta-netcdf/nq_density.c:271 #, c-format msgid "Retrieve value for variable 'density': %s." msgstr "" #: ../lib/plug-ins/nanoquanta-netcdf/nq_density.c:292 msgid "1, no spin information" msgstr "" #: ../lib/plug-ins/nanoquanta-netcdf/nq_density.c:295 msgid "1, spin-up ; 2, spin-down" msgstr "" #: ../lib/plug-ins/nanoquanta-netcdf/nq_density.c:298 msgid "1, average density ; [2;4], magnetisation vector" msgstr "" #: ../lib/plug-ins/nanoquanta-netcdf/nq_density.c:302 msgid "unknown value" msgstr "" #: ../lib/plug-ins/msym/msym.c:57 msgid "" "This plug-in introduces support for\n" "point group symmetry detection \n" "thanks to MSYM library (see \n" "http://github.com/mcodev31/libmsym)." msgstr "" #: ../lib/plug-ins/msym/msym.c:65 ../lib/plug-ins/abinit/ab_symmetry.c:61 msgid "" "left-button\t\t: select one atom to get the equivalent ones\n" "right-button\t\t: switch to observe" msgstr "" #: ../lib/plug-ins/msym/msym.c:88 #, c-format msgid "point group symmetry: %s" msgstr "" #: ../lib/plug-ins/msym/msym.c:190 msgid "Identity" msgstr "" #: ../lib/plug-ins/msym/msym.c:193 msgid "Rotation" msgstr "" #: ../lib/plug-ins/msym/msym.c:196 msgid "Rotation + reflexion" msgstr "" #: ../lib/plug-ins/msym/msym.c:199 msgid "Reflexion" msgstr "" #: ../lib/plug-ins/msym/msym.c:202 #, c-format msgid "Plane (%4.2f ; %4.2f ; %4.2f)" msgstr "" #: ../lib/plug-ins/msym/msym.c:214 msgid "Inversion" msgstr "" #: ../lib/plug-ins/msym/msym.c:233 #, c-format msgid "%d symmetries (%s)" msgstr "" #: ../lib/plug-ins/msym/msym.c:254 msgid "Geometry threshold:" msgstr "" #: ../lib/plug-ins/msym/msym.c:256 msgid "Angle threshold:" msgstr "" #: ../lib/plug-ins/archives/archives.c:54 msgid "" "This plug-in adds support for\n" "compressed input files\n" "(see http://code.google.com/p/libarchive/)." msgstr "" #: ../lib/plug-ins/archives/archives.c:101 msgid "Compressed file formats" msgstr "" #: ../lib/plug-ins/python-gi/pythongi.c:61 msgid "" "This plug-in allows to execute\n" "Python scripts using GObject\n" "introspection." msgstr "" #. Long description #: ../lib/plug-ins/python-gi/pythongi.c:165 msgid "Python scripting" msgstr "" #. Short description #: ../lib/plug-ins/python-gi/pythongi.c:167 msgid "Python" msgstr "" #: ../lib/plug-ins/python-gi/pythongi.c:254 msgid "Python scripts for V_Sim" msgstr "" #: ../lib/plug-ins/python-gi/pythongi.c:308 msgid "Scripts loaded on startup" msgstr "" #: ../lib/plug-ins/python-gi/pythongi.c:328 msgid "This list is saved with the parameter file." msgstr "" #: ../lib/plug-ins/python-gi/pythongi.c:366 msgid "Interactive scripting" msgstr "" #: ../lib/plug-ins/python-gi/pythongi.c:374 msgid "Load:" msgstr "" #: ../lib/plug-ins/python-gi/pythongi.c:377 #: ../lib/plug-ins/python-gi/pythongi.c:515 #: ../lib/plug-ins/python-gi/pythongi.c:541 msgid "Choose a Python script" msgstr "" #: ../lib/plug-ins/python-gi/pythongi.c:422 msgid "Clear Python output." msgstr "" #: ../lib/plug-ins/python-gi/pythongi.c:433 msgid "" "Get the current VisuData object as 'data' variable and the current " "VisuGlView as 'view'." msgstr "" #: ../lib/plug-ins/python-gi/pythongi.c:438 msgid "Python interactive command line" msgstr "" #: ../lib/plug-ins/python-gi/pythongi.c:487 msgid "Load a Python script" msgstr "" #: ../lib/plug-ins/python-gi/pythongi.c:496 #, c-format msgid "Load script \"%s\"\n" msgstr "" #: ../lib/plug-ins/python-gi/pythongi.c:516 msgid "Not a regular file." msgstr "" #: ../lib/plug-ins/xsf/xsf.c:58 msgid "" "This plug-in reads XSF input files\n" " (position, forces and densities)." msgstr "" #: ../lib/plug-ins/xsf/xsf.c:117 ../lib/plug-ins/xsf/xsf.c:560 msgid "XCrysDen Structure File format" msgstr "" #: ../lib/plug-ins/xsf/xsf.c:217 ../lib/plug-ins/xsf/xsf.c:226 #, c-format msgid "Wrong XSF format, '%s' flag has a wrong value.\n" msgstr "" #: ../lib/plug-ins/xsf/xsf.c:271 #, c-format msgid "Wrong XSF format, missing float values after tag '%s'.\n" msgstr "" #: ../lib/plug-ins/xsf/xsf.c:297 #, c-format msgid "Wrong XSF format, missing or wrong integer values after tag '%s'.\n" msgstr "" #: ../lib/plug-ins/xsf/xsf.c:314 #, c-format msgid "Wrong XSF format, can't read coordinates at line '%s'.\n" msgstr "" #: ../lib/plug-ins/xsf/xsf.c:326 #, c-format msgid "Wrong XSF format, can't read coordinates from '%s' (only %d read).\n" msgstr "" #: ../lib/plug-ins/xsf/xsf.c:407 #, c-format msgid "Wrong XSF format, '%s' tag already defined.\n" msgstr "" #: ../lib/plug-ins/xsf/xsf.c:429 #, c-format msgid "" "Wrong XSF format, primitive vectors found with free boundary conditions.\n" msgstr "" #: ../lib/plug-ins/xsf/xsf.c:459 #, c-format msgid "" "Wrong XSF format, primitive coordinates found with free boundary " "conditions.\n" msgstr "" #: ../lib/plug-ins/xsf/xsf.c:488 #, c-format msgid "" "Wrong XSF format, atom coordinates found with free boundary conditions.\n" msgstr "" #: ../lib/plug-ins/xsf/xsf.c:529 #, c-format msgid "Wrong XSF format, basis-set is degenerated.\n" msgstr "" #: ../lib/plug-ins/xsf/xsf_density.c:61 msgid "XCrysDen density file format" msgstr "" #: ../lib/plug-ins/xsf/xsf_density.c:98 #, c-format msgid "Wrong XSF format, unreadable float value %d for density.\n" msgstr "" #: ../lib/plug-ins/xsf/xsf_density.c:110 #, c-format msgid "Wrong XSF format, missing density lines.\n" msgstr "" #: ../lib/plug-ins/xsf/xsf_density.c:124 #, c-format msgid "" "Wrong XSF format, missing float values for density (%d read, %d awaited).\n" msgstr "" #: ../lib/plug-ins/xsf/xsf_density.c:159 #, c-format msgid "Wrong XSF format, missing or wrong mesh size after tag '%s'.\n" msgstr "" #: ../lib/plug-ins/xsf/xsf_density.c:171 #, c-format msgid "Wrong XSF format, missing or wrong translation definition." msgstr "" #: ../lib/plug-ins/abinit/abinit.c:72 msgid "" "This plug-in introduces support for\n" "crystallographic structures in\n" "ABINIT input files." msgstr "" #: ../lib/plug-ins/abinit/abinit.c:150 ../lib/plug-ins/abinit/abinit.c:783 msgid "ABINIT input file format" msgstr "" #: ../lib/plug-ins/abinit/abinit.c:723 #, c-format msgid "" "Abinit loader report error:\n" " basis-set is degenerated.\n" msgstr "" #: ../lib/plug-ins/abinit/ab_symmetry.c:127 msgid "Symmetries" msgstr "" #: ../lib/plug-ins/abinit/ab_symmetry.c:146 msgid "Analyse the symmetries" msgstr "" #: ../lib/plug-ins/abinit/ab_symmetry.c:151 msgid "Compute symmetries" msgstr "" #. A message for ABINIT. #: ../lib/plug-ins/abinit/ab_symmetry.c:173 msgid "" "The symmetry routines are provided by ABINIT (http://www.abinit.org)." msgstr "" #: ../lib/plug-ins/abinit/ab_symmetry.c:184 msgid "Space group:" msgstr "" #: ../lib/plug-ins/abinit/ab_symmetry.c:188 msgid "" "http://en.wikipedia.org/wiki/" "Space_group" msgstr "" #: ../lib/plug-ins/abinit/ab_symmetry.c:197 msgid "Crystal system:" msgstr "" #: ../lib/plug-ins/abinit/ab_symmetry.c:202 msgid "space group:" msgstr "" #: ../lib/plug-ins/abinit/ab_symmetry.c:208 msgid "" "Warning: the Bravais lattice determined from the " "primitive vectors is more symmetric than the real one obtained from " "coordinates (printed)." msgstr "" #: ../lib/plug-ins/abinit/ab_symmetry.c:213 msgid "List of symmetry operations:" msgstr "" #: ../lib/plug-ins/abinit/ab_symmetry.c:228 msgid "operation" msgstr "" #: ../lib/plug-ins/abinit/ab_symmetry.c:236 msgid "translation" msgstr "" #: ../lib/plug-ins/abinit/ab_symmetry.c:243 msgid "comment" msgstr "" #. The interface to choose one atom to select. #: ../lib/plug-ins/abinit/ab_symmetry.c:248 msgid "Equivalent atoms:" msgstr "" #: ../lib/plug-ins/abinit/ab_symmetry.c:255 msgid "Visualise the equivalent nodes of node:" msgstr "" #: ../lib/plug-ins/abinit/ab_symmetry.c:261 msgid " or pick directly." msgstr "" #: ../lib/plug-ins/abinit/ab_symmetry.c:615 msgid "not primitive" msgstr "" #: ../lib/plug-ins/abinit/ab_symmetry.c:641 msgid "ABINIT symmetry calculation" msgstr "" #: ../lib/plug-ins/abinit/ab_symmetry.c:668 msgid "Unknown symmetry" msgstr "" #: ../lib/plug-ins/fpcrystal/fpcrystal.cpp:18 msgid "a wrapper around CrystalFp." msgstr "" #: ../lib/plug-ins/fpcrystal/fpcrystal.cpp:20 #: ../lib/plug-ins/OpenBabel-wrapper/ob_basic.cpp:46 msgid "" "Caliste Damien:\n" " wrapper." msgstr "" #: ../lib/plug-ins/OpenBabel-wrapper/ob_basic.cpp:42 msgid "" "This plug-in wraps the OpenBabel\n" "library (visit the home page at URL\n" "http://www.openbabel.org)." msgstr "" #: ../lib/plug-ins/OpenBabel-wrapper/ob_basic.cpp:73 msgid "OpenBabel known formats" msgstr "" #: ../lib/plug-ins/OpenBabel-wrapper/ob_basic.cpp:76 msgid "Add implicit hydrogens" msgstr "" #. Declare the output using OpenBabel. #: ../lib/plug-ins/OpenBabel-wrapper/ob_basic.cpp:83 msgid "OpenBabel output formats" msgstr "" #: ../lib/plug-ins/OpenBabel-wrapper/ob_basic.cpp:140 #: ../lib/plug-ins/OpenBabel-wrapper/ob_basic.cpp:352 #, c-format msgid "'%s' doesn't match any file format." msgstr "" #: ../lib/plug-ins/OpenBabel-wrapper/ob_basic.cpp:147 #: ../lib/plug-ins/OpenBabel-wrapper/ob_basic.cpp:359 #, c-format msgid "format of '%s' is not a readable one." msgstr "" #: ../lib/plug-ins/OpenBabel-wrapper/ob_basic.cpp:171 #, c-format msgid "The given file doesn't match the format '%s'." msgstr "" #: ../lib/plug-ins/OpenBabel-wrapper/ob_basic.cpp:196 #, c-format msgid "Wrong OpenBabel format, basis-set is degenerated.\n" msgstr "" #: ../lib/plug-ins/OpenBabel-wrapper/ob_basic.cpp:279 msgid "Implicit H" msgstr "" #: ../lib/plug-ins/OpenBabel-wrapper/ob_basic.cpp:424 #, c-format msgid "Unable to write the file." msgstr "" #: ../lib/plug-ins/cube/cube.c:51 msgid "" "This plug-in reads Cube files (see \n" "http://local.wasp.uwa.edu.au/\n" "~pbourke/dataformats/cube/),\n" "both structural and and volumetric data." msgstr "" #. char *typeXV[] = {"*.XV", "*.STRUCT_OUT", (char*)0}; #. char *nameXV = "Siesta output format"; #. char *descrXV = _("Siesta geometric output format"); #: ../lib/plug-ins/cube/cube.c:101 ../lib/plug-ins/cube/cube.c:105 msgid "Gaussian structural/volumetric format" msgstr "" #: ../lib/plug-ins/cube/cube.c:169 ../lib/plug-ins/cube/cube.c:177 #, c-format msgid "Wrong Cube format, missing comment lines.\n" msgstr "" #: ../lib/plug-ins/cube/cube.c:195 #, c-format msgid "Wrong Cube format, missing the atom line.\n" msgstr "" #: ../lib/plug-ins/cube/cube.c:202 #, c-format msgid "Wrong Cube format, missing the number of atoms on the third line.\n" msgstr "" #: ../lib/plug-ins/cube/cube.c:221 #, c-format msgid "Wrong Cube format, missing the %d box line.\n" msgstr "" #: ../lib/plug-ins/cube/cube.c:229 #, c-format msgid "Wrong Cube format, missing float values for box definition.\n" msgstr "" #: ../lib/plug-ins/cube/cube.c:236 #, c-format msgid "Wrong Cube format, wrong mesh size in %c direction.\n" msgstr "" #: ../lib/plug-ins/cube/cube.c:272 #, c-format msgid "Wrong Cube format, missing line %d with coordinates.\n" msgstr "" #: ../lib/plug-ins/cube/cube.c:282 #, c-format msgid "Wrong Cube format, can't read coordinates.\n" msgstr "" #: ../lib/plug-ins/cube/cube.c:293 #, c-format msgid "" "Wrong Cube format, one atomic number is 0 or lower, or greater than 103, " "check your input file.\n" msgstr "" #: ../lib/plug-ins/cube/cube.c:339 #, c-format msgid "Wrong Cube format, missing density lines.\n" msgstr "" #: ../lib/plug-ins/cube/cube.c:350 #, c-format msgid "Wrong Cube format, unreadable float value %d for density.\n" msgstr "" #: ../lib/plug-ins/cube/cube.c:369 #, c-format msgid "" "Wrong Cube format, missing float values for density (%d read, %d awaited).\n" msgstr "" #: ../lib/plug-ins/cube/cube.c:474 #, c-format msgid "Wrong Cube format, basis-set is degenerated.\n" msgstr "" #: ../lib/plug-ins/bigdft/bigdft.c:69 msgid "" "This plug-in adds support for specific\n" "capabilities of BigDFT." msgstr "" #: ../lib/plug-ins/bigdft/bigdft.c:146 msgid "Wavefunction file from BigDFT" msgstr "" #: ../lib/plug-ins/bigdft/bigdft.c:150 msgid "BigDFT wavelet boxes" msgstr "" #: ../lib/plug-ins/bigdft/bigdft.c:153 msgid "Hgrid along x" msgstr "" #: ../lib/plug-ins/bigdft/bigdft.c:154 msgid "Hgrid along y" msgstr "" #: ../lib/plug-ins/bigdft/bigdft.c:155 msgid "Hgrid along z" msgstr "" #: ../lib/plug-ins/bigdft/bigdft.c:156 msgid "Coarse grid multiplier" msgstr "" #: ../lib/plug-ins/bigdft/bigdft.c:157 msgid "Fine grid multiplier" msgstr "" #: ../lib/plug-ins/bigdft/bigdft.c:158 msgid "Exchange-correlation functional code" msgstr "" #: ../lib/plug-ins/bigdft/bigdft.c:159 msgid "Number of processors for memory estimation" msgstr "" #: ../lib/plug-ins/bigdft/bigdft.c:207 msgid "BigDFT settings" msgstr "" #: ../lib/plug-ins/bigdft/bigdft.c:272 msgid "BigDFT specific parameters" msgstr "" #: ../lib/plug-ins/bigdft/bigdft.c:280 msgid "use BigDFT to load xyz and ASCII files" msgstr "" #: ../lib/plug-ins/bigdft/bigdft.c:289 msgid "hgrids:" msgstr "" #: ../lib/plug-ins/bigdft/bigdft.c:307 msgid "ixc:" msgstr "" #: ../lib/plug-ins/bigdft/bigdft.c:319 msgid "show _coarse grid" msgstr "" #: ../lib/plug-ins/bigdft/bigdft.c:328 ../lib/plug-ins/bigdft/bigdft.c:370 msgid "radius of ele." msgstr "" #: ../lib/plug-ins/bigdft/bigdft.c:360 msgid "show _fine grid" msgstr "" #: ../lib/plug-ins/bigdft/bigdft.c:412 msgid "Memory estimation" msgstr "" #: ../lib/plug-ins/bigdft/bigdft.c:415 msgid "Memory estimation for" msgstr "" #: ../lib/plug-ins/bigdft/bigdft.c:422 msgid "core(s)" msgstr "" #: ../lib/plug-ins/bigdft/bigdft.c:443 msgid "Running BigDFT" msgstr "" #: ../lib/plug-ins/bigdft/bigdft.c:558 #, c-format msgid "Can't read wavefunction %d from file '%s'." msgstr "" #. Add options to the field. #: ../lib/plug-ins/bigdft/bigdft.c:598 ../lib/plug-ins/bigdft/bigdft.c:720 msgid "orbital id" msgstr "" #: ../lib/plug-ins/bigdft/bigdft.c:601 ../lib/plug-ins/bigdft/bigdft.c:733 msgid "spin id" msgstr "" #: ../lib/plug-ins/bigdft/bigdft.c:609 ../lib/plug-ins/bigdft/bigdft.c:725 msgid "k-point id" msgstr "" #: ../lib/plug-ins/bigdft/bigdft.c:612 ../lib/plug-ins/bigdft/bigdft.c:745 msgid "real/imag or partial density" msgstr "" #: ../lib/plug-ins/bigdft/bigdft.c:655 msgid "Choose orbital:" msgstr "" #: ../lib/plug-ins/bigdft/bigdft.c:659 msgid "band id:" msgstr "" #: ../lib/plug-ins/bigdft/bigdft.c:670 msgid "spin:" msgstr "" #: ../lib/plug-ins/bigdft/bigdft.c:678 ../lib/plug-ins/bigdft/bigdft_run.c:260 msgid "up" msgstr "" #: ../lib/plug-ins/bigdft/bigdft.c:679 ../lib/plug-ins/bigdft/bigdft_run.c:274 msgid "down" msgstr "" #: ../lib/plug-ins/bigdft/bigdft.c:688 msgid "k-point:" msgstr "" #: ../lib/plug-ins/bigdft/bigdft.c:699 msgid "representation:" msgstr "" #: ../lib/plug-ins/bigdft/bigdft.c:703 ../lib/plug-ins/bigdft/bigdft_run.c:344 msgid "partial density" msgstr "" #: ../lib/plug-ins/bigdft/bigdft.c:704 ../lib/plug-ins/bigdft/bigdft_run.c:342 msgid "real part" msgstr "" #: ../lib/plug-ins/bigdft/bigdft.c:706 ../lib/plug-ins/bigdft/bigdft_run.c:343 msgid "imaginary part" msgstr "" #: ../lib/plug-ins/bigdft/bigdft.c:851 ../lib/plug-ins/bigdft/bigdft.c:858 #, c-format msgid "%d grid points" msgstr "" #: ../lib/plug-ins/bigdft/bigdft.c:853 ../lib/plug-ins/bigdft/bigdft.c:860 msgid "no grid" msgstr "" #: ../lib/plug-ins/bigdft/bigdft_run.c:217 msgid "Run locally" msgstr "" #: ../lib/plug-ins/bigdft/bigdft_run.c:221 msgid "Go go go..." msgstr "" #: ../lib/plug-ins/bigdft/bigdft_run.c:235 msgid "Rho / V:" msgstr "" #: ../lib/plug-ins/bigdft/bigdft_run.c:238 msgid "_Density" msgstr "" #: ../lib/plug-ins/bigdft/bigdft_run.c:242 msgid "V_ext" msgstr "" #: ../lib/plug-ins/bigdft/bigdft_run.c:247 msgid "V_hartr" msgstr "" #: ../lib/plug-ins/bigdft/bigdft_run.c:250 msgid "V_xc" msgstr "" #: ../lib/plug-ins/bigdft/bigdft_run.c:257 msgid "Wavefunctions:" msgstr "" #: ../lib/plug-ins/bigdft/bigdft_run.c:290 msgid "for k-point(s)" msgstr "" #: ../lib/plug-ins/bigdft/bigdft_run.c:334 msgid "retrieve selection" msgstr "" #: ../lib/plug-ins/bigdft/bigdft_run.c:339 msgid "Wfn. repr.:" msgstr "" #: ../lib/plug-ins/bigdft/bigdft_run.c:538 #, c-format msgid "" "partial density (iter: %d)\n" " ikpt: %d, iorb: %d" msgstr "" #: ../lib/plug-ins/bigdft/bigdft_run.c:541 #, c-format msgid "" "wavefunction (iter: %d)\n" " ikpt: %d, iorb: %d" msgstr "" #: ../lib/plug-ins/bigdft/bigdft_run.c:551 msgid "Retrieve wavefunction" msgstr "" #: ../lib/plug-ins/bigdft/bigdft_run.c:552 msgid "Wavefunction has no imaginary part" msgstr "" #: ../lib/plug-ins/bigdft/bigdft_run.c:576 msgid "external potential" msgstr "" #: ../lib/plug-ins/bigdft/bigdft_run.c:582 #, c-format msgid "electronic density (iter: %d)" msgstr "" #: ../lib/plug-ins/bigdft/bigdft_run.c:724 msgid "Energies in _Ht" msgstr "" #: ../lib/plug-ins/bigdft/bigdft_run.c:729 msgid "Energies in _eV" msgstr "" #: ../lib/plug-ins/bigdft/bigdft_run.c:1074 msgid "Running BigDFT on a host" msgstr "" #: ../lib/plug-ins/bigdft/bigdft_run.c:1122 #, c-format msgid "%s" msgstr "" #: ../lib/plug-ins/bigdft/bigdft_run.c:1180 msgid "Hamiltonian optimisation" msgstr "" #: ../lib/plug-ins/bigdft/bigdft_run.c:1182 msgid "Sub-space optimisation" msgstr "" #: ../lib/plug-ins/bigdft/bigdft_run.c:1184 msgid "Wfn iteration" msgstr "" #: ../lib/plug-ins/bigdft/bigdft_run.c:1189 msgid "Initial stage" msgstr "" #: ../lib/plug-ins/bigdft/bigdft_run.c:1213 #, c-format msgid "kpt %d (%3.3f,%3.3f,%3.3f - %3.3f)" msgstr "" #: ../lib/plug-ins/bigdft/bigdft_run.c:1224 #: ../lib/plug-ins/bigdft/bigdft_run.c:1232 #, c-format msgid "orb. %d" msgstr "" v_sim-3.8.0/rename.REMOVE_ME.sh000077500000000000000000000002511370110300500160060ustar00rootroot00000000000000#!/bin/bash for i in `find {src,lib,Documentation} -not -wholename \*\.svn\* -name \*.[ch]\* -exec grep -q "$1" {} \; -print` ; do sed -i "s;$1;$2;g" $i; echo $i; done v_sim-3.8.0/src/000077500000000000000000000000001370110300500134145ustar00rootroot00000000000000v_sim-3.8.0/src/Makefile.am000066400000000000000000000566741370110300500154720ustar00rootroot00000000000000## Process this file with automake to produce Makefile.in vpath %.xpm $(top_srcdir) EXTRA_DIST = glade/v_sim.glade glade/v_sim.gladep AM_CPPFLAGS = -D'LOCALE_DIR="$(datadir)/locale"' -D'DATA_DIR="$(v_simresourcesdir)"' -D'LEGAL_DIR="$(v_simlegaldir)"' -D'PIXMAPS_DIR="$(v_simpixmapsdir)"' -D'PLUGINS_DIR="$(v_simpluginsdir)"' -D'ICONS_DIR="$(datadir)/icons"' -I$(top_srcdir) $(GTKS_CFLAGS) $(GLU_CFLAGS) $(LIB_YAML_CFLAGS) lib_LTLIBRARIES = libv_sim-3.la bin_PROGRAMS = v_sim EXTRA_PROGRAMS = v_sim-test #noinst_LIBRARIES = libgui.a if OPENGL_BUILTIN_WIN32 GL_source = OSOpenGL/visu_WGL.c endif if OPENGL_BUILTIN_X11 GL_source = OSOpenGL/visu_GLX.c endif if OPENGL_GTKGLEXT GL_source = OSOpenGL/visu_GtkGlExt.c endif v_sim_sources = \ dumpModules/externalDumpModules.h \ dumpModules/fileDump.c dumpModules/fileDump.h\ dumpModules/glDump.c dumpModules/glDump.h\ dumpModules/dumpToTiff.c dumpModules/dumpToTiff.h\ dumpModules/dumpToGif.c dumpModules/dumpToGif.h\ dumpModules/dumpToPsAndPdf.c dumpModules/dumpToPsAndPdf.h \ dumpModules/dumpToAscii.c dumpModules/dumpToAscii.h \ dumpModules/dumpToSVG.c dumpModules/dumpToSVG.h \ dumpModules/dumpToXyz.c dumpModules/dumpToXyz.h \ dumpModules/dumpToYaml.c dumpModules/dumpToYaml.h \ dumpModules/dumpToABINIT.c dumpModules/dumpToABINIT.h \ dumpModules/dumpThroughGdkPixbuf.c dumpModules/dumpThroughGdkPixbuf.h \ extensions/iface_lined.c extensions/iface_lined.h\ extensions/nodes.c extensions/nodes.h\ extensions/box.c extensions/box.h\ extensions/box_legend.c extensions/box_legend.h\ extensions/axes.c extensions/axes.h\ extensions/fogAndBGColor.c extensions/fogAndBGColor.h \ extensions/scale.c extensions/scale.h \ extensions/infos.h extensions/infos.c \ extensions/legend.h extensions/legend.c \ extensions/rings.h extensions/rings.c \ extensions/marks.c extensions/marks.h \ extensions/pairs.c extensions/pairs.h \ extensions/shade.c extensions/shade.h \ extensions/frame.c extensions/frame.h \ extensions/node_vectors.c extensions/node_vectors.h \ extensions/vibrations.c extensions/vibrations.h \ extensions/planes.c extensions/planes.h \ extensions/surfs.c extensions/surfs.h \ extensions/maps.c extensions/maps.h \ extensions/mapset.c extensions/mapset.h \ extensions/paths.c extensions/paths.h \ extensions/forces.c extensions/forces.h \ extensions/geodiff.c extensions/geodiff.h \ $(GL_source) \ OSOpenGL/visu_openGL.h \ renderingBackend/visu_actionInterface.h \ coreTools/toolDbg.c coreTools/toolDbg.h \ coreTools/toolPool.c coreTools/toolPool.h \ coreTools/toolShade.c coreTools/toolShade.h \ coreTools/toolFileFormat.c coreTools/toolFileFormat.h \ coreTools/toolMatrix.c coreTools/toolMatrix.h \ coreTools/toolColor.c coreTools/toolColor.h \ coreTools/toolConfigFile.c coreTools/toolConfigFile.h \ coreTools/toolOptions.c coreTools/toolOptions.h \ coreTools/toolFortran.c coreTools/toolFortran.h \ coreTools/toolPhysic.c coreTools/toolPhysic.h \ coreTools/toolArray.c coreTools/toolArray.h \ coreTools/atoms_yaml.c coreTools/atoms_yaml.h \ coreTools/toolFiles.c coreTools/toolFiles.h \ pairsModeling/linkRenderer.c pairsModeling/linkRenderer.h \ pairsModeling/wire_renderer.c pairsModeling/wire_renderer.h \ pairsModeling/cylinder_renderer.c pairsModeling/cylinder_renderer.h \ pairsModeling/iface_wire.c pairsModeling/iface_wire.h \ pairsModeling/iface_cylinder.c pairsModeling/iface_cylinder.h \ pairsModeling/link.c pairsModeling/link.h \ loaders/atomic_ascii.c loaders/atomic_ascii.h \ loaders/atomic_d3.c loaders/atomic_d3.h \ loaders/atomic_xyz.c loaders/atomic_xyz.h \ loaders/atomic_yaml.c loaders/atomic_yaml.h \ renderingMethods/elementRenderer.c renderingMethods/elementRenderer.h \ renderingMethods/iface_nodeArrayRenderer.c renderingMethods/iface_nodeArrayRenderer.h\ renderingMethods/elementAtomic.c renderingMethods/elementAtomic.h\ renderingMethods/elementSpin.c renderingMethods/elementSpin.h\ renderingMethods/spinMethod.c renderingMethods/spinMethod.h\ openGLFunctions/light.c openGLFunctions/light.h \ openGLFunctions/renderingMode.c openGLFunctions/renderingMode.h \ openGLFunctions/text.c openGLFunctions/text.h \ openGLFunctions/view.c openGLFunctions/view.h \ openGLFunctions/interactive.c openGLFunctions/interactive.h \ openGLFunctions/objectList.c openGLFunctions/objectList.h \ extraFunctions/colorizer.c extraFunctions/colorizer.h\ extraFunctions/dataFile.c extraFunctions/dataFile.h\ extraFunctions/fragColorizer.c extraFunctions/fragColorizer.h\ extraFunctions/vectColorizer.c extraFunctions/vectColorizer.h\ extraFunctions/shadedColorizer.c extraFunctions/shadedColorizer.h\ extraFunctions/plane.c extraFunctions/plane.h\ extraFunctions/planeset.c extraFunctions/planeset.h\ extraFunctions/pot2surf.c extraFunctions/pot2surf.h\ extraFunctions/surfaces_resources.c extraFunctions/surfaces_resources.h \ extraFunctions/surfaces_points.c extraFunctions/surfaces_points.h \ extraFunctions/surfaces.c extraFunctions/surfaces.h \ extraFunctions/nodeProp.c extraFunctions/nodeProp.h \ extraFunctions/stringProp.c extraFunctions/stringProp.h \ extraFunctions/floatProp.c extraFunctions/floatProp.h \ extraFunctions/coordProp.c extraFunctions/coordProp.h \ extraFunctions/typeProp.c extraFunctions/typeProp.h \ extraFunctions/idProp.c extraFunctions/idProp.h \ extraFunctions/vectorProp.c extraFunctions/vectorProp.h \ extraFunctions/fragProp.c extraFunctions/fragProp.h \ extraFunctions/shellProp.c extraFunctions/shellProp.h \ extraFunctions/poleProp.c extraFunctions/poleProp.h \ extraFunctions/iface_sourceable.c extraFunctions/iface_sourceable.h \ extraFunctions/scalarFields.c extraFunctions/scalarFields.h \ extraFunctions/scalarFieldSet.c extraFunctions/scalarFieldSet.h \ extraFunctions/sfielddata.c extraFunctions/sfielddata.h \ extraFunctions/sfieldbinary.c extraFunctions/sfieldbinary.h \ extraFunctions/map.c extraFunctions/map.h \ extraFunctions/isoline.c extraFunctions/isoline.h \ extraFunctions/geometry.c extraFunctions/geometry.h \ extraFunctions/vibration.c extraFunctions/vibration.h \ extraFunctions/finder.c extraFunctions/finder.h \ extraFunctions/mover.c extraFunctions/mover.h \ extraFunctions/rotate.c extraFunctions/rotate.h \ extraFunctions/translate.c extraFunctions/translate.h \ extraFunctions/neighbours.c extraFunctions/neighbours.h \ extraFunctions/gdiff.c extraFunctions/gdiff.h \ extraFunctions/nodeList.c extraFunctions/nodeList.h \ iface_boxed.c iface_boxed.h\ iface_pointset.c iface_pointset.h\ iface_maskable.c iface_maskable.h\ iface_nodemasker.c iface_nodemasker.h\ iface_animatable.c iface_animatable.h\ visu_tools.c visu_tools.h\ visu_animation.c visu_animation.h\ visu_configFile.c visu_configFile.h \ visu_extension.c visu_extension.h\ visu_extset.c visu_extset.h\ visu_glnodescene.c visu_glnodescene.h\ visu_elements.c visu_elements.h \ visu_nodes.c visu_nodes.h \ visu_box.c visu_box.h\ visu_data.c visu_data.h\ visu_dataloadable.c visu_dataloadable.h\ visu_dataatomic.c visu_dataatomic.h\ visu_dataspin.c visu_dataspin.h\ visu_dataloader.c visu_dataloader.h\ visu_commandLine.c visu_commandLine.h\ visu_basic.c visu_basic.h\ visu_plugins.c visu_plugins.h \ visu_dump.c visu_dump.h\ opengl.c opengl.h\ visu_pairs.c visu_pairs.h \ visu_pairset.c visu_pairset.h \ extraGtkFunctions/gtk_dumpDialogWidget.c extraGtkFunctions/gtk_dumpDialogWidget.h \ uiElements/ui_elements.c uiElements/ui_elements.h \ uiElements/ui_atomic.c uiElements/ui_atomic.h \ uiElements/ui_spin.c uiElements/ui_spin.h \ uiElements/ui_axes.c uiElements/ui_axes.h \ uiElements/ui_box.c uiElements/ui_box.h \ uiElements/ui_scale.c uiElements/ui_scale.h \ uiElements/ui_boxTransform.c uiElements/ui_boxTransform.h \ uiElements/ui_planetree.c uiElements/ui_planetree.h \ uiElements/ui_link.c uiElements/ui_link.h \ uiElements/ui_pairtree.c uiElements/ui_pairtree.h \ uiElements/ui_selection.c uiElements/ui_selection.h \ uiElements/ui_properties.c uiElements/ui_properties.h \ renderingBackend/visu_action_gdk.c \ gtk_renderingWindowWidget.c gtk_renderingWindowWidget.h\ gtk_openGLWidget.c gtk_openGLWidget.h \ visu_gtk.c visu_gtk.h interface_sources = \ panelModules/externalModules.h \ panelModules/panelElements.c panelModules/panelElements.h\ panelModules/gtkAtomic.c panelModules/gtkAtomic.h\ panelModules/gtkSpin.c panelModules/gtkSpin.h\ panelModules/panelConfig.c panelModules/panelConfig.h\ panelModules/panelOpenGL.c panelModules/panelOpenGL.h\ panelModules/panelGeometry.c panelModules/panelGeometry.h\ panelModules/panelAxes.c panelModules/panelAxes.h\ panelModules/panelFogBgColor.c panelModules/panelFogBgColor.h\ panelModules/panelBrowser.c panelModules/panelBrowser.h\ panelModules/panelDataFile.c panelModules/panelDataFile.h \ panelModules/panelPlanes.c panelModules/panelPlanes.h\ panelModules/panelSurfaces.c panelModules/panelSurfaces.h\ panelModules/panelSurfacesTools.c panelModules/panelSurfacesTools.h \ panelModules/panelMethod.c panelModules/panelMethod.h \ panelModules/panelMap.c panelModules/panelMap.h \ panelModules/panelVibration.c panelModules/panelVibration.h \ extraGtkFunctions/gtk_colorComboBoxWidget.c extraGtkFunctions/gtk_colorComboBoxWidget.h \ extraGtkFunctions/gtk_toolPanelWidget.c extraGtkFunctions/gtk_toolPanelWidget.h \ extraGtkFunctions/gtk_orientationChooser.c extraGtkFunctions/gtk_orientationChooser.h \ extraGtkFunctions/gtk_numericalEntryWidget.c extraGtkFunctions/gtk_numericalEntryWidget.h \ extraGtkFunctions/gtk_shadeComboBoxWidget.c extraGtkFunctions/gtk_shadeComboBoxWidget.h \ extraGtkFunctions/gtk_elementComboBox.c extraGtkFunctions/gtk_elementComboBox.h \ extraGtkFunctions/gtk_stippleComboBoxWidget.c extraGtkFunctions/gtk_stippleComboBoxWidget.h \ extraGtkFunctions/gtk_lineObjectWidget.c extraGtkFunctions/gtk_lineObjectWidget.h \ extraGtkFunctions/gtk_valueIOWidget.c extraGtkFunctions/gtk_valueIOWidget.h \ extraGtkFunctions/gtk_curveWidget.c extraGtkFunctions/gtk_curveWidget.h \ extraGtkFunctions/gtk_fieldChooser.c extraGtkFunctions/gtk_fieldChooser.h \ extraGtkFunctions/gtk_dataChooser.c extraGtkFunctions/gtk_dataChooser.h \ gtk_main.c gtk_main.h \ gtk_about.c gtk_about.h\ gtk_save.c gtk_save.h \ support.c support.h\ interface.c interface.h \ gtk_interactive.c gtk_interactive.h \ gtk_pick.c gtk_pick.h \ gtk_move.c gtk_move.h \ gtk_pairs.c gtk_pairs.h libv_sim_3_la_SOURCES = $(v_sim_sources) $(interface_sources) libv_sim_3_la_LDFLAGS = @EXTRA_LDFLAGS@ -version-info $(lib_v_sim_version) #libgui_a_SOURCES = $(interface_sources) v_sim_SOURCES = visu_main.c v_sim_LDADD = libv_sim-3.la v_sim_LDFLAGS = @EXTRA_LDFLAGS@ v_sim_test_SOURCES = visu_test.c v_sim_test_LDADD = libv_sim-3.la v_sim_test_LDFLAGS = @EXTRA_LDFLAGS@ AM_CFLAGS = @EXTRA_CFLAGS@ @GOBJECT_INTROSPECTION_CFLAGS@ @LIB_ARCHIVE_CFLAGS@ LIBS += @GTKS_LIBS@ @FTGL_LIBS@ @GLU_LIBS@ @EXTRA_LIBS@ @GOBJECT_INTROSPECTION_LIBS@ @LIB_YAML_LIBS@ @LIB_ARCHIVE_LIBS@ #check_PROGRAMS = test_surfaces #test_surfaces_SOURCES = extraFunctions/surfaces_tests.c #test_surfaces_LDADD = $(links) #test_surfaces_LDFLAGS = #TESTS = test_surfaces # ------------------- introspection ------------------- if WITH_GOBJECT_INTROSPECTION BUILT_GIRSOURCES = v_sim-$(V_SIM_MAJOR_VERSION).$(V_SIM_MINOR_VERSION).gir v_simgir_DATA = $(BUILT_GIRSOURCES) v_simtypelibs_DATA = $(BUILT_GIRSOURCES:.gir=.typelib) USE_EXTERNAL = --libtool=$(top_builddir)/libtool --library libv_sim-3.la $(v_simgir_DATA): $(G_IR_SCANNER) v_sim $(G_IR_SCANNER) -v --warn-all \ --namespace v_sim \ --symbol-prefix=visu --identifier-prefix=Visu \ --symbol-prefix=tool --identifier-prefix=Tool \ --nsversion "$(V_SIM_MAJOR_VERSION).$(V_SIM_MINOR_VERSION)" \ --add-include-path=$(girdir) \ --include GObject-2.0 \ --include GLib-2.0 \ --include GModule-2.0 \ --include cairo-1.0 \ --include xlib-2.0 \ --include GL-1.0 \ --include Gtk-3.0 \ --output=$(v_simgir_DATA) $(USE_EXTERNAL) \ -I$(srcdir) -I$(top_builddir) $(GTKS_CFLAGS) \ $(srcdir)/OSOpenGL/visu_openGL.h \ $(srcdir)/OSOpenGL/visu_GLX.c \ $(srcdir)/renderingBackend/visu_actionInterface.h \ $(srcdir)/coreTools/toolDbg.h $(srcdir)/coreTools/toolDbg.c \ $(srcdir)/coreTools/toolPool.h $(srcdir)/coreTools/toolPool.c \ $(srcdir)/coreTools/toolOptions.h $(srcdir)/coreTools/toolOptions.c \ $(srcdir)/coreTools/toolColor.h $(srcdir)/coreTools/toolColor.c \ $(srcdir)/coreTools/toolShade.h $(srcdir)/coreTools/toolShade.c \ $(srcdir)/coreTools/toolMatrix.h $(srcdir)/coreTools/toolMatrix.c \ $(srcdir)/coreTools/toolPhysic.h $(srcdir)/coreTools/toolPhysic.c \ $(srcdir)/coreTools/toolFileFormat.h $(srcdir)/coreTools/toolFileFormat.c \ $(srcdir)/coreTools/toolFortran.h $(srcdir)/coreTools/toolFortran.c \ $(srcdir)/coreTools/toolArray.h $(srcdir)/coreTools/toolArray.c \ $(srcdir)/coreTools/toolFiles.h $(srcdir)/coreTools/toolFiles.c \ $(srcdir)/extensions/iface_lined.h $(srcdir)/extensions/iface_lined.c \ $(srcdir)/extensions/nodes.h $(srcdir)/extensions/nodes.c \ $(srcdir)/extensions/infos.h $(srcdir)/extensions/infos.c \ $(srcdir)/extensions/marks.h $(srcdir)/extensions/marks.c \ $(srcdir)/extensions/axes.h $(srcdir)/extensions/axes.c \ $(srcdir)/extensions/box.h $(srcdir)/extensions/box.c \ $(srcdir)/extensions/box_legend.h $(srcdir)/extensions/box_legend.c \ $(srcdir)/extensions/legend.h $(srcdir)/extensions/legend.c \ $(srcdir)/extensions/pairs.h $(srcdir)/extensions/pairs.c \ $(srcdir)/extensions/shade.h $(srcdir)/extensions/shade.c \ $(srcdir)/extensions/frame.h $(srcdir)/extensions/frame.c \ $(srcdir)/extensions/planes.h $(srcdir)/extensions/planes.c \ $(srcdir)/extensions/node_vectors.h $(srcdir)/extensions/node_vectors.c \ $(srcdir)/extensions/vibrations.h $(srcdir)/extensions/vibrations.c \ $(srcdir)/extensions/fogAndBGColor.h $(srcdir)/extensions/fogAndBGColor.c \ $(srcdir)/extensions/scale.h $(srcdir)/extensions/scale.c \ $(srcdir)/extensions/surfs.h $(srcdir)/extensions/surfs.c \ $(srcdir)/extensions/maps.h $(srcdir)/extensions/maps.c \ $(srcdir)/extensions/mapset.h $(srcdir)/extensions/mapset.c \ $(srcdir)/extensions/paths.h $(srcdir)/extensions/paths.c \ $(srcdir)/extensions/forces.h $(srcdir)/extensions/forces.c \ $(srcdir)/extensions/geodiff.h $(srcdir)/extensions/geodiff.c \ $(srcdir)/extraFunctions/surfaces_points.h $(srcdir)/extraFunctions/surfaces_points.c \ $(srcdir)/extraFunctions/surfaces_resources.h $(srcdir)/extraFunctions/surfaces_resources.c \ $(srcdir)/extraFunctions/surfaces.h $(srcdir)/extraFunctions/surfaces.c \ $(srcdir)/extraFunctions/pot2surf.h $(srcdir)/extraFunctions/pot2surf.c \ $(srcdir)/extraFunctions/plane.h $(srcdir)/extraFunctions/plane.c \ $(srcdir)/extraFunctions/planeset.h $(srcdir)/extraFunctions/planeset.c \ $(srcdir)/extraFunctions/colorizer.h $(srcdir)/extraFunctions/colorizer.c \ $(srcdir)/extraFunctions/dataFile.h $(srcdir)/extraFunctions/dataFile.c \ $(srcdir)/extraFunctions/fragColorizer.h $(srcdir)/extraFunctions/fragColorizer.c \ $(srcdir)/extraFunctions/vectColorizer.h $(srcdir)/extraFunctions/vectColorizer.c \ $(srcdir)/extraFunctions/shadedColorizer.h $(srcdir)/extraFunctions/shadedColorizer.c \ $(srcdir)/extraFunctions/geometry.h $(srcdir)/extraFunctions/geometry.c \ $(srcdir)/extraFunctions/isoline.h $(srcdir)/extraFunctions/isoline.c \ $(srcdir)/extraFunctions/map.h $(srcdir)/extraFunctions/map.c \ $(srcdir)/extraFunctions/vibration.h $(srcdir)/extraFunctions/vibration.c \ $(srcdir)/extraFunctions/scalarFields.h $(srcdir)/extraFunctions/scalarFields.c \ $(srcdir)/extraFunctions/scalarFieldSet.h $(srcdir)/extraFunctions/scalarFieldSet.c \ $(srcdir)/extraFunctions/sfielddata.h $(srcdir)/extraFunctions/sfielddata.c \ $(srcdir)/extraFunctions/sfieldbinary.h $(srcdir)/extraFunctions/sfieldbinary.c \ $(srcdir)/extraFunctions/nodeProp.h $(srcdir)/extraFunctions/nodeProp.c \ $(srcdir)/extraFunctions/stringProp.h $(srcdir)/extraFunctions/stringProp.c \ $(srcdir)/extraFunctions/floatProp.h $(srcdir)/extraFunctions/floatProp.c \ $(srcdir)/extraFunctions/coordProp.h $(srcdir)/extraFunctions/coordProp.c \ $(srcdir)/extraFunctions/typeProp.h $(srcdir)/extraFunctions/typeProp.c \ $(srcdir)/extraFunctions/idProp.h $(srcdir)/extraFunctions/idProp.c \ $(srcdir)/extraFunctions/vectorProp.h $(srcdir)/extraFunctions/vectorProp.c \ $(srcdir)/extraFunctions/fragProp.h $(srcdir)/extraFunctions/fragProp.c \ $(srcdir)/extraFunctions/shellProp.h $(srcdir)/extraFunctions/shellProp.c \ $(srcdir)/extraFunctions/poleProp.h $(srcdir)/extraFunctions/poleProp.c \ $(srcdir)/extraFunctions/iface_sourceable.h $(srcdir)/extraFunctions/iface_sourceable.c \ $(srcdir)/extraFunctions/finder.h $(srcdir)/extraFunctions/finder.c \ $(srcdir)/extraFunctions/mover.h $(srcdir)/extraFunctions/mover.c \ $(srcdir)/extraFunctions/rotate.h $(srcdir)/extraFunctions/rotate.c \ $(srcdir)/extraFunctions/translate.h $(srcdir)/extraFunctions/translate.c \ $(srcdir)/extraFunctions/neighbours.h $(srcdir)/extraFunctions/neighbours.c \ $(srcdir)/extraFunctions/gdiff.h $(srcdir)/extraFunctions/gdiff.c \ $(srcdir)/extraFunctions/nodeList.h $(srcdir)/extraFunctions/nodeList.c \ $(srcdir)/openGLFunctions/renderingMode.h $(srcdir)/openGLFunctions/renderingMode.c \ $(srcdir)/openGLFunctions/light.c $(srcdir)/openGLFunctions/light.h \ $(srcdir)/openGLFunctions/text.c $(srcdir)/openGLFunctions/text.h \ $(srcdir)/openGLFunctions/objectList.c $(srcdir)/openGLFunctions/objectList.h \ $(srcdir)/openGLFunctions/interactive.c $(srcdir)/openGLFunctions/interactive.h \ $(srcdir)/openGLFunctions/view.c $(srcdir)/openGLFunctions/view.h \ $(srcdir)/loaders/atomic_ascii.h $(srcdir)/loaders/atomic_ascii.c \ $(srcdir)/loaders/atomic_d3.h $(srcdir)/loaders/atomic_d3.c \ $(srcdir)/loaders/atomic_xyz.h $(srcdir)/loaders/atomic_xyz.c \ $(srcdir)/loaders/atomic_yaml.h $(srcdir)/loaders/atomic_yaml.c \ $(srcdir)/renderingMethods/elementRenderer.h $(srcdir)/renderingMethods/elementRenderer.c\ $(srcdir)/renderingMethods/iface_nodeArrayRenderer.h $(srcdir)/renderingMethods/iface_nodeArrayRenderer.c\ $(srcdir)/renderingMethods/elementAtomic.h $(srcdir)/renderingMethods/elementAtomic.c\ $(srcdir)/renderingMethods/elementSpin.h $(srcdir)/renderingMethods/elementSpin.c\ $(srcdir)/renderingMethods/spinMethod.h $(srcdir)/renderingMethods/spinMethod.c\ $(srcdir)/dumpModules/fileDump.c $(srcdir)/dumpModules/fileDump.h \ $(srcdir)/dumpModules/glDump.c $(srcdir)/dumpModules/glDump.h \ $(srcdir)/dumpModules/dumpToAscii.c $(srcdir)/dumpModules/dumpToAscii.h \ $(srcdir)/dumpModules/dumpThroughGdkPixbuf.c $(srcdir)/dumpModules/dumpThroughGdkPixbuf.h \ $(srcdir)/dumpModules/dumpToTiff.c $(srcdir)/dumpModules/dumpToTiff.h \ $(srcdir)/dumpModules/dumpToSVG.c $(srcdir)/dumpModules/dumpToSVG.h \ $(srcdir)/dumpModules/dumpToXyz.c $(srcdir)/dumpModules/dumpToXyz.h \ $(srcdir)/dumpModules/dumpToYaml.c $(srcdir)/dumpModules/dumpToYaml.h \ $(srcdir)/dumpModules/dumpToABINIT.c $(srcdir)/dumpModules/dumpToABINIT.h \ $(srcdir)/dumpModules/dumpToPsAndPdf.c $(srcdir)/dumpModules/dumpToPsAndPdf.h \ $(srcdir)/pairsModeling/link.c $(srcdir)/pairsModeling/link.h \ $(srcdir)/pairsModeling/linkRenderer.c $(srcdir)/pairsModeling/linkRenderer.h \ $(srcdir)/pairsModeling/wire_renderer.c $(srcdir)/pairsModeling/wire_renderer.h \ $(srcdir)/pairsModeling/cylinder_renderer.c $(srcdir)/pairsModeling/cylinder_renderer.h \ $(srcdir)/pairsModeling/iface_wire.c $(srcdir)/pairsModeling/iface_wire.h \ $(srcdir)/pairsModeling/iface_cylinder.c $(srcdir)/pairsModeling/iface_cylinder.h \ $(srcdir)/iface_boxed.h $(srcdir)/iface_boxed.c \ $(srcdir)/iface_pointset.h $(srcdir)/iface_pointset.c \ $(srcdir)/iface_maskable.h $(srcdir)/iface_maskable.c \ $(srcdir)/iface_nodemasker.h $(srcdir)/iface_nodemasker.c \ $(srcdir)/iface_animatable.h $(srcdir)/iface_animatable.c \ $(srcdir)/visu_configFile.h $(srcdir)/visu_configFile.c \ $(srcdir)/visu_basic.h $(srcdir)/visu_basic.c \ $(srcdir)/visu_extension.h $(srcdir)/visu_extension.c \ $(srcdir)/visu_extset.h $(srcdir)/visu_extset.c \ $(srcdir)/visu_glnodescene.h $(srcdir)/visu_glnodescene.c \ $(srcdir)/visu_dump.h $(srcdir)/visu_dump.c \ $(srcdir)/visu_pairs.h $(srcdir)/visu_pairs.c \ $(srcdir)/visu_pairset.h $(srcdir)/visu_pairset.c \ $(srcdir)/visu_plugins.h $(srcdir)/visu_plugins.c \ $(srcdir)/visu_tools.h $(srcdir)/visu_tools.c \ $(srcdir)/visu_animation.h $(srcdir)/visu_animation.c \ $(srcdir)/visu_elements.c $(srcdir)/visu_elements.h \ $(srcdir)/visu_nodes.c $(srcdir)/visu_nodes.h \ $(srcdir)/visu_box.c $(srcdir)/visu_box.h \ $(srcdir)/visu_data.c $(srcdir)/visu_data.h \ $(srcdir)/visu_dataloadable.c $(srcdir)/visu_dataloadable.h \ $(srcdir)/visu_dataatomic.c $(srcdir)/visu_dataatomic.h \ $(srcdir)/visu_dataspin.c $(srcdir)/visu_dataspin.h \ $(srcdir)/visu_dataloader.c $(srcdir)/visu_dataloader.h \ $(srcdir)/opengl.c $(srcdir)/opengl.h \ $(srcdir)/extraGtkFunctions/gtk_dumpDialogWidget.h $(srcdir)/extraGtkFunctions/gtk_dumpDialogWidget.c \ $(srcdir)/extraGtkFunctions/gtk_toolPanelWidget.h $(srcdir)/extraGtkFunctions/gtk_toolPanelWidget.c \ $(srcdir)/extraGtkFunctions/gtk_numericalEntryWidget.h $(srcdir)/extraGtkFunctions/gtk_numericalEntryWidget.c \ $(srcdir)/extraGtkFunctions/gtk_colorComboBoxWidget.h $(srcdir)/extraGtkFunctions/gtk_colorComboBoxWidget.c \ $(srcdir)/extraGtkFunctions/gtk_elementComboBox.h $(srcdir)/extraGtkFunctions/gtk_elementComboBox.c \ $(srcdir)/extraGtkFunctions/gtk_lineObjectWidget.h $(srcdir)/extraGtkFunctions/gtk_lineObjectWidget.c \ $(srcdir)/extraGtkFunctions/gtk_fieldChooser.h $(srcdir)/extraGtkFunctions/gtk_fieldChooser.c \ $(srcdir)/extraGtkFunctions/gtk_dataChooser.h $(srcdir)/extraGtkFunctions/gtk_dataChooser.c \ $(srcdir)/uiElements/ui_elements.c $(srcdir)/uiElements/ui_elements.h \ $(srcdir)/uiElements/ui_atomic.c $(srcdir)/uiElements/ui_atomic.h \ $(srcdir)/uiElements/ui_spin.c $(srcdir)/uiElements/ui_spin.h \ $(srcdir)/uiElements/ui_axes.h $(srcdir)/uiElements/ui_axes.c \ $(srcdir)/uiElements/ui_box.h $(srcdir)/uiElements/ui_box.c \ $(srcdir)/uiElements/ui_scale.h $(srcdir)/uiElements/ui_scale.c \ $(srcdir)/uiElements/ui_boxTransform.h $(srcdir)/uiElements/ui_boxTransform.c \ $(srcdir)/uiElements/ui_planetree.h $(srcdir)/uiElements/ui_planetree.c \ $(srcdir)/uiElements/ui_link.h $(srcdir)/uiElements/ui_link.c \ $(srcdir)/uiElements/ui_pairtree.h $(srcdir)/uiElements/ui_pairtree.c \ $(srcdir)/uiElements/ui_selection.h $(srcdir)/uiElements/ui_selection.c \ $(srcdir)/uiElements/ui_properties.h $(srcdir)/uiElements/ui_properties.c \ $(srcdir)/panelModules/panelSurfaces.h $(srcdir)/panelModules/panelSurfaces.c \ $(srcdir)/panelModules/panelAxes.h $(srcdir)/panelModules/panelAxes.c \ $(srcdir)/panelModules/panelPlanes.h $(srcdir)/panelModules/panelPlanes.c \ $(srcdir)/panelModules/panelDataFile.h $(srcdir)/panelModules/panelDataFile.c \ $(srcdir)/panelModules/panelElements.h $(srcdir)/panelModules/panelElements.c \ $(srcdir)/panelModules/panelGeometry.h $(srcdir)/panelModules/panelGeometry.c \ $(srcdir)/panelModules/panelConfig.h $(srcdir)/panelModules/panelConfig.c \ $(srcdir)/panelModules/panelMap.h $(srcdir)/panelModules/panelMap.c \ $(srcdir)/gtk_renderingWindowWidget.c $(srcdir)/gtk_renderingWindowWidget.h \ $(srcdir)/visu_gtk.c $(srcdir)/visu_gtk.h \ $(srcdir)/gtk_openGLWidget.c $(srcdir)/gtk_openGLWidget.h \ $(srcdir)/gtk_pairs.c $(srcdir)/gtk_pairs.h \ $(srcdir)/gtk_pick.c $(srcdir)/gtk_pick.h \ $(srcdir)/gtk_main.c $(srcdir)/gtk_main.h $(v_simtypelibs_DATA): $(v_simgir_DATA) $(G_IR_COMPILER) $(G_IR_COMPILER) \ --includedir=. \ --verbose \ -o $(v_simtypelibs_DATA) \ $(v_simgir_DATA) CLEANFILES = $(v_simgir_DATA) $(v_simtypelibs_DATA) endif # WITH_GOBJECT_INTROSPECTION v_sim-3.8.0/src/OSOpenGL/000077500000000000000000000000001370110300500150025ustar00rootroot00000000000000v_sim-3.8.0/src/OSOpenGL/visu_GLX.c000066400000000000000000000263051370110300500166540ustar00rootroot00000000000000/* EXTRAITS DE LA LICENCE Copyright CEA, contributeurs : Luc BILLARD et Damien CALISTE, laboratoire L_Sim, (2001-2006) Adresse mèl : BILLARD, non joignable par mèl ; CALISTE, damien P caliste AT cea P fr. Ce logiciel est un programme informatique servant à visualiser des structures atomiques dans un rendu pseudo-3D. Ce logiciel est régi par la licence CeCILL soumise au droit français et respectant les principes de diffusion des logiciels libres. Vous pouvez utiliser, modifier et/ou redistribuer ce programme sous les conditions de la licence CeCILL telle que diffusée par le CEA, le CNRS et l'INRIA sur le site "http://www.cecill.info". Le fait que vous puissiez accéder à cet en-tête signifie que vous avez pris connaissance de la licence CeCILL, et que vous en avez accepté les termes (cf. le fichier Documentation/licence.fr.txt fourni avec ce logiciel). */ /* LICENCE SUM UP Copyright CEA, contributors : Luc BILLARD et Damien CALISTE, laboratoire L_Sim, (2001-2006) E-mail address: BILLARD, not reachable any more ; CALISTE, damien P caliste AT cea P fr. This software is a computer program whose purpose is to visualize atomic configurations in 3D. This software is governed by the CeCILL license under French law and abiding by the rules of distribution of free software. You can use, modify and/ or redistribute the software under the terms of the CeCILL license as circulated by CEA, CNRS and INRIA at the following URL "http://www.cecill.info". The fact that you are presently reading this means that you have had knowledge of the CeCILL license and that you accept its terms. You can find a copy of this licence shipped with this software at Documentation/licence.en.txt. */ #ifdef HAVE_CONFIG_H #include #endif #include #include #include #include "visu_openGL.h" #include #include static Display *dpy = (Display*)0; static gboolean Xerror = FALSE; struct _VisuPixmapContext { GLXContext context; #ifdef HAVE_PBUFFER GLXPbuffer glxPbuffer; #else GLXPixmap glxPixmap; #endif Pixmap pixmap; guint width, height; }; struct _VisuGLXFont { GLuint id; GLsizei len; XFontStruct *font; }; static GHashTable *fonts = (GHashTable*)0; static int handler(Display *dpy _U_, XErrorEvent *error _U_) { DBG_fprintf(stderr, "Visu GLX: ouch one X error.\n"); Xerror = TRUE; return 0; } #ifdef HAVE_PBUFFER static XVisualInfo* _visualInfoFromFB(Display *dpy, int screenId, GLXFBConfig **fb) { XVisualInfo *vinfo; GLXFBConfig *fbconfig; int nitems; int attrib[] = { GLX_DOUBLEBUFFER, False, GLX_RED_SIZE, 1, GLX_GREEN_SIZE, 1, GLX_BLUE_SIZE, 1, GLX_DEPTH_SIZE, 1, GLX_RENDER_TYPE, GLX_RGBA_BIT, GLX_DRAWABLE_TYPE, GLX_PBUFFER_BIT, None }; fbconfig = glXChooseFBConfig(dpy, screenId, attrib, &nitems); if (fbconfig == (GLXFBConfig*)0 || nitems == 0) { g_warning("Can't get FBConfig."); return (XVisualInfo*)0; } *fb = fbconfig; vinfo = glXGetVisualFromFBConfig(dpy, fbconfig[0]); if (!vinfo) { g_warning("Can't get RGBA Visual."); return (XVisualInfo*)0; } return vinfo; } #endif XVisualInfo* visu_gl_getVisualInfo(Display *dpy, int screenId) { XVisualInfo *vinfo; int list[] = { GLX_RGBA, GLX_RED_SIZE, 1, GLX_GREEN_SIZE, 1, GLX_BLUE_SIZE, 1, GLX_DEPTH_SIZE, 1, GLX_DOUBLEBUFFER, GLX_STEREO, None }; if ( (vinfo = glXChooseVisual(dpy, screenId, list)) == NULL ) { list[10] = None; if ( (vinfo = glXChooseVisual(dpy, screenId, list)) == NULL ) { g_error("Cannot find a visual.\n" "Have you enough right access on the X server?"); } DBG_fprintf(stderr, " | not a stereo buffer.\n"); } else DBG_fprintf(stderr, " | stereo buffer.\n"); return vinfo; } /** * visu_pixmap_context_new: * @width: an integer ; * @height: an integer. * * Create a pixmap storage and a context associated to it. This pixmap * can then be used to dump pixel data from an OpenGL area. * * Returns: (transfer none): a newly allocated #DumpImage object. */ VisuPixmapContext* visu_pixmap_context_new(guint width, guint height) { VisuPixmapContext *image; int screenId, res; Bool direct; XVisualInfo *visualInfo; #ifdef HAVE_PBUFFER GLXFBConfig *fbconfig; int pbufAttrib[] = { GLX_PBUFFER_WIDTH, 0, GLX_PBUFFER_HEIGHT, 0, GLX_LARGEST_PBUFFER, False, None }; #endif DBG_fprintf(stderr, "Visu GLX: creating a off-screen buffer (%dx%d).\n", width, height); image = g_malloc(sizeof(VisuPixmapContext)); image->pixmap = (Pixmap)0; #ifdef HAVE_PBUFFER image->glxPbuffer = (GLXPbuffer)0; #else image->glxPixmap = (GLXPixmap)0; #endif image->context = (GLXContext)0; if (!dpy) dpy = XOpenDisplay(0); if (!dpy) { g_warning("Cannot connect to the X server."); g_free(image); return (VisuPixmapContext*)0; } DBG_fprintf(stderr, "Visu GLX: display opened.\n"); screenId = DefaultScreen(dpy); #ifdef HAVE_PBUFFER visualInfo = _visualInfoFromFB(dpy, screenId, &fbconfig); #else visualInfo = visu_gl_getVisualInfo(dpy, screenId); #endif if (!visualInfo) { g_free(image); return (VisuPixmapContext*)0; } image->width = width; image->height = height; image->pixmap = XCreatePixmap(dpy, RootWindow(dpy, screenId), width, height, visualInfo->depth); if (!image->pixmap) { g_warning("Cannot allocate a XPixmap for the indirect rendering."); g_free(image); XFree(visualInfo); return (VisuPixmapContext*)0; } DBG_fprintf(stderr, "Visu GLX: X pixmap created.\n"); #ifdef HAVE_PBUFFER pbufAttrib[1] = width; pbufAttrib[3] = height; image->glxPbuffer = glXCreatePbuffer(dpy, fbconfig[0], pbufAttrib); DBG_fprintf(stderr, "Visu GLX: use pBuffer.\n"); if (!image->glxPbuffer) { g_warning("Cannot allocate a GLXPbuffer for the indirect rendering."); XFreePixmap(dpy, image->pixmap); g_free(image); XFree(visualInfo); return (VisuPixmapContext*)0; } direct = GL_TRUE; #else image->glxPixmap = glXCreateGLXPixmap(dpy, visualInfo, image->pixmap); DBG_fprintf(stderr, "Visu GLX: use GLXPixmap.\n"); if (!image->glxPixmap) { g_warning("Cannot allocate a GLXPixmap for the indirect rendering."); XFreePixmap(dpy, image->pixmap); g_free(image); XFree(visualInfo); return (VisuPixmapContext*)0; } direct = GL_FALSE; #endif DBG_fprintf(stderr, "Visu GLX: GLX off-creen surface created.\n"); image->context = glXCreateContext(dpy, visualInfo, 0, direct); if (!image->context) { g_warning("Cannot create indirect GLX context."); XFreePixmap(dpy, image->pixmap); #ifdef HAVE_PBUFFER glXDestroyPbuffer(dpy, image->glxPbuffer); #else glXDestroyGLXPixmap(dpy, image->glxPixmap); #endif g_free(image); XFree(visualInfo); return (VisuPixmapContext*)0; } DBG_fprintf(stderr, "Visu GLX: new OpenGL context created.\n"); Xerror = FALSE; XSetErrorHandler(handler); #ifdef HAVE_PBUFFER res = glXMakeCurrent(dpy, image->glxPbuffer, image->context); #else res = glXMakeCurrent(dpy, image->glxPixmap, image->context); #endif XSetErrorHandler(NULL); if (!res || Xerror) { g_warning("Cannot make current the pixmap context."); XFreePixmap(dpy, image->pixmap); #ifdef HAVE_PBUFFER glXDestroyPbuffer(dpy, image->glxPbuffer); #else glXDestroyGLXPixmap(dpy, image->glxPixmap); #endif g_free(image); XFree(visualInfo); return (VisuPixmapContext*)0; } DBG_fprintf(stderr, "Visu GLX: pixmap context is now current.\n"); /* Changing context, update fonts. */ visu_gl_text_onNewContext(); XFree(visualInfo); glXWaitX(); return image; } /** * visu_pixmap_context_free: * @dumpData: an allocated #DumpImage object. * * Free an allocated #DumpImage. */ void visu_pixmap_context_free(VisuPixmapContext *dumpData) { g_return_if_fail(dumpData); if (dpy) { #ifdef HAVE_PBUFFER DBG_fprintf(stderr, "Visu GLX: free the GLX pbuffer 0x%x.\n", (int)dumpData->glxPbuffer); if (dumpData->glxPbuffer) glXDestroyPbuffer(dpy, dumpData->glxPbuffer); #else DBG_fprintf(stderr, "Visu GLX: free the GLX pixmap 0x%x.\n", (int)dumpData->glxPixmap); if (dumpData->glxPixmap) glXDestroyGLXPixmap(dpy, dumpData->glxPixmap); #endif DBG_fprintf(stderr, "Visu GLX: free the X pixmap 0x%x.\n", (int)dumpData->pixmap); if (dumpData->pixmap) XFreePixmap(dpy, dumpData->pixmap); DBG_fprintf(stderr, "Visu GLX: free the context.\n"); if (dumpData->context) glXDestroyContext(dpy, dumpData->context); /* We do NOT close the display since it is shared by all the application and thus dpy structure is unique and will be closed by the main program when quiting. */ /* XCloseDisplay(dumpData->dpy); */ glXWaitX(); } g_free(dumpData); } static void freeFont(gpointer data) { struct _VisuGLXFont *font = (struct _VisuGLXFont*)data; if (!dpy) dpy = XOpenDisplay(0); DBG_fprintf(stderr, "Visu GLX: delete font %d.\n", font->id); glDeleteLists(font->id, font->len); XFreeFont(dpy, font->font); g_free(data); } GLuint visu_gl_initFontList(guint size) { XFontStruct *fontInfo = (XFontStruct*)0; guint first, last; gchar *name; struct _VisuGLXFont *font; name = g_strdup_printf("-misc-fixed-bold-r-normal-*-%d-*-*-*-*-*-iso8859-1", size); DBG_fprintf(stderr, "Visu GLX: initialise fonts (%s).\n", name); if (!dpy) dpy = XOpenDisplay(0); if (!fonts) fonts = g_hash_table_new_full(g_str_hash, g_str_equal, g_free, freeFont); /* Delete previous lists for this size. */ DBG_fprintf(stderr, " | remove previous entry %p if any from %p (%d).\n", GINT_TO_POINTER(size), (gpointer)fonts, g_hash_table_size(fonts)); g_hash_table_remove(fonts, name); DBG_fprintf(stderr, " | get the X font description.\n"); Xerror = FALSE; XSetErrorHandler(handler); if ((fontInfo = XLoadQueryFont(dpy, name)) == NULL) { g_message("Specified font not available in gl_font_init\n" "Trying to use fixed font\n"); if ((fontInfo = XLoadQueryFont(dpy, "fixed")) == NULL) { g_error("Fixed font not available.\n"); } } XSetErrorHandler(NULL); if (Xerror) { g_warning("No font for this surface."); return 0; } DBG_fprintf(stderr, " | Found XFontStruct.\n"); first = fontInfo->min_char_or_byte2; last = fontInfo->max_char_or_byte2; DBG_fprintf(stderr, " | XFontStruct OK (%d %d).\n", first, last); /* this creates display lists 1 to 256 (not checked) */ font = g_malloc(sizeof(struct _VisuGLXFont)); font->font = fontInfo; font->len = last + 1; font->id = glGenLists(font->len); if (!font->id) { g_free(font); g_free(name); return 0; } g_hash_table_insert(fonts, name, (gpointer)font); Xerror = FALSE; XSetErrorHandler(handler); glXUseXFont(fontInfo->fid, first, last-first+1, font->id+first); XSetErrorHandler(NULL); if (Xerror) { g_warning("No font generation for this surface."); font->id = 0; } DBG_fprintf(stderr, " | list id %d\n", font->id); return font->id; } v_sim-3.8.0/src/OSOpenGL/visu_GtkGlExt.c000066400000000000000000000123201370110300500177030ustar00rootroot00000000000000/* EXTRAITS DE LA LICENCE Copyright CEA, contributeurs : Luc BILLARD et Damien CALISTE, laboratoire L_Sim, (2001-2006) Adresse mèl : BILLARD, non joignable par mèl ; CALISTE, damien P caliste AT cea P fr. Ce logiciel est un programme informatique servant à visualiser des structures atomiques dans un rendu pseudo-3D. Ce logiciel est régi par la licence CeCILL soumise au droit français et respectant les principes de diffusion des logiciels libres. Vous pouvez utiliser, modifier et/ou redistribuer ce programme sous les conditions de la licence CeCILL telle que diffusée par le CEA, le CNRS et l'INRIA sur le site "http://www.cecill.info". Le fait que vous puissiez accéder à cet en-tête signifie que vous avez pris connaissance de la licence CeCILL, et que vous en avez accepté les termes (cf. le fichier Documentation/licence.fr.txt fourni avec ce logiciel). */ /* LICENCE SUM UP Copyright CEA, contributors : Luc BILLARD et Damien CALISTE, laboratoire L_Sim, (2001-2006) E-mail address: BILLARD, not reachable any more ; CALISTE, damien P caliste AT cea P fr. This software is a computer program whose purpose is to visualize atomic configurations in 3D. This software is governed by the CeCILL license under French law and abiding by the rules of distribution of free software. You can use, modify and/ or redistribute the software under the terms of the CeCILL license as circulated by CEA, CNRS and INRIA at the following URL "http://www.cecill.info". The fact that you are presently reading this means that you have had knowledge of the CeCILL license and that you accept its terms. You can find a copy of this licence shipped with this software at Documentation/licence.en.txt. */ #include "visu_openGL.h" #include struct VisuPixmapContext_struct { GdkGLConfig *glConfig; GdkGLContext *glContext; GdkGLPixmap *glPixmap; GdkPixmap *pixmap; guint width, height; }; GdkGLConfig* visu_gl_getGLConfig(GdkScreen *screen) { GdkGLConfig *glconfig; int list[] = { GDK_GL_RGBA, GDK_GL_RED_SIZE, 1, GDK_GL_GREEN_SIZE, 1, GDK_GL_BLUE_SIZE, 1, GDK_GL_DEPTH_SIZE, 1, GDK_GL_DOUBLEBUFFER, GDK_GL_STEREO, GDK_GL_ATTRIB_LIST_NONE }; /* Create the GdkGLConfig for this screen. */ glconfig = gdk_gl_config_new_for_screen(screen, list); if ( !glconfig ) { list[10] = (int)GDK_GL_ATTRIB_LIST_NONE; glconfig = gdk_gl_config_new_for_screen(screen, list); if ( !glconfig ) g_error("Cannot find a matching visual."); } return glconfig; } GLuint visu_gl_initFontList(guint size) { PangoFont *font; GLuint BASE; gchar *str; /* GtkWidget *wd; */ DBG_fprintf(stderr, "Visu GtkGlExt: initialise fonts.\n"); /* wd = gtk_label_new("toto"); */ BASE = 123; str = g_strdup_printf("sans %d", size); font = gdk_gl_font_use_pango_font(pango_font_description_from_string(str), 0, 128, BASE); g_free(str); /* font = gdk_gl_font_use_pango_font(gtk_widget_get_style(wd)->font_desc, */ /* 0, 128, BASE); */ if (!font) g_error("Font not available for OpenGLification.\n"); /* g_object_unref(G_OBJECT(wd)); */ return BASE; } VisuPixmapContext* visu_pixmap_context_new(guint width, guint height) { GdkScreen *screen; gboolean res; VisuPixmapContext *image; DBG_fprintf(stderr, "Visu GtkGlExt: creating a off-screen buffer (%dx%d).\n", width, height); image = g_malloc(sizeof(VisuPixmapContext)); image->glConfig = (GdkGLConfig*)0; image->glContext = (GdkGLContext*)0; image->pixmap = (GdkPixmap*)0; image->glPixmap = (GdkGLPixmap*)0; screen = gdk_screen_get_default(); image->glConfig = visu_gl_getGLConfig(screen); image->width = width; image->height = height; image->pixmap = gdk_pixmap_new((GdkDrawable*)0, (gint)width, (gint)height, gdk_gl_config_get_depth(image->glConfig)); if (!image->pixmap) { g_warning("Cannot allocate a GdkPixmap for the indirect rendering."); visu_pixmap_context_free(image); return (VisuPixmapContext*)0; } image->glPixmap = gdk_gl_pixmap_new(image->glConfig, image->pixmap, NULL); if (!image->glPixmap) { g_warning("Cannot allocate a GdkGLPixmap for the indirect rendering."); visu_pixmap_context_free(image); return (VisuPixmapContext*)0; } image->glContext = gdk_gl_context_new(GDK_GL_DRAWABLE(image->glPixmap), (GdkGLContext*)0, FALSE, GDK_GL_RGBA_TYPE); if (!image->glContext) { g_warning("Cannot create indirect context."); visu_pixmap_context_free(image); return (VisuPixmapContext*)0; } res = gdk_gl_drawable_make_current((GdkGLDrawable*)image->glPixmap, image->glContext); if (!res) { g_warning("Cannot make current the pixmap context."); visu_pixmap_context_free(image); return (VisuPixmapContext*)0; } return image; } void visu_pixmap_context_free(VisuPixmapContext *dumpData) { if (!dumpData) return; if (dumpData->pixmap) g_object_unref(dumpData->pixmap); if (dumpData->glConfig) g_object_unref(dumpData->glConfig); if (dumpData->glPixmap) gdk_gl_pixmap_destroy(dumpData->glPixmap); if (dumpData->glContext) gdk_gl_context_destroy(dumpData->glContext); g_free(dumpData); } v_sim-3.8.0/src/OSOpenGL/visu_WGL.c000066400000000000000000000162501370110300500166510ustar00rootroot00000000000000/* EXTRAITS DE LA LICENCE Copyright CEA, contributeurs : Luc BILLARD et Damien CALISTE, laboratoire L_Sim, (2001-2006) Adresse mèl : BILLARD, non joignable par mèl ; CALISTE, damien P caliste AT cea P fr. Ce logiciel est un programme informatique servant à visualiser des structures atomiques dans un rendu pseudo-3D. Ce logiciel est régi par la licence CeCILL soumise au droit français et respectant les principes de diffusion des logiciels libres. Vous pouvez utiliser, modifier et/ou redistribuer ce programme sous les conditions de la licence CeCILL telle que diffusée par le CEA, le CNRS et l'INRIA sur le site "http://www.cecill.info". Le fait que vous puissiez accéder à cet en-tête signifie que vous avez pris connaissance de la licence CeCILL, et que vous en avez accepté les termes (cf. le fichier Documentation/licence.fr.txt fourni avec ce logiciel). */ /* LICENCE SUM UP Copyright CEA, contributors : Luc BILLARD et Damien CALISTE, laboratoire L_Sim, (2001-2006) E-mail address: BILLARD, not reachable any more ; CALISTE, damien P caliste AT cea P fr. This software is a computer program whose purpose is to visualize atomic configurations in 3D. This software is governed by the CeCILL license under French law and abiding by the rules of distribution of free software. You can use, modify and/ or redistribute the software under the terms of the CeCILL license as circulated by CEA, CNRS and INRIA at the following URL "http://www.cecill.info". The fact that you are presently reading this means that you have had knowledge of the CeCILL license and that you accept its terms. You can find a copy of this licence shipped with this software at Documentation/licence.en.txt. */ #ifdef HAVE_CONFIG_H #include #endif #include "visu_openGL.h" #include #include #include struct _VisuPixmapContext { HDC hdc; HDC pixmapDC; HBITMAP pixmap; int width, height; HGLRC context; }; void visu_gl_setupPixelFormat(HDC hDC) { /* Pixel format index */ int nPixelFormat; static PIXELFORMATDESCRIPTOR pfd = { sizeof(PIXELFORMATDESCRIPTOR), /*size of structure*/ 1, /*default version*/ PFD_DRAW_TO_WINDOW | /*window drawing support*/ PFD_SUPPORT_OPENGL | /*opengl support*/ PFD_DOUBLEBUFFER, /*double buffering support*/ PFD_TYPE_RGBA, /*RGBA color mode*/ 32, /*32 bit color mode*/ 0, 0, 0, 0, 0, 0, /*ignore color bits*/ 0, /*no alpha buffer*/ 0, /*ignore shift bit*/ 0, /*no accumulation buffer*/ 0, 0, 0, 0, /*ignore accumulation bits*/ 16, /*16 bit z-buffer size*/ 0, /*no stencil buffer*/ 0, /*no aux buffer*/ PFD_MAIN_PLANE, /*main drawing plane*/ 0, /*reserved*/ 0, 0, 0 }; /*layer masks ignored*/ /* Choose best matching format*/ nPixelFormat = ChoosePixelFormat(hDC, &pfd); /* Set the pixel format to the device context*/ SetPixelFormat(hDC, nPixelFormat, &pfd); } void SetupPixelFormatPixmap(HDC hDC) { /* Pixel format index */ int nPixelFormat; static PIXELFORMATDESCRIPTOR pfdPix = { sizeof(PIXELFORMATDESCRIPTOR), /*size of structure*/ 1, /*default version*/ PFD_DRAW_TO_BITMAP | /*window drawing support*/ PFD_SUPPORT_OPENGL, /*opengl support*/ PFD_TYPE_RGBA, /*RGBA color mode*/ 32, /*32 bit color mode*/ 0, 0, 0, 0, 0, 0, /*ignore color bits*/ 0, /*no alpha buffer*/ 0, /*ignore shift bit*/ 0, /*no accumulation buffer*/ 0, 0, 0, 0, /*ignore accumulation bits*/ 16, /*16 bit z-buffer size*/ 0, /*no stencil buffer*/ 0, /*no aux buffer*/ PFD_MAIN_PLANE, /*main drawing plane*/ 0, /*reserved*/ 0, 0, 0 }; /*layer masks ignored*/ /* Choose best matching format*/ nPixelFormat = ChoosePixelFormat(hDC, &pfdPix); /* Set the pixel format to the device context*/ SetPixelFormat(hDC, nPixelFormat, &pfdPix); } VisuPixmapContext* visu_pixmap_context_new(guint width, guint height) { VisuPixmapContext *image; DBG_fprintf(stderr, "Visu WGL : creating a off-screen buffer (%dx%d).", width, height); image = g_malloc(sizeof(VisuPixmapContext)); image->hdc = (HDC)0; image->pixmap = (HBITMAP)0; image->pixmapDC = (HDC)0; image->context = (HGLRC)0; image->width = width; image->height = height; image->hdc = GetDC(NULL); if (!image->hdc) { g_warning("Cannot get a HDC."); g_free(image); return (VisuPixmapContext*)0; } image->pixmap = CreateCompatibleBitmap(image->hdc, width, height); if (!image->pixmap) { g_warning("Cannot allocate a pixmap for the indirect rendering."); g_free(image); return (VisuPixmapContext*)0; } image->pixmapDC = CreateCompatibleDC(NULL); if (!image->pixmapDC) { g_warning("Cannot allocate a pixmapDC for the indirect rendering."); g_free(image); return (VisuPixmapContext*)0; } image->pixmap = SelectObject(image->pixmapDC, image->pixmap); SetupPixelFormatPixmap(image->pixmapDC); image->context = wglCreateContext(image->pixmapDC); if (!image->context) { g_warning("Cannot create indirect WGL context."); g_free(image); return (VisuPixmapContext*)0; } wglMakeCurrent(NULL, NULL); wglMakeCurrent(image->pixmapDC, image->context); /* Changing context, update fonts. */ visu_gl_text_onNewContext(); return image; } void visu_pixmap_context_free(VisuPixmapContext *dumpData) { g_return_if_fail(dumpData); wglDeleteContext(dumpData->context); DeleteObject(SelectObject(dumpData->pixmapDC, dumpData->pixmap)); DeleteDC(dumpData->pixmapDC); g_free(dumpData); } GLuint visu_gl_initFontList(guint size) { GLuint BASE; BOOL res; HDC hdc; BASE = 0; DBG_fprintf(stderr, "Visu WGL : initialise fonts.\n"); /* this creates display lists 1 to 256 (not checked) */ if ( (BASE = glGenLists(256)) == 0 ) { g_warning("Cannot build font display lists.\n"); return 0; } hdc = GetDC(NULL); res = wglUseFontBitmaps(hdc, 0, 255, BASE); /* else res = wglUseFontBitmaps(hdcPixmap, 0, 255, BASE);*/ if ( !res ) { g_warning("wglUseFontBitmaps returns false.\n"); return 0; } else return BASE; } v_sim-3.8.0/src/OSOpenGL/visu_openGL.h000066400000000000000000000077451370110300500174220ustar00rootroot00000000000000/* EXTRAITS DE LA LICENCE Copyright CEA, contributeurs : Luc BILLARD et Damien CALISTE, laboratoire L_Sim, (2001-2006) Adresse mèl : BILLARD, non joignable par mèl ; CALISTE, damien P caliste AT cea P fr. Ce logiciel est un programme informatique servant à visualiser des structures atomiques dans un rendu pseudo-3D. Ce logiciel est régi par la licence CeCILL soumise au droit français et respectant les principes de diffusion des logiciels libres. Vous pouvez utiliser, modifier et/ou redistribuer ce programme sous les conditions de la licence CeCILL telle que diffusée par le CEA, le CNRS et l'INRIA sur le site "http://www.cecill.info". Le fait que vous puissiez accéder à cet en-tête signifie que vous avez pris connaissance de la licence CeCILL, et que vous en avez accepté les termes (cf. le fichier Documentation/licence.fr.txt fourni avec ce logiciel). */ /* LICENCE SUM UP Copyright CEA, contributors : Luc BILLARD et Damien CALISTE, laboratoire L_Sim, (2001-2006) E-mail address: BILLARD, not reachable any more ; CALISTE, damien P caliste AT cea P fr. This software is a computer program whose purpose is to visualize atomic configurations in 3D. This software is governed by the CeCILL license under French law and abiding by the rules of distribution of free software. You can use, modify and/ or redistribute the software under the terms of the CeCILL license as circulated by CEA, CNRS and INRIA at the following URL "http://www.cecill.info". The fact that you are presently reading this means that you have had knowledge of the CeCILL license and that you accept its terms. You can find a copy of this licence shipped with this software at Documentation/licence.en.txt. */ #ifndef VISU_GL_H #define VISU_GL_H #ifdef HAVE_CONFIG_H #include #endif #include #include /** * SECTION:visu_openGL * @short_description: some OpenGL wrappers for host implementation. * * */ #ifdef HAVE_GTKGLEXT /** * GDKGLEXT_MULTIHEAD_SUPPORT: (skip) * * GtkGlExt support. */ #define GDKGLEXT_MULTIHEAD_SUPPORT #include /** * IMPL_GTKGLEXT: (skip) * * GtkGlExt support. */ #define IMPL_GTKGLEXT #else #if SYSTEM_X11 == 1 #include #include /** * IMPL_BUILTIN_X11: (skip) * * X11 support. */ #define IMPL_BUILTIN_X11 #endif #if SYSTEM_WIN32 == 1 #include /** * IMPL_BUILTIN_WIN32: (skip) * * Win32 support. */ #define IMPL_BUILTIN_WIN32 #endif #endif /** * VisuPixmapContext: * * Short way to address #_VisuPixmapContext objects. */ typedef struct _VisuPixmapContext VisuPixmapContext; VisuPixmapContext* visu_pixmap_context_new(guint width, guint height); void visu_pixmap_context_free(VisuPixmapContext *dumpData); /** * visu_gl_initFontList: * @size: the size of the text. * * This method create a list with a default font. * * Returns: (type guint32): the GL id of the list storing the font. */ GLuint visu_gl_initFontList(guint size); #ifdef IMPL_GTKGLEXT /** * visu_gl_getGLConfig: * @screen: a #GdkScreen. * * Call gdk_gl_config_new_for_screen(), trying to acquire a RGBA visual with stereo * capabilities. This method is used internaly and should not be used elsewhere. * * Returns: a matching #GdkGLConfig. */ GdkGLConfig* visu_gl_getGLConfig(GdkScreen *screen); #endif #ifdef IMPL_BUILTIN_X11 /** * visu_gl_getVisualInfo: * @dpy: an X display ; * @screenId: an X screen id. * * Call glXChooseVisual(), trying to acquire a RGBA visual with stereo * capabilities. This method is used internaly and should not be used elsewhere. * * Returns: an allocated XVisualInfo. */ XVisualInfo* visu_gl_getVisualInfo(Display *dpy, int screenId); #endif #ifdef IMPL_BUILTIN_WIN32 /** * visu_gl_setupPixelFormat: * @hDC: an HDC. * * Call ChoosePixelFormat() and SetPixelFormat(), trying to acquire a RGBA visual. * This method is used internaly and should not be used elsewhere. */ void visu_gl_setupPixelFormat(HDC hDC); #endif #endif v_sim-3.8.0/src/coreTools/000077500000000000000000000000001370110300500153655ustar00rootroot00000000000000v_sim-3.8.0/src/coreTools/atoms_yaml.c000066400000000000000000001370641370110300500177110ustar00rootroot00000000000000#define _ISOC99_SOURCE #include "config.h" #ifdef HAVE_YAML #include #endif #ifdef _POSIX_C_SOURCE #undef _POSIX_C_SOURCE #endif #define _POSIX_C_SOURCE 200809L #include #include #include #include #ifndef __STDC_VERSION__ #define __STDC_VERSION__ 199901L #endif #include #include "atoms_yaml.h" #ifndef FC_FUNC_ #define FC_FUNC_(A,B) A ## _ #endif #ifdef HAVE_YAML static const char *UnitsPositions_keys[] = {"bohr", "angstroem", "reduced", "atomic", NULL}; #ifdef TEST_ME static const char *BC_keys[] = {"free", "wireZ", "wireY", "surfaceYZ", "wireX", "surfaceXZ", "surfaceXY", "periodic", NULL}; static const char *Units_keys[] = {"bohr", "angstroem", "atomic", NULL}; #endif static const char *funits_keys[] = {"Ha/Bohr", "eV/Ang", NULL}; static const char *eunits_keys[] = {"Ha", "eV", "Ry", NULL}; static const char *frozen_keys[] = {"No", "Yes", "fy", "fxz", "N", "Y", "", "", "", "f", "", "", "", "fxyz", "", "", "false", "true", "", "", "off", "on", "", "", NULL}; static const char *bool_keys[] = {"No", "Yes", "N", "Y", "false", "true", "off", "on", NULL}; static PosinpAtoms* posinp_atoms_new() { PosinpAtoms *atoms; atoms = malloc(sizeof(PosinpAtoms)); memset(atoms, 0, sizeof(PosinpAtoms)); /* Default values. */ atoms->BC = POSINP_BC_FREE; atoms->Units = POSINP_CELL_UNITS_BOHR; atoms->angdeg[0] = 90.; atoms->angdeg[1] = 90.; atoms->angdeg[2] = 90.; /* Default values. */ atoms->units = POSINP_COORD_UNITS_BOHR; atoms->punits = POSINP_COORD_UNITS_BOHR; /* Default values. */ atoms->funits = POSINP_FORCE_UNITS_HARTREE_PER_BOHR; /* Default values. */ atoms->energy = NAN; atoms->eunits = POSINP_ENERG_UNITS_HARTREE; atoms->gnrm_wfn = NAN; return atoms; } #endif static unsigned int _dict_len(const PosinpDict *dict) { unsigned int j; for (j = 0; j < (dict ? dict->len : 0) && dict->items[j].key; j++); return j; } static const PosinpDictEntry* _dict_value_const(const PosinpDict *dict, const char *key) { unsigned int j; if (!key) return (PosinpDictEntry*)0; for (j = 0; j < (dict ? dict->len : 0) && dict->items[j].key; j++) if (!strcmp(dict->items[j].key, key)) return dict->items + j; return (const PosinpDictEntry*)0; } static const PosinpDictEntry* _dict_at_const(const PosinpDict *dict, unsigned int i) { if (i < _dict_len(dict)) return dict->items + i; return (const PosinpDictEntry*)0; } #ifdef HAVE_YAML static const PosinpDict* _as_dict(const PosinpDict *dict, const char *key) { const PosinpDictEntry *val; val = _dict_value_const(dict, key); if (!val || !val->key || val->type != POSINP_TYPE_DICT) return (PosinpDict*)0; return &val->value.dict; } static const PosinpDict* _at_dict(const PosinpDict *dict, unsigned int i) { const PosinpDictEntry *val; val = _dict_at_const(dict, i); if (!val || !val->key || val->type != POSINP_TYPE_DICT) return (PosinpDict*)0; return &val->value.dict; } static const char* _as_str(const PosinpDict *dict, const char *key) { const PosinpDictEntry *val; val = _dict_value_const(dict, key); if (!val || !val->key || val->type != POSINP_TYPE_STR) return (const char*)0; return val->value.str; } static void _as_dbl(const PosinpDict *dict, const char *key, double *arr, size_t len) { const PosinpDictEntry *val; val = _dict_value_const(dict, key); if (!val || !val->key || val->type != POSINP_TYPE_DBL_ARR || val->value.darr.len != len) return; memcpy(arr, val->value.darr.arr, sizeof(double) * len); } #endif /* static void _dict_repr(const PosinpDict *dict, const char *buf) */ /* { */ /* unsigned int j, i; */ /* char *buf2; */ /* fprintf(stderr, "%s(%p) %2d entries\n", buf ? buf : "", (void*)dict, _dict_len(dict)); */ /* for (j = 0; j < (dict ? dict->len : 0) && dict->items[j].key; j++) */ /* switch (dict->items[j].type) */ /* { */ /* case POSINP_TYPE_INT: */ /* fprintf(stderr, "%s - %d (%s)\n", buf ? buf : "", dict->items[j].value.ival, dict->items[j].key); */ /* break; */ /* case POSINP_TYPE_DBL: */ /* fprintf(stderr, "%s - %f (%s)\n", buf ? buf : "", dict->items[j].value.dval, dict->items[j].key); */ /* break; */ /* case POSINP_TYPE_INT_ARR: */ /* fprintf(stderr, "%s - [", buf ? buf : ""); */ /* if (dict->items[j].value.iarr.len > 0) */ /* fprintf(stderr, "%d", dict->items[j].value.iarr.arr[0]); */ /* for (i = 1; i < dict->items[j].value.iarr.len; i++) */ /* fprintf(stderr, ", %d", dict->items[j].value.iarr.arr[i]); */ /* fprintf(stderr, "] (%s)\n", dict->items[j].key); */ /* break; */ /* case POSINP_TYPE_DBL_ARR: */ /* fprintf(stderr, "%s - [", buf ? buf : ""); */ /* if (dict->items[j].value.darr.len > 0) */ /* fprintf(stderr, "%f", dict->items[j].value.darr.arr[0]); */ /* for (i = 1; i < dict->items[j].value.darr.len; i++) */ /* fprintf(stderr, ", %f", dict->items[j].value.darr.arr[i]); */ /* fprintf(stderr, "] (%s)\n", dict->items[j].key); */ /* break; */ /* case POSINP_TYPE_STR: */ /* fprintf(stderr, "%s - '%s' (%s)\n", buf ? buf : "", dict->items[j].value.str, dict->items[j].key); */ /* break; */ /* case POSINP_TYPE_DICT: */ /* fprintf(stderr, "%s - (%s)\n", buf ? buf : "", dict->items[j].key); */ /* buf2 = malloc(sizeof(char) * (strlen(buf) + 2)); */ /* memcpy(buf2, buf, sizeof(char) * strlen(buf)); */ /* buf2[strlen(buf)] = ' '; */ /* buf2[strlen(buf) + 1] = '\0'; */ /* _dict_repr(&dict->items[j].value.dict, buf2); */ /* free(buf2); */ /* break; */ /* } */ /* } */ static void _free_dict(PosinpDict *dict) { unsigned int j; for (j = 0; j < dict->len; j++) { free(dict->items[j].key); switch (dict->items[j].type) { case (POSINP_TYPE_INT_ARR): free(dict->items[j].value.iarr.arr); break; case (POSINP_TYPE_DBL_ARR): free(dict->items[j].value.darr.arr); break; case (POSINP_TYPE_STR): free(dict->items[j].value.str); break; case (POSINP_TYPE_DICT): _free_dict(&dict->items[j].value.dict); break; default: break; } } } static void posinp_atoms_free(PosinpAtoms *atoms) { unsigned int i; /* Freeing. */ free(atoms->comment); free(atoms->rxyz); if (atoms->atomnames) for (i = 0; i < atoms->ntypes; i++) free(atoms->atomnames[i]); free(atoms->atomnames); free(atoms->iatype); free(atoms->ifrztyp); free(atoms->igspin); free(atoms->igchg); free(atoms->fxyz); free(atoms->pxyz); free(atoms->psigma); free(atoms->ppoles); for (i = 0; atoms->potnames && atoms->potnames[i]; i++) free(atoms->potnames[i]); free(atoms->potnames); if (atoms->props) for (i = 0; i < atoms->nat; i++) _free_dict(atoms->props + i); free(atoms->props); free(atoms); } #ifdef TEST_ME static void posinp_atoms_trace(PosinpAtoms *atoms) { unsigned int i; fprintf(stdout, "'%s'.\n", atoms->comment); if (!isnan(atoms->gnrm_wfn)) fprintf(stdout, "Converged %d (%g).\n", atoms->converged, atoms->gnrm_wfn); if (!isnan(atoms->energy)) fprintf(stdout, "Energy is %g %s (%d).\n", atoms->energy, eunits_keys[atoms->eunits], atoms->eunits); fprintf(stdout, "BC is %d (%s).\n", atoms->BC, BC_keys[atoms->BC]); fprintf(stdout, "Units are %d (%s).\n", atoms->Units, Units_keys[atoms->Units]); fprintf(stdout, "acell is %g %g %g.\n", atoms->acell[0], atoms->acell[1], atoms->acell[2]); fprintf(stdout, "angdeg is %g %g %g.\n", atoms->angdeg[0], atoms->angdeg[1], atoms->angdeg[2]); fprintf(stdout, "Position units are %d (%s).\n", atoms->units, UnitsPositions_keys[atoms->units]); for (i = 0; i < atoms->nat; i++) fprintf(stdout, "Atom '%s' at %g %g %g (%d) f:%d s:%d c:%d.\n", atoms->atomnames[atoms->iatype[i]], atoms->rxyz[3 * i + 0], atoms->rxyz[3 * i + 1], atoms->rxyz[3 * i + 2], atoms->iatype[i], atoms->ifrztyp[i], atoms->igspin[i], atoms->igchg[i]); if (atoms->fxyz) { fprintf(stdout, "Forces units are %d (%s).\n", atoms->funits, funits_keys[atoms->funits]); fprintf(stdout, "fnrm is %g, maxval is %g.\n", atoms->fnrm, atoms->maxval); for (i = 0; i < atoms->nat; i++) fprintf(stdout, "Force on '%s' is %g %g %g.\n", atoms->atomnames[atoms->iatype[i]], atoms->fxyz[3 * i + 0], atoms->fxyz[3 * i + 1], atoms->fxyz[3 * i + 2]); } } #endif #define set_error(...) \ if (message && !*message) \ { \ ln = snprintf(NULL, 0, __VA_ARGS__); \ *message = malloc(sizeof(char) * ln); \ sprintf(*message, __VA_ARGS__); \ } \ else \ fprintf(stderr, __VA_ARGS__) #ifdef HAVE_YAML static void _yaml_parser_error(const yaml_parser_t *parser, char **message) { size_t ln; switch (parser->error) { case YAML_MEMORY_ERROR: set_error("Memory error: Not enough memory for parsing\n"); return; case YAML_READER_ERROR: if (parser->problem_value != -1) { set_error("Reader error: %s: #%X at %zu\n", parser->problem, parser->problem_value, parser->problem_offset); } else { set_error("Reader error: %s at %zu\n", parser->problem, parser->problem_offset); } return; case YAML_SCANNER_ERROR: if (parser->context) { set_error("Scanner error: %s at line %zu, column %zu\n" "%s at line %zu, column %zu\n", parser->context, parser->context_mark.line+1, parser->context_mark.column+1, parser->problem, parser->problem_mark.line+1, parser->problem_mark.column+1); } else { set_error("Scanner error: %s at line %zu, column %zu\n", parser->problem, parser->problem_mark.line+1, parser->problem_mark.column+1); } return; case YAML_PARSER_ERROR: if (parser->context) { set_error("Parser error: %s at line %zu, column %zu\n" "%s at line %zu, column %zu\n", parser->context, parser->context_mark.line+1, parser->context_mark.column+1, parser->problem, parser->problem_mark.line+1, parser->problem_mark.column+1); } else { set_error("Parser error: %s at line %zu, column %zu\n", parser->problem, parser->problem_mark.line+1, parser->problem_mark.column+1); } return; default: /* Couldn't happen. */ set_error("Internal error\n"); return; } } static int _yaml_parser_copy_str(yaml_parser_t *parser, char **val, char **message) { yaml_event_t event; int done; size_t ln; /* Read the value. */ done = 0; if (yaml_parser_parse(parser, &event)) { if (event.type == YAML_SCALAR_EVENT) { ln = strlen((const char*)event.data.scalar.value); *val = malloc(sizeof(char) * (ln + 1)); memcpy(*val, event.data.scalar.value, sizeof(char) * (ln + 1)); done = 0; } else { set_error("Parser error: value awaited.\n"); done = (event.type == YAML_STREAM_END_EVENT)?1:-1; } /* The application is responsible for destroying the event object. */ yaml_event_delete(&event); } else { /* Error treatment. */ _yaml_parser_error(parser, message); done = -1; } return done; } static int _yaml_parser_read_int(yaml_parser_t *parser, int *val, char **message) { yaml_event_t event; int done; char *end; size_t ln; /* Read the value. */ done = 0; if (yaml_parser_parse(parser, &event)) { if (event.type == YAML_SCALAR_EVENT) { *val = (int)strtol((const char*)event.data.scalar.value, &end, 10); if (end == (char*)event.data.scalar.value) { set_error("Parser error: cannot convert '%s' to an int.\n", end); done = -1; } else done = 0; } else { set_error("Parser error: value awaited.\n"); done = (event.type == YAML_STREAM_END_EVENT)?1:-1; } /* The application is responsible for destroying the event object. */ yaml_event_delete(&event); } else { /* Error treatment. */ _yaml_parser_error(parser, message); done = -1; } return done; } static int _yaml_parser_read_bool(yaml_parser_t *parser, int *val, char **message) { yaml_event_t event; int done; size_t ln; const char *value; *val = 0; /* Read the value. */ done = 0; if (yaml_parser_parse(parser, &event)) { if (event.type == YAML_SCALAR_EVENT) { value = (const char*)event.data.scalar.value; done = 0; if (value && (value[0] == 'T' || value[0] == 'Y' || !strcmp(value, "true") || !strcmp(value, "yes"))) *val = 1; else if (value && (value[0] == 'F' || value[0] == 'N' || !strcmp(value, "false") || !strcmp(value, "no"))) *val = 0; else { set_error("Parser error: cannot convert '%s' to a boolean.\n", value); done = -1; } } else { set_error("Parser error: value awaited.\n"); done = (event.type == YAML_STREAM_END_EVENT)?1:-1; } /* The application is responsible for destroying the event object. */ yaml_event_delete(&event); } else { /* Error treatment. */ _yaml_parser_error(parser, message); done = -1; } return done; } static int _yaml_parser_read_double(yaml_parser_t *parser, double *val, char **message) { yaml_event_t event; int done; char *end; size_t ln; /* Read the value. */ done = 0; if (yaml_parser_parse(parser, &event)) { if (event.type == YAML_SCALAR_EVENT) { end = (char*)0; if (!event.data.scalar.value[0]) *val = NAN; else if (!strcasecmp((const char*)event.data.scalar.value, ".inf")) *val = INFINITY; else *val = strtod((const char*)event.data.scalar.value, &end); if (end == (char*)event.data.scalar.value) { set_error("Parser error: cannot convert '%s' to a double.\n", end); done = -1; } else done = 0; } else { set_error("Parser error: value awaited.\n"); done = (event.type == YAML_STREAM_END_EVENT)?1:-1; } /* The application is responsible for destroying the event object. */ yaml_event_delete(&event); } else { /* Error treatment. */ _yaml_parser_error(parser, message); done = -1; } return done; } static int _yaml_parser_read_double_array(yaml_parser_t *parser, const char *key, double *vals, unsigned int n, char **message) { yaml_event_t event; int done; unsigned int i; size_t ln; /* Read the value. */ done = 0; if (yaml_parser_parse(parser, &event)) { if (event.type == YAML_SEQUENCE_START_EVENT) { for (i = 0; i < n && done == 0; i++) done = _yaml_parser_read_double(parser, vals + i, message); yaml_event_delete(&event); if (yaml_parser_parse(parser, &event)) { if (event.type != YAML_SEQUENCE_END_EVENT) { set_error("Parser error: end sequence missing for key '%s' after %d values.\n", key, n); done = -1; } } else { /* Error treatment. */ _yaml_parser_error(parser, message); done = -1; } } else { set_error("Parser error: sequence awaited after key '%s'.\n", key); done = -1; } /* The application is responsible for destroying the event object. */ yaml_event_delete(&event); } else { /* Error treatment. */ _yaml_parser_error(parser, message); done = -1; } return done; } static PosinpDictEntry* _dict_get_next(PosinpDict *dict, const char *key) { size_t ln; unsigned int j; #define DICT_INC 5 if (!dict->items) { dict->items = malloc(sizeof(PosinpDictEntry) * DICT_INC); memset(dict->items, 0, sizeof(PosinpDictEntry) * DICT_INC); dict->len = DICT_INC; } for (j = 0; dict->items[j].key && j < dict->len; j++); if (j == dict->len) { dict->items = realloc(dict->items, sizeof(PosinpDictEntry) * (dict->len + DICT_INC)); memset(dict->items + dict->len, 0, sizeof(PosinpDictEntry) * DICT_INC); dict->len += DICT_INC; } /* Store the key. */ ln = strlen(key); dict->items[j].key = malloc(sizeof(char) * (ln + 1)); memcpy(dict->items[j].key, key, sizeof(char) * (ln + 1)); return dict->items + j; } static void _read_value(PosinpDictEntry *entry, const char *value) { char *end, *pt; size_t ln; int ival; entry->type = POSINP_TYPE_DBL; if (!value[0]) entry->value.dval = NAN; else if (!strcasecmp(value, ".inf")) entry->value.dval = INFINITY; else { entry->value.dval = strtod(value, &end); if (end == value) entry->type = POSINP_TYPE_INT; } ival = (int)strtol(value, &end, 10); pt = strchr(value, '.'); if (end != value && !pt && (entry->type == POSINP_TYPE_INT || (double)ival == entry->value.dval)) { entry->type = POSINP_TYPE_INT; entry->value.ival = ival; return; } else if (entry->type == POSINP_TYPE_DBL) return; entry->type = POSINP_TYPE_STR; ln = strlen(value); entry->value.str = malloc(sizeof(char) * (ln + 1)); memcpy(entry->value.str, value, sizeof(char) * (ln + 1)); } static void _read_array(PosinpDictEntry *entry) { unsigned int ln; PosinpDict *dict; PosinpTypeId type; int *iarr; double *darr; if (entry->type != POSINP_TYPE_DICT || !entry->value.dict.len || !entry->value.dict.items[0].key) return; type = entry->value.dict.items[0].type; if (type != POSINP_TYPE_INT && type != POSINP_TYPE_DBL) return; dict = &entry->value.dict; for (ln = 1; ln < dict->len && dict->items[ln].key; ln++) if (dict->items[ln].type != type) return; switch (type) { case (POSINP_TYPE_INT): iarr = malloc(sizeof(int) * ln); for (ln = 0; ln < dict->len && dict->items[ln].key; ln++) iarr[ln] = dict->items[ln].value.ival; _free_dict(dict); entry->type = POSINP_TYPE_INT_ARR; entry->value.iarr.len = ln; entry->value.iarr.arr = iarr; break; case (POSINP_TYPE_DBL): darr = malloc(sizeof(double) * ln); for (ln = 0; ln < dict->len && dict->items[ln].key; ln++) darr[ln] = dict->items[ln].value.dval; _free_dict(dict); entry->type = POSINP_TYPE_DBL_ARR; entry->value.darr.len = ln; entry->value.darr.arr = darr; break; default: break; } } static int _yaml_parser_read_property_map(yaml_parser_t *parser, PosinpDictEntry *entry, char **message); static int _yaml_parser_read_property_list(yaml_parser_t *parser, PosinpDictEntry *entry, char **message) { yaml_event_t event; int done; size_t ln; PosinpDict *dict; PosinpDictEntry *val; if (entry->type != POSINP_TYPE_DICT) return 0; dict = &entry->value.dict; /* Store the value. */ done = 0; while (!done && yaml_parser_parse(parser, &event)) { switch (event.type) { case YAML_SCALAR_EVENT: _read_value(_dict_get_next(dict, "index"), (const char*)event.data.scalar.value); done = 0; break; case YAML_MAPPING_START_EVENT: case YAML_SEQUENCE_START_EVENT: val = _dict_get_next(dict, "index"); val->type = POSINP_TYPE_DICT; if (event.type == YAML_SEQUENCE_START_EVENT) done = _yaml_parser_read_property_list(parser, val, message); else done = _yaml_parser_read_property_map(parser, val, message); break; case YAML_SEQUENCE_END_EVENT: _read_array(entry); done = 1; break; default: set_error("Parser error: value in list '%s' awaited.\n", entry->key); done = (event.type == YAML_STREAM_END_EVENT)?1:-1; break; } /* The application is responsible for destroying the event object. */ yaml_event_delete(&event); } /* Error treatment. */ if (!done) { _yaml_parser_error(parser, message); done = -1; } return (done < 0) ? done : 0; } static int _yaml_parser_read_property_map(yaml_parser_t *parser, PosinpDictEntry *entry, char **message) { yaml_event_t event; int done; size_t ln; PosinpDict *dict; PosinpDictEntry *key; if (entry->type != POSINP_TYPE_DICT) return 0; dict = &entry->value.dict; key = (PosinpDictEntry*)0; /* Store the value. */ done = 0; while (!done && yaml_parser_parse(parser, &event)) { switch (event.type) { case YAML_SCALAR_EVENT: if (!key) key = _dict_get_next(dict, (const char*)event.data.scalar.value); else { _read_value(key, (const char*)event.data.scalar.value); key = (PosinpDictEntry*)0; } done = 0; break; case YAML_MAPPING_START_EVENT: case YAML_SEQUENCE_START_EVENT: if (!key) { set_error("Parser error: key must be a scalar in '%s'.\n", entry->key); done = -1; } else { key->type = POSINP_TYPE_DICT; if (event.type == YAML_SEQUENCE_START_EVENT) done = _yaml_parser_read_property_list(parser, key, message); else done = _yaml_parser_read_property_map(parser, key, message); key = (PosinpDictEntry*)0; } break; case YAML_MAPPING_END_EVENT: done = 1; break; default: set_error("Parser error: value in list '%s' awaited.\n", entry->key); done = (event.type == YAML_STREAM_END_EVENT)?1:-1; break; } /* The application is responsible for destroying the event object. */ yaml_event_delete(&event); } /* Error treatment. */ if (!done) { _yaml_parser_error(parser, message); done = -1; } return (done < 0) ? done : 0; } static int _yaml_parser_read_property(yaml_parser_t *parser, const char *key, PosinpDict *props, char **message) { yaml_event_t event; int done; size_t ln; PosinpDictEntry *val; val = _dict_get_next(props, key); /* Store the value. */ done = 0; if (yaml_parser_parse(parser, &event)) { switch (event.type) { case YAML_SCALAR_EVENT: _read_value(val, (const char*)event.data.scalar.value); done = 0; break; case YAML_SEQUENCE_START_EVENT: val->type = POSINP_TYPE_DICT; done = _yaml_parser_read_property_list(parser, val, message); break; case YAML_MAPPING_START_EVENT: val->type = POSINP_TYPE_DICT; done = _yaml_parser_read_property_map(parser, val, message); break; default: set_error("Parser error: value awaited for '%s'.\n", val->key); done = (event.type == YAML_STREAM_END_EVENT)?1:-1; break; } /* The application is responsible for destroying the event object. */ yaml_event_delete(&event); } else { /* Error treatment. */ _yaml_parser_error(parser, message); done = -1; } return done; } static int _find_keyword(const char *keys[], const char *value, unsigned int *id, unsigned int modulo, char **message) { int done; size_t ln; for (*id = 0; keys[*id]; *id += 1) if (!strcasecmp(value, keys[*id])) break; if (keys[*id]) { *id = *id % modulo; done = 0; } else { *id = 0; set_error("Parser error: cannot find key value '%s'.\n", value); done = -1; } return done; } static int _find_units(const char *keys[], const char *value, unsigned int *id, unsigned int modulo, char **message) { int done; size_t ln; char *start, *end, *unit; *id = 0; start = strchr(value, '('); if (!start) /* No unit specified, no error. */ return 0; end = strchr(start, ')'); if (!end) { /* Parentethis not closed, error. */ set_error("Parser error: unit not properly written in '%s'.\n", value); return -1; } ln = end - start - 1; unit = malloc(sizeof(char) * (ln + 1)); memcpy(unit, start + 1, ln); unit[ln] = '\0'; done = _find_keyword(keys, unit, id, modulo, message); free(unit); return done; } static int _yaml_parser_read_keyword(yaml_parser_t *parser, const char *key, const char *keys[], unsigned int *id, unsigned int modulo, char **message) { yaml_event_t event; int done; size_t ln; /* Read the value. */ done = 0; if (yaml_parser_parse(parser, &event)) { if (event.type == YAML_SCALAR_EVENT) done = _find_keyword(keys, (const char*)event.data.scalar.value, id, modulo, message); else { set_error("Parser error: value awaited after key '%s'.\n", key); done = -1; } /* The application is responsible for destroying the event object. */ yaml_event_delete(&event); } else { /* Error treatment. */ _yaml_parser_error(parser, message); done = -1; } return done; } static int posinp_yaml_cell(yaml_parser_t *parser, PosinpAtoms *atoms, char **message) { int done; done = _yaml_parser_read_double_array(parser, "acell", atoms->acell, 3, message); if (done == 0) { atoms->BC = POSINP_BC_PERIODIC; if (atoms->acell[0] == INFINITY) atoms->BC -= 4; if (atoms->acell[1] == INFINITY) atoms->BC -= 2; if (atoms->acell[2] == INFINITY) atoms->BC -= 1; } return done; } static int posinp_yaml_coord(yaml_parser_t *parser, const char *symbol, double coords[3], char **names, unsigned int *iat, char **message) { unsigned int ln; int done; /* Here parse the name... */ for (*iat = 0; names[*iat] && strcmp((const char*)names[*iat], symbol); *iat += 1); if (!names[*iat]) { ln = strlen(symbol); names[*iat] = malloc(sizeof(char*) * (ln + 1)); memcpy(names[*iat], symbol, sizeof(char*) * ln); names[*iat][ln] = '\0'; } done = _yaml_parser_read_double_array(parser, names[*iat], coords, 3, message); return done; } static int posinp_yaml_coords(yaml_parser_t *parser, PosinpAtoms *atoms, char **message) { yaml_event_t event; int done, hasIGSpin, hasIGChg, hasFrozen; unsigned int count, atom_size; #define ATOM_INC 100 #define UNSET 123456789 /* Read the event sequence. */ done = 0; count = 0; atom_size = ATOM_INC; atoms->rxyz = realloc(atoms->rxyz, sizeof(double) * atom_size * 3); atoms->atomnames = realloc(atoms->atomnames, sizeof(char*) * atom_size); memset(atoms->atomnames, 0, sizeof(char*) * atom_size); atoms->iatype = realloc(atoms->iatype, sizeof(unsigned int) * atom_size); atoms->ifrztyp = realloc(atoms->ifrztyp, sizeof(unsigned int) * atom_size); memset(atoms->ifrztyp, 0, sizeof(unsigned int) * atom_size); atoms->igspin = realloc(atoms->igspin, sizeof(int) * atom_size); memset(atoms->igspin, 0, sizeof(int) * atom_size); atoms->igchg = realloc(atoms->igchg, sizeof(int) * atom_size); memset(atoms->igchg, 0, sizeof(int) * atom_size); atoms->props = realloc(atoms->props, sizeof(PosinpDict) * atom_size); memset(atoms->props, 0, sizeof(PosinpDict) * atom_size); hasIGSpin = 0; hasIGChg = 0; hasFrozen = 0; while (!done) /* Get the next event. */ if (yaml_parser_parse(parser, &event)) { switch(event.type) { case YAML_MAPPING_START_EVENT: if (count >= atom_size) { atom_size += ATOM_INC; atoms->rxyz = realloc(atoms->rxyz, sizeof(double) * 3 * atom_size); atoms->atomnames = realloc(atoms->atomnames, sizeof(char*) * atom_size); memset(atoms->atomnames + atom_size - ATOM_INC, 0, sizeof(char*) * ATOM_INC); atoms->iatype = realloc(atoms->iatype, sizeof(unsigned int) * atom_size); atoms->ifrztyp = realloc(atoms->ifrztyp, sizeof(unsigned int) * atom_size); memset(atoms->ifrztyp + atom_size - ATOM_INC, 0, sizeof(unsigned int) * ATOM_INC); atoms->igspin = realloc(atoms->igspin, sizeof(int) * atom_size); memset(atoms->igspin + atom_size - ATOM_INC, 0, sizeof(int) * ATOM_INC); atoms->igchg = realloc(atoms->igchg, sizeof(int) * atom_size); memset(atoms->igchg + atom_size - ATOM_INC, 0, sizeof(int) * ATOM_INC); atoms->props = realloc(atoms->props, sizeof(PosinpDict) * atom_size); memset(atoms->props + atom_size - ATOM_INC, 0, sizeof(PosinpDict) * ATOM_INC); } atoms->iatype[count] = UNSET; break; case YAML_MAPPING_END_EVENT: if (atoms->iatype[count] != UNSET) count += 1; break; case YAML_SEQUENCE_END_EVENT: done = 2; break; case YAML_SCALAR_EVENT: if (!strcmp((const char*)event.data.scalar.value, "IGSpin")) { done = _yaml_parser_read_int(parser, atoms->igspin + count, message); hasIGSpin = 1; } else if (!strcmp((const char*)event.data.scalar.value, "IGChg")) { done = _yaml_parser_read_int(parser, atoms->igchg + count, message); hasIGChg = 1; } else if (!strcmp((const char*)event.data.scalar.value, "Frozen")) { done = _yaml_parser_read_keyword(parser, "Frozen", frozen_keys, atoms->ifrztyp + count, POSINP_N_FROZEN, message); hasFrozen = 1; } else if (event.data.scalar.value[0] >= 'A' && event.data.scalar.value[0] <= 'Z' && atoms->iatype[count] == UNSET) done = posinp_yaml_coord(parser, (const char*)event.data.scalar.value, atoms->rxyz + 3 * count, atoms->atomnames, atoms->iatype + count, message); else done = _yaml_parser_read_property(parser, (const char*)event.data.scalar.value, atoms->props + count, message); break; default: done = (event.type == YAML_STREAM_END_EVENT); break; } /* The application is responsible for destroying the event object. */ yaml_event_delete(&event); } else { /* Error treatment. */ _yaml_parser_error(parser, message); done = -1; } if (done == 2) done = 0; atoms->nat = count; atoms->rxyz = realloc(atoms->rxyz, sizeof(double) * 3 * atoms->nat); atoms->iatype = realloc(atoms->iatype, sizeof(unsigned int) * atoms->nat); if (hasFrozen) atoms->ifrztyp = realloc(atoms->ifrztyp, sizeof(unsigned int) * atoms->nat); else { free(atoms->ifrztyp); atoms->ifrztyp = (unsigned int*)0; } if (hasIGSpin) atoms->igspin = realloc(atoms->igspin, sizeof(int) * atoms->nat); else { free(atoms->igspin); atoms->igspin = (int*)0; } if (hasIGChg) atoms->igchg = realloc(atoms->igchg, sizeof(int) * atoms->nat); else { free(atoms->igchg); atoms->igchg = (int*)0; } for (atoms->ntypes = 0; atoms->atomnames[atoms->ntypes]; atoms->ntypes++); atoms->props = realloc(atoms->props, sizeof(PosinpDict) * atoms->nat); atoms->atomnames = realloc(atoms->atomnames, sizeof(char*) * atoms->ntypes); return done; } static int posinp_yaml_force(yaml_parser_t *parser, PosinpAtoms *atoms, char **message) { yaml_event_t event, event2; int done; unsigned int count; size_t ln; if (atoms->nat < 1) { set_error("Parser error: forces are defined before atoms.\n"); done = -1; } /* Read the event sequence. */ done = 0; count = 0; atoms->fxyz = realloc(atoms->fxyz, sizeof(double) * atoms->nat * 3); memset(atoms->fxyz, 0, sizeof(double) * atoms->nat * 3); while (!done) /* Get the next event. */ if (yaml_parser_parse(parser, &event)) { switch(event.type) { case YAML_MAPPING_START_EVENT: /* Each mapping is one atom. */ if (count >= atoms->nat) { set_error("Parser error: there are more forces than actual atoms.\n"); done = -1; break; } if (yaml_parser_parse(parser, &event2)) { if (event2.type == YAML_SCALAR_EVENT) { /* Here parse the name... */ if (!strcmp(atoms->atomnames[atoms->iatype[count]], (const char*)event2.data.scalar.value)) /* Then the coordinates. */ done = _yaml_parser_read_double_array(parser, atoms->atomnames[atoms->iatype[count]], atoms->fxyz + 3 * count, 3, message); else { set_error("Parser error: force %d is applied on atom '%s' while atom" " %d is named '%s'.\n", count, (const char*)event2.data.scalar.value, count, atoms->atomnames[atoms->iatype[count]]); done = -1; } } else { set_error("Parser error: atom name awaited.\n"); done = -1; } } else { /* Error treatment. */ _yaml_parser_error(parser, message); done = -1; } yaml_event_delete(&event2); count += 1; break; case YAML_SEQUENCE_END_EVENT: done = 2; break; case YAML_SCALAR_EVENT: done = 0; break; default: done = (event.type == YAML_STREAM_END_EVENT); break; } /* The application is responsible for destroying the event object. */ yaml_event_delete(&event); } else { /* Error treatment. */ _yaml_parser_error(parser, message); done = -1; } if (done == 2) done = 0; return done; } static int posinp_yaml_forces(yaml_parser_t *parser, PosinpAtoms *atoms, char **message) { yaml_event_t event; int done, count; /* Read the event sequence. */ done = 0; count = 0; while (!done) /* Get the next event. */ if (yaml_parser_parse(parser, &event)) { switch(event.type) { case YAML_SEQUENCE_START_EVENT: if (count == 0) { done = posinp_yaml_force(parser, atoms, message); break; } /* Falls through. */ case YAML_MAPPING_START_EVENT: count += 1; done = 0; break; case YAML_SEQUENCE_END_EVENT: case YAML_MAPPING_END_EVENT: count -= 1; done = 0; break; case YAML_SCALAR_EVENT: if (!strcmp((const char*)event.data.scalar.value, "Units")) done = _yaml_parser_read_keyword(parser, "Units", funits_keys, &atoms->funits, POSINP_FORCE_N_UNITS, message); else if (!strcmp((const char*)event.data.scalar.value, "Values")) done = posinp_yaml_force(parser, atoms, message); else if (!strcmp((const char*)event.data.scalar.value, "Fnrm")) done = _yaml_parser_read_double(parser, &atoms->fnrm, message); else if (!strcmp((const char*)event.data.scalar.value, "MaxVal")) done = _yaml_parser_read_double(parser, &atoms->maxval, message); else done = 0; break; default: done = (event.type == YAML_STREAM_END_EVENT); break; } /* Are we finished? */ if (count == 0) done = 2; /* The application is responsible for destroying the event object. */ yaml_event_delete(&event); } else { /* Error treatment. */ _yaml_parser_error(parser, message); done = -1; } if (done == 2) done = 0; return done; } #if SYSTEM_X11 == 1 static char* strdup(const char *src) { char *dest; size_t ln; ln = strlen(src); dest = malloc(sizeof(char) * (ln + 1)); memcpy(dest, src, sizeof(char) * ln); dest[ln] = '\0'; return dest; } #endif static int posinp_yaml_external_potential(const PosinpDict *dict, PosinpAtoms *atoms, char **message) { int done; const char *val; const PosinpDict *values; unsigned int i; done = 0; val = _as_str(dict, "units"); if (val && (done = _find_keyword(UnitsPositions_keys, val, &atoms->punits, POSINP_COORD_N_UNITS, message))) return done; values = _as_dict(dict, "values"); if (!values) return done; atoms->npots = _dict_len(values); if (atoms->npots) { atoms->potnames = malloc(sizeof(char*) * (atoms->npots + 1)); for (i = 0; i < atoms->npots; i++) atoms->potnames[i] = strdup(_as_str(_at_dict(values, i), "sym")); atoms->potnames[atoms->npots] = (char*)0; atoms->pxyz = malloc(sizeof(double) * atoms->npots * 3); for (i = 0; i < atoms->npots; i++) _as_dbl(_at_dict(values, i), "r", atoms->pxyz + 3 * i, 3); atoms->psigma = malloc(sizeof(PosinpSigma) * atoms->npots); memset(atoms->psigma, '\0', sizeof(PosinpSigma) * atoms->npots); for (i = 0; i < atoms->npots; i++) _as_dbl(_at_dict(values, i), "sigma", atoms->psigma[i], POSINP_SIGMA_SIZE); atoms->ppoles = malloc(sizeof(PosinpPole) * atoms->npots); memset(atoms->ppoles, '\0', sizeof(PosinpPole) * atoms->npots); for (i = 0; i < atoms->npots; i++) { _as_dbl(_at_dict(values, i), "q0", &atoms->ppoles[i].q0, 1); _as_dbl(_at_dict(values, i), "q1", atoms->ppoles[i].q1, 3); _as_dbl(_at_dict(values, i), "q2", atoms->ppoles[i].q2, 5); } } return done; } static int posinp_yaml_properties(yaml_parser_t *parser, PosinpAtoms *atoms, char **message) { yaml_event_t event; int done, count, reduced; /* Read the event sequence. */ done = 0; count = 0; while (!done) /* Get the next event. */ if (yaml_parser_parse(parser, &event)) { switch(event.type) { case YAML_SEQUENCE_START_EVENT: case YAML_MAPPING_START_EVENT: count += 1; done = 0; break; case YAML_SEQUENCE_END_EVENT: case YAML_MAPPING_END_EVENT: count -= 1; done = 0; break; case YAML_SCALAR_EVENT: if (!strcmp((const char*)event.data.scalar.value, "Converged")) done = _yaml_parser_read_keyword(parser, "Converged", bool_keys, &atoms->converged, 2, message); else if (!strcmp((const char*)event.data.scalar.value, "Gnrm_wfn")) done = _yaml_parser_read_double(parser, &atoms->gnrm_wfn, message); else if (!strncmp((const char*)event.data.scalar.value, "Energy", 6)) { done = _find_units(eunits_keys, (const char*)event.data.scalar.value, &atoms->eunits, POSINP_ENERG_N_UNITS, message); done = (!done)?_yaml_parser_read_double(parser, &atoms->energy, message):done; } else if (!strcmp((const char*)event.data.scalar.value, "Comment")) done = _yaml_parser_copy_str(parser, &atoms->comment, message); else if (!strcmp((const char*)event.data.scalar.value, "reduced")) { done = _yaml_parser_read_bool(parser, &reduced, message); if (reduced) atoms->units = POSINP_COORD_UNITS_REDUCED; } else done = 0; break; default: done = (event.type == YAML_STREAM_END_EVENT); break; } /* Are we finished? */ if (count == 0) done = 2; /* The application is responsible for destroying the event object. */ yaml_event_delete(&event); } else { /* Error treatment. */ _yaml_parser_error(parser, message); done = -1; } if (done == 2) done = 0; return done; } #endif PosinpDict* posinp_yaml_parse_properties(const char *buffer, char **message) { PosinpDict *dict; #ifdef HAVE_YAML yaml_parser_t parser; yaml_event_t event; int done; dict = (PosinpDict*)0; /* Create the Parser object. */ yaml_parser_initialize(&parser); yaml_parser_set_input_string(&parser, (const unsigned char*)buffer, strlen(buffer)); /* Read the event sequence. */ done = 0; while (!done) /* Get the next event. */ if (yaml_parser_parse(&parser, &event)) { if (event.type == YAML_DOCUMENT_START_EVENT) { dict = malloc(sizeof(PosinpDict)); memset(dict, '\0', sizeof(PosinpDict)); } else if (event.type == YAML_SCALAR_EVENT) done = _yaml_parser_read_property(&parser, (const char*)event.data.scalar.value, dict, message); else done = (event.type == YAML_STREAM_END_EVENT); /* The application is responsible for destroying the event object. */ yaml_event_delete(&event); } else { /* Error treatment. */ _yaml_parser_error(&parser, message); done = -1; } /* Destroy the Parser object. */ yaml_parser_delete(&parser); #else int ln; (void)buffer; dict = (PosinpDict*)0; set_error("No YAML support, cannot read properties.\n"); #endif return dict; } void posinp_yaml_free_properties(PosinpDict *dict) { if (!dict) return; _free_dict(dict); } void posinp_yaml_parse(PosinpList **out, const char *filename, char **message) { #ifdef HAVE_YAML PosinpList *list, *single, *tmp; PosinpList start; PosinpDict dict; FILE *input; yaml_parser_t parser; yaml_event_t event; int done, stored; if (out) list = *out; else list = (PosinpList*)0; start.next = list; tmp = &start; input = fopen(filename, "rb"); if (!input) return; /* Create the Parser object. */ yaml_parser_initialize(&parser); yaml_parser_set_input_file(&parser, input); /* Read the event sequence. */ stored = 0; done = 0; while (!done) /* Get the next event. */ if (yaml_parser_parse(&parser, &event)) { if (event.type == YAML_DOCUMENT_START_EVENT) { if (!tmp->next) { single = malloc(sizeof(PosinpList)); memset(single, 0, sizeof(PosinpList)); single->data = posinp_atoms_new(); if (!list) list = single; tmp->next = single; } tmp = tmp->next; stored = 0; } else if (event.type == YAML_SCALAR_EVENT && !stored && !strcmp((const char*)event.data.scalar.value, "units")) { done = _yaml_parser_read_keyword(&parser, "units", UnitsPositions_keys, &tmp->data->units, POSINP_COORD_N_UNITS, message); if (tmp->data->units != POSINP_COORD_UNITS_REDUCED) tmp->data->Units = (PosinpCellUnits)tmp->data->units; } else if (event.type == YAML_SCALAR_EVENT && !stored && !strcmp((const char*)event.data.scalar.value, "cell")) done = posinp_yaml_cell(&parser, tmp->data, message); else if (event.type == YAML_SCALAR_EVENT && !stored && !strcmp((const char*)event.data.scalar.value, "positions")) done = posinp_yaml_coords(&parser, tmp->data, message); else if (event.type == YAML_SCALAR_EVENT && !stored && !strcmp((const char*)event.data.scalar.value, "forces")) done = posinp_yaml_forces(&parser, tmp->data, message); else if (event.type == YAML_SCALAR_EVENT && !stored && !strcmp((const char*)event.data.scalar.value, "properties")) done = posinp_yaml_properties(&parser, tmp->data, message); else if (event.type == YAML_SCALAR_EVENT && !strcmp((const char*)event.data.scalar.value, "external_potential")) { memset(&dict, '\0', sizeof(PosinpDict)); done = _yaml_parser_read_property(&parser, (const char*)event.data.scalar.value, &dict, message); if (!done) done = posinp_yaml_external_potential(_as_dict(&dict, "external_potential"), tmp->data, message); _free_dict(&dict); } else if (event.type == YAML_MAPPING_END_EVENT) { stored = (tmp->data->rxyz != (double*)0); done = 0; } else done = (event.type == YAML_STREAM_END_EVENT); /* The application is responsible for destroying the event object. */ yaml_event_delete(&event); } else { /* Error treatment. */ _yaml_parser_error(&parser, message); done = -1; } /* Destroy the Parser object. */ yaml_parser_delete(&parser); fclose(input); if (out) *out = list; else posinp_yaml_free_list(list); #else size_t ln; set_error("No YAML support, cannot read file '%s'.\n", filename); if (out) *out = (PosinpList*)0; #endif } void posinp_yaml_free_list(PosinpList *lst) { PosinpList *tmp; while(lst) { posinp_atoms_free(lst->data); tmp = lst; lst = lst->next; free(tmp); } } #ifdef TEST_ME int main(int argc, const char **argv) { PosinpList *lst, *tmp; lst = posinp_yaml_parse(argv[1], NULL); for (tmp = lst; tmp; tmp = tmp->next) { fprintf(stdout, "---\n"); posinp_atoms_trace(tmp->data); } posinp_yaml_free_list(lst); return 0; } #endif v_sim-3.8.0/src/coreTools/atoms_yaml.h000066400000000000000000000064231370110300500177100ustar00rootroot00000000000000/* !> @file !! Routines to read YAML position files. !! @author !! Copyright (C) 2007-2012 BigDFT group !! This file is distributed under the terms of the !! GNU General Public License, see ~/COPYING file !! or http://www.gnu.org/copyleft/gpl.txt . !! For the list of contributors, see ~/AUTHORS */ #ifndef ATOMS_YAML_H #define ATOMS_YAML_H typedef enum { POSINP_BC_FREE, /* 0, 0, 0 */ POSINP_BC_WIRE_Z, /* 0, 0, 1 */ POSINP_BC_WIRE_Y, /* 0, 1, 0 */ POSINP_BC_SURFACE_YZ, /* 0, 1, 1 */ POSINP_BC_WIRE_X, /* 1, 0, 0 */ POSINP_BC_SURFACE_XZ, /* 1, 0, 1 */ POSINP_BC_SURFACE_XY, /* 1, 1, 0 */ POSINP_BC_PERIODIC, /* 1, 1, 1 */ POSINP_N_BC } PosinpBC; typedef enum { POSINP_CELL_UNITS_BOHR, POSINP_CELL_UNITS_ANGSTROEM, POSINP_CELL_N_UNITS } PosinpCellUnits; typedef enum { POSINP_COORD_UNITS_BOHR, POSINP_COORD_UNITS_ANGSTROEM, POSINP_COORD_UNITS_REDUCED, POSINP_COORD_N_UNITS } PosinpCoordUnits; typedef enum { POSINP_FORCE_UNITS_HARTREE_PER_BOHR, POSINP_FORCE_UNITS_EV_PER_ANGSTROEM, POSINP_FORCE_N_UNITS } PosinpForceUnits; typedef enum { POSINP_ENERG_UNITS_HARTREE, POSINP_ENERG_UNITS_EV, POSINP_ENERG_UNITS_RYDBERG, POSINP_ENERG_N_UNITS } PosinpEnergUnits; typedef enum { POSINP_FROZEN_FREE, POSINP_FROZEN_FULL, POSINP_FROZEN_Y, POSINP_FROZEN_XZ, POSINP_N_FROZEN } PosinpFrozenType; typedef enum { POSINP_TYPE_INT, POSINP_TYPE_DBL, POSINP_TYPE_INT_ARR, POSINP_TYPE_DBL_ARR, POSINP_TYPE_STR, POSINP_TYPE_DICT } PosinpTypeId; typedef struct _PosinpDictEntry PosinpDictEntry; typedef struct _PosinpDict PosinpDict; struct _PosinpDict { unsigned int len; PosinpDictEntry *items; }; struct _PosinpDictEntry { char *key; PosinpTypeId type; union { int ival; struct { unsigned int len; int *arr; } iarr; double dval; struct { unsigned int len; double *arr; } darr; char *str; PosinpDict dict; } value; }; #define POSINP_SIGMA_SIZE 3 typedef double PosinpSigma[POSINP_SIGMA_SIZE]; typedef struct _PosinpPole { double q0; double q1[3]; double q2[5]; } PosinpPole; typedef struct _PosinpAtoms { /* The cell. */ PosinpBC BC; PosinpCellUnits Units; double acell[3], angdeg[3]; /* The positions. */ unsigned int nat, ntypes; PosinpCoordUnits units; double *rxyz; char **atomnames; /* Per atoms data. */ unsigned int *iatype, *ifrztyp; int *igspin, *igchg; PosinpDict *props; /* The forces. */ PosinpForceUnits funits; double fnrm, maxval; double *fxyz; /* External potential. */ PosinpCoordUnits punits; unsigned int npots; char **potnames; double *pxyz; PosinpSigma *psigma; PosinpPole *ppoles; /* Additional data. */ char *comment; PosinpEnergUnits eunits; double energy; unsigned int converged; double gnrm_wfn; } PosinpAtoms; typedef struct _PosinpList PosinpList; struct _PosinpList { PosinpList *next; PosinpAtoms *data; }; void posinp_yaml_parse(PosinpList **out, const char *filename, char **message); void posinp_yaml_free_list(PosinpList *lst); PosinpDict* posinp_yaml_parse_properties(const char *buffer, char **message); void posinp_yaml_free_properties(PosinpDict *dict); #endif v_sim-3.8.0/src/coreTools/toolArray.c000066400000000000000000000155321370110300500175130ustar00rootroot00000000000000/* EXTRAITS DE LA LICENCE Copyright CEA, contributeurs : Damien CALISTE, laboratoire L_Sim, (2016) Adresse mèl : CALISTE, damien P caliste AT cea P fr. Ce logiciel est un programme informatique servant à visualiser des structures atomiques dans un rendu pseudo-3D. Ce logiciel est régi par la licence CeCILL soumise au droit français et respectant les principes de diffusion des logiciels libres. Vous pouvez utiliser, modifier et/ou redistribuer ce programme sous les conditions de la licence CeCILL telle que diffusée par le CEA, le CNRS et l'INRIA sur le site "http://www.cecill.info". Le fait que vous puissiez accéder à cet en-tête signifie que vous avez pris connaissance de la licence CeCILL, et que vous en avez accepté les termes (cf. le fichier Documentation/licence.fr.txt fourni avec ce logiciel). */ /* LICENCE SUM UP Copyright CEA, contributors : Damien CALISTE, laboratoire L_Sim, (2016) E-mail address: CALISTE, damien P caliste AT cea P fr. This software is a computer program whose purpose is to visualize atomic configurations in 3D. This software is governed by the CeCILL license under French law and abiding by the rules of distribution of free software. You can use, modify and/ or redistribute the software under the terms of the CeCILL license as circulated by CEA, CNRS and INRIA at the following URL "http://www.cecill.info". The fact that you are presently reading this means that you have had knowledge of the CeCILL license and that you accept its terms. You can find a copy of this licence shipped with this software at Documentation/licence.en.txt. */ #include #include #include "toolArray.h" /** * SECTION:toolArray * @short_description: read text files formated in columns. * * Defines various routines to read text files formatted in columns. */ static GQuark quark = 0; /** * tool_array_getErrorQuark: * * Internal routine for error handling. * * Since: 3.8 * * Returns: the #GQuark associated to errors related to data * files. */ GQuark tool_array_getErrorQuark() { if (!quark) quark = g_quark_from_static_string("ToolArray"); return quark; } /** * tool_array_fromFile: * @filename: (type filename): a filename. * @nColumns: (out caller-allocates): a location for an integer. * @error: an error location. * * Read a data column file. * * Since: 3.8 * * Returns: (transfer full) (element-type float): a newly allocated #GArray. **/ GArray* tool_array_fromFile(const gchar *filename, guint *nColumns, GError **error) { GArray *array; GIOChannel *readFrom; GIOStatus status; GError *err; GString *line; gboolean voidLine; gsize term; gchar **dataRead; float *data, fval; guint i, nb0, nb; #if DEBUG == 1 GTimer *timer; gulong fractionTimer; #endif g_return_val_if_fail(error && (*error) == (GError*)0, FALSE); if (nColumns) *nColumns = 0; readFrom = g_io_channel_new_file(filename, "r", error); if (!readFrom) return (GArray*)0; DBG_fprintf(stderr, "Tool Array: begin reading file '%s'.\n", filename); #if DEBUG == 1 timer = g_timer_new(); g_timer_start(timer); #endif array = g_array_new(FALSE, FALSE, sizeof(float)); line = g_string_new(""); data = (float*)0; /* If the file is not finished, we read until a non-void line and return this line. */ nb0 = 0; do { voidLine = TRUE; do { err = (GError*)0; status = g_io_channel_read_line_string(readFrom, line, &term, &err); if (status == G_IO_STATUS_NORMAL) { g_strchug(line->str); voidLine = (line->str[0] == '#' || line->str[0] == '!' || line->str[0] == '\0'); } if (!voidLine) { dataRead = g_strsplit_set(line->str, " \t;:\n", TOOL_MAX_LINE_LENGTH); if (!data) { nb0 = 0; for (i = 0; dataRead[i]; i++) if (dataRead[i][0] && 1 == sscanf(dataRead[i], "%f", &fval)) nb0 += 1; data = g_malloc(sizeof(float) * nb0); } nb = 0; for (i = 0; dataRead[i] && nb < nb0; i++) if (1 == sscanf(dataRead[i], "%f", data + nb)) { DBG_fprintf(stderr, " '%s' - '%f'\n", dataRead[i], data[nb]); nb += 1; } for (i = nb; i < nb0; i++) data[i] = 0.f; g_strfreev(dataRead); voidLine = (nb == 0); } } while (status == G_IO_STATUS_NORMAL && voidLine); if (status == G_IO_STATUS_ERROR) { g_string_free(line, TRUE); g_free(data); g_array_free(array, TRUE); status = g_io_channel_shutdown(readFrom, FALSE, (GError**)0); g_io_channel_unref(readFrom); *error = err; return (GArray*)0; } if (!voidLine) g_array_append_vals(array, data, nb0); } while (status == G_IO_STATUS_NORMAL); g_free(data); g_string_free(line, TRUE); status = g_io_channel_shutdown(readFrom, FALSE, (GError**)0); g_io_channel_unref(readFrom); #if DEBUG == 1 g_timer_stop(timer); fprintf(stderr, "Tool Array: %d (%d) data associated in %g micro-s.\n", array->len, nb0, g_timer_elapsed(timer, &fractionTimer)/1e-6); g_timer_destroy(timer); #endif if (array->len == 0) g_set_error_literal(error, TOOL_ARRAY_ERROR, TOOL_ARRAY_ERROR_NO_COLUMN, _("Can't find any columns with numbers.\n" "Valid format are as much numbers as desired, separated" " by any of the following characters : [ ;:\\t].\n")); if (nColumns) *nColumns = nb0; return array; } /** * tool_array_sizedFromFile: * @filename: a path; * @size: expected number of read lines; * @nColumns: (out caller-allocates): number of read columns; * @error: an error pointer. * * Like tool_array_fromFile(), but check that the number of read lines * corresponds to the expected value given by @size. * * Since: 3.8 * * Returns: (transfer full) (element-type float): a newly allocated #GArray. **/ GArray* tool_array_sizedFromFile(const gchar *filename, guint size, guint *nColumns, GError **error) { GArray *array; guint nRead; guint n; array = tool_array_fromFile(filename, &n, error); nRead = array ? array->len / n : 0; if (nRead != size) { if (array) g_array_set_size(array, 0); g_set_error(error, TOOL_ARRAY_ERROR, TOOL_ARRAY_ERROR_MISSING_DATA, _("There is a different number of data (%d) compared to expected (%d).\n"), nRead, size); } if (nColumns) *nColumns = n; return array; } v_sim-3.8.0/src/coreTools/toolArray.h000066400000000000000000000046471370110300500175250ustar00rootroot00000000000000/* EXTRAITS DE LA LICENCE Copyright CEA, contributeurs : Damien CALISTE, laboratoire L_Sim, (2016) Adresse mèl : CALISTE, damien P caliste AT cea P fr. Ce logiciel est un programme informatique servant à visualiser des structures atomiques dans un rendu pseudo-3D. Ce logiciel est régi par la licence CeCILL soumise au droit français et respectant les principes de diffusion des logiciels libres. Vous pouvez utiliser, modifier et/ou redistribuer ce programme sous les conditions de la licence CeCILL telle que diffusée par le CEA, le CNRS et l'INRIA sur le site "http://www.cecill.info". Le fait que vous puissiez accéder à cet en-tête signifie que vous avez pris connaissance de la licence CeCILL, et que vous en avez accepté les termes (cf. le fichier Documentation/licence.fr.txt fourni avec ce logiciel). */ /* LICENCE SUM UP Copyright CEA, contributors : Damien CALISTE, laboratoire L_Sim, (2016) E-mail address: CALISTE, damien P caliste AT cea P fr. This software is a computer program whose purpose is to visualize atomic configurations in 3D. This software is governed by the CeCILL license under French law and abiding by the rules of distribution of free software. You can use, modify and/ or redistribute the software under the terms of the CeCILL license as circulated by CEA, CNRS and INRIA at the following URL "http://www.cecill.info". The fact that you are presently reading this means that you have had knowledge of the CeCILL license and that you accept its terms. You can find a copy of this licence shipped with this software at Documentation/licence.en.txt. */ #ifndef TOOLARRAY_H #define TOOLARRAY_H #include /** * TOOL_ARRAY_ERROR: (skip) * * Internal function for error handling. */ #define TOOL_ARRAY_ERROR tool_array_getErrorQuark() GQuark tool_array_getErrorQuark(); /** * ToolArrayErrorFlag: * @TOOL_ARRAY_ERROR_NO_COLUMN: no column can be found in the file ; * @TOOL_ARRAY_ERROR_MISSING_DATA: some data are missing to match the * required number of read data. * * Possible errors when reading a file with column data. */ typedef enum { TOOL_ARRAY_ERROR_NO_COLUMN, TOOL_ARRAY_ERROR_MISSING_DATA } ToolArrayErrorFlag; GArray* tool_array_fromFile(const gchar *filename, guint *nColumns, GError **error); GArray* tool_array_sizedFromFile(const gchar *filename, guint size, guint *nColumns, GError **error); #endif v_sim-3.8.0/src/coreTools/toolColor.c000066400000000000000000000407361370110300500175170ustar00rootroot00000000000000/* EXTRAITS DE LA LICENCE Copyright CEA, contributeurs : Luc BILLARD et Damien CALISTE, laboratoire L_Sim, (2001-2005) Adresse mèl : BILLARD, non joignable par mèl ; CALISTE, damien P caliste AT cea P fr. Ce logiciel est un programme informatique servant à visualiser des structures atomiques dans un rendu pseudo-3D. Ce logiciel est régi par la licence CeCILL soumise au droit français et respectant les principes de diffusion des logiciels libres. Vous pouvez utiliser, modifier et/ou redistribuer ce programme sous les conditions de la licence CeCILL telle que diffusée par le CEA, le CNRS et l'INRIA sur le site "http://www.cecill.info". Le fait que vous puissiez accéder à cet en-tête signifie que vous avez pris connaissance de la licence CeCILL, et que vous en avez accepté les termes (cf. le fichier Documentation/licence.fr.txt fourni avec ce logiciel). */ /* LICENCE SUM UP Copyright CEA, contributors : Luc BILLARD et Damien CALISTE, laboratoire L_Sim, (2001-2005) E-mail address: BILLARD, not reachable any more ; CALISTE, damien P caliste AT cea P fr. This software is a computer program whose purpose is to visualize atomic configurations in 3D. This software is governed by the CeCILL license under French law and abiding by the rules of distribution of free software. You can use, modify and/ or redistribute the software under the terms of the CeCILL license as circulated by CEA, CNRS and INRIA at the following URL "http://www.cecill.info". The fact that you are presently reading this means that you have had knowledge of the CeCILL license and that you accept its terms. You can find a copy of this licence shipped with this software at Documentation/licence.en.txt. */ #include "toolColor.h" #include #include #include #include /** * SECTION:toolColor * @short_description: Simple handling and storage of RGBA colours. * * This file defines a basic structure to store colours (not * using the GDK one beca use V_Sim core should not rely on GDK and * GTK): #ToolColor. Several transformations are possible on a colour, * going from and to RGB encoding. Use tool_color_convertHSVtoRGB() and * tool_color_convertHSLtoRGB() to do that. * * This file gives also the capability to store known colours in * a list. Use methods such as tool_color_addColor() or * tool_color_addFloatRGBA(). Them, one can access to stored colours, using * tool_color_getByValues() or tool_color_getByColor(). */ static ToolColor* color_copy(const ToolColor *boxed); static gint _compare(const ToolColor *color1, const ToolColor *color2); /******************/ /* Storing colors */ /******************/ static ToolPool *colorPool = NULL; #define N_BRIGHT_COLORS 20 static ToolColor brightColors[N_BRIGHT_COLORS] = {{{1,0,0, 1.f}, "", (gpointer)0}, {{0,1,0, 1.f}, "", (gpointer)0}, {{0,0,1, 1.f}, "", (gpointer)0}, {{1,0,1, 1.f}, "", (gpointer)0}, {{0,1,1, 1.f}, "", (gpointer)0}, {{1,1,0, 1.f}, "", (gpointer)0}, {{1,0.5,0, 1.f}, "", (gpointer)0}, {{0.5,0,0.5, 1.f}, "", (gpointer)0}, {{0,0.5,0.5, 1.f}, "", (gpointer)0}, {{0.5,0.5,0, 1.f}, "", (gpointer)0}, {{0.5,0,0, 1.f}, "", (gpointer)0}, {{0,0.5,0, 1.f}, "", (gpointer)0}, {{0,0,0.5, 1.f}, "", (gpointer)0}, {{0.5,0.5,0.5, 1.f}, "", (gpointer)0}, {{1,0,0.5, 1.f}, "", (gpointer)0}, {{0.5,1,0, 1.f}, "", (gpointer)0}, {{0.5,0,1, 1.f}, "", (gpointer)0}, {{0,1,0.5, 1.f}, "", (gpointer)0}, {{0,0.5,1, 1.f}, "", (gpointer)0}, {{0,0,0, 1.f}, "", (gpointer)0}}; /******************/ /* Storing colors */ /******************/ static void _initPool() { colorPool = tool_pool_new(TOOL_TYPE_COLOR, (GCompareFunc)_compare); } /** * tool_color_getStorage: * * Give access to the #ToolPool instance storing all the colors. * * Since: 3.8 * * Returns: (transfer none): a #ToolPool object. **/ ToolPool* tool_color_getStorage() { if (!colorPool) _initPool(); return colorPool; } /** * tool_color_new_bright: * @id: an index * * V_Sim has a list of 20 bright colors. One can get one by calling * this routine. The @id is taken modulo the number of available colors. * * Since: 3.7 * * Returns: (transfer none): a bright color. **/ const ToolColor* tool_color_new_bright(guint id) { return brightColors + (id % N_BRIGHT_COLORS); } /** * tool_color_get_type: * * Create and retrieve a #GType for a #ToolColor object. * * Since: 3.7 * * Returns: a new type for #ToolColor structures. */ GType tool_color_get_type(void) { static GType g_define_type_id = 0; if (g_define_type_id == 0) g_define_type_id = g_boxed_type_register_static("ToolColor", (GBoxedCopyFunc)color_copy, (GBoxedFreeFunc)g_free); return g_define_type_id; } /** * tool_color_new: * @rgba: (in) (array fixed-size=4): four values between 0. and * 1. that represent [Red, Green, Blue, Alpha]. * * Create a new color with initial values given as arguments. * * Returns: (transfer full): a new allocated #ToolColor (use g_free() to free it). */ ToolColor* tool_color_new(const float rgba[4]) { ToolColor *color; int i; color = g_malloc(sizeof(ToolColor)); for (i = 0; i< 4; i++) color->rgba[i] = CLAMP(rgba[i], 0.f, 1.f); color->userData = (gpointer)0; return color; } static gint _compare(const ToolColor *color1, const ToolColor *color2) { if (!color1 && !color2) return 0; if (!color1) return -1; if (!color2) return +1; if (color1->rgba[0] == color2->rgba[0] && color1->rgba[1] == color2->rgba[1] && color1->rgba[2] == color2->rgba[2] && color1->rgba[3] == color2->rgba[3]) return 0; if (color1 < color2) return -1; else return +1; } /** * tool_color_equal: * @color1: a #ToolColor ; * @color2: an other #ToolColor. * * Test if the two colours are the same. * * Returns: TRUE if the @rgba attributes are the same. */ gboolean tool_color_equal(const ToolColor *color1, const ToolColor *color2) { return (_compare(color1, color2) == 0); } /** * tool_color_getByValues: * @pos: (out caller-allocates) (allow-none): an allocated int to store the position of the found color ; * @red: a value between 0. and 1. ; * @green: a value between 0. and 1. ; * @blue: a value between 0. and 1. ; * @alpha: a value between 0. and 1.. * * This method is used to look for a specific color in the stored list. The argument @pos * is -1 if nothing is found or stores the position (beginning at 0) of the found color. * * Returns: (transfer none): the found color, or NULL if none exists. */ ToolColor* tool_color_getByValues(int *pos, float red, float green, float blue, float alpha) { gint found; ToolColor color; color.rgba[0] = CLAMP(red, 0.f, 1.f); color.rgba[1] = CLAMP(green, 0.f, 1.f); color.rgba[2] = CLAMP(blue, 0.f, 1.f); color.rgba[3] = CLAMP(alpha, 0.f, 1.f); if (!colorPool) _initPool(); found = tool_pool_index(colorPool, &color); if (pos) *pos = found; if (found < 0) return (ToolColor*)0; else return (ToolColor*)tool_pool_getById(colorPool, found); } static ToolColor* color_copy(const ToolColor *boxed) { ToolColor *color; if (!boxed) return (ToolColor*)0; color = g_malloc(sizeof(ToolColor)); tool_color_copy(color, boxed); return color; } /** * tool_color_copy: * @color: an allocated #ToolColor object to receive values ; * @color_old: a #ToolColor to read the values from. * * This method copies all values from @color_old to @color. */ void tool_color_copy(ToolColor *color, const ToolColor *color_old) { g_return_if_fail(color && color_old); memcpy(color->rgba, color_old->rgba, sizeof(float) * 4); color->userData = color_old->userData; } /** * tool_color_addFloatRGBA: * @rgba: four values between 0. and 1. that represent [Red, Green, Blue, Alpha] ; * @position: (out caller-allocates) (allow-none): an int pointer to store the position * of the returned colour. * * This method adds a new color in the list of stored colors with the given values. * If it already exits it returns the pointer of that color. * * Returns: (transfer none): a newly created #ToolColor or the already existing one. */ ToolColor* tool_color_addFloatRGBA(const float rgba[4], int *position) { ToolColor color, *found; found = tool_color_getByValues(position, rgba[0], rgba[1], rgba[2], rgba[3]); if (found) { DBG_fprintf(stderr, "Visu Tools : color already exist, no color added.\n"); return found; } color.rgba[0] = CLAMP(rgba[0], 0.f, 1.f); color.rgba[1] = CLAMP(rgba[1], 0.f, 1.f); color.rgba[2] = CLAMP(rgba[2], 0.f, 1.f); color.rgba[3] = CLAMP(rgba[3], 0.f, 1.f); found = (ToolColor*)tool_pool_add(colorPool, &color); if (position) *position = tool_pool_index(colorPool, found); DBG_fprintf(stderr, "Tool Color: adding a new color at %p (%d).\n", (gpointer)found, (position) ? *position : -1); return found; } /** * tool_color_addIntRGBA: * @rgba: four values between 0 and 255 that represent [Red, Green, Blue, Alpha]. * * This method adds a new color in the list of stored colors with the given values. * * Returns: (transfer none): a newly created #ToolColor or the already existing one. */ ToolColor* tool_color_addIntRGBA(int rgba[4]) { float rgbaf[4]; int i; for (i = 0; i < 4; i++) g_return_val_if_fail(rgba[i] >= 0 && rgba[i] < 256, (ToolColor*)0); for (i = 0; i < 4; i++) rgbaf[i] = (float)CLAMP(rgba[i], 0.f, 255.f) / 255.; return tool_color_addFloatRGBA(rgbaf, NULL); } /** * tool_color_fromStr: * @str: a string. * @pos: (out caller-allocates) (allow-none): a location. * * This method parse @str with the format %RRGGBB or %RRGGBBAA to * create a #ToolColor. This color is added to the pool, see * tool_color_getStorage(). * * Since: 3.8 * * Returns: (transfer none): a corresponding #ToolColor, creating it * if necessary. **/ const ToolColor* tool_color_fromStr(const gchar *str, int *pos) { guint repr[4]; gfloat rgba[4]; ToolColor *color; g_return_val_if_fail(str, (ToolColor*)0); if (str[0] != '#' || strlen(str) < 7) return (ToolColor*)0; if (sscanf(str + 1, "%2x%2x%2x", repr, repr + 1, repr + 2) != 3) return (ToolColor*)0; if (sscanf(str + 7, "%2x", repr + 3) != 1) repr[3] = 255; rgba[0] = (float)repr[0] / 255.; rgba[1] = (float)repr[1] / 255.; rgba[2] = (float)repr[2] / 255.; rgba[3] = (float)repr[3] / 255.; color = tool_color_getByValues(pos, rgba[0], rgba[1], rgba[2], rgba[3]); if (!color) color = tool_color_addFloatRGBA(rgba, pos); return color; } /** * tool_color_fromName: * @name: a string. * @pos: (out caller-allocates) (allow-none): a location. * * Parse a name like 'black' and generate a colour. This color is * added to the pool, see tool_color_getStorage(). * * Since: 3.8 * * Returns: (transfer none): a corresponding #ToolColor, creating it * if necessary. **/ const ToolColor* tool_color_fromName(const gchar *name, int *pos) { PangoColor color; gfloat rgba[4]; ToolColor *out; if (!pango_color_parse(&color, name)) { g_warning(_("cannot read a color from '%s' (name, #rgb, #rrggbb ... awaited).\n"), name); color.red = 0; color.green = 0; color.blue = 0; } rgba[0] = (float)color.red / (float)G_MAXUINT16; rgba[1] = (float)color.green / (float)G_MAXUINT16; rgba[2] = (float)color.blue / (float)G_MAXUINT16; rgba[3] = 1.f; out = tool_color_getByValues(pos, rgba[0], rgba[1], rgba[2], rgba[3]); if (!out) out = tool_color_addFloatRGBA(rgba, pos); return out; } /** * tool_color_asStr: * @color: a #ToolColor object. * * Gives a string representation of @color. The string is computed at * each call. * * Since: 3.8 * * Returns: a string representing @color. **/ const gchar* tool_color_asStr(ToolColor *color) { g_return_val_if_fail(color, (gchar*)0); sprintf(color->repr, "#%02x%02x%02x%02x", (guint)(color->rgba[0] * 255.), (guint)(color->rgba[1] * 255.), (guint)(color->rgba[2] * 255.), (guint)(color->rgba[3] * 255.)); return color->repr; } /** * tool_color_convertHSVtoRGB: * @rgb: an allocated 3 elements array to receive the RGB values ; * @hsv: a 3 elements array to retrieve the HSV values from. * * This methods convert a HSV color to a RGB one. */ void tool_color_convertHSVtoRGB(float* rgb, const float* hsv) { float var_h, var_0, var_1, var_2, var_3; int var_i; g_return_if_fail(rgb && hsv); if (hsv[1] == 0) { rgb[0] = hsv[2]; rgb[1] = hsv[2]; rgb[2] = hsv[2]; } else { var_h = hsv[0] * 6.; var_i = (int)var_h; var_0 = hsv[2]; var_1 = hsv[2] * (1. - hsv[1]); var_2 = hsv[2] * (1. - hsv[1] * (var_h - (float)var_i)); var_3 = hsv[2] * (1. - hsv[1] * (1. - (var_h - (float)var_i))); switch (var_i % 6) { case 0: rgb[0] = var_0; rgb[1] = var_3; rgb[2] = var_1; break; case 1: rgb[0] = var_2; rgb[1] = var_0; rgb[2] = var_1; break; case 2: rgb[0] = var_1; rgb[1] = var_0; rgb[2] = var_3; break; case 3: rgb[0] = var_1; rgb[1] = var_2; rgb[2] = var_0; break; case 4: rgb[0] = var_3; rgb[1] = var_1; rgb[2] = var_0; break; case 5: rgb[0] = var_0; rgb[1] = var_1; rgb[2] = var_2; break; } } } float Hue_2_RGB(float v1, float v2, float vH) { /* from www.easyrgb.com */ if (vH < 0) vH += 1; if (vH > 1) vH -= 1; if ((6*vH) < 1) return (v1+(v2-v1)*6*vH); if ((2*vH) < 1) return v2; if ((3*vH) < 2) return (v1+(v2-v1)*((2./3.)-vH)*6); return v1; } /** * tool_color_convertHSLtoRGB: * @rgb: an allocated 3 elements array to receive the RGB values ; * @hsl: a 3 elements array to retrieve the HSL values from. * * This methods convert a HSL color to a RGB one. */ void tool_color_convertHSLtoRGB(float *rgb, const float *hsl) { /* from www.easyrgb.com */ if (hsl[1] == 0) /*HSL values = 0 ÷ 1*/ { rgb[0] = hsl[2]; /*RGB results = 0 ÷ 255*/ rgb[1] = hsl[2]; rgb[2] = hsl[2]; } else { float var_1, var_2; if (hsl[2] < 0.5) var_2 = hsl[2] * (1 + hsl[1]); else var_2 = (hsl[2] + hsl[1]) - (hsl[1] * hsl[2]); var_1 = 2 * hsl[2] - var_2; rgb[0] = Hue_2_RGB( var_1, var_2, hsl[0] + ( 1. / 3. ) ); rgb[1] = Hue_2_RGB( var_1, var_2, hsl[0] ); rgb[2] = Hue_2_RGB( var_1, var_2, hsl[0] - ( 1. / 3. ) ); } } /** * tool_color_convertRGBtoHSL: * @hsl: three float to store the HSL value ; * @rgb: three floats giving the RGB values. * * Convert a RGB colour into a HSL one. */ void tool_color_convertRGBtoHSL(float *hsl, const float *rgb) { float var_Min, var_Max, del_Max, del_R, del_G, del_B; var_Min = MIN(MIN( rgb[0], rgb[1]), rgb[2] ); var_Max = MAX(MAX( rgb[0], rgb[1]), rgb[2] ); del_Max = var_Max - var_Min; hsl[2] = ( var_Max + var_Min ) / 2; if ( del_Max == 0 ) { hsl[0] = 0.f; hsl[1] = 0.f; } else { if ( hsl[2] < 0.5f ) hsl[1] = del_Max / ( var_Max + var_Min ); else hsl[1] = del_Max / ( 2.f - var_Max - var_Min ); del_R = ( ( ( var_Max - rgb[0] ) / 6 ) + ( del_Max / 2 ) ) / del_Max; del_G = ( ( ( var_Max - rgb[1] ) / 6 ) + ( del_Max / 2 ) ) / del_Max; del_B = ( ( ( var_Max - rgb[2] ) / 6 ) + ( del_Max / 2 ) ) / del_Max; if ( rgb[0] == var_Max ) hsl[0] = del_B - del_G; else if ( rgb[1] == var_Max ) hsl[0] = ( 1.f / 3.f ) + del_R - del_B; else if ( rgb[2] == var_Max ) hsl[0] = ( 2.f / 3.f ) + del_G - del_R; if ( hsl[0] < 0.f ) hsl[0] += 1; if ( hsl[0] > 1.f ) hsl[0] -= 1; } } /** * tool_color_invertRGBA: * @inv: a location to store the inverted colour. * @rgba: a colour defined in RGBA. * * Invert the colour on the stack. * * Since: 3.8 **/ void tool_color_invertRGBA(float inv[4], const float rgba[4]) { inv[0] = 1.f - rgba[0]; inv[1] = 1.f - rgba[1]; inv[2] = 1.f - rgba[2]; inv[3] = rgba[3]; } static gpointer material_copy(gpointer boxed) { return g_memdup(boxed, sizeof(gfloat) * TOOL_MATERIAL_N_VALUES); } /** * tool_material_get_type: * * Create and retrieve a #GType for a #ToolMaterial object. * * Since: 3.8 * * Returns: a new type for #ToolVector structures. */ GType tool_material_get_type(void) { static GType g_define_type_id = 0; if (g_define_type_id == 0) g_define_type_id = g_boxed_type_register_static("ToolMaterial", material_copy, g_free); return g_define_type_id; } v_sim-3.8.0/src/coreTools/toolColor.h000066400000000000000000000133721370110300500175200ustar00rootroot00000000000000/* EXTRAITS DE LA LICENCE Copyright CEA, contributeurs : Luc BILLARD et Damien CALISTE, laboratoire L_Sim, (2001-2005) Adresse mèl : BILLARD, non joignable par mèl ; CALISTE, damien P caliste AT cea P fr. Ce logiciel est un programme informatique servant à visualiser des structures atomiques dans un rendu pseudo-3D. Ce logiciel est régi par la licence CeCILL soumise au droit français et respectant les principes de diffusion des logiciels libres. Vous pouvez utiliser, modifier et/ou redistribuer ce programme sous les conditions de la licence CeCILL telle que diffusée par le CEA, le CNRS et l'INRIA sur le site "http://www.cecill.info". Le fait que vous puissiez accéder à cet en-tête signifie que vous avez pris connaissance de la licence CeCILL, et que vous en avez accepté les termes (cf. le fichier Documentation/licence.fr.txt fourni avec ce logiciel). */ /* LICENCE SUM UP Copyright CEA, contributors : Luc BILLARD et Damien CALISTE, laboratoire L_Sim, (2001-2005) E-mail address: BILLARD, not reachable any more ; CALISTE, damien P caliste AT cea P fr. This software is a computer program whose purpose is to visualize atomic configurations in 3D. This software is governed by the CeCILL license under French law and abiding by the rules of distribution of free software. You can use, modify and/ or redistribute the software under the terms of the CeCILL license as circulated by CEA, CNRS and INRIA at the following URL "http://www.cecill.info". The fact that you are presently reading this means that you have had knowledge of the CeCILL license and that you accept its terms. You can find a copy of this licence shipped with this software at Documentation/licence.en.txt. */ #ifndef TOOLCOLOR_H #define TOOLCOLOR_H #include #include #include "toolPool.h" G_BEGIN_DECLS /** * TOOL_COLOR_MASK_R: * * This value can be used to create a mask for methods that * require one for reading rgb color array. This value actually * correspond to red. */ #define TOOL_COLOR_MASK_R (1 << 0) /** * TOOL_COLOR_MASK_G: * * This value can be used to create a mask for methods that * require one for reading rgb color array. This value actually * correspond to green. */ #define TOOL_COLOR_MASK_G (1 << 1) /** * TOOL_COLOR_MASK_B: * * This value can be used to create a mask for methods that * require one for reading rgb color array. This value actually * correspond to blue. */ #define TOOL_COLOR_MASK_B (1 << 2) /** * TOOL_COLOR_MASK_A: * * This value can be used to create a mask for methods that * require one for reading rgb color array. This value actually * correspond to the alpha channel. */ #define TOOL_COLOR_MASK_A (1 << 3) /** * TOOL_COLOR_MASK_RGBA: * * This value can be used to create a mask for methods that * require one for reading rgb color array. This value is a * shortcut for #TOOL_COLOR_MASK_R | #TOOL_COLOR_MASK_G | #TOOL_COLOR_MASK_B. */ #define TOOL_COLOR_MASK_RGBA (15) /** * ToolColorChannel: * @TOOL_COLOR_RED: the red channel. * @TOOL_COLOR_GREEN: the red channel. * @TOOL_COLOR_BLUE: the red channel. * @TOOL_COLOR_ALPHA: the red channel. * * Index to be used whenever accessing red, green or blue channels is * required. * * Since: 3.8 */ typedef enum { TOOL_COLOR_RED, TOOL_COLOR_GREEN, TOOL_COLOR_BLUE, TOOL_COLOR_ALPHA } ToolColorChannel; /******************/ /* Storing colors */ /******************/ /** * ToolColor: * @rgba: the coding of color in Red, Green, Blue, Alpha format, * floating point numbers between 0 and 1 ; * @repr: store the representation of the colour as "#rrggbbaa". * @userData: unused. * * A structure to store colors. @repr is not set before * tool_color_asStr() is called. Any changes in @rgba are not * transfered to @repr and tool_color_asStr() should be called again. */ typedef struct _ToolColor ToolColor; struct _ToolColor { float rgba[4]; gchar repr[10]; gpointer userData; }; #define TOOL_TYPE_COLOR (tool_color_get_type()) GType tool_color_get_type(void); ToolColor* tool_color_new(const float rgba[4]); const ToolColor* tool_color_new_bright(guint id); gboolean tool_color_equal(const ToolColor *color1, const ToolColor *color2); void tool_color_copy(ToolColor *color, const ToolColor *color_old); ToolPool* tool_color_getStorage(); ToolColor* tool_color_getByValues(int *pos, float red, float green, float blue, float alpha); ToolColor* tool_color_addFloatRGBA(const float rgba[4], int *position); ToolColor* tool_color_addIntRGBA(int rgba[4]); const ToolColor* tool_color_fromStr(const gchar *str, int *pos); const gchar* tool_color_asStr(ToolColor *color); const ToolColor* tool_color_fromName(const gchar *name, int *pos); void tool_color_invertRGBA(float inv[4], const float rgba[4]); void tool_color_convertHSVtoRGB(float* rgb, const float* hsv); void tool_color_convertHSLtoRGB(float *rgb, const float *hsl); void tool_color_convertRGBtoHSL(float *hsl, const float *rgb); /** * ToolMaterialIds: * @TOOL_MATERIAL_AMB: the ambient identifier ; * @TOOL_MATERIAL_DIF: the diffuse identifier ; * @TOOL_MATERIAL_SHI: the shiningness identifier ; * @TOOL_MATERIAL_SPE: the specular identifier ; * @TOOL_MATERIAL_EMI: the emissivity identifier ; * @TOOL_MATERIAL_N_VALUES: number of used material identifiers. * * This enum is used to address the OpenGL parameters for light rendering. */ typedef enum { TOOL_MATERIAL_AMB, TOOL_MATERIAL_DIF, TOOL_MATERIAL_SHI, TOOL_MATERIAL_SPE, TOOL_MATERIAL_EMI, TOOL_MATERIAL_N_VALUES } ToolMaterialIds; /** * ToolMaterial: * * A type used to exchange five floats defining material values between * #GObject properties. */ #define TOOL_TYPE_MATERIAL (tool_material_get_type()) GType tool_material_get_type(void); G_END_DECLS #endif v_sim-3.8.0/src/coreTools/toolConfigFile.c000066400000000000000000000464351370110300500204500ustar00rootroot00000000000000/* EXTRAITS DE LA LICENCE Copyright CEA, contributeurs : Luc BILLARD et Damien CALISTE, laboratoire L_Sim, (2001-2005) Adresse mèl : BILLARD, non joignable par mèl ; CALISTE, damien P caliste AT cea P fr. Ce logiciel est un programme informatique servant à visualiser des structures atomiques dans un rendu pseudo-3D. Ce logiciel est régi par la licence CeCILL soumise au droit français et respectant les principes de diffusion des logiciels libres. Vous pouvez utiliser, modifier et/ou redistribuer ce programme sous les conditions de la licence CeCILL telle que diffusée par le CEA, le CNRS et l'INRIA sur le site "http://www.cecill.info". Le fait que vous puissiez accéder à cet en-tête signifie que vous avez pris connaissance de la licence CeCILL, et que vous en avez accepté les termes (cf. le fichier Documentation/licence.fr.txt fourni avec ce logiciel). */ /* LICENCE SUM UP Copyright CEA, contributors : Luc BILLARD et Damien CALISTE, laboratoire L_Sim, (2001-2005) E-mail address: BILLARD, not reachable any more ; CALISTE, damien P caliste AT cea P fr. This software is a computer program whose purpose is to visualize atomic configurations in 3D. This software is governed by the CeCILL license under French law and abiding by the rules of distribution of free software. You can use, modify and/ or redistribute the software under the terms of the CeCILL license as circulated by CEA, CNRS and INRIA at the following URL "http://www.cecill.info". The fact that you are presently reading this means that you have had knowledge of the CeCILL license and that you accept its terms. You can find a copy of this licence shipped with this software at Documentation/licence.en.txt. */ #include "toolConfigFile.h" #include /** * SECTION:toolConfigFile * @short_description: Generic read methods of the configuration files * are defined here. * * These methods give generic tools to read common data in the * configuration files, such as arrays of float values or one * #VisuElement... It also defines a enumeration of detailed errors * (see #ToolConfigFileError) when reading a file. All read elements * are either from tokens (given g_strsplit()) or strings. */ /** * tool_config_file_getQuark: * * Internal routine for error handling. * * Returns: the #GQuark associated to errors related to configuration * files. */ GQuark tool_config_file_getQuark() { return g_quark_from_static_string("visu_configFile"); } /** * tool_config_file_readFloatFromTokens: * @tokens: array of tokens resulting from a call to g_strsplit() with " " as separator ; * @position: IN, the position of the beginning in @tokens ; OUT, one token * after the last read ; * @values: allocated area to store read values ; * @size: the number of floating point values to be read ; * @lineId: the number of the line of the config * file which the @line argument is taken from ; * @error: a location to store a possible reading error. * * Read @size floating point values from @tokens, store them in @values and returns * the new head in @tokens. * * Returns: TRUE if no error occured. */ gboolean tool_config_file_readFloatFromTokens(gchar **tokens, int *position, float *values, guint size, int lineId, GError **error) { int res; guint i, nb; g_return_val_if_fail(error && (*error == (GError*)0), FALSE); g_return_val_if_fail(values, FALSE); g_return_val_if_fail(tokens && position, FALSE); /* Read @size floating point values from tokens. */ nb = 0; for (i = *position; tokens[i] && nb < size; i++) { if (tokens[i][0] != '\0') { res = sscanf(tokens[i], "%f", values + nb); if (res != 1) { *error = g_error_new(TOOL_CONFIG_FILE_ERROR, TOOL_CONFIG_FILE_ERROR_READ, _("Parse error at line %d, %d floating point" " values should appear here.\n"), lineId, size); *position = i; return FALSE; } nb += 1; } } *position = i; if (nb != size) { *error = g_error_new(TOOL_CONFIG_FILE_ERROR, TOOL_CONFIG_FILE_ERROR_MISSING, _("Parse error at line %d, %d floating point value(s)" " should appear here but %d has been found.\n"), lineId, size, nb); return FALSE; } return TRUE; } /** * tool_config_file_readFloat: * @line: string where values are read from ; * @position: the number of the line of the config * file which the @line argument is taken from ; * @values: allocated area to store read values ; * @size: the number of floating point values to be read ; * @error: a location to store a possible reading error. * * Read @size floating point values from @line and store them in @values. * * Returns: TRUE if no error occured. */ gboolean tool_config_file_readFloat(gchar *line, int position, float *values, guint size, GError **error) { int id; gboolean res; gchar **tokens; /* Read @size floating point values from @line. */ tokens = g_strsplit_set(line, " \n", TOOL_MAX_LINE_LENGTH); id = 0; res = tool_config_file_readFloatFromTokens(tokens, &id, values, size, position, error); g_strfreev(tokens); return res; } /** * tool_config_file_readBooleanFromTokens: * @tokens: array of tokens resulting from a call to g_strsplit() with " " as separator ; * @position: IN, the position of the beginning in @tokens ; OUT, one token * after the last read ; * @values: allocated area to store read values ; * @size: the number of floating point values to be read ; * @lineId: the number of the line of the config * file which the @line argument is taken from ; * @error: a location to store a possible reading error. * * Read @size boolean values from @tokens, store them in @values and returns * the new head in @tokens. * * Returns: TRUE if no error occured. */ gboolean tool_config_file_readBooleanFromTokens(gchar **tokens, int *position, gboolean *values, guint size, int lineId, GError **error) { int res; guint i, nb; g_return_val_if_fail(error && (*error == (GError*)0), FALSE); g_return_val_if_fail(values, FALSE); g_return_val_if_fail(tokens && position, FALSE); /* Read @size floating point values from @line. */ nb = 0; for (i = *position; tokens[i] && nb < size; i++) { if (tokens[i][0] != '\0') { res = sscanf(tokens[i], "%d", values + nb); if (res != 1) { *error = g_error_new(TOOL_CONFIG_FILE_ERROR, TOOL_CONFIG_FILE_ERROR_READ, _("Parse error at line %d, %d boolean" " values should appear here.\n"), lineId, size); *position = i; return FALSE; } nb += 1; } } *position = i; if (nb != size) { *error = g_error_new(TOOL_CONFIG_FILE_ERROR, TOOL_CONFIG_FILE_ERROR_MISSING, _("Parse error at line %d, %d boolean(s)" " values should appear here but %d has been found.\n"), lineId, size, nb); return FALSE; } return TRUE; } /** * tool_config_file_readBoolean: * @line: string where values are read from ; * @position: the number of the line of the config * file which the @line argument is taken from ; * @values: allocated area to store read values ; * @size: the number of boolean values to be read ; * @error: a location to store a possible reading error. * * Read @size boolean values from @line and store them in @values. * * Returns: TRUE if no error occured. */ gboolean tool_config_file_readBoolean(gchar *line, int position, gboolean *values, guint size, GError **error) { int id; gboolean res; gchar **tokens; /* Read @size boolean values from @line. */ tokens = g_strsplit_set(line, " \n", TOOL_MAX_LINE_LENGTH); id = 0; res = tool_config_file_readBooleanFromTokens(tokens, &id, values, size, position, error); g_strfreev(tokens); return res; } /** * tool_config_file_readStringFromTokens: * @tokens: array of tokens resulting from a call to g_strsplit() with " " as separator ; * @position: IN, the position of the beginning in @tokens ; OUT, one token * after the last read ; * @values: a location to point on a gchar** ; * @size: the number of floating point values to be read ; * @lineId: the number of the line of the config * file which the @line argument is taken from ; * @error: a location to store a possible reading error. * * Read @size strings from @tokens, store them in @values and returns * the new head in @tokens. * * Returns: TRUE if no error occured. */ gboolean tool_config_file_readStringFromTokens(gchar **tokens, int *position, gchar ***values, guint size, int lineId, GError **error) { guint i, nb; g_return_val_if_fail(error && (*error == (GError*)0), FALSE); g_return_val_if_fail(values, FALSE); g_return_val_if_fail(tokens && position, FALSE); /* Read @size floating point values from @line. */ *values = g_malloc(sizeof(gchar**) * (size + 1)); nb = 0; for (i = *position; tokens[i] && nb < size; i++) if (tokens[i][0] != '\0') (*values)[nb++] = g_strdup(tokens[i]); *position = i; (*values)[nb] = (gchar*)0; if (nb != size) { *error = g_error_new(TOOL_CONFIG_FILE_ERROR, TOOL_CONFIG_FILE_ERROR_MISSING, _("Parse error at line %d, %d string(s)" " should appear here but %d has been found.\n"), lineId, size, nb); g_strfreev(*values); *values = (gchar**)0; return FALSE; } return TRUE; } /** * tool_config_file_readString: * @line: string where values are read from ; * @position: the number of the line of the config * file which the @line argument is taken from ; * @values: a location to point on a gchar** ; * @size: the number of strings to be read ; * @join: a boolean ; * @error: a location to store a possible reading error. * * Read @size strings from @line and @values points on them. If more * strings than @size are available, an error is raised ; except if * @join is TRUE. In that case, the method return @size tokens, * joining all remaining ones. * * Returns: TRUE if no error occured, then @values point on an allocated * memory area that is NULL terminated and that must be freed * with g_strfreev(). */ gboolean tool_config_file_readString(gchar *line, int position, gchar ***values, guint size, gboolean join, GError **error) { guint i, nb; gchar *tmp; g_return_val_if_fail(error && (*error == (GError*)0), FALSE); g_return_val_if_fail(values, FALSE); /* Read @size floating point values from @line. */ *values = g_strsplit_set(line, " \n", TOOL_MAX_LINE_LENGTH); nb = 0; for (i = 0; (*values)[i]; i++) if ((*values)[i][0] != '\0') { tmp = (*values)[i]; (*values)[i] = (*values)[nb]; (*values)[nb] = tmp; nb += 1; } if (!join) { if (nb != size) { *error = g_error_new(TOOL_CONFIG_FILE_ERROR, TOOL_CONFIG_FILE_ERROR_MISSING, _("Parse error at line %d, %d string(s)" " should appear here but %d has been found.\n"), position, size, nb); g_strfreev(*values); return FALSE; } } else { tmp = g_strjoinv(" ", (*values) + (size - 1)); for (i = size - 1; (*values)[i]; i++) g_free((*values)[i]); (*values)[size - 1] = tmp; (*values)[size] = (gchar*)0; } return TRUE; } /** * tool_config_file_readBooleanWithLabel: * @line: string where values are read from ; * @position: the number of the line of the config * file which the @line argument is taken from ; * @values: allocated area to store read values ; * @size: the number of boolean values to be read ; * @label: (allow-none): a location to store a string ; * @error: a location to store a possible reading error. * * Same as tool_config_file_readBoolean() but begins by reading a * string label at the begining of the line and store it in @label. If * @label is %NULL, only booleans are parsed. * * Since: 3.8 * * Returns: TRUE if no error occured. */ gboolean tool_config_file_readBooleanWithLabel(gchar *line, int position, gboolean *values, guint size, gchar **label, GError **error) { int id; gboolean res; gchar **tokens; /* Read @size boolean values from @line. */ tokens = g_strsplit_set(line, " \n", TOOL_MAX_LINE_LENGTH); id = 0; if (label) { while (tokens[id] && !tokens[id][0]) id++; if (!tokens[id]) { *error = g_error_new(TOOL_CONFIG_FILE_ERROR, TOOL_CONFIG_FILE_ERROR_MISSING, _("Parse error at line %d, a label" " should appear here but none has been found.\n"), position); g_strfreev(tokens); return FALSE; } *label = g_strdup(tokens[id]); DBG_fprintf(stderr, "Tool ConfigFile: found a label '%s'.\n", *label); id += 1; } res = tool_config_file_readBooleanFromTokens(tokens, &id, values, size, position, error); g_strfreev(tokens); return res; } /** * tool_config_file_readFloatWithLabel: * @line: string where values are read from ; * @position: the number of the line of the config * file which the @line argument is taken from ; * @values: allocated area to store read values ; * @size: the number of float values to be read ; * @label: (allow-none): a location to store a string ; * @error: a location to store a possible reading error. * * Same as tool_config_file_readFloat() but begins by reading a * string label at the begining of the line and store it in @label. If * @label is %NULL, only floats are parsed. * * Since: 3.8 * * Returns: TRUE if no error occured. */ gboolean tool_config_file_readFloatWithLabel(gchar *line, int position, gfloat *values, guint size, gchar **label, GError **error) { int id; gboolean res; gchar **tokens; /* Read @size float values from @line. */ tokens = g_strsplit_set(line, " \n", TOOL_MAX_LINE_LENGTH); id = 0; if (label) { while (tokens[id] && !tokens[id][0]) id++; if (!tokens[id]) { *error = g_error_new(TOOL_CONFIG_FILE_ERROR, TOOL_CONFIG_FILE_ERROR_MISSING, _("Parse error at line %d, a label" " should appear here but none has been found.\n"), position); g_strfreev(tokens); return FALSE; } *label = g_strdup(tokens[id]); DBG_fprintf(stderr, "Tool ConfigFile: found a label '%s'.\n", *label); id += 1; } res = tool_config_file_readFloatFromTokens(tokens, &id, values, size, position, error); g_strfreev(tokens); return res; } /* gboolean tool_config_file_readStringWithElement(gchar *line, int position, gchar ***values, */ /* guint size, VisuElement **ele, GError **error) */ /* { */ /* int id; */ /* gboolean res; */ /* gchar **tokens; */ /* /\* Read @size boolean values from @line. *\/ */ /* tokens = g_strsplit_set(line, " \n", TOOL_MAX_LINE_LENGTH); */ /* id = 0; */ /* res = tool_config_file_readElementFromTokens(tokens, &id, ele, 1, position, error); */ /* if (!res) */ /* { */ /* g_strfreev(tokens); */ /* return FALSE; */ /* } */ /* res = tool_config_file_readStringFromTokens(tokens, &id, values, size, position, error); */ /* g_strfreev(tokens); */ /* return res; */ /* } */ /** * tool_config_file_readIntegerFromTokens: * @tokens: array of tokens resulting from a call to g_strsplit() with " " as separator ; * @position: IN, the position of the beginning in @tokens ; OUT, one token * after the last read ; * @values: allocated area to store read values ; * @size: the number of floating point values to be read ; * @lineId: the number of the line of the config * file which the @line argument is taken from ; * @error: a location to store a possible reading error. * * Read @size integer values from @tokens, store them in @values and returns * the new head in @tokens. * * Returns: TRUE if no error occured. */ gboolean tool_config_file_readIntegerFromTokens(gchar **tokens, int *position, int *values, guint size, int lineId, GError **error) { int res; guint i, nb; g_return_val_if_fail(error && (*error == (GError*)0), FALSE); g_return_val_if_fail(values, FALSE); g_return_val_if_fail(tokens && position, FALSE); /* Read @size floating point values from @line. */ nb = 0; for (i = *position; tokens[i] && nb < size; i++) { if (tokens[i][0] != '\0') { res = sscanf(tokens[i], "%d", values + nb); if (res != 1) { *error = g_error_new(TOOL_CONFIG_FILE_ERROR, TOOL_CONFIG_FILE_ERROR_READ, _("Parse error at line %d, %d integer" " values should appear here.\n"), lineId, size); *position = i; return FALSE; } nb += 1; } } *position = i; if (nb != size) { *error = g_error_new(TOOL_CONFIG_FILE_ERROR, TOOL_CONFIG_FILE_ERROR_MISSING, _("Parse error at line %d, %d integer(s)" " values should appear here but %d has been found.\n"), lineId, size, nb); return FALSE; } return TRUE; } /** * tool_config_file_readInteger: * @line: string where values are read from ; * @position: the number of the line of the config * file which the @line argument is taken from ; * @values: allocated area to store read values ; * @size: the number of floating point values to be read ; * @error: a location to store a possible reading error. * * Read @size integers from @line and store them in @values. * * Returns: TRUE if no error occured. */ gboolean tool_config_file_readInteger(gchar *line, int position, int *values, guint size, GError **error) { int id; gboolean res; gchar **tokens; /* Read @size floating point values from @line. */ tokens = g_strsplit_set(line, " \n", TOOL_MAX_LINE_LENGTH); id = 0; res = tool_config_file_readIntegerFromTokens(tokens, &id, values, size, position, error); g_strfreev(tokens); return res; } /** * tool_config_file_clampFloat: * @variable: a pointer to a storage for the value ; * @value: the value to put in the storage ; * @min: a lower bound ; * @max: a upper bound. * * It puts value in a variable if value is in min and max * or put min or max in if not. It return true if value * is out of bounds. Min and max are inclusive values. * If there is no max bounds then put max at a lower * value than min and if there is no min bound, put min * at a higher value than max. * * Returns: TRUE if the value is out of bounds. */ gboolean tool_config_file_clampFloat(float *variable, float value, float min, float max) { g_return_val_if_fail(variable, FALSE); if (max > min && value > max) { *variable = max; return TRUE; } if (min < max && value < min) { *variable = min; return TRUE; } *variable = value; return FALSE; } /** * tool_config_file_clampInt: * @variable: a pointer to a storage for the value ; * @value: the value to put in the storage ; * @min: a lower bound ; * @max: a upper bound. * * Integer version o tool_config_file_clampFloat(). * * Since: 3.8 * * Returns: TRUE if the value is out of bounds. */ gboolean tool_config_file_clampInt(int *variable, int value, int min, int max) { g_return_val_if_fail(variable, FALSE); if (max > min && value > max) { *variable = max; return TRUE; } if (min < max && value < min) { *variable = min; return TRUE; } *variable = value; return FALSE; } v_sim-3.8.0/src/coreTools/toolConfigFile.h000066400000000000000000000107411370110300500204440ustar00rootroot00000000000000/* EXTRAITS DE LA LICENCE Copyright CEA, contributeurs : Luc BILLARD et Damien CALISTE, laboratoire L_Sim, (2001-2005) Adresse mèl : BILLARD, non joignable par mèl ; CALISTE, damien P caliste AT cea P fr. Ce logiciel est un programme informatique servant à visualiser des structures atomiques dans un rendu pseudo-3D. Ce logiciel est régi par la licence CeCILL soumise au droit français et respectant les principes de diffusion des logiciels libres. Vous pouvez utiliser, modifier et/ou redistribuer ce programme sous les conditions de la licence CeCILL telle que diffusée par le CEA, le CNRS et l'INRIA sur le site "http://www.cecill.info". Le fait que vous puissiez accéder à cet en-tête signifie que vous avez pris connaissance de la licence CeCILL, et que vous en avez accepté les termes (cf. le fichier Documentation/licence.fr.txt fourni avec ce logiciel). */ /* LICENCE SUM UP Copyright CEA, contributors : Luc BILLARD et Damien CALISTE, laboratoire L_Sim, (2001-2005) E-mail address: BILLARD, not reachable any more ; CALISTE, damien P caliste AT cea P fr. This software is a computer program whose purpose is to visualize atomic configurations in 3D. This software is governed by the CeCILL license under French law and abiding by the rules of distribution of free software. You can use, modify and/ or redistribute the software under the terms of the CeCILL license as circulated by CEA, CNRS and INRIA at the following URL "http://www.cecill.info". The fact that you are presently reading this means that you have had knowledge of the CeCILL license and that you accept its terms. You can find a copy of this licence shipped with this software at Documentation/licence.en.txt. */ #ifndef TOOLCONFIGFILE_H #define TOOLCONFIGFILE_H #include /** * TOOL_CONFIG_FILE_ERROR: * * Domain used to parse config files. */ #define TOOL_CONFIG_FILE_ERROR tool_config_file_getQuark() GQuark tool_config_file_getQuark(); /** * ToolConfigFileError: * @TOOL_CONFIG_FILE_ERROR_EMPTY_LINE: error when reading the file, found an empty line, * where something should have been. * @TOOL_CONFIG_FILE_ERROR_VALUE: error of file format, values read are out of bounds. * @TOOL_CONFIG_FILE_ERROR_READ: error of file format (can't read variables...). * @TOOL_CONFIG_FILE_ERROR_MISSING: error of file format (missing * variables...). * @TOOL_CONFIG_FILE_ERROR_TAG: error dealing with a tag. * @TOOL_CONFIG_FILE_ERROR_MARKUP: error dealing with a markup (unkown * one...). * @TOOL_CONFIG_FILE_ERROR_NO_FILE: no valid file found on disk. * * Possible errors when parsing a config file. */ typedef enum { TOOL_CONFIG_FILE_ERROR_EMPTY_LINE, TOOL_CONFIG_FILE_ERROR_VALUE, TOOL_CONFIG_FILE_ERROR_READ, TOOL_CONFIG_FILE_ERROR_MISSING, TOOL_CONFIG_FILE_ERROR_TAG, TOOL_CONFIG_FILE_ERROR_MARKUP, TOOL_CONFIG_FILE_ERROR_NO_FILE } ToolConfigFileError; gboolean tool_config_file_readFloatFromTokens(gchar **tokens, int *position, float *values, guint size, int lineId, GError **error); gboolean tool_config_file_readFloat(gchar *line, int position, float *values, guint size, GError **error); gboolean tool_config_file_readIntegerFromTokens(gchar **tokens, int *position, int *values, guint size, int lineId, GError **error); gboolean tool_config_file_readInteger(gchar *line, int position, int *values, guint size, GError **error); gboolean tool_config_file_readBooleanFromTokens(gchar **tokens, int *position, gboolean *values, guint size, int lineId, GError **error); gboolean tool_config_file_readBoolean(gchar *line, int position, gboolean *values, guint size, GError **error); gboolean tool_config_file_readStringFromTokens(gchar **tokens, int *position, gchar ***values, guint size, int lineId, GError **error); gboolean tool_config_file_readString(gchar *line, int position, gchar ***values, guint size, gboolean join, GError **error); gboolean tool_config_file_clampFloat(float *variable, float value, float min, float max); gboolean tool_config_file_clampInt(int *variable, int value, int min, int max); #endif v_sim-3.8.0/src/coreTools/toolDbg.c000066400000000000000000000100121370110300500171150ustar00rootroot00000000000000/* EXTRAITS DE LA LICENCE Copyright CEA, contributeurs : Damien CALISTE, laboratoire L_Sim, (2017) Adresse mèl : CALISTE, damien P caliste AT cea P fr. Ce logiciel est un programme informatique servant à visualiser des structures atomiques dans un rendu pseudo-3D. Ce logiciel est régi par la licence CeCILL soumise au droit français et respectant les principes de diffusion des logiciels libres. Vous pouvez utiliser, modifier et/ou redistribuer ce programme sous les conditions de la licence CeCILL telle que diffusée par le CEA, le CNRS et l'INRIA sur le site "http://www.cecill.info". Le fait que vous puissiez accéder à cet en-tête signifie que vous avez pris connaissance de la licence CeCILL, et que vous en avez accepté les termes (cf. le fichier Documentation/licence.fr.txt fourni avec ce logiciel). */ /* LICENCE SUM UP Copyright CEA, contributors : Damien CALISTE, laboratoire L_Sim, (2017) E-mail address: CALISTE, damien P caliste AT cea P fr. This software is a computer program whose purpose is to visualize atomic configurations in 3D. This software is governed by the CeCILL license under French law and abiding by the rules of distribution of free software. You can use, modify and/ or redistribute the software under the terms of the CeCILL license as circulated by CEA, CNRS and INRIA at the following URL "http://www.cecill.info". The fact that you are presently reading this means that you have had knowledge of the CeCILL license and that you accept its terms. You can find a copy of this licence shipped with this software at Documentation/licence.en.txt. */ #include "toolDbg.h" #include #include #if DEBUG == 1 && PLATFORM_X11 == 1 #define __USE_GNU #include #endif /** * SECTION: toolDbg * @short_description: A wrapper around #GObject for debugging * purposes * * This is a thin wrapper around #GObject to count allocation * and deallocation and check memory leaks of objects created by V_Sim. * * Since: 3.8 */ /** * ToolDbgObj: * * Opaque structure used to encapsulate #GObject with debug counters. * * Since: 3.8 */ static GHashTable *_objSet; static void tool_dbg_obj_finalize(GObject* obj); G_DEFINE_TYPE(ToolDbgObj, tool_dbg_obj, G_TYPE_OBJECT) static void tool_dbg_obj_class_init(ToolDbgObjClass *klass) { /* Connect the overloading methods. */ G_OBJECT_CLASS(klass)->finalize = tool_dbg_obj_finalize; _objSet = g_hash_table_new(g_direct_hash, g_direct_equal); } static void tool_dbg_obj_init(ToolDbgObj *obj) { g_hash_table_add(_objSet, obj); } static void tool_dbg_obj_finalize(GObject* obj) { g_hash_table_remove(_objSet, obj); G_OBJECT_CLASS(tool_dbg_obj_parent_class)->finalize(obj); } /** * tool_dbg_obj_class_summarize: * * Debug function displaying the currently in-memory #ToolDbgObj. * * Since: 3.8 **/ void tool_dbg_obj_class_summarize(void) { GHashTableIter iter; gpointer key, value; fprintf(stderr, "Number of allocated GObjects: %d\n", g_hash_table_size(_objSet)); g_hash_table_iter_init(&iter, _objSet); while (g_hash_table_iter_next(&iter, &key, &value)) fprintf(stderr, "- %p: %s (%d ref counts)\n", key, G_OBJECT_TYPE_NAME(value), G_OBJECT(value)->ref_count); } #if DEBUG == 1 && PLATFORM_X11 == 1 #pragma GCC diagnostic push /* Save actual diagnostics state */ #pragma GCC diagnostic ignored "-Wpedantic" /* Disable pedantic */ #undef g_object_ref gpointer g_object_ref(gpointer obj) { static gpointer (*ref)(gpointer); if (!ref) ref = (gpointer (*)(gpointer))dlsym(RTLD_NEXT, "g_object_ref"); if (TOOL_IS_DBG_OBJ(obj)) fprintf(stderr, "Tool Dbg: ref %p (%d).\n", obj, G_OBJECT(obj)->ref_count); return ref(obj); } void g_object_unref(gpointer obj) { static void (*unref)(gpointer); if (TOOL_IS_DBG_OBJ(obj)) fprintf(stderr, "Tool Dbg: unref %p (%d).\n", obj, G_OBJECT(obj)->ref_count); if (!unref) unref = (void (*)(gpointer))dlsym(RTLD_NEXT, "g_object_unref"); unref(obj); } #pragma GCC diagnostic pop /* Restore diagnostics state */ #endif v_sim-3.8.0/src/coreTools/toolDbg.h000066400000000000000000000041571370110300500171370ustar00rootroot00000000000000/* EXTRAITS DE LA LICENCE Copyright CEA, contributeurs : Damien CALISTE, laboratoire L_Sim, (2017) Adresse mèl : CALISTE, damien P caliste AT cea P fr. Ce logiciel est un programme informatique servant à visualiser des structures atomiques dans un rendu pseudo-3D. Ce logiciel est régi par la licence CeCILL soumise au droit français et respectant les principes de diffusion des logiciels libres. Vous pouvez utiliser, modifier et/ou redistribuer ce programme sous les conditions de la licence CeCILL telle que diffusée par le CEA, le CNRS et l'INRIA sur le site "http://www.cecill.info". Le fait que vous puissiez accéder à cet en-tête signifie que vous avez pris connaissance de la licence CeCILL, et que vous en avez accepté les termes (cf. le fichier Documentation/licence.fr.txt fourni avec ce logiciel). */ /* LICENCE SUM UP Copyright CEA, contributors : Damien CALISTE, laboratoire L_Sim, (2017) E-mail address: CALISTE, damien P caliste AT cea P fr. This software is a computer program whose purpose is to visualize atomic configurations in 3D. This software is governed by the CeCILL license under French law and abiding by the rules of distribution of free software. You can use, modify and/ or redistribute the software under the terms of the CeCILL license as circulated by CEA, CNRS and INRIA at the following URL "http://www.cecill.info". The fact that you are presently reading this means that you have had knowledge of the CeCILL license and that you accept its terms. You can find a copy of this licence shipped with this software at Documentation/licence.en.txt. */ #ifndef TOOLDBG_H #define TOOLDBG_H #include #include G_BEGIN_DECLS /** * TOOL_TYPE_DBG_OBJ: * * return the type of #ToolDbgObj. */ #define TOOL_TYPE_DBG_OBJ (tool_dbg_obj_get_type ()) G_DECLARE_DERIVABLE_TYPE(ToolDbgObj, tool_dbg_obj, TOOL, DBG_OBJ, GObject) /** * ToolDbgObjClass: * @parent: private. * * Common name to refer to a #_ToolDbgObjClass. */ struct _ToolDbgObjClass { GObjectClass parent; }; void tool_dbg_obj_class_summarize(void); G_END_DECLS #endif v_sim-3.8.0/src/coreTools/toolFileFormat.c000066400000000000000000000607461370110300500204740ustar00rootroot00000000000000/* EXTRAITS DE LA LICENCE Copyright CEA, contributeurs : Luc BILLARD et Damien CALISTE, laboratoire L_Sim, (2001-2005) Adresse mèl : BILLARD, non joignable par mèl ; CALISTE, damien P caliste AT cea P fr. Ce logiciel est un programme informatique servant à visualiser des structures atomiques dans un rendu pseudo-3D. Ce logiciel est régi par la licence CeCILL soumise au droit français et respectant les principes de diffusion des logiciels libres. Vous pouvez utiliser, modifier et/ou redistribuer ce programme sous les conditions de la licence CeCILL telle que diffusée par le CEA, le CNRS et l'INRIA sur le site "http://www.cecill.info". Le fait que vous puissiez accéder à cet en-tête signifie que vous avez pris connaissance de la licence CeCILL, et que vous en avez accepté les termes (cf. le fichier Documentation/licence.fr.txt fourni avec ce logiciel). */ /* LICENCE SUM UP Copyright CEA, contributors : Luc BILLARD et Damien CALISTE, laboratoire L_Sim, (2001-2005) E-mail address: BILLARD, not reachable any more ; CALISTE, damien P caliste AT cea P fr. This software is a computer program whose purpose is to visualize atomic configurations in 3D. This software is governed by the CeCILL license under French law and abiding by the rules of distribution of free software. You can use, modify and/ or redistribute the software under the terms of the CeCILL license as circulated by CEA, CNRS and INRIA at the following URL "http://www.cecill.info". The fact that you are presently reading this means that you have had knowledge of the CeCILL license and that you accept its terms. You can find a copy of this licence shipped with this software at Documentation/licence.en.txt. */ #include "toolFileFormat.h" #include #include #include #include /** * SECTION:toolFileFormat * @short_description: Describes file format objects (name patterns, * description, properties...). * * When dealing with files, it is convenient to class then by * formats, one format for JPEG files, one other for * postscript... Such file formats are characterized by their * description, explaining what they are, one or more name pattern * (e.g. "*.jpg") and some properties (e.g. compression level for JPEG * file). * This module describes objects that can store all these * informations and deals with them. To create a new file format, use * tool_file_format_new(). A #ToolFileFormat object can be used in a * GtkFileChooser object, using a GtkFileFilter. tool_file_format_getLabel() * will return directly the label to give to the GtkFileFilter and the * name patterns can be passed to it also. * A file format property is a #ToolOption value. There are some * convenient routines to add common boolean or integer * properties. For instance, use tool_file_format_addPropertyBoolean() * to add a boolean property to a given #ToolFileFormat object. Then the stored * properties can be iterated on using a #ToolFileFormatIter iterator. */ /** * ToolFileFormatIter: * @lst: internal pointer. * @name: name of the current iterated property (read only). * @label: label of the current iterated property (read only). * @val: its value (read only). * * Iterator on #ToolFileFormat object properties. See * tool_file_format_iterNextProperty(). * * Since: 3.6 */ GQuark tool_file_format_getQuark(void) { return g_quark_from_static_string("ToolFileFormat"); } /** * ToolFileFormatPrivate: * * Private attributes of #ToolFileFormat objects. **/ struct _ToolFileFormatPrivate { /* This is the list of file patterns, for example (*.jpg; *.jpeg; *.jpe). */ GList *fileType; GList *fileMatchers; gboolean ignoreFileType; /* This is a short text to describe this file format. It should not be bigger than 30 characters. */ gchar *name; /* This is a private field, it is a concatenation of "name ({patterns},)". */ gchar *labelString; /* A validating routine for this file format. */ ToolFileFormatValidate validate; /* This is a private field. It enables to add some properties to a file format. See fileFormatAdd_property*() and tool_file_format_property_get*() to control them. */ GList *properties; }; enum { PROP_0, NAME_PROP, LABEL_PROP, IGNORE_PROP }; static void tool_file_format_finalize(GObject *obj); static void tool_file_format_get_property(GObject* obj, guint property_id, GValue *value, GParamSpec *pspec); static void tool_file_format_set_property(GObject* obj, guint property_id, const GValue *value, GParamSpec *pspec); static ToolOption* _getProperty(const ToolFileFormat *format, const gchar *name); G_DEFINE_TYPE_WITH_CODE(ToolFileFormat, tool_file_format, VISU_TYPE_OBJECT, G_ADD_PRIVATE(ToolFileFormat)) static void tool_file_format_class_init(ToolFileFormatClass *klass) { DBG_fprintf(stderr, "Tool FileFormat: creating the class of the object.\n"); G_OBJECT_CLASS(klass)->finalize = tool_file_format_finalize; G_OBJECT_CLASS(klass)->set_property = tool_file_format_set_property; G_OBJECT_CLASS(klass)->get_property = tool_file_format_get_property; /** * ToolFileFormat::name: * * The name identifying one file format, can be translate and used in a UI. * * Since: 3.7 */ g_object_class_install_property (G_OBJECT_CLASS(klass), NAME_PROP, g_param_spec_string("name", _("Name"), _("File format description."), "", G_PARAM_CONSTRUCT_ONLY | G_PARAM_READWRITE)); /** * ToolFileFormat::label: * * The label giving the file pattern, can be translate and used in a UI. * * Since: 3.7 */ g_object_class_install_property (G_OBJECT_CLASS(klass), LABEL_PROP, g_param_spec_string("label", _("Label"), _("Label used to show the file pattern."), "", G_PARAM_READABLE)); /** * ToolFileFormat::ignore-type: * * Store if the patterns of format descibes all possible patterns * for the file format. * * Since: 3.7 */ g_object_class_install_property (G_OBJECT_CLASS(klass), IGNORE_PROP, g_param_spec_boolean("ignore-type", _("Ignore file patterns"), _("Don't restrict file matching to the given patterns."), FALSE, G_PARAM_READWRITE)); } static void tool_file_format_init(ToolFileFormat *fmt) { DBG_fprintf(stderr, "Tool FileFormat: initializing new object (%p).\n", (gpointer)fmt); fmt->priv = tool_file_format_get_instance_private(fmt); fmt->priv->name = (gchar*)0; fmt->priv->fileType = (GList*)0; fmt->priv->fileMatchers = (GList*)0; fmt->priv->labelString = (gchar*)0; fmt->priv->validate = (ToolFileFormatValidate)0; fmt->priv->properties = (GList*)0; fmt->priv->ignoreFileType = FALSE; } static void tool_file_format_finalize(GObject *obj) { ToolFileFormatPrivate *format; DBG_fprintf(stderr, "Tool FileFormat: finalize object %p.\n", (gpointer)obj); format = TOOL_FILE_FORMAT(obj)->priv; g_free(format->name); g_free(format->labelString); g_list_free_full(format->fileType, g_free); g_list_free_full(format->fileMatchers, (GDestroyNotify)g_pattern_spec_free); g_list_free_full(format->properties, (GDestroyNotify)tool_option_free); /* Chain up to the parent class */ G_OBJECT_CLASS(tool_file_format_parent_class)->finalize(obj); DBG_fprintf(stderr, "Tool FileFormat: freeing ... OK.\n"); } static void tool_file_format_get_property(GObject* obj, guint property_id, GValue *value, GParamSpec *pspec) { ToolFileFormatPrivate *self = TOOL_FILE_FORMAT(obj)->priv; DBG_fprintf(stderr, "Tool FileFormat: get property '%s' -> ", g_param_spec_get_name(pspec)); switch (property_id) { case NAME_PROP: g_value_set_string(value, self->name); DBG_fprintf(stderr, "%s.\n", self->name); break; case LABEL_PROP: g_value_set_string(value, self->labelString); DBG_fprintf(stderr, "%s.\n", self->labelString); break; case IGNORE_PROP: g_value_set_boolean(value, self->ignoreFileType); DBG_fprintf(stderr, "%d.\n", self->ignoreFileType); break; default: /* We don't have any other property... */ G_OBJECT_WARN_INVALID_PROPERTY_ID(obj, property_id, pspec); break; } } static void tool_file_format_set_property(GObject* obj, guint property_id, const GValue *value, GParamSpec *pspec) { ToolFileFormatPrivate *self = TOOL_FILE_FORMAT(obj)->priv; gint nbCharacterMax = 45, lg; DBG_fprintf(stderr, "Tool FileFormat: set property '%s' -> ", g_param_spec_get_name(pspec)); switch (property_id) { case NAME_PROP: lg = strlen(g_value_get_string(value)); if (lg > nbCharacterMax) { g_warning("The label property is bigger than" " %d characters and it will be truncated.", nbCharacterMax); lg = nbCharacterMax; } self->name = g_strndup(g_value_get_string(value), lg); DBG_fprintf(stderr, "%s.\n", self->name); break; case IGNORE_PROP: self->ignoreFileType = g_value_get_boolean(value); DBG_fprintf(stderr, "%d.\n", self->ignoreFileType); break; default: /* We don't have any other property... */ G_OBJECT_WARN_INVALID_PROPERTY_ID(obj, property_id, pspec); break; } } static void _buildLabel(ToolFileFormat *format) { GList *lst; GString *tmpStr; tmpStr = g_string_new(format->priv->name); g_string_append_printf(tmpStr, " ("); for (lst = format->priv->fileType; lst; lst = g_list_next(lst)) { g_string_append_printf(tmpStr, "%s", (gchar*) lst->data); if (lst->next) g_string_append_printf(tmpStr, ", "); } if (!format->priv->fileType) g_string_append_printf(tmpStr, "no filter"); if (format->priv->fileType && format->priv->ignoreFileType) g_string_append_printf(tmpStr, ", ..."); g_string_append_printf(tmpStr, ")"); if (format->priv->labelString) g_free(format->priv->labelString); format->priv->labelString = tmpStr->str; g_string_free(tmpStr, FALSE); } /** * tool_file_format_newRestricted: * @descr: a short string to label a new file format. * @patterns: a set of patterns to identify files of this format. * * Allocate a new #ToolFileFormat. The @patterns argument is copied in * the #ToolFileFormat object and can be freed safely after the call to this method. * The @patterns list is not all the patterns supported by the format. * * Returns: (transfer none): a newly allocated ToolFileFormat, * or NULL if something goes wrong. */ ToolFileFormat* tool_file_format_newRestricted(const gchar* descr, const gchar** patterns) { ToolFileFormat *format; g_return_val_if_fail(descr && descr[0] && patterns, (ToolFileFormat*)0); format = TOOL_FILE_FORMAT(g_object_new(TOOL_TYPE_FILE_FORMAT, "name", descr, "ignore-type", TRUE, NULL)); tool_file_format_addPatterns(format, patterns); return format; } /** * tool_file_format_new: * @descr: a short string to label a new file format. * @patterns: (array zero-terminated=1) (element-type utf8): a set of patterns to identify files of this format. * * Allocate a new #ToolFileFormat. The @patterns argument is copied in * the #ToolFileFormat object and can be freed safely after the call to this method. * * Returns: (transfer none): a newly allocated ToolFileFormat, * or NULL if something goes wrong. */ ToolFileFormat* tool_file_format_new(const gchar* descr, const gchar** patterns) { ToolFileFormat *format; g_return_val_if_fail(descr && descr[0] && patterns, (ToolFileFormat*)0); format = TOOL_FILE_FORMAT(g_object_new(TOOL_TYPE_FILE_FORMAT, "name", descr, "ignore-type", FALSE, NULL)); tool_file_format_addPatterns(format, patterns); return format; } /** * tool_file_format_addPatterns: * @fmt: a #ToolFileFormat object. * @patterns: (array zero-terminated=1): a list of matching patterns. * * A file format may have pattern for the naming scheme of files, like * "*.jpg" and "*.jpeg" for JPEG files. It's not mandatory for a file * format to match its own pattern anyway. * * Since: 3.7 **/ void tool_file_format_addPatterns(ToolFileFormat *fmt, const gchar **patterns) { gint n; g_return_if_fail(TOOL_IS_FILE_FORMAT(fmt)); for (n = 0; patterns[n]; n++) fmt->priv->fileType = g_list_append(fmt->priv->fileType, g_strdup(patterns[n])); g_list_free_full(fmt->priv->fileMatchers, (GDestroyNotify)g_pattern_spec_free); fmt->priv->fileMatchers = (GList*)0; _buildLabel(fmt); } /** * tool_file_format_copy: * @from: a #ToolFileFormat object. * * Copy the given file format @from a create a new one. * * Since: 3.6 * * Returns: (transfer full): a newly created #ToolFileFormat. Should * be freed with g_object_unref(). */ ToolFileFormat* tool_file_format_copy(const ToolFileFormat *from) { ToolFileFormat *to; GList *lst; g_return_val_if_fail(from, (ToolFileFormat*)0); to = TOOL_FILE_FORMAT(g_object_new(TOOL_TYPE_FILE_FORMAT, "name", from->priv->name, "ignore-type", from->priv->ignoreFileType, NULL)); DBG_fprintf(stderr, "Tool ToolFileFormat: copy to file format %p.\n", (gpointer)to); to->priv->fileType = (GList*)0; for (lst = from->priv->fileType; lst; lst = g_list_next(lst)) to->priv->fileType = g_list_append(to->priv->fileType, g_strdup((gchar*)lst->data)); _buildLabel(to); to->priv->properties = (GList*)0; for (lst = from->priv->properties; lst; lst = g_list_next(lst)) to->priv->properties = g_list_append(to->priv->properties, tool_option_copy((ToolOption*)lst->data)); return to; } /** * tool_file_format_getName: * @format: a #ToolFileFormat. * * This method gives the name describing the file format. * * Returns: (transfer none): a string with the name. This string * should not be freed. */ const gchar* tool_file_format_getName(ToolFileFormat *format) { DBG_fprintf(stderr, "Tool ToolFileFormat: get the name of format '%p'.\n", (gpointer)format); g_return_val_if_fail(format, (gchar*)0); return format->priv->name; } /** * tool_file_format_getLabel: * @format: a #ToolFileFormat. * * This method gives a label describing the file format. * * Returns: (transfer none): a string made by the name and all * the paterns of the given format, given in parentethis. This string * should not be freed. */ const gchar* tool_file_format_getLabel(ToolFileFormat *format) { DBG_fprintf(stderr, "Tool ToolFileFormat: get the label of format '%p'.\n", (gpointer)format); g_return_val_if_fail(format, (gchar*)0); return format->priv->labelString; } /** * tool_file_format_getFilePatterns: * @format: a #ToolFileFormat. * * This method gives a list with the file patterns. * * Returns: (transfer none) (element-type utf8): a list with the file * patterns. This list should not be freed. * * Since: 3.6 */ const GList* tool_file_format_getFilePatterns(ToolFileFormat *format) { DBG_fprintf(stderr, "Tool ToolFileFormat: get the file patterns of format '%p'.\n", (gpointer)format); g_return_val_if_fail(format, (GList*)0); return format->priv->fileType; } /** * tool_file_format_canMatch: * @format: a #ToolFileFormat. * * This method is used to know if the file pattern list can be used * to match a given filename with tool_file_format_match(). * * Returns: TRUE if a call to tool_file_format_match() is safe. * * Since: 3.6 */ gboolean tool_file_format_canMatch(ToolFileFormat* format) { g_return_val_if_fail(format, FALSE); return !format->priv->ignoreFileType; } /** * tool_file_format_match: * @format: a #ToolFileFormat ; * @filename: a string to match. * * This method try to match the given string to one of the patterns of * the #ToolFileFormat @format. * * Returns: the matching pattern, if any. */ const gchar* tool_file_format_match(ToolFileFormat *format, const gchar *filename) { GList *tmpLst; g_return_val_if_fail(format, FALSE); DBG_fprintf(stderr, "Tool FileFormat: try to match '%s' with '%s' -> ", filename, format->priv->name); tmpLst = format->priv->fileType; while(tmpLst && !g_pattern_match_simple(tmpLst->data, filename)) tmpLst = g_list_next(tmpLst); DBG_fprintf(stderr, "%d.\n", (tmpLst != (GList*)0)); return (tmpLst)?(const gchar*)tmpLst->data:(const gchar*)0; } static gboolean _validate(ToolFileFormat *format, const gchar *filename) { gboolean passed; GList *lst; if (!format->priv->fileMatchers) for (lst = format->priv->fileType; lst; lst = g_list_next(lst)) format->priv->fileMatchers = g_list_prepend(format->priv->fileMatchers, g_pattern_spec_new((char*)lst->data)); passed = FALSE; for (lst = format->priv->fileMatchers; lst && !passed; lst = g_list_next(lst)) passed = g_pattern_match_string((GPatternSpec*)lst->data, filename); return passed; } /** * tool_file_format_validate: * @format: a #ToolFileFormat ; * @filename: a string to match. * * This method runs a minimal parsing routine set with * tool_file_format_setValidator() to check if the provided filename * correspond to this file format. * * Since: 3.7 * * Returns: TRUE, if the file (after minimal parsing) is of this file * format. If there is no validator routine, it is using a built-in * one, based on pattern matching with file types, see * tool_file_format_addPatterns(). */ gboolean tool_file_format_validate(ToolFileFormat *format, const gchar *filename) { gboolean res; g_return_val_if_fail(format, FALSE); DBG_fprintf(stderr, "Tool FileFormat: try to validate '%s' with '%s' -> ", filename, format->priv->name); if (format->priv->validate) res = format->priv->validate(filename); else res = _validate(format, filename); DBG_fprintf(stderr, "%d.\n", res); return res; } /** * tool_file_format_setValidator: * @format: a #ToolFileFormat ; * @validate: (scope call) (allow-none): a pointer to a validator routine. * * Set up a validating routine that do a minimal parsing to check that * a provided file corresponds to this file format. * * Since: 3.7 */ void tool_file_format_setValidator(ToolFileFormat *format, ToolFileFormatValidate validate) { g_return_if_fail(format); format->priv->validate = validate; } /** * tool_file_format_addOption: * @format: a #ToolFileFormat object. * @opt: a #ToolOption object. * * File format may have options, like pseudo-potential pparameters in * case of BigDFT calculations. * * Since: 3.7 **/ void tool_file_format_addOption(ToolFileFormat *format, ToolOption *opt) { g_return_if_fail(TOOL_IS_FILE_FORMAT(format)); format->priv->properties = g_list_append(format->priv->properties, (gpointer)opt); } /** * tool_file_format_addPropertyBoolean: * @format: the #ToolFileFormat object. * @name: a name ; * @label: a description ; * @defaultVal: a default value. * * Add a new boolean property to the file format @format. * * Returns: (transfer none): a newly created #ToolOption, free with tool_option_free(). */ ToolOption* tool_file_format_addPropertyBoolean(ToolFileFormat *format, const gchar *name, const gchar *label, gboolean defaultVal) { ToolOption *opt; GValue *val; opt = _getProperty(format, name); if (!opt) { opt = tool_option_new(name, label, G_TYPE_BOOLEAN); format->priv->properties = g_list_append(format->priv->properties, (gpointer)opt); } val = tool_option_getValue(opt); g_value_set_boolean(val, defaultVal); return opt; } /** * tool_file_format_addPropertyInt: * @format: the #ToolFileFormat object. * @name: a name ; * @label: a description ; * @defaultVal: a default value. * * Add a new integer property to the file format @format. * * Returns: (transfer none): a newly created #ToolOption, free with tool_option_free(). */ ToolOption* tool_file_format_addPropertyInt(ToolFileFormat *format, const gchar *name, const gchar *label, gint defaultVal) { ToolOption *opt; GValue *val; opt = _getProperty(format, name); if (!opt) { opt = tool_option_new(name, label, G_TYPE_INT); format->priv->properties = g_list_append(format->priv->properties, (gpointer)opt); } val = tool_option_getValue(opt); g_value_set_int(val, defaultVal); return opt; } /** * tool_file_format_addPropertyDouble: * @format: the #ToolFileFormat object. * @name: a name ; * @label: a description ; * @defaultVal: a default value. * * Add a new integer property to the file format @format. * * Since: 3.7 * * Returns: (transfer none): a newly created #ToolOption, free with tool_option_free(). */ ToolOption* tool_file_format_addPropertyDouble(ToolFileFormat *format, const gchar *name, const gchar *label, gdouble defaultVal) { ToolOption *opt; GValue *val; opt = _getProperty(format, name); if (!opt) { opt = tool_option_new(name, label, G_TYPE_DOUBLE); format->priv->properties = g_list_append(format->priv->properties, (gpointer)opt); } val = tool_option_getValue(opt); g_value_set_double(val, defaultVal); return opt; } /** * tool_file_format_iterNextProperty: * @format: a #ToolFileFormat object. * @iter: an iterator. * * Run to the next property of the file format @format. The iterator * attributes are updated so it's convenient to access the property * values and details, see #ToolFileFormatIter. * * Since: 3.6 * * Returns: TRUE if any. */ gboolean tool_file_format_iterNextProperty(ToolFileFormat *format, ToolFileFormatIter *iter) { if (!iter->lst) iter->lst = format->priv->properties; else iter->lst = g_list_next(iter->lst); if (!iter->lst) return FALSE; iter->name = (gchar*)tool_option_getName ((ToolOption*)iter->lst->data); iter->label = (gchar*)tool_option_getLabel((ToolOption*)iter->lst->data); iter->val = tool_option_getValue((ToolOption*)iter->lst->data); return TRUE; } static ToolOption* _getProperty(const ToolFileFormat *format, const gchar *name) { GList *lst; g_return_val_if_fail(format && name, (ToolOption*)0); DBG_fprintf(stderr, "Tool FileFormat: grep property '%s' from file format %p.\n", name, (gpointer)format); for (lst = format->priv->properties; lst; lst = g_list_next(lst)) if (!strcmp(name, tool_option_getName((ToolOption*)lst->data))) return (ToolOption*)lst->data; return (ToolOption*)0; } /** * tool_file_format_setPropertiesFromCLI: * @format: A #ToolFileFormat object. * * Scan all options from command line and affects values. * * Since: 3.8 **/ void tool_file_format_setPropertiesFromCLI(ToolFileFormat *format) { GHashTable *opts; GHashTableIter iter; gpointer key, value; ToolOption *prop; opts = commandLineGet_options(); if (!opts) return; g_hash_table_iter_init(&iter, opts); while(g_hash_table_iter_next(&iter, &key, &value)) { prop = _getProperty(format, (const gchar*)key); if (prop) g_value_copy(tool_option_getValue((ToolOption*)value), tool_option_getValue(prop)); } } /** * tool_file_format_getPropertyBoolean: * @format: a #ToolFileFormat object. * @name: a property name. * * Retrieves the value of property @prop. * * Since: 3.8 * * Returns: the property value if exists, FALSE otherwise. **/ gboolean tool_file_format_getPropertyBoolean(const ToolFileFormat *format, const gchar *name) { ToolOption *prop; g_return_val_if_fail(TOOL_IS_FILE_FORMAT(format), FALSE); prop = _getProperty(format, name); if (!prop) return FALSE; return g_value_get_boolean(tool_option_getValue(prop)); } /** * tool_file_format_getPropertyInt: * @format: a #ToolFileFormat object. * @name: a property name. * * Retrieves the value of property @prop. * * Since: 3.8 * * Returns: the property value if exists, -1 otherwise. **/ gint tool_file_format_getPropertyInt(const ToolFileFormat *format, const gchar *name) { ToolOption *prop; g_return_val_if_fail(TOOL_IS_FILE_FORMAT(format), -1); prop = _getProperty(format, name); if (!prop) return -1; return g_value_get_int(tool_option_getValue(prop)); } v_sim-3.8.0/src/coreTools/toolFileFormat.h000066400000000000000000000165611370110300500204750ustar00rootroot00000000000000/* EXTRAITS DE LA LICENCE Copyright CEA, contributeurs : Luc BILLARD et Damien CALISTE, laboratoire L_Sim, (2001-2005) Adresse mèl : BILLARD, non joignable par mèl ; CALISTE, damien P caliste AT cea P fr. Ce logiciel est un programme informatique servant à visualiser des structures atomiques dans un rendu pseudo-3D. Ce logiciel est régi par la licence CeCILL soumise au droit français et respectant les principes de diffusion des logiciels libres. Vous pouvez utiliser, modifier et/ou redistribuer ce programme sous les conditions de la licence CeCILL telle que diffusée par le CEA, le CNRS et l'INRIA sur le site "http://www.cecill.info". Le fait que vous puissiez accéder à cet en-tête signifie que vous avez pris connaissance de la licence CeCILL, et que vous en avez accepté les termes (cf. le fichier Documentation/licence.fr.txt fourni avec ce logiciel). */ /* LICENCE SUM UP Copyright CEA, contributors : Luc BILLARD et Damien CALISTE, laboratoire L_Sim, (2001-2005) E-mail address: BILLARD, not reachable any more ; CALISTE, damien P caliste AT cea P fr. This software is a computer program whose purpose is to visualize atomic configurations in 3D. This software is governed by the CeCILL license under French law and abiding by the rules of distribution of free software. You can use, modify and/ or redistribute the software under the terms of the CeCILL license as circulated by CEA, CNRS and INRIA at the following URL "http://www.cecill.info". The fact that you are presently reading this means that you have had knowledge of the CeCILL license and that you accept its terms. You can find a copy of this licence shipped with this software at Documentation/licence.en.txt. */ #ifndef TOOLTOOL_FILE_FORMAT_H #define TOOLTOOL_FILE_FORMAT_H #include #include #include "toolOptions.h" G_BEGIN_DECLS /** * TOOL_TYPE_FILE_FORMAT: * * Return the associated #GType to the ToolFileFormat objects. */ #define TOOL_TYPE_FILE_FORMAT (tool_file_format_get_type ()) /** * TOOL_FILE_FORMAT: * @obj: the widget to cast. * * Cast the given object to a #ToolFileFormat object. */ #define TOOL_FILE_FORMAT(obj) (G_TYPE_CHECK_INSTANCE_CAST ((obj), TOOL_TYPE_FILE_FORMAT, ToolFileFormat)) /** * TOOL_FILE_FORMAT_CLASS: * @klass: the class to cast. * * Cast the given class to a #ToolFileFormatClass object. */ #define TOOL_FILE_FORMAT_CLASS(klass) (G_TYPE_CHECK_CLASS_CAST ((klass), TOOL_TYPE_FILE_FORMAT, ToolFileFormatClass)) /** * TOOL_IS_FILE_FORMAT: * @obj: the object to test. * * Return if the given object is a valid #ToolFileFormat object. */ #define TOOL_IS_FILE_FORMAT(obj) (G_TYPE_CHECK_INSTANCE_TYPE ((obj), TOOL_TYPE_FILE_FORMAT)) /** * TOOL_IS_FILE_FORMAT_CLASS: * @klass: the class to test. * * Return if the given class is a valid #ToolFileFormatClass class. */ #define TOOL_IS_FILE_FORMAT_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE ((klass), TOOL_TYPE_FILE_FORMAT)) /** * TOOL_FILE_FORMAT_GET_CLASS: * @obj: the widget to get the class of. * * Get the class of the given object. */ #define TOOL_FILE_FORMAT_GET_CLASS(obj) (G_TYPE_INSTANCE_GET_CLASS(obj, TOOL_TYPE_FILE_FORMAT, ToolFileFormatClass)) typedef struct _ToolFileFormatPrivate ToolFileFormatPrivate; /** * ToolFileFormat: * * An opaque structure. */ typedef struct _ToolFileFormat ToolFileFormat; struct _ToolFileFormat { VisuObject parent; ToolFileFormatPrivate *priv; }; /** * ToolFileFormatClass: * @parent: the parent. * * An opaque structure. */ typedef struct _ToolFileFormatClass ToolFileFormatClass; struct _ToolFileFormatClass { VisuObjectClass parent; }; /** * tool_file_format_get_type * * #GType are unique numbers to identify objects. * * Returns: the #GType associated with #ToolFileFormat objects. */ GType tool_file_format_get_type(void); typedef struct _ToolFileFormatIter ToolFileFormatIter; struct _ToolFileFormatIter { GList *lst; gchar *name; gchar *label; GValue *val; }; /** * TOOL_FILE_FORMAT_ERROR: (skip) * * Internal function for error handling. */ #define TOOL_FILE_FORMAT_ERROR tool_file_format_getQuark() /** * tool_file_format_getQuark: (skip) * * Internal routine to get the #GQuark to handle error related to file formats. */ GQuark tool_file_format_getQuark(void); /** * ToolFileFormatErrorFlag: * @TOOL_FILE_FORMAT_ERROR_METHOD: Error from the loading method. * @TOOL_FILE_FORMAT_ERROR_FILE: Error when opening. * @TOOL_FILE_FORMAT_ERROR_FORMAT: Wrongness in format. * @TOOL_FILE_FORMAT_ERROR_CANCEL: Cancellation occurs. * @TOOL_FILE_FORMAT_ERROR_UNKNOWN_FORMAT: the file is not recognised. * * These are flags used when reading a file with a loading method associated to a file format. */ typedef enum { TOOL_FILE_FORMAT_ERROR_METHOD, /* Error from the method. */ TOOL_FILE_FORMAT_ERROR_FILE, /* Error when opening. */ TOOL_FILE_FORMAT_ERROR_FORMAT, /* Wrongness in format. */ TOOL_FILE_FORMAT_ERROR_CANCEL, /* Cancellation occurs. */ TOOL_FILE_FORMAT_ERROR_UNKNOWN_FORMAT } ToolFileFormatErrorFlag; /** * ToolFileFormatValidate: * @filename: (type filename): a path. * * Function to match a given @filename for a file format. See * tool_file_format_setValidator(). * * Since: 3.7 * * Returns: TRUE if @filename is a valid name for a file format. */ typedef gboolean (*ToolFileFormatValidate)(const gchar *filename); ToolFileFormat* tool_file_format_new(const gchar* descr, const gchar** patterns); ToolFileFormat* tool_file_format_newRestricted(const gchar* descr, const gchar** patterns); ToolFileFormat* tool_file_format_copy(const ToolFileFormat *from); void tool_file_format_addPatterns(ToolFileFormat *fmt, const gchar **patterns); const gchar* tool_file_format_getName(ToolFileFormat *format); const gchar* tool_file_format_getLabel(ToolFileFormat *format); const GList* tool_file_format_getFilePatterns(ToolFileFormat *format); gboolean tool_file_format_canMatch(ToolFileFormat* format); const gchar* tool_file_format_match(ToolFileFormat *format, const gchar*filename); gboolean tool_file_format_validate(ToolFileFormat *format, const gchar *filename); void tool_file_format_setValidator(ToolFileFormat *format, ToolFileFormatValidate validate); void tool_file_format_addOption(ToolFileFormat *format, ToolOption *opt); ToolOption* tool_file_format_addPropertyBoolean(ToolFileFormat *format, const gchar *name, const gchar *label, gboolean defaultVal); ToolOption* tool_file_format_addPropertyInt(ToolFileFormat *format, const gchar *name, const gchar *label, gint defaultVal); ToolOption* tool_file_format_addPropertyDouble(ToolFileFormat *format, const gchar *name, const gchar *label, gdouble defaultVal); void tool_file_format_setPropertiesFromCLI(ToolFileFormat *format); gboolean tool_file_format_getPropertyBoolean(const ToolFileFormat *format, const gchar *name); gint tool_file_format_getPropertyInt(const ToolFileFormat *format, const gchar *name); gboolean tool_file_format_iterNextProperty(ToolFileFormat *format, ToolFileFormatIter *iter); G_END_DECLS #endif v_sim-3.8.0/src/coreTools/toolFiles.c000066400000000000000000000357231370110300500175030ustar00rootroot00000000000000/* EXTRAITS DE LA LICENCE Copyright CEA, contributeurs : Damien CALISTE, laboratoire L_Sim, (2017) Adresses mèl : CALISTE, damien P caliste AT cea P fr. Ce logiciel est un programme informatique servant à visualiser des structures atomiques dans un rendu pseudo-3D. Ce logiciel est régi par la licence CeCILL soumise au droit français et respectant les principes de diffusion des logiciels libres. Vous pouvez utiliser, modifier et/ou redistribuer ce programme sous les conditions de la licence CeCILL telle que diffusée par le CEA, le CNRS et l'INRIA sur le site "http://www.cecill.info". Le fait que vous puissiez accéder à cet en-tête signifie que vous avez pris connaissance de la licence CeCILL, et que vous en avez accepté les termes (cf. le fichier Documentation/licence.fr.txt fourni avec ce logiciel). */ /* LICENCE SUM UP Copyright CEA, contributors : Damien CALISTE, laboratoire L_Sim, (2017) E-mail addresses : CALISTE, damien P caliste AT cea P fr. This software is a computer program whose purpose is to visualize atomic configurations in 3D. This software is governed by the CeCILL license under French law and abiding by the rules of distribution of free software. You can use, modify and/ or redistribute the software under the terms of the CeCILL license as circulated by CEA, CNRS and INRIA at the following URL "http://www.cecill.info". The fact that you are presently reading this means that you have had knowledge of the CeCILL license and that you accept its terms. You can find a copy of this licence shipped with this software at Documentation/licence.en.txt. */ #include #ifdef HAVE_LIB_ARCHIVE #include #endif #include /** * SECTION:toolFiles * @short_description: abstract reading of compressed or not text files. * * This class defines objects to read text files with the same * API than with #GIOChannel. The addition is that these files can be * transparently compressed or not. */ struct _ToolFilesPrivate { gboolean dispose_has_run; gchar *filename; #ifdef HAVE_LIB_ARCHIVE struct archive *archive; #define BUFF_SIZE 1024 char buff[BUFF_SIZE + 1]; char *cur; gssize buffSize; #endif GIOChannel *direct; GIOStatus latest; gchar *data; gchar *at; }; static void tool_files_dispose(GObject* obj); static void tool_files_finalize(GObject* obj); G_DEFINE_TYPE_WITH_CODE(ToolFiles, tool_files, VISU_TYPE_OBJECT, G_ADD_PRIVATE(ToolFiles)) static void tool_files_class_init(ToolFilesClass *klass) { DBG_fprintf(stderr, "ToolFiles: creating the class of the object.\n"); /* DBG_fprintf(stderr, " - adding new signals ;\n"); */ /* Connect freeing methods. */ G_OBJECT_CLASS(klass)->dispose = tool_files_dispose; G_OBJECT_CLASS(klass)->finalize = tool_files_finalize; } static void tool_files_init(ToolFiles *obj) { DBG_fprintf(stderr, "ToolFiles: creating a new file reader (%p).\n", (gpointer)obj); obj->priv = tool_files_get_instance_private(obj); obj->priv->dispose_has_run = FALSE; obj->priv->filename = (gchar*)0; #ifdef HAVE_LIB_ARCHIVE obj->priv->archive = (struct archive*)0; obj->priv->buff[0] = '\0'; obj->priv->cur = (char*)0; obj->priv->buffSize = -1; #endif obj->priv->direct = (GIOChannel*)0; obj->priv->data = (gchar*)0; obj->priv->at = (gchar*)0; } static void tool_files_dispose(GObject* obj) { ToolFiles *self = TOOL_FILES(obj); DBG_fprintf(stderr, "ToolFiles: dispose object %p.\n", (gpointer)obj); if (self->priv->dispose_has_run) return; self->priv->dispose_has_run = TRUE; if (self->priv->direct) g_io_channel_unref(self->priv->direct); /* Chain up to the parent class */ G_OBJECT_CLASS(tool_files_parent_class)->dispose(obj); } static void tool_files_finalize(GObject* obj) { ToolFiles *self = TOOL_FILES(obj); DBG_fprintf(stderr, "ToolFiles: finalize object %p.\n", (gpointer)obj); g_free(self->priv->filename); #ifdef HAVE_LIB_ARCHIVE if (self->priv->archive) archive_read_free(self->priv->archive); #endif g_free(self->priv->data); /* Chain up to the parent class */ G_OBJECT_CLASS(tool_files_parent_class)->finalize(obj); } /** * tool_files_new: * * Creates a new #ToolFiles object. * * Since: 3.8 * * Returns: (transfer full): a newly created #ToolFiles object. */ ToolFiles* tool_files_new() { return TOOL_FILES(g_object_new(TOOL_TYPE_FILES, NULL)); } /** * tool_files_open: * @file: a #ToolFiles object. * @filename: a filename. * @error: a location for an error. * * Open @filename for read access. The file can be compressed or not. * * Since: 3.8 * * Returns: TRUE if no error occured when opening the file. **/ gboolean tool_files_open(ToolFiles *file, const gchar *filename, GError **error) { #ifdef HAVE_LIB_ARCHIVE int r; struct archive_entry *ae; #else char *pt; #endif g_return_val_if_fail(TOOL_IS_FILES(file), FALSE); g_return_val_if_fail(!error || *error == (GError*)0, FALSE); file->priv->filename = g_strdup(filename); #ifdef HAVE_LIB_ARCHIVE file->priv->archive = archive_read_new(); archive_read_support_filter_all(file->priv->archive); archive_read_support_format_raw(file->priv->archive); r = archive_read_open_filename(file->priv->archive, filename, 16384); if (r == ARCHIVE_OK) { r = archive_read_next_header(file->priv->archive, &ae); if (r != ARCHIVE_OK) { g_set_error(error, G_FILE_ERROR, G_FILE_ERROR_FAILED, _("cannot read next archive entry.\n")); return FALSE; } return TRUE; } else { archive_read_free(file->priv->archive); file->priv->archive = (struct archive*)0; } #else pt = strrchr(filename, '.'); if (pt && (!strcmp(pt, ".gz") || !strcmp(pt, ".bz2"))) { g_set_error(error, G_FILE_ERROR, G_FILE_ERROR_FAILED, _("Format not supported.")); return FALSE; } #endif file->priv->direct = g_io_channel_new_file(filename, "r", error); if (!file->priv->direct) return FALSE; return TRUE; } /** * tool_files_setEncoding: * @file: a #ToolFiles object. * @encoding: an encoding. * * Set-up the encoding of @file. * * Since: 3.8 **/ void tool_files_setEncoding(ToolFiles *file, const gchar *encoding) { g_return_if_fail(TOOL_IS_FILES(file)); if (file->priv->direct) g_io_channel_set_encoding(file->priv->direct, encoding, NULL); } /** * tool_files_fromMemory: * @file: a #ToolFiles object. * @data: some data. * * Create a #ToolFiles object from @data. * * Since: 3.8 **/ void tool_files_fromMemory(ToolFiles *file, const gchar *data) { g_return_if_fail(TOOL_IS_FILES(file)); file->priv->data = g_strdup(data); file->priv->at = file->priv->data; } #ifdef HAVE_LIB_ARCHIVE static GIOStatus _archiveReadChunk(ToolFiles *file, GError **error) { gboolean empty = file->priv->cur == (char*)0; file->priv->buff[0] = '\0'; file->priv->cur = (char*)0; file->priv->buffSize = archive_read_data(file->priv->archive, file->priv->buff, BUFF_SIZE); if (file->priv->buffSize < 0) { g_set_error(error, G_FILE_ERROR, G_FILE_ERROR_IO, _("read error from archive.\n")); return G_IO_STATUS_ERROR; } if (file->priv->buffSize == 0) return empty ? G_IO_STATUS_EOF : G_IO_STATUS_NORMAL; file->priv->buff[file->priv->buffSize] = '\0'; file->priv->cur = file->priv->buff; return G_IO_STATUS_NORMAL; } #endif /** * tool_files_read: * @file: a #ToolFiles object * @buffer: (array) (element-type char): a buffer * @count: the size of allocated @buffer in bytes. * @error: an error location or NULL * * Read @count bytes from @file and store them into @buffer. * * Since: 3.8 * * Returns: a IO status. **/ GIOStatus tool_files_read(ToolFiles *file, void *buffer, gsize count, GError **error) { g_return_val_if_fail(TOOL_IS_FILES(file), G_IO_STATUS_ERROR); g_return_val_if_fail(!error || *error == (GError*)0, G_IO_STATUS_ERROR); #ifdef HAVE_LIB_ARCHIVE if (file->priv->archive) { gchar *cbuff = (gchar*)buffer; while (TRUE) { GIOStatus status; if (file->priv->cur) { gsize buffSize = file->priv->buffSize - (file->priv->cur - file->priv->buff); if (count <= buffSize) { memcpy(cbuff, file->priv->cur, sizeof(char) * count); file->priv->cur += count; return G_IO_STATUS_NORMAL; } memcpy(cbuff, file->priv->cur, sizeof(char) * buffSize); cbuff += buffSize; count -= buffSize; } status = _archiveReadChunk(file, error); if (status != G_IO_STATUS_NORMAL) return status; } } #endif if (file->priv->direct) { file->priv->latest = g_io_channel_read_chars(file->priv->direct, buffer, count, NULL, error); return file->priv->latest; } else if (file->priv->data) { gsize len = strlen(file->priv->at); gchar *cbuff = (gchar*)buffer; cbuff[count] = '\0'; if (len >= count) memcpy(cbuff, file->priv->at, count); else cbuff[0] = '\0'; file->priv->at += MIN(len, count); return *file->priv->at ? G_IO_STATUS_NORMAL : G_IO_STATUS_EOF; } g_set_error(error, G_FILE_ERROR, G_FILE_ERROR_NOENT, _("file not opened.\n")); return G_IO_STATUS_ERROR; } /** * tool_files_skip: * @file: a #ToolFiles object. * @count: a number of bytes. * @error: an error location. * * Read @count bytes from @file but don't store them. * * Since: 3.8 * * Returns: a status. **/ GIOStatus tool_files_skip(ToolFiles *file, gsize count, GError **error) { g_return_val_if_fail(TOOL_IS_FILES(file), G_IO_STATUS_ERROR); g_return_val_if_fail(!error || *error == (GError*)0, G_IO_STATUS_ERROR); #ifdef HAVE_LIB_ARCHIVE if (file->priv->archive) { while (TRUE) { GIOStatus status; if (file->priv->cur) { gsize buffSize = file->priv->buffSize - (file->priv->cur - file->priv->buff); if (count <= buffSize) { file->priv->cur += count; return G_IO_STATUS_NORMAL; } count -= buffSize; } status = _archiveReadChunk(file, error); if (status != G_IO_STATUS_NORMAL) return status; } } #endif if (file->priv->direct) { file->priv->latest = g_io_channel_seek_position(file->priv->direct, count, G_SEEK_CUR, error); return file->priv->latest; } else if (file->priv->data) { file->priv->at += MIN( strlen(file->priv->at), count); return *file->priv->at ? G_IO_STATUS_NORMAL : G_IO_STATUS_EOF; } g_set_error(error, G_FILE_ERROR, G_FILE_ERROR_NOENT, _("file not opened.\n")); return G_IO_STATUS_ERROR; } /** * tool_files_read_line_string: * @file: a #ToolFiles object. * @buffer: (out caller-allocates): an allocated string. * @terminator_pos: (out caller-allocates): position of the terminator * in @buffer. * @error: an error location. * * Read a new line from @file and put it into @buffer. This works like * g_io_channel_read_line_string() but is transparent for compressed files. * * Since: 3.8 * * Returns: a status. **/ GIOStatus tool_files_read_line_string(ToolFiles *file, GString *buffer, gsize *terminator_pos, GError **error) { g_return_val_if_fail(TOOL_IS_FILES(file), G_IO_STATUS_ERROR); g_return_val_if_fail(!error || *error == (GError*)0, G_IO_STATUS_ERROR); #ifdef HAVE_LIB_ARCHIVE if (file->priv->archive) { if (buffer->str) g_string_set_size(buffer, 0); while (TRUE) { GIOStatus status; if (file->priv->cur) { char *eol = strchr(file->priv->cur, '\n'); if (eol) { char at = eol[1]; eol += 1; *eol = '\0'; g_string_append(buffer, file->priv->cur); *eol = at; file->priv->cur = eol; return G_IO_STATUS_NORMAL; } else if (*file->priv->cur) g_string_append(buffer, file->priv->cur); } status = _archiveReadChunk(file, error); if (status != G_IO_STATUS_NORMAL) return status; } } #endif if (file->priv->direct) { file->priv->latest = g_io_channel_read_line_string(file->priv->direct, buffer, terminator_pos, error); return file->priv->latest; } else if (file->priv->data) { char *eol = strchr(file->priv->at, '\n'); if (buffer->str) g_string_set_size(buffer, 0); if (eol) { char at = eol[1]; eol += 1; *eol = '\0'; g_string_append(buffer, file->priv->at); *eol = at; file->priv->at = eol; return G_IO_STATUS_NORMAL; } else if (*file->priv->at) { g_string_append(buffer, file->priv->at); for (; file->priv->at; file->priv->at++); return G_IO_STATUS_EOF; } else return G_IO_STATUS_EOF; } g_set_error(error, G_FILE_ERROR, G_FILE_ERROR_NOENT, _("file not opened.\n")); return G_IO_STATUS_ERROR; } /** * tool_files_rewind: * @file: a #ToolFiles object. * @error: an error location. * * Transparently rewind @file at the beginning for compressed files or not. * * Since: 3.8 * * Returns: a status. **/ GIOStatus tool_files_rewind(ToolFiles *file, GError **error) { #ifdef HAVE_LIB_ARCHIVE if (file->priv->archive) { /* Close and reopen. */ archive_read_free(file->priv->archive); return tool_files_open(file, file->priv->filename, error); } #endif if (file->priv->direct) { return g_io_channel_seek_position(file->priv->direct, 0, G_SEEK_SET, error); } else if (file->priv->data) { file->priv->at = file->priv->data; return G_IO_STATUS_NORMAL; } g_set_error(error, G_FILE_ERROR, G_FILE_ERROR_NOENT, _("file not opened.\n")); return G_IO_STATUS_ERROR; } /** * tool_files_atEnd: * @file: a #ToolFiles object. * * Inquires if @file is at end of file. * * Since: 3.8 * * Returns: TRUE on success. **/ gboolean tool_files_atEnd(ToolFiles *file) { g_return_val_if_fail(TOOL_IS_FILES(file), TRUE); #ifdef HAVE_LIB_ARCHIVE if (file->priv->archive) { if (file->priv->buffSize < 0) _archiveReadChunk(file, NULL); return file->priv->buffSize == 0; } #endif if (file->priv->direct) return file->priv->latest == G_IO_STATUS_EOF; else if (file->priv->data) return !*file->priv->at; return TRUE; } v_sim-3.8.0/src/coreTools/toolFiles.h000066400000000000000000000101761370110300500175030ustar00rootroot00000000000000/* EXTRAITS DE LA LICENCE Copyright CEA, contributeurs : Damien CALISTE, laboratoire L_Sim, (2017) Adresses mèl : CALISTE, damien P caliste AT cea P fr. Ce logiciel est un programme informatique servant à visualiser des structures atomiques dans un rendu pseudo-3D. Ce logiciel est régi par la licence CeCILL soumise au droit français et respectant les principes de diffusion des logiciels libres. Vous pouvez utiliser, modifier et/ou redistribuer ce programme sous les conditions de la licence CeCILL telle que diffusée par le CEA, le CNRS et l'INRIA sur le site "http://www.cecill.info". Le fait que vous puissiez accéder à cet en-tête signifie que vous avez pris connaissance de la licence CeCILL, et que vous en avez accepté les termes (cf. le fichier Documentation/licence.fr.txt fourni avec ce logiciel). */ /* LICENCE SUM UP Copyright CEA, contributors : Damien CALISTE, laboratoire L_Sim, (2017) E-mail addresses : CALISTE, damien P caliste AT cea P fr. This software is a computer program whose purpose is to visualize atomic configurations in 3D. This software is governed by the CeCILL license under French law and abiding by the rules of distribution of free software. You can use, modify and/ or redistribute the software under the terms of the CeCILL license as circulated by CEA, CNRS and INRIA at the following URL "http://www.cecill.info". The fact that you are presently reading this means that you have had knowledge of the CeCILL license and that you accept its terms. You can find a copy of this licence shipped with this software at Documentation/licence.en.txt. */ #ifndef TOOLFILES_H #define TOOLFILES_H #include #include "visu_tools.h" /** * TOOL_TYPE_FILES: * * return the type of #ToolFiles. */ #define TOOL_TYPE_FILES (tool_files_get_type ()) /** * FILES: * @obj: a #GObject to cast. * * Cast the given @obj into #ToolFiles type. */ #define TOOL_FILES(obj) (G_TYPE_CHECK_INSTANCE_CAST(obj, TOOL_TYPE_FILES, ToolFiles)) /** * TOOL_FILES_CLASS: * @klass: a #GObjectClass to cast. * * Cast the given @klass into #ToolFilesClass. */ #define TOOL_FILES_CLASS(klass) (G_TYPE_CHECK_CLASS_CAST(klass, TOOL_TYPE_FILES, ToolFilesClass)) /** * TOOL_IS_FILES: * @obj: a #GObject to test. * * Test if the given @ogj is of the type of #ToolFiles object. */ #define TOOL_IS_FILES(obj) (G_TYPE_CHECK_INSTANCE_TYPE(obj, TOOL_TYPE_FILES)) /** * TOOL_IS_FILES_CLASS: * @klass: a #GObjectClass to test. * * Test if the given @klass is of the type of #ToolFilesClass class. */ #define TOOL_IS_FILES_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE(klass, TOOL_TYPE_FILES)) /** * TOOL_FILES_GET_CLASS: * @obj: a #GObject to get the class of. * * It returns the class of the given @obj. */ #define TOOL_FILES_GET_CLASS(obj) (G_TYPE_INSTANCE_GET_CLASS(obj, TOOL_TYPE_FILES, ToolFilesClass)) typedef struct _ToolFiles ToolFiles; typedef struct _ToolFilesPrivate ToolFilesPrivate; typedef struct _ToolFilesClass ToolFilesClass; /** * ToolFiles: * * An opaque structure for the scalar field. */ struct _ToolFiles { VisuObject parent; ToolFilesPrivate *priv; }; /** * ToolFilesClass: * @parent: the parent class. * * An opaque structure for the class. */ struct _ToolFilesClass { VisuObjectClass parent; }; /** * tool_scalar_field_operator_get_type: * * This method returns the type of #ToolFiles, use TOOL_TYPE_FILES instead. * * Returns: the type of #ToolFiles. */ GType tool_files_get_type(void); ToolFiles* tool_files_new(); gboolean tool_files_open(ToolFiles *file, const gchar *filename, GError **error); void tool_files_fromMemory(ToolFiles *file, const gchar *data); void tool_files_setEncoding(ToolFiles *file, const gchar *encoding); GIOStatus tool_files_read(ToolFiles *file, void *buffer, gsize count, GError **error); GIOStatus tool_files_skip(ToolFiles *file, gsize count, GError **error); GIOStatus tool_files_read_line_string(ToolFiles *file, GString *buffer, gsize *terminator_pos, GError **error); gboolean tool_files_atEnd(ToolFiles *file); GIOStatus tool_files_rewind(ToolFiles *file, GError **error); #endif v_sim-3.8.0/src/coreTools/toolFortran.c000066400000000000000000000333341370110300500200500ustar00rootroot00000000000000/* EXTRAITS DE LA LICENCE Copyright CEA, contributeurs : Luc BILLARD, Damien CALISTE, Olivier D'Astier, laboratoire L_Sim, (2001-2005) Adresses mèl : BILLARD, non joignable par mèl ; CALISTE, damien P caliste AT cea P fr. D'ASTIER, dastier AT iie P cnam P fr. Ce logiciel est un programme informatique servant à visualiser des structures atomiques dans un rendu pseudo-3D. Ce logiciel est régi par la licence CeCILL soumise au droit français et respectant les principes de diffusion des logiciels libres. Vous pouvez utiliser, modifier et/ou redistribuer ce programme sous les conditions de la licence CeCILL telle que diffusée par le CEA, le CNRS et l'INRIA sur le site "http://www.cecill.info". Le fait que vous puissiez accéder à cet en-tête signifie que vous avez pris connaissance de la licence CeCILL, et que vous en avez accepté les termes (cf. le fichier Documentation/licence.fr.txt fourni avec ce logiciel). */ /* LICENCE SUM UP Copyright CEA, contributors : Luc BILLARD and Damien CALISTE and Olivier D'Astier, laboratoire L_Sim, (2001-2005) E-mail addresses : BILLARD, not reachable any more ; CALISTE, damien P caliste AT cea P fr. D'ASTIER, dastier AT iie P cnam P fr. This software is a computer program whose purpose is to visualize atomic configurations in 3D. This software is governed by the CeCILL license under French law and abiding by the rules of distribution of free software. You can use, modify and/ or redistribute the software under the terms of the CeCILL license as circulated by CEA, CNRS and INRIA at the following URL "http://www.cecill.info". The fact that you are presently reading this means that you have had knowledge of the CeCILL license and that you accept its terms. You can find a copy of this licence shipped with this software at Documentation/licence.en.txt. */ #include "toolFortran.h" #include /** * SECTION:toolFortran * @short_description: Introduces routines to read the binary Fortran data format. * * In Fortran binary data are written inside tags. These tags * give the size to the data that are between. The routines in this * module can read these tags and the data inside. One must know the * endianness of the file and the kind of data to be read (integer, * float, double...). If the first tag is known, one can test the * endianness of the file calling tool_files_fortran_testEndianness(). * The size of the tag (32 bits or 64 bits) is not modifiable * for the moment and is fixed at 32 bits. This may be changed in the * futur with the same kind of things that for endianness. */ /** * tool_files_fortran_open: * @file: a #ToolFiles object. * @filename: a file path. * @error: an error location. * * Open @filename as a Fortran binary file. * * Since: 3.8 * * Returns: TRUE on success. **/ gboolean tool_files_fortran_open(ToolFiles *file, const gchar *filename, GError **error) { if (!tool_files_open(file, filename, error)) return FALSE; tool_files_setEncoding(file, NULL); return TRUE; } /** * tool_files_fortran_readFlag: * @flux: a pointer on an opened file ; * @nb: (out): a location t store the value of the flag ; * @endianness: reverse or not the order of multi-bytes. * @error: a pointer to an error location ; * * Read the flag of a record (a 32bits integer). * * Returns: TRUE if everything went right. */ gboolean tool_files_fortran_readFlag(ToolFiles *flux, gsize *nb, ToolFortranEndianId endianness, GError **error) { guint n; if (tool_files_read(flux, &n, sizeof(guint), error) != G_IO_STATUS_NORMAL) return FALSE; DBG_fprintf(stderr, "Tool Fortran: reading flag %d %d (%d).\n", n, GUINT32_SWAP_LE_BE(n), endianness); if (endianness == TOOL_FORTRAN_ENDIAN_CHANGE) *nb = GUINT32_SWAP_LE_BE(n); else *nb = n; return TRUE; } gboolean tool_files_fortran_readCharacter(ToolFiles *flux, char *var, gsize nb, GError **error, ToolFortranEndianId endianness, gboolean testFlag, gboolean store) { if (testFlag && !tool_files_fortran_checkFlag(flux, nb, endianness, error)) return FALSE; if ((store && tool_files_read(flux, var, sizeof(char) * nb, error) != G_IO_STATUS_NORMAL) || (!store && tool_files_skip(flux, sizeof(char) * nb, error) != G_IO_STATUS_NORMAL)) return FALSE; if (testFlag && !tool_files_fortran_checkFlag(flux, nb, endianness, error)) return FALSE; return TRUE; } /** * tool_files_fortran_readString: * @flux: a #ToolFiles object. * @var: (out): a location to store the read string. * @nb: the length of the expected string. * @endianness: the endianness of @flux. * @testFlag: a boolean. * @error: an error location. * * Read a string from the next Fortran record. This string is * allocated with malloc and should be freed after use. The expected * string is supposed to employ @nb bytes on disk, padded with white * spaces. The output string is trimmed from whitespaces though. * * Since: 3.8 * * Returns: TRUE on success. **/ gboolean tool_files_fortran_readString(ToolFiles *flux, gchar **var, gsize nb, ToolFortranEndianId endianness, gboolean testFlag, GError **error) { if (testFlag && !tool_files_fortran_checkFlag(flux, nb, endianness, error)) return FALSE; if (var) *var = g_malloc(sizeof(gchar) * (nb + 1)); if ((var && tool_files_read(flux, *var, sizeof(char) * nb, error) != G_IO_STATUS_NORMAL) || (!var && tool_files_skip(flux, sizeof(char) * nb, error) != G_IO_STATUS_NORMAL)) { if (var) g_free(*var); return FALSE; } if (var) { (*var)[nb] = '\0'; g_strchomp(*var); } if (testFlag && !tool_files_fortran_checkFlag(flux, nb, endianness, error)) { if (var) g_free(*var); return FALSE; } return TRUE; } static gboolean _readArray(ToolFiles *flux, GArray **var, gsize esize, gsize nb, ToolFortranEndianId endianness, gboolean testFlag, GError **error) { if (testFlag && !tool_files_fortran_checkFlag(flux, esize * nb, endianness, error)) return FALSE; /* Read the data. */ if (var) *var = g_array_sized_new(FALSE, FALSE, esize, nb); if ((var && tool_files_read(flux, (*var)->data, esize * nb, error) != G_IO_STATUS_NORMAL) || (!var && tool_files_skip(flux, esize * nb, error) != G_IO_STATUS_NORMAL)) { if (var) g_array_unref(*var); return FALSE; } if (var) g_array_set_size(*var, nb); if (testFlag && !tool_files_fortran_checkFlag(flux, esize * nb, endianness, error)) { if (var) g_array_unref(*var); return FALSE; } return TRUE; } /** * tool_files_fortran_readInteger: * @flux: a pointer on an opened file ; * @var: (out): an integer location. * @error: a pointer to an error location ; * @endianness: reverse or not the order of multi-bytes ; * * Read one integer without reading enclosing flags. * * Returns: TRUE if everything went right. */ gboolean tool_files_fortran_readInteger(ToolFiles *flux, gint *var, ToolFortranEndianId endianness, GError **error) { char c[sizeof(gint)]; register guint ks, l; gint *val; if (tool_files_read(flux, (char*)var, sizeof(gint), error) != G_IO_STATUS_NORMAL) return FALSE; if (endianness == TOOL_FORTRAN_ENDIAN_CHANGE) { ks = sizeof(int) - 1; for(l=0; ldata; for(k=0; kdata + ks - l); val = (guint*)c; data[k] = *val; } } return TRUE; } /** * tool_files_fortran_readRealArray: * @flux: a pointer on an opened file ; * @var: (out) (element-type float): an allocated array of float ; * @nb: the expected size of the array @var ; * @endianness: reverse or not the order of multi-bytes ; * @testFlag: if TRUE, read start and stop flags and test their * values ; * @error: a pointer to an error location ; * * Read an array of reals from a fortran record. * * Returns: TRUE if everything went right. */ gboolean tool_files_fortran_readRealArray(ToolFiles *flux, GArray **var, gsize nb, ToolFortranEndianId endianness, gboolean testFlag, GError **error) { char c[sizeof(float)]; register guint k, ks, l; float *val, *data; if (!_readArray(flux, var, sizeof(gfloat), nb, endianness, testFlag, error)) return FALSE; if (var && endianness == TOOL_FORTRAN_ENDIAN_CHANGE) { data = (float*)(*var)->data; for(k=0; kdata + ks - l); val = (float*)c; data[k] = *val; } } return TRUE; } /** * tool_files_fortran_readDouble: * @flux: a pointer on an opened file ; * @var: (out): a double location. * @error: a pointer to an error location ; * @endianness: reverse or not the order of multi-bytes ; * * Read one double without reading enclosing flags. * * Returns: TRUE if everything went right. */ gboolean tool_files_fortran_readDouble(ToolFiles *flux, gdouble *var, ToolFortranEndianId endianness, GError **error) { char c[sizeof(gdouble)]; register guint ks, l; gdouble *val; if (tool_files_read(flux, (char*)var, sizeof(gdouble), error) != G_IO_STATUS_NORMAL) return FALSE; if (endianness == TOOL_FORTRAN_ENDIAN_CHANGE) { ks = sizeof(gdouble) - 1; for(l=0; ldata; for(k=0; kdata + ks - l); val = (double*)c; data[k] = *val; } } return TRUE; } /** * tool_files_fortran_testEndianness: * @flux: a pointer on an opened file ; * @nb: the value of the flag to read ; * @endianness: (out): a location to store the endianness. * * Read a flag and compare the value with @nb for little and big endian. * It return the value of endianness to be used after. The file is rewind after the * call. * * Returns: TRUE if everything went right. */ gboolean tool_files_fortran_testEndianness(ToolFiles *flux, gsize nb, ToolFortranEndianId *endianness) { gsize n; guint nf; if (!tool_files_fortran_readFlag(flux, &n, TOOL_FORTRAN_ENDIAN_KEEP, NULL)) return FALSE; nf = n; DBG_fprintf(stderr, "Tool Fortran: testing endianness %d %d (%ld).\n", nf, GUINT32_SWAP_LE_BE(nf), nb); *endianness = TOOL_FORTRAN_ENDIAN_KEEP; if (GUINT32_SWAP_LE_BE(nf) == (guint)nb) *endianness = TOOL_FORTRAN_ENDIAN_CHANGE; else if (n != nb) return FALSE; return TRUE; } /** * tool_files_fortran_checkFlag: * @flux: a #ToolFiles object. * @ncheck: the size to be checked for. * @endian: the endianness of @flux. * @error: a location for an error. * * Read the next Fortran flag and check that it's content is equal to @ncheck. * * Since: 3.8 * * Returns: TRUE on successful read. **/ gboolean tool_files_fortran_checkFlag(ToolFiles *flux, gsize ncheck, ToolFortranEndianId endian, GError **error) { gsize mcheck; if (!tool_files_fortran_readFlag(flux, &mcheck, endian, error)) return FALSE; if (ncheck != mcheck) { g_set_error(error, VISU_DATA_LOADABLE_ERROR, DATA_LOADABLE_ERROR_FORMAT, _("wrong fortran syntax, flag size unmatched (%ld != %ld).\n"), ncheck, mcheck); return FALSE; } return TRUE; } v_sim-3.8.0/src/coreTools/toolFortran.h000066400000000000000000000117171370110300500200560ustar00rootroot00000000000000/* EXTRAITS DE LA LICENCE Copyright CEA, contributeurs : Luc BILLARD, Damien CALISTE, Olivier D'Astier, laboratoire L_Sim, (2001-2005) Adresses mèl : BILLARD, non joignable par mèl ; CALISTE, damien P caliste AT cea P fr. D'ASTIER, dastier AT iie P cnam P fr. Ce logiciel est un programme informatique servant à visualiser des structures atomiques dans un rendu pseudo-3D. Ce logiciel est régi par la licence CeCILL soumise au droit français et respectant les principes de diffusion des logiciels libres. Vous pouvez utiliser, modifier et/ou redistribuer ce programme sous les conditions de la licence CeCILL telle que diffusée par le CEA, le CNRS et l'INRIA sur le site "http://www.cecill.info". Le fait que vous puissiez accéder à cet en-tête signifie que vous avez pris connaissance de la licence CeCILL, et que vous en avez accepté les termes (cf. le fichier Documentation/licence.fr.txt fourni avec ce logiciel). */ /* LICENCE SUM UP Copyright CEA, contributors : Luc BILLARD and Damien CALISTE and Olivier D'Astier, laboratoire L_Sim, (2001-2005) E-mail addresses : BILLARD, not reachable any more ; CALISTE, damien P caliste AT cea P fr. D'ASTIER, dastier AT iie P cnam P fr. This software is a computer program whose purpose is to visualize atomic configurations in 3D. This software is governed by the CeCILL license under French law and abiding by the rules of distribution of free software. You can use, modify and/ or redistribute the software under the terms of the CeCILL license as circulated by CEA, CNRS and INRIA at the following URL "http://www.cecill.info". The fact that you are presently reading this means that you have had knowledge of the CeCILL license and that you accept its terms. You can find a copy of this licence shipped with this software at Documentation/licence.en.txt. */ #ifndef TOOLFORTRAN_H #define TOOLFORTRAN_H #include #include "toolFiles.h" /** * ToolFortranEndianId: * @TOOL_FORTRAN_ENDIAN_KEEP: read a file without inverting records. * @TOOL_FORTRAN_ENDIAN_CHANGE: read a file inverting records. * * Thiese ids are used when reading a multi-bytes information from a binary file. */ typedef enum { TOOL_FORTRAN_ENDIAN_KEEP, TOOL_FORTRAN_ENDIAN_CHANGE } ToolFortranEndianId; gboolean tool_files_fortran_open(ToolFiles *file, const gchar *filename, GError **error); /** * tool_files_fortran_readCharacter: * @var: an allocated array of char ; * @nb: the size of the array @var ; * @flux: a pointer on an opened file ; * @error: a pointer to an error location ; * @endianness: reverse or not the order of multi-bytes ; * @testFlag: if TRUE, read start and stop flags and test their values * ; * @store: a boolean. * * Read an array of characters from a fortran record. The endianness is required * to read the Fortran flag. If argument @store is FALSE, then the * file is read and consistency checked but no data is stored. In that * case, @var can be not allocated. * * Returns: TRUE if everything went right. */ gboolean tool_files_fortran_readCharacter(ToolFiles *flux, char *var, gsize nb, GError **error, ToolFortranEndianId endianness, gboolean testFlag, gboolean store); gboolean tool_files_fortran_readString(ToolFiles *flux, gchar **var, gsize nb, ToolFortranEndianId endianness, gboolean testFlag, GError **error); gboolean tool_files_fortran_readInteger(ToolFiles *flux, gint *var, ToolFortranEndianId endianness, GError **error); gboolean tool_files_fortran_readIntegerArray(ToolFiles *flux, GArray **var, gsize nb, ToolFortranEndianId endianness, gboolean testFlag, GError **error); gboolean tool_files_fortran_readRealArray(ToolFiles *flux, GArray **var, gsize nb, ToolFortranEndianId endianness, gboolean testFlag, GError **error); gboolean tool_files_fortran_readDouble(ToolFiles *flux, double *var, ToolFortranEndianId endianness, GError **error); gboolean tool_files_fortran_readDoubleArray(ToolFiles *flux, GArray **var, gsize nb, ToolFortranEndianId endianness, gboolean testFlag, GError **error); gboolean tool_files_fortran_readFlag(ToolFiles *flux, gsize *nb, ToolFortranEndianId endianness, GError **error); gboolean tool_files_fortran_testEndianness(ToolFiles *flux, gsize nb, ToolFortranEndianId *endianness); gboolean tool_files_fortran_checkFlag(ToolFiles *flux, gsize ncheck, ToolFortranEndianId endian, GError **error); #endif v_sim-3.8.0/src/coreTools/toolMatrix.c000066400000000000000000000613041370110300500176770ustar00rootroot00000000000000/* EXTRAITS DE LA LICENCE Copyright CEA, contributeurs : Luc BILLARD et Damien CALISTE, laboratoire L_Sim, (2001-2005) Adresse mèl : BILLARD, non joignable par mèl ; CALISTE, damien P caliste AT cea P fr. Ce logiciel est un programme informatique servant à visualiser des structures atomiques dans un rendu pseudo-3D. Ce logiciel est régi par la licence CeCILL soumise au droit français et respectant les principes de diffusion des logiciels libres. Vous pouvez utiliser, modifier et/ou redistribuer ce programme sous les conditions de la licence CeCILL telle que diffusée par le CEA, le CNRS et l'INRIA sur le site "http://www.cecill.info". Le fait que vous puissiez accéder à cet en-tête signifie que vous avez pris connaissance de la licence CeCILL, et que vous en avez accepté les termes (cf. le fichier Documentation/licence.fr.txt fourni avec ce logiciel). */ /* LICENCE SUM UP Copyright CEA, contributors : Luc BILLARD et Damien CALISTE, laboratoire L_Sim, (2001-2005) E-mail address: BILLARD, not reachable any more ; CALISTE, damien P caliste AT cea P fr. This software is a computer program whose purpose is to visualize atomic configurations in 3D. This software is governed by the CeCILL license under French law and abiding by the rules of distribution of free software. You can use, modify and/ or redistribute the software under the terms of the CeCILL license as circulated by CEA, CNRS and INRIA at the following URL "http://www.cecill.info". The fact that you are presently reading this means that you have had knowledge of the CeCILL license and that you accept its terms. You can find a copy of this licence shipped with this software at Documentation/licence.en.txt. */ #include "toolMatrix.h" #include #include #include #include "toolConfigFile.h" /** * SECTION:toolMatrix * @short_description: Defines basic handlings on matrix. * * Some very basic linear algebra are redefined here. It also * gives access to coordinates conversion, essentially between * cartesian and spherical. */ /** * VisuBoxVertices: * @vertices: (array fixed-size=8) (element-type ToolVector): * * Structure used for bindings. * * Since: 3.7 */ /** * VisuBoxCell: * @box: (array fixed-size=6) (element-type gdouble): * * Structure used for bindings. * * Since: 3.7 */ /** * ToolVector: * * An opaque object, to exchange three floats as #GObject properties. * * Since: 3.8 */ /** * ToolGridSize: * @grid: (array fixed-size=3) (element-type guint): * * Structure used for bindings. * * Since: 3.7 */ /** * tool_matrix_reducePrimitiveVectors: * @reduced: (out caller-allocates) (array fixed-size=6): a storage for 6 floating point values ; * @full: (in) (array fixed-size=9): a full 3x3 matrix to be transformed. * * This routine transforms the given matrix @full into a reduced array * used by V_Sim to store box definition. * * Returns: FALSE if the given matrix is planar. */ gboolean tool_matrix_reducePrimitiveVectors(double reduced[6], double full[3][3]) { double X[3]; double Y[3]; double Z[3]; double u[3], x[3]; int i, j, k; double deltaIJ; double norm; g_return_val_if_fail(reduced && full, FALSE); DBG_fprintf(stderr, "Matrix: transform full to reduced matrix.\n"); DBG_fprintf(stderr, "Matrix: full is %8g %8g %8g\n" " %8g %8g %8g\n" " %8g %8g %8g\n", full[0][0], full[0][1], full[0][2], full[1][0], full[1][1], full[1][2], full[2][0], full[2][1], full[2][2]); /* Compute the X vector of the new basis, colinear with old x. */ for (i = 0; i < 3; i++) { X[i] = full[0][i]; x[i] = full[0][i]; } /* Compute the Y vector of the new basis, orthogonal to X and coplanar with X and old y vector. */ u[0] = full[0][1] * full[1][2] - full[0][2] * full[1][1]; u[1] = full[0][2] * full[1][0] - full[0][0] * full[1][2]; u[2] = full[0][0] * full[1][1] - full[0][1] * full[1][0]; /* DBG_fprintf(stderr, "x : %f %f %f\n", x[0], x[1], x[2]); */ /* DBG_fprintf(stderr, "x vect y : %f %f %f\n", u[0], u[1], u[2]); */ deltaIJ = x[0] * u[1] - x[1] * u[0]; if (deltaIJ != 0.) { i = 0; j = 1; k = 2; DBG_fprintf(stderr, " Using deltaIJ scheme with (i, j, k)" " = (%d, %d, %d)\n", i, j, k); } else { deltaIJ = x[0] * u[2] - x[2] * u[0]; if (deltaIJ != 0.) { i = 0; j = 2; k = 1; DBG_fprintf(stderr, " Using deltaIJ scheme with (i, j, k)" " = (%d, %d, %d)\n", i, j, k); } else { deltaIJ = x[1] * u[2] - x[2] * u[1]; if (deltaIJ != 0.) { i = 1; j = 2; k = 0; DBG_fprintf(stderr, " Using deltaIJ scheme with (i, j, k)" " = (%d, %d, %d)\n", i, j, k); } else return FALSE; } } Y[k] = -1.; Y[i] = (x[k] * u[j] - x[j] * u[k]) / deltaIJ; Y[j] = (x[i] * u[k] - x[k] * u[i]) / deltaIJ; /* We need to turn Y if y.Y is negative. */ norm = 0.; for (i = 0; i < 3; i++) norm += full[1][i] * Y[i]; if (norm < 0.) for (i = 0; i < 3; i++) Y[i] *= -1.; /* Compute the new Z vector in order to form a direct orthogonal basis with X and Y. */ Z[0] = X[1] * Y[2] - X[2] * Y[1]; Z[1] = X[2] * Y[0] - X[0] * Y[2]; Z[2] = X[0] * Y[1] - X[1] * Y[0]; /* Normalise the new basis (X, Y, Z). */ norm = 0.; for (i = 0; i < 3; i++) norm += X[i] * X[i]; norm = sqrt(norm); for (i = 0; i < 3; i++) X[i] /= norm; norm = 0.; for (i = 0; i < 3; i++) norm += Y[i] * Y[i]; norm = sqrt(norm); for (i = 0; i < 3; i++) Y[i] /= norm; norm = 0.; for (i = 0; i < 3; i++) norm += Z[i] * Z[i]; norm = sqrt(norm); for (i = 0; i < 3; i++) Z[i] /= norm; /* DBG_fprintf(stderr, "X : %f %f %f\n", X[0], X[1], X[2]); */ /* DBG_fprintf(stderr, "Y : %f %f %f\n", Y[0], Y[1], Y[2]); */ /* DBG_fprintf(stderr, "Z : %f %f %f\n", Z[0], Z[1], Z[2]); */ /* Compute the reduce value for the basis. */ DBG_fprintf(stderr, " Write to reduced (%p).\n", (gpointer)reduced); reduced[0] = 0.; for (i = 0; i < 3; i++) reduced[0] += X[i] * full[0][i]; reduced[1] = 0.; for (i = 0; i < 3; i++) reduced[1] += X[i] * full[1][i]; reduced[2] = 0.; for (i = 0; i < 3; i++) reduced[2] += Y[i] * full[1][i]; reduced[3] = 0.; for (i = 0; i < 3; i++) reduced[3] += X[i] * full[2][i]; reduced[4] = 0.; for (i = 0; i < 3; i++) reduced[4] += Y[i] * full[2][i]; reduced[5] = 0.; for (i = 0; i < 3; i++) reduced[5] += Z[i] * full[2][i]; DBG_fprintf(stderr, " Write OK.\n"); return TRUE; } /** * tool_matrix_dtof: * @mf: a matrix in single precision. * @md: a matrix in double precision. * * Cast @md into @mf. * * Since: 3.7 **/ void tool_matrix_dtof(float mf[3][3], double md[3][3]) { int i, j; for (i = 0; i < 3; i++) for (j = 0; j < 3; j++) mf[i][j] = md[i][j]; } /** * tool_matrix_setIdentity: * @mat: (array fixed-size=9): a matrix location. * * Initialise @mat with the identity. * * Since: 3.7 **/ void tool_matrix_setIdentity(float mat[3][3]) { mat[0][0] = 1.f; mat[0][1] = 0.f; mat[0][2] = 0.f; mat[1][0] = 0.f; mat[1][1] = 1.f; mat[1][2] = 0.f; mat[2][0] = 0.f; mat[2][1] = 0.f; mat[2][2] = 1.f; } /** * tool_matrix_set: * @mat: a matrix. * @orig: a matrix. * * Copy @orig into @mat. * * Since: 3.8 **/ void tool_matrix_set(float mat[3][3], float orig[3][3]) { mat[0][0] = orig[0][0]; mat[0][1] = orig[0][1]; mat[0][2] = orig[0][2]; mat[1][0] = orig[1][0]; mat[1][1] = orig[1][1]; mat[1][2] = orig[1][2]; mat[2][0] = orig[2][0]; mat[2][1] = orig[2][1]; mat[2][2] = orig[2][2]; } /** * tool_matrix_rotate: * @mat: a matrix. * @angle: an angle in degrees. * @dir: a direction. * * Create a rotation matrix along axis @dir of the given @angle. * * Since: 3.8 **/ void tool_matrix_rotate(float mat[3][3], float angle, ToolXyzDir dir) { float rot[3][3], work[3][3]; int perm[3][3] = {{1, 2, 0}, {2, 0, 1}, {0, 1, 2}}; rot[perm[dir][0]][perm[dir][0]] = cos(angle * TOOL_PI180); rot[perm[dir][0]][perm[dir][1]] = -sin(angle * TOOL_PI180); rot[perm[dir][0]][perm[dir][2]] = 0.f; rot[perm[dir][1]][perm[dir][0]] = sin(angle * TOOL_PI180); rot[perm[dir][1]][perm[dir][1]] = cos(angle * TOOL_PI180); rot[perm[dir][1]][perm[dir][2]] = 0.f; rot[perm[dir][2]][perm[dir][0]] = 0.f; rot[perm[dir][2]][perm[dir][1]] = 0.f; rot[perm[dir][2]][perm[dir][2]] = 1.f; tool_matrix_set(work, mat); tool_matrix_productMatrix(mat, work, rot); } /** * tool_matrix_productMatrix: * @matRes: an array of floating point values of size 3x3 ; * @matA: an array of floating point values of size 3x3 ; * @matB: an array of floating point values of size 3x3. * * Compute the mathematical product between @matA and @matB and * put the result matrix in @matRes. * * Since: 3.2 */ void tool_matrix_productMatrix(float matRes[3][3], float matA[3][3], float matB[3][3]) { int i, j, k; for (i = 0; i < 3; i++) for (j = 0; j < 3; j++) { matRes[i][j] = 0.; for (k = 0; k < 3; k++) matRes[i][j] += matA[i][k] * matB[k][j]; } } /** * tool_matrix_productVector: * @vectRes: an array of floating point values of size 3 ; * @mat: an array of floating point values of size 3x3 ; * @vect: an array of floating point values of size 3. * * Compute the mathematical product between @matA and @vect and * put the result vector in @vectRes. * * Since: 3.2 */ void tool_matrix_productVector(float vectRes[3], float mat[3][3], float vect[3]) { int i, j; for (i = 0; i < 3; i++) { vectRes[i] = 0.; for (j = 0; j < 3; j++) vectRes[i] += mat[i][j] * vect[j]; } } /** * tool_matrix_determinant: * @mat: a matrix. * * Calculate the determinant of matrix @mat. * * Since: 3.6 * * Returns: the determinant value. */ float tool_matrix_determinant(float mat[3][3]) { DBG_fprintf(stderr, "Tool Matrix: %g is det( %8g %8g %8g\n" " %8g %8g %8g\n" " %8g %8g %8g )\n", mat[0][0] * (mat[1][1] * mat[2][2] - mat[1][2] * mat[2][1]) - mat[0][1] * (mat[1][0] * mat[2][2] - mat[1][2] * mat[2][0]) + mat[0][2] * (mat[1][0] * mat[2][1] - mat[1][1] * mat[2][0]), mat[0][0], mat[0][1], mat[0][2], mat[1][0], mat[1][1], mat[1][2], mat[2][0], mat[2][1], mat[2][2]); return mat[0][0] * (mat[1][1] * mat[2][2] - mat[1][2] * mat[2][1]) - mat[0][1] * (mat[1][0] * mat[2][2] - mat[1][2] * mat[2][0]) + mat[0][2] * (mat[1][0] * mat[2][1] - mat[1][1] * mat[2][0]); } /** * tool_matrix_invert: * @inv: a matrix (out values). * @mat: a matrix. * * Calculate the inverse matrix of matrix @mat and store it in @inv. * * Since: 3.6 * * Returns: FALSE if @mat is singular. */ gboolean tool_matrix_invert(float inv[3][3], float mat[3][3]) { float det; det = tool_matrix_determinant(mat); if (det == 0.f) return FALSE; det = 1.f / det; inv[0][0] = det * (mat[1][1] * mat[2][2] - mat[1][2] * mat[2][1]); inv[0][1] = det * (mat[0][2] * mat[2][1] - mat[0][1] * mat[2][2]); inv[0][2] = det * (mat[0][1] * mat[1][2] - mat[0][2] * mat[1][1]); inv[1][0] = det * (mat[1][2] * mat[2][0] - mat[1][0] * mat[2][2]); inv[1][1] = det * (mat[0][0] * mat[2][2] - mat[0][2] * mat[2][0]); inv[1][2] = det * (mat[0][2] * mat[1][0] - mat[0][0] * mat[1][2]); inv[2][0] = det * (mat[1][0] * mat[2][1] - mat[1][1] * mat[2][0]); inv[2][1] = det * (mat[0][1] * mat[2][0] - mat[0][0] * mat[2][1]); inv[2][2] = det * (mat[0][0] * mat[1][1] - mat[0][1] * mat[1][0]); return TRUE; } /** * tool_matrix_getRotationFromFull: * @rot: a rotation matrix (out values). * @full: the description of basis set in full development. * @box: the description of basis set in align X axis. * * There is a rotation matrix to transform from full cartesian * coordinates into reduced box cartesian coordinates. * * Since: 3.6 * * Returns: TRUE if @full does not describe properly a 3D box. */ gboolean tool_matrix_getRotationFromFull(float rot[3][3], double full[3][3], double box[6]) { float boxMat[3][3], fileMat[3][3], fileMatInv[3][3]; /* We create the rotation matrix that pass from the cartesian coordinates of the file to the cartesian coordinates of the box. */ boxMat[0][0] = box[0]; boxMat[0][1] = box[1]; boxMat[0][2] = box[3]; boxMat[1][0] = 0.f; boxMat[1][1] = box[2]; boxMat[1][2] = box[4]; boxMat[2][0] = 0.f; boxMat[2][1] = 0.f; boxMat[2][2] = box[5]; fileMat[0][0] = (float)full[0][0]; fileMat[0][1] = (float)full[1][0]; fileMat[0][2] = (float)full[2][0]; fileMat[1][0] = (float)full[0][1]; fileMat[1][1] = (float)full[1][1]; fileMat[1][2] = (float)full[2][1]; fileMat[2][0] = (float)full[0][2]; fileMat[2][1] = (float)full[1][2]; fileMat[2][2] = (float)full[2][2]; if (!tool_matrix_invert(fileMatInv, fileMat)) return FALSE; tool_matrix_productMatrix(rot, boxMat, fileMatInv); DBG_fprintf(stderr, "Tool Matrix: rotation matrix %8g %8g %8g\n" " %8g %8g %8g\n" " %8g %8g %8g\n", rot[0][0], rot[0][1], rot[0][2], rot[1][0], rot[1][1], rot[1][2], rot[2][0], rot[2][1], rot[2][2]); return TRUE; } #ifndef RAD2DEG #define RAD2DEG(x) (57.29577951308232311 * x) #endif #ifndef DEG2RAD #define DEG2RAD(x) (0.01745329251994329509 * x) #endif /** * tool_matrix_cartesianToSpherical: * @spherical: an allocated array of 3 floating point values to store the result ; * @cartesian: an allocated array of 3 floating point values to read the input. * * A method to transform cartesian coordinates in spherical * coordinates (radius, phi and theta). * * Since: 3.3 */ void tool_matrix_cartesianToSpherical(float spherical[3], const float cartesian[3]) { /* s[0] = rho, s[1] = theta, s[2] = phi c[0] = x, c[1] = y, c[2] = z */ double rho; double theta; double phi; if (cartesian[0] == 0 && cartesian[1] == 0 && cartesian[2] == 0) { spherical[TOOL_MATRIX_SPHERICAL_MODULUS] = 0; spherical[TOOL_MATRIX_SPHERICAL_THETA] = 0; spherical[TOOL_MATRIX_SPHERICAL_PHI] = 0; return; } rho = sqrt(cartesian[0] * cartesian[0] + cartesian[1] * cartesian[1] + cartesian[2] * cartesian[2]); if (cartesian[0] == 0 && cartesian[1] == 0) theta = (cartesian[2] > 0) ? 0 : G_PI; else theta = acos(CLAMP(cartesian[2] / rho, -1., 1.)); if (cartesian[0] != 0) { phi = atan(cartesian[1] / cartesian[0]) + G_PI*((cartesian[0] < 0) ? 1 : 0); } else { if (cartesian[1] == 0) /* facultatif*/ phi = 0; /* facultatif*/ else if(cartesian[1] > 0) phi = G_PI_2; else phi = -G_PI_2; } spherical[TOOL_MATRIX_SPHERICAL_MODULUS] = rho; spherical[TOOL_MATRIX_SPHERICAL_THETA] = RAD2DEG(theta); spherical[TOOL_MATRIX_SPHERICAL_PHI] = tool_modulo_float(RAD2DEG(phi), 360); } /** * tool_matrix_sphericalToCartesian: * @cartesian: an allocated array of 3 floating point values to store the result ; * @spherical: an allocated array of 3 floating point values to read the input. * * A method to transform spherical coordinates (radius, phi and theta) * to cartesian coordinates. * * Since: 3.3 */ void tool_matrix_sphericalToCartesian(float cartesian[3], const float spherical[3]) { cartesian[0] = spherical[TOOL_MATRIX_SPHERICAL_MODULUS] * sin(DEG2RAD(spherical[TOOL_MATRIX_SPHERICAL_THETA])) * cos(DEG2RAD(spherical[TOOL_MATRIX_SPHERICAL_PHI])); cartesian[1] = spherical[TOOL_MATRIX_SPHERICAL_MODULUS] * sin(DEG2RAD(spherical[TOOL_MATRIX_SPHERICAL_THETA])) * sin(DEG2RAD(spherical[TOOL_MATRIX_SPHERICAL_PHI])); cartesian[2] = spherical[TOOL_MATRIX_SPHERICAL_MODULUS] * cos(DEG2RAD(spherical[TOOL_MATRIX_SPHERICAL_THETA])); } /** * tool_matrix_getInter2D: * @lambda: a location to store a float. * @a: a point. * @b: another point. * @A: a point. * @B: another point. * * Get the intersection coeeficient of lines [ab] and [AB]. * * Returns: TRUE if [ab] and [AB] have an intersection. */ gboolean tool_matrix_getInter2D(float *lambda, float a[2], float b[2], float A[2], float B[2]) { float denom; denom = (b[0] - a[0]) * (B[1] - A[1]) - (b[1] - a[1]) * (B[0] - A[0]); if (denom == 0.f) return FALSE; *lambda = (A[0] - a[0]) * (B[1] - A[1]) - (A[1] - a[1]) * (B[0] - A[0]); *lambda /= denom; /* fprintf(stderr, "%g\n", *lambda); */ return TRUE; } /** * tool_matrix_getInter2DFromList: (skip) * @i: a location to store a point. * @lambda: a location to store a float. * @a: a point. * @b: another point. * @set: a list of points. * * Same as tool_matrix_getInter2D(), but from a list of points. * * Returns: TRUE if an intersection exists. */ gboolean tool_matrix_getInter2DFromList(float i[2], float *lambda, float a[2], float b[2], GList *set) { float *pt1, *pt2; float l, min; i[0] = a[0]; i[1] = a[1]; min = 1.2f; for (pt1 = (float*)(g_list_last(set)->data); set; set = g_list_next(set)) { pt2 = (float*)set->data; if (tool_matrix_getInter2D(&l, a, b, pt1, pt2)) min = (l >= 0.f)?MIN(min, l):min; pt1 = pt2; } if (min > 1.00001f) return FALSE; if (lambda) *lambda = min; i[0] = (b[0] - a[0]) * min + a[0]; i[1] = (b[1] - a[1]) * min + a[1]; /* fprintf(stderr, "%g -> %gx%g\n", min, i[0], i[1]); */ return TRUE; } #define FLAG_PARAMETER_THRESHOLD "scale_log_threshold" #define DESC_PARAMETER_THRESHOLD "Value of the threshold used in the zero centred TOOL_MATRIX_SCALING_LOG scaling function ; a positive float (1e-3)" static float threshold = 1e-3; static void exportParameters(GString *data, VisuData *dataObj); /** * tool_matrix_getScaledLinear: * @x: the initial value ; * @minmax: the boundaries for the @x argument ; * * Transform @x into [0;1] with a linear scale. * * Returns: a value into [0;1]. * * Since: 3.5 */ float tool_matrix_getScaledLinear(float x, float minmax[2]) { return ((CLAMP(x, minmax[0], minmax[1]) - minmax[0]) / (minmax[1] - minmax[0])); } /** * tool_matrix_getScaledLog: * @x: the initial value ; * @minmax: the boundaries for the @x argument. * * Transform @x into [0;1] with a log scale. * * Returns: a value into [0;1]. * * Since: 3.5 */ float tool_matrix_getScaledLog(float x, float minmax[2]) { /* float v; */ float lMinMax[2]; lMinMax[0] = log10(MAX(1e-12, minmax[0])); lMinMax[1] = log10(MAX(1e-12, minmax[1])); return tool_matrix_getScaledLinear(log10(MAX(1e-12, x)), lMinMax); /* return (v == 0.)?0.: - (log10(v) - param) / param; */ } /** * tool_matrix_getScaledZeroCentredLog: * @x: the initial value ; * @minmax: the boundaries for the @x argument. * * Transform @x into [0;1] with a log scale with zero centred values. * * Returns: a value into [0;1]. * * Since: 3.5 */ float tool_matrix_getScaledZeroCentredLog(float x, float minmax[2]) { float v, m; m = MAX(minmax[1], -minmax[0]); v = CLAMP(x, -m, m); return 0.5 + (v < 0.?-1.:1.) * (log(m * threshold) - log(MAX(ABS(v), m * threshold))) / (2. * log(threshold)); } /** * tool_matrix_getScaledLinearInv: * @x: the initial value ; * @minmax: the boundaries for the @x argument. * * Reverse function for tool_matrix_getScaledLinear(). * * Returns: a value into [0;1]. * * Since: 3.5 */ float tool_matrix_getScaledLinearInv(float x, float minmax[2]) { return (minmax[0] + CLAMP(x, 0., 1.) * (minmax[1] - minmax[0])); } /** * tool_matrix_getScaledLogInv: * @x: the initial value ; * @minmax: the boundaries for the @x argument. * * Reverse function for tool_matrix_getScaledLog(). * * Returns: a value into [0;1]. * * Since: 3.5 */ float tool_matrix_getScaledLogInv(float x, float minmax[2]) { return MAX(1e-12, minmax[0]) * pow(MAX(1e-12, minmax[1]) / MAX(1e-12, minmax[0]), CLAMP(x, 0., 1.)); /* return (minmax[0] + (minmax[1] - minmax[0]) * exp((1. - CLAMP(x, 0., 1.)) * param)); */ } /** * tool_matrix_getScaledZeroCentredLogInv: * @x: the initial value ; * @minmax: the boundaries for the @x argument. * * Reverse function for tool_matrix_getScaledZeroCentredLog(). * * Returns: a value into [0;1]. * * Since: 3.5 */ float tool_matrix_getScaledZeroCentredLogInv(float x, float minmax[2]) { float s, m, out; DBG_fprintf(stderr, "Matrix: get inv ZCL %g (%g-%g).\n", x, minmax[0], minmax[1]); s = (x < 0.5)?-1.:1.; m = MAX(minmax[1], -minmax[0]); out = s * m * threshold * exp(s * (1. - 2. * CLAMP(x, 0., 1.)) * log(threshold)); DBG_fprintf(stderr, " | %g (%g)\n", out, tool_matrix_getScaledZeroCentredLog(out, minmax)); return out; } static void exportParameters(GString *data, VisuData *dataObj _U_) { g_string_append_printf(data, "# %s\n", DESC_PARAMETER_THRESHOLD); g_string_append_printf(data, "%s: %f\n\n", FLAG_PARAMETER_THRESHOLD, threshold); } /** * tool_matrix_init: (skip) * * This method is used by V_Sim internally and should not be called. * * Since: 3.5 */ void tool_matrix_init(void) { float rg[2] = {G_MINFLOAT, G_MAXFLOAT}; VisuConfigFileEntry *entry; /* Set private variables. */ entry = visu_config_file_addFloatArrayEntry(VISU_CONFIG_FILE_PARAMETER, FLAG_PARAMETER_THRESHOLD, DESC_PARAMETER_THRESHOLD, 1, &threshold, rg, FALSE); visu_config_file_entry_setVersion(entry, 3.5f); visu_config_file_addExportFunction(VISU_CONFIG_FILE_PARAMETER, exportParameters); } static gpointer vector_copy(gconstpointer boxed) { gfloat *vector, *orig = (gfloat*)boxed; if (!boxed) return (gpointer)0; vector = g_malloc(sizeof(gfloat) * 3); vector[0] = orig[0]; vector[1] = orig[1]; vector[2] = orig[2]; return (gpointer)vector; } /** * tool_vector_get_type: * * Create and retrieve a #GType for a #ToolVector object. * * Since: 3.8 * * Returns: a new type for #ToolVector structures. */ GType tool_vector_get_type(void) { static GType g_define_type_id = 0; if (g_define_type_id == 0) g_define_type_id = g_boxed_type_register_static("ToolVector", (GBoxedCopyFunc)vector_copy, g_free); return g_define_type_id; } /** * tool_vector_new: * @orig: (array fixed-size=3): a vector. * * Creates a new #ToolVector by copying @orig. * * Since: 3.8 * * Returns: (transfer full) (type ToolVector): **/ float* tool_vector_new(const float orig[3]) { return vector_copy(orig); } /** * tool_vector_set: * @dest: a vector. * @orig: a vector. * * Copy @orig into @dest and also test if @dest was already equals to @orig. * * Since: 3.8 * * Returns: TRUE if @dest is different from @orig. **/ gboolean tool_vector_set(float dest[3], const float orig[3]) { if (dest[0] == orig[0] && dest[1] == orig[1] && dest[2] == orig[2]) return FALSE; dest[0] = orig[0]; dest[1] = orig[1]; dest[2] = orig[2]; return TRUE; } /** * tool_vector_spherical: * @cart: (array fixed-size=3): a vector in cartesian coordinates. * @at: a spherical direction. * * Convert @cart in spherical coordinates. It is equivalent to * tool_matrix_cartesianToSpherical() but returns the value in a given * direction only. This is intended for bindings. * * Since: 3.8 * * Returns: the coodinate in spherical. **/ float tool_vector_spherical(const float cart[3], ToolMatrixSphericalCoord at) { float sph[3]; tool_matrix_cartesianToSpherical(sph, cart); return sph[at]; } static gpointer minmax_copy(gpointer boxed) { gfloat *mm, *orig = (gfloat*)boxed; if (!boxed) return (gpointer)0; mm = g_malloc(sizeof(gfloat) * 2); mm[0] = orig[0]; mm[1] = orig[1]; return (gpointer)mm; } /** * tool_minmax_get_type: * * Create and retrieve a #GType for a #ToolMinmax object. * * Since: 3.8 * * Returns: a new type for #ToolMinmax structures. */ GType tool_minmax_get_type(void) { static GType g_define_type_id = 0; if (g_define_type_id == 0) g_define_type_id = g_boxed_type_register_static("ToolMinmax", minmax_copy, g_free); return g_define_type_id; } /** * tool_minmax: * @global: (array fixed-size=2): the global min and max values. * @minmax: (array fixed-size=2): some min and max values. * * Take the minimum and maximum of @global and @minmax and put them * into @global. @global should be initialised. * * Since: 3.8 **/ void tool_minmax(float global[2], const float minmax[2]) { global[0] = MIN(minmax[0], global[0]); global[1] = MAX(minmax[1], global[1]); } /** * tool_minmax_fromDbl: * @global: (array fixed-size=2): the global min and max values. * @minmax: (array fixed-size=2): some min and max values. * * Same as tool_minmax() for double inputs. * * Since: 3.8 **/ void tool_minmax_fromDbl(float global[2], const double minmax[2]) { global[0] = MIN(minmax[0], global[0]); global[1] = MAX(minmax[1], global[1]); } v_sim-3.8.0/src/coreTools/toolMatrix.h000066400000000000000000000170531370110300500177060ustar00rootroot00000000000000/* EXTRAITS DE LA LICENCE Copyright CEA, contributeurs : Luc BILLARD et Damien CALISTE, laboratoire L_Sim, (2001-2005) Adresse mèl : BILLARD, non joignable par mèl ; CALISTE, damien P caliste AT cea P fr. Ce logiciel est un programme informatique servant à visualiser des structures atomiques dans un rendu pseudo-3D. Ce logiciel est régi par la licence CeCILL soumise au droit français et respectant les principes de diffusion des logiciels libres. Vous pouvez utiliser, modifier et/ou redistribuer ce programme sous les conditions de la licence CeCILL telle que diffusée par le CEA, le CNRS et l'INRIA sur le site "http://www.cecill.info". Le fait que vous puissiez accéder à cet en-tête signifie que vous avez pris connaissance de la licence CeCILL, et que vous en avez accepté les termes (cf. le fichier Documentation/licence.fr.txt fourni avec ce logiciel). */ /* LICENCE SUM UP Copyright CEA, contributors : Luc BILLARD et Damien CALISTE, laboratoire L_Sim, (2001-2005) E-mail address: BILLARD, not reachable any more ; CALISTE, damien P caliste AT cea P fr. This software is a computer program whose purpose is to visualize atomic configurations in 3D. This software is governed by the CeCILL license under French law and abiding by the rules of distribution of free software. You can use, modify and/ or redistribute the software under the terms of the CeCILL license as circulated by CEA, CNRS and INRIA at the following URL "http://www.cecill.info". The fact that you are presently reading this means that you have had knowledge of the CeCILL license and that you accept its terms. You can find a copy of this licence shipped with this software at Documentation/licence.en.txt. */ #ifndef TOOLMATRIX_H #define TOOLMATRIX_H #include #include G_BEGIN_DECLS /** * TOOL_XYZ_MASK_X: * * This value can be used to create a mask for methods that * require one for reading xyz coordinates array. This value actually * correspond to the x direction. * * Since: 3.3 */ #define TOOL_XYZ_MASK_X (1 << 0) /** * TOOL_XYZ_MASK_Y: * * This value can be used to create a mask for methods that * require one for reading xyz coordinates array. This value actually * correspond to the y direction. * * Since: 3.3 */ #define TOOL_XYZ_MASK_Y (1 << 1) /** * TOOL_XYZ_MASK_Z: * * This value can be used to create a mask for methods that * require one for reading xyz coordinates array. This value actually * correspond to the z direction. * * Since: 3.3 */ #define TOOL_XYZ_MASK_Z (1 << 2) /** * TOOL_XYZ_MASK_ALL: * * This value can be used to create a mask for methods that * require one for reading xyz coordinates array. This value is a * shortcut for #TOOL_XYZ_MASK_X | #TOOL_XYZ_MASK_Y | #TOOL_XYZ_MASK_Z. * * Since: 3.3 */ #define TOOL_XYZ_MASK_ALL (7) /** * ToolXyzDir: * @TOOL_XYZ_X: the x axis; * @TOOL_XYZ_Y: the y axis; * @TOOL_XYZ_Z: the z axis. * * The three space axis. * * Since: 3.8 */ typedef enum { TOOL_XYZ_X, TOOL_XYZ_Y, TOOL_XYZ_Z } ToolXyzDir; /** * TOOL_PI180: * * Value of pi / 180. */ #define TOOL_PI180 0.017453292522 void tool_matrix_setIdentity(float mat[3][3]); void tool_matrix_set(float mat[3][3], float orig[3][3]); void tool_matrix_dtof(float mf[3][3], double md[3][3]); void tool_matrix_productMatrix(float matRes[3][3], float matA[3][3], float matB[3][3]); void tool_matrix_productVector(float vectRes[3], float mat[3][3], float vect[3]); gboolean tool_matrix_invert(float inv[3][3], float mat[3][3]); float tool_matrix_determinant(float mat[3][3]); void tool_matrix_rotate(float mat[3][3], float angle, ToolXyzDir dir); gboolean tool_matrix_reducePrimitiveVectors(double reduced[6], double full[3][3]); gboolean tool_matrix_getRotationFromFull(float rot[3][3], double full[3][3], double box[6]); /** * ToolMatrixSphericalCoord: * @TOOL_MATRIX_SPHERICAL_MODULUS: the modulus of a spherical vector. * @TOOL_MATRIX_SPHERICAL_THETA: the theta angle of a spherical vector. * @TOOL_MATRIX_SPHERICAL_PHI: the phi angle of a spherical vector. * * This is used to access the ordering of the vectors with * tool_matrix_cartesianToSpherical() or with * tool_matrix_sphericalToCartesian(). * * Since: 3.6 */ typedef enum { TOOL_MATRIX_SPHERICAL_MODULUS, TOOL_MATRIX_SPHERICAL_THETA, TOOL_MATRIX_SPHERICAL_PHI } ToolMatrixSphericalCoord; void tool_matrix_cartesianToSpherical(float spherical[3], const float cartesian[3]); void tool_matrix_sphericalToCartesian(float cartesian[3], const float spherical[3]); float tool_vector_spherical(const float cart[3], ToolMatrixSphericalCoord at); /** * ToolMatrixScalingFlag: * @TOOL_MATRIX_SCALING_LINEAR: a linear convertion from [min,max] to [0,1] ; * @TOOL_MATRIX_SCALING_LOG: a TOOL_MATRIX_SCALING_LOGic transformation from [min,max] to [0,1], the * formula is -(f(x) - f(m) / f(m) where f(x) = * ln((x-xmin)/(xmax-xmin)) ; * @TOOL_MATRIX_SCALING_ZERO_CENTRED_LOG: a TOOL_MATRIX_SCALING_LOGic transformation for data that are * zero centred, the formula is * 0.5+s*(log(MAX*SEUIL)-log(max(abs(x),MAX*SEUIL)))/(2*log(SEUIL)) * where s is the sign, max=max(xmax,-xmin) and seuil a parameter * (1e-5). * @TOOL_MATRIX_SCALING_N_VALUES: number of available scale functions. * * Flag used to specify the transformation for maps, see scalarFieldDraw_map() * routine. * * Since: 3.4 */ typedef enum { TOOL_MATRIX_SCALING_LINEAR, TOOL_MATRIX_SCALING_LOG, TOOL_MATRIX_SCALING_ZERO_CENTRED_LOG, TOOL_MATRIX_SCALING_N_VALUES } ToolMatrixScalingFlag; /** * tool_matrix_getScaledValue: * @x: the initial value ; * @minmax: the boundaries for the @x argument. * * Transform @x into [0;1] using the given @minmax values. * * Returns: a value into [0;1]. * * Since: 3.4 */ typedef float (*tool_matrix_getScaledValue)(float x, float minmax[2]); float tool_matrix_getScaledLinear(float x, float minmax[2]); float tool_matrix_getScaledLog(float x, float minmax[2]); float tool_matrix_getScaledZeroCentredLog(float x, float minmax[2]); float tool_matrix_getScaledLinearInv(float x, float minmax[2]); float tool_matrix_getScaledLogInv(float x, float minmax[2]); float tool_matrix_getScaledZeroCentredLogInv(float x, float minmax[2]); gboolean tool_matrix_getInter2D(float *lambda, float a[2], float b[2], float A[2], float B[2]); gboolean tool_matrix_getInter2DFromList(float i[2], float *lambda, float a[2], float b[2], GList *set); /* These structures are used for bindings. */ #define TOOL_TYPE_VECTOR (tool_vector_get_type()) GType tool_vector_get_type(void); gboolean tool_vector_set(float dest[3], const float orig[3]); float* tool_vector_new(const float orig[3]); /* typedef gfloat[3] ToolVector; */ /* typedef struct _ToolVector ToolVector; */ /* struct _ToolVector */ /* { */ /* float vect[3]; */ /* }; */ typedef struct _ToolGridSize ToolGridSize; struct _ToolGridSize { guint grid[3]; }; void tool_matrix_init(void); /* These structures are used for bindings. */ #define TOOL_TYPE_MINMAX (tool_minmax_get_type()) GType tool_minmax_get_type(void); void tool_minmax(float global[2], const float minmax[2]); void tool_minmax_fromDbl(float global[2], const double minmax[2]); /** * ToolScalingId: * @TOOL_SCALING_NORMALIZE: input data are converted into [0;1] using input min/max values. * @TOOL_SCALING_MINMAX: input data are converted into [0;1] using user defined min/max values. * * Control how input data are converted into [0;1], after conversion, * values are clamped if needed. */ typedef enum { TOOL_SCALING_NORMALIZE, TOOL_SCALING_MINMAX } ToolScalingId; G_END_DECLS #endif v_sim-3.8.0/src/coreTools/toolOptions.c000066400000000000000000000131641370110300500200670ustar00rootroot00000000000000/* EXTRAITS DE LA LICENCE Copyright CEA, contributeurs : Luc BILLARD et Damien CALISTE, laboratoire L_Sim, (2001-2005) Adresse mèl : BILLARD, non joignable par mèl ; CALISTE, damien P caliste AT cea P fr. Ce logiciel est un programme informatique servant à visualiser des structures atomiques dans un rendu pseudo-3D. Ce logiciel est régi par la licence CeCILL soumise au droit français et respectant les principes de diffusion des logiciels libres. Vous pouvez utiliser, modifier et/ou redistribuer ce programme sous les conditions de la licence CeCILL telle que diffusée par le CEA, le CNRS et l'INRIA sur le site "http://www.cecill.info". Le fait que vous puissiez accéder à cet en-tête signifie que vous avez pris connaissance de la licence CeCILL, et que vous en avez accepté les termes (cf. le fichier Documentation/licence.fr.txt fourni avec ce logiciel). */ /* LICENCE SUM UP Copyright CEA, contributors : Luc BILLARD et Damien CALISTE, laboratoire L_Sim, (2001-2005) E-mail address: BILLARD, not reachable any more ; CALISTE, damien P caliste AT cea P fr. This software is a computer program whose purpose is to visualize atomic configurations in 3D. This software is governed by the CeCILL license under French law and abiding by the rules of distribution of free software. You can use, modify and/ or redistribute the software under the terms of the CeCILL license as circulated by CEA, CNRS and INRIA at the following URL "http://www.cecill.info". The fact that you are presently reading this means that you have had knowledge of the CeCILL license and that you accept its terms. You can find a copy of this licence shipped with this software at Documentation/licence.en.txt. */ #include "toolOptions.h" #include /** * SECTION:toolOptions * @short_description: A convienent wrapper around GHashTable that can support types. * * This wrapper is a simple way to store integers, floating * point values or booleans in a table, accessing with a string key * and remembering their types. */ struct _ToolOption { /* The name of the option, copied on creation and used as key in a table of options. */ gchar *name; /* A short description of the option. */ gchar *label; /* Value. */ GValue *value; }; /** * tool_option_new: * @name: a string identifying the option ; * @label: a string describing shortly the option (must be in UTF-8). * @g_type: the type of option to create. * * Create a new #Option using the name as identifier. * * Returns: (transfer none): a newly created option, use tool_option_free() to free it. */ ToolOption* tool_option_new(const gchar *name, const gchar *label, GType g_type) { ToolOption *option; g_return_val_if_fail(name && name[0] && label, (ToolOption*)0); g_return_val_if_fail(G_TYPE_IS_VALUE(g_type), (ToolOption*)0); option = g_malloc(sizeof(ToolOption)); option->name = g_strdup(name); option->label = g_strdup(label); option->value = g_slice_new0(GValue); g_value_init(option->value, g_type); return option; } /** * tool_option_free: * @option: the #Option to free. * * Free the memory used by the @data. */ void tool_option_free(ToolOption *option) { g_return_if_fail(option); g_free(option->name); g_free(option->label); g_value_unset(option->value); g_slice_free(GValue, option->value); g_free(option); } /** * tool_option_copy: * @from: an existing #ToolOption. * * Create a new #ToolOption using the values from option @from. * * Returns: (transfer none): a newly created option, use tool_option_free() to free it. */ ToolOption* tool_option_copy(const ToolOption *from) { ToolOption *to; g_return_val_if_fail(from, (ToolOption*)0); to = tool_option_new(from->name, from->label, G_VALUE_TYPE(from->value)); g_value_copy(from->value, to->value); return to; } /** * tool_option_getName: * @option: the #Option to get the name of. * * Get the name of the option. * * Returns: a string owned by V_Sim, should not be freed. */ const gchar* tool_option_getName(ToolOption *option) { g_return_val_if_fail(option, (gchar*)0); return option->name; } /** * tool_option_getLabel: * @option: the #Option to get the label of. * * Get the label of the option. * * Returns: a string owned by V_Sim, should not be freed. */ const gchar* tool_option_getLabel(ToolOption *option) { g_return_val_if_fail(option, (gchar*)0); return option->label; } /** * tool_option_getType: * @option: the #Option to get the type of. * * Get the type of the option. * * Returns: a #OptionTypes value. */ GType tool_option_getType(ToolOption *option) { g_return_val_if_fail(option, 0); return G_VALUE_TYPE(option->value); } /** * tool_option_getValue: * @option: a #Option object. * * Get the location of the storage for the option. * * Returns: the #GValue storing the option value. */ GValue* tool_option_getValue(ToolOption *option) { g_return_val_if_fail(option, (GValue*)0); return option->value; } /** * tool_option_getValueAndLabel: * @option: the #Option to get the value from. * * This method returns a string with the value followed by the label in parenthesis * and with Pango markup for smaller font. * * Returns: a newly created markup string. */ gchar* tool_option_getValueAndLabel(ToolOption *option) { gchar *markup, *tmp; g_return_val_if_fail(option, (gchar*)0); if (G_VALUE_TYPE(option->value) != G_TYPE_NONE) { tmp = g_strdup_value_contents(option->value); markup = g_markup_printf_escaped("%s (%s)", tmp, option->label); g_free(tmp); } else markup = (gchar*)0; return markup; } v_sim-3.8.0/src/coreTools/toolOptions.h000066400000000000000000000046611370110300500200760ustar00rootroot00000000000000/* EXTRAITS DE LA LICENCE Copyright CEA, contributeurs : Luc BILLARD et Damien CALISTE, laboratoire L_Sim, (2001-2005) Adresse mèl : BILLARD, non joignable par mèl ; CALISTE, damien P caliste AT cea P fr. Ce logiciel est un programme informatique servant à visualiser des structures atomiques dans un rendu pseudo-3D. Ce logiciel est régi par la licence CeCILL soumise au droit français et respectant les principes de diffusion des logiciels libres. Vous pouvez utiliser, modifier et/ou redistribuer ce programme sous les conditions de la licence CeCILL telle que diffusée par le CEA, le CNRS et l'INRIA sur le site "http://www.cecill.info". Le fait que vous puissiez accéder à cet en-tête signifie que vous avez pris connaissance de la licence CeCILL, et que vous en avez accepté les termes (cf. le fichier Documentation/licence.fr.txt fourni avec ce logiciel). */ /* LICENCE SUM UP Copyright CEA, contributors : Luc BILLARD et Damien CALISTE, laboratoire L_Sim, (2001-2005) E-mail address: BILLARD, not reachable any more ; CALISTE, damien P caliste AT cea P fr. This software is a computer program whose purpose is to visualize atomic configurations in 3D. This software is governed by the CeCILL license under French law and abiding by the rules of distribution of free software. You can use, modify and/ or redistribute the software under the terms of the CeCILL license as circulated by CEA, CNRS and INRIA at the following URL "http://www.cecill.info". The fact that you are presently reading this means that you have had knowledge of the CeCILL license and that you accept its terms. You can find a copy of this licence shipped with this software at Documentation/licence.en.txt. */ #ifndef TOOLOPTIONS_H #define TOOLOPTIONS_H #include #include /** * ToolOption: * * An opaque structure to store values. It is equivalent to #GValue * but with a name and a label. */ typedef struct _ToolOption ToolOption; struct _ToolOption; ToolOption* tool_option_new(const gchar *name, const gchar *label, GType g_type); void tool_option_free(ToolOption *option); ToolOption* tool_option_copy(const ToolOption *from); const gchar* tool_option_getName(ToolOption *option); const gchar* tool_option_getLabel(ToolOption *option); GType tool_option_getType(ToolOption *option); GValue* tool_option_getValue(ToolOption *option); gchar* tool_option_getValueAndLabel(ToolOption *option); #endif v_sim-3.8.0/src/coreTools/toolPhysic.c000066400000000000000000000215341370110300500176730ustar00rootroot00000000000000/* EXTRAITS DE LA LICENCE Copyright CEA, contributeurs : Luc BILLARD et Damien CALISTE, laboratoire L_Sim, (2001-2005) Adresse mèl : BILLARD, non joignable par mèl ; CALISTE, damien P caliste AT cea P fr. Ce logiciel est un programme informatique servant à visualiser des structures atomiques dans un rendu pseudo-3D. Ce logiciel est régi par la licence CeCILL soumise au droit français et respectant les principes de diffusion des logiciels libres. Vous pouvez utiliser, modifier et/ou redistribuer ce programme sous les conditions de la licence CeCILL telle que diffusée par le CEA, le CNRS et l'INRIA sur le site "http://www.cecill.info". Le fait que vous puissiez accéder à cet en-tête signifie que vous avez pris connaissance de la licence CeCILL, et que vous en avez accepté les termes (cf. le fichier Documentation/licence.fr.txt fourni avec ce logiciel). */ /* LICENCE SUM UP Copyright CEA, contributors : Luc BILLARD et Damien CALISTE, laboratoire L_Sim, (2001-2005) E-mail address: BILLARD, not reachable any more ; CALISTE, damien P caliste AT cea P fr. This software is a computer program whose purpose is to visualize atomic configurations in 3D. This software is governed by the CeCILL license under French law and abiding by the rules of distribution of free software. You can use, modify and/ or redistribute the software under the terms of the CeCILL license as circulated by CEA, CNRS and INRIA at the following URL "http://www.cecill.info". The fact that you are presently reading this means that you have had knowledge of the CeCILL license and that you accept its terms. You can find a copy of this licence shipped with this software at Documentation/licence.en.txt. */ #include #include #include "toolPhysic.h" #include /** * SECTION:toolPhysic * @short_description: introduce physical values for the chemical species. * * This is a data base associating symbol names and atomic * numbers. One can also get the covalent radius of chemical * species. It is convenient to plot bindings. * * Since: 3.4 */ struct periodic_table { gchar *name; float radcov; float mass; }; #define NUMBER_OF_ELEMENTS 103 static struct periodic_table eles[NUMBER_OF_ELEMENTS] = { {"H", 0.32, 1.008}, {"He", 0.93, 4.0026}, {"Li", 1.23, 6.94}, {"Be", 0.90, 9.0122}, {"B", 0.80, 10.81}, {"C", 0.77, 12.011}, {"N", 0.74, 14.007}, {"O", 0.73, 15.999}, {"F", 0.72, 18.998}, {"Ne", 0.71, 20.180}, {"Na", 1.54, 22.990}, {"Mg", 1.36, 24.305}, {"Al", 1.18, 26.982}, {"Si", 1.11, 28.085}, {"P", 1.06, 30.974}, {"S", 1.02, 32.06}, {"Cl", 0.99, 35.45}, {"Ar", 0.98, 39.948}, {"K", 2.03, 39.098}, {"Ca", 1.74, 40.078}, {"Sc", 1.44, 44.956}, {"Ti", 1.32, 47.867}, {"V", 1.22, 50.942}, {"Cr", 1.18, 51.996}, {"Mn", 1.17, 54.938}, {"Fe", 1.17, 55.845}, {"Co", 1.16, 58.933}, {"Ni", 1.15, 58.693}, {"Cu", 1.17, 63.546}, {"Zn", 1.25, 65.38}, {"Ga", 1.26, 69.723}, {"Ge", 1.22, 72.630}, {"As", 1.20, 74.922}, {"Se", 1.16, 78.971}, {"Br", 1.14, 79.904}, {"Kr", 1.12, 83.798}, {"Rb", 2.16, 85.468}, {"Sr", 1.91, 87.62}, {"Y", 1.62, 88.906}, {"Zr", 1.45, 91.224}, {"Nb", 1.34, 92.906}, {"Mo", 1.30, 95.95}, {"Tc", 1.27, 98.}, {"Ru", 1.25, 101.07}, {"Rh", 1.25, 102.91}, {"Pd", 1.28, 106.42}, {"Ag", 1.34, 107.87}, {"Cd", 1.48, 112.41}, {"In", 1.44, 114.82}, {"Sn", 1.41, 118.71}, {"Sb", 1.40, 121.76}, {"Te", 1.36, 127.60}, {"I", 1.33, 126.90}, {"Xe", 1.31, 131.29}, {"Cs", 2.35, 132.91}, {"Ba", 1.98, 137.33}, {"La", 1.69, 138.91}, {"Ce", 1.65, 140.12}, {"Pr", 1.65, 140.91}, {"Nd", 1.64, 144.24}, {"Pm", 1.64, 145.}, {"Sm", 1.62, 150.36}, {"Eu", 1.85, 151.96}, {"Gd", 1.61, 157.25}, {"Tb", 1.59, 158.93}, {"Dy", 1.59, 162.50}, {"Ho", 1.57, 164.93}, {"Er", 1.57, 167.26}, {"Tm", 1.56, 168.93}, {"Yb", 1.70, 173.05}, {"Lu", 1.56, 174.97}, {"Hf", 1.44, 178.49}, {"Ta", 1.34, 180.95}, {"W", 1.30, 183.84}, {"Re", 1.28, 186.21}, {"Os", 1.26, 190.23}, {"Ir", 1.27, 192.22}, {"Pt", 1.30, 195.08}, {"Au", 1.34, 196.97}, {"Hg", 1.49, 200.59}, {"Tl", 1.48, 204.38}, {"Pb", 1.47, 207.2}, {"Bi", 1.46, 208.98}, {"Po", 1.46, 209.}, {"At", 1.45, 210.}, {"Rn", 1.45, 222.}, {"Fr", 2.50, 223.}, {"Ra", 2.10, 226.}, {"Ac", 1.85, 227.}, {"Th", 1.65, 232.04}, {"Pa", 1.50, 231.04}, {"U", 1.42, 238.03}, {"Np", 1.42, 237.}, {"Pu", 1.42, 244.}, {"Am", 1.42, 243.}, {"Cm", 1.42, 247.}, {"Bk", 1.42, 247.}, {"Cf", 1.42, 251.}, {"Es", 1.42, 252.}, {"Fm", 1.42, 257.}, {"Md", 1.42, 258.}, {"No", 1.42, 259.}, {"Lr", 1.42, 266.} }; /** * tool_physic_getSymbolFromZ: * @name: (out) (allow-none): a pointer on an unallocated string (can be NULL) ; * @radcov: (out) (allow-none): a pointer on a float (can be NULL) ; * @mass: (out) (allow-none): a pointer on a float (can be NULL) ; * @zele: the atomic number. * * Get the symbol or the covalence radius of the argument @zele. * * Returns: TRUE if zele is known in the atomic built-in list. */ gboolean tool_physic_getSymbolFromZ(gchar **name, float *radcov, float *mass, int zele) { g_return_val_if_fail(zele > 0 && zele < NUMBER_OF_ELEMENTS + 1, FALSE); if (name) *name = eles[zele - 1].name; if (radcov) *radcov = eles[zele - 1].radcov; if (mass) *mass = eles[zele - 1].mass; return TRUE; } /** * tool_physic_getZFromSymbol: * @zele: (out) (allow-none): a pointer on an integer (can be NULL) ; * @radcov: (out) (allow-none): a pointer on a float (can be NULL) ; * @mass: (out) (allow-none): a pointer on a float (can be NULL) ; * @symbol: the symbol of an atom. * * Get the the covalence radius or the atomic number of a given atomic * @symbol. * * Returns: TRUE if @symbol is known in the atomic built-in list. */ gboolean tool_physic_getZFromSymbol(int *zele, float *radcov, float *mass, const gchar *symbol) { int i; for (i = 0; i < NUMBER_OF_ELEMENTS; i++) { if (!strcmp(symbol, eles[i].name)) { if (radcov) *radcov = eles[i].radcov; if (mass) *mass = eles[i].mass; if (zele) *zele = i + 1; return TRUE; } } return FALSE; } static const gchar* unitNames[TOOL_UNITS_N_VALUES + 1] = {"undefined", "bohr", "angstroem", "nanometer", NULL}; static const gchar* unitLabels[TOOL_UNITS_N_VALUES + 1] = {"", "bohr", "\303\205", "nm", NULL}; static const gchar* unitNamesAll[TOOL_UNITS_N_VALUES + 1][8] = {{"undefined", NULL, NULL, NULL, NULL, NULL, NULL, NULL}, {"bohr", "Bohr", "bohrd0", "Bohrd0", "atomic", "Atomic", "atomicd0", "Atomicd0"}, {"angstroem", "Angstroem", "angstroemd0", "Angstroemd0", "angstrom", "Angstrom", NULL, NULL}, {"nanometer", "Nanometer", "nanometerd0", "Nanometerd0", NULL, NULL, NULL, NULL}, {NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL}}; /** * tool_physic_getUnitNames: * * It provides the names corresponding to each units. * * Since: 3.5 * * Returns: (transfer none) (array zero-terminated=1): an array, null * terminated of strings. It is owned by V_Sim. */ const gchar** tool_physic_getUnitNames(void) { return unitNames; } /** * tool_physic_getUnitLabel: * @unit: a given unit. * * This routine provides the label representing the unit, not its * name, see tool_physic_getUnitNames(). * * Since: 3.8 * * Returns: a UTF8 string, not translated. **/ const gchar* tool_physic_getUnitLabel(ToolUnits unit) { g_return_val_if_fail(unit < TOOL_UNITS_N_VALUES, NULL); return unitLabels[unit]; } static float unitValues[TOOL_UNITS_N_VALUES] = {-1.f, 5.291772108e-11f, 1e-10f, 1e-9f}; /** * tool_physic_getUnitValueInMeter: * @unit: a #ToolUnits. * * It provides the factor used to transform @unit into meters. * * Since: 3.5 * * Returns: a factor. */ float tool_physic_getUnitValueInMeter(ToolUnits unit) { g_return_val_if_fail(unit != TOOL_UNITS_UNDEFINED && unit != TOOL_UNITS_N_VALUES, -1.f); DBG_fprintf(stderr, "Visu Tools: get unit (%d) length.\n", unit); return unitValues[unit]; } /** * tool_physic_getUnitConversionFactor: * @from: a #ToolUnits. * @to: a #ToolUnits. * * Retrieve the factor used to convert from @from to @to. * * Since: 3.8 * * Returns: a factor. **/ float tool_physic_getUnitConversionFactor(ToolUnits from, ToolUnits to) { g_return_val_if_fail(from < TOOL_UNITS_N_VALUES && to < TOOL_UNITS_N_VALUES, 1.f); if (from == TOOL_UNITS_UNDEFINED || to == TOOL_UNITS_UNDEFINED) return 1.f; return unitValues[from] / unitValues[to]; } /** * tool_physic_getUnitFromName: * @name: a unit name. * * Find the unit corresponding to the @name. If none is found, * #TOOL_UNITS_UNDEFINED is returned. * * Since: 3.5 * * Returns: a #ToolUnits. */ ToolUnits tool_physic_getUnitFromName(const gchar *name) { int i, j; for (i = 0; i < TOOL_UNITS_N_VALUES; i++) for (j = 0; j < 8 && unitNamesAll[i][j]; j++) if (!strcmp(name, unitNamesAll[i][j])) return i; return TOOL_UNITS_UNDEFINED; } v_sim-3.8.0/src/coreTools/toolPhysic.h000066400000000000000000000056501370110300500177010ustar00rootroot00000000000000/* EXTRAITS DE LA LICENCE Copyright CEA, contributeurs : Luc BILLARD et Damien CALISTE, laboratoire L_Sim, (2001-2005) Adresse mèl : BILLARD, non joignable par mèl ; CALISTE, damien P caliste AT cea P fr. Ce logiciel est un programme informatique servant à visualiser des structures atomiques dans un rendu pseudo-3D. Ce logiciel est régi par la licence CeCILL soumise au droit français et respectant les principes de diffusion des logiciels libres. Vous pouvez utiliser, modifier et/ou redistribuer ce programme sous les conditions de la licence CeCILL telle que diffusée par le CEA, le CNRS et l'INRIA sur le site "http://www.cecill.info". Le fait que vous puissiez accéder à cet en-tête signifie que vous avez pris connaissance de la licence CeCILL, et que vous en avez accepté les termes (cf. le fichier Documentation/licence.fr.txt fourni avec ce logiciel). */ /* LICENCE SUM UP Copyright CEA, contributors : Luc BILLARD et Damien CALISTE, laboratoire L_Sim, (2001-2005) E-mail address: BILLARD, not reachable any more ; CALISTE, damien P caliste AT cea P fr. This software is a computer program whose purpose is to visualize atomic configurations in 3D. This software is governed by the CeCILL license under French law and abiding by the rules of distribution of free software. You can use, modify and/ or redistribute the software under the terms of the CeCILL license as circulated by CEA, CNRS and INRIA at the following URL "http://www.cecill.info". The fact that you are presently reading this means that you have had knowledge of the CeCILL license and that you accept its terms. You can find a copy of this licence shipped with this software at Documentation/licence.en.txt. */ #ifndef TOOLELEMENTS_H #define TOOLELEMENTS_H G_BEGIN_DECLS gboolean tool_physic_getSymbolFromZ(gchar **name, float *radcov, float *mass, int zele); gboolean tool_physic_getZFromSymbol(int *zele, float *radcov, float *mass, const gchar *symbol); /** * ToolUnits: * @TOOL_UNITS_UNDEFINED: the units are undefined. * @TOOL_UNITS_BOHR: the length are given in Bohr (1ang = 0.529177Bohr); * @TOOL_UNITS_ANGSTROEM: the length are given in angstroems ; * @TOOL_UNITS_NANOMETER: the length are given in nanometers. * @TOOL_UNITS_N_VALUES: private. * * The possible length units defined in V_Sim. The special case * @TOOL_UNITS_UNDEFINED means that a unit must be defined before any * conversion operations may be done. * * Since: 3.5 */ typedef enum { TOOL_UNITS_UNDEFINED, TOOL_UNITS_BOHR, TOOL_UNITS_ANGSTROEM, TOOL_UNITS_NANOMETER, /*< private >*/ TOOL_UNITS_N_VALUES } ToolUnits; const gchar** tool_physic_getUnitNames(void); const gchar* tool_physic_getUnitLabel(ToolUnits unit); float tool_physic_getUnitValueInMeter(ToolUnits unit); float tool_physic_getUnitConversionFactor(ToolUnits from, ToolUnits to); ToolUnits tool_physic_getUnitFromName(const gchar *name); G_END_DECLS #endif v_sim-3.8.0/src/coreTools/toolPool.c000066400000000000000000000217251370110300500173470ustar00rootroot00000000000000/* EXTRAITS DE LA LICENCE Copyright CEA, contributeurs : Damien CALISTE, laboratoire L_Sim, (2017) Adresse mèl : CALISTE, damien P caliste AT cea P fr. Ce logiciel est un programme informatique servant à visualiser des structures atomiques dans un rendu pseudo-3D. Ce logiciel est régi par la licence CeCILL soumise au droit français et respectant les principes de diffusion des logiciels libres. Vous pouvez utiliser, modifier et/ou redistribuer ce programme sous les conditions de la licence CeCILL telle que diffusée par le CEA, le CNRS et l'INRIA sur le site "http://www.cecill.info". Le fait que vous puissiez accéder à cet en-tête signifie que vous avez pris connaissance de la licence CeCILL, et que vous en avez accepté les termes (cf. le fichier Documentation/licence.fr.txt fourni avec ce logiciel). */ /* LICENCE SUM UP Copyright CEA, contributors : Damien CALISTE, laboratoire L_Sim, (2017) E-mail address: CALISTE, damien P caliste AT cea P fr. This software is a computer program whose purpose is to visualize atomic configurations in 3D. This software is governed by the CeCILL license under French law and abiding by the rules of distribution of free software. You can use, modify and/ or redistribute the software under the terms of the CeCILL license as circulated by CEA, CNRS and INRIA at the following URL "http://www.cecill.info". The fact that you are presently reading this means that you have had knowledge of the CeCILL license and that you accept its terms. You can find a copy of this licence shipped with this software at Documentation/licence.en.txt. */ #include "toolPool.h" /** * SECTION: toolPool * @short_description: a storage container that can uniquely stores * #GBoxed objects. * * This storage is intended to be a signaling container for a * given type of #GBoxed objects. In addition, these objects are * guaranteed to be unique in the container. */ enum { PROP_0, PROP_TYPE, N_PROP }; static GParamSpec *_properties[N_PROP]; enum { ADDED_SIGNAL, VISU_NB_SIGNAL }; static guint _signals[VISU_NB_SIGNAL]; /** * ToolPool: * * Structure defining #ToolPool objects. * * Since: 3.8 */ struct _ToolPoolPrivate { GType type; GCompareFunc compare; GList *lst; }; static void tool_pool_finalize (GObject* obj); static void tool_pool_get_property(GObject* obj, guint property_id, GValue *value, GParamSpec *pspec); static void tool_pool_set_property(GObject* obj, guint property_id, const GValue *value, GParamSpec *pspec); G_DEFINE_TYPE_WITH_CODE(ToolPool, tool_pool, G_TYPE_OBJECT, G_ADD_PRIVATE(ToolPool)) static void tool_pool_class_init(ToolPoolClass *klass) { /* Connect the overloading methods. */ G_OBJECT_CLASS(klass)->finalize = tool_pool_finalize; G_OBJECT_CLASS(klass)->get_property = tool_pool_get_property; G_OBJECT_CLASS(klass)->set_property = tool_pool_set_property; /** * ToolPool::type: * * The type contained in the pool. * * Since: 3.8 */ _properties[PROP_TYPE] = g_param_spec_gtype("type", "Type", "stored type.", G_TYPE_BOXED, G_PARAM_READWRITE | G_PARAM_CONSTRUCT_ONLY); g_object_class_install_properties(G_OBJECT_CLASS(klass), N_PROP, _properties); /** * ToolPool::new-element: * @pool: the object emitting the signal. * @boxed: the newly added object. * * A new object is available in the pool. * * Since: 3.8 */ _signals[ADDED_SIGNAL] = g_signal_new("new-element", G_TYPE_FROM_CLASS(klass), G_SIGNAL_RUN_LAST | G_SIGNAL_NO_RECURSE | G_SIGNAL_NO_HOOKS, 0, NULL /* accumulator */, NULL /* accu_data */, g_cclosure_marshal_VOID__POINTER, G_TYPE_NONE /* return_type */, 1, G_TYPE_POINTER); } static void tool_pool_init(ToolPool *obj) { obj->priv = tool_pool_get_instance_private(obj); /* Private data. */ obj->priv->lst = (GList*)0; obj->priv->compare = NULL; } static void tool_pool_finalize(GObject* obj) { ToolPool *data; GList *tmp; data = TOOL_POOL(obj); for (tmp = data->priv->lst; tmp; tmp = g_list_next(tmp)) g_boxed_free(data->priv->type, tmp->data); g_list_free(data->priv->lst); /* Chain up to the parent class */ G_OBJECT_CLASS(tool_pool_parent_class)->finalize(obj); } static void tool_pool_get_property(GObject* obj, guint property_id, GValue *value, GParamSpec *pspec) { ToolPool *self = TOOL_POOL(obj); switch (property_id) { case PROP_TYPE: g_value_set_gtype(value, self->priv->type); break; default: /* We don't have any other property... */ G_OBJECT_WARN_INVALID_PROPERTY_ID(obj, property_id, pspec); break; } } static void tool_pool_set_property(GObject* obj, guint property_id, const GValue *value, GParamSpec *pspec) { ToolPool *self = TOOL_POOL(obj); switch (property_id) { case PROP_TYPE: self->priv->type = g_value_get_gtype(value); break; default: /* We don't have any other property... */ G_OBJECT_WARN_INVALID_PROPERTY_ID(obj, property_id, pspec); break; } } /** * tool_pool_new: * @type: a type inheriting #G_TYPE_BOXED. * @compare: (scope call): a comparison function. * * Create a new #ToolPool object to store #GBoxed objects defined by * @type. These objects must be comparable with @compare function. * * Since: 3.8 * * Returns: (transfer full): a newly created #ToolPool object. **/ ToolPool* tool_pool_new(GType type, GCompareFunc compare) { ToolPool *pool; pool = g_object_new(TOOL_TYPE_POOL, "type", type, NULL); g_return_val_if_fail(pool, NULL); pool->priv->compare = compare; return pool; } /** * tool_pool_add: * @pool: a #ToolPool object. * @boxed: a #GBoxed pointer. * * Copy @boxed into @pool if not already present. * * Since: 3.8 * * Returns: (transfer none): a pointer on the copy of @boxed. This * copy is owned by V_Sim. **/ gpointer tool_pool_add(ToolPool *pool, gconstpointer boxed) { gpointer elem; g_return_val_if_fail(TOOL_IS_POOL(pool), (gpointer)0); elem = g_list_find_custom(pool->priv->lst, boxed, pool->priv->compare); if (elem) return elem; elem = g_boxed_copy(pool->priv->type, boxed); pool->priv->lst = g_list_append(pool->priv->lst, elem); g_signal_emit(pool, _signals[ADDED_SIGNAL], 0, elem); return elem; } /** * tool_pool_take: * @pool: a #ToolPool object. * @boxed: a #GBoxed pointer. * * Insert @boxed in @pool and takes ownership. * * Since: 3.8 * * Returns: (transfer none): a pointer on @boxed. This pointer is * owned by V_Sim. **/ gpointer tool_pool_take(ToolPool *pool, gpointer boxed) { gpointer elem; g_return_val_if_fail(TOOL_IS_POOL(pool), (gpointer)0); elem = g_list_find_custom(pool->priv->lst, boxed, pool->priv->compare); if (elem) return elem; pool->priv->lst = g_list_append(pool->priv->lst, boxed); g_signal_emit(pool, _signals[ADDED_SIGNAL], 0, boxed); return boxed; } /** * tool_pool_asList: * @pool: a #ToolPool object. * * Get the list of elements stored in @pool. * * Since: 3.8 * * Returns: (transfer container) (element-type GLib.Value): the list * should be freed with g_list_free() when no longer needed. **/ GList* tool_pool_asList(ToolPool *pool) { g_return_val_if_fail(TOOL_IS_POOL(pool), (GList*)0); return g_list_copy(pool->priv->lst); } /** * tool_pool_getById: * @pool: a #ToolPool object. * @num: an integer (>0). * * This function retrieves the nth stored object. Number 0, is the last * added object. * * Returns: (transfer none): the corresponding object, or NULL if none * has been found. */ gpointer tool_pool_getById(ToolPool *pool, guint num) { GList *tmpLst; g_return_val_if_fail(TOOL_IS_POOL(pool), (gpointer)0); tmpLst = g_list_nth(pool->priv->lst, num); if (tmpLst) return tmpLst->data; else return (gpointer)0; } /** * tool_pool_getByData: * @pool: a #ToolPool object. * @boxed: a #GBoxed object. * * This function retrieves the stored object that is equivalent to @boxed. * * Since: 3.8 * * Returns: (transfer none): the corresponding object, or NULL if none * has been found. **/ gpointer tool_pool_getByData(ToolPool *pool, gconstpointer boxed) { GList *tmpLst; g_return_val_if_fail(TOOL_IS_POOL(pool), (gpointer)0); tmpLst = g_list_find_custom(pool->priv->lst, boxed, pool->priv->compare); if (tmpLst) return tmpLst->data; else return (gpointer)0; } /** * tool_pool_index: * @pool: a #ToolPool object. * @boxed: an object. * * Retrieve the storage index of @boxed if it exists, or -1 if not. * * Since: 3.8 * * Returns: an index. **/ gint tool_pool_index(ToolPool *pool, gconstpointer boxed) { GList *tmp; gint i; g_return_val_if_fail(TOOL_IS_POOL(pool), -1); for (tmp = pool->priv->lst, i = 0; tmp; tmp = g_list_next(tmp), i += 1) if (pool->priv->compare(tmp->data, boxed) == 0) return i; return -1; } v_sim-3.8.0/src/coreTools/toolPool.h000066400000000000000000000074321370110300500173530ustar00rootroot00000000000000/* EXTRAITS DE LA LICENCE Copyright CEA, contributeurs : Damien CALISTE, laboratoire L_Sim, (2017) Adresse mèl : CALISTE, damien P caliste AT cea P fr. Ce logiciel est un programme informatique servant à visualiser des structures atomiques dans un rendu pseudo-3D. Ce logiciel est régi par la licence CeCILL soumise au droit français et respectant les principes de diffusion des logiciels libres. Vous pouvez utiliser, modifier et/ou redistribuer ce programme sous les conditions de la licence CeCILL telle que diffusée par le CEA, le CNRS et l'INRIA sur le site "http://www.cecill.info". Le fait que vous puissiez accéder à cet en-tête signifie que vous avez pris connaissance de la licence CeCILL, et que vous en avez accepté les termes (cf. le fichier Documentation/licence.fr.txt fourni avec ce logiciel). */ /* LICENCE SUM UP Copyright CEA, contributors : Damien CALISTE, laboratoire L_Sim, (2017) E-mail address: CALISTE, damien P caliste AT cea P fr. This software is a computer program whose purpose is to visualize atomic configurations in 3D. This software is governed by the CeCILL license under French law and abiding by the rules of distribution of free software. You can use, modify and/ or redistribute the software under the terms of the CeCILL license as circulated by CEA, CNRS and INRIA at the following URL "http://www.cecill.info". The fact that you are presently reading this means that you have had knowledge of the CeCILL license and that you accept its terms. You can find a copy of this licence shipped with this software at Documentation/licence.en.txt. */ #ifndef TOOL_POOL_H #define TOOL_POOL_H #include #include G_BEGIN_DECLS /** * TOOL_TYPE_POOL: * * return the type of #ToolDataAtomic. */ #define TOOL_TYPE_POOL (tool_pool_get_type ()) /** * TOOL_POOL: * @obj: a #GObject to cast. * * Cast the given @obj into #ToolDataAtomic type. */ #define TOOL_POOL(obj) (G_TYPE_CHECK_INSTANCE_CAST(obj, TOOL_TYPE_POOL, ToolPool)) /** * TOOL_POOL_CLASS: * @klass: a #GObjectClass to cast. * * Cast the given @klass into #ToolPoolClass. */ #define TOOL_POOL_CLASS(klass) (G_TYPE_CHECK_CLASS_CAST(klass, TOOL_TYPE_POOL, ToolPoolClass)) /** * TOOL_IS_POOL: * @obj: a #GObject to test. * * Test if the given @ogj is of the type of #ToolPool object. */ #define TOOL_IS_POOL(obj) (G_TYPE_CHECK_INSTANCE_TYPE(obj, TOOL_TYPE_POOL)) /** * TOOL_IS_POOL_CLASS: * @klass: a #GObjectClass to test. * * Test if the given @klass is of the type of #ToolPoolClass class. */ #define TOOL_IS_POOL_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE(klass, TOOL_TYPE_POOL)) /** * TOOL_POOL_GET_CLASS: * @obj: a #GObject to get the class of. * * It returns the class of the given @obj. */ #define TOOL_POOL_GET_CLASS(obj) (G_TYPE_INSTANCE_GET_CLASS(obj, TOOL_TYPE_POOL, ToolPoolClass)) typedef struct _ToolPoolPrivate ToolPoolPrivate; typedef struct _ToolPool ToolPool; struct _ToolPool { GObject parent; ToolPoolPrivate *priv; }; /** * ToolPoolClass: * @parent: the parent class. * * A short way to identify #_ToolPoolClass structure. */ typedef struct _ToolPoolClass ToolPoolClass; struct _ToolPoolClass { GObjectClass parent; }; /** * tool_pool_get_type: * * This method returns the type of #ToolPool, use TOOL_TYPE_POOL instead. * * Returns: the type of #ToolPool. */ GType tool_pool_get_type(void); ToolPool* tool_pool_new(GType type, GCompareFunc compare); gpointer tool_pool_add(ToolPool *pool, gconstpointer boxed); gpointer tool_pool_take(ToolPool *pool, gpointer boxed); GList* tool_pool_asList(ToolPool *pool); gpointer tool_pool_getById(ToolPool *pool, guint num); gpointer tool_pool_getByData(ToolPool *pool, gconstpointer boxed); gint tool_pool_index(ToolPool *pool, gconstpointer boxed); G_END_DECLS #endif v_sim-3.8.0/src/coreTools/toolShade.c000066400000000000000000000676651370110300500174770ustar00rootroot00000000000000/* EXTRAITS DE LA LICENCE Copyright CEA, contributeurs : Luc BILLARD et Damien CALISTE, laboratoire L_Sim, (2001-2005) Adresse mèl : BILLARD, non joignable par mèl ; CALISTE, damien P caliste AT cea P fr. Ce logiciel est un programme informatique servant à visualiser des structures atomiques dans un rendu pseudo-3D. Ce logiciel est régi par la licence CeCILL soumise au droit français et respectant les principes de diffusion des logiciels libres. Vous pouvez utiliser, modifier et/ou redistribuer ce programme sous les conditions de la licence CeCILL telle que diffusée par le CEA, le CNRS et l'INRIA sur le site "http://www.cecill.info". Le fait que vous puissiez accéder à cet en-tête signifie que vous avez pris connaissance de la licence CeCILL, et que vous en avez accepté les termes (cf. le fichier Documentation/licence.fr.txt fourni avec ce logiciel). */ /* LICENCE SUM UP Copyright CEA, contributors : Luc BILLARD et Damien CALISTE, laboratoire L_Sim, (2001-2005) E-mail address: BILLARD, not reachable any more ; CALISTE, damien P caliste AT cea P fr. This software is a computer program whose purpose is to visualize atomic configurations in 3D. This software is governed by the CeCILL license under French law and abiding by the rules of distribution of free software. You can use, modify and/ or redistribute the software under the terms of the CeCILL license as circulated by CEA, CNRS and INRIA at the following URL "http://www.cecill.info". The fact that you are presently reading this means that you have had knowledge of the CeCILL license and that you accept its terms. You can find a copy of this licence shipped with this software at Documentation/licence.en.txt. */ #include "toolShade.h" #include #include #include #include #include "toolConfigFile.h" #include "toolColor.h" /** * SECTION:toolShade * @short_description: ToolShades are color gradients. * * This module allow V_Sim to deal with color gradients. Such a * gradient is defined by a linear transformation of color space. This * space can be RBG or HSV (see the enum #ToolShadeColorMode). This linear * transformation can be written [resulting color vector] = [vectB] + * lambda.[vectA], where lambda denotes the input variable of the * gradient (ranging from 0 to 1). Resulting color vector are clamped * to [0;1] if needed. * Use tool_shade_new() to create a new shade, giving the arguments as * defined above. * To share color gradients between modules in V_Sim, you can * find a global list of stored shades with tool_shade_getStorage(). * This is a #ToolPool object. Use tool_pool_add() to add a new shade * to it. */ #define SHADE_LEGEND_WIDTH 0.05 #define SHADE_LEGEND_HEIGHT 0.3 #define SHADE_LEGEND_N_QUADS 20 #define FLAG_SHADE "shade_palette" #define DESC_SHADE "Define a new shade by giving colours to points ; label (val [name|#rgb|#rrggbb|...], ...)" static void exportParameters(GString *data, VisuData *dataObj); static gboolean readShade(VisuConfigFileEntry *entry _U_, gchar **lines, int nbLines,int position, GError **error); static gboolean parseValue(gchar *line, float *index, float rgb[3], GError **error); static void _buildPresetList(void); struct _ToolShade { gchar* labelUTF8; ToolShadeColorMode colorMode; ToolShadeMode mode; /* The linear storage. */ float vectA[3], vectB[3]; /* The array storage. */ float *index; float *vectCh[3]; guint nVals; /* Some user defined values. */ gboolean userDefined; gchar *steps; }; static ToolPool *shadePool = NULL; /** * tool_shade_get_type: * * Create and retrieve a #GType for a #ToolShade object. * * Since: 3.7 * * Returns: a new type for #ToolShade structures. */ GType tool_shade_get_type(void) { static GType g_define_type_id = 0; VisuConfigFileEntry *entry; if (g_define_type_id == 0) { g_define_type_id = g_boxed_type_register_static("ToolShade", (GBoxedCopyFunc)tool_shade_copy, (GBoxedFreeFunc)tool_shade_free); /* Set private variables. */ entry = visu_config_file_addEntry(VISU_CONFIG_FILE_RESOURCE, FLAG_SHADE, DESC_SHADE, 1, readShade); visu_config_file_entry_setVersion(entry, 3.7f); visu_config_file_addExportFunction(VISU_CONFIG_FILE_RESOURCE, exportParameters); } return g_define_type_id; } /** * tool_shade_getById: * @id: an id. * * Convenience function calling tool_pool_getById() on the default * #ToolShade storage. * * Since: 3.8 * * Returns: a #ToolShade from the pool. **/ const ToolShade* tool_shade_getById(guint id) { return tool_pool_getById(tool_shade_getStorage(), id); } /** * tool_shade_new: * @labelUTF8: a UTF8 string that shortly named this new shade ; * @vectA: an array of three floating point values ; * @vectB: an array of three floating point values ; * @colorMode: an integer that describes the color code (see #ToolShadeColorMode enumeration). * * Create a linear shade. Its profile is given by an AX+B formula, * dealing on three channels. These channels are defined by the * @colorMode parameter. All given values are copied when the new * shade is created. * * Returns: the newly created ToolShade. */ ToolShade* tool_shade_new(const gchar* labelUTF8, float vectA[3], float vectB[3], ToolShadeColorMode colorMode) { ToolShade *shade; int i; g_return_val_if_fail(labelUTF8 && vectA && vectB && colorMode < TOOL_SHADE_COLOR_MODE_N_VALUES, (ToolShade*)0); DBG_fprintf(stderr, "Tool ToolShade: create a new ToolShade object (linear):"); shade = g_malloc(sizeof(ToolShade)); shade->labelUTF8 = g_strdup(labelUTF8); for (i = 0; i < 3; i++) { shade->vectA[i] = vectA[i]; shade->vectB[i] = vectB[i]; } shade->index = (float*)0; shade->vectCh[0] = (float*)0; shade->vectCh[1] = (float*)0; shade->vectCh[2] = (float*)0; shade->colorMode = colorMode; shade->mode = TOOL_SHADE_MODE_LINEAR; shade->userDefined = TRUE; shade->steps = (gchar*)0; DBG_fprintf(stderr, " %p.\n", (gpointer)shade); return shade; } /** * tool_shade_newFromData: * @labelUTF8: a UTF8 string that shortly named this new shade ; * @len: the size of arguments @vectCh1, @vectCh2 and @vectCh3 ; * @vectCh1: an array of floating point values for the first channel ; * @vectCh2: an array of floating point values for the second channel ; * @vectCh3: an array of floating point values for the third channel ; * @colorMode: an integer that describes the color code (see * #ToolShadeColorMode enumeration). * * Create a #ToolShade from direct data for three channels. These channels * are defined by the @colorMode parameter. All given values are * copied when the new shade is created. * * Returns: the newly created ToolShade. */ ToolShade* tool_shade_newFromData(const gchar* labelUTF8, guint len, float *vectCh1, float *vectCh2, float *vectCh3, ToolShadeColorMode colorMode) { ToolShade *shade; guint i; g_return_val_if_fail(labelUTF8 && vectCh1 && vectCh2 && vectCh3 && colorMode < TOOL_SHADE_COLOR_MODE_N_VALUES && len > 0, (ToolShade*)0); DBG_fprintf(stderr, "Tool ToolShade: create a new ToolShade object (array):"); shade = g_malloc(sizeof(ToolShade)); shade->labelUTF8 = g_strdup(labelUTF8); shade->colorMode = colorMode; shade->mode = TOOL_SHADE_MODE_ARRAY; shade->nVals = len; shade->index = g_malloc(sizeof(float) * len); shade->vectCh[0] = g_malloc(sizeof(float) * len); shade->vectCh[1] = g_malloc(sizeof(float) * len); shade->vectCh[2] = g_malloc(sizeof(float) * len); for (i = 0; i < len; i++) shade->index[i] = (float)i / (float)(len - 1); memcpy(shade->vectCh[0], vectCh1, sizeof(float) * len); memcpy(shade->vectCh[1], vectCh2, sizeof(float) * len); memcpy(shade->vectCh[2], vectCh3, sizeof(float) * len); shade->userDefined = TRUE; shade->steps = (gchar*)0; DBG_fprintf(stderr, " %p.\n", (gpointer)shade); return shade; } /** * tool_shade_newFromSteps: * @labelUTF8: a UTF8 string that shortly named this new shade ; * @lst: (transfer none) (element-type ToolShadeStep*): a list of * color steps. * @colorMode: a #ToolShadeColorMode mode. * * Create a #ToolShade from a set of steps defining colours at given * indexes. These channels are defined by the @colorMode * parameter. All given values are copied when the new shade is * created. The values of indexes will be normalised by this call to * range in [0;1]. Colour channel values must be in [0;1] for each step. * * Since: 3.7 * * Returns: (transfer full): the newly created ToolShade. */ ToolShade* tool_shade_newFromSteps(const gchar* labelUTF8, GList *lst, ToolShadeColorMode colorMode) { ToolShade *shade; float minVal, maxVal, f; GList *tmp; ToolShadeStep *step; guint i; g_return_val_if_fail(labelUTF8 && lst && (g_list_length(lst) > 1), (ToolShade*)0); DBG_fprintf(stderr, "Tool ToolShade: create a new ToolShade object (array):\n"); shade = g_malloc(sizeof(ToolShade)); shade->labelUTF8 = g_strdup(labelUTF8); shade->nVals = g_list_length(lst); shade->index = g_malloc(sizeof(float) * shade->nVals); shade->vectCh[0] = g_malloc(sizeof(float) * shade->nVals); shade->vectCh[1] = g_malloc(sizeof(float) * shade->nVals); shade->vectCh[2] = g_malloc(sizeof(float) * shade->nVals); shade->colorMode = colorMode; shade->mode = TOOL_SHADE_MODE_ARRAY; shade->userDefined = TRUE; shade->steps = (gchar*)0; /* Normalise entry. */ minVal = G_MAXFLOAT; maxVal = -G_MAXFLOAT; for (tmp = lst; tmp; tmp = g_list_next(tmp)) { minVal = MIN(minVal, ((ToolShadeStep*)tmp->data)->index); maxVal = MAX(maxVal, ((ToolShadeStep*)tmp->data)->index); } f = 1.f / (maxVal - minVal); DBG_fprintf(stderr, " | applying factor %g to index\n", f); for (tmp = lst, i = 0; tmp; tmp = g_list_next(tmp), i++) { step = (ToolShadeStep*)tmp->data; shade->index[i] = (step->index - minVal) * f; shade->vectCh[0][i] = CLAMP(step->channels[0], 0.f, 1.f); shade->vectCh[1][i] = CLAMP(step->channels[1], 0.f, 1.f); shade->vectCh[2][i] = CLAMP(step->channels[2], 0.f, 1.f); } DBG_fprintf(stderr, " | done %p.\n", (gpointer)shade); return shade; } /** * tool_shade_newFromString: * @labelUTF8: a UTF8 string that shortly named this new shade ; * @descr: a string with the shade description. * @colorMode: a #ToolShadeColorMode mode. * @error: (allow-none): a location for an error. * * As tool_shade_newFromSteps() routine, but it takes an unparsed * string describing the steps in @descr. * * Since: 3.7 * * Returns: (transfer full): the newly created ToolShade. */ ToolShade* tool_shade_newFromString(const gchar* labelUTF8, const gchar *descr, ToolShadeColorMode colorMode, GError **error) { ToolShade *shade; gchar **tokens; guint i; GList *lst; ToolShadeStep *step; g_return_val_if_fail(labelUTF8 && descr && error, (ToolShade*)0); DBG_fprintf(stderr, "Tool ToolShade: create a new ToolShade object (string): %s\n", descr); /* Read @size boolean values from @line. */ lst = (GList*)0; tokens = g_strsplit_set(descr, ",", TOOL_MAX_LINE_LENGTH); for (i = 0; tokens[i]; i++) if (tokens[i][0]) { step = g_malloc(sizeof(ToolShadeStep)); lst = g_list_append(lst, step); if (!parseValue(tokens[i], &(step->index), step->channels, error)) { g_strfreev(tokens); g_list_free_full(lst, g_free); return FALSE; } } shade = tool_shade_newFromSteps(labelUTF8, lst, colorMode); if (shade) shade->steps = g_strdup(descr); g_strfreev(tokens); g_list_free_full(lst, g_free); return shade; } /** * tool_shade_free: * @shade: a #ToolShade. * * Free all dynamic memory from @shade and free @shade itself. */ void tool_shade_free(ToolShade *shade) { if (shade) { DBG_fprintf(stderr, "Tool Shade: freeing %p.\n", (gpointer)shade); g_free(shade->labelUTF8); g_free(shade->index); g_free(shade->vectCh[0]); g_free(shade->vectCh[1]); g_free(shade->vectCh[2]); g_free(shade->steps); g_free(shade); } } /** * tool_shade_copy: * @shade: a #ToolShade. * * Create a new shade deep copy of the first. * * Returns: a newly created shade. */ ToolShade* tool_shade_copy(const ToolShade *shade) { ToolShade *out; if (!shade) return (ToolShade*)0; out = g_malloc(sizeof(ToolShade)); out->labelUTF8 = g_strdup(shade->labelUTF8); out->colorMode = shade->colorMode; out->mode = shade->mode; out->nVals = shade->nVals; out->vectA[0] = shade->vectA[0]; out->vectA[1] = shade->vectA[1]; out->vectA[2] = shade->vectA[2]; out->vectB[0] = shade->vectB[0]; out->vectB[1] = shade->vectB[1]; out->vectB[2] = shade->vectB[2]; out->index = g_memdup(shade->index, sizeof(float) * out->nVals); out->vectCh[0] = g_memdup(shade->vectCh[0], sizeof(float) * out->nVals); out->vectCh[1] = g_memdup(shade->vectCh[1], sizeof(float) * out->nVals); out->vectCh[2] = g_memdup(shade->vectCh[2], sizeof(float) * out->nVals); out->userDefined = shade->userDefined; out->steps = g_strdup(shade->steps); return out; } static gint _compare(const ToolShade* sh1, const ToolShade *sh2) { guint i; gboolean equal; if (!sh1 && !sh2) return 0; if (!sh1) return -1; if (!sh2) return +1; if (sh1->mode != sh2->mode) return (sh2 - sh1); if (sh1->colorMode != sh2->colorMode) return (sh2 - sh1); if (sh1->mode == TOOL_SHADE_MODE_LINEAR) return (sh1->vectA[0] == sh2->vectA[0] && sh1->vectA[1] == sh2->vectA[1] && sh1->vectA[2] == sh2->vectA[2] && sh1->vectB[0] == sh2->vectB[0] && sh1->vectB[1] == sh2->vectB[1] && sh1->vectB[2] == sh2->vectB[2]) ? 0 : (sh2 - sh1); else { if (sh1->nVals != sh2->nVals) return (sh2 - sh1); equal = TRUE; for (i = 0; i < sh1->nVals && equal; i++) equal = equal && (sh1->index[i] == sh2->index[i]) && (sh1->vectCh[0][i] == sh2->vectCh[0][i]) && (sh1->vectCh[1][i] == sh2->vectCh[1][i]) && (sh1->vectCh[2][i] == sh2->vectCh[2][i]); return equal ? 0 : (sh2 - sh1); } } /** * tool_shade_compare: * @sh1: a #ToolShade ; * @sh2: a #ToolShade. * * Compare if the two shade are identical (first, smae mode, then same * values). * * Returns: TRUE if @shade1 is equivalent to @shade2. */ gboolean tool_shade_compare(const ToolShade* sh1, const ToolShade *sh2) { return (_compare(sh1, sh2) == 0); } /** * tool_shade_getLabel: * @shade: a valid #ToolShade object. * * Get the name (in UTF8) of the shade. * * Returns: a string naming the shade. */ gchar* tool_shade_getLabel(ToolShade *shade) { g_return_val_if_fail(shade, (gchar*)0); return shade->labelUTF8; } /** * tool_shade_getColorMode: * @shade: a valid #ToolShade object. * * Get the color mode of the shade (RGB or HSV). * * Returns: the color mode. */ ToolShadeColorMode tool_shade_getColorMode(ToolShade *shade) { g_return_val_if_fail(shade, (int)0); return shade->colorMode; } /** * tool_shade_getMode: * @shade: a valid #ToolShade object. * * Get the mode of the shade (linear, array...). * * Returns: the mode. */ ToolShadeMode tool_shade_getMode(const ToolShade *shade) { g_return_val_if_fail(shade, (int)0); return shade->mode; } /** * tool_shade_setColorMode: * @shade: a #ToolShade ; * @mode: a new mode for the shade. * * Change the mode of the shade, see #ToolShadeColorMode. * * Returns: TRUE if @mode is different from previous @shade mode. */ gboolean tool_shade_setColorMode(ToolShade *shade, ToolShadeColorMode mode) { g_return_val_if_fail(shade, FALSE); if (shade->colorMode == mode) return FALSE; shade->colorMode = mode; return TRUE; } /** * tool_shade_getLinearCoeff: * @shade: a valid #ToolShade object ; * @vectA: a pointer to a floating point values array to store vect in AX+B ; * @vectB: a pointer to a floating point values array to store vect in AX+B. * * This methods can get the linear color transformation. The given * arrays (@vectA, @vectB) are read-only. This method return * FALSE if the @shade is not in a #TOOL_SHADE_MODE_LINEAR state. * * Returns: TRUE if @vectA, @vectB and @vectX have been set correctly. */ gboolean tool_shade_getLinearCoeff(const ToolShade *shade, const float **vectA, const float **vectB) { g_return_val_if_fail(shade, FALSE); g_return_val_if_fail(shade->mode == TOOL_SHADE_MODE_LINEAR, FALSE); g_return_val_if_fail(vectA && vectB, FALSE); *vectA = shade->vectA; *vectB = shade->vectB; return TRUE; } /** * tool_shade_setLinearCoeff: * @shade: a #ToolShade ; * @coeff: a new value ; * @channel: either RGBA (from 0 to 3) ; * @order: the order in the linear approx (0 means constant and 1 is * the linear coeeficient). * * Change one value @coeff of the linear mode for the given @shade. * * Returns: TRUE if the new value changes anything. */ gboolean tool_shade_setLinearCoeff(ToolShade *shade, float coeff, int channel, int order) { float *pt; g_return_val_if_fail(shade, FALSE); g_return_val_if_fail(channel >= 0 && channel < 3 && order >= 0 && order < 2, FALSE); if (order == 0) pt = shade->vectB + channel; else pt = shade->vectA + channel; DBG_fprintf(stderr, "Tool ToolShade: set the %d value of vect[%d]" " to %f (previuosly %f).\n", channel, order, coeff, *pt); if (*pt == coeff) return FALSE; *pt = coeff; return TRUE; } /** * tool_shade_channelToRGB: * @shade: a #ToolShade ; * @rgba: a location to store the result of the colour transformation ; * @values: inout values. * * Like tool_shade_valueToRGB() but here, the three values * are applied respectivly for the Red, the Green and the Blue * channel. */ void tool_shade_channelToRGB(const ToolShade *shade, float rgba[4], float values[3]) { guint i; g_return_if_fail(shade); /* DBG_fprintf(stderr, "Tool Shade: get RGB from (%g ; %g ; %g).\n", */ /* values[0], values[1], values[2]); */ if (shade->mode == TOOL_SHADE_MODE_LINEAR) { rgba[0] = CLAMP(shade->vectA[0] * values[0] + shade->vectB[0], 0.f, 1.f); rgba[1] = CLAMP(shade->vectA[1] * values[1] + shade->vectB[1], 0.f, 1.f); rgba[2] = CLAMP(shade->vectA[2] * values[2] + shade->vectB[2], 0.f, 1.f); } else { for (i = 1; i < shade->nVals - 1; i++) if (values[0] < shade->index[i]) break; rgba[0] = CLAMP(shade->vectCh[0][i - 1] + (shade->vectCh[0][i] - shade->vectCh[0][i - 1]) * (values[0] - shade->index[i - 1]) / (shade->index[i] - shade->index[i - 1]), 0.f, 1.f); for (i = 1; i < shade->nVals - 1; i++) if (values[1] < shade->index[i]) break; rgba[1] = CLAMP(shade->vectCh[1][i - 1] + (shade->vectCh[1][i] - shade->vectCh[1][i - 1]) * (values[1] - shade->index[i - 1]) / (shade->index[i] - shade->index[i - 1]), 0.f, 1.f); for (i = 1; i < shade->nVals - 1; i++) if (values[2] < shade->index[i]) break; rgba[2] = CLAMP(shade->vectCh[2][i - 1] + (shade->vectCh[2][i] - shade->vectCh[2][i - 1]) * (values[2] - shade->index[i - 1]) / (shade->index[i] - shade->index[i - 1]), 0.f, 1.f); } /* Don't use alpha channel at present time. */ rgba[3] = 1.; /* Transform if required. */ if (shade->colorMode == TOOL_SHADE_COLOR_MODE_HSV) tool_color_convertHSVtoRGB(rgba, rgba); } /** * tool_shade_valueToRGB: * @shade: a valid #ToolShade object ; * @rgba: an array of size [4] ; * @value: the value ranged in [0;1]. * * Give a RGBA vector for the given value. */ void tool_shade_valueToRGB(const ToolShade *shade, float rgba[4], float value) { float vals[3]; vals[0] = value; vals[1] = value; vals[2] = value; tool_shade_channelToRGB(shade, rgba, vals); } /*********************************************/ /* Methods to deal with internal shade list. */ /*********************************************/ /** * tool_shade_getStorage: * * It returns a read-only pointer to the internal shade list. Use tool_shade_appendList() * to add new shades to this list. * * Since: 3.8 * * Returns: (transfer none): a pointer to the internal shade list. */ ToolPool* tool_shade_getStorage(void) { if (!shadePool) _buildPresetList(); return shadePool; } static void _buildPresetList(void) { ToolShade *shade; float vectA[3], vectB[3]; /* Zero Centred Colored. */ #define zccLn 3 float zccH[zccLn] = {0.f, 0.333f, 0.667f}; float zccS[zccLn] = {1.0f, 0.0f, 1.0f}; float zccV[zccLn] = {1.f, 1.f, 1.f}; /* Zero Centred Light. */ #define zclLn 3 float zclR[zclLn] = {1.f, 1.f, 0.f}; float zclG[zclLn] = {0.0f, 1.0f, 0.0f}; float zclB[zclLn] = {0.f, 1.f, 1.f}; /* Jet colour shade. */ #define jetn 9 float jetR[jetn] = {0.f, 0.f, 0.f, 0.f, 0.5f, 1.f, 1.f, 1.f, 0.5f}; float jetG[jetn] = {0.f, 0.f, 0.5f, 1.f, 1.f, 1.f, 0.5f, 0.f, 0.f}; float jetB[jetn] = {0.5f, 1.f, 1.f, 1.f, 0.5f, 0.f, 0.f, 0.f, 0.f}; shadePool = tool_pool_new(TOOL_TYPE_SHADE, (GCompareFunc)_compare); /* Create a blue to red color range. */ vectA[0] = -0.66667; vectA[1] = 0.; vectA[2] = 0.; vectB[0] = 0.66667; vectB[1] = 1.; vectB[2] = 1.; shade = tool_shade_new(_("blue to red"), vectA, vectB, TOOL_SHADE_COLOR_MODE_HSV); shade->userDefined = FALSE; tool_pool_take(shadePool, shade); /* Create a black to white (through yellow and red) color range. */ vectA[0] = 2.66667; vectA[1] = 2.66667; vectA[2] = 4.; vectB[0] = 0.; vectB[1] = -1.; vectB[2] = -3.; shade = tool_shade_new(_("hot color"), vectA, vectB, TOOL_SHADE_COLOR_MODE_RGB); shade->userDefined = FALSE; tool_pool_take(shadePool, shade); /* Create a blue to yellow (through dark purple) color range. */ vectA[0] = 1.33333; vectA[1] = 2.; vectA[2] = -2; vectB[0] = 0.; vectB[1] = -1.; vectB[2] = 1.; shade = tool_shade_new(_("blue to yellow"), vectA, vectB, TOOL_SHADE_COLOR_MODE_RGB); shade->userDefined = FALSE; tool_pool_take(shadePool, shade); /* Create a blue and red shade with black zero centred. */ vectA[0] = -2.; vectA[1] = 0.; vectA[2] = 2.; vectB[0] = 1.; vectB[1] = 0.; vectB[2] = -1.; shade = tool_shade_new(_("zero centred dark"), vectA, vectB, TOOL_SHADE_COLOR_MODE_RGB); shade->userDefined = FALSE; tool_pool_take(shadePool, shade); /* Create a blue and red shade with withe zero centred. */ shade = tool_shade_newFromData(_("zero centred light"), zclLn, zclR, zclG, zclB, TOOL_SHADE_COLOR_MODE_RGB); shade->userDefined = FALSE; tool_pool_take(shadePool, shade); shade = tool_shade_newFromData(_("zero centred coloured"), zccLn, zccH, zccS, zccV, TOOL_SHADE_COLOR_MODE_HSV); shade->userDefined = FALSE; tool_pool_take(shadePool, shade); /* Create a green to red color range. */ vectA[0] = -.3333; vectA[1] = 0.; vectA[2] = 0.; vectB[0] = 0.3333; vectB[1] = 1.; vectB[2] = 1.; shade = tool_shade_new(_("green to red"), vectA, vectB, TOOL_SHADE_COLOR_MODE_HSV); shade->userDefined = FALSE; tool_pool_take(shadePool, shade); /* Create a white to red color range. */ vectA[0] = -.3333; vectA[1] = 0.8; vectA[2] = 0.; vectB[0] = 0.3333; vectB[1] = 0.1; vectB[2] = 1.; shade = tool_shade_new(_("light green to red"), vectA, vectB, TOOL_SHADE_COLOR_MODE_HSV); shade->userDefined = FALSE; tool_pool_take(shadePool, shade); /* Create a black to white color range. */ vectA[0] = 0.; vectA[1] = 0.; vectA[2] = 1.; vectB[0] = 0.; vectB[1] = 0.; vectB[2] = 0.; shade = tool_shade_new(_("black to white"), vectA, vectB, TOOL_SHADE_COLOR_MODE_HSV); shade->userDefined = FALSE; tool_pool_take(shadePool, shade); /* Create a black to white color range. */ vectA[0] = 0.; vectA[1] = 0.; vectA[2] = -1.; vectB[0] = 0.; vectB[1] = 0.; vectB[2] = 1.; shade = tool_shade_new(_("white to black"), vectA, vectB, TOOL_SHADE_COLOR_MODE_HSV); shade->userDefined = FALSE; tool_pool_take(shadePool, shade); /* Create a black to red (through purple) color range. */ vectA[0] = 1.; vectA[1] = 1.; vectA[2] = 1.; vectB[0] = 0.; vectB[1] = 0.; vectB[2] = 0.; shade = tool_shade_new(_("purple color"), vectA, vectB, TOOL_SHADE_COLOR_MODE_HSV); shade->userDefined = FALSE; tool_pool_take(shadePool, shade); /* Create the so-called Jet colour map. */ shade = tool_shade_newFromData(_("Jet map"), jetn, jetR, jetG, jetB, TOOL_SHADE_COLOR_MODE_RGB); shade->userDefined = FALSE; tool_pool_take(shadePool, shade); } static gboolean parseValue(gchar *line, float *index, float rgb[3], GError **error) { gchar *name; PangoColor color; double index_; DBG_fprintf(stderr, "Tool Shade: parse step from '%s'\n", line); index_ = g_ascii_strtod(line, &name); if (errno != 0 || name == line) { *error = g_error_new(TOOL_CONFIG_FILE_ERROR, TOOL_CONFIG_FILE_ERROR_READ, _("1 floating point value should start a step '%s'.\n"), line); return FALSE; } *index = (float)index_; DBG_fprintf(stderr, " | index %g\n", *index); name += 1; g_strdelimit(name, "\"'", ' '); g_strstrip(name); if (!pango_color_parse(&color, name)) { *error = g_error_new(TOOL_CONFIG_FILE_ERROR, TOOL_CONFIG_FILE_ERROR_READ, _("cannot read a color from '%s' (name, #rgb, #rrggbb ... awaited).\n"), name); return FALSE; } rgb[0] = (float)color.red / (float)G_MAXUINT16; rgb[1] = (float)color.green / (float)G_MAXUINT16; rgb[2] = (float)color.blue / (float)G_MAXUINT16; DBG_fprintf(stderr, " | color %fx%fx%f\n", rgb[0], rgb[1], rgb[2]); return TRUE; } static void exportParameters(GString *data, VisuData *dataObj _U_) { GList *lst; ToolShade *shade; guint i; PangoColor pcolor; gchar *color; GString *buf; visu_config_file_exportComment(data, DESC_SHADE); for (lst = tool_pool_asList(shadePool); lst; lst = g_list_next(lst)) if (((ToolShade*)lst->data)->userDefined) { shade = (ToolShade*)lst->data; buf = g_string_new(""); if (shade->userDefined) g_string_append(buf, shade->steps); else for (i = 0; i < shade->nVals ; i++) { if (i != 0) g_string_append_printf(buf, ", "); pcolor.red = (guint16)(shade->vectCh[0][i] * (gfloat)G_MAXUINT16); pcolor.green = (guint16)(shade->vectCh[1][i] * (gfloat)G_MAXUINT16); pcolor.blue = (guint16)(shade->vectCh[2][i] * (gfloat)G_MAXUINT16); color = pango_color_to_string(&pcolor); g_string_append_printf(buf, "%g %s", shade->index[i], color); g_free(color); } visu_config_file_exportEntry(data, FLAG_SHADE, shade->labelUTF8, "%s", buf->str); g_string_free(buf, TRUE); } visu_config_file_exportComment(data, ""); } static gboolean readShade(VisuConfigFileEntry *entry, gchar **lines, int nbLines _U_, int position _U_, GError **error) { gchar *name, *descr; char *startDef, *endDef; ToolShade *shade; ToolPool *pool; name = g_strdup(visu_config_file_entry_getLabel(entry)); startDef = strchr(lines[0], '('); if (!startDef) startDef = lines[0]; else startDef += 1; endDef = strchr(startDef, ')'); if (endDef) descr = g_strndup(startDef, endDef - startDef); else descr = g_strdup(startDef); shade = tool_shade_newFromString(g_strstrip(name), descr, TOOL_SHADE_COLOR_MODE_RGB, error); g_free(name); g_free(descr); if (!shade) return FALSE; pool = tool_shade_getStorage(); tool_pool_take(pool, shade); return TRUE; } v_sim-3.8.0/src/coreTools/toolShade.h000066400000000000000000000115021370110300500174570ustar00rootroot00000000000000/* EXTRAITS DE LA LICENCE Copyright CEA, contributeurs : Luc BILLARD et Damien CALISTE, laboratoire L_Sim, (2001-2005) Adresse mèl : BILLARD, non joignable par mèl ; CALISTE, damien P caliste AT cea P fr. Ce logiciel est un programme informatique servant à visualiser des structures atomiques dans un rendu pseudo-3D. Ce logiciel est régi par la licence CeCILL soumise au droit français et respectant les principes de diffusion des logiciels libres. Vous pouvez utiliser, modifier et/ou redistribuer ce programme sous les conditions de la licence CeCILL telle que diffusée par le CEA, le CNRS et l'INRIA sur le site "http://www.cecill.info". Le fait que vous puissiez accéder à cet en-tête signifie que vous avez pris connaissance de la licence CeCILL, et que vous en avez accepté les termes (cf. le fichier Documentation/licence.fr.txt fourni avec ce logiciel). */ /* LICENCE SUM UP Copyright CEA, contributors : Luc BILLARD et Damien CALISTE, laboratoire L_Sim, (2001-2005) E-mail address: BILLARD, not reachable any more ; CALISTE, damien P caliste AT cea P fr. This software is a computer program whose purpose is to visualize atomic configurations in 3D. This software is governed by the CeCILL license under French law and abiding by the rules of distribution of free software. You can use, modify and/ or redistribute the software under the terms of the CeCILL license as circulated by CEA, CNRS and INRIA at the following URL "http://www.cecill.info". The fact that you are presently reading this means that you have had knowledge of the CeCILL license and that you accept its terms. You can find a copy of this licence shipped with this software at Documentation/licence.en.txt. */ #ifndef TOOLSHADE_H #define TOOLSHADE_H #include #include #include "toolMatrix.h" #include "toolPool.h" /** * _ToolShade * * Opaque structure to store linear shade informations. */ struct _ToolShade; /** * ToolShade: * * Short name to address _ToolShade objects. */ typedef struct _ToolShade ToolShade; /** * ToolShadeColorMode: * @TOOL_SHADE_COLOR_MODE_RGB: variation described in the shade are applied to RGB coding colors ; * @TOOL_SHADE_COLOR_MODE_HSV: variation described in the shade are applied to HSV coding colors ; * @TOOL_SHADE_COLOR_MODE_N_VALUES: number of modes available. * * Defines color mode : Red-Green-Blue or Hue-Saturation-Value. */ typedef enum { TOOL_SHADE_COLOR_MODE_RGB, TOOL_SHADE_COLOR_MODE_HSV, TOOL_SHADE_COLOR_MODE_N_VALUES } ToolShadeColorMode; /** * ToolShadeMode: * @TOOL_SHADE_MODE_LINEAR: all channels are defined by a linear variation * Ax+B ; * @TOOL_SHADE_MODE_ARRAY: all channels are defined by a given array of * values ; * @TOOL_SHADE_MODE_N_VALUES: the number of different shade mode. * * Defines the storage of the shade mode. */ typedef enum { TOOL_SHADE_MODE_LINEAR, TOOL_SHADE_MODE_ARRAY, TOOL_SHADE_MODE_N_VALUES } ToolShadeMode; /** * ToolShadeStep: * @index: a value. * @channels: (array fixed-size=3): three values in [0;1] for RGB or * HSV channels. * * Stores a step in the definition of a shade. * * Since: 3.7 **/ typedef struct _ToolShadeStep ToolShadeStep; struct _ToolShadeStep { float index; float channels[3]; }; GType tool_shade_get_type(void); #define TOOL_TYPE_SHADE (tool_shade_get_type()) ToolPool* tool_shade_getStorage(void); const ToolShade* tool_shade_getById(guint id); ToolShade* tool_shade_new(const gchar* labelUTF8, float vectA[3], float vectB[3], ToolShadeColorMode colorMode); ToolShade* tool_shade_newFromData(const gchar* labelUTF8, guint len, float *vectCh1, float *vectCh2, float *vectCh3, ToolShadeColorMode colorMode); ToolShade* tool_shade_newFromSteps(const gchar* labelUTF8, GList *lst, ToolShadeColorMode colorMode); ToolShade* tool_shade_newFromString(const gchar* labelUTF8, const gchar *descr, ToolShadeColorMode colorMode, GError **error); void tool_shade_free(ToolShade *shade); ToolShade* tool_shade_copy(const ToolShade *shade); gboolean tool_shade_compare(const ToolShade* sh1, const ToolShade *sh2); gchar* tool_shade_getLabel(ToolShade *shade); ToolShadeColorMode tool_shade_getColorMode(ToolShade *shade); gboolean tool_shade_setColorMode(ToolShade *shade, ToolShadeColorMode mode); ToolShadeMode tool_shade_getMode(const ToolShade *shade); gboolean tool_shade_getLinearCoeff(const ToolShade *shade, const float **vectA, const float **vectB); gboolean tool_shade_setLinearCoeff(ToolShade *shade, float coeff, int channel, int order); void tool_shade_valueToRGB(const ToolShade *shade, float rgba[4], float value); void tool_shade_channelToRGB(const ToolShade *shade, float rgba[4], float values[3]); #endif v_sim-3.8.0/src/dumpModules/000077500000000000000000000000001370110300500157125ustar00rootroot00000000000000v_sim-3.8.0/src/dumpModules/dumpThroughGdkPixbuf.c000066400000000000000000000152231370110300500221730ustar00rootroot00000000000000/* EXTRAITS DE LA LICENCE Copyright CEA, contributeur : Damien CALISTE, laboratoire L_Sim, (2001-2006) Adresse mèl : CALISTE, damien P caliste AT cea P fr. Ce logiciel est un programme informatique servant à visualiser des structures atomiques dans un rendu pseudo-3D. Ce logiciel est régi par la licence CeCILL soumise au droit français et respectant les principes de diffusion des logiciels libres. Vous pouvez utiliser, modifier et/ou redistribuer ce programme sous les conditions de la licence CeCILL telle que diffusée par le CEA, le CNRS et l'INRIA sur le site "http://www.cecill.info". Le fait que vous puissiez accéder à cet en-tête signifie que vous avez pris connaissance de la licence CeCILL, et que vous en avez accepté les termes (cf. le fichier Documentation/licence.fr.txt fourni avec ce logiciel). */ /* LICENCE SUM UP Copyright CEA, contributors : Damien CALISTE, laboratoire L_Sim, (2001-2006) E-mail address: CALISTE, damien P caliste AT cea P fr. This software is a computer program whose purpose is to visualize atomic configurations in 3D. This software is governed by the CeCILL license under French law and abiding by the rules of distribution of free software. You can use, modify and/ or redistribute the software under the terms of the CeCILL license as circulated by CEA, CNRS and INRIA at the following URL "http://www.cecill.info". The fact that you are presently reading this means that you have had knowledge of the CeCILL license and that you accept its terms. You can find a copy of this licence shipped with this software at Documentation/licence.en.txt. */ #include #include #include #include #include "dumpThroughGdkPixbuf.h" #include /** * SECTION:dumpThroughGdkPixbuf * @short_description: add an export capability into PNG and JPG files. * * This provides a write routine to export V_Sim views into PNG and JPG * files. It uses the GdkPixbuf to do it. */ static gpointer waitData; static ToolVoidDataFunc waitFunc; static gboolean writeViewInPngFormat(ToolFileFormat *format, const char* filename, VisuGlNodeScene *scene, guint width, guint height, GError **error, ToolVoidDataFunc functionWait, gpointer data); static gboolean writeViewInJpegFormat(ToolFileFormat *format, const char* filename, VisuGlNodeScene *scene, guint width, guint height, GError **error, ToolVoidDataFunc functionWait, gpointer data); static VisuDump *png = NULL; static VisuDump *jpeg = NULL; const VisuDump* visu_dump_png_getStatic() { const gchar *typePng[] = {"*.png", (char*)0}; if (png) return png; png = VISU_DUMP(visu_dump_scene_new(_("Png file"), typePng, writeViewInPngFormat, TRUE)); waitFunc = (ToolVoidDataFunc)0; waitData = (gpointer)0; return png; } const VisuDump* visu_dump_jpeg_getStatic() { const gchar *typeJpeg[] = {"*.jpg", "*.jpeg", (char*)0}; if (jpeg) return jpeg; jpeg = VISU_DUMP(visu_dump_scene_new(_("Jpeg file"), typeJpeg, writeViewInJpegFormat, FALSE)); tool_file_format_addPropertyInt(TOOL_FILE_FORMAT(jpeg), "quality", _("Compression ratio (given in percent)"), 85); waitFunc = (ToolVoidDataFunc)0; waitData = (gpointer)0; return jpeg; } static gboolean writeViewWithGdkPixbuf(ToolFileFormat *format, const char* filename, guint width, guint height, const gchar *type, VisuGlNodeScene *scene, GError **error) { GdkPixbuf *pixbuf; gboolean success, hasAlpha; GArray *propName, *propValues; int length; gchar *str; ToolFileFormatIter iter; GArray *imageData; g_return_val_if_fail(error && !*error, FALSE); DBG_fprintf(stderr, "Dump with GdkPixbuf: begin %s export in %dx%d : %s.\n", type, width, height, filename); if (strcmp(type, "png")) { length = 3; hasAlpha = FALSE; } else { length = 4; hasAlpha = TRUE; } imageData = visu_gl_ext_set_getPixmapData(VISU_GL_EXT_SET(scene), width, height, hasAlpha); if (!imageData) { *error = g_error_new(VISU_DUMP_ERROR, DUMP_ERROR_OPENGL, _("Can't dump OpenGL area to data.\n")); return FALSE; } pixbuf = gdk_pixbuf_new_from_data((guchar*)imageData->data, GDK_COLORSPACE_RGB, hasAlpha, 8, width, height, length * width, NULL, (gpointer)0); if (!pixbuf) { *error = g_error_new(VISU_DUMP_ERROR, DUMP_ERROR_FILE, _("Cannot convert pixmap to pixbuf.")); return FALSE; } propName = g_array_new(TRUE, FALSE, sizeof(gchar*)); propValues = g_array_new(TRUE, FALSE, sizeof(gchar*)); iter.lst = (GList*)0; for (tool_file_format_iterNextProperty(format, &iter); iter.lst; tool_file_format_iterNextProperty(format, &iter)) { str = g_strdup(iter.name); g_array_append_vals(propName, &str, 1); str = g_strdup_value_contents(iter.val); g_array_append_vals(propValues, &str, 1); } DBG_fprintf(stderr, "Dump with GdkPixbuf: transfer properties.\n"); success = gdk_pixbuf_savev(pixbuf, filename, type, (gchar**)propName->data, (gchar**)propValues->data, error); g_strfreev((gchar**)g_array_free(propName, FALSE)); g_strfreev((gchar**)g_array_free(propValues, FALSE)); g_object_unref(pixbuf); g_array_free(imageData, TRUE); return success; } static gboolean writeViewInJpegFormat(ToolFileFormat *format, const char* filename, VisuGlNodeScene *scene, guint width, guint height, GError **error, ToolVoidDataFunc functionWait, gpointer data) { int i, res; res = writeViewWithGdkPixbuf(format, filename, width, height, "jpeg", scene, error); /* Must call 100 times functionWait if exists before leaving... */ if (functionWait) for (i = 0; i < 100; i++) functionWait(data); return res; } static gboolean writeViewInPngFormat(ToolFileFormat *format, const char* filename, VisuGlNodeScene *scene, guint width, guint height, GError **error, ToolVoidDataFunc functionWait, gpointer data) { int i, res; res = writeViewWithGdkPixbuf(format, filename, width, height, "png", scene, error); /* Must call 100 times functionWait if exists before leaving... */ if (functionWait) for (i = 0; i < 100; i++) functionWait(data); return res; } v_sim-3.8.0/src/dumpModules/dumpThroughGdkPixbuf.h000066400000000000000000000041641370110300500222020ustar00rootroot00000000000000/* EXTRAITS DE LA LICENCE Copyright CEA, contributeur : Damien CALISTE, laboratoire L_Sim, (2001-2005) Adresse mèl : CALISTE, damien P caliste AT cea P fr. Ce logiciel est un programme informatique servant à visualiser des structures atomiques dans un rendu pseudo-3D. Ce logiciel est régi par la licence CeCILL soumise au droit français et respectant les principes de diffusion des logiciels libres. Vous pouvez utiliser, modifier et/ou redistribuer ce programme sous les conditions de la licence CeCILL telle que diffusée par le CEA, le CNRS et l'INRIA sur le site "http://www.cecill.info". Le fait que vous puissiez accéder à cet en-tête signifie que vous avez pris connaissance de la licence CeCILL, et que vous en avez accepté les termes (cf. le fichier Documentation/licence.fr.txt fourni avec ce logiciel). */ /* LICENCE SUM UP Copyright CEA, contributors : Damien CALISTE, laboratoire L_Sim, (2001-2005) E-mail address: CALISTE, damien P caliste AT cea P fr. This software is a computer program whose purpose is to visualize atomic configurations in 3D. This software is governed by the CeCILL license under French law and abiding by the rules of distribution of free software. You can use, modify and/ or redistribute the software under the terms of the CeCILL license as circulated by CEA, CNRS and INRIA at the following URL "http://www.cecill.info". The fact that you are presently reading this means that you have had knowledge of the CeCILL license and that you accept its terms. You can find a copy of this licence shipped with this software at Documentation/licence.en.txt. */ #ifndef DUMPTHROUGHGDKPIXBUF_H #define DUMPTHROUGHGDKPIXBUF_H #include "glDump.h" /** * visu_dump_png_getStatic: * * This routine returns the PNG dump object. * * Returns: (transfer none): a newly created dump object to create PNG files. */ const VisuDump* visu_dump_png_getStatic(); /** * visu_dump_jpeg_getStatic: * * This routine returns the JPG dump object. * * Returns: (transfer none): a newly created dump object to create JPEG files. */ const VisuDump* visu_dump_jpeg_getStatic(); #endif v_sim-3.8.0/src/dumpModules/dumpToABINIT.c000066400000000000000000000232541370110300500202230ustar00rootroot00000000000000/* EXTRAITS DE LA LICENCE Copyright CEA, contributeurs : Damien CALISTE, laboratoire L_Sim, (2011) Adresse mèl : CALISTE, damien P caliste AT cea P fr. Ce logiciel est un programme informatique servant à visualiser des structures atomiques dans un rendu pseudo-3D. Ce logiciel est régi par la licence CeCILL soumise au droit français et respectant les principes de diffusion des logiciels libres. Vous pouvez utiliser, modifier et/ou redistribuer ce programme sous les conditions de la licence CeCILL telle que diffusée par le CEA, le CNRS et l'INRIA sur le site "http://www.cecill.info". Le fait que vous puissiez accéder à cet en-tête signifie que vous avez pris connaissance de la licence CeCILL, et que vous en avez accepté les termes (cf. le fichier Documentation/licence.fr.txt fourni avec ce logiciel). */ /* LICENCE SUM UP Copyright CEA, contributors : Damien CALISTE, laboratoire L_Sim, (2011) E-mail address: BILLARD, not reachable any more ; CALISTE, damien P caliste AT cea P fr. This software is a computer program whose purpose is to visualize atomic configurations in 3D. This software is governed by the CeCILL license under French law and abiding by the rules of distribution of free software. You can use, modify and/ or redistribute the software under the terms of the CeCILL license as circulated by CEA, CNRS and INRIA at the following URL "http://www.cecill.info". The fact that you are presently reading this means that you have had knowledge of the CeCILL license and that you accept its terms. You can find a copy of this licence shipped with this software at Documentation/licence.en.txt. */ #include "dumpToABINIT.h" #include #include #include #include #include #include #include #include /** * SECTION:dumpToABINIT * @short_description: add an export capability of current positions * in ABINIT format. * * This provides a write routine to export V_Sim current * coordinates. It has several options to output or not hiddden nodes * or replicated nodes. */ static gboolean writeDataInABINIT(VisuDumpData *format, const char* filename, VisuData *dataObj, GError **error); static VisuDumpData *ab; const VisuDumpData* visu_dump_abinit_getStatic() { const gchar *typeABINIT[] = {"*.in", (char*)0}; #define descrABINIT _("ABINIT file (crystal only)") if (ab) return ab; ab = visu_dump_data_new(descrABINIT, typeABINIT, writeDataInABINIT); tool_file_format_addPropertyBoolean(TOOL_FILE_FORMAT(ab), "reduced_coordinates", _("Export positions in reduced coordinates"), FALSE); tool_file_format_addPropertyBoolean(TOOL_FILE_FORMAT(ab), "angdeg_box", _("Export box as lengths and angles"), FALSE); return ab; } static gboolean writeDataInABINIT(VisuDumpData *format, const char* filename, VisuData *dataObj, GError **error) { const gchar *nom; gchar *prevFile; gchar unit[25], tag[25]; gboolean reduced, angdeg; float xyz[3], uvw[3], vertices[8][3], box[6]; VisuNodeArrayIter iter; GString *output; ToolFileFormatIter it; int znucl; VisuBox *boxObj; g_return_val_if_fail(error && !*error, FALSE); reduced = FALSE; angdeg = FALSE; it.lst = (GList*)0; for (tool_file_format_iterNextProperty(TOOL_FILE_FORMAT(format), &it); it.lst; tool_file_format_iterNextProperty(TOOL_FILE_FORMAT(format), &it)) { DBG_fprintf(stderr, "Dump ABINIT: test property '%s'.\n", it.name); if (strcmp(it.name, "reduced_coordinates") == 0) reduced = g_value_get_boolean(it.val); else if (strcmp(it.name, "angdeg_box") == 0) angdeg = g_value_get_boolean(it.val); } DBG_fprintf(stderr, "Dump ABINIT: begin export of current positions...\n"); DBG_fprintf(stderr, " | reduced %d ;\n", reduced); DBG_fprintf(stderr, " | angdeg %d ;\n", angdeg); output = g_string_new(""); if (VISU_IS_DATA_LOADABLE(dataObj)) { nom = visu_data_loadable_getFilename(VISU_DATA_LOADABLE(dataObj), 0); prevFile = g_path_get_basename(nom); g_string_append_printf(output, "# V_Sim export to ABINIT from '%s'\n", prevFile); g_free(prevFile); } else { g_warning("Can't get the name of the file to export."); g_string_append(output, "# V_Sim export to ABINIT\n"); } boxObj = visu_boxed_getBox(VISU_BOXED(dataObj)); switch (visu_box_getUnit(boxObj)) { case TOOL_UNITS_ANGSTROEM: strcpy(unit, "angstroms"); strcpy(tag, "xangst"); break; default: g_warning("Unsupported unit for ABINIT, defaulting to Bohr."); /* Falls through. */ case TOOL_UNITS_UNDEFINED: case TOOL_UNITS_BOHR: unit[0] = '\0'; strcpy(tag, "xcart"); break; } if (reduced) strcpy(tag, "xred"); visu_box_getVertices(boxObj, vertices, TRUE); box[0] = sqrt((vertices[1][0] - vertices[0][0]) * (vertices[1][0] - vertices[0][0]) + (vertices[1][1] - vertices[0][1]) * (vertices[1][1] - vertices[0][1]) + (vertices[1][2] - vertices[0][2]) * (vertices[1][2] - vertices[0][2])); box[1] = sqrt((vertices[3][0] - vertices[0][0]) * (vertices[3][0] - vertices[0][0]) + (vertices[3][1] - vertices[0][1]) * (vertices[3][1] - vertices[0][1]) + (vertices[3][2] - vertices[0][2]) * (vertices[3][2] - vertices[0][2])); box[2] = sqrt((vertices[4][0] - vertices[0][0]) * (vertices[4][0] - vertices[0][0]) + (vertices[4][1] - vertices[0][1]) * (vertices[4][1] - vertices[0][1]) + (vertices[4][2] - vertices[0][2]) * (vertices[4][2] - vertices[0][2])); g_string_append_printf(output, "acell %17.8g %17.8g %17.8g %s\n", box[0], box[1], box[2], unit); if (angdeg) { box[3] = acos(CLAMP(((vertices[3][0] - vertices[0][0]) * (vertices[4][0] - vertices[0][0]) + (vertices[3][1] - vertices[0][1]) * (vertices[4][1] - vertices[0][1]) + (vertices[3][2] - vertices[0][2]) * (vertices[4][2] - vertices[0][2])) / box[1] / box[2], -1.f, 1.f)) * 180.f / G_PI; box[4] = acos(CLAMP(((vertices[1][0] - vertices[0][0]) * (vertices[4][0] - vertices[0][0]) + (vertices[1][1] - vertices[0][1]) * (vertices[4][1] - vertices[0][1]) + (vertices[1][2] - vertices[0][2]) * (vertices[4][2] - vertices[0][2])) / box[0] / box[2], -1.f, 1.f)) * 180.f / G_PI; box[4] *= (vertices[4][2] < 0.)?-1.:+1.; box[5] = acos(CLAMP(((vertices[3][0] - vertices[0][0]) * (vertices[1][0] - vertices[0][0]) + (vertices[3][1] - vertices[0][1]) * (vertices[1][1] - vertices[0][1]) + (vertices[3][2] - vertices[0][2]) * (vertices[1][2] - vertices[0][2])) / box[0] / box[1], -1.f, 1.f)) * 180.f / G_PI; g_string_append_printf(output, "angdeg %17.8g %17.8g %17.8g\n", box[3], box[4], box[5]); } else { g_string_append_printf(output, "rprim %17.8g %17.8g %17.8g\n", (vertices[1][0] - vertices[0][0]) / box[0], (vertices[1][1] - vertices[0][1]) / box[0], (vertices[1][2] - vertices[0][2]) / box[0]); g_string_append_printf(output, " %17.8g %17.8g %17.8g\n", (vertices[3][0] - vertices[0][0]) / box[1], (vertices[3][1] - vertices[0][1]) / box[1], (vertices[3][2] - vertices[0][2]) / box[1]); g_string_append_printf(output, " %17.8g %17.8g %17.8g\n", (vertices[4][0] - vertices[0][0]) / box[2], (vertices[4][1] - vertices[0][1]) / box[2], (vertices[4][2] - vertices[0][2]) / box[2]); } visu_node_array_iter_new(VISU_NODE_ARRAY(dataObj), &iter); g_string_append_printf(output, "ntypat %d\n", iter.nElements); g_string_append_printf(output, "natom %d\n", iter.nAllStoredNodes); g_string_append(output, "znucl"); for(visu_node_array_iterStart(VISU_NODE_ARRAY(dataObj), &iter); iter.element; visu_node_array_iterNextElement(VISU_NODE_ARRAY(dataObj), &iter, FALSE)) { tool_physic_getZFromSymbol(&znucl, (float*)0, (float*)0, iter.element->name); g_string_append_printf(output, " %d", znucl); } g_string_append(output, "\n"); g_string_append(output, "typat"); for(visu_node_array_iterStart(VISU_NODE_ARRAY(dataObj), &iter); iter.node; visu_node_array_iterNext(VISU_NODE_ARRAY(dataObj), &iter)) if (visu_element_getRendered(iter.element) && iter.node->rendered) { g_string_append_printf(output, " %d", iter.node->posElement + 1); if (iter.node->number % 10 == 9) g_string_append(output, "\n"); } g_string_append(output, "\n"); g_string_append(output, tag); for(visu_node_array_iterStart(VISU_NODE_ARRAY(dataObj), &iter); iter.node; visu_node_array_iterNext(VISU_NODE_ARRAY(dataObj), &iter)) { visu_data_getNodePosition(dataObj, iter.node, xyz); if (reduced) visu_box_convertXYZtoBoxCoordinates(boxObj, uvw, xyz); else { uvw[0] = xyz[0]; uvw[1] = xyz[1]; uvw[2] = xyz[2]; } if (visu_element_getRendered(iter.element) && iter.node->rendered) g_string_append_printf(output, " %17.8g %17.8g %17.8g\n", uvw[0], uvw[1], uvw[2]); } g_string_append_printf(output, "\n"); g_file_set_contents(filename, output->str, -1, error); g_string_free(output, TRUE); if (*error) return FALSE; else return TRUE; } v_sim-3.8.0/src/dumpModules/dumpToABINIT.h000066400000000000000000000036731370110300500202330ustar00rootroot00000000000000/* EXTRAITS DE LA LICENCE Copyright CEA, contributeurs : Damien CALISTE, laboratoire L_Sim, (2011) Adresse mèl : CALISTE, damien P caliste AT cea P fr. Ce logiciel est un programme informatique servant à visualiser des structures atomiques dans un rendu pseudo-3D. Ce logiciel est régi par la licence CeCILL soumise au droit français et respectant les principes de diffusion des logiciels libres. Vous pouvez utiliser, modifier et/ou redistribuer ce programme sous les conditions de la licence CeCILL telle que diffusée par le CEA, le CNRS et l'INRIA sur le site "http://www.cecill.info". Le fait que vous puissiez accéder à cet en-tête signifie que vous avez pris connaissance de la licence CeCILL, et que vous en avez accepté les termes (cf. le fichier Documentation/licence.fr.txt fourni avec ce logiciel). */ /* LICENCE SUM UP Copyright CEA, contributors : Damien CALISTE, laboratoire L_Sim, (2011) E-mail address: BILLARD, not reachable any more ; CALISTE, damien P caliste AT cea P fr. This software is a computer program whose purpose is to visualize atomic configurations in 3D. This software is governed by the CeCILL license under French law and abiding by the rules of distribution of free software. You can use, modify and/ or redistribute the software under the terms of the CeCILL license as circulated by CEA, CNRS and INRIA at the following URL "http://www.cecill.info". The fact that you are presently reading this means that you have had knowledge of the CeCILL license and that you accept its terms. You can find a copy of this licence shipped with this software at Documentation/licence.en.txt. */ #ifndef DUMPTOABINIT_H #define DUMPTOABINIT_H #include "fileDump.h" /** * visu_dump_abinit_getStatic: * * This routine returns the ABINIT dump object. * * Returns: (transfer none): a newly created dump object to create ABINIT files. */ const VisuDumpData* visu_dump_abinit_getStatic(); #endif v_sim-3.8.0/src/dumpModules/dumpToAscii.c000066400000000000000000000316441370110300500203070ustar00rootroot00000000000000/* EXTRAITS DE LA LICENCE Copyright CEA, contributeurs : Luc BILLARD et Damien CALISTE, laboratoire L_Sim, (2001-2005) Adresse mèl : BILLARD, non joignable par mèl ; CALISTE, damien P caliste AT cea P fr. Ce logiciel est un programme informatique servant à visualiser des structures atomiques dans un rendu pseudo-3D. Ce logiciel est régi par la licence CeCILL soumise au droit français et respectant les principes de diffusion des logiciels libres. Vous pouvez utiliser, modifier et/ou redistribuer ce programme sous les conditions de la licence CeCILL telle que diffusée par le CEA, le CNRS et l'INRIA sur le site "http://www.cecill.info". Le fait que vous puissiez accéder à cet en-tête signifie que vous avez pris connaissance de la licence CeCILL, et que vous en avez accepté les termes (cf. le fichier Documentation/licence.fr.txt fourni avec ce logiciel). */ /* LICENCE SUM UP Copyright CEA, contributors : Luc BILLARD et Damien CALISTE, laboratoire L_Sim, (2001-2005) E-mail address: BILLARD, not reachable any more ; CALISTE, damien P caliste AT cea P fr. This software is a computer program whose purpose is to visualize atomic configurations in 3D. This software is governed by the CeCILL license under French law and abiding by the rules of distribution of free software. You can use, modify and/ or redistribute the software under the terms of the CeCILL license as circulated by CEA, CNRS and INRIA at the following URL "http://www.cecill.info". The fact that you are presently reading this means that you have had knowledge of the CeCILL license and that you accept its terms. You can find a copy of this licence shipped with this software at Documentation/licence.en.txt. */ #include "dumpToAscii.h" #include #include #include #include #include #include #include static VisuDumpData *ascii = NULL; /** * SECTION:dumpToAscii * @short_description: add an export capability of current positions. * * This provides a write routine to export V_Sim current * coordinates. It has several options to output or not hiddden nodes * or replicated nodes. */ static gboolean writeDataInAscii(VisuDumpData *format, const char* filename, VisuData *dataObj, GError **error); const VisuDumpData* visu_dump_ascii_getStatic() { const gchar *typeASCII[] = {"*.ascii", (char*)0}; #define descrASCII _("ASCII file (current positions)") if (ascii) return ascii; ascii = visu_dump_data_new(descrASCII, typeASCII, writeDataInAscii); tool_file_format_addPropertyBoolean(TOOL_FILE_FORMAT(ascii), "delete_hidden_nodes", _("Don't output hidden nodes"), FALSE); tool_file_format_addPropertyBoolean(TOOL_FILE_FORMAT(ascii), "comment_hidden_nodes", _("Comment hidden nodes (if output)"), TRUE); tool_file_format_addPropertyBoolean(TOOL_FILE_FORMAT(ascii), "expand_box", _("Keep primitive box (in case of node expansion)"), FALSE); tool_file_format_addPropertyBoolean(TOOL_FILE_FORMAT(ascii), "reduced_coordinates", _("Export positions in reduced coordinates"), FALSE); tool_file_format_addPropertyBoolean(TOOL_FILE_FORMAT(ascii), "angdeg_box", _("Export box as lengths and angles"), FALSE); tool_file_format_addPropertyBoolean(TOOL_FILE_FORMAT(ascii), "type_alignment", _("Export nodes sorted by elements"), FALSE); return ascii; } static gboolean writeDataInAscii(VisuDumpData *format, const char* filename, VisuData *dataObj, GError **error) { const gchar *nom; gchar *prevFile; char tmpChr; gchar *diff; gboolean suppr, comment, expand, reduced, angdeg, eleSort; float xyz[3], ext[3], uvw[3], vertices[8][3], box[6]; double ene; VisuNodeArrayIter iter; GString *output; const gchar *nodeComment; ToolFileFormatIter it; VisuBox *boxObj; VisuDataDiff *geodiff; VisuBoxBoundaries bc; g_return_val_if_fail(error && !*error, FALSE); comment = TRUE; expand = FALSE; suppr = FALSE; reduced = FALSE; angdeg = FALSE; eleSort = FALSE; it.lst = (GList*)0; for (tool_file_format_iterNextProperty(TOOL_FILE_FORMAT(format), &it); it.lst; tool_file_format_iterNextProperty(TOOL_FILE_FORMAT(format), &it)) { DBG_fprintf(stderr, "Dump ASCII: test property '%s'.\n", it.name); if (strcmp(it.name, "comment_hidden_nodes") == 0) comment = g_value_get_boolean(it.val); else if (strcmp(it.name, "expand_box") == 0) expand = !g_value_get_boolean(it.val); else if (strcmp(it.name, "delete_hidden_nodes") == 0) suppr = g_value_get_boolean(it.val); else if (strcmp(it.name, "reduced_coordinates") == 0) reduced = g_value_get_boolean(it.val); else if (strcmp(it.name, "angdeg_box") == 0) angdeg = g_value_get_boolean(it.val); else if (strcmp(it.name, "type_alignment") == 0) eleSort = g_value_get_boolean(it.val); } DBG_fprintf(stderr, "Dump ASCII: begin export of current positions...\n"); DBG_fprintf(stderr, " | comment %d ;\n", comment); DBG_fprintf(stderr, " | expand %d ;\n", expand); DBG_fprintf(stderr, " | suppr %d ;\n", suppr); DBG_fprintf(stderr, " | reduced %d ;\n", reduced); DBG_fprintf(stderr, " | angdeg %d ;\n", angdeg); DBG_fprintf(stderr, " | eleSort %d ;\n", eleSort); output = g_string_new(""); if (VISU_IS_DATA_LOADABLE(dataObj)) { nom = visu_data_loadable_getFilename(VISU_DATA_LOADABLE(dataObj), 0); prevFile = g_path_get_basename(nom); g_string_append_printf(output, "# V_Sim export to ascii from '%s'\n", prevFile); g_free(prevFile); } else { g_string_append(output, "# V_Sim export to ascii\n"); } boxObj = visu_boxed_getBox(VISU_BOXED(dataObj)); visu_box_getVertices(boxObj, vertices, expand); if (angdeg) { box[0] = sqrt((vertices[1][0] - vertices[0][0]) * (vertices[1][0] - vertices[0][0]) + (vertices[1][1] - vertices[0][1]) * (vertices[1][1] - vertices[0][1]) + (vertices[1][2] - vertices[0][2]) * (vertices[1][2] - vertices[0][2])); box[1] = sqrt((vertices[3][0] - vertices[0][0]) * (vertices[3][0] - vertices[0][0]) + (vertices[3][1] - vertices[0][1]) * (vertices[3][1] - vertices[0][1]) + (vertices[3][2] - vertices[0][2]) * (vertices[3][2] - vertices[0][2])); box[2] = sqrt((vertices[4][0] - vertices[0][0]) * (vertices[4][0] - vertices[0][0]) + (vertices[4][1] - vertices[0][1]) * (vertices[4][1] - vertices[0][1]) + (vertices[4][2] - vertices[0][2]) * (vertices[4][2] - vertices[0][2])); box[3] = acos(CLAMP(((vertices[3][0] - vertices[0][0]) * (vertices[4][0] - vertices[0][0]) + (vertices[3][1] - vertices[0][1]) * (vertices[4][1] - vertices[0][1]) + (vertices[3][2] - vertices[0][2]) * (vertices[4][2] - vertices[0][2])) / box[1] / box[2], -1.f, 1.f)) * 180.f / G_PI; box[4] = acos(CLAMP(((vertices[1][0] - vertices[0][0]) * (vertices[4][0] - vertices[0][0]) + (vertices[1][1] - vertices[0][1]) * (vertices[4][1] - vertices[0][1]) + (vertices[1][2] - vertices[0][2]) * (vertices[4][2] - vertices[0][2])) / box[0] / box[2], -1.f, 1.f)) * 180.f / G_PI; box[4] *= (vertices[4][2] < 0.)?-1.:+1.; box[5] = acos(CLAMP(((vertices[3][0] - vertices[0][0]) * (vertices[1][0] - vertices[0][0]) + (vertices[3][1] - vertices[0][1]) * (vertices[1][1] - vertices[0][1]) + (vertices[3][2] - vertices[0][2]) * (vertices[1][2] - vertices[0][2])) / box[0] / box[1], -1.f, 1.f)) * 180.f / G_PI; } else { box[0] = vertices[1][0] - vertices[0][0]; box[1] = vertices[3][0] - vertices[0][0]; box[2] = vertices[3][1] - vertices[0][1]; box[3] = vertices[4][0] - vertices[0][0]; box[4] = vertices[4][1] - vertices[0][1]; box[5] = vertices[4][2] - vertices[0][2]; } g_string_append_printf(output, "%17.8g %17.8g %17.8g\n", box[0], box[1], box[2]); g_string_append_printf(output, "%17.8g %17.8g %17.8g\n", box[3], box[4], box[5]); if (angdeg) g_string_append(output, "#keyword: angdeg\n"); if (reduced) g_string_append(output, "#keyword: reduced\n"); switch (visu_box_getUnit(boxObj)) { case TOOL_UNITS_ANGSTROEM: g_string_append(output, "#keyword: angstroem\n"); break; case TOOL_UNITS_BOHR: g_string_append(output, "#keyword: atomic\n"); break; default: break; } bc = visu_box_getBoundary(boxObj); switch (bc) { case VISU_BOX_SURFACE_XY: g_string_append(output, "#keyword: surfaceXY\n"); break; case VISU_BOX_SURFACE_YZ: g_string_append(output, "#keyword: surfaceYZ\n"); break; case VISU_BOX_SURFACE_ZX: g_string_append(output, "#keyword: surface\n"); break; case VISU_BOX_FREE: if (reduced) g_warning("Using reduced coordinates in free boundary conditions" " is possible but not not adviced. The given box will be" " used to obtain the real coordinates."); g_string_append(output, "#keyword: freeBC\n"); break; default: break; } g_object_get(G_OBJECT(dataObj), "totalEnergy", &ene, NULL); if (ene != G_MAXFLOAT) g_string_append_printf(output, "#metaData: totalEnergy=%22.16feV\n", ene); visu_box_getVertices(boxObj, vertices, FALSE); if (expand) visu_box_getExtension(boxObj, ext); else { ext[0] = 0.; ext[1] = 0.; ext[2] = 0.; } if (ext[0] != 0. || ext[1] != 0. || ext[2] != 0.) { g_string_append(output, "# Box is expanded, previous box size:\n"); g_string_append_printf(output, "# %15g %15g %15g\n", vertices[1][0], vertices[3][0], vertices[3][1]); g_string_append_printf(output, "# %15g %15g %15g\n", vertices[4][0], vertices[4][1], vertices[4][2]); g_string_append(output, "# and box extension:\n"); g_string_append_printf(output, "# %15g %15g %15g\n", ext[0], ext[1], ext[2]); } if (comment) { g_string_append(output, "# Statistics are valid for all nodes (hidden or not).\n"); g_string_append(output, "# Hidden nodes are printed, but commented.\n"); } visu_node_array_iter_new(VISU_NODE_ARRAY(dataObj), &iter); g_string_append_printf(output, "# Box contains %d element(s).\n", iter.nElements); g_string_append_printf(output, "# Box contains %d nodes.\n", iter.nAllStoredNodes); for (visu_node_array_iterStart(VISU_NODE_ARRAY(dataObj), &iter); iter.element; visu_node_array_iterNextElement(VISU_NODE_ARRAY(dataObj), &iter, FALSE)) g_string_append_printf(output, "# | %d nodes for element '%s'.\n", iter.nStoredNodes, iter.element->name); if (suppr) g_string_append(output, "# Hidden nodes have been suppressed.\n"); geodiff = VISU_DATA_DIFF(visu_data_getNodeProperties(dataObj, VISU_DATA_DIFF_DEFAULT_ID)); if (geodiff) { diff = visu_data_diff_export(geodiff); g_string_append(output, diff); g_free(diff); } for ((eleSort)?visu_node_array_iterStart(VISU_NODE_ARRAY(dataObj), &iter): visu_node_array_iterStartNumber(VISU_NODE_ARRAY(dataObj), &iter); iter.node && iter.element; (eleSort)?visu_node_array_iterNext(VISU_NODE_ARRAY(dataObj), &iter): visu_node_array_iterNextNodeNumber(VISU_NODE_ARRAY(dataObj), &iter)) { if ((visu_element_getRendered(iter.element) && iter.node->rendered) || !comment) tmpChr = ' '; else tmpChr = '#'; visu_data_getNodePosition(dataObj, iter.node, xyz); if ((visu_element_getRendered(iter.element) && iter.node->rendered) || !suppr) { /*g_message("ext : %f, vertices : %f, ext : %f, vertices : %f, ext : %f, vertice : %f\n",ext[0],vertices[1][0],ext[1],vertices[3][0], ext[2],vertices[4][0]);*/ xyz[0] += ext[0] * vertices[1][0] + ext[1] * vertices[3][0] + ext[2] * vertices[4][0]; xyz[1] += ext[1] * vertices[3][1] + ext[2] * vertices[4][1]; xyz[2] += ext[2] * vertices[4][2]; if (reduced) { visu_box_convertXYZtoBoxCoordinates(boxObj, uvw, xyz); if (bc & 1) uvw[0] /= (1.f + 2.f * ext[0]); else uvw[0] = xyz[0]; if (bc & 2) uvw[1] /= (1.f + 2.f * ext[1]); else uvw[1] = xyz[1]; if (bc & 4) uvw[2] /= (1.f + 2.f * ext[2]); else uvw[2] = xyz[2]; } else { uvw[0] = xyz[0]; uvw[1] = xyz[1]; uvw[2] = xyz[2]; } g_string_append_printf(output, "%c%17.8g %17.8g %17.8g %c%s", tmpChr, uvw[0], uvw[1], uvw[2], (visu_element_getPhysical(iter.element))?' ':'%', iter.element->name); nodeComment = visu_data_getNodeLabelAt(dataObj, iter.node); if (nodeComment) g_string_append_printf(output, " %s", nodeComment); g_string_append(output, "\n"); } } g_file_set_contents(filename, output->str, -1, error); g_string_free(output, TRUE); if (*error) return FALSE; else return TRUE; } v_sim-3.8.0/src/dumpModules/dumpToAscii.h000066400000000000000000000040401370110300500203020ustar00rootroot00000000000000/* EXTRAITS DE LA LICENCE Copyright CEA, contributeurs : Luc BILLARD et Damien CALISTE, laboratoire L_Sim, (2001-2005) Adresse mèl : BILLARD, non joignable par mèl ; CALISTE, damien P caliste AT cea P fr. Ce logiciel est un programme informatique servant à visualiser des structures atomiques dans un rendu pseudo-3D. Ce logiciel est régi par la licence CeCILL soumise au droit français et respectant les principes de diffusion des logiciels libres. Vous pouvez utiliser, modifier et/ou redistribuer ce programme sous les conditions de la licence CeCILL telle que diffusée par le CEA, le CNRS et l'INRIA sur le site "http://www.cecill.info". Le fait que vous puissiez accéder à cet en-tête signifie que vous avez pris connaissance de la licence CeCILL, et que vous en avez accepté les termes (cf. le fichier Documentation/licence.fr.txt fourni avec ce logiciel). */ /* LICENCE SUM UP Copyright CEA, contributors : Luc BILLARD et Damien CALISTE, laboratoire L_Sim, (2001-2005) E-mail address: BILLARD, not reachable any more ; CALISTE, damien P caliste AT cea P fr. This software is a computer program whose purpose is to visualize atomic configurations in 3D. This software is governed by the CeCILL license under French law and abiding by the rules of distribution of free software. You can use, modify and/ or redistribute the software under the terms of the CeCILL license as circulated by CEA, CNRS and INRIA at the following URL "http://www.cecill.info". The fact that you are presently reading this means that you have had knowledge of the CeCILL license and that you accept its terms. You can find a copy of this licence shipped with this software at Documentation/licence.en.txt. */ #ifndef DUMPTOASCII_H #define DUMPTOASCII_H #include "fileDump.h" /** * visu_dump_ascii_getStatic: * * This routine is used to get the static #VisuDump object for ASCII exportation. * * Returns: (transfer none): the static dump object to create ASCII files. */ const VisuDumpData* visu_dump_ascii_getStatic(); #endif v_sim-3.8.0/src/dumpModules/dumpToGif.c000066400000000000000000000665731370110300500177750ustar00rootroot00000000000000/* EXTRAITS DE LA LICENCE Copyright CEA, contributeurs : Luc BILLARD et Damien CALISTE, laboratoire L_Sim, (2001-2005) Adresse mèl : BILLARD, non joignable par mèl ; CALISTE, damien P caliste AT cea P fr. Ce logiciel est un programme informatique servant à visualiser des structures atomiques dans un rendu pseudo-3D. Ce logiciel est régi par la licence CeCILL soumise au droit français et respectant les principes de diffusion des logiciels libres. Vous pouvez utiliser, modifier et/ou redistribuer ce programme sous les conditions de la licence CeCILL telle que diffusée par le CEA, le CNRS et l'INRIA sur le site "http://www.cecill.info". Le fait que vous puissiez accéder à cet en-tête signifie que vous avez pris connaissance de la licence CeCILL, et que vous en avez accepté les termes (cf. le fichier Documentation/licence.fr.txt fourni avec ce logiciel). */ /* LICENCE SUM UP Copyright CEA, contributors : Luc BILLARD et Damien CALISTE, laboratoire L_Sim, (2001-2005) E-mail address: BILLARD, not reachable any more ; CALISTE, damien P caliste AT cea P fr. This software is a computer program whose purpose is to visualize atomic configurations in 3D. This software is governed by the CeCILL license under French law and abiding by the rules of distribution of free software. You can use, modify and/ or redistribute the software under the terms of the CeCILL license as circulated by CEA, CNRS and INRIA at the following URL "http://www.cecill.info". The fact that you are presently reading this means that you have had knowledge of the CeCILL license and that you accept its terms. You can find a copy of this licence shipped with this software at Documentation/licence.en.txt. */ #include "dumpToGif.h" #include "stdlib.h" #include "stdio.h" #include "string.h" #include #include /* #include */ #include /** * SECTION:dumpToGif * @short_description: add an export capability into GIF files. * * This provides a write routine to export V_Sim views into GIF * files. * * Most of the routines used there have been modified by * L. Billard (1997 - 2001) from the original ones taken from the * ImageMagick package of cristy@dupont.com. * * The goal of this is to reduce the colour span into 256 to be * able to output as GIF file. * * * Copyright 1994 E. I. du Pont de Nemours & Company * Permission to use, copy, modify, distribute, and sell this * software and its documentation for any purpose is hereby granted * without fee, provided that the above copyright notice appear in all * copies and that both that copyright notice and this permission * notice appear in supporting documentation, and that the name of * E. I. du Pont de Nemours & Company not be used in advertising or * publicity pertaining to distribution of the software without * specific, written prior permission. E. I. du Pont de Nemours & * Company makes no representations about the suitability of this * software for any purpose. It is provided "as is" without express * or implied warranty. * E. I. du Pont de Nemours & Company disclaims all warranties * with regard to this software, including all implied warranties of * merchantability and fitness, in no event shall E. I. du Pont de * Nemours & Company be liable for any special, indirect or * consequential damages or any damages whatsoever resulting from loss * of use, data or profits, whether in an action of contract, * negligence or other tortious action, arising out of or in * connection with the use or performance of this software. * */ static unsigned char *image; #define _XOPEN_SOURCE_EXTENDED static Image *img; static FILE *file; #define False 0 #define True 1 #define Max(x,y) (((x) > (y)) ? (x) : (y)) #define Min(x,y) (((x) < (y)) ? (x) : (y)) #define MaxMapSize 65535 #define MaxRGB 255 #define color_number number_colors #define MaxNodes 266817 #define MaxTreeDepth 8 /* Log2(MaxRGB) */ #define NodesInAList 2048 static gpointer waitData; static ToolVoidDataFunc waitFunc; typedef struct _Node { struct _Node *parent, *child[8]; unsigned char id, level, children, mid_red, mid_green, mid_blue; unsigned long number_colors, number_unique, total_red, total_green, total_blue; } Node; typedef struct _Nodes { Node nodes[NodesInAList]; struct _Nodes *next; } Nodes; typedef struct _Cube{ Node *root; ColorPacket color, *colormap; guint depth; unsigned long colors, pruning_threshold, next_pruning_threshold, distance, squares[MaxRGB+MaxRGB+1]; guint shift[MaxTreeDepth+1], nodes, free_nodes, color_number; Node *next_node; Nodes *node_queue; } Cube; static Cube cube; static guint tree_depth = 8; static guint Assignment(); static guint Classification(GError **error); static void ClosestColor(register Node *node); static void Map(register Node *node); static guint DitherImage(); static guint InitializeCube(guint number_pixels, GError **error); static Node *InitializeNode( guint id,guint level,Node *parent, guint mid_red,guint mid_green,guint mid_blue); static void PruneChild(register Node *node); static void PruneLevel(register Node *node); static void Reduce(register Node *node); static void Reduction(guint number_colors); static guint LZWEncodeImage(guint data_size); static void LSBFirstWriteShort(guint value); static gboolean writeViewInGifFormat(ToolFileFormat *format, const char* filename, VisuGlNodeScene *scene, guint width, guint height, GError **error, ToolVoidDataFunc functionWait, gpointer data); /******************************************************************************/ /******************************************************************************/ void dumpToGif_setImage(Image *data) { img = data; } /******************************************************************************/ guint Assignment() { img->colormap=g_malloc(cube.colors*sizeof(ColorPacket)); cube.colormap=img->colormap; cube.colors=0; Map(cube.root); img->colors=(guint) cube.colors; if (DitherImage()) return 1; return 0; } /******************************************************************************/ guint Classification(GError **error) { register guint i; register Node *node; register ColorPacket *p; register guint bisect, id, level; p=img->pixels; for (i=0; i < img->packets; i++) { if (cube.nodes > MaxNodes) { /* Prune one level if the color tree is too large. */ PruneLevel(cube.root); cube.depth--; } /* Start at the root and descend the color cube tree. */ node=cube.root; for (level=1; level <= cube.depth; level++) { id=(p->red > node->mid_red ? 1 : 0) | (p->green > node->mid_green ? 1 : 0) << 1 | (p->blue > node->mid_blue ? 1 : 0) << 2; if (node->child[id] == (Node *) NULL) { /* Set colors of new node to contain pixel. */ node->children|=1 << id; bisect=(guint) (1 << (MaxTreeDepth-level)) >> 1; node->child[id]=InitializeNode(id,level,node, node->mid_red+(id & 1 ? bisect : -bisect), node->mid_green+(id & 2 ? bisect : -bisect), node->mid_blue+(id & 4 ? bisect : -bisect)); if (node->child[id] == (Node *) NULL) { *error = g_error_new(VISU_DUMP_ERROR, DUMP_ERROR_ENCODE, _("Unable to quantize image, " "initialisation failed for node child %d."), id); return 1; } if (level == cube.depth) cube.colors++; } /* Record the number of colors represented by this node. Shift by level in the color description tree. */ node=node->child[id]; node->number_colors+=1 << cube.shift[level]; } /* Increment unique color count and sum RGB values for this leaf for later derivation of the mean cube color. */ node->number_unique+=1; node->total_red+=p->red; node->total_green+=p->green; node->total_blue+=p->blue; p++; } return 0; } /******************************************************************************/ void ClosestColor(register Node *node) { register guint id; /* Traverse any children. */ if (node->children != 0) for (id=0; id < 8; id++) if (node->children & (1 << id)) ClosestColor(node->child[id]); if (node->number_unique != 0) { register ColorPacket *color; register guint blue_distance, green_distance, red_distance; register unsigned long distance; /* Determine if this color is "closest". */ color=cube.colormap+node->color_number; red_distance=(int) color->red-(int) cube.color.red+MaxRGB; green_distance=(int) color->green-(int) cube.color.green+MaxRGB; blue_distance=(int) color->blue-(int) cube.color.blue+MaxRGB; distance=cube.squares[red_distance]+ cube.squares[green_distance]+ cube.squares[blue_distance]; if (distance < cube.distance) { cube.distance=distance; cube.color_number=(unsigned short) node->color_number; } } } /******************************************************************************/ void Map(register Node *node) { register guint id; /* Traverse any children*/ if (node->children != 0) for (id=0; id < 8; id++) if (node->children & (1 << id)) Map(node->child[id]); if (node->number_unique > 0) { /* Map entry is defined by the mean color in this cube. */ cube.colormap[cube.colors].red=(unsigned char) ((node->total_red+(node->number_unique >> 1))/node->number_unique); cube.colormap[cube.colors].green=(unsigned char) ((node->total_green+(node->number_unique >> 1))/node->number_unique); cube.colormap[cube.colors].blue=(unsigned char) ((node->total_blue+(node->number_unique >> 1))/node->number_unique); node->color_number=cube.colors++; } } /******************************************************************************/ guint DitherImage() { #define MaxError 16 typedef struct { int red, green, blue; } ErrorPacket; ErrorPacket *error; int *cache; register int blue_error, green_error, red_error, step; register Node *node; register ColorPacket *q; register ErrorPacket *cs, *ns; register unsigned char *range_limit; register guint id; unsigned char blue, green, *range_table, red; guint i, x, y; unsigned short index; cache=g_malloc((1 << 18)*sizeof(int)); error=g_malloc(((img->columns+2) << 1)*sizeof(ErrorPacket)); range_table=g_malloc(3*(MaxRGB+1)*sizeof(unsigned char)); for (i=0; i < (1 << 18); i++) cache[i]=(-1); for (i=0; i < ((img->columns+2) << 1); i++) { error[i].red=0; error[i].green=0; error[i].blue=0; } for (i=0; i <= MaxRGB; i++) { range_table[i]=0; range_table[i+(MaxRGB+1)]=(unsigned char) i; range_table[i+(MaxRGB+1)*2]=MaxRGB; } range_limit=range_table+(MaxRGB+1); for (y=0; y < img->rows; y++) { q=img->pixels+img->columns*y; cs=error+1; ns=error+(img->columns+2)+1; step=1; if (y & 0x01) { /* Distribute error right-to-left for odd scanlines. */ q+=(img->columns-1); cs=error+(img->columns+2)+(img->columns-1)+1; ns=error+(img->columns-1)+1; step=(-1); } for (x=0; x < img->columns; x++) { red_error=(cs->red+8)/16; if (red_error > MaxError) red_error=MaxError; else if (red_error < -MaxError) red_error=(-MaxError); green_error=(cs->green+8)/16; if (green_error > MaxError) green_error=MaxError; else if (green_error < -MaxError) green_error=(-MaxError); blue_error=(cs->blue+8)/16; if (blue_error > MaxError) blue_error=MaxError; else if (blue_error < -MaxError) blue_error=(-MaxError); red=range_limit[q->red+red_error]; green=range_limit[q->green+green_error]; blue=range_limit[q->blue+blue_error]; i=(red >> 2) << 12 | (green >> 2) << 6 | blue >> 2; if (cache[i] < 0) { /* Identify the deepest node containing the pixel's color. */ node=cube.root; for ( ; ; ) { id=(red > node->mid_red ? 1 : 0) | (green > node->mid_green ? 1 : 0) << 1 | (blue > node->mid_blue ? 1 : 0) << 2; if ((node->children & (1 << id)) == 0) break; node=node->child[id]; } /* Find closest color among siblings and their children. */ cube.color.red=red; cube.color.green=green; cube.color.blue=blue; cube.distance=(unsigned long) (~0); ClosestColor(node->parent); cache[i]=cube.color_number; } index=(unsigned short) cache[i]; red_error=(int) red-(int) cube.colormap[index].red; green_error=(int) green-(int) cube.colormap[index].green; blue_error=(int) blue-(int) cube.colormap[index].blue; q->index=index; q+=step; /* Propagate the error in these proportions: Q 7/16 3/16 5/16 1/16 */ cs->red=0; cs->green=0; cs->blue=0; cs+=step; cs->red+=7*red_error; cs->green+=7*green_error; cs->blue+=7*blue_error; ns-=step; ns->red+=3*red_error; ns->green+=3*green_error; ns->blue+=3*blue_error; ns+=step; ns->red+=5*red_error; ns->green+=5*green_error; ns->blue+=5*blue_error; ns+=step; ns->red+=red_error; ns->green+=green_error; ns->blue+=blue_error; } } g_free(range_table); g_free(error); g_free(cache); return 0; } /******************************************************************************/ guint InitializeCube(guint number_pixels, GError **error) { char c; register int i; guint bits, level, max_shift; cube.node_queue=(Nodes *) NULL; cube.nodes=0; cube.free_nodes=0; cube.depth=Min(tree_depth,8); /* Initialize the shift values. */ c=1; for (bits=0; c != (char) 0; bits++) c<<=1; for (max_shift=sizeof(guint)*bits; number_pixels != 0; max_shift--) number_pixels>>=1; for (level=0; level <= cube.depth; level++) { cube.shift[level]=max_shift; if (max_shift != 0) max_shift--; } /* Initialize root node. */ cube.root=InitializeNode(0,0,(Node *) NULL, (MaxRGB+1) >> 1,(MaxRGB+1) >> 1, (MaxRGB+1) >> 1); if (cube.root == (Node *) NULL) { *error = g_error_new(VISU_DUMP_ERROR, DUMP_ERROR_ENCODE, _("Unable to quantize image, initialisation failed.")); return 1; } cube.root->parent=cube.root; cube.root->number_colors=(unsigned long) (~0); cube.colors=0; /* Initialize the square values. */ for (i=(-MaxRGB); i <= MaxRGB; i++) cube.squares[i+MaxRGB]=i*i; return 0; } /******************************************************************************/ Node *InitializeNode( guint id,guint level,Node *parent, guint mid_red,guint mid_green,guint mid_blue) { register int i; register Node *node; if (cube.free_nodes == 0) { register Nodes *nodes; /* Allocate a new nodes of nodes. */ nodes=(Nodes *) malloc(sizeof(Nodes)); if (nodes == (Nodes *) NULL) return((Node *) NULL); nodes->next=cube.node_queue; cube.node_queue=nodes; cube.next_node=nodes->nodes; cube.free_nodes=NodesInAList; } cube.nodes++; cube.free_nodes--; node=cube.next_node++; node->parent=parent; for (i=0; i < 8; i++) node->child[i]=(Node *) NULL; node->id=id; node->level=level; node->children=0; node->mid_red=mid_red; node->mid_green=mid_green; node->mid_blue=mid_blue; node->number_colors=0; node->number_unique=0; node->total_red=0; node->total_green=0; node->total_blue=0; return(node); } /******************************************************************************/ void PruneChild(register Node *node) { register Node *parent; /* Merge color statistics into parent. */ parent=node->parent; parent->children&=~(1 << node->id); parent->number_unique+=node->number_unique; parent->total_red+=node->total_red; parent->total_green+=node->total_green; parent->total_blue+=node->total_blue; cube.nodes--; } /******************************************************************************/ void PruneLevel(register Node *node) { register int id; /* Traverse any children. */ if (node->children != 0) for (id=0; id < 8; id++) if (node->children & (1 << id)) PruneLevel(node->child[id]); if (node->level == cube.depth) PruneChild(node); } /******************************************************************************/ void Reduce(register Node *node) { register guint id; /* Traverse any children. */ if (node->children != 0) for (id=0; id < 8; id++) if (node->children & (1 << id)) Reduce(node->child[id]); /* Node is a colormap entry if it has unique colors. */ if (node->number_unique > 0) cube.colors++; /* Find minimum pruning threshold. */ if (node->number_colors < cube.next_pruning_threshold) cube.next_pruning_threshold=node->number_colors; if (node->number_colors <= cube.pruning_threshold) PruneChild(node); /* Node has a sub-threshold color count */ } /******************************************************************************/ void Reduction(guint number_colors) { float i; i = 0.; cube.next_pruning_threshold=1; while (cube.colors > number_colors) { cube.pruning_threshold=cube.next_pruning_threshold; cube.next_pruning_threshold=cube.root->number_colors-1; cube.colors=0; i += 0.025; if (waitFunc && (int)(i * 100.) % 100 == 0 && i < 50.) waitFunc(waitData); Reduce(cube.root); } while (waitFunc && i<50.) { i = i + 1.; waitFunc(waitData); } } /******************************************************************************/ guint dumpToGif_quantizeImage(guint number_colors, GError **error, ToolVoidDataFunc functionWait, gpointer data) { Nodes *nodes; waitFunc = functionWait; waitData = data; /* Reduce the number of colors in the continuous tone image. */ if (number_colors > MaxMapSize) number_colors=MaxMapSize; if(InitializeCube(img->columns*img->rows, error)) return 1; if(Classification(error)) return 1; Reduction(number_colors); if(Assignment(error)) return 1; do { nodes=cube.node_queue->next; (void)free(cube.node_queue); cube.node_queue=nodes; } while (cube.node_queue != (Nodes *) NULL); return 0; } /******************************************************************************/ /******************************************************************************/ /* Function LZWEncodeImage compresses an image via LZW-coding. */ guint LZWEncodeImage(guint data_size) { #define MaxCode(number_bits) ((1 << (number_bits))-1) #define MaxHashTable 5003 #define MaxLZWBits 12 #define MaxLZWTable (1 << MaxLZWBits) #define LZWOutputCode(code) \ { \ if (bits > 0) datum|=((long) code << bits); \ else datum=(long) code; \ bits+=number_bits; \ while (bits >= 8) { \ packet[byte_count++]=(unsigned char) (datum & 0xff); \ if (byte_count >= 254) { \ (void) fputc(byte_count,file); \ (void) fwrite((char *) packet,1,byte_count,file); \ byte_count=0; \ } \ datum>>=8; \ bits-=8; \ } \ if (free_code > max_code) { \ number_bits++; \ if (number_bits == MaxLZWBits) max_code=MaxLZWTable; \ else max_code=MaxCode(number_bits); \ } \ } int bits, byte_count, next_pixel, number_bits; long datum; register unsigned i; register int displacement, j; register ColorPacket *p; short clear_code, end_of_information_code; short free_code, *hash_code, *hash_prefix, index, max_code, waiting_code; unsigned char *packet, *hash_suffix; packet=g_malloc(256*sizeof(unsigned char)); hash_code=g_malloc(MaxHashTable*sizeof(short)); hash_prefix=g_malloc(MaxHashTable*sizeof(short)); hash_suffix=g_malloc(MaxHashTable*sizeof(unsigned char)); number_bits=data_size; max_code=MaxCode(number_bits); clear_code=((short) 1 << (data_size-1)); end_of_information_code=clear_code+1; free_code=clear_code+2; byte_count=0; datum=0; bits=0; for (i=0; i < MaxHashTable; i++) hash_code[i]=0; LZWOutputCode(clear_code); p=img->pixels; waiting_code=p->index; for (i=1; i < (img->columns*img->rows); i++) { if (waitFunc && i % (img->columns*img->rows / 50) == 0) waitFunc(waitData); p++; index=p->index & 0xff; j=(int) ((int) index << (MaxLZWBits-8))+waiting_code; if (j >= MaxHashTable) j-=MaxHashTable; if (hash_code[j] > 0) { if ((hash_prefix[j] == waiting_code) && (hash_suffix[j] == index)) { waiting_code=hash_code[j]; continue; } if (j == 0) displacement=1; else displacement=MaxHashTable-j; next_pixel=False; for ( ; ; ) { j-=displacement; if (j < 0) j+=MaxHashTable; if (hash_code[j] == 0) break; if ((hash_prefix[j] == waiting_code) && (hash_suffix[j] == index)) { waiting_code=hash_code[j]; next_pixel=True; break; } } if (next_pixel == True) continue; } LZWOutputCode(waiting_code); if (free_code < MaxLZWTable) { hash_code[j]=free_code++; hash_prefix[j]=waiting_code; hash_suffix[j]=(unsigned char)index; } else { for (j=0; j < MaxHashTable; j++) hash_code[j]=0; free_code=clear_code+2; LZWOutputCode(clear_code); number_bits=data_size; max_code=MaxCode(number_bits); } waiting_code=index; } LZWOutputCode(waiting_code); LZWOutputCode(end_of_information_code); if (bits > 0) { /* Add a character to current packet. */ packet[byte_count++]=(unsigned char) (datum & 0xff); if (byte_count >= 254) { (void) fputc(byte_count,file); (void) fwrite((char *) packet,1,byte_count,file); byte_count=0; } } if (byte_count > 0) { (void) fputc(byte_count,file); (void) fwrite((char *) packet,1,byte_count,file); } g_free(hash_suffix); g_free(hash_prefix); g_free(hash_code); g_free(packet); if (i < img->packets) return(False); return(True); } /******************************************************************************/ /* LSBFirstWriteShort writes a long value as a 16 bit quantity in least-significant byte first order. */ void LSBFirstWriteShort(guint value) { unsigned char buffer[2]; buffer[0]=(unsigned char) (value); buffer[1]=(unsigned char) ((value) >> 8); (void) fwrite((char *) buffer,1,2,file); } /******************************************************************************/ void dumpToGif_syncImage(void) { register guint i; register ColorPacket *p; register unsigned short index; p=img->pixels; for (i=0; i < img->packets; i++) { index=p->index; p->red=img->colormap[index].red; p->green=img->colormap[index].green; p->blue=img->colormap[index].blue; p++; } } /******************************************************************************/ static void write_comment_comm(unsigned char comm[]) { size_t size; unsigned char c[256]; /* Extension Introducer */ c[0] = 0x21; (void)fwrite(c, sizeof(unsigned char), 1, file); /* Comment Label */ c[0] = 0xFE; (void)fwrite(c, sizeof(unsigned char), 1, file); /* Data Size ( entre 1 et 255 ) */ size = strlen((char *)comm); c[0] = (unsigned char)size; (void)fwrite(c, sizeof(unsigned char), 1, file); /* Data */ (void)fwrite(comm, sizeof(unsigned char), size, file); /* Block Terminator */ c[0] = '\0'; (void)fwrite(c, sizeof(unsigned char), 1, file); } /******************************************************************************/ VisuDump* dumpToGif_init() { VisuDump *gif; const gchar *typeGIF[] = {"*.gif", (char*)0}; #define descrGIF _("Gif (256 colors) file") gif = VISU_DUMP(visu_dump_scene_new(descrGIF, typeGIF, writeViewInGifFormat, FALSE)); waitData = (gpointer)0; waitFunc = (ToolVoidDataFunc)0; return gif; } static gboolean writeViewInGifFormat(ToolFileFormat *format _U_, const char* filename, VisuGlNodeScene *scene, guint width, guint height, GError **error, ToolVoidDataFunc functionWait, gpointer data) { register guint i; register ColorPacket *q; register unsigned char *p; unsigned char bits_per_pixel, c; guint status; GArray *imageData; g_return_val_if_fail(error && !*error, FALSE); imageData = visu_gl_ext_set_getPixmapData(VISU_GL_EXT_SET(scene), width, height, FALSE); if (!imageData) { *error = g_error_new(VISU_DUMP_ERROR, DUMP_ERROR_OPENGL, _("Can't dump OpenGL area to data.\n")); return FALSE; } waitData = data; waitFunc = functionWait; image = (unsigned char*)imageData->data; DBG_fprintf(stderr, "Dump Gif : begin export in %dx%d...\n", width, height); file = fopen(filename, "wb"); if(!file) { *error = g_error_new(VISU_DUMP_ERROR, DUMP_ERROR_FILE, _("Cannot open file (to write in).")); return FALSE; } img=g_malloc(sizeof(Image)); img->colormap = (ColorPacket*)0; img->columns = width; img->rows = height; img->packets=img->columns*img->rows; img->pixels=g_malloc(img->packets*sizeof(ColorPacket)); q=img->pixels; p=image; for (i=0; i < img->packets; i++) { q->red=(*p++); q->green=(*p++); q->blue=(*p++); q->index=0; q++; } if(dumpToGif_quantizeImage(256, error, waitFunc, data)) { g_free(img->pixels); if (img->colormap) g_free(img->colormap); g_free(img); return FALSE; } dumpToGif_syncImage(); for (bits_per_pixel=1; bits_per_pixel < 8; bits_per_pixel++) if ((1 << bits_per_pixel) >= (int)img->colors) break; (void) fwrite("GIF89a",1,6,file); LSBFirstWriteShort(img->columns); LSBFirstWriteShort(img->rows); c=0x80; /* global colormap */ c|=(8-1) << 4; /* color resolution */ c|=(bits_per_pixel-1); /* size of global colormap */ (void) fputc((int)(char) c,file); (void) fputc(0x0,file); /* background color */ (void) fputc(0x0,file); /* reserved */ for (i=0; i < img->colors; i++) { (void) fputc((int)(char) img->colormap[i].red,file); (void) fputc((int)(char) img->colormap[i].green,file); (void) fputc((int)(char) img->colormap[i].blue,file); } for ( ; i < (guint)(1 << bits_per_pixel) ; i++) { (void) fputc(0x0,file); (void) fputc(0x0,file); (void) fputc(0x0,file); } /* écriture du commentaire */ write_comment_comm((unsigned char *)"Image créée par le programme V_Sim\n" "Auteur : L. BILLARD"); (void) fputc(',',file); /* image separator */ LSBFirstWriteShort(0); LSBFirstWriteShort(0); LSBFirstWriteShort(img->columns); LSBFirstWriteShort(img->rows); (void) fputc(0x0,file); c=Max(bits_per_pixel,2); (void) fputc((int)(char) c,file); status=LZWEncodeImage(Max(bits_per_pixel,2)+1); if (status == False) { *error = g_error_new(VISU_DUMP_ERROR, DUMP_ERROR_ENCODE, _("Fail to compress the GIF file.")); g_free(img->pixels); g_free(img->colormap); g_free(img); return FALSE; } (void) fputc(0x0,file); (void) fputc(';',file); /* terminator */ (void) fclose(file); g_free(img->pixels); g_free(img->colormap); g_free(img); g_array_free(imageData, TRUE); return TRUE; } v_sim-3.8.0/src/dumpModules/dumpToGif.h000066400000000000000000000072101370110300500177610ustar00rootroot00000000000000/* EXTRAITS DE LA LICENCE Copyright CEA, contributeurs : Luc BILLARD et Damien CALISTE, laboratoire L_Sim, (2001-2005) Adresse mèl : BILLARD, non joignable par mèl ; CALISTE, damien P caliste AT cea P fr. Ce logiciel est un programme informatique servant à visualiser des structures atomiques dans un rendu pseudo-3D. Ce logiciel est régi par la licence CeCILL soumise au droit français et respectant les principes de diffusion des logiciels libres. Vous pouvez utiliser, modifier et/ou redistribuer ce programme sous les conditions de la licence CeCILL telle que diffusée par le CEA, le CNRS et l'INRIA sur le site "http://www.cecill.info". Le fait que vous puissiez accéder à cet en-tête signifie que vous avez pris connaissance de la licence CeCILL, et que vous en avez accepté les termes (cf. le fichier Documentation/licence.fr.txt fourni avec ce logiciel). */ /* LICENCE SUM UP Copyright CEA, contributors : Luc BILLARD et Damien CALISTE, laboratoire L_Sim, (2001-2005) E-mail address: BILLARD, not reachable any more ; CALISTE, damien P caliste AT cea P fr. This software is a computer program whose purpose is to visualize atomic configurations in 3D. This software is governed by the CeCILL license under French law and abiding by the rules of distribution of free software. You can use, modify and/ or redistribute the software under the terms of the CeCILL license as circulated by CEA, CNRS and INRIA at the following URL "http://www.cecill.info". The fact that you are presently reading this means that you have had knowledge of the CeCILL license and that you accept its terms. You can find a copy of this licence shipped with this software at Documentation/licence.en.txt. */ #ifndef DUMPTOGIF_H #define DUMPTOGIF_H #include "glDump.h" /** * dumpToGif_init: * * This routine should not be used since it inialised the module * and is already called when V_Sim is launched. * * Returns: (transfer none): a newly created dump object to create GIF files. */ VisuDump* dumpToGif_init(); /** * ColorPacket: * @red: red value ; * @green: green value ; * @blue: blue value ; * @index: ??. * * A private structure used by the GIF conversion. It is usefull for all * convertion from RGB to color table. */ typedef struct _ColorPacket { unsigned char red, green, blue; unsigned short index; } ColorPacket; /** * Image: * @columns: number of columns ; * @rows: number of rows ; * @colors: number of colours ; * @colormap: an array of colours ; * @pixels: the definition for each pixels ; * @packet: ?? ; * @packets: ??. * * A private structure used by the GIF conversion. It is usefull for all * convertion from RGB to color table. */ typedef struct _Image { guint columns, rows, colors; ColorPacket *colormap, *pixels, *packet; unsigned long packets; } Image; /** * dumpToGif_quantizeImage: * @number_colors: the number of desired colours ; * @error: an error location ; * @functionWait: a method that will be called during the quantize process ; * @data: an argument to give to the wait function. * * This routine transform an RGB image to an indexed colours image. To set the image * to quantize, use setImage(). * * Returns: 0 if everithing went right. */ guint dumpToGif_quantizeImage(guint number_colors, GError **error, ToolVoidDataFunc functionWait, gpointer data); /** * dumpToGif_syncImage: * * Do something in the GIF exoprt process. */ void dumpToGif_syncImage(void); /** * dumpToGif_setImage: * @data: a #Image structure. * * Set the image to be manipulated by the GIF convertor (see * dumpToGif_quantizeImage()). */ void dumpToGif_setImage(Image *data); #endif v_sim-3.8.0/src/dumpModules/dumpToPsAndPdf.c000066400000000000000000000534671370110300500207250ustar00rootroot00000000000000/* EXTRAITS DE LA LICENCE Copyright CEA, contributeurs : Luc BILLARD et Damien CALISTE, laboratoire L_Sim, (2001-2005) Adresse mèl : BILLARD, non joignable par mèl ; CALISTE, damien P caliste AT cea P fr. Ce logiciel est un programme informatique servant à visualiser des structures atomiques dans un rendu pseudo-3D. Ce logiciel est régi par la licence CeCILL soumise au droit français et respectant les principes de diffusion des logiciels libres. Vous pouvez utiliser, modifier et/ou redistribuer ce programme sous les conditions de la licence CeCILL telle que diffusée par le CEA, le CNRS et l'INRIA sur le site "http://www.cecill.info". Le fait que vous puissiez accéder à cet en-tête signifie que vous avez pris connaissance de la licence CeCILL, et que vous en avez accepté les termes (cf. le fichier Documentation/licence.fr.txt fourni avec ce logiciel). */ /* LICENCE SUM UP Copyright CEA, contributors : Luc BILLARD et Damien CALISTE, laboratoire L_Sim, (2001-2005) E-mail address: BILLARD, not reachable any more ; CALISTE, damien P caliste AT cea P fr. This software is a computer program whose purpose is to visualize atomic configurations in 3D. This software is governed by the CeCILL license under French law and abiding by the rules of distribution of free software. You can use, modify and/ or redistribute the software under the terms of the CeCILL license as circulated by CEA, CNRS and INRIA at the following URL "http://www.cecill.info". The fact that you are presently reading this means that you have had knowledge of the CeCILL license and that you accept its terms. You can find a copy of this licence shipped with this software at Documentation/licence.en.txt. */ #include "dumpToPsAndPdf.h" #include "dumpToGif.h" #define _XOPEN_SOURCE_EXTENDED #include #include #include #include /* #include */ #include #include #include /** * SECTION:dumpToPsAndPdf * @short_description: add an export capability into PS and PDF files * (encapsulating bitmaps). * * This provides a write routine to export V_Sim views into bitmaps * encapsulated into PS or PDF files. The PostScript file can be * either in 256 colours or in full True Color. For a vectorial * export, see #dumpToSVG. */ static void PrintByte(unsigned long lcode); static void OutputCode(int code); static unsigned long accumulator; static int cnt, code_width, bits; static FILE *out; static unsigned char *image; static Image *img; static int PSwidth, PSheight; static gpointer waitData; static ToolVoidDataFunc waitFunc; static gboolean writeViewInPsFormat(ToolFileFormat *format, const char* filename, VisuGlNodeScene *scene, guint width, guint height, GError **error, ToolVoidDataFunc functionWait, gpointer data); static gboolean writeViewInPs256Format(const char* filename, int width, int height, guchar* imageData, GError **error, ToolVoidDataFunc functionWait, gpointer data); static gboolean writePsTrueColor(const char* filename, int width, int height, guchar* imageData, GError **error, ToolVoidDataFunc functionWait, gpointer data); static gboolean writeViewInPdfFormat(ToolFileFormat *format, const char* filename, VisuGlNodeScene *scene, guint width, guint height, GError **error, ToolVoidDataFunc functionWait, gpointer data); static VisuDump *ps; const VisuDump* visu_dump_bitmap_ps_getStatic() { const gchar *typePS[] = {"*.ps", (char*)0}; #define descrPS _("Bitmap in a postscript (v3.0) file") if (ps) return ps; ps = VISU_DUMP(visu_dump_scene_new(descrPS, typePS, writeViewInPsFormat, FALSE)); waitFunc = (ToolVoidDataFunc)0; waitData = (gpointer)0; tool_file_format_addPropertyBoolean(TOOL_FILE_FORMAT(ps), "reduced_colormap", _("Use a reduced colormap (256 colors)"), FALSE); return ps; } static VisuDump *pdf; const VisuDump* visu_dump_bitmap_pdf_getStatic() { const gchar *typePDF[] = {"*.pdf", (char*)0}; #define descrPDF _("Bitmap in a PDF (v. 1.2)") if (pdf) return pdf; pdf = VISU_DUMP(visu_dump_scene_new(descrPDF, typePDF, writeViewInPdfFormat, FALSE)); waitFunc = (ToolVoidDataFunc)0; waitData = (gpointer)0; return pdf; } /******************************************************************************/ static void PrintByte(unsigned long lcode) { int ii; ii = lcode%256ul; (void)fprintf(out, "%02x", ii); cnt = cnt + 2; if(cnt == 78) { (void)fprintf(out, "\n"); cnt = 0; } } /******************************************************************************/ static void OutputCode(int code) { unsigned long lcode; lcode = code; accumulator = accumulator + (lcode << (32 - code_width - bits)); bits = bits + code_width; for(;;) { if(bits < 8) { break; } PrintByte(accumulator >> 24); accumulator = accumulator << 8; bits = bits - 8; } } /******************************************************************************/ static void OutputData() { #define LZWClr 256 #define LZWEod 257 int prefix[4096], suffix[4096], next[4096]; int idx, next_idx, last_code; int i; accumulator = 0ul; cnt = 0; code_width = 9; bits = 0; OutputCode(LZWClr); for(idx = 0; idx < 256; idx++) { prefix[idx] = -1; suffix[idx] = idx; next[idx] = -1; } next_idx = LZWEod + 1; code_width = 9; last_code = image[0]; for(i = 1; i<3*PSwidth*PSheight; i++) { if (waitFunc && i % (3*PSwidth*PSheight / 100) == 0) waitFunc(waitData); idx = last_code; for(;;) { if(idx == -1) { break; } if ( (prefix[idx] != last_code) || (suffix[idx] != image[i]) ) { idx = next[idx]; } else { last_code = idx; break; } } if ( last_code != idx ) { OutputCode(last_code); prefix[next_idx] = last_code; suffix[next_idx] = image[i]; next[next_idx] = next[last_code]; next[last_code] = next_idx; next_idx = next_idx + 1; if ( (next_idx >> code_width) != 0 ) { code_width = code_width + 1; if ( code_width > 12 ) { code_width = code_width - 1; OutputCode(LZWClr); for(idx = 0; idx < 256; idx++) { prefix[idx] = -1; suffix[idx] = idx; next[idx] = -1; } next_idx = LZWEod + 1; code_width = 9; } } last_code = image[i]; } } OutputCode(last_code); OutputCode(LZWEod); if ( bits != 0 ) { PrintByte(accumulator >> 24); } } /******************************************************************************/ static void OutputDataPS256() { #define LZWClr 256 #define LZWEod 257 int prefix[4096], suffix[4096], next[4096]; int idx, next_idx, last_code; guint i; accumulator = 0ul; cnt = 0; code_width = 9; bits = 0; OutputCode(LZWClr); for(idx = 0; idx < 256; idx++) { prefix[idx] = -1; suffix[idx] = idx; next[idx] = -1; } next_idx = LZWEod + 1; code_width = 9; last_code = (img->pixels[0]).index; for(i = 1; icolumns*img->rows; i++) { if (waitFunc && i % (img->columns*img->rows / 100) == 0) waitFunc(waitData); idx = last_code; for(;;) { if(idx == -1) { break; } if ( (prefix[idx] != last_code) || (suffix[idx] != (img->pixels[i]).index) ) { idx = next[idx]; } else { last_code = idx; break; } } if ( last_code != idx ) { OutputCode(last_code); prefix[next_idx] = last_code; suffix[next_idx] = (img->pixels[i]).index; next[next_idx] = next[last_code]; next[last_code] = next_idx; next_idx = next_idx + 1; if ( (next_idx >> code_width) != 0 ) { code_width = code_width + 1; if ( code_width > 12 ) { code_width = code_width - 1; OutputCode(LZWClr); for(idx = 0; idx < 256; idx++) { prefix[idx] = -1; suffix[idx] = idx; next[idx] = -1; } next_idx = LZWEod + 1; code_width = 9; } } last_code = (img->pixels[i]).index; } } OutputCode(last_code); OutputCode(LZWEod); if ( bits != 0 ) { PrintByte(accumulator >> 24); } } /******************************************************************************/ static gboolean writeViewInPsFormat(ToolFileFormat *format, const char* filename, VisuGlNodeScene *scene, guint width, guint height, GError **error, ToolVoidDataFunc functionWait _U_, gpointer data _U_) { GArray *imageData; imageData = visu_gl_ext_set_getPixmapData(VISU_GL_EXT_SET(scene), width, height, FALSE); if (!imageData) { *error = g_error_new(VISU_DUMP_ERROR, DUMP_ERROR_OPENGL, _("Can't dump OpenGL area to data.\n")); return FALSE; } if (tool_file_format_getPropertyBoolean(format, "reduced_colormap")) return writeViewInPs256Format(filename, width, height, (unsigned char*)imageData->data, error, functionWait, data); else return writePsTrueColor(filename, width, height, (unsigned char*)imageData->data, error, functionWait, data); g_array_free(imageData, TRUE); } /******************************************************************************/ static gboolean writePsTrueColor(const char* filename, int width, int height, guchar* imageData, GError **error, ToolVoidDataFunc functionWait _U_, gpointer data _U_) { static int x = 10, y = 10; time_t timer; float facx, facy, fac; int wu, hu; g_return_val_if_fail(error && !*error, FALSE); g_return_val_if_fail(imageData, FALSE); image = imageData; PSwidth = width; PSheight = height; DBG_fprintf(stderr, "Dump PS & PDF : begin PS True ToolColor export in %dx%d : %s.\n", width, height, filename); out = fopen(filename, "w"); if(!out) { *error = g_error_new(VISU_DUMP_ERROR, DUMP_ERROR_FILE, _("Cannot open file (to write in).")); return FALSE; } facx = (552.0f - x - 5)/PSwidth; facy = (796.0f - y - 5)/PSheight; if(facx < facy) { fac = facx; } else { fac = facy; } if(fac < 1.0f) { wu = PSwidth*fac + 1; hu = PSheight*fac + 1; } else { wu = PSwidth; hu = PSheight; } (void)fprintf(out, "%%!PS-Adobe-3.0\n"); (void)fprintf(out, "%%%%Title: %s\n", filename); (void)fprintf(out, "%%%%Creator: v_sim (L. BILLARD)\n"); timer = time((time_t *) NULL); (void)localtime(&timer); (void)fprintf(out, "%%%%CreationDate: %s",ctime(&timer)); (void)fprintf(out, "%%%%For: %s\n", g_get_user_name()); (void)fprintf(out, "%%%%LanguageLevel: 2\n"); (void)fprintf(out, "%%%%DocumentData: Clean7Bit\n"); (void)fprintf(out, "%%%%Orientation: Portrait\n"); (void)fprintf(out, "%%%%BoundingBox: %d %d %d %d\n", x - 1, y - 1, x + wu + 1, y + hu + 1); (void)fprintf(out, "%%%%Pages: 1\n"); (void)fprintf(out, "%%%%EndComments\n"); (void)fprintf(out, "%%%%BeginProlog\n"); (void)fprintf(out, "/ASCLZW {\n"); (void)fprintf(out, " /DeviceRGB setcolorspace\n"); (void)fprintf(out, " <>image\n"); (void)fprintf(out, "} bind def\n"); (void)fprintf(out, "%%%%EndProlog\n"); (void)fprintf(out, "%%%%Page: un 1\n"); (void)fprintf(out, "gsave\n"); (void)fprintf(out, "%d %d translate\n", x, y); (void)fprintf(out, "%f %f scale\n", 1.0*PSwidth, 1.0*PSheight); if(fac < 1.0f) { (void)fprintf(out, "%%Supplementary scaling to remain A4\n"); (void)fprintf(out, "%f %f scale\n", fac, fac); } (void)fprintf(out, "ASCLZW\n"); OutputData(); (void)fprintf(out, ">\n"); (void)fprintf(out, "grestore\n"); (void)fprintf(out, "showpage\n"); (void)fprintf(out, "%%%%PageTrailer\n"); (void)fprintf(out, "%%%%Trailer\n"); (void)fprintf(out, "%%%%EOF\n"); (void)fclose(out); return TRUE; } /******************************************************************************/ static gboolean writeViewInPdfFormat(ToolFileFormat *format _U_, const char* filename, VisuGlNodeScene *scene, guint width, guint height, GError **error, ToolVoidDataFunc functionWait _U_, gpointer data _U_) { GArray *imageData; time_t timer; struct tm *ltm; long int longueur; long int sz[10]; int i; g_return_val_if_fail(error && !*error, FALSE); imageData = visu_gl_ext_set_getPixmapData(VISU_GL_EXT_SET(scene), width, height, FALSE); if (!imageData) { *error = g_error_new(VISU_DUMP_ERROR, DUMP_ERROR_OPENGL, _("Can't dump OpenGL area to data.\n")); return FALSE; } image = (unsigned char*)imageData->data; PSwidth = width; PSheight = height; DBG_fprintf(stderr, "Dump PS & PDF : begin PDF export in %dx%d : %s.\n", width, height, filename); out = fopen(filename, "w"); if(!out) { *error = g_error_new(VISU_DUMP_ERROR, DUMP_ERROR_FILE, _("Cannot open file (to write in).")); return FALSE; } timer = time((time_t *) NULL); ltm = localtime(&timer); (void)fprintf(out, "%%PDF-1.2\n"); (void)fprintf(out, "%c%c%c%c\n", 202, 203, 204, 205); sz[1] = ftell(out); (void)fprintf(out, "1 0 obj\n"); (void)fprintf(out, "<<\n"); (void)fprintf(out, "/CreationDate (D:%04d%02d%02d%02d%02d%02d)\n", ltm->tm_year+1900, ltm->tm_mon+1, ltm->tm_mday, ltm->tm_hour, ltm->tm_min, ltm->tm_sec); (void)fprintf(out, "/Producer (v_sim \\(L. BILLARD\\))\n"); (void)fprintf(out, "/Author (%s)\n", g_get_real_name()); (void)fprintf(out, "/Title (%s)\n", filename); (void)fprintf(out, ">>\n"); (void)fprintf(out, "endobj\n"); sz[2] = ftell(out); (void)fprintf(out, "2 0 obj\n"); (void)fprintf(out, "<>\n"); (void)fprintf(out, "endobj\n"); sz[3] = ftell(out); (void)fprintf(out, "3 0 obj\n"); (void)fprintf(out, "<>\n"); (void)fprintf(out, "endobj\n"); sz[4] = ftell(out); (void)fprintf(out, "4 0 obj\n"); (void)fprintf(out, "<<\n"); (void)fprintf(out, "/Type/Page/MediaBox[0 0 %d %d]/Parent 3 0 R/Contents 5 0 R\n", PSwidth, PSheight); (void)fprintf(out, "/Resources<>>>\n"); (void)fprintf(out, ">>\n"); (void)fprintf(out, "endobj\n"); sz[5] = ftell(out); (void)fprintf(out, "5 0 obj\n"); (void)fprintf(out, "<>\n"); (void)fprintf(out, "stream\n"); longueur = ftell(out); (void)fprintf(out, "q\n"); (void)fprintf(out, "%4d 0 0 %4d 0 0 cm\n", PSwidth, PSheight); (void)fprintf(out, "/IMG Do\n"); (void)fprintf(out, "Q\n"); longueur = ftell(out) - longueur; (void)fprintf(out, "endstream\n"); (void)fprintf(out, "endobj\n"); sz[6] = ftell(out); (void)fprintf(out, "6 0 obj\n"); (void)fprintf(out, "%ld\n", longueur); (void)fprintf(out, "endobj\n"); sz[7] = ftell(out); (void)fprintf(out, "7 0 obj\n"); (void)fprintf(out, "<<\n"); (void)fprintf(out, "/Type/XObject/Subtype/Image/Name/IMG/Length" " 8 0 R/ToolColorSpace /DeviceRGB\n"); (void)fprintf(out, "/Width %d/Height %d/BitsPerComponent" " 8/Filter[/ASCIIHexDecode/LZWDecode]\n", PSwidth, PSheight); (void)fprintf(out, ">>\n"); (void)fprintf(out, "stream\n"); longueur = ftell(out); OutputData(); (void)fprintf(out, ">\n"); longueur = ftell(out) - longueur; (void)fprintf(out, "endstream\n"); (void)fprintf(out, "endobj\n"); sz[8] = ftell(out); (void)fprintf(out, "8 0 obj\n"); (void)fprintf(out, "%ld\n", longueur); (void)fprintf(out, "endobj\n"); sz[9] = ftell(out); (void)fprintf(out, "xref\n"); (void)fprintf(out, "0 9\n"); (void)fprintf(out, "%010d %05d f \n", 0, 65535); for(i=1; i<= 8; i++) (void)fprintf(out, "%010ld %05d n \n", sz[i], 0); (void)fprintf(out, "trailer\n"); (void)fprintf(out, "<>\n"); (void)fprintf(out, "startxref\n"); (void)fprintf(out, "%ld\n", sz[9]); (void)fprintf(out, "%%%%EOF\n"); (void)fclose(out); g_array_free(imageData, TRUE); return TRUE; } /******************************************************************************/ static gboolean writeViewInPs256Format(const char* filename, int width, int height, guchar* imageData, GError **error, ToolVoidDataFunc functionWait, gpointer data) { static int x = 10, y = 10; time_t timer; float facx, facy, fac; int wu, hu; register guint i; register ColorPacket *q; register unsigned char *p; g_return_val_if_fail(error && !*error, FALSE); g_return_val_if_fail(imageData, FALSE); image = imageData; PSwidth = width; PSheight = height; DBG_fprintf(stderr, "Dump PS & PDF : begin PS 256c. export in %dx%d : %s.\n", width, height, filename); img=g_malloc(sizeof(Image)); img->colormap = (ColorPacket*)0; img->columns = PSwidth; img->rows = PSheight; img->packets=img->columns*img->rows; img->pixels=g_malloc(img->packets*sizeof(ColorPacket)); q=img->pixels; p=image; for (i=0; i < img->packets; i++) { q->red=(*p++); q->green=(*p++); q->blue=(*p++); q->index=0; q++; } dumpToGif_setImage(img); if(dumpToGif_quantizeImage(256, error, functionWait, data)) { g_free(img->pixels); if (img->colormap) g_free(img->colormap); g_free(img); return FALSE; } dumpToGif_syncImage(); out = fopen(filename, "w"); if(!out) { *error = g_error_new(VISU_DUMP_ERROR, DUMP_ERROR_FILE, _("Cannot open file (to write in).")); g_free(img->pixels); g_free(img->colormap); g_free(img); return FALSE; } facx = (552.0f - x - 5)/img->columns; facy = (796.0f - y - 5)/img->rows; if(facx < facy) { fac = facx; } else { fac = facy; } if(fac < 1.0f) { wu = img->columns*fac + 1; hu = img->rows*fac + 1; } else { wu = img->columns; hu = img->rows; } (void)fprintf(out, "%%!PS-Adobe-3.0\n"); (void)fprintf(out, "%%%%Title: %s\n", filename); (void)fprintf(out, "%%%%Creator: v_sim (L. BILLARD)\n"); timer = time((time_t *) NULL); (void)localtime(&timer); (void)fprintf(out, "%%%%CreationDate: %s",ctime(&timer)); (void)fprintf(out, "%%%%For: %s\n", g_get_user_name()); (void)fprintf(out, "%%%%LanguageLevel: 2\n"); (void)fprintf(out, "%%%%DocumentData: Clean7Bit\n"); (void)fprintf(out, "%%%%Orientation: Portrait\n"); (void)fprintf(out, "%%%%BoundingBox: %d %d %d %d\n", x - 1, y - 1, x + wu + 1, y + hu + 1); (void)fprintf(out, "%%%%Pages: 1\n"); (void)fprintf(out, "%%%%EndComments\n"); (void)fprintf(out, "%%%%BeginProlog\n"); (void)fprintf(out, "/ASCLZWI {\n"); (void)fprintf(out, " /table currentfile %d string readhexstring pop " "def\n", 3 * img->colors); (void)fprintf(out, " [/Indexed /DeviceRGB %d table] setcolorspace\n", img->colors - 1); (void)fprintf(out, " <columns, img->rows); (void)fprintf(out, " /Decode [0 255] " "/ImageMatrix [%d 0 0 %d 0 %d]\n", img->columns, -img->rows, img->rows); (void)fprintf(out, " /DataSource currentfile /ASCIIHexDecode filter " "/LZWDecode filter\n"); (void)fprintf(out, " >>image\n"); (void)fprintf(out, "} bind def\n"); (void)fprintf(out, "%%%%EndProlog\n"); (void)fprintf(out, "%%%%Page: un 1\n"); (void)fprintf(out, "gsave\n"); (void)fprintf(out, "%d %d translate\n", x, y); (void)fprintf(out, "%f %f scale\n", 1.0*img->columns, 1.0*img->rows); if(fac < 1.0f) { (void)fprintf(out, "%%Supplementary scaling to remain A4\n"); (void)fprintf(out, "%f %f scale\n", fac, fac); } (void)fprintf(out, "ASCLZWI\n"); for ( i = 0; i < img->colors; i++ ) (void)fprintf(out, "%02x%02x%02x\n", (unsigned char) img->colormap[i].red, (unsigned char) img->colormap[i].green, (unsigned char) img->colormap[i].blue); OutputDataPS256(); (void)fprintf(out, ">\n"); (void)fprintf(out, "grestore\n"); (void)fprintf(out, "showpage\n"); (void)fprintf(out, "%%%%PageTrailer\n"); (void)fprintf(out, "%%%%Trailer\n"); (void)fprintf(out, "%%%%EOF\n"); (void)fclose(out); g_free(img->pixels); g_free(img->colormap); g_free(img); return TRUE; } v_sim-3.8.0/src/dumpModules/dumpToPsAndPdf.h000066400000000000000000000043721370110300500207210ustar00rootroot00000000000000/* EXTRAITS DE LA LICENCE Copyright CEA, contributeurs : Luc BILLARD et Damien CALISTE, laboratoire L_Sim, (2001-2005) Adresse mèl : BILLARD, non joignable par mèl ; CALISTE, damien P caliste AT cea P fr. Ce logiciel est un programme informatique servant à visualiser des structures atomiques dans un rendu pseudo-3D. Ce logiciel est régi par la licence CeCILL soumise au droit français et respectant les principes de diffusion des logiciels libres. Vous pouvez utiliser, modifier et/ou redistribuer ce programme sous les conditions de la licence CeCILL telle que diffusée par le CEA, le CNRS et l'INRIA sur le site "http://www.cecill.info". Le fait que vous puissiez accéder à cet en-tête signifie que vous avez pris connaissance de la licence CeCILL, et que vous en avez accepté les termes (cf. le fichier Documentation/licence.fr.txt fourni avec ce logiciel). */ /* LICENCE SUM UP Copyright CEA, contributors : Luc BILLARD et Damien CALISTE, laboratoire L_Sim, (2001-2005) E-mail address: BILLARD, not reachable any more ; CALISTE, damien P caliste AT cea P fr. This software is a computer program whose purpose is to visualize atomic configurations in 3D. This software is governed by the CeCILL license under French law and abiding by the rules of distribution of free software. You can use, modify and/ or redistribute the software under the terms of the CeCILL license as circulated by CEA, CNRS and INRIA at the following URL "http://www.cecill.info". The fact that you are presently reading this means that you have had knowledge of the CeCILL license and that you accept its terms. You can find a copy of this licence shipped with this software at Documentation/licence.en.txt. */ #ifndef DUMPTOPSANDPDF_H #define DUMPTOPSANDPDF_H #include "glDump.h" /** * visu_dump_bitmap_ps_getStatic: * * This routine returns the dump object to PS (bitmap). * * Returns: (transfer none): a newly created dump object to create PS files. */ const VisuDump* visu_dump_bitmap_ps_getStatic(); /** * visu_dump_bitmap_pdf_getStatic: * * This routine returns the dump object to PDF (bitmap). * * Returns: (transfer none): a newly created dump object to create PDF files. */ const VisuDump* visu_dump_bitmap_pdf_getStatic(); #endif v_sim-3.8.0/src/dumpModules/dumpToSVG.c000066400000000000000000001240241370110300500177110ustar00rootroot00000000000000/* EXTRAITS DE LA LICENCE Copyright CEA, contributeurs : Damien CALISTE, laboratoire L_Sim, (2001-2005) Adresse mèl : CALISTE, damien P caliste AT cea P fr. Ce logiciel est un programme informatique servant à visualiser des structures atomiques dans un rendu pseudo-3D. Ce logiciel est régi par la licence CeCILL soumise au droit français et respectant les principes de diffusion des logiciels libres. Vous pouvez utiliser, modifier et/ou redistribuer ce programme sous les conditions de la licence CeCILL telle que diffusée par le CEA, le CNRS et l'INRIA sur le site "http://www.cecill.info". Le fait que vous puissiez accéder à cet en-tête signifie que vous avez pris connaissance de la licence CeCILL, et que vous en avez accepté les termes (cf. le fichier Documentation/licence.fr.txt fourni avec ce logiciel). */ /* LICENCE SUM UP Copyright CEA, contributors : Damien CALISTE, laboratoire L_Sim, (2001-2005) E-mail address: CALISTE, damien P caliste AT cea P fr. This software is a computer program whose purpose is to visualize atomic configurations in 3D. This software is governed by the CeCILL license under French law and abiding by the rules of distribution of free software. You can use, modify and/ or redistribute the software under the terms of the CeCILL license as circulated by CEA, CNRS and INRIA at the following URL "http://www.cecill.info". The fact that you are presently reading this means that you have had knowledge of the CeCILL license and that you accept its terms. You can find a copy of this licence shipped with this software at Documentation/licence.en.txt. */ #include "dumpToSVG.h" /** * SECTION:dumpToSVG * @short_description: add an export capability into SVG files. * @include: extensions/box.h, extensions/axes.h, visu_pairs.h and visu_data.h * * This provides a write routine to export V_Sim views into SVG * files. Currently, this is an experimental feature. Not all V_Sim * elements are rendered, only the nodes, the box, the pairs and the * axes. All the characteristics are not used (no line stipple for * instance). In spin mode, nodes are only atomic. * * Since: 3.4 */ #ifdef HAVE_CAIRO #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #if CAIRO_VERSION_MINOR > 1 #include #include #define FONT_SIZE 16. #define FONT_SMALL 12. #define NVERT 2 #define NVALS 8 #define NPASS 6 #define NBUFF (NVERT * NVALS + NPASS * 2) #define PAIRS_NVERT 2 #define PAIRS_NVALS 4 #define PAIRS_XBUFF (PAIRS_NVERT * PAIRS_NVALS) #define PAIRS_NPASS 7 #define PAIRS_NBUFF (PAIRS_XBUFF + PAIRS_NPASS * 2) #define PAIRS_NCMPT (4 + 1 + PAIRS_NPASS) static gboolean writeViewInSvgFormat(ToolFileFormat *format, const char* filename, VisuGlNodeScene *scene, guint width, guint height, GError **error, ToolVoidDataFunc functionWait, gpointer data); static gboolean writeViewInPdfFormat(ToolFileFormat *format, const char* filename, VisuGlNodeScene *scene, guint width, guint height, GError **error, ToolVoidDataFunc functionWait, gpointer data); static cairo_pattern_t** svgSetup_patterns(VisuNodeArrayRenderer *array, gboolean flat); static GList* svgSetup_pairs(VisuData *dataObj); static void svgSetup_scale(cairo_t *cr, VisuData *dataObj); static GLfloat* svgCompute_pairs(VisuData *dataObj, VisuGlExtPairs *pairs, int *nPairs_out); static GLfloat* svgCompute_coordinates(VisuData *dataObj, VisuNodeArrayRenderer *renderer, int *nNodes_out); static GLfloat* svgCompute_box(int *nBox_out, VisuGlExtBox *extBox); static gboolean svgDraw_line(cairo_t *cr, float x0, float y0, float x1, float y1, float z0, float z1, float *rgb, gboolean useFog, float *fog, float se[2]); static void svgDraw_boxBack(cairo_t *cr, GLfloat *box, int nValuesBox, GLfloat val, double width, float *rgb, gboolean useFog, float fog[4], float se[2]); static void svgDraw_boxFront(cairo_t *cr, GLfloat *box, int nValuesBox, GLfloat val, double width, float *rgb, gboolean useFog, float fog[4], float se[2]); static void svgDraw_nodesAndPairs(cairo_t *cr, GLfloat *coordinates, int nNodes, GLfloat *pairs, int nPairs, cairo_pattern_t **pat, gboolean flat, gboolean useFog, float rgbaFog[4], float se[2]); static void svgDraw_legend(cairo_t *cr, VisuGlExtLegend *extLegend, cairo_pattern_t **pat); static void svgDraw_axes(cairo_t *cr, VisuGlExtAxes *extAxes); static void svgDraw_pairs(cairo_t *cr, GLfloat *pairs, int nPairs, int *iPairs, GLfloat val, gboolean useFog, float fog[4], float se[2]); static void svgDraw_node(cairo_t *cr, VisuElementAtomicShapeId shape, float radius); static VisuDump *svg; static double g_width, g_height; static double zoomLevel = 1.; static VisuDumpCairoAdd postFunc = NULL; /** * visu_dump_cairo_setPostFunc: * @func: (allow-none) (scope call): a #VisuDumpCairoAdd function or %NULL. * * Allow to add a function that will be called on every Cairo * exportation after V_Sim rendering to allow post-processing. * * Since: 3.7 **/ void visu_dump_cairo_setPostFunc(VisuDumpCairoAdd func) { DBG_fprintf(stderr, "Visu DumpCairo: set a new post-processing method.\n"); postFunc = func; } const VisuDump* visu_dump_cairo_svg_getStatic() { const gchar *typeSVG[] = {"*.svg", (char*)0}; #define descrSVG _("Scalar Vector Graphic (SVG) file") if (svg) return svg; svg = VISU_DUMP(visu_dump_scene_new(descrSVG, typeSVG, writeViewInSvgFormat, TRUE)); tool_file_format_addPropertyBoolean(TOOL_FILE_FORMAT(svg), "use_flat_rendering", _("Use flat colours for scheme rendering"), FALSE); return svg; } static VisuDump *pdf; const VisuDump* visu_dump_cairo_pdf_getStatic() { const gchar *typePDF[] = {"*.pdf", (char*)0}; #define descrPDF _("Portable Document Format (PDF) file") if (pdf) return pdf; pdf = VISU_DUMP(visu_dump_scene_new(descrPDF, typePDF, writeViewInPdfFormat, TRUE)); tool_file_format_addPropertyBoolean(TOOL_FILE_FORMAT(pdf), "use_flat_rendering", _("Use flat colours for scheme rendering"), FALSE); return pdf; } static void sort_by_z(float *coordinates, float *buffer, int n, int z, int begin, int end) { int i; int middle; if( begin >= end ) return; memcpy(buffer, coordinates + begin * n, sizeof(float) * n); memcpy(coordinates + begin * n, coordinates + (end + begin) / 2 * n, sizeof(float) * n); memcpy(coordinates + (end + begin) / 2 * n, buffer, sizeof(float) * n); middle = begin; for(i = begin + 1; i <= end; i++) { if ( coordinates[i * n + z] > coordinates[begin * n + z] ) { middle += 1; memcpy(buffer, coordinates + i * n, sizeof(float) * n); memcpy(coordinates + i * n, coordinates + middle * n, sizeof(float) * n); memcpy(coordinates + middle * n, buffer, sizeof(float) * n); } } memcpy(buffer, coordinates + begin * n, sizeof(float) * n); memcpy(coordinates + begin * n, coordinates + middle * n, sizeof(float) * n); memcpy(coordinates + middle * n, buffer, sizeof(float) * n); sort_by_z(coordinates, buffer, n, z, begin, middle - 1); sort_by_z(coordinates, buffer, n, z, middle + 1, end); } gboolean writeDataToCairoSurface(cairo_surface_t *cairo_surf, guint width, guint height, ToolFileFormat *format, VisuGlNodeScene *scene, GError **error, ToolVoidDataFunc functionWait, gpointer user_data) { cairo_t *cr; cairo_status_t status; cairo_pattern_t **pat; guint i; int nNodes, nPairs; float rgbaBg[4], centre[3], fog[4], se[2]; GLfloat *coordinates, *box, *pairs; int nValuesBox; gboolean flat; VisuNodeArrayIter iter; cairo_matrix_t scale = {1., 0., 0., 1., 0., 0.}; VisuData *dataObj; VisuGlView *view; double gross; guint oldW, oldH; VisuGlExtBox *extBox; VisuDataColorizer *colorizer; VisuPixmapContext *dumpData; DBG_fprintf(stderr, "Dump SVG: begin OpenGL buffer writing.\n"); /* We get the properties related to SVG output. */ flat = tool_file_format_getPropertyBoolean(format, "use_flat_rendering"); /* We setup the cairo output. */ cr = cairo_create(cairo_surf); status = cairo_status(cr); if (status != CAIRO_STATUS_SUCCESS) { *error = g_error_new(VISU_DUMP_ERROR, DUMP_ERROR_FILE, "%s", cairo_status_to_string(status)); cairo_destroy(cr); return FALSE; } view = visu_gl_node_scene_getGlView(scene); /* We need a fake pixmap context for OpenGL rendering. */ dumpData = visu_pixmap_context_new((width > 0) ? width : view->window.width, (height > 0) ? height : view->window.height); if (!dumpData) { *error = g_error_new(VISU_DUMP_ERROR, DUMP_ERROR_FILE, "can't create off-screen pixmap."); cairo_destroy(cr); return FALSE; } /* We set the glViewport of this new context. */ visu_gl_initContext(VISU_GL(scene)); /* We must change the viewport and zoom... */ gross = view->camera.gross; oldW = view->window.width; oldH = view->window.height; /* We unzoom to allow GL to render out-of-the-box points. */ zoomLevel = MAX(view->camera.gross, 1.f); visu_gl_view_setGross(view, MIN(view->camera.gross, 1.f)); visu_gl_view_setViewport(view, (width > 0) ? width : view->window.width, (height > 0) ? height : view->window.height); dataObj = visu_gl_node_scene_getData(scene); cairo_set_line_cap(cr, CAIRO_LINE_CAP_ROUND); DBG_fprintf(stderr, "Dump SVG: setup scale and patterns.\n"); svgSetup_scale(cr, dataObj); pat = svgSetup_patterns(VISU_NODE_ARRAY_RENDERER(visu_gl_node_scene_getNodes(scene)), flat); DBG_fprintf(stderr, " | OK.\n"); glPushMatrix(); visu_box_getCentre(visu_boxed_getBox(VISU_BOXED(dataObj)), centre); glTranslated(-centre[0], -centre[1], -centre[2]); /* We calculate the node positions. */ DBG_fprintf(stderr, "Dump SVG: compute coordinates.\n"); coordinates = svgCompute_coordinates(dataObj, VISU_NODE_ARRAY_RENDERER(visu_gl_node_scene_getNodes(scene)), &nNodes); if (functionWait) functionWait(user_data); /* Calculate the pair positions. */ nPairs = -1; pairs = (GLfloat*)0; if (visu_gl_ext_getActive(VISU_GL_EXT(visu_gl_node_scene_getPairs(scene)))) pairs = svgCompute_pairs(dataObj, visu_gl_node_scene_getPairs(scene), &nPairs); if (functionWait) functionWait(user_data); /* We draw the background colour. */ visu_gl_ext_set_getBgColor(VISU_GL_EXT_SET(scene), rgbaBg); cairo_set_source_rgba(cr, rgbaBg[0], rgbaBg[1], rgbaBg[2], rgbaBg[3]); cairo_paint(cr); /* Experimental. */ g_width = width; g_height = height; cairo_save(cr); cairo_scale(cr, zoomLevel, zoomLevel); cairo_translate(cr, g_width * (1. / zoomLevel - 1.) * 0.5, g_height * (1. / zoomLevel - 1.) * 0.5); cairo_rectangle(cr, -g_width * (1. / zoomLevel - 1.) * 0.5, -g_height * (1. / zoomLevel - 1.) * 0.5, (g_width - 0.5) / zoomLevel, (g_height - 0.5) / zoomLevel); cairo_clip(cr); /* Draw the back box. */ nValuesBox = -1; box = (GLfloat*)0; extBox = visu_gl_node_scene_getBox(scene); visu_gl_ext_set_getFogColor(VISU_GL_EXT_SET(scene), fog); visu_gl_ext_set_getFogStartFull(VISU_GL_EXT_SET(scene), se); if (visu_gl_ext_getActive(VISU_GL_EXT(extBox))) { box = svgCompute_box(&nValuesBox, visu_gl_node_scene_getBox(scene)); svgDraw_boxBack(cr, box, nValuesBox, coordinates[nNodes - NBUFF + 3], (double)visu_gl_ext_lined_getWidth(VISU_GL_EXT_LINED(extBox)) / zoomLevel, visu_gl_ext_lined_getRGBA(VISU_GL_EXT_LINED(extBox)), visu_gl_ext_set_getFogActive(VISU_GL_EXT_SET(scene)), fog, se); } if (functionWait) functionWait(user_data); DBG_fprintf(stderr, "Dump SVG: begin main SVG exportation.\n"); /* We draw nodes and pairs. */ colorizer = visu_node_array_renderer_getColorizer(VISU_NODE_ARRAY_RENDERER(visu_gl_node_scene_getNodes(scene))); svgDraw_nodesAndPairs(cr, coordinates, nNodes, pairs, nPairs, !(colorizer && visu_data_colorizer_getActive(colorizer)) ? pat:(cairo_pattern_t**)0, flat, visu_gl_ext_set_getFogActive(VISU_GL_EXT_SET(scene)), fog, se); if (pairs) g_free(pairs); if (functionWait) functionWait(user_data); /* Draw the front box. */ if (box) svgDraw_boxFront(cr, box, nValuesBox, coordinates[nNodes - NBUFF + 3], (double)visu_gl_ext_lined_getWidth(VISU_GL_EXT_LINED(extBox)) / zoomLevel, visu_gl_ext_lined_getRGBA(VISU_GL_EXT_LINED(extBox)), visu_gl_ext_set_getFogActive(VISU_GL_EXT_SET(scene)), fog, se); if (box) g_free(box); if (functionWait) functionWait(user_data); cairo_restore(cr); g_free(coordinates); /* We draw the axes. */ if (visu_gl_ext_getActive(VISU_GL_EXT(visu_gl_node_scene_getAxes(scene)))) svgDraw_axes(cr, visu_gl_node_scene_getAxes(scene)); if (functionWait) functionWait(user_data); glPopMatrix(); /* We draw a legend, if required. */ if (visu_gl_ext_getActive(VISU_GL_EXT(visu_gl_node_scene_getLegend(scene)))) svgDraw_legend(cr, visu_gl_node_scene_getLegend(scene), pat); if (functionWait) functionWait(user_data); visu_node_array_iter_new(VISU_NODE_ARRAY(dataObj), &iter); for (i = 0; i < iter.nElements; i++) cairo_pattern_destroy(pat[i]); g_free(pat); if (postFunc) { DBG_fprintf(stderr, "Visu DumpCairo: call the post-processing method.\n"); cairo_set_matrix(cr, &scale); postFunc(cr, width, height); } cairo_show_page(cr); cairo_destroy(cr); /* We free the pixmap context. */ visu_pixmap_context_free(dumpData); /* We must put back the viewport... */ visu_gl_view_setViewport(view, oldW, oldH); /* We must put back the gross also. */ visu_gl_view_setGross(view, gross); return TRUE; } static gboolean writeViewInSvgFormat(ToolFileFormat *format, const char* filename, VisuGlNodeScene *scene, guint width, guint height, GError **error, ToolVoidDataFunc functionWait, gpointer data) { cairo_surface_t *svg_surface; cairo_status_t status; g_return_val_if_fail(error && !*error, FALSE); DBG_fprintf(stderr, "Dump Cairo: begin export to SVG.\n"); svg_surface = cairo_svg_surface_create(filename, (double)width, (double)height); status = cairo_surface_status(svg_surface); if (status != CAIRO_STATUS_SUCCESS) { *error = g_error_new(VISU_DUMP_ERROR, DUMP_ERROR_FILE, "%s", cairo_status_to_string(status)); cairo_surface_destroy(svg_surface); return FALSE; } writeDataToCairoSurface(svg_surface, width, height, format, scene, error, functionWait, data); cairo_surface_destroy(svg_surface); return TRUE; } static gboolean writeViewInPdfFormat(ToolFileFormat *format, const char* filename, VisuGlNodeScene *scene, guint width, guint height, GError **error, ToolVoidDataFunc functionWait, gpointer data) { cairo_surface_t *pdf_surface; cairo_status_t status; g_return_val_if_fail(error && !*error, FALSE); DBG_fprintf(stderr, "Dump Cairo: begin export to PDF.\n"); pdf_surface = cairo_pdf_surface_create(filename, (double)width, (double)height); status = cairo_surface_status(pdf_surface); if (status != CAIRO_STATUS_SUCCESS) { *error = g_error_new(VISU_DUMP_ERROR, DUMP_ERROR_FILE, "%s", cairo_status_to_string(status)); cairo_surface_destroy(pdf_surface); return FALSE; } writeDataToCairoSurface(pdf_surface, width, height, format, scene, error, functionWait, data); cairo_surface_destroy(pdf_surface); return TRUE; } static void svgDraw_legend(cairo_t *cr, VisuGlExtLegend *extLegend, cairo_pattern_t **pat) { cairo_matrix_t scaleFont = {FONT_SIZE, 0., 0., -FONT_SIZE, 0., 0.}; GLfloat *legend; GLint nValuesLegend; float lgWidth, lgHeight, max; int i, iEle; gchar *lbl; float radius; VisuNodeArrayRenderer *nodes; VisuNodeArrayRendererIter iter; legend = g_malloc(sizeof(GLfloat) * 70000); glFeedbackBuffer(70000, GL_3D, legend); glRenderMode(GL_FEEDBACK); visu_gl_ext_call(VISU_GL_EXT(extLegend), TRUE); nValuesLegend = glRenderMode(GL_RENDER); cairo_select_font_face(cr, "Serif", CAIRO_FONT_SLANT_NORMAL, CAIRO_FONT_WEIGHT_NORMAL); cairo_set_font_size(cr, 12.0); /* The two first polygons are the white frame. */ if (nValuesLegend >= 22) { cairo_set_source_rgba(cr, 1.f, 1.f, 1.f, 0.4f); lgWidth = legend[5] - legend[2]; lgHeight = legend[9] - legend[3]; cairo_rectangle(cr, legend[2], legend[3], lgWidth, lgHeight); cairo_fill(cr); /* Run to the names and the elements... */ iEle = 0; nodes = visu_gl_ext_legend_getNodes(extLegend); visu_node_array_renderer_iter_new(nodes, &iter, TRUE); max = visu_node_array_renderer_getMaxElementSize(nodes, NULL); for (i = 0; i < nValuesLegend; i++) if (legend[i] == GL_BITMAP_TOKEN) { /* Write the name. */ cairo_move_to(cr, legend[i + 1], legend[i + 2]); lbl = g_strdup_printf("%s (%d)", iter.element->name, iter.nStoredNodes); cairo_set_source_rgb(cr, 0.f, 0.f, 0.f); cairo_set_font_matrix(cr, &scaleFont); cairo_show_text(cr, lbl); g_free(lbl); /* Draw the element. */ radius = 0.4f * lgHeight * visu_element_atomic_getRadius(VISU_ELEMENT_ATOMIC(iter.renderer)) / max; cairo_new_path(cr); cairo_save(cr); cairo_translate(cr, legend[i + 1] - 0.6f * lgHeight, legend[3] + 0.5f * lgHeight); svgDraw_node(cr, visu_element_atomic_getShape(VISU_ELEMENT_ATOMIC(iter.renderer)), radius); cairo_save(cr); cairo_scale(cr, radius, radius); cairo_set_source(cr, pat[iEle]); cairo_fill_preserve(cr); cairo_restore(cr); cairo_set_source_rgb(cr, 0.f, 0.f, 0.f); cairo_stroke(cr); cairo_restore(cr); iEle += 1; visu_node_array_renderer_iter_next(&iter); do i += 4; while (legend[i] == GL_BITMAP_TOKEN && i < nValuesLegend); } } g_free(legend); } static void svgDraw_axes(cairo_t *cr, VisuGlExtAxes *extAxes) { cairo_matrix_t scaleFont = {FONT_SIZE, 0., 0., -FONT_SIZE, 0., 0.}; GLfloat *axes; GLint nValuesAxes; float *rgb; /* We create the feedback for the axes. */ axes = g_malloc(sizeof(GLfloat) * 7000); glFeedbackBuffer(7000, GL_3D, axes); glRenderMode(GL_FEEDBACK); visu_gl_ext_call(VISU_GL_EXT(extAxes), TRUE); nValuesAxes = glRenderMode(GL_RENDER); DBG_fprintf(stderr, "Dump Cairo: found %d axes output.\n", nValuesAxes); cairo_set_line_width(cr, (double)visu_gl_ext_lined_getWidth(VISU_GL_EXT_LINED(extAxes))); rgb = visu_gl_ext_lined_getRGBA(VISU_GL_EXT_LINED(extAxes)); cairo_set_source_rgb(cr, rgb[0], rgb[1], rgb[2]); cairo_select_font_face(cr, "Serif", CAIRO_FONT_SLANT_NORMAL, CAIRO_FONT_WEIGHT_NORMAL); cairo_set_font_size(cr, 12.0); /* We draw the 3 lines of the axes. */ if (nValuesAxes >= 21 && axes[0] == GL_LINE_RESET_TOKEN && axes[7] == GL_LINE_RESET_TOKEN && axes[14] == GL_LINE_RESET_TOKEN) { DBG_fprintf(stderr, "Dump Cairo: output axes.\n"); cairo_move_to(cr, axes[0 + 1], axes[0 + 2]); cairo_line_to(cr, axes[0 + 4], axes[0 + 5]); cairo_stroke(cr); cairo_move_to(cr, axes[7 + 1], axes[7 + 2]); cairo_line_to(cr, axes[7 + 4], axes[7 + 5]); cairo_stroke(cr); cairo_move_to(cr, axes[14 + 1], axes[14 + 2]); cairo_line_to(cr, axes[14 + 4], axes[14 + 5]); cairo_stroke(cr); } cairo_set_source_rgb(cr, 1.f - rgb[0], 1.f - rgb[1], 1.f - rgb[2]); cairo_set_font_matrix(cr, &scaleFont); if (nValuesAxes >= 33 && axes[21] == GL_BITMAP_TOKEN && axes[25] == GL_BITMAP_TOKEN && axes[29] == GL_BITMAP_TOKEN) { DBG_fprintf(stderr, "Dump Cairo: output axes names.\n"); cairo_move_to(cr, axes[21 + 1], axes[21 + 2]); cairo_show_text(cr, "x"); cairo_move_to(cr, axes[25 + 1], axes[25 + 2]); cairo_show_text(cr, "y"); cairo_move_to(cr, axes[29 + 1], axes[29 + 2]); cairo_show_text(cr, "z"); } g_free(axes); } static GList* svgSetup_pairs(VisuData *dataObj) { GList *pairsLst; VisuPairLinkIter iter, *pairData; VisuPairSet *pairs; VisuPairSetIter it; gboolean valid; pairsLst = (GList*)0; pairs = visu_pair_set_new(); visu_pair_set_setModel(pairs, dataObj); for (visu_pair_set_iter_new(pairs, &it, FALSE); it.link; visu_pair_set_iter_next(&it)) { for (valid = visu_pair_link_iter_new(it.link, dataObj, &iter, FALSE); valid; valid = visu_pair_link_iter_next(&iter)) { #if GLIB_MINOR_VERSION > 9 pairData = g_slice_alloc(sizeof(VisuPairLinkIter)); #else pairData = g_malloc(sizeof(VisuPairLinkIter)); #endif *pairData = iter; pairsLst = g_list_prepend(pairsLst, pairData); } } g_object_unref(pairs); return pairsLst; } static GLfloat* svgCompute_pairs(VisuData *dataObj, VisuGlExtPairs *pairs, int *nPairs_out) { int nPairs, i; guint width; GLfloat *glPairs; GLint nValues; GList *tmpLst; VisuPairLinkIter *pairData; float u[3], radius, norm; ToolColor *color; float tmpPairs[6]; GList *pairsLst; VisuElementRenderer *eleRenderer; VisuNodeArrayRenderer *nodeRenderer; VisuPairLinkRenderer *renderer; VisuDataColorizer *colorizer; pairsLst = svgSetup_pairs(dataObj); *nPairs_out = nPairs = g_list_length(pairsLst); if (nPairs <= 0) return (GLfloat*)0; DBG_fprintf(stderr, "Dump Cairo: found %d pairs to draw.\n", nPairs); glPairs = g_malloc(sizeof(GLfloat) * nPairs * PAIRS_NBUFF); glFeedbackBuffer(nPairs * PAIRS_NBUFF, GL_3D, glPairs); glRenderMode(GL_FEEDBACK); glPushMatrix(); /* Render the list of pairs and free them each time. */ nodeRenderer = visu_gl_ext_pairs_getDataRenderer(pairs); colorizer = visu_node_array_renderer_getColorizer(nodeRenderer); for (tmpLst = pairsLst; tmpLst; tmpLst = g_list_next(tmpLst)) { pairData = (VisuPairLinkIter*)tmpLst->data; u[0] = pairData->xyz2[0] - pairData->xyz1[0]; u[1] = pairData->xyz2[1] - pairData->xyz1[1]; u[2] = pairData->xyz2[2] - pairData->xyz1[2]; norm = sqrt(pairData->d2); u[0] /= norm; u[1] /= norm; u[2] /= norm; eleRenderer = visu_node_array_renderer_get(nodeRenderer, pairData->iter1.element); radius = visu_element_renderer_getExtent(eleRenderer); radius *= (colorizer) ? visu_data_colorizer_getScalingFactor(colorizer, dataObj, pairData->iter1.node) : 1.f; pairData->xyz1[0] += radius * u[0]; pairData->xyz1[1] += radius * u[1]; pairData->xyz1[2] += radius * u[2]; eleRenderer = visu_node_array_renderer_get(nodeRenderer, pairData->iter2.element); radius = visu_element_renderer_getExtent(eleRenderer); radius *= (colorizer) ? visu_data_colorizer_getScalingFactor(colorizer, dataObj, pairData->iter2.node) : 1.f; pairData->xyz2[0] -= radius * u[0]; pairData->xyz2[1] -= radius * u[1]; pairData->xyz2[2] -= radius * u[2]; glBegin(GL_POINTS); glVertex3fv(pairData->xyz1); glVertex3fv(pairData->xyz2); glEnd(); /* We save colour channel as passthrough. */ color = visu_pair_link_getColor(pairData->parent); glPassThrough(color->rgba[0]); glPassThrough(color->rgba[1]); glPassThrough(color->rgba[2]); glPassThrough(pairData->coeff); /* We save the width and the printLength in a passthrough. */ renderer = visu_gl_ext_pairs_getLinkRenderer(pairs, pairData->parent); if (VISU_IS_PAIR_WIRE_RENDERER(renderer)) width = visu_pair_wire_getWidth(VISU_PAIR_WIRE(pairData->parent)); else width = 10; glPassThrough((float)width); if (visu_pair_link_getPrintLength(pairData->parent)) glPassThrough(norm); else glPassThrough(-1.f); glPassThrough((float)visu_pair_wire_getStipple(VISU_PAIR_WIRE(pairData->parent))); /* Free the data. */ #if GLIB_MINOR_VERSION > 9 g_slice_free1(sizeof(VisuPairLinkIter), tmpLst->data); #else g_free(tmpLst->data); #endif } glPopMatrix(); /* Free the list itself. */ g_list_free(pairsLst); /* Analyse the OpenGL results. */ nValues = glRenderMode(GL_RENDER); DBG_fprintf(stderr, " | OpenGL returns %d.\n", nValues); i = 0; nPairs = 0; while (i < nValues) { if (glPairs[i] == GL_POINT_TOKEN && glPairs[i + PAIRS_NVALS] == GL_POINT_TOKEN && glPairs[i + 2 * PAIRS_NVALS] == GL_PASS_THROUGH_TOKEN) { /* Copy all these values into the beginning of the pairs array. */ norm = (glPairs[i + 3] + glPairs[i + 7]) / 2.f; glPairs[nPairs * PAIRS_NCMPT + 0] = glPairs[i + 1]; /* x1 */ glPairs[nPairs * PAIRS_NCMPT + 1] = glPairs[i + 2]; /* y1 */ glPairs[nPairs * PAIRS_NCMPT + 2] = glPairs[i + 5]; /* x2 */ glPairs[nPairs * PAIRS_NCMPT + 3] = glPairs[i + 6]; /* y2 */ glPairs[nPairs * PAIRS_NCMPT + 4] = norm; /* altitude */ glPairs[nPairs * PAIRS_NCMPT + 5] = glPairs[i + PAIRS_XBUFF + 7]; /* alpha */ glPairs[nPairs * PAIRS_NCMPT + 6] = glPairs[i + PAIRS_XBUFF + 1]; /* red */ glPairs[nPairs * PAIRS_NCMPT + 7] = glPairs[i + PAIRS_XBUFF + 3]; /* green */ glPairs[nPairs * PAIRS_NCMPT + 8] = glPairs[i + PAIRS_XBUFF + 5]; /* blue */ glPairs[nPairs * PAIRS_NCMPT + 9] = glPairs[i + PAIRS_XBUFF + 9]; /* width */ glPairs[nPairs * PAIRS_NCMPT + 10] = glPairs[i + PAIRS_XBUFF + 11]; /* prtLg */ glPairs[nPairs * PAIRS_NCMPT + 11] = glPairs[i + PAIRS_XBUFF + 13]; /* Stipp */ i += PAIRS_NBUFF; nPairs += 1; } else if (glPairs[i] == GL_POINT_TOKEN && glPairs[i + PAIRS_NVALS] == GL_PASS_THROUGH_TOKEN) { DBG_fprintf(stderr, "| uncomplete pair for i=%d\n", i); i += PAIRS_NVALS + 2 * PAIRS_NPASS; } else if (glPairs[i] == GL_PASS_THROUGH_TOKEN) { DBG_fprintf(stderr, "| no pair for i=%d\n", i); i += 2 * PAIRS_NPASS; } } sort_by_z(glPairs, tmpPairs, PAIRS_NCMPT, 4, 0, nPairs - 1); DBG_fprintf(stderr, " | will draw %d pairs.\n", nPairs); *nPairs_out = nPairs; return glPairs; } static GLfloat* svgCompute_coordinates(VisuData *dataObj, VisuNodeArrayRenderer *nodeRenderer, int *nNodes_out) { VisuNodeArrayIter iter; VisuElementRenderer *renderer; const ToolColor *color; const gfloat *material; GLfloat *coordinates; GLint nValues; float tmpFloat[NBUFF]; float modelView[16]; float xyz[3], radius, rgba[4]; int i, nNodes; VisuDataColorizer *colorizer; colorizer = visu_node_array_renderer_getColorizer(nodeRenderer); visu_node_array_iter_new(VISU_NODE_ARRAY(dataObj), &iter); /* We create a feedback mode to get node coordinates. */ coordinates = g_malloc(sizeof(GLfloat) * (iter.nAllStoredNodes * NBUFF)); glFeedbackBuffer((iter.nAllStoredNodes * NBUFF), GL_3D_COLOR, coordinates); glRenderMode(GL_FEEDBACK); glGetFloatv(GL_MODELVIEW_MATRIX, modelView); /* First thing is to order nodes along z axes. */ for (visu_node_array_iterStartVisible(VISU_NODE_ARRAY(dataObj), &iter); iter.node; visu_node_array_iterNextVisible(VISU_NODE_ARRAY(dataObj), &iter)) { renderer = visu_node_array_renderer_get(nodeRenderer, iter.element); color = visu_element_renderer_getColor(renderer); material = visu_element_renderer_getMaterial(renderer); glBegin(GL_POINTS); visu_data_getNodePosition(dataObj, iter.node, xyz); if (!colorizer || !visu_data_colorizer_getColor(colorizer, rgba, dataObj, iter.node)) { rgba[0] = color->rgba[0]; rgba[1] = color->rgba[1]; rgba[2] = color->rgba[2]; rgba[3] = color->rgba[3]; } visu_gl_setColor((VisuGl*)0, material, rgba); /* We compute the node position in the eyes coordinates. */ glVertex3fv(xyz); /* We compute the node apparent radius using the real radius in X direction in ModelView. */ radius = visu_element_atomic_getRadius(VISU_ELEMENT_ATOMIC(renderer)); radius *= (colorizer) ? visu_data_colorizer_getScalingFactor(colorizer, dataObj, iter.node) : 1.f; glVertex3f(xyz[0] + modelView[0] * radius, xyz[1] + modelView[4] * radius, xyz[2] + modelView[8] * radius); glEnd(); /* We store the number of the VisuElement. */ glPassThrough(iter.iElement); /* We store the element shape. */ glPassThrough(visu_element_atomic_getShape(VISU_ELEMENT_ATOMIC(renderer))); /* We store the node colour. */ glPassThrough(rgba[0]); glPassThrough(rgba[1]); glPassThrough(rgba[2]); glPassThrough(rgba[3]); } /* We sort the coordinates along z. */ nValues = glRenderMode(GL_RENDER); /* We compact coordinates to keep complete vertex list. */ i = 0; nNodes = 0; while (i < nValues) { if (coordinates[i] == GL_POINT_TOKEN && coordinates[i + NVALS] == GL_POINT_TOKEN) { /* fprintf(stderr, "Found a complete node %d, at %gx%g.\n", */ /* i, coordinates[i + 1], coordinates[i + 2]); */ /* fprintf(stderr, " | move it from %d to %d.\n", i, nNodes); */ /* A complete set, copying it to nNodes location. */ if (nNodes != i) memcpy(coordinates + nNodes, coordinates + i, sizeof(GLfloat) * NBUFF); i += NBUFF; nNodes += NBUFF; } else { /* fprintf(stderr, "Found a uncomplete node at %d.\n", i); */ /* Incomplete set, go on till the GL_PASS_THROUGH_TOKEN. */ while (coordinates[i] != GL_PASS_THROUGH_TOKEN) i += 1; /* Remove the GL_POINT_TOKEN. */ i += 2; /* fprintf(stderr, " | jump to %d.\n", i); */ } } sort_by_z(coordinates, tmpFloat, NBUFF, 3, 0, nNodes / NBUFF - 1); *nNodes_out = nNodes; return coordinates; } static cairo_pattern_t* svgGet_pattern(gboolean flat, const float rgba[4], float alpha) { cairo_pattern_t *pat; float hsl[3], rgb[3], lum; if (flat) pat = cairo_pattern_create_rgba(rgba[0], rgba[1], rgba[2], rgba[3] * alpha); else { pat = cairo_pattern_create_radial(.4f, .4f, .1f, 0.f, 0.f, 1.f); /* We get the Element colour in HSL. */ tool_color_convertRGBtoHSL(hsl, rgba); lum = hsl[2]; hsl[2] = CLAMP(lum + 0.2f, 0.f, 1.f); tool_color_convertHSLtoRGB(rgb, hsl); cairo_pattern_add_color_stop_rgba(pat, 0, rgb[0], rgb[1], rgb[2], alpha); hsl[2] = CLAMP(lum + 0.05f, 0.f, 1.f); tool_color_convertHSLtoRGB(rgb, hsl); cairo_pattern_add_color_stop_rgba(pat, 0.3, rgb[0], rgb[1], rgb[2], alpha); hsl[2] = CLAMP(lum - 0.05f, 0.f, 1.f); tool_color_convertHSLtoRGB(rgb, hsl); cairo_pattern_add_color_stop_rgba(pat, 0.7, rgb[0], rgb[1], rgb[2], alpha); hsl[2] = CLAMP(lum - 0.2f, 0.f, 1.f); tool_color_convertHSLtoRGB(rgb, hsl); cairo_pattern_add_color_stop_rgba(pat, 1, rgb[0], rgb[1], rgb[2], alpha); } return pat; } static cairo_pattern_t** svgSetup_patterns(VisuNodeArrayRenderer *array, gboolean flat) { cairo_pattern_t **pat; VisuNodeArrayRendererIter iter; guint i; pat = g_malloc(sizeof(cairo_pattern_t*) * visu_node_array_getNElements(visu_node_array_renderer_getNodeArray(array), FALSE)); for (visu_node_array_renderer_iter_new(array, &iter, FALSE), i = 0; iter.element; visu_node_array_renderer_iter_next(&iter), i++) pat[i] = svgGet_pattern(flat, visu_element_renderer_getColor(iter.renderer)->rgba, 1.f); return pat; } static void svgSetup_scale(cairo_t *cr, VisuData *dataObj _U_) { int viewport[4]; cairo_matrix_t scale = {1., 0., 0., -1., 0., 0.}; glGetIntegerv(GL_VIEWPORT, viewport); scale.y0 = (double)viewport[3]; cairo_set_matrix(cr, &scale); } static GLfloat* svgCompute_box(int *nBox_out, VisuGlExtBox *extBox) { GLfloat *box; GLint nValuesBox; box = g_malloc(sizeof(GLfloat) * 7000); glFeedbackBuffer(7000, GL_3D, box); glRenderMode(GL_FEEDBACK); visu_gl_ext_call(VISU_GL_EXT(extBox), FALSE); nValuesBox = glRenderMode(GL_RENDER); *nBox_out = (int)nValuesBox; return box; } static gboolean svgDraw_line(cairo_t *cr, float x0, float y0, float x1, float y1, float z0, float z1, float *rgb, gboolean useFog, float fog[4], float se[2]) { float d[4], a; cairo_pattern_t *pat; double xm, ym; /* projection of surface centre on AB. */ double xo, yo /* surface centre. */; double alpha, beta, lambda; double xmin, xmax, ymin, ymax; alpha = x1 - x0; beta = y1 - y0; xo = g_width * 0.5; yo = g_height * 0.5; xm = alpha * alpha * xo - alpha * beta * (y0 - yo) + beta * beta * x0; ym = alpha * alpha * y0 - alpha * beta * (x0 - xo) + beta * beta * yo; xm /= alpha * alpha + beta * beta; ym /= alpha * alpha + beta * beta; lambda = (alpha * (xm - x0) + beta * (ym - y0)) / (alpha * alpha + beta * beta); xmin = g_width * (1. - 1. / zoomLevel) * 0.5; xmax = g_width * (1. + 1. / zoomLevel) * 0.5; ymin = g_height * (1. - 1. / zoomLevel) * 0.5; ymax = g_height * (1. + 1. / zoomLevel) * 0.5; /* The projection of AB is outside the box. */ if (xm < xmin || xm > xmax || ym < ymin || ym > ymax) return FALSE; /* The projection is outside AB and a and B are outside the box. */ if ((lambda < 0. || lambda > 1.) && (x0 < xmin || x0 > xmax || y0 < ymin || y0 > ymax) && (x1 < xmin || x1 > xmax || y1 < ymin || y1 > ymax)) return FALSE; pat = (cairo_pattern_t*)0; if (useFog) { DBG_fprintf(stderr, "Dump SVG: draw a line between %g - %g with fog at %g - %g.\n", z0, z1, se[0], se[1]); if (z0 != z1) { pat = cairo_pattern_create_linear(x0, y0, x1, y1); a = CLAMP(se[0] + (se[1] - z0) / (se[1] - se[0]), 0.f, 1.f); d[0] = a * rgb[0] + (1.f - a) * fog[0]; d[1] = a * rgb[1] + (1.f - a) * fog[1]; d[2] = a * rgb[2] + (1.f - a) * fog[2]; d[3] = a + (1.f - a) * fog[3]; cairo_pattern_add_color_stop_rgba(pat, 0, d[0], d[1], d[2], d[3]); a = CLAMP(se[0] + (se[1] - z1) / (se[1] - se[0]), 0.f, 1.f); d[0] = a * rgb[0] + (1.f - a) * fog[0]; d[1] = a * rgb[1] + (1.f - a) * fog[1]; d[2] = a * rgb[2] + (1.f - a) * fog[2]; d[3] = a + (1.f - a) * fog[3]; cairo_pattern_add_color_stop_rgba(pat, 1, d[0], d[1], d[2], d[3]); cairo_set_source(cr, pat); } else { a = CLAMP(se[0] + (se[1] - z1) / (se[1] - se[0]), 0.f, 1.f); d[0] = a * rgb[0] + (1.f - a) * fog[0]; d[1] = a * rgb[1] + (1.f - a) * fog[1]; d[2] = a * rgb[2] + (1.f - a) * fog[2]; d[3] = a + (1.f - a) * fog[3]; cairo_set_source_rgba(cr, d[0], d[1], d[2], d[3]); } } else cairo_set_source_rgb(cr, rgb[0], rgb[1], rgb[2]); cairo_move_to(cr, x0, y0); cairo_line_to(cr, x1, y1); cairo_stroke(cr); if (pat) cairo_pattern_destroy(pat); return TRUE; } static void svgDraw_boxBack(cairo_t *cr, GLfloat *box, int nValuesBox, GLfloat val, double width, float *rgb, gboolean useFog, float fog[4], float se[2]) { int i; cairo_set_line_width(cr, width); /* We draw the lines that have a boundary hidden by elements. */ for (i = 0; i < nValuesBox; i += 7) if (box[i + 3] >= val && box[i + 6] >= val) svgDraw_line(cr, box[i + 1], box[i + 2], box[i + 4], box[i + 5], box[i + 3], box[i + 6], rgb, useFog, fog, se); } static void svgDraw_boxFront(cairo_t *cr, GLfloat *box, int nValuesBox, GLfloat val, double width, float *rgb, gboolean useFog, float fog[4], float se[2]) { int i; cairo_set_line_width(cr, width); /* We draw the lines that have a boundary hidden by elements. */ for (i = 0; i < nValuesBox; i += 7) if (box[i + 3] < val || box[i + 6] < val) svgDraw_line(cr, box[i + 1], box[i + 2], box[i + 4], box[i + 5], box[i + 3], box[i + 6], rgb, useFog, fog, se); } static void svgDraw_node(cairo_t *cr, VisuElementAtomicShapeId shape, float radius) { if (shape == VISU_ELEMENT_ATOMIC_POINT) cairo_rectangle(cr, -radius / 4, -radius / 4, radius / 2, radius / 2); else cairo_arc(cr, 0.f, 0.f, radius, 0., 2 * G_PI); } static void svgDraw_nodesAndPairs(cairo_t *cr, GLfloat *coordinates, int nNodes, GLfloat *pairs, int nPairs, cairo_pattern_t **pat, gboolean flat, gboolean useFog, float rgbaFog[4], float se[2]) { int iPairs, i; float alpha, radius, rgba[4]; cairo_matrix_t scaleFont = {FONT_SMALL / zoomLevel, 0., 0., -FONT_SMALL / zoomLevel, 0., 0.}; cairo_pattern_t *pat_; VisuElementAtomicShapeId shape; double xmin, xmax, ymin, ymax; cairo_set_line_width(cr, 1. / zoomLevel); cairo_set_font_matrix(cr, &scaleFont); iPairs = 0; alpha = 1.f; xmin = g_width * (1. - 1. / zoomLevel) * 0.5; xmax = g_width * (1. + 1. / zoomLevel) * 0.5; ymin = g_height * (1. - 1. / zoomLevel) * 0.5; ymax = g_height * (1. + 1. / zoomLevel) * 0.5; for (i = 0; i < nNodes; i+= NBUFF) { /* We draw the pairs in between. */ svgDraw_pairs(cr, pairs, nPairs, &iPairs, coordinates[i + 3], useFog, rgbaFog, se); /* Compute the alpha for the fog. */ alpha = (useFog) ? CLAMP(se[0] + (se[1] - coordinates[i + 3]) / (se[1] - se[0]), 0.f, 1.f) : 1.f; radius = (coordinates[i + NVALS + 1] - coordinates[i + 1]) * (coordinates[i + NVALS + 1] - coordinates[i + 1]) + (coordinates[i + NVALS + 2] - coordinates[i + 2]) * (coordinates[i + NVALS + 2] - coordinates[i + 2]); radius = sqrt(radius); /* fprintf(stderr, "%gx%g %g %g %g\n", coordinates[i + 1], coordinates[i + 2], */ /* radius, coordinates[i + 3], coordinates[i + NBUFF - 1]); */ if (alpha > 0.f && radius > 0.f && (coordinates[i + 1] + radius) >= xmin && (coordinates[i + 1] - radius) <= xmax && (coordinates[i + 2] + radius) >= ymin && (coordinates[i + 2] - radius) <= ymax ) { /* cairo_push_group(cr); */ cairo_new_path(cr); cairo_save(cr); shape = (VisuElementAtomicShapeId)coordinates[i + NVERT * NVALS + 3]; cairo_translate(cr, coordinates[i + 1], coordinates[i + 2]); svgDraw_node(cr, shape, radius); cairo_save(cr); cairo_scale(cr, radius, radius); if (pat) cairo_set_source(cr, pat[(int)coordinates[i + NVERT * NVALS + 1]]); else { if (flat) { rgba[0] = coordinates[i + NVERT * NVALS + 5]; rgba[1] = coordinates[i + NVERT * NVALS + 7]; rgba[2] = coordinates[i + NVERT * NVALS + 9]; rgba[3] = coordinates[i + NVERT * NVALS + 11]; } else { rgba[0] = coordinates[i + 4]; rgba[1] = coordinates[i + 5]; rgba[2] = coordinates[i + 6]; rgba[3] = 1.f; } pat_ = svgGet_pattern(flat, rgba, 1.f); cairo_set_source(cr, pat_); cairo_pattern_destroy(pat_); } cairo_fill_preserve(cr); if (alpha < 1.f) { cairo_set_source_rgba(cr, rgbaFog[0], rgbaFog[1], rgbaFog[2], 1.f - alpha); cairo_fill_preserve(cr); } cairo_restore(cr); cairo_set_source_rgb(cr, (1.f - alpha) * rgbaFog[0], (1.f - alpha) * rgbaFog[1], (1.f - alpha) * rgbaFog[2]); cairo_set_line_width(cr, 1. / zoomLevel); cairo_stroke(cr); cairo_restore(cr); /* cairo_pop_group_to_source(cr); */ /* cairo_paint_with_alpha (cr, alpha); */ } } /* We draw the remaining pairs. */ svgDraw_pairs(cr, pairs, nPairs, &iPairs, -1, useFog, rgbaFog, se); } static int svgGet_stipple(guint16 stipple, double dashes[16]) { int n, i; gboolean status; n = 0; memset(dashes, '\0', sizeof(double) * 16); for (i = 0, status = (stipple & 1); i < 16; status = (stipple & (1 << i++))) { if (((stipple & (1 << i)) && !status) || (!(stipple & (1 << i)) && status)) n += 1; dashes[n] += 1; } DBG_fprintf(stderr, " | %d -> ", stipple); for (i = 0; i <= n; i++) DBG_fprintf(stderr, " %f", dashes[i]); DBG_fprintf(stderr, "\n"); return n + 1; } static void svgDraw_pairs(cairo_t *cr, GLfloat *pairs, int nPairs, int *iPairs, GLfloat val, gboolean useFog, float fog[4], float se[2]) { char distStr[8]; double dashes[16]; int n; if (pairs && *iPairs < PAIRS_NCMPT * nPairs) { while (pairs[*iPairs + 4] > val && *iPairs < PAIRS_NCMPT * nPairs) { n = svgGet_stipple((guint16)pairs[*iPairs + 11], dashes); DBG_fprintf(stderr, " | pair %d at (%f;%f) - (%f;%f) %g,%g %d -> %d\n", *iPairs / PAIRS_NCMPT, pairs[*iPairs + 0], pairs[*iPairs + 1], pairs[*iPairs + 2], pairs[*iPairs + 3], pairs[*iPairs + 4], pairs[*iPairs + 5], (guint16)pairs[*iPairs + 11], n); if (n > 1) cairo_set_dash(cr, dashes, n, 0); cairo_set_line_width(cr, pairs[*iPairs + 9] / zoomLevel); if (svgDraw_line(cr, pairs[*iPairs + 0], pairs[*iPairs + 1], pairs[*iPairs + 2], pairs[*iPairs + 3], pairs[*iPairs + 4], pairs[*iPairs + 4], pairs + *iPairs + 6, useFog, fog, se) && pairs[*iPairs + 10] > 0) { cairo_move_to(cr, (pairs[*iPairs + 0] + pairs[*iPairs + 2]) * 0.5, (pairs[*iPairs + 1] + pairs[*iPairs + 3]) * 0.5); sprintf(distStr, "%7.3f", pairs[*iPairs + 10]); cairo_show_text(cr, distStr); } cairo_set_dash(cr, dashes, 0, 0); *iPairs += PAIRS_NCMPT; } cairo_set_line_width(cr, 1. / zoomLevel); } } #endif #endif v_sim-3.8.0/src/dumpModules/dumpToSVG.h000066400000000000000000000047671370110300500177310ustar00rootroot00000000000000/* EXTRAITS DE LA LICENCE Copyright CEA, contributeurs : Damien CALISTE, laboratoire L_Sim, (2001-2005) Adresse mèl : CALISTE, damien P caliste AT cea P fr. Ce logiciel est un programme informatique servant à visualiser des structures atomiques dans un rendu pseudo-3D. Ce logiciel est régi par la licence CeCILL soumise au droit français et respectant les principes de diffusion des logiciels libres. Vous pouvez utiliser, modifier et/ou redistribuer ce programme sous les conditions de la licence CeCILL telle que diffusée par le CEA, le CNRS et l'INRIA sur le site "http://www.cecill.info". Le fait que vous puissiez accéder à cet en-tête signifie que vous avez pris connaissance de la licence CeCILL, et que vous en avez accepté les termes (cf. le fichier Documentation/licence.fr.txt fourni avec ce logiciel). */ /* LICENCE SUM UP Copyright CEA, contributors : Damien CALISTE, laboratoire L_Sim, (2001-2005) E-mail address: CALISTE, damien P caliste AT cea P fr. This software is a computer program whose purpose is to visualize atomic configurations in 3D. This software is governed by the CeCILL license under French law and abiding by the rules of distribution of free software. You can use, modify and/ or redistribute the software under the terms of the CeCILL license as circulated by CEA, CNRS and INRIA at the following URL "http://www.cecill.info". The fact that you are presently reading this means that you have had knowledge of the CeCILL license and that you accept its terms. You can find a copy of this licence shipped with this software at Documentation/licence.en.txt. */ #ifndef DUMPTOSVG_H #define DUMPTOSVG_H #include "glDump.h" #include /** * visu_dump_cairo_svg_getStatic: * * This routine returns the dump object to SVG format. * * Returns: (transfer none): a newly created dump object to create SVG files. */ const VisuDump* visu_dump_cairo_svg_getStatic(); /** * visu_dump_cairo_pdf_getStatic: * * This routine returns the dump object to PDF format. * * Returns: (transfer none): a newly created dump object to create SVG files. */ const VisuDump* visu_dump_cairo_pdf_getStatic(); /** * VisuDumpCairoAdd: * @cr: a #cairo_t context. * @width: width of the surface. * @height: height of the surface. * * A method to be called by V_Sim after exportation to allow post-processing. */ typedef void (*VisuDumpCairoAdd)(cairo_t *cr, guint width, guint height); void visu_dump_cairo_setPostFunc(VisuDumpCairoAdd func); #endif v_sim-3.8.0/src/dumpModules/dumpToTiff.c000066400000000000000000000403021370110300500201360ustar00rootroot00000000000000/* EXTRAITS DE LA LICENCE Copyright CEA, contributeurs : Luc BILLARD et Damien CALISTE, laboratoire L_Sim, (2001-2005) Adresse mèl : BILLARD, non joignable par mèl ; CALISTE, damien P caliste AT cea P fr. Ce logiciel est un programme informatique servant à visualiser des structures atomiques dans un rendu pseudo-3D. Ce logiciel est régi par la licence CeCILL soumise au droit français et respectant les principes de diffusion des logiciels libres. Vous pouvez utiliser, modifier et/ou redistribuer ce programme sous les conditions de la licence CeCILL telle que diffusée par le CEA, le CNRS et l'INRIA sur le site "http://www.cecill.info". Le fait que vous puissiez accéder à cet en-tête signifie que vous avez pris connaissance de la licence CeCILL, et que vous en avez accepté les termes (cf. le fichier Documentation/licence.fr.txt fourni avec ce logiciel). */ /* LICENCE SUM UP Copyright CEA, contributors : Luc BILLARD et Damien CALISTE, laboratoire L_Sim, (2001-2005) E-mail address: BILLARD, not reachable any more ; CALISTE, damien P caliste AT cea P fr. This software is a computer program whose purpose is to visualize atomic configurations in 3D. This software is governed by the CeCILL license under French law and abiding by the rules of distribution of free software. You can use, modify and/ or redistribute the software under the terms of the CeCILL license as circulated by CEA, CNRS and INRIA at the following URL "http://www.cecill.info". The fact that you are presently reading this means that you have had knowledge of the CeCILL license and that you accept its terms. You can find a copy of this licence shipped with this software at Documentation/licence.en.txt. */ #include "dumpToTiff.h" #include "stdlib.h" #include "stdio.h" #include "string.h" #include #include /** * SECTION:dumpToTiff * @short_description: add an export capability into TIFF files. * * This provides a write routine to export V_Sim views into TIFF * files. */ static FILE *output; static unsigned char *image; static int TIFFwidth, TIFFheight; static gboolean writeViewInTiffFormat(ToolFileFormat *format, const char* filename, VisuGlNodeScene *scene, guint width, guint height, GError **error, ToolVoidDataFunc functionWait, gpointer data); static gpointer waitData; static ToolVoidDataFunc waitFunc; static VisuDump *tiff; const VisuDump* visu_dump_tiff_getStatic() { const gchar *typeTIF[] = {"*.tif", "*.tiff", (char*)0}; #define descrTIF _("Tiff file") if (tiff) return tiff; tiff = VISU_DUMP(visu_dump_scene_new(descrTIF, typeTIF, writeViewInTiffFormat, FALSE)); waitData = (gpointer)0; waitFunc = (ToolVoidDataFunc)0; return tiff; } /******************************************************************************/ /******************************************************************************/ static void encode(); /******************************************************************************/ static void OutputData() { encode(); } /******************************************************************************/ static void OutHeader(guint value, guint bytes) { unsigned char str[4]; register guint k; register int is = 4 - bytes; for (k=0; k> 24; (void)fwrite(str, sizeof(unsigned char), bytes, output); } /******************************************************************************/ static void WriteTif() { char ImageDescription[1024] = "Image dump from V_Sim"; char Software[] = "V_Sim (L. BILLARD)"; /* RGB FullColor */ guint PhotometricInterpretation = 2; guint BitsPerSample[3] = {8, 8, 8}; guint SamplesPerPixel = 3; /* LZW compression */ guint Compression = 5; unsigned char str[4]; guint offset; guint nb_entries; guint tag, type, count; guint offset_bits; guint ImageDescription_length; guint offset_imagedescription; guint StripOffsets_nbr; guint offset_posi; guint RowsPerStrip; guint StripByteCounts_nbr; guint data_written; guint XResolution[2]; guint x_posi; guint YResolution[2]; guint y_posi; guint ResolutionUnit; guint Software_length; guint offset_software; /********************* 12 octets en tête ****************************/ /* big_endian */ str[0] = 77; str[1] = 77; (void)fwrite(str, sizeof(unsigned char), 2, output); /* caractéristique TIFF 42 */ str[0] = 0; str[1] = 42; (void)fwrite(str, sizeof(unsigned char), 2, output); /* offset = 8 pour IFD (temporaire) */ offset = 8; OutHeader(offset, 4); /******************** Champs 'trop longs ' *************************/ StripOffsets_nbr = 1; XResolution[0] = 72; XResolution[1] = 1; YResolution[0] = 72; YResolution[1] = 1; ResolutionUnit = 2; offset_bits = ftell(output); OutHeader(BitsPerSample[0], 2); OutHeader(BitsPerSample[1], 2); OutHeader(BitsPerSample[2], 2); ImageDescription_length = 1 + strlen(ImageDescription); switch (ImageDescription_length) { case 1: offset_imagedescription = 0; break; case 2: offset_imagedescription = 65536*ImageDescription[0]; break; default: offset_imagedescription = ftell(output); (void)fwrite(ImageDescription, sizeof(char), ImageDescription_length, output); break; } offset_posi = ftell(output); OutputData(); data_written = ftell(output) - offset_posi; RowsPerStrip = TIFFheight; StripByteCounts_nbr = StripOffsets_nbr; x_posi = ftell(output); OutHeader(XResolution[0], 4); OutHeader(XResolution[1], 4); y_posi = ftell(output); OutHeader(YResolution[0], 4); OutHeader(YResolution[1], 4); Software_length = 1 + strlen(Software); switch (Software_length) { case 1: offset_software = 0; break; case 2: offset_software = 65536*Software[0]; break; default: offset_software = ftell(output); (void)fwrite(Software, sizeof(char), Software_length, output); break; } /******************** IFD ******************************************/ /* je stocke la position */ offset = ftell(output); /* provisoire */ nb_entries = 0; OutHeader(nb_entries, 2); tag = 256; OutHeader(tag, 2); type = 4; OutHeader(type, 2); count = 1; OutHeader(count, 4); OutHeader(TIFFwidth, 4); nb_entries++; tag = 257; OutHeader(tag, 2); type = 4; OutHeader(type, 2); count = 1; OutHeader(count, 4); OutHeader(TIFFheight, 4); nb_entries++; tag = 258; OutHeader(tag, 2); type = 3; OutHeader(type, 2); count = SamplesPerPixel; OutHeader(count, 4); OutHeader(offset_bits, 4); nb_entries++; tag = 259; OutHeader(tag, 2); type = 3; OutHeader(type, 2); count = 1; OutHeader(count, 4); OutHeader(Compression, 2); OutHeader(0, 2); nb_entries++; tag = 262; OutHeader(tag, 2); type = 3; OutHeader(type, 2); count = 1; OutHeader(count, 4); OutHeader(PhotometricInterpretation, 2); OutHeader(0, 2); nb_entries++; tag = 270; OutHeader(tag, 2); type = 2; OutHeader(type, 2); count = ImageDescription_length; OutHeader(count, 4); OutHeader(offset_imagedescription, 4); nb_entries++; tag = 273; OutHeader(tag, 2); type = 4; OutHeader(type, 2); count = StripOffsets_nbr; OutHeader(count, 4); OutHeader(offset_posi, 4); nb_entries++; tag = 277; OutHeader(tag, 2); type = 3; OutHeader(type, 2); count = 1; OutHeader(count, 4); OutHeader(SamplesPerPixel, 2); OutHeader(0, 2); nb_entries++; tag = 278; OutHeader(tag, 2); type = 4; OutHeader(type, 2); count = 1; OutHeader(count, 4); OutHeader(RowsPerStrip, 4); nb_entries++; tag = 279; OutHeader(tag, 2); type = 4; OutHeader(type, 2); count = StripByteCounts_nbr; OutHeader(count, 4); OutHeader(data_written, 4); nb_entries++; tag = 282; OutHeader(tag, 2); type = 5; OutHeader(type, 2); count = 1; OutHeader(count, 4); OutHeader(x_posi, 4); nb_entries++; tag = 283; OutHeader(tag, 2); type = 5; OutHeader(type, 2); count = 1; OutHeader(count, 4); OutHeader(y_posi, 4); nb_entries++; tag = 296; OutHeader(tag, 2); type = 3; OutHeader(type, 2); count = 1; OutHeader(count, 4); OutHeader(ResolutionUnit, 2); OutHeader(0, 2); nb_entries++; tag = 305; OutHeader(tag, 2); type = 2; OutHeader(type, 2); count = Software_length; OutHeader(count, 4); OutHeader(offset_software, 4); nb_entries++; /* pas d'autre IFD */ OutHeader(0, 4); /* je ré-écris proprement nb_entries */ if (fseek(output, offset, SEEK_SET)) { g_error("INTERNAL ERROR! I cannot go at requested position\n"); } OutHeader(nb_entries, 2); /* je ré-écris proprement la position de l'IFD */ if (fseek(output, 4, SEEK_SET)) { g_error("INTERNAL ERROR! I cannot go at requested position\n"); } OutHeader(offset, 4); } /******************************************************************************/ /******************************************************************************/ /* Encodage LZW pp. 57 et suivantes */ #define CLEAR 256 #define EOI 257 static struct { int previous; unsigned char value; } table[4096]; static guint table_next; static guint length_bit; static guint stock; static guint remain; /******************************************************************************/ static struct { guint nbr; guint *table_index; guint *table_previous; } related[256]; /* related[i] donne la liste de toutes les tables dont table[].value = i; à savoir: pour k = 0; k < related[i].nbr on a: (related[i].table_index)[k] (related[i].table_previous)[k] table[(related[i].table_index)[k]].previous = (related[i].table_previous)[k]; table[(related[i].table_index)[k]].value = i; */ static int search(unsigned char value, guint previous) { /* chercher la table telle que: table[which].previous = previous; table[which].value = value; retourne -1, si pas trouvée */ register guint k; int which = -1; for (k=0; k= 8) { guint k = (stock >> 24); fputc(k, output); stock <<= 8; remain -= 8; } } /******************************************************************************/ static void Flush() { /* je sors ce qui reste (< 8 bits) */ if (remain) { guint k = (stock >> 24); fputc(k, output); } } /******************************************************************************/ static void AddTableEntry(guint last, unsigned char c) { guint nbr; table[table_next].previous = last; table[table_next].value = c; nbr = related[c].nbr + 1; related[c].table_index = g_realloc(related[c].table_index, nbr * sizeof(guint)); related[c].table_previous = g_realloc(related[c].table_previous, nbr * sizeof(guint)); (related[c].table_index)[related[c].nbr] = table_next; (related[c].table_previous)[related[c].nbr] = last; related[c].nbr = nbr; table_next++; if (table_next == 512) length_bit = 10; else if (table_next == 1024) length_bit = 11; else if (table_next == 2048) length_bit = 12; } /******************************************************************************/ static void encode() { register guint n; int it_is; unsigned char k; int which; guint image_length; /*(void)printf("Be patient: LZW encoding!...\n");*/ image_length = 3*TIFFwidth*TIFFheight; stock = 0; remain = 0; InitializeStringTable(); WriteCode(CLEAR); k = image[0]; it_is = k; for (n=1; ndata; TIFFwidth = width; TIFFheight = height; DBG_fprintf(stderr, "Dump TIFF: begin export in %dx%d...\n", width, height); output = fopen(filename, "wb"); if(!output) { *error = g_error_new(VISU_DUMP_ERROR, DUMP_ERROR_FILE, _("Cannot open file (to write in).")); return FALSE; } DBG_fprintf(stderr, "Dump Tif: begin export...\n"); WriteTif(); g_array_free(imageData, TRUE); (void)fclose(output); return TRUE; } v_sim-3.8.0/src/dumpModules/dumpToTiff.h000066400000000000000000000037571370110300500201600ustar00rootroot00000000000000/* EXTRAITS DE LA LICENCE Copyright CEA, contributeurs : Luc BILLARD et Damien CALISTE, laboratoire L_Sim, (2001-2005) Adresse mèl : BILLARD, non joignable par mèl ; CALISTE, damien P caliste AT cea P fr. Ce logiciel est un programme informatique servant à visualiser des structures atomiques dans un rendu pseudo-3D. Ce logiciel est régi par la licence CeCILL soumise au droit français et respectant les principes de diffusion des logiciels libres. Vous pouvez utiliser, modifier et/ou redistribuer ce programme sous les conditions de la licence CeCILL telle que diffusée par le CEA, le CNRS et l'INRIA sur le site "http://www.cecill.info". Le fait que vous puissiez accéder à cet en-tête signifie que vous avez pris connaissance de la licence CeCILL, et que vous en avez accepté les termes (cf. le fichier Documentation/licence.fr.txt fourni avec ce logiciel). */ /* LICENCE SUM UP Copyright CEA, contributors : Luc BILLARD et Damien CALISTE, laboratoire L_Sim, (2001-2005) E-mail address: BILLARD, not reachable any more ; CALISTE, damien P caliste AT cea P fr. This software is a computer program whose purpose is to visualize atomic configurations in 3D. This software is governed by the CeCILL license under French law and abiding by the rules of distribution of free software. You can use, modify and/ or redistribute the software under the terms of the CeCILL license as circulated by CEA, CNRS and INRIA at the following URL "http://www.cecill.info". The fact that you are presently reading this means that you have had knowledge of the CeCILL license and that you accept its terms. You can find a copy of this licence shipped with this software at Documentation/licence.en.txt. */ #ifndef DUMPTOTIFF_H #define DUMPTOTIFF_H #include "glDump.h" /** * visu_dump_tiff_getStatic: * * This routine returns the dump object in TIFF format. * * Returns: a newly created dump object to create TIFF files. */ const VisuDump* visu_dump_tiff_getStatic(); #endif v_sim-3.8.0/src/dumpModules/dumpToXyz.c000066400000000000000000000170401370110300500200430ustar00rootroot00000000000000/* EXTRAITS DE LA LICENCE Copyright CEA, contributeurs : Luc BILLARD et Damien CALISTE, laboratoire L_Sim, (2001-2005) Adresse mèl : BILLARD, non joignable par mèl ; CALISTE, damien P caliste AT cea P fr. Ce logiciel est un programme informatique servant à visualiser des structures atomiques dans un rendu pseudo-3D. Ce logiciel est régi par la licence CeCILL soumise au droit français et respectant les principes de diffusion des logiciels libres. Vous pouvez utiliser, modifier et/ou redistribuer ce programme sous les conditions de la licence CeCILL telle que diffusée par le CEA, le CNRS et l'INRIA sur le site "http://www.cecill.info". Le fait que vous puissiez accéder à cet en-tête signifie que vous avez pris connaissance de la licence CeCILL, et que vous en avez accepté les termes (cf. le fichier Documentation/licence.fr.txt fourni avec ce logiciel). */ /* LICENCE SUM UP Copyright CEA, contributors : Luc BILLARD et Damien CALISTE, laboratoire L_Sim, (2001-2005) E-mail address: BILLARD, not reachable any more ; CALISTE, damien P caliste AT cea P fr. This software is a computer program whose purpose is to visualize atomic configurations in 3D. This software is governed by the CeCILL license under French law and abiding by the rules of distribution of free software. You can use, modify and/ or redistribute the software under the terms of the CeCILL license as circulated by CEA, CNRS and INRIA at the following URL "http://www.cecill.info". The fact that you are presently reading this means that you have had knowledge of the CeCILL license and that you accept its terms. You can find a copy of this licence shipped with this software at Documentation/licence.en.txt. */ #include "dumpToXyz.h" #include #include #include #include #include #include /** * SECTION:dumpToXyz * @short_description: add an export capability of current positions. * * This provides a write routine to export V_Sim current * coordinates. It has several options to output or not hiddden nodes * or replicated nodes. */ static gboolean writeDataInXyz(VisuDumpData *format, const char* filename, VisuData *dataObj, GError **error); static VisuDumpData *xyz; const VisuDumpData* visu_dump_xyz_getStatic() { const gchar *typeXYZ[] = {"*.xyz", (char*)0}; #define descrXYZ _("Xyz file (current positions)") if (xyz) return xyz; xyz = visu_dump_data_new(descrXYZ, typeXYZ, writeDataInXyz); tool_file_format_addPropertyBoolean(TOOL_FILE_FORMAT(xyz), "expand_box", _("Expand the bounding box"), TRUE); tool_file_format_addPropertyBoolean(TOOL_FILE_FORMAT(xyz), "type_alignment", _("Export nodes sorted by elements"), FALSE); return xyz; } static gboolean writeDataInXyz(VisuDumpData *format, const char* filename, VisuData *dataObj, GError **error) { const gchar *nom; gchar *prevFile; gchar firstLine[256]; gboolean expand, eleSort; gint nb; float xyz[3], ext[3], vertices[8][3]; VisuNodeArrayIter iter; GString *output; VisuBoxBoundaries bc; gchar *bcStr[8] = {"FreeBC", "wire", "wire", "surface", "wire", "surface", "surface", "periodic"}; const gchar *nodeComment; double ene; VisuBox *boxObj; g_return_val_if_fail(error && !*error, FALSE); expand = tool_file_format_getPropertyBoolean(TOOL_FILE_FORMAT(format), "expand_box"); eleSort = tool_file_format_getPropertyBoolean(TOOL_FILE_FORMAT(format), "type_alignment"); DBG_fprintf(stderr, "Dump XYZ: begin export of current positions...\n"); output = g_string_new(""); boxObj = visu_boxed_getBox(VISU_BOXED(dataObj)); visu_node_array_iter_new(VISU_NODE_ARRAY(dataObj), &iter); /* The number of elements will be prepended later... */ /* The commentary line. */ bc = visu_box_getBoundary(boxObj); if (bc != VISU_BOX_FREE) { visu_box_getVertices(boxObj, vertices, expand); fprintf(stderr, "Dump XYZ: box is\n"); fprintf(stderr, " | v[0] %g, %g, %g\n", vertices[0][0], vertices[0][1], vertices[0][2]); fprintf(stderr, " | v[1] %g, %g, %g\n", vertices[1][0], vertices[1][1], vertices[1][2]); fprintf(stderr, " | v[2] %g, %g, %g\n", vertices[2][0], vertices[2][1], vertices[2][2]); fprintf(stderr, " | v[3] %g, %g, %g\n", vertices[3][0], vertices[3][1], vertices[3][2]); fprintf(stderr, " | v[4] %g, %g, %g\n", vertices[4][0], vertices[4][1], vertices[4][2]); vertices[1][0] -= vertices[0][0]; vertices[1][1] -= vertices[0][1]; vertices[1][2] -= vertices[0][2]; vertices[2][0] -= vertices[0][0]; vertices[2][1] -= vertices[0][1]; vertices[2][2] -= vertices[0][2]; vertices[3][0] -= vertices[0][0]; vertices[3][1] -= vertices[0][1]; vertices[3][2] -= vertices[0][2]; vertices[4][0] -= vertices[0][0]; vertices[4][1] -= vertices[0][1]; vertices[4][2] -= vertices[0][2]; if (vertices[1][1] == 0.f && vertices[1][2] == 0.f && vertices[3][0] == 0.f && vertices[3][2] == 0.f && vertices[4][0] == 0.f && vertices[4][1] == 0.f) g_string_append_printf(output, "%s %17.8g %17.8g %17.8g ", bcStr[bc], vertices[1][0], vertices[3][1], vertices[4][2]); else g_warning("Can't export box, not orthogonal."); } if (VISU_IS_DATA_LOADABLE(dataObj)) { nom = visu_data_loadable_getFilename(VISU_DATA_LOADABLE(dataObj), 0); prevFile = g_path_get_basename(nom); g_string_append_printf(output, "# V_Sim export to xyz from '%s'", prevFile); g_free(prevFile); } else { g_warning("Can't get the name of the file to export."); g_string_append_printf(output, "# V_Sim export to xyz"); } g_string_append(output, "\n"); visu_box_getVertices(boxObj, vertices, FALSE); if (expand) visu_box_getExtension(boxObj, ext); else { ext[0] = 0.; ext[1] = 0.; ext[2] = 0.; } nb = 0; for (visu_node_array_iterStartNumber(VISU_NODE_ARRAY(dataObj), &iter); iter.node && iter.element; (eleSort)?visu_node_array_iterNext(VISU_NODE_ARRAY(dataObj), &iter): visu_node_array_iterNextNodeNumber(VISU_NODE_ARRAY(dataObj), &iter)) { visu_data_getNodePosition(dataObj, iter.node, xyz); if (visu_element_getRendered(iter.element) && iter.node->rendered) { xyz[0] += ext[0] * vertices[1][0] + ext[1] * vertices[3][0] + ext[2] * vertices[4][0]; xyz[1] += ext[1] * vertices[3][1] + ext[2] * vertices[4][1]; xyz[2] += ext[2] * vertices[4][2]; nb += 1; g_string_append_printf(output, "%s %17.8g %17.8g %17.8g", iter.element->name, xyz[0], xyz[1], xyz[2]); nodeComment = visu_data_getNodeLabelAt(dataObj, iter.node); if (nodeComment) g_string_append_printf(output, " %s", nodeComment); g_string_append(output, "\n"); } } g_string_prepend(output, "\n"); g_object_get(G_OBJECT(dataObj), "totalEnergy", &ene, NULL); if (ene != G_MAXFLOAT) { sprintf(firstLine, " %22.16f", ene / 27.21138386); g_string_prepend(output, firstLine); } switch (visu_box_getUnit(boxObj)) { case TOOL_UNITS_ANGSTROEM: sprintf(firstLine, " %d angstroem", nb); break; case TOOL_UNITS_BOHR: sprintf(firstLine, " %d atomic", nb); break; default: sprintf(firstLine, " %d", nb); break; } g_string_prepend(output, firstLine); g_file_set_contents(filename, output->str, -1, error); g_string_free(output, TRUE); return TRUE; } v_sim-3.8.0/src/dumpModules/dumpToXyz.h000066400000000000000000000040011370110300500200410ustar00rootroot00000000000000/* EXTRAITS DE LA LICENCE Copyright CEA, contributeurs : Luc BILLARD et Damien CALISTE, laboratoire L_Sim, (2001-2005) Adresse mèl : BILLARD, non joignable par mèl ; CALISTE, damien P caliste AT cea P fr. Ce logiciel est un programme informatique servant à visualiser des structures atomiques dans un rendu pseudo-3D. Ce logiciel est régi par la licence CeCILL soumise au droit français et respectant les principes de diffusion des logiciels libres. Vous pouvez utiliser, modifier et/ou redistribuer ce programme sous les conditions de la licence CeCILL telle que diffusée par le CEA, le CNRS et l'INRIA sur le site "http://www.cecill.info". Le fait que vous puissiez accéder à cet en-tête signifie que vous avez pris connaissance de la licence CeCILL, et que vous en avez accepté les termes (cf. le fichier Documentation/licence.fr.txt fourni avec ce logiciel). */ /* LICENCE SUM UP Copyright CEA, contributors : Luc BILLARD et Damien CALISTE, laboratoire L_Sim, (2001-2005) E-mail address: BILLARD, not reachable any more ; CALISTE, damien P caliste AT cea P fr. This software is a computer program whose purpose is to visualize atomic configurations in 3D. This software is governed by the CeCILL license under French law and abiding by the rules of distribution of free software. You can use, modify and/ or redistribute the software under the terms of the CeCILL license as circulated by CEA, CNRS and INRIA at the following URL "http://www.cecill.info". The fact that you are presently reading this means that you have had knowledge of the CeCILL license and that you accept its terms. You can find a copy of this licence shipped with this software at Documentation/licence.en.txt. */ #ifndef DUMPTOXYZ_H #define DUMPTOXYZ_H #include "fileDump.h" /** * visu_dump_xyz_getStatic: * * This routine returns the dump object for XYZ format. * * Returns: (transfer none): a newly created dump object to create XYZ files. */ const VisuDumpData* visu_dump_xyz_getStatic(); #endif v_sim-3.8.0/src/dumpModules/dumpToYaml.c000066400000000000000000000230541370110300500201550ustar00rootroot00000000000000/* EXTRAITS DE LA LICENCE Copyright CEA, contributeurs : Damien CALISTE, laboratoire L_Sim, (2016) Adresse mèl : CALISTE, damien P caliste AT cea P fr. Ce logiciel est un programme informatique servant à visualiser des structures atomiques dans un rendu pseudo-3D. Ce logiciel est régi par la licence CeCILL soumise au droit français et respectant les principes de diffusion des logiciels libres. Vous pouvez utiliser, modifier et/ou redistribuer ce programme sous les conditions de la licence CeCILL telle que diffusée par le CEA, le CNRS et l'INRIA sur le site "http://www.cecill.info". Le fait que vous puissiez accéder à cet en-tête signifie que vous avez pris connaissance de la licence CeCILL, et que vous en avez accepté les termes (cf. le fichier Documentation/licence.fr.txt fourni avec ce logiciel). */ /* LICENCE SUM UP Copyright CEA, contributors : Damien CALISTE, laboratoire L_Sim, (2016) E-mail address: CALISTE, damien P caliste AT cea P fr. This software is a computer program whose purpose is to visualize atomic configurations in 3D. This software is governed by the CeCILL license under French law and abiding by the rules of distribution of free software. You can use, modify and/ or redistribute the software under the terms of the CeCILL license as circulated by CEA, CNRS and INRIA at the following URL "http://www.cecill.info". The fact that you are presently reading this means that you have had knowledge of the CeCILL license and that you accept its terms. You can find a copy of this licence shipped with this software at Documentation/licence.en.txt. */ #include "dumpToYaml.h" #include #include #include #include #include #include #include static VisuDumpData *yaml = NULL; /** * SECTION:dumpToYaml * @short_description: add an export capability of current positions. * * This provides a write routine to export V_Sim current * coordinates. It has several options to output or not hiddden nodes * or replicated nodes. */ static gboolean writeDataInYaml(VisuDumpData *format, const char* filename, VisuData *dataObj, GError **error); const VisuDumpData* visu_dump_yaml_getStatic() { const gchar *typeYAML[] = {"*.yaml", (char*)0}; #define descrYAML _("YAML file (current positions)") if (yaml) return yaml; yaml = visu_dump_data_new(descrYAML, typeYAML, writeDataInYaml); tool_file_format_addPropertyBoolean(TOOL_FILE_FORMAT(yaml), "delete_hidden_nodes", _("Don't output hidden nodes"), FALSE); tool_file_format_addPropertyBoolean(TOOL_FILE_FORMAT(yaml), "comment_hidden_nodes", _("Comment hidden nodes (if output)"), TRUE); tool_file_format_addPropertyBoolean(TOOL_FILE_FORMAT(yaml), "expand_box", _("Keep primitive box (in case of node expansion)"), FALSE); tool_file_format_addPropertyBoolean(TOOL_FILE_FORMAT(yaml), "reduced_coordinates", _("Export positions in reduced coordinates"), FALSE); tool_file_format_addPropertyBoolean(TOOL_FILE_FORMAT(yaml), "type_alignment", _("Export nodes sorted by elements"), FALSE); return yaml; } static gboolean writeDataInYaml(VisuDumpData *format, const char* filename, VisuData *dataObj, GError **error) { const gchar *nom; gchar *prevFile; char tmpChr; gboolean suppr, comment, expand, reduced, eleSort; float factor, xyz[3], ext[3], uvw[3], vertices[8][3], box[6]; double ene; VisuNodeArrayIter iter; GString *output; const gchar *nodeComment; ToolFileFormatIter it; VisuBox *boxObj; g_return_val_if_fail(error && !*error, FALSE); comment = TRUE; expand = FALSE; suppr = FALSE; reduced = FALSE; eleSort = FALSE; it.lst = (GList*)0; for (tool_file_format_iterNextProperty(TOOL_FILE_FORMAT(format), &it); it.lst; tool_file_format_iterNextProperty(TOOL_FILE_FORMAT(format), &it)) { DBG_fprintf(stderr, "Dump YAML: test property '%s'.\n", it.name); if (strcmp(it.name, "comment_hidden_nodes") == 0) comment = g_value_get_boolean(it.val); else if (strcmp(it.name, "expand_box") == 0) expand = !g_value_get_boolean(it.val); else if (strcmp(it.name, "delete_hidden_nodes") == 0) suppr = g_value_get_boolean(it.val); else if (strcmp(it.name, "reduced_coordinates") == 0) reduced = g_value_get_boolean(it.val); else if (strcmp(it.name, "type_alignment") == 0) eleSort = g_value_get_boolean(it.val); } DBG_fprintf(stderr, "Dump YAML: begin export of current positions...\n"); DBG_fprintf(stderr, " | comment %d ;\n", comment); DBG_fprintf(stderr, " | expand %d ;\n", expand); DBG_fprintf(stderr, " | suppr %d ;\n", suppr); DBG_fprintf(stderr, " | reduced %d ;\n", reduced); DBG_fprintf(stderr, " | eleSort %d ;\n", eleSort); output = g_string_new("---\n"); boxObj = visu_boxed_getBox(VISU_BOXED(dataObj)); visu_box_getVertices(boxObj, vertices, expand); box[0] = vertices[1][0] - vertices[0][0]; box[1] = vertices[3][0] - vertices[0][0]; box[2] = vertices[3][1] - vertices[0][1]; box[3] = vertices[4][0] - vertices[0][0]; box[4] = vertices[4][1] - vertices[0][1]; box[5] = vertices[4][2] - vertices[0][2]; if (ABS(box[1]) > 1e-8 || ABS(box[3]) > 1e-8 || ABS(box[4]) > 1e-8) { g_set_error_literal(error, VISU_DUMP_ERROR, DUMP_ERROR_ENCODE, "YAML format supports only orthorhombic cell."); return FALSE; } if (reduced) g_string_append(output, " units: reduced\n"); else if (visu_box_getUnit(boxObj) == TOOL_UNITS_ANGSTROEM) g_string_append(output, " units: angstroem\n"); switch (visu_box_getBoundary(boxObj)) { case VISU_BOX_PERIODIC: if (reduced && visu_box_getUnit(boxObj) != TOOL_UNITS_BOHR) { factor = tool_physic_getUnitConversionFactor(visu_box_getUnit(boxObj), TOOL_UNITS_BOHR); g_string_append_printf(output, " cell: [%17.8g, %17.8g, %17.8g]\n", box[0] * factor, box[2] * factor, box[5] * factor); } else g_string_append_printf(output, " cell: [%17.8g, %17.8g, %17.8g]\n", box[0], box[2], box[5]); break; case VISU_BOX_SURFACE_ZX: if (reduced && visu_box_getUnit(boxObj) != TOOL_UNITS_BOHR) { factor = tool_physic_getUnitConversionFactor(visu_box_getUnit(boxObj), TOOL_UNITS_BOHR); g_string_append_printf(output, " cell: [%17.8g, .inf, %17.8g]\n", box[0] * factor, box[5] * factor); } else g_string_append_printf(output, " cell: [%17.8g, .inf, %17.8g]\n", box[0], box[5]); break; case VISU_BOX_FREE: break; default: g_set_error_literal(error, VISU_DUMP_ERROR, DUMP_ERROR_ENCODE, "YAML format does not support the given periodicity."); return FALSE; } visu_box_getVertices(boxObj, vertices, FALSE); if (expand) visu_box_getExtension(boxObj, ext); else { ext[0] = 0.; ext[1] = 0.; ext[2] = 0.; } g_string_append(output, " positions:\n"); visu_node_array_iter_new(VISU_NODE_ARRAY(dataObj), &iter); for ((eleSort)?visu_node_array_iterStart(VISU_NODE_ARRAY(dataObj), &iter): visu_node_array_iterStartNumber(VISU_NODE_ARRAY(dataObj), &iter); iter.node && iter.element; (eleSort)?visu_node_array_iterNext(VISU_NODE_ARRAY(dataObj), &iter): visu_node_array_iterNextNodeNumber(VISU_NODE_ARRAY(dataObj), &iter)) { if ((visu_element_getRendered(iter.element) && iter.node->rendered) || !comment) tmpChr = '-'; else tmpChr = '#'; visu_data_getNodePosition(dataObj, iter.node, xyz); if ((visu_element_getRendered(iter.element) && iter.node->rendered) || !suppr) { xyz[0] += ext[0] * vertices[1][0] + ext[1] * vertices[3][0] + ext[2] * vertices[4][0]; xyz[1] += ext[1] * vertices[3][1] + ext[2] * vertices[4][1]; xyz[2] += ext[2] * vertices[4][2]; if (reduced) { visu_box_convertXYZtoBoxCoordinates(boxObj, uvw, xyz); uvw[0] /= (1.f + 2.f * ext[0]); uvw[1] /= (1.f + 2.f * ext[1]); uvw[2] /= (1.f + 2.f * ext[2]); } else { uvw[0] = xyz[0]; uvw[1] = xyz[1]; uvw[2] = xyz[2]; } nodeComment = visu_data_getNodeLabelAt(dataObj, iter.node); if (nodeComment) g_string_append_printf(output, " %c {%s: [%17.8g, %17.8g, %17.8g], label: %s}\n", tmpChr, visu_element_getName(iter.element), uvw[0], uvw[1], uvw[2], nodeComment); else g_string_append_printf(output, " %c %s: [%17.8g, %17.8g, %17.8g]\n", tmpChr, visu_element_getName(iter.element), uvw[0], uvw[1], uvw[2]); } } g_string_append(output, " properties:\n"); g_string_append(output, " info: exported from V_Sim\n"); if (VISU_IS_DATA_LOADABLE(dataObj)) { nom = visu_data_loadable_getFilename(VISU_DATA_LOADABLE(dataObj), 0); prevFile = g_path_get_basename(nom); g_string_append_printf(output, " source: %s\n", prevFile); g_free(prevFile); } g_object_get(G_OBJECT(dataObj), "totalEnergy", &ene, NULL); if (ene != G_MAXFLOAT) g_string_append_printf(output, " totalEnergy (eV): %22.16f\n", ene); g_file_set_contents(filename, output->str, -1, error); g_string_free(output, TRUE); if (*error) return FALSE; else return TRUE; } v_sim-3.8.0/src/dumpModules/dumpToYaml.h000066400000000000000000000036541370110300500201660ustar00rootroot00000000000000/* EXTRAITS DE LA LICENCE Copyright CEA, contributeurs : Damien CALISTE, laboratoire L_Sim, (2016) Adresse mèl : CALISTE, damien P caliste AT cea P fr. Ce logiciel est un programme informatique servant à visualiser des structures atomiques dans un rendu pseudo-3D. Ce logiciel est régi par la licence CeCILL soumise au droit français et respectant les principes de diffusion des logiciels libres. Vous pouvez utiliser, modifier et/ou redistribuer ce programme sous les conditions de la licence CeCILL telle que diffusée par le CEA, le CNRS et l'INRIA sur le site "http://www.cecill.info". Le fait que vous puissiez accéder à cet en-tête signifie que vous avez pris connaissance de la licence CeCILL, et que vous en avez accepté les termes (cf. le fichier Documentation/licence.fr.txt fourni avec ce logiciel). */ /* LICENCE SUM UP Copyright CEA, contributors : Damien CALISTE, laboratoire L_Sim, (2016) E-mail address: CALISTE, damien P caliste AT cea P fr. This software is a computer program whose purpose is to visualize atomic configurations in 3D. This software is governed by the CeCILL license under French law and abiding by the rules of distribution of free software. You can use, modify and/ or redistribute the software under the terms of the CeCILL license as circulated by CEA, CNRS and INRIA at the following URL "http://www.cecill.info". The fact that you are presently reading this means that you have had knowledge of the CeCILL license and that you accept its terms. You can find a copy of this licence shipped with this software at Documentation/licence.en.txt. */ #ifndef DUMPTOYAML_H #define DUMPTOYAML_H #include "fileDump.h" /** * visu_dump_yaml_getStatic: * * This routine is used to get the static #VisuDump object for YAML exportation. * * Returns: (transfer none): the static dump object to create YAML files. */ const VisuDumpData* visu_dump_yaml_getStatic(); #endif v_sim-3.8.0/src/dumpModules/externalDumpModules.h000066400000000000000000000044731370110300500220740ustar00rootroot00000000000000/* EXTRAITS DE LA LICENCE Copyright CEA, contributeurs : Luc BILLARD et Damien CALISTE, laboratoire L_Sim, (2001-2005) Adresse mèl : BILLARD, non joignable par mèl ; CALISTE, damien P caliste AT cea P fr. Ce logiciel est un programme informatique servant à visualiser des structures atomiques dans un rendu pseudo-3D. Ce logiciel est régi par la licence CeCILL soumise au droit français et respectant les principes de diffusion des logiciels libres. Vous pouvez utiliser, modifier et/ou redistribuer ce programme sous les conditions de la licence CeCILL telle que diffusée par le CEA, le CNRS et l'INRIA sur le site "http://www.cecill.info". Le fait que vous puissiez accéder à cet en-tête signifie que vous avez pris connaissance de la licence CeCILL, et que vous en avez accepté les termes (cf. le fichier Documentation/licence.fr.txt fourni avec ce logiciel). */ /* LICENCE SUM UP Copyright CEA, contributors : Luc BILLARD et Damien CALISTE, laboratoire L_Sim, (2001-2005) E-mail address: BILLARD, not reachable any more ; CALISTE, damien P caliste AT cea P fr. This software is a computer program whose purpose is to visualize atomic configurations in 3D. This software is governed by the CeCILL license under French law and abiding by the rules of distribution of free software. You can use, modify and/ or redistribute the software under the terms of the CeCILL license as circulated by CEA, CNRS and INRIA at the following URL "http://www.cecill.info". The fact that you are presently reading this means that you have had knowledge of the CeCILL license and that you accept its terms. You can find a copy of this licence shipped with this software at Documentation/licence.en.txt. */ #ifndef EXTERNALDUMPMODULES_H #define EXTERNALDUMPMODULES_H #include "../visu_dump.h" #include "dumpToTiff.h" #include "dumpToGif.h" #include "dumpToPsAndPdf.h" #include "dumpThroughGdkPixbuf.h" #ifdef HAVE_CAIRO #include "dumpToSVG.h" #endif static VisuDumpInitFunc listInitDumpModuleFunc[] = { visu_dump_jpeg_getStatic, visu_dump_png_getStatic, visu_dump_tiff_getStatic, #ifdef HAVE_CAIRO visu_dump_cairo_svg_getStatic, visu_dump_cairo_pdf_getStatic, #endif visu_dump_bitmap_pdf_getStatic, visu_dump_bitmap_ps_getStatic, (VisuDumpInitFunc)dumpToGif_init, (VisuDumpInitFunc)0}; #endif v_sim-3.8.0/src/dumpModules/fileDump.c000066400000000000000000000074551370110300500176360ustar00rootroot00000000000000/* EXTRAITS DE LA LICENCE Copyright CEA, contributeurs : Damien CALISTE, laboratoire L_Sim, (2016) Adresse mèl : CALISTE, damien P caliste AT cea P fr. Ce logiciel est un programme informatique servant à visualiser des structures atomiques dans un rendu pseudo-3D. Ce logiciel est régi par la licence CeCILL soumise au droit français et respectant les principes de diffusion des logiciels libres. Vous pouvez utiliser, modifier et/ou redistribuer ce programme sous les conditions de la licence CeCILL telle que diffusée par le CEA, le CNRS et l'INRIA sur le site "http://www.cecill.info". Le fait que vous puissiez accéder à cet en-tête signifie que vous avez pris connaissance de la licence CeCILL, et que vous en avez accepté les termes (cf. le fichier Documentation/licence.fr.txt fourni avec ce logiciel). */ /* LICENCE SUM UP Copyright CEA, contributors : Damien CALISTE, laboratoire L_Sim, (2016) E-mail address: CALISTE, damien P caliste AT cea P fr. This software is a computer program whose purpose is to visualize atomic configurations in 3D. This software is governed by the CeCILL license under French law and abiding by the rules of distribution of free software. You can use, modify and/ or redistribute the software under the terms of the CeCILL license as circulated by CEA, CNRS and INRIA at the following URL "http://www.cecill.info". The fact that you are presently reading this means that you have had knowledge of the CeCILL license and that you accept its terms. You can find a copy of this licence shipped with this software at Documentation/licence.en.txt. */ #include "fileDump.h" /** * SECTION:fileDump * @short_description: A generic class defining interface to export * #VisuData into text formats. * * Instance of this class can be used to export any #VisuData * into other text formats. */ struct _VisuDumpDataPrivate { VisuDumpDataWriteFunc writeFunc; }; /* Local callbacks */ G_DEFINE_TYPE_WITH_CODE(VisuDumpData, visu_dump_data, VISU_TYPE_DUMP, G_ADD_PRIVATE(VisuDumpData)) static void visu_dump_data_class_init(VisuDumpDataClass *klass _U_) { DBG_fprintf(stderr, "Visu Node Scene: creating the class of the object.\n"); /* DBG_fprintf(stderr, " - adding new signals ;\n"); */ } static void visu_dump_data_init(VisuDumpData *self) { self->priv = visu_dump_data_get_instance_private(self); self->priv->writeFunc = NULL; } /** * visu_dump_data_new: * @descr: a description. * @patterns: (array zero-terminated=1): a list of file patterns. * @method: (scope call): the write method. * * Creates a new #VisuDumpData object. * * Since: 3.8 * * Returns: (transfer full): a newly created #VisuDumpData object. **/ VisuDumpData* visu_dump_data_new(const gchar* descr, const gchar** patterns, VisuDumpDataWriteFunc method) { VisuDumpData *dump; dump = VISU_DUMP_DATA(g_object_new(VISU_TYPE_DUMP_DATA, "name", descr, "ignore-type", FALSE, NULL)); tool_file_format_addPatterns(TOOL_FILE_FORMAT(dump), patterns); dump->priv->writeFunc = method; return dump; } /** * visu_dump_data_write: * @dump: a #VisuDump object ; * @fileName: (type filename): a string that defined the file to write to ; * @dataObj: the #VisuData to be exported ; * @error: a location to store some error (not NULL) ; * * Use the write function of @dump to export the current @dataObj to * file @fileName. * * Since: 3.6 * * Returns: TRUE if dump succeed. */ gboolean visu_dump_data_write(VisuDumpData *dump, const char* fileName, VisuData *dataObj, GError **error) { g_return_val_if_fail(VISU_IS_DUMP_DATA(dump) && dump->priv->writeFunc, FALSE); return dump->priv->writeFunc(dump, fileName, dataObj, error); } v_sim-3.8.0/src/dumpModules/fileDump.h000066400000000000000000000112751370110300500176360ustar00rootroot00000000000000/* EXTRAITS DE LA LICENCE Copyright CEA, contributeurs : Damien CALISTE, laboratoire L_Sim, (2016) Adresse mèl : CALISTE, damien P caliste AT cea P fr. Ce logiciel est un programme informatique servant à visualiser des structures atomiques dans un rendu pseudo-3D. Ce logiciel est régi par la licence CeCILL soumise au droit français et respectant les principes de diffusion des logiciels libres. Vous pouvez utiliser, modifier et/ou redistribuer ce programme sous les conditions de la licence CeCILL telle que diffusée par le CEA, le CNRS et l'INRIA sur le site "http://www.cecill.info". Le fait que vous puissiez accéder à cet en-tête signifie que vous avez pris connaissance de la licence CeCILL, et que vous en avez accepté les termes (cf. le fichier Documentation/licence.fr.txt fourni avec ce logiciel). */ /* LICENCE SUM UP Copyright CEA, contributors : Damien CALISTE, laboratoire L_Sim, (2016) E-mail address: CALISTE, damien P caliste AT cea P fr. This software is a computer program whose purpose is to visualize atomic configurations in 3D. This software is governed by the CeCILL license under French law and abiding by the rules of distribution of free software. You can use, modify and/ or redistribute the software under the terms of the CeCILL license as circulated by CEA, CNRS and INRIA at the following URL "http://www.cecill.info". The fact that you are presently reading this means that you have had knowledge of the CeCILL license and that you accept its terms. You can find a copy of this licence shipped with this software at Documentation/licence.en.txt. */ #ifndef VISU_DUMP_DATA_H #define VISU_DUMP_DATA_H #include #include #include #include G_BEGIN_DECLS /***************/ /* Public part */ /***************/ /** * VISU_TYPE_DUMP_DATA: * * return the type of #VisuDumpData. */ #define VISU_TYPE_DUMP_DATA (visu_dump_data_get_type ()) /** * VISU_DUMP_DATA: * @obj: a #GObject to cast. * * Cast the given @obj into #VisuDumpData type. */ #define VISU_DUMP_DATA(obj) (G_TYPE_CHECK_INSTANCE_CAST(obj, VISU_TYPE_DUMP_DATA, VisuDumpData)) /** * VISU_DUMP_DATA_CLASS: * @klass: a #GObjectClass to cast. * * Cast the given @klass into #VisuDumpDataClass. */ #define VISU_DUMP_DATA_CLASS(klass) (G_TYPE_CHECK_CLASS_CAST(klass, VISU_TYPE_DUMP_DATA, VisuDumpDataClass)) /** * VISU_IS_DUMP_DATA: * @obj: a #GObject to test. * * Test if the given @ogj is of the type of #VisuDumpData object. */ #define VISU_IS_DUMP_DATA(obj) (G_TYPE_CHECK_INSTANCE_TYPE(obj, VISU_TYPE_DUMP_DATA)) /** * VISU_IS_DUMP_DATA_CLASS: * @klass: a #GObjectClass to test. * * Test if the given @klass is of the type of #VisuDumpDataClass class. */ #define VISU_IS_DUMP_DATA_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE(klass, VISU_TYPE_DUMP_DATA)) /** * VISU_DUMP_DATA_GET_CLASS: * @obj: a #GObject to get the class of. * * It returns the class of the given @obj. */ #define VISU_DUMP_DATA_GET_CLASS(obj) (G_TYPE_INSTANCE_GET_CLASS(obj, VISU_TYPE_DUMP_DATA, VisuDumpDataClass)) /** * VisuDumpDataPrivate: * * Private data for #VisuDumpData objects. */ typedef struct _VisuDumpDataPrivate VisuDumpDataPrivate; /** * VisuDumpData: * * Common name to refer to a #_VisuDumpData. */ typedef struct _VisuDumpData VisuDumpData; struct _VisuDumpData { VisuDump parent; VisuDumpDataPrivate *priv; }; /** * VisuDumpDataClass: * @parent: private. * * Common name to refer to a #_VisuDumpDataClass. */ typedef struct _VisuDumpDataClass VisuDumpDataClass; struct _VisuDumpDataClass { VisuDumpClass parent; }; /** * visu_dump_data_get_type: * * This method returns the type of #VisuDumpData, use * VISU_TYPE_DUMP_DATA instead. * * Since: 3.7 * * Returns: the type of #VisuDumpData. */ GType visu_dump_data_get_type(void); /** * VisuDumpDataWriteFunc: * @format: a #VisuDumpData object ; * @fileName: a string that defined the file to write to ; * @dataObj: the #VisuData to be exported ; * @error: (allow-none): a location to store some error (not NULL) ; * * This is a prototype of a method implemented by a dumping extension that is called * when the current rendering must be dumped to a file. * * Returns: TRUE if everything went right. */ typedef gboolean (*VisuDumpDataWriteFunc) (VisuDumpData *format, const char* fileName, VisuData *dataObj, GError **error); VisuDumpData* visu_dump_data_new(const gchar* descr, const gchar** patterns, VisuDumpDataWriteFunc method); gboolean visu_dump_data_write(VisuDumpData *dump, const char* fileName, VisuData *dataObj, GError **error); G_END_DECLS #endif v_sim-3.8.0/src/dumpModules/glDump.c000066400000000000000000000115021370110300500173050ustar00rootroot00000000000000/* EXTRAITS DE LA LICENCE Copyright CEA, contributeurs : Damien CALISTE, laboratoire L_Sim, (2016) Adresse mèl : CALISTE, damien P caliste AT cea P fr. Ce logiciel est un programme informatique servant à visualiser des structures atomiques dans un rendu pseudo-3D. Ce logiciel est régi par la licence CeCILL soumise au droit français et respectant les principes de diffusion des logiciels libres. Vous pouvez utiliser, modifier et/ou redistribuer ce programme sous les conditions de la licence CeCILL telle que diffusée par le CEA, le CNRS et l'INRIA sur le site "http://www.cecill.info". Le fait que vous puissiez accéder à cet en-tête signifie que vous avez pris connaissance de la licence CeCILL, et que vous en avez accepté les termes (cf. le fichier Documentation/licence.fr.txt fourni avec ce logiciel). */ /* LICENCE SUM UP Copyright CEA, contributors : Damien CALISTE, laboratoire L_Sim, (2016) E-mail address: CALISTE, damien P caliste AT cea P fr. This software is a computer program whose purpose is to visualize atomic configurations in 3D. This software is governed by the CeCILL license under French law and abiding by the rules of distribution of free software. You can use, modify and/ or redistribute the software under the terms of the CeCILL license as circulated by CEA, CNRS and INRIA at the following URL "http://www.cecill.info". The fact that you are presently reading this means that you have had knowledge of the CeCILL license and that you accept its terms. You can find a copy of this licence shipped with this software at Documentation/licence.en.txt. */ #include "glDump.h" /** * SECTION:glDump * @short_description: A generic class defining interface to export * #VisuGlNodeScene into image formats. * * Instance of this class can be used to export any #VisuGlNodeScene * into image formats. */ struct _VisuDumpScenePrivate { VisuDumpSceneWriteFunc writeFunc; gboolean hasAlpha; }; /* Local callbacks */ G_DEFINE_TYPE_WITH_CODE(VisuDumpScene, visu_dump_scene, VISU_TYPE_DUMP, G_ADD_PRIVATE(VisuDumpScene)) static void visu_dump_scene_class_init(VisuDumpSceneClass *klass _U_) { DBG_fprintf(stderr, "Visu Node Scene: creating the class of the object.\n"); /* DBG_fprintf(stderr, " - adding new signals ;\n"); */ } static void visu_dump_scene_init(VisuDumpScene *self) { self->priv = visu_dump_scene_get_instance_private(self); self->priv->writeFunc = NULL; self->priv->hasAlpha = FALSE; } /** * visu_dump_scene_new: * @descr: a description. * @patterns: (array zero-terminated=1): a list of file patterns. * @method: (scope call): the write method. * @hasAlpha: a boolean. * * Creates a new #VisuDumpScene object. * * Since: 3.8 * * Returns: (transfer full): a newly created #VisuDumpScene object. **/ VisuDumpScene* visu_dump_scene_new(const gchar* descr, const gchar** patterns, VisuDumpSceneWriteFunc method, gboolean hasAlpha) { VisuDumpScene *dump; dump = VISU_DUMP_SCENE(g_object_new(VISU_TYPE_DUMP_SCENE, "name", descr, "ignore-type", FALSE, NULL)); tool_file_format_addPatterns(TOOL_FILE_FORMAT(dump), patterns); dump->priv->writeFunc = method; dump->priv->hasAlpha = hasAlpha; return dump; } /** * visu_dump_scene_getAlphaStatus: * @dump: a #VisuDump method. * * Retrieve if @dump use alpha channel or not. * * Returns: TRUE if @dump has an alpha channel. **/ gboolean visu_dump_scene_getAlphaStatus(VisuDumpScene *dump) { g_return_val_if_fail(VISU_IS_DUMP_SCENE(dump), FALSE); return dump->priv->hasAlpha; } /** * visu_dump_scene_write: * @dump: a #VisuDump object ; * @fileName: (type filename): a string that defined the file to write * to ; * @scene: the #VisuGlNodeScene to be exported. * @width: an integer ; * @height: an integer ; * @functionWait: (allow-none) (closure data) (scope call): a method * to call periodically during the dump ; * @data: (closure): some pointer on object to be passed to the wait * function. * @error: a location to store some error (not NULL) ; * * Use the write function of @dump to export the @scene to file @fileName. * * Since: 3.6 * * Returns: TRUE if dump succeed. */ gboolean visu_dump_scene_write(VisuDumpScene *dump, const char* fileName, VisuGlNodeScene *scene, guint width, guint height, ToolVoidDataFunc functionWait, gpointer data, GError **error) { gboolean res; g_return_val_if_fail(VISU_IS_DUMP_SCENE(dump) && dump->priv->writeFunc, FALSE); visu_gl_addHint(VISU_GL(scene), VISU_GL_OFFSCREEN); res = dump->priv->writeFunc(TOOL_FILE_FORMAT(dump), fileName, scene, width, height, error, functionWait, data); visu_gl_addHint(VISU_GL(scene), 0); return res; } v_sim-3.8.0/src/dumpModules/glDump.h000066400000000000000000000125201370110300500173130ustar00rootroot00000000000000/* EXTRAITS DE LA LICENCE Copyright CEA, contributeurs : Damien CALISTE, laboratoire L_Sim, (2016) Adresse mèl : CALISTE, damien P caliste AT cea P fr. Ce logiciel est un programme informatique servant à visualiser des structures atomiques dans un rendu pseudo-3D. Ce logiciel est régi par la licence CeCILL soumise au droit français et respectant les principes de diffusion des logiciels libres. Vous pouvez utiliser, modifier et/ou redistribuer ce programme sous les conditions de la licence CeCILL telle que diffusée par le CEA, le CNRS et l'INRIA sur le site "http://www.cecill.info". Le fait que vous puissiez accéder à cet en-tête signifie que vous avez pris connaissance de la licence CeCILL, et que vous en avez accepté les termes (cf. le fichier Documentation/licence.fr.txt fourni avec ce logiciel). */ /* LICENCE SUM UP Copyright CEA, contributors : Damien CALISTE, laboratoire L_Sim, (2016) E-mail address: CALISTE, damien P caliste AT cea P fr. This software is a computer program whose purpose is to visualize atomic configurations in 3D. This software is governed by the CeCILL license under French law and abiding by the rules of distribution of free software. You can use, modify and/ or redistribute the software under the terms of the CeCILL license as circulated by CEA, CNRS and INRIA at the following URL "http://www.cecill.info". The fact that you are presently reading this means that you have had knowledge of the CeCILL license and that you accept its terms. You can find a copy of this licence shipped with this software at Documentation/licence.en.txt. */ #ifndef VISU_DUMP_SCENE_H #define VISU_DUMP_SCENE_H #include #include #include #include G_BEGIN_DECLS /***************/ /* Public part */ /***************/ /** * VisuDumpSceneWriteFunc: * @format: a #ToolFileFormat object, corresponding to the write method ; * @fileName: a string that defined the file to write to ; * @scene: the #VisuGlNodeScene to be exported ; * @width: the desired width. * @height: the desired height. * @error: (allow-none): a location to store some error (not NULL) ; * @functionWait: (allow-none) (scope call): a method to call * periodically during the dump ; * @data: (closure): some pointer on object to be passed to the wait function. * * This is a prototype of a method implemented by a dumping extension that is called * when the current rendering must be dumped to a file. * * Returns: TRUE if everything went right. */ typedef gboolean (*VisuDumpSceneWriteFunc) (ToolFileFormat *format, const char* fileName, VisuGlNodeScene *scene, guint width, guint height, GError **error, ToolVoidDataFunc functionWait, gpointer data); /** * VISU_TYPE_DUMP_SCENE: * * return the type of #VisuDumpScene. */ #define VISU_TYPE_DUMP_SCENE (visu_dump_scene_get_type ()) /** * VISU_DUMP_SCENE: * @obj: a #GObject to cast. * * Cast the given @obj into #VisuDumpScene type. */ #define VISU_DUMP_SCENE(obj) (G_TYPE_CHECK_INSTANCE_CAST(obj, VISU_TYPE_DUMP_SCENE, VisuDumpScene)) /** * VISU_DUMP_SCENE_CLASS: * @klass: a #GObjectClass to cast. * * Cast the given @klass into #VisuDumpSceneClass. */ #define VISU_DUMP_SCENE_CLASS(klass) (G_TYPE_CHECK_CLASS_CAST(klass, VISU_TYPE_DUMP_SCENE, VisuDumpSceneClass)) /** * VISU_IS_DUMP_SCENE: * @obj: a #GObject to test. * * Test if the given @ogj is of the type of #VisuDumpScene object. */ #define VISU_IS_DUMP_SCENE(obj) (G_TYPE_CHECK_INSTANCE_TYPE(obj, VISU_TYPE_DUMP_SCENE)) /** * VISU_IS_DUMP_SCENE_CLASS: * @klass: a #GObjectClass to test. * * Test if the given @klass is of the type of #VisuDumpSceneClass class. */ #define VISU_IS_DUMP_SCENE_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE(klass, VISU_TYPE_DUMP_SCENE)) /** * VISU_DUMP_SCENE_GET_CLASS: * @obj: a #GObject to get the class of. * * It returns the class of the given @obj. */ #define VISU_DUMP_SCENE_GET_CLASS(obj) (G_TYPE_INSTANCE_GET_CLASS(obj, VISU_TYPE_DUMP_SCENE, VisuDumpSceneClass)) /** * VisuDumpScenePrivate: * * Private data for #VisuDumpScene objects. */ typedef struct _VisuDumpScenePrivate VisuDumpScenePrivate; /** * VisuDumpScene: * * Common name to refer to a #_VisuDumpScene. */ typedef struct _VisuDumpScene VisuDumpScene; struct _VisuDumpScene { VisuDump parent; VisuDumpScenePrivate *priv; }; /** * VisuDumpSceneClass: * @parent: private. * * Common name to refer to a #_VisuDumpSceneClass. */ typedef struct _VisuDumpSceneClass VisuDumpSceneClass; struct _VisuDumpSceneClass { VisuDumpClass parent; }; /** * visu_dump_scene_get_type: * * This method returns the type of #VisuDumpScene, use * VISU_TYPE_DUMP_SCENE instead. * * Since: 3.7 * * Returns: the type of #VisuDumpScene. */ GType visu_dump_scene_get_type(void); VisuDumpScene* visu_dump_scene_new(const gchar* descr, const gchar** patterns, VisuDumpSceneWriteFunc method, gboolean hasAlpha); gboolean visu_dump_scene_getAlphaStatus(VisuDumpScene *dump); gboolean visu_dump_scene_write(VisuDumpScene *dump, const char* fileName, VisuGlNodeScene *scene, guint width, guint height, ToolVoidDataFunc functionWait, gpointer data, GError **error); G_END_DECLS #endif v_sim-3.8.0/src/extensions/000077500000000000000000000000001370110300500156135ustar00rootroot00000000000000v_sim-3.8.0/src/extensions/axes.c000066400000000000000000001546631370110300500167360ustar00rootroot00000000000000/* EXTRAITS DE LA LICENCE Copyright CEA, contributeurs : Luc BILLARD et Damien CALISTE, laboratoire L_Sim, (2001-2005) Adresse mèl : BILLARD, non joignable par mèl ; CALISTE, damien P caliste AT cea P fr. Ce logiciel est un programme informatique servant à visualiser des structures atomiques dans un rendu pseudo-3D. Ce logiciel est régi par la licence CeCILL soumise au droit français et respectant les principes de diffusion des logiciels libres. Vous pouvez utiliser, modifier et/ou redistribuer ce programme sous les conditions de la licence CeCILL telle que diffusée par le CEA, le CNRS et l'INRIA sur le site "http://www.cecill.info". Le fait que vous puissiez accéder à cet en-tête signifie que vous avez pris connaissance de la licence CeCILL, et que vous en avez accepté les termes (cf. le fichier Documentation/licence.fr.txt fourni avec ce logiciel). */ /* LICENCE SUM UP Copyright CEA, contributors : Luc BILLARD et Damien CALISTE, laboratoire L_Sim, (2001-2005) E-mail address: BILLARD, not reachable any more ; CALISTE, damien P caliste AT cea P fr. This software is a computer program whose purpose is to visualize atomic configurations in 3D. This software is governed by the CeCILL license under French law and abiding by the rules of distribution of free software. You can use, modify and/ or redistribute the software under the terms of the CeCILL license as circulated by CEA, CNRS and INRIA at the following URL "http://www.cecill.info". The fact that you are presently reading this means that you have had knowledge of the CeCILL license and that you accept its terms. You can find a copy of this licence shipped with this software at Documentation/licence.en.txt. */ #include "axes.h" #include #include #include #include #include #include #include #include #include #include #undef near #undef far /** * SECTION:axes * @short_description: Defines methods to draw axes. * * The axes are the X, Y and Z lines drawn on the bottom right of the * screen defining a given orthogonal basis set in which the box is * projected. * The axis may be different, depending on the rendering method * currently used. For instance, when the spin is used, a projection * of the colour scheme is added to the simple lines of the basis * set. Besides that, axes are defined by their width (see * visu_gl_ext_lined_setWidth()) and their colour (see * visu_gl_ext_lined_setRGBA()). */ /* Parameters & resources*/ /* This is a boolean to control is the axes is render or not. */ #define FLAG_RESOURCE_AXES_USED "axes_are_on" #define DESC_RESOURCE_AXES_USED "Control if the axes are drawn ; boolean (0 or 1)" static gboolean RESOURCE_AXES_USED_DEFAULT = FALSE; /* A resource to control the color used to render the lines of the axes. */ #define FLAG_RESOURCE_AXES_COLOR "axes_color" #define DESC_RESOURCE_AXES_COLOR "Define the color of the axes ; three floating point values (0. <= v <= 1.)" static float rgbDefault[4] = {1.0, 0.5, 0.1, 1.}; /* A resource to control the width to render the lines of the axes. */ #define FLAG_RESOURCE_AXES_LINE "axes_line_width" #define DESC_RESOURCE_AXES_LINE "Define the width of the lines of the axes ; one floating point values (1. <= v <= 10.)" static float LINE_WIDTH_DEFAULT = 1.f; /* A resource to control the stipple to render the lines of the axes. */ #define FLAG_RESOURCE_AXES_STIPPLE "axes_line_stipple" #define DESC_RESOURCE_AXES_STIPPLE "Dot scheme detail for the lines of the axes ; 0 < integer < 2^16" static guint16 LINE_STIPPLE_DEFAULT = 65535; /* A resource to control the position to render the axes. */ #define FLAG_RESOURCE_AXES_POSITION "axes_position" #define DESC_RESOURCE_AXES_POSITION "Position of the representation of the axes ; two floating point values (0. <= v <= 1.)" static float POSITION_DEFAULT[2] = {1.f, 1.f}; #define FLAG_RESOURCE_AXES_LABEL_X "axes_label_x" #define FLAG_RESOURCE_AXES_LABEL_Y "axes_label_y" #define FLAG_RESOURCE_AXES_LABEL_Z "axes_label_z" #define DESC_RESOURCE_AXES_LABEL "Label to be drawn beside each axis ; string" static gchar *LABEL_DEFAULT[3] = {NULL, NULL, NULL}; #define FLAG_RESOURCE_AXES_FACTOR "axes_size" #define DESC_RESOURCE_AXES_FACTOR "Portion of the screen used to draw the axis ; one floating point value (0. <= v <= 1.)" static float SIZE_DEFAULT = .16f; /* Export function that is called by visu_module to write the values of resources to a file. */ static void exportResources(GString *data, VisuData *dataObj); struct _VisuGlExtAxesPrivate { gboolean dispose_has_run; /* Basis definition. */ double matrix[3][3]; VisuBox *box; gulong box_signal; /* Rendenring parameters. */ float xpos, ypos; float lgFact; float rgb[4]; float lineWidth; guint16 lineStipple; gchar *lbl[3]; gboolean displayOrientation; float orientation[3]; /* Signals for the current view. */ VisuGlView *view; gulong widthHeight_signal, persp_signal, refLength_signal, color_signal; }; enum { PROP_0, XPOS_PROP, YPOS_PROP, SIZE_PROP, COLOR_PROP, WIDTH_PROP, STIPPLE_PROP, VIEW_PROP, BOX_PROP, LBLX_PROP, LBLY_PROP, LBLZ_PROP, USE_ORIENTATION_PROP, CONE_THETA_PROP, CONE_PHI_PROP, CONE_OMEGA_PROP, N_PROP }; static GParamSpec *properties[N_PROP]; static VisuGlExtAxes* defaultAxes; static void visu_gl_ext_lined_interface_init(VisuGlExtLinedInterface *iface); static void visu_gl_ext_axes_finalize(GObject* obj); static void visu_gl_ext_axes_dispose(GObject* obj); static void visu_gl_ext_axes_get_property(GObject* obj, guint property_id, GValue *value, GParamSpec *pspec); static void visu_gl_ext_axes_set_property(GObject* obj, guint property_id, const GValue *value, GParamSpec *pspec); static void visu_gl_ext_axes_rebuild(VisuGlExt *ext); static void visu_gl_ext_axes_draw(VisuGlExt *ext); static gboolean visu_gl_ext_axes_setGlView(VisuGlExt *axes, VisuGlView *view); static void _setBox(VisuGlExtAxes *axes, VisuBox *box); static gboolean _setRGB(VisuGlExtLined *axes, float rgb[4], int mask); static gboolean _setLineWidth(VisuGlExtLined *axes, float width); static gboolean _setLineStipple(VisuGlExtLined *axes, guint16 stipple); static float* _getRGB(const VisuGlExtLined *axes); static float _getLineWidth(const VisuGlExtLined *axes); static guint16 _getLineStipple(const VisuGlExtLined *axes); /* Local callbacks */ static void onAxesParametersChange(VisuGlExtAxes *axes); static void onBoxChange(VisuBox *box, float extens, gpointer data); static void onEntryUsed(VisuGlExtAxes *axes, VisuConfigFileEntry *entry, VisuConfigFile *obj); static void onEntryColor(VisuGlExtAxes *axes, VisuConfigFileEntry *entry, VisuConfigFile *obj); static void onEntryWidth(VisuGlExtAxes *axes, VisuConfigFileEntry *entry, VisuConfigFile *obj); static void onEntryStipple(VisuGlExtAxes *axes, VisuConfigFileEntry *entry, VisuConfigFile *obj); static void onEntryPosition(VisuGlExtAxes *axes, VisuConfigFileEntry *entry, VisuConfigFile *obj); static void onEntryLabel(VisuGlExtAxes *axes, VisuConfigFileEntry *entry, VisuConfigFile *obj); static void onEntryFactor(VisuGlExtAxes *axes, VisuConfigFileEntry *entry, VisuConfigFile *obj); G_DEFINE_TYPE_WITH_CODE(VisuGlExtAxes, visu_gl_ext_axes, VISU_TYPE_GL_EXT, G_ADD_PRIVATE(VisuGlExtAxes) G_IMPLEMENT_INTERFACE(VISU_TYPE_GL_EXT_LINED, visu_gl_ext_lined_interface_init)) static void visu_gl_ext_lined_interface_init(VisuGlExtLinedInterface *iface) { iface->get_width = _getLineWidth; iface->set_width = _setLineWidth; iface->get_stipple = _getLineStipple; iface->set_stipple = _setLineStipple; iface->get_rgba = _getRGB; iface->set_rgba = _setRGB; } static void visu_gl_ext_axes_class_init(VisuGlExtAxesClass *klass) { float rgColor[2] = {0.f, 1.f}; float rgWidth[2] = {0.f, 10.f}; float rgFactor[2] = {0.f, 1.f}; VisuConfigFileEntry *resourceEntry; DBG_fprintf(stderr, "Extension Axes: creating the class of the object.\n"); /* DBG_fprintf(stderr, " - adding new signals ;\n"); */ LABEL_DEFAULT[TOOL_XYZ_X] = g_strdup("x"); LABEL_DEFAULT[TOOL_XYZ_Y] = g_strdup("y"); LABEL_DEFAULT[TOOL_XYZ_Z] = g_strdup("z"); DBG_fprintf(stderr, " - adding new resources ;\n"); resourceEntry = visu_config_file_addBooleanEntry(VISU_CONFIG_FILE_RESOURCE, FLAG_RESOURCE_AXES_USED, DESC_RESOURCE_AXES_USED, &RESOURCE_AXES_USED_DEFAULT, FALSE); resourceEntry = visu_config_file_addFloatArrayEntry(VISU_CONFIG_FILE_RESOURCE, FLAG_RESOURCE_AXES_COLOR, DESC_RESOURCE_AXES_COLOR, 3, rgbDefault, rgColor, FALSE); resourceEntry = visu_config_file_addFloatArrayEntry(VISU_CONFIG_FILE_RESOURCE, FLAG_RESOURCE_AXES_LINE, DESC_RESOURCE_AXES_LINE, 1, &LINE_WIDTH_DEFAULT, rgWidth, FALSE); resourceEntry = visu_config_file_addStippleArrayEntry(VISU_CONFIG_FILE_RESOURCE, FLAG_RESOURCE_AXES_STIPPLE, DESC_RESOURCE_AXES_STIPPLE, 1, &LINE_STIPPLE_DEFAULT); visu_config_file_entry_setVersion(resourceEntry, 3.4f); resourceEntry = visu_config_file_addFloatArrayEntry(VISU_CONFIG_FILE_RESOURCE, FLAG_RESOURCE_AXES_POSITION, DESC_RESOURCE_AXES_POSITION, 2, POSITION_DEFAULT, rgColor, FALSE); visu_config_file_entry_setVersion(resourceEntry, 3.7f); resourceEntry = visu_config_file_addStringEntry(VISU_CONFIG_FILE_RESOURCE, FLAG_RESOURCE_AXES_LABEL_X, DESC_RESOURCE_AXES_LABEL, LABEL_DEFAULT + TOOL_XYZ_X); visu_config_file_entry_setVersion(resourceEntry, 3.8f); resourceEntry = visu_config_file_addStringEntry(VISU_CONFIG_FILE_RESOURCE, FLAG_RESOURCE_AXES_LABEL_Y, DESC_RESOURCE_AXES_LABEL, LABEL_DEFAULT + TOOL_XYZ_Y); visu_config_file_entry_setVersion(resourceEntry, 3.8f); resourceEntry = visu_config_file_addStringEntry(VISU_CONFIG_FILE_RESOURCE, FLAG_RESOURCE_AXES_LABEL_Z, DESC_RESOURCE_AXES_LABEL, LABEL_DEFAULT + TOOL_XYZ_Z); visu_config_file_entry_setVersion(resourceEntry, 3.8f); resourceEntry = visu_config_file_addFloatArrayEntry(VISU_CONFIG_FILE_RESOURCE, FLAG_RESOURCE_AXES_FACTOR, DESC_RESOURCE_AXES_FACTOR, 1, &SIZE_DEFAULT, rgFactor, FALSE); visu_config_file_entry_setVersion(resourceEntry, 3.8f); visu_config_file_addExportFunction(VISU_CONFIG_FILE_RESOURCE, exportResources); defaultAxes = (VisuGlExtAxes*)0; /* Connect the overloading methods. */ G_OBJECT_CLASS(klass)->dispose = visu_gl_ext_axes_dispose; G_OBJECT_CLASS(klass)->finalize = visu_gl_ext_axes_finalize; G_OBJECT_CLASS(klass)->set_property = visu_gl_ext_axes_set_property; G_OBJECT_CLASS(klass)->get_property = visu_gl_ext_axes_get_property; VISU_GL_EXT_CLASS(klass)->rebuild = visu_gl_ext_axes_rebuild; VISU_GL_EXT_CLASS(klass)->draw = visu_gl_ext_axes_draw; VISU_GL_EXT_CLASS(klass)->setGlView = visu_gl_ext_axes_setGlView; /** * VisuGlExtAxes::x-pos: * * Store the position along x of the axes. * * Since: 3.8 */ properties[XPOS_PROP] = g_param_spec_float("x-pos", "x position", "position along x axis", 0., 1., POSITION_DEFAULT[0], G_PARAM_READWRITE); g_object_class_install_property(G_OBJECT_CLASS(klass), XPOS_PROP, properties[XPOS_PROP]); /** * VisuGlExtAxes::y-pos: * * Store the position along y of the axes. * * Since: 3.8 */ properties[YPOS_PROP] = g_param_spec_float("y-pos", "y position", "position along y axis", 0., 1., POSITION_DEFAULT[1], G_PARAM_READWRITE); g_object_class_install_property(G_OBJECT_CLASS(klass), YPOS_PROP, properties[YPOS_PROP]); /** * VisuGlExtAxes::size: * * Store the portion of screen the axis occupy. * * Since: 3.8 */ properties[SIZE_PROP] = g_param_spec_float("size", "Size", "portion of the screen for the axis", 0., 1., .16f, G_PARAM_READWRITE); g_object_class_install_property(G_OBJECT_CLASS(klass), SIZE_PROP, properties[SIZE_PROP]); g_object_class_override_property(G_OBJECT_CLASS(klass), COLOR_PROP, "color"); g_object_class_override_property(G_OBJECT_CLASS(klass), WIDTH_PROP, "width"); g_object_class_override_property(G_OBJECT_CLASS(klass), STIPPLE_PROP, "stipple"); /** * VisuGlExtAxes::view: * * Store the view where the axes are rendered. * * Since: 3.8 */ properties[VIEW_PROP] = g_param_spec_object("view", "OpenGl View", "rendering view for the axes", VISU_TYPE_GL_VIEW, G_PARAM_READWRITE); g_object_class_install_property(G_OBJECT_CLASS(klass), VIEW_PROP, properties[VIEW_PROP]); /** * VisuGlExtAxes::basis: * * Store the #VisuBoxed object that defines the axes. If %NULL, a * cartesian basis-set is assumed. * * Since: 3.8 */ properties[BOX_PROP] = g_param_spec_object("basis", "basis-set", "provides the basis-set to draw the axes", VISU_TYPE_BOX, G_PARAM_READWRITE); g_object_class_install_property(G_OBJECT_CLASS(klass), BOX_PROP, properties[BOX_PROP]); /** * VisuGlExtAxes::x-label: * * Store the label for x axis. * * Since: 3.8 */ properties[LBLX_PROP] = g_param_spec_string("x-label", "X label", "label for the x axis", "x", G_PARAM_READWRITE); g_object_class_install_property(G_OBJECT_CLASS(klass), LBLX_PROP, properties[LBLX_PROP]); /** * VisuGlExtAxes::y-label: * * Store the label for y axis. * * Since: 3.8 */ properties[LBLY_PROP] = g_param_spec_string("y-label", "Y label", "label for the y axis", "y", G_PARAM_READWRITE); g_object_class_install_property(G_OBJECT_CLASS(klass), LBLY_PROP, properties[LBLY_PROP]); /** * VisuGlExtAxes::z-label: * * Store the label for z axis. * * Since: 3.8 */ properties[LBLZ_PROP] = g_param_spec_string("z-label", "Z label", "label for the z axis", "z", G_PARAM_READWRITE); g_object_class_install_property(G_OBJECT_CLASS(klass), LBLZ_PROP, properties[LBLZ_PROP]); /** * VisuGlExtAxes::display-orienation: * * If TRUE, it draws a coloured cone to display orientation information. * * Since: 3.8 */ properties[USE_ORIENTATION_PROP] = g_param_spec_boolean("display-orientation", "Display orientation", "display orientation information", FALSE, G_PARAM_READWRITE); g_object_class_install_property(G_OBJECT_CLASS(klass), USE_ORIENTATION_PROP, properties[USE_ORIENTATION_PROP]); /** * VisuGlExtAxes::orientation-theta: * * Store the theta angle used to defined the coloured cone position * when axis are used to display a coloured orientation. * * Since: 3.8 */ properties[CONE_THETA_PROP] = g_param_spec_float("orientation-theta", "Theta angle in degrees", "theta defining top", 0., 180., 0.f, G_PARAM_READWRITE); g_object_class_install_property(G_OBJECT_CLASS(klass), CONE_THETA_PROP, properties[CONE_THETA_PROP]); /** * VisuGlExtAxes::orientation-phi: * * Store the phi angle used to defined the coloured cone position * when axis are used to display a coloured orientation. * * Since: 3.8 */ properties[CONE_PHI_PROP] = g_param_spec_float("orientation-phi", "Phi angle in degrees", "phi defining top", 0., 360., 0.f, G_PARAM_READWRITE); g_object_class_install_property(G_OBJECT_CLASS(klass), CONE_PHI_PROP, properties[CONE_PHI_PROP]); /** * VisuGlExtAxes::orientation-omega: * * Store the omega angle used to defined the coloured cone position * when axis are used to display a coloured orientation. * * Since: 3.8 */ properties[CONE_OMEGA_PROP] = g_param_spec_float("orientation-omega", "Omega angle in degrees", "omega defining top", 0., 360., 0.f, G_PARAM_READWRITE); g_object_class_install_property(G_OBJECT_CLASS(klass), CONE_OMEGA_PROP, properties[CONE_OMEGA_PROP]); } static void visu_gl_ext_axes_init(VisuGlExtAxes *obj) { DBG_fprintf(stderr, "Extension Axes: initializing a new object (%p).\n", (gpointer)obj); obj->priv = visu_gl_ext_axes_get_instance_private(obj); obj->priv->dispose_has_run = FALSE; /* Private data. */ obj->priv->rgb[0] = rgbDefault[0]; obj->priv->rgb[1] = rgbDefault[1]; obj->priv->rgb[2] = rgbDefault[2]; obj->priv->rgb[3] = 1.f; obj->priv->lgFact = SIZE_DEFAULT; obj->priv->lineWidth = LINE_WIDTH_DEFAULT; obj->priv->lineStipple = LINE_STIPPLE_DEFAULT; obj->priv->xpos = POSITION_DEFAULT[0]; obj->priv->ypos = POSITION_DEFAULT[1]; obj->priv->view = (VisuGlView*)0; obj->priv->widthHeight_signal = 0; obj->priv->persp_signal = 0; obj->priv->refLength_signal = 0; obj->priv->color_signal = 0; obj->priv->matrix[0][0] = 1.; obj->priv->matrix[0][1] = 0.; obj->priv->matrix[0][2] = 0.; obj->priv->matrix[1][0] = 0.; obj->priv->matrix[1][1] = 1.; obj->priv->matrix[1][2] = 0.; obj->priv->matrix[2][0] = 0.; obj->priv->matrix[2][1] = 0.; obj->priv->matrix[2][2] = 1.; obj->priv->box = (VisuBox*)0; obj->priv->box_signal = 0; obj->priv->lbl[0] = g_strdup(LABEL_DEFAULT[TOOL_XYZ_X]); obj->priv->lbl[1] = g_strdup(LABEL_DEFAULT[TOOL_XYZ_Y]); obj->priv->lbl[2] = g_strdup(LABEL_DEFAULT[TOOL_XYZ_Z]); obj->priv->displayOrientation = FALSE; obj->priv->orientation[0] = 0.f; obj->priv->orientation[1] = 0.f; obj->priv->orientation[2] = 0.f; g_signal_connect_object(VISU_CONFIG_FILE_RESOURCE, "parsed::" FLAG_RESOURCE_AXES_USED, G_CALLBACK(onEntryUsed), (gpointer)obj, G_CONNECT_SWAPPED); g_signal_connect_object(VISU_CONFIG_FILE_RESOURCE, "parsed::" FLAG_RESOURCE_AXES_COLOR, G_CALLBACK(onEntryColor), (gpointer)obj, G_CONNECT_SWAPPED); g_signal_connect_object(VISU_CONFIG_FILE_RESOURCE, "parsed::" FLAG_RESOURCE_AXES_LINE, G_CALLBACK(onEntryWidth), (gpointer)obj, G_CONNECT_SWAPPED); g_signal_connect_object(VISU_CONFIG_FILE_RESOURCE, "parsed::" FLAG_RESOURCE_AXES_STIPPLE, G_CALLBACK(onEntryStipple), (gpointer)obj, G_CONNECT_SWAPPED); g_signal_connect_object(VISU_CONFIG_FILE_RESOURCE, "parsed::" FLAG_RESOURCE_AXES_POSITION, G_CALLBACK(onEntryPosition), (gpointer)obj, G_CONNECT_SWAPPED); g_signal_connect_object(VISU_CONFIG_FILE_RESOURCE, "parsed::" FLAG_RESOURCE_AXES_LABEL_X, G_CALLBACK(onEntryLabel), (gpointer)obj, G_CONNECT_SWAPPED); g_signal_connect_object(VISU_CONFIG_FILE_RESOURCE, "parsed::" FLAG_RESOURCE_AXES_LABEL_Y, G_CALLBACK(onEntryLabel), (gpointer)obj, G_CONNECT_SWAPPED); g_signal_connect_object(VISU_CONFIG_FILE_RESOURCE, "parsed::" FLAG_RESOURCE_AXES_LABEL_Z, G_CALLBACK(onEntryLabel), (gpointer)obj, G_CONNECT_SWAPPED); g_signal_connect_object(VISU_CONFIG_FILE_RESOURCE, "parsed::" FLAG_RESOURCE_AXES_FACTOR, G_CALLBACK(onEntryFactor), (gpointer)obj, G_CONNECT_SWAPPED); if (!defaultAxes) defaultAxes = obj; } /* This method can be called several times. It should unref all of its reference to GObjects. */ static void visu_gl_ext_axes_dispose(GObject* obj) { VisuGlExtAxes *axes; DBG_fprintf(stderr, "Extension Axes: dispose object %p.\n", (gpointer)obj); axes = VISU_GL_EXT_AXES(obj); if (axes->priv->dispose_has_run) return; axes->priv->dispose_has_run = TRUE; /* Disconnect signals. */ visu_gl_ext_axes_setGlView(VISU_GL_EXT(axes), (VisuGlView*)0); _setBox(axes, (VisuBox*)0); /* Chain up to the parent class */ G_OBJECT_CLASS(visu_gl_ext_axes_parent_class)->dispose(obj); } /* This method is called once only. */ static void visu_gl_ext_axes_finalize(GObject* obj) { VisuGlExtAxes *axes; g_return_if_fail(obj); DBG_fprintf(stderr, "Extension Axes: finalize object %p.\n", (gpointer)obj); axes = VISU_GL_EXT_AXES(obj); /* Free privs elements. */ if (axes->priv) { DBG_fprintf(stderr, "Extension Axes: free private axes.\n"); g_free(axes->priv->lbl[0]); g_free(axes->priv->lbl[1]); g_free(axes->priv->lbl[2]); } /* The free is called by g_type_free_instance... */ /* g_free(axes); */ /* Chain up to the parent class */ DBG_fprintf(stderr, "Extension Axes: chain to parent.\n"); G_OBJECT_CLASS(visu_gl_ext_axes_parent_class)->finalize(obj); DBG_fprintf(stderr, "Extension Axes: freeing ... OK.\n"); } static void visu_gl_ext_axes_get_property(GObject* obj, guint property_id, GValue *value, GParamSpec *pspec) { VisuGlExtAxes *self = VISU_GL_EXT_AXES(obj); DBG_fprintf(stderr, "Extension Axes: get property '%s' -> ", g_param_spec_get_name(pspec)); switch (property_id) { case SIZE_PROP: g_value_set_float(value, self->priv->lgFact); DBG_fprintf(stderr, "%g.\n", self->priv->lgFact); break; case XPOS_PROP: g_value_set_float(value, self->priv->xpos); DBG_fprintf(stderr, "%g.\n", self->priv->xpos); break; case YPOS_PROP: g_value_set_float(value, self->priv->ypos); DBG_fprintf(stderr, "%g.\n", self->priv->ypos); break; case COLOR_PROP: g_value_take_boxed(value, tool_color_new(self->priv->rgb)); DBG_fprintf(stderr, "%gx%gx%g.\n", self->priv->rgb[0], self->priv->rgb[1], self->priv->rgb[2]); break; case WIDTH_PROP: g_value_set_float(value, self->priv->lineWidth); DBG_fprintf(stderr, "%g.\n", self->priv->lineWidth); break; case STIPPLE_PROP: g_value_set_uint(value, (guint)self->priv->lineStipple); DBG_fprintf(stderr, "%d.\n", (guint)self->priv->lineStipple); break; case VIEW_PROP: g_value_set_object(value, self->priv->view); DBG_fprintf(stderr, "%p.\n", (gpointer)self->priv->view); break; case BOX_PROP: g_value_set_object(value, self->priv->box); DBG_fprintf(stderr, "%p.\n", g_value_get_object(value)); break; case LBLX_PROP: g_value_set_static_string(value, self->priv->lbl[0]); DBG_fprintf(stderr, "'%s'.\n", self->priv->lbl[0]); break; case LBLY_PROP: g_value_set_static_string(value, self->priv->lbl[1]); DBG_fprintf(stderr, "'%s'.\n", self->priv->lbl[1]); break; case LBLZ_PROP: g_value_set_static_string(value, self->priv->lbl[2]); DBG_fprintf(stderr, "'%s'.\n", self->priv->lbl[2]); break; case USE_ORIENTATION_PROP: g_value_set_boolean(value, self->priv->displayOrientation); DBG_fprintf(stderr, "%d.\n", self->priv->displayOrientation); break; case CONE_THETA_PROP: g_value_set_float(value, self->priv->orientation[0]); DBG_fprintf(stderr, "%g.\n", self->priv->orientation[0]); break; case CONE_PHI_PROP: g_value_set_float(value, self->priv->orientation[1]); DBG_fprintf(stderr, "%g.\n", self->priv->orientation[1]); break; case CONE_OMEGA_PROP: g_value_set_float(value, self->priv->orientation[2]); DBG_fprintf(stderr, "%g.\n", self->priv->orientation[2]); break; default: /* We don't have any other property... */ G_OBJECT_WARN_INVALID_PROPERTY_ID(obj, property_id, pspec); break; } } static void visu_gl_ext_axes_set_property(GObject* obj, guint property_id, const GValue *value, GParamSpec *pspec) { ToolColor *color; VisuGlExtAxes *self = VISU_GL_EXT_AXES(obj); float orientation[3]; DBG_fprintf(stderr, "Extension Axes: set property '%s' -> ", g_param_spec_get_name(pspec)); switch (property_id) { case SIZE_PROP: visu_gl_ext_axes_setLengthFactor(self, g_value_get_float(value)); DBG_fprintf(stderr, "%g.\n", self->priv->lgFact); break; case XPOS_PROP: visu_gl_ext_axes_setPosition(self, g_value_get_float(value), self->priv->ypos); DBG_fprintf(stderr, "%g.\n", self->priv->xpos); break; case YPOS_PROP: visu_gl_ext_axes_setPosition(self, self->priv->xpos, g_value_get_float(value)); DBG_fprintf(stderr, "%g.\n", self->priv->ypos); break; case COLOR_PROP: color = (ToolColor*)g_value_get_boxed(value); _setRGB((VisuGlExtLined*)self, color->rgba, TOOL_COLOR_MASK_RGBA); DBG_fprintf(stderr, "%gx%gx%g.\n", self->priv->rgb[0], self->priv->rgb[1], self->priv->rgb[2]); break; case WIDTH_PROP: _setLineWidth((VisuGlExtLined*)self, g_value_get_float(value)); DBG_fprintf(stderr, "%g.\n", self->priv->lineWidth); break; case STIPPLE_PROP: _setLineStipple((VisuGlExtLined*)self, (guint16)g_value_get_uint(value)); DBG_fprintf(stderr, "%d.\n", (guint)self->priv->lineStipple); break; case VIEW_PROP: visu_gl_ext_axes_setGlView(VISU_GL_EXT(self), VISU_GL_VIEW(g_value_get_object(value))); DBG_fprintf(stderr, "%p.\n", (gpointer)self->priv->view); break; case BOX_PROP: DBG_fprintf(stderr, "%p.\n", (gpointer)g_value_get_object(value)); visu_gl_ext_axes_setBasisFromBox(self, VISU_BOX(g_value_get_object(value))); break; case LBLX_PROP: visu_gl_ext_axes_setLabel(self, g_value_get_string(value), TOOL_XYZ_X); DBG_fprintf(stderr, "'%s'.\n", self->priv->lbl[0]); break; case LBLY_PROP: visu_gl_ext_axes_setLabel(self, g_value_get_string(value), TOOL_XYZ_Y); DBG_fprintf(stderr, "'%s'.\n", self->priv->lbl[1]); break; case LBLZ_PROP: visu_gl_ext_axes_setLabel(self, g_value_get_string(value), TOOL_XYZ_Z); DBG_fprintf(stderr, "'%s'.\n", self->priv->lbl[2]); break; case USE_ORIENTATION_PROP: visu_gl_ext_axes_useOrientation(self, g_value_get_boolean(value)); DBG_fprintf(stderr, "%d.\n", self->priv->displayOrientation); break; case CONE_THETA_PROP: orientation[0] = g_value_get_float(value); visu_gl_ext_axes_setOrientationTop(self, orientation, VISU_GL_CAMERA_THETA); DBG_fprintf(stderr, "%g.\n", self->priv->orientation[0]); break; case CONE_PHI_PROP: orientation[1] = g_value_get_float(value); visu_gl_ext_axes_setOrientationTop(self, orientation, VISU_GL_CAMERA_PHI); DBG_fprintf(stderr, "%g.\n", self->priv->orientation[1]); break; case CONE_OMEGA_PROP: DBG_fprintf(stderr, "%g.\n", g_value_get_float(value)); orientation[2] = g_value_get_float(value); visu_gl_ext_axes_setOrientationTop(self, orientation, VISU_GL_CAMERA_OMEGA); break; default: /* We don't have any other property... */ G_OBJECT_WARN_INVALID_PROPERTY_ID(obj, property_id, pspec); break; } } static void _setBox(VisuGlExtAxes *axes, VisuBox *box) { if (axes->priv->box == box) return; if (axes->priv->box) { g_signal_handler_disconnect(G_OBJECT(axes->priv->box), axes->priv->box_signal); g_object_unref(axes->priv->box); } if (box) { g_object_ref(box); axes->priv->box_signal = g_signal_connect(G_OBJECT(box), "SizeChanged", G_CALLBACK(onBoxChange), (gpointer)axes); } else axes->priv->box_signal = 0; axes->priv->box = box; g_object_notify_by_pspec(G_OBJECT(axes), properties[BOX_PROP]); } /** * visu_gl_ext_axes_new: * @name: (allow-none): the name to give to the extension (default is #VISU_GL_EXT_AXES_ID). * * Creates a new #VisuGlExt to draw axes. * * Since: 3.7 * * Returns: a pointer to the #VisuGlExt it created or * NULL otherwise. */ VisuGlExtAxes* visu_gl_ext_axes_new(const gchar *name) { char *name_ = VISU_GL_EXT_AXES_ID; char *description = _("Draw {x,y,z} axes."); VisuGlExt *extensionAxes; DBG_fprintf(stderr,"Extension Axes: new object.\n"); extensionAxes = VISU_GL_EXT(g_object_new(VISU_TYPE_GL_EXT_AXES, "name", (name)?name:name_, "label", _(name), "description", description, "nGlObj", 1, "priority", VISU_GL_EXT_PRIORITY_LAST, "saveState", TRUE, NULL)); return VISU_GL_EXT_AXES(extensionAxes); } static gboolean _setRGB(VisuGlExtLined *axes, float rgb[4], int mask) { VisuGlExtAxesPrivate *self; g_return_val_if_fail(VISU_IS_GL_EXT_AXES(axes), FALSE); self = VISU_GL_EXT_AXES(axes)->priv; if (mask & TOOL_COLOR_MASK_R) self->rgb[0] = rgb[0]; if (mask & TOOL_COLOR_MASK_G) self->rgb[1] = rgb[1]; if (mask & TOOL_COLOR_MASK_B) self->rgb[2] = rgb[2]; visu_gl_ext_setDirty(VISU_GL_EXT(axes), TRUE); return TRUE; } static gboolean _setLineWidth(VisuGlExtLined *axes, float width) { VisuGlExtAxesPrivate *self; g_return_val_if_fail(VISU_IS_GL_EXT_AXES(axes), FALSE); self = VISU_GL_EXT_AXES(axes)->priv; self->lineWidth = width; visu_gl_ext_setDirty(VISU_GL_EXT(axes), TRUE); return TRUE; } static gboolean _setLineStipple(VisuGlExtLined *axes, guint16 stipple) { VisuGlExtAxesPrivate *self; g_return_val_if_fail(VISU_IS_GL_EXT_AXES(axes), FALSE); self = VISU_GL_EXT_AXES(axes)->priv; self->lineStipple = stipple; visu_gl_ext_setDirty(VISU_GL_EXT(axes), TRUE); return TRUE; } static void _setBasis(VisuGlExtAxes *axes, double matrix[3][3]) { double sum2; DBG_fprintf(stderr, "Extension Axes: %8g %8g %8g\n" " %8g %8g %8g\n" " %8g %8g %8g\n", matrix[0][0], matrix[0][1], matrix[0][2], matrix[1][0], matrix[1][1], matrix[1][2], matrix[2][0], matrix[2][1], matrix[2][2]); /* We normalise it and copy it. */ sum2 = 1. / sqrt(matrix[0][0] * matrix[0][0] + matrix[1][0] * matrix[1][0] + matrix[2][0] * matrix[2][0]); axes->priv->matrix[0][0] = matrix[0][0] * sum2; axes->priv->matrix[0][1] = matrix[1][0] * sum2; axes->priv->matrix[0][2] = matrix[2][0] * sum2; sum2 = 1. / sqrt(matrix[0][1] * matrix[0][1] + matrix[1][1] * matrix[1][1] + matrix[2][1] * matrix[2][1]); axes->priv->matrix[1][0] = matrix[0][1] * sum2; axes->priv->matrix[1][1] = matrix[1][1] * sum2; axes->priv->matrix[1][2] = matrix[2][1] * sum2; sum2 = 1. / sqrt(matrix[0][2] * matrix[0][2] + matrix[1][2] * matrix[1][2] + matrix[2][2] * matrix[2][2]); axes->priv->matrix[2][0] = matrix[0][2] * sum2; axes->priv->matrix[2][1] = matrix[1][2] * sum2; axes->priv->matrix[2][2] = matrix[2][2] * sum2; visu_gl_ext_setDirty(VISU_GL_EXT(axes), TRUE); } /** * visu_gl_ext_axes_setBasis: * @axes: the #VisuGlExtAxes object to modify. * @matrix: the definition of the three basis axis. * * The @axes can represent an arbitrary basis-set, provided by * @matrix. @matrix[{0,1,2}] represents the {x,y,z} axis vector in a * cartesian basis-set. See visu_gl_ext_axes_setBasisFromBox() if the * basis-set should follow the one of a given #VisuBox. * * Since: 3.7 * * Returns: TRUE if the basis is actually changed. **/ gboolean visu_gl_ext_axes_setBasis(VisuGlExtAxes *axes, double matrix[3][3]) { g_return_val_if_fail(VISU_IS_GL_EXT_AXES(axes), FALSE); _setBox(axes, (VisuBox*)0); _setBasis(axes, matrix); return visu_gl_ext_getActive(VISU_GL_EXT(axes)); } /** * visu_gl_ext_axes_setBasisFromBox: * @axes: the #VisuGlExtAxes object to modify. * @box: (allow-none): the #VisuBox to use as basis-set. * * The @axes can follow the basis-set defined by @box. If NULL is * passed, then the orthorombic default basis-set is used. * * Since: 3.7 * * Returns: TRUE if the basis is actually changed. **/ gboolean visu_gl_ext_axes_setBasisFromBox(VisuGlExtAxes *axes, VisuBox *box) { double m[3][3]; g_return_val_if_fail(VISU_IS_GL_EXT_AXES(axes), FALSE); if (box) visu_box_getCellMatrix(box, m); else { memset(m, '\0', sizeof(double) * 9); m[0][0] = 1.; m[1][1] = 1.; m[2][2] = 1.; } _setBox(axes, box); _setBasis(axes, m); return visu_gl_ext_getActive(VISU_GL_EXT(axes)); } /** * visu_gl_ext_axes_setLabel: * @axes: a #VisuGlExtAxes object. * @lbl: a string. * @dir: an axis direction. * * Set the label @lbl for the given axis @dir. * * Since: 3.8 * * Returns: TRUE if the label is modified. **/ gboolean visu_gl_ext_axes_setLabel(VisuGlExtAxes *axes, const gchar *lbl, ToolXyzDir dir) { g_return_val_if_fail(VISU_IS_GL_EXT_AXES(axes) && lbl, FALSE); if (!strcmp(axes->priv->lbl[dir], lbl)) return FALSE; g_free(axes->priv->lbl[dir]); axes->priv->lbl[dir] = g_strdup(lbl); g_object_notify_by_pspec(G_OBJECT(axes), properties[LBLX_PROP + dir]); visu_gl_ext_setDirty(VISU_GL_EXT(axes), TRUE); return TRUE; } /** * visu_gl_ext_axes_setPosition: * @axes: the #VisuGlExtAxes object to modify. * @xpos: the reduced x position (1 to the right). * @ypos: the reduced y position (1 to the bottom). * * Change the position of the axes representation. * * Since: 3.7 * * Returns: TRUE if the position is actually changed. **/ gboolean visu_gl_ext_axes_setPosition(VisuGlExtAxes *axes, float xpos, float ypos) { gboolean changed; g_return_val_if_fail(VISU_IS_GL_EXT_AXES(axes), FALSE); xpos = CLAMP(xpos, 0.f, 1.f); ypos = CLAMP(ypos, 0.f, 1.f); changed = FALSE; g_object_freeze_notify(G_OBJECT(axes)); if (xpos != axes->priv->xpos) { axes->priv->xpos = xpos; g_object_notify_by_pspec(G_OBJECT(axes), properties[XPOS_PROP]); changed = TRUE; } if (ypos != axes->priv->ypos) { axes->priv->ypos = ypos; g_object_notify_by_pspec(G_OBJECT(axes), properties[YPOS_PROP]); changed = TRUE; } if (changed) visu_gl_ext_setDirty(VISU_GL_EXT(axes), TRUE); g_object_thaw_notify(G_OBJECT(axes)); return changed; } /** * visu_gl_ext_axes_useOrientation: * @axes: a #VisuGlExtAxes object. * @use: a boolean. * * If TRUE, @axes also draws a coloured cone to display orientation information. * * Since: 3.8 * * Returns: TRUE if value is actually changed. **/ gboolean visu_gl_ext_axes_useOrientation(VisuGlExtAxes *axes, gboolean use) { g_return_val_if_fail(VISU_IS_GL_EXT_AXES(axes), FALSE); if (axes->priv->displayOrientation == use) return FALSE; axes->priv->displayOrientation = use; g_object_notify_by_pspec(G_OBJECT(axes), properties[USE_ORIENTATION_PROP]); visu_gl_ext_setDirty(VISU_GL_EXT(axes), TRUE); return TRUE; } /** * visu_gl_ext_axes_setOrientationTop: * @axes: a #VisuGlExtAxes object. * @top: (array fixed-size=3): a camera orientation. * @dir: flags used to specify which angles to set. * * Define the camera orientation of the top orientation when @axes are * used to display orientation information. * * Since: 3.8 * * Returns: TRUE if value is actually changed. **/ gboolean visu_gl_ext_axes_setOrientationTop(VisuGlExtAxes *axes, const gfloat top[3], int dir) { gboolean changed; g_return_val_if_fail(VISU_IS_GL_EXT_AXES(axes), FALSE); changed = FALSE; g_object_freeze_notify(G_OBJECT(axes)); if ((dir & VISU_GL_CAMERA_THETA) && (CLAMP(top[0], 0.f, 180.) != axes->priv->orientation[0])) { axes->priv->orientation[0] = CLAMP(top[0], 0.f, 180.); g_object_notify_by_pspec(G_OBJECT(axes), properties[CONE_THETA_PROP]); changed = TRUE; } if ((dir & VISU_GL_CAMERA_PHI) && (CLAMP(top[1], 0.f, 360.) != axes->priv->orientation[1])) { axes->priv->orientation[1] = CLAMP(top[1], 0.f, 360.); g_object_notify_by_pspec(G_OBJECT(axes), properties[CONE_PHI_PROP]); changed = TRUE; } if ((dir & VISU_GL_CAMERA_OMEGA) && (CLAMP(top[2], 0.f, 360.) != axes->priv->orientation[2])) { axes->priv->orientation[2] = CLAMP(top[2], 0.f, 360.); g_object_notify_by_pspec(G_OBJECT(axes), properties[CONE_OMEGA_PROP]); changed = TRUE; } if (changed && axes->priv->displayOrientation) visu_gl_ext_setDirty(VISU_GL_EXT(axes), TRUE); g_object_thaw_notify(G_OBJECT(axes)); return changed; } static gboolean visu_gl_ext_axes_setGlView(VisuGlExt *axes, VisuGlView *view) { VisuGlExtAxesPrivate *priv = ((VisuGlExtAxes*)axes)->priv; /* No change to be done. */ if (view == priv->view) return FALSE; if (priv->view) { g_signal_handler_disconnect(G_OBJECT(priv->view), priv->persp_signal); g_signal_handler_disconnect(G_OBJECT(priv->view), priv->refLength_signal); g_signal_handler_disconnect(G_OBJECT(priv->view), priv->widthHeight_signal); g_object_unref(priv->view); priv->persp_signal = 0; priv->refLength_signal = 0; priv->widthHeight_signal = 0; priv->color_signal = 0; } if (view) { g_object_ref(view); priv->persp_signal = g_signal_connect_swapped(G_OBJECT(view), "notify::perspective", G_CALLBACK(onAxesParametersChange), (gpointer)axes); priv->refLength_signal = g_signal_connect_swapped(G_OBJECT(view), "RefLengthChanged", G_CALLBACK(onAxesParametersChange), (gpointer)axes); priv->widthHeight_signal = g_signal_connect_swapped(G_OBJECT(view), "WidthHeightChanged", G_CALLBACK(onAxesParametersChange), (gpointer)axes); } priv->view = view; g_object_notify_by_pspec(G_OBJECT(axes), properties[VIEW_PROP]); return TRUE; } /* Get methods. */ static float* _getRGB(const VisuGlExtLined *axes) { g_return_val_if_fail(VISU_IS_GL_EXT_AXES(axes), rgbDefault); return ((VisuGlExtAxes*)axes)->priv->rgb; } static float _getLineWidth(const VisuGlExtLined *axes) { g_return_val_if_fail(VISU_IS_GL_EXT_AXES(axes), LINE_WIDTH_DEFAULT); return ((VisuGlExtAxes*)axes)->priv->lineWidth; } static guint16 _getLineStipple(const VisuGlExtLined *axes) { g_return_val_if_fail(VISU_IS_GL_EXT_AXES(axes), LINE_STIPPLE_DEFAULT); return ((VisuGlExtAxes*)axes)->priv->lineStipple; } /** * visu_gl_ext_axes_getPosition: * @axes: the #VisuGlExtAxes object to inquire. * @xpos: (out) (allow-none): a location to store the x position. * @ypos: (out) (allow-none): a location to store the y position. * * Inquire the position of the representation of tha axes. * * Since: 3.7 **/ void visu_gl_ext_axes_getPosition(VisuGlExtAxes *axes, float *xpos, float *ypos) { g_return_if_fail(VISU_IS_GL_EXT_AXES(axes)); if (xpos) *xpos = axes->priv->xpos; if (ypos) *ypos = axes->priv->ypos; } /** * visu_gl_ext_axes_setLengthFactor: * @axes: a #VisuGlExtAxes object. * @factor: a floating point value between 0. and 10. * * Change the scaling factor to draw the axis. * * Since: 3.8 * * Returns: TRUE if value is indeed changed. **/ gboolean visu_gl_ext_axes_setLengthFactor(VisuGlExtAxes *axes, float factor) { g_return_val_if_fail(VISU_IS_GL_EXT_AXES(axes), FALSE); if (axes->priv->lgFact == factor) return FALSE; axes->priv->lgFact = factor; g_object_notify_by_pspec(G_OBJECT(axes), properties[SIZE_PROP]); visu_gl_ext_setDirty(VISU_GL_EXT(axes), TRUE); return TRUE; } /** * visu_gl_ext_axes_getLengthFactor: * @axes: a #VisuGlExtAxes object. * * Retrieve the scaling factor used to draw axis. * * Since: 3.8 * * Returns: the scaling factor. **/ float visu_gl_ext_axes_getLengthFactor(VisuGlExtAxes *axes) { g_return_val_if_fail(VISU_IS_GL_EXT_AXES(axes), 1.f); return axes->priv->lgFact; } /****************/ /* Private part */ /****************/ static void visu_gl_ext_axes_rebuild(VisuGlExt *ext) { visu_gl_text_rebuildFontList(); visu_gl_ext_axes_draw(ext); } static void onAxesParametersChange(VisuGlExtAxes *axes) { DBG_fprintf(stderr, "Extension Axes: caught change on view.\n"); visu_gl_ext_setDirty(VISU_GL_EXT(axes), TRUE); } static void onBoxChange(VisuBox *box, float extens _U_, gpointer data) { VisuGlExtAxes *axes = VISU_GL_EXT_AXES(data); double m[3][3]; /* We copy the definition of the box. */ visu_box_getCellMatrix(box, m); _setBasis(axes, m); } static void onEntryUsed(VisuGlExtAxes *axes, VisuConfigFileEntry *entry _U_, VisuConfigFile *obj _U_) { visu_gl_ext_setActive(VISU_GL_EXT(axes), RESOURCE_AXES_USED_DEFAULT); } static void onEntryColor(VisuGlExtAxes *axes, VisuConfigFileEntry *entry _U_, VisuConfigFile *obj _U_) { visu_gl_ext_lined_setRGBA(VISU_GL_EXT_LINED(axes), rgbDefault, TOOL_COLOR_MASK_RGBA); } static void onEntryWidth(VisuGlExtAxes *axes, VisuConfigFileEntry *entry _U_, VisuConfigFile *obj _U_) { visu_gl_ext_lined_setWidth(VISU_GL_EXT_LINED(axes), LINE_WIDTH_DEFAULT); } static void onEntryStipple(VisuGlExtAxes *axes, VisuConfigFileEntry *entry _U_, VisuConfigFile *obj _U_) { visu_gl_ext_lined_setStipple(VISU_GL_EXT_LINED(axes), LINE_STIPPLE_DEFAULT); } static void onEntryPosition(VisuGlExtAxes *axes, VisuConfigFileEntry *entry _U_, VisuConfigFile *obj _U_) { visu_gl_ext_axes_setPosition(axes, POSITION_DEFAULT[0], POSITION_DEFAULT[1]); } static void onEntryLabel(VisuGlExtAxes *axes, VisuConfigFileEntry *entry, VisuConfigFile *obj _U_) { if (!strcmp(visu_config_file_entry_getKey(entry), FLAG_RESOURCE_AXES_LABEL_X)) g_object_set(G_OBJECT(axes), "x-label", LABEL_DEFAULT[TOOL_XYZ_X], NULL); else if (!strcmp(visu_config_file_entry_getKey(entry), FLAG_RESOURCE_AXES_LABEL_Y)) g_object_set(G_OBJECT(axes), "y-label", LABEL_DEFAULT[TOOL_XYZ_Y], NULL); else if (!strcmp(visu_config_file_entry_getKey(entry), FLAG_RESOURCE_AXES_LABEL_Z)) g_object_set(G_OBJECT(axes), "z-label", LABEL_DEFAULT[TOOL_XYZ_Z], NULL); } static void onEntryFactor(VisuGlExtAxes *axes, VisuConfigFileEntry *entry _U_, VisuConfigFile *obj _U_) { visu_gl_ext_axes_setLengthFactor(axes, SIZE_DEFAULT); } static void drawAxes(float length, double matrix[3][3], GLsizei w, GLsizei h, float width, float rgb[3], const char *legend, gboolean long_axes, gchar *lbl[3]) { double orig[3][3]; if (long_axes) { orig[0][0] = -matrix[0][0]; orig[0][1] = -matrix[0][1]; orig[0][2] = -matrix[0][2]; orig[1][0] = -matrix[1][0]; orig[1][1] = -matrix[1][1]; orig[1][2] = -matrix[1][2]; orig[2][0] = -matrix[2][0]; orig[2][1] = -matrix[2][1]; orig[2][2] = -matrix[2][2]; } else memset(orig, '\0', sizeof(double) * 9); glLineWidth(width); glColor3fv(rgb); glPushMatrix(); glScalef(length, length, length); glBegin(GL_LINES); glVertex3dv(orig[0]); glVertex3dv(matrix[0]); glVertex3dv(orig[1]); glVertex3dv(matrix[1]); glVertex3dv(orig[2]); glVertex3dv(matrix[2]); glEnd(); glRasterPos3dv(matrix[0]); visu_gl_text_drawChars(lbl[0], VISU_GL_TEXT_NORMAL); glRasterPos3dv(matrix[1]); visu_gl_text_drawChars(lbl[1], VISU_GL_TEXT_NORMAL); glRasterPos3dv(matrix[2]); visu_gl_text_drawChars(lbl[2], VISU_GL_TEXT_NORMAL); glPopMatrix(); if(legend != NULL) { glMatrixMode (GL_PROJECTION); glPushMatrix(); glLoadIdentity (); gluOrtho2D (0, MIN(w,h), 0, MIN(h,w)); glMatrixMode (GL_MODELVIEW); glPushMatrix(); glLoadIdentity (); glRasterPos3f(20., 5., 0.9); visu_gl_text_drawChars(legend, VISU_GL_TEXT_NORMAL); glPopMatrix(); glMatrixMode(GL_PROJECTION); glPopMatrix(); glMatrixMode(GL_MODELVIEW); } } /** * draw_coloured_cone: * @r: the radius of the cone * @h: the semi-height of the cone * @n: the precision used to draw the sphere * * Draws a coloured double cone at the given position. */ static void draw_coloured_cone(double r, double h, int n, float phi_prime_zero) { float hsv[3], rgb[3]; int i,j; double theta1,theta2,theta3; float e_x, e_y, e_z, p_x, p_y, p_z; g_return_if_fail(r >= 0 && n >= 0); if (n < 4 || r <= 0) { glBegin(GL_POINTS); glVertex3f(0,0,0); glEnd(); return; } glFrontFace(GL_CW); glPushMatrix(); glRotatef(phi_prime_zero, 0, 0, 1); glRotatef(-90, 1, 0, 0); hsv[1] = 0; hsv[2] = 1; for (j=0;j 1) hsv[1] = 1; hsv[2] = 2-2*(float)(1+j)/(float)(n/2); if(hsv[2] > 1) hsv[2] = 1; e_x = /*cos(theta2) **/hsv[1]*hsv[2]* cos(theta3); e_y = sin(theta2); e_z = /*cos(theta2) **/hsv[1]*hsv[2]* sin(theta3); p_x = r * e_x; p_y = /*r * e_y*/h*(hsv[1] - hsv[2]); p_z = r * e_z; tool_color_convertHSVtoRGB(rgb, hsv); glColor3f(rgb[0], rgb[1], rgb[2]); glNormal3f(e_x,e_y,e_z); glVertex3f(p_x,p_y,p_z); hsv[0] = /*1-*/(float)i/(float)n; hsv[1] = 2*(float)j/(float)(n/2); if(hsv[1] > 1) hsv[1] = 1; hsv[2] = 2-2*(float)j/(float)(n/2); if(hsv[2] > 1) hsv[2] = 1; e_x = /*cos(theta1) **/hsv[1]*hsv[2]* cos(theta3); e_y = sin(theta1); e_z = /*cos(theta1) **/hsv[1]*hsv[2]* sin(theta3); p_x = r * e_x; p_y = /*r * e_y*/h*(hsv[1] - hsv[2]); p_z = r * e_z; tool_color_convertHSVtoRGB(rgb, hsv); glColor3f(rgb[0], rgb[1], rgb[2]); glNormal3f(e_x,e_y,e_z); glVertex3f(p_x,p_y,p_z); } glEnd(); } glPopMatrix(); glFrontFace(GL_CCW); } /* void drawConeCircle(/\*XYZ c,*\/ double r, int n) */ /* { */ /* /\* XYZ e,p;*\/ */ /* GLboolean antialiasing_was_on; */ /* GLUquadric* trash = gluNewQuadric(); */ /* int i; */ /* double theta, height = 1; */ /* /\* glEnable (GL_POLYGON_SMOOTH); *\/ */ /* /\* glDisable (GL_DEPTH_TEST); *\/ */ /* antialiasing_was_on = enableGlFeature(GL_LINE_SMOOTH); */ /* glPushMatrix(); */ /* glRotatef(90, 1, 0, 0); */ /* glTranslatef(0, 0, -height/2); */ /* glLineWidth(lineWidth); */ /* glColor3f(0, 0, 0); */ /* gluQuadricOrientation(trash, GLU_INSIDE); */ /* gluCylinder(trash, 0.95*r, 0.95*r, height, n, 1); */ /* /\* glBegin(GL_LINE_LOOP); *\/ */ /* /\* for (i=0;i<=n;i++) *\/ */ /* /\* { *\/ */ /* /\* theta = i * TWOPI / n; *\/ */ /* /\* e.x = cos(theta); *\/ */ /* /\* e.z = sin(theta); *\/ */ /* /\* p.x = 0.8*(c.x + r * e.x); *\/ */ /* /\* p.z = 0.8*(c.z + r * e.z); *\/ */ /* /\* glVertex3f(p.x, -0.6, p.z); *\/ */ /* /\* glVertex3f(p.x, 0.6, p.z); *\/ */ /* /\* } *\/ */ /* /\* glEnd(); *\/ */ /* glPopMatrix(); */ /* restoreGlFeature(GL_LINE_SMOOTH, antialiasing_was_on); */ /* /\* glEnable (GL_DEPTH_TEST); *\/ */ /* /\* glDisable(GL_POLYGON_SMOOTH); *\/ */ /* } */ /** * visu_gl_ext_axes_draw: * @axes: the #VisuBox object to build axes for. * * This method creates a compiled list that draws axes. */ static void visu_gl_ext_axes_draw(VisuGlExt *ext) { float length; GLsizei w, h; GLint xx, yy; double mini, maxi, near, far; float length0; VisuGlExtAxes *axes; g_return_if_fail(VISU_IS_GL_EXT_AXES(ext)); axes = VISU_GL_EXT_AXES(ext); DBG_fprintf(stderr, "Extension Axes: call to axes draw (%p).\n", (gpointer)axes->priv->view); /* Nothing to draw; */ if (!axes->priv->view) return; DBG_fprintf(stderr, "Extension axes: creating axes in (%dx%d).\n", axes->priv->view->window.width, axes->priv->view->window.height); length0 = visu_gl_camera_getRefLength(&axes->priv->view->camera, (ToolUnits*)0); DBG_fprintf(stderr, " | refLength = %g\n", length0); DBG_fprintf(stderr, " | window = %dx%d\n", axes->priv->view->window.width, axes->priv->view->window.height); w = axes->priv->lgFact * MIN(axes->priv->view->window.width, axes->priv->view->window.height); h = w; xx = (axes->priv->view->window.width - w) * axes->priv->xpos; yy = (axes->priv->view->window.height - h) * (1.f - axes->priv->ypos); mini = -0.5f * length0 * (axes->priv->view->camera.d_red - 1.f) / axes->priv->view->camera.d_red; maxi = -mini; near = far = axes->priv->view->camera.d_red * length0; near -= length0; far += length0; DBG_fprintf(stderr, " | near/far = %g %g\n", near, far); visu_gl_text_initFontList(); glDeleteLists(visu_gl_ext_getGlList(ext), 1); visu_gl_ext_startDrawing(ext); /* Désactivation de la lumière et du brouillard et activation du culling. */ glEnable(GL_CULL_FACE); glDisable(GL_LIGHTING); glDisable(GL_FOG); if (axes->priv->lineStipple != 65535) { glEnable(GL_LINE_STIPPLE); glLineStipple(1, axes->priv->lineStipple); } glMatrixMode(GL_PROJECTION); glPushMatrix(); glLoadIdentity(); DBG_fprintf(stderr, "Extension axes: frustum is %fx%f %fx%f %fx%f.\n", mini, maxi, mini, maxi, near, far); glFrustum(mini, maxi, mini, maxi, near, far); glMatrixMode(GL_MODELVIEW); glPopMatrix(); DBG_fprintf(stderr, "Extension Axes: new view port at %dx%d, size %dx%d.\n", xx, yy, w, h); glViewport(xx, yy, w, h); length = 0.33 * length0; if (axes->priv->displayOrientation) { /* Resetting the depth buffer. */ glClear(GL_DEPTH_BUFFER_BIT); glEnable(GL_DEPTH_TEST); /* Draw the first color cone */ glPushMatrix(); glRotatef(axes->priv->orientation[1], 0, 0, 1); glRotatef(axes->priv->orientation[0], 0, 1, 0); draw_coloured_cone(length, 1.2*length, 16, axes->priv->orientation[2]); glPopMatrix(); drawAxes(1.5*length, axes->priv->matrix, w, h, axes->priv->lineWidth, axes->priv->rgb, _("front"), TRUE, axes->priv->lbl); glViewport(xx, yy+h, w, h); /* Enabling front culling and drawing the second color cone */ glPushMatrix(); glRotatef(axes->priv->orientation[1], 0, 0, 1); glRotatef(axes->priv->orientation[0], 0, 1, 0); glCullFace(GL_FRONT); draw_coloured_cone(length, 1.2*length, 16, axes->priv->orientation[2]); glCullFace(GL_BACK); glPopMatrix(); drawAxes(1.5*length, axes->priv->matrix, w, h, axes->priv->lineWidth, axes->priv->rgb, _("back"), TRUE, axes->priv->lbl); } else { glDisable(GL_DEPTH_TEST); drawAxes(length, axes->priv->matrix, w, h, axes->priv->lineWidth, axes->priv->rgb, NULL, FALSE, axes->priv->lbl); glEnable(GL_DEPTH_TEST); } glPushMatrix(); glMatrixMode(GL_PROJECTION); glPopMatrix(); glMatrixMode(GL_MODELVIEW); /* Back to the main viewport. */ glViewport(0, 0, axes->priv->view->window.width, axes->priv->view->window.height); visu_gl_ext_completeDrawing(ext); } /*************************/ /* Parameters & resources*/ /*************************/ /* Export function that is called by visu_module to write the values of resources to a file. */ static void exportResources(GString *data, VisuData *dataObj _U_) { if (!defaultAxes) return; visu_config_file_exportComment(data, DESC_RESOURCE_AXES_USED); visu_config_file_exportEntry(data, FLAG_RESOURCE_AXES_USED, NULL, "%d", visu_gl_ext_getActive(VISU_GL_EXT(defaultAxes))); visu_config_file_exportComment(data, DESC_RESOURCE_AXES_COLOR); visu_config_file_exportEntry(data, FLAG_RESOURCE_AXES_COLOR, NULL, "%4.3f %4.3f %4.3f", defaultAxes->priv->rgb[0], defaultAxes->priv->rgb[1], defaultAxes->priv->rgb[2]); visu_config_file_exportComment(data, DESC_RESOURCE_AXES_LINE); visu_config_file_exportEntry(data, FLAG_RESOURCE_AXES_LINE, NULL, "%4.0f", defaultAxes->priv->lineWidth); visu_config_file_exportComment(data, DESC_RESOURCE_AXES_STIPPLE); visu_config_file_exportEntry(data, FLAG_RESOURCE_AXES_STIPPLE, NULL, "%d", defaultAxes->priv->lineStipple); visu_config_file_exportComment(data, DESC_RESOURCE_AXES_POSITION); visu_config_file_exportEntry(data, FLAG_RESOURCE_AXES_POSITION, NULL, "%4.3f %4.3f", defaultAxes->priv->xpos, defaultAxes->priv->ypos); visu_config_file_exportComment(data, DESC_RESOURCE_AXES_LABEL); visu_config_file_exportEntry(data, FLAG_RESOURCE_AXES_LABEL_X, NULL, "%s", defaultAxes->priv->lbl[TOOL_XYZ_X]); visu_config_file_exportEntry(data, FLAG_RESOURCE_AXES_LABEL_Y, NULL, "%s", defaultAxes->priv->lbl[TOOL_XYZ_Y]); visu_config_file_exportEntry(data, FLAG_RESOURCE_AXES_LABEL_Z, NULL, "%s", defaultAxes->priv->lbl[TOOL_XYZ_Z]); visu_config_file_exportEntry(data, FLAG_RESOURCE_AXES_FACTOR, NULL, "%4.3f", defaultAxes->priv->lgFact); visu_config_file_exportComment(data, ""); } v_sim-3.8.0/src/extensions/axes.h000066400000000000000000000116731370110300500167340ustar00rootroot00000000000000/* EXTRAITS DE LA LICENCE Copyright CEA, contributeurs : Luc BILLARD et Damien CALISTE, laboratoire L_Sim, (2001-2005) Adresse mèl : BILLARD, non joignable par mèl ; CALISTE, damien P caliste AT cea P fr. Ce logiciel est un programme informatique servant à visualiser des structures atomiques dans un rendu pseudo-3D. Ce logiciel est régi par la licence CeCILL soumise au droit français et respectant les principes de diffusion des logiciels libres. Vous pouvez utiliser, modifier et/ou redistribuer ce programme sous les conditions de la licence CeCILL telle que diffusée par le CEA, le CNRS et l'INRIA sur le site "http://www.cecill.info". Le fait que vous puissiez accéder à cet en-tête signifie que vous avez pris connaissance de la licence CeCILL, et que vous en avez accepté les termes (cf. le fichier Documentation/licence.fr.txt fourni avec ce logiciel). */ /* LICENCE SUM UP Copyright CEA, contributors : Luc BILLARD et Damien CALISTE, laboratoire L_Sim, (2001-2005) E-mail address: BILLARD, not reachable any more ; CALISTE, damien P caliste AT cea P fr. This software is a computer program whose purpose is to visualize atomic configurations in 3D. This software is governed by the CeCILL license under French law and abiding by the rules of distribution of free software. You can use, modify and/ or redistribute the software under the terms of the CeCILL license as circulated by CEA, CNRS and INRIA at the following URL "http://www.cecill.info". The fact that you are presently reading this means that you have had knowledge of the CeCILL license and that you accept its terms. You can find a copy of this licence shipped with this software at Documentation/licence.en.txt. */ #ifndef AXES_H #define AXES_H #include #include #include #include "iface_lined.h" /** * VISU_TYPE_GL_EXT_AXES: * * return the type of #VisuGlExtAxes. * * Since: 3.7 */ #define VISU_TYPE_GL_EXT_AXES (visu_gl_ext_axes_get_type ()) /** * VISU_GL_EXT_AXES: * @obj: a #GObject to cast. * * Cast the given @obj into #VisuGlExtAxes type. * * Since: 3.7 */ #define VISU_GL_EXT_AXES(obj) (G_TYPE_CHECK_INSTANCE_CAST(obj, VISU_TYPE_GL_EXT_AXES, VisuGlExtAxes)) /** * VISU_GL_EXT_AXES_CLASS: * @klass: a #GObjectClass to cast. * * Cast the given @klass into #VisuGlExtAxesClass. * * Since: 3.7 */ #define VISU_GL_EXT_AXES_CLASS(klass) (G_TYPE_CHECK_CLASS_CAST(klass, VISU_TYPE_GL_EXT_AXES, VisuGlExtAxesClass)) /** * VISU_IS_GL_EXT_AXES: * @obj: a #GObject to test. * * Test if the given @ogj is of the type of #VisuGlExtAxes object. * * Since: 3.7 */ #define VISU_IS_GL_EXT_AXES(obj) (G_TYPE_CHECK_INSTANCE_TYPE(obj, VISU_TYPE_GL_EXT_AXES)) /** * VISU_IS_GL_EXT_AXES_CLASS: * @klass: a #GObjectClass to test. * * Test if the given @klass is of the type of #VisuGlExtAxesClass class. * * Since: 3.7 */ #define VISU_IS_GL_EXT_AXES_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE(klass, VISU_TYPE_GL_EXT_AXES)) /** * VISU_GL_EXT_AXES_GET_CLASS: * @obj: a #GObject to get the class of. * * It returns the class of the given @obj. * * Since: 3.7 */ #define VISU_GL_EXT_AXES_GET_CLASS(obj) (G_TYPE_INSTANCE_GET_CLASS(obj, VISU_TYPE_GL_EXT_AXES, VisuGlExtAxesClass)) typedef struct _VisuGlExtAxes VisuGlExtAxes; typedef struct _VisuGlExtAxesPrivate VisuGlExtAxesPrivate; typedef struct _VisuGlExtAxesClass VisuGlExtAxesClass; /** * VisuGlExtAxes: * * An opaque structure. * * Since: 3.7 */ struct _VisuGlExtAxes { VisuGlExt parent; VisuGlExtAxesPrivate *priv; }; /** * VisuGlExtAxesClass: * @parent: the parent class; * * A short way to identify #_VisuGlExtAxesClass structure. * * Since: 3.7 */ struct _VisuGlExtAxesClass { VisuGlExtClass parent; }; /** * VISU_GL_EXT_AXES_ID: * * The id used to identify this extension, see * visu_gl_ext_rebuild() for instance. */ #define VISU_GL_EXT_AXES_ID "Axes" /** * visu_gl_ext_axes_get_type: * * This method returns the type of #VisuGlExtAxes, use * VISU_TYPE_GL_EXT_AXES instead. * * Since: 3.7 * * Returns: the type of #VisuGlExtAxes. */ GType visu_gl_ext_axes_get_type(void); VisuGlExtAxes* visu_gl_ext_axes_new(const gchar *name); gboolean visu_gl_ext_axes_setBasisFromBox(VisuGlExtAxes *axes, VisuBox *box); gboolean visu_gl_ext_axes_setBasis(VisuGlExtAxes *axes, double matrix[3][3]); gboolean visu_gl_ext_axes_setPosition(VisuGlExtAxes *axes, float xpos, float ypos); gboolean visu_gl_ext_axes_setLabel(VisuGlExtAxes *axes, const gchar *lbl, ToolXyzDir dir); gboolean visu_gl_ext_axes_setLengthFactor(VisuGlExtAxes *axes, float factor); gboolean visu_gl_ext_axes_useOrientation(VisuGlExtAxes *axes, gboolean use); gboolean visu_gl_ext_axes_setOrientationTop(VisuGlExtAxes *axes, const gfloat top[3], int dir); void visu_gl_ext_axes_getPosition(VisuGlExtAxes *axes, float *xpos, float *ypos); float visu_gl_ext_axes_getLengthFactor(VisuGlExtAxes *axes); #endif v_sim-3.8.0/src/extensions/box.c000066400000000000000000001121601370110300500165500ustar00rootroot00000000000000/* EXTRAITS DE LA LICENCE Copyright CEA, contributeurs : Luc BILLARD et Damien CALISTE, laboratoire L_Sim, (2001-2014) Adresse mèl : BILLARD, non joignable par mèl ; CALISTE, damien P caliste AT cea P fr. Ce logiciel est un programme informatique servant à visualiser des structures atomiques dans un rendu pseudo-3D. Ce logiciel est régi par la licence CeCILL soumise au droit français et respectant les principes de diffusion des logiciels libres. Vous pouvez utiliser, modifier et/ou redistribuer ce programme sous les conditions de la licence CeCILL telle que diffusée par le CEA, le CNRS et l'INRIA sur le site "http://www.cecill.info". Le fait que vous puissiez accéder à cet en-tête signifie que vous avez pris connaissance de la licence CeCILL, et que vous en avez accepté les termes (cf. le fichier Documentation/licence.fr.txt fourni avec ce logiciel). */ /* LICENCE SUM UP Copyright CEA, contributors : Luc BILLARD et Damien CALISTE, laboratoire L_Sim, (2001-2014) E-mail address: BILLARD, not reachable any more ; CALISTE, damien P caliste AT cea P fr. This software is a computer program whose purpose is to visualize atomic configurations in 3D. This software is governed by the CeCILL license under French law and abiding by the rules of distribution of free software. You can use, modify and/ or redistribute the software under the terms of the CeCILL license as circulated by CEA, CNRS and INRIA at the following URL "http://www.cecill.info". The fact that you are presently reading this means that you have had knowledge of the CeCILL license and that you accept its terms. You can find a copy of this licence shipped with this software at Documentation/licence.en.txt. */ #include "box.h" #include #include #include #include #include #include #include #include #include #include #include /** * SECTION:box * @short_description: Draw a bounding box around nodes. * * This extension allows V_Sim to draw a box around the * nodes. The box is defined in the #VisuBox structure and can be * retrieved with visu_box_getGeometry(). This box is not necessary * orthogonal. * It has several properties, namely, its colour, its line width * and its line pattern. It is represented in OpenGL with simple lines * and is affected by the antialiasing property. Defined resources: * * * box_is_on (boolean): controls if a box * is drawn around the rendering area (since 3.0). * * * box_color (RGB in [0;1]): defines the * color of the box(since 3.0). * * * box_line_width (integer in [1;10]): * defines the width of the lines of the box (since 3.0). * * * box_line_stipple (2 integers in * ]0;65535]): dot scheme detail for the lines of the box. The first * value is the pattern for the line of the main box and the second * is the pattern for the lines of the expanded areas (since 3.4). * * */ /* Parameters & resources*/ /* This is a boolean to control is the box is render or not. */ #define FLAG_RESOURCE_BOX_USED "box_is_on" #define DESC_RESOURCE_BOX_USED "Control if a box is drawn around the rendering area ; boolean (0 or 1)" static gboolean RESOURCE_BOX_USED_DEFAULT = FALSE; /* A resource to control the color used to render the lines of the box. */ #define FLAG_RESOURCE_BOX_COLOR "box_color" #define DESC_RESOURCE_BOX_COLOR "Define the color of the box ; three floating point values (0. <= v <= 1.)" static float rgbDefault[4] = {1.0, 0.5, 0.1, 1.}; /* A resource to control the width to render the lines of the box. */ #define FLAG_RESOURCE_BOX_LINE "box_line_width" #define DESC_RESOURCE_BOX_LINE "Define the width of the lines of the box ; one integer (1. <= v <= 10.)" static float LINE_WIDTH_DEFAULT = 1.; /* A resource to control the stipple to render the lines of the box. */ #define FLAG_RESOURCE_BOX_STIPPLE "box_line_stipple" #define DESC_RESOURCE_BOX_STIPPLE "Dot scheme detail for the lines of the box (main and expanded) ; 0 < 2 integers < 2^16" static guint16 stippleDefault[2] = {65535, 65280}; #define FLAG_RESOURCE_BOX_SIDE "box_side_color" #define DESC_RESOURCE_BOX_SIDE "RGBA color used to draw the pristine box sides when expanded ; four floating point values (0. <= v <= 1.)" static float sideRGBDefault[4] = {0.f, 0.f, 0.f, 0.3333f}; #define RESOURCE_WITH_BASIS_DEFAULT FALSE /* static gboolean withBasis = FALSE; */ static float basisLength = 2.5f; /* Export function that is called by visu_module to write the values of resources to a file. */ static void exportResourcesBox(GString *data, VisuData *dataObj); struct _VisuGlExtBoxPrivate { gboolean dispose_has_run; /* Box definition. */ VisuBox *box; gulong box_signal; /* Matrix definition (to be merge later within box. */ float matrix[3][3]; /* Rendenring parameters. */ float rgb[4], sideRGB[4]; float lineWidth; guint16 lineStipple[2]; }; static VisuGlExtBox* defaultBox; enum { PROP_0, COLOR_PROP, SIDE_COLOR_PROP, WIDTH_PROP, STIPPLE_PROP, EXT_STIPPLE_PROP, BOX_PROP, N_PROP }; static GParamSpec *properties[N_PROP]; static void visu_gl_ext_lined_interface_init(VisuGlExtLinedInterface *iface); static void visu_gl_ext_box_dispose(GObject* obj); static void visu_gl_ext_box_get_property(GObject* obj, guint property_id, GValue *value, GParamSpec *pspec); static void visu_gl_ext_box_set_property(GObject* obj, guint property_id, const GValue *value, GParamSpec *pspec); static void visu_gl_ext_box_rebuild(VisuGlExt *ext); static void visu_gl_ext_box_draw(VisuGlExt *ext); static gboolean _setRGB(VisuGlExtLined *box, float rgb[4], int mask); static gboolean _setLineWidth(VisuGlExtLined *box, float width); static gboolean _setLineStipple(VisuGlExtLined *box, guint16 stipple); static float* _getRGB(const VisuGlExtLined *box); static float _getLineWidth(const VisuGlExtLined *box); static guint16 _getLineStipple(const VisuGlExtLined *box); /* Callbacks. */ static void onSizeChanged(VisuBox *box, gfloat extens, gpointer user_data); static void onEntryUsed(VisuGlExtBox *box, VisuConfigFileEntry *entry, VisuConfigFile *obj); static void onEntryColor(VisuGlExtBox *box, VisuConfigFileEntry *entry, VisuConfigFile *obj); static void onEntryWidth(VisuGlExtBox *box, VisuConfigFileEntry *entry, VisuConfigFile *obj); static void onEntryStipple(VisuGlExtBox *box, VisuConfigFileEntry *entry, VisuConfigFile *obj); static void onEntrySide(VisuGlExtBox *box, VisuConfigFileEntry *entry, VisuConfigFile *obj); G_DEFINE_TYPE_WITH_CODE(VisuGlExtBox, visu_gl_ext_box, VISU_TYPE_GL_EXT, G_ADD_PRIVATE(VisuGlExtBox) G_IMPLEMENT_INTERFACE(VISU_TYPE_GL_EXT_LINED, visu_gl_ext_lined_interface_init)) static void visu_gl_ext_lined_interface_init(VisuGlExtLinedInterface *iface) { iface->get_width = _getLineWidth; iface->set_width = _setLineWidth; iface->get_stipple = _getLineStipple; iface->set_stipple = _setLineStipple; iface->get_rgba = _getRGB; iface->set_rgba = _setRGB; } static void visu_gl_ext_box_class_init(VisuGlExtBoxClass *klass) { float rgColor[2] = {0.f, 1.f}; float rgWidth[2] = {0.f, 10.f}; VisuConfigFileEntry *resourceEntry; DBG_fprintf(stderr, "Extension Box: creating the class of the object.\n"); /* DBG_fprintf(stderr, " - adding new signals ;\n"); */ DBG_fprintf(stderr, " - adding new resources ;\n"); resourceEntry = visu_config_file_addBooleanEntry(VISU_CONFIG_FILE_RESOURCE, FLAG_RESOURCE_BOX_USED, DESC_RESOURCE_BOX_USED, &RESOURCE_BOX_USED_DEFAULT, FALSE); resourceEntry = visu_config_file_addFloatArrayEntry(VISU_CONFIG_FILE_RESOURCE, FLAG_RESOURCE_BOX_COLOR, DESC_RESOURCE_BOX_COLOR, 3, rgbDefault, rgColor, FALSE); resourceEntry = visu_config_file_addFloatArrayEntry(VISU_CONFIG_FILE_RESOURCE, FLAG_RESOURCE_BOX_LINE, DESC_RESOURCE_BOX_LINE, 1, &LINE_WIDTH_DEFAULT, rgWidth, FALSE); resourceEntry = visu_config_file_addStippleArrayEntry(VISU_CONFIG_FILE_RESOURCE, FLAG_RESOURCE_BOX_STIPPLE, DESC_RESOURCE_BOX_STIPPLE, 2, stippleDefault); visu_config_file_entry_setVersion(resourceEntry, 3.4f); resourceEntry = visu_config_file_addFloatArrayEntry(VISU_CONFIG_FILE_RESOURCE, FLAG_RESOURCE_BOX_SIDE, DESC_RESOURCE_BOX_SIDE, 4, sideRGBDefault, rgColor, FALSE); visu_config_file_entry_setVersion(resourceEntry, 3.8f); visu_config_file_addExportFunction(VISU_CONFIG_FILE_RESOURCE, exportResourcesBox); defaultBox = (VisuGlExtBox*)0; /* Connect the overloading methods. */ G_OBJECT_CLASS(klass)->dispose = visu_gl_ext_box_dispose; G_OBJECT_CLASS(klass)->set_property = visu_gl_ext_box_set_property; G_OBJECT_CLASS(klass)->get_property = visu_gl_ext_box_get_property; VISU_GL_EXT_CLASS(klass)->rebuild = visu_gl_ext_box_rebuild; VISU_GL_EXT_CLASS(klass)->draw = visu_gl_ext_box_draw; /** * VisuGlExtBox::color: * * Store the color of the box. * * Since: 3.8 */ g_object_class_override_property(G_OBJECT_CLASS(klass), COLOR_PROP, "color"); /** * VisuGlExtBox::side-color: * * Store the color of the sides drawn on the primary cell when the * box is expanded. * * Since: 3.8 */ properties[SIDE_COLOR_PROP] = g_param_spec_boxed("side-color", "side color", "color of the primary cell sides", TOOL_TYPE_COLOR, G_PARAM_READWRITE); g_object_class_install_property(G_OBJECT_CLASS(klass), SIDE_COLOR_PROP, properties[SIDE_COLOR_PROP]); /** * VisuGlExtBox::width: * * Store the line width of the box. * * Since: 3.8 */ g_object_class_override_property(G_OBJECT_CLASS(klass), WIDTH_PROP, "width"); /** * VisuGlExtBox::stipple: * * Store the line stipple pattern of the box. * * Since: 3.8 */ g_object_class_override_property(G_OBJECT_CLASS(klass), STIPPLE_PROP, "stipple"); /** * VisuGlExtBox::expand-stipple: * * Store the line stipple pattern of the extension lines of the box. * * Since: 3.8 */ properties[EXT_STIPPLE_PROP] = g_param_spec_uint("expand-stipple", "extension line stipple", "rendering line stipple pattern of extension", 0, 65535, stippleDefault[1], G_PARAM_READWRITE); g_object_class_install_property(G_OBJECT_CLASS(klass), EXT_STIPPLE_PROP, properties[EXT_STIPPLE_PROP]); /** * VisuGlExtBox::basis: * * Store the #VisuBoxed object that defines the box. If %NULL, a * cartesian basis-set is assumed. * * Since: 3.8 */ properties[BOX_PROP] = g_param_spec_object("basis", "basis-set", "provides the basis-set to draw the box", VISU_TYPE_BOX, G_PARAM_READWRITE); g_object_class_install_property(G_OBJECT_CLASS(klass), BOX_PROP, properties[BOX_PROP]); } static void visu_gl_ext_box_init(VisuGlExtBox *obj) { DBG_fprintf(stderr, "Extension Box: initializing a new object (%p).\n", (gpointer)obj); obj->priv = visu_gl_ext_box_get_instance_private(obj); obj->priv->dispose_has_run = FALSE; /* Private data. */ tool_matrix_setIdentity(obj->priv->matrix); obj->priv->rgb[0] = rgbDefault[0]; obj->priv->rgb[1] = rgbDefault[1]; obj->priv->rgb[2] = rgbDefault[2]; obj->priv->rgb[3] = 1.f; obj->priv->sideRGB[0] = sideRGBDefault[0]; obj->priv->sideRGB[1] = sideRGBDefault[1]; obj->priv->sideRGB[2] = sideRGBDefault[2]; obj->priv->sideRGB[3] = sideRGBDefault[3]; obj->priv->lineWidth = LINE_WIDTH_DEFAULT; obj->priv->lineStipple[0] = stippleDefault[0]; obj->priv->lineStipple[1] = stippleDefault[1]; obj->priv->box = (VisuBox*)0; obj->priv->box_signal = 0; /* withBasis = RESOURCE_WITH_BASIS_DEFAULT; */ g_signal_connect_object(VISU_CONFIG_FILE_RESOURCE, "parsed::" FLAG_RESOURCE_BOX_USED, G_CALLBACK(onEntryUsed), (gpointer)obj, G_CONNECT_SWAPPED); g_signal_connect_object(VISU_CONFIG_FILE_RESOURCE, "parsed::" FLAG_RESOURCE_BOX_COLOR, G_CALLBACK(onEntryColor), (gpointer)obj, G_CONNECT_SWAPPED); g_signal_connect_object(VISU_CONFIG_FILE_RESOURCE, "parsed::" FLAG_RESOURCE_BOX_LINE, G_CALLBACK(onEntryWidth), (gpointer)obj, G_CONNECT_SWAPPED); g_signal_connect_object(VISU_CONFIG_FILE_RESOURCE, "parsed::" FLAG_RESOURCE_BOX_STIPPLE, G_CALLBACK(onEntryStipple), (gpointer)obj, G_CONNECT_SWAPPED); g_signal_connect_object(VISU_CONFIG_FILE_RESOURCE, "parsed::" FLAG_RESOURCE_BOX_SIDE, G_CALLBACK(onEntrySide), (gpointer)obj, G_CONNECT_SWAPPED); if (!defaultBox) defaultBox = obj; } /* This method can be called several times. It should unref all of its reference to GObjects. */ static void visu_gl_ext_box_dispose(GObject* obj) { VisuGlExtBox *box; DBG_fprintf(stderr, "Extension Box: dispose object %p.\n", (gpointer)obj); box = VISU_GL_EXT_BOX(obj); if (box->priv->dispose_has_run) return; box->priv->dispose_has_run = TRUE; /* Disconnect signals. */ visu_gl_ext_box_setBox(box, (VisuBox*)0); /* Chain up to the parent class */ G_OBJECT_CLASS(visu_gl_ext_box_parent_class)->dispose(obj); } static void visu_gl_ext_box_get_property(GObject* obj, guint property_id, GValue *value, GParamSpec *pspec) { VisuGlExtBox *self = VISU_GL_EXT_BOX(obj); DBG_fprintf(stderr, "Extension Box: get property '%s' -> ", g_param_spec_get_name(pspec)); switch (property_id) { case COLOR_PROP: g_value_take_boxed(value, tool_color_new(self->priv->rgb)); DBG_fprintf(stderr, "%gx%gx%g.\n", self->priv->rgb[0], self->priv->rgb[1], self->priv->rgb[2]); break; case SIDE_COLOR_PROP: g_value_take_boxed(value, tool_color_new(self->priv->sideRGB)); DBG_fprintf(stderr, "%gx%gx%g.\n", self->priv->rgb[0], self->priv->rgb[1], self->priv->rgb[2]); break; case WIDTH_PROP: g_value_set_float(value, self->priv->lineWidth); DBG_fprintf(stderr, "%g.\n", self->priv->lineWidth); break; case STIPPLE_PROP: g_value_set_uint(value, (guint)self->priv->lineStipple[0]); DBG_fprintf(stderr, "%d.\n", (guint)self->priv->lineStipple[0]); break; case EXT_STIPPLE_PROP: g_value_set_uint(value, (guint)self->priv->lineStipple[1]); DBG_fprintf(stderr, "%d.\n", (guint)self->priv->lineStipple[1]); break; case BOX_PROP: g_value_set_object(value, self->priv->box); DBG_fprintf(stderr, "%p.\n", (gpointer)self->priv->box); break; default: /* We don't have any other property... */ G_OBJECT_WARN_INVALID_PROPERTY_ID(obj, property_id, pspec); break; } } static void visu_gl_ext_box_set_property(GObject* obj, guint property_id, const GValue *value, GParamSpec *pspec) { ToolColor *color; VisuGlExtBox *self = VISU_GL_EXT_BOX(obj); DBG_fprintf(stderr, "Extension Box: set property '%s' -> ", g_param_spec_get_name(pspec)); switch (property_id) { case COLOR_PROP: color = (ToolColor*)g_value_get_boxed(value); _setRGB((VisuGlExtLined*)self, color->rgba, TOOL_COLOR_MASK_RGBA); DBG_fprintf(stderr, "%gx%gx%g.\n", self->priv->rgb[0], self->priv->rgb[1], self->priv->rgb[2]); break; case SIDE_COLOR_PROP: color = (ToolColor*)g_value_get_boxed(value); visu_gl_ext_box_setSideRGB(self, color->rgba, TOOL_COLOR_MASK_RGBA); DBG_fprintf(stderr, "%gx%gx%g.\n", self->priv->rgb[0], self->priv->rgb[1], self->priv->rgb[2]); break; case WIDTH_PROP: _setLineWidth((VisuGlExtLined*)self, g_value_get_float(value)); DBG_fprintf(stderr, "%g.\n", self->priv->lineWidth); break; case STIPPLE_PROP: _setLineStipple((VisuGlExtLined*)self, (guint16)g_value_get_uint(value)); DBG_fprintf(stderr, "%d.\n", (guint)self->priv->lineStipple[0]); break; case EXT_STIPPLE_PROP: visu_gl_ext_box_setExpandStipple(self, (guint16)g_value_get_uint(value)); DBG_fprintf(stderr, "%d.\n", (guint)self->priv->lineStipple[1]); break; case BOX_PROP: visu_gl_ext_box_setBox(self, VISU_BOX(g_value_get_object(value))); DBG_fprintf(stderr, "%p.\n", (gpointer)g_value_get_object(value)); break; default: /* We don't have any other property... */ G_OBJECT_WARN_INVALID_PROPERTY_ID(obj, property_id, pspec); break; } } /** * visu_gl_ext_box_new: * @name: (allow-none): the name to give to the extension (default is #VISU_GL_EXT_BOX_ID). * * Creates a new #VisuGlExt to draw a box. * * Since: 3.7 * * Returns: a pointer to the #VisuGlExt it created or * NULL otherwise. */ VisuGlExtBox* visu_gl_ext_box_new(const gchar *name) { char *name_ = VISU_GL_EXT_BOX_ID; char *description = _("Draw a box representing the limit of the area."); DBG_fprintf(stderr,"Extension Box: new object.\n"); return g_object_new(VISU_TYPE_GL_EXT_BOX, "name", (name)?name:name_, "label", _(name), "description", description, "nGlObj", 1, "priority", VISU_GL_EXT_PRIORITY_LOW, NULL); } /** * visu_gl_ext_box_setBox: * @box: the #VisuGlExtBox object to attach to. * @boxObj: the box to get the definition of. * * Attach the #VisuBox to draw the frame of. * * Since: 3.7 * * Returns: TRUE if the #VisuBox model is actually changed. **/ gboolean visu_gl_ext_box_setBox(VisuGlExtBox *box, VisuBox *boxObj) { g_return_val_if_fail(VISU_IS_GL_EXT_BOX(box), FALSE); DBG_fprintf(stderr, "Extension Box: set box %p.\n", (gpointer)boxObj); if (box->priv->box) { g_signal_handler_disconnect(G_OBJECT(box->priv->box), box->priv->box_signal); g_object_unref(box->priv->box); } if (boxObj) { g_object_ref(boxObj); box->priv->box_signal = g_signal_connect(G_OBJECT(boxObj), "SizeChanged", G_CALLBACK(onSizeChanged), (gpointer)box); } else box->priv->box_signal = 0; box->priv->box = boxObj; visu_gl_ext_setDirty(VISU_GL_EXT(box), TRUE); g_object_notify_by_pspec(G_OBJECT(box), properties[BOX_PROP]); return TRUE; } /** * visu_gl_ext_box_setBasis: * @box: the #VisuGlExtBox object to attach to. * @orig: (array fixed-size=3): the origin. * @mat: (array fixed-size=9): the basis-set. * * Define the box to draw with a simple matrix basis-set and an origin. * * Since: 3.7 * * Returns: TRUE if value is actually changed. **/ gboolean visu_gl_ext_box_setBasis(VisuGlExtBox *box, float orig[3], float mat[3][3]) { g_return_val_if_fail(VISU_IS_GL_EXT_BOX(box), FALSE); visu_gl_ext_box_setBox(box, (VisuBox*)0); visu_gl_ext_setTranslation(VISU_GL_EXT(box), orig); memcpy(box->priv->matrix, mat, sizeof(float) * 9); visu_gl_ext_setDirty(VISU_GL_EXT(box), TRUE); return TRUE; } static gboolean _setRGB(VisuGlExtLined *box, float rgb[3], int mask) { VisuGlExtBoxPrivate *self; g_return_val_if_fail(VISU_IS_GL_EXT_BOX(box), FALSE); self = VISU_GL_EXT_BOX(box)->priv; if (mask & TOOL_COLOR_MASK_R) self->rgb[0] = rgb[0]; if (mask & TOOL_COLOR_MASK_G) self->rgb[1] = rgb[1]; if (mask & TOOL_COLOR_MASK_B) self->rgb[2] = rgb[2]; visu_gl_ext_setDirty(VISU_GL_EXT(box), TRUE); return TRUE; } /** * visu_gl_ext_box_setSideRGB: * @box: the #VisuGlExtBox to update. * @rgba: (array fixed-size=4): a four floats array with values (0 <= values <= 1) for the * red, the green, the blue color and the alpha channel. Only values * specified by the mask are really relevant. * @mask: use #TOOL_COLOR_MASK_R, #TOOL_COLOR_MASK_G, * #TOOL_COLOR_MASK_B, #TOOL_COLOR_MASK_A or a combinaison to indicate * what values in the @rgba array must be taken into account. * * Change the colour to represent the side of the super-cell. A * channel alpha of zero, means that the box is rendered as wire-frame * only. The sides are indeed drawn only if the box has expansion. * * Since: 3.7 * * Returns: TRUE if value is actually changed. */ gboolean visu_gl_ext_box_setSideRGB(VisuGlExtBox *box, float rgba[4], int mask) { gboolean diff = FALSE; g_return_val_if_fail(VISU_IS_GL_EXT_BOX(box), FALSE); if (mask & TOOL_COLOR_MASK_R && box->priv->sideRGB[0] != rgba[0]) { box->priv->sideRGB[0] = rgba[0]; diff = TRUE; } if (mask & TOOL_COLOR_MASK_G && box->priv->sideRGB[1] != rgba[1]) { box->priv->sideRGB[1] = rgba[1]; diff = TRUE; } if (mask & TOOL_COLOR_MASK_B && box->priv->sideRGB[2] != rgba[2]) { box->priv->sideRGB[2] = rgba[2]; diff = TRUE; } if (mask & TOOL_COLOR_MASK_A && box->priv->sideRGB[3] != rgba[3]) { box->priv->sideRGB[3] = rgba[3]; diff = TRUE; } if (!diff) return FALSE; visu_gl_ext_setDirty(VISU_GL_EXT(box), TRUE); g_object_notify_by_pspec(G_OBJECT(box), properties[SIDE_COLOR_PROP]); return TRUE; } static gboolean _setLineWidth(VisuGlExtLined *box, float width) { VisuGlExtBoxPrivate *self; g_return_val_if_fail(VISU_IS_GL_EXT_BOX(box), FALSE); self = VISU_GL_EXT_BOX(box)->priv; self->lineWidth = width; visu_gl_ext_setDirty(VISU_GL_EXT(box), TRUE); return TRUE; } static gboolean _setLineStipple(VisuGlExtLined *box, guint16 stipple) { VisuGlExtBoxPrivate *self; g_return_val_if_fail(VISU_IS_GL_EXT_BOX(box), FALSE); self = VISU_GL_EXT_BOX(box)->priv; self->lineStipple[0] = stipple; visu_gl_ext_setDirty(VISU_GL_EXT(box), TRUE); return TRUE; } /** * visu_gl_ext_box_setExpandStipple: * @box: the #VisuGlExtBox to update. * @stipple: a pattern for line stipple in OpenGL. * * Method used to change the value of the parameter box_line_stipple * (expanded part). * * Returns: TRUE if value is actually changed. */ gboolean visu_gl_ext_box_setExpandStipple(VisuGlExtBox *box, guint16 stipple) { g_return_val_if_fail(VISU_IS_GL_EXT_BOX(box), FALSE); if (stipple == box->priv->lineStipple[1]) return FALSE; box->priv->lineStipple[1] = stipple; visu_gl_ext_setDirty(VISU_GL_EXT(box), TRUE); g_object_notify_by_pspec(G_OBJECT(box), properties[EXT_STIPPLE_PROP]); return TRUE; } /* Get methods. */ static float* _getRGB(const VisuGlExtLined *box) { g_return_val_if_fail(VISU_IS_GL_EXT_BOX(box), rgbDefault); return ((VisuGlExtBox*)box)->priv->rgb; } /** * visu_gl_ext_box_getSideRGB: * @box: the #VisuGlExtBox to inquire. * * Read the colour components of the sides of the box (in [0;1]). * * Returns: all the colour values of the current box line. */ float* visu_gl_ext_box_getSideRGB(VisuGlExtBox *box) { g_return_val_if_fail(VISU_IS_GL_EXT_BOX(box), rgbDefault); return box->priv->sideRGB; } static float _getLineWidth(const VisuGlExtLined *box) { g_return_val_if_fail(VISU_IS_GL_EXT_BOX(box), LINE_WIDTH_DEFAULT); return ((VisuGlExtBox*)box)->priv->lineWidth; } static guint16 _getLineStipple(const VisuGlExtLined *box) { g_return_val_if_fail(VISU_IS_GL_EXT_BOX(box), stippleDefault[0]); return ((VisuGlExtBox*)box)->priv->lineStipple[0]; } /** * visu_gl_ext_box_getExpandStipple: * @box: the #VisuGlExtBox to inquire. * * Read the line stipple pattern used for box (expanded part). * * Returns: the value of current box line pattern. */ guint16 visu_gl_ext_box_getExpandStipple(VisuGlExtBox *box) { g_return_val_if_fail(VISU_IS_GL_EXT_BOX(box), stippleDefault[1]); return box->priv->lineStipple[1]; } /****************/ /* Private part */ /****************/ static void visu_gl_ext_box_rebuild(VisuGlExt *ext) { visu_gl_ext_box_draw(ext); } static void onSizeChanged(VisuBox *boxObj _U_, gfloat extens _U_, gpointer user_data) { DBG_fprintf(stderr, "Extension Box: caught the 'SizeChanged' signal.\n"); visu_gl_ext_setDirty(VISU_GL_EXT(user_data), TRUE); } static void onEntryUsed(VisuGlExtBox *box, VisuConfigFileEntry *entry _U_, VisuConfigFile *obj _U_) { visu_gl_ext_setActive(VISU_GL_EXT(box), RESOURCE_BOX_USED_DEFAULT); } static void onEntryColor(VisuGlExtBox *box, VisuConfigFileEntry *entry _U_, VisuConfigFile *obj _U_) { visu_gl_ext_lined_setRGBA(VISU_GL_EXT_LINED(box), rgbDefault, TOOL_COLOR_MASK_RGBA); } static void onEntryWidth(VisuGlExtBox *box, VisuConfigFileEntry *entry _U_, VisuConfigFile *obj _U_) { visu_gl_ext_lined_setWidth(VISU_GL_EXT_LINED(box), LINE_WIDTH_DEFAULT); } static void onEntryStipple(VisuGlExtBox *box, VisuConfigFileEntry *entry _U_, VisuConfigFile *obj _U_) { visu_gl_ext_lined_setStipple(VISU_GL_EXT_LINED(box), stippleDefault[0]); visu_gl_ext_box_setExpandStipple(box, stippleDefault[1]); } static void onEntrySide(VisuGlExtBox *box, VisuConfigFileEntry *entry _U_, VisuConfigFile *obj _U_) { visu_gl_ext_box_setSideRGB(box, sideRGBDefault, TOOL_COLOR_MASK_RGBA); } static void drawSides(float ext[3], float v[8][3], float rgba[4]) { glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA); glDisable(GL_CULL_FACE); glColor4fv(rgba); if (ext[0] > 0.) { glBegin(GL_POLYGON); glVertex3fv(v[0]); glVertex3fv(v[3]); glVertex3fv(v[7]); glVertex3fv(v[4]); glEnd(); glBegin(GL_POLYGON); glVertex3fv(v[6]); glVertex3fv(v[5]); glVertex3fv(v[1]); glVertex3fv(v[2]); glEnd(); } if (ext[1] > 0.) { glBegin(GL_POLYGON); glVertex3fv(v[0]); glVertex3fv(v[1]); glVertex3fv(v[5]); glVertex3fv(v[4]); glEnd(); glBegin(GL_POLYGON); glVertex3fv(v[6]); glVertex3fv(v[7]); glVertex3fv(v[3]); glVertex3fv(v[2]); glEnd(); } if (ext[2] > 0.) { glBegin(GL_POLYGON); glVertex3fv(v[0]); glVertex3fv(v[1]); glVertex3fv(v[2]); glVertex3fv(v[3]); glEnd(); glBegin(GL_POLYGON); glVertex3fv(v[4]); glVertex3fv(v[5]); glVertex3fv(v[6]); glVertex3fv(v[7]); glEnd(); } glEnable(GL_CULL_FACE); glCullFace(GL_BACK); } /** * visu_gl_ext_box_draw: * @box: a #VisuBox object. * * This method create a compile list that draw a box for the given @box. */ static void visu_gl_ext_box_draw(VisuGlExt *ext) { int i, j, k; float v[8][3], e[8][3]; float extens[3] = {0.f, 0.f, 0.f}, centre[3]; float material[5] = {.5f, .5f, .2f, .5f, .0f}; GLUquadricObj *obj; gchar strLg[64]; VisuGlExtBox *box; /* Nothing to draw; */ g_return_if_fail(VISU_IS_GL_EXT_BOX(ext)); box = VISU_GL_EXT_BOX(ext); DBG_fprintf(stderr, "Extension box: creating box for" " VisuBox %p.\n", (gpointer)box->priv->box); if (box->priv->box) { visu_box_getVertices(box->priv->box, v, FALSE); if (visu_box_getExtensionActive(box->priv->box)) visu_box_getExtension(box->priv->box, extens); } else { /* We build the vertex array. */ v[0][0] = 0.f; v[0][1] = 0.f; v[0][2] = 0.f; v[1][0] = box->priv->matrix[0][0]; v[1][1] = box->priv->matrix[1][0]; v[1][2] = box->priv->matrix[2][0]; v[2][0] = box->priv->matrix[0][0] + box->priv->matrix[0][1]; v[2][1] = box->priv->matrix[1][0] + box->priv->matrix[1][1]; v[2][2] = box->priv->matrix[2][0] + box->priv->matrix[2][1]; v[3][0] = box->priv->matrix[0][1]; v[3][1] = box->priv->matrix[1][1]; v[3][2] = box->priv->matrix[2][1]; v[4][0] = box->priv->matrix[0][2]; v[4][1] = box->priv->matrix[1][2]; v[4][2] = box->priv->matrix[2][2]; v[5][0] = box->priv->matrix[0][0] + box->priv->matrix[0][2]; v[5][1] = box->priv->matrix[1][0] + box->priv->matrix[1][2]; v[5][2] = box->priv->matrix[2][0] + box->priv->matrix[2][2]; v[6][0] = box->priv->matrix[0][0] + box->priv->matrix[0][1] + box->priv->matrix[0][2]; v[6][1] = box->priv->matrix[1][0] + box->priv->matrix[1][1] + box->priv->matrix[1][2]; v[6][2] = box->priv->matrix[2][0] + box->priv->matrix[2][1] + box->priv->matrix[2][2]; v[7][0] = box->priv->matrix[0][1] + box->priv->matrix[0][2]; v[7][1] = box->priv->matrix[1][1] + box->priv->matrix[1][2]; v[7][2] = box->priv->matrix[2][1] + box->priv->matrix[2][2]; extens[0] = 1.f; extens[1] = 1.f; extens[2] = 1.f; } glDeleteLists(visu_gl_ext_getGlList(ext), 1); visu_gl_ext_startDrawing(ext); glDisable(GL_LIGHTING); glDisable(GL_DITHER); glLineWidth(box->priv->lineWidth); /* We draw sides of the box, if specified. */ if ((extens[0] > 0. || extens[1] > 0. || extens[2] > 0.) && box->priv->sideRGB[3] == 1.f) drawSides(extens, v, box->priv->sideRGB); /* Draw the basic lines. */ glColor3fv(box->priv->rgb); if (box->priv->lineStipple[0] != 65535) { glEnable(GL_LINE_STIPPLE); glLineStipple(1, box->priv->lineStipple[0]); } glBegin(GL_LINES); glVertex3fv(v[0]); glVertex3fv(v[1]); glVertex3fv(v[1]); glVertex3fv(v[2]); glVertex3fv(v[2]); glVertex3fv(v[3]); glVertex3fv(v[3]); glVertex3fv(v[0]); glVertex3fv(v[4]); glVertex3fv(v[5]); glVertex3fv(v[5]); glVertex3fv(v[6]); glVertex3fv(v[6]); glVertex3fv(v[7]); glVertex3fv(v[7]); glVertex3fv(v[4]); glVertex3fv(v[0]); glVertex3fv(v[4]); glVertex3fv(v[1]); glVertex3fv(v[5]); glVertex3fv(v[2]); glVertex3fv(v[6]); glVertex3fv(v[3]); glVertex3fv(v[7]); glEnd(); if (box->priv->lineStipple[0] != 65535) glDisable(GL_LINE_STIPPLE); /* Draw the extension lines. */ if (extens[0] > 0. || extens[1] > 0. || extens[2] > 0.) { glColor3fv(box->priv->rgb); /* We draw then the expansion lines. */ if (box->priv->lineStipple[1] != 65535) { glEnable(GL_LINE_STIPPLE); glLineStipple(1, box->priv->lineStipple[1]); } for (i = 1; i < 8; i++) { e[i][0] = v[i][0] - v[0][0]; e[i][1] = v[i][1] - v[0][1]; e[i][2] = v[i][2] - v[0][2]; } glTranslatef(v[0][0], v[0][1], v[0][2]); glBegin(GL_LINES); /* X coordinate. */ for (j = -(int)extens[1]; j < 2 + (int)extens[1]; j++) for (k = -(int)extens[2]; k < 2 + (int)extens[2]; k++) { glVertex3f(-extens[0] * e[1][0] + e[3][0] * j + e[4][0] * k, -extens[0] * e[1][1] + e[3][1] * j + e[4][1] * k, -extens[0] * e[1][2] + e[3][2] * j + e[4][2] * k); if ((j == 0 || j == 1) && (k == 0 || k == 1)) { glVertex3f(e[3][0] * j + e[4][0] * k, e[3][1] * j + e[4][1] * k, e[3][2] * j + e[4][2] * k); glVertex3f(e[1][0] + e[3][0] * j + e[4][0] * k, e[1][1] + e[3][1] * j + e[4][1] * k, e[1][2] + e[3][2] * j + e[4][2] * k); } glVertex3f((1. + extens[0]) * e[1][0] + e[3][0] * j + e[4][0] * k, (1. + extens[0]) * e[1][1] + e[3][1] * j + e[4][1] * k, (1. + extens[0]) * e[1][2] + e[3][2] * j + e[4][2] * k); } /* Y coordinate. */ for (i = -(int)extens[0]; i < 2 + (int)extens[0]; i++) for (k = -(int)extens[2]; k < 2 + (int)extens[2]; k++) { glVertex3f(-extens[1] * e[3][0] + e[1][0] * i + e[4][0] * k, -extens[1] * e[3][1] + e[1][1] * i + e[4][1] * k, -extens[1] * e[3][2] + e[1][2] * i + e[4][2] * k); if ((i == 0 || i == 1) && (k == 0 || k == 1)) { glVertex3f(e[1][0] * i + e[4][0] * k, e[1][1] * i + e[4][1] * k, e[1][2] * i + e[4][2] * k); glVertex3f(e[3][0] + e[1][0] * i + e[4][0] * k, e[3][1] + e[1][1] * i + e[4][1] * k, e[3][2] + e[1][2] * i + e[4][2] * k); } glVertex3f((1. + extens[1]) * e[3][0] + e[1][0] * i + e[4][0] * k, (1. + extens[1]) * e[3][1] + e[1][1] * i + e[4][1] * k, (1. + extens[1]) * e[3][2] + e[1][2] * i + e[4][2] * k); } /* Z coordinate. */ for (i = -(int)extens[0]; i < 2 + (int)extens[0]; i++) for (j = -(int)extens[1]; j < 2 + (int)extens[1]; j++) { glVertex3f(-extens[2] * e[4][0] + e[1][0] * i + e[3][0] * j, -extens[2] * e[4][1] + e[1][1] * i + e[3][1] * j, -extens[2] * e[4][2] + e[1][2] * i + e[3][2] * j); if ((j == 0 || j == 1) && (i == 0 || i == 1)) { glVertex3f(e[1][0] * i + e[3][0] * j, e[1][1] * i + e[3][1] * j, e[1][2] * i + e[3][2] * j); glVertex3f(e[4][0] + e[1][0] * i + e[3][0] * j, e[4][1] + e[1][1] * i + e[3][1] * j, e[4][2] + e[1][2] * i + e[3][2] * j); } glVertex3f((1. + extens[2]) * e[4][0] + e[1][0] * i + e[3][0] * j, (1. + extens[2]) * e[4][1] + e[1][1] * i + e[3][1] * j, (1. + extens[2]) * e[4][2] + e[1][2] * i + e[3][2] * j); } glEnd(); if (box->priv->lineStipple[1] != 65535) glDisable(GL_LINE_STIPPLE); glTranslatef(-v[0][0], -v[0][1], -v[0][2]); } /* We draw sides of the box, if specified. */ if ((extens[0] > 0. || extens[1] > 0. || extens[2] > 0.) && box->priv->sideRGB[3] > 0.f && box->priv->sideRGB[3] < 1.f) drawSides(extens, v, box->priv->sideRGB); glEnable(GL_LIGHTING); glEnable(GL_DITHER); /* WARNING: it is the default! */ /* Draw the basis set if needed. */ if (FALSE) { visu_box_getCentre(box->priv->box, centre); obj = gluNewQuadric(); visu_gl_setHighlightColor((VisuGl*)0, material, box->priv->rgb, 1.f); /* Draw the basis set. */ glPushMatrix(); glTranslated(0., 0., 0.); glRotated(90., 0, 1, 0); visu_gl_drawSmoothArrow(obj, VISU_GL_ARROW_BOTTOM_CENTERED, basisLength - 0.3f, 0.1f, 10, NULL, 0.3f, 0.2f, 10, NULL); glRasterPos3f(0.0f, 0.0f, basisLength); sprintf(strLg, _("x: %7.3f"), centre[0]); visu_gl_text_drawChars(strLg, VISU_GL_TEXT_SMALL); glPopMatrix(); glPushMatrix(); glTranslated(0., 0., 0.); glRotated(-90., 1, 0, 0); visu_gl_drawSmoothArrow(obj, VISU_GL_ARROW_BOTTOM_CENTERED, basisLength - 0.3f, 0.1f, 10, NULL, 0.3f, 0.2f, 10, NULL); glRasterPos3f(0.0f, 0.0f, basisLength); sprintf(strLg, _("y: %7.3f"), centre[1]); visu_gl_text_drawChars(strLg, VISU_GL_TEXT_SMALL); glPopMatrix(); glPushMatrix(); glTranslated(0., 0., 0.); visu_gl_drawSmoothArrow(obj, VISU_GL_ARROW_BOTTOM_CENTERED, basisLength - 0.3f, 0.1f, 10, NULL, 0.3f, 0.2f, 10, NULL); glRasterPos3f(0.0f, 0.0f, basisLength); sprintf(strLg, _("z: %7.3f"), centre[2]); visu_gl_text_drawChars(strLg, VISU_GL_TEXT_SMALL); glPopMatrix(); gluDeleteQuadric(obj); } glLineWidth(1.); visu_gl_ext_completeDrawing(ext); } /* Parameters & resources*/ /* Export function that is called by visu_module to write the values of resources to a file. */ static void exportResourcesBox(GString *data, VisuData *dataObj _U_) { if (!defaultBox) return; visu_config_file_exportComment(data, DESC_RESOURCE_BOX_USED); visu_config_file_exportEntry(data, FLAG_RESOURCE_BOX_USED, NULL, "%d", visu_gl_ext_getActive(VISU_GL_EXT(defaultBox))); visu_config_file_exportComment(data, DESC_RESOURCE_BOX_COLOR); visu_config_file_exportEntry(data, FLAG_RESOURCE_BOX_COLOR, NULL, "%4.3f %4.3f %4.3f", defaultBox->priv->rgb[0], defaultBox->priv->rgb[1], defaultBox->priv->rgb[2]); visu_config_file_exportComment(data, DESC_RESOURCE_BOX_LINE); visu_config_file_exportEntry(data, FLAG_RESOURCE_BOX_LINE, NULL, "%4.0f", defaultBox->priv->lineWidth); visu_config_file_exportComment(data, DESC_RESOURCE_BOX_STIPPLE); visu_config_file_exportEntry(data, FLAG_RESOURCE_BOX_STIPPLE, NULL, "%d %d", defaultBox->priv->lineStipple[0], defaultBox->priv->lineStipple[1]); visu_config_file_exportComment(data, DESC_RESOURCE_BOX_SIDE); visu_config_file_exportEntry(data, FLAG_RESOURCE_BOX_SIDE, NULL, "%4.3f %4.3f %4.3f %4.3f", defaultBox->priv->sideRGB[0], defaultBox->priv->sideRGB[1], defaultBox->priv->sideRGB[2], defaultBox->priv->sideRGB[3]); visu_config_file_exportComment(data, ""); } v_sim-3.8.0/src/extensions/box.h000066400000000000000000000111111370110300500165470ustar00rootroot00000000000000/* EXTRAITS DE LA LICENCE Copyright CEA, contributeurs : Luc BILLARD et Damien CALISTE, laboratoire L_Sim, (2001-2005) Adresse mèl : BILLARD, non joignable par mèl ; CALISTE, damien P caliste AT cea P fr. Ce logiciel est un programme informatique servant à visualiser des structures atomiques dans un rendu pseudo-3D. Ce logiciel est régi par la licence CeCILL soumise au droit français et respectant les principes de diffusion des logiciels libres. Vous pouvez utiliser, modifier et/ou redistribuer ce programme sous les conditions de la licence CeCILL telle que diffusée par le CEA, le CNRS et l'INRIA sur le site "http://www.cecill.info". Le fait que vous puissiez accéder à cet en-tête signifie que vous avez pris connaissance de la licence CeCILL, et que vous en avez accepté les termes (cf. le fichier Documentation/licence.fr.txt fourni avec ce logiciel). */ /* LICENCE SUM UP Copyright CEA, contributors : Luc BILLARD et Damien CALISTE, laboratoire L_Sim, (2001-2005) E-mail address: BILLARD, not reachable any more ; CALISTE, damien P caliste AT cea P fr. This software is a computer program whose purpose is to visualize atomic configurations in 3D. This software is governed by the CeCILL license under French law and abiding by the rules of distribution of free software. You can use, modify and/ or redistribute the software under the terms of the CeCILL license as circulated by CEA, CNRS and INRIA at the following URL "http://www.cecill.info". The fact that you are presently reading this means that you have had knowledge of the CeCILL license and that you accept its terms. You can find a copy of this licence shipped with this software at Documentation/licence.en.txt. */ #ifndef BOX_H #define BOX_H #include "frame.h" #include #include #include #include "iface_lined.h" /** * VISU_TYPE_GL_EXT_BOX: * * return the type of #VisuGlExtBox. * * Since: 3.7 */ #define VISU_TYPE_GL_EXT_BOX (visu_gl_ext_box_get_type ()) /** * VISU_GL_EXT_BOX: * @obj: a #GObject to cast. * * Cast the given @obj into #VisuGlExtBox type. * * Since: 3.7 */ #define VISU_GL_EXT_BOX(obj) (G_TYPE_CHECK_INSTANCE_CAST(obj, VISU_TYPE_GL_EXT_BOX, VisuGlExtBox)) /** * VISU_GL_EXT_BOX_CLASS: * @klass: a #GObjectClass to cast. * * Cast the given @klass into #VisuGlExtBoxClass. * * Since: 3.7 */ #define VISU_GL_EXT_BOX_CLASS(klass) (G_TYPE_CHECK_CLASS_CAST(klass, VISU_TYPE_GL_EXT_BOX, VisuGlExtBoxClass)) /** * VISU_IS_GL_EXT_BOX: * @obj: a #GObject to test. * * Test if the given @ogj is of the type of #VisuGlExtBox object. * * Since: 3.7 */ #define VISU_IS_GL_EXT_BOX(obj) (G_TYPE_CHECK_INSTANCE_TYPE(obj, VISU_TYPE_GL_EXT_BOX)) /** * VISU_IS_GL_EXT_BOX_CLASS: * @klass: a #GObjectClass to test. * * Test if the given @klass is of the type of #VisuGlExtBoxClass class. * * Since: 3.7 */ #define VISU_IS_GL_EXT_BOX_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE(klass, VISU_TYPE_GL_EXT_BOX)) /** * VISU_GL_EXT_BOX_GET_CLASS: * @obj: a #GObject to get the class of. * * It returns the class of the given @obj. * * Since: 3.7 */ #define VISU_GL_EXT_BOX_GET_CLASS(obj) (G_TYPE_INSTANCE_GET_CLASS(obj, VISU_TYPE_GL_EXT_BOX, VisuGlExtBoxClass)) typedef struct _VisuGlExtBox VisuGlExtBox; typedef struct _VisuGlExtBoxPrivate VisuGlExtBoxPrivate; typedef struct _VisuGlExtBoxClass VisuGlExtBoxClass; /** * VisuGlExtBox: * * An opaque structure. * * Since: 3.7 */ struct _VisuGlExtBox { VisuGlExt parent; VisuGlExtBoxPrivate *priv; }; /** * VisuGlExtBoxClass: * @parent: the parent class; * * A short way to identify #_VisuGlExtBoxClass structure. * * Since: 3.7 */ struct _VisuGlExtBoxClass { VisuGlExtClass parent; }; /** * visu_gl_ext_box_get_type: * * This method returns the type of #VisuGlExtBox, use * VISU_TYPE_GL_EXT_BOX instead. * * Since: 3.7 * * Returns: the type of #VisuGlExtBox. */ GType visu_gl_ext_box_get_type(void); /** * VISU_GL_EXT_BOX_ID: * * The id used to identify this extension, see * visu_gl_ext_rebuild() for instance. */ #define VISU_GL_EXT_BOX_ID "Box" VisuGlExtBox* visu_gl_ext_box_new(const gchar *name); gboolean visu_gl_ext_box_setBox(VisuGlExtBox *box, VisuBox *boxObj); gboolean visu_gl_ext_box_setBasis(VisuGlExtBox *box, float orig[3], float mat[3][3]); gboolean visu_gl_ext_box_setSideRGB(VisuGlExtBox *box, float rgba[4], int mask); gboolean visu_gl_ext_box_setExpandStipple(VisuGlExtBox *box, guint16 stipple); float* visu_gl_ext_box_getSideRGB(VisuGlExtBox *box); guint16 visu_gl_ext_box_getExpandStipple(VisuGlExtBox *box); #endif v_sim-3.8.0/src/extensions/box_legend.c000066400000000000000000000311341370110300500200670ustar00rootroot00000000000000/* EXTRAITS DE LA LICENCE Copyright CEA, contributeurs : Luc BILLARD et Damien CALISTE, laboratoire L_Sim, (2001-2005) Adresse mèl : BILLARD, non joignable par mèl ; CALISTE, damien P caliste AT cea P fr. Ce logiciel est un programme informatique servant à visualiser des structures atomiques dans un rendu pseudo-3D. Ce logiciel est régi par la licence CeCILL soumise au droit français et respectant les principes de diffusion des logiciels libres. Vous pouvez utiliser, modifier et/ou redistribuer ce programme sous les conditions de la licence CeCILL telle que diffusée par le CEA, le CNRS et l'INRIA sur le site "http://www.cecill.info". Le fait que vous puissiez accéder à cet en-tête signifie que vous avez pris connaissance de la licence CeCILL, et que vous en avez accepté les termes (cf. le fichier Documentation/licence.fr.txt fourni avec ce logiciel). */ /* LICENCE SUM UP Copyright CEA, contributors : Luc BILLARD et Damien CALISTE, laboratoire L_Sim, (2001-2005) E-mail address: BILLARD, not reachable any more ; CALISTE, damien P caliste AT cea P fr. This software is a computer program whose purpose is to visualize atomic configurations in 3D. This software is governed by the CeCILL license under French law and abiding by the rules of distribution of free software. You can use, modify and/ or redistribute the software under the terms of the CeCILL license as circulated by CEA, CNRS and INRIA at the following URL "http://www.cecill.info". The fact that you are presently reading this means that you have had knowledge of the CeCILL license and that you accept its terms. You can find a copy of this licence shipped with this software at Documentation/licence.en.txt. */ #include "box_legend.h" #include #include #include #include #include /** * SECTION:box_legend * @short_description: Draw a legend describing the box. * * This extension allows V_Sim to draw a small box with box * information like the box size. */ /* A resource to control the position to render the box lengths. */ #define FLAG_RESOURCE_LEGEND_POSITION "box_legend_position" #define DESC_RESOURCE_LEGEND_POSITION "Position of the legend area for the box ; two floating point values (0. <= v <= 1.)" static float POSITION_DEFAULT[2] = {.5f, 0.f}; /* A resource to control if the box lengths are printed. */ #define FLAG_RESOURCE_BOX_LENGTHS "box_show_lengths" #define DESC_RESOURCE_BOX_LENGTHS "Print the box lengths ; boolean (0 or 1)" static gboolean WITH_LENGTHS_DEFAULT = FALSE; static void exportResourcesBoxLegend(GString *data, VisuData *dataObj); /** * VisuGlExtBoxLegendClass: * @parent: the parent class; * * A short way to identify #_VisuGlExtBoxLegendClass structure. * * Since: 3.7 */ /** * VisuGlExtBoxLegend: * * An opaque structure. * * Since: 3.7 */ /** * VisuGlExtBoxLegendPrivate: * * Private fields for #VisuGlExtBoxLegend objects. * * Since: 3.7 */ struct _VisuGlExtBoxLegendPrivate { gboolean dispose_has_run; /* Box definition. */ VisuBox *box; gulong box_signal; }; static VisuGlExtBoxLegend* defaultBoxLegend; static void visu_gl_ext_box_legend_dispose(GObject* obj); static void visu_gl_ext_box_legend_rebuild(VisuGlExt *ext); static void visu_gl_ext_box_legend_draw(const VisuGlExtFrame *frame); static gboolean visu_gl_ext_box_legend_isValid(const VisuGlExtFrame *frame); /* Callbacks. */ static void onBoxSizeChanged(VisuBox *box, gfloat extens, gpointer user_data); static void onEntryLgUsed(VisuGlExtBoxLegend *lg, VisuConfigFileEntry *entry, VisuConfigFile *obj); static void onEntryLgPosition(VisuGlExtBoxLegend *lg, VisuConfigFileEntry *entry, VisuConfigFile *obj); G_DEFINE_TYPE_WITH_CODE(VisuGlExtBoxLegend, visu_gl_ext_box_legend, VISU_TYPE_GL_EXT_FRAME, G_ADD_PRIVATE(VisuGlExtBoxLegend)) static void visu_gl_ext_box_legend_class_init(VisuGlExtBoxLegendClass *klass) { float rgPos[2] = {0.f, 1.f}; VisuConfigFileEntry *resourceEntry; DBG_fprintf(stderr, "Extension Box: creating the class of the object (legend).\n"); /* DBG_fprintf(stderr, " - adding new signals ;\n"); */ DBG_fprintf(stderr, " - adding new resources ;\n"); resourceEntry = visu_config_file_addBooleanEntry(VISU_CONFIG_FILE_RESOURCE, FLAG_RESOURCE_BOX_LENGTHS, DESC_RESOURCE_BOX_LENGTHS, &WITH_LENGTHS_DEFAULT, FALSE); visu_config_file_entry_setVersion(resourceEntry, 3.6f); resourceEntry = visu_config_file_addFloatArrayEntry(VISU_CONFIG_FILE_RESOURCE, FLAG_RESOURCE_LEGEND_POSITION, DESC_RESOURCE_LEGEND_POSITION, 2, POSITION_DEFAULT, rgPos, FALSE); visu_config_file_entry_setVersion(resourceEntry, 3.7f); visu_config_file_addExportFunction(VISU_CONFIG_FILE_RESOURCE, exportResourcesBoxLegend); defaultBoxLegend = (VisuGlExtBoxLegend*)0; /* Connect the overloading methods. */ G_OBJECT_CLASS(klass)->dispose = visu_gl_ext_box_legend_dispose; VISU_GL_EXT_CLASS(klass)->rebuild = visu_gl_ext_box_legend_rebuild; VISU_GL_EXT_FRAME_CLASS(klass)->draw = visu_gl_ext_box_legend_draw; VISU_GL_EXT_FRAME_CLASS(klass)->isValid = visu_gl_ext_box_legend_isValid; } static void visu_gl_ext_box_legend_init(VisuGlExtBoxLegend *obj) { DBG_fprintf(stderr, "Extension Box: initializing a new legend object (%p).\n", (gpointer)obj); obj->priv = visu_gl_ext_box_legend_get_instance_private(obj); obj->priv->dispose_has_run = FALSE; /* Private data. */ obj->priv->box = (VisuBox*)0; obj->priv->box_signal = 0; g_signal_connect_object(VISU_CONFIG_FILE_RESOURCE, "parsed::" FLAG_RESOURCE_BOX_LENGTHS, G_CALLBACK(onEntryLgUsed), (gpointer)obj, G_CONNECT_SWAPPED); g_signal_connect_object(VISU_CONFIG_FILE_RESOURCE, "parsed::" FLAG_RESOURCE_LEGEND_POSITION, G_CALLBACK(onEntryLgPosition), (gpointer)obj, G_CONNECT_SWAPPED); if (!defaultBoxLegend) defaultBoxLegend = obj; } static void visu_gl_ext_box_legend_dispose(GObject* obj) { VisuGlExtBoxLegend *legend; DBG_fprintf(stderr, "Extension Box: dispose legend object %p.\n", (gpointer)obj); legend = VISU_GL_EXT_BOX_LEGEND(obj); if (legend->priv->dispose_has_run) return; legend->priv->dispose_has_run = TRUE; /* Disconnect signals. */ visu_gl_ext_box_legend_setBox(legend, (VisuBox*)0); /* Chain up to the parent class */ G_OBJECT_CLASS(visu_gl_ext_box_legend_parent_class)->dispose(obj); } /** * visu_gl_ext_box_legend_new: * @name: (allow-none): the name to give to the extension. * * Creates a new #VisuGlExt to draw a legend with the box size. * * Since: 3.7 * * Returns: a pointer to the #VisuGlExt it created or * NULL otherwise. */ VisuGlExtBoxLegend* visu_gl_ext_box_legend_new(const gchar *name) { char *name_ = VISU_GL_EXT_BOX_LEGEND_ID; char *description = _("Draw informations related to the box."); VisuGlExt *extensionBox; #define BOX_WIDTH 100 #define BOX_HEIGHT 55 DBG_fprintf(stderr,"Extension Box: new legend object.\n"); extensionBox = VISU_GL_EXT(g_object_new(VISU_TYPE_GL_EXT_BOX_LEGEND, "active", WITH_LENGTHS_DEFAULT, "name", (name)?name:name_, "label", _(name), "description", description, "nGlObj", 1, "priority", VISU_GL_EXT_PRIORITY_LAST, "saveState", TRUE, NULL)); visu_gl_ext_frame_setTitle(VISU_GL_EXT_FRAME(extensionBox), _("Box lengths")); visu_gl_ext_frame_setPosition(VISU_GL_EXT_FRAME(extensionBox), POSITION_DEFAULT[0], POSITION_DEFAULT[1]); visu_gl_ext_frame_setRequisition(VISU_GL_EXT_FRAME(extensionBox), BOX_WIDTH, BOX_HEIGHT); return VISU_GL_EXT_BOX_LEGEND(extensionBox); } /** * visu_gl_ext_box_legend_setBox: * @legend: The #VisuGlExtBoxLegend to attached to. * @boxObj: the box to get the size of. * * Attach an #VisuGlView to render to and setup the box to get the * size of also. * * Since: 3.7 * * Returns: TRUE if model is changed. **/ gboolean visu_gl_ext_box_legend_setBox(VisuGlExtBoxLegend *legend, VisuBox *boxObj) { g_return_val_if_fail(VISU_IS_GL_EXT_BOX_LEGEND(legend), FALSE); DBG_fprintf(stderr, "Extension Box Legend: set box %p.\n", (gpointer)boxObj); if (legend->priv->box == boxObj) return FALSE; if (legend->priv->box) { g_signal_handler_disconnect(G_OBJECT(legend->priv->box), legend->priv->box_signal); g_object_unref(legend->priv->box); } if (boxObj) { g_object_ref(boxObj); legend->priv->box_signal = g_signal_connect(G_OBJECT(boxObj), "SizeChanged", G_CALLBACK(onBoxSizeChanged), (gpointer)legend); } else legend->priv->box_signal = 0; legend->priv->box = boxObj; visu_gl_ext_setDirty(VISU_GL_EXT(legend), TRUE); return TRUE; } /****************/ /* Private part */ /****************/ static void visu_gl_ext_box_legend_rebuild(VisuGlExt *ext) { visu_gl_text_rebuildFontList(); if (VISU_GL_EXT_GET_CLASS(ext)->draw) VISU_GL_EXT_GET_CLASS(ext)->draw(ext); } static void onBoxSizeChanged(VisuBox *boxObj _U_, gfloat extens _U_, gpointer user_data) { DBG_fprintf(stderr, "Extension Box: caught the 'SizeChanged' signal.\n"); visu_gl_ext_setDirty(VISU_GL_EXT(user_data), TRUE); } static void onEntryLgUsed(VisuGlExtBoxLegend *lg, VisuConfigFileEntry *entry _U_, VisuConfigFile *obj _U_) { visu_gl_ext_setActive(VISU_GL_EXT(lg), WITH_LENGTHS_DEFAULT); } static void onEntryLgPosition(VisuGlExtBoxLegend *lg, VisuConfigFileEntry *entry _U_, VisuConfigFile *obj _U_) { visu_gl_ext_frame_setPosition(VISU_GL_EXT_FRAME(lg), POSITION_DEFAULT[0], POSITION_DEFAULT[1]); } static gboolean visu_gl_ext_box_legend_isValid(const VisuGlExtFrame *frame) { g_return_val_if_fail(VISU_IS_GL_EXT_BOX_LEGEND(frame), FALSE); /* Nothing to draw if no data is associated to the current rendering window. */ return (VISU_GL_EXT_BOX_LEGEND(frame)->priv->box != (VisuBox*)0); } static void visu_gl_ext_box_legend_draw(const VisuGlExtFrame *frame) { gchar strLg[64]; float vertices[8][3], box[3]; VisuGlExtBoxLegend *legend; g_return_if_fail(VISU_IS_GL_EXT_BOX_LEGEND(frame)); legend = VISU_GL_EXT_BOX_LEGEND(frame); visu_box_getVertices(legend->priv->box, vertices, FALSE); box[0] = sqrt((vertices[1][0] - vertices[0][0]) * (vertices[1][0] - vertices[0][0]) + (vertices[1][1] - vertices[0][1]) * (vertices[1][1] - vertices[0][1]) + (vertices[1][2] - vertices[0][2]) * (vertices[1][2] - vertices[0][2])); box[1] = sqrt((vertices[3][0] - vertices[0][0]) * (vertices[3][0] - vertices[0][0]) + (vertices[3][1] - vertices[0][1]) * (vertices[3][1] - vertices[0][1]) + (vertices[3][2] - vertices[0][2]) * (vertices[3][2] - vertices[0][2])); box[2] = sqrt((vertices[4][0] - vertices[0][0]) * (vertices[4][0] - vertices[0][0]) + (vertices[4][1] - vertices[0][1]) * (vertices[4][1] - vertices[0][1]) + (vertices[4][2] - vertices[0][2]) * (vertices[4][2] - vertices[0][2])); glColor3fv(frame->fontRGB); glRasterPos2f(0.f, frame->height * 2.f / 3.f); sprintf(strLg, " %s: %7.3f", "x", box[0]); visu_gl_text_drawChars(strLg, VISU_GL_TEXT_SMALL); glRasterPos2f(0.f, frame->height / 3.f); sprintf(strLg, " %s: %7.3f", "y", box[1]); visu_gl_text_drawChars(strLg, VISU_GL_TEXT_SMALL); glRasterPos2f(0.f, 0.f); sprintf(strLg, " %s: %7.3f", "z", box[2]); visu_gl_text_drawChars(strLg, VISU_GL_TEXT_SMALL); } /* Parameters & resources*/ /* Export function that is called by visu_module to write the values of resources to a file. */ static void exportResourcesBoxLegend(GString *data, VisuData *dataObj _U_) { float xpos, ypos; if (!defaultBoxLegend) return; visu_config_file_exportComment(data, DESC_RESOURCE_BOX_LENGTHS); visu_config_file_exportEntry(data, FLAG_RESOURCE_BOX_LENGTHS, NULL, "%d", visu_gl_ext_getActive(VISU_GL_EXT(defaultBoxLegend))); visu_gl_ext_frame_getPosition(VISU_GL_EXT_FRAME(defaultBoxLegend), &xpos, &ypos); visu_config_file_exportComment(data, DESC_RESOURCE_LEGEND_POSITION); visu_config_file_exportEntry(data, FLAG_RESOURCE_LEGEND_POSITION, NULL, "%4.3f %4.3f", xpos, ypos); visu_config_file_exportComment(data, ""); } v_sim-3.8.0/src/extensions/box_legend.h000066400000000000000000000104431370110300500200740ustar00rootroot00000000000000/* EXTRAITS DE LA LICENCE Copyright CEA, contributeurs : Luc BILLARD et Damien CALISTE, laboratoire L_Sim, (2001-2005) Adresse mèl : BILLARD, non joignable par mèl ; CALISTE, damien P caliste AT cea P fr. Ce logiciel est un programme informatique servant à visualiser des structures atomiques dans un rendu pseudo-3D. Ce logiciel est régi par la licence CeCILL soumise au droit français et respectant les principes de diffusion des logiciels libres. Vous pouvez utiliser, modifier et/ou redistribuer ce programme sous les conditions de la licence CeCILL telle que diffusée par le CEA, le CNRS et l'INRIA sur le site "http://www.cecill.info". Le fait que vous puissiez accéder à cet en-tête signifie que vous avez pris connaissance de la licence CeCILL, et que vous en avez accepté les termes (cf. le fichier Documentation/licence.fr.txt fourni avec ce logiciel). */ /* LICENCE SUM UP Copyright CEA, contributors : Luc BILLARD et Damien CALISTE, laboratoire L_Sim, (2001-2005) E-mail address: BILLARD, not reachable any more ; CALISTE, damien P caliste AT cea P fr. This software is a computer program whose purpose is to visualize atomic configurations in 3D. This software is governed by the CeCILL license under French law and abiding by the rules of distribution of free software. You can use, modify and/ or redistribute the software under the terms of the CeCILL license as circulated by CEA, CNRS and INRIA at the following URL "http://www.cecill.info". The fact that you are presently reading this means that you have had knowledge of the CeCILL license and that you accept its terms. You can find a copy of this licence shipped with this software at Documentation/licence.en.txt. */ #ifndef BOX_LEGEND_H #define BOX_LEGEND_H #include "frame.h" #include #include /** * VISU_TYPE_GL_EXT_BOX_LEGEND: * * return the type of #VisuGlExtBoxLegend. * * Since: 3.7 */ #define VISU_TYPE_GL_EXT_BOX_LEGEND (visu_gl_ext_box_legend_get_type ()) /** * VISU_GL_EXT_BOX_LEGEND: * @obj: a #GObject to cast. * * Cast the given @obj into #VisuGlExtBoxLegend type. * * Since: 3.7 */ #define VISU_GL_EXT_BOX_LEGEND(obj) (G_TYPE_CHECK_INSTANCE_CAST(obj, VISU_TYPE_GL_EXT_BOX_LEGEND, VisuGlExtBoxLegend)) /** * VISU_GL_EXT_BOX_LEGEND_CLASS: * @klass: a #GObjectClass to cast. * * Cast the given @klass into #VisuGlExtBoxLegendClass. * * Since: 3.7 */ #define VISU_GL_EXT_BOX_LEGEND_CLASS(klass) (G_TYPE_CHECK_CLASS_CAST(klass, VISU_TYPE_GL_EXT_BOX_LEGEND, VisuGlExtBoxLegendClass)) /** * VISU_IS_GL_EXT_BOX_LEGEND: * @obj: a #GObject to test. * * Test if the given @obj is of the type of #VisuGlExtBoxLegend object. * * Since: 3.7 */ #define VISU_IS_GL_EXT_BOX_LEGEND(obj) (G_TYPE_CHECK_INSTANCE_TYPE(obj, VISU_TYPE_GL_EXT_BOX_LEGEND)) /** * VISU_IS_GL_EXT_BOX_LEGEND_CLASS: * @klass: a #GObjectClass to test. * * Test if the given @klass is of the type of #VisuGlExtBoxLegendClass class. * * Since: 3.7 */ #define VISU_IS_GL_EXT_BOX_LEGEND_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE(klass, VISU_TYPE_GL_EXT_BOX_LEGEND)) /** * VISU_GL_EXT_BOX_LEGEND_GET_CLASS: * @obj: a #GObject to get the class of. * * It returns the class of the given @obj. * * Since: 3.7 */ #define VISU_GL_EXT_BOX_LEGEND_GET_CLASS(obj) (G_TYPE_INSTANCE_GET_CLASS(obj, VISU_TYPE_GL_EXT_BOX_LEGEND, VisuGlExtBoxLegendClass)) typedef struct _VisuGlExtBoxLegend VisuGlExtBoxLegend; typedef struct _VisuGlExtBoxLegendPrivate VisuGlExtBoxLegendPrivate; typedef struct _VisuGlExtBoxLegendClass VisuGlExtBoxLegendClass; struct _VisuGlExtBoxLegend { VisuGlExtFrame parent; VisuGlExtBoxLegendPrivate *priv; }; struct _VisuGlExtBoxLegendClass { VisuGlExtFrameClass parent; }; /** * visu_gl_ext_box_legend_get_type: * * This method returns the type of #VisuGlExtBoxLegend, use * VISU_TYPE_GL_EXT_BOX_LEGEND instead. * * Since: 3.7 * * Returns: the type of #VisuGlExtBoxLegend. */ GType visu_gl_ext_box_legend_get_type(void); /** * VISU_GL_EXT_BOX_LEGEND_ID: * * The id used to identify this extension, see * visu_gl_ext_rebuild() for instance. */ #define VISU_GL_EXT_BOX_LEGEND_ID "Box legend" VisuGlExtBoxLegend* visu_gl_ext_box_legend_new(const gchar *name); gboolean visu_gl_ext_box_legend_setBox(VisuGlExtBoxLegend *legend, VisuBox *boxObj); #endif v_sim-3.8.0/src/extensions/fogAndBGColor.c000066400000000000000000000507231370110300500203740ustar00rootroot00000000000000/* EXTRAITS DE LA LICENCE Copyright CEA, contributeurs : Luc BILLARD et Damien CALISTE, laboratoire L_Sim, (2001-2005) Adresse mèl : BILLARD, non joignable par mèl ; CALISTE, damien P caliste AT cea P fr. Ce logiciel est un programme informatique servant à visualiser des structures atomiques dans un rendu pseudo-3D. Ce logiciel est régi par la licence CeCILL soumise au droit français et respectant les principes de diffusion des logiciels libres. Vous pouvez utiliser, modifier et/ou redistribuer ce programme sous les conditions de la licence CeCILL telle que diffusée par le CEA, le CNRS et l'INRIA sur le site "http://www.cecill.info". Le fait que vous puissiez accéder à cet en-tête signifie que vous avez pris connaissance de la licence CeCILL, et que vous en avez accepté les termes (cf. le fichier Documentation/licence.fr.txt fourni avec ce logiciel). */ /* LICENCE SUM UP Copyright CEA, contributors : Luc BILLARD et Damien CALISTE, laboratoire L_Sim, (2001-2005) E-mail address: BILLARD, not reachable any more ; CALISTE, damien P caliste AT cea P fr. This software is a computer program whose purpose is to visualize atomic configurations in 3D. This software is governed by the CeCILL license under French law and abiding by the rules of distribution of free software. You can use, modify and/ or redistribute the software under the terms of the CeCILL license as circulated by CEA, CNRS and INRIA at the following URL "http://www.cecill.info". The fact that you are presently reading this means that you have had knowledge of the CeCILL license and that you accept its terms. You can find a copy of this licence shipped with this software at Documentation/licence.en.txt. */ #include "fogAndBGColor.h" #include #include #include #include #include #include #include #include #include /* For the GdkPixbuf, to be removed later. */ #include #include #include /** * SECTION:fogAndBGColor * @short_description: Handle the background colour and the fog. * * This module is used to support a background colour and to tune the * fog. This last one can be turn on or off and its colour can be * either a user defined one or the one of the background. The fog is * a linear blending into the fog colour. It starts at a given z * position (in the camera basis set) and ends at a lower z. */ /** * VisuGlExtBgClass: * @parent: the parent class; * * A short way to identify #_VisuGlExtBgClass structure. * * Since: 3.7 */ /** * VisuGlExtBg: * * An opaque structure. * * Since: 3.7 */ /** * VisuGlExtBgPrivate: * * Private fields for #VisuGlExtBg objects. * * Since: 3.7 */ struct _VisuGlExtBgPrivate { gboolean dispose_has_run; /* Handling the background image. */ guchar *bgImage; gboolean bgImageAlpha, bgImageFit, bgImageFollowZoom; guint bgImageW, bgImageH; gchar *bgImageTitle; float bgImageZoomInit, bgImageZoom, bgImageZoomRatioInit; float bgImageXsInit, bgImageXs, bgImageXs0; float bgImageYsInit, bgImageYs, bgImageYs0; gchar *bgFile; gboolean withLabel; /* Signals for the current view. */ VisuGlView *view; gulong widthHeight_signal; gulong transx_signal, transy_signal, gross_signal; }; enum { PROP_0, BG_IMAGE_PROP, BG_LABEL_PROP, N_PROP, }; static GParamSpec *_properties[N_PROP]; static void visu_gl_ext_bg_finalize(GObject* obj); static void visu_gl_ext_bg_dispose(GObject* obj); static void visu_gl_ext_bg_get_property(GObject* obj, guint property_id, GValue *value, GParamSpec *pspec); static void visu_gl_ext_bg_set_property(GObject* obj, guint property_id, const GValue *value, GParamSpec *pspec); static void visu_gl_ext_bg_rebuild(VisuGlExt *ext); static void visu_gl_ext_bg_draw(VisuGlExt *bg); static gboolean visu_gl_ext_bg_setGlView(VisuGlExt *bg, VisuGlView *view); /* Local callbacks */ static void onBgImageRescale(VisuGlView *view, gpointer data); static void onCameraChange(VisuGlView *view, GParamSpec *pspec, gpointer data); G_DEFINE_TYPE_WITH_CODE(VisuGlExtBg, visu_gl_ext_bg, VISU_TYPE_GL_EXT, G_ADD_PRIVATE(VisuGlExtBg)) static void visu_gl_ext_bg_class_init(VisuGlExtBgClass *klass) { DBG_fprintf(stderr, "Extension Bg: creating the class of the object.\n"); /* DBG_fprintf(stderr, " - adding new signals ;\n"); */ /* Connect the overloading methods. */ G_OBJECT_CLASS(klass)->dispose = visu_gl_ext_bg_dispose; G_OBJECT_CLASS(klass)->finalize = visu_gl_ext_bg_finalize; G_OBJECT_CLASS(klass)->set_property = visu_gl_ext_bg_set_property; G_OBJECT_CLASS(klass)->get_property = visu_gl_ext_bg_get_property; VISU_GL_EXT_CLASS(klass)->rebuild = visu_gl_ext_bg_rebuild; VISU_GL_EXT_CLASS(klass)->draw = visu_gl_ext_bg_draw; VISU_GL_EXT_CLASS(klass)->setGlView = visu_gl_ext_bg_setGlView; /** * VisuGlNodeScene::background-file: * * Path to the background image. * * Since: 3.8 */ _properties[BG_IMAGE_PROP] = g_param_spec_string("background-file", "Background file", "path to the background image.", "", G_PARAM_READWRITE); /** * VisuGlNodeScene::display-background-filename: * * Display or not the background filename. * * Since: 3.8 */ _properties[BG_LABEL_PROP] = g_param_spec_boolean("display-background-filename", "Display background filename", "display or not the background filename.", FALSE, G_PARAM_READWRITE); g_object_class_install_properties(G_OBJECT_CLASS(klass), N_PROP, _properties); } static void visu_gl_ext_bg_init(VisuGlExtBg *obj) { DBG_fprintf(stderr, "Extension Bg: initializing a new object (%p).\n", (gpointer)obj); obj->priv = visu_gl_ext_bg_get_instance_private(obj); obj->priv->dispose_has_run = FALSE; /* Private data. */ obj->priv->bgImage = (guchar*)0; obj->priv->bgImageTitle = (gchar*)0; obj->priv->bgImageFollowZoom = FALSE; obj->priv->bgImageZoomInit = obj->priv->bgImageZoom = -1.f; obj->priv->bgImageZoomRatioInit = 1.f; obj->priv->bgImageXsInit = obj->priv->bgImageXs = 0.5f; obj->priv->bgImageXs0 = 0.f; obj->priv->bgImageYsInit = obj->priv->bgImageYs = 0.5f; obj->priv->bgImageYs0 = 0.f; obj->priv->view = (VisuGlView*)0; obj->priv->widthHeight_signal = 0; obj->priv->bgFile = (gchar*)0; obj->priv->withLabel = FALSE; } static void visu_gl_ext_bg_dispose(GObject* obj) { VisuGlExtBg *bg; DBG_fprintf(stderr, "Extension Bg: dispose object %p.\n", (gpointer)obj); bg = VISU_GL_EXT_BG(obj); if (bg->priv->dispose_has_run) return; bg->priv->dispose_has_run = TRUE; /* Disconnect signals. */ visu_gl_ext_bg_setGlView(VISU_GL_EXT(bg), (VisuGlView*)0); /* Chain up to the parent class */ G_OBJECT_CLASS(visu_gl_ext_bg_parent_class)->dispose(obj); } static void visu_gl_ext_bg_finalize(GObject* obj) { VisuGlExtBg *bg; g_return_if_fail(obj); DBG_fprintf(stderr, "Extension Bg: finalize object %p.\n", (gpointer)obj); bg = VISU_GL_EXT_BG(obj); /* Free privs elements. */ DBG_fprintf(stderr, "Extension Bg: free private bg.\n"); g_free(bg->priv->bgImage); g_free(bg->priv->bgImageTitle); g_free(bg->priv->bgFile); /* Chain up to the parent class */ DBG_fprintf(stderr, "Extension Bg: chain to parent.\n"); G_OBJECT_CLASS(visu_gl_ext_bg_parent_class)->finalize(obj); DBG_fprintf(stderr, "Extension Bg: freeing ... OK.\n"); } static void visu_gl_ext_bg_get_property(GObject* obj, guint property_id, GValue *value, GParamSpec *pspec) { VisuGlExtBg *self = VISU_GL_EXT_BG(obj); DBG_fprintf(stderr, "Extension Bg: get property '%s' -> ", g_param_spec_get_name(pspec)); switch (property_id) { case BG_IMAGE_PROP: g_value_set_string(value, self->priv->bgFile); DBG_fprintf(stderr, "%s.\n", g_value_get_string(value)); break; case BG_LABEL_PROP: g_value_set_boolean(value, self->priv->withLabel); DBG_fprintf(stderr, "%d.\n", g_value_get_boolean(value)); break; default: /* We don't have any other property... */ G_OBJECT_WARN_INVALID_PROPERTY_ID(obj, property_id, pspec); break; } } static void visu_gl_ext_bg_set_property(GObject* obj, guint property_id, const GValue *value, GParamSpec *pspec) { VisuGlExtBg *self = VISU_GL_EXT_BG(obj); GError *error; gchar *path; DBG_fprintf(stderr, "Extension Bg: set property '%s' -> ", g_param_spec_get_name(pspec)); switch (property_id) { case BG_IMAGE_PROP: DBG_fprintf(stderr, "%s.\n", g_value_get_string(value)); error = (GError*)0; visu_gl_ext_bg_setFile(self, g_value_get_string(value), &error); if (error) { g_warning("%s", error->message); g_error_free(error); } break; case BG_LABEL_PROP: DBG_fprintf(stderr, "%d.\n", g_value_get_boolean(value)); self->priv->withLabel = g_value_get_boolean(value); path = self->priv->bgFile; self->priv->bgFile = (gchar*)0; error = (GError*)0; visu_gl_ext_bg_setFile(self, path, &error); if (error) { g_warning("%s", error->message); g_error_free(error); } g_free(path); break; default: /* We don't have any other property... */ G_OBJECT_WARN_INVALID_PROPERTY_ID(obj, property_id, pspec); break; } } /** * visu_gl_ext_bg_new: * @name: (allow-none): the name to give to the extension (default is #VISU_GL_EXT_BG_ID). * * Creates a new #VisuGlExt to draw bg. * * Since: 3.7 * * Returns: a pointer to the #VisuGlExt it created or * NULL otherwise. */ VisuGlExtBg* visu_gl_ext_bg_new(const gchar *name) { char *name_ = VISU_GL_EXT_BG_ID; char *description = _("Set an image as background."); VisuGlExt *extensionBg; DBG_fprintf(stderr,"Extension Bg: new object.\n"); extensionBg = VISU_GL_EXT(g_object_new(VISU_TYPE_GL_EXT_BG, "name", (name)?name:name_, "label", _(name), "description", description, "nGlObj", 1, "priority", VISU_GL_EXT_PRIORITY_BACKGROUND, "saveState", TRUE, NULL)); return VISU_GL_EXT_BG(extensionBg); } static gboolean visu_gl_ext_bg_setGlView(VisuGlExt *bg, VisuGlView *view) { VisuGlExtBgPrivate *priv = ((VisuGlExtBg*)bg)->priv; /* No change to be done. */ if (view == priv->view) return FALSE; if (priv->view) { g_signal_handler_disconnect(G_OBJECT(priv->view), priv->widthHeight_signal); g_signal_handler_disconnect(G_OBJECT(priv->view), priv->transx_signal); g_signal_handler_disconnect(G_OBJECT(priv->view), priv->transy_signal); g_signal_handler_disconnect(G_OBJECT(priv->view), priv->gross_signal); g_object_unref(priv->view); } if (view) { g_object_ref(view); priv->widthHeight_signal = g_signal_connect(G_OBJECT(view), "WidthHeightChanged", G_CALLBACK(onBgImageRescale), (gpointer)bg); priv->transx_signal = g_signal_connect(G_OBJECT(view), "notify::trans-x", G_CALLBACK(onCameraChange), (gpointer)bg); priv->transy_signal = g_signal_connect(G_OBJECT(view), "notify::trans-y", G_CALLBACK(onCameraChange), (gpointer)bg); priv->gross_signal = g_signal_connect(G_OBJECT(view), "notify::zoom", G_CALLBACK(onCameraChange), (gpointer)bg); } else { priv->widthHeight_signal = 0; } priv->view = view; visu_gl_ext_setDirty(bg, TRUE); return TRUE; } /** * visu_gl_ext_bg_setFile: * @bg: a #VisuGlExtBg object. * @path: a file path * @error: an error location. * * Loads @path and store it as a background image for the scene, see * visu_gl_ext_bg_setImage(). * * Since: 3.8 * * Returns: FALSE if an error occured. **/ gboolean visu_gl_ext_bg_setFile(VisuGlExtBg *bg, const gchar *path, GError **error) { GdkPixbuf *pixbuf; gchar *title; gboolean fit; g_return_val_if_fail(VISU_IS_GL_EXT_BG(bg), FALSE); if (!g_strcmp0(bg->priv->bgFile, path)) return FALSE; g_free(bg->priv->bgFile); bg->priv->bgFile = (gchar*)0; if (!path) { visu_gl_ext_bg_setImage(bg, (guchar*)0, 0, 0, FALSE, (const gchar*)0, TRUE); g_object_notify_by_pspec(G_OBJECT(bg), _properties[BG_IMAGE_PROP]); return TRUE; } pixbuf = gdk_pixbuf_new_from_file(path, error); if (!pixbuf) { visu_gl_ext_bg_setImage(bg, (guchar*)0, 0, 0, FALSE, (const gchar*)0, TRUE); g_object_notify_by_pspec(G_OBJECT(bg), _properties[BG_IMAGE_PROP]); return TRUE; } fit = TRUE; title = g_path_get_basename(path); if (!strcmp(title, "logo_grey.png")) { fit = FALSE; g_free(title); title = (gchar*)0; } visu_gl_ext_bg_setImage(bg, gdk_pixbuf_get_pixels(pixbuf), gdk_pixbuf_get_width(pixbuf), gdk_pixbuf_get_height(pixbuf), gdk_pixbuf_get_has_alpha(pixbuf), bg->priv->withLabel ? title : (const gchar*)0, fit); g_object_unref(pixbuf); g_free(title); bg->priv->bgFile = g_strdup(path); g_object_notify_by_pspec(G_OBJECT(bg), _properties[BG_IMAGE_PROP]); return TRUE; } /** * visu_gl_ext_bg_setImage: * @bg: a #VisuGlExtBg object. * @imageData: (allow-none): raw image data in RGB or RGBA format ; * @width: the width ; * @height: the height ; * @alpha: TRUE if the image is RGBA ; * @title: (allow-none): an optional title (can be NULL). * @fit: a boolean (default is TRUE). * * Draw the @imageData on the background. The image is scaled to the * viewport dimensions, keeping the width/height ratio, if @fit is set * to TRUE. If @title is not NULL, the title is also printed on the * background. The image data are copied and can be free after this * call. */ void visu_gl_ext_bg_setImage(VisuGlExtBg *bg, const guchar *imageData, guint width, guint height, gboolean alpha, const gchar *title, gboolean fit) { guint n; g_return_if_fail(VISU_IS_GL_EXT_BG(bg)); g_free(bg->priv->bgImage); bg->priv->bgImage = (guchar*)0; g_free(bg->priv->bgImageTitle); bg->priv->bgImageTitle = (gchar*)0; visu_gl_ext_setDirty(VISU_GL_EXT(bg), TRUE); if (!imageData) return; DBG_fprintf(stderr, "Extension bg: copy image to memory buffer.\n"); /* We copy the image to some correct size buffer. */ bg->priv->bgImageW = width; bg->priv->bgImageH = height; n = (alpha)?4:3; bg->priv->bgImage = g_memdup(imageData, sizeof(guchar) * bg->priv->bgImageW * bg->priv->bgImageH * n); bg->priv->bgImageAlpha = alpha; if (title) bg->priv->bgImageTitle = g_strdup(title); bg->priv->bgImageFit = fit; bg->priv->bgImageZoomInit = bg->priv->bgImageZoom = -1.f; bg->priv->bgImageZoomRatioInit = 1.f; bg->priv->bgImageXsInit = bg->priv->bgImageXs = 0.5f; bg->priv->bgImageXs0 = 0.f; bg->priv->bgImageYsInit = bg->priv->bgImageYs = 0.5f; bg->priv->bgImageYs0 = 0.f; } /** * visu_gl_ext_bg_setFollowCamera: * @bg: a #VisuGlExtBg object. * @follow: a boolean. * @zoomInit: a floating point value. * @xs: a floating point value. * @ys: a floating point value. * * When @follow is TRUE, the size and the position of the background * image is adjusted with every camera change. * * Since: 3.7 * * Returns: TRUE if the following status has been changed. */ gboolean visu_gl_ext_bg_setFollowCamera(VisuGlExtBg *bg, gboolean follow, float zoomInit, float xs, float ys) { g_return_val_if_fail(VISU_IS_GL_EXT_BG(bg), FALSE); if (follow == bg->priv->bgImageFollowZoom) return FALSE; bg->priv->bgImageFollowZoom = follow; if (follow) { bg->priv->bgImageZoomInit = bg->priv->bgImageZoom = zoomInit; bg->priv->bgImageXsInit = bg->priv->bgImageXs = xs; bg->priv->bgImageYsInit = bg->priv->bgImageYs = ys; } else { bg->priv->bgImageZoomRatioInit *= bg->priv->bgImageZoom / bg->priv->bgImageZoomInit; bg->priv->bgImageXs0 -= bg->priv->bgImageXs - bg->priv->bgImageXsInit; bg->priv->bgImageYs0 -= bg->priv->bgImageYs - bg->priv->bgImageYsInit; } visu_gl_ext_setDirty(VISU_GL_EXT(bg), TRUE); return TRUE; } /** * visu_gl_ext_bg_setCamera: * @bg: a #VisuGlExtBg object. * @zoom: a floating point value. * @xs: a floating point value. * @ys: a floating point value. * * If the background image is in follow mode, see * visu_gl_ext_bg_setFollowCamera(), this routine is used to update * the current camera settings of the background image. * * Since: 3.7 * * Returns: TRUE if the settings are indeed changed. */ gboolean visu_gl_ext_bg_setCamera(VisuGlExtBg *bg, float zoom, float xs, float ys) { g_return_val_if_fail(VISU_IS_GL_EXT_BG(bg), FALSE); if (zoom == bg->priv->bgImageZoom && xs == bg->priv->bgImageXs && ys == bg->priv->bgImageYs) return FALSE; if (bg->priv->bgImageFollowZoom) { bg->priv->bgImageZoom = zoom; bg->priv->bgImageXs = xs; bg->priv->bgImageYs = ys; } return bg->priv->bgImageFollowZoom; } /****************/ /* Private part */ /****************/ static void visu_gl_ext_bg_draw(VisuGlExt *ext) { VisuGlExtBg *bg = VISU_GL_EXT_BG(ext); int viewport[4]; float x, y; float zoom; DBG_fprintf(stderr, "Extension BG: redrawing.\n"); glDeleteLists(visu_gl_ext_getGlList(ext), 1); visu_gl_ext_setDirty(ext, FALSE); /* Nothing to draw; */ if(!bg->priv->view || !bg->priv->bgImage) return; DBG_fprintf(stderr, "Extension bg: set background image.\n"); visu_gl_text_initFontList(); glGetIntegerv(GL_VIEWPORT, viewport); if (bg->priv->bgImageFit) { x = (float)viewport[2] / (float)bg->priv->bgImageW; y = (float)viewport[3] / (float)bg->priv->bgImageH; } else { x = y = 1.f; } DBG_fprintf(stderr, "Extension bg: use follow zoom %d (%g / %g).\n", bg->priv->bgImageFollowZoom, bg->priv->bgImageZoom, bg->priv->bgImageZoomInit); zoom = MIN(x, y) * bg->priv->bgImageZoomRatioInit * bg->priv->bgImageZoom / bg->priv->bgImageZoomInit; x = ((float)viewport[2] - zoom * (float)bg->priv->bgImageW) / 2.f; x += (float)viewport[2] * (bg->priv->bgImageXs - bg->priv->bgImageXsInit - bg->priv->bgImageXs0); y = ((float)viewport[3] - zoom * (float)bg->priv->bgImageH) / 2.f; y -= (float)viewport[3] * (bg->priv->bgImageYs - bg->priv->bgImageYsInit - bg->priv->bgImageYs0); visu_gl_ext_startDrawing(ext); glEnable(GL_BLEND); glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA); glMatrixMode(GL_PROJECTION); glPushMatrix(); glLoadIdentity(); gluOrtho2D(0., (float)viewport[2], 0., (float)viewport[3]); glMatrixMode(GL_MODELVIEW); glPushMatrix(); glLoadIdentity(); glDepthMask(0); glRasterPos2i(0, 0); glBitmap(0, 0, 0, 0, x, viewport[3] - y, NULL); glPixelZoom(zoom, -zoom); if (bg->priv->bgImageAlpha) glDrawPixels(bg->priv->bgImageW, bg->priv->bgImageH, GL_RGBA, GL_UNSIGNED_BYTE, bg->priv->bgImage); else glDrawPixels(bg->priv->bgImageW, bg->priv->bgImageH, GL_RGB, GL_UNSIGNED_BYTE, bg->priv->bgImage); glPixelZoom(1., 1.); if (bg->priv->bgImageTitle) { glDisable(GL_LIGHTING); glColor4f(0.5f, 0.5f, 0.5f, 1.f); glRasterPos2f(5.f, 5.f); visu_gl_text_drawChars(bg->priv->bgImageTitle, VISU_GL_TEXT_NORMAL); } glDepthMask(1); glPopMatrix(); glMatrixMode(GL_PROJECTION); glPopMatrix(); glMatrixMode(GL_MODELVIEW); visu_gl_ext_completeDrawing(ext); } static void visu_gl_ext_bg_rebuild(VisuGlExt *ext) { DBG_fprintf(stderr, "Fog & Bg: rebuild extension.\n"); visu_gl_ext_setDirty(ext, TRUE); visu_gl_ext_bg_draw(ext); } static void onBgImageRescale(VisuGlView *view _U_, gpointer data) { DBG_fprintf(stderr, "Extension Bg: caught the 'WidthHeightChanged' signal.\n"); if (VISU_GL_EXT_BG(data)->priv->bgImage) visu_gl_ext_setDirty(VISU_GL_EXT(data), TRUE); } static void onCameraChange(VisuGlView *view, GParamSpec *pspec _U_, gpointer data) { if (visu_gl_ext_bg_setCamera(VISU_GL_EXT_BG(data), view->camera.gross, view->camera.xs, view->camera.ys)) visu_gl_ext_setDirty(VISU_GL_EXT(data), TRUE); } v_sim-3.8.0/src/extensions/fogAndBGColor.h000066400000000000000000000107771370110300500204060ustar00rootroot00000000000000/* EXTRAITS DE LA LICENCE Copyright CEA, contributeurs : Luc BILLARD et Damien CALISTE, laboratoire L_Sim, (2001-2005) Adresse mèl : BILLARD, non joignable par mèl ; CALISTE, damien P caliste AT cea P fr. Ce logiciel est un programme informatique servant à visualiser des structures atomiques dans un rendu pseudo-3D. Ce logiciel est régi par la licence CeCILL soumise au droit français et respectant les principes de diffusion des logiciels libres. Vous pouvez utiliser, modifier et/ou redistribuer ce programme sous les conditions de la licence CeCILL telle que diffusée par le CEA, le CNRS et l'INRIA sur le site "http://www.cecill.info". Le fait que vous puissiez accéder à cet en-tête signifie que vous avez pris connaissance de la licence CeCILL, et que vous en avez accepté les termes (cf. le fichier Documentation/licence.fr.txt fourni avec ce logiciel). */ /* LICENCE SUM UP Copyright CEA, contributors : Luc BILLARD et Damien CALISTE, laboratoire L_Sim, (2001-2005) E-mail address: BILLARD, not reachable any more ; CALISTE, damien P caliste AT cea P fr. This software is a computer program whose purpose is to visualize atomic configurations in 3D. This software is governed by the CeCILL license under French law and abiding by the rules of distribution of free software. You can use, modify and/ or redistribute the software under the terms of the CeCILL license as circulated by CEA, CNRS and INRIA at the following URL "http://www.cecill.info". The fact that you are presently reading this means that you have had knowledge of the CeCILL license and that you accept its terms. You can find a copy of this licence shipped with this software at Documentation/licence.en.txt. */ #ifndef FOG_H #define FOG_H #include #include /** * VISU_TYPE_GL_EXT_BG: * * return the type of #VisuGlExtBg. * * Since: 3.7 */ #define VISU_TYPE_GL_EXT_BG (visu_gl_ext_bg_get_type ()) /** * VISU_GL_EXT_BG: * @obj: a #GObject to cast. * * Cast the given @obj into #VisuGlExtBg type. * * Since: 3.7 */ #define VISU_GL_EXT_BG(obj) (G_TYPE_CHECK_INSTANCE_CAST(obj, VISU_TYPE_GL_EXT_BG, VisuGlExtBg)) /** * VISU_GL_EXT_BG_CLASS: * @klass: a #GObjectClass to cast. * * Cast the given @klass into #VisuGlExtBgClass. * * Since: 3.7 */ #define VISU_GL_EXT_BG_CLASS(klass) (G_TYPE_CHECK_CLASS_CAST(klass, VISU_TYPE_GL_EXT_BG, VisuGlExtBgClass)) /** * VISU_IS_GL_EXT_BG: * @obj: a #GObject to test. * * Test if the given @ogj is of the type of #VisuGlExtBg object. * * Since: 3.7 */ #define VISU_IS_GL_EXT_BG(obj) (G_TYPE_CHECK_INSTANCE_TYPE(obj, VISU_TYPE_GL_EXT_BG)) /** * VISU_IS_GL_EXT_BG_CLASS: * @klass: a #GObjectClass to test. * * Test if the given @klass is of the type of #VisuGlExtBgClass class. * * Since: 3.7 */ #define VISU_IS_GL_EXT_BG_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE(klass, VISU_TYPE_GL_EXT_BG)) /** * VISU_GL_EXT_BG_GET_CLASS: * @obj: a #GObject to get the class of. * * It returns the class of the given @obj. * * Since: 3.7 */ #define VISU_GL_EXT_BG_GET_CLASS(obj) (G_TYPE_INSTANCE_GET_CLASS(obj, VISU_TYPE_GL_EXT_BG, VisuGlExtBgClass)) typedef struct _VisuGlExtBg VisuGlExtBg; typedef struct _VisuGlExtBgPrivate VisuGlExtBgPrivate; typedef struct _VisuGlExtBgClass VisuGlExtBgClass; struct _VisuGlExtBg { VisuGlExt parent; VisuGlExtBgPrivate *priv; }; struct _VisuGlExtBgClass { VisuGlExtClass parent; }; /** * VISU_GL_EXT_BG_ID: * * The id used to identify this extension, see * visu_gl_ext_rebuild() for instance. */ #define VISU_GL_EXT_BG_ID "Background" /** * visu_gl_ext_bg_get_type: * * This method returns the type of #VisuGlExtBg, use * VISU_TYPE_GL_EXT_BG instead. * * Since: 3.7 * * Returns: the type of #VisuGlExtBg. */ GType visu_gl_ext_bg_get_type(void); VisuGlExtBg* visu_gl_ext_bg_new(const gchar *name); gboolean visu_gl_ext_bg_setFile(VisuGlExtBg *bg, const gchar *path, GError **error); void visu_gl_ext_bg_setImage(VisuGlExtBg *bg, const guchar *imageData, guint width, guint height, gboolean alpha, const gchar *title, gboolean fit); gboolean visu_gl_ext_bg_setFollowCamera(VisuGlExtBg *bg, gboolean follow, float zoomInit, float xs, float ys); gboolean visu_gl_ext_bg_setCamera(VisuGlExtBg *bg, float zoom, float xs, float ys); #endif v_sim-3.8.0/src/extensions/forces.c000066400000000000000000000153271370110300500172500ustar00rootroot00000000000000/* EXTRAITS DE LA LICENCE Copyright CEA, contributeurs : Damien CALISTE, laboratoire L_Sim, (2011-2013) Adresse mèl : BILLARD, non joignable par mèl ; CALISTE, damien P caliste AT cea P fr. Ce logiciel est un programme informatique servant à visualiser des structures atomiques dans un rendu pseudo-3D. Ce logiciel est régi par la licence CeCILL soumise au droit français et respectant les principes de diffusion des logiciels libres. Vous pouvez utiliser, modifier et/ou redistribuer ce programme sous les conditions de la licence CeCILL telle que diffusée par le CEA, le CNRS et l'INRIA sur le site "http://www.cecill.info". Le fait que vous puissiez accéder à cet en-tête signifie que vous avez pris connaissance de la licence CeCILL, et que vous en avez accepté les termes (cf. le fichier Documentation/licence.fr.txt fourni avec ce logiciel). */ /* LICENCE SUM UP Copyright CEA, contributors : Damien CALISTE, laboratoire L_Sim, (2011-2013) E-mail address: BILLARD, not reachable any more ; CALISTE, damien P caliste AT cea P fr. This software is a computer program whose purpose is to visualize atomic configurations in 3D. This software is governed by the CeCILL license under French law and abiding by the rules of distribution of free software. You can use, modify and/ or redistribute the software under the terms of the CeCILL license as circulated by CEA, CNRS and INRIA at the following URL "http://www.cecill.info". The fact that you are presently reading this means that you have had knowledge of the CeCILL license and that you accept its terms. You can find a copy of this licence shipped with this software at Documentation/licence.en.txt. */ #include "forces.h" #include #include #define FLAG_RESOURCE_FORCES_USED "forces_are_on" #define DESC_RESOURCE_FORCES_USED "Control if the forces are drawn when available ; boolean (0 or 1)" static gboolean RESOURCE_FORCES_USED_DEFAULT = FALSE; #define FLAG_RESOURCE_FORCES_SCALE "forces_scale" #define DESC_RESOURCE_FORCES_SCALE "Scaling factor (or automatic) for the force rendering ; float (-1 for auto or a positive value)" static float RESOURCE_FORCES_SCALE_DEFAULT = -1.f; static void exportResourceForces(GString *data, VisuData *dataObj); /** * SECTION:forces * @short_description: Draw arrows at each node to represent forces. * * A specialised #VisuGlExtNodeVectors to represent forces on nodes. */ /** * VisuGlExtForcesClass: * @parent: the parent class; * * A short way to identify #_VisuGlExtForcesClass structure. * * Since: 3.7 */ /** * VisuGlExtForces: * * An opaque structure. * * Since: 3.7 */ /* Local callbacks. */ static void onEntryUsed(VisuGlExtForces *forces, VisuConfigFileEntry *entry, VisuConfigFile *obj); static void onEntryNorm(VisuGlExtForces *forces, VisuConfigFileEntry *entry, VisuConfigFile *obj); G_DEFINE_TYPE(VisuGlExtForces, visu_gl_ext_forces, VISU_TYPE_GL_EXT_NODE_VECTORS) static void visu_gl_ext_forces_class_init(VisuGlExtForcesClass *klass _U_) { float rg[2] = {-G_MAXFLOAT, G_MAXFLOAT}; VisuConfigFileEntry *resourceEntry; DBG_fprintf(stderr, "Visu GlExt Forces: creating the class of the object.\n"); /* DBG_fprintf(stderr, " - adding new signals ;\n"); */ /* Resources for forces extensions. */ resourceEntry = visu_config_file_addBooleanEntry(VISU_CONFIG_FILE_RESOURCE, FLAG_RESOURCE_FORCES_USED, DESC_RESOURCE_FORCES_USED, &RESOURCE_FORCES_USED_DEFAULT, FALSE); visu_config_file_entry_setVersion(resourceEntry, 3.7f); resourceEntry = visu_config_file_addFloatArrayEntry(VISU_CONFIG_FILE_RESOURCE, FLAG_RESOURCE_FORCES_SCALE, DESC_RESOURCE_FORCES_SCALE, 1, &RESOURCE_FORCES_SCALE_DEFAULT, rg, FALSE); visu_config_file_entry_setVersion(resourceEntry, 3.7f); visu_config_file_addExportFunction(VISU_CONFIG_FILE_RESOURCE, exportResourceForces); } static void visu_gl_ext_forces_init(VisuGlExtForces *obj) { DBG_fprintf(stderr, "Visu GlExt Forces: initializing a new object (%p).\n", (gpointer)obj); /* Private data. */ g_signal_connect_object(VISU_CONFIG_FILE_RESOURCE, "parsed::" FLAG_RESOURCE_FORCES_USED, G_CALLBACK(onEntryUsed), (gpointer)obj, G_CONNECT_SWAPPED); g_signal_connect_object(VISU_CONFIG_FILE_RESOURCE, "parsed::" FLAG_RESOURCE_FORCES_SCALE, G_CALLBACK(onEntryNorm), (gpointer)obj, G_CONNECT_SWAPPED); } /** * visu_gl_ext_forces_new: * @name: (allow-none): the name to give to the extension. * * Creates a new #VisuGlExt to draw forces. * * Since: 3.7 * * Returns: a pointer to the #VisuGlExt it created or * NULL otherwise. */ VisuGlExtForces* visu_gl_ext_forces_new(const gchar *name) { char *name_ = "Forces"; char *description = _("Draw forces with vectors."); VisuGlExtNodeVectors *forces; DBG_fprintf(stderr,"Visu GlExt Forces: new object.\n"); forces = VISU_GL_EXT_NODE_VECTORS(g_object_new(VISU_TYPE_GL_EXT_FORCES, "name", (name)?name:name_, "label", _(name), "description", description, "nGlObj", 1, NULL)); visu_gl_ext_node_vectors_setTranslation(forces, 1.1f); visu_gl_ext_node_vectors_setRenderedSize(forces, -2.f); visu_gl_ext_node_vectors_setNormalisation(forces, RESOURCE_FORCES_SCALE_DEFAULT); return VISU_GL_EXT_FORCES(forces); } /* Callbacks. */ static void onEntryUsed(VisuGlExtForces *forces, VisuConfigFileEntry *entry _U_, VisuConfigFile *obj _U_) { visu_gl_ext_setActive(VISU_GL_EXT(forces), RESOURCE_FORCES_USED_DEFAULT); } static void onEntryNorm(VisuGlExtForces *forces, VisuConfigFileEntry *entry _U_, VisuConfigFile *obj _U_) { visu_gl_ext_node_vectors_setNormalisation(VISU_GL_EXT_NODE_VECTORS(forces), RESOURCE_FORCES_SCALE_DEFAULT); } /* Resources. */ static void exportResourceForces(GString *data, VisuData *dataObj _U_) { visu_config_file_exportComment(data, DESC_RESOURCE_FORCES_USED); visu_config_file_exportEntry(data, FLAG_RESOURCE_FORCES_USED, NULL, "%d", RESOURCE_FORCES_USED_DEFAULT); visu_config_file_exportComment(data, DESC_RESOURCE_FORCES_SCALE); visu_config_file_exportEntry(data, FLAG_RESOURCE_FORCES_SCALE, NULL, "%f", RESOURCE_FORCES_SCALE_DEFAULT); visu_config_file_exportComment(data, ""); } v_sim-3.8.0/src/extensions/forces.h000066400000000000000000000072121370110300500172470ustar00rootroot00000000000000/* EXTRAITS DE LA LICENCE Copyright CEA, contributeurs : Damien CALISTE, laboratoire L_Sim, (2001-2013) Adresse mèl : CALISTE, damien P caliste AT cea P fr. Ce logiciel est un programme informatique servant à visualiser des structures atomiques dans un rendu pseudo-3D. Ce logiciel est régi par la licence CeCILL soumise au droit français et respectant les principes de diffusion des logiciels libres. Vous pouvez utiliser, modifier et/ou redistribuer ce programme sous les conditions de la licence CeCILL telle que diffusée par le CEA, le CNRS et l'INRIA sur le site "http://www.cecill.info". Le fait que vous puissiez accéder à cet en-tête signifie que vous avez pris connaissance de la licence CeCILL, et que vous en avez accepté les termes (cf. le fichier Documentation/licence.fr.txt fourni avec ce logiciel). */ /* LICENCE SUM UP Copyright CEA, contributors : Damien CALISTE, laboratoire L_Sim, (2001-2013) E-mail address: CALISTE, damien P caliste AT cea P fr. This software is a computer program whose purpose is to visualize atomic configurations in 3D. This software is governed by the CeCILL license under French law and abiding by the rules of distribution of free software. You can use, modify and/ or redistribute the software under the terms of the CeCILL license as circulated by CEA, CNRS and INRIA at the following URL "http://www.cecill.info". The fact that you are presently reading this means that you have had knowledge of the CeCILL license and that you accept its terms. You can find a copy of this licence shipped with this software at COPYING. */ #ifndef FORCES_H #define FORCES_H #include "node_vectors.h" /** * VISU_TYPE_GL_EXT_FORCES: * * return the type of #VisuGlExtForces. * * Since: 3.7 */ #define VISU_TYPE_GL_EXT_FORCES (visu_gl_ext_forces_get_type ()) /** * VISU_GL_EXT_FORCES: * @obj: a #GObject to cast. * * Cast the given @obj into #VisuGlExtForces type. * * Since: 3.7 */ #define VISU_GL_EXT_FORCES(obj) (G_TYPE_CHECK_INSTANCE_CAST(obj, VISU_TYPE_GL_EXT_FORCES, VisuGlExtForces)) /** * VISU_GL_EXT_FORCES_CLASS: * @klass: a #GObjectClass to cast. * * Cast the given @klass into #VisuGlExtForcesClass. * * Since: 3.7 */ #define VISU_GL_EXT_FORCES_CLASS(klass) (G_TYPE_CHECK_CLASS_CAST(klass, VISU_TYPE_GL_EXT_FORCES, VisuGlExtForcesClass)) /** * VISU_IS_GL_EXT_FORCES: * @obj: a #GObject to test. * * Test if the given @ogj is of the type of #VisuGlExtForces object. * * Since: 3.7 */ #define VISU_IS_GL_EXT_FORCES(obj) (G_TYPE_CHECK_INSTANCE_TYPE(obj, VISU_TYPE_GL_EXT_FORCES)) /** * VISU_IS_GL_EXT_FORCES_CLASS: * @klass: a #GObjectClass to test. * * Test if the given @klass is of the type of #VisuGlExtForcesClass class. * * Since: 3.7 */ #define VISU_IS_GL_EXT_FORCES_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE(klass, VISU_TYPE_GL_EXT_FORCES)) /** * VISU_GL_EXT_FORCES_GET_CLASS: * @obj: a #GObject to get the class of. * * It returns the class of the given @obj. * * Since: 3.7 */ #define VISU_GL_EXT_FORCES_GET_CLASS(obj) (G_TYPE_INSTANCE_GET_CLASS(obj, VISU_TYPE_GL_EXT_FORCES, VisuGlExtForcesClass)) typedef struct _VisuGlExtForces VisuGlExtForces; typedef struct _VisuGlExtForcesClass VisuGlExtForcesClass; struct _VisuGlExtForces { VisuGlExtNodeVectors parent; }; struct _VisuGlExtForcesClass { VisuGlExtNodeVectorsClass parent; }; /** * visu_gl_ext_forces_get_type: * * This method returns the type of #VisuGlExtForces, use * VISU_TYPE_GL_EXT_FORCES instead. * * Since: 3.7 * * Returns: the type of #VisuGlExtForces. */ GType visu_gl_ext_forces_get_type(void); VisuGlExtForces* visu_gl_ext_forces_new(const gchar *name); #endif v_sim-3.8.0/src/extensions/frame.c000066400000000000000000000554051370110300500170620ustar00rootroot00000000000000/* EXTRAITS DE LA LICENCE Copyright CEA, contributeurs : Damien CALISTE, laboratoire L_Sim, (2001-2013) Adresse mèl : CALISTE, damien P caliste AT cea P fr. Ce logiciel est un programme informatique servant à visualiser des structures atomiques dans un rendu pseudo-3D. Ce logiciel est régi par la licence CeCILL soumise au droit français et respectant les principes de diffusion des logiciels libres. Vous pouvez utiliser, modifier et/ou redistribuer ce programme sous les conditions de la licence CeCILL telle que diffusée par le CEA, le CNRS et l'INRIA sur le site "http://www.cecill.info". Le fait que vous puissiez accéder à cet en-tête signifie que vous avez pris connaissance de la licence CeCILL, et que vous en avez accepté les termes (cf. le fichier Documentation/licence.fr.txt fourni avec ce logiciel). */ /* LICENCE SUM UP Copyright CEA, contributors : Damien CALISTE, laboratoire L_Sim, (2001-2013) E-mail address: CALISTE, damien P caliste AT cea P fr. This software is a computer program whose purpose is to visualize atomic configurations in 3D. This software is governed by the CeCILL license under French law and abiding by the rules of distribution of free software. You can use, modify and/ or redistribute the software under the terms of the CeCILL license as circulated by CEA, CNRS and INRIA at the following URL "http://www.cecill.info". The fact that you are presently reading this means that you have had knowledge of the CeCILL license and that you accept its terms. You can find a copy of this licence shipped with this software at COPYING. */ #include "frame.h" #include #include #include #include /** * SECTION:frame * @short_description: Draw a frame with the representation of a color frame. * * This extension draws a frame on top of the rendering area * with a color frame. One can setup printed values and draw * additional marks inside the frame. * * Since: 3.7 */ /** * VisuGlExtFrameClass: * @parent: the parent class; * @draw: the draw method for the content of this frame. * * A short way to identify #_VisuGlExtFrameClass structure. * * Since: 3.7 */ /** * VisuGlExtFrame: * * An opaque structure. * * Since: 3.7 */ /** * VisuGlExtFramePrivate: * * Private fields for #VisuGlExtFrame objects. * * Since: 3.7 */ struct _VisuGlExtFramePrivate { gboolean dispose_has_run; /* Rendering parameters. */ guint requisition[2]; float scale; float xpos, ypos, xmargin, ymargin, xpad, ypad; float bgRGBA[4]; gchar *title; /* Object dependencies. */ VisuGlView *view; gulong widthHeight_signal; }; enum { PROP_0, XPOS_PROP, YPOS_PROP, XPAD_PROP, YPAD_PROP, N_PROP }; static GParamSpec *properties[N_PROP]; static int refMask[4] = {TOOL_COLOR_MASK_R, TOOL_COLOR_MASK_G, TOOL_COLOR_MASK_B, TOOL_COLOR_MASK_A}; static float bgRGBADefault[4] = {1.f, 1.f, 1.f, 0.4f}; static float fontRGBDefault[4] = {0.f, 0.f, 0.f}; static float xmarginDefault = 10.f, ymarginDefault = 10.f; static float xpadDefault = 5.f, ypadDefault = 5.f; static void visu_gl_ext_frame_finalize(GObject* obj); static void visu_gl_ext_frame_dispose(GObject* obj); static void visu_gl_ext_frame_get_property(GObject* obj, guint property_id, GValue *value, GParamSpec *pspec); static void visu_gl_ext_frame_set_property(GObject* obj, guint property_id, const GValue *value, GParamSpec *pspec); static void visu_gl_ext_frame_draw(VisuGlExt *ext); static gboolean visu_gl_ext_frame_setGlView(VisuGlExt *frame, VisuGlView *view); static void onViewChanged(VisuGlView *view, gpointer data); G_DEFINE_TYPE_WITH_CODE(VisuGlExtFrame, visu_gl_ext_frame, VISU_TYPE_GL_EXT, G_ADD_PRIVATE(VisuGlExtFrame)) static void visu_gl_ext_frame_class_init(VisuGlExtFrameClass *klass) { DBG_fprintf(stderr, "Extension Frame: creating the class of the object.\n"); /* DBG_fprintf(stderr, " - adding new signals ;\n"); */ /* DBG_fprintf(stderr, " - adding new resources ;\n"); */ klass->draw = NULL; /* Connect the overloading methods. */ G_OBJECT_CLASS(klass)->dispose = visu_gl_ext_frame_dispose; G_OBJECT_CLASS(klass)->finalize = visu_gl_ext_frame_finalize; G_OBJECT_CLASS(klass)->set_property = visu_gl_ext_frame_set_property; G_OBJECT_CLASS(klass)->get_property = visu_gl_ext_frame_get_property; VISU_GL_EXT_CLASS(klass)->draw = visu_gl_ext_frame_draw; VISU_GL_EXT_CLASS(klass)->setGlView = visu_gl_ext_frame_setGlView; /** * VisuGlExtFrame::x-pos: * * Store the position along x of the frame. * * Since: 3.8 */ properties[XPOS_PROP] = g_param_spec_float("x-pos", "x position", "position along x axis", 0., 1., 0., G_PARAM_READWRITE); g_object_class_install_property(G_OBJECT_CLASS(klass), XPOS_PROP, properties[XPOS_PROP]); /** * VisuGlExtFrame::y-pos: * * Store the position along y of the frame. * * Since: 3.8 */ properties[YPOS_PROP] = g_param_spec_float("y-pos", "y position", "position along y axis", 0., 1., 1., G_PARAM_READWRITE); g_object_class_install_property(G_OBJECT_CLASS(klass), YPOS_PROP, properties[YPOS_PROP]); /** * VisuGlExtFrame::x-padding: * * Store the padding along x of the frame. * * Since: 3.8 */ properties[XPAD_PROP] = g_param_spec_float("x-padding", "x padding", "padding along x axis", 0., 30., xpadDefault, G_PARAM_READWRITE); g_object_class_install_property(G_OBJECT_CLASS(klass), XPAD_PROP, properties[XPAD_PROP]); /** * VisuGlExtFrame::y-padding: * * Store the padding along y of the frame. * * Since: 3.8 */ properties[YPAD_PROP] = g_param_spec_float("y-padding", "y padding", "padding along y axis", 0., 30., ypadDefault, G_PARAM_READWRITE); g_object_class_install_property(G_OBJECT_CLASS(klass), YPAD_PROP, properties[YPAD_PROP]); } static void visu_gl_ext_frame_init(VisuGlExtFrame *obj) { DBG_fprintf(stderr, "Extension Frame: initializing a new object (%p).\n", (gpointer)obj); obj->width = 0; obj->height = 0; obj->fontRGB[0] = fontRGBDefault[0]; obj->fontRGB[1] = fontRGBDefault[1]; obj->fontRGB[2] = fontRGBDefault[2]; obj->priv = visu_gl_ext_frame_get_instance_private(obj); obj->priv->dispose_has_run = FALSE; /* Private data. */ obj->priv->requisition[0] = 0; obj->priv->requisition[1] = 0; obj->priv->scale = 1.f; obj->priv->xpos = 0.f; obj->priv->ypos = 0.f; obj->priv->xmargin = xmarginDefault; obj->priv->ymargin = ymarginDefault; obj->priv->xpad = xpadDefault; obj->priv->ypad = ypadDefault; obj->priv->bgRGBA[0] = bgRGBADefault[0]; obj->priv->bgRGBA[1] = bgRGBADefault[1]; obj->priv->bgRGBA[2] = bgRGBADefault[2]; obj->priv->bgRGBA[3] = bgRGBADefault[3]; obj->priv->title = g_strdup(""); obj->priv->view = (VisuGlView*)0; obj->priv->widthHeight_signal = 0; } /* This method can be called several times. It should unref all of its reference to GObjects. */ static void visu_gl_ext_frame_dispose(GObject* obj) { VisuGlExtFrame *frame; DBG_fprintf(stderr, "Extension Frame: dispose object %p.\n", (gpointer)obj); frame = VISU_GL_EXT_FRAME(obj); if (frame->priv->dispose_has_run) return; frame->priv->dispose_has_run = TRUE; /* Disconnect signals. */ visu_gl_ext_frame_setGlView(VISU_GL_EXT(obj), (VisuGlView*)0); /* Chain up to the parent class */ G_OBJECT_CLASS(visu_gl_ext_frame_parent_class)->dispose(obj); } /* This method is called once only. */ static void visu_gl_ext_frame_finalize(GObject* obj) { VisuGlExtFrame *frame; g_return_if_fail(obj); DBG_fprintf(stderr, "Extension Frame: finalize object %p.\n", (gpointer)obj); frame = VISU_GL_EXT_FRAME(obj); /* Free privs elements. */ if (frame->priv) { DBG_fprintf(stderr, "Extension Frame: free private frame.\n"); g_free(frame->priv->title); } /* Chain up to the parent class */ DBG_fprintf(stderr, "Extension Frame: chain to parent.\n"); G_OBJECT_CLASS(visu_gl_ext_frame_parent_class)->finalize(obj); DBG_fprintf(stderr, "Extension Frame: freeing ... OK.\n"); } static void visu_gl_ext_frame_get_property(GObject* obj, guint property_id, GValue *value, GParamSpec *pspec) { VisuGlExtFrame *self = VISU_GL_EXT_FRAME(obj); DBG_fprintf(stderr, "Extension Frame: get property '%s' -> ", g_param_spec_get_name(pspec)); switch (property_id) { case XPOS_PROP: g_value_set_float(value, self->priv->xpos); DBG_fprintf(stderr, "%g.\n", self->priv->xpos); break; case YPOS_PROP: g_value_set_float(value, self->priv->ypos); DBG_fprintf(stderr, "%g.\n", self->priv->ypos); break; case XPAD_PROP: g_value_set_float(value, self->priv->xpad); DBG_fprintf(stderr, "%g.\n", self->priv->xpad); break; case YPAD_PROP: g_value_set_float(value, self->priv->ypad); DBG_fprintf(stderr, "%g.\n", self->priv->ypad); break; default: /* We don't have any other property... */ G_OBJECT_WARN_INVALID_PROPERTY_ID(obj, property_id, pspec); break; } } static void visu_gl_ext_frame_set_property(GObject* obj, guint property_id, const GValue *value, GParamSpec *pspec) { VisuGlExtFrame *self = VISU_GL_EXT_FRAME(obj); DBG_fprintf(stderr, "Extension Frame: set property '%s' -> ", g_param_spec_get_name(pspec)); switch (property_id) { case XPOS_PROP: visu_gl_ext_frame_setPosition(self, g_value_get_float(value), self->priv->ypos); DBG_fprintf(stderr, "%g.\n", self->priv->xpos); break; case YPOS_PROP: visu_gl_ext_frame_setPosition(self, self->priv->xpos, g_value_get_float(value)); DBG_fprintf(stderr, "%g.\n", self->priv->ypos); break; case XPAD_PROP: DBG_fprintf(stderr, "%g.\n", g_value_get_float(value)); visu_gl_ext_frame_setPadding(self, g_value_get_float(value), self->priv->ypad); break; case YPAD_PROP: DBG_fprintf(stderr, "%g.\n", g_value_get_float(value)); visu_gl_ext_frame_setPadding(self, self->priv->xpad, g_value_get_float(value)); break; default: /* We don't have any other property... */ G_OBJECT_WARN_INVALID_PROPERTY_ID(obj, property_id, pspec); break; } } static gboolean visu_gl_ext_frame_setGlView(VisuGlExt *frame, VisuGlView *view) { VisuGlExtFramePrivate *priv = VISU_GL_EXT_FRAME(frame)->priv; if (priv->view == view) return FALSE; if (priv->view) { g_signal_handler_disconnect(G_OBJECT(priv->view), priv->widthHeight_signal); g_object_unref(priv->view); } if (view) { g_object_ref(view); priv->widthHeight_signal = g_signal_connect(G_OBJECT(view), "WidthHeightChanged", G_CALLBACK(onViewChanged), (gpointer)frame); } else priv->widthHeight_signal = 0; priv->view = view; visu_gl_ext_setDirty(frame, TRUE); return TRUE; } /** * visu_gl_ext_frame_setPosition: * @frame: the #VisuGlExtFrame object to modify. * @xpos: the reduced y position (1 to the left). * @ypos: the reduced y position (1 to the bottom). * * Change the position of the frame representation. * * Since: 3.7 * * Returns: TRUE if any position is actually changed. **/ gboolean visu_gl_ext_frame_setPosition(VisuGlExtFrame *frame, float xpos, float ypos) { gboolean changed; g_return_val_if_fail(VISU_IS_GL_EXT_FRAME(frame), FALSE); xpos = CLAMP(xpos, 0.f, 1.f); ypos = CLAMP(ypos, 0.f, 1.f); changed = FALSE; g_object_freeze_notify(G_OBJECT(frame)); if (xpos != frame->priv->xpos) { frame->priv->xpos = xpos; g_object_notify_by_pspec(G_OBJECT(frame), properties[XPOS_PROP]); changed = TRUE; } if (ypos != frame->priv->ypos) { frame->priv->ypos = ypos; g_object_notify_by_pspec(G_OBJECT(frame), properties[YPOS_PROP]); changed = TRUE; } if (changed) visu_gl_ext_setDirty(VISU_GL_EXT(frame), TRUE); g_object_thaw_notify(G_OBJECT(frame)); return changed; } /** * visu_gl_ext_frame_setPadding: * @frame: the #VisuGlExtFrame object to modify. * @xpad: the padding along x. * @ypad: the padding along y. * * Change the padding of the frame representation. * * Since: 3.8 * * Returns: TRUE if any position is actually changed. **/ gboolean visu_gl_ext_frame_setPadding(VisuGlExtFrame *frame, float xpad, float ypad) { gboolean changed; g_return_val_if_fail(VISU_IS_GL_EXT_FRAME(frame), FALSE); xpad = CLAMP(xpad, 0.f, 30.f); ypad = CLAMP(ypad, 0.f, 30.f); changed = FALSE; g_object_freeze_notify(G_OBJECT(frame)); if (xpad != frame->priv->xpad) { frame->priv->xpad = xpad; g_object_notify_by_pspec(G_OBJECT(frame), properties[XPAD_PROP]); changed = TRUE; } if (ypad != frame->priv->ypad) { frame->priv->ypad = ypad; g_object_notify_by_pspec(G_OBJECT(frame), properties[YPAD_PROP]); changed = TRUE; } if (changed) visu_gl_ext_setDirty(VISU_GL_EXT(frame), TRUE); g_object_thaw_notify(G_OBJECT(frame)); return changed; } #define SET_RGBA_I(S, I, V, M) {if (M & refMask[I] && S[I] != V[I]) \ {S[I] = V[I]; diff = TRUE;}} #define SET_RGBA(S, V, M) {SET_RGBA_I(S, 0, V, M); \ SET_RGBA_I(S, 1, V, M); SET_RGBA_I(S, 2, V, M); SET_RGBA_I(S, 3, V, M); } #define SET_RGB(S, V, M) {SET_RGBA_I(S, 0, V, M); \ SET_RGBA_I(S, 1, V, M); SET_RGBA_I(S, 2, V, M); } /** * visu_gl_ext_frame_setBgRGBA: * @frame: the #VisuGlExtFrame to update. * @rgba: (array fixed-size=4): a four floats array with values (0 <= values <= 1) for the * red, the green, the blue color and the alpha channel. Only values * specified by the @mask are really relevant. * @mask: use #TOOL_COLOR_MASK_R, #TOOL_COLOR_MASK_G, * #TOOL_COLOR_MASK_B, #TOOL_COLOR_MASK_A or a combinaison to indicate * what values in the @rgba array must be taken into account. * * Change the colour to represent the background of the frame. * * Since: 3.7 * * Returns: TRUE if value is actually changed. */ gboolean visu_gl_ext_frame_setBgRGBA(VisuGlExtFrame *frame, float rgba[4], int mask) { gboolean diff = FALSE; g_return_val_if_fail(VISU_IS_GL_EXT_FRAME(frame), FALSE); SET_RGBA(frame->priv->bgRGBA, rgba, mask); if (!diff) return FALSE; visu_gl_ext_setDirty(VISU_GL_EXT(frame), TRUE); return TRUE; } /** * visu_gl_ext_frame_setFontRGB: * @frame: the #VisuGlExtFrame to update. * @rgb: (array fixed-size=3): a four floats array with values (0 <= values <= 1) for the * red, the green, the blue color. Only values specified by the @mask * are really relevant. * @mask: use #TOOL_COLOR_MASK_R, #TOOL_COLOR_MASK_G, * #TOOL_COLOR_MASK_B or a combinaison to indicate what values in the * @rgb array must be taken into account. * * Change the colour to represent the font of the frame. * * Since: 3.7 * * Returns: TRUE if value is actually changed. */ gboolean visu_gl_ext_frame_setFontRGB(VisuGlExtFrame *frame, float rgb[3], int mask) { gboolean diff = FALSE; g_return_val_if_fail(VISU_IS_GL_EXT_FRAME(frame), FALSE); SET_RGB(frame->fontRGB, rgb, mask); if (!diff) return FALSE; visu_gl_ext_setDirty(VISU_GL_EXT(frame), TRUE); return TRUE; } /** * visu_gl_ext_frame_setScale: * @frame: the #VisuGlExtFrame to update. * @scale: a positive value. * * Change the zoom level for the rendering of the legend. * * Since: 3.7 * * Returns: TRUE if value is actually changed. **/ gboolean visu_gl_ext_frame_setScale(VisuGlExtFrame *frame, float scale) { g_return_val_if_fail(VISU_IS_GL_EXT_FRAME(frame), FALSE); if (frame->priv->scale == scale) return FALSE; frame->priv->scale = CLAMP(scale, 0.01f, 10.f); visu_gl_ext_setDirty(VISU_GL_EXT(frame), TRUE); return TRUE; } /** * visu_gl_ext_frame_setTitle: * @frame: the #VisuGlExtFrame object to modify. * @title: a title. * * Change the title of the box legend. * * Since: 3.7 * * Returns: TRUE if title is actually changed. **/ gboolean visu_gl_ext_frame_setTitle(VisuGlExtFrame *frame, const gchar *title) { g_return_val_if_fail(VISU_IS_GL_EXT_FRAME(frame) && title, FALSE); if (!strcmp(title, frame->priv->title)) return FALSE; g_free(frame->priv->title); frame->priv->title = g_strdup(title); visu_gl_ext_setDirty(VISU_GL_EXT(frame), TRUE); return TRUE; } /** * visu_gl_ext_frame_setRequisition: * @frame: the #VisuGlExtFrame object to modify. * @width: the desired width. * @height: the desired height. * * Set the size of the frame in pixels. Use * visu_gl_ext_frame_setScale() to adjust the size if necessary. * * Since: 3.7 * * Returns: TRUE if requested size is changed. **/ gboolean visu_gl_ext_frame_setRequisition(VisuGlExtFrame *frame, guint width, guint height) { g_return_val_if_fail(VISU_IS_GL_EXT_FRAME(frame), FALSE); if (frame->priv->requisition[0] == width && frame->priv->requisition[1] == height) return FALSE; frame->priv->requisition[0] = width; frame->priv->requisition[1] = height; visu_gl_ext_setDirty(VISU_GL_EXT(frame), TRUE); return TRUE; } /** * visu_gl_ext_frame_getScale: * @frame: a #VisuGlExtFrame object. * * Frames are rendered with a scaling factor of 1. by default. * * Since: 3.7 * * Returns: the scaling factor used to represent frames. **/ float visu_gl_ext_frame_getScale(const VisuGlExtFrame *frame) { g_return_val_if_fail(VISU_IS_GL_EXT_FRAME(frame), 1.f); return frame->priv->scale; } /** * visu_gl_ext_frame_getPosition: * @frame: the #VisuGlExtFrame object to inquire. * @xpos: (out) (allow-none): a location to store the x position. * @ypos: (out) (allow-none): a location to store the y position. * * Inquire the position of the representation of the frame. * * Since: 3.7 **/ void visu_gl_ext_frame_getPosition(const VisuGlExtFrame *frame, float *xpos, float *ypos) { g_return_if_fail(VISU_IS_GL_EXT_FRAME(frame)); if (xpos) *xpos = frame->priv->xpos; if (ypos) *ypos = frame->priv->ypos; } static void onViewChanged(VisuGlView *view _U_, gpointer data) { visu_gl_ext_setDirty(VISU_GL_EXT(data), TRUE); } /** * visu_gl_ext_frame_draw: * @frame: a #VisuGlExtFrame object. * * Render the@frame and its child. * * Since: 3.7 */ static void visu_gl_ext_frame_draw(VisuGlExt *ext) { int viewport[4]; float requisition[2]; VisuGlExtFrame *frame; VisuGlExtFrameClass *klass; int xpos, ypos, dx, dy; g_return_if_fail(VISU_IS_GL_EXT_FRAME(ext)); frame = VISU_GL_EXT_FRAME(ext); DBG_fprintf(stderr, "Visu GlExt Frame: drawing the extension '%p'.\n", (gpointer)frame); klass = VISU_GL_EXT_FRAME_GET_CLASS(frame); if (!klass->draw || (klass->isValid && !klass->isValid(frame))) return; visu_gl_text_initFontList(); visu_gl_ext_startDrawing(ext); /* We get the size of the current viewport. */ glGetIntegerv(GL_VIEWPORT, viewport); DBG_fprintf(stderr, "Visu GlExt Frame: current viewport is %dx%d.\n", viewport[2], viewport[3]); /* We change the viewport. */ DBG_fprintf(stderr, "Visu GlExt Frame: requisition is %dx%d.\n", frame->priv->requisition[0], frame->priv->requisition[1]); requisition[0] = (float)frame->priv->requisition[0]; requisition[1] = (float)frame->priv->requisition[1] + ((frame->priv->title[0])?(frame->priv->ypad + 12.f):0.f); DBG_fprintf(stderr, "Visu GlExt Frame: requisition is %gx%g.\n", requisition[0], requisition[1]); frame->width = MIN((guint)(requisition[0] * frame->priv->scale), viewport[2] - (guint)(2.f * frame->priv->xmargin)); frame->height = MIN((guint)(requisition[1] * frame->priv->scale), viewport[3] - (guint)(2.f * frame->priv->ymargin)); xpos = frame->priv->xmargin + ((float)viewport[2] - 2.f * frame->priv->xmargin - frame->width) * frame->priv->xpos; ypos = frame->priv->ymargin + ((float)viewport[3] - 2.f * frame->priv->ymargin - frame->height) * frame->priv->ypos; glViewport(xpos, ypos, frame->width, frame->height); glDisable(GL_FOG); glDisable(GL_LIGHTING); glDisable(GL_DEPTH_TEST); /* glDisable(GL_ALPHA_TEST); */ glEnable(GL_BLEND); glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA); /* We change the projection for a 2D one. */ glMatrixMode(GL_PROJECTION); glPushMatrix(); glLoadIdentity(); glOrtho(0., (float)frame->width, 0., (float)frame->height, -50., +50.); glMatrixMode(GL_MODELVIEW); glPushMatrix(); glLoadIdentity(); /* We draw a big transparent square to do the back. */ if (frame->priv->bgRGBA[3] > 0.f) { glColor4fv(frame->priv->bgRGBA); glRecti(0, 0, frame->width, frame->height); } /* We draw the title, if any. */ if (frame->priv->title[0]) { glColor3fv(frame->fontRGB); glRasterPos2f(frame->priv->xpad * frame->priv->scale, frame->height - (frame->priv->ypad + 12.) * frame->priv->scale); visu_gl_text_drawChars(frame->priv->title, VISU_GL_TEXT_NORMAL); } /* We change again the viewport to adjust to padding. */ dx = frame->priv->xpad * frame->priv->scale; dy = frame->priv->ypad * frame->priv->scale; xpos += dx; ypos += dy; frame->width -= 2.f * dx * frame->priv->scale; frame->height -= 2.f * dy * frame->priv->scale; if (frame->priv->title[0]) frame->height -= (frame->priv->ypad + 12.) * frame->priv->scale; if (frame->width > (guint)viewport[2]) frame->width = 0; if (frame->height > (guint)viewport[3]) frame->height = 0; DBG_fprintf(stderr, "Visu GlExt Frame: frame actual size is %dx%d.\n", frame->width, frame->height); glViewport(xpos, ypos, frame->width, frame->height); glPopMatrix(); glMatrixMode(GL_PROJECTION); glPopMatrix(); glPushMatrix(); glLoadIdentity(); glOrtho(0., (float)frame->width, 0., (float)frame->height, -50., +50.); glMatrixMode(GL_MODELVIEW); glPushMatrix(); glLoadIdentity(); klass->draw(frame); /* We change the projection back. */ glPopMatrix(); glMatrixMode(GL_PROJECTION); glPopMatrix(); glMatrixMode(GL_MODELVIEW); /* We set viewport back. */ DBG_fprintf(stderr, "Visu GlExt Frame: put back viewport at %dx%d.\n", viewport[2], viewport[3]); glViewport(0, 0, viewport[2], viewport[3]); visu_gl_ext_completeDrawing(ext); } v_sim-3.8.0/src/extensions/frame.h000066400000000000000000000110551370110300500170600ustar00rootroot00000000000000/* EXTRAITS DE LA LICENCE Copyright CEA, contributeurs : Damien CALISTE, laboratoire L_Sim, (2001-2009) Adresse mèl : CALISTE, damien P caliste AT cea P fr. Ce logiciel est un programme informatique servant à visualiser des structures atomiques dans un rendu pseudo-3D. Ce logiciel est régi par la licence CeCILL soumise au droit français et respectant les principes de diffusion des logiciels libres. Vous pouvez utiliser, modifier et/ou redistribuer ce programme sous les conditions de la licence CeCILL telle que diffusée par le CEA, le CNRS et l'INRIA sur le site "http://www.cecill.info". Le fait que vous puissiez accéder à cet en-tête signifie que vous avez pris connaissance de la licence CeCILL, et que vous en avez accepté les termes (cf. le fichier Documentation/licence.fr.txt fourni avec ce logiciel). */ /* LICENCE SUM UP Copyright CEA, contributors : Damien CALISTE, laboratoire L_Sim, (2001-2009) E-mail address: CALISTE, damien P caliste AT cea P fr. This software is a computer program whose purpose is to visualize atomic configurations in 3D. This software is governed by the CeCILL license under French law and abiding by the rules of distribution of free software. You can use, modify and/ or redistribute the software under the terms of the CeCILL license as circulated by CEA, CNRS and INRIA at the following URL "http://www.cecill.info". The fact that you are presently reading this means that you have had knowledge of the CeCILL license and that you accept its terms. You can find a copy of this licence shipped with this software at COPYING. */ #ifndef FRAME_H #define FRAME_H #include #include #include /** * VISU_TYPE_GL_EXT_FRAME: * * return the type of #VisuGlExtFrame. * * Since: 3.7 */ #define VISU_TYPE_GL_EXT_FRAME (visu_gl_ext_frame_get_type ()) /** * VISU_GL_EXT_FRAME: * @obj: a #GObject to cast. * * Cast the given @obj into #VisuGlExtFrame type. * * Since: 3.7 */ #define VISU_GL_EXT_FRAME(obj) (G_TYPE_CHECK_INSTANCE_CAST(obj, VISU_TYPE_GL_EXT_FRAME, VisuGlExtFrame)) /** * VISU_GL_EXT_FRAME_CLASS: * @klass: a #GObjectClass to cast. * * Cast the given @klass into #VisuGlExtFrameClass. * * Since: 3.7 */ #define VISU_GL_EXT_FRAME_CLASS(klass) (G_TYPE_CHECK_CLASS_CAST(klass, VISU_TYPE_GL_EXT_FRAME, VisuGlExtFrameClass)) /** * VISU_IS_GL_EXT_FRAME: * @obj: a #GObject to test. * * Test if the given @ogj is of the type of #VisuGlExtFrame object. * * Since: 3.7 */ #define VISU_IS_GL_EXT_FRAME(obj) (G_TYPE_CHECK_INSTANCE_TYPE(obj, VISU_TYPE_GL_EXT_FRAME)) /** * VISU_IS_GL_EXT_FRAME_CLASS: * @klass: a #GObjectClass to test. * * Test if the given @klass is of the type of #VisuGlExtFrameClass class. * * Since: 3.7 */ #define VISU_IS_GL_EXT_FRAME_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE(klass, VISU_TYPE_GL_EXT_FRAME)) /** * VISU_GL_EXT_FRAME_GET_CLASS: * @obj: a #GObject to get the class of. * * It returns the class of the given @obj. * * Since: 3.7 */ #define VISU_GL_EXT_FRAME_GET_CLASS(obj) (G_TYPE_INSTANCE_GET_CLASS(obj, VISU_TYPE_GL_EXT_FRAME, VisuGlExtFrameClass)) typedef struct _VisuGlExtFrame VisuGlExtFrame; typedef struct _VisuGlExtFramePrivate VisuGlExtFramePrivate; typedef struct _VisuGlExtFrameClass VisuGlExtFrameClass; struct _VisuGlExtFrame { VisuGlExt parent; guint width, height; float fontRGB[3]; VisuGlExtFramePrivate *priv; }; struct _VisuGlExtFrameClass { VisuGlExtClass parent; gboolean (*isValid) (const VisuGlExtFrame* frame); void (*draw) (const VisuGlExtFrame* frame); }; /** * visu_gl_ext_frame_get_type: * * This method returns the type of #VisuGlExtFrame, use * VISU_TYPE_GL_EXT_FRAME instead. * * Since: 3.7 * * Returns: the type of #VisuGlExtFrame. */ GType visu_gl_ext_frame_get_type(void); gboolean visu_gl_ext_frame_setPosition(VisuGlExtFrame *frame, float xpos, float ypos); gboolean visu_gl_ext_frame_setBgRGBA(VisuGlExtFrame *frame, float rgba[4], int mask); gboolean visu_gl_ext_frame_setFontRGB(VisuGlExtFrame *frame, float rgb[3], int mask); gboolean visu_gl_ext_frame_setScale(VisuGlExtFrame *frame, float scale); gboolean visu_gl_ext_frame_setTitle(VisuGlExtFrame *frame, const gchar *title); gboolean visu_gl_ext_frame_setRequisition(VisuGlExtFrame *frame, guint width, guint height); gboolean visu_gl_ext_frame_setPadding(VisuGlExtFrame *frame, float xpad, float ypad); void visu_gl_ext_frame_getPosition(const VisuGlExtFrame *frame, float *xpos, float *ypos); float visu_gl_ext_frame_getScale(const VisuGlExtFrame *frame); #endif v_sim-3.8.0/src/extensions/geodiff.c000066400000000000000000000244401370110300500173660ustar00rootroot00000000000000/* EXTRAITS DE LA LICENCE Copyright CEA, contributeurs : Damien CALISTE, laboratoire L_Sim, (2011-2013) Adresse mèl : BILLARD, non joignable par mèl ; CALISTE, damien P caliste AT cea P fr. Ce logiciel est un programme informatique servant à visualiser des structures atomiques dans un rendu pseudo-3D. Ce logiciel est régi par la licence CeCILL soumise au droit français et respectant les principes de diffusion des logiciels libres. Vous pouvez utiliser, modifier et/ou redistribuer ce programme sous les conditions de la licence CeCILL telle que diffusée par le CEA, le CNRS et l'INRIA sur le site "http://www.cecill.info". Le fait que vous puissiez accéder à cet en-tête signifie que vous avez pris connaissance de la licence CeCILL, et que vous en avez accepté les termes (cf. le fichier Documentation/licence.fr.txt fourni avec ce logiciel). */ /* LICENCE SUM UP Copyright CEA, contributors : Damien CALISTE, laboratoire L_Sim, (2011-2013) E-mail address: BILLARD, not reachable any more ; CALISTE, damien P caliste AT cea P fr. This software is a computer program whose purpose is to visualize atomic configurations in 3D. This software is governed by the CeCILL license under French law and abiding by the rules of distribution of free software. You can use, modify and/ or redistribute the software under the terms of the CeCILL license as circulated by CEA, CNRS and INRIA at the following URL "http://www.cecill.info". The fact that you are presently reading this means that you have had knowledge of the CeCILL license and that you accept its terms. You can find a copy of this licence shipped with this software at Documentation/licence.en.txt. */ #include "geodiff.h" #include #include #define FLAG_RESOURCE_ARROW "nodeDisplacement_arrow" #define DESC_RESOURCE_ARROW "Describe the arrow to be drawn ; four floats (tail lg. tail rd. head lg. head rd., negative values means auto)" static float arrow[4] = {4.f, .2f, .5f, .3f}; #define FLAG_RESOURCE_RATIO_MIN "nodeDisplacement_minThreshold" #define DESC_RESOURCE_RATIO_MIN "Choose the minimum value for drawn arrows in geometry differences ; float (ratio threshold if between -1 and 0)" #define DEFT_RESOURCE_RATIO_MIN -0.1f static float ratioMin = DEFT_RESOURCE_RATIO_MIN; #define FLAG_RESOURCE_RATIO_STR "nodeDisplacement_lblThreshold" #define DESC_RESOURCE_RATIO_STR "Choose the minimum value for labels in geometry differences ; float (ratio threshold if between -1 and 0)" #define DEFT_RESOURCE_RATIO_STR -0.9f static float ratioStr = DEFT_RESOURCE_RATIO_STR; #define FLAG_RESOURCE_MULT "nodeDisplacement_factor" #define DESC_RESOURCE_MULT "Choose the factor to draw arrows in geometry differences ; float (negative means auto)" #define DEFT_RESOURCE_MULT -1.f static float mult = DEFT_RESOURCE_MULT; #define DEFT_RESOURCE_SCAL -4.f static void exportResourcesDiff(GString *data, VisuData *dataObj); /** * SECTION:geodiff * @short_description: Draw arrows at each node to represent geodiff. * * A specialised #VisuGlExtNodeVectors to represent geodiff on nodes. */ /** * VisuGlExtGeodiffClass: * @parent: the parent class; * * A short way to identify #_VisuGlExtGeodiffClass structure. * * Since: 3.7 */ /** * VisuGlExtGeodiff: * * An opaque structure. * * Since: 3.7 */ #include static float scal = DEFT_RESOURCE_SCAL; /* Local callbacks. */ static void onEntryArrow(VisuGlExtGeodiff *geodiff, VisuConfigFileEntry *entry, VisuConfigFile *obj); static void onEntryRatioMin(VisuGlExtGeodiff *geodiff, VisuConfigFileEntry *entry, VisuConfigFile *obj); static void onEntryRatioStr(VisuGlExtGeodiff *geodiff, VisuConfigFileEntry *entry, VisuConfigFile *obj); static void onEntryMult(VisuGlExtGeodiff *geodiff, VisuConfigFileEntry *entry, VisuConfigFile *obj); G_DEFINE_TYPE(VisuGlExtGeodiff, visu_gl_ext_geodiff, VISU_TYPE_GL_EXT_NODE_VECTORS) static void visu_gl_ext_geodiff_class_init(VisuGlExtGeodiffClass *klass _U_) { float rgRatio[2] = {-1.f, G_MAXFLOAT}; VisuConfigFileEntry *resourceEntry; DBG_fprintf(stderr, "Visu GlExt Geodiff: creating the class of the object.\n"); /* DBG_fprintf(stderr, " - adding new signals ;\n"); */ /* Resources for geodiff extensions. */ resourceEntry = visu_config_file_addFloatArrayEntry(VISU_CONFIG_FILE_RESOURCE, FLAG_RESOURCE_ARROW, DESC_RESOURCE_ARROW, 4, arrow, rgRatio, FALSE); visu_config_file_entry_setVersion(resourceEntry, 3.5f); resourceEntry = visu_config_file_addFloatArrayEntry(VISU_CONFIG_FILE_RESOURCE, FLAG_RESOURCE_RATIO_MIN, DESC_RESOURCE_RATIO_MIN, 1, &ratioMin, rgRatio, FALSE); visu_config_file_entry_setVersion(resourceEntry, 3.5f); resourceEntry = visu_config_file_addFloatArrayEntry(VISU_CONFIG_FILE_RESOURCE, FLAG_RESOURCE_RATIO_STR, DESC_RESOURCE_RATIO_STR, 1, &ratioStr, rgRatio, FALSE); visu_config_file_entry_setVersion(resourceEntry, 3.5f); resourceEntry = visu_config_file_addFloatArrayEntry(VISU_CONFIG_FILE_RESOURCE, FLAG_RESOURCE_MULT, DESC_RESOURCE_MULT, 1, &mult, rgRatio, FALSE); visu_config_file_entry_setVersion(resourceEntry, 3.5f); visu_config_file_addExportFunction(VISU_CONFIG_FILE_RESOURCE, exportResourcesDiff); } static void visu_gl_ext_geodiff_init(VisuGlExtGeodiff *obj) { DBG_fprintf(stderr, "Visu GlExt Geodiff: initializing a new object (%p).\n", (gpointer)obj); /* Private data. */ g_signal_connect_object(VISU_CONFIG_FILE_RESOURCE, "parsed::" FLAG_RESOURCE_ARROW, G_CALLBACK(onEntryArrow), (gpointer)obj, G_CONNECT_SWAPPED); g_signal_connect_object(VISU_CONFIG_FILE_RESOURCE, "parsed::" FLAG_RESOURCE_RATIO_MIN, G_CALLBACK(onEntryRatioMin), (gpointer)obj, G_CONNECT_SWAPPED); g_signal_connect_object(VISU_CONFIG_FILE_RESOURCE, "parsed::" FLAG_RESOURCE_RATIO_STR, G_CALLBACK(onEntryRatioStr), (gpointer)obj, G_CONNECT_SWAPPED); g_signal_connect_object(VISU_CONFIG_FILE_RESOURCE, "parsed::" FLAG_RESOURCE_MULT, G_CALLBACK(onEntryMult), (gpointer)obj, G_CONNECT_SWAPPED); } /** * visu_gl_ext_geodiff_new: * @name: (allow-none): the name to give to the extension. * * Creates a new #VisuGlExt to draw geodiff. * * Since: 3.7 * * Returns: a pointer to the #VisuGlExt it created or * NULL otherwise. */ VisuGlExtGeodiff* visu_gl_ext_geodiff_new(const gchar *name) { char *name_ = "Geodiff"; char *description = _("Draw geodiff with vectors."); VisuGlExtNodeVectors *geodiff; DBG_fprintf(stderr,"Visu GlExt Geodiff: new object.\n"); geodiff = VISU_GL_EXT_NODE_VECTORS(g_object_new(VISU_TYPE_GL_EXT_GEODIFF, "name", (name)?name:name_, "label", _(name), "description", description, "nGlObj", 1, NULL)); visu_gl_ext_node_vectors_setCentering(geodiff, VISU_GL_ARROW_CENTERED); visu_gl_ext_node_vectors_setColor(geodiff, VISU_COLOR_BRIGHT); visu_gl_ext_node_vectors_setRenderedSize(geodiff, scal); visu_gl_ext_node_vectors_setNormalisation(geodiff, mult); visu_gl_ext_node_vectors_setArrow(geodiff, arrow[0], arrow[1], 10, arrow[2], arrow[3], 10); visu_gl_ext_node_vectors_setVectorThreshold(geodiff, ratioMin); visu_gl_ext_node_vectors_setLabelThreshold(geodiff, ratioStr); return VISU_GL_EXT_GEODIFF(geodiff); } /* Callbacks. */ static void onEntryArrow(VisuGlExtGeodiff *geodiff, VisuConfigFileEntry *entry _U_, VisuConfigFile *obj _U_) { float vals[4]; vals[0] = (arrow[0] > 0.f)?arrow[0]:4.f; vals[1] = (arrow[1] > 0.f)?arrow[1]:.2f; vals[2] = (arrow[2] > 0.f)?arrow[2]:.5f; vals[3] = (arrow[3] > 0.f)?arrow[3]:.3f; visu_gl_ext_node_vectors_setArrow(VISU_GL_EXT_NODE_VECTORS(geodiff), vals[0], vals[1], 10, vals[2], vals[3], 10); visu_gl_ext_node_vectors_setRenderedSize(VISU_GL_EXT_NODE_VECTORS(geodiff), (arrow[0] > 0.f)?arrow[0]:-4.f); } static void onEntryRatioMin(VisuGlExtGeodiff *geodiff, VisuConfigFileEntry *entry _U_, VisuConfigFile *obj _U_) { visu_gl_ext_node_vectors_setVectorThreshold(VISU_GL_EXT_NODE_VECTORS(geodiff), ratioMin); } static void onEntryRatioStr(VisuGlExtGeodiff *geodiff, VisuConfigFileEntry *entry _U_, VisuConfigFile *obj _U_) { visu_gl_ext_node_vectors_setLabelThreshold(VISU_GL_EXT_NODE_VECTORS(geodiff), ratioStr); } static void onEntryMult(VisuGlExtGeodiff *geodiff, VisuConfigFileEntry *entry _U_, VisuConfigFile *obj _U_) { visu_gl_ext_node_vectors_setNormalisation(VISU_GL_EXT_NODE_VECTORS(geodiff), mult); } /* Resources. */ static void exportResourcesDiff(GString *data, VisuData *dataObj _U_) { visu_config_file_exportComment(data, DESC_RESOURCE_ARROW); visu_config_file_exportEntry(data, FLAG_RESOURCE_ARROW, NULL, "%f %f %f %f", arrow[0], arrow[1], arrow[2], arrow[3]); visu_config_file_exportComment(data, DESC_RESOURCE_MULT); visu_config_file_exportEntry(data, FLAG_RESOURCE_MULT, NULL, "%f", mult); visu_config_file_exportComment(data, DESC_RESOURCE_RATIO_MIN); visu_config_file_exportEntry(data, FLAG_RESOURCE_RATIO_MIN, NULL, "%f", ratioMin); visu_config_file_exportComment(data, DESC_RESOURCE_RATIO_STR); visu_config_file_exportEntry(data, FLAG_RESOURCE_RATIO_STR, NULL, "%f", ratioStr); visu_config_file_exportComment(data, ""); } v_sim-3.8.0/src/extensions/geodiff.h000066400000000000000000000072631370110300500173770ustar00rootroot00000000000000/* EXTRAITS DE LA LICENCE Copyright CEA, contributeurs : Damien CALISTE, laboratoire L_Sim, (2001-2013) Adresse mèl : CALISTE, damien P caliste AT cea P fr. Ce logiciel est un programme informatique servant à visualiser des structures atomiques dans un rendu pseudo-3D. Ce logiciel est régi par la licence CeCILL soumise au droit français et respectant les principes de diffusion des logiciels libres. Vous pouvez utiliser, modifier et/ou redistribuer ce programme sous les conditions de la licence CeCILL telle que diffusée par le CEA, le CNRS et l'INRIA sur le site "http://www.cecill.info". Le fait que vous puissiez accéder à cet en-tête signifie que vous avez pris connaissance de la licence CeCILL, et que vous en avez accepté les termes (cf. le fichier Documentation/licence.fr.txt fourni avec ce logiciel). */ /* LICENCE SUM UP Copyright CEA, contributors : Damien CALISTE, laboratoire L_Sim, (2001-2013) E-mail address: CALISTE, damien P caliste AT cea P fr. This software is a computer program whose purpose is to visualize atomic configurations in 3D. This software is governed by the CeCILL license under French law and abiding by the rules of distribution of free software. You can use, modify and/ or redistribute the software under the terms of the CeCILL license as circulated by CEA, CNRS and INRIA at the following URL "http://www.cecill.info". The fact that you are presently reading this means that you have had knowledge of the CeCILL license and that you accept its terms. You can find a copy of this licence shipped with this software at COPYING. */ #ifndef GEODIFF_H #define GEODIFF_H #include "node_vectors.h" /** * VISU_TYPE_GL_EXT_GEODIFF: * * return the type of #VisuGlExtGeodiff. * * Since: 3.8 */ #define VISU_TYPE_GL_EXT_GEODIFF (visu_gl_ext_geodiff_get_type ()) /** * VISU_GL_EXT_GEODIFF: * @obj: a #GObject to cast. * * Cast the given @obj into #VisuGlExtGeodiff type. * * Since: 3.8 */ #define VISU_GL_EXT_GEODIFF(obj) (G_TYPE_CHECK_INSTANCE_CAST(obj, VISU_TYPE_GL_EXT_GEODIFF, VisuGlExtGeodiff)) /** * VISU_GL_EXT_GEODIFF_CLASS: * @klass: a #GObjectClass to cast. * * Cast the given @klass into #VisuGlExtGeodiffClass. * * Since: 3.8 */ #define VISU_GL_EXT_GEODIFF_CLASS(klass) (G_TYPE_CHECK_CLASS_CAST(klass, VISU_TYPE_GL_EXT_GEODIFF, VisuGlExtGeodiffClass)) /** * VISU_IS_GL_EXT_GEODIFF: * @obj: a #GObject to test. * * Test if the given @ogj is of the type of #VisuGlExtGeodiff object. * * Since: 3.8 */ #define VISU_IS_GL_EXT_GEODIFF(obj) (G_TYPE_CHECK_INSTANCE_TYPE(obj, VISU_TYPE_GL_EXT_GEODIFF)) /** * VISU_IS_GL_EXT_GEODIFF_CLASS: * @klass: a #GObjectClass to test. * * Test if the given @klass is of the type of #VisuGlExtGeodiffClass class. * * Since: 3.8 */ #define VISU_IS_GL_EXT_GEODIFF_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE(klass, VISU_TYPE_GL_EXT_GEODIFF)) /** * VISU_GL_EXT_GEODIFF_GET_CLASS: * @obj: a #GObject to get the class of. * * It returns the class of the given @obj. * * Since: 3.8 */ #define VISU_GL_EXT_GEODIFF_GET_CLASS(obj) (G_TYPE_INSTANCE_GET_CLASS(obj, VISU_TYPE_GL_EXT_GEODIFF, VisuGlExtGeodiffClass)) typedef struct _VisuGlExtGeodiff VisuGlExtGeodiff; typedef struct _VisuGlExtGeodiffClass VisuGlExtGeodiffClass; struct _VisuGlExtGeodiff { VisuGlExtNodeVectors parent; }; struct _VisuGlExtGeodiffClass { VisuGlExtNodeVectorsClass parent; }; /** * visu_gl_ext_geodiff_get_type: * * This method returns the type of #VisuGlExtGeodiff, use * VISU_TYPE_GL_EXT_GEODIFF instead. * * Since: 3.8 * * Returns: the type of #VisuGlExtGeodiff. */ GType visu_gl_ext_geodiff_get_type(void); VisuGlExtGeodiff* visu_gl_ext_geodiff_new(const gchar *name); #endif v_sim-3.8.0/src/extensions/iface_lined.c000066400000000000000000000167051370110300500202120ustar00rootroot00000000000000/* EXTRAITS DE LA LICENCE Copyright CEA, contributeurs : Luc BILLARD et Damien CALISTE, laboratoire L_Sim, (2001-2014) Adresse mèl : BILLARD, non joignable par mèl ; CALISTE, damien P caliste AT cea P fr. Ce logiciel est un programme informatique servant à visualiser des structures atomiques dans un rendu pseudo-3D. Ce logiciel est régi par la licence CeCILL soumise au droit français et respectant les principes de diffusion des logiciels libres. Vous pouvez utiliser, modifier et/ou redistribuer ce programme sous les conditions de la licence CeCILL telle que diffusée par le CEA, le CNRS et l'INRIA sur le site "http://www.cecill.info". Le fait que vous puissiez accéder à cet en-tête signifie que vous avez pris connaissance de la licence CeCILL, et que vous en avez accepté les termes (cf. le fichier Documentation/licence.fr.txt fourni avec ce logiciel). */ /* LICENCE SUM UP Copyright CEA, contributors : Luc BILLARD et Damien CALISTE, laboratoire L_Sim, (2001-2014) E-mail address: BILLARD, not reachable any more ; CALISTE, damien P caliste AT cea P fr. This software is a computer program whose purpose is to visualize atomic configurations in 3D. This software is governed by the CeCILL license under French law and abiding by the rules of distribution of free software. You can use, modify and/ or redistribute the software under the terms of the CeCILL license as circulated by CEA, CNRS and INRIA at the following URL "http://www.cecill.info". The fact that you are presently reading this means that you have had knowledge of the CeCILL license and that you accept its terms. You can find a copy of this licence shipped with this software at Documentation/licence.en.txt. */ #include "iface_lined.h" #include #include /** * SECTION:iface_lined * @short_description: Defines a common interface for #VisuGlExt * objects with line characteristics. * @See_also: #VisuGlExtAxes, #VisuGlExtScale or #VisuGlExtBox * * * * Since: 3.8 */ /* enum */ /* { */ /* SET_BOX_SIGNAL, */ /* NB_SIGNAL */ /* }; */ /* static guint signals[NB_SIGNAL] = { 0 }; */ enum { PROP_0, COLOR_PROP, WIDTH_PROP, STIPPLE_PROP, N_PROP }; static GParamSpec *properties[N_PROP]; /* GlExtLined interface. */ G_DEFINE_INTERFACE(VisuGlExtLined, visu_gl_ext_lined, G_TYPE_OBJECT) static void visu_gl_ext_lined_default_init(VisuGlExtLinedInterface *iface) { /** * VisuGlExtAxes::color: * * Store the color of the axes. * * Since: 3.8 */ properties[COLOR_PROP] = g_param_spec_boxed("color", "color", "rendering color", TOOL_TYPE_COLOR, G_PARAM_READWRITE); g_object_interface_install_property(iface, properties[COLOR_PROP]); /** * VisuGlExtAxes::width: * * Store the line width of the axes. * * Since: 3.8 */ properties[WIDTH_PROP] = g_param_spec_float("width", "line width", "rendering line width", 0., 10., 1., G_PARAM_READWRITE); g_object_interface_install_property(iface, properties[WIDTH_PROP]); /** * VisuGlExtAxes::stipple: * * Store the line stipple pattern of the axes. * * Since: 3.8 */ properties[STIPPLE_PROP] = g_param_spec_uint("stipple", "line stipple", "rendering line stipple pattern", 0, 65535, 65535, G_PARAM_READWRITE); g_object_interface_install_property(iface, properties[STIPPLE_PROP]); } /** * visu_gl_ext_lined_getWidth: * @self: the #VisuGlExtLined object to inquire. * * Read the line width used to draw lines. * * Since: 3.8 * * Returns: the value of current line width. */ gfloat visu_gl_ext_lined_getWidth(const VisuGlExtLined *self) { g_return_val_if_fail(VISU_IS_GL_EXT_LINED(self), 0.f); return VISU_GL_EXT_LINED_GET_INTERFACE(self)->get_width(self); } /** * visu_gl_ext_lined_getStipple: * @self: the #VisuGlExtLined object to inquire. * * Read the line pattern used to draw lines. * * Since: 3.8 * * Returns: the value of current line pattern. */ guint16 visu_gl_ext_lined_getStipple(const VisuGlExtLined *self) { g_return_val_if_fail(VISU_IS_GL_EXT_LINED(self), 0); return VISU_GL_EXT_LINED_GET_INTERFACE(self)->get_stipple(self); } /** * visu_gl_ext_lined_getRGBA: * @self: the #VisuGlExtLined object to inquire. * * Read all the colour components of the line (in [0;1]). * * Since: 3.8 * * Returns: (array fixed-size=4) (transfer none): four RGB values, * private from V_Sim, read only. */ gfloat* visu_gl_ext_lined_getRGBA(const VisuGlExtLined *self) { g_return_val_if_fail(VISU_IS_GL_EXT_LINED(self), (gfloat*)0); return VISU_GL_EXT_LINED_GET_INTERFACE(self)->get_rgba(self); } /** * visu_gl_ext_lined_setWidth: * @self: the #VisuGlExtLined object to modify. * @value: value of the desired line width. * * Method used to change the value of the line width. * * Since: 3.8 * * Returns: TRUE if modified. */ gboolean visu_gl_ext_lined_setWidth(VisuGlExtLined *self, gfloat value) { gboolean ret; g_return_val_if_fail(VISU_IS_GL_EXT_LINED(self), FALSE); value = CLAMP(value, 0.01f, 10.f); if (value == VISU_GL_EXT_LINED_GET_INTERFACE(self)->get_width(self)) return FALSE; ret = VISU_GL_EXT_LINED_GET_INTERFACE(self)->set_width(self, value); g_object_notify_by_pspec(G_OBJECT(self), properties[WIDTH_PROP]); return ret; } /** * visu_gl_ext_lined_setStipple: * @self: the #VisuGlExtLined object to modify. * @value: value of the desired pattern. * * Method used to change the value of the line stipple. * * Since: 3.8 * * Returns: TRUE if modified. */ gboolean visu_gl_ext_lined_setStipple(VisuGlExtLined *self, guint16 value) { gboolean ret; g_return_val_if_fail(VISU_IS_GL_EXT_LINED(self), FALSE); if (value == VISU_GL_EXT_LINED_GET_INTERFACE(self)->get_stipple(self)) return FALSE; ret = VISU_GL_EXT_LINED_GET_INTERFACE(self)->set_stipple(self, value); g_object_notify_by_pspec(G_OBJECT(self), properties[STIPPLE_PROP]); return ret; } /** * visu_gl_ext_lined_setRGBA: * @self: the #VisuGlExtLined object to modify. * @values: (array fixed-size=4): a four floats array with values (0 * <= values <= 1) for the red, the green and the blue color. Only * values specified by the mask are really relevant. * @mask: use #TOOL_COLOR_MASK_R, #TOOL_COLOR_MASK_G, * #TOOL_COLOR_MASK_B, #TOOL_COLOR_MASK_A or a combinaison to * indicate what values in the rgb array must be taken into account. * * Method used to change the value of the color used to draw the line. * * Since: 3.8 * * Returns: TRUE if modified. */ gboolean visu_gl_ext_lined_setRGBA(VisuGlExtLined *self, gfloat values[4], gint mask) { gboolean ret; gfloat *rgba; g_return_val_if_fail(VISU_IS_GL_EXT_LINED(self), FALSE); rgba = VISU_GL_EXT_LINED_GET_INTERFACE(self)->get_rgba(self); g_return_val_if_fail(rgba, FALSE); ret = FALSE; if ((mask & TOOL_COLOR_MASK_R && rgba[0] != values[0]) || (mask & TOOL_COLOR_MASK_G && rgba[1] != values[1]) || (mask & TOOL_COLOR_MASK_B && rgba[2] != values[2]) || (mask & TOOL_COLOR_MASK_A && rgba[3] != values[3])) { ret = VISU_GL_EXT_LINED_GET_INTERFACE(self)->set_rgba(self, values, mask); g_object_notify_by_pspec(G_OBJECT(self), properties[COLOR_PROP]); } return ret; } v_sim-3.8.0/src/extensions/iface_lined.h000066400000000000000000000075211370110300500202130ustar00rootroot00000000000000/* EXTRAITS DE LA LICENCE Copyright CEA, contributeurs : Luc BILLARD et Damien CALISTE, laboratoire L_Sim, (2001-2014) Adresse mèl : BILLARD, non joignable par mèl ; CALISTE, damien P caliste AT cea P fr. Ce logiciel est un programme informatique servant à visualiser des structures atomiques dans un rendu pseudo-3D. Ce logiciel est régi par la licence CeCILL soumise au droit français et respectant les principes de diffusion des logiciels libres. Vous pouvez utiliser, modifier et/ou redistribuer ce programme sous les conditions de la licence CeCILL telle que diffusée par le CEA, le CNRS et l'INRIA sur le site "http://www.cecill.info". Le fait que vous puissiez accéder à cet en-tête signifie que vous avez pris connaissance de la licence CeCILL, et que vous en avez accepté les termes (cf. le fichier Documentation/licence.fr.txt fourni avec ce logiciel). */ /* LICENCE SUM UP Copyright CEA, contributors : Luc BILLARD et Damien CALISTE, laboratoire L_Sim, (2001-2014) E-mail address: BILLARD, not reachable any more ; CALISTE, damien P caliste AT cea P fr. This software is a computer program whose purpose is to visualize atomic configurations in 3D. This software is governed by the CeCILL license under French law and abiding by the rules of distribution of free software. You can use, modify and/ or redistribute the software under the terms of the CeCILL license as circulated by CEA, CNRS and INRIA at the following URL "http://www.cecill.info". The fact that you are presently reading this means that you have had knowledge of the CeCILL license and that you accept its terms. You can find a copy of this licence shipped with this software at Documentation/licence.en.txt. */ #ifndef IFACE_LINED_H #define IFACE_LINED_H #include #include G_BEGIN_DECLS /* GlExtLined interface. */ #define VISU_TYPE_GL_EXT_LINED (visu_gl_ext_lined_get_type ()) #define VISU_GL_EXT_LINED(obj) (G_TYPE_CHECK_INSTANCE_CAST ((obj), VISU_TYPE_GL_EXT_LINED, VisuGlExtLined)) #define VISU_IS_GL_EXT_LINED(obj) (G_TYPE_CHECK_INSTANCE_TYPE ((obj), VISU_TYPE_GL_EXT_LINED)) #define VISU_GL_EXT_LINED_GET_INTERFACE(inst) (G_TYPE_INSTANCE_GET_INTERFACE ((inst), VISU_TYPE_GL_EXT_LINED, VisuGlExtLinedInterface)) typedef struct _VisuGlExtLined VisuGlExtLined; /* dummy object */ typedef struct _VisuGlExtLinedInterface VisuGlExtLinedInterface; /** * VisuGlExtLined: * * Interface object. * * Since: 3.8 */ /** * VisuGlExtLinedInterface: * @parent: yet, its parent. * @get_width: a routine to get line width. * @set_width: a routine to set line width. * @get_stipple: a routine to get line stipple. * @set_stipple: a routine to set line stipple. * @get_rgba: a routine to get line color. * @set_rgba: a routine to set line color. * * The different routines common to objects implementing a #VisuGlExtLined interface. * * Since: 3.8 */ struct _VisuGlExtLinedInterface { GTypeInterface parent; gfloat (*get_width) (const VisuGlExtLined *self); guint16 (*get_stipple) (const VisuGlExtLined *self); gfloat* (*get_rgba) (const VisuGlExtLined *self); gboolean (*set_width) (VisuGlExtLined *self, gfloat value); gboolean (*set_stipple) (VisuGlExtLined *self, guint16 value); gboolean (*set_rgba) (VisuGlExtLined *self, gfloat values[4], gint mask); }; GType visu_gl_ext_lined_get_type (void); gfloat visu_gl_ext_lined_getWidth (const VisuGlExtLined *self); guint16 visu_gl_ext_lined_getStipple (const VisuGlExtLined *self); gfloat* visu_gl_ext_lined_getRGBA (const VisuGlExtLined *self); gboolean visu_gl_ext_lined_setWidth (VisuGlExtLined *self, gfloat value); gboolean visu_gl_ext_lined_setStipple (VisuGlExtLined *self, guint16 value); gboolean visu_gl_ext_lined_setRGBA (VisuGlExtLined *self, gfloat values[4], gint mask); G_END_DECLS #endif v_sim-3.8.0/src/extensions/infos.c000066400000000000000000000557261370110300500171140ustar00rootroot00000000000000/* EXTRAITS DE LA LICENCE Copyright CEA, contributeurs : Damien CALISTE, laboratoire L_Sim, (2001-2013) Adresse mèl : CALISTE, damien P caliste AT cea P fr. Ce logiciel est un programme informatique servant à visualiser des structures atomiques dans un rendu pseudo-3D. Ce logiciel est régi par la licence CeCILL soumise au droit français et respectant les principes de diffusion des logiciels libres. Vous pouvez utiliser, modifier et/ou redistribuer ce programme sous les conditions de la licence CeCILL telle que diffusée par le CEA, le CNRS et l'INRIA sur le site "http://www.cecill.info". Le fait que vous puissiez accéder à cet en-tête signifie que vous avez pris connaissance de la licence CeCILL, et que vous en avez accepté les termes (cf. le fichier Documentation/licence.fr.txt fourni avec ce logiciel). */ /* LICENCE SUM UP Copyright CEA, contributors : Damien CALISTE, laboratoire L_Sim, (2001-2013) E-mail address: CALISTE, damien P caliste AT cea P fr. This software is a computer program whose purpose is to visualize atomic configurations in 3D. This software is governed by the CeCILL license under French law and abiding by the rules of distribution of free software. You can use, modify and/ or redistribute the software under the terms of the CeCILL license as circulated by CEA, CNRS and INRIA at the following URL "http://www.cecill.info". The fact that you are presently reading this means that you have had knowledge of the CeCILL license and that you accept its terms. You can find a copy of this licence shipped with this software at COPYING. */ #include "infos.h" #include #include #include #include /** * SECTION:infos * @short_description: give the capability to draw some information * near each node. * * This part is used to draw some information near the * nodes. This information can be the one of a #VisuNodeProperty or * something else. When read from a #VisuNodeProperty, just giving the * name will produce the right output. In other cases a print routine * must be given. */ /* Interface for a routine to draw the informations into a label. */ typedef void (*DrawInfosFunc)(VisuData *data, VisuElement *element, VisuNode *node, VisuNodeValues *values); static void drawNumber(VisuData *data, VisuElement *element, VisuNode *node, VisuNodeValues *dataNode); static void drawElement(VisuData *data, VisuElement *element, VisuNode *node, VisuNodeValues *dataNode); static void drawProps(VisuData *data, VisuElement *element, VisuNode *node, VisuNodeValues *values); /** * VisuGlExtInfosClass: * @parent: the parent class; * * A short way to identify #_VisuGlExtInfosClass structure. * * Since: 3.7 */ /** * VisuGlExtInfos: * * An opaque structure. * * Since: 3.7 */ /** * VisuGlExtInfosPrivate: * * Private fields for #VisuGlExtInfos objects. * * Since: 3.7 */ struct _VisuGlExtInfosPrivate { gboolean dispose_has_run; /* What to draw. */ GArray *nodes; DrawInfosFunc draw; /* Object signals. */ VisuNodeArrayRenderer *renderer; gulong popDec, popInc, pos_sig, col_sig, vis_sig, siz_sig; VisuGlView *view; gulong thetaChg, phiChg, omegaChg; VisuNodeValues *values; gulong nodeChgd; }; enum { PROP_0, SELECTION_PROP, VALUES_PROP, N_PROP }; static GParamSpec *_properties[N_PROP]; static void visu_gl_ext_infos_finalize(GObject* obj); static void visu_gl_ext_infos_dispose(GObject* obj); static void visu_gl_ext_infos_get_property(GObject* obj, guint property_id, GValue *value, GParamSpec *pspec); static void visu_gl_ext_infos_set_property(GObject* obj, guint property_id, const GValue *value, GParamSpec *pspec); static void visu_gl_ext_infos_rebuild(VisuGlExt *ext); static void visu_gl_ext_infos_draw(VisuGlExt *infos); static gboolean visu_gl_ext_infos_setGlView(VisuGlExt *infos, VisuGlView *view); /* Callbacks. */ static void onPopulationIncrease(VisuNodeArrayRenderer *renderer, GArray *newNodes, gpointer user_data); static void onPopulationDecrease(VisuNodeArrayRenderer *renderer, GArray *oldNodes, gpointer user_data); static void onNodeValuesChanged(VisuNodeValues *values, VisuNode *node, gpointer user_data); static void _setNodeValues(VisuGlExtInfos *infos, VisuNodeValues *values); static void _setDirty(VisuGlExt *ext); G_DEFINE_TYPE_WITH_CODE(VisuGlExtInfos, visu_gl_ext_infos, VISU_TYPE_GL_EXT, G_ADD_PRIVATE(VisuGlExtInfos)) static void visu_gl_ext_infos_class_init(VisuGlExtInfosClass *klass) { DBG_fprintf(stderr, "Extension Infos: creating the class of the object.\n"); /* DBG_fprintf(stderr, " - adding new signals ;\n"); */ /* DBG_fprintf(stderr, " - adding new resources ;\n"); */ /* Connect the overloading methods. */ G_OBJECT_CLASS(klass)->dispose = visu_gl_ext_infos_dispose; G_OBJECT_CLASS(klass)->finalize = visu_gl_ext_infos_finalize; G_OBJECT_CLASS(klass)->set_property = visu_gl_ext_infos_set_property; G_OBJECT_CLASS(klass)->get_property = visu_gl_ext_infos_get_property; VISU_GL_EXT_CLASS(klass)->rebuild = visu_gl_ext_infos_rebuild; VISU_GL_EXT_CLASS(klass)->draw = visu_gl_ext_infos_draw; VISU_GL_EXT_CLASS(klass)->setGlView = visu_gl_ext_infos_setGlView; /** * VisuGlExtInfos::selection: * * The ids of selected nodes. * * Since: 3.8 */ _properties[SELECTION_PROP] = g_param_spec_boxed ("selection", "Selection", "ids of selected nodes.", G_TYPE_ARRAY, G_PARAM_READWRITE); /** * VisuGlExtInfos::values: * * Some #VisuNodeValues to display the values of. * * Since: 3.8 */ _properties[VALUES_PROP] = g_param_spec_object ("values", "Values", "some node values to display.", VISU_TYPE_NODE_VALUES, G_PARAM_READWRITE); g_object_class_install_properties(G_OBJECT_CLASS(klass), N_PROP, _properties); } static void visu_gl_ext_infos_init(VisuGlExtInfos *obj) { DBG_fprintf(stderr, "Extension Infos: initializing a new object (%p).\n", (gpointer)obj); obj->priv = visu_gl_ext_infos_get_instance_private(obj); obj->priv->dispose_has_run = FALSE; /* Private data. */ obj->priv->nodes = (GArray*)0; obj->priv->draw = drawNumber; obj->priv->values = (VisuNodeValues*)0; obj->priv->renderer = (VisuNodeArrayRenderer*)0; obj->priv->view = (VisuGlView*)0; } static void visu_gl_ext_infos_get_property(GObject* obj, guint property_id, GValue *value, GParamSpec *pspec) { DBG_fprintf(stderr, "Extension Infos: get property '%s' -> ", g_param_spec_get_name(pspec)); switch (property_id) { case SELECTION_PROP: g_value_set_boxed(value, VISU_GL_EXT_INFOS(obj)->priv->nodes); DBG_fprintf(stderr, "%p.\n", g_value_get_boxed(value)); break; case VALUES_PROP: g_value_set_object(value, VISU_GL_EXT_INFOS(obj)->priv->values); DBG_fprintf(stderr, "%p.\n", g_value_get_object(value)); break; default: /* We don't have any other property... */ G_OBJECT_WARN_INVALID_PROPERTY_ID(obj, property_id, pspec); break; } } static void visu_gl_ext_infos_set_property(GObject* obj, guint property_id, const GValue *value, GParamSpec *pspec) { VisuGlExtInfos *self = VISU_GL_EXT_INFOS(obj); DBG_fprintf(stderr, "Extension Infos: set property '%s'.\n", g_param_spec_get_name(pspec)); switch (property_id) { case SELECTION_PROP: if (self->priv->nodes) g_array_unref(self->priv->nodes); self->priv->nodes = g_value_dup_boxed(value); break; case VALUES_PROP: _setNodeValues(self, VISU_NODE_VALUES(g_value_get_object(value))); self->priv->draw = g_value_get_object(value) ? drawProps : NULL; break; default: /* We don't have any other property... */ G_OBJECT_WARN_INVALID_PROPERTY_ID(obj, property_id, pspec); break; } visu_gl_ext_setDirty(VISU_GL_EXT(obj), TRUE); } /* This method can be called several times. It should unref all of its reference to GObjects. */ static void visu_gl_ext_infos_dispose(GObject* obj) { VisuGlExtInfos *infos; DBG_fprintf(stderr, "Extension Infos: dispose object %p.\n", (gpointer)obj); infos = VISU_GL_EXT_INFOS(obj); if (infos->priv->dispose_has_run) return; infos->priv->dispose_has_run = TRUE; /* Disconnect signals. */ visu_gl_ext_infos_setGlView(VISU_GL_EXT(infos), (VisuGlView*)0); visu_gl_ext_infos_setDataRenderer(infos, (VisuNodeArrayRenderer*)0); _setNodeValues(infos, (VisuNodeValues*)0); /* Chain up to the parent class */ G_OBJECT_CLASS(visu_gl_ext_infos_parent_class)->dispose(obj); } /* This method is called once only. */ static void visu_gl_ext_infos_finalize(GObject* obj) { VisuGlExtInfos *infos; g_return_if_fail(obj); DBG_fprintf(stderr, "Extension Infos: finalize object %p.\n", (gpointer)obj); infos = VISU_GL_EXT_INFOS(obj); /* Free privs elements. */ DBG_fprintf(stderr, "Extension Infos: free private infos.\n"); if (infos->priv->nodes) g_array_unref(infos->priv->nodes); /* Chain up to the parent class */ DBG_fprintf(stderr, "Extension Infos: chain to parent.\n"); G_OBJECT_CLASS(visu_gl_ext_infos_parent_class)->finalize(obj); DBG_fprintf(stderr, "Extension Infos: freeing ... OK.\n"); } /** * visu_gl_ext_infos_new: * @name: (allow-none): the name of the #VisuGlExt. * * Create a new #VisuGlExt to represent information on nodes. * * Since: 3.7 * * Returns: a new #VisuGlExtInfos object. **/ VisuGlExtInfos* visu_gl_ext_infos_new(const gchar *name) { char *name_ = VISU_GL_EXT_INFOS_ID; char *description = _("Draw informations on nodes."); DBG_fprintf(stderr,"Extension Infos: new object.\n"); return g_object_new(VISU_TYPE_GL_EXT_INFOS, "name", (name)?name:name_, "label", _(name), "description", description, "nGlObj", 1, "priority", VISU_GL_EXT_PRIORITY_HIGH, NULL); } /********************/ /* Public routines. */ /********************/ /** * visu_gl_ext_infos_setDataRenderer: * @infos: The #VisuGlExtInfos to attached to. * @renderer: the #VisuNodeArrayRenderer displaying the data. * * Attach a #VisuNodeArrayRenderer to render to and setup the infos. * * Since: 3.7 * * Returns: TRUE if the model was actually changed. **/ gboolean visu_gl_ext_infos_setDataRenderer(VisuGlExtInfos *infos, VisuNodeArrayRenderer *renderer) { g_return_val_if_fail(VISU_IS_GL_EXT_INFOS(infos), FALSE); if (renderer == infos->priv->renderer) return FALSE; if (infos->priv->renderer) { g_signal_handler_disconnect(G_OBJECT(infos->priv->renderer), infos->priv->vis_sig); g_signal_handler_disconnect(G_OBJECT(infos->priv->renderer), infos->priv->pos_sig); g_signal_handler_disconnect(G_OBJECT(infos->priv->renderer), infos->priv->siz_sig); g_signal_handler_disconnect(G_OBJECT(infos->priv->renderer), infos->priv->col_sig); g_signal_handler_disconnect(G_OBJECT(infos->priv->renderer), infos->priv->popDec); g_signal_handler_disconnect(G_OBJECT(infos->priv->renderer), infos->priv->popInc); g_object_unref(infos->priv->renderer); } if (renderer) { g_object_ref(renderer); infos->priv->vis_sig = g_signal_connect_swapped(G_OBJECT(renderer), "nodes::visibility", G_CALLBACK(_setDirty), (gpointer)infos); infos->priv->pos_sig = g_signal_connect_swapped(G_OBJECT(renderer), "nodes::position", G_CALLBACK(_setDirty), (gpointer)infos); infos->priv->siz_sig = g_signal_connect_swapped(G_OBJECT(renderer), "element-size-changed", G_CALLBACK(_setDirty), (gpointer)infos); infos->priv->col_sig = g_signal_connect_swapped(G_OBJECT(renderer), "element-notify::color", G_CALLBACK(_setDirty), (gpointer)infos); infos->priv->popDec = g_signal_connect(G_OBJECT(renderer), "nodes::population-decrease", G_CALLBACK(onPopulationDecrease), (gpointer)infos); infos->priv->popInc = g_signal_connect(G_OBJECT(renderer), "nodes::population-increase", G_CALLBACK(onPopulationIncrease), (gpointer)infos); } infos->priv->renderer = renderer; visu_gl_ext_setDirty(VISU_GL_EXT(infos), TRUE); return TRUE; } static void _setNodeValues(VisuGlExtInfos *infos, VisuNodeValues *values) { g_return_if_fail(VISU_IS_GL_EXT_INFOS(infos)); if (values == infos->priv->values) return; if (infos->priv->values) { g_signal_handler_disconnect(G_OBJECT(infos->priv->values), infos->priv->nodeChgd); g_object_unref(infos->priv->values); } if (values) { g_object_ref(values); infos->priv->nodeChgd = g_signal_connect(G_OBJECT(values), "changed", G_CALLBACK(onNodeValuesChanged), (gpointer)infos); } infos->priv->values = values; g_object_notify_by_pspec(G_OBJECT(infos), _properties[VALUES_PROP]); } /** * visu_gl_ext_infos_drawIds: * @infos: the #VisuGlExtInfos object to update. * @nodes: (element-type guint) (transfer full): an integer list. * * With this extension, * some the number of nodes will be drawn on them. Numbers can be drawn and * all nodes (set @nodes to a NULL pointer), or to a restricted list of nodes * represented by their numbers. In this case, @nodes can have whatever length * but must be terminated by a negative integer. This array is then owned by the * extension and should not be freed. * * Returns: TRUE if the status was actually changed. */ gboolean visu_gl_ext_infos_drawIds(VisuGlExtInfos *infos, GArray *nodes) { g_return_val_if_fail(VISU_IS_GL_EXT_INFOS(infos), FALSE); if (infos->priv->nodes) g_array_unref(infos->priv->nodes); infos->priv->nodes = nodes ? g_array_ref(nodes) : (GArray*)0; g_object_notify_by_pspec(G_OBJECT(infos), _properties[SELECTION_PROP]); infos->priv->draw = drawNumber; _setNodeValues(infos, (VisuNodeValues*)0); visu_gl_ext_setDirty(VISU_GL_EXT(infos), TRUE); return TRUE; } /** * visu_gl_ext_infos_drawElements: * @infos: the #VisuGlExtInfos object to update. * @nodes: (element-type guint) (transfer full): an integer list. * * As visu_gl_ext_infos_drawIds(), but draw the names of elements instead of their * numbers. * * Returns: TRUE if the status was actually changed. */ gboolean visu_gl_ext_infos_drawElements(VisuGlExtInfos *infos, GArray *nodes) { g_return_val_if_fail(VISU_IS_GL_EXT_INFOS(infos), FALSE); if (infos->priv->nodes) g_array_unref(infos->priv->nodes); infos->priv->nodes = nodes ? g_array_ref(nodes) : (GArray*)0; g_object_notify_by_pspec(G_OBJECT(infos), _properties[SELECTION_PROP]); infos->priv->draw = drawElement; _setNodeValues(infos, (VisuNodeValues*)0); visu_gl_ext_setDirty(VISU_GL_EXT(infos), TRUE); return TRUE; } /** * visu_gl_ext_infos_drawNodeProperties: * @infos: the #VisuGlExtInfos object to update. * @values: the #VisuNodeValues to render on nodes. * @nodes: (element-type guint) (transfer full): an integer list. * * Draw @values on selected @nodes. * * Since: 3.8 * * Returns: TRUE. **/ gboolean visu_gl_ext_infos_drawNodeProperties(VisuGlExtInfos *infos, VisuNodeValues *values, GArray *nodes) { g_return_val_if_fail(VISU_IS_GL_EXT_INFOS(infos) && VISU_IS_NODE_VALUES(values), FALSE); if (infos->priv->nodes) g_array_unref(infos->priv->nodes); infos->priv->nodes = nodes ? g_array_ref(nodes) : (GArray*)0; g_object_notify_by_pspec(G_OBJECT(infos), _properties[SELECTION_PROP]); infos->priv->draw = (DrawInfosFunc)drawProps; _setNodeValues(infos, values); visu_gl_ext_setDirty(VISU_GL_EXT(infos), TRUE); return TRUE; } static gboolean visu_gl_ext_infos_setGlView(VisuGlExt *infos, VisuGlView *view) { VisuGlExtInfosPrivate *priv = VISU_GL_EXT_INFOS(infos)->priv; if (view == priv->view) return FALSE; if (priv->view) { g_signal_handler_disconnect(G_OBJECT(priv->view), priv->thetaChg); g_signal_handler_disconnect(G_OBJECT(priv->view), priv->phiChg); g_signal_handler_disconnect(G_OBJECT(priv->view), priv->omegaChg); g_clear_object(&priv->view); } if (view) { priv->view = g_object_ref(view); priv->thetaChg = g_signal_connect_swapped(G_OBJECT(view), "notify::theta", G_CALLBACK(_setDirty), (gpointer)infos); priv->phiChg = g_signal_connect_swapped(G_OBJECT(view), "notify::phi", G_CALLBACK(_setDirty), (gpointer)infos); priv->omegaChg = g_signal_connect_swapped(G_OBJECT(view), "notify::omega", G_CALLBACK(_setDirty), (gpointer)infos); } visu_gl_ext_setDirty(VISU_GL_EXT(infos), TRUE); return TRUE; } static void visu_gl_ext_infos_draw(VisuGlExt *infos) { float modelView[16]; float delta[3], xyz[3], size; VisuNodeArray *nodes; VisuNodeArrayRendererIter iter; guint i; gboolean valid; VisuGlExtInfosPrivate *priv = VISU_GL_EXT_INFOS(infos)->priv; glDeleteLists(visu_gl_ext_getGlList(VISU_GL_EXT(infos)), 1); visu_gl_ext_setDirty(VISU_GL_EXT(infos), FALSE); /* Nothing to draw; */ if(!priv->view || !priv->renderer || !priv->draw) return; /* Get the camera orientation. */ glGetFloatv(GL_MODELVIEW_MATRIX, modelView); visu_gl_text_initFontList(); visu_gl_ext_startDrawing(infos); glPushAttrib(GL_ENABLE_BIT); glDisable(GL_LIGHTING); /* If nodes is NULL, we draw for all nodes. */ nodes = visu_node_array_renderer_getNodeArray(priv->renderer); if (!priv->nodes || !priv->nodes->len) { DBG_fprintf(stderr, " | use all the nodes.\n"); for (valid = visu_node_array_renderer_iter_new(priv->renderer, &iter, TRUE); valid; valid = visu_node_array_renderer_iter_next(&iter)) if (visu_element_getRendered(iter.element)) { visu_element_renderer_colorize(iter.renderer, VISU_ELEMENT_RENDERER_INVERT); size = visu_element_renderer_getExtent(iter.renderer); delta[0] = size * modelView[2]; delta[1] = size * modelView[6]; delta[2] = size * modelView[10]; for(visu_node_array_iterRestartNode(iter.parent.array, &iter.parent); iter.parent.node; visu_node_array_iterNextNode(iter.parent.array, &iter.parent)) if (iter.parent.node->rendered) { visu_data_getNodePosition(VISU_DATA(iter.parent.array), iter.parent.node, xyz); glRasterPos3f(xyz[0] + delta[0], xyz[1] + delta[1], xyz[2] + delta[2]); priv->draw(VISU_DATA(nodes), iter.element, iter.parent.node, priv->values); } } } else { DBG_fprintf(stderr, " | use a restricted list of nodes.\n"); /* nodes is not NULL, we draw for the given nodes only. */ for (i = 0; i < priv->nodes->len; i++) { DBG_fprintf(stderr, " | %d\n", g_array_index(priv->nodes, guint, i)); iter.parent.node = visu_node_array_getFromId (nodes, g_array_index(priv->nodes, guint, i)); g_return_if_fail(iter.parent.node); iter.element = visu_node_array_getElement(nodes, iter.parent.node); if (visu_element_getRendered(iter.element) && iter.parent.node->rendered) { iter.renderer = visu_node_array_renderer_get(priv->renderer, iter.element); visu_element_renderer_colorize(iter.renderer, VISU_ELEMENT_RENDERER_INVERT); size = visu_element_renderer_getExtent(iter.renderer); delta[0] = size * modelView[2]; delta[1] = size * modelView[6]; delta[2] = size * modelView[10]; visu_data_getNodePosition(VISU_DATA(nodes), iter.parent.node, xyz); glRasterPos3f(xyz[0] + delta[0], xyz[1] + delta[1], xyz[2] + delta[2]); priv->draw(VISU_DATA(nodes), iter.element, iter.parent.node, priv->values); } } } glPopAttrib(); visu_gl_ext_completeDrawing(infos); } /*********************/ /* Private routines. */ /*********************/ static void visu_gl_ext_infos_rebuild(VisuGlExt *ext) { visu_gl_text_rebuildFontList(); visu_gl_ext_setDirty(ext, TRUE); visu_gl_ext_infos_draw(ext); } static void drawNumber(VisuData *data _U_, VisuElement *element _U_, VisuNode *node, VisuNodeValues *dataNode _U_) { gchar str[10]; sprintf(str, "%d", node->number + 1); visu_gl_text_drawChars(str, VISU_GL_TEXT_NORMAL); } static void drawElement(VisuData *data _U_, VisuElement *element, VisuNode *node _U_, VisuNodeValues *dataNode _U_) { visu_gl_text_drawChars(element->name, VISU_GL_TEXT_NORMAL); } static void drawProps(VisuData *data _U_, VisuElement *element _U_, VisuNode *node, VisuNodeValues *values) { gchar *label; label = visu_node_values_toString(values, node); if (label) visu_gl_text_drawChars(label, VISU_GL_TEXT_NORMAL); g_free(label); } /*************/ /* Callbacks */ /*************/ static void _setDirty(VisuGlExt *ext) { visu_gl_ext_setDirty(ext, TRUE); } static void onPopulationIncrease(VisuNodeArrayRenderer *renderer _U_, GArray *newNodes _U_, gpointer user_data) { VisuGlExtInfos *infos = VISU_GL_EXT_INFOS(user_data); /* If we draw all nodes, then we must redraw. */ if (!infos->priv->nodes || !infos->priv->nodes->len) visu_gl_ext_setDirty(VISU_GL_EXT(user_data), TRUE); } static void onPopulationDecrease(VisuNodeArrayRenderer *renderer _U_, GArray *oldNodes, gpointer user_data) { VisuGlExtInfos *infos = VISU_GL_EXT_INFOS(user_data); guint i; DBG_fprintf(stderr, "Extension Informations: caught the 'PopulationDecrease'" " signal, update and rebuild in list nodes case.\n"); /* If we draw a list of nodes, then we must remove some and redraw. */ /* We remove all old nodes. */ if (infos->priv->nodes) { for (i = 0; i < oldNodes->len; i++) g_array_remove_index_fast(infos->priv->nodes, g_array_index(oldNodes, guint, i)); g_object_notify_by_pspec(G_OBJECT(infos), _properties[SELECTION_PROP]); } visu_gl_ext_setDirty(VISU_GL_EXT(user_data), TRUE); } static void onNodeValuesChanged(VisuNodeValues *values _U_, VisuNode *node, gpointer user_data) { VisuGlExtInfos *infos = VISU_GL_EXT_INFOS(user_data); guint i; DBG_fprintf(stderr, "Extension Informations: caught the 'changed'" " signal, rebuild.\n"); if (!infos->priv->nodes || !infos->priv->nodes->len || !node) { visu_gl_ext_setDirty(VISU_GL_EXT(user_data), TRUE); return; } for (i = 0; i < infos->priv->nodes->len; i++) if (g_array_index(infos->priv->nodes, guint, i) == node->number) { visu_gl_ext_setDirty(VISU_GL_EXT(user_data), TRUE); return; } } v_sim-3.8.0/src/extensions/infos.h000066400000000000000000000115111370110300500171010ustar00rootroot00000000000000/* EXTRAITS DE LA LICENCE Copyright CEA, contributeurs : Luc BILLARD et Damien CALISTE, laboratoire L_Sim, (2001-2005) Adresse mèl : BILLARD, non joignable par mèl ; CALISTE, damien P caliste AT cea P fr. Ce logiciel est un programme informatique servant à visualiser des structures atomiques dans un rendu pseudo-3D. Ce logiciel est régi par la licence CeCILL soumise au droit français et respectant les principes de diffusion des logiciels libres. Vous pouvez utiliser, modifier et/ou redistribuer ce programme sous les conditions de la licence CeCILL telle que diffusée par le CEA, le CNRS et l'INRIA sur le site "http://www.cecill.info". Le fait que vous puissiez accéder à cet en-tête signifie que vous avez pris connaissance de la licence CeCILL, et que vous en avez accepté les termes (cf. le fichier Documentation/licence.fr.txt fourni avec ce logiciel). */ /* LICENCE SUM UP Copyright CEA, contributors : Luc BILLARD et Damien CALISTE, laboratoire L_Sim, (2001-2005) E-mail address: BILLARD, not reachable any more ; CALISTE, damien P caliste AT cea P fr. This software is a computer program whose purpose is to visualize atomic configurations in 3D. This software is governed by the CeCILL license under French law and abiding by the rules of distribution of free software. You can use, modify and/ or redistribute the software under the terms of the CeCILL license as circulated by CEA, CNRS and INRIA at the following URL "http://www.cecill.info". The fact that you are presently reading this means that you have had knowledge of the CeCILL license and that you accept its terms. You can find a copy of this licence shipped with this software at Documentation/licence.en.txt. */ #ifndef EXTINFOS_H #define EXTINFOS_H #include #include #include #include /** * VisuGlExtInfosDrawId: * @DRAW_NEVER: don't draw any information on nodes ; * @DRAW_SELECTED: draw information only on a list of nodes ; * @DRAW_ALWAYS: draw information on all nodes. * * This enum represents the possibilities for the information drawing. */ typedef enum { DRAW_NEVER, DRAW_SELECTED, DRAW_ALWAYS } VisuGlExtInfosDrawId; /** * VISU_TYPE_GL_EXT_INFOS: * * return the type of #VisuGlExtInfos. * * Since: 3.7 */ #define VISU_TYPE_GL_EXT_INFOS (visu_gl_ext_infos_get_type ()) /** * VISU_GL_EXT_INFOS: * @obj: a #GObject to cast. * * Cast the given @obj into #VisuGlExtInfos type. * * Since: 3.7 */ #define VISU_GL_EXT_INFOS(obj) (G_TYPE_CHECK_INSTANCE_CAST(obj, VISU_TYPE_GL_EXT_INFOS, VisuGlExtInfos)) /** * VISU_GL_EXT_INFOS_CLASS: * @klass: a #GObjectClass to cast. * * Cast the given @klass into #VisuGlExtInfosClass. * * Since: 3.7 */ #define VISU_GL_EXT_INFOS_CLASS(klass) (G_TYPE_CHECK_CLASS_CAST(klass, VISU_TYPE_GL_EXT_INFOS, VisuGlExtInfosClass)) /** * VISU_IS_GL_EXT_INFOS: * @obj: a #GObject to test. * * Test if the given @ogj is of the type of #VisuGlExtInfos object. * * Since: 3.7 */ #define VISU_IS_GL_EXT_INFOS(obj) (G_TYPE_CHECK_INSTANCE_TYPE(obj, VISU_TYPE_GL_EXT_INFOS)) /** * VISU_IS_GL_EXT_INFOS_CLASS: * @klass: a #GObjectClass to test. * * Test if the given @klass is of the type of #VisuGlExtInfosClass class. * * Since: 3.7 */ #define VISU_IS_GL_EXT_INFOS_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE(klass, VISU_TYPE_GL_EXT_INFOS)) /** * VISU_GL_EXT_INFOS_GET_CLASS: * @obj: a #GObject to get the class of. * * It returns the class of the given @obj. * * Since: 3.7 */ #define VISU_GL_EXT_INFOS_GET_CLASS(obj) (G_TYPE_INSTANCE_GET_CLASS(obj, VISU_TYPE_GL_EXT_INFOS, VisuGlExtInfosClass)) typedef struct _VisuGlExtInfos VisuGlExtInfos; typedef struct _VisuGlExtInfosPrivate VisuGlExtInfosPrivate; typedef struct _VisuGlExtInfosClass VisuGlExtInfosClass; struct _VisuGlExtInfos { VisuGlExt parent; VisuGlExtInfosPrivate *priv; }; struct _VisuGlExtInfosClass { VisuGlExtClass parent; }; /** * VISU_GL_EXT_INFOS_ID: * * The id used to identify this extension, see * visu_gl_ext_rebuild() for instance. */ #define VISU_GL_EXT_INFOS_ID "Node information" /** * visu_gl_ext_infos_get_type: * * This method returns the type of #VisuGlExtInfos, use * VISU_TYPE_GL_EXT_INFOS instead. * * Since: 3.7 * * Returns: the type of #VisuGlExtInfos. */ GType visu_gl_ext_infos_get_type(void); VisuGlExtInfos* visu_gl_ext_infos_new(const gchar *name); gboolean visu_gl_ext_infos_setDataRenderer(VisuGlExtInfos *infos, VisuNodeArrayRenderer *renderer); gboolean visu_gl_ext_infos_drawIds(VisuGlExtInfos *infos, GArray *nodes); gboolean visu_gl_ext_infos_drawElements(VisuGlExtInfos *infos, GArray *nodes); gboolean visu_gl_ext_infos_drawNodeProperties(VisuGlExtInfos *infos, VisuNodeValues *values, GArray *nodes); #endif v_sim-3.8.0/src/extensions/legend.c000066400000000000000000000305041370110300500172170ustar00rootroot00000000000000/* EXTRAITS DE LA LICENCE Copyright CEA, contributeurs : Damien CALISTE, laboratoire L_Sim, (2001-2009) Adresse mèl : CALISTE, damien P caliste AT cea P fr. Ce logiciel est un programme informatique servant à visualiser des structures atomiques dans un rendu pseudo-3D. Ce logiciel est régi par la licence CeCILL soumise au droit français et respectant les principes de diffusion des logiciels libres. Vous pouvez utiliser, modifier et/ou redistribuer ce programme sous les conditions de la licence CeCILL telle que diffusée par le CEA, le CNRS et l'INRIA sur le site "http://www.cecill.info". Le fait que vous puissiez accéder à cet en-tête signifie que vous avez pris connaissance de la licence CeCILL, et que vous en avez accepté les termes (cf. le fichier Documentation/licence.fr.txt fourni avec ce logiciel). */ /* LICENCE SUM UP Copyright CEA, contributors : Damien CALISTE, laboratoire L_Sim, (2001-2009) E-mail address: CALISTE, damien P caliste AT cea P fr. This software is a computer program whose purpose is to visualize atomic configurations in 3D. This software is governed by the CeCILL license under French law and abiding by the rules of distribution of free software. You can use, modify and/ or redistribute the software under the terms of the CeCILL license as circulated by CEA, CNRS and INRIA at the following URL "http://www.cecill.info". The fact that you are presently reading this means that you have had knowledge of the CeCILL license and that you accept its terms. You can find a copy of this licence shipped with this software at COPYING. */ #include "legend.h" #include #include #include /** * SECTION:legend * @short_description: Draw a frame with the representation of each * atom species, its name and the number of elements. * * This extension draws a frame on top of the rendering area with an * item per #VisuElement currently rendered. For each #VisuElement, a * small representation of its OpenGL shape is drawn, its label is * printed and the number of #VisuNode associated to this * element. * This extension defines one resource entry labeled * "legend_is_on" to control if the legend is printed or not. * * Since: 3.5 */ #define FLAG_RESOURCE_LEGEND_USED "legend_is_on" #define DESC_RESOURCE_LEGEND_USED "Control if the legend is drawn ; boolean (0 or 1)" static gboolean DEFAULT_LEGEND_USED = FALSE; /** * VisuGlExtLegendClass: * @parent: the parent class; * * A short way to identify #_VisuGlExtLegendClass structure. * * Since: 3.7 */ /** * VisuGlExtLegend: * * An opaque structure. * * Since: 3.7 */ /** * VisuGlExtLegendPrivate: * * Private fields for #VisuGlExtLegend objects. * * Since: 3.7 */ struct _VisuGlExtLegendPrivate { gboolean dispose_has_run; /* Legend definition. */ VisuNodeArrayRenderer *nodes; gulong col_sig, mat_sig, pop_sig, siz_sig, ren_sig; }; static VisuGlExtLegend* defaultLegend; static void visu_gl_ext_legend_dispose(GObject* obj); static void visu_gl_ext_legend_draw(const VisuGlExtFrame *legend); static gboolean visu_gl_ext_legend_isValid(const VisuGlExtFrame *legend); static void visu_gl_ext_legend_rebuild(VisuGlExt *ext); /* Local callbacks. */ static void setDirty(VisuGlExt *ext); static void onEntryUsed(VisuGlExtLegend *lg, VisuConfigFileEntry *entry, VisuConfigFile *obj); /* Local routines. */ static void exportResources(GString *data, VisuData *dataObj); G_DEFINE_TYPE_WITH_CODE(VisuGlExtLegend, visu_gl_ext_legend, VISU_TYPE_GL_EXT_FRAME, G_ADD_PRIVATE(VisuGlExtLegend)) static void visu_gl_ext_legend_class_init(VisuGlExtLegendClass *klass) { VisuConfigFileEntry *resourceEntry; DBG_fprintf(stderr, "Extension Legend: creating the class of the object.\n"); /* DBG_fprintf(stderr, " - adding new signals ;\n"); */ DBG_fprintf(stderr, " - adding new resources ;\n"); resourceEntry = visu_config_file_addBooleanEntry(VISU_CONFIG_FILE_RESOURCE, FLAG_RESOURCE_LEGEND_USED, DESC_RESOURCE_LEGEND_USED, &DEFAULT_LEGEND_USED, FALSE); visu_config_file_entry_setVersion(resourceEntry, 3.5f); visu_config_file_addExportFunction(VISU_CONFIG_FILE_RESOURCE, exportResources); defaultLegend = (VisuGlExtLegend*)0; /* Connect the overloading methods. */ G_OBJECT_CLASS(klass)->dispose = visu_gl_ext_legend_dispose; VISU_GL_EXT_CLASS(klass)->rebuild = visu_gl_ext_legend_rebuild; VISU_GL_EXT_FRAME_CLASS(klass)->draw = visu_gl_ext_legend_draw; VISU_GL_EXT_FRAME_CLASS(klass)->isValid = visu_gl_ext_legend_isValid; } static void visu_gl_ext_legend_init(VisuGlExtLegend *obj) { DBG_fprintf(stderr, "Extension Legend: initializing a new object (%p).\n", (gpointer)obj); obj->priv = visu_gl_ext_legend_get_instance_private(obj); obj->priv->dispose_has_run = FALSE; /* Private data. */ obj->priv->nodes = (VisuNodeArrayRenderer*)0; g_signal_connect_object(VISU_CONFIG_FILE_RESOURCE, "parsed::" FLAG_RESOURCE_LEGEND_USED, G_CALLBACK(onEntryUsed), (gpointer)obj, G_CONNECT_SWAPPED); if (!defaultLegend) defaultLegend = obj; } /* This method can be called several times. It should unref all of its reference to GObjects. */ static void visu_gl_ext_legend_dispose(GObject* obj) { VisuGlExtLegend *legend; DBG_fprintf(stderr, "Extension Legend: dispose object %p.\n", (gpointer)obj); legend = VISU_GL_EXT_LEGEND(obj); if (legend->priv->dispose_has_run) return; legend->priv->dispose_has_run = TRUE; /* Disconnect signals. */ visu_gl_ext_legend_setNodes(legend, (VisuNodeArrayRenderer*)0); /* Chain up to the parent class */ G_OBJECT_CLASS(visu_gl_ext_legend_parent_class)->dispose(obj); } /** * visu_gl_ext_legend_new: * @name: (allow-none): the name to give to the extension (default is #VISU_GL_EXT_LEGEND_ID). * * Creates a new #VisuGlExt to draw a legend. * * Since: 3.7 * * Returns: a pointer to the #VisuGlExt it created or * NULL otherwise. */ VisuGlExtLegend* visu_gl_ext_legend_new(const gchar *name) { char *name_ = VISU_GL_EXT_LEGEND_ID; char *description = _("Draw the name and the shape of available elements on screen."); VisuGlExt *legend; #define LEGEND_HEIGHT 30 DBG_fprintf(stderr,"Extension Legend: new object.\n"); legend = VISU_GL_EXT(g_object_new(VISU_TYPE_GL_EXT_LEGEND, "active", DEFAULT_LEGEND_USED, "name", (name)?name:name_, "label", _(name), "description", description, "nGlObj", 1, "priority", VISU_GL_EXT_PRIORITY_LAST, "saveState", TRUE, "x-pos", 0.f, "y-pos", 1.f, "x-padding", 5.f, "y-padding", 3.f, NULL)); visu_gl_ext_frame_setRequisition(VISU_GL_EXT_FRAME(legend), G_MAXUINT / 2, LEGEND_HEIGHT); return VISU_GL_EXT_LEGEND(legend); } /** * visu_gl_ext_legend_setNodes: * @legend: The #VisuGlExtLegend to attached to. * @nodes: the nodes to get the population of. * * Attach an #VisuGlView to render to and setup the legend to get the * node population also. * * Since: 3.7 * * Returns: TRUE if model has been changed. **/ gboolean visu_gl_ext_legend_setNodes(VisuGlExtLegend *legend, VisuNodeArrayRenderer *nodes) { g_return_val_if_fail(VISU_IS_GL_EXT_LEGEND(legend), FALSE); if (legend->priv->nodes == nodes) return FALSE; if (legend->priv->nodes) { g_signal_handler_disconnect(G_OBJECT(legend->priv->nodes), legend->priv->ren_sig); g_signal_handler_disconnect(G_OBJECT(legend->priv->nodes), legend->priv->col_sig); g_signal_handler_disconnect(G_OBJECT(legend->priv->nodes), legend->priv->mat_sig); g_signal_handler_disconnect(G_OBJECT(legend->priv->nodes), legend->priv->pop_sig); g_signal_handler_disconnect(G_OBJECT(legend->priv->nodes), legend->priv->siz_sig); g_object_unref(legend->priv->nodes); } legend->priv->nodes = nodes; if (nodes) { g_object_ref(nodes); legend->priv->ren_sig = g_signal_connect_swapped(G_OBJECT(nodes), "element-notify::rendered", G_CALLBACK(setDirty), (gpointer)legend); legend->priv->col_sig = g_signal_connect_swapped(G_OBJECT(nodes), "element-notify::color", G_CALLBACK(setDirty), (gpointer)legend); legend->priv->mat_sig = g_signal_connect_swapped(G_OBJECT(nodes), "element-notify::material", G_CALLBACK(setDirty), (gpointer)legend); legend->priv->pop_sig = g_signal_connect_swapped(G_OBJECT(nodes), "nodes::population", G_CALLBACK(setDirty), (gpointer)legend); legend->priv->siz_sig = g_signal_connect_swapped(G_OBJECT(nodes), "element-size-changed", G_CALLBACK(setDirty), (gpointer)legend); } visu_gl_ext_setDirty(VISU_GL_EXT(legend), TRUE); return TRUE; } /** * visu_gl_ext_legend_getNodes: * @legend: a #VisuGlExtLegend object. * * @legend is displaying a label showing the element of a * #VisuNodeArray using the rendering properties of a #VisuNodeArrayRenderer. * * Since: 3.8 * * Returns: (transfer none): the #VisuNodeArrayRenderer this legend is * based on. **/ VisuNodeArrayRenderer* visu_gl_ext_legend_getNodes(VisuGlExtLegend *legend) { g_return_val_if_fail(VISU_IS_GL_EXT_LEGEND(legend), (VisuNodeArrayRenderer*)0); return legend->priv->nodes; } static void onEntryUsed(VisuGlExtLegend *lg, VisuConfigFileEntry *entry _U_, VisuConfigFile *obj _U_) { visu_gl_ext_setActive(VISU_GL_EXT(lg), DEFAULT_LEGEND_USED); } static void setDirty(VisuGlExt *ext) { visu_gl_ext_setDirty(ext, TRUE); } static void visu_gl_ext_legend_rebuild(VisuGlExt *ext) { visu_gl_text_rebuildFontList(); if (VISU_GL_EXT_GET_CLASS(ext)->draw) VISU_GL_EXT_GET_CLASS(ext)->draw(ext); } static gboolean visu_gl_ext_legend_isValid(const VisuGlExtFrame *frame) { g_return_val_if_fail(VISU_IS_GL_EXT_LEGEND(frame), FALSE); return (VISU_GL_EXT_LEGEND(frame)->priv->nodes != (VisuNodeArrayRenderer*)0); } static void visu_gl_ext_legend_draw(const VisuGlExtFrame *frame) { guint dw; guint i; float scale, mSize; GString *str; VisuNodeArrayRendererIter iter; VisuGlExtLegend *legend; gboolean valid; g_return_if_fail(VISU_IS_GL_EXT_LEGEND(frame)); legend = VISU_GL_EXT_LEGEND(frame); mSize = visu_node_array_renderer_getMaxElementSize(legend->priv->nodes, &i); DBG_fprintf(stderr, "Extension Legend: max size is %g (%d).\n", mSize, i); /* We draw the legend. */ str = g_string_new(""); scale = 0.5f * frame->height / mSize; dw = MAX(frame->width / i, frame->height + 10 + 60); for (valid = visu_node_array_renderer_iter_new(legend->priv->nodes, &iter, TRUE), i = 0; valid; valid = visu_node_array_renderer_iter_next(&iter), i += 1) { /* The element. */ glEnable(GL_LIGHTING); if (visu_element_getRendered(iter.element)) visu_element_renderer_colorize(iter.renderer, VISU_ELEMENT_RENDERER_NO_EFFECT); else visu_element_renderer_colorize(iter.renderer, VISU_ELEMENT_RENDERER_FLATTEN_DARK); glPushMatrix(); glTranslated(0.5f * frame->height + i * dw, 0.5f * frame->height, 0.f); glRotated(45., 0, 0, 1); glRotated(60., 0, 1, 0); glScalef(scale, scale, scale); visu_element_renderer_call(iter.renderer); glPopMatrix(); glDisable(GL_LIGHTING); /* The label. */ glColor3fv(VISU_GL_EXT_FRAME(legend)->fontRGB); g_string_printf(str, "%s (%d)", visu_element_getName(iter.element), iter.nStoredNodes); glRasterPos2f(5.f + i * dw + frame->height, 5.f + 0.5f * (frame->height - 20)); visu_gl_text_drawChars(str->str, VISU_GL_TEXT_SMALL); } g_string_free(str, TRUE); } static void exportResources(GString *data, VisuData *dataObj _U_) { if (!defaultLegend) return; visu_config_file_exportComment(data, DESC_RESOURCE_LEGEND_USED); visu_config_file_exportEntry(data, FLAG_RESOURCE_LEGEND_USED, NULL, "%d", visu_gl_ext_getActive(VISU_GL_EXT(defaultLegend))); visu_config_file_exportComment(data, ""); } v_sim-3.8.0/src/extensions/legend.h000066400000000000000000000101341370110300500172210ustar00rootroot00000000000000/* EXTRAITS DE LA LICENCE Copyright CEA, contributeurs : Damien CALISTE, laboratoire L_Sim, (2001-2009) Adresse mèl : CALISTE, damien P caliste AT cea P fr. Ce logiciel est un programme informatique servant à visualiser des structures atomiques dans un rendu pseudo-3D. Ce logiciel est régi par la licence CeCILL soumise au droit français et respectant les principes de diffusion des logiciels libres. Vous pouvez utiliser, modifier et/ou redistribuer ce programme sous les conditions de la licence CeCILL telle que diffusée par le CEA, le CNRS et l'INRIA sur le site "http://www.cecill.info". Le fait que vous puissiez accéder à cet en-tête signifie que vous avez pris connaissance de la licence CeCILL, et que vous en avez accepté les termes (cf. le fichier Documentation/licence.fr.txt fourni avec ce logiciel). */ /* LICENCE SUM UP Copyright CEA, contributors : Damien CALISTE, laboratoire L_Sim, (2001-2009) E-mail address: CALISTE, damien P caliste AT cea P fr. This software is a computer program whose purpose is to visualize atomic configurations in 3D. This software is governed by the CeCILL license under French law and abiding by the rules of distribution of free software. You can use, modify and/ or redistribute the software under the terms of the CeCILL license as circulated by CEA, CNRS and INRIA at the following URL "http://www.cecill.info". The fact that you are presently reading this means that you have had knowledge of the CeCILL license and that you accept its terms. You can find a copy of this licence shipped with this software at COPYING. */ #ifndef LEGEND_H #define LEGEND_H #include "frame.h" #include /** * VISU_TYPE_GL_EXT_LEGEND: * * return the type of #VisuGlExtLegend. * * Since: 3.7 */ #define VISU_TYPE_GL_EXT_LEGEND (visu_gl_ext_legend_get_type ()) /** * VISU_GL_EXT_LEGEND: * @obj: a #GObject to cast. * * Cast the given @obj into #VisuGlExtLegend type. * * Since: 3.7 */ #define VISU_GL_EXT_LEGEND(obj) (G_TYPE_CHECK_INSTANCE_CAST(obj, VISU_TYPE_GL_EXT_LEGEND, VisuGlExtLegend)) /** * VISU_GL_EXT_LEGEND_CLASS: * @klass: a #GObjectClass to cast. * * Cast the given @klass into #VisuGlExtLegendClass. * * Since: 3.7 */ #define VISU_GL_EXT_LEGEND_CLASS(klass) (G_TYPE_CHECK_CLASS_CAST(klass, VISU_TYPE_GL_EXT_LEGEND, VisuGlExtLegendClass)) /** * VISU_IS_GL_EXT_LEGEND: * @obj: a #GObject to test. * * Test if the given @ogj is of the type of #VisuGlExtLegend object. * * Since: 3.7 */ #define VISU_IS_GL_EXT_LEGEND(obj) (G_TYPE_CHECK_INSTANCE_TYPE(obj, VISU_TYPE_GL_EXT_LEGEND)) /** * VISU_IS_GL_EXT_LEGEND_CLASS: * @klass: a #GObjectClass to test. * * Test if the given @klass is of the type of #VisuGlExtLegendClass class. * * Since: 3.7 */ #define VISU_IS_GL_EXT_LEGEND_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE(klass, VISU_TYPE_GL_EXT_LEGEND)) /** * VISU_GL_EXT_LEGEND_GET_CLASS: * @obj: a #GObject to get the class of. * * It returns the class of the given @obj. * * Since: 3.7 */ #define VISU_GL_EXT_LEGEND_GET_CLASS(obj) (G_TYPE_INSTANCE_GET_CLASS(obj, VISU_TYPE_GL_EXT_LEGEND, VisuGlExtLegendClass)) typedef struct _VisuGlExtLegend VisuGlExtLegend; typedef struct _VisuGlExtLegendPrivate VisuGlExtLegendPrivate; typedef struct _VisuGlExtLegendClass VisuGlExtLegendClass; struct _VisuGlExtLegend { VisuGlExtFrame parent; VisuGlExtLegendPrivate *priv; }; struct _VisuGlExtLegendClass { VisuGlExtFrameClass parent; }; /** * visu_gl_ext_legend_get_type: * * This method returns the type of #VisuGlExtLegend, use * VISU_TYPE_GL_EXT_LEGEND instead. * * Since: 3.7 * * Returns: the type of #VisuGlExtLegend. */ GType visu_gl_ext_legend_get_type(void); /** * VISU_GL_EXT_LEGEND_ID: * * The id used to identify this extension, see * visu_gl_ext_rebuild() for instance. */ #define VISU_GL_EXT_LEGEND_ID "Legend" VisuGlExtLegend* visu_gl_ext_legend_new(const gchar *name); gboolean visu_gl_ext_legend_setNodes(VisuGlExtLegend *legend, VisuNodeArrayRenderer *nodes); VisuNodeArrayRenderer* visu_gl_ext_legend_getNodes(VisuGlExtLegend *legend); #endif v_sim-3.8.0/src/extensions/maps.c000066400000000000000000000532671370110300500167340ustar00rootroot00000000000000/* EXTRAITS DE LA LICENCE Copyright CEA, contributeurs : Luc BILLARD et Damien CALISTE, laboratoire L_Sim, (2001-2013) Adresse mèl : BILLARD, non joignable par mèl ; CALISTE, damien P caliste AT cea P fr. Ce logiciel est un programme informatique servant à visualiser des structures atomiques dans un rendu pseudo-3D. Ce logiciel est régi par la licence CeCILL soumise au droit français et respectant les principes de diffusion des logiciels libres. Vous pouvez utiliser, modifier et/ou redistribuer ce programme sous les conditions de la licence CeCILL telle que diffusée par le CEA, le CNRS et l'INRIA sur le site "http://www.cecill.info". Le fait que vous puissiez accéder à cet en-tête signifie que vous avez pris connaissance de la licence CeCILL, et que vous en avez accepté les termes (cf. le fichier Documentation/licence.fr.txt fourni avec ce logiciel). */ /* LICENCE SUM UP Copyright CEA, contributors : Luc BILLARD et Damien CALISTE, laboratoire L_Sim, (2001-2013) E-mail address: BILLARD, not reachable any more ; CALISTE, damien P caliste AT cea P fr. This software is a computer program whose purpose is to visualize atomic configurations in 3D. This software is governed by the CeCILL license under French law and abiding by the rules of distribution of free software. You can use, modify and/ or redistribute the software under the terms of the CeCILL license as circulated by CEA, CNRS and INRIA at the following URL "http://www.cecill.info". The fact that you are presently reading this means that you have had knowledge of the CeCILL license and that you accept its terms. You can find a copy of this licence shipped with this software at Documentation/licence.en.txt. */ #include "maps.h" #include #include #include /** * SECTION:maps * @short_description: Defines methods to draw maps. * * Maps are coloured representation of a #VisuScalarField on a #VisuPlane. */ /** * VisuGlExtMapsClass: * @parent: the parent class; * @added: a method that is called when a #VisuMap is added to a * #VisuGlExtMaps object. * @removed: a method that is called when a #VisuMap is removed from a * #VisuGlExtMaps object. * * A short way to identify #_VisuGlExtMapsClass structure. * * Since: 3.7 */ /** * VisuGlExtMaps: * * An opaque structure. * * Since: 3.7 */ /** * VisuGlExtMapsPrivate: * * Private fields for #VisuGlExtMaps objects. * * Since: 3.7 */ struct _VisuGlExtMapsPrivate { gboolean dispose_has_run; GList *maps; /* Objects for rendering. */ VisuGlView *view; gulong gross_signal, detail_signal; }; typedef struct _MapHandleStruct { VisuGlExtMaps *maps; VisuMap *map; gulong chg_signal; gboolean isBuilt; float prec; ToolShade *shade; ToolColor *color; gboolean alpha; /* The OpenGL list for this map. */ int glListId; } _MapHandle; enum { ADDED_SIGNAL, REMOVED_SIGNAL, N_SIGNALS }; static guint _signals[N_SIGNALS] = { 0 }; static void visu_gl_ext_maps_finalize(GObject* obj); static void visu_gl_ext_maps_dispose(GObject* obj); static void visu_gl_ext_maps_rebuild(VisuGlExt *ext); static void visu_gl_ext_maps_draw(VisuGlExt *maps); static gboolean visu_gl_ext_maps_setGlView(VisuGlExt *maps, VisuGlView *view); static gboolean _add(VisuGlExtMaps *maps, VisuMap *map, float prec, ToolShade *shade, const ToolColor *color, gboolean alpha); /* Local callbacks */ static void onViewChange(VisuGlView *view, gpointer data); static void onMapChange(VisuMap *map, gpointer data); /* Local routines. */ static void _freeMapHandle(gpointer obj) { _MapHandle *mhd; mhd = (_MapHandle*)obj; if (VISU_GL_EXT_MAPS_GET_CLASS(mhd->maps)->removed) VISU_GL_EXT_MAPS_GET_CLASS(mhd->maps)->removed(mhd->maps, mhd->map); DBG_fprintf(stderr, "Extension Maps: emiting %p map removed.\n", (gpointer)mhd->map); g_signal_emit(G_OBJECT(mhd->maps), _signals[REMOVED_SIGNAL], 0, mhd->map); DBG_fprintf(stderr, "Extension Maps: emission done.\n"); g_signal_handler_disconnect(G_OBJECT(mhd->map), mhd->chg_signal); g_object_unref(G_OBJECT(mhd->map)); tool_shade_free(mhd->shade); g_free(mhd->color); glDeleteLists(mhd->glListId, 1); #if GLIB_MINOR_VERSION > 9 g_slice_free1(sizeof(_MapHandle), obj); #else g_free(obj); #endif } static gpointer _newMapHandle(VisuGlExtMaps *maps, VisuMap *map, float prec, ToolShade *shade, const ToolColor *color, gboolean alpha) { _MapHandle *mhd; g_object_ref(G_OBJECT(map)); #if GLIB_MINOR_VERSION > 9 mhd = g_slice_alloc(sizeof(_MapHandle)); #else mhd = g_malloc(sizeof(_MapHandle)); #endif DBG_fprintf(stderr, "Extension Maps: add listeners on map %p.\n", (gpointer)map); mhd->maps = maps; mhd->map = map; mhd->chg_signal = g_signal_connect(G_OBJECT(map), "changed", G_CALLBACK(onMapChange), maps); mhd->isBuilt = FALSE; mhd->prec = prec; mhd->shade = tool_shade_copy(shade); mhd->color = (color) ? g_boxed_copy(TOOL_TYPE_COLOR, color) : (ToolColor*)0; mhd->alpha = alpha; mhd->glListId = visu_gl_objectlist_new(1); if (maps->priv->view) visu_map_setLevel(mhd->map, visu_gl_view_getPrecision(maps->priv->view), maps->priv->view->camera.gross, visu_gl_camera_getRefLength(&maps->priv->view->camera, (ToolUnits*)0)); if (VISU_GL_EXT_MAPS_GET_CLASS(maps)->added) VISU_GL_EXT_MAPS_GET_CLASS(maps)->added(maps, map); return (gpointer)mhd; } static gint _cmpMapHandle(gconstpointer a, gconstpointer b) { _MapHandle *mhd_a = (_MapHandle*)a; if (mhd_a->map == b) return 0; return 1; } #define _getMap(H) ((_MapHandle*)H)->map G_DEFINE_TYPE_WITH_CODE(VisuGlExtMaps, visu_gl_ext_maps, VISU_TYPE_GL_EXT, G_ADD_PRIVATE(VisuGlExtMaps)) static void visu_gl_ext_maps_class_init(VisuGlExtMapsClass *klass) { DBG_fprintf(stderr, "Extension Maps: creating the class of the object.\n"); /* DBG_fprintf(stderr, " - adding new signals ;\n"); */ /* Connect the overloading methods. */ G_OBJECT_CLASS(klass)->dispose = visu_gl_ext_maps_dispose; G_OBJECT_CLASS(klass)->finalize = visu_gl_ext_maps_finalize; VISU_GL_EXT_CLASS(klass)->rebuild = visu_gl_ext_maps_rebuild; VISU_GL_EXT_CLASS(klass)->draw = visu_gl_ext_maps_draw; VISU_GL_EXT_CLASS(klass)->setGlView = visu_gl_ext_maps_setGlView; VISU_GL_EXT_MAPS_CLASS(klass)->add = _add; /** * VisuGlExtMaps::added: * @maps: the object emitting the signal. * @map: the added #VisuMap. * * This signal is emitted when @map is added to @maps. * * Since: 3.8 */ _signals[ADDED_SIGNAL] = g_signal_new("added", G_TYPE_FROM_CLASS(klass), G_SIGNAL_RUN_LAST | G_SIGNAL_NO_RECURSE | G_SIGNAL_NO_HOOKS, G_STRUCT_OFFSET(VisuGlExtMapsClass, added), NULL, NULL, g_cclosure_marshal_VOID__OBJECT, G_TYPE_NONE, 1, VISU_TYPE_MAP); /** * VisuGlExtMaps::removed: * @maps: the object emitting the signal. * @map: the removed #VisuMap. * * This signal is emitted when @map is removed to @maps. * * Since: 3.8 */ _signals[REMOVED_SIGNAL] = g_signal_new("removed", G_TYPE_FROM_CLASS(klass), G_SIGNAL_RUN_LAST | G_SIGNAL_NO_RECURSE | G_SIGNAL_NO_HOOKS, G_STRUCT_OFFSET(VisuGlExtMapsClass, removed), NULL, NULL, g_cclosure_marshal_VOID__OBJECT, G_TYPE_NONE, 1, VISU_TYPE_MAP); } static void visu_gl_ext_maps_init(VisuGlExtMaps *obj) { DBG_fprintf(stderr, "Extension Maps: initializing a new object (%p).\n", (gpointer)obj); obj->priv = visu_gl_ext_maps_get_instance_private(obj); obj->priv->dispose_has_run = FALSE; /* Private data. */ obj->priv->maps = (GList*)0; obj->priv->view = (VisuGlView*)0; obj->priv->gross_signal = 0; obj->priv->detail_signal = 0; } static void visu_gl_ext_maps_dispose(GObject* obj) { VisuGlExtMaps *maps; GList *lst; DBG_fprintf(stderr, "Extension Maps: dispose object %p.\n", (gpointer)obj); maps = VISU_GL_EXT_MAPS(obj); if (maps->priv->dispose_has_run) return; maps->priv->dispose_has_run = TRUE; /* Disconnect signals. */ visu_gl_ext_maps_setGlView(VISU_GL_EXT(obj), (VisuGlView*)0); DBG_fprintf(stderr, "Extension MapSet: clearing a list of %d maps.\n", g_list_length(maps->priv->maps)); for (lst = maps->priv->maps; lst; lst = g_list_next(lst)) _freeMapHandle(lst->data); /* Chain up to the parent class */ G_OBJECT_CLASS(visu_gl_ext_maps_parent_class)->dispose(obj); } static void visu_gl_ext_maps_finalize(GObject* obj) { VisuGlExtMaps *maps = VISU_GL_EXT_MAPS(obj); g_return_if_fail(obj); DBG_fprintf(stderr, "Extension Maps: finalize object %p.\n", (gpointer)obj); /* Free privs elements. */ if (maps->priv) g_list_free(maps->priv->maps); /* Chain up to the parent class */ DBG_fprintf(stderr, "Extension Maps: chain to parent.\n"); G_OBJECT_CLASS(visu_gl_ext_maps_parent_class)->finalize(obj); DBG_fprintf(stderr, "Extension Maps: freeing ... OK.\n"); } /** * visu_gl_ext_maps_new: * @name: (allow-none): the name to give to the extension (default is #VISU_GL_EXT_MAPS_ID). * * Creates a new #VisuGlExt to draw maps. * * Since: 3.7 * * Returns: a pointer to the #VisuGlExt it created or * NULL otherwise. */ VisuGlExtMaps* visu_gl_ext_maps_new(const gchar *name) { char *name_ = VISU_GL_EXT_MAPS_ID; char *description = _("Drawing extension for maps."); VisuGlExt *extensionMaps; DBG_fprintf(stderr,"Extension Maps: new object.\n"); extensionMaps = VISU_GL_EXT(g_object_new(VISU_TYPE_GL_EXT_MAPS, "name", (name)?name:name_, "label", _(name), "description", description, "nGlObj", 1, "priority", VISU_GL_EXT_PRIORITY_NORMAL - 1, "saveState", TRUE, NULL)); return VISU_GL_EXT_MAPS(extensionMaps); } static void _setZoomLevel(VisuGlExtMaps *maps) { GList *lst; _MapHandle *mhd; /* Adjust zoom level for all maps. */ for (lst = maps->priv->maps; lst; lst = g_list_next(lst)) { mhd = (_MapHandle*)lst->data; visu_map_setLevel(mhd->map, visu_gl_view_getPrecision(maps->priv->view), maps->priv->view->camera.gross, visu_gl_camera_getRefLength(&maps->priv->view->camera, (ToolUnits*)0)); mhd->isBuilt = FALSE; } visu_gl_ext_setDirty(VISU_GL_EXT(maps), TRUE); } static gboolean visu_gl_ext_maps_setGlView(VisuGlExt *maps, VisuGlView *view) { VisuGlExtMapsPrivate *priv = VISU_GL_EXT_MAPS(maps)->priv; /* No change to be done. */ if (view == priv->view) return FALSE; if (priv->view) { g_signal_handler_disconnect(G_OBJECT(priv->view), priv->detail_signal); g_object_unref(priv->view); } priv->view = view; if (view) { g_object_ref(view); priv->detail_signal = g_signal_connect(G_OBJECT(view), "DetailLevelChanged", G_CALLBACK(onViewChange), (gpointer)maps); _setZoomLevel(VISU_GL_EXT_MAPS(maps)); } else { /* priv->gross_signal = 0; */ priv->detail_signal = 0; } return TRUE; } /** * visu_gl_ext_maps_add: * @maps: a #VisuGlExtMaps object. * @map: (transfer full): a #VisuMaps object. * @prec: rendering adaptivity level (default is 100). * @shade: (transfer full): a #ToolShade object. * @color: (transfer full) (allow-none): a #ToolColor object. * @alpha: a boolean. * * Add a new map to the list of drawn maps. If @color is %NULL, then * iso-lines will be drawn in inverse color. If @alpha is TRUE, the * map will be rendered with alpha blending when values go to zero. * * Since: 3.7 * * Returns: FALSE if @surf was already reguistered. **/ gboolean visu_gl_ext_maps_add(VisuGlExtMaps *maps, VisuMap *map, float prec, ToolShade *shade, const ToolColor *color, gboolean alpha) { VisuGlExtMapsClass *klass = VISU_GL_EXT_MAPS_GET_CLASS(maps); g_return_val_if_fail(klass && klass->add, FALSE); return klass->add(maps, map, prec, shade, color, alpha); } static gboolean _add(VisuGlExtMaps *maps, VisuMap *map, float prec, ToolShade *shade, const ToolColor *color, gboolean alpha) { GList *lst; g_return_val_if_fail(VISU_IS_GL_EXT_MAPS(maps), FALSE); lst = g_list_find_custom(maps->priv->maps, map, _cmpMapHandle); if (lst) return FALSE; maps->priv->maps = g_list_prepend(maps->priv->maps, _newMapHandle(maps, map, prec, shade, color, alpha)); DBG_fprintf(stderr, "Extension MapSet: adding map %p (%d).\n", (gpointer)map, g_list_length(maps->priv->maps)); g_signal_emit(G_OBJECT(maps), _signals[ADDED_SIGNAL], 0, map); visu_gl_ext_setDirty(VISU_GL_EXT(maps), TRUE); return TRUE; } /** * visu_gl_ext_maps_remove: * @maps: a #VisuGlExtMaps object. * @map: a #VisuMaps object. * * Removes @map from the list of drawn maps. * * Since: 3.7 * * Returns: TRUE if @map was part of drawn maps. **/ gboolean visu_gl_ext_maps_remove(VisuGlExtMaps *maps, VisuMap *map) { GList *lst; g_return_val_if_fail(VISU_IS_GL_EXT_MAPS(maps), FALSE); lst = g_list_find_custom(maps->priv->maps, map, _cmpMapHandle); if (!lst) return FALSE; maps->priv->maps = g_list_remove_link(maps->priv->maps, lst); _freeMapHandle(lst->data); g_list_free(lst); DBG_fprintf(stderr, "Extension MapSet: removing map %p (%d).\n", (gpointer)map, g_list_length(maps->priv->maps)); visu_gl_ext_setDirty(VISU_GL_EXT(maps), TRUE); return TRUE; } /** * visu_gl_ext_maps_removeAll: * @maps: a #VisuGlExtMaps object. * * Removes all the #VisuMap stored in @maps. * * Since: 3.8 **/ void visu_gl_ext_maps_removeAll(VisuGlExtMaps *maps) { g_return_if_fail(VISU_IS_GL_EXT_MAPS(maps)); g_list_free_full(maps->priv->maps, _freeMapHandle); maps->priv->maps = (GList*)0; DBG_fprintf(stderr, "Extension MapSet: removing all.\n"); visu_gl_ext_setDirty(VISU_GL_EXT(maps), TRUE); } static gboolean _getMapIter(VisuGlExtMaps *maps, VisuMap *map, GList *iter) { GList *lst; if (map) { lst = g_list_find_custom(maps->priv->maps, map, _cmpMapHandle); if (!lst) return FALSE; iter->data = lst->data; iter->next = (GList*)0; } else { if (!maps->priv->maps) return FALSE; *iter = *maps->priv->maps; } return TRUE; } /** * visu_gl_ext_maps_setPrecision: * @maps: a #VisuGlExtMaps object. * @map: a #VisuMap object. * @prec: a floating point value (default is 100). * * Changes the adaptative mesh of @map. At a value of 200, there is no * adaptivity and all triangles are rendered. At a level of 100, a * variation of less than 3% on neighbouring triangles make them merged. * * Since: 3.7 * * Returns: TRUE if @prec of @map is changed. **/ gboolean visu_gl_ext_maps_setPrecision(VisuGlExtMaps *maps, VisuMap *map, float prec) { GList *lst, iter; _MapHandle *mhd; gboolean diff; g_return_val_if_fail(VISU_IS_GL_EXT_MAPS(maps), FALSE); if (!_getMapIter(maps, map, &iter)) return FALSE; diff = FALSE; for (lst = &iter; lst; lst = g_list_next(lst)) { mhd = (_MapHandle*)lst->data; if (mhd->prec != prec) { mhd->prec = prec; mhd->isBuilt = FALSE; diff = TRUE; } } if (diff) visu_gl_ext_setDirty(VISU_GL_EXT(maps), TRUE); return diff; } /** * visu_gl_ext_maps_setShade: * @maps: a #VisuGlExtMaps object. * @map: a #VisuMap object. * @shade: (allow-none) (transfer full): a #ToolShade object. * * Changes the #ToolShade used to render data variation on the @map. * * Since: 3.7 * * Returns: TRUE if @shade of @map is changed. **/ gboolean visu_gl_ext_maps_setShade(VisuGlExtMaps *maps, VisuMap *map, ToolShade *shade) { GList *lst, iter; _MapHandle *mhd; gboolean diff; g_return_val_if_fail(VISU_IS_GL_EXT_MAPS(maps), FALSE); DBG_fprintf(stderr, "Extension Maps: change shade (for maps %p).\n", (gpointer)map); if (!_getMapIter(maps, map, &iter)) return FALSE; diff = FALSE; for (lst = &iter; lst; lst = g_list_next(lst)) { mhd = (_MapHandle*)lst->data; DBG_fprintf(stderr, " | map %p, update %d.\n", (gpointer)mhd->map, !tool_shade_compare(mhd->shade, shade)); if (!tool_shade_compare(mhd->shade, shade)) { tool_shade_free(mhd->shade); mhd->shade = tool_shade_copy(shade); mhd->isBuilt = FALSE; diff = TRUE; } } if (diff) visu_gl_ext_setDirty(VISU_GL_EXT(maps), TRUE); return diff; } /** * visu_gl_ext_maps_setLineColor: * @maps: a #VisuGlExtMaps object. * @map: a #VisuMap object. * @color: (allow-none) (transfer full): a #ToolColor object. * * Changes the rendered isoline color of @map to @color. If @color is * %NULL, then the isolines will be color inversed to the #ToolShade * of @map (see visu_gl_ext_maps_setShade()). * * Since: 3.7 * * Returns: TRUE if @color of @map is changed. **/ gboolean visu_gl_ext_maps_setLineColor(VisuGlExtMaps *maps, VisuMap *map, const ToolColor *color) { GList *lst, iter; _MapHandle *mhd; gboolean diff; g_return_val_if_fail(VISU_IS_GL_EXT_MAPS(maps), FALSE); if (!_getMapIter(maps, map, &iter)) return FALSE; diff = FALSE; for (lst = &iter; lst; lst = g_list_next(lst)) { mhd = (_MapHandle*)lst->data; if (!tool_color_equal(mhd->color, color)) { g_free(mhd->color); mhd->color = (color) ? g_boxed_copy(TOOL_TYPE_COLOR, color) : (ToolColor*)0; mhd->isBuilt = FALSE; diff = TRUE; } } if (diff) visu_gl_ext_setDirty(VISU_GL_EXT(maps), TRUE); return diff; } /** * visu_gl_ext_maps_setTransparent: * @maps: a #VisuGlExtMaps object. * @map: a #VisuMap object. * @alpha: a boolean. * * Sets if @map is rendered with transparency or not. If @alpha is * %TRUE, the lower the rendered value is, the more transparent the * colour will be. * * Since: 3.7 * * Returns: TRUE if transparency of @map is changed. **/ gboolean visu_gl_ext_maps_setTransparent(VisuGlExtMaps *maps, VisuMap *map, gboolean alpha) { GList *lst, iter; _MapHandle *mhd; gboolean diff; g_return_val_if_fail(VISU_IS_GL_EXT_MAPS(maps), FALSE); if (!_getMapIter(maps, map, &iter)) return FALSE; diff = FALSE; for (lst = &iter; lst; lst = g_list_next(lst)) { mhd = (_MapHandle*)lst->data; if (mhd->alpha != alpha) { mhd->alpha = alpha; mhd->isBuilt = FALSE; diff = TRUE; } } if (diff) visu_gl_ext_setDirty(VISU_GL_EXT(maps), TRUE); return diff; } static void visu_gl_ext_maps_draw(VisuGlExt *maps) { _MapHandle *mhd; GList *lst; #if DEBUG == 1 GTimer *timer; gulong fractionTimer; #endif VisuGlExtMapsPrivate *priv = VISU_GL_EXT_MAPS(maps)->priv; DBG_fprintf(stderr, "Extension Maps: rebuilding map list.\n"); glDeleteLists(visu_gl_ext_getGlList(maps), 1); visu_gl_ext_setDirty(maps, FALSE); if (!priv->view || !priv->maps) return; #if DEBUG == 1 timer = g_timer_new(); g_timer_start(timer); #endif /* Rebuild maps if required. */ for (lst = priv->maps; lst; lst = g_list_next(lst)) { mhd = (_MapHandle*)lst->data; if (!mhd->isBuilt) { glNewList(mhd->glListId, GL_COMPILE); visu_map_draw(_getMap(lst->data), mhd->prec, mhd->shade, (mhd->color) ? mhd->color->rgba:(float*)0, mhd->alpha); glEndList(); mhd->isBuilt = TRUE; } } /* Call the map one by one. */ visu_gl_ext_startDrawing(maps); for (lst = priv->maps; lst; lst = g_list_next(lst)) glCallList(((_MapHandle*)lst->data)->glListId); visu_gl_ext_completeDrawing(maps); #if DEBUG == 1 g_timer_stop(timer); fprintf(stderr, "Extension Maps: draw map(s) in %g micro-s.\n", g_timer_elapsed(timer, &fractionTimer)/1e-6); g_timer_destroy(timer); #endif } /* Callbacks. */ static void visu_gl_ext_maps_rebuild(VisuGlExt *ext) { VisuGlExtMaps *maps = VISU_GL_EXT_MAPS(ext); GList *lst; for (lst = maps->priv->maps; lst; lst = g_list_next(lst)) ((_MapHandle*)lst->data)->isBuilt = FALSE; visu_gl_ext_maps_draw(ext); } static void onViewChange(VisuGlView *view _U_, gpointer data) { _setZoomLevel(VISU_GL_EXT_MAPS(data)); } static void onMapChange(VisuMap *map, gpointer data) { GList *lst; for (lst = VISU_GL_EXT_MAPS(data)->priv->maps; lst; lst = g_list_next(lst)) if (((_MapHandle*)lst->data)->map == map) { DBG_fprintf(stderr, "Extension Maps: map %p is dirty.\n", (gpointer)map); ((_MapHandle*)lst->data)->isBuilt = FALSE; break; } DBG_fprintf(stderr, "Extension Maps: map changed, becoming dirty.\n"); visu_gl_ext_setDirty(VISU_GL_EXT(data), TRUE); } /** * visu_gl_ext_maps_iter_new: * @maps: a #VisuGlExtMaps object. * @iter: (out caller-allocates): a location to #VisuGlExtMapsIter. * * Generate a new iterator to run over #VisuMap objects stored in @maps. * * Since: 3.8 **/ void visu_gl_ext_maps_iter_new(VisuGlExtMaps *maps, VisuGlExtMapsIter *iter) { g_return_if_fail(VISU_IS_GL_EXT_MAPS(maps) && iter); iter->maps = maps; iter->next = maps->priv->maps; visu_gl_ext_maps_iter_next(iter); } /** * visu_gl_ext_maps_iter_next: * @iter: a #VisuGlExtMapsIter iterator. * * Go to the next #VisuMap in @iter. * * Since: 3.8 **/ void visu_gl_ext_maps_iter_next(VisuGlExtMapsIter *iter) { g_return_if_fail(iter); iter->valid = (iter->next != (GList*)0); iter->map = (iter->valid) ? _getMap(iter->next->data) : (VisuMap*)0; iter->next = g_list_next(iter->next); } v_sim-3.8.0/src/extensions/maps.h000066400000000000000000000126011370110300500167240ustar00rootroot00000000000000/* EXTRAITS DE LA LICENCE Copyright CEA, contributeurs : Damien CALISTE, laboratoire L_Sim, (2001-2013) Adresse mèl : CALISTE, damien P caliste AT cea P fr. Ce logiciel est un programme informatique servant à visualiser des structures atomiques dans un rendu pseudo-3D. Ce logiciel est régi par la licence CeCILL soumise au droit français et respectant les principes de diffusion des logiciels libres. Vous pouvez utiliser, modifier et/ou redistribuer ce programme sous les conditions de la licence CeCILL telle que diffusée par le CEA, le CNRS et l'INRIA sur le site "http://www.cecill.info". Le fait que vous puissiez accéder à cet en-tête signifie que vous avez pris connaissance de la licence CeCILL, et que vous en avez accepté les termes (cf. le fichier Documentation/licence.fr.txt fourni avec ce logiciel). */ /* LICENCE SUM UP Copyright CEA, contributors : Damien CALISTE, laboratoire L_Sim, (2001-2013) E-mail address: CALISTE, damien P caliste AT cea P fr. This software is a computer program whose purpose is to visualize atomic configurations in 3D. This software is governed by the CeCILL license under French law and abiding by the rules of distribution of free software. You can use, modify and/ or redistribute the software under the terms of the CeCILL license as circulated by CEA, CNRS and INRIA at the following URL "http://www.cecill.info". The fact that you are presently reading this means that you have had knowledge of the CeCILL license and that you accept its terms. You can find a copy of this licence shipped with this software at COPYING. */ #ifndef MAPS_H #define MAPS_H #include #include /** * VISU_TYPE_GL_EXT_MAPS: * * return the type of #VisuGlExtMaps. * * Since: 3.7 */ #define VISU_TYPE_GL_EXT_MAPS (visu_gl_ext_maps_get_type ()) /** * VISU_GL_EXT_MAPS: * @obj: a #GObject to cast. * * Cast the given @obj into #VisuGlExtMaps type. * * Since: 3.7 */ #define VISU_GL_EXT_MAPS(obj) (G_TYPE_CHECK_INSTANCE_CAST(obj, VISU_TYPE_GL_EXT_MAPS, VisuGlExtMaps)) /** * VISU_GL_EXT_MAPS_CLASS: * @klass: a #GObjectClass to cast. * * Cast the given @klass into #VisuGlExtMapsClass. * * Since: 3.7 */ #define VISU_GL_EXT_MAPS_CLASS(klass) (G_TYPE_CHECK_CLASS_CAST(klass, VISU_TYPE_GL_EXT_MAPS, VisuGlExtMapsClass)) /** * VISU_IS_GL_EXT_MAPS: * @obj: a #GObject to test. * * Test if the given @ogj is of the type of #VisuGlExtMaps object. * * Since: 3.7 */ #define VISU_IS_GL_EXT_MAPS(obj) (G_TYPE_CHECK_INSTANCE_TYPE(obj, VISU_TYPE_GL_EXT_MAPS)) /** * VISU_IS_GL_EXT_MAPS_CLASS: * @klass: a #GObjectClass to test. * * Test if the given @klass is of the type of #VisuGlExtMapsClass class. * * Since: 3.7 */ #define VISU_IS_GL_EXT_MAPS_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE(klass, VISU_TYPE_GL_EXT_MAPS)) /** * VISU_GL_EXT_MAPS_GET_CLASS: * @obj: a #GObject to get the class of. * * It returns the class of the given @obj. * * Since: 3.7 */ #define VISU_GL_EXT_MAPS_GET_CLASS(obj) (G_TYPE_INSTANCE_GET_CLASS(obj, VISU_TYPE_GL_EXT_MAPS, VisuGlExtMapsClass)) typedef struct _VisuGlExtMaps VisuGlExtMaps; typedef struct _VisuGlExtMapsPrivate VisuGlExtMapsPrivate; typedef struct _VisuGlExtMapsClass VisuGlExtMapsClass; struct _VisuGlExtMaps { VisuGlExt parent; VisuGlExtMapsPrivate *priv; }; struct _VisuGlExtMapsClass { VisuGlExtClass parent; gboolean (*add)(VisuGlExtMaps *maps, VisuMap *map, float prec, ToolShade *shade, const ToolColor *color, gboolean alpha); void (*added)(VisuGlExtMaps *maps, VisuMap *map); void (*removed)(VisuGlExtMaps *maps, VisuMap *map); }; /** * visu_gl_ext_maps_get_type: * * This method returns the type of #VisuGlExtMaps, use * VISU_TYPE_GL_EXT_MAPS instead. * * Since: 3.7 * * Returns: the type of #VisuGlExtMaps. */ GType visu_gl_ext_maps_get_type(void); /** * VISU_GL_EXT_MAPS_ID: * * The id used to identify this extension, see * visu_gl_ext_rebuild() for instance. */ #define VISU_GL_EXT_MAPS_ID "Maps" VisuGlExtMaps* visu_gl_ext_maps_new(const gchar *name); gboolean visu_gl_ext_maps_add(VisuGlExtMaps *maps, VisuMap *map, float prec, ToolShade *shade, const ToolColor *color, gboolean alpha); gboolean visu_gl_ext_maps_remove(VisuGlExtMaps *maps, VisuMap *map); void visu_gl_ext_maps_removeAll(VisuGlExtMaps *maps); gboolean visu_gl_ext_maps_setPrecision(VisuGlExtMaps *maps, VisuMap *map, float prec); gboolean visu_gl_ext_maps_setShade(VisuGlExtMaps *maps, VisuMap *map, ToolShade *shade); gboolean visu_gl_ext_maps_setLineColor(VisuGlExtMaps *maps, VisuMap *map, const ToolColor *color); gboolean visu_gl_ext_maps_setTransparent(VisuGlExtMaps *maps, VisuMap *map, gboolean alpha); /** * VisuGlExtMapsIter: * @maps: the #VisuGlExtMaps object the iterator iters on. * @valid: if the iterator is in a valid state. * @map: the current #VisuMap object the iterator is on. * * Structure to iterate over #VisuMap objects stored in a * #VisuGlExtMaps object. * * Since: 3.8 */ typedef struct _VisuGlExtMapsIter VisuGlExtMapsIter; struct _VisuGlExtMapsIter { VisuGlExtMaps *maps; gboolean valid; VisuMap *map; /*< private >*/ GList *next; }; void visu_gl_ext_maps_iter_new(VisuGlExtMaps *maps, VisuGlExtMapsIter *iter); void visu_gl_ext_maps_iter_next(VisuGlExtMapsIter *iter); #endif v_sim-3.8.0/src/extensions/mapset.c000066400000000000000000001135701370110300500172570ustar00rootroot00000000000000/* EXTRAITS DE LA LICENCE Copyright CEA, contributeurs : Damien CALISTE, laboratoire L_Sim, (20016) Adresse mèl : CALISTE, damien P caliste AT cea P fr. Ce logiciel est un programme informatique servant à visualiser des structures atomiques dans un rendu pseudo-3D. Ce logiciel est régi par la licence CeCILL soumise au droit français et respectant les principes de diffusion des logiciels libres. Vous pouvez utiliser, modifier et/ou redistribuer ce programme sous les conditions de la licence CeCILL telle que diffusée par le CEA, le CNRS et l'INRIA sur le site "http://www.cecill.info". Le fait que vous puissiez accéder à cet en-tête signifie que vous avez pris connaissance de la licence CeCILL, et que vous en avez accepté les termes (cf. le fichier Documentation/licence.fr.txt fourni avec ce logiciel). */ /* LICENCE SUM UP Copyright CEA, contributors : Damien CALISTE, laboratoire L_Sim, (20016) E-mail address: CALISTE, damien P caliste AT cea P fr. This software is a computer program whose purpose is to visualize atomic configurations in 3D. This software is governed by the CeCILL license under French law and abiding by the rules of distribution of free software. You can use, modify and/ or redistribute the software under the terms of the CeCILL license as circulated by CEA, CNRS and INRIA at the following URL "http://www.cecill.info". The fact that you are presently reading this means that you have had knowledge of the CeCILL license and that you accept its terms. You can find a copy of this licence shipped with this software at Documentation/licence.en.txt. */ #include "mapset.h" /** * SECTION:mapset * @short_description: Defines methods to draw maps that share a same #VisuScalarField. * * Maps are coloured representation of a #VisuScalarField on a #VisuPlane. */ /** * VisuGlExtMapSetClass: * @parent: the parent class; * * A short way to identify #_VisuGlExtMapSetClass structure. * * Since: 3.8 */ /** * VisuGlExtMapSet: * * An opaque structure. * * Since: 3.8 */ /** * VisuGlExtMapSetPrivate: * * Private fields for #VisuGlExtMapSet objects. * * Since: 3.8 */ struct _VisuGlExtMapSetPrivate { gboolean dispose_has_run; VisuScalarField *field; gulong sig_chg; GHashTable *maps; /* General values. */ float prec; gboolean alpha; guint nLines; gboolean useManualRange; float manualMinMax[2]; float drawnMinMax[2]; ToolMatrixScalingFlag scale; ToolShade *shade; ToolColor *color; VisuGlExtShade *extLegend; }; struct _mapData { VisuMap *map; gulong changed_sig; VisuPlane *plane; gboolean planeStatus; }; enum { PROP_0, FIELD_PROP, COLOR_PROP, SHADE_PROP, PRECISION_PROP, ALPHA_PROP, N_LINES_PROP, SCALE_PROP, USE_MANUAL_MM_PROP, MANUAL_MM_PROP, MANUAL_MIN_PROP, MANUAL_MAX_PROP, N_PROP }; static GParamSpec *_properties[N_PROP]; static void visu_gl_ext_map_set_finalize(GObject* obj); static void visu_gl_ext_map_set_dispose(GObject* obj); static void visu_gl_ext_map_set_get_property(GObject* obj, guint property_id, GValue *value, GParamSpec *pspec); static void visu_gl_ext_map_set_set_property(GObject* obj, guint property_id, const GValue *value, GParamSpec *pspec); static gboolean visu_gl_ext_map_set_add(VisuGlExtMaps *maps, VisuMap *map, float prec, ToolShade *shade, const ToolColor *color, gboolean alpha); static void visu_gl_ext_map_set_added(VisuGlExtMaps *maps, VisuMap *map); static void visu_gl_ext_map_set_removed(VisuGlExtMaps *maps, VisuMap *map); /* Local callbacks */ static void onMapChange(VisuMap *map, gpointer data); static void onFieldChanged(VisuScalarField *field, gpointer data); /* Local routines. */ static struct _mapData* _newMapData(VisuGlExtMapSet *maps, VisuMap *map) { struct _mapData *data = g_malloc(sizeof(struct _mapData)); data->map = map; data->changed_sig = g_signal_connect(G_OBJECT(map), "changed", G_CALLBACK(onMapChange), (gpointer)maps); data->plane = (VisuPlane*)0; return data; } static void _freeMapData(struct _mapData *data) { DBG_fprintf(stderr, "Extension MapSet: freeing handle on map %p.\n", (gpointer)data->map); g_signal_handler_disconnect(G_OBJECT(data->map), data->changed_sig); if (data->plane) { visu_plane_setRendered(data->plane, data->planeStatus); g_object_unref(data->plane); } } static gboolean _setLeg(GBinding *bind _U_, const GValue *from, GValue *to, gpointer data) { g_value_set_boolean(to, g_value_get_boolean(from) && g_hash_table_size(VISU_GL_EXT_MAP_SET(data)->priv->maps) > 0); return TRUE; } G_DEFINE_TYPE_WITH_CODE(VisuGlExtMapSet, visu_gl_ext_map_set, VISU_TYPE_GL_EXT_MAPS, G_ADD_PRIVATE(VisuGlExtMapSet)) static void visu_gl_ext_map_set_class_init(VisuGlExtMapSetClass *klass) { DBG_fprintf(stderr, "Extension MapSet: creating the class of the object.\n"); /* DBG_fprintf(stderr, " - adding new signals ;\n"); */ /* Connect the overloading methods. */ G_OBJECT_CLASS(klass)->dispose = visu_gl_ext_map_set_dispose; G_OBJECT_CLASS(klass)->finalize = visu_gl_ext_map_set_finalize; G_OBJECT_CLASS(klass)->set_property = visu_gl_ext_map_set_set_property; G_OBJECT_CLASS(klass)->get_property = visu_gl_ext_map_set_get_property; VISU_GL_EXT_MAPS_CLASS(klass)->add = visu_gl_ext_map_set_add; VISU_GL_EXT_MAPS_CLASS(klass)->added = visu_gl_ext_map_set_added; VISU_GL_EXT_MAPS_CLASS(klass)->removed = visu_gl_ext_map_set_removed; /** * VisuGlExtMapSet::field: * * Store the field maps are drawn from. * * Since: 3.8 */ _properties[FIELD_PROP] = g_param_spec_object("field", "Field", "field storing 3D data", VISU_TYPE_SCALAR_FIELD, G_PARAM_READWRITE); g_object_class_install_property(G_OBJECT_CLASS(klass), FIELD_PROP, _properties[FIELD_PROP]); /** * VisuGlExtMapSet::line-color: * * Store the colour used to draw isolines. * * Since: 3.8 */ _properties[COLOR_PROP] = g_param_spec_boxed("line-color", "Line color", "colour used to draw isolines", TOOL_TYPE_COLOR, G_PARAM_READWRITE); g_object_class_install_property(G_OBJECT_CLASS(klass), COLOR_PROP, _properties[COLOR_PROP]); /** * VisuGlExtMapSet::shade: * * Store the shade used to colourise the map. * * Since: 3.8 */ _properties[SHADE_PROP] = g_param_spec_boxed("shade", "Shade", "shade used to colourise the map", TOOL_TYPE_SHADE, G_PARAM_READWRITE); g_object_class_install_property(G_OBJECT_CLASS(klass), SHADE_PROP, _properties[SHADE_PROP]); /** * VisuGlExtMapSet::precision: * * Store the adaptatbility level used to render mapSet. * * Since: 3.8 */ _properties[PRECISION_PROP] = g_param_spec_float("precision", "Precision", "map degree of adaptability", 10.f, 200.f, 100.f, G_PARAM_READWRITE); g_object_class_install_property(G_OBJECT_CLASS(klass), PRECISION_PROP, _properties[PRECISION_PROP]); /** * VisuGlExtMapSet::transparent: * * Define if field value is transfered to alpha channel also. * * Since: 3.8 */ _properties[ALPHA_PROP] = g_param_spec_boolean("transparent", "Transparent", "use alpha channel according to field values", FALSE, G_PARAM_READWRITE); g_object_class_install_property(G_OBJECT_CLASS(klass), ALPHA_PROP, _properties[ALPHA_PROP]); /** * VisuGlExtMapSet::n-lines: * * Define how many lines are drawn in full range. * * Since: 3.8 */ _properties[N_LINES_PROP] = g_param_spec_uint("n-lines", "N lines", "number of lines is the full range", 0, G_MAXUINT, 0, G_PARAM_READWRITE); g_object_class_install_property(G_OBJECT_CLASS(klass), N_LINES_PROP, _properties[N_LINES_PROP]); /** * VisuGlExtMapSet::scale: * * Define how to scale input values into [0;1]. * * Since: 3.8 */ _properties[SCALE_PROP] = g_param_spec_uint("scale", "Scale", "scaling method", 0, TOOL_MATRIX_SCALING_N_VALUES - 1, TOOL_MATRIX_SCALING_LINEAR, G_PARAM_READWRITE); g_object_class_install_property(G_OBJECT_CLASS(klass), SCALE_PROP, _properties[SCALE_PROP]); /** * VisuGlExtMapSet::use-manual-range: * * True, when mapSet are scaled according to a manual range. * * Since: 3.8 */ _properties[USE_MANUAL_MM_PROP] = g_param_spec_boolean("use-manual-range", "Use manual range", "use manual range", FALSE, G_PARAM_READWRITE); g_object_class_install_property(G_OBJECT_CLASS(klass), USE_MANUAL_MM_PROP, _properties[USE_MANUAL_MM_PROP]); /** * VisuGlExtMapSet::manual-range: * * Min / max range as used to normalise data. * * Since: 3.8 */ _properties[MANUAL_MM_PROP] = g_param_spec_boxed("manual-range", "Manual range", "manual range values", G_TYPE_ARRAY, G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS); g_object_class_install_property (G_OBJECT_CLASS(klass), MANUAL_MM_PROP, _properties[MANUAL_MM_PROP]); /** * VisuGlExtMapSet::manual-range-min: * * Min range as used to normalise data. * * Since: 3.8 */ _properties[MANUAL_MIN_PROP] = g_param_spec_float("manual-range-min", "Manual range minimum", "manual range minimum value", -G_MAXFLOAT, G_MAXFLOAT, -G_MAXFLOAT, G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS); g_object_class_install_property (G_OBJECT_CLASS(klass), MANUAL_MIN_PROP, _properties[MANUAL_MIN_PROP]); /** * VisuGlExtMapSet::manual-range-max: * * Max range as used to normalise data. * * Since: 3.8 */ _properties[MANUAL_MAX_PROP] = g_param_spec_float("manual-range-max", "Manual range maximum", "manual range maximum value", -G_MAXFLOAT, G_MAXFLOAT, -G_MAXFLOAT, G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS); g_object_class_install_property (G_OBJECT_CLASS(klass), MANUAL_MAX_PROP, _properties[MANUAL_MAX_PROP]); } static void visu_gl_ext_map_set_init(VisuGlExtMapSet *obj) { DBG_fprintf(stderr, "Extension MapSet: initializing a new object (%p).\n", (gpointer)obj); obj->priv = visu_gl_ext_map_set_get_instance_private(obj); obj->priv->dispose_has_run = FALSE; /* Private data. */ obj->priv->field = (VisuScalarField*)0; obj->priv->maps = g_hash_table_new_full(g_direct_hash, g_direct_equal, NULL, (GDestroyNotify)_freeMapData); obj->priv->color = (ToolColor*)0; obj->priv->shade = (ToolShade*)0; obj->priv->prec = 100.f; obj->priv->alpha = FALSE; obj->priv->nLines = 0; obj->priv->useManualRange = FALSE; obj->priv->drawnMinMax[0] = G_MAXFLOAT; obj->priv->drawnMinMax[1] = -G_MAXFLOAT; obj->priv->manualMinMax[0] = -G_MAXFLOAT; obj->priv->manualMinMax[1] = G_MAXFLOAT; obj->priv->scale = TOOL_MATRIX_SCALING_LINEAR; obj->priv->extLegend = visu_gl_ext_shade_new("Map legend"); g_object_bind_property_full(G_OBJECT(obj), "active", G_OBJECT(obj->priv->extLegend), "active", G_BINDING_SYNC_CREATE, _setLeg, NULL, obj, NULL); visu_gl_ext_frame_setScale(VISU_GL_EXT_FRAME(obj->priv->extLegend), visu_map_getLegendScale()); visu_gl_ext_frame_setPosition(VISU_GL_EXT_FRAME(obj->priv->extLegend), visu_map_getLegendPosition(TOOL_XYZ_X), visu_map_getLegendPosition(TOOL_XYZ_Y)); } static void visu_gl_ext_map_set_dispose(GObject* obj) { VisuGlExtMapSet *mapSet = VISU_GL_EXT_MAP_SET(obj); DBG_fprintf(stderr, "Extension MapSet: dispose object %p.\n", (gpointer)obj); if (mapSet->priv->dispose_has_run) return; mapSet->priv->dispose_has_run = TRUE; g_object_unref(mapSet->priv->extLegend); visu_gl_ext_map_set_setField(mapSet, (VisuScalarField*)0); g_hash_table_remove_all(mapSet->priv->maps); /* Chain up to the parent class */ G_OBJECT_CLASS(visu_gl_ext_map_set_parent_class)->dispose(obj); } static void visu_gl_ext_map_set_finalize(GObject* obj) { g_return_if_fail(obj); DBG_fprintf(stderr, "Extension MapSet: finalize object %p.\n", (gpointer)obj); g_hash_table_destroy(VISU_GL_EXT_MAP_SET(obj)->priv->maps); /* Chain up to the parent class */ DBG_fprintf(stderr, "Extension MapSet: chain to parent.\n"); G_OBJECT_CLASS(visu_gl_ext_map_set_parent_class)->finalize(obj); DBG_fprintf(stderr, "Extension MapSet: freeing ... OK.\n"); } static void visu_gl_ext_map_set_get_property(GObject* obj, guint property_id, GValue *value, GParamSpec *pspec) { GArray *arr; VisuGlExtMapSet *self = VISU_GL_EXT_MAP_SET(obj); DBG_fprintf(stderr, "Extension MapSet: get property '%s' -> ", g_param_spec_get_name(pspec)); switch (property_id) { case FIELD_PROP: g_value_set_object(value, self->priv->field); DBG_fprintf(stderr, "%p.\n", (gpointer)self->priv->field); break; case SHADE_PROP: g_value_set_boxed(value, self->priv->shade); DBG_fprintf(stderr, "%p.\n", (gpointer)self->priv->shade); break; case COLOR_PROP: g_value_set_boxed(value, self->priv->color); DBG_fprintf(stderr, "%p.\n", (gpointer)self->priv->color); break; case PRECISION_PROP: g_value_set_float(value, self->priv->prec); DBG_fprintf(stderr, "%g.\n", self->priv->prec); break; case ALPHA_PROP: g_value_set_boolean(value, self->priv->alpha); DBG_fprintf(stderr, "%d.\n", self->priv->alpha); break; case N_LINES_PROP: g_value_set_uint(value, self->priv->nLines); DBG_fprintf(stderr, "%u.\n", self->priv->nLines); break; case SCALE_PROP: g_value_set_uint(value, self->priv->scale); DBG_fprintf(stderr, "%u.\n", self->priv->scale); break; case USE_MANUAL_MM_PROP: g_value_set_boolean(value, self->priv->useManualRange); DBG_fprintf(stderr, "%d.\n", self->priv->useManualRange); break; case MANUAL_MM_PROP: arr = g_array_sized_new(FALSE, FALSE, sizeof(float) * 2, 2); g_array_append_vals(arr, self->priv->manualMinMax, 2); g_value_take_boxed(value, self->priv->manualMinMax); DBG_fprintf(stderr, "%p.\n", (gpointer)arr); break; case MANUAL_MIN_PROP: g_value_set_float(value, self->priv->manualMinMax[0]); DBG_fprintf(stderr, "%g.\n", self->priv->manualMinMax[0]); break; case MANUAL_MAX_PROP: g_value_set_float(value, self->priv->manualMinMax[1]); DBG_fprintf(stderr, "%g.\n", self->priv->manualMinMax[1]); break; default: /* We don't have any other property... */ G_OBJECT_WARN_INVALID_PROPERTY_ID(obj, property_id, pspec); break; } } static void visu_gl_ext_map_set_set_property(GObject* obj, guint property_id, const GValue *value, GParamSpec *pspec) { GArray *arr; float mm[2]; VisuGlExtMapSet *self = VISU_GL_EXT_MAP_SET(obj); DBG_fprintf(stderr, "Extension MapSet: set property '%s' -> ", g_param_spec_get_name(pspec)); switch (property_id) { case FIELD_PROP: DBG_fprintf(stderr, "%p.\n", g_value_get_object(value)); visu_gl_ext_map_set_setField(self, VISU_SCALAR_FIELD(g_value_get_object(value))); break; case COLOR_PROP: DBG_fprintf(stderr, "%p.\n", g_value_get_boxed(value)); visu_gl_ext_map_set_setLineColor(self, (ToolColor*)g_value_get_boxed(value)); break; case SHADE_PROP: DBG_fprintf(stderr, "%p.\n", g_value_get_boxed(value)); visu_gl_ext_map_set_setShade(self, (ToolShade*)g_value_get_boxed(value)); break; case PRECISION_PROP: DBG_fprintf(stderr, "%g.\n", g_value_get_float(value)); visu_gl_ext_map_set_setPrecision(self, g_value_get_float(value)); break; case ALPHA_PROP: DBG_fprintf(stderr, "%d.\n", g_value_get_boolean(value)); visu_gl_ext_map_set_setTransparent(self, g_value_get_boolean(value)); break; case N_LINES_PROP: DBG_fprintf(stderr, "%u.\n", g_value_get_uint(value)); visu_gl_ext_map_set_setLines(self, g_value_get_uint(value)); break; case SCALE_PROP: DBG_fprintf(stderr, "%u.\n", g_value_get_uint(value)); visu_gl_ext_map_set_setScaling(self, g_value_get_uint(value)); break; case USE_MANUAL_MM_PROP: DBG_fprintf(stderr, "%d.\n", g_value_get_boolean(value)); visu_gl_ext_map_set_setScalingRange(self, g_value_get_boolean(value) ? self->priv->manualMinMax : (const float*)0); break; case MANUAL_MM_PROP: arr = (GArray*)g_value_get_boxed(value); g_return_if_fail(arr && arr->len == 2); if (self->priv->useManualRange) visu_gl_ext_map_set_setScalingRange(self, (float*)arr->data); else { self->priv->manualMinMax[0] = g_array_index(arr, float, 0); self->priv->manualMinMax[1] = g_array_index(arr, float, 1); } break; case MANUAL_MIN_PROP: if (self->priv->useManualRange) { mm[0] = g_value_get_float(value); mm[1] = self->priv->manualMinMax[1]; visu_gl_ext_map_set_setScalingRange(self, mm); } else self->priv->manualMinMax[0] = g_value_get_float(value); break; case MANUAL_MAX_PROP: if (self->priv->useManualRange) { mm[0] = self->priv->manualMinMax[0]; mm[1] = g_value_get_float(value); visu_gl_ext_map_set_setScalingRange(self, mm); } else self->priv->manualMinMax[1] = g_value_get_float(value); break; default: /* We don't have any other property... */ G_OBJECT_WARN_INVALID_PROPERTY_ID(obj, property_id, pspec); break; } } /** * visu_gl_ext_map_set_new: * @name: (allow-none): the name to give to the extension. * * Creates a new #VisuGlExt to draw mapSet. * * Since: 3.7 * * Returns: a pointer to the #VisuGlExt it created or * NULL otherwise. */ VisuGlExtMapSet* visu_gl_ext_map_set_new(const gchar *name) { char *name_ = "MapSet"; char *description = _("Drawing extension for mapSet."); VisuGlExt *extensionMapSet; DBG_fprintf(stderr,"Extension MapSet: new object.\n"); extensionMapSet = VISU_GL_EXT(g_object_new(VISU_TYPE_GL_EXT_MAP_SET, "name", (name)?name:name_, "label", _(name), "description", description, "nGlObj", 1, "priority", VISU_GL_EXT_PRIORITY_NORMAL - 1, "saveState", TRUE, NULL)); return VISU_GL_EXT_MAP_SET(extensionMapSet); } /** * visu_gl_ext_map_set_getLegend: * @mapSet: a #VisuGlExtMapSet object. * * Retrieve the associated #VisuGlExtShade object used to draw the legend. * * Since: 3.8 * * Returns: (transfer none): the associated #VisuGlExtShade legend. **/ VisuGlExtShade* visu_gl_ext_map_set_getLegend(VisuGlExtMapSet *mapSet) { g_return_val_if_fail(VISU_IS_GL_EXT_MAP_SET(mapSet), (VisuGlExtShade*)0); return mapSet->priv->extLegend; } /** * visu_gl_ext_map_set_setField: * @mapSet: a #VisuGlExtMapSet object. * @field: (transfer none): a #VisuScalarField object. * * Associate @field to the @mapSet. * * Since: 3.8 **/ void visu_gl_ext_map_set_setField(VisuGlExtMapSet *mapSet, VisuScalarField *field) { VisuGlExtMapsIter iter; g_return_if_fail(VISU_IS_GL_EXT_MAP_SET(mapSet)); if (mapSet->priv->field) { g_signal_handler_disconnect(G_OBJECT(mapSet->priv->field), mapSet->priv->sig_chg); g_object_unref(G_OBJECT(mapSet->priv->field)); } mapSet->priv->field = field; if (field) { g_object_ref(G_OBJECT(field)); mapSet->priv->sig_chg = g_signal_connect(G_OBJECT(field), "changed", G_CALLBACK(onFieldChanged), mapSet); } g_object_notify_by_pspec(G_OBJECT(mapSet), _properties[FIELD_PROP]); /* Update stored maps. */ for (visu_gl_ext_maps_iter_new(VISU_GL_EXT_MAPS(mapSet), &iter); iter.valid; visu_gl_ext_maps_iter_next(&iter)) visu_map_setField(iter.map, field); DBG_fprintf(stderr, "Extension MapSet: setting field %p.\n", (gpointer)field); visu_gl_ext_setActive(VISU_GL_EXT(mapSet->priv->extLegend), visu_gl_ext_getActive(VISU_GL_EXT(mapSet)) && g_hash_table_size(mapSet->priv->maps) > 0 && mapSet->priv->field && !visu_scalar_field_isEmpty(mapSet->priv->field)); } static void _legend(VisuGlExtMapSet *mapSet) { float *marks, minmax[2], inputMM[2] = {G_MAXFLOAT, -G_MAXFLOAT}, factor; guint i; double dmm[2]; VisuGlExtMapsIter iter; if (!visu_gl_ext_getActive(VISU_GL_EXT(mapSet->priv->extLegend))) return; if (mapSet->priv->useManualRange) { inputMM[0] = mapSet->priv->manualMinMax[0]; inputMM[1] = mapSet->priv->manualMinMax[1]; minmax[0] = 0.; minmax[1] = 1.; } else { for (visu_gl_ext_maps_iter_new(VISU_GL_EXT_MAPS(mapSet), &iter); iter.valid; visu_gl_ext_maps_iter_next(&iter)) { visu_scalar_field_getMinMax(visu_map_getField(iter.map), dmm); tool_minmax_fromDbl(inputMM, dmm); } minmax[0] = mapSet->priv->drawnMinMax[0]; minmax[1] = mapSet->priv->drawnMinMax[1]; } visu_gl_ext_shade_setMinMax(mapSet->priv->extLegend, inputMM[0], inputMM[1]); /* Update the shade legend. */ marks = g_malloc(sizeof(float) * (2 + mapSet->priv->nLines)); factor = (minmax[1] - minmax[0]) / (float)(mapSet->priv->nLines + 1); for (i = 0; i < mapSet->priv->nLines; i++) marks[1 + i] = factor * (float)(i + 1) + minmax[0]; marks[0] = mapSet->priv->drawnMinMax[0]; marks[1 + mapSet->priv->nLines] = mapSet->priv->drawnMinMax[1]; visu_gl_ext_shade_setMarks(mapSet->priv->extLegend, marks, 2 + mapSet->priv->nLines); g_free(marks); } static void _setLines(VisuGlExtMapSet *mapSet) { float minmax[2]; VisuGlExtMapsIter iter; if (mapSet->priv->useManualRange) { minmax[0] = 0.; minmax[1] = 1.; } else { minmax[0] = mapSet->priv->drawnMinMax[0]; minmax[1] = mapSet->priv->drawnMinMax[1]; } for (visu_gl_ext_maps_iter_new(VISU_GL_EXT_MAPS(mapSet), &iter); iter.valid; visu_gl_ext_maps_iter_next(&iter)) visu_map_setLines(iter.map, mapSet->priv->nLines, minmax); _legend(mapSet); } static gboolean _drawnMinMax(VisuGlExtMapSet *mapSet) { float drawnMinMax[2], oldMinMax[2], minMax[2]; VisuGlExtMapsIter iter; oldMinMax[0] = mapSet->priv->drawnMinMax[0]; oldMinMax[1] = mapSet->priv->drawnMinMax[1]; /* We update the drawnMinMax array. */ drawnMinMax[0] = G_MAXFLOAT; drawnMinMax[1] = -G_MAXFLOAT; for (visu_gl_ext_maps_iter_new(VISU_GL_EXT_MAPS(mapSet), &iter); iter.valid; visu_gl_ext_maps_iter_next(&iter)) if (visu_map_getScaledMinMax(iter.map, minMax)) { drawnMinMax[0] = MIN(drawnMinMax[0], minMax[0]); drawnMinMax[1] = MAX(drawnMinMax[1], minMax[1]); } else return FALSE; /* No global drawn min max available yet. */ DBG_fprintf(stderr, "Extension MapSet: global scaled min/max: %g/%g (%g/%g).\n", drawnMinMax[0], drawnMinMax[1], oldMinMax[0], oldMinMax[1]); if (oldMinMax[0] == drawnMinMax[0] && oldMinMax[1] == drawnMinMax[1]) return FALSE; mapSet->priv->drawnMinMax[0] = drawnMinMax[0]; mapSet->priv->drawnMinMax[1] = drawnMinMax[1]; _setLines(mapSet); return TRUE; } /** * visu_gl_ext_map_set_addFromPlane: * @mapSet: a #VisuGlExtMapSet object. * @plane: (transfer none): a #VisuPlane object. * * Add a new map to the list of drawn mapSet. If @color is %NULL, then * iso-lines will be drawn in inverse color. * * Since: 3.8 * * Returns: (transfer none): the corresponding #VisuMap. **/ VisuMap* visu_gl_ext_map_set_addFromPlane(VisuGlExtMapSet *mapSet, VisuPlane *plane) { VisuMap *map; float full[2] = {0.f, 1.f}; g_return_val_if_fail(VISU_IS_GL_EXT_MAP_SET(mapSet) && plane, (VisuMap*)0); map = visu_map_new_fromPlane(plane); visu_map_setField(map, mapSet->priv->field); visu_map_setScaling(map, mapSet->priv->scale); visu_map_setScalingRange(map, (mapSet->priv->useManualRange) ? mapSet->priv->manualMinMax : (float*)0); visu_map_setLines(map, mapSet->priv->nLines, (mapSet->priv->useManualRange) ? full : mapSet->priv->drawnMinMax); if (!visu_gl_ext_maps_add(VISU_GL_EXT_MAPS(mapSet), map, mapSet->priv->prec, mapSet->priv->shade, mapSet->priv->color, mapSet->priv->alpha)) { g_object_unref(map); return (VisuMap*)0; } visu_gl_ext_map_set_setPlane(mapSet, map, plane); g_object_unref(map); return map; } /** * visu_gl_ext_map_set_setPlane: * @mapSet: a #VisuGlExtMapSet object. * @map: a #VisuMap object. * @plane: a #VisuPlane object. * * Change the plane where @map is projected on to @plane. * * Since: 3.8 **/ void visu_gl_ext_map_set_setPlane(VisuGlExtMapSet *mapSet, VisuMap *map, VisuPlane *plane) { struct _mapData *data; g_return_if_fail(VISU_IS_GL_EXT_MAP_SET(mapSet)); data = (struct _mapData*)g_hash_table_lookup(mapSet->priv->maps, map); g_return_if_fail(data); if (data->plane == plane) return; if (data->plane) { visu_plane_setRendered(data->plane, data->planeStatus); g_object_unref(data->plane); } g_object_ref(plane); data->plane = plane; data->planeStatus = visu_plane_getRendered(plane); visu_plane_setRendered(plane, FALSE); visu_map_setPlane(map, plane); } /** * visu_gl_ext_map_set_getPlane: * @mapSet: a #VisuGlExtMapSet object. * @map: a #VisuMap object. * * Retrieve the #VisuPlane @map was build from (if any). * * Since: 3.8 * * Returns: (transfer none): the attached #VisuPlane if any. **/ VisuPlane* visu_gl_ext_map_set_getPlane(VisuGlExtMapSet *mapSet, VisuMap *map) { struct _mapData *data; g_return_val_if_fail(VISU_IS_GL_EXT_MAP_SET(mapSet), (VisuPlane*)0); DBG_fprintf(stderr, "Extension MapSet: looking for map %p.\n", (gpointer)map); data = (struct _mapData*)g_hash_table_lookup(mapSet->priv->maps, map); g_return_val_if_fail(data, (VisuPlane*)0); return data->plane; } /** * visu_gl_ext_map_set_setPrecision: * @mapSet: a #VisuGlExtMapSet object. * @prec: a floating point value (default is 100). * * Changes the adaptative mesh of @map. At a value of 200, there is no * adaptivity and all triangles are rendered. At a level of 100, a * variation of less than 3% on neighbouring triangles make them merged. * * Since: 3.8 * * Returns: TRUE if @prec of @map is changed. **/ gboolean visu_gl_ext_map_set_setPrecision(VisuGlExtMapSet *mapSet, float prec) { g_return_val_if_fail(VISU_IS_GL_EXT_MAP_SET(mapSet), FALSE); if (mapSet->priv->prec != prec) { mapSet->priv->prec = prec; g_object_notify_by_pspec(G_OBJECT(mapSet), _properties[PRECISION_PROP]); } return visu_gl_ext_maps_setPrecision(VISU_GL_EXT_MAPS(mapSet), (VisuMap*)0, prec); } /** * visu_gl_ext_map_set_setShade: * @mapSet: a #VisuGlExtMapSet object. * @shade: (allow-none) (transfer full): a #ToolShade object. * * Changes the #ToolShade used to render data variation on the @map. * * Since: 3.8 * * Returns: TRUE if @shade of @map is changed. **/ gboolean visu_gl_ext_map_set_setShade(VisuGlExtMapSet *mapSet, ToolShade *shade) { gboolean diff; if (!tool_shade_compare(mapSet->priv->shade, shade)) { if (mapSet->priv->shade) g_boxed_free(TOOL_TYPE_SHADE, mapSet->priv->shade); mapSet->priv->shade = (shade) ? g_boxed_copy(TOOL_TYPE_SHADE, shade) : (ToolShade*)0; diff = TRUE; g_object_notify_by_pspec(G_OBJECT(mapSet), _properties[SHADE_PROP]); } visu_gl_ext_maps_setShade(VISU_GL_EXT_MAPS(mapSet), (VisuMap*)0, shade); visu_gl_ext_shade_setShade(mapSet->priv->extLegend, shade); return diff; } /** * visu_gl_ext_map_set_setLineColor: * @mapSet: a #VisuGlExtMapSet object. * @color: (allow-none) (transfer full): a #ToolColor object. * * Changes the rendered isoline color of @map to @color. If @color is * %NULL, then the isolines will be color inversed to the #ToolShade * of @map (see visu_gl_ext_map_set_setShade()). * * Since: 3.8 * * Returns: TRUE if @color of @map is changed. **/ gboolean visu_gl_ext_map_set_setLineColor(VisuGlExtMapSet *mapSet, const ToolColor *color) { gboolean diff; if (!tool_color_equal(mapSet->priv->color, color)) { if (mapSet->priv->color) g_boxed_free(TOOL_TYPE_COLOR, mapSet->priv->color); mapSet->priv->color = (color) ? g_boxed_copy(TOOL_TYPE_COLOR, color) : (ToolColor*)0; diff = TRUE; g_object_notify_by_pspec(G_OBJECT(mapSet), _properties[COLOR_PROP]); } visu_gl_ext_maps_setLineColor(VISU_GL_EXT_MAPS(mapSet), (VisuMap*)0, color); return diff; } /** * visu_gl_ext_map_set_setTransparent: * @mapSet: a #VisuGlExtMapSet object. * @alpha: a boolean. * * Sets if @map is rendered with transparency or not. If @alpha is * %TRUE, the lower the rendered value is, the more transparent the * colour will be. * * Since: 3.8 * * Returns: TRUE if transparency of @map is changed. **/ gboolean visu_gl_ext_map_set_setTransparent(VisuGlExtMapSet *mapSet, gboolean alpha) { g_return_val_if_fail(VISU_IS_GL_EXT_MAP_SET(mapSet), FALSE); if (mapSet->priv->alpha != alpha) { mapSet->priv->alpha = alpha; g_object_notify_by_pspec(G_OBJECT(mapSet), _properties[ALPHA_PROP]); } return visu_gl_ext_maps_setTransparent(VISU_GL_EXT_MAPS(mapSet), (VisuMap*)0, alpha); } /** * visu_gl_ext_map_set_setLines: * @mapSet: a #VisuGlExtMapSet object. * @nLines: a number. * * Set the number of iso-lines that are computed for each #VisuMap in * @mapSet. Contrary to visu_map_setLines(), this routine set the same * number of lines for every #VisuMap and use the same bounds for all. * * Since: 3.8 * * Returns: TRUE if the number of lines of @mapSet is changed. **/ gboolean visu_gl_ext_map_set_setLines(VisuGlExtMapSet *mapSet, guint nLines) { g_return_val_if_fail(VISU_IS_GL_EXT_MAP_SET(mapSet), FALSE); if (mapSet->priv->nLines == nLines) return FALSE; mapSet->priv->nLines = nLines; g_object_notify_by_pspec(G_OBJECT(mapSet), _properties[N_LINES_PROP]); _setLines(mapSet); return TRUE; } /** * visu_gl_ext_map_set_setScaling: * @mapSet: a #VisuGlExtMapSet object. * @scale: a #ToolMatrixScalingFlag scaling method. * * Set globally the scaling method for all #VisuMap in @mapSet. * * Since: 3.8 * * Returns: TRUE if scaling function is changed. **/ gboolean visu_gl_ext_map_set_setScaling(VisuGlExtMapSet *mapSet, ToolMatrixScalingFlag scale) { VisuGlExtMapsIter iter; g_return_val_if_fail(VISU_IS_GL_EXT_MAP_SET(mapSet), FALSE); if (mapSet->priv->scale == scale) return FALSE; mapSet->priv->scale = scale; g_object_notify_by_pspec(G_OBJECT(mapSet), _properties[SCALE_PROP]); visu_gl_ext_shade_setScaling(mapSet->priv->extLegend, scale); for (visu_gl_ext_maps_iter_new(VISU_GL_EXT_MAPS(mapSet), &iter); iter.valid; visu_gl_ext_maps_iter_next(&iter)) visu_map_setScaling(iter.map, scale); return TRUE; } /** * visu_gl_ext_map_set_setScalingRange: * @mapSet: a #VisuGlExtMapSet object. * @minMax: (array fixed-size=2) (allow-none): a range. * * Set globally the scaling range for all #VisuMap in @mapSet. * * Since: 3.8 * * Returns: TRUE if the range is changed of @mapSet is changed. **/ gboolean visu_gl_ext_map_set_setScalingRange(VisuGlExtMapSet *mapSet, const float minMax[2]) { VisuGlExtMapsIter iter; g_return_val_if_fail(VISU_IS_GL_EXT_MAP_SET(mapSet), FALSE); DBG_fprintf(stderr, "Extension MapSet: set scaling range to %p (%d).\n", (gpointer)minMax, mapSet->priv->useManualRange); if ((mapSet->priv->useManualRange && minMax && mapSet->priv->manualMinMax[0] == minMax[0] && mapSet->priv->manualMinMax[1] == minMax[1]) || (!mapSet->priv->useManualRange && !minMax)) return FALSE; mapSet->priv->useManualRange = (minMax != (const float*)0); g_object_notify_by_pspec(G_OBJECT(mapSet), _properties[USE_MANUAL_MM_PROP]); if (minMax) { mapSet->priv->manualMinMax[0] = minMax[0]; g_object_notify_by_pspec(G_OBJECT(mapSet), _properties[MANUAL_MIN_PROP]); mapSet->priv->manualMinMax[1] = minMax[1]; g_object_notify_by_pspec(G_OBJECT(mapSet), _properties[MANUAL_MAX_PROP]); g_object_notify_by_pspec(G_OBJECT(mapSet), _properties[MANUAL_MM_PROP]); } for (visu_gl_ext_maps_iter_new(VISU_GL_EXT_MAPS(mapSet), &iter); iter.valid; visu_gl_ext_maps_iter_next(&iter)) visu_map_setScalingRange(iter.map, minMax); /* We update the legend min and max. */ _legend(mapSet); return TRUE; } /** * visu_gl_ext_map_set_getPrecision: * @mapSet: a #VisuGlExtMapSet object. * * Return the rendering adaptability of @map, or the general * adaptability value if @map is %NULL. * * Since: 3.8 * * Returns: the precision value. **/ float visu_gl_ext_map_set_getPrecision(const VisuGlExtMapSet *mapSet) { g_return_val_if_fail(VISU_IS_GL_EXT_MAP_SET(mapSet), 100.f); return mapSet->priv->prec; } /** * visu_gl_ext_map_set_getTransparent: * @mapSet: a #VisuGlExtMapSet object. * * Return if field values are also used for alpha channel for @map, or the general * setting if @map is %NULL. * * Since: 3.8 * * Returns: if map is rendered with transparency or not. **/ gboolean visu_gl_ext_map_set_getTransparent(const VisuGlExtMapSet *mapSet) { g_return_val_if_fail(VISU_IS_GL_EXT_MAP_SET(mapSet), FALSE); return mapSet->priv->alpha; } /* Callbacks. */ static gboolean visu_gl_ext_map_set_add(VisuGlExtMaps *maps, VisuMap *map, float prec, ToolShade *shade, const ToolColor *color, gboolean alpha) { VisuGlExtMapSet *self = VISU_GL_EXT_MAP_SET(maps); g_return_val_if_fail(VISU_IS_GL_EXT_MAP_SET(maps), FALSE); g_return_val_if_fail(!visu_map_getField(map) || visu_map_getField(map) == self->priv->field, FALSE); g_hash_table_insert(self->priv->maps, map, _newMapData(VISU_GL_EXT_MAP_SET(maps), map)); if (!VISU_GL_EXT_MAPS_CLASS(visu_gl_ext_map_set_parent_class)->add(maps, map, prec, shade, color, alpha)) { g_hash_table_remove(self->priv->maps, map); return FALSE; } return TRUE; } static void visu_gl_ext_map_set_added(VisuGlExtMaps *maps, VisuMap *map _U_) { VisuGlExtMapSet *self = VISU_GL_EXT_MAP_SET(maps); if (visu_gl_ext_getActive(VISU_GL_EXT(maps)) && self->priv->field && !visu_scalar_field_isEmpty(self->priv->field)) visu_gl_ext_setActive(VISU_GL_EXT(self->priv->extLegend), TRUE); } static void visu_gl_ext_map_set_removed(VisuGlExtMaps *maps, VisuMap *map) { VisuGlExtMapSet *self = VISU_GL_EXT_MAP_SET(maps); DBG_fprintf(stderr, "Extension MapSet: removing map %p.\n", (gpointer)map); g_hash_table_remove(self->priv->maps, map); if (!g_hash_table_size(self->priv->maps)) visu_gl_ext_setActive(VISU_GL_EXT(self->priv->extLegend), FALSE); } static void onMapChange(VisuMap *map _U_, gpointer data) { DBG_fprintf(stderr, "Extension MapSet: caught 'changed' signal for map %p.\n", (gpointer)map); _drawnMinMax(VISU_GL_EXT_MAP_SET(data)); } static void onFieldChanged(VisuScalarField *field _U_, gpointer data) { VisuGlExtMapSet *self = VISU_GL_EXT_MAP_SET(data); visu_gl_ext_setActive(VISU_GL_EXT(self->priv->extLegend), visu_gl_ext_getActive(VISU_GL_EXT(self)) && g_hash_table_size(self->priv->maps) > 0 && !visu_scalar_field_isEmpty(self->priv->field)); self->priv->drawnMinMax[0] = G_MAXFLOAT; self->priv->drawnMinMax[1] = -G_MAXFLOAT; } /** * visu_gl_ext_map_set_export: * @mapSet: a #VisuGlExtMapSet object. * @map: a given #VisuMap object. * @filename: a filename. * @format: a format. * @error: an error location. * * Runs visu_map_export() on @map with @mapSet shade and colour. * * Since: 3.8 * * Returns: TRUE if exportation is successful. **/ gboolean visu_gl_ext_map_set_export(VisuGlExtMapSet *mapSet, VisuMap *map, const gchar *filename, VisuMapExportFormat format, GError **error) { return visu_map_export(map, mapSet->priv->shade, (mapSet->priv->color) ? mapSet->priv->color->rgba : (float*)0, mapSet->priv->prec, filename, format, error); } v_sim-3.8.0/src/extensions/mapset.h000066400000000000000000000122151370110300500172560ustar00rootroot00000000000000/* EXTRAITS DE LA LICENCE Copyright CEA, contributeurs : Damien CALISTE, laboratoire L_Sim, (20016) Adresse mèl : CALISTE, damien P caliste AT cea P fr. Ce logiciel est un programme informatique servant à visualiser des structures atomiques dans un rendu pseudo-3D. Ce logiciel est régi par la licence CeCILL soumise au droit français et respectant les principes de diffusion des logiciels libres. Vous pouvez utiliser, modifier et/ou redistribuer ce programme sous les conditions de la licence CeCILL telle que diffusée par le CEA, le CNRS et l'INRIA sur le site "http://www.cecill.info". Le fait que vous puissiez accéder à cet en-tête signifie que vous avez pris connaissance de la licence CeCILL, et que vous en avez accepté les termes (cf. le fichier Documentation/licence.fr.txt fourni avec ce logiciel). */ /* LICENCE SUM UP Copyright CEA, contributors : Damien CALISTE, laboratoire L_Sim, (20016) E-mail address: CALISTE, damien P caliste AT cea P fr. This software is a computer program whose purpose is to visualize atomic configurations in 3D. This software is governed by the CeCILL license under French law and abiding by the rules of distribution of free software. You can use, modify and/ or redistribute the software under the terms of the CeCILL license as circulated by CEA, CNRS and INRIA at the following URL "http://www.cecill.info". The fact that you are presently reading this means that you have had knowledge of the CeCILL license and that you accept its terms. You can find a copy of this licence shipped with this software at COPYING. */ #ifndef MAPSET_H #define MAPSET_H #include "maps.h" #include "shade.h" /** * VISU_TYPE_GL_EXT_MAP_SET: * * return the type of #VisuGlExtMapSet. * * Since: 3.7 */ #define VISU_TYPE_GL_EXT_MAP_SET (visu_gl_ext_map_set_get_type ()) /** * VISU_GL_EXT_MAP_SET: * @obj: a #GObject to cast. * * Cast the given @obj into #VisuGlExtMapSet type. * * Since: 3.7 */ #define VISU_GL_EXT_MAP_SET(obj) (G_TYPE_CHECK_INSTANCE_CAST(obj, VISU_TYPE_GL_EXT_MAP_SET, VisuGlExtMapSet)) /** * VISU_GL_EXT_MAP_SET_CLASS: * @klass: a #GObjectClass to cast. * * Cast the given @klass into #VisuGlExtMapSetClass. * * Since: 3.7 */ #define VISU_GL_EXT_MAP_SET_CLASS(klass) (G_TYPE_CHECK_CLASS_CAST(klass, VISU_TYPE_GL_EXT_MAP_SET, VisuGlExtMapSetClass)) /** * VISU_IS_GL_EXT_MAP_SET: * @obj: a #GObject to test. * * Test if the given @ogj is of the type of #VisuGlExtMapSet object. * * Since: 3.7 */ #define VISU_IS_GL_EXT_MAP_SET(obj) (G_TYPE_CHECK_INSTANCE_TYPE(obj, VISU_TYPE_GL_EXT_MAP_SET)) /** * VISU_IS_GL_EXT_MAP_SET_CLASS: * @klass: a #GObjectClass to test. * * Test if the given @klass is of the type of #VisuGlExtMapSetClass class. * * Since: 3.7 */ #define VISU_IS_GL_EXT_MAP_SET_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE(klass, VISU_TYPE_GL_EXT_MAP_SET)) /** * VISU_GL_EXT_MAP_SET_GET_CLASS: * @obj: a #GObject to get the class of. * * It returns the class of the given @obj. * * Since: 3.7 */ #define VISU_GL_EXT_MAP_SET_GET_CLASS(obj) (G_TYPE_INSTANCE_GET_CLASS(obj, VISU_TYPE_GL_EXT_MAP_SET, VisuGlExtMapSetClass)) typedef struct _VisuGlExtMapSet VisuGlExtMapSet; typedef struct _VisuGlExtMapSetPrivate VisuGlExtMapSetPrivate; typedef struct _VisuGlExtMapSetClass VisuGlExtMapSetClass; struct _VisuGlExtMapSet { VisuGlExtMaps parent; VisuGlExtMapSetPrivate *priv; }; struct _VisuGlExtMapSetClass { VisuGlExtMapsClass parent; }; /** * visu_gl_ext_map_set_get_type: * * This method returns the type of #VisuGlExtMapSet, use * VISU_TYPE_GL_EXT_MAP_SET instead. * * Since: 3.8 * * Returns: the type of #VisuGlExtMapSet. */ GType visu_gl_ext_map_set_get_type(void); VisuGlExtMapSet* visu_gl_ext_map_set_new(const gchar *name); VisuGlExtShade* visu_gl_ext_map_set_getLegend(VisuGlExtMapSet *mapSet); void visu_gl_ext_map_set_setField(VisuGlExtMapSet *mapSet, VisuScalarField *field); VisuMap* visu_gl_ext_map_set_addFromPlane(VisuGlExtMapSet *mapSet, VisuPlane *plane); void visu_gl_ext_map_set_setPlane(VisuGlExtMapSet *mapSet, VisuMap *map, VisuPlane *plane); VisuPlane* visu_gl_ext_map_set_getPlane(VisuGlExtMapSet *mapSet, VisuMap *map); gboolean visu_gl_ext_map_set_setPrecision(VisuGlExtMapSet *mapSet, float prec); gboolean visu_gl_ext_map_set_setShade(VisuGlExtMapSet *mapSet, ToolShade *shade); gboolean visu_gl_ext_map_set_setLineColor(VisuGlExtMapSet *mapSet, const ToolColor *color); gboolean visu_gl_ext_map_set_setTransparent(VisuGlExtMapSet *mapSet, gboolean alpha); float visu_gl_ext_map_set_getPrecision(const VisuGlExtMapSet *mapSet); gboolean visu_gl_ext_map_set_getTransparent(const VisuGlExtMapSet *mapSet); gboolean visu_gl_ext_map_set_setLines(VisuGlExtMapSet *mapSet, guint nLines); gboolean visu_gl_ext_map_set_setScaling(VisuGlExtMapSet *mapSet, ToolMatrixScalingFlag scale); gboolean visu_gl_ext_map_set_setScalingRange(VisuGlExtMapSet *mapSet, const float minMax[2]); gboolean visu_gl_ext_map_set_export(VisuGlExtMapSet *mapSet, VisuMap *map, const gchar *filename, VisuMapExportFormat format, GError **error); #endif v_sim-3.8.0/src/extensions/marks.c000066400000000000000000002510071370110300500171010ustar00rootroot00000000000000/* EXTRAITS DE LA LICENCE Copyright CEA, contributeurs : Luc BILLARD et Damien CALISTE, laboratoire L_Sim, (2001-2005) Adresse mèl : BILLARD, non joignable par mèl ; CALISTE, damien P caliste AT cea P fr. Ce logiciel est un programme informatique servant à visualiser des structures atomiques dans un rendu pseudo-3D. Ce logiciel est régi par la licence CeCILL soumise au droit français et respectant les principes de diffusion des logiciels libres. Vous pouvez utiliser, modifier et/ou redistribuer ce programme sous les conditions de la licence CeCILL telle que diffusée par le CEA, le CNRS et l'INRIA sur le site "http://www.cecill.info". Le fait que vous puissiez accéder à cet en-tête signifie que vous avez pris connaissance de la licence CeCILL, et que vous en avez accepté les termes (cf. le fichier Documentation/licence.fr.txt fourni avec ce logiciel). */ /* LICENCE SUM UP Copyright CEA, contributors : Luc BILLARD et Damien CALISTE, laboratoire L_Sim, (2001-2005) E-mail address: BILLARD, not reachable any more ; CALISTE, damien P caliste AT cea P fr. This software is a computer program whose purpose is to visualize atomic configurations in 3D. This software is governed by the CeCILL license under French law and abiding by the rules of distribution of free software. You can use, modify and/ or redistribute the software under the terms of the CeCILL license as circulated by CEA, CNRS and INRIA at the following URL "http://www.cecill.info". The fact that you are presently reading this means that you have had knowledge of the CeCILL license and that you accept its terms. You can find a copy of this licence shipped with this software at Documentation/licence.en.txt. */ #include #include #include #include #include "marks.h" #include #include #include #include #include #include #include #include #include #include /** * SECTION:marks * @short_description: Draw features on nodes, like measurement marks * or highlights. * * #VisuGlExtMarks is used to store a set of mark on a list of * nodes. A mark can be a distance measurement, an angle measurement * or an highlight. The measurement marks are automatically updated by * listening to the #VisuInteractive::node-selection signal. On the * contrary, highlights are set, unset or toggled using * visu_gl_ext_marks_setHighlight(). * In addition, #VisuGlExtMarks can be export to or loaded from an * XML file thanks to visu_gl_ext_marks_exportXMLFile() and visu_gl_ext_marks_parseXMLFile(). * * Since: 3.6 */ typedef enum { MARK_BIG_SQUARE, MARK_SMALL_SQUARE, MARK_HIGHLIGHT, MARK_DISTANCE, MARK_ANGLE, MARK_LINE } VisuMarkType; struct MarkInfo_struct { /* Mark type. */ VisuMarkType type; /* Id used to address the VisuNode when the pointer node1 has changed, for example when a new VisuData is loaded with the same geometry and we want to apply this mark. */ guint idNode1; /* Idem for a second node. */ guint idNode2; /* Idem for a third node. */ guint idNode3; /* List of nodes */ GList *nodes; guint size; GLfloat *coord; guint *nIds; }; /** * VisuNodeInfo: * @id: an id; * @dist: a float. * * Some data. * * Since: 3.5 */ typedef struct _VisuNodeInfo VisuNodeInfo; struct _VisuNodeInfo { guint id; float dist; }; typedef struct _ExtNode ExtNode; struct _ExtNode { VisuGlExt parent; VisuGlExtMarks *marks; }; struct _VisuGlExtMarksPrivate { gboolean dispose_has_run; ExtNode *extNode; /* A reference on the #VisuData and #VisuGlView it refers to. */ VisuGlView *view; gulong cameraAngles, cameraPosition, cameraZoom, cameraPersp; VisuNodeArrayRenderer *renderer; gulong nodePosition, nodeRender, nodeMaterial, nodePopulation, siz_sig, dat_sig; /* Interactive object to get measurement signals. */ VisuInteractive *inter; gulong nodeSelection; /* A list of MarkInfo_struct elements. */ GList *storedMarks; guint hasCameraMarks; gboolean drawValues; GArray *cachedHighlighted; /* Miscellaneous. */ float infoRange; VisuGlExtMarksHidingModes hidingMode; }; enum { MEASUREMENT_CHANGE_SIGNAL, NB_SIGNAL }; static guint signals[NB_SIGNAL]; enum { PROP_0, VIEW_PROP, INTER_PROP, HIDING_PROP, HIGHLIGHT_PROP, N_PROP }; static GParamSpec *properties[N_PROP]; /* Local variables. */ #define MARK_BIG_SQUARE_SIZE 8 #define MARK_SMALL_SQUARE_SIZE 4 static guchar markBigSquare[MARK_BIG_SQUARE_SIZE * MARK_BIG_SQUARE_SIZE * 4]; static guchar markSmallSquare[MARK_SMALL_SQUARE_SIZE * MARK_SMALL_SQUARE_SIZE * 4]; static float highlightFactor = 1.25f; /* Local methods. */ static ExtNode* ext_node_new(VisuGlExtMarks *marks); static struct MarkInfo_struct* markNew(VisuMarkType type); static void markFree(struct MarkInfo_struct *mark); static VisuMarkType markRemove(VisuGlExtMarks *marks, GList *rmList); static void removeDot(VisuGlExtMarks *marks, guint nodeId, VisuMarkType type); static void addDot(VisuGlExtMarks *marks, guint nodeId, VisuMarkType type); static gboolean toggleDistance(VisuGlExtMarks *marks, guint nodeRefId, guint nodeId, gboolean set); static gboolean toggleAngle(VisuGlExtMarks *marks, guint nodeRefId, guint nodeRef2Id, guint nodeId, gboolean set); static gboolean toggleHighlight(VisuGlExtMarks *marks, guint nodeId, VisuGlExtMarksStatus status, gboolean *finalStatus); static gboolean setInformation(VisuGlExtMarks *marks, VisuData *dataObj, guint node); static void putMark(VisuData *data, guint nodeRefId, guint nodeId, VisuMarkType type); static void drawMarkDot(VisuData *data, guint nodeId, VisuMarkType type); static void drawMarkHighlight(VisuData *data, guint nodeId, VisuGlView *view, VisuNodeArrayRenderer *renderer); static void drawMarkDistance(VisuData *data, guint nodeRefId, guint nodeId, VisuMarkType type); static void drawMarkAngle(VisuData *data, guint nodeRefId, guint nodeRef2Id, guint nodeId, guint id); static void drawMarkLine(VisuData *data _U_, GLfloat *coord, guint size); static void visu_gl_ext_marks_dispose(GObject *obj); static void visu_gl_ext_marks_get_property(GObject* obj, guint property_id, GValue *value, GParamSpec *pspec); static void visu_gl_ext_marks_set_property(GObject* obj, guint property_id, const GValue *value, GParamSpec *pspec); static void visu_gl_ext_marks_rebuild(VisuGlExt *ext); static void visu_gl_ext_marks_draw(VisuGlExt *ext); static gboolean visu_gl_ext_marks_setGlView(VisuGlExt *ext, VisuGlView *view); static void visu_node_masker_interface_init(VisuNodeMaskerInterface *iface); static gboolean _maskApply(const VisuNodeMasker *self, VisuNodeArray *array); static VisuNodeInfo* _getDistanceList(VisuData *data, guint nodeId, float *minVal); /* Local callbacks. */ static void _setDirty(VisuGlExtMarks *marks); static void onNotifyData(VisuGlExtMarks *marks, GParamSpec *pspec, VisuNodeArrayRenderer *renderer); static void _populationDecrease(VisuGlExtMarks *marks, GArray *nodes); /* static void updateListOnCameraChange(VisuGlView *view, gpointer data); */ static gboolean onNodeSelection(VisuInteractive *inter, VisuInteractivePick kind, VisuData *dataObje, VisuNode *node1, VisuNode *node2, VisuNode *node3, gpointer data); /* V_Sim resources and paramaters. */ #define FLAG_RESOURCE_FACTOR "highlight_radiusFactor" #define DESC_RESOURCE_FACTOR "Give the factor for the highlight radius ; one float (> 1.)" static void exportResources(GString *data, VisuData *dataObj); G_DEFINE_TYPE_WITH_CODE(VisuGlExtMarks, visu_gl_ext_marks, VISU_TYPE_GL_EXT, G_ADD_PRIVATE(VisuGlExtMarks) G_IMPLEMENT_INTERFACE(VISU_TYPE_NODE_MASKER, visu_node_masker_interface_init)) static void visu_gl_ext_marks_class_init(VisuGlExtMarksClass *klass) { int i; float rg[2] = {1.01f, G_MAXFLOAT}; VisuConfigFileEntry *conf; G_OBJECT_CLASS(klass)->dispose = visu_gl_ext_marks_dispose; G_OBJECT_CLASS(klass)->get_property = visu_gl_ext_marks_get_property; G_OBJECT_CLASS(klass)->set_property = visu_gl_ext_marks_set_property; VISU_GL_EXT_CLASS(klass)->rebuild = visu_gl_ext_marks_rebuild; VISU_GL_EXT_CLASS(klass)->draw = visu_gl_ext_marks_draw; VISU_GL_EXT_CLASS(klass)->setGlView = visu_gl_ext_marks_setGlView; DBG_fprintf(stderr, "Visu Marks: installing signals.\n"); /** * VisuGlExtMarks::measurementChanged: * @marks: the object emitting the signal. * @data: the #VisuData the measurement is done on. * * The list of measurements has been changed. * * Since: 3.6 */ signals[MEASUREMENT_CHANGE_SIGNAL] = g_signal_new("measurementChanged", G_TYPE_FROM_CLASS(klass), G_SIGNAL_RUN_LAST | G_SIGNAL_NO_RECURSE | G_SIGNAL_NO_HOOKS, 0, NULL, NULL, g_cclosure_marshal_VOID__OBJECT, G_TYPE_NONE, 1, VISU_TYPE_DATA); /** * VisuGlExtMarks::gl-view: * * Store to which #VisuGlView the marks labels are aligned with. * * Since: 3.8 */ properties[VIEW_PROP] = g_param_spec_object("gl-view", "GlView", "GlView mark labels are aligned with", VISU_TYPE_GL_VIEW, G_PARAM_READWRITE); /** * VisuGlExtMarks::interactive: * * Store which #VisuInteractive the marks should react on. * * Since: 3.8 */ properties[INTER_PROP] = g_param_spec_object("interactive", "Interactive", "Interactive the marks react on", VISU_TYPE_INTERACTIVE, G_PARAM_READWRITE); /** * VisuGlExtMarks::hiding-mode: * * Mode used to hide nodes. * * Since: 3.8 */ properties[HIDING_PROP] = g_param_spec_uint("hiding-mode", "Hiding mode", "nodes hiding property", 0, HIDE_NON_HIGHLIGHT, HIDE_NONE, G_PARAM_READWRITE); /** * VisuGlExtMarks::highlight: * * Set of node ids with highlight. * * Since: 3.8 */ properties[HIGHLIGHT_PROP] = g_param_spec_boxed("highlight", "Highlight", "node ids with highlight mark.", G_TYPE_ARRAY, G_PARAM_READWRITE); g_object_class_install_properties(G_OBJECT_CLASS(klass), N_PROP, properties); /* Create the marks. */ for (i = 0; i < MARK_BIG_SQUARE_SIZE * MARK_BIG_SQUARE_SIZE * 4 ; i++) markBigSquare[i] = 0xff; for (i = 0; i < MARK_SMALL_SQUARE_SIZE * MARK_SMALL_SQUARE_SIZE * 4; i++) markSmallSquare[i] = 0xff; conf = visu_config_file_addFloatArrayEntry(VISU_CONFIG_FILE_RESOURCE, FLAG_RESOURCE_FACTOR, DESC_RESOURCE_FACTOR, 1, &highlightFactor, rg, FALSE); visu_config_file_entry_setVersion(conf, 3.6f); visu_config_file_addExportFunction(VISU_CONFIG_FILE_RESOURCE, exportResources); } static void visu_node_masker_interface_init(VisuNodeMaskerInterface *iface) { iface->apply = _maskApply; } static void visu_gl_ext_marks_init(VisuGlExtMarks *marks) { DBG_fprintf(stderr, "Visu Marks: create a new object, %p.\n", (gpointer)marks); marks->priv = visu_gl_ext_marks_get_instance_private(marks); marks->priv->dispose_has_run = FALSE; marks->priv->renderer = (VisuNodeArrayRenderer*)0; marks->priv->view = (VisuGlView*)0; marks->priv->storedMarks = (GList*)0; marks->priv->cachedHighlighted = (GArray*)0; marks->priv->hasCameraMarks = 0; marks->priv->drawValues = TRUE; marks->priv->infoRange = 1.44f; marks->priv->extNode = (ExtNode*)0; marks->priv->inter = (VisuInteractive*)0; marks->priv->nodeSelection = 0; marks->priv->hidingMode = HIDE_NONE; } static void visu_gl_ext_marks_dispose(GObject *obj) { VisuGlExtMarks *marks; DBG_fprintf(stderr, "Visu Marks: dispose object %p.\n", (gpointer)obj); marks = VISU_GL_EXT_MARKS(obj); if (marks->priv->dispose_has_run) return; marks->priv->dispose_has_run = TRUE; visu_gl_ext_marks_setDataRenderer(marks, (VisuNodeArrayRenderer*)0); DBG_fprintf(stderr, " | release VisuGlView.\n"); visu_gl_ext_marks_setGlView(VISU_GL_EXT(marks), (VisuGlView*)0); DBG_fprintf(stderr, " | free internal VisuGlExt.\n"); g_object_unref(G_OBJECT(marks->priv->extNode)); DBG_fprintf(stderr, " | unconnect signals.\n"); visu_gl_ext_marks_setInteractive(marks, (VisuInteractive*)0); /* Chain up to the parent class */ DBG_fprintf(stderr, " | chain up.\n"); G_OBJECT_CLASS(visu_gl_ext_marks_parent_class)->dispose(obj); DBG_fprintf(stderr, " | OK.\n"); } static void visu_gl_ext_marks_get_property(GObject* obj, guint property_id, GValue *value, GParamSpec *pspec) { VisuGlExtMarks *self = VISU_GL_EXT_MARKS(obj); DBG_fprintf(stderr, "Extension Marks: get property '%s' -> ", g_param_spec_get_name(pspec)); switch (property_id) { case VIEW_PROP: g_value_set_object(value, self->priv->view); DBG_fprintf(stderr, "%p.\n", (gpointer)self->priv->view); break; case INTER_PROP: g_value_set_object(value, self->priv->inter); DBG_fprintf(stderr, "%p.\n", (gpointer)self->priv->inter); break; case HIDING_PROP: g_value_set_uint(value, self->priv->hidingMode); DBG_fprintf(stderr, "%d.\n", self->priv->hidingMode); break; case HIGHLIGHT_PROP: g_value_set_boxed(value, visu_gl_ext_marks_getHighlighted(self)); DBG_fprintf(stderr, "%p.\n", g_value_get_boxed(value)); break; default: /* We don't have any other property... */ G_OBJECT_WARN_INVALID_PROPERTY_ID(obj, property_id, pspec); break; } } static void visu_gl_ext_marks_set_property(GObject* obj, guint property_id, const GValue *value, GParamSpec *pspec) { VisuGlExtMarks *self = VISU_GL_EXT_MARKS(obj); DBG_fprintf(stderr, "Extension Marks: set property '%s' -> ", g_param_spec_get_name(pspec)); switch (property_id) { case VIEW_PROP: visu_gl_ext_marks_setGlView(VISU_GL_EXT(obj), VISU_GL_VIEW(g_value_get_object(value))); DBG_fprintf(stderr, "%p.\n", (gpointer)self->priv->view); break; case INTER_PROP: DBG_fprintf(stderr, "%p.\n", g_value_get_object(value)); visu_gl_ext_marks_setInteractive (self, VISU_INTERACTIVE(g_value_get_object(value))); break; case HIDING_PROP: DBG_fprintf(stderr, "%d.\n", g_value_get_uint(value)); visu_gl_ext_marks_setHidingMode(self, g_value_get_uint(value)); break; case HIGHLIGHT_PROP: DBG_fprintf(stderr, "%p.\n", g_value_get_boxed(value)); visu_gl_ext_marks_setHighlight(self, g_value_get_boxed(value), MARKS_STATUS_SET); break; default: /* We don't have any other property... */ G_OBJECT_WARN_INVALID_PROPERTY_ID(obj, property_id, pspec); break; } } /** * visu_gl_ext_marks_new: * @name: (allow-none): a possible name for the #VisuGlExt. * * Create a new #VisuGlExtMarks object. Make it listen to * #VisuInteractive::node-selection signal to update itself * automatically. * * Returns: the newly created object. */ VisuGlExtMarks* visu_gl_ext_marks_new(const gchar *name) { char *name_ = "MarksInv"; char *description = _("Draw some marks on element in video inverse."); VisuGlExtMarks *marks; marks = VISU_GL_EXT_MARKS(g_object_new(VISU_TYPE_GL_EXT_MARKS, "name", (name)?name:name_, "label", _(name), "description", description, "nGlObj", 1, "priority", VISU_GL_EXT_PRIORITY_LAST - 1, "saveState", TRUE, NULL)); marks->priv->extNode = ext_node_new(marks); return marks; } /** * visu_gl_ext_marks_getInternalList: * @marks: a #VisuGlExtMarks object. * * Return an additional list used internaly. * * Since: 3.7 * * Returns: (transfer none): a #VisuGlExt object. **/ VisuGlExt* visu_gl_ext_marks_getInternalList(VisuGlExtMarks *marks) { g_return_val_if_fail(VISU_IS_GL_EXT_MARKS(marks), (VisuGlExt*)0); return VISU_GL_EXT(marks->priv->extNode); } static struct MarkInfo_struct* markNew(VisuMarkType type) { struct MarkInfo_struct *mark; mark = g_malloc(sizeof(struct MarkInfo_struct)); mark->type = type; mark->idNode1 = -1; mark->idNode2 = -1; mark->idNode3 = -1; mark->nodes = (GList*)0; mark->size = 0; mark->coord = (GLfloat*)0; mark->nIds = (guint*)0; return (struct MarkInfo_struct*)mark; } static void markFree(struct MarkInfo_struct *mark) { if (mark->nodes) g_list_free(mark->nodes); if (mark->coord) g_free(mark->coord); if (mark->nIds) g_free(mark->nIds); g_free(mark); } static VisuMarkType markRemove(VisuGlExtMarks *marks, GList *rmList) { struct MarkInfo_struct *mark; gboolean hasCameraMarks; VisuMarkType type; mark = (struct MarkInfo_struct*)rmList->data; DBG_fprintf(stderr, "Visu Marks: remove mark (%d %d %d).\n", mark->idNode1, mark->idNode2, mark->idNode3); hasCameraMarks = (marks->priv->hasCameraMarks > 0); type = mark->type; if (mark->type == MARK_LINE) marks->priv->hasCameraMarks -= 1; if (mark->type == MARK_HIGHLIGHT && marks->priv->cachedHighlighted) { g_array_unref(marks->priv->cachedHighlighted); marks->priv->cachedHighlighted = (GArray*)0; } markFree(mark); marks->priv->storedMarks = g_list_delete_link(marks->priv->storedMarks, rmList); if (hasCameraMarks && marks->priv->hasCameraMarks == 0) { g_signal_handler_disconnect(G_OBJECT(marks->priv->view), marks->priv->cameraAngles); g_signal_handler_disconnect(G_OBJECT(marks->priv->view), marks->priv->cameraPosition); g_signal_handler_disconnect(G_OBJECT(marks->priv->view), marks->priv->cameraZoom); g_signal_handler_disconnect(G_OBJECT(marks->priv->view), marks->priv->cameraPersp); } return type; } /** * visu_gl_ext_marks_setInteractive: * @marks: a #VisuGlExtMarks object. * @inter: (transfer full) (allow-none): a #VisuInteractive object. * * Listen to #VisuInteractive::node-selection signal to update @marks. * * Since: 3.7 **/ void visu_gl_ext_marks_setInteractive(VisuGlExtMarks *marks, VisuInteractive *inter) { g_return_if_fail(VISU_IS_GL_EXT_MARKS(marks)); DBG_fprintf(stderr, "Visu Marks: set interactive object.\n"); if (marks->priv->inter) { DBG_fprintf(stderr, " | old interactive (%p) has %d ref counts.\n", (gpointer)marks->priv->inter, G_OBJECT(marks->priv->inter)->ref_count); g_signal_handler_disconnect(G_OBJECT(marks->priv->inter), marks->priv->nodeSelection); g_object_unref(marks->priv->inter); } if (inter) { g_object_ref(inter); marks->priv->nodeSelection = g_signal_connect(G_OBJECT(inter), "node-selection", G_CALLBACK(onNodeSelection), (gpointer)marks); DBG_fprintf(stderr, " | new interactive (%p) has %d ref counts.\n", (gpointer)inter, G_OBJECT(inter)->ref_count); } else marks->priv->nodeSelection = 0; marks->priv->inter = inter; g_object_notify_by_pspec(G_OBJECT(marks), properties[INTER_PROP]); } static gboolean visu_gl_ext_marks_setGlView(VisuGlExt *ext, VisuGlView *view) { VisuGlExtMarks *marks = VISU_GL_EXT_MARKS(ext); DBG_fprintf(stderr, " | marks has %d ref counts.\n", G_OBJECT(marks)->ref_count); /* We attach a new VisuGlView object. */ if (marks->priv->view == view) return FALSE; /* We unref the previous VisuView and disconnect signals. */ if (marks->priv->view) { /* if (marks->priv->hasCameraMarks > 0) */ /* { */ /* g_signal_handler_disconnect(marks->priv->view, marks->priv->cameraAngles); */ /* g_signal_handler_disconnect(marks->priv->view, marks->priv->cameraPosition); */ /* g_signal_handler_disconnect(marks->priv->view, marks->priv->cameraZoom); */ /* g_signal_handler_disconnect(marks->priv->view, marks->priv->cameraPersp); */ /* } */ g_object_unref(marks->priv->view); } marks->priv->view = view; if (marks->priv->view) { /* if (marks->priv->hasCameraMarks > 0) */ /* { */ /* marks->priv->cameraAngles = */ /* g_signal_connect(marks->priv->view, "ThetaPhiOmegaChanged", */ /* G_CALLBACK(updateListOnCameraChange), */ /* (gpointer)marks); */ /* marks->priv->cameraPosition = */ /* g_signal_connect(marks->priv->view, "XsYsChanged", */ /* G_CALLBACK(updateListOnCameraChange), */ /* (gpointer)marks); */ /* marks->priv->cameraZoom = */ /* g_signal_connect(marks->priv->view, "GrossChanged", */ /* G_CALLBACK(updateListOnCameraChange), */ /* (gpointer)marks); */ /* marks->priv->cameraPersp = */ /* g_signal_connect(marks->priv->view, "PerspChanged", */ /* G_CALLBACK(updateListOnCameraChange), */ /* (gpointer)marks); */ /* } */ /* We ref the new given view. */ g_object_ref(marks->priv->view); } g_object_notify_by_pspec(G_OBJECT(marks), properties[VIEW_PROP]); return TRUE; } static void _setData(VisuGlExtMarks *marks, VisuNodeArray *array) { GList *list, *rmList; struct MarkInfo_struct*mark; gboolean remove; gboolean invDirty, dirDirty; VisuMarkType type; invDirty = dirDirty = FALSE; /* Mark list as dirty because of position changed, if necessary. */ for (list = marks->priv->storedMarks; list; list = g_list_next(list)) if (((struct MarkInfo_struct*)list->data)->type == MARK_HIGHLIGHT) dirDirty = TRUE; else invDirty = TRUE; /* We update the list of nodes with marks. */ if (array) { /* Try to match previous marks on new VisuData. */ list = marks->priv->storedMarks; while(list) { mark = (struct MarkInfo_struct*)list->data; DBG_fprintf(stderr, " | old mark %p of type %d.\n", (gpointer)mark, mark->type); remove = FALSE; rmList = list; /* We remove mark if one of the node can't be matched. */ switch (mark->type) { case MARK_BIG_SQUARE: case MARK_SMALL_SQUARE: case MARK_HIGHLIGHT: remove = remove || !visu_node_array_getFromId(array, mark->idNode1); break; case MARK_DISTANCE: remove = remove || !visu_node_array_getFromId(array, mark->idNode1) || !visu_node_array_getFromId(array, mark->idNode2); break; case MARK_ANGLE: remove = remove || !visu_node_array_getFromId(array, mark->idNode1) || !visu_node_array_getFromId(array, mark->idNode2) || !visu_node_array_getFromId(array, mark->idNode3); break; default: g_warning("TODO implementation required."); } list = g_list_next(list); if (remove) { DBG_fprintf(stderr, " | delete old mark %p of type %d.\n", (gpointer)mark, mark->type); type = markRemove(marks, rmList); if (type == MARK_HIGHLIGHT) dirDirty = TRUE; else invDirty = TRUE; } } } else { invDirty = dirDirty = (g_list_length(marks->priv->storedMarks) > 0); for (list = marks->priv->storedMarks; list; list = g_list_next(list)) markFree((struct MarkInfo_struct*)list->data); g_list_free(marks->priv->storedMarks); marks->priv->storedMarks = (GList*)0; if (marks->priv->cachedHighlighted) g_array_unref(marks->priv->cachedHighlighted); marks->priv->cachedHighlighted = (GArray*)0; } DBG_fprintf(stderr, " | New mark list is pointing to %p.\n", (gpointer)marks->priv->storedMarks); /* Signal changes. */ g_object_notify_by_pspec(G_OBJECT(marks), properties[HIGHLIGHT_PROP]); g_signal_emit(G_OBJECT(marks), signals[MEASUREMENT_CHANGE_SIGNAL], 0, array); if (invDirty) visu_gl_ext_setDirty(VISU_GL_EXT(marks), TRUE); if (dirDirty) visu_gl_ext_setDirty(VISU_GL_EXT(marks->priv->extNode), TRUE); } /** * visu_gl_ext_marks_setDataRenderer: * @marks: a #VisuGlExtMarks object. * @renderer: a #VisuNodeArrayRenderer object. * * Attach the given @marks to @data. @marks will be updated if @data * is changed and internal list of marks is updated with the new nodes * of @data. */ void visu_gl_ext_marks_setDataRenderer(VisuGlExtMarks *marks, VisuNodeArrayRenderer *renderer) { DBG_fprintf(stderr, "Visu Marks: set new VisuNodeArrayRenderer %p (%p).\n", (gpointer)renderer, (gpointer)marks->priv->renderer); if (marks->priv->renderer == renderer) return; /* We unref the previous VisuData and disconnect signals. */ if (marks->priv->renderer) { g_signal_handler_disconnect(marks->priv->renderer, marks->priv->nodePosition); g_signal_handler_disconnect(marks->priv->renderer, marks->priv->nodeRender); g_signal_handler_disconnect(marks->priv->renderer, marks->priv->nodeMaterial); g_signal_handler_disconnect(marks->priv->renderer, marks->priv->nodePopulation); g_signal_handler_disconnect(marks->priv->renderer, marks->priv->siz_sig); g_signal_handler_disconnect(marks->priv->renderer, marks->priv->dat_sig); g_object_unref(marks->priv->renderer); } marks->priv->renderer = renderer; if (renderer) { /* We ref the new given data. */ g_object_ref(renderer); /* Connect a signal on file change to remove everything. */ marks->priv->nodePopulation = g_signal_connect_swapped(renderer, "nodes::population-decrease", G_CALLBACK(_populationDecrease), (gpointer)marks); marks->priv->nodePosition = g_signal_connect_swapped(renderer, "nodes::position", G_CALLBACK(_setDirty), (gpointer)marks); marks->priv->nodeRender = g_signal_connect_swapped(renderer, "nodes::visibility", G_CALLBACK(_setDirty), (gpointer)marks); marks->priv->nodeMaterial = g_signal_connect_swapped(renderer, "element-notify::color", G_CALLBACK(_setDirty), (gpointer)marks); marks->priv->siz_sig = g_signal_connect_swapped(renderer, "element-size-changed", G_CALLBACK(_setDirty), (gpointer)marks); marks->priv->dat_sig = g_signal_connect_swapped(renderer, "notify::data", G_CALLBACK(onNotifyData), (gpointer)marks); } _setData(marks, (renderer) ? visu_node_array_renderer_getNodeArray(renderer) : (VisuNodeArray*)0); } static void onNotifyData(VisuGlExtMarks *marks, GParamSpec *pspec _U_, VisuNodeArrayRenderer *renderer) { _setData(marks, visu_node_array_renderer_getNodeArray(renderer)); } static void _populationDecrease(VisuGlExtMarks *marks, GArray *nodes) { guint i; GList *list, *rmList; struct MarkInfo_struct*mark; gboolean remove; gboolean invDirty, dirDirty; VisuMarkType type; DBG_fprintf(stderr, "Visu Marks: caught 'PopulationDecrease'" " signal (%p).\n", (gpointer)marks); invDirty = dirDirty = FALSE; /* Run through the mark list to get all nodeId and look into nodes to find if mark must be removed or not. */ DBG_fprintf(stderr, " | list contains %d elements\n", g_list_length(marks->priv->storedMarks)); list = marks->priv->storedMarks; while(list) { mark = (struct MarkInfo_struct*)list->data; DBG_fprintf(stderr, " | mark %p of type %d.\n", (gpointer)mark, mark->type); /* We remove mark if one of the node is in the list. */ remove = FALSE; rmList = list; for (i = 0; !remove && i < nodes->len; i++) remove = remove || (g_array_index(nodes, guint, i) == mark->idNode1) || (g_array_index(nodes, guint, i) == mark->idNode2) || (g_array_index(nodes, guint, i) == mark->idNode3); list = g_list_next(list); if (remove) { DBG_fprintf(stderr, " | delete mark %p of type %d.\n", (gpointer)mark, mark->type); type = markRemove(marks, rmList); if (type == MARK_HIGHLIGHT) dirDirty = TRUE; else invDirty = TRUE; } } if (invDirty) visu_gl_ext_setDirty(VISU_GL_EXT(marks), TRUE); if (dirDirty) visu_gl_ext_setDirty(VISU_GL_EXT(marks->priv->extNode), TRUE); } static void _setDirty(VisuGlExtMarks *marks) { visu_gl_ext_setDirty(VISU_GL_EXT(marks), TRUE); visu_gl_ext_setDirty(VISU_GL_EXT(marks->priv->extNode), TRUE); } /* static void updateListOnCameraChange(VisuGlView *view _U_, gpointer data _U_) */ /* { */ /* GList *tmpLst; */ /* struct MarkInfo_struct* mark; */ /* VisuGlExtMarks *marks; */ /* marks = (VisuGlExtMarks*)data; */ /* g_return_if_fail(data); */ /* for (tmpLst = mesureData->storedMarks; tmpLst; tmpLst = g_list_next(tmpLst)) */ /* { */ /* mark = (struct MarkInfo_struct*)(tmpLst->data); */ /* if (mark->type == PICK_MESURE_MARK_LINE) */ /* visu_interactive_class_getNodes2DCoordinates(mesureData->data, mark->nIds, g_list_length(mark->nodes), mark->coord, &mark->size); */ /* } */ /* marksDraw(marks, 0); */ /* } */ static gboolean onNodeSelection(VisuInteractive *inter _U_, VisuInteractivePick pick, VisuData *dataObj, VisuNode *node0, VisuNode *node1, VisuNode *node2, gpointer data) { gint nodeId; VisuMarkType type; gboolean set, status; GList *list; VisuGlExtMarks *marks = VISU_GL_EXT_MARKS(data); DBG_fprintf(stderr, "Visu Marks: get a 'node-selection' signals -> %d.\n", pick); switch (pick) { case PICK_DISTANCE: if (marks->priv->drawValues) { toggleDistance(marks, node1->number, node0->number, FALSE); putMark(dataObj, node1->number, node0->number, MARK_DISTANCE); g_signal_emit(G_OBJECT(marks), signals[MEASUREMENT_CHANGE_SIGNAL], 0, dataObj); visu_gl_ext_setDirty(VISU_GL_EXT(data), TRUE); } return TRUE; case PICK_ANGLE: if (marks->priv->drawValues) { toggleAngle(marks, node1->number, node2->number, node0->number, FALSE); g_signal_emit(G_OBJECT(marks), signals[MEASUREMENT_CHANGE_SIGNAL], 0, dataObj); visu_gl_ext_setDirty(VISU_GL_EXT(data), TRUE); } return TRUE; case PICK_UNREFERENCE_1: case PICK_UNREFERENCE_2: case PICK_REFERENCE_1: case PICK_REFERENCE_2: type = (pick == PICK_REFERENCE_1 || pick == PICK_UNREFERENCE_1)? MARK_BIG_SQUARE:MARK_SMALL_SQUARE; nodeId = -1; for (list = marks->priv->storedMarks; list; list = g_list_next(list)) if (((struct MarkInfo_struct*)list->data)->type == type) nodeId = ((struct MarkInfo_struct*)list->data)->idNode1; /* Erase previous one. */ if (nodeId >= 0) { removeDot(marks, nodeId, type); putMark(dataObj, -1, nodeId, type); } /* Add new one. */ if (pick == PICK_REFERENCE_1 || pick == PICK_REFERENCE_2) { addDot(marks, node0->number, type); putMark(dataObj, -1, node0->number, type); } visu_gl_ext_setDirty(VISU_GL_EXT(data), TRUE); return TRUE; case PICK_HIGHLIGHT: set = toggleHighlight(marks, node0->number, MARKS_STATUS_TOGGLE, &status); if (set) { g_object_notify_by_pspec(G_OBJECT(marks), properties[HIGHLIGHT_PROP]); if (marks->priv->hidingMode != HIDE_NONE) visu_node_masker_emitDirty(VISU_NODE_MASKER(marks)); visu_gl_ext_setDirty(VISU_GL_EXT(marks->priv->extNode), TRUE); } return TRUE; case PICK_INFORMATION: set = setInformation(marks, dataObj, node0->number); if (set) { g_signal_emit(G_OBJECT(marks), signals[MEASUREMENT_CHANGE_SIGNAL], 0, dataObj); visu_gl_ext_setDirty(VISU_GL_EXT(data), TRUE); } return TRUE; case PICK_SELECTED: default: return TRUE; } } /* Method that add/remove mark to the list of drawn marks. */ static void removeDot(VisuGlExtMarks *marks, guint nodeId, VisuMarkType type) { struct MarkInfo_struct *mark; GList *tmpLst; g_return_if_fail(marks); /* Look for the mark. */ for (tmpLst = marks->priv->storedMarks; tmpLst; tmpLst = g_list_next(tmpLst)) { mark = (struct MarkInfo_struct*)tmpLst->data; if (mark->type == type && mark->idNode1 == nodeId) { DBG_fprintf(stderr, "Visu Marks: found a dot mark.\n"); markRemove(marks, tmpLst); return; } } } static void addDot(VisuGlExtMarks *marks, guint nodeId, VisuMarkType type) { struct MarkInfo_struct *mark; g_return_if_fail((type == MARK_BIG_SQUARE || type == MARK_SMALL_SQUARE || type == MARK_HIGHLIGHT)); DBG_fprintf(stderr, "Visu Marks: add a new mark of type %d.\n", type); mark = markNew(type); mark->idNode1 = nodeId; marks->priv->storedMarks = g_list_prepend(marks->priv->storedMarks, (gpointer)mark); if (type == MARK_HIGHLIGHT && marks->priv->cachedHighlighted) { g_array_unref(marks->priv->cachedHighlighted); marks->priv->cachedHighlighted = (GArray*)0; } return; } static gboolean toggleDistance(VisuGlExtMarks *marks, guint nodeRefId, guint nodeId, gboolean set) { struct MarkInfo_struct *mark; GList *tmpLst; g_return_val_if_fail(marks, FALSE); /* Look for the mark. */ for (tmpLst = marks->priv->storedMarks; tmpLst; tmpLst = g_list_next(tmpLst)) { mark = (struct MarkInfo_struct*)tmpLst->data; if (mark->type == MARK_DISTANCE && ((mark->idNode1 == nodeRefId && mark->idNode2 == nodeId) || (mark->idNode2 == nodeRefId && mark->idNode1 == nodeId))) { DBG_fprintf(stderr, "Visu Marks: found a distance mark.\n"); if (!set) markRemove(marks, tmpLst); return set; } } /* Found none, create a new one. */ mark = markNew(MARK_DISTANCE); mark->idNode1 = nodeRefId; mark->idNode2 = nodeId; DBG_fprintf(stderr, "Visu Marks: add a distance mark.\n"); marks->priv->storedMarks = g_list_prepend(marks->priv->storedMarks, (gpointer)mark); return TRUE; } static gboolean toggleAngle(VisuGlExtMarks *marks, guint nodeRefId, guint nodeRef2Id, guint nodeId, gboolean set) { struct MarkInfo_struct *mark; GList *tmpLst; g_return_val_if_fail(marks, FALSE); /* Look for the mark. */ for (tmpLst = marks->priv->storedMarks; tmpLst; tmpLst = g_list_next(tmpLst)) { mark = (struct MarkInfo_struct*)tmpLst->data; if (mark->type == MARK_ANGLE && mark->idNode1 == nodeRefId && ((mark->idNode2 == nodeRef2Id && mark->idNode3 == nodeId) || (mark->idNode3 == nodeRef2Id && mark->idNode2 == nodeId))) { DBG_fprintf(stderr, "Visu Marks: found an angle mark.\n"); if (!set) markRemove(marks, tmpLst); return set; } } /* Found none, create a new one. */ mark = markNew(MARK_ANGLE); mark->idNode1 = nodeRefId; mark->idNode2 = nodeRef2Id; mark->idNode3 = nodeId; DBG_fprintf(stderr, "Visu Marks: add an angle mark.\n"); marks->priv->storedMarks = g_list_prepend(marks->priv->storedMarks, (gpointer)mark); return TRUE; } static gboolean toggleHighlight(VisuGlExtMarks *marks, guint nodeId, VisuGlExtMarksStatus status, gboolean *finalStatus) { struct MarkInfo_struct *mark; GList *tmpLst; g_return_val_if_fail(VISU_IS_GL_EXT_MARKS(marks), FALSE); /* Look for the mark. */ for (tmpLst = marks->priv->storedMarks; tmpLst; tmpLst = g_list_next(tmpLst)) { mark = (struct MarkInfo_struct*)tmpLst->data; if (mark->type == MARK_HIGHLIGHT && mark->idNode1 == nodeId) { DBG_fprintf(stderr, "Visu Marks: found a highlight mark (%d).\n", nodeId); if (status == MARKS_STATUS_TOGGLE || status == MARKS_STATUS_UNSET) markRemove(marks, tmpLst); if (finalStatus) *finalStatus = (status != MARKS_STATUS_TOGGLE && status != MARKS_STATUS_UNSET); /* Return if it has been changed. */ return (status == MARKS_STATUS_TOGGLE || status == MARKS_STATUS_UNSET); } } if (status == MARKS_STATUS_TOGGLE || status == MARKS_STATUS_SET) /* Found none, create a new one. */ addDot(marks, nodeId, MARK_HIGHLIGHT); if (finalStatus) *finalStatus = (status == MARKS_STATUS_TOGGLE || status == MARKS_STATUS_SET); /* Return if it has been changed. */ return (status == MARKS_STATUS_TOGGLE || status == MARKS_STATUS_SET); } /** * visu_gl_ext_marks_unHighlight: * @marks: a #VisuGlExtMarks object. * * Remove all highlight marks. * * Since: 3.8 * * Returns: TRUE if anything was highlighted. **/ gboolean visu_gl_ext_marks_unHighlight(VisuGlExtMarks *marks) { struct MarkInfo_struct *mark; GList *tmpLst, *rmLst; gboolean changed; g_return_val_if_fail(VISU_IS_GL_EXT_MARKS(marks), FALSE); /* Look for the mark. */ changed = FALSE; tmpLst = marks->priv->storedMarks; while (tmpLst) { mark = (struct MarkInfo_struct*)tmpLst->data; rmLst = tmpLst; tmpLst = g_list_next(tmpLst); if (mark->type == MARK_HIGHLIGHT) { markRemove(marks, rmLst); changed = TRUE; } } if (changed) { g_object_notify_by_pspec(G_OBJECT(marks), properties[HIGHLIGHT_PROP]); if (marks->priv->hidingMode != HIDE_NONE) visu_node_masker_emitDirty(VISU_NODE_MASKER(marks)); visu_gl_ext_setDirty(VISU_GL_EXT(marks->priv->extNode), TRUE); } return changed; } static gboolean setInformation(VisuGlExtMarks *marks, VisuData *dataObj, guint node) { VisuNodeInfo *infos; float min; GList *lst, *tmpLst, *tmpLst2; int i, n; gboolean redraw; float *dists; guint *ids; float xyz1[3], xyz2[3]; g_return_val_if_fail(marks, FALSE); DBG_fprintf(stderr, "Visu Marks: compute and print distances" " and angles for %d.\n", node); infos = _getDistanceList(dataObj, node, &min); lst = (GList*)0; redraw = FALSE; for (i = 0; infos[i].id != node; i+= 1) if (infos[i].dist < marks->priv->infoRange * min) { toggleDistance(marks, node, infos[i].id, TRUE); lst = g_list_prepend(lst, GINT_TO_POINTER(infos[i].id)); redraw = TRUE; } g_free(infos); n = g_list_length(lst); if (n > 1) { n = n * (n - 1 ) / 2; DBG_fprintf(stderr, "Visu Marks: there are %d angles at max.\n", n); ids = g_malloc(sizeof(guint) * n * 2); dists = g_malloc(sizeof(float) * n); i = 0; min = G_MAXFLOAT; for (tmpLst = lst; tmpLst; tmpLst = g_list_next(tmpLst)) for (tmpLst2 = tmpLst->next; tmpLst2; tmpLst2 = g_list_next(tmpLst2)) { ids[i * 2 + 0] = (guint)GPOINTER_TO_INT(tmpLst->data); ids[i * 2 + 1] = (guint)GPOINTER_TO_INT(tmpLst2->data); visu_data_getNodePosition(dataObj, visu_node_array_getFromId(VISU_NODE_ARRAY(dataObj), ids[i * 2 + 0]), xyz1); visu_data_getNodePosition(dataObj, visu_node_array_getFromId(VISU_NODE_ARRAY(dataObj), ids[i * 2 + 1]), xyz2); dists[i] = (xyz1[0] - xyz2[0]) * (xyz1[0] - xyz2[0]) + (xyz1[1] - xyz2[1]) * (xyz1[1] - xyz2[1]) + (xyz1[2] - xyz2[2]) * (xyz1[2] - xyz2[2]); DBG_fprintf(stderr, " | %d (%d %d) -> %g\n", i, ids[i * 2 + 0], ids[i * 2 + 1], dists[i]); min = MIN(min, dists[i]); i += 1; } for (i = 0; i < n; i++) if (dists[i] < (2.75f * min)) { DBG_fprintf(stderr, " | %d (%d %d) -> %g OK\n", i, ids[i * 2 + 0], ids[i * 2 + 1], dists[i]); toggleAngle(marks, node, ids[i * 2 + 0], ids[i * 2 + 1], TRUE); } g_free(ids); g_free(dists); } g_list_free(lst); return redraw; } /** * visu_gl_ext_marks_getActive: * @marks: a #VisuGlExtMarks object. * @nodeId: a node id. * * Retrieve if @nodeId is implied any measurement marks stored in @mark. * * Returns: TRUE if @nodeId participate to any mark (distance, * angle...). */ gboolean visu_gl_ext_marks_getActive(VisuGlExtMarks *marks, guint nodeId) { GList *list; struct MarkInfo_struct *mark; g_return_val_if_fail(marks, FALSE); for (list = marks->priv->storedMarks; list; list = g_list_next(list)) { mark = (struct MarkInfo_struct*)list->data; if ((mark->type == MARK_DISTANCE && mark->idNode1 == nodeId) || (mark->type == MARK_ANGLE && mark->idNode1 == nodeId)) return TRUE; } return FALSE; } /** * visu_gl_ext_marks_getHighlighted: * @marks: a #VisuGlExtMarks object ; * * @marks has a list of mark for some nodes. These marks are only * highlight marks. * * Returns: (element-type guint) (transfer none): list of * highlighted nodes (starting from 0), should not be freed. * * Since: 3.6 */ GArray* visu_gl_ext_marks_getHighlighted(const VisuGlExtMarks *marks) { GList *tmpLst; struct MarkInfo_struct* mark; g_return_val_if_fail(marks, (GArray*)0); if (!marks->priv->cachedHighlighted) { marks->priv->cachedHighlighted = g_array_new(FALSE, FALSE, sizeof(guint)); for (tmpLst = marks->priv->storedMarks; tmpLst; tmpLst = g_list_next(tmpLst)) { mark = (struct MarkInfo_struct*)(tmpLst->data); if (mark->type == MARK_HIGHLIGHT) g_array_append_val(marks->priv->cachedHighlighted, mark->idNode1); } } return marks->priv->cachedHighlighted; } /** * visu_gl_ext_marks_getHighlightStatus: * @marks: a #VisuGlExtMarks object. * @nodeId: a node id (ranging from 0). * * Nodes can be highlighted. * * Since: 3.7 * * Returns: TRUE if @nodeId has an highlight. **/ gboolean visu_gl_ext_marks_getHighlightStatus(VisuGlExtMarks *marks, guint nodeId) { GList *tmpLst; struct MarkInfo_struct* mark; g_return_val_if_fail(marks, FALSE); for (tmpLst = marks->priv->storedMarks; tmpLst; tmpLst = g_list_next(tmpLst)) { mark = (struct MarkInfo_struct*)(tmpLst->data); if (mark->type == MARK_HIGHLIGHT && mark->idNode1 == nodeId) return TRUE; } return FALSE; } /** * visu_gl_ext_marks_setHighlight: * @marks: a #VisuGlExtMarks object ; * @nodes: (element-type guint32): a set of node ids (0 started) ; * @status: changing command. * * @marks has a list of mark for some nodes. These marks can be * highlight (or distance, angles...). Depending on @status values, * the mark may be switch on or off. * * Returns: TRUE if redraw needed. * * Since: 3.6 */ gboolean visu_gl_ext_marks_setHighlight(VisuGlExtMarks *marks, GArray *nodes, VisuGlExtMarksStatus status) { gboolean redraw, res; guint i; g_return_val_if_fail(VISU_IS_GL_EXT_MARKS(marks), FALSE); if (!nodes || !nodes->len) return FALSE; DBG_fprintf(stderr, "Visu Marks: set highlight status of list to %d.\n", status); redraw = FALSE; for (i = 0; i < nodes->len; i++) { res = toggleHighlight(marks, g_array_index(nodes, guint, i), status, (gboolean*)0); DBG_fprintf(stderr, " | %d -> %d\n", g_array_index(nodes, guint, i), res); redraw = redraw || res; } DBG_fprintf(stderr, "Visu Marks: resulting redraw %d.\n", redraw); if (redraw) { g_object_notify_by_pspec(G_OBJECT(marks), properties[HIGHLIGHT_PROP]); if (marks->priv->hidingMode != HIDE_NONE) visu_node_masker_emitDirty(VISU_NODE_MASKER(marks)); visu_gl_ext_setDirty(VISU_GL_EXT(marks->priv->extNode), TRUE); } return redraw; } /** * visu_gl_ext_marks_setDrawValues: * @marks: a #VisuGlExtMarks object. * @status: a boolean. * * Change if the measurements are printed or not (distance length, or * angles...). * * Returns: TRUE if @marks is modified. */ gboolean visu_gl_ext_marks_setDrawValues(VisuGlExtMarks *marks, gboolean status) { g_return_val_if_fail(marks, FALSE); if (marks->priv->drawValues == status) return FALSE; marks->priv->drawValues = status; return TRUE; } /** * visu_gl_ext_marks_removeMeasures: * @marks: a #VisuGlExtMarks object. * @nodeId: a node id. * * This routine scans the @mark to remove all marks of distance or * angle where @nodeId is implied in. * * Returns: TRUE is @mark is changed. */ gboolean visu_gl_ext_marks_removeMeasures(VisuGlExtMarks *marks, gint nodeId) { gboolean redraw; GList *list, *tmpLst; struct MarkInfo_struct *mark; g_return_val_if_fail(marks, FALSE); DBG_fprintf(stderr, "Visu Marks: remove measures (%d).\n", nodeId); redraw = FALSE; for (list = marks->priv->storedMarks; list; list = tmpLst) { tmpLst = g_list_next(list); mark = (struct MarkInfo_struct*)list->data; if ((mark->type == MARK_DISTANCE || mark->type == MARK_ANGLE) && (nodeId < 0 || mark->idNode1 == (guint)nodeId)) { markRemove(marks, list); redraw = TRUE; } } if (!redraw) return FALSE; visu_gl_ext_setDirty(VISU_GL_EXT(marks), TRUE); return TRUE; } /** * visu_gl_ext_marks_setInfos: * @marks: a #VisuGlExtMarks object. * @nodeId: a node id. * @status: a boolean. * * Depending on @status, it removes all measurements from @nodeId or * it calculate all first neighbour relations of @nodeId. * * Return: TRUE if @marks is changed. */ gboolean visu_gl_ext_marks_setInfos(VisuGlExtMarks *marks, guint nodeId, gboolean status) { g_return_val_if_fail(VISU_IS_GL_EXT_MARKS(marks), FALSE); g_return_val_if_fail(marks->priv->renderer, FALSE); DBG_fprintf(stderr, "Visu Marks: set info for node %d.\n", nodeId); if (status) { if (setInformation(marks, VISU_DATA(visu_node_array_renderer_getNodeArray(marks->priv->renderer)), nodeId)) { visu_gl_ext_setDirty(VISU_GL_EXT(marks), TRUE); return TRUE; } } else return visu_gl_ext_marks_removeMeasures(marks, nodeId); return FALSE; } /****************************/ /* OpenGL drawing routines. */ /****************************/ static void drawMarkDot(VisuData *data, guint nodeId, VisuMarkType type) { VisuNode *node; float xyz[3]; VisuElement *ele; node = visu_node_array_getFromId(VISU_NODE_ARRAY(data), nodeId); g_return_if_fail(node); /* If the node is masked, then we don't draw the dot. */ if (!node->rendered) return; /* If the element is masked, then we don't draw the dot. */ ele = visu_node_array_getElement(VISU_NODE_ARRAY(data), node); if (!visu_element_getRendered(ele)) return; DBG_fprintf(stderr, "Visu Mark: draw a mark (%d) on node %d.\n", (int)type, node->number); visu_data_getNodePosition(data, node, xyz); switch (type) { case MARK_BIG_SQUARE: glRasterPos3f(xyz[0], xyz[1], xyz[2]); glDrawPixels(MARK_BIG_SQUARE_SIZE, MARK_BIG_SQUARE_SIZE, GL_RGBA, GL_UNSIGNED_BYTE, markBigSquare); break; case MARK_SMALL_SQUARE: glRasterPos3f(xyz[0], xyz[1], xyz[2]); glDrawPixels(MARK_SMALL_SQUARE_SIZE, MARK_SMALL_SQUARE_SIZE, GL_RGBA, GL_UNSIGNED_BYTE, markSmallSquare); break; default: break; } } static void drawMarkHighlight(VisuData *data, guint nodeId, VisuGlView *view, VisuNodeArrayRenderer *renderer) { VisuNode *node; float xyz[3]; VisuElement *ele; int nlat; float eleSize; GLUquadricObj *obj; VisuElementRenderer *eleRenderer; node = visu_node_array_getFromId(VISU_NODE_ARRAY(data), nodeId); g_return_if_fail(node); /* If the node is masked, then we don't draw the dot. */ if (!node->rendered) return; /* If the element is masked, then we don't draw the dot. */ ele = visu_node_array_getElement(VISU_NODE_ARRAY(data), node); if (!visu_element_getRendered(ele)) return; DBG_fprintf(stderr, "Visu Mark: draw a mark highlight on node %d.\n", node->number); visu_data_getNodePosition(data, node, xyz); g_return_if_fail(view); obj = gluNewQuadric(); eleRenderer = visu_node_array_renderer_get(renderer, ele); visu_element_renderer_colorize(eleRenderer, VISU_ELEMENT_RENDERER_HIGHLIGHT_SEMI); eleSize = visu_element_renderer_getExtent(eleRenderer); nlat = visu_gl_view_getDetailLevel(view, eleSize * highlightFactor); glPushMatrix(); glTranslated(xyz[0], xyz[1], xyz[2]); gluSphere(obj, (double)eleSize * highlightFactor, 2 * nlat, 2 * nlat); glPopMatrix(); gluDeleteQuadric(obj); } static void drawMarkDistance(VisuData *data, guint nodeRefId, guint nodeId, VisuMarkType type _U_) { VisuNode *nodeRef; VisuNode *node; float xyzRef[3], xyz[3]; VisuElement *ele; nodeRef = visu_node_array_getFromId(VISU_NODE_ARRAY(data), nodeRefId); node = visu_node_array_getFromId(VISU_NODE_ARRAY(data), nodeId); g_return_if_fail(node && nodeRef); /* If one of the node is masked, then we don't draw the distance. */ if (!nodeRef->rendered || !node->rendered) return; /* If one of the element is masked, then we don't draw the distance. */ ele = visu_node_array_getElement(VISU_NODE_ARRAY(data), nodeRef); if (!visu_element_getRendered(ele)) return; ele = visu_node_array_getElement(VISU_NODE_ARRAY(data), node); if (!visu_element_getRendered(ele)) return; visu_data_getNodePosition(data, nodeRef, xyzRef); visu_data_getNodePosition(data, node, xyz); visu_gl_drawDistance(xyzRef, xyz, TRUE); } static void drawMarkAngle(VisuData *data, guint nodeRefId, guint nodeRef2Id, guint nodeId, guint id) { VisuNode *nodeRef, *nodeRef2, *node; float xyzRef[3], xyzRef2[3], xyz[3]; VisuElement *ele; nodeRef = visu_node_array_getFromId(VISU_NODE_ARRAY(data), nodeRefId); nodeRef2 = visu_node_array_getFromId(VISU_NODE_ARRAY(data), nodeRef2Id); node = visu_node_array_getFromId(VISU_NODE_ARRAY(data), nodeId); g_return_if_fail(node && nodeRef && nodeRef2); /* If one of the node is masked, then we don't draw the angle. */ if (!nodeRef->rendered || !nodeRef2->rendered || !node->rendered) return; /* If one of the element is masked, then we don't draw the angle. */ ele = visu_node_array_getElement(VISU_NODE_ARRAY(data), nodeRef); if (!visu_element_getRendered(ele)) return; ele = visu_node_array_getElement(VISU_NODE_ARRAY(data), nodeRef2); if (!visu_element_getRendered(ele)) return; ele = visu_node_array_getElement(VISU_NODE_ARRAY(data), node); if (!visu_element_getRendered(ele)) return; visu_data_getNodePosition(data, nodeRef, xyzRef); visu_data_getNodePosition(data, nodeRef2, xyzRef2); visu_data_getNodePosition(data, node, xyz); DBG_fprintf(stderr, "Visu PickMesure: draw an angle mark on nodes %d/%d/%d.\n", nodeRef->number, nodeRef2->number, node->number); visu_gl_drawAngle(xyzRef, xyzRef2, xyz, id, TRUE); } /* Calculate the node vertices coordinates (contained in the array nodevertices), from node coordinates (xn,yn) */ static void defineNodeVertices(int nVert, double radius, double xn, double yn, double *nodeVertices) { int i; for (i = 0; i < nVert; i++) { nodeVertices[2 * i] = (xn + radius * (cos (((2 * G_PI * i) / nVert)))); nodeVertices[2 * i + 1] = (yn + radius * (sin (((2 * G_PI * i) / nVert)))); } } /* Add node vertices to vertices array, from position i+1 */ static void addVerticesToGlobalArray(int nVert, double *nodeVertices, double *vertices, int i) { int j; int k = 0; for (j = (i * 2) * nVert; j < (i * 2) * nVert + (nVert * 2); j += 2) { vertices[j] = nodeVertices[k]; vertices[j + 1] = nodeVertices[k + 1]; k += 2; } } static void drawMarkLine(VisuData *data _U_, GLfloat *coord, guint size) { #define NEWLINE 1 #define NEWNODE 2 int i = 0, j; int elem = 0; int nNodes, nTotalVert; /***********************************/ /* values must be selected by user */ int nVert = 30; double radius = 30; /***********************************/ double *vertices, *nodeVertices, *verticesKept; double link[2] = {0}; double distance; gboolean visible = TRUE; gboolean li = FALSE; nNodes = size / 2; nTotalVert = nNodes * nVert; glMatrixMode(GL_PROJECTION); glPushMatrix(); glLoadIdentity(); gluOrtho2D(0.0, 600, 0., 600); glMatrixMode(GL_MODELVIEW); glPushMatrix(); glLoadIdentity(); vertices = g_malloc(sizeof(double) * (nTotalVert * 2)); nodeVertices = g_malloc(sizeof(double) * (nVert * 2)); verticesKept = g_malloc(sizeof(double) * (nTotalVert * 2) + sizeof(int) * nTotalVert * 2); /* For each node, compute and add its vertices coordinates (nodeVertices) to the vertices global array (vertices) */ for (i = 0; i < nNodes; i++){ defineNodeVertices(nVert, radius, coord[2 * i], coord[2 * i + 1], nodeVertices); addVerticesToGlobalArray(nVert, nodeVertices, vertices, i); } g_free(nodeVertices); verticesKept[elem] = NEWNODE; elem++; /* For each vertex */ for (i = 0; i < nTotalVert; i++){ /* We notify with a marker each new node */ if (i / nVert != (i - 1) / nVert){ verticesKept[elem] = NEWNODE; elem++; } /* For each node */ for (j = 0; j < nNodes; j++){ /* If vertex i doesn't belong to node j */ if (j != i / nVert){ /* Distance between vertex i and node j */ distance = sqrt( (pow ((coord[2 * j + 1] - vertices[2 * i + 1]), 2)) + (pow ((coord[2 * j] - vertices[2 * i]), 2)) ); if (distance < radius) visible = FALSE; } } if (visible){ verticesKept[elem] = vertices[2 * i]; verticesKept[elem + 1] = vertices[2 * i + 1]; elem += 2; } else { if (verticesKept[elem - 1] != NEWLINE){ verticesKept[elem] = NEWLINE; elem++; } visible = TRUE; } } glLineWidth(4.0); glColor3f(1.0, 1.0, 1.0); i = 0; while (i < elem){ if (verticesKept[i] == NEWLINE) i++; else if (verticesKept[i] == NEWNODE){ i++; if (verticesKept[i] != NEWNODE && verticesKept[i] != NEWLINE){ link[0] = verticesKept[i]; link[1] = verticesKept[i + 1]; li = TRUE; } else { li = FALSE; while (verticesKept[i] == NEWNODE || verticesKept[i] == NEWLINE) i++; } } else { glBegin(GL_LINES); while (verticesKept[i + 2] != NEWNODE && verticesKept[i + 2] != NEWLINE && i + 2 < elem){ glVertex2f(verticesKept[i], verticesKept[i + 1]); glVertex2f(verticesKept[i + 2], verticesKept[i + 3]); i += 2; } if (i + 2 >= elem){ if (li){ glVertex2f(verticesKept[i], verticesKept[i + 1]); glVertex2f(link[0], link[1]); } i = elem; } else if (verticesKept[i + 2] == NEWLINE) i += 3; else if (verticesKept[i + 2] == NEWNODE){ if (li){ glVertex2f(verticesKept[i], verticesKept[i + 1]); glVertex2f(link[0], link[1]); } i += 2; } glEnd(); } } g_free(verticesKept); g_free(vertices); glPopMatrix(); glMatrixMode(GL_PROJECTION); glPopMatrix(); glMatrixMode(GL_MODELVIEW); } static void putMark(VisuData *data, guint nodeRefId, guint nodeId, VisuMarkType type) { float centre[3]; visu_box_getCentre(visu_boxed_getBox(VISU_BOXED(data)), centre); DBG_fprintf(stderr, "Visu Marks: draw directly a distance on front buffer.\n"); glDrawBuffer(GL_FRONT); glPushAttrib(GL_ENABLE_BIT); glDisable(GL_DEPTH_TEST); glDisable(GL_LIGHTING); glDisable(GL_FOG); glEnable(GL_BLEND); glBlendFunc(GL_ONE_MINUS_DST_COLOR, GL_ONE_MINUS_SRC_COLOR); glPushMatrix(); glTranslated(-centre[0], -centre[1], -centre[2]); switch (type) { case MARK_BIG_SQUARE: case MARK_SMALL_SQUARE: drawMarkDot(data, nodeId, type); break; case MARK_DISTANCE: drawMarkDistance(data, nodeRefId, nodeId, type); break; default: g_warning("No direct drawing available for this type."); } glPopMatrix(); glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA); glPopAttrib(); glDrawBuffer(GL_BACK); glFlush(); } /*************************/ /* Resources management. */ /*************************/ static void exportResources(GString *data, VisuData *dataObj _U_) { visu_config_file_exportComment(data, DESC_RESOURCE_FACTOR); visu_config_file_exportEntry(data, FLAG_RESOURCE_FACTOR, NULL, "%f", highlightFactor); visu_config_file_exportComment(data, ""); } /****************************/ /* List drawing management. */ /****************************/ static void visu_gl_ext_marks_rebuild(VisuGlExt *ext) { visu_gl_text_rebuildFontList(); visu_gl_ext_marks_draw(ext); } static void visu_gl_ext_marks_draw(VisuGlExt *ext) { VisuGlExtMarks *marks = VISU_GL_EXT_MARKS(ext); struct MarkInfo_struct *mark; GList *tmpLst; guint id; VisuData *dataObj; visu_gl_ext_setDirty(ext, FALSE); DBG_fprintf(stderr, "Visu Marks: update the list %p" " of all marks.\n", (gpointer)marks->priv->storedMarks); glDeleteLists(visu_gl_ext_getGlList(ext), 1); if (!marks->priv->storedMarks || !marks->priv->renderer) return; visu_gl_text_initFontList(); id = 0; /* Draw the colour inverse list. */ visu_gl_ext_startDrawing(ext); glEnable(GL_DEPTH_TEST); glClear(GL_DEPTH_BUFFER_BIT); /* glDisable(GL_DEPTH_TEST); */ glDisable(GL_LIGHTING); glDisable(GL_FOG); glDisable(GL_CULL_FACE); /* glDisable(GL_DITHER); */ glEnable(GL_BLEND); glBlendFunc(GL_ONE_MINUS_DST_COLOR, GL_ONE_MINUS_SRC_COLOR); dataObj = VISU_DATA(visu_node_array_renderer_getNodeArray(marks->priv->renderer)); for (tmpLst = marks->priv->storedMarks; tmpLst; tmpLst = g_list_next(tmpLst)) { mark = (struct MarkInfo_struct*)tmpLst->data; DBG_fprintf(stderr, " | draw mark of type %d.\n", mark->type); switch (mark->type) { case MARK_BIG_SQUARE: case MARK_SMALL_SQUARE: drawMarkDot(dataObj, mark->idNode1, mark->type); break; case MARK_DISTANCE: drawMarkDistance(dataObj, mark->idNode1, mark->idNode2, mark->type); break; case MARK_LINE: drawMarkLine(dataObj, mark->coord, mark->size); break; case MARK_ANGLE: drawMarkAngle(dataObj, mark->idNode1, mark->idNode2, mark->idNode3, id); id += 1; break; default: break; } } glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA); visu_gl_ext_completeDrawing(ext); } /******************************************/ /* XML files for marks and other exports. */ /******************************************/ /** * visu_gl_ext_marks_getMeasurementLabels: * @marks: a #VisuGlExtMarks object. * * Exports as a string the ids of nodes for measurement marks. * * Since: 3.6 * * Returns: a newly allocated string. */ gchar* visu_gl_ext_marks_getMeasurementLabels(VisuGlExtMarks *marks) { GString *str; GList *tmpLst; struct MarkInfo_struct *mark; guint i; g_return_val_if_fail(VISU_IS_GL_EXT_MARKS(marks), (gchar*)0); str = g_string_new("#"); /* Look for the mark. */ for (tmpLst = marks->priv->storedMarks, i = 0; tmpLst && i < 6; tmpLst = g_list_next(tmpLst), i += 1) { mark = (struct MarkInfo_struct*)tmpLst->data; if (mark->type == MARK_DISTANCE) g_string_append_printf(str, " %4d-%4d", mark->idNode1 + 1, mark->idNode2 + 1); else if (mark->type == MARK_ANGLE) g_string_append_printf(str, " %4d-%4d-%4d", mark->idNode3 + 1, mark->idNode1 + 1, mark->idNode2 + 1); } if (!tmpLst) g_string_append(str, "\n"); else g_string_append(str, " (truncated list)\n"); return g_string_free(str, FALSE); } /** * visu_gl_ext_marks_getMeasurementStrings: * @marks: a #VisuGlExtMarks object. * * Exports as a string all measurements stored in @marks. * * Since: 3.6 * * Returns: a newly allocated string. */ gchar* visu_gl_ext_marks_getMeasurementStrings(VisuGlExtMarks *marks) { VisuData *dataObj; GString *str; GList *tmpLst; struct MarkInfo_struct *mark; float posSelect[3], posRef1[3], posRef2[3], dx, dy, dz, dr; float dx1, dy1, dz1, dx2, dy2, dz2, dr1, dr2, ang; VisuNode *nodes[3]; gchar *lbl; gboolean export; guint i; g_return_val_if_fail(VISU_IS_GL_EXT_MARKS(marks) && marks->priv->renderer, (gchar*)0); str = g_string_new(" "); export = FALSE; dataObj = VISU_DATA(visu_node_array_renderer_getNodeArray(marks->priv->renderer)); /* Look for the mark. */ for (tmpLst = marks->priv->storedMarks, i = 0; tmpLst && i < 6; tmpLst = g_list_next(tmpLst), i += 1) { mark = (struct MarkInfo_struct*)tmpLst->data; nodes[0] = visu_node_array_getFromId(VISU_NODE_ARRAY(dataObj), mark->idNode1); nodes[1] = visu_node_array_getFromId(VISU_NODE_ARRAY(dataObj), mark->idNode2); nodes[2] = visu_node_array_getFromId(VISU_NODE_ARRAY(dataObj), mark->idNode3); if (mark->type == MARK_DISTANCE) { DBG_fprintf(stderr, "Visu Marks: export this distance.\n"); visu_data_getNodePosition(dataObj, nodes[0], posRef1); visu_data_getNodePosition(dataObj, nodes[1], posSelect); dx = posSelect[0] - posRef1[0]; dy = posSelect[1] - posRef1[1]; dz = posSelect[2] - posRef1[2]; dr = sqrt(dx*dx + dy*dy + dz*dz); g_string_append_printf(str, " %12.6g", dr); export = TRUE; } else if (mark->type == MARK_ANGLE) { DBG_fprintf(stderr, "Visu Marks: export this angle.\n"); visu_data_getNodePosition(dataObj, nodes[0], posRef1); visu_data_getNodePosition(dataObj, nodes[1], posRef2); visu_data_getNodePosition(dataObj, nodes[2], posSelect); dx1 = posSelect[0] - posRef1[0]; dy1 = posSelect[1] - posRef1[1]; dz1 = posSelect[2] - posRef1[2]; dx2 = posRef2[0] - posRef1[0]; dy2 = posRef2[1] - posRef1[1]; dz2 = posRef2[2] - posRef1[2]; dr1 = sqrt(dx1*dx1 + dy1*dy1 + dz1*dz1); dr2 = sqrt(dx2*dx2 + dy2*dy2 + dz2*dz2); ang = acos((dx2*dx1+dy2*dy1+dz2*dz1)/(dr2*dr1))/TOOL_PI180; g_string_append_printf(str, " %12.6g", ang); export = TRUE; } } if (!export) { g_string_free(str, TRUE); return (gchar*)0; } if (VISU_IS_DATA_LOADABLE(dataObj)) { g_object_get(dataObj, "label", &lbl, NULL); g_string_append_printf(str, " # %s\n", lbl); g_free(lbl); } return g_string_free(str, FALSE); } /** * visu_gl_ext_marks_getHidingMode: * @marks: a #VisuGlExtMarks object. * * Retrieves the hiding mode of @marks, see #VisuGlExtMarksHidingModes. * * Since: 3.8 * * Returns: a #VisuGlExtMarksHidingModes value. **/ VisuGlExtMarksHidingModes visu_gl_ext_marks_getHidingMode(const VisuGlExtMarks *marks) { g_return_val_if_fail(VISU_IS_GL_EXT_MARKS(marks), HIDE_NONE); return marks->priv->hidingMode; } /** * visu_gl_ext_marks_setHidingMode: * @marks: a #VisuGlExtMarks object. * @mode: a #VisuGlExtMarksHidingModes value. * * Change the hiding mode of @marks. * * Returns: TRUE if value is actually changed. **/ gboolean visu_gl_ext_marks_setHidingMode(VisuGlExtMarks *marks, VisuGlExtMarksHidingModes mode) { g_return_val_if_fail(VISU_IS_GL_EXT_MARKS(marks), FALSE); DBG_fprintf(stderr, "Visu Ext Marks: setting hiding mode to %d (%d).\n", mode, marks->priv->hidingMode); if (marks->priv->hidingMode == mode) return FALSE; marks->priv->hidingMode = mode; g_object_notify_by_pspec(G_OBJECT(marks), properties[HIDING_PROP]); visu_node_masker_emitDirty(VISU_NODE_MASKER(marks)); return TRUE; } static gboolean _maskApply(const VisuNodeMasker *self, VisuNodeArray *array) { VisuGlExtMarks *marks; gboolean redraw; GArray *ids; guint i; guint nHl, *hl, j; guint min, max; VisuNodeArrayIter iter; gboolean hide; g_return_val_if_fail(VISU_IS_GL_EXT_MARKS(self), FALSE); marks = VISU_GL_EXT_MARKS(self); if (marks->priv->hidingMode == HIDE_NONE) return FALSE; redraw = FALSE; ids = visu_gl_ext_marks_getHighlighted(marks); if (marks->priv->hidingMode == HIDE_NON_HIGHLIGHT) { /* We switch off all nodes except the highlighted ones. To avoid to run the list of highlighted nodes to many times, we create a temporary array and store the min and max indexes. */ if (!ids || !ids->len) return FALSE; visu_node_array_iter_new(array, &iter); hl = g_malloc(sizeof(gint) * ids->len); nHl = 0; min = iter.nAllStoredNodes; max = 0; for (i = 0; i < ids->len; i++) { hl[nHl] = g_array_index(ids, guint, i); min = MIN(min, hl[nHl]); max = MAX(max, hl[nHl]); nHl += 1; } for (visu_node_array_iterStart(array, &iter); iter.node; visu_node_array_iterNext(array, &iter)) if (iter.node->number >= min && iter.node->number <= max) { hide = TRUE; for (j = 0; hide && j < nHl; j++) hide = (iter.node->number != hl[j]); if (hide) redraw = visu_node_setVisibility(iter.node, FALSE) || redraw; } else redraw = visu_node_setVisibility(iter.node, FALSE) || redraw; g_free(hl); } else if (marks->priv->hidingMode == HIDE_HIGHLIGHT) for (i = 0; i < ids->len; i++) { redraw = visu_node_setVisibility (visu_node_array_getFromId(array, g_array_index(ids, guint, i)), FALSE) || redraw; } return redraw; } /** * visu_data_getDistanceList: * @data: a #VisuData object ; * @nodeId: a node id. * @minVal: a location for a float. * * This routine creates an array of #VisuNodeInfo, storing for each * node its node id and its distance to @nodeId. The periodicity is * NOT taken into account. The array is not distance sorted, but if * @minVal is provided, it will contain the minimal distance between * @nodeId and the other nodes. * * Since: 3.5 * * Returns: an array of #VisuNodeInfo of size the number of nodes. It * is terminated by @nodeId value itself. */ static VisuNodeInfo* _getDistanceList(VisuData *data, guint nodeId, float *minVal) { VisuNodeInfo *infos; int nNodes; VisuNodeArrayIter iter; VisuNode *nodeRef; float xyz[3], xyzRef[3], min; if (minVal) *minVal = -1.f; g_return_val_if_fail(VISU_IS_DATA(data), (VisuNodeInfo*)0); DBG_fprintf(stderr, "Visu Data: get distance list for node %d.\n", nodeId); nodeRef = visu_node_array_getFromId(VISU_NODE_ARRAY(data), nodeId); g_return_val_if_fail(nodeRef, (VisuNodeInfo*)0); nNodes = visu_node_array_getNNodes(VISU_NODE_ARRAY(data)); infos = g_malloc(sizeof(VisuNodeInfo) * nNodes); visu_data_getNodePosition(data, nodeRef, xyzRef); min = G_MAXFLOAT; nNodes = 0; visu_node_array_iter_new(VISU_NODE_ARRAY(data), &iter); for (visu_node_array_iterStart(VISU_NODE_ARRAY(data), &iter); iter.node; visu_node_array_iterNextVisible(VISU_NODE_ARRAY(data), &iter)) { infos[nNodes].id = iter.node->number; visu_data_getNodePosition(data, iter.node, xyz); infos[nNodes].dist = (xyz[0] - xyzRef[0]) * (xyz[0] - xyzRef[0]) + (xyz[1] - xyzRef[1]) * (xyz[1] - xyzRef[1]) + (xyz[2] - xyzRef[2]) * (xyz[2] - xyzRef[2]); if (infos[nNodes].dist > 0.0001f) { min = MIN(min, infos[nNodes].dist); nNodes += 1; } } infos[nNodes].id = nodeId; DBG_fprintf(stderr, " | min value = %g.\n", min); if (minVal) *minVal = min; return infos; } /* */ /* Known elements. */ #define PICK_PARSER_ELEMENT_PICK "pick" #define PICK_PARSER_ELEMENT_NODE "node" #define PICK_PARSER_ELEMENT_DIST "distance" #define PICK_PARSER_ELEMENT_ANGL "angle" /* Known attributes. */ #define PICK_PARSER_ATTRIBUTES_MODE "info-mode" #define PICK_PARSER_ATTRIBUTES_INFO "info-data" #define PICK_PARSER_ATTRIBUTES_ID "id" #define PICK_PARSER_ATTRIBUTES_REF "ref" #define PICK_PARSER_ATTRIBUTES_REF2 "ref2" #define PICK_PARSER_ATTRIBUTES_HLT "highlight" static gboolean startPick; static VisuGlExtInfosDrawId mode; static guint info; /* This method is called for every element that is parsed. The user_data must be a GList of _pick_xml. When a 'surface' element, a new struct instance is created and prepend in the list. When 'hidden-by-planes' or other qualificative elements are found, the first surface of the list is modified accordingly. */ static void pickXML_element(GMarkupParseContext *context _U_, const gchar *element_name, const gchar **attribute_names, const gchar **attribute_values, gpointer user_data, GError **error) { GList **pickList; int i, n; guint val, val2, val3; gboolean highlight; g_return_if_fail(user_data); pickList = (GList **)user_data; DBG_fprintf(stderr, "Pick parser: found '%s' element.\n", element_name); if (!strcmp(element_name, PICK_PARSER_ELEMENT_PICK)) { /* Initialise the pickList. */ if (*pickList) { g_set_error(error, G_MARKUP_ERROR, G_MARKUP_ERROR_PARSE, _("DTD error: element '%s' should appear only once."), PICK_PARSER_ELEMENT_PICK); return; } *pickList = (GList*)0; startPick = TRUE; /* Should have 2 mandatory attributes. */ for (i = 0; attribute_names[i]; i++) { if (!strcmp(attribute_names[i], PICK_PARSER_ATTRIBUTES_MODE)) { if (!strcmp(attribute_values[i], "never")) mode = DRAW_NEVER; else if (!strcmp(attribute_values[i], "selected")) mode = DRAW_SELECTED; else if (!strcmp(attribute_values[i], "always")) mode = DRAW_ALWAYS; else { g_set_error(error, G_MARKUP_ERROR, G_MARKUP_ERROR_PARSE, _("DTD error: attribute '%s' has an unknown value '%s'."), PICK_PARSER_ATTRIBUTES_MODE, attribute_values[i]); return; } } else if (!strcmp(attribute_names[i], PICK_PARSER_ATTRIBUTES_INFO)) { n = sscanf(attribute_values[i], "%u", &info); if (n != 1 || info < 1) { g_set_error(error, G_MARKUP_ERROR, G_MARKUP_ERROR_PARSE, _("DTD error: attribute '%s' has an unknown value '%s'."), PICK_PARSER_ATTRIBUTES_INFO, attribute_values[i]); return; } } } } else if (!strcmp(element_name, PICK_PARSER_ELEMENT_NODE)) { if (!startPick) { g_set_error(error, G_MARKUP_ERROR, G_MARKUP_ERROR_INVALID_CONTENT, _("DTD error: parent element '%s' of element '%s' is missing."), PICK_PARSER_ELEMENT_PICK, PICK_PARSER_ELEMENT_NODE); return; } highlight = FALSE; /* We parse the attributes. */ for (i = 0; attribute_names[i]; i++) { if (!strcmp(attribute_names[i], PICK_PARSER_ATTRIBUTES_ID)) { n = sscanf(attribute_values[i], "%u", &val); if (n != 1) { g_set_error(error, G_MARKUP_ERROR, G_MARKUP_ERROR_PARSE, _("DTD error: attribute '%s' has an unknown value '%s'."), PICK_PARSER_ATTRIBUTES_ID, attribute_values[i]); return; } } else if (!strcmp(attribute_names[i], PICK_PARSER_ATTRIBUTES_HLT)) highlight = (!strcmp(attribute_values[i], "yes") || !strcmp(attribute_values[i], "Yes")); } if (highlight) *pickList = g_list_prepend(*pickList, GINT_TO_POINTER(PICK_HIGHLIGHT)); else *pickList = g_list_prepend(*pickList, GINT_TO_POINTER(PICK_SELECTED)); *pickList = g_list_prepend(*pickList, GINT_TO_POINTER(val)); } else if (!strcmp(element_name, PICK_PARSER_ELEMENT_DIST)) { if (!startPick) { g_set_error(error, G_MARKUP_ERROR, G_MARKUP_ERROR_INVALID_CONTENT, _("DTD error: parent element '%s' of element '%s' is missing."), PICK_PARSER_ELEMENT_PICK, PICK_PARSER_ELEMENT_DIST); return; } /* We parse the attributes. */ for (i = 0; attribute_names[i]; i++) { if (!strcmp(attribute_names[i], PICK_PARSER_ATTRIBUTES_ID)) { n = sscanf(attribute_values[i], "%u", &val); if (n != 1) { g_set_error(error, G_MARKUP_ERROR, G_MARKUP_ERROR_PARSE, _("DTD error: attribute '%s' has an unknown value '%s'."), PICK_PARSER_ATTRIBUTES_ID, attribute_values[i]); return; } } else if (!strcmp(attribute_names[i], PICK_PARSER_ATTRIBUTES_REF)) { n = sscanf(attribute_values[i], "%u", &val2); if (n != 1) { g_set_error(error, G_MARKUP_ERROR, G_MARKUP_ERROR_PARSE, _("DTD error: attribute '%s' has an unknown value '%s'."), PICK_PARSER_ATTRIBUTES_REF, attribute_values[i]); return; } } } *pickList = g_list_prepend(*pickList, GINT_TO_POINTER(PICK_DISTANCE)); *pickList = g_list_prepend(*pickList, GINT_TO_POINTER(val2)); *pickList = g_list_prepend(*pickList, GINT_TO_POINTER(val)); } else if (!strcmp(element_name, PICK_PARSER_ELEMENT_ANGL)) { if (!startPick) { g_set_error(error, G_MARKUP_ERROR, G_MARKUP_ERROR_INVALID_CONTENT, _("DTD error: parent element '%s' of element '%s' is missing."), PICK_PARSER_ELEMENT_PICK, PICK_PARSER_ELEMENT_ANGL); return; } /* We parse the attributes. */ for (i = 0; attribute_names[i]; i++) { if (!strcmp(attribute_names[i], PICK_PARSER_ATTRIBUTES_ID)) { n = sscanf(attribute_values[i], "%u", &val); if (n != 1) { g_set_error(error, G_MARKUP_ERROR, G_MARKUP_ERROR_PARSE, _("DTD error: attribute '%s' has an unknown value '%s'."), PICK_PARSER_ATTRIBUTES_ID, attribute_values[i]); return; } } else if (!strcmp(attribute_names[i], PICK_PARSER_ATTRIBUTES_REF)) { n = sscanf(attribute_values[i], "%u", &val2); if (n != 1) { g_set_error(error, G_MARKUP_ERROR, G_MARKUP_ERROR_PARSE, _("DTD error: attribute '%s' has an unknown value '%s'."), PICK_PARSER_ATTRIBUTES_REF, attribute_values[i]); return; } } else if (!strcmp(attribute_names[i], PICK_PARSER_ATTRIBUTES_REF2)) { n = sscanf(attribute_values[i], "%u", &val3); if (n != 1) { g_set_error(error, G_MARKUP_ERROR, G_MARKUP_ERROR_PARSE, _("DTD error: attribute '%s' has an unknown value '%s'."), PICK_PARSER_ATTRIBUTES_REF2, attribute_values[i]); return; } } } *pickList = g_list_prepend(*pickList, GINT_TO_POINTER(PICK_ANGLE)); *pickList = g_list_prepend(*pickList, GINT_TO_POINTER(val3)); *pickList = g_list_prepend(*pickList, GINT_TO_POINTER(val2)); *pickList = g_list_prepend(*pickList, GINT_TO_POINTER(val)); } else if (startPick) { /* We silently ignore the element if pickList is unset, but raise an error if pickList has been set. */ g_set_error(error, G_MARKUP_ERROR, G_MARKUP_ERROR_UNKNOWN_ELEMENT, _("Unexpected element '%s'."), element_name); } } /* Check when a element is closed that everything required has been set. */ static void pickXML_end(GMarkupParseContext *context _U_, const gchar *element_name, gpointer user_data _U_, GError **error _U_) { if (!strcmp(element_name, PICK_PARSER_ELEMENT_PICK)) startPick = FALSE; } /* What to do when an error is raised. */ static void pickXML_error(GMarkupParseContext *context _U_, GError *error, gpointer user_data) { DBG_fprintf(stderr, "Pick parser: error raised '%s'.\n", error->message); g_return_if_fail(user_data); /* We free the current list of pick. */ g_list_free(*(GList**)user_data); } /** * visu_gl_ext_marks_parseXMLFile: * @marks: a #VisuGlExtMarks object. * @filename: a location to save to. * @infos: (element-type guint32) (out): a location to a #GList. * @drawingMode: a location to a flag. * @drawingInfos: a location to a flag. * @error: a location to store an error. * * This routines read from an XML file the description of selected * nodes, @mark is updated accordingly. * * Since: 3.5 * * Returns: TRUE if no error. */ gboolean visu_gl_ext_marks_parseXMLFile(VisuGlExtMarks *marks, const gchar* filename, GList **infos, VisuGlExtInfosDrawId *drawingMode, guint *drawingInfos, GError **error) { GMarkupParseContext* xmlContext; GMarkupParser parser; gboolean status; gchar *buffer; gsize size; GList *tmpLst; guint id1, id2, id3; VisuData *dataObj; g_return_val_if_fail(filename, FALSE); g_return_val_if_fail(infos && drawingMode && drawingInfos, FALSE); buffer = (gchar*)0; if (!g_file_get_contents(filename, &buffer, &size, error)) return FALSE; /* Create context. */ *infos = (GList*)0; parser.start_element = pickXML_element; parser.end_element = pickXML_end; parser.text = NULL; parser.passthrough = NULL; parser.error = pickXML_error; xmlContext = g_markup_parse_context_new(&parser, 0, infos, NULL); /* Parse data. */ startPick = FALSE; status = g_markup_parse_context_parse(xmlContext, buffer, size, error); /* Free buffers. */ g_markup_parse_context_free(xmlContext); g_free(buffer); if (!status) return FALSE; if (!*infos) { *error = g_error_new(G_MARKUP_ERROR, G_MARKUP_ERROR_EMPTY, _("No picked node found.")); return FALSE; } /* Need to reverse the list since elements have been prepended. */ *infos = g_list_reverse(*infos); *drawingMode = mode; *drawingInfos = info; /* Update the current marks. */ if (marks) { g_return_val_if_fail(VISU_IS_GL_EXT_MARKS(marks) && marks->priv->renderer, FALSE); dataObj = VISU_DATA(visu_node_array_renderer_getNodeArray(marks->priv->renderer)); tmpLst = *infos; while(tmpLst) { if (GPOINTER_TO_INT(tmpLst->data) == PICK_SELECTED) tmpLst = g_list_next(tmpLst); else if (GPOINTER_TO_INT(tmpLst->data) == PICK_HIGHLIGHT) { tmpLst = g_list_next(tmpLst); id1 = (guint)GPOINTER_TO_INT(tmpLst->data) - 1; /* We silently ignore out of bound values. */ if (visu_node_array_getFromId(VISU_NODE_ARRAY(dataObj), id1)) toggleHighlight(marks, id1, MARKS_STATUS_SET, (gboolean*)0); } else if (GPOINTER_TO_INT(tmpLst->data) == PICK_DISTANCE) { tmpLst = g_list_next(tmpLst); id1 = (guint)GPOINTER_TO_INT(tmpLst->data) - 1; tmpLst = g_list_next(tmpLst); id2 = (guint)GPOINTER_TO_INT(tmpLst->data) - 1; /* We silently ignore out of bound values. */ if (visu_node_array_getFromId(VISU_NODE_ARRAY(dataObj), id1) && visu_node_array_getFromId(VISU_NODE_ARRAY(dataObj), id2)) toggleDistance(marks, id1, id2, TRUE); } else if (GPOINTER_TO_INT(tmpLst->data) == PICK_ANGLE) { tmpLst = g_list_next(tmpLst); id1 = (guint)GPOINTER_TO_INT(tmpLst->data) - 1; tmpLst = g_list_next(tmpLst); id2 = (guint)GPOINTER_TO_INT(tmpLst->data) - 1; tmpLst = g_list_next(tmpLst); id3 = (guint)GPOINTER_TO_INT(tmpLst->data) - 1; /* We silently ignore out of bound values. */ if (visu_node_array_getFromId(VISU_NODE_ARRAY(dataObj), id1) && visu_node_array_getFromId(VISU_NODE_ARRAY(dataObj), id2) && visu_node_array_getFromId(VISU_NODE_ARRAY(dataObj), id3)) toggleAngle(marks, id2, id1, id3, TRUE); } else { g_error("Should not be here!"); } tmpLst = g_list_next(tmpLst); } g_object_notify_by_pspec(G_OBJECT(marks), properties[HIGHLIGHT_PROP]); if (marks->priv->hidingMode != HIDE_NONE) visu_node_masker_emitDirty(VISU_NODE_MASKER(marks)); g_signal_emit(G_OBJECT(marks), signals[MEASUREMENT_CHANGE_SIGNAL], 0, dataObj); visu_gl_ext_setDirty(VISU_GL_EXT(marks), TRUE); visu_gl_ext_setDirty(VISU_GL_EXT(marks->priv->extNode), TRUE); } return TRUE; } /** * visu_gl_ext_marks_exportXMLFile: * @marks: a #VisuGlExtMarks object. * @filename: a location to save to. * @nodes: (element-type uint): an array of node ids. * @drawingMode: a flag. * @drawingInfos: a flag. * @error: a location to store an error. * * This routines export to an XML file a description of selected * @nodes. If @nodes is NULL, the nodes stored in the @mark will be * used instead. * * Since: 3.5 * * Returns: TRUE if no error. */ gboolean visu_gl_ext_marks_exportXMLFile(VisuGlExtMarks *marks, const gchar* filename, GArray *nodes, VisuGlExtInfosDrawId drawingMode, guint drawingInfos, GError **error) { gboolean valid, set; GString *output; guint i; char *modes[] = {"never", "selected", "always"}; GList *tmpLst; struct MarkInfo_struct *mark; g_return_val_if_fail(marks && filename, FALSE); /* */ output = g_string_new(" \n", modes[drawingMode], drawingInfos); if (nodes) for (i = 0; i < nodes->len; i++) { set = FALSE; /* We print them only if they are not part of marks. */ for (tmpLst = marks->priv->storedMarks; tmpLst; tmpLst = g_list_next(tmpLst)) { mark = (struct MarkInfo_struct*)(tmpLst->data); set = set || ( (mark->type == MARK_DISTANCE && g_array_index(nodes, guint, i) == mark->idNode2) || (mark->type == MARK_HIGHLIGHT && g_array_index(nodes, guint, i) == mark->idNode1) ); } if (!set) g_string_append_printf(output, " \n", g_array_index(nodes, guint, i) + 1); } for (tmpLst = marks->priv->storedMarks; tmpLst; tmpLst = g_list_next(tmpLst)) { mark = (struct MarkInfo_struct*)(tmpLst->data); if (mark->type == MARK_DISTANCE) g_string_append_printf(output, " \n", mark->idNode1 + 1, mark->idNode2 + 1); else if (mark->type == MARK_ANGLE) g_string_append_printf(output, " \n", mark->idNode1 + 1, mark->idNode2 + 1, mark->idNode3 + 1); else if (mark->type == MARK_HIGHLIGHT) g_string_append_printf(output, " \n", mark->idNode1 + 1); } g_string_append(output, " "); valid = tool_XML_substitute(output, filename, "pick", error); if (!valid) { g_string_free(output, TRUE); return FALSE; } valid = g_file_set_contents(filename, output->str, -1, error); g_string_free(output, TRUE); return valid; } /* Local VisuGlExt for direct node marks. */ typedef struct _ExtNodeClass ExtNodeClass; struct _ExtNodeClass { VisuGlExtClass parent; }; static void ext_node_rebuild(VisuGlExt *ext); static void ext_node_draw(VisuGlExt *ext); #define TYPE_EXT_NODE (ext_node_get_type()) GType ext_node_get_type(void); #define EXT_NODE(obj) (G_TYPE_CHECK_INSTANCE_CAST((obj), TYPE_EXT_NODE, ExtNode)) G_DEFINE_TYPE (ExtNode, ext_node, VISU_TYPE_GL_EXT) static void ext_node_class_init(ExtNodeClass *class) { DBG_fprintf(stderr, "Visu Marks: create internal ExtNode class.\n"); VISU_GL_EXT_CLASS(class)->rebuild = ext_node_rebuild; VISU_GL_EXT_CLASS(class)->draw = ext_node_draw; } static void ext_node_init(ExtNode *marks) { DBG_fprintf(stderr, "Visu Marks: initialise new ExtNode object.\n"); marks->marks = (VisuGlExtMarks*)0; } static ExtNode* ext_node_new(VisuGlExtMarks *marks) { ExtNode *ext; ext = EXT_NODE(g_object_new(TYPE_EXT_NODE, "name", "Marks", "label", _("Marks - classical"), "description", _("Draw some marks on element."), "nGlObj", 1, "priority", VISU_GL_EXT_PRIORITY_LOW, NULL)); ext->marks = marks; return ext; } static void ext_node_rebuild(VisuGlExt *ext) { ext_node_draw(ext); } static void ext_node_draw(VisuGlExt *ext) { ExtNode *extNode = EXT_NODE(ext); struct MarkInfo_struct *mark; GList *tmpLst; VisuData *dataObj; DBG_fprintf(stderr, "Visu Marks: update the list %p" " of all marks.\n", (gpointer)extNode->marks->priv->storedMarks); glDeleteLists(visu_gl_ext_getGlList(ext), 1); visu_gl_ext_setDirty(ext, FALSE); if (!extNode->marks->priv->storedMarks || !extNode->marks->priv->renderer) return; /* Draw the classical list. */ visu_gl_ext_startDrawing(ext); glEnable(GL_LIGHTING); dataObj = VISU_DATA(visu_node_array_renderer_getNodeArray(extNode->marks->priv->renderer)); for (tmpLst = extNode->marks->priv->storedMarks; tmpLst; tmpLst = g_list_next(tmpLst)) { mark = (struct MarkInfo_struct*)tmpLst->data; if (mark->type == MARK_HIGHLIGHT) { DBG_fprintf(stderr, " | draw mark of type %d.\n", mark->type); drawMarkHighlight(dataObj, mark->idNode1, extNode->marks->priv->view, extNode->marks->priv->renderer); } } visu_gl_ext_completeDrawing(ext); } v_sim-3.8.0/src/extensions/marks.h000066400000000000000000000151651370110300500171110ustar00rootroot00000000000000/* EXTRAITS DE LA LICENCE Copyright CEA, contributeurs : Luc BILLARD et Damien CALISTE, laboratoire L_Sim, (2001-2005) Adresse mèl : BILLARD, non joignable par mèl ; CALISTE, damien P caliste AT cea P fr. Ce logiciel est un programme informatique servant à visualiser des structures atomiques dans un rendu pseudo-3D. Ce logiciel est régi par la licence CeCILL soumise au droit français et respectant les principes de diffusion des logiciels libres. Vous pouvez utiliser, modifier et/ou redistribuer ce programme sous les conditions de la licence CeCILL telle que diffusée par le CEA, le CNRS et l'INRIA sur le site "http://www.cecill.info". Le fait que vous puissiez accéder à cet en-tête signifie que vous avez pris connaissance de la licence CeCILL, et que vous en avez accepté les termes (cf. le fichier Documentation/licence.fr.txt fourni avec ce logiciel). */ /* LICENCE SUM UP Copyright CEA, contributors : Luc BILLARD et Damien CALISTE, laboratoire L_Sim, (2001-2005) E-mail address: BILLARD, not reachable any more ; CALISTE, damien P caliste AT cea P fr. This software is a computer program whose purpose is to visualize atomic configurations in 3D. This software is governed by the CeCILL license under French law and abiding by the rules of distribution of free software. You can use, modify and/ or redistribute the software under the terms of the CeCILL license as circulated by CEA, CNRS and INRIA at the following URL "http://www.cecill.info". The fact that you are presently reading this means that you have had knowledge of the CeCILL license and that you accept its terms. You can find a copy of this licence shipped with this software at Documentation/licence.en.txt. */ #ifndef MARKS_H #define MARKS_H #include "infos.h" #include #include #include /** * VisuGlExtMarksStatus: * @MARKS_STATUS_KEEP: do not change the status of the mark ; * @MARKS_STATUS_TOGGLE: change the status of the mark ; * @MARKS_STATUS_SET: set the mark on ; * @MARKS_STATUS_UNSET: unset a mark. * * Possible parameters to change mark status, see * visu_gl_ext_marks_setHighlightedList() for instance. * * Since: 3.6 */ typedef enum { MARKS_STATUS_KEEP, MARKS_STATUS_TOGGLE, MARKS_STATUS_SET, MARKS_STATUS_UNSET } VisuGlExtMarksStatus; /** * VisuGlExtMarksHidingModes: * @HIDE_NONE: don't hide nodes. * @HIDE_HIGHLIGHT: hide highlighted nodes. * @HIDE_NON_HIGHLIGHT: hide all non-highlighted nodes. * * Possible parameters used by visu_gl_ext_marks_setHidingMode(). * * Since: 3.8 */ typedef enum { HIDE_NONE, HIDE_HIGHLIGHT, HIDE_NON_HIGHLIGHT } VisuGlExtMarksHidingModes; /** * VISU_TYPE_GL_EXT_MARKS: * * Return the associated #GType to the #VisuGlExtMarks objects. * * Since: 3.6 */ #define VISU_TYPE_GL_EXT_MARKS (visu_gl_ext_marks_get_type()) /** * VISU_GL_EXT_MARKS: * @obj: the widget to cast. * * Cast the given object to a #VisuGlExtMarks object. * * Since: 3.6 */ #define VISU_GL_EXT_MARKS(obj) (G_TYPE_CHECK_INSTANCE_CAST((obj), VISU_TYPE_GL_EXT_MARKS, VisuGlExtMarks)) /** * VISU_GL_EXT_MARKS_CLASS: * @obj: the class to cast. * * Cast the given class to a #VisuGlExtMarks object. * * Since: 3.6 */ #define VISU_GL_EXT_MARKS_CLASS(obj) (G_TYPE_CHECK_CLASS_CAST((obj), VISU_GL_EXT_MARKS, VisuGlExtMarksClass)) /** * VISU_IS_GL_EXT_MARKS: * @obj: the object to test. * * Return if the given object is a valid #VisuGlExtMarks object. * * Since: 3.6 */ #define VISU_IS_GL_EXT_MARKS(obj) (G_TYPE_CHECK_INSTANCE_TYPE((obj), VISU_TYPE_GL_EXT_MARKS)) /** * VISU_IS_GL_EXT_MARKS_CLASS: * @obj: the class to test. * * Return if the given class is a valid #VisuGlExtMarksClass class. * * Since: 3.6 */ #define VISU_IS_GL_EXT_MARKS_CLASS(obj) (G_TYPE_CHECK_CLASS_TYPE((obj), VISU_TYPE_GL_EXT_MARKS)) /** * VISU_GL_EXT_MARKS_GET_CLASS: * @obj: the widget to get the class of. * * Get the class of the given object. * * Since: 3.6 */ #define VISU_GL_EXT_MARKS_GET_CLASS(obj) (G_TYPE_INSTANCE_GET_CLASS((obj), VISU_TYPE_GL_EXT_MARKS, VisuGlExtMarksClass)) typedef struct _VisuGlExtMarks VisuGlExtMarks; typedef struct _VisuGlExtMarksClass VisuGlExtMarksClass; typedef struct _VisuGlExtMarksPrivate VisuGlExtMarksPrivate; /** * VisuGlExtMarks: * * All fields are private. * * Since: 3.6 */ struct _VisuGlExtMarks { VisuGlExt parent; VisuGlExtMarksPrivate *priv; }; /** * VisuGlExtMarksClass: * @parent: the parent class. * * An opaque structure defining the class of a #VisuGlExtMarks objects. * * Since: 3.6 */ struct _VisuGlExtMarksClass { VisuGlExtClass parent; }; /** * visu_gl_ext_marks_get_type: * * Internal routine to get #VISU_TYPE_GL_EXT_MARKS value. * * Since: 3.6 */ GType visu_gl_ext_marks_get_type(void); VisuGlExtMarks* visu_gl_ext_marks_new(const gchar *name); void visu_gl_ext_marks_setDataRenderer(VisuGlExtMarks *marks, VisuNodeArrayRenderer *renderer); void visu_gl_ext_marks_setInteractive(VisuGlExtMarks *marks, VisuInteractive *inter); gboolean visu_gl_ext_marks_setHighlight(VisuGlExtMarks *marks, GArray *nodes, VisuGlExtMarksStatus status); gboolean visu_gl_ext_marks_unHighlight(VisuGlExtMarks *marks); GArray* visu_gl_ext_marks_getHighlighted(const VisuGlExtMarks *marks); gboolean visu_gl_ext_marks_setInfos(VisuGlExtMarks *marks, guint nodeId, gboolean status); gboolean visu_gl_ext_marks_getActive(VisuGlExtMarks *marks, guint nodeId); gboolean visu_gl_ext_marks_getHighlightStatus(VisuGlExtMarks *marks, guint nodeId); gboolean visu_gl_ext_marks_setDrawValues(VisuGlExtMarks *marks, gboolean status); gboolean visu_gl_ext_marks_removeMeasures(VisuGlExtMarks *marks, gint nodeId); gboolean visu_gl_ext_marks_parseXMLFile(VisuGlExtMarks *marks, const gchar* filename, GList **infos, VisuGlExtInfosDrawId *drawingMode, guint *drawingInfos, GError **error); gboolean visu_gl_ext_marks_exportXMLFile(VisuGlExtMarks *marks, const gchar* filename, GArray *nodes, VisuGlExtInfosDrawId drawingMode, guint drawingInfos, GError **error); gchar* visu_gl_ext_marks_getMeasurementStrings(VisuGlExtMarks *marks); gchar* visu_gl_ext_marks_getMeasurementLabels(VisuGlExtMarks *marks); VisuGlExt* visu_gl_ext_marks_getInternalList(VisuGlExtMarks *marks); VisuGlExtMarksHidingModes visu_gl_ext_marks_getHidingMode(const VisuGlExtMarks *marks); gboolean visu_gl_ext_marks_setHidingMode(VisuGlExtMarks *marks, VisuGlExtMarksHidingModes mode); #endif v_sim-3.8.0/src/extensions/node_vectors.c000066400000000000000000000720441370110300500204600ustar00rootroot00000000000000/* EXTRAITS DE LA LICENCE Copyright CEA, contributeurs : Damien CALISTE, laboratoire L_Sim, (2011-2019) Adresse mèl : BILLARD, non joignable par mèl ; CALISTE, damien P caliste AT cea P fr. Ce logiciel est un programme informatique servant à visualiser des structures atomiques dans un rendu pseudo-3D. Ce logiciel est régi par la licence CeCILL soumise au droit français et respectant les principes de diffusion des logiciels libres. Vous pouvez utiliser, modifier et/ou redistribuer ce programme sous les conditions de la licence CeCILL telle que diffusée par le CEA, le CNRS et l'INRIA sur le site "http://www.cecill.info". Le fait que vous puissiez accéder à cet en-tête signifie que vous avez pris connaissance de la licence CeCILL, et que vous en avez accepté les termes (cf. le fichier Documentation/licence.fr.txt fourni avec ce logiciel). */ /* LICENCE SUM UP Copyright CEA, contributors : Damien CALISTE, laboratoire L_Sim, (2011-2019) E-mail address: BILLARD, not reachable any more ; CALISTE, damien P caliste AT cea P fr. This software is a computer program whose purpose is to visualize atomic configurations in 3D. This software is governed by the CeCILL license under French law and abiding by the rules of distribution of free software. You can use, modify and/ or redistribute the software under the terms of the CeCILL license as circulated by CEA, CNRS and INRIA at the following URL "http://www.cecill.info". The fact that you are presently reading this means that you have had knowledge of the CeCILL license and that you accept its terms. You can find a copy of this licence shipped with this software at Documentation/licence.en.txt. */ #include "node_vectors.h" #include #include #include #include #include #include #include #include #include #include /** * SECTION:node_vectors * @short_description: Draw arrows at each node to represent forces, * displacements, vibrations... * * A generic #VisuGlExt to represent vectors on nodes. */ enum { TAIL_LENGTH, TAIL_RADIUS, TAIL_NLAT, HEAD_LENGTH, HEAD_RADIUS, HEAD_NLAT, N_ARROW_DEFS }; /** * VisuGlExtNodeVectorsClass: * @parent: the parent class; * * A short way to identify #_VisuGlExtNodeVectorsClass structure. * * Since: 3.7 */ /** * VisuGlExtNodeVectors: * * An opaque structure. * * Since: 3.7 */ /** * VisuGlExtNodeVectorsPrivate: * * Private fields for #VisuGlExtNodeVectors objects. * * Since: 3.7 */ struct _VisuGlExtNodeVectorsPrivate { gboolean dispose_has_run; VisuSourceableData *source; /* Rendering definitions. */ VisuGlExtNodeVectorsColorScheme colorScheme; float arrow[N_ARROW_DEFS]; float normFactor, scale; VisuGlArrowCentering centering; float translation, addLength; float ratioMin, ratioMinLabel; VisuNodeArrayRenderer *renderer; gulong size_sig, col_sig, mat_sig, pop_sig, vis_sig, pos_sig, inc_sig; }; enum { PROP_0, NORM_PROP, SCALE_PROP, N_PROP, SOURCE_PROP, MODEL_PROP }; static GParamSpec *_properties[N_PROP]; static void visu_gl_ext_node_vectors_dispose(GObject* obj); static void visu_gl_ext_node_vectors_rebuild(VisuGlExt *ext); static void visu_gl_ext_node_vectors_draw(VisuGlExt *vect); static void visu_gl_ext_node_vectors_get_property(GObject* obj, guint property_id, GValue *value, GParamSpec *pspec); static void visu_gl_ext_node_vectors_set_property(GObject* obj, guint property_id, const GValue *value, GParamSpec *pspec); static void visu_sourceable_interface_init(VisuSourceableInterface *iface); static VisuSourceableData** _getSource(VisuSourceable *self); static void _modelChanged(VisuSourceable *self); /* Local callbacks. */ static void _setDirty(VisuGlExt *ext); static void onElementSize(VisuElementRenderer *renderer, VisuElementRenderer *element, gfloat extent, VisuGlExtNodeVectors *vect); G_DEFINE_TYPE_WITH_CODE(VisuGlExtNodeVectors, visu_gl_ext_node_vectors, VISU_TYPE_GL_EXT, G_ADD_PRIVATE(VisuGlExtNodeVectors) G_IMPLEMENT_INTERFACE(VISU_TYPE_SOURCEABLE, visu_sourceable_interface_init)) static void visu_gl_ext_node_vectors_class_init(VisuGlExtNodeVectorsClass *klass) { DBG_fprintf(stderr, "Visu GlExt NodeVectors: creating the class of the object.\n"); /* DBG_fprintf(stderr, " - adding new signals ;\n"); */ /* Connect the overloading methods. */ G_OBJECT_CLASS(klass)->dispose = visu_gl_ext_node_vectors_dispose; G_OBJECT_CLASS(klass)->set_property = visu_gl_ext_node_vectors_set_property; G_OBJECT_CLASS(klass)->get_property = visu_gl_ext_node_vectors_get_property; VISU_GL_EXT_CLASS(klass)->rebuild = visu_gl_ext_node_vectors_rebuild; VISU_GL_EXT_CLASS(klass)->draw = visu_gl_ext_node_vectors_draw; /** * VisuGlExtNodeVectors::normalisation: * * The normalisation factor, zero to scale to the maximum value, * and positive for an absolute value. * * Since: 3.8 */ _properties[NORM_PROP] = g_param_spec_float("normalisation", "Normalisation", "normalisation factor", -1.f, G_MAXFLOAT, 0.f, G_PARAM_READWRITE); /** * VisuGlExtNodeVectors::rendering-size: * * When positive, this will be the rendering size for a normalised * value of 1, if negative, it is a factor used to scale element size. * * Since: 3.8 */ _properties[SCALE_PROP] = g_param_spec_float("rendering-size", "Rendering size", "rendering size", -G_MAXFLOAT, G_MAXFLOAT, -2.f, G_PARAM_READWRITE); g_object_class_install_properties(G_OBJECT_CLASS(klass), N_PROP, _properties); g_object_class_override_property(G_OBJECT_CLASS(klass), SOURCE_PROP, "source"); g_object_class_override_property(G_OBJECT_CLASS(klass), MODEL_PROP, "model"); } static void visu_sourceable_interface_init(VisuSourceableInterface *iface) { iface->getSource = _getSource; iface->modelChanged = _modelChanged; } static void visu_gl_ext_node_vectors_init(VisuGlExtNodeVectors *obj) { DBG_fprintf(stderr, "Visu GlExt NodeVectors: initializing a new object (%p).\n", (gpointer)obj); obj->priv = visu_gl_ext_node_vectors_get_instance_private(obj); obj->priv->dispose_has_run = FALSE; /* Private data. */ visu_sourceable_init(VISU_SOURCEABLE(obj)); obj->priv->colorScheme = VISU_COLOR_ELEMENT; obj->priv->arrow[TAIL_LENGTH] = 0.7f; obj->priv->arrow[TAIL_RADIUS] = 0.1f; obj->priv->arrow[TAIL_NLAT] = 10.f; obj->priv->arrow[HEAD_LENGTH] = 0.3f; obj->priv->arrow[HEAD_RADIUS] = 0.15f; obj->priv->arrow[HEAD_NLAT] = 10.f; obj->priv->normFactor = -1.f; obj->priv->scale = -2.f; obj->priv->centering = VISU_GL_ARROW_BOTTOM_CENTERED; obj->priv->translation = 0.f; obj->priv->addLength = 0.f; obj->priv->ratioMin = 0.f; obj->priv->ratioMinLabel = G_MAXFLOAT; obj->priv->renderer = (VisuNodeArrayRenderer*)0; } /* This method can be called several times. It should unref all of its reference to GObjects. */ static void visu_gl_ext_node_vectors_dispose(GObject* obj) { VisuGlExtNodeVectors *vect; DBG_fprintf(stderr, "Visu GlExt NodeVectors: dispose object %p.\n", (gpointer)obj); vect = VISU_GL_EXT_NODE_VECTORS(obj); if (vect->priv->dispose_has_run) return; vect->priv->dispose_has_run = TRUE; /* Disconnect signals. */ visu_sourceable_dispose(VISU_SOURCEABLE(obj)); visu_gl_ext_node_vectors_setNodeRenderer(vect, (VisuNodeArrayRenderer*)0); /* Chain up to the parent class */ G_OBJECT_CLASS(visu_gl_ext_node_vectors_parent_class)->dispose(obj); } static void visu_gl_ext_node_vectors_get_property(GObject* obj, guint property_id, GValue *value, GParamSpec *pspec) { VisuGlExtNodeVectors *self = VISU_GL_EXT_NODE_VECTORS(obj); DBG_fprintf(stderr, "Extension NodeVectors: get property '%s' -> ", g_param_spec_get_name(pspec)); switch (property_id) { case SOURCE_PROP: g_value_set_string(value, visu_sourceable_getSource(VISU_SOURCEABLE(self))); DBG_fprintf(stderr, "%s.\n", g_value_get_string(value)); break; case MODEL_PROP: g_value_set_object(value, visu_sourceable_getNodeModel(VISU_SOURCEABLE(self))); DBG_fprintf(stderr, "%p.\n", g_value_get_object(value)); break; case NORM_PROP: g_value_set_float(value, self->priv->normFactor); DBG_fprintf(stderr, "%g.\n", g_value_get_float(value)); break; case SCALE_PROP: g_value_set_float(value, self->priv->scale); DBG_fprintf(stderr, "%g.\n", g_value_get_float(value)); break; default: /* We don't have any other property... */ G_OBJECT_WARN_INVALID_PROPERTY_ID(obj, property_id, pspec); break; } } static void visu_gl_ext_node_vectors_set_property(GObject* obj, guint property_id, const GValue *value, GParamSpec *pspec) { VisuGlExtNodeVectors *self = VISU_GL_EXT_NODE_VECTORS(obj); DBG_fprintf(stderr, "Extension NodeVectors: set property '%s' -> ", g_param_spec_get_name(pspec)); switch (property_id) { case SOURCE_PROP: DBG_fprintf(stderr, "%s.\n", g_value_get_string(value)); visu_sourceable_setSource(VISU_SOURCEABLE(obj), g_value_get_string(value)); break; case MODEL_PROP: DBG_fprintf(stderr, "%p.\n", g_value_get_object(value)); visu_sourceable_setNodeModel(VISU_SOURCEABLE(obj), g_value_get_object(value)); break; case NORM_PROP: DBG_fprintf(stderr, "%g.\n", g_value_get_float(value)); visu_gl_ext_node_vectors_setNormalisation(self, g_value_get_float(value)); break; case SCALE_PROP: DBG_fprintf(stderr, "%g.\n", g_value_get_float(value)); visu_gl_ext_node_vectors_setRenderedSize(self, g_value_get_float(value)); break; default: /* We don't have any other property... */ G_OBJECT_WARN_INVALID_PROPERTY_ID(obj, property_id, pspec); break; } } /** * visu_gl_ext_node_vectors_new: * @name: (allow-none): the name to give to the extension. * * Creates a new #VisuGlExt to draw a box. * * Since: 3.7 * * Returns: a pointer to the #VisuGlExt it created or * NULL otherwise. */ VisuGlExtNodeVectors* visu_gl_ext_node_vectors_new(const gchar *name) { char *name_ = "Node vectors"; char *description = _("Draw vectors on each nodes."); DBG_fprintf(stderr,"Visu GlExt NodeVectors: new object.\n"); return g_object_new(VISU_TYPE_GL_EXT_NODE_VECTORS, "name", (name)?name:name_, "label", _(name), "description", description, "nGlObj", 1, "priority", VISU_GL_EXT_PRIORITY_NODE_DECORATIONS, NULL); } /** * visu_gl_ext_node_vectors_setNodeRenderer: * @vect: a #VisuGlExtNodeVectors object. * @renderer: a #VisuNodeArrayRenderer object. * * Use the #VisuElementRenderer properties from @renderer to display * vector properties. * * Since: 3.8 * * Returns: TRUE if changed. **/ gboolean visu_gl_ext_node_vectors_setNodeRenderer(VisuGlExtNodeVectors *vect, VisuNodeArrayRenderer *renderer) { g_return_val_if_fail(VISU_IS_GL_EXT_NODE_VECTORS(vect), FALSE); if (vect->priv->renderer == renderer) return FALSE; if (vect->priv->renderer) { g_signal_handler_disconnect(vect->priv->renderer, vect->priv->size_sig); g_signal_handler_disconnect(vect->priv->renderer, vect->priv->col_sig); g_signal_handler_disconnect(vect->priv->renderer, vect->priv->mat_sig); g_signal_handler_disconnect(vect->priv->renderer, vect->priv->pop_sig); g_signal_handler_disconnect(vect->priv->renderer, vect->priv->inc_sig); g_signal_handler_disconnect(vect->priv->renderer, vect->priv->vis_sig); g_signal_handler_disconnect(vect->priv->renderer, vect->priv->pos_sig); g_object_unref(vect->priv->renderer); } vect->priv->renderer = renderer; if (renderer) { g_object_ref(renderer); vect->priv->size_sig = g_signal_connect(renderer, "element-size-changed", G_CALLBACK(onElementSize), vect); vect->priv->col_sig = g_signal_connect_swapped(renderer, "element-notify::color", G_CALLBACK(_setDirty), vect); vect->priv->mat_sig = g_signal_connect_swapped(renderer, "element-notify::material", G_CALLBACK(_setDirty), vect); vect->priv->pop_sig = g_signal_connect_swapped(renderer, "nodes::population-decrease", G_CALLBACK(_setDirty), vect); vect->priv->inc_sig = g_signal_connect_swapped(renderer, "nodes::population-increase", G_CALLBACK(_setDirty), vect); vect->priv->vis_sig = g_signal_connect_swapped(renderer, "nodes::visibility", G_CALLBACK(_setDirty), vect); vect->priv->pos_sig = g_signal_connect_swapped(renderer, "nodes::position", G_CALLBACK(_setDirty), vect); } visu_gl_ext_setDirty(VISU_GL_EXT(vect), TRUE); return TRUE; } static VisuSourceableData** _getSource(VisuSourceable *self) { VisuGlExtNodeVectors *vect = VISU_GL_EXT_NODE_VECTORS(self); g_return_val_if_fail(VISU_IS_GL_EXT_NODE_VECTORS(self), (VisuSourceableData**)0); return &vect->priv->source; } static void _modelChanged(VisuSourceable *self) { visu_gl_ext_setDirty(VISU_GL_EXT(self), TRUE); } /** * visu_gl_ext_node_vectors_setRenderedSize: * @vect: the #VisuGlExtNodeVectors object to modify. * @scale: a floating point value. * * @scale governs how large the node vectors are drawn. For a positive * value, a vector with a normalised size of 1 (see * visu_gl_ext_node_vectors_setNormalisation()) will be drawn with the size of * @scale. For a negative value, a vector of normalised size of 1 will * be drawn with a size of -@scale times the maximum element size (see * visu_node_array_renderer_getMaxElementSize()). * * Since: 3.7 * * Returns: TRUE if setting has been changed. **/ gboolean visu_gl_ext_node_vectors_setRenderedSize(VisuGlExtNodeVectors *vect, gfloat scale) { g_return_val_if_fail(VISU_IS_GL_EXT_NODE_VECTORS(vect), FALSE); if (vect->priv->scale == scale) return FALSE; vect->priv->scale = scale; if (vect->priv->renderer && visu_sourceable_getNodeModel(VISU_SOURCEABLE(vect))) visu_gl_ext_setDirty(VISU_GL_EXT(vect), TRUE); return TRUE; } /** * visu_gl_ext_node_vectors_setNormalisation: * @vect: the #VisuGlExtNodeVectors object to modify. * @norm: a floating point value. * * @norm governs how the input node vector field is normalised. With a * positive value, all node vectors will be normalised by @norm. With * a negative value, all node vectors are normalised with respect to * the biggest one. * * Since: 3.7 * * Returns: TRUE if setting has been changed. **/ gboolean visu_gl_ext_node_vectors_setNormalisation(VisuGlExtNodeVectors *vect, float norm) { g_return_val_if_fail(VISU_IS_GL_EXT_NODE_VECTORS(vect), FALSE); if (vect->priv->normFactor == norm) return FALSE; vect->priv->normFactor = norm; g_object_notify_by_pspec(G_OBJECT(vect), _properties[NORM_PROP]); if (vect->priv->renderer && visu_sourceable_getSource(VISU_SOURCEABLE(vect))) visu_gl_ext_setDirty(VISU_GL_EXT(vect), TRUE); return TRUE; } /** * visu_gl_ext_node_vectors_setTranslation: * @vect: the #VisuGlExtNodeVectors object to modify. * @trans: a positive floating point value. * * Defines a translation with respect to the center of each node. The * vector is shifted outwards, following the vector direction by an * amount given by the product of @trans and the element size * currently drawn. * * Since: 3.7 * * Returns: TRUE if setting has been changed. **/ gboolean visu_gl_ext_node_vectors_setTranslation(VisuGlExtNodeVectors *vect, float trans) { g_return_val_if_fail(VISU_IS_GL_EXT_NODE_VECTORS(vect), FALSE); if (vect->priv->translation == trans) return FALSE; vect->priv->translation = MAX(0.f, trans); if (vect->priv->renderer && visu_sourceable_getSource(VISU_SOURCEABLE(vect))) visu_gl_ext_setDirty(VISU_GL_EXT(vect), TRUE); return TRUE; } /** * visu_gl_ext_node_vectors_setColor: * @vect: the #VisuGlExtNodeVectors object to modify. * @scheme: a value. * * If @scheme is %VISU_COLOR_ELEMENT, the vectors are drawn with the color of the * currently drawn #VisuElement. If @scheme is %VISU_COLOR_BRIGHT, they * are drawn with a highlighted color. If @scheme is * %VISU_COLOR_ORIENTATION, they are drawn with a hue depending onn orientation. * * Since: 3.7 * * Returns: TRUE if setting has been changed. **/ gboolean visu_gl_ext_node_vectors_setColor(VisuGlExtNodeVectors *vect, VisuGlExtNodeVectorsColorScheme scheme) { g_return_val_if_fail(VISU_IS_GL_EXT_NODE_VECTORS(vect), FALSE); if (vect->priv->colorScheme == scheme) return FALSE; vect->priv->colorScheme = scheme; if (vect->priv->renderer && visu_sourceable_getSource(VISU_SOURCEABLE(vect))) visu_gl_ext_setDirty(VISU_GL_EXT(vect), TRUE); return TRUE; } /** * visu_gl_ext_node_vectors_setCentering: * @vect: the #VisuGlExtNodeVectors object to modify. * @centering: a #VisuGlArrowCentering id. * * Change how vectors are position with respect to to center of each node. * * Since: 3.7 * * Returns: TRUE if setting has been changed. **/ gboolean visu_gl_ext_node_vectors_setCentering(VisuGlExtNodeVectors *vect, VisuGlArrowCentering centering) { g_return_val_if_fail(VISU_IS_GL_EXT_NODE_VECTORS(vect), FALSE); if (vect->priv->centering == centering) return FALSE; vect->priv->centering = centering; if (vect->priv->renderer && visu_sourceable_getSource(VISU_SOURCEABLE(vect))) visu_gl_ext_setDirty(VISU_GL_EXT(vect), TRUE); return TRUE; } /** * visu_gl_ext_node_vectors_setAddLength: * @vect: the #VisuGlExtNodeVectors object to modify. * @addLength: a positive value. * * Change the additional length that is used to draw the tail. * * Since: 3.8 * * Returns: TRUE if settings has been changed. **/ gboolean visu_gl_ext_node_vectors_setAddLength(VisuGlExtNodeVectors *vect, gfloat addLength) { g_return_val_if_fail(VISU_IS_GL_EXT_NODE_VECTORS(vect), FALSE); if (vect->priv->addLength == addLength) return FALSE; vect->priv->addLength = MAX(addLength, 0.f); if (vect->priv->renderer && visu_sourceable_getSource(VISU_SOURCEABLE(vect))) visu_gl_ext_setDirty(VISU_GL_EXT(vect), TRUE); return TRUE; } /** * visu_gl_ext_node_vectors_setVectorThreshold: * @vect: the #VisuGlExtNodeVectors object to modify. * @val: a value. * * Vectors are indeed drawn if a threshold value is reach. If @val is * strictly positive, the norm of each vector is compared to @val. If * @val is negative, the normalised [0;1] norm is compared to -@val. * * Since: 3.7 * * Returns: TRUE if setting has been changed. **/ gboolean visu_gl_ext_node_vectors_setVectorThreshold(VisuGlExtNodeVectors *vect, float val) { g_return_val_if_fail(VISU_IS_GL_EXT_NODE_VECTORS(vect), FALSE); if (vect->priv->ratioMin == val) return FALSE; vect->priv->ratioMin = val; if (vect->priv->renderer && visu_sourceable_getSource(VISU_SOURCEABLE(vect))) visu_gl_ext_setDirty(VISU_GL_EXT(vect), TRUE); return TRUE; } /** * visu_gl_ext_node_vectors_setLabelThreshold: * @vect: the #VisuGlExtNodeVectors object to modify. * @val: a value. * * Vector norms can be drawn if a threshold value is reach. If @val is * strictly positive, the norm of each vector is compared to @val. If * @val is negative, the normalised [0;1] norm is compared to -@val. * * Since: 3.7 * * Returns: TRUE if setting has been changed. **/ gboolean visu_gl_ext_node_vectors_setLabelThreshold(VisuGlExtNodeVectors *vect, float val) { g_return_val_if_fail(VISU_IS_GL_EXT_NODE_VECTORS(vect), FALSE); if (vect->priv->ratioMinLabel == val) return FALSE; vect->priv->ratioMinLabel = val; if (vect->priv->renderer && visu_sourceable_getSource(VISU_SOURCEABLE(vect))) visu_gl_ext_setDirty(VISU_GL_EXT(vect), TRUE); return TRUE; } /** * visu_gl_ext_node_vectors_setArrow: * @vect: the #VisuGlExtNodeVectors object to modify. * @tailLength: the length for the tail part of the vector. * @tailRadius: the radius for the tail part of the vector. * @tailN: the number of polygons to draw the tail part of the vector. * @headLength: the length for the head part of the vector. * @headRadius: the radius for the head part of the vector. * @headN: the number of polygons to draw the head part of the vector. * * Defines the profile of the arrows representing the vectors. * * Since: 3.7 * * Returns: TRUE if setting has been changed. **/ gboolean visu_gl_ext_node_vectors_setArrow(VisuGlExtNodeVectors *vect, float tailLength, float tailRadius, guint tailN, float headLength, float headRadius, guint headN) { gboolean diff; float fact; g_return_val_if_fail(VISU_IS_GL_EXT_NODE_VECTORS(vect), FALSE); diff = FALSE; diff = diff || (vect->priv->arrow[TAIL_LENGTH] != tailLength); diff = diff || (vect->priv->arrow[TAIL_RADIUS] != tailRadius); diff = diff || (vect->priv->arrow[TAIL_NLAT] != tailN); diff = diff || (vect->priv->arrow[HEAD_LENGTH] != headLength); diff = diff || (vect->priv->arrow[HEAD_RADIUS] != headRadius); diff = diff || (vect->priv->arrow[HEAD_NLAT] != headN); if (!diff) return FALSE; fact = 1.f / (tailLength + headLength); vect->priv->arrow[TAIL_LENGTH] = tailLength * fact; vect->priv->arrow[TAIL_RADIUS] = tailRadius * fact; vect->priv->arrow[TAIL_NLAT] = tailN; vect->priv->arrow[HEAD_LENGTH] = headLength * fact; vect->priv->arrow[HEAD_RADIUS] = headRadius * fact; vect->priv->arrow[HEAD_NLAT] = headN; if (vect->priv->renderer && visu_sourceable_getSource(VISU_SOURCEABLE(vect))) visu_gl_ext_setDirty(VISU_GL_EXT(vect), TRUE); return TRUE; } /** * visu_gl_ext_node_vectors_getScale: * * The forces can be scaled manually or automatically, see * visu_gl_ext_forces_setScale() and visu_rendering_atomic_drawForces(). * * Since: 3.7 * * Returns: the scaling factor, -1 if automatic. **/ /* gfloat visu_gl_ext_forces_getScale() */ /* { */ /* return scale; */ /* } */ /** * visu_gl_ext_node_vectors_getNormalisation: * @vect: the #VisuGlExtNodeVectors object to inquire. * * Gets the normalisation factor, see visu_gl_ext_node_vectors_setNormalisation(). * * Since: 3.7 * * Returns: the normalisation factor used by @vact. **/ float visu_gl_ext_node_vectors_getNormalisation(VisuGlExtNodeVectors *vect) { g_return_val_if_fail(VISU_IS_GL_EXT_NODE_VECTORS(vect), -1.f); return vect->priv->normFactor; } /********************/ /* Local callbacks. */ /********************/ static void _setDirty(VisuGlExt *ext) { visu_gl_ext_setDirty(ext, TRUE); } static void onElementSize(VisuElementRenderer *renderer _U_, VisuElementRenderer *element _U_, gfloat extent _U_, VisuGlExtNodeVectors *vect) { if (vect->priv->scale < 0.f || vect->priv->translation > 0.f) visu_gl_ext_setDirty(VISU_GL_EXT(vect), TRUE); } /***********/ /* OpenGL. */ /***********/ static void visu_gl_ext_node_vectors_draw(VisuGlExt *vect) { VisuNodeArrayRendererIter iter; GLUquadricObj *obj; float fact, scale, eleSize; float rMult, r, sMult, s, l, headLength, tailLength; float xyz[3], dxyz[3], hsl[3], rgba[4]; const gfloat *sph; char distStr[10]; gboolean valid; VisuGlExtNodeVectorsPrivate *priv = VISU_GL_EXT_NODE_VECTORS(vect)->priv; glDeleteLists(visu_gl_ext_getGlList(vect), 1); visu_gl_ext_setDirty(vect, FALSE); DBG_fprintf(stderr, "Extension Node Vectors: building for nodes %p and vectors %p.\n", (gpointer)priv->renderer, (gpointer)visu_sourceable_getNodeModel(VISU_SOURCEABLE(vect))); if (!priv->renderer || !visu_sourceable_getNodeModel(VISU_SOURCEABLE(vect))) return; obj = gluNewQuadric(); /* Normalization factor. */ fact = priv->normFactor; if (fact <= 0.f) fact = visu_node_values_farray_max(VISU_NODE_VALUES_FARRAY(visu_sourceable_getNodeModel(VISU_SOURCEABLE(vect)))); fact = 1.f / fact; /* Drawing rule for vectors. */ rMult = 1.f; r = 1.f; if (priv->ratioMin <= 0.f) { rMult = fact; r = -1.f; } /* Drawing rule for label. */ sMult = 1.f; s = 1.f; if (priv->ratioMinLabel <= 0.f) { sMult = fact; s = -1.f; } /* Maximum representation size. */ scale = priv->scale; if (scale <= 0.f) scale = visu_node_array_renderer_getMaxElementSize(priv->renderer, NULL) * (-scale); visu_gl_ext_startDrawing(vect); eleSize = 0.f; for (valid = visu_node_array_renderer_iter_new(priv->renderer, &iter, TRUE); valid; valid = visu_node_array_renderer_iter_next(&iter)) { if (!visu_element_getRendered(iter.element)) continue; if (priv->colorScheme == VISU_COLOR_ELEMENT) visu_element_renderer_colorize(iter.renderer, VISU_ELEMENT_RENDERER_NO_EFFECT); else if (priv->colorScheme == VISU_COLOR_BRIGHT) visu_element_renderer_colorize(iter.renderer, VISU_ELEMENT_RENDERER_HIGHLIGHT); eleSize = visu_element_renderer_getExtent(iter.renderer); for(visu_node_array_iterRestartNode(iter.parent.array, &iter.parent); iter.parent.node; visu_node_array_iterNextNode(iter.parent.array, &iter.parent)) { if (!iter.parent.node->rendered) continue; sph = visu_node_values_vector_getAtSpherical(VISU_NODE_VALUES_VECTOR(visu_sourceable_getNodeModel(VISU_SOURCEABLE(vect))), iter.parent.node); if (!sph) continue; if (sph[TOOL_MATRIX_SPHERICAL_MODULUS] * rMult <= priv->ratioMin * r) continue; l = sph[TOOL_MATRIX_SPHERICAL_MODULUS] * fact; visu_data_getNodePosition(VISU_DATA(iter.parent.array), iter.parent.node, xyz); visu_node_values_vector_getShift(VISU_NODE_VALUES_VECTOR(visu_sourceable_getNodeModel(VISU_SOURCEABLE(vect))), iter.parent.node, dxyz); glPushMatrix(); glTranslatef(xyz[0] - dxyz[0], xyz[1] - dxyz[1], xyz[2] - dxyz[2]); /* We draw the arrow. */ if (priv->colorScheme == VISU_COLOR_ORIENTATION) { hsl[2] = 1.f - sph[TOOL_MATRIX_SPHERICAL_THETA] / 180.; hsl[1] = 1.f; hsl[0] = sph[TOOL_MATRIX_SPHERICAL_PHI] / 360.; tool_color_convertHSLtoRGB(rgba, hsl); rgba[3] = visu_element_renderer_getColor(iter.renderer)->rgba[3]; visu_gl_setColor((VisuGl*)0, visu_element_renderer_getMaterial(iter.renderer), rgba); } glRotated(sph[TOOL_MATRIX_SPHERICAL_PHI], 0, 0, 1); glRotated(sph[TOOL_MATRIX_SPHERICAL_THETA], 0, 1, 0); glTranslated(0.f, 0.f, eleSize * priv->translation); switch (priv->centering) { case (VISU_GL_ARROW_CENTERED): glScalef(scale, scale, scale); tailLength = MAX(0.f, l - priv->arrow[HEAD_LENGTH]); headLength = MIN(l, priv->arrow[HEAD_LENGTH]); break; case (VISU_GL_ARROW_TAIL_CENTERED): glScalef(eleSize, eleSize, eleSize); tailLength = l * scale / eleSize + priv->addLength; headLength = priv->arrow[HEAD_LENGTH]; break; default: glScalef(l * scale, l * scale, l * scale); tailLength = priv->arrow[TAIL_LENGTH]; headLength = priv->arrow[HEAD_LENGTH]; } visu_gl_drawSmoothArrow(obj, priv->centering, tailLength, priv->arrow[TAIL_RADIUS], (guint)priv->arrow[TAIL_NLAT], NULL, headLength, priv->arrow[HEAD_RADIUS], (guint)priv->arrow[HEAD_NLAT], NULL); /* We draw the value. */ if (sph[TOOL_MATRIX_SPHERICAL_MODULUS] * sMult > priv->ratioMinLabel * s) { glRasterPos3f(0.f, 0.f, 0.f); sprintf(distStr, "%6.3f", sph[TOOL_MATRIX_SPHERICAL_MODULUS]); visu_gl_text_drawChars(distStr, VISU_GL_TEXT_NORMAL); } glPopMatrix(); } } visu_gl_ext_completeDrawing(vect); gluDeleteQuadric(obj); } static void visu_gl_ext_node_vectors_rebuild(VisuGlExt *ext) { DBG_fprintf(stderr, "Visu GlExt NodeVectors: rebuilding vectors %p.\n", (gpointer)ext); visu_gl_text_rebuildFontList(); visu_gl_ext_setDirty(ext, TRUE); visu_gl_ext_node_vectors_draw(ext); } v_sim-3.8.0/src/extensions/node_vectors.h000066400000000000000000000115541370110300500204640ustar00rootroot00000000000000/* EXTRAITS DE LA LICENCE Copyright CEA, contributeurs : Damien CALISTE, laboratoire L_Sim, (2011-2019) Adresse mèl : CALISTE, damien P caliste AT cea P fr. Ce logiciel est un programme informatique servant à visualiser des structures atomiques dans un rendu pseudo-3D. Ce logiciel est régi par la licence CeCILL soumise au droit français et respectant les principes de diffusion des logiciels libres. Vous pouvez utiliser, modifier et/ou redistribuer ce programme sous les conditions de la licence CeCILL telle que diffusée par le CEA, le CNRS et l'INRIA sur le site "http://www.cecill.info". Le fait que vous puissiez accéder à cet en-tête signifie que vous avez pris connaissance de la licence CeCILL, et que vous en avez accepté les termes (cf. le fichier Documentation/licence.fr.txt fourni avec ce logiciel). */ /* LICENCE SUM UP Copyright CEA, contributors : Damien CALISTE, laboratoire L_Sim, (2011-2019) E-mail address: CALISTE, damien P caliste AT cea P fr. This software is a computer program whose purpose is to visualize atomic configurations in 3D. This software is governed by the CeCILL license under French law and abiding by the rules of distribution of free software. You can use, modify and/ or redistribute the software under the terms of the CeCILL license as circulated by CEA, CNRS and INRIA at the following URL "http://www.cecill.info". The fact that you are presently reading this means that you have had knowledge of the CeCILL license and that you accept its terms. You can find a copy of this licence shipped with this software at COPYING. */ #ifndef NODE_VECTORS_H #define NODE_VECTORS_H #include #include #include #include #include #include /** * VisuGlExtNodeVectorsColorScheme: * @VISU_COLOR_ELEMENT: use the #VisuElement colour for vectors. * @VISU_COLOR_BRIGHT: use a bright colour derived from the * #VisuElement colour for the vectors. * @VISU_COLOR_ORIENTATION: use the orientation to colour the vectors. * * Different colour schemes used to colourize the vectors. * * Since: 3.8 */ typedef enum { VISU_COLOR_ELEMENT, VISU_COLOR_BRIGHT, VISU_COLOR_ORIENTATION } VisuGlExtNodeVectorsColorScheme; #define VISU_TYPE_GL_EXT_NODE_VECTORS (visu_gl_ext_node_vectors_get_type ()) #define VISU_GL_EXT_NODE_VECTORS(obj) (G_TYPE_CHECK_INSTANCE_CAST(obj, VISU_TYPE_GL_EXT_NODE_VECTORS, VisuGlExtNodeVectors)) #define VISU_GL_EXT_NODE_VECTORS_CLASS(klass) (G_TYPE_CHECK_CLASS_CAST(klass, VISU_TYPE_GL_EXT_NODE_VECTORS, VisuGlExtNodeVectorsClass)) #define VISU_IS_GL_EXT_NODE_VECTORS(obj) (G_TYPE_CHECK_INSTANCE_TYPE(obj, VISU_TYPE_GL_EXT_NODE_VECTORS)) #define VISU_IS_GL_EXT_NODE_VECTORS_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE(klass, VISU_TYPE_GL_EXT_NODE_VECTORS)) #define VISU_GL_EXT_NODE_VECTORS_GET_CLASS(obj) (G_TYPE_INSTANCE_GET_CLASS(obj, VISU_TYPE_GL_EXT_NODE_VECTORS, VisuGlExtNodeVectorsClass)) typedef struct _VisuGlExtNodeVectors VisuGlExtNodeVectors; typedef struct _VisuGlExtNodeVectorsPrivate VisuGlExtNodeVectorsPrivate; typedef struct _VisuGlExtNodeVectorsClass VisuGlExtNodeVectorsClass; GType visu_gl_ext_node_vectors_get_type(void); struct _VisuGlExtNodeVectors { VisuGlExt parent; VisuGlExtNodeVectorsPrivate *priv; }; struct _VisuGlExtNodeVectorsClass { VisuGlExtClass parent; }; VisuGlExtNodeVectors* visu_gl_ext_node_vectors_new(const gchar *name); gboolean visu_gl_ext_node_vectors_setNodeRenderer(VisuGlExtNodeVectors *vect, VisuNodeArrayRenderer *renderer); gboolean visu_gl_ext_node_vectors_setRenderedSize(VisuGlExtNodeVectors *vect, gfloat scale); gboolean visu_gl_ext_node_vectors_setNormalisation(VisuGlExtNodeVectors *vect, float norm); gboolean visu_gl_ext_node_vectors_setTranslation(VisuGlExtNodeVectors *vect, float trans); gboolean visu_gl_ext_node_vectors_setColor(VisuGlExtNodeVectors *vect, VisuGlExtNodeVectorsColorScheme scheme); gboolean visu_gl_ext_node_vectors_setCentering(VisuGlExtNodeVectors *vect, VisuGlArrowCentering centering); gboolean visu_gl_ext_node_vectors_setAddLength(VisuGlExtNodeVectors *vect, gfloat addLength); gboolean visu_gl_ext_node_vectors_setVectorThreshold(VisuGlExtNodeVectors *vect, float val); gboolean visu_gl_ext_node_vectors_setLabelThreshold(VisuGlExtNodeVectors *vect, float val); gboolean visu_gl_ext_node_vectors_setArrow(VisuGlExtNodeVectors *vect, float tailLength, float tailRadius, guint tailN, float headLength, float headRadius, guint headN); float visu_gl_ext_node_vectors_getNormalisation(VisuGlExtNodeVectors *vect); #endif v_sim-3.8.0/src/extensions/nodes.c000066400000000000000000001142111370110300500170670ustar00rootroot00000000000000/* EXTRAITS DE LA LICENCE Copyright CEA, contributeurs : Damien CALISTE, laboratoire L_Sim, (2013-2019) Adresse mèl : CALISTE, damien P caliste AT cea P fr. Ce logiciel est un programme informatique servant à visualiser des structures atomiques dans un rendu pseudo-3D. Ce logiciel est régi par la licence CeCILL soumise au droit français et respectant les principes de diffusion des logiciels libres. Vous pouvez utiliser, modifier et/ou redistribuer ce programme sous les conditions de la licence CeCILL telle que diffusée par le CEA, le CNRS et l'INRIA sur le site "http://www.cecill.info". Le fait que vous puissiez accéder à cet en-tête signifie que vous avez pris connaissance de la licence CeCILL, et que vous en avez accepté les termes (cf. le fichier Documentation/licence.fr.txt fourni avec ce logiciel). */ /* LICENCE SUM UP Copyright CEA, contributors : Damien CALISTE, laboratoire L_Sim, (2013-2019) E-mail address: CALISTE, damien P caliste AT cea P fr. This software is a computer program whose purpose is to visualize atomic configurations in 3D. This software is governed by the CeCILL license under French law and abiding by the rules of distribution of free software. You can use, modify and/ or redistribute the software under the terms of the CeCILL license as circulated by CEA, CNRS and INRIA at the following URL "http://www.cecill.info". The fact that you are presently reading this means that you have had knowledge of the CeCILL license and that you accept its terms. You can find a copy of this licence shipped with this software at Documentation/licence.en.txt. */ #include "nodes.h" #include #include #include #include #include #include #include #include #include #include #undef near #undef far /** * SECTION:nodes * @short_description: Defines methods to draw a set of nodes. * * */ typedef struct _GlIds { VisuElementRenderer *renderer; gulong notify_sig, size_sig, colorize_sig; GLuint material, nodes; } GlIds; enum { PROP_0, DATA_PROP, TYPE_PROP, MAX_SIZE_PROP, COLORIZER_PROP, N_PROP }; /* static GParamSpec *_properties[N_PROP]; */ struct _VisuGlExtNodesPrivate { gboolean dispose_has_run; VisuElementRendererEffects effect; guint nEle; GArray *glIds; VisuGlView *view; VisuData *dataObj; gulong popId, posId, popIncId, popDecId, visId, boxId; gulong renId, detailsId; VisuBox *box; gulong unitId; GList *colorizers; gulong dirtyId; }; #define VISU_GL_EXT_NODES_ID "Nodes" /* Local routines. */ static void visu_gl_ext_nodes_dispose (GObject* obj); static void visu_gl_ext_nodes_finalize(GObject* obj); static void visu_gl_ext_nodes_get_property(GObject* obj, guint property_id, GValue *value, GParamSpec *pspec); static void visu_gl_ext_nodes_set_property(GObject* obj, guint property_id, const GValue *value, GParamSpec *pspec); static void visu_gl_ext_nodes_rebuild (VisuGlExt *ext); static void visu_gl_ext_nodes_draw(VisuGlExt *ext); static gboolean visu_gl_ext_nodes_setGlView(VisuGlExt *ext, VisuGlView *view); static void visu_node_array_renderer_interface_init(VisuNodeArrayRendererInterface *iface); static void _setPopulation(VisuGlExtNodes *nodes); static void compileElementMaterial(VisuGlExtNodes *ext, GLuint displayList, VisuElementRenderer *ele); static void createAllElements(VisuGlExtNodes *ext); static void createNodes(VisuGlExtNodes *ext, GlIds *ids); static void createAllNodes(VisuGlExtNodes *ext); static void _freeGlIds(GlIds *ids); static VisuNodeArray* _getNodeArray(VisuNodeArrayRenderer *self); static gboolean _setNodeArray(VisuNodeArrayRenderer *self, VisuNodeArray *array); static VisuElementRenderer* _getElementRenderer(VisuNodeArrayRenderer *self, const VisuElement *element); static gfloat _getMaxElementSize(VisuNodeArrayRenderer *node_array, guint *n); static void _setColorizer(VisuNodeArrayRenderer *nodes, VisuDataColorizer *colorizer); static gboolean _pushColorizer(VisuNodeArrayRenderer *nodes, VisuDataColorizer *colorizer); static gboolean _removeColorizer(VisuNodeArrayRenderer *nodes, VisuDataColorizer *colorizer); static VisuDataColorizer* _getColorizer(VisuNodeArrayRenderer *nodes); /* Signal callbacks. */ static void _setDirty(VisuGlExt *ext); static void onPopulationInc(VisuData *dataObj, GArray *ids, gpointer data); static void onPopulationDec(VisuData *dataObj, GArray *ids, gpointer data); static void onPositionChanged(VisuData *dataObj, GArray *ids, gpointer data); static void onVisibilityChanged(VisuData *dataObj, gpointer data); static void onRenderingChanged(VisuGlExtNodes *nodes); static void onColorize(VisuGlExtNodes *ext, GParamSpec *pspec, VisuElement *element); static void onRenderer(VisuGlExtNodes *ext, GParamSpec *pspec, VisuElementRenderer *renderer); static void onSize(VisuGlExtNodes *ext, gfloat extent, VisuElementRenderer *renderer); static void onUnits(VisuGlExtNodes *ext, gfloat fact, VisuBox *box); G_DEFINE_TYPE_WITH_CODE(VisuGlExtNodes, visu_gl_ext_nodes, VISU_TYPE_GL_EXT, G_ADD_PRIVATE(VisuGlExtNodes) G_IMPLEMENT_INTERFACE(VISU_TYPE_NODE_ARRAY_RENDERER, visu_node_array_renderer_interface_init)) static void visu_gl_ext_nodes_class_init(VisuGlExtNodesClass *klass) { DBG_fprintf(stderr, "Extension Nodes: creating the class of the object.\n"); /* DBG_fprintf(stderr, " - adding new signals ;\n"); */ /* Connect the overloading methods. */ G_OBJECT_CLASS(klass)->dispose = visu_gl_ext_nodes_dispose; G_OBJECT_CLASS(klass)->finalize = visu_gl_ext_nodes_finalize; G_OBJECT_CLASS(klass)->set_property = visu_gl_ext_nodes_set_property; G_OBJECT_CLASS(klass)->get_property = visu_gl_ext_nodes_get_property; VISU_GL_EXT_CLASS(klass)->rebuild = visu_gl_ext_nodes_rebuild; VISU_GL_EXT_CLASS(klass)->draw = visu_gl_ext_nodes_draw; VISU_GL_EXT_CLASS(klass)->setGlView = visu_gl_ext_nodes_setGlView; g_object_class_override_property(G_OBJECT_CLASS(klass), DATA_PROP, "data"); g_object_class_override_property(G_OBJECT_CLASS(klass), TYPE_PROP, "type"); g_object_class_override_property(G_OBJECT_CLASS(klass), MAX_SIZE_PROP, "max-element-size"); g_object_class_override_property(G_OBJECT_CLASS(klass), COLORIZER_PROP, "colorizer"); } static void visu_node_array_renderer_interface_init(VisuNodeArrayRendererInterface *iface) { iface->getNodeArray = _getNodeArray; iface->setNodeArray = _setNodeArray; iface->getElement = _getElementRenderer; iface->getExtent = _getMaxElementSize; iface->getColorizer = _getColorizer; iface->pushColorizer = _pushColorizer; iface->removeColorizer = _removeColorizer; } static void visu_gl_ext_nodes_init(VisuGlExtNodes *obj) { DBG_fprintf(stderr, "Extension Nodes: initializing a new object (%p).\n", (gpointer)obj); obj->priv = visu_gl_ext_nodes_get_instance_private(obj); obj->priv->dispose_has_run = FALSE; /* Private data. */ obj->priv->effect = VISU_ELEMENT_RENDERER_NO_EFFECT; obj->priv->glIds = g_array_new(FALSE, FALSE, sizeof(GlIds)); g_array_set_clear_func(obj->priv->glIds, (GDestroyNotify)_freeGlIds); obj->priv->nEle = 0; obj->priv->view = (VisuGlView*)0; obj->priv->dataObj = (VisuData*)0; obj->priv->popId = 0; obj->priv->posId = 0; obj->priv->popIncId = 0; obj->priv->popDecId = 0; obj->priv->visId = 0; obj->priv->boxId = 0; obj->priv->box = (VisuBox*)0; obj->priv->colorizers = (GList*)0; } /* This method can be called several times. It should unref all of its reference to GObjects. */ static void visu_gl_ext_nodes_dispose(GObject* obj) { VisuGlExtNodes *nodes; DBG_fprintf(stderr, "Extension Nodes: dispose object %p.\n", (gpointer)obj); nodes = VISU_GL_EXT_NODES(obj); if (nodes->priv->dispose_has_run) return; nodes->priv->dispose_has_run = TRUE; visu_gl_ext_nodes_setGlView(VISU_GL_EXT(nodes), (VisuGlView*)0); _setNodeArray(VISU_NODE_ARRAY_RENDERER(nodes), (VisuNodeArray*)0); _setColorizer(VISU_NODE_ARRAY_RENDERER(nodes), (VisuDataColorizer*)0); g_list_free_full(VISU_GL_EXT_NODES(nodes)->priv->colorizers, g_object_unref); /* Chain up to the parent class */ G_OBJECT_CLASS(visu_gl_ext_nodes_parent_class)->dispose(obj); } /* This method is called once only. */ static void visu_gl_ext_nodes_finalize(GObject* obj) { VisuGlExtNodesPrivate *nodes; g_return_if_fail(obj); DBG_fprintf(stderr, "Extension Nodes: finalize object %p.\n", (gpointer)obj); nodes = VISU_GL_EXT_NODES(obj)->priv; /* Free privs elements. */ DBG_fprintf(stderr, "Extension Nodes: free private nodes.\n"); g_array_free(nodes->glIds, TRUE); /* Chain up to the parent class */ DBG_fprintf(stderr, "Extension Nodes: chain to parent.\n"); G_OBJECT_CLASS(visu_gl_ext_nodes_parent_class)->finalize(obj); DBG_fprintf(stderr, "Extension Nodes: freeing ... OK.\n"); } static void visu_gl_ext_nodes_get_property(GObject* obj, guint property_id, GValue *value, GParamSpec *pspec) { VisuGlExtNodes *self = VISU_GL_EXT_NODES(obj); DBG_fprintf(stderr, "Extension Nodes: get property '%s' -> ", g_param_spec_get_name(pspec)); switch (property_id) { case DATA_PROP: g_value_set_object(value, self->priv->dataObj); DBG_fprintf(stderr, "%p.\n", g_value_get_object(value)); break; case TYPE_PROP: g_value_set_gtype(value, (self->priv->dataObj) ? G_OBJECT_TYPE(self->priv->dataObj) : G_TYPE_NONE); DBG_fprintf(stderr, "%d.\n", (gint)g_value_get_gtype(value)); break; case MAX_SIZE_PROP: g_value_set_float(value, visu_node_array_renderer_getMaxElementSize(VISU_NODE_ARRAY_RENDERER(obj), (guint*)0)); DBG_fprintf(stderr, "%g.\n", g_value_get_float(value)); break; case COLORIZER_PROP: g_value_set_object(value, self->priv->colorizers ? self->priv->colorizers->data : NULL); DBG_fprintf(stderr, "%p.\n", g_value_get_object(value)); break; default: /* We don't have any other property... */ G_OBJECT_WARN_INVALID_PROPERTY_ID(obj, property_id, pspec); break; } } static void visu_gl_ext_nodes_set_property(GObject* obj, guint property_id, const GValue *value, GParamSpec *pspec) { DBG_fprintf(stderr, "Extension Nodes: set property '%s' -> ", g_param_spec_get_name(pspec)); switch (property_id) { case DATA_PROP: DBG_fprintf(stderr, "%p\n", g_value_get_object(value)); visu_node_array_renderer_setNodeArray(VISU_NODE_ARRAY_RENDERER(obj), VISU_NODE_ARRAY(g_value_get_object(value))); break; case COLORIZER_PROP: DBG_fprintf(stderr, "%p.\n", g_value_get_object(value)); _pushColorizer(VISU_NODE_ARRAY_RENDERER(obj), g_value_get_object(value)); break; default: /* We don't have any other property... */ G_OBJECT_WARN_INVALID_PROPERTY_ID(obj, property_id, pspec); break; } } /** * visu_gl_ext_nodes_new: * * Creates a new #VisuGlExt to draw a set of nodes. It can be used * also for picking, see visu_gl_ext_nodes_getSelection(). * * Since: 3.7 * * Returns: a pointer to the VisuGlExt it created or * NULL otherwise. */ VisuGlExtNodes* visu_gl_ext_nodes_new() { char *name = VISU_GL_EXT_NODES_ID; char *description = _("Draw all the nodes."); DBG_fprintf(stderr,"Extension Nodes: new object.\n"); return g_object_new(VISU_TYPE_GL_EXT_NODES, "name", name, "label", _(name), "description", description, "nGlObj", 1, "priority", VISU_GL_EXT_PRIORITY_NODES, NULL); } static void visu_gl_ext_nodes_rebuild(VisuGlExt *ext) { VisuGlExtNodes *extNodes; VisuNodeArrayIter iter; GlIds *ids; guint i; extNodes = VISU_GL_EXT_NODES(ext); DBG_fprintf(stderr, "Extension Nodes: rebuilding object list for visuData %p.\n", (gpointer)extNodes->priv->dataObj); if (!extNodes->priv->dataObj) glDeleteLists(visu_gl_ext_getGlList(ext), 1); else { visu_node_array_iter_new(VISU_NODE_ARRAY(extNodes->priv->dataObj), &iter); createAllElements(extNodes); for (i = 0; i < extNodes->priv->glIds->len; i++) { ids = &g_array_index(extNodes->priv->glIds, GlIds, i); visu_element_renderer_rebuild(ids->renderer, extNodes->priv->view); } createAllNodes(extNodes); } visu_gl_ext_setDirty(ext, FALSE); } static gboolean _setGlIdRenderer(GlIds *ids, VisuElementRenderer *renderer, VisuGlExtNodes *ext) { DBG_fprintf(stderr, "Extension Nodes: defining renderer for %p.\n", (gpointer)ids); if (ids->renderer == renderer) return FALSE; if (ids->renderer) { g_signal_handler_disconnect(visu_element_renderer_getElement(ids->renderer), ids->colorize_sig); g_signal_handler_disconnect(ids->renderer, ids->notify_sig); g_signal_handler_disconnect(ids->renderer, ids->size_sig); visu_element_renderer_setGlView(ids->renderer, (VisuGlView*)0); DBG_fprintf(stderr, "Extension Nodes: free renderer %p.\n", (gpointer)ids->renderer); g_object_unref(ids->renderer); } ids->renderer = renderer; if (renderer) { g_return_val_if_fail(VISU_IS_GL_EXT_NODES(ext), FALSE); DBG_fprintf(stderr, "Extension Nodes: ref renderer %p.\n", (gpointer)renderer); g_object_ref(renderer); visu_element_renderer_setGlView(renderer, ext->priv->view); ids->notify_sig = g_signal_connect_swapped(renderer, "notify", G_CALLBACK(onRenderer), ext); ids->size_sig = g_signal_connect_swapped(renderer, "size-changed", G_CALLBACK(onSize), ext); ids->colorize_sig = g_signal_connect_swapped(visu_element_renderer_getElement(renderer), "notify::colorizable", G_CALLBACK(onColorize), ext); } return TRUE; } static void _freeGlIds(GlIds *ids) { DBG_fprintf(stderr, "Extension Nodes: free ids %p.\n", (gpointer)ids); _setGlIdRenderer(ids, (VisuElementRenderer*)0, (VisuGlExtNodes*)0); } static GlIds* _getGlIds(VisuGlExtNodes *ext, const VisuElement *element) { GlIds *ids; guint i; g_return_val_if_fail(VISU_IS_GL_EXT_NODES(ext), (GlIds*)0); for (i = 0; i < ext->priv->nEle; i++) { ids = &g_array_index(ext->priv->glIds, GlIds, i); if (visu_element_renderer_getElement(ids->renderer) == element) return ids; } return (GlIds*)0; } static GlIds* _getGlIdsByRenderer(VisuGlExtNodes *ext, const VisuElementRenderer *renderer) { GlIds *ids; guint i; g_return_val_if_fail(VISU_IS_GL_EXT_NODES(ext), (GlIds*)0); for (i = 0; i < ext->priv->nEle; i++) { ids = &g_array_index(ext->priv->glIds, GlIds, i); if (ids->renderer == renderer) return ids; } return (GlIds*)0; } /** * createAllElements: * @data: a #VisuData object. * @view: a #VisuGlView object. * * This method will call the visu_rendering_createElement() method of the * current #RenderingMethod on all the elements of the given #VisuData. */ static void createAllElements(VisuGlExtNodes *ext) { VisuNodeArray *array; GlIds *ids; guint i; guint len; GArray *elements; VisuElementRenderer *renderer; g_return_if_fail(VISU_IS_GL_EXT_NODES(ext)); array = VISU_NODE_ARRAY(ext->priv->dataObj); elements = (GArray*)0; if (array) g_object_get(G_OBJECT(array), "elements", &elements, NULL); ext->priv->nEle = elements ? elements->len : 0; DBG_fprintf(stderr, "Extension Nodes (%p): setup population at %d.\n", (gpointer)ext, ext->priv->nEle); if (ext->priv->nEle > ext->priv->glIds->len) { DBG_fprintf(stderr, " | increase nodes gl ids (%d).\n", ext->priv->glIds->len); len = ext->priv->glIds->len; /* Change glIds size according to nEle. */ ext->priv->glIds = g_array_set_size(ext->priv->glIds, ext->priv->nEle); for (; len < ext->priv->nEle; len++) { ids = &g_array_index(ext->priv->glIds, GlIds, len); ids->renderer = (VisuElementRenderer*)0; ids->material = visu_gl_objectlist_new(1); ids->nodes = visu_gl_objectlist_new(1); } } DBG_fprintf(stderr, "Extension Nodes: create OpenGl elements for" " all VisuElement used in given VisuNodeArray %p.\n", (gpointer)array); i = 0; if (array) { g_return_if_fail(ext->priv->glIds->len >= elements->len); for (; i < elements->len; i++) { ids = &g_array_index(ext->priv->glIds, GlIds, i); renderer = (VisuElementRenderer*)0; if (VISU_IS_DATA_SPIN(ext->priv->dataObj) && (!VISU_IS_ELEMENT_SPIN(ids->renderer) || visu_element_renderer_getElement(ids->renderer) != g_array_index(elements, VisuElement*, i))) { renderer = VISU_ELEMENT_RENDERER(visu_element_spin_new(g_array_index(elements, VisuElement*, i))); visu_element_spin_bindToPool(VISU_ELEMENT_SPIN(renderer)); } else if (VISU_IS_DATA_ATOMIC(ext->priv->dataObj) && ! VISU_IS_DATA_SPIN(ext->priv->dataObj) && (!VISU_IS_ELEMENT_ATOMIC(ids->renderer) || VISU_IS_ELEMENT_SPIN(ids->renderer) || visu_element_renderer_getElement(ids->renderer) != g_array_index(elements, VisuElement*, i))) { renderer = VISU_ELEMENT_RENDERER(visu_element_atomic_new(g_array_index(elements, VisuElement*, i))); visu_element_atomic_bindToPool(VISU_ELEMENT_ATOMIC(renderer)); if (ext->priv->box) visu_element_atomic_setUnits(VISU_ELEMENT_ATOMIC(renderer), visu_box_getUnit(ext->priv->box)); } if (renderer) { _setGlIdRenderer(ids, renderer, ext); g_object_unref(renderer); } if (ids->renderer) compileElementMaterial(ext, ids->material, ids->renderer); } } if (elements) g_array_unref(elements); ext->priv->glIds = g_array_set_size(ext->priv->glIds, ext->priv->nEle); DBG_fprintf(stderr, "Extension Nodes: creation done for all elements.\n"); } /** * createAllNodes: * @data: a #VisuData object. * * This create the glObjectList registered that contains all the * nodes. This glObjectList is made of all nodes of all element whose * attribute rendered is TRUE and translated to their own positions. */ static void createAllNodes(VisuGlExtNodes *ext) { guint i; #if DEBUG == 1 GTimer *timer; gulong fractionTimer; #endif g_return_if_fail(VISU_IS_GL_EXT_NODES(ext)); DBG_fprintf(stderr, "##### All node creation #####\n"); DBG_fprintf(stderr, "Extension Nodes: 'createAllNodes' called.\n"); #if DEBUG == 1 timer = g_timer_new(); g_timer_start(timer); #endif DBG_fprintf(stderr, "Extension Nodes: loop on elements.\n"); for (i = 0; i < ext->priv->nEle; i++) createNodes(ext, &g_array_index(ext->priv->glIds, GlIds, i)); DBG_fprintf(stderr, "Extension Nodes: OK.\n"); visu_gl_ext_startDrawing(VISU_GL_EXT(ext)); glEnable(GL_LIGHTING); glLineWidth(1); DBG_fprintf(stderr, "Extension Nodes: create nodes for %d elements.\n", ext->priv->nEle); for (i = 0; i < ext->priv->nEle; i++) { DBG_fprintf(stderr, " | call list %d.\n", g_array_index(ext->priv->glIds, GlIds, i).nodes); glCallList(g_array_index(ext->priv->glIds, GlIds, i).nodes); } visu_gl_ext_completeDrawing(VISU_GL_EXT(ext)); #if DEBUG == 1 g_timer_stop(timer); fprintf(stderr, "Extension Nodes: lists built in %g micro-s.\n", g_timer_elapsed(timer, &fractionTimer)/1e-6); g_timer_destroy(timer); #endif } static void compileElementMaterial(VisuGlExtNodes *ext, GLuint displayList, VisuElementRenderer *ele) { glNewList(displayList, GL_COMPILE); visu_element_renderer_colorize(ele, ext->priv->effect); glEndList(); } static void createNodes(VisuGlExtNodes *ext, GlIds *ids) { VisuNodeArrayIter iter; VisuElement *element; g_return_if_fail(VISU_IS_GL_EXT_NODES(ext)); element = visu_element_renderer_getElement(ids->renderer); DBG_fprintf(stderr, "Extension Nodes: create list of element '%s'.\n", element->name); DBG_fprintf(stderr, " | list of nodes %d.\n", ids->nodes); glNewList(ids->nodes, GL_COMPILE); if (visu_element_getRendered(element)) { DBG_fprintf(stderr, " | call material list %d.\n", ids->material); glCallList(ids->material); DBG_fprintf(stderr, "Extension Nodes: creating glObjectList of nodes for '%s' - %d.\n", element->name, ids->material); visu_node_array_iter_new(VISU_NODE_ARRAY(ext->priv->dataObj), &iter); iter.element = element; for(visu_node_array_iterRestartNode(VISU_NODE_ARRAY(ext->priv->dataObj), &iter); iter.node; visu_node_array_iterNextNode(VISU_NODE_ARRAY(ext->priv->dataObj), &iter)) if (iter.node->rendered) { glLoadName((GLuint)iter.node->number); visu_element_renderer_callAt(ids->renderer, _getColorizer(VISU_NODE_ARRAY_RENDERER(ext)), ext->priv->dataObj, iter.node); } } else DBG_fprintf(stderr, "Extension Nodes: skipping glObjectList of nodes for '%s' - %d.\n", element->name, ids->nodes); glEndList(); } static void _setBox(VisuGlExtNodes *nodes, VisuBox *box) { if (nodes->priv->box == box) return; if (nodes->priv->box) { g_signal_handler_disconnect(G_OBJECT(nodes->priv->box), nodes->priv->unitId); g_object_unref(G_OBJECT(nodes->priv->box)); } nodes->priv->box = box; if (box) { g_object_ref(G_OBJECT(box)); nodes->priv->unitId = g_signal_connect_swapped(G_OBJECT(box), "UnitChanged", G_CALLBACK(onUnits), nodes); onUnits(nodes, 0.f, nodes->priv->box); } } static void _setPopulation(VisuGlExtNodes *nodes) { createAllElements(nodes); g_signal_emit_by_name(nodes, "nodes::population", (GArray*)0); g_signal_emit_by_name(nodes, "nodes::population-set", (GArray*)0); } static gboolean _setNodeArray(VisuNodeArrayRenderer *self, VisuNodeArray *array) { VisuData *dataObj; VisuGlExtNodes *nodes; g_return_val_if_fail(VISU_IS_GL_EXT_NODES(self), FALSE); nodes = VISU_GL_EXT_NODES(self); dataObj = VISU_DATA(array); if (nodes->priv->dataObj == dataObj) return FALSE; if (nodes->priv->dataObj) { g_signal_handler_disconnect(nodes->priv->dataObj, nodes->priv->boxId); g_signal_handler_disconnect(nodes->priv->dataObj, nodes->priv->popId); g_signal_handler_disconnect(nodes->priv->dataObj, nodes->priv->posId); g_signal_handler_disconnect(nodes->priv->dataObj, nodes->priv->popIncId); g_signal_handler_disconnect(nodes->priv->dataObj, nodes->priv->popDecId); g_signal_handler_disconnect(nodes->priv->dataObj, nodes->priv->visId); if (nodes->priv->renId) g_signal_handler_disconnect(visu_method_spin_getDefault(), nodes->priv->renId); g_object_unref(nodes->priv->dataObj); } nodes->priv->dataObj = dataObj; nodes->priv->renId = 0; if (dataObj) { g_object_ref(dataObj); nodes->priv->boxId = g_signal_connect_swapped(G_OBJECT(dataObj), "setBox", G_CALLBACK(_setBox), (gpointer)nodes); nodes->priv->popId = g_signal_connect_swapped(G_OBJECT(dataObj), "notify::elements", G_CALLBACK(_setPopulation), (gpointer)nodes); nodes->priv->posId = g_signal_connect_after(G_OBJECT(dataObj), "position-changed", G_CALLBACK(onPositionChanged), (gpointer)nodes); nodes->priv->popIncId = g_signal_connect_after(G_OBJECT(dataObj), "PopulationIncrease", G_CALLBACK(onPopulationInc), (gpointer)nodes); nodes->priv->popDecId = g_signal_connect_after(G_OBJECT(dataObj), "PopulationDecrease", G_CALLBACK(onPopulationDec), (gpointer)nodes); nodes->priv->visId = g_signal_connect_after(dataObj, "visibility-changed", G_CALLBACK(onVisibilityChanged), (gpointer)nodes); if (VISU_IS_DATA_SPIN(dataObj)) nodes->priv->renId = g_signal_connect_swapped (G_OBJECT(visu_method_spin_getDefault()), "notify", G_CALLBACK(onRenderingChanged), nodes); } _setBox(nodes, (dataObj) ? visu_boxed_getBox(VISU_BOXED(dataObj)) : (VisuBox*)0); _setPopulation(nodes); if (_getColorizer(VISU_NODE_ARRAY_RENDERER(nodes))) visu_sourceable_follow(VISU_SOURCEABLE(_getColorizer(VISU_NODE_ARRAY_RENDERER(nodes))), dataObj); visu_gl_ext_setDirty(VISU_GL_EXT(nodes), TRUE); return TRUE; } /** * visu_gl_ext_nodes_setMaterialEffect: * @nodes: a #VisuGlExtNodes object. * @effect: a #VisuElementRendererEffects id. * * Changes the effect applied on the color used to render #VisuElement. * * Since: 3.7 * * Returns: TRUE if the effect has been changed. **/ gboolean visu_gl_ext_nodes_setMaterialEffect(VisuGlExtNodes *nodes, VisuElementRendererEffects effect) { g_return_val_if_fail(VISU_IS_GL_EXT_NODES(nodes), FALSE); if (nodes->priv->effect == effect) return FALSE; nodes->priv->effect = effect; createAllElements(nodes); return TRUE; } static VisuNodeArray* _getNodeArray(VisuNodeArrayRenderer *self) { g_return_val_if_fail(VISU_IS_GL_EXT_NODES(self), (VisuNodeArray*)0); return VISU_NODE_ARRAY(VISU_GL_EXT_NODES(self)->priv->dataObj); } static VisuElementRenderer* _getElementRenderer(VisuNodeArrayRenderer *self, const VisuElement *element) { GlIds *ids; g_return_val_if_fail(VISU_IS_GL_EXT_NODES(self), (VisuElementRenderer*)0); ids = _getGlIds(VISU_GL_EXT_NODES(self), element); if (!ids) return (VisuElementRenderer*)0; return ids->renderer; } static gfloat _getMaxElementSize(VisuNodeArrayRenderer *node_array, guint *n) { guint i; GlIds *ids; gfloat s; g_return_val_if_fail(VISU_IS_GL_EXT_NODES(node_array), 0.f); s = 0.f; for (i = 0; i < VISU_GL_EXT_NODES(node_array)->priv->nEle; i += 1) { ids = &g_array_index(VISU_GL_EXT_NODES(node_array)->priv->glIds, GlIds, i); if (ids->renderer) s = MAX(s, visu_element_renderer_getExtent(ids->renderer)); } if (n) *n = i; return s; } static void visu_gl_ext_nodes_draw(VisuGlExt *ext) { VisuGlExtNodes *nodes = VISU_GL_EXT_NODES(ext); glDeleteLists(visu_gl_ext_getGlList(VISU_GL_EXT(nodes)), 1); visu_gl_ext_setDirty(ext, FALSE); /* Nothing to draw; */ if(!nodes->priv->dataObj || !nodes->priv->view) return; createAllNodes(nodes); } static gboolean visu_gl_ext_nodes_setGlView(VisuGlExt *ext, VisuGlView *view) { VisuGlExtNodesPrivate *priv = VISU_GL_EXT_NODES(ext)->priv; guint i; GlIds *ids; if (priv->view == view) return FALSE; if (priv->view) { g_signal_handler_disconnect(priv->view, priv->detailsId); g_object_unref(priv->view); } if (view) { g_object_ref(view); priv->detailsId = g_signal_connect_swapped(G_OBJECT(view), "DetailLevelChanged", G_CALLBACK(_setDirty), ext); } priv->view = view; for (i = 0; i < priv->nEle; i += 1) { ids = &g_array_index(priv->glIds, GlIds, i); if (ids->renderer) visu_element_renderer_setGlView(ids->renderer, view); } visu_gl_ext_setDirty(ext, TRUE); return TRUE; } /********************/ /* Signal handlers. */ /********************/ static void _setDirty(VisuGlExt *ext) { DBG_fprintf(stderr, "Extension Nodes: set dirty.\n"); visu_gl_ext_setDirty(ext, TRUE); } static void onPopulationInc(VisuData *dataObj _U_, GArray *ids, gpointer data) { createAllNodes(VISU_GL_EXT_NODES(data)); g_signal_emit_by_name(data, "nodes::population", ids); g_signal_emit_by_name(data, "nodes::population-increase", ids); g_object_notify(G_OBJECT(data), "dirty"); } static void onPopulationDec(VisuData *dataObj _U_, GArray *ids, gpointer data) { createAllNodes(VISU_GL_EXT_NODES(data)); g_signal_emit_by_name(data, "nodes::population", ids); g_signal_emit_by_name(data, "nodes::population-decrease", ids); g_object_notify(G_OBJECT(data), "dirty"); } static void onColorize(VisuGlExtNodes *ext, GParamSpec *pspec _U_, VisuElement *element) { GlIds *ids; if (!_getColorizer(VISU_NODE_ARRAY_RENDERER(ext))) return; ids = _getGlIds(ext, element); g_return_if_fail(ids); createNodes(ext, ids); g_object_notify(G_OBJECT(ext), "dirty"); } static void onRenderer(VisuGlExtNodes *ext, GParamSpec *pspec, VisuElementRenderer *renderer) { gchar *sig; GlIds *ids; DBG_fprintf(stderr, "Extension Nodes: caught 'notify::%s' for ext %p.\n", g_param_spec_get_name(pspec), (gpointer)ext); ids = _getGlIdsByRenderer(ext, renderer); g_return_if_fail(ids); if (!strcmp(g_param_spec_get_name(pspec), "rendered") || !visu_element_renderer_featureMaterialCache(renderer)) createNodes(ext, ids); else compileElementMaterial(ext, ids->material, renderer); sig = g_strdup_printf("%s::%s", "element-notify", g_param_spec_get_name(pspec)); g_signal_emit_by_name(ext, sig, renderer); g_free(sig); g_object_notify(G_OBJECT(ext), "dirty"); } static void onSize(VisuGlExtNodes *ext, gfloat extent, VisuElementRenderer *renderer) { DBG_fprintf(stderr, "Extension Nodes: caught 'size-changed' for ext %p.\n", (gpointer)ext); g_signal_emit_by_name(ext, "element-size-changed", renderer, extent); g_object_notify(G_OBJECT(ext), "max-element-size"); } static void onPositionChanged(VisuData *dataObj _U_, GArray *ids, gpointer data) { VisuGlExtNodes *ext = VISU_GL_EXT_NODES(data); DBG_fprintf(stderr, "Extension Nodes: caught 'onPositionChanged'.\n"); /* if (ele) */ /* createNodes(ext, _getGlIds(ext, ele)); */ /* else */ createAllNodes(ext); g_signal_emit_by_name(data, "nodes::position", ids); g_object_notify(G_OBJECT(data), "dirty"); } static void onVisibilityChanged(VisuData *dataObj _U_, gpointer data) { createAllNodes(VISU_GL_EXT_NODES(data)); g_signal_emit_by_name(data, "nodes::visibility", (GArray*)0); g_object_notify(G_OBJECT(data), "dirty"); } static void onRenderingChanged(VisuGlExtNodes *nodes) { createAllNodes(nodes); g_object_notify(G_OBJECT(nodes), "dirty"); } static void onUnits(VisuGlExtNodes *ext, gfloat fact _U_, VisuBox *box) { guint i; GlIds *ids; ToolUnits units; if (!VISU_IS_DATA_ATOMIC(ext->priv->dataObj)) return; units = visu_box_getUnit(box); for (i = 0; i < ext->priv->nEle; i++) { ids = &g_array_index(ext->priv->glIds, GlIds, i); visu_element_atomic_setUnits(VISU_ELEMENT_ATOMIC(ids->renderer), units); } } /****************/ /* OpenGL pick. */ /****************/ static int _getSelection(VisuGlExtNodes *ext, VisuGlView *view, GLfloat x0, GLfloat y0, GLfloat w, GLfloat h, GLuint *select_buf, GLsizei bufsize) { float centre[3]; GLint viewport[4] = {0, 0, 0, 0}; int hits; g_return_val_if_fail(VISU_IS_GL_EXT_NODES(ext), 0); DBG_fprintf(stderr, "Extension Nodes: get nodes in region %gx%g - %gx%g.\n", x0, x0, w, h); if ((w == 0) || (h == 0)) return 0; visu_box_getCentre(visu_boxed_getBox(VISU_BOXED(view)), centre); glSelectBuffer(bufsize, select_buf); hits = glRenderMode(GL_SELECT); glInitNames(); glPushName(-1); viewport[2] = view->window.width; viewport[3] = view->window.height; glNewList(10, GL_COMPILE); gluPickMatrix(x0 , y0, w, h, viewport); glEndList(); glMatrixMode(GL_PROJECTION); glPushMatrix(); glLoadIdentity(); glCallList(10); glFrustum(view->window.left, view->window.right, view->window.bottom, view->window.top, view->window.near, view->window.far); glMatrixMode(GL_MODELVIEW); glPushMatrix(); glTranslated(-centre[0], -centre[1], -centre[2]); glCallList(visu_gl_ext_getGlList(VISU_GL_EXT(ext))); glFlush(); hits = glRenderMode(GL_RENDER); DBG_fprintf(stderr, "%d elements are on the z buffer %gx%g - %gx%g.\n", hits, x0, y0, w, h); /* return the buffer to normal */ glPopMatrix(); glMatrixMode(GL_PROJECTION); glPopMatrix(); glMatrixMode(GL_MODELVIEW); return hits; } /** * visu_gl_ext_nodes_getSelectionByRegion: * @ext: a #VisuGlExtNodes object; * @x1: a window coordinate; * @y1: a window coordinate; * @x2: a window coordinate; * @y2: a window coordinate. * * Get the #VisuNode ids in the picked region defined by (x1, y1) - * (x2, y2). * * Since: 3.7 * * Returns: (transfer full) (element-type guint): an empty list if no * node found, or a newly created list of ids if any. **/ GArray* visu_gl_ext_nodes_getSelectionByRegion(VisuGlExtNodes *ext, int x1, int y1, int x2, int y2) { GArray *ids; int i, hits, ptr, names; guint id; GLuint *select_buf; GLsizei bufsize; g_return_val_if_fail(VISU_IS_GL_EXT_NODES(ext) && ext->priv->dataObj, (GArray*)0); bufsize = visu_node_array_getNNodes(VISU_NODE_ARRAY(ext->priv->dataObj)) * 4; select_buf = g_malloc(sizeof(GLuint) * bufsize); hits = _getSelection(ext, ext->priv->view, 0.5f * (x1 + x2), (float)ext->priv->view->window.height - 0.5f * (y1 + y2), (float)ABS(x2 - x1), (float)ABS(y2 - y1), select_buf, bufsize); ids = g_array_new(FALSE, FALSE, sizeof(guint)); ptr = 0; for(i = 0; i < hits; i++) { names = select_buf[ptr]; if (names != 1) { g_warning("OpenGL picking is not working???\n"); g_array_unref(ids); return (GArray*)0; } ptr += 3; id = select_buf[ptr]; g_array_append_val(ids, id); ptr += 1; } g_free(select_buf); return ids; } /** * visu_gl_ext_nodes_getSelection: * @ext: a #VisuGlExtNodes object; * @x: a window coordinate; * @y: a window coordinate. * * Get the id of a #VisuNode on top of the z-buffer. * * Since: 3.7 * * Returns: -1 if no node found, or its id. **/ int visu_gl_ext_nodes_getSelection(VisuGlExtNodes *ext, int x, int y) { int i, hits, ptr, names, number; GLuint *select_buf; GLsizei bufsize; unsigned int z1; unsigned int z1_sauve = UINT_MAX; g_return_val_if_fail(VISU_IS_GL_EXT_NODES(ext) && ext->priv->dataObj, -1); bufsize = visu_node_array_getNNodes(VISU_NODE_ARRAY(ext->priv->dataObj)) * 4; select_buf = g_malloc(sizeof(GLuint) * bufsize); hits = _getSelection(ext, ext->priv->view, x, (float)ext->priv->view->window.height - y, 2.f, 2.f, select_buf, bufsize); ptr = 0; number = -1; for(i = 0; i < hits; i++) { names = select_buf[ptr]; if (names != 1) { g_warning("OpenGL picking is not working???\n"); return -1; } ptr = ptr + 1; z1 = select_buf[ptr]; DBG_fprintf(stderr, " | z position %f for %d\n", (float)z1/0x7fffffff, (int)select_buf[ptr + 2]); ptr = ptr + 2; if (z1 < z1_sauve) { z1_sauve = z1; number = (int)select_buf[ptr]; } ptr = ptr + 1; } return number; } static void _setColorizer(VisuNodeArrayRenderer *nodes, VisuDataColorizer *colorizer) { VisuGlExtNodes *self; g_return_if_fail(VISU_IS_GL_EXT_NODES(nodes)); self = VISU_GL_EXT_NODES(nodes); if (_getColorizer(nodes) == colorizer) return; if (_getColorizer(nodes)) { g_signal_handler_disconnect(_getColorizer(nodes), self->priv->dirtyId); g_object_unref(_getColorizer(nodes)); } if (colorizer) { g_object_ref(colorizer); self->priv->dirtyId = g_signal_connect_swapped(colorizer, "dirty", G_CALLBACK(onRenderingChanged), self); visu_sourceable_follow(VISU_SOURCEABLE(colorizer), self->priv->dataObj); } return; } static gboolean _pushColorizer(VisuNodeArrayRenderer *nodes, VisuDataColorizer *colorizer) { GList *elem; VisuGlExtNodes *self; g_return_val_if_fail(VISU_IS_GL_EXT_NODES(nodes), FALSE); self = VISU_GL_EXT_NODES(nodes); if (_getColorizer(nodes) == colorizer) return FALSE; if ((elem = g_list_find(self->priv->colorizers, colorizer))) { g_object_unref(elem->data); self->priv->colorizers = g_list_delete_link(self->priv->colorizers, elem); } _setColorizer(nodes, colorizer); self->priv->colorizers = g_list_prepend(self->priv->colorizers, colorizer); g_object_ref(colorizer); onRenderingChanged(self); return TRUE; } static gboolean _removeColorizer(VisuNodeArrayRenderer *nodes, VisuDataColorizer *colorizer) { GList *elem; VisuGlExtNodes *self; g_return_val_if_fail(VISU_IS_GL_EXT_NODES(nodes), FALSE); self = VISU_GL_EXT_NODES(nodes); if (_getColorizer(nodes) != colorizer) { if ((elem = g_list_find(self->priv->colorizers, colorizer))) { g_object_unref(elem->data); self->priv->colorizers = g_list_delete_link(self->priv->colorizers, elem); } return FALSE; } _setColorizer(nodes, self->priv->colorizers->next ? self->priv->colorizers->next->data : (VisuDataColorizer*)0); self->priv->colorizers = g_list_delete_link(self->priv->colorizers, self->priv->colorizers); g_object_unref(colorizer); onRenderingChanged(self); return TRUE; } static VisuDataColorizer* _getColorizer(VisuNodeArrayRenderer *nodes) { g_return_val_if_fail(VISU_IS_GL_EXT_NODES(nodes), (VisuDataColorizer*)0); return VISU_GL_EXT_NODES(nodes)->priv->colorizers ? VISU_GL_EXT_NODES(nodes)->priv->colorizers->data : (VisuDataColorizer*)0; } v_sim-3.8.0/src/extensions/nodes.h000066400000000000000000000071071370110300500171010ustar00rootroot00000000000000/* EXTRAITS DE LA LICENCE Copyright CEA, contributeurs : Damien CALISTE, laboratoire L_Sim, (2013-2019) Adresse mèl : CALISTE, damien P caliste AT cea P fr. Ce logiciel est un programme informatique servant à visualiser des structures atomiques dans un rendu pseudo-3D. Ce logiciel est régi par la licence CeCILL soumise au droit français et respectant les principes de diffusion des logiciels libres. Vous pouvez utiliser, modifier et/ou redistribuer ce programme sous les conditions de la licence CeCILL telle que diffusée par le CEA, le CNRS et l'INRIA sur le site "http://www.cecill.info". Le fait que vous puissiez accéder à cet en-tête signifie que vous avez pris connaissance de la licence CeCILL, et que vous en avez accepté les termes (cf. le fichier Documentation/licence.fr.txt fourni avec ce logiciel). */ /* LICENCE SUM UP Copyright CEA, contributors : Damien CALISTE, laboratoire L_Sim, (2013-2019) E-mail address: CALISTE, damien P caliste AT cea P fr. This software is a computer program whose purpose is to visualize atomic configurations in 3D. This software is governed by the CeCILL license under French law and abiding by the rules of distribution of free software. You can use, modify and/ or redistribute the software under the terms of the CeCILL license as circulated by CEA, CNRS and INRIA at the following URL "http://www.cecill.info". The fact that you are presently reading this means that you have had knowledge of the CeCILL license and that you accept its terms. You can find a copy of this licence shipped with this software at Documentation/licence.en.txt. */ #ifndef NODES_H #define NODES_H #include #include #include G_BEGIN_DECLS #define VISU_TYPE_GL_EXT_NODES (visu_gl_ext_nodes_get_type ()) #define VISU_GL_EXT_NODES(obj) (G_TYPE_CHECK_INSTANCE_CAST(obj, VISU_TYPE_GL_EXT_NODES, VisuGlExtNodes)) #define VISU_GL_EXT_NODES_CLASS(klass) (G_TYPE_CHECK_CLASS_CAST(klass, VISU_TYPE_GL_EXT_NODES, VisuGlExtNodesClass)) #define VISU_IS_GL_EXT_NODES(obj) (G_TYPE_CHECK_INSTANCE_TYPE(obj, VISU_TYPE_GL_EXT_NODES)) #define VISU_IS_GL_EXT_NODES_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE(klass, VISU_TYPE_GL_EXT_NODES)) #define VISU_GL_EXT_NODES_GET_CLASS(obj) (G_TYPE_INSTANCE_GET_CLASS(obj, VISU_TYPE_GL_EXT_NODES, VisuGlExtNodesClass)) typedef struct _VisuGlExtNodes VisuGlExtNodes; typedef struct _VisuGlExtNodesPrivate VisuGlExtNodesPrivate; typedef struct _VisuGlExtNodesClass VisuGlExtNodesClass; /** * VisuGlExtNodes: * * An opaque structure. * * Since: 3.7 */ struct _VisuGlExtNodes { VisuGlExt parent; VisuGlExtNodesPrivate *priv; }; /** * VisuGlExtNodesClass: * @parent: the parent class; * * A short way to identify #_VisuGlExtNodesClass structure. * * Since: 3.7 */ struct _VisuGlExtNodesClass { VisuGlExtClass parent; }; /** * visu_gl_ext_nodes_get_type: * * This method returns the type of #VisuGlExtNodes, use * VISU_TYPE_GL_EXT_NODES instead. * * Since: 3.7 * * Returns: the type of #VisuGlExtNodes. */ GType visu_gl_ext_nodes_get_type(void); VisuGlExtNodes* visu_gl_ext_nodes_new(); gboolean visu_gl_ext_nodes_setMaterialEffect(VisuGlExtNodes *nodes, VisuElementRendererEffects effect); GArray* visu_gl_ext_nodes_getSelectionByRegion(VisuGlExtNodes *ext, int x1, int y1, int x2, int y2); int visu_gl_ext_nodes_getSelection(VisuGlExtNodes *ext, int x, int y); G_END_DECLS #endif v_sim-3.8.0/src/extensions/pairs.c000066400000000000000000001031061370110300500170760ustar00rootroot00000000000000/* EXTRAITS DE LA LICENCE Copyright CEA, contributeurs : Damien CALISTE, laboratoire L_Sim, (2001-2009) Adresse mèl : CALISTE, damien P caliste AT cea P fr. Ce logiciel est un programme informatique servant à visualiser des structures atomiques dans un rendu pseudo-3D. Ce logiciel est régi par la licence CeCILL soumise au droit français et respectant les principes de diffusion des logiciels libres. Vous pouvez utiliser, modifier et/ou redistribuer ce programme sous les conditions de la licence CeCILL telle que diffusée par le CEA, le CNRS et l'INRIA sur le site "http://www.cecill.info". Le fait que vous puissiez accéder à cet en-tête signifie que vous avez pris connaissance de la licence CeCILL, et que vous en avez accepté les termes (cf. le fichier Documentation/licence.fr.txt fourni avec ce logiciel). */ /* LICENCE SUM UP Copyright CEA, contributors : Damien CALISTE, laboratoire L_Sim, (2001-2009) E-mail address: CALISTE, damien P caliste AT cea P fr. This software is a computer program whose purpose is to visualize atomic configurations in 3D. This software is governed by the CeCILL license under French law and abiding by the rules of distribution of free software. You can use, modify and/ or redistribute the software under the terms of the CeCILL license as circulated by CEA, CNRS and INRIA at the following URL "http://www.cecill.info". The fact that you are presently reading this means that you have had knowledge of the CeCILL license and that you accept its terms. You can find a copy of this licence shipped with this software at COPYING. */ #include "pairs.h" #include #include #include #include #include #include #include #include /** * SECTION:pairs * @short_description: Draw links between nodes. * * This extension draws links between nodes, depending on * #VisuPairLinkRenderer drawing capabilities. * * Since: 3.7 */ /** * VisuGlExtPairsClass: * @parent: the parent class; * * A short way to identify #_VisuGlExtPairsClass structure. * * Since: 3.7 */ /** * VisuGlExtPairs: * * An opaque structure. * * Since: 3.7 */ /** * VisuGlExtPairsPrivate: * * Private fields for #VisuGlExtPairs objects. * * Since: 3.7 */ struct _VisuGlExtPairsPrivate { gboolean dispose_has_run; /* Pairs definition. */ VisuNodeArrayRenderer *nodeRenderer; VisuData *data; gulong popInc_signal, popDec_signal; gulong visChg_signal, posChg_signal; VisuPairSet *pairs; gulong link_signal; GArray *links; /* Contains all drawn links, through struct _LinkData. */ GHashTable *linkRenderers; /* Contains an association link -> renderer for all links, not just drawn. */ /* Renderer listeners. */ GList *renderers; VisuPairLinkRenderer *defaultRenderer; GHashTable *rendererData; }; struct _RendererData { VisuPairLinkRenderer *renderer; guint usage; gulong dirty_sig; }; struct _LinkData { VisuPairLink *link; gulong param_sig; VisuNodeArrayRenderer *nodes; VisuElementRenderer *ele1, *ele2; VisuPair *pair; struct _RendererData *rdt; GLuint id; gboolean dirty; }; static VisuGlExtPairs *defaultPairs = NULL; static GArray *glIds; #define BOND_PROP_ID _("Bonds") #define FLAG_RESOURCES_PAIRS "pairs_are_on" #define DESC_RESOURCES_PAIRS "Ask the opengl engine to draw pairs between elements ; boolean 0 or 1" static gboolean pairsAreOn = FALSE; #define FLAG_RESOURCES_FAV_PAIRS "pairs_favoriteMethod" #define DESC_RESOURCES_FAV_PAIRS "Favorite method used to render files ; string" static gchar *favRenderer = NULL; #define FLAG_RESOURCES_PAIRS_DATA "pair_data" #define DESC_RESOURCES_PAIRS_DATA "Draw pairs between [ele1] [ele2] [0. <= dmin] [0. <= dmax] [0. <= RGB <= 1.]x3" #define FLAG_RESOURCES_PAIR_LINK "pair_link" #define DESC1_RESOURCES_PAIR_LINK "Draw a link between [ele1] [ele2] [0. <= dmin] [0. <= dmax]" #define DESC2_RESOURCES_PAIR_LINK " [0. <= RGB <= 1.]x3 [bool: drawn] [bool: printLength] [string: method]" static GHashTable *_linkRenderers; static void exportResourcesPairs(GString *data, VisuData *dataObj); static void visu_gl_ext_pairs_finalize(GObject* obj); static void visu_gl_ext_pairs_dispose(GObject* obj); static void visu_gl_ext_pairs_rebuild(VisuGlExt *ext); static void visu_gl_ext_pairs_draw(VisuGlExt *pairs); static gboolean visu_gl_ext_pairs_setGlView(VisuGlExt *pairs, VisuGlView *view); enum { RENDERER_SIGNAL, LAST_SIGNAL }; static guint _signals[LAST_SIGNAL] = { 0 }; /* Local callbacks. */ static void onLinkNotified(VisuGlExtPairs *ext, GParamSpec *pspec, VisuPairLink *link); static void onDirtyRenderer(VisuGlExtPairs *ext, VisuPairLinkRenderer *renderer); static void onPairsNotified(VisuGlExtPairs *ext, GParamSpec *pspec, VisuPairSet *pairs); static void onLinksChanged(VisuGlExtPairs *ext, VisuPair *pair, VisuPairSet *pairs); static void _setDirty(VisuGlExtPairs *ext); static void onActiveChanged(VisuGlExtPairs *pairs, GParamSpec *pspec, gpointer data); static void onEntryUsed(VisuGlExtPairs *pairs, VisuConfigFileEntry *entry, VisuConfigFile *obj); static void onEntryFav(VisuGlExtPairs *pairs, VisuConfigFileEntry *entry, VisuConfigFile *obj); static void onEntryLink(VisuConfigFile *obj, VisuConfigFileEntry *entry, gpointer data); /* Local routines. */ static gboolean _setLinkRenderer(VisuGlExtPairs *pairs, struct _LinkData *dt, VisuPairLinkRenderer *renderer); static VisuPairLinkRenderer* _rendererByName(VisuGlExtPairs *pairs, const gchar *name); G_DEFINE_TYPE_WITH_CODE(VisuGlExtPairs, visu_gl_ext_pairs, VISU_TYPE_GL_EXT, G_ADD_PRIVATE(VisuGlExtPairs)) static void visu_gl_ext_pairs_class_init(VisuGlExtPairsClass *klass) { VisuConfigFileEntry *resourceEntry, *oldEntry; DBG_fprintf(stderr, "Extension Pairs: creating the class of the object.\n"); DBG_fprintf(stderr, " - adding new signals ;\n"); /** * VisuGlExtPairs::renderer-changed: * @ext: the object which emits the signal ; * @link: the #VisuPairLink which is changed. * * Gets emitted when the renderer used for @link is changed. * * Since: 3.8 */ _signals[RENDERER_SIGNAL] = g_signal_new("renderer-changed", G_TYPE_FROM_CLASS(klass), G_SIGNAL_RUN_LAST | G_SIGNAL_NO_RECURSE | G_SIGNAL_NO_HOOKS, 0 , NULL, NULL, g_cclosure_marshal_VOID__OBJECT, G_TYPE_NONE, 1, VISU_TYPE_PAIR_LINK); /* Add resources. */ visu_config_file_addBooleanEntry(VISU_CONFIG_FILE_RESOURCE, FLAG_RESOURCES_PAIRS, DESC_RESOURCES_PAIRS, &pairsAreOn, FALSE); visu_config_file_addStringEntry(VISU_CONFIG_FILE_RESOURCE, FLAG_RESOURCES_FAV_PAIRS, DESC_RESOURCES_FAV_PAIRS, &favRenderer); oldEntry = visu_config_file_addEntry(VISU_CONFIG_FILE_RESOURCE, FLAG_RESOURCES_PAIRS_DATA, DESC_RESOURCES_PAIRS_DATA, 1, NULL); resourceEntry = visu_config_file_addTokenizedEntry(VISU_CONFIG_FILE_RESOURCE, FLAG_RESOURCES_PAIR_LINK, DESC1_RESOURCES_PAIR_LINK, TRUE); visu_config_file_entry_setVersion(resourceEntry, 3.4f); visu_config_file_entry_setReplace(resourceEntry, oldEntry); visu_config_file_addExportFunction(VISU_CONFIG_FILE_RESOURCE, exportResourcesPairs); g_signal_connect(VISU_CONFIG_FILE_RESOURCE, "parsed::" FLAG_RESOURCES_PAIR_LINK, G_CALLBACK(onEntryLink), (gpointer)0); /* Connect the overloading methods. */ G_OBJECT_CLASS(klass)->dispose = visu_gl_ext_pairs_dispose; G_OBJECT_CLASS(klass)->finalize = visu_gl_ext_pairs_finalize; VISU_GL_EXT_CLASS(klass)->rebuild = visu_gl_ext_pairs_rebuild; VISU_GL_EXT_CLASS(klass)->draw = visu_gl_ext_pairs_draw; VISU_GL_EXT_CLASS(klass)->setGlView = visu_gl_ext_pairs_setGlView; g_type_class_ref(VISU_TYPE_PAIR_LINK); glIds = g_array_new(FALSE, FALSE, sizeof(GLuint)); _linkRenderers = g_hash_table_new_full(g_direct_hash, g_direct_equal, NULL, g_free); } static void _addLink(VisuPair *pair, VisuPairLink *link, gpointer data) { VisuGlExtPairs *ext = VISU_GL_EXT_PAIRS(data); struct _LinkData dt; guint i; GLuint id; VisuElement *ele; VisuPairLinkRenderer *renderer; gchar *name; DBG_fprintf(stderr, " | adding link %p\n", (gpointer)link); if (ext->priv->links->len >= glIds->len) for (i = glIds->len; i <= ext->priv->links->len; i++) { id = visu_gl_objectlist_new(1); g_array_append_val(glIds, id); } renderer = (VisuPairLinkRenderer*)g_hash_table_lookup(ext->priv->linkRenderers, link); if (!renderer) { name = (gchar*)g_hash_table_lookup(_linkRenderers, link); if (name) renderer = _rendererByName(ext, name); } dt.id = g_array_index(glIds, GLuint, ext->priv->links->len); dt.link = g_object_ref(link); dt.param_sig = g_signal_connect_swapped(G_OBJECT(link), "notify", G_CALLBACK(onLinkNotified), ext); dt.nodes = ext->priv->nodeRenderer; ele = visu_pair_link_getFirstElement(dt.link); dt.ele1 = visu_node_array_renderer_get(ext->priv->nodeRenderer, ele); g_object_unref(ele); ele = visu_pair_link_getSecondElement(dt.link); dt.ele2 = visu_node_array_renderer_get(ext->priv->nodeRenderer, ele); g_object_unref(ele); dt.pair = pair; dt.dirty = TRUE; dt.rdt = g_hash_table_lookup(ext->priv->rendererData, (renderer) ? renderer : ext->priv->defaultRenderer); if (!dt.rdt->usage) g_signal_handler_unblock(G_OBJECT(dt.rdt->renderer), dt.rdt->dirty_sig); dt.rdt->usage += 1; g_array_append_val(ext->priv->links, dt); } static void _freeLink(struct _LinkData *dt) { g_signal_handler_disconnect(G_OBJECT(dt->link), dt->param_sig); g_clear_object(&dt->link); dt->rdt->usage -= 1; if (!dt->rdt->usage) g_signal_handler_block(G_OBJECT(dt->rdt->renderer), dt->rdt->dirty_sig); } static void _freeRendererData(struct _RendererData *dt) { DBG_fprintf(stderr, "Extension Pairs: deleting sig %lu on %p (%d).\n", dt->dirty_sig, (gpointer)dt->renderer, G_OBJECT(dt->renderer)->ref_count); g_signal_handler_disconnect(G_OBJECT(dt->renderer), dt->dirty_sig); g_object_unref(dt->renderer); } static void visu_gl_ext_pairs_init(VisuGlExtPairs *obj) { GList *renderer; struct _RendererData *dt; gchar *id; DBG_fprintf(stderr, "Extension Pairs: initializing a new object (%p).\n", (gpointer)obj); obj->priv = visu_gl_ext_pairs_get_instance_private(obj); obj->priv->dispose_has_run = FALSE; /* Private data. */ obj->priv->data = (VisuData*)0; obj->priv->popInc_signal = 0; obj->priv->popDec_signal = 0; obj->priv->visChg_signal = 0; obj->priv->posChg_signal = 0; obj->priv->pairs = visu_pair_set_new(); g_signal_connect_object(obj->priv->pairs, "notify::pairs", G_CALLBACK(onPairsNotified), obj, G_CONNECT_SWAPPED); g_signal_connect_object(obj->priv->pairs, "links-changed", G_CALLBACK(onLinksChanged), obj, G_CONNECT_SWAPPED); obj->priv->links = g_array_new(FALSE, FALSE, sizeof(struct _LinkData)); g_array_set_clear_func(obj->priv->links, (GDestroyNotify)_freeLink); obj->priv->linkRenderers = g_hash_table_new(g_direct_hash, g_direct_equal); obj->priv->rendererData = g_hash_table_new_full(g_direct_hash, g_direct_equal, NULL, (GDestroyNotify)_freeRendererData); obj->priv->renderers = (GList*)0; obj->priv->renderers = g_list_append(obj->priv->renderers, visu_pair_wire_renderer_new()); obj->priv->renderers = g_list_append(obj->priv->renderers, visu_pair_cylinder_renderer_new()); obj->priv->defaultRenderer = VISU_PAIR_LINK_RENDERER(obj->priv->renderers->data); for (renderer = obj->priv->renderers; renderer; renderer = g_list_next(renderer)) { dt = g_malloc(sizeof(struct _RendererData)); g_object_ref(renderer->data); dt->renderer = VISU_PAIR_LINK_RENDERER(renderer->data); dt->usage = 0; dt->dirty_sig = g_signal_connect_object(G_OBJECT(renderer->data), "dirty", G_CALLBACK(onDirtyRenderer), obj, G_CONNECT_SWAPPED); g_signal_handler_block(G_OBJECT(renderer->data), dt->dirty_sig); DBG_fprintf(stderr, "Extension Pairs: creating sig %lu on %p.\n", dt->dirty_sig, renderer->data); g_hash_table_insert(obj->priv->rendererData, renderer->data, dt); if (favRenderer) { g_object_get(dt->renderer, "id", &id, NULL); if (!g_ascii_strcasecmp(id, favRenderer)) obj->priv->defaultRenderer = dt->renderer; g_free(id); } } g_signal_connect(G_OBJECT(obj), "notify::active", G_CALLBACK(onActiveChanged), (gpointer)0); g_signal_connect_object(VISU_CONFIG_FILE_RESOURCE, "parsed::" FLAG_RESOURCES_PAIRS, G_CALLBACK(onEntryUsed), (gpointer)obj, G_CONNECT_SWAPPED); g_signal_connect_object(VISU_CONFIG_FILE_RESOURCE, "parsed::" FLAG_RESOURCES_FAV_PAIRS, G_CALLBACK(onEntryFav), (gpointer)obj, G_CONNECT_SWAPPED); if (!defaultPairs) defaultPairs = obj; } /* This method can be called several times. It should unref all of its reference to GObjects. */ static void visu_gl_ext_pairs_dispose(GObject* obj) { VisuGlExtPairs *pairs; DBG_fprintf(stderr, "Extension Pairs: dispose object %p.\n", (gpointer)obj); pairs = VISU_GL_EXT_PAIRS(obj); if (pairs->priv->dispose_has_run) return; pairs->priv->dispose_has_run = TRUE; /* Disconnect signals. */ DBG_fprintf(stderr, "Extension Pairs: connected Data has %d ref count.\n", (pairs->priv->data)?G_OBJECT(pairs->priv->data)->ref_count:0); visu_gl_ext_pairs_setData(pairs, (VisuData*)0); visu_gl_ext_pairs_setDataRenderer(pairs, (VisuNodeArrayRenderer*)0); g_object_unref(pairs->priv->pairs); /* Need to do it here, because the structures contains signals that must be disconnected first. */ g_hash_table_remove_all(pairs->priv->rendererData); /* Chain up to the parent class */ G_OBJECT_CLASS(visu_gl_ext_pairs_parent_class)->dispose(obj); } /* This method is called once only. */ static void visu_gl_ext_pairs_finalize(GObject* obj) { VisuGlExtPairs *pairs; g_return_if_fail(obj); DBG_fprintf(stderr, "Extension Pairs: finalize object %p.\n", (gpointer)obj); pairs = VISU_GL_EXT_PAIRS(obj); /* Free privs elements. */ DBG_fprintf(stderr, "Extension Pairs: free private pairs.\n"); g_array_free(pairs->priv->links, TRUE); g_hash_table_destroy(pairs->priv->linkRenderers); g_hash_table_destroy(pairs->priv->rendererData); g_list_free_full(pairs->priv->renderers, (GDestroyNotify)g_object_unref); /* Chain up to the parent class */ DBG_fprintf(stderr, "Extension Pairs: chain to parent.\n"); G_OBJECT_CLASS(visu_gl_ext_pairs_parent_class)->finalize(obj); DBG_fprintf(stderr, "Extension Pairs: freeing ... OK.\n"); } /** * visu_gl_ext_pairs_new: * @name: (allow-none): the name to give to the extension (default is #VISU_GL_EXT_PAIRS_ID). * * Creates a new #VisuGlExt to draw a pairs. * * Since: 3.7 * * Returns: a pointer to the #VisuGlExt it created or * NULL otherwise. */ VisuGlExtPairs* visu_gl_ext_pairs_new(const gchar *name) { char *name_ = VISU_GL_EXT_PAIRS_ID; char *description = _("Draw pairs between elements with a criterion of distance."); DBG_fprintf(stderr,"Extension Pairs: new object.\n"); return g_object_new(VISU_TYPE_GL_EXT_PAIRS, "name", (name) ? name : name_, "label", (name) ? name : _(name_), "description", description, "nGlObj", 1, "active", pairsAreOn, NULL); } static void _addBondValues(VisuData *data, const gchar *label) { VisuNodeValues *bonds; bonds = visu_node_values_new(VISU_NODE_ARRAY(data), label, G_TYPE_INT, 1); visu_node_values_setEditable(bonds, FALSE); visu_data_addNodeProperties(data, bonds); } /** * visu_gl_ext_pairs_setDataRenderer: * @pairs: a #VisuGlExtPairs object. * @renderer: a #VisuNodeArrayRenderer object. * * Specify the @renderer that may be used to draw pairs in the same * colour and material than elements. * * Since: 3.8 * * Returns: TRUE if value is actually changed. **/ gboolean visu_gl_ext_pairs_setDataRenderer(VisuGlExtPairs *pairs, VisuNodeArrayRenderer *renderer) { g_return_val_if_fail(VISU_IS_GL_EXT_PAIRS(pairs), FALSE); if (pairs->priv->nodeRenderer == renderer) return FALSE; if (pairs->priv->nodeRenderer) g_object_unref(pairs->priv->nodeRenderer); pairs->priv->nodeRenderer = renderer; if (renderer) g_object_ref(renderer); return TRUE; } /** * visu_gl_ext_pairs_getDataRenderer: * @pairs: a #VisuGlExtPairs object. * * Retrieve the #VisuNodeArrayRenderer this @pairs is using the * rendering properties from. * * Since: 3.8 * * Returns: (transfer none): the #VisuNodeArrayRenderer this @pairs is * using the rendering properties from. **/ VisuNodeArrayRenderer* visu_gl_ext_pairs_getDataRenderer(VisuGlExtPairs *pairs) { g_return_val_if_fail(VISU_IS_GL_EXT_PAIRS(pairs), (VisuNodeArrayRenderer*)0); return pairs->priv->nodeRenderer; } /** * visu_gl_ext_pairs_setData: * @pairs: The #VisuGlExtPairs to attached to. * @data: the nodes to get the population of. * * Attach a #VisuData to render to and setup the pairs to get the * node population also. * * Since: 3.7 * * Returns: TRUE if @data is actually changed. **/ gboolean visu_gl_ext_pairs_setData(VisuGlExtPairs *pairs, VisuData *data) { g_return_val_if_fail(VISU_IS_GL_EXT_PAIRS(pairs), FALSE); if (pairs->priv->data) { g_signal_handler_disconnect(G_OBJECT(pairs->priv->data), pairs->priv->popInc_signal); g_signal_handler_disconnect(G_OBJECT(pairs->priv->data), pairs->priv->popDec_signal); g_signal_handler_disconnect(G_OBJECT(pairs->priv->data), pairs->priv->visChg_signal); g_signal_handler_disconnect(G_OBJECT(pairs->priv->data), pairs->priv->posChg_signal); visu_data_removeNodeProperties(pairs->priv->data, BOND_PROP_ID); g_object_unref(pairs->priv->data); } if (data) { g_object_ref(data); pairs->priv->popInc_signal = g_signal_connect_swapped(G_OBJECT(data), "PopulationIncrease", G_CALLBACK(_setDirty), (gpointer)pairs); pairs->priv->popDec_signal = g_signal_connect_swapped(G_OBJECT(data), "PopulationDecrease", G_CALLBACK(_setDirty), (gpointer)pairs); pairs->priv->visChg_signal = g_signal_connect_swapped(data, "visibility-changed", G_CALLBACK(_setDirty), (gpointer)pairs); pairs->priv->posChg_signal = g_signal_connect_swapped(G_OBJECT(data), "position-changed", G_CALLBACK(_setDirty), (gpointer)pairs); if (visu_gl_ext_getActive(VISU_GL_EXT(pairs))) _addBondValues(data, BOND_PROP_ID); } pairs->priv->data = data; visu_pair_set_setModel(pairs->priv->pairs, data); visu_gl_ext_setDirty(VISU_GL_EXT(pairs), TRUE); return TRUE; } static gboolean _setLinkRenderer(VisuGlExtPairs *pairs, struct _LinkData *dt, VisuPairLinkRenderer *renderer) { if (dt->rdt->renderer == ((renderer) ? renderer : pairs->priv->defaultRenderer)) return FALSE; dt->rdt->usage -= 1; if (!dt->rdt->usage) g_signal_handler_block(G_OBJECT(dt->rdt->renderer), dt->rdt->dirty_sig); dt->rdt = g_hash_table_lookup(pairs->priv->rendererData, (renderer) ? renderer : pairs->priv->defaultRenderer); if (!dt->rdt->usage) g_signal_handler_unblock(G_OBJECT(dt->rdt->renderer), dt->rdt->dirty_sig); dt->rdt->usage += 1; if (renderer) g_hash_table_insert(pairs->priv->linkRenderers, dt->link, renderer); else g_hash_table_remove(pairs->priv->linkRenderers, dt->link); g_signal_emit(G_OBJECT(pairs), _signals[RENDERER_SIGNAL], 0, dt->link); dt->dirty = TRUE; return TRUE; } /** * visu_gl_ext_pairs_setLinkRenderer: * @pairs: the rendering #VisuGlExtPairs object. * @data: a #VisuPairLink object. * @renderer: a #VisuPairLinkRenderer object. * * Set the drawing method of a pair. * * Since: 3.6 * * Returns: TRUE if drawing method is changed. */ gboolean visu_gl_ext_pairs_setLinkRenderer(VisuGlExtPairs *pairs, VisuPairLink *data, VisuPairLinkRenderer *renderer) { guint i; gboolean res; g_return_val_if_fail(VISU_IS_GL_EXT_PAIRS(pairs) && data, FALSE); DBG_fprintf(stderr, "Extension Pairs: set method %p for %p.\n", (gpointer)renderer, (gpointer)data); for (i = 0; i < pairs->priv->links->len; i++) if (g_array_index(pairs->priv->links, struct _LinkData, i).link == data) { res = _setLinkRenderer(pairs, &g_array_index(pairs->priv->links, struct _LinkData, i), renderer); if (res) visu_gl_ext_setDirty(VISU_GL_EXT(pairs), TRUE); return res; } return FALSE; } /** * visu_gl_ext_pairs_getLinkRenderer: * @pairs: the rendering #VisuGlExtPairs object. * @data: a #VisuPairLink object. * * Get the drawing method of a pair. * * Since: 3.6 * * Returns: (transfer none): a drawing method. */ VisuPairLinkRenderer* visu_gl_ext_pairs_getLinkRenderer(VisuGlExtPairs *pairs, VisuPairLink *data) { guint i; g_return_val_if_fail(VISU_IS_GL_EXT_PAIRS(pairs) && data, (VisuPairLinkRenderer*)0); for (i = 0; i < pairs->priv->links->len; i++) if (g_array_index(pairs->priv->links, struct _LinkData, i).link == data) return g_array_index(pairs->priv->links, struct _LinkData, i).rdt->renderer; return (VisuPairLinkRenderer*)0; } /** * visu_gl_ext_pairs_getSet: * @pairs: a #VisuGlExtPairs object. * * Retrieve the #VisuPairSet this @pairs is based on. * * Since: 3.8 * * Returns: (transfer none): the #VisuPairSet this @pairs is based on. **/ VisuPairSet* visu_gl_ext_pairs_getSet(VisuGlExtPairs *pairs) { g_return_val_if_fail(VISU_IS_GL_EXT_PAIRS(pairs), (VisuPairSet*)0); return pairs->priv->pairs; } /************/ /* Signals. */ /************/ static void onLinkNotified(VisuGlExtPairs *ext, GParamSpec *pspec _U_, VisuPairLink *link) { guint i; for (i = 0; i < ext->priv->links->len; i++) if (g_array_index(ext->priv->links, struct _LinkData, i).link == link) { g_array_index(ext->priv->links, struct _LinkData, i).dirty = TRUE; visu_gl_ext_setDirty(VISU_GL_EXT(ext), TRUE); return; } } static void onDirtyRenderer(VisuGlExtPairs *ext, VisuPairLinkRenderer *renderer) { guint i; for (i = 0; i < ext->priv->links->len; i++) if (g_array_index(ext->priv->links, struct _LinkData, i).rdt->renderer == renderer) g_array_index(ext->priv->links, struct _LinkData, i).dirty = TRUE; visu_gl_ext_setDirty(VISU_GL_EXT(ext), TRUE); } static void onPairsNotified(VisuGlExtPairs *ext, GParamSpec *pspec _U_, VisuPairSet *pairs) { VisuPairSetIter iter; DBG_fprintf(stderr, "Extension Pairs: recreate link list from pair notify.\n"); g_array_set_size(ext->priv->links, 0); for (visu_pair_set_iter_new(pairs, &iter, TRUE); iter.link; visu_pair_set_iter_next(&iter)) _addLink(iter.pair, iter.link, ext); visu_gl_ext_setDirty(VISU_GL_EXT(ext), TRUE); } static void onLinksChanged(VisuGlExtPairs *ext, VisuPair *pair, VisuPairSet *pairs _U_) { guint i; DBG_fprintf(stderr, "Extension Pairs: recreate link for pair %p.\n", (gpointer)pair); /* Remove all old VisuPairLink related to pair. */ i = 0; while (i < ext->priv->links->len) { if (g_array_index(ext->priv->links, struct _LinkData, i).pair == pair) g_array_remove_index_fast(ext->priv->links, i); else i += 1; }; /* Add all VisuPairLink of pair. */ visu_pair_foreach(pair, _addLink, ext); visu_gl_ext_setDirty(VISU_GL_EXT(ext), TRUE); } static void _setDirty(VisuGlExtPairs *ext) { guint i; for (i = 0; i < ext->priv->links->len; i++) g_array_index(ext->priv->links, struct _LinkData, i).dirty = TRUE; visu_gl_ext_setDirty(VISU_GL_EXT(ext), TRUE); } static void onActiveChanged(VisuGlExtPairs *pairs, GParamSpec *pspec _U_, gpointer data _U_) { if (!pairs->priv->data) return; if (visu_gl_ext_getActive(VISU_GL_EXT(pairs))) _addBondValues(pairs->priv->data, BOND_PROP_ID); else visu_data_removeNodeProperties(pairs->priv->data, BOND_PROP_ID); } static void onEntryUsed(VisuGlExtPairs *pairs, VisuConfigFileEntry *entry _U_, VisuConfigFile *obj _U_) { visu_gl_ext_setActive(VISU_GL_EXT(pairs), pairsAreOn); } static void onEntryFav(VisuGlExtPairs *pairs, VisuConfigFileEntry *entry, VisuConfigFile *obj _U_) { VisuPairLinkRenderer *fav; DBG_fprintf(stderr, "Extension Pairs: got '%s' as favorite method.\n", favRenderer); fav = _rendererByName(pairs, favRenderer); if (!fav) visu_config_file_entry_setErrorMessage(entry, _("the method '%s' is unknown"), favRenderer); else pairs->priv->defaultRenderer = fav; } static void onEntryLink(VisuConfigFile *obj _U_, VisuConfigFileEntry *entry, gpointer data _U_) { VisuPairLink *link; gchar *errMess; gboolean flags[2]; gchar *favLabel; const ToolColor *color; if (!visu_pair_pool_readLinkFromLabel(visu_config_file_entry_getLabel(entry), &link, &errMess)) { visu_config_file_entry_setErrorMessage(entry, errMess); g_free(errMess); return; } if (!visu_config_file_entry_popTokenAsColor(entry, &color)) return; if (!visu_config_file_entry_popTokenAsBoolean(entry, 2, flags)) return; favLabel = visu_config_file_entry_popAllTokens(entry); g_strstrip(favLabel); /* Set the values. */ visu_pair_link_setColor(link, color); visu_pair_link_setDrawn(link, flags[0]); visu_pair_link_setPrintLength(link, flags[1]); if (favLabel[0]) g_hash_table_insert(_linkRenderers, link, favLabel); else g_free(favLabel); } static gboolean visu_gl_ext_pairs_setGlView(VisuGlExt *pairs, VisuGlView *view) { GList *renderer; for (renderer = VISU_GL_EXT_PAIRS(pairs)->priv->renderers; renderer; renderer = g_list_next(renderer)) visu_pair_link_renderer_setGlView(VISU_PAIR_LINK_RENDERER(renderer->data), view); return FALSE; } static void visu_gl_ext_pairs_rebuild(VisuGlExt *ext) { guint i; VisuGlExtPairs *self = VISU_GL_EXT_PAIRS(ext); for (i = 0; i < self->priv->links->len; i++) g_array_index(self->priv->links, struct _LinkData, i).dirty = TRUE; visu_gl_text_rebuildFontList(); visu_gl_ext_setDirty(ext, TRUE); visu_gl_ext_pairs_draw(ext); } static void _drawLink(struct _LinkData *dt, VisuData *data, VisuNodeValues *bonds) { VisuPairLinkIter iter; gboolean valid; char distStr[8]; glDeleteLists(dt->id, 1); DBG_fprintf(stderr, "Extension Pairs: drawing link %p (%d).\n", (gpointer)dt->link, visu_pair_link_getDrawn(dt->link)); if (!visu_pair_link_getDrawn(dt->link)) return; glNewList(dt->id, GL_COMPILE); visu_pair_link_renderer_start(dt->rdt->renderer, dt->link, dt->ele1, dt->ele2, visu_node_array_renderer_getColorizer(dt->nodes)); for (valid = visu_pair_link_iter_new(dt->link, data, &iter, TRUE); valid; valid = visu_pair_link_iter_next(&iter)) { if (iter.coeff == 1.f && bonds) { (*(int*)visu_node_values_getPtrAt(bonds, iter.iter1.node)) += 1; (*(int*)visu_node_values_getPtrAt(bonds, iter.iter2.node)) += 1; } visu_pair_link_renderer_draw(dt->rdt->renderer, &iter); if (visu_pair_link_getPrintLength(dt->link)) { sprintf(distStr, "%7.3f", sqrt(iter.d2)); glRasterPos3f(iter.xyz1[0] + iter.dxyz[0] / 2., iter.xyz1[1] + iter.dxyz[1] / 2., iter.xyz1[2] + iter.dxyz[2] / 2.); visu_gl_text_drawChars(distStr, VISU_GL_TEXT_NORMAL); if (iter.periodic) { glRasterPos3f(iter.xyz2[0] - iter.dxyz[0] / 2., iter.xyz2[1] - iter.dxyz[1] / 2., iter.xyz2[2] - iter.dxyz[2] / 2.); visu_gl_text_drawChars(distStr, VISU_GL_TEXT_NORMAL); } } } visu_pair_link_renderer_stop(dt->rdt->renderer, dt->link); glEndList(); dt->dirty = FALSE; } static void visu_gl_ext_pairs_draw(VisuGlExt *pairs) { VisuGlExtPairs *self = VISU_GL_EXT_PAIRS(pairs); VisuGlExtPairsPrivate *priv = self->priv; VisuNodeValues *bonds; struct _LinkData *dt; guint i; /* Cleans. */ glDeleteLists(visu_gl_ext_getGlList(pairs), 1); visu_gl_ext_setDirty(pairs, FALSE); /* Nothing to draw if no data is associated to the current rendering window. */ if (!priv->data) return; visu_gl_text_initFontList(); /* We get the counting array for bonds. */ bonds = visu_data_getNodeProperties(priv->data, BOND_PROP_ID); if (bonds) visu_node_values_reset(bonds); for (i = 0; i < priv->links->len; i++) if (g_array_index(priv->links, struct _LinkData, i).dirty) _drawLink(&g_array_index(priv->links, struct _LinkData, i), priv->data, bonds); visu_gl_ext_startDrawing(pairs); for (i = 0; i < priv->links->len; i++) { dt = &g_array_index(priv->links, struct _LinkData, i); DBG_fprintf(stderr, "Extension Pairs: call list %d.\n", dt->id); glCallList(dt->id); } visu_gl_ext_completeDrawing(pairs); } /**************/ /* Resources. */ /**************/ static void exportResourcesPairs(GString *data, VisuData *dataObj) { GList *pairsMeth; GString *buf; VisuElement *ele1, *ele2; ToolColor *color; gchar *buf2, *id; guint i; struct _LinkData *dt; visu_config_file_exportComment(data, DESC_RESOURCES_PAIRS); visu_config_file_exportEntry(data, FLAG_RESOURCES_PAIRS, NULL, "%i", (defaultPairs)?visu_gl_ext_getActive(VISU_GL_EXT(defaultPairs)):pairsAreOn); if (defaultPairs && defaultPairs->priv->defaultRenderer) { buf = g_string_new(""); g_string_append_printf(buf, "%s (", DESC_RESOURCES_FAV_PAIRS); for (pairsMeth = defaultPairs->priv->renderers; pairsMeth; pairsMeth = g_list_next(pairsMeth)) { g_object_get(G_OBJECT(pairsMeth->data), "id", &id, NULL); g_string_append_printf(buf, "'%s'", id); g_free(id); if (pairsMeth->next) g_string_append_printf(buf, ", "); } g_string_append_printf(buf, ")"); visu_config_file_exportComment(data, buf->str); g_string_free(buf, TRUE); g_object_get(G_OBJECT(defaultPairs->priv->defaultRenderer), "id", &id, NULL); visu_config_file_exportEntry(data, FLAG_RESOURCES_FAV_PAIRS, NULL, "%s", id); g_free(id); } visu_config_file_exportComment(data, DESC1_RESOURCES_PAIR_LINK); visu_config_file_exportComment(data, DESC2_RESOURCES_PAIR_LINK); for (i = 0; i < defaultPairs->priv->links->len; i++) { dt = &g_array_index(defaultPairs->priv->links, struct _LinkData, i); visu_pair_getElements(dt->pair, &ele1, &ele2); /* We export only if the two elements of the pair are used in the given dataObj. */ if (dataObj && (!visu_node_array_containsElement(VISU_NODE_ARRAY(dataObj), ele1) || !visu_node_array_containsElement(VISU_NODE_ARRAY(dataObj), ele2))) continue; buf2 = g_strdup_printf("%s %s %4.3f %4.3f", visu_element_getName(ele1), visu_element_getName(ele2), visu_pair_link_getDistance(dt->link, VISU_DISTANCE_MIN), visu_pair_link_getDistance(dt->link, VISU_DISTANCE_MAX)); color = visu_pair_link_getColor(dt->link); g_object_get(G_OBJECT(dt->rdt->renderer), "id", &id, NULL); visu_config_file_exportEntry(data, FLAG_RESOURCES_PAIR_LINK, buf2, "%s %d %d %s", tool_color_asStr(color), visu_pair_link_getDrawn(dt->link), visu_pair_link_getPrintLength(dt->link), id); g_free(buf2); g_free(id); } visu_config_file_exportComment(data, ""); } /*****************************************/ /* Methods to organize pairs extensions. */ /*****************************************/ /** * visu_gl_ext_pairs_getAllLinkRenderer: * @pairs: a #VisuGlExtPairs object. * * Useful to know all #VisuPairLinkRenderer used by @pairs. * * Since: 3.8 * * Returns: (element-type VisuPairLinkRenderer*) (transfer none): a list * of all the known #VisuPairLinkRenderer. This list should be considered * read-only. */ GList* visu_gl_ext_pairs_getAllLinkRenderer(VisuGlExtPairs *pairs) { g_return_val_if_fail(VISU_IS_GL_EXT_PAIRS(pairs), (GList*)0); return pairs->priv->renderers; } static gint _cmpRenderers(gconstpointer a, gconstpointer b) { gchar *id; gint res; g_object_get(VISU_PAIR_LINK_RENDERER(a), "id", &id, NULL); res = g_ascii_strcasecmp(id, b); g_free(id); return res; } static VisuPairLinkRenderer* _rendererByName(VisuGlExtPairs *pairs, const gchar *name) { GList *pairsMethods; gchar *name_; name_ = g_strstrip(g_strdup(name)); pairsMethods = g_list_find_custom(pairs->priv->renderers, name_, _cmpRenderers); g_free(name_); return (pairsMethods) ? VISU_PAIR_LINK_RENDERER(pairsMethods->data) : (VisuPairLinkRenderer*)0; } v_sim-3.8.0/src/extensions/pairs.h000066400000000000000000000113411370110300500171020ustar00rootroot00000000000000/* EXTRAITS DE LA LICENCE Copyright CEA, contributeurs : Damien CALISTE, laboratoire L_Sim, (2001-2009) Adresse mèl : CALISTE, damien P caliste AT cea P fr. Ce logiciel est un programme informatique servant à visualiser des structures atomiques dans un rendu pseudo-3D. Ce logiciel est régi par la licence CeCILL soumise au droit français et respectant les principes de diffusion des logiciels libres. Vous pouvez utiliser, modifier et/ou redistribuer ce programme sous les conditions de la licence CeCILL telle que diffusée par le CEA, le CNRS et l'INRIA sur le site "http://www.cecill.info". Le fait que vous puissiez accéder à cet en-tête signifie que vous avez pris connaissance de la licence CeCILL, et que vous en avez accepté les termes (cf. le fichier Documentation/licence.fr.txt fourni avec ce logiciel). */ /* LICENCE SUM UP Copyright CEA, contributors : Damien CALISTE, laboratoire L_Sim, (2001-2009) E-mail address: CALISTE, damien P caliste AT cea P fr. This software is a computer program whose purpose is to visualize atomic configurations in 3D. This software is governed by the CeCILL license under French law and abiding by the rules of distribution of free software. You can use, modify and/ or redistribute the software under the terms of the CeCILL license as circulated by CEA, CNRS and INRIA at the following URL "http://www.cecill.info". The fact that you are presently reading this means that you have had knowledge of the CeCILL license and that you accept its terms. You can find a copy of this licence shipped with this software at COPYING. */ #ifndef PAIRS_H #define PAIRS_H #include #include #include #include #include G_BEGIN_DECLS /** * VISU_TYPE_GL_EXT_PAIRS: * * return the type of #VisuGlExtPairs. * * Since: 3.7 */ #define VISU_TYPE_GL_EXT_PAIRS (visu_gl_ext_pairs_get_type ()) /** * VISU_GL_EXT_PAIRS: * @obj: a #GObject to cast. * * Cast the given @obj into #VisuGlExtPairs type. * * Since: 3.7 */ #define VISU_GL_EXT_PAIRS(obj) (G_TYPE_CHECK_INSTANCE_CAST(obj, VISU_TYPE_GL_EXT_PAIRS, VisuGlExtPairs)) /** * VISU_GL_EXT_PAIRS_CLASS: * @klass: a #GObjectClass to cast. * * Cast the given @klass into #VisuGlExtPairsClass. * * Since: 3.7 */ #define VISU_GL_EXT_PAIRS_CLASS(klass) (G_TYPE_CHECK_CLASS_CAST(klass, VISU_TYPE_GL_EXT_PAIRS, VisuGlExtPairsClass)) /** * VISU_IS_GL_EXT_PAIRS: * @obj: a #GObject to test. * * Test if the given @ogj is of the type of #VisuGlExtPairs object. * * Since: 3.7 */ #define VISU_IS_GL_EXT_PAIRS(obj) (G_TYPE_CHECK_INSTANCE_TYPE(obj, VISU_TYPE_GL_EXT_PAIRS)) /** * VISU_IS_GL_EXT_PAIRS_CLASS: * @klass: a #GObjectClass to test. * * Test if the given @klass is of the type of #VisuGlExtPairsClass class. * * Since: 3.7 */ #define VISU_IS_GL_EXT_PAIRS_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE(klass, VISU_TYPE_GL_EXT_PAIRS)) /** * VISU_GL_EXT_PAIRS_GET_CLASS: * @obj: a #GObject to get the class of. * * It returns the class of the given @obj. * * Since: 3.7 */ #define VISU_GL_EXT_PAIRS_GET_CLASS(obj) (G_TYPE_INSTANCE_GET_CLASS(obj, VISU_TYPE_GL_EXT_PAIRS, VisuGlExtPairsClass)) typedef struct _VisuGlExtPairs VisuGlExtPairs; typedef struct _VisuGlExtPairsPrivate VisuGlExtPairsPrivate; typedef struct _VisuGlExtPairsClass VisuGlExtPairsClass; struct _VisuGlExtPairs { VisuGlExt parent; VisuGlExtPairsPrivate *priv; }; struct _VisuGlExtPairsClass { VisuGlExtClass parent; }; /** * visu_gl_ext_pairs_get_type: * * This method returns the type of #VisuGlExtPairs, use * VISU_TYPE_GL_EXT_PAIRS instead. * * Since: 3.7 * * Returns: the type of #VisuGlExtPairs. */ GType visu_gl_ext_pairs_get_type(void); /** * VISU_GL_EXT_PAIRS_ID: * * The id used to identify this extension, see * visu_gl_ext_rebuild() for instance. */ #define VISU_GL_EXT_PAIRS_ID "Pairs" VisuGlExtPairs* visu_gl_ext_pairs_new(const gchar *name); gboolean visu_gl_ext_pairs_setData(VisuGlExtPairs *pairs, VisuData *data); gboolean visu_gl_ext_pairs_setDataRenderer(VisuGlExtPairs *pairs, VisuNodeArrayRenderer *renderer); VisuNodeArrayRenderer* visu_gl_ext_pairs_getDataRenderer(VisuGlExtPairs *pairs); VisuPairSet* visu_gl_ext_pairs_getSet(VisuGlExtPairs *pairs); GList* visu_gl_ext_pairs_getAllLinkRenderer(VisuGlExtPairs *pairs); VisuPairLinkRenderer* visu_gl_ext_pairs_getLinkRenderer(VisuGlExtPairs *pairs, VisuPairLink *data); gboolean visu_gl_ext_pairs_setLinkRenderer(VisuGlExtPairs *pairs, VisuPairLink *data, VisuPairLinkRenderer *renderer); G_END_DECLS #endif v_sim-3.8.0/src/extensions/paths.c000066400000000000000000000207761370110300500171120ustar00rootroot00000000000000/* EXTRAITS DE LA LICENCE Copyright CEA, contributeurs : Luc BILLARD et Damien CALISTE, laboratoire L_Sim, (2001-2005) Adresse mèl : BILLARD, non joignable par mèl ; CALISTE, damien P caliste AT cea P fr. Ce logiciel est un programme informatique servant à visualiser des structures atomiques dans un rendu pseudo-3D. Ce logiciel est régi par la licence CeCILL soumise au droit français et respectant les principes de diffusion des logiciels libres. Vous pouvez utiliser, modifier et/ou redistribuer ce programme sous les conditions de la licence CeCILL telle que diffusée par le CEA, le CNRS et l'INRIA sur le site "http://www.cecill.info". Le fait que vous puissiez accéder à cet en-tête signifie que vous avez pris connaissance de la licence CeCILL, et que vous en avez accepté les termes (cf. le fichier Documentation/licence.fr.txt fourni avec ce logiciel). */ /* LICENCE SUM UP Copyright CEA, contributors : Luc BILLARD et Damien CALISTE, laboratoire L_Sim, (2001-2005) E-mail address: BILLARD, not reachable any more ; CALISTE, damien P caliste AT cea P fr. This software is a computer program whose purpose is to visualize atomic configurations in 3D. This software is governed by the CeCILL license under French law and abiding by the rules of distribution of free software. You can use, modify and/ or redistribute the software under the terms of the CeCILL license as circulated by CEA, CNRS and INRIA at the following URL "http://www.cecill.info". The fact that you are presently reading this means that you have had knowledge of the CeCILL license and that you accept its terms. You can find a copy of this licence shipped with this software at Documentation/licence.en.txt. */ #include "paths.h" #include #include #include /** * SECTION:paths * @short_description: Defines methods to draw paths. * * Create a #VisuGlExt object to handle #VisuPaths drawing. */ /** * VisuGlExtPathsClass: * @parent: the parent class; * * A short way to identify #_VisuGlExtPathsClass structure. * * Since: 3.7 */ /** * VisuGlExtPaths: * * An opaque structure. * * Since: 3.7 */ /** * VisuGlExtPathsPrivate: * * Private fields for #VisuGlExtPaths objects. * * Since: 3.7 */ struct _VisuGlExtPathsPrivate { gboolean dispose_has_run; /* Related objects. */ VisuPaths *obj; float width; }; static void visu_gl_ext_paths_dispose(GObject* obj); static void visu_gl_ext_paths_rebuild(VisuGlExt *ext); static void visu_gl_ext_paths_draw(VisuGlExt *paths); #define FLAG_RESOURCE_WIDTH "path_lineWidth" #define DESC_RESOURCE_WIDTH "Line width for drawing of paths ; float (positive)" static void exportResources(GString *data, VisuData *dataObj); /* Local variables. */ static float pathWidth = 3.f; /* Local callbacks */ static void onEntryUsed(VisuGlExtPaths *paths, VisuConfigFileEntry *entry, VisuConfigFile *obj); G_DEFINE_TYPE_WITH_CODE(VisuGlExtPaths, visu_gl_ext_paths, VISU_TYPE_GL_EXT, G_ADD_PRIVATE(VisuGlExtPaths)) static void visu_gl_ext_paths_class_init(VisuGlExtPathsClass *klass) { float rg[2] = {0.01f, 10.f}; VisuConfigFileEntry *conf; DBG_fprintf(stderr, "Extension Paths: creating the class of the object.\n"); /* DBG_fprintf(stderr, " - adding new signals ;\n"); */ /* Connect the overloading methods. */ G_OBJECT_CLASS(klass)->dispose = visu_gl_ext_paths_dispose; VISU_GL_EXT_CLASS(klass)->rebuild = visu_gl_ext_paths_rebuild; VISU_GL_EXT_CLASS(klass)->draw = visu_gl_ext_paths_draw; DBG_fprintf(stderr, "Extension Paths: set the conf entries for this class.\n"); conf = visu_config_file_addFloatArrayEntry(VISU_CONFIG_FILE_RESOURCE, FLAG_RESOURCE_WIDTH, DESC_RESOURCE_WIDTH, 1, &pathWidth, rg, FALSE); visu_config_file_entry_setVersion(conf, 3.7f); visu_config_file_addExportFunction(VISU_CONFIG_FILE_RESOURCE, exportResources); } static void visu_gl_ext_paths_init(VisuGlExtPaths *obj) { DBG_fprintf(stderr, "Extension Paths: initializing a new object (%p).\n", (gpointer)obj); obj->priv = visu_gl_ext_paths_get_instance_private(obj); obj->priv->dispose_has_run = FALSE; /* Private data. */ obj->priv->obj = (VisuPaths*)0; obj->priv->width = pathWidth; g_signal_connect_object(VISU_CONFIG_FILE_RESOURCE, "parsed::" FLAG_RESOURCE_WIDTH, G_CALLBACK(onEntryUsed), (gpointer)obj, G_CONNECT_SWAPPED); } static void visu_gl_ext_paths_dispose(GObject* obj) { VisuGlExtPaths *paths; DBG_fprintf(stderr, "Extension Paths: dispose object %p.\n", (gpointer)obj); paths = VISU_GL_EXT_PATHS(obj); if (paths->priv->dispose_has_run) return; paths->priv->dispose_has_run = TRUE; /* Disconnect signals. */ visu_gl_ext_paths_set(paths, (VisuPaths*)0); /* Chain up to the parent class */ G_OBJECT_CLASS(visu_gl_ext_paths_parent_class)->dispose(obj); } /** * visu_gl_ext_paths_new: * @name: (allow-none): the name to give to the extension (default is #VISU_GL_EXT_PATHS_ID). * * Creates a new #VisuGlExt to draw paths. * * Since: 3.7 * * Returns: (transfer full): a pointer to the #VisuGlExt it created or * NULL otherwise. */ VisuGlExtPaths* visu_gl_ext_paths_new(const gchar *name) { char *name_ = VISU_GL_EXT_PATHS_ID; char *description = _("Representation of paths."); VisuGlExt *extensionPaths; DBG_fprintf(stderr,"Extension Paths: new object.\n"); extensionPaths = VISU_GL_EXT(g_object_new(VISU_TYPE_GL_EXT_PATHS, "name", (name)?name:name_, "label", _(name), "description", description, "nGlObj", 1, "priority", VISU_GL_EXT_PRIORITY_NODES - 1, NULL)); return VISU_GL_EXT_PATHS(extensionPaths); } /** * visu_gl_ext_paths_set: * @paths: the #VisuGlExtPaths object to modify. * @obj: (allow-none) (transfer none): a #VisuPaths object. * * Set the #VisuPaths to be drawn. * * Since: 3.7 * * Returns: TRUE if the model was actually changed. **/ gboolean visu_gl_ext_paths_set(VisuGlExtPaths *paths, VisuPaths *obj) { g_return_val_if_fail(VISU_IS_GL_EXT_PATHS(paths), FALSE); DBG_fprintf(stderr, "Extension Paths: set a new path %p (%p).\n", (gpointer)obj, (gpointer)paths->priv->obj); if (obj == paths->priv->obj) return FALSE; if (paths->priv->obj) visu_paths_unref(paths->priv->obj); paths->priv->obj = obj; if (obj) visu_paths_ref(obj); visu_gl_ext_setDirty(VISU_GL_EXT(paths), TRUE); return TRUE; } /** * visu_gl_ext_paths_setWidth: * @paths: a #VisuGlExtPaths object. * @value: a positive float lower than 10. * * Change the rendering width of the @paths. * * Since: 3.8 * * Returns: TRUE if the width has changed. **/ gboolean visu_gl_ext_paths_setWidth(VisuGlExtPaths *paths, float value) { g_return_val_if_fail(VISU_IS_GL_EXT_PATHS(paths) && value > 0.f, FALSE); value = CLAMP(value, 0.f, 10.f); if (value == paths->priv->width) return FALSE; paths->priv->width = value; visu_gl_ext_setDirty(VISU_GL_EXT(paths), TRUE); return TRUE; } /** * visu_gl_ext_paths_getWidth: * @paths: a #VisuGlExtPaths object. * * Inquire the width used to render the @paths. * * Since: 3.8 * * Returns: the width used to render the path. **/ float visu_gl_ext_paths_getWidth(VisuGlExtPaths *paths) { g_return_val_if_fail(VISU_IS_GL_EXT_PATHS(paths), pathWidth); return paths->priv->width; } /****************/ /* Private part */ /****************/ static void visu_gl_ext_paths_rebuild(VisuGlExt *ext) { visu_gl_ext_setDirty(ext, TRUE); visu_gl_ext_paths_draw(ext); } static void visu_gl_ext_paths_draw(VisuGlExt *paths) { visu_gl_ext_startDrawing(paths); if (VISU_GL_EXT_PATHS(paths)->priv->obj) visu_paths_draw(VISU_GL_EXT_PATHS(paths)->priv->obj, pathWidth); visu_gl_ext_completeDrawing(paths); } /*************************/ /* Resources management. */ /*************************/ static void exportResources(GString *data, VisuData *dataObj _U_) { visu_config_file_exportComment(data, DESC_RESOURCE_WIDTH); visu_config_file_exportEntry(data, FLAG_RESOURCE_WIDTH, NULL, "%f", pathWidth); visu_config_file_exportComment(data, ""); } static void onEntryUsed(VisuGlExtPaths *paths, VisuConfigFileEntry *entry _U_, VisuConfigFile *obj _U_) { visu_gl_ext_paths_setWidth(paths, pathWidth); } v_sim-3.8.0/src/extensions/paths.h000066400000000000000000000102621370110300500171040ustar00rootroot00000000000000/* EXTRAITS DE LA LICENCE Copyright CEA, contributeurs : Luc BILLARD et Damien CALISTE, laboratoire L_Sim, (2001-2005) Adresse mèl : BILLARD, non joignable par mèl ; CALISTE, damien P caliste AT cea P fr. Ce logiciel est un programme informatique servant à visualiser des structures atomiques dans un rendu pseudo-3D. Ce logiciel est régi par la licence CeCILL soumise au droit français et respectant les principes de diffusion des logiciels libres. Vous pouvez utiliser, modifier et/ou redistribuer ce programme sous les conditions de la licence CeCILL telle que diffusée par le CEA, le CNRS et l'INRIA sur le site "http://www.cecill.info". Le fait que vous puissiez accéder à cet en-tête signifie que vous avez pris connaissance de la licence CeCILL, et que vous en avez accepté les termes (cf. le fichier Documentation/licence.fr.txt fourni avec ce logiciel). */ /* LICENCE SUM UP Copyright CEA, contributors : Luc BILLARD et Damien CALISTE, laboratoire L_Sim, (2001-2005) E-mail address: BILLARD, not reachable any more ; CALISTE, damien P caliste AT cea P fr. This software is a computer program whose purpose is to visualize atomic configurations in 3D. This software is governed by the CeCILL license under French law and abiding by the rules of distribution of free software. You can use, modify and/ or redistribute the software under the terms of the CeCILL license as circulated by CEA, CNRS and INRIA at the following URL "http://www.cecill.info". The fact that you are presently reading this means that you have had knowledge of the CeCILL license and that you accept its terms. You can find a copy of this licence shipped with this software at Documentation/licence.en.txt. */ #ifndef PATHS_H #define PATHS_H #include #include /** * VISU_TYPE_GL_EXT_PATHS: * * return the type of #VisuGlExtPaths. * * Since: 3.7 */ #define VISU_TYPE_GL_EXT_PATHS (visu_gl_ext_paths_get_type ()) /** * VISU_GL_EXT_PATHS: * @obj: a #GObject to cast. * * Cast the given @obj into #VisuGlExtPaths type. * * Since: 3.7 */ #define VISU_GL_EXT_PATHS(obj) (G_TYPE_CHECK_INSTANCE_CAST(obj, VISU_TYPE_GL_EXT_PATHS, VisuGlExtPaths)) /** * VISU_GL_EXT_PATHS_CLASS: * @klass: a #GObjectClass to cast. * * Cast the given @klass into #VisuGlExtPathsClass. * * Since: 3.7 */ #define VISU_GL_EXT_PATHS_CLASS(klass) (G_TYPE_CHECK_CLASS_CAST(klass, VISU_TYPE_GL_EXT_PATHS, VisuGlExtPathsClass)) /** * VISU_IS_GL_EXT_PATHS: * @obj: a #GObject to test. * * Test if the given @ogj is of the type of #VisuGlExtPaths object. * * Since: 3.7 */ #define VISU_IS_GL_EXT_PATHS(obj) (G_TYPE_CHECK_INSTANCE_TYPE(obj, VISU_TYPE_GL_EXT_PATHS)) /** * VISU_IS_GL_EXT_PATHS_CLASS: * @klass: a #GObjectClass to test. * * Test if the given @klass is of the type of #VisuGlExtPathsClass class. * * Since: 3.7 */ #define VISU_IS_GL_EXT_PATHS_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE(klass, VISU_TYPE_GL_EXT_PATHS)) /** * VISU_GL_EXT_PATHS_GET_CLASS: * @obj: a #GObject to get the class of. * * It returns the class of the given @obj. * * Since: 3.7 */ #define VISU_GL_EXT_PATHS_GET_CLASS(obj) (G_TYPE_INSTANCE_GET_CLASS(obj, VISU_TYPE_GL_EXT_PATHS, VisuGlExtPathsClass)) typedef struct _VisuGlExtPaths VisuGlExtPaths; typedef struct _VisuGlExtPathsPrivate VisuGlExtPathsPrivate; typedef struct _VisuGlExtPathsClass VisuGlExtPathsClass; struct _VisuGlExtPaths { VisuGlExt parent; VisuGlExtPathsPrivate *priv; }; struct _VisuGlExtPathsClass { VisuGlExtClass parent; }; /** * VISU_GL_EXT_PATHS_ID: * * The id used to identify this extension, see * visu_gl_ext_rebuild() for instance. */ #define VISU_GL_EXT_PATHS_ID "Paths" /** * visu_gl_ext_paths_get_type: * * This method returns the type of #VisuGlExtPaths, use * VISU_TYPE_GL_EXT_PATHS instead. * * Since: 3.7 * * Returns: the type of #VisuGlExtPaths. */ GType visu_gl_ext_paths_get_type(void); VisuGlExtPaths* visu_gl_ext_paths_new(const gchar *name); gboolean visu_gl_ext_paths_set(VisuGlExtPaths *paths, VisuPaths *obj); gboolean visu_gl_ext_paths_setWidth(VisuGlExtPaths *paths, float value); float visu_gl_ext_paths_getWidth(VisuGlExtPaths *paths); #endif v_sim-3.8.0/src/extensions/planes.c000066400000000000000000000251341370110300500172460ustar00rootroot00000000000000/* EXTRAITS DE LA LICENCE Copyright CEA, contributeurs : Damien CALISTE, laboratoire L_Sim, (2001-2009) Adresse mèl : CALISTE, damien P caliste AT cea P fr. Ce logiciel est un programme informatique servant à visualiser des structures atomiques dans un rendu pseudo-3D. Ce logiciel est régi par la licence CeCILL soumise au droit français et respectant les principes de diffusion des logiciels libres. Vous pouvez utiliser, modifier et/ou redistribuer ce programme sous les conditions de la licence CeCILL telle que diffusée par le CEA, le CNRS et l'INRIA sur le site "http://www.cecill.info". Le fait que vous puissiez accéder à cet en-tête signifie que vous avez pris connaissance de la licence CeCILL, et que vous en avez accepté les termes (cf. le fichier Documentation/licence.fr.txt fourni avec ce logiciel). */ /* LICENCE SUM UP Copyright CEA, contributors : Damien CALISTE, laboratoire L_Sim, (2001-2009) E-mail address: CALISTE, damien P caliste AT cea P fr. This software is a computer program whose purpose is to visualize atomic configurations in 3D. This software is governed by the CeCILL license under French law and abiding by the rules of distribution of free software. You can use, modify and/ or redistribute the software under the terms of the CeCILL license as circulated by CEA, CNRS and INRIA at the following URL "http://www.cecill.info". The fact that you are presently reading this means that you have had knowledge of the CeCILL license and that you accept its terms. You can find a copy of this licence shipped with this software at COPYING. */ #include "planes.h" #include #include /** * SECTION:planes * @short_description: Draw a list of #VisuPlane. * * This extension draws a list of #VisuPlane. Planes are * outlined with a black line and also the intersections of planes. * * Since: 3.7 */ /** * VisuGlExtPlanesClass: * @parent: the parent class; * * A short way to identify #_VisuGlExtPlanesClass structure. * * Since: 3.7 */ /** * VisuGlExtPlanes: * * An opaque structure. * * Since: 3.7 */ /** * VisuGlExtPlanesPrivate: * * Private fields for #VisuGlExtPlanes objects. * * Since: 3.7 */ struct _VisuGlExtPlanesPrivate { gboolean dispose_has_run; VisuBox *box; }; typedef struct _PlaneHandleStruct { gulong move_signal, rendering_signal; } _PlaneHandle; static void visu_gl_ext_planes_dispose(GObject* obj); static void visu_gl_ext_planes_rebuild(VisuGlExt *ext); static void visu_gl_ext_planes_draw(VisuGlExt *planes); /* Local callbacks. */ static void onSetChanged(VisuGlExt *ext); static void onPlaneMoved(VisuGlExt *ext, VisuPlane *plane); static void onPlaneRendering(VisuGlExt *ext); /* Local routines. */ static void _freePlaneHandle(VisuPlane *plane, gpointer obj) { _PlaneHandle *phd; phd = (_PlaneHandle*)obj; g_signal_handler_disconnect(G_OBJECT(plane), phd->move_signal); g_signal_handler_disconnect(G_OBJECT(plane), phd->rendering_signal); #if GLIB_MINOR_VERSION > 9 g_slice_free1(sizeof(_PlaneHandle), obj); #else g_free(obj); #endif } static gpointer _newPlaneHandle(VisuPlane *plane, gpointer data) { _PlaneHandle *phd; #if GLIB_MINOR_VERSION > 9 phd = g_slice_alloc(sizeof(_PlaneHandle)); #else phd = g_malloc(sizeof(_PlaneHandle)); #endif phd->move_signal = g_signal_connect_swapped(G_OBJECT(plane), "moved", G_CALLBACK(onPlaneMoved), data); phd->rendering_signal = g_signal_connect_swapped(G_OBJECT(plane), "rendering", G_CALLBACK(onPlaneRendering), data); return (gpointer)phd; } G_DEFINE_TYPE_WITH_CODE(VisuGlExtPlanes, visu_gl_ext_planes, VISU_TYPE_GL_EXT, G_ADD_PRIVATE(VisuGlExtPlanes)) static void visu_gl_ext_planes_class_init(VisuGlExtPlanesClass *klass) { DBG_fprintf(stderr, "Extension Planes: creating the class of the object.\n"); /* DBG_fprintf(stderr, " - adding new signals ;\n"); */ /* Connect the overloading methods. */ G_OBJECT_CLASS(klass)->dispose = visu_gl_ext_planes_dispose; VISU_GL_EXT_CLASS(klass)->rebuild = visu_gl_ext_planes_rebuild; VISU_GL_EXT_CLASS(klass)->draw = visu_gl_ext_planes_draw; } static void visu_gl_ext_planes_init(VisuGlExtPlanes *obj) { DBG_fprintf(stderr, "Extension Planes: initializing a new object (%p).\n", (gpointer)obj); obj->priv = visu_gl_ext_planes_get_instance_private(obj); obj->priv->dispose_has_run = FALSE; obj->priv->box = (VisuBox*)0; /* Private data. */ obj->planes = visu_plane_set_newFull(_newPlaneHandle, _freePlaneHandle, (gpointer)obj); g_signal_connect_object(G_OBJECT(obj->planes), "added", G_CALLBACK(onSetChanged), obj, G_CONNECT_SWAPPED); g_signal_connect_object(G_OBJECT(obj->planes), "removed", G_CALLBACK(onSetChanged), obj, G_CONNECT_SWAPPED); g_object_bind_property(obj, "active", obj->planes, "masking", G_BINDING_SYNC_CREATE); } /* This method can be called several times. It should unref all of its reference to GObjects. */ static void visu_gl_ext_planes_dispose(GObject* obj) { VisuGlExtPlanes *planes; DBG_fprintf(stderr, "Extension Planes: dispose object %p.\n", (gpointer)obj); planes = VISU_GL_EXT_PLANES(obj); if (planes->priv->dispose_has_run) return; planes->priv->dispose_has_run = TRUE; g_object_unref(planes->planes); visu_gl_ext_planes_setBox(planes, (VisuBox*)0); /* Chain up to the parent class */ G_OBJECT_CLASS(visu_gl_ext_planes_parent_class)->dispose(obj); } /** * visu_gl_ext_planes_new: * @name: (allow-none): the name to give to the extension (default is #VISU_GL_EXT_PLANES_ID). * * Creates a new #VisuGlExt to draw a list of planes. * * Since: 3.7 * * Returns: a pointer to the #VisuGlExt it created or * NULL otherwise. */ VisuGlExtPlanes* visu_gl_ext_planes_new(const gchar *name) { char *name_ = VISU_GL_EXT_PLANES_ID; char *description = _("Draw some planes."); #define PLANES_HEIGHT 30 DBG_fprintf(stderr,"Extension Planes: new object.\n"); return g_object_new(VISU_TYPE_GL_EXT_PLANES, "name", (name)?name:name_, "label", _(name), "description", description, "nGlObj", 1, "priority", VISU_GL_EXT_PRIORITY_NORMAL + 1, NULL); } /** * visu_gl_ext_planes_setBox: * @ext: a #VisuGlExtPlanes object. * @box: a #VisuBox object. * * Apply @box on every plane rendered by @ext. * * Since: 3.8 * * Returns: TRUE if the box is actually changed. **/ gboolean visu_gl_ext_planes_setBox(VisuGlExtPlanes *ext, VisuBox *box) { g_return_val_if_fail(VISU_IS_GL_EXT_PLANES(ext), FALSE); DBG_fprintf(stderr, "Extension Planes: set box %p.\n", (gpointer)box); if (ext->priv->box == box) return FALSE; if (ext->priv->box) g_object_unref(ext->priv->box); ext->priv->box = box; if (!box) return TRUE; g_object_ref(box); visu_boxed_setBox(VISU_BOXED(ext->planes), VISU_BOXED(box)); return TRUE; } static void visu_gl_ext_planes_rebuild(VisuGlExt *ext) { visu_gl_ext_setDirty(ext, TRUE); visu_gl_ext_planes_draw(ext); } static void onSetChanged(VisuGlExt *ext) { DBG_fprintf(stderr, "Extension Planes: caught added/removed signals on model.\n"); visu_gl_ext_setDirty(ext, TRUE); } static void onPlaneMoved(VisuGlExt *ext, VisuPlane *plane) { DBG_fprintf(stderr, "Extension Planes: caught 'plane moved' signal (%d).\n", visu_plane_getRendered(plane)); if (visu_plane_getRendered(plane)) visu_gl_ext_setDirty(ext, TRUE); } static void onPlaneRendering(VisuGlExt *ext) { visu_gl_ext_setDirty(ext, TRUE); } static void visu_plane_draw(VisuPlane* plane) { GList *inter, *tmpLst; const ToolColor *color; if (!visu_boxed_getBox(VISU_BOXED(plane))) return; inter = visu_plane_getIntersection(plane); if (inter && visu_plane_getRendered(plane)) { DBG_fprintf(stderr, " | plane %p\n", (gpointer)plane); glLineWidth(1.f); glColor4f(0.f, 0.f, 0.f, visu_plane_getOpacity(plane)); glBegin(GL_LINE_LOOP); for (tmpLst = inter; tmpLst; tmpLst = g_list_next(tmpLst)) glVertex3fv((float*)tmpLst->data); glEnd(); glDisable(GL_CULL_FACE); color = visu_plane_getColor(plane); glColor4f(color->rgba[0], color->rgba[1], color->rgba[2], MIN(visu_plane_getOpacity(plane), color->rgba[3])); glBegin(GL_POLYGON); for (tmpLst = inter; tmpLst; tmpLst = g_list_next(tmpLst)) glVertex3fv((float*)tmpLst->data); glEnd(); glEnable(GL_CULL_FACE); glCullFace(GL_BACK); } } static void visu_gl_ext_planes_draw(VisuGlExt *ext) { float A[3], B[3]; VisuGlExtPlanes *planes = VISU_GL_EXT_PLANES(ext); VisuPlaneSetIter iter, iter2; g_return_if_fail(VISU_IS_GL_EXT_PLANES(ext)); glDeleteLists(visu_gl_ext_getGlList(ext), 1); visu_gl_ext_setDirty(ext, FALSE); if (!planes) return; visu_gl_ext_startDrawing(ext); /* Set blend if not present. */ glEnable(GL_BLEND); glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA); glDisable(GL_LIGHTING); glDisable(GL_DITHER); glLineWidth(1.f); glBegin(GL_LINES); DBG_fprintf(stderr, "VisuPlane: intersection list of planes %p.\n", (gpointer)planes); visu_plane_set_iter_new(planes->planes, &iter); for (visu_plane_set_iter_next(&iter); iter.plane; visu_plane_set_iter_next(&iter)) for (iter2 = iter, visu_plane_set_iter_next(&iter2); iter2.plane; visu_plane_set_iter_next(&iter2)) if (visu_plane_getRendered(iter.plane) && visu_plane_getRendered(iter2.plane) && visu_plane_getPlaneIntersection(iter.plane, iter2.plane, A, B)) { glColor4f(0.f, 0.f, 0.f, MAX(visu_plane_getOpacity(iter.plane), visu_plane_getOpacity(iter2.plane))); glVertex3fv(A); glVertex3fv(B); } glEnd(); DBG_fprintf(stderr, "VisuPlane: drawing list of planes %p.\n", (gpointer)planes); visu_plane_set_iter_new(planes->planes, &iter); for (visu_plane_set_iter_next(&iter); iter.plane; visu_plane_set_iter_next(&iter)) if (visu_plane_getColor(iter.plane)->rgba[3] == 1.f && visu_plane_getOpacity(iter.plane) == 1.f) visu_plane_draw(iter.plane); visu_plane_set_iter_new(planes->planes, &iter); for (visu_plane_set_iter_next(&iter); iter.plane; visu_plane_set_iter_next(&iter)) if (visu_plane_getColor(iter.plane)->rgba[3] < 1.f || visu_plane_getOpacity(iter.plane) < 1.f) visu_plane_draw(iter.plane); glEnable(GL_LIGHTING); glEnable(GL_DITHER); /* WARNING: it is the default! */ visu_gl_ext_completeDrawing(ext); } v_sim-3.8.0/src/extensions/planes.h000066400000000000000000000100511370110300500172430ustar00rootroot00000000000000/* EXTRAITS DE LA LICENCE Copyright CEA, contributeurs : Damien CALISTE, laboratoire L_Sim, (2001-2013) Adresse mèl : CALISTE, damien P caliste AT cea P fr. Ce logiciel est un programme informatique servant à visualiser des structures atomiques dans un rendu pseudo-3D. Ce logiciel est régi par la licence CeCILL soumise au droit français et respectant les principes de diffusion des logiciels libres. Vous pouvez utiliser, modifier et/ou redistribuer ce programme sous les conditions de la licence CeCILL telle que diffusée par le CEA, le CNRS et l'INRIA sur le site "http://www.cecill.info". Le fait que vous puissiez accéder à cet en-tête signifie que vous avez pris connaissance de la licence CeCILL, et que vous en avez accepté les termes (cf. le fichier Documentation/licence.fr.txt fourni avec ce logiciel). */ /* LICENCE SUM UP Copyright CEA, contributors : Damien CALISTE, laboratoire L_Sim, (2001-2013) E-mail address: CALISTE, damien P caliste AT cea P fr. This software is a computer program whose purpose is to visualize atomic configurations in 3D. This software is governed by the CeCILL license under French law and abiding by the rules of distribution of free software. You can use, modify and/ or redistribute the software under the terms of the CeCILL license as circulated by CEA, CNRS and INRIA at the following URL "http://www.cecill.info". The fact that you are presently reading this means that you have had knowledge of the CeCILL license and that you accept its terms. You can find a copy of this licence shipped with this software at COPYING. */ #ifndef PLANES_H #define PLANES_H #include "frame.h" #include #include #include /** * VISU_TYPE_GL_EXT_PLANES: * * return the type of #VisuGlExtPlanes. * * Since: 3.7 */ #define VISU_TYPE_GL_EXT_PLANES (visu_gl_ext_planes_get_type ()) /** * VISU_GL_EXT_PLANES: * @obj: a #GObject to cast. * * Cast the given @obj into #VisuGlExtPlanes type. * * Since: 3.7 */ #define VISU_GL_EXT_PLANES(obj) (G_TYPE_CHECK_INSTANCE_CAST(obj, VISU_TYPE_GL_EXT_PLANES, VisuGlExtPlanes)) /** * VISU_GL_EXT_PLANES_CLASS: * @klass: a #GObjectClass to cast. * * Cast the given @klass into #VisuGlExtPlanesClass. * * Since: 3.7 */ #define VISU_GL_EXT_PLANES_CLASS(klass) (G_TYPE_CHECK_CLASS_CAST(klass, VISU_TYPE_GL_EXT_PLANES, VisuGlExtPlanesClass)) /** * VISU_IS_GL_EXT_PLANES: * @obj: a #GObject to test. * * Test if the given @ogj is of the type of #VisuGlExtPlanes object. * * Since: 3.7 */ #define VISU_IS_GL_EXT_PLANES(obj) (G_TYPE_CHECK_INSTANCE_TYPE(obj, VISU_TYPE_GL_EXT_PLANES)) /** * VISU_IS_GL_EXT_PLANES_CLASS: * @klass: a #GObjectClass to test. * * Test if the given @klass is of the type of #VisuGlExtPlanesClass class. * * Since: 3.7 */ #define VISU_IS_GL_EXT_PLANES_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE(klass, VISU_TYPE_GL_EXT_PLANES)) /** * VISU_GL_EXT_PLANES_GET_CLASS: * @obj: a #GObject to get the class of. * * It returns the class of the given @obj. * * Since: 3.7 */ #define VISU_GL_EXT_PLANES_GET_CLASS(obj) (G_TYPE_INSTANCE_GET_CLASS(obj, VISU_TYPE_GL_EXT_PLANES, VisuGlExtPlanesClass)) typedef struct _VisuGlExtPlanes VisuGlExtPlanes; typedef struct _VisuGlExtPlanesPrivate VisuGlExtPlanesPrivate; typedef struct _VisuGlExtPlanesClass VisuGlExtPlanesClass; struct _VisuGlExtPlanes { VisuGlExt parent; VisuPlaneSet *planes; VisuGlExtPlanesPrivate *priv; }; struct _VisuGlExtPlanesClass { VisuGlExtClass parent; }; /** * visu_gl_ext_planes_get_type: * * This method returns the type of #VisuGlExtPlanes, use * VISU_TYPE_GL_EXT_PLANES instead. * * Since: 3.7 * * Returns: the type of #VisuGlExtPlanes. */ GType visu_gl_ext_planes_get_type(void); /** * VISU_GL_EXT_PLANES_ID: * * The id used to identify this extension, see * visu_gl_ext_rebuild() for instance. */ #define VISU_GL_EXT_PLANES_ID "Planes" VisuGlExtPlanes* visu_gl_ext_planes_new(const gchar *name); gboolean visu_gl_ext_planes_setBox(VisuGlExtPlanes *ext, VisuBox *box); #endif v_sim-3.8.0/src/extensions/rings.c000066400000000000000000001010541370110300500171020ustar00rootroot00000000000000/* EXTRAITS DE LA LICENCE Copyright CEA, contributeurs : Damien CALISTE, laboratoire L_Sim, (2001-2009) David WAROQUIERS, PCPM UC Louvain la Neuve (2009) Adresse mèl : WAROQUIERS, david P waroquiers AT uclouvain P be CALISTE, damien P caliste AT cea P fr. Ce logiciel est un programme informatique servant à visualiser des structures atomiques dans un rendu pseudo-3D. Ce logiciel est régi par la licence CeCILL soumise au droit français et respectant les principes de diffusion des logiciels libres. Vous pouvez utiliser, modifier et/ou redistribuer ce programme sous les conditions de la licence CeCILL telle que diffusée par le CEA, le CNRS et l'INRIA sur le site "http://www.cecill.info". Le fait que vous puissiez accéder à cet en-tête signifie que vous avez pris connaissance de la licence CeCILL, et que vous en avez accepté les termes (cf. le fichier Documentation/licence.fr.txt fourni avec ce logiciel). */ /* LICENCE SUM UP Copyright CEA, contributors : Damien CALISTE, laboratoire L_Sim, (2001-2009) David WAROQUIERS, PCPM UC Louvain la Neuve (2009) E-mail address: CALISTE, damien P caliste AT cea P fr WAROQUIERS, david P waroquiers AT uclouvain P be This software is a computer program whose purpose is to visualize atomic configurations in 3D. This software is governed by the CeCILL license under French law and abiding by the rules of distribution of free software. You can use, modify and/ or redistribute the software under the terms of the CeCILL license as circulated by CEA, CNRS and INRIA at the following URL "http://www.cecill.info". The fact that you are presently reading this means that you have had knowledge of the CeCILL license and that you accept its terms. You can find a copy of this licence shipped with this software at COPYING. */ #include "rings.h" #include #include #include #include #include /** * SECTION: rings * @short_description: an extension to highlight closed rings in a structure. * * TODO */ static VisuGlExt* extRings; static gboolean extRingsIsBuilt; /* static gulong popInc_signal, popDec_signal, popChg_signal; */ /* Local callbacks. */ /* static void onNodePopulationChanged(VisuData *dataObj, GArray *nodes, gpointer data); */ /* static void onPositionChanged(VisuData *dataObj, gpointer data _U_); */ /* Local routines. */ /* static void rebuildRings(VisuGlExt *ext, VisuData *dataObj, */ /* VisuGlView *view, gpointer data); */ void changeCoordfromBoxChange(VisuData *dataObj, float *coord, float boxChange[3], float *newcoord); #define RADTODEG 57.29577951 /* Some test rings that are relevant */ #define NB_NODES8 8 #define NB_NODES16 16 #define NB_NODES10 10 #define NB_NODES5 5 #define NB_NODES NB_NODES16 int testring_1[NB_NODES8] = {30,69,14,60,2,55,31,71}; /* NB_NODES 8*/ int testring_2[NB_NODES8] = {10,53,15,50,22,71,11,67}; /* NB_NODES 8*/ int testring_3[NB_NODES16] = {2,55,46,64,4,67,11,71,30,69,45,56,6,65,3,60}; /* NB_NODES 16*/ int testring_4[NB_NODES16] = {6,56,45,69,30,71,11,67,10,53,43,63,23,51,35,65}; /* NB_NODES 16*/ int testring[NB_NODES16] = {22,50,9,68,36,63,23,51,35,65,3,60,14,69,30,71}; /* NB_NODES 16*/ int testring_6[NB_NODES10] = {26,54,47,69,30,71,31,55,21,66}; /* NB_NODES 10*/ int testring_7[NB_NODES5] = {60,39,8,61,14}; /* NB_NODES 10*/ typedef struct { int drawSpheres; int drawCylinders; int drawTrianglePlanars; float sphereRadius; float sphereColor[4]; float cylinderRadius; float cylinderColor[4]; float trianglePlanarsColor[4]; } ringVisualisation; /** * initExtRings: (skip) * * Initialise the ring extension, internal routine, do not use. * * Since: 3.5 * * Returns: a newly allocated #VisuGlExt. */ VisuGlExt* initExtRings() { /* char *name = EXT_RINGS_ID; */ /* char *description = _("Draw a representation for the rings in an atomic structures."); */ DBG_fprintf(stderr,"Ext Rings: initialising the rings OpenGL extension...\n"); /* extRings = visu_gl_ext_new(name, _(name), description, */ /* 1, rebuildRings, (gpointer)0); */ /* visu_gl_ext_setActive(extRings, FALSE); */ extRings = (VisuGlExt*)0; extRingsIsBuilt = FALSE; /* Disable rings extension for now. */ return extRings; } /** * extRingsSet_isOn: * @value: a boolean. * * Set if rings are drawn or not. * * Since: 3.5 * * Returns: TRUE is status is changed. */ gboolean extRingsSet_isOn(gboolean value) { if (!visu_gl_ext_setActive(extRings, value)) return FALSE; return (value && !extRingsIsBuilt); } /** * extRingsGet_isOn: * * Retrieves if the ring extension is used. * * Since: 3.5 * * Returns: TRUE if ring extension is used. */ gboolean extRingsGet_isOn() { return visu_gl_ext_getActive(extRings); } /* static void onDataReadySignal(GObject *obj _U_, VisuData *dataObj, */ /* VisuGlView *view, gpointer data _U_) */ /* { */ /* DBG_fprintf(stderr, "Ext Rings: catch 'dataRendered' signal.\n"); */ /* if (dataObj && visu_gl_ext_getActive(extRings)) */ /* { */ /* if (visu_data_getChangeElementFlag(dataObj)) */ /* { */ /* DBG_fprintf(stderr,"Ext Rings: elements not changed, keep it.\n"); */ /* return; */ /* } */ /* extRingsIsBuilt = FALSE; */ /* extRingsDraw(dataObj); */ /* } */ /* if (dataObj && view) */ /* { */ /* popInc_signal = */ /* g_signal_connect(G_OBJECT(dataObj), "PopulationIncrease", */ /* G_CALLBACK(onNodePopulationChanged), (gpointer)0); */ /* popDec_signal = */ /* g_signal_connect(G_OBJECT(dataObj), "PopulationDecrease", */ /* G_CALLBACK(onNodePopulationChanged), (gpointer)0); */ /* popChg_signal = */ /* g_signal_connect(G_OBJECT(dataObj), "PositionChanged", */ /* G_CALLBACK(onPositionChanged), (gpointer)0); */ /* } */ /* } */ /* static void onDataNotReadySignal(GObject *obj _U_, VisuData *dataObj, */ /* VisuGlView *view _U_, gpointer data _U_) */ /* { */ /* g_signal_handler_disconnect(G_OBJECT(dataObj), popInc_signal); */ /* g_signal_handler_disconnect(G_OBJECT(dataObj), popDec_signal); */ /* g_signal_handler_disconnect(G_OBJECT(dataObj), popChg_signal); */ /* } */ /* static void onNodePopulationChanged(VisuData *dataObj, GArray *nodes _U_, */ /* gpointer data _U_) */ /* { */ /* if (visu_gl_ext_getActive(extRings)) */ /* { */ /* extRingsIsBuilt = FALSE; */ /* extRingsDraw(dataObj); */ /* } */ /* } */ /* static void onPositionChanged(VisuData *dataObj, gpointer data _U_) */ /* { */ /* if (visu_gl_ext_getActive(extRings)) */ /* { */ /* extRingsIsBuilt = FALSE; */ /* extRingsDraw(dataObj); */ /* } */ /* } */ /* static void rebuildRings(VisuGlExt *ext _U_, VisuData *dataObj, */ /* VisuGlView *view _U_, gpointer data _U_) */ /* { */ /* extRingsIsBuilt = FALSE; */ /* extRingsDraw(dataObj); */ /* } */ void drawCylinder(float x1, float y1, float z1, float x2, float y2, float z2, float cylRad, int nFaces) { double vNorm[3]; double vDest[3]; double cosAlpha; double alpha; double distsq; GLUquadricObj *obj; DBG_fprintf(stderr, "Drawing Cylinder between points (%.4f,%.4f,%.4f) and (%.4f,%.4f,%.4f)\n",x1 , y1 , z1, x2, y2, z2); vDest[0] = x2 - x1; vDest[1] = y2 - y1; vDest[2] = z2 - z1; distsq = (vDest[0]*vDest[0])+(vDest[1]*vDest[1])+(vDest[2]*vDest[2]); if (vDest[0] != 0 || vDest[1] != 0) { vNorm[0] = - vDest[1]; vNorm[1] = vDest[0]; vNorm[2] = 0.; cosAlpha = sqrt((vDest[2] * vDest[2]) / distsq); if (vDest[2] < 0.) cosAlpha = - cosAlpha; cosAlpha = CLAMP(cosAlpha, -1., 1.); alpha = acos(cosAlpha) * RADTODEG; } else { vNorm[0] = 1.; vNorm[1] = 0.; vNorm[2] = 0.; if (vDest[2] < 0.) alpha = 180.; else alpha = 0.; } obj = gluNewQuadric(); glPushMatrix(); glTranslated(x1, y1, z1); glRotated(alpha, vNorm[0], vNorm[1], vNorm[2]); gluCylinder(obj, (GLdouble)cylRad, (GLdouble)cylRad, (GLdouble)sqrt(distsq), (GLint)nFaces, (GLint)1); glPopMatrix(); gluDeleteQuadric(obj); } void drawSphere(float x1, float y1, float z1, float sphRad, int longit, int latit) { GLUquadricObj *obj; DBG_fprintf(stderr, "Drawing Sphere at point (%.4f,%.4f,%.4f)\n",x1 , y1 , z1); obj = gluNewQuadric(); glPushMatrix(); glTranslated(x1, y1, z1); gluSphere(obj, sphRad, longit, latit); glPopMatrix(); gluDeleteQuadric(obj); } void drawRingPlanar(int ringSize, float *xyzPts, float *boxRing, float bary[3], float baryBox[3]) { int i; glBegin(GL_TRIANGLES); for (i = 0; i < ringSize-1; i++) { if (baryBox[0] == *(boxRing + i*3) && baryBox[1] == *(boxRing + i*3 + 1) && baryBox[2] == *(boxRing + i*3 + 2)) { if (baryBox[0] == *(boxRing + i*3 + 3) && baryBox[1] == *(boxRing + i*3 + 4) && baryBox[2] == *(boxRing + i*3 + 5)) { glVertex3fv(bary); glVertex3fv(xyzPts + i*3); glVertex3fv(xyzPts + i*3 + 3); } } } if (baryBox[0] == *(boxRing + (ringSize-1)*3) && baryBox[1] == *(boxRing + (ringSize-1)*3 + 1) && baryBox[2] == *(boxRing + (ringSize-1)*3 + 2)) { if (baryBox[0] == *(boxRing) && baryBox[1] == *(boxRing + 1) && baryBox[2] == *(boxRing + 2)) { glVertex3fv(bary); glVertex3fv(xyzPts + (ringSize-1)*3); glVertex3fv(xyzPts); } } glEnd(); } void computeBaryCenter(VisuData *dataObj, int ringSize, float *xyz, float *boxRing, float *baryCoord, float *baryBox) { int i; int bBox[3]; float sum[3] = {0.0,0.0,0.0}; float tmp[3]; float tmp2[3]; DBG_fprintf(stderr, "Computing barycenter of the ring\n"); for (i = 0; i < ringSize; i++) { tmp[0] = *(boxRing + 3*i); tmp[1] = *(boxRing + 3*i + 1); tmp[2] = *(boxRing + 3*i + 2); tmp2[0] = *(xyz + 3*i); tmp2[1] = *(xyz + 3*i + 1); tmp2[2] = *(xyz + 3*i + 2); changeCoordfromBoxChange(dataObj, tmp2, tmp, baryCoord); sum[0] = sum[0] + *(baryCoord); sum[1] = sum[1] + *(baryCoord + 1); sum[2] = sum[2] + *(baryCoord + 2); } *(baryCoord) = sum[0]/ringSize; *(baryCoord + 1) = sum[1]/ringSize; *(baryCoord + 2) = sum[2]/ringSize; visu_data_getNodeBoxFromCoord(dataObj, baryCoord, bBox); *(baryBox) = (float)bBox[0]; *(baryBox + 1) = (float)bBox[1]; *(baryBox + 2) = (float)bBox[2]; tmp[0] = -*(baryBox); tmp[1] = -*(baryBox + 1); tmp[2] = -*(baryBox + 2); tmp2[0] = *(baryCoord); tmp2[1] = *(baryCoord + 1); tmp2[2] = *(baryCoord + 2); changeCoordfromBoxChange(dataObj, tmp2, tmp, baryCoord); DBG_fprintf(stderr, "Barycenter of the ring :\n - coordinates (in center box) : %f %f %f \n - box associated : %f %f %f \n", *(baryCoord), *(baryCoord + 1), *(baryCoord + 2), *(baryBox), *(baryBox + 1), *(baryBox + 2)); } void drawRingCylinder(int nbOfPairs, float *xyzPts) { float radius = 0.3; int nFaces = 10; int i; for (i = 0; i < nbOfPairs; i++) { drawCylinder((xyzPts + i*6)[0], (xyzPts + i*6)[1], (xyzPts + i*6)[2], (xyzPts + i*6 + 3)[0],(xyzPts + i*6 + 3)[1], (xyzPts + i*6 + 3)[2], radius, nFaces); } } void drawRingSpheres(int nbOfPairs, float *xyzPts, int *atomInd) { int i; for (i = 0; i < 2*nbOfPairs; i++) { if (*(atomInd + i)) drawSphere(*(xyzPts + 3*i), *(xyzPts + 3*i + 1), *(xyzPts + 3*i + 2), 0.4, 10, 10); } } void drawRingLine(int nbOfPairs, float *xyzPts) { int i; glBegin(GL_LINES); for (i = 0; i < nbOfPairs; i++) { glVertex3fv(xyzPts + i * 6); glVertex3fv(xyzPts + i * 6 + 3); } glEnd(); } void initTranslationForBoxAndCoord(VisuData *dataObj, int ringSize, float *xyz, float *boxRing) { float xyzTrans[3]; float boxTrans[3]; int i, j, nodeBox[3]; visu_pointset_getTranslation(VISU_POINTSET(dataObj), boxTrans); DBG_fprintf(stderr, "Initializing translation for the box indices and coordinates of the ring : \n"); DBG_fprintf(stderr, " with a box translation of %f %f %f\n", boxTrans[0], boxTrans[1], boxTrans[2]); DBG_fprintf(stderr, "Initializing translation for the box indices and coordinates of the ring : \n"); for (i = 0; i < ringSize; i++) /* Get the coordinates of the nodes */ { for (j = 0; j < 3; j++) { xyzTrans[j] = *(xyz + 3*i + j) + boxTrans[j]; /* *(boxRing + 3*i + j) = *(boxRing + 3*i + j);*/ } visu_data_getNodeBoxFromCoord(dataObj, xyzTrans, nodeBox); for (j = 0; j < 3; j++) { DBG_fprintf(stderr, " %d", nodeBox[j]); *(boxRing + 3*i + j) = *(boxRing + 3*i + j) + nodeBox[j]; } DBG_fprintf(stderr, "\n"); } g_free(boxTrans); } void initRing(VisuData *dataObj _U_, int ringSize, float *xyz _U_, float *boxRing, float *boxChange, int *totNbPts) { int i, j; /* float initBoxChange[ringSize][3]; */ *totNbPts = ringSize; DBG_fprintf(stderr, "Initializing boxChange of a ring : \n"); for (i = 0; i < ringSize-1; i++) { for (j = 0; j < 3; j++) { *(boxChange + 3*i + j) = *(boxRing + 3*(i+1) + j) - *(boxRing + 3*i + j); DBG_fprintf(stderr, " %.1f", *(boxChange + 3*i + j)); } DBG_fprintf(stderr, "\n"); } for (j = 0; j < 3; j++) { *(boxChange + 3*(ringSize-1) + j) = *(boxRing + j) - *(boxRing + 3*(ringSize-1) + j); DBG_fprintf(stderr, " %.1f", *(boxChange + 3*(ringSize-1) + j)); } DBG_fprintf(stderr, "\n"); for (i = 0; i < ringSize; i++) /* Calculate the total number of points needed to draw the rings */ { for (j = 0; j < 3; j++) { *totNbPts = *totNbPts + ABS(*(boxChange + 3*i + j)); } } *totNbPts = *totNbPts * 2; DBG_fprintf(stderr, "Total number of points for this ring (including intersections with the box) : %d \n",*totNbPts); } void changeCoordfromBoxChange(VisuData *dataObj, float *coord, float boxChange[3], float *newcoord) { float xyz[3], bxyz[3]; int i; xyz[0] = *(coord); xyz[1] = *(coord + 1); xyz[2] = *(coord + 2); visu_box_convertXYZtoBoxCoordinates(visu_boxed_getBox(VISU_BOXED(dataObj)), bxyz, xyz); for (i = 0; i < 3; i++) { bxyz[i] = bxyz[i] + boxChange[i]; } visu_box_convertBoxCoordinatestoXYZ(visu_boxed_getBox(VISU_BOXED(dataObj)), (float*)newcoord, bxyz); DBG_fprintf(stderr, "Changing coordinate (%f %f %f) from box change (%.1f %.1f %.1f) to (%f %f %f)\n", xyz[0],xyz[1],xyz[2],boxChange[0],boxChange[1],boxChange[2],*(newcoord),*(newcoord + 1),*(newcoord + 2)); } void setVisuPlaneFromBoxChange(VisuData *dataObj, float boxChange[3], VisuPlane *plane) { float tmpCoord[3], norm, distToOrigin = 0; float boxMatrix[3][3]; float boxToOrtho[3][3]; float normal[3]; float bC[3]; float point[3]; /* float xyz[3];*/ int i, j; /* Change the transformation matrix. */ DBG_fprintf(stderr, "Setting a new plane from boxchange %.1f %.1f %.1f :\n", boxChange[0], boxChange[1], boxChange[2]); for (j = 0; j < 3; j++) { if (boxChange[j] < 0.) bC[j] = boxChange[j] + 1.; else bC[j] = boxChange[j]; tmpCoord[0] = (j == 0)?1.:0.; tmpCoord[1] = (j == 1)?1.:0.; tmpCoord[2] = (j == 2)?1.:0.; visu_box_convertBoxCoordinatestoXYZ(visu_boxed_getBox(VISU_BOXED(dataObj)), boxMatrix[j], tmpCoord); } /* We create a matrix to transform the box coordinates to cartesian values keeping the orthogonality. */ for (i = 0; i < 3; i++) { norm = 0.; for (j = 0; j < 3; j++) { boxToOrtho[j][i] = boxMatrix[(i + 1)%3][(j + 1)%3] * boxMatrix[(i + 2)%3][(j + 2)%3] - boxMatrix[(i + 1)%3][(j + 2)%3] * boxMatrix[(i + 2)%3][(j + 1)%3]; norm += boxToOrtho[j][i] * boxToOrtho[j][i]; } /* We normalise the tranformation matrix. */ norm = sqrt(norm); for (j = 0; j < 3; j++) boxToOrtho[j][i] /= norm; } tool_matrix_productVector(normal, boxToOrtho, boxChange); DBG_fprintf(stderr, " - normal vector : %f %f %f\n", normal[0], normal[1], normal[2]); visu_plane_setNormalVector(plane,normal); visu_plane_getNVect(plane,normal); DBG_fprintf(stderr, " - normal vector (normalized) : %f %f %f\n", normal[0], normal[1], normal[2]); visu_box_convertBoxCoordinatestoXYZ(visu_boxed_getBox(VISU_BOXED(dataObj)), point, bC); for (i = 0; i < 3; i++) { distToOrigin += normal[i]*point[i]; } DBG_fprintf(stderr, " - distance to origin : %f\n", distToOrigin); visu_plane_setDistanceFromOrigin(plane, distToOrigin); } void initDrawCoord(VisuData *dataObj, int ringSize, int *atomInd, float *xyz, float *boxChange, float *drawCoord, int totalNumberOfPoints _U_) {/* Initialize the drawCoordinates : for a given ring size RS and a give number of intersected planes NP, the number of coordinates is 2*(RS + NP), ie one pair of coordinates for each element to draw. */ int i, j, k = 0; int np; int l, p; float A[3], B[3], xrB[3], bC[3], tBC[3] = {0.,0.,0.}; float *inter; float *change; int *index; VisuPlane **listOfVisuPlanes; /* Number of planes + 1 (in order to get a NULL at the end and stop)*/ for (j = 0; j < 3; j++) { *(drawCoord + j) = *(xyz + j); *(atomInd) = 1; } DBG_fprintf(stderr, "Point added (first point) to drawCoord %f %f %f from box (0 0 0)\n", *(drawCoord + 3*k), *(drawCoord + 3*k + 1), *(drawCoord + 3*k + 2)); k++; for (i = 0; i < ringSize-1; i++) { if ( (*(boxChange + 3*i) == 0.) && (*(boxChange + 3*i + 1) == 0.) && (*(boxChange + 3*i + 2) == 0.) ) { *(drawCoord + 3*k) = *(xyz + 3*(i+1)); *(drawCoord + 3*k + 1) = *(xyz + 3*(i+1) + 1); *(drawCoord + 3*k + 2) = *(xyz + 3*(i+1) + 2); DBG_fprintf(stderr, "Point added to drawCoord %f %f %f from box (0 0 0)\n", *(drawCoord + 3*k), *(drawCoord + 3*k + 1), *(drawCoord + 3*k + 2)); *(atomInd + k) = 1; k++; *(drawCoord + 3*k) = *(xyz + 3*(i+1)); *(drawCoord + 3*k + 1) = *(xyz + 3*(i+1) + 1); *(drawCoord + 3*k + 2) = *(xyz + 3*(i+1) + 2); DBG_fprintf(stderr, "Point added to drawCoord %f %f %f from box (0 0 0)\n", *(drawCoord + 3*k), *(drawCoord + 3*k + 1), *(drawCoord + 3*k + 2)); *(atomInd + k) = 1; k++; } else { np = ABS(*(boxChange + 3*i)) + ABS(*(boxChange + 3*i + 1)) + ABS(*(boxChange + 3*i + 2)); inter = g_malloc(sizeof(float) * np * 3); change = g_malloc(sizeof(float) * np * 3); index = g_malloc(sizeof(float) * np); for (j = 0; j < 3; j++) { A[j] = *(xyz + 3*i + j); B[j] = *(xyz + 3*(i+1) + j); } DBG_fprintf(stderr, "Point A : %f %f %f\nPoint B : %f %f %f\n", A[0],A[1],A[2],B[0],B[1],B[2]); DBG_fprintf(stderr, "BoxChange for B : %.1f %.1f %.1f\n", *(boxChange + 3*i),*(boxChange + 3*i + 1),*(boxChange + 3*i + 2)); visu_box_convertXYZtoBoxCoordinates(visu_boxed_getBox(VISU_BOXED(dataObj)), xrB, B); xrB[0] = xrB[0] + *(boxChange + 3*i); xrB[1] = xrB[1] + *(boxChange + 3*i + 1); xrB[2] = xrB[2] + *(boxChange + 3*i + 2); visu_box_convertBoxCoordinatestoXYZ(visu_boxed_getBox(VISU_BOXED(dataObj)), B, xrB); DBG_fprintf(stderr, "Point B after BoxChange : %f %f %f\n",B[0],B[1],B[2]); listOfVisuPlanes = g_malloc(sizeof(VisuPlane*) * (np + 1)); listOfVisuPlanes[np] = (VisuPlane*)0; p = 0; for (j = 0; j < 3; j++) { bC[0] = 0.; bC[1] = 0.; bC[2] = 0.; for (l = 0; l < ABS(*(boxChange + 3*i + j)); l++) { if (*(boxChange + 3*i + j) > 0.) { bC[j] = (float)(+l+1); } else if (*(boxChange + 3*i + j) < 0.) { bC[j] = (float)(-l-1); } listOfVisuPlanes[p] = visu_plane_newUndefined(); setVisuPlaneFromBoxChange(dataObj, bC, listOfVisuPlanes[p]); change[3 * p + 0] = bC[0]; change[3 * p + 1] = bC[1]; change[3 * p + 2] = bC[2]; p++; } } if (visu_plane_class_getOrderedIntersections(np, listOfVisuPlanes, A, B, (float*)inter, (int*)index)) { tBC[0] = 0.; tBC[1] = 0.; tBC[2] = 0.; for (p = 0; p < np; p++) { A[0] = inter[3 * p + 0]; A[1] = inter[3 * p + 1]; A[2] = inter[3 * p + 2]; changeCoordfromBoxChange(dataObj, A, tBC, B); *(drawCoord + 3*k) = B[0]; *(drawCoord + 3*k + 1) = B[1]; *(drawCoord + 3*k + 2) = B[2]; /* *(drawCoord + 3*k) = inter[p][0]; *(drawCoord + 3*k + 1) = inter[p][1]; *(drawCoord + 3*k + 2) = inter[p][2];*/ DBG_fprintf(stderr, "Point added to drawCoord %f %f %f for a plane\n", *(drawCoord + 3*k), *(drawCoord + 3*k + 1), *(drawCoord + 3*k + 2)); *(atomInd + k) = 0; k++; if (change[index[p] * 3 + 0] < 0.) tBC[0] = tBC[0] + 1.; else if (change[index[p] * 3 + 0] > 0.) tBC[0] = tBC[0] - 1.; if (change[index[p] * 3 + 1] < 0.) tBC[1] = tBC[1] + 1.; else if (change[index[p] * 3 + 1] > 0.) tBC[1] = tBC[1] - 1.; if (change[index[p] * 3 + 2] < 0.) tBC[2] = tBC[2] + 1.; else if (change[index[p] * 3 + 2] > 0.) tBC[2] = tBC[2] - 1.; DBG_fprintf(stderr, "Change of box needed for the next point : %f %f %f\n", tBC[0],tBC[1],tBC[2]); A[0] = inter[p * 3 + 0]; A[1] = inter[p * 3 + 1]; A[2] = inter[p * 3 + 2]; changeCoordfromBoxChange(dataObj, A, tBC, B); *(drawCoord + 3*k) = B[0]; *(drawCoord + 3*k + 1) = B[1]; *(drawCoord + 3*k + 2) = B[2]; DBG_fprintf(stderr, "Point added to drawCoord %f %f %f for a plane\n", *(drawCoord + 3*k), *(drawCoord + 3*k + 1), *(drawCoord + 3*k + 2)); *(atomInd + k) = 0; k++; } *(drawCoord + 3*k) = *(xyz + 3*(i+1)); *(drawCoord + 3*k + 1) = *(xyz + 3*(i+1) + 1); *(drawCoord + 3*k + 2) = *(xyz + 3*(i+1) + 2); DBG_fprintf(stderr, "Point added to drawCoord %f %f %f after planes\n", *(drawCoord + 3*k), *(drawCoord + 3*k + 1), *(drawCoord + 3*k + 2)); *(atomInd + k) = 1; k++; *(drawCoord + 3*k) = *(xyz + 3*(i+1)); *(drawCoord + 3*k + 1) = *(xyz + 3*(i+1) + 1); *(drawCoord + 3*k + 2) = *(xyz + 3*(i+1) + 2); DBG_fprintf(stderr, "Point added to drawCoord %f %f %f after planes\n", *(drawCoord + 3*k), *(drawCoord + 3*k + 1), *(drawCoord + 3*k + 2)); *(atomInd + k) = 1; k++; } else { DBG_fprintf(stderr, "WARNING : visu_plane_class_getOrderedIntersections did not find any plane !!!\n"); } g_free(listOfVisuPlanes); g_free(inter); g_free(change); g_free(index); } } if ( (*(boxChange + 3*(ringSize-1)) == 0.) && (*(boxChange + 3*(ringSize-1) + 1) == 0.) && (*(boxChange + 3*(ringSize-1) + 2) == 0.) ) { *(drawCoord + 3*k) = *(xyz); *(drawCoord + 3*k + 1) = *(xyz + 1); *(drawCoord + 3*k + 2) = *(xyz + 2); DBG_fprintf(stderr, "Point added to drawCoord %f %f %f from box (0 0 0)\n", *(drawCoord + 3*k), *(drawCoord + 3*k + 1), *(drawCoord + 3*k + 2)); *(atomInd + k) = 1; k++; } else { np = ABS(*(boxChange + 3*(ringSize-1))) + ABS(*(boxChange + 3*(ringSize-1) + 1)) + ABS(*(boxChange + 3*(ringSize-1) + 2)); inter = g_malloc(sizeof(float) * np * 3); change = g_malloc(sizeof(float) * np * 3); index = g_malloc(sizeof(float) * np); for (j = 0; j < 3; j++) { A[j] = *(xyz + 3*(ringSize-1) + j); B[j] = *(xyz + j); } DBG_fprintf(stderr, "Point A : %f %f %f\nPoint B : %f %f %f\n", A[0],A[1],A[2],B[0],B[1],B[2]); DBG_fprintf(stderr, "BoxChange for B : %.1f %.1f %.1f\n", *(boxChange + 3*(ringSize-1)),*(boxChange + 3*(ringSize-1) + 1), *(boxChange + 3*(ringSize-1) + 2)); visu_box_convertXYZtoBoxCoordinates(visu_boxed_getBox(VISU_BOXED(dataObj)), xrB, B); xrB[0] = xrB[0] + *(boxChange + 3*(ringSize-1)); xrB[1] = xrB[1] + *(boxChange + 3*(ringSize-1) + 1); xrB[2] = xrB[2] + *(boxChange + 3*(ringSize-1) + 2); visu_box_convertBoxCoordinatestoXYZ(visu_boxed_getBox(VISU_BOXED(dataObj)), B, xrB); DBG_fprintf(stderr, "Point B after BoxChange : %f %f %f\n",B[0],B[1],B[2]); listOfVisuPlanes = g_malloc(sizeof(VisuPlane*) * (np + 1)); listOfVisuPlanes[np] = (VisuPlane*)0; p = 0; for (j = 0; j < 3; j++) { bC[0] = 0.; bC[1] = 0.; bC[2] = 0.; for (l = 0; l < ABS(*(boxChange + 3*(ringSize-1) + j)); l++) { if (*(boxChange + 3*(ringSize-1) + j) > 0.) { bC[j] = (float)(+l+1); } else if (*(boxChange + 3*(ringSize-1) + j) < 0.) { bC[j] = (float)(-l-1); } listOfVisuPlanes[p] = visu_plane_newUndefined(); setVisuPlaneFromBoxChange(dataObj, bC, listOfVisuPlanes[p]); change[p * 3 + 0] = bC[0]; change[p * 3 + 1] = bC[1]; change[p * 3 + 2] = bC[2]; p++; } } if (visu_plane_class_getOrderedIntersections(np, listOfVisuPlanes, A, B, (float*)inter, (int*)index)) { tBC[0] = 0.; tBC[1] = 0.; tBC[2] = 0.; for (p = 0; p < np; p++) { A[0] = inter[3 * p + 0]; A[1] = inter[3 * p + 1]; A[2] = inter[3 * p + 2]; changeCoordfromBoxChange(dataObj, A, tBC, B); *(drawCoord + 3*k) = B[0]; *(drawCoord + 3*k + 1) = B[1]; *(drawCoord + 3*k + 2) = B[2]; /* *(drawCoord + 3*k) = inter[p][0]; *(drawCoord + 3*k + 1) = inter[p][1]; *(drawCoord + 3*k + 2) = inter[p][2];*/ DBG_fprintf(stderr, "Point added to drawCoord %f %f %f for a plane\n", *(drawCoord + 3*k), *(drawCoord + 3*k + 1), *(drawCoord + 3*k + 2)); *(atomInd + k) = 0; k++; if (change[index[p] * 3 + 0] < 0.) tBC[0] = tBC[0] + 1.; else if (change[index[p] * 3 + 0] > 0.) tBC[0] = tBC[0] - 1.; if (change[index[p] * 3 + 1] < 0.) tBC[1] = tBC[1] + 1.; else if (change[index[p] * 3 + 1] > 0.) tBC[1] = tBC[1] - 1.; if (change[index[p] * 3 + 2] < 0.) tBC[2] = tBC[2] + 1.; else if (change[index[p] * 3 + 2] > 0.) tBC[2] = tBC[2] - 1.; DBG_fprintf(stderr, "Change of box needed for the next point : %f %f %f\n", tBC[0],tBC[1],tBC[2]); A[0] = inter[p * 3 + 0]; A[1] = inter[p * 3 + 1]; A[2] = inter[p * 3 + 2]; changeCoordfromBoxChange(dataObj, A, tBC, B); *(drawCoord + 3*k) = B[0]; *(drawCoord + 3*k + 1) = B[1]; *(drawCoord + 3*k + 2) = B[2]; DBG_fprintf(stderr, "Point added to drawCoord %f %f %f for a plane\n", *(drawCoord + 3*k), *(drawCoord + 3*k + 1), *(drawCoord + 3*k + 2)); *(atomInd + k) = 0; k++; } *(drawCoord + 3*k) = *(xyz); *(drawCoord + 3*k + 1) = *(xyz + 1); *(drawCoord + 3*k + 2) = *(xyz + 2); DBG_fprintf(stderr, "Point added to drawCoord %f %f %f after planes\n", *(drawCoord + 3*k), *(drawCoord + 3*k + 1), *(drawCoord + 3*k + 2)); *(atomInd + k) = 1; k++; } else { DBG_fprintf(stderr, "WARNING : visu_plane_class_getOrderedIntersections did not find any plane !!!\n"); } g_free(listOfVisuPlanes); g_free(inter); g_free(change); g_free(index); } } /** * extRingsDraw: * @dataObj: a #VisuData object. * * Draw the rings (if any). * * Since: 3.5 */ void extRingsDraw(VisuData *dataObj) { /* float boxring_1[NB_NODES8][3] = {0.,0.,0.,0.,0.,0.,1.,0.,0.,1.,0.,0.,1.,0.,0.,1.,0.,0.,1.,0.,0.,0.,0.,0.}; */ /* float boxring_2[NB_NODES8][3] = {0.,0.,0.}; */ /* float boxring_3[NB_NODES16][3] = {0.}; */ /* float boxring_4[NB_NODES16][3] = {0.,0.,0.}; */ /* float boxring[NB_NODES16][3] = {0.,0.,0.,0.,0.,0.,1.,0.,0.,1.,0.,0.,1.,0.,0.,1.,0.,0.,1.,0.,0.,1.,0.,0.,1.,0.,0.,1.,0.,0.,1.,0.,0.,1.,0.,0.,1.,0.,0.,0.,0.,0.,0.,0.,0.,0.,0.,0.}; */ /* float boxring_6[NB_NODES10][3] = {0.,0.,0.,0.,0.,1.,0.,0.,1.,0.,0.,1.,0.,0.,1.,0.,0.,1.,1.,0.,1.,1.,0.,1.,1.,0.,0.,1.,0.,0.}; */ float boxring_7[NB_NODES5][3] = {{0.,0.,0.},{0.,0.,0.},{-1.,-1.,-1.},{-1.,-1.,-1.},{0.,0.,0.}}; /* int bleh; */ float rgba[4] = {1., 0., 0., 0.5}; int *my_test = testring; int i, j; VisuNode *vtmp; float sum[3] = {0.0,0.0,0.0}; float xyz[NB_NODES][3]; /* The initial coordinates */ /* float XYZ[NB_NODES][3]; */ /* The translated coordinates */ /* float nodeTrans[NB_NODES][3]; */ /* float bary[3]; */ int totalNumberOfPoints; float *drawCoord; int *atomIndices; float boxChange[NB_NODES][3]; /* float newBoxChange[NB_NODES][3]; */ float baryCoord[3]; float baryBox[3]; if (extRingsIsBuilt || !dataObj) return; DBG_fprintf(stderr, "Ext Rings: drawing the rings.\n"); extRingsIsBuilt = TRUE; glNewList(visu_gl_ext_getGlList(extRings), GL_COMPILE); /* for (i = 0; i < 6; i++) */ /* box[i] = visu_data_getBoxGeometry(dataObj, i); */ /* Put the drawing primitives here. */ DBG_fprintf(stderr, "Coordinates in initial box :\n"); for (i = 0; i < NB_NODES; i++) /* Get the coordinates of the nodes */ { vtmp = visu_node_array_getFromId(VISU_NODE_ARRAY(dataObj), my_test[i]); xyz[i][0] = vtmp->xyz[0]; xyz[i][1] = vtmp->xyz[1]; xyz[i][2] = vtmp->xyz[2]; for (j = 0; j < 3; j++) { DBG_fprintf(stderr, " %f",xyz[i][j]); sum[j] = sum[j] + xyz[i][j]; } DBG_fprintf(stderr, "\n"); } /* bary[0] = sum[0]/NB_NODES; /\* Get the barycentre *\/ */ /* bary[1] = sum[1]/NB_NODES; */ /* bary[2] = sum[2]/NB_NODES; */ /* INITIALIZING THE BOXRINGS AND COORDINATES */ initTranslationForBoxAndCoord(dataObj, NB_NODES, (float*)xyz, (float*)boxring_7); for (i = 0; i < NB_NODES; i++) /* Get the coordinates of the nodes */ { vtmp = visu_node_array_getFromId(VISU_NODE_ARRAY(dataObj), my_test[i]); visu_data_getNodePosition(dataObj, vtmp, xyz[i]); } /* INITIALIZING THE RINGS*/ initRing(dataObj, NB_NODES, (float*)xyz, (float*)boxring_7, (float*)boxChange, &totalNumberOfPoints); /*COMPUTE BARYCENTER OF THE RING*/ computeBaryCenter(dataObj, NB_NODES, (float*)xyz, (float*)boxring_7, (float*)baryCoord, (float*)baryBox); /*INITIALIZING THE DRAW COORDINATES*/ atomIndices = g_malloc(sizeof(int) * totalNumberOfPoints); drawCoord = g_malloc(sizeof(float) * 3 * totalNumberOfPoints); initDrawCoord(dataObj, NB_NODES, (int*)atomIndices, (float*)xyz, (float*)boxChange, (float*)drawCoord, totalNumberOfPoints); glDisable(GL_LIGHTING); glDisable(GL_CULL_FACE); glColor4fv(rgba); /* float radius = 0.5; */ rgba[0] = 0.; rgba[1] = 1.; rgba[2] = 0.; rgba[3] = 0.5; glColor4fv(rgba); /* bleh = totalNumberOfPoints/2; */ drawRingPlanar(NB_NODES,(float*)xyz, (float*)boxring_7, baryCoord, baryBox); rgba[0] = 0.; rgba[1] = 1.; rgba[2] = 0.; rgba[3] = 1.; glColor4fv(rgba); /* drawRingCylinder(bleh,(float*)drawCoord);*/ rgba[0] = 0.; rgba[1] = 0.; rgba[2] = 1.; rgba[3] = 1.; /* glColor4fv(rgba); drawSphere(baryCoord[0], baryCoord[1], baryCoord[2], 0.5, 10, 10);*/ rgba[0] = 1.; rgba[1] = 0.; rgba[2] = 0.; rgba[3] = 1.; glColor4fv(rgba); /* drawRingSpheres(bleh, (float*)drawCoord, (int*)atomIndices);*/ /* drawRingLine(bleh,(float*)drawCoord);*/ g_free(atomIndices); g_free(drawCoord); glEnable(GL_CULL_FACE); glEnable(GL_LIGHTING); glEndList(); } v_sim-3.8.0/src/extensions/rings.h000066400000000000000000000050411370110300500171060ustar00rootroot00000000000000/* EXTRAITS DE LA LICENCE Copyright CEA, contributeurs : Damien CALISTE, laboratoire L_Sim, (2001-2009) David WAROQUIERS, PCPM UC Louvain la Neuve (2009) Adresse mèl : WAROQUIERS, david P waroquiers AT uclouvain P be CALISTE, damien P caliste AT cea P fr. Ce logiciel est un programme informatique servant à visualiser des structures atomiques dans un rendu pseudo-3D. Ce logiciel est régi par la licence CeCILL soumise au droit français et respectant les principes de diffusion des logiciels libres. Vous pouvez utiliser, modifier et/ou redistribuer ce programme sous les conditions de la licence CeCILL telle que diffusée par le CEA, le CNRS et l'INRIA sur le site "http://www.cecill.info". Le fait que vous puissiez accéder à cet en-tête signifie que vous avez pris connaissance de la licence CeCILL, et que vous en avez accepté les termes (cf. le fichier Documentation/licence.fr.txt fourni avec ce logiciel). */ /* LICENCE SUM UP Copyright CEA, contributors : Damien CALISTE, laboratoire L_Sim, (2001-2009) David WAROQUIERS, PCPM UC Louvain la Neuve (2009) E-mail address: CALISTE, damien P caliste AT cea P fr WAROQUIERS, david P waroquiers AT uclouvain P be This software is a computer program whose purpose is to visualize atomic configurations in 3D. This software is governed by the CeCILL license under French law and abiding by the rules of distribution of free software. You can use, modify and/ or redistribute the software under the terms of the CeCILL license as circulated by CEA, CNRS and INRIA at the following URL "http://www.cecill.info". The fact that you are presently reading this means that you have had knowledge of the CeCILL license and that you accept its terms. You can find a copy of this licence shipped with this software at COPYING. */ #ifndef RINGS_H #define RINGS_H #include #include /** * EXT_RINGS_ID: * * The id of the ring extension. */ #define EXT_RINGS_ID "Rings" VisuGlExt* initExtRings(); gboolean extRingsSet_isOn(gboolean value); gboolean extRingsGet_isOn(); /** * setVisuPlaneFromBoxChange: * @dataObj: a #VisuData object ; * @boxChange: the boxchange associated to the plane ; * @point: a point through which the plane passes ; * @plane: a VisuPlane declared in which to store the plane properties. * * A method to set a plane corresponding to a box change */ /* void setVisuPlaneFromBoxChange(VisuData *dataObj, float boxChange[3], float point[3], VisuPlane *plane); */ void extRingsDraw(VisuData *dataObj); #endif v_sim-3.8.0/src/extensions/scale.c000066400000000000000000001237331370110300500170570ustar00rootroot00000000000000/* EXTRAITS DE LA LICENCE Copyright CEA, contributeurs : Luc BILLARD et Damien CALISTE, laboratoire L_Sim, (2001-2005) Adresse mèl : BILLARD, non joignable par mèl ; CALISTE, damien P caliste AT cea P fr. Ce logiciel est un programme informatique servant à visualiser des structures atomiques dans un rendu pseudo-3D. Ce logiciel est régi par la licence CeCILL soumise au droit français et respectant les principes de diffusion des logiciels libres. Vous pouvez utiliser, modifier et/ou redistribuer ce programme sous les conditions de la licence CeCILL telle que diffusée par le CEA, le CNRS et l'INRIA sur le site "http://www.cecill.info". Le fait que vous puissiez accéder à cet en-tête signifie que vous avez pris connaissance de la licence CeCILL, et que vous en avez accepté les termes (cf. le fichier Documentation/licence.fr.txt fourni avec ce logiciel). */ /* LICENCE SUM UP Copyright CEA, contributors : Luc BILLARD et Damien CALISTE, laboratoire L_Sim, (2001-2005) E-mail address: BILLARD, not reachable any more ; CALISTE, damien P caliste AT cea P fr. This software is a computer program whose purpose is to visualize atomic configurations in 3D. This software is governed by the CeCILL license under French law and abiding by the rules of distribution of free software. You can use, modify and/ or redistribute the software under the terms of the CeCILL license as circulated by CEA, CNRS and INRIA at the following URL "http://www.cecill.info". The fact that you are presently reading this means that you have had knowledge of the CeCILL license and that you accept its terms. You can find a copy of this licence shipped with this software at Documentation/licence.en.txt. */ #include "scale.h" #include #include #include #include #include #include #include #include #include #include #include /** * SECTION:scale * @short_description: Draw an arrow with a label. * * This little extension is used to draw an arrow at a given position * displaying a given length. * * Since: 3.3 */ /* Parameters & resources*/ /* This is a boolean to control is the axes is render or not. */ #define FLAG_RESOURCE_SCALE_USED "scales_are_on" #define DESC_RESOURCE_SCALE_USED "Control if scales are drawn ; boolean (0 or 1)" static gboolean defaultUsed = FALSE; /* A resource to control the color used to render the lines of the Scale. */ #define FLAG_RESOURCE_SCALE_COLOR "scales_color" #define DESC_RESOURCE_SCALE_COLOR "Define the color RGBA of all scales ; four floating point values (0. <= v <= 1.)" static float _rgba[4] = {0.f, 0.f, 0.f, 1.f}; /* A resource to control the width to render the lines of the Scale. */ #define FLAG_RESOURCE_SCALE_LINE "scales_line_width" #define DESC_RESOURCE_SCALE_LINE "Define the width of the lines of all scales ; one floating point value (1. <= v <= 10.)" static float _width = 1.f; /* A resource to control the width to render the lines of the Scale. */ #define FLAG_RESOURCE_SCALE_STIPPLE "scales_line_stipple" #define DESC_RESOURCE_SCALE_STIPPLE "Define the stipple pattern of the lines of all scales ; one integer value (0 <= v <= 65535)" static guint16 _stipple = 65535; /* A resource to control the elements of a scale (origin, direction, length... */ #define FLAG_RESOURCE_SCALE_DEFINITION "scale_definition" #define DESC_RESOURCE_SCALE_DEFINITION "Define the position, the direction, the length and the legend of a scale ; position[3] direction[3] length legend" #define SCALE_LEGEND_DEFAULT _("Length: %6.2f") /* Export function that is called by visu_module to write the values of resources to a file. */ static void exportResourcesScale(GString *data, VisuData *dataObj); #define SCALE_AUTO_LEGEND "[auto]" typedef struct _Arrow { /* Definition of the scale. */ float origin[3]; float direction[3]; float length; /* Characteristics. */ gboolean drawn; gchar *legendPattern; GString *legend; } Arrow; struct _VisuGlExtScalePrivate { /* Internal object gestion. */ gboolean dispose_has_run; /* A list of arrows. */ GList *arrows; guint iArr; float width; float rgba[4]; guint16 stipple; /* Related objects. */ VisuGlView *view; gulong view_signal; }; enum { PROP_0, COLOR_PROP, WIDTH_PROP, STIPPLE_PROP, N_ARR_PROP, CUR_PROP, CUR_LENGTH_PROP, CUR_LBL_PROP, CUR_ORIG_X_PROP, CUR_ORIG_Y_PROP, CUR_ORIG_Z_PROP, CUR_DIR_X_PROP, CUR_DIR_Y_PROP, CUR_DIR_Z_PROP, N_PROP }; static GParamSpec *properties[N_PROP]; static VisuGlExtScale * defaultScale = NULL; /* Object gestion methods. */ static void visu_gl_ext_lined_interface_init(VisuGlExtLinedInterface *iface); static void scale_dispose (GObject* obj); static void scale_finalize(GObject* obj); static void scale_get_property(GObject* obj, guint property_id, GValue *value, GParamSpec *pspec); static void scale_set_property(GObject* obj, guint property_id, const GValue *value, GParamSpec *pspec); static void scale_rebuild (VisuGlExt *ext); static void scale_draw(VisuGlExt *ext); static gboolean scale_setGlView(VisuGlExt *ext, VisuGlView *view); static gboolean _setRGB(VisuGlExtLined *scale, float rgb[4], int mask); static gboolean _setLineWidth(VisuGlExtLined *scale, float width); static gboolean _setLineStipple(VisuGlExtLined *scale, guint16 stipple); static float* _getRGB(const VisuGlExtLined *scale); static float _getLineWidth(const VisuGlExtLined *scale); static guint16 _getLineStipple(const VisuGlExtLined *scale); /* Local methods. */ static void _freeArrow(Arrow *arr); static void _drawArrow(Arrow *arr, guint nlat); /* Local callbacks */ static void onScaleParametersChange(VisuGlExtScale *scale); static void onEntryUsed(VisuGlExtScale *scale, VisuConfigFileEntry *entry, VisuConfigFile *obj); static void onEntryColor(VisuGlExtScale *scale, VisuConfigFileEntry *entry, VisuConfigFile *obj); static void onEntryWidth(VisuGlExtScale *scale, VisuConfigFileEntry *entry, VisuConfigFile *obj); static void onEntryStipple(VisuGlExtScale *scale, VisuConfigFileEntry *entry, VisuConfigFile *obj); G_DEFINE_TYPE_WITH_CODE(VisuGlExtScale, visu_gl_ext_scale, VISU_TYPE_GL_EXT, G_ADD_PRIVATE(VisuGlExtScale) G_IMPLEMENT_INTERFACE(VISU_TYPE_GL_EXT_LINED, visu_gl_ext_lined_interface_init)) static void visu_gl_ext_lined_interface_init(VisuGlExtLinedInterface *iface) { iface->get_width = _getLineWidth; iface->set_width = _setLineWidth; iface->get_stipple = _getLineStipple; iface->set_stipple = _setLineStipple; iface->get_rgba = _getRGB; iface->set_rgba = _setRGB; } static void visu_gl_ext_scale_class_init(VisuGlExtScaleClass *klass) { float rgColor[2] = {0.f, 1.f}; float rgWidth[2] = {0.f, 10.f}; VisuConfigFileEntry *resourceEntry; DBG_fprintf(stderr, "Scale: creating the class of the object.\n"); /* Connect freeing methods. */ G_OBJECT_CLASS(klass)->dispose = scale_dispose; G_OBJECT_CLASS(klass)->finalize = scale_finalize; G_OBJECT_CLASS(klass)->set_property = scale_set_property; G_OBJECT_CLASS(klass)->get_property = scale_get_property; VISU_GL_EXT_CLASS(klass)->rebuild = scale_rebuild; VISU_GL_EXT_CLASS(klass)->draw = scale_draw; VISU_GL_EXT_CLASS(klass)->setGlView = scale_setGlView; /* Create the entries in config files. */ DBG_fprintf(stderr," - create entries for config file.\n"); resourceEntry = visu_config_file_addBooleanEntry(VISU_CONFIG_FILE_RESOURCE, FLAG_RESOURCE_SCALE_USED, DESC_RESOURCE_SCALE_USED, &defaultUsed, FALSE); visu_config_file_entry_setVersion(resourceEntry, 3.3f); resourceEntry = visu_config_file_addFloatArrayEntry(VISU_CONFIG_FILE_RESOURCE, FLAG_RESOURCE_SCALE_COLOR, DESC_RESOURCE_SCALE_COLOR, 4, _rgba, rgColor, FALSE); visu_config_file_entry_setVersion(resourceEntry, 3.3f); resourceEntry = visu_config_file_addFloatArrayEntry(VISU_CONFIG_FILE_RESOURCE, FLAG_RESOURCE_SCALE_LINE, DESC_RESOURCE_SCALE_LINE, 1, &_width, rgWidth, FALSE); visu_config_file_entry_setVersion(resourceEntry, 3.3f); resourceEntry = visu_config_file_addTokenizedEntry(VISU_CONFIG_FILE_RESOURCE, FLAG_RESOURCE_SCALE_DEFINITION, DESC_RESOURCE_SCALE_DEFINITION, FALSE); visu_config_file_entry_setVersion(resourceEntry, 3.3f); resourceEntry = visu_config_file_addStippleArrayEntry(VISU_CONFIG_FILE_RESOURCE, FLAG_RESOURCE_SCALE_STIPPLE, DESC_RESOURCE_SCALE_STIPPLE, 1, &_stipple); visu_config_file_entry_setVersion(resourceEntry, 3.4f); visu_config_file_addExportFunction(VISU_CONFIG_FILE_RESOURCE, exportResourcesScale); /** * VisuGlExtScale::color: * * Store the color of the scale. * * Since: 3.8 */ g_object_class_override_property(G_OBJECT_CLASS(klass), COLOR_PROP, "color"); /** * VisuGlExtScale::width: * * Store the line width of the scale. * * Since: 3.8 */ g_object_class_override_property(G_OBJECT_CLASS(klass), WIDTH_PROP, "width"); /** * VisuGlExtScale::stipple: * * Store the line stipple pattern of the scale. * * Since: 3.8 */ g_object_class_override_property(G_OBJECT_CLASS(klass), STIPPLE_PROP, "stipple"); /** * VisuGlExtScale::n-arrows: * * Store the number of arrows. * * Since: 3.8 */ properties[N_ARR_PROP] = g_param_spec_uint("n-arrows", "number of arrows", "number of stored arrows", 0, G_MAXUINT, 0, G_PARAM_READABLE); g_object_class_install_property(G_OBJECT_CLASS(klass), N_ARR_PROP, properties[N_ARR_PROP]); /** * VisuGlExtScale::current: * * Store the id of the current arrow. * * Since: 3.8 */ properties[CUR_PROP] = g_param_spec_uint("current", "current arrow", "id of the current arrow", 0, G_MAXUINT, 0, G_PARAM_READWRITE); g_object_class_install_property(G_OBJECT_CLASS(klass), CUR_PROP, properties[CUR_PROP]); /** * VisuGlExtScale::current-length: * * Store the length of the current arrow. * * Since: 3.8 */ properties[CUR_LENGTH_PROP] = g_param_spec_float("current-length", "current arrow length", "length of the current arrow", 0.f, G_MAXFLOAT, 0.f, G_PARAM_READWRITE); g_object_class_install_property(G_OBJECT_CLASS(klass), CUR_LENGTH_PROP, properties[CUR_LENGTH_PROP]); /** * VisuGlExtScale::current-label: * * Store the label of the current arrow. * * Since: 3.8 */ properties[CUR_LBL_PROP] = g_param_spec_string("current-label", "current arrow label", "label of the current arrow", "", G_PARAM_READWRITE); g_object_class_install_property(G_OBJECT_CLASS(klass), CUR_LBL_PROP, properties[CUR_LBL_PROP]); /** * VisuGlExtScale::current-origin-x: * * Store the origin[x] of the current arrow. * * Since: 3.8 */ properties[CUR_ORIG_X_PROP] = g_param_spec_float("current-origin-x", "current arrow origin", "origin of the current arrow", -G_MAXFLOAT, G_MAXFLOAT, 0., G_PARAM_READWRITE); g_object_class_install_property(G_OBJECT_CLASS(klass), CUR_ORIG_X_PROP, properties[CUR_ORIG_X_PROP]); /** * VisuGlExtScale::current-origin-y: * * Store the origin[y] of the current arrow. * * Since: 3.8 */ properties[CUR_ORIG_Y_PROP] = g_param_spec_float("current-origin-y", "current arrow origin", "origin of the current arrow", -G_MAXFLOAT, G_MAXFLOAT, 0., G_PARAM_READWRITE); g_object_class_install_property(G_OBJECT_CLASS(klass), CUR_ORIG_Y_PROP, properties[CUR_ORIG_Y_PROP]); /** * VisuGlExtScale::current-origin-z: * * Store the origin[z] of the current arrow. * * Since: 3.8 */ properties[CUR_ORIG_Z_PROP] = g_param_spec_float("current-origin-z", "current arrow origin", "origin of the current arrow", -G_MAXFLOAT, G_MAXFLOAT, 0., G_PARAM_READWRITE); g_object_class_install_property(G_OBJECT_CLASS(klass), CUR_ORIG_Z_PROP, properties[CUR_ORIG_Z_PROP]); /** * VisuGlExtScale::current-orientation-x: * * Store the orientation[x] of the current arrow. * * Since: 3.8 */ properties[CUR_DIR_X_PROP] = g_param_spec_float("current-orientation-x", "current arrow orientation", "orientation of the current arrow", -G_MAXFLOAT, G_MAXFLOAT, 0., G_PARAM_READWRITE); g_object_class_install_property(G_OBJECT_CLASS(klass), CUR_DIR_X_PROP, properties[CUR_DIR_X_PROP]); /** * VisuGlExtScale::current-orientation-y: * * Store the orientation[y] of the current arrow. * * Since: 3.8 */ properties[CUR_DIR_Y_PROP] = g_param_spec_float("current-orientation-y", "current arrow orientation", "orientation of the current arrow", -G_MAXFLOAT, G_MAXFLOAT, 0., G_PARAM_READWRITE); g_object_class_install_property(G_OBJECT_CLASS(klass), CUR_DIR_Y_PROP, properties[CUR_DIR_Y_PROP]); /** * VisuGlExtScale::current-orientation-z: * * Store the orientation[z] of the current arrow. * * Since: 3.8 */ properties[CUR_DIR_Z_PROP] = g_param_spec_float("current-orientation-z", "current arrow orientation", "orientation of the current arrow", -G_MAXFLOAT, G_MAXFLOAT, 0., G_PARAM_READWRITE); g_object_class_install_property(G_OBJECT_CLASS(klass), CUR_DIR_Z_PROP, properties[CUR_DIR_Z_PROP]); } static void visu_gl_ext_scale_init(VisuGlExtScale *obj) { DBG_fprintf(stderr, "Scale: creating a new scale (%p).\n", (gpointer)obj); obj->priv = visu_gl_ext_scale_get_instance_private(obj); obj->priv->dispose_has_run = FALSE; obj->priv->arrows = (GList*)0; obj->priv->iArr = 0; obj->priv->view = (VisuGlView*)0; obj->priv->view_signal = 0; obj->priv->width = _width; obj->priv->rgba[0] = _rgba[0]; obj->priv->rgba[1] = _rgba[1]; obj->priv->rgba[2] = _rgba[2]; obj->priv->rgba[3] = _rgba[3]; obj->priv->stipple = _stipple; g_signal_connect_object(VISU_CONFIG_FILE_RESOURCE, "parsed::" FLAG_RESOURCE_SCALE_USED, G_CALLBACK(onEntryUsed), (gpointer)obj, G_CONNECT_SWAPPED); g_signal_connect_object(VISU_CONFIG_FILE_RESOURCE, "parsed::" FLAG_RESOURCE_SCALE_COLOR, G_CALLBACK(onEntryColor), (gpointer)obj, G_CONNECT_SWAPPED); g_signal_connect_object(VISU_CONFIG_FILE_RESOURCE, "parsed::" FLAG_RESOURCE_SCALE_LINE, G_CALLBACK(onEntryWidth), (gpointer)obj, G_CONNECT_SWAPPED); g_signal_connect_object(VISU_CONFIG_FILE_RESOURCE, "parsed::" FLAG_RESOURCE_SCALE_STIPPLE, G_CALLBACK(onEntryStipple), (gpointer)obj, G_CONNECT_SWAPPED); if (!defaultScale) defaultScale = obj; } /* This method can be called several times. It should unref all of its reference to GObjects. */ static void scale_dispose(GObject* obj) { DBG_fprintf(stderr, "Scale: dispose object %p.\n", (gpointer)obj); if (VISU_GL_EXT_SCALE(obj)->priv->dispose_has_run) return; VISU_GL_EXT_SCALE(obj)->priv->dispose_has_run = TRUE; /* Chain up to the parent class */ G_OBJECT_CLASS(visu_gl_ext_scale_parent_class)->dispose(obj); } /* This method is called once only. */ static void scale_finalize(GObject* obj) { VisuGlExtScale *scale = VISU_GL_EXT_SCALE(obj); GList *lst; g_return_if_fail(obj); DBG_fprintf(stderr, "Scale: finalize object %p.\n", (gpointer)obj); /* Free my memory. */ for (lst = scale->priv->arrows; lst; lst = g_list_next(lst)) _freeArrow((Arrow*)lst->data); g_list_free(scale->priv->arrows); scale_setGlView(VISU_GL_EXT(scale), (VisuGlView*)0); /* Chain up to the parent class */ G_OBJECT_CLASS(visu_gl_ext_scale_parent_class)->finalize(obj); } static void scale_get_property(GObject* obj, guint property_id, GValue *value, GParamSpec *pspec) { const gchar *lbl; float *arr; VisuGlExtScale *self = VISU_GL_EXT_SCALE(obj); DBG_fprintf(stderr, "Extension Scale: get property '%s' -> ", g_param_spec_get_name(pspec)); switch (property_id) { case COLOR_PROP: g_value_take_boxed(value, tool_color_new(self->priv->rgba)); DBG_fprintf(stderr, "%gx%gx%g.\n", self->priv->rgba[0], self->priv->rgba[1], self->priv->rgba[2]); break; case WIDTH_PROP: g_value_set_float(value, self->priv->width); DBG_fprintf(stderr, "%g.\n", self->priv->width); break; case STIPPLE_PROP: g_value_set_uint(value, (guint)self->priv->stipple); DBG_fprintf(stderr, "%d.\n", (guint)self->priv->stipple); break; case N_ARR_PROP: g_value_set_uint(value, g_list_length(self->priv->arrows)); DBG_fprintf(stderr, "%d.\n", g_list_length(self->priv->arrows)); break; case CUR_PROP: g_value_set_uint(value, (guint)self->priv->iArr); DBG_fprintf(stderr, "%d.\n", (guint)self->priv->iArr); break; case CUR_LENGTH_PROP: g_value_set_float(value, visu_gl_ext_scale_getLength(self, self->priv->iArr)); DBG_fprintf(stderr, "%g.\n", g_value_get_float(value)); break; case CUR_LBL_PROP: lbl = visu_gl_ext_scale_getLegend(self, self->priv->iArr); if (lbl) g_value_set_string(value, lbl); else g_value_set_static_string(value, ""); DBG_fprintf(stderr, "%s.\n", g_value_get_string(value)); break; case CUR_ORIG_X_PROP: case CUR_ORIG_Y_PROP: case CUR_ORIG_Z_PROP: arr = visu_gl_ext_scale_getOrigin(self, self->priv->iArr); g_value_set_float(value, (arr) ? arr[property_id - CUR_ORIG_X_PROP] : 0.f); DBG_fprintf(stderr, "%g.\n", g_value_get_float(value)); break; case CUR_DIR_X_PROP: case CUR_DIR_Y_PROP: case CUR_DIR_Z_PROP: arr = visu_gl_ext_scale_getOrientation(self, self->priv->iArr); g_value_set_float(value, (arr) ? arr[property_id - CUR_DIR_X_PROP] : 0.f); DBG_fprintf(stderr, "%g.\n", g_value_get_float(value)); break; default: /* We don't have any other property... */ G_OBJECT_WARN_INVALID_PROPERTY_ID(obj, property_id, pspec); break; } } static void scale_set_property(GObject* obj, guint property_id, const GValue *value, GParamSpec *pspec) { ToolColor *color; float arr[3]; VisuGlExtScale *self = VISU_GL_EXT_SCALE(obj); gint mask[3] = {TOOL_XYZ_MASK_X, TOOL_XYZ_MASK_Y, TOOL_XYZ_MASK_Z }; DBG_fprintf(stderr, "Extension Scale: set property '%s' -> ", g_param_spec_get_name(pspec)); switch (property_id) { case COLOR_PROP: color = (ToolColor*)g_value_get_boxed(value); _setRGB((VisuGlExtLined*)self, color->rgba, TOOL_COLOR_MASK_RGBA); DBG_fprintf(stderr, "%gx%gx%g.\n", self->priv->rgba[0], self->priv->rgba[1], self->priv->rgba[2]); break; case WIDTH_PROP: _setLineWidth((VisuGlExtLined*)self, g_value_get_float(value)); DBG_fprintf(stderr, "%g.\n", self->priv->width); break; case STIPPLE_PROP: _setLineStipple((VisuGlExtLined*)self, (guint16)g_value_get_uint(value)); DBG_fprintf(stderr, "%d.\n", (guint)self->priv->stipple); break; case CUR_PROP: self->priv->iArr = g_value_get_uint(value); DBG_fprintf(stderr, "%d.\n", (guint)self->priv->iArr); break; case CUR_LENGTH_PROP: visu_gl_ext_scale_setLength(self, self->priv->iArr, g_value_get_float(value)); DBG_fprintf(stderr, "%g.\n", g_value_get_float(value)); break; case CUR_LBL_PROP: visu_gl_ext_scale_setLegend(self, self->priv->iArr, g_value_get_string(value)); DBG_fprintf(stderr, "%s.\n", g_value_get_string(value)); break; case CUR_ORIG_X_PROP: case CUR_ORIG_Y_PROP: case CUR_ORIG_Z_PROP: arr[property_id - CUR_ORIG_X_PROP] = g_value_get_float(value); visu_gl_ext_scale_setOrigin(self, self->priv->iArr, arr, mask[property_id - CUR_ORIG_X_PROP]); DBG_fprintf(stderr, "%g.\n", arr[property_id - CUR_ORIG_X_PROP]); break; case CUR_DIR_X_PROP: case CUR_DIR_Y_PROP: case CUR_DIR_Z_PROP: arr[property_id - CUR_DIR_X_PROP] = g_value_get_float(value); visu_gl_ext_scale_setOrientation(self, self->priv->iArr, arr, mask[property_id - CUR_DIR_X_PROP]); DBG_fprintf(stderr, "%g.\n", arr[property_id - CUR_DIR_X_PROP]); break; default: /* We don't have any other property... */ G_OBJECT_WARN_INVALID_PROPERTY_ID(obj, property_id, pspec); break; } } /** * visu_gl_ext_scale_new: * @name: (allow-none): a name for the #VisuGlExt. * * Create a new arrow set without any elements. Add arrows with visu_gl_ext_scale_add(). * * Returns: a newly created #VisuGlExtScale object. * * Since: 3.3 */ VisuGlExtScale* visu_gl_ext_scale_new(const gchar *name) { char *name_ = "Scale"; char *description = _("Draw scales in the rendering area."); VisuGlExt *scale; scale = VISU_GL_EXT(g_object_new(VISU_TYPE_GL_EXT_SCALE, "name", (name)?name:name_, "label", _(name), "description", description, "nGlObj", 1, "saveState", TRUE, NULL)); return VISU_GL_EXT_SCALE(scale); } static gboolean scale_setGlView(VisuGlExt *ext, VisuGlView *view) { VisuGlExtScalePrivate *priv = VISU_GL_EXT_SCALE(ext)->priv; if (view == priv->view) return FALSE; if (priv->view) { g_signal_handler_disconnect(G_OBJECT(priv->view), priv->view_signal); g_clear_object(&priv->view); } if (view) { priv->view = g_object_ref(view); priv->view_signal = g_signal_connect_swapped(G_OBJECT(view), "notify", G_CALLBACK(onScaleParametersChange), (gpointer)ext); } visu_gl_ext_setDirty(ext, TRUE); return TRUE; } /** * visu_gl_ext_scale_add: * @scale: the #VisuGlExtScale object to add to. * @origin: (array fixed-size=3): the origin ; * @orientation: (array fixed-size=3): the orientation in cartesian coordinates ; * @length: the length of the arrow ; * @legend: (allow-none): the text going with the arrow (can be NULL). * * Create a new arrow pointing somewhere in the box with a label. * If @legend is NULL, then the label will be the value of the length. * * Since: 3.7 * * Returns: the id of the newly added arrow. */ guint visu_gl_ext_scale_add(VisuGlExtScale *scale, float origin[3], float orientation[3], float length, const gchar *legend) { Arrow *arr; g_return_val_if_fail(length > 0.f && VISU_IS_GL_EXT_SCALE(scale), 0); arr = g_malloc(sizeof(Arrow)); arr->drawn = TRUE; arr->origin[0] = origin[0]; arr->origin[1] = origin[1]; arr->origin[2] = origin[2]; arr->direction[0] = orientation[0]; arr->direction[1] = orientation[1]; arr->direction[2] = orientation[2]; arr->length = length; if (legend && strcmp(legend, SCALE_AUTO_LEGEND)) arr->legendPattern = g_strdup(legend); else arr->legendPattern = (gchar*)0; arr->legend = g_string_new(""); if (arr->legendPattern) g_string_assign(arr->legend, arr->legendPattern); else g_string_printf(arr->legend, SCALE_LEGEND_DEFAULT, arr->length); scale->priv->arrows = g_list_append(scale->priv->arrows, arr); if (scale->priv->iArr == g_list_length(scale->priv->arrows) - 1) { g_object_notify_by_pspec(G_OBJECT(scale), properties[CUR_LENGTH_PROP]); g_object_notify_by_pspec(G_OBJECT(scale), properties[CUR_LBL_PROP]); g_object_notify_by_pspec(G_OBJECT(scale), properties[CUR_ORIG_X_PROP]); g_object_notify_by_pspec(G_OBJECT(scale), properties[CUR_ORIG_Y_PROP]); g_object_notify_by_pspec(G_OBJECT(scale), properties[CUR_ORIG_Z_PROP]); g_object_notify_by_pspec(G_OBJECT(scale), properties[CUR_DIR_X_PROP]); g_object_notify_by_pspec(G_OBJECT(scale), properties[CUR_DIR_Y_PROP]); g_object_notify_by_pspec(G_OBJECT(scale), properties[CUR_DIR_Z_PROP]); } g_object_notify_by_pspec(G_OBJECT(scale), properties[N_ARR_PROP]); return g_list_length(scale->priv->arrows) - 1; } static void _freeArrow(Arrow *arr) { if (arr->legendPattern) g_free(arr->legendPattern); g_string_free(arr->legend, TRUE); g_free(arr); } static gboolean _setRGB(VisuGlExtLined *scale, float rgba[4], int mask) { VisuGlExtScalePrivate *self; g_return_val_if_fail(VISU_IS_GL_EXT_SCALE(scale), FALSE); self = VISU_GL_EXT_SCALE(scale)->priv; if (mask & TOOL_COLOR_MASK_R) self->rgba[0] = rgba[0]; if (mask & TOOL_COLOR_MASK_G) self->rgba[1] = rgba[1]; if (mask & TOOL_COLOR_MASK_B) self->rgba[2] = rgba[2]; visu_gl_ext_setDirty(VISU_GL_EXT(scale), TRUE); return TRUE; } static gboolean _setLineWidth(VisuGlExtLined *scale, float width) { VisuGlExtScalePrivate *self; g_return_val_if_fail(VISU_IS_GL_EXT_SCALE(scale), FALSE); self = VISU_GL_EXT_SCALE(scale)->priv; self->width = width; visu_gl_ext_setDirty(VISU_GL_EXT(scale), TRUE); return TRUE; } static gboolean _setLineStipple(VisuGlExtLined *scale, guint16 stipple) { VisuGlExtScalePrivate *self; g_return_val_if_fail(VISU_IS_GL_EXT_SCALE(scale), FALSE); self = VISU_GL_EXT_SCALE(scale)->priv; self->stipple = stipple; visu_gl_ext_setDirty(VISU_GL_EXT(scale), TRUE); return TRUE; } /* Get methods. */ static float* _getRGB(const VisuGlExtLined *scale) { g_return_val_if_fail(VISU_IS_GL_EXT_SCALE(scale), (float*)0); return ((VisuGlExtScale*)scale)->priv->rgba; } static float _getLineWidth(const VisuGlExtLined *scale) { g_return_val_if_fail(VISU_IS_GL_EXT_SCALE(scale), 0.f); return ((VisuGlExtScale*)scale)->priv->width; } static guint16 _getLineStipple(const VisuGlExtLined *scale) { g_return_val_if_fail(VISU_IS_GL_EXT_SCALE(scale), 0); return ((VisuGlExtScale*)scale)->priv->stipple; } /** * visu_gl_ext_scale_getNArrows: * @scale: the #VisuGlExtScale to poll. * * A #VisuGlExtScale is characterised by a set of arrows. * * Since: 3.7 * * Returns: the number of stored arrows. */ guint visu_gl_ext_scale_getNArrows(VisuGlExtScale *scale) { g_return_val_if_fail(VISU_IS_GL_EXT_SCALE(scale), 0); return g_list_length(scale->priv->arrows); } static Arrow* _ensureOneArrow(VisuGlExtScale *scale, guint i) { GList *lst; float origin[3] = { 0.f, 0.f, 0.f }; float orientation[3] = { 1.f, 0.f, 0.f }; lst = g_list_nth(scale->priv->arrows, i); if (!lst && i == 0 && g_list_length(scale->priv->arrows) == 0) { visu_gl_ext_scale_add(scale, origin, orientation, 5.f, (const gchar*)0); lst = scale->priv->arrows; } g_return_val_if_fail(lst, (Arrow*)0); return (Arrow*)lst->data; } /** * visu_gl_ext_scale_getLength: * @scale: the #VisuGlExtScale to poll. * @i: the ith arrow. * * A #VisuGlExtScale is characterised by its length. * * Since: 3.3 * * Returns: a positive floating point value or a negative value if @i * is not in the arrow list. */ float visu_gl_ext_scale_getLength(VisuGlExtScale *scale, guint i) { GList *lst; g_return_val_if_fail(VISU_IS_GL_EXT_SCALE(scale), -1.f); lst = g_list_nth(scale->priv->arrows, i); return (lst) ? ((Arrow*)lst->data)->length : -1.f; } /** * visu_gl_ext_scale_getOrigin: * @scale: the #VisuGlExtScale to poll. * @i: the ith arrow. * * A #VisuGlExtScale is characterised by its origin in cartesian coordinates. * * Since: 3.3 * * Returns: (array fixed-size=3) (transfer none) (allow-none): three * floating point values. */ float* visu_gl_ext_scale_getOrigin(VisuGlExtScale *scale, guint i) { GList *lst; g_return_val_if_fail(VISU_IS_GL_EXT_SCALE(scale), (float*)0); lst = g_list_nth(scale->priv->arrows, i); if (lst) return ((Arrow*)lst->data)->origin; else return (float*)0; } /** * visu_gl_ext_scale_getOrientation: * @scale: the #VisuGlExtScale to poll. * @i: the ith arrow. * * A #VisuGlExtScale is characterised by its orientation in cartesian coordinates. * * Since: 3.3 * * Returns: (array fixed-size=3) (transfer none) (allow-none): three * floating point values. */ float* visu_gl_ext_scale_getOrientation(VisuGlExtScale *scale, guint i) { GList *lst; g_return_val_if_fail(VISU_IS_GL_EXT_SCALE(scale), (float*)0); lst = g_list_nth(scale->priv->arrows, i); if (lst) return ((Arrow*)lst->data)->direction; else return (float*)0; } /** * visu_gl_ext_scale_getLegend: * @scale: the #VisuGlExtScale to poll. * @i: the ith arrow. * * A #VisuGlExtScale can have a legend. This is not actualy the string printed * on screen but the one used to generate it. * * Since: 3.3 * * Returns: (allow-none): a string (private, do not free it). */ const gchar* visu_gl_ext_scale_getLegend(VisuGlExtScale *scale, guint i) { GList *lst; g_return_val_if_fail(VISU_IS_GL_EXT_SCALE(scale), (const gchar*)0); lst = g_list_nth(scale->priv->arrows, i); if (lst) return ((Arrow*)lst->data)->legendPattern; else return (const gchar*)0; } /** * visu_gl_ext_scale_setOrigin: * @scale: the #VisuGlExtScale to modify ; * @i: the ith arrow ; * @xyz: (array fixed-size=3): a vector in cartesian coordinates ; * @mask: relevant values in @xyz, see #TOOL_XYZ_MASK_X... * * Routine that changes the origin of the scale. * * Since: 3.3 * * Returns: TRUE if the origin was actually changed. */ gboolean visu_gl_ext_scale_setOrigin(VisuGlExtScale *scale, guint i, float xyz[3], int mask) { Arrow *arr; gboolean difference; g_return_val_if_fail(VISU_IS_GL_EXT_SCALE(scale), FALSE); arr = _ensureOneArrow(scale, i); if (!arr) return FALSE; difference = FALSE; g_object_freeze_notify(G_OBJECT(scale)); if (mask & TOOL_XYZ_MASK_X && arr->origin[0] != xyz[0]) { arr->origin[0] = xyz[0]; difference = TRUE; g_object_notify_by_pspec(G_OBJECT(scale), properties[CUR_ORIG_X_PROP]); } if (mask & TOOL_XYZ_MASK_Y && arr->origin[1] != xyz[1]) { arr->origin[1] = xyz[1]; difference = TRUE; g_object_notify_by_pspec(G_OBJECT(scale), properties[CUR_ORIG_Y_PROP]); } if (mask & TOOL_XYZ_MASK_Z && arr->origin[2] != xyz[2]) { arr->origin[2] = xyz[2]; difference = TRUE; g_object_notify_by_pspec(G_OBJECT(scale), properties[CUR_ORIG_Z_PROP]); } if (difference) visu_gl_ext_setDirty(VISU_GL_EXT(scale), TRUE); g_object_thaw_notify(G_OBJECT(scale)); return difference; } /** * visu_gl_ext_scale_setOrientation: * @scale: the #VisuGlExtScale to modify ; * @i: the ith arrow ; * @xyz: (array fixed-size=3): a vector in cartesian coordinates ; * @mask: relevant values in @xyz, see #TOOL_XYZ_MASK_X... * * Routine that changes the direction of the scale. * * Since: 3.3 * * Returns: TRUE if the orientation was actually changed. */ gboolean visu_gl_ext_scale_setOrientation(VisuGlExtScale *scale, guint i, float xyz[3], int mask) { Arrow *arr; gboolean difference; g_return_val_if_fail(VISU_IS_GL_EXT_SCALE(scale), FALSE); arr = _ensureOneArrow(scale, i); if (!arr) return FALSE; difference = FALSE; g_object_freeze_notify(G_OBJECT(scale)); if (mask & TOOL_XYZ_MASK_X && arr->direction[0] != xyz[0]) { arr->direction[0] = xyz[0]; difference = TRUE; g_object_notify_by_pspec(G_OBJECT(scale), properties[CUR_ORIG_X_PROP]); } if (mask & TOOL_XYZ_MASK_Y && arr->direction[1] != xyz[1]) { arr->direction[1] = xyz[1]; difference = TRUE; g_object_notify_by_pspec(G_OBJECT(scale), properties[CUR_ORIG_Y_PROP]); } if (mask & TOOL_XYZ_MASK_Z && arr->direction[2] != xyz[2]) { arr->direction[2] = xyz[2]; difference = TRUE; g_object_notify_by_pspec(G_OBJECT(scale), properties[CUR_ORIG_Z_PROP]); } if (difference) visu_gl_ext_setDirty(VISU_GL_EXT(scale), TRUE); g_object_thaw_notify(G_OBJECT(scale)); return difference; } static void _updateLbl(Arrow *arr) { g_return_if_fail(arr); if (arr->legendPattern) g_string_assign(arr->legend, arr->legendPattern); else g_string_printf(arr->legend, SCALE_LEGEND_DEFAULT, arr->length); } /** * visu_gl_ext_scale_setLength: * @scale: the #VisuGlExtScale to modify ; * @i: the ith arrow ; * @lg: a positive length. * * Routine that changes the length of the scale. If @i is zero and * @scale has currently no arrow, a default one is created. * * Since: 3.3 * * Returns: TRUE if the length was actually changed. */ gboolean visu_gl_ext_scale_setLength(VisuGlExtScale *scale, guint i, float lg) { Arrow *arr; g_return_val_if_fail(VISU_IS_GL_EXT_SCALE(scale), FALSE); arr = _ensureOneArrow(scale, i); if (!arr || lg == arr->length) return FALSE; arr->length = lg; _updateLbl(arr); visu_gl_ext_setDirty(VISU_GL_EXT(scale), TRUE); g_object_notify_by_pspec(G_OBJECT(scale), properties[CUR_LENGTH_PROP]); return TRUE; } /** * visu_gl_ext_scale_setLegend: * @scale: the #VisuGlExtScale to modify ; * @i: the ith arrow ; * @value: (allow-none): a string (can be NULL). * * Routine that changes the legend of the scale. If @value is NULL * then the length of the scale is printed. * * Since: 3.3 * * Returns: TRUE if the legend was actually changed. */ gboolean visu_gl_ext_scale_setLegend(VisuGlExtScale *scale, guint i, const gchar *value) { Arrow *arr; g_return_val_if_fail(VISU_IS_GL_EXT_SCALE(scale), FALSE); arr = _ensureOneArrow(scale, i); if (!arr) return FALSE; g_free(arr->legendPattern); if (value && *g_strstrip((gchar*)value)) arr->legendPattern = g_strdup(value); else arr->legendPattern = (gchar*)0; _updateLbl(arr); visu_gl_ext_setDirty(VISU_GL_EXT(scale), TRUE); g_object_notify_by_pspec(G_OBJECT(scale), properties[CUR_LBL_PROP]); return TRUE; } /****************/ /* Private part */ /****************/ static void scale_rebuild(VisuGlExt *ext) { visu_gl_text_rebuildFontList(); visu_gl_ext_setDirty(ext, TRUE); scale_draw(ext); } static void onScaleParametersChange(VisuGlExtScale *scale) { visu_gl_ext_setDirty(VISU_GL_EXT(scale), TRUE); } static void onEntryUsed(VisuGlExtScale *scale, VisuConfigFileEntry *entry _U_, VisuConfigFile *obj _U_) { visu_gl_ext_setActive(VISU_GL_EXT(scale), defaultUsed); } static void onEntryColor(VisuGlExtScale *scale, VisuConfigFileEntry *entry _U_, VisuConfigFile *obj _U_) { visu_gl_ext_lined_setRGBA(VISU_GL_EXT_LINED(scale), _rgba, TOOL_COLOR_MASK_RGBA); } static void onEntryWidth(VisuGlExtScale *scale, VisuConfigFileEntry *entry _U_, VisuConfigFile *obj _U_) { visu_gl_ext_lined_setWidth(VISU_GL_EXT_LINED(scale), _width); } static void onEntryStipple(VisuGlExtScale *scale, VisuConfigFileEntry *entry _U_, VisuConfigFile *obj _U_) { visu_gl_ext_lined_setStipple(VISU_GL_EXT_LINED(scale), _stipple); } /** * visu_gl_ext_scale_draw: * @scale: the #VisuGlExtScale object to draw. * * This method creates a compile list that draw all arrow of a scale. * * Since: 3.3 */ static void scale_draw(VisuGlExt *ext) { GList *tmpLst; int nlat; float radius = 0.3; VisuGlExtScale *scale; g_return_if_fail(VISU_IS_GL_EXT_SCALE(ext)); scale = VISU_GL_EXT_SCALE(ext); /* Nothing to draw; */ if(!scale->priv->view) return; DBG_fprintf(stderr, "Extension Scale: creating scales.\n"); visu_gl_text_initFontList(); nlat = visu_gl_view_getDetailLevel(scale->priv->view, radius); glDeleteLists(visu_gl_ext_getGlList(VISU_GL_EXT(scale)), 1); visu_gl_ext_startDrawing(ext); /* Deactivate light and fog. */ glDisable(GL_LIGHTING); glDisable(GL_FOG); glLineWidth(scale->priv->width); glColor4fv(scale->priv->rgba); if (scale->priv->stipple != 65535) { glEnable(GL_LINE_STIPPLE); glLineStipple(1, scale->priv->stipple); } for (tmpLst = scale->priv->arrows; tmpLst; tmpLst = g_list_next(tmpLst)) _drawArrow((Arrow*)tmpLst->data, nlat); if (scale->priv->stipple != 65535) glDisable(GL_LINE_STIPPLE); visu_gl_ext_completeDrawing(ext); } /* fonction qui dessine la legende*/ static void _drawArrow(Arrow *arr, guint nlat) { float x2,y2,z2, norm; float angles[3]; /*declaration des tableaux angles et coordonnées a 3 cellules*/ float coord[3], u, v, s; float radius = 0.3 * (0.25f * log(_width) + 1.f); float tl = 1.f; GLUquadricObj *obj; float modelView[16]; obj = gluNewQuadric(); norm = (arr->length - tl) / sqrt(arr->direction[0] * arr->direction[0] + arr->direction[1] * arr->direction[1] + arr->direction[2] * arr->direction[2]); x2 = arr->origin[0] + arr->direction[0] * norm; y2 = arr->origin[1] + arr->direction[1] * norm; z2 = arr->origin[2] + arr->direction[2] * norm; coord[0] = x2 - arr->origin[0]; coord[1] = y2 - arr->origin[1]; coord[2] = z2 - arr->origin[2]; tool_matrix_cartesianToSpherical(angles, coord); glPushMatrix(); glTranslated(arr->origin[0], arr->origin[1], arr->origin[2]); glRotated(angles[2], 0., 0., 1.); glRotated(angles[1], 0., 1., 0.); glTranslated(0., 0., angles[0]); gluCylinder(obj, radius, 0., tl, nlat, 1); glRotated(180., 1., 0., 0.); gluDisk(obj, 0, radius, nlat, 1); glPopMatrix(); glBegin (GL_LINES); glVertex3fv(arr->origin); glVertex3f(x2, y2, z2); glEnd(); glGetFloatv(GL_MODELVIEW_MATRIX, modelView); v = -(coord[0] * modelView[0] + coord[1] * modelView[4] + coord[2] * modelView[8]); u = +(coord[0] * modelView[1] + coord[1] * modelView[5] + coord[2] * modelView[9]); s = (v < 0.f)?0.25f:0.75f; if (v > 0.f) { u *= -1.f; v *= -1.f; } coord[0] = arr->origin[0] + s * arr->direction[0] * norm; coord[1] = arr->origin[1] + s * arr->direction[1] * norm; coord[2] = arr->origin[2] + s * arr->direction[2] * norm; norm = 1.f / sqrt(u * u + v * v) * radius * 2.f; coord[0] += (u * modelView[0] + v * modelView[1]) * norm; coord[1] += (u * modelView[4] + v * modelView[5]) * norm; coord[2] += (u * modelView[8] + v * modelView[9]) * norm; glRasterPos3fv(coord); visu_gl_text_drawChars(arr->legend->str, VISU_GL_TEXT_NORMAL); gluDeleteQuadric(obj); } /* Parameters & resources*/ /* Export function that is called by visu_module to write the values of resources to a file. */ static void exportResourcesScale(GString *data, VisuData *dataObj _U_) { GList *tmpLst; Arrow *arr; gchar *legend; if (!defaultScale) return; visu_config_file_exportComment(data, DESC_RESOURCE_SCALE_USED); visu_config_file_exportEntry(data, FLAG_RESOURCE_SCALE_USED, NULL, "%d", visu_gl_ext_getActive(VISU_GL_EXT(defaultScale))); visu_config_file_exportComment(data, DESC_RESOURCE_SCALE_COLOR); visu_config_file_exportEntry(data, FLAG_RESOURCE_SCALE_COLOR, NULL, "%4.3f %4.3f %4.3f %4.3f", defaultScale->priv->rgba[0], defaultScale->priv->rgba[1], defaultScale->priv->rgba[2], defaultScale->priv->rgba[3]); visu_config_file_exportComment(data, DESC_RESOURCE_SCALE_LINE); visu_config_file_exportEntry(data, FLAG_RESOURCE_SCALE_LINE, NULL, "%4.0f", defaultScale->priv->width); visu_config_file_exportComment(data, DESC_RESOURCE_SCALE_STIPPLE); visu_config_file_exportEntry(data, FLAG_RESOURCE_SCALE_STIPPLE, NULL, "%d", defaultScale->priv->stipple); visu_config_file_exportComment(data, DESC_RESOURCE_SCALE_DEFINITION); for (tmpLst = defaultScale->priv->arrows; tmpLst; tmpLst = g_list_next(tmpLst)) { arr = (Arrow*)tmpLst->data; if (arr->legendPattern) legend = arr->legendPattern; else legend = SCALE_AUTO_LEGEND; visu_config_file_exportEntry(data, FLAG_RESOURCE_SCALE_DEFINITION, NULL, "%g %g %g %g %g %g %g %s", arr->origin[0], arr->origin[1], arr->origin[2], arr->direction[0], arr->direction[1], arr->direction[2], arr->length, legend); } visu_config_file_exportComment(data, ""); } v_sim-3.8.0/src/extensions/scale.h000066400000000000000000000115741370110300500170630ustar00rootroot00000000000000/* EXTRAITS DE LA LICENCE Copyright CEA, contributeurs : Luc BILLARD et Damien CALISTE, laboratoire L_Sim, (2001-2005) Adresse mèl : BILLARD, non joignable par mèl ; CALISTE, damien P caliste AT cea P fr. Ce logiciel est un programme informatique servant à visualiser des structures atomiques dans un rendu pseudo-3D. Ce logiciel est régi par la licence CeCILL soumise au droit français et respectant les principes de diffusion des logiciels libres. Vous pouvez utiliser, modifier et/ou redistribuer ce programme sous les conditions de la licence CeCILL telle que diffusée par le CEA, le CNRS et l'INRIA sur le site "http://www.cecill.info". Le fait que vous puissiez accéder à cet en-tête signifie que vous avez pris connaissance de la licence CeCILL, et que vous en avez accepté les termes (cf. le fichier Documentation/licence.fr.txt fourni avec ce logiciel). */ /* LICENCE SUM UP Copyright CEA, contributors : Luc BILLARD et Damien CALISTE, laboratoire L_Sim, (2001-2005) E-mail address: BILLARD, not reachable any more ; CALISTE, damien P caliste AT cea P fr. This software is a computer program whose purpose is to visualize atomic configurations in 3D. This software is governed by the CeCILL license under French law and abiding by the rules of distribution of free software. You can use, modify and/ or redistribute the software under the terms of the CeCILL license as circulated by CEA, CNRS and INRIA at the following URL "http://www.cecill.info". The fact that you are presently reading this means that you have had knowledge of the CeCILL license and that you accept its terms. You can find a copy of this licence shipped with this software at Documentation/licence.en.txt. */ #ifndef SCALE_H #define SCALE_H #include "iface_lined.h" #include #include /** * VISU_TYPE_GL_EXT_SCALE: * * return the type of #VisuGlExtScale. * * Since: 3.3 */ #define VISU_TYPE_GL_EXT_SCALE (visu_gl_ext_scale_get_type ()) /** * VISU_GL_EXT_SCALE: * @obj: a #GObject to cast. * * Cast the given @obj into #VisuGlExtScale type. * * Since: 3.3 */ #define VISU_GL_EXT_SCALE(obj) (G_TYPE_CHECK_INSTANCE_CAST(obj, VISU_TYPE_GL_EXT_SCALE, VisuGlExtScale)) /** * VISU_GL_EXT_SCALE_CLASS: * @klass: a #GObjectClass to cast. * * Cast the given @klass into #VisuGlExtScaleClass. * * Since: 3.3 */ #define VISU_GL_EXT_SCALE_CLASS(klass) (G_TYPE_CHECK_CLASS_CAST(klass, VISU_TYPE_GL_EXT_SCALE, VisuGlExtScaleClass)) /** * VISU_IS_GL_EXT_SCALE: * @obj: a #GObject to test. * * Test if the given @ogj is of the type of #VisuGlExtScale object. * * Since: 3.3 */ #define VISU_IS_GL_EXT_SCALE(obj) (G_TYPE_CHECK_INSTANCE_TYPE(obj, VISU_TYPE_GL_EXT_SCALE)) /** * VISU_IS_GL_EXT_SCALE_CLASS: * @klass: a #GObjectClass to test. * * Test if the given @klass is of the type of #VisuGlExtScaleClass class. * * Since: 3.3 */ #define VISU_IS_GL_EXT_SCALE_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE(klass, VISU_TYPE_GL_EXT_SCALE)) /** * VISU_GL_EXT_SCALE_GET_CLASS: * @obj: a #GObject to get the class of. * * It returns the class of the given @obj. * * Since: 3.3 */ #define VISU_GL_EXT_SCALE_GET_CLASS(obj) (G_TYPE_INSTANCE_GET_CLASS(obj, VISU_TYPE_GL_EXT_SCALE, VisuGlExtScaleClass)) typedef struct _VisuGlExtScale VisuGlExtScale; typedef struct _VisuGlExtScalePrivate VisuGlExtScalePrivate; typedef struct _VisuGlExtScaleClass VisuGlExtScaleClass; /** * VisuGlExtScale: * * All fields are private, use the access routines. * * Since: 3.3 */ struct _VisuGlExtScale { VisuGlExt parent; VisuGlExtScalePrivate *priv; }; /** * VisuGlExtScaleClass: * @parent: parent structure. * * An opaque structure. * * Since: 3.3 */ struct _VisuGlExtScaleClass { VisuGlExtClass parent; }; /** * visu_gl_ext_scale_get_type: * * This method returns the type of #VisuGlExtScale, use %VISU_TYPE_GL_EXT_SCALE instead. * * Returns: the type of #VisuGlExtScale. * * Since: 3.3 */ GType visu_gl_ext_scale_get_type(void); VisuGlExtScale* visu_gl_ext_scale_new(const gchar *name); guint visu_gl_ext_scale_add(VisuGlExtScale *scale, float origin[3], float orientation[3], float length, const gchar *legend); gboolean visu_gl_ext_scale_setOrigin(VisuGlExtScale *scale, guint i, float xyz[3], int mask); gboolean visu_gl_ext_scale_setOrientation(VisuGlExtScale *scale, guint i, float xyz[3], int mask); gboolean visu_gl_ext_scale_setLength(VisuGlExtScale *scale, guint i, float lg); gboolean visu_gl_ext_scale_setLegend(VisuGlExtScale *scale, guint i, const gchar *value); guint visu_gl_ext_scale_getNArrows(VisuGlExtScale *scale); const gchar* visu_gl_ext_scale_getLegend(VisuGlExtScale *scale, guint i); float visu_gl_ext_scale_getLength(VisuGlExtScale *scale, guint i); float* visu_gl_ext_scale_getOrigin(VisuGlExtScale *scale, guint i); float* visu_gl_ext_scale_getOrientation(VisuGlExtScale *scale, guint i); #endif v_sim-3.8.0/src/extensions/shade.c000066400000000000000000000374121370110300500170520ustar00rootroot00000000000000/* EXTRAITS DE LA LICENCE Copyright CEA, contributeurs : Damien CALISTE, laboratoire L_Sim, (2001-2009) Adresse mèl : CALISTE, damien P caliste AT cea P fr. Ce logiciel est un programme informatique servant à visualiser des structures atomiques dans un rendu pseudo-3D. Ce logiciel est régi par la licence CeCILL soumise au droit français et respectant les principes de diffusion des logiciels libres. Vous pouvez utiliser, modifier et/ou redistribuer ce programme sous les conditions de la licence CeCILL telle que diffusée par le CEA, le CNRS et l'INRIA sur le site "http://www.cecill.info". Le fait que vous puissiez accéder à cet en-tête signifie que vous avez pris connaissance de la licence CeCILL, et que vous en avez accepté les termes (cf. le fichier Documentation/licence.fr.txt fourni avec ce logiciel). */ /* LICENCE SUM UP Copyright CEA, contributors : Damien CALISTE, laboratoire L_Sim, (2001-2009) E-mail address: CALISTE, damien P caliste AT cea P fr. This software is a computer program whose purpose is to visualize atomic configurations in 3D. This software is governed by the CeCILL license under French law and abiding by the rules of distribution of free software. You can use, modify and/ or redistribute the software under the terms of the CeCILL license as circulated by CEA, CNRS and INRIA at the following URL "http://www.cecill.info". The fact that you are presently reading this means that you have had knowledge of the CeCILL license and that you accept its terms. You can find a copy of this licence shipped with this software at COPYING. */ #include "shade.h" #include #include #include #include /** * SECTION:shade * @short_description: Draw a frame with the representation of a color shade. * * This extension draws a frame on top of the rendering area * with a color shade. One can setup printed values and draw * additional marks inside the shade. * * Since: 3.7 */ #define SHADE_LEGEND_N_QUADS 50 /** * VisuGlExtShadeClass: * @parent: the parent class; * * A short way to identify #_VisuGlExtShadeClass structure. * * Since: 3.7 */ /** * VisuGlExtShade: * * An opaque structure. * * Since: 3.7 */ /** * VisuGlExtShadePrivate: * * Private fields for #VisuGlExtShade objects. * * Since: 3.7 */ struct _VisuGlExtShadePrivate { /* Shade definition. */ ToolShade *shade; /* Parameters. */ float minMax[2]; ToolMatrixScalingFlag scaling; GArray *marks; }; enum { PROP_0, PROP_SHADE, PROP_MM, N_PROPS }; static GParamSpec *_properties[N_PROPS]; static void visu_gl_ext_shade_finalize(GObject* obj); static void visu_gl_ext_shade_get_property(GObject* obj, guint property_id, GValue *value, GParamSpec *pspec); static void visu_gl_ext_shade_set_property(GObject* obj, guint property_id, const GValue *value, GParamSpec *pspec); static gboolean visu_gl_ext_shade_isValid(const VisuGlExtFrame *frame); static void visu_gl_ext_shade_draw(const VisuGlExtFrame *frame); static void visu_gl_ext_shade_rebuild(VisuGlExt *ext); G_DEFINE_TYPE_WITH_CODE(VisuGlExtShade, visu_gl_ext_shade, VISU_TYPE_GL_EXT_FRAME, G_ADD_PRIVATE(VisuGlExtShade)) static void visu_gl_ext_shade_class_init(VisuGlExtShadeClass *klass) { DBG_fprintf(stderr, "Extension Shade: creating the class of the object.\n"); /* DBG_fprintf(stderr, " - adding new signals ;\n"); */ /* DBG_fprintf(stderr, " - adding new resources ;\n"); */ /* Connect the overloading methods. */ G_OBJECT_CLASS(klass)->finalize = visu_gl_ext_shade_finalize; G_OBJECT_CLASS(klass)->set_property = visu_gl_ext_shade_set_property; G_OBJECT_CLASS(klass)->get_property = visu_gl_ext_shade_get_property; VISU_GL_EXT_CLASS(klass)->rebuild = visu_gl_ext_shade_rebuild; VISU_GL_EXT_FRAME_CLASS(klass)->isValid = visu_gl_ext_shade_isValid; VISU_GL_EXT_FRAME_CLASS(klass)->draw = visu_gl_ext_shade_draw; /** * VisuGlExtShade::shade: * * The colour shade. * * Since: 3.8 */ _properties[PROP_SHADE] = g_param_spec_boxed("shade", "Shade", "colorization scheme", TOOL_TYPE_SHADE, G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS); /** * VisuGlExtShade::range-min-max: * * Min / max range as used to normalise data. * * Since: 3.8 */ _properties[PROP_MM] = g_param_spec_boxed("range-min-max", "Range min/max", "min / max range to normalise data", G_TYPE_ARRAY, G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS); g_object_class_install_properties(G_OBJECT_CLASS(klass), N_PROPS, _properties); } static void visu_gl_ext_shade_init(VisuGlExtShade *obj) { DBG_fprintf(stderr, "Extension Shade: initializing a new object (%p).\n", (gpointer)obj); obj->priv = visu_gl_ext_shade_get_instance_private(obj); /* Private data. */ obj->priv->marks = g_array_new(FALSE, FALSE, sizeof(float)); obj->priv->scaling = TOOL_MATRIX_SCALING_LINEAR; obj->priv->minMax[0] = G_MAXFLOAT; obj->priv->minMax[1] = -G_MAXFLOAT; obj->priv->shade = (ToolShade*)0; } static void visu_gl_ext_shade_get_property(GObject* obj, guint property_id, GValue *value, GParamSpec *pspec) { VisuGlExtShade *self = VISU_GL_EXT_SHADE(obj); GArray *arr; DBG_fprintf(stderr, "Extension Shade: get property '%s' -> ", g_param_spec_get_name(pspec)); switch (property_id) { case PROP_SHADE: g_value_set_boxed(value, self->priv->shade); DBG_fprintf(stderr, "%p.\n", (gpointer)self->priv->shade); break; case PROP_MM: DBG_fprintf(stderr, "%g / %g.\n", self->priv->minMax[0], self->priv->minMax[1]); arr = g_array_sized_new(FALSE, FALSE, sizeof(float), 2); g_array_index(arr, float, 0) = self->priv->minMax[0]; g_array_index(arr, float, 1) = self->priv->minMax[1]; g_value_take_boxed(value, arr); break; default: /* We don't have any other property... */ G_OBJECT_WARN_INVALID_PROPERTY_ID(obj, property_id, pspec); break; } } static void visu_gl_ext_shade_set_property(GObject* obj, guint property_id, const GValue *value, GParamSpec *pspec) { VisuGlExtShade *self = VISU_GL_EXT_SHADE(obj); GArray *arr; DBG_fprintf(stderr, "Visu Data Colorizer Fragment: set property '%s' -> ", g_param_spec_get_name(pspec)); switch (property_id) { case PROP_SHADE: DBG_fprintf(stderr, "%p.\n", g_value_get_boxed(value)); visu_gl_ext_shade_setShade(self, (ToolShade*)g_value_get_boxed(value)); break; case PROP_MM: DBG_fprintf(stderr, "%p.\n", g_value_get_boxed(value)); arr = (GArray*)g_value_get_boxed(value); visu_gl_ext_shade_setMinMax(self, g_array_index(arr, float, 0), g_array_index(arr, float, 1)); break; default: /* We don't have any other property... */ G_OBJECT_WARN_INVALID_PROPERTY_ID(obj, property_id, pspec); break; } } static void visu_gl_ext_shade_finalize(GObject* obj) { VisuGlExtShade *shade; g_return_if_fail(obj); DBG_fprintf(stderr, "Extension Shade: finalize object %p.\n", (gpointer)obj); shade = VISU_GL_EXT_SHADE(obj); /* Free privs elements. */ DBG_fprintf(stderr, "Extension Shade: free private shade.\n"); tool_shade_free(shade->priv->shade); g_array_unref(shade->priv->marks); /* Chain up to the parent class */ DBG_fprintf(stderr, "Extension Shade: chain to parent.\n"); G_OBJECT_CLASS(visu_gl_ext_shade_parent_class)->finalize(obj); DBG_fprintf(stderr, "Extension Shade: freeing ... OK.\n"); } /** * visu_gl_ext_shade_new: * @name: (allow-none): the name to give to the extension (default is #VISU_GL_EXT_SHADE_ID). * * Creates a new #VisuGlExt to draw a shade. * * Since: 3.7 * * Returns: a pointer to the #VisuGlExt it created or * NULL otherwise. */ VisuGlExtShade* visu_gl_ext_shade_new(const gchar *name) { char *name_ = VISU_GL_EXT_SHADE_ID; char *description = _("Draw the legend of a color shade."); VisuGlExt *shade; #define SHADE_LEGEND_WIDTH 20.f #define SHADE_LEGEND_HEIGHT 175.f DBG_fprintf(stderr,"Extension Shade: new object.\n"); shade = g_object_new(VISU_TYPE_GL_EXT_SHADE, "name", (name)?name:name_, "label", _(name), "description", description, "saveState", TRUE, "nGlObj", 1, "priority", VISU_GL_EXT_PRIORITY_LAST, NULL); visu_gl_ext_frame_setPosition(VISU_GL_EXT_FRAME(shade), 0.f, 0.f); visu_gl_ext_frame_setRequisition(VISU_GL_EXT_FRAME(shade), SHADE_LEGEND_WIDTH + 5 + 12 * 7, SHADE_LEGEND_HEIGHT); return VISU_GL_EXT_SHADE(shade); } /** * visu_gl_ext_shade_setShade: * @ext: The #VisuGlExtShade to attached to. * @shade: the shade to get the color of. * * Attach an #VisuGlView to render to and setup the shade. * * Since: 3.7 * * Returns: TRUE if internal shade is changed. **/ gboolean visu_gl_ext_shade_setShade(VisuGlExtShade *ext, const ToolShade *shade) { g_return_val_if_fail(VISU_IS_GL_EXT_SHADE(ext), FALSE); if (tool_shade_compare(ext->priv->shade, shade)) return FALSE; tool_shade_free(ext->priv->shade); ext->priv->shade = tool_shade_copy(shade); g_object_notify_by_pspec(G_OBJECT(ext), _properties[PROP_SHADE]); visu_gl_ext_setDirty(VISU_GL_EXT(ext), TRUE); return TRUE; } /** * visu_gl_ext_shade_setMinMax: * @shade: the #VisuGlExtShade to update. * @minV: a value. * @maxV: another value. * * Change the minimum and maximum values used on the legend. * * Since: 3.7 * * Returns: TRUE if value is actually changed. **/ gboolean visu_gl_ext_shade_setMinMax(VisuGlExtShade *shade, float minV, float maxV) { g_return_val_if_fail(VISU_IS_GL_EXT_SHADE(shade), FALSE); g_return_val_if_fail(minV <= maxV, FALSE); if (shade->priv->minMax[0] == minV && shade->priv->minMax[1] == maxV) return FALSE; shade->priv->minMax[0] = minV; shade->priv->minMax[1] = maxV; g_object_notify_by_pspec(G_OBJECT(shade), _properties[PROP_MM]); visu_gl_ext_setDirty(VISU_GL_EXT(shade), TRUE); return TRUE; } /** * visu_gl_ext_shade_setScaling: * @shade: the #VisuGlExtShade to update. * @scaling: a #ToolMatrixScalingFlag value. * * Change the scaling variation of the shade between the minimum and * the maximum values, see visu_gl_ext_shade_setMinMax(). * * Since: 3.7 * * Returns: TRUE if value is actually changed. **/ gboolean visu_gl_ext_shade_setScaling(VisuGlExtShade *shade, ToolMatrixScalingFlag scaling) { g_return_val_if_fail(VISU_IS_GL_EXT_SHADE(shade), FALSE); if (shade->priv->scaling == scaling) return FALSE; shade->priv->scaling = scaling; visu_gl_ext_setDirty(VISU_GL_EXT(shade), TRUE); return TRUE; } /** * visu_gl_ext_shade_setMarks: * @shade: the #VisuGlExtShade to update. * @marks: (array length=n): a list of float values in [0;1]. * @n: the length of @marks. * * The legend can draw additional marks in the shade. Setup these * marks with this routine. The first and the last marks of the list will be * rendered bigger than the next ones. * * Since: 3.7 * * Returns: TRUE if value is actually changed. **/ gboolean visu_gl_ext_shade_setMarks(VisuGlExtShade *shade, float *marks, guint n) { g_return_val_if_fail(VISU_IS_GL_EXT_SHADE(shade), FALSE); g_array_set_size(shade->priv->marks, n); memcpy(shade->priv->marks->data, marks, sizeof(float) * n); visu_gl_ext_setDirty(VISU_GL_EXT(shade), TRUE); return TRUE; } static void visu_gl_ext_shade_rebuild(VisuGlExt *ext) { visu_gl_text_rebuildFontList(); if (VISU_GL_EXT_GET_CLASS(ext)->draw) VISU_GL_EXT_GET_CLASS(ext)->draw(ext); } static gboolean visu_gl_ext_shade_isValid(const VisuGlExtFrame *frame) { VisuGlExtShade *shade; g_return_val_if_fail(VISU_IS_GL_EXT_SHADE(frame), FALSE); shade = VISU_GL_EXT_SHADE(frame); return (shade->priv->shade && shade->priv->minMax[0] < shade->priv->minMax[1]); } static void visu_gl_ext_shade_draw(const VisuGlExtFrame *frame) { guint i; float yStep, xbuf, scale, sW; float rgba[4]; char value[16]; tool_matrix_getScaledValue get_inv; VisuGlExtShade *shade; g_return_if_fail(VISU_IS_GL_EXT_SHADE(frame)); shade = VISU_GL_EXT_SHADE(frame); scale = visu_gl_ext_frame_getScale(frame); sW = SHADE_LEGEND_WIDTH * scale; /* We draw the colored bar. */ tool_shade_valueToRGB(shade->priv->shade, rgba, 0.); glColor4fv(rgba); yStep = (float)frame->height / (float)SHADE_LEGEND_N_QUADS; glBegin(GL_QUAD_STRIP); for (i = 0; i <= SHADE_LEGEND_N_QUADS; i++) { glVertex2f(0, (float)i * yStep); glVertex2f(sW, (float)i * yStep); tool_shade_valueToRGB(shade->priv->shade, rgba, (float)i / (float)SHADE_LEGEND_N_QUADS); glColor4fv(rgba); } glEnd(); switch (shade->priv->scaling) { case TOOL_MATRIX_SCALING_LINEAR: get_inv = tool_matrix_getScaledLinearInv; break; case TOOL_MATRIX_SCALING_LOG: get_inv = tool_matrix_getScaledLogInv; break; case TOOL_MATRIX_SCALING_ZERO_CENTRED_LOG: get_inv = tool_matrix_getScaledZeroCentredLogInv; break; default: get_inv = (tool_matrix_getScaledValue)0; break; } g_return_if_fail(get_inv); glDisable(GL_LINE_SMOOTH); /* We draw some marks. */ if (shade->priv->marks) { DBG_fprintf(stderr, "Extension Shade: put %d marks.\n", shade->priv->marks->len); xbuf = 0.f; for (i = 0; i < shade->priv->marks->len; i++) { if (i == 0 || i == shade->priv->marks->len - 1) { glLineWidth(2 * scale); xbuf = 3.f; } else if (i == 1) { glLineWidth(scale); xbuf = 8.f; } yStep = CLAMP(g_array_index(shade->priv->marks, float, i), 0., 1.); tool_shade_valueToRGB(shade->priv->shade, rgba, yStep); rgba[0] = 1. - rgba[0]; rgba[1] = 1. - rgba[1]; rgba[2] = 1. - rgba[2]; glColor4fv(rgba); yStep *= (float)frame->height; yStep = CLAMP(yStep, 2.f * scale, frame->height - scale); glBegin(GL_LINES); glVertex2f(xbuf, yStep); glVertex2f(sW - xbuf, yStep); DBG_fprintf(stderr, " - %g.\n", yStep); glEnd(); } } glColor3fv(frame->fontRGB); glLineWidth(scale); /* We draw the frame around. */ DBG_fprintf(stderr, "Extension Shade: frame actual size is %dx%d.\n", frame->width, frame->height); glBegin(GL_LINE_STRIP); glVertex2i(1, 1); glVertex2i(sW, 1); glVertex2i(sW, frame->height); glVertex2i(1, frame->height); glVertex2i(1, 1); glEnd(); /* We draw the tics. */ glBegin(GL_LINES); glVertex2i(sW , 1); glVertex2i(sW + 3, 1); glVertex2i(sW , frame->height / 3); glVertex2i(sW + 3, frame->height / 3); glVertex2i(sW , 2 * frame->height / 3); glVertex2i(sW + 3, 2 * frame->height / 3); glVertex2i(sW , frame->height); glVertex2i(sW + 3, frame->height); glEnd(); /* We print the labels. */ sprintf(value, "%.3g", get_inv(0.f, shade->priv->minMax)); glRasterPos2i(sW + 5, 0); visu_gl_text_drawChars(value, VISU_GL_TEXT_NORMAL); sprintf(value, "%.3g", get_inv(0.33333f, shade->priv->minMax)); glRasterPos2i(sW + 5, frame->height / 3 - 5); visu_gl_text_drawChars(value, VISU_GL_TEXT_NORMAL); sprintf(value, "%.3g", get_inv(0.66667f, shade->priv->minMax)); glRasterPos2i(sW + 5, 2 * frame->height / 3 - 5); visu_gl_text_drawChars(value, VISU_GL_TEXT_NORMAL); sprintf(value, "%.3g", get_inv(1.f, shade->priv->minMax)); glRasterPos2i(sW + 5, frame->height - 10); visu_gl_text_drawChars(value, VISU_GL_TEXT_NORMAL); } v_sim-3.8.0/src/extensions/shade.h000066400000000000000000000104031370110300500170460ustar00rootroot00000000000000/* EXTRAITS DE LA LICENCE Copyright CEA, contributeurs : Damien CALISTE, laboratoire L_Sim, (2001-2009) Adresse mèl : CALISTE, damien P caliste AT cea P fr. Ce logiciel est un programme informatique servant à visualiser des structures atomiques dans un rendu pseudo-3D. Ce logiciel est régi par la licence CeCILL soumise au droit français et respectant les principes de diffusion des logiciels libres. Vous pouvez utiliser, modifier et/ou redistribuer ce programme sous les conditions de la licence CeCILL telle que diffusée par le CEA, le CNRS et l'INRIA sur le site "http://www.cecill.info". Le fait que vous puissiez accéder à cet en-tête signifie que vous avez pris connaissance de la licence CeCILL, et que vous en avez accepté les termes (cf. le fichier Documentation/licence.fr.txt fourni avec ce logiciel). */ /* LICENCE SUM UP Copyright CEA, contributors : Damien CALISTE, laboratoire L_Sim, (2001-2009) E-mail address: CALISTE, damien P caliste AT cea P fr. This software is a computer program whose purpose is to visualize atomic configurations in 3D. This software is governed by the CeCILL license under French law and abiding by the rules of distribution of free software. You can use, modify and/ or redistribute the software under the terms of the CeCILL license as circulated by CEA, CNRS and INRIA at the following URL "http://www.cecill.info". The fact that you are presently reading this means that you have had knowledge of the CeCILL license and that you accept its terms. You can find a copy of this licence shipped with this software at COPYING. */ #ifndef SHADE_H #define SHADE_H #include "frame.h" #include #include #include /** * VISU_TYPE_GL_EXT_SHADE: * * return the type of #VisuGlExtShade. * * Since: 3.7 */ #define VISU_TYPE_GL_EXT_SHADE (visu_gl_ext_shade_get_type ()) /** * VISU_GL_EXT_SHADE: * @obj: a #GObject to cast. * * Cast the given @obj into #VisuGlExtShade type. * * Since: 3.7 */ #define VISU_GL_EXT_SHADE(obj) (G_TYPE_CHECK_INSTANCE_CAST(obj, VISU_TYPE_GL_EXT_SHADE, VisuGlExtShade)) /** * VISU_GL_EXT_SHADE_CLASS: * @klass: a #GObjectClass to cast. * * Cast the given @klass into #VisuGlExtShadeClass. * * Since: 3.7 */ #define VISU_GL_EXT_SHADE_CLASS(klass) (G_TYPE_CHECK_CLASS_CAST(klass, VISU_TYPE_GL_EXT_SHADE, VisuGlExtShadeClass)) /** * VISU_IS_GL_EXT_SHADE: * @obj: a #GObject to test. * * Test if the given @ogj is of the type of #VisuGlExtShade object. * * Since: 3.7 */ #define VISU_IS_GL_EXT_SHADE(obj) (G_TYPE_CHECK_INSTANCE_TYPE(obj, VISU_TYPE_GL_EXT_SHADE)) /** * VISU_IS_GL_EXT_SHADE_CLASS: * @klass: a #GObjectClass to test. * * Test if the given @klass is of the type of #VisuGlExtShadeClass class. * * Since: 3.7 */ #define VISU_IS_GL_EXT_SHADE_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE(klass, VISU_TYPE_GL_EXT_SHADE)) /** * VISU_GL_EXT_SHADE_GET_CLASS: * @obj: a #GObject to get the class of. * * It returns the class of the given @obj. * * Since: 3.7 */ #define VISU_GL_EXT_SHADE_GET_CLASS(obj) (G_TYPE_INSTANCE_GET_CLASS(obj, VISU_TYPE_GL_EXT_SHADE, VisuGlExtShadeClass)) typedef struct _VisuGlExtShade VisuGlExtShade; typedef struct _VisuGlExtShadePrivate VisuGlExtShadePrivate; typedef struct _VisuGlExtShadeClass VisuGlExtShadeClass; struct _VisuGlExtShade { VisuGlExtFrame parent; VisuGlExtShadePrivate *priv; }; struct _VisuGlExtShadeClass { VisuGlExtFrameClass parent; }; /** * visu_gl_ext_shade_get_type: * * This method returns the type of #VisuGlExtShade, use * VISU_TYPE_GL_EXT_SHADE instead. * * Since: 3.7 * * Returns: the type of #VisuGlExtShade. */ GType visu_gl_ext_shade_get_type(void); /** * VISU_GL_EXT_SHADE_ID: * * The id used to identify this extension, see * visu_gl_ext_rebuild() for instance. */ #define VISU_GL_EXT_SHADE_ID "Shade" VisuGlExtShade* visu_gl_ext_shade_new(const gchar *name); gboolean visu_gl_ext_shade_setShade(VisuGlExtShade *ext, const ToolShade *shade); gboolean visu_gl_ext_shade_setMinMax(VisuGlExtShade *shade, float minV, float maxV); gboolean visu_gl_ext_shade_setScaling(VisuGlExtShade *shade, ToolMatrixScalingFlag scaling); gboolean visu_gl_ext_shade_setMarks(VisuGlExtShade *shade, float *marks, guint n); #endif v_sim-3.8.0/src/extensions/surfs.c000066400000000000000000001065371370110300500171350ustar00rootroot00000000000000/* EXTRAITS DE LA LICENCE Copyright CEA, contributeurs : Damien CALISTE, laboratoire L_Sim, (2001-2013) Adresse mèl : CALISTE, damien P caliste AT cea P fr. Ce logiciel est un programme informatique servant à visualiser des structures atomiques dans un rendu pseudo-3D. Ce logiciel est régi par la licence CeCILL soumise au droit français et respectant les principes de diffusion des logiciels libres. Vous pouvez utiliser, modifier et/ou redistribuer ce programme sous les conditions de la licence CeCILL telle que diffusée par le CEA, le CNRS et l'INRIA sur le site "http://www.cecill.info". Le fait que vous puissiez accéder à cet en-tête signifie que vous avez pris connaissance de la licence CeCILL, et que vous en avez accepté les termes (cf. le fichier Documentation/licence.fr.txt fourni avec ce logiciel). */ /* LICENCE SUM UP Copyright CEA, contributors : Damien CALISTE, laboratoire L_Sim, (2001-2013) E-mail address: CALISTE, damien P caliste AT cea P fr. This software is a computer program whose purpose is to visualize atomic configurations in 3D. This software is governed by the CeCILL license under French law and abiding by the rules of distribution of free software. You can use, modify and/ or redistribute the software under the terms of the CeCILL license as circulated by CEA, CNRS and INRIA at the following URL "http://www.cecill.info". The fact that you are presently reading this means that you have had knowledge of the CeCILL license and that you accept its terms. You can find a copy of this licence shipped with this software at COPYING. */ #include "surfs.h" #include #include #include #include "opengl.h" #include #include /** * SECTION:surfs * @short_description: Defines methods to draw surfaces. * * #VisuSurface object can be drawn with this class. Simply * create a new #VisuGlExtSurfaces object and add surfaces with * visu_gl_ext_surfaces_add(). It is better to add several surfaces to * a single #VisuGlExtSurfaces object since all vertices are reordered * when necessary to ensure proper transparency. */ #define DESC_RESOURCE_INTRA "Choose if the interior is drawn in color inverse ;"\ " a boolean (0 or 1)" #define FLAG_RESOURCE_INTRA "isosurfaces_drawIntra" static gboolean INTRA_DEFAULT = FALSE; typedef struct _SurfaceHandleStruct { VisuGlExtSurfaces *ext; VisuSurface *surface; gulong masked_signal, resource_signal, box_signal; VisuSurfaceResource *res; gulong notify_signal; } _SurfaceHandle; typedef struct _VisuSurfaceOrder VisuSurfaceOrder; /** * VisuSurfaceOrder: * * Short name to adress #_VisuSurfaceOrder objects. */ struct _VisuSurfaceOrder { /* Any_pointer[i][0:1] gives the id for surfaces and id for poly i in the z sorted from back to front. */ GArray *any_pointer; /* Give for all poly the id for surfaces object and the id for poly in this object. any_pointer elements point to that array. */ GArray *polygon_number; }; struct _orderInfo { VisuSurfaceIterPoly iter; double z; }; /* static gint _cmpZ(gconstpointer a, gconstpointer b) */ /* { */ /* struct _orderInfo *alpha = (struct _orderInfo*)a; */ /* struct _orderInfo *beta = (struct _orderInfo*)b; */ /* if (alpha->z > beta->z) */ /* return +1; */ /* else if (alpha->z < beta->z) */ /* return -1; */ /* else */ /* return 0; */ /* } */ static void sort_by_z(struct _orderInfo *pointer[], int begin, int end) { int i; int middle; struct _orderInfo *temp; if( begin >= end ) return; temp = pointer[begin]; pointer[begin] = pointer[(end+begin)/2]; pointer[(end+begin)/2] = temp; middle = begin; for(i = begin +1; i <= end; i++) { if ( pointer[i]->z < pointer[begin]->z ) { temp = pointer[i]; pointer[i] = pointer[++middle]; pointer[middle] = temp; } } temp = pointer[begin]; pointer[begin] = pointer[middle]; pointer[middle] = temp; sort_by_z(pointer, begin, middle-1); sort_by_z(pointer, middle+1, end); } /** * visu_surface_order_new: * * Create an object to hold the order in which the surfaces must be * drawn. See visu_surface_order_polygons() to set this object. * * Returns: a newly created #VisuSurfaceOrder object without any values. */ VisuSurfaceOrder* visu_surface_order_new(void) { VisuSurfaceOrder *order; order = g_malloc(sizeof(VisuSurfaceOrder)); order->any_pointer = g_array_new(FALSE, FALSE, sizeof(struct _orderInfo*)); order->polygon_number = g_array_new(FALSE, FALSE, sizeof(struct _orderInfo)); return order; } /** * visu_surface_order_free: * @order: the object to be freed. * * Free memory used by a #VisuSurfaceOrder object. */ void visu_surface_order_free(VisuSurfaceOrder *order) { g_return_if_fail(order); if (order->any_pointer) g_array_unref(order->any_pointer); if (order->polygon_number) g_array_unref(order->polygon_number); g_free(order); } /** * visu_surface_order_polygons: * @order: the description of the polygons order ; * @surfs: an array of #VisuSurface object, must be NULL terminated. * * Re-orders the polygons in back to front order. * This function should be called everytime a redraw is needed. */ void visu_surface_order_polygons(VisuSurfaceOrder *order, GList *surfs) { float mat[16]; double z; VisuSurfaceIterPoly iter; struct _orderInfo data, *pdata; GList *surf; guint i; g_return_if_fail(order); DBG_fprintf(stderr, "Extension Surfaces: re-ordering polygons in back to front order.\n"); glGetFloatv(GL_MODELVIEW_MATRIX, mat); /* For all polygons, we compute the z position of the isobarycentre. */ g_array_set_size(order->polygon_number, 0); for (surf = surfs; surf; surf = g_list_next(surf)) for (visu_surface_iter_poly_new(((_SurfaceHandle*)surf->data)->surface, &iter); iter.valid; visu_surface_iter_poly_next(&iter)) if (visu_surface_iter_poly_getZ(&iter, &z, mat)) { data.iter = iter; data.z = z; g_array_append_val(order->polygon_number, data); } g_array_set_size(order->any_pointer, 0); for (i = 0; i < order->polygon_number->len; i++) { pdata = &g_array_index(order->polygon_number, struct _orderInfo, i); g_array_append_val(order->any_pointer, pdata); } DBG_fprintf(stderr, "Extension Surfaces: sorting..."); /* g_array_sort(order->any_pointer, _cmpZ); */ sort_by_z(&g_array_index(order->any_pointer, struct _orderInfo*, 0), 0, order->polygon_number->len - 1); DBG_fprintf(stderr, "OK\n"); } /** * VisuGlExtSurfacesClass: * @parent: the parent class; * * A short way to identify #_VisuGlExtSurfacesClass structure. * * Since: 3.7 */ /** * VisuGlExtSurfaces: * * An opaque structure. * * Since: 3.7 */ /** * VisuGlExtSurfacesPrivate: * * Private fields for #VisuGlExtSurfaces objects. * * Since: 3.7 */ struct _VisuGlExtSurfacesPrivate { gboolean dispose_has_run; /* Polygon ordering for alpha drawing. */ VisuSurfaceOrder *order; gboolean reorderingNeeded; /* Rendering characteristics. */ gboolean drawIntra; /* Signals for the attached objects. */ GList *surfs; VisuGlView *view; gulong theta_signal, phi_signal, omega_signal; VisuInteractive *inter; gulong observe_signal; VisuPlaneSet *mask; VisuBox *box; gulong size_signal; }; enum { ADD_SIGNAL, REMOVE_SIGNAL, NB_SIGNAL }; static guint _signals[NB_SIGNAL] = { 0 }; enum { PROP_0, DRAW_INTRA_PROP, BOX_PROP, N_PROP }; static GParamSpec *_properties[N_PROP]; static VisuGlExtSurfaces* defaultSurfaces; static void visu_gl_ext_surfaces_finalize(GObject* obj); static void visu_gl_ext_surfaces_dispose(GObject* obj); static void visu_gl_ext_surfaces_get_property(GObject* obj, guint property_id, GValue *value, GParamSpec *pspec); static void visu_gl_ext_surfaces_set_property(GObject* obj, guint property_id, const GValue *value, GParamSpec *pspec); static void visu_gl_ext_surfaces_rebuild(VisuGlExt *ext); static void visu_gl_ext_surfaces_draw(VisuGlExt *surfs); static gboolean _setGlView(VisuGlExt *ext, VisuGlView *view); /* Callbacks. */ static void _markDirty(VisuGlExt *data); static void _markDirtyAndReorder(VisuGlExtSurfaces *data); static void onSurfaceResource(VisuSurface *surfaces, GParamSpec *param, _SurfaceHandle *data); static void onResourceNotify(VisuSurfaceResource *res, GParamSpec *param, VisuGlExtSurfaces *data); static void onCameraChange(VisuGlExtSurfaces *data); static void onObserve(VisuInteractive *inter, gboolean start, VisuGlExtSurfaces *data); static void onEntryIntra(VisuGlExtSurfaces *surfs, VisuConfigFileEntry *entry, VisuConfigFile *obj); /* Local methods. */ static void isosurfaces_export_resources(GString *data, VisuData *dataObj); /* Local routines. */ static void _freeSurfaceHandle(gpointer obj) { _SurfaceHandle *shd; shd = (_SurfaceHandle*)obj; g_signal_handler_disconnect(G_OBJECT(shd->surface), shd->resource_signal); g_signal_handler_disconnect(G_OBJECT(shd->surface), shd->masked_signal); g_signal_handler_disconnect(G_OBJECT(shd->surface), shd->box_signal); g_object_unref(shd->surface); g_signal_handler_disconnect(G_OBJECT(shd->res), shd->notify_signal); g_object_unref(shd->res); #if GLIB_MINOR_VERSION > 9 g_slice_free1(sizeof(_SurfaceHandle), obj); #else g_free(obj); #endif } static gpointer _newSurfaceHandle(VisuGlExtSurfaces *surfaces, VisuSurface *surface) { _SurfaceHandle *shd; #if GLIB_MINOR_VERSION > 9 shd = g_slice_alloc(sizeof(_SurfaceHandle)); #else shd = g_malloc(sizeof(_SurfaceHandle)); #endif DBG_fprintf(stderr, "Extension Surfaces: add listeners on surface %p.\n", (gpointer)surface); shd->ext = surfaces; shd->surface = surface; g_object_ref(surface); shd->masked_signal = g_signal_connect_swapped (G_OBJECT(surface), "masked", G_CALLBACK(_markDirtyAndReorder), surfaces); shd->resource_signal = g_signal_connect(G_OBJECT(surface), "notify::resource", G_CALLBACK(onSurfaceResource), (gpointer)shd); shd->box_signal = g_signal_connect_swapped (G_OBJECT(surface), "setBox", G_CALLBACK(_markDirty), surfaces); shd->res = visu_surface_getResource(surface); g_object_ref(shd->res); shd->notify_signal = g_signal_connect(G_OBJECT(shd->res), "notify", G_CALLBACK(onResourceNotify), (gpointer)surfaces); return (gpointer)shd; } static gint _cmpSurfaceHandle(gconstpointer a, gconstpointer b) { return ((_SurfaceHandle*)a)->surface == b ? 0 : 1; } #define _getSurface(H) ((_SurfaceHandle*)H)->surface G_DEFINE_TYPE_WITH_CODE(VisuGlExtSurfaces, visu_gl_ext_surfaces, VISU_TYPE_GL_EXT, G_ADD_PRIVATE(VisuGlExtSurfaces)) static void visu_gl_ext_surfaces_class_init(VisuGlExtSurfacesClass *klass) { VisuConfigFileEntry *entry; DBG_fprintf(stderr, "Extension Surfaces: creating the class of the object.\n"); DBG_fprintf(stderr, " - adding new signals ;\n"); /** * VisuGlExtSurfaces::added: * @set: the object emitting the signal. * @surface: the added #VisuSurface object. * * This signal is emitted each time a surface is added to * the set. * * Since: 3.8 */ _signals[ADD_SIGNAL] = g_signal_new("added", G_TYPE_FROM_CLASS(klass), G_SIGNAL_RUN_LAST | G_SIGNAL_NO_RECURSE | G_SIGNAL_NO_HOOKS, 0, NULL, NULL, g_cclosure_marshal_VOID__OBJECT, G_TYPE_NONE, 1, VISU_TYPE_SURFACE, NULL); /** * VisuGlExtSurfaces::removed: * @set: the object emitting the signal. * @surface: the removed #VisuSurface object. * * This signal is emitted each time a surface is removed from * the set. * * Since: 3.8 */ _signals[REMOVE_SIGNAL] = g_signal_new("removed", G_TYPE_FROM_CLASS(klass), G_SIGNAL_RUN_LAST | G_SIGNAL_NO_RECURSE | G_SIGNAL_NO_HOOKS, 0, NULL, NULL, g_cclosure_marshal_VOID__OBJECT, G_TYPE_NONE, 1, VISU_TYPE_SURFACE, NULL); DBG_fprintf(stderr, " - adding new resources ;\n"); entry = visu_config_file_addBooleanEntry(VISU_CONFIG_FILE_RESOURCE, FLAG_RESOURCE_INTRA, DESC_RESOURCE_INTRA, &INTRA_DEFAULT, FALSE); visu_config_file_entry_setVersion(entry, 3.4f); visu_config_file_addExportFunction(VISU_CONFIG_FILE_RESOURCE, isosurfaces_export_resources); defaultSurfaces = (VisuGlExtSurfaces*)0; /* Connect the overloading methods. */ G_OBJECT_CLASS(klass)->dispose = visu_gl_ext_surfaces_dispose; G_OBJECT_CLASS(klass)->finalize = visu_gl_ext_surfaces_finalize; G_OBJECT_CLASS(klass)->set_property = visu_gl_ext_surfaces_set_property; G_OBJECT_CLASS(klass)->get_property = visu_gl_ext_surfaces_get_property; VISU_GL_EXT_CLASS(klass)->setGlView = _setGlView; VISU_GL_EXT_CLASS(klass)->rebuild = visu_gl_ext_surfaces_rebuild; VISU_GL_EXT_CLASS(klass)->draw = visu_gl_ext_surfaces_draw; /** * VisuGlExtSurfaces::draw-intra: * * Store if the inside of surfaces are drawn with inverse colour. * * Since: 3.8 */ _properties[DRAW_INTRA_PROP] = g_param_spec_boolean("draw-intra", "Draw intra", "use inverse colour for inside", FALSE, G_PARAM_READWRITE); g_object_class_install_property(G_OBJECT_CLASS(klass), DRAW_INTRA_PROP, _properties[DRAW_INTRA_PROP]); /** * VisuGlExtSurfaces::fitting-box: * * If set, all surfaces are scaled to fit this box. * * Since: 3.8 */ _properties[BOX_PROP] = g_param_spec_object("fitting-box", "Fitting box", "If set, all surfaces are scaled to fit this box.", VISU_TYPE_BOX, G_PARAM_READWRITE); g_object_class_install_property(G_OBJECT_CLASS(klass), BOX_PROP, _properties[BOX_PROP]); } static void visu_gl_ext_surfaces_init(VisuGlExtSurfaces *obj) { DBG_fprintf(stderr, "Extension Surfaces: initializing a new object (%p).\n", (gpointer)obj); obj->priv = visu_gl_ext_surfaces_get_instance_private(obj); obj->priv->dispose_has_run = FALSE; /* Private data. */ obj->priv->drawIntra = INTRA_DEFAULT; obj->priv->surfs = (GList*)0; obj->priv->view = (VisuGlView*)0; obj->priv->inter = (VisuInteractive*)0; obj->priv->observe_signal = 0; obj->priv->mask = (VisuPlaneSet*)0; obj->priv->reorderingNeeded = FALSE; obj->priv->order = visu_surface_order_new(); obj->priv->box = (VisuBox*)0; g_signal_connect_object(VISU_CONFIG_FILE_RESOURCE, "parsed::" FLAG_RESOURCE_INTRA, G_CALLBACK(onEntryIntra), (gpointer)obj, G_CONNECT_SWAPPED); if (!defaultSurfaces) defaultSurfaces = obj; } static void visu_gl_ext_surfaces_dispose(GObject* obj) { VisuGlExtSurfaces *surfaces; GList *lst; DBG_fprintf(stderr, "Extension Surfaces: dispose object %p.\n", (gpointer)obj); surfaces = VISU_GL_EXT_SURFACES(obj); if (surfaces->priv->dispose_has_run) return; surfaces->priv->dispose_has_run = TRUE; /* Disconnect signals. */ if (surfaces->priv->mask) g_object_unref(surfaces->priv->mask); for (lst = surfaces->priv->surfs; lst; lst = g_list_next(lst)) _freeSurfaceHandle((_SurfaceHandle*)lst->data); _setGlView(VISU_GL_EXT(surfaces), (VisuGlView*)0); visu_gl_ext_surfaces_setOnObserveOrdering(surfaces, (VisuInteractive*)0); visu_gl_ext_surfaces_setFittingBox(surfaces, (VisuBox*)0); /* Chain up to the parent class */ G_OBJECT_CLASS(visu_gl_ext_surfaces_parent_class)->dispose(obj); } static void visu_gl_ext_surfaces_finalize(GObject* obj) { VisuGlExtSurfaces *surfaces; g_return_if_fail(obj); DBG_fprintf(stderr, "Extension Surfaces: finalize object %p.\n", (gpointer)obj); surfaces = VISU_GL_EXT_SURFACES(obj); /* Free privs elements. */ if (surfaces->priv) { DBG_fprintf(stderr, "Extension Surfaces: free private surfaces.\n"); visu_surface_order_free(surfaces->priv->order); g_list_free(surfaces->priv->surfs); } /* Chain up to the parent class */ DBG_fprintf(stderr, "Extension Surfaces: chain to parent.\n"); G_OBJECT_CLASS(visu_gl_ext_surfaces_parent_class)->finalize(obj); DBG_fprintf(stderr, "Extension Surfaces: freeing ... OK.\n"); } static void visu_gl_ext_surfaces_get_property(GObject* obj, guint property_id, GValue *value, GParamSpec *pspec) { VisuGlExtSurfaces *self = VISU_GL_EXT_SURFACES(obj); DBG_fprintf(stderr, "Extension Surfaces: get property '%s' -> ", g_param_spec_get_name(pspec)); switch (property_id) { case DRAW_INTRA_PROP: g_value_set_boolean(value, self->priv->drawIntra); DBG_fprintf(stderr, "%d.\n", self->priv->drawIntra); break; case BOX_PROP: g_value_set_object(value, self->priv->box); DBG_fprintf(stderr, "%p.\n", g_value_get_object(value)); break; default: /* We don't have any other property... */ G_OBJECT_WARN_INVALID_PROPERTY_ID(obj, property_id, pspec); break; } } static void visu_gl_ext_surfaces_set_property(GObject* obj, guint property_id, const GValue *value, GParamSpec *pspec) { VisuGlExtSurfaces *self = VISU_GL_EXT_SURFACES(obj); DBG_fprintf(stderr, "Extension Surfaces: set property '%s' -> ", g_param_spec_get_name(pspec)); switch (property_id) { case DRAW_INTRA_PROP: DBG_fprintf(stderr, "%d.\n", g_value_get_boolean(value)); visu_gl_ext_surfaces_setDrawIntra(self, g_value_get_boolean(value)); break; case BOX_PROP: DBG_fprintf(stderr, "%p.\n", g_value_get_object(value)); visu_gl_ext_surfaces_setFittingBox(self, VISU_BOX(g_value_get_object(value))); break; default: /* We don't have any other property... */ G_OBJECT_WARN_INVALID_PROPERTY_ID(obj, property_id, pspec); break; } } /** * visu_gl_ext_surfaces_new: * @name: (allow-none): the name to give to the extension (default is #VISU_GL_EXT_SURFACES_ID). * * Creates a new #VisuGlExt to draw surfaces. * * Since: 3.7 * * Returns: a pointer to the #VisuGlExt it created or * NULL otherwise. */ VisuGlExtSurfaces* visu_gl_ext_surfaces_new(const gchar *name) { char *name_ = VISU_GL_EXT_SURFACES_ID; char *description = _("Drawing iso-surfaces"); DBG_fprintf(stderr,"Extension Surfaces: new object.\n"); return g_object_new(VISU_TYPE_GL_EXT_SURFACES, "name", (name) ? name : name_, "label", (name) ? name : _(name_), "description", description, "nGlObj", 2, "priority", VISU_GL_EXT_PRIORITY_NORMAL + 2, "saveState", TRUE, NULL); } /** * visu_gl_ext_surfaces_add: * @surfaces: a #VisuGlExtSurfaces object. * @surf: (transfer full): a #VisuSurface object. * * Add a new surface to the list of drawn surfaces. * * Since: 3.7 * * Returns: FALSE if @surf was already registered. **/ gboolean visu_gl_ext_surfaces_add(VisuGlExtSurfaces *surfaces, VisuSurface *surf) { GList *lst; g_return_val_if_fail(VISU_IS_GL_EXT_SURFACES(surfaces), FALSE); lst = g_list_find_custom(surfaces->priv->surfs, surf, _cmpSurfaceHandle); if (lst) return FALSE; surfaces->priv->surfs = g_list_prepend(surfaces->priv->surfs, _newSurfaceHandle(surfaces, surf)); visu_surface_setMask(surf, surfaces->priv->mask); if (surfaces->priv->box) { g_object_set(surf, "auto-adjust", TRUE, NULL); visu_boxed_setBox(VISU_BOXED(surf), VISU_BOXED(surfaces->priv->box)); } surfaces->priv->reorderingNeeded = !visu_gl_getTrueTransparency(visu_gl_ext_getGlContext(VISU_GL_EXT(surfaces))); visu_gl_ext_setDirty(VISU_GL_EXT(surfaces), TRUE); g_signal_emit(G_OBJECT(surfaces), _signals[ADD_SIGNAL], 0, surf); return TRUE; } /** * visu_gl_ext_surfaces_remove: * @surfaces: a #VisuGlExtSurfaces object. * @surf: a #VisuSurface object. * * Removes @surf from the list of drawn surfaces. * * Since: 3.7 * * Returns: TRUE if @surf was part of the drawn surfaces. **/ gboolean visu_gl_ext_surfaces_remove(VisuGlExtSurfaces *surfaces, VisuSurface *surf) { GList *lst; g_return_val_if_fail(VISU_IS_GL_EXT_SURFACES(surfaces), FALSE); lst = g_list_find_custom(surfaces->priv->surfs, surf, _cmpSurfaceHandle); if (!lst) return FALSE; g_object_ref(surf); surfaces->priv->surfs = g_list_remove_link(surfaces->priv->surfs, lst); _freeSurfaceHandle(lst->data); g_list_free(lst); surfaces->priv->reorderingNeeded = !visu_gl_getTrueTransparency(visu_gl_ext_getGlContext(VISU_GL_EXT(surfaces))); visu_gl_ext_setDirty(VISU_GL_EXT(surfaces), TRUE); g_signal_emit(G_OBJECT(surfaces), _signals[REMOVE_SIGNAL], 0, surf); g_object_unref(surf); return TRUE; } static gboolean _setGlView(VisuGlExt *ext, VisuGlView *view) { VisuGlExtSurfaces *surfaces; g_return_val_if_fail(VISU_IS_GL_EXT_SURFACES(ext), FALSE); surfaces = VISU_GL_EXT_SURFACES(ext); /* No change to be done. */ if (view == surfaces->priv->view) return FALSE; if (surfaces->priv->view) { g_signal_handler_disconnect(G_OBJECT(surfaces->priv->view), surfaces->priv->theta_signal); g_signal_handler_disconnect(G_OBJECT(surfaces->priv->view), surfaces->priv->phi_signal); g_signal_handler_disconnect(G_OBJECT(surfaces->priv->view), surfaces->priv->omega_signal); g_clear_object(&surfaces->priv->view); } if (view) { surfaces->priv->view = g_object_ref(view); surfaces->priv->theta_signal = g_signal_connect_swapped(G_OBJECT(view), "notify::theta", G_CALLBACK(onCameraChange), (gpointer)surfaces); surfaces->priv->phi_signal = g_signal_connect_swapped(G_OBJECT(view), "notify::phi", G_CALLBACK(onCameraChange), (gpointer)surfaces); surfaces->priv->omega_signal = g_signal_connect_swapped(G_OBJECT(view), "notify::omega", G_CALLBACK(onCameraChange), (gpointer)surfaces); } return TRUE; } /** * visu_gl_ext_surfaces_setMask: * @surfaces: a #VisuGlExtSurfaces object. * @mask: (allow-none): a #VisuPlaneSet object. * * Attach @mask to every surface of the set. * * Since: 3.8 * * Returns: TRUE if mask is changed. **/ gboolean visu_gl_ext_surfaces_setMask(VisuGlExtSurfaces *surfaces, VisuPlaneSet *mask) { GList *lst; g_return_val_if_fail(VISU_IS_GL_EXT_SURFACES(surfaces), FALSE); if (surfaces->priv->mask == mask) return FALSE; if (surfaces->priv->mask) g_object_unref(surfaces->priv->mask); surfaces->priv->mask = mask; if (surfaces->priv->mask) g_object_ref(surfaces->priv->mask); /* Apply mask on every surface. */ for (lst = surfaces->priv->surfs; lst; lst = g_list_next(lst)) visu_surface_setMask(((_SurfaceHandle*)lst->data)->surface, mask); return TRUE; } static void _fitToBox(VisuGlExtSurfaces *surfaces, gfloat extens _U_, VisuBox *box) { GList *lst; gboolean res; res = FALSE; for (lst = surfaces->priv->surfs; lst; lst = g_list_next(lst)) { g_object_set(G_OBJECT(((_SurfaceHandle*)lst->data)->surface), "auto-adjust", TRUE, NULL); res = visu_boxed_setBox(VISU_BOXED(((_SurfaceHandle*)lst->data)->surface), VISU_BOXED(box)) || res; } if (res) visu_gl_ext_setDirty(VISU_GL_EXT(surfaces), TRUE); } /** * visu_gl_ext_surfaces_setFittingBox: * @surfaces: a #VisuGlExtSurfaces object. * @box: (allow-none): a #VisuBox object. * * Changes the box from which surfaces are scaled in. * * Since: 3.8 * * Returns: TRUE if value is actually changed. **/ gboolean visu_gl_ext_surfaces_setFittingBox(VisuGlExtSurfaces *surfaces, VisuBox *box) { g_return_val_if_fail(VISU_IS_GL_EXT_SURFACES(surfaces), FALSE); DBG_fprintf(stderr, "Extension Surfaces: set box %p.\n", (gpointer)box); if (surfaces->priv->box == box) return FALSE; if (surfaces->priv->box) { g_signal_handler_disconnect(surfaces->priv->box, surfaces->priv->size_signal); g_object_unref(surfaces->priv->box); } if (box) { g_object_ref(box); surfaces->priv->size_signal = g_signal_connect_swapped(box, "SizeChanged", G_CALLBACK(_fitToBox), surfaces); _fitToBox(surfaces, 0.f, box); } surfaces->priv->box = box; return TRUE; } /** * visu_gl_ext_surfaces_setOnObserveOrdering: * @surfaces: the #VisuGlExtSurfaces object to attached to rendering inter. * @inter: (transfer full) (allow-none): a #VisuInteractive object. * * Attach @surfaces to @inter, so it can be rendered there. * * Since: 3.7 * * Returns: TRUE if the status actually changed. **/ gboolean visu_gl_ext_surfaces_setOnObserveOrdering(VisuGlExtSurfaces *surfaces, VisuInteractive *inter) { g_return_val_if_fail(VISU_IS_GL_EXT_SURFACES(surfaces), FALSE); /* No change to be done. */ if (inter == surfaces->priv->inter) return FALSE; if (surfaces->priv->inter) { g_signal_handler_disconnect(G_OBJECT(surfaces->priv->inter), surfaces->priv->observe_signal); DBG_fprintf(stderr, "Extension Surfaces: inter %p has %d ref counts.\n", (gpointer)surfaces->priv->inter, G_OBJECT(surfaces->priv->inter)->ref_count); g_object_unref(surfaces->priv->inter); } if (inter) { g_object_ref(inter); surfaces->priv->observe_signal = g_signal_connect(G_OBJECT(inter), "observe", G_CALLBACK(onObserve), (gpointer)surfaces); DBG_fprintf(stderr, "Extension Surfaces: inter %p has %d ref counts.\n", (gpointer)inter, G_OBJECT(inter)->ref_count); } else { surfaces->priv->observe_signal = 0; } surfaces->priv->inter = inter; return TRUE; } /** * visu_gl_ext_surfaces_getDrawIntra: * @surfs: a #VisuGlExtSurfaces object. * * Retrieve if the interiors of surfaces are drawn with a colour inverse or not. * * Returns: TRUE if the interior is painted in colour inverse. */ gboolean visu_gl_ext_surfaces_getDrawIntra(VisuGlExtSurfaces *surfs) { g_return_val_if_fail(VISU_IS_GL_EXT_SURFACES(surfs), FALSE); return surfs->priv->drawIntra; } /** * visu_gl_ext_surfaces_setDrawIntra: * @surfs: a #VisuGlExtSurfaces object. * @status: a boolean. * * Set if the interiors of surfaces are drawn with a colour inverse or not. * * Returns: TRUE if the status actually changed. */ gboolean visu_gl_ext_surfaces_setDrawIntra(VisuGlExtSurfaces *surfs, gboolean status) { g_return_val_if_fail(VISU_IS_GL_EXT_SURFACES(surfs), FALSE); if (surfs->priv->drawIntra == status) return FALSE; surfs->priv->drawIntra = status; g_object_notify_by_pspec(G_OBJECT(surfs), _properties[DRAW_INTRA_PROP]); visu_gl_ext_setDirty(VISU_GL_EXT(surfs), TRUE); return TRUE; } static void sort_block_by_z(int *order, float *z, int begin, int end) { int i; int middle; int temp; if( begin >= end ) return; /* We make sure end + begin / 2 has found its place. */ temp = order[begin]; order[begin] = order[(end + begin) / 2]; order[(end + begin) / 2] = temp; middle = begin; for(i = begin + 1; i <= end; i++) { if ( z[order[i]] < z[order[begin]] ) { temp = order[i]; middle += 1; order[i] = order[middle]; order[middle] = temp; } } temp = order[begin]; order[begin] = order[middle]; order[middle] = temp; sort_block_by_z(order, z, begin, middle-1); sort_block_by_z(order, z, middle+1, end); } /** * visu_surface_duplicate: * @totalList: an OpenGL identifier for the global list to create ; * @simpleBlockList: an OpenGL identifier for the list with the * surfaces in the primitive cell ; * @box: the definition of the #VisuBox for extension ; * @reorder: if TRUE the blocks are drawn from back to front. * * Duplicate the list @simpleBlockList using the extension of the * given @box. */ static void _duplicate(VisuGlExt *extension, int simpleBlockList, VisuBox *box, gboolean reorder) { float ext[3], *xyzTrans, boxTrans[3], *z; int i, j, k, n, *order; float mat[16]; DBG_fprintf(stderr, "Isosurfaces: duplicate the primitive block.\n"); if (box) /* Duplicate the surface according to the box extension. */ visu_box_getExtension(box, ext); else { ext[0] = 0.f; ext[1] = 0.f; ext[2] = 0.f; } if (reorder) glGetFloatv(GL_MODELVIEW_MATRIX, mat); n = (1 + 2 * (int)ext[0]) * (1 + 2 * (int)ext[1]) * (1 + 2 * (int)ext[2]); xyzTrans = g_malloc(sizeof(int) * 3 * n); z = (float*)0; if (reorder) z = g_malloc(sizeof(float) * n); order = g_malloc(sizeof(int) * n); if (n > 1) { n = 0; for (i = -(int)ext[0]; i < 1 + (int)ext[0]; i++) for (j = -(int)ext[1]; j < 1 + (int)ext[1]; j++) for (k = -(int)ext[2]; k < 1 + (int)ext[2]; k++) { boxTrans[0] = (float)i; boxTrans[1] = (float)j; boxTrans[2] = (float)k; visu_box_convertBoxCoordinatestoXYZ(box, xyzTrans + 3 * n, boxTrans); if (reorder) z[n] = (mat[ 2] * xyzTrans[3 * n + 0] + mat[ 6] * xyzTrans[3 * n + 1] + mat[10] * xyzTrans[3 * n + 2] + mat[14] * 1.) / (mat[ 3] * xyzTrans[3 * n + 0] + mat[ 7] * xyzTrans[3 * n + 1] + mat[11] * xyzTrans[3 * n + 2] + mat[15] * 1.); order[n] = n; n += 1; } } else { order[0] = 0; xyzTrans[0] = 0.f; xyzTrans[1] = 0.f; xyzTrans[2] = 0.f; } if (reorder) /* we sort xyzTrans following z values. */ sort_block_by_z(order, z, 0, n - 1); visu_gl_ext_startDrawing(extension); for (i = 0; i < n; i++) { /* DBG_fprintf(stderr, "Isosurfaces: translate surfaces to box %d.\n", */ /* order[i]); */ glPushMatrix(); glTranslated(xyzTrans[3 * order[i] + 0], xyzTrans[3 * order[i] + 1], xyzTrans[3 * order[i] + 2]); glCallList(simpleBlockList); glPopMatrix(); } visu_gl_ext_completeDrawing(extension); g_free(order); g_free(xyzTrans); if (reorder) g_free(z); } static void visu_gl_ext_surfaces_draw(VisuGlExt *surfs) { guint i, j; struct _orderInfo *data; VisuSurfaceResource *res, *res_old; float rgba[4]; GArray *vertices; VisuSurfacePoint *at; VisuGlExtSurfacesPrivate *priv = VISU_GL_EXT_SURFACES(surfs)->priv; DBG_fprintf(stderr, "Isosurfaces: rebuilding surfaces list\n"); visu_gl_ext_setDirty(surfs, FALSE); glDeleteLists(visu_gl_ext_getGlList(surfs), 1); if (!priv->surfs) return; /* If order is out of date, we update. */ if (priv->reorderingNeeded || priv->order->polygon_number->len == 0) { visu_surface_order_polygons(priv->order, priv->surfs); priv->reorderingNeeded = FALSE; } vertices = g_array_sized_new(FALSE, FALSE, sizeof(VisuSurfacePoint), 5); glNewList(visu_gl_ext_getGlList(surfs) + 1, GL_COMPILE); if (priv->drawIntra) glEnable(GL_CULL_FACE); else glDisable(GL_CULL_FACE); glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA); glEnable(GL_BLEND); DBG_fprintf(stderr, " | draw polygons.\n"); res = res_old = (VisuSurfaceResource*)0; for(i = 0; i < priv->order->any_pointer->len; i++) { data = g_array_index(priv->order->any_pointer, struct _orderInfo*, i); res = visu_surface_getResource(data->iter.surf); if (res != res_old || priv->drawIntra) { visu_gl_setColor((VisuGl*)0, visu_surface_resource_getMaterial(res), visu_surface_resource_getColor(res)->rgba); res_old = res; } /* This is where to find the points and the normals. */ visu_surface_iter_poly_getVertices(&data->iter, vertices); glBegin(GL_POLYGON); for (j = 0; j < vertices->len; j++ ) { at = &g_array_index(vertices, VisuSurfacePoint, j); glNormal3dv(at->normal); glVertex3dv(at->at); } glEnd(); if (priv->drawIntra) { glBegin(GL_POLYGON); tool_color_invertRGBA(rgba, visu_surface_resource_getColor(res)->rgba); visu_gl_setColor((VisuGl*)0, visu_surface_resource_getMaterial(res), rgba); for (j = vertices->len; j > 0; j-- ) { at = &g_array_index(vertices, VisuSurfacePoint, j - 1); glNormal3d(-at->normal[0], -at->normal[1], -at->normal[2]); glVertex3dv(at->at); } glEnd(); } } glEndList(); g_array_unref(vertices); /* Duplicate here. */ _duplicate(surfs, visu_gl_ext_getGlList(surfs) + 1, visu_boxed_getBox(VISU_BOXED(((_SurfaceHandle*)priv->surfs->data)->surface)), TRUE); } /**************/ /* Callbacks. */ /**************/ static void _markDirty(VisuGlExt *data) { visu_gl_ext_setDirty(data, TRUE); } static void _markDirtyAndReorder(VisuGlExtSurfaces *data) { data->priv->reorderingNeeded = TRUE; visu_gl_ext_setDirty(VISU_GL_EXT(data), TRUE); } static void visu_gl_ext_surfaces_rebuild(VisuGlExt *ext) { _markDirtyAndReorder(VISU_GL_EXT_SURFACES(ext)); visu_gl_ext_surfaces_draw(ext); } static void onSurfaceResource(VisuSurface *surfaces, GParamSpec *param, _SurfaceHandle *data) { g_signal_handler_disconnect(G_OBJECT(data->res), data->notify_signal); g_object_unref(data->res); data->res = visu_surface_getResource(surfaces); g_object_ref(data->res); data->notify_signal = g_signal_connect(G_OBJECT(data->res), "notify", G_CALLBACK(onResourceNotify), (gpointer)data->ext); onResourceNotify(data->res, param, (gpointer)data->ext); } static void onResourceNotify(VisuSurfaceResource *res _U_, GParamSpec *param, VisuGlExtSurfaces *data) { if (!strcmp(g_param_spec_get_name(param), "maskable") || !strcmp(g_param_spec_get_name(param), "rendered")) data->priv->reorderingNeeded = TRUE; visu_gl_ext_setDirty(VISU_GL_EXT(data), TRUE); } static void onCameraChange(VisuGlExtSurfaces *data) { data->priv->reorderingNeeded = !visu_gl_getTrueTransparency(visu_gl_ext_getGlContext(VISU_GL_EXT(data))); visu_gl_ext_setDirty(VISU_GL_EXT(data), TRUE); } static void onObserve(VisuInteractive *inter _U_, gboolean start, VisuGlExtSurfaces *data) { if (!data->priv->view && !start) { data->priv->reorderingNeeded = !visu_gl_getTrueTransparency(visu_gl_ext_getGlContext(VISU_GL_EXT(data))); visu_gl_ext_setDirty(VISU_GL_EXT(data), TRUE); } } static void onEntryIntra(VisuGlExtSurfaces *surfs, VisuConfigFileEntry *entry _U_, VisuConfigFile *obj _U_) { visu_gl_ext_surfaces_setDrawIntra(surfs, INTRA_DEFAULT); } /***************/ /* Properties. */ /***************/ static void isosurfaces_export_resources(GString *data, VisuData *dataObj _U_) { if (!defaultSurfaces) return; visu_config_file_exportComment(data, DESC_RESOURCE_INTRA); visu_config_file_exportEntry(data, FLAG_RESOURCE_INTRA, NULL, "%d", defaultSurfaces->priv->drawIntra); visu_config_file_exportComment(data, ""); } v_sim-3.8.0/src/extensions/surfs.h000066400000000000000000000076001370110300500171310ustar00rootroot00000000000000/* EXTRAITS DE LA LICENCE Copyright CEA, contributeurs : Damien CALISTE, laboratoire L_Sim, (2001-2019) Adresse mèl : CALISTE, damien P caliste AT cea P fr. Ce logiciel est un programme informatique servant à visualiser des structures atomiques dans un rendu pseudo-3D. Ce logiciel est régi par la licence CeCILL soumise au droit français et respectant les principes de diffusion des logiciels libres. Vous pouvez utiliser, modifier et/ou redistribuer ce programme sous les conditions de la licence CeCILL telle que diffusée par le CEA, le CNRS et l'INRIA sur le site "http://www.cecill.info". Le fait que vous puissiez accéder à cet en-tête signifie que vous avez pris connaissance de la licence CeCILL, et que vous en avez accepté les termes (cf. le fichier Documentation/licence.fr.txt fourni avec ce logiciel). */ /* LICENCE SUM UP Copyright CEA, contributors : Damien CALISTE, laboratoire L_Sim, (2001-2019) E-mail address: CALISTE, damien P caliste AT cea P fr. This software is a computer program whose purpose is to visualize atomic configurations in 3D. This software is governed by the CeCILL license under French law and abiding by the rules of distribution of free software. You can use, modify and/ or redistribute the software under the terms of the CeCILL license as circulated by CEA, CNRS and INRIA at the following URL "http://www.cecill.info". The fact that you are presently reading this means that you have had knowledge of the CeCILL license and that you accept its terms. You can find a copy of this licence shipped with this software at COPYING. */ #ifndef SURFS_H #define SURFS_H #include #include #include #include #define VISU_TYPE_GL_EXT_SURFACES (visu_gl_ext_surfaces_get_type ()) #define VISU_GL_EXT_SURFACES(obj) (G_TYPE_CHECK_INSTANCE_CAST(obj, VISU_TYPE_GL_EXT_SURFACES, VisuGlExtSurfaces)) #define VISU_GL_EXT_SURFACES_CLASS(klass) (G_TYPE_CHECK_CLASS_CAST(klass, VISU_TYPE_GL_EXT_SURFACES, VisuGlExtSurfacesClass)) #define VISU_IS_GL_EXT_SURFACES(obj) (G_TYPE_CHECK_INSTANCE_TYPE(obj, VISU_TYPE_GL_EXT_SURFACES)) #define VISU_IS_GL_EXT_SURFACES_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE(klass, VISU_TYPE_GL_EXT_SURFACES)) #define VISU_GL_EXT_SURFACES_GET_CLASS(obj) (G_TYPE_INSTANCE_GET_CLASS(obj, VISU_TYPE_GL_EXT_SURFACES, VisuGlExtSurfacesClass)) typedef struct _VisuGlExtSurfaces VisuGlExtSurfaces; typedef struct _VisuGlExtSurfacesPrivate VisuGlExtSurfacesPrivate; typedef struct _VisuGlExtSurfacesClass VisuGlExtSurfacesClass; struct _VisuGlExtSurfaces { VisuGlExt parent; VisuGlExtSurfacesPrivate *priv; }; struct _VisuGlExtSurfacesClass { VisuGlExtClass parent; }; /** * VISU_GL_EXT_SURFACES_ID: * * The id used to identify this extension, see * visu_gl_ext_rebuild() for instance. */ #define VISU_GL_EXT_SURFACES_ID "Surfaces" /** * visu_gl_ext_surfaces_get_type: * * This method returns the type of #VisuGlExtSurfaces, use * VISU_TYPE_GL_EXT_SURFACES instead. * * Since: 3.7 * * Returns: the type of #VisuGlExtSurfaces. */ GType visu_gl_ext_surfaces_get_type(void); VisuGlExtSurfaces* visu_gl_ext_surfaces_new(const gchar *name); gboolean visu_gl_ext_surfaces_add(VisuGlExtSurfaces *surfaces, VisuSurface *surf); gboolean visu_gl_ext_surfaces_remove(VisuGlExtSurfaces *surfaces, VisuSurface *surf); gboolean visu_gl_ext_surfaces_setMask(VisuGlExtSurfaces *surfaces, VisuPlaneSet *mask); gboolean visu_gl_ext_surfaces_setOnObserveOrdering(VisuGlExtSurfaces *surfaces, VisuInteractive *inter); gboolean visu_gl_ext_surfaces_setFittingBox(VisuGlExtSurfaces *surfaces, VisuBox *box); gboolean visu_gl_ext_surfaces_getDrawIntra(VisuGlExtSurfaces *surfs); gboolean visu_gl_ext_surfaces_setDrawIntra(VisuGlExtSurfaces *surfs, gboolean status); #endif v_sim-3.8.0/src/extensions/vibrations.c000066400000000000000000000101241370110300500201350ustar00rootroot00000000000000/* EXTRAITS DE LA LICENCE Copyright CEA, contributeurs : Damien CALISTE, laboratoire L_Sim, (2016) Adresse mèl : CALISTE, damien P caliste AT cea P fr. Ce logiciel est un programme informatique servant à visualiser des structures atomiques dans un rendu pseudo-3D. Ce logiciel est régi par la licence CeCILL soumise au droit français et respectant les principes de diffusion des logiciels libres. Vous pouvez utiliser, modifier et/ou redistribuer ce programme sous les conditions de la licence CeCILL telle que diffusée par le CEA, le CNRS et l'INRIA sur le site "http://www.cecill.info". Le fait que vous puissiez accéder à cet en-tête signifie que vous avez pris connaissance de la licence CeCILL, et que vous en avez accepté les termes (cf. le fichier Documentation/licence.fr.txt fourni avec ce logiciel). */ /* LICENCE SUM UP Copyright CEA, contributors : Damien CALISTE, laboratoire L_Sim, (2016) E-mail address: CALISTE, damien P caliste AT cea P fr. This software is a computer program whose purpose is to visualize atomic configurations in 3D. This software is governed by the CeCILL license under French law and abiding by the rules of distribution of free software. You can use, modify and/ or redistribute the software under the terms of the CeCILL license as circulated by CEA, CNRS and INRIA at the following URL "http://www.cecill.info". The fact that you are presently reading this means that you have had knowledge of the CeCILL license and that you accept its terms. You can find a copy of this licence shipped with this software at Documentation/licence.en.txt. */ #include "vibrations.h" /** * SECTION:vibrations * @short_description: Draw arrows at each node to represent vibrations. * * A specialised #VisuGlExtNodeVectors to represent vibrations on nodes. */ /** * VisuGlExtVibrationsClass: * @parent: the parent class; * * A short way to identify #_VisuGlExtVibrationsClass structure. * * Since: 3.8 */ /** * VisuGlExtVibrations: * * An opaque structure. * * Since: 3.8 */ G_DEFINE_TYPE(VisuGlExtVibrations, visu_gl_ext_vibrations, VISU_TYPE_GL_EXT_NODE_VECTORS) static void visu_gl_ext_vibrations_class_init(VisuGlExtVibrationsClass *klass _U_) { DBG_fprintf(stderr, "Visu GlExt Vibrations: creating the class of the object.\n"); /* DBG_fprintf(stderr, " - adding new signals ;\n"); */ } static void visu_gl_ext_vibrations_init(VisuGlExtVibrations *obj _U_) { DBG_fprintf(stderr, "Visu GlExt Vibrations: initializing a new object (%p).\n", (gpointer)obj); } /** * visu_gl_ext_vibrations_new: * @name: (allow-none): the name to give to the extension. * * Creates a new #VisuGlExt to draw vibrations. * * Since: 3.8 * * Returns: a pointer to the #VisuGlExt it created or * NULL otherwise. */ VisuGlExtVibrations* visu_gl_ext_vibrations_new(const gchar *name) { char *name_ = "Vibrations"; char *description = _("Draw vibrations with vectors."); VisuGlExtNodeVectors *vibrations; DBG_fprintf(stderr,"Visu GlExt Vibrations: new object.\n"); vibrations = VISU_GL_EXT_NODE_VECTORS(g_object_new(VISU_TYPE_GL_EXT_VIBRATIONS, "name", (name) ? name : name_, "label", _(name_), "description", description, "nGlObj", 1, "rendering-size", 1.f, "normalisation", -1.f, NULL)); visu_gl_ext_node_vectors_setCentering(vibrations, VISU_GL_ARROW_TAIL_CENTERED); visu_gl_ext_node_vectors_setColor(vibrations, FALSE); visu_gl_ext_node_vectors_setArrow(vibrations, 0.5f, 0.2f, 10, 0.5f, 0.3f, 10); visu_gl_ext_node_vectors_setVectorThreshold(vibrations, -0.05f); /* Value in percentage. */ visu_gl_ext_node_vectors_setAddLength(vibrations, 2.5f); return VISU_GL_EXT_VIBRATIONS(vibrations); } v_sim-3.8.0/src/extensions/vibrations.h000066400000000000000000000074441370110300500201550ustar00rootroot00000000000000/* EXTRAITS DE LA LICENCE Copyright CEA, contributeurs : Damien CALISTE, laboratoire L_Sim, (2016) Adresse mèl : CALISTE, damien P caliste AT cea P fr. Ce logiciel est un programme informatique servant à visualiser des structures atomiques dans un rendu pseudo-3D. Ce logiciel est régi par la licence CeCILL soumise au droit français et respectant les principes de diffusion des logiciels libres. Vous pouvez utiliser, modifier et/ou redistribuer ce programme sous les conditions de la licence CeCILL telle que diffusée par le CEA, le CNRS et l'INRIA sur le site "http://www.cecill.info". Le fait que vous puissiez accéder à cet en-tête signifie que vous avez pris connaissance de la licence CeCILL, et que vous en avez accepté les termes (cf. le fichier Documentation/licence.fr.txt fourni avec ce logiciel). */ /* LICENCE SUM UP Copyright CEA, contributors : Damien CALISTE, laboratoire L_Sim, (2016) E-mail address: CALISTE, damien P caliste AT cea P fr. This software is a computer program whose purpose is to visualize atomic configurations in 3D. This software is governed by the CeCILL license under French law and abiding by the rules of distribution of free software. You can use, modify and/ or redistribute the software under the terms of the CeCILL license as circulated by CEA, CNRS and INRIA at the following URL "http://www.cecill.info". The fact that you are presently reading this means that you have had knowledge of the CeCILL license and that you accept its terms. You can find a copy of this licence shipped with this software at COPYING. */ #ifndef VIBRATIONS_H #define VIBRATIONS_H #include "node_vectors.h" /** * VISU_TYPE_GL_EXT_VIBRATIONS: * * return the type of #VisuGlExtVibrations. * * Since: 3.8 */ #define VISU_TYPE_GL_EXT_VIBRATIONS (visu_gl_ext_vibrations_get_type ()) /** * VISU_GL_EXT_VIBRATIONS: * @obj: a #GObject to cast. * * Cast the given @obj into #VisuGlExtVibrations type. * * Since: 3.8 */ #define VISU_GL_EXT_VIBRATIONS(obj) (G_TYPE_CHECK_INSTANCE_CAST(obj, VISU_TYPE_GL_EXT_VIBRATIONS, VisuGlExtVibrations)) /** * VISU_GL_EXT_VIBRATIONS_CLASS: * @klass: a #GObjectClass to cast. * * Cast the given @klass into #VisuGlExtVibrationsClass. * * Since: 3.8 */ #define VISU_GL_EXT_VIBRATIONS_CLASS(klass) (G_TYPE_CHECK_CLASS_CAST(klass, VISU_TYPE_GL_EXT_VIBRATIONS, VisuGlExtVibrationsClass)) /** * VISU_IS_GL_EXT_VIBRATIONS: * @obj: a #GObject to test. * * Test if the given @ogj is of the type of #VisuGlExtVibrations object. * * Since: 3.8 */ #define VISU_IS_GL_EXT_VIBRATIONS(obj) (G_TYPE_CHECK_INSTANCE_TYPE(obj, VISU_TYPE_GL_EXT_VIBRATIONS)) /** * VISU_IS_GL_EXT_VIBRATIONS_CLASS: * @klass: a #GObjectClass to test. * * Test if the given @klass is of the type of #VisuGlExtVibrationsClass class. * * Since: 3.8 */ #define VISU_IS_GL_EXT_VIBRATIONS_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE(klass, VISU_TYPE_GL_EXT_VIBRATIONS)) /** * VISU_GL_EXT_VIBRATIONS_GET_CLASS: * @obj: a #GObject to get the class of. * * It returns the class of the given @obj. * * Since: 3.8 */ #define VISU_GL_EXT_VIBRATIONS_GET_CLASS(obj) (G_TYPE_INSTANCE_GET_CLASS(obj, VISU_TYPE_GL_EXT_VIBRATIONS, VisuGlExtVibrationsClass)) typedef struct _VisuGlExtVibrations VisuGlExtVibrations; typedef struct _VisuGlExtVibrationsClass VisuGlExtVibrationsClass; struct _VisuGlExtVibrations { VisuGlExtNodeVectors parent; }; struct _VisuGlExtVibrationsClass { VisuGlExtNodeVectorsClass parent; }; /** * visu_gl_ext_vibrations_get_type: * * This method returns the type of #VisuGlExtVibrations, use * VISU_TYPE_GL_EXT_VIBRATIONS instead. * * Since: 3.8 * * Returns: the type of #VisuGlExtVibrations. */ GType visu_gl_ext_vibrations_get_type(void); VisuGlExtVibrations* visu_gl_ext_vibrations_new(const gchar *name); #endif v_sim-3.8.0/src/extraFunctions/000077500000000000000000000000001370110300500164305ustar00rootroot00000000000000v_sim-3.8.0/src/extraFunctions/colorizer.c000066400000000000000000000265111370110300500206110ustar00rootroot00000000000000/* EXTRAITS DE LA LICENCE Copyright CEA, contributeurs : Damien CALISTE, laboratoire L_Sim, (2017) Adresse mèl : CALISTE, damien P caliste AT cea P fr. Ce logiciel est un programme informatique servant à visualiser des structures atomiques dans un rendu pseudo-3D. Ce logiciel est régi par la licence CeCILL soumise au droit français et respectant les principes de diffusion des logiciels libres. Vous pouvez utiliser, modifier et/ou redistribuer ce programme sous les conditions de la licence CeCILL telle que diffusée par le CEA, le CNRS et l'INRIA sur le site "http://www.cecill.info". Le fait que vous puissiez accéder à cet en-tête signifie que vous avez pris connaissance de la licence CeCILL, et que vous en avez accepté les termes (cf. le fichier Documentation/licence.fr.txt fourni avec ce logiciel). */ /* LICENCE SUM UP Copyright CEA, contributors : Damien CALISTE, laboratoire L_Sim, (2017) E-mail address: CALISTE, damien P caliste AT cea P fr. This software is a computer program whose purpose is to visualize atomic configurations in 3D. This software is governed by the CeCILL license under French law and abiding by the rules of distribution of free software. You can use, modify and/ or redistribute the software under the terms of the CeCILL license as circulated by CEA, CNRS and INRIA at the following URL "http://www.cecill.info". The fact that you are presently reading this means that you have had knowledge of the CeCILL license and that you accept its terms. You can find a copy of this licence shipped with this software at Documentation/licence.en.txt. */ #include "colorizer.h" /** * SECTION:colorizer * @short_description: a virtual class to colorise #VisuNodeArray. * * */ struct _VisuDataColorizerPrivate { gboolean dispose_has_run; guint dirtyPending; gboolean active; VisuSourceableData *source; }; enum { PROP_0, PROP_ACTIVE, N_PROPS, PROP_MODEL, PROP_SOURCE }; static GParamSpec *_properties[N_PROPS]; enum { DIRTY_SIGNAL, LAST_SIGNAL }; static guint _signals[LAST_SIGNAL] = { 0 }; static void visu_data_colorizer_dispose (GObject* obj); static void visu_data_colorizer_get_property(GObject* obj, guint property_id, GValue *value, GParamSpec *pspec); static void visu_data_colorizer_set_property(GObject* obj, guint property_id, const GValue *value, GParamSpec *pspec); static void visu_sourceable_interface_init(VisuSourceableInterface *iface); static VisuSourceableData** _getSource(VisuSourceable *self); static void _modelChanged(VisuSourceable *self); G_DEFINE_TYPE_WITH_CODE(VisuDataColorizer, visu_data_colorizer, VISU_TYPE_OBJECT, G_ADD_PRIVATE(VisuDataColorizer) G_IMPLEMENT_INTERFACE(VISU_TYPE_SOURCEABLE, visu_sourceable_interface_init)) static void visu_data_colorizer_class_init(VisuDataColorizerClass *klass) { /* Connect the overloading methods. */ G_OBJECT_CLASS(klass)->dispose = visu_data_colorizer_dispose; G_OBJECT_CLASS(klass)->set_property = visu_data_colorizer_set_property; G_OBJECT_CLASS(klass)->get_property = visu_data_colorizer_get_property; /** * VisuDataColorizer::dirty: * * Gets emitted when colorizer characteristics have changed and a * redraw is needed. * * Since: 3.8 */ _signals[DIRTY_SIGNAL] = g_signal_new("dirty", G_TYPE_FROM_CLASS(klass), G_SIGNAL_RUN_LAST | G_SIGNAL_NO_RECURSE | G_SIGNAL_NO_HOOKS, 0 , NULL, NULL, g_cclosure_marshal_VOID__VOID, G_TYPE_NONE, 0); /** * VisuDataColorizer::active: * * A flag specifying if the colorizer has changed. * * Since: 3.8 */ _properties[PROP_ACTIVE] = g_param_spec_boolean("active", "Active", "active", FALSE, G_PARAM_READWRITE); g_object_class_install_properties(G_OBJECT_CLASS(klass), N_PROPS, _properties); g_object_class_override_property(G_OBJECT_CLASS(klass), PROP_SOURCE, "source"); g_object_class_override_property(G_OBJECT_CLASS(klass), PROP_MODEL, "model"); } static void visu_sourceable_interface_init(VisuSourceableInterface *iface) { iface->getSource = _getSource; iface->modelChanged = _modelChanged; } static void visu_data_colorizer_init(VisuDataColorizer *obj) { DBG_fprintf(stderr, "Visu Data Colorizer: initializing a new object (%p).\n", (gpointer)obj); obj->priv = visu_data_colorizer_get_instance_private(obj); obj->priv->dispose_has_run = FALSE; obj->priv->dirtyPending = 0; obj->priv->active = FALSE; visu_sourceable_init(VISU_SOURCEABLE(obj)); } static void visu_data_colorizer_get_property(GObject* obj, guint property_id, GValue *value, GParamSpec *pspec) { VisuDataColorizer *self = VISU_DATA_COLORIZER(obj); DBG_fprintf(stderr, "Visu Data Colorizer: get property '%s' -> ", g_param_spec_get_name(pspec)); switch (property_id) { case PROP_ACTIVE: g_value_set_boolean(value, self->priv->active); DBG_fprintf(stderr, "%d.\n", self->priv->active); break; case PROP_MODEL: g_value_set_object(value, visu_sourceable_getNodeModel(VISU_SOURCEABLE(self))); DBG_fprintf(stderr, "%p.\n", g_value_get_object(value)); break; case PROP_SOURCE: g_value_set_string(value, visu_sourceable_getSource(VISU_SOURCEABLE(self))); DBG_fprintf(stderr, "%s.\n", g_value_get_string(value)); break; default: /* We don't have any other property... */ G_OBJECT_WARN_INVALID_PROPERTY_ID(obj, property_id, pspec); break; } } static void visu_data_colorizer_set_property(GObject* obj, guint property_id, const GValue *value, GParamSpec *pspec) { VisuDataColorizer *self = VISU_DATA_COLORIZER(obj); DBG_fprintf(stderr, "Visu Data Colorizer: set property '%s' -> ", g_param_spec_get_name(pspec)); switch (property_id) { case PROP_ACTIVE: DBG_fprintf(stderr, "%d.\n", g_value_get_boolean(value)); visu_data_colorizer_setActive(self, g_value_get_boolean(value)); break; case PROP_MODEL: DBG_fprintf(stderr, "%p.\n", g_value_get_object(value)); visu_sourceable_setNodeModel(VISU_SOURCEABLE(obj), g_value_get_object(value)); break; case PROP_SOURCE: DBG_fprintf(stderr, "%s.\n", g_value_get_string(value)); visu_sourceable_setSource(VISU_SOURCEABLE(obj), g_value_get_string(value)); break; default: /* We don't have any other property... */ G_OBJECT_WARN_INVALID_PROPERTY_ID(obj, property_id, pspec); break; } } static void visu_data_colorizer_dispose(GObject* obj) { VisuDataColorizer *self; self = VISU_DATA_COLORIZER(obj); if (self->priv->dispose_has_run) return; self->priv->dispose_has_run = TRUE; visu_sourceable_dispose(VISU_SOURCEABLE(obj)); if (self->priv->dirtyPending) g_source_remove(self->priv->dirtyPending); /* Chain up to the parent class */ G_OBJECT_CLASS(visu_data_colorizer_parent_class)->dispose(obj); } /** * visu_data_colorizer_getColor: * @colorizer: a #VisuDataColorizer object. * @rgba: (array fixed-size=4) (out caller-allocates): a location for * store a colour definition. * @visuData: a #VisuData object. * @node: a #VisuNode structure. * * Call the class colorizer function of @colorizer to setup a colour * in @rgba for given @node inside @visuData. If there is no specific * colour for this node and the default element colour should be used * instead, this function returns FALSE. * * Since: 3.8 * * Returns: TRUE if @colorizer can actually provide a colour for @node. **/ gboolean visu_data_colorizer_getColor(const VisuDataColorizer *colorizer, float rgba[4], const VisuData *visuData, const VisuNode* node) { g_return_val_if_fail(VISU_IS_DATA_COLORIZER(colorizer), FALSE); if (!visu_data_colorizer_getActive(colorizer)) return FALSE; /* if (!colorizer->priv->model) */ /* return FALSE; */ if (!visu_element_getColorizable(visu_node_array_getElement(VISU_NODE_ARRAY_CONST(visuData), node))) return FALSE; if (!VISU_DATA_COLORIZER_GET_CLASS(colorizer)->colorize) return FALSE; return VISU_DATA_COLORIZER_GET_CLASS(colorizer)->colorize(colorizer, rgba, visuData, node); } /** * visu_data_colorizer_getScalingFactor: * @colorizer: a #VisuDataColorizer object. * @visuData: a #VisuData object. * @node: a #VisuNode structure. * * Calls the class scaling function of @colorizer to retrieve a * scaling factor for @node in @visuData. * * Since: 3.8 * * Returns: a scaling factor. **/ gfloat visu_data_colorizer_getScalingFactor(const VisuDataColorizer *colorizer, const VisuData *visuData, const VisuNode* node) { g_return_val_if_fail(VISU_IS_DATA_COLORIZER(colorizer), FALSE); if (!VISU_DATA_COLORIZER_GET_CLASS(colorizer)->scale) return 1.f; return VISU_DATA_COLORIZER_GET_CLASS(colorizer)->scale(colorizer, visuData, node); } static gboolean _emitDirty(VisuDataColorizer *colorizer) { g_signal_emit(colorizer, _signals[DIRTY_SIGNAL], 0); colorizer->priv->dirtyPending = 0; return FALSE; } /** * visu_data_colorizer_setDirty: * @colorizer: a #VisuDataColorizer object. * * Notifies when @colorizer colorising parameters have been changed. * * Since: 3.8 * * Returns: TRUE if dirty status is actually changed. **/ gboolean visu_data_colorizer_setDirty(VisuDataColorizer *colorizer) { g_return_val_if_fail(VISU_IS_DATA_COLORIZER(colorizer), FALSE); if (!colorizer->priv->active || colorizer->priv->dirtyPending) return FALSE; colorizer->priv->dirtyPending = g_idle_add((GSourceFunc)_emitDirty, colorizer); return TRUE; } /** * visu_data_colorizer_setActive: * @colorizer: a #VisuDataColorizer object. * @status: a boolean. * * Changes the active @status of @colorizer. * * Since: 3.8 * * Returns: TRUE if the status is actually changed. **/ gboolean visu_data_colorizer_setActive(VisuDataColorizer *colorizer, gboolean status) { g_return_val_if_fail(VISU_IS_DATA_COLORIZER(colorizer), FALSE); if (status == colorizer->priv->active) return FALSE; if (colorizer->priv->active) visu_data_colorizer_setDirty(colorizer); colorizer->priv->active = status; g_object_notify_by_pspec(G_OBJECT(colorizer), _properties[PROP_ACTIVE]); if (colorizer->priv->active) visu_data_colorizer_setDirty(colorizer); return TRUE; } /** * visu_data_colorizer_getActive: * @colorizer: a #VisuDataColorizer object. * * Retrieve if @colorizer is actively changing the #VisuNode colours. * * Since: 3.8 * * Returns: TRUE if @colorizer is active. **/ gboolean visu_data_colorizer_getActive(const VisuDataColorizer *colorizer) { g_return_val_if_fail(VISU_IS_DATA_COLORIZER(colorizer), FALSE); return colorizer->priv->active; } static VisuSourceableData** _getSource(VisuSourceable *self) { VisuDataColorizer *colorizer = VISU_DATA_COLORIZER(self); g_return_val_if_fail(VISU_IS_DATA_COLORIZER(self), (VisuSourceableData**)0); return &colorizer->priv->source; } static void _modelChanged(VisuSourceable *self) { visu_data_colorizer_setDirty(VISU_DATA_COLORIZER(self)); } v_sim-3.8.0/src/extraFunctions/colorizer.h000066400000000000000000000104371370110300500206160ustar00rootroot00000000000000/* EXTRAITS DE LA LICENCE Copyright CEA, contributeurs : Damien CALISTE, laboratoire L_Sim, (2017) Adresse mèl : CALISTE, damien P caliste AT cea P fr. Ce logiciel est un programme informatique servant à visualiser des structures atomiques dans un rendu pseudo-3D. Ce logiciel est régi par la licence CeCILL soumise au droit français et respectant les principes de diffusion des logiciels libres. Vous pouvez utiliser, modifier et/ou redistribuer ce programme sous les conditions de la licence CeCILL telle que diffusée par le CEA, le CNRS et l'INRIA sur le site "http://www.cecill.info". Le fait que vous puissiez accéder à cet en-tête signifie que vous avez pris connaissance de la licence CeCILL, et que vous en avez accepté les termes (cf. le fichier Documentation/licence.fr.txt fourni avec ce logiciel). */ /* LICENCE SUM UP Copyright CEA, contributors : Damien CALISTE, laboratoire L_Sim, (2017) E-mail address: CALISTE, damien P caliste AT cea P fr. This software is a computer program whose purpose is to visualize atomic configurations in 3D. This software is governed by the CeCILL license under French law and abiding by the rules of distribution of free software. You can use, modify and/ or redistribute the software under the terms of the CeCILL license as circulated by CEA, CNRS and INRIA at the following URL "http://www.cecill.info". The fact that you are presently reading this means that you have had knowledge of the CeCILL license and that you accept its terms. You can find a copy of this licence shipped with this software at Documentation/licence.en.txt. */ #ifndef DATA_COLORIZER_H #define DATA_COLORIZER_H #include #include #include #include "iface_sourceable.h" G_BEGIN_DECLS /* DataColorizer interface. */ #define VISU_TYPE_DATA_COLORIZER (visu_data_colorizer_get_type()) #define VISU_DATA_COLORIZER(obj) (G_TYPE_CHECK_INSTANCE_CAST((obj), VISU_TYPE_DATA_COLORIZER, VisuDataColorizer)) #define VISU_DATA_COLORIZER_CLASS(klass) (G_TYPE_CHECK_CLASS_CAST(klass, VISU_TYPE_DATA_COLORIZER, VisuDataColorizerClass)) #define VISU_IS_DATA_COLORIZER(obj) (G_TYPE_CHECK_INSTANCE_TYPE((obj), VISU_TYPE_DATA_COLORIZER)) #define VISU_IS_DATA_COLORIZER_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE(klass, VISU_TYPE_DATA_COLORIZER)) #define VISU_DATA_COLORIZER_GET_CLASS(obj) (G_TYPE_INSTANCE_GET_CLASS(obj, VISU_TYPE_DATA_COLORIZER, VisuDataColorizerClass)) typedef struct _VisuDataColorizerClass VisuDataColorizerClass; typedef struct _VisuDataColorizer VisuDataColorizer; typedef struct _VisuDataColorizerPrivate VisuDataColorizerPrivate; /** * visu_data_colorizer_get_type: * * This method returns the type of #VisuDataColorizer, use VISU_TYPE_DATA_COLORIZER instead. * * Returns: the type of #VisuDataColorizer. */ GType visu_data_colorizer_get_type(void); /** * VisuDataColorizer: * * Structure used to define #VisuDataColorizer objects. * * Since: 3.8 */ struct _VisuDataColorizer { VisuObject parent; VisuDataColorizerPrivate *priv; }; /** * VisuDataColorizerClass: * @parent: its parent. * @colorize: a method to colorize a given node according to a model. * @scale: a method to scale a given node according to a model. * * Interface for class that can represent #VisuDataColorizer. * * Since: 3.8 */ struct _VisuDataColorizerClass { VisuObjectClass parent; gboolean (*colorize)(const VisuDataColorizer *colorizer, float rgba[4], const VisuData *visuData, const VisuNode* node); gfloat (*scale)(const VisuDataColorizer *colorizer, const VisuData *visuData, const VisuNode* node); }; gboolean visu_data_colorizer_setActive(VisuDataColorizer *colorizer, gboolean status); gboolean visu_data_colorizer_getActive(const VisuDataColorizer *colorizer); gboolean visu_data_colorizer_setDirty(VisuDataColorizer *colorizer); gboolean visu_data_colorizer_getColor(const VisuDataColorizer *colorizer, float rgba[4], const VisuData *visuData, const VisuNode* node); gfloat visu_data_colorizer_getScalingFactor(const VisuDataColorizer *colorizer, const VisuData *visuData, const VisuNode* node); G_END_DECLS #endif v_sim-3.8.0/src/extraFunctions/coordProp.c000066400000000000000000000157271370110300500205570ustar00rootroot00000000000000/* EXTRAITS DE LA LICENCE Copyright CEA, contributeurs : Damien CALISTE, laboratoire L_Sim, (2016) Adresse mèl : CALISTE, damien P caliste AT cea P fr. Ce logiciel est un programme informatique servant à visualiser des structures atomiques dans un rendu pseudo-3D. Ce logiciel est régi par la licence CeCILL soumise au droit français et respectant les principes de diffusion des logiciels libres. Vous pouvez utiliser, modifier et/ou redistribuer ce programme sous les conditions de la licence CeCILL telle que diffusée par le CEA, le CNRS et l'INRIA sur le site "http://www.cecill.info". Le fait que vous puissiez accéder à cet en-tête signifie que vous avez pris connaissance de la licence CeCILL, et que vous en avez accepté les termes (cf. le fichier Documentation/licence.fr.txt fourni avec ce logiciel). */ /* LICENCE SUM UP Copyright CEA, contributors : Damien CALISTE, laboratoire L_Sim, (2016) E-mail address: CALISTE, damien P caliste AT cea P fr. This software is a computer program whose purpose is to visualize atomic configurations in 3D. This software is governed by the CeCILL license under French law and abiding by the rules of distribution of free software. You can use, modify and/ or redistribute the software under the terms of the CeCILL license as circulated by CEA, CNRS and INRIA at the following URL "http://www.cecill.info". The fact that you are presently reading this means that you have had knowledge of the CeCILL license and that you accept its terms. You can find a copy of this licence shipped with this software at Documentation/licence.en.txt. */ #include "coordProp.h" #include #include /** * SECTION:coordProp * @short_description: define a #VisuNodeValues object to access node coordinates. * * Defines a #VisuNodeValues object to be notified about * coordinate changes. */ static gboolean _getAt(const VisuNodeValues *vals, const VisuNode *node, GValue *value); static gboolean _setAt(VisuNodeValues *vals, const VisuNode *node, GValue *value); static gboolean _parse(VisuNodeValues *vals, VisuNode *node, const gchar *from); static gchar* _serialize(const VisuNodeValues *vals, const VisuNode *node); G_DEFINE_TYPE(VisuNodeValuesCoord, visu_node_values_coord, VISU_TYPE_NODE_VALUES_FARRAY) static void visu_node_values_coord_class_init(VisuNodeValuesCoordClass *klass) { /* Connect the overloading methods. */ VISU_NODE_VALUES_CLASS(klass)->getAt = _getAt; VISU_NODE_VALUES_CLASS(klass)->setAt = _setAt; VISU_NODE_VALUES_CLASS(klass)->parse = _parse; VISU_NODE_VALUES_CLASS(klass)->serialize = _serialize; } static void visu_node_values_coord_init(VisuNodeValuesCoord *self _U_) { } static gboolean _parse(VisuNodeValues *vals, VisuNode *node, const gchar *from) { gfloat fvals[3]; gchar **datas; guint i; GValue value = {0, {{0}, {0}}}; g_return_val_if_fail(from, FALSE); datas = g_strsplit_set(from, "(;)", 3); for (i = 0; datas[i]; i++) if (sscanf(from, "%f", fvals + i) != 1) { g_strfreev(datas); return FALSE; } g_strfreev(datas); g_value_init(&value, G_TYPE_POINTER); g_value_set_pointer(&value, fvals); return _setAt(vals, node, &value); } static gchar* _serialize(const VisuNodeValues *vals _U_, const VisuNode *node) { return g_strdup_printf("(%#.3g ; %#.3g ; %#.3g)", node->xyz[0], node->xyz[1], node->xyz[2]); } /** * visu_node_values_coord_new: * @dataObj: a #VisuData object. * * Create a #VisuNodeValues object to handle coordinates of nodes. * * Since: 3.8 * * Returns: (transfer full): a newly created #VisuNodeValuesCoord object. **/ VisuNodeValuesCoord* visu_node_values_coord_new(VisuData *dataObj) { VisuNodeValuesCoord *vals; vals = VISU_NODE_VALUES_COORD(g_object_new(VISU_TYPE_NODE_VALUES_COORD, "label", _("Coord. (x, y, z)"), "internal", TRUE, "nodes", dataObj, "type", G_TYPE_FLOAT, "n-elements", 3, NULL)); return vals; } static gfloat zeros[3] = {0.f, 0.f, 0.f}; /** * visu_node_values_coord_getAt: * @vect: a #VisuNodeValuesCoord object. * @node: a #VisuNode object. * * Retrieves the coord hosted on @node. * * Since: 3.8 * * Returns: (array fixed-size=3) (transfer none): the coordinates of * coord for @node. **/ const gfloat* visu_node_values_coord_getAt(const VisuNodeValuesCoord *vect, const VisuNode *node) { g_return_val_if_fail(VISU_IS_NODE_VALUES_COORD(vect), zeros); return node->xyz; } static gboolean _getAt(const VisuNodeValues *vals _U_, const VisuNode *node, GValue *value) { g_value_set_pointer(value, (gpointer)node->xyz); return TRUE; } static gboolean _setAt(VisuNodeValues *vect, const VisuNode *node, GValue *value) { VisuNodeArray *arr; gfloat *coords; gboolean res; VisuNode *n; arr = visu_node_values_getArray(vect); n = visu_node_array_getFromId(arr, node->number); g_object_unref(arr); g_return_val_if_fail(n, FALSE); coords = (gfloat*)g_value_get_pointer(value); if (n->xyz[0] == coords[0] && n->xyz[1] == coords[1] && n->xyz[2] == coords[2]) return FALSE; n->xyz[0] = coords[0]; n->xyz[1] = coords[1]; n->xyz[2] = coords[2]; /* Chain up to parent. */ res = VISU_NODE_VALUES_CLASS(visu_node_values_coord_parent_class)->setAt(vect, node, value); return res; } /** * visu_node_values_coord_setAt: * @vect: a #VisuNodeValuesCoord object. * @node: a #VisuNode object. * @xyz: (array fixed-size=3): coord coordinates. * * Changes the coord hosted at @node for one of coordinates defined * by @xyz. * * Since: 3.8 * * Returns: TRUE if coord for @node is indeed changed. **/ gboolean visu_node_values_coord_setAt(VisuNodeValuesCoord *vect, const VisuNode *node, const gfloat xyz[3]) { GValue value = {0, {{0}, {0}}}; g_value_init(&value, G_TYPE_POINTER); g_value_set_pointer(&value, (gpointer)xyz); return visu_node_values_setAt(VISU_NODE_VALUES(vect), node, &value); } /** * visu_node_values_coord_setAtDbl: * @vect: a #VisuNodeValuesCoord object. * @node: a #VisuNode object. * @dxyz: (array fixed-size=3): coord coordinates. * * Same as visu_node_values_coord_setAt() but for double values. * * Since: 3.8 * * Returns: TRUE if coord for @node is indeed changed. **/ gboolean visu_node_values_coord_setAtDbl(VisuNodeValuesCoord *vect, const VisuNode *node, const double dxyz[3]) { gfloat fxyz[3]; fxyz[0] = dxyz[0]; fxyz[1] = dxyz[1]; fxyz[2] = dxyz[2]; return visu_node_values_coord_setAt(vect, node, fxyz); } v_sim-3.8.0/src/extraFunctions/coordProp.h000066400000000000000000000110021370110300500205420ustar00rootroot00000000000000/* EXTRAITS DE LA LICENCE Copyright CEA, contributeurs : Damien CALISTE, laboratoire L_Sim, (2016) Adresse mèl : CALISTE, damien P caliste AT cea P fr. Ce logiciel est un programme informatique servant à visualiser des structures atomiques dans un rendu pseudo-3D. Ce logiciel est régi par la licence CeCILL soumise au droit français et respectant les principes de diffusion des logiciels libres. Vous pouvez utiliser, modifier et/ou redistribuer ce programme sous les conditions de la licence CeCILL telle que diffusée par le CEA, le CNRS et l'INRIA sur le site "http://www.cecill.info". Le fait que vous puissiez accéder à cet en-tête signifie que vous avez pris connaissance de la licence CeCILL, et que vous en avez accepté les termes (cf. le fichier Documentation/licence.fr.txt fourni avec ce logiciel). */ /* LICENCE SUM UP Copyright CEA, contributors : Damien CALISTE, laboratoire L_Sim, (2016) E-mail address: CALISTE, damien P caliste AT cea P fr. This software is a computer program whose purpose is to visualize atomic configurations in 3D. This software is governed by the CeCILL license under French law and abiding by the rules of distribution of free software. You can use, modify and/ or redistribute the software under the terms of the CeCILL license as circulated by CEA, CNRS and INRIA at the following URL "http://www.cecill.info". The fact that you are presently reading this means that you have had knowledge of the CeCILL license and that you accept its terms. You can find a copy of this licence shipped with this software at Documentation/licence.en.txt. */ #ifndef COORDPROP_H #define COORDPROP_H #include #include #include "floatProp.h" #include G_BEGIN_DECLS /** * VISU_TYPE_NODE_VALUES_COORD: * * return the type of #VisuNodeValuesCoord. */ #define VISU_TYPE_NODE_VALUES_COORD (visu_node_values_coord_get_type ()) /** * VISU_NODE_VALUES_COORD: * @obj: a #GObject to cast. * * Cast the given @obj into #VisuNodeValuesCoord type. */ #define VISU_NODE_VALUES_COORD(obj) (G_TYPE_CHECK_INSTANCE_CAST(obj, VISU_TYPE_NODE_VALUES_COORD, VisuNodeValuesCoord)) /** * VISU_NODE_VALUES_COORD_CLASS: * @klass: a #GObjectClass to cast. * * Cast the given @klass into #VisuNodeValuesCoordClass. */ #define VISU_NODE_VALUES_COORD_CLASS(klass) (G_TYPE_CHECK_CLASS_CAST(klass, VISU_TYPE_NODE_VALUES_COORD, VisuNodeValuesCoordClass)) /** * VISU_IS_NODE_VALUES_COORD: * @obj: a #GObject to test. * * Test if the given @ogj is of the type of #VisuNodeValuesCoord object. */ #define VISU_IS_NODE_VALUES_COORD(obj) (G_TYPE_CHECK_INSTANCE_TYPE(obj, VISU_TYPE_NODE_VALUES_COORD)) /** * VISU_IS_NODE_VALUES_COORD_CLASS: * @klass: a #GObjectClass to test. * * Test if the given @klass is of the type of #VisuNodeValuesCoordClass class. */ #define VISU_IS_NODE_VALUES_COORD_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE(klass, VISU_TYPE_NODE_VALUES_COORD)) /** * VISU_NODE_VALUES_COORD_GET_CLASS: * @obj: a #GObject to get the class of. * * It returns the class of the given @obj. */ #define VISU_NODE_VALUES_COORD_GET_CLASS(obj) (G_TYPE_INSTANCE_GET_CLASS(obj, VISU_TYPE_NODE_VALUES_COORD, VisuNodeValuesCoordClass)) /** * VisuNodeValuesCoord: * * Common name to refer to a #_VisuNodeValuesCoord. */ typedef struct _VisuNodeValuesCoord VisuNodeValuesCoord; struct _VisuNodeValuesCoord { VisuNodeValuesFarray parent; }; /** * VisuNodeValuesCoordClass: * @parent: private. * * Common name to refer to a #_VisuNodeValuesCoordClass. */ typedef struct _VisuNodeValuesCoordClass VisuNodeValuesCoordClass; struct _VisuNodeValuesCoordClass { VisuNodeValuesFarrayClass parent; }; /** * visu_node_values_coord_get_type: * * This method returns the type of #VisuNodeValuesCoord, use * VISU_TYPE_NODE_VALUES_COORD instead. * * Since: 3.8 * * Returns: the type of #VisuNodeValuesCoord. */ GType visu_node_values_coord_get_type(void); VisuNodeValuesCoord* visu_node_values_coord_new(VisuData *dataObj); const gfloat* visu_node_values_coord_getAt(const VisuNodeValuesCoord *vect, const VisuNode *node); gboolean visu_node_values_coord_setAt(VisuNodeValuesCoord *vect, const VisuNode *node, const gfloat xyz[3]); gboolean visu_node_values_coord_setAtDbl(VisuNodeValuesCoord *vect, const VisuNode *node, const double dxyz[3]); G_END_DECLS #endif v_sim-3.8.0/src/extraFunctions/dataFile.c000066400000000000000000001523001370110300500203060ustar00rootroot00000000000000/* EXTRAITS DE LA LICENCE Copyright CEA, contributeurs : Luc BILLARD et Damien CALISTE, laboratoire L_Sim, (2001-2005) Adresse mèl : BILLARD, non joignable par mèl ; CALISTE, damien P caliste AT cea P fr. Ce logiciel est un programme informatique servant à visualiser des structures atomiques dans un rendu pseudo-3D. Ce logiciel est régi par la licence CeCILL soumise au droit français et respectant les principes de diffusion des logiciels libres. Vous pouvez utiliser, modifier et/ou redistribuer ce programme sous les conditions de la licence CeCILL telle que diffusée par le CEA, le CNRS et l'INRIA sur le site "http://www.cecill.info". Le fait que vous puissiez accéder à cet en-tête signifie que vous avez pris connaissance de la licence CeCILL, et que vous en avez accepté les termes (cf. le fichier Documentation/licence.fr.txt fourni avec ce logiciel). */ /* LICENCE SUM UP Copyright CEA, contributors : Luc BILLARD et Damien CALISTE, laboratoire L_Sim, (2001-2005) E-mail address: BILLARD, not reachable any more ; CALISTE, damien P caliste AT cea P fr. This software is a computer program whose purpose is to visualize atomic configurations in 3D. This software is governed by the CeCILL license under French law and abiding by the rules of distribution of free software. You can use, modify and/ or redistribute the software under the terms of the CeCILL license as circulated by CEA, CNRS and INRIA at the following URL "http://www.cecill.info". The fact that you are presently reading this means that you have had knowledge of the CeCILL license and that you accept its terms. You can find a copy of this licence shipped with this software at Documentation/licence.en.txt. */ #include "dataFile.h" #include #include #include #include #include #include #include #include "visu_commandLine.h" /** * SECTION:dataFile * @short_description: Adds a possibility to colorize nodes depending * on data read in an input file. * * With this module, it is possible to colorize nodes depending * on data read in an input file. An input file can be associated to a * #VisuData object using visu_colorization_new(). Doing this, the * rendering is changed and nodes are colorized following a scheme * describe later. To turn off colorization without removing the data * file (for temporary turn off for instance), use * visu_data_colorizer_setActive(). * The input file must have the same numbers of uncommented * lines as there are nodes in the #VisuData associated with. If less * data is given, missing data are treaded as min values data. The * input data file can has as much column as desired. The colorization * is based on a linear color transformation. This transformation is * applied on color channel in RGB mode or in HSV mode. Resulting * color is given by : [resulting color vect] = [vectB] + [input * data][vectA], where [input data] are input data scaled to [0;1]. It * is possible to choose which column multiplies which color * channel. * It is implementing #VisuNodeMasker interface, thus allowing * to hide nodes depending on colorization values. */ struct _VisuColorizationPrivate { gboolean dispose_has_run; /* Storage for data. */ gulong file_sig; VisuBox *box; gulong sig_box; float boxSize[3]; VisuNodeValuesFarray *model; gulong sig_readMinMax, sig_nElements; GArray *manualMinMax; /* Min and max values for manual scale, for each column. */ /* Representation. */ int colUsed[3]; /* Columns to be used for each channel. */ int scaleUsed; /* Column to be used for radius scaling. */ VisuColorizationInputScaleId scaleType; /* Scheme to scale : manual or auto. */ gboolean applyToAll; /* Colourisation is applied only on values in range when FALSE. */ /* Hiding function and data. */ VisuNodeMaskerFunc maskerFunc; gpointer maskerData; GDestroyNotify maskerDestroy; }; enum { PROP_0, BOX_PROP, N_COLS_PROP, SINGLE_COL_PROP, SINGLE_MM_PROP, APPLY_ALL_PROP, FILE_PROP, NORM_PROP, COL_R_PROP, COL_G_PROP, COL_B_PROP, COL_SIZE_PROP, READ_MM_PROP, MANUAL_MM_PROP, N_PROP }; static GParamSpec *properties[N_PROP]; static void visu_colorization_dispose (GObject* obj); static void visu_colorization_finalize (GObject* obj); static void visu_colorization_get_property(GObject* obj, guint property_id, GValue *value, GParamSpec *pspec); static void visu_colorization_set_property(GObject* obj, guint property_id, const GValue *value, GParamSpec *pspec); static void visu_node_masker_interface_init(VisuNodeMaskerInterface *iface); static gboolean _setMaskFunc(VisuNodeMasker *self, VisuNodeMaskerFunc func, gpointer data, GDestroyNotify destroy); static gboolean _maskApply(const VisuNodeMasker *self, VisuNodeArray *array); /* Default values */ #define DATAFILE_SCALE_TYPE_DEFAULT VISU_COLORIZATION_NORMALIZE #define DATAFILE_MIN_NORM_DEFAULT 0. #define DATAFILE_MAX_NORM_DEFAULT +1. #define RESOURCE_RANGE_NAME "colorization_restrictInRange" #define RESOURCE_RANGE_DESC "Apply colourisation only if in range." /* Internal variables. */ static gboolean restrictInRange = FALSE; /* local methods. */ static void _setNodeModel(VisuColorization *dt, VisuNodeValues *model); static gboolean _toValues(const VisuDataColorizerShaded *self, gfloat values[3], const VisuData *visuData, const VisuNode* node); static gfloat _scale(const VisuDataColorizer *self, const VisuData *visuData, const VisuNode *node); static void exportResources(GString *data, VisuData *dataObj); static void onEntryRange(VisuConfigFile *obj, VisuConfigFileEntry *entry, gpointer data); static void onBoxSize(VisuColorization *dt, float extens, VisuBox *box); static void onReadMinMax(VisuColorization *dt); static void onNColumns(VisuColorization *dt); static void onModelNotified(VisuColorization *dt); static void onShadeNotified(VisuColorization *dt); G_DEFINE_TYPE_WITH_CODE(VisuColorization, visu_colorization, VISU_TYPE_DATA_COLORIZER_SHADED, G_ADD_PRIVATE(VisuColorization) G_IMPLEMENT_INTERFACE(VISU_TYPE_NODE_MASKER, visu_node_masker_interface_init)) static void visu_colorization_class_init(VisuColorizationClass *klass) { VisuConfigFileEntry *resourceEntry; resourceEntry = visu_config_file_addBooleanEntry(VISU_CONFIG_FILE_RESOURCE, RESOURCE_RANGE_NAME, RESOURCE_RANGE_DESC, &restrictInRange, FALSE); visu_config_file_entry_setVersion(resourceEntry, 3.7f); visu_config_file_addExportFunction(VISU_CONFIG_FILE_RESOURCE, exportResources); /* Connect the overloading methods. */ G_OBJECT_CLASS(klass)->dispose = visu_colorization_dispose; G_OBJECT_CLASS(klass)->finalize = visu_colorization_finalize; G_OBJECT_CLASS(klass)->set_property = visu_colorization_set_property; G_OBJECT_CLASS(klass)->get_property = visu_colorization_get_property; VISU_DATA_COLORIZER_CLASS(klass)->scale = _scale; VISU_DATA_COLORIZER_SHADED_CLASS(klass)->toValues = _toValues; /** * VisuColorization::box: * * The box from which the boundaries are used to colorize using the coordinates. * * Since: 3.8 */ properties[BOX_PROP] = g_param_spec_object("box", "Box", "box", VISU_TYPE_BOX, G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS); /** * VisuColorization::n-columns: * * Number of data stored per node. * * Since: 3.8 */ properties[N_COLS_PROP] = g_param_spec_uint("n-columns", "N columns", "number of columns", 0, G_MAXUINT, 0, G_PARAM_READABLE | G_PARAM_STATIC_STRINGS); /** * VisuColorization::single-param: * * If colorization data is based on the variation of a single * column. If it's not the case, this parameter is set to #VISU_COLORIZATION_UNSET. * * Since: 3.8 */ properties[SINGLE_COL_PROP] = g_param_spec_int("single-param", "Single parameter", "colorization data is single variable", VISU_COLORIZATION_UNSET, G_MAXINT, VISU_COLORIZATION_UNSET, G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS); /** * VisuColorization::single-range: * * If colorization data is based on the variation of a single * column, this stores its min and max values (either for automatic * normalisation or from manual settings). * * Since: 3.8 */ properties[SINGLE_MM_PROP] = g_param_spec_boxed("single-range", "Single range", "applied min and max values", TOOL_TYPE_MINMAX, G_PARAM_READABLE | G_PARAM_STATIC_STRINGS); /** * VisuColorization::apply-all: * * Colourization is applied to all nodes, or only to those in range. * * Since: 3.8 */ properties[APPLY_ALL_PROP] = g_param_spec_boolean("apply-all", "Apply all", "apply colorization on all nodes", !restrictInRange, G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS); /** * VisuColorization::source-file: * * Name of the source file the data come from. * * Since: 3.8 */ properties[FILE_PROP] = g_param_spec_string("source-file", "Source file", "Source file if any", (const gchar*)0, G_PARAM_READABLE | G_PARAM_STATIC_STRINGS); /** * VisuColorization::normalisation: * * Normalisation method for the input data. * * Since: 3.8 */ properties[NORM_PROP] = g_param_spec_uint("normalisation", "Normalisation", "input normalisation scheme", VISU_COLORIZATION_NORMALIZE, VISU_COLORIZATION_MINMAX, DATAFILE_SCALE_TYPE_DEFAULT, G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS); /** * VisuColorization::column-red: * * Column to be used to set the red channel values. * * Since: 3.8 */ properties[COL_R_PROP] = g_param_spec_int("column-red", "Column red value", "column the red channel is read from", VISU_COLORIZATION_UNSET, G_MAXINT, VISU_COLORIZATION_UNSET, G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS); /** * VisuColorization::column-green: * * Column to be used to set the green channel values. * * Since: 3.8 */ properties[COL_G_PROP] = g_param_spec_int("column-green", "Column green value", "column the green channel is read from", VISU_COLORIZATION_UNSET, G_MAXINT, VISU_COLORIZATION_UNSET, G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS); /** * VisuColorization::column-blue: * * Column to be used to set the green channel values. * * Since: 3.8 */ properties[COL_B_PROP] = g_param_spec_int("column-blue", "Column blue value", "column the blue channel is read from", VISU_COLORIZATION_UNSET, G_MAXINT, VISU_COLORIZATION_UNSET, G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS); /** * VisuColorization::column-size: * * Column to be used to set the node scaling factor. * * Since: 3.8 */ properties[COL_SIZE_PROP] = g_param_spec_int("column-size", "Column size value", "column the size factor is read from", VISU_COLORIZATION_UNSET, G_MAXINT, VISU_COLORIZATION_UNSET, G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS); /** * VisuColorization::data-min-max: * * Min / max values of the stored data. * * Since: 3.8 */ properties[READ_MM_PROP] = g_param_spec_boxed("data-min-max", "Data min/max", "min / max values of data", G_TYPE_ARRAY, G_PARAM_READABLE | G_PARAM_STATIC_STRINGS); /** * VisuColorization::range-min-max: * * Min / max range as used to normalise data. Default are the data * min / max themselves. * * Since: 3.8 */ properties[MANUAL_MM_PROP] = g_param_spec_boxed("range-min-max", "Range min/max", "min / max range to normalise data", G_TYPE_ARRAY, G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS); g_object_class_install_properties(G_OBJECT_CLASS(klass), N_PROP, properties); } static void visu_node_masker_interface_init(VisuNodeMaskerInterface *iface) { iface->set_mask_func = _setMaskFunc; iface->apply = _maskApply; } static void visu_colorization_init(VisuColorization *obj) { float init[2] = {DATAFILE_MIN_NORM_DEFAULT, G_MAXFLOAT}; DBG_fprintf(stderr, "Visu Colorization: initializing a new object (%p).\n", (gpointer)obj); obj->priv = visu_colorization_get_instance_private(obj); obj->priv->dispose_has_run = FALSE; obj->priv->box = (VisuBox*)0; obj->priv->manualMinMax = g_array_sized_new(FALSE, FALSE, sizeof(float) * 2, 3); g_array_insert_vals(obj->priv->manualMinMax, 0, init, 1); g_array_insert_vals(obj->priv->manualMinMax, 1, init, 1); g_array_insert_vals(obj->priv->manualMinMax, 2, init, 1); obj->priv->scaleType = DATAFILE_SCALE_TYPE_DEFAULT; obj->priv->colUsed[0] = VISU_COLORIZATION_UNSET; obj->priv->colUsed[1] = VISU_COLORIZATION_UNSET; obj->priv->colUsed[2] = VISU_COLORIZATION_UNSET; obj->priv->scaleUsed = VISU_COLORIZATION_UNSET; obj->priv->applyToAll = !restrictInRange; obj->priv->maskerFunc = (VisuNodeMaskerFunc)0; obj->priv->maskerData = 0; obj->priv->maskerDestroy = (GDestroyNotify)0; obj->priv->model = (VisuNodeValuesFarray*)0; g_signal_connect_object(VISU_CONFIG_FILE_RESOURCE, "parsed::" RESOURCE_RANGE_NAME, G_CALLBACK(onEntryRange), obj, G_CONNECT_AFTER); g_signal_connect(obj, "notify::model", G_CALLBACK(onModelNotified), (gpointer)0); g_signal_connect(obj, "notify::shade", G_CALLBACK(onShadeNotified), (gpointer)0); } /* This method can be called several times. It should unref all of its reference to GObjects. */ static void visu_colorization_dispose(GObject* obj) { VisuColorization *ext; DBG_fprintf(stderr, "Visu Colorization: dispose object %p.\n", (gpointer)obj); ext = VISU_COLORIZATION(obj); if (ext->priv->dispose_has_run) return; ext->priv->dispose_has_run = TRUE; g_object_freeze_notify(obj); visu_colorization_setBox(VISU_COLORIZATION(obj), (VisuBox*)0); _setNodeModel(VISU_COLORIZATION(obj), (VisuNodeValues*)0); if (ext->priv->maskerData && ext->priv->maskerDestroy) ext->priv->maskerDestroy(ext->priv->maskerData); /* Chain up to the parent class */ G_OBJECT_CLASS(visu_colorization_parent_class)->dispose(obj); } /* This method is called once only. */ static void visu_colorization_finalize(GObject* obj) { VisuColorizationPrivate *ext; g_return_if_fail(obj); DBG_fprintf(stderr, "Visu Colorization: finalize object %p.\n", (gpointer)obj); ext = VISU_COLORIZATION(obj)->priv; g_array_unref(ext->manualMinMax); /* Chain up to the parent class */ DBG_fprintf(stderr, "Visu Colorization: chain to parent.\n"); G_OBJECT_CLASS(visu_colorization_parent_class)->finalize(obj); DBG_fprintf(stderr, "Visu Colorization: freeing ... OK.\n"); } static void visu_colorization_get_property(GObject* obj, guint property_id, GValue *value, GParamSpec *pspec) { VisuColorizationPrivate *self = VISU_COLORIZATION(obj)->priv; VisuNodeValues *model; int id; float mm[2]; DBG_fprintf(stderr, "Visu Colorization: get property '%s' -> ", g_param_spec_get_name(pspec)); switch (property_id) { case BOX_PROP: g_value_set_object(value, self->box); DBG_fprintf(stderr, "%p.\n", (gpointer)self->box); break; case N_COLS_PROP: g_value_set_uint(value, visu_colorization_getNColumns(VISU_COLORIZATION(obj))); DBG_fprintf(stderr, "%d.\n", g_value_get_uint(value)); break; case SINGLE_COL_PROP: visu_colorization_getSingleColumnId(VISU_COLORIZATION(obj), &id); g_value_set_int(value, id); DBG_fprintf(stderr, "%d.\n", id); break; case SINGLE_MM_PROP: g_value_set_boxed(value, (gconstpointer)0); if (visu_colorization_getSingleColumnId(VISU_COLORIZATION(obj), &id)) { if (self->scaleType == VISU_COLORIZATION_NORMALIZE && id < 0) { mm[0] = 0.f; mm[1] = -1.f; if (id == VISU_COLORIZATION_FROM_X) mm[1] = self->boxSize[TOOL_XYZ_X]; else if (id == VISU_COLORIZATION_FROM_Y) mm[1] = self->boxSize[TOOL_XYZ_Y]; else if (id == VISU_COLORIZATION_FROM_Z) mm[1] = self->boxSize[TOOL_XYZ_Z]; g_value_set_boxed(value, mm); } else if (self->scaleType == VISU_COLORIZATION_NORMALIZE) { model = visu_sourceable_getNodeModel(VISU_SOURCEABLE(obj)); if (model) { visu_node_values_farray_getColumnMinMax(VISU_NODE_VALUES_FARRAY(model), mm, id); g_value_set_boxed(value, mm); } } else g_value_set_boxed(value, &g_array_index(self->manualMinMax, float, 2 * (id + 3))); } DBG_fprintf(stderr, "%d.\n", id); break; case APPLY_ALL_PROP: g_value_set_boolean(value, self->applyToAll); DBG_fprintf(stderr, "%d.\n", self->applyToAll); break; case FILE_PROP: model = visu_sourceable_getNodeModel(VISU_SOURCEABLE(obj)); if (model) g_object_get_property(G_OBJECT(model), "source-file", value); else g_value_set_static_string(value, (const gchar*)0); DBG_fprintf(stderr, "'%s'.\n", g_value_get_string(value)); break; case NORM_PROP: g_value_set_uint(value, self->scaleType); DBG_fprintf(stderr, "%d.\n", self->scaleType); break; case COL_R_PROP: g_value_set_int(value, self->colUsed[0]); DBG_fprintf(stderr, "%d.\n", self->colUsed[0]); break; case COL_G_PROP: g_value_set_int(value, self->colUsed[1]); DBG_fprintf(stderr, "%d.\n", self->colUsed[1]); break; case COL_B_PROP: g_value_set_int(value, self->colUsed[2]); DBG_fprintf(stderr, "%d.\n", self->colUsed[2]); break; case COL_SIZE_PROP: g_value_set_int(value, self->scaleUsed); DBG_fprintf(stderr, "%d.\n", self->scaleUsed); break; case READ_MM_PROP: model = visu_sourceable_getNodeModel(VISU_SOURCEABLE(obj)); if (VISU_IS_NODE_VALUES_FARRAY(model)) g_object_get_property(G_OBJECT(model), "data-min-max", value); else g_value_set_boxed(value, (gconstpointer)0); DBG_fprintf(stderr, "%p.\n", (gpointer)g_value_get_boxed(value)); break; case MANUAL_MM_PROP: g_value_set_boxed(value, self->manualMinMax); DBG_fprintf(stderr, "%p.\n", (gpointer)self->manualMinMax); break; default: /* We don't have any other property... */ G_OBJECT_WARN_INVALID_PROPERTY_ID(obj, property_id, pspec); break; } } static void visu_colorization_set_property(GObject* obj, guint property_id, const GValue *value, GParamSpec *pspec) { VisuColorization *self = VISU_COLORIZATION(obj); GArray *arr; const ToolShade *shade; int vals[3]; const float *vectA, *vectB; DBG_fprintf(stderr, "Visu Colorization: set property '%s' -> ", g_param_spec_get_name(pspec)); switch (property_id) { case BOX_PROP: DBG_fprintf(stderr, "%p.\n", g_value_get_object(value)); visu_colorization_setBox(self, VISU_BOX(g_value_get_object(value))); break; case APPLY_ALL_PROP: visu_colorization_setRestrictInRange(self, !g_value_get_boolean(value)); DBG_fprintf(stderr, "%d.\n", self->priv->applyToAll); break; case SINGLE_COL_PROP: DBG_fprintf(stderr, "%d.\n", g_value_get_int(value)); if (g_value_get_int(value) == VISU_COLORIZATION_UNSET) break; if (g_value_get_int(value) < visu_colorization_getNColumns(self)) vals[0] = vals[1] = vals[2] = g_value_get_int(value); else vals[0] = vals[1] = vals[2] = VISU_COLORIZATION_UNSET; shade = visu_data_colorizer_shaded_getShade(VISU_DATA_COLORIZER_SHADED(obj)); if (tool_shade_getMode(shade) == TOOL_SHADE_MODE_LINEAR) { tool_shade_getLinearCoeff(shade, &vectA, &vectB); vals[0] = (vectA[0] == 0.f && self->priv->colUsed[0] != VISU_COLORIZATION_UNSET) ? self->priv->colUsed[0] : vals[0]; vals[1] = (vectA[1] == 0.f && self->priv->colUsed[1] != VISU_COLORIZATION_UNSET) ? self->priv->colUsed[1] : vals[1]; vals[2] = (vectA[2] == 0.f && self->priv->colUsed[2] != VISU_COLORIZATION_UNSET) ? self->priv->colUsed[2] : vals[2]; } visu_colorization_setColUsedArr(self, vals); break; case NORM_PROP: visu_colorization_setScaleType(self, g_value_get_uint(value)); DBG_fprintf(stderr, "%d.\n", self->priv->scaleType); break; case COL_R_PROP: visu_colorization_setColUsed(self, g_value_get_int(value), 0); DBG_fprintf(stderr, "%d.\n", self->priv->colUsed[0]); break; case COL_G_PROP: visu_colorization_setColUsed(self, g_value_get_int(value), 1); DBG_fprintf(stderr, "%d.\n", self->priv->colUsed[1]); break; case COL_B_PROP: visu_colorization_setColUsed(self, g_value_get_int(value), 2); DBG_fprintf(stderr, "%d.\n", self->priv->colUsed[2]); break; case COL_SIZE_PROP: visu_colorization_setScalingUsed(self, g_value_get_int(value)); DBG_fprintf(stderr, "%d.\n", self->priv->scaleUsed); break; case MANUAL_MM_PROP: arr = (GArray*)g_value_dup_boxed(value); g_array_unref(self->priv->manualMinMax); self->priv->manualMinMax = arr; DBG_fprintf(stderr, "%p.\n", (gpointer)self->priv->manualMinMax); if (self->priv->scaleType == VISU_COLORIZATION_MINMAX) { g_object_notify_by_pspec(obj, properties[SINGLE_MM_PROP]); visu_data_colorizer_setDirty(VISU_DATA_COLORIZER(self)); } break; default: /* We don't have any other property... */ G_OBJECT_WARN_INVALID_PROPERTY_ID(obj, property_id, pspec); break; } } /** * visu_colorization_new: * * Create a new object to store colorisation data. * * Since: 3.7 * * Returns: (transfer full): a newly created #VisuColorization. **/ VisuColorization* visu_colorization_new() { VisuColorization *dataFile; DBG_fprintf(stderr, "Visu Colorization: creating new object.\n"); dataFile = VISU_COLORIZATION(g_object_new(VISU_TYPE_COLORIZATION, NULL)); return dataFile; } /** * visu_colorization_setBox: * @dt: a #VisuColorization object. * @box: (allow-none): a #VisuBox object. * * Change the associated @box for @dt. This box is used for the * coordinate colourisation. * * Since: 3.8 * * Returns: TRUE if value has been changed. **/ gboolean visu_colorization_setBox(VisuColorization *dt, VisuBox *box) { g_return_val_if_fail(VISU_IS_COLORIZATION(dt), FALSE); if (dt->priv->box == box) return FALSE; if (dt->priv->box) { g_signal_handler_disconnect(G_OBJECT(dt->priv->box), dt->priv->sig_box); g_object_unref(dt->priv->box); } if (box) { g_object_ref(box); dt->priv->sig_box = g_signal_connect_swapped(G_OBJECT(box), "SizeChanged", G_CALLBACK(onBoxSize), (gpointer)dt); onBoxSize(dt, 0.f, box); } dt->priv->box = box; return TRUE; } /** * visu_colorization_setNodeModel: * @dt: a #VisuColorization object. * @values: (allow-none): a #VisuNodeValuesFarray object. * * Change the #VisuNodeValuesFarray this @dt is associated to. * * Since: 3.8 **/ void visu_colorization_setNodeModel(VisuColorization *dt, VisuNodeValuesFarray *values) { visu_sourceable_setNodeModel(VISU_SOURCEABLE(dt), VISU_NODE_VALUES(values)); } static void _setNodeModel(VisuColorization *dt, VisuNodeValues *model) { guint i, nbColumns; float minmax[2]; g_return_if_fail(VISU_IS_NODE_VALUES_FARRAY(model) || !model); if (dt->priv->model) { g_signal_handler_disconnect(G_OBJECT(dt->priv->model), dt->priv->sig_readMinMax); g_signal_handler_disconnect(G_OBJECT(dt->priv->model), dt->priv->sig_nElements); g_object_unref(dt->priv->model); } dt->priv->model = VISU_NODE_VALUES_FARRAY(model); if (model) { g_object_ref(model); dt->priv->sig_readMinMax = g_signal_connect_swapped (G_OBJECT(model), "notify::data-min-max", G_CALLBACK(onReadMinMax), dt); dt->priv->sig_nElements = g_signal_connect_swapped (G_OBJECT(model), "notify::n-elements", G_CALLBACK(onNColumns), dt); } onReadMinMax(dt); onNColumns(dt); nbColumns = model ? visu_node_values_getDimension(model) : 0; /* Copy the read minMax into the manual minMax. */ for (i = dt->priv->manualMinMax->len - 3; i < nbColumns; i++) { visu_node_values_farray_getColumnMinMax(VISU_NODE_VALUES_FARRAY(model), minmax, i); g_array_append_vals(dt->priv->manualMinMax, minmax, 1); } g_array_set_size(dt->priv->manualMinMax, nbColumns + 3); g_object_notify_by_pspec(G_OBJECT(dt), properties[MANUAL_MM_PROP]); /* Select a default column if not any already. */ if (dt->priv->colUsed[0] == VISU_COLORIZATION_UNSET && dt->priv->colUsed[1] == VISU_COLORIZATION_UNSET && dt->priv->colUsed[2] == VISU_COLORIZATION_UNSET && nbColumns) g_object_set(dt, "single-param", 0, NULL); g_object_notify_by_pspec(G_OBJECT(dt), properties[SINGLE_MM_PROP]); } static void onModelNotified(VisuColorization *dt) { VisuNodeValues *values; g_object_get(dt, "model", &values, NULL); _setNodeModel(dt, values); if (values) g_object_unref(values); g_object_notify_by_pspec(G_OBJECT(dt), properties[FILE_PROP]); } /** * visu_colorization_getFile: * @dt: (allow-none): a #VisuColorization object. * * If the given @dt has an input data file already loaded, it returns its name. * * Returns: the name of the input data file if set. */ const gchar* visu_colorization_getFile(const VisuColorization *dt) { if (dt && visu_sourceable_getNodeModel(VISU_SOURCEABLE(dt))) return visu_node_values_farray_getFile(VISU_NODE_VALUES_FARRAY(visu_sourceable_getNodeModel(VISU_SOURCEABLE(dt)))); else return (const gchar*)0; } /** * visu_colorization_setRestrictInRange: * @dt: a #VisuColorization object with some data file information. * @status: a boolean. * * The colourisation can be applied on all nodes or on nodes within * range. See visu_colorization_getRestrictInRange() and * visu_colorization_setMin() and visu_colorization_setMax(). * * Since: 3.7 * * Returns: TRUE if the status is changed indeed. */ gboolean visu_colorization_setRestrictInRange(VisuColorization *dt, gboolean status) { g_return_val_if_fail(VISU_IS_COLORIZATION(dt), FALSE); if (dt->priv->applyToAll != status) return FALSE; dt->priv->applyToAll = !status; g_object_notify_by_pspec(G_OBJECT(dt), properties[APPLY_ALL_PROP]); visu_data_colorizer_setDirty(VISU_DATA_COLORIZER(dt)); return TRUE; } /** * visu_colorization_getRestrictInRange: * @dt: a #VisuColorization object with some data file information. * * The colourisation can be applied on all nodes or on nodes within * range. See visu_colorization_setRestrictInRange(). * * Since: 3.7 * * Returns: TRUE if colourisation is done only if values are in range. */ gboolean visu_colorization_getRestrictInRange(const VisuColorization *dt) { g_return_val_if_fail(VISU_IS_COLORIZATION(dt), TRUE); return !dt->priv->applyToAll; } /** * visu_colorization_setScaleType: * @dt: a #VisuColorization object ; * @scale: an integer. * * This method is used to change the scale method used on input data. * See #VisuColorizationInputScaleId for further informations. This method raises * a error if no input file has already been associated to the give @visuData. * * Returns: TRUE if VisuNodeArray::RenderingChanged should be emitted. */ gboolean visu_colorization_setScaleType(VisuColorization *dt, VisuColorizationInputScaleId scale) { g_return_val_if_fail(VISU_IS_COLORIZATION(dt), FALSE); DBG_fprintf(stderr, "Visu Colorization: set the scale type to %d (previuosly %d).\n", scale, dt->priv->scaleType); if (scale == dt->priv->scaleType) return FALSE; dt->priv->scaleType = scale; g_object_notify_by_pspec(G_OBJECT(dt), properties[NORM_PROP]); g_object_notify_by_pspec(G_OBJECT(dt), properties[SINGLE_MM_PROP]); visu_data_colorizer_setDirty(VISU_DATA_COLORIZER(dt)); return TRUE; } /** * visu_colorization_getScaleType: * @dt: (allow-none): a #VisuColorization object. * * Retrieve the scaling method of input data associated to the given @dt. * * Returns: the scaling method if @dt is not NULL * or the default value if not. */ VisuColorizationInputScaleId visu_colorization_getScaleType(const VisuColorization *dt) { if (!dt || !VISU_IS_COLORIZATION(dt)) return DATAFILE_SCALE_TYPE_DEFAULT; else return dt->priv->scaleType; } static gboolean _setManualMinMax(VisuColorization *dt, float val, int column, guint minmax) { float *minMax; g_return_val_if_fail(VISU_IS_COLORIZATION(dt), FALSE); g_return_val_if_fail(column >= VISU_COLORIZATION_FROM_X && (guint)(column + 3) < dt->priv->manualMinMax->len, FALSE); minMax = &g_array_index(dt->priv->manualMinMax, float, 2 * (column + 3)); DBG_fprintf(stderr, "Visu Colorization: set the min/max (%d) value" " of column %d to %f (previuosly %f).\n", minmax, column, val, minMax[minmax]); if (minMax[minmax] == val) return FALSE; minMax[minmax] = val; g_object_notify_by_pspec(G_OBJECT(dt), properties[MANUAL_MM_PROP]); if (dt->priv->scaleType == VISU_COLORIZATION_MINMAX) g_object_notify_by_pspec(G_OBJECT(dt), properties[SINGLE_MM_PROP]); if (dt->priv->scaleType == VISU_COLORIZATION_MINMAX) visu_data_colorizer_setDirty(VISU_DATA_COLORIZER(dt)); return TRUE; } /** * visu_colorization_setMin: * @dt: a #VisuColorization object ; * @min: a floating point value. * @column: a column id. * * When the scaling method is #VISU_COLORIZATION_MINMAX (see #VisuColorizationInputScaleId) * min and max value for convert input data are user defined. Use this method * to choose the minimum bound. This method raises * a error if no input file has already been associated to the give @visuData. * * Returns: TRUE if VisuNodeArray::RenderingChanged should be emitted. */ gboolean visu_colorization_setMin(VisuColorization *dt, float min, int column) { return _setManualMinMax(dt, min, column, 0); } /** * visu_colorization_setMax: * @dt: a #VisuColorization object ; * @max: a floating point value. * @column: a column id. * * When the scaling method is #VISU_COLORIZATION_MINMAX (see #VisuColorizationInputScaleId) * min and max value for convert input data are user defined. Use this method * to choose the maximum bound. This method raises * a error if no input file has already been associated to the give @visuData. * * Returns: TRUE if VisuNodeArray::RenderingChanged should be emitted. **/ gboolean visu_colorization_setMax(VisuColorization *dt, float max, int column) { return _setManualMinMax(dt, max, column, 1); } static float _getManualMinMax(const VisuColorization *dt, int column, int minmax) { float *minMax; if (!dt || !VISU_IS_COLORIZATION(dt)) return (minmax == 0)?DATAFILE_MIN_NORM_DEFAULT:DATAFILE_MAX_NORM_DEFAULT; g_return_val_if_fail((guint)(column + 3) < dt->priv->manualMinMax->len, 0.f); minMax = &g_array_index(dt->priv->manualMinMax, float, 2 * (column + 3)); return minMax[minmax]; } /** * visu_colorization_getMin: * @dt: (allow-none): a #VisuData object. * @column: a column id. * * Retrieve the minimum value used when scaling is user defined. * * Returns: the minimum bound if @dt is not NULL * or the default value if not. */ float visu_colorization_getMin(const VisuColorization *dt, int column) { return _getManualMinMax(dt, column, 0); } /** * visu_colorization_getMax: * @dt: (allow-none): a #VisuData object. * @column: a column id. * * Retrieve the maximum value used when scaling is user defined. * * Returns: the maximum bound if @dt is not NULL * or the default value if not. */ float visu_colorization_getMax(const VisuColorization *dt, int column) { return _getManualMinMax(dt, column, 1); } /** * visu_colorization_getNColumns: * @dt: a #VisuColorization object. * * This method is used to retrieve the number of columns of data read in * the loaded file. * * Returns: this number of columns, or -1 if none. */ int visu_colorization_getNColumns(const VisuColorization *dt) { VisuNodeValues *model; if (!dt || !VISU_IS_COLORIZATION(dt)) return -1; model = visu_sourceable_getNodeModel(VISU_SOURCEABLE(dt)); if (!model) return 0; else return visu_node_values_getDimension(model); } /** * visu_colorization_getSingleColumnId: * @dt: (allow-none): a #VisuColorization object. * @id: (out): a location to store a column id. * * The colourisation can be applied from values coming from several * columns. But, if only one column is used, this routine will give it * in @id. * * Returns: FALSE if several columns are used, or TRUE if a single * column is used for the colourisation. */ gboolean visu_colorization_getSingleColumnId(const VisuColorization *dt, gint *id) { const ToolShade *shade; const float *vectA, *vectB; gint col; if (!dt || !VISU_IS_COLORIZATION(dt)) return FALSE; shade = visu_data_colorizer_shaded_getShade(VISU_DATA_COLORIZER_SHADED(dt)); if (shade && tool_shade_getMode(shade) == TOOL_SHADE_MODE_LINEAR) tool_shade_getLinearCoeff(shade, &vectA, &vectB); else vectA = (float*)0; col = VISU_COLORIZATION_UNSET; if ((dt->priv->colUsed[0] == VISU_COLORIZATION_UNSET || dt->priv->colUsed[1] == VISU_COLORIZATION_UNSET || dt->priv->colUsed[0] == dt->priv->colUsed[1] || (vectA && (vectA[0] == 0.f || vectA[1] == 0.f))) && (dt->priv->colUsed[1] == VISU_COLORIZATION_UNSET || dt->priv->colUsed[2] == VISU_COLORIZATION_UNSET || dt->priv->colUsed[1] == dt->priv->colUsed[2] || (vectA && (vectA[1] == 0.f || vectA[2] == 0.f))) && (dt->priv->colUsed[2] == VISU_COLORIZATION_UNSET || dt->priv->colUsed[0] == VISU_COLORIZATION_UNSET || dt->priv->colUsed[2] == dt->priv->colUsed[0] || (vectA && (vectA[0] == 0.f || vectA[2] == 0.f)))) { if (dt->priv->colUsed[0] != VISU_COLORIZATION_UNSET && (!vectA || vectA[0] != 0.f)) col = dt->priv->colUsed[0]; else if (dt->priv->colUsed[1] != VISU_COLORIZATION_UNSET && (!vectA || vectA[1] != 0.f)) col = dt->priv->colUsed[1]; else col = dt->priv->colUsed[2]; } if (id) *id = col; DBG_fprintf(stderr, "Visu Colorization: retrieve single column %d.\n", col); return (col != VISU_COLORIZATION_UNSET); } static gboolean _setCol(VisuColorization *dt, int val, int pos) { DBG_fprintf(stderr, "Visu Colorization: channel %d uses column %d (previuosly %d).\n", pos, val, dt->priv->colUsed[pos]); g_return_val_if_fail(val < (int)visu_colorization_getNColumns(dt) && val >= VISU_COLORIZATION_UNSET, FALSE); if (dt->priv->colUsed[pos] == val) return FALSE; dt->priv->colUsed[pos] = val; return TRUE; } /** * visu_colorization_setColUsedArr: * @dt: a #VisuColorization object. * @vals: (array fixed-size=3): the new columns to be used per * channel. * * Setup all three channels at once, see visu_colorization_setColUsed(). * * Since: 3.8 * * Returns: TRUE if any changes. **/ gboolean visu_colorization_setColUsedArr(VisuColorization *dt, const int vals[3]) { gboolean changed; g_return_val_if_fail(VISU_IS_COLORIZATION(dt), FALSE); changed = FALSE; if (_setCol(dt, vals[0], 0)) { changed = TRUE; g_object_notify_by_pspec(G_OBJECT(dt), properties[COL_R_PROP]); } if (_setCol(dt, vals[1], 1)) { changed = TRUE; g_object_notify_by_pspec(G_OBJECT(dt), properties[COL_G_PROP]); } if (_setCol(dt, vals[2], 2)) { changed = TRUE; g_object_notify_by_pspec(G_OBJECT(dt), properties[COL_B_PROP]); } if (!changed) return FALSE; g_object_notify_by_pspec(G_OBJECT(dt), properties[SINGLE_COL_PROP]); g_object_notify_by_pspec(G_OBJECT(dt), properties[SINGLE_MM_PROP]); visu_data_colorizer_setDirty(VISU_DATA_COLORIZER(dt)); return TRUE; } /** * visu_colorization_setColUsed: * @dt: a #VisuColorization object ; * @val: a column id a special value ; * @pos: an integer in [0;2]. * * Choose if the loaded value should change the given channel of the colour. * * Returns: TRUE if VisuNodeArray::RenderingChanged should be emitted. */ gboolean visu_colorization_setColUsed(VisuColorization *dt, int val, int pos) { g_return_val_if_fail(pos >= 0 && pos < 3, FALSE); g_return_val_if_fail(VISU_IS_COLORIZATION(dt), FALSE); if (!_setCol(dt, val, pos)) return FALSE; g_object_notify_by_pspec(G_OBJECT(dt), properties[COL_R_PROP + pos]); g_object_notify_by_pspec(G_OBJECT(dt), properties[SINGLE_COL_PROP]); g_object_notify_by_pspec(G_OBJECT(dt), properties[SINGLE_MM_PROP]); visu_data_colorizer_setDirty(VISU_DATA_COLORIZER(dt)); return TRUE; } /** * visu_colorization_getColUsed: * @dt: (allow-none): a #VisuData object. * * This method is used to retrieve the vector used to adapt or not the colour * to the value of the loaded data. * * Returns: (transfer none) (array fixed-size=3): a three value array, * own by V_Sim. It should not be freed. */ const int* visu_colorization_getColUsed(const VisuColorization *dt) { if (!dt || !VISU_IS_COLORIZATION(dt)) return (const int*)0; else return dt->priv->colUsed; } /** * visu_colorization_setScalingUsed: * @dt: a #VisuColorization object hosting the data values ; * @val: a column id. * * Give the column id to used to take the scaling values from. Set -1 * if no scaling used. The scaling is used to change the size of each * node, using an homothetic factor. * * Returns: TRUE if the status changed. */ gboolean visu_colorization_setScalingUsed(VisuColorization *dt, int val) { g_return_val_if_fail(VISU_IS_COLORIZATION(dt), FALSE); DBG_fprintf(stderr, "Visu Colorization: scaling uses column %d (previuosly %d).\n", val, dt->priv->scaleUsed); g_return_val_if_fail((val < (int)visu_colorization_getNColumns(dt) && val >= 0) || val == VISU_COLORIZATION_UNSET, FALSE); if (dt->priv->scaleUsed == val) return FALSE; dt->priv->scaleUsed = val; g_object_notify_by_pspec(G_OBJECT(dt), properties[COL_SIZE_PROP]); visu_data_colorizer_setDirty(VISU_DATA_COLORIZER(dt)); return TRUE; } /** * visu_colorization_getScalingUsed: * @dt: (allow-none): a #VisuColorization object hosting the data values. * * Retrieve if a column is used as entry to scale the nodes. * * Returns: -1 if no scaling is used. */ int visu_colorization_getScalingUsed(const VisuColorization *dt) { if (!dt || !VISU_IS_COLORIZATION(dt)) return VISU_COLORIZATION_UNSET; else return dt->priv->scaleUsed; } static void onShadeNotified(VisuColorization *dt) { g_object_notify_by_pspec(G_OBJECT(dt), properties[SINGLE_COL_PROP]); g_object_notify_by_pspec(G_OBJECT(dt), properties[SINGLE_MM_PROP]); } static gboolean _setMaskFunc(VisuNodeMasker *self, VisuNodeMaskerFunc func, gpointer data, GDestroyNotify destroy) { VisuColorization *dt; g_return_val_if_fail(VISU_IS_COLORIZATION(self), FALSE); dt = VISU_COLORIZATION(self); /* Free previous association. */ if (dt->priv->maskerData && dt->priv->maskerDestroy) dt->priv->maskerDestroy(dt->priv->maskerData); DBG_fprintf(stderr, "Visu Colorization: set masker function with data %p.\n", data); dt->priv->maskerFunc = func; dt->priv->maskerData = data; dt->priv->maskerDestroy = destroy; return TRUE; } static gboolean _maskApply(const VisuNodeMasker *self, VisuNodeArray *array) { VisuColorization *dt; gboolean redraw; VisuNodeValuesIter iter; VisuNodeValues *model; g_return_val_if_fail(VISU_IS_COLORIZATION(self), FALSE); dt = VISU_COLORIZATION(self); model = visu_sourceable_getNodeModel(VISU_SOURCEABLE(self)); if (!visu_data_colorizer_getActive(VISU_DATA_COLORIZER(self)) || !model || dt->priv->maskerFunc == (VisuNodeMaskerFunc)0) return FALSE; g_return_val_if_fail(visu_node_values_fromArray(model, array), FALSE); redraw = FALSE; for (visu_node_values_iter_new(&iter, ITER_NODES_VISIBLE, model); iter.iter.node; visu_node_values_iter_next(&iter)) { if (dt->priv->maskerFunc(self, &iter, dt->priv->maskerData)) redraw = visu_node_setVisibility(iter.iter.node, FALSE) || redraw; } return redraw; } static void onBoxSize(VisuColorization *dt, float extens _U_, VisuBox *box) { float top[3] = {1.f, 1.f, 1.f}; visu_box_convertBoxCoordinatestoXYZ(box, dt->priv->boxSize, top); if (g_array_index(dt->priv->manualMinMax, float, 1) == G_MAXFLOAT) g_array_index(dt->priv->manualMinMax, float, 1) = dt->priv->boxSize[TOOL_XYZ_X]; if (g_array_index(dt->priv->manualMinMax, float, 3) == G_MAXFLOAT) g_array_index(dt->priv->manualMinMax, float, 3) = dt->priv->boxSize[TOOL_XYZ_Y]; if (g_array_index(dt->priv->manualMinMax, float, 5) == G_MAXFLOAT) g_array_index(dt->priv->manualMinMax, float, 5) = dt->priv->boxSize[TOOL_XYZ_Z]; } static void onReadMinMax(VisuColorization *dt) { g_object_notify_by_pspec(G_OBJECT(dt), properties[READ_MM_PROP]); if (dt->priv->scaleType == VISU_COLORIZATION_NORMALIZE) g_object_notify_by_pspec(G_OBJECT(dt), properties[SINGLE_MM_PROP]); } static void onNColumns(VisuColorization *dt) { guint nbColumns; nbColumns = visu_colorization_getNColumns(dt); g_object_notify_by_pspec(G_OBJECT(dt), properties[N_COLS_PROP]); if (dt->priv->colUsed[0] >= (int)nbColumns) { dt->priv->colUsed[0] = (nbColumns) ? 0 : VISU_COLORIZATION_UNSET; g_object_notify_by_pspec(G_OBJECT(dt), properties[COL_R_PROP]); } if (dt->priv->colUsed[1] >= (int)nbColumns) { dt->priv->colUsed[1] = (nbColumns) ? 0 : VISU_COLORIZATION_UNSET; g_object_notify_by_pspec(G_OBJECT(dt), properties[COL_G_PROP]); } if (dt->priv->colUsed[2] >= (int)nbColumns) { dt->priv->colUsed[2] = (nbColumns) ? 0 : VISU_COLORIZATION_UNSET; g_object_notify_by_pspec(G_OBJECT(dt), properties[COL_B_PROP]); } if (dt->priv->scaleUsed >= (int)nbColumns) { dt->priv->scaleUsed = (nbColumns) ? 0 : VISU_COLORIZATION_UNSET; g_object_notify_by_pspec(G_OBJECT(dt), properties[COL_SIZE_PROP]); } } /*******************/ /* Drawing methods */ /*******************/ /* Normalization methods */ static float valuesFromData(const VisuColorization *dt, guint column, const float *vals, gboolean *out) { float res, minmax[2], *manual; VisuNodeValues *model; g_return_val_if_fail(vals, 0.f); switch (dt->priv->scaleType) { case VISU_COLORIZATION_NORMALIZE: model = visu_sourceable_getNodeModel(VISU_SOURCEABLE(dt)); visu_node_values_farray_getColumnMinMax(VISU_NODE_VALUES_FARRAY(model), minmax, column); break; case VISU_COLORIZATION_MINMAX: manual = &g_array_index(dt->priv->manualMinMax, float, 2 * (column + 3)); minmax[0] = manual[0]; minmax[1] = manual[1]; break; default: minmax[0] = minmax[1] = 0.f; } res = ( (vals[column] - minmax[0]) / (minmax[1] - minmax[0]) ); DBG_fprintf(stderr, "Visu VisuColorization: normalise %f -> %f.\n", vals[column], res); if (out) *out = (res < 0. || res > 1.); return CLAMP(res, 0., 1.); } static float valuesFromCoord(VisuColorizationPrivate *dt, guint dir, const float xred[3], gboolean *out) { float res = 0.f, *minmax; switch (dt->scaleType) { case VISU_COLORIZATION_NORMALIZE: res = xred[dir]; break; case VISU_COLORIZATION_MINMAX: minmax = &g_array_index(dt->manualMinMax, float, 2 * dir); res = ( (xred[dir] * dt->boxSize[dir] - minmax[0]) / (minmax[1] - minmax[0]) ); break; } DBG_fprintf(stderr, "Visu VisuColorization: normalise %f -> %f.\n", xred[dir] * dt->boxSize[dir], res); if (out) *out = (res < 0. || res > 1.); return CLAMP(res, 0., 1.); } /*******************/ /* Color functions */ /*******************/ static gboolean _toValues(const VisuDataColorizerShaded *self, gfloat values[3], const VisuData *visuData, const VisuNode* node) { float red[3], coord[3]; int i; const float *storedValues; gboolean useCoord, useData, status, out; VisuColorization *dt = VISU_COLORIZATION(self); const VisuNodeValues* model; g_return_val_if_fail(VISU_IS_COLORIZATION(dt), FALSE); g_return_val_if_fail(visuData && node, FALSE); useCoord = (dt->priv->colUsed[0] == VISU_COLORIZATION_FROM_X || dt->priv->colUsed[0] == VISU_COLORIZATION_FROM_Y || dt->priv->colUsed[0] == VISU_COLORIZATION_FROM_Z || dt->priv->colUsed[1] == VISU_COLORIZATION_FROM_X || dt->priv->colUsed[1] == VISU_COLORIZATION_FROM_Y || dt->priv->colUsed[1] == VISU_COLORIZATION_FROM_Z || dt->priv->colUsed[2] == VISU_COLORIZATION_FROM_X || dt->priv->colUsed[2] == VISU_COLORIZATION_FROM_Y || dt->priv->colUsed[2] == VISU_COLORIZATION_FROM_Z); useData = (dt->priv->colUsed[0] >= 0 || dt->priv->colUsed[1] >= 0 || dt->priv->colUsed[2] >= 0); storedValues = (const float*)0; if (useData) { model = visu_sourceable_getConstNodeModel(VISU_SOURCEABLE(self)); if (!model) return FALSE; storedValues = visu_node_values_farray_getAt(VISU_NODE_VALUES_FARRAY(model), node); if (!storedValues) return FALSE; } if (useCoord) { visu_data_getNodePosition(visuData, node, coord); visu_box_convertXYZtoBoxCoordinates(dt->priv->box, red, coord); } status = TRUE; for (i = 0; i < 3; i++) { out = FALSE; if (dt->priv->colUsed[i] == VISU_COLORIZATION_UNSET) values[i] = 1.; else if (dt->priv->colUsed[i] == VISU_COLORIZATION_FROM_X) values[i] = valuesFromCoord(dt->priv, TOOL_XYZ_X, red, &out); else if (dt->priv->colUsed[i] == VISU_COLORIZATION_FROM_Y) values[i] = valuesFromCoord(dt->priv, TOOL_XYZ_Y, red, &out); else if (dt->priv->colUsed[i] == VISU_COLORIZATION_FROM_Z) values[i] = valuesFromCoord(dt->priv, TOOL_XYZ_Z, red, &out); else values[i] = valuesFromData(dt, dt->priv->colUsed[i], storedValues, &out); status = status && !out; } return dt->priv->applyToAll || status; } static gfloat _scale(const VisuDataColorizer *colorizer, const VisuData *visuData _U_, const VisuNode *node) { const float *storedValues; VisuColorization *dt = VISU_COLORIZATION(colorizer); const VisuNodeValues *model; if (dt->priv->scaleUsed == VISU_COLORIZATION_UNSET) return 1.f; model = visu_sourceable_getConstNodeModel(VISU_SOURCEABLE(colorizer)); if (!model) return 1.f; storedValues = visu_node_values_farray_getAt(VISU_NODE_VALUES_FARRAY(model), node); return storedValues ? valuesFromData(dt, dt->priv->scaleUsed, storedValues, (gboolean*)0) : 1.f; } static void exportResources(GString *data, VisuData *dataObj _U_) { visu_config_file_exportComment(data, RESOURCE_RANGE_DESC); visu_config_file_exportEntry(data, RESOURCE_RANGE_NAME, NULL, "%d", restrictInRange); visu_config_file_exportComment(data, ""); } static void onEntryRange(VisuConfigFile *obj _U_, VisuConfigFileEntry *entry _U_, gpointer data) { VisuColorization *dt = (VisuColorization*)data; dt->priv->applyToAll = !restrictInRange; } /** * visu_colorization_new_fromCLI: * @dataObj: a #VisuData object. * @error: (allow-none): an error location. * * Use all command line options related to colorization to create a * new colorization object, storing its values in @dataObj. * * Since: 3.8 * * Returns: (transfer full): a newly created #VisuColorization object. **/ VisuColorization* visu_colorization_new_fromCLI(VisuData *dataObj, GError **error) { VisuColorization *dt; const gchar *colorFile; int *colUsed; guint i; ToolShade *shade; gboolean somethingIsLoaded, isFile; VisuNodeValues *vals; GArray *minMax; VisuColorRange *rg; dt = (VisuColorization*)0; colorFile = commandLineGet_colorizeSource(&isFile); colUsed = commandLineGet_colorizeColUsed(); if (!colorFile && !colUsed) return dt; DBG_fprintf(stderr, "Visu basic : loading a new data file '%s'.\n", colorFile); if (colorFile && isFile) { VisuNodeValuesFarray *values; GError *error_; error_ = (GError*)0; values = visu_node_values_farray_new_fromFile(VISU_NODE_ARRAY(dataObj), VISU_COLORIZATION_LABEL, colorFile, &error_); if (!error_) { visu_data_removeNodeProperties (dataObj, visu_node_values_getLabel(VISU_NODE_VALUES(values))); visu_data_addNodeProperties(dataObj, VISU_NODE_VALUES(values)); dt = visu_colorization_new(); visu_sourceable_setSource(VISU_SOURCEABLE(dt), VISU_COLORIZATION_LABEL); visu_colorization_setNodeModel(dt, values); } else { g_propagate_error(error, error_); g_object_unref(values); } } else if (colorFile) { vals = visu_data_getNodeProperties(dataObj, colorFile); if (!vals) g_set_error(error, VISU_COMMAND_LINE_ERROR, ERROR_ARGUMENT, _("Colorization from a non existing node property '%s'."), colorFile); else if (!VISU_IS_NODE_VALUES_FARRAY(vals)) g_set_error_literal(error, VISU_COMMAND_LINE_ERROR, ERROR_ARGUMENT, _("Colorization from a node property that is not" " a float array.")); else { dt = visu_colorization_new(); visu_sourceable_setSource(VISU_SOURCEABLE(dt), colorFile); visu_colorization_setNodeModel(dt, VISU_NODE_VALUES_FARRAY(vals)); } } else { somethingIsLoaded = FALSE; for (i = 0; i < 3; i++) { somethingIsLoaded = somethingIsLoaded || (colUsed[i] <= 0); if (colUsed[i] > 0) g_set_error(error, VISU_COMMAND_LINE_ERROR, ERROR_ARGUMENT, _("Assign a column data without specifying a data file." " Use -c option or change the value %d."), colUsed[i]); } if (somethingIsLoaded) { dt = visu_colorization_new(); visu_colorization_setBox(dt, visu_boxed_getBox(VISU_BOXED(dataObj))); } } if (dt) { minMax = commandLineGet_colorMinMax(); if (minMax->len > 0) { visu_colorization_setScaleType(dt, VISU_COLORIZATION_MINMAX); for (i = 0; i < minMax->len; i++) { rg = &g_array_index(minMax, VisuColorRange, i); visu_colorization_setMin(dt, rg->min, rg->column - 1); visu_colorization_setMax(dt, rg->max, rg->column - 1); } } for (i = 0; i < 3; i++) visu_colorization_setColUsed(dt, (colUsed)?colUsed[i] - 1:0, i); shade = tool_pool_getById(tool_shade_getStorage(), commandLineGet_presetColor()); visu_data_colorizer_shaded_setShade(VISU_DATA_COLORIZER_SHADED(dt), (shade) ? shade : tool_pool_getById(tool_shade_getStorage(), 0)); if (commandLineGet_scalingColumn() >= 0) visu_colorization_setScalingUsed(dt, commandLineGet_scalingColumn()); visu_data_colorizer_setActive(VISU_DATA_COLORIZER(dt), TRUE); } return dt; } v_sim-3.8.0/src/extraFunctions/dataFile.h000066400000000000000000000155401370110300500203170ustar00rootroot00000000000000/* EXTRAITS DE LA LICENCE Copyright CEA, contributeurs : Luc BILLARD et Damien CALISTE, laboratoire L_Sim, (2001-2005) Adresse mèl : BILLARD, non joignable par mèl ; CALISTE, damien P caliste AT cea P fr. Ce logiciel est un programme informatique servant à visualiser des structures atomiques dans un rendu pseudo-3D. Ce logiciel est régi par la licence CeCILL soumise au droit français et respectant les principes de diffusion des logiciels libres. Vous pouvez utiliser, modifier et/ou redistribuer ce programme sous les conditions de la licence CeCILL telle que diffusée par le CEA, le CNRS et l'INRIA sur le site "http://www.cecill.info". Le fait que vous puissiez accéder à cet en-tête signifie que vous avez pris connaissance de la licence CeCILL, et que vous en avez accepté les termes (cf. le fichier Documentation/licence.fr.txt fourni avec ce logiciel). */ /* LICENCE SUM UP Copyright CEA, contributors : Luc BILLARD et Damien CALISTE, laboratoire L_Sim, (2001-2005) E-mail address: BILLARD, not reachable any more ; CALISTE, damien P caliste AT cea P fr. This software is a computer program whose purpose is to visualize atomic configurations in 3D. This software is governed by the CeCILL license under French law and abiding by the rules of distribution of free software. You can use, modify and/ or redistribute the software under the terms of the CeCILL license as circulated by CEA, CNRS and INRIA at the following URL "http://www.cecill.info". The fact that you are presently reading this means that you have had knowledge of the CeCILL license and that you accept its terms. You can find a copy of this licence shipped with this software at Documentation/licence.en.txt. */ #ifndef VISU_DATAFILE_H #define VISU_DATAFILE_H #include #include #include #include "floatProp.h" #include "shadedColorizer.h" /** * VisuColorizationInputScaleId: * @VISU_COLORIZATION_NORMALIZE: input data are converted into [0;1] using input min/max values. * @VISU_COLORIZATION_MINMAX: input data are converted into [0;1] using user defined min/max values. * * Control how input data are converted into [0;1], after conversion, * values are clamped if needed. */ typedef enum { VISU_COLORIZATION_NORMALIZE, VISU_COLORIZATION_MINMAX } VisuColorizationInputScaleId; /** * VISU_COLORIZATION_UNSET: * * To be used when a column id is awaited. A constant value will then * be used. */ #define VISU_COLORIZATION_UNSET -4 /** * VISU_COLORIZATION_FROM_X: * * To be used when a column id is awaited. The reduced coordinate in x * direction will then be used. */ #define VISU_COLORIZATION_FROM_X -3 /** * VISU_COLORIZATION_FROM_Y: * * To be used when a column id is awaited. The reduced coordinate in y * direction will then be used. */ #define VISU_COLORIZATION_FROM_Y -2 /** * VISU_COLORIZATION_FROM_Z: * * To be used when a column id is awaited. The reduced coordinate in z * direction will then be used. */ #define VISU_COLORIZATION_FROM_Z -1 /** * VISU_COLORIZATION_LABEL: * * Default label used to name colourisation data. */ #define VISU_COLORIZATION_LABEL _("Colorization data") /** * VISU_TYPE_COLORIZATION: * * return the type of #VisuColorization. */ #define VISU_TYPE_COLORIZATION (visu_colorization_get_type ()) /** * VISU_COLORIZATION: * @obj: a #GObject to cast. * * Cast the given @obj into #VisuColorization type. */ #define VISU_COLORIZATION(obj) (G_TYPE_CHECK_INSTANCE_CAST(obj, VISU_TYPE_COLORIZATION, VisuColorization)) /** * VISU_COLORIZATION_CLASS: * @klass: a #GObjectClass to cast. * * Cast the given @klass into #VisuColorizationClass. */ #define VISU_COLORIZATION_CLASS(klass) (G_TYPE_CHECK_CLASS_CAST(klass, VISU_TYPE_COLORIZATION, VisuColorizationClass)) /** * VISU_IS_COLORIZATION: * @obj: a #GObject to test. * * Test if the given @ogj is of the type of #VisuColorization object. */ #define VISU_IS_COLORIZATION(obj) (G_TYPE_CHECK_INSTANCE_TYPE(obj, VISU_TYPE_COLORIZATION)) /** * VISU_IS_COLORIZATION_CLASS: * @klass: a #GObjectClass to test. * * Test if the given @klass is of the type of #VisuColorizationClass class. */ #define VISU_IS_COLORIZATION_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE(klass, VISU_TYPE_COLORIZATION)) /** * VISU_COLORIZATION_GET_CLASS: * @obj: a #GObject to get the class of. * * It returns the class of the given @obj. */ #define VISU_COLORIZATION_GET_CLASS(obj) (G_TYPE_INSTANCE_GET_CLASS(obj, VISU_TYPE_COLORIZATION, VisuColorizationClass)) /** * VisuColorizationPrivate: * * Private data for #VisuColorization objects. */ typedef struct _VisuColorizationPrivate VisuColorizationPrivate; /** * VisuColorization: * * An opaque structure to store colorisation settings. * * Since: 3.7 */ typedef struct _VisuColorization VisuColorization; struct _VisuColorization { VisuDataColorizerShaded parent; VisuColorizationPrivate *priv; }; /** * VisuColorizationClass: * @parent: private. * * Common name to refer to a #_VisuColorizationClass. */ typedef struct _VisuColorizationClass VisuColorizationClass; struct _VisuColorizationClass { VisuDataColorizerShadedClass parent; }; /** * visu_colorization_get_type: * * This method returns the type of #VisuColorization, use * VISU_TYPE_COLORIZATION instead. * * Returns: the type of #VisuColorization. */ GType visu_colorization_get_type(void); VisuColorization* visu_colorization_new(); VisuColorization* visu_colorization_new_fromCLI(VisuData *dataObj, GError **error); gboolean visu_colorization_setBox(VisuColorization *dt, VisuBox *box); void visu_colorization_setNodeModel(VisuColorization *dt, VisuNodeValuesFarray *values); gboolean visu_colorization_setScaleType(VisuColorization *dt, VisuColorizationInputScaleId scale); VisuColorizationInputScaleId visu_colorization_getScaleType(const VisuColorization *dt); gboolean visu_colorization_setMin(VisuColorization *dt, float min, int column); gboolean visu_colorization_setMax(VisuColorization *dt, float max, int column); float visu_colorization_getMin(const VisuColorization *dt, int column); float visu_colorization_getMax(const VisuColorization *dt, int column); gboolean visu_colorization_setColUsed(VisuColorization *dt, int val, int pos); gboolean visu_colorization_setColUsedArr(VisuColorization *dt, const int vals[3]); const int* visu_colorization_getColUsed(const VisuColorization *dt); int visu_colorization_getNColumns(const VisuColorization *dt); gboolean visu_colorization_getSingleColumnId(const VisuColorization *dt, gint *id); gboolean visu_colorization_setScalingUsed(VisuColorization *dt, int val); int visu_colorization_getScalingUsed(const VisuColorization *dt); gboolean visu_colorization_setRestrictInRange(VisuColorization *dt, gboolean status); gboolean visu_colorization_getRestrictInRange(const VisuColorization *dt); const gchar* visu_colorization_getFile(const VisuColorization *dt); #endif v_sim-3.8.0/src/extraFunctions/finder.c000066400000000000000000000277601370110300500200570ustar00rootroot00000000000000/* EXTRAITS DE LA LICENCE Copyright CEA, contributeurs : Damien CALISTE, laboratoire L_Sim, (2014) Adresse mèl : CALISTE, damien P caliste AT cea P fr. Ce logiciel est un programme informatique servant à visualiser des structures atomiques dans un rendu pseudo-3D. Ce logiciel est régi par la licence CeCILL soumise au droit français et respectant les principes de diffusion des logiciels libres. Vous pouvez utiliser, modifier et/ou redistribuer ce programme sous les conditions de la licence CeCILL telle que diffusée par le CEA, le CNRS et l'INRIA sur le site "http://www.cecill.info". Le fait que vous puissiez accéder à cet en-tête signifie que vous avez pris connaissance de la licence CeCILL, et que vous en avez accepté les termes (cf. le fichier Documentation/licence.fr.txt fourni avec ce logiciel). */ /* LICENCE SUM UP Copyright CEA, contributors : Damien CALISTE, laboratoire L_Sim, (2014) E-mail address: CALISTE, damien P caliste AT cea P fr. This software is a computer program whose purpose is to visualize atomic configurations in 3D. This software is governed by the CeCILL license under French law and abiding by the rules of distribution of free software. You can use, modify and/ or redistribute the software under the terms of the CeCILL license as circulated by CEA, CNRS and INRIA at the following URL "http://www.cecill.info". The fact that you are presently reading this means that you have had knowledge of the CeCILL license and that you accept its terms. You can find a copy of this licence shipped with this software at Documentation/licence.en.txt. */ #include "finder.h" #include /** * SECTION:finder * @short_description: provide a node lookup based on coordinates. * * This object can be used to find nodes based on coordinates in * a linear scaling complexity. */ /** * VisuNodeFinderClass: * @parent: the parent class; * * A short way to identify #_VisuNodeFinderClass structure. * * Since: 3.8 */ /** * VisuNodeFinder: * * An opaque structure. * * Since: 3.8 */ /** * VisuNodeFinderPrivate: * * Private fields for #VisuNodeFinder objects. * * Since: 3.8 */ struct _VisuNodeFinderPrivate { gboolean dispose_has_run; gfloat size; guint mesh[3]; GList **table; VisuData *data; gulong popDec_sig, popInc_sig, popPos_sig, popVis_sig; }; static void visu_node_finder_finalize(GObject* obj); static void visu_node_finder_dispose(GObject* obj); G_DEFINE_TYPE_WITH_CODE(VisuNodeFinder, visu_node_finder, VISU_TYPE_OBJECT, G_ADD_PRIVATE(VisuNodeFinder)) static void visu_node_finder_class_init(VisuNodeFinderClass *klass) { DBG_fprintf(stderr, "Visu Finder: creating the class of the object.\n"); /* DBG_fprintf(stderr, " - adding new signals ;\n"); */ /* Connect the overloading methods. */ G_OBJECT_CLASS(klass)->dispose = visu_node_finder_dispose; G_OBJECT_CLASS(klass)->finalize = visu_node_finder_finalize; } static void visu_node_finder_init(VisuNodeFinder *obj) { DBG_fprintf(stderr, "Visu Finder: initializing a new object (%p).\n", (gpointer)obj); obj->priv = visu_node_finder_get_instance_private(obj); obj->priv->dispose_has_run = FALSE; obj->priv->size = 4.f; obj->priv->mesh[0] = 0; obj->priv->mesh[1] = 0; obj->priv->mesh[2] = 0; obj->priv->table = (GList**)0; obj->priv->data = (VisuData*)0; } static void visu_node_finder_dispose(GObject* obj) { VisuNodeFinder *finder; DBG_fprintf(stderr, "Visu Finder: dispose object %p.\n", (gpointer)obj); finder = VISU_NODE_FINDER(obj); if (finder->priv->dispose_has_run) return; finder->priv->dispose_has_run = TRUE; /* Disconnect signals. */ if (G_LIKELY(finder->priv->data)) { g_signal_handler_disconnect(G_OBJECT(finder->priv->data), finder->priv->popDec_sig); g_signal_handler_disconnect(G_OBJECT(finder->priv->data), finder->priv->popInc_sig); g_signal_handler_disconnect(G_OBJECT(finder->priv->data), finder->priv->popPos_sig); g_signal_handler_disconnect(G_OBJECT(finder->priv->data), finder->priv->popVis_sig); g_object_unref(finder->priv->data); } /* Chain up to the parent class */ G_OBJECT_CLASS(visu_node_finder_parent_class)->dispose(obj); } static void visu_node_finder_finalize(GObject* obj) { VisuNodeFinder *finder; g_return_if_fail(obj); DBG_fprintf(stderr, "Visu Finder: finalize object %p.\n", (gpointer)obj); finder = VISU_NODE_FINDER(obj); /* Free privs elements. */ if (finder->priv) { DBG_fprintf(stderr, "Visu Finder: free private.\n"); g_free(finder->priv->table); } /* Chain up to the parent class */ DBG_fprintf(stderr, "Visu Finder: chain to parent.\n"); G_OBJECT_CLASS(visu_node_finder_parent_class)->finalize(obj); DBG_fprintf(stderr, "Visu Finder: freeing ... OK.\n"); } static void onChange(VisuNodeFinder *finder) { finder->priv->mesh[0] = 0; finder->priv->mesh[1] = 0; finder->priv->mesh[2] = 0; } /** * visu_node_finder_new: * @data: a #VisuData object. * * Creates a new #VisuNodeFinder to look for node from coordinates. * * Since: 3.8 * * Returns: a pointer to the #VisuNodeFinder it created or * NULL otherwise. */ VisuNodeFinder* visu_node_finder_new(VisuData *data) { VisuNodeFinder *finder; DBG_fprintf(stderr,"Visu Finder: new object.\n"); finder = VISU_NODE_FINDER(g_object_new(VISU_TYPE_NODE_FINDER, NULL)); g_return_val_if_fail(data, finder); g_object_ref(data); finder->priv->data = data; finder->priv->popDec_sig = g_signal_connect_object(G_OBJECT(data), "PopulationDecrease", G_CALLBACK(onChange), finder, G_CONNECT_SWAPPED); finder->priv->popInc_sig = g_signal_connect_object(G_OBJECT(data), "PopulationIncrease", G_CALLBACK(onChange), finder, G_CONNECT_SWAPPED); finder->priv->popPos_sig = g_signal_connect_object(G_OBJECT(data), "position-changed", G_CALLBACK(onChange), finder, G_CONNECT_SWAPPED); finder->priv->popVis_sig = g_signal_connect_object(data, "visibility-changed", G_CALLBACK(onChange), finder, G_CONNECT_SWAPPED); return finder; } /** * visu_node_finder_getData: * @finder: a #VisuNodeFinder object. * * Get the #VisuData object the @finder is working on. * * Since: 3.8 * * Returns: (transfer full): the corresponding #VisuData the finder * work on. **/ VisuData* visu_node_finder_getData(VisuNodeFinder *finder) { g_return_val_if_fail(VISU_IS_NODE_FINDER(finder), (VisuData*)0); g_object_ref(finder->priv->data); return finder->priv->data; } static void _generate_mesh(VisuNodeFinder *finder) { float bsize[3], xyz[3], f; VisuNodeArrayIter iter; guint i, j, k, id; /* Mesh cubes will have roughly priv->size. */ visu_box_getCentre(visu_boxed_getBox(VISU_BOXED(finder->priv->data)), bsize); bsize[0] *= 2.f; bsize[1] *= 2.f; bsize[2] *= 2.f; f = 1.f / finder->priv->size; finder->priv->mesh[0] = MAX((int)(bsize[0] * f), 1); finder->priv->mesh[1] = MAX((int)(bsize[1] * f), 1); finder->priv->mesh[2] = MAX((int)(bsize[2] * f), 1); DBG_fprintf(stderr, "Visu Finder: generate a mesh of %dx%dx%d.\n", finder->priv->mesh[0], finder->priv->mesh[1], finder->priv->mesh[2]); if (finder->priv->table) g_free(finder->priv->table); finder->priv->table = g_malloc0(sizeof(GList*) * finder->priv->mesh[0] * finder->priv->mesh[1] * finder->priv->mesh[2]); /* Distribute nodes inside table, according to their coordinates. */ visu_node_array_iter_new(VISU_NODE_ARRAY(finder->priv->data), &iter); for (visu_node_array_iterStart(VISU_NODE_ARRAY(finder->priv->data), &iter); iter.node; visu_node_array_iterNext(VISU_NODE_ARRAY(finder->priv->data), &iter)) { visu_data_getNodePosition(finder->priv->data, iter.node, xyz); i = CLAMP((int)(xyz[0] * f), 0, (int)finder->priv->mesh[0] - 1); j = CLAMP((int)(xyz[1] * f), 0, (int)finder->priv->mesh[1] - 1); k = CLAMP((int)(xyz[2] * f), 0, (int)finder->priv->mesh[2] - 1); id = k * finder->priv->mesh[0] * finder->priv->mesh[1] + j * finder->priv->mesh[0] + i; finder->priv->table[id] = g_list_prepend(finder->priv->table[id], GINT_TO_POINTER(iter.node->number)); } } static gint _mesh_lookup(VisuNodeFinder *finder, guint id, const gfloat at[3], gfloat *d) { VisuNodeArrayIter iter; gint res; gfloat dist, xyz[3], d2; dist = G_MAXFLOAT; res = -1; visu_node_array_iter_new(VISU_NODE_ARRAY(finder->priv->data), &iter); for (visu_node_array_iterStartList(VISU_NODE_ARRAY(finder->priv->data), &iter, finder->priv->table[id]); iter.node; visu_node_array_iterNextList(VISU_NODE_ARRAY(finder->priv->data), &iter)) { /* Currently, we don't take into account the periodicity. */ visu_data_getNodePosition(finder->priv->data, iter.node, xyz); xyz[0] -= at[0]; xyz[1] -= at[1]; xyz[2] -= at[2]; d2 = xyz[0] * xyz[0] + xyz[1] * xyz[1] + xyz[2] * xyz[2]; if (d2 < dist) { dist = d2; res = iter.node->number; } } if (d) *d = dist; return res; } /** * visu_node_finder_lookup: * @finder: a #VisuNodeFinder object. * @at: (array fixed-size=3): * @tol: a float. * * Giving the cartesian coordinates @at, this method lookup for the closest * #VisuNode within a radius of @tol. * * Since: 3.8 * * Returns: the id of the closest node to @at (within a maximum radius * of @tol). If none is found, returns -1. **/ gint visu_node_finder_lookup(VisuNodeFinder *finder, const gfloat at[3], gfloat tol) { guint i, j, k; gint s; guint i0, j0, k0; gint res, res2; gfloat f, dist, d2; GTimer *timer; gulong fractionTimer; #if DEBUG == 1 timer = g_timer_new(); g_timer_start(timer); #endif g_return_val_if_fail(VISU_IS_NODE_FINDER(finder), -1); g_return_val_if_fail(finder->priv->data, -1); if (!finder->priv->mesh[0] || !finder->priv->mesh[1] || !finder->priv->mesh[2]) _generate_mesh(finder); f = 1.f / finder->priv->size; i0 = CLAMP((int)(at[0] * f), 0, (int)finder->priv->mesh[0] - 1); j0 = CLAMP((int)(at[1] * f), 0, (int)finder->priv->mesh[1] - 1); k0 = CLAMP((int)(at[2] * f), 0, (int)finder->priv->mesh[2] - 1); DBG_fprintf(stderr, "Visu Finder: testing (%gx%gx%g) in mesh:\n", at[0], at[1], at[2]); res = -1; dist = G_MAXFLOAT; s = (int)(tol / finder->priv->size) + 1; for (i = MAX(0, (int)i0 - s); i < MIN(finder->priv->mesh[0], i0 + s + 1); i++) for (j = MAX(0, (int)j0 - s); j < MIN(finder->priv->mesh[1], j0 + s + 1); j++) for (k = MAX(0, (int)k0 - s); k < MIN(finder->priv->mesh[2], k0 + s + 1); k++) { DBG_fprintf(stderr, " | %dx%dx%d\n", i, j, k); res2 = _mesh_lookup(finder, k * finder->priv->mesh[0] * finder->priv->mesh[1] + j * finder->priv->mesh[0] + i, at, &d2); DBG_fprintf(stderr, " | found %d at %g.\n", res2, sqrt(d2)); if (d2 < dist) { dist = d2; res = res2; } DBG_fprintf(stderr, " | at %g micro-s.\n", g_timer_elapsed(timer, &fractionTimer)*1e6); } #if DEBUG == 1 g_timer_stop(timer); g_timer_destroy(timer); #endif if (sqrt(dist) < tol) return res; else return -1; } /** * visu_node_finder_lookupArray: * @finder: a #VisuNodeFinder object. * @ids: (type gint64): an allocated array of size @np. * @at: (type gint64): an allocated array of size 3 * @np, with * coordinates to be tested. * @np: the number of coordinates to be tested. * @tol: a radius to find the nodes in. * * Apply visu_node_finder_lookup() on the array @at. It's used mainly * for bindings. * * Since: 3.8 **/ void visu_node_finder_lookupArray(VisuNodeFinder *finder, gint *ids, const gfloat *at, guint np, gfloat tol) { guint i; for (i = 0; i < np; i++) ids[i] = visu_node_finder_lookup(finder, at + 3 * i, tol); } v_sim-3.8.0/src/extraFunctions/finder.h000066400000000000000000000076511370110300500200610ustar00rootroot00000000000000/* EXTRAITS DE LA LICENCE Copyright CEA, contributeurs : Damien CALISTE, laboratoire L_Sim, (2014) Adresse mèl : CALISTE, damien P caliste AT cea P fr. Ce logiciel est un programme informatique servant à visualiser des structures atomiques dans un rendu pseudo-3D. Ce logiciel est régi par la licence CeCILL soumise au droit français et respectant les principes de diffusion des logiciels libres. Vous pouvez utiliser, modifier et/ou redistribuer ce programme sous les conditions de la licence CeCILL telle que diffusée par le CEA, le CNRS et l'INRIA sur le site "http://www.cecill.info". Le fait que vous puissiez accéder à cet en-tête signifie que vous avez pris connaissance de la licence CeCILL, et que vous en avez accepté les termes (cf. le fichier Documentation/licence.fr.txt fourni avec ce logiciel). */ /* LICENCE SUM UP Copyright CEA, contributors : Damien CALISTE, laboratoire L_Sim, (2014) E-mail address: CALISTE, damien P caliste AT cea P fr. This software is a computer program whose purpose is to visualize atomic configurations in 3D. This software is governed by the CeCILL license under French law and abiding by the rules of distribution of free software. You can use, modify and/ or redistribute the software under the terms of the CeCILL license as circulated by CEA, CNRS and INRIA at the following URL "http://www.cecill.info". The fact that you are presently reading this means that you have had knowledge of the CeCILL license and that you accept its terms. You can find a copy of this licence shipped with this software at COPYING. */ #ifndef FINDER_H #define FINDER_H #include "visu_data.h" /** * VISU_TYPE_NODE_FINDER: * * return the type of #VisuNodeFinder. * * Since: 3.8 */ #define VISU_TYPE_NODE_FINDER (visu_node_finder_get_type ()) /** * VISU_NODE_FINDER: * @obj: a #GObject to cast. * * Cast the given @obj into #VisuNodeFinder type. * * Since: 3.8 */ #define VISU_NODE_FINDER(obj) (G_TYPE_CHECK_INSTANCE_CAST(obj, VISU_TYPE_NODE_FINDER, VisuNodeFinder)) /** * VISU_NODE_FINDER_CLASS: * @klass: a #GObjectClass to cast. * * Cast the given @klass into #VisuNodeFinderClass. * * Since: 3.8 */ #define VISU_NODE_FINDER_CLASS(klass) (G_TYPE_CHECK_CLASS_CAST(klass, VISU_TYPE_NODE_FINDER, VisuNodeFinderClass)) /** * VISU_IS_NODE_FINDER: * @obj: a #GObject to test. * * Test if the given @ogj is of the type of #VisuNodeFinder object. * * Since: 3.8 */ #define VISU_IS_NODE_FINDER(obj) (G_TYPE_CHECK_INSTANCE_TYPE(obj, VISU_TYPE_NODE_FINDER)) /** * VISU_IS_NODE_FINDER_CLASS: * @klass: a #GObjectClass to test. * * Test if the given @klass is of the type of #VisuNodeFinderClass class. * * Since: 3.8 */ #define VISU_IS_NODE_FINDER_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE(klass, VISU_TYPE_NODE_FINDER)) /** * VISU_NODE_FINDER_GET_CLASS: * @obj: a #GObject to get the class of. * * It returns the class of the given @obj. * * Since: 3.8 */ #define VISU_NODE_FINDER_GET_CLASS(obj) (G_TYPE_INSTANCE_GET_CLASS(obj, VISU_TYPE_NODE_FINDER, VisuNodeFinderClass)) typedef struct _VisuNodeFinder VisuNodeFinder; typedef struct _VisuNodeFinderPrivate VisuNodeFinderPrivate; typedef struct _VisuNodeFinderClass VisuNodeFinderClass; struct _VisuNodeFinder { VisuObject parent; VisuNodeFinderPrivate *priv; }; struct _VisuNodeFinderClass { VisuObjectClass parent; }; /** * visu_node_finder_get_type: * * This method returns the type of #VisuNodeFinder, use * VISU_TYPE_NODE_FINDER instead. * * Since: 3.8 * * Returns: the type of #VisuNodeFinder. */ GType visu_node_finder_get_type(void); VisuNodeFinder* visu_node_finder_new(VisuData *data); VisuData* visu_node_finder_getData(VisuNodeFinder *finder); gint visu_node_finder_lookup(VisuNodeFinder *finder, const gfloat at[3], gfloat tol); void visu_node_finder_lookupArray(VisuNodeFinder *finder, gint *ids, const gfloat *at, guint np, gfloat tol); #endif v_sim-3.8.0/src/extraFunctions/floatProp.c000066400000000000000000000525111370110300500205460ustar00rootroot00000000000000/* EXTRAITS DE LA LICENCE Copyright CEA, contributeurs : Damien CALISTE, laboratoire L_Sim, (2016) Adresse mèl : CALISTE, damien P caliste AT cea P fr. Ce logiciel est un programme informatique servant à visualiser des structures atomiques dans un rendu pseudo-3D. Ce logiciel est régi par la licence CeCILL soumise au droit français et respectant les principes de diffusion des logiciels libres. Vous pouvez utiliser, modifier et/ou redistribuer ce programme sous les conditions de la licence CeCILL telle que diffusée par le CEA, le CNRS et l'INRIA sur le site "http://www.cecill.info". Le fait que vous puissiez accéder à cet en-tête signifie que vous avez pris connaissance de la licence CeCILL, et que vous en avez accepté les termes (cf. le fichier Documentation/licence.fr.txt fourni avec ce logiciel). */ /* LICENCE SUM UP Copyright CEA, contributors : Damien CALISTE, laboratoire L_Sim, (2016) E-mail address: CALISTE, damien P caliste AT cea P fr. This software is a computer program whose purpose is to visualize atomic configurations in 3D. This software is governed by the CeCILL license under French law and abiding by the rules of distribution of free software. You can use, modify and/ or redistribute the software under the terms of the CeCILL license as circulated by CEA, CNRS and INRIA at the following URL "http://www.cecill.info". The fact that you are presently reading this means that you have had knowledge of the CeCILL license and that you accept its terms. You can find a copy of this licence shipped with this software at Documentation/licence.en.txt. */ #include "floatProp.h" #include /** * SECTION:floatProp * @short_description: define a #VisuNodeValues object to handle any * array of floats. * * Defines a #VisuNodeValues object to store floating point * arrays on every nodes and get notification for them. */ struct _VisuNodeValuesFarrayPrivate { gboolean dispose_has_run; gboolean dirty; gfloat min, max, nrm2; gfloat *zeros; GArray *readMinMax; /* Values min and max read for each column. */ gchar *file; }; enum { PROP_0, MIN_PROP, MAX_PROP, NRM2_PROP, READ_MM_PROP, FILE_PROP, N_PROP }; static GParamSpec *_properties[N_PROP]; static void visu_node_values_farray_finalize (GObject* obj); static void visu_node_values_farray_get_property(GObject* obj, guint property_id, GValue *value, GParamSpec *pspec); static gboolean _setAt(VisuNodeValues *vals, const VisuNode *node, GValue *value); static gfloat _nrm2(const VisuNodeValuesFarray *vect, const GValue *value); static void _compute(VisuNodeValuesFarray *vect); static void onDimensionSet(VisuNodeValuesFarray *vect, const GParamSpec *pspec, gpointer data); G_DEFINE_TYPE_WITH_CODE(VisuNodeValuesFarray, visu_node_values_farray, VISU_TYPE_NODE_VALUES, G_ADD_PRIVATE(VisuNodeValuesFarray)) static void visu_node_values_farray_class_init(VisuNodeValuesFarrayClass *klass) { /* Connect the overloading methods. */ G_OBJECT_CLASS(klass)->finalize = visu_node_values_farray_finalize; /* G_OBJECT_CLASS(klass)->set_property = visu_node_values_farray_set_property; */ G_OBJECT_CLASS(klass)->get_property = visu_node_values_farray_get_property; VISU_NODE_VALUES_CLASS(klass)->setAt = _setAt; klass->nrm2 = _nrm2; /** * VisuNodeValuesFarray::minimum: * * Holds the norm of the minimum value. * * Since: 3.8 */ _properties[MIN_PROP] = g_param_spec_float("minimum", "Minimum", "minimum norm", 0.f, G_MAXFLOAT, 0.f, G_PARAM_READABLE | G_PARAM_STATIC_STRINGS); /** * VisuNodeValuesFarray::maximum: * * Holds the norm of the maximum value. * * Since: 3.8 */ _properties[MAX_PROP] = g_param_spec_float("maximum", "Maximum", "maximum norm", 0.f, G_MAXFLOAT, 0.f, G_PARAM_READABLE | G_PARAM_STATIC_STRINGS); /** * VisuNodeValuesFarray::square-norm: * * Holds the square norm of the values. * * Since: 3.8 */ _properties[NRM2_PROP] = g_param_spec_float("square-norm", "Square-norm", "Square norm", 0.f, G_MAXFLOAT, 0.f, G_PARAM_READABLE | G_PARAM_STATIC_STRINGS); /** * VisuNodeValuesFarray::data-min-max: * * Min / max values per dimension of the stored data. * * Since: 3.8 */ _properties[READ_MM_PROP] = g_param_spec_boxed("data-min-max", "Data min/max", "min / max values of data", G_TYPE_ARRAY, G_PARAM_READABLE | G_PARAM_STATIC_STRINGS); /** * VisuNodeValuesFarray::source-file: * * Name of the source file the data come from. * * Since: 3.8 */ _properties[FILE_PROP] = g_param_spec_string("source-file", "Source file", "Source file if any", (const gchar*)0, G_PARAM_READABLE | G_PARAM_STATIC_STRINGS); g_object_class_install_properties(G_OBJECT_CLASS(klass), N_PROP, _properties); } static void visu_node_values_farray_init(VisuNodeValuesFarray *self) { DBG_fprintf(stderr, "Node Values Float : initialise %p.\n", (gpointer)self); self->priv = visu_node_values_farray_get_instance_private(self); self->priv->readMinMax = g_array_new(FALSE, FALSE, sizeof(float) * 2); self->priv->file = (gchar*)0; self->priv->dirty = TRUE; g_signal_connect(G_OBJECT(self), "notify::n-elements", G_CALLBACK(onDimensionSet), (gpointer)0); } static void onDimensionSet(VisuNodeValuesFarray *vect, const GParamSpec *pspec _U_, gpointer data _U_) { vect->priv->zeros = g_malloc0(sizeof(float) * visu_node_values_getDimension(VISU_NODE_VALUES(vect))); } /* This method is called once only. */ static void visu_node_values_farray_finalize(GObject* obj) { VisuNodeValuesFarray *self; DBG_fprintf(stderr, "Node Values Float : finalize %p.\n", (gpointer)obj); g_return_if_fail(obj); self = VISU_NODE_VALUES_FARRAY(obj); g_free(self->priv->zeros); g_array_unref(self->priv->readMinMax); g_free(self->priv->file); /* Chain up to the parent class */ G_OBJECT_CLASS(visu_node_values_farray_parent_class)->finalize(obj); } static void visu_node_values_farray_get_property(GObject* obj, guint property_id, GValue *value, GParamSpec *pspec) { VisuNodeValuesFarray *self = VISU_NODE_VALUES_FARRAY(obj); switch (property_id) { case MIN_PROP: g_value_set_float(value, visu_node_values_farray_min(self)); break; case MAX_PROP: g_value_set_float(value, visu_node_values_farray_max(self)); break; case NRM2_PROP: g_value_set_float(value, visu_node_values_farray_nrm2(self)); break; case READ_MM_PROP: _compute(self); g_value_set_boxed(value, self->priv->readMinMax); break; case FILE_PROP: g_value_set_static_string(value, self->priv->file); break; default: /* We don't have any other property... */ G_OBJECT_WARN_INVALID_PROPERTY_ID(obj, property_id, pspec); break; } } static gfloat _nrm2(const VisuNodeValuesFarray *vect, const GValue *value) { gfloat *diff, nrm2; guint i, ln; diff = (gfloat*)g_value_get_pointer(value); if (diff) { ln = visu_node_values_getDimension(VISU_NODE_VALUES(vect)); nrm2 = 0.f; for (i = 0; i < ln; i++) nrm2 += diff[i] * diff[i]; return nrm2; } else return 0.f; } /** * visu_node_values_farray_new: * @arr: a #VisuNodeArray object. * @label: a translatable label. * @dimension: a integer value. * * Create a new farray field located on nodes, storing @dimension * floats per node. * * Since: 3.8 * * Returns: (transfer full): a newly created #VisuNodeValuesFarray object. **/ VisuNodeValuesFarray* visu_node_values_farray_new(VisuNodeArray *arr, const gchar *label, guint dimension) { VisuNodeValuesFarray *vals; vals = VISU_NODE_VALUES_FARRAY(g_object_new(VISU_TYPE_NODE_VALUES_FARRAY, "nodes", arr, "label", label, "type", G_TYPE_FLOAT, "n-elements", dimension, NULL)); return vals; } /** * visu_node_values_farray_new_fromFile: * @arr: a #VisuNodeArray object. * @label: a label. * @filename: a filename. * @error: an error location. * * Parse @filename to read floating point values and creates a new * #VisuNodeValuesFarray object based on @arr. If an error occurs, an * empty #VisuNodeValuesFarray object is created. * * Since: 3.8 * * Returns: (transfer full): a newly created #VisuNodeValuesFarray object. **/ VisuNodeValuesFarray* visu_node_values_farray_new_fromFile(VisuNodeArray *arr, const gchar *label, const gchar *filename, GError **error) { guint nColumns, nbNodes; GArray *data; VisuNodeValuesFarray *vals; nbNodes = visu_node_array_getNNodes(arr); data = tool_array_sizedFromFile(filename, nbNodes, &nColumns, error); if (!data) return visu_node_values_farray_new(arr, label, 1); vals = visu_node_values_farray_new(arr, label, nColumns); visu_node_values_farray_set(vals, data); vals->priv->file = g_strdup(filename); g_array_free(data, TRUE); return vals; } /** * visu_node_values_farray_min: * @vect: a #VisuNodeValuesFarray object. * * Computes and returns the smallest farray in the field. * * Since: 3.8 * * Returns: the minimum farray norm. **/ gfloat visu_node_values_farray_min(VisuNodeValuesFarray *vect) { g_return_val_if_fail(VISU_IS_NODE_VALUES_FARRAY(vect), G_MAXFLOAT); _compute(vect); return vect->priv->min; } /** * visu_node_values_farray_max: * @vect: a #VisuNodeValuesFarray object. * * Computes and returns the longest farray in the field. * * Since: 3.8 * * Returns: the maximum farray norm. **/ gfloat visu_node_values_farray_max(VisuNodeValuesFarray *vect) { g_return_val_if_fail(VISU_IS_NODE_VALUES_FARRAY(vect), -1.f); _compute(vect); return vect->priv->max; } /** * visu_node_values_farray_nrm2: * @vect: a #VisuNodeValuesFarray object. * * Computes and returns the sum of square norm all farrays in the field. * * Since: 3.8 * * Returns: the square norm of the farray field. **/ gfloat visu_node_values_farray_nrm2(VisuNodeValuesFarray *vect) { g_return_val_if_fail(VISU_IS_NODE_VALUES_FARRAY(vect), -1.f); _compute(vect); return vect->priv->nrm2; } /** * visu_node_values_farray_getColumnMinMax: * @vect: the #VisuNodeValuesFarray object. * @minMax: (array fixed-size=2) (out): an allocated array of two * floating point values ; * @column: an integer. * * This method is used to retrieve the minimum and the maximum * values of the column designed by the @column argument. Column * are numbered beginning at 0. * * Returns: FALSE if @column < 0 or if @column is greater than the number * of read column or if no file has been set. */ gboolean visu_node_values_farray_getColumnMinMax(VisuNodeValuesFarray *vect, float minMax[2], guint column) { float *minmax; g_return_val_if_fail(VISU_IS_NODE_VALUES_FARRAY(vect), FALSE); _compute(vect); g_return_val_if_fail(column < vect->priv->readMinMax->len, FALSE); minmax = &g_array_index(vect->priv->readMinMax, float, column * 2); minMax[0] = minmax[0]; minMax[1] = minmax[1]; return TRUE; } static void _compute(VisuNodeValuesFarray *vect) { float nrm2; gboolean valid; guint i, ln; VisuNodeValuesIter iter; VisuNodeValuesFarrayClass *klass = VISU_NODE_VALUES_FARRAY_GET_CLASS(vect); float init[2] = {G_MAXFLOAT, -G_MAXFLOAT}; float *data, *minmax; DBG_fprintf(stderr, "Node Values Float (%p): recompute %d.\n", (gpointer)vect, vect->priv->dirty); if (!vect->priv->dirty) return; vect->priv->dirty = FALSE; vect->priv->nrm2 = 0.f; vect->priv->min = G_MAXFLOAT; vect->priv->max = 0.f; valid = visu_node_values_iter_new(&iter, ITER_NODES_BY_TYPE, VISU_NODE_VALUES(vect)); while (valid) { nrm2 = klass->nrm2(vect, &iter.value); if (nrm2 >= 0.f) { vect->priv->nrm2 += nrm2; vect->priv->min = MIN(vect->priv->min, nrm2); vect->priv->max = MAX(vect->priv->max, nrm2); } valid = visu_node_values_iter_next(&iter); } vect->priv->min = sqrt(vect->priv->min); vect->priv->max = sqrt(vect->priv->max); ln = visu_node_values_getDimension(VISU_NODE_VALUES(vect)); g_array_set_size(vect->priv->readMinMax, ln); /* Check for minMax values for each column. */ for (i = 0; i < ln; i++) g_array_insert_vals(vect->priv->readMinMax, i, init, 1); for (visu_node_values_iter_new(&iter, ITER_NODES_BY_TYPE, VISU_NODE_VALUES(vect)); iter.iter.node; visu_node_values_iter_next(&iter)) { data = (float*)g_value_get_pointer(&iter.value); if (!data) continue; for (i = 0; i < ln; i++) { minmax = &g_array_index(vect->priv->readMinMax, float, i * 2); if (data[i] < minmax[0]) minmax[0] = data[i]; if (data[i] > minmax[1]) minmax[1] = data[i]; } } } /** * visu_node_values_farray_getAt: * @vect: a #VisuNodeValuesFarray object. * @node: a #VisuNode object. * * Retrieves the float array hosted on @node. * * Since: 3.8 * * Returns: (transfer none): the coordinates of * float array for @node. **/ const gfloat* visu_node_values_farray_getAt(VisuNodeValuesFarray *vect, const VisuNode *node) { GValue diffValue = G_VALUE_INIT; const gfloat *diff; g_return_val_if_fail(VISU_IS_NODE_VALUES_FARRAY(vect), NULL); visu_node_values_getAt(VISU_NODE_VALUES(vect), node, &diffValue); diff = (const gfloat*)g_value_get_pointer(&diffValue); return diff; /* ? diff : vect->priv->zeros; */ } /** * visu_node_values_farray_getAtIter: * @vect: a #VisuNodeValuesFarray object. * @iter: an iterator on @vect. * * Provide the floats stored in @vect at @iter. * * Since: 3.8 * * Returns: a pointer to the float array. **/ const gfloat* visu_node_values_farray_getAtIter(const VisuNodeValuesFarray *vect, const VisuNodeValuesIter *iter) { g_return_val_if_fail(VISU_IS_NODE_VALUES_FARRAY(vect), NULL); g_return_val_if_fail(iter, NULL); return (const gfloat*)g_value_get_pointer(&iter->value); } /** * visu_node_values_farray_getFloatAt: * @vect: a #VisuNodeValuesFarray object. * @node: a #VisuNode pointer. * @column: a column id. * * Retrieves the float value stored for @node at @column, if any. * * Since: 3.8 * * Returns: a float value. **/ gfloat visu_node_values_farray_getFloatAt(const VisuNodeValuesFarray *vect, const VisuNode *node, guint column) { GValue diffValue = G_VALUE_INIT; const gfloat *vals; g_return_val_if_fail(column < visu_node_values_getDimension(VISU_NODE_VALUES(vect)), 0.f); visu_node_values_getAt(VISU_NODE_VALUES(vect), node, &diffValue); vals = (const gfloat*)g_value_get_pointer(&diffValue); return vals ? vals[column] : 0.f; } /** * visu_node_values_farray_getFloatAtIter: * @vect: a #VisuNodeValuesFarray object. * @iter: a #VisuNodeValuesIter object. * @column: a column id. * * Retrieves the float value stored for the current iteration of @iter * for the column @column. @iter must be running on @vect. * * Since: 3.8 * * Returns: a float value. **/ gfloat visu_node_values_farray_getFloatAtIter(const VisuNodeValuesFarray *vect, const VisuNodeValuesIter *iter, guint column) { const gfloat *vals; g_return_val_if_fail(iter && iter->vals == VISU_NODE_VALUES(vect), 0.f); g_return_val_if_fail(VISU_IS_NODE_VALUES_FARRAY(vect), 0.f); g_return_val_if_fail(column < visu_node_values_getDimension(VISU_NODE_VALUES(vect)), 0.f); vals = (const gfloat*)g_value_get_pointer(&iter->value); return vals ? vals[column] : 0.f; } static gboolean _setAt(VisuNodeValues *vect, const VisuNode *node, GValue *value) { gboolean res; VISU_NODE_VALUES_FARRAY(vect)->priv->dirty = TRUE; /* Chain up to parent. */ res = VISU_NODE_VALUES_CLASS(visu_node_values_farray_parent_class)->setAt(vect, node, value); if (res) { g_object_notify_by_pspec(G_OBJECT(vect), _properties[READ_MM_PROP]); g_object_notify_by_pspec(G_OBJECT(vect), _properties[MIN_PROP]); g_object_notify_by_pspec(G_OBJECT(vect), _properties[MAX_PROP]); g_object_notify_by_pspec(G_OBJECT(vect), _properties[NRM2_PROP]); } return res; } /** * visu_node_values_farray_setAt: * @vect: a #VisuNodeValuesFarray object. * @node: a #VisuNode object. * @vals: (array length=ln): farray coordinates. * @ln: a length. * * Changes the float array hosted at @node for one of values defined * by @vals. * * Since: 3.8 * * Returns: TRUE if farray for @node is indeed changed. **/ gboolean visu_node_values_farray_setAt(VisuNodeValuesFarray *vect, const VisuNode *node, const gfloat *vals, guint ln) { gfloat *old; guint i; gboolean changed; GValue value = {0, {{0}, {0}}}; g_return_val_if_fail(visu_node_values_getDimension(VISU_NODE_VALUES(vect)) == ln, FALSE); visu_node_values_getAt(VISU_NODE_VALUES(vect), node, &value); old = (gfloat*)g_value_get_pointer(&value); if (old) { changed = FALSE; for (i = 0; i < ln && !changed; i++) changed = (old[i] != vals[i]); if (!changed) return FALSE; } g_value_set_pointer(&value, (gpointer)vals); return visu_node_values_setAt(VISU_NODE_VALUES(vect), node, &value); } /** * visu_node_values_farray_setAtDbl: * @vect: a #VisuNodeValuesFarray object. * @node: a #VisuNode object. * @vals: (array fixed-size=3): farray coordinates. * @ln: a length. * * Same as visu_node_values_farray_setAt() but for double values. * * Since: 3.8 * * Returns: TRUE if farray for @node is indeed changed. **/ gboolean visu_node_values_farray_setAtDbl(VisuNodeValuesFarray *vect, const VisuNode *node, const double *vals, guint ln) { guint i; gfloat *farr; gboolean ret; g_return_val_if_fail(visu_node_values_getDimension(VISU_NODE_VALUES(vect)) == ln, FALSE); farr = g_malloc(sizeof(gfloat) * ln); for (i = 0; i < ln; i++) farr[i] = vals[i]; ret = visu_node_values_farray_setAt(vect, node, farr, ln); g_free(farr); return ret; } /** * visu_node_values_farray_set: * @vect: a #VisuNodeValuesFarray object. * @data: (element-type float): some farray coordinates. * * Assigns the coordinates stored in @data to each nodes in @vect. * * Since: 3.8 * * Returns: TRUE if @data has the same size as @vect. **/ gboolean visu_node_values_farray_set(VisuNodeValuesFarray *vect, const GArray *data) { guint i, ln; gboolean valid; VisuNodeValuesIter iter; ln = visu_node_values_getDimension(VISU_NODE_VALUES(vect)); g_return_val_if_fail(data && data->len % ln == 0, FALSE); g_object_freeze_notify(G_OBJECT(vect)); i = 0; valid = visu_node_values_iter_new(&iter, ITER_NODES_BY_NUMBER, VISU_NODE_VALUES(vect)); while (valid && i + ln <= data->len) { visu_node_values_farray_setAt(vect, iter.iter.node, &g_array_index(data, float, i), ln); i += ln; valid = visu_node_values_iter_next(&iter); } g_object_thaw_notify(G_OBJECT(vect)); return (i == data->len); } /** * visu_node_values_farray_getFile: * @vect: a #VisuNodeValuesFarray object. * * Retrieve the filename from which the values have been read, if any. * * Since: 3.8 * * Returns: a filename. **/ const gchar* visu_node_values_farray_getFile(const VisuNodeValuesFarray *vect) { g_return_val_if_fail(VISU_IS_NODE_VALUES_FARRAY(vect), (const gchar*)0); return vect->priv->file; } /** * visu_node_values_farray_scale: * @vect: a #VisuNodeValuesFarray object. * @factor: a factor. * * Multiply every element of @vect by @factor. * * Since: 3.8 **/ void visu_node_values_farray_scale(VisuNodeValuesFarray *vect, gfloat factor) { guint i, ln; VisuNodeValuesIter iter; gfloat *data; g_return_if_fail(VISU_IS_NODE_VALUES_FARRAY(vect)); if (factor == 1.f) return; vect->priv->dirty = TRUE; ln = visu_node_values_getDimension(VISU_NODE_VALUES(vect)); for (visu_node_values_iter_new(&iter, ITER_NODES_BY_TYPE, VISU_NODE_VALUES(vect)); iter.iter.node; visu_node_values_iter_next(&iter)) { data = (gfloat*)g_value_get_pointer(&iter.value); if (!data) continue; for (i = 0; i < ln; i++) data[i] *= factor; } } v_sim-3.8.0/src/extraFunctions/floatProp.h000066400000000000000000000156341370110300500205600ustar00rootroot00000000000000/* EXTRAITS DE LA LICENCE Copyright CEA, contributeurs : Damien CALISTE, laboratoire L_Sim, (2016) Adresse mèl : CALISTE, damien P caliste AT cea P fr. Ce logiciel est un programme informatique servant à visualiser des structures atomiques dans un rendu pseudo-3D. Ce logiciel est régi par la licence CeCILL soumise au droit français et respectant les principes de diffusion des logiciels libres. Vous pouvez utiliser, modifier et/ou redistribuer ce programme sous les conditions de la licence CeCILL telle que diffusée par le CEA, le CNRS et l'INRIA sur le site "http://www.cecill.info". Le fait que vous puissiez accéder à cet en-tête signifie que vous avez pris connaissance de la licence CeCILL, et que vous en avez accepté les termes (cf. le fichier Documentation/licence.fr.txt fourni avec ce logiciel). */ /* LICENCE SUM UP Copyright CEA, contributors : Damien CALISTE, laboratoire L_Sim, (2016) E-mail address: CALISTE, damien P caliste AT cea P fr. This software is a computer program whose purpose is to visualize atomic configurations in 3D. This software is governed by the CeCILL license under French law and abiding by the rules of distribution of free software. You can use, modify and/ or redistribute the software under the terms of the CeCILL license as circulated by CEA, CNRS and INRIA at the following URL "http://www.cecill.info". The fact that you are presently reading this means that you have had knowledge of the CeCILL license and that you accept its terms. You can find a copy of this licence shipped with this software at Documentation/licence.en.txt. */ #ifndef FARRAYPROP_H #define FARRAYPROP_H #include #include #include "nodeProp.h" #include G_BEGIN_DECLS /** * VISU_TYPE_NODE_VALUES_FARRAY: * * return the type of #VisuNodeValuesFarray. */ #define VISU_TYPE_NODE_VALUES_FARRAY (visu_node_values_farray_get_type ()) /** * VISU_NODE_VALUES_FARRAY: * @obj: a #GObject to cast. * * Cast the given @obj into #VisuNodeValuesFarray type. */ #define VISU_NODE_VALUES_FARRAY(obj) (G_TYPE_CHECK_INSTANCE_CAST(obj, VISU_TYPE_NODE_VALUES_FARRAY, VisuNodeValuesFarray)) /** * VISU_NODE_VALUES_FARRAY_CLASS: * @klass: a #GObjectClass to cast. * * Cast the given @klass into #VisuNodeValuesFarrayClass. */ #define VISU_NODE_VALUES_FARRAY_CLASS(klass) (G_TYPE_CHECK_CLASS_CAST(klass, VISU_TYPE_NODE_VALUES_FARRAY, VisuNodeValuesFarrayClass)) /** * VISU_IS_NODE_VALUES_FARRAY: * @obj: a #GObject to test. * * Test if the given @ogj is of the type of #VisuNodeValuesFarray object. */ #define VISU_IS_NODE_VALUES_FARRAY(obj) (G_TYPE_CHECK_INSTANCE_TYPE(obj, VISU_TYPE_NODE_VALUES_FARRAY)) /** * VISU_IS_NODE_VALUES_FARRAY_CLASS: * @klass: a #GObjectClass to test. * * Test if the given @klass is of the type of #VisuNodeValuesFarrayClass class. */ #define VISU_IS_NODE_VALUES_FARRAY_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE(klass, VISU_TYPE_NODE_VALUES_FARRAY)) /** * VISU_NODE_VALUES_FARRAY_GET_CLASS: * @obj: a #GObject to get the class of. * * It returns the class of the given @obj. */ #define VISU_NODE_VALUES_FARRAY_GET_CLASS(obj) (G_TYPE_INSTANCE_GET_CLASS(obj, VISU_TYPE_NODE_VALUES_FARRAY, VisuNodeValuesFarrayClass)) /** * VisuNodeValuesFarrayPrivate: * * Private data for #VisuNodeValuesFarray objects. */ typedef struct _VisuNodeValuesFarrayPrivate VisuNodeValuesFarrayPrivate; /** * VisuNodeValuesFarray: * * Common name to refer to a #_VisuNodeValuesFarray. */ typedef struct _VisuNodeValuesFarray VisuNodeValuesFarray; struct _VisuNodeValuesFarray { VisuNodeValues parent; VisuNodeValuesFarrayPrivate *priv; }; /** * VisuNodeValuesFarrayNrm2: * @vect: a #VisuNodeValuesFarray object. * @value: a value. * * Prototype of method used to compute the square norm of @value. * * Since: 3.8 */ typedef gfloat (*VisuNodeValuesFarrayNrm2)(const VisuNodeValuesFarray *vect, const GValue *value); /** * VisuNodeValuesFarrayClass: * @parent: private. * @nrm2: the function used to compute the squared norm of the float array. * * Common name to refer to a #_VisuNodeValuesFarrayClass. */ typedef struct _VisuNodeValuesFarrayClass VisuNodeValuesFarrayClass; struct _VisuNodeValuesFarrayClass { VisuNodeValuesClass parent; VisuNodeValuesFarrayNrm2 nrm2; }; /** * visu_node_values_farray_get_type: * * This method returns the type of #VisuNodeValuesFarray, use * VISU_TYPE_NODE_VALUES_FARRAY instead. * * Since: 3.8 * * Returns: the type of #VisuNodeValuesFarray. */ GType visu_node_values_farray_get_type(void); VisuNodeValuesFarray* visu_node_values_farray_new(VisuNodeArray *arr, const gchar *label, guint dimension); VisuNodeValuesFarray* visu_node_values_farray_new_fromFile(VisuNodeArray *arr, const gchar *label, const gchar *filename, GError **error); gfloat visu_node_values_farray_min(VisuNodeValuesFarray *vect); gfloat visu_node_values_farray_max(VisuNodeValuesFarray *vect); gfloat visu_node_values_farray_nrm2(VisuNodeValuesFarray *vect); gboolean visu_node_values_farray_getColumnMinMax(VisuNodeValuesFarray *vect, float minMax[2], guint column); const gfloat* visu_node_values_farray_getAt(VisuNodeValuesFarray *vect, const VisuNode *node); const gfloat* visu_node_values_farray_getAtIter(const VisuNodeValuesFarray *vect, const VisuNodeValuesIter *iter); gfloat visu_node_values_farray_getFloatAt(const VisuNodeValuesFarray *vect, const VisuNode *node, guint column); gfloat visu_node_values_farray_getFloatAtIter(const VisuNodeValuesFarray *vect, const VisuNodeValuesIter *iter, guint column); gboolean visu_node_values_farray_setAt(VisuNodeValuesFarray *vect, const VisuNode *node, const float *vals, guint ln); gboolean visu_node_values_farray_setAtDbl(VisuNodeValuesFarray *vect, const VisuNode *node, const double *vals, guint ln); gboolean visu_node_values_farray_set(VisuNodeValuesFarray *vect, const GArray *data); void visu_node_values_farray_scale(VisuNodeValuesFarray *vect, gfloat factor); const gchar* visu_node_values_farray_getFile(const VisuNodeValuesFarray *vect); G_END_DECLS #endif v_sim-3.8.0/src/extraFunctions/fragColorizer.c000066400000000000000000000320431370110300500214060ustar00rootroot00000000000000/* EXTRAITS DE LA LICENCE Copyright CEA, contributeurs : Damien CALISTE, laboratoire L_Sim, (2017) Adresse mèl : CALISTE, damien P caliste AT cea P fr. Ce logiciel est un programme informatique servant à visualiser des structures atomiques dans un rendu pseudo-3D. Ce logiciel est régi par la licence CeCILL soumise au droit français et respectant les principes de diffusion des logiciels libres. Vous pouvez utiliser, modifier et/ou redistribuer ce programme sous les conditions de la licence CeCILL telle que diffusée par le CEA, le CNRS et l'INRIA sur le site "http://www.cecill.info". Le fait que vous puissiez accéder à cet en-tête signifie que vous avez pris connaissance de la licence CeCILL, et que vous en avez accepté les termes (cf. le fichier Documentation/licence.fr.txt fourni avec ce logiciel). */ /* LICENCE SUM UP Copyright CEA, contributors : Damien CALISTE, laboratoire L_Sim, (2017) E-mail address: CALISTE, damien P caliste AT cea P fr. This software is a computer program whose purpose is to visualize atomic configurations in 3D. This software is governed by the CeCILL license under French law and abiding by the rules of distribution of free software. You can use, modify and/ or redistribute the software under the terms of the CeCILL license as circulated by CEA, CNRS and INRIA at the following URL "http://www.cecill.info". The fact that you are presently reading this means that you have had knowledge of the CeCILL license and that you accept its terms. You can find a copy of this licence shipped with this software at Documentation/licence.en.txt. */ #include "fragColorizer.h" #include /** * SECTION:fragColorizer * @short_description: A class defining node colorisation according to * #VisuNodeValuesFrag. * * This class implements #VisuDataColorizer for data coming from * #VisuNodeFragment. One can specify colorization according to * fragment label or fragment id, see * visu_data_colorizer_fragment_setType(). This class also implements * #VisuNodeMaskerInterface and can be used to toggle the visibility * of #VisuNode depending on their fragment label, see * visu_data_colorizer_fragment_setVisibility() and * visu_data_colorizer_fragment_setDefaultVisibility(). */ struct _VisuDataColorizerFragmentPrivate { VisuDataColorizerFragmentTypes type; gboolean defaultVisibility; GHashTable *hidingTable; }; enum { PROP_0, PROP_TYPE, N_PROPS }; static GParamSpec *_properties[N_PROPS]; static void visu_data_colorizer_fragment_finalize(GObject* obj); static void visu_data_colorizer_fragment_get_property(GObject* obj, guint property_id, GValue *value, GParamSpec *pspec); static void visu_data_colorizer_fragment_set_property(GObject* obj, guint property_id, const GValue *value, GParamSpec *pspec); static gboolean _colorize(const VisuDataColorizer *colorizer, float rgba[4], const VisuData *visuData, const VisuNode* node); static void visu_node_masker_interface_init(VisuNodeMaskerInterface *iface); static gboolean _maskApply(const VisuNodeMasker *self, VisuNodeArray *array); G_DEFINE_TYPE_WITH_CODE(VisuDataColorizerFragment, visu_data_colorizer_fragment, VISU_TYPE_DATA_COLORIZER, G_ADD_PRIVATE(VisuDataColorizerFragment) G_IMPLEMENT_INTERFACE(VISU_TYPE_NODE_MASKER, visu_node_masker_interface_init)) static void visu_data_colorizer_fragment_class_init(VisuDataColorizerFragmentClass *klass) { /* Connect the overloading methods. */ G_OBJECT_CLASS(klass)->finalize = visu_data_colorizer_fragment_finalize; G_OBJECT_CLASS(klass)->set_property = visu_data_colorizer_fragment_set_property; G_OBJECT_CLASS(klass)->get_property = visu_data_colorizer_fragment_get_property; VISU_DATA_COLORIZER_CLASS(klass)->colorize = _colorize; /** * VisuDataColorizerFragment::type: * * A flag specifying if the colorizer has changed. * * Since: 3.8 */ _properties[PROP_TYPE] = g_param_spec_uint("type", "Type", "colorization type", 0, COLORIZATION_PER_TYPE, COLORIZATION_PER_FRAGMENT, G_PARAM_READWRITE); g_object_class_install_properties(G_OBJECT_CLASS(klass), N_PROPS, _properties); } static void visu_node_masker_interface_init(VisuNodeMaskerInterface *iface) { iface->apply = _maskApply; } static void visu_data_colorizer_fragment_init(VisuDataColorizerFragment *obj) { DBG_fprintf(stderr, "Visu Data Colorizer Fragment: initializing a new object (%p).\n", (gpointer)obj); obj->priv = visu_data_colorizer_fragment_get_instance_private(obj); obj->priv->type = COLORIZATION_PER_FRAGMENT; obj->priv->defaultVisibility = TRUE; obj->priv->hidingTable = g_hash_table_new_full(g_str_hash, g_str_equal, g_free, NULL); g_signal_connect(obj, "notify::active", G_CALLBACK(visu_node_masker_emitDirty), (gpointer)0); } static void visu_data_colorizer_fragment_get_property(GObject* obj, guint property_id, GValue *value, GParamSpec *pspec) { VisuDataColorizerFragment *self = VISU_DATA_COLORIZER_FRAGMENT(obj); DBG_fprintf(stderr, "Visu Data Colorizer Fragment: get property '%s' -> ", g_param_spec_get_name(pspec)); switch (property_id) { case PROP_TYPE: g_value_set_uint(value, self->priv->type); DBG_fprintf(stderr, "%d.\n", self->priv->type); break; default: /* We don't have any other property... */ G_OBJECT_WARN_INVALID_PROPERTY_ID(obj, property_id, pspec); break; } } static void visu_data_colorizer_fragment_set_property(GObject* obj, guint property_id, const GValue *value, GParamSpec *pspec) { VisuDataColorizerFragment *self = VISU_DATA_COLORIZER_FRAGMENT(obj); DBG_fprintf(stderr, "Visu Data Colorizer Fragment: set property '%s' -> ", g_param_spec_get_name(pspec)); switch (property_id) { case PROP_TYPE: DBG_fprintf(stderr, "%d.\n", g_value_get_uint(value)); visu_data_colorizer_fragment_setType(self, g_value_get_uint(value)); break; default: /* We don't have any other property... */ G_OBJECT_WARN_INVALID_PROPERTY_ID(obj, property_id, pspec); break; } } static void visu_data_colorizer_fragment_finalize(GObject* obj) { VisuDataColorizerFragment *frag; g_return_if_fail(obj); frag = VISU_DATA_COLORIZER_FRAGMENT(obj); g_hash_table_destroy(frag->priv->hidingTable); G_OBJECT_CLASS(visu_data_colorizer_fragment_parent_class)->finalize(obj); } /** * visu_data_colorizer_fragment_new: * * Creates a #VisuDataColorizer object to colorize and hide #VisuNode * based on a #VisuNodeValuesFrag model. * * Since: 3.8 * * Returns: (transfer full): a newly created * #VisuDataColorizerFragment object. **/ VisuDataColorizerFragment* visu_data_colorizer_fragment_new() { return VISU_DATA_COLORIZER_FRAGMENT(g_object_new(VISU_TYPE_DATA_COLORIZER_FRAGMENT, NULL)); } /** * visu_data_colorizer_fragment_setNodeModel: * @colorizer: a #VisuDataColorizerFragment object. * @model: (transfer none): a #VisuNodeValuesFrag object. * * Associate @model to @colorizer. * * Since: 3.8 * * Returns: TRUE if the model is indeed changed. **/ gboolean visu_data_colorizer_fragment_setNodeModel(VisuDataColorizerFragment *colorizer, VisuNodeValuesFrag *model) { return visu_sourceable_setNodeModel(VISU_SOURCEABLE(colorizer), VISU_NODE_VALUES(model)); } /** * visu_data_colorizer_fragment_setType: * @colorizer: a #VisuDataColorizerFragment object. * @type: a #VisuDataColorizerFragmentTypes value. * * Defines how @colorizer is changing the node colours. See * visu_node_array_renderer_pushColorizer() function. * * Since: 3.8 * * Returns: TRUE if the value is actually changed. **/ gboolean visu_data_colorizer_fragment_setType(VisuDataColorizerFragment *colorizer, VisuDataColorizerFragmentTypes type) { g_return_val_if_fail(VISU_IS_DATA_COLORIZER_FRAGMENT(colorizer), FALSE); if (colorizer->priv->type == type) return FALSE; colorizer->priv->type = type; g_object_notify_by_pspec(G_OBJECT(colorizer), _properties[PROP_TYPE]); visu_data_colorizer_setDirty(VISU_DATA_COLORIZER(colorizer)); return TRUE; } /** * visu_data_colorizer_fragment_setVisibility: * @frag: a #VisuDataColorizerFragment object. * @label: (allow-none): a string. * @status: a boolean. * * Change the visibility of all #VisuNode belonging to a * #VisuNodeFragment labelled by @label according to @status. If * @label is %NULL, status is changed for every fragments. * * Since: 3.8 * * Returns: TRUE is the value is actually changed. **/ gboolean visu_data_colorizer_fragment_setVisibility(VisuDataColorizerFragment *frag, const gchar *label, gboolean status) { gboolean old; VisuNodeValuesIter iter; VisuNodeValues *model; const VisuNodeFragment *f; g_return_val_if_fail(VISU_IS_DATA_COLORIZER_FRAGMENT(frag), FALSE); if (label) { old = GPOINTER_TO_INT(g_hash_table_lookup(frag->priv->hidingTable, label)); if (old == !status) return FALSE; g_hash_table_replace(frag->priv->hidingTable, g_strdup(label), GINT_TO_POINTER(!status)); } else { model = visu_sourceable_getNodeModel(VISU_SOURCEABLE(frag)); if (!model) return FALSE; for (visu_node_values_iter_new(&iter, ITER_NODES_BY_TYPE, model); iter.iter.node; visu_node_values_iter_next(&iter)) { f = visu_node_values_frag_getAtIter(VISU_NODE_VALUES_FRAG(iter.vals), &iter); if (f) g_hash_table_replace(frag->priv->hidingTable, g_strdup(f->label), GINT_TO_POINTER(!status)); } } if (visu_data_colorizer_getActive(VISU_DATA_COLORIZER(frag))) visu_node_masker_emitDirty(VISU_NODE_MASKER(frag)); return TRUE; } /** * visu_data_colorizer_fragment_setDefaultVisibility: * @frag: a #VisuDataColorizerFragment object. * @status: a boolean. * * Defines the visibility @status of all #VisuNode not belonging to * any #VisuNodeFragment. * * Since: 3.8 * * Returns: TRUE is the value is actually changed. **/ gboolean visu_data_colorizer_fragment_setDefaultVisibility(VisuDataColorizerFragment *frag, gboolean status) { g_return_val_if_fail(VISU_IS_DATA_COLORIZER_FRAGMENT(frag), FALSE); if (frag->priv->defaultVisibility == status) return FALSE; frag->priv->defaultVisibility = status; if (visu_data_colorizer_getActive(VISU_DATA_COLORIZER(frag))) visu_node_masker_emitDirty(VISU_NODE_MASKER(frag)); return TRUE; } static gboolean _colorize(const VisuDataColorizer *colorizer, float rgba[4], const VisuData *visuData _U_, const VisuNode* node) { guint id, i; const VisuNodeFragment *f; const ToolColor *color; const VisuNodeValues *model; model = visu_sourceable_getConstNodeModel(VISU_SOURCEABLE(colorizer)); f = visu_node_values_frag_getAt(VISU_NODE_VALUES_FRAG(model), node); if (!f) return FALSE; switch (VISU_DATA_COLORIZER_FRAGMENT(colorizer)->priv->type) { case COLORIZATION_PER_TYPE: id = 0; for (i = 0; f->label[i]; i++) id += f->label[i]; color = tool_color_new_bright(id); rgba[0] = color->rgba[0]; rgba[1] = color->rgba[1]; rgba[2] = color->rgba[2]; rgba[3] = color->rgba[3]; return TRUE; case COLORIZATION_PER_FRAGMENT: color = tool_color_new_bright(f->id); rgba[0] = color->rgba[0]; rgba[1] = color->rgba[1]; rgba[2] = color->rgba[2]; rgba[3] = color->rgba[3]; return TRUE; default: break; } return FALSE; } static gboolean _maskApply(const VisuNodeMasker *self, VisuNodeArray *array) { VisuDataColorizerFragment *frag; gboolean redraw; VisuNodeValuesIter iter; VisuNodeValues *model; const VisuNodeFragment *f; g_return_val_if_fail(VISU_IS_DATA_COLORIZER_FRAGMENT(self), FALSE); frag = VISU_DATA_COLORIZER_FRAGMENT(self); model = visu_sourceable_getNodeModel(VISU_SOURCEABLE(self)); if (!visu_data_colorizer_getActive(VISU_DATA_COLORIZER(self)) || !model) return FALSE; g_return_val_if_fail(visu_node_values_fromArray(model, array), FALSE); redraw = FALSE; for (visu_node_values_iter_new(&iter, ITER_NODES_VISIBLE, model); iter.iter.node; visu_node_values_iter_next(&iter)) { f = visu_node_values_frag_getAtIter(VISU_NODE_VALUES_FRAG(iter.vals), &iter); if ((f && GPOINTER_TO_INT(g_hash_table_lookup(frag->priv->hidingTable, f->label))) || (!f && !frag->priv->defaultVisibility)) redraw = visu_node_setVisibility(iter.iter.node, FALSE) || redraw; } return redraw; } v_sim-3.8.0/src/extraFunctions/fragColorizer.h000066400000000000000000000132721370110300500214160ustar00rootroot00000000000000/* EXTRAITS DE LA LICENCE Copyright CEA, contributeurs : Damien CALISTE, laboratoire L_Sim, (2017) Adresse mèl : CALISTE, damien P caliste AT cea P fr. Ce logiciel est un programme informatique servant à visualiser des structures atomiques dans un rendu pseudo-3D. Ce logiciel est régi par la licence CeCILL soumise au droit français et respectant les principes de diffusion des logiciels libres. Vous pouvez utiliser, modifier et/ou redistribuer ce programme sous les conditions de la licence CeCILL telle que diffusée par le CEA, le CNRS et l'INRIA sur le site "http://www.cecill.info". Le fait que vous puissiez accéder à cet en-tête signifie que vous avez pris connaissance de la licence CeCILL, et que vous en avez accepté les termes (cf. le fichier Documentation/licence.fr.txt fourni avec ce logiciel). */ /* LICENCE SUM UP Copyright CEA, contributors : Damien CALISTE, laboratoire L_Sim, (2017) E-mail address: CALISTE, damien P caliste AT cea P fr. This software is a computer program whose purpose is to visualize atomic configurations in 3D. This software is governed by the CeCILL license under French law and abiding by the rules of distribution of free software. You can use, modify and/ or redistribute the software under the terms of the CeCILL license as circulated by CEA, CNRS and INRIA at the following URL "http://www.cecill.info". The fact that you are presently reading this means that you have had knowledge of the CeCILL license and that you accept its terms. You can find a copy of this licence shipped with this software at Documentation/licence.en.txt. */ #ifndef FRAGCOLORIZER_H #define FRAGCOLORIZER_H #include #include #include "colorizer.h" #include "fragProp.h" #include G_BEGIN_DECLS /** * VISU_TYPE_DATA_COLORIZER_FRAGMENT: * * return the type of #VisuDataColorizerFragment. */ #define VISU_TYPE_DATA_COLORIZER_FRAGMENT (visu_data_colorizer_fragment_get_type ()) /** * VISU_DATA_COLORIZER_FRAGMENT: * @obj: a #GObject to cast. * * Cast the given @obj into #VisuDataColorizerFragment type. */ #define VISU_DATA_COLORIZER_FRAGMENT(obj) (G_TYPE_CHECK_INSTANCE_CAST(obj, VISU_TYPE_DATA_COLORIZER_FRAGMENT, VisuDataColorizerFragment)) /** * VISU_DATA_COLORIZER_FRAGMENT_CLASS: * @klass: a #GObjectClass to cast. * * Cast the given @klass into #VisuDataColorizerFragmentClass. */ #define VISU_DATA_COLORIZER_FRAGMENT_CLASS(klass) (G_TYPE_CHECK_CLASS_CAST(klass, VISU_TYPE_DATA_COLORIZER_FRAGMENT, VisuDataColorizerFragmentClass)) /** * VISU_IS_DATA_COLORIZER_FRAGMENT: * @obj: a #GObject to test. * * Test if the given @ogj is of the type of #VisuDataColorizerFragment object. */ #define VISU_IS_DATA_COLORIZER_FRAGMENT(obj) (G_TYPE_CHECK_INSTANCE_TYPE(obj, VISU_TYPE_DATA_COLORIZER_FRAGMENT)) /** * VISU_IS_DATA_COLORIZER_FRAGMENT_CLASS: * @klass: a #GObjectClass to test. * * Test if the given @klass is of the type of #VisuDataColorizerFragmentClass class. */ #define VISU_IS_DATA_COLORIZER_FRAGMENT_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE(klass, VISU_TYPE_DATA_COLORIZER_FRAGMENT)) /** * VISU_DATA_COLORIZER_FRAGMENT_GET_CLASS: * @obj: a #GObject to get the class of. * * It returns the class of the given @obj. */ #define VISU_DATA_COLORIZER_FRAGMENT_GET_CLASS(obj) (G_TYPE_INSTANCE_GET_CLASS(obj, VISU_TYPE_DATA_COLORIZER_FRAGMENT, VisuDataColorizerFragmentClass)) /** * VisuDataColorizerFragmentPrivate: * * Private data for #VisuDataColorizerFragment objects. */ typedef struct _VisuDataColorizerFragmentPrivate VisuDataColorizerFragmentPrivate; /** * VisuDataColorizerFragment: * * Common name to refer to a #_VisuDataColorizerFragment. */ typedef struct _VisuDataColorizerFragment VisuDataColorizerFragment; struct _VisuDataColorizerFragment { VisuDataColorizer parent; VisuDataColorizerFragmentPrivate *priv; }; /** * VisuDataColorizerFragmentClass: * @parent: its parent. * * Interface for class that can represent #VisuDataColorizerFragment. * * Since: 3.8 */ typedef struct _VisuDataColorizerFragmentClass VisuDataColorizerFragmentClass; struct _VisuDataColorizerFragmentClass { VisuDataColorizerClass parent; }; /** * visu_data_colorizer_fragment_get_type: * * This method returns the type of #VisuDataColorizerFragment, use * VISU_TYPE_DATA_COLORIZER_FRAGMENT instead. * * Since: 3.8 * * Returns: the type of #VisuDataColorizerFragment. */ GType visu_data_colorizer_fragment_get_type(void); VisuDataColorizerFragment* visu_data_colorizer_fragment_new(); gboolean visu_data_colorizer_fragment_setNodeModel(VisuDataColorizerFragment *colorizer, VisuNodeValuesFrag *model); /** * VisuDataColorizerFragmentTypes: * @COLORIZATION_NONE: no per node colorization. * @COLORIZATION_PER_FRAGMENT: colorize each node of a given fragment * with the same colour. * @COLORIZATION_PER_TYPE: colorize ecah node of the same fragment * family with the same colour. * * The fragment colorization schemes. * * Since: 3.8 */ typedef enum { COLORIZATION_NONE, COLORIZATION_PER_FRAGMENT, COLORIZATION_PER_TYPE } VisuDataColorizerFragmentTypes; gboolean visu_data_colorizer_fragment_setType(VisuDataColorizerFragment *colorizer, VisuDataColorizerFragmentTypes type); gboolean visu_data_colorizer_fragment_setDefaultVisibility(VisuDataColorizerFragment *frag, gboolean status); gboolean visu_data_colorizer_fragment_setVisibility(VisuDataColorizerFragment *frag, const gchar *label, gboolean status); G_END_DECLS #endif v_sim-3.8.0/src/extraFunctions/fragProp.c000066400000000000000000000230651370110300500203620ustar00rootroot00000000000000/* EXTRAITS DE LA LICENCE Copyright CEA, contributeurs : Damien CALISTE, laboratoire L_Sim, (2016) Adresse mèl : CALISTE, damien P caliste AT cea P fr. Ce logiciel est un programme informatique servant à visualiser des structures atomiques dans un rendu pseudo-3D. Ce logiciel est régi par la licence CeCILL soumise au droit français et respectant les principes de diffusion des logiciels libres. Vous pouvez utiliser, modifier et/ou redistribuer ce programme sous les conditions de la licence CeCILL telle que diffusée par le CEA, le CNRS et l'INRIA sur le site "http://www.cecill.info". Le fait que vous puissiez accéder à cet en-tête signifie que vous avez pris connaissance de la licence CeCILL, et que vous en avez accepté les termes (cf. le fichier Documentation/licence.fr.txt fourni avec ce logiciel). */ /* LICENCE SUM UP Copyright CEA, contributors : Damien CALISTE, laboratoire L_Sim, (2016) E-mail address: CALISTE, damien P caliste AT cea P fr. This software is a computer program whose purpose is to visualize atomic configurations in 3D. This software is governed by the CeCILL license under French law and abiding by the rules of distribution of free software. You can use, modify and/ or redistribute the software under the terms of the CeCILL license as circulated by CEA, CNRS and INRIA at the following URL "http://www.cecill.info". The fact that you are presently reading this means that you have had knowledge of the CeCILL license and that you accept its terms. You can find a copy of this licence shipped with this software at Documentation/licence.en.txt. */ #include "fragProp.h" #include #include #include static VisuNodeFragment* _copyFrag(VisuNodeFragment* boxed) { VisuNodeFragment *frag; if (!boxed) return (VisuNodeFragment*)0; frag = g_slice_new(VisuNodeFragment); frag->label = g_strdup(boxed->label); frag->id = boxed->id; return frag; } static void _freeFrag(VisuNodeFragment *boxed) { if (!boxed) return; g_free(boxed->label); g_slice_free(VisuNodeFragment, boxed); } /** * visu_node_fragment_get_type: * * Create and retrieve a #GType for a #VisuNodeFragment object. This * function is mainly intended to be used with visu_node_values_frag_setAt(). * * Since: 3.8 * * Returns: a new type for #VisuNodeFragment structures. */ GType visu_node_fragment_get_type(void) { static GType g_define_type_id = 0; if (g_define_type_id == 0) g_define_type_id = g_boxed_type_register_static("VisuNodeFragment", (GBoxedCopyFunc)_copyFrag, (GBoxedFreeFunc)_freeFrag); return g_define_type_id; } /** * visu_node_fragment_new: * @label: a label. * @id: an id. * * Creates a new #VisuNodeFragment, based on @label and @id. * * Since: 3.8 * * Returns: (transfer full): a newly allocated #VisuNodeFragment structure. **/ VisuNodeFragment* visu_node_fragment_new(const gchar *label, guint id) { VisuNodeFragment *frag; g_return_val_if_fail(label, (VisuNodeFragment*)0); frag = g_malloc(sizeof(VisuNodeFragment)); frag->label = g_strdup(label); frag->id = id; return frag; } /** * SECTION:fragProp * @short_description: define a #VisuNodeValues object to handle frags. * * Defines a #VisuNodeValues object to store frags on every * nodes and get notification for them. */ struct _VisuNodeValuesFragPrivate { gboolean dispose_has_run; GHashTable *labels; }; static void _finalize(GObject *obj); static gboolean _parse(VisuNodeValues *vals, VisuNode *node, const gchar *from); static gchar* _serialize(const VisuNodeValues *vals, const VisuNode *node); G_DEFINE_TYPE_WITH_CODE(VisuNodeValuesFrag, visu_node_values_frag, VISU_TYPE_NODE_VALUES, G_ADD_PRIVATE(VisuNodeValuesFrag)) static void visu_node_values_frag_class_init(VisuNodeValuesFragClass *klass) { /* Connect the overloading methods. */ G_OBJECT_CLASS(klass)->finalize = _finalize; VISU_NODE_VALUES_CLASS(klass)->parse = _parse; VISU_NODE_VALUES_CLASS(klass)->serialize = _serialize; } static void visu_node_values_frag_init(VisuNodeValuesFrag *self) { self->priv = visu_node_values_frag_get_instance_private(self); self->priv->dispose_has_run = FALSE; self->priv->labels = g_hash_table_new_full(g_str_hash, g_str_equal, g_free, NULL); } static void _finalize(GObject* obj) { VisuNodeValuesFrag *self; g_return_if_fail(obj); self = VISU_NODE_VALUES_FRAG(obj); g_hash_table_unref(self->priv->labels); G_OBJECT_CLASS(visu_node_values_frag_parent_class)->finalize(obj); } static gboolean _parse(VisuNodeValues *vals, VisuNode *node, const gchar *from) { VisuNodeFragment frag; gchar *at; gboolean res; frag.label = g_strdup(from); at = strchr(frag.label, ':'); if (!at) { g_free(frag.label); return FALSE; } *at = '\0'; if (sscanf(at + 1, "%u", &frag.id) != 1) { g_free(frag.label); return FALSE; } res = visu_node_values_frag_setAt(VISU_NODE_VALUES_FRAG(vals), node, &frag); g_free(frag.label); return res; } static gchar* _serialize(const VisuNodeValues *vals, const VisuNode *node) { GValue value = {0, {{0}, {0}}}; VisuNodeFragment *frag; if (!visu_node_values_getAt(vals, node, &value)) return (gchar*)0; frag = (VisuNodeFragment*)g_value_get_boxed(&value); if (!frag) return (gchar*)0; return g_strdup_printf("%s: %u", frag->label, frag->id); } /** * visu_node_values_frag_new: * @arr: a #VisuNodeArray object. * @label: a translatable label. * * Create a new frag field located on nodes. * * Since: 3.8 * * Returns: (transfer full): a newly created #VisuNodeValuesFrag object. **/ VisuNodeValuesFrag* visu_node_values_frag_new(VisuNodeArray *arr, const gchar *label) { VisuNodeValuesFrag *vals; vals = VISU_NODE_VALUES_FRAG(g_object_new(VISU_TYPE_NODE_VALUES_FRAG, "nodes", arr, "label", label, "type", VISU_TYPE_NODE_FRAGMENT, NULL)); return vals; } /** * visu_node_values_frag_getAt: * @vect: a #VisuNodeValuesFrag object. * @node: a #VisuNode object. * * Retrieves the float array hosted on @node. * * Since: 3.8 * * Returns: (transfer none): the coordinates of * float array for @node. **/ const VisuNodeFragment* visu_node_values_frag_getAt(VisuNodeValuesFrag *vect, const VisuNode *node) { GValue value = {0, {{0}, {0}}}; g_return_val_if_fail(VISU_IS_NODE_VALUES_FRAG(vect), NULL); visu_node_values_getAt(VISU_NODE_VALUES(vect), node, &value); return g_value_get_boxed(&value); } /** * visu_node_values_frag_getAtIter: * @vect: a #VisuNodeValuesFrag object. * @iter: a #VisuNodeValuesIter object. * * Retrieve the current #VisuNodeFragment of @iter. * * Since: 3.8 * * Returns: A #VisuNodeFragment pointer. **/ const VisuNodeFragment* visu_node_values_frag_getAtIter(VisuNodeValuesFrag *vect, const VisuNodeValuesIter *iter) { g_return_val_if_fail(VISU_IS_NODE_VALUES_FRAG(vect), NULL); return g_value_get_boxed(&iter->value); } /** * visu_node_values_frag_setAt: * @vect: a #VisuNodeValuesFrag object. * @node: a #VisuNode object. * @frag: a #VisuNodeFragment value. * * Changes the frag hosted at @node for one of defined by @str. * * Since: 3.8 * * Returns: TRUE if frag for @node is indeed changed. **/ gboolean visu_node_values_frag_setAt(VisuNodeValuesFrag *vect, const VisuNode *node, const VisuNodeFragment *frag) { GValue value = G_VALUE_INIT; VisuNodeFragment *old; visu_node_values_getAt(VISU_NODE_VALUES(vect), node, &value); old = (VisuNodeFragment*)g_value_get_boxed(&value); if (frag && old && !strcmp(frag->label, old->label) && frag->id == old->id) return FALSE; if (!g_hash_table_contains(vect->priv->labels, frag->label)) g_hash_table_add(vect->priv->labels, g_strdup(frag->label)); g_value_set_static_boxed(&value, frag); return visu_node_values_setAt(VISU_NODE_VALUES(vect), node, &value); } /** * visu_node_values_frag_getLabels: * @frag: a #VisuNodeValuesFrag object. * * Retrieves the set of fragment labels. * * Since: 3.8 * * Returns: (transfer none) (element-type utf8 utf8): a set of labels. **/ GHashTable* visu_node_values_frag_getLabels(VisuNodeValuesFrag *frag) { g_return_val_if_fail(VISU_IS_NODE_VALUES_FRAG(frag), (GHashTable*)0); return frag->priv->labels; } /** * visu_node_values_frag_getNodeIds: * @frag: a #VisuNodeValuesFrag object. * @label: a label. * * Construct a list of node ids which fragment label is matching @label; * * Since: 3.8 * * Returns: (transfer full) (element-type guint): a set of node ids. **/ GArray* visu_node_values_frag_getNodeIds(const VisuNodeValuesFrag *frag, const gchar *label) { GArray *array; VisuNodeValuesIter iter; gboolean valid; g_return_val_if_fail(VISU_IS_NODE_VALUES_FRAG(frag), (GArray*)0); if (!label) return (GArray*)0; array = g_array_new(FALSE, FALSE, sizeof(guint)); for (valid = visu_node_values_iter_new(&iter, ITER_NODES_BY_TYPE, VISU_NODE_VALUES(frag)); valid; valid = visu_node_values_iter_next(&iter)) { const VisuNodeFragment *fragment = g_value_get_boxed(&iter.value); if (fragment && fragment->label && !strcmp(fragment->label, label)) g_array_append_val(array, iter.iter.node->number); } return array; } v_sim-3.8.0/src/extraFunctions/fragProp.h000066400000000000000000000111041370110300500203560ustar00rootroot00000000000000/* EXTRAITS DE LA LICENCE Copyright CEA, contributeurs : Damien CALISTE, laboratoire L_Sim, (2016-2019) Adresse mèl : CALISTE, damien P caliste AT cea P fr. Ce logiciel est un programme informatique servant à visualiser des structures atomiques dans un rendu pseudo-3D. Ce logiciel est régi par la licence CeCILL soumise au droit français et respectant les principes de diffusion des logiciels libres. Vous pouvez utiliser, modifier et/ou redistribuer ce programme sous les conditions de la licence CeCILL telle que diffusée par le CEA, le CNRS et l'INRIA sur le site "http://www.cecill.info". Le fait que vous puissiez accéder à cet en-tête signifie que vous avez pris connaissance de la licence CeCILL, et que vous en avez accepté les termes (cf. le fichier Documentation/licence.fr.txt fourni avec ce logiciel). */ /* LICENCE SUM UP Copyright CEA, contributors : Damien CALISTE, laboratoire L_Sim, (2016-2019) E-mail address: CALISTE, damien P caliste AT cea P fr. This software is a computer program whose purpose is to visualize atomic configurations in 3D. This software is governed by the CeCILL license under French law and abiding by the rules of distribution of free software. You can use, modify and/ or redistribute the software under the terms of the CeCILL license as circulated by CEA, CNRS and INRIA at the following URL "http://www.cecill.info". The fact that you are presently reading this means that you have had knowledge of the CeCILL license and that you accept its terms. You can find a copy of this licence shipped with this software at Documentation/licence.en.txt. */ #ifndef FRAGPROP_H #define FRAGPROP_H #include #include #include "nodeProp.h" G_BEGIN_DECLS /** * VisuNodeFragment: * @label: a label. * @id: the fragment id for this label. * * Defines property for a given fragment. * * Since: 3.8 */ typedef struct _VisuNodeFragment VisuNodeFragment; struct _VisuNodeFragment { gchar *label; guint id; }; #define VISU_TYPE_NODE_FRAGMENT (visu_node_fragment_get_type()) GType visu_node_fragment_get_type(void); VisuNodeFragment* visu_node_fragment_new(const gchar *label, guint id); #define VISU_TYPE_NODE_VALUES_FRAG (visu_node_values_frag_get_type ()) #define VISU_NODE_VALUES_FRAG(obj) (G_TYPE_CHECK_INSTANCE_CAST(obj, VISU_TYPE_NODE_VALUES_FRAG, VisuNodeValuesFrag)) #define VISU_NODE_VALUES_FRAG_CLASS(klass) (G_TYPE_CHECK_CLASS_CAST(klass, VISU_TYPE_NODE_VALUES_FRAG, VisuNodeValuesFragClass)) #define VISU_IS_NODE_VALUES_FRAG(obj) (G_TYPE_CHECK_INSTANCE_TYPE(obj, VISU_TYPE_NODE_VALUES_FRAG)) #define VISU_IS_NODE_VALUES_FRAG_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE(klass, VISU_TYPE_NODE_VALUES_FRAG)) #define VISU_NODE_VALUES_FRAG_GET_CLASS(obj) (G_TYPE_INSTANCE_GET_CLASS(obj, VISU_TYPE_NODE_VALUES_FRAG, VisuNodeValuesFragClass)) /** * VisuNodeValuesFragPrivate: * * Private data for #VisuNodeValuesFrag objects. */ typedef struct _VisuNodeValuesFragPrivate VisuNodeValuesFragPrivate; /** * VisuNodeValuesFrag: * * Common name to refer to a #_VisuNodeValuesFrag. */ typedef struct _VisuNodeValuesFrag VisuNodeValuesFrag; struct _VisuNodeValuesFrag { VisuNodeValues parent; VisuNodeValuesFragPrivate *priv; }; /** * VisuNodeValuesFragClass: * @parent: private. * * Common name to refer to a #_VisuNodeValuesFragClass. */ typedef struct _VisuNodeValuesFragClass VisuNodeValuesFragClass; struct _VisuNodeValuesFragClass { VisuNodeValuesClass parent; }; /** * visu_node_values_frag_get_type: * * This method returns the type of #VisuNodeValuesFrag, use * VISU_TYPE_NODE_VALUES_FRAG instead. * * Since: 3.8 * * Returns: the type of #VisuNodeValuesFrag. */ GType visu_node_values_frag_get_type(void); VisuNodeValuesFrag* visu_node_values_frag_new(VisuNodeArray *arr, const gchar *label); const VisuNodeFragment* visu_node_values_frag_getAt(VisuNodeValuesFrag *vect, const VisuNode *node); const VisuNodeFragment* visu_node_values_frag_getAtIter(VisuNodeValuesFrag *vect, const VisuNodeValuesIter *iter); gboolean visu_node_values_frag_setAt(VisuNodeValuesFrag *vect, const VisuNode *node, const VisuNodeFragment *frag); GHashTable* visu_node_values_frag_getLabels(VisuNodeValuesFrag *frag); GArray* visu_node_values_frag_getNodeIds(const VisuNodeValuesFrag *frag, const gchar *label); G_END_DECLS #endif v_sim-3.8.0/src/extraFunctions/gdiff.c000066400000000000000000000235301370110300500176560ustar00rootroot00000000000000/* EXTRAITS DE LA LICENCE Copyright CEA, contributeurs : Damien CALISTE, laboratoire L_Sim, (2017) Adresse mèl : CALISTE, damien P caliste AT cea P fr. Ce logiciel est un programme informatique servant à visualiser des structures atomiques dans un rendu pseudo-3D. Ce logiciel est régi par la licence CeCILL soumise au droit français et respectant les principes de diffusion des logiciels libres. Vous pouvez utiliser, modifier et/ou redistribuer ce programme sous les conditions de la licence CeCILL telle que diffusée par le CEA, le CNRS et l'INRIA sur le site "http://www.cecill.info". Le fait que vous puissiez accéder à cet en-tête signifie que vous avez pris connaissance de la licence CeCILL, et que vous en avez accepté les termes (cf. le fichier Documentation/licence.fr.txt fourni avec ce logiciel). */ /* LICENCE SUM UP Copyright CEA, contributors : Damien CALISTE, laboratoire L_Sim, (2017) E-mail address: CALISTE, damien P caliste AT cea P fr. This software is a computer program whose purpose is to visualize atomic configurations in 3D. This software is governed by the CeCILL license under French law and abiding by the rules of distribution of free software. You can use, modify and/ or redistribute the software under the terms of the CeCILL license as circulated by CEA, CNRS and INRIA at the following URL "http://www.cecill.info". The fact that you are presently reading this means that you have had knowledge of the CeCILL license and that you accept its terms. You can find a copy of this licence shipped with this software at Documentation/licence.en.txt. */ #include "gdiff.h" #include /** * SECTION:gdiff * @short_description: a #VisuNodeValues object to store displacements * between to #VisuData objects. * * */ struct _VisuDataDiffPrivate { gboolean dispose_has_run; gboolean empty; VisuBox *box; gulong sig_units; }; static void visu_data_diff_dispose(GObject *obj); G_DEFINE_TYPE_WITH_CODE(VisuDataDiff, visu_data_diff, VISU_TYPE_NODE_VALUES_VECTOR, G_ADD_PRIVATE(VisuDataDiff)) static void visu_data_diff_class_init(VisuDataDiffClass *klass) { /* Connect the overloading methods. */ G_OBJECT_CLASS(klass)->dispose = visu_data_diff_dispose; } static void visu_data_diff_init(VisuDataDiff *self) { self->priv = visu_data_diff_get_instance_private(self); self->priv->dispose_has_run = FALSE; self->priv->empty = TRUE; self->priv->box = (VisuBox*)0; } static void visu_data_diff_dispose(GObject *obj) { VisuDataDiff *self = VISU_DATA_DIFF(obj); if (self->priv->dispose_has_run) return; self->priv->dispose_has_run = TRUE; g_object_unref(self->priv->box); G_OBJECT_CLASS(visu_data_diff_parent_class)->dispose(obj); } static void _setBox(VisuDataDiff *self, VisuBox *box) { g_return_if_fail(VISU_IS_DATA_DIFF(self)); if (self->priv->box == box) return; if (self->priv->box) { g_signal_handler_disconnect(self->priv->box, self->priv->sig_units); g_object_unref(self->priv->box); } if (box) { g_object_ref(box); self->priv->sig_units = g_signal_connect_swapped(box, "UnitChanged", G_CALLBACK(visu_node_values_farray_scale), self); } visu_node_values_farray_scale(VISU_NODE_VALUES_FARRAY(self), (self->priv->box && box) ? tool_physic_getUnitConversionFactor (visu_box_getUnit(self->priv->box), visu_box_getUnit(box)) : 1.f); self->priv->box = box; } static void _getPeriodicDistance(float diff[3], const VisuData *data1, const VisuNode *node1, const VisuData *data2, const VisuNode *node2, float factor) { float xyz1[3], xyz2[3]; visu_data_getNodePosition(data1, node1, xyz1); visu_data_getNodePosition(data2, node2, xyz2); diff[0] = xyz1[0] - xyz2[0] * factor; diff[1] = xyz1[1] - xyz2[1] * factor; diff[2] = xyz1[2] - xyz2[2] * factor; visu_box_getPeriodicVector(visu_boxed_getBox(VISU_BOXED(data1)), diff); } /** * visu_data_diff_new: * @dataRef: a #VisuData object. * @data: a #VisuData object. * @reorder: a boolean. * @label: a label. * * Compute the node per node position differences between @dataRef and * @data. If @reorder is %TRUE, the node in @data are reordered to * minimize the distance with @dataRef. If @dataRef and @data are * incompatible, the returned object will be empty, see visu_data_diff_isEmpty(). * * Since: 3.8 * * Returns: (transfer full): a newly created #VisuDataDiff object. **/ VisuDataDiff* visu_data_diff_new(const VisuData *dataRef, VisuData *data, gboolean reorder, const gchar *label) { VisuDataDiff *data_diff; VisuNodeArrayIter iter, iterRef; float diff[3], factor; data_diff = g_object_new(VISU_TYPE_DATA_DIFF, "nodes", data, "label", label, "type", G_TYPE_FLOAT, "n-elements", 6, NULL); /* Check compatibility of population. */ if (visu_node_array_getNNodes(VISU_NODE_ARRAY(data)) != visu_node_array_getNNodes(VISU_NODE_ARRAY_CONST(dataRef))) return data_diff; /* if (iter.nElements != iterRef.nElements) */ /* return data_diff; */ /* for (visu_node_array_iterStart(VISU_NODE_ARRAY(data), &iter), */ /* visu_node_array_iterStart(VISU_NODE_ARRAY(dataRef), &iterRef); */ /* iter.element && iterRef.element; */ /* visu_node_array_iterNextElement(VISU_NODE_ARRAY(data), &iter, FALSE), */ /* visu_node_array_iterNextElement(VISU_NODE_ARRAY(dataRef), &iterRef, FALSE)) */ /* if (iter.nStoredNodes != iterRef.nStoredNodes) */ /* return data_diff; */ if (reorder) visu_data_reorder(data, dataRef); factor = tool_physic_getUnitConversionFactor (visu_box_getUnit(visu_boxed_getBox(VISU_BOXED(dataRef))), visu_box_getUnit(visu_boxed_getBox(VISU_BOXED(data)))); visu_node_array_iter_new(VISU_NODE_ARRAY(data), &iter); visu_node_array_iter_new(VISU_NODE_ARRAY((VisuNodeArray*)dataRef), &iterRef); for (visu_node_array_iterStartNumber(VISU_NODE_ARRAY(data), &iter), visu_node_array_iterStartNumber(VISU_NODE_ARRAY((VisuNodeArray*)dataRef), &iterRef); iter.node && iterRef.node; visu_node_array_iterNextNodeNumber(VISU_NODE_ARRAY(data), &iter), visu_node_array_iterNextNodeNumber(VISU_NODE_ARRAY((VisuNodeArray*)dataRef), &iterRef)) { _getPeriodicDistance(diff, data, iter.node, dataRef, iterRef.node, factor); visu_node_values_vector_setAt(VISU_NODE_VALUES_VECTOR(data_diff), iter.node, diff); } g_signal_connect_object(data, "setBox", G_CALLBACK(_setBox), data_diff, G_CONNECT_SWAPPED); _setBox(data_diff, visu_boxed_getBox(VISU_BOXED(data))); data_diff->priv->empty = FALSE; return data_diff; } /** * visu_data_diff_isEmpty: * @self: a #VisuDataDiff object. * * When creating a #VisuDataDiff, if the reference and the data don't * have the same number of types or atoms, the difference cannot be * computed and the created object is empty. * * Since: 3.8 * * Returns: TRUE if there is no difference data stored. **/ gboolean visu_data_diff_isEmpty(const VisuDataDiff *self) { g_return_val_if_fail(VISU_IS_DATA_DIFF(self), TRUE); return self->priv->empty; } /** * visu_data_diff_export: * @self: a #VisuDataDiff object. * * Create a string with differences of coordinates stored in @self in * cartesian coordinates. * * Since: 3.6 * * Returns: a new string that should be freed after use. */ gchar* visu_data_diff_export(const VisuDataDiff *self) { GString *output; gboolean start; VisuNodeValuesIter iter; gfloat *data; gfloat zeros[3] = {0.f, 0.f, 0.f}; g_return_val_if_fail(VISU_IS_DATA_DIFF(self), (gchar*)0); if (self->priv->empty) return (gchar*)0; start = TRUE; output = g_string_new("#metaData: diff=[ \\\n"); for (visu_node_values_iter_new(&iter, ITER_NODES_BY_TYPE, VISU_NODE_VALUES(self)); iter.iter.node; visu_node_values_iter_next(&iter)) { data = (gfloat*)g_value_get_pointer(&iter.value); if (!data) data = zeros; if (!start) output = g_string_append(output, "; \\\n"); g_string_append_printf(output, "# %12.8f; %12.8f; %12.8f", data[0], data[1], data[2]); start = FALSE; } output = g_string_append(output, " \\\n# ]\n"); return g_string_free(output, FALSE); } /** * visu_data_diff_applyWithFinder: * @geodiff: a #VisuDataDiff object with a displacement field. * @finder: a #VisuNodeFinder to apply the displacement on. * @tol: a tolerance. * * For each node displacement of @geodiff, if a matching node in * @finder is found within the tolerance @tol, then the displacement * is applied. * * Since: 3.8 **/ void visu_data_diff_applyWithFinder(const VisuDataDiff *geodiff, VisuNodeFinder *finder, gfloat tol) { VisuData *data; VisuNodeArray *target; VisuNodeValuesIter iter; gfloat xyz[3]; const gfloat *diff; gint id; data = VISU_DATA(visu_node_values_getArray(VISU_NODE_VALUES(geodiff))); target = VISU_NODE_ARRAY(visu_node_finder_getData(finder)); visu_node_array_startMoving(target); for (visu_node_values_iter_new(&iter, ITER_NODES_BY_TYPE, VISU_NODE_VALUES(geodiff)); iter.iter.node; visu_node_values_iter_next(&iter)) { visu_data_getNodePosition(data, iter.iter.node, xyz); id = visu_node_finder_lookup(finder, xyz, tol); if (id >= 0 && (diff = visu_node_values_farray_getAtIter (VISU_NODE_VALUES_FARRAY(geodiff), &iter))) visu_node_array_shiftNode(target, id, diff); } visu_node_array_completeMoving(target); g_object_unref(data); } v_sim-3.8.0/src/extraFunctions/gdiff.h000066400000000000000000000104171370110300500176630ustar00rootroot00000000000000/* EXTRAITS DE LA LICENCE Copyright CEA, contributeurs : Damien CALISTE, laboratoire L_Sim, (2017) Adresse mèl : CALISTE, damien P caliste AT cea P fr. Ce logiciel est un programme informatique servant à visualiser des structures atomiques dans un rendu pseudo-3D. Ce logiciel est régi par la licence CeCILL soumise au droit français et respectant les principes de diffusion des logiciels libres. Vous pouvez utiliser, modifier et/ou redistribuer ce programme sous les conditions de la licence CeCILL telle que diffusée par le CEA, le CNRS et l'INRIA sur le site "http://www.cecill.info". Le fait que vous puissiez accéder à cet en-tête signifie que vous avez pris connaissance de la licence CeCILL, et que vous en avez accepté les termes (cf. le fichier Documentation/licence.fr.txt fourni avec ce logiciel). */ /* LICENCE SUM UP Copyright CEA, contributors : Damien CALISTE, laboratoire L_Sim, (2017) E-mail address: CALISTE, damien P caliste AT cea P fr. This software is a computer program whose purpose is to visualize atomic configurations in 3D. This software is governed by the CeCILL license under French law and abiding by the rules of distribution of free software. You can use, modify and/ or redistribute the software under the terms of the CeCILL license as circulated by CEA, CNRS and INRIA at the following URL "http://www.cecill.info". The fact that you are presently reading this means that you have had knowledge of the CeCILL license and that you accept its terms. You can find a copy of this licence shipped with this software at Documentation/licence.en.txt. */ #ifndef GDIFF_H #define GDIFF_H #include #include #include "vectorProp.h" #include "finder.h" #include G_BEGIN_DECLS /** * VISU_TYPE_DATA_DIFF: * * return the type of #VisuDataDiff. */ #define VISU_TYPE_DATA_DIFF (visu_data_diff_get_type ()) /** * VISU_DATA_DIFF: * @obj: a #GObject to cast. * * Cast the given @obj into #VisuDataDiff type. */ #define VISU_DATA_DIFF(obj) (G_TYPE_CHECK_INSTANCE_CAST(obj, VISU_TYPE_DATA_DIFF, VisuDataDiff)) /** * VISU_DATA_DIFF_CLASS: * @klass: a #GObjectClass to cast. * * Cast the given @klass into #VisuDataDiffClass. */ #define VISU_DATA_DIFF_CLASS(klass) (G_TYPE_CHECK_CLASS_CAST(klass, VISU_TYPE_DATA_DIFF, VisuDataDiffClass)) /** * VISU_IS_DATA_DIFF: * @obj: a #GObject to test. * * Test if the given @ogj is of the type of #VisuDataDiff object. */ #define VISU_IS_DATA_DIFF(obj) (G_TYPE_CHECK_INSTANCE_TYPE(obj, VISU_TYPE_DATA_DIFF)) /** * VISU_IS_DATA_DIFF_CLASS: * @klass: a #GObjectClass to test. * * Test if the given @klass is of the type of #VisuDataDiffClass class. */ #define VISU_IS_DATA_DIFF_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE(klass, VISU_TYPE_DATA_DIFF)) /** * VISU_DATA_DIFF_GET_CLASS: * @obj: a #GObject to get the class of. * * It returns the class of the given @obj. */ #define VISU_DATA_DIFF_GET_CLASS(obj) (G_TYPE_INSTANCE_GET_CLASS(obj, VISU_TYPE_DATA_DIFF, VisuDataDiffClass)) typedef struct _VisuDataDiffPrivate VisuDataDiffPrivate; /** * VisuDataDiff: * * Common name to refer to a #VisuDataDiff. */ typedef struct _VisuDataDiff VisuDataDiff; struct _VisuDataDiff { VisuNodeValuesVector parent; VisuDataDiffPrivate *priv; }; /** * VisuDataDiffClass: * @parent: private. * * Common name to refer to a #VisuDataDiffClass. */ typedef struct _VisuDataDiffClass VisuDataDiffClass; struct _VisuDataDiffClass { VisuNodeValuesVectorClass parent; }; /** * visu_data_diff_get_type: * * This method returns the type of #VisuDataDiff, use * VISU_TYPE_DATA_DIFF instead. * * Since: 3.8 * * Returns: the type of #VisuDataDiff. */ GType visu_data_diff_get_type(void); /** * VISU_DATA_DIFF_DEFAULT_ID: * * A default label that is used to store a #VisuDataDiff in a #VisuData. * * Since: 3.8 */ #define VISU_DATA_DIFF_DEFAULT_ID "geometry_diff" VisuDataDiff* visu_data_diff_new(const VisuData *dataRef, VisuData *data, gboolean reorder, const gchar *label); gboolean visu_data_diff_isEmpty(const VisuDataDiff *self); gchar* visu_data_diff_export(const VisuDataDiff *self); void visu_data_diff_applyWithFinder(const VisuDataDiff *geodiff, VisuNodeFinder *finder, gfloat tol); G_END_DECLS #endif v_sim-3.8.0/src/extraFunctions/geometry.c000066400000000000000000000627041370110300500204400ustar00rootroot00000000000000/* EXTRAITS DE LA LICENCE Copyright CEA, contributeurs : Luc BILLARD et Damien CALISTE, laboratoire L_Sim, (2001-2005) Adresse mèl : BILLARD, non joignable par mèl ; CALISTE, damien P caliste AT cea P fr. Ce logiciel est un programme informatique servant à visualiser des structures atomiques dans un rendu pseudo-3D. Ce logiciel est régi par la licence CeCILL soumise au droit français et respectant les principes de diffusion des logiciels libres. Vous pouvez utiliser, modifier et/ou redistribuer ce programme sous les conditions de la licence CeCILL telle que diffusée par le CEA, le CNRS et l'INRIA sur le site "http://www.cecill.info". Le fait que vous puissiez accéder à cet en-tête signifie que vous avez pris connaissance de la licence CeCILL, et que vous en avez accepté les termes (cf. le fichier Documentation/licence.fr.txt fourni avec ce logiciel). */ /* LICENCE SUM UP Copyright CEA, contributors : Luc BILLARD et Damien CALISTE, laboratoire L_Sim, (2001-2005) E-mail address: BILLARD, not reachable any more ; CALISTE, damien P caliste AT cea P fr. This software is a computer program whose purpose is to visualize atomic configurations in 3D. This software is governed by the CeCILL license under French law and abiding by the rules of distribution of free software. You can use, modify and/ or redistribute the software under the terms of the CeCILL license as circulated by CEA, CNRS and INRIA at the following URL "http://www.cecill.info". The fact that you are presently reading this means that you have had knowledge of the CeCILL license and that you accept its terms. You can find a copy of this licence shipped with this software at Documentation/licence.en.txt. */ #include "geometry.h" #include #include #include #include /** * SECTION:geometry * @short_description: different routines to do high level geometry * studies on a box or a set of boxes. * * The first possibility of the #geometry section is to make a * two by two difference node position difference between two * #VisuData objects. The #VisuNode positions are compared (number to number and * not closed equivalent to closed equivalent) and stored for * visualisation. The visualisation is done through small arrows * position on the currently visualised file. * * Since: 3.5 */ enum PathItem { PATH_ITEM_COORD, PATH_ITEM_DELTA }; struct Item_ { enum PathItem type; guint time; float dxyz[3]; float energy; }; typedef struct Path_ { guint nodeId; /* A per node translation. */ float translation[3]; guint size, nItems; struct Item_ *items; } Path; /** * VisuPaths: * * An opaque structure to save a set of paths. * * Since: 3.6 */ struct _VisuPaths { guint refCount; /* The current time stamp. */ guint time; /* The global translation. */ float translation[3]; /* The min/max for the possible energies along the paths. */ float minE, maxE; ToolShade *shade; /* A list of Path elements. */ GList *lst; }; #define GEOMETRY_PATH_ALLOC_SIZE 50 /** * visu_paths_get_type: * @void: nothing. * * Create and retrieve a #GType for a #VisuPaths object. * * Since: 3.7 * * Returns: a new type for #VisuPaths structures. **/ GType visu_paths_get_type(void) { static GType g_define_type_id = 0; if (g_define_type_id == 0) g_define_type_id = g_boxed_type_register_static("VisuPaths", (GBoxedCopyFunc)visu_paths_ref, (GBoxedFreeFunc)visu_paths_unref); return g_define_type_id; } /** * visu_paths_new: * @translation: (in) (array fixed-size=3): the current box translation (cartesian). * * Create a new #VisuPaths object. * * Since: 3.6 * * Returns: the newly create object #VisuPaths, to be freed with * visu_paths_free(). */ VisuPaths* visu_paths_new(float translation[3]) { VisuPaths *paths; paths = g_malloc(sizeof(VisuPaths)); paths->refCount = 1; paths->time = 0; paths->translation[0] = translation[0]; paths->translation[1] = translation[1]; paths->translation[2] = translation[2]; paths->shade = (ToolShade*)0; paths->minE = G_MAXFLOAT; paths->maxE = -G_MAXFLOAT; paths->lst = (GList*)0; return paths; } /** * visu_paths_ref: * @paths: a #VisuPaths object. * * Increase the ref counter. * * Since: 3.7 * * Returns: itself. **/ VisuPaths* visu_paths_ref(VisuPaths *paths) { paths->refCount += 1; return paths; } /** * visu_paths_unref: * @paths: a #VisuPaths object. * * Decrease the ref counter, free all memory if counter reachs zero. * * Since: 3.7 **/ void visu_paths_unref(VisuPaths *paths) { paths->refCount -= 1; if (!paths->refCount) visu_paths_free(paths); } static Path* newPath() { Path *path; path = g_malloc(sizeof(Path)); path->size = GEOMETRY_PATH_ALLOC_SIZE; path->items = g_malloc(sizeof(struct Item_) * path->size); path->nItems = 0; return path; } static Path* addPathItem(Path *path, guint time, float xyz[3], enum PathItem type, float energy) { DBG_fprintf(stderr, "Visu Geometry: add a new item for path %p.\n", (gpointer)path); if (!path) /* We create a new path for the given node id. */ path = newPath(); /* We reallocate if necessary. */ if (path->nItems == path->size) { path->size += GEOMETRY_PATH_ALLOC_SIZE; path->items = g_realloc(path->items, sizeof(struct Item_) * path->size); } /* If previous type was PATH_ITEM_COORD and new is also PATH_ITEM_COORD we remove the previous one. */ if (path->nItems > 0 && path->items[path->nItems - 1].type == PATH_ITEM_COORD && type == PATH_ITEM_COORD) path->nItems -= 1; /* We add the new delta to the path. */ path->items[path->nItems].time = time; path->items[path->nItems].type = type; path->items[path->nItems].dxyz[0] = xyz[0]; path->items[path->nItems].dxyz[1] = xyz[1]; path->items[path->nItems].dxyz[2] = xyz[2]; path->items[path->nItems].energy = (energy == G_MAXFLOAT)?-G_MAXFLOAT:energy; path->nItems += 1; return path; } /** * visu_paths_addNodeStep: * @paths: a set of paths. * @time: the flag that give the number of expansion to update. * @nodeId: the node to expand the path of. * @xyz: the current position of the path. * @dxyz: the variation in the path. * @energy: the energy of the system. * * This routine expand the path for the given @nodeId at position @xyz * of @dxyz. The @energy value will be used only if * visu_paths_setToolShade() is used with a non NULL #ToolShade. In that * case the @energy value will be used to colourise the provided path. * * Since: 3.6 * * Returns: TRUE if a new path is started. */ gboolean visu_paths_addNodeStep(VisuPaths *paths, guint time, guint nodeId, float xyz[3], float dxyz[3], float energy) { GList *tmpLst; Path *path; gboolean new; /* Look for a Path with the good node id. */ new = FALSE; for (tmpLst = paths->lst; tmpLst && ((Path*)tmpLst->data)->nodeId != nodeId; tmpLst = g_list_next(tmpLst)); if (!tmpLst) { /* We create a new path for the given node id. */ path = addPathItem((Path*)0, time, xyz, PATH_ITEM_COORD, energy); path->nodeId = nodeId; path->translation[0] = paths->translation[0]; path->translation[1] = paths->translation[1]; path->translation[2] = paths->translation[2]; paths->lst = g_list_prepend(paths->lst, (gpointer)path); new = TRUE; } else path = (Path*)tmpLst->data; addPathItem(path, time, dxyz, PATH_ITEM_DELTA, energy); if (energy != G_MAXFLOAT) { paths->minE = MIN(paths->minE, energy); paths->maxE = MAX(paths->maxE, energy); } return new; } /** * visu_paths_empty: * @paths: a #VisuPaths object. * * Reinitialise internal values of a given @paths. * * Since: 3.6 */ void visu_paths_empty(VisuPaths *paths) { GList *tmpLst; Path *path; g_return_if_fail(paths); for (tmpLst = paths->lst; tmpLst; tmpLst = g_list_next(tmpLst)) { path = (Path*)tmpLst->data; g_free(path->items); g_free(path); } g_list_free(paths->lst); paths->lst = (GList*)0; paths->minE = G_MAXFLOAT; paths->maxE = -G_MAXFLOAT; paths->time = 0; } /** * visu_paths_free: * @paths: a #VisuPaths object. * * Free a set of paths. * * Since: 3.6 */ void visu_paths_free(VisuPaths *paths) { visu_paths_empty(paths); if (paths->shade) tool_shade_free(paths->shade); g_free(paths); } /** * visu_paths_addFromDiff: * @data: a #VisuData object with a geometry difference (see * visu_geodiff_new()). * @paths: the set of paths to extend. * @energy: the current total energy, if any, otherwise use %G_MAXFLOAT. * * This routine read the geometry difference hold in @data and add a * new step in the set of paths. If new paths are created, one * should call visu_paths_setTranslation() to be sure that all * paths are moved inside the box. * * Since: 3.6 * * Returns: TRUE if new paths have been added. */ gboolean visu_paths_addFromDiff(VisuPaths *paths, VisuDataDiff *data, gdouble energy) { VisuNodeValuesIter iter; float *diff, xyz[3]; gboolean new; if (visu_data_diff_isEmpty(data)) return FALSE; if (energy == G_MAXFLOAT) energy = paths->minE; new = FALSE; for (visu_node_values_iter_new(&iter, ITER_NODES_BY_TYPE, VISU_NODE_VALUES(data)); iter.iter.node; visu_node_values_iter_next(&iter)) { diff = (gfloat*)g_value_get_pointer(&iter.value); if (diff[3] > 0.01f) { xyz[0] = iter.iter.node->xyz[0] - diff[0]; xyz[1] = iter.iter.node->xyz[1] - diff[1]; xyz[2] = iter.iter.node->xyz[2] - diff[2]; new = visu_paths_addNodeStep(paths, paths->time, iter.iter.node->number, xyz, diff, (float)energy) || new; } } paths->time += 1; return new; } /** * visu_paths_getLength: * @paths: a #VisuPaths object. * * Get the number of steps stored in a #VisuPaths. * * Since: 3.6 * * Returns: the number of steps. */ guint visu_paths_getLength(VisuPaths *paths) { g_return_val_if_fail(paths, 0); return paths->time; } /** * visu_paths_setTranslation: * @paths: a #VisuPaths object. * @cartCoord: three floats. * * Change the translation of the path, stored in cartesian * coordinates. * * Since: 3.6 */ void visu_paths_setTranslation(VisuPaths *paths, float cartCoord[3]) { g_return_if_fail(paths); paths->translation[0] = cartCoord[0]; paths->translation[1] = cartCoord[1]; paths->translation[2] = cartCoord[2]; } /** * visu_paths_constrainInBox: * @paths: a #VisuPaths object. * @data: a #VisuData object. * * Modify the corrdinates of the path nodes to contraint them in a box * (when applying translations for instance). * * Since: 3.6 */ void visu_paths_constrainInBox(VisuPaths *paths, VisuData *data) { VisuBox *box; float t[3], xyz[3]; GList *tmpLst; Path *path; g_return_if_fail(paths && data); box = visu_boxed_getBox(VISU_BOXED(data)); for(tmpLst = paths->lst; tmpLst; tmpLst = g_list_next(tmpLst)) { path = (Path*)tmpLst->data; xyz[0] = path->items[0].dxyz[0] + paths->translation[0]; xyz[1] = path->items[0].dxyz[1] + paths->translation[1]; xyz[2] = path->items[0].dxyz[2] + paths->translation[2]; visu_box_constrainInside(box, t, xyz, TRUE); path->translation[0] = t[0] + paths->translation[0]; path->translation[1] = t[1] + paths->translation[1]; path->translation[2] = t[2] + paths->translation[2]; } } /** * visu_paths_pinPositions: * @paths: a #VisuPaths object. * @data: a #VisuData object. * * Use the current positions of @data to extend @paths. * * Since: 3.6 */ void visu_paths_pinPositions(VisuPaths *paths, VisuData *data) { VisuNodeArrayIter iter; GList *tmpLst; gdouble energy; g_return_if_fail(paths && data); g_object_get(G_OBJECT(data), "totalEnergy", &energy, NULL); if (energy == G_MAXFLOAT) energy = paths->minE; DBG_fprintf(stderr, "Visu Geometry: pin current positions.\n"); visu_node_array_iter_new(VISU_NODE_ARRAY(data), &iter); for (visu_node_array_iterStart(VISU_NODE_ARRAY(data), &iter); iter.node; visu_node_array_iterNext(VISU_NODE_ARRAY(data), &iter)) { for (tmpLst = paths->lst; tmpLst; tmpLst = g_list_next(tmpLst)) if (((Path*)tmpLst->data)->nodeId == iter.node->number) break; if (tmpLst) addPathItem((Path*)tmpLst->data, paths->time, iter.node->xyz, PATH_ITEM_COORD, (float)energy); } if (energy != G_MAXFLOAT) { paths->minE = MIN(paths->minE, (float)energy); paths->maxE = MAX(paths->maxE, (float)energy); } } /** * visu_paths_setToolShade: * @paths: a #VisuPaths object. * @shade: a #ToolShade object. * * Set the colourisation scheme for the path. * * Since: 3.6 * * Returns: TRUE is the scheme is changed. */ gboolean visu_paths_setToolShade(VisuPaths *paths, const ToolShade* shade) { g_return_val_if_fail(paths, FALSE); if (tool_shade_compare(paths->shade, shade)) return FALSE; if (paths->shade) tool_shade_free(paths->shade); paths->shade = tool_shade_copy(shade); return TRUE; } /** * visu_paths_getToolShade: * @paths: a #VisuPaths object. * * The paths are drawn with a colourisation scheme. * * Since: 3.6 * * Returns: the #ToolShade used by the @paths. */ const ToolShade* visu_paths_getToolShade(const VisuPaths *paths) { g_return_val_if_fail(paths, (const ToolShade*)0); return paths->shade; } /*********************/ /* Drawing routines. */ /*********************/ static void drawPath(Path *path, ToolShade *shade, float min, float max) { guint i; float xyz[3], rgba[4]; g_return_if_fail(path); /* DBG_fprintf(stderr, "Geometry: draw path for node %d.\n", path->nodeId); */ if (!shade) glColor3f(0.f, 0.f, 0.f); for (i = 0; i < path->nItems; i++) { if (path->items[i].type == PATH_ITEM_COORD) { if (i > 0) glEnd(); glBegin(GL_LINE_STRIP); xyz[0] = path->items[i].dxyz[0] + path->translation[0]; xyz[1] = path->items[i].dxyz[1] + path->translation[1]; xyz[2] = path->items[i].dxyz[2] + path->translation[2]; } else { xyz[0] += path->items[i].dxyz[0]; xyz[1] += path->items[i].dxyz[1]; xyz[2] += path->items[i].dxyz[2]; } if (shade) { tool_shade_valueToRGB (shade, rgba, CLAMP((path->items[i].energy - min) / (max - min), 0., 1.)); glColor3fv(rgba); } glVertex3fv(xyz); } glEnd(); glEnable(GL_POINT_SMOOTH); glBegin(GL_POINTS); for (i = 0; i < path->nItems; i++) { if (path->items[i].type == PATH_ITEM_COORD) { xyz[0] = path->items[i].dxyz[0] + path->translation[0]; xyz[1] = path->items[i].dxyz[1] + path->translation[1]; xyz[2] = path->items[i].dxyz[2] + path->translation[2]; } else { xyz[0] += path->items[i].dxyz[0]; xyz[1] += path->items[i].dxyz[1]; xyz[2] += path->items[i].dxyz[2]; } if (shade) { tool_shade_valueToRGB (shade, rgba, CLAMP((path->items[i].energy - min) / (max - min), 0., 1.)); glColor3fv(rgba); } glVertex3fv(xyz); } glEnd(); glDisable(GL_POINT_SMOOTH); } /** * visu_paths_draw: * @paths: a set of paths. * @pathWidth: the width for the drawn path * * OpenGL calls to create the paths. * * Since: 3.6 */ void visu_paths_draw(VisuPaths *paths, float pathWidth) { GList *tmpLst; ToolShade *shade; if (ABS(paths->maxE - paths->minE) < 1e-6) shade = (ToolShade*)0; else shade = paths->shade; glDisable(GL_LIGHTING); glDepthMask(0); glColor3f(0.f, 0.f, 0.f); glLineWidth(pathWidth); glPointSize(pathWidth); for (tmpLst = paths->lst; tmpLst; tmpLst = g_list_next(tmpLst)) drawPath((Path*)tmpLst->data, shade, paths->minE, paths->maxE); glDepthMask(1); glEnable(GL_LIGHTING); } /*****************************/ /* XML files for iso-values. */ /*****************************/ /* */ /* Known elements. */ #define GEOMETRY_ELEMENT_PATHES "paths" #define GEOMETRY_ELEMENT_PATH "path" #define GEOMETRY_ELEMENT_ITEM "item" /* Known attributes. */ #define GEOMETRY_ATTRIBUTE_TIME "time" #define GEOMETRY_ATTRIBUTE_TRANS "translat" #define GEOMETRY_ATTRIBUTE_NODE "nodeId" #define GEOMETRY_ATTRIBUTE_TYPE "type" #define GEOMETRY_ATTRIBUTE_COORD "coordinates" #define GEOMETRY_ATTRIBUTE_TOT_E "totalEnergy" static guint timeShift; static gboolean startVisuPaths; static Path *currentPath; /* This method is called for every element that is parsed. The user_data must be a GList of _pick_xml. When a 'surface' element, a new struct instance is created and prepend in the list. When 'hidden-by-planes' or other qualificative elements are found, the first surface of the list is modified accordingly. */ static void geometryXML_element(GMarkupParseContext *context _U_, const gchar *element_name, const gchar **attribute_names, const gchar **attribute_values, gpointer user_data, GError **error) { VisuPaths *paths; int i, n; guint val, time, type; float t[3], en; gboolean ok; GList *tmpLst; g_return_if_fail(user_data); paths = (VisuPaths*)user_data; DBG_fprintf(stderr, "Geometry: found '%s' element.\n", element_name); if (!g_ascii_strcasecmp(element_name, GEOMETRY_ELEMENT_PATHES)) { /* Initialise the pathList. */ if (startVisuPaths) { g_set_error(error, G_MARKUP_ERROR, G_MARKUP_ERROR_PARSE, _("DTD error: element '%s' should appear only once."), GEOMETRY_ELEMENT_PATHES); return; } startVisuPaths = TRUE; /* Parse the attributes. */ for (i = 0; attribute_names[i]; i++) { /* Possible translation. */ if (!g_ascii_strcasecmp(attribute_names[i], GEOMETRY_ATTRIBUTE_TRANS)) { n = sscanf(attribute_values[i], "%f;%f;%f", t, t + 1, t + 2); if (n != 3) { g_set_error(error, G_MARKUP_ERROR, G_MARKUP_ERROR_PARSE, _("DTD error: attribute '%s' has an unknown value '%s'."), GEOMETRY_ATTRIBUTE_TRANS, attribute_values[i]); return; } paths->translation[0] = t[0]; paths->translation[1] = t[1]; paths->translation[2] = t[2]; } } } else if (!g_ascii_strcasecmp(element_name, GEOMETRY_ELEMENT_PATH)) { if (!startVisuPaths) { g_set_error(error, G_MARKUP_ERROR, G_MARKUP_ERROR_INVALID_CONTENT, _("DTD error: parent element '%s' of element '%s' is missing."), GEOMETRY_ELEMENT_PATHES, GEOMETRY_ELEMENT_PATH); return; } /* We parse the attributes. */ val = 123456789; t[0] = 0.f; t[1] = 0.f; t[2] = 0.f; for (i = 0; attribute_names[i]; i++) { ok = TRUE; if (!g_ascii_strcasecmp(attribute_names[i], GEOMETRY_ATTRIBUTE_NODE)) ok = (sscanf(attribute_values[i], "%u", &val) == 1); else if (!g_ascii_strcasecmp(attribute_names[i], GEOMETRY_ATTRIBUTE_TRANS)) ok = (sscanf(attribute_values[i], "%f;%f;%f", t, t + 1, t + 2) == 3); if (!ok) { g_set_error(error, G_MARKUP_ERROR, G_MARKUP_ERROR_PARSE, _("DTD error: attribute '%s' has an unknown value '%s'."), GEOMETRY_ATTRIBUTE_NODE, attribute_values[i]); return; } } if (val == 123456789) { g_set_error(error, G_MARKUP_ERROR, G_MARKUP_ERROR_PARSE, _("DTD error: element '%s' have missing mandatory attributes."), GEOMETRY_ELEMENT_PATH); return; } for (tmpLst = paths->lst; tmpLst && ((Path*)tmpLst->data)->nodeId != val; tmpLst = g_list_next(tmpLst)); if (!tmpLst) { currentPath = newPath(); currentPath->nodeId = val; currentPath->translation[0] = t[0]; currentPath->translation[1] = t[1]; currentPath->translation[2] = t[2]; paths->lst = g_list_prepend(paths->lst, (gpointer)currentPath); } else currentPath = (Path*)tmpLst->data; } else if (!g_ascii_strcasecmp(element_name, GEOMETRY_ELEMENT_ITEM)) { if (!currentPath) { g_set_error(error, G_MARKUP_ERROR, G_MARKUP_ERROR_INVALID_CONTENT, _("DTD error: parent element '%s' of element '%s' is missing."), GEOMETRY_ELEMENT_PATH, GEOMETRY_ELEMENT_ITEM); return; } /* We parse the attributes. */ type = 999; time = 123456789; t[0] = G_MAXFLOAT; en = G_MAXFLOAT; for (i = 0; attribute_names[i]; i++) { ok = TRUE; if (!g_ascii_strcasecmp(attribute_names[i], GEOMETRY_ATTRIBUTE_TIME)) ok = (sscanf(attribute_values[i], "%u", &time) == 1); else if (!g_ascii_strcasecmp(attribute_names[i], GEOMETRY_ATTRIBUTE_TYPE)) { if (!g_ascii_strcasecmp(attribute_values[i], "dot")) type = PATH_ITEM_COORD; else if (!g_ascii_strcasecmp(attribute_values[i], "delta")) type = PATH_ITEM_DELTA; ok = (type != 999); } else if (!g_ascii_strcasecmp(attribute_names[i], GEOMETRY_ATTRIBUTE_COORD)) ok = (sscanf(attribute_values[i], "%f;%f;%f", t, t + 1, t + 2) == 3); else if (!g_ascii_strcasecmp(attribute_names[i], GEOMETRY_ATTRIBUTE_TOT_E)) ok = (sscanf(attribute_values[i], "%f", &en) == 1); if (!ok) { g_set_error(error, G_MARKUP_ERROR, G_MARKUP_ERROR_PARSE, _("DTD error: attribute '%s' has an unknown value '%s'."), GEOMETRY_ATTRIBUTE_NODE, attribute_values[i]); return; } } if (time == 123456789 || type == 999 || t[0] == G_MAXFLOAT) { g_set_error(error, G_MARKUP_ERROR, G_MARKUP_ERROR_PARSE, _("DTD error: element '%s' have missing mandatory attributes."), GEOMETRY_ELEMENT_PATH); return; } addPathItem(currentPath, time + timeShift, t, type, en); paths->time = MAX(time + timeShift + 1, paths->time); if (en != G_MAXFLOAT) { paths->minE = MIN(en, paths->minE); paths->maxE = MAX(en, paths->maxE); } } else if (startVisuPaths) { /* We silently ignore the element if pathList is unset, but raise an error if pathList has been set. */ g_set_error(error, G_MARKUP_ERROR, G_MARKUP_ERROR_UNKNOWN_ELEMENT, _("Unexpected element '%s'."), element_name); } } /** * visu_paths_parseFromXML: * @filename: a location on disk. * @paths: a #VisuPaths object. * @error: a pointer on an error. * * Read an XML containing a description of @paths. @paths is newly * created on success and should be freed with visu_paths_free(). * * Since: 3.6 * * Returns: TRUE on success. */ gboolean visu_paths_parseFromXML(const gchar* filename, VisuPaths *paths, GError **error) { GMarkupParseContext* xmlContext; GMarkupParser parser; gboolean status; gchar *buffer; gsize size; g_return_val_if_fail(filename, FALSE); g_return_val_if_fail(paths, FALSE); buffer = (gchar*)0; if (!g_file_get_contents(filename, &buffer, &size, error)) return FALSE; /* Create context. */ currentPath = (Path*)0; timeShift = paths->time; parser.start_element = geometryXML_element; parser.end_element = NULL; parser.text = NULL; parser.passthrough = NULL; parser.error = NULL; xmlContext = g_markup_parse_context_new(&parser, 0, paths, NULL); /* Parse data. */ startVisuPaths = FALSE; status = g_markup_parse_context_parse(xmlContext, buffer, size, error); /* Free buffers. */ g_markup_parse_context_free(xmlContext); g_free(buffer); if (!startVisuPaths) { *error = g_error_new(G_MARKUP_ERROR, G_MARKUP_ERROR_EMPTY, _("No paths found.")); status = FALSE; } if (!status) return FALSE; return TRUE; } /** * visu_paths_exportXMLFile: * @paths: a #VisuPaths object. * @filename: a location on disk. * @error: a pointer on an error. * * Write an XML file with the description of the given @paths. * * Since: 3.6 * * Returns: TRUE if no error. */ gboolean visu_paths_exportXMLFile(const VisuPaths *paths, const gchar *filename, GError **error) { GString *output; GList *tmpLst; Path *path; guint i; gboolean valid; if (!paths) return TRUE; output = g_string_new("\n", paths->translation[0], paths->translation[1], paths->translation[2]); for (tmpLst = paths->lst; tmpLst; tmpLst = g_list_next(tmpLst)) { path = (Path*)tmpLst->data; g_string_append_printf(output, " \n", path->nodeId, path->translation[0], path->translation[1], path->translation[2]); for (i = 0; i < path->nItems; i++) if (ABS(path->items[i].energy) != G_MAXFLOAT) g_string_append_printf (output, " \n", path->items[i].time, (path->items[i].type == PATH_ITEM_COORD)?"dot":"delta", path->items[i].dxyz[0], path->items[i].dxyz[1], path->items[i].dxyz[2], path->items[i].energy); else g_string_append_printf (output, " \n", path->items[i].time, (path->items[i].type == PATH_ITEM_COORD)?"dot":"delta", path->items[i].dxyz[0], path->items[i].dxyz[1], path->items[i].dxyz[2]); g_string_append(output, " \n"); } g_string_append(output, ""); valid = tool_XML_substitute(output, filename, "paths", error); if (!valid) { g_string_free(output, TRUE); return FALSE; } valid = g_file_set_contents(filename, output->str, -1, error); g_string_free(output, TRUE); return valid; } v_sim-3.8.0/src/extraFunctions/geometry.h000066400000000000000000000063551370110300500204450ustar00rootroot00000000000000/* EXTRAITS DE LA LICENCE Copyright CEA, contributeurs : Luc BILLARD et Damien CALISTE, laboratoire L_Sim, (2001-2005) Adresse mèl : BILLARD, non joignable par mèl ; CALISTE, damien P caliste AT cea P fr. Ce logiciel est un programme informatique servant à visualiser des structures atomiques dans un rendu pseudo-3D. Ce logiciel est régi par la licence CeCILL soumise au droit français et respectant les principes de diffusion des logiciels libres. Vous pouvez utiliser, modifier et/ou redistribuer ce programme sous les conditions de la licence CeCILL telle que diffusée par le CEA, le CNRS et l'INRIA sur le site "http://www.cecill.info". Le fait que vous puissiez accéder à cet en-tête signifie que vous avez pris connaissance de la licence CeCILL, et que vous en avez accepté les termes (cf. le fichier Documentation/licence.fr.txt fourni avec ce logiciel). */ /* LICENCE SUM UP Copyright CEA, contributors : Luc BILLARD et Damien CALISTE, laboratoire L_Sim, (2001-2005) E-mail address: BILLARD, not reachable any more ; CALISTE, damien P caliste AT cea P fr. This software is a computer program whose purpose is to visualize atomic configurations in 3D. This software is governed by the CeCILL license under French law and abiding by the rules of distribution of free software. You can use, modify and/ or redistribute the software under the terms of the CeCILL license as circulated by CEA, CNRS and INRIA at the following URL "http://www.cecill.info". The fact that you are presently reading this means that you have had knowledge of the CeCILL license and that you accept its terms. You can find a copy of this licence shipped with this software at Documentation/licence.en.txt. */ #ifndef GEOMETRY_H #define GEOMETRY_H #include #include #include #include #include "gdiff.h" typedef struct _VisuPaths VisuPaths; #define VISU_TYPE_PATHS (visu_paths_get_type()) GType visu_paths_get_type(void); VisuPaths* visu_paths_new(float translation[3]); VisuPaths* visu_paths_ref(VisuPaths *paths); void visu_paths_unref(VisuPaths *paths); void visu_paths_free(VisuPaths *paths); void visu_paths_empty(VisuPaths *paths); gboolean visu_paths_addFromDiff(VisuPaths *paths, VisuDataDiff *data, gdouble energy); gboolean visu_paths_addNodeStep(VisuPaths *paths, guint time, guint nodeId, float xyz[3], float dxyz[3], float energy); void visu_paths_pinPositions(VisuPaths *paths, VisuData *data); void visu_paths_draw(VisuPaths *paths, float pathWidth); void visu_paths_constrainInBox(VisuPaths *paths, VisuData *data); gboolean visu_paths_exportXMLFile(const VisuPaths *paths, const gchar *filename, GError **error); gboolean visu_paths_parseFromXML(const gchar* filename, VisuPaths *paths, GError **error); void visu_paths_setTranslation(VisuPaths *paths, float cartCoord[3]); gboolean visu_paths_setToolShade(VisuPaths *paths, const ToolShade* shade); const ToolShade* visu_paths_getToolShade(const VisuPaths *paths); guint visu_paths_getLength(VisuPaths *paths); #endif v_sim-3.8.0/src/extraFunctions/idProp.c000066400000000000000000000077561370110300500200500ustar00rootroot00000000000000/* EXTRAITS DE LA LICENCE Copyright CEA, contributeurs : Damien CALISTE, laboratoire L_Sim, (2017) Adresse mèl : CALISTE, damien P caliste AT cea P fr. Ce logiciel est un programme informatique servant à visualiser des structures atomiques dans un rendu pseudo-3D. Ce logiciel est régi par la licence CeCILL soumise au droit français et respectant les principes de diffusion des logiciels libres. Vous pouvez utiliser, modifier et/ou redistribuer ce programme sous les conditions de la licence CeCILL telle que diffusée par le CEA, le CNRS et l'INRIA sur le site "http://www.cecill.info". Le fait que vous puissiez accéder à cet en-tête signifie que vous avez pris connaissance de la licence CeCILL, et que vous en avez accepté les termes (cf. le fichier Documentation/licence.fr.txt fourni avec ce logiciel). */ /* LICENCE SUM UP Copyright CEA, contributors : Damien CALISTE, laboratoire L_Sim, (2017) E-mail address: CALISTE, damien P caliste AT cea P fr. This software is a computer program whose purpose is to visualize atomic configurations in 3D. This software is governed by the CeCILL license under French law and abiding by the rules of distribution of free software. You can use, modify and/ or redistribute the software under the terms of the CeCILL license as circulated by CEA, CNRS and INRIA at the following URL "http://www.cecill.info". The fact that you are presently reading this means that you have had knowledge of the CeCILL license and that you accept its terms. You can find a copy of this licence shipped with this software at Documentation/licence.en.txt. */ #include "idProp.h" /** * SECTION:idProp * @short_description: define a #VisuNodeValues object to access node idinates. * * Defines a #VisuNodeValues object to be notified about * idinate changes. */ static gboolean _getAt(const VisuNodeValues *vals, const VisuNode *node, GValue *value); static gchar* _serialize(const VisuNodeValues *vals, const VisuNode *node); G_DEFINE_TYPE(VisuNodeValuesId, visu_node_values_id, VISU_TYPE_NODE_VALUES) static void visu_node_values_id_class_init(VisuNodeValuesIdClass *klass) { /* Connect the overloading methods. */ VISU_NODE_VALUES_CLASS(klass)->getAt = _getAt; VISU_NODE_VALUES_CLASS(klass)->serialize = _serialize; } static void visu_node_values_id_init(VisuNodeValuesId *self _U_) { DBG_fprintf(stderr, "Visu ValuesId: creating new object %p.\n", (gpointer)self); } static gchar* _serialize(const VisuNodeValues *vals _U_, const VisuNode *node) { return g_strdup_printf("%u", node ? node->number + 1 : 0); } /** * visu_node_values_id_new: * @array: a #VisuData object. * * Create a #VisuNodeValues object to handle idinates of nodes. * * Since: 3.8 * * Returns: (transfer full): a newly created #VisuNodeValuesId object. **/ VisuNodeValuesId* visu_node_values_id_new(VisuNodeArray *array) { VisuNodeValuesId *vals; vals = VISU_NODE_VALUES_ID(g_object_new(VISU_TYPE_NODE_VALUES_ID, "label", _("Id"), "internal", TRUE, "nodes", array, "type", G_TYPE_UINT, "n-elements", 1, "editable", FALSE, NULL)); return vals; } /** * visu_node_values_id_getAt: * @vect: a #VisuNodeValuesId object. * @node: a #VisuNode object. * * Retrieves the id hosted on @node. * * Since: 3.8 * * Returns: the #VisuElement for @node. **/ guint visu_node_values_id_getAt(const VisuNodeValuesId *vect, const VisuNode *node) { g_return_val_if_fail(VISU_IS_NODE_VALUES_ID(vect), 0); return node ? node->number : 0; } static gboolean _getAt(const VisuNodeValues *vals _U_, const VisuNode *node, GValue *value) { g_value_set_uint(value, node ? node->number : 0); return TRUE; } v_sim-3.8.0/src/extraFunctions/idProp.h000066400000000000000000000076631370110300500200520ustar00rootroot00000000000000/* EXTRAITS DE LA LICENCE Copyright CEA, contributeurs : Damien CALISTE, laboratoire L_Sim, (2017) Adresse mèl : CALISTE, damien P caliste AT cea P fr. Ce logiciel est un programme informatique servant à visualiser des structures atomiques dans un rendu pseudo-3D. Ce logiciel est régi par la licence CeCILL soumise au droit français et respectant les principes de diffusion des logiciels libres. Vous pouvez utiliser, modifier et/ou redistribuer ce programme sous les conditions de la licence CeCILL telle que diffusée par le CEA, le CNRS et l'INRIA sur le site "http://www.cecill.info". Le fait que vous puissiez accéder à cet en-tête signifie que vous avez pris connaissance de la licence CeCILL, et que vous en avez accepté les termes (cf. le fichier Documentation/licence.fr.txt fourni avec ce logiciel). */ /* LICENCE SUM UP Copyright CEA, contributors : Damien CALISTE, laboratoire L_Sim, (2017) E-mail address: CALISTE, damien P caliste AT cea P fr. This software is a computer program whose purpose is to visualize atomic configurations in 3D. This software is governed by the CeCILL license under French law and abiding by the rules of distribution of free software. You can use, modify and/ or redistribute the software under the terms of the CeCILL license as circulated by CEA, CNRS and INRIA at the following URL "http://www.cecill.info". The fact that you are presently reading this means that you have had knowledge of the CeCILL license and that you accept its terms. You can find a copy of this licence shipped with this software at Documentation/licence.en.txt. */ #ifndef IDPROP_H #define IDPROP_H #include #include #include "nodeProp.h" G_BEGIN_DECLS /** * VISU_ID_NODE_VALUES_ID: * * return the id of #VisuNodeValuesId. */ #define VISU_TYPE_NODE_VALUES_ID (visu_node_values_id_get_type ()) /** * VISU_NODE_VALUES_ID: * @obj: a #GObject to cast. * * Cast the given @obj into #VisuNodeValuesId id. */ #define VISU_NODE_VALUES_ID(obj) (G_TYPE_CHECK_INSTANCE_CAST(obj, VISU_TYPE_NODE_VALUES_ID, VisuNodeValuesId)) /** * VISU_NODE_VALUES_ID_CLASS: * @klass: a #GObjectClass to cast. * * Cast the given @klass into #VisuNodeValuesIdClass. */ #define VISU_NODE_VALUES_ID_CLASS(klass) (G_TYPE_CHECK_CLASS_CAST(klass, VISU_TYPE_NODE_VALUES_ID, VisuNodeValuesIdClass)) /** * VISU_IS_NODE_VALUES_ID_ID: * @obj: a #GObject to test. * * Test if the given @ogj is of the id of #VisuNodeValuesId object. */ #define VISU_IS_NODE_VALUES_ID(obj) (G_TYPE_CHECK_INSTANCE_TYPE(obj, VISU_TYPE_NODE_VALUES_ID)) /** * VISU_IS_NODE_VALUES_ID_CLASS: * @klass: a #GObjectClass to test. * * Test if the given @klass is of the id of #VisuNodeValuesIdClass class. */ #define VISU_IS_NODE_VALUES_ID_CLASS(klass) (G_TYPE_CHECK_CLASS_ID(klass, VISU_TYPE_NODE_VALUES_ID)) /** * VISU_NODE_VALUES_ID_GET_CLASS: * @obj: a #GObject to get the class of. * * It returns the class of the given @obj. */ #define VISU_NODE_VALUES_ID_GET_CLASS(obj) (G_TYPE_INSTANCE_GET_CLASS(obj, VISU_TYPE_NODE_VALUES_ID, VisuNodeValuesIdClass)) /** * VisuNodeValuesId: * * Common name to refer to a #_VisuNodeValuesId. */ typedef struct _VisuNodeValuesId VisuNodeValuesId; struct _VisuNodeValuesId { VisuNodeValues parent; }; /** * VisuNodeValuesIdClass: * @parent: private. * * Common name to refer to a #_VisuNodeValuesIdClass. */ typedef struct _VisuNodeValuesIdClass VisuNodeValuesIdClass; struct _VisuNodeValuesIdClass { VisuNodeValuesClass parent; }; /** * visu_node_values_id_get_id: * * This method returns the id of #VisuNodeValuesId, use * VISU_ID_NODE_VALUES_ID instead. * * Since: 3.8 * * Returns: the id of #VisuNodeValuesId. */ GType visu_node_values_id_get_type(void); VisuNodeValuesId* visu_node_values_id_new(VisuNodeArray *array); guint visu_node_values_id_getAt(const VisuNodeValuesId *vect, const VisuNode *node); G_END_DECLS #endif v_sim-3.8.0/src/extraFunctions/iface_sourceable.c000066400000000000000000000245031370110300500220530ustar00rootroot00000000000000/* EXTRAITS DE LA LICENCE Copyright CEA, contributeurs : Damien CALISTE, laboratoire L_Sim, (2019) Adresse mèl : CALISTE, damien P caliste AT cea P fr. Ce logiciel est un programme informatique servant à visualiser des structures atomiques dans un rendu pseudo-3D. Ce logiciel est régi par la licence CeCILL soumise au droit français et respectant les principes de diffusion des logiciels libres. Vous pouvez utiliser, modifier et/ou redistribuer ce programme sous les conditions de la licence CeCILL telle que diffusée par le CEA, le CNRS et l'INRIA sur le site "http://www.cecill.info". Le fait que vous puissiez accéder à cet en-tête signifie que vous avez pris connaissance de la licence CeCILL, et que vous en avez accepté les termes (cf. le fichier Documentation/licence.fr.txt fourni avec ce logiciel). */ /* LICENCE SUM UP Copyright CEA, contributors : Damien CALISTE, laboratoire L_Sim, (2019) E-mail address: BILLARD, not reachable any more ; CALISTE, damien P caliste AT cea P fr. This software is a computer program whose purpose is to visualize atomic configurations in 3D. This software is governed by the CeCILL license under French law and abiding by the rules of distribution of free software. You can use, modify and/ or redistribute the software under the terms of the CeCILL license as circulated by CEA, CNRS and INRIA at the following URL "http://www.cecill.info". The fact that you are presently reading this means that you have had knowledge of the CeCILL license and that you accept its terms. You can find a copy of this licence shipped with this software at Documentation/licence.en.txt. */ #include "iface_sourceable.h" #include #include "config.h" /** * SECTION:iface_sourceable * @short_description: an interface for sourceable objects. * * This interface describes objects that can take data from a * #VisuNodeValues object. This model can be named and changed each * time a #VisuData is reloaded. */ /** * VisuSourceableData: * * An opaque structure to store internal implementation of #VisuSourceable. * * Since: 3.8 */ struct _VisuSourceableData { gchar *source; VisuData *dataObj; gulong added_sig, removed_sig; VisuNodeValues *model; gulong chg_sig; }; enum { PROP_0, PROP_SOURCE, PROP_MODEL, N_PROPS }; static GParamSpec *_properties[N_PROPS]; /* Sourceable interface. */ G_DEFINE_INTERFACE(VisuSourceable, visu_sourceable, G_TYPE_OBJECT) static void visu_sourceable_default_init(VisuSourceableInterface *iface) { /** * VisuSourceable::source: * * The source property used to get the model from. * * Since: 3.8 */ _properties[PROP_SOURCE] = g_param_spec_string("source", "Source", "name of the source property", "", G_PARAM_READWRITE); g_object_interface_install_property(iface, _properties[PROP_SOURCE]); /** * VisuSourceable::model: * * The #VisuNodeValues object associated to the object. * * Since: 3.8 */ _properties[PROP_MODEL] = g_param_spec_object("model", "Model", "node property associated to the object", VISU_TYPE_NODE_VALUES, G_PARAM_READWRITE); g_object_interface_install_property(iface, _properties[PROP_MODEL]); } /** * visu_sourceable_init: * @self: a #VisuSourceable object. * * Method used in initialisation of the object to allocate a * #VisuSourceableData structure. This structure should be store by * the implementer of the sourceable interface and returned by the * getSource() virtual method. * * Since: 3.8 **/ void visu_sourceable_init(VisuSourceable *self) { VisuSourceableData **src; g_return_if_fail(VISU_IS_SOURCEABLE(self)); src = VISU_SOURCEABLE_GET_INTERFACE(self)->getSource(self); *src = g_malloc0(sizeof(VisuSourceableData)); } /** * visu_sourceable_dispose: * @self: a #VisuSourceable object. * * This method should be called in the dispose() method of @self to * ensure that any data referenced in a #VisuSourceableData structure * are released. * * Since: 3.8 **/ void visu_sourceable_dispose(VisuSourceable *self) { VisuSourceableData **src; g_return_if_fail(VISU_IS_SOURCEABLE(self)); src = VISU_SOURCEABLE_GET_INTERFACE(self)->getSource(self); if (*src) { visu_sourceable_follow(self, (VisuData*)0); visu_sourceable_setNodeModel(self, (VisuNodeValues*)0); visu_sourceable_setSource(self, (const gchar*)0); g_free(*src); } } /** * visu_sourceable_setSource: * @self: a #VisuSourceable object. * @source: a property name. * * @self can be bound to a specific #VisuNodeValues defined by * its name. When @source is not %NULL and @self attached to a * #VisuData, its model is changed to match any #VisuNodeValues of its * current #VisuNodeArray with the label @source. * * Since: 3.8 * * Returns: TRUE if the value is actually changed. **/ gboolean visu_sourceable_setSource(VisuSourceable *self, const gchar *source) { VisuSourceableData *src; VisuNodeValues *model; g_return_val_if_fail(VISU_IS_SOURCEABLE(self), FALSE); src = *VISU_SOURCEABLE_GET_INTERFACE(self)->getSource(self); if (!src || !g_strcmp0(src->source, source)) return FALSE; DBG_fprintf(stderr, "Iface Sourceable: set source '%s'.\n", source); g_free(src->source); src->source = g_strdup(source); g_object_notify_by_pspec(G_OBJECT(self), _properties[PROP_SOURCE]); if (src->dataObj && src->source) { model = visu_data_getNodeProperties(src->dataObj, src->source); if (model) visu_sourceable_setNodeModel(self, model); } return TRUE; } /** * visu_sourceable_getSource: * @self: a #VisuSourceable object. * * Retrieves the name of the property @model should be bound to * retrieve its #VisuNodeValues model. * * Since: 3.8 * * Returns: (allow-none): a property name. **/ const gchar* visu_sourceable_getSource(const VisuSourceable *self) { VisuSourceableData *src; g_return_val_if_fail(VISU_IS_SOURCEABLE(self), (const gchar*)0); src = *VISU_SOURCEABLE_GET_INTERFACE(self)->getSource(VISU_SOURCEABLE(self)); return src ? src->source: (const gchar*)0; } static void onModelChanged(VisuSourceable *self) { if (VISU_SOURCEABLE_GET_INTERFACE(self)->modelChanged) VISU_SOURCEABLE_GET_INTERFACE(self)->modelChanged(self); } /** * visu_sourceable_setNodeModel: * @self: The #VisuSourceable to attached to. * @model: (allow-none): a #VisuNodeValues object. * * Set @model to @self. * * Since: 3.8 * * Returns: TRUE if changed. **/ gboolean visu_sourceable_setNodeModel(VisuSourceable *self, VisuNodeValues *model) { VisuSourceableData *src; g_return_val_if_fail(VISU_IS_SOURCEABLE(self), FALSE); src = *VISU_SOURCEABLE_GET_INTERFACE(self)->getSource(self); if (!src || src->model == model) return FALSE; if (src->model) { g_signal_handler_disconnect(G_OBJECT(src->model), src->chg_sig); g_object_unref(src->model); } src->model = model; if (model) { g_object_ref(model); src->chg_sig = g_signal_connect_swapped(G_OBJECT(model), "changed", G_CALLBACK(onModelChanged), self); } g_object_notify_by_pspec(G_OBJECT(self), _properties[PROP_MODEL]); onModelChanged(self); return TRUE; } /** * visu_sourceable_getNodeModel: * @self: a #VisuSourceable object. * * Retrieves associated model, if any. * * Since: 3.8 * * Returns: (transfer none): the associated model. **/ VisuNodeValues* visu_sourceable_getNodeModel(VisuSourceable *self) { VisuSourceableData *src; g_return_val_if_fail(VISU_IS_SOURCEABLE(self), (VisuNodeValues*)0); src = *VISU_SOURCEABLE_GET_INTERFACE(self)->getSource(self); return src ? src->model : (VisuNodeValues*)0; } /** * visu_sourceable_getConstNodeModel: * @self: a #VisuSourceable object. * * Retrieves associated model, if any. * * Since: 3.8 * * Returns: (transfer none): the associated model. **/ const VisuNodeValues* visu_sourceable_getConstNodeModel(const VisuSourceable *self) { VisuSourceableData *src; g_return_val_if_fail(VISU_IS_SOURCEABLE(self), (const VisuNodeValues*)0); src = *VISU_SOURCEABLE_GET_INTERFACE(self)->getSource(VISU_SOURCEABLE(self)); return src ? src->model : (const VisuNodeValues*)0; } static void onNodePropAdded(VisuSourceable *self, VisuNodeValues *prop) { if (!visu_sourceable_getSource(self)) return; if (!g_strcmp0(visu_node_values_getLabel(prop), visu_sourceable_getSource(self))) visu_sourceable_setNodeModel(self, prop); } static void onNodePropRemoved(VisuSourceable *self, VisuNodeValues *prop) { if (!visu_sourceable_getSource(self)) return; if (!g_strcmp0(visu_node_values_getLabel(prop), visu_sourceable_getSource(self))) visu_sourceable_setNodeModel(self, (VisuNodeValues*)0); } /** * visu_sourceable_follow: * @self: a #VisuSourceable object. * @data: (allow-none): a #VisuData object. * * Set the #VisuNodeValues @self is based on by polling the node * property of @data referenced by the source name of @self (see * visu_sourceable_setSource()). If @self is not following any named * property, this call does nothing. If @self is following a named * property and @data is %NULL, the node model is set to %NULL also. * * Since: 3.8 * * Returns: TRUE if the followed @data is actually changed. **/ gboolean visu_sourceable_follow(VisuSourceable *self, VisuData *data) { VisuSourceableData *src; VisuNodeValues *model; g_return_val_if_fail(VISU_IS_SOURCEABLE(self), FALSE); src = *VISU_SOURCEABLE_GET_INTERFACE(self)->getSource(VISU_SOURCEABLE(self)); if (!src || !src->source || src->dataObj == data) return FALSE; model = (VisuNodeValues*)0; if (src->dataObj) { g_signal_handler_disconnect(src->dataObj, src->added_sig); g_signal_handler_disconnect(src->dataObj, src->removed_sig); g_object_unref(src->dataObj); } src->dataObj = data; if (data) { g_object_ref(data); src->added_sig = g_signal_connect_swapped(G_OBJECT(data), "node-properties-added", G_CALLBACK(onNodePropAdded), self); src->removed_sig = g_signal_connect_swapped(G_OBJECT(data), "node-properties-removed", G_CALLBACK(onNodePropRemoved), self); model = visu_data_getNodeProperties(data, src->source); } visu_sourceable_setNodeModel(self, model); return TRUE; } v_sim-3.8.0/src/extraFunctions/iface_sourceable.h000066400000000000000000000071641370110300500220640ustar00rootroot00000000000000/* EXTRAITS DE LA LICENCE Copyright CEA, contributeurs : Damien CALISTE, laboratoire L_Sim, (2019) Adresse mèl : CALISTE, damien P caliste AT cea P fr. Ce logiciel est un programme informatique servant à visualiser des structures atomiques dans un rendu pseudo-3D. Ce logiciel est régi par la licence CeCILL soumise au droit français et respectant les principes de diffusion des logiciels libres. Vous pouvez utiliser, modifier et/ou redistribuer ce programme sous les conditions de la licence CeCILL telle que diffusée par le CEA, le CNRS et l'INRIA sur le site "http://www.cecill.info". Le fait que vous puissiez accéder à cet en-tête signifie que vous avez pris connaissance de la licence CeCILL, et que vous en avez accepté les termes (cf. le fichier Documentation/licence.fr.txt fourni avec ce logiciel). */ /* LICENCE SUM UP Copyright CEA, contributors : Damien CALISTE, laboratoire L_Sim, (2019) E-mail address: BILLARD, not reachable any more ; CALISTE, damien P caliste AT cea P fr. This software is a computer program whose purpose is to visualize atomic configurations in 3D. This software is governed by the CeCILL license under French law and abiding by the rules of distribution of free software. You can use, modify and/ or redistribute the software under the terms of the CeCILL license as circulated by CEA, CNRS and INRIA at the following URL "http://www.cecill.info". The fact that you are presently reading this means that you have had knowledge of the CeCILL license and that you accept its terms. You can find a copy of this licence shipped with this software at Documentation/licence.en.txt. */ #ifndef IFACE_SOURCEABLE_H #define IFACE_SOURCEABLE_H #include #include #include #include "nodeProp.h" G_BEGIN_DECLS /* Sourceable interface. */ #define VISU_TYPE_SOURCEABLE (visu_sourceable_get_type ()) #define VISU_SOURCEABLE(obj) (G_TYPE_CHECK_INSTANCE_CAST ((obj), VISU_TYPE_SOURCEABLE, VisuSourceable)) #define VISU_IS_SOURCEABLE(obj) (G_TYPE_CHECK_INSTANCE_TYPE ((obj), VISU_TYPE_SOURCEABLE)) #define VISU_SOURCEABLE_GET_INTERFACE(inst) (G_TYPE_INSTANCE_GET_INTERFACE ((inst), VISU_TYPE_SOURCEABLE, VisuSourceableInterface)) typedef struct _VisuSourceableInterface VisuSourceableInterface; typedef struct _VisuSourceable VisuSourceable; typedef struct _VisuSourceableData VisuSourceableData; /** * VisuSourceable: * * Interface object. * * Since: 3.8 */ /** * VisuSourceableInterface: * @parent: its parent. * @getSource: a method to access the #VisuSourceableData storage that * a sourceable object should store. * @modelChanged: called whenever the underlying model is changed. * * The different routines common to objects implementing a #VisuSourceable interface. * * Since: 3.8 */ struct _VisuSourceableInterface { GTypeInterface parent; VisuSourceableData** (*getSource)(VisuSourceable *self); void (*modelChanged)(VisuSourceable *self); }; GType visu_sourceable_get_type(void); void visu_sourceable_init(VisuSourceable *self); void visu_sourceable_dispose(VisuSourceable *self); gboolean visu_sourceable_setSource(VisuSourceable *self, const gchar *source); const gchar* visu_sourceable_getSource(const VisuSourceable *self); gboolean visu_sourceable_setNodeModel(VisuSourceable *self, VisuNodeValues *model); VisuNodeValues* visu_sourceable_getNodeModel(VisuSourceable *self); const VisuNodeValues* visu_sourceable_getConstNodeModel(const VisuSourceable *self); gboolean visu_sourceable_follow(VisuSourceable *self, VisuData *data); G_END_DECLS #endif v_sim-3.8.0/src/extraFunctions/isoline.c000066400000000000000000000334331370110300500202440ustar00rootroot00000000000000/* EXTRAITS DE LA LICENCE Copyright CEA, contributeurs : Aurélien LHERBIER, laboratoire L_Sim, (2001-2005) Adresse mèl : LHERBIER, aurelien P lherbier A cea P fr. Ce logiciel est un programme informatique servant à visualiser des structures atomiques dans un rendu pseudo-3D. Ce logiciel est régi par la licence CeCILL soumise au droit français et respectant les principes de diffusion des logiciels libres. Vous pouvez utiliser, modifier et/ou redistribuer ce programme sous les conditions de la licence CeCILL telle que diffusée par le CEA, le CNRS et l'INRIA sur le site "http://www.cecill.info". Le fait que vous puissiez accéder à cet en-tête signifie que vous avez pris connaissance de la licence CeCILL, et que vous en avez accepté les termes (cf. le fichier Documentation/licence.fr.txt fourni avec ce logiciel). */ /* LICENCE SUM UP Copyright CEA, contributors : Aurélien LHERBIER, laboratoire L_Sim, (2001-2005) E-mail addresses : LHERBIER, aurelien D lherbier AT cea D fr. This software is a computer program whose purpose is to visualize atomic configurations in 3D. This software is governed by the CeCILL license under French law and abiding by the rules of distribution of free software. You can use, modify and/ or redistribute the software under the terms of the CeCILL license as circulated by CEA, CNRS and INRIA at the following URL "http://www.cecill.info". The fact that you are presently reading this means that you have had knowledge of the CeCILL license and that you accept its terms. You can find a copy of this licence shipped with this software at Documentation/licence.en.txt. */ #include #include #include #include "isoline.h" /** * SECTION:isoline * @short_description: handle the drawing and the computation of * isolines. * * TODO */ /** * VisuLine: * * Structure representing a curved line in 3D, opaque structure. */ struct _VisuLine { guint refCount; guint num_sublines, num_vertices; float **vertex_3dpos; double value; }; static gboolean Create_line(int *iTab, int ntriangles, double *xline, double *yline, double *zline, VisuLine **isoline); static int edgeTable[8] = { 0x0 , 0x0, 0x0, 0x1, 0x0, 0x2, 0x3, 0x4 }; static int linTable[5][5] = { {-1, -1, -1, -1, -1}, { 0, 1, -1, -1, -1}, { 0, 2, -1, -1, -1}, { 1, 2, -1, -1, -1}, { 0, 1, 2, 0, -1} }; /******************************************************************************/ /******************************************************************************/ /* DEVELOPMENT AREA Methods are copied to be callable without all static stuff everywhere. */ /** * visu_line_free: * @line: a set of lines. * * Free the line object. * * Since: 3.4 */ void visu_line_free(VisuLine *line) { g_return_if_fail(line); DBG_fprintf(stderr, "Line: free line %p.\n", (gpointer)line); if(line->vertex_3dpos) { g_free(line->vertex_3dpos[0]); g_free(line->vertex_3dpos); line->vertex_3dpos = (float**)0; } DBG_fprintf(stderr, " | Ok.\n"); } /** * visu_line_get_type: * @void: * * Create and retrieve a #GType for a #VisuLine object. * * Since: 3.7 * * Returns: a new type for #VisuLine structures. **/ GType visu_line_get_type(void) { static GType g_define_type_id = 0; if (g_define_type_id == 0) g_define_type_id = g_boxed_type_register_static("VisuLine", (GBoxedCopyFunc)visu_line_ref, (GBoxedFreeFunc)visu_line_unref); return g_define_type_id; } /** * visu_line_ref: * @line: a #VisuLine object. * * Increase the ref counter. * * Since: 3.7 * * Returns: itself. **/ VisuLine* visu_line_ref(VisuLine *line) { line->refCount += 1; return line; } /** * visu_line_unref: * @line: a #VisuLine object. * * Decrease the ref counter, free all memory if counter reachs zero. * * Since: 3.7 **/ void visu_line_unref(VisuLine *line) { line->refCount -= 1; if (line->refCount) return; visu_line_free(line); g_free(line); } /** * visu_line_newFromTriangles: * @data: the lines to be computed ; * @nTriangles: the surface to compute isoline from ; * @isoValue: the value of the computed isoline. * * Create on the fly an isoline from a given set of triangles. If the * lines are created, @isoline will be allocated and should be freed * with visu_line_free() after use. * * Since: 3.6 * * Returns: the newly allocated #VisuLine or NULL. */ VisuLine* visu_line_newFromTriangles(float **data, guint nTriangles, double isoValue) { /* Local variables */ VisuLine *isoline_; guint j, n; int p, q; int nPoints, nedges; int *iTab; /* give edge index in the full edge list with edge j of a given triangle i as input*/ /* j in [0,1,2] and i in [0,ntriangles-1]*/ float fac, isov; double val0, val1; double *xline, *yline, *zline; float *coord0, *coord1; /* local vertex coordinates */ gboolean status; #if DEBUG == 1 GTimer *timer; gulong fractionTimer; #endif /* Routine code*/ isov = isoValue; /* Ensure that the pointer is not zero */ g_return_val_if_fail(data, (VisuLine*)0); DBG_fprintf(stderr, "Line: compute isoline at value %g from %d triangles.\n", isoValue, nTriangles); #if DEBUG == 1 timer = g_timer_new(); g_timer_start(timer); #endif /* Allocate memory*/ nedges = 3 * nTriangles; iTab = g_malloc(nedges * sizeof(int)); xline = g_malloc(nedges * sizeof(double)); yline = g_malloc(nedges * sizeof(double)); zline = g_malloc(nedges * sizeof(double)); /* Glance trough the list of edges and search intersection between edges and VisuScalarField */ nPoints = 0; for(n = 0; n < nTriangles; n++) { /* Get the 3D coordinates and scalar field value of each vertex (0,1) of the current edge*/ for(j=0; j<3; j++) { /* Get the xyz coordinates of the 2 vertices of the current edge of the current triangle*/ p=j; q=(j == 2)?0:j+1; val0 = data[2 * n + 1][p]; val1 = data[2 * n + 1][q]; /* Test if edge contains isovalue */ if((isov - val0 < 0.0 && isov - val1 >= 0.0) || (isov - val0 >= 0.0 && isov - val1 < 0.0)) { fac = (isov - val0) / (val1 - val0); coord0 = data[2 * n + 0] + 3 * p; coord1 = data[2 * n + 0] + 3 * q; iTab[3 * n + j] = nPoints; xline[nPoints] = coord0[0] + fac * (coord1[0]-coord0[0]); yline[nPoints] = coord0[1] + fac * (coord1[1]-coord0[1]); zline[nPoints] = coord0[2] + fac * (coord1[2]-coord0[2]); nPoints++; } else iTab[3 * n + j] = -1; } } xline = g_realloc(xline, nPoints * sizeof(double)); yline = g_realloc(yline, nPoints * sizeof(double)); zline = g_realloc(zline, nPoints * sizeof(double)); DBG_fprintf(stderr, " | found %d points for line.\n", nPoints); #if DEBUG == 1 g_timer_stop(timer); fprintf(stderr, "Isoline : compute intersections in %g micro-s.\n", g_timer_elapsed(timer, &fractionTimer)/1e-6); g_timer_destroy(timer); #endif #if DEBUG == 1 timer = g_timer_new(); g_timer_start(timer); #endif if(nPoints == 0) { /* g_warning("no isoline found for value %g.", isoValue); */ status = FALSE; isoline_ = (VisuLine*)0; } else { /* Create lines from the computed points*/ isoline_ = g_malloc(sizeof(VisuLine)); isoline_->refCount = 1; isoline_->value = isoValue; status = Create_line(iTab, nTriangles, xline, yline, zline, &isoline_); } #if DEBUG == 1 g_timer_stop(timer); fprintf(stderr, "Isoline : build lines in %g micro-s.\n", g_timer_elapsed(timer, &fractionTimer)/1e-6); g_timer_destroy(timer); #endif g_free(iTab); g_free(xline); g_free(yline); g_free(zline); DBG_fprintf(stderr, " | Line exit with status %d.\n", (int)status); return (status)?isoline_:(VisuLine*)0; } /* * Create_line: * @nPoints: an integer giving the number points of the line; * @iTab: table containing the number of line points if line exists at this place otherwise -1; * @nedges: an integer giving the number of edges; * @ntriangles: an integer giving the number of triangles; * @vertices_index_from_triangles : return general vertex index from a given triangle; * @edges_index_from_triangles : return general edge index from a given triangle; * @isoValue: the value of the isoline; * @xline: x coordinate of the line points; * @yline: y coordinate of the line points; * @zline: z coordinate of the line points; * @vertices_SFV: scalar field value on each vertex; * @isoline: the Line structure containing data for plot; * Create on the fly a line from a list of points. * Returns: TRUE if the line is created. */ static gboolean Create_line(int *iTab, int ntriangles, double *xline, double *yline, double *zline, VisuLine **isoline) { /* Local variables */ register int i; int cubeindex; int e; guint n, nlines; int m0, m1; int *vTab; /* Routine code */ /* Ensure that the pointer is not zero */ g_return_val_if_fail(isoline, FALSE); /* Allocate buffers. */ vTab = g_malloc(2*3*ntriangles * sizeof(int)); nlines = 0; /* Loop over the triangles */ for(i=0; i= 0) cubeindex |= 1; if (iTab[3 * i + 1] >= 0) cubeindex |= 2; if (iTab[3 * i + 2] >= 0) cubeindex |= 4; e = edgeTable[cubeindex]; if (e == 0) continue; for (n = 0; linTable[e][n + 1]!= -1; n += 1) { m0 = iTab[3 * i + linTable[e][n ]]; if(m0 == -1) { g_warning("m1 %d.", i); g_free(vTab); g_free(*isoline); return FALSE; } m1 = iTab[3 * i + linTable[e][n+1]]; if(m1 == -1) { g_warning("m2 %d.", i); g_free(vTab); g_free(*isoline); return FALSE; } vTab[2*nlines + 0] = m0; vTab[2*nlines + 1] = m1; nlines++; } } DBG_fprintf(stderr, " | found %d lines.\n", nlines); if(nlines == 0) { g_warning("no isolines found."); g_free(vTab); g_free(*isoline); return FALSE; } /* Ok, try to create a Line object from here. */ DBG_fprintf(stderr, " | copy vertices.\n"); (*isoline)->num_sublines = nlines; (*isoline)->num_vertices = 2*nlines+1; /* Allocate memory. */ (*isoline)->vertex_3dpos = g_malloc(sizeof(float*) * (*isoline)->num_vertices); (*isoline)->vertex_3dpos[0] = g_malloc(sizeof(float) * (*isoline)->num_vertices * 3); for (n = 0; n < (*isoline)->num_vertices; n++) (*isoline)->vertex_3dpos[n] = (*isoline)->vertex_3dpos[0] + 3 * n; for(n = 0; n < nlines; n++) { (*isoline)->vertex_3dpos[2*n ][0] = xline[vTab[2*n ]]; (*isoline)->vertex_3dpos[2*n ][1] = yline[vTab[2*n ]]; (*isoline)->vertex_3dpos[2*n ][2] = zline[vTab[2*n ]]; (*isoline)->vertex_3dpos[2*n+1][0] = xline[vTab[2*n+1]]; (*isoline)->vertex_3dpos[2*n+1][1] = yline[vTab[2*n+1]]; (*isoline)->vertex_3dpos[2*n+1][2] = zline[vTab[2*n+1]]; } DBG_fprintf(stderr, " | finishing lines.\n"); g_free(vTab); return TRUE; } /** * visu_line_draw: * @line: a set of points forming a line. * @rgb: a colour. * * Call the OpenGL routine that will draw this line. * * Since: 3.4 */ void visu_line_draw(VisuLine *line, float rgb[3]) { guint i; g_return_if_fail(line); glLineWidth(2.f); /* glPointSize(2.f); */ glColor3fv(rgb); glDepthMask(0); glBegin(GL_LINES); for ( i = 0; i < line->num_sublines; i++) { glVertex3fv(line->vertex_3dpos[2 * i]); glVertex3fv(line->vertex_3dpos[2 * i + 1]); } glEnd(); /* glEnable(GL_POINT_SMOOTH); */ /* glBegin(GL_POINTS); */ /* for ( i = 0; i < line->num_sublines; i++) */ /* { */ /* glVertex3fv(line->vertex_3dpos[2 * i]); */ /* glVertex3fv(line->vertex_3dpos[2 * i + 1]); */ /* } */ /* glEnd(); */ /* glDisable(GL_POINT_SMOOTH); */ glDepthMask(1); } /** * visu_line_project: * @line: a #VisuLine object. * @plane: a #VisuPlane object. * @nSeg: a location to store the size of projection. * * Calculate the projection of each @line vertex on @plane. * * Since: 3.6 * * Returns: a newly allocated array of line segments. The size of this * array is 4 * @nSeg, holding the two plane coordiantes of the two * vertices of a line. */ float* visu_line_project(VisuLine *line, VisuPlane *plane, guint *nSeg) { float basis[2][3], center[3], *out; guint i; g_return_val_if_fail(line && nSeg, (float*)0); visu_plane_getBasis(plane, basis, center); out = g_malloc(sizeof(float) * 2 * line->num_sublines * 2); *nSeg = line->num_sublines; for ( i = 0; i < line->num_sublines; i++) { out[i * 4 + 0] = basis[0][0] * (line->vertex_3dpos[2 * i + 0][0] - center[0]) + basis[0][1] * (line->vertex_3dpos[2 * i + 0][1] - center[1]) + basis[0][2] * (line->vertex_3dpos[2 * i + 0][2] - center[2]); out[i * 4 + 1] = basis[1][0] * (line->vertex_3dpos[2 * i + 0][0] - center[0]) + basis[1][1] * (line->vertex_3dpos[2 * i + 0][1] - center[1]) + basis[1][2] * (line->vertex_3dpos[2 * i + 0][2] - center[2]); out[i * 4 + 2] = basis[0][0] * (line->vertex_3dpos[2 * i + 1][0] - center[0]) + basis[0][1] * (line->vertex_3dpos[2 * i + 1][1] - center[1]) + basis[0][2] * (line->vertex_3dpos[2 * i + 1][2] - center[2]); out[i * 4 + 3] = basis[1][0] * (line->vertex_3dpos[2 * i + 1][0] - center[0]) + basis[1][1] * (line->vertex_3dpos[2 * i + 1][1] - center[1]) + basis[1][2] * (line->vertex_3dpos[2 * i + 1][2] - center[2]); } return out; } /** * visu_line_getValue: * @line: a #VisuLine object. * * Lines are usually created as iso-values line in a mesh. * * Since: 3.6 * * Returns: the value associated to the line. */ double visu_line_getValue(VisuLine *line) { g_return_val_if_fail(line, -1.); return line->value; } v_sim-3.8.0/src/extraFunctions/isoline.h000066400000000000000000000045431370110300500202510ustar00rootroot00000000000000/* EXTRAITS DE LA LICENCE Copyright CEA, contributeurs : Damien CALISTE, Olivier D'Astier, laboratoire L_Sim, (2001-2005) Adresse mèl : CALISTE, damien P caliste AT cea P fr. D'ASTIER, dastier AT iie P cnam P fr. Ce logiciel est un programme informatique servant à visualiser des structures atomiques dans un rendu pseudo-3D. Ce logiciel est régi par la licence CeCILL soumise au droit français et respectant les principes de diffusion des logiciels libres. Vous pouvez utiliser, modifier et/ou redistribuer ce programme sous les conditions de la licence CeCILL telle que diffusée par le CEA, le CNRS et l'INRIA sur le site "http://www.cecill.info". Le fait que vous puissiez accéder à cet en-tête signifie que vous avez pris connaissance de la licence CeCILL, et que vous en avez accepté les termes (cf. le fichier Documentation/licence.fr.txt fourni avec ce logiciel). */ /* LICENCE SUM UP Copyright CEA, contributors : Damien CALISTE, Olivier D'Astier, laboratoire L_Sim, (2001-2005) E-mail address: CALISTE, damien P caliste AT cea P fr. D'ASTIER, dastier AT iie P cnam P fr. This software is a computer program whose purpose is to visualize atomic configurations in 3D. This software is governed by the CeCILL license under French law and abiding by the rules of distribution of free software. You can use, modify and/ or redistribute the software under the terms of the CeCILL license as circulated by CEA, CNRS and INRIA at the following URL "http://www.cecill.info". The fact that you are presently reading this means that you have had knowledge of the CeCILL license and that you accept its terms. You can find a copy of this licence shipped with this software at Documentation/licence.en.txt. */ #ifndef ISOLINE_H #define ISOLINE_H #include #include #include "plane.h" typedef struct _VisuLine VisuLine; #define VISU_TYPE_LINE (visu_line_get_type()) GType visu_line_get_type(void); VisuLine* visu_line_newFromTriangles(float **data, guint nTriangles, double isoValue); VisuLine* visu_line_ref(VisuLine *line); void visu_line_unref(VisuLine *line); void visu_line_free(VisuLine *line); void visu_line_draw(VisuLine *line, float rgb[3]); float* visu_line_project(VisuLine *line, VisuPlane *plane, guint *nSeg); double visu_line_getValue(VisuLine *line); #endif v_sim-3.8.0/src/extraFunctions/map.c000066400000000000000000001630561370110300500173640ustar00rootroot00000000000000/* EXTRAITS DE LA LICENCE Copyright CEA, contributeurs : Luc BILLARD, Damien CALISTE, Olivier D'Astier, laboratoire L_Sim, (2001-2005) Adresses mèl : BILLARD, non joignable par mèl ; CALISTE, damien P caliste AT cea P fr. D'ASTIER, dastier AT iie P cnam P fr. Ce logiciel est un programme informatique servant à visualiser des structures atomiques dans un rendu pseudo-3D. Ce logiciel est régi par la licence CeCILL soumise au droit français et respectant les principes de diffusion des logiciels libres. Vous pouvez utiliser, modifier et/ou redistribuer ce programme sous les conditions de la licence CeCILL telle que diffusée par le CEA, le CNRS et l'INRIA sur le site "http://www.cecill.info". Le fait que vous puissiez accéder à cet en-tête signifie que vous avez pris connaissance de la licence CeCILL, et que vous en avez accepté les termes (cf. le fichier Documentation/licence.fr.txt fourni avec ce logiciel). */ /* LICENCE SUM UP Copyright CEA, contributors : Luc BILLARD and Damien CALISTE and Olivier D'Astier, laboratoire L_Sim, (2001-2005) E-mail addresses : BILLARD, not reachable any more ; CALISTE, damien P caliste AT cea P fr. D'ASTIER, dastier AT iie P cnam P fr. This software is a computer program whose purpose is to visualize atomic configurations in 3D. This software is governed by the CeCILL license under French law and abiding by the rules of distribution of free software. You can use, modify and/ or redistribute the software under the terms of the CeCILL license as circulated by CEA, CNRS and INRIA at the following URL "http://www.cecill.info". The fact that you are presently reading this means that you have had knowledge of the CeCILL license and that you accept its terms. You can find a copy of this licence shipped with this software at Documentation/licence.en.txt. */ #include "map.h" #include "isoline.h" #include #include #include #include #include #ifdef HAVE_CAIRO #include #include #include #endif /** * SECTION:map * @short_description: Describe how to handle and draw coloured map on * a plane from a density field. * * A map is a coloured representation of a scalar field on a * plane. To define a new map, use visu_map_new_fromPlane() and use * visu_map_setField() to associate a scalarfield to it. * The representation of the map is done by an adaptive mesh of * triangles. One can adjust the size of the smaller resolution by * using visu_map_setLevel(). Finally the level of adaptiveness is * chosen at rendering time by choosing a more or less crude precision * argument to visu_map_draw(). * In adition to the colour representation, isolines can be * drawn at given iso-values, see visu_map_setLines(). * An additionnal capability allows to export #VisuMap into SVG * or PDF vector files. * * Since: 3.6 */ /** * VisuMapClass: * @parent: private. * @computePool: unused. * * Common name to refer to a #_VisuMapClass. */ /** * Triangle : * @triangle_ABC :a location to store coordinates of tree vertexs * @value_scalarfield: a location to store the value of scalarfideld * @min_node : the minimum value * @max_node : the maximum value * @rgba: a color,can be NULL; * @flag:return TRUE if the triangle has the least one vertex is out of bounds,return FALSE ifnot * * The structure is used to store informations about coordinates,color,position of each vertex and * the maximum and minimum value of scalarfield */ typedef struct _Triangle { float vertices[3][3]; float minmax[2]; float value[3]; guint level; struct _Triangle *children[4]; } Triangle; struct _VisuMapPrivate { gboolean dispose_has_run; GMutex access; GMutex mutex; guint dirty; gboolean computing; /* Pointers to building objects. */ VisuPlane *plane; glong moved_signal, boxed_signal; VisuSurface *surface; VisuScalarField *field; gulong changed_sig; /* Transformation values. */ ToolMatrixScalingFlag scale; tool_matrix_getScaledValue get_val; tool_matrix_getScaledValue get_inv; GArray *scaleminmax; gboolean scaleauto; float extension[3]; /* Triangle structure. */ guint level; GList *triangles; /* The min/max valuess in [0;1] after colour transformation. */ float minmax[2]; /* The min/max values in scalarfield unit. */ float valMinMax[2]; /* Desired lines description. */ guint nLines; float lineminmax[2]; GArray *lines; /* Actual line storage. */ }; enum { CHANGED_SIGNAL, NB_SIGNAL }; static guint _signals[NB_SIGNAL] = { 0 }; enum { PROP_0, FIELD_PROP, PLANE_PROP, SURFACE_PROP, SCALE_PROP, MANUAL_MM_PROP, N_PROP }; static GParamSpec *properties[N_PROP]; #define FLAG_RESOURCE_LEG_SCALE "map_legendScale" #define DESC_RESOURCE_LEG_SCALE "Choose the scale to draw the legend for coloured maps ; float (positive)" #define DEFT_RESOURCE_LEG_SCALE 1.f #define FLAG_RESOURCE_LEG_POS "map_legendPosition" #define DESC_RESOURCE_LEG_POS "Choose the legend position ; two floats (between 0 and 1)" #define DEFT_RESOURCE_LEG_POS 0.f static float legendScale, legendPosition[2]; static void exportResources(GString *data, VisuData *dataObj); static Triangle* triangle_new(float ABC[3][3], guint level); static void triangle_free(Triangle *T); static void triangle_getDataAtLevel(Triangle *T, guint level, float **data, guint *pos); static void triangle_setValues(Triangle *T, VisuScalarField *field, tool_matrix_getScaledValue get_val, float minmax[2], float extension[3]); static void triangle_draw(Triangle *T, float thresh, const ToolShade *shade); static void triangle_drawWithAlpha(Triangle *T, float thresh, const ToolShade *shade); #ifdef HAVE_CAIRO static void triangle_drawToCairo(Triangle *T, cairo_t *cr, float thresh, const ToolShade *shade, float basis[2][3], float center[3]); #endif static gboolean _compute(VisuMap *map); static gboolean _computeLines(VisuMap *map, guint nIsoLines, float minMax[2]); static void onPlaneMoved(VisuPlane *plane, gpointer data); static void onPlaneBoxed(VisuPlane *plane, VisuBox *box, gpointer data); static void onChanged(VisuScalarField *field, VisuMap *map); #define ROOT_LEVEL 0 static Triangle* triangle_new(float ABC[3][3], guint level) { Triangle *T; T = g_malloc(sizeof(Triangle)); T->children[0] = (Triangle*)0; T->children[1] = (Triangle*)0; T->children[2] = (Triangle*)0; T->children[3] = (Triangle*)0; T->minmax[0] = G_MAXFLOAT; T->minmax[1] = -G_MAXFLOAT; T->level = level; memcpy(T->vertices, ABC, sizeof(float) * 9); /* DBG_fprintf(stderr, "VisuScalarField: create Triangle %p (%d).\n", (gpointer)T, level); */ return T; } static Triangle* triangle_newFromVertices(GArray *vertices, guint level) { Triangle *T; VisuSurfacePoint *pt; g_return_val_if_fail(vertices->len == 3, (Triangle*)0); T = g_malloc(sizeof(Triangle)); T->children[0] = (Triangle*)0; T->children[1] = (Triangle*)0; T->children[2] = (Triangle*)0; T->children[3] = (Triangle*)0; T->minmax[0] = G_MAXFLOAT; T->minmax[1] = -G_MAXFLOAT; T->level = level; pt = &g_array_index(vertices, VisuSurfacePoint, 0); T->vertices[0][0] = pt->at[0]; T->vertices[0][1] = pt->at[1]; T->vertices[0][2] = pt->at[2]; pt = &g_array_index(vertices, VisuSurfacePoint, 1); T->vertices[1][0] = pt->at[0]; T->vertices[1][1] = pt->at[1]; T->vertices[1][2] = pt->at[2]; pt = &g_array_index(vertices, VisuSurfacePoint, 2); T->vertices[2][0] = pt->at[0]; T->vertices[2][1] = pt->at[1]; T->vertices[2][2] = pt->at[2]; /* DBG_fprintf(stderr, "VisuScalarField: create Triangle %p (%d).\n", (gpointer)T, level); */ return T; } static void triangle_free(Triangle *T) { if (T->children[0]) triangle_free(T->children[0]); if (T->children[1]) triangle_free(T->children[1]); if (T->children[2]) triangle_free(T->children[2]); if (T->children[3]) triangle_free(T->children[3]); g_free(T); } static void triangle_getDataAtLevel(Triangle *T, guint level, float **data, guint *pos) { if (T->level == level) { (data + (*pos))[0] = (float*)T->vertices; (data + (*pos))[1] = (float*)T->value; *pos += 2; return; } if (T->children[0]) triangle_getDataAtLevel(T->children[0], level, data, pos); if (T->children[1]) triangle_getDataAtLevel(T->children[1], level, data, pos); if (T->children[2]) triangle_getDataAtLevel(T->children[2], level, data, pos); if (T->children[3]) triangle_getDataAtLevel(T->children[3], level, data, pos); } static void _3DToVisuPlane(float uv[2], float xyz[3], float basis[2][3], float origin[3]) { uv[0] = basis[0][0] * (xyz[0] - origin[0]) + basis[0][1] * (xyz[1] - origin[1]) + basis[0][2] * (xyz[2] - origin[2]); uv[1] = basis[1][0] * (xyz[0] - origin[0]) + basis[1][1] * (xyz[1] - origin[1]) + basis[1][2] * (xyz[2] - origin[2]); } static void triangle_setValues(Triangle *T, VisuScalarField *field, tool_matrix_getScaledValue get_val, float minmax[2], float extension[3]) { double value; int i; g_return_if_fail(T); T->minmax[0] = G_MAXFLOAT; T->minmax[1] = -G_MAXFLOAT; if (field) for (i = 0; i < 3; i++) { if (!visu_scalar_field_getValue(field, T->vertices[i], &value, extension)) if (!visu_scalar_field_getValue(field, T->vertices[(i + 1) % 3], &value, extension)) visu_scalar_field_getValue(field, T->vertices[(i + 2) % 3], &value, extension); T->value[i] = (float)get_val(value, minmax); T->minmax[0] = MIN(T->minmax[0], T->value[i]); T->minmax[1] = MAX(T->minmax[1], T->value[i]); } } static void triangle_draw(Triangle *T, float thresh, const ToolShade *shade) { /* gchar str[32]; */ float rgba[4]; if ((T->minmax[1] - T->minmax[0]) <= thresh || (!T->children[0] && !T->children[1] && !T->children[2] && !T->children[3])) { glBegin(GL_TRIANGLE_STRIP); tool_shade_valueToRGB(shade, rgba, T->value[0]); glColor3fv(rgba); glVertex3fv(T->vertices[0]); tool_shade_valueToRGB(shade, rgba, T->value[1]); glColor3fv(rgba); glVertex3fv(T->vertices[1]); tool_shade_valueToRGB(shade, rgba, T->value[2]); glColor3fv(rgba); glVertex3fv(T->vertices[2]); glEnd(); /* sprintf(str, "%6.5f", T->value[0]); */ /* glColor3fv(T->rgba[0]); */ /* glRasterPos3fv(T->vertices[0]); visu_gl_text_drawChars(str, VISU_GL_TEXT_SMALL); */ /* sprintf(str, "%6.5f", T->value[1]); */ /* glColor3fv(T->rgba[1]); */ /* glRasterPos3fv(T->vertices[1]); visu_gl_text_drawChars(str, VISU_GL_TEXT_SMALL); */ /* sprintf(str, "%6.5f", T->value[2]); */ /* glColor3fv(T->rgba[2]); */ /* glRasterPos3fv(T->vertices[2]); visu_gl_text_drawChars(str, VISU_GL_TEXT_SMALL); */ return; } if (T->children[0]) triangle_draw(T->children[0], thresh, shade); if (T->children[1]) triangle_draw(T->children[1], thresh, shade); if (T->children[2]) triangle_draw(T->children[2], thresh, shade); if (T->children[3]) triangle_draw(T->children[3], thresh, shade); } static void triangle_drawWithAlpha(Triangle *T, float thresh, const ToolShade *shade) { /* gchar str[32]; */ float rgba[4]; if ((T->minmax[1] - T->minmax[0]) <= thresh || (!T->children[0] && !T->children[1] && !T->children[2] && !T->children[3])) { glBegin(GL_TRIANGLE_STRIP); tool_shade_valueToRGB(shade, rgba, T->value[0]); rgba[3] = T->value[0]; glColor4fv(rgba); glVertex3fv(T->vertices[0]); tool_shade_valueToRGB(shade, rgba, T->value[1]); rgba[3] = T->value[1]; glColor4fv(rgba); glVertex3fv(T->vertices[1]); tool_shade_valueToRGB(shade, rgba, T->value[2]); rgba[3] = T->value[2]; glColor4fv(rgba); glVertex3fv(T->vertices[2]); glEnd(); return; } if (T->children[0]) triangle_drawWithAlpha(T->children[0], thresh, shade); if (T->children[1]) triangle_drawWithAlpha(T->children[1], thresh, shade); if (T->children[2]) triangle_drawWithAlpha(T->children[2], thresh, shade); if (T->children[3]) triangle_drawWithAlpha(T->children[3], thresh, shade); } #ifdef HAVE_CAIRO static void triangle_drawToCairo(Triangle *T, cairo_t *cr, float thresh, const ToolShade *shade, float basis[2][3], float center[3]) { float uv[2]; float v, rgba[4]; if ((T->minmax[1] - T->minmax[0]) <= thresh || (!T->children[0] && !T->children[1] && !T->children[2] && !T->children[3])) { v = (T->value[0] + T->value[1] + T->value[2]) / 3.f; tool_shade_valueToRGB(shade, rgba, v); cairo_set_source_rgba(cr, rgba[0], rgba[1], rgba[2], 1.f); _3DToVisuPlane(uv, T->vertices[0], basis, center); cairo_move_to(cr, uv[0], uv[1]); _3DToVisuPlane(uv, T->vertices[1], basis, center); cairo_line_to(cr, uv[0], uv[1]); _3DToVisuPlane(uv, T->vertices[2], basis, center); cairo_line_to(cr, uv[0], uv[1]); _3DToVisuPlane(uv, T->vertices[0], basis, center); cairo_line_to(cr, uv[0], uv[1]); cairo_fill_preserve(cr); /* cairo_set_source_rgb(cr, 0., 0., 0.); */ cairo_stroke(cr); return; } if (T->children[0]) triangle_drawToCairo(T->children[0], cr, thresh, shade, basis, center); if (T->children[1]) triangle_drawToCairo(T->children[1], cr, thresh, shade, basis, center); if (T->children[2]) triangle_drawToCairo(T->children[2], cr, thresh, shade, basis, center); if (T->children[3]) triangle_drawToCairo(T->children[3], cr, thresh, shade, basis, center); } #endif static void visu_map_dispose (GObject* obj); static void visu_map_finalize (GObject* obj); static void visu_map_get_property(GObject* obj, guint property_id, GValue *value, GParamSpec *pspec); static void visu_map_set_property(GObject* obj, guint property_id, const GValue *value, GParamSpec *pspec); G_DEFINE_TYPE_WITH_CODE(VisuMap, visu_map, VISU_TYPE_OBJECT, G_ADD_PRIVATE(VisuMap)) /**************************/ /* The Map object itself. */ /**************************/ static void visu_map_class_init(VisuMapClass *klass) { float rgWidth[2] = {0.01f, 10.f}; float rgPos[2] = {0.f, 1.f}; VisuConfigFileEntry *conf; DBG_fprintf(stderr, "Visu Map: creating the class of the object.\n"); DBG_fprintf(stderr, " - adding new signals ;\n"); /* Connect the overloading methods. */ G_OBJECT_CLASS(klass)->dispose = visu_map_dispose; G_OBJECT_CLASS(klass)->finalize = visu_map_finalize; G_OBJECT_CLASS(klass)->set_property = visu_map_set_property; G_OBJECT_CLASS(klass)->get_property = visu_map_get_property; klass->computePool = (GThreadPool*)0; /** * VisuMap::changed: * @map: the object emitting the signal. * * This signal is emitted each time the map has been changed and recomputed. * * Since: 3.8 */ _signals[CHANGED_SIGNAL] = g_signal_new("changed", G_TYPE_FROM_CLASS(klass), G_SIGNAL_RUN_LAST | G_SIGNAL_NO_RECURSE | G_SIGNAL_NO_HOOKS, 0, NULL, NULL, g_cclosure_marshal_VOID__VOID, G_TYPE_NONE, 0); /** * VisuMap::field: * * Field with the values used to colour the map. * * Since: 3.8 */ properties[FIELD_PROP] = g_param_spec_object("field", "Field", "projection field", VISU_TYPE_SCALAR_FIELD, G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS); g_object_class_install_property (G_OBJECT_CLASS(klass), FIELD_PROP, properties[FIELD_PROP]); /** * VisuMap::plane: * * Projection plane for the coloured map. * * Since: 3.8 */ properties[PLANE_PROP] = g_param_spec_object("plane", "Plane", "projection plane", VISU_TYPE_PLANE, G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS); g_object_class_install_property (G_OBJECT_CLASS(klass), PLANE_PROP, properties[PLANE_PROP]); /** * VisuMap::surface: * * Projection surface for the coloured map. * * Since: 3.8 */ properties[SURFACE_PROP] = g_param_spec_object("surface", "Surface", "projection surface", VISU_TYPE_SURFACE, G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS); g_object_class_install_property (G_OBJECT_CLASS(klass), SURFACE_PROP, properties[SURFACE_PROP]); /** * VisuMap::scale: * * Scaling method to transform the field values into [0;1]. * * Since: 3.8 */ properties[SCALE_PROP] = g_param_spec_uint("scale", "Scale", "scaling scheme of input values", 0, TOOL_MATRIX_SCALING_N_VALUES - 1, TOOL_MATRIX_SCALING_LINEAR, G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS); g_object_class_install_property (G_OBJECT_CLASS(klass), SCALE_PROP, properties[SCALE_PROP]); /** * VisuMap::range-min-max: * * Min / max range as used to normalise data. Default are the data * min / max themselves. * * Since: 3.8 */ properties[MANUAL_MM_PROP] = g_param_spec_boxed("range-min-max", "Range min/max", "min / max range to normalise data", G_TYPE_ARRAY, G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS); g_object_class_install_property (G_OBJECT_CLASS(klass), MANUAL_MM_PROP, properties[MANUAL_MM_PROP]); DBG_fprintf(stderr, " - set the conf entries.\n"); conf = visu_config_file_addFloatArrayEntry(VISU_CONFIG_FILE_RESOURCE, FLAG_RESOURCE_LEG_SCALE, DESC_RESOURCE_LEG_SCALE, 1, &legendScale, rgWidth, FALSE); visu_config_file_entry_setVersion(conf, 3.7f); conf = visu_config_file_addFloatArrayEntry(VISU_CONFIG_FILE_RESOURCE, FLAG_RESOURCE_LEG_POS, DESC_RESOURCE_LEG_POS, 2, legendPosition, rgPos, FALSE); visu_config_file_entry_setVersion(conf, 3.7f); visu_config_file_addExportFunction(VISU_CONFIG_FILE_RESOURCE, exportResources); legendScale = DEFT_RESOURCE_LEG_SCALE; legendPosition[0] = DEFT_RESOURCE_LEG_POS; legendPosition[1] = DEFT_RESOURCE_LEG_POS; } static void visu_map_init(VisuMap *obj) { DBG_fprintf(stderr, "Visu Map: initializing a new object (%p).\n", (gpointer)obj); obj->priv = visu_map_get_instance_private(obj); obj->priv->dispose_has_run = FALSE; g_mutex_init(&obj->priv->access); obj->priv->dirty = 0; obj->priv->computing = FALSE; g_mutex_init(&obj->priv->mutex); obj->priv->plane = (VisuPlane*)0; obj->priv->moved_signal = 0; obj->priv->boxed_signal = 0; obj->priv->surface = (VisuSurface*)0; obj->priv->field = (VisuScalarField*)0; obj->priv->changed_sig = 0; obj->priv->scale = TOOL_MATRIX_SCALING_LINEAR; obj->priv->get_val = tool_matrix_getScaledLinear; obj->priv->get_inv = tool_matrix_getScaledLinearInv; obj->priv->scaleminmax = g_array_sized_new(FALSE, FALSE, sizeof(float), 2); obj->priv->scaleauto = TRUE; obj->priv->level = 0; obj->priv->minmax[0] = G_MAXFLOAT; obj->priv->minmax[1] = -G_MAXFLOAT; obj->priv->triangles = (GList*)0; obj->priv->nLines = 0; obj->priv->lines = g_array_new(FALSE, FALSE, sizeof(VisuLine*)); g_array_set_clear_func(obj->priv->lines, (GDestroyNotify)visu_line_unref); } /* This method can be called several times. It should unref all of its reference to GObjects. */ static void visu_map_dispose(GObject* obj) { VisuMap *map; DBG_fprintf(stderr, "Visu Map: dispose object %p.\n", (gpointer)obj); map = VISU_MAP(obj); if (map->priv->dispose_has_run) return; map->priv->dispose_has_run = TRUE; /* Disconnect signals. */ visu_map_setPlane(map, (VisuPlane*)0); visu_map_setField(map, (VisuScalarField*)0); /* Chain up to the parent class */ G_OBJECT_CLASS(visu_map_parent_class)->dispose(obj); } /* This method is called once only. */ static void visu_map_finalize(GObject* obj) { VisuMap *map; g_return_if_fail(obj); DBG_fprintf(stderr, "Visu Map: finalize object %p.\n", (gpointer)obj); map = VISU_MAP(obj); g_array_free(map->priv->scaleminmax, TRUE); g_array_free(map->priv->lines, TRUE); g_mutex_lock(&map->priv->mutex); g_mutex_unlock(&map->priv->mutex); g_mutex_clear(&map->priv->mutex); g_mutex_lock(&map->priv->access); g_mutex_unlock(&map->priv->access); g_mutex_clear(&map->priv->access); /* Chain up to the parent class */ DBG_fprintf(stderr, "Visu Map: chain to parent.\n"); G_OBJECT_CLASS(visu_map_parent_class)->finalize(obj); DBG_fprintf(stderr, "Visu Map: freeing ... OK.\n"); } static void visu_map_get_property(GObject* obj, guint property_id, GValue *value, GParamSpec *pspec) { VisuMapPrivate *self = VISU_MAP(obj)->priv; DBG_fprintf(stderr, "Visu Map: get property '%s' -> ", g_param_spec_get_name(pspec)); switch (property_id) { case FIELD_PROP: g_value_set_object(value, self->field); DBG_fprintf(stderr, "%p\n", (gpointer)self->field); break; case PLANE_PROP: g_value_set_object(value, self->plane); DBG_fprintf(stderr, "%p\n", (gpointer)self->plane); break; case SURFACE_PROP: g_value_set_object(value, self->surface); DBG_fprintf(stderr, "%p\n", (gpointer)self->surface); break; case SCALE_PROP: g_value_set_uint(value, self->scale); DBG_fprintf(stderr, "%d\n", self->scale); break; case MANUAL_MM_PROP: g_value_set_boxed(value, self->scaleminmax); DBG_fprintf(stderr, "%p.\n", (gpointer)self->scaleminmax); break; default: /* We don't have any other property... */ G_OBJECT_WARN_INVALID_PROPERTY_ID(obj, property_id, pspec); break; } } static void visu_map_set_property(GObject* obj, guint property_id, const GValue *value, GParamSpec *pspec) { GArray *arr; DBG_fprintf(stderr, "Visu Map: set property '%s' -> ", g_param_spec_get_name(pspec)); switch (property_id) { case FIELD_PROP: DBG_fprintf(stderr, "%p\n", (gpointer)g_value_get_object(value)); visu_map_setField(VISU_MAP(obj), VISU_SCALAR_FIELD(g_value_get_object(value))); break; case PLANE_PROP: DBG_fprintf(stderr, "%p\n", (gpointer)g_value_get_object(value)); visu_map_setPlane(VISU_MAP(obj), VISU_PLANE(g_value_get_object(value))); break; case SCALE_PROP: DBG_fprintf(stderr, "%d\n", g_value_get_uint(value)); visu_map_setScaling(VISU_MAP(obj), g_value_get_uint(value)); break; case MANUAL_MM_PROP: arr = (GArray*)g_value_get_boxed(value); g_return_if_fail(arr && arr->len == 2); visu_map_setScalingRange(VISU_MAP(obj), (arr) ? (float*)arr->data : (float*)0); break; default: /* We don't have any other property... */ G_OBJECT_WARN_INVALID_PROPERTY_ID(obj, property_id, pspec); break; } } /** * visu_map_new: * * Creates a new #VisuMap object. * * Since: 3.6 * * Returns: (transfer full): a newly created #VisuMap object. */ VisuMap* visu_map_new() { VisuMap *map; map = VISU_MAP(g_object_new(VISU_TYPE_MAP, NULL)); return map; } /** * visu_map_new_fromPlane: * @plane: a #VisuPlane object. * * Creates a new #VisuMap object, projected on @plane. * * Since: 3.6 * * Returns: a newly created #VisuMap object. */ VisuMap* visu_map_new_fromPlane(VisuPlane *plane) { VisuMap *map; map = VISU_MAP(g_object_new(VISU_TYPE_MAP, "plane", plane, NULL)); return map; } static void _setDirty(VisuMap *map) { DBG_fprintf(stderr, "Visu Map: set dirty (%d).\n", map->priv->dirty); if (map->priv->dirty) return; map->priv->dirty = g_idle_add((GSourceFunc)_compute, map); DBG_fprintf(stderr, "Visu Map (%p): create dirty idle %d.\n", (gpointer)g_thread_self(), map->priv->dirty); } static float** _getDataAtLevel(GList *triangles, guint level, guint *n) { float **data; guint i, m; GList *lst; g_return_val_if_fail(level < 13, (float**)0); m = pow(4, level) * g_list_length(triangles); if (!m) return (float**)0; data = g_malloc(sizeof(float*) * m * 2); if (n) *n = m; DBG_fprintf(stderr, "Visu Map: generate the %d triangle data for %d triangles.\n", g_list_length(triangles), m); i = 0; for (lst = triangles; lst; lst = g_list_next(lst)) triangle_getDataAtLevel((Triangle*)lst->data, level, data, &i); return data; } static void _freeLines(VisuMap *map) { DBG_fprintf(stderr, "Map: free old lines (%d).\n", map->priv->lines->len); g_array_set_size(map->priv->lines, 0); } static void _freeTriangles(VisuMap *map) { g_list_free_full(map->priv->triangles, (GDestroyNotify)triangle_free); map->priv->triangles = (GList*)0; _freeLines(map); } static void _setTriangles(VisuMap *map, VisuPlane *plane) { GList *inter, *lst; float xyz[2][3], ABC[3][3]; guint i; g_mutex_lock(&map->priv->access); /* Free currently allocated triangles. */ _freeTriangles(map); inter = (plane && (visu_boxed_getBox(VISU_BOXED(plane)) != (VisuBox*)0)) ? visu_plane_getIntersection(plane) : (GList*)0; if (inter) { /* Reallocate everyone. */ visu_plane_getBasis(plane, xyz, ABC[0]); i = 1; ABC[i][0] = ((float*)inter->data)[0]; ABC[i][1] = ((float*)inter->data)[1]; ABC[i][2] = ((float*)inter->data)[2]; for (lst = g_list_next(inter); lst; lst = g_list_next(lst)) { i = i % 2 + 1; ABC[i][0] = ((float*)lst->data)[0]; ABC[i][1] = ((float*)lst->data)[1]; ABC[i][2] = ((float*)lst->data)[2]; map->priv->triangles = g_list_append(map->priv->triangles, triangle_new(ABC, ROOT_LEVEL)); } i = i % 2 + 1; ABC[i][0] = ((float*)inter->data)[0]; ABC[i][1] = ((float*)inter->data)[1]; ABC[i][2] = ((float*)inter->data)[2]; map->priv->triangles = g_list_append(map->priv->triangles, triangle_new(ABC, ROOT_LEVEL)); } g_mutex_unlock(&map->priv->access); } /** * visu_map_setPlane: * @map: a #VisuMap object. * @plane: (transfer full) (allow-none): a #VisuPlane object. * * Set the internal #VisuPlane of @map to @plane. All changed to * @plane will be automatically propagated to @map. Use * visu_map_setField() to choose the field to take values from, set * the level precision with visu_map_setLevel(). * * Since: 3.7 * * Returns: TRUE if internal plane is changed. **/ gboolean visu_map_setPlane(VisuMap *map, VisuPlane *plane) { g_return_val_if_fail(map, FALSE); if (map->priv->plane == plane) return FALSE; /* Free previous handle on plane. */ if (map->priv->plane) { g_signal_handler_disconnect(G_OBJECT(map->priv->plane), map->priv->moved_signal); g_signal_handler_disconnect(G_OBJECT(map->priv->plane), map->priv->boxed_signal); g_object_unref(map->priv->plane); } map->priv->plane = plane; if (plane) { g_object_ref(plane); map->priv->moved_signal = g_signal_connect(G_OBJECT(plane), "moved", G_CALLBACK(onPlaneMoved), (gpointer)map); map->priv->boxed_signal = g_signal_connect(G_OBJECT(plane), "setBox", G_CALLBACK(onPlaneBoxed), (gpointer)map); if (visu_boxed_getBox(VISU_BOXED(plane)) != (VisuBox*)0) visu_box_getExtension(visu_boxed_getBox(VISU_BOXED(map->priv->plane)), map->priv->extension); } _setTriangles(map, plane); _setDirty(map); return TRUE; } static void _setTrianglesFromSurface(VisuMap *map, VisuSurface *surface) { VisuSurfaceIterPoly iter; GArray *vertices; g_mutex_lock(&map->priv->access); /* Free currently allocated triangles. */ _freeTriangles(map); vertices = g_array_sized_new(FALSE, FALSE, sizeof(VisuSurfacePoint), 3); for (visu_surface_iter_poly_new(surface, &iter); iter.valid; visu_surface_iter_poly_next(&iter)) { visu_surface_iter_poly_getVertices(&iter, vertices); if (vertices->len == 3) map->priv->triangles = g_list_append(map->priv->triangles, triangle_newFromVertices(vertices, ROOT_LEVEL)); } g_mutex_unlock(&map->priv->access); } /** * visu_map_setSurface: * @map: a #VisuMap object. * @surface: (transfer full) (allow-none): a #VisuSurface object. * * Set the internal #VisuSurface of @map to @surface. All changed to * @surface will be automatically propagated to @map. Use * visu_map_setField() to choose the field to take values from, set * the level precision with visu_map_setLevel(). * * Since: 3.8 * * Returns: TRUE if internal surface is changed. **/ gboolean visu_map_setSurface(VisuMap *map, VisuSurface *surface) { g_return_val_if_fail(VISU_IS_MAP(map), FALSE); if (map->priv->surface == surface) return FALSE; /* Free previous handle on surface. */ if (map->priv->surface) { /* g_signal_handler_disconnect(G_OBJECT(map->priv->surface), map->priv->moved_signal); */ /* g_signal_handler_disconnect(G_OBJECT(map->priv->surface), map->priv->boxed_signal); */ g_object_unref(map->priv->surface); } map->priv->surface = surface; if (surface) { g_object_ref(surface); /* map->priv->moved_signal = g_signal_connect(G_OBJECT(surface), "moved", */ /* G_CALLBACK(onSurfaceMoved), (gpointer)map); */ /* map->priv->boxed_signal = g_signal_connect(G_OBJECT(surface), "setBox", */ /* G_CALLBACK(onSurfaceBoxed), (gpointer)map); */ if (visu_boxed_getBox(VISU_BOXED(surface)) != (VisuBox*)0) visu_box_getExtension(visu_boxed_getBox(VISU_BOXED(map->priv->surface)), map->priv->extension); } _setTrianglesFromSurface(map, surface); _setDirty(map); return TRUE; } /** * visu_map_setField: * @map: a #VisuMap object. * @field: a #VisuScalarField object. * * It associates the values of @field to @map. * * Since: 3.6 * * Returns: TRUE if @field is changed. */ gboolean visu_map_setField(VisuMap *map, VisuScalarField *field) { double minMax_[2]; g_return_val_if_fail(map, FALSE); if (map->priv->field) { g_signal_handler_disconnect(G_OBJECT(map->priv->field), map->priv->changed_sig); g_object_unref(G_OBJECT(map->priv->field)); } map->priv->field = field; map->priv->minmax[0] = G_MAXFLOAT; map->priv->minmax[1] = -G_MAXFLOAT; if (field) { g_object_ref(G_OBJECT(field)); map->priv->changed_sig = g_signal_connect(G_OBJECT(field), "changed", G_CALLBACK(onChanged), (gpointer)map); DBG_fprintf(stderr, "Visu Map: attach 'changed' signal from %p.\n", (gpointer)field); if (map->priv->scaleauto) { visu_scalar_field_getMinMax(map->priv->field, minMax_); g_array_index(map->priv->scaleminmax, float, 0) = minMax_[0]; g_array_index(map->priv->scaleminmax, float, 1) = minMax_[1]; g_object_notify_by_pspec(G_OBJECT(map), properties[MANUAL_MM_PROP]); } } _freeTriangles(map); if (map->priv->plane) _setTriangles(map, map->priv->plane); if (map->priv->surface) _setTrianglesFromSurface(map, map->priv->surface); _setDirty(map); return TRUE; } /** * visu_map_setScaling: * @map: a #VisuMap object. * @scale: a flag. * * The scaling algorithm to transform input values into [0;1] is * defined by @scale. * * Since: 3.8 * * Returns: TRUE if @scale is changed. **/ gboolean visu_map_setScaling(VisuMap *map, ToolMatrixScalingFlag scale) { g_return_val_if_fail(VISU_IS_MAP(map), FALSE); if (scale == map->priv->scale) return FALSE; /* In log scale, we need the second minimum value. */ map->priv->scale = scale; switch (scale) { case TOOL_MATRIX_SCALING_LINEAR: map->priv->get_val = tool_matrix_getScaledLinear; map->priv->get_inv = tool_matrix_getScaledLinearInv; break; case TOOL_MATRIX_SCALING_LOG: map->priv->get_val = tool_matrix_getScaledLog; map->priv->get_inv = tool_matrix_getScaledLogInv; break; case TOOL_MATRIX_SCALING_ZERO_CENTRED_LOG: map->priv->get_val = tool_matrix_getScaledZeroCentredLog; map->priv->get_inv = tool_matrix_getScaledZeroCentredLogInv; break; default: map->priv->get_val = tool_matrix_getScaledLinear; map->priv->get_inv = tool_matrix_getScaledLinearInv; break; } g_object_notify_by_pspec(G_OBJECT(map), properties[SCALE_PROP]); _setDirty(map); return TRUE; } /** * visu_map_setScalingRange: * @map: a #VisuMap object. * @minMax: (allow-none) (array fixed-size=2): two floats defining a * range for input scaling. * * If @minMax is provided, these values are used to scale the values * of @field to [0;1], otherwise the minMax values of the field itself * are used. * * Since: 3.8 * * Returns: TRUE if @minMax is changed. **/ gboolean visu_map_setScalingRange(VisuMap *map, const float *minMax) { double minMax_[2]; g_return_val_if_fail(VISU_IS_MAP(map), FALSE); DBG_fprintf(stderr, "Visu Map: set map %p scaling range to %p (%d).\n", (gpointer)map, (gpointer)minMax, map->priv->scaleauto); if ((!minMax && map->priv->scaleauto) || (minMax && !map->priv->scaleauto && minMax[0] == g_array_index(map->priv->scaleminmax, float, 0) && minMax[1] == g_array_index(map->priv->scaleminmax, float, 1))) return FALSE; map->priv->scaleauto = (minMax == (float*)0); if (minMax) { g_array_index(map->priv->scaleminmax, float, 0) = minMax[0]; g_array_index(map->priv->scaleminmax, float, 1) = minMax[1]; } else if (map->priv->field) { visu_scalar_field_getMinMax(map->priv->field, minMax_); DBG_fprintf(stderr, "Visu Map: set map %p min/max to %g / %g.\n", (gpointer)map, minMax_[0], minMax_[1]); g_array_index(map->priv->scaleminmax, float, 0) = minMax_[0]; g_array_index(map->priv->scaleminmax, float, 1) = minMax_[1]; } g_object_notify_by_pspec(G_OBJECT(map), properties[MANUAL_MM_PROP]); _setDirty(map); return TRUE; } /** * visu_map_setLevel: * @map: a #VisuMap object. * @glPrec: the global OpenGL precision for drawing (default is 1.). * @gross: current zoom level. * @refLength: a reference length (see visu_gl_camera_getRefLength()). * * Setup the level of recursivity in triangle calculation, depending * on the current zoom level. * * Since: 3.6 * * Returns: TRUE if the level is actually changed. */ gboolean visu_map_setLevel(VisuMap *map, float glPrec, float gross, float refLength) { float length, mLength; GList *lst; guint level; Triangle *tri; g_return_val_if_fail(map, FALSE); /* Compute the longest triangle length. */ mLength = 0.f; for (lst = map->priv->triangles; lst; lst = g_list_next(lst)) { tri = (Triangle*)lst->data; mLength = MAX(mLength, (tri->vertices[0][0] - tri->vertices[1][0]) * (tri->vertices[0][0] - tri->vertices[1][0]) + (tri->vertices[0][1] - tri->vertices[1][1]) * (tri->vertices[0][1] - tri->vertices[1][1]) + (tri->vertices[0][2] - tri->vertices[1][2]) * (tri->vertices[0][2] - tri->vertices[1][2])); mLength = MAX(mLength, (tri->vertices[1][0] - tri->vertices[2][0]) * (tri->vertices[1][0] - tri->vertices[2][0]) + (tri->vertices[1][1] - tri->vertices[2][1]) * (tri->vertices[1][1] - tri->vertices[2][1]) + (tri->vertices[1][2] - tri->vertices[2][2]) * (tri->vertices[1][2] - tri->vertices[2][2])); mLength = MAX(mLength, (tri->vertices[2][0] - tri->vertices[0][0]) * (tri->vertices[2][0] - tri->vertices[0][0]) + (tri->vertices[2][1] - tri->vertices[0][1]) * (tri->vertices[2][1] - tri->vertices[0][1]) + (tri->vertices[2][2] - tri->vertices[0][2]) * (tri->vertices[2][2] - tri->vertices[0][2])); } /* We put by default (precision and gross = 1) 200 triangles along the longest line in the box. */ length = refLength / (200. * glPrec * (gross * .5 + .5)); level = MIN(12, MAX((guint)(log(sqrt(mLength) / length) / log(2)), 2) - 1); DBG_fprintf(stderr, "Map: number of division %d for map %p.\n", level, (gpointer)map); if (level == map->priv->level) return FALSE; map->priv->level = level; _setDirty(map); return TRUE; } /** * visu_map_setLines: * @map: a #VisuMap object. * @nIsoLines: number of required isolines. * @minmax: span for isoline values. * * Calculate @nIsoLines equally distributed in @minmax. * * Since: 3.6 * * Returns: TRUE if lines are successfully calculated. */ gboolean visu_map_setLines(VisuMap *map, guint nIsoLines, float minmax[2]) { g_return_val_if_fail(map, FALSE); DBG_fprintf(stderr, "Visu Map: %p setting line min / max to %g / %g (%g / %g).\n", (gpointer)map, minmax[0], minmax[1], map->priv->lineminmax[0], map->priv->lineminmax[1]); if (minmax[1] <= minmax[0]) return FALSE; if (map->priv->nLines == nIsoLines && map->priv->lineminmax[0] == minmax[0] && map->priv->lineminmax[1] == minmax[1]) return FALSE; if (_computeLines(map, nIsoLines, minmax)) g_signal_emit(G_OBJECT(map), _signals[CHANGED_SIGNAL], 0); return TRUE; } static void map_refine(VisuMap *map, Triangle *T) { float ABC[3][3]; g_return_if_fail(T && map && T->level < 100); /* We update the values of this triangle. */ triangle_setValues(T, map->priv->field, map->priv->get_val, (float*)map->priv->scaleminmax->data, map->priv->extension); if (T->level >= map->priv->level) return; if (!T->children[0]) { ABC[0][0] = T->vertices[0][0]; ABC[0][1] = T->vertices[0][1]; ABC[0][2] = T->vertices[0][2]; ABC[1][0] = 0.5f * (ABC[0][0] + T->vertices[1][0]); ABC[1][1] = 0.5f * (ABC[0][1] + T->vertices[1][1]); ABC[1][2] = 0.5f * (ABC[0][2] + T->vertices[1][2]); ABC[2][0] = 0.5f * (ABC[0][0] + T->vertices[2][0]); ABC[2][1] = 0.5f * (ABC[0][1] + T->vertices[2][1]); ABC[2][2] = 0.5f * (ABC[0][2] + T->vertices[2][2]); T->children[0] = triangle_new(ABC, T->level + 1); } map_refine(map, T->children[0]); T->minmax[0] = MIN(T->minmax[0], T->children[0]->minmax[0]); T->minmax[1] = MAX(T->minmax[1], T->children[0]->minmax[1]); if (!T->children[1]) { ABC[0][0] = 0.5f * (T->vertices[2][0] + T->vertices[1][0]); ABC[0][1] = 0.5f * (T->vertices[2][1] + T->vertices[1][1]); ABC[0][2] = 0.5f * (T->vertices[2][2] + T->vertices[1][2]); T->children[1] = triangle_new(ABC, T->level + 1); } map_refine(map, T->children[1]); T->minmax[0] = MIN(T->minmax[0], T->children[1]->minmax[0]); T->minmax[1] = MAX(T->minmax[1], T->children[1]->minmax[1]); if (!T->children[2]) { ABC[2][0] = T->vertices[1][0]; ABC[2][1] = T->vertices[1][1]; ABC[2][2] = T->vertices[1][2]; T->children[2] = triangle_new(ABC, T->level + 1); } map_refine(map, T->children[2]); T->minmax[0] = MIN(T->minmax[0], T->children[2]->minmax[0]); T->minmax[1] = MAX(T->minmax[1], T->children[2]->minmax[1]); if (!T->children[3]) { ABC[1][0] = 0.5f * (T->vertices[0][0] + T->vertices[2][0]); ABC[1][1] = 0.5f * (T->vertices[0][1] + T->vertices[2][1]); ABC[1][2] = 0.5f * (T->vertices[0][2] + T->vertices[2][2]); ABC[2][0] = T->vertices[2][0]; ABC[2][1] = T->vertices[2][1]; ABC[2][2] = T->vertices[2][2]; T->children[3] = triangle_new(ABC, T->level + 1); } map_refine(map, T->children[3]); T->minmax[0] = MIN(T->minmax[0], T->children[3]->minmax[0]); T->minmax[1] = MAX(T->minmax[1], T->children[3]->minmax[1]); } static GList* _lockTriangles(VisuMap *map) { GList *root; /* Disconnect the triangles during the computation. */ g_mutex_lock(&map->priv->access); root = map->priv->triangles; map->priv->triangles = (GList*)0; g_mutex_unlock(&map->priv->access); return root; } static void _unlockTriangles(VisuMap *map, GList *root) { /* Reconnect the triangles after computation. */ g_mutex_lock(&map->priv->access); if (map->priv->triangles) g_list_free_full(root, (GDestroyNotify)triangle_free); else map->priv->triangles = root; g_mutex_unlock(&map->priv->access); } static void _computeOne(Triangle* tri, VisuMap *map) { map_refine(map, tri); DBG_fprintf(stderr, " | %p done.\n", (gpointer)tri); } static void _computeAll(VisuMap *map) { GList *inter, *root; DBG_fprintf(stderr, "Map: refine all triangles of map %p (%d) for level %d.\n", (gpointer)map, g_list_length(map->priv->triangles), map->priv->level); /* if (!klass->computePool) */ /* { */ /* klass->computePool = g_thread_pool_new((GFunc)_computeOne, map, */ /* 4, TRUE, NULL); */ /* g_thread_pool_set_max_idle_time(5000); */ /* } */ /* for (inter = map->priv->triangles; inter; inter = g_list_next(inter)) */ /* g_thread_pool_push(klass->computePool, inter->data, NULL); */ /* while(g_thread_pool_get_num_threads(klass->computePool) > 0) DBG_fprintf(stderr, "%d\n", g_thread_pool_get_num_threads(klass->computePool)); */ root = _lockTriangles(map); map->priv->minmax[0] = G_MAXFLOAT; map->priv->minmax[1] = -G_MAXFLOAT; for (inter = root; inter; inter = g_list_next(inter)) { _computeOne((Triangle*)inter->data, map); map->priv->minmax[0] = MIN(map->priv->minmax[0], ((Triangle*)inter->data)->minmax[0]); map->priv->minmax[1] = MAX(map->priv->minmax[1], ((Triangle*)inter->data)->minmax[1]); } _unlockTriangles(map, root); DBG_fprintf(stderr, " | minmax is %g %g.\n", map->priv->minmax[0], map->priv->minmax[1]); map->priv->valMinMax[0] = map->priv->get_inv(map->priv->minmax[0], (float*)map->priv->scaleminmax->data); map->priv->valMinMax[1] = map->priv->get_inv(map->priv->minmax[1], (float*)map->priv->scaleminmax->data); DBG_fprintf(stderr, " | memory usage is %gko\n", g_list_length(map->priv->triangles) * pow(4, map->priv->level) * sizeof(Triangle) / 1024.f); DBG_fprintf(stderr, " | %d lines.\n", map->priv->nLines); map->priv->computing = FALSE; _computeLines(map, map->priv->nLines, map->priv->lineminmax); g_signal_emit(G_OBJECT(map), _signals[CHANGED_SIGNAL], 0); } #if GLIB_MINOR_VERSION > 35 && 0 static void _computeThread(GTask *task, VisuMap *map, gpointer data _U_, GCancellable *cancel _U_) { g_mutex_lock(&map->priv->mutex); _computeAll(map); g_mutex_unlock(&map->priv->mutex); g_task_return_boolean(task, TRUE); } #endif static gboolean _compute(VisuMap *map) { #if GLIB_MINOR_VERSION > 35 && 0 GTask *task; #endif g_return_val_if_fail(map, FALSE); if (map->priv->dirty) { DBG_fprintf(stderr, "Visu Map %p: removing dirty idle %d.\n", (gpointer)g_thread_self(), map->priv->dirty); g_source_remove(map->priv->dirty); map->priv->dirty = 0; } DBG_fprintf(stderr, "Visu Map %p: computing (%d %d %d).\n", (gpointer)g_thread_self(), g_list_length(map->priv->triangles), (map->priv->field != NULL), map->priv->field ? visu_scalar_field_isEmpty(map->priv->field) : FALSE); if (!map->priv->triangles || !map->priv->field || visu_scalar_field_isEmpty(map->priv->field)) return G_SOURCE_REMOVE; map->priv->computing = TRUE; #if GLIB_MINOR_VERSION > 35 && 0 task = g_task_new(map, NULL, NULL, NULL); g_task_run_in_thread(task, (GTaskThreadFunc)_computeThread); g_object_unref(task); #else _computeAll(map); #endif return G_SOURCE_REMOVE; } /** * visu_map_compute_sync: * @map: a #VisuMap object. * * For later use. Currently computation of maps is always synchronous. * * Since: 3.8 **/ void visu_map_compute_sync(VisuMap *map) { g_return_if_fail(VISU_IS_MAP(map)); if (map->priv->dirty) { g_source_remove(map->priv->dirty); map->priv->dirty = 0; } map->priv->computing = TRUE; _computeAll(map); } static gboolean _computeLines(VisuMap *map, guint nIsoLines, float minMax[2]) { float v, **data; guint i, j, n; VisuLine *line; DBG_fprintf(stderr, "Visu Map: create %d new lines for map %p.\n", nIsoLines, (gpointer)map); map->priv->nLines = nIsoLines; map->priv->lineminmax[0] = minMax[0]; map->priv->lineminmax[1] = minMax[1]; if (map->priv->dirty || map->priv->computing) return FALSE; g_mutex_lock(&map->priv->access); _freeLines(map); if (nIsoLines > 0) { n = 0; data = _getDataAtLevel(map->priv->triangles, map->priv->level, &n); if (data) { j = 0; for (i = 1; i <= nIsoLines; i++) { v = minMax[0] + (minMax[1] - minMax[0]) * (float)i / (float)(nIsoLines + 1); DBG_fprintf(stderr, "Map: compute line %d at value %f.\n", j, v); line = visu_line_newFromTriangles(data, n, v); if (line) g_array_insert_val(map->priv->lines, j++, line); DBG_fprintf(stderr, " | Ok %p.\n", (gpointer)line); } g_free(data); } } g_mutex_unlock(&map->priv->access); return TRUE; } static void onPlaneMoved(VisuPlane *plane, gpointer data) { VisuMap *map = (VisuMap*)data; /* We reset the plane. */ _setTriangles(map, plane); /* We recompute. */ if (map->priv->field) _setDirty(map); } static void onPlaneBoxed(VisuPlane *plane, VisuBox *box, gpointer data) { VisuMap *map = (VisuMap*)data; if (box != (VisuBox*)0) visu_box_getExtension(box, map->priv->extension); /* We reset the plane. */ _setTriangles(map, plane); /* We recompute. */ if (map->priv->field) _setDirty(map); } static void onChanged(VisuScalarField *field _U_, VisuMap *map) { DBG_fprintf(stderr, "Visu Map %p: caught 'changed' signal from %p.\n", (gpointer)g_thread_self(), (gpointer)field); if (map->priv->scaleauto) { /* Trick to force a recalculation of min/max. */ map->priv->scaleauto = FALSE; visu_map_setScalingRange(map, (const float*)0); } /* We recompute. */ _setDirty(map); } /** * visu_map_draw: * @map: a #VisuMap object. * @prec: a pourcentage value. * @shade: a #ToolShade object. * @rgb: a colour or NULL. * @alpha: a boolean. * * It draws the @map with the given @shade. @prec give the level of * refinement used to draw the map, 100 means normal and 200 means * twice smaller level. If @rgb is present, this colour is used for * possible isolines. If @alpha is TRUE, an alpha channel is added as * a linear variation of the value of each vertex. * * Since: 3.6 */ void visu_map_draw(VisuMap *map, float prec, ToolShade *shade, float *rgb, gboolean alpha) { GList *inter; float thresh; guint i; float rgba[4]; VisuLine *line; if (!map->priv->triangles || !map->priv->field) return; if (map->priv->dirty) _compute(map); if (visu_scalar_field_isEmpty(map->priv->field) || map->priv->computing) return; glDisable(GL_CULL_FACE); glDisable(GL_LIGHTING); prec = (.06f - prec * 0.0003f); DBG_fprintf(stderr, "Visu Map: %p plot triangles.\n", (gpointer)map); thresh = (map->priv->minmax[1] - map->priv->minmax[0]) * prec; if (alpha) for (inter = map->priv->triangles; inter; inter = g_list_next(inter)) triangle_drawWithAlpha((Triangle*)inter->data, thresh, shade); else for (inter = map->priv->triangles; inter; inter = g_list_next(inter)) triangle_draw((Triangle*)inter->data, thresh, shade); DBG_fprintf(stderr, "Visu Map: %p plot %d lines.\n", (gpointer)map, map->priv->lines->len); for (i = 0; i < map->priv->lines->len; i++) { line = g_array_index(map->priv->lines, VisuLine*, i); if (!rgb) { tool_shade_valueToRGB(shade, rgba, visu_line_getValue(line)); rgba[0] = 1.f - rgba[0]; rgba[1] = 1.f - rgba[1]; rgba[2] = 1.f - rgba[2]; rgb = rgba; } visu_line_draw(line, rgb); } if (!alpha && map->priv->plane) { DBG_fprintf(stderr, "Visu Map: %p plot box.\n", (gpointer)map); glLineWidth(1.f); glColor3f(0.f, 0.f, 0.f); glBegin(GL_LINE_LOOP); for (inter = visu_plane_getIntersection(map->priv->plane); inter; inter = g_list_next(inter)) glVertex3fv((float*)inter->data); glEnd(); } glEnable(GL_CULL_FACE); glEnable(GL_LIGHTING); } /** * visu_map_getPlane: * @map: a #VisuMap object. * * Retrieves the plane @map is based on. * * Since: 3.7 * * Returns: (transfer none) (allow-none): a #VisuPlane or %NULL. **/ VisuPlane* visu_map_getPlane(VisuMap *map) { g_return_val_if_fail(VISU_IS_MAP(map), (VisuPlane*)0); return map->priv->plane; } /** * visu_map_getField: * @map: a #VisuMap object. * * Retrieves the field @map is projected from. * * Since: 3.8 * * Returns: (transfer none) (allow-none): a #VisuScalarField or %NULL. **/ VisuScalarField* visu_map_getField(VisuMap *map) { g_return_val_if_fail(VISU_IS_MAP(map), (VisuScalarField*)0); return map->priv->field; } /** * visu_map_getScaledMinMax: * @map: a #VisuMap object. * @minMax: (out caller-allocates) (array fixed-size=2): two float location. * * After @map has been computed, one can access * the scaled min and max values represented in the map. For * field values, see visu_map_getFieldMinMax(). * * Since: 3.6 * * Returns: TRUE if the map has been computed and @minMax has valid values. */ gboolean visu_map_getScaledMinMax(const VisuMap *map, float minMax[2]) { g_return_val_if_fail(VISU_IS_MAP(map), FALSE); if (map->priv->dirty || map->priv->computing) return FALSE; minMax[0] = map->priv->minmax[0]; minMax[1] = map->priv->minmax[1]; return TRUE; } /** * visu_map_getFieldMinMax: * @map: a #VisuMap object. * * After @map has been computed, one can access * the min and max values of the field as represented in the map. For * scaled values, see visu_map_getScaledMinMax(). * * Since: 3.6 * * Returns: two floats being the min and the max. */ float* visu_map_getFieldMinMax(VisuMap *map) { g_return_val_if_fail(VISU_IS_MAP(map), (float*)0); return map->priv->valMinMax; } /** * visu_map_getScalingRange: * @map: a #VisuMap object. * * Retrieves the min and max values used to scale the data in @map. * * Since: 3.8 * * Returns: (array fixed-size=2): a min / max range. **/ const float* visu_map_getScalingRange(const VisuMap *map) { g_return_val_if_fail(VISU_IS_MAP(map), (const float*)0); return (const float*)map->priv->scaleminmax->data; } /** * visu_map_export: * @map: a #VisuMap object. * @shade: a #ToolShade object. * @rgb: a colour (can be NULL). * @precision: a pourcentage for rendering quality. * @filename: the location to export to. * @format: the kind of format. * @error: a location to store an error. * * Export the given map to the @format, using the @shade color. If * @rgb is provided and @map has some isolines, they will be drawn * with this colour, otherwise an inverse colour is used. * * Since: 3.6 * * Returns: TRUE if no error. */ gboolean visu_map_export(VisuMap *map, const ToolShade *shade, const float *rgb, float precision, const gchar *filename, VisuMapExportFormat format, GError **error) { #ifdef HAVE_CAIRO #define fact 25.f float viewport[4]; guint i, j; float *uvs; guint nVals; cairo_surface_t *surface; cairo_t *cr; cairo_status_t status; cairo_matrix_t mat = {fact, 0., 0., fact, 0., 0.}; float basis[2][3], center[3], uv[2], rgba[4]; GList *lst; VisuLine *line; g_return_val_if_fail(error && *error == (GError*)0, FALSE); viewport[0] = viewport[2] = G_MAXFLOAT; viewport[1] = viewport[3] = -G_MAXFLOAT; visu_plane_getBasis(map->priv->plane, basis, center); for (lst = visu_plane_getIntersection(map->priv->plane); lst; lst = g_list_next(lst)) { _3DToVisuPlane(uv, (float*)lst->data, basis, center); viewport[0] = MIN(viewport[0], uv[0]); viewport[1] = MAX(viewport[1], uv[0]); viewport[2] = MIN(viewport[2], uv[1]); viewport[3] = MAX(viewport[3], uv[1]); } DBG_fprintf(stderr, "Map: begin export to PDF/SVG in (%f-%f x %f-%f).\n", viewport[0], viewport[1], viewport[2], viewport[3]); switch (format) { case VISU_MAP_EXPORT_SVG: surface = cairo_svg_surface_create(filename, (double)((viewport[1] - viewport[0]) * fact), (double)((viewport[3] - viewport[2]) * fact)); break; case VISU_MAP_EXPORT_PDF: surface = cairo_pdf_surface_create(filename, (double)((viewport[1] - viewport[0]) * fact), (double)((viewport[3] - viewport[2]) * fact)); break; default: surface = (cairo_surface_t*)0; } status = cairo_surface_status(surface); if (status != CAIRO_STATUS_SUCCESS) { *error = g_error_new(G_FILE_ERROR, G_FILE_ERROR_FAILED, "%s", cairo_status_to_string(status)); cairo_surface_destroy(surface); return FALSE; } cr = cairo_create(surface); status = cairo_status(cr); if (status != CAIRO_STATUS_SUCCESS) { *error = g_error_new(G_FILE_ERROR, G_FILE_ERROR_FAILED, "%s", cairo_status_to_string(status)); cairo_destroy(cr); cairo_surface_destroy(surface); return FALSE; } mat.x0 = -(double)viewport[0] * fact; mat.y0 = -(double)viewport[2] * fact; cairo_set_matrix(cr, &mat); cairo_set_line_cap(cr, CAIRO_LINE_CAP_BUTT); cairo_set_line_join(cr, CAIRO_LINE_JOIN_BEVEL); cairo_set_line_width(cr, 0.01); if (map->priv->dirty) _compute(map); while (map->priv->computing) { g_mutex_lock(&map->priv->mutex); g_mutex_unlock(&map->priv->mutex); } for (lst = map->priv->triangles; lst; lst = g_list_next(lst)) triangle_drawToCairo((Triangle*)lst->data, cr, (map->priv->minmax[1] - map->priv->minmax[0]) * (.06f - precision * 0.0003f), shade, basis, center); /* Add isolines. */ DBG_fprintf(stderr, "Map: export isolines.\n"); for (i = 0; i < map->priv->lines->len; i++) { line = g_array_index(map->priv->lines, VisuLine*, i); if (!rgb) { tool_shade_valueToRGB(shade, rgba, visu_line_getValue(line)); rgba[0] = 1.f - rgba[0]; rgba[1] = 1.f - rgba[1]; rgba[2] = 1.f - rgba[2]; rgba[3] = 1.f; rgb = rgba; } cairo_set_source_rgb(cr, rgb[0], rgb[1], rgb[2]); DBG_fprintf(stderr, "VisuScalarFields: project line on plane %p.\n", (gpointer)map->priv->plane); uvs = visu_line_project(line, map->priv->plane, &nVals); for (j = 0; j < nVals; j++) { cairo_move_to(cr, uvs[j * 4 + 0], uvs[j * 4 + 1]); cairo_line_to(cr, uvs[j * 4 + 2], uvs[j * 4 + 3]); cairo_stroke(cr); } g_free(uvs); } /* Add frame. */ DBG_fprintf(stderr, "Map: export the frame.\n"); uvs = visu_plane_getReducedIntersection(map->priv->plane, &nVals); if (uvs) { cairo_set_source_rgb(cr, 0., 0., 0.); cairo_move_to(cr, uvs[(nVals - 1) * 2 + 0], uvs[(nVals - 1) * 2 + 1]); for (j = 0; j < nVals; j++) cairo_line_to(cr, uvs[j * 2 + 0], uvs[j * 2 + 1]); cairo_stroke(cr); g_free(uvs); } /* Add legend. */ /* toolShadeExport(shade, (double)(viewport[2] * fact), */ /* (double)(viewport[3] * fact)); */ /* Finalising */ cairo_show_page(cr); cairo_destroy(cr); cairo_surface_destroy(surface); return TRUE; #else g_error("Not compiled with CAIRO not able to export."); return FALSE; #endif } /*************************/ /* Resources management. */ /*************************/ static void exportResources(GString *data, VisuData *dataObj _U_) { visu_config_file_exportComment(data, DESC_RESOURCE_LEG_SCALE); visu_config_file_exportEntry(data, FLAG_RESOURCE_LEG_SCALE, NULL, "%f", legendScale); visu_config_file_exportComment(data, DESC_RESOURCE_LEG_POS); visu_config_file_exportEntry(data, FLAG_RESOURCE_LEG_POS, NULL, "%f %f", legendPosition[0], legendPosition[1]); visu_config_file_exportComment(data, ""); } /** * visu_map_getLegendScale: * * Retrieve information about the static legend attached to maps. * * Since: 3.7 * * Returns: the scale factor of the static legend associated to maps. **/ float visu_map_getLegendScale() { return legendScale; } /** * visu_map_getLegendPosition: * @dir: %TOOL_XYZ_X or %TOOL_XYZ_Y * * Retrieve information about the static legend attached to maps. * * Since: 3.7 * * Returns: the static legend position on screen in reduced coordinates. **/ float visu_map_getLegendPosition(ToolXyzDir dir) { return (dir == TOOL_XYZ_X || dir == TOOL_XYZ_Y)?legendPosition[dir]:0.f; } v_sim-3.8.0/src/extraFunctions/map.h000066400000000000000000000124311370110300500173570ustar00rootroot00000000000000/* EXTRAITS DE LA LICENCE Copyright CEA, contributeurs : Luc BILLARD, Damien CALISTE, Olivier D'Astier, laboratoire L_Sim, (2001-2005) Adresses mèl : BILLARD, non joignable par mèl ; CALISTE, damien P caliste AT cea P fr. D'ASTIER, dastier AT iie P cnam P fr. Ce logiciel est un programme informatique servant à visualiser des structures atomiques dans un rendu pseudo-3D. Ce logiciel est régi par la licence CeCILL soumise au droit français et respectant les principes de diffusion des logiciels libres. Vous pouvez utiliser, modifier et/ou redistribuer ce programme sous les conditions de la licence CeCILL telle que diffusée par le CEA, le CNRS et l'INRIA sur le site "http://www.cecill.info". Le fait que vous puissiez accéder à cet en-tête signifie que vous avez pris connaissance de la licence CeCILL, et que vous en avez accepté les termes (cf. le fichier Documentation/licence.fr.txt fourni avec ce logiciel). */ /* LICENCE SUM UP Copyright CEA, contributors : Luc BILLARD and Damien CALISTE and Olivier D'Astier, laboratoire L_Sim, (2001-2005) E-mail addresses : BILLARD, not reachable any more ; CALISTE, damien P caliste AT cea P fr. D'ASTIER, dastier AT iie P cnam P fr. This software is a computer program whose purpose is to visualize atomic configurations in 3D. This software is governed by the CeCILL license under French law and abiding by the rules of distribution of free software. You can use, modify and/ or redistribute the software under the terms of the CeCILL license as circulated by CEA, CNRS and INRIA at the following URL "http://www.cecill.info". The fact that you are presently reading this means that you have had knowledge of the CeCILL license and that you accept its terms. You can find a copy of this licence shipped with this software at Documentation/licence.en.txt. */ #ifndef MAP_H #define MAP_H #include #include "scalarFields.h" #include "plane.h" #include "surfaces.h" #include #include /** * VisuMapExportFormat: * @VISU_MAP_EXPORT_SVG: SVG export ; * @VISU_MAP_EXPORT_PDF: PDF export. * * Possible export for the map, see visu_map_export(). * * Since: 3.6 */ typedef enum { VISU_MAP_EXPORT_SVG, VISU_MAP_EXPORT_PDF } VisuMapExportFormat; /** * VISU_TYPE_MAP: * * return the type of #VisuMap. */ #define VISU_TYPE_MAP (visu_map_get_type ()) /** * VISU_MAP: * @obj: a #GObject to cast. * * Cast the given @obj into #VisuMap type. */ #define VISU_MAP(obj) (G_TYPE_CHECK_INSTANCE_CAST(obj, VISU_TYPE_MAP, VisuMap)) /** * VISU_MAP_CLASS: * @klass: a #GObjectClass to cast. * * Cast the given @klass into #VisuMapClass. */ #define VISU_MAP_CLASS(klass) (G_TYPE_CHECK_CLASS_CAST(klass, VISU_TYPE_MAP, VisuMapClass)) /** * VISU_IS_MAP: * @obj: a #GObject to test. * * Test if the given @ogj is of the type of #VisuMap object. */ #define VISU_IS_MAP(obj) (G_TYPE_CHECK_INSTANCE_TYPE(obj, VISU_TYPE_MAP)) /** * VISU_IS_MAP_CLASS: * @klass: a #GObjectClass to test. * * Test if the given @klass is of the type of #VisuMapClass class. */ #define VISU_IS_MAP_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE(klass, VISU_TYPE_MAP)) /** * VISU_MAP_GET_CLASS: * @obj: a #GObject to get the class of. * * It returns the class of the given @obj. */ #define VISU_MAP_GET_CLASS(obj) (G_TYPE_INSTANCE_GET_CLASS(obj, VISU_TYPE_MAP, VisuMapClass)) /** * VisuMapPrivate: * * Private data for #VisuMap objects. */ typedef struct _VisuMapPrivate VisuMapPrivate; /** * VisuMap: * * Common name to refer to a #_VisuMap. */ typedef struct _VisuMap VisuMap; struct _VisuMap { VisuObject parent; VisuMapPrivate *priv; }; typedef struct _VisuMapClass VisuMapClass; struct _VisuMapClass { VisuObjectClass parent; GThreadPool *computePool; }; /** * visu_map_get_type: * * This method returns the type of #VisuMap, use * VISU_TYPE_MAP instead. * * Since: 3.8 * * Returns: the type of #VisuMap. */ GType visu_map_get_type(void); VisuMap* visu_map_new(); VisuMap* visu_map_new_fromPlane(VisuPlane *plane); gboolean visu_map_setPlane(VisuMap *map, VisuPlane *plane); gboolean visu_map_setSurface(VisuMap *map, VisuSurface *surface); gboolean visu_map_setField(VisuMap *map, VisuScalarField *field); gboolean visu_map_setLevel(VisuMap *map, float glPrec, float gross, float refLength); gboolean visu_map_setLines(VisuMap *map, guint nIsoLines, float minmax[2]); gboolean visu_map_setScaling(VisuMap *map, ToolMatrixScalingFlag scale); gboolean visu_map_setScalingRange(VisuMap *map, const float *minMax); void visu_map_compute_sync(VisuMap *map); VisuPlane* visu_map_getPlane(VisuMap *map); VisuScalarField* visu_map_getField(VisuMap *map); gboolean visu_map_getScaledMinMax(const VisuMap *map, float minMax[2]); float* visu_map_getFieldMinMax(VisuMap *map); const float* visu_map_getScalingRange(const VisuMap *map); float visu_map_getLegendScale(); float visu_map_getLegendPosition(ToolXyzDir dir); void visu_map_draw(VisuMap *map, float prec, ToolShade *shade, float *rgb, gboolean alpha); gboolean visu_map_export(VisuMap *map, const ToolShade *shade, const float *rgb, float precision, const gchar *filename, VisuMapExportFormat format, GError **error); #endif v_sim-3.8.0/src/extraFunctions/mover.c000066400000000000000000000356461370110300500177420ustar00rootroot00000000000000/* EXTRAITS DE LA LICENCE Copyright CEA, contributeurs : Damien CALISTE, laboratoire L_Sim, (2017) Adresse mèl : CALISTE, damien P caliste AT cea P fr. Ce logiciel est un programme informatique servant à visualiser des structures atomiques dans un rendu pseudo-3D. Ce logiciel est régi par la licence CeCILL soumise au droit français et respectant les principes de diffusion des logiciels libres. Vous pouvez utiliser, modifier et/ou redistribuer ce programme sous les conditions de la licence CeCILL telle que diffusée par le CEA, le CNRS et l'INRIA sur le site "http://www.cecill.info". Le fait que vous puissiez accéder à cet en-tête signifie que vous avez pris connaissance de la licence CeCILL, et que vous en avez accepté les termes (cf. le fichier Documentation/licence.fr.txt fourni avec ce logiciel). */ /* LICENCE SUM UP Copyright CEA, contributors : Damien CALISTE, laboratoire L_Sim, (2017) E-mail address: CALISTE, damien P caliste AT cea P fr. This software is a computer program whose purpose is to visualize atomic configurations in 3D. This software is governed by the CeCILL license under French law and abiding by the rules of distribution of free software. You can use, modify and/ or redistribute the software under the terms of the CeCILL license as circulated by CEA, CNRS and INRIA at the following URL "http://www.cecill.info". The fact that you are presently reading this means that you have had knowledge of the CeCILL license and that you accept its terms. You can find a copy of this licence shipped with this software at Documentation/licence.en.txt. */ #include "mover.h" #include /** * SECTION:mover * @short_description: Base class defining an undo stack of geometry modifications. * * This is a base class to define geometry modifications with an * undo stack. The geometry modifications can be animated with * visu_node_mover_animate() or applied immediately with * visu_node_mover_apply(). */ /** * VisuNodeMoverClass: * @parent: the parent class; * * A short way to identify #_VisuNodeMoverClass structure. * * Since: 3.8 */ /** * VisuNodeMover: * * An opaque structure. * * Since: 3.8 */ /** * VisuNodeMoverPrivate: * * Private fields for #VisuNodeMover objects. * * Since: 3.8 */ struct _VisuNodeMoverPrivate { gboolean dispose_has_run; GWeakRef nodes; GArray *ids; GSList *stack; gfloat completion; VisuAnimation *anim; }; enum { PROP_0, NODES_PROP, IDS_PROP, COMPLETION_PROP, UNDO_PROP, VALID_PROP, N_PROP }; static GParamSpec *_properties[N_PROP]; static void visu_node_mover_finalize(GObject* obj); static void visu_node_mover_dispose(GObject* obj); static void visu_node_mover_get_property(GObject* obj, guint property_id, GValue *value, GParamSpec *pspec); static void visu_node_mover_set_property(GObject* obj, guint property_id, const GValue *value, GParamSpec *pspec); static void visu_animatable_interface_init(VisuAnimatableInterface *iface); static VisuAnimation* _getAnimation(const VisuAnimatable *animatable, const gchar *prop); static gboolean _validate(const VisuNodeMover *mover); G_DEFINE_TYPE_WITH_CODE(VisuNodeMover, visu_node_mover, VISU_TYPE_OBJECT, G_ADD_PRIVATE(VisuNodeMover) G_IMPLEMENT_INTERFACE(VISU_TYPE_ANIMATABLE, visu_animatable_interface_init)) static void visu_node_mover_class_init(VisuNodeMoverClass *klass) { DBG_fprintf(stderr, "Visu Mover: creating the class of the object.\n"); /* DBG_fprintf(stderr, " - adding new signals ;\n"); */ /* Connect the overloading methods. */ G_OBJECT_CLASS(klass)->dispose = visu_node_mover_dispose; G_OBJECT_CLASS(klass)->finalize = visu_node_mover_finalize; G_OBJECT_CLASS(klass)->set_property = visu_node_mover_set_property; G_OBJECT_CLASS(klass)->get_property = visu_node_mover_get_property; /** * VisuNodeMover::nodes: * * #VisuNodeArray to apply the move to. * * Since: 3.8 */ _properties[NODES_PROP] = g_param_spec_object("nodes", "Nodes", "nodes to apply the move to.", VISU_TYPE_NODE_ARRAY, G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS); /** * VisuNodeMover::ids: * * The node ids to move. * * Since: 3.8 */ _properties[IDS_PROP] = g_param_spec_boxed("ids", "Ids", "node ids to move.", G_TYPE_ARRAY, G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS); /** * VisuNodeMover::completion: * * Percentage of completion during animation. * * Since: 3.8 */ _properties[COMPLETION_PROP] = g_param_spec_float("completion", "Completion", "percentage of completion during animation.", 0.f, 1.f, 0.f, G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS); /** * VisuNodeMover::undo-stack-depth: * * Percentage of completion during animation. * * Since: 3.8 */ _properties[UNDO_PROP] = g_param_spec_uint("undo-stack-depth", "Undo stack depth", "undo stack depth.", 0, G_MAXUINT, 0, G_PARAM_READABLE | G_PARAM_STATIC_STRINGS); /** * VisuNodeMover::valid: * * If current mover parameter are valid. * * Since: 3.8 */ _properties[VALID_PROP] = g_param_spec_boolean("valid", "Valid", "if mover parameters are valid.", FALSE, G_PARAM_READABLE | G_PARAM_STATIC_STRINGS); g_object_class_install_properties(G_OBJECT_CLASS(klass), N_PROP, _properties); } static void visu_animatable_interface_init(VisuAnimatableInterface *iface) { iface->get_animation = _getAnimation; } static void visu_node_mover_init(VisuNodeMover *obj) { DBG_fprintf(stderr, "Visu Mover: initializing a new object (%p).\n", (gpointer)obj); obj->priv = visu_node_mover_get_instance_private(obj); obj->priv->dispose_has_run = FALSE; g_weak_ref_init(&obj->priv->nodes, (gpointer)0); obj->priv->ids = (GArray*)0; obj->priv->stack = (GSList*)0; obj->priv->completion = 0.f; obj->priv->anim = visu_animation_new(G_OBJECT(obj), "completion"); } static void visu_node_mover_dispose(GObject* obj) { VisuNodeMover *mover; DBG_fprintf(stderr, "Visu Mover: dispose object %p.\n", (gpointer)obj); mover = VISU_NODE_MOVER(obj); if (mover->priv->dispose_has_run) return; mover->priv->dispose_has_run = TRUE; /* Disconnect signals. */ g_weak_ref_clear(&mover->priv->nodes); g_object_unref(mover->priv->anim); /* Chain up to the parent class */ G_OBJECT_CLASS(visu_node_mover_parent_class)->dispose(obj); } static void visu_node_mover_finalize(GObject* obj) { VisuNodeMover *mover; g_return_if_fail(obj); DBG_fprintf(stderr, "Visu Mover: finalize object %p.\n", (gpointer)obj); mover = VISU_NODE_MOVER(obj); /* Free privs elements. */ if (mover->priv->ids) g_array_unref(mover->priv->ids); if (mover->priv->stack) g_slist_free_full(mover->priv->stack, (GDestroyNotify)g_array_unref); /* Chain up to the parent class */ DBG_fprintf(stderr, "Visu Mover: chain to parent.\n"); G_OBJECT_CLASS(visu_node_mover_parent_class)->finalize(obj); DBG_fprintf(stderr, "Visu Mover: freeing ... OK.\n"); } static void visu_node_mover_get_property(GObject* obj, guint property_id, GValue *value, GParamSpec *pspec) { VisuNodeMover *self = VISU_NODE_MOVER(obj); switch (property_id) { case NODES_PROP: g_value_take_object(value, g_weak_ref_get(&self->priv->nodes)); break; case IDS_PROP: g_value_set_boxed(value, self->priv->ids); break; case COMPLETION_PROP: g_value_set_float(value, self->priv->completion); break; case UNDO_PROP: g_value_set_uint(value, g_slist_length(self->priv->stack)); break; case VALID_PROP: g_value_set_boolean(value, _validate(self)); break; default: /* We don't have any other property... */ G_OBJECT_WARN_INVALID_PROPERTY_ID(obj, property_id, pspec); break; } } static void visu_node_mover_set_property(GObject* obj, guint property_id, const GValue *value, GParamSpec *pspec) { VisuNodeMover *self = VISU_NODE_MOVER(obj); VisuNodeArray *arr; switch (property_id) { case NODES_PROP: g_weak_ref_set(&self->priv->nodes, g_value_get_object(value)); break; case IDS_PROP: visu_node_mover_setNodes(self, g_value_get_boxed(value)); break; case COMPLETION_PROP: self->priv->completion = g_value_get_float(value); if (!self->priv->ids || !self->priv->ids->len) break; arr = g_weak_ref_get(&self->priv->nodes); if (!arr) break; if (VISU_NODE_MOVER_GET_CLASS(self)->apply && VISU_NODE_MOVER_GET_CLASS(self)->apply(self, arr, self->priv->ids, self->priv->completion) && self->priv->completion == 1.f) { self->priv->stack = g_slist_prepend(self->priv->stack, g_array_ref(self->priv->ids)); g_object_notify_by_pspec(obj, _properties[UNDO_PROP]); } g_object_unref(arr); break; default: /* We don't have any other property... */ G_OBJECT_WARN_INVALID_PROPERTY_ID(obj, property_id, pspec); break; } } static VisuAnimation* _getAnimation(const VisuAnimatable *animatable, const gchar *prop) { g_return_val_if_fail(VISU_IS_NODE_MOVER(animatable), (VisuAnimation*)0); return !g_strcmp0(prop, "completion") ? VISU_NODE_MOVER(animatable)->priv->anim : (VisuAnimation*)0; } /** * visu_node_mover_setNodes: * @mover: a #VisuNodeMover object. * @ids: (element-type uint): a list of node ids. * * Defines the nodes that will be affected by the modification in @mover. * * Since: 3.8 **/ void visu_node_mover_setNodes(VisuNodeMover *mover, GArray *ids) { g_return_if_fail(VISU_IS_NODE_MOVER(mover)); if (mover->priv->ids) g_array_unref(mover->priv->ids); mover->priv->ids = g_array_ref(ids); g_object_notify_by_pspec(G_OBJECT(mover), _properties[IDS_PROP]); g_object_notify_by_pspec(G_OBJECT(mover), _properties[VALID_PROP]); } /** * visu_node_mover_getNodes: * @mover: a #VisuNodeMover object. * * Retrieves the node ids impacted by @mover. * * Since: 3.8 * * Returns: (transfer none) (element-type uint): a list of node ids. **/ const GArray* visu_node_mover_getNodes(const VisuNodeMover *mover) { g_return_val_if_fail(VISU_IS_NODE_MOVER(mover), (const GArray*)0); return mover->priv->ids; } static gboolean _validate(const VisuNodeMover *mover) { g_return_val_if_fail(VISU_IS_NODE_MOVER(mover), FALSE); if (!mover->priv->ids || !mover->priv->ids->len) return FALSE; return VISU_NODE_MOVER_GET_CLASS(mover)->validate && VISU_NODE_MOVER_GET_CLASS(mover)->validate(mover); } /** * visu_node_mover_apply: * @mover: a #VisuNodeMover object. * * Apply the modification defined by @mover. To animate the * transition, use visu_node_mover_animate(). * * Since: 3.8 **/ void visu_node_mover_apply(VisuNodeMover *mover) { VisuNodeArray *arr; g_return_if_fail(VISU_IS_NODE_MOVER(mover)); if (!mover->priv->ids || !mover->priv->ids->len) return; g_return_if_fail(mover->priv->completion == 0.f || mover->priv->completion == 1.f); arr = g_weak_ref_get(&mover->priv->nodes); if (!arr) return; if (VISU_NODE_MOVER_GET_CLASS(mover)->setup) VISU_NODE_MOVER_GET_CLASS(mover)->setup(mover); if (VISU_NODE_MOVER_GET_CLASS(mover)->apply && VISU_NODE_MOVER_GET_CLASS(mover)->apply(mover, arr, mover->priv->ids, 1.f)) mover->priv->stack = g_slist_prepend(mover->priv->stack, g_array_ref(mover->priv->ids)); g_object_unref(arr); } /** * visu_node_mover_animate: * @mover: a #VisuNodeMover object. * * Starts the animation defined by @mover. For an application of the * change without animation, use visu_node_mover_apply(). * * Since: 3.8 **/ void visu_node_mover_animate(VisuNodeMover *mover) { VisuNodeArray *arr; g_return_if_fail(VISU_IS_NODE_MOVER(mover)); if (!mover->priv->ids || !mover->priv->ids->len) return; g_return_if_fail(mover->priv->completion == 0.f || mover->priv->completion == 1.f); arr = g_weak_ref_get(&mover->priv->nodes); if (!arr) return; mover->priv->completion = 0.f; if (VISU_NODE_MOVER_GET_CLASS(mover)->setup) VISU_NODE_MOVER_GET_CLASS(mover)->setup(mover); if (!visu_animatable_animateFloat(VISU_ANIMATABLE(mover), mover->priv->anim, 1.f, 400, FALSE, VISU_ANIMATION_SIN)) { if (VISU_NODE_MOVER_GET_CLASS(mover)->apply && VISU_NODE_MOVER_GET_CLASS(mover)->apply(mover, arr, mover->priv->ids, 1.f)) { mover->priv->stack = g_slist_prepend(mover->priv->stack, g_array_ref(mover->priv->ids)); g_object_notify_by_pspec(G_OBJECT(mover), _properties[UNDO_PROP]); } } g_object_unref(arr); } /** * visu_node_mover_push: * @mover: a #VisuNodeMover object. * * Push the current modification on the undo stack without actually * doing the modification. * * Since: 3.8 **/ void visu_node_mover_push(VisuNodeMover *mover) { g_return_if_fail(VISU_IS_NODE_MOVER(mover)); if (VISU_NODE_MOVER_GET_CLASS(mover)->push && VISU_NODE_MOVER_GET_CLASS(mover)->push(mover)) { mover->priv->stack = g_slist_prepend(mover->priv->stack, g_array_ref(mover->priv->ids)); g_object_notify_by_pspec(G_OBJECT(mover), _properties[UNDO_PROP]); } } /** * visu_node_mover_undo: * @mover: a #VisuNodeMover object. * * Undo the last modification. * * Since: 3.8 **/ void visu_node_mover_undo(VisuNodeMover *mover) { VisuNodeArray *arr; GSList *ids; g_return_if_fail(VISU_IS_NODE_MOVER(mover)); if (!mover->priv->stack) return; arr = g_weak_ref_get(&mover->priv->nodes); if (!arr) return; if (VISU_NODE_MOVER_GET_CLASS(mover)->undo) { ids = mover->priv->stack; mover->priv->stack = g_slist_next(ids); VISU_NODE_MOVER_GET_CLASS(mover)->undo(mover, arr, (const GArray*)ids->data); g_array_unref((GArray*)ids->data); g_slist_free_1(ids); g_object_notify_by_pspec(G_OBJECT(mover), _properties[UNDO_PROP]); } g_object_unref(arr); } v_sim-3.8.0/src/extraFunctions/mover.h000066400000000000000000000104421370110300500177320ustar00rootroot00000000000000/* EXTRAITS DE LA LICENCE Copyright CEA, contributeurs : Damien CALISTE, laboratoire L_Sim, (2017) Adresse mèl : CALISTE, damien P caliste AT cea P fr. Ce logiciel est un programme informatique servant à visualiser des structures atomiques dans un rendu pseudo-3D. Ce logiciel est régi par la licence CeCILL soumise au droit français et respectant les principes de diffusion des logiciels libres. Vous pouvez utiliser, modifier et/ou redistribuer ce programme sous les conditions de la licence CeCILL telle que diffusée par le CEA, le CNRS et l'INRIA sur le site "http://www.cecill.info". Le fait que vous puissiez accéder à cet en-tête signifie que vous avez pris connaissance de la licence CeCILL, et que vous en avez accepté les termes (cf. le fichier Documentation/licence.fr.txt fourni avec ce logiciel). */ /* LICENCE SUM UP Copyright CEA, contributors : Damien CALISTE, laboratoire L_Sim, (2017) E-mail address: CALISTE, damien P caliste AT cea P fr. This software is a computer program whose purpose is to visualize atomic configurations in 3D. This software is governed by the CeCILL license under French law and abiding by the rules of distribution of free software. You can use, modify and/ or redistribute the software under the terms of the CeCILL license as circulated by CEA, CNRS and INRIA at the following URL "http://www.cecill.info". The fact that you are presently reading this means that you have had knowledge of the CeCILL license and that you accept its terms. You can find a copy of this licence shipped with this software at COPYING. */ #ifndef MOVER_H #define MOVER_H #include #include #include #include G_BEGIN_DECLS /** * VISU_TYPE_NODE_MOVER: * * return the type of #VisuNodeMover. * * Since: 3.8 */ #define VISU_TYPE_NODE_MOVER (visu_node_mover_get_type ()) /** * VISU_NODE_MOVER: * @obj: a #GObject to cast. * * Cast the given @obj into #VisuNodeMover type. * * Since: 3.8 */ #define VISU_NODE_MOVER(obj) (G_TYPE_CHECK_INSTANCE_CAST(obj, VISU_TYPE_NODE_MOVER, VisuNodeMover)) /** * VISU_NODE_MOVER_CLASS: * @klass: a #GObjectClass to cast. * * Cast the given @klass into #VisuNodeMoverClass. * * Since: 3.8 */ #define VISU_NODE_MOVER_CLASS(klass) (G_TYPE_CHECK_CLASS_CAST(klass, VISU_TYPE_NODE_MOVER, VisuNodeMoverClass)) /** * VISU_IS_NODE_MOVER: * @obj: a #GObject to test. * * Test if the given @ogj is of the type of #VisuNodeMover object. * * Since: 3.8 */ #define VISU_IS_NODE_MOVER(obj) (G_TYPE_CHECK_INSTANCE_TYPE(obj, VISU_TYPE_NODE_MOVER)) /** * VISU_IS_NODE_MOVER_CLASS: * @klass: a #GObjectClass to test. * * Test if the given @klass is of the type of #VisuNodeMoverClass class. * * Since: 3.8 */ #define VISU_IS_NODE_MOVER_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE(klass, VISU_TYPE_NODE_MOVER)) /** * VISU_NODE_MOVER_GET_CLASS: * @obj: a #GObject to get the class of. * * It returns the class of the given @obj. * * Since: 3.8 */ #define VISU_NODE_MOVER_GET_CLASS(obj) (G_TYPE_INSTANCE_GET_CLASS(obj, VISU_TYPE_NODE_MOVER, VisuNodeMoverClass)) typedef struct _VisuNodeMover VisuNodeMover; typedef struct _VisuNodeMoverPrivate VisuNodeMoverPrivate; typedef struct _VisuNodeMoverClass VisuNodeMoverClass; struct _VisuNodeMover { VisuObject parent; VisuNodeMoverPrivate *priv; }; struct _VisuNodeMoverClass { VisuObjectClass parent; gboolean (*validate)(const VisuNodeMover *mover); void (*setup)(VisuNodeMover *mover); gboolean (*apply)(VisuNodeMover *mover, VisuNodeArray *arr, const GArray *ids, gfloat completion); gboolean (*push)(VisuNodeMover *mover); void (*undo)(VisuNodeMover *mover, VisuNodeArray *arr, const GArray *ids); }; /** * visu_node_mover_get_type: * * This method returns the type of #VisuNodeMover, use * VISU_TYPE_NODE_MOVER instead. * * Since: 3.8 * * Returns: the type of #VisuNodeMover. */ GType visu_node_mover_get_type(void); void visu_node_mover_setNodes(VisuNodeMover *mover, GArray *ids); const GArray* visu_node_mover_getNodes(const VisuNodeMover *mover); void visu_node_mover_apply(VisuNodeMover *mover); void visu_node_mover_animate(VisuNodeMover *mover); void visu_node_mover_push(VisuNodeMover *mover); void visu_node_mover_undo(VisuNodeMover *mover); G_END_DECLS #endif v_sim-3.8.0/src/extraFunctions/neighbours.c000066400000000000000000000514611370110300500207500ustar00rootroot00000000000000/* EXTRAITS DE LA LICENCE Copyright CEA, contributeur : Damien CALISTE, laboratoire L_Sim, (2015) Adresse mèl : CALISTE, damien P caliste AT cea P fr. Ce logiciel est un programme informatique servant à visualiser des structures atomiques dans un rendu pseudo-3D. Ce logiciel est régi par la licence CeCILL soumise au droit français et respectant les principes de diffusion des logiciels libres. Vous pouvez utiliser, modifier et/ou redistribuer ce programme sous les conditions de la licence CeCILL telle que diffusée par le CEA, le CNRS et l'INRIA sur le site "http://www.cecill.info". Le fait que vous puissiez accéder à cet en-tête signifie que vous avez pris connaissance de la licence CeCILL, et que vous en avez accepté les termes (cf. le fichier Documentation/licence.fr.txt fourni avec ce logiciel). */ /* LICENCE SUM UP Copyright CEA, contributor : Damien CALISTE, laboratoire L_Sim, (2015) E-mail address: BILLARD, not reachable any more ; CALISTE, damien P caliste AT cea P fr. This software is a computer program whose purpose is to visualize atomic configurations in 3D. This software is governed by the CeCILL license under French law and abiding by the rules of distribution of free software. You can use, modify and/ or redistribute the software under the terms of the CeCILL license as circulated by CEA, CNRS and INRIA at the following URL "http://www.cecill.info". The fact that you are presently reading this means that you have had knowledge of the CeCILL license and that you accept its terms. You can find a copy of this licence shipped with this software at Documentation/licence.en.txt. */ #include "neighbours.h" #include /** * SECTION:neighbours * @short_description: node neighbours handling. * * Define an object to store information about neighbours, see * visu_node_neighbours_new() and an iterator to run over neighbours. */ struct _VisuNodeNeighboursPrivate { gboolean dispose_has_run; /* The data the neighbours are computed from. */ VisuData *data; /*gulong widthHeight_signal;*/ gboolean dirty; gfloat factor; guint idMax; guint *keynei; GArray *nei; }; enum { PROP_0, DATA_PROP, FACTOR_PROP, N_PROP }; static GParamSpec *properties[N_PROP]; static void visu_node_neighbours_dispose (GObject* obj); static void visu_node_neighbours_finalize (GObject* obj); static void visu_node_neighbours_get_property(GObject* obj, guint property_id, GValue *value, GParamSpec *pspec); static void visu_node_neighbours_set_property(GObject* obj, guint property_id, const GValue *value, GParamSpec *pspec); G_DEFINE_TYPE_WITH_CODE(VisuNodeNeighbours, visu_node_neighbours, VISU_TYPE_OBJECT, G_ADD_PRIVATE(VisuNodeNeighbours)) static void visu_node_neighbours_class_init(VisuNodeNeighboursClass *klass) { /* Connect the overloading methods. */ G_OBJECT_CLASS(klass)->dispose = visu_node_neighbours_dispose; G_OBJECT_CLASS(klass)->finalize = visu_node_neighbours_finalize; G_OBJECT_CLASS(klass)->set_property = visu_node_neighbours_set_property; G_OBJECT_CLASS(klass)->get_property = visu_node_neighbours_get_property; /** * VisuNodeNeighbours::data: * * The #VisuData the neighbour list is built for. * * Since: 3.8 */ properties[DATA_PROP] = g_param_spec_object("data", "Data", "the Data the neighbours are for", VISU_TYPE_DATA, G_PARAM_READWRITE | G_PARAM_CONSTRUCT_ONLY); /** * VisuNodeNeighbours::factor: * * The additional percentage to add to the Bohr radii of elements. * * Since: 3.8 */ properties[FACTOR_PROP] = g_param_spec_float("factor", "Factor", "additional percentage on radii", 0.f, 1.5f, 0.2f, G_PARAM_READWRITE); g_object_class_install_properties(G_OBJECT_CLASS(klass), N_PROP, properties); } static void visu_node_neighbours_init(VisuNodeNeighbours *nei) { nei->priv = visu_node_neighbours_get_instance_private(nei); nei->priv->dispose_has_run = FALSE; nei->priv->dirty = TRUE; nei->priv->factor = .2f; nei->priv->keynei = (guint*)0; nei->priv->nei = g_array_new(FALSE, FALSE, sizeof(guint)); } static void visu_node_neighbours_dispose(GObject* obj) { VisuNodeNeighbours *nei; nei = VISU_NODE_NEIGHBOURS(obj); if (nei->priv->dispose_has_run) return; nei->priv->dispose_has_run = TRUE; if (nei->priv->data) g_object_unref(nei->priv->data); /* Chain up to the parent class */ G_OBJECT_CLASS(visu_node_neighbours_parent_class)->dispose(obj); } static void visu_node_neighbours_finalize(GObject* obj) { VisuNodeNeighbours *nei; nei = VISU_NODE_NEIGHBOURS(obj); g_return_if_fail(nei); g_free(nei->priv->keynei); g_array_unref(nei->priv->nei); /* Chain up to the parent class */ G_OBJECT_CLASS(visu_node_neighbours_parent_class)->finalize(obj); } static void visu_node_neighbours_get_property(GObject* obj, guint property_id, GValue *value, GParamSpec *pspec) { VisuNodeNeighbours *self = VISU_NODE_NEIGHBOURS(obj); switch (property_id) { case DATA_PROP: g_value_set_object(value, self->priv->data); break; case FACTOR_PROP: g_value_set_float(value, self->priv->factor); break; default: /* We don't have any other property... */ G_OBJECT_WARN_INVALID_PROPERTY_ID(obj, property_id, pspec); break; } } static void visu_node_neighbours_set_property(GObject* obj, guint property_id, const GValue *value, GParamSpec *pspec) { VisuNodeNeighbours *self = VISU_NODE_NEIGHBOURS(obj); GObject *dt; switch (property_id) { case DATA_PROP: dt = g_value_dup_object(value); if (dt) { self->priv->data = VISU_DATA(dt); /* Connect here to population signals. */ } break; case FACTOR_PROP: self->priv->factor = g_value_get_float(value); break; default: /* We don't have any other property... */ G_OBJECT_WARN_INVALID_PROPERTY_ID(obj, property_id, pspec); break; } } /** * visu_node_neighbours_new: * @data: a #VisuData object. * * Create an object to handle a set of neighbours for @data. * * Since: 3.8 * * Returns: (transfer full): a newly created #VisuNodeNeighbours object. **/ VisuNodeNeighbours* visu_node_neighbours_new(VisuData *data) { VisuNodeNeighbours *nei; nei = VISU_NODE_NEIGHBOURS(g_object_new(VISU_TYPE_NODE_NEIGHBOURS, "data", data, NULL)); return nei; } static void _computeNeighbours(VisuNodeNeighbours *nei) { VisuBox *box; VisuNodeArray *array; VisuNodeArrayIter iter, iter2; GArray **arr; float *rcuts; float factor, xyz[3], xyz2[3]; int z_; nei->priv->dirty = FALSE; if (!nei->priv->data) return; box = visu_boxed_getBox(VISU_BOXED(nei->priv->data)); array = VISU_NODE_ARRAY(nei->priv->data); visu_node_array_iter_new(array, &iter); nei->priv->idMax = iter.idMax + 1; nei->priv->keynei = g_realloc(nei->priv->keynei, sizeof(guint) * nei->priv->idMax * 2); g_array_set_size(nei->priv->nei, 0); factor = 1.f + nei->priv->factor; if (visu_box_getUnit(box) != TOOL_UNITS_UNDEFINED) factor *= tool_physic_getUnitValueInMeter(TOOL_UNITS_ANGSTROEM) / tool_physic_getUnitValueInMeter(visu_box_getUnit(box)); rcuts = g_malloc(sizeof(float) * iter.nElements); for (visu_node_array_iterStart(array, &iter); iter.element; visu_node_array_iterNextElement(array, &iter, FALSE)) { if (!tool_physic_getZFromSymbol(&z_, rcuts + iter.iElement, (float*)0, visu_element_getName(iter.element))) rcuts[iter.iElement] = 0.; else rcuts[iter.iElement] *= factor; DBG_fprintf(stderr, " | element %d -> rcut = %g (%g).\n", iter.iElement, rcuts[iter.iElement], factor); } arr = g_malloc(sizeof(GArray*) * nei->priv->idMax); for (visu_node_array_iterStart(array, &iter); iter.node; visu_node_array_iterNext(array, &iter)) arr[iter.node->number] = g_array_new(FALSE, FALSE, sizeof(guint)); for (visu_node_array_iterStart(array, &iter); iter.node; visu_node_array_iterNext(array, &iter)) { visu_data_getNodePosition(nei->priv->data, iter.node, xyz); iter2 = iter; for (visu_node_array_iterNext(array, &iter2); iter2.node; visu_node_array_iterNext(array, &iter2)) { visu_data_getNodePosition(nei->priv->data, iter2.node, xyz2); xyz2[0] -= xyz[0]; xyz2[1] -= xyz[1]; xyz2[2] -= xyz[2]; visu_box_getPeriodicVector(box, xyz2); if (xyz2[0] * xyz2[0] + xyz2[1] * xyz2[1] + xyz2[2] * xyz2[2] < (rcuts[iter.iElement] + rcuts[iter2.iElement]) * (rcuts[iter.iElement] + rcuts[iter2.iElement])) { g_array_append_val(arr[iter.node->number], iter2.node->number); g_array_append_val(arr[iter2.node->number], iter.node->number); } } } for (visu_node_array_iterStart(array, &iter); iter.node; visu_node_array_iterNext(array, &iter)) { nei->priv->keynei[2 * iter.node->number + 0] = nei->priv->nei->len; nei->priv->keynei[2 * iter.node->number + 1] = arr[iter.node->number]->len; DBG_fprintf(stderr, " - node #%d -> %d\n", iter.node->number, arr[iter.node->number]->len); g_array_append_vals(nei->priv->nei, arr[iter.node->number]->data, arr[iter.node->number]->len); g_array_free(arr[iter.node->number], TRUE); } g_free(rcuts); g_free(arr); } /** * visu_node_neighbours_iter: * @nei: a #VisuNodeNeighbours object to iterate on. * @iter: (out caller-allocates): a #VisuNodeNeighboursIter structure. * @nodeId: the node id to obtain neighbours of. * * Initialise @iter to iterate over the neighbours of node @nodeId. * * Since: 3.8 * * Returns: TRUE if the iterator is valid. **/ gboolean visu_node_neighbours_iter(VisuNodeNeighbours *nei, VisuNodeNeighboursIter *iter, guint nodeId) { g_return_val_if_fail(VISU_IS_NODE_NEIGHBOURS(nei) && iter, FALSE); iter->nodeId = nodeId; iter->nei = nei; iter->index = 0; return visu_node_neighbours_iter_next(iter); } /** * visu_node_neighbours_iter_next: * @iter: a #VisuNodeNeighboursIter iterator. * * Look to the next neighbour, see visu_node_neighbours_iter(). * * Since: 3.8 * * Returns: TRUE if the iterator is valid. **/ gboolean visu_node_neighbours_iter_next(VisuNodeNeighboursIter *iter) { g_return_val_if_fail(iter, FALSE); if (iter->nei->priv->dirty) _computeNeighbours(iter->nei); if (!iter->nei->priv->keynei || !iter->nei->priv->nei || iter->nodeId >= iter->nei->priv->idMax) return FALSE; iter->nnei = iter->nei->priv->keynei[2 * iter->nodeId + 1]; if (iter->index >= iter->nnei) return FALSE; iter->neiId = g_array_index(iter->nei->priv->nei, guint, iter->nei->priv->keynei[2 * iter->nodeId + 0] + iter->index); iter->index += 1; return TRUE; } /** * visu_node_neighbours_iter___iter__: * @iter: a #VisuNodeNeighboursIter structure. * @out: (out caller-allocates): a #VisuNodeNeighboursIter structure. * * Used for Python binding only. * * Since: 3.8 **/ void visu_node_neighbours_iter___iter__(const VisuNodeNeighboursIter *iter, VisuNodeNeighboursIter *out) { *out = *iter; out->index = 0; } static int _closeTo(const VisuSurfacePoint *pt, VisuSurfaceDefinition *def, const int offsets[3], const gfloat ref[3]) { gfloat d2, dRef; VisuSurfacePoint *pt2; VisuSurfacePoly *poly; guint i, j, k, n; guint matches[27]; dRef = (ref[0] - pt->at[0]) * (ref[0] - pt->at[0]) + (ref[1] - pt->at[1]) * (ref[1] - pt->at[1]) + (ref[2] - pt->at[2]) * (ref[2] - pt->at[2]); n = 0; for (i = 0; i < 3; i++) if (offsets[i] >= 0) { for (j = 0; j < 3; j++) { poly = &g_array_index(def->polys, VisuSurfacePoly, offsets[i] + j); for (k = 0; k < 3; k++) { pt2 = &g_array_index(def->points, VisuSurfacePoint, poly->indices[k]); d2 = (pt2->at[0] - pt->at[0]) * (pt2->at[0] - pt->at[0]) + (pt2->at[1] - pt->at[1]) * (pt2->at[1] - pt->at[1]) + (pt2->at[2] - pt->at[2]) * (pt2->at[2] - pt->at[2]); if (d2 < 0.1f * dRef) matches[n++] = poly->indices[k]; } } } if (!n) return -1; for (i = 1; i < n; i++) g_array_index(def->points, VisuSurfacePoint, matches[i]) = g_array_index(def->points, VisuSurfacePoint, matches[0]); return matches[0]; } static int _addSurfaceAt(VisuNodeNeighbours *nei, VisuNode *node, VisuSurfaceDefinition *def, float refNrm[3], VisuNodeProperty *done) { VisuNodeNeighboursIter iter; gboolean valid; float scal, ref; float xyzM[3], xyz[3][3]; float A[3][3], B[3], inv[3][3], out[3]; guint i, j1, j2, offset, poffset; int pid[3]; int poffsets[3]; VisuSurfacePoint pt; VisuSurfacePoly poly; GValue val = G_VALUE_INIT; g_return_val_if_fail(VISU_IS_NODE_NEIGHBOURS(nei), 0); visu_data_getNodePosition(nei->priv->data, node, xyzM); valid = visu_node_neighbours_iter(nei, &iter, node->number); DBG_fprintf(stderr, "Visu Neighbours: node id %d has %d neighbours.\n", node->number, iter.nnei); if (!valid || iter.nnei < 3) return 0; g_return_val_if_fail(def, 0); g_value_init(&val, G_TYPE_INT); poffsets[0] = 0; poffsets[1] = 0; poffsets[2] = 0; /* Try to find three neighbours more or less orthogonal to the refNrm. */ ref = sqrt(refNrm[0] * refNrm[0] + refNrm[1] * refNrm[1] + refNrm[2] * refNrm[2]); for (i = 0; valid && i < 3; valid = visu_node_neighbours_iter_next(&iter)) { node = visu_node_array_getFromId(VISU_NODE_ARRAY(nei->priv->data), iter.neiId); if (done) { visu_node_property_getValue(done, node, &val); poffsets[i] = g_value_get_int(&val) - 1; } visu_data_getNodePosition(nei->priv->data, node, xyz[i]); scal = ABS((xyz[i][0] - xyzM[0]) * refNrm[0] + (xyz[i][1] - xyzM[1]) * refNrm[1] + (xyz[i][2] - xyzM[2]) * refNrm[2]) / ref; scal /= sqrt((xyz[i][0] - xyzM[0]) * (xyz[i][0] - xyzM[0]) + (xyz[i][1] - xyzM[1]) * (xyz[i][1] - xyzM[1]) + (xyz[i][2] - xyzM[2]) * (xyz[i][2] - xyzM[2])); if (ref == 0.f || scal < 0.1) i += 1; } if (i != 3) return 0; /* Add this node. */ pt.at[0] = xyzM[0]; pt.at[1] = xyzM[1]; pt.at[2] = xyzM[2]; pt.normal[0] = (xyz[1][1] - xyz[0][1]) * (xyz[2][2] - xyz[0][2]) - (xyz[1][2] - xyz[0][2]) * (xyz[2][1] - xyz[0][1]); pt.normal[1] = (xyz[1][2] - xyz[0][2]) * (xyz[2][0] - xyz[0][0]) - (xyz[1][0] - xyz[0][0]) * (xyz[2][2] - xyz[0][2]); pt.normal[2] = (xyz[1][0] - xyz[0][0]) * (xyz[2][1] - xyz[0][1]) - (xyz[1][1] - xyz[0][1]) * (xyz[2][0] - xyz[0][0]); if (ref == 0.f) { refNrm[0] = pt.normal[0]; refNrm[1] = pt.normal[1]; refNrm[2] = pt.normal[2]; } else if (refNrm[0] * pt.normal[0] + refNrm[1] * pt.normal[1] + refNrm[2] * pt.normal[2] < 0.f) { pt.normal[0] = -pt.normal[0]; pt.normal[1] = -pt.normal[1]; pt.normal[2] = -pt.normal[2]; } offset = def->points->len; g_array_append_val(def->points, pt); /* Dealing with neighbour i. */ for (i = 0; i < 3; i++) { j1 = (i + 1) % 3; /* First half-way plane. */ A[0][0] = xyz[j1][0] - xyzM[0]; A[0][1] = xyz[j1][1] - xyzM[1]; A[0][2] = xyz[j1][2] - xyzM[2]; B[0] = A[0][0] * (xyz[j1][0] + xyzM[0]) / 2.f + A[0][1] * (xyz[j1][1] + xyzM[1]) / 2.f + A[0][2] * (xyz[j1][2] + xyzM[2]) / 2.f; j2 = (i + 2) % 3; /* Second half-way plane. */ A[1][0] = xyz[j2][0] - xyzM[0]; A[1][1] = xyz[j2][1] - xyzM[1]; A[1][2] = xyz[j2][2] - xyzM[2]; B[1] = A[1][0] * (xyz[j2][0] + xyzM[0]) / 2.f + A[1][1] * (xyz[j2][1] + xyzM[1]) / 2.f + A[1][2] * (xyz[j2][2] + xyzM[2]) / 2.f; /* In-plane */ A[2][0] = (xyz[j1][1] - xyzM[1]) * (xyz[j2][2] - xyzM[2]) - (xyz[j1][2] - xyzM[2]) * (xyz[j2][1] - xyzM[1]); A[2][1] = (xyz[j1][2] - xyzM[2]) * (xyz[j2][0] - xyzM[0]) - (xyz[j1][0] - xyzM[0]) * (xyz[j2][2] - xyzM[2]); A[2][2] = (xyz[j1][0] - xyzM[0]) * (xyz[j2][1] - xyzM[1]) - (xyz[j1][1] - xyzM[1]) * (xyz[j2][0] - xyzM[0]); B[2] = A[2][0] * xyzM[0] + A[2][1] * xyzM[1] + A[2][2] * xyzM[2]; tool_matrix_invert(inv, A); tool_matrix_productVector(out, inv, B); pt.at[0] = out[0]; pt.at[1] = out[1]; pt.at[2] = out[2]; /* Try to attach the new point to one of already computed for the neighbours. */ pid[i] = _closeTo(&pt, def, poffsets, xyzM); if (pid[i] < 0) { pt.normal[0] = A[2][0]; pt.normal[1] = A[2][1]; pt.normal[2] = A[2][2]; if (refNrm[0] * A[2][0] + refNrm[1] * A[2][1] + refNrm[2] * A[2][2] < 0.f) { pt.normal[0] = -pt.normal[0]; pt.normal[1] = -pt.normal[1]; pt.normal[2] = -pt.normal[2]; } pid[i] = def->points->len; g_array_append_val(def->points, pt); } } poffset = def->polys->len; poly.nvertices = 3; poly.indices[0] = offset; poly.indices[1] = pid[0]; poly.indices[2] = pid[1]; g_array_append_val(def->polys, poly); poly.indices[1] = pid[1]; poly.indices[2] = pid[2]; g_array_append_val(def->polys, poly); poly.indices[1] = pid[2]; poly.indices[2] = pid[0]; g_array_append_val(def->polys, poly); return poffset + 1; } /** * visu_node_neighbours_getSurfaceAt: * @nei: a #VisuNodeNeighbours object. * @nodeId: a node number. * @def: (out caller-allocates): a place to store points and polys. * * Generate a surface definition around atom @nodeId. * * Since: 3.8 * * Returns: TRUE if @def is generated. **/ gboolean visu_node_neighbours_getSurfaceAt(VisuNodeNeighbours *nei, guint nodeId, VisuSurfaceDefinition *def) { float nrm[3]; g_return_val_if_fail(def, FALSE); def->points = g_array_sized_new(FALSE, FALSE, sizeof(VisuSurfacePoint), 4); def->polys = g_array_sized_new(FALSE, FALSE, sizeof(VisuSurfacePoly), 3); nrm[0] = 0.f; nrm[1] = 0.f; nrm[2] = 0.f; return (_addSurfaceAt(nei, visu_node_array_getFromId(VISU_NODE_ARRAY(nei->priv->data), nodeId), def, nrm, (VisuNodeProperty*)0) != FALSE); } static void _addSurfaceFrom(VisuNodeNeighbours *nei, VisuNodeProperty *done, VisuNode *node, VisuSurfaceDefinition *def, float refNrm[3]) { VisuNodeNeighboursIter iter; int offset; gboolean valid; GValue val = G_VALUE_INIT; g_value_init(&val, G_TYPE_INT); visu_node_property_getValue(done, node, &val); if (g_value_get_int(&val) == 0 && (offset = _addSurfaceAt(nei, node, def, refNrm, done))) { g_value_set_int(&val, offset); visu_node_property_setValue(done, node, &val); for (valid = visu_node_neighbours_iter(nei, &iter, node->number); valid; valid = visu_node_neighbours_iter_next(&iter)) _addSurfaceFrom(nei, done, visu_node_array_getFromId(VISU_NODE_ARRAY(nei->priv->data), iter.neiId), def, refNrm); } } /** * visu_node_neighbours_getSurfaceFrom: * @nei: a #VisuNodeNeighbours object. * @nodeId: a node id. * @def: (out caller-allocates): a place to store points and polys. * * Generate a surface definition around atom @nodeId and all its neighbours. * * Since: 3.8 * * Returns: TRUE if there is any generated surface. **/ gboolean visu_node_neighbours_getSurfaceFrom(VisuNodeNeighbours *nei, guint nodeId, VisuSurfaceDefinition *def) { VisuNodeProperty *done; float nrm[3]; g_return_val_if_fail(def, FALSE); done = visu_node_array_property_newInteger(VISU_NODE_ARRAY(nei->priv->data), "_NeighboursDone"); def->points = g_array_new(FALSE, FALSE, sizeof(VisuSurfacePoint)); def->polys = g_array_new(FALSE, FALSE, sizeof(VisuSurfacePoly)); nrm[0] = 0.f; nrm[1] = 0.f; nrm[2] = 0.f; _addSurfaceFrom(nei, done, visu_node_array_getFromId(VISU_NODE_ARRAY(nei->priv->data), nodeId), def, nrm); if (!def->points->len || !def->polys->len) { g_array_free(def->points, TRUE); g_array_free(def->polys, TRUE); return FALSE; } return TRUE; } v_sim-3.8.0/src/extraFunctions/neighbours.h000066400000000000000000000124041370110300500207470ustar00rootroot00000000000000/* EXTRAITS DE LA LICENCE Copyright CEA, contributeur : Damien CALISTE, laboratoire L_Sim, (2015) Adresse mèl : CALISTE, damien P caliste AT cea P fr. Ce logiciel est un programme informatique servant à visualiser des structures atomiques dans un rendu pseudo-3D. Ce logiciel est régi par la licence CeCILL soumise au droit français et respectant les principes de diffusion des logiciels libres. Vous pouvez utiliser, modifier et/ou redistribuer ce programme sous les conditions de la licence CeCILL telle que diffusée par le CEA, le CNRS et l'INRIA sur le site "http://www.cecill.info". Le fait que vous puissiez accéder à cet en-tête signifie que vous avez pris connaissance de la licence CeCILL, et que vous en avez accepté les termes (cf. le fichier Documentation/licence.fr.txt fourni avec ce logiciel). */ /* LICENCE SUM UP Copyright CEA, contributor : Damien CALISTE, laboratoire L_Sim, (2015) E-mail address: BILLARD, not reachable any more ; CALISTE, damien P caliste AT cea P fr. This software is a computer program whose purpose is to visualize atomic configurations in 3D. This software is governed by the CeCILL license under French law and abiding by the rules of distribution of free software. You can use, modify and/ or redistribute the software under the terms of the CeCILL license as circulated by CEA, CNRS and INRIA at the following URL "http://www.cecill.info". The fact that you are presently reading this means that you have had knowledge of the CeCILL license and that you accept its terms. You can find a copy of this licence shipped with this software at Documentation/licence.en.txt. */ #ifndef NEIGHBOURS_H #define NEIGHBOURS_H #include #include #include #include "surfaces.h" /** * VISU_TYPE_NODE_NEIGHBOURS: * * return the type of #VisuNodeNeighbours. */ #define VISU_TYPE_NODE_NEIGHBOURS (visu_node_neighbours_get_type ()) /** * VISU_NODE_NEIGHBOURS: * @obj: a #GObject to cast. * * Cast the given @obj into #VisuNodeNeighbours type. */ #define VISU_NODE_NEIGHBOURS(obj) (G_TYPE_CHECK_INSTANCE_CAST(obj, VISU_TYPE_NODE_NEIGHBOURS, VisuNodeNeighbours)) /** * VISU_NODE_NEIGHBOURS_CLASS: * @klass: a #GObjectClass to cast. * * Cast the given @klass into #VisuNodeNeighboursClass. */ #define VISU_NODE_NEIGHBOURS_CLASS(klass) (G_TYPE_CHECK_CLASS_CAST(klass, VISU_TYPE_NODE_NEIGHBOURS, VisuNodeNeighboursClass)) /** * VISU_IS_NODE_NEIGHBOURS: * @obj: a #GObject to test. * * Test if the given @ogj is of the type of #VisuNodeNeighbours object. */ #define VISU_IS_NODE_NEIGHBOURS(obj) (G_TYPE_CHECK_INSTANCE_TYPE(obj, VISU_TYPE_NODE_NEIGHBOURS)) /** * VISU_IS_NODE_NEIGHBOURS_CLASS: * @klass: a #GObjectClass to test. * * Test if the given @klass is of the type of #VisuNodeNeighboursClass class. */ #define VISU_IS_NODE_NEIGHBOURS_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE(klass, VISU_TYPE_NODE_NEIGHBOURS)) /** * VISU_NODE_NEIGHBOURS_GET_CLASS: * @obj: a #GObject to get the class of. * * It returns the class of the given @obj. */ #define VISU_NODE_NEIGHBOURS_GET_CLASS(obj) (G_TYPE_INSTANCE_GET_CLASS(obj, VISU_TYPE_NODE_NEIGHBOURS, VisuNodeNeighboursClass)) /** * VisuNodeNeighboursPrivate: * * Private data for #VisuNodeNeighbours objects. */ typedef struct _VisuNodeNeighboursPrivate VisuNodeNeighboursPrivate; /** * VisuNodeNeighbours: * * Common name to refer to a #_VisuNodeNeighbours. */ typedef struct _VisuNodeNeighbours VisuNodeNeighbours; struct _VisuNodeNeighbours { VisuObject parent; VisuNodeNeighboursPrivate *priv; }; /** * VisuNodeNeighboursClass: * @parent: private. * * Common name to refer to a #_VisuNodeNeighboursClass. */ typedef struct _VisuNodeNeighboursClass VisuNodeNeighboursClass; struct _VisuNodeNeighboursClass { VisuObjectClass parent; }; /** * visu_node_neighbours_get_type: * * This method returns the type of #VisuNodeNeighbours, use * VISU_TYPE_NODE_NEIGHBOURS instead. * * Since: 3.8 * * Returns: the type of #VisuNodeNeighbours. */ GType visu_node_neighbours_get_type(void); VisuNodeNeighbours* visu_node_neighbours_new(VisuData *data); gboolean visu_node_neighbours_getSurfaceAt(VisuNodeNeighbours *nei, guint nodeId, VisuSurfaceDefinition *def); gboolean visu_node_neighbours_getSurfaceFrom(VisuNodeNeighbours *nei, guint nodeId, VisuSurfaceDefinition *def); /** * VisuNodeNeighboursIter: * @index: current neighbour index. * @nnei: number of neighbours. * @neiId: node id of the current neighbour. * @nei: parent #VisuNodeNeighbours object. * @nodeId: node id of the current node. * * Iterator structure used to span over the neighbours of @nodeId. * * Since: 3.8 */ typedef struct _VisuNodeNeighboursIter VisuNodeNeighboursIter; struct _VisuNodeNeighboursIter { guint index, nnei, neiId; /* Private */ VisuNodeNeighbours *nei; guint nodeId; }; gboolean visu_node_neighbours_iter(VisuNodeNeighbours *nei, VisuNodeNeighboursIter *iter, guint nodeId); void visu_node_neighbours_iter___iter__(const VisuNodeNeighboursIter *iter, VisuNodeNeighboursIter *out); gboolean visu_node_neighbours_iter_next(VisuNodeNeighboursIter *iter); #endif v_sim-3.8.0/src/extraFunctions/nodeList.c000066400000000000000000000342411370110300500203610ustar00rootroot00000000000000/* EXTRAITS DE LA LICENCE Copyright CEA, contributeurs : Damien CALISTE, laboratoire L_Sim, (2019) Adresse mèl : CALISTE, damien P caliste AT cea P fr. Ce logiciel est un programme informatique servant à visualiser des structures atomiques dans un rendu pseudo-3D. Ce logiciel est régi par la licence CeCILL soumise au droit français et respectant les principes de diffusion des logiciels libres. Vous pouvez utiliser, modifier et/ou redistribuer ce programme sous les conditions de la licence CeCILL telle que diffusée par le CEA, le CNRS et l'INRIA sur le site "http://www.cecill.info". Le fait que vous puissiez accéder à cet en-tête signifie que vous avez pris connaissance de la licence CeCILL, et que vous en avez accepté les termes (cf. le fichier Documentation/licence.fr.txt fourni avec ce logiciel). */ /* LICENCE SUM UP Copyright CEA, contributors : Damien CALISTE, laboratoire L_Sim, (2019) E-mail address: CALISTE, damien P caliste AT cea P fr. This software is a computer program whose purpose is to visualize atomic configurations in 3D. This software is governed by the CeCILL license under French law and abiding by the rules of distribution of free software. You can use, modify and/ or redistribute the software under the terms of the CeCILL license as circulated by CEA, CNRS and INRIA at the following URL "http://www.cecill.info". The fact that you are presently reading this means that you have had knowledge of the CeCILL license and that you accept its terms. You can find a copy of this licence shipped with this software at Documentation/licence.en.txt. */ #include "nodeList.h" #include #include /** * SECTION:nodeList * @short_description: Defines an object to store a set of nodes. * * */ enum { PROP_0, NODES_PROP, DIM_PROP, IDS_PROP, N_PROP }; static GParamSpec *_properties[N_PROP]; struct _VisuNodeListPrivate { gboolean dispose_has_run; GWeakRef nodes; gulong decSig, posSig; GArray *list; VisuScalarFieldData *field; }; /* Local routines. */ static void _dispose (GObject* obj); static void _finalize(GObject* obj); static void _get_property(GObject* obj, guint property_id, GValue *value, GParamSpec *pspec); static void _set_property(GObject* obj, guint property_id, const GValue *value, GParamSpec *pspec); static void _setArray(VisuNodeList *list, VisuNodeArray *array); static void _popDecrease(VisuNodeList *list, const GArray *ids); static void _posChanged(VisuNodeList *list, const GArray *ids); static void _computeField(VisuNodeList *list); G_DEFINE_TYPE_WITH_CODE(VisuNodeList, visu_node_list, VISU_TYPE_OBJECT, G_ADD_PRIVATE(VisuNodeList)) static void visu_node_list_class_init(VisuNodeListClass *klass) { DBG_fprintf(stderr, "Visu NodeList: creating the class of the object.\n"); /* DBG_fprintf(stderr, " - adding new signals ;\n"); */ /* Connect the overloading methods. */ G_OBJECT_CLASS(klass)->dispose = _dispose; G_OBJECT_CLASS(klass)->finalize = _finalize; G_OBJECT_CLASS(klass)->set_property = _set_property; G_OBJECT_CLASS(klass)->get_property = _get_property; /** * VisuNodeList::nodes: * * Holds the #VisuNodeArray the nodes are taken from. * * Since: 3.8 */ _properties[NODES_PROP] = g_param_spec_object("nodes", "Nodes", "nodes values are related to", VISU_TYPE_NODE_ARRAY, G_PARAM_READWRITE | G_PARAM_CONSTRUCT_ONLY); /** * VisuNodeList::n-nodes: * * Holds the number of nodes stored in the list. * * Since: 3.8 */ _properties[DIM_PROP] = g_param_spec_uint("n-nodes", "N-nodes", "number of nodes", 0, G_MAXINT, 0, G_PARAM_READABLE); /** * VisuNodeList::ids: * * The current ids stored in the object. * * Since: 3.8 */ _properties[IDS_PROP] = g_param_spec_boxed("ids", "Ids", "node ids", G_TYPE_ARRAY, G_PARAM_READWRITE); g_object_class_install_properties(G_OBJECT_CLASS(klass), N_PROP, _properties); } static void visu_node_list_init(VisuNodeList *obj) { DBG_fprintf(stderr, "Visu NodeList: initializing a new object (%p).\n", (gpointer)obj); obj->priv = visu_node_list_get_instance_private(obj); obj->priv->dispose_has_run = FALSE; /* Private data. */ g_weak_ref_init(&obj->priv->nodes, (gpointer)0); obj->priv->list = g_array_new(FALSE, FALSE, sizeof(guint)); obj->priv->field = (VisuScalarFieldData*)0; } static void _dispose(GObject* obj) { VisuNodeList *self = VISU_NODE_LIST(obj); DBG_fprintf(stderr, "Visu NodeList: dispose object %p.\n", (gpointer)obj); if (self->priv->dispose_has_run) return; self->priv->dispose_has_run = TRUE; _setArray(self, (VisuNodeArray*)0); g_weak_ref_clear(&self->priv->nodes); if (self->priv->field) g_object_unref(self->priv->field); /* Chain up to the parent class */ G_OBJECT_CLASS(visu_node_list_parent_class)->dispose(obj); } /* This method is called once only. */ static void _finalize(GObject* obj) { VisuNodeList *self = VISU_NODE_LIST(obj); DBG_fprintf(stderr, "Visu NodeList: finalize object %p.\n", (gpointer)obj); g_array_unref(self->priv->list); /* Chain up to the parent class */ DBG_fprintf(stderr, "Visu NodeList: chain to parent.\n"); G_OBJECT_CLASS(visu_node_list_parent_class)->finalize(obj); DBG_fprintf(stderr, "Visu NodeList: freeing ... OK.\n"); } static void _get_property(GObject* obj, guint property_id, GValue *value, GParamSpec *pspec) { VisuNodeList *self = VISU_NODE_LIST(obj); DBG_fprintf(stderr, "Visu NodeList: get property '%s' -> ", g_param_spec_get_name(pspec)); switch (property_id) { case NODES_PROP: g_value_take_object(value, g_weak_ref_get(&self->priv->nodes)); DBG_fprintf(stderr, "%p.\n", g_value_get_object(value)); break; case DIM_PROP: g_value_set_uint(value, self->priv->list->len); DBG_fprintf(stderr, "%d.\n", g_value_get_uint(value)); break; case IDS_PROP: g_value_set_boxed(value, self->priv->list); DBG_fprintf(stderr, "%p.\n", g_value_get_boxed(value)); break; default: /* We don't have any other property... */ G_OBJECT_WARN_INVALID_PROPERTY_ID(obj, property_id, pspec); break; } } static void _set_property(GObject* obj, guint property_id, const GValue *value, GParamSpec *pspec) { VisuNodeList *self = VISU_NODE_LIST(obj); guint len; GArray *boxed; DBG_fprintf(stderr, "Visu NodeList: set property '%s' -> ", g_param_spec_get_name(pspec)); switch (property_id) { case NODES_PROP: DBG_fprintf(stderr, "%p.\n", g_value_get_object(value)); _setArray(self, g_value_dup_object(value)); g_object_unref(g_value_get_object(value)); break; case IDS_PROP: DBG_fprintf(stderr, "%p.\n", g_value_get_boxed(value)); len = self->priv->list->len; boxed = (GArray*)g_value_dup_boxed(value); if (boxed) { g_array_unref(self->priv->list); self->priv->list = boxed; } else g_array_set_size(self->priv->list, 0); if (len != self->priv->list->len) g_object_notify_by_pspec(obj, _properties[DIM_PROP]); break; default: /* We don't have any other property... */ G_OBJECT_WARN_INVALID_PROPERTY_ID(obj, property_id, pspec); break; } } static void _setArray(VisuNodeList *list, VisuNodeArray *array) { VisuNodeArray *old = VISU_NODE_ARRAY(g_weak_ref_get(&list->priv->nodes)); if (array) { g_return_if_fail(!old); g_weak_ref_set(&list->priv->nodes, array); list->priv->decSig = g_signal_connect_swapped(array, "PopulationDecrease", G_CALLBACK(_popDecrease), list); list->priv->posSig = g_signal_connect_swapped(array, "position-changed", G_CALLBACK(_posChanged), list); } else if (old) { g_signal_handler_disconnect(old, list->priv->decSig); g_signal_handler_disconnect(old, list->priv->posSig); g_object_unref(old); } } static void _popDecrease(VisuNodeList *list, const GArray *ids) { guint i = 0, len = list->priv->list->len; while (i < list->priv->list->len) { guint j; for (j = 0; j < ids->len; j++) if (g_array_index(ids, guint, j) == g_array_index(list->priv->list, guint, i)) break; if (j < ids->len) g_array_remove_index_fast(list->priv->list, i); else i += 1; } if (list->priv->list->len < len) g_object_notify_by_pspec(G_OBJECT(list), _properties[DIM_PROP]); } static void _posChanged(VisuNodeList *list, const GArray *ids) { guint i; for (i = 0; i < list->priv->list->len; i++) { guint j; for (j = 0; j < ids->len; j++) if (g_array_index(ids, guint, j) == g_array_index(list->priv->list, guint, i)) break; if (j < ids->len) break; } if (i < list->priv->list->len && list->priv->field) _computeField(list); } /** * visu_node_list_new: * @array: a #VisuNodeArray object. * * Creates a new #VisuNodeList storing indexes of nodes from @array.. * * Since: 3.8 * * Returns: a pointer to the #VisuNodeList it created or * %NULL otherwise. */ VisuNodeList* visu_node_list_new(VisuNodeArray *array) { DBG_fprintf(stderr,"Visu NodeList: new object.\n"); return g_object_new(VISU_TYPE_NODE_LIST, "nodes", array, NULL); } /** * visu_node_list_new_fromFrag: * @frag: a #VisuNodeValuesFrag object. * @label: a label. * * Create a list of nodes from the node labelled by @label in * @frag. When the fragment definition is chaged or the node * population is changed, the node list is updated accordingly. * * Since: 3.8 * * Returns: a newly created #VisuNodeList object. **/ VisuNodeList* visu_node_list_new_fromFrag(VisuNodeValuesFrag *frag, const gchar *label) { VisuNodeList *list; GArray *ids; VisuNodeArray *array = visu_node_values_getArray(VISU_NODE_VALUES(frag)); if (!array) return (VisuNodeList*)0; ids = visu_node_values_frag_getNodeIds(frag, label); list = g_object_new(VISU_TYPE_NODE_LIST, "nodes", array, "ids", ids, NULL); g_object_unref(array); g_array_unref(ids); return list; } /** * visu_node_list_add: * @list: a #VisuNodeList object. * @id: a node id. * * Add @id to the list of nodes. * * Since: 3.8 * * Returns: %TRUE if node is not already existing in the list. **/ gboolean visu_node_list_add(VisuNodeList *list, guint id) { guint i; g_return_val_if_fail(VISU_IS_NODE_LIST(list), FALSE); for (i = 0; i < list->priv->list->len; i++) if (g_array_index(list->priv->list, guint, i) == id) return FALSE; g_array_append_val(list->priv->list, id); g_object_notify_by_pspec(G_OBJECT(list), _properties[DIM_PROP]); return TRUE; } /** * visu_node_list_remove: * @list: a #VisuNodeList object. * @id: a node id. * * Remove @id from the list of nodes. * * Since: 3.8 * * Returns: %TRUE if the id was actually in the list. **/ gboolean visu_node_list_remove(VisuNodeList *list, guint id) { g_return_val_if_fail(VISU_IS_NODE_LIST(list), FALSE); guint i; for (i = 0; i < list->priv->list->len; i++) if (g_array_index(list->priv->list, guint, i) == id) break; if (i < list->priv->list->len) { g_array_remove_index_fast(list->priv->list, i); g_object_notify_by_pspec(G_OBJECT(list), _properties[DIM_PROP]); } return (i < list->priv->list->len); } static void _computeField(VisuNodeList *list) { const guint size[3] = {50, 50, 50}; GArray *data; guint i, j, k, id; double *at; VisuData *dataObj; VisuBox *box; const float top[3] = {1.f, 1.f, 1.f}; float blen[3]; dataObj = g_weak_ref_get(&list->priv->nodes); if (!dataObj) return; data = g_array_sized_new(FALSE, FALSE, sizeof(double), size[0] * size[1] * size[2]); box = visu_boxed_getBox(VISU_BOXED(dataObj)); visu_box_convertBoxCoordinatestoXYZ(box, blen, top); for (k = 0; k < size[2]; k++) for (j = 0; j < size[1]; j++) for (i = 0; i < size[0]; i++) { double pt[3] = {blen[0] * i / size[0], blen[1] * j / size[1], blen[2] * k / size[2]}; at = &g_array_index(data, double, k * size[0] * size[1] + j * size[0] + i); *at = G_MAXDOUBLE; for (id = 0; id < list->priv->list->len; id++) { const VisuNode *node; node = visu_node_array_getFromId(VISU_NODE_ARRAY(dataObj), g_array_index(list->priv->list, guint, id)); if (node) { float coord[3]; visu_data_getNodePosition(dataObj, node, coord); coord[0] -= pt[0]; coord[1] -= pt[1]; coord[2] -= pt[2]; visu_box_getPeriodicVector(box, coord); *at = MIN(*at, sqrt(coord[0] * coord[0] + coord[1] * coord[1] + coord[2] * coord[2])); } } } g_array_set_size(data, size[0] * size[1] * size[2]); g_object_unref(dataObj); if (!list->priv->field) { list->priv->field = g_object_new(VISU_TYPE_SCALAR_FIELD_DATA, NULL); visu_boxed_setBox(VISU_BOXED(list->priv->field), VISU_BOXED(dataObj)); visu_scalar_field_setGridSize(VISU_SCALAR_FIELD(list->priv->field), size); g_signal_connect(list, "notify::n-nodes", G_CALLBACK(_computeField), (gpointer)0); } visu_scalar_field_data_set(list->priv->field, data, VISU_SCALAR_FIELD_DATA_XYZ); g_array_unref(data); } /** * visu_node_list_envelope: * @list: a #VisuNodeList object. * * Compute a scalarfield corresponding to the envelope of the node * list. When the node positions are changed, the scalar field is * updated accordingly. * * Since: 3.8 * * Returns: (transfer none): a newly created #VisuScalarFieldData. **/ VisuScalarFieldData* visu_node_list_envelope(VisuNodeList *list) { g_return_val_if_fail(VISU_IS_NODE_LIST(list), (VisuScalarFieldData*)0); if (!list->priv->field) _computeField(list); return list->priv->field; } v_sim-3.8.0/src/extraFunctions/nodeList.h000066400000000000000000000066611370110300500203730ustar00rootroot00000000000000/* EXTRAITS DE LA LICENCE Copyright CEA, contributeurs : Damien CALISTE, laboratoire L_Sim, (2019) Adresse mèl : CALISTE, damien P caliste AT cea P fr. Ce logiciel est un programme informatique servant à visualiser des structures atomiques dans un rendu pseudo-3D. Ce logiciel est régi par la licence CeCILL soumise au droit français et respectant les principes de diffusion des logiciels libres. Vous pouvez utiliser, modifier et/ou redistribuer ce programme sous les conditions de la licence CeCILL telle que diffusée par le CEA, le CNRS et l'INRIA sur le site "http://www.cecill.info". Le fait que vous puissiez accéder à cet en-tête signifie que vous avez pris connaissance de la licence CeCILL, et que vous en avez accepté les termes (cf. le fichier Documentation/licence.fr.txt fourni avec ce logiciel). */ /* LICENCE SUM UP Copyright CEA, contributors : Damien CALISTE, laboratoire L_Sim, (2019) E-mail address: CALISTE, damien P caliste AT cea P fr. This software is a computer program whose purpose is to visualize atomic configurations in 3D. This software is governed by the CeCILL license under French law and abiding by the rules of distribution of free software. You can use, modify and/ or redistribute the software under the terms of the CeCILL license as circulated by CEA, CNRS and INRIA at the following URL "http://www.cecill.info". The fact that you are presently reading this means that you have had knowledge of the CeCILL license and that you accept its terms. You can find a copy of this licence shipped with this software at Documentation/licence.en.txt. */ #ifndef NODELIST_H #define NODELIST_H #include #include #include "fragProp.h" #include "sfielddata.h" G_BEGIN_DECLS #define VISU_TYPE_NODE_LIST (visu_node_list_get_type ()) #define VISU_NODE_LIST(obj) (G_TYPE_CHECK_INSTANCE_CAST(obj, VISU_TYPE_NODE_LIST, VisuNodeList)) #define VISU_NODE_LIST_CLASS(klass) (G_TYPE_CHECK_CLASS_CAST(klass, VISU_TYPE_NODE_LIST, VisuNodeListClass)) #define VISU_IS_NODE_LIST(obj) (G_TYPE_CHECK_INSTANCE_TYPE(obj, VISU_TYPE_NODE_LIST)) #define VISU_IS_NODE_LIST_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE(klass, VISU_TYPE_NODE_LIST)) #define VISU_NODE_LIST_GET_CLASS(obj) (G_TYPE_INSTANCE_GET_CLASS(obj, VISU_TYPE_NODE_LIST, VisuNodeListClass)) typedef struct _VisuNodeList VisuNodeList; typedef struct _VisuNodeListPrivate VisuNodeListPrivate; typedef struct _VisuNodeListClass VisuNodeListClass; /** * VisuNodeList: * * An opaque structure. * * Since: 3.8 */ struct _VisuNodeList { VisuObject parent; VisuNodeListPrivate *priv; }; /** * VisuNodeListClass: * @parent: the parent class; * * A short way to identify #_VisuNodeListClass structure. * * Since: 3.8 */ struct _VisuNodeListClass { VisuObjectClass parent; }; /** * visu_node_list_get_type: * * This method returns the type of #VisuNodeList, use * VISU_TYPE_NODE_LIST instead. * * Since: 3.8 * * Returns: the type of #VisuNodeList. */ GType visu_node_list_get_type(void); VisuNodeList* visu_node_list_new(VisuNodeArray *array); VisuNodeList* visu_node_list_new_fromFrag(VisuNodeValuesFrag *frag, const gchar *label); gboolean visu_node_list_add(VisuNodeList *list, guint id); gboolean visu_node_list_remove(VisuNodeList *list, guint id); VisuScalarFieldData* visu_node_list_envelope(VisuNodeList *list); G_END_DECLS #endif v_sim-3.8.0/src/extraFunctions/nodeProp.c000066400000000000000000000764451370110300500204020ustar00rootroot00000000000000/* EXTRAITS DE LA LICENCE Copyright CEA, contributeurs : Damien CALISTE, laboratoire L_Sim, (2015) Adresse mèl : CALISTE, damien P caliste AT cea P fr. Ce logiciel est un programme informatique servant à visualiser des structures atomiques dans un rendu pseudo-3D. Ce logiciel est régi par la licence CeCILL soumise au droit français et respectant les principes de diffusion des logiciels libres. Vous pouvez utiliser, modifier et/ou redistribuer ce programme sous les conditions de la licence CeCILL telle que diffusée par le CEA, le CNRS et l'INRIA sur le site "http://www.cecill.info". Le fait que vous puissiez accéder à cet en-tête signifie que vous avez pris connaissance de la licence CeCILL, et que vous en avez accepté les termes (cf. le fichier Documentation/licence.fr.txt fourni avec ce logiciel). */ /* LICENCE SUM UP Copyright CEA, contributors : Damien CALISTE, laboratoire L_Sim, (2015) E-mail address: CALISTE, damien P caliste AT cea P fr. This software is a computer program whose purpose is to visualize atomic configurations in 3D. This software is governed by the CeCILL license under French law and abiding by the rules of distribution of free software. You can use, modify and/ or redistribute the software under the terms of the CeCILL license as circulated by CEA, CNRS and INRIA at the following URL "http://www.cecill.info". The fact that you are presently reading this means that you have had knowledge of the CeCILL license and that you accept its terms. You can find a copy of this licence shipped with this software at Documentation/licence.en.txt. */ #include "nodeProp.h" #include /** * SECTION:nodeProp * @short_description: generic way to store (and being notify) data * for each node. * * This is the base object to store data for each node. In * addition, it provides routines to convert this information from and * to strings. It is also possible to get notification on any changes * of this information. */ struct _VisuNodeValuesPrivate { gboolean dispose_has_run; gchar *label; GType type; gboolean editable; guint dim; GWeakRef nodes; gboolean internal; VisuNodeProperty *prop; }; enum { CHANGED_SIGNAL, LAST_SIGNAL }; static guint _signals[LAST_SIGNAL] = { 0 }; enum { PROP_0, INTERNAL_PROP, NODES_PROP, LABEL_PROP, TYPE_PROP, DIM_PROP, EDIT_PROP, N_PROP }; static GParamSpec *_properties[N_PROP]; static void visu_node_values_dispose (GObject* obj); static void visu_node_values_finalize (GObject* obj); static void visu_node_values_constructed (GObject* obj); static void visu_node_values_get_property(GObject* obj, guint property_id, GValue *value, GParamSpec *pspec); static void visu_node_values_set_property(GObject* obj, guint property_id, const GValue *value, GParamSpec *pspec); static gboolean visu_node_values_parse(VisuNodeValues *vals, VisuNode *node, const gchar *from); static gchar* visu_node_values_serialize(const VisuNodeValues *vals, const VisuNode *node); static gboolean _setAt(VisuNodeValues *vals, const VisuNode *node, GValue *value); static gboolean _getAt(const VisuNodeValues *vals, const VisuNode *node, GValue *value); static void _freeBoxed(gpointer data, VisuNodeValues *self); static gpointer _copyBoxed(gconstpointer data, VisuNodeValues *self); G_DEFINE_TYPE_WITH_CODE(VisuNodeValues, visu_node_values, VISU_TYPE_OBJECT, G_ADD_PRIVATE(VisuNodeValues)) static void visu_node_values_class_init(VisuNodeValuesClass *klass) { /* Connect the overloading methods. */ G_OBJECT_CLASS(klass)->dispose = visu_node_values_dispose; G_OBJECT_CLASS(klass)->finalize = visu_node_values_finalize; G_OBJECT_CLASS(klass)->constructed = visu_node_values_constructed; G_OBJECT_CLASS(klass)->set_property = visu_node_values_set_property; G_OBJECT_CLASS(klass)->get_property = visu_node_values_get_property; klass->parse = visu_node_values_parse; klass->serialize = visu_node_values_serialize; klass->setAt = _setAt; klass->getAt = _getAt; /** * VisuNodeValues::internal: * * Values of are internal to #VisuNode structure. * * Since: 3.8 */ _properties[INTERNAL_PROP] = g_param_spec_boolean("internal", "Internal", "internal to VisuNode structure", FALSE, G_PARAM_WRITABLE | G_PARAM_CONSTRUCT_ONLY); /** * VisuNodeValues::nodes: * * Holds the #VisuNodeArray the values are related to. * * Since: 3.8 */ _properties[NODES_PROP] = g_param_spec_object("nodes", "Nodes", "nodes values are related to", VISU_TYPE_NODE_ARRAY, G_PARAM_READWRITE | G_PARAM_CONSTRUCT_ONLY); /** * VisuNodeValues::label: * * Holds the label (translated) that describes the values. * * Since: 3.8 */ _properties[LABEL_PROP] = g_param_spec_string("label", "Label", "description label", "", G_PARAM_READWRITE | G_PARAM_CONSTRUCT_ONLY); /** * VisuNodeValues::type: * * Holds the type of the values. * * Since: 3.8 */ _properties[TYPE_PROP] = g_param_spec_gtype("type", "Type", "type of the values", G_TYPE_NONE, G_PARAM_READWRITE | G_PARAM_CONSTRUCT_ONLY); /** * VisuNodeValues::n-elements: * * Holds the dimension of the property for each nodes. * * Since: 3.8 */ _properties[DIM_PROP] = g_param_spec_uint("n-elements", "N-elements", "number of dimensions", 1, G_MAXINT, 1, G_PARAM_READWRITE | G_PARAM_CONSTRUCT_ONLY); /** * VisuNodeValues::editable: * * Wether the property is editable or not. * * Since: 3.8 */ _properties[EDIT_PROP] = g_param_spec_boolean("editable", "Editable", "user can modify the value", TRUE, G_PARAM_READWRITE); g_object_class_install_properties(G_OBJECT_CLASS(klass), N_PROP, _properties); /** * VisuNodeValues::changed: * @vals: the object which received the signal ; * @node: the #VisuNode that is modified. * * Gets emitted when the values corresponding to this node property * are changed for @node. * * Since: 3.8 */ _signals[CHANGED_SIGNAL] = g_signal_new("changed", G_TYPE_FROM_CLASS(klass), G_SIGNAL_RUN_LAST | G_SIGNAL_NO_RECURSE | G_SIGNAL_NO_HOOKS, 0, NULL, NULL, g_cclosure_marshal_VOID__BOXED, G_TYPE_NONE, 1, VISU_TYPE_NODE, NULL); } static void visu_node_values_init(VisuNodeValues *self) { self->priv = visu_node_values_get_instance_private(self); self->priv->dispose_has_run = FALSE; self->priv->label = (gchar*)0; self->priv->editable = TRUE; self->priv->internal = FALSE; g_weak_ref_init(&self->priv->nodes, (gpointer)0); self->priv->type = 0; self->priv->dim = 0; self->priv->prop = (VisuNodeProperty*)0; } static void visu_node_values_dispose(GObject* obj) { VisuNodeValues *self; self = VISU_NODE_VALUES(obj); if (self->priv->dispose_has_run) return; self->priv->dispose_has_run = TRUE; g_weak_ref_clear(&self->priv->nodes); /* Chain up to the parent class */ G_OBJECT_CLASS(visu_node_values_parent_class)->dispose(obj); } /* This method is called once only. */ static void visu_node_values_finalize(GObject* obj) { VisuNodeValues *self; g_return_if_fail(obj); self = VISU_NODE_VALUES(obj); DBG_fprintf(stderr, "Visu NodeProp: finalising '%s'.\n", self->priv->label); g_free(self->priv->label); /* Chain up to the parent class */ G_OBJECT_CLASS(visu_node_values_parent_class)->finalize(obj); } static void visu_node_values_get_property(GObject* obj, guint property_id, GValue *value, GParamSpec *pspec) { VisuNodeValues *self = VISU_NODE_VALUES(obj); switch (property_id) { case NODES_PROP: g_value_take_object(value, g_weak_ref_get(&self->priv->nodes)); break; case LABEL_PROP: g_value_set_string(value, self->priv->label); break; case TYPE_PROP: g_value_set_gtype(value, self->priv->type); break; case DIM_PROP: g_value_set_uint(value, self->priv->dim); break; case EDIT_PROP: g_value_set_boolean(value, self->priv->editable); break; default: /* We don't have any other property... */ G_OBJECT_WARN_INVALID_PROPERTY_ID(obj, property_id, pspec); break; } } static void visu_node_values_set_property(GObject* obj, guint property_id, const GValue *value, GParamSpec *pspec) { VisuNodeValues *self = VISU_NODE_VALUES(obj); switch (property_id) { case INTERNAL_PROP: self->priv->internal = g_value_get_boolean(value); break; case NODES_PROP: g_weak_ref_set(&self->priv->nodes, g_value_dup_object(value)); g_object_unref(g_value_get_object(value)); break; case LABEL_PROP: self->priv->label = g_value_dup_string(value); break; case TYPE_PROP: self->priv->type = g_value_get_gtype(value); break; case DIM_PROP: self->priv->dim = g_value_get_uint(value); break; case EDIT_PROP: visu_node_values_setEditable(self, g_value_get_boolean(value)); break; default: /* We don't have any other property... */ G_OBJECT_WARN_INVALID_PROPERTY_ID(obj, property_id, pspec); break; } } static void _stringFree(gchar *data, gpointer add _U_) { g_free(data); } static gchar* _stringCopy(const gchar *data, gpointer add _U_) { return g_strdup(data); } static void _objectFree(GObject *data, gpointer add _U_) { g_object_unref(data); } static GObject* _objectCopy(GObject *data, gpointer add _U_) { return g_object_ref(data); } static void visu_node_values_constructed(GObject *obj) { VisuNodeValues *self = VISU_NODE_VALUES(obj); gpointer nodes; if (self->priv->type && self->priv->dim && !self->priv->internal) { nodes = g_weak_ref_get(&self->priv->nodes); if (!nodes) return; switch (G_TYPE_FUNDAMENTAL(self->priv->type)) { case (G_TYPE_INT): case (G_TYPE_UINT): case (G_TYPE_BOOLEAN): self->priv->prop = visu_node_array_property_newInteger(VISU_NODE_ARRAY(nodes), self->priv->label); break; case (G_TYPE_FLOAT): self->priv->prop = visu_node_array_property_newFloatArray(VISU_NODE_ARRAY(nodes), self->priv->label, self->priv->dim); break; case (G_TYPE_STRING): self->priv->prop = visu_node_array_property_newPointer(VISU_NODE_ARRAY(nodes), self->priv->label, (GFunc)_stringFree, (GCopyFunc)_stringCopy, (gpointer)0); break; case (G_TYPE_BOXED): self->priv->prop = visu_node_array_property_newPointer(VISU_NODE_ARRAY(nodes), self->priv->label, (GFunc)_freeBoxed, (GCopyFunc)_copyBoxed, (gpointer)self); break; case (G_TYPE_OBJECT): self->priv->prop = visu_node_array_property_newPointer(VISU_NODE_ARRAY(nodes), self->priv->label, (GFunc)_objectFree, (GCopyFunc)_objectCopy, (gpointer)0); break; default: g_warning("Unsupported NodeValues type."); } g_object_unref(nodes); } G_OBJECT_CLASS(visu_node_values_parent_class)->constructed(obj); } static void _freeBoxed(gpointer data, VisuNodeValues *self) { g_boxed_free(self->priv->type, data); } static gpointer _copyBoxed(gconstpointer data, VisuNodeValues *self) { return g_boxed_copy(self->priv->type, data); } gboolean visu_node_values_parse(VisuNodeValues *vals, VisuNode *node, const gchar *from) { int ival; guint uval; gboolean bval, modify; float *fvals, *rvals; gchar **datas; guint i; GValue value = G_VALUE_INIT; g_return_val_if_fail(VISU_IS_NODE_VALUES(vals) && node && from, FALSE); if (!visu_node_values_getAt(vals, node, &value)) return FALSE; fvals = (float*)0; switch (vals->priv->type) { case (G_TYPE_INT): if (sscanf(from, "%d", &ival) != 1) return FALSE; if (ival == g_value_get_int(&value)) return TRUE; g_value_set_int(&value, ival); break; case (G_TYPE_UINT): if (sscanf(from, "%u", &uval) != 1) return FALSE; if (uval == g_value_get_uint(&value)) return TRUE; g_value_set_uint(&value, uval); break; case (G_TYPE_BOOLEAN): if (!strcmp(from, _("T"))) bval = TRUE; else if (!strcmp(from, _("F"))) bval = FALSE; else return FALSE; if (bval == g_value_get_boolean(&value)) return TRUE; g_value_set_boolean(&value, bval); break; case (G_TYPE_FLOAT): datas = g_strsplit_set(from, "(;)", vals->priv->dim); if (datas && datas[0] && !datas[1] && !strcmp(datas[0], _("none"))) { g_strfreev(datas); g_value_set_pointer(&value, (gpointer)0); break; } fvals = g_malloc(sizeof(float) * vals->priv->dim); for (i = 0; datas[i]; i++) if (sscanf(from, "%f", fvals + i) != 1) { g_free(fvals); g_strfreev(datas); return FALSE; } g_strfreev(datas); if (i != vals->priv->dim) { g_free(fvals); return FALSE; } rvals = (float*)g_value_get_pointer(&value); modify = (rvals == (float*)0); for (i = 0; i < (rvals ? vals->priv->dim : 0); i++) modify = modify || (rvals[i] != fvals[i]); if (!modify) { g_free(fvals); return TRUE; } g_value_set_pointer(&value, fvals); break; case (G_TYPE_STRING): if (!strcmp(from, g_value_get_string(&value))) return TRUE; g_value_set_string(&value, from); break; default: g_warning("Unsupported NodeValues type."); } modify = visu_node_values_setAt(vals, node, &value); if (vals->priv->type == G_TYPE_FLOAT) g_free(fvals); return modify; } gchar* visu_node_values_serialize(const VisuNodeValues *vals, const VisuNode *node) { GString *str; guint i; float *fvals; gchar *ret; GValue value = {0, {{0}, {0}}}; g_return_val_if_fail(VISU_IS_NODE_VALUES(vals) && node, (gchar*)0); if (!visu_node_values_getAt(vals, node, &value)) return (gchar*)0; switch (vals->priv->type) { case (G_TYPE_INT): return g_strdup_printf("%d", g_value_get_int(&value)); case (G_TYPE_UINT): return g_strdup_printf("%d", g_value_get_uint(&value)); case (G_TYPE_BOOLEAN): if (g_value_get_boolean(&value)) return g_strdup(_("T")); else return g_strdup(_("F")); case (G_TYPE_FLOAT): fvals = (float*)g_value_get_pointer(&value); if (fvals) { str = g_string_new(""); if (vals->priv->dim > 1) g_string_append(str, "( "); g_string_append_printf(str, "%#.3g", fvals[0]); for (i = 1; i < vals->priv->dim; i++) g_string_append_printf(str, " ; %#.3g", fvals[i]); if (vals->priv->dim > 1) g_string_append(str, " )"); ret = str->str; g_string_free(str, FALSE); return ret; } else { return g_strdup(_("none")); } case (G_TYPE_STRING): return g_value_dup_string(&value); default: g_warning("Unsupported NodeValues type."); } return (gchar*)0; } static gboolean _setAt(VisuNodeValues *vals, const VisuNode *node, GValue *value) { gpointer nodes; g_return_val_if_fail(VISU_IS_NODE_VALUES(vals) && (vals->priv->prop || vals->priv->internal), FALSE); nodes = g_weak_ref_get(&vals->priv->nodes); if (!nodes) return FALSE; if (!vals->priv->internal) visu_node_property_setValue(vals->priv->prop, node, value); g_signal_emit(G_OBJECT(vals), _signals[CHANGED_SIGNAL], 0, node); g_object_unref(nodes); return TRUE; } static gboolean _getAt(const VisuNodeValues *vals, const VisuNode *node, GValue *value) { gpointer nodes; g_return_val_if_fail(VISU_IS_NODE_VALUES(vals) && (vals->priv->prop || vals->priv->internal), FALSE); if (vals->priv->internal) return TRUE; nodes = g_weak_ref_get(&vals->priv->nodes); if (!nodes) return FALSE; visu_node_property_getValue(vals->priv->prop, node, value); g_object_unref(nodes); return TRUE; } /** * visu_node_values_new: * @arr: a #VisuNodeArray object. * @label: a label. * @type: a type. * @dim: some dimension. * * Creates a new #VisuNodeValues object, used to store @dim values of * type @type for each node in @arr. * * Since: 3.8 * * Returns: (transfer full): a newly created #VisuNodeValues object. **/ VisuNodeValues* visu_node_values_new(VisuNodeArray *arr, const gchar *label, GType type, guint dim) { VisuNodeValues *vals; vals = VISU_NODE_VALUES(g_object_new(VISU_TYPE_NODE_VALUES, "nodes", arr, "label", label, "type", type, "n-elements", dim, NULL)); return vals; } /** * visu_node_values_getLabel: * @vals: a #VisuNodeValues object. * * Retrives the label used to identify @vals. * * Since: 3.8 * * Returns: a string. **/ const gchar* visu_node_values_getLabel(const VisuNodeValues *vals) { g_return_val_if_fail(VISU_IS_NODE_VALUES(vals), (const gchar*)0); return vals->priv->label; } /** * visu_node_values_getDimension: * @vals: a #VisuNodeValues object. * * Retrieves how many values are stored per node, aka the column number. * * Since: 3.8 * * Returns: a number of columns. **/ guint visu_node_values_getDimension(const VisuNodeValues *vals) { g_return_val_if_fail(VISU_IS_NODE_VALUES(vals), 0); return vals->priv->dim; } /** * visu_node_values_setEditable: * @vals: a #VisuNodeValues object. * @status: a boolean. * * Change the writable @status of @vals. * * Since: 3.8 **/ void visu_node_values_setEditable(VisuNodeValues *vals, gboolean status) { g_return_if_fail(VISU_IS_NODE_VALUES(vals)); if (vals->priv->editable == status) return; vals->priv->editable = status; g_object_notify_by_pspec(G_OBJECT(vals), _properties[EDIT_PROP]); } /** * visu_node_values_getEditable: * @vals: a #VisuNodeValues object. * * Retrieves if @vals are writable or not. * * Since: 3.8 * * Returns: TRUE if values can be changed. **/ gboolean visu_node_values_getEditable(const VisuNodeValues *vals) { g_return_val_if_fail(VISU_IS_NODE_VALUES(vals), FALSE); return vals->priv->editable; } /** * visu_node_values_setFromString: * @vals: a #VisuNodeValues object. * @node: a #VisuNode pointer. * @from: a string. * * Parse @from to set a value to @node in @vals. * * Since: 3.8 * * Returns: TRUE if value is actually changed. **/ gboolean visu_node_values_setFromString(VisuNodeValues *vals, VisuNode *node, const gchar *from) { VisuNodeValuesClass *klass = VISU_NODE_VALUES_GET_CLASS(vals); g_return_val_if_fail(klass && klass->parse, FALSE); g_return_val_if_fail(VISU_IS_NODE_VALUES(vals), FALSE); if (!vals->priv->editable) return FALSE; return klass->parse(vals, node, from); } /** * visu_node_values_setFromStringForId: * @vals: a #VisuNodeValues object. * @nodeId: a node id. * @from: a string. * * Same as visu_node_values_setFromString(), but uses a node id to * identify a #VisuNode in @vals. * * Since: 3.8 * * Returns: TRUE if value is actually changed. **/ gboolean visu_node_values_setFromStringForId(VisuNodeValues *vals, guint nodeId, const gchar *from) { VisuNode *node; VisuNodeArray *arr; arr = visu_node_values_getArray(vals); node = visu_node_array_getFromId(arr, nodeId); g_object_unref(arr); if (!node) return FALSE; return visu_node_values_setFromString(vals, node, from); } /** * visu_node_values_toString: * @vals: a #VisuNodeValues object. * @node: a #VisuNode pointer. * * Creates a string representation of the value stored for @node. * * Since: 3.8 * * Returns: (transfer full): a newly created string. **/ gchar* visu_node_values_toString(const VisuNodeValues *vals, const VisuNode *node) { g_return_val_if_fail(VISU_IS_NODE_VALUES(vals), (gchar*)0); VisuNodeValuesClass *klass = VISU_NODE_VALUES_GET_CLASS(vals); g_return_val_if_fail(klass && klass->serialize, (gchar*)0); return klass->serialize(vals, node); } /** * visu_node_values_toStringFromId: * @vals: a #VisuNodeValues object. * @nodeId: a node id. * * Like visu_node_values_toString(), but using a string id. * * Since: 3.8 * * Returns: (transfer full): a newly created string. **/ gchar* visu_node_values_toStringFromId(const VisuNodeValues *vals, guint nodeId) { VisuNode *node; VisuNodeArray *arr; arr = visu_node_values_getArray(vals); node = visu_node_array_getFromId(arr, nodeId); g_object_unref(arr); if (!node) return (gchar*)0; return visu_node_values_toString(vals, node); } /** * visu_node_values_setAt: * @vals: a #VisuNodeValues object. * @node: a #VisuNode pointer. * @value: some value. * * Set @value for @node in @vals. * * Since: 3.8 * * Returns: TRUE if value is actually changed. **/ gboolean visu_node_values_setAt(VisuNodeValues *vals, const VisuNode *node, GValue *value) { VisuNodeValuesClass *klass = VISU_NODE_VALUES_GET_CLASS(vals); g_return_val_if_fail(klass && klass->setAt, FALSE); g_return_val_if_fail(VISU_IS_NODE_VALUES(vals), FALSE); return klass->setAt(vals, node, value); } /** * visu_node_values_copy: * @vals: a #VisuNodeValues object. * @from: a #VisuNodeValues object. * * Copies all values @from to @vals, providing that @from and @vals * store compatible data. The values are copied using the #VisuNode * id. If an id for a node of @vals is not found in @from, no node * value is copied for this node. The original id is used. * * Since: 3.8 * * Returns: TRUE if @vals is editable and all values @from have been * actually copied. **/ gboolean visu_node_values_copy(VisuNodeValues *vals, const VisuNodeValues *from) { g_return_val_if_fail(VISU_IS_NODE_VALUES(vals), FALSE); VisuNodeValuesClass *klass = VISU_NODE_VALUES_GET_CLASS(vals); g_return_val_if_fail(klass && klass->setAt, FALSE); VisuNodeValuesClass *klassFrom = VISU_NODE_VALUES_GET_CLASS(from); g_return_val_if_fail(klassFrom && klassFrom->getAt, FALSE); VisuNodeArrayIter iter; VisuNodeArray *arr, *cur; VisuNode *fromNode; GValue value = G_VALUE_INIT; int orig; DBG_fprintf(stderr, "Node Values : copy from %p to %p.\n", (gpointer)from, (gpointer)vals); if (!vals->priv->editable) return FALSE; switch (G_TYPE_FUNDAMENTAL(vals->priv->type)) { case (G_TYPE_INT): g_value_init(&value, G_TYPE_INT); break; case (G_TYPE_UINT): g_value_init(&value, G_TYPE_UINT); break; case (G_TYPE_BOOLEAN): g_value_init(&value, G_TYPE_BOOLEAN); break; case (G_TYPE_FLOAT): g_value_init(&value, G_TYPE_POINTER); break; case (G_TYPE_STRING): g_value_init(&value, G_TYPE_STRING); break; case (G_TYPE_BOXED): g_value_init(&value, vals->priv->type); break; case (G_TYPE_OBJECT): g_value_init(&value, vals->priv->type); break; default: g_warning("Unsupported NodeValues type."); return FALSE; } cur = visu_node_values_getArray(vals); arr = visu_node_values_getArray(from); g_return_val_if_fail(arr && cur, FALSE); visu_node_array_iter_new(cur, &iter); for (visu_node_array_iterStart(cur, &iter); iter.node; visu_node_array_iterNext(cur, &iter)) { orig = visu_node_array_getOriginal(cur, iter.node->number); fromNode = visu_node_array_getFromId (arr, orig < 0 ? iter.node->number : (guint)orig); if (fromNode && klassFrom->getAt(from, fromNode, &value)) klass->setAt(vals, iter.node, &value); } g_object_unref(arr); g_object_unref(cur); DBG_fprintf(stderr, "Node Values : copy done.\n"); return TRUE; } /** * visu_node_values_reset: * @vals: a #VisuNodeValues object. * * Reset all stored values. * * Since: 3.8 **/ void visu_node_values_reset(VisuNodeValues *vals) { g_return_if_fail(VISU_IS_NODE_VALUES(vals)); visu_node_property_reset(vals->priv->prop); g_signal_emit(G_OBJECT(vals), _signals[CHANGED_SIGNAL], 0, NULL); } /** * visu_node_values_getAt: * @vals: a #VisuNodeValues object. * @node: a #VisuNode structure. * @value: (out caller-allocates): a value location. * * Retrieves the value stored in @vals for @node. @value is * initialised to the proper type at each call. For repeatedly * retrieving values for various nodes, prefer to use a * #VisuNodeValuesIter instead. * * Since: 3.8 * * Returns: TRUE if value is properly retrieved. **/ gboolean visu_node_values_getAt(const VisuNodeValues *vals, const VisuNode *node, GValue *value) { VisuNodeValuesClass *klass = VISU_NODE_VALUES_GET_CLASS(vals); g_return_val_if_fail(klass && klass->getAt, FALSE); switch (G_TYPE_FUNDAMENTAL(vals->priv->type)) { case (G_TYPE_INT): g_value_init(value, G_TYPE_INT); break; case (G_TYPE_UINT): g_value_init(value, G_TYPE_UINT); break; case (G_TYPE_BOOLEAN): g_value_init(value, G_TYPE_BOOLEAN); break; case (G_TYPE_FLOAT): g_value_init(value, G_TYPE_POINTER); break; case (G_TYPE_STRING): g_value_init(value, G_TYPE_STRING); break; case (G_TYPE_BOXED): g_value_init(value, vals->priv->type); break; case (G_TYPE_OBJECT): g_value_init(value, vals->priv->type); break; default: g_warning("Unsupported NodeValues type."); } return klass->getAt(vals, node, value); } /** * visu_node_values_getPtrAt: * @vals: a #VisuNodeValues object. * @node: a #VisuNode object. * * Retrieve the values associated to @node, as long as it can be * stored as a pointer. This is aconvenient function to avoid * instanciating a GValue. * * Since: 3.8 * * Returns: (transfer none): a pointer to some data. **/ gpointer visu_node_values_getPtrAt(const VisuNodeValues *vals, const VisuNode *node) { GValue value; VisuNodeValuesClass *klass = VISU_NODE_VALUES_GET_CLASS(vals); g_return_val_if_fail(klass && klass->getAt, FALSE); memset(&value, '\0', sizeof(GValue)); g_value_init(&value, G_TYPE_POINTER); if (klass->getAt(vals, node, &value)) return g_value_get_pointer(&value); else return (gpointer)0; } /** * visu_node_values_getArray: * @vals: a #VisuNodeValues object. * * Retrieves the #VisuNodeArray, @vels is based on. * * Since: 3.8 * * Returns: (transfer full) (allow-none): a #VisuNodeArray object. **/ VisuNodeArray* visu_node_values_getArray(const VisuNodeValues *vals) { gpointer nodes; g_return_val_if_fail(VISU_IS_NODE_VALUES(vals), (VisuNodeArray*)0); nodes = g_weak_ref_get(&vals->priv->nodes); return (nodes) ? VISU_NODE_ARRAY(nodes) : (VisuNodeArray*)0; } /** * visu_node_values_fromArray: * @vals: a #VisuNodeValues object. * @arr: a #VisuNodeArray object. * * Tests if @arr is used as base for @vals. * * Since: 3.8 * * Returns: TRUE if @vals is stored in @arr. **/ gboolean visu_node_values_fromArray(VisuNodeValues *vals, const VisuNodeArray *arr) { VisuNodeArray *source; gboolean res; source = visu_node_values_getArray(vals); res = (source == arr); if (source) g_object_unref(source); return res; } /** * visu_node_values_iter_new: * @iter: (out caller-allocates): an iterator location. * @type: a iteration type. * @vals: a #VisuNodeValues object. * * Creates an iterator to run over node values stored in @vals, * following @type way of iterate. * * Since: 3.8 * * Returns: TRUE if the iterator is in a valid state. **/ gboolean visu_node_values_iter_new(VisuNodeValuesIter *iter, VisuNodeArrayIterType type, VisuNodeValues *vals) { g_return_val_if_fail(VISU_IS_NODE_VALUES(vals) && iter, FALSE); visu_node_values___iter__(vals, iter); if (!iter->vals) return FALSE; iter->iter.type = type; return visu_node_values_iter_next(iter); } /** * visu_node_values___iter__: * @iter: (out caller-allocates): an iterator location. * @vals: a #VisuNodeValues object. * * Creates an iterator to run over node values stored in @vals. This * routine is mainly for Python bindings, use * visu_node_values_iter_new() instead. * * Since: 3.8 **/ void visu_node_values___iter__(VisuNodeValues *vals, VisuNodeValuesIter *iter) { gpointer nodes; g_return_if_fail(VISU_IS_NODE_VALUES(vals) && iter); iter->vals = (VisuNodeValues*)0; nodes = g_weak_ref_get(&vals->priv->nodes); if (!nodes) return; /* Currently don't guarantee the availability of nodes during the iter. */ g_object_unref(nodes); iter->vals = vals; memset(&iter->value, '\0', sizeof(GValue)); switch (G_TYPE_FUNDAMENTAL(vals->priv->type)) { case (G_TYPE_INT): g_value_init(&iter->value, G_TYPE_INT); break; case (G_TYPE_UINT): g_value_init(&iter->value, G_TYPE_UINT); break; case (G_TYPE_BOOLEAN): g_value_init(&iter->value, G_TYPE_BOOLEAN); break; case (G_TYPE_FLOAT): g_value_init(&iter->value, G_TYPE_POINTER); break; case (G_TYPE_STRING): g_value_init(&iter->value, G_TYPE_STRING); break; case (G_TYPE_BOXED): g_value_init(&iter->value, vals->priv->type); break; case (G_TYPE_OBJECT): g_value_init(&iter->value, vals->priv->type); break; default: g_warning("Unsupported NodeValues type."); } visu_node_array_iter_new(VISU_NODE_ARRAY(nodes), &iter->iter); } /** * visu_node_values_iter_next: * @iter: a #VisuNodeValuesIter object. * * Iterates to the next node value. * * Since: 3.8 * * Returns: TRUE if the iterator is still in a valid state. **/ gboolean visu_node_values_iter_next(VisuNodeValuesIter *iter) { gboolean res; VisuNodeValuesClass *klass = VISU_NODE_VALUES_GET_CLASS(iter->vals); g_return_val_if_fail(klass && klass->getAt, FALSE); res = visu_node_array_iter_next(&iter->iter); if (res) klass->getAt(iter->vals, iter->iter.node, &iter->value); return res; } v_sim-3.8.0/src/extraFunctions/nodeProp.h000066400000000000000000000172121370110300500203720ustar00rootroot00000000000000/* EXTRAITS DE LA LICENCE Copyright CEA, contributeurs : Damien CALISTE, laboratoire L_Sim, (2015-2019) Adresse mèl : CALISTE, damien P caliste AT cea P fr. Ce logiciel est un programme informatique servant à visualiser des structures atomiques dans un rendu pseudo-3D. Ce logiciel est régi par la licence CeCILL soumise au droit français et respectant les principes de diffusion des logiciels libres. Vous pouvez utiliser, modifier et/ou redistribuer ce programme sous les conditions de la licence CeCILL telle que diffusée par le CEA, le CNRS et l'INRIA sur le site "http://www.cecill.info". Le fait que vous puissiez accéder à cet en-tête signifie que vous avez pris connaissance de la licence CeCILL, et que vous en avez accepté les termes (cf. le fichier Documentation/licence.fr.txt fourni avec ce logiciel). */ /* LICENCE SUM UP Copyright CEA, contributors : Damien CALISTE, laboratoire L_Sim, (2015-2019) E-mail address: CALISTE, damien P caliste AT cea P fr. This software is a computer program whose purpose is to visualize atomic configurations in 3D. This software is governed by the CeCILL license under French law and abiding by the rules of distribution of free software. You can use, modify and/ or redistribute the software under the terms of the CeCILL license as circulated by CEA, CNRS and INRIA at the following URL "http://www.cecill.info". The fact that you are presently reading this means that you have had knowledge of the CeCILL license and that you accept its terms. You can find a copy of this licence shipped with this software at Documentation/licence.en.txt. */ #ifndef NODEPROP_H #define NODEPROP_H #include #include #include G_BEGIN_DECLS #define VISU_TYPE_NODE_VALUES (visu_node_values_get_type ()) #define VISU_NODE_VALUES(obj) (G_TYPE_CHECK_INSTANCE_CAST(obj, VISU_TYPE_NODE_VALUES, VisuNodeValues)) #define VISU_NODE_VALUES_CLASS(klass) (G_TYPE_CHECK_CLASS_CAST(klass, VISU_TYPE_NODE_VALUES, VisuNodeValuesClass)) #define VISU_IS_NODE_VALUES(obj) (G_TYPE_CHECK_INSTANCE_TYPE(obj, VISU_TYPE_NODE_VALUES)) #define VISU_IS_NODE_VALUES_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE(klass, VISU_TYPE_NODE_VALUES)) #define VISU_NODE_VALUES_GET_CLASS(obj) (G_TYPE_INSTANCE_GET_CLASS(obj, VISU_TYPE_NODE_VALUES, VisuNodeValuesClass)) /** * VisuNodeValuesPrivate: * * Private data for #VisuNodeValues objects. */ typedef struct _VisuNodeValuesPrivate VisuNodeValuesPrivate; /** * VisuNodeValues: * * Common name to refer to a #_VisuNodeValues. */ typedef struct _VisuNodeValues VisuNodeValues; struct _VisuNodeValues { VisuObject parent; VisuNodeValuesPrivate *priv; }; /** * VisuNodeValuesFromString: * @vals: a #VisuNodeValues object. * @node: a #VisuNode pointer. * @string: a string. * * Prototype of functions used to parse @string and store its content * for @node in @vals. * * Since: 3.8 * * Returns: TRUE on success. */ typedef gboolean (*VisuNodeValuesFromString)(VisuNodeValues *vals, VisuNode *node, const gchar *string); /** * VisuNodeValuestoString: * @vals: a #VisuNodeValues object. * @node: a #VisuNode pointer. * * Prototype of functions used to stringify the node values of @node * from @vals. * * Since: 3.8 * * Returns: (transfer full): a newly created string representing the * values of @node. */ typedef gchar* (*VisuNodeValuestoString)(const VisuNodeValues *vals, const VisuNode *node); /** * VisuNodeValuesSetAt: * @vals: a #VisuNodeValues object. * @node: a #VisuNode pointer. * @value: a value. * * Prototype of functions used to store the content of @value for * @node in @vals. * * Since: 3.8 * * Returns: TRUE on success. */ typedef gboolean (*VisuNodeValuesSetAt)(VisuNodeValues *vals, const VisuNode *node, GValue *value); /** * VisuNodeValuesGetAt: * @vals: a #VisuNodeValues object. * @node: a #VisuNode pointer. * @value: a value. * * Prototype of functions used to store in @value the values * associated to @node from @vals. * * Since: 3.8 * * Returns: TRUE on success. */ typedef gboolean (*VisuNodeValuesGetAt)(const VisuNodeValues *vals, const VisuNode *node, GValue *value); /** * VisuNodeValuesClass: * @parent: private. * @parse: a routine to get values from a string. * @serialize: a routine to write format into a string. * @setAt: a routine to store values at a node. * @getAt: a routine to get values at a node. * * Common name to refer to a #_VisuNodeValuesClass. */ typedef struct _VisuNodeValuesClass VisuNodeValuesClass; struct _VisuNodeValuesClass { VisuObjectClass parent; VisuNodeValuesFromString parse; VisuNodeValuestoString serialize; VisuNodeValuesSetAt setAt; VisuNodeValuesGetAt getAt; }; /** * visu_node_values_get_type: * * This method returns the type of #VisuNodeValues, use * VISU_TYPE_NODE_VALUES instead. * * Since: 3.8 * * Returns: the type of #VisuNodeValues. */ GType visu_node_values_get_type(void); VisuNodeValues* visu_node_values_new(VisuNodeArray *arr, const gchar *label, GType type, guint dim); gboolean visu_node_values_fromArray(VisuNodeValues *vals, const VisuNodeArray *arr); const gchar* visu_node_values_getLabel(const VisuNodeValues *vals); guint visu_node_values_getDimension(const VisuNodeValues *vals); void visu_node_values_setEditable(VisuNodeValues *vals, gboolean status); gboolean visu_node_values_getEditable(const VisuNodeValues *vals); gboolean visu_node_values_setFromString(VisuNodeValues *vals, VisuNode *node, const gchar *from); gboolean visu_node_values_setFromStringForId(VisuNodeValues *vals, guint nodeId, const gchar *from); gchar* visu_node_values_toString(const VisuNodeValues *vals, const VisuNode *node); gchar* visu_node_values_toStringFromId(const VisuNodeValues *vals, guint nodeId); gboolean visu_node_values_setAt(VisuNodeValues *vals, const VisuNode *node, GValue *value); gboolean visu_node_values_getAt(const VisuNodeValues *vals, const VisuNode *node, GValue *value); gpointer visu_node_values_getPtrAt(const VisuNodeValues *vals, const VisuNode *node); gboolean visu_node_values_copy(VisuNodeValues *vals, const VisuNodeValues *from); VisuNodeArray* visu_node_values_getArray(const VisuNodeValues *vals); void visu_node_values_reset(VisuNodeValues *vals); /** * VisuNodeValuesIter: * @value: the stored value. * @iter: the iterator used to span nodes. * @vals: the parent #VisuNodeValues object. * * Iterator structure used to read values of nodes. * * Since: 3.8 */ typedef struct _VisuNodeValuesIter VisuNodeValuesIter; struct _VisuNodeValuesIter { GValue value; VisuNodeArrayIter iter; /* Private. */ VisuNodeValues *vals; }; gboolean visu_node_values_iter_new(VisuNodeValuesIter *iter, VisuNodeArrayIterType type, VisuNodeValues *vals); void visu_node_values___iter__(VisuNodeValues *vals, VisuNodeValuesIter *iter); gboolean visu_node_values_iter_next(VisuNodeValuesIter *iter); G_END_DECLS #endif v_sim-3.8.0/src/extraFunctions/plane.c000066400000000000000000001114261370110300500177000ustar00rootroot00000000000000/* EXTRAITS DE LA LICENCE Copyright CEA, contributeurs : Luc BILLARD et Damien CALISTE, laboratoire L_Sim, (2001-2017) Adresse mèl : BILLARD, non joignable par mèl ; CALISTE, damien P caliste AT cea P fr. Ce logiciel est un programme informatique servant à visualiser des structures atomiques dans un rendu pseudo-3D. Ce logiciel est régi par la licence CeCILL soumise au droit français et respectant les principes de diffusion des logiciels libres. Vous pouvez utiliser, modifier et/ou redistribuer ce programme sous les conditions de la licence CeCILL telle que diffusée par le CEA, le CNRS et l'INRIA sur le site "http://www.cecill.info". Le fait que vous puissiez accéder à cet en-tête signifie que vous avez pris connaissance de la licence CeCILL, et que vous en avez accepté les termes (cf. le fichier Documentation/licence.fr.txt fourni avec ce logiciel). */ /* LICENCE SUM UP Copyright CEA, contributors : Luc BILLARD et Damien CALISTE, laboratoire L_Sim, (2001-2017) E-mail address: BILLARD, not reachable any more ; CALISTE, damien P caliste AT cea P fr. This software is a computer program whose purpose is to visualize atomic configurations in 3D. This software is governed by the CeCILL license under French law and abiding by the rules of distribution of free software. You can use, modify and/ or redistribute the software under the terms of the CeCILL license as circulated by CEA, CNRS and INRIA at the following URL "http://www.cecill.info". The fact that you are presently reading this means that you have had knowledge of the CeCILL license and that you accept its terms. You can find a copy of this licence shipped with this software at Documentation/licence.en.txt. */ #include "plane.h" #include #include #include #include #include /** * SECTION:plane * @short_description: Adds capabilities to draw and handle planes. * * A #VisuPlane is a GObject. It is defined by its normal vector and * the distance of the plane with the origin (see * visu_plane_setNormalVector() and visu_plane_setDistanceFromOrigin()). When * these informations are given and an #VisuGlView is used to render * the plane, V_Sim computes the intersections of the plane with the * bounding box (see visu_plane_getIntersection()). * #VisuPlane can be used to hide nodes defining their * visu_plane_setHiddenState() and visu_plane_set_setHiddingMode(). A list of planes * can also be exported or imported from an XML file using * visu_plane_set_exportXMLFile() and visu_plane_set_parseXMLFile(). * #VisuPlane can have transparency but the support of it is limited * to one plane. If several planes are drawn with transparency, they * may hide each other because of the implementation of transparency * in OpenGL (planes are treated as single polygons). */ struct _VisuPlane { /* Internal object gestion. */ VisuObject parent; gboolean dispose_has_run; /* Normal vector, unitary. */ float nVect[3]; /* Normal vector, user given. */ float nVectUser[3]; /* Distance between origin and intersection of the plane and the line made by origin and normal vector. */ float dist; /* ToolColor of that plane. */ ToolColor *color; gfloat opacity; VisuAnimation *opacity_anim; /* Internal variables */ VisuBox *box; gulong size_signal; /* Intersections with the bounding box. Consist of a GList of float[3], can be NULL if there is no interstection. */ GList *inter; /* Isobarycenter G of all intersection points, required to order these points to form a convex polygon. */ float pointG[3]; /* The plane can hide the nodes on one of its side. This variable can be VISU_PLANE_SIDE_PLUS or VISU_PLANE_SIDE_MINUS or VISU_PLANE_SIDE_NONE. It codes the side of the plane which hides the nodes. If VISU_PLANE_SIDE_NONE is selected all nodes are rendered. */ int hiddenSide; }; enum { VISU_PLANE_MOVED_SIGNAL, VISU_PLANE_RENDERING_SIGNAL, VISU_PLANE_NB_SIGNAL }; enum { PROP_0, DIST_PROP, VECT_PROP, COLOR_PROP, HIDDING_PROP, RENDERED_PROP, OPACITY_PROP, N_PROP, ADJUST_PROP, BOX_PROP }; static GParamSpec *properties[N_PROP]; /* Internal variables. */ static guint plane_signals[VISU_PLANE_NB_SIGNAL] = { 0 }; /* Object gestion methods. */ static void visu_plane_dispose (GObject* obj); static void visu_plane_finalize (GObject* obj); static void visu_boxed_interface_init(VisuBoxedInterface *iface); static void visu_animatable_interface_init(VisuAnimatableInterface *iface); static void visu_plane_get_property(GObject* obj, guint property_id, GValue *value, GParamSpec *pspec); static void visu_plane_set_property(GObject* obj, guint property_id, const GValue *value, GParamSpec *pspec); /* Local methods. */ static VisuBox* visu_plane_getBox(VisuBoxed *self); static gboolean visu_plane_setBox(VisuBoxed *self, VisuBox *box); static VisuAnimation* _getAnimation(const VisuAnimatable *self, const gchar *prop); static void onBoxSizeChanged(VisuBox *box, float extens, gpointer data); static int comparePolygonPoint(gconstpointer pointA, gconstpointer pointB, gpointer data); static void computeInter(VisuPlane* plane); G_DEFINE_TYPE_WITH_CODE(VisuPlane, visu_plane, VISU_TYPE_OBJECT, G_IMPLEMENT_INTERFACE(VISU_TYPE_BOXED, visu_boxed_interface_init) G_IMPLEMENT_INTERFACE(VISU_TYPE_ANIMATABLE, visu_animatable_interface_init)) static void visu_plane_class_init(VisuPlaneClass *klass) { DBG_fprintf(stderr, "Visu Plane : creating the class of the object.\n"); /* Connect freeing methods. */ G_OBJECT_CLASS(klass)->dispose = visu_plane_dispose; G_OBJECT_CLASS(klass)->finalize = visu_plane_finalize; G_OBJECT_CLASS(klass)->set_property = visu_plane_set_property; G_OBJECT_CLASS(klass)->get_property = visu_plane_get_property; DBG_fprintf(stderr, " - adding new signals ;\n"); /** * VisuPlane::moved: * @plane: the object emitting the signal. * * This signal is emitted each time the plane position is changed * (either distance or normal). * * Since: 3.3 */ plane_signals[VISU_PLANE_MOVED_SIGNAL] = g_signal_newv("moved", G_TYPE_FROM_CLASS(klass), G_SIGNAL_RUN_LAST | G_SIGNAL_NO_RECURSE | G_SIGNAL_NO_HOOKS, NULL, NULL, NULL, g_cclosure_marshal_VOID__VOID, G_TYPE_NONE, 0, NULL); /** * VisuPlane::rendering: * @plane: the object emitting the signal. * * This signal is emitted each time the rendering properties (color, * visibility...) are affected. * * Since: 3.7 */ plane_signals[VISU_PLANE_RENDERING_SIGNAL] = g_signal_newv("rendering", G_TYPE_FROM_CLASS(klass), G_SIGNAL_RUN_LAST | G_SIGNAL_NO_RECURSE | G_SIGNAL_NO_HOOKS, NULL, NULL, NULL, g_cclosure_marshal_VOID__VOID, G_TYPE_NONE, 0, NULL); /** * VisuPlane::distance: * * Distance to origin. * * Since: 3.8 */ properties[DIST_PROP] = g_param_spec_float("distance", "Distance", "distance to origin", -G_MAXFLOAT, G_MAXFLOAT, 0.f, G_PARAM_READWRITE); /** * VisuPlane::n-vector: * * Normal vector (not necessary unitary). * * Since: 3.8 */ properties[VECT_PROP] = g_param_spec_boxed("n-vector", "NormalVector", "normal vector", TOOL_TYPE_VECTOR, G_PARAM_READWRITE); /** * VisuPlane::color: * * Rendering colour. * * Since: 3.8 */ properties[COLOR_PROP] = g_param_spec_boxed("color", "Color", "rendering color", TOOL_TYPE_COLOR, G_PARAM_READWRITE); /** * VisuPlane::hidding-side: * * If the plane is masking nodes or surfaces... And on which side. * * Since: 3.8 */ properties[HIDDING_PROP] = g_param_spec_int("hidding-side", "HiddingSide", "hidding property", VISU_PLANE_SIDE_MINUS, VISU_PLANE_SIDE_PLUS, VISU_PLANE_SIDE_NONE, G_PARAM_READWRITE); /** * VisuPlane::rendered: * * If the plane is drawn. * * Since: 3.8 */ properties[RENDERED_PROP] = g_param_spec_boolean("rendered", "Rendered", "rendering property", TRUE, G_PARAM_READWRITE); /** * VisuPlane::opacity: * * The opacity the plane is drawn with. * * Since: 3.8 */ properties[OPACITY_PROP] = g_param_spec_float("opacity", "Opacity", "opacity property", 0.f, 1.f, 1.f, G_PARAM_READWRITE); g_object_class_install_properties(G_OBJECT_CLASS(klass), N_PROP, properties); g_object_class_override_property(G_OBJECT_CLASS(klass), ADJUST_PROP, "auto-adjust"); g_object_class_override_property(G_OBJECT_CLASS(klass), BOX_PROP, "box"); } static void visu_boxed_interface_init(VisuBoxedInterface *iface) { iface->get_box = visu_plane_getBox; iface->set_box = visu_plane_setBox; } static void visu_animatable_interface_init(VisuAnimatableInterface *iface) { iface->get_animation = _getAnimation; } static void visu_plane_init(VisuPlane *obj) { obj->dispose_has_run = FALSE; DBG_fprintf(stderr, "Visu Plane : creating a new plane (%p).\n", (gpointer)obj); obj->inter = (GList*)0; obj->hiddenSide = VISU_PLANE_SIDE_NONE; obj->nVectUser[0] = 0.; obj->nVectUser[1] = 0.; obj->nVectUser[2] = 0.; obj->dist = 0.; obj->color = (ToolColor*)0; obj->box = (VisuBox*)0; obj->size_signal = 0; obj->opacity = 1.f; obj->opacity_anim = visu_animation_new(G_OBJECT(obj), "opacity"); } /* This method can be called several times. It should unref all of its reference to GObjects. */ static void visu_plane_dispose(GObject* obj) { DBG_fprintf(stderr, "Visu Plane : dispose object %p.\n", (gpointer)obj); if (VISU_PLANE(obj)->dispose_has_run) return; visu_plane_setBox(VISU_BOXED(obj), (VisuBox*)0); g_object_unref(VISU_PLANE(obj)->opacity_anim); VISU_PLANE(obj)->dispose_has_run = TRUE; /* Chain up to the parent class */ G_OBJECT_CLASS(visu_plane_parent_class)->dispose(obj); } /* This method is called once only. */ static void visu_plane_finalize(GObject* obj) { GList *tmpLst; g_return_if_fail(obj); DBG_fprintf(stderr, "Visu Plane : finalize object %p.\n", (gpointer)obj); /* Deleting the intersection nodes if any. */ tmpLst = VISU_PLANE(obj)->inter; while (tmpLst) { g_free(tmpLst->data); tmpLst = g_list_next(tmpLst); } if (VISU_PLANE(obj)->color) g_boxed_free(TOOL_TYPE_COLOR, VISU_PLANE(obj)->color); /* Chain up to the parent class */ G_OBJECT_CLASS(visu_plane_parent_class)->finalize(obj); } static void visu_plane_get_property(GObject* obj, guint property_id, GValue *value, GParamSpec *pspec) { VisuPlane *self = VISU_PLANE(obj); gfloat opacity; DBG_fprintf(stderr, "Visu Plane: get property '%s' -> ", g_param_spec_get_name(pspec)); switch (property_id) { case BOX_PROP: g_value_set_object(value, self->box); DBG_fprintf(stderr, "%p.\n", (gpointer)self->box); break; case DIST_PROP: g_value_set_float(value, self->dist); DBG_fprintf(stderr, "%g.\n", self->dist); break; case VECT_PROP: g_value_set_static_boxed(value, (gconstpointer)self->nVectUser); DBG_fprintf(stderr, "%g,%g,%g.\n", self->nVectUser[0], self->nVectUser[1], self->nVectUser[2]); break; case COLOR_PROP: g_value_set_static_boxed(value, visu_plane_getColor(self)); DBG_fprintf(stderr, "%g,%g,%g.\n", self->color->rgba[0], self->color->rgba[1], self->color->rgba[2]); break; case HIDDING_PROP: g_value_set_int(value, self->hiddenSide); DBG_fprintf(stderr, "%d.\n", self->hiddenSide); break; case RENDERED_PROP: g_object_get(self, "opacity", &opacity, NULL); g_value_set_boolean(value, opacity > 0.f); DBG_fprintf(stderr, "%d.\n", g_value_get_boolean(value)); break; case OPACITY_PROP: if (visu_animation_isRunning(self->opacity_anim)) visu_animation_getTo(self->opacity_anim, value); else g_value_set_float(value, self->opacity); DBG_fprintf(stderr, "%g.\n", self->opacity); break; case ADJUST_PROP: g_value_set_boolean(value, FALSE); break; default: /* We don't have any other property... */ G_OBJECT_WARN_INVALID_PROPERTY_ID(obj, property_id, pspec); break; } } static void visu_plane_set_property(GObject* obj, guint property_id, const GValue *value, GParamSpec *pspec) { VisuPlane *self = VISU_PLANE(obj); DBG_fprintf(stderr, "Visu Plane: set property '%s' -> ", g_param_spec_get_name(pspec)); switch (property_id) { case BOX_PROP: DBG_fprintf(stderr, "%p.\n", g_value_get_object(value)); visu_plane_setBox(VISU_BOXED(obj), VISU_BOX(g_value_get_object(value))); break; case DIST_PROP: visu_plane_setDistanceFromOrigin(self, g_value_get_float(value)); DBG_fprintf(stderr, "%g.\n", self->dist); break; case VECT_PROP: visu_plane_setNormalVector(self, (float*)g_value_get_boxed(value)); DBG_fprintf(stderr, "%g,%g,%g.\n", self->nVectUser[0], self->nVectUser[1], self->nVectUser[2]); break; case COLOR_PROP: visu_plane_setColor(self, (ToolColor*)g_value_get_boxed(value)); DBG_fprintf(stderr, "%g,%g,%g (%p).\n", ((ToolColor*)g_value_get_boxed(value))->rgba[0], ((ToolColor*)g_value_get_boxed(value))->rgba[1], ((ToolColor*)g_value_get_boxed(value))->rgba[2], (gpointer)self->color); break; case HIDDING_PROP: visu_plane_setHiddenState(self, g_value_get_int(value)); DBG_fprintf(stderr, "%d.\n", self->hiddenSide); break; case RENDERED_PROP: DBG_fprintf(stderr, "%d.\n", g_value_get_boolean(value)); if (!visu_animatable_animateFloat(VISU_ANIMATABLE(self), self->opacity_anim, g_value_get_boolean(value) ? 1.f : 0.f, 100, FALSE, VISU_ANIMATION_QUAD)) visu_plane_setRendered(self, g_value_get_boolean(value)); break; case ADJUST_PROP: DBG_fprintf(stderr, "%d.\n", FALSE); break; case OPACITY_PROP: if (!visu_animatable_animateFloat(VISU_ANIMATABLE(self), self->opacity_anim, g_value_get_float(value), 100, FALSE, VISU_ANIMATION_QUAD)) visu_plane_setOpacity(self, g_value_get_float(value)); break; default: /* We don't have any other property... */ G_OBJECT_WARN_INVALID_PROPERTY_ID(obj, property_id, pspec); break; } } /** * visu_plane_newUndefined: * * Create a new plane with default values. This plane can't be * rendered directly and one needs to computes its intersection with * the bounding box before using planeComputeInter(). * * Returns: (transfer full): a newly allocated #VisuPlane structure. */ VisuPlane* visu_plane_newUndefined(void) { return g_object_new(VISU_TYPE_PLANE, NULL); } /** * visu_plane_new: * @box: (transfer full) (allow-none): a box description ; * @vect: (array fixed-size=3): three values defining the normal * vector (unitary or not) ; * @dist: the distance between origin and intersection of the plane and the * line made by origin and normal vector ; * @color: a #ToolColor. * * Create a plane with the specified attributes. * * Returns: a newly allocated #VisuPlane structure. */ VisuPlane* visu_plane_new(VisuBox *box, float vect[3], float dist, const ToolColor *color) { VisuPlane *plane; g_return_val_if_fail(color, (VisuPlane*)0); /* Create the object with defaulty values. */ plane = VISU_PLANE(g_object_new(VISU_TYPE_PLANE, NULL)); g_return_val_if_fail(plane, (VisuPlane*)0); visu_plane_setNormalVector(plane, vect); visu_plane_setDistanceFromOrigin(plane, dist); visu_plane_setBox(VISU_BOXED(plane), box); visu_plane_setColor(plane, color); return plane; } /** * visu_plane_setNormalVector: * @plane: a #VisuPlane object ; * @vect: (array fixed-size=3): three values defining the normal * vector (unitary or not). * * Change the normal vector defining the orientation of the plane. * * Returns: 1 if the intersections should be recalculated by * a call to planeComputeInter(), 0 if not. Or -1 if there is * an error. */ gboolean visu_plane_setNormalVector(VisuPlane *plane, float vect[3]) { int i; float norm; g_return_val_if_fail(VISU_IS_PLANE(plane), FALSE); if (vect[0] == plane->nVectUser[0] && vect[1] == plane->nVectUser[1] && vect[2] == plane->nVectUser[2]) return FALSE; g_return_val_if_fail(vect[0] * vect[0] + vect[1] * vect[1] + vect[2] * vect[2] != 0., FALSE); norm = 0.; for (i = 0; i < 3; i++) { norm += vect[i] * vect[i]; plane->nVect[i] = vect[i]; plane->nVectUser[i] = vect[i]; } norm = sqrt(norm); for (i = 0; i < 3; i++) plane->nVect[i] /= norm; DBG_fprintf(stderr, "Visu Plane : set normal vector (%f,%f,%f) for plane %p.\n", plane->nVect[0], plane->nVect[1], plane->nVect[2], (gpointer)plane); DBG_fprintf(stderr, "Visu Plane : set user vector (%f,%f,%f) for plane %p.\n", plane->nVectUser[0], plane->nVectUser[1], plane->nVectUser[2], (gpointer)plane); g_object_notify_by_pspec(G_OBJECT(plane), properties[VECT_PROP]); if (!plane->box) return TRUE; /* We recompute the intersection. */ computeInter(plane); return TRUE; } gboolean visu_plane_setDistanceFromOrigin(VisuPlane *plane, float dist) { g_return_val_if_fail(VISU_IS_PLANE(plane), FALSE); if (plane->dist == dist) return FALSE; plane->dist = dist; DBG_fprintf(stderr, "Visu Plane : set distance from origin %f for plane %p.\n", dist, (gpointer)plane); g_object_notify_by_pspec(G_OBJECT(plane), properties[DIST_PROP]); if (!plane->box) return TRUE; /* We recompute the intersection. */ computeInter(plane); return TRUE; } /** * visu_plane_setOrigin: * @plane: a #VisuPlane object. * @origin: (array fixed-size=3): some cartesian coordinates. * * Defines a point belonging to @plane instead of defining distance of * @plane to the box origin. * * Since: 3.8 * * Returns: TRUE if origin is actually changed. **/ gboolean visu_plane_setOrigin(VisuPlane *plane, const float origin[3]) { float dist; g_return_val_if_fail(VISU_IS_PLANE(plane), FALSE); if (plane->nVect[0] == 0.f && plane->nVect[1] == 0.f && plane->nVect[2] == 0.f) return FALSE; dist = plane->nVect[0] * origin[0] + plane->nVect[1] * origin[1] + plane->nVect[2] * origin[2]; return visu_plane_setDistanceFromOrigin(plane, dist); } static gboolean visu_plane_setBox(VisuBoxed *self, VisuBox *box) { VisuPlane *plane; g_return_val_if_fail(VISU_IS_PLANE(self), FALSE); plane = VISU_PLANE(self); DBG_fprintf(stderr, "Visu Plane: set box %p.\n", (gpointer)box); if (plane->box == box) return FALSE; if (plane->box) { g_signal_handler_disconnect(G_OBJECT(plane->box), plane->size_signal); g_object_unref(plane->box); } plane->box = box; if (!box) return TRUE; g_object_ref(box); plane->size_signal = g_signal_connect(G_OBJECT(box), "SizeChanged", G_CALLBACK(onBoxSizeChanged), (gpointer)plane); computeInter(plane); return TRUE; } static VisuBox* visu_plane_getBox(VisuBoxed *self) { g_return_val_if_fail(VISU_IS_PLANE(self), (VisuBox*)0); return VISU_PLANE(self)->box; } /** * visu_plane_setColor: * @plane: a #VisuPlane object ; * @color: a #ToolColor. * * Change the color of the plane. * * Returns: TRUE if color changed. */ gboolean visu_plane_setColor(VisuPlane *plane, const ToolColor *color) { g_return_val_if_fail(VISU_IS_PLANE(plane), FALSE); if (tool_color_equal(color, plane->color)) return FALSE; DBG_fprintf(stderr, "Visu Plane: changed color (%p) for plane : %p.\n", (gpointer)color, (gpointer)plane); plane->color = g_boxed_copy(TOOL_TYPE_COLOR, color); g_object_notify_by_pspec(G_OBJECT(plane), properties[COLOR_PROP]); g_signal_emit(G_OBJECT(plane), plane_signals[VISU_PLANE_RENDERING_SIGNAL], 0, NULL); return TRUE; } /** * visu_plane_getOpacity: * @plane: a #VisuPlane object. * * Retrieves the plane opacity. * * Since: 3.8 * * Returns: a float within [0;1]. **/ gfloat visu_plane_getOpacity(const VisuPlane *plane) { g_return_val_if_fail(VISU_IS_PLANE(plane), 1.f); return plane->opacity; } /** * visu_plane_setOpacity: * @plane: a #VisuPlane object. * @opacity: a float in [0;1]. * * Defines the plane opacity. Planes can be coloured with alpha * channel colours. The opacity is an additional parameter that can be * used to animate plane apparition for instance. * * Since: 3.8 * * Returns: TRUE if value is actually changed. **/ gboolean visu_plane_setOpacity(VisuPlane *plane, gfloat opacity) { gboolean renderedChanged; g_return_val_if_fail(VISU_IS_PLANE(plane), FALSE); opacity = CLAMP(opacity, 0.f, 1.f); if (opacity == plane->opacity) return FALSE; renderedChanged = (plane->opacity == 0.f && opacity > 0.f) || (plane->opacity > 0.f && opacity == 0.f); plane->opacity = opacity; g_object_notify_by_pspec(G_OBJECT(plane), properties[OPACITY_PROP]); if (renderedChanged) g_object_notify_by_pspec(G_OBJECT(plane), properties[RENDERED_PROP]); g_signal_emit(G_OBJECT(plane), plane_signals[VISU_PLANE_RENDERING_SIGNAL], 0, NULL); return TRUE; } /** * visu_plane_setRendered: * @plane: a #VisuPlane ; * @rendered: TRUE to make the plane drawable. * * Change the visibility of the plane. * * Returns: TRUE if the visibility is actually changed. */ gboolean visu_plane_setRendered(VisuPlane *plane, gboolean rendered) { g_return_val_if_fail(VISU_IS_PLANE(plane), FALSE); if (visu_animation_isRunning(plane->opacity_anim)) visu_animation_abort(plane->opacity_anim); else if (rendered == (plane->opacity > 0.f)) return FALSE; DBG_fprintf(stderr, "Visu Plane: change plane visibility to %d.\n", rendered); return visu_plane_setOpacity(plane, rendered ? 1.f : 0.f); } /** * visu_plane_getRendered: * @plane: a #VisuPlane. * * Get the visibility of a plane. * * Returns: TRUE if the plane is visible. */ gboolean visu_plane_getRendered(const VisuPlane *plane) { g_return_val_if_fail(VISU_IS_PLANE(plane), FALSE); return (plane->opacity > 0.f); } /** * visu_plane_getIntersection: * @plane: a #VisuPlane. * * The list of intersection between the plane and the box is made of * float[3]. The planeComputeInter() should have been called before. * * Returns: (transfer none) (element-type ToolVector): a list of float[3] * elements. This list is owned by V_Sim. */ GList* visu_plane_getIntersection(const VisuPlane *plane) { g_return_val_if_fail(VISU_IS_PLANE(plane) && plane->box, (GList*)0); return plane->inter; } /** * visu_plane_getBasis: * @plane: a #VisuPlane ; * @xyz: two vectors. * @center: a point in cartesian coordinates. * * Stores the coordinates of barycentre of the plane in @center and * provide coordinates of two orthogonal vector in the plane. The planeComputeInter() * should have been called before. */ void visu_plane_getBasis(const VisuPlane *plane, float xyz[2][3], float center[3]) { float spherical[3]; g_return_if_fail(VISU_IS_PLANE(plane)); tool_matrix_cartesianToSpherical(spherical, plane->nVectUser); xyz[0][0] = cos(spherical[1] * TOOL_PI180) * cos(spherical[2] * TOOL_PI180); xyz[0][1] = cos(spherical[1] * TOOL_PI180) * sin(spherical[2] * TOOL_PI180); xyz[0][2] = -sin(spherical[1] * TOOL_PI180); xyz[1][0] = -sin(spherical[2] * TOOL_PI180); xyz[1][1] = cos(spherical[2] * TOOL_PI180); xyz[1][2] = 0.; center[0] = plane->pointG[0]; center[1] = plane->pointG[1]; center[2] = plane->pointG[2]; } /** * visu_plane_getReducedIntersection: * @plane: a #VisuPlane object. * @nVals: a location for an integer. * * This routine returns the coordinates in the @plane basis set of its * intersections with a box (see visu_boxed_setBox()). The coordinates are * appended in the return array which length is stored in @nVals. * * Since: 3.6 * * Returns: a newly allocated array of @nVals * 2 values. Free it with * g_free(). */ float* visu_plane_getReducedIntersection(const VisuPlane *plane, guint *nVals) { float *out, basis[2][3], center[3], *xyz; GList *tmpLst; gint i; g_return_val_if_fail(VISU_IS_PLANE(plane) && plane->box, (float*)0); g_return_val_if_fail(nVals, (float*)0); if (!plane->inter) return (float*)0; visu_plane_getBasis(plane, basis, center); i = 0; out = g_malloc(sizeof(float) * g_list_length(plane->inter) * 2); for (tmpLst = plane->inter; tmpLst; tmpLst = g_list_next(tmpLst)) { xyz = (float*)tmpLst->data; out[i * 2 + 0] = basis[0][0] * (xyz[0] - center[0]) + basis[0][1] * (xyz[1] - center[1]) + basis[0][2] * (xyz[2] - center[2]); out[i * 2 + 1] = basis[1][0] * (xyz[0] - center[0]) + basis[1][1] * (xyz[1] - center[1]) + basis[1][2] * (xyz[2] - center[2]); i += 1; } *nVals = i; return out; } /** * visu_plane_getLineIntersection: * @plane: a #VisuPlane object. * @A: (array fixed-size=3): coordinates of point A. * @B: (array fixed-size=3): coordinates of point B. * @lambda: (out caller-allocates) (allow-none): a location to store * the intersecting factor. * * If there is an intersection M between line (AB) and @plane, then this * function calculates M coordinates as M = A + lambda * AB. * * Since: 3.6 * * Returns: TRUE if there is an intersection between line (AB) and the plane. **/ gboolean visu_plane_getLineIntersection(const VisuPlane *plane, const float A[3], const float B[3], float *lambda) { float denom, lambda_; g_return_val_if_fail(VISU_IS_PLANE(plane), FALSE); /* The plane is defined by n1x+n2y+n3z-d=0 with (n1,n2,n3) the normal vector (unitary) and d the algebric distance from the origin. A segment {P} of the box is defined by P=A+lambda.l with A a vertex, l a vector in the direction of the segment and lambda a real. If it exists a lambda that can solve P(lambda) in the plane equation, and this lambda is in [0;1] then this is the intersection. */ lambda_ = plane->dist; lambda_ -= plane->nVect[0] * A[0]; lambda_ -= plane->nVect[1] * A[1]; lambda_ -= plane->nVect[2] * A[2]; denom = plane->nVect[0] * (B[0] - A[0]); denom += plane->nVect[1] * (B[1] - A[1]); denom += plane->nVect[2] * (B[2] - A[2]); if (denom == 0.) { /* if A is in the plane, we put lambda to 0. */ if (lambda_ == 0.f) denom = 1.f; else return FALSE; } lambda_ /= denom; if (lambda) *lambda = lambda_; return TRUE; } static void computeInter(VisuPlane* plane) { float lambda; int a[12] = {0, 1, 2, 3, 0, 1, 2, 3, 4, 5, 6, 7}; int b[12] = {1, 2, 3, 0, 4, 5, 6, 7, 5, 6, 7, 4}; int i, j, n; float *inter; GList *tmpLst; float vertices[8][3]; g_return_if_fail(VISU_IS_PLANE(plane) && plane->box); /* RAZ old intersection list. */ if (plane->inter) { tmpLst = plane->inter; while(tmpLst) { g_free((float*)tmpLst->data); tmpLst = g_list_next(tmpLst); } g_list_free(plane->inter); plane->inter = (GList*)0; } /* Compute, vector and position for the box. */ n = 0; plane->pointG[0] = 0.; plane->pointG[1] = 0.; plane->pointG[2] = 0.; visu_box_getVertices(plane->box, vertices, TRUE); for (i = 0; i < 12; i++) if (visu_plane_getLineIntersection(plane, vertices[a[i]], vertices[b[i]], &lambda) && lambda >= 0. && lambda <= 1.) { inter = g_malloc(sizeof(float) * 3); for (j = 0; j < 3; j++) { inter[j] = vertices[a[i]][j] + lambda * (vertices[b[i]][j] - vertices[a[i]][j]); plane->pointG[j] += inter[j]; } n += 1; plane->inter = g_list_append(plane->inter, (gpointer)inter); DBG_fprintf(stderr, "Visu Plane: a new intersection (%f,%f,%f) for plane %p.\n", inter[0], inter[1], inter[2], (gpointer)plane); } if (n > 0) { for (i = 0; i < 3; i++) plane->pointG[i] /= (float)n; plane->inter = g_list_sort_with_data(plane->inter, comparePolygonPoint, (gpointer)plane); } DBG_fprintf(stderr, "Visu Plane: emit 'plane moved' signal.\n"); g_signal_emit(G_OBJECT(plane), plane_signals[VISU_PLANE_MOVED_SIGNAL], 0, NULL); } /** * visu_plane_getPlaneIntersection: * @plane1: a #VisuPlane object. * @plane2: another #VisuPlane object. * @A: (out) (array fixed-size=3): the coordinates of the first point * of intersection. * @B: (out) (array fixed-size=3): the coordinates of the second point * of intersection. * * Calculates the intersection between @plane1 and @plane2, if it * exists. The intersection is returned in @A and @B as the * coordinates of the two points on the border of @plane1 that * intersect @plane2. * * Since: 3.7 * * Returns: TRUE if there is an intersection between @plane1 and @plane2. **/ gboolean visu_plane_getPlaneIntersection(const VisuPlane *plane1, const VisuPlane *plane2, float A[3], float B[3]) { float lambda, *I, *J; GList *inter; guint n; float M[8][3]; n = 0; for (inter = plane1->inter; inter; inter = g_list_next(inter)) { g_return_val_if_fail(n < 8, FALSE); I = (float*)inter->data; J = (inter->next)?(float*)inter->next->data:(float*)plane1->inter->data; if (visu_plane_getLineIntersection(plane2, I, J, &lambda) && lambda >= 0.f && lambda <= 1.f) { M[n][0] = I[0] + lambda * (J[0] - I[0]); M[n][1] = I[1] + lambda * (J[1] - I[1]); M[n][2] = I[2] + lambda * (J[2] - I[2]); n += 1; } } if (n != 2) return FALSE; A[0] = M[0][0]; A[1] = M[0][1]; A[2] = M[0][2]; B[0] = M[1][0]; B[1] = M[1][1]; B[2] = M[1][2]; fprintf(stderr, "%g %g %g | %g %g %g\n", A[0], A[1], A[2], B[0], B[1], B[2]); return TRUE; } static int comparePolygonPoint(gconstpointer pointA, gconstpointer pointB, gpointer data) { VisuPlane *plane; float vectGA[3], vectGB[3]; int i; float det; plane = (VisuPlane*)data; for (i = 0; i < 3; i++) { vectGA[i] = ((float*)pointA)[i] - plane->pointG[i]; vectGB[i] = ((float*)pointB)[i] - plane->pointG[i]; } det = vectGA[0] * vectGB[1] * plane->nVect[2] + vectGB[0] * plane->nVect[1] * vectGA[2] + plane->nVect[0] * vectGA[1] * vectGB[2] - vectGA[2] * vectGB[1] * plane->nVect[0] - vectGA[1] * vectGB[0] * plane->nVect[2] - vectGA[0] * vectGB[2] * plane->nVect[1]; if (det < 0.) return -1; else if (det > 0.) return 1; else return 0; } void visu_plane_getNVectUser(const VisuPlane *plane, float vect[3]) { g_return_if_fail(VISU_IS_PLANE(plane)); vect[0] = plane->nVectUser[0]; vect[1] = plane->nVectUser[1]; vect[2] = plane->nVectUser[2]; } void visu_plane_getNVect(const VisuPlane *plane, float vect[3]) { g_return_if_fail(VISU_IS_PLANE(plane)); vect[0] = plane->nVect[0]; vect[1] = plane->nVect[1]; vect[2] = plane->nVect[2]; } /** * visu_plane_getColor: * @plane: a #VisuPlane ; * * Stores the color of the plane. * * Returns: (transfer none): a #ToolColor. */ const ToolColor* visu_plane_getColor(VisuPlane *plane) { static guint id = 0; g_return_val_if_fail(VISU_IS_PLANE(plane), (ToolColor*)0); if (!plane->color) visu_plane_setColor(plane, tool_color_new_bright(id++)); return plane->color; } /** * visu_plane_getDistanceFromOrigin: * @plane: a #VisuPlane ; * * Stores the distance of the plane to the origin. * * Returns: a float value. */ gfloat visu_plane_getDistanceFromOrigin(const VisuPlane *plane) { g_return_val_if_fail(VISU_IS_PLANE(plane), 0.f); return plane->dist; } /** * visu_plane_setHiddenState: * @plane: a #VisuPlane ; * @side: a key, #VISU_PLANE_SIDE_NONE, #VISU_PLANE_SIDE_PLUS or #VISU_PLANE_SIDE_MINUS. * * The plane can hide the nodes on one of its side. * The @side argument can be VISU_PLANE_SIDE_PLUS or VISU_PLANE_SIDE_MINUS or * VISU_PLANE_SIDE_NONE. It codes the side of the plane which hides the nodes. * If VISU_PLANE_SIDE_NONE is selected all nodes are rendered. * * Returns: TRUE if the hidding side was actually changed. */ gboolean visu_plane_setHiddenState(VisuPlane *plane, int side) { g_return_val_if_fail(VISU_IS_PLANE(plane), FALSE); g_return_val_if_fail(side == VISU_PLANE_SIDE_NONE || side == VISU_PLANE_SIDE_PLUS || side == VISU_PLANE_SIDE_MINUS, FALSE); DBG_fprintf(stderr, "Visu Plane : hide state (%d, old %d) for plane %p.\n", side, plane->hiddenSide, (gpointer)plane); if (plane->hiddenSide == side) return FALSE; plane->hiddenSide = side; g_object_notify_by_pspec(G_OBJECT(plane), properties[HIDDING_PROP]); return TRUE; } int visu_plane_getHiddenState(const VisuPlane *plane) { g_return_val_if_fail(VISU_IS_PLANE(plane), 0); return plane->hiddenSide; } /** * visu_plane_getVisibility: * @plane: a #VisuPlane object. * @point: (array fixed-size=3): some coordinates. * * Test the visibility of a given point with respect to the plane attributes. * * Since: 3.8 * * Returns: TRUE if the given point is not masked by the @plane. **/ gboolean visu_plane_getVisibility(const VisuPlane *plane, float point[3]) { float pScal; g_return_val_if_fail(VISU_IS_PLANE(plane), TRUE); pScal = plane->nVect[0] * point[0] + plane->nVect[1] * point[1] + plane->nVect[2] * point[2] - plane->dist; /* DBG_fprintf(stderr, "Visu plane: test point %g %g %g -> %d\n", point[0], point[1], point[2], */ /* (pScal * plane->hiddenSide >= 0.)); */ return (pScal * plane->hiddenSide >= 0.); } static void onBoxSizeChanged(VisuBox *box _U_, float extens _U_, gpointer data) { computeInter(VISU_PLANE(data)); } static VisuAnimation* _getAnimation(const VisuAnimatable *self, const gchar *prop) { VisuPlane *plane = VISU_PLANE(self); if (!strcmp(prop, "opacity")) return plane->opacity_anim; return (VisuAnimation*)0; } static gint comparisonForSortingFloats(gconstpointer a, gconstpointer b, gpointer user_data _U_) { float c; c = *((float*)b) - *((float*)a); if (c < 0.f) return (gint)(1); else if (c > 0.f) return (gint)(-1); else return (gint)(0); } static gint comparisonForHavingIndices(gconstpointer a, gconstpointer b, gpointer user_data) { float c; float *array; array = (float*)user_data; /*DBG_fprintf(stderr, "INDICES : a %d b %d\n", *((int*)a), *((int*)b));*/ c = array[*(int*)b] - array[*(int*)a]; /*DBG_fprintf(stderr, "LAMBDA b (%f) - LAMBDA a (%f) : %f\n", vb, va,c);*/ if (c < 0.f) return (gint)(1); else if (c > 0.f) return (gint)(-1); else return (gint)(0); } gboolean visu_plane_class_getOrderedIntersections(int nVisuPlanes, VisuPlane **listOfVisuPlanes, float pointA[3], float pointB[3], float *inter, int *index) { float *lambda; int *indices; int i; lambda = g_malloc(sizeof(float) * nVisuPlanes); indices = g_malloc(sizeof(int) * nVisuPlanes); for (i = 0; listOfVisuPlanes[i]; i++) { indices[i] = i; if (!visu_plane_getLineIntersection(listOfVisuPlanes[i], pointA, pointB, lambda + i) || lambda[i] < 0. || lambda[i] > 1.) /* If lambda is not between 0 and 1, this means that the plane i is not intersected by the AB segment => return FALSE */ return FALSE; } /* Sort lambda */ DBG_fprintf(stderr, "Sorting planes by lambda :\n ... lambda unsorted : "); for (i = 0; i < nVisuPlanes; i++) DBG_fprintf(stderr, "%f ", lambda[i]); DBG_fprintf(stderr, "\n"); g_qsort_with_data(indices, nVisuPlanes, sizeof(int), comparisonForHavingIndices, (float*)lambda); g_qsort_with_data(lambda, nVisuPlanes, sizeof(float), comparisonForSortingFloats, NULL); DBG_fprintf(stderr, " ... lambda sorted : "); for (i = 0; i < nVisuPlanes; i++) DBG_fprintf(stderr, "%f ", lambda[i]); DBG_fprintf(stderr, "\n ... indices : "); for (i = 0; i < nVisuPlanes; i++) DBG_fprintf(stderr, "%d ", indices[i]); DBG_fprintf(stderr, "\n"); /* Put the intersections in inter in the right order. */ DBG_fprintf(stderr, " ... intersections sorted :\n"); for (i = 0; i < nVisuPlanes; i++) { *(inter + 3*i) = pointA[0] + lambda[i] * (pointB[0] - pointA[0]); *(inter + 3*i + 1) = pointA[1] + lambda[i] * (pointB[1] - pointA[1]); *(inter + 3*i + 2) = pointA[2] + lambda[i] * (pointB[2] - pointA[2]); DBG_fprintf(stderr, " %f %f %f\n", *(inter + 3*i), *(inter + 3*i + 1), *(inter + 3*i + 2)); *(index + i) = indices[i]; } g_free(lambda); g_free(indices); return TRUE; } v_sim-3.8.0/src/extraFunctions/plane.h000066400000000000000000000173101370110300500177020ustar00rootroot00000000000000/* EXTRAITS DE LA LICENCE Copyright CEA, contributeurs : Luc BILLARD et Damien CALISTE, laboratoire L_Sim, (2001-2005) Adresse mèl : BILLARD, non joignable par mèl ; CALISTE, damien P caliste AT cea P fr. Ce logiciel est un programme informatique servant à visualiser des structures atomiques dans un rendu pseudo-3D. Ce logiciel est régi par la licence CeCILL soumise au droit français et respectant les principes de diffusion des logiciels libres. Vous pouvez utiliser, modifier et/ou redistribuer ce programme sous les conditions de la licence CeCILL telle que diffusée par le CEA, le CNRS et l'INRIA sur le site "http://www.cecill.info". Le fait que vous puissiez accéder à cet en-tête signifie que vous avez pris connaissance de la licence CeCILL, et que vous en avez accepté les termes (cf. le fichier Documentation/licence.fr.txt fourni avec ce logiciel). */ /* LICENCE SUM UP Copyright CEA, contributors : Luc BILLARD et Damien CALISTE, laboratoire L_Sim, (2001-2005) E-mail address: BILLARD, not reachable any more ; CALISTE, damien P caliste AT cea P fr. This software is a computer program whose purpose is to visualize atomic configurations in 3D. This software is governed by the CeCILL license under French law and abiding by the rules of distribution of free software. You can use, modify and/ or redistribute the software under the terms of the CeCILL license as circulated by CEA, CNRS and INRIA at the following URL "http://www.cecill.info". The fact that you are presently reading this means that you have had knowledge of the CeCILL license and that you accept its terms. You can find a copy of this licence shipped with this software at Documentation/licence.en.txt. */ #ifndef VISU_PLANE_H #define VISU_PLANE_H #include #include #include G_BEGIN_DECLS /** * VISU_TYPE_PLANE: * * return the type of #VisuPlane. */ #define VISU_TYPE_PLANE (visu_plane_get_type ()) /** * VISU_PLANE: * @obj: a #GObject to cast. * * Cast the given @obj into #VisuPlane type. */ #define VISU_PLANE(obj) (G_TYPE_CHECK_INSTANCE_CAST(obj, VISU_TYPE_PLANE, VisuPlane)) /** * VISU_PLANE_CLASS: * @klass: a #GObjectClass to cast. * * Cast the given @klass into #VisuPlaneClass. */ #define VISU_PLANE_CLASS(klass) (G_TYPE_CHECK_CLASS_CAST(klass, VISU_TYPE_PLANE, VisuPlaneClass)) /** * VISU_IS_PLANE: * @obj: a #GObject to test. * * Test if the given @ogj is of the type of #VisuPlane object. */ #define VISU_IS_PLANE(obj) (G_TYPE_CHECK_INSTANCE_TYPE(obj, VISU_TYPE_PLANE)) /** * VISU_IS_PLANE_CLASS: * @klass: a #GObjectClass to test. * * Test if the given @klass is of the type of #VisuPlaneClass class. */ #define VISU_IS_PLANE_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE(klass, VISU_TYPE_PLANE)) /** * VISU_PLANE_GET_CLASS: * @obj: a #GObject to get the class of. * * It returns the class of the given @obj. */ #define VISU_PLANE_GET_CLASS(obj) (G_TYPE_INSTANCE_GET_CLASS(obj, VISU_TYPE_PLANE, VisuPlaneClass)) typedef struct _VisuPlaneClass VisuPlaneClass; typedef struct _VisuPlane VisuPlane; GType visu_plane_get_type(void); /** * VisuPlane: * * All fields are private, use the access routines. */ /** * VisuPlaneClass: * @parent: the parent. * * An opaque structure. */ struct _VisuPlaneClass { VisuObjectClass parent; }; /** * VISU_PLANE_SIDE_PLUS * * This is a key that defines which side is hidden by the plane. For * this value, the side is the one pointed by the normal vector. */ #define VISU_PLANE_SIDE_PLUS +1 /** * VISU_PLANE_SIDE_MINUS * * This is a key that defines which side is hidden by the plane. For * this value, the side is the one at the opposite of the one pointed * by the normal vector. */ #define VISU_PLANE_SIDE_MINUS -1 /** * VISU_PLANE_SIDE_NONE * * This is a key that defines which side is hidden by the plane. For * this value, no node is hidden. */ #define VISU_PLANE_SIDE_NONE 0 VisuPlane* visu_plane_new(VisuBox *box, float vect[3], float dist, const ToolColor *color); VisuPlane* visu_plane_newUndefined(void); gboolean visu_plane_setNormalVector(VisuPlane *plane, float vect[3]); /** * visu_plane_setDistanceFromOrigin: * @plane: a #VisuPlane object ; * @dist: the distance between origin and intersection of the plane and the * line made by origin and normal vector. * * Change the position of the plane. * * Returns: 1 if the intersections should be recalculated by * a call to planeComputeInter(), 0 if not. Or -1 if there is * an error. */ gboolean visu_plane_setDistanceFromOrigin(VisuPlane *plane, float dist); gboolean visu_plane_setOrigin(VisuPlane *plane, const float origin[3]); gboolean visu_plane_setColor(VisuPlane *plane, const ToolColor *color); void visu_plane_getBasis(const VisuPlane *plane, float xyz[2][3], float center[3]); GList* visu_plane_getIntersection(const VisuPlane *plane); float* visu_plane_getReducedIntersection(const VisuPlane *plane, guint *nVals); /** * visu_plane_getNVectUser: * @plane: a #VisuPlane. * @vect: an already alloacted (size 3) float array. * * Stores the coordinates of the normal vector in @vec of the plane. It returns the values * given by the user, not the normalized vaues. */ void visu_plane_getNVectUser(const VisuPlane *plane, float *vect); /** * visu_plane_getNVect: * @plane: a #VisuPlane. * @vect: an already alloacted (size 3) float array. * * Stores the coordinates of the normal vector in @vect of the plane. * It returns the normalized values. */ void visu_plane_getNVect(const VisuPlane *plane, float *vect); gfloat visu_plane_getDistanceFromOrigin(const VisuPlane *plane); gboolean visu_plane_getLineIntersection(const VisuPlane *plane, const float A[3], const float B[3], float *lambda); gboolean visu_plane_getPlaneIntersection(const VisuPlane *plane1, const VisuPlane *plane2, float A[3], float B[3]); const ToolColor* visu_plane_getColor(VisuPlane *plane); gboolean visu_plane_setHiddenState(VisuPlane *plane, int side); /** * visu_plane_getHiddenState: * @plane: a #VisuPlane. * * The plane can hide the nodes on one of its side. this * method get the status for the given @plane. * * Returns: the state, defined by VISU_PLANE_SIDE_PLUS or VISU_PLANE_SIDE_MINUS or * VISU_PLANE_SIDE_NONE. */ int visu_plane_getHiddenState(const VisuPlane *plane); gboolean visu_plane_setRendered(VisuPlane *plane, gboolean rendered); gboolean visu_plane_getRendered(const VisuPlane *plane); gboolean visu_plane_getVisibility(const VisuPlane *plane, float point[3]); gfloat visu_plane_getOpacity(const VisuPlane *plane); gboolean visu_plane_setOpacity(VisuPlane *plane, gfloat opacity); /* No object method. */ /** * visu_plane_class_getOrderedIntersections: * @nVisuPlanes: the number of planes (must be consistent with the number of * planes in listOfVisuPlanes!) * @listOfVisuPlanes: an array of #VisuPlane, NULL terminated ; * @pointA: three cartesian coordinates. * @pointB: three cartesian coordinates. * @inter: a pointer to the location to store the intersection points. * Supposing you know the number of intersection points ! * @index: a pointer to the location to store the indices of ordering * of the planes. * * Compute the location of the intersection points of segment AB with list of * planes @listOfVisuPlanes. If there are several intersections, they are ordered * by the proximity to point A. * * Returns: TRUE if the intersections are found. */ gboolean visu_plane_class_getOrderedIntersections(int nVisuPlanes, VisuPlane **listOfVisuPlanes, float pointA[3], float pointB[3], float *inter, int *index); G_END_DECLS #endif v_sim-3.8.0/src/extraFunctions/planeset.c000066400000000000000000001153701370110300500204160ustar00rootroot00000000000000/* EXTRAITS DE LA LICENCE Copyright CEA, contributeurs : Damien CALISTE, laboratoire L_Sim, (2015) Adresse mèl : CALISTE, damien P caliste AT cea P fr. Ce logiciel est un programme informatique servant à visualiser des structures atomiques dans un rendu pseudo-3D. Ce logiciel est régi par la licence CeCILL soumise au droit français et respectant les principes de diffusion des logiciels libres. Vous pouvez utiliser, modifier et/ou redistribuer ce programme sous les conditions de la licence CeCILL telle que diffusée par le CEA, le CNRS et l'INRIA sur le site "http://www.cecill.info". Le fait que vous puissiez accéder à cet en-tête signifie que vous avez pris connaissance de la licence CeCILL, et que vous en avez accepté les termes (cf. le fichier Documentation/licence.fr.txt fourni avec ce logiciel). */ /* LICENCE SUM UP Copyright CEA, contributors : Damien CALISTE, laboratoire L_Sim, (2015) E-mail address: CALISTE, damien P caliste AT cea P fr. This software is a computer program whose purpose is to visualize atomic configurations in 3D. This software is governed by the CeCILL license under French law and abiding by the rules of distribution of free software. You can use, modify and/ or redistribute the software under the terms of the CeCILL license as circulated by CEA, CNRS and INRIA at the following URL "http://www.cecill.info". The fact that you are presently reading this means that you have had knowledge of the CeCILL license and that you accept its terms. You can find a copy of this licence shipped with this software at Documentation/licence.en.txt. */ #include "planeset.h" #include #include #include #include /** * SECTION:planeset * @short_description: Defines a storage object to gather #VisuPlane objects. * * A #VisuPlaneSet object is a storage object for a bunch of * #VisuPlane. This object provides methods to compute hiding * properties, like visu_plane_set_getVisibility() ; method to load * and save plane definitions into a file, see * visu_plane_set_exportXMLFile() ; or to iterate over the internal storage. */ /** * VisuPlaneSetIter: * @set: the #VisuPlaneSet to iter on. * @plane: the current #VisuPlane. * @next: (element-type gpointer): internal index. * * Structure to iterate over the stored @plane of @set. * * Since: 3.8 */ struct _VisuPlaneSetPrivate { gboolean dispose_has_run; /* A GList to store all the planes. */ GList *set; VisuBox *box; VisuPlaneSetItemNew newItem; VisuPlaneSetItemFree freeItem; gpointer data; /* Masking properties. */ gboolean masking; VisuPlaneSetHiddingEnum mode; }; enum { ADD_SIGNAL, REMOVE_SIGNAL, NB_SIGNAL }; static guint _signals[NB_SIGNAL] = { 0 }; enum { PROP_0, N_PLANES_PROP, MASKING_PROP, MODE_PROP, N_PROP, ADJUST_PROP, BOX_PROP }; static GParamSpec *properties[N_PROP]; static void visu_plane_set_dispose (GObject* obj); static void visu_plane_set_get_property(GObject* obj, guint property_id, GValue *value, GParamSpec *pspec); static void visu_plane_set_set_property(GObject* obj, guint property_id, const GValue *value, GParamSpec *pspec); static void visu_boxed_interface_init(VisuBoxedInterface *iface); static VisuBox* visu_plane_set_getBox(VisuBoxed *self); static gboolean visu_plane_set_setBox(VisuBoxed *self, VisuBox *box); static void visu_node_masker_interface_init(VisuNodeMaskerInterface *iface); static void visu_animatable_interface_init(VisuAnimatableInterface *iface); static gboolean _maskApply(const VisuNodeMasker *self, VisuNodeArray *array); G_DEFINE_TYPE_WITH_CODE(VisuPlaneSet, visu_plane_set, VISU_TYPE_OBJECT, G_ADD_PRIVATE(VisuPlaneSet) G_IMPLEMENT_INTERFACE(VISU_TYPE_BOXED, visu_boxed_interface_init) G_IMPLEMENT_INTERFACE(VISU_TYPE_NODE_MASKER, visu_node_masker_interface_init) G_IMPLEMENT_INTERFACE(VISU_TYPE_ANIMATABLE, visu_animatable_interface_init)) /* Local callbacks. */ static void onPlaneMoved(VisuPlane *plane, gpointer data); static void onPlaneHidding(GObject *obj, GParamSpec *pspec, gpointer data); static gboolean onPlaneAnimate(VisuPlaneSet *set, VisuAnimation *anim, const GValue *to, gulong duration, gboolean loop, VisuAnimationType type); struct _Item { VisuPlane *plane; gulong move_sig, hidding_sig, animate_sig; gpointer add; }; /* Local routines. */ static void _freeItem(VisuPlaneSet *set, struct _Item *obj) { if (set->priv->freeItem) set->priv->freeItem(obj->plane, obj->add); g_signal_handler_disconnect(G_OBJECT(obj->plane), obj->move_sig); g_signal_handler_disconnect(G_OBJECT(obj->plane), obj->hidding_sig); g_signal_handler_disconnect(G_OBJECT(obj->plane), obj->animate_sig); g_object_unref(obj->plane); #if GLIB_MINOR_VERSION > 9 g_slice_free1(sizeof(struct _Item), obj); #else g_free(obj); #endif } static gpointer _newItem(VisuPlaneSet *set, VisuPlane *plane) { struct _Item *it; #if GLIB_MINOR_VERSION > 9 it = g_slice_alloc(sizeof(struct _Item)); #else it = g_malloc(sizeof(struct _Item)); #endif g_object_ref(plane); it->plane = plane; it->move_sig = g_signal_connect(G_OBJECT(plane), "moved", G_CALLBACK(onPlaneMoved), set); it->hidding_sig = g_signal_connect(G_OBJECT(plane), "notify::hidding-side", G_CALLBACK(onPlaneHidding), set); it->animate_sig = g_signal_connect_swapped(G_OBJECT(plane), "animate", G_CALLBACK(onPlaneAnimate), set); if (set->priv->newItem) it->add = set->priv->newItem(plane, set->priv->data); else it->add = (gpointer)0; return (gpointer)it; } static gint _cmpItem(gconstpointer a, gconstpointer b) { struct _Item *obj = (struct _Item*)a; if (obj->plane == b) return 0; return 1; } #define _getItem(lst) ((struct _Item*)lst->data)->plane static void visu_plane_set_class_init(VisuPlaneSetClass *klass) { DBG_fprintf(stderr, "Visu Plane Set: creating the class of the object.\n"); /* DBG_fprintf(stderr, " - adding new signals ;\n"); */ /* Connect the overloading methods. */ G_OBJECT_CLASS(klass)->dispose = visu_plane_set_dispose; G_OBJECT_CLASS(klass)->set_property = visu_plane_set_set_property; G_OBJECT_CLASS(klass)->get_property = visu_plane_set_get_property; /** * VisuPlaneSet::added: * @set: the object emitting the signal. * @plane: the added #VisuPlane object. * * This signal is emitted each time a plane is added to * the set. * * Since: 3.8 */ _signals[ADD_SIGNAL] = g_signal_new("added", G_TYPE_FROM_CLASS(klass), G_SIGNAL_RUN_LAST | G_SIGNAL_NO_RECURSE | G_SIGNAL_NO_HOOKS, 0, NULL, NULL, g_cclosure_marshal_VOID__OBJECT, G_TYPE_NONE, 1, VISU_TYPE_PLANE, NULL); /** * VisuPlaneSet::removed: * @set: the object emitting the signal. * @plane: the removed #VisuPlane object. * * This signal is emitted each time a plane is removed from * the set. * * Since: 3.8 */ _signals[REMOVE_SIGNAL] = g_signal_new("removed", G_TYPE_FROM_CLASS(klass), G_SIGNAL_RUN_LAST | G_SIGNAL_NO_RECURSE | G_SIGNAL_NO_HOOKS, 0, NULL, NULL, g_cclosure_marshal_VOID__OBJECT, G_TYPE_NONE, 1, VISU_TYPE_PLANE, NULL); /** * VisuPlaneSet::n-planes: * * Number of stored planes. * * Since: 3.8 */ properties[N_PLANES_PROP] = g_param_spec_uint("n-planes", "Number of planes", "number of planes", 0, G_MAXUINT, 0, G_PARAM_READABLE | G_PARAM_STATIC_STRINGS); /** * VisuPlaneSet::masking: * * If the plane set has masking properties or not. * * Since: 3.8 */ properties[MASKING_PROP] = g_param_spec_boolean("masking", "Masking", "masking property", FALSE, G_PARAM_READWRITE); /** * VisuPlaneSet::hidding-mode: * * How multiple planes are hidding an element. * * Since: 3.8 */ properties[MODE_PROP] = g_param_spec_uint ("hidding-mode", "Hidding mode", "how to hide from multiple planes", VISU_PLANE_SET_HIDE_UNION, VISU_PLANE_SET_HIDE_INTER, VISU_PLANE_SET_HIDE_UNION, G_PARAM_READWRITE); g_object_class_install_properties(G_OBJECT_CLASS(klass), N_PROP, properties); g_object_class_override_property(G_OBJECT_CLASS(klass), ADJUST_PROP, "auto-adjust"); g_object_class_override_property(G_OBJECT_CLASS(klass), BOX_PROP, "box"); } static void visu_boxed_interface_init(VisuBoxedInterface *iface) { iface->get_box = visu_plane_set_getBox; iface->set_box = visu_plane_set_setBox; } static void visu_node_masker_interface_init(VisuNodeMaskerInterface *iface) { iface->apply = _maskApply; } static void visu_animatable_interface_init(VisuAnimatableInterface *iface) { iface->get_animation = NULL; } static void visu_plane_set_init(VisuPlaneSet *ext) { DBG_fprintf(stderr, "Visu Plane Set: initializing a new object (%p).\n", (gpointer)ext); ext->priv = visu_plane_set_get_instance_private(ext); ext->priv->dispose_has_run = FALSE; ext->priv->set = (GList*)0; ext->priv->box = (VisuBox*)0; ext->priv->masking = FALSE; ext->priv->mode = VISU_PLANE_SET_HIDE_UNION; ext->priv->newItem = (VisuPlaneSetItemNew)0; ext->priv->freeItem = (VisuPlaneSetItemFree)0; ext->priv->data = (gpointer)0; } /* This method can be called several times. It should unref all of its reference to GObjects. */ static void visu_plane_set_dispose(GObject* obj) { VisuPlaneSet *set; DBG_fprintf(stderr, "Visu Plane Set: dispose object %p.\n", (gpointer)obj); set = VISU_PLANE_SET(obj); if (set->priv->dispose_has_run) return; set->priv->dispose_has_run = TRUE; /* Disconnect signals. */ visu_plane_set_removeAll(set); visu_plane_set_setBox(VISU_BOXED(obj), (VisuBox*)0); /* Chain up to the parent class */ G_OBJECT_CLASS(visu_plane_set_parent_class)->dispose(obj); } static void visu_plane_set_get_property(GObject* obj, guint property_id, GValue *value, GParamSpec *pspec) { VisuPlaneSetPrivate *self = VISU_PLANE_SET(obj)->priv; DBG_fprintf(stderr, "Visu PlaneSet: get property '%s' -> ", g_param_spec_get_name(pspec)); switch (property_id) { case BOX_PROP: g_value_set_object(value, self->box); DBG_fprintf(stderr, "%p.\n", g_value_get_object(value)); break; case N_PLANES_PROP: g_value_set_uint(value, g_list_length(self->set)); DBG_fprintf(stderr, "%d.\n", g_value_get_uint(value)); break; case MASKING_PROP: g_value_set_boolean(value, self->masking); DBG_fprintf(stderr, "%d.\n", self->masking); break; case MODE_PROP: g_value_set_uint(value, self->mode); DBG_fprintf(stderr, "%d.\n", self->mode); break; case ADJUST_PROP: g_value_set_boolean(value, FALSE); break; default: /* We don't have any other property... */ G_OBJECT_WARN_INVALID_PROPERTY_ID(obj, property_id, pspec); break; } } static void visu_plane_set_set_property(GObject* obj, guint property_id, const GValue *value, GParamSpec *pspec) { VisuPlaneSetPrivate *self = VISU_PLANE_SET(obj)->priv; DBG_fprintf(stderr, "Visu PlaneSet: set property '%s' -> ", g_param_spec_get_name(pspec)); switch (property_id) { case BOX_PROP: DBG_fprintf(stderr, "%p.\n", g_value_get_object(value)); visu_plane_set_setBox(VISU_BOXED(obj), VISU_BOX(g_value_get_object(value))); break; case MASKING_PROP: if (self->masking == g_value_get_boolean(value)) break; self->masking = g_value_get_boolean(value); DBG_fprintf(stderr, "%d.\n", self->masking); visu_node_masker_emitDirty(VISU_NODE_MASKER(obj)); break; case MODE_PROP: visu_plane_set_setHiddingMode(VISU_PLANE_SET(obj), g_value_get_uint(value)); DBG_fprintf(stderr, "%d.\n", self->mode); break; case ADJUST_PROP: DBG_fprintf(stderr, "%d.\n", FALSE); break; default: /* We don't have any other property... */ G_OBJECT_WARN_INVALID_PROPERTY_ID(obj, property_id, pspec); break; } } static gboolean visu_plane_set_setBox(VisuBoxed *self, VisuBox *box) { VisuPlaneSet *set; VisuPlaneSetIter iter; g_return_val_if_fail(VISU_IS_PLANE_SET(self), FALSE); set = VISU_PLANE_SET(self); DBG_fprintf(stderr, "Visu PlaneSet: set box %p.\n", (gpointer)box); if (set->priv->box == box) return FALSE; if (set->priv->box) g_object_unref(set->priv->box); set->priv->box = box; if (!box) return TRUE; g_object_ref(box); visu_plane_set_iter_new(set, &iter); for (visu_plane_set_iter_next(&iter); iter.plane; visu_plane_set_iter_next(&iter)) visu_boxed_setBox(VISU_BOXED(iter.plane), VISU_BOXED(box)); DBG_fprintf(stderr, "Visu PlaneSet: set box done.\n"); return TRUE; } static VisuBox* visu_plane_set_getBox(VisuBoxed *self) { g_return_val_if_fail(VISU_IS_PLANE_SET(self), (VisuBox*)0); return VISU_PLANE_SET(self)->priv->box; } /** * visu_plane_set_new: * * Creates an object to store several planes and do hiding operations * with them. * * Since: 3.8 * * Returns: (transfer full): the newly created object. **/ VisuPlaneSet* visu_plane_set_new() { VisuPlaneSet *set; set = VISU_PLANE_SET(g_object_new(VISU_TYPE_PLANE_SET, NULL)); return set; } /** * visu_plane_set_newFull: * @newItem: (scope call): a routine to be called when adding a plane * to the set. * @freeItem: (scope call): a routine to be called when removing a * plane from the set. * @data: some user data. * * Creates an object to store several planes and do hiding operations * with them. * * Since: 3.8 * * Returns: (transfer full): **/ VisuPlaneSet* visu_plane_set_newFull(VisuPlaneSetItemNew newItem, VisuPlaneSetItemFree freeItem, gpointer data) { VisuPlaneSet *set; set = VISU_PLANE_SET(g_object_new(VISU_TYPE_PLANE_SET, NULL)); set->priv->newItem = newItem; set->priv->freeItem = freeItem; set->priv->data = data; return set; } /** * visu_plane_set_iter_new: * @set: a #VisuPlaneSet object. * @iter: (out caller-allocates): the iterator to create. * * Creates an iterator on the internal storage of #VisuPlane objects. * * Since: 3.8 * * Returns: TRUE if iterator is valid (i.e. there are planes in @set). **/ gboolean visu_plane_set_iter_new(const VisuPlaneSet *set, VisuPlaneSetIter *iter) { g_return_val_if_fail(VISU_IS_PLANE_SET(set) && iter, FALSE); iter->set = set; iter->next = set->priv->set; return (iter->next != (GList*)0); } /** * visu_plane_set_iter_next: * @iter: an iterator. * * Use this function to iterate on plane stored in a #VisuPlaneSet object. * * Since: 3.8 * * Returns: TRUE if any plane remains. **/ gboolean visu_plane_set_iter_next(VisuPlaneSetIter *iter) { g_return_val_if_fail(iter && iter->set, FALSE); if (!iter->next) iter->plane = (VisuPlane*)0; else { iter->plane = _getItem(iter->next); iter->next = g_list_next(iter->next); } return (iter->next != (GList*)0); } /** * visu_plane_set_getAt: * @set: a #VisuPlaneSet object. * @i: an index. * * Retrieve the plane stored at index @i. * * Since: 3.8 * * Returns: (transfer none) (allow-none): a #VisuPlane object or NULL * index is out of bounds. **/ VisuPlane* visu_plane_set_getAt(const VisuPlaneSet *set, guint i) { GList *at; g_return_val_if_fail(VISU_IS_PLANE_SET(set), (VisuPlane*)0); at = g_list_nth(set->priv->set, i); if (at) return _getItem(at); else return (VisuPlane*)0; } /** * visu_plane_set_add: * @set: a #VisuPlaneSet object. * @plane: (transfer none): a #VisuPlane object. * * Adds a @plane to the list of stored planes. * * Since: 3.8 * * Returns: FALSE if @plane was already registered. **/ gboolean visu_plane_set_add(VisuPlaneSet *set, VisuPlane *plane) { GList *lst; g_return_val_if_fail(VISU_IS_PLANE_SET(set) && plane, FALSE); lst = g_list_find_custom(set->priv->set, plane, _cmpItem); if (lst) return FALSE; if (set->priv->box) visu_boxed_setBox(VISU_BOXED(plane), VISU_BOXED(set->priv->box)); set->priv->set = g_list_append(set->priv->set, _newItem(set, plane)); g_signal_emit(G_OBJECT(set), _signals[ADD_SIGNAL], 0, plane); g_object_notify_by_pspec(G_OBJECT(set), properties[N_PLANES_PROP]); DBG_fprintf(stderr, "Visu Planeset: %p has %d ref counts.\n", (gpointer)plane, G_OBJECT(plane)->ref_count); if (visu_plane_getHiddenState(plane) != VISU_PLANE_SIDE_NONE && set->priv->masking) visu_node_masker_emitDirty(VISU_NODE_MASKER(set)); return TRUE; } /** * visu_plane_set_remove: * @set: a #VisuPlaneSet object. * @plane: a #VisuPlane object. * * Remove @plane from the list of stored planes. * * Since: 3.8 * * Returns: TRUE if @plane was found and removed. **/ gboolean visu_plane_set_remove(VisuPlaneSet *set, VisuPlane *plane) { gboolean wasMasking; GList *lst; g_return_val_if_fail(VISU_IS_PLANE_SET(set) && plane, FALSE); lst = g_list_find_custom(set->priv->set, plane, _cmpItem); if (!lst) return FALSE; wasMasking = (visu_plane_getHiddenState(plane) != VISU_PLANE_SIDE_NONE); _freeItem(set, (struct _Item*)lst->data); set->priv->set = g_list_delete_link(set->priv->set, lst); g_signal_emit(G_OBJECT(set), _signals[REMOVE_SIGNAL], 0, plane, NULL); g_object_notify_by_pspec(G_OBJECT(set), properties[N_PLANES_PROP]); if (wasMasking && set->priv->masking) visu_node_masker_emitDirty(VISU_NODE_MASKER(set)); return TRUE; } /** * visu_plane_set_removeAll: * @set: a #VisuPlaneSet object. * * Remove all stored planes. * * Since: 3.8 * * Returns: TRUE if some planes were actually removed. **/ gboolean visu_plane_set_removeAll(VisuPlaneSet *set) { GList *lst; gboolean cleaned; g_return_val_if_fail(VISU_IS_PLANE_SET(set), FALSE); cleaned = (set->priv->set != (GList*)0); for (lst = set->priv->set; lst; lst = g_list_next(lst)) { g_signal_emit(G_OBJECT(set), _signals[REMOVE_SIGNAL], 0, ((struct _Item*)lst->data)->plane, NULL); _freeItem(set, (struct _Item*)lst->data); } g_list_free(set->priv->set); set->priv->set = (GList*)0; if (cleaned) { g_object_notify_by_pspec(G_OBJECT(set), properties[N_PLANES_PROP]); visu_node_masker_emitDirty(VISU_NODE_MASKER(set)); } return cleaned; } /** * visu_plane_set_getIntersection: * @set: an array of #VisuPlane, NULL terminated ; * @pointA: three cartesian coordinates. * @pointB: three cartesian coordinates. * @inter: a location to store the intersection point. * @inside: a boolean. * * Compute the location of the intersection point of segment AB with list of * planes @set. If there are several intersections, the closest to * point A is returned. If @inside is TRUE, then the intersection * point must be within the line [AB]. * * Since: 3.8 * * Returns: TRUE if there is an intersection. */ gboolean visu_plane_set_getIntersection(const VisuPlaneSet *set, float pointA[3], float pointB[3], float inter[3], gboolean inside) { float lambda; float lambdaMin; VisuPlaneSetIter iter; g_return_val_if_fail(VISU_IS_PLANE_SET(set), FALSE); /* DBG_fprintf(stderr, "VisuPlane: intersection A(%g;%g;%g) B(%g;%g;%g).\n", */ /* pointA[0], pointA[1], pointA[2], pointB[0], pointB[1], pointB[2]); */ lambdaMin = 2.f; visu_plane_set_iter_new(set, &iter); for (visu_plane_set_iter_next(&iter); iter.plane; visu_plane_set_iter_next(&iter)) { if (!visu_plane_getLineIntersection(iter.plane, pointA, pointB, &lambda)) lambda = 2.f; if (( inside && lambda >= 0. && lambda <= 1. && lambda < lambdaMin) || (!inside && ((lambda <= 0.f && lambda > lambdaMin) || (lambdaMin > 0.f && lambda < lambdaMin)))) lambdaMin = lambda; } if (lambdaMin == 2.f) return FALSE; inter[0] = pointA[0] + lambdaMin * (pointB[0] - pointA[0]); inter[1] = pointA[1] + lambdaMin * (pointB[1] - pointA[1]); inter[2] = pointA[2] + lambdaMin * (pointB[2] - pointA[2]); return TRUE; } /* Masking property of the list of planes. */ static void onPlaneMoved(VisuPlane *plane, gpointer data) { /* No effect. */ if (visu_plane_getHiddenState(plane) == VISU_PLANE_SIDE_NONE || !VISU_PLANE_SET(data)->priv->masking) return; if (VISU_PLANE_SET(data)->priv->masking) visu_node_masker_emitDirty(VISU_NODE_MASKER(data)); } static void onPlaneHidding(GObject *obj _U_, GParamSpec *pspec _U_, gpointer data) { if (!VISU_PLANE_SET(data)->priv->masking) return; if (VISU_PLANE_SET(data)->priv->masking) visu_node_masker_emitDirty(VISU_NODE_MASKER(data)); } static gboolean onPlaneAnimate(VisuPlaneSet *set, VisuAnimation *anim, const GValue *to, gulong duration, gboolean loop, VisuAnimationType type) { return visu_animatable_animate(VISU_ANIMATABLE(set), anim, to, duration / 1000, loop, type); } /** * visu_plane_set_setHiddingMode: * @set: the list of planes. * @mode: a value related to the hiding mode (look at the enum #VisuPlaneSetHiddingEnum). * * This method is used to set the hiding mode flag. In union mode, elements * are not drawn if they are hidden by one plane at least. In intersection mode, * elements are only hidden if masked by all planes. * * Since: 3.8 * * Returns: TRUE if status changed. */ gboolean visu_plane_set_setHiddingMode(VisuPlaneSet *set, VisuPlaneSetHiddingEnum mode) { g_return_val_if_fail(VISU_IS_PLANE_SET(set), FALSE); if (set->priv->mode == mode) return FALSE; set->priv->mode = mode; g_object_notify_by_pspec(G_OBJECT(set), properties[MODE_PROP]); if (set->priv->masking) visu_node_masker_emitDirty(VISU_NODE_MASKER(set)); return TRUE; } /** * visu_plane_set_getHiddingStatus: * @set: a #VisuPlaneSet object. * * Inquire if the @set has any masking planes. * * Since: 3.8 * * Returns: TRUE if @set has any masking planes. **/ gboolean visu_plane_set_getHiddingStatus(const VisuPlaneSet *set) { VisuPlaneSetIter pl; g_return_val_if_fail(VISU_IS_PLANE_SET(set), FALSE); if (!set->priv->masking) return FALSE; visu_plane_set_iter_new(set, &pl); for (visu_plane_set_iter_next(&pl); pl.plane; visu_plane_set_iter_next(&pl)) if (visu_plane_getHiddenState(pl.plane) != VISU_PLANE_SIDE_NONE) return TRUE; return FALSE; } /** * visu_plane_set_getVisibility: * @set: a #VisuPlaneSet object ; * @point: three cartesian coordinates. * * Compute the visibility of the given @point, following the masking scheme * of the given plane list. * * Since: 3.8 * * Returns: TRUE if the point is not masked. */ gboolean visu_plane_set_getVisibility(const VisuPlaneSet *set, float point[3]) { VisuPlaneSetIter iter; gboolean visibility; g_return_val_if_fail(VISU_IS_PLANE_SET(set), FALSE); visu_plane_set_iter_new(set, &iter); switch (set->priv->mode) { case VISU_PLANE_SET_HIDE_UNION: visibility = TRUE; for (visu_plane_set_iter_next(&iter); iter.plane; visu_plane_set_iter_next(&iter)) if (visu_plane_getHiddenState(iter.plane) != VISU_PLANE_SIDE_NONE) visibility = visibility && visu_plane_getVisibility(iter.plane, point); break; case VISU_PLANE_SET_HIDE_INTER: visibility = FALSE; for (visu_plane_set_iter_next(&iter); iter.plane; visu_plane_set_iter_next(&iter)) if (visu_plane_getHiddenState(iter.plane) != VISU_PLANE_SIDE_NONE) visibility = visibility || visu_plane_getVisibility(iter.plane, point); break; default: visibility = TRUE; break; } return visibility; } static gboolean _maskApply(const VisuNodeMasker *self, VisuNodeArray *array) { gboolean reDraw; float point[3]; VisuNodeArrayIter iter; VisuPlaneSet *set; g_return_val_if_fail(VISU_IS_PLANE_SET(self), FALSE); set = VISU_PLANE_SET(self); DBG_fprintf(stderr, "VisuPlaneSet : applying masking properties of planes.\n"); if (!visu_plane_set_getHiddingStatus(set)) return FALSE; reDraw = FALSE; /* We change the rendered attribute of all nodes, very expensive... */ visu_node_array_iter_new(array, &iter); for (visu_node_array_iterStart(array, &iter); iter.element; visu_node_array_iterNextElement(array, &iter, FALSE)) if (visu_element_getMaskable(iter.element) && visu_element_getRendered(iter.element)) { DBG_fprintf(stderr, " | element '%s'\n", iter.element->name); for (visu_node_array_iterRestartNode(array, &iter); iter.node; visu_node_array_iterNextNode(array, &iter)) { /* If node is already hiden, well, we go to the next. */ if (!iter.node->rendered) continue; visu_data_getNodePosition(VISU_DATA(array), iter.node, point); if (!visu_plane_set_getVisibility(set, point)) reDraw = visu_node_setVisibility(iter.node, FALSE) || reDraw; DBG_fprintf(stderr, " | node '%d' -> %d\n", iter.node->number, iter.node->rendered); } } return reDraw; } /*************************************************** * Parsing of data files containing list of planes * ***************************************************/ /* Known elements. */ #define PLANES_PARSER_ELEMENT_PLANES "planes" #define PLANES_PARSER_ELEMENT_PLANE "plane" #define PLANES_PARSER_ELEMENT_GEOMETRY "geometry" #define PLANES_PARSER_ELEMENT_HIDE "hide" #define PLANES_PARSER_ELEMENT_COLOR "color" /* Known attributes. */ #define PLANES_PARSER_ATTRIBUTES_RENDERED "rendered" #define PLANES_PARSER_ATTRIBUTES_VECTOR "normal-vector" #define PLANES_PARSER_ATTRIBUTES_DISTANCE "distance" #define PLANES_PARSER_ATTRIBUTES_STATUS "status" #define PLANES_PARSER_ATTRIBUTES_INVERT "invert" #define PLANES_PARSER_ATTRIBUTES_RGBA "rgba" static gboolean planesStarted; /* This method is called for every element that is parsed. The user_data must be a GList of planes. When a 'plane' element, a new plane is created and prepend in the list. When 'geometry' or other qualificative elements are found, the first plane of the list is modified accordingly. */ static void listOfVisuPlanes_element(GMarkupParseContext *context _U_, const gchar *element_name, const gchar **attribute_names, const gchar **attribute_values, gpointer user_data, GError **error) { GList **planesList; VisuPlane *plane; float normalVector[3]; float distance; float colorRGBA[4]; ToolColor *color; int i, res; int side, set; gboolean rendered; g_return_if_fail(user_data); planesList = (GList **)user_data; DBG_fprintf(stderr, "VisuPlanes parser: found '%s' element.\n", element_name); if (!strcmp(element_name, PLANES_PARSER_ELEMENT_PLANES)) { /* Should have no attributes. */ if (attribute_names[0]) { g_set_error(error, G_MARKUP_ERROR, G_MARKUP_ERROR_UNKNOWN_ATTRIBUTE, _("Unexpected attribute '%s' for element '%s'."), attribute_names[0], PLANES_PARSER_ELEMENT_PLANES); return; } /* Initialise planeList. */ if (*planesList) g_warning("Unexpected non null pointer as user_data for the " "plane parser."); planesStarted = TRUE; *planesList = (GList*)0; } else if (!strcmp(element_name, PLANES_PARSER_ELEMENT_PLANE)) { rendered = TRUE; /* May have one attribute. */ if (attribute_names[0]) { if (!strcmp(attribute_names[0], PLANES_PARSER_ATTRIBUTES_RENDERED) ) { if (!strcmp(attribute_values[0], "yes")) rendered = TRUE; else if (!strcmp(attribute_values[0], "no")) rendered = FALSE; else g_set_error(error, G_MARKUP_ERROR, G_MARKUP_ERROR_INVALID_CONTENT, _("Invalid value '%s' for attribute '%s'."), attribute_values[0], PLANES_PARSER_ATTRIBUTES_RENDERED); } else { g_set_error(error, G_MARKUP_ERROR, G_MARKUP_ERROR_UNKNOWN_ATTRIBUTE, _("Unexpected attribute '%s' for element '%s'."), attribute_names[0], PLANES_PARSER_ELEMENT_PLANE); return; } } plane = visu_plane_newUndefined(); visu_plane_setRendered(plane, rendered); DBG_fprintf(stderr, "VisuPlanes parser: adding plane %p to list %p.\n", (gpointer)plane, (gpointer)(*planesList)); *planesList = g_list_prepend(*planesList, (gpointer)plane); DBG_fprintf(stderr, " | new plane list: %p.\n", (gpointer)(*planesList)); } else if (planesStarted && !strcmp(element_name, PLANES_PARSER_ELEMENT_GEOMETRY)) { if (!*planesList || !(*planesList)->data) { g_set_error(error, G_MARKUP_ERROR, G_MARKUP_ERROR_INVALID_CONTENT, _("DTD error : parent element '%s' of element '%s' is missing."), PLANES_PARSER_ELEMENT_PLANE, element_name); return; } DBG_fprintf(stderr, "VisuPlanes parser: associated plane : %p.\n", (*planesList)->data); for(i = 0; attribute_names[i]; i++) { if (!strcmp(attribute_names[i], PLANES_PARSER_ATTRIBUTES_VECTOR)) { res = sscanf(attribute_values[i], "%g %g %g", normalVector, normalVector + 1, normalVector + 2); if (res != 3) g_set_error(error, G_MARKUP_ERROR, G_MARKUP_ERROR_INVALID_CONTENT, _("Invalid value '%s' for attribute '%s'."), attribute_values[i], PLANES_PARSER_ATTRIBUTES_VECTOR); visu_plane_setNormalVector(VISU_PLANE((*planesList)->data), normalVector); } else if (!strcmp(attribute_names[i], PLANES_PARSER_ATTRIBUTES_DISTANCE)) { res = sscanf(attribute_values[i], "%g", &distance); if (res != 1) g_set_error(error, G_MARKUP_ERROR, G_MARKUP_ERROR_INVALID_CONTENT, _("Invalid value '%s' for attribute '%s'."), attribute_values[i], PLANES_PARSER_ATTRIBUTES_DISTANCE); visu_plane_setDistanceFromOrigin(VISU_PLANE((*planesList)->data), distance); } else g_set_error(error, G_MARKUP_ERROR, G_MARKUP_ERROR_UNKNOWN_ATTRIBUTE, _("Unexpected attribute '%s' for element '%s'."), attribute_names[i], PLANES_PARSER_ELEMENT_GEOMETRY); } } else if (planesStarted && !strcmp(element_name, PLANES_PARSER_ELEMENT_HIDE)) { if (!*planesList || !(*planesList)->data) { g_set_error(error, G_MARKUP_ERROR, G_MARKUP_ERROR_INVALID_CONTENT, _("DTD error: parent element '%s' of element '%s' is missing."), PLANES_PARSER_ELEMENT_PLANE, element_name); return; } set = 0; side = 1; for(i = 0; attribute_names[i]; i++) { if (!strcmp(attribute_names[i], PLANES_PARSER_ATTRIBUTES_STATUS)) { if (!strcmp(attribute_values[i], "yes")) set = 1; else if (!strcmp(attribute_values[i], "no")) set = 0; else g_set_error(error, G_MARKUP_ERROR, G_MARKUP_ERROR_INVALID_CONTENT, _("Invalid value '%s' for attribute '%s'."), attribute_values[i], PLANES_PARSER_ATTRIBUTES_STATUS); } else if (!strcmp(attribute_names[i], PLANES_PARSER_ATTRIBUTES_INVERT)) { if (!strcmp(attribute_values[i], "yes")) side = -1; else if (!strcmp(attribute_values[i], "no")) side = 1; else g_set_error(error, G_MARKUP_ERROR, G_MARKUP_ERROR_INVALID_CONTENT, _("Invalid value '%s' for attribute '%s'."), attribute_values[i], PLANES_PARSER_ATTRIBUTES_INVERT); } else g_set_error(error, G_MARKUP_ERROR, G_MARKUP_ERROR_UNKNOWN_ATTRIBUTE, _("Unexpected attribute '%s' for element '%s'."), attribute_names[i], PLANES_PARSER_ELEMENT_HIDE); } visu_plane_setHiddenState(VISU_PLANE((*planesList)->data), side * set); } else if (planesStarted && !strcmp(element_name, PLANES_PARSER_ELEMENT_COLOR)) { if (!*planesList || !(*planesList)->data) { g_set_error(error, G_MARKUP_ERROR, G_MARKUP_ERROR_INVALID_CONTENT, _("DTD error: parent element '%s' of element '%s' is missing."), PLANES_PARSER_ELEMENT_PLANE, element_name); return; } for(i = 0; attribute_names[i]; i++) { if (!strcmp(attribute_names[i], PLANES_PARSER_ATTRIBUTES_RGBA)) { res = sscanf(attribute_values[i], "%g %g %g %g", colorRGBA, colorRGBA + 1, colorRGBA + 2, colorRGBA + 3); if (res != 4) g_set_error(error, G_MARKUP_ERROR, G_MARKUP_ERROR_INVALID_CONTENT, _("Invalid value '%s' for attribute '%s'."), attribute_values[i], PLANES_PARSER_ATTRIBUTES_RGBA); color = tool_color_addFloatRGBA(colorRGBA, &res); visu_plane_setColor(VISU_PLANE((*planesList)->data), color); } else g_set_error(error, G_MARKUP_ERROR, G_MARKUP_ERROR_UNKNOWN_ATTRIBUTE, _("Unexpected attribute '%s' for element '%s'."), attribute_names[i], PLANES_PARSER_ELEMENT_COLOR); } } else if (planesStarted) g_set_error(error, G_MARKUP_ERROR, G_MARKUP_ERROR_UNKNOWN_ELEMENT, _("Unexpected element '%s'."), element_name); } /* Check when a element is closed that everything required has been set. */ static void listOfVisuPlanes_end(GMarkupParseContext *context _U_, const gchar *element_name, gpointer user_data, GError **error) { GList **planesList; float vect[3]; g_return_if_fail(user_data); planesList = (GList**)user_data; if (!strcmp(element_name, PLANES_PARSER_ELEMENT_PLANE)) { g_return_if_fail(*planesList && (*planesList)->data); if (!visu_plane_getColor(VISU_PLANE((*planesList)->data))) { g_set_error(error, G_MARKUP_ERROR, G_MARKUP_ERROR_UNKNOWN_ATTRIBUTE, _("DTD error: missing or wrong child element '%s'."), PLANES_PARSER_ELEMENT_COLOR); return; } visu_plane_getNVectUser(VISU_PLANE((*planesList)->data), vect); if (vect[0] == 0. && vect[1] == 0. && vect[2] == 0.) { g_set_error(error, G_MARKUP_ERROR, G_MARKUP_ERROR_UNKNOWN_ATTRIBUTE, _("DTD error: missing or wrong child element '%s'."), PLANES_PARSER_ELEMENT_GEOMETRY); return; } } else if (!strcmp(element_name, PLANES_PARSER_ELEMENT_PLANES)) planesStarted = FALSE; } /* What to do when an error is raised. */ static void listOfVisuPlanes_error(GMarkupParseContext *context _U_, GError *error, gpointer user_data _U_) { DBG_fprintf(stderr, "VisuPlaneSet parser: error raised '%s'.\n", error->message); } /** * visu_plane_set_parseXMLFile: * @set: a #VisuPlaneSet object to store read planes. * @filename: (type filename): the file to parse ; * @error: a pointer to store the error (can be NULL). * * Read the given file (syntax in XML) and create a list of planes. * * Since: 3.8 * * Returns: TRUE if everything goes right, if not and @error (if not NULL) * is set and contains the message of the error. */ gboolean visu_plane_set_parseXMLFile(VisuPlaneSet *set, const gchar* filename, GError **error) { GMarkupParseContext* xmlContext; GMarkupParser parser; gboolean res; gsize size; gchar *buffer; GList *list, *tmpLst; g_return_val_if_fail(VISU_IS_PLANE_SET(set) && filename, FALSE); buffer = (gchar*)0; if (!g_file_get_contents(filename, &buffer, &size, error)) return FALSE; /* Create context. */ list = (GList*)0; parser.start_element = listOfVisuPlanes_element; parser.end_element = listOfVisuPlanes_end; parser.text = NULL; parser.passthrough = NULL; parser.error = listOfVisuPlanes_error; xmlContext = g_markup_parse_context_new(&parser, 0, &list, NULL); /* Parse data. */ planesStarted = FALSE; res = g_markup_parse_context_parse(xmlContext, buffer, size, error); /* Free buffers. */ g_markup_parse_context_free(xmlContext); g_free(buffer); if (!res) return FALSE; if (!list) { *error = g_error_new(G_MARKUP_ERROR, G_MARKUP_ERROR_EMPTY, _("The file contains no plane.\n")); return FALSE; } /* Need to reverse the list since elements have been prepended. */ list = g_list_reverse(list); /* Convert the list to an array. */ DBG_fprintf(stderr, "Visu PlaneSet: add %d planes to set.\n", g_list_length(list)); for (tmpLst = list; tmpLst; tmpLst = g_list_next(tmpLst)) { visu_plane_set_add(set, VISU_PLANE(tmpLst->data)); g_object_unref(tmpLst->data); } g_list_free(list); return TRUE; } /** * visu_plane_set_exportXMLFile: * @set: a #VisuPlaneSet object. * @filename: the file to export to ; * @error: a pointer to store the error (can be NULL). * * Export in XML format the given list of planes to the given file. * * Since: 3.8 * * Returns: TRUE if everything goes right, if not and @error (if not NULL) * is set and contains the message of the error. */ gboolean visu_plane_set_exportXMLFile(const VisuPlaneSet *set, const gchar* filename, GError **error) { GString *buffer; VisuPlaneSetIter iter; gboolean valid; float vect[3]; const ToolColor *color; g_return_val_if_fail(VISU_IS_PLANE_SET(set) && filename, FALSE); buffer = g_string_new(" \n"); visu_plane_set_iter_new(set, &iter); for (visu_plane_set_iter_next(&iter); iter.plane; visu_plane_set_iter_next(&iter)) { g_string_append_printf(buffer, " \n", (visu_plane_getRendered(iter.plane))?"yes":"no"); visu_plane_getNVectUser(iter.plane, vect); g_string_append_printf(buffer, " \n", vect[0], vect[1], vect[2], visu_plane_getDistanceFromOrigin(iter.plane)); switch (visu_plane_getHiddenState(iter.plane)) { case VISU_PLANE_SIDE_NONE: g_string_append(buffer, " \n"); break; case VISU_PLANE_SIDE_MINUS: g_string_append(buffer, " \n"); break; case VISU_PLANE_SIDE_PLUS: g_string_append(buffer, " \n"); break; default: g_warning("Unknown hiddenSide attribute ofr the given plane."); }; color = visu_plane_getColor(iter.plane); g_string_append_printf(buffer, " \n", color->rgba[0], color->rgba[1], color->rgba[2], color->rgba[3]); g_string_append(buffer, " \n"); } g_string_append(buffer, " "); valid = tool_XML_substitute(buffer, filename, "planes", error); if (!valid) { g_string_free(buffer, TRUE); return FALSE; } valid = g_file_set_contents(filename, buffer->str, -1, error); g_string_free(buffer, TRUE); return valid; } v_sim-3.8.0/src/extraFunctions/planeset.h000066400000000000000000000145111370110300500204160ustar00rootroot00000000000000/* EXTRAITS DE LA LICENCE Copyright CEA, contributeurs : Damien CALISTE, laboratoire L_Sim, (2015) Adresse mèl : CALISTE, damien P caliste AT cea P fr. Ce logiciel est un programme informatique servant à visualiser des structures atomiques dans un rendu pseudo-3D. Ce logiciel est régi par la licence CeCILL soumise au droit français et respectant les principes de diffusion des logiciels libres. Vous pouvez utiliser, modifier et/ou redistribuer ce programme sous les conditions de la licence CeCILL telle que diffusée par le CEA, le CNRS et l'INRIA sur le site "http://www.cecill.info". Le fait que vous puissiez accéder à cet en-tête signifie que vous avez pris connaissance de la licence CeCILL, et que vous en avez accepté les termes (cf. le fichier Documentation/licence.fr.txt fourni avec ce logiciel). */ /* LICENCE SUM UP Copyright CEA, contributors : Damien CALISTE, laboratoire L_Sim, (2015) E-mail address: CALISTE, damien P caliste AT cea P fr. This software is a computer program whose purpose is to visualize atomic configurations in 3D. This software is governed by the CeCILL license under French law and abiding by the rules of distribution of free software. You can use, modify and/ or redistribute the software under the terms of the CeCILL license as circulated by CEA, CNRS and INRIA at the following URL "http://www.cecill.info". The fact that you are presently reading this means that you have had knowledge of the CeCILL license and that you accept its terms. You can find a copy of this licence shipped with this software at Documentation/licence.en.txt. */ #ifndef VISU_PLANE_SET_H #define VISU_PLANE_SET_H #include #include #include "plane.h" #include #include /***************/ /* Public part */ /***************/ /** * VISU_TYPE_PLANE_SET: * * return the type of #VisuPlaneSet. */ #define VISU_TYPE_PLANE_SET (visu_plane_set_get_type ()) /** * VISU_PLANE_SET: * @obj: a #GObject to cast. * * Cast the given @obj into #VisuPlaneSet type. */ #define VISU_PLANE_SET(obj) (G_TYPE_CHECK_INSTANCE_CAST(obj, VISU_TYPE_PLANE_SET, VisuPlaneSet)) /** * VISU_PLANE_SET_CLASS: * @klass: a #GObjectClass to cast. * * Cast the given @klass into #VisuPlaneSetClass. */ #define VISU_PLANE_SET_CLASS(klass) (G_TYPE_CHECK_CLASS_CAST(klass, VISU_TYPE_PLANE_SET, VisuPlaneSetClass)) /** * VISU_IS_PLANE_SET: * @obj: a #GObject to test. * * Test if the given @ogj is of the type of #VisuPlaneSet object. */ #define VISU_IS_PLANE_SET(obj) (G_TYPE_CHECK_INSTANCE_TYPE(obj, VISU_TYPE_PLANE_SET)) /** * VISU_IS_PLANE_SET_CLASS: * @klass: a #GObjectClass to test. * * Test if the given @klass is of the type of #VisuPlaneSetClass class. */ #define VISU_IS_PLANE_SET_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE(klass, VISU_TYPE_PLANE_SET)) /** * VISU_PLANE_SET_GET_CLASS: * @obj: a #GObject to get the class of. * * It returns the class of the given @obj. */ #define VISU_PLANE_SET_GET_CLASS(obj) (G_TYPE_INSTANCE_GET_CLASS(obj, VISU_TYPE_PLANE_SET, VisuPlaneSetClass)) /** * VisuPlaneSetPrivate: * * Private data for #VisuPlaneSet objects. */ typedef struct _VisuPlaneSetPrivate VisuPlaneSetPrivate; /** * VisuPlaneSet: * * Common name to refer to a #_VisuPlaneSet. */ typedef struct _VisuPlaneSet VisuPlaneSet; struct _VisuPlaneSet { VisuObject parent; VisuPlaneSetPrivate *priv; }; /** * VisuPlaneSetClass: * @parent: private. * * Common name to refer to a #_VisuPlaneSetClass. */ typedef struct _VisuPlaneSetClass VisuPlaneSetClass; struct _VisuPlaneSetClass { VisuObjectClass parent; }; /** * visu_plane_set_get_type: * * This method returns the type of #VisuPlaneSet, use * VISU_TYPE_PLANE_SET instead. * * Since: 3.8 * * Returns: the type of #VisuPlaneSet. */ GType visu_plane_set_get_type(void); /** * VisuPlaneSetItemNew: * @plane: a #VisuPlane object. * @data: some user data. * * A method to generate a new plane item in the plane set for * @plane. This method is called to encapsulate @plane when @plane is * added to the plane set. * * Since: 3.8 */ typedef gpointer (*VisuPlaneSetItemNew)(VisuPlane *plane, gpointer data); /** * VisuPlaneSetItemFree: * @plane: a #VisuPlane object. * @data: some user data. * * A method to free a given plane item in the plane set for * @plane. This method is called when @plane is removed from the plane set. * * Since: 3.8 */ typedef void (*VisuPlaneSetItemFree)(VisuPlane *plane, gpointer data); VisuPlaneSet* visu_plane_set_new(); VisuPlaneSet* visu_plane_set_newFull(VisuPlaneSetItemNew newItem, VisuPlaneSetItemFree freeItem, gpointer data); gboolean visu_plane_set_add(VisuPlaneSet *set, VisuPlane *plane); gboolean visu_plane_set_remove(VisuPlaneSet *set, VisuPlane *plane); gboolean visu_plane_set_removeAll(VisuPlaneSet *set); VisuPlane* visu_plane_set_getAt(const VisuPlaneSet *set, guint i); typedef struct _VisuPlaneSetIter VisuPlaneSetIter; struct _VisuPlaneSetIter { const VisuPlaneSet *set; VisuPlane *plane; GList *next; }; gboolean visu_plane_set_iter_new(const VisuPlaneSet *set, VisuPlaneSetIter *iter); gboolean visu_plane_set_iter_next(VisuPlaneSetIter *iter); gboolean visu_plane_set_getIntersection(const VisuPlaneSet *set, float pointA[3], float pointB[3], float inter[3], gboolean inside); /** * VisuPlaneSetHiddingEnum: * @VISU_PLANE_SET_HIDE_UNION: element are masked if one plane at least mask it ; * @VISU_PLANE_SET_HIDE_INTER: element are masked if all planes mask it ; * @VISU_PLANE_SET_HIDE_N_VALUES: number of masking possibilities. * * Enum used to address different hiding modes. See visu_plane_set_setHiddingMode() for * further details. */ typedef enum { VISU_PLANE_SET_HIDE_UNION, VISU_PLANE_SET_HIDE_INTER, VISU_PLANE_SET_HIDE_N_VALUES } VisuPlaneSetHiddingEnum; gboolean visu_plane_set_setHiddingMode(VisuPlaneSet *set, VisuPlaneSetHiddingEnum mode); gboolean visu_plane_set_getHiddingStatus(const VisuPlaneSet *set); gboolean visu_plane_set_getVisibility(const VisuPlaneSet *set, float point[3]); gboolean visu_plane_set_parseXMLFile(VisuPlaneSet *set, const gchar* filename, GError **error); gboolean visu_plane_set_exportXMLFile(const VisuPlaneSet *set, const gchar* filename, GError **error); #endif v_sim-3.8.0/src/extraFunctions/poleProp.c000066400000000000000000000250301370110300500203740ustar00rootroot00000000000000/* EXTRAITS DE LA LICENCE Copyright CEA, contributeurs : Damien CALISTE, laboratoire L_Sim, (2018) Adresse mèl : CALISTE, damien P caliste AT cea P fr. Ce logiciel est un programme informatique servant à visualiser des structures atomiques dans un rendu pseudo-3D. Ce logiciel est régi par la licence CeCILL soumise au droit français et respectant les principes de diffusion des logiciels libres. Vous pouvez utiliser, modifier et/ou redistribuer ce programme sous les conditions de la licence CeCILL telle que diffusée par le CEA, le CNRS et l'INRIA sur le site "http://www.cecill.info". Le fait que vous puissiez accéder à cet en-tête signifie que vous avez pris connaissance de la licence CeCILL, et que vous en avez accepté les termes (cf. le fichier Documentation/licence.fr.txt fourni avec ce logiciel). */ /* LICENCE SUM UP Copyright CEA, contributors : Damien CALISTE, laboratoire L_Sim, (2018) E-mail address: CALISTE, damien P caliste AT cea P fr. This software is a computer program whose purpose is to visualize atomic configurations in 3D. This software is governed by the CeCILL license under French law and abiding by the rules of distribution of free software. You can use, modify and/ or redistribute the software under the terms of the CeCILL license as circulated by CEA, CNRS and INRIA at the following URL "http://www.cecill.info". The fact that you are presently reading this means that you have had knowledge of the CeCILL license and that you accept its terms. You can find a copy of this licence shipped with this software at Documentation/licence.en.txt. */ #include "poleProp.h" #include #include #include #include /** * SECTION:poleProp * @short_description: define a #VisuNodeValues object to handle * multipole node information. * * Defines a #VisuNodeValues object to store a pole * information on nodes. */ static gboolean _parse(VisuNodeValues *vals, VisuNode *node, const gchar *from); static gchar* _serialize(const VisuNodeValues *vals, const VisuNode *node); G_DEFINE_TYPE(VisuNodeValuesPole, visu_node_values_pole, VISU_TYPE_NODE_VALUES_FARRAY) static void visu_node_values_pole_class_init(VisuNodeValuesPoleClass *klass) { /* Connect the overloading methods. */ VISU_NODE_VALUES_CLASS(klass)->parse = _parse; VISU_NODE_VALUES_CLASS(klass)->serialize = _serialize; } static void visu_node_values_pole_init(VisuNodeValuesPole *self _U_) { } static gboolean _parse(VisuNodeValues *vals, VisuNode *node, const gchar *from) { gfloat data[9]; GValue value = G_VALUE_INIT; PosinpDict *dict; guint i; g_return_val_if_fail(from, FALSE); dict = posinp_yaml_parse_properties(from, NULL); if (!dict) return FALSE; memset(vals, '\0', sizeof(gfloat) * 9); for (i = 0; i < dict->len && dict->items[i].key; i++) if (!strcmp(dict->items[i].key, "q0") && dict->items[i].type == POSINP_TYPE_DBL_ARR && dict->items[i].value.darr.len == 1) data[0] = dict->items[i].value.darr.arr[0]; else if (!strcmp(dict->items[i].key, "q1") && dict->items[i].type == POSINP_TYPE_DBL_ARR && dict->items[i].value.darr.len == 3) { data[1] = dict->items[i].value.darr.arr[0]; data[2] = dict->items[i].value.darr.arr[1]; data[3] = dict->items[i].value.darr.arr[2]; } else if (!strcmp(dict->items[i].key, "q2") && dict->items[i].type == POSINP_TYPE_DBL_ARR && dict->items[i].value.darr.len == 5) { data[4] = dict->items[i].value.darr.arr[0]; data[5] = dict->items[i].value.darr.arr[1]; data[6] = dict->items[i].value.darr.arr[2]; data[7] = dict->items[i].value.darr.arr[3]; data[8] = dict->items[i].value.darr.arr[4]; } posinp_yaml_free_properties(dict); g_value_set_pointer(&value, data); return visu_node_values_setAt(vals, node, &value); } static gchar* _serialize(const VisuNodeValues *vals, const VisuNode *node) { GValue value = G_VALUE_INIT; gfloat *fvals; if (!visu_node_values_getAt(vals, node, &value)) return (gchar*)0; fvals = (float*)g_value_get_pointer(&value); if (fvals) return g_strdup_printf("q0: [%#.3g]\nq1: [%#.3g, %#.3g, %#.3g]\nq2: [%#.3g, %#.3g, %#.3g, %#.3g, %#.3g]", fvals[0], fvals[1], fvals[2], fvals[3], fvals[4], fvals[5], fvals[6], fvals[7], fvals[8]); else return (gchar*)0; } /** * visu_node_values_pole_new: * @arr: a #VisuNodeArray object. * @label: a translatable label. * * Create a new pole field located on nodes. * * Since: 3.8 * * Returns: (transfer full): a newly created #VisuNodeValuesPole object. **/ VisuNodeValuesPole* visu_node_values_pole_new(VisuNodeArray *arr, const gchar *label) { VisuNodeValuesPole *vals; vals = VISU_NODE_VALUES_POLE(g_object_new(VISU_TYPE_NODE_VALUES_POLE, "nodes", arr, "label", label, "type", G_TYPE_FLOAT, "n-elements", 9, NULL)); return vals; } static const gfloat zmono[1] = {0.f}; static const gfloat zdi[3] = {0.f, 0.f, 0.f}; static const gfloat zquad[5] = {0.f, 0.f, 0.f, 0.f, 0.f}; /** * visu_node_values_pole_getAt: * @pole: a #VisuNodeValuesPole object. * @node: a #VisuNode object. * @order: a #VisuPoleOrder value. * * Retrieves the pole hosted on @node. * * Since: 3.8 * * Returns: (array fixed-size=3) (transfer none): the coordinates of * pole for @node. **/ const gfloat* visu_node_values_pole_getAt(const VisuNodeValuesPole *pole, const VisuNode *node, VisuPoleOrder order) { GValue diffValue = G_VALUE_INIT; const gfloat *diff; diff = (const gfloat*)0; if (visu_node_values_getAt(VISU_NODE_VALUES(pole), node, &diffValue)) diff = (const gfloat*)g_value_get_pointer(&diffValue); switch (order) { case VISU_MONOPOLE: return (diff) ? diff : zmono; case VISU_DIPOLE: return (diff) ? diff + 1: zdi; case VISU_QUADRUPOLE: return (diff) ? diff + 4: zquad; default: return (const gfloat*)0; } } /** * visu_node_values_pole_setMonoAt: * @pole: a #VisuNodeValuesPole object. * @node: a #VisuNode object. * @val: a mono-pole value. * * Changes the mono-pole hosted at @node. * * Since: 3.8 * * Returns: TRUE if pole for @node is indeed changed. **/ gboolean visu_node_values_pole_setMonoAt(VisuNodeValuesPole *pole, const VisuNode *node, gfloat val) { gfloat *vals, poles[9]; GValue gval = G_VALUE_INIT; visu_node_values_getAt(VISU_NODE_VALUES(pole), node, &gval); vals = (gfloat*)g_value_get_pointer(&gval); if (vals && vals[0] == val) return FALSE; if (!vals) { vals = poles; memset(poles, '\0', sizeof(gfloat) * 9); } vals[0] = val; g_value_set_pointer(&gval, vals); return visu_node_values_setAt(VISU_NODE_VALUES(pole), node, &gval); } /** * visu_node_values_pole_setMonoAtDbl: * @pole: a #VisuNodeValuesPole object. * @node: a #VisuNode object. * @val: a mono-pole value. * * Changes the mono-pole hosted at @node. * * Since: 3.8 * * Returns: TRUE if pole for @node is indeed changed. **/ gboolean visu_node_values_pole_setMonoAtDbl(VisuNodeValuesPole *pole, const VisuNode *node, gdouble val) { return visu_node_values_pole_setMonoAt(pole, node, val); } /** * visu_node_values_pole_setDiAt: * @pole: a #VisuNodeValuesPole object. * @node: a #VisuNode object. * @val: a di-pole value. * * Changes the di-pole hosted at @node. * * Since: 3.8 * * Returns: TRUE if pole for @node is indeed changed. **/ gboolean visu_node_values_pole_setDiAt(VisuNodeValuesPole *pole, const VisuNode *node, const gfloat val[3]) { gfloat *vals, poles[9]; GValue gval = G_VALUE_INIT; visu_node_values_getAt(VISU_NODE_VALUES(pole), node, &gval); vals = (gfloat*)g_value_get_pointer(&gval); if (vals && vals[1] == val[0] && vals[2] == val[1] && vals[3] == val[2]) return FALSE; if (!vals) { vals = poles; memset(poles, '\0', sizeof(gfloat) * 9); } vals[1] = val[0]; vals[2] = val[1]; vals[3] = val[2]; g_value_set_pointer(&gval, vals); return visu_node_values_setAt(VISU_NODE_VALUES(pole), node, &gval); } /** * visu_node_values_pole_setDiAtDbl: * @pole: a #VisuNodeValuesPole object. * @node: a #VisuNode object. * @val: a di-pole value. * * Changes the di-pole hosted at @node. * * Since: 3.8 * * Returns: TRUE if pole for @node is indeed changed. **/ gboolean visu_node_values_pole_setDiAtDbl(VisuNodeValuesPole *pole, const VisuNode *node, const gdouble val[3]) { gfloat fval[3]; fval[0] = val[0]; fval[1] = val[1]; fval[2] = val[2]; return visu_node_values_pole_setDiAt(pole, node, fval); } /** * visu_node_values_pole_setQuadAt: * @pole: a #VisuNodeValuesPole object. * @node: a #VisuNode object. * @val: a quadru-pole value. * * Changes the quadru-pole hosted at @node. * * Since: 3.8 * * Returns: TRUE if pole for @node is indeed changed. **/ gboolean visu_node_values_pole_setQuadAt(VisuNodeValuesPole *pole, const VisuNode *node, const gfloat val[5]) { gfloat *vals, poles[9]; GValue gval = G_VALUE_INIT; visu_node_values_getAt(VISU_NODE_VALUES(pole), node, &gval); vals = (gfloat*)g_value_get_pointer(&gval); if (vals && vals[4] == val[0] && vals[5] == val[1] && vals[6] == val[2] && vals[7] == val[3] && vals[8] == val[4]) return FALSE; if (!vals) { vals = poles; memset(poles, '\0', sizeof(gfloat) * 9); } vals[4] = val[0]; vals[5] = val[1]; vals[6] = val[2]; vals[7] = val[3]; vals[8] = val[4]; g_value_set_pointer(&gval, vals); return visu_node_values_setAt(VISU_NODE_VALUES(pole), node, &gval); } /** * visu_node_values_pole_setQuadAtDbl: * @pole: a #VisuNodeValuesPole object. * @node: a #VisuNode object. * @val: a quadru-pole value. * * Changes the quadru-pole hosted at @node. * * Since: 3.8 * * Returns: TRUE if pole for @node is indeed changed. **/ gboolean visu_node_values_pole_setQuadAtDbl(VisuNodeValuesPole *pole, const VisuNode *node, const gdouble val[5]) { gfloat fval[5]; fval[0] = val[0]; fval[1] = val[1]; fval[2] = val[2]; fval[3] = val[3]; fval[4] = val[4]; return visu_node_values_pole_setQuadAt(pole, node, fval); } v_sim-3.8.0/src/extraFunctions/poleProp.h000066400000000000000000000115011370110300500203770ustar00rootroot00000000000000/* EXTRAITS DE LA LICENCE Copyright CEA, contributeurs : Damien CALISTE, laboratoire L_Sim, (2018) Adresse mèl : CALISTE, damien P caliste AT cea P fr. Ce logiciel est un programme informatique servant à visualiser des structures atomiques dans un rendu pseudo-3D. Ce logiciel est régi par la licence CeCILL soumise au droit français et respectant les principes de diffusion des logiciels libres. Vous pouvez utiliser, modifier et/ou redistribuer ce programme sous les conditions de la licence CeCILL telle que diffusée par le CEA, le CNRS et l'INRIA sur le site "http://www.cecill.info". Le fait que vous puissiez accéder à cet en-tête signifie que vous avez pris connaissance de la licence CeCILL, et que vous en avez accepté les termes (cf. le fichier Documentation/licence.fr.txt fourni avec ce logiciel). */ /* LICENCE SUM UP Copyright CEA, contributors : Damien CALISTE, laboratoire L_Sim, (2018) E-mail address: CALISTE, damien P caliste AT cea P fr. This software is a computer program whose purpose is to visualize atomic configurations in 3D. This software is governed by the CeCILL license under French law and abiding by the rules of distribution of free software. You can use, modify and/ or redistribute the software under the terms of the CeCILL license as circulated by CEA, CNRS and INRIA at the following URL "http://www.cecill.info". The fact that you are presently reading this means that you have had knowledge of the CeCILL license and that you accept its terms. You can find a copy of this licence shipped with this software at Documentation/licence.en.txt. */ #ifndef POLEPROP_H #define POLEPROP_H #include #include #include "floatProp.h" G_BEGIN_DECLS #define VISU_TYPE_NODE_VALUES_POLE (visu_node_values_pole_get_type ()) #define VISU_NODE_VALUES_POLE(obj) (G_TYPE_CHECK_INSTANCE_CAST(obj, VISU_TYPE_NODE_VALUES_POLE, VisuNodeValuesPole)) #define VISU_NODE_VALUES_POLE_CLASS(klass) (G_TYPE_CHECK_CLASS_CAST(klass, VISU_TYPE_NODE_VALUES_POLE, VisuNodeValuesPoleClass)) #define VISU_IS_NODE_VALUES_POLE_TYPE(obj) (G_TYPE_CHECK_INSTANCE_TYPE(obj, VISU_TYPE_NODE_VALUES_POLE)) #define VISU_IS_NODE_VALUES_POLE_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE(klass, VISU_TYPE_NODE_VALUES_POLE)) #define VISU_NODE_VALUES_POLE_GET_CLASS(obj) (G_TYPE_INSTANCE_GET_CLASS(obj, VISU_TYPE_NODE_VALUES_POLE, VisuNodeValuesPoleClass)) /** * VisuNodeValuesPole: * * Common name to refer to a #_VisuNodeValuesPole. */ typedef struct _VisuNodeValuesPole VisuNodeValuesPole; struct _VisuNodeValuesPole { VisuNodeValuesFarray parent; }; /** * VisuNodeValuesPoleClass: * @parent: private. * * Common name to refer to a #_VisuNodeValuesPoleClass. */ typedef struct _VisuNodeValuesPoleClass VisuNodeValuesPoleClass; struct _VisuNodeValuesPoleClass { VisuNodeValuesFarrayClass parent; }; /** * visu_node_values_pole_get_type: * * This method returns the type of #VisuNodeValuesPole, use * VISU_TYPE_NODE_VALUES_POLE instead. * * Since: 3.8 * * Returns: the type of #VisuNodeValuesPole. */ GType visu_node_values_pole_get_type(void); /** * VisuPoleOrder: * @VISU_MONOPOLE: a mono-pole. * @VISU_DIPOLE: a di-pole. * @VISU_QUADRUPOLE: a quadru-pole. * * Various pole orders. * * Since: 3.8 */ typedef enum { VISU_MONOPOLE, VISU_DIPOLE, VISU_QUADRUPOLE, } VisuPoleOrder; VisuNodeValuesPole* visu_node_values_pole_new(VisuNodeArray *arr, const gchar *label); const gfloat* visu_node_values_pole_getAt(const VisuNodeValuesPole *pole, const VisuNode *node, VisuPoleOrder order); gboolean visu_node_values_pole_setMonoAt(VisuNodeValuesPole *pole, const VisuNode *node, gfloat val); gboolean visu_node_values_pole_setDiAt(VisuNodeValuesPole *pole, const VisuNode *node, const gfloat val[3]); gboolean visu_node_values_pole_setQuadAt(VisuNodeValuesPole *pole, const VisuNode *node, const gfloat val[5]); gboolean visu_node_values_pole_setMonoAtDbl(VisuNodeValuesPole *pole, const VisuNode *node, gdouble val); gboolean visu_node_values_pole_setDiAtDbl(VisuNodeValuesPole *pole, const VisuNode *node, const gdouble val[3]); gboolean visu_node_values_pole_setQuadAtDbl(VisuNodeValuesPole *pole, const VisuNode *node, const gdouble val[5]); G_END_DECLS #endif v_sim-3.8.0/src/extraFunctions/pot2surf.c000066400000000000000000002302611370110300500203640ustar00rootroot00000000000000/* EXTRAITS DE LA LICENCE Copyright CEA, contributeurs : Luc BILLARD, Damien CALISTE, Olivier D'Astier, laboratoire L_Sim, (2001-2005) Adresse mèl : BILLARD, non joignable par mèl ; CALISTE, damien P caliste AT cea P fr. D'ASTIER, dastier AT iie P cnam P fr. Ce logiciel est un programme informatique servant à visualiser des structures atomiques dans un rendu pseudo-3D. Ce logiciel est régi par la licence CeCILL soumise au droit français et respectant les principes de diffusion des logiciels libres. Vous pouvez utiliser, modifier et/ou redistribuer ce programme sous les conditions de la licence CeCILL telle que diffusée par le CEA, le CNRS et l'INRIA sur le site "http://www.cecill.info". Le fait que vous puissiez accéder à cet en-tête signifie que vous avez pris connaissance de la licence CeCILL, et que vous en avez accepté les termes (cf. le fichier Documentation/licence.fr.txt fourni avec ce logiciel). */ /* LICENCE SUM UP Copyright CEA, contributors : Luc BILLARD and Damien CALISTE and Olivier D'Astier, laboratoire L_Sim, (2001-2005) E-mail addresses : BILLARD, not reachable any more ; CALISTE, damien P caliste AT cea P fr. D'ASTIER, dastier AT iie P cnam P fr. This software is a computer program whose purpose is to visualize atomic configurations in 3D. This software is governed by the CeCILL license under French law and abiding by the rules of distribution of free software. You can use, modify and/ or redistribute the software under the terms of the CeCILL license as circulated by CEA, CNRS and INRIA at the following URL "http://www.cecill.info". The fact that you are presently reading this means that you have had knowledge of the CeCILL license and that you accept its terms. You can find a copy of this licence shipped with this software at Documentation/licence.en.txt. */ #include #include #include #include #include #include #include "surfaces.h" #include "pot2surf.h" /** * SECTION:pot2surf * @short_description: Creates surfaces from scalar fields. * * Originally written by Luc Billard for his program * VISUALISE. It has been since transformed to a single function and * integrated in V_Sim. .pot file are text files which specification * are the following : * * 1st line: full pathname of the potential file to * read * 2nd line: full pathname of the surface file to * build * 3rd line: an integer giving the nbr n of * isosurfaces to build * Each of the n following lines must match the * pattern [value name] where value is a real number for the isovalue * and name is the name given for the corresponding isosurface to * build. Each surface should be named surface_*. * * The function will fail if it finds no isosurface corresponding to * some of the given isovalues. The panelSurfacesTools * contains a frontend to build valid .instruc files. This panel is * originally integrated in V_Sim. You can access it through the * Convert tab in the Isosurfaces panel. */ #define ISOSURFACES_FLAG_POTENTIAL "# potentialValue" static int nx, ny, nz; static double dxx, dyx, dyy, dzx, dzy, dzz; static double exx, eyx, eyy, ezx, ezy, ezz; static int nxm1, nym1, nzm1; static int nz3, nyz3, nxyz3; static double dxx1, dyx1, dyy1, dzx1, dzy1, dzz1; static double ***f = NULL; static double isovalue; static FILE *in = NULL; static int *itab = NULL; static double *xs = NULL, *ys = NULL, *zs = NULL, *xns = NULL, *yns = NULL, *zns = NULL; static gboolean create_fromSF_uniform(VisuSurface **surf, const VisuScalarField *field, double isoValue, const gchar *name); static gboolean create_fromSF_nonuniform(VisuSurface **surf, const VisuScalarField *field, double isoValue, const gchar *name); static gboolean Create_surf(int nelez3, int neleyz3, int nelexyz3, guint sizem1[3], int *iTab, GArray *points, double isoValue, const VisuScalarField *field, double scalarBox[6], const gchar *name, VisuSurface **surf); /* Tables from : http://www.swin.edu.au/astronomy/pbourke/modelling/polygonise/index.html (valid link on February 25, 2002) YOU WILL FIND MANY VERY INTERESTING PAGES at Paul Bourke's site: http://astronomy.swin.edu.au/pbourke/ Other routines by Luc Billard, on March 1, 2002 */ static int edgeTable[256]={ 0x0 , 0x109, 0x203, 0x30a, 0x406, 0x50f, 0x605, 0x70c, 0x80c, 0x905, 0xa0f, 0xb06, 0xc0a, 0xd03, 0xe09, 0xf00, 0x190, 0x99 , 0x393, 0x29a, 0x596, 0x49f, 0x795, 0x69c, 0x99c, 0x895, 0xb9f, 0xa96, 0xd9a, 0xc93, 0xf99, 0xe90, 0x230, 0x339, 0x33 , 0x13a, 0x636, 0x73f, 0x435, 0x53c, 0xa3c, 0xb35, 0x83f, 0x936, 0xe3a, 0xf33, 0xc39, 0xd30, 0x3a0, 0x2a9, 0x1a3, 0xaa , 0x7a6, 0x6af, 0x5a5, 0x4ac, 0xbac, 0xaa5, 0x9af, 0x8a6, 0xfaa, 0xea3, 0xda9, 0xca0, 0x460, 0x569, 0x663, 0x76a, 0x66 , 0x16f, 0x265, 0x36c, 0xc6c, 0xd65, 0xe6f, 0xf66, 0x86a, 0x963, 0xa69, 0xb60, 0x5f0, 0x4f9, 0x7f3, 0x6fa, 0x1f6, 0xff , 0x3f5, 0x2fc, 0xdfc, 0xcf5, 0xfff, 0xef6, 0x9fa, 0x8f3, 0xbf9, 0xaf0, 0x650, 0x759, 0x453, 0x55a, 0x256, 0x35f, 0x55 , 0x15c, 0xe5c, 0xf55, 0xc5f, 0xd56, 0xa5a, 0xb53, 0x859, 0x950, 0x7c0, 0x6c9, 0x5c3, 0x4ca, 0x3c6, 0x2cf, 0x1c5, 0xcc , 0xfcc, 0xec5, 0xdcf, 0xcc6, 0xbca, 0xac3, 0x9c9, 0x8c0, 0x8c0, 0x9c9, 0xac3, 0xbca, 0xcc6, 0xdcf, 0xec5, 0xfcc, 0xcc , 0x1c5, 0x2cf, 0x3c6, 0x4ca, 0x5c3, 0x6c9, 0x7c0, 0x950, 0x859, 0xb53, 0xa5a, 0xd56, 0xc5f, 0xf55, 0xe5c, 0x15c, 0x55 , 0x35f, 0x256, 0x55a, 0x453, 0x759, 0x650, 0xaf0, 0xbf9, 0x8f3, 0x9fa, 0xef6, 0xfff, 0xcf5, 0xdfc, 0x2fc, 0x3f5, 0xff , 0x1f6, 0x6fa, 0x7f3, 0x4f9, 0x5f0, 0xb60, 0xa69, 0x963, 0x86a, 0xf66, 0xe6f, 0xd65, 0xc6c, 0x36c, 0x265, 0x16f, 0x66 , 0x76a, 0x663, 0x569, 0x460, 0xca0, 0xda9, 0xea3, 0xfaa, 0x8a6, 0x9af, 0xaa5, 0xbac, 0x4ac, 0x5a5, 0x6af, 0x7a6, 0xaa , 0x1a3, 0x2a9, 0x3a0, 0xd30, 0xc39, 0xf33, 0xe3a, 0x936, 0x83f, 0xb35, 0xa3c, 0x53c, 0x435, 0x73f, 0x636, 0x13a, 0x33 , 0x339, 0x230, 0xe90, 0xf99, 0xc93, 0xd9a, 0xa96, 0xb9f, 0x895, 0x99c, 0x69c, 0x795, 0x49f, 0x596, 0x29a, 0x393, 0x99 , 0x190, 0xf00, 0xe09, 0xd03, 0xc0a, 0xb06, 0xa0f, 0x905, 0x80c, 0x70c, 0x605, 0x50f, 0x406, 0x30a, 0x203, 0x109, 0x0 }; static int triTable[256][16] = {{-1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1}, {0, 8, 3, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1}, {0, 1, 9, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1}, {1, 8, 3, 9, 8, 1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1}, {1, 2, 10, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1}, {0, 8, 3, 1, 2, 10, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1}, {9, 2, 10, 0, 2, 9, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1}, {2, 8, 3, 2, 10, 8, 10, 9, 8, -1, -1, -1, -1, -1, -1, -1}, {3, 11, 2, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1}, {0, 11, 2, 8, 11, 0, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1}, {1, 9, 0, 2, 3, 11, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1}, {1, 11, 2, 1, 9, 11, 9, 8, 11, -1, -1, -1, -1, -1, -1, -1}, {3, 10, 1, 11, 10, 3, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1}, {0, 10, 1, 0, 8, 10, 8, 11, 10, -1, -1, -1, -1, -1, -1, -1}, {3, 9, 0, 3, 11, 9, 11, 10, 9, -1, -1, -1, -1, -1, -1, -1}, {9, 8, 10, 10, 8, 11, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1}, {4, 7, 8, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1}, {4, 3, 0, 7, 3, 4, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1}, {0, 1, 9, 8, 4, 7, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1}, {4, 1, 9, 4, 7, 1, 7, 3, 1, -1, -1, -1, -1, -1, -1, -1}, {1, 2, 10, 8, 4, 7, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1}, {3, 4, 7, 3, 0, 4, 1, 2, 10, -1, -1, -1, -1, -1, -1, -1}, {9, 2, 10, 9, 0, 2, 8, 4, 7, -1, -1, -1, -1, -1, -1, -1}, {2, 10, 9, 2, 9, 7, 2, 7, 3, 7, 9, 4, -1, -1, -1, -1}, {8, 4, 7, 3, 11, 2, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1}, {11, 4, 7, 11, 2, 4, 2, 0, 4, -1, -1, -1, -1, -1, -1, -1}, {9, 0, 1, 8, 4, 7, 2, 3, 11, -1, -1, -1, -1, -1, -1, -1}, {4, 7, 11, 9, 4, 11, 9, 11, 2, 9, 2, 1, -1, -1, -1, -1}, {3, 10, 1, 3, 11, 10, 7, 8, 4, -1, -1, -1, -1, -1, -1, -1}, {1, 11, 10, 1, 4, 11, 1, 0, 4, 7, 11, 4, -1, -1, -1, -1}, {4, 7, 8, 9, 0, 11, 9, 11, 10, 11, 0, 3, -1, -1, -1, -1}, {4, 7, 11, 4, 11, 9, 9, 11, 10, -1, -1, -1, -1, -1, -1, -1}, {9, 5, 4, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1}, {9, 5, 4, 0, 8, 3, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1}, {0, 5, 4, 1, 5, 0, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1}, {8, 5, 4, 8, 3, 5, 3, 1, 5, -1, -1, -1, -1, -1, -1, -1}, {1, 2, 10, 9, 5, 4, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1}, {3, 0, 8, 1, 2, 10, 4, 9, 5, -1, -1, -1, -1, -1, -1, -1}, {5, 2, 10, 5, 4, 2, 4, 0, 2, -1, -1, -1, -1, -1, -1, -1}, {2, 10, 5, 3, 2, 5, 3, 5, 4, 3, 4, 8, -1, -1, -1, -1}, {9, 5, 4, 2, 3, 11, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1}, {0, 11, 2, 0, 8, 11, 4, 9, 5, -1, -1, -1, -1, -1, -1, -1}, {0, 5, 4, 0, 1, 5, 2, 3, 11, -1, -1, -1, -1, -1, -1, -1}, {2, 1, 5, 2, 5, 8, 2, 8, 11, 4, 8, 5, -1, -1, -1, -1}, {10, 3, 11, 10, 1, 3, 9, 5, 4, -1, -1, -1, -1, -1, -1, -1}, {4, 9, 5, 0, 8, 1, 8, 10, 1, 8, 11, 10, -1, -1, -1, -1}, {5, 4, 0, 5, 0, 11, 5, 11, 10, 11, 0, 3, -1, -1, -1, -1}, {5, 4, 8, 5, 8, 10, 10, 8, 11, -1, -1, -1, -1, -1, -1, -1}, {9, 7, 8, 5, 7, 9, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1}, {9, 3, 0, 9, 5, 3, 5, 7, 3, -1, -1, -1, -1, -1, -1, -1}, {0, 7, 8, 0, 1, 7, 1, 5, 7, -1, -1, -1, -1, -1, -1, -1}, {1, 5, 3, 3, 5, 7, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1}, {9, 7, 8, 9, 5, 7, 10, 1, 2, -1, -1, -1, -1, -1, -1, -1}, {10, 1, 2, 9, 5, 0, 5, 3, 0, 5, 7, 3, -1, -1, -1, -1}, {8, 0, 2, 8, 2, 5, 8, 5, 7, 10, 5, 2, -1, -1, -1, -1}, {2, 10, 5, 2, 5, 3, 3, 5, 7, -1, -1, -1, -1, -1, -1, -1}, {7, 9, 5, 7, 8, 9, 3, 11, 2, -1, -1, -1, -1, -1, -1, -1}, {9, 5, 7, 9, 7, 2, 9, 2, 0, 2, 7, 11, -1, -1, -1, -1}, {2, 3, 11, 0, 1, 8, 1, 7, 8, 1, 5, 7, -1, -1, -1, -1}, {11, 2, 1, 11, 1, 7, 7, 1, 5, -1, -1, -1, -1, -1, -1, -1}, {9, 5, 8, 8, 5, 7, 10, 1, 3, 10, 3, 11, -1, -1, -1, -1}, {5, 7, 0, 5, 0, 9, 7, 11, 0, 1, 0, 10, 11, 10, 0, -1}, {11, 10, 0, 11, 0, 3, 10, 5, 0, 8, 0, 7, 5, 7, 0, -1}, {11, 10, 5, 7, 11, 5, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1}, {10, 6, 5, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1}, {0, 8, 3, 5, 10, 6, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1}, {9, 0, 1, 5, 10, 6, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1}, {1, 8, 3, 1, 9, 8, 5, 10, 6, -1, -1, -1, -1, -1, -1, -1}, {1, 6, 5, 2, 6, 1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1}, {1, 6, 5, 1, 2, 6, 3, 0, 8, -1, -1, -1, -1, -1, -1, -1}, {9, 6, 5, 9, 0, 6, 0, 2, 6, -1, -1, -1, -1, -1, -1, -1}, {5, 9, 8, 5, 8, 2, 5, 2, 6, 3, 2, 8, -1, -1, -1, -1}, {2, 3, 11, 10, 6, 5, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1}, {11, 0, 8, 11, 2, 0, 10, 6, 5, -1, -1, -1, -1, -1, -1, -1}, {0, 1, 9, 2, 3, 11, 5, 10, 6, -1, -1, -1, -1, -1, -1, -1}, {5, 10, 6, 1, 9, 2, 9, 11, 2, 9, 8, 11, -1, -1, -1, -1}, {6, 3, 11, 6, 5, 3, 5, 1, 3, -1, -1, -1, -1, -1, -1, -1}, {0, 8, 11, 0, 11, 5, 0, 5, 1, 5, 11, 6, -1, -1, -1, -1}, {3, 11, 6, 0, 3, 6, 0, 6, 5, 0, 5, 9, -1, -1, -1, -1}, {6, 5, 9, 6, 9, 11, 11, 9, 8, -1, -1, -1, -1, -1, -1, -1}, {5, 10, 6, 4, 7, 8, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1}, {4, 3, 0, 4, 7, 3, 6, 5, 10, -1, -1, -1, -1, -1, -1, -1}, {1, 9, 0, 5, 10, 6, 8, 4, 7, -1, -1, -1, -1, -1, -1, -1}, {10, 6, 5, 1, 9, 7, 1, 7, 3, 7, 9, 4, -1, -1, -1, -1}, {6, 1, 2, 6, 5, 1, 4, 7, 8, -1, -1, -1, -1, -1, -1, -1}, {1, 2, 5, 5, 2, 6, 3, 0, 4, 3, 4, 7, -1, -1, -1, -1}, {8, 4, 7, 9, 0, 5, 0, 6, 5, 0, 2, 6, -1, -1, -1, -1}, {7, 3, 9, 7, 9, 4, 3, 2, 9, 5, 9, 6, 2, 6, 9, -1}, {3, 11, 2, 7, 8, 4, 10, 6, 5, -1, -1, -1, -1, -1, -1, -1}, {5, 10, 6, 4, 7, 2, 4, 2, 0, 2, 7, 11, -1, -1, -1, -1}, {0, 1, 9, 4, 7, 8, 2, 3, 11, 5, 10, 6, -1, -1, -1, -1}, {9, 2, 1, 9, 11, 2, 9, 4, 11, 7, 11, 4, 5, 10, 6, -1}, {8, 4, 7, 3, 11, 5, 3, 5, 1, 5, 11, 6, -1, -1, -1, -1}, {5, 1, 11, 5, 11, 6, 1, 0, 11, 7, 11, 4, 0, 4, 11, -1}, {0, 5, 9, 0, 6, 5, 0, 3, 6, 11, 6, 3, 8, 4, 7, -1}, {6, 5, 9, 6, 9, 11, 4, 7, 9, 7, 11, 9, -1, -1, -1, -1}, {10, 4, 9, 6, 4, 10, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1}, {4, 10, 6, 4, 9, 10, 0, 8, 3, -1, -1, -1, -1, -1, -1, -1}, {10, 0, 1, 10, 6, 0, 6, 4, 0, -1, -1, -1, -1, -1, -1, -1}, {8, 3, 1, 8, 1, 6, 8, 6, 4, 6, 1, 10, -1, -1, -1, -1}, {1, 4, 9, 1, 2, 4, 2, 6, 4, -1, -1, -1, -1, -1, -1, -1}, {3, 0, 8, 1, 2, 9, 2, 4, 9, 2, 6, 4, -1, -1, -1, -1}, {0, 2, 4, 4, 2, 6, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1}, {8, 3, 2, 8, 2, 4, 4, 2, 6, -1, -1, -1, -1, -1, -1, -1}, {10, 4, 9, 10, 6, 4, 11, 2, 3, -1, -1, -1, -1, -1, -1, -1}, {0, 8, 2, 2, 8, 11, 4, 9, 10, 4, 10, 6, -1, -1, -1, -1}, {3, 11, 2, 0, 1, 6, 0, 6, 4, 6, 1, 10, -1, -1, -1, -1}, {6, 4, 1, 6, 1, 10, 4, 8, 1, 2, 1, 11, 8, 11, 1, -1}, {9, 6, 4, 9, 3, 6, 9, 1, 3, 11, 6, 3, -1, -1, -1, -1}, {8, 11, 1, 8, 1, 0, 11, 6, 1, 9, 1, 4, 6, 4, 1, -1}, {3, 11, 6, 3, 6, 0, 0, 6, 4, -1, -1, -1, -1, -1, -1, -1}, {6, 4, 8, 11, 6, 8, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1}, {7, 10, 6, 7, 8, 10, 8, 9, 10, -1, -1, -1, -1, -1, -1, -1}, {0, 7, 3, 0, 10, 7, 0, 9, 10, 6, 7, 10, -1, -1, -1, -1}, {10, 6, 7, 1, 10, 7, 1, 7, 8, 1, 8, 0, -1, -1, -1, -1}, {10, 6, 7, 10, 7, 1, 1, 7, 3, -1, -1, -1, -1, -1, -1, -1}, {1, 2, 6, 1, 6, 8, 1, 8, 9, 8, 6, 7, -1, -1, -1, -1}, {2, 6, 9, 2, 9, 1, 6, 7, 9, 0, 9, 3, 7, 3, 9, -1}, {7, 8, 0, 7, 0, 6, 6, 0, 2, -1, -1, -1, -1, -1, -1, -1}, {7, 3, 2, 6, 7, 2, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1}, {2, 3, 11, 10, 6, 8, 10, 8, 9, 8, 6, 7, -1, -1, -1, -1}, {2, 0, 7, 2, 7, 11, 0, 9, 7, 6, 7, 10, 9, 10, 7, -1}, {1, 8, 0, 1, 7, 8, 1, 10, 7, 6, 7, 10, 2, 3, 11, -1}, {11, 2, 1, 11, 1, 7, 10, 6, 1, 6, 7, 1, -1, -1, -1, -1}, {8, 9, 6, 8, 6, 7, 9, 1, 6, 11, 6, 3, 1, 3, 6, -1}, {0, 9, 1, 11, 6, 7, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1}, {7, 8, 0, 7, 0, 6, 3, 11, 0, 11, 6, 0, -1, -1, -1, -1}, {7, 11, 6, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1}, {7, 6, 11, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1}, {3, 0, 8, 11, 7, 6, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1}, {0, 1, 9, 11, 7, 6, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1}, {8, 1, 9, 8, 3, 1, 11, 7, 6, -1, -1, -1, -1, -1, -1, -1}, {10, 1, 2, 6, 11, 7, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1}, {1, 2, 10, 3, 0, 8, 6, 11, 7, -1, -1, -1, -1, -1, -1, -1}, {2, 9, 0, 2, 10, 9, 6, 11, 7, -1, -1, -1, -1, -1, -1, -1}, {6, 11, 7, 2, 10, 3, 10, 8, 3, 10, 9, 8, -1, -1, -1, -1}, {7, 2, 3, 6, 2, 7, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1}, {7, 0, 8, 7, 6, 0, 6, 2, 0, -1, -1, -1, -1, -1, -1, -1}, {2, 7, 6, 2, 3, 7, 0, 1, 9, -1, -1, -1, -1, -1, -1, -1}, {1, 6, 2, 1, 8, 6, 1, 9, 8, 8, 7, 6, -1, -1, -1, -1}, {10, 7, 6, 10, 1, 7, 1, 3, 7, -1, -1, -1, -1, -1, -1, -1}, {10, 7, 6, 1, 7, 10, 1, 8, 7, 1, 0, 8, -1, -1, -1, -1}, {0, 3, 7, 0, 7, 10, 0, 10, 9, 6, 10, 7, -1, -1, -1, -1}, {7, 6, 10, 7, 10, 8, 8, 10, 9, -1, -1, -1, -1, -1, -1, -1}, {6, 8, 4, 11, 8, 6, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1}, {3, 6, 11, 3, 0, 6, 0, 4, 6, -1, -1, -1, -1, -1, -1, -1}, {8, 6, 11, 8, 4, 6, 9, 0, 1, -1, -1, -1, -1, -1, -1, -1}, {9, 4, 6, 9, 6, 3, 9, 3, 1, 11, 3, 6, -1, -1, -1, -1}, {6, 8, 4, 6, 11, 8, 2, 10, 1, -1, -1, -1, -1, -1, -1, -1}, {1, 2, 10, 3, 0, 11, 0, 6, 11, 0, 4, 6, -1, -1, -1, -1}, {4, 11, 8, 4, 6, 11, 0, 2, 9, 2, 10, 9, -1, -1, -1, -1}, {10, 9, 3, 10, 3, 2, 9, 4, 3, 11, 3, 6, 4, 6, 3, -1}, {8, 2, 3, 8, 4, 2, 4, 6, 2, -1, -1, -1, -1, -1, -1, -1}, {0, 4, 2, 4, 6, 2, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1}, {1, 9, 0, 2, 3, 4, 2, 4, 6, 4, 3, 8, -1, -1, -1, -1}, {1, 9, 4, 1, 4, 2, 2, 4, 6, -1, -1, -1, -1, -1, -1, -1}, {8, 1, 3, 8, 6, 1, 8, 4, 6, 6, 10, 1, -1, -1, -1, -1}, {10, 1, 0, 10, 0, 6, 6, 0, 4, -1, -1, -1, -1, -1, -1, -1}, {4, 6, 3, 4, 3, 8, 6, 10, 3, 0, 3, 9, 10, 9, 3, -1}, {10, 9, 4, 6, 10, 4, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1}, {4, 9, 5, 7, 6, 11, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1}, {0, 8, 3, 4, 9, 5, 11, 7, 6, -1, -1, -1, -1, -1, -1, -1}, {5, 0, 1, 5, 4, 0, 7, 6, 11, -1, -1, -1, -1, -1, -1, -1}, {11, 7, 6, 8, 3, 4, 3, 5, 4, 3, 1, 5, -1, -1, -1, -1}, {9, 5, 4, 10, 1, 2, 7, 6, 11, -1, -1, -1, -1, -1, -1, -1}, {6, 11, 7, 1, 2, 10, 0, 8, 3, 4, 9, 5, -1, -1, -1, -1}, {7, 6, 11, 5, 4, 10, 4, 2, 10, 4, 0, 2, -1, -1, -1, -1}, {3, 4, 8, 3, 5, 4, 3, 2, 5, 10, 5, 2, 11, 7, 6, -1}, {7, 2, 3, 7, 6, 2, 5, 4, 9, -1, -1, -1, -1, -1, -1, -1}, {9, 5, 4, 0, 8, 6, 0, 6, 2, 6, 8, 7, -1, -1, -1, -1}, {3, 6, 2, 3, 7, 6, 1, 5, 0, 5, 4, 0, -1, -1, -1, -1}, {6, 2, 8, 6, 8, 7, 2, 1, 8, 4, 8, 5, 1, 5, 8, -1}, {9, 5, 4, 10, 1, 6, 1, 7, 6, 1, 3, 7, -1, -1, -1, -1}, {1, 6, 10, 1, 7, 6, 1, 0, 7, 8, 7, 0, 9, 5, 4, -1}, {4, 0, 10, 4, 10, 5, 0, 3, 10, 6, 10, 7, 3, 7, 10, -1}, {7, 6, 10, 7, 10, 8, 5, 4, 10, 4, 8, 10, -1, -1, -1, -1}, {6, 9, 5, 6, 11, 9, 11, 8, 9, -1, -1, -1, -1, -1, -1, -1}, {3, 6, 11, 0, 6, 3, 0, 5, 6, 0, 9, 5, -1, -1, -1, -1}, {0, 11, 8, 0, 5, 11, 0, 1, 5, 5, 6, 11, -1, -1, -1, -1}, {6, 11, 3, 6, 3, 5, 5, 3, 1, -1, -1, -1, -1, -1, -1, -1}, {1, 2, 10, 9, 5, 11, 9, 11, 8, 11, 5, 6, -1, -1, -1, -1}, {0, 11, 3, 0, 6, 11, 0, 9, 6, 5, 6, 9, 1, 2, 10, -1}, {11, 8, 5, 11, 5, 6, 8, 0, 5, 10, 5, 2, 0, 2, 5, -1}, {6, 11, 3, 6, 3, 5, 2, 10, 3, 10, 5, 3, -1, -1, -1, -1}, {5, 8, 9, 5, 2, 8, 5, 6, 2, 3, 8, 2, -1, -1, -1, -1}, {9, 5, 6, 9, 6, 0, 0, 6, 2, -1, -1, -1, -1, -1, -1, -1}, {1, 5, 8, 1, 8, 0, 5, 6, 8, 3, 8, 2, 6, 2, 8, -1}, {1, 5, 6, 2, 1, 6, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1}, {1, 3, 6, 1, 6, 10, 3, 8, 6, 5, 6, 9, 8, 9, 6, -1}, {10, 1, 0, 10, 0, 6, 9, 5, 0, 5, 6, 0, -1, -1, -1, -1}, {0, 3, 8, 5, 6, 10, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1}, {10, 5, 6, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1}, {11, 5, 10, 7, 5, 11, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1}, {11, 5, 10, 11, 7, 5, 8, 3, 0, -1, -1, -1, -1, -1, -1, -1}, {5, 11, 7, 5, 10, 11, 1, 9, 0, -1, -1, -1, -1, -1, -1, -1}, {10, 7, 5, 10, 11, 7, 9, 8, 1, 8, 3, 1, -1, -1, -1, -1}, {11, 1, 2, 11, 7, 1, 7, 5, 1, -1, -1, -1, -1, -1, -1, -1}, {0, 8, 3, 1, 2, 7, 1, 7, 5, 7, 2, 11, -1, -1, -1, -1}, {9, 7, 5, 9, 2, 7, 9, 0, 2, 2, 11, 7, -1, -1, -1, -1}, {7, 5, 2, 7, 2, 11, 5, 9, 2, 3, 2, 8, 9, 8, 2, -1}, {2, 5, 10, 2, 3, 5, 3, 7, 5, -1, -1, -1, -1, -1, -1, -1}, {8, 2, 0, 8, 5, 2, 8, 7, 5, 10, 2, 5, -1, -1, -1, -1}, {9, 0, 1, 5, 10, 3, 5, 3, 7, 3, 10, 2, -1, -1, -1, -1}, {9, 8, 2, 9, 2, 1, 8, 7, 2, 10, 2, 5, 7, 5, 2, -1}, {1, 3, 5, 3, 7, 5, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1}, {0, 8, 7, 0, 7, 1, 1, 7, 5, -1, -1, -1, -1, -1, -1, -1}, {9, 0, 3, 9, 3, 5, 5, 3, 7, -1, -1, -1, -1, -1, -1, -1}, {9, 8, 7, 5, 9, 7, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1}, {5, 8, 4, 5, 10, 8, 10, 11, 8, -1, -1, -1, -1, -1, -1, -1}, {5, 0, 4, 5, 11, 0, 5, 10, 11, 11, 3, 0, -1, -1, -1, -1}, {0, 1, 9, 8, 4, 10, 8, 10, 11, 10, 4, 5, -1, -1, -1, -1}, {10, 11, 4, 10, 4, 5, 11, 3, 4, 9, 4, 1, 3, 1, 4, -1}, {2, 5, 1, 2, 8, 5, 2, 11, 8, 4, 5, 8, -1, -1, -1, -1}, {0, 4, 11, 0, 11, 3, 4, 5, 11, 2, 11, 1, 5, 1, 11, -1}, {0, 2, 5, 0, 5, 9, 2, 11, 5, 4, 5, 8, 11, 8, 5, -1}, {9, 4, 5, 2, 11, 3, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1}, {2, 5, 10, 3, 5, 2, 3, 4, 5, 3, 8, 4, -1, -1, -1, -1}, {5, 10, 2, 5, 2, 4, 4, 2, 0, -1, -1, -1, -1, -1, -1, -1}, {3, 10, 2, 3, 5, 10, 3, 8, 5, 4, 5, 8, 0, 1, 9, -1}, {5, 10, 2, 5, 2, 4, 1, 9, 2, 9, 4, 2, -1, -1, -1, -1}, {8, 4, 5, 8, 5, 3, 3, 5, 1, -1, -1, -1, -1, -1, -1, -1}, {0, 4, 5, 1, 0, 5, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1}, {8, 4, 5, 8, 5, 3, 9, 0, 5, 0, 3, 5, -1, -1, -1, -1}, {9, 4, 5, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1}, {4, 11, 7, 4, 9, 11, 9, 10, 11, -1, -1, -1, -1, -1, -1, -1}, {0, 8, 3, 4, 9, 7, 9, 11, 7, 9, 10, 11, -1, -1, -1, -1}, {1, 10, 11, 1, 11, 4, 1, 4, 0, 7, 4, 11, -1, -1, -1, -1}, {3, 1, 4, 3, 4, 8, 1, 10, 4, 7, 4, 11, 10, 11, 4, -1}, {4, 11, 7, 9, 11, 4, 9, 2, 11, 9, 1, 2, -1, -1, -1, -1}, {9, 7, 4, 9, 11, 7, 9, 1, 11, 2, 11, 1, 0, 8, 3, -1}, {11, 7, 4, 11, 4, 2, 2, 4, 0, -1, -1, -1, -1, -1, -1, -1}, {11, 7, 4, 11, 4, 2, 8, 3, 4, 3, 2, 4, -1, -1, -1, -1}, {2, 9, 10, 2, 7, 9, 2, 3, 7, 7, 4, 9, -1, -1, -1, -1}, {9, 10, 7, 9, 7, 4, 10, 2, 7, 8, 7, 0, 2, 0, 7, -1}, {3, 7, 10, 3, 10, 2, 7, 4, 10, 1, 10, 0, 4, 0, 10, -1}, {1, 10, 2, 8, 7, 4, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1}, {4, 9, 1, 4, 1, 7, 7, 1, 3, -1, -1, -1, -1, -1, -1, -1}, {4, 9, 1, 4, 1, 7, 0, 8, 1, 8, 7, 1, -1, -1, -1, -1}, {4, 0, 3, 7, 4, 3, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1}, {4, 8, 7, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1}, {9, 10, 8, 10, 11, 8, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1}, {3, 0, 9, 3, 9, 11, 11, 9, 10, -1, -1, -1, -1, -1, -1, -1}, {0, 1, 10, 0, 10, 8, 8, 10, 11, -1, -1, -1, -1, -1, -1, -1}, {3, 1, 10, 11, 3, 10, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1}, {1, 2, 11, 1, 11, 9, 9, 11, 8, -1, -1, -1, -1, -1, -1, -1}, {3, 0, 9, 3, 9, 11, 1, 2, 9, 2, 11, 9, -1, -1, -1, -1}, {0, 2, 11, 8, 0, 11, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1}, {3, 2, 11, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1}, {2, 3, 8, 2, 8, 10, 10, 8, 9, -1, -1, -1, -1, -1, -1, -1}, {9, 10, 2, 0, 9, 2, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1}, {2, 3, 8, 2, 8, 10, 0, 1, 8, 1, 10, 8, -1, -1, -1, -1}, {1, 10, 2, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1}, {1, 3, 8, 9, 1, 8, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1}, {0, 9, 1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1}, {0, 3, 8, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1}, {-1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1}}; /******************************************************************************/ static double gx(int i, int j, int k) { if(i > 0 && i < nxm1) { return (f[i+1][j][k]-f[i-1][j][k]) / 2.0; } else if(i == 0) { return (f[i+1][j][k]-f[i][j][k]); } else { return (f[i][j][k]-f[i-1][j][k]); } } /******************************************************************************/ static double gy(int i, int j, int k) { if(j > 0 && j < nym1) { return (f[i][j+1][k]-f[i][j-1][k]) / 2.0; } else if(j == 0) { return (f[i][j+1][k]-f[i][j][k]); } else { return (f[i][j][k]-f[i][j-1][k]); } } /******************************************************************************/ static double gz(int i, int j, int k) { if(k > 0 && k < nzm1) { return (f[i][j][k+1]-f[i][j][k-1]) / 2.0; } else if(k == 0) { return (f[i][j][k+1]-f[i][j][k]); } else { return (f[i][j][k]-f[i][j][k-1]); } } /******************************************************************************/ static GString* calc(guint *n1, guint *n2) { /* I label local cell vertices as in ref. above and assigns x y z names like this : y | 4----------5 /. /| 7----------6 | | . | | | . | | | 0........|.1 --x |/ |/ 3----------2 / z */ register int i, j, k; guint n; double fac; double xu, yu, zu, xui, xuij, yuj; int cubeindex; int e; int vertlist[12]; int m1, m2, m3; double ux, uy, uz, vx, vy, vz, wx, wy, wz, s; double xnu, ynu, znu; GString *out; /* edges are labelled from each corner: x+ then z+ then y+ for k varying fastest then j varying fastest then i varying fastest */ n = 0; for(i=0; i= 0) || (isovalue-f[i][j][k] >= 0.0 && isovalue-f[i+1][j][k] < 0)) { fac = (isovalue-f[i][j][k])/(f[i+1][j][k]-f[i][j][k]); itab[n] = *n2; xs[*n2] = xu + fac*dxx1; ys[*n2] = yu; zs[*n2] = zu; ux = xnu + fac*(gx(i+1, j, k) - xnu); uy = ynu + fac*(gy(i+1, j, k) - ynu); uz = znu + fac*(gz(i+1, j, k) - znu); ux = ux*exx+uy*eyx+uz*ezx; uy = uy*eyy+uz*ezy; uz = uz*ezz; s = sqrt(ux*ux+uy*uy+uz*uz); if(s <= 0.0) { g_warning("normal direction assumed"); xns[*n2] = 1.0; yns[*n2] = 0.0; zns[*n2] = 0.0; } else { xns[*n2] = ux/s; yns[*n2] = uy/s; zns[*n2] = uz/s; } *n2 += 1; } else { itab[n] = -1; } } else { itab[n] = -1; } n++; if(k= 0) || (isovalue-f[i][j][k] >= 0.0 && isovalue-f[i][j][k+1] < 0)) { fac = (isovalue-f[i][j][k])/(f[i][j][k+1]-f[i][j][k]); itab[n] = *n2; xs[*n2] = xu + fac*dzx1; ys[*n2] = yu + fac*dzy1; zs[*n2] = zu + fac*dzz1; ux = xnu + fac*(gx(i, j, k+1) - xnu); uy = ynu + fac*(gy(i, j, k+1) - ynu); uz = znu + fac*(gz(i, j, k+1) - znu); ux = ux*exx+uy*eyx+uz*ezx; uy = uy*eyy+uz*ezy; uz = uz*ezz; s = sqrt(ux*ux+uy*uy+uz*uz); if(s <= 0.0) { g_warning("normal direction assumed"); xns[*n2] = 1.0; yns[*n2] = 0.0; zns[*n2] = 0.0; } else { xns[*n2] = ux/s; yns[*n2] = uy/s; zns[*n2] = uz/s; } *n2 += 1; } else { itab[n] = -1; } } else { itab[n] = -1; } n++; if(j= 0) || (isovalue-f[i][j][k] >= 0.0 && isovalue-f[i][j+1][k] < 0)) { fac = (isovalue-f[i][j][k])/(f[i][j+1][k]-f[i][j][k]); itab[n] = *n2; xs[*n2] = xu + fac*dyx1; ys[*n2] = yu + fac*dyy1; zs[*n2] = zu; ux = xnu + fac*(gx(i, j+1, k) - xnu); uy = ynu + fac*(gy(i, j+1, k) - ynu); uz = znu + fac*(gz(i, j+1, k) - znu); ux = ux*exx+uy*eyx+uz*ezx; uy = uy*eyy+uz*ezy; uz = uz*ezz; s = sqrt(ux*ux+uy*uy+uz*uz); if(s <= 0.0) { g_warning("normal direction assumed"); xns[*n2] = 1.0; yns[*n2] = 0.0; zns[*n2] = 0.0; } else { xns[*n2] = ux/s; yns[*n2] = uy/s; zns[*n2] = uz/s; } *n2 += 1; } else { itab[n] = -1; } } else { itab[n] = -1; } n++; } } } if(*n2 == 0) { g_warning("no isosurfaces found."); return (GString*)0; } out = g_string_new(""); for(i=0; istr); g_string_free(local, TRUE); n1_tot += n1; n2_tot += n2; } local = g_string_new(comment); g_free(comment); g_string_append_printf(local, "%f %f %f\n", dxx, dyx, dyy); g_string_append_printf(local, "%f %f %f\n", dzx, dzy, dzz); g_string_append_printf(local, "%12d%12d%12d", nsurfs_to_build, n1_tot, n2_tot); g_string_prepend(out, local->str); g_string_free(local, TRUE); DBG_fprintf(stderr, "Found a total of %d facets and %d points\n", n1_tot, n2_tot); DBG_fprintf(stderr, "Done.\n"); for(i=0; istr, -1, &error)) { g_warning("%s", error->message); g_error_free(error); return 1; } g_string_free(out, TRUE); return 0; } #endif /******************************************************************************/ /******************************************************************************/ /* DEVELOPMENT AREA Methods are copied to be callable without all static stuff everywhere. */ static double getDeltaMesh(int i, double *mesh, int size, gboolean periodic) { if (i >= size - 1) { if (periodic) return 1. + mesh[(i + 1)%size] - mesh[i%size]; else return (mesh[size] - mesh[size - 1]); } return (mesh[i + 1] - mesh[i]); } /** * visu_surface_new_fromScalarField: * @field: the scalar field to create the surface from ; * @isoValue: the value of the isosurface ; * @name: (allow-none): the name of the surface to use (can be NULL). * * Create on the fly a surface from the scalar field @field. If * @name is given, the surface is created with it, if not, "Isosurface * @id + 1" is used. @surf can already contains several surfaces, in * that case, the new surface is added. If @surf is NULL, then a new * #VisuSurface object is created and returned. * * Returns: (transfer full): the newly created surface, if any. */ VisuSurface* visu_surface_new_fromScalarField(const VisuScalarField *field, double isoValue, const gchar *name) { VisuSurface *surf; surf = (VisuSurface*)0; switch (visu_scalar_field_getMeshtype(field)) { case VISU_SCALAR_FIELD_MESH_UNIFORM: create_fromSF_uniform (&surf, field, isoValue, name); break; case VISU_SCALAR_FIELD_MESH_NON_UNIFORM: create_fromSF_nonuniform(&surf, field, isoValue, name); break; default: g_warning("Wrong value for 'meshtype'."); return FALSE; } if (surf) g_object_set_data(G_OBJECT(surf), "origin", (gpointer)field); return surf; } /** * visu_surface_new_defaultFromScalarField: * @field: a #VisuScalarField object. * @neg: (transfer full) (out): a #VisuSurface location. * @pos: (transfer full) (out): a #VisuSurface location. * * Creates one or two surface from @field. If @field is mostly * positive, one surface is generated at the mean value. If @field has * equivalent negative and positive values, two surfaces are * generated, one for th mean negative value and one for the mean * positive value. * * Since: 3.8 **/ void visu_surface_new_defaultFromScalarField(const VisuScalarField *field, VisuSurface **neg, VisuSurface **pos) { double mimax[2]; VisuSurface *surf; VisuSurfaceResource *res; gchar *label; static guint id = 0; int blue[4] = {0, 24, 185, 196}, red[4] = {185, 24, 0, 196}; gboolean new; if (neg) *neg = (VisuSurface*)0; if (pos) *pos = (VisuSurface*)0; id += 1; visu_scalar_field_getMinMax(field, mimax); /* For densities, this create only one surface. For wavefunctions, it create two and set their style accordingly. */ if (mimax[0] <= mimax[1] && mimax[0] * mimax[1] < 0.f && MIN(ABS(mimax[0]), ABS(mimax[1])) / MAX(ABS(mimax[0]), ABS(mimax[1])) > 0.2) { label = g_strdup_printf(_("Negative (%d)"), id); res = visu_surface_resource_new_fromName(label, &new); if (new) g_object_set(res, "color", tool_color_addIntRGBA(blue), "rendered", TRUE, NULL); g_object_unref(res); surf = visu_surface_new_fromScalarField(field, mimax[0] / 2., label); g_free(label); if (surf && neg) *neg = surf; else if (surf) g_object_unref(surf); label = g_strdup_printf(_("Positive (%d)"), id); res = visu_surface_resource_new_fromName(label, &new); if (new) g_object_set(res, "color", tool_color_addIntRGBA(red), "rendered", TRUE, NULL); g_object_unref(res); surf = visu_surface_new_fromScalarField(field, mimax[1] / 2., label); g_free(label); if (surf && pos) *pos = surf; else if (surf) g_object_unref(surf); } else if (mimax[0] <= mimax[1]) { surf = visu_surface_new_fromScalarField(field, (mimax[0] + mimax[1]) / 2., (const gchar*)0); if (surf && pos) *pos = surf; else if (surf) g_object_unref(surf); } else { surf = visu_surface_new_fromScalarField(field, 0., (gchar*)0); if (surf && pos) *pos = surf; else if (surf) g_object_unref(surf); } } static void _setNormal(double nrm[3], double s, double vux, double vuy, double vuz) { if (s <= 0.0) { g_warning("normal direction assumed"); nrm[0] = 1.; nrm[1] = 0.; nrm[2] = 0.; } else { nrm[0] = vux/s; nrm[1] = vuy/s; nrm[2] = vuz/s; } } /** * create_fromSF_uniform: * @surf: a location on a #VisuSurface pointer ; * @field: the scalar field to create the surface from ; * @isoValue: the value of the isosurface ; * @id: an integer identifying the surface ; * @name: the name of the surface to use (can be NULL). * * Create on the fly a surface from the scalar field @field. If @name is given, the surface * is created with it, if not, "Isosurface @id + 1" is used. @surf can already * contains several surfaces, in that case, the new surface is added. If @surf is * NULL, then a new #VisuSurface object is created and returned. * * Returns: TRUE if the surface is created. */ static gboolean create_fromSF_uniform(VisuSurface **surf, const VisuScalarField *field, double isoValue, const gchar *name) { /* I label local cell vertices as in ref. above and assigns x y z names like this : y | 4----------5 /. /| 7----------6 | | . | | | . | | | 0........|.1 --x |/ |/ 3----------2 / z */ /* Local variables */ register guint i, j, k; int n; int nelez3, neleyz3, nelexyz3; guint sizem1[3]; /*nx-1, ny-1 ,nz-1 : number of mesh intervals in the x,y and z direction*/ guint scalarGrid[3]; /*nx, ny ,nz : number of mesh nodes in the x,y and z direction*/ int *iTab; double fac; double xu, yu, zu, xui, xuij, yuj; double vux, vuy, vuz, s; double vxnu, vynu, vznu, v; double orthoBox[6]; /* inverse length of the box*/ double dBox[6]; /*step of the mesh*/ GArray *points; VisuSurfacePoint at; double val1, val2; VisuBox *box; double scalarBox[VISU_BOX_N_VECTORS]; /*define the box edges and topology*/ gboolean per[3], status; float scalarShift[3]; /* Routine code*/ /* Ensure that the pointer is not zero */ g_return_val_if_fail(surf, FALSE); /* edges are labelled from each corner: x+ then z+ then y+ for k varying fastest then j varying fastest then i varying fastest */ /* Get data from the field. */ box = visu_boxed_getBox(VISU_BOXED(field)); for (i = 0; i < VISU_BOX_N_VECTORS; i++) scalarBox[i] = visu_box_getGeometry(box, i); visu_box_getPeriodicity(box, per); visu_scalar_field_getGridSize(field, scalarGrid); visu_pointset_getTranslation(VISU_POINTSET(field), scalarShift); DBG_fprintf(stderr, "Pot2surf : compute isosurface at value %g from" " field %p.\n", isoValue, (gpointer)field); DBG_fprintf(stderr, " | periodic %d, %d, %d.\n", per[0], per[1], per[2]); DBG_fprintf(stderr, " | value %g.\n", isoValue); DBG_fprintf(stderr, " | size %d %d %d.\n", scalarGrid[0], scalarGrid[1], scalarGrid[2]); DBG_fprintf(stderr, " | box %g %g %g\n", scalarBox[0], scalarBox[1], scalarBox[2]); DBG_fprintf(stderr, " | %g %g %g.\n", scalarBox[3], scalarBox[4], scalarBox[5]); DBG_fprintf(stderr, " | shift %g %g %g\n", scalarShift[0], scalarShift[1], scalarShift[2]); /* Compute some local values. */ if (per[0]) scalarGrid[0] += 1; if (per[1]) scalarGrid[1] += 1; if (per[2]) scalarGrid[2] += 1; for (i = 0; i < 3; i++) sizem1[i] = scalarGrid[i] - 1; v = scalarBox[0] * scalarBox[2] * scalarBox[5]; /* volume of the box = Lx*Ly*Lz */ orthoBox[0] = scalarBox[2] * scalarBox[5] / v; /* 1/Lx */ orthoBox[1] = -scalarBox[1] * scalarBox[5] / v; orthoBox[2] = scalarBox[0] * scalarBox[5] / v; /* 1/Ly */ orthoBox[3] = (scalarBox[1] * scalarBox[4] - scalarBox[2] * scalarBox[3]) / v; orthoBox[4] = -scalarBox[0] * scalarBox[4] / v; orthoBox[5] = scalarBox[0] * scalarBox[2] / v; /* 1/Lz */ dBox[0] = scalarBox[0] / sizem1[0]; dBox[1] = scalarBox[1] / sizem1[1]; dBox[2] = scalarBox[2] / sizem1[1]; dBox[3] = scalarBox[3] / sizem1[2]; dBox[4] = scalarBox[4] / sizem1[2]; dBox[5] = scalarBox[5] / sizem1[2]; nelez3 = 3 * scalarGrid[2]; neleyz3 = scalarGrid[1] * nelez3; nelexyz3 = scalarGrid[0] * neleyz3; /* 3*nx*ny*nz */ /* Allocate buffers. */ points = g_array_sized_new(FALSE, FALSE, sizeof(VisuSurfacePoint), nelexyz3 / 10); /* Indexes. */ iTab = g_malloc(nelexyz3 * sizeof(int)); n = 0; for(i=0; i= 0.0) || (isoValue - val1 >= 0.0 && isoValue - val2 < 0.0)) { fac = (isoValue - val1) / (val2 - val1); iTab[n] = points->len; at.at[0] = xu + fac*dBox[0]; /* surface intersection coordinates*/ at.at[1] = yu; at.at[2] = zu; vux = vxnu + fac*(visu_scalar_field_getGradAt(field, i+1, j, k, TOOL_XYZ_X) - vxnu); vuy = vynu + fac*(visu_scalar_field_getGradAt(field, i+1, j, k, TOOL_XYZ_Y) - vynu); vuz = vznu + fac*(visu_scalar_field_getGradAt(field, i+1, j, k, TOOL_XYZ_Z) - vznu); vux = vux*orthoBox[0]+vuy*orthoBox[1]+vuz*orthoBox[3]; vuy = vuy*orthoBox[2]+vuz*orthoBox[4]; vuz = vuz*orthoBox[5]; s = sqrt(vux*vux+vuy*vuy+vuz*vuz); _setNormal(at.normal, s, vux, vuy, vuz); g_array_append_val(points, at); } else { iTab[n] = -1; } } else { iTab[n] = -1; } n++; if(k= 0.0) || (isoValue - val1 >= 0.0 && isoValue - val2 < 0.0)) { fac = (isoValue - val1) / (val2 - val1); iTab[n] = points->len; at.at[0] = xu + fac*dBox[3]; at.at[1] = yu + fac*dBox[4]; at.at[2] = zu + fac*dBox[5]; vux = vxnu + fac*(visu_scalar_field_getGradAt(field, i, j, k+1, TOOL_XYZ_X) - vxnu); vuy = vynu + fac*(visu_scalar_field_getGradAt(field, i, j, k+1, TOOL_XYZ_Y) - vynu); vuz = vznu + fac*(visu_scalar_field_getGradAt(field, i, j, k+1, TOOL_XYZ_Z) - vznu); vux = vux*orthoBox[0]+vuy*orthoBox[1]+vuz*orthoBox[3]; vuy = vuy*orthoBox[2]+vuz*orthoBox[4]; vuz = vuz*orthoBox[5]; s = sqrt(vux*vux+vuy*vuy+vuz*vuz); _setNormal(at.normal, s, vux, vuy, vuz); g_array_append_val(points, at); } else { iTab[n] = -1; } } else { iTab[n] = -1; } n++; if(j= 0.0) || (isoValue - val1 >= 0.0 && isoValue - val2 < 0.0)) { fac = (isoValue - val1) / (val2 - val1); iTab[n] = points->len; at.at[0] = xu + fac*dBox[1]; at.at[1] = yu + fac*dBox[2]; at.at[2] = zu; vux = vxnu + fac*(visu_scalar_field_getGradAt(field, i, j+1, k, TOOL_XYZ_X) - vxnu); vuy = vynu + fac*(visu_scalar_field_getGradAt(field, i, j+1, k, TOOL_XYZ_Y) - vynu); vuz = vznu + fac*(visu_scalar_field_getGradAt(field, i, j+1, k, TOOL_XYZ_Z) - vznu); vux = vux*orthoBox[0]+vuy*orthoBox[1]+vuz*orthoBox[3]; vuy = vuy*orthoBox[2]+vuz*orthoBox[4]; vuz = vuz*orthoBox[5]; s = sqrt(vux*vux+vuy*vuy+vuz*vuz); _setNormal(at.normal, s, vux, vuy, vuz); g_array_append_val(points, at); } else { iTab[n] = -1; } } else { iTab[n] = -1; } n++; } } } DBG_fprintf(stderr, " | found %d points.\n", points->len); if (points->len == 0) { g_warning("no isosurface found."); g_array_unref(points); g_free(iTab); return FALSE; } status = Create_surf(nelez3, neleyz3, nelexyz3, sizem1, iTab, points, isoValue, field, scalarBox, name, surf); DBG_fprintf(stderr, " | Surface successfully created.\n"); return status; } /** * create_fromSF_nonuniform: * @surf: a location on a #VisuSurface pointer ; * @field: the scalar field to create the surface from ; * @isoValue: the value of the isosurface ; * @id: an integer identifying the surface ; * @name: the name of the surface to use (can be NULL). * * Create on the fly a surface from the scalar field @field. If @name is given, the surface * is created with it, if not, "Isosurface @id + 1" is used. @surf can already * contains several surfaces, in that case, the new surface is added. If @surf is * NULL, then a new #VisuSurface object is created and returned. * * Returns: TRUE if the surface is created. */ static gboolean create_fromSF_nonuniform(VisuSurface **surf, const VisuScalarField *field, double isoValue, const gchar *name) { /* I label local cell vertices as in ref. above and assigns x y z names like this : y | 4---------------5 /. /| 7---------------6 | | . | | | . | | | 0.............|.1 --x |/ |/ 3---------------2 / z */ /* Local variables */ register guint i, j, k; int n; int nelez3, neleyz3, nelexyz3; guint sizem1[3]; /*nx-1, ny-1 ,nz-1 : number of mesh intervals in the x,y and z direction*/ guint scalarGrid[3]; /*nx, ny ,nz : number of mesh nodes in the x,y and z direction*/ int *iTab; double fac; double xu, yu, zu, xui, xuij, yuj, dmesh; double vux, vuy, vuz, s; double vxnu, vynu, vznu, v; double orthoBox[6]; /* inverse length of the box*/ GArray *points; VisuSurfacePoint at; double *meshx, *meshy, *meshz; double val1, val2; VisuBox *box; double scalarBox[6]; /*define the box edges and topology*/ gboolean per[3], status; /* Routine code*/ /* Ensure that the pointer is not zero */ g_return_val_if_fail(surf, FALSE); /* edges are labelled from each corner: x+ then z+ then y+ for k varying fastest then j varying fastest then i varying fastest */ /* Get data from the field. */ box = visu_boxed_getBox(VISU_BOXED(field)); for (i = 0; i < VISU_BOX_N_VECTORS; i++) scalarBox[i] = visu_box_getGeometry(box, i); visu_box_getPeriodicity(box, per); meshx = visu_scalar_field_getMesh(field, TOOL_XYZ_X); meshy = visu_scalar_field_getMesh(field, TOOL_XYZ_Y); meshz = visu_scalar_field_getMesh(field, TOOL_XYZ_Z); visu_scalar_field_getGridSize(field, scalarGrid); DBG_fprintf(stderr, "Pot2surf : compute isosurface at value %g from" " field %p.\n", isoValue, (gpointer)field); DBG_fprintf(stderr, " | periodic %d, %d, %d.\n", per[0], per[1], per[2]); DBG_fprintf(stderr, " | value %g.\n", isoValue); DBG_fprintf(stderr, " | size %d %d %d.\n", scalarGrid[0], scalarGrid[1], scalarGrid[2]); DBG_fprintf(stderr, " | box %g %g %g\n", scalarBox[0], scalarBox[1], scalarBox[2]); DBG_fprintf(stderr, " | %g %g %g.\n", scalarBox[3], scalarBox[4], scalarBox[5]); /* Compute some local values. */ if (per[0]) scalarGrid[0] += 1; if (per[1]) scalarGrid[1] += 1; if (per[2]) scalarGrid[2] += 1; for (i = 0; i < 3; i++) sizem1[i] = scalarGrid[i] - 1; v = scalarBox[0] * scalarBox[2] * scalarBox[5]; /* volume of the box = Lx*Ly*Lz */ orthoBox[0] = scalarBox[2] * scalarBox[5] / v; /* 1/Lx */ orthoBox[1] = -scalarBox[1] * scalarBox[5] / v; orthoBox[2] = scalarBox[0] * scalarBox[5] / v; /* 1/Ly */ orthoBox[3] = (scalarBox[1] * scalarBox[4] - scalarBox[2] * scalarBox[3]) / v; orthoBox[4] = -scalarBox[0] * scalarBox[4] / v; orthoBox[5] = scalarBox[0] * scalarBox[2] / v; /* 1/Lz */ nelez3 = 3 * scalarGrid[2]; neleyz3 = scalarGrid[1] * nelez3; nelexyz3 = scalarGrid[0] * neleyz3; /* 3*nx*ny*nz */ /* Allocate buffers. */ points = g_array_sized_new(FALSE, FALSE, sizeof(VisuSurfacePoint), nelexyz3 / 10); /* Indexes. */ iTab = g_malloc(nelexyz3 * sizeof(int)); n = 0; for(i=0; i= 0.0) || (isoValue - val1 >= 0.0 && isoValue - val2 < 0.0)) { fac = (isoValue - val1) / (val2 - val1); iTab[n] = points->len; dmesh = getDeltaMesh(i, meshx, sizem1[0], per[0]); at.at[0] = xu + fac * dmesh * scalarBox[0]; at.at[1] = yu; at.at[2] = zu; vux = vxnu + fac*(visu_scalar_field_getGradAt(field, i+1, j, k, TOOL_XYZ_X) - vxnu); vuy = vynu + fac*(visu_scalar_field_getGradAt(field, i+1, j, k, TOOL_XYZ_Y) - vynu); vuz = vznu + fac*(visu_scalar_field_getGradAt(field, i+1, j, k, TOOL_XYZ_Z) - vznu); vux = vux*orthoBox[0]+vuy*orthoBox[1]+vuz*orthoBox[3]; vuy = vuy*orthoBox[2]+vuz*orthoBox[4]; vuz = vuz*orthoBox[5]; s = sqrt(vux*vux+vuy*vuy+vuz*vuz); _setNormal(at.normal, s, vux, vuy, vuz); g_array_append_val(points, at); } else { iTab[n] = -1; } } else { iTab[n] = -1; } n++; if(k= 0.0) || (isoValue - val1 >= 0.0 && isoValue - val2 < 0.0)) { fac = (isoValue - val1) / (val2 - val1); iTab[n] = points->len; dmesh = getDeltaMesh(k, meshz, sizem1[2], per[2]); at.at[0] = xu + fac * dmesh * scalarBox[3]; at.at[1] = yu + fac * dmesh * scalarBox[4]; at.at[2] = zu + fac * dmesh * scalarBox[5]; vux = vxnu + fac*(visu_scalar_field_getGradAt(field, i, j, k+1, TOOL_XYZ_X) - vxnu); vuy = vynu + fac*(visu_scalar_field_getGradAt(field, i, j, k+1, TOOL_XYZ_Y) - vynu); vuz = vznu + fac*(visu_scalar_field_getGradAt(field, i, j, k+1, TOOL_XYZ_Z) - vznu); vux = vux*orthoBox[0]+vuy*orthoBox[1]+vuz*orthoBox[3]; vuy = vuy*orthoBox[2]+vuz*orthoBox[4]; vuz = vuz*orthoBox[5]; s = sqrt(vux*vux+vuy*vuy+vuz*vuz); _setNormal(at.normal, s, vux, vuy, vuz); g_array_append_val(points, at); } else { iTab[n] = -1; } } else { iTab[n] = -1; } n++; if(j= 0.0) || (isoValue - val1 >= 0.0 && isoValue - val2 < 0.0)) { fac = (isoValue - val1) / (val2 - val1); iTab[n] = points->len; dmesh = getDeltaMesh(j, meshy, sizem1[1], per[1]); at.at[0] = xu + fac * dmesh * scalarBox[1]; at.at[1] = yu + fac * dmesh * scalarBox[2]; at.at[2] = zu; vux = vxnu + fac*(visu_scalar_field_getGradAt(field, i, j+1, k, TOOL_XYZ_X) - vxnu); vuy = vynu + fac*(visu_scalar_field_getGradAt(field, i, j+1, k, TOOL_XYZ_Y) - vynu); vuz = vznu + fac*(visu_scalar_field_getGradAt(field, i, j+1, k, TOOL_XYZ_Z) - vznu); vux = vux*orthoBox[0]+vuy*orthoBox[1]+vuz*orthoBox[3]; vuy = vuy*orthoBox[2]+vuz*orthoBox[4]; vuz = vuz*orthoBox[5]; s = sqrt(vux*vux+vuy*vuy+vuz*vuz); _setNormal(at.normal, s, vux, vuy, vuz); g_array_append_val(points, at); } else { iTab[n] = -1; } } else { iTab[n] = -1; } n++; } } } DBG_fprintf(stderr, " | found %d points.\n", points->len); if (points->len == 0) { g_warning("no isosurface found."); g_array_unref(points); g_free(iTab); return FALSE; } status = Create_surf(nelez3, neleyz3, nelexyz3, sizem1, iTab, points, isoValue, field, scalarBox, name, surf); DBG_fprintf(stderr, " | Surface successfully created.\n"); return status; } /** * Create_surf: * @id: an integer identifying the surface ; * @nelez3: an integer giving the number of element times 3 along z; * @neleyz3: an integer giving the number of element times 3 in plane y by z; * @nelexyz3: an integer giving the number of element times 3 in volume x by y by z; * @nPoints: an integer giving the number points of the surface; * @sizem1: the number of intervals in each direction; * @iTab: table containing the number of surface points if surface exists at this place otherwise -1; * @xsurf: x coordinate of the surface points; * @ysurf: y coordinate of the surface points; * @zsurf: z coordinate of the surface points; * @xnsurf: normal value of the surface points; * @ynsurf: normal of the surface points; * @znsurf: normal of the surface points; * @isoValue: the value of the isosurface; * @scalarData: the potential values; * @scalarBox: the box parameters; * @name: the name of the surface to use (can be NULL). * @per: boolean for periodicity; * @surf: a location on a #VisuSurface pointer ; * * Create on the fly a surface from the scalar field @field. If @name is given, the surface * is created with it, if not, "Isosurface @id + 1" is used. @surf can already * contains several surfaces, in that case, the new surface is added. If @surf is * NULL, then a new #VisuSurface object is created and returned. * * Returns: TRUE if the surface is created. */ static gboolean Create_surf(int nelez3, int neleyz3, int nelexyz3 _U_, guint sizem1[3], int *iTab, GArray *points, double isoValue, const VisuScalarField *field, double scalarBox[6], const gchar *name, VisuSurface **surf) { /* Local variables */ register guint i, j, k; int cubeindex; int e, n; int m1, m2, m3; int vertlist[12]; GArray *vTab; VisuSurfacePoly poly; VisuSurfacePoint *at1, *at2, *at3; double vx, vy, vz, wx, wy, wz; double ux, uy, uz, s; float* densityData; VisuBox *box; /* Routine code */ /* Ensure that the pointer is not zero */ g_return_val_if_fail(surf, FALSE); /* Allocate buffers. The 16 coefficient is for the maximum number of polygons per grid points. */ vTab = g_array_sized_new(FALSE, FALSE, sizeof(VisuSurfacePoly), points->len / 3); poly.nvertices = 3; /* Main loop */ for(i=0; iat[0] - at1->at[0]; uy = at2->at[1] - at1->at[1]; uz = at2->at[2] - at1->at[2]; vx = at3->at[0] - at1->at[0]; vy = at3->at[1] - at1->at[1]; vz = at3->at[2] - at1->at[2]; wx = uy*vz-uz*vy; wy = uz*vx-ux*vz; wz = ux*vy-uy*vx; s = sqrt(wx*wx+wy*wy+wz*wz); if(s <= 0.0) continue; poly.indices[0] = m1; poly.indices[1] = m2; poly.indices[2] = m3; g_array_append_val(vTab, poly); } } } } DBG_fprintf(stderr, " | found %d polygons.\n", vTab->len); if (vTab->len == 0) { g_warning("no isosurface found."); g_array_unref(points); g_free(iTab); g_array_unref(vTab); return FALSE; } /* Ok, try to create a VisuSurface object from here. */ g_return_val_if_fail(*surf == (VisuSurface*)0, FALSE); DBG_fprintf(stderr, " | create new VisuSurface.\n"); *surf = visu_surface_new(name, points, vTab); box = visu_box_new(scalarBox, VISU_BOX_PERIODIC); visu_boxed_setBox(VISU_BOXED(*surf), VISU_BOXED(box)); g_object_unref(box); densityData = visu_surface_addPropertyFloat(*surf, VISU_SURFACE_PROPERTY_POTENTIAL); densityData[0] = isoValue; #if DEBUG == 1 visu_surface_checkConsistency(*surf); #endif g_array_unref(points); g_array_unref(vTab); g_free(iTab); return TRUE; } /*****************************/ /* XML files for iso-values. */ /*****************************/ /* */ /* Known elements. */ #define SURF_PARSER_ELEMENT_SURFACES "surfaces" #define SURF_PARSER_ELEMENT_SURFACE "surface" #define SURF_PARSER_ELEMENT_HIDE "hidden-by-planes" #define SURF_PARSER_ELEMENT_COLOR "color" /* Known attributes. */ #define SURF_PARSER_ATTRIBUTES_RENDERED "rendered" #define SURF_PARSER_ATTRIBUTES_VALUE "iso-value" #define SURF_PARSER_ATTRIBUTES_NAME "name" #define SURF_PARSER_ATTRIBUTES_STATUS "status" #define SURF_PARSER_ATTRIBUTES_RGBA "rgba" #define SURF_PARSER_ATTRIBUTES_MATERIAL "material" struct _surfaces_xml { gchar *name; float iso; gboolean rendered, masked; gboolean colorSet, materialSet; float color[4], material[5]; }; static gboolean startVisuSurface; /* This method is called for every element that is parsed. The user_data must be a GList of _surfaces_xml. When a 'surface' element, a new struct instance is created and prepend in the list. When 'hidden-by-planes' or other qualificative elements are found, the first surface of the list is modified accordingly. */ static void surfacesXML_element(GMarkupParseContext *context _U_, const gchar *element_name, const gchar **attribute_names, const gchar **attribute_values, gpointer user_data, GError **error) { GList **surfacesList; struct _surfaces_xml *surf; int i; g_return_if_fail(user_data); surfacesList = (GList **)user_data; DBG_fprintf(stderr, "Surf parser: found '%s' element.\n", element_name); if (!strcmp(element_name, SURF_PARSER_ELEMENT_SURFACES)) { /* Should have no attributes. */ if (attribute_names[0]) { g_set_error(error, G_MARKUP_ERROR, G_MARKUP_ERROR_UNKNOWN_ATTRIBUTE, _("Unexpected attribute '%s' for element '%s'."), attribute_names[0], SURF_PARSER_ELEMENT_SURFACES); return; } /* Initialise the surfacesList. */ if (*surfacesList) { g_set_error(error, G_MARKUP_ERROR, G_MARKUP_ERROR_PARSE, _("DTD error: element '%s' should appear only once."), SURF_PARSER_ELEMENT_SURFACES); return; } *surfacesList = (GList*)0; startVisuSurface = TRUE; } else if (!strcmp(element_name, SURF_PARSER_ELEMENT_SURFACE)) { surf = g_malloc(sizeof(struct _surfaces_xml)); surf->name = (gchar*)0; surf->rendered = TRUE; surf->masked = TRUE; surf->iso = 12345.6789f; surf->colorSet = FALSE; surf->materialSet = FALSE; /* We parse the attributes. */ for (i = 0; attribute_names[i]; i++) { if (!strcmp(attribute_names[i], SURF_PARSER_ATTRIBUTES_NAME)) surf->name = g_strdup(attribute_values[i]); else if (!strcmp(attribute_names[i], SURF_PARSER_ATTRIBUTES_RENDERED)) { if (!strcmp(attribute_values[i], "yes")) surf->rendered = TRUE; else if (!strcmp(attribute_values[i], "no")) surf->rendered = FALSE; else g_set_error(error, G_MARKUP_ERROR, G_MARKUP_ERROR_INVALID_CONTENT, _("Invalid value '%s' for attribute '%s'."), attribute_values[i], SURF_PARSER_ATTRIBUTES_RENDERED); } else if (!strcmp(attribute_names[i], SURF_PARSER_ATTRIBUTES_VALUE)) { if (!(sscanf(attribute_values[i], "%f", &surf->iso) == 1)) g_set_error(error, G_MARKUP_ERROR, G_MARKUP_ERROR_INVALID_CONTENT, _("Invalid value '%s' for attribute '%s'."), attribute_values[i], SURF_PARSER_ATTRIBUTES_VALUE); } else g_set_error(error, G_MARKUP_ERROR, G_MARKUP_ERROR_UNKNOWN_ATTRIBUTE, _("Unexpected attribute '%s' for element '%s'."), attribute_names[i], SURF_PARSER_ELEMENT_SURFACE); if (*error) { g_free(surf->name); g_free(surf); return; } } /* We check the mandatory attribute. */ if (surf->iso == 12345.6789f) { g_set_error(error, G_MARKUP_ERROR, G_MARKUP_ERROR_PARSE, _("Missing attribute '%s' for element '%s'."), SURF_PARSER_ATTRIBUTES_VALUE, SURF_PARSER_ELEMENT_SURFACE); g_free(surf->name); g_free(surf); return; } DBG_fprintf(stderr, "Surf parser: add a new surface '%s' %f %d.\n", (surf->name)?surf->name:"None", surf->iso, surf->rendered); *surfacesList = g_list_prepend(*surfacesList, (gpointer)surf); } else if (startVisuSurface && !strcmp(element_name, SURF_PARSER_ELEMENT_HIDE)) { if (!*surfacesList) { g_set_error(error, G_MARKUP_ERROR, G_MARKUP_ERROR_INVALID_CONTENT, _("DTD error: parent element '%s' of element '%s' is missing."), SURF_PARSER_ELEMENT_SURFACE, SURF_PARSER_ELEMENT_HIDE); return; } surf = (struct _surfaces_xml*)((*surfacesList)->data); /* We read the mandatory attribute. */ if (attribute_names[0]) { if (!strcmp(attribute_names[0], SURF_PARSER_ATTRIBUTES_STATUS)) { if (!strcmp(attribute_values[0], "yes")) surf->masked = TRUE; else if (!strcmp(attribute_values[0], "no")) surf->masked = FALSE; else g_set_error(error, G_MARKUP_ERROR, G_MARKUP_ERROR_INVALID_CONTENT, _("Invalid value '%s' for attribute '%s'."), attribute_values[0], SURF_PARSER_ATTRIBUTES_STATUS); } else g_set_error(error, G_MARKUP_ERROR, G_MARKUP_ERROR_UNKNOWN_ATTRIBUTE, _("Unexpected attribute '%s' for element '%s'."), attribute_names[0], SURF_PARSER_ELEMENT_HIDE); } else g_set_error(error, G_MARKUP_ERROR, G_MARKUP_ERROR_PARSE, _("Missing attribute '%s' for element '%s'."), SURF_PARSER_ATTRIBUTES_VALUE, SURF_PARSER_ELEMENT_SURFACE); if (*error) return; } else if (startVisuSurface && !strcmp(element_name, SURF_PARSER_ELEMENT_COLOR)) { if (!*surfacesList) { g_set_error(error, G_MARKUP_ERROR, G_MARKUP_ERROR_INVALID_CONTENT, _("DTD error: parent element '%s' of element '%s' is missing."), SURF_PARSER_ELEMENT_SURFACE, SURF_PARSER_ELEMENT_COLOR); return; } surf = (struct _surfaces_xml*)((*surfacesList)->data); for(i = 0; attribute_names[i]; i++) { if (!strcmp(attribute_names[i], SURF_PARSER_ATTRIBUTES_RGBA)) { if (sscanf(attribute_values[i], "%g %g %g %g", surf->color, surf->color + 1, surf->color + 2, surf->color + 3) != 4) g_set_error(error, G_MARKUP_ERROR, G_MARKUP_ERROR_INVALID_CONTENT, _("Invalid value '%s' for attribute '%s'."), attribute_values[i], SURF_PARSER_ATTRIBUTES_RGBA); else surf->colorSet = TRUE; } else if (!strcmp(attribute_names[i], SURF_PARSER_ATTRIBUTES_MATERIAL)) { if (sscanf(attribute_values[i], "%g %g %g %g %g", surf->material, surf->material + 1, surf->material + 2, surf->material + 3, surf->material + 4) != 5) g_set_error(error, G_MARKUP_ERROR, G_MARKUP_ERROR_INVALID_CONTENT, _("Invalid value '%s' for attribute '%s'."), attribute_values[i], SURF_PARSER_ATTRIBUTES_MATERIAL); else surf->materialSet = TRUE; } else g_set_error(error, G_MARKUP_ERROR, G_MARKUP_ERROR_UNKNOWN_ATTRIBUTE, _("Unexpected attribute '%s' for element '%s'."), attribute_names[i], SURF_PARSER_ELEMENT_COLOR); if (*error) return; } } else if (startVisuSurface) { /* We silently ignore the element if surfacesList is unset, but raise an error if surfacesList has been set. */ g_set_error(error, G_MARKUP_ERROR, G_MARKUP_ERROR_UNKNOWN_ELEMENT, _("Unexpected element '%s'."), element_name); } } /* Check when a element is closed that everything required has been set. */ void surfacesXML_end(GMarkupParseContext *context _U_, const gchar *element_name, gpointer user_data _U_, GError **error _U_) { if (!strcmp(element_name, SURF_PARSER_ELEMENT_SURFACES)) startVisuSurface = FALSE; } /* What to do when an error is raised. */ static void surfacesXML_error(GMarkupParseContext *context _U_, GError *error, gpointer user_data) { GList *tmpLst; DBG_fprintf(stderr, "Surf parser: error raised '%s'.\n", error->message); g_return_if_fail(user_data); /* We free the current list of surfaces. */ tmpLst = *(GList**)user_data; while (tmpLst) { g_free(((struct _surfaces_xml*)tmpLst->data)->name); g_free(tmpLst->data); tmpLst = g_list_next(tmpLst); } g_list_free(*(GList**)user_data); } /** * visu_surface_parseXMLFile: * @filename: a path to a file. * @surfaces: (inout) (element-type VisuSurface*): a location on a * #VisuSurface pointer. * @field: the scalar field to create the surface from. * @error: a location to store a possible error. * * Parse the given XML file, looking for the <surfaces> tag and create * the given surfaces. * * Returns: FALSE if a error occured. */ gboolean visu_surface_parseXMLFile(const gchar* filename, GList **surfaces, VisuScalarField *field, GError **error) { GMarkupParseContext* xmlContext; GMarkupParser parser; gboolean status; gsize size; gchar *buffer; GList *list, *tmpLst; VisuSurface *surface; struct _surfaces_xml *surf; VisuSurfaceResource *res; g_return_val_if_fail(filename && surfaces && field, FALSE); buffer = (gchar*)0; if (!g_file_get_contents(filename, &buffer, &size, error)) return FALSE; /* Create context. */ list = (GList*)0; parser.start_element = surfacesXML_element; parser.end_element = surfacesXML_end; parser.text = NULL; parser.passthrough = NULL; parser.error = surfacesXML_error; xmlContext = g_markup_parse_context_new(&parser, 0, &list, NULL); /* Parse data. */ startVisuSurface = FALSE; status = g_markup_parse_context_parse(xmlContext, buffer, size, error); /* Free buffers. */ g_markup_parse_context_free(xmlContext); g_free(buffer); if (!status) return FALSE; if (!list) { *error = g_error_new(G_MARKUP_ERROR, G_MARKUP_ERROR_EMPTY, _("No iso-value found.")); return FALSE; } /* Need to reverse the list since elements have been prepended. */ list = g_list_reverse(list); /* Convert the list to new isosurfaces. */ DBG_fprintf(stderr, "Surf parser: create %d new surfaces for %p.\n", g_list_length(list), (gpointer)(*surfaces)); tmpLst = list; while(tmpLst) { surf = (struct _surfaces_xml*)tmpLst->data; surface = visu_surface_new_fromScalarField(field, surf->iso, surf->name); if (surface) { res = visu_surface_getResource(surface); g_object_set(G_OBJECT(res), "rendered", surf->rendered, "maskable", surf->masked, NULL); if (surf->colorSet) g_object_set(G_OBJECT(res), "color", tool_color_addFloatRGBA(surf->color, NULL), NULL); if (surf->materialSet) g_object_set(G_OBJECT(res), "material", surf->material, NULL); *surfaces = g_list_append(*surfaces, surface); } g_free(surf->name); g_free(surf); tmpLst = g_list_next(tmpLst); } g_list_free(list); return TRUE; } /** * visu_surface_exportXMLFile: * @filename: a path to a file. * @values: an array of @n values. * @res: an array of @n #VisuSurfaceResource. * @n: number of surface resources to export. * @error: a location to store a possible error. * * Export the surface resources into an XML file. * * Returns: FALSE if a error occured. */ gboolean visu_surface_exportXMLFile(const gchar* filename, float *values, VisuSurfaceResource **res, int n, GError **error) { gboolean valid; GString *output; int i; gchar *lbl; gboolean rendered, maskable; ToolColor *color; float *mat; /* We actually output the values. */ output = g_string_new(" \n"); for (i = 0; i < n; i++) { g_object_get(G_OBJECT(res[i]), "label", &lbl, "color", &color, "material", &mat, "rendered", &rendered, "maskable", &maskable, NULL); g_string_append_printf(output, " \n"); g_string_append_printf(output, " \n", (maskable)?"yes":"no"); g_string_append_printf(output, " \n", color->rgba[0], color->rgba[1], color->rgba[2], color->rgba[3], mat[0], mat[1], mat[2], mat[3], mat[4]); g_string_append(output, " \n"); } g_string_append(output, " "); valid = tool_XML_substitute(output, filename, "surfaces", error); if (!valid) { g_string_free(output, TRUE); return FALSE; } valid = g_file_set_contents(filename, output->str, -1, error); g_string_free(output, TRUE); return valid; } v_sim-3.8.0/src/extraFunctions/pot2surf.h000066400000000000000000000057011370110300500203700ustar00rootroot00000000000000/* EXTRAITS DE LA LICENCE Copyright CEA, contributeurs : Luc BILLARD, Damien CALISTE, Olivier D'Astier, laboratoire L_Sim, (2001-2005) Adresse mèl : BILLARD, non joignable par mèl ; CALISTE, damien P caliste AT cea P fr. D'ASTIER, dastier AT iie P cnam P fr. Ce logiciel est un programme informatique servant à visualiser des structures atomiques dans un rendu pseudo-3D. Ce logiciel est régi par la licence CeCILL soumise au droit français et respectant les principes de diffusion des logiciels libres. Vous pouvez utiliser, modifier et/ou redistribuer ce programme sous les conditions de la licence CeCILL telle que diffusée par le CEA, le CNRS et l'INRIA sur le site "http://www.cecill.info". Le fait que vous puissiez accéder à cet en-tête signifie que vous avez pris connaissance de la licence CeCILL, et que vous en avez accepté les termes (cf. le fichier Documentation/licence.fr.txt fourni avec ce logiciel). */ /* LICENCE SUM UP Copyright CEA, contributors : Luc BILLARD and Damien CALISTE and Olivier D'Astier, laboratoire L_Sim, (2001-2005) E-mail addresses : BILLARD, not reachable any more ; CALISTE, damien P caliste AT cea P fr. D'ASTIER, dastier AT iie P cnam P fr. This software is a computer program whose purpose is to visualize atomic configurations in 3D. This software is governed by the CeCILL license under French law and abiding by the rules of distribution of free software. You can use, modify and/ or redistribute the software under the terms of the CeCILL license as circulated by CEA, CNRS and INRIA at the following URL "http://www.cecill.info". The fact that you are presently reading this means that you have had knowledge of the CeCILL license and that you accept its terms. You can find a copy of this licence shipped with this software at Documentation/licence.en.txt. */ #ifndef POT2SURF_H #define POT2SURF_H #include "surfaces.h" #include "scalarFields.h" #ifndef V_SIM_DISABLE_DEPRECATED int visu_surface_createFromPotentialFile(const gchar *surf_file_to_write, const gchar *pot_file_to_read, int nsurfs_to_build, const float *surf_value, const gchar **surf_name); #endif VisuSurface* visu_surface_new_fromScalarField(const VisuScalarField *field, double isoValue, const gchar *name); void visu_surface_new_defaultFromScalarField(const VisuScalarField *field, VisuSurface **neg, VisuSurface **pos); gboolean visu_surface_parseXMLFile(const gchar* filename, GList **surfaces, VisuScalarField *field, GError **error); gboolean visu_surface_exportXMLFile(const gchar* filename, float *values, VisuSurfaceResource **res, int n, GError **error); #endif v_sim-3.8.0/src/extraFunctions/rotate.c000066400000000000000000000362121370110300500200760ustar00rootroot00000000000000/* EXTRAITS DE LA LICENCE Copyright CEA, contributeurs : Damien CALISTE, laboratoire L_Sim, (2017) Adresse mèl : CALISTE, damien P caliste AT cea P fr. Ce logiciel est un programme informatique servant à visualiser des structures atomiques dans un rendu pseudo-3D. Ce logiciel est régi par la licence CeCILL soumise au droit français et respectant les principes de diffusion des logiciels libres. Vous pouvez utiliser, modifier et/ou redistribuer ce programme sous les conditions de la licence CeCILL telle que diffusée par le CEA, le CNRS et l'INRIA sur le site "http://www.cecill.info". Le fait que vous puissiez accéder à cet en-tête signifie que vous avez pris connaissance de la licence CeCILL, et que vous en avez accepté les termes (cf. le fichier Documentation/licence.fr.txt fourni avec ce logiciel). */ /* LICENCE SUM UP Copyright CEA, contributors : Damien CALISTE, laboratoire L_Sim, (2017) E-mail address: CALISTE, damien P caliste AT cea P fr. This software is a computer program whose purpose is to visualize atomic configurations in 3D. This software is governed by the CeCILL license under French law and abiding by the rules of distribution of free software. You can use, modify and/ or redistribute the software under the terms of the CeCILL license as circulated by CEA, CNRS and INRIA at the following URL "http://www.cecill.info". The fact that you are presently reading this means that you have had knowledge of the CeCILL license and that you accept its terms. You can find a copy of this licence shipped with this software at Documentation/licence.en.txt. */ #include "rotate.h" #include /** * SECTION:rotate * @short_description: A class defining rotations for a set of nodes. * * Define and apply a rotation for a set of nodes. The * rotation can be changed and the set of nodes also. Each time the * rotation is applied, it is added to an undo stack. */ /** * VisuNodeMoverRotationClass: * @parent: the parent class; * * A short way to identify #_VisuNodeMoverRotationClass structure. * * Since: 3.8 */ /** * VisuNodeMoverRotation: * * An opaque structure. * * Since: 3.8 */ struct _Params { gfloat angle; gfloat axis[3], center[3]; }; /** * VisuNodeMoverRotationPrivate: * * Private fields for #VisuNodeMoverRotation objects. * * Since: 3.8 */ struct _VisuNodeMoverRotationPrivate { struct _Params params; struct _Params target; gfloat lastAngle; GSList *stack; }; enum { PROP_0, ANGLE_PROP, CENTER_PROP, AXIS_PROP, N_PROP }; static GParamSpec *_properties[N_PROP]; static void visu_node_mover_rotation_finalize(GObject *obj); static void visu_node_mover_rotation_get_property(GObject* obj, guint property_id, GValue *value, GParamSpec *pspec); static void visu_node_mover_rotation_set_property(GObject* obj, guint property_id, const GValue *value, GParamSpec *pspec); static gboolean _validate(const VisuNodeMover *mover); static void _setup(VisuNodeMover *mover); static gboolean _apply(VisuNodeMover *mover, VisuNodeArray *arr, const GArray *ids, gfloat completion); static gboolean _push(VisuNodeMover *mover); static void _undo(VisuNodeMover *mover, VisuNodeArray *arr, const GArray *ids); G_DEFINE_TYPE_WITH_CODE(VisuNodeMoverRotation, visu_node_mover_rotation, VISU_TYPE_NODE_MOVER, G_ADD_PRIVATE(VisuNodeMoverRotation)) static void visu_node_mover_rotation_class_init(VisuNodeMoverRotationClass *klass) { DBG_fprintf(stderr, "Visu MoverRotation: creating the class of the object.\n"); /* DBG_fprintf(stderr, " - adding new signals ;\n"); */ /* Connect the overloading methods. */ G_OBJECT_CLASS(klass)->finalize = visu_node_mover_rotation_finalize; G_OBJECT_CLASS(klass)->set_property = visu_node_mover_rotation_set_property; G_OBJECT_CLASS(klass)->get_property = visu_node_mover_rotation_get_property; VISU_NODE_MOVER_CLASS(klass)->validate = _validate; VISU_NODE_MOVER_CLASS(klass)->setup = _setup; VISU_NODE_MOVER_CLASS(klass)->apply = _apply; VISU_NODE_MOVER_CLASS(klass)->push = _push; VISU_NODE_MOVER_CLASS(klass)->undo = _undo; /** * VisuNodeMoverRotation::angle: * * The angle of rotation. * * Since: 3.8 */ _properties[ANGLE_PROP] = g_param_spec_float("angle", "Angle", "rotation angle in degrees.", -G_MAXFLOAT, G_MAXFLOAT, 0.f, G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS); /** * VisuNodeMoverRotation::center: * * The center of rotation. * * Since: 3.8 */ _properties[CENTER_PROP] = g_param_spec_boxed("center", "Center", "center of rotation.", TOOL_TYPE_VECTOR, G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS); /** * VisuNodeMoverRotation::axis: * * The axis of rotation. * * Since: 3.8 */ _properties[AXIS_PROP] = g_param_spec_boxed("axis", "Axis", "axis of rotation.", TOOL_TYPE_VECTOR, G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS); g_object_class_install_properties(G_OBJECT_CLASS(klass), N_PROP, _properties); } static void visu_node_mover_rotation_init(VisuNodeMoverRotation *obj) { DBG_fprintf(stderr, "Visu MoverRotation: initializing a new object (%p).\n", (gpointer)obj); obj->priv = visu_node_mover_rotation_get_instance_private(obj); obj->priv->stack = (GSList*)0; obj->priv->params.angle = 0.f; obj->priv->params.axis[0] = 0.f; obj->priv->params.axis[1] = 0.f; obj->priv->params.axis[2] = 1.f; obj->priv->params.center[0] = 0.f; obj->priv->params.center[1] = 0.f; obj->priv->params.center[2] = 0.f; } static void visu_node_mover_rotation_get_property(GObject* obj, guint property_id, GValue *value, GParamSpec *pspec) { VisuNodeMoverRotation *self = VISU_NODE_MOVER_ROTATION(obj); DBG_fprintf(stderr, "Visu MoverRotation: get property %s.\n", g_param_spec_get_name(pspec)); switch (property_id) { case ANGLE_PROP: g_value_set_float(value, self->priv->params.angle); break; case AXIS_PROP: g_value_set_boxed(value, self->priv->params.axis); break; case CENTER_PROP: g_value_set_boxed(value, self->priv->params.center); break; default: /* We don't have any other property... */ G_OBJECT_WARN_INVALID_PROPERTY_ID(obj, property_id, pspec); break; } } static void visu_node_mover_rotation_set_property(GObject* obj, guint property_id, const GValue *value, GParamSpec *pspec) { VisuNodeMoverRotation *self = VISU_NODE_MOVER_ROTATION(obj); DBG_fprintf(stderr, "Visu MoverRotation: set property %s.\n", g_param_spec_get_name(pspec)); switch (property_id) { case ANGLE_PROP: visu_node_mover_rotation_setAngle(self, g_value_get_float(value)); break; case AXIS_PROP: visu_node_mover_rotation_setAxis(self, (float*)g_value_get_boxed(value)); break; case CENTER_PROP: visu_node_mover_rotation_setCenter(self, (float*)g_value_get_boxed(value)); break; default: /* We don't have any other property... */ G_OBJECT_WARN_INVALID_PROPERTY_ID(obj, property_id, pspec); break; } } static void visu_node_mover_rotation_finalize(GObject *obj) { VisuNodeMoverRotation *rot; g_return_if_fail(obj); DBG_fprintf(stderr, "Visu MoverRotation: finalize object %p.\n", (gpointer)obj); rot = VISU_NODE_MOVER_ROTATION(obj); /* Free privs elements. */ if (rot->priv->stack) g_slist_free_full(rot->priv->stack, g_free); /* Chain up to the parent class */ DBG_fprintf(stderr, "Visu MoverRotation: chain to parent.\n"); G_OBJECT_CLASS(visu_node_mover_rotation_parent_class)->finalize(obj); DBG_fprintf(stderr, "Visu MoverRotation: freeing ... OK.\n"); } static gboolean _validate(const VisuNodeMover *mover) { VisuNodeMoverRotation *rot; g_return_val_if_fail(VISU_IS_NODE_MOVER_ROTATION(mover), FALSE); rot = VISU_NODE_MOVER_ROTATION(mover); if (rot->priv->params.angle == 0.f) return FALSE; if (rot->priv->params.axis[0] == 0.f && rot->priv->params.axis[1] == 0.f && rot->priv->params.axis[2] == 0.f) return FALSE; return TRUE; } static void _setup(VisuNodeMover *mover) { VisuNodeMoverRotation *rot; g_return_if_fail(VISU_IS_NODE_MOVER_ROTATION(mover)); rot = VISU_NODE_MOVER_ROTATION(mover); rot->priv->target = rot->priv->params; rot->priv->lastAngle = 0.f; } static gboolean _apply(VisuNodeMover *mover, VisuNodeArray *arr, const GArray *ids, gfloat completion) { VisuNodeMoverRotation *rot; struct _Params *params; g_return_val_if_fail(VISU_IS_NODE_MOVER_ROTATION(mover), FALSE); rot = VISU_NODE_MOVER_ROTATION(mover); DBG_fprintf(stderr, "Visu MoverRotation: apply rotation %g %gx%gx%g.\n", rot->priv->params.angle, rot->priv->params.axis[0], rot->priv->params.axis[1], rot->priv->params.axis[2]); if (!_validate(mover)) return FALSE; visu_node_array_rotateNodes(arr, ids, rot->priv->target.axis, rot->priv->target.center, rot->priv->target.angle * completion - rot->priv->lastAngle); rot->priv->lastAngle = rot->priv->target.angle * completion; if (completion == 1.f) { params = g_malloc(sizeof(struct _Params)); *params = rot->priv->params; rot->priv->stack = g_slist_prepend(rot->priv->stack, params); } return TRUE; } static gboolean _push(VisuNodeMover *mover) { VisuNodeMoverRotation *rot; struct _Params *params; g_return_val_if_fail(VISU_IS_NODE_MOVER_ROTATION(mover), FALSE); rot = VISU_NODE_MOVER_ROTATION(mover); if (!_validate(mover)) return FALSE; params = g_malloc(sizeof(struct _Params)); *params = rot->priv->params; rot->priv->stack = g_slist_prepend(rot->priv->stack, params); return TRUE; } static void _undo(VisuNodeMover *mover, VisuNodeArray *arr, const GArray *ids) { VisuNodeMoverRotation *rot; struct _Params *params; GSList *p; g_return_if_fail(VISU_IS_NODE_MOVER_ROTATION(mover)); rot = VISU_NODE_MOVER_ROTATION(mover); if (!rot->priv->stack) return; p = rot->priv->stack; params = (struct _Params*)p->data; visu_node_array_rotateNodes(arr, ids, params->axis, params->center, -params->angle); rot->priv->stack = g_slist_next(rot->priv->stack); g_free(params); g_slist_free_1(p); } /** * visu_node_mover_rotation_new: * * Creates a new rotation. * * Since: 3.8 * * Returns: (transfer full): a new #VisuNodeMoverRotation object. **/ VisuNodeMoverRotation* visu_node_mover_rotation_new() { return g_object_new(VISU_TYPE_NODE_MOVER_ROTATION, NULL); } /** * visu_node_mover_rotation_new_full: * @ids: (element-type guint): a set of node ids. * @axis: (array fixed-size=3): an axis in cartesian coordinates. * @center: (array fixed-size=3): a point in cartesian coordinates. * @angle: an angle in degrees. * * Creates a new rotation. * * Since: 3.8 * * Returns: (transfer full): a new #VisuNodeMoverRotation object. **/ VisuNodeMoverRotation* visu_node_mover_rotation_new_full(const GArray *ids, const gfloat axis[3], const gfloat center[3], gfloat angle) { return g_object_new(VISU_TYPE_NODE_MOVER_ROTATION, "ids", ids, "axis", axis, "center", center, "angle", angle, NULL); } /** * visu_node_mover_rotation_setAngle: * @rot: a #VisuNodeMoverRotation object. * @angle: an angle in degree. * * Defines the angle of @rot. * * Since: 3.8 * * Returns: TRUE if value is actually changed. **/ gboolean visu_node_mover_rotation_setAngle(VisuNodeMoverRotation *rot, gfloat angle) { g_return_val_if_fail(VISU_IS_NODE_MOVER_ROTATION(rot), FALSE); if (rot->priv->params.angle == angle) return FALSE; rot->priv->params.angle = angle; g_object_notify_by_pspec(G_OBJECT(rot), _properties[ANGLE_PROP]); g_object_notify(G_OBJECT(rot), "valid"); return TRUE; } /** * visu_node_mover_rotation_setCenter: * @rot: a #VisuNodeMoverRotation object. * @center: (array fixed-size=3): a point in cartesian coordinates. * * Defines the center of @rot. * * Since: 3.8 * * Returns: TRUE if value is actually changed. **/ gboolean visu_node_mover_rotation_setCenter(VisuNodeMoverRotation *rot, const gfloat center[3]) { g_return_val_if_fail(VISU_IS_NODE_MOVER_ROTATION(rot), FALSE); DBG_fprintf(stderr, "Visu MoverRotation: set center %gx%gx%g.\n", center[0], center[1], center[2]); if (!tool_vector_set(rot->priv->params.center, center)) return FALSE; g_object_notify_by_pspec(G_OBJECT(rot), _properties[CENTER_PROP]); g_object_notify(G_OBJECT(rot), "valid"); return TRUE; } /** * visu_node_mover_rotation_setAxis: * @rot: a #VisuNodeMoverRotation object. * @axis: (array fixed-size=3): an axis in cartesian coordinates. * * Defines the axis of @rot. * * Since: 3.8 * * Returns: TRUE if value is actually changed. **/ gboolean visu_node_mover_rotation_setAxis(VisuNodeMoverRotation *rot, const gfloat axis[3]) { g_return_val_if_fail(VISU_IS_NODE_MOVER_ROTATION(rot), FALSE); DBG_fprintf(stderr, "Visu MoverRotation: set center %gx%gx%g.\n", axis[0], axis[1], axis[2]); if (!tool_vector_set(rot->priv->params.axis, axis)) return FALSE; g_object_notify_by_pspec(G_OBJECT(rot), _properties[AXIS_PROP]); g_object_notify(G_OBJECT(rot), "valid"); return TRUE; } /** * visu_node_mover_rotation_getAngle: * @rot: a #VisuNodeMoverRotation object. * * Retrieves the rotation angle. * * Since: 3.8 * * Returns: an angle in degrees. **/ gfloat visu_node_mover_rotation_getAngle(const VisuNodeMoverRotation *rot) { g_return_val_if_fail(VISU_IS_NODE_MOVER_ROTATION(rot), 0.f); return rot->priv->params.angle; } /** * visu_node_mover_rotation_getCenter: * @rot: a #VisuNodeMoverRotation object. * @center: (out) (array fixed-size=3): a location for the center. * * Retrieves the rotation center. * * Since: 3.8 **/ void visu_node_mover_rotation_getCenter(const VisuNodeMoverRotation *rot, gfloat center[3]) { g_return_if_fail(VISU_IS_NODE_MOVER_ROTATION(rot)); tool_vector_set(center, rot->priv->params.center); } /** * visu_node_mover_rotation_getAxis: * @rot: a #VisuNodeMoverRotation object. * @axis: (out) (array fixed-size=3): a location for the axis. * * Retrieves the rotation axis. * * Since: 3.8 **/ void visu_node_mover_rotation_getAxis(const VisuNodeMoverRotation *rot, gfloat axis[3]) { g_return_if_fail(VISU_IS_NODE_MOVER_ROTATION(rot)); tool_vector_set(axis, rot->priv->params.axis); } v_sim-3.8.0/src/extraFunctions/rotate.h000066400000000000000000000117021370110300500201000ustar00rootroot00000000000000/* EXTRAITS DE LA LICENCE Copyright CEA, contributeurs : Damien CALISTE, laboratoire L_Sim, (2017) Adresse mèl : CALISTE, damien P caliste AT cea P fr. Ce logiciel est un programme informatique servant à visualiser des structures atomiques dans un rendu pseudo-3D. Ce logiciel est régi par la licence CeCILL soumise au droit français et respectant les principes de diffusion des logiciels libres. Vous pouvez utiliser, modifier et/ou redistribuer ce programme sous les conditions de la licence CeCILL telle que diffusée par le CEA, le CNRS et l'INRIA sur le site "http://www.cecill.info". Le fait que vous puissiez accéder à cet en-tête signifie que vous avez pris connaissance de la licence CeCILL, et que vous en avez accepté les termes (cf. le fichier Documentation/licence.fr.txt fourni avec ce logiciel). */ /* LICENCE SUM UP Copyright CEA, contributors : Damien CALISTE, laboratoire L_Sim, (2017) E-mail address: CALISTE, damien P caliste AT cea P fr. This software is a computer program whose purpose is to visualize atomic configurations in 3D. This software is governed by the CeCILL license under French law and abiding by the rules of distribution of free software. You can use, modify and/ or redistribute the software under the terms of the CeCILL license as circulated by CEA, CNRS and INRIA at the following URL "http://www.cecill.info". The fact that you are presently reading this means that you have had knowledge of the CeCILL license and that you accept its terms. You can find a copy of this licence shipped with this software at COPYING. */ #ifndef ROTATE_H #define ROTATE_H #include "mover.h" G_BEGIN_DECLS /** * VISU_TYPE_NODE_MOVER_ROTATION: * * return the type of #VisuNodeMoverRotation. * * Since: 3.8 */ #define VISU_TYPE_NODE_MOVER_ROTATION (visu_node_mover_rotation_get_type ()) /** * VISU_NODE_MOVER_ROTATION: * @obj: a #GObject to cast. * * Cast the given @obj into #VisuNodeMoverRotation type. * * Since: 3.8 */ #define VISU_NODE_MOVER_ROTATION(obj) (G_TYPE_CHECK_INSTANCE_CAST(obj, VISU_TYPE_NODE_MOVER_ROTATION, VisuNodeMoverRotation)) /** * VISU_NODE_MOVER_ROTATION_CLASS: * @klass: a #GObjectClass to cast. * * Cast the given @klass into #VisuNodeMoverRotationClass. * * Since: 3.8 */ #define VISU_NODE_MOVER_ROTATION_CLASS(klass) (G_TYPE_CHECK_CLASS_CAST(klass, VISU_TYPE_NODE_MOVER_ROTATION, VisuNodeMoverRotationClass)) /** * VISU_IS_NODE_MOVER_ROTATION: * @obj: a #GObject to test. * * Test if the given @ogj is of the type of #VisuNodeMoverRotation object. * * Since: 3.8 */ #define VISU_IS_NODE_MOVER_ROTATION(obj) (G_TYPE_CHECK_INSTANCE_TYPE(obj, VISU_TYPE_NODE_MOVER_ROTATION)) /** * VISU_IS_NODE_MOVER_ROTATION_CLASS: * @klass: a #GObjectClass to test. * * Test if the given @klass is of the type of #VisuNodeMoverRotationClass class. * * Since: 3.8 */ #define VISU_IS_NODE_MOVER_ROTATION_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE(klass, VISU_TYPE_NODE_MOVER_ROTATION)) /** * VISU_NODE_MOVER_ROTATION_GET_CLASS: * @obj: a #GObject to get the class of. * * It returns the class of the given @obj. * * Since: 3.8 */ #define VISU_NODE_MOVER_ROTATION_GET_CLASS(obj) (G_TYPE_INSTANCE_GET_CLASS(obj, VISU_TYPE_NODE_MOVER_ROTATION, VisuNodeMoverRotationClass)) typedef struct _VisuNodeMoverRotation VisuNodeMoverRotation; typedef struct _VisuNodeMoverRotationPrivate VisuNodeMoverRotationPrivate; typedef struct _VisuNodeMoverRotationClass VisuNodeMoverRotationClass; struct _VisuNodeMoverRotation { VisuNodeMover parent; VisuNodeMoverRotationPrivate *priv; }; struct _VisuNodeMoverRotationClass { VisuNodeMoverClass parent; }; /** * visu_node_mover_rotation_get_type: * * This method returns the type of #VisuNodeMoverRotation, use * VISU_TYPE_NODE_MOVER_ROTATION instead. * * Since: 3.8 * * Returns: the type of #VisuNodeMoverRotation. */ GType visu_node_mover_rotation_get_type(void); VisuNodeMoverRotation* visu_node_mover_rotation_new(); VisuNodeMoverRotation* visu_node_mover_rotation_new_full(const GArray *ids, const gfloat axis[3], const gfloat center[3], gfloat angle); gboolean visu_node_mover_rotation_setAngle(VisuNodeMoverRotation *rot, gfloat angle); gboolean visu_node_mover_rotation_setCenter(VisuNodeMoverRotation *rot, const gfloat center[3]); gboolean visu_node_mover_rotation_setAxis(VisuNodeMoverRotation *rot, const gfloat axis[3]); gfloat visu_node_mover_rotation_getAngle(const VisuNodeMoverRotation *rot); void visu_node_mover_rotation_getCenter(const VisuNodeMoverRotation *rot, gfloat center[3]); void visu_node_mover_rotation_getAxis(const VisuNodeMoverRotation *rot, gfloat axis[3]); G_END_DECLS #endif v_sim-3.8.0/src/extraFunctions/scalarFieldSet.c000066400000000000000000000370341370110300500214700ustar00rootroot00000000000000/* EXTRAITS DE LA LICENCE Copyright CEA, contributeurs : Damien CALISTE, laboratoire L_Sim, (2016) Adresse mèl : CALISTE, damien P caliste AT cea P fr. Ce logiciel est un programme informatique servant à visualiser des structures atomiques dans un rendu pseudo-3D. Ce logiciel est régi par la licence CeCILL soumise au droit français et respectant les principes de diffusion des logiciels libres. Vous pouvez utiliser, modifier et/ou redistribuer ce programme sous les conditions de la licence CeCILL telle que diffusée par le CEA, le CNRS et l'INRIA sur le site "http://www.cecill.info". Le fait que vous puissiez accéder à cet en-tête signifie que vous avez pris connaissance de la licence CeCILL, et que vous en avez accepté les termes (cf. le fichier Documentation/licence.fr.txt fourni avec ce logiciel). */ /* LICENCE SUM UP Copyright CEA, contributors : Damien CALISTE, laboratoire L_Sim, (2016) E-mail address: CALISTE, damien P caliste AT cea P fr. This software is a computer program whose purpose is to visualize atomic configurations in 3D. This software is governed by the CeCILL license under French law and abiding by the rules of distribution of free software. You can use, modify and/ or redistribute the software under the terms of the CeCILL license as circulated by CEA, CNRS and INRIA at the following URL "http://www.cecill.info". The fact that you are presently reading this means that you have had knowledge of the CeCILL license and that you accept its terms. You can find a copy of this licence shipped with this software at Documentation/licence.en.txt. */ #include "scalarFieldSet.h" #include #include /** * SECTION:scalarFieldSet * @short_description: Defines a storage object to gather #VisuScalarField objects. * * A #VisuScalarfieldSet object is a storage object for a bunch of * #VisuScalarField. This object provides methods to iterate over the * internal storage. */ /** * VisuScalarfieldSetIter: * @set: the #VisuScalarfieldSet to iter on. * @field: the current #VisuScalarField. * @next: (element-type gpointer): internal index. * * Structure to iterate over the stored @field of @set. * * Since: 3.8 */ struct _item { gchar *label; VisuScalarField *field; }; struct _item* newItem(const char *label, VisuScalarField *field) { struct _item *item; item = g_malloc(sizeof(struct _item)); item->label = g_strdup(label); g_object_ref(G_OBJECT(field)); item->field = field; return item; } static void freeItem(struct _item *item) { g_object_unref(G_OBJECT(item->field)); g_free(item->label); g_free(item); } static gint findItem(const struct _item *a, const VisuScalarField *b) { return (a->field == b) ? 0 : 1; } struct _VisuScalarfieldSetPrivate { gboolean dispose_has_run; /* A GList to store all the fields. */ GList *set; }; enum { ADD_SIGNAL, REMOVE_SIGNAL, NB_SIGNAL }; static guint _signals[NB_SIGNAL] = { 0 }; enum { PROP_0, N_FIELDS_PROP, N_PROP }; static GParamSpec *properties[N_PROP]; static void visu_scalarfield_set_dispose (GObject* obj); static void visu_scalarfield_set_get_property(GObject* obj, guint property_id, GValue *value, GParamSpec *pspec); G_DEFINE_TYPE_WITH_CODE(VisuScalarfieldSet, visu_scalarfield_set, VISU_TYPE_OBJECT, G_ADD_PRIVATE(VisuScalarfieldSet)) static void visu_scalarfield_set_class_init(VisuScalarfieldSetClass *klass) { DBG_fprintf(stderr, "Visu Field Set: creating the class of the object.\n"); /* DBG_fprintf(stderr, " - adding new signals ;\n"); */ /* Connect the overloading methods. */ G_OBJECT_CLASS(klass)->dispose = visu_scalarfield_set_dispose; G_OBJECT_CLASS(klass)->get_property = visu_scalarfield_set_get_property; /** * VisuScalarfieldSet::added: * @set: the object emitting the signal. * @field: the added #VisuScalarField object. * * This signal is emitted each time a field is added to * the set. * * Since: 3.8 */ _signals[ADD_SIGNAL] = g_signal_new("added", G_TYPE_FROM_CLASS(klass), G_SIGNAL_RUN_LAST | G_SIGNAL_NO_RECURSE | G_SIGNAL_NO_HOOKS, 0, NULL, NULL, g_cclosure_marshal_VOID__OBJECT, G_TYPE_NONE, 1, VISU_TYPE_SCALAR_FIELD, NULL); /** * VisuScalarfieldSet::removed: * @set: the object emitting the signal. * @field: the removed #VisuScalarField object. * * This signal is emitted each time a field is removed from * the set. * * Since: 3.8 */ _signals[REMOVE_SIGNAL] = g_signal_new("removed", G_TYPE_FROM_CLASS(klass), G_SIGNAL_RUN_LAST | G_SIGNAL_NO_RECURSE | G_SIGNAL_NO_HOOKS, 0, NULL, NULL, g_cclosure_marshal_VOID__OBJECT, G_TYPE_NONE, 1, VISU_TYPE_SCALAR_FIELD, NULL); /** * VisuScalarfieldSet::n-fields: * * Number of stored fields. * * Since: 3.8 */ properties[N_FIELDS_PROP] = g_param_spec_uint("n-fields", "Number of fields", "number of fields", 0, G_MAXUINT, 0, G_PARAM_READABLE | G_PARAM_STATIC_STRINGS); g_object_class_install_property (G_OBJECT_CLASS(klass), N_FIELDS_PROP, properties[N_FIELDS_PROP]); } static void visu_scalarfield_set_init(VisuScalarfieldSet *ext) { DBG_fprintf(stderr, "Visu Field Set: initializing a new object (%p).\n", (gpointer)ext); ext->priv = visu_scalarfield_set_get_instance_private(ext); ext->priv->dispose_has_run = FALSE; ext->priv->set = (GList*)0; } /* This method can be called several times. It should unref all of its reference to GObjects. */ static void visu_scalarfield_set_dispose(GObject* obj) { VisuScalarfieldSet *set; DBG_fprintf(stderr, "Visu Field Set: dispose object %p.\n", (gpointer)obj); set = VISU_SCALARFIELD_SET(obj); if (set->priv->dispose_has_run) return; set->priv->dispose_has_run = TRUE; /* Disconnect signals. */ g_list_free_full(set->priv->set, (GDestroyNotify)freeItem); /* Chain up to the parent class */ G_OBJECT_CLASS(visu_scalarfield_set_parent_class)->dispose(obj); } static void visu_scalarfield_set_get_property(GObject* obj, guint property_id, GValue *value, GParamSpec *pspec) { VisuScalarfieldSetPrivate *self = VISU_SCALARFIELD_SET(obj)->priv; DBG_fprintf(stderr, "Visu ScalarfieldSet: get property '%s' -> ", g_param_spec_get_name(pspec)); switch (property_id) { case N_FIELDS_PROP: g_value_set_uint(value, g_list_length(self->set)); DBG_fprintf(stderr, "%d.\n", g_value_get_uint(value)); break; default: /* We don't have any other property... */ G_OBJECT_WARN_INVALID_PROPERTY_ID(obj, property_id, pspec); break; } } /** * visu_scalarfield_set_new: * * Creates an object to store several fields and do hiding operations * with them. * * Since: 3.8 * * Returns: (transfer full): the newly created object. **/ VisuScalarfieldSet* visu_scalarfield_set_new() { VisuScalarfieldSet *set; set = VISU_SCALARFIELD_SET(g_object_new(VISU_TYPE_SCALARFIELD_SET, NULL)); return set; } /** * visu_scalarfield_set_iter_new: * @set: a #VisuScalarfieldSet object. * @iter: (out caller-allocates): the iterator to create. * * Creates an iterator on the internal storage of #VisuScalarField objects. * * Since: 3.8 * * Returns: TRUE if iterator is valid (i.e. there are fields in @set). **/ gboolean visu_scalarfield_set_iter_new(const VisuScalarfieldSet *set, VisuScalarfieldSetIter *iter) { g_return_val_if_fail(VISU_IS_SCALARFIELD_SET(set) && iter, FALSE); memset(iter, '\0', sizeof(VisuScalarfieldSetIter)); iter->set = set; iter->next = set->priv->set; return (iter->next != (GList*)0); } /** * visu_scalarfield_set_iter_next: * @iter: an iterator. * * Use this function to iterate on field stored in a #VisuScalarfieldSet object. * * Since: 3.8 * * Returns: TRUE if any field remains. **/ gboolean visu_scalarfield_set_iter_next(VisuScalarfieldSetIter *iter) { g_return_val_if_fail(iter && iter->set, FALSE); if (!iter->next) iter->field = (VisuScalarField*)0; else { iter->field = VISU_SCALAR_FIELD(((struct _item*)iter->next->data)->field); iter->next = g_list_next(iter->next); } return (iter->field != (VisuScalarField*)0); } /** * visu_scalarfield_set_getAt: * @set: a #VisuScalarfieldSet object. * @i: an index. * * Retrieve the field stored at index @i. * * Since: 3.8 * * Returns: (transfer none) (allow-none): a #VisuScalarField object or NULL * index is out of bounds. **/ VisuScalarField* visu_scalarfield_set_getAt(const VisuScalarfieldSet *set, guint i) { GList *at; g_return_val_if_fail(VISU_IS_SCALARFIELD_SET(set), (VisuScalarField*)0); at = g_list_nth(set->priv->set, i); if (at) return VISU_SCALAR_FIELD(((struct _item*)at->data)->field); else return (VisuScalarField*)0; } /** * visu_scalarfield_set_getLabel: * @set: a #VisuScalarfieldSet object. * @field: a #VisuScalarField object. * * Retrieve the label that has been associated to @field. * * Since: 3.8 * * Returns: the label associated to @field, if @field belongs to @set. **/ const gchar* visu_scalarfield_set_getLabel(const VisuScalarfieldSet *set, const VisuScalarField *field) { GList *lst; g_return_val_if_fail(VISU_IS_SCALARFIELD_SET(set) && field, (const gchar*)0); lst = g_list_find_custom(set->priv->set, field, (GCompareFunc)findItem); if (!lst) return (const gchar*)0; return ((struct _item*)lst->data)->label; } /** * visu_scalarfield_set_getLength: * @set: a #VisuScalarfieldSet object. * * Retrieve the number of fields stored in @set. * * Since: 3.8 * * Returns: the size of the set. **/ guint visu_scalarfield_set_getLength(const VisuScalarfieldSet *set) { g_return_val_if_fail(VISU_IS_SCALARFIELD_SET(set), 0); return g_list_length(set->priv->set); } /** * visu_scalarfield_set_add: * @set: a #VisuScalarfieldSet object. * @label: a string. * @field: (transfer none): a #VisuScalarField object. * * Adds a @field to the list of stored fields. @label is not * necessarily unique in he set. * * Since: 3.8 * * Returns: FALSE if @field was already registered. **/ gboolean visu_scalarfield_set_add(VisuScalarfieldSet *set, const gchar *label, VisuScalarField *field) { GList *lst; g_return_val_if_fail(VISU_IS_SCALARFIELD_SET(set) && field, FALSE); lst = g_list_find_custom(set->priv->set, field, (GCompareFunc)findItem); if (lst) return FALSE; set->priv->set = g_list_append(set->priv->set, newItem(label, field)); g_signal_emit(G_OBJECT(set), _signals[ADD_SIGNAL], 0, field); g_object_notify_by_pspec(G_OBJECT(set), properties[N_FIELDS_PROP]); return TRUE; } static gboolean _takeFields(VisuScalarfieldSet *set, const gchar *filename, GList *fields) { GList *it; gchar *name; if (!fields) return FALSE; name = g_path_get_basename(filename); g_object_freeze_notify(G_OBJECT(set)); for (it = fields; it; it = g_list_next(it)) visu_scalarfield_set_add(set, name, VISU_SCALAR_FIELD(it->data)); g_object_thaw_notify(G_OBJECT(set)); g_free(name); g_list_free_full(fields, g_object_unref); return TRUE; } /** * visu_scalarfield_set_addFromFile: * @set: a #VisuScalarfieldSet object. * @meth: (allow-none): a #VisuScalarFieldMethod object. * @filename: (type filename): the path to the file to be loaded ; * @table: (allow-none): a set of different options (can be NULL). * @cancel: (allow-none): a #GCancellable object. * @callback: (allow-none): a method to call when the load finishes. * @user_data: (scope async): some user data. * * Read the given file and try to load it as a scalar field file. If succeed, * all read fields are added to @set. If @table is given, it means * that the caller routine gives some options to the loader * routine. These options are a set of names and values. If @meth is * %NULL, then all known methods are used to parse @filename. * * This is an asynchronous method. Use * visu_scalarfield_set_addFromFileSync() for a blocking equivalent. * * Since: 3.8 * * Returns: TRUE if everything goes with no error. */ gboolean visu_scalarfield_set_addFromFile(VisuScalarfieldSet *set, VisuScalarFieldMethod *meth, const gchar *filename, GHashTable *table, GCancellable *cancel, GAsyncReadyCallback callback, gpointer user_data) { GList *fields; if (meth) fields = visu_scalar_field_method_load(meth, filename, table, cancel, callback, user_data); else fields = visu_scalar_field_data_new_fromFile(filename, table, cancel, callback, user_data); return _takeFields(set, filename, fields); } /** * visu_scalarfield_set_addFromFileSync: * @set: a #VisuScalarfieldSet object. * @meth: (allow-none): a #VisuScalarFieldMethod object. * @filename: (type filename): the path to the file to be loaded ; * @table: (allow-none): a set of different options (can be NULL). * @cancel: (allow-none): a #GCancellable object. * @error: (allow-none): an error location. * * As visu_scalarfield_set_addFromFileSync(), but blocking variant. * * Since: 3.8 * * Returns: TRUE if everything goes with no error. */ gboolean visu_scalarfield_set_addFromFileSync(VisuScalarfieldSet *set, VisuScalarFieldMethod *meth, const gchar *filename, GHashTable *table, GCancellable *cancel, GError **error) { GList *fields; if (meth) fields = visu_scalar_field_method_loadSync(meth, filename, table, cancel, error); else fields = visu_scalar_field_data_new_fromFileSync(filename, table, cancel, error); return _takeFields(set, filename, fields); } /** * visu_scalarfield_set_remove: * @set: a #VisuScalarfieldSet object. * @field: a #VisuScalarField object. * * Remove @field from the list of stored fields. * * Since: 3.8 * * Returns: TRUE if @field was found and removed. **/ gboolean visu_scalarfield_set_remove(VisuScalarfieldSet *set, VisuScalarField *field) { GList *lst; g_return_val_if_fail(VISU_IS_SCALARFIELD_SET(set) && field, FALSE); lst = g_list_find_custom(set->priv->set, field, (GCompareFunc)findItem); if (!lst) return FALSE; freeItem((struct _item*)lst->data); set->priv->set = g_list_delete_link(set->priv->set, lst); g_signal_emit(G_OBJECT(set), _signals[REMOVE_SIGNAL], 0, field); g_object_notify_by_pspec(G_OBJECT(set), properties[N_FIELDS_PROP]); return TRUE; } static VisuScalarfieldSet *defaultSet = NULL; /** * visu_scalarfield_set_getDefault: * * Retrieve the default storage for #VisuScalarField objects. * * Since: 3.8 * * Returns: (transfer none): the default #VisuScalarfieldSet object. **/ VisuScalarfieldSet* visu_scalarfield_set_getDefault(void) { if (!defaultSet) defaultSet = visu_scalarfield_set_new(); return defaultSet; } /** * visu_scalarfield_set_class_finalize: (skip) * * Cleanup function. * * Since: 3.8 **/ void visu_scalarfield_set_class_finalize(void) { if (defaultSet) g_object_unref(defaultSet); } v_sim-3.8.0/src/extraFunctions/scalarFieldSet.h000066400000000000000000000137141370110300500214740ustar00rootroot00000000000000/* EXTRAITS DE LA LICENCE Copyright CEA, contributeurs : Damien CALISTE, laboratoire L_Sim, (2016) Adresse mèl : CALISTE, damien P caliste AT cea P fr. Ce logiciel est un programme informatique servant à visualiser des structures atomiques dans un rendu pseudo-3D. Ce logiciel est régi par la licence CeCILL soumise au droit français et respectant les principes de diffusion des logiciels libres. Vous pouvez utiliser, modifier et/ou redistribuer ce programme sous les conditions de la licence CeCILL telle que diffusée par le CEA, le CNRS et l'INRIA sur le site "http://www.cecill.info". Le fait que vous puissiez accéder à cet en-tête signifie que vous avez pris connaissance de la licence CeCILL, et que vous en avez accepté les termes (cf. le fichier Documentation/licence.fr.txt fourni avec ce logiciel). */ /* LICENCE SUM UP Copyright CEA, contributors : Damien CALISTE, laboratoire L_Sim, (2016) E-mail address: CALISTE, damien P caliste AT cea P fr. This software is a computer program whose purpose is to visualize atomic configurations in 3D. This software is governed by the CeCILL license under French law and abiding by the rules of distribution of free software. You can use, modify and/ or redistribute the software under the terms of the CeCILL license as circulated by CEA, CNRS and INRIA at the following URL "http://www.cecill.info". The fact that you are presently reading this means that you have had knowledge of the CeCILL license and that you accept its terms. You can find a copy of this licence shipped with this software at Documentation/licence.en.txt. */ #ifndef SCALARFIELDSET_H #define SCALARFIELDSET_H #include #include #include "scalarFields.h" #include "sfielddata.h" G_BEGIN_DECLS /** * VISU_TYPE_SCALARFIELD_SET: * * return the type of #VisuScalarfieldSet. */ #define VISU_TYPE_SCALARFIELD_SET (visu_scalarfield_set_get_type ()) /** * VISU_SCALARFIELD_SET: * @obj: a #GObject to cast. * * Cast the given @obj into #VisuScalarfieldSet type. */ #define VISU_SCALARFIELD_SET(obj) (G_TYPE_CHECK_INSTANCE_CAST(obj, VISU_TYPE_SCALARFIELD_SET, VisuScalarfieldSet)) /** * VISU_SCALARFIELD_SET_CLASS: * @klass: a #GObjectClass to cast. * * Cast the given @klass into #VisuScalarfieldSetClass. */ #define VISU_SCALARFIELD_SET_CLASS(klass) (G_TYPE_CHECK_CLASS_CAST(klass, VISU_TYPE_SCALARFIELD_SET, VisuScalarfieldSetClass)) /** * VISU_IS_SCALARFIELD_SET: * @obj: a #GObject to test. * * Test if the given @ogj is of the type of #VisuScalarfieldSet object. */ #define VISU_IS_SCALARFIELD_SET(obj) (G_TYPE_CHECK_INSTANCE_TYPE(obj, VISU_TYPE_SCALARFIELD_SET)) /** * VISU_IS_SCALARFIELD_SET_CLASS: * @klass: a #GObjectClass to test. * * Test if the given @klass is of the type of #VisuScalarfieldSetClass class. */ #define VISU_IS_SCALARFIELD_SET_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE(klass, VISU_TYPE_SCALARFIELD_SET)) /** * VISU_SCALARFIELD_SET_GET_CLASS: * @obj: a #GObject to get the class of. * * It returns the class of the given @obj. */ #define VISU_SCALARFIELD_SET_GET_CLASS(obj) (G_TYPE_INSTANCE_GET_CLASS(obj, VISU_TYPE_SCALARFIELD_SET, VisuScalarfieldSetClass)) /** * VisuScalarfieldSetPrivate: * * Private data for #VisuScalarfieldSet objects. */ typedef struct _VisuScalarfieldSetPrivate VisuScalarfieldSetPrivate; /** * VisuScalarfieldSet: * * Common name to refer to a #_VisuScalarfieldSet. */ typedef struct _VisuScalarfieldSet VisuScalarfieldSet; struct _VisuScalarfieldSet { VisuObject parent; VisuScalarfieldSetPrivate *priv; }; /** * VisuScalarfieldSetClass: * @parent: private. * * Common name to refer to a #_VisuScalarfieldSetClass. */ typedef struct _VisuScalarfieldSetClass VisuScalarfieldSetClass; struct _VisuScalarfieldSetClass { VisuObjectClass parent; }; /** * visu_scalarfield_set_get_type: * * This method returns the type of #VisuScalarfieldSet, use * VISU_TYPE_SCALARFIELD_SET instead. * * Since: 3.8 * * Returns: the type of #VisuScalarfieldSet. */ GType visu_scalarfield_set_get_type(void); VisuScalarfieldSet* visu_scalarfield_set_new(); gboolean visu_scalarfield_set_add(VisuScalarfieldSet *set, const gchar *label, VisuScalarField *field); gboolean visu_scalarfield_set_addFromFile(VisuScalarfieldSet *set, VisuScalarFieldMethod *meth, const gchar *filename, GHashTable *table, GCancellable *cancel, GAsyncReadyCallback callback, gpointer user_data); gboolean visu_scalarfield_set_addFromFileSync(VisuScalarfieldSet *set, VisuScalarFieldMethod *meth, const gchar *filename, GHashTable *table, GCancellable *cancel, GError **error); gboolean visu_scalarfield_set_remove(VisuScalarfieldSet *set, VisuScalarField *field); VisuScalarField* visu_scalarfield_set_getAt(const VisuScalarfieldSet *set, guint i); guint visu_scalarfield_set_getLength(const VisuScalarfieldSet *set); const gchar* visu_scalarfield_set_getLabel(const VisuScalarfieldSet *set, const VisuScalarField *field); VisuScalarfieldSet* visu_scalarfield_set_getDefault(void); void visu_scalarfield_set_class_finalize(void); typedef struct _VisuScalarfieldSetIter VisuScalarfieldSetIter; struct _VisuScalarfieldSetIter { const VisuScalarfieldSet *set; VisuScalarField *field; GList *next; }; gboolean visu_scalarfield_set_iter_new(const VisuScalarfieldSet *set, VisuScalarfieldSetIter *iter); gboolean visu_scalarfield_set_iter_next(VisuScalarfieldSetIter *iter); G_END_DECLS #endif v_sim-3.8.0/src/extraFunctions/scalarFields.c000066400000000000000000000765311370110300500212040ustar00rootroot00000000000000/* EXTRAITS DE LA LICENCE Copyright CEA, contributeurs : Luc BILLARD, Damien CALISTE, Olivier D'Astier, laboratoire L_Sim, (2001-2005) Adresses mél : BILLARD, non joignable par mél ; CALISTE, damien P caliste AT cea P fr. D'ASTIER, dastier AT iie P cnam P fr. Ce logiciel est un programme informatique servant à visualiser des structures atomiques dans un rendu pseudo-3D. Ce logiciel est régi par la licence CeCILL soumise au droit français et respectant les principes de diffusion des logiciels libres. Vous pouvez utiliser, modifier et/ou redistribuer ce programme sous les conditions de la licence CeCILL telle que diffusée par le CEA, le CNRS et l'INRIA sur le site "http://www.cecill.info". Le fait que vous puissiez accéder à cet en-tête signifie que vous avez pris connaissance de la licence CeCILL, et que vous en avez accepté les termes (cf. le fichier Documentation/licence.fr.txt fourni avec ce logiciel). */ /* LICENCE SUM UP Copyright CEA, contributors : Luc BILLARD and Damien CALISTE and Olivier D'Astier, laboratoire L_Sim, (2001-2005) E-mail addresses : BILLARD, not reachable any more ; CALISTE, damien P caliste AT cea P fr. D'ASTIER, dastier AT iie P cnam P fr. This software is a computer program whose purpose is to visualize atomic configurations in 3D. This software is governed by the CeCILL license under French law and abiding by the rules of distribution of free software. You can use, modify and/ or redistribute the software under the terms of the CeCILL license as circulated by CEA, CNRS and INRIA at the following URL "http://www.cecill.info". The fact that you are presently reading this means that you have had knowledge of the CeCILL license and that you accept its terms. You can find a copy of this licence shipped with this software at Documentation/licence.en.txt. */ #include "scalarFields.h" #include #include #include #include #include /** * SECTION:scalarFields * @short_description:Gives capabilities to load a scalar field. * * A scalar field is represented by the given of datas on a * regular grid meshing the bounding box. Scalar field can be read * from several kind of files by adding load methods using * scalarFieldAdd_loadMethod(). The basic implementation gives access * to ASCII encoded files following a simple format. * * When the scalar field is periodic, the values on the border x = 1, * y = 1 or z = 1 can be obtained reading those of border x = 0, y = 0 * or z = 0. So if there are n values in one direction, the nth is at * position 1 - 1/n in box coordinates in that direction. On the * contrary, for non-periodic scalar field, the nth value is at * coordinate 1 in box system and can be different from value 0. * * In coordination with #VisuPlane and #ToolShade, scalar field can be * represented as coloured map calling scalarFieldDraw_map(). The * current implementation of interpolation is very limited since basic * linear approximation is used. * * If a structure file also contains a scalar field, when * loaded, it should add a #VisuData property called * VISU_SCALAR_FIELD_DEFINED_IN_STRUCT_FILE using * g_object_set_data(). Then V_Sim will be able to handle the * structure file as a density file also. */ enum { PROP_0, LABEL_PROP, EMPTY_PROP, N_PROP, TRANS_PROP, RED_TRANS_PROP, USE_TRANS_PROP, MODULO_PROP, ADJUST_PROP, BOX_PROP }; static GParamSpec *_properties[N_PROP]; /* * _VisuScalarField: * @filename: the path to the file from which the scalar field * has been read ; * @commentary: a commentary read from the file (must be in UTF-8) ; * @box: description of the associated bounding box ; * @nElements: number of points in each direction ; * @data: the values ; * @min: the minimum value ; * @max: the maximum value ; * @options: a GList of #Option values. * * The structure used to store a scalar field. */ struct _VisuScalarFieldPrivate { gboolean dispose_has_run; /* The name of the file, where the data were read from. */ gchar *filename; /* An associated commentary. */ gchar *commentary; /* Description of the box. */ VisuBox *box; float shift[3]; gboolean adjust, inTheBox, translationActive; /* Number of elements in each directions [x, y, z]. */ guint nElements[3]; gboolean periodicity[3]; guint sizem1[3]; /* Mesh. */ VisuScalarFieldMeshFlags mesh_type; double *mesh[3]; /* A GList to store some options (key, values) associated to the data. */ GList *options; }; enum { CHANGED_SIGNAL, LAST_SIGNAL }; static guint _signals[LAST_SIGNAL] = { 0 }; /* Object gestion methods. */ static void visu_scalar_field_dispose (GObject* obj); static void visu_scalar_field_finalize(GObject* obj); static void visu_scalar_field_get_property(GObject* obj, guint property_id, GValue *value, GParamSpec *pspec); static void visu_scalar_field_set_property(GObject* obj, guint property_id, const GValue *value, GParamSpec *pspec); static void visu_boxed_interface_init (VisuBoxedInterface *iface); static void visu_pointset_interface_init(VisuPointsetInterface *iface); static void _getGridSize(const VisuScalarField *field, guint grid[3]); static gboolean _setGridSize(VisuScalarField *field, const guint grid[3]); static VisuBox* _getBox(VisuBoxed *boxed); static gboolean _setBox(VisuBoxed *self, VisuBox *box); static gboolean _inTheBox(VisuPointset *self, gboolean status); static void _getTranslation(VisuPointset *self, float trans[3]); static gboolean _setTranslation(VisuPointset *self, float trans[3], gboolean withModulo); static gboolean _setTranslationActive(VisuPointset *self, gboolean status); static void _applyTranslation(VisuPointset *self); /* Local methods. */ G_DEFINE_TYPE_WITH_CODE(VisuScalarField, visu_scalar_field, VISU_TYPE_OBJECT, G_ADD_PRIVATE(VisuScalarField) G_IMPLEMENT_INTERFACE(VISU_TYPE_BOXED, visu_boxed_interface_init) G_IMPLEMENT_INTERFACE(VISU_TYPE_POINTSET, visu_pointset_interface_init)) static void visu_scalar_field_class_init(VisuScalarFieldClass *klass) { DBG_fprintf(stderr, "VisuScalarField: creating the class of the object.\n"); /* DBG_fprintf(stderr, " - adding new signals ;\n"); */ /* Connect freeing methods. */ G_OBJECT_CLASS(klass)->dispose = visu_scalar_field_dispose; G_OBJECT_CLASS(klass)->finalize = visu_scalar_field_finalize; G_OBJECT_CLASS(klass)->set_property = visu_scalar_field_set_property; G_OBJECT_CLASS(klass)->get_property = visu_scalar_field_get_property; VISU_SCALAR_FIELD_CLASS(klass)->getGridSize = _getGridSize; VISU_SCALAR_FIELD_CLASS(klass)->setGridSize = _setGridSize; /** * VisuScalarField::label: * * Holds the label (translated) that describes the scalar field. * * Since: 3.8 */ _properties[LABEL_PROP] = g_param_spec_string("label", "Label", "description label", "", G_PARAM_READWRITE | G_PARAM_CONSTRUCT_ONLY); /** * VisuScalarField::empty: * * TRUE if the scalarfield has not yet been set a grid size and values. * * Since: 3.8 */ _properties[EMPTY_PROP] = g_param_spec_boolean("empty", "Empty", "whether has data or not", TRUE, G_PARAM_READABLE); g_object_class_install_properties(G_OBJECT_CLASS(klass), N_PROP, _properties); g_object_class_override_property(G_OBJECT_CLASS(klass), USE_TRANS_PROP, "use-translation"); g_object_class_override_property(G_OBJECT_CLASS(klass), TRANS_PROP, "translation"); g_object_class_override_property(G_OBJECT_CLASS(klass), RED_TRANS_PROP, "reduced-translation"); g_object_class_override_property(G_OBJECT_CLASS(klass), MODULO_PROP, "in-the-box"); g_object_class_override_property(G_OBJECT_CLASS(klass), ADJUST_PROP, "auto-adjust"); g_object_class_override_property(G_OBJECT_CLASS(klass), BOX_PROP, "box"); /** * VisuScalarField::changed: * @field: the object which received the signal ; * * Gets emitted when the values stored in this @field are changed. * * Since: 3.8 */ _signals[CHANGED_SIGNAL] = g_signal_new("changed", G_TYPE_FROM_CLASS(klass), G_SIGNAL_RUN_LAST | G_SIGNAL_NO_RECURSE | G_SIGNAL_NO_HOOKS, 0, NULL, NULL, g_cclosure_marshal_VOID__VOID, G_TYPE_NONE, 0, NULL); } static void visu_boxed_interface_init(VisuBoxedInterface *iface) { iface->get_box = _getBox; iface->set_box = _setBox; } static void visu_pointset_interface_init(VisuPointsetInterface *iface) { iface->set_inTheBox = _inTheBox; iface->apply_translation = _applyTranslation; iface->get_translation = _getTranslation; iface->set_translation = _setTranslation; iface->set_translationActive = _setTranslationActive; } static void visu_scalar_field_init(VisuScalarField *obj) { DBG_fprintf(stderr, "VisuScalarField: creating a new scalar_field (%p).\n", (gpointer)obj); obj->priv = visu_scalar_field_get_instance_private(obj); obj->priv->dispose_has_run = FALSE; obj->priv->adjust = FALSE; obj->priv->nElements[0] = 0; obj->priv->nElements[1] = 0; obj->priv->nElements[2] = 0; obj->priv->filename = (gchar*)0; obj->priv->commentary = (gchar*)0; obj->priv->mesh[0] = (double*)0; obj->priv->mesh[1] = (double*)0; obj->priv->mesh[2] = (double*)0; obj->priv->box = (VisuBox*)0; obj->priv->mesh_type = VISU_SCALAR_FIELD_MESH_UNIFORM; obj->priv->inTheBox = FALSE; obj->priv->translationActive = FALSE; obj->priv->shift[0] = 0.f; obj->priv->shift[1] = 0.f; obj->priv->shift[2] = 0.f; obj->priv->options = (GList*)0; } static void visu_scalar_field_dispose(GObject* obj) { DBG_fprintf(stderr, "VisuScalarField: dispose object %p.\n", (gpointer)obj); if (VISU_SCALAR_FIELD(obj)->priv->dispose_has_run) return; VISU_SCALAR_FIELD(obj)->priv->dispose_has_run = TRUE; _setBox(VISU_BOXED(obj), (VisuBox*)0); /* Chain up to the parent class */ G_OBJECT_CLASS(visu_scalar_field_parent_class)->dispose(obj); } static void visu_scalar_field_finalize(GObject* obj) { VisuScalarFieldPrivate *field = VISU_SCALAR_FIELD(obj)->priv; DBG_fprintf(stderr, "VisuScalarField: finalize object %p.\n", (gpointer)obj); g_free(field->filename); g_free(field->commentary); g_free(field->mesh[0]); g_free(field->mesh[1]); g_free(field->mesh[2]); g_list_free_full(field->options, (GDestroyNotify)tool_option_free); /* Chain up to the parent class */ G_OBJECT_CLASS(visu_scalar_field_parent_class)->finalize(obj); } static void visu_scalar_field_get_property(GObject* obj, guint property_id, GValue *value, GParamSpec *pspec) { VisuScalarField *self = VISU_SCALAR_FIELD(obj); DBG_fprintf(stderr, "Visu GlView: get property '%s' -> ", g_param_spec_get_name(pspec)); switch (property_id) { case LABEL_PROP: g_value_set_string(value, self->priv->filename); DBG_fprintf(stderr, "%s.\n", self->priv->filename); break; case EMPTY_PROP: g_value_set_boolean(value, visu_scalar_field_isEmpty(self)); DBG_fprintf(stderr, "%d.\n", g_value_get_boolean(value)); break; case ADJUST_PROP: g_value_set_boolean(value, self->priv->adjust); DBG_fprintf(stderr, "%d.\n", self->priv->adjust); break; case BOX_PROP: g_value_set_object(value, self->priv->box); DBG_fprintf(stderr, "%p.\n", (gpointer)self->priv->box); break; default: /* We don't have any other property... */ G_OBJECT_WARN_INVALID_PROPERTY_ID(obj, property_id, pspec); break; } } static void visu_scalar_field_set_property(GObject* obj, guint property_id, const GValue *value, GParamSpec *pspec) { VisuScalarField *self = VISU_SCALAR_FIELD(obj); DBG_fprintf(stderr, "Visu GlView: set property '%s' -> ", g_param_spec_get_name(pspec)); switch (property_id) { case LABEL_PROP: self->priv->filename = g_value_dup_string(value); DBG_fprintf(stderr, "%s.\n", self->priv->filename); break; case ADJUST_PROP: self->priv->adjust = g_value_get_boolean(value); DBG_fprintf(stderr, "%d.\n", self->priv->adjust); break; case BOX_PROP: DBG_fprintf(stderr, "%p.\n", g_value_get_object(value)); _setBox(VISU_BOXED(obj), VISU_BOX(g_value_get_object(value))); break; default: /* We don't have any other property... */ G_OBJECT_WARN_INVALID_PROPERTY_ID(obj, property_id, pspec); break; } } /** * visu_scalar_field_new: * @label: a label to identify the scalar field. * * Create a new #VisuScalarField object that is empty (all internal pointers * are set to NULL and no memory is allocated except for the object itself. * The @label argument is copied. * * Returns: (transfer full): a newly created #VisuScalarField * object. */ VisuScalarField* visu_scalar_field_new(const gchar *label) { g_return_val_if_fail(label && label[0], (VisuScalarField*)0); return VISU_SCALAR_FIELD(g_object_new(VISU_TYPE_SCALAR_FIELD, "label", label, NULL)); } /** * visu_scalar_field_isEmpty: * @field: a #VisuScalarField object. * * Since loading of scalar fields is asynchronous, this method can be * used to inquire if @field has been populated yet or not. * * Since: 3.8 * * Returns: TRUE if @field has not been populated yet. **/ gboolean visu_scalar_field_isEmpty(const VisuScalarField *field) { VisuScalarFieldClass *klass = field ? VISU_SCALAR_FIELD_GET_CLASS(field) : NULL; g_return_val_if_fail(klass, TRUE); if (klass->isEmpty) return klass->isEmpty(field); else return FALSE; } /** * visu_scalar_field_getCommentary: * @field: a #VisuScalarField object. * * If the file format support a commentary, this is a good method to get it. * * Returns: a pointer on the commentary (it should not be freed), can be NULL. */ const gchar* visu_scalar_field_getCommentary(VisuScalarField *field) { g_return_val_if_fail(field, (gchar*)0); return field->priv->commentary; } /** * visu_scalar_field_setCommentary: * @field: a #VisuScalarField object ; * @comment: an UTF-8 string to store as a commentary. * * A commentary can be associated to a #VisuScalarField, use this method to set it. * The value of @comment is NOT copied. */ void visu_scalar_field_setCommentary(VisuScalarField *field, const gchar* comment) { g_return_if_fail(field); field->priv->commentary = g_strdup(comment); } /** * visu_scalar_field_getMeshtype: * @field: a #VisuScalarField object ; * to be added * * The vertex may be distributed linearly along the different * directions or customily distributed. * * Returns: a #VisuScalarFieldMeshFlags (uniform or nonuniform). */ VisuScalarFieldMeshFlags visu_scalar_field_getMeshtype(const VisuScalarField *field) { g_return_val_if_fail(VISU_IS_SCALAR_FIELD(field), VISU_SCALAR_FIELD_MESH_UNIFORM); return field->priv->mesh_type; } /** * visu_scalar_field_setMeshtype: * @field: a #VisuScalarField object ; * @meshtype: a #VisuScalarFieldMeshFlags object. * * Change the distribution of the vertex of the scalarfield between * regular or custom. */ void visu_scalar_field_setMeshtype(VisuScalarField *field, VisuScalarFieldMeshFlags meshtype) { g_return_if_fail(field); field->priv->mesh_type = meshtype; } /** * visu_scalar_field_getLabel: * @field: a #VisuScalarField object. * * The data are read from a file. * * Returns: a pointer on the filename (it should not be freed). */ const gchar* visu_scalar_field_getLabel(VisuScalarField *field) { g_return_val_if_fail(field, (gchar*)0); return field->priv->filename; } static gboolean _setGridSize(VisuScalarField *field, const guint grid[3]) { g_return_val_if_fail(VISU_IS_SCALAR_FIELD(field), FALSE); if (field->priv->nElements[0] == grid[0] && field->priv->nElements[1] == grid[1] && field->priv->nElements[2] == grid[2]) return FALSE; DBG_fprintf(stderr, "Visu ScalarField: changing size from (%d ; %d ; %d)" " to (%d ; %d ; %d).\n", field->priv->nElements[0], field->priv->nElements[1], field->priv->nElements[2], grid[0], grid[1], grid[2]); field->priv->nElements[0] = grid[0]; field->priv->nElements[1] = grid[1]; field->priv->nElements[2] = grid[2]; DBG_fprintf(stderr, " | free the previous mesh allocation.\n"); g_free(field->priv->mesh[0]); g_free(field->priv->mesh[1]); g_free(field->priv->mesh[2]); if (field->priv->mesh_type == VISU_SCALAR_FIELD_MESH_NON_UNIFORM) { field->priv->mesh[0] = g_malloc(sizeof(double) * grid[0]); field->priv->mesh[1] = g_malloc(sizeof(double) * grid[1]); field->priv->mesh[2] = g_malloc(sizeof(double) * grid[2]); } /* We change the size and reallocate mesh and data. */ if (field->priv->box) { field->priv->sizem1[0] = (field->priv->periodicity[0]) ? grid[0] : grid[0] - 1; field->priv->sizem1[1] = (field->priv->periodicity[1]) ? grid[1] : grid[1] - 1; field->priv->sizem1[2] = (field->priv->periodicity[2]) ? grid[2] : grid[2] - 1; } return TRUE; } /** * visu_scalar_field_setGridSize: * @field: a #VisuScalarField object ; * @grid: (array fixed-size=3): 3 integers. * * This method is used to set the division in x, y, and z directions. * If the size of internal array for data is changed, it is reallocated and * previous data are erased. Use visu_scalar_field_getData() to get a pointer on this * data array. */ gboolean visu_scalar_field_setGridSize(VisuScalarField *field, const guint grid[3]) { VisuScalarFieldClass *klass = VISU_SCALAR_FIELD_GET_CLASS(field); g_return_val_if_fail(klass && klass->setGridSize, FALSE); return klass->setGridSize(field, grid); } /** * visu_scalar_field_getMeshInside: * @field: a #VisuScalarField object. * @grid: (out) (array fixed-size=3): a location to store the mesh coordinates. * @i: an integer. * @j: an integer. * @k: an integer. * * Apply periodicity when required to convert a mesh coordinates * (i,j,k) into a valid coordinate @grid. * * Since: 3.8 **/ void visu_scalar_field_getMeshInside(const VisuScalarField *field, guint grid[3], int i, int j, int k) { g_return_if_fail(VISU_IS_SCALAR_FIELD(field)); if (field->priv->periodicity[0]) grid[0] = (i < 0)?i + field->priv->sizem1[0]:i%field->priv->sizem1[0]; else grid[0] = CLAMP(i, 0, (int)field->priv->sizem1[0]); if (field->priv->periodicity[1]) grid[1] = (j < 0)?j + field->priv->sizem1[1]:j%field->priv->sizem1[1]; else grid[1] = CLAMP(j, 0, (int)field->priv->sizem1[1]); if (field->priv->periodicity[2]) grid[2] = (k < 0)?k + field->priv->sizem1[2]:k%field->priv->sizem1[2]; else grid[2] = CLAMP(k, 0, (int)field->priv->sizem1[2]); } /** * visu_scalar_field_getCoordInside: * @field: a #VisuScalarField object. * @grid: (out) (array fixed-size=3): a location to store grid coordinates. * @dgrid: (out) (array fixed-size=3): a location to store grid coordinates. * @factor: (out) (array fixed-size=3): a location to store factors in * every directions. * @xyz: (array fixed-size=3): some cartesian coordinates. * @extension: (array fixed-size=3): extension to consider. * * From the coordinates @xyz, compute the grid coordinate @grid * closest to @xyz. Put also in @dgrid the closest grid coordinate * after @xyz. On output, @factor will contains three float in [0;1] * defining where is @xyz within the cube defined by @grid and @dgrid. * * Since: 3.8 * * Returns: TRUE if @grid is valid. **/ gboolean visu_scalar_field_getCoordInside(const VisuScalarField *field, guint grid[3], guint dgrid[3], gfloat factor[3], const gfloat xyz[3], const gfloat extension[3]) { guint l, m, n; int nval1, nval2; gfloat xyz_[3], redXyz[3], pos; g_return_val_if_fail(VISU_IS_SCALAR_FIELD(field), FALSE); /* First, we transform the coordinates into reduced coordinates. */ xyz_[0] = xyz[0] + field->priv->shift[0]; xyz_[1] = xyz[1] + field->priv->shift[1]; xyz_[2] = xyz[2] + field->priv->shift[2]; visu_box_convertXYZtoBoxCoordinates(field->priv->box, redXyz, xyz_); /* We compute i, j, k. */ for (l = 0; l < 3; l++) { /* If we are periodic and inside the extension, we put back in the box. */ if (field->priv->periodicity[l] && redXyz[l] > -extension[l] && redXyz[l] < 1. + extension[l]) redXyz[l] = tool_modulo_float(redXyz[l], 1); switch (field->priv->mesh_type) { case VISU_SCALAR_FIELD_MESH_UNIFORM: pos = (gfloat)field->priv->sizem1[l] * redXyz[l]; grid[l] = (guint)pos; factor[l] = pos - (gfloat)grid[l]; break; case VISU_SCALAR_FIELD_MESH_NON_UNIFORM: nval1 = 0; nval2 = field->priv->sizem1[l]-1; n = 0; for (m = 0; m < field->priv->sizem1[l]/2; m++) { n = (int)((nval2-nval1)/2); if (n == 0) { n = nval1; break; } else n = nval1+n; if (redXyz[l] > field->priv->mesh[l][n]) nval1 = n; else nval2 = n; } grid[l] = n; factor[l] = (redXyz[l]-field->priv->mesh[l][n]) / (field->priv->mesh[l][n+1]-field->priv->mesh[l][n]); break; default: g_warning("Wrong value for 'meshtype'."); return FALSE; } if (redXyz[l] < 0. || redXyz[l] > 1.) return FALSE; } grid[0] = grid[0] % field->priv->sizem1[0]; grid[1] = grid[1] % field->priv->sizem1[1]; grid[2] = grid[2] % field->priv->sizem1[2]; dgrid[0] = (grid[0] + 1) % field->priv->sizem1[0]; dgrid[1] = (grid[1] + 1) % field->priv->sizem1[1]; dgrid[2] = (grid[2] + 1) % field->priv->sizem1[2]; return TRUE; } /** * visu_scalar_field_getMinMax: * @field: a #VisuScalarField object ; * @minmax: (array fixed-size=2): two double values. * * Get the minimum and the maximum values of the given @field. */ void visu_scalar_field_getMinMax(const VisuScalarField *field, double minmax[2]) { VisuScalarFieldClass *klass = VISU_SCALAR_FIELD_GET_CLASS(field); g_return_if_fail(klass && klass->getAt); klass->getMinMax(field, minmax); } /** * visu_scalar_field_getGradAt: * @field: a #VisuScalarField object. * @i: an integer. * @j: an integer. * @k: an integer. * @dir: a direction. * * Computes the gradient along @dir at @i, @j and @k. * * Since: 3.8 * * Returns: the gradient value. **/ double visu_scalar_field_getGradAt(const VisuScalarField *field, int i, int j, int k, ToolXyzDir dir) { int prev[3], after[3]; g_return_val_if_fail(VISU_IS_SCALAR_FIELD(field), -1.); prev[0] = i; prev[1] = j; prev[2] = k; prev[dir] -= 1; after[0] = i; after[1] = j; after[2] = k; after[dir] += 1; if (field->priv->periodicity[dir]) return (visu_scalar_field_getAt(field, after[0], after[1], after[2]) - visu_scalar_field_getAt(field, prev[0], prev[1], prev[2])) / 2.; else { if (prev[dir] < 0 || after[dir] > (int)field->priv->sizem1[dir]) return (visu_scalar_field_getAt(field, after[0], after[1], after[2]) - visu_scalar_field_getAt(field, prev[0], prev[1], prev[2])); else return (visu_scalar_field_getAt(field, after[0], after[1], after[2]) - visu_scalar_field_getAt(field, prev[0], prev[1], prev[2])) / 2.; } } /** * visu_scalar_field_getAt: * @field: a #VisuScalarField object. * @i: an integer. * @j: an integer. * @k: an integer. * * Computes the scalarfield value at @i, @j and @k. * * Since: 3.8 * * Returns: the value. **/ double visu_scalar_field_getAt(const VisuScalarField *field, int i, int j, int k) { VisuScalarFieldClass *klass = field ? VISU_SCALAR_FIELD_GET_CLASS(field) : NULL; g_return_val_if_fail(klass && klass->getAt, -1.); return klass->getAt(field, i, j, k); } /** * visu_scalar_field_getValue: * @field: a #VisuScalarField object ; * @xyz: (array fixed-size=3): a point coordinate (in real space) ; * @value: (out caller-allocates): a location to store the value ; * @extension: (array fixed-size=3): a possible extension in box coordinates. * * Knowing the point coordinates, it interpolate a value from the * scalar field. If the scalar field is periodic, then it allow the * coordinates to extend inside the given @extension. * * Returns: TRUE if the value can be interpolate, FALSE otherwise, for instance, * when the point @xyz is out of bounds. */ gboolean visu_scalar_field_getValue(const VisuScalarField *field, float xyz[3], double *value, float extension[3]) { VisuScalarFieldClass *klass = field ? VISU_SCALAR_FIELD_GET_CLASS(field) : NULL; g_return_val_if_fail(klass && klass->getValue, FALSE); return klass->getValue(field, xyz, value, extension); } static gboolean _setBox(VisuBoxed *self, VisuBox *box) { VisuScalarField *field; g_return_val_if_fail(VISU_IS_SCALAR_FIELD(self), FALSE); field = VISU_SCALAR_FIELD(self); DBG_fprintf(stderr, "VisuScalarField: set the bounding box to %p.\n", (gpointer)box); if (field->priv->box == box) return FALSE; if (field->priv->box) g_object_unref(field->priv->box); if (box) g_object_ref(box); field->priv->box = box; if (box) { visu_box_getPeriodicity(box, field->priv->periodicity); field->priv->sizem1[0] = (field->priv->periodicity[0]) ? field->priv->nElements[0] : field->priv->nElements[0] - 1; field->priv->sizem1[1] = (field->priv->periodicity[1]) ? field->priv->nElements[1] : field->priv->nElements[1] - 1; field->priv->sizem1[2] = (field->priv->periodicity[2]) ? field->priv->nElements[2] : field->priv->nElements[2] - 1; } return TRUE; } static VisuBox* _getBox(VisuBoxed *boxed) { g_return_val_if_fail(VISU_IS_SCALAR_FIELD(boxed), (VisuBox*)0); return VISU_SCALAR_FIELD(boxed)->priv->box; } static gboolean _inTheBox(VisuPointset *self, gboolean status) { VisuScalarField *field = VISU_SCALAR_FIELD(self); g_return_val_if_fail(VISU_IS_SCALAR_FIELD(self), FALSE); if (field->priv->inTheBox == status) return FALSE; field->priv->inTheBox = status; if ((field->priv->shift[0] != 0.f || field->priv->shift[0] != 0.f || field->priv->shift[0] != 0.f) && field->priv->translationActive) g_signal_emit(self, _signals[CHANGED_SIGNAL], 0); return TRUE; } static void _applyTranslation(VisuPointset *self _U_) { g_warning("Not implemented."); } static void _getTranslation(VisuPointset *self, float trans[3]) { VisuScalarField *field; g_return_if_fail(VISU_IS_SCALAR_FIELD(self)); field = VISU_SCALAR_FIELD(self); trans[0] = field->priv->shift[0]; trans[1] = field->priv->shift[1]; trans[2] = field->priv->shift[2]; } static gboolean _setTranslation(VisuPointset *self, float trans[3], gboolean withModulo _U_) { VisuScalarField *field; gboolean res; g_return_val_if_fail(VISU_IS_SCALAR_FIELD(self), FALSE); field = VISU_SCALAR_FIELD(self); res = FALSE; if (field->priv->shift[0] != trans[0]) { field->priv->shift[0] = trans[0]; res = TRUE; } if (field->priv->shift[1] != trans[1]) { field->priv->shift[1] = trans[1]; res = TRUE; } if (field->priv->shift[2] != trans[2]) { field->priv->shift[2] = trans[2]; res = TRUE; } DBG_fprintf(stderr, "Visu ScalarField: force translation to: %f %f %f\n", field->priv->shift[0], field->priv->shift[1], field->priv->shift[2]); if (res) g_object_notify(G_OBJECT(self), "translation"); if (res && field->priv->translationActive && !visu_scalar_field_isEmpty(field)) g_signal_emit(self, _signals[CHANGED_SIGNAL], 0); return res; } static gboolean _setTranslationActive(VisuPointset *self, gboolean status) { VisuScalarField *field; g_return_val_if_fail(VISU_IS_SCALAR_FIELD(self), FALSE); field = VISU_SCALAR_FIELD(self); if (field->priv->translationActive == status) return FALSE; field->priv->translationActive = status; g_object_notify(G_OBJECT(self), "use-translation"); if (field->priv->shift[0] != 0.f || field->priv->shift[0] != 0.f || field->priv->shift[0] != 0.f) g_signal_emit(self, _signals[CHANGED_SIGNAL], 0); return TRUE; } static void _getGridSize(const VisuScalarField *field, guint grid[3]) { g_return_if_fail(VISU_IS_SCALAR_FIELD(field)); DBG_fprintf(stderr, "Visu ScalarField: get grid size.\n"); grid[0] = field->priv->nElements[0]; grid[1] = field->priv->nElements[1]; grid[2] = field->priv->nElements[2]; DBG_fprintf(stderr, " | done.\n"); } /** * visu_scalar_field_getGridSize: * @field: a #VisuScalarField object ; * @grid: (out caller-allocates) (type ToolGridSize): 3 integer locations. * * This method is used to get the division in x, y, and z directions. */ void visu_scalar_field_getGridSize(const VisuScalarField *field, guint grid[3]) { VisuScalarFieldClass *klass = VISU_SCALAR_FIELD_GET_CLASS(field); g_return_if_fail(klass && klass->getGridSize); klass->getGridSize(field, grid); } /** * visu_scalar_field_getMesh: * @field: a #VisuScalarField object. * @dir: a direction. * * The mesh along x is stored as an array in x increasing. * * Returns: a pointer on the allocated meshx array (it should not be freed). */ double* visu_scalar_field_getMesh(const VisuScalarField *field, ToolXyzDir dir) { g_return_val_if_fail(VISU_IS_SCALAR_FIELD(field), (double*)0); return field->priv->mesh[dir]; } /** * visu_scalar_field_setMesh: * @field: a #VisuScalarField object. * @mesh: an array with the mesh description in one direction. * @dir: a direction. * * Define the mesh in case of non regular one. * * Since: 3.8 **/ void visu_scalar_field_setMesh(VisuScalarField *field, const double *mesh, ToolXyzDir dir) { g_return_if_fail(VISU_IS_SCALAR_FIELD(field)); g_return_if_fail(field->priv->mesh_type == VISU_SCALAR_FIELD_MESH_NON_UNIFORM); g_return_if_fail(field->priv->mesh[dir]); memcpy(field->priv->mesh[dir], mesh, sizeof(double) * field->priv->nElements[dir]); } /** * visu_scalar_field_getAllOptions: * @field: a #VisuScalarField object. * * Some #Option can be stored in association to the values of the scalar field. * These options are usually values associated to the read data, such as * a spin direction when dealing with density of spin... * * Returns: (transfer container) (element-type ToolOption*): a newly * created GList that should be freed after use with * g_list_free(). But data of the list are owned by V_Sim and should * not be modified or freed. */ GList* visu_scalar_field_getAllOptions(VisuScalarField *field) { g_return_val_if_fail(VISU_IS_SCALAR_FIELD(field), (GList*)0); return g_list_copy(field->priv->options); } /** * visu_scalar_field_addOption: * @field: a #VisuScalarField object ; * @option: a newly allocated option. * * This method adds an option to the list of #Option associated to the data. The given * @option will not be duplicated and should not be used elsewhere because it will be freed * when the @field will be freed. */ void visu_scalar_field_addOption(VisuScalarField *field, ToolOption *option) { g_return_if_fail(VISU_IS_SCALAR_FIELD(field) && option); field->priv->options = g_list_append(field->priv->options, (gpointer)option); } v_sim-3.8.0/src/extraFunctions/scalarFields.h000066400000000000000000000170241370110300500212010ustar00rootroot00000000000000/* EXTRAITS DE LA LICENCE Copyright CEA, contributeurs : Luc BILLARD, Damien CALISTE, Olivier D'Astier, laboratoire L_Sim, (2001-2005) Adresses mèl : BILLARD, non joignable par mèl ; CALISTE, damien P caliste AT cea P fr. D'ASTIER, dastier AT iie P cnam P fr. Ce logiciel est un programme informatique servant à visualiser des structures atomiques dans un rendu pseudo-3D. Ce logiciel est régi par la licence CeCILL soumise au droit français et respectant les principes de diffusion des logiciels libres. Vous pouvez utiliser, modifier et/ou redistribuer ce programme sous les conditions de la licence CeCILL telle que diffusée par le CEA, le CNRS et l'INRIA sur le site "http://www.cecill.info". Le fait que vous puissiez accéder à cet en-tête signifie que vous avez pris connaissance de la licence CeCILL, et que vous en avez accepté les termes (cf. le fichier Documentation/licence.fr.txt fourni avec ce logiciel). */ /* LICENCE SUM UP Copyright CEA, contributors : Luc BILLARD and Damien CALISTE and Olivier D'Astier, laboratoire L_Sim, (2001-2005) E-mail addresses : BILLARD, not reachable any more ; CALISTE, damien P caliste AT cea P fr. D'ASTIER, dastier AT iie P cnam P fr. This software is a computer program whose purpose is to visualize atomic configurations in 3D. This software is governed by the CeCILL license under French law and abiding by the rules of distribution of free software. You can use, modify and/ or redistribute the software under the terms of the CeCILL license as circulated by CEA, CNRS and INRIA at the following URL "http://www.cecill.info". The fact that you are presently reading this means that you have had knowledge of the CeCILL license and that you accept its terms. You can find a copy of this licence shipped with this software at Documentation/licence.en.txt. */ #ifndef SCALARFIELDS_H #define SCALARFIELDS_H #include #include #include #include #include #include #include G_BEGIN_DECLS /** * VisuScalarFieldMeshFlags: * @VISU_SCALAR_FIELD_MESH_UNIFORM: the mesh has constant divisions along x, y and z axis ; * @VISU_SCALAR_FIELD_MESH_NON_UNIFORM: the mesh has non linear divisions along x, y or z axis. * * flag (comment) standing at the begining of a Scalar field file, * that gives informations concerning the mesh. */ typedef enum { VISU_SCALAR_FIELD_MESH_UNIFORM, VISU_SCALAR_FIELD_MESH_NON_UNIFORM } VisuScalarFieldMeshFlags; /** * VISU_TYPE_SCALAR_FIELD: * * return the type of #VisuScalarField. */ #define VISU_TYPE_SCALAR_FIELD (visu_scalar_field_get_type ()) /** * SCALAR_FIELD: * @obj: a #GObject to cast. * * Cast the given @obj into #VisuScalarField type. */ #define VISU_SCALAR_FIELD(obj) (G_TYPE_CHECK_INSTANCE_CAST(obj, VISU_TYPE_SCALAR_FIELD, VisuScalarField)) /** * VISU_SCALAR_FIELD_CLASS: * @klass: a #GObjectClass to cast. * * Cast the given @klass into #VisuScalarFieldClass. */ #define VISU_SCALAR_FIELD_CLASS(klass) (G_TYPE_CHECK_CLASS_CAST(klass, VISU_TYPE_SCALAR_FIELD, VisuScalarFieldClass)) /** * VISU_IS_SCALAR_FIELD: * @obj: a #GObject to test. * * Test if the given @ogj is of the type of #VisuScalarField object. */ #define VISU_IS_SCALAR_FIELD(obj) (G_TYPE_CHECK_INSTANCE_TYPE(obj, VISU_TYPE_SCALAR_FIELD)) /** * VISU_IS_SCALAR_FIELD_CLASS: * @klass: a #GObjectClass to test. * * Test if the given @klass is of the type of #VisuScalarFieldClass class. */ #define VISU_IS_SCALAR_FIELD_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE(klass, VISU_TYPE_SCALAR_FIELD)) /** * VISU_SCALAR_FIELD_GET_CLASS: * @obj: a #GObject to get the class of. * * It returns the class of the given @obj. */ #define VISU_SCALAR_FIELD_GET_CLASS(obj) (G_TYPE_INSTANCE_GET_CLASS(obj, VISU_TYPE_SCALAR_FIELD, VisuScalarFieldClass)) typedef struct _VisuScalarField VisuScalarField; typedef struct _VisuScalarFieldPrivate VisuScalarFieldPrivate; typedef struct _VisuScalarFieldClass VisuScalarFieldClass; /** * VisuScalarField: * * An opaque structure for the scalar field. */ struct _VisuScalarField { VisuObject parent; VisuScalarFieldPrivate *priv; }; /** * VisuScalarFieldClass: * @parent: the parent class. * @isEmpty: a method returning %TRUE if the scalar field has * no data yet. * @setGridSize: a method to define the grid size. * @getGridSize: a method returning the three grid dimensions. * @getAt: a method to get the value on a grid point. * @getValue: a method to get an interpolated value in space. * @getMinMax: a method to get the minimum and maximum value reached * by the scalar field. * * An opaque structure for the class. */ struct _VisuScalarFieldClass { VisuObjectClass parent; gboolean (*isEmpty)(const VisuScalarField *field); gboolean (*setGridSize)(VisuScalarField *field, const guint grid[3]); void (*getGridSize)(const VisuScalarField *field, guint grid[3]); double (*getAt)(const VisuScalarField *field, int i, int j, int k); gboolean (*getValue)(const VisuScalarField *field, float xyz[3], double *value, float extension[3]); void (*getMinMax)(const VisuScalarField *field, double minmax[2]); }; /** * visu_scalar_field_get_type: * * This method returns the type of #VisuScalarField, use VISU_TYPE_SCALAR_FIELD instead. * * Returns: the type of #VisuScalarField. */ GType visu_scalar_field_get_type(void); /** * VISU_SCALAR_FIELD_DEFINED_IN_STRUCT_FILE: * * Flag used to registered a gboolean property in a #VisuData object. * If this flag is TRUE, the file used to read the structure can be used to * read a density or a potential. */ #define VISU_SCALAR_FIELD_DEFINED_IN_STRUCT_FILE "fileFormat_hasPotentialOrDensity" VisuScalarField* visu_scalar_field_new(const gchar *label); gboolean visu_scalar_field_isEmpty(const VisuScalarField *field); void visu_scalar_field_setCommentary(VisuScalarField *field, const gchar* comment); void visu_scalar_field_getGridSize(const VisuScalarField *field, guint grid[3]); gboolean visu_scalar_field_setGridSize(VisuScalarField *field, const guint grid[3]); void visu_scalar_field_setMeshtype(VisuScalarField *field, VisuScalarFieldMeshFlags meshtype); void visu_scalar_field_getMinMax(const VisuScalarField *field, double minmax[2]); VisuScalarFieldMeshFlags visu_scalar_field_getMeshtype(const VisuScalarField *field); double* visu_scalar_field_getMesh(const VisuScalarField *field, ToolXyzDir dir); void visu_scalar_field_setMesh(VisuScalarField *field, const double *mesh, ToolXyzDir dir); const gchar* visu_scalar_field_getLabel(VisuScalarField *field); const gchar* visu_scalar_field_getCommentary(VisuScalarField *field); void visu_scalar_field_getMeshInside(const VisuScalarField *field, guint grid[3], int i, int j, int k); gboolean visu_scalar_field_getCoordInside(const VisuScalarField *field, guint grid[3], guint dgrid[3], gfloat factor[3], const gfloat xyz[3], const gfloat extension[3]); double visu_scalar_field_getAt(const VisuScalarField *field, int i, int j, int k); double visu_scalar_field_getGradAt(const VisuScalarField *field, int i, int j, int k, ToolXyzDir dir); gboolean visu_scalar_field_getValue(const VisuScalarField *field, float xyz[3], double *value, float extension[3]); void visu_scalar_field_addOption(VisuScalarField *field, ToolOption *option); GList* visu_scalar_field_getAllOptions(VisuScalarField *field); G_END_DECLS #endif v_sim-3.8.0/src/extraFunctions/sfieldbinary.c000066400000000000000000000374661370110300500212670ustar00rootroot00000000000000/* EXTRAITS DE LA LICENCE Copyright CEA, contributeurs : Damien CALISTE, laboratoire L_Sim, (2017) Adresses mèl : CALISTE, damien P caliste AT cea P fr. Ce logiciel est un programme informatique servant à visualiser des structures atomiques dans un rendu pseudo-3D. Ce logiciel est régi par la licence CeCILL soumise au droit français et respectant les principes de diffusion des logiciels libres. Vous pouvez utiliser, modifier et/ou redistribuer ce programme sous les conditions de la licence CeCILL telle que diffusée par le CEA, le CNRS et l'INRIA sur le site "http://www.cecill.info". Le fait que vous puissiez accéder à cet en-tête signifie que vous avez pris connaissance de la licence CeCILL, et que vous en avez accepté les termes (cf. le fichier Documentation/licence.fr.txt fourni avec ce logiciel). */ /* LICENCE SUM UP Copyright CEA, contributors : Damien CALISTE, laboratoire L_Sim, (2017) E-mail addresses : CALISTE, damien P caliste AT cea P fr. This software is a computer program whose purpose is to visualize atomic configurations in 3D. This software is governed by the CeCILL license under French law and abiding by the rules of distribution of free software. You can use, modify and/ or redistribute the software under the terms of the CeCILL license as circulated by CEA, CNRS and INRIA at the following URL "http://www.cecill.info". The fact that you are presently reading this means that you have had knowledge of the CeCILL license and that you accept its terms. You can find a copy of this licence shipped with this software at Documentation/licence.en.txt. */ #include /** * SECTION:sfieldbinary * @short_description: Defines a specialised #VisuScalarField class * that is the result of a binary operation. * * This class allows to define scalarfields as a result of a * binary operation over two scalar fields without allocating any new * memory for the new scalar field. The resultig scalar field is also * automatically updated whenever any of the source scalar field are * changed. */ struct _VisuScalarFieldBinaryOpPrivate { gboolean dispose_has_run; VisuScalarFieldBinaryOpTypes op; double lvalue, rvalue; VisuScalarField *lfield, *rfield; gulong lchanged, rchanged, lempty, rempty; gboolean mmdirty; double minmax[2]; }; static void visu_scalar_field_binary_op_dispose(GObject* obj); static void visu_boxed_interface_init (VisuBoxedInterface *iface); static gboolean _isEmpty(const VisuScalarField *field); static void _getGridSize(const VisuScalarField *field, guint grid[3]); static double _getAt(const VisuScalarField *field, int i, int j, int k); static gboolean _getValue(const VisuScalarField *field, float xyz[3], double *value, float extension[3]); static void _getMinMax(const VisuScalarField *field, double minmax[2]); static VisuBox* _getBox(VisuBoxed *boxed); static gboolean _setBox(VisuBoxed *self, VisuBox *box); G_DEFINE_TYPE_WITH_CODE(VisuScalarFieldBinaryOp, visu_scalar_field_binary_op, VISU_TYPE_SCALAR_FIELD, G_ADD_PRIVATE(VisuScalarFieldBinaryOp) G_IMPLEMENT_INTERFACE(VISU_TYPE_BOXED, visu_boxed_interface_init)) static void visu_scalar_field_binary_op_class_init(VisuScalarFieldBinaryOpClass *klass) { DBG_fprintf(stderr, "VisuScalarFieldBinaryOp: creating the class of the object.\n"); /* DBG_fprintf(stderr, " - adding new signals ;\n"); */ /* Connect freeing methods. */ G_OBJECT_CLASS(klass)->dispose = visu_scalar_field_binary_op_dispose; VISU_SCALAR_FIELD_CLASS(klass)->isEmpty = _isEmpty; VISU_SCALAR_FIELD_CLASS(klass)->getGridSize = _getGridSize; VISU_SCALAR_FIELD_CLASS(klass)->getAt = _getAt; VISU_SCALAR_FIELD_CLASS(klass)->getValue = _getValue; VISU_SCALAR_FIELD_CLASS(klass)->getMinMax = _getMinMax; } static void visu_boxed_interface_init(VisuBoxedInterface *iface) { iface->get_box = _getBox; iface->set_box = _setBox; } static void visu_scalar_field_binary_op_init(VisuScalarFieldBinaryOp *obj) { DBG_fprintf(stderr, "VisuScalarFieldBinaryOp: creating a new scalar field operator (%p).\n", (gpointer)obj); obj->priv = visu_scalar_field_binary_op_get_instance_private(obj); obj->priv->dispose_has_run = FALSE; obj->priv->lfield = (VisuScalarField*)0; obj->priv->rfield = (VisuScalarField*)0; obj->priv->mmdirty = TRUE; obj->priv->minmax[0] = G_MAXFLOAT; obj->priv->minmax[1] = -G_MAXFLOAT; } static void visu_scalar_field_binary_op_dispose(GObject* obj) { VisuScalarFieldBinaryOp *self = VISU_SCALAR_FIELD_BINARY_OP(obj); DBG_fprintf(stderr, "VisuScalarFieldBinaryOp: dispose object %p.\n", (gpointer)obj); if (self->priv->dispose_has_run) return; self->priv->dispose_has_run = TRUE; visu_scalar_field_binary_op_setLeftField(self, (VisuScalarField*)0); visu_scalar_field_binary_op_setRightField(self, (VisuScalarField*)0); /* Chain up to the parent class */ G_OBJECT_CLASS(visu_scalar_field_binary_op_parent_class)->dispose(obj); } static void _setOp(VisuScalarFieldBinaryOp *field, VisuScalarFieldBinaryOpTypes op) { field->priv->op = op; field->priv->lvalue = (op == VISU_OPERATOR_ADDITION || op == VISU_OPERATOR_DIFFERENCE) ? 0. : 1.; field->priv->rvalue = (op == VISU_OPERATOR_ADDITION || op == VISU_OPERATOR_DIFFERENCE) ? 0. : 1.; } static gboolean _isEmpty(const VisuScalarField *field) { VisuScalarFieldBinaryOp *self; gboolean lEmpty, rEmpty; g_return_val_if_fail(VISU_IS_SCALAR_FIELD_BINARY_OP(field), TRUE); self = VISU_SCALAR_FIELD_BINARY_OP(field); lEmpty = (self->priv->lfield) ? visu_scalar_field_isEmpty(self->priv->lfield) : FALSE; rEmpty = (self->priv->rfield) ? visu_scalar_field_isEmpty(self->priv->rfield) : FALSE; return lEmpty || rEmpty; } static void _getGridSize(const VisuScalarField *field, guint grid[3]) { VisuScalarFieldBinaryOp *self; g_return_if_fail(VISU_IS_SCALAR_FIELD_BINARY_OP(field)); self = VISU_SCALAR_FIELD_BINARY_OP(field); if (self->priv->lfield) visu_scalar_field_getGridSize(self->priv->lfield, grid); else if (self->priv->rfield) visu_scalar_field_getGridSize(self->priv->rfield, grid); } static double _getAt(const VisuScalarField *field, int i, int j, int k) { VisuScalarFieldBinaryOp *self; double lval, rval; g_return_val_if_fail(VISU_IS_SCALAR_FIELD_BINARY_OP(field), 0.); self = VISU_SCALAR_FIELD_BINARY_OP(field); lval = (self->priv->lfield) ? visu_scalar_field_getAt(self->priv->lfield, i, j, k) : self->priv->lvalue; rval = (self->priv->rfield) ? visu_scalar_field_getAt(self->priv->rfield, i, j, k) : self->priv->rvalue; switch(self->priv->op) { case VISU_OPERATOR_ADDITION: return lval + rval; case VISU_OPERATOR_DIFFERENCE: return lval - rval; case VISU_OPERATOR_PRODUCT: return lval * rval; case VISU_OPERATOR_RATIO: return lval / rval; } return 0.; } static gboolean _getValue(const VisuScalarField *field, float xyz[3], double *value, float extension[3]) { VisuScalarFieldBinaryOp *self; double lval, rval; gboolean lret, rret; g_return_val_if_fail(VISU_IS_SCALAR_FIELD_BINARY_OP(field), FALSE); self = VISU_SCALAR_FIELD_BINARY_OP(field); lval = self->priv->lvalue;; if (self->priv->lfield) lret = visu_scalar_field_getValue(self->priv->lfield, xyz, &lval, extension); else lret = TRUE; rval = self->priv->rvalue; if (self->priv->rfield) rret = visu_scalar_field_getValue(self->priv->rfield, xyz, &rval, extension); else rret = TRUE; switch(self->priv->op) { case VISU_OPERATOR_ADDITION: *value = lval + rval; return lret && rret; case VISU_OPERATOR_DIFFERENCE: *value = lval - rval; return lret && rret; case VISU_OPERATOR_PRODUCT: *value = lval * rval; return lret && rret; case VISU_OPERATOR_RATIO: *value = lval / rval; return lret && rret; } return FALSE; } static void _computeMinMax(VisuScalarFieldBinaryOp *op) { guint grid[3], i, j, k; double v; VisuScalarField *field; op->priv->minmax[0] = G_MAXFLOAT; op->priv->minmax[1] = -G_MAXFLOAT; field = VISU_SCALAR_FIELD(op); _getGridSize(field, grid); for (i = 0; i < grid[0]; i++) for (j = 0; j < grid[1]; j++) for (k = 0; k < grid[2]; k++) { v = _getAt(field, i, j, k); if (v < op->priv->minmax[0]) op->priv->minmax[0] = v; if (v > op->priv->minmax[1]) op->priv->minmax[1] = v; } DBG_fprintf(stderr, "VisuScalarFieldBinaryOp: computing min / max to %g / %g.\n ", op->priv->minmax[0], op->priv->minmax[1]); op->priv->mmdirty = FALSE; } static void _getMinMax(const VisuScalarField *field, double minmax[2]) { VisuScalarFieldBinaryOp *self; g_return_if_fail(VISU_IS_SCALAR_FIELD_BINARY_OP(field)); self = VISU_SCALAR_FIELD_BINARY_OP(field); if (self->priv->mmdirty) _computeMinMax(self); minmax[0] = self->priv->minmax[0]; minmax[1] = self->priv->minmax[1]; } static void emitEmpty(VisuScalarFieldBinaryOp *op) { DBG_fprintf(stderr, "Visu ScalarFieldBinaryOp: %p caught 'empty' notify.\n", (gpointer)op); if (_isEmpty(VISU_SCALAR_FIELD(op)) || op->priv->dispose_has_run) return; g_object_notify(G_OBJECT(op), "empty"); } static void emitChanged(VisuScalarFieldBinaryOp *op) { DBG_fprintf(stderr, "Visu ScalarFieldBinaryOp: %p caught 'changed' signal.\n", (gpointer)op); op->priv->mmdirty = TRUE; if (_isEmpty(VISU_SCALAR_FIELD(op)) || op->priv->dispose_has_run) return; g_signal_emit_by_name(op, "changed"); } static gboolean _setBox(VisuBoxed *self, VisuBox *box) { VisuScalarFieldBinaryOp *op; gboolean lstatus, rstatus; g_return_val_if_fail(VISU_IS_SCALAR_FIELD_BINARY_OP(self), FALSE); op = VISU_SCALAR_FIELD_BINARY_OP(self); DBG_fprintf(stderr, "Visu ScalarFieldBinaryOp: set the bounding box to %p.\n", (gpointer)box); lstatus = FALSE; if (op->priv->lfield) lstatus = VISU_BOXED_GET_INTERFACE(op->priv->lfield)->set_box(VISU_BOXED(op->priv->lfield), box); rstatus = FALSE; if (op->priv->rfield) rstatus = VISU_BOXED_GET_INTERFACE(op->priv->rfield)->set_box(VISU_BOXED(op->priv->rfield), box); return lstatus || rstatus; } static VisuBox* _getBox(VisuBoxed *boxed) { VisuScalarFieldBinaryOp *op; g_return_val_if_fail(VISU_IS_SCALAR_FIELD_BINARY_OP(boxed), (VisuBox*)0); op = VISU_SCALAR_FIELD_BINARY_OP(boxed); if (op->priv->lfield) return visu_boxed_getBox(VISU_BOXED(op->priv->lfield)); if (op->priv->rfield) return visu_boxed_getBox(VISU_BOXED(op->priv->rfield)); return (VisuBox*)0; } /** * visu_scalar_field_binary_op_new: * @op: the type of binary operator. * @a: a #VisuScalarField object. * @b: a #VisuScalarField object. * * Create a new #VisuScalarField object as the operation between * scalar field @a and @b. * * Since: 3.8 * * Returns: (transfer full): a newly created #VisuScalarFieldBinaryOp * object. */ VisuScalarField* visu_scalar_field_binary_op_new(VisuScalarFieldBinaryOpTypes op, VisuScalarField *a, VisuScalarField *b) { VisuScalarFieldBinaryOp *field; field = g_object_new(VISU_TYPE_SCALAR_FIELD_BINARY_OP, "label", "binary op", NULL); _setOp(field, op); visu_scalar_field_binary_op_setLeftField(field, a); visu_scalar_field_binary_op_setRightField(field, b); return VISU_SCALAR_FIELD(field); } /** * visu_scalar_field_binary_op_new_withLeftConst: * @op: the type of binary operator. * @lValue: a constant. * @b: a #VisuScalarField object. * * Like visu_scalar_field_binary_op_new() but with the left member * being a constant. * * Since: 3.8 * * Returns: (transfer full): a newly created #VisuScalarFieldBinaryOp * object. **/ VisuScalarField* visu_scalar_field_binary_op_new_withLeftConst(VisuScalarFieldBinaryOpTypes op, double lValue, VisuScalarField *b) { VisuScalarFieldBinaryOp *field; field = g_object_new(VISU_TYPE_SCALAR_FIELD_BINARY_OP, "label", "binary op", NULL); _setOp(field, op); field->priv->lvalue = lValue; visu_scalar_field_binary_op_setRightField(field, b); return VISU_SCALAR_FIELD(field); } /** * visu_scalar_field_binary_op_new_withRightConst: * @op: the type of binary operator. * @a: a #VisuScalarField object. * @rValue: a constant. * * Like visu_scalar_field_binary_op_new() but with the right member * being a constant. * * Since: 3.8 * * Returns: (transfer full): a newly created #VisuScalarFieldBinaryOp * object. **/ VisuScalarField* visu_scalar_field_binary_op_new_withRightConst(VisuScalarFieldBinaryOpTypes op, VisuScalarField *a, double rValue) { VisuScalarFieldBinaryOp *field; field = g_object_new(VISU_TYPE_SCALAR_FIELD_BINARY_OP, "label", "binary op", NULL); _setOp(field, op); visu_scalar_field_binary_op_setLeftField(field, a); field->priv->rvalue = rValue; return VISU_SCALAR_FIELD(field); } /** * visu_scalar_field_binary_op_setLeftField: * @op: a #VisuScalarFieldBinaryOp object. * @field: a #VisuScalarField object. * * Change the left hand side operator to be @field. * * Returns: TRUE if the left operator is actually changed. **/ gboolean visu_scalar_field_binary_op_setLeftField(VisuScalarFieldBinaryOp *op, VisuScalarField *field) { g_return_val_if_fail(VISU_IS_SCALAR_FIELD_BINARY_OP(op), FALSE); if (op->priv->lfield == field) return FALSE; if (op->priv->lfield) { g_signal_handler_disconnect(op->priv->lfield, op->priv->lchanged); g_signal_handler_disconnect(op->priv->lfield, op->priv->lempty); g_clear_object(&op->priv->lfield); } if (field) { op->priv->lfield = g_object_ref(field); visu_boxed_setBox(VISU_BOXED(op), VISU_BOXED(field)); op->priv->lchanged = g_signal_connect_swapped(field, "changed", G_CALLBACK(emitChanged), op); op->priv->lempty = g_signal_connect_swapped(field, "notify::empty", G_CALLBACK(emitEmpty), op); DBG_fprintf(stderr, "Visu ScalarFieldBinaryOp: attach 'changed' signal from %p.\n", (gpointer)field); } emitChanged(op); return TRUE; } /** * visu_scalar_field_binary_op_setRightField: * @op: a #VisuScalarFieldBinaryOp object. * @field: a #VisuScalarField object. * * Change the right hand side operator to be @field. * * Returns: TRUE if the right operator is actually changed. **/ gboolean visu_scalar_field_binary_op_setRightField(VisuScalarFieldBinaryOp *op, VisuScalarField *field) { g_return_val_if_fail(VISU_IS_SCALAR_FIELD_BINARY_OP(op), FALSE); if (op->priv->rfield == field) return FALSE; if (op->priv->rfield) { g_signal_handler_disconnect(op->priv->rfield, op->priv->rchanged); g_signal_handler_disconnect(op->priv->rfield, op->priv->rempty); g_clear_object(&op->priv->rfield); } if (field) { op->priv->rfield = g_object_ref(field); visu_boxed_setBox(VISU_BOXED(op), VISU_BOXED(field)); op->priv->rchanged = g_signal_connect_swapped(field, "changed", G_CALLBACK(emitChanged), op); op->priv->rempty = g_signal_connect_swapped(field, "notify::empty", G_CALLBACK(emitEmpty), op); DBG_fprintf(stderr, "Visu ScalarFieldBinaryOp: attach 'changed' signal from %p.\n", (gpointer)field); } emitChanged(op); return TRUE; } v_sim-3.8.0/src/extraFunctions/sfieldbinary.h000066400000000000000000000132171370110300500212600ustar00rootroot00000000000000/* EXTRAITS DE LA LICENCE Copyright CEA, contributeurs : Damien CALISTE, laboratoire L_Sim, (2017) Adresses mèl : CALISTE, damien P caliste AT cea P fr. Ce logiciel est un programme informatique servant à visualiser des structures atomiques dans un rendu pseudo-3D. Ce logiciel est régi par la licence CeCILL soumise au droit français et respectant les principes de diffusion des logiciels libres. Vous pouvez utiliser, modifier et/ou redistribuer ce programme sous les conditions de la licence CeCILL telle que diffusée par le CEA, le CNRS et l'INRIA sur le site "http://www.cecill.info". Le fait que vous puissiez accéder à cet en-tête signifie que vous avez pris connaissance de la licence CeCILL, et que vous en avez accepté les termes (cf. le fichier Documentation/licence.fr.txt fourni avec ce logiciel). */ /* LICENCE SUM UP Copyright CEA, contributors : Damien CALISTE, laboratoire L_Sim, (2017) E-mail addresses : CALISTE, damien P caliste AT cea P fr. This software is a computer program whose purpose is to visualize atomic configurations in 3D. This software is governed by the CeCILL license under French law and abiding by the rules of distribution of free software. You can use, modify and/ or redistribute the software under the terms of the CeCILL license as circulated by CEA, CNRS and INRIA at the following URL "http://www.cecill.info". The fact that you are presently reading this means that you have had knowledge of the CeCILL license and that you accept its terms. You can find a copy of this licence shipped with this software at Documentation/licence.en.txt. */ #ifndef SFIELDSUM_H #define SFIELDSUM_H #include #include /** * VisuScalarFieldBinaryOpTypes: * @VISU_OPERATOR_ADDITION: an addition binary operation. * @VISU_OPERATOR_DIFFERENCE: a difference binary operation. * @VISU_OPERATOR_PRODUCT: a multiplication binary operation. * @VISU_OPERATOR_RATIO: a division binary operation. * * Defines the kind of implemented binary operation. * * Since: 3.8 */ typedef enum { VISU_OPERATOR_ADDITION, VISU_OPERATOR_DIFFERENCE, VISU_OPERATOR_PRODUCT, VISU_OPERATOR_RATIO } VisuScalarFieldBinaryOpTypes; /** * VISU_TYPE_SCALAR_FIELD_BINARY_OP: * * return the type of #VisuScalarFieldBinaryOp. */ #define VISU_TYPE_SCALAR_FIELD_BINARY_OP (visu_scalar_field_binary_op_get_type ()) /** * SCALAR_FIELD_BINARY_OP: * @obj: a #GObject to cast. * * Cast the given @obj into #VisuScalarFieldBinaryOp type. */ #define VISU_SCALAR_FIELD_BINARY_OP(obj) (G_TYPE_CHECK_INSTANCE_CAST(obj, VISU_TYPE_SCALAR_FIELD_BINARY_OP, VisuScalarFieldBinaryOp)) /** * VISU_SCALAR_FIELD_BINARY_OP_CLASS: * @klass: a #GObjectClass to cast. * * Cast the given @klass into #VisuScalarFieldBinaryOpClass. */ #define VISU_SCALAR_FIELD_BINARY_OP_CLASS(klass) (G_TYPE_CHECK_CLASS_CAST(klass, VISU_TYPE_SCALAR_FIELD_BINARY_OP, VisuScalarFieldBinaryOpClass)) /** * VISU_IS_SCALAR_FIELD_BINARY_OP: * @obj: a #GObject to test. * * Test if the given @ogj is of the type of #VisuScalarFieldBinaryOp object. */ #define VISU_IS_SCALAR_FIELD_BINARY_OP(obj) (G_TYPE_CHECK_INSTANCE_TYPE(obj, VISU_TYPE_SCALAR_FIELD_BINARY_OP)) /** * VISU_IS_SCALAR_FIELD_BINARY_OP_CLASS: * @klass: a #GObjectClass to test. * * Test if the given @klass is of the type of #VisuScalarFieldBinaryOpClass class. */ #define VISU_IS_SCALAR_FIELD_BINARY_OP_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE(klass, VISU_TYPE_SCALAR_FIELD_BINARY_OP)) /** * VISU_SCALAR_FIELD_BINARY_OP_GET_CLASS: * @obj: a #GObject to get the class of. * * It returns the class of the given @obj. */ #define VISU_SCALAR_FIELD_BINARY_OP_GET_CLASS(obj) (G_TYPE_INSTANCE_GET_CLASS(obj, VISU_TYPE_SCALAR_FIELD_BINARY_OP, VisuScalarFieldBinaryOpClass)) typedef struct _VisuScalarFieldBinaryOp VisuScalarFieldBinaryOp; typedef struct _VisuScalarFieldBinaryOpPrivate VisuScalarFieldBinaryOpPrivate; typedef struct _VisuScalarFieldBinaryOpClass VisuScalarFieldBinaryOpClass; /** * VisuScalarFieldBinaryOp: * * An opaque structure for the scalar field. */ struct _VisuScalarFieldBinaryOp { VisuScalarField parent; VisuScalarFieldBinaryOpPrivate *priv; }; /** * VisuScalarFieldBinaryOpClass: * @parent: the parent class. * * An opaque structure for the class. */ struct _VisuScalarFieldBinaryOpClass { VisuScalarFieldClass parent; }; /** * visu_scalar_field_operator_get_type: * * This method returns the type of #VisuScalarFieldBinaryOp, use VISU_TYPE_SCALAR_FIELD_BINARY_OP instead. * * Returns: the type of #VisuScalarFieldBinaryOp. */ GType visu_scalar_field_binary_op_get_type(void); VisuScalarField* visu_scalar_field_binary_op_new(VisuScalarFieldBinaryOpTypes op, VisuScalarField *a, VisuScalarField *b); VisuScalarField* visu_scalar_field_binary_op_new_withLeftConst(VisuScalarFieldBinaryOpTypes op, double lValue, VisuScalarField *b); VisuScalarField* visu_scalar_field_binary_op_new_withRightConst(VisuScalarFieldBinaryOpTypes op, VisuScalarField *a, double rValue); gboolean visu_scalar_field_binary_op_setLeftField(VisuScalarFieldBinaryOp *op, VisuScalarField *field); gboolean visu_scalar_field_binary_op_setRightField(VisuScalarFieldBinaryOp *op, VisuScalarField *field); #endif v_sim-3.8.0/src/extraFunctions/sfielddata.c000066400000000000000000000773431370110300500207120ustar00rootroot00000000000000/* EXTRAITS DE LA LICENCE Copyright CEA, contributeurs : Damien CALISTE, laboratoire L_Sim, (2017) Adresses mèl : CALISTE, damien P caliste AT cea P fr. Ce logiciel est un programme informatique servant à visualiser des structures atomiques dans un rendu pseudo-3D. Ce logiciel est régi par la licence CeCILL soumise au droit français et respectant les principes de diffusion des logiciels libres. Vous pouvez utiliser, modifier et/ou redistribuer ce programme sous les conditions de la licence CeCILL telle que diffusée par le CEA, le CNRS et l'INRIA sur le site "http://www.cecill.info". Le fait que vous puissiez accéder à cet en-tête signifie que vous avez pris connaissance de la licence CeCILL, et que vous en avez accepté les termes (cf. le fichier Documentation/licence.fr.txt fourni avec ce logiciel). */ /* LICENCE SUM UP Copyright CEA, contributors : Damien CALISTE, laboratoire L_Sim, (2017) E-mail addresses : CALISTE, damien P caliste AT cea P fr. This software is a computer program whose purpose is to visualize atomic configurations in 3D. This software is governed by the CeCILL license under French law and abiding by the rules of distribution of free software. You can use, modify and/ or redistribute the software under the terms of the CeCILL license as circulated by CEA, CNRS and INRIA at the following URL "http://www.cecill.info". The fact that you are presently reading this means that you have had knowledge of the CeCILL license and that you accept its terms. You can find a copy of this licence shipped with this software at Documentation/licence.en.txt. */ #include "sfielddata.h" /** * SECTION:sfielddata * @short_description: Defines a specialised #VisuScalarField class * based on data on a grid. * * This kind of scalar fields is a simple scalar field with data * available on a grid, regular or not. Data can be read from a file * or set directly. */ struct _VisuScalarFieldDataPrivate { /* Datas. */ gboolean empty; double ***data; GArray *arr; /* Minimum and maximum values. */ double min, max; }; static void visu_scalar_field_data_finalize(GObject* obj); static gboolean _isEmpty(const VisuScalarField *self); static gboolean _setGridSize(VisuScalarField *self, const guint grid[3]); static double _getAt(const VisuScalarField *self, int i, int j, int k); static gboolean _getValue(const VisuScalarField *self, float xyz[3], double *value, float extension[3]); static void _getMinMax(const VisuScalarField *self, double minmax[2]); static gboolean scalarFieldLoad_fromAscii(VisuScalarFieldMethod *meth, VisuScalarFieldMethodData *data, GCancellable *cancel, GError **error); G_DEFINE_TYPE_WITH_CODE(VisuScalarFieldData, visu_scalar_field_data, VISU_TYPE_SCALAR_FIELD, G_ADD_PRIVATE(VisuScalarFieldData)) static void visu_scalar_field_data_class_init(VisuScalarFieldDataClass *klass) { const gchar *type[] = {"*.pot", "*.dat", (char*)0}; const gchar *descr = _("Potential/density files"); DBG_fprintf(stderr, "VisuScalarFieldData: creating the class of the object.\n"); /* DBG_fprintf(stderr, " - adding new signals ;\n"); */ /* Connect freeing methods. */ G_OBJECT_CLASS(klass)->finalize = visu_scalar_field_data_finalize; VISU_SCALAR_FIELD_CLASS(klass)->isEmpty = _isEmpty; VISU_SCALAR_FIELD_CLASS(klass)->setGridSize = _setGridSize; VISU_SCALAR_FIELD_CLASS(klass)->getAt = _getAt; VISU_SCALAR_FIELD_CLASS(klass)->getValue = _getValue; VISU_SCALAR_FIELD_CLASS(klass)->getMinMax = _getMinMax; visu_scalar_field_method_new(descr, type, scalarFieldLoad_fromAscii, G_PRIORITY_LOW); } static void visu_scalar_field_data_init(VisuScalarFieldData *obj) { DBG_fprintf(stderr, "VisuScalarFieldData: creating a new scalar field operator (%p).\n", (gpointer)obj); obj->priv = visu_scalar_field_data_get_instance_private(obj); obj->priv->empty = TRUE; obj->priv->data = (double***)0; obj->priv->arr = (GArray*)0; obj->priv->min = G_MAXFLOAT; obj->priv->max = -G_MAXFLOAT; } static void visu_scalar_field_data_finalize(GObject* obj) { guint i; guint grid[3]; VisuScalarFieldData *self = VISU_SCALAR_FIELD_DATA(obj); DBG_fprintf(stderr, "VisuScalarFieldData: finalize object %p.\n", (gpointer)obj); if (self->priv->data) { visu_scalar_field_getGridSize(VISU_SCALAR_FIELD(obj), grid); for (i = 0; i < grid[0]; i++) g_free(self->priv->data[i]); g_free(self->priv->data); } if (self->priv->arr) g_array_unref(self->priv->arr); /* Chain up to the parent class */ G_OBJECT_CLASS(visu_scalar_field_data_parent_class)->finalize(obj); } /** * visu_scalar_field_data_new_fromFile: * @filename: (type filename): the path to the file to be loaded ; * @table: (allow-none): a set of different options (can be NULL). * @cancel: (allow-none): a #GCancellable object. * @callback: (allow-none): a callback when the load finishes. * @user_data: (scope async): some user data to pass to the callback. * * Read the given file and try to load it as a scalar field file. If succeed, * all read fields are appended to the @fieldList argument. If an error * occurs, it is stored into @error. When entering the routine, *@error must be NULL. * If @table is given, it means that the caller routine gives some options to the loader * routine. These options are a set of names and values. * * If the file contains several fields, they must be loaded and added to @fieldList. * * Returns: (transfer full) (element-type VisuScalarField*): * a #GList to store read field(s). */ GList* visu_scalar_field_data_new_fromFile(const gchar *filename, GHashTable *table, GCancellable *cancel, GAsyncReadyCallback callback, gpointer user_data) { return visu_scalar_field_method_load((VisuScalarFieldMethod*)0, filename, table, cancel, callback, user_data); } /** * visu_scalar_field_data_new_fromFileSync: * @filename: (type filename): the path to the file to be loaded ; * @table: (allow-none): a set of different options (can be NULL). * @cancel: (allow-none): a #GCancellable object. * @error: (allow-none): an error location. * * Like visu_scalar_field_data_new_fromFile(), but synchronous. * * Since: 3.8 * * Returns: (transfer full) (element-type VisuScalarField*): * a #GList to store read field(s). */ GList* visu_scalar_field_data_new_fromFileSync(const gchar *filename, GHashTable *table, GCancellable *cancel, GError **error) { return visu_scalar_field_method_loadSync((VisuScalarFieldMethod*)0, filename, table, cancel, error); } static gboolean _isEmpty(const VisuScalarField *self) { g_return_val_if_fail(VISU_IS_SCALAR_FIELD_DATA(self), TRUE); return VISU_SCALAR_FIELD_DATA(self)->priv->empty; } static void _getMinMax(const VisuScalarField *self, double minmax[2]) { VisuScalarFieldData *field; g_return_if_fail(VISU_IS_SCALAR_FIELD_DATA(self)); field = VISU_SCALAR_FIELD_DATA(self); minmax[0] = field->priv->min; minmax[1] = field->priv->max; } static gboolean _emitEmpty(gpointer data) { g_object_notify(G_OBJECT(data), "empty"); return G_SOURCE_REMOVE; } static gboolean _emitChanged(gpointer data) { g_signal_emit_by_name(G_OBJECT(data), "changed"); return G_SOURCE_REMOVE; } static gboolean _setGridSize(VisuScalarField *self, const guint grid[3]) { guint i, j; guint nElements[3]; VisuScalarFieldData *field; g_return_val_if_fail(VISU_IS_SCALAR_FIELD_DATA(self), FALSE); visu_scalar_field_getGridSize(self, nElements); if (!VISU_SCALAR_FIELD_CLASS(visu_scalar_field_data_parent_class)->setGridSize(self, grid)) return FALSE; field = VISU_SCALAR_FIELD_DATA(self); /* If data was already allocated, we free it. */ if (field->priv->data) { DBG_fprintf(stderr, " | free the previous data allocation.\n"); for (i = 0; i < nElements[0]; i++) g_free(field->priv->data[i]); g_free(field->priv->data); } if (field->priv->arr) g_array_unref(field->priv->arr); DBG_fprintf(stderr, "Visu ScalarFieldData: allocating data array (%d,%d,%d).\n", grid[0], grid[1], grid[2]); field->priv->arr = g_array_sized_new(FALSE, FALSE, sizeof(double), grid[0] * grid[1] * grid[2]); g_array_set_size(field->priv->arr, grid[0] * grid[1] * grid[2]); field->priv->data = g_malloc(sizeof(double **) * grid[0]); for(i = 0; i < grid[0]; i++) { field->priv->data[i] = g_malloc(sizeof(double *) * grid[1]); for(j = 0; j < grid[1]; j++) field->priv->data[i][j] = &g_array_index(field->priv->arr, double, ((i * grid[1] + j) * grid[2])); } DBG_fprintf(stderr, " | allocation done.\n"); return TRUE; } /** * visu_scalar_field_data_set: * @field: a #VisuScalarFieldData object ; * @data: (element-type double): an array containing data to be copied ; * @xyzOrder: a boolean. * * Set the data of the given @field. The array @data should be stored in z direction * first, followed by y and x if @xyzOrder is FALSE, or in the other * order when TRUE. The number of elements in the x, y and z directions * are read from field->priv->nElements. Then use visu_scalar_field_setGridSize() * before using this method. */ void visu_scalar_field_data_set(VisuScalarFieldData *field, GArray *data, VisuScalarFieldDataOrder xyzOrder) { guint i, j, k, ii; guint grid[3]; g_return_if_fail(VISU_IS_SCALAR_FIELD_DATA(field) && data); visu_scalar_field_getGridSize(VISU_SCALAR_FIELD(field), grid); g_return_if_fail(data->len == grid[0] * grid[1] * grid[2]); DBG_fprintf(stderr, "VisuScalarField: set data from array %p (%d ele.).\n", (gpointer)data, data->len); field->priv->min = G_MAXFLOAT; field->priv->max = -G_MAXFLOAT; ii = 0; if (xyzOrder == VISU_SCALAR_FIELD_DATA_XYZ) for (k = 0 ; k < grid[2] ; k++) for (j = 0 ; j < grid[1] ; j++) for (i = 0 ; i < grid[0] ; i++) { field->priv->data[i][j][k] = ((double*)data->data)[ii]; field->priv->min = MIN(field->priv->data[i][j][k], field->priv->min); field->priv->max = MAX(field->priv->data[i][j][k], field->priv->max); ii += 1; } else for (i = 0 ; i < grid[0] ; i++) for (j = 0 ; j < grid[1] ; j++) for (k = 0 ; k < grid[2] ; k++) { field->priv->data[i][j][k] = ((double*)data->data)[ii]; field->priv->min = MIN(field->priv->data[i][j][k], field->priv->min); field->priv->max = MAX(field->priv->data[i][j][k], field->priv->max); ii += 1; } DBG_fprintf(stderr, " | done (%p).\n", (gpointer)g_thread_self()); field->priv->empty = FALSE; g_idle_add(_emitEmpty, field); g_idle_add(_emitChanged, field); } /** * visu_scalar_field_data_getArray: * @field: a #VisuScalarFieldData object. * * The data are stored z first in a flatten array. * * Since: 3.7 * * Returns: (transfer none) (element-type double): a pointer on the allocated data array. */ const GArray* visu_scalar_field_data_getArray(const VisuScalarFieldData *field) { g_return_val_if_fail(VISU_IS_SCALAR_FIELD(field), (const GArray*)0); return field->priv->arr; } static double _getAt(const VisuScalarField *self, int i, int j, int k) { guint grid[3]; VisuScalarFieldData *field; g_return_val_if_fail(VISU_IS_SCALAR_FIELD_DATA(self), -1.); if (_isEmpty(self)) return 0.; visu_scalar_field_getMeshInside(self, grid, i, j, k); field = VISU_SCALAR_FIELD_DATA(self); g_return_val_if_fail(field->priv->data, -1.); return field->priv->data[grid[0]][grid[1]][grid[2]]; } static gboolean _getValue(const VisuScalarField *self, float xyz[3], double *value, float extension[3]) { gfloat factor[3], x1, x2, x3; guint ijk[3], dijk[3]; VisuScalarFieldData *field; g_return_val_if_fail(VISU_IS_SCALAR_FIELD_DATA(self), FALSE); *value = 0.; if (_isEmpty(self)) return FALSE; /* lower left is ijk. */ /* upper right is dijk. */ if (!visu_scalar_field_getCoordInside(self, ijk, dijk, factor, xyz, extension)) return FALSE; /* weight is factor. */ x1 = factor[0]; x2 = factor[1]; x3 = factor[2]; field = VISU_SCALAR_FIELD_DATA(self); g_return_val_if_fail(field->priv->data, FALSE); /* calculation of the density value */ *value = 0.f; *value += field->priv->data[ ijk[0]][ ijk[1]][ ijk[2]] * (1.f - x1) * (1.f - x2) * (1.f - x3); *value += field->priv->data[dijk[0]][ ijk[1]][ ijk[2]] * x1 * (1.f - x2) * (1.f - x3); *value += field->priv->data[ ijk[0]][dijk[1]][ ijk[2]] * (1.f - x1) * x2 * (1.f - x3); *value += field->priv->data[ ijk[0]][ ijk[1]][dijk[2]] * (1.f - x1) * (1.f - x2) * x3; *value += field->priv->data[dijk[0]][dijk[1]][ ijk[2]] * x1 * x2 * (1.f - x3); *value += field->priv->data[ ijk[0]][dijk[1]][dijk[2]] * (1.f -x1) * x2 * x3; *value += field->priv->data[dijk[0]][ ijk[1]][dijk[2]] * x1 * (1.f - x2) * x3; *value += field->priv->data[dijk[0]][dijk[1]][dijk[2]] * x1 * x2 * x3; return TRUE; } #include #define MESH_FLAG "meshType" #define MESH_FLAG_UNIFORM "uniform" #define MESH_FLAG_NON_UNIFORM "nonuniform" static gboolean scalarFieldLoad_fromAscii(VisuScalarFieldMethod *meth _U_, VisuScalarFieldMethodData *data, GCancellable *cancel _U_, GError **error) { FILE *in; char rep[TOOL_MAX_LINE_LENGTH], flag[TOOL_MAX_LINE_LENGTH]; char format[TOOL_MAX_LINE_LENGTH], period[TOOL_MAX_LINE_LENGTH]; char *feed; gchar *comment; int res; guint i, j, k; guint size[3]; double box[6], *mesh; VisuScalarFieldData *field; VisuBox *boxObj; gboolean periodic; VisuScalarFieldMeshFlags meshtype; g_return_val_if_fail(data, FALSE); g_return_val_if_fail(!error || (*error == (GError*)0), FALSE); DBG_fprintf(stderr, "VisuScalarField : try to read '%s' as a ASCII scalar" " field data file.\n", visu_scalar_field_method_data_getFilename(data)); in = fopen(visu_scalar_field_method_data_getFilename(data), "r"); if (!in) { g_set_error(error, G_FILE_ERROR, G_FILE_ERROR_ACCES, _("impossible to open the file.\n")); return FALSE; } /* 1st line (comment) */ if (!fgets(rep, TOOL_MAX_LINE_LENGTH, in)) { fclose(in); return FALSE; } rep[strlen(rep)-1] = 0; /* skipping \n */ comment = g_locale_to_utf8(rep, -1, NULL, NULL, NULL); if (!comment) comment = g_strdup(""); if (!fgets(rep, TOOL_MAX_LINE_LENGTH, in) || sscanf(rep, "%u %u %u", size, size + 1, size + 2) != 3) { /* Not a valid ASCII format. */ g_free(comment); fclose(in); return FALSE; } if (!fgets(rep, TOOL_MAX_LINE_LENGTH, in) || sscanf(rep, "%lf %lf %lf", box, box + 1, box + 2) != 3) { /* Not a valid ASCII format. */ g_free(comment); fclose(in); return FALSE; } if (!fgets(rep, TOOL_MAX_LINE_LENGTH, in) || sscanf(rep, "%lf %lf %lf", box + 3, box + 4, box + 5) != 3) { /* Not a valid ASCII format. */ g_free(comment); fclose(in); return FALSE; } if (!fgets(rep, TOOL_MAX_LINE_LENGTH, in) || sscanf(rep, "%s %s", format, period) < 1 || (strcmp(format, "xyz") && strcmp(format, "zyx"))) { /* Not a valid ASCII format. */ g_free(comment); fclose(in); return FALSE; } periodic = !strcmp(period, "periodic"); /* OK, from now on, the format is supposed to be ASCII. */ field = g_object_new(VISU_TYPE_SCALAR_FIELD_DATA, "label", visu_scalar_field_method_data_getFilename(data), NULL); if (!field) { g_warning("impossible to create a VisuScalarField object."); g_free(comment); fclose(in); return FALSE; } visu_scalar_field_setCommentary(VISU_SCALAR_FIELD(field), comment); boxObj = visu_box_new(box, (periodic)?VISU_BOX_PERIODIC:VISU_BOX_FREE); visu_box_setMargin(boxObj, 0.f, FALSE); visu_boxed_setBox(VISU_BOXED(field), VISU_BOXED(boxObj)); g_object_unref(boxObj); visu_scalar_field_method_data_addField(data, VISU_SCALAR_FIELD(field)); g_object_ref(field); visu_scalar_field_method_data_ready(data); /* by default the meshtype is set to uniform to keep working previous version.*/ meshtype = VISU_SCALAR_FIELD_MESH_UNIFORM; feed = fgets(rep, TOOL_MAX_LINE_LENGTH, in); while (feed && rep[0] == '#') { if (strncmp(rep + 2, MESH_FLAG, strlen(MESH_FLAG)) == 0) { DBG_fprintf(stderr, "VisuScalarField: found flag '%s'.\n", MESH_FLAG); res = sscanf(rep + 2 + strlen(MESH_FLAG) + 1, "%s", flag); if (res == 1 && strcmp(flag, MESH_FLAG_UNIFORM) == 0) meshtype = VISU_SCALAR_FIELD_MESH_UNIFORM; else if (res == 1 && strcmp(flag, MESH_FLAG_NON_UNIFORM) == 0) meshtype = VISU_SCALAR_FIELD_MESH_NON_UNIFORM; else if (res == 1) { g_set_error(error, TOOL_FILE_FORMAT_ERROR, TOOL_FILE_FORMAT_ERROR_FORMAT, _("wrong '%s' value for flag '%s'.\n"), flag, MESH_FLAG); fclose(in); g_object_unref(field); return TRUE; } } feed = fgets(rep, TOOL_MAX_LINE_LENGTH, in); } visu_scalar_field_setMeshtype(VISU_SCALAR_FIELD(field), meshtype); _setGridSize(VISU_SCALAR_FIELD(field), size); if (meshtype == VISU_SCALAR_FIELD_MESH_NON_UNIFORM) for (k = 0; k < 3; k++) { DBG_fprintf(stderr, "VisuScalarField : Start to read mesh %d.\n", k); mesh = g_malloc(sizeof(double) * size[k]); for ( i = 0; i < size[0]; i++ ) { if (!feed) { g_set_error(error, TOOL_FILE_FORMAT_ERROR, TOOL_FILE_FORMAT_ERROR_FORMAT, _("not enough meshx values.\n")); fclose(in); g_object_unref(field); return TRUE; } res = sscanf(rep, "%lf", &mesh[i]); do feed = fgets(rep, TOOL_MAX_LINE_LENGTH, in); while (rep[0] == '#' && feed); if (res != 1) { g_set_error(error, TOOL_FILE_FORMAT_ERROR, TOOL_FILE_FORMAT_ERROR_FORMAT, _("impossible to read meshx values.\n")); fclose(in); g_object_unref(field); return TRUE; } } visu_scalar_field_setMesh(VISU_SCALAR_FIELD(field), mesh, k); g_free(mesh); } DBG_fprintf(stderr, "Visu ScalarField: Start to read data.\n"); field->priv->min = G_MAXFLOAT; field->priv->max = G_MINFLOAT; if(!strcmp(format, "xyz")) { for ( k = 0; k < size[2]; k++ ) for ( j = 0; j < size[1]; j++ ) for ( i = 0; i < size[0]; i++ ) { if (g_cancellable_set_error_if_cancelled(cancel, error)) { fclose(in); g_object_unref(field); return TRUE; } if (!feed) { g_set_error(error, TOOL_FILE_FORMAT_ERROR, TOOL_FILE_FORMAT_ERROR_FORMAT, _("not enough density values.\n")); fclose(in); g_object_unref(field); return TRUE; } res = sscanf(rep, "%lf", &field->priv->data[i][j][k]); do feed = fgets(rep, TOOL_MAX_LINE_LENGTH, in); while (rep[0] == '#' && feed); if (res != 1) { g_set_error(error, TOOL_FILE_FORMAT_ERROR, TOOL_FILE_FORMAT_ERROR_FORMAT, _("impossible to read density values.\n")); fclose(in); g_object_unref(field); return TRUE; } field->priv->min = MIN(field->priv->data[i][j][k], field->priv->min); field->priv->max = MAX(field->priv->data[i][j][k], field->priv->max); } } else { for ( i = 0; i < size[0]; i++ ) for ( j = 0; j < size[1]; j++ ) for ( k = 0; k < size[2]; k++ ) { if (g_cancellable_set_error_if_cancelled(cancel, error)) { fclose(in); g_object_unref(field); return TRUE; } if (!feed) { g_set_error(error, TOOL_FILE_FORMAT_ERROR, TOOL_FILE_FORMAT_ERROR_FORMAT, _("not enough density values.\n")); fclose(in); g_object_unref(field); return TRUE; } res = sscanf(rep, "%lf", &field->priv->data[i][j][k]); do feed = fgets(rep, TOOL_MAX_LINE_LENGTH, in); while (rep[0] == '#' && feed); if (res != 1) { g_set_error(error, TOOL_FILE_FORMAT_ERROR, TOOL_FILE_FORMAT_ERROR_FORMAT, _("impossible to read density values.\n")); fclose(in); g_object_unref(field); return TRUE; } field->priv->min = MIN(field->priv->data[i][j][k], field->priv->min); field->priv->max = MAX(field->priv->data[i][j][k], field->priv->max); } } fclose(in); DBG_fprintf(stderr, "Visu ScalarField: field completed.\n"); field->priv->empty = FALSE; g_idle_add(_emitEmpty, field); g_idle_add(_emitChanged, field); DBG_fprintf(stderr, "Visu ScalarField: emission done.\n"); g_object_unref(field); return TRUE; } /* Local variables. */ static GList *loadMethods; enum _dataStatus { PREPARING, READY, FAILED }; struct _VisuScalarFieldMethodData { const gchar *filename; GHashTable *options; GList *fieldList; GMutex mutex; enum _dataStatus status; }; static VisuScalarFieldMethodData* data_copy(VisuScalarFieldMethodData *orig) { VisuScalarFieldMethodData *copy; copy = g_malloc(sizeof(VisuScalarFieldMethodData)); *copy = *orig; return copy; } GType visu_scalar_field_method_data_get_type(void) { static GType g_define_type_id = 0; if (g_define_type_id == 0) g_define_type_id = g_boxed_type_register_static("VisuScalarFieldMethodData", (GBoxedCopyFunc)data_copy, (GBoxedFreeFunc)g_free); return g_define_type_id; } static VisuScalarFieldMethodData* visu_scalar_field_method_data_new(const gchar *filename, GHashTable *options) { VisuScalarFieldMethodData *data; data = g_malloc(sizeof(VisuScalarFieldMethodData)); data->filename = filename; data->options = options; data->fieldList = (GList*)0; g_mutex_init(&data->mutex); data->status = PREPARING; return data; } /** * visu_scalar_field_method_data_getFilename: * @data: a #VisuScalarFieldMethodData structure. * * Get the filename that is currently parsed. * * Since: 3.8 * * Returns: a filename. **/ const gchar* visu_scalar_field_method_data_getFilename(const VisuScalarFieldMethodData *data) { g_return_val_if_fail(data, (const gchar*)0); return data->filename; } /** * visu_scalar_field_method_data_addField: * @data: a #VisuScalarFieldMethodData structure. * @field: (transfer none): a #VisuScalarField object. * * When parsing a file with several scalar field, use this method to * store a new one. * * Since: 3.8 **/ void visu_scalar_field_method_data_addField(VisuScalarFieldMethodData *data, VisuScalarField *field) { g_return_if_fail(data); data->fieldList = g_list_append(data->fieldList, field); } /** * visu_scalar_field_method_data_ready: * @data: a #VisuScalarFieldMethodData structure. * * While parsing a file, call this method when all scalar fields are * known, but not yet populated. * * Since: 3.8 **/ void visu_scalar_field_method_data_ready(VisuScalarFieldMethodData *data) { g_return_if_fail(data); data->status = READY; g_mutex_unlock(&data->mutex); } /** * visu_scalar_field_method_data_waitReady: * @data: a #VisuScalarFieldMethodData structure. * * Block while reading for all scalar fields to be known, if not populated. * * Since: 3.8 * * Returns: (element-type VisuScalarField) (transfer none): The list * of read #VisuScalarField objects. **/ static GList* visu_scalar_field_method_data_waitReady(VisuScalarFieldMethodData *data) { /* Wait for initialisation completion. */ DBG_fprintf(stderr, "Visu ScalarFieldMethod: waiting for thread start.\n"); g_mutex_lock(&data->mutex); while (data->status == PREPARING) { g_mutex_unlock(&data->mutex); g_mutex_lock(&data->mutex); } g_mutex_unlock(&data->mutex); g_mutex_clear(&data->mutex); DBG_fprintf(stderr, "Visu ScalarFieldMethod: thread completed with status %d.\n", data->status); DBG_fprintf(stderr, "Visu ScalarFieldMethod: found %d fields.\n", g_list_length(data->fieldList)); return data->fieldList; } G_DEFINE_TYPE(VisuScalarFieldMethod, visu_scalar_field_method, TOOL_TYPE_FILE_FORMAT) static void visu_scalar_field_method_class_init(VisuScalarFieldMethodClass *klass _U_) { DBG_fprintf(stderr, "Visu VisuScalarField: creating the class of the object.\n"); loadMethods = (GList*)0; } static void visu_scalar_field_method_init(VisuScalarFieldMethod *obj) { DBG_fprintf(stderr, "Visu VisuScalarField: initializing a new object (%p).\n", (gpointer)obj); obj->load = (VisuScalarFieldMethodLoadFunc)0; obj->priority = G_PRIORITY_LOW; loadMethods = g_list_prepend(loadMethods, obj); } static gint compareLoadPriority(gconstpointer a, gconstpointer b) { if (VISU_SCALAR_FIELD_METHOD(a)->priority < VISU_SCALAR_FIELD_METHOD(b)->priority) return (gint)-1; else if (VISU_SCALAR_FIELD_METHOD(a)->priority > VISU_SCALAR_FIELD_METHOD(b)->priority) return (gint)+1; else return (gint)0; } /** * visu_scalar_field_method_new: * @descr: the name of the method ; * @patterns: (array zero-terminated=1): a NULL terminated list of strings ; * @method: (scope call): a #VisuScalarFieldMethodLoadFunc method ; * @priority: a priority value (the lower value, the higher priority). * * This routine is used to add a new method to load scalar field. The priority uses * the scale of the GLib (G_PRIORITY_DEFAULT is 0, G_PRIORITY_LOW is * 300 for instance). * * Returns: (transfer full): a newly create method to load scalar fields. */ VisuScalarFieldMethod* visu_scalar_field_method_new(const gchar* descr, const gchar** patterns, VisuScalarFieldMethodLoadFunc method, int priority) { VisuScalarFieldMethod *meth; g_return_val_if_fail(descr && method && patterns, (VisuScalarFieldMethod*)0); meth = VISU_SCALAR_FIELD_METHOD(g_object_new(VISU_TYPE_SCALAR_FIELD_METHOD, "name", descr, "ignore-type", FALSE, NULL)); tool_file_format_addPatterns(TOOL_FILE_FORMAT(meth), patterns); meth->load = method; meth->priority = priority; loadMethods = g_list_sort(loadMethods, compareLoadPriority); return meth; } static void setToolFileFormatOption(gpointer key, gpointer value, gpointer data) { DBG_fprintf(stderr, "Visu ScalarFieldMethod: transfer option '%s' to file format.\n", (gchar*)key); tool_file_format_addOption(TOOL_FILE_FORMAT(data), tool_option_copy((ToolOption*)value)); } static void _loadThread(GTask *task, VisuScalarFieldMethod *self, VisuScalarFieldMethodData *data, GCancellable *cancel) { GError *error; VisuScalarFieldMethod *meth; gboolean validFormat; GList *tmpLst, single; g_return_if_fail(data && data->fieldList == (GList*)0); DBG_fprintf(stderr, "Visu ScalarFieldMethod: try all known formats (%p).\n", (gpointer)self); error = (GError*)0; g_mutex_lock(&data->mutex); /* Try all supported format. */ single.data = self; single.next = (GList*)0; validFormat = FALSE; for (tmpLst = self ? &single : visu_scalar_field_method_getAll(); tmpLst && !validFormat; tmpLst = g_list_next(tmpLst)) { meth = VISU_SCALAR_FIELD_METHOD(tmpLst->data); /* Transfer option from table to ToolFileFormat. */ if (data->options) g_hash_table_foreach(data->options, setToolFileFormatOption, tmpLst->data); DBG_fprintf(stderr, " | try format '%s'.\n", tool_file_format_getName(TOOL_FILE_FORMAT(tmpLst->data))); g_clear_error(&error); validFormat = meth->load(meth, data, cancel, &error); DBG_fprintf(stderr, " | %d (%p).\n", validFormat, (gpointer)error); } if (data->status == PREPARING) { data->status = validFormat ? READY : FAILED; g_mutex_unlock(&data->mutex); } if (!validFormat) g_set_error(&error, TOOL_FILE_FORMAT_ERROR, TOOL_FILE_FORMAT_ERROR_UNKNOWN_FORMAT, _("unknown density/potential format.\n")); if (error) g_task_return_error(task, error); else g_task_return_boolean(task, TRUE); } /** * visu_scalar_field_method_load: * @fmt: a #VisuScalarFieldMethod object ; * @filename: (type filename): a path ; * @options: (allow-none): some key / value options. * @cancel: (allow-none): a #GCancellable object. * @callback: (allow-none): a method to call on load finished. * @user_data: (scope async): some user data. * * Call the load routine of the given scalar field file format @fmt. * * Since: 3.7 * * Returns: (element-type VisuScalarField) (transfer full): a list of * #VisuScalarField on success. */ GList* visu_scalar_field_method_load(VisuScalarFieldMethod *fmt, const gchar *filename, GHashTable *options, GCancellable *cancel, GAsyncReadyCallback callback, gpointer user_data) { VisuScalarFieldMethodData *data; GList *list; GTask *task; g_return_val_if_fail(filename, (GList*)0); data = visu_scalar_field_method_data_new(filename, options); task = g_task_new(fmt, cancel, callback, user_data); g_task_set_task_data(task, data, g_free); g_task_run_in_thread(task, (GTaskThreadFunc)_loadThread); list = visu_scalar_field_method_data_waitReady(data); g_object_unref(task); return list; } /** * visu_scalar_field_method_loadSync: * @fmt: a #VisuScalarFieldMethod object ; * @filename: (type filename): a path ; * @options: (allow-none): some key / value options. * @cancel: (allow-none): a #GCancellable object. * @error: (allow-none): an error location. * * Same as visu_scalar_field_method_load(), but blocking variant. * * Since: 3.8 * * Returns: (element-type VisuScalarField) (transfer full): a list of * #VisuScalarField on success. */ GList* visu_scalar_field_method_loadSync(VisuScalarFieldMethod *fmt, const gchar *filename, GHashTable *options, GCancellable *cancel, GError **error) { VisuScalarFieldMethodData *data; GList *list; GTask *task; g_return_val_if_fail(filename, (GList*)0); data = visu_scalar_field_method_data_new(filename, options); task = g_task_new(fmt, cancel, NULL, NULL); g_task_set_task_data(task, data, g_free); g_task_run_in_thread_sync(task, (GTaskThreadFunc)_loadThread); g_task_propagate_boolean(task, error); list = visu_scalar_field_method_data_waitReady(data); g_object_unref(task); return list; } /** * visu_scalar_field_method_getAll: * * This routine gives access to all the registered load method for scamlar fields. * * Returns: (transfer none) (element-type VisuScalarFieldMethod*): * returns a list of V_Sim owned #VisuScalarFieldMethod objects. */ GList* visu_scalar_field_method_getAll(void) { return loadMethods; } /** * visu_scalar_field_method_class_finalize: (skip) * * Free allocated memory for all known #VisuScalarFieldMethod. * * Since: 3.8 **/ void visu_scalar_field_method_class_finalize(void) { g_list_free_full(loadMethods, (GDestroyNotify)g_object_unref); loadMethods = (GList*)0; } v_sim-3.8.0/src/extraFunctions/sfielddata.h000066400000000000000000000233701370110300500207060ustar00rootroot00000000000000/* EXTRAITS DE LA LICENCE Copyright CEA, contributeurs : Damien CALISTE, laboratoire L_Sim, (2017) Adresses mèl : CALISTE, damien P caliste AT cea P fr. Ce logiciel est un programme informatique servant à visualiser des structures atomiques dans un rendu pseudo-3D. Ce logiciel est régi par la licence CeCILL soumise au droit français et respectant les principes de diffusion des logiciels libres. Vous pouvez utiliser, modifier et/ou redistribuer ce programme sous les conditions de la licence CeCILL telle que diffusée par le CEA, le CNRS et l'INRIA sur le site "http://www.cecill.info". Le fait que vous puissiez accéder à cet en-tête signifie que vous avez pris connaissance de la licence CeCILL, et que vous en avez accepté les termes (cf. le fichier Documentation/licence.fr.txt fourni avec ce logiciel). */ /* LICENCE SUM UP Copyright CEA, contributors : Damien CALISTE, laboratoire L_Sim, (2017) E-mail addresses : CALISTE, damien P caliste AT cea P fr. This software is a computer program whose purpose is to visualize atomic configurations in 3D. This software is governed by the CeCILL license under French law and abiding by the rules of distribution of free software. You can use, modify and/ or redistribute the software under the terms of the CeCILL license as circulated by CEA, CNRS and INRIA at the following URL "http://www.cecill.info". The fact that you are presently reading this means that you have had knowledge of the CeCILL license and that you accept its terms. You can find a copy of this licence shipped with this software at Documentation/licence.en.txt. */ #ifndef SFIELDDIST_H #define SFIELDDIST_H #include #include /** * VISU_TYPE_SCALAR_FIELD_DATA: * * return the type of #VisuScalarFieldData. */ #define VISU_TYPE_SCALAR_FIELD_DATA (visu_scalar_field_data_get_type ()) /** * SCALAR_FIELD_DATA: * @obj: a #GObject to cast. * * Cast the given @obj into #VisuScalarFieldData type. */ #define VISU_SCALAR_FIELD_DATA(obj) (G_TYPE_CHECK_INSTANCE_CAST(obj, VISU_TYPE_SCALAR_FIELD_DATA, VisuScalarFieldData)) /** * VISU_SCALAR_FIELD_DATA_CLASS: * @klass: a #GObjectClass to cast. * * Cast the given @klass into #VisuScalarFieldDataClass. */ #define VISU_SCALAR_FIELD_DATA_CLASS(klass) (G_TYPE_CHECK_CLASS_CAST(klass, VISU_TYPE_SCALAR_FIELD_DATA, VisuScalarFieldDataClass)) /** * VISU_IS_SCALAR_FIELD_DATA: * @obj: a #GObject to test. * * Test if the given @ogj is of the type of #VisuScalarFieldData object. */ #define VISU_IS_SCALAR_FIELD_DATA(obj) (G_TYPE_CHECK_INSTANCE_TYPE(obj, VISU_TYPE_SCALAR_FIELD_DATA)) /** * VISU_IS_SCALAR_FIELD_DATA_CLASS: * @klass: a #GObjectClass to test. * * Test if the given @klass is of the type of #VisuScalarFieldDataClass class. */ #define VISU_IS_SCALAR_FIELD_DATA_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE(klass, VISU_TYPE_SCALAR_FIELD_DATA)) /** * VISU_SCALAR_FIELD_DATA_GET_CLASS: * @obj: a #GObject to get the class of. * * It returns the class of the given @obj. */ #define VISU_SCALAR_FIELD_DATA_GET_CLASS(obj) (G_TYPE_INSTANCE_GET_CLASS(obj, VISU_TYPE_SCALAR_FIELD_DATA, VisuScalarFieldDataClass)) typedef struct _VisuScalarFieldData VisuScalarFieldData; typedef struct _VisuScalarFieldDataPrivate VisuScalarFieldDataPrivate; typedef struct _VisuScalarFieldDataClass VisuScalarFieldDataClass; /** * VisuScalarFieldData: * * An opaque structure for the scalar field. */ struct _VisuScalarFieldData { VisuScalarField parent; VisuScalarFieldDataPrivate *priv; }; /** * VisuScalarFieldDataClass: * @parent: the parent class. * * An opaque structure for the class. */ struct _VisuScalarFieldDataClass { VisuScalarFieldClass parent; }; /** * VisuScalarFieldDataOrder: * @VISU_SCALAR_FIELD_DATA_XYZ: packed data are ordered x first. * @VISU_SCALAR_FIELD_DATA_ZYX: packed data are ordered z first. * * Ordering of 3D data. **/ typedef enum { VISU_SCALAR_FIELD_DATA_XYZ, VISU_SCALAR_FIELD_DATA_ZYX } VisuScalarFieldDataOrder; /** * visu_scalar_field_data_get_type: * * This method returns the type of #VisuScalarFieldData, use VISU_TYPE_SCALAR_FIELD_DATA instead. * * Returns: the type of #VisuScalarFieldData. */ GType visu_scalar_field_data_get_type(void); GList* visu_scalar_field_data_new_fromFile(const gchar *filename, GHashTable *table, GCancellable *cancel, GAsyncReadyCallback callback, gpointer user_data); GList* visu_scalar_field_data_new_fromFileSync(const gchar *filename, GHashTable *table, GCancellable *cancel, GError **error); void visu_scalar_field_data_set(VisuScalarFieldData *field, GArray *data, VisuScalarFieldDataOrder xyzOrder); const GArray* visu_scalar_field_data_getArray(const VisuScalarFieldData *field); /* Handling load methos. */ /** * VISU_TYPE_SCALAR_FIELD_METHOD: * * Return the associated #GType to the VisuScalarFieldMethod objects. */ #define VISU_TYPE_SCALAR_FIELD_METHOD (visu_scalar_field_method_get_type ()) /** * VISU_SCALAR_FIELD_METHOD: * @obj: the widget to cast. * * Cast the given object to a #VisuScalarFieldMethod object. */ #define VISU_SCALAR_FIELD_METHOD(obj) (G_TYPE_CHECK_INSTANCE_CAST ((obj), VISU_TYPE_SCALAR_FIELD_METHOD, VisuScalarFieldMethod)) /** * VISU_SCALAR_FIELD_METHOD_CLASS: * @klass: the class to cast. * * Cast the given class to a #VisuScalarFieldMethodClass object. */ #define VISU_SCALAR_FIELD_METHOD_CLASS(klass) (G_TYPE_CHECK_CLASS_CAST ((klass), VISU_TYPE_SCALAR_FIELD_METHOD, VisuScalarFieldMethodClass)) /** * VISU_IS_SCALAR_FIELD_METHOD: * @obj: the object to test. * * Return if the given object is a valid #VisuScalarFieldMethod object. */ #define VISU_IS_SCALAR_FIELD_METHOD(obj) (G_TYPE_CHECK_INSTANCE_TYPE ((obj), VISU_TYPE_SCALAR_FIELD_METHOD)) /** * VISU_IS_SCALAR_FIELD_METHOD_CLASS: * @klass: the class to test. * * Return if the given class is a valid #VisuScalarFieldMethodClass class. */ #define VISU_IS_SCALAR_FIELD_METHOD_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE ((klass), VISU_TYPE_SCALAR_FIELD_METHOD)) /** * VISU_SCALAR_FIELD_METHOD_GET_CLASS: * @obj: the widget to get the class of. * * Get the class of the given object. */ #define VISU_SCALAR_FIELD_METHOD_GET_CLASS(obj) (G_TYPE_INSTANCE_GET_CLASS(obj, VISU_TYPE_SCALAR_FIELD_METHOD, VisuScalarFieldMethodClass)) /** * VisuScalarFieldMethod: * * An opaque structure. */ typedef struct _VisuScalarFieldMethod VisuScalarFieldMethod; /** * VisuScalarFieldMethodClass: * @parent: the parent class. * * An opaque structure. */ typedef struct _VisuScalarFieldMethodClass VisuScalarFieldMethodClass; struct _VisuScalarFieldMethodClass { ToolFileFormatClass parent; }; /** * visu_scalar_field_method_get_type * * #GType are unique numbers to identify objects. * * Returns: the #GType associated with #VisuScalarFieldMethod objects. */ GType visu_scalar_field_method_get_type(void); typedef struct _VisuScalarFieldMethodData VisuScalarFieldMethodData; /** * visu_scalar_field_method_data_get_type * * #GType are unique numbers to identify objects. * * Returns: the #GType associated with #VisuScalarFieldMethodData objects. */ GType visu_scalar_field_method_data_get_type(void); /** * VisuScalarFieldMethodLoadFunc: * @meth: a #VisuScalarFieldMethod object ; * @data: the various data the load method requires. * @cancel: (allow-none): a #GCancellable object ; * @error: a location on a error pointer. * * Read the given file try to load it as a scalar field file. * If succeed (i.e. with none fatal errors) the method should return TRUE. If an error * occurs, it is stored into @error. * * If the file contains several fields, they must be loaded and added * to @data with visu_scalar_field_method_data_addField(). * * * Returns: TRUE if the read file is in a valid format (even with minor * errors), FALSE otherwise. */ typedef gboolean (*VisuScalarFieldMethodLoadFunc)(VisuScalarFieldMethod *meth, VisuScalarFieldMethodData *data, GCancellable *cancel, GError **error); struct _VisuScalarFieldMethod { ToolFileFormat parent; VisuScalarFieldMethodLoadFunc load; int priority; }; VisuScalarFieldMethod* visu_scalar_field_method_new(const gchar* descr, const gchar** patterns, VisuScalarFieldMethodLoadFunc method, int priority); GList* visu_scalar_field_method_load(VisuScalarFieldMethod *fmt, const gchar *filename, GHashTable *options, GCancellable *cancel, GAsyncReadyCallback callback, gpointer user_data); GList* visu_scalar_field_method_loadSync(VisuScalarFieldMethod *fmt, const gchar *filename, GHashTable *options, GCancellable *cancel, GError **error); const gchar* visu_scalar_field_method_data_getFilename(const VisuScalarFieldMethodData *data); void visu_scalar_field_method_data_addField(VisuScalarFieldMethodData *data, VisuScalarField *field); void visu_scalar_field_method_data_ready(VisuScalarFieldMethodData *data); GList* visu_scalar_field_method_getAll(void); void visu_scalar_field_method_class_finalize(void); #endif v_sim-3.8.0/src/extraFunctions/shadedColorizer.c000066400000000000000000000167741370110300500217340ustar00rootroot00000000000000/* EXTRAITS DE LA LICENCE Copyright CEA, contributeurs : Damien CALISTE, laboratoire L_Sim, (2019) Adresse mèl : CALISTE, damien P caliste AT cea P fr. Ce logiciel est un programme informatique servant à visualiser des structures atomiques dans un rendu pseudo-3D. Ce logiciel est régi par la licence CeCILL soumise au droit français et respectant les principes de diffusion des logiciels libres. Vous pouvez utiliser, modifier et/ou redistribuer ce programme sous les conditions de la licence CeCILL telle que diffusée par le CEA, le CNRS et l'INRIA sur le site "http://www.cecill.info". Le fait que vous puissiez accéder à cet en-tête signifie que vous avez pris connaissance de la licence CeCILL, et que vous en avez accepté les termes (cf. le fichier Documentation/licence.fr.txt fourni avec ce logiciel). */ /* LICENCE SUM UP Copyright CEA, contributors : Damien CALISTE, laboratoire L_Sim, (2019) E-mail address: CALISTE, damien P caliste AT cea P fr. This software is a computer program whose purpose is to visualize atomic configurations in 3D. This software is governed by the CeCILL license under French law and abiding by the rules of distribution of free software. You can use, modify and/ or redistribute the software under the terms of the CeCILL license as circulated by CEA, CNRS and INRIA at the following URL "http://www.cecill.info". The fact that you are presently reading this means that you have had knowledge of the CeCILL license and that you accept its terms. You can find a copy of this licence shipped with this software at Documentation/licence.en.txt. */ #include "shadedColorizer.h" /** * SECTION:shadedColorizer * @short_description: A class defining node colorisation using * a #ToolShade. * * This class implements #VisuDataColorizer and computes the * colors to apply to nodes from a #ToolShade. */ enum { PROP_0, SHADE_PROP, N_PROP }; static GParamSpec *properties[N_PROP]; struct _VisuDataColorizerShadedPrivate { ToolShade *shade; }; static void visu_data_colorizer_shaded_finalize(GObject* obj); static void visu_data_colorizer_shaded_get_property(GObject* obj, guint property_id, GValue *value, GParamSpec *pspec); static void visu_data_colorizer_shaded_set_property(GObject* obj, guint property_id, const GValue *value, GParamSpec *pspec); static gboolean _colorize(const VisuDataColorizer *colorizer, float rgba[4], const VisuData *visuData, const VisuNode* node); G_DEFINE_TYPE_WITH_CODE(VisuDataColorizerShaded, visu_data_colorizer_shaded, VISU_TYPE_DATA_COLORIZER, G_ADD_PRIVATE(VisuDataColorizerShaded)) static void visu_data_colorizer_shaded_class_init(VisuDataColorizerShadedClass *klass) { /* Connect the overloading methods. */ G_OBJECT_CLASS(klass)->finalize = visu_data_colorizer_shaded_finalize; G_OBJECT_CLASS(klass)->set_property = visu_data_colorizer_shaded_set_property; G_OBJECT_CLASS(klass)->get_property = visu_data_colorizer_shaded_get_property; VISU_DATA_COLORIZER_CLASS(klass)->colorize = _colorize; /** * VisuColorization::shade: * * The shading used to colorise. * * Since: 3.8 */ properties[SHADE_PROP] = g_param_spec_boxed("shade", "Shade", "shading scheme", TOOL_TYPE_SHADE, G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS); g_object_class_install_properties(G_OBJECT_CLASS(klass), N_PROP, properties); } static void visu_data_colorizer_shaded_get_property(GObject* obj, guint property_id, GValue *value, GParamSpec *pspec) { VisuDataColorizerShadedPrivate *self = VISU_DATA_COLORIZER_SHADED(obj)->priv; DBG_fprintf(stderr, "Colorizer Shaded: get property '%s' -> ", g_param_spec_get_name(pspec)); switch (property_id) { case SHADE_PROP: g_value_set_boxed(value, self->shade); DBG_fprintf(stderr, "%p.\n", (gpointer)self->shade); break; default: /* We don't have any other property... */ G_OBJECT_WARN_INVALID_PROPERTY_ID(obj, property_id, pspec); break; } } static void visu_data_colorizer_shaded_set_property(GObject* obj, guint property_id, const GValue *value, GParamSpec *pspec) { VisuDataColorizerShaded *self = VISU_DATA_COLORIZER_SHADED(obj); ToolShade *shade; DBG_fprintf(stderr, "Colorizer Shaded: set property '%s' -> ", g_param_spec_get_name(pspec)); switch (property_id) { case SHADE_PROP: shade = (ToolShade*)g_value_get_boxed(value); DBG_fprintf(stderr, "%p.\n", (gpointer)shade); if (shade) visu_data_colorizer_shaded_setShade(self, shade); break; default: /* We don't have any other property... */ G_OBJECT_WARN_INVALID_PROPERTY_ID(obj, property_id, pspec); break; } } static void visu_data_colorizer_shaded_init(VisuDataColorizerShaded *obj) { DBG_fprintf(stderr, "Visu Data Colorizer Shaded: initializing a new object (%p).\n", (gpointer)obj); obj->priv = visu_data_colorizer_shaded_get_instance_private(obj); obj->priv->shade = tool_shade_copy(tool_shade_getById(0)); } static void visu_data_colorizer_shaded_finalize(GObject *obj) { VisuDataColorizerShaded *vect; g_return_if_fail(obj); vect = VISU_DATA_COLORIZER_SHADED(obj); tool_shade_free(vect->priv->shade); G_OBJECT_CLASS(visu_data_colorizer_shaded_parent_class)->finalize(obj); } /** * visu_data_colorizer_shaded_setShade: * @colorizer: a #VisuDataColorizerShaded object. * @shade: a #ToolShade object. * * Change the @shade used by the @colorizer. * * Since: 3.8 * * Returns: TRUE if the shade is actually changed. **/ gboolean visu_data_colorizer_shaded_setShade(VisuDataColorizerShaded *colorizer, const ToolShade *shade) { g_return_val_if_fail(VISU_IS_DATA_COLORIZER_SHADED(colorizer), FALSE); if (tool_shade_compare(colorizer->priv->shade, shade)) return FALSE; tool_shade_free(colorizer->priv->shade); colorizer->priv->shade = tool_shade_copy(shade); g_object_notify_by_pspec(G_OBJECT(colorizer), properties[SHADE_PROP]); visu_data_colorizer_setDirty(VISU_DATA_COLORIZER(colorizer)); return TRUE; } /** * visu_data_colorizer_shaded_getShade: * @colorizer: a #VisuDataColorizerShaded object. * * Return the shade used to colourise the nodes. * * Returns: (transfer none): the ToolShade used (own by V_Sim). */ const ToolShade* visu_data_colorizer_shaded_getShade(const VisuDataColorizerShaded *colorizer) { g_return_val_if_fail(VISU_IS_DATA_COLORIZER_SHADED(colorizer), (const ToolShade*)0); return colorizer->priv->shade; } static gboolean _colorize(const VisuDataColorizer *colorizer, float rgba[4], const VisuData *visuData, const VisuNode* node) { VisuDataColorizerShaded *self; VisuDataColorizerShadedClass *klass; gfloat values[3]; g_return_val_if_fail(VISU_IS_DATA_COLORIZER_SHADED(colorizer), FALSE); self = VISU_DATA_COLORIZER_SHADED(colorizer); klass = VISU_DATA_COLORIZER_SHADED_GET_CLASS(self); if (!klass->toValues) return FALSE; if (klass->toValues(self, values, visuData, node)) tool_shade_channelToRGB(self->priv->shade, rgba, values); else return FALSE; return TRUE; } v_sim-3.8.0/src/extraFunctions/shadedColorizer.h000066400000000000000000000114351370110300500217260ustar00rootroot00000000000000/* EXTRAITS DE LA LICENCE Copyright CEA, contributeurs : Damien CALISTE, laboratoire L_Sim, (2019) Adresse mèl : CALISTE, damien P caliste AT cea P fr. Ce logiciel est un programme informatique servant à visualiser des structures atomiques dans un rendu pseudo-3D. Ce logiciel est régi par la licence CeCILL soumise au droit français et respectant les principes de diffusion des logiciels libres. Vous pouvez utiliser, modifier et/ou redistribuer ce programme sous les conditions de la licence CeCILL telle que diffusée par le CEA, le CNRS et l'INRIA sur le site "http://www.cecill.info". Le fait que vous puissiez accéder à cet en-tête signifie que vous avez pris connaissance de la licence CeCILL, et que vous en avez accepté les termes (cf. le fichier Documentation/licence.fr.txt fourni avec ce logiciel). */ /* LICENCE SUM UP Copyright CEA, contributors : Damien CALISTE, laboratoire L_Sim, (2019) E-mail address: CALISTE, damien P caliste AT cea P fr. This software is a computer program whose purpose is to visualize atomic configurations in 3D. This software is governed by the CeCILL license under French law and abiding by the rules of distribution of free software. You can use, modify and/ or redistribute the software under the terms of the CeCILL license as circulated by CEA, CNRS and INRIA at the following URL "http://www.cecill.info". The fact that you are presently reading this means that you have had knowledge of the CeCILL license and that you accept its terms. You can find a copy of this licence shipped with this software at Documentation/licence.en.txt. */ #ifndef SHADEDCOLORIZER_H #define SHADEDCOLORIZER_H #include #include #include "colorizer.h" #include "floatProp.h" #include G_BEGIN_DECLS /** * VISU_TYPE_DATA_COLORIZER_SHADED: * * return the type of #VisuDataColorizerShaded. */ #define VISU_TYPE_DATA_COLORIZER_SHADED (visu_data_colorizer_shaded_get_type ()) /** * VISU_DATA_COLORIZER_SHADED: * @obj: a #GObject to cast. * * Cast the given @obj into #VisuDataColorizerShaded type. */ #define VISU_DATA_COLORIZER_SHADED(obj) (G_TYPE_CHECK_INSTANCE_CAST(obj, VISU_TYPE_DATA_COLORIZER_SHADED, VisuDataColorizerShaded)) /** * VISU_DATA_COLORIZER_SHADED_CLASS: * @klass: a #GObjectClass to cast. * * Cast the given @klass into #VisuDataColorizerShadedClass. */ #define VISU_DATA_COLORIZER_SHADED_CLASS(klass) (G_TYPE_CHECK_CLASS_CAST(klass, VISU_TYPE_DATA_COLORIZER_SHADED, VisuDataColorizerShadedClass)) /** * VISU_IS_DATA_COLORIZER_SHADED: * @obj: a #GObject to test. * * Test if the given @ogj is of the type of #VisuDataColorizerShaded object. */ #define VISU_IS_DATA_COLORIZER_SHADED(obj) (G_TYPE_CHECK_INSTANCE_TYPE(obj, VISU_TYPE_DATA_COLORIZER_SHADED)) /** * VISU_IS_DATA_COLORIZER_SHADED_CLASS: * @klass: a #GObjectClass to test. * * Test if the given @klass is of the type of #VisuDataColorizerShadedClass class. */ #define VISU_IS_DATA_COLORIZER_SHADED_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE(klass, VISU_TYPE_DATA_COLORIZER_SHADED)) /** * VISU_DATA_COLORIZER_SHADED_GET_CLASS: * @obj: a #GObject to get the class of. * * It returns the class of the given @obj. */ #define VISU_DATA_COLORIZER_SHADED_GET_CLASS(obj) (G_TYPE_INSTANCE_GET_CLASS(obj, VISU_TYPE_DATA_COLORIZER_SHADED, VisuDataColorizerShadedClass)) /** * VisuDataColorizerShadedPrivate: * * Private data for #VisuDataColorizerShaded objects. */ typedef struct _VisuDataColorizerShadedPrivate VisuDataColorizerShadedPrivate; /** * VisuDataColorizerShaded: * * Common name to refer to a #_VisuDataColorizerShaded. */ typedef struct _VisuDataColorizerShaded VisuDataColorizerShaded; struct _VisuDataColorizerShaded { VisuDataColorizer parent; VisuDataColorizerShadedPrivate *priv; }; /** * VisuDataColorizerShadedClass: * @parent: its parent. * @toValues: a method that returns normalised values for @node. * * Interface for class that can represent #VisuDataColorizerShaded. * * Since: 3.8 */ typedef struct _VisuDataColorizerShadedClass VisuDataColorizerShadedClass; struct _VisuDataColorizerShadedClass { VisuDataColorizerClass parent; gboolean (*toValues) (const VisuDataColorizerShaded *colorizer, gfloat values[3], const VisuData *dataObj, const VisuNode *node); }; /** * visu_data_colorizer_shaded_get_type: * * This method returns the type of #VisuDataColorizerShaded, use * VISU_TYPE_DATA_COLORIZER_SHADED instead. * * Since: 3.8 * * Returns: the type of #VisuDataColorizerShaded. */ GType visu_data_colorizer_shaded_get_type(void); gboolean visu_data_colorizer_shaded_setShade(VisuDataColorizerShaded *colorizer, const ToolShade *shade); const ToolShade* visu_data_colorizer_shaded_getShade(const VisuDataColorizerShaded *colorizer); G_END_DECLS #endif v_sim-3.8.0/src/extraFunctions/shellProp.c000066400000000000000000000237611370110300500205550ustar00rootroot00000000000000/* EXTRAITS DE LA LICENCE Copyright CEA, contributeurs : Damien CALISTE, laboratoire L_Sim, (2017) Adresse mèl : CALISTE, damien P caliste AT cea P fr. Ce logiciel est un programme informatique servant à visualiser des structures atomiques dans un rendu pseudo-3D. Ce logiciel est régi par la licence CeCILL soumise au droit français et respectant les principes de diffusion des logiciels libres. Vous pouvez utiliser, modifier et/ou redistribuer ce programme sous les conditions de la licence CeCILL telle que diffusée par le CEA, le CNRS et l'INRIA sur le site "http://www.cecill.info". Le fait que vous puissiez accéder à cet en-tête signifie que vous avez pris connaissance de la licence CeCILL, et que vous en avez accepté les termes (cf. le fichier Documentation/licence.fr.txt fourni avec ce logiciel). */ /* LICENCE SUM UP Copyright CEA, contributors : Damien CALISTE, laboratoire L_Sim, (2017) E-mail address: CALISTE, damien P caliste AT cea P fr. This software is a computer program whose purpose is to visualize atomic configurations in 3D. This software is governed by the CeCILL license under French law and abiding by the rules of distribution of free software. You can use, modify and/ or redistribute the software under the terms of the CeCILL license as circulated by CEA, CNRS and INRIA at the following URL "http://www.cecill.info". The fact that you are presently reading this means that you have had knowledge of the CeCILL license and that you accept its terms. You can find a copy of this licence shipped with this software at Documentation/licence.en.txt. */ #include "shellProp.h" #include "neighbours.h" #include /** * SECTION:shellProp * @short_description: define a #VisuNodeValues object to handle shells. * * Defines a #VisuNodeValues object to store shells on every * nodes and get notification for them. */ struct _VisuNodeValuesShellPrivate { gboolean dispose_has_run; gint rootId; gfloat factor; guint level; }; enum { PROP_0, ROOT_PROP, LEVEL_PROP, N_PROP }; static GParamSpec *_properties[N_PROP]; static gchar* _serialize(const VisuNodeValues *vals, const VisuNode *node); static void _get_property(GObject* obj, guint property_id, GValue *value, GParamSpec *pspec); static void _set_property(GObject* obj, guint property_id, const GValue *value, GParamSpec *pspec); G_DEFINE_TYPE_WITH_CODE(VisuNodeValuesShell, visu_node_values_shell, VISU_TYPE_NODE_VALUES_FRAG, G_ADD_PRIVATE(VisuNodeValuesShell)) static void visu_node_values_shell_class_init(VisuNodeValuesShellClass *klass) { /* Connect the overloading methods. */ G_OBJECT_CLASS(klass)->set_property = _set_property; G_OBJECT_CLASS(klass)->get_property = _get_property; VISU_NODE_VALUES_CLASS(klass)->serialize = _serialize; /** * VisuNodeValuesShell::level: * * Level of recursion in shell building. * * Since: 3.8 */ _properties[LEVEL_PROP] = g_param_spec_uint("level", "Level", "Level of recursion in shell building.", 2, 10, 5, G_PARAM_READWRITE); /** * VisuNodeValuesShell::root: * * Id of the root node, or -1 if not any. * * Since: 3.8 */ _properties[ROOT_PROP] = g_param_spec_int("root", "Root", "Id of the root node, or -1 if not any.", -1, G_MAXINT, -1, G_PARAM_READWRITE); g_object_class_install_properties(G_OBJECT_CLASS(klass), N_PROP, _properties); } static void visu_node_values_shell_init(VisuNodeValuesShell *self) { self->priv = visu_node_values_shell_get_instance_private(self); self->priv->dispose_has_run = FALSE; self->priv->rootId = -1; self->priv->factor = 0.2f; self->priv->level = 5; } static void _get_property(GObject* obj, guint property_id, GValue *value, GParamSpec *pspec) { VisuNodeValuesShell *self = VISU_NODE_VALUES_SHELL(obj); DBG_fprintf(stderr, "Visu Node Values Shell: get property '%s' -> ", g_param_spec_get_name(pspec)); switch (property_id) { case ROOT_PROP: g_value_set_int(value, self->priv->rootId); DBG_fprintf(stderr, "%d.\n", self->priv->rootId); break; case LEVEL_PROP: g_value_set_uint(value, self->priv->level); DBG_fprintf(stderr, "%d.\n", self->priv->level); break; default: /* We don't have any other property... */ G_OBJECT_WARN_INVALID_PROPERTY_ID(obj, property_id, pspec); break; } } static void _set_property(GObject* obj, guint property_id, const GValue *value, GParamSpec *pspec) { VisuNodeValuesShell *self = VISU_NODE_VALUES_SHELL(obj); DBG_fprintf(stderr, "Visu Node Values Shell: set property '%s' -> ", g_param_spec_get_name(pspec)); switch (property_id) { case ROOT_PROP: DBG_fprintf(stderr, "%d\n", g_value_get_int(value)); visu_node_values_shell_compute(self, g_value_get_int(value), self->priv->factor); break; case LEVEL_PROP: DBG_fprintf(stderr, "%d\n", g_value_get_uint(value)); visu_node_values_shell_setLevel(self, g_value_get_uint(value)); break; default: /* We don't have any other property... */ G_OBJECT_WARN_INVALID_PROPERTY_ID(obj, property_id, pspec); break; } } static gchar* _serialize(const VisuNodeValues *vals, const VisuNode *node) { GValue value = {0, {{0}, {0}}}; VisuNodeFragment *frag; if (!visu_node_values_getAt(vals, node, &value)) return (gchar*)0; frag = (VisuNodeFragment*)g_value_get_boxed(&value); if (!frag) return (gchar*)0; return g_strdup(frag->label); } /** * visu_node_values_shell_new: * @arr: a #VisuNodeArray object. * @label: a translatable label. * * Create a new shell field. * * Since: 3.8 * * Returns: (transfer full): a newly created #VisuNodeValuesShell object. **/ VisuNodeValuesShell* visu_node_values_shell_new(VisuNodeArray *arr, const gchar *label) { VisuNodeValuesShell *vals; vals = VISU_NODE_VALUES_SHELL(g_object_new(VISU_TYPE_NODE_VALUES_SHELL, "nodes", arr, "label", label, "type", VISU_TYPE_NODE_FRAGMENT, "editable", FALSE, NULL)); return vals; } static gboolean _compute(VisuNodeValuesShell *shell, VisuNodeNeighbours *nei, VisuNodeArray *array, guint id, guint shellId) { VisuNodeNeighboursIter iter; const VisuNodeFragment *frag; VisuNodeFragment f; VisuNode *node; gboolean valid, ret; if (shellId > shell->priv->level) return TRUE; DBG_fprintf(stderr, "Visu NodeValuesShell: treating node %d (%d).\n", id, shellId); node = visu_node_array_getFromId(array, id); if (!node) return FALSE; frag = visu_node_values_frag_getAt(VISU_NODE_VALUES_FRAG(shell), node); if (frag && frag->id < shellId) return TRUE; if (shellId) f.label = g_strdup_printf(_("shell %d"), shellId); else f.label = g_strdup(_("root")); f.id = shellId; visu_node_values_frag_setAt(VISU_NODE_VALUES_FRAG(shell), node, &f); g_free(f.label); ret = TRUE; for (valid = visu_node_neighbours_iter(nei, &iter, id); valid; valid = visu_node_neighbours_iter_next(&iter)) ret = _compute(shell, nei, array, iter.neiId, shellId + 1) && ret; return ret; } /** * visu_node_values_shell_compute: * @shell: a #VisuNodeValuesShell object. * @id: a node id. * @factor: a afctor. * * Compute the neighbouring shells of node @id. The neighbour tables * is computed within @factor (for the sphere radii). * * Since: 3.8 * * Returns: TRUE if computation succeed. **/ gboolean visu_node_values_shell_compute(VisuNodeValuesShell *shell, guint id, gfloat factor) { VisuNodeArray *array; VisuNodeNeighbours *nei; gboolean valid; g_return_val_if_fail(VISU_IS_NODE_VALUES_SHELL(shell), FALSE); if (shell->priv->rootId == (gint)id) return TRUE; array = visu_node_values_getArray(VISU_NODE_VALUES(shell)); nei = visu_node_neighbours_new(VISU_DATA(array)); g_object_set(nei, "factor", factor, NULL); visu_node_values_reset(VISU_NODE_VALUES(shell)); shell->priv->rootId = id; shell->priv->factor = factor; valid = _compute(shell, nei, array, id, 0); g_object_unref(nei); g_object_unref(array); return valid; } /** * visu_node_values_shell_getLevel: * @shell: a #VisuNodeValuesShell object. * * Retrieves the current level of recursion that is done to look for * neighbouring shells. * * Since: 3.8 * * Returns: an integer value. **/ guint visu_node_values_shell_getLevel(VisuNodeValuesShell *shell) { g_return_val_if_fail(VISU_IS_NODE_VALUES_SHELL(shell), 5); return shell->priv->level; } /** * visu_node_values_shell_setLevel: * @shell: a #VisuNodeValuesShell object. * @level: an integer value. * * Defines the level of recursion that is done to look for * neighbouring shells. * * Since: 3.8 * * Returns: TRUE if the value is actually changed. **/ gboolean visu_node_values_shell_setLevel(VisuNodeValuesShell *shell, guint level) { guint id; g_return_val_if_fail(VISU_IS_NODE_VALUES_SHELL(shell), FALSE); if (level == shell->priv->level) return FALSE; shell->priv->level = level; g_object_notify_by_pspec(G_OBJECT(shell), _properties[LEVEL_PROP]); if (shell->priv->rootId >= 0) { id = shell->priv->rootId; shell->priv->rootId = -1; visu_node_values_shell_compute(shell, id, shell->priv->factor); } return TRUE; } /** * visu_node_values_shell_getRoot: * @shell: a #VisuNodeValuesShell object. * * Retrieve the node id used as reference for shell computation. * * Since: 3.8 * * Returns: the node id taken as reference, or -1 if none has been set. **/ gint visu_node_values_shell_getRoot(const VisuNodeValuesShell *shell) { g_return_val_if_fail(VISU_IS_NODE_VALUES_SHELL(shell), -1); return shell->priv->rootId; } v_sim-3.8.0/src/extraFunctions/shellProp.h000066400000000000000000000111171370110300500205520ustar00rootroot00000000000000/* EXTRAITS DE LA LICENCE Copyright CEA, contributeurs : Damien CALISTE, laboratoire L_Sim, (2017) Adresse mèl : CALISTE, damien P caliste AT cea P fr. Ce logiciel est un programme informatique servant à visualiser des structures atomiques dans un rendu pseudo-3D. Ce logiciel est régi par la licence CeCILL soumise au droit français et respectant les principes de diffusion des logiciels libres. Vous pouvez utiliser, modifier et/ou redistribuer ce programme sous les conditions de la licence CeCILL telle que diffusée par le CEA, le CNRS et l'INRIA sur le site "http://www.cecill.info". Le fait que vous puissiez accéder à cet en-tête signifie que vous avez pris connaissance de la licence CeCILL, et que vous en avez accepté les termes (cf. le fichier Documentation/licence.fr.txt fourni avec ce logiciel). */ /* LICENCE SUM UP Copyright CEA, contributors : Damien CALISTE, laboratoire L_Sim, (2017) E-mail address: CALISTE, damien P caliste AT cea P fr. This software is a computer program whose purpose is to visualize atomic configurations in 3D. This software is governed by the CeCILL license under French law and abiding by the rules of distribution of free software. You can use, modify and/ or redistribute the software under the terms of the CeCILL license as circulated by CEA, CNRS and INRIA at the following URL "http://www.cecill.info". The fact that you are presently reading this means that you have had knowledge of the CeCILL license and that you accept its terms. You can find a copy of this licence shipped with this software at Documentation/licence.en.txt. */ #ifndef SHELLPROP_H #define SHELLPROP_H #include #include #include "fragProp.h" G_BEGIN_DECLS /** * VISU_TYPE_NODE_VALUES_SHELL: * * return the type of #VisuNodeValuesShell. */ #define VISU_TYPE_NODE_VALUES_SHELL (visu_node_values_shell_get_type ()) /** * VISU_NODE_VALUES_SHELL: * @obj: a #GObject to cast. * * Cast the given @obj into #VisuNodeValuesShell type. */ #define VISU_NODE_VALUES_SHELL(obj) (G_TYPE_CHECK_INSTANCE_CAST(obj, VISU_TYPE_NODE_VALUES_SHELL, VisuNodeValuesShell)) /** * VISU_NODE_VALUES_SHELL_CLASS: * @klass: a #GObjectClass to cast. * * Cast the given @klass into #VisuNodeValuesShellClass. */ #define VISU_NODE_VALUES_SHELL_CLASS(klass) (G_TYPE_CHECK_CLASS_CAST(klass, VISU_TYPE_NODE_VALUES_SHELL, VisuNodeValuesShellClass)) /** * VISU_IS_NODE_VALUES_SHELL: * @obj: a #GObject to test. * * Test if the given @ogj is of the type of #VisuNodeValuesShell object. */ #define VISU_IS_NODE_VALUES_SHELL(obj) (G_TYPE_CHECK_INSTANCE_TYPE(obj, VISU_TYPE_NODE_VALUES_SHELL)) /** * VISU_IS_NODE_VALUES_SHELL_CLASS: * @klass: a #GObjectClass to test. * * Test if the given @klass is of the type of #VisuNodeValuesShellClass class. */ #define VISU_IS_NODE_VALUES_SHELL_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE(klass, VISU_TYPE_NODE_VALUES_SHELL)) /** * VISU_NODE_VALUES_SHELL_GET_CLASS: * @obj: a #GObject to get the class of. * * It returns the class of the given @obj. */ #define VISU_NODE_VALUES_SHELL_GET_CLASS(obj) (G_TYPE_INSTANCE_GET_CLASS(obj, VISU_TYPE_NODE_VALUES_SHELL, VisuNodeValuesShellClass)) /** * VisuNodeValuesShellPrivate: * * Private data for #VisuNodeValuesShell objects. */ typedef struct _VisuNodeValuesShellPrivate VisuNodeValuesShellPrivate; /** * VisuNodeValuesShell: * * Common name to refer to a #_VisuNodeValuesShell. */ typedef struct _VisuNodeValuesShell VisuNodeValuesShell; struct _VisuNodeValuesShell { VisuNodeValuesFrag parent; VisuNodeValuesShellPrivate *priv; }; /** * VisuNodeValuesShellClass: * @parent: private. * * Common name to refer to a #_VisuNodeValuesShellClass. */ typedef struct _VisuNodeValuesShellClass VisuNodeValuesShellClass; struct _VisuNodeValuesShellClass { VisuNodeValuesFragClass parent; }; /** * visu_node_values_shell_get_type: * * This method returns the type of #VisuNodeValuesShell, use * VISU_TYPE_NODE_VALUES_SHELL instead. * * Since: 3.8 * * Returns: the type of #VisuNodeValuesShell. */ GType visu_node_values_shell_get_type(void); VisuNodeValuesShell* visu_node_values_shell_new(VisuNodeArray *arr, const gchar *label); gboolean visu_node_values_shell_compute(VisuNodeValuesShell *shell, guint id, gfloat factor); guint visu_node_values_shell_getLevel(VisuNodeValuesShell *shell); gboolean visu_node_values_shell_setLevel(VisuNodeValuesShell *shell, guint level); gint visu_node_values_shell_getRoot(const VisuNodeValuesShell *shell); G_END_DECLS #endif v_sim-3.8.0/src/extraFunctions/stringProp.c000066400000000000000000000115001370110300500207400ustar00rootroot00000000000000/* EXTRAITS DE LA LICENCE Copyright CEA, contributeurs : Damien CALISTE, laboratoire L_Sim, (2016) Adresse mèl : CALISTE, damien P caliste AT cea P fr. Ce logiciel est un programme informatique servant à visualiser des structures atomiques dans un rendu pseudo-3D. Ce logiciel est régi par la licence CeCILL soumise au droit français et respectant les principes de diffusion des logiciels libres. Vous pouvez utiliser, modifier et/ou redistribuer ce programme sous les conditions de la licence CeCILL telle que diffusée par le CEA, le CNRS et l'INRIA sur le site "http://www.cecill.info". Le fait que vous puissiez accéder à cet en-tête signifie que vous avez pris connaissance de la licence CeCILL, et que vous en avez accepté les termes (cf. le fichier Documentation/licence.fr.txt fourni avec ce logiciel). */ /* LICENCE SUM UP Copyright CEA, contributors : Damien CALISTE, laboratoire L_Sim, (2016) E-mail address: CALISTE, damien P caliste AT cea P fr. This software is a computer program whose purpose is to visualize atomic configurations in 3D. This software is governed by the CeCILL license under French law and abiding by the rules of distribution of free software. You can use, modify and/ or redistribute the software under the terms of the CeCILL license as circulated by CEA, CNRS and INRIA at the following URL "http://www.cecill.info". The fact that you are presently reading this means that you have had knowledge of the CeCILL license and that you accept its terms. You can find a copy of this licence shipped with this software at Documentation/licence.en.txt. */ #include "stringProp.h" #include /** * SECTION:stringProp * @short_description: define a #VisuNodeValues object to handle strings. * * Defines a #VisuNodeValues object to store strings on every * nodes and get notification for them. */ static gboolean _parse(VisuNodeValues *vals, VisuNode *node, const gchar *from); static gchar* _serialize(const VisuNodeValues *vals, const VisuNode *node); G_DEFINE_TYPE(VisuNodeValuesString, visu_node_values_string, VISU_TYPE_NODE_VALUES) static void visu_node_values_string_class_init(VisuNodeValuesStringClass *klass) { /* Connect the overloading methods. */ VISU_NODE_VALUES_CLASS(klass)->parse = _parse; VISU_NODE_VALUES_CLASS(klass)->serialize = _serialize; } static void visu_node_values_string_init(VisuNodeValuesString *self _U_) { } static gboolean _parse(VisuNodeValues *vals, VisuNode *node, const gchar *from) { return visu_node_values_string_setAt(VISU_NODE_VALUES_STRING(vals), node, from); } static gchar* _serialize(const VisuNodeValues *vals, const VisuNode *node) { GValue value = {0, {{0}, {0}}}; if (!visu_node_values_getAt(vals, node, &value)) return (gchar*)0; return g_value_dup_string(&value); } /** * visu_node_values_string_new: * @arr: a #VisuNodeArray object. * @label: a translatable label. * * Create a new string field located on nodes. * * Since: 3.8 * * Returns: (transfer full): a newly created #VisuNodeValuesString object. **/ VisuNodeValuesString* visu_node_values_string_new(VisuNodeArray *arr, const gchar *label) { VisuNodeValuesString *vals; vals = VISU_NODE_VALUES_STRING(g_object_new(VISU_TYPE_NODE_VALUES_STRING, "nodes", arr, "label", label, "type", G_TYPE_STRING, NULL)); return vals; } /** * visu_node_values_string_getAt: * @vect: a #VisuNodeValuesString object. * @node: a #VisuNode object. * * Retrieves the float array hosted on @node. * * Since: 3.8 * * Returns: (transfer none): the coordinates of * float array for @node. **/ const gchar* visu_node_values_string_getAt(VisuNodeValuesString *vect, const VisuNode *node) { GValue value = {0, {{0}, {0}}}; g_return_val_if_fail(VISU_IS_NODE_VALUES_STRING(vect), NULL); visu_node_values_getAt(VISU_NODE_VALUES(vect), node, &value); return g_value_get_string(&value); } /** * visu_node_values_string_setAt: * @vect: a #VisuNodeValuesString object. * @node: a #VisuNode object. * @str: string value. * * Changes the string hosted at @node for one of defined by @str. * * Since: 3.8 * * Returns: TRUE if string for @node is indeed changed. **/ gboolean visu_node_values_string_setAt(VisuNodeValuesString *vect, const VisuNode *node, const gchar *str) { GValue value = {0, {{0}, {0}}}; visu_node_values_getAt(VISU_NODE_VALUES(vect), node, &value); if (str && g_value_get_string(&value) && !strcmp(str, g_value_get_string(&value))) return FALSE; g_value_set_static_string(&value, str); return visu_node_values_setAt(VISU_NODE_VALUES(vect), node, &value); } v_sim-3.8.0/src/extraFunctions/stringProp.h000066400000000000000000000106131370110300500207510ustar00rootroot00000000000000/* EXTRAITS DE LA LICENCE Copyright CEA, contributeurs : Damien CALISTE, laboratoire L_Sim, (2016) Adresse mèl : CALISTE, damien P caliste AT cea P fr. Ce logiciel est un programme informatique servant à visualiser des structures atomiques dans un rendu pseudo-3D. Ce logiciel est régi par la licence CeCILL soumise au droit français et respectant les principes de diffusion des logiciels libres. Vous pouvez utiliser, modifier et/ou redistribuer ce programme sous les conditions de la licence CeCILL telle que diffusée par le CEA, le CNRS et l'INRIA sur le site "http://www.cecill.info". Le fait que vous puissiez accéder à cet en-tête signifie que vous avez pris connaissance de la licence CeCILL, et que vous en avez accepté les termes (cf. le fichier Documentation/licence.fr.txt fourni avec ce logiciel). */ /* LICENCE SUM UP Copyright CEA, contributors : Damien CALISTE, laboratoire L_Sim, (2016) E-mail address: CALISTE, damien P caliste AT cea P fr. This software is a computer program whose purpose is to visualize atomic configurations in 3D. This software is governed by the CeCILL license under French law and abiding by the rules of distribution of free software. You can use, modify and/ or redistribute the software under the terms of the CeCILL license as circulated by CEA, CNRS and INRIA at the following URL "http://www.cecill.info". The fact that you are presently reading this means that you have had knowledge of the CeCILL license and that you accept its terms. You can find a copy of this licence shipped with this software at Documentation/licence.en.txt. */ #ifndef STRINGPROP_H #define STRINGPROP_H #include #include #include "nodeProp.h" G_BEGIN_DECLS /** * VISU_TYPE_NODE_VALUES_STRING: * * return the type of #VisuNodeValuesString. */ #define VISU_TYPE_NODE_VALUES_STRING (visu_node_values_string_get_type ()) /** * VISU_NODE_VALUES_STRING: * @obj: a #GObject to cast. * * Cast the given @obj into #VisuNodeValuesString type. */ #define VISU_NODE_VALUES_STRING(obj) (G_TYPE_CHECK_INSTANCE_CAST(obj, VISU_TYPE_NODE_VALUES_STRING, VisuNodeValuesString)) /** * VISU_NODE_VALUES_STRING_CLASS: * @klass: a #GObjectClass to cast. * * Cast the given @klass into #VisuNodeValuesStringClass. */ #define VISU_NODE_VALUES_STRING_CLASS(klass) (G_TYPE_CHECK_CLASS_CAST(klass, VISU_TYPE_NODE_VALUES_STRING, VisuNodeValuesStringClass)) /** * VISU_IS_NODE_VALUES_STRING: * @obj: a #GObject to test. * * Test if the given @ogj is of the type of #VisuNodeValuesString object. */ #define VISU_IS_NODE_VALUES_STRING(obj) (G_TYPE_CHECK_INSTANCE_TYPE(obj, VISU_TYPE_NODE_VALUES_STRING)) /** * VISU_IS_NODE_VALUES_STRING_CLASS: * @klass: a #GObjectClass to test. * * Test if the given @klass is of the type of #VisuNodeValuesStringClass class. */ #define VISU_IS_NODE_VALUES_STRING_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE(klass, VISU_TYPE_NODE_VALUES_STRING)) /** * VISU_NODE_VALUES_STRING_GET_CLASS: * @obj: a #GObject to get the class of. * * It returns the class of the given @obj. */ #define VISU_NODE_VALUES_STRING_GET_CLASS(obj) (G_TYPE_INSTANCE_GET_CLASS(obj, VISU_TYPE_NODE_VALUES_STRING, VisuNodeValuesStringClass)) /** * VisuNodeValuesString: * * Common name to refer to a #_VisuNodeValuesString. */ typedef struct _VisuNodeValuesString VisuNodeValuesString; struct _VisuNodeValuesString { VisuNodeValues parent; }; /** * VisuNodeValuesStringClass: * @parent: private. * * Common name to refer to a #_VisuNodeValuesStringClass. */ typedef struct _VisuNodeValuesStringClass VisuNodeValuesStringClass; struct _VisuNodeValuesStringClass { VisuNodeValuesClass parent; }; /** * visu_node_values_string_get_type: * * This method returns the type of #VisuNodeValuesString, use * VISU_TYPE_NODE_VALUES_STRING instead. * * Since: 3.8 * * Returns: the type of #VisuNodeValuesString. */ GType visu_node_values_string_get_type(void); VisuNodeValuesString* visu_node_values_string_new(VisuNodeArray *arr, const gchar *label); const gchar* visu_node_values_string_getAt(VisuNodeValuesString *vect, const VisuNode *node); gboolean visu_node_values_string_setAt(VisuNodeValuesString *vect, const VisuNode *node, const gchar *str); G_END_DECLS #endif v_sim-3.8.0/src/extraFunctions/surfaces.c000066400000000000000000001134701370110300500204150ustar00rootroot00000000000000/* EXTRAITS DE LA LICENCE Copyright CEA, contributeurs : Luc BILLARD, Damien CALISTE, Olivier D'Astier, laboratoire L_Sim, (2001-2016) Adresse mèl : BILLARD, non joignable par mèl ; CALISTE, damien P caliste AT cea P fr. Ce logiciel est un programme informatique servant à visualiser des structures atomiques dans un rendu pseudo-3D. Ce logiciel est régi par la licence CeCILL soumise au droit français et respectant les principes de diffusion des logiciels libres. Vous pouvez utiliser, modifier et/ou redistribuer ce programme sous les conditions de la licence CeCILL telle que diffusée par le CEA, le CNRS et l'INRIA sur le site "http://www.cecill.info". Le fait que vous puissiez accéder à cet en-tête signifie que vous avez pris connaissance de la licence CeCILL, et que vous en avez accepté les termes (cf. le fichier Documentation/licence.fr.txt fourni avec ce logiciel). */ /* LICENCE SUM UP Copyright CEA, contributors : Luc BILLARD and Damien CALISTE and Olivier D'Astier, laboratoire L_Sim, (2001-2016) E-mail addresses : BILLARD, not reachable any more ; CALISTE, damien P caliste AT cea P fr. D'ASTIER, dastier AT iie P cnam P fr. This software is a computer program whose purpose is to visualize atomic configurations in 3D. This software is governed by the CeCILL license under French law and abiding by the rules of distribution of free software. You can use, modify and/ or redistribute the software under the terms of the CeCILL license as circulated by CEA, CNRS and INRIA at the following URL "http://www.cecill.info". The fact that you are presently reading this means that you have had knowledge of the CeCILL license and that you accept its terms. You can find a copy of this licence shipped with this software at Documentation/licence.en.txt. */ #include "surfaces.h" #include #include #include #include #include #include /** * SECTION:surfaces * @short_description: Supports loading of .surf files and drawing of * surfaces through OpenGL. * * Originally written by Luc Billard for his Visualize program. This * module allows loading of .surf files to draw scalar fields on top of * the current display scene. .surf files are text files which specs are * the following : * * * 1st line is arbitrary * * * 2nd line must contain 3 real (float) values: dxx dyx dyy * * * 3rd line must contain 3 real (float) values: dzx dzy dzz * * * 4th line must contain 3 positive integers which * represents respectively the number of surfaces, the total number of * polys, and the total number of points * * * Then, for each of these surfaces : * * * * next line must contain the name of the surface : it is a * string which should match the pattern surface_* * * * next line must contain 2 positive integer values: the number of polys * (num_polys) and * the number of points (num_points) used by the surface * * * each of the following num_polys lines must match the pattern * [n i_1 i_2 i_3 ... i_n] where n is the number of vertices in the poly (n >= 3) * and [i_1 i_2 i_3 ... i_n] are the numbering of these vertices (vertices numbered from 1 to num_points) * * * each of the following num_points lines must contain 6 real values for the * successive (1 to num_points) points : [x y z nx ny nz], where x y z are the coordinates of the point * and nx ny nz are the coordinates of the unit normal at the point * * * * * * * It is the responsibility of the user to guarantee that * dxx, dyx, dyy, dzx, dzy, dzz match the one currently loaded in V_Sim's * current context. Though if you use panelSurfaces you can ask * to resize the surfaces so that they fit in the current loaded box. * */ #define ISOSURFACES_FLAG_POTENTIAL "# potentialValue" static GQuark quark; typedef struct VisuSurfaceProperties_struct { gchar *name; /* The element (G_TYPE_INT...). */ guint type; /* A pointer to the surf it belongs to. */ VisuSurface *surf; /* The data. */ gpointer data; } VisuSurfaceProperties; static void freeVisuSurfaceProperties(gpointer data); enum { SURFACE_MASKED_SIGNAL, NB_SIGNAL }; enum { PROP_0, RESOURCE_PROP, N_PROP, ADJUST_PROP, BOX_PROP }; /* Private area. */ struct _VisuSurfacePrivate { gboolean dispose_has_run; VisuSurfacePoints basePoints; VisuSurfacePoints volatilePlanes; /* The description of the box where surfaces are drawn. */ VisuBox *box; gboolean adjust; /* Resources for the surface. */ VisuSurfaceResource *resource; gulong maskable_signal; /* Related objects. */ VisuPlaneSet *mask; gulong masking_signal; /* Table to add properties to surfaces. */ GHashTable *properties; }; /* Internal variables. */ static guint surfaces_signals[NB_SIGNAL] = { 0 }; static GParamSpec* properties[N_PROP]; /* Object gestion methods. */ static void visu_surface_dispose (GObject* obj); static void visu_surface_finalize (GObject* obj); static void visu_surface_get_property(GObject* obj, guint property_id, GValue *value, GParamSpec *pspec); static void visu_surface_set_property(GObject* obj, guint property_id, const GValue *value, GParamSpec *pspec); static void visu_boxed_interface_init(VisuBoxedInterface *iface); /* Local functions. */ static VisuBox* visu_surface_getBox(VisuBoxed *self); static gboolean visu_surface_setBox(VisuBoxed *self, VisuBox *box); static void onMasking(VisuPlaneSet *mask, VisuSurface *data); static gboolean _setResource(VisuSurface *surf, VisuSurfaceResource *res); static void onMaskable(VisuSurfaceResource *res, GParamSpec *param, VisuSurface *data); G_DEFINE_TYPE_WITH_CODE(VisuSurface, visu_surface, VISU_TYPE_OBJECT, G_ADD_PRIVATE(VisuSurface) G_IMPLEMENT_INTERFACE(VISU_TYPE_BOXED, visu_boxed_interface_init)) static void visu_surface_class_init(VisuSurfaceClass *klass) { DBG_fprintf(stderr, "VisuSurface: creating the class of the object.\n"); DBG_fprintf(stderr, " - adding new signals ;\n"); /** * VisuSurface::masked: * @surf: the object which received the signal. * * Gets emitted when a surface is shown or hidden by a plane. * * Since: 3.7 */ surfaces_signals[SURFACE_MASKED_SIGNAL] = g_signal_new("masked", G_TYPE_FROM_CLASS (klass), G_SIGNAL_RUN_LAST | G_SIGNAL_NO_RECURSE | G_SIGNAL_NO_HOOKS, 0, NULL, NULL, g_cclosure_marshal_VOID__VOID, G_TYPE_NONE, 0); /* Connect freeing methods. */ G_OBJECT_CLASS(klass)->dispose = visu_surface_dispose; G_OBJECT_CLASS(klass)->finalize = visu_surface_finalize; G_OBJECT_CLASS(klass)->set_property = visu_surface_set_property; G_OBJECT_CLASS(klass)->get_property = visu_surface_get_property; g_object_class_override_property(G_OBJECT_CLASS(klass), ADJUST_PROP, "auto-adjust"); g_object_class_override_property(G_OBJECT_CLASS(klass), BOX_PROP, "box"); /** * VisuSurface::resource: * * Resource used to draw the suface (color, properties...). * * Since: 3.8 */ properties[RESOURCE_PROP] = g_param_spec_object("resource", "Resource", "resource", VISU_TYPE_SURFACE_RESOURCE, G_PARAM_READWRITE); g_object_class_install_property (G_OBJECT_CLASS(klass), RESOURCE_PROP, properties[RESOURCE_PROP]); quark = g_quark_from_static_string("visu_isosurfaces"); } static void visu_boxed_interface_init(VisuBoxedInterface *iface) { iface->get_box = visu_surface_getBox; iface->set_box = visu_surface_setBox; } static void visu_surface_init(VisuSurface *obj) { DBG_fprintf(stderr, "VisuSurface: creating a new surfaces (%p).\n", (gpointer)obj); obj->priv = visu_surface_get_instance_private(obj); obj->priv->dispose_has_run = FALSE; obj->priv->adjust = FALSE; obj->priv->box = (VisuBox*)0; obj->priv->resource = (VisuSurfaceResource*)0; obj->priv->maskable_signal = 0; obj->priv->mask = (VisuPlaneSet*)0; obj->priv->masking_signal = 0; obj->priv->properties = g_hash_table_new_full(g_str_hash, g_str_equal, NULL, freeVisuSurfaceProperties); } /* This method can be called several times. It should unref all of its reference to GObjects. */ static void visu_surface_dispose(GObject* obj) { DBG_fprintf(stderr, "VisuSurface: dispose object %p.\n", (gpointer)obj); if (VISU_SURFACE(obj)->priv->dispose_has_run) return; visu_surface_setBox(VISU_BOXED(obj), (VisuBox*)0); visu_surface_setMask(VISU_SURFACE(obj), (VisuPlaneSet*)0); _setResource(VISU_SURFACE(obj), (VisuSurfaceResource*)0); VISU_SURFACE(obj)->priv->dispose_has_run = TRUE; /* Chain up to the parent class */ G_OBJECT_CLASS(visu_surface_parent_class)->dispose(obj); } /* This method is called once only. */ static void visu_surface_finalize(GObject* obj) { VisuSurfacePrivate *priv = VISU_SURFACE(obj)->priv; DBG_fprintf(stderr, "VisuSurface: finalize object %p.\n", (gpointer)obj); visu_surface_points_free(&priv->basePoints); visu_surface_points_free(&priv->volatilePlanes); if (priv->properties) g_hash_table_destroy(priv->properties); /* Chain up to the parent class */ G_OBJECT_CLASS(visu_surface_parent_class)->finalize(obj); } static void visu_surface_get_property(GObject* obj, guint property_id, GValue *value, GParamSpec *pspec) { VisuSurface *self = VISU_SURFACE(obj); DBG_fprintf(stderr, "Visu GlView: get property '%s' -> ", g_param_spec_get_name(pspec)); switch (property_id) { case BOX_PROP: g_value_set_object(value, self->priv->box); DBG_fprintf(stderr, "%p.\n", (gpointer)self->priv->box); break; case ADJUST_PROP: g_value_set_boolean(value, self->priv->adjust); DBG_fprintf(stderr, "%d.\n", self->priv->adjust); break; case RESOURCE_PROP: g_value_set_object(value, self->priv->resource); DBG_fprintf(stderr, "%p.\n", (gpointer)self->priv->resource); break; default: /* We don't have any other property... */ G_OBJECT_WARN_INVALID_PROPERTY_ID(obj, property_id, pspec); break; } } static void visu_surface_set_property(GObject* obj, guint property_id, const GValue *value, GParamSpec *pspec) { VisuSurface *self = VISU_SURFACE(obj); DBG_fprintf(stderr, "Visu GlView: set property '%s' -> ", g_param_spec_get_name(pspec)); switch (property_id) { case BOX_PROP: DBG_fprintf(stderr, "%p.\n", g_value_get_object(value)); visu_surface_setBox(VISU_BOXED(obj), VISU_BOX(g_value_get_object(value))); break; case ADJUST_PROP: self->priv->adjust = g_value_get_boolean(value); DBG_fprintf(stderr, "%d.\n", self->priv->adjust); break; case RESOURCE_PROP: visu_surface_setResource(self, g_value_get_object(value)); DBG_fprintf(stderr, "%p.\n", (gpointer)self->priv->resource); break; default: /* We don't have any other property... */ G_OBJECT_WARN_INVALID_PROPERTY_ID(obj, property_id, pspec); break; } } /** * visu_surface_getErrorQuark: * * Internal routine for error handling. * * Returns: the #GQuark associated to errors related to surface * files. */ GQuark visu_surface_getErrorQuark(void) { return quark; } /** * VisuSurfaceDefinition: * @points: (element-type VisuSurfacePoint): some coordinates. * @polys: (element-type VisuSurfacePoly): some polygons. * * Define a surface by giving some node coordinates and normals and * how to connect these nodes to form polygons. */ static gpointer definition_copy(gpointer boxed) { VisuSurfaceDefinition *out; out = (VisuSurfaceDefinition*)g_memdup(boxed, sizeof(VisuSurfaceDefinition)); g_array_ref(out->points); g_array_ref(out->polys); return (gpointer)out; } static void definition_free(gpointer boxed) { VisuSurfaceDefinition *def = (VisuSurfaceDefinition*)boxed; g_array_unref(def->points); g_array_unref(def->polys); g_free(boxed); } /** * visu_surface_definition_get_type: * * Create and retrieve a #GType for a #VisuSurfaceDefinition object. * * Since: 3.8 * * Returns: a new type for #VisuSurfaceDefinition structures. */ GType visu_surface_definition_get_type(void) { static GType g_define_type_id = 0; if (g_define_type_id == 0) g_define_type_id = g_boxed_type_register_static("VisuSurfaceDefinition", definition_copy, definition_free); return g_define_type_id; } /** * visu_surface_checkConsistency: * @surf: a #VisuSurface object. * * Check if all arrays in the structures are consistent (without * overflow). */ void visu_surface_checkConsistency(VisuSurface* surf) { DBG_fprintf(stderr, "Isosurfaces: Check consistency.\n"); DBG_fprintf(stderr, " | Base points\n"); visu_surface_points_check(&surf->priv->basePoints); DBG_fprintf(stderr, " | Volatile planes\n"); visu_surface_points_check(&surf->priv->volatilePlanes); } /** * visu_surface_new: * @label: a string. * @points: (element-type VisuSurfacePoint): a set of point coordinates. * @polys: (element-type VisuSurfacePoly): a set of polygons. * * Create a new #VisuSurface object as defined by @points and @polys. * * Returns: a newly allocated #VisuSurface structure. */ VisuSurface* visu_surface_new(const gchar *label, const GArray *points, const GArray *polys) { VisuSurface *surf; VisuSurfaceResource *res; gboolean new; surf = VISU_SURFACE(g_object_new(VISU_TYPE_SURFACE, NULL)); DBG_fprintf(stderr, "Visu Surface: new surfaces %p.\n", (gpointer)surf); visu_surface_points_init(&surf->priv->basePoints, 0); visu_surface_points_init(&surf->priv->volatilePlanes, 0); DBG_fprintf(stderr, "Visu Surface: add surface %d %d.\n", polys->len, points->len); visu_surface_points_addPoly(&surf->priv->basePoints, points, polys); visu_surface_points_addPoly(&surf->priv->volatilePlanes, NULL, NULL); res = visu_surface_resource_new_fromName(label, &new); visu_surface_setResource(surf, res); if (new) g_object_set(G_OBJECT(surf->priv->resource), "rendered", TRUE, NULL); g_object_unref(res); #if DEBUG == 1 visu_surface_checkConsistency(surf); #endif return surf; } /** * visu_surface_new_fromDefinition: * @label: a string. * @definition: Some points and polys. * * Same as visu_surface_new(), mainly for language bindings. * * Since: 3.8 * * Returns: a newly allocated #VisuSurface structure. **/ VisuSurface* visu_surface_new_fromDefinition(const gchar *label, const VisuSurfaceDefinition *definition) { g_return_val_if_fail(definition, (VisuSurface*)0); return visu_surface_new(label, definition->points, definition->polys); } static gboolean visu_surface_setBox(VisuBoxed *self, VisuBox *box) { VisuSurface *surf; float trans[3][3], boxToXYZ[3][3], XYZToOldBox[3][3]; double boxToXYZd[3][3], XYZToOldBoxd[3][3]; g_return_val_if_fail(VISU_IS_SURFACE(self), FALSE); surf = VISU_SURFACE(self); DBG_fprintf(stderr, "Isosurfaces: change the current box to fit to %p.\n", (gpointer)box); if (surf->priv->box == box) return FALSE; if (surf->priv->adjust && surf->priv->box && box) { visu_box_getInvMatrix(surf->priv->box, XYZToOldBoxd); tool_matrix_dtof(XYZToOldBox, XYZToOldBoxd); visu_box_getCellMatrix(box, boxToXYZd); tool_matrix_dtof(boxToXYZ, boxToXYZd); tool_matrix_productMatrix(trans, boxToXYZ, XYZToOldBox); visu_surface_points_transform(&surf->priv->basePoints, trans); visu_surface_points_transform(&surf->priv->volatilePlanes, trans); } if (surf->priv->box) g_object_unref(surf->priv->box); surf->priv->box = box; if (box) g_object_ref(box); return TRUE; } static VisuBox* visu_surface_getBox(VisuBoxed *self) { g_return_val_if_fail(VISU_IS_SURFACE(self), (VisuBox*)0); DBG_fprintf(stderr, "VisuSurface: get box.\n"); return VISU_SURFACE(self)->priv->box; } static void freeVisuSurfaceProperties(gpointer data) { VisuSurfaceProperties *prop; prop = (VisuSurfaceProperties*)data; g_free(prop->name); g_free(prop->data); g_free(prop); } /* Dealing with properties as floats. */ /** * visu_surface_addPropertyFloat: * @surf: a #VisuSurface object ; * @name: the name of the property to add. * * Some properties can be associated to the surfaces stored in @surf. * This method is add a new property. * * Returns: a newly allocated array that can be populated. */ float* visu_surface_addPropertyFloat(VisuSurface *surf, const gchar* name) { VisuSurfaceProperties *prop; g_return_val_if_fail(surf, (float*)0); g_return_val_if_fail(name && name[0], (float*)0); DBG_fprintf(stderr, "Visu Surfaces: add a new float prop '%s'.\n", name); prop = g_malloc(sizeof(VisuSurfaceProperties)); prop->name = g_strdup(name); prop->type = G_TYPE_FLOAT; prop->surf = surf; prop->data = g_malloc(sizeof(float)); g_hash_table_insert(surf->priv->properties, (gpointer)prop->name, (gpointer)prop); return (float*)prop->data; } gboolean visu_surface_addPropertyFloatValue(VisuSurface *surf, const gchar* name, float value) { float* data; VisuSurfaceProperties *prop; g_return_val_if_fail(surf, FALSE); prop = (VisuSurfaceProperties*)g_hash_table_lookup(surf->priv->properties, name); if (!prop) return FALSE; g_return_val_if_fail(prop->surf != surf, FALSE); data = (float*)prop->data; *data = value; return TRUE; } /** * visu_surface_getPropertyValueFloat: * @surf: a #VisuSurface object ; * @name: the name of the property to get the value from ; * @value: a location to store the value. * * This method retrieves a float value stored as a property called @name for * the surface defined by its number @idSurf. * * Returns: TRUE if a value is indeed found. */ gboolean visu_surface_getPropertyValueFloat(VisuSurface *surf, const gchar *name, float *value) { float* data; VisuSurfaceProperties *prop; g_return_val_if_fail(surf && value, FALSE); prop = (VisuSurfaceProperties*)g_hash_table_lookup(surf->priv->properties, name); if (!prop) return FALSE; g_return_val_if_fail(prop->surf != surf, FALSE); data = (float*)prop->data; *value = *data; return TRUE; } /** * visu_surface_getPropertyFloat: * @surf: a #VisuSurface object ; * @name: the name of the property to look for. * * Some properties can be associated to the surfaces stored in @surf. * This method is used to retrieve floating point values properties. * * Returns: a table with the values if the property is found, NULL * otherwise. */ float* visu_surface_getPropertyFloat(VisuSurface *surf, const gchar *name) { VisuSurfaceProperties *prop; g_return_val_if_fail(surf, (float*)0); prop = (VisuSurfaceProperties*)g_hash_table_lookup(surf->priv->properties, name); if (prop) return (float*)prop->data; else return (float*)0; } /** * visu_surface_loadFile: * @file: target file to load ; * @surf: (out) (transfer full) (element-type VisuSurface*): a set of * surfaces (location) ; * @error: a location to store errors. * * This loads a surface file and set default material properties for it. * See surf file specifications. * * Returns: TRUE in case of success, FALSE otherwise. Even in case of success * @error may have been set. */ gboolean visu_surface_loadFile(const char *file, GList **surf, GError **error) { GIOChannel* surf_file; int line_number = 0; double dxx=0, dyx=0, dyy=0; double dzx=0, dzy=0, dzz=0; double geometry[VISU_BOX_N_VECTORS]; guint file_nsurfs=0, file_npolys=0, file_npoints=0; guint npolys_loaded=0, npoints_loaded=0; guint i; int j,k, res; guint sum_polys=0, sum_points=0; GIOStatus io_status; GString *current_line; float *densityData, densityValue; gchar *label; GArray *points, *polys; VisuBox *box; VisuSurface *surface; g_return_val_if_fail(surf, FALSE); g_return_val_if_fail(error, FALSE); DBG_fprintf(stderr, "Isosurfaces: trying to load %s file.\n", file); *surf = (GList*)0; current_line = g_string_new(""); *error = (GError*)0; surf_file = g_io_channel_new_file(file, "r", error); if(!surf_file) return FALSE; /* DBG_fprintf(stderr, "File opened\n"); */ *error = (GError*)0; io_status = g_io_channel_read_line_string(surf_file, current_line, NULL, error); if(io_status != G_IO_STATUS_NORMAL) { g_string_free(current_line, TRUE); g_io_channel_unref(surf_file); return FALSE; } line_number++; /* DBG_fprintf(stderr, "Line %d read successfully\n", line_number); */ *error = (GError*)0; io_status = g_io_channel_read_line_string(surf_file, current_line, NULL, error); if(io_status != G_IO_STATUS_NORMAL) { g_string_free(current_line, TRUE); g_io_channel_unref(surf_file); return FALSE; } line_number++; /* DBG_fprintf(stderr, "Line %d read successfully\n", line_number); */ if(sscanf(current_line->str, "%lf %lf %lf", &dxx, &dyx, &dyy) != 3) { *error = g_error_new(VISU_ERROR_ISOSURFACES, VISU_ERROR_FORMAT, _("Line %d doesn't match the [float, float, float]" " pattern."), line_number); g_string_free(current_line, TRUE); g_io_channel_unref(surf_file); return FALSE; } *error = (GError*)0; io_status = g_io_channel_read_line_string(surf_file, current_line, NULL, error); if(io_status != G_IO_STATUS_NORMAL) { g_string_free(current_line, TRUE); g_io_channel_unref(surf_file); return FALSE; } line_number++; /* DBG_fprintf(stderr, "Line %d read successfully\n", line_number); */ if(sscanf(current_line->str, "%lf %lf %lf", &dzx, &dzy, &dzz) != 3) { *error = g_error_new(VISU_ERROR_ISOSURFACES, VISU_ERROR_FORMAT, _("Line %d doesn't match the [float, float, float]" " pattern."), line_number); g_string_free(current_line, TRUE); g_io_channel_unref(surf_file); return FALSE; } *error = (GError*)0; io_status = g_io_channel_read_line_string(surf_file, current_line, NULL, error); if(io_status != G_IO_STATUS_NORMAL) { g_string_free(current_line, TRUE); g_io_channel_unref(surf_file); return FALSE; } line_number++; /* DBG_fprintf(stderr, "Line %d read successfully\n", line_number); */ res = sscanf(current_line->str, "%u %u %u", &file_nsurfs, &file_npolys, &file_npoints); if(res != 3 || file_nsurfs <= 0 || file_npolys <= 0 || file_npoints <= 0) { *error = g_error_new(VISU_ERROR_ISOSURFACES, VISU_ERROR_FORMAT, _("Line %d doesn't match the [int > 0, int > 0, int > 0]" " pattern."), line_number); g_string_free(current_line, TRUE); g_io_channel_unref(surf_file); return FALSE; } /* From now on, the file is supposed to be a valid surface file. */ geometry[VISU_BOX_DXX] = dxx; geometry[VISU_BOX_DYX] = dyx; geometry[VISU_BOX_DYY] = dyy; geometry[VISU_BOX_DZX] = dzx; geometry[VISU_BOX_DZY] = dzy; geometry[VISU_BOX_DZZ] = dzz; box = visu_box_new(geometry, VISU_BOX_PERIODIC); visu_box_setMargin(box, 0, FALSE); /* For each surf */ for(i = 0; i < file_nsurfs; i++) { int surf_npolys=0, surf_npoints=0; densityValue = G_MAXFLOAT; /* Allow some commentaries here begining with a '#' character. */ do { /* Get the first line that should contains current surf' name */ *error = (GError*)0; io_status = g_io_channel_read_line_string(surf_file, current_line, NULL, error); if(io_status != G_IO_STATUS_NORMAL) { g_string_free(current_line, TRUE); g_io_channel_unref(surf_file); g_object_unref(box); return TRUE; } line_number++; /* If the line begins with a '#', then we try to find a density value. */ if (current_line->str[0] == '#') sscanf(current_line->str, ISOSURFACES_FLAG_POTENTIAL" %f", &densityValue); } while (current_line->str[0] == '#'); g_strdelimit(current_line->str, "\n", ' '); g_strstrip(current_line->str); label = g_strdup(current_line->str); DBG_fprintf(stderr, "Visu Surfaces: line %d ('%s') read successfully %f\n", line_number, label, densityValue); *error = (GError*)0; io_status = g_io_channel_read_line_string(surf_file, current_line, NULL, error); if(io_status != G_IO_STATUS_NORMAL) { g_string_free(current_line, TRUE); g_io_channel_unref(surf_file); g_object_unref(box); g_free(label); return TRUE; } line_number++; /* DBG_fprintf(stderr, "Line %d read successfully\n", line_number); */ res = sscanf(current_line->str, "%d %d", &surf_npolys, &surf_npoints); if(res != 2 || surf_npolys <= 0 || surf_npoints <= 0) { *error = g_error_new(VISU_ERROR_ISOSURFACES, VISU_ERROR_FORMAT, _("Line %d doesn't match the [int > 0, int > 0]" " pattern."), line_number); g_string_free(current_line, TRUE); g_io_channel_unref(surf_file); g_object_unref(box); g_free(label); return TRUE; } sum_polys += surf_npolys; if(sum_polys > file_npolys) { *error = g_error_new(VISU_ERROR_ISOSURFACES, VISU_ERROR_CHECKSUM, _("Error on line %d. Declared number of polygons" " reached."), line_number); g_string_free(current_line, TRUE); g_io_channel_unref(surf_file); g_object_unref(box); g_free(label); return TRUE; } sum_points += surf_npoints; if(sum_points > file_npoints) { *error = g_error_new(VISU_ERROR_ISOSURFACES, VISU_ERROR_CHECKSUM, _("Error on line %d. Declared number of points" " reached."), line_number); g_string_free(current_line, TRUE); g_io_channel_unref(surf_file); g_object_unref(box); g_free(label); return TRUE; } polys = g_array_sized_new(FALSE, FALSE, sizeof(VisuSurfacePoly), surf_npolys); for(j = 0; j < surf_npolys; j++) { VisuSurfacePoly poly; guint nvertex_i=0; gchar **split_line; poly.nvertices = 0; *error = (GError*)0; io_status = g_io_channel_read_line_string(surf_file, current_line, NULL, error); if(io_status != G_IO_STATUS_NORMAL) { g_string_free(current_line, TRUE); g_io_channel_unref(surf_file); g_object_unref(box); g_free(label); return TRUE; } line_number++; split_line = g_strsplit_set(current_line->str, " ", -1); for(k = 0; split_line[k] != NULL; k++) { if(g_ascii_strcasecmp(split_line[k], "") == 0) continue; if (poly.nvertices == 0) { if(sscanf(split_line[k], "%u", &poly.nvertices) != 1 || poly.nvertices < 3) { *error = g_error_new(VISU_ERROR_ISOSURFACES, VISU_ERROR_FORMAT, _("Line %dmust begin by an int."), line_number); g_string_free(current_line, TRUE); g_io_channel_unref(surf_file); g_object_unref(box); g_free(label); g_array_unref(polys); return TRUE; } npolys_loaded++; continue; } res = sscanf(split_line[k], "%u", poly.indices + nvertex_i); if(res != 1) { *error = g_error_new(VISU_ERROR_ISOSURFACES, VISU_ERROR_FORMAT, _("Line %d doesn't match the [int > 3, ...]" " required pattern."), line_number); g_string_free(current_line, TRUE); g_io_channel_unref(surf_file); g_object_unref(box); g_free(label); g_array_unref(polys); return TRUE; } poly.indices[nvertex_i] -= 1; nvertex_i += 1; if (nvertex_i >= poly.nvertices) break; } g_strfreev(split_line); g_array_append_val(polys, poly); } points = g_array_sized_new(FALSE, FALSE, sizeof(VisuSurfacePoint), surf_npoints); for(j = 0; j < surf_npoints; j++) { VisuSurfacePoint point; *error = (GError*)0; io_status = g_io_channel_read_line_string(surf_file, current_line, NULL, error); if(io_status != G_IO_STATUS_NORMAL) { g_string_free(current_line, TRUE); g_io_channel_unref(surf_file); g_object_unref(box); g_free(label); g_array_unref(polys); g_array_unref(points); return TRUE; } line_number++; if(sscanf(current_line->str, "%lf %lf %lf %lf %lf %lf", point.at, point.at + 1, point.at + 2, point.normal, point.normal + 1, point.normal + 2) != 6) { *error = g_error_new(VISU_ERROR_ISOSURFACES, VISU_ERROR_FORMAT, _("Line %d doesn't match the [float x 6]" " required pattern."), line_number); g_string_free(current_line, TRUE); g_io_channel_unref(surf_file); g_object_unref(box); g_free(label); g_array_unref(polys); g_array_unref(points); return TRUE; } npoints_loaded++; g_array_append_val(points, point); } surface = visu_surface_new(label, points, polys); visu_surface_setBox(VISU_BOXED(surface), box); if (densityValue != G_MAXFLOAT) { /* Create a table to store the density values. */ densityData = visu_surface_addPropertyFloat(surface, VISU_SURFACE_PROPERTY_POTENTIAL); densityData[0] = densityValue; } g_free(label); g_array_unref(points); g_array_unref(polys); *surf = g_list_append(*surf, surface); } g_object_unref(box); g_string_free(current_line, TRUE); g_io_channel_unref(surf_file); return TRUE; } static void onMasking(VisuPlaneSet *mask, VisuSurface *data) { gboolean redraw; DBG_fprintf(stderr, "Isosurfaces: compute masked polygons" " for surface %p.\n", (gpointer)data); if (mask && !visu_plane_set_getHiddingStatus(mask)) return; /* Free previous volatile points. */ visu_surface_points_free(&data->priv->volatilePlanes); redraw = visu_surface_points_hide(&data->priv->basePoints, (const VisuSurfaceResource*)data->priv->resource, &data->priv->volatilePlanes, mask); #if DEBUG == 1 visu_surface_checkConsistency(data); #endif if (redraw) g_signal_emit(G_OBJECT(data), surfaces_signals[SURFACE_MASKED_SIGNAL], 0, NULL); } static void onMaskable(VisuSurfaceResource *res _U_, GParamSpec *param _U_, VisuSurface *data) { if (data->priv->mask) onMasking(data->priv->mask, data); } /** * visu_surface_getResource: * @surf: the surface object ; * * This returns the resource of the @surf. * * Since: 3.7 * * Returns: (transfer none): the resource of the surface or NULL, if * @i is invalid. */ VisuSurfaceResource* visu_surface_getResource(VisuSurface *surf) { g_return_val_if_fail(VISU_IS_SURFACE(surf), (VisuSurfaceResource*)0); return surf->priv->resource; } static gboolean _setResource(VisuSurface *surf, VisuSurfaceResource *res) { g_return_val_if_fail(VISU_IS_SURFACE(surf), FALSE); if (surf->priv->resource == res) return FALSE; if (surf->priv->resource) { g_signal_handler_disconnect(G_OBJECT(surf->priv->resource), surf->priv->maskable_signal); g_object_unref(G_OBJECT(surf->priv->resource)); } DBG_fprintf(stderr, "VisuSurface: set resource %p (%s) to surface.\n", (gpointer)res, (res) ? visu_surface_resource_getLabel(res) : NULL); surf->priv->resource = res; if (surf->priv->resource) { g_object_ref(surf->priv->resource); surf->priv->maskable_signal = g_signal_connect(G_OBJECT(surf->priv->resource), "notify::maskable", G_CALLBACK(onMaskable), (gpointer)surf); } return TRUE; } /** * visu_surface_setResource: * @surf: the surface object ; * @res: the new resource. * * This method is used to change the resource of a surface. * * Returns: TRUE if the resource is changed. */ gboolean visu_surface_setResource(VisuSurface *surf, VisuSurfaceResource *res) { g_return_val_if_fail(res, FALSE); if (_setResource(surf, res)) { g_object_notify_by_pspec(G_OBJECT(surf), properties[RESOURCE_PROP]); return TRUE; } return FALSE; } /** * visu_surface_setMask: * @surface: a #VisuSurface object. * @mask: (allow-none): a #VisuPlaneSet object. * * Use @mask to hide portion of @surface (when maskable, depending on * their resources). Set @mask to %NULL to remove the mask. * * Since: 3.8 * * Returns: TRUE if mask is changed. **/ gboolean visu_surface_setMask(VisuSurface *surface, VisuPlaneSet *mask) { g_return_val_if_fail(VISU_IS_SURFACE(surface), FALSE); if (surface->priv->mask == mask) return FALSE; if (surface->priv->mask) { g_signal_handler_disconnect(G_OBJECT(surface->priv->mask), surface->priv->masking_signal); g_object_unref(surface->priv->mask); } surface->priv->mask = mask; if (surface->priv->mask) { g_object_ref(surface->priv->mask); surface->priv->masking_signal = g_signal_connect(G_OBJECT(surface->priv->mask), "masking-dirty", G_CALLBACK(onMasking), (gpointer)surface); } /* Apply (or remove) masking immediately. */ onMasking(surface->priv->mask, surface); return TRUE; } static double z_eye(const float mat[16], const float points[3]) { return (mat[ 2]*points[0]+ mat[ 6]*points[1]+ mat[10]*points[2]+ mat[14]*1.)/ (mat[ 3]*points[0]+ mat[ 7]*points[1]+ mat[11]*points[2]+ mat[15]*1.); } static gboolean _nextPoints(VisuSurfaceIterPoly *iter) { g_return_val_if_fail(iter && iter->surf, FALSE); if (!iter->valid && iter->points == &iter->surf->priv->basePoints) { iter->points = &iter->surf->priv->volatilePlanes; iter->i = 0; iter->valid = (iter->i < iter->points->num_polys); return !iter->valid; } return FALSE; } /** * visu_surface_iter_poly_new: * @surf: a #VisuSurface object. * @iter: (out caller-allocates): a #VisuSurfaceIterPoly structure. * * Setup a new @iter to iterate on drawn polygons of @surf. * * Since: 3.8 **/ void visu_surface_iter_poly_new(VisuSurface *surf, VisuSurfaceIterPoly *iter) { g_return_if_fail(iter); iter->valid = FALSE; iter->surf = (VisuSurface*)0; iter->points = (VisuSurfacePoints*)0; g_return_if_fail(VISU_IS_SURFACE(surf)); iter->surf = surf; iter->points = &surf->priv->basePoints; iter->i = 0; iter->valid = (iter->i < iter->points->num_polys); while (_nextPoints(iter)); } /** * visu_surface_iter_poly_next: * @iter: a #VisuSurfaceIterPoly structure. * * Iterate to the next drawn polygon. * * Since: 3.8 **/ void visu_surface_iter_poly_next(VisuSurfaceIterPoly *iter) { g_return_if_fail(iter && iter->points); iter->i += 1; iter->valid = (iter->i < iter->points->num_polys); while (_nextPoints(iter)); } /** * visu_surface_iter_poly_getZ: * @iter: a #VisuSurfaceIterPoly structure. * @z: (out): a location to store double. * @mat: a transformation matrix to go into viewport basis. * * Retrieve the @z value in the viewport basis of the drawn polygon * defined by @iter. If the polygon is not drawn, @z is not computed. * * Return: TRUE if polygon defined by @iter is drawn and z is computed * * Since: 3.8 **/ gboolean visu_surface_iter_poly_getZ(const VisuSurfaceIterPoly *iter, double *z, const float mat[16]) { guint j; g_return_val_if_fail(iter && iter->points && z, FALSE); g_return_val_if_fail(iter->valid, FALSE); g_return_val_if_fail(iter->points->poly_surf_index[iter->i], FALSE); if (iter->points->poly_surf_index[iter->i] <= 0 || !visu_surface_resource_getRendered(iter->surf->priv->resource)) return FALSE; *z = 0.; for (j = 0; j < iter->points->poly_num_vertices[iter->i]; j++) *z += z_eye(mat, iter->points->poly_points_data[iter->points->poly_vertices[iter->i][j]]); *z /= (double)iter->points->poly_num_vertices[iter->i]; return TRUE; } /** * visu_surface_iter_poly_getVertices: * @iter: a #VisuSurfaceIterPoly structure. * @vertices: (element-type VisuSurfacePoint): an array to store the vertex * coordinates and normals. * * Retrieve the position and normal of the point refered by @iter. * * Since: 3.8 **/ void visu_surface_iter_poly_getVertices(const VisuSurfaceIterPoly *iter, GArray *vertices) { guint j; guint *pvertices; VisuSurfacePoint vert; g_return_if_fail(iter && iter->points); g_return_if_fail(iter->valid); g_return_if_fail(iter->i < iter->points->num_polys); g_return_if_fail(vertices); pvertices = iter->points->poly_vertices[iter->i]; g_array_set_size(vertices, 0); for (j = 0; j < iter->points->poly_num_vertices[iter->i]; j++ ) { vert.at[0] = iter->points->poly_points_data[pvertices[j]][0]; vert.at[1] = iter->points->poly_points_data[pvertices[j]][1]; vert.at[2] = iter->points->poly_points_data[pvertices[j]][2]; vert.normal[0] = iter->points->poly_points_data[pvertices[j]][0 + VISU_SURFACE_POINTS_OFFSET_NORMAL]; vert.normal[1] = iter->points->poly_points_data[pvertices[j]][1 + VISU_SURFACE_POINTS_OFFSET_NORMAL]; vert.normal[2] = iter->points->poly_points_data[pvertices[j]][2 + VISU_SURFACE_POINTS_OFFSET_NORMAL]; g_array_append_val(vertices, vert); } } v_sim-3.8.0/src/extraFunctions/surfaces.h000066400000000000000000000145411370110300500204210ustar00rootroot00000000000000/* EXTRAITS DE LA LICENCE Copyright CEA, contributeurs : Luc BILLARD, Damien CALISTE, Olivier D'Astier, laboratoire L_Sim, (2001-2016) Adresse mèl : BILLARD, non joignable par mèl ; CALISTE, damien P caliste AT cea P fr. D'ASTIER, dastier AT iie P cnam P fr. Ce logiciel est un programme informatique servant à visualiser des structures atomiques dans un rendu pseudo-3D. Ce logiciel est régi par la licence CeCILL soumise au droit français et respectant les principes de diffusion des logiciels libres. Vous pouvez utiliser, modifier et/ou redistribuer ce programme sous les conditions de la licence CeCILL telle que diffusée par le CEA, le CNRS et l'INRIA sur le site "http://www.cecill.info". Le fait que vous puissiez accéder à cet en-tête signifie que vous avez pris connaissance de la licence CeCILL, et que vous en avez accepté les termes (cf. le fichier Documentation/licence.fr.txt fourni avec ce logiciel). */ /* LICENCE SUM UP Copyright CEA, contributors : Luc BILLARD and Damien CALISTE and Olivier D'Astier, laboratoire L_Sim, (2001-2016) E-mail addresses : BILLARD, not reachable any more ; CALISTE, damien P caliste AT cea P fr. D'ASTIER, dastier AT iie P cnam P fr. This software is a computer program whose purpose is to visualize atomic configurations in 3D. This software is governed by the CeCILL license under French law and abiding by the rules of distribution of free software. You can use, modify and/ or redistribute the software under the terms of the CeCILL license as circulated by CEA, CNRS and INRIA at the following URL "http://www.cecill.info". The fact that you are presently reading this means that you have had knowledge of the CeCILL license and that you accept its terms. You can find a copy of this licence shipped with this software at Documentation/licence.en.txt. */ #ifndef SURFACES_H #define SURFACES_H #include #include #include "surfaces_points.h" #include #include #include G_BEGIN_DECLS /** * VISU_TYPE_SURFACE: * * return the type of #VisuSurface. */ #define VISU_TYPE_SURFACE (visu_surface_get_type ()) /** * SURFACES: * @obj: a #GObject to cast. * * Cast the given @obj into #VisuSurface type. */ #define VISU_SURFACE(obj) (G_TYPE_CHECK_INSTANCE_CAST(obj, VISU_TYPE_SURFACE, VisuSurface)) /** * VISU_SURFACE_CLASS: * @klass: a #GObjectClass to cast. * * Cast the given @klass into #VisuSurfaceClass. */ #define VISU_SURFACE_CLASS(klass) (G_TYPE_CHECK_CLASS_CAST(klass, VISU_TYPE_SURFACE, VisuSurfaceClass)) /** * VISU_IS_SURFACE: * @obj: a #GObject to test. * * Test if the given @ogj is of the type of #VisuSurface object. */ #define VISU_IS_SURFACE(obj) (G_TYPE_CHECK_INSTANCE_TYPE(obj, VISU_TYPE_SURFACE)) /** * VISU_IS_SURFACE_CLASS: * @klass: a #GObjectClass to test. * * Test if the given @klass is of the type of #VisuSurfaceClass class. */ #define VISU_IS_SURFACE_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE(klass, VISU_TYPE_SURFACE)) /** * VISU_SURFACE_GET_CLASS: * @obj: a #GObject to get the class of. * * It returns the class of the given @obj. */ #define VISU_SURFACE_GET_CLASS(obj) (G_TYPE_INSTANCE_GET_CLASS(obj, VISU_TYPE_SURFACE, VisuSurfaceClass)) typedef struct _VisuSurfaceClass VisuSurfaceClass; typedef struct _VisuSurface VisuSurface; typedef struct _VisuSurfacePrivate VisuSurfacePrivate; /** * visu_surface_get_type: * * This method returns the type of #VisuSurface, use VISU_TYPE_SURFACE instead. * * Returns: the type of #VisuSurface. */ GType visu_surface_get_type(void); /** * VisuSurface: * * All fields are private, use the access routines. */ struct _VisuSurface { VisuObject parent; VisuSurfacePrivate *priv; }; /** * VisuSurfaceClass: * @parent: the parent. * * An opaque structure. */ struct _VisuSurfaceClass { VisuObjectClass parent; }; /** * VISU_ERROR_ISOSURFACES: (skip) * * Internal function for error handling. */ #define VISU_ERROR_ISOSURFACES visu_surface_getErrorQuark() GQuark visu_surface_getErrorQuark(void); enum { VISU_ERROR_FORMAT, VISU_ERROR_CHECKSUM }; /** * VISU_SURFACE_PROPERTY_POTENTIAL * * Flag used in an ASCII surf file to give informations on the value * the surface is built from. */ #define VISU_SURFACE_PROPERTY_POTENTIAL "potential_values" #define VISU_TYPE_SURFACE_DEFINITION (visu_surface_definition_get_type()) GType visu_surface_definition_get_type(void); typedef struct _VisuSurfaceDefinition VisuSurfaceDefinition; struct _VisuSurfaceDefinition { GArray *points; GArray *polys; }; /* Some constructors, destructors. */ VisuSurface* visu_surface_new(const gchar *label, const GArray *points, const GArray *polys); VisuSurface* visu_surface_new_fromDefinition(const gchar *label, const VisuSurfaceDefinition *definition); gboolean visu_surface_loadFile(const char *file, GList **surf, GError **error); VisuSurfaceResource* visu_surface_getResource(VisuSurface *surf); gboolean visu_surface_setResource(VisuSurface *surf, VisuSurfaceResource *res); gboolean visu_surface_setMask(VisuSurface *surface, VisuPlaneSet *mask); /** * VisuSurfaceIterPoly: * @surf: the parent #VisuSurface. * @valid: a flag TRUE, as long as the iterator is valid. * @i: the index of the current polygon. * @points: the storage for polygons. * * Structures used to iterate on polygons of @surf. * * Since: 3.8 */ typedef struct _VisuSurfaceIterPoly VisuSurfaceIterPoly; struct _VisuSurfaceIterPoly { VisuSurface *surf; gboolean valid; guint i; /* Private */ VisuSurfacePoints *points; }; void visu_surface_iter_poly_new(VisuSurface *surf, VisuSurfaceIterPoly *iter); void visu_surface_iter_poly_next(VisuSurfaceIterPoly *iter); gboolean visu_surface_iter_poly_getZ(const VisuSurfaceIterPoly *iter, double *z, const float mat[16]); void visu_surface_iter_poly_getVertices(const VisuSurfaceIterPoly *iter, GArray *vertices); float* visu_surface_getPropertyFloat(VisuSurface *surf, const gchar *name); float* visu_surface_addPropertyFloat(VisuSurface *surf, const gchar* name); gboolean visu_surface_getPropertyValueFloat(VisuSurface *surf, const gchar *name, float *value); void visu_surface_checkConsistency(VisuSurface* surf); G_END_DECLS #endif v_sim-3.8.0/src/extraFunctions/surfaces_points.c000066400000000000000000000626471370110300500220220ustar00rootroot00000000000000/* EXTRAITS DE LA LICENCE Copyright CEA, contributeurs : Damien CALISTE, laboratoire L_Sim, (2001-2005) Adresse mèl : CALISTE, damien P caliste AT cea P fr. Ce logiciel est un programme informatique servant à visualiser des structures atomiques dans un rendu pseudo-3D. Ce logiciel est régi par la licence CeCILL soumise au droit français et respectant les principes de diffusion des logiciels libres. Vous pouvez utiliser, modifier et/ou redistribuer ce programme sous les conditions de la licence CeCILL telle que diffusée par le CEA, le CNRS et l'INRIA sur le site "http://www.cecill.info". Le fait que vous puissiez accéder à cet en-tête signifie que vous avez pris connaissance de la licence CeCILL, et que vous en avez accepté les termes (cf. le fichier Documentation/licence.fr.txt fourni avec ce logiciel). */ /* LICENCE SUM UP Copyright CEA, contributors : Damien CALISTE, laboratoire L_Sim, (2001-2005) E-mail addresses : CALISTE, damien P caliste AT cea P fr. This software is a computer program whose purpose is to visualize atomic configurations in 3D. This software is governed by the CeCILL license under French law and abiding by the rules of distribution of free software. You can use, modify and/ or redistribute the software under the terms of the CeCILL license as circulated by CEA, CNRS and INRIA at the following URL "http://www.cecill.info". The fact that you are presently reading this means that you have had knowledge of the CeCILL license and that you accept its terms. You can find a copy of this licence shipped with this software at Documentation/licence.en.txt. */ #include "surfaces_points.h" #include #include #include /** * SECTION:surfaces_points * @short_description: Define a structure to store a set of triangles * defining a surface. * * This structure is used to store and draw polyedges as a set * of XYZ points and a set of link to them. */ /** * VisuSurfacePoints: * @nsurf: number of surfaces encoded in this structure ; * @bufferSize: number of stored float in addition to coordinates and * normals ; * @num_polys: number of polygoins stored in this structure ; * @num_points: number of vertices stored in this structure ; * @num_polys_surf: number of visible polygons stored in this structure per surface ; * @poly_surf_index: gives the id of the surface for each polygon, * this value ranges from - nsurf to + nsurf. abs(id - 1) gives * the index of the surface the polygon is attached to. If values * are negative, then the polygon is currently not used ; * @poly_num_vertices: gives the number of vertices used by each polygons ; * @poly_vertices: returns the id j of the vertices of polygon i ; * @poly_points_data: vectors giving additional data of vertex i. * * This structure stores geometric description of surfaces. * Several surfaces are stored in a single structure for improved performances. */ /** * visu_surface_point_new: * @pt: (out caller-allocates): a location to a #VisuSurfacePoint structure. * @at: (array fixed-size=3): coordinates. * @normal: (array fixed-size=3): normal. * * Initialise @pt with @at and @normal. * * Since: 3.8 **/ void visu_surface_point_new(VisuSurfacePoint *pt, const double at[3], const double normal[3]) { pt->at[0] = at[0]; pt->at[1] = at[1]; pt->at[2] = at[2]; pt->normal[0] = normal[0]; pt->normal[1] = normal[1]; pt->normal[2] = normal[2]; } /** * visu_surface_points_check: * @points: a set of points. * * A debug routines to check that all pointers and size are * relevant. It should not be used outside a debug area because it can * be slow. */ void visu_surface_points_check(VisuSurfacePoints *points) { guint i, j; guint *nbPolys; /* Check the surface index. */ DBG_fprintf(stderr, " | check surface index for each polygons.\n"); for (i = 0; i < points->num_polys; i++) g_return_if_fail(ABS(points->poly_surf_index[i]) > 0 && (guint)ABS(points->poly_surf_index[i]) <= points->nsurf); /* Check vertice index. */ DBG_fprintf(stderr, " | check vertice index for each polygons.\n"); for (i = 0; i < points->num_polys; i++) for (j = 0; j < points->poly_num_vertices[i]; j++) g_return_if_fail(points->poly_vertices[i][j] < points->num_points); /* Check the number of polygons. */ nbPolys = g_malloc(sizeof(int) * points->nsurf); memset(nbPolys, 0, sizeof(int) * points->nsurf); for (i = 0; i < points->num_polys; i++) if (points->poly_surf_index[i] > 0) nbPolys[points->poly_surf_index[i] - 1] += 1; for (i = 0; i < points->nsurf; i++) { DBG_fprintf(stderr, " | %d counted %7d : stored %7d\n", i, nbPolys[i], points->num_polys_surf[i]); g_return_if_fail(nbPolys[i] == points->num_polys_surf[i]); } g_free(nbPolys); } /** * visu_surface_points_translate: * @points: a set of points. * @xyz: a given translation in cartesian coordinates. * * In devel... */ void visu_surface_points_translate(VisuSurfacePoints *points, float xyz[3]) { gboolean *verticeStatus, visibility, boundary; guint i, j; int *boundaryPolys, nBounadryPolys; g_return_if_fail(points); DBG_fprintf(stderr, "IsosurfacesPoints: translate points %p of %gx%gx%g.\n", (gpointer)points, xyz[0], xyz[1], xyz[2]); /* As for surface hide: translate and reput in the box except if the triangle has some points that have been reput in the box. */ verticeStatus = g_malloc(sizeof(gboolean) * points->num_points); /* Apply the translation and compute a translation flag for each vertice. */ for (i = 0; i < points->num_points; i++) { /* Translations are given in cartesian coordinates. */ /* points->poly_points_data[j] += xyz[j]; */ /* verticeStatus[i] = visu_plane_class_getVisibility(planes, surf->basePoints.poly_points_data[i]); */ } /* We store the id of boundary polygons. */ boundaryPolys = g_malloc(sizeof(int) * points->num_polys); nBounadryPolys = 0; /* Hide polygons. */ for (i = 0; i < points->num_polys; i++) { visibility = TRUE; boundary = FALSE; /* if (surf->resources[ABS(points->poly_surf_index[i]) - 1]->sensitiveToPlanes) */ { for (j = 0; j < points->poly_num_vertices[i]; j++) { visibility = visibility && verticeStatus[points->poly_vertices[i][j]]; boundary = boundary || verticeStatus[points->poly_vertices[i][j]]; } boundary = !visibility && boundary; } if (!visibility && points->poly_surf_index[i] > 0) { /* Hide this polygon. */ points->num_polys_surf[points->poly_surf_index[i] - 1] -= 1; points->poly_surf_index[i] = -points->poly_surf_index[i]; } else if (visibility && points->poly_surf_index[i] < 0) { /* Show this polygon. */ points->poly_surf_index[i] = -points->poly_surf_index[i]; points->num_polys_surf[points->poly_surf_index[i] - 1] += 1; } if (boundary) boundaryPolys[nBounadryPolys++] = i; } /* if (DEBUG) */ /* for (i = 0; i < surf->nsurf; i++) */ /* fprintf(stderr, , " | surface %2d -> %7d polygons\n", i, points->num_polys_surf[i]); */ /* We count the number of boundaries per surface and allocate accordingly the volatile. */ } /** * visu_surface_points_transform: * @points: a set of points. * @trans: a matrix. * * Apply @trans matrix to all vertices coordinates stored by @points. * * Since: 3.7 **/ void visu_surface_points_transform(VisuSurfacePoints *points, float trans[3][3]) { guint i; float old_poly_points[6]; g_return_if_fail(points); DBG_fprintf(stderr, " | apply change to %d points.\n", points->num_points); for (i = 0; i < points->num_points; i++) { old_poly_points[0] = points->poly_points_data[i][0]; old_poly_points[1] = points->poly_points_data[i][1]; old_poly_points[2] = points->poly_points_data[i][2]; old_poly_points[3] = points->poly_points_data[i][VISU_SURFACE_POINTS_OFFSET_NORMAL + 0]; old_poly_points[4] = points->poly_points_data[i][VISU_SURFACE_POINTS_OFFSET_NORMAL + 1]; old_poly_points[5] = points->poly_points_data[i][VISU_SURFACE_POINTS_OFFSET_NORMAL + 2]; tool_matrix_productVector(points->poly_points_data[i], trans, old_poly_points); tool_matrix_productVector(points->poly_points_data[i] + VISU_SURFACE_POINTS_OFFSET_NORMAL, trans, old_poly_points + 3); } } static void _reallocate(VisuSurfacePoints *points, const guint nPoints, const guint nPolys) { gboolean alloc; guint i; points->num_points = nPoints; if (nPoints > 0) { alloc = (points->poly_points_data == (float**)0); points->poly_points_data = g_realloc(points->poly_points_data, points->num_points * sizeof(float *)); if (alloc) points->poly_points_data[0] = (float*)0; points->poly_points_data[0] = g_realloc(points->poly_points_data[0], (VISU_SURFACE_POINTS_OFFSET_USER + points->bufferSize) * points->num_points * sizeof(float)); for(i = 1; i < points->num_points; i++) points->poly_points_data[i] = points->poly_points_data[0] + i * (VISU_SURFACE_POINTS_OFFSET_USER + points->bufferSize); } else { if (points->poly_points_data) g_free(points->poly_points_data[0]); g_free(points->poly_points_data); points->poly_points_data = (float**)0; } points->num_polys = nPolys; if (nPolys > 0) { /* for each of the num_polys polygons will contain the surf value to which it belongs */ points->poly_surf_index = g_realloc(points->poly_surf_index, points->num_polys * sizeof(int)); /* for each of the num_polys polygons will contain the number of vertices in it */ points->poly_num_vertices = g_realloc(points->poly_num_vertices, points->num_polys * sizeof(guint)); /* for each of the num_polys polygons will contain the indices of vertices in it */ points->poly_vertices = g_realloc(points->poly_vertices, points->num_polys * sizeof(int*)); } else { g_free(points->poly_surf_index); g_free(points->poly_num_vertices); g_free(points->poly_vertices); } } /** * visu_surface_points_remove: * @points: a set of points ; * @pos: an integer between 0 and points->nsurf. * * Remove the points belonging to surface number @pos. */ void visu_surface_points_remove(VisuSurfacePoints *points, guint pos) { int nPoly, nPoint; guint i, j; int iPoly, iPoint; VisuSurfacePoints tmpPoints; gboolean *usedPoints; int *switchArray; points->nsurf -= 1; if (!points->num_points) { points->num_polys_surf = g_realloc(points->num_polys_surf, points->nsurf * sizeof(int)); return; } DBG_fprintf(stderr, "IsosurfacesPoints: remove surface %d from points %p.\n", pos, (gpointer)points); g_return_if_fail(pos <= points->nsurf); /* Special case when there is only one remaining surface. */ if (points->nsurf == 0) { visu_surface_points_free(points); return; } /* Simple implementation is to create a new VisuSurfacePoints object arrays, and to copy everything, except the polygons belonging to the given pos. */ /* Count number of poly and points to remove. */ usedPoints = g_malloc(sizeof(gboolean) * points->num_points); memset(usedPoints, 0, sizeof(gboolean) * points->num_points); /* We don't use num_polys_surf since it is restricted to visible surfaces. */ nPoly = 0; for (i = 0; i < points->num_polys; i++) if ((guint)(ABS(points->poly_surf_index[i]) - 1) != pos) { nPoly += 1; for (j = 0; j < points->poly_num_vertices[i]; j++) usedPoints[points->poly_vertices[i][j]] = TRUE; } nPoint = 0; for (i = 0; i < points->num_points; i++) if (usedPoints[i]) nPoint += 1; DBG_fprintf(stderr, " | remove %d polygons and %d points.\n", points->num_polys - nPoly, points->num_points - nPoint); visu_surface_points_init(&tmpPoints, points->bufferSize); _reallocate(&tmpPoints, nPoly, nPoint); /* Copy from surf to tmpSurf. */ switchArray = g_malloc(sizeof(int) * points->num_points); iPoint = 0; for (i = 0; i < points->num_points; i++) if (usedPoints[i]) { memcpy(tmpPoints.poly_points_data[iPoint], points->poly_points_data[i], sizeof(float) * (VISU_SURFACE_POINTS_OFFSET_USER + points->bufferSize)); switchArray[i] = iPoint; iPoint += 1; if (iPoint > nPoint) { g_error("Incorrect point checksum."); } } iPoly = 0; for (i = 0; i < points->num_polys; i++) { if ((guint)(ABS(points->poly_surf_index[i]) - 1) != pos) { if (points->poly_surf_index[i] > (int)pos + 1) tmpPoints.poly_surf_index[iPoly] = points->poly_surf_index[i] - 1; else if (points->poly_surf_index[i] < -(int)pos - 1) tmpPoints.poly_surf_index[iPoly] = points->poly_surf_index[i] + 1; else tmpPoints.poly_surf_index[iPoly] = points->poly_surf_index[i]; tmpPoints.poly_num_vertices[iPoly] = points->poly_num_vertices[i]; tmpPoints.poly_vertices[iPoly] = g_malloc(sizeof(int) * tmpPoints.poly_num_vertices[iPoly]); for (j = 0; j < tmpPoints.poly_num_vertices[iPoly]; j++) tmpPoints.poly_vertices[iPoly][j] = switchArray[points->poly_vertices[i][j]]; iPoly += 1; if (iPoly > nPoly) { g_error("Incorrect polygon checksum."); } } } g_free(usedPoints); g_free(switchArray); /* Check sum. */ if (iPoly != nPoly || iPoint != nPoint) { g_error("Incorrect checksum (%d %d | %d %d).", iPoly, nPoly, iPoint, nPoint); } /* Move the number of polygons per surface. */ for (i = pos; i < points->nsurf; i++) points->num_polys_surf[i] = points->num_polys_surf[i + 1]; points->num_polys_surf = g_realloc(points->num_polys_surf, sizeof(int) * points->nsurf); /* We replace the arrays between tmpSurf and surf. */ DBG_fprintf(stderr, " | switch and free arrays.\n"); g_free(points->poly_surf_index); points->poly_surf_index = tmpPoints.poly_surf_index; g_free(points->poly_num_vertices); points->poly_num_vertices = tmpPoints.poly_num_vertices; for (i = 0; i< points->num_polys; i++) g_free(points->poly_vertices[i]); g_free(points->poly_vertices); points->poly_vertices = tmpPoints.poly_vertices; g_free(points->poly_points_data[0]); g_free(points->poly_points_data); points->poly_points_data = tmpPoints.poly_points_data; /* additionnal tuning. */ points->num_polys = nPoly; points->num_points = nPoint; } /** * visu_surface_points_free: * @points: a set of points. * * Free all allocated arrays of the given set of points. The point * structure itself is not freed. */ void visu_surface_points_free(VisuSurfacePoints *points) { guint i; if(points->num_polys == 0) return; if (points->num_polys_surf) g_free(points->num_polys_surf); if (points->poly_surf_index) g_free(points->poly_surf_index); if (points->poly_num_vertices) g_free(points->poly_num_vertices); if (points->poly_vertices) { for (i = 0; i < points->num_polys; i++) g_free(points->poly_vertices[i]); g_free(points->poly_vertices); } if (points->poly_points_data) { g_free(points->poly_points_data[0]); g_free(points->poly_points_data); } points->nsurf = 0; points->num_polys = 0; points->num_points = 0; points->num_polys_surf = (guint*)0; points->poly_surf_index = (int*)0; points->poly_num_vertices = (guint*)0; points->poly_vertices = (guint**)0; points->poly_points_data = (float **)0; } /** * visu_surface_points_init: * @points: a pointer on a set of points (not initialised) ; * @bufferSize: the number of additional data to coordinates and * normals. * * Initialise a VisuSurfacePoints structure. It must be done before any use. */ void visu_surface_points_init(VisuSurfacePoints *points, int bufferSize) { g_return_if_fail(bufferSize >= 0 && points); DBG_fprintf(stderr, "Surfaces Points: initialise point definitions (%p-%d).\n", (gpointer)points, bufferSize); points->nsurf = 0; points->num_polys = 0; points->num_points = 0; points->bufferSize = bufferSize; points->num_polys_surf = (guint*)0; points->poly_surf_index = (int*)0; points->poly_num_vertices = (guint*)0; points->poly_vertices = (guint**)0; points->poly_points_data = (float **)0; } /** * visu_surface_points_addPoly: * @points: a #VisuSurfacePoints object. * @vertices: (element-type VisuSurfacePoint): a set of #VisuSurfacePoint. * @polys: (element-type VisuSurfacePoly): a set of #VisuSurfacePoly. * * Add a new surface in @points with the given definition of @vertices * and @polys. * * Since: 3.8 **/ void visu_surface_points_addPoly(VisuSurfacePoints *points, const GArray *vertices, const GArray *polys) { guint i, n, old_num_points, old_num_polys; float *fval; VisuSurfacePoint *point; VisuSurfacePoly *poly; g_return_if_fail(points); points->nsurf += 1; points->num_polys_surf = g_realloc(points->num_polys_surf, points->nsurf * sizeof(int)); points->num_polys_surf[points->nsurf - 1] = (polys) ? polys->len : 0; if (!vertices || !vertices->len || !polys || !polys->len) return; old_num_points = points->num_points; old_num_polys = points->num_polys; _reallocate(points, points->num_points + vertices->len, points->num_polys + polys->len); DBG_fprintf(stderr, " | copy vertices.\n"); for (n = 0; n < vertices->len; n++) { fval = points->poly_points_data[old_num_points + n]; point = &g_array_index(vertices, VisuSurfacePoint, n); fval[0] = point->at[0]; fval[1] = point->at[1]; fval[2] = point->at[2]; fval[VISU_SURFACE_POINTS_OFFSET_NORMAL + 0] = -point->normal[0]; fval[VISU_SURFACE_POINTS_OFFSET_NORMAL + 1] = -point->normal[1]; fval[VISU_SURFACE_POINTS_OFFSET_NORMAL + 2] = -point->normal[2]; } DBG_fprintf(stderr, " | copy poly.\n"); for (n = 0; n < polys->len; n++) { poly = &g_array_index(polys, VisuSurfacePoly, n); points->poly_surf_index[old_num_polys + n] = points->nsurf; points->poly_num_vertices[old_num_polys + n] = poly->nvertices; points->poly_vertices[old_num_polys + n] = g_malloc(sizeof(int) * poly->nvertices); for (i = 0; i < poly->nvertices; i++) points->poly_vertices[old_num_polys + n][poly->nvertices - i - 1] = poly->indices[i] + old_num_points; } } /** * visu_surface_points_hide: * @points: a #VisuSurfacePoints object. * @resource: a #VisuSurfaceResource object. * @edges: (out caller-allocates): a #VisuSurfacePoints location. * @planes: a #VisuPlaneSet object. * * Apply the masking properties of @planes on @points, creating * additional vertices and polygons to smooth the edges of the cut * surface in @edges. * * Since: 3.8 * * Returns: TRUE if some polygons of @points have changed visibility. **/ gboolean visu_surface_points_hide(VisuSurfacePoints *points, const VisuSurfaceResource *resource, VisuSurfacePoints *edges, const VisuPlaneSet *planes) { guint i, j, iv; int k, iPoly, isurf, iVertice, n; gboolean *verticeStatus; gboolean visibility, redraw, boundary, valid; int *boundaryPolys; guint nBounadryPolys; int npolys, npoints; g_return_val_if_fail(points && edges, FALSE); if (!planes) { for (i = 0; i < points->num_polys; i++) points->poly_surf_index[i] = ABS(points->poly_surf_index[i]); points->num_polys_surf[0] = points->num_polys; return TRUE; } verticeStatus = g_malloc(sizeof(gboolean) * points->num_points); redraw = FALSE; /* Compute a visibility flag for each vertice. */ for (i = 0; i < points->num_points; i++) verticeStatus[i] = visu_plane_set_getVisibility(planes, points->poly_points_data[i]); /* We store the id of boundary polygons. */ boundaryPolys = g_malloc(sizeof(int) * points->num_polys); nBounadryPolys = 0; /* Hide polygons. */ for (i = 0; i < points->num_polys; i++) { visibility = TRUE; boundary = FALSE; if (visu_surface_resource_getMaskable(resource)) { for (j = 0; j < points->poly_num_vertices[i]; j++) { visibility = visibility && verticeStatus[points->poly_vertices[i][j]]; boundary = boundary || verticeStatus[points->poly_vertices[i][j]]; } boundary = !visibility && boundary; } if (!visibility && points->poly_surf_index[i] > 0) { /* Hide this polygon. */ points->num_polys_surf[points->poly_surf_index[i] - 1] -= 1; points->poly_surf_index[i] = -points->poly_surf_index[i]; redraw = TRUE; } else if (visibility && points->poly_surf_index[i] < 0) { /* Show this polygon. */ points->poly_surf_index[i] = -points->poly_surf_index[i]; points->num_polys_surf[points->poly_surf_index[i] - 1] += 1; redraw = TRUE; } if (boundary) boundaryPolys[nBounadryPolys++] = i; } if (DEBUG) for (i = 0; i < points->nsurf; i++) fprintf(stderr, " | surface %2d -> %7d polygons\n", i, points->num_polys_surf[i]); /* We count the number of boundaries per surface and allocate accordingly the volatile. */ npolys = nBounadryPolys; npoints = 0; for (i = 0; i < nBounadryPolys; i++) { /* The number of points to add is the number of visible points plus 2. */ npoints += 2; for (j = 0; j < points->poly_num_vertices[boundaryPolys[i]]; j++) if (verticeStatus[points->poly_vertices[boundaryPolys[i]][j]]) npoints += 1; } DBG_fprintf(stderr, "Isosurfaces: volatile polygons.\n"); DBG_fprintf(stderr, " | polys %d, points %d\n", npolys, npoints); _reallocate(edges, npoints, npolys); edges->nsurf = points->nsurf; edges->num_polys_surf = g_realloc(edges->num_polys_surf, edges->nsurf * sizeof(int)); for (i = 0; i < edges->nsurf; i++) edges->num_polys_surf[i] = 0; edges->num_polys = 0; edges->num_points = 0; /* We copy the polygons and the vertices in the volatile part. */ for (i = 0; i < nBounadryPolys; i++) { isurf = -points->poly_surf_index[boundaryPolys[i]] - 1; iPoly = edges->num_polys; iVertice = edges->num_points; edges->num_polys_surf[isurf] += 1; edges->poly_surf_index[iPoly] = (int)isurf + 1; n = 2; for (j = 0; j < points->poly_num_vertices[boundaryPolys[i]]; j++) if (verticeStatus[points->poly_vertices[boundaryPolys[i]][j]]) n += 1; edges->poly_num_vertices[iPoly] = n; edges->poly_vertices[iPoly] = g_malloc(sizeof(int) * n); n = points->poly_num_vertices[boundaryPolys[i]]; /* Compute new vertex. */ iv = 0; for (k = 0; k < n; k++) { /* If vertex is visible, we put it. */ if (verticeStatus[points->poly_vertices[boundaryPolys[i]][k]]) { memcpy(edges->poly_points_data[iVertice], points->poly_points_data[points->poly_vertices[boundaryPolys[i]][k]], sizeof(float) * (VISU_SURFACE_POINTS_OFFSET_USER + edges->bufferSize)); g_return_val_if_fail(iv < edges->poly_num_vertices[iPoly], redraw); edges->poly_vertices[iPoly][iv] = iVertice; iVertice += 1; iv += 1; } /* If next vertex brings a visibility change, we compute intersection. */ if ((!verticeStatus[points->poly_vertices[boundaryPolys[i]][k]] && verticeStatus[points->poly_vertices[boundaryPolys[i]][(k + 1)%n]])) { /* We take the previous and compute the intersection. */ valid = visu_plane_set_getIntersection (planes, points->poly_points_data[points->poly_vertices[boundaryPolys[i]][(k + 1)%n]], points->poly_points_data[points->poly_vertices[boundaryPolys[i]][k]], edges->poly_points_data[iVertice], TRUE); g_return_val_if_fail(valid, redraw); /* Other values than coordinates are copied. */ memcpy(edges->poly_points_data[iVertice] + 3, points->poly_points_data[points->poly_vertices[boundaryPolys[i]][(k + 1)%n]] + 3, sizeof(float) * (VISU_SURFACE_POINTS_OFFSET_USER + edges->bufferSize - 3)); g_return_val_if_fail(iv < edges->poly_num_vertices[iPoly], redraw); edges->poly_vertices[iPoly][iv] = iVertice; iVertice += 1; iv += 1; } if ((verticeStatus[points->poly_vertices[boundaryPolys[i]][k]] && !verticeStatus[points->poly_vertices[boundaryPolys[i]][(k + 1)%n]])) { /* We take the previous and compute the intersection. */ valid = visu_plane_set_getIntersection (planes, points->poly_points_data[points->poly_vertices[boundaryPolys[i]][k]], points->poly_points_data[points->poly_vertices[boundaryPolys[i]][(k + 1)%n]], edges->poly_points_data[iVertice], TRUE); g_return_val_if_fail(valid, redraw); memcpy(edges->poly_points_data[iVertice] + 3, points->poly_points_data[points->poly_vertices[boundaryPolys[i]][k]] + 3, sizeof(float) * (VISU_SURFACE_POINTS_OFFSET_USER + edges->bufferSize - 3)); g_return_val_if_fail(iv < edges->poly_num_vertices[iPoly], redraw); edges->poly_vertices[iPoly][iv] = iVertice; iVertice += 1; iv += 1; } } edges->num_polys += 1; edges->num_points = iVertice; } g_free(verticeStatus); g_free(boundaryPolys); return redraw; } v_sim-3.8.0/src/extraFunctions/surfaces_points.h000066400000000000000000000114721370110300500220150ustar00rootroot00000000000000/* EXTRAITS DE LA LICENCE Copyright CEA, contributeurs : Damien CALISTE, laboratoire L_Sim, (2001-2005) Adresse mèl : CALISTE, damien P caliste AT cea P fr. Ce logiciel est un programme informatique servant à visualiser des structures atomiques dans un rendu pseudo-3D. Ce logiciel est régi par la licence CeCILL soumise au droit français et respectant les principes de diffusion des logiciels libres. Vous pouvez utiliser, modifier et/ou redistribuer ce programme sous les conditions de la licence CeCILL telle que diffusée par le CEA, le CNRS et l'INRIA sur le site "http://www.cecill.info". Le fait que vous puissiez accéder à cet en-tête signifie que vous avez pris connaissance de la licence CeCILL, et que vous en avez accepté les termes (cf. le fichier Documentation/licence.fr.txt fourni avec ce logiciel). */ /* LICENCE SUM UP Copyright CEA, contributors : Damien CALISTE, laboratoire L_Sim, (2001-2005) E-mail addresses : CALISTE, damien P caliste AT cea P fr. This software is a computer program whose purpose is to visualize atomic configurations in 3D. This software is governed by the CeCILL license under French law and abiding by the rules of distribution of free software. You can use, modify and/ or redistribute the software under the terms of the CeCILL license as circulated by CEA, CNRS and INRIA at the following URL "http://www.cecill.info". The fact that you are presently reading this means that you have had knowledge of the CeCILL license and that you accept its terms. You can find a copy of this licence shipped with this software at Documentation/licence.en.txt. */ #ifndef SURFACES_POINTS_H #define SURFACES_POINTS_H #include #include "surfaces_resources.h" #include "planeset.h" /** * VISU_SURFACE_POINTS_OFFSET_NORMAL: * * The offset to read the normal values in poly_points. */ #define VISU_SURFACE_POINTS_OFFSET_NORMAL 3 /** * VISU_SURFACE_POINTS_OFFSET_TRANSLATION: * * The offset to read the translation values in poly_points. */ #define VISU_SURFACE_POINTS_OFFSET_TRANSLATION 6 /** * VISU_SURFACE_POINTS_OFFSET_USER: * * The offset to read the user values in poly_points. */ #define VISU_SURFACE_POINTS_OFFSET_USER 9 typedef struct _VisuSurfacePoints VisuSurfacePoints; struct _VisuSurfacePoints { /* Number of different surfaces. */ guint nsurf; /* This is the size of additional data on each points in addition to (x,y,z) coordinates, normal and translation. Then poly_points is allocated to (num_points * (9 + bufferSize)). */ guint bufferSize; /* Number of polygons */ guint num_polys, num_points; /* Number of polygons per surface. */ guint *num_polys_surf; /* Give the number of the surface when the number of the polygon is given. */ int *poly_surf_index; /* Return the number of vertices when the id of the polygon is given. */ guint *poly_num_vertices; /* Return the id in poly_points_data of the vertice j of polygon i. */ guint **poly_vertices; /* Vectors giving points and normal of the vertice i. */ float **poly_points_data; }; /** * VisuSurfacePoint: * @at: coordinates of the point. * @normal: normal vector at the point. * * Structure used to access a point coordinates and normal in a #VisuSurface. * * Since: 3.8 */ typedef struct _VisuSurfacePoint VisuSurfacePoint; struct _VisuSurfacePoint { double at[3]; double normal[3]; }; void visu_surface_point_new(VisuSurfacePoint *pt, const double at[3], const double normal[3]); /** * VISU_SURFACE_POINTS_MAX_VERTICES: * * Size used in #VisuSurfacePoly structure. * * Since: 3.8 */ #define VISU_SURFACE_POINTS_MAX_VERTICES 10 /** * VisuSurfacePoly: * @nvertices: number of vrtice for this polygon. * @indices: point indices for the various vertices. * * Structure used to access a polygon definition in a #VisuSurface. * * Since: 3.8 */ typedef struct _VisuSurfacePoly VisuSurfacePoly; struct _VisuSurfacePoly { guint nvertices; guint indices[VISU_SURFACE_POINTS_MAX_VERTICES]; }; void visu_surface_points_init(VisuSurfacePoints *points, int bufferSize); void visu_surface_points_addPoly(VisuSurfacePoints *points, const GArray *vertices, const GArray *polys); void visu_surface_points_free(VisuSurfacePoints *points); void visu_surface_points_remove(VisuSurfacePoints *points, guint pos); void visu_surface_points_translate(VisuSurfacePoints *points, float xyz[3]); void visu_surface_points_transform(VisuSurfacePoints *points, float trans[3][3]); gboolean visu_surface_points_hide(VisuSurfacePoints *points, const VisuSurfaceResource *resource, VisuSurfacePoints *edges, const VisuPlaneSet *planes); void visu_surface_points_check(VisuSurfacePoints *points); #endif v_sim-3.8.0/src/extraFunctions/surfaces_resources.c000066400000000000000000000510531370110300500225050ustar00rootroot00000000000000/* EXTRAITS DE LA LICENCE Copyright CEA, contributeurs : Luc BILLARD, Damien CALISTE, Olivier D'Astier, laboratoire L_Sim, (2001-2005) Adresse mèl : BILLARD, non joignable par mèl ; CALISTE, damien P caliste AT cea P fr. D'ASTIER, dastier AT iie P cnam P fr. Ce logiciel est un programme informatique servant à visualiser des structures atomiques dans un rendu pseudo-3D. Ce logiciel est régi par la licence CeCILL soumise au droit français et respectant les principes de diffusion des logiciels libres. Vous pouvez utiliser, modifier et/ou redistribuer ce programme sous les conditions de la licence CeCILL telle que diffusée par le CEA, le CNRS et l'INRIA sur le site "http://www.cecill.info". Le fait que vous puissiez accéder à cet en-tête signifie que vous avez pris connaissance de la licence CeCILL, et que vous en avez accepté les termes (cf. le fichier Documentation/licence.fr.txt fourni avec ce logiciel). */ /* LICENCE SUM UP Copyright CEA, contributors : Luc BILLARD and Damien CALISTE and Olivier D'Astier, laboratoire L_Sim, (2001-2005) E-mail addresses : BILLARD, not reachable any more ; CALISTE, damien P caliste AT cea P fr. D'ASTIER, dastier AT iie P cnam P fr. This software is a computer program whose purpose is to visualize atomic configurations in 3D. This software is governed by the CeCILL license under French law and abiding by the rules of distribution of free software. You can use, modify and/ or redistribute the software under the terms of the CeCILL license as circulated by CEA, CNRS and INRIA at the following URL "http://www.cecill.info". The fact that you are presently reading this means that you have had knowledge of the CeCILL license and that you accept its terms. You can find a copy of this licence shipped with this software at Documentation/licence.en.txt. */ #include "surfaces_resources.h" #include #include #include #include /** * SECTION:surfaces_resources * @short_description: Define the rendering parameters of a surface. * * This structure stores all the rendering elements of a set of #VisuSurface. */ /** * VisuSurfaceResource: * @label: the name of the surface (in UTF-8) ; * @color: a #ToolColor for the surface ; * @material: the lighting effects of the surface ; * @rendered: boolean for the visibility of the surface ; * @sensitiveToPlanes: boolean for the sensitivity of a surface * to the masking effect of planes. * * This structure defines some drawing properties of a set of #VisuSurface. */ struct _VisuSurfaceResourcePrivate { /* Name used to label the surface. */ gchar *label; /* ToolMaterialIds used to draw a specific surface. */ ToolColor color; float material[TOOL_MATERIAL_N_VALUES]; /* Rendered or not */ gboolean rendered; /* Sensitive to masking properties of planes. */ gboolean sensitiveToPlanes; }; #define DESC_RESOURCE_COLOR "Define the colour of one surface ;" \ " 4 floats (RGBA) 5 floats (material)" #define FLAG_RESOURCE_COLOR "isosurface_color" static gfloat _colorMat[9]; #define DESC_RESOURCE_PROPERTIES "Define some surface properties ;" \ " rendered (0 or 1) sensitive to planes (0 or 1)" #define FLAG_RESOURCE_PROPERTIES "isosurface_properties" static gboolean _prop[2]; /* Local variables. */ static GHashTable *isosurfaces_resources = NULL; /* Local methods. */ static void isosurfaces_export_resources(GString *data, VisuData *dataObj); static void onEntryColor(VisuConfigFile *obj, VisuConfigFileEntry *entry, gpointer data); static void onEntryProperties(VisuConfigFile *obj, VisuConfigFileEntry *entry, gpointer data); enum { PROP_0, LABEL_PROP, COLOR_PROP, MATERIAL_PROP, RENDERED_PROP, MASKING_PROP, N_PROP }; static GParamSpec *properties[N_PROP]; static void visu_surface_resource_finalize (GObject* obj); static void visu_surface_resource_get_property(GObject* obj, guint property_id, GValue *value, GParamSpec *pspec); static void visu_surface_resource_set_property(GObject* obj, guint property_id, const GValue *value, GParamSpec *pspec); G_DEFINE_TYPE_WITH_CODE(VisuSurfaceResource, visu_surface_resource, VISU_TYPE_OBJECT, G_ADD_PRIVATE(VisuSurfaceResource)) static void visu_surface_resource_class_init(VisuSurfaceResourceClass *klass) { VisuConfigFileEntry *entry, *oldEntry; gfloat rgColor[2] = {0.f, 1.f}; DBG_fprintf(stderr, "Surface Resource: creating the class of the object.\n"); /* DBG_fprintf(stderr, " - adding new signals ;\n"); */ /* Connect the overloading methods. */ G_OBJECT_CLASS(klass)->finalize = visu_surface_resource_finalize; G_OBJECT_CLASS(klass)->set_property = visu_surface_resource_set_property; G_OBJECT_CLASS(klass)->get_property = visu_surface_resource_get_property; /** * VisuSurfaceResource::label: * * Label used to identify the resource. * * Since: 3.8 */ properties[LABEL_PROP] = g_param_spec_string("label", "Label", "label of the resource", NULL, G_PARAM_READWRITE | G_PARAM_CONSTRUCT_ONLY | G_PARAM_STATIC_STRINGS); g_object_class_install_property (G_OBJECT_CLASS(klass), LABEL_PROP, properties[LABEL_PROP]); /** * VisuSurfaceResource::color: * * Rendering colour. * * Since: 3.8 */ properties[COLOR_PROP] = g_param_spec_boxed("color", "Color", "rendering color", TOOL_TYPE_COLOR, G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS); g_object_class_install_property (G_OBJECT_CLASS(klass), COLOR_PROP, properties[COLOR_PROP]); /** * VisuSurfaceResource::material: * * Rendering material properties. * * Since: 3.8 */ properties[MATERIAL_PROP] = g_param_spec_boxed("material", "Material", "rendering material", TOOL_TYPE_MATERIAL, G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS); g_object_class_install_property (G_OBJECT_CLASS(klass), MATERIAL_PROP, properties[MATERIAL_PROP]); /** * VisuSurfaceResource::rendered: * * If the surface is displayed or not. * * Since: 3.8 */ properties[RENDERED_PROP] = g_param_spec_boolean("rendered", "Rendered", "rendered or not", FALSE, G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS); g_object_class_install_property (G_OBJECT_CLASS(klass), RENDERED_PROP, properties[RENDERED_PROP]); /** * VisuSurfaceResource::maskable: * * If the surface is maskable by planes or not. * * Since: 3.8 */ properties[MASKING_PROP] = g_param_spec_boolean("maskable", "Maskable", "masked or not", FALSE, G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS); g_object_class_install_property (G_OBJECT_CLASS(klass), MASKING_PROP, properties[MASKING_PROP]); /* This entry is now obsolete but is kept for backward compatibility. */ oldEntry = visu_config_file_addEntry(VISU_CONFIG_FILE_RESOURCE, "isosurface_property", "Properties of a given isosurface", 1, NULL); visu_config_file_entry_setVersion(oldEntry, 3.3f); entry = visu_config_file_addFloatArrayEntry(VISU_CONFIG_FILE_RESOURCE, FLAG_RESOURCE_COLOR, DESC_RESOURCE_COLOR, 9, _colorMat, rgColor, TRUE); visu_config_file_entry_setVersion(entry, 3.4f); visu_config_file_entry_setReplace(entry, oldEntry); g_signal_connect(VISU_CONFIG_FILE_RESOURCE, "parsed::" FLAG_RESOURCE_COLOR, G_CALLBACK(onEntryColor), (gpointer)0); entry = visu_config_file_addBooleanArrayEntry(VISU_CONFIG_FILE_RESOURCE, FLAG_RESOURCE_PROPERTIES, DESC_RESOURCE_PROPERTIES, 2, _prop, TRUE); visu_config_file_entry_setVersion(entry, 3.4f); g_signal_connect(VISU_CONFIG_FILE_RESOURCE, "parsed::" FLAG_RESOURCE_PROPERTIES, G_CALLBACK(onEntryProperties), (gpointer)0); visu_config_file_addExportFunction(VISU_CONFIG_FILE_RESOURCE, isosurfaces_export_resources); isosurfaces_resources = g_hash_table_new_full(g_str_hash, g_str_equal, NULL, g_object_unref); } static void visu_surface_resource_init(VisuSurfaceResource *res) { const float rgba[4] = {1.f, 0.5f, 0.5f, 0.75f}; DBG_fprintf(stderr, "Surface Resource: initializing a new object (%p).\n", (gpointer)res); res->priv = visu_surface_resource_get_instance_private(res); tool_color_copy(&res->priv->color, tool_color_addFloatRGBA(rgba, NULL)); res->priv->material[0] = 0.2f; res->priv->material[1] = 1.0f; res->priv->material[2] = 0.5f; res->priv->material[3] = 0.5f; res->priv->material[4] = 0.0f; res->priv->rendered = TRUE; res->priv->label = (gchar*)0; res->priv->sensitiveToPlanes = TRUE; } /* This method is called once only. */ static void visu_surface_resource_finalize(GObject* obj) { VisuSurfaceResourcePrivate *res; g_return_if_fail(obj); DBG_fprintf(stderr, "Surface Resource: finalize object %p.\n", (gpointer)obj); res = VISU_SURFACE_RESOURCE(obj)->priv; g_free(res->label); /* Chain up to the parent class */ DBG_fprintf(stderr, "Visu Plane Res: chain to parent.\n"); G_OBJECT_CLASS(visu_surface_resource_parent_class)->finalize(obj); DBG_fprintf(stderr, "Visu Plane Res: freeing ... OK.\n"); } static void visu_surface_resource_get_property(GObject* obj, guint property_id, GValue *value, GParamSpec *pspec) { VisuSurfaceResourcePrivate *self = VISU_SURFACE_RESOURCE(obj)->priv; DBG_fprintf(stderr, "Visu SurfaceResource: get property '%s' -> ", g_param_spec_get_name(pspec)); switch (property_id) { case LABEL_PROP: g_value_set_static_string(value, self->label); DBG_fprintf(stderr, "%s.\n", self->label); break; case COLOR_PROP: g_value_set_static_boxed(value, (gconstpointer)&self->color); DBG_fprintf(stderr, "%g,%g,%g.\n", self->color.rgba[0], self->color.rgba[1], self->color.rgba[2]); break; case MATERIAL_PROP: g_value_set_static_boxed(value, (gconstpointer)self->material); DBG_fprintf(stderr, "%g,%g,%g,%g,%g.\n", self->material[0], self->material[1], self->material[2], self->material[3], self->material[4]); break; case RENDERED_PROP: g_value_set_boolean(value, self->rendered); DBG_fprintf(stderr, "%d.\n", self->rendered); break; case MASKING_PROP: g_value_set_boolean(value, self->sensitiveToPlanes); DBG_fprintf(stderr, "%d.\n", self->sensitiveToPlanes); break; default: /* We don't have any other property... */ G_OBJECT_WARN_INVALID_PROPERTY_ID(obj, property_id, pspec); break; } } static void visu_surface_resource_set_property(GObject* obj, guint property_id, const GValue *value, GParamSpec *pspec) { VisuSurfaceResourcePrivate *self = VISU_SURFACE_RESOURCE(obj)->priv; float *mat; DBG_fprintf(stderr, "Visu SurfaceResource: set property '%s' -> ", g_param_spec_get_name(pspec)); switch (property_id) { case LABEL_PROP: g_free(self->label); self->label = g_value_dup_string(value); if (self->label) { g_strstrip(self->label); if (!self->label[0]) { g_free(self->label); self->label = (gchar*)0; } } DBG_fprintf(stderr, "%s.\n", self->label); break; case COLOR_PROP: tool_color_copy(&self->color, (ToolColor*)g_value_get_boxed(value)); DBG_fprintf(stderr, "%g,%g,%g (%p).\n", self->color.rgba[0], self->color.rgba[1], self->color.rgba[2], (gpointer)&self->color); break; case MATERIAL_PROP: mat = (float*)g_value_get_boxed(value); self->material[0] = mat[0]; self->material[1] = mat[1]; self->material[2] = mat[2]; self->material[3] = mat[3]; self->material[4] = mat[4]; DBG_fprintf(stderr, "%g,%g,%g,%g,%g.\n", self->material[0], self->material[1], self->material[2], self->material[3], self->material[4]); break; case RENDERED_PROP: self->rendered = g_value_get_boolean(value); DBG_fprintf(stderr, "%d.\n", self->rendered); break; case MASKING_PROP: self->sensitiveToPlanes = g_value_get_boolean(value); DBG_fprintf(stderr, "%d.\n", self->sensitiveToPlanes); break; default: /* We don't have any other property... */ G_OBJECT_WARN_INVALID_PROPERTY_ID(obj, property_id, pspec); break; } } /** * visu_surface_resource_new_fromName: * @surf_name: the name of the surface (can be NULL) ; * @new_surf: a location to store a boolean value (can be NULL). * * This returns the resource information matching the given @surf_name. If * the resource doesn't exist, it is created and @new is set to TRUE. If the given * name (@surf_name) is NULL, then a new resource is created, but it is not stored * and will not be shared by surfaces. * * Returns: (transfer full): the resource (created or retrieved). */ VisuSurfaceResource* visu_surface_resource_new_fromName(const gchar *surf_name, gboolean *nw) { VisuSurfaceResource *res; if (!isosurfaces_resources) g_type_class_ref(VISU_TYPE_SURFACE_RESOURCE); res = (VisuSurfaceResource*)0; if (surf_name && surf_name[0]) res = g_hash_table_lookup(isosurfaces_resources, surf_name); if (nw) *nw = (!res); if (res) { g_object_ref(G_OBJECT(res)); return res; } res = VISU_SURFACE_RESOURCE(g_object_new(VISU_TYPE_SURFACE_RESOURCE, "label", surf_name, NULL)); if (res->priv->label) { g_object_ref(G_OBJECT(res)); g_hash_table_insert(isosurfaces_resources, res->priv->label, res); } return res; } /** * visu_surface_resource_pool_finalize: (skip) * * Free memory allocated to store various #VisuSurfaceResource objects. * * Since: 3.8 **/ void visu_surface_resource_pool_finalize(void) { g_hash_table_destroy(isosurfaces_resources); isosurfaces_resources = (GHashTable*)0; } /** * visu_surface_resource_new_fromCopy: * @surf_name: a label. * @orig: a #VisuSurfaceResource obejct. * * Copy constructor of #VisuSurfaceResource objects. * * Since: 3.8 * * Returns: (transfer full): a newly created #VisuSurfaceResource object. **/ VisuSurfaceResource* visu_surface_resource_new_fromCopy(const gchar *surf_name, const VisuSurfaceResource *orig) { VisuSurfaceResource *res; gboolean nw; g_return_val_if_fail(VISU_IS_SURFACE_RESOURCE(orig), (VisuSurfaceResource*)0); res = visu_surface_resource_new_fromName(surf_name, &nw); if (nw) { res->priv->color = orig->priv->color; res->priv->material[0] = orig->priv->material[0]; res->priv->material[1] = orig->priv->material[1]; res->priv->material[2] = orig->priv->material[2]; res->priv->material[3] = orig->priv->material[3]; res->priv->material[4] = orig->priv->material[4]; res->priv->rendered = orig->priv->rendered; res->priv->sensitiveToPlanes = orig->priv->sensitiveToPlanes; } return res; } /** * visu_surface_resource_getLabel: * @res: a #VisuSurfaceResource object. * * Retrieves the label of @res. * * Since: 3.8 * * Returns: a string. **/ const gchar* visu_surface_resource_getLabel(const VisuSurfaceResource *res) { g_return_val_if_fail(VISU_IS_SURFACE_RESOURCE(res), (const gchar*)0); return res->priv->label; } /** * visu_surface_resource_getColor: * @res: a #VisuSurfaceResource object. * * Retrieves the color of @res. * * Since: 3.8 * * Returns: a color. **/ const ToolColor* visu_surface_resource_getColor(const VisuSurfaceResource *res) { g_return_val_if_fail(VISU_IS_SURFACE_RESOURCE(res), (const ToolColor*)0); return &res->priv->color; } /** * visu_surface_resource_getMaterial: * @res: a #VisuSurfaceResource object. * * Retrieves the material of @res. * * Since: 3.8 * * Returns: a material. **/ const float* visu_surface_resource_getMaterial(const VisuSurfaceResource *res) { g_return_val_if_fail(VISU_IS_SURFACE_RESOURCE(res), (const float*)0); return res->priv->material; } /** * visu_surface_resource_getRendered: * @res: a #VisuSurfaceResource object. * * Retrieves wether @res is drawn or not. * * Since: 3.8 * * Returns: a boolean. **/ gboolean visu_surface_resource_getRendered(const VisuSurfaceResource *res) { g_return_val_if_fail(VISU_IS_SURFACE_RESOURCE(res), FALSE); return res->priv->rendered; } /** * visu_surface_resource_getMaskable: * @res: a #VisuSurfaceResource object. * * Retrieves if @res is sensitive to masking properties. * * Since: 3.8 * * Returns: a boolean. **/ gboolean visu_surface_resource_getMaskable(const VisuSurfaceResource *res) { g_return_val_if_fail(VISU_IS_SURFACE_RESOURCE(res), FALSE); return res->priv->sensitiveToPlanes; } /******************/ /* Local methods. */ /******************/ static void onEntryColor(VisuConfigFile *obj _U_, VisuConfigFileEntry *entry, gpointer data _U_) { VisuSurfaceResource *res; ToolColor color; DBG_fprintf(stderr, "Isosurfaces Resources: resources '%s' found for surface '%s'\n", FLAG_RESOURCE_COLOR, visu_config_file_entry_getLabel(entry)); /* Read resources are always made public and added in the hashtable. */ res = visu_surface_resource_new_fromName(visu_config_file_entry_getLabel(entry), (gboolean*)0); memcpy(color.rgba, _colorMat, sizeof(gfloat) * 4); g_object_set(G_OBJECT(res), "color", &color, "material", _colorMat + 4, NULL); g_object_unref(G_OBJECT(res)); } static void onEntryProperties(VisuConfigFile *obj _U_, VisuConfigFileEntry *entry, gpointer data _U_) { VisuSurfaceResource *res; DBG_fprintf(stderr, "Surface Resource: resources '%s' found for surface '%s'\n", FLAG_RESOURCE_PROPERTIES, visu_config_file_entry_getLabel(entry)); /* Read resources are always made public and added in the hashtable. */ res = visu_surface_resource_new_fromName(visu_config_file_entry_getLabel(entry), (gboolean*)0); g_object_set(G_OBJECT(res), "rendered", _prop[0], "maskable", _prop[1], NULL); g_object_unref(G_OBJECT(res)); } static void isosurfaces_export_one_surf_resources(gpointer key, gpointer value, gpointer user_data) { VisuSurfaceResource *res; res = (VisuSurfaceResource*)value; DBG_fprintf(stderr, "Isosurfaces Resources: exporting surface '%s' properties...", (char *)key); visu_config_file_exportEntry((GString*)user_data, FLAG_RESOURCE_COLOR, (gchar *)key, "%4.3f %4.3f %4.3f %4.3f %4.2f %4.2f %4.2f %4.2f %4.2f", res->priv->color.rgba[0], res->priv->color.rgba[1], res->priv->color.rgba[2], res->priv->color.rgba[3], res->priv->material[0], res->priv->material[1], res->priv->material[2], res->priv->material[3], res->priv->material[4]); visu_config_file_exportEntry((GString*)user_data, FLAG_RESOURCE_PROPERTIES, (gchar *)key, "%d %d", res->priv->rendered, res->priv->sensitiveToPlanes); DBG_fprintf(stderr, "OK.\n"); } static void isosurfaces_export_resources(GString *data, VisuData *dataObj _U_) { if (isosurfaces_resources != NULL && g_hash_table_size(isosurfaces_resources) > 0) { visu_config_file_exportComment(data, DESC_RESOURCE_COLOR); visu_config_file_exportComment(data, DESC_RESOURCE_PROPERTIES); g_hash_table_foreach(isosurfaces_resources, isosurfaces_export_one_surf_resources, data); visu_config_file_exportComment(data, ""); } DBG_fprintf(stderr, "Isosurfaces Resources: exporting OK.\n"); } v_sim-3.8.0/src/extraFunctions/surfaces_resources.h000066400000000000000000000117731370110300500225170ustar00rootroot00000000000000/* EXTRAITS DE LA LICENCE Copyright CEA, contributeurs : Luc BILLARD, Damien CALISTE, Olivier D'Astier, laboratoire L_Sim, (2001-2005) Adresse mèl : BILLARD, non joignable par mèl ; CALISTE, damien P caliste AT cea P fr. D'ASTIER, dastier AT iie P cnam P fr. Ce logiciel est un programme informatique servant à visualiser des structures atomiques dans un rendu pseudo-3D. Ce logiciel est régi par la licence CeCILL soumise au droit français et respectant les principes de diffusion des logiciels libres. Vous pouvez utiliser, modifier et/ou redistribuer ce programme sous les conditions de la licence CeCILL telle que diffusée par le CEA, le CNRS et l'INRIA sur le site "http://www.cecill.info". Le fait que vous puissiez accéder à cet en-tête signifie que vous avez pris connaissance de la licence CeCILL, et que vous en avez accepté les termes (cf. le fichier Documentation/licence.fr.txt fourni avec ce logiciel). */ /* LICENCE SUM UP Copyright CEA, contributors : Luc BILLARD and Damien CALISTE and Olivier D'Astier, laboratoire L_Sim, (2001-2005) E-mail addresses : BILLARD, not reachable any more ; CALISTE, damien P caliste AT cea P fr. D'ASTIER, dastier AT iie P cnam P fr. This software is a computer program whose purpose is to visualize atomic configurations in 3D. This software is governed by the CeCILL license under French law and abiding by the rules of distribution of free software. You can use, modify and/ or redistribute the software under the terms of the CeCILL license as circulated by CEA, CNRS and INRIA at the following URL "http://www.cecill.info". The fact that you are presently reading this means that you have had knowledge of the CeCILL license and that you accept its terms. You can find a copy of this licence shipped with this software at Documentation/licence.en.txt. */ #ifndef SURFACES_RESOURCES_H #define SURFACES_RESOURCES_H #include #include #include #include G_BEGIN_DECLS /** * VISU_TYPE_SURFACE_RESOURCE: * * return the type of #VisuSurfaceResource. */ #define VISU_TYPE_SURFACE_RESOURCE (visu_surface_resource_get_type ()) /** * VISU_SURFACE_RESOURCE: * @obj: a #GObject to cast. * * Cast the given @obj into #VisuSurfaceResource type. */ #define VISU_SURFACE_RESOURCE(obj) (G_TYPE_CHECK_INSTANCE_CAST(obj, VISU_TYPE_SURFACE_RESOURCE, VisuSurfaceResource)) /** * VISU_SURFACE_RESOURCE_CLASS: * @klass: a #GObjectClass to cast. * * Cast the given @klass into #VisuSurfaceResourceClass. */ #define VISU_SURFACE_RESOURCE_CLASS(klass) (G_TYPE_CHECK_CLASS_CAST(klass, VISU_TYPE_SURFACE_RESOURCE, VisuSurfaceResourceClass)) /** * VISU_IS_SURFACE_RESOURCE: * @obj: a #GObject to test. * * Test if the given @ogj is of the type of #VisuSurfaceResource object. */ #define VISU_IS_SURFACE_RESOURCE(obj) (G_TYPE_CHECK_INSTANCE_TYPE(obj, VISU_TYPE_SURFACE_RESOURCE)) /** * VISU_IS_SURFACE_RESOURCE_CLASS: * @klass: a #GObjectClass to test. * * Test if the given @klass is of the type of #VisuSurfaceResourceClass class. */ #define VISU_IS_SURFACE_RESOURCE_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE(klass, VISU_TYPE_SURFACE_RESOURCE)) /** * VISU_SURFACE_RESOURCE_GET_CLASS: * @obj: a #GObject to get the class of. * * It returns the class of the given @obj. */ #define VISU_SURFACE_RESOURCE_GET_CLASS(obj) (G_TYPE_INSTANCE_GET_CLASS(obj, VISU_TYPE_SURFACE_RESOURCE, VisuSurfaceResourceClass)) /** * VisuSurfaceResourcePrivate: * * Private data for #VisuSurfaceResource objects. */ typedef struct _VisuSurfaceResourcePrivate VisuSurfaceResourcePrivate; typedef struct _VisuSurfaceResource VisuSurfaceResource; struct _VisuSurfaceResource { VisuObject parent; VisuSurfaceResourcePrivate *priv; }; /** * VisuSurfaceResourceClass: * @parent: private. * * Common name to refer to a #_VisuSurfaceResourceClass. */ typedef struct _VisuSurfaceResourceClass VisuSurfaceResourceClass; struct _VisuSurfaceResourceClass { VisuObjectClass parent; }; /** * visu_surface_resource_get_type: * * This method returns the type of #VisuSurfaceResource, use * VISU_TYPE_SURFACE_RESOURCE instead. * * Since: 3.8 * * Returns: the type of #VisuSurfaceResource. */ GType visu_surface_resource_get_type(void); VisuSurfaceResource* visu_surface_resource_new_fromName(const gchar *surf_name, gboolean *new_surf); VisuSurfaceResource* visu_surface_resource_new_fromCopy(const gchar *surf_name, const VisuSurfaceResource *orig); const gchar* visu_surface_resource_getLabel(const VisuSurfaceResource *res); const ToolColor* visu_surface_resource_getColor(const VisuSurfaceResource *res); const float* visu_surface_resource_getMaterial(const VisuSurfaceResource *res); gboolean visu_surface_resource_getRendered(const VisuSurfaceResource *res); gboolean visu_surface_resource_getMaskable(const VisuSurfaceResource *res); void visu_surface_resource_pool_finalize(void); G_END_DECLS #endif v_sim-3.8.0/src/extraFunctions/surfaces_tests.c000066400000000000000000000243041370110300500216340ustar00rootroot00000000000000/* EXTRAITS DE LA LICENCE Copyright CEA, contributeurs : Damien CALISTE, laboratoire L_Sim, (2001-2005) Adresse mèl : CALISTE, damien P caliste AT cea P fr. Ce logiciel est un programme informatique servant à visualiser des structures atomiques dans un rendu pseudo-3D. Ce logiciel est régi par la licence CeCILL soumise au droit français et respectant les principes de diffusion des logiciels libres. Vous pouvez utiliser, modifier et/ou redistribuer ce programme sous les conditions de la licence CeCILL telle que diffusée par le CEA, le CNRS et l'INRIA sur le site "http://www.cecill.info". Le fait que vous puissiez accéder à cet en-tête signifie que vous avez pris connaissance de la licence CeCILL, et que vous en avez accepté les termes (cf. le fichier Documentation/licence.fr.txt fourni avec ce logiciel). */ /* LICENCE SUM UP Copyright CEA, contributors : Damien CALISTE, laboratoire L_Sim, (2001-2005) E-mail addresses : CALISTE, damien P caliste AT cea P fr. This software is a computer program whose purpose is to visualize atomic configurations in 3D. This software is governed by the CeCILL license under French law and abiding by the rules of distribution of free software. You can use, modify and/ or redistribute the software under the terms of the CeCILL license as circulated by CEA, CNRS and INRIA at the following URL "http://www.cecill.info". The fact that you are presently reading this means that you have had knowledge of the CeCILL license and that you accept its terms. You can find a copy of this licence shipped with this software at Documentation/licence.en.txt. */ #include "surfaces.h" #define BUFFERSIZE 2 #define NB_SURFS 2 #define NB_POLYS 10 #define NB_POINTS 5 /* Various tests for the surface routines. */ static gboolean test_visu_surface_points_init(VisuSurfacePoints *points); static gboolean test_visu_surface_points_allocate_0(VisuSurfacePoints *points); static gboolean test_visu_surface_points_allocate(VisuSurfacePoints *points); static gboolean test_visu_surface_points_remove_1(VisuSurfacePoints *points); static gboolean test_visu_surface_points_remove_all(VisuSurfacePoints *points); static void local_populate(VisuSurfacePoints *points); static gboolean test_visu_surface_new(VisuSurface **surf); int main(int argc, char** argv) { VisuSurfacePoints points; VisuSurface *surf; /* To be removed later, needed for the link. */ getGeneralPaths(); /* Test the VisuSurfacePoints structure. */ visu_surface_points_init(&points, BUFFERSIZE); g_return_val_if_fail(test_visu_surface_points_init(&points), 1); /* Try to allocate a points with zero points. */ visu_surface_points_allocate(&points, NB_SURFS + 1, 0, 0); g_return_val_if_fail(test_visu_surface_points_allocate_0(&points), 1); visu_surface_points_free(&points); /* We try to allocate with some points this time. */ visu_surface_points_allocate(&points, NB_SURFS + 1, NB_POLYS, NB_POINTS); g_return_val_if_fail(test_visu_surface_points_allocate(&points), 1); /* We populate the surfaces. */ local_populate(&points); /* We try to remove the second surface. */ g_message("IsosurfacesPoints: remove one surface."); visu_surface_points_remove(&points, 1); g_return_val_if_fail(test_visu_surface_points_remove_1(&points), 1); /* We try to remove the last two surfaces. */ g_message("IsosurfacesPoints: remove all remaining surfaces."); visu_surface_points_remove(&points, 1); visu_surface_points_remove(&points, 0); g_return_val_if_fail(test_visu_surface_points_remove_all(&points), 1); visu_surface_points_free(&points); /* Test the VisuSurface structure. */ g_return_val_if_fail(test_visu_surface_new(&surf), 1); return 0; } static gboolean test_visu_surface_points_init(VisuSurfacePoints *points) { /* We check all the scalars. */ g_return_val_if_fail(points->nsurf == 0, FALSE); g_return_val_if_fail(points->bufferSize == BUFFERSIZE, FALSE); g_return_val_if_fail(points->num_polys == 0, FALSE); g_return_val_if_fail(points->num_points == 0, FALSE); /* We check that all the pointers are null. */ g_return_val_if_fail(!points->num_polys_surf, FALSE); g_return_val_if_fail(!points->poly_surf_index, FALSE); g_return_val_if_fail(!points->poly_num_vertices, FALSE); g_return_val_if_fail(!points->poly_vertices, FALSE); g_return_val_if_fail(!points->poly_points, FALSE); g_return_val_if_fail(!points->poly_normals, FALSE); return TRUE; } static gboolean test_visu_surface_points_allocate_0(VisuSurfacePoints *points) { /* We check the allocated arrays. */ g_return_val_if_fail(points->num_polys_surf, FALSE); g_return_val_if_fail(points->num_polys_surf[0] == 0 && points->num_polys_surf[1] == 0 && points->num_polys_surf[2] == 0, FALSE); /* We check that all other pointers are null. */ g_return_val_if_fail(!points->poly_surf_index, FALSE); g_return_val_if_fail(!points->poly_num_vertices, FALSE); g_return_val_if_fail(!points->poly_vertices, FALSE); g_return_val_if_fail(!points->poly_points, FALSE); g_return_val_if_fail(!points->poly_normals, FALSE); return TRUE; } static gboolean test_visu_surface_points_allocate(VisuSurfacePoints *points) { /* We check the allocated arrays. */ g_return_val_if_fail(points->num_polys_surf, FALSE); g_return_val_if_fail(points->num_polys_surf[0] == 0 && points->num_polys_surf[1] == 0 && points->num_polys_surf[2] == 0, FALSE); /* We check that all other pointers are allocated. */ g_return_val_if_fail(points->poly_surf_index, FALSE); g_return_val_if_fail(points->poly_num_vertices, FALSE); g_return_val_if_fail(points->poly_vertices, FALSE); g_return_val_if_fail(points->poly_points, FALSE); g_return_val_if_fail(points->poly_normals, FALSE); return TRUE; } static void local_populate(VisuSurfacePoints *points) { int i, j; points->num_polys_surf[0] = NB_POLYS / 2 - 2; points->num_polys_surf[1] = NB_POLYS / 2 - 1; points->num_polys_surf[2] = 3; for (i = 0; i < NB_POLYS / 2 - 2; i++) points->poly_surf_index[i] = 1; for (i = NB_POLYS / 2 - 2; i < NB_POLYS - 3; i++) points->poly_surf_index[i] = 2; for (i = NB_POLYS - 3; i < NB_POLYS; i++) points->poly_surf_index[i] = 3; for (i = 0; i < NB_POLYS / 2 + 1; i++) points->poly_num_vertices[i] = 4; for (i = NB_POLYS / 2 + 1; i < NB_POLYS; i++) points->poly_num_vertices[i] = 3; for (i = 0; i < NB_POLYS / 2 + 1; i++) { points->poly_vertices[i] = g_malloc(sizeof(int) * 4); for (j = 0; j < 4; j++) points->poly_vertices[i][j] = (i + j) % 5; } for (i = NB_POLYS / 2 + 1; i < NB_POLYS; i++) { points->poly_vertices[i] = g_malloc(sizeof(int) * 3); for (j = 0; j < 3; j++) points->poly_vertices[i][j] = (i - j) % 5; } for (i = 0; i < NB_POINTS; i++) for (j = 0; j < 3 + BUFFERSIZE; j++) points->poly_points[i][j] = i + j; for (i = 0; i < NB_POINTS; i++) for (j = 0; j < 3; j++) points->poly_normals[i][j] = i + j; } static gboolean test_visu_surface_points_remove_1(VisuSurfacePoints *points) { gboolean valid; int i, j; /* We check the scalar values. */ g_message(" | check scalar values."); g_return_val_if_fail(points->nsurf == NB_SURFS, FALSE); g_return_val_if_fail(points->bufferSize == BUFFERSIZE, FALSE); g_return_val_if_fail(points->num_polys == NB_POLYS / 2 + 1, FALSE); g_return_val_if_fail(points->num_points == NB_POINTS, FALSE); /* We check 1D arrays. */ g_message(" | check 1D arrays."); g_return_val_if_fail(points->num_polys_surf[0] == NB_POLYS / 2 - 2 && points->num_polys_surf[1] == 3, FALSE); g_return_val_if_fail(points->poly_surf_index[0] == 1 && points->poly_surf_index[1] == 1 && points->poly_surf_index[2] == 1 && points->poly_surf_index[3] == 2 && points->poly_surf_index[4] == 2 && points->poly_surf_index[5] == 2, FALSE); g_return_val_if_fail(points->poly_num_vertices[0] == 4 && points->poly_num_vertices[1] == 4 && points->poly_num_vertices[2] == 4 && points->poly_num_vertices[3] == 3 && points->poly_num_vertices[4] == 3 && points->poly_num_vertices[5] == 3, FALSE); /* We check 2D arrays. */ valid = TRUE; for (i = 0; i < NB_POLYS / 2 - 2; i++) for (j = 0; j < 4; j++) valid = valid && (points->poly_vertices[i][j] == (i + j) % 5); for (i = NB_POLYS / 2 - 2; i < NB_POLYS / 2 + 1; i++) for (j = 0; j < 3; j++) valid = valid && (points->poly_vertices[i][j] == (i - j - 1) % 5); g_message(" | check 2D arrays."); g_return_val_if_fail(valid, FALSE); /* We check the points and normal values. */ valid = TRUE; for (i = 0; i < NB_POINTS; i++) for (j = 0; j < 3 + BUFFERSIZE; j++) valid = valid && (points->poly_points[i][j] == i + j); for (i = 0; i < NB_POINTS; i++) for (j = 0; j < 3; j++) valid = valid && (points->poly_normals[i][j] == i + j); g_message(" | check points and normals."); g_return_val_if_fail(valid, FALSE); return TRUE; } static gboolean test_visu_surface_points_remove_all(VisuSurfacePoints *points) { /* We check the scalar values. */ g_message(" | check scalar values."); g_return_val_if_fail(points->nsurf == 0, FALSE); g_return_val_if_fail(points->bufferSize == BUFFERSIZE, FALSE); g_return_val_if_fail(points->num_polys == 0, FALSE); g_return_val_if_fail(points->num_points == 0, FALSE); /* We check that all arrays have been nullified. */ g_message(" | check null arrays."); g_return_val_if_fail(!points->poly_surf_index, FALSE); g_return_val_if_fail(!points->poly_num_vertices, FALSE); g_return_val_if_fail(!points->poly_vertices, FALSE); g_return_val_if_fail(!points->poly_points, FALSE); g_return_val_if_fail(!points->poly_normals, FALSE); return TRUE; } static gboolean test_visu_surface_new(VisuSurface **surf) { *surf = visu_surface_new(BUFFERSIZE); g_return_val_if_fail(test_visu_surface_points_init(&(*surf)->basePoints), FALSE); g_return_val_if_fail(test_visu_surface_points_init(&(*surf)->volatilePlanes), FALSE); /* We check the null pointers. */ g_return_val_if_fail(!(*surf)->ids, FALSE); g_return_val_if_fail(!(*surf)->resources, FALSE); /* We check the associated pointers. */ g_return_val_if_fail((*surf)->properties, FALSE); return TRUE; } v_sim-3.8.0/src/extraFunctions/translate.c000066400000000000000000000326751370110300500206060ustar00rootroot00000000000000/* EXTRAITS DE LA LICENCE Copyright CEA, contributeurs : Damien CALISTE, laboratoire L_Sim, (2017) Adresse mèl : CALISTE, damien P caliste AT cea P fr. Ce logiciel est un programme informatique servant à visualiser des structures atomiques dans un rendu pseudo-3D. Ce logiciel est régi par la licence CeCILL soumise au droit français et respectant les principes de diffusion des logiciels libres. Vous pouvez utiliser, modifier et/ou redistribuer ce programme sous les conditions de la licence CeCILL telle que diffusée par le CEA, le CNRS et l'INRIA sur le site "http://www.cecill.info". Le fait que vous puissiez accéder à cet en-tête signifie que vous avez pris connaissance de la licence CeCILL, et que vous en avez accepté les termes (cf. le fichier Documentation/licence.fr.txt fourni avec ce logiciel). */ /* LICENCE SUM UP Copyright CEA, contributors : Damien CALISTE, laboratoire L_Sim, (2017) E-mail address: CALISTE, damien P caliste AT cea P fr. This software is a computer program whose purpose is to visualize atomic configurations in 3D. This software is governed by the CeCILL license under French law and abiding by the rules of distribution of free software. You can use, modify and/ or redistribute the software under the terms of the CeCILL license as circulated by CEA, CNRS and INRIA at the following URL "http://www.cecill.info". The fact that you are presently reading this means that you have had knowledge of the CeCILL license and that you accept its terms. You can find a copy of this licence shipped with this software at Documentation/licence.en.txt. */ #include "translate.h" #include /** * SECTION:translate * @short_description: A class defining translations for a set of nodes. * * Define and apply a translation for a set of nodes. The * translation can be changed and the set of nodes also. Each time the * translation is applied, it is added to an undo stack. */ /** * VisuNodeMoverTranslationClass: * @parent: the parent class; * * A short way to identify #_VisuNodeMoverTranslationClass structure. * * Since: 3.8 */ /** * VisuNodeMoverTranslation: * * An opaque structure. * * Since: 3.8 */ struct _Params { gfloat delta[3]; }; /** * VisuNodeMoverTranslationPrivate: * * Private fields for #VisuNodeMoverTranslation objects. * * Since: 3.8 */ struct _VisuNodeMoverTranslationPrivate { struct _Params params; struct _Params target; gfloat lastDelta[3]; GSList *stack; }; enum { PROP_0, TRANS_PROP, N_PROP }; static GParamSpec *_properties[N_PROP]; static void visu_node_mover_translation_finalize(GObject *obj); static void visu_node_mover_translation_get_property(GObject* obj, guint property_id, GValue *value, GParamSpec *pspec); static void visu_node_mover_translation_set_property(GObject* obj, guint property_id, const GValue *value, GParamSpec *pspec); static gboolean _validate(const VisuNodeMover *mover); static void _setup(VisuNodeMover *mover); static gboolean _apply(VisuNodeMover *mover, VisuNodeArray *arr, const GArray *ids, gfloat completion); static gboolean _push(VisuNodeMover *mover); static void _undo(VisuNodeMover *mover, VisuNodeArray *arr, const GArray *ids); G_DEFINE_TYPE_WITH_CODE(VisuNodeMoverTranslation, visu_node_mover_translation, VISU_TYPE_NODE_MOVER, G_ADD_PRIVATE(VisuNodeMoverTranslation)) static void visu_node_mover_translation_class_init(VisuNodeMoverTranslationClass *klass) { DBG_fprintf(stderr, "Visu MoverTranslation: creating the class of the object.\n"); /* DBG_fprintf(stderr, " - adding new signals ;\n"); */ /* Connect the overloading methods. */ G_OBJECT_CLASS(klass)->finalize = visu_node_mover_translation_finalize; G_OBJECT_CLASS(klass)->set_property = visu_node_mover_translation_set_property; G_OBJECT_CLASS(klass)->get_property = visu_node_mover_translation_get_property; VISU_NODE_MOVER_CLASS(klass)->validate = _validate; VISU_NODE_MOVER_CLASS(klass)->setup = _setup; VISU_NODE_MOVER_CLASS(klass)->apply = _apply; VISU_NODE_MOVER_CLASS(klass)->push = _push; VISU_NODE_MOVER_CLASS(klass)->undo = _undo; /** * VisuNodeMoverTranslation::translation: * * The translation. * * Since: 3.8 */ _properties[TRANS_PROP] = g_param_spec_boxed("translation", "Translation", "value of translation.", TOOL_TYPE_VECTOR, G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS); g_object_class_install_properties(G_OBJECT_CLASS(klass), N_PROP, _properties); } static void visu_node_mover_translation_init(VisuNodeMoverTranslation *obj) { DBG_fprintf(stderr, "Visu MoverTranslation: initializing a new object (%p).\n", (gpointer)obj); obj->priv = visu_node_mover_translation_get_instance_private(obj); obj->priv->stack = (GSList*)0; obj->priv->params.delta[0] = 0.f; obj->priv->params.delta[1] = 0.f; obj->priv->params.delta[2] = 0.f; } static void visu_node_mover_translation_get_property(GObject* obj, guint property_id, GValue *value, GParamSpec *pspec) { VisuNodeMoverTranslation *self = VISU_NODE_MOVER_TRANSLATION(obj); DBG_fprintf(stderr, "Visu MoverTranslation: get property %s.\n", g_param_spec_get_name(pspec)); switch (property_id) { case TRANS_PROP: g_value_set_boxed(value, self->priv->params.delta); break; default: /* We don't have any other property... */ G_OBJECT_WARN_INVALID_PROPERTY_ID(obj, property_id, pspec); break; } } static void visu_node_mover_translation_set_property(GObject* obj, guint property_id, const GValue *value, GParamSpec *pspec) { VisuNodeMoverTranslation *self = VISU_NODE_MOVER_TRANSLATION(obj); DBG_fprintf(stderr, "Visu MoverTranslation: set property %s.\n", g_param_spec_get_name(pspec)); switch (property_id) { case TRANS_PROP: visu_node_mover_translation_set(self, (float*)g_value_get_boxed(value)); break; default: /* We don't have any other property... */ G_OBJECT_WARN_INVALID_PROPERTY_ID(obj, property_id, pspec); break; } } static void visu_node_mover_translation_finalize(GObject *obj) { VisuNodeMoverTranslation *trans; g_return_if_fail(obj); DBG_fprintf(stderr, "Visu MoverTranslation: finalize object %p.\n", (gpointer)obj); trans = VISU_NODE_MOVER_TRANSLATION(obj); /* Free privs elements. */ if (trans->priv->stack) g_slist_free_full(trans->priv->stack, g_free); /* Chain up to the parent class */ DBG_fprintf(stderr, "Visu MoverTranslation: chain to parent.\n"); G_OBJECT_CLASS(visu_node_mover_translation_parent_class)->finalize(obj); DBG_fprintf(stderr, "Visu MoverTranslation: freeing ... OK.\n"); } static gboolean _validate(const VisuNodeMover *mover) { VisuNodeMoverTranslation *trans; g_return_val_if_fail(VISU_IS_NODE_MOVER_TRANSLATION(mover), FALSE); trans = VISU_NODE_MOVER_TRANSLATION(mover); if (trans->priv->params.delta[0] == 0.f && trans->priv->params.delta[1] == 0.f && trans->priv->params.delta[2] == 0.f) return FALSE; return TRUE; } static void _setup(VisuNodeMover *mover) { VisuNodeMoverTranslation *trans; g_return_if_fail(VISU_IS_NODE_MOVER_TRANSLATION(mover)); trans = VISU_NODE_MOVER_TRANSLATION(mover); trans->priv->target = trans->priv->params; trans->priv->lastDelta[0] = 0.f; trans->priv->lastDelta[1] = 0.f; trans->priv->lastDelta[2] = 0.f; } static gboolean _apply(VisuNodeMover *mover, VisuNodeArray *arr, const GArray *ids, gfloat completion) { VisuNodeMoverTranslation *trans; struct _Params *params; gfloat delta[3]; g_return_val_if_fail(VISU_IS_NODE_MOVER_TRANSLATION(mover), FALSE); trans = VISU_NODE_MOVER_TRANSLATION(mover); DBG_fprintf(stderr, "Visu MoverTranslation: apply translation %gx%gx%g.\n", trans->priv->params.delta[0], trans->priv->params.delta[1], trans->priv->params.delta[2]); if (!_validate(mover)) return FALSE; delta[0] = trans->priv->target.delta[0] * completion - trans->priv->lastDelta[0]; delta[1] = trans->priv->target.delta[1] * completion - trans->priv->lastDelta[1]; delta[2] = trans->priv->target.delta[2] * completion - trans->priv->lastDelta[2]; visu_node_array_shiftNodes(arr, ids, delta); trans->priv->lastDelta[0] = trans->priv->target.delta[0] * completion; trans->priv->lastDelta[1] = trans->priv->target.delta[1] * completion; trans->priv->lastDelta[2] = trans->priv->target.delta[2] * completion; if (completion == 1.f) { params = g_malloc(sizeof(struct _Params)); *params = trans->priv->params; trans->priv->stack = g_slist_prepend(trans->priv->stack, params); } return TRUE; } static gboolean _push(VisuNodeMover *mover) { VisuNodeMoverTranslation *trans; struct _Params *params; g_return_val_if_fail(VISU_IS_NODE_MOVER_TRANSLATION(mover), FALSE); trans = VISU_NODE_MOVER_TRANSLATION(mover); if (!_validate(mover)) return FALSE; DBG_fprintf(stderr, "Visu MoverTranslation: push the current translation.\n"); params = g_malloc(sizeof(struct _Params)); *params = trans->priv->params; trans->priv->stack = g_slist_prepend(trans->priv->stack, params); return TRUE; } static void _undo(VisuNodeMover *mover, VisuNodeArray *arr, const GArray *ids) { VisuNodeMoverTranslation *trans; struct _Params *params; gfloat delta[3]; GSList *p; g_return_if_fail(VISU_IS_NODE_MOVER_TRANSLATION(mover)); trans = VISU_NODE_MOVER_TRANSLATION(mover); if (!trans->priv->stack) return; p = trans->priv->stack; params = (struct _Params*)p->data; delta[0] = -params->delta[0]; delta[1] = -params->delta[1]; delta[2] = -params->delta[2]; visu_node_array_shiftNodes(arr, ids, delta); trans->priv->stack = g_slist_next(trans->priv->stack); g_free(params); g_slist_free_1(p); } /** * visu_node_mover_translation_new: * * Creates a new #VisuNodeMoverTranslation object. * * Since: 3.8 * * Returns: (transfer full): a new #VisuNodeMoverTranslation object. **/ VisuNodeMoverTranslation* visu_node_mover_translation_new() { return g_object_new(VISU_TYPE_NODE_MOVER_TRANSLATION, NULL); } /** * visu_node_mover_translation_new_full: * @ids: (element-type guint): a list of node ids. * @trans: (array fixed-size=3): a translation. * * Creates a new @trans for nodes defined by @ids. * * Since: 3.8 * * Returns: (transfer full): a new #VisuNodeMoverTranslation object. **/ VisuNodeMoverTranslation* visu_node_mover_translation_new_full(const GArray *ids, const gfloat trans[3]) { return g_object_new(VISU_TYPE_NODE_MOVER_TRANSLATION, "ids", ids, "translation", trans, NULL); } /** * visu_node_mover_translation_set: * @trans: a #VisuNodeMoverTranslation object. * @delta: (array fixed-size=3): a translation. * * Defines the translation to be applied by @trans. * * Since: 3.8 * * Returns: TRUE if value is actually changed. **/ gboolean visu_node_mover_translation_set(VisuNodeMoverTranslation *trans, const gfloat delta[3]) { g_return_val_if_fail(VISU_IS_NODE_MOVER_TRANSLATION(trans), FALSE); DBG_fprintf(stderr, "Visu MoverTranslation: set %gx%gx%g.\n", delta[0], delta[1], delta[2]); if (!tool_vector_set(trans->priv->params.delta, delta)) return FALSE; DBG_fprintf(stderr, "Visu MoverTranslation: translation changed.\n"); g_object_notify_by_pspec(G_OBJECT(trans), _properties[TRANS_PROP]); g_object_notify(G_OBJECT(trans), "valid"); return TRUE; } /** * visu_node_mover_translation_reset: * @trans: a #VisuNodeMoverTranslation object. * * Helper function to sets the translation to [0;0;0]. * * Since: 3.8 * * Returns: TRUE if translation is actually changed. **/ gboolean visu_node_mover_translation_reset(VisuNodeMoverTranslation *trans) { gfloat zeros[3] = {0.f, 0.f, 0.f}; return visu_node_mover_translation_set(trans, zeros); } /** * visu_node_mover_translation_add: * @trans: a #VisuNodeMoverTranslation object. * @delta: (array fixed-size=3): a translation. * * Add @delta to the current translation. * * Since: 3.8 * * Returns: TRUE if translation is actually changed. **/ gboolean visu_node_mover_translation_add(VisuNodeMoverTranslation *trans, const gfloat delta[3]) { gfloat value[3]; g_return_val_if_fail(VISU_IS_NODE_MOVER_TRANSLATION(trans), FALSE); DBG_fprintf(stderr, "Visu MoverTranslation: add %gx%gx%g.\n", delta[0], delta[1], delta[2]); value[0] = trans->priv->params.delta[0] + delta[0]; value[1] = trans->priv->params.delta[1] + delta[1]; value[2] = trans->priv->params.delta[2] + delta[2]; return visu_node_mover_translation_set(trans, value); } /** * visu_node_mover_translation_get: * @trans: a #VisuNodeMoverTranslation object. * @delta: (out) (array fixed-size=3): a location for the translation. * * Retrieves the current translation. * * Since: 3.8 **/ void visu_node_mover_translation_get(const VisuNodeMoverTranslation *trans, gfloat delta[3]) { g_return_if_fail(VISU_IS_NODE_MOVER_TRANSLATION(trans)); tool_vector_set(delta, trans->priv->params.delta); } v_sim-3.8.0/src/extraFunctions/translate.h000066400000000000000000000113471370110300500206040ustar00rootroot00000000000000/* EXTRAITS DE LA LICENCE Copyright CEA, contributeurs : Damien CALISTE, laboratoire L_Sim, (2017) Adresse mèl : CALISTE, damien P caliste AT cea P fr. Ce logiciel est un programme informatique servant à visualiser des structures atomiques dans un rendu pseudo-3D. Ce logiciel est régi par la licence CeCILL soumise au droit français et respectant les principes de diffusion des logiciels libres. Vous pouvez utiliser, modifier et/ou redistribuer ce programme sous les conditions de la licence CeCILL telle que diffusée par le CEA, le CNRS et l'INRIA sur le site "http://www.cecill.info". Le fait que vous puissiez accéder à cet en-tête signifie que vous avez pris connaissance de la licence CeCILL, et que vous en avez accepté les termes (cf. le fichier Documentation/licence.fr.txt fourni avec ce logiciel). */ /* LICENCE SUM UP Copyright CEA, contributors : Damien CALISTE, laboratoire L_Sim, (2017) E-mail address: CALISTE, damien P caliste AT cea P fr. This software is a computer program whose purpose is to visualize atomic configurations in 3D. This software is governed by the CeCILL license under French law and abiding by the rules of distribution of free software. You can use, modify and/ or redistribute the software under the terms of the CeCILL license as circulated by CEA, CNRS and INRIA at the following URL "http://www.cecill.info". The fact that you are presently reading this means that you have had knowledge of the CeCILL license and that you accept its terms. You can find a copy of this licence shipped with this software at COPYING. */ #ifndef TRANSLATE_H #define TRANSLATE_H #include "mover.h" G_BEGIN_DECLS /** * VISU_TYPE_NODE_MOVER_TRANSLATION: * * return the type of #VisuNodeMoverTranslation. * * Since: 3.8 */ #define VISU_TYPE_NODE_MOVER_TRANSLATION (visu_node_mover_translation_get_type ()) /** * VISU_NODE_MOVER_TRANSLATION: * @obj: a #GObject to cast. * * Cast the given @obj into #VisuNodeMoverTranslation type. * * Since: 3.8 */ #define VISU_NODE_MOVER_TRANSLATION(obj) (G_TYPE_CHECK_INSTANCE_CAST(obj, VISU_TYPE_NODE_MOVER_TRANSLATION, VisuNodeMoverTranslation)) /** * VISU_NODE_MOVER_TRANSLATION_CLASS: * @klass: a #GObjectClass to cast. * * Cast the given @klass into #VisuNodeMoverTranslationClass. * * Since: 3.8 */ #define VISU_NODE_MOVER_TRANSLATION_CLASS(klass) (G_TYPE_CHECK_CLASS_CAST(klass, VISU_TYPE_NODE_MOVER_TRANSLATION, VisuNodeMoverTranslationClass)) /** * VISU_IS_NODE_MOVER_TRANSLATION: * @obj: a #GObject to test. * * Test if the given @ogj is of the type of #VisuNodeMoverTranslation object. * * Since: 3.8 */ #define VISU_IS_NODE_MOVER_TRANSLATION(obj) (G_TYPE_CHECK_INSTANCE_TYPE(obj, VISU_TYPE_NODE_MOVER_TRANSLATION)) /** * VISU_IS_NODE_MOVER_TRANSLATION_CLASS: * @klass: a #GObjectClass to test. * * Test if the given @klass is of the type of #VisuNodeMoverTranslationClass class. * * Since: 3.8 */ #define VISU_IS_NODE_MOVER_TRANSLATION_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE(klass, VISU_TYPE_NODE_MOVER_TRANSLATION)) /** * VISU_NODE_MOVER_TRANSLATION_GET_CLASS: * @obj: a #GObject to get the class of. * * It returns the class of the given @obj. * * Since: 3.8 */ #define VISU_NODE_MOVER_TRANSLATION_GET_CLASS(obj) (G_TYPE_INSTANCE_GET_CLASS(obj, VISU_TYPE_NODE_MOVER_TRANSLATION, VisuNodeMoverTranslationClass)) typedef struct _VisuNodeMoverTranslation VisuNodeMoverTranslation; typedef struct _VisuNodeMoverTranslationPrivate VisuNodeMoverTranslationPrivate; typedef struct _VisuNodeMoverTranslationClass VisuNodeMoverTranslationClass; struct _VisuNodeMoverTranslation { VisuNodeMover parent; VisuNodeMoverTranslationPrivate *priv; }; struct _VisuNodeMoverTranslationClass { VisuNodeMoverClass parent; }; /** * visu_node_mover_translation_get_type: * * This method returns the type of #VisuNodeMoverTranslation, use * VISU_TYPE_NODE_MOVER_TRANSLATION instead. * * Since: 3.8 * * Returns: the type of #VisuNodeMoverTranslation. */ GType visu_node_mover_translation_get_type(void); VisuNodeMoverTranslation* visu_node_mover_translation_new(); VisuNodeMoverTranslation* visu_node_mover_translation_new_full(const GArray *ids, const gfloat trans[3]); gboolean visu_node_mover_translation_set(VisuNodeMoverTranslation *trans, const gfloat delta[3]); gboolean visu_node_mover_translation_reset(VisuNodeMoverTranslation *trans); gboolean visu_node_mover_translation_add(VisuNodeMoverTranslation *trans, const gfloat delta[3]); void visu_node_mover_translation_get(const VisuNodeMoverTranslation *trans, gfloat delta[3]); G_END_DECLS #endif v_sim-3.8.0/src/extraFunctions/typeProp.c000066400000000000000000000143051370110300500204210ustar00rootroot00000000000000/* EXTRAITS DE LA LICENCE Copyright CEA, contributeurs : Damien CALISTE, laboratoire L_Sim, (2017) Adresse mèl : CALISTE, damien P caliste AT cea P fr. Ce logiciel est un programme informatique servant à visualiser des structures atomiques dans un rendu pseudo-3D. Ce logiciel est régi par la licence CeCILL soumise au droit français et respectant les principes de diffusion des logiciels libres. Vous pouvez utiliser, modifier et/ou redistribuer ce programme sous les conditions de la licence CeCILL telle que diffusée par le CEA, le CNRS et l'INRIA sur le site "http://www.cecill.info". Le fait que vous puissiez accéder à cet en-tête signifie que vous avez pris connaissance de la licence CeCILL, et que vous en avez accepté les termes (cf. le fichier Documentation/licence.fr.txt fourni avec ce logiciel). */ /* LICENCE SUM UP Copyright CEA, contributors : Damien CALISTE, laboratoire L_Sim, (2017) E-mail address: CALISTE, damien P caliste AT cea P fr. This software is a computer program whose purpose is to visualize atomic configurations in 3D. This software is governed by the CeCILL license under French law and abiding by the rules of distribution of free software. You can use, modify and/ or redistribute the software under the terms of the CeCILL license as circulated by CEA, CNRS and INRIA at the following URL "http://www.cecill.info". The fact that you are presently reading this means that you have had knowledge of the CeCILL license and that you accept its terms. You can find a copy of this licence shipped with this software at Documentation/licence.en.txt. */ #include "typeProp.h" #include #include /** * SECTION:typeProp * @short_description: define a #VisuNodeValues object to access node typeinates. * * Defines a #VisuNodeValues object to be notified about * typeinate changes. */ static gboolean _getAt(const VisuNodeValues *vals, const VisuNode *node, GValue *value); static gboolean _setAt(VisuNodeValues *vals, const VisuNode *node, GValue *value); static gboolean _parse(VisuNodeValues *vals, VisuNode *node, const gchar *from); static gchar* _serialize(const VisuNodeValues *vals, const VisuNode *node); G_DEFINE_TYPE(VisuNodeValuesType, visu_node_values_type, VISU_TYPE_NODE_VALUES) static void visu_node_values_type_class_init(VisuNodeValuesTypeClass *klass) { /* Connect the overloading methods. */ VISU_NODE_VALUES_CLASS(klass)->getAt = _getAt; VISU_NODE_VALUES_CLASS(klass)->setAt = _setAt; VISU_NODE_VALUES_CLASS(klass)->parse = _parse; VISU_NODE_VALUES_CLASS(klass)->serialize = _serialize; } static void visu_node_values_type_init(VisuNodeValuesType *self _U_) { } VisuElement* _getElement(const VisuNodeValues *vals, const VisuNode *node) { VisuNodeArray *arr; VisuElement *ele; arr = visu_node_values_getArray(vals); ele = visu_node_array_getElement(arr, node); g_object_unref(arr); return ele; } static gboolean _parse(VisuNodeValues *vals, VisuNode *node, const gchar *from) { gfloat fvals[3]; gchar **datas; guint i; GValue value = {0, {{0}, {0}}}; g_return_val_if_fail(from, FALSE); datas = g_strsplit_set(from, "(;)", 3); for (i = 0; datas[i]; i++) if (sscanf(from, "%f", fvals + i) != 1) { g_strfreev(datas); return FALSE; } g_strfreev(datas); g_value_init(&value, G_TYPE_POINTER); g_value_set_pointer(&value, fvals); return _setAt(vals, node, &value); } static gchar* _serialize(const VisuNodeValues *vals, const VisuNode *node) { return g_strdup(visu_element_getName(_getElement(vals, node))); } /** * visu_node_values_type_new: * @array: a #VisuData object. * * Create a #VisuNodeValues object to handle typeinates of nodes. * * Since: 3.8 * * Returns: (transfer full): a newly created #VisuNodeValuesType object. **/ VisuNodeValuesType* visu_node_values_type_new(VisuNodeArray *array) { return g_object_new(VISU_TYPE_NODE_VALUES_TYPE, "label", _("Type"), "internal", TRUE, "nodes", array, "type", VISU_TYPE_ELEMENT, "n-elements", 1, "editable", FALSE, NULL); } /** * visu_node_values_type_getAt: * @vect: a #VisuNodeValuesType object. * @node: a #VisuNode object. * * Retrieves the type hosted on @node. * * Since: 3.8 * * Returns: (transfer none): the #VisuElement for @node. **/ VisuElement* visu_node_values_type_getAt(const VisuNodeValuesType *vect, const VisuNode *node) { g_return_val_if_fail(VISU_IS_NODE_VALUES_TYPE(vect), (VisuElement*)0); return _getElement(VISU_NODE_VALUES(vect), node); } static gboolean _getAt(const VisuNodeValues *vals, const VisuNode *node, GValue *value) { g_value_set_object(value, _getElement(vals, node)); return TRUE; } static gboolean _setAt(VisuNodeValues *vect, const VisuNode *node, GValue *value) { VisuNodeArray *arr; VisuNode *n, *newNode; arr = visu_node_values_getArray(vect); n = visu_node_array_getFromId(arr, node->number); newNode = visu_node_array_setElement(arr, n, VISU_ELEMENT(g_value_get_object(value))); g_object_unref(arr); /* Chain up to parent. */ return VISU_NODE_VALUES_CLASS(visu_node_values_type_parent_class)->setAt(vect, newNode, value); } /** * visu_node_values_type_setAt: * @vect: a #VisuNodeValuesType object. * @node: a #VisuNode object. * @element: type typeinates. * * Changes the type hosted at @node for @element. This will change * @node and its location. @node is not valid anymore after a call to * this function. * * Since: 3.8 * * Returns: TRUE if type for @node is indeed changed. **/ gboolean visu_node_values_type_setAt(VisuNodeValuesType *vect, const VisuNode *node, VisuElement *element) { GValue value = G_VALUE_INIT; gboolean res; g_value_init(&value, VISU_TYPE_ELEMENT); g_value_set_object(&value, element); res = visu_node_values_setAt(VISU_NODE_VALUES(vect), node, &value); g_value_unset(&value); return res; } v_sim-3.8.0/src/extraFunctions/typeProp.h000066400000000000000000000103371370110300500204270ustar00rootroot00000000000000/* EXTRAITS DE LA LICENCE Copyright CEA, contributeurs : Damien CALISTE, laboratoire L_Sim, (2017) Adresse mèl : CALISTE, damien P caliste AT cea P fr. Ce logiciel est un programme informatique servant à visualiser des structures atomiques dans un rendu pseudo-3D. Ce logiciel est régi par la licence CeCILL soumise au droit français et respectant les principes de diffusion des logiciels libres. Vous pouvez utiliser, modifier et/ou redistribuer ce programme sous les conditions de la licence CeCILL telle que diffusée par le CEA, le CNRS et l'INRIA sur le site "http://www.cecill.info". Le fait que vous puissiez accéder à cet en-tête signifie que vous avez pris connaissance de la licence CeCILL, et que vous en avez accepté les termes (cf. le fichier Documentation/licence.fr.txt fourni avec ce logiciel). */ /* LICENCE SUM UP Copyright CEA, contributors : Damien CALISTE, laboratoire L_Sim, (2017) E-mail address: CALISTE, damien P caliste AT cea P fr. This software is a computer program whose purpose is to visualize atomic configurations in 3D. This software is governed by the CeCILL license under French law and abiding by the rules of distribution of free software. You can use, modify and/ or redistribute the software under the terms of the CeCILL license as circulated by CEA, CNRS and INRIA at the following URL "http://www.cecill.info". The fact that you are presently reading this means that you have had knowledge of the CeCILL license and that you accept its terms. You can find a copy of this licence shipped with this software at Documentation/licence.en.txt. */ #ifndef TYPEPROP_H #define TYPEPROP_H #include #include #include "nodeProp.h" G_BEGIN_DECLS /** * VISU_TYPE_NODE_VALUES_TYPE: * * return the type of #VisuNodeValuesType. */ #define VISU_TYPE_NODE_VALUES_TYPE (visu_node_values_type_get_type ()) /** * VISU_NODE_VALUES_TYPE: * @obj: a #GObject to cast. * * Cast the given @obj into #VisuNodeValuesType type. */ #define VISU_NODE_VALUES_TYPE(obj) (G_TYPE_CHECK_INSTANCE_CAST(obj, VISU_TYPE_NODE_VALUES_TYPE, VisuNodeValuesType)) /** * VISU_NODE_VALUES_TYPE_CLASS: * @klass: a #GObjectClass to cast. * * Cast the given @klass into #VisuNodeValuesTypeClass. */ #define VISU_NODE_VALUES_TYPE_CLASS(klass) (G_TYPE_CHECK_CLASS_CAST(klass, VISU_TYPE_NODE_VALUES_TYPE, VisuNodeValuesTypeClass)) /** * VISU_IS_NODE_VALUES_TYPE: * @obj: a #GObject to test. * * Test if the given @ogj is of the type of #VisuNodeValuesType object. */ #define VISU_IS_NODE_VALUES_TYPE(obj) (G_TYPE_CHECK_INSTANCE_TYPE(obj, VISU_TYPE_NODE_VALUES_TYPE)) /** * VISU_IS_NODE_VALUES_TYPE_CLASS: * @klass: a #GObjectClass to test. * * Test if the given @klass is of the type of #VisuNodeValuesTypeClass class. */ #define VISU_IS_NODE_VALUES_TYPE_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE(klass, VISU_TYPE_NODE_VALUES)) /** * VISU_NODE_VALUES_TYPE_GET_CLASS: * @obj: a #GObject to get the class of. * * It returns the class of the given @obj. */ #define VISU_NODE_VALUES_TYPE_GET_CLASS(obj) (G_TYPE_INSTANCE_GET_CLASS(obj, VISU_TYPE_NODE_VALUES_TYPE, VisuNodeValuesTypeClass)) /** * VisuNodeValuesType: * * Common name to refer to a #_VisuNodeValuesType. */ typedef struct _VisuNodeValuesType VisuNodeValuesType; struct _VisuNodeValuesType { VisuNodeValues parent; }; /** * VisuNodeValuesTypeClass: * @parent: private. * * Common name to refer to a #_VisuNodeValuesTypeClass. */ typedef struct _VisuNodeValuesTypeClass VisuNodeValuesTypeClass; struct _VisuNodeValuesTypeClass { VisuNodeValuesClass parent; }; /** * visu_node_values_type_get_type: * * This method returns the type of #VisuNodeValuesType, use * VISU_TYPE_NODE_VALUES instead. * * Since: 3.8 * * Returns: the type of #VisuNodeValuesType. */ GType visu_node_values_type_get_type(void); VisuNodeValuesType* visu_node_values_type_new(VisuNodeArray *array); VisuElement* visu_node_values_type_getAt(const VisuNodeValuesType *vect, const VisuNode *node); gboolean visu_node_values_type_setAt(VisuNodeValuesType *vect, const VisuNode *node, VisuElement *element); G_END_DECLS #endif v_sim-3.8.0/src/extraFunctions/vectColorizer.c000066400000000000000000000102011370110300500214200ustar00rootroot00000000000000/* EXTRAITS DE LA LICENCE Copyright CEA, contributeurs : Damien CALISTE, laboratoire L_Sim, (2018) Adresse mèl : CALISTE, damien P caliste AT cea P fr. Ce logiciel est un programme informatique servant à visualiser des structures atomiques dans un rendu pseudo-3D. Ce logiciel est régi par la licence CeCILL soumise au droit français et respectant les principes de diffusion des logiciels libres. Vous pouvez utiliser, modifier et/ou redistribuer ce programme sous les conditions de la licence CeCILL telle que diffusée par le CEA, le CNRS et l'INRIA sur le site "http://www.cecill.info". Le fait que vous puissiez accéder à cet en-tête signifie que vous avez pris connaissance de la licence CeCILL, et que vous en avez accepté les termes (cf. le fichier Documentation/licence.fr.txt fourni avec ce logiciel). */ /* LICENCE SUM UP Copyright CEA, contributors : Damien CALISTE, laboratoire L_Sim, (2018) E-mail address: CALISTE, damien P caliste AT cea P fr. This software is a computer program whose purpose is to visualize atomic configurations in 3D. This software is governed by the CeCILL license under French law and abiding by the rules of distribution of free software. You can use, modify and/ or redistribute the software under the terms of the CeCILL license as circulated by CEA, CNRS and INRIA at the following URL "http://www.cecill.info". The fact that you are presently reading this means that you have had knowledge of the CeCILL license and that you accept its terms. You can find a copy of this licence shipped with this software at Documentation/licence.en.txt. */ #include "vectColorizer.h" /** * SECTION:vectColorizer * @short_description: A class defining node colorisation according to * #VisuNodeValuesVector. * * This class implements #VisuDataColorizer for data coming from * #VisuNodeValuesVector. The colorisation is done according to vector * norm. */ static gboolean _toValues(const VisuDataColorizerShaded *colorizer, gfloat values[3], const VisuData *visuData, const VisuNode* node); G_DEFINE_TYPE(VisuDataColorizerVector, visu_data_colorizer_vector, VISU_TYPE_DATA_COLORIZER_SHADED) static void visu_data_colorizer_vector_class_init(VisuDataColorizerVectorClass *klass) { /* Connect the overloading methods. */ VISU_DATA_COLORIZER_SHADED_CLASS(klass)->toValues = _toValues; } static void visu_data_colorizer_vector_init(VisuDataColorizerVector *obj _U_) { } /** * visu_data_colorizer_vector_new: * * Creates a #VisuDataColorizer object to colorize and hide #VisuNode * based on a #VisuNodeValuesVector model. * * Since: 3.8 * * Returns: (transfer full): a newly created * #VisuDataColorizerVector object. **/ VisuDataColorizerVector* visu_data_colorizer_vector_new() { return VISU_DATA_COLORIZER_VECTOR(g_object_new(VISU_TYPE_DATA_COLORIZER_VECTOR, NULL)); } /** * visu_data_colorizer_vector_setNodeModel: * @colorizer: a #VisuDataColorizerVector object. * @model: (transfer none): a #VisuNodeValuesVector object. * * Associate @model to @colorizer. * * Since: 3.8 * * Returns: TRUE if the model is indeed changed. **/ gboolean visu_data_colorizer_vector_setNodeModel(VisuDataColorizerVector *colorizer, VisuNodeValuesVector *model) { return visu_sourceable_setNodeModel(VISU_SOURCEABLE(colorizer), VISU_NODE_VALUES(model)); } static gboolean _toValues(const VisuDataColorizerShaded *colorizer, gfloat values[3], const VisuData *visuData _U_, const VisuNode* node) { const gfloat *f; const VisuNodeValues *model; gfloat m, M, v; model = visu_sourceable_getConstNodeModel(VISU_SOURCEABLE(colorizer)); f = visu_node_values_vector_getAtSpherical(VISU_NODE_VALUES_VECTOR(model), node); if (!f) return FALSE; m = visu_node_values_farray_min(VISU_NODE_VALUES_FARRAY(model)); M = visu_node_values_farray_max(VISU_NODE_VALUES_FARRAY(model)); v = (f[TOOL_MATRIX_SPHERICAL_MODULUS] - m) / (M - m); values[0] = values[1] = values[2] = v; return TRUE; } v_sim-3.8.0/src/extraFunctions/vectColorizer.h000066400000000000000000000106061370110300500214360ustar00rootroot00000000000000/* EXTRAITS DE LA LICENCE Copyright CEA, contributeurs : Damien CALISTE, laboratoire L_Sim, (2018) Adresse mèl : CALISTE, damien P caliste AT cea P fr. Ce logiciel est un programme informatique servant à visualiser des structures atomiques dans un rendu pseudo-3D. Ce logiciel est régi par la licence CeCILL soumise au droit français et respectant les principes de diffusion des logiciels libres. Vous pouvez utiliser, modifier et/ou redistribuer ce programme sous les conditions de la licence CeCILL telle que diffusée par le CEA, le CNRS et l'INRIA sur le site "http://www.cecill.info". Le fait que vous puissiez accéder à cet en-tête signifie que vous avez pris connaissance de la licence CeCILL, et que vous en avez accepté les termes (cf. le fichier Documentation/licence.fr.txt fourni avec ce logiciel). */ /* LICENCE SUM UP Copyright CEA, contributors : Damien CALISTE, laboratoire L_Sim, (2018) E-mail address: CALISTE, damien P caliste AT cea P fr. This software is a computer program whose purpose is to visualize atomic configurations in 3D. This software is governed by the CeCILL license under French law and abiding by the rules of distribution of free software. You can use, modify and/ or redistribute the software under the terms of the CeCILL license as circulated by CEA, CNRS and INRIA at the following URL "http://www.cecill.info". The fact that you are presently reading this means that you have had knowledge of the CeCILL license and that you accept its terms. You can find a copy of this licence shipped with this software at Documentation/licence.en.txt. */ #ifndef VECTCOLORIZER_H #define VECTCOLORIZER_H #include #include #include "shadedColorizer.h" #include "vectorProp.h" #include G_BEGIN_DECLS /** * VISU_TYPE_DATA_COLORIZER_VECTOR: * * return the type of #VisuDataColorizerVector. */ #define VISU_TYPE_DATA_COLORIZER_VECTOR (visu_data_colorizer_vector_get_type ()) /** * VISU_DATA_COLORIZER_VECTOR: * @obj: a #GObject to cast. * * Cast the given @obj into #VisuDataColorizerVector type. */ #define VISU_DATA_COLORIZER_VECTOR(obj) (G_TYPE_CHECK_INSTANCE_CAST(obj, VISU_TYPE_DATA_COLORIZER_VECTOR, VisuDataColorizerVector)) /** * VISU_DATA_COLORIZER_VECTOR_CLASS: * @klass: a #GObjectClass to cast. * * Cast the given @klass into #VisuDataColorizerVectorClass. */ #define VISU_DATA_COLORIZER_VECTOR_CLASS(klass) (G_TYPE_CHECK_CLASS_CAST(klass, VISU_TYPE_DATA_COLORIZER_VECTOR, VisuDataColorizerVectorClass)) /** * VISU_IS_DATA_COLORIZER_VECTOR: * @obj: a #GObject to test. * * Test if the given @ogj is of the type of #VisuDataColorizerVector object. */ #define VISU_IS_DATA_COLORIZER_VECTOR(obj) (G_TYPE_CHECK_INSTANCE_TYPE(obj, VISU_TYPE_DATA_COLORIZER_VECTOR)) /** * VISU_IS_DATA_COLORIZER_VECTOR_CLASS: * @klass: a #GObjectClass to test. * * Test if the given @klass is of the type of #VisuDataColorizerVectorClass class. */ #define VISU_IS_DATA_COLORIZER_VECTOR_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE(klass, VISU_TYPE_DATA_COLORIZER_VECTOR)) /** * VISU_DATA_COLORIZER_VECTOR_GET_CLASS: * @obj: a #GObject to get the class of. * * It returns the class of the given @obj. */ #define VISU_DATA_COLORIZER_VECTOR_GET_CLASS(obj) (G_TYPE_INSTANCE_GET_CLASS(obj, VISU_TYPE_DATA_COLORIZER_VECTOR, VisuDataColorizerVectorClass)) /** * VisuDataColorizerVector: * * Common name to refer to a #_VisuDataColorizerVector. */ typedef struct _VisuDataColorizerVector VisuDataColorizerVector; struct _VisuDataColorizerVector { VisuDataColorizerShaded parent; }; /** * VisuDataColorizerVectorClass: * @parent: its parent. * * Interface for class that can represent #VisuDataColorizerVector. * * Since: 3.8 */ typedef struct _VisuDataColorizerVectorClass VisuDataColorizerVectorClass; struct _VisuDataColorizerVectorClass { VisuDataColorizerShadedClass parent; }; /** * visu_data_colorizer_vector_get_type: * * This method returns the type of #VisuDataColorizerVector, use * VISU_TYPE_DATA_COLORIZER_VECTOR instead. * * Since: 3.8 * * Returns: the type of #VisuDataColorizerVector. */ GType visu_data_colorizer_vector_get_type(void); VisuDataColorizerVector* visu_data_colorizer_vector_new(); gboolean visu_data_colorizer_vector_setNodeModel(VisuDataColorizerVector *colorizer, VisuNodeValuesVector *model); G_END_DECLS #endif v_sim-3.8.0/src/extraFunctions/vectorProp.c000066400000000000000000000277311370110300500207510ustar00rootroot00000000000000/* EXTRAITS DE LA LICENCE Copyright CEA, contributeurs : Damien CALISTE, laboratoire L_Sim, (2015) Adresse mèl : CALISTE, damien P caliste AT cea P fr. Ce logiciel est un programme informatique servant à visualiser des structures atomiques dans un rendu pseudo-3D. Ce logiciel est régi par la licence CeCILL soumise au droit français et respectant les principes de diffusion des logiciels libres. Vous pouvez utiliser, modifier et/ou redistribuer ce programme sous les conditions de la licence CeCILL telle que diffusée par le CEA, le CNRS et l'INRIA sur le site "http://www.cecill.info". Le fait que vous puissiez accéder à cet en-tête signifie que vous avez pris connaissance de la licence CeCILL, et que vous en avez accepté les termes (cf. le fichier Documentation/licence.fr.txt fourni avec ce logiciel). */ /* LICENCE SUM UP Copyright CEA, contributors : Damien CALISTE, laboratoire L_Sim, (2015) E-mail address: CALISTE, damien P caliste AT cea P fr. This software is a computer program whose purpose is to visualize atomic configurations in 3D. This software is governed by the CeCILL license under French law and abiding by the rules of distribution of free software. You can use, modify and/ or redistribute the software under the terms of the CeCILL license as circulated by CEA, CNRS and INRIA at the following URL "http://www.cecill.info". The fact that you are presently reading this means that you have had knowledge of the CeCILL license and that you accept its terms. You can find a copy of this licence shipped with this software at Documentation/licence.en.txt. */ #include "vectorProp.h" #include #include #include /** * SECTION:vectorProp * @short_description: define a #VisuNodeValues object to handle * vectorial node information. * * Defines a #VisuNodeValues object to store a vector * information on nodes. One can set and retrieve vector on each node * as cartesian (see visu_node_values_vector_setAt() or * visu_node_values_vector_getAt() functions) or spherical coordinates * (see visu_node_values_vector_setAtSpherical() and * visu_node_values_vector_getAtSpherical() functions). */ static gboolean _setAt(VisuNodeValues *vals, const VisuNode *node, GValue *value); static gfloat _nrm2(const VisuNodeValuesFarray *vect, const GValue *value); static void _shift(const VisuNodeValuesVector *vect, const VisuNode *node, gfloat dxyz[3]); static gboolean _parse(VisuNodeValues *vals, VisuNode *node, const gchar *from); static gchar* _serialize(const VisuNodeValues *vals, const VisuNode *node); G_DEFINE_TYPE(VisuNodeValuesVector, visu_node_values_vector, VISU_TYPE_NODE_VALUES_FARRAY) static void visu_node_values_vector_class_init(VisuNodeValuesVectorClass *klass) { /* Connect the overloading methods. */ VISU_NODE_VALUES_CLASS(klass)->setAt = _setAt; VISU_NODE_VALUES_CLASS(klass)->parse = _parse; VISU_NODE_VALUES_CLASS(klass)->serialize = _serialize; VISU_NODE_VALUES_FARRAY_CLASS(klass)->nrm2 = _nrm2; klass->shift = _shift; } static void visu_node_values_vector_init(VisuNodeValuesVector *self _U_) { } static gfloat _nrm2(const VisuNodeValuesFarray *vect _U_, const GValue *value) { gfloat *diff; diff = (gfloat*)g_value_get_pointer(value); if (diff) return diff[3] * diff[3]; else return -1.f; } static gboolean _parse(VisuNodeValues *vals, VisuNode *node, const gchar *from) { gfloat fvals[6]; gchar **datas; guint i; GValue value = {0, {{0}, {0}}}; g_return_val_if_fail(from, FALSE); datas = g_strsplit_set(from, "(;)", 3); for (i = 0; datas[i]; i++) if (sscanf(from, "%f", fvals + i) != 1) { g_strfreev(datas); return FALSE; } g_strfreev(datas); g_value_init(&value, G_TYPE_POINTER); g_value_set_pointer(&value, fvals); return _setAt(vals, node, &value); } static gchar* _serialize(const VisuNodeValues *vals, const VisuNode *node) { GValue value = {0, {{0}, {0}}}; float *fvals; if (!visu_node_values_getAt(vals, node, &value)) return (gchar*)0; fvals = (float*)g_value_get_pointer(&value); if (fvals) return g_strdup_printf("(%#.3g ; %#.3g ; %#.3g)", fvals[0], fvals[1], fvals[2]); else return (gchar*)0; } /** * visu_node_values_vector_new: * @arr: a #VisuNodeArray object. * @label: a translatable label. * * Create a new vector field located on nodes. * * Since: 3.8 * * Returns: (transfer full): a newly created #VisuNodeValuesVector object. **/ VisuNodeValuesVector* visu_node_values_vector_new(VisuNodeArray *arr, const gchar *label) { VisuNodeValuesVector *vals; vals = VISU_NODE_VALUES_VECTOR(g_object_new(VISU_TYPE_NODE_VALUES_VECTOR, "nodes", arr, "label", label, "type", G_TYPE_FLOAT, "n-elements", 6, NULL)); return vals; } static const gfloat zeros[3] = {0.f, 0.f, 0.f}; /** * visu_node_values_vector_getAt: * @vect: a #VisuNodeValuesVector object. * @node: a #VisuNode object. * * Retrieves the vector hosted on @node. * * Since: 3.8 * * Returns: (array fixed-size=3) (transfer none): the coordinates of * vector for @node. **/ const gfloat* visu_node_values_vector_getAt(const VisuNodeValuesVector *vect, const VisuNode *node) { GValue diffValue = G_VALUE_INIT; const gfloat *diff; g_return_val_if_fail(VISU_IS_NODE_VALUES_VECTOR(vect), zeros); visu_node_values_getAt(VISU_NODE_VALUES(vect), node, &diffValue); diff = (const gfloat*)g_value_get_pointer(&diffValue); return (diff) ? diff : zeros; } /** * visu_node_values_vector_getAtSpherical: * @vect: a #VisuNodeValuesVector object. * @node: a #VisuNode object. * * Retrieves the vector hosted on @node in spherical coordinates. * * Since: 3.8 * * Returns: (array fixed-size=3) (allow-none): the spherical coordinates. **/ const gfloat* visu_node_values_vector_getAtSpherical(const VisuNodeValuesVector *vect, const VisuNode *node) { GValue diffValue = G_VALUE_INIT; const gfloat *diff; g_return_val_if_fail(VISU_IS_NODE_VALUES_VECTOR(vect), FALSE); visu_node_values_getAt(VISU_NODE_VALUES(vect), node, &diffValue); diff = (const gfloat*)g_value_get_pointer(&diffValue); if (!diff) return (const gfloat*)0; return diff + 3; } /** * visu_node_values_vector_getAtIterSpherical: * @vect: a #VisuNodeValuesVector object. * @iter: a #VisuNodeValuesIter object. * * Retrieves the vector hosted on @iter in spherical coordinates. * * Since: 3.8 * * Returns: (array fixed-size=3) (allow-none): the spherical coordinates. **/ const gfloat* visu_node_values_vector_getAtIterSpherical(const VisuNodeValuesVector *vect, const VisuNodeValuesIter *iter) { const gfloat *diff; g_return_val_if_fail(VISU_IS_NODE_VALUES_VECTOR(vect) && iter, (const gfloat*)0); diff = (const gfloat*)g_value_get_pointer(&iter->value); if (!diff) return (const gfloat*)0; return diff + 3; } static void _shift(const VisuNodeValuesVector *vect _U_, const VisuNode *node _U_, gfloat dxyz[3]) { dxyz[0] = 0.f; dxyz[1] = 0.f; dxyz[2] = 0.f; } /** * visu_node_values_vector_getShift: * @vect: a #VisuNodeValuesVector object. * @node: a #VisuNode pointer. * @dxyz: (out caller-allocates) (array fixed-size=3): a vector * location. * * Get the shift value that is applied to every vector of @vect. * * Since: 3.8 **/ void visu_node_values_vector_getShift(const VisuNodeValuesVector *vect, const VisuNode *node, gfloat dxyz[3]) { VisuNodeValuesVectorClass *klass = VISU_NODE_VALUES_VECTOR_GET_CLASS(vect); g_return_if_fail(klass && klass->shift); klass->shift(vect, node, dxyz); } static gboolean _setAt(VisuNodeValues *vect, const VisuNode *node, GValue *value) { gfloat *vals; gboolean res; vals = (gfloat*)g_value_get_pointer(value); if (vals[3] == G_MAXFLOAT) tool_matrix_cartesianToSpherical(vals + 3, vals); else tool_matrix_sphericalToCartesian(vals, vals + 3); /* Chain up to parent. */ res = VISU_NODE_VALUES_CLASS(visu_node_values_vector_parent_class)->setAt(vect, node, value); return res; } /** * visu_node_values_vector_setAt: * @vect: a #VisuNodeValuesVector object. * @node: a #VisuNode object. * @dxyz: (array fixed-size=3): vector coordinates. * * Changes the vector hosted at @node for one of coordinates defined * by @dxyz. * * Since: 3.8 * * Returns: TRUE if vector for @node is indeed changed. **/ gboolean visu_node_values_vector_setAt(VisuNodeValuesVector *vect, const VisuNode *node, const gfloat dxyz[3]) { gfloat *vals, diff[6]; GValue diffValue = G_VALUE_INIT; visu_node_values_getAt(VISU_NODE_VALUES(vect), node, &diffValue); vals = (gfloat*)g_value_get_pointer(&diffValue); if (vals && vals[0] == dxyz[0] && vals[1] == dxyz[1] && vals[2] == dxyz[2]) return FALSE; diff[0] = dxyz[0]; diff[1] = dxyz[1]; diff[2] = dxyz[2]; diff[3] = G_MAXFLOAT; g_value_set_pointer(&diffValue, (gpointer)diff); return visu_node_values_setAt(VISU_NODE_VALUES(vect), node, &diffValue); } /** * visu_node_values_vector_setAtDbl: * @vect: a #VisuNodeValuesVector object. * @node: a #VisuNode object. * @dxyz: (array fixed-size=3): vector coordinates. * * Same as visu_node_values_vector_setAt() but for double values. * * Since: 3.8 * * Returns: TRUE if vector for @node is indeed changed. **/ gboolean visu_node_values_vector_setAtDbl(VisuNodeValuesVector *vect, const VisuNode *node, const double dxyz[3]) { gfloat fxyz[3]; fxyz[0] = dxyz[0]; fxyz[1] = dxyz[1]; fxyz[2] = dxyz[2]; return visu_node_values_vector_setAt(vect, node, fxyz); } /** * visu_node_values_vector_setAtSpherical: * @vect: a #VisuNodeValuesVector object. * @node: a #VisuNode object. * @sph: (array fixed-size=3): spherical coordinates. * * Same as visu_node_values_vector_setAt() but using a spherical * coordinate description. * * Since: 3.8 * * Returns: TRUE if vector for @node is indeed changed. **/ gboolean visu_node_values_vector_setAtSpherical(VisuNodeValuesVector *vect, const VisuNode *node, const gfloat sph[3]) { gfloat *vals, diff[6]; GValue diffValue = G_VALUE_INIT; visu_node_values_getAt(VISU_NODE_VALUES(vect), node, &diffValue); vals = (gfloat*)g_value_get_pointer(&diffValue); if (vals && vals[3] == sph[0] && vals[4] == sph[1] && vals[5] == sph[2]) return FALSE; diff[0] = G_MAXFLOAT; diff[3] = sph[0]; diff[4] = sph[1]; diff[5] = sph[2]; g_value_set_pointer(&diffValue, (gpointer)diff); return visu_node_values_setAt(VISU_NODE_VALUES(vect), node, &diffValue); } /** * visu_node_values_vector_set: * @vect: a #VisuNodeValuesVector object. * @data: (element-type float): some vector coordinates. * * Assigns the coordinates stored in @data to each nodes in @vect. * * Since: 3.8 * * Returns: TRUE if @data has the same size as @vect. **/ gboolean visu_node_values_vector_set(VisuNodeValuesVector *vect, const GArray *data) { guint i; gboolean valid; VisuNodeValuesIter iter; g_object_freeze_notify(G_OBJECT(vect)); i = 0; valid = visu_node_values_iter_new(&iter, ITER_NODES_BY_NUMBER, VISU_NODE_VALUES(vect)); while (valid && i + 3 <= data->len) { visu_node_values_vector_setAt(vect, iter.iter.node, &g_array_index(data, float, i)); i += 3; valid = visu_node_values_iter_next(&iter); } g_object_thaw_notify(G_OBJECT(vect)); return (i == data->len); } v_sim-3.8.0/src/extraFunctions/vectorProp.h000066400000000000000000000137261370110300500207550ustar00rootroot00000000000000/* EXTRAITS DE LA LICENCE Copyright CEA, contributeurs : Damien CALISTE, laboratoire L_Sim, (2015) Adresse mèl : CALISTE, damien P caliste AT cea P fr. Ce logiciel est un programme informatique servant à visualiser des structures atomiques dans un rendu pseudo-3D. Ce logiciel est régi par la licence CeCILL soumise au droit français et respectant les principes de diffusion des logiciels libres. Vous pouvez utiliser, modifier et/ou redistribuer ce programme sous les conditions de la licence CeCILL telle que diffusée par le CEA, le CNRS et l'INRIA sur le site "http://www.cecill.info". Le fait que vous puissiez accéder à cet en-tête signifie que vous avez pris connaissance de la licence CeCILL, et que vous en avez accepté les termes (cf. le fichier Documentation/licence.fr.txt fourni avec ce logiciel). */ /* LICENCE SUM UP Copyright CEA, contributors : Damien CALISTE, laboratoire L_Sim, (2015) E-mail address: CALISTE, damien P caliste AT cea P fr. This software is a computer program whose purpose is to visualize atomic configurations in 3D. This software is governed by the CeCILL license under French law and abiding by the rules of distribution of free software. You can use, modify and/ or redistribute the software under the terms of the CeCILL license as circulated by CEA, CNRS and INRIA at the following URL "http://www.cecill.info". The fact that you are presently reading this means that you have had knowledge of the CeCILL license and that you accept its terms. You can find a copy of this licence shipped with this software at Documentation/licence.en.txt. */ #ifndef VECTORPROP_H #define VECTORPROP_H #include #include #include "floatProp.h" G_BEGIN_DECLS /** * VISU_TYPE_NODE_VALUES_VECTOR: * * return the type of #VisuNodeValuesVector. */ #define VISU_TYPE_NODE_VALUES_VECTOR (visu_node_values_vector_get_type ()) /** * VISU_NODE_VALUES_VECTOR: * @obj: a #GObject to cast. * * Cast the given @obj into #VisuNodeValuesVector type. */ #define VISU_NODE_VALUES_VECTOR(obj) (G_TYPE_CHECK_INSTANCE_CAST(obj, VISU_TYPE_NODE_VALUES_VECTOR, VisuNodeValuesVector)) /** * VISU_NODE_VALUES_VECTOR_CLASS: * @klass: a #GObjectClass to cast. * * Cast the given @klass into #VisuNodeValuesVectorClass. */ #define VISU_NODE_VALUES_VECTOR_CLASS(klass) (G_TYPE_CHECK_CLASS_CAST(klass, VISU_TYPE_NODE_VALUES_VECTOR, VisuNodeValuesVectorClass)) /** * VISU_IS_NODE_VALUES_VECTOR: * @obj: a #GObject to test. * * Test if the given @ogj is of the type of #VisuNodeValuesVector object. */ #define VISU_IS_NODE_VALUES_VECTOR(obj) (G_TYPE_CHECK_INSTANCE_TYPE(obj, VISU_TYPE_NODE_VALUES_VECTOR)) /** * VISU_IS_NODE_VALUES_VECTOR_CLASS: * @klass: a #GObjectClass to test. * * Test if the given @klass is of the type of #VisuNodeValuesVectorClass class. */ #define VISU_IS_NODE_VALUES_VECTOR_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE(klass, VISU_TYPE_NODE_VALUES_VECTOR)) /** * VISU_NODE_VALUES_VECTOR_GET_CLASS: * @obj: a #GObject to get the class of. * * It returns the class of the given @obj. */ #define VISU_NODE_VALUES_VECTOR_GET_CLASS(obj) (G_TYPE_INSTANCE_GET_CLASS(obj, VISU_TYPE_NODE_VALUES_VECTOR, VisuNodeValuesVectorClass)) /** * VisuNodeValuesVector: * * Common name to refer to a #_VisuNodeValuesVector. */ typedef struct _VisuNodeValuesVector VisuNodeValuesVector; struct _VisuNodeValuesVector { VisuNodeValuesFarray parent; }; /** * VisuNodeValuesVectorShift: * @vect: a #VisuNodeValuesVector object. * @node: a #VisuNode pointer: * @dxyz: (array fixed-size=3): a shift in cartesian coordinates. * * Prototype of functions used to define a shift between the centre of * @node and the origin of the stored vector for this node. */ typedef void (*VisuNodeValuesVectorShift)(const VisuNodeValuesVector *vect, const VisuNode *node, gfloat dxyz[3]); /** * VisuNodeValuesVectorClass: * @parent: private. * @shift: a routine to add a shift on each node. * * Common name to refer to a #_VisuNodeValuesVectorClass. */ typedef struct _VisuNodeValuesVectorClass VisuNodeValuesVectorClass; struct _VisuNodeValuesVectorClass { VisuNodeValuesFarrayClass parent; VisuNodeValuesVectorShift shift; }; /** * visu_node_values_vector_get_type: * * This method returns the type of #VisuNodeValuesVector, use * VISU_TYPE_NODE_VALUES_VECTOR instead. * * Since: 3.8 * * Returns: the type of #VisuNodeValuesVector. */ GType visu_node_values_vector_get_type(void); VisuNodeValuesVector* visu_node_values_vector_new(VisuNodeArray *arr, const gchar *label); const gfloat* visu_node_values_vector_getAt(const VisuNodeValuesVector *vect, const VisuNode *node); const gfloat* visu_node_values_vector_getAtSpherical(const VisuNodeValuesVector *vect, const VisuNode *node); const gfloat* visu_node_values_vector_getAtIterSpherical(const VisuNodeValuesVector *vect, const VisuNodeValuesIter *iter); void visu_node_values_vector_getShift(const VisuNodeValuesVector *vect, const VisuNode *node, gfloat dxyz[3]); gboolean visu_node_values_vector_setAt(VisuNodeValuesVector *vect, const VisuNode *node, const gfloat dxyz[3]); gboolean visu_node_values_vector_setAtSpherical(VisuNodeValuesVector *vect, const VisuNode *node, const gfloat sph[3]); gboolean visu_node_values_vector_setAtDbl(VisuNodeValuesVector *vect, const VisuNode *node, const double dxyz[3]); gboolean visu_node_values_vector_set(VisuNodeValuesVector *vect, const GArray *data); G_END_DECLS #endif v_sim-3.8.0/src/extraFunctions/vibration.c000066400000000000000000000704511370110300500206000ustar00rootroot00000000000000/* EXTRAITS DE LA LICENCE Copyright CEA, contributeurs : Jérémy BLANC et Damien CALISTE, laboratoire L_Sim, (2001-2005) Adresse mèl : BLANC, CALISTE, damien P caliste AT cea P fr. Ce logiciel est un programme informatique servant à visualiser des structures atomiques dans un rendu pseudo-3D. Ce logiciel est régi par la licence CeCILL soumise au droit français et respectant les principes de diffusion des logiciels libres. Vous pouvez utiliser, modifier et/ou redistribuer ce programme sous les conditions de la licence CeCILL telle que diffusée par le CEA, le CNRS et l'INRIA sur le site "http://www.cecill.info". Le fait que vous puissiez accéder à cet en-tête signifie que vous avez pris connaissance de la licence CeCILL, et que vous en avez accepté les termes (cf. le fichier Documentation/licence.fr.txt fourni avec ce logiciel). */ /* LICENCE SUM UP Copyright CEA, contributors : Jérémy BLANC et Damien CALISTE, laboratoire L_Sim, (2001-2005) E-mail address: BILLARD, not reachable any more ; CALISTE, damien P caliste AT cea P fr. This software is a computer program whose purpose is to visualize atomic configurations in 3D. This software is governed by the CeCILL license under French law and abiding by the rules of distribution of free software. You can use, modify and/ or redistribute the software under the terms of the CeCILL license as circulated by CEA, CNRS and INRIA at the following URL "http://www.cecill.info". The fact that you are presently reading this means that you have had knowledge of the CeCILL license and that you accept its terms. You can find a copy of this licence shipped with this software at Documentation/licence.en.txt. */ #include "vibration.h" #include #include /*for sinus*/ #include /* for spherical coordonates */ #include #include #include /** * SECTION:vibration * @short_description: Add a support to animate the node positions * with a phonon frequency. * * Define a way to store vibration or phonons to a #VisuData * object. One can store several phonons in one object, each phonon is * them represented by its id. The phonons can be animated on screen, * using a user defined frequency (visu_vibration_setUserFrequency) * and amplitue (visu_vibration_setAmplitude), by calling * visu_vibration_play(). * Phonons are set with visu_vibration_setCharacteristic() and * #VisuNode displacements are set with visu_vibration_setDisplacements(). */ /** * VISU_VIBRATION_ID: * * The default name used for the #VisuGlExt representing * vibrations, see visu_gl_ext_getFromName(). */ #define VISU_VIBRATION_ID "Vibration" #define AMPL_COEFF 0.5f /* Displacement vector per atom is (U+iV) = (Ux + iVx, ...). Current applied displacement on one atom is (dx, dy, dz). qr is the Q.R part of the exponential. */ enum { Ux, Uy, Uz, mod, theta, phi, Vx, Vy, Vz, dx, dy, dz, qr, nData }; struct _VisuVibrationPrivate { gboolean dispose_has_run; /* Parameters for the available phonons. */ guint n; float *q; float *omega; float *en; /* Array of all the displacement vectors. */ gboolean *complex; GArray **u; float *norm; /* Current applied frequency and amplitude, phonon id, time and delta time. */ float freq, ampl; gint iph; gfloat t; VisuAnimation *time_anim; /* Internal parameters. */ gulong signal; } Vibration; enum { PROP_0, N_MODE_PROP, FREQ_PROP, AMPL_PROP, TIME_PROP, N_PROP }; static GParamSpec *_properties[N_PROP]; static void visu_vibration_dispose (GObject* obj); static void visu_vibration_finalize (GObject* obj); static void visu_vibration_get_property(GObject* obj, guint property_id, GValue *value, GParamSpec *pspec); static void visu_vibration_set_property(GObject* obj, guint property_id, const GValue *value, GParamSpec *pspec); static gfloat visu_vibration_nrm2(const VisuNodeValuesFarray *vect, const GValue *value); static void _shift(const VisuNodeValuesVector *vect, const VisuNode *node, gfloat dxyz[3]); static void visu_animatable_interface_init(VisuAnimatableInterface *iface); static VisuAnimation* _getAnimation(const VisuAnimatable *animatable, const gchar *prop); static void onPopulationChanged(VisuVibration *vib, GArray *ids, VisuData *dataObj); static void onPositionChanged(VisuVibration *vib, GArray *ids, VisuData *dataObj); static void vibrationAt(VisuVibration *vib, gboolean withPhase); G_DEFINE_TYPE_WITH_CODE(VisuVibration, visu_vibration, VISU_TYPE_NODE_VALUES_VECTOR, G_ADD_PRIVATE(VisuVibration) G_IMPLEMENT_INTERFACE(VISU_TYPE_ANIMATABLE, visu_animatable_interface_init)) static void visu_vibration_class_init(VisuVibrationClass *klass) { /* Connect the overloading methods. */ G_OBJECT_CLASS(klass)->dispose = visu_vibration_dispose; G_OBJECT_CLASS(klass)->finalize = visu_vibration_finalize; G_OBJECT_CLASS(klass)->set_property = visu_vibration_set_property; G_OBJECT_CLASS(klass)->get_property = visu_vibration_get_property; VISU_NODE_VALUES_FARRAY_CLASS(klass)->nrm2 = visu_vibration_nrm2; VISU_NODE_VALUES_VECTOR_CLASS(klass)->shift = _shift; /** * VisuVibration::n-modes: * * Holds the number of modes for this vibration. * * Since: 3.8 */ _properties[N_MODE_PROP] = g_param_spec_uint("n-modes", "N-modes", "number of modes", 1, G_MAXINT, 1, G_PARAM_READWRITE | G_PARAM_CONSTRUCT_ONLY); /** * VisuVibration::frequency: * * Holds the frequency at which nodes oscilate when animated. * * Since: 3.8 */ _properties[FREQ_PROP] = g_param_spec_float("frequency", "Frequency", "oscilation frequency", 0.f, 50.f, 5.f, G_PARAM_READWRITE); /** * VisuVibration::amplitude: * * Holds the amplitude at which nodes oscilate when animated. * * Since: 3.8 */ _properties[AMPL_PROP] = g_param_spec_float("amplitude", "Amplitude", "oscilation amplitude", 0.f, G_MAXFLOAT, 1.f, G_PARAM_READWRITE); /** * VisuVibration::reduced-time: * * The time during an animation, given in reduce value [0;1] mapping * the real time [0;1/frequency]. * * Since: 3.8 */ _properties[TIME_PROP] = g_param_spec_float("reduced-time", "Reduced time", "time during an animation", 0.f, G_MAXFLOAT, 0.f, G_PARAM_READWRITE); g_object_class_install_properties(G_OBJECT_CLASS(klass), N_PROP, _properties); } static void visu_animatable_interface_init(VisuAnimatableInterface *iface) { iface->get_animation = _getAnimation; } static void visu_vibration_init(VisuVibration *self) { self->priv = visu_vibration_get_instance_private(self); self->priv->dispose_has_run = FALSE; self->priv->q = (float*)0; self->priv->omega = (float*)0; self->priv->en = (float*)0; self->priv->u = (GArray**)0; self->priv->complex = (gboolean*)0; self->priv->norm = (float*)0; self->priv->n = 0; self->priv->iph = -1; self->priv->t = 0.f; self->priv->freq = 5.f; self->priv->ampl = 1.f; self->priv->time_anim = visu_animation_new(G_OBJECT(self), "reduced-time"); } static void visu_vibration_dispose(GObject* obj) { VisuVibration *self; guint i; self = VISU_VIBRATION(obj); if (self->priv->dispose_has_run) return; self->priv->dispose_has_run = TRUE; g_object_unref(self->priv->time_anim); for (i = 0; i < self->priv->n; i++) if (self->priv->u[i]) g_array_unref(self->priv->u[i]); /* Chain up to the parent class */ G_OBJECT_CLASS(visu_vibration_parent_class)->dispose(obj); } /* This method is called once only. */ static void visu_vibration_finalize(GObject* obj) { VisuVibration *self; g_return_if_fail(obj); self = VISU_VIBRATION(obj); g_free(self->priv->q); g_free(self->priv->omega); g_free(self->priv->en); g_free(self->priv->u); g_free(self->priv->complex); g_free(self->priv->norm); /* Chain up to the parent class */ G_OBJECT_CLASS(visu_vibration_parent_class)->finalize(obj); } static void visu_vibration_get_property(GObject* obj, guint property_id, GValue *value, GParamSpec *pspec) { VisuVibration *self = VISU_VIBRATION(obj); switch (property_id) { case N_MODE_PROP: g_value_set_uint(value, self->priv->n); break; case FREQ_PROP: g_value_set_float(value, self->priv->freq); break; case AMPL_PROP: g_value_set_float(value, self->priv->ampl); break; case TIME_PROP: if (visu_animation_isRunning(self->priv->time_anim)) visu_animation_getTo(self->priv->time_anim, value); else g_value_set_float(value, tool_modulo_float(self->priv->t, 1.f)); break; default: /* We don't have any other property... */ G_OBJECT_WARN_INVALID_PROPERTY_ID(obj, property_id, pspec); break; } } static void visu_vibration_set_property(GObject* obj, guint property_id, const GValue *value, GParamSpec *pspec) { VisuVibration *self = VISU_VIBRATION(obj); switch (property_id) { case N_MODE_PROP: self->priv->n = g_value_get_uint(value); self->priv->q = g_malloc(sizeof(float) * self->priv->n * 3); self->priv->omega = g_malloc0(sizeof(float) * self->priv->n); self->priv->en = g_malloc0(sizeof(float) * self->priv->n); self->priv->norm = g_malloc(sizeof(float) * self->priv->n); self->priv->u = g_malloc0(sizeof(GArray*) * self->priv->n); self->priv->complex = g_malloc(sizeof(gboolean) * self->priv->n); break; case FREQ_PROP: visu_vibration_setUserFrequency(self, g_value_get_float(value)); break; case AMPL_PROP: visu_vibration_setAmplitude(self, g_value_get_float(value)); break; case TIME_PROP: if (!visu_animatable_animateFloat(VISU_ANIMATABLE(self), self->priv->time_anim, g_value_get_float(value), 500, FALSE, VISU_ANIMATION_SIN)) visu_vibration_setTime(self, g_value_get_float(value)); break; default: /* We don't have any other property... */ G_OBJECT_WARN_INVALID_PROPERTY_ID(obj, property_id, pspec); break; } } static gfloat visu_vibration_nrm2(const VisuNodeValuesFarray *vect _U_, const GValue *value) { gfloat *diff; diff = (gfloat*)g_value_get_pointer(value); if (diff) return diff[mod] * diff[mod] + diff[Vx] * diff[Vx] + diff[Vy] * diff[Vy] + diff[Vz] * diff[Vz]; else return -1.f; } static VisuAnimation* _getAnimation(const VisuAnimatable *animatable, const gchar *prop) { g_return_val_if_fail(VISU_IS_VIBRATION(animatable), (VisuAnimation*)0); if (!g_strcmp0(prop, "reduced-time")) return VISU_VIBRATION(animatable)->priv->time_anim; return (VisuAnimation*)0; } /** * visu_vibration_new: * @data: a #VisuData object. * @label: a label. * @n: an integer. * * Creates a #VisuVibration object to store @n vibration modes for @data. * * Since: 3.8 * * Returns: (transfer full): a newly created #VisuVibration object. **/ VisuVibration* visu_vibration_new(VisuData *data, const gchar *label, guint n) { VisuVibration *vib; vib = VISU_VIBRATION(g_object_new(VISU_TYPE_VIBRATION, "nodes", data, "label", label, "type", G_TYPE_FLOAT, "n-elements", nData, "n-modes", n, NULL)); g_signal_connect_swapped(G_OBJECT(data), "PopulationIncrease", G_CALLBACK(onPopulationChanged), (gpointer)vib); vib->priv->signal = g_signal_connect_swapped(G_OBJECT(data), "position-changed", G_CALLBACK(onPositionChanged), (gpointer)vib); return vib; } /** * visu_vibration_setDisplacements: * @vib: a #VisuVibration object. * @iph: a phonon id. * @vibes: (element-type float): a set of displacement vectors. * @complex: a flag. * * visu_vibration_init() must have been call before. This routine is * used to define a set of displacement vectors, corresponding to one * phonon. The displacement vectors can be @complex, in that case * @vibes contains 6 values for each #VisuNode. * * Since: 3.5 * * Returns: TRUE on success. */ gboolean visu_vibration_setDisplacements(VisuVibration *vib, guint iph, const GArray *vibes, gboolean complex) { gfloat u[6], *vals; guint i, nSet; g_return_val_if_fail(VISU_IS_VIBRATION(vib) && vibes, FALSE); g_return_val_if_fail(iph < vib->priv->n, FALSE); DBG_fprintf(stderr, "Vibration: set vibration data for phonon %d.\n", iph); nSet = (complex) ? 6 : 3; /* We copy the displacement information into the Vibration structure for the given phonon. */ vib->priv->norm[iph] = 0.f; if (vib->priv->u[iph]) g_array_unref(vib->priv->u[iph]); vib->priv->u[iph] = g_array_sized_new(FALSE, FALSE, sizeof(gfloat), vibes->len); g_array_append_vals(vib->priv->u[iph], vibes->data, vibes->len); vib->priv->complex[iph] = complex; for (i = 0; i < vibes->len / nSet; i++) { vals = &g_array_index(vibes, gfloat, i * nSet); u[0] = vals[0]; u[1] = vals[1]; u[2] = vals[2]; u[3] = (complex) ? vals[3] : 0.f; u[4] = (complex) ? vals[4] : 0.f; u[5] = (complex) ? vals[5] : 0.f; vib->priv->norm[iph] = MAX(u[0] * u[0] + u[1] * u[1] + u[2] * u[2] + u[3] * u[3] + u[4] * u[4] + u[5] * u[5], vib->priv->norm[iph]); DBG_fprintf(stderr, "| %d -> (%g,%g,%g) + i (%g,%g,%g)\n", i, u[0], u[1], u[2], u[3], u[4], u[5]); } DBG_fprintf(stderr, "Vibration: set norm to %f.\n", vib->priv->norm[iph]); return TRUE; } static gfloat _getPhase(const VisuVibration *vib, guint iph, const VisuData *data, const VisuBox *box, const VisuNode *node) { gfloat xyz[3], red[3]; /* Set the phase. */ visu_data_getNodePosition(data, node, xyz); visu_box_convertXYZtoBoxCoordinates(box, red, xyz); return 2.f * G_PI * (red[0] * vib->priv->q[3 * iph + 0] + red[1] * vib->priv->q[3 * iph + 1] + red[2] * vib->priv->q[3 * iph + 2]); } /** * visu_vibration_setCurrentMode: * @vib: a #VisuVibration object. * @iph: a phonon id. * @error: a location for a possible error. * * Set all node displacements to zero and setup the displacement * vector (u+iv) for each #VisuNode. After this call, * visu_vibration_play() will move the nodes according to their vibration. * * Since: 3.5 * * Returns: TRUE if its the first time #VisuNodes are displaced. */ gboolean visu_vibration_setCurrentMode(VisuVibration *vib, guint iph, GError **error) { gboolean valid; VisuNodeValuesIter iter; VisuNodeArray *nodes; VisuBox *box; gfloat vibes[nData], *vals; gint iNode; guint nSet; g_return_val_if_fail(VISU_IS_VIBRATION(vib), FALSE); g_return_val_if_fail(iph < vib->priv->n, FALSE); DBG_fprintf(stderr, "Vibration: set current mode to %d.\n", iph); nodes = visu_node_values_getArray(VISU_NODE_VALUES(vib)); if (!vib->priv->u[iph] && VISU_IS_DATA_LOADABLE(nodes)) { g_signal_handler_block(G_OBJECT(nodes), vib->priv->signal); visu_data_freePopulation(VISU_DATA(nodes)); valid = visu_data_loadable_load(VISU_DATA_LOADABLE(nodes), iph, (GCancellable*)0, error); g_signal_handler_unblock(G_OBJECT(nodes), vib->priv->signal); if (!valid) { g_object_unref(nodes); return FALSE; } } g_return_val_if_fail(iph < vib->priv->n, FALSE); g_return_val_if_fail(vib->priv->u[iph], FALSE); vib->priv->iph = iph; nSet = vib->priv->complex[iph] ? 6 : 3; g_return_val_if_fail(vib->priv->u[iph]->len == visu_node_array_getNOriginalNodes(nodes) * nSet, FALSE); visu_vibration_resetPosition(vib); /* We copy for all the nodes the displacements into the VISU_VIBRATION_ID node property for each node*/ box = visu_boxed_getBox(VISU_BOXED(nodes)); valid = visu_node_values_iter_new(&iter, ITER_NODES_BY_TYPE, VISU_NODE_VALUES(vib)); while (valid) { iNode = visu_node_array_getOriginal(nodes, iter.iter.node->number); iNode = (iNode >= 0) ? iNode : (int)iter.iter.node->number; vals = &g_array_index(vib->priv->u[iph], gfloat, iNode * nSet); vibes[Ux] = vals[0]; vibes[Uy] = vals[1]; vibes[Uz] = vals[2]; vibes[mod] = G_MAXFLOAT; vibes[Vx] = vib->priv->complex[iph] ? vals[3] : 0.f; vibes[Vy] = vib->priv->complex[iph] ? vals[4] : 0.f; vibes[Vz] = vib->priv->complex[iph] ? vals[5] : 0.f; vibes[dx] = 0.f; vibes[dy] = 0.f; vibes[dz] = 0.f; vibes[qr] = _getPhase(vib, iph, VISU_DATA(nodes), box, iter.iter.node); g_value_set_pointer(&iter.value, vibes); visu_node_values_setAt(VISU_NODE_VALUES(vib), iter.iter.node, &iter.value); valid = visu_node_values_iter_next(&iter); } g_object_unref(nodes); if (vib->priv->t != 0.f) vibrationAt(vib, TRUE); return TRUE; } /** * visu_vibration_setCharacteristic: * @vib: a #VisuVibration object. * @iph: a phonon id. * @q: a reciprocal vector. * @en: the phonon energy. * @omega: the phonon frequency. * * This routine is used to define the characteristics of a given * phonon. * * Since: 3.5 * * Returns: TRUE on success. */ gboolean visu_vibration_setCharacteristic(VisuVibration *vib, guint iph, const float q[3], float en, float omega) { g_return_val_if_fail(VISU_IS_VIBRATION(vib), FALSE); g_return_val_if_fail(iph < vib->priv->n, FALSE); vib->priv->q[iph * 3 + 0] = q[0]; vib->priv->q[iph * 3 + 1] = q[1]; vib->priv->q[iph * 3 + 2] = q[2]; vib->priv->omega[iph] = omega; vib->priv->en[iph] = en; return TRUE; } /** * visu_vibration_getCharacteristic: * @vib: a #VisuVibration object. * @iph: a phonon id. * @q: a location for the reciprocal vector. * @en: a locattion for the phonon energy. * @omega: a location for the phonon frequency. * * This routine is used to get the characteristics of a given * phonon, see visu_vibration_setCharacteristic() to set them. * * Since: 3.5 * * Returns: TRUE on success. */ gboolean visu_vibration_getCharacteristic(const VisuVibration *vib, guint iph, float q[3], float *en, float *omega) { g_return_val_if_fail(VISU_IS_VIBRATION(vib), FALSE); g_return_val_if_fail(iph < vib->priv->n, FALSE); q[0] = vib->priv->q[iph * 3 + 0]; q[1] = vib->priv->q[iph * 3 + 1]; q[2] = vib->priv->q[iph * 3 + 2]; if (omega) *omega = vib->priv->omega[iph]; if (en) *en = vib->priv->en[iph]; return TRUE; } /** * visu_vibration_setUserFrequency: * @vib: a #VisuVibration object. * @freq: a frequency. * * Change the frequency at which phonons are played with visu_vibration_play(). * * Since: 3.5 */ gboolean visu_vibration_setUserFrequency(VisuVibration *vib, float freq) { float f; g_return_val_if_fail(VISU_IS_VIBRATION(vib), FALSE); g_return_val_if_fail(freq > 0.f || vib->priv->iph >= 0, FALSE); if (freq > 0.f) f = freq; else f = vib->priv->omega[vib->priv->iph] ? vib->priv->omega[vib->priv->iph] : 1.f; if (f == vib->priv->freq) return FALSE; vib->priv->freq = f; g_object_notify_by_pspec(G_OBJECT(vib), _properties[FREQ_PROP]); if (visu_animation_isRunning(vib->priv->time_anim)) visu_vibration_animate(vib); return TRUE; } /** * visu_vibration_setAmplitude: * @vib: a #VisuVibration object. * @ampl: an amplitude. * * Change the amplitude at which phonon are displayed on screen when * using visu_vibration_play(). * * Since: 3.5 * * Returns: TRUE if amplitude is actually changed. */ gboolean visu_vibration_setAmplitude(VisuVibration *vib, float ampl) { g_return_val_if_fail(VISU_IS_VIBRATION(vib), FALSE); if (vib->priv->ampl == ampl) return FALSE; vib->priv->ampl = ampl; g_object_notify_by_pspec(G_OBJECT(vib), _properties[AMPL_PROP]); if (visu_animation_isRunning(vib->priv->time_anim)) visu_vibration_animate(vib); else vibrationAt(vib, TRUE); return TRUE; } /** * visu_vibration_setTime: * @vib: a #VisuVibration object. * @at: a given reduced time in [0;1]. * * Defines the current time offset used to displace nodes according to * phonon distortions. * * Since: 3.8 * * Returns: TRUE if value has been actually changed. **/ gboolean visu_vibration_setTime(VisuVibration *vib, gfloat at) { gfloat t; g_return_val_if_fail(VISU_IS_VIBRATION(vib), FALSE); t = tool_modulo_float(at, 1.f); if (vib->priv->t == t) return FALSE; vib->priv->t = t; g_object_notify_by_pspec(G_OBJECT(vib), _properties[TIME_PROP]); vibrationAt(vib, TRUE); return TRUE; } /** * visu_vibration_animate: * @vib: a #VisuVibration object. * * Starts animating phonons. * * Since: 3.8 **/ void visu_vibration_animate(VisuVibration *vib) { g_return_if_fail(VISU_IS_VIBRATION(vib)); if (visu_animation_isRunning(vib->priv->time_anim)) visu_animation_abort(vib->priv->time_anim); visu_animatable_animateFloat(VISU_ANIMATABLE(vib), vib->priv->time_anim, vib->priv->t + 1.f, 5000.f / vib->priv->freq, TRUE, VISU_ANIMATION_LINEAR); } /** * visu_vibration_getNPhonons: * @vib: a #VisuVibration object. * * Retrieves the number of phonons in @vib. * * Since: 3.5 * * Returns: a number of phonons. */ guint visu_vibration_getNPhonons(VisuVibration *vib) { g_return_val_if_fail(VISU_IS_VIBRATION(vib), 0); return vib->priv->n; } /** * visu_vibration_getCurrentMode: * @data: a #VisuData object. * * Retrieves the phonon that is currently applied to @data. * * Since: 3.5 * * Returns: a phonon id. */ /* guint visu_vibration_getCurrentMode(VisuData *data) */ /* { */ /* Vibration *vib; */ /* g_return_val_if_fail(data, 0); */ /* vib = (Vibration*)g_object_get_data(G_OBJECT(data), "tmp_vib_object"); */ /* g_return_val_if_fail(vib, 0); */ /* return vib->iph; */ /* } */ static void _shift(const VisuNodeValuesVector *vect, const VisuNode *node, gfloat dxyz[3]) { GValue vibeValue = G_VALUE_INIT; gfloat *values; dxyz[0] = 0.f; dxyz[1] = 0.f; dxyz[2] = 0.f; visu_node_values_getAt(VISU_NODE_VALUES(vect), node, &vibeValue); values = (float*)g_value_get_pointer(&vibeValue); if (!values) return; dxyz[0] = values[dx]; dxyz[1] = values[dy]; dxyz[2] = values[dz]; } static void vibrationAt(VisuVibration *vib, gboolean withPhase) { float t, c, wdtr, wdti, dU[3]; gfloat *dxyz; VisuNodeValuesIter iter; VisuNodeArray *data; g_return_if_fail(VISU_IS_VIBRATION(vib)); if (vib->priv->iph < 0) return; c = AMPL_COEFF * vib->priv->ampl / vib->priv->norm[vib->priv->iph]; t = -2.f * G_PI * vib->priv->t; DBG_fprintf(stderr, "Vibration: incr %d\n", withPhase); DBG_fprintf(stderr, " | t = %g, w = %g.\n", vib->priv->t, vib->priv->freq); DBG_fprintf(stderr, " | c = %g, t = %g.\n", c, t); data = visu_node_values_getArray(VISU_NODE_VALUES(vib)); visu_node_array_startMoving(data); for (visu_node_values_iter_new(&iter, ITER_NODES_BY_TYPE, VISU_NODE_VALUES(vib)); iter.iter.node; visu_node_values_iter_next(&iter)) { dxyz = (gfloat*)visu_node_values_farray_getAtIter(VISU_NODE_VALUES_FARRAY(vib), &iter); /* calculate xyz(t) */ if (dxyz) { DBG_fprintf(stderr, " | dx = %f, dy = %f, dz = %f\n", dxyz[mod], dxyz[theta], dxyz[phi]); wdtr = c * sin(t + (withPhase ? dxyz[qr] : 0.f)); wdti = -c * cos(t + (withPhase ? dxyz[qr] : G_PI_2)); dU[0] = dxyz[Ux] * wdtr + dxyz[Vx] * wdti - dxyz[dx]; dU[1] = dxyz[Uy] * wdtr + dxyz[Vy] * wdti - dxyz[dy]; dU[2] = dxyz[Uz] * wdtr + dxyz[Vz] * wdti - dxyz[dz]; visu_node_array_shiftNode(data, iter.iter.node->number, dU); dxyz[dx] += dU[0]; dxyz[dy] += dU[1]; dxyz[dz] += dU[2]; DBG_fprintf(stderr, " | dx = %f, dy = %f, dz = %f\n", dU[0], dU[1], dU[2]); } } g_signal_handler_block(G_OBJECT(data), vib->priv->signal); visu_node_array_completeMoving(data); g_signal_handler_unblock(G_OBJECT(data), vib->priv->signal); g_object_unref(data); } /** * visu_vibration_resetPosition: * @vib: a #VisuVibration object. * * Reset the node position of the given VisuData. * * Since: 3.5 */ void visu_vibration_resetPosition(VisuVibration *vib) { visu_vibration_setTime(vib, 0.f); vibrationAt(vib, FALSE); } /** * visu_vibration_setZeroTime: * @vib: a #VisuVibration object. * * Reset the position of phonons to use position at time equals zero * (so applying just the q vector displacement). * * Since: 3.5 */ void visu_vibration_setZeroTime(VisuVibration *vib) { visu_vibration_setTime(vib, 0.f); vibrationAt(vib, TRUE); } static void onPopulationChanged(VisuVibration *vib, GArray *ids, VisuData *dataObj) { guint i; VisuNode *node; VisuBox *box; GValue vibeValue = {0.0, {{0.0}, {0.0}}}; float *dxyz; if (vib->priv->iph < 0 || !ids) return; DBG_fprintf(stderr, "Vibration: on population increase recalculate phase.\n"); box = visu_boxed_getBox(VISU_BOXED(dataObj)); /* We need to recalculate the phase of the new ones. */ for (i = 0; i < ids->len; i++) { node = visu_node_array_getFromId(VISU_NODE_ARRAY(dataObj), g_array_index(ids, guint, i)); visu_node_values_getAt(VISU_NODE_VALUES(vib), node, &vibeValue); dxyz = (float*)g_value_get_pointer(&vibeValue); g_return_if_fail(dxyz); dxyz[qr] = _getPhase(vib, vib->priv->iph, dataObj, box, node); } } static void onPositionChanged(VisuVibration *vib, GArray *ids, VisuData *dataObj) { VisuNodeValuesIter iter; VisuBox *box; float *dxyz; gboolean valid; guint i; VisuNode *node; GValue vibeValue = G_VALUE_INIT; DBG_fprintf(stderr, "Vibration: on position changed recalculate phase.\n"); if (vib->priv->iph < 0 || !vib->priv->u[vib->priv->iph]) return; box = visu_boxed_getBox(VISU_BOXED(dataObj)); if (!ids) { valid = visu_node_values_iter_new(&iter, ITER_NODES_BY_TYPE, VISU_NODE_VALUES(vib)); while (valid) { /* Convert GValue to Float[3] */ dxyz = (float*)g_value_get_pointer(&iter.value); g_return_if_fail(dxyz); dxyz[qr] = _getPhase(vib, vib->priv->iph, dataObj, box, iter.iter.node); valid = visu_node_values_iter_next(&iter); } } else for (i = 0; i < ids->len; i++) { node = visu_node_array_getFromId(VISU_NODE_ARRAY(dataObj), g_array_index(ids, guint, i)); visu_node_values_getAt(VISU_NODE_VALUES(vib), node, &vibeValue); dxyz = (float*)g_value_get_pointer(&vibeValue); g_return_if_fail(dxyz); dxyz[qr] = _getPhase(vib, vib->priv->iph, dataObj, box, node); } } /** * visu_data_getVibration: * @dataObj: a #VisuData object. * @nModes: an integer. * * Retrieves the #VisuNodeValuesVector object used to store the * vibration data. If this object is not existing already, it is * created with @nModes modes. * * Since: 3.8 * * Returns: (transfer none): a #VisuNodeValuesVector owned by V_Sim. **/ VisuVibration* visu_data_getVibration(VisuData *dataObj, guint nModes) { VisuVibration *vect; if (!dataObj) return (VisuVibration*)0; vect = (VisuVibration*)visu_data_getNodeProperties(dataObj, VISU_VIBRATION_ID); if (!vect && nModes > 0) { vect = visu_vibration_new(dataObj, VISU_VIBRATION_ID, nModes); visu_data_addNodeProperties(dataObj, VISU_NODE_VALUES(vect)); } g_return_val_if_fail(!nModes || (vect && nModes && vect->priv->n == nModes), (VisuVibration*)0); return vect; } v_sim-3.8.0/src/extraFunctions/vibration.h000066400000000000000000000120541370110300500206000ustar00rootroot00000000000000/* EXTRAITS DE LA LICENCE Copyright CEA, contributeurs : Luc BILLARD et Damien CALISTE, laboratoire L_Sim, (2001-2005) Adresse mèl : BILLARD, non joignable par mèl ; CALISTE, damien P caliste AT cea P fr. Ce logiciel est un programme informatique servant à visualiser des structures atomiques dans un rendu pseudo-3D. Ce logiciel est régi par la licence CeCILL soumise au droit français et respectant les principes de diffusion des logiciels libres. Vous pouvez utiliser, modifier et/ou redistribuer ce programme sous les conditions de la licence CeCILL telle que diffusée par le CEA, le CNRS et l'INRIA sur le site "http://www.cecill.info". Le fait que vous puissiez accéder à cet en-tête signifie que vous avez pris connaissance de la licence CeCILL, et que vous en avez accepté les termes (cf. le fichier Documentation/licence.fr.txt fourni avec ce logiciel). */ /* LICENCE SUM UP Copyright CEA, contributors : Luc BILLARD et Damien CALISTE, laboratoire L_Sim, (2001-2005) E-mail address: BILLARD, not reachable any more ; CALISTE, damien P caliste AT cea P fr. This software is a computer program whose purpose is to visualize atomic configurations in 3D. This software is governed by the CeCILL license under French law and abiding by the rules of distribution of free software. You can use, modify and/ or redistribute the software under the terms of the CeCILL license as circulated by CEA, CNRS and INRIA at the following URL "http://www.cecill.info". The fact that you are presently reading this means that you have had knowledge of the CeCILL license and that you accept its terms. You can find a copy of this licence shipped with this software at Documentation/licence.en.txt. */ #ifndef VIBRATION_H #define VIBRATION_H #include #include G_BEGIN_DECLS /** * VISU_TYPE_VIBRATION: * * return the type of #VisuVibration. */ #define VISU_TYPE_VIBRATION (visu_vibration_get_type ()) /** * VISU_VIBRATION: * @obj: a #GObject to cast. * * Cast the given @obj into #VisuVibration type. */ #define VISU_VIBRATION(obj) (G_TYPE_CHECK_INSTANCE_CAST(obj, VISU_TYPE_VIBRATION, VisuVibration)) /** * VISU_VIBRATION_CLASS: * @klass: a #GObjectClass to cast. * * Cast the given @klass into #VisuVibrationClass. */ #define VISU_VIBRATION_CLASS(klass) (G_TYPE_CHECK_CLASS_CAST(klass, VISU_TYPE_VIBRATION, VisuVibrationClass)) /** * VISU_IS_VIBRATION: * @obj: a #GObject to test. * * Test if the given @ogj is of the type of #VisuVibration object. */ #define VISU_IS_VIBRATION(obj) (G_TYPE_CHECK_INSTANCE_TYPE(obj, VISU_TYPE_VIBRATION)) /** * VISU_IS_VIBRATION_CLASS: * @klass: a #GObjectClass to test. * * Test if the given @klass is of the type of #VisuVibrationClass class. */ #define VISU_IS_VIBRATION_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE(klass, VISU_TYPE_VIBRATION)) /** * VISU_VIBRATION_GET_CLASS: * @obj: a #GObject to get the class of. * * It returns the class of the given @obj. */ #define VISU_VIBRATION_GET_CLASS(obj) (G_TYPE_INSTANCE_GET_CLASS(obj, VISU_TYPE_VIBRATION, VisuVibrationClass)) /** * VisuVibrationPrivate: * * Private data for #VisuVibration objects. */ typedef struct _VisuVibrationPrivate VisuVibrationPrivate; /** * VisuVibration: * * Common name to refer to a #_VisuVibration. */ typedef struct _VisuVibration VisuVibration; struct _VisuVibration { VisuNodeValuesVector parent; VisuVibrationPrivate *priv; }; /** * VisuVibrationClass: * @parent: private. * * Common name to refer to a #_VisuVibrationClass. */ typedef struct _VisuVibrationClass VisuVibrationClass; struct _VisuVibrationClass { VisuNodeValuesVectorClass parent; }; /** * visu_vibration_get_type: * * This method returns the type of #VisuVibration, use * VISU_TYPE_VIBRATION instead. * * Since: 3.7 * * Returns: the type of #VisuVibration. */ GType visu_vibration_get_type(void); VisuVibration* visu_vibration_new(VisuData *data, const gchar *label, guint n); gboolean visu_vibration_setDisplacements(VisuVibration *vib, guint iph, const GArray *vibes, gboolean complex); gboolean visu_vibration_setCurrentMode(VisuVibration *vib, guint iph, GError **error); gboolean visu_vibration_setCharacteristic(VisuVibration *vib, guint iph, const float q[3], float en, float omega); gboolean visu_vibration_getCharacteristic(const VisuVibration *vib, guint iph, float q[3], float *en, float *omega); gboolean visu_vibration_setUserFrequency(VisuVibration *vib, float freq); gboolean visu_vibration_setAmplitude(VisuVibration *vib, float ampl); gboolean visu_vibration_setTime(VisuVibration *vib, gfloat at); void visu_vibration_resetPosition(VisuVibration *vib); void visu_vibration_setZeroTime(VisuVibration *vib); guint visu_vibration_getNPhonons(VisuVibration *vib); void visu_vibration_animate(VisuVibration *vib); VisuVibration* visu_data_getVibration(VisuData *dataObj, guint nModes); G_END_DECLS #endif v_sim-3.8.0/src/extraGtkFunctions/000077500000000000000000000000001370110300500170765ustar00rootroot00000000000000v_sim-3.8.0/src/extraGtkFunctions/gtk_colorComboBoxWidget.c000066400000000000000000001341771370110300500240370ustar00rootroot00000000000000/* EXTRAITS DE LA LICENCE Copyright CEA, contributeurs : Luc BILLARD et Damien CALISTE, laboratoire L_Sim, (2001-2005) Adresse mèl : BILLARD, non joignable par mèl ; CALISTE, damien P caliste AT cea P fr. Ce logiciel est un programme informatique servant à visualiser des structures atomiques dans un rendu pseudo-3D. Ce logiciel est régi par la licence CeCILL soumise au droit français et respectant les principes de diffusion des logiciels libres. Vous pouvez utiliser, modifier et/ou redistribuer ce programme sous les conditions de la licence CeCILL telle que diffusée par le CEA, le CNRS et l'INRIA sur le site "http://www.cecill.info". Le fait que vous puissiez accéder à cet en-tête signifie que vous avez pris connaissance de la licence CeCILL, et que vous en avez accepté les termes (cf. le fichier Documentation/licence.fr.txt fourni avec ce logiciel). */ /* LICENCE SUM UP Copyright CEA, contributors : Luc BILLARD et Damien CALISTE, laboratoire L_Sim, (2001-2005) E-mail address: BILLARD, not reachable any more ; CALISTE, damien P caliste AT cea P fr. This software is a computer program whose purpose is to visualize atomic configurations in 3D. This software is governed by the CeCILL license under French law and abiding by the rules of distribution of free software. You can use, modify and/ or redistribute the software under the terms of the CeCILL license as circulated by CEA, CNRS and INRIA at the following URL "http://www.cecill.info". The fact that you are presently reading this means that you have had knowledge of the CeCILL license and that you accept its terms. You can find a copy of this licence shipped with this software at Documentation/licence.en.txt. */ #include #include "gtk_colorComboBoxWidget.h" #include #include /** * SECTION:gtk_colorComboBoxWidget * @short_description: Defines a specialised #GtkComboBox to choose * stored colours. * @see_also: #ToolColor, #VisuUiStippleCombobox, #VisuUiShadeCombobox * @include: coreTools/toolColor.h * * This widget looks like a #GtkComboBox and it displays a list * of stored colours. These colours may come from the configuration * files or can be selected and stored by the user actions. To do it, * the first entry of the combo box is 'new / modify', that opens a GTK * colour picker. The new values are used to craete a new colour entry * in the combo box. In a complete version, the combo box can have a * #GtkVBox associated to modify colours without creating new entries, see * visu_ui_color_combobox_newWithRanges() method. Otherwise, only already * selected colours are available. The stored colours are shared by * all widgets of this class. It is thus a convenient way to have * coherent colour picker through V_Sim. * * When the widget is created with ranges, the additional part * can be retrieve with visu_ui_color_combobox_getRangeWidgets() and attached * whereever is convenient. When the ranges are modified, the new * colour is not added to the combo box. It can be read using * visu_ui_color_combobox_getRangeColor() or visu_ui_color_combobox_getRangeMaterial(). The combo * box is set thus to an unselected state and * visu_ui_color_combobox_getSelection() will return a NULL * pointer. Besides the colour ranges, there is an add button to * insert the newly defined colour into the combo box. * * This widget can emit a #VisuUiColorCombobox::color-selected * signal that is a wrapper around the #GtkComboBox::changed signal, * but it is emitted only when a new colour is selected (either an * existing one or a newly created from the picker). This colour * is passed to the callback. The two other signals, * #VisuUiColorCombobox::color-value-changed and * #VisuUiColorCombobox::material-value-changed, are generated when the * widget have been created with ranges and that one of these ranges * is modified. * * Since: 3.1 */ enum { COLOR_SELECTED_SIGNAL, COLOR_VALUE_CHANGED_SIGNAL, MATERIAL_VALUE_CHANGED_SIGNAL, LAST_SIGNAL }; static guint signals[LAST_SIGNAL] = { 0 }; enum { PROP_0, COLOR_PROP, MATERIAL_PROP, N_PROP }; static GParamSpec *properties[N_PROP]; /* This enum is used to access the column of the GtkListStore that contains the informations of stroed colors. */ enum { /* This has a pointer to a 16x16 image to represent the color, including the alpha channel. */ COLUMN_COLOR_PIXBUF_ALPHA, /* This has a pointer to a 16x16 image to represent the color, without the alpha channel. */ COLUMN_COLOR_PIXBUF, /* This is a pointer to a label that describes the color : "(n_red;n_green;n_blue;n_alpha)" with n_xxx from 0 to 255. */ COLUMN_COLOR_LABEL_ALPHA, /* This is the same label than above but without the alpha value. */ COLUMN_COLOR_LABEL, /* This a pointer to the #ToolColor as defined in visuTools.h */ COLUMN_COLOR_POINTER_TO, N_COLUMN_COLOR }; /* Labels for the ranges part. */ #define RED_ELE_LABEL _("R:") #define GREEN_ELE_LABEL _("G:") #define BLUE_ELE_LABEL _("B:") #define ALPHA_ELE_LABEL _("Alph:") #define AMB_ELE_LABEL _("amb:") #define DIF_ELE_LABEL _("dif:") #define SHI_ELE_LABEL _("shi:") #define SPE_ELE_LABEL _("spe:") #define EMI_ELE_LABEL _("emi:") static void visu_ui_color_combobox_changed (GtkWidget *widget, VisuUiColorCombobox *colorComboBox); static void visu_ui_color_combobox_dispose (GObject *obj); static void visu_ui_color_combobox_finalize(GObject *obj); static void visu_ui_color_combobox_get_property(GObject* obj, guint property_id, GValue *value, GParamSpec *pspec); static void visu_ui_color_combobox_set_property(GObject* obj, guint property_id, const GValue *value, GParamSpec *pspec); /** * VisuUiColorCombobox * * Private structure to store informations of a #VisuUiColorCombobox object. * * Since: 3.1 */ struct _VisuUiColorCombobox { GtkComboBox comboColor; ToolColor* previouslySelectedColor; gboolean withRanges; GtkWidget *expandRanges; GtkWidget *rgbRanges[4]; GtkWidget *materialRanges[TOOL_MATERIAL_N_VALUES]; gulong rgbSignals[4]; gulong materialSignals[TOOL_MATERIAL_N_VALUES]; gulong comboSignal; GtkWidget *addButton; gboolean hasAlphaChannel; GtkCellRenderer *rendererRGB; /* Memory gestion. */ gboolean dispose_has_run; }; /** * VisuUiColorComboboxClass * * Private structure to store informations of a #VisuUiColorComboboxClass object. * * Since: 3.1 */ struct _VisuUiColorComboboxClass { GtkComboBoxClass parent_class; void (*colorComboBox) (VisuUiColorCombobox *colorCombo); /* This listStore contains all the colors known by widgets of this class. It is used as TreeModel for the combobox in the widget. */ GtkListStore *listStoredColors; gulong colorAddedSignalId; }; /* Local callbacks. */ static void visu_ui_color_combobox_materialChanged(GtkRange *rg, gpointer data); static void visu_ui_color_combobox_rgbChanged(GtkRange *rg, gpointer data); static void visu_ui_color_combobox_addButtonClicked(GtkButton *button, gpointer data); /* Local methods. */ static void addColorToModel(GtkTreeIter *iter, VisuUiColorComboboxClass* klass, ToolColor* color); static void onNewColorAvailable(ToolPool *pool, ToolColor* newColor, gpointer data); /** * visu_ui_color_combobox_get_type * * #GType are unique numbers to identify objects. * * Returns: the #GType associated with #VisuUiColorCombobox objects. * * Since: 3.1 */ G_DEFINE_TYPE(VisuUiColorCombobox, visu_ui_color_combobox, GTK_TYPE_COMBO_BOX) static void visu_ui_color_combobox_class_init(VisuUiColorComboboxClass *klass) { GtkTreeIter iter; GList *colorLst; DBG_fprintf(stderr, "Gtk VisuUiColorCombobox: creating the class of the widget.\n"); DBG_fprintf(stderr, " - adding new signals ;\n"); /** * VisuUiColorCombobox::color-selected: * @combo: the #VisuUiColorCombobox that emits the signal ; * @color: the newly selected #ToolColor. * * This signal is emitted when a new valid colour is selected, * either an existing one or newly created one. * * Since: 3.1 */ signals[COLOR_SELECTED_SIGNAL] = g_signal_new ("color-selected", G_TYPE_FROM_CLASS (klass), G_SIGNAL_RUN_FIRST | G_SIGNAL_ACTION, G_STRUCT_OFFSET (VisuUiColorComboboxClass, colorComboBox), NULL, NULL, g_cclosure_marshal_VOID__POINTER, G_TYPE_NONE, 1, G_TYPE_POINTER); /** * VisuUiColorCombobox::color-value-changed: * @combo: the #VisuUiColorCombobox that emits the signal ; * @RGBA: the modified channel. * * This signal is emitted when the range of a colour is modified. * * Since: 3.3 */ signals[COLOR_VALUE_CHANGED_SIGNAL] = g_signal_new ("color-value-changed", G_TYPE_FROM_CLASS (klass), G_SIGNAL_RUN_FIRST | G_SIGNAL_ACTION, G_STRUCT_OFFSET (VisuUiColorComboboxClass, colorComboBox), NULL, NULL, g_cclosure_marshal_VOID__UINT, G_TYPE_NONE, 1, G_TYPE_UINT); /** * VisuUiColorCombobox::material-value-changed: * @combo: the #VisuUiColorCombobox that emits the signal ; * @mat: the modified material channel (see #ToolMaterialIds). * * This signal is emitted when the range of a material is modified. * * Since: 3.3 */ signals[MATERIAL_VALUE_CHANGED_SIGNAL] = g_signal_new ("material-value-changed", G_TYPE_FROM_CLASS (klass), G_SIGNAL_RUN_FIRST | G_SIGNAL_ACTION, G_STRUCT_OFFSET (VisuUiColorComboboxClass, colorComboBox), NULL, NULL, g_cclosure_marshal_VOID__UINT, G_TYPE_NONE, 1, G_TYPE_UINT); DBG_fprintf(stderr, " - initializing the listStore of colors.\n"); /* Init the listStore of colors. */ klass->listStoredColors = gtk_list_store_new (N_COLUMN_COLOR, GDK_TYPE_PIXBUF, GDK_TYPE_PIXBUF, G_TYPE_STRING, G_TYPE_STRING, G_TYPE_POINTER); gtk_list_store_append(klass->listStoredColors, &iter); gtk_list_store_set(klass->listStoredColors, &iter, COLUMN_COLOR_PIXBUF_ALPHA, NULL, COLUMN_COLOR_PIXBUF , NULL, COLUMN_COLOR_LABEL_ALPHA , _("New / modify"), COLUMN_COLOR_LABEL , _("New / modify"), COLUMN_COLOR_POINTER_TO , NULL, -1); klass->colorAddedSignalId = g_signal_connect(tool_color_getStorage(), "new-element", G_CALLBACK(onNewColorAvailable), (gpointer)klass); DBG_fprintf(stderr, " - add stored colours.\n"); colorLst = tool_pool_asList(tool_color_getStorage()); while (colorLst) { addColorToModel(&iter, klass, (ToolColor*)colorLst->data); colorLst = g_list_next(colorLst); } /* Connect freeing methods. */ G_OBJECT_CLASS(klass)->dispose = visu_ui_color_combobox_dispose; G_OBJECT_CLASS(klass)->finalize = visu_ui_color_combobox_finalize; G_OBJECT_CLASS(klass)->set_property = visu_ui_color_combobox_set_property; G_OBJECT_CLASS(klass)->get_property = visu_ui_color_combobox_get_property; /** * VisuUiColorCombobox::color: * * Store the color of the current selection. * * Since: 3.8 */ properties[COLOR_PROP] = g_param_spec_boxed("color", "Color", "color of the current selection", TOOL_TYPE_COLOR, G_PARAM_READWRITE); /** * VisuUiColorCombobox::material: * * Store the material of the current selection. * * Since: 3.8 */ properties[MATERIAL_PROP] = g_param_spec_boxed("material", "Material", "material of the current selection", TOOL_TYPE_MATERIAL, G_PARAM_READWRITE); g_object_class_install_properties(G_OBJECT_CLASS(klass), N_PROP, properties); } static void visu_ui_color_combobox_dispose(GObject *obj) { DBG_fprintf(stderr, "Gtk VisuUiColorCombobox: dispose object %p.\n", (gpointer)obj); if (VISU_UI_COLOR_COMBOBOX(obj)->dispose_has_run) return; VISU_UI_COLOR_COMBOBOX(obj)->dispose_has_run = TRUE; /* Chain up to the parent class */ G_OBJECT_CLASS(visu_ui_color_combobox_parent_class)->dispose(obj); } static void visu_ui_color_combobox_finalize(GObject *obj) { /* VisuUiColorCombobox *colorComboBox; */ g_return_if_fail(obj); DBG_fprintf(stderr, "Gtk VisuUiColorCombobox: finalize object %p.\n", (gpointer)obj); /* colorComboBox = VISU_UI_COLOR_COMBOBOX(obj); */ /* if (colorComboBox->expandRanges) */ /* gtk_widget_destroy(colorComboBox->expandRanges); */ /* Chain up to the parent class */ G_OBJECT_CLASS(visu_ui_color_combobox_parent_class)->finalize(obj); DBG_fprintf(stderr, "Gtk VisuUiColorCombobox: freeing ... OK.\n"); } static void visu_ui_color_combobox_get_property(GObject* obj, guint property_id, GValue *value, GParamSpec *pspec) { VisuUiColorCombobox *self = VISU_UI_COLOR_COMBOBOX(obj); const ToolColor *color; ToolColor _color; DBG_fprintf(stderr, "Gtk VisuUiColorCombobox: get property '%s'.\n", g_param_spec_get_name(pspec)); switch (property_id) { case COLOR_PROP: color = visu_ui_color_combobox_getSelection(self); if (color) g_value_set_static_boxed(value, color); else { _color.rgba[0] = gtk_range_get_value(GTK_RANGE(self->rgbRanges[0])); _color.rgba[1] = gtk_range_get_value(GTK_RANGE(self->rgbRanges[1])); _color.rgba[2] = gtk_range_get_value(GTK_RANGE(self->rgbRanges[2])); _color.rgba[3] = gtk_range_get_value(GTK_RANGE(self->rgbRanges[3])); g_value_set_boxed(value, &_color); } DBG_fprintf(stderr, " | color pointer is %p.\n", (gpointer)g_value_get_boxed(value)); break; case MATERIAL_PROP: g_value_take_boxed(value, visu_ui_color_combobox_getRangeMaterial(self)); DBG_fprintf(stderr, " | material pointer is %p.\n", (gpointer)g_value_get_boxed(value)); break; default: /* We don't have any other property... */ G_OBJECT_WARN_INVALID_PROPERTY_ID(obj, property_id, pspec); break; } } static void visu_ui_color_combobox_set_property(GObject* obj, guint property_id, const GValue *value, GParamSpec *pspec) { GtkTreeIter iter; VisuUiColorCombobox *self = VISU_UI_COLOR_COMBOBOX(obj); DBG_fprintf(stderr, "Gtk VisuUiColorCombobox: set property '%s'.\n", g_param_spec_get_name(pspec)); switch (property_id) { case COLOR_PROP: if (!visu_ui_color_combobox_setSelection(self, (ToolColor*)g_value_get_boxed(value))) { addColorToModel(&iter, VISU_UI_COLOR_COMBOBOX_GET_CLASS(obj), (ToolColor*)g_value_get_boxed(value)); gtk_combo_box_set_active_iter(GTK_COMBO_BOX(obj), &iter); } break; case MATERIAL_PROP: visu_ui_color_combobox_setRangeMaterial(self, (float*)g_value_get_boxed(value), FALSE); break; default: /* We don't have any other property... */ G_OBJECT_WARN_INVALID_PROPERTY_ID(obj, property_id, pspec); break; } } static void visu_ui_color_combobox_init(VisuUiColorCombobox *colorComboBox) { DBG_fprintf(stderr, "Gtk VisuUiColorCombobox: initializing new object (%p).\n", (gpointer)colorComboBox); colorComboBox->hasAlphaChannel = TRUE; colorComboBox->dispose_has_run = FALSE; colorComboBox->previouslySelectedColor = tool_pool_getById(tool_color_getStorage(), 0); } static void _drawPix(GtkCellLayout *layout _U_, GtkCellRenderer *cell, GtkTreeModel *model, GtkTreeIter *iter, gpointer data) { GdkPixbuf *pix; if (GPOINTER_TO_INT(data)) gtk_tree_model_get(model, iter, COLUMN_COLOR_PIXBUF_ALPHA, &pix, -1); else gtk_tree_model_get(model, iter, COLUMN_COLOR_PIXBUF, &pix, -1); if (pix) { g_object_set(G_OBJECT(cell), "pixbuf", pix, NULL); g_object_unref(pix); } else g_object_set(G_OBJECT(cell), "icon-name", "list-add", NULL); } static void buildWidgets(VisuUiColorCombobox *colorComboBox) { GObjectClass *klass; GtkCellRenderer *renderer; GtkWidget *vboxExpand, *table, *label, *hbox, *image; char *rgb[4]; char *rgbName[4] = {"scroll_r", "scroll_g", "scroll_b", "scroll_a"}; char *material[5]; int i, j; klass = G_OBJECT_GET_CLASS(colorComboBox); gtk_combo_box_set_model(GTK_COMBO_BOX(colorComboBox), GTK_TREE_MODEL(VISU_UI_COLOR_COMBOBOX_CLASS(klass)->listStoredColors)); DBG_fprintf(stderr, "Gtk VisuUiColorCombobox: build widgets.\n"); renderer = gtk_cell_renderer_pixbuf_new(); gtk_cell_layout_pack_start(GTK_CELL_LAYOUT(colorComboBox), renderer, FALSE); gtk_cell_layout_set_cell_data_func(GTK_CELL_LAYOUT(colorComboBox), renderer, _drawPix, GINT_TO_POINTER(colorComboBox->hasAlphaChannel), (GDestroyNotify)0); /* if (colorComboBox->hasAlphaChannel) */ /* gtk_cell_layout_add_attribute(GTK_CELL_LAYOUT(colorComboBox), renderer, */ /* "pixbuf", COLUMN_COLOR_PIXBUF_ALPHA); */ /* else */ /* gtk_cell_layout_add_attribute(GTK_CELL_LAYOUT(colorComboBox), renderer, */ /* "pixbuf", COLUMN_COLOR_PIXBUF); */ renderer = gtk_cell_renderer_text_new(); g_object_set(G_OBJECT(renderer), "scale", 0.85, NULL); gtk_cell_layout_pack_start(GTK_CELL_LAYOUT(colorComboBox), renderer, FALSE); if (colorComboBox->hasAlphaChannel) gtk_cell_layout_add_attribute(GTK_CELL_LAYOUT(colorComboBox), renderer, "text", COLUMN_COLOR_LABEL_ALPHA); else gtk_cell_layout_add_attribute(GTK_CELL_LAYOUT(colorComboBox), renderer, "text", COLUMN_COLOR_LABEL); colorComboBox->rendererRGB = renderer; DBG_fprintf(stderr, " | renderers OK\n"); gtk_combo_box_set_active(GTK_COMBO_BOX(colorComboBox), 1); DBG_fprintf(stderr, " | selection OK\n"); colorComboBox->expandRanges = (GtkWidget*)0; if (colorComboBox->withRanges) { DBG_fprintf(stderr, "Gtk VisuUiColorCombobox: add range widgets.\n"); rgb[0] = RED_ELE_LABEL; rgb[1] = GREEN_ELE_LABEL; rgb[2] = BLUE_ELE_LABEL; rgb[3] = ALPHA_ELE_LABEL; material[0] = AMB_ELE_LABEL; material[1] = DIF_ELE_LABEL; material[2] = SHI_ELE_LABEL; material[3] = SPE_ELE_LABEL; material[4] = EMI_ELE_LABEL; colorComboBox->expandRanges = gtk_expander_new(_("More options")); gtk_expander_set_expanded(GTK_EXPANDER(colorComboBox->expandRanges), FALSE); vboxExpand = gtk_vbox_new(FALSE, 0); gtk_container_add(GTK_CONTAINER(colorComboBox->expandRanges), vboxExpand); hbox = gtk_hbox_new(FALSE, 0); gtk_box_pack_start(GTK_BOX(vboxExpand), hbox, FALSE, FALSE, 5); table = gtk_grid_new(); tool_grid_resize(table, 3, 2); gtk_box_pack_start(GTK_BOX(hbox), table, TRUE, TRUE, 0); gtk_widget_show(table); for (i = 0; i < 3; i++) { label = gtk_label_new(rgb[i]); gtk_grid_attach(GTK_GRID(table), label, 0, i, 1, 1); colorComboBox->rgbRanges[i] = gtk_hscale_new_with_range(0., 1., 0.001); gtk_widget_set_hexpand(colorComboBox->rgbRanges[i], TRUE); gtk_scale_set_value_pos(GTK_SCALE(colorComboBox->rgbRanges[i]), GTK_POS_RIGHT); gtk_widget_set_name(colorComboBox->rgbRanges[i], rgbName[i]); gtk_grid_attach(GTK_GRID(table), colorComboBox->rgbRanges[i], 1, i, 1, 1); } colorComboBox->addButton = gtk_button_new(); gtk_box_pack_start(GTK_BOX(hbox), colorComboBox->addButton, FALSE, FALSE, 2); image = gtk_image_new_from_icon_name("list-add", GTK_ICON_SIZE_BUTTON); gtk_container_add(GTK_CONTAINER(colorComboBox->addButton), image); DBG_fprintf(stderr, " | color OK\n"); table = gtk_grid_new(); tool_grid_resize(table, 3, 4); gtk_box_pack_start(GTK_BOX(vboxExpand), table, FALSE, FALSE, 5); for (i = 0; i < 2; i++) { for (j = 0; j < 2; j++) { label = gtk_label_new(material[i * 2 + j]); gtk_label_set_xalign(GTK_LABEL(label), 1.); gtk_grid_attach(GTK_GRID(table), label, j * 2, i, 1, 1); colorComboBox->materialRanges[i * 2 + j] = gtk_hscale_new_with_range(0., 1., 0.01); gtk_widget_set_hexpand(colorComboBox->materialRanges[i * 2 + j], TRUE); gtk_scale_set_value_pos(GTK_SCALE(colorComboBox->materialRanges[i * 2 + j]), GTK_POS_RIGHT); gtk_widget_set_name(colorComboBox->materialRanges[i * 2 +j], "scroll_mat"); gtk_grid_attach(GTK_GRID(table), colorComboBox->materialRanges[i * 2 + j], 2 * j + 1, i, 1, 1); } } label = gtk_label_new(material[4]); gtk_label_set_xalign(GTK_LABEL(label), 1); gtk_grid_attach(GTK_GRID(table), label, 0, i, 1, 1); colorComboBox->materialRanges[4] = gtk_hscale_new_with_range(0., 1., 0.01); gtk_scale_set_value_pos(GTK_SCALE(colorComboBox->materialRanges[4]), GTK_POS_RIGHT); gtk_widget_set_name(colorComboBox->materialRanges[4], "scroll_mat"); gtk_grid_attach(GTK_GRID(table), colorComboBox->materialRanges[4], 1, i, 1, 1); label = gtk_label_new(rgb[3]); gtk_label_set_xalign(GTK_LABEL(label), 1.); gtk_grid_attach(GTK_GRID(table), label, 2, i, 1, 1); colorComboBox->rgbRanges[3] = gtk_hscale_new_with_range(0., 1., 0.01); gtk_scale_set_value_pos(GTK_SCALE(colorComboBox->rgbRanges[3]), GTK_POS_RIGHT); gtk_widget_set_name(colorComboBox->rgbRanges[3], rgbName[3]); gtk_grid_attach(GTK_GRID(table), colorComboBox->rgbRanges[3], 3, i, 1, 1); DBG_fprintf(stderr, " | material OK\n"); /* Attach the callbacks. */ for (i = 0; i < 4; i++) colorComboBox->rgbSignals[i] = g_signal_connect(G_OBJECT(colorComboBox->rgbRanges[i]), "value-changed", G_CALLBACK(visu_ui_color_combobox_rgbChanged), (gpointer)colorComboBox); for (i = 0; i < TOOL_MATERIAL_N_VALUES; i++) colorComboBox->materialSignals[i] = g_signal_connect(G_OBJECT(colorComboBox->materialRanges[i]), "value-changed", G_CALLBACK(visu_ui_color_combobox_materialChanged), (gpointer)colorComboBox); g_signal_connect(G_OBJECT(colorComboBox->addButton), "clicked", G_CALLBACK(visu_ui_color_combobox_addButtonClicked), (gpointer)colorComboBox); DBG_fprintf(stderr, " | signals OK\n"); } colorComboBox->comboSignal = g_signal_connect(G_OBJECT(colorComboBox), "changed", G_CALLBACK(visu_ui_color_combobox_changed), (gpointer)colorComboBox); } /** * visu_ui_color_combobox_newWithRanges: * @hasAlphaChannel: a boolean. * * Create a color combo and several ranges. * * Returns: (transfer full): a newly created #VisuUiColorCombobox widget. * * Since: 3.3 */ GtkWidget* visu_ui_color_combobox_newWithRanges(gboolean hasAlphaChannel) { VisuUiColorCombobox *colorComboBox; DBG_fprintf(stderr, "Gtk VisuUiColorCombobox: creating new object with alpha & ranges: %d.\n", hasAlphaChannel); colorComboBox = VISU_UI_COLOR_COMBOBOX(g_object_new(visu_ui_color_combobox_get_type (), NULL)); colorComboBox->hasAlphaChannel = hasAlphaChannel; colorComboBox->withRanges = TRUE; buildWidgets(colorComboBox); DBG_fprintf(stderr, "Gtk VisuUiColorCombobox: object ready.\n"); return GTK_WIDGET(colorComboBox); } /** * visu_ui_color_combobox_new: * @hasAlphaChannel: a boolean. * * A #VisuUiColorCombobox widget is like a #GtkComboBox widget, but it is already filled * with the colors stores in the structures adhoc in visu_tools.h. Using this widget * is a convienient way to share colors between all part of V_Sim and to give a consistent * look of all color selection. If the argument @hasAlphaChannel is FALSE, the widget * display all colors but without their alpha channel, assuming it to be fully opaque. * * Returns: (transfer full): a newly created #VisuUiColorCombobox widget. * * Since: 3.1 */ GtkWidget* visu_ui_color_combobox_new(gboolean hasAlphaChannel) { VisuUiColorCombobox *colorComboBox; DBG_fprintf(stderr, "Gtk VisuUiColorCombobox: creating new object with alpha: %d.\n", hasAlphaChannel); colorComboBox = VISU_UI_COLOR_COMBOBOX(g_object_new(visu_ui_color_combobox_get_type (), NULL)); colorComboBox->hasAlphaChannel = hasAlphaChannel; colorComboBox->withRanges = FALSE; buildWidgets(colorComboBox); DBG_fprintf(stderr, "Gtk VisuUiColorCombobox: object ready.\n"); return GTK_WIDGET(colorComboBox); } /** * visu_ui_color_combobox_setExpanded: * @colorComboBox: a #ToolColor object ; * @value: a boolean value. * * Set the expanded state of the ranges. This is usable only if the colorComboBox * has been created with ranges. * * Since: 3.3 */ void visu_ui_color_combobox_setExpanded(VisuUiColorCombobox *colorComboBox, gboolean value) { g_return_if_fail(VISU_IS_UI_COLOR_COMBOBOX(colorComboBox)); g_return_if_fail(colorComboBox->withRanges); gtk_expander_set_expanded(GTK_EXPANDER(colorComboBox->expandRanges), value); } /** * visu_ui_color_combobox_setPrintValues: * @colorComboBox: a #ToolColor object ; * @value: a boolean. * * Print or not the RGB values. * * Since: 3.4 */ void visu_ui_color_combobox_setPrintValues(VisuUiColorCombobox *colorComboBox, gboolean value) { g_object_set(G_OBJECT(colorComboBox->rendererRGB), "visible", value, NULL); } /** * visu_ui_color_combobox_getRangeWidgets: * @colorComboBox: a #ToolColor object. * * Retrieve the wiodget using to represent the ranges, or NULL if the object * has no ranges. * * Returns: (transfer none): a widget owned by @color. * * Since: 3.3 */ GtkWidget* visu_ui_color_combobox_getRangeWidgets(VisuUiColorCombobox *colorComboBox) { g_return_val_if_fail(VISU_IS_UI_COLOR_COMBOBOX(colorComboBox), (GtkWidget*)0); return colorComboBox->expandRanges; } static void visu_ui_color_combobox_changed(GtkWidget *widget _U_, VisuUiColorCombobox *colorComboBox) { int selected, i; GdkRGBA gdkcolor; GtkWidget *selection; gint code; float rgba[4]; GtkTreeIter iter; GObjectClass *klass; ToolColor *color; selected = gtk_combo_box_get_active(GTK_COMBO_BOX(colorComboBox)); DBG_fprintf(stderr, "Gtk VisuUiColorCombobox: internal combobox changed signal -> %d.\n", selected); if (selected < 0) { if (colorComboBox->withRanges) gtk_widget_set_sensitive(colorComboBox->addButton, TRUE); colorComboBox->previouslySelectedColor = (ToolColor*)0; return; } if (colorComboBox->withRanges) gtk_widget_set_sensitive(colorComboBox->addButton, FALSE); if (selected != 0) { gtk_combo_box_get_active_iter(GTK_COMBO_BOX(colorComboBox), &iter); klass = G_OBJECT_GET_CLASS(colorComboBox); gtk_tree_model_get(GTK_TREE_MODEL(VISU_UI_COLOR_COMBOBOX_CLASS(klass)->listStoredColors), &iter, COLUMN_COLOR_POINTER_TO, &color, -1); if (color != colorComboBox->previouslySelectedColor) { colorComboBox->previouslySelectedColor = color; /* Set the ranges. */ if (colorComboBox->withRanges) for (i = 0; i <4; i++) { g_signal_handler_block(G_OBJECT(colorComboBox->rgbRanges[i]), colorComboBox->rgbSignals[i]); gtk_range_set_value(GTK_RANGE(colorComboBox->rgbRanges[i]), (gdouble)color->rgba[i]); g_signal_handler_unblock(G_OBJECT(colorComboBox->rgbRanges[i]), colorComboBox->rgbSignals[i]); } DBG_fprintf(stderr, "Gtk VisuUiColorCombobox: emitting 'color-selected' signal.\n"); g_object_notify_by_pspec(G_OBJECT(colorComboBox), properties[COLOR_PROP]); g_signal_emit(G_OBJECT(colorComboBox), signals[COLOR_SELECTED_SIGNAL], 0, (gpointer)color, NULL); } else DBG_fprintf(stderr, "Gtk VisuUiColorCombobox: aborting 'color-selected' signal.\n"); return; } if (colorComboBox->previouslySelectedColor) { gdkcolor.red = colorComboBox->previouslySelectedColor->rgba[0]; gdkcolor.green = colorComboBox->previouslySelectedColor->rgba[1]; gdkcolor.blue = colorComboBox->previouslySelectedColor->rgba[2]; gdkcolor.alpha = colorComboBox->previouslySelectedColor->rgba[3]; } else { gdkcolor.red = 0.; gdkcolor.green = 0.; gdkcolor.blue = 0.; gdkcolor.alpha = 1.; } /* Create the selection. */ selection = gtk_color_chooser_dialog_new(_("Select a color"), NULL); gtk_color_chooser_set_use_alpha(GTK_COLOR_CHOOSER(selection), colorComboBox->hasAlphaChannel); /* createColorSelectionCustomList(GTK_COLOR_SELECTION_DIALOG(selection)); */ /* Initialise its values. */ gtk_color_chooser_set_rgba(GTK_COLOR_CHOOSER(selection), &gdkcolor); /* Run the dialog window. */ code = gtk_dialog_run(GTK_DIALOG(selection)); if (code == GTK_RESPONSE_OK || code == GTK_RESPONSE_ACCEPT) { gtk_color_chooser_get_rgba(GTK_COLOR_CHOOSER(selection), &gdkcolor); rgba[0] = (float)gdkcolor.red; rgba[1] = (float)gdkcolor.green; rgba[2] = (float)gdkcolor.blue; rgba[3] = (float)gdkcolor.alpha; klass = G_OBJECT_GET_CLASS(colorComboBox); g_signal_handler_block(tool_color_getStorage(), VISU_UI_COLOR_COMBOBOX_CLASS(klass)->colorAddedSignalId); color = tool_color_addFloatRGBA(rgba, &selected); g_signal_handler_unblock(tool_color_getStorage(), VISU_UI_COLOR_COMBOBOX_CLASS(klass)->colorAddedSignalId); addColorToModel(&iter, VISU_UI_COLOR_COMBOBOX_CLASS(klass), color); gtk_combo_box_set_active_iter(GTK_COMBO_BOX(colorComboBox), &iter); } else { /* Return the combobox to the previously selected color. */ if (colorComboBox->previouslySelectedColor) visu_ui_color_combobox_setSelection(colorComboBox, colorComboBox->previouslySelectedColor); else gtk_combo_box_set_active(GTK_COMBO_BOX(colorComboBox), -1); } gtk_widget_destroy(selection); } static void visu_ui_color_combobox_materialChanged(GtkRange *rg, gpointer data) { int i; VisuUiColorCombobox *colorComboBox; g_return_if_fail(VISU_IS_UI_COLOR_COMBOBOX(data)); g_object_notify_by_pspec(G_OBJECT(data), properties[MATERIAL_PROP]); colorComboBox = VISU_UI_COLOR_COMBOBOX(data); DBG_fprintf(stderr, "Gtk VisuUiColorCombobox: internal material range changed signal.\n"); DBG_fprintf(stderr, "Gtk VisuUiColorCombobox: emitting 'material-value-changed' signal.\n"); for (i = 0; i < TOOL_MATERIAL_N_VALUES; i++) if (GTK_WIDGET(rg) == colorComboBox->materialRanges[i]) { g_signal_emit(G_OBJECT(colorComboBox), signals[MATERIAL_VALUE_CHANGED_SIGNAL], 0, (ToolMaterialIds)i, NULL); return; } g_warning("Internal error, unrecognized range."); } static void visu_ui_color_combobox_rgbChanged(GtkRange *rg, gpointer data) { int i; VisuUiColorCombobox *colorComboBox; float *rgba; g_return_if_fail(VISU_IS_UI_COLOR_COMBOBOX(data)); colorComboBox = VISU_UI_COLOR_COMBOBOX(data); DBG_fprintf(stderr, "Gtk VisuUiColorCombobox: internal color range changed signal.\n"); rgba = visu_ui_color_combobox_getRangeColor(colorComboBox); tool_color_getByValues(&i, rgba[0], rgba[1], rgba[2], rgba[3]); if (i < 0) { gtk_combo_box_set_active(GTK_COMBO_BOX(colorComboBox), -1); g_object_notify_by_pspec(G_OBJECT(data), properties[COLOR_PROP]); } else gtk_combo_box_set_active(GTK_COMBO_BOX(colorComboBox), i + 1); g_free(rgba); DBG_fprintf(stderr, "Gtk VisuUiColorCombobox: emitting 'color-value-changed' signal.\n"); for (i = 0; i < 4; i++) if (GTK_WIDGET(rg) == colorComboBox->rgbRanges[i]) { g_signal_emit(G_OBJECT(colorComboBox), signals[COLOR_VALUE_CHANGED_SIGNAL], 0, (ToolMaterialIds)i, NULL); return; } g_warning("Internal error, unrecognized range."); } static void visu_ui_color_combobox_addButtonClicked(GtkButton *button _U_, gpointer data) { GtkTreeIter iter; GObjectClass *klass; ToolColor *color; VisuUiColorCombobox *colorComboBox; float *rgba; int selected; g_return_if_fail(VISU_IS_UI_COLOR_COMBOBOX(data)); colorComboBox = VISU_UI_COLOR_COMBOBOX(data); DBG_fprintf(stderr, "Gtk VisuUiColorCombobox: adding a new color from ranges.\n"); rgba = visu_ui_color_combobox_getRangeColor(colorComboBox); klass = G_OBJECT_GET_CLASS(colorComboBox); g_signal_handler_block(tool_color_getStorage(), VISU_UI_COLOR_COMBOBOX_CLASS(klass)->colorAddedSignalId); color = tool_color_addFloatRGBA(rgba, &selected); g_signal_handler_unblock(tool_color_getStorage(), VISU_UI_COLOR_COMBOBOX_CLASS(klass)->colorAddedSignalId); addColorToModel(&iter, VISU_UI_COLOR_COMBOBOX_CLASS(klass), color); gtk_combo_box_set_active_iter(GTK_COMBO_BOX(colorComboBox), &iter); g_free(rgba); } static void addColorToModel(GtkTreeIter *iter, VisuUiColorComboboxClass* klass, ToolColor* color) { char str[20], strAlpha[20]; GdkPixbuf *pixbufColorBox; GdkPixbuf *pixbufColorAlphaBox; if (!color || !klass) return; sprintf(strAlpha, "(#%02x%02x%02x%02x)", (int)(color->rgba[0] * 255.), (int)(color->rgba[1] * 255.), (int)(color->rgba[2] * 255.), (int)(color->rgba[3] * 255.)); sprintf(str, "(#%02x%02x%02x)", (int)(color->rgba[0] * 255.), (int)(color->rgba[1] * 255.), (int)(color->rgba[2] * 255.)); pixbufColorAlphaBox = tool_color_get_stamp(color, TRUE); pixbufColorBox = tool_color_get_stamp(color, FALSE); gtk_list_store_append(klass->listStoredColors, iter); gtk_list_store_set(klass->listStoredColors, iter, COLUMN_COLOR_PIXBUF_ALPHA, pixbufColorAlphaBox, COLUMN_COLOR_PIXBUF , pixbufColorBox, COLUMN_COLOR_LABEL_ALPHA , strAlpha, COLUMN_COLOR_LABEL , str, COLUMN_COLOR_POINTER_TO , (gpointer)color, -1); DBG_fprintf(stderr, "Gtk VisuUiColorCombobox: appending a new color '%s'.\n", strAlpha); g_object_unref(pixbufColorAlphaBox); g_object_unref(pixbufColorBox); } /** * visu_ui_color_combobox_setSelection: * @colorComboBox: a #VisuUiColorCombobox widget ; * @color: a #ToolColor object. * * Use this method to set the ComboBox on the given color. This emits a 'color-channel' * signal if the color is changed, which means, a previous color has been modified, * or a new color is selected. * * Returns: TRUE if the @color already exists in the model. * * Since: 3.1 */ gboolean visu_ui_color_combobox_setSelection(VisuUiColorCombobox* colorComboBox, ToolColor *color) { GtkTreeIter iter; gboolean validIter; GObjectClass *klass; GtkListStore *model; ToolColor *tmpColor; g_return_val_if_fail(color && VISU_IS_UI_COLOR_COMBOBOX(colorComboBox), FALSE); DBG_fprintf(stderr, "Gtk VisuUiColorCombobox: select a new color %p.\n", (gpointer)color); klass = G_OBJECT_GET_CLASS(colorComboBox); model = GTK_LIST_STORE(VISU_UI_COLOR_COMBOBOX_CLASS(klass)->listStoredColors); validIter = gtk_tree_model_get_iter_first(GTK_TREE_MODEL(model), &iter); while (validIter) { gtk_tree_model_get(GTK_TREE_MODEL(model), &iter, COLUMN_COLOR_POINTER_TO, &tmpColor, -1); if (tmpColor && tool_color_equal(tmpColor, color)) { gtk_combo_box_set_active_iter(GTK_COMBO_BOX(colorComboBox), &iter); return TRUE; } validIter = gtk_tree_model_iter_next(GTK_TREE_MODEL(model), &iter); } return FALSE; } /** * visu_ui_color_combobox_setRangeColor: * @colorComboBox: a #VisuUiColorCombobox widget ; * @rgba: 4 floating point values ; * @raiseSignal: if TRUE a material-value-changed can be raised. * * Change the values for the ranges that control the color. If the color exists * in the list, it is also selected. * This is possible only if the @colorComboBox has been created with * visu_ui_color_combobox_newWithRanges(). * * Since: 3.3 */ void visu_ui_color_combobox_setRangeColor(VisuUiColorCombobox *colorComboBox, const float rgba[4], gboolean raiseSignal) { int pos, i; ToolColor *color; color = tool_color_getByValues(&pos, rgba[0], rgba[1], rgba[2], rgba[3]); if (!color) { gtk_combo_box_set_active(GTK_COMBO_BOX(colorComboBox), -1); if (raiseSignal) for (i = 0; i < 4; i++) gtk_range_set_value(GTK_RANGE(colorComboBox->rgbRanges[i]), (gdouble)rgba[i]); else for (i = 0; i < 4; i++) { g_signal_handler_block(G_OBJECT(colorComboBox->rgbRanges[i]), colorComboBox->rgbSignals[i]); gtk_range_set_value(GTK_RANGE(colorComboBox->rgbRanges[i]), (gdouble)rgba[i]); g_signal_handler_unblock(G_OBJECT(colorComboBox->rgbRanges[i]), colorComboBox->rgbSignals[i]); } } else { if (raiseSignal) gtk_combo_box_set_active(GTK_COMBO_BOX(colorComboBox), pos + 1); else { colorComboBox->previouslySelectedColor = color; g_signal_handler_block(G_OBJECT(colorComboBox), colorComboBox->comboSignal); gtk_combo_box_set_active(GTK_COMBO_BOX(colorComboBox), pos + 1); g_signal_handler_unblock(G_OBJECT(colorComboBox), colorComboBox->comboSignal); for (i = 0; i < 4; i++) { g_signal_handler_block(G_OBJECT(colorComboBox->rgbRanges[i]), colorComboBox->rgbSignals[i]); gtk_range_set_value(GTK_RANGE(colorComboBox->rgbRanges[i]), (gdouble)rgba[i]); g_signal_handler_unblock(G_OBJECT(colorComboBox->rgbRanges[i]), colorComboBox->rgbSignals[i]); } } } } static void onNewColorAvailable(ToolPool *pool _U_, ToolColor* newColor, gpointer data) { VisuUiColorComboboxClass *klass; GtkTreeIter iter; g_return_if_fail(data); DBG_fprintf(stderr, "Gtk VisuUiColorComboboxClass: catch the 'new-element' signal.\n"); klass = VISU_UI_COLOR_COMBOBOX_CLASS(data); addColorToModel(&iter, klass, newColor); } /** * visu_ui_color_combobox_getSelection: * @colorComboBox: a #VisuUiColorCombobox widget. * * The user can access to the selected #ToolColor object using this method. * * Returns: (transfer none): a pointer to the selected #ToolColor * object (or NULL). This object is read-only. * * Since: 3.1 */ const ToolColor* visu_ui_color_combobox_getSelection(VisuUiColorCombobox *colorComboBox) { gboolean validIter; GtkTreeIter iter; ToolColor *color; GObjectClass *klass; g_return_val_if_fail(VISU_IS_UI_COLOR_COMBOBOX(colorComboBox), (ToolColor*)0); validIter = gtk_combo_box_get_active_iter(GTK_COMBO_BOX(colorComboBox), &iter); if (!validIter) return (const ToolColor*)0; color = (ToolColor*)0; klass = G_OBJECT_GET_CLASS(colorComboBox); gtk_tree_model_get(GTK_TREE_MODEL(VISU_UI_COLOR_COMBOBOX_CLASS(klass)->listStoredColors), &iter, COLUMN_COLOR_POINTER_TO, &color, -1); return color; } /** * visu_ui_color_combobox_getPixbufFromColor: * @colorComboBox: a #VisuUiColorCombobox widget ; * @color: a #ToolColor object. * * The @colorComboBox has little pixbufs to represent the color. User methods can * use these pixbufs but should considered them read-only. * * Returns: (transfer full): a pixbuf pointer corresponding to the * little image shown on the @colorComboBox. * * Since: 3.1 */ GdkPixbuf* visu_ui_color_combobox_getPixbufFromColor(VisuUiColorCombobox *colorComboBox, ToolColor *color) { GtkTreeIter iter; gboolean validIter; GdkPixbuf *pixbuf; ToolColor *cl; GtkListStore *model; g_return_val_if_fail(colorComboBox && color, (GdkPixbuf*)0); model = VISU_UI_COLOR_COMBOBOX_CLASS(G_OBJECT_GET_CLASS(colorComboBox))->listStoredColors; validIter = gtk_tree_model_get_iter_first(GTK_TREE_MODEL(model), &iter); while (validIter) { pixbuf = (GdkPixbuf*)0; cl = (ToolColor*)0; if (colorComboBox->hasAlphaChannel) gtk_tree_model_get(GTK_TREE_MODEL(model), &iter, COLUMN_COLOR_PIXBUF_ALPHA, &pixbuf, COLUMN_COLOR_POINTER_TO, &cl, -1); else gtk_tree_model_get(GTK_TREE_MODEL(model), &iter, COLUMN_COLOR_PIXBUF, &pixbuf, COLUMN_COLOR_POINTER_TO, &cl, -1); if (cl && tool_color_equal(color, cl)) return pixbuf; if (pixbuf) g_object_unref(pixbuf); validIter = gtk_tree_model_iter_next(GTK_TREE_MODEL(model), &iter); } return (GdkPixbuf*)0; } /** * visu_ui_color_combobox_setRangeMaterial: * @colorComboBox: a #VisuUiColorCombobox widget ; * @material: TOOL_MATERIAL_N_VALUES (see #ToolMaterialIds) floating point values ; * @raiseSignal: if TRUE a material-value-changed can be raised. * * Change the values for the ranges that control the light (emission, diffuse...). * This is possible only if the @colorComboBox has been created with * visu_ui_color_combobox_newWithRanges(). * * Since: 3.3 */ void visu_ui_color_combobox_setRangeMaterial(VisuUiColorCombobox *colorComboBox, const float material[TOOL_MATERIAL_N_VALUES], gboolean raiseSignal) { int i; g_return_if_fail(VISU_IS_UI_COLOR_COMBOBOX(colorComboBox)); g_return_if_fail(colorComboBox->withRanges); if (raiseSignal) for (i = 0; i < TOOL_MATERIAL_N_VALUES; i++) gtk_range_set_value(GTK_RANGE(colorComboBox->materialRanges[i]), (gdouble)material[i]); else for (i = 0; i < TOOL_MATERIAL_N_VALUES; i++) { g_signal_handler_block(G_OBJECT(colorComboBox->materialRanges[i]), colorComboBox->materialSignals[i]); gtk_range_set_value(GTK_RANGE(colorComboBox->materialRanges[i]), (gdouble)material[i]); g_signal_handler_unblock(G_OBJECT(colorComboBox->materialRanges[i]), colorComboBox->materialSignals[i]); } } /** * visu_ui_color_combobox_getRangeMaterial: * @colorComboBox: a #VisuUiColorCombobox widget. * * If the @colorComboBox uses ranges (see visu_ui_color_combobox_newWithRanges()), this method * is used to get the values from the material ranges. * * Returns: (array fixed-size=5) (transfer full): a newly created array of size * TOOL_MATERIAL_N_VALUES (see #ToolMaterialIds). Use g_free() to delete it. * * Since: 3.3 */ float* visu_ui_color_combobox_getRangeMaterial(VisuUiColorCombobox *colorComboBox) { int i; float *values; g_return_val_if_fail(VISU_IS_UI_COLOR_COMBOBOX(colorComboBox), (float*)0); g_return_val_if_fail(colorComboBox->withRanges, (float*)0); values = g_malloc(sizeof(float) * TOOL_MATERIAL_N_VALUES); for (i = 0; i < TOOL_MATERIAL_N_VALUES; i++) values[i] = (float)gtk_range_get_value(GTK_RANGE(colorComboBox->materialRanges[i])); return values; } /** * visu_ui_color_combobox_getRangeColor: * @colorComboBox: a #VisuUiColorCombobox widget. * * If the @colorComboBox uses ranges (see visu_ui_color_combobox_newWithRanges()), this method * is used to get the values from the color ranges. * * Returns: (array fixed-size=4) (transfer full): a newly created * array of size 4. Use g_free() to delete it. * * Since: 3.2 */ float* visu_ui_color_combobox_getRangeColor(VisuUiColorCombobox *colorComboBox) { int i; float *values; g_return_val_if_fail(VISU_IS_UI_COLOR_COMBOBOX(colorComboBox), (float*)0); g_return_val_if_fail(colorComboBox->withRanges, (float*)0); values = g_malloc(sizeof(float) * 4); for (i = 0; i < 4; i++) values[i] = (float)gtk_range_get_value(GTK_RANGE(colorComboBox->rgbRanges[i])); return values; } /* Under developpement method, not used at the present time. */ /* void createColorSelectionCustomList(GtkColorSelectionDialog *selection) */ /* { */ /* GtkWidget *hbox; */ /* GtkWidget *buttonF, *buttonB, *button; */ /* GtkWidget *image; */ /* GtkWidget *table; */ /* GtkWidget *label; */ /* GtkWidget *align; */ /* gboolean validIter; */ /* GdkPixbuf *pixbuf; */ /* int i; */ /* gboolean usedPrevNext; */ /* #define N_SHOW_COLOR 15 */ /* GtkTreeIter iter; */ /* GtkWidget *imageGroup; */ /* GtkTreeIter *iterStored; */ /* hbox = gtk_hbox_new(FALSE, 0); */ /* gtk_widget_show(hbox); */ /* gtk_box_pack_start(GTK_BOX(GTK_DIALOG(selection)->vbox), hbox, FALSE, FALSE, 2); */ /* label = gtk_label_new(_("Stored colors:")); */ /* gtk_misc_set_alignment(GTK_MISC(label), 0., 0.5); */ /* gtk_widget_show(label); */ /* gtk_box_pack_start(GTK_BOX(hbox), label, TRUE, TRUE, 2); */ /* button = gtk_button_new_from_stock(GTK_STOCK_REMOVE); */ /* gtk_widget_show(button); */ /* gtk_box_pack_start(GTK_BOX(hbox), button, FALSE, FALSE, 2); */ /* usedPrevNext = (gtk_tree_model_iter_n_children(GTK_TREE_MODEL(listStoredColors), NULL) >= N_SHOW_COLOR); */ /* hbox = gtk_hbox_new(FALSE, 0); */ /* gtk_widget_show(hbox); */ /* gtk_box_pack_start(GTK_BOX(GTK_DIALOG(selection)->vbox), hbox, FALSE, FALSE, 2); */ /* if (usedPrevNext) */ /* { */ /* buttonB = gtk_button_new (); */ /* gtk_widget_show(buttonB); */ /* gtk_box_pack_start(GTK_BOX(hbox), buttonB, FALSE, FALSE, 2); */ /* image = gtk_image_new_from_stock(GTK_STOCK_GO_BACK, GTK_ICON_SIZE_BUTTON); */ /* gtk_widget_show (image); */ /* gtk_container_add(GTK_CONTAINER(buttonB), image); */ /* } */ /* align= gtk_alignment_new(0.5, 0.5, 0., 0.); */ /* gtk_widget_show(align); */ /* gtk_box_pack_start(GTK_BOX(hbox), align, FALSE, FALSE, 2); */ /* table = gtk_table_new(1, 10, FALSE); */ /* gtk_widget_show(table); */ /* gtk_container_add(GTK_CONTAINER(align), table); */ /* if (usedPrevNext) */ /* { */ /* buttonF = gtk_button_new (); */ /* gtk_widget_show(buttonF); */ /* gtk_box_pack_start(GTK_BOX(hbox), buttonF, FALSE, FALSE, 2); */ /* image = gtk_image_new_from_stock(GTK_STOCK_GO_FORWARD, GTK_ICON_SIZE_BUTTON); */ /* gtk_widget_show (image); */ /* gtk_container_add(GTK_CONTAINER(buttonF), image); */ /* } */ /* Put all the colors. */ /* imageGroup = (GtkWidget*)0; */ /* i = 0; */ /* validIter = gtk_tree_model_get_iter_first(GTK_TREE_MODEL(listStoredColors), &iter); */ /* while (validIter && i < N_SHOW_COLOR) */ /* { */ /* pixbuf = (GdkPixbuf*)0; */ /* gtk_tree_model_get(GTK_TREE_MODEL(listStoredColors), */ /* &iter, COLUMN_COLOR_PIXBUF_ALPHA, */ /* &pixbuf, -1); */ /* if (pixbuf) */ /* { */ /* if (!imageGroup) */ /* { */ /* imageGroup = gtk_radio_button_new(NULL); */ /* button = imageGroup; */ /* } */ /* else */ /* button = gtk_radio_button_new_from_widget(GTK_RADIO_BUTTON(imageGroup)); */ /* gtk_widget_show(button); */ /* gtk_table_attach(GTK_TABLE(table), button, i, i + 1, 0, 1, GTK_FILL, GTK_FILL, 2, 2); */ /* image = gtk_image_new_from_pixbuf(pixbuf); */ /* gtk_widget_show(image); */ /* gtk_container_add(GTK_CONTAINER(button), image); */ /* iterStored = gtk_tree_iter_copy(&iter); */ /* i += 1; */ /* } */ /* validIter = gtk_tree_model_iter_next(GTK_TREE_MODEL(listStoredColors), &iter); */ /* } */ /* } */ v_sim-3.8.0/src/extraGtkFunctions/gtk_colorComboBoxWidget.h000066400000000000000000000120011370110300500240210ustar00rootroot00000000000000/* EXTRAITS DE LA LICENCE Copyright CEA, contributeurs : Luc BILLARD et Damien CALISTE, laboratoire L_Sim, (2001-2005) Adresse mèl : BILLARD, non joignable par mèl ; CALISTE, damien P caliste AT cea P fr. Ce logiciel est un programme informatique servant à visualiser des structures atomiques dans un rendu pseudo-3D. Ce logiciel est régi par la licence CeCILL soumise au droit français et respectant les principes de diffusion des logiciels libres. Vous pouvez utiliser, modifier et/ou redistribuer ce programme sous les conditions de la licence CeCILL telle que diffusée par le CEA, le CNRS et l'INRIA sur le site "http://www.cecill.info". Le fait que vous puissiez accéder à cet en-tête signifie que vous avez pris connaissance de la licence CeCILL, et que vous en avez accepté les termes (cf. le fichier Documentation/licence.fr.txt fourni avec ce logiciel). */ /* LICENCE SUM UP Copyright CEA, contributors : Luc BILLARD et Damien CALISTE, laboratoire L_Sim, (2001-2005) E-mail address: BILLARD, not reachable any more ; CALISTE, damien P caliste AT cea P fr. This software is a computer program whose purpose is to visualize atomic configurations in 3D. This software is governed by the CeCILL license under French law and abiding by the rules of distribution of free software. You can use, modify and/ or redistribute the software under the terms of the CeCILL license as circulated by CEA, CNRS and INRIA at the following URL "http://www.cecill.info". The fact that you are presently reading this means that you have had knowledge of the CeCILL license and that you accept its terms. You can find a copy of this licence shipped with this software at Documentation/licence.en.txt. */ #ifndef GTK_COLORCOMBOBOXWIDGET_H #define GTK_COLORCOMBOBOXWIDGET_H #include #include #include #include #include G_BEGIN_DECLS /** * VISU_TYPE_UI_COLOR_COMBOBOX: * * Return the associated #GType to the VisuUiColorCombobox objects. * * Since: 3.1 */ #define VISU_TYPE_UI_COLOR_COMBOBOX (visu_ui_color_combobox_get_type ()) /** * VISU_UI_COLOR_COMBOBOX: * @obj: the widget to cast. * * Cast the given object to a #VisuUiColorCombobox object. * * Since: 3.1 */ #define VISU_UI_COLOR_COMBOBOX(obj) (G_TYPE_CHECK_INSTANCE_CAST ((obj), VISU_TYPE_UI_COLOR_COMBOBOX, VisuUiColorCombobox)) /** * VISU_UI_COLOR_COMBOBOX_CLASS: * @klass: the class to cast. * * Cast the given class to a #VisuUiColorComboboxClass object. * * Since: 3.1 */ #define VISU_UI_COLOR_COMBOBOX_CLASS(klass) (G_TYPE_CHECK_CLASS_CAST ((klass), VISU_TYPE_UI_COLOR_COMBOBOX, VisuUiColorComboboxClass)) /** * VISU_IS_UI_COLOR_COMBOBOX: * @obj: the object to test. * * Return if the given object is a valid #VisuUiColorCombobox object. * * Since: 3.1 */ #define VISU_IS_UI_COLOR_COMBOBOX(obj) (G_TYPE_CHECK_INSTANCE_TYPE ((obj), VISU_TYPE_UI_COLOR_COMBOBOX)) /** * VISU_IS_UI_COLOR_COMBOBOX_CLASS: * @klass: the class to test. * * Return if the given class is a valid #VisuUiColorComboboxClass class. * * Since: 3.1 */ #define VISU_IS_UI_COLOR_COMBOBOX_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE ((klass), VISU_TYPE_UI_COLOR_COMBOBOX)) /** * VISU_UI_COLOR_COMBOBOX_GET_CLASS: * @obj: a #GObject to get the class of. * * It returns the class of the given @obj. */ #define VISU_UI_COLOR_COMBOBOX_GET_CLASS(obj) (G_TYPE_INSTANCE_GET_CLASS(obj, VISU_TYPE_UI_COLOR_COMBOBOX, VisuUiColorComboboxClass)) typedef struct _VisuUiColorCombobox VisuUiColorCombobox; typedef struct _VisuUiColorComboboxClass VisuUiColorComboboxClass; GType visu_ui_color_combobox_get_type(void); GtkWidget* visu_ui_color_combobox_new(gboolean hasAlphaChannel); GtkWidget* visu_ui_color_combobox_newWithRanges(gboolean hasAlphaChannel); gboolean visu_ui_color_combobox_setSelection(VisuUiColorCombobox* colorComboBox, ToolColor *color); void visu_ui_color_combobox_setRangeColor(VisuUiColorCombobox *colorComboBox, const float rgba[4], gboolean raiseSignal); void visu_ui_color_combobox_setRangeMaterial(VisuUiColorCombobox *colorComboBox, const float material[TOOL_MATERIAL_N_VALUES], gboolean raiseSignal); const ToolColor* visu_ui_color_combobox_getSelection(VisuUiColorCombobox *colorComboBox); GdkPixbuf* visu_ui_color_combobox_getPixbufFromColor(VisuUiColorCombobox *colorComboBox, ToolColor *color); float* visu_ui_color_combobox_getRangeMaterial(VisuUiColorCombobox *colorComboBox); float* visu_ui_color_combobox_getRangeColor(VisuUiColorCombobox *colorComboBox); void visu_ui_color_combobox_setExpanded(VisuUiColorCombobox *colorComboBox, gboolean value); GtkWidget* visu_ui_color_combobox_getRangeWidgets(VisuUiColorCombobox *colorComboBox); void visu_ui_color_combobox_setPrintValues(VisuUiColorCombobox *colorComboBox, gboolean value); G_END_DECLS #endif v_sim-3.8.0/src/extraGtkFunctions/gtk_curveWidget.c000066400000000000000000001073551370110300500224120ustar00rootroot00000000000000/* EXTRAITS DE LA LICENCE Copyright CEA, contributeurs : Luc BILLARD et Damien CALISTE, laboratoire L_Sim, (2001-2005) Adresse mèl : BILLARD, non joignable par mèl ; CALISTE, damien P caliste AT cea P fr. Ce logiciel est un programme informatique servant à visualiser des structures atomiques dans un rendu pseudo-3D. Ce logiciel est régi par la licence CeCILL soumise au droit français et respectant les principes de diffusion des logiciels libres. Vous pouvez utiliser, modifier et/ou redistribuer ce programme sous les conditions de la licence CeCILL telle que diffusée par le CEA, le CNRS et l'INRIA sur le site "http://www.cecill.info". Le fait que vous puissiez accéder à cet en-tête signifie que vous avez pris connaissance de la licence CeCILL, et que vous en avez accepté les termes (cf. le fichier Documentation/licence.fr.txt fourni avec ce logiciel). */ /* LICENCE SUM UP Copyright CEA, contributors : Luc BILLARD et Damien CALISTE, laboratoire L_Sim, (2001-2005) E-mail address: BILLARD, not reachable any more ; CALISTE, damien P caliste AT cea P fr. This software is a computer program whose purpose is to visualize atomic configurations in 3D. This software is governed by the CeCILL license under French law and abiding by the rules of distribution of free software. You can use, modify and/ or redistribute the software under the terms of the CeCILL license as circulated by CEA, CNRS and INRIA at the following URL "http://www.cecill.info". The fact that you are presently reading this means that you have had knowledge of the CeCILL license and that you accept its terms. You can find a copy of this licence shipped with this software at Documentation/licence.en.txt. */ #include #include #include #include "gtk_curveWidget.h" #include #include #include #include #include /** * SECTION: gtk_curveWidget * @short_description: A specialised curve widget to draw distance * distribution for pairs. * * This is a psecialised widget to display g(r) * information. * * Since: 3.6 */ /** * VisuUiCurveFrame: * * An opaque structure defining a #VisuUiCurveFrame widget. * * Since: 3.6 */ struct _VisuUiCurveFrame { GtkDrawingArea parent; gboolean dispose_has_run, dirty; VisuPairSet *model; gulong pair_sig; ToolMatrixScalingFlag scale; float zoom; float dists[2]; float heights[2]; float hlRange[2]; VisuUiCurveFrameStyle style; VisuElement *filter; GHashTable *data; guint nSteps; float init, step; }; /** * VisuUiCurveFrameClass: * * An opaque structure defining the class of a #VisuUiCurveFrame widget. * * Since: 3.6 */ struct _VisuUiCurveFrameClass { GtkDrawingAreaClass parent_class; }; #define SPACER "\302\240-\302\240" #define ALL _("All") enum { PROP_0, MIN_PROP, MAX_PROP, ZOOM_PROP, MIN_HL_PROP, MAX_HL_PROP, INT_HL_PROP, MEAN_HL_PROP, FILTER_PROP, LABEL_PROP, N_PROP }; static GParamSpec *_properties[N_PROP]; /** * visu_ui_curve_frame_get_type: * * Internal routine to get #VISU_TYPE_UI_CURVE_FRAME value. * * Since: 3.6 */ G_DEFINE_TYPE (VisuUiCurveFrame, visu_ui_curve_frame, GTK_TYPE_DRAWING_AREA) #if GTK_MAJOR_VERSION < 3 && GTK_MINOR_VERSION < 26 static gboolean visu_ui_curve_frame_expose(GtkWidget *curve, GdkEventExpose *event); #endif static gboolean visu_ui_curve_frame_drawCairo(GtkWidget *curve, cairo_t *cr); static void visu_ui_curve_frame_get_property(GObject* obj, guint property_id, GValue *value, GParamSpec *pspec); static void visu_ui_curve_frame_set_property(GObject* obj, guint property_id, const GValue *value, GParamSpec *pspec); static void visu_ui_curve_frame_dispose(GObject *obj); static void visu_ui_curve_frame_finalize(GObject *obj); static void hashDraw(gpointer key, gpointer value, gpointer usre_data); static void drawData(VisuUiCurveFrame *curve, cairo_t *cr, const gchar *name, const guint *data, double w, double h, double dw, VisuUiCurveFrameStyle style); static void _addData(VisuUiCurveFrame *curve, const gchar *eleName, const gchar *lkName, const guint *data, guint nSteps, float init, float step); static void _setNNodes(VisuUiCurveFrame *curve, const gchar *ele, guint n); static void visu_ui_curve_frame_class_init (VisuUiCurveFrameClass *klass) { #if GTK_MAJOR_VERSION < 3 && GTK_MINOR_VERSION < 26 GTK_WIDGET_CLASS(klass)->expose_event = visu_ui_curve_frame_expose; #else GTK_WIDGET_CLASS(klass)->draw = visu_ui_curve_frame_drawCairo; #endif G_OBJECT_CLASS(klass)->dispose = visu_ui_curve_frame_dispose; G_OBJECT_CLASS(klass)->finalize = visu_ui_curve_frame_finalize; G_OBJECT_CLASS(klass)->get_property = visu_ui_curve_frame_get_property; G_OBJECT_CLASS(klass)->set_property = visu_ui_curve_frame_set_property; /** * VisuUiCurveFrame::minimum: * * Store the minimum distance to get the g(r) from. * * Since: 3.8 */ _properties[MIN_PROP] = g_param_spec_float("minimum", "Minimum", "minimum distance", 0.f, G_MAXFLOAT, 0.f, G_PARAM_READWRITE); /** * VisuUiCurveFrame::maximum: * * Store the maximum distance to get the g(r) to. * * Since: 3.8 */ _properties[MAX_PROP] = g_param_spec_float("maximum", "Maximum", "maximum distance", 0.f, G_MAXFLOAT, 10.f, G_PARAM_READWRITE); /** * VisuUiCurveFrame::zoom: * * Store the zoom factor to discretise the g(r). * * Since: 3.8 */ _properties[ZOOM_PROP] = g_param_spec_float("zoom", "Zoom", "zoom factor", 1.f, G_MAXFLOAT, 5.f, G_PARAM_READWRITE); /** * VisuUiCurveFrame::minimum-highlight: * * Store the minimum distance for the highlight region. * * Since: 3.8 */ _properties[MIN_HL_PROP] = g_param_spec_float("minimum-highlight", "Minimum highlight", "minimum highlight distance", 0.f, G_MAXFLOAT, 1.f, G_PARAM_READWRITE); /** * VisuUiCurveFrame::maximum-highlight: * * Store the maximum distance for the highlight region. * * Since: 3.8 */ _properties[MAX_HL_PROP] = g_param_spec_float("maximum-highlight", "Maximum highlight", "maximum highlight distance", 0.f, G_MAXFLOAT, 1.f, G_PARAM_READWRITE); /** * VisuUiCurveFrame::integral-in-range: * * Store the integral value in the highlight range. * * Since: 3.8 */ _properties[INT_HL_PROP] = g_param_spec_float("integral-in-range", "Integral in range", "integral value in highlight range", 0.f, G_MAXFLOAT, 0.f, G_PARAM_READABLE); /** * VisuUiCurveFrame::mean-in-range: * * Store the mean value in the highlight range. * * Since: 3.8 */ _properties[MEAN_HL_PROP] = g_param_spec_float("mean-in-range", "Mean in range", "mean value in highlight range", 0.f, G_MAXFLOAT, 0.f, G_PARAM_READABLE); /** * VisuUiCurveFrame::filter: * * Store the filter. * * Since: 3.8 */ _properties[FILTER_PROP] = g_param_spec_object("filter", "Filter", "filter by element", VISU_TYPE_ELEMENT, G_PARAM_READWRITE); /** * VisuUiCurveFrame::label: * * Store the label used by the filter. * * Since: 3.8 */ _properties[LABEL_PROP] = g_param_spec_string("label", "Label", "label describing the filter", "", G_PARAM_READABLE); g_object_class_install_properties(G_OBJECT_CLASS(klass), N_PROP, _properties); } static void visu_ui_curve_frame_init(VisuUiCurveFrame *curve) { curve->dispose_has_run = FALSE; curve->model = (VisuPairSet*)0; curve->dirty = TRUE; curve->style = CURVE_LINEAR; curve->scale = TOOL_MATRIX_SCALING_LOG; curve->heights[0] = 0.; curve->heights[1] = 5.; curve->dists[0] = 0.f; curve->dists[1] = G_MAXFLOAT; curve->hlRange[0] = -1.f; curve->zoom = 5.f; curve->filter = (VisuElement*)0; curve->data = g_hash_table_new_full(g_str_hash, g_str_equal, g_free, g_free); } static void visu_ui_curve_frame_get_property(GObject* obj, guint property_id, GValue *value, GParamSpec *pspec) { VisuUiCurveFrame *self = VISU_UI_CURVE_FRAME(obj); guint *data, i, n; gfloat d, val; switch (property_id) { case MIN_PROP: g_value_set_float(value, self->dists[0]); break; case MAX_PROP: g_value_set_float(value, self->dists[1]); break; case ZOOM_PROP: g_value_set_float(value, self->zoom); break; case MIN_HL_PROP: g_value_set_float(value, self->hlRange[0]); break; case MAX_HL_PROP: g_value_set_float(value, self->hlRange[1]); break; case INT_HL_PROP: if (self->filter) data = (guint*)g_hash_table_lookup(self->data, visu_element_getName(self->filter)); else data = (guint*)g_hash_table_lookup(self->data, ALL); if (data) { val = 0.f; for (i = 0, d = self->init; i < self->nSteps - 1; i++, d += self->step) if (d >= self->hlRange[0] && d < self->hlRange[1]) val += (float)data[i]; g_value_set_float(value, val / (float)data[self->nSteps - 1]); } else g_value_set_float(value, 0.f); break; case MEAN_HL_PROP: if (self->filter) data = (guint*)g_hash_table_lookup(self->data, visu_element_getName(self->filter)); else data = (guint*)g_hash_table_lookup(self->data, ALL); if (data) { val = 0.f; n = 0; for (i = 0, d = self->init; i < self->nSteps - 1; i++, d += self->step) if (d >= self->hlRange[0] && d < self->hlRange[1]) { val += (float)data[i] * (d + self->step * 0.5f); n += data[i]; } g_value_set_float(value, val / (float)n); } else g_value_set_float(value, 0.f); break; case FILTER_PROP: g_value_set_object(value, self->filter); break; case LABEL_PROP: g_value_set_string(value, self->filter ? visu_element_getName(self->filter) : ALL); break; default: /* We don't have any other property... */ G_OBJECT_WARN_INVALID_PROPERTY_ID(obj, property_id, pspec); break; } } static void visu_ui_curve_frame_set_property(GObject* obj, guint property_id, const GValue *value, GParamSpec *pspec) { VisuUiCurveFrame *self = VISU_UI_CURVE_FRAME(obj); float rg[2]; switch (property_id) { case MIN_PROP: rg[0] = g_value_get_float(value); rg[1] = self->dists[1]; visu_ui_curve_frame_setSpan(self, rg); break; case MAX_PROP: rg[0] = self->dists[0]; rg[1] = g_value_get_float(value); visu_ui_curve_frame_setSpan(self, rg); break; case ZOOM_PROP: visu_ui_curve_frame_setZoomFactor(self, g_value_get_float(value)); break; case MIN_HL_PROP: rg[0] = g_value_get_float(value); rg[1] = self->hlRange[1]; visu_ui_curve_frame_setHighlightRange(self, rg); break; case MAX_HL_PROP: rg[0] = self->hlRange[0]; rg[1] = g_value_get_float(value); visu_ui_curve_frame_setHighlightRange(self, rg); break; case FILTER_PROP: visu_ui_curve_frame_setFilter(self, VISU_ELEMENT(g_value_get_object(value))); break; default: /* We don't have any other property... */ G_OBJECT_WARN_INVALID_PROPERTY_ID(obj, property_id, pspec); break; } } static void visu_ui_curve_frame_dispose(GObject *obj) { DBG_fprintf(stderr, "Gtk Curve: dispose object %p.\n", (gpointer)obj); if (VISU_UI_CURVE_FRAME(obj)->dispose_has_run) return; VISU_UI_CURVE_FRAME(obj)->dispose_has_run = TRUE; visu_ui_curve_frame_setModel(VISU_UI_CURVE_FRAME(obj), (VisuPairSet*)0); visu_ui_curve_frame_setFilter(VISU_UI_CURVE_FRAME(obj), (VisuElement*)0); /* Chain up to the parent class */ G_OBJECT_CLASS(visu_ui_curve_frame_parent_class)->dispose(obj); } static void visu_ui_curve_frame_finalize(GObject *obj) { g_return_if_fail(obj); DBG_fprintf(stderr, "Gtk Curve: finalize object %p.\n", (gpointer)obj); g_hash_table_destroy(VISU_UI_CURVE_FRAME(obj)->data); /* Chain up to the parent class */ G_OBJECT_CLASS(visu_ui_curve_frame_parent_class)->finalize(obj); DBG_fprintf(stderr, " | freeing ... OK.\n"); } static double tickDist(float dists[2], int length, ToolMatrixScalingFlag scale) { #define TICK_SPACE 50.f float s, l, n; n = (float)length / TICK_SPACE; s = (dists[1] - dists[0]) / n; l = log10(s); l = (int)((l < 0.f)?l - 1.f:l); s = s / exp(l * log(10)); if (scale == TOOL_MATRIX_SCALING_LINEAR) { if (s <= 1.25) n = 1.f; else if (s <= 3.75) n = 2.5f; else if (s <= 7.5) n = 5.f; else s = 10.f; } else { if (s <= 5.f) n = 1.f; else n = 10.f; } s = n * exp(l * log(10)); return (double)s; } static gboolean isValidData(VisuElement* filter, const gchar *data) { gchar *tmp; gboolean res; if (filter) { tmp = g_strdup_printf("%s"SPACER, visu_element_getName(filter)); res = (!strcmp(data, visu_element_getName(filter)) || strstr(data, tmp)); g_free(tmp); } else res = (!strcmp(data, ALL) || !strstr(data, SPACER)); return res; } static void setCairoColor(cairo_t *cr, const VisuElement *filter, const gchar *data) { VisuElement *ele; const ToolColor *color; gchar *tmp; const gchar *name; if (!filter) name = data; else { tmp = g_strdup_printf("%s"SPACER, visu_element_getName(filter)); name = data + strlen(tmp); g_free(tmp); } ele = visu_element_lookup(name); if (ele) { color = visu_element_renderer_getColor(visu_element_renderer_getFromPool(ele)); cairo_set_source_rgb (cr, color->rgba[0], color->rgba[1], color->rgba[2]); } else cairo_set_source_rgb (cr, 0.5, 0.5, 0.5); } static void _compute(VisuUiCurveFrame *curve) { VisuPair *pair; VisuData *dataObj; VisuPairDistribution *dd; guint i, *storage; curve->dirty = FALSE; g_hash_table_remove_all(curve->data); if (!curve->model) return; g_object_get(curve->model, "data", &dataObj, NULL); if (!dataObj) return; curve->nSteps = 0; curve->init = -1.f; curve->step = (curve->dists[1] - curve->dists[0]) / curve->zoom / 50.f; i = 0; while ((pair = visu_pair_set_getNthPair(curve->model, i++))) { dd = visu_pair_getDistanceDistribution(pair, dataObj, curve->step, curve->dists[0], curve->dists[1]); if (i == 1) { curve->init = dd->initValue; curve->nSteps = dd->nValues; storage = g_malloc0(sizeof(guint) * curve->nSteps); g_hash_table_insert(curve->data, g_strdup(ALL), storage); } _addData(curve, dd->ele1->name, dd->ele2->name, dd->histo, dd->nValues, dd->initValue, dd->stepValue); if (dd->ele1 == dd->ele2) _setNNodes(curve, dd->ele1->name, dd->nNodesEle1); }; g_object_unref(dataObj); } struct _drawData { VisuUiCurveFrame *curve; cairo_t *cr; double w; double h; double dw; }; static gboolean visu_ui_curve_frame_drawCairo(GtkWidget *wd, cairo_t *cr) { #define BUF 3. double x, s, f, g, w, h, dw, dh, xp, wl, hl, yp; float *dists, *heights; gchar val[64]; cairo_text_extents_t ext; struct _drawData dt; guint *data; VisuUiCurveFrame *curve; GList *eles, *tmpLst; GtkAllocation allocation; DBG_fprintf(stderr, "Gtk Curve: general redraw.\n"); curve = VISU_UI_CURVE_FRAME(wd); if (curve->dirty) _compute(curve); dists = curve->dists; heights = curve->heights; gtk_widget_get_allocation(wd, &allocation); cairo_select_font_face(cr, "Sans", CAIRO_FONT_SLANT_NORMAL, CAIRO_FONT_WEIGHT_NORMAL); cairo_set_font_size(cr, 10.0); cairo_text_extents(cr, "10000.", &ext); dw = ext.width + BUF * 2.; dh = ext.height + BUF * 2.; w = (double)allocation.width - dw; h = (double)allocation.height - dh; data = (guint*)g_hash_table_lookup(curve->data, (curve->filter)?visu_element_getName(curve->filter):ALL); /* the frame itself. */ cairo_set_line_width(cr, 1.); cairo_rectangle(cr, dw - 0.5, 0.5, w, h); cairo_set_source_rgb (cr, 1, 1, 1); cairo_fill_preserve (cr); cairo_set_source_rgb (cr, 0, 0, 0); cairo_stroke (cr); cairo_set_line_width(cr, 2.); DBG_fprintf(stderr, "Gtk Curve: frame done.\n"); /* The highlight zone. */ if (curve->hlRange[0] >= 0.f && data) { wl = w * CLAMP((curve->hlRange[1] - curve->hlRange[0]) / (dists[1] - dists[0]), 0.f, 1.f); cairo_set_source_rgba(cr, 0.05, 0., 1., 0.25); cairo_rectangle(cr, dw + w * CLAMP((curve->hlRange[0] - dists[0])/ (dists[1] - dists[0]), 0.f, 1.f), 0.5, wl, h); cairo_fill(cr); } /* The plots. */ dt.curve = curve; dt.cr = cr; dt.w = w; dt.dw = dw; dt.h = h; if (data && curve->style != CURVE_BAR) drawData(curve, cr, (curve->filter)?visu_element_getName(curve->filter):ALL, data, w, h, dw, CURVE_BAR); g_hash_table_foreach(curve->data, hashDraw, &dt); if (data && curve->style == CURVE_BAR) drawData(curve, cr, (curve->filter)?visu_element_getName(curve->filter):ALL, data, w, h, dw, CURVE_LINEAR); DBG_fprintf(stderr, "Gtk Curve: plots done.\n"); /* the ticks & the labels */ cairo_set_source_rgb (cr, 0, 0, 0); cairo_set_line_width(cr, 2.); f = w / (dists[1] - dists[0]); g = 1.f / f; s = tickDist(dists, w, TOOL_MATRIX_SCALING_LINEAR) * f; for (x = - dists[0] * f; x <= w; x += s) if (x >= 0.) { cairo_move_to(cr, dw + x, 0); cairo_line_to(cr, dw + x, 3); cairo_move_to(cr, dw + x, h); cairo_line_to(cr, dw + x, h - 3); cairo_stroke(cr); sprintf(val, "%g", x * g + dists[0]); cairo_text_extents(cr, val, &ext); cairo_move_to(cr, dw + MIN(MAX(0., x - ext.width/2 - ext.x_bearing), w - ext.width - ext.x_bearing), allocation.height - ext.height - ext.y_bearing - BUF); cairo_show_text(cr, val); } if (curve->scale == TOOL_MATRIX_SCALING_LOG) f = h / log(heights[1] + 0.5f); else { f = h / heights[1]; s = tickDist(heights, h, curve->scale); } for (x = (curve->scale == TOOL_MATRIX_SCALING_LOG)?1.:0.; x <= heights[1]; x = (curve->scale == TOOL_MATRIX_SCALING_LOG)?x * 10:x + s) { if (curve->scale == TOOL_MATRIX_SCALING_LOG) { cairo_set_line_width(cr, 1.); for (xp = x * 2.; xp < x * 10.; xp += x) { yp = h - log(xp + 0.5f) * f; cairo_move_to(cr, dw + 0, yp); cairo_line_to(cr, dw + 1.5, yp); cairo_move_to(cr, allocation.width, yp); cairo_line_to(cr, allocation.width - 2.5, yp); cairo_stroke(cr); } xp = h - log(x + 0.5f) * f; } else xp = h - x * f; cairo_set_line_width(cr, 2.); cairo_move_to(cr, dw + 0, xp); cairo_line_to(cr, dw + 3, xp); cairo_move_to(cr, allocation.width, xp); cairo_line_to(cr, allocation.width - 4, xp); cairo_stroke(cr); sprintf(val, "%g", x); cairo_text_extents(cr, val, &ext); cairo_move_to(cr, dw - BUF - ext.width - ext.x_bearing, MIN(MAX(- ext.y_bearing, xp - ext.height/2 - ext.y_bearing), h)); cairo_show_text(cr, val); } DBG_fprintf(stderr, "Gtk Curve: ticks done.\n"); /* The legend. */ eles = g_hash_table_get_keys(curve->data); if (eles) { DBG_fprintf(stderr, "Gtk Curve: rebuild the legend (%d).\n", g_list_length(eles)); wl = 0; s = 0; hl = BUF; for (tmpLst = eles; tmpLst; tmpLst = g_list_next(tmpLst)) if (isValidData(curve->filter, (gchar*)tmpLst->data)) { cairo_text_extents(cr, (gchar*)tmpLst->data, &ext); DBG_fprintf(stderr, " | '%s' -> %fx%fx%f\n", (gchar*)tmpLst->data, ext.width, ext.height, ext.y_bearing); wl = MAX(wl, ext.width); s = MAX(s, -ext.y_bearing - 2.); hl += BUF - ext.y_bearing; } wl += 2 * BUF + BUF + s; hl += BUF; cairo_set_line_width(cr, 1.); cairo_rectangle(cr, dw + 3 + BUF + 0.5, 0.5 + 3 + BUF, wl, hl); cairo_set_source_rgb(cr, 0.67, 0.67, 0.67); cairo_fill_preserve (cr); cairo_set_source_rgb (cr, 0, 0, 0); cairo_stroke (cr); hl = BUF; for (tmpLst = eles; tmpLst; tmpLst = g_list_next(tmpLst)) if (isValidData(curve->filter, (gchar*)tmpLst->data)) { cairo_text_extents(cr, (gchar*)tmpLst->data, &ext); hl -= ext.y_bearing; cairo_move_to(cr, dw + 3 + 3 * BUF + 0.5 + ext.x_bearing + s, 0.5 + 3 + BUF + hl); cairo_set_source_rgb(cr, 0, 0, 0); cairo_show_text(cr, (gchar*)tmpLst->data); cairo_arc(cr, dw + 3 + 2 * BUF + 0.5 + s / 2., 0.5 + 3 + BUF + hl - s / 2., s / 2., 0, 2 * G_PI); setCairoColor(cr, curve->filter, (gchar*)tmpLst->data); cairo_fill(cr); hl += BUF/* + ext.y_bearing + ext.height */; } g_list_free(eles); } DBG_fprintf(stderr, "Gtk Curve: redraw done.\n"); return FALSE; } static void hashDraw(gpointer key, gpointer value, gpointer user_data) { struct _drawData *dt; gchar *tmp; gboolean ret; if (!strcmp(key, ALL)) return; dt = (struct _drawData*)user_data; if (!dt->curve->filter) { if (strstr((gchar*)key, SPACER)) return; } else { tmp = g_strdup_printf("%s"SPACER, visu_element_getName(dt->curve->filter)); ret = (!strstr((gchar*)key, tmp)); g_free(tmp); if (ret) return; } drawData(dt->curve, dt->cr, (gchar*)key, (guint*)value, dt->w, dt->h, dt->dw, dt->curve->style); } static void drawData(VisuUiCurveFrame *curve, cairo_t *cr, const gchar *name, const guint *data, double w, double h, double dw, VisuUiCurveFrameStyle style) { float step, fx, x, fy, y, val, init; int nSteps, i; double bw; VisuPairDistribution dd; guint startStopId[2], pos; cairo_text_extents_t ext; gchar str[25]; init = curve->init; step = curve->step; nSteps = curve->nSteps; setCairoColor(cr, curve->filter, name); bw = MAX(w * step / (curve->dists[1] - curve->dists[0]) - 1., 0.5); if (style == CURVE_BAR) cairo_set_line_width(cr, bw); else cairo_set_line_width(cr, 1.5); cairo_move_to(cr, dw, h - 0.5); fx = w / (curve->dists[1] - curve->dists[0]); if (curve->scale == TOOL_MATRIX_SCALING_LINEAR) fy = (h - 1.) / (curve->heights[1] - curve->heights[0]); else fy = (h - 1.) / log(curve->heights[1] + 0.5); for (i = 0; i < nSteps - 1; i++) if ((val = (step * i + init - curve->dists[0])) >= 0.) { if (style != CURVE_BAR || data[i] > 0) { x = dw + val * fx + bw / 2.; if (style == CURVE_BAR) cairo_move_to(cr, x, h - 0.5); if (curve->scale == TOOL_MATRIX_SCALING_LINEAR) cairo_line_to(cr, x, h - 0.5 - data[i] * fy); else cairo_line_to(cr, x, h - 0.5 - log(MAX(data[i] + 0.5, 1)) * fy); if (style == CURVE_BAR) cairo_stroke(cr); } } if (style != CURVE_BAR) cairo_stroke(cr); if (style != CURVE_BAR) { dd.histo = (guint*)data; dd.nValues = (guint)nSteps; dd.initValue = init; dd.stepValue = step; if (curve->scale == TOOL_MATRIX_SCALING_LINEAR) dd.nNodesEle1 = dd.nNodesEle2 = h / fy / 1.5; else dd.nNodesEle1 = dd.nNodesEle2 = exp(h / fy / 1.5); startStopId[0] = 0; startStopId[1] = (guint)(nSteps - 1); while (visu_pair_distribution_getNextPick(&dd, startStopId, (guint*)0, (guint*)0, &pos)) { sprintf(str, "%6.3f", init + step * pos); val = step * pos + init - curve->dists[0]; cairo_text_extents(cr, str, &ext); x = val * fx + bw / 2. + 1.; x = (x + ext.width >= w)?w - ext.width:x; y = h - 0.5; if (curve->scale == TOOL_MATRIX_SCALING_LINEAR) y -= data[pos] * fy; else y -= log(MAX(data[pos] + 0.5, 1)) * fy; y += ext.height / 2.; y = MAX(y, ext.height + 1.5); cairo_move_to(cr, dw + x, y); cairo_set_source_rgb (cr, 0., 0., 0.); cairo_show_text(cr, str); startStopId[0] = startStopId[1]; startStopId[1] = (guint)(nSteps - 1); } } } #if GTK_MAJOR_VERSION < 3 && GTK_MINOR_VERSION < 26 static gboolean visu_ui_curve_frame_expose(GtkWidget *curve, GdkEventExpose *event) { cairo_t *cr; gboolean res; /* get a cairo_t */ cr = gdk_cairo_create(GDK_DRAWABLE(gtk_widget_get_window(curve))); cairo_rectangle (cr, event->area.x, event->area.y, event->area.width, event->area.height); cairo_clip (cr); res = visu_ui_curve_frame_drawCairo(curve, cr); cairo_destroy (cr); return res; } #endif /** * visu_ui_curve_frame_new: * @distMin: a float. * @distMax: a float (bigger than @distMin). * * It creates a graph that can display distances distribution for * #VisuElement pairing. The display span is given by @distMin and @distMax. * * Since: 3.6 * * Returns: a newly craeted #VisuUiCurveFrame widget. */ GtkWidget *visu_ui_curve_frame_new(float distMin, float distMax) { g_return_val_if_fail(distMin >= 0.f && distMax > distMin, (GtkWidget*)0); return g_object_new(VISU_TYPE_UI_CURVE_FRAME, "minimum", distMin, "maximum", distMax, NULL); } /** * visu_ui_curve_frame_setSpan: * @curve: a #VisuUiCurveFrame widget. * @span: two floats. * * Changes the distance range that is displayed on the curve. * * Since: 3.6 * * Returns: TRUE if the distance displayed is actually changed. */ gboolean visu_ui_curve_frame_setSpan(VisuUiCurveFrame *curve, float span[2]) { gboolean updateMin, updateMax; g_return_val_if_fail(VISU_IS_UI_CURVE_FRAME(curve), FALSE); g_return_val_if_fail(span[0] >= 0.f && span[1] > span[0], FALSE); updateMin = (curve->dists[0] != span[0]); updateMax = (curve->dists[1] != span[1]); curve->dists[0] = span[0]; curve->dists[1] = span[1]; if (updateMin) g_object_notify_by_pspec(G_OBJECT(curve), _properties[MIN_PROP]); if (updateMax) g_object_notify_by_pspec(G_OBJECT(curve), _properties[MAX_PROP]); if (curve->hlRange[0] < curve->dists[0]) { curve->hlRange[0] = curve->dists[0]; g_object_notify_by_pspec(G_OBJECT(curve), _properties[MIN_HL_PROP]); } if (curve->hlRange[1] > curve->dists[1]) { curve->hlRange[1] = curve->dists[1]; g_object_notify_by_pspec(G_OBJECT(curve), _properties[MAX_HL_PROP]); } if (updateMin || updateMax) { curve->dirty = TRUE; gtk_widget_queue_draw(GTK_WIDGET(curve)); } return updateMin || updateMax; } /** * visu_ui_curve_frame_getSpan: * @curve: a #VisuUiCurveFrame widget. * @span: a location for two floats. * * Retrieves the distances inside which the distribution is displayed. * * Since: 3.6 */ void visu_ui_curve_frame_getSpan(VisuUiCurveFrame *curve, float span[2]) { g_return_if_fail(VISU_IS_UI_CURVE_FRAME(curve)); span[0] = curve->dists[0]; span[1] = curve->dists[1]; } /** * visu_ui_curve_frame_setZoomFactor: * @curve: a #VisuUiCurveFrame widget. * @zoom: the zoom factor. * * Adjusts the zoom factor. * * Since: 3.8 * * Returns: TRUE if value is actually changed. */ gboolean visu_ui_curve_frame_setZoomFactor(VisuUiCurveFrame *curve, float zoom) { g_return_val_if_fail(VISU_IS_UI_CURVE_FRAME(curve) && zoom >= 0.f, FALSE); if (zoom == curve->zoom) return FALSE; curve->zoom = zoom; g_object_notify_by_pspec(G_OBJECT(curve), _properties[ZOOM_PROP]); curve->dirty = TRUE; gtk_widget_queue_draw(GTK_WIDGET(curve)); return TRUE; } static void onPairsNotify(VisuPairSet *set _U_, GParamSpec *pspec _U_, gpointer data) { VISU_UI_CURVE_FRAME(data)->dirty = TRUE; gtk_widget_queue_draw(GTK_WIDGET(data)); } /** * visu_ui_curve_frame_setModel: * @curve: a #VisuUiCurveFrame object. * @model: a #VisuPairSet object. * * Bind the #VisuPairLink of @model to @curve. * * Since: 3.8 * * Returns: TRUE if the value actually changed. **/ gboolean visu_ui_curve_frame_setModel(VisuUiCurveFrame *curve, VisuPairSet *model) { g_return_val_if_fail(VISU_IS_UI_CURVE_FRAME(curve), FALSE); if (curve->model == model) return FALSE; if (curve->model) { g_signal_handler_disconnect(curve->model, curve->pair_sig); g_object_unref(curve->model); } if (model) { g_object_ref(model); curve->pair_sig = g_signal_connect(model, "notify::pairs", G_CALLBACK(onPairsNotify), curve); } curve->model = model; return TRUE; } /** * visu_ui_curve_frame_addData: * @curve: a #VisuUiCurveFrame widget. * @eleName: a string. * @lkName: a string. * @data: an array of frequencies. * @nSteps: the size of @data. * @init: the initial x value for array @data. * @step: the step value to increase x for array @data. * * This routine changes the distribution for element @eleName, with * respect to element @lkName. @data is an array that gives the number @data[i] * of pairs @eleName - @lkName which distance is in (@init + @step * i). * * Since: 3.6 */ static void _addData(VisuUiCurveFrame *curve, const gchar *eleName, const gchar *lkName, const guint *data, guint nSteps, float init, float step) { guint max, i; guint *storage, *all, *ele1, *ele2; gchar *link1, *link2; g_return_if_fail(VISU_IS_UI_CURVE_FRAME(curve)); g_return_if_fail(eleName && eleName[0] && lkName && lkName[0] && data); g_return_if_fail(curve->nSteps == nSteps && curve->init == init && curve->step == step); link1 = g_strdup_printf("%s"SPACER"%s", eleName, lkName); if (strcmp(eleName, lkName)) link2 = g_strdup_printf("%s"SPACER"%s", lkName, eleName); else link2 = (gchar*)0; DBG_fprintf(stderr, "Gtk Curve: add data for link '%s'.\n", link1); ele1 = (guint*)g_hash_table_lookup(curve->data, eleName); ele2 = (guint*)g_hash_table_lookup(curve->data, lkName); all = (guint*)g_hash_table_lookup(curve->data, ALL); /* Create or replace the link data themselves. */ storage = (guint*)g_hash_table_lookup(curve->data, link1); if (storage) { /* Remove it from the element data and all data. */ g_return_if_fail(all && ele1 && ele2); DBG_fprintf(stderr, "Gtk Curve: remove previously stored" " values for link '%s'.\n", link1); for (i = 0; i < nSteps; i++) { ele1[i] -= storage[i]; if (ele1 != ele2) ele2[i] -= storage[i]; all[i] -= storage[i]; } } DBG_fprintf(stderr, "Gtk Curve: copy histo values.\n"); storage = g_memdup(data, sizeof(int) * nSteps); g_hash_table_insert(curve->data, link1, (gpointer)storage); if (link2) { storage = g_memdup(data, sizeof(int) * nSteps); g_hash_table_insert(curve->data, link2, (gpointer)storage); } /* Add the data to the element data and all data. */ if (!ele1) { ele1 = g_memdup(data, sizeof(int) * nSteps); g_hash_table_insert(curve->data, g_strdup(eleName), (gpointer)ele1); } else for (i = 0; i < nSteps - 1; i++) ele1[i] += data[i]; if (link2) { if (!ele2) { ele2 = g_memdup(data, sizeof(int) * nSteps); g_hash_table_insert(curve->data, g_strdup(lkName), (gpointer)ele2); } else for (i = 0; i < nSteps - 1; i++) ele2[i] += data[i]; } max = 0; for (i = 0; i < nSteps - 1; i++) { max = MAX(max, data[i]); all[i] += data[i]; } curve->heights[1] = MAX(curve->heights[1], max * 1.1f); DBG_fprintf(stderr, " | max %g becomes %g.\n", (double)max, curve->heights[1]); } /** * visu_ui_curve_frame_setNNodes: * @curve: a #VisuUiCurveFrame widget. * @ele: a string. * @n: a number. * * Modify the number of ... TODO * * Since: 3.6 */ static void _setNNodes(VisuUiCurveFrame *curve, const gchar *ele, guint n) { guint *data; g_return_if_fail(VISU_IS_UI_CURVE_FRAME(curve)); data = (guint*)g_hash_table_lookup(curve->data, ele); g_return_if_fail(data); data[curve->nSteps - 1] = n; data = (guint*)g_hash_table_lookup(curve->data, ALL); g_return_if_fail(data); data[curve->nSteps - 1] += n; DBG_fprintf(stderr, "Gtk Curve: set %d nodes to '%s' (all = %d).\n", n, ele, data[curve->nSteps - 1]); } /** * visu_ui_curve_frame_setStyle: * @curve: a #VisuUiCurveFrame object. * @style: a style id. * * Modify the rendering style of the graph. * * Since: 3.5 * * Returns: TRUE if the style is actually changed. */ gboolean visu_ui_curve_frame_setStyle(VisuUiCurveFrame *curve, VisuUiCurveFrameStyle style) { g_return_val_if_fail(VISU_IS_UI_CURVE_FRAME(curve), FALSE); if (curve->style == style) return FALSE; curve->style = style; curve->dirty = TRUE; gtk_widget_queue_draw(GTK_WIDGET(curve)); return TRUE; } /** * visu_ui_curve_frame_setFilter: * @curve: a #VisuUiCurveFrame widget. * @filter: a string. * * Modify the filter used to draw all or single #VisuElement * distribution. * * Since: 3.6 * * Returns: TRUE if filter is actually changed. */ gboolean visu_ui_curve_frame_setFilter(VisuUiCurveFrame *curve, VisuElement* filter) { g_return_val_if_fail(VISU_IS_UI_CURVE_FRAME(curve), FALSE); if (curve->filter == filter) return FALSE; if (curve->filter) g_object_unref(curve->filter); curve->filter = filter; if (filter) g_object_ref(filter); g_object_notify_by_pspec(G_OBJECT(curve), _properties[FILTER_PROP]); g_object_notify_by_pspec(G_OBJECT(curve), _properties[LABEL_PROP]); curve->dirty = TRUE; gtk_widget_queue_draw(GTK_WIDGET(curve)); return TRUE; } /** * visu_ui_curve_frame_setHighlightRange: * @curve: a #VisuUiCurveFrame widget. * @range: two floats. * * Modify the distance span that is used for highlight rendering and * calculation, see visu_ui_curve_frame_getMeanInRange(). * * Since: 3.6 * * Returns: TRUE if range is actually changed. */ gboolean visu_ui_curve_frame_setHighlightRange(VisuUiCurveFrame *curve, float range[2]) { gboolean updateMin, updateMax; g_return_val_if_fail(VISU_IS_UI_CURVE_FRAME(curve), FALSE); DBG_fprintf(stderr, "Gtk Curve: set highlight range to %gx%g.\n", range[0], range[1]); updateMin = (curve->hlRange[0] != range[0]); updateMax = (curve->hlRange[1] != range[1]); if (!updateMin && !updateMax) return FALSE; if (range[0] < 0.f || range[1] <= range[0]) return FALSE; curve->hlRange[0] = range[0]; curve->hlRange[1] = range[1]; if (updateMin) g_object_notify_by_pspec(G_OBJECT(curve), _properties[MIN_HL_PROP]); if (updateMax) g_object_notify_by_pspec(G_OBJECT(curve), _properties[MAX_HL_PROP]); g_object_notify_by_pspec(G_OBJECT(curve), _properties[INT_HL_PROP]); g_object_notify_by_pspec(G_OBJECT(curve), _properties[MEAN_HL_PROP]); curve->dirty = TRUE; gtk_widget_queue_draw(GTK_WIDGET(curve)); return TRUE; } /** * visu_ui_curve_frame_getHighlightRange: * @curve: a #VisuUiCurveFrame widget. * @range: a location for two floats. * * Retrieves the distance span that is used for highlight rendering and * calculation, see visu_ui_curve_frame_setHighlightRange(). * * Since: 3.6 * * Returns: TRUE if range has been set already. */ gboolean visu_ui_curve_frame_getHighlightRange(VisuUiCurveFrame *curve, float range[2]) { g_return_val_if_fail(VISU_IS_UI_CURVE_FRAME(curve), FALSE); DBG_fprintf(stderr, "Gtk Curve: get highlight range of %gx%g.\n", curve->hlRange[0], curve->hlRange[1]); if (curve->hlRange[0] < 0.f || curve->hlRange[1] <= curve->hlRange[0]) return FALSE; range[0] = curve->hlRange[0]; range[1] = curve->hlRange[1]; return TRUE; } v_sim-3.8.0/src/extraGtkFunctions/gtk_curveWidget.h000066400000000000000000000056151370110300500224130ustar00rootroot00000000000000#ifndef __CURVEFRAME_H__ #define __CURVEFRAME_H__ #include #include #include G_BEGIN_DECLS /** * VisuUiCurveFrameStyle: * @CURVE_LINEAR: the curve is drawn with lines ; * @CURVE_BAR: the curve is drawn with bars ; * @CURVE_GAUSS: the curve is convoluted with gaussians (not * implemented yet). * * Possible styles for the curve rendering, see visu_ui_curve_frame_setStyle(). */ typedef enum { CURVE_LINEAR, CURVE_BAR, CURVE_GAUSS } VisuUiCurveFrameStyle; /** * VISU_TYPE_UI_CURVE_FRAME: * * Return the associated #GType to the #VisuUiCurveFrame objects. * * Since: 3.6 */ #define VISU_TYPE_UI_CURVE_FRAME (visu_ui_curve_frame_get_type()) /** * VISU_UI_CURVE_FRAME: * @obj: the widget to cast. * * Cast the given object to a #VisuUiCurveFrame object. * * Since: 3.6 */ #define VISU_UI_CURVE_FRAME(obj) (G_TYPE_CHECK_INSTANCE_CAST((obj), VISU_TYPE_UI_CURVE_FRAME, VisuUiCurveFrame)) /** * VISU_UI_CURVE_FRAME_CLASS: * @obj: the class to cast. * * Cast the given class to a #VisuUiCurveFrame object. * * Since: 3.6 */ #define VISU_UI_CURVE_FRAME_CLASS(obj) (G_TYPE_CHECK_CLASS_CAST((obj), VISU_UI_CURVE_FRAME, VisuUiCurveFrameClass)) /** * VISU_IS_UI_CURVE_FRAME: * @obj: the object to test. * * Return if the given object is a valid #VisuUiCurveFrame object. * * Since: 3.6 */ #define VISU_IS_UI_CURVE_FRAME(obj) (G_TYPE_CHECK_INSTANCE_TYPE((obj), VISU_TYPE_UI_CURVE_FRAME)) /** * VISU_IS_UI_CURVE_FRAME_CLASS: * @obj: the class to test. * * Return if the given class is a valid #VisuUiCurveFrameClass class. * * Since: 3.6 */ #define VISU_IS_UI_CURVE_FRAME_CLASS(obj) (G_TYPE_CHECK_CLASS_TYPE((obj), VISU_TYPE_UI_CURVE_FRAME)) /** * VISU_UI_CURVE_FRAME_GET_CLASS: * @obj: the widget to get the class of. * * Get the class of the given object. * * Since: 3.6 */ #define VISU_UI_CURVE_FRAME_GET_CLASS (G_TYPE_INSTANCE_GET_CLASS((obj), VISU_TYPE_UI_CURVE_FRAME, VisuUiCurveFrameClass)) typedef struct _VisuUiCurveFrame VisuUiCurveFrame; typedef struct _VisuUiCurveFrameClass VisuUiCurveFrameClass; GType visu_ui_curve_frame_get_type(void); GtkWidget *visu_ui_curve_frame_new(float distMin, float distMax); gboolean visu_ui_curve_frame_setModel(VisuUiCurveFrame *curve, VisuPairSet *model); gboolean visu_ui_curve_frame_setSpan(VisuUiCurveFrame *curve, float span[2]); void visu_ui_curve_frame_getSpan(VisuUiCurveFrame *curve, float span[2]); gboolean visu_ui_curve_frame_setZoomFactor(VisuUiCurveFrame *curve, float zoom); gboolean visu_ui_curve_frame_setStyle(VisuUiCurveFrame *curve, VisuUiCurveFrameStyle style); gboolean visu_ui_curve_frame_setFilter(VisuUiCurveFrame *curve, VisuElement* filter); gboolean visu_ui_curve_frame_setHighlightRange(VisuUiCurveFrame *curve, float range[2]); gboolean visu_ui_curve_frame_getHighlightRange(VisuUiCurveFrame *curve, float range[2]); G_END_DECLS #endif v_sim-3.8.0/src/extraGtkFunctions/gtk_dataChooser.c000066400000000000000000000543041370110300500223510ustar00rootroot00000000000000/* EXTRAITS DE LA LICENCE Copyright CEA, contributeurs : Damien CALISTE, laboratoire L_Sim, (2016) Adresse mèl : CALISTE, damien P caliste AT cea P fr. Ce logiciel est un programme informatique servant à visualiser des structures atomiques dans un rendu pseudo-3D. Ce logiciel est régi par la licence CeCILL soumise au droit français et respectant les principes de diffusion des logiciels libres. Vous pouvez utiliser, modifier et/ou redistribuer ce programme sous les conditions de la licence CeCILL telle que diffusée par le CEA, le CNRS et l'INRIA sur le site "http://www.cecill.info". Le fait que vous puissiez accéder à cet en-tête signifie que vous avez pris connaissance de la licence CeCILL, et que vous en avez accepté les termes (cf. le fichier Documentation/licence.fr.txt fourni avec ce logiciel). */ /* LICENCE SUM UP Copyright CEA, contributors : Damien CALISTE, laboratoire L_Sim, (2016) E-mail address: CALISTE, damien P caliste AT cea P fr. This software is a computer program whose purpose is to visualize atomic configurations in 3D. This software is governed by the CeCILL license under French law and abiding by the rules of distribution of free software. You can use, modify and/ or redistribute the software under the terms of the CeCILL license as circulated by CEA, CNRS and INRIA at the following URL "http://www.cecill.info". The fact that you are presently reading this means that you have had knowledge of the CeCILL license and that you accept its terms. You can find a copy of this licence shipped with this software at Documentation/licence.en.txt. */ #include "gtk_dataChooser.h" #include #include #include #include #include #include #include #include #include /* Parameters. */ #define FLAG_PARAMETER_PREVIEW "main_usePreview" #define DESC_PARAMETER_PREVIEW "Automatically compute preview in filechooser ; boolean" static gboolean usePreview; /** * SECTION:gtk_dataChooser * @short_description: A customed file chooser, allowing to slect one * or several files a create a #VisuDataLoadable object accordingly. * * This is a standard file chooser with additional combo box to * select which kind of #VisuDataLoadable we want to select, simple * atomic or spin files. */ /* enum { */ /* PROP_0, */ /* N_PROPS */ /* }; */ /* static GParamSpec *_properties[N_PROPS]; */ /** * VisuUiDataChooserPrivate: * * Private data. */ struct _VisuUiDataChooserPrivate { gboolean dispose_has_run; GtkWidget *comboMethod, *boxMethod; GtkWidget *checkPreview; GtkWidget *image; GtkWidget *boxDescr; guint worker; GtkWidget *checkAtomic, *checkSpin; GtkWidget *labelPosition, *labelSpin; gchar *atomicFile, *spinFile; VisuDataLoader *atomicFormat, *spinFormat; }; static void visu_ui_data_chooser_dispose(GObject* obj); static void _setMethod(VisuUiDataChooser *this); static void _updatePreview(VisuUiDataChooser *this); static gboolean _setFile(VisuUiDataChooser *this); static void exportParameters(GString *data, VisuData *dataObj); /* Pointset interface. */ G_DEFINE_TYPE_WITH_CODE(VisuUiDataChooser, visu_ui_data_chooser, GTK_TYPE_FILE_CHOOSER_DIALOG, G_ADD_PRIVATE(VisuUiDataChooser)) static void visu_ui_data_chooser_class_init(VisuUiDataChooserClass *klass) { VisuConfigFileEntry *entry; G_OBJECT_CLASS(klass)->dispose = visu_ui_data_chooser_dispose; /* Set private variables. */ usePreview = TRUE; entry = visu_config_file_addBooleanEntry(VISU_CONFIG_FILE_PARAMETER, FLAG_PARAMETER_PREVIEW, DESC_PARAMETER_PREVIEW, &usePreview, FALSE); visu_config_file_entry_setVersion(entry, 3.4f); visu_config_file_addExportFunction(VISU_CONFIG_FILE_PARAMETER, exportParameters); } static void visu_ui_data_chooser_init(VisuUiDataChooser *obj) { obj->priv = visu_ui_data_chooser_get_instance_private(obj); obj->priv->dispose_has_run = FALSE; obj->priv->atomicFile = (gchar*)0; obj->priv->spinFile = (gchar*)0; obj->priv->atomicFormat = (VisuDataLoader*)0; obj->priv->spinFormat = (VisuDataLoader*)0; } static void visu_ui_data_chooser_dispose(GObject* obj) { VisuUiDataChooser *this; this = VISU_UI_DATA_CHOOSER(obj); if (this->priv->dispose_has_run) return; this->priv->dispose_has_run = TRUE; g_free(this->priv->atomicFile); g_free(this->priv->spinFile); if (this->priv->worker) g_source_remove(this->priv->worker); G_OBJECT_CLASS(visu_ui_data_chooser_parent_class)->dispose(obj); } /** * visu_ui_data_chooser_new: * @parent: (allow-none): a #GtkWindow parent. * * Creates a dialog allowing to select files to load. * * Since: 3.8 * * Returns: (transfer full): a newly created #VisuUiDataChooser object. **/ GtkWidget* visu_ui_data_chooser_new(GtkWindow *parent) { VisuUiDataChooser *this; GtkWidget *vbox, *label; GtkWidget *hbox; GtkWidget *frame; #if GTK_MAJOR_VERSION == 2 && GTK_MINOR_VERSION < 12 GtkTooltips *tooltips; tooltips = gtk_tooltips_new (); #endif this = g_object_new(VISU_TYPE_UI_DATA_CHOOSER, "title", _("Load session"), NULL); gtk_widget_set_name(GTK_WIDGET(this), "filesel"); gtk_window_set_transient_for(GTK_WINDOW(this), parent); gtk_window_set_position(GTK_WINDOW(this), GTK_WIN_POS_CENTER_ON_PARENT); gtk_window_set_modal(GTK_WINDOW(this), TRUE); gtk_dialog_add_buttons(GTK_DIALOG(this), TOOL_ICON_CANCEL, GTK_RESPONSE_CANCEL, TOOL_ICON_OPEN, GTK_RESPONSE_OK, NULL); gtk_file_chooser_set_action(GTK_FILE_CHOOSER(this), GTK_FILE_CHOOSER_ACTION_OPEN); vbox = gtk_dialog_get_content_area(GTK_DIALOG(this)); hbox = gtk_hbox_new(FALSE, 0); gtk_box_pack_start(GTK_BOX(vbox), hbox, FALSE, FALSE, 0); this->priv->boxMethod = gtk_hbox_new(FALSE, 0); gtk_box_pack_start(GTK_BOX(vbox), this->priv->boxMethod, FALSE, FALSE, 0); label = gtk_label_new(_("Rendering method:")); gtk_box_pack_start(GTK_BOX(hbox), label, TRUE, TRUE, 0); gtk_label_set_xalign(GTK_LABEL(label), 0.); this->priv->comboMethod = gtk_combo_box_text_new(); gtk_combo_box_text_append(GTK_COMBO_BOX_TEXT(this->priv->comboMethod), "atomic", _("display node as atoms")); gtk_combo_box_text_append(GTK_COMBO_BOX_TEXT(this->priv->comboMethod), "spin", _("display node as spins")); g_signal_connect_swapped(this->priv->comboMethod, "changed", G_CALLBACK(_setMethod), this); gtk_combo_box_set_active(GTK_COMBO_BOX(this->priv->comboMethod), 0); gtk_box_pack_end(GTK_BOX(hbox), this->priv->comboMethod, FALSE, FALSE, 0); /* The preview widget. */ vbox = gtk_vbox_new(FALSE, 0); gtk_widget_set_hexpand(vbox, FALSE); this->priv->checkPreview = gtk_check_button_new_with_mnemonic(_("_Preview:")); gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON(this->priv->checkPreview), usePreview); gtk_box_pack_start(GTK_BOX(vbox), this->priv->checkPreview, FALSE, FALSE, 5); frame = gtk_frame_new(NULL); gtk_widget_set_size_request(frame, 150, 150); gtk_frame_set_shadow_type(GTK_FRAME(frame), GTK_SHADOW_ETCHED_IN); gtk_widget_set_vexpand(frame, FALSE); gtk_box_pack_start(GTK_BOX(vbox), frame, TRUE, FALSE, 0); this->priv->image = gtk_image_new(); gtk_container_add(GTK_CONTAINER(frame), this->priv->image); this->priv->boxDescr = gtk_hbox_new(FALSE, 0); gtk_box_pack_start(GTK_BOX(vbox), this->priv->boxDescr, FALSE, FALSE, 0); gtk_widget_show_all(vbox); gtk_file_chooser_set_preview_widget(GTK_FILE_CHOOSER(this), vbox); gtk_file_chooser_set_use_preview_label(GTK_FILE_CHOOSER(this), FALSE); gtk_file_chooser_set_preview_widget_active(GTK_FILE_CHOOSER(this), TRUE); g_signal_connect(this, "update-preview", G_CALLBACK(_updatePreview), (gpointer)0); /* /\* The additional widgets. *\/ */ /* /\* Hiding mode button *\/ */ /* hbox = gtk_hbox_new(FALSE, 0); */ /* gtk_box_pack_start(GTK_BOX(vbox), hbox, FALSE, FALSE, 2); */ /* label = gtk_label_new(LABEL_SPIN_POLICY); */ /* gtk_widget_set_name(label, "label_head_2"); */ /* gtk_box_pack_start(GTK_BOX(hbox), label, FALSE, FALSE, 2); */ /* hiding_mode = createHidingModeRadioWidgets(); */ /* gtk_box_pack_start(GTK_BOX(hbox), hiding_mode, FALSE, FALSE, 2); */ gtk_widget_show_all(GTK_WIDGET(this)); return GTK_WIDGET(this); } static GtkWidget* _getDescr(VisuDataLoadable *previewData) { GtkWidget *table, *wd; const gchar *comment; gchar *text; VisuNodeArrayIter iter; /* We reset the flag of material. */ comment = visu_data_getDescription(VISU_DATA(previewData)); visu_node_array_iter_new(VISU_NODE_ARRAY(previewData), &iter); table = gtk_grid_new(); tool_grid_resize(table, iter.nElements + 1, 2); wd = gtk_label_new(_("Box composition:")); gtk_label_set_use_markup(GTK_LABEL(wd), TRUE); gtk_label_set_xalign(GTK_LABEL(wd), 0.); gtk_widget_set_hexpand(wd, TRUE); gtk_grid_attach(GTK_GRID(table), wd, 0, 0, 2, 1); for (visu_node_array_iterStart(VISU_NODE_ARRAY(previewData), &iter); iter.element; visu_node_array_iterNextElement(VISU_NODE_ARRAY(previewData), &iter, FALSE)) { wd = gtk_label_new(""); text = g_markup_printf_escaped(_("%s:"), iter.element->name); gtk_label_set_markup(GTK_LABEL(wd), text); gtk_label_set_xalign(GTK_LABEL(wd), 1.); gtk_widget_set_hexpand(wd, TRUE); g_free(text); gtk_grid_attach(GTK_GRID(table), wd, 0, iter.iElement + 1, 1, 1); wd = gtk_label_new(""); if (iter.nStoredNodes > 1) text = g_markup_printf_escaped (_("%d nodes"), iter.nStoredNodes); else if (iter.nStoredNodes == 1) text = g_strdup(_("1 node")); else text = g_strdup_printf("negative node number %d", iter.nStoredNodes); gtk_label_set_markup(GTK_LABEL(wd), text); gtk_label_set_xalign(GTK_LABEL(wd), 0.); gtk_widget_set_hexpand(wd, TRUE); g_free(text); gtk_grid_attach(GTK_GRID(table), wd, 1, iter.iElement + 1, 1, 1); } if (comment && comment[0]) { wd = gtk_label_new(_("Description:")); gtk_label_set_use_markup(GTK_LABEL(wd), TRUE); gtk_label_set_xalign(GTK_LABEL(wd), 0.); gtk_widget_set_hexpand(wd, TRUE); gtk_grid_attach(GTK_GRID(table), wd, 0, iter.nElements + 2, 2, 1); wd = gtk_label_new(""); text = g_markup_printf_escaped("%s", comment); gtk_label_set_markup(GTK_LABEL(wd), text); g_free(text); gtk_label_set_xalign(GTK_LABEL(wd), 0.); gtk_label_set_justify(GTK_LABEL(wd), GTK_JUSTIFY_FILL); gtk_label_set_line_wrap(GTK_LABEL(wd), TRUE); gtk_widget_set_size_request(wd, 150, -1); gtk_widget_set_hexpand(wd, TRUE); gtk_grid_attach(GTK_GRID(table), wd, 0, iter.nElements + 3, 2, 1); } gtk_widget_show_all(table); return table; } static void _freeUChar(guchar *pixels, gpointer data _U_) { g_free(pixels); } static gboolean _renderPreview(VisuUiDataChooser *this) { GError *error; gboolean valid; VisuGlView *view; VisuGlExtNodes *nodes; VisuGlExtBox *box; VisuGlExtSet *set; GArray* image; GdkPixbuf *pixbuf; VisuDataLoadable *preview; this->priv->worker = 0; DBG_fprintf(stderr, "Gtk DataChooser: rendering preview.\n"); error = (GError*)0; switch (gtk_combo_box_get_active(GTK_COMBO_BOX(this->priv->comboMethod))) { case 0: if (!this->priv->atomicFile) return G_SOURCE_REMOVE; preview = VISU_DATA_LOADABLE(visu_data_atomic_new(this->priv->atomicFile, this->priv->atomicFormat)); break; case 1: if (!this->priv->atomicFile || !this->priv->spinFile) return G_SOURCE_REMOVE; preview = VISU_DATA_LOADABLE(visu_data_spin_new(this->priv->atomicFile, this->priv->spinFile, (VisuDataLoader*)0, (VisuDataLoader*)0)); break; default: preview = (VisuDataLoadable*)0; break; } valid = visu_data_loadable_load(preview, 0, (GCancellable*)0, &error); if (!valid) { if (preview) g_object_unref(preview); gtk_image_set_from_icon_name(GTK_IMAGE(this->priv->image), "dialog-question", GTK_ICON_SIZE_DIALOG); gtk_box_pack_start(GTK_BOX(this->priv->boxDescr), gtk_label_new(_("Not a V_Sim file")), TRUE, FALSE, 0); gtk_widget_show_all(this->priv->boxDescr); return FALSE; } if (error) { if (preview) g_object_unref(preview); gtk_image_set_from_icon_name(GTK_IMAGE(this->priv->image), "dialog-error", GTK_ICON_SIZE_DIALOG); gtk_box_pack_start(GTK_BOX(this->priv->boxDescr), gtk_label_new(_("This file has errors")), TRUE, FALSE, 0); gtk_widget_show_all(this->priv->boxDescr); return FALSE; } gtk_box_pack_start(GTK_BOX(this->priv->boxDescr), _getDescr(preview), FALSE, FALSE, 0); view = visu_gl_view_new_withSize((guint)150, (guint)150); g_object_set(G_OBJECT(view), "auto-adjust", TRUE, NULL); visu_boxed_setBox(VISU_BOXED(view), VISU_BOXED(preview)); /* Setup extensions for the preview. */ set = visu_gl_ext_set_new(); nodes = visu_gl_ext_nodes_new(); visu_gl_ext_set_add(set, VISU_GL_EXT(nodes)); g_object_unref(nodes); visu_node_array_renderer_setNodeArray(VISU_NODE_ARRAY_RENDERER(nodes), VISU_NODE_ARRAY(preview)); g_object_unref(preview); box = visu_gl_ext_box_new("box preview"); visu_gl_ext_set_add(set, VISU_GL_EXT(box)); g_object_unref(box); visu_gl_ext_box_setBox(box, visu_boxed_getBox(VISU_BOXED(preview))); visu_gl_ext_set_setGlView(set, view); g_object_unref(view); image = visu_gl_ext_set_getPixmapData(set, 0, 0, FALSE); g_object_unref(set); pixbuf = gdk_pixbuf_new_from_data((guchar*)image->data, GDK_COLORSPACE_RGB, FALSE, 8, 150, 150, 3 * 150, (GdkPixbufDestroyNotify)_freeUChar, (gpointer)0); g_array_free(image, FALSE); gtk_image_set_from_pixbuf(GTK_IMAGE(this->priv->image), pixbuf); g_object_unref(pixbuf); return FALSE; } static void _updatePreview(VisuUiDataChooser *this) { GList *lst, *child; lst = gtk_container_get_children(GTK_CONTAINER(this->priv->boxDescr)); for (child = lst; child; child = g_list_next(child)) gtk_widget_destroy(GTK_WIDGET(child->data)); g_list_free(lst); gtk_image_clear(GTK_IMAGE(this->priv->image)); if (!gtk_toggle_button_get_active(GTK_TOGGLE_BUTTON(this->priv->checkPreview)) || !_setFile(this)) return; if (!this->priv->worker) this->priv->worker = g_idle_add((GSourceFunc)_renderPreview, this); } static void _createFilter(GtkFileChooser *chooser, GList *list) { GtkFileFilter *filter, *filterAll; const GList *tmpLst2, *tmpLst; const char *name; GSList *filters, *it; filters = gtk_file_chooser_list_filters(chooser); for (it = filters; it; it = g_slist_next(it)) gtk_file_chooser_remove_filter(chooser, GTK_FILE_FILTER(it->data)); filters = (GSList*)0; filterAll = gtk_file_filter_new(); gtk_file_filter_set_name(filterAll, _("All supported formats")); for (tmpLst = list; tmpLst; tmpLst = g_list_next(tmpLst)) { filter = gtk_file_filter_new(); name = tool_file_format_getLabel(TOOL_FILE_FORMAT(tmpLst->data)); if (name) gtk_file_filter_set_name(filter, name); else gtk_file_filter_set_name(filter, _("No description")); for (tmpLst2 = tool_file_format_getFilePatterns(TOOL_FILE_FORMAT(tmpLst->data)); tmpLst2; tmpLst2 = g_list_next(tmpLst2)) { gtk_file_filter_add_pattern(filter, (gchar*)tmpLst2->data); gtk_file_filter_add_pattern(filterAll, (gchar*)tmpLst2->data); } g_object_set_data(G_OBJECT(filter), "_VisuDataLoader", tmpLst->data); filters = g_slist_append(filters, (gpointer)filter); } filters = g_slist_append(filters, (gpointer)filterAll); filter = gtk_file_filter_new(); gtk_file_filter_set_name(filter, _("All files")); gtk_file_filter_add_pattern (filter, "*"); filters = g_slist_append(filters, (gpointer)filter); for (it = filters; it; it = g_slist_next(it)) gtk_file_chooser_add_filter(chooser, GTK_FILE_FILTER(it->data)); gtk_file_chooser_set_filter(chooser, filterAll); g_slist_free(filters); } static void _setSpinInput(VisuUiDataChooser *this) { if (gtk_combo_box_get_active(GTK_COMBO_BOX(this->priv->comboMethod)) != 1) return; if (gtk_toggle_button_get_active(GTK_TOGGLE_BUTTON(this->priv->checkAtomic))) _createFilter(GTK_FILE_CHOOSER(this), visu_data_atomic_class_getLoaders()); else if (gtk_toggle_button_get_active(GTK_TOGGLE_BUTTON(this->priv->checkSpin))) _createFilter(GTK_FILE_CHOOSER(this), visu_data_spin_class_getLoaders()); } static void _setMethod(VisuUiDataChooser *this) { GList *lst, *child; GtkWidget *table; g_free(this->priv->atomicFile); this->priv->atomicFile = (gchar*)0; g_free(this->priv->spinFile); this->priv->spinFile = (gchar*)0; lst = gtk_container_get_children(GTK_CONTAINER(this->priv->boxMethod)); for (child = lst; child; child = g_list_next(child)) gtk_widget_destroy(GTK_WIDGET(child->data)); switch (gtk_combo_box_get_active(GTK_COMBO_BOX(this->priv->comboMethod))) { case 0: _createFilter(GTK_FILE_CHOOSER(this), visu_data_atomic_class_getLoaders()); break; case 1: /* The table for the two file types selections (spin & position). */ table = gtk_grid_new(); tool_grid_resize(table, 2, 4); gtk_box_pack_start(GTK_BOX(this->priv->boxMethod), table, TRUE, TRUE, 2); /* Position button. */ this->priv->checkAtomic = gtk_radio_button_new_with_label(NULL, _("Positions:")); gtk_grid_attach(GTK_GRID(table), this->priv->checkAtomic, 0, 0, 1, 1); g_signal_connect_swapped(this->priv->checkAtomic, "toggled", G_CALLBACK(_setSpinInput), this); /* Spin button */ this->priv->checkSpin = gtk_radio_button_new_with_label_from_widget (GTK_RADIO_BUTTON(this->priv->checkAtomic), _("Spins:")); gtk_grid_attach(GTK_GRID(table), this->priv->checkSpin, 0, 1, 1, 1); g_signal_connect_swapped(this->priv->checkSpin, "toggled", G_CALLBACK(_setSpinInput), this); this->priv->labelPosition = gtk_label_new(_("None")); gtk_widget_set_hexpand(this->priv->labelPosition, TRUE); gtk_label_set_xalign(GTK_LABEL(this->priv->labelPosition), 0.); gtk_widget_set_margin_start(this->priv->labelPosition, 10); gtk_grid_attach(GTK_GRID(table), this->priv->labelPosition, 3, 0, 1, 1); this->priv->labelSpin = gtk_label_new(_("None")); gtk_widget_set_hexpand(this->priv->labelSpin, TRUE); gtk_label_set_xalign(GTK_LABEL(this->priv->labelSpin), 0.); gtk_widget_set_margin_start(this->priv->labelSpin, 10); gtk_grid_attach(GTK_GRID(table), this->priv->labelSpin, 3, 1, 1, 1); gtk_widget_show_all(table); _setSpinInput(this); break; default: break; } } static gboolean _setFile(VisuUiDataChooser *this) { gchar *filename; VisuDataLoader *format; filename = gtk_file_chooser_get_filename(GTK_FILE_CHOOSER(this)); format = VISU_DATA_LOADER(g_object_get_data(G_OBJECT(gtk_file_chooser_get_filter(GTK_FILE_CHOOSER(this))), "_VisuDataLoader")); switch (gtk_combo_box_get_active(GTK_COMBO_BOX(this->priv->comboMethod))) { case 0: g_free(this->priv->atomicFile); this->priv->atomicFile = filename; this->priv->atomicFormat = format; return TRUE; case 1: if (gtk_toggle_button_get_active(GTK_TOGGLE_BUTTON(this->priv->checkAtomic))) { g_free(this->priv->atomicFile); this->priv->atomicFile = filename; this->priv->atomicFormat = format; if (filename) gtk_label_set_text(GTK_LABEL(this->priv->labelPosition), filename); else gtk_label_set_text(GTK_LABEL(this->priv->labelPosition), _("None")); } else if (gtk_toggle_button_get_active(GTK_TOGGLE_BUTTON(this->priv->checkSpin))) { g_free(this->priv->spinFile); this->priv->spinFile = filename; this->priv->spinFormat = format; if (filename) gtk_label_set_text(GTK_LABEL(this->priv->labelSpin), filename); else gtk_label_set_text(GTK_LABEL(this->priv->labelSpin), _("None")); } return this->priv->atomicFile && this->priv->spinFile; default: break; } return FALSE; } /** * visu_ui_data_chooser_run: * @this: a #VisuUiDataChooser object. * * Runs a file dialog chooser to select a #VisuDataLoadable file. * * Since: 3.8 * * Returns: (transfer full): a newly created #VisuDataLoadable object. **/ VisuDataLoadable* visu_ui_data_chooser_run(VisuUiDataChooser *this) { gint status; do { status = gtk_dialog_run(GTK_DIALOG(this)); if (status != GTK_RESPONSE_OK) return (VisuDataLoadable*)0; } while (!_setFile(this)); switch (gtk_combo_box_get_active(GTK_COMBO_BOX(this->priv->comboMethod))) { case 0: return VISU_DATA_LOADABLE(visu_data_atomic_new(this->priv->atomicFile, this->priv->atomicFormat)); case 1: return VISU_DATA_LOADABLE(visu_data_spin_new(this->priv->atomicFile, this->priv->spinFile, this->priv->atomicFormat, this->priv->spinFormat)); default: break; } return (VisuDataLoadable*)0; } static void exportParameters(GString *data, VisuData *dataObj _U_) { g_string_append_printf(data, "# %s\n", DESC_PARAMETER_PREVIEW); g_string_append_printf(data, "%s[gtk]: %d\n\n", FLAG_PARAMETER_PREVIEW, usePreview); } v_sim-3.8.0/src/extraGtkFunctions/gtk_dataChooser.h000066400000000000000000000063201370110300500223510ustar00rootroot00000000000000/* EXTRAITS DE LA LICENCE Copyright CEA, contributeurs : Damien CALISTE, laboratoire L_Sim, (2016) Adresse mèl : CALISTE, damien P caliste AT cea P fr. Ce logiciel est un programme informatique servant à visualiser des structures atomiques dans un rendu pseudo-3D. Ce logiciel est régi par la licence CeCILL soumise au droit français et respectant les principes de diffusion des logiciels libres. Vous pouvez utiliser, modifier et/ou redistribuer ce programme sous les conditions de la licence CeCILL telle que diffusée par le CEA, le CNRS et l'INRIA sur le site "http://www.cecill.info". Le fait que vous puissiez accéder à cet en-tête signifie que vous avez pris connaissance de la licence CeCILL, et que vous en avez accepté les termes (cf. le fichier Documentation/licence.fr.txt fourni avec ce logiciel). */ /* LICENCE SUM UP Copyright CEA, contributors : Damien CALISTE, laboratoire L_Sim, (2016) E-mail address: CALISTE, damien P caliste AT cea P fr. This software is a computer program whose purpose is to visualize atomic configurations in 3D. This software is governed by the CeCILL license under French law and abiding by the rules of distribution of free software. You can use, modify and/ or redistribute the software under the terms of the CeCILL license as circulated by CEA, CNRS and INRIA at the following URL "http://www.cecill.info". The fact that you are presently reading this means that you have had knowledge of the CeCILL license and that you accept its terms. You can find a copy of this licence shipped with this software at Documentation/licence.en.txt. */ #ifndef VISU_UI_DATA_CHOOSER_H #define VISU_UI_DATA_CHOOSER_H #include #include "visu_dataloadable.h" G_BEGIN_DECLS #define VISU_TYPE_UI_DATA_CHOOSER (visu_ui_data_chooser_get_type ()) #define VISU_UI_DATA_CHOOSER(obj) (G_TYPE_CHECK_INSTANCE_CAST ((obj), VISU_TYPE_UI_DATA_CHOOSER, VisuUiDataChooser)) #define VISU_UI_DATA_CHOOSER_CLASS(klass) (G_TYPE_CHECK_CLASS_CAST ((klass), VISU_TYPE_UI_DATA_CHOOSER, VisuUiDataChooserClass)) #define VISU_IS_UI_DATA_CHOOSER(obj) (G_TYPE_CHECK_INSTANCE_TYPE ((obj), VISU_TYPE_UI_DATA_CHOOSER)) #define VISU_IS_UI_DATA_CHOOSER_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE ((klass), VISU_TYPE_UI_DATA_CHOOSER)) #define VISU_UI_DATA_CHOOSER_GET_CLASS(obj) (G_TYPE_INSTANCE_GET_CLASS(obj, VISU_TYPE_UI_DATA_CHOOSER, VisuUiDataChooserClass)) typedef struct _VisuUiDataChooser VisuUiDataChooser; typedef struct _VisuUiDataChooserPrivate VisuUiDataChooserPrivate; /** * VisuUiDataChooser: * * Structure used to define #VisuUiDataChooser objects. * * Since: 3.8 */ struct _VisuUiDataChooser { GtkFileChooserDialog parent; VisuUiDataChooserPrivate *priv; }; /** * VisuUiDataChooserClass: * @parent: its parent. * * The class defining a file chooser widget specialised to open * #VisuDataLoadable objects. * * Since: 3.8 */ typedef struct _VisuUiDataChooserClass VisuUiDataChooserClass; struct _VisuUiDataChooserClass { GtkFileChooserDialogClass parent; }; GType visu_ui_data_chooser_get_type (void); GtkWidget* visu_ui_data_chooser_new(GtkWindow *parent); VisuDataLoadable* visu_ui_data_chooser_run(VisuUiDataChooser *this); G_END_DECLS #endif v_sim-3.8.0/src/extraGtkFunctions/gtk_dumpDialogWidget.c000066400000000000000000000602231370110300500233430ustar00rootroot00000000000000/* EXTRAITS DE LA LICENCE Copyright CEA, contributeurs : Luc BILLARD et Damien CALISTE, laboratoire L_Sim, (2001-2005) Adresse mèl : BILLARD, non joignable par mèl ; CALISTE, damien P caliste AT cea P fr. Ce logiciel est un programme informatique servant à visualiser des structures atomiques dans un rendu pseudo-3D. Ce logiciel est régi par la licence CeCILL soumise au droit français et respectant les principes de diffusion des logiciels libres. Vous pouvez utiliser, modifier et/ou redistribuer ce programme sous les conditions de la licence CeCILL telle que diffusée par le CEA, le CNRS et l'INRIA sur le site "http://www.cecill.info". Le fait que vous puissiez accéder à cet en-tête signifie que vous avez pris connaissance de la licence CeCILL, et que vous en avez accepté les termes (cf. le fichier Documentation/licence.fr.txt fourni avec ce logiciel). */ /* LICENCE SUM UP Copyright CEA, contributors : Luc BILLARD et Damien CALISTE, laboratoire L_Sim, (2001-2005) E-mail address: BILLARD, not reachable any more ; CALISTE, damien P caliste AT cea P fr. This software is a computer program whose purpose is to visualize atomic configurations in 3D. This software is governed by the CeCILL license under French law and abiding by the rules of distribution of free software. You can use, modify and/ or redistribute the software under the terms of the CeCILL license as circulated by CEA, CNRS and INRIA at the following URL "http://www.cecill.info". The fact that you are presently reading this means that you have had knowledge of the CeCILL license and that you accept its terms. You can find a copy of this licence shipped with this software at Documentation/licence.en.txt. */ #include #include #include #include "gtk_dumpDialogWidget.h" #include #include #include /** * SECTION:gtk_dumpDialogWidget * @short_description: Defines a widget to export into different file * formats. * * This widget is based on the #GtkFileChooser in the save * mode. It proposes the user to choose a file to save to. In * addition, it automatically build a list of filters, corresponding * to the available export routines in V_Sim. By default, the filter * is set on 'auto', which means that the filter method is selected * with the file extension. The dialog also has a progress bar. * * This widget is also a dialog, and should be used with * gtk_dialog_run(). After the response GTK_RESPONSE_ACCEPT has been * recieved, one can grep the selected filename with * visu_ui_dump_dialog_getFilename(). The dialog does not call the exporting * routine by itself, the calling method should take care of * that. When doing it, the filechoosing part should be made * insensitive, using visu_ui_dump_dialog_start() and the progress bar should be * updated accordingly (get it with * visu_ui_dump_dialog_getProgressBar()). * * The user interface propose also to change the size (see * visu_ui_dump_dialog_getHeight() and visu_ui_dump_dialog_getWidth()) and if * some options are associated to a file format, these options are * displayed. */ static void visu_ui_dump_dialog_dispose (GObject *obj); static void visu_ui_dump_dialog_finalize(GObject *obj); struct _VisuUiDumpDialog { GtkDialog dialog; GtkWidget *fileChooser; GtkWidget *hBoxOptions; GtkWidget *comboType; VisuDump *selectedToolFileFormat; GtkWidget *expanderToolFileFormat; GtkWidget *checkFileExtension; GtkWidget *spinWidth, *spinHeight; GtkWidget *infoBar; GtkWidget *progressBar; GtkWidget *cancelButton; gchar *dumpFileName; VisuData *dataObj; /* Memory gestion. */ gboolean dispose_has_run; }; struct _VisuUiDumpDialogClass { GtkDialogClass parent_class; guint width, height; gchar *current_dir; guint formatId; void (*dumpDialog) (VisuUiDumpDialog *dump); }; /* Local callbacks */ static void onWidthHeightChanged(GtkSpinButton *spin, gpointer data); static void onSpinPropertyChange(GtkSpinButton *spin, gpointer data); static void onCheckPropertyChange(GtkToggleButton *toggle, gpointer data); static void onComboToolFileFormatChange(GtkComboBox *combo, gpointer data); static void onVisuUiDumpDialogResponse(GtkDialog *dialog, gint id, gpointer *data); G_DEFINE_TYPE(VisuUiDumpDialog, visu_ui_dump_dialog, GTK_TYPE_DIALOG) static void visu_ui_dump_dialog_class_init(VisuUiDumpDialogClass *klass) { DBG_fprintf(stderr, "Gtk VisuUiDumpDialog: creating the class of the widget.\n"); klass->width = 0; klass->height = 0; klass->current_dir = (gchar*)0; klass->formatId = 0; G_OBJECT_CLASS(klass)->dispose = visu_ui_dump_dialog_dispose; G_OBJECT_CLASS(klass)->finalize = visu_ui_dump_dialog_finalize; } static void visu_ui_dump_dialog_init(VisuUiDumpDialog *dumpDialog) { DBG_fprintf(stderr, "Gtk VisuUiDumpDialog: initializing new object (%p).\n", (gpointer)dumpDialog); dumpDialog->selectedToolFileFormat = (VisuDump*)0; dumpDialog->dumpFileName = (gchar*)0; dumpDialog->dataObj = (VisuData*)0; g_signal_connect(G_OBJECT(dumpDialog), "response", G_CALLBACK(onVisuUiDumpDialogResponse), (gpointer)dumpDialog); } static void visu_ui_dump_dialog_dispose(GObject *obj) { DBG_fprintf(stderr, "Gtk VisuUiDumpDialog: dispose object %p.\n", (gpointer)obj); if (VISU_UI_DUMP_DIALOG(obj)->dispose_has_run) return; VISU_UI_DUMP_DIALOG(obj)->dispose_has_run = TRUE; /* Chain up to the parent class */ G_OBJECT_CLASS(visu_ui_dump_dialog_parent_class)->dispose(obj); } static void visu_ui_dump_dialog_finalize(GObject *obj) { VisuUiDumpDialog *dialog; g_return_if_fail(obj); DBG_fprintf(stderr, "Gtk VisuUiDumpDialog: finalize object %p.\n", (gpointer)obj); dialog = VISU_UI_DUMP_DIALOG(obj); if (dialog->dumpFileName) /* Free the stored filename. */ g_free(dialog->dumpFileName); /* Chain up to the parent class */ G_OBJECT_CLASS(visu_ui_dump_dialog_parent_class)->finalize(obj); DBG_fprintf(stderr, "Gtk VisuUiDumpDialog: freeing ... OK.\n"); } /** * visu_ui_dump_dialog_new : * @dataObj: (allow-none): a #VisuData object (can be NULL) ; * @parent: (allow-none): the parent window ; * @suggestedFilename: (allow-none): a string or NULL. * @suggestedWidth: a positive suggested width for exportation or a * negative value to get the default. * @suggestedHeight: idem for height. * * A #VisuUiDumpDialog widget is complete dialog window widget, but it is already * prepared for dumping, proposing known file formats. It is usefull to get * an filename to export to. It has also a progress bar that can illustrate * the process. The given @dataObj argument is used to initialize some * values related to the data to be dumped. * * Returns: a newly created #VisuUiDumpDialog widget. */ GtkWidget* visu_ui_dump_dialog_new(VisuData *dataObj, GtkWindow *parent, const gchar *suggestedFilename, gint suggestedWidth, gint suggestedHeight) { VisuUiDumpDialog *dumpDialog; VisuUiDumpDialogClass *klass; const gchar *directory; const gchar *filename, *labelType; GList *format; GtkWidget *hbox2, *hbox; GtkWidget *label; GtkWidget *wd; GtkWidget *vbox; if (!parent) parent = visu_ui_getRenderWindow(); DBG_fprintf(stderr, "Gtk VisuUiDumpDialog: creating a new VisuUiDumpDialog object.\n"); dumpDialog = VISU_UI_DUMP_DIALOG(g_object_new(VISU_TYPE_UI_DUMP_DIALOG, NULL)); gtk_window_set_title(GTK_WINDOW(dumpDialog), _("Export to a file (image, atomic structures...)")); klass = VISU_UI_DUMP_DIALOG_CLASS(G_OBJECT_GET_CLASS(dumpDialog)); /* This is to avoid a bug in gtk 2.4 */ #if GTK_MAJOR_VERSION > 2 || GTK_MINOR_VERSION > 5 gtk_window_set_modal(GTK_WINDOW(dumpDialog), TRUE); #endif gtk_window_set_transient_for(GTK_WINDOW(dumpDialog), GTK_WINDOW(parent)); gtk_window_set_position(GTK_WINDOW(dumpDialog), GTK_WIN_POS_CENTER_ON_PARENT); dumpDialog->cancelButton = gtk_dialog_add_button(GTK_DIALOG(dumpDialog), TOOL_ICON_CANCEL, GTK_RESPONSE_CANCEL); gtk_dialog_add_button(GTK_DIALOG(dumpDialog), TOOL_ICON_SAVE, GTK_RESPONSE_ACCEPT); gtk_dialog_set_default_response(GTK_DIALOG(dumpDialog), GTK_RESPONSE_ACCEPT); /* Create the file chooser part. */ dumpDialog->fileChooser = gtk_file_chooser_widget_new(GTK_FILE_CHOOSER_ACTION_SAVE); gtk_widget_set_size_request(dumpDialog->fileChooser, -1, 350); #if GTK_MAJOR_VERSION > 2 || GTK_MINOR_VERSION > 7 gtk_file_chooser_set_do_overwrite_confirmation (GTK_FILE_CHOOSER(dumpDialog->fileChooser), TRUE); #endif gtk_box_pack_start(GTK_BOX(gtk_dialog_get_content_area(GTK_DIALOG(dumpDialog))), dumpDialog->fileChooser, TRUE, TRUE, 2); gtk_file_chooser_set_select_multiple(GTK_FILE_CHOOSER(dumpDialog->fileChooser), FALSE); /* We set the suggested filename, either a previous one or the one given. */ filename = (const gchar*)0; dumpDialog->dataObj = dataObj; if (dataObj) filename = (const gchar*)g_object_get_data(G_OBJECT(dataObj), "visu_ui_dump_dialog_filename"); if (!filename) filename = suggestedFilename; if (filename) gtk_file_chooser_set_current_name(GTK_FILE_CHOOSER(dumpDialog->fileChooser), filename); /* Create the file options part. */ dumpDialog->hBoxOptions = gtk_hbox_new(FALSE, 0); gtk_file_chooser_set_extra_widget(GTK_FILE_CHOOSER(dumpDialog->fileChooser), dumpDialog->hBoxOptions); vbox = gtk_vbox_new(FALSE, 0); gtk_box_pack_start(GTK_BOX(dumpDialog->hBoxOptions), vbox, TRUE, TRUE, 2); hbox = gtk_hbox_new(FALSE, 0); gtk_box_pack_start(GTK_BOX(vbox), hbox, FALSE, FALSE, 0); /* Label to introduce the combobox which allow to choose the format */ label = gtk_label_new(_("Choose the file format : ")); gtk_label_set_xalign(GTK_LABEL(label), 0.); gtk_box_pack_start(GTK_BOX(hbox), label, TRUE, TRUE, 0); dumpDialog->comboType = gtk_combo_box_text_new(); /* Set the combo entry that let V_Sim detect the desired format through the extension. */ gtk_combo_box_text_append(GTK_COMBO_BOX_TEXT(dumpDialog->comboType), (const gchar*)0, _("Autodetect format")); gtk_box_pack_start(GTK_BOX(hbox), dumpDialog->comboType, FALSE, FALSE, 0); /* Add an expander for file format options. */ dumpDialog->expanderToolFileFormat = gtk_expander_new(_("File format option:")); gtk_widget_set_sensitive(dumpDialog->expanderToolFileFormat, FALSE); gtk_box_pack_start(GTK_BOX(vbox), dumpDialog->expanderToolFileFormat, FALSE, FALSE, 0); g_signal_connect(G_OBJECT(dumpDialog->comboType), "changed", G_CALLBACK(onComboToolFileFormatChange), (gpointer)dumpDialog); /* Add a separator. */ wd = gtk_vseparator_new(); gtk_box_pack_start(GTK_BOX(dumpDialog->hBoxOptions), wd, FALSE, FALSE, 0); /* Create common options part. */ vbox = gtk_vbox_new(FALSE, 0); gtk_box_pack_start(GTK_BOX(dumpDialog->hBoxOptions), vbox, TRUE, TRUE, 2); dumpDialog->checkFileExtension = gtk_check_button_new_with_label(_("Add extension")); gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON(dumpDialog->checkFileExtension), TRUE); gtk_widget_set_sensitive(dumpDialog->checkFileExtension, FALSE); gtk_box_pack_start(GTK_BOX(vbox), dumpDialog->checkFileExtension, FALSE, FALSE, 0); hbox = gtk_hbox_new(FALSE, 0); gtk_box_pack_start(GTK_BOX(vbox), hbox, FALSE, FALSE, 0); label = gtk_label_new(_("Width: ")); gtk_label_set_xalign(GTK_LABEL(label), 0.); gtk_box_pack_start(GTK_BOX(hbox), label, TRUE, TRUE, 0); dumpDialog->spinWidth = gtk_spin_button_new_with_range(1., 2000., 1.); if (klass->width > 0) gtk_spin_button_set_value(GTK_SPIN_BUTTON(dumpDialog->spinWidth), (gdouble)klass->width); else if (suggestedWidth > 0) gtk_spin_button_set_value(GTK_SPIN_BUTTON(dumpDialog->spinWidth), (gdouble)suggestedWidth); gtk_box_pack_start(GTK_BOX(hbox), dumpDialog->spinWidth, FALSE, FALSE, 0); label = gtk_label_new(_("px")); gtk_box_pack_start(GTK_BOX(hbox), label, FALSE, FALSE, 0); hbox = gtk_hbox_new(FALSE, 0); gtk_box_pack_start(GTK_BOX(vbox), hbox, FALSE, FALSE, 0); label = gtk_label_new(_("Height: ")); gtk_label_set_xalign(GTK_LABEL(label), 0.); gtk_box_pack_start(GTK_BOX(hbox), label, TRUE, TRUE, 0); dumpDialog->spinHeight = gtk_spin_button_new_with_range(1., 2000., 1.); if (klass->height > 0) gtk_spin_button_set_value(GTK_SPIN_BUTTON(dumpDialog->spinHeight), (gdouble)klass->height); else if (suggestedHeight > 0) gtk_spin_button_set_value(GTK_SPIN_BUTTON(dumpDialog->spinHeight), (gdouble)suggestedHeight); gtk_box_pack_start(GTK_BOX(hbox), dumpDialog->spinHeight, FALSE, FALSE, 0); label = gtk_label_new(_("px")); gtk_box_pack_start(GTK_BOX(hbox), label, FALSE, FALSE, 0); g_signal_connect(G_OBJECT(dumpDialog->spinWidth), "value-changed", G_CALLBACK(onWidthHeightChanged), (gpointer)&klass->width); g_signal_connect(G_OBJECT(dumpDialog->spinHeight), "value-changed", G_CALLBACK(onWidthHeightChanged), (gpointer)&klass->height); /* Create the progress bar part. */ hbox2 = gtk_hbox_new(FALSE, 0); gtk_box_pack_start(GTK_BOX(gtk_dialog_get_content_area(GTK_DIALOG(dumpDialog))), hbox2, FALSE, FALSE, 2); /* Label to introduce the progress bar */ label = gtk_label_new(_("Dump progress : ")); gtk_label_set_xalign(GTK_LABEL(label), 0.); gtk_box_pack_start(GTK_BOX(hbox2), label, FALSE, FALSE, 0); dumpDialog->progressBar = gtk_progress_bar_new(); gtk_box_pack_start(GTK_BOX(hbox2), dumpDialog->progressBar, TRUE, TRUE, 2); /* Add an info bar for warning and so on. */ #if GTK_MAJOR_VERSION > 2 || GTK_MINOR_VERSION > 17 dumpDialog->infoBar = gtk_info_bar_new(); gtk_widget_set_no_show_all(dumpDialog->infoBar, TRUE); gtk_info_bar_set_message_type(GTK_INFO_BAR(dumpDialog->infoBar), GTK_MESSAGE_WARNING); label = gtk_label_new(_("Current box has translations applied," " do you want to proceed to exportation anyway?")); gtk_widget_show(label); gtk_container_add (GTK_CONTAINER(gtk_info_bar_get_content_area(GTK_INFO_BAR(dumpDialog->infoBar))), label); gtk_box_pack_start(GTK_BOX(gtk_dialog_get_content_area(GTK_DIALOG(dumpDialog))), dumpDialog->infoBar, FALSE, FALSE, 2); #endif /* Setting default values. */ gtk_widget_set_name(GTK_WIDGET(dumpDialog), "filesel"); directory = visu_ui_main_getLastOpenDirectory(visu_ui_main_class_getCurrentPanel()); if (klass->current_dir) gtk_file_chooser_set_current_folder(GTK_FILE_CHOOSER(dumpDialog->fileChooser), klass->current_dir); else if (directory) gtk_file_chooser_set_current_folder(GTK_FILE_CHOOSER(dumpDialog->fileChooser), directory); for (format = visu_dump_pool_getAllModules(); format; format = g_list_next(format)) { labelType = tool_file_format_getLabel(TOOL_FILE_FORMAT(format->data)); if (labelType) gtk_combo_box_text_append(GTK_COMBO_BOX_TEXT(dumpDialog->comboType), (const gchar*)0, labelType); } gtk_combo_box_set_active(GTK_COMBO_BOX(dumpDialog->comboType), klass->formatId); gtk_widget_show_all(GTK_WIDGET(dumpDialog)); return GTK_WIDGET(dumpDialog); } /*******************/ /* Local callbacks */ /*******************/ static void onSpinPropertyChange(GtkSpinButton *spin, gpointer data) { GValue *val; val = (GValue*)data; g_value_set_int(val, (int)gtk_spin_button_get_value(spin)); DBG_fprintf(stderr, "Gtk VisuUiDumpDialog: set property spin to %d.\n", g_value_get_int(val)); } static void onCheckPropertyChange(GtkToggleButton *toggle, gpointer data) { GValue *val; val = (GValue*)data; g_value_set_boolean(val, gtk_toggle_button_get_active(toggle)); DBG_fprintf(stderr, "Gtk VisuUiDumpDialog: set property check to %d.\n", g_value_get_boolean(val)); } static void onComboToolFileFormatChange(GtkComboBox *combo, gpointer data) { int formatInt, i; GList *dumpTypes; ToolFileFormatIter iter; GtkWidget *wd, *label, *hbox, *vbox; g_return_if_fail(VISU_IS_UI_DUMP_DIALOG(data)); /* Empty the expander for properties. */ wd = gtk_bin_get_child(GTK_BIN(VISU_UI_DUMP_DIALOG(data)->expanderToolFileFormat)); if (wd) gtk_widget_destroy(wd); dumpTypes = visu_dump_pool_getAllModules(); formatInt = gtk_combo_box_get_active(combo); VISU_UI_DUMP_DIALOG_GET_CLASS(data)->formatId = (guint)formatInt; DBG_fprintf(stderr, "Gtk VisuUiDumpDialog: On file format change (%d).\n", formatInt); /* Select auto file format -> no properties. */ if (formatInt == 0) { gtk_widget_set_sensitive(VISU_UI_DUMP_DIALOG(data)->expanderToolFileFormat, FALSE); gtk_widget_set_sensitive(VISU_UI_DUMP_DIALOG(data)->checkFileExtension, FALSE); return; } else /* Search for the selected property. */ for(i = 0; i < formatInt - 1; i++) dumpTypes = g_list_next(dumpTypes); /* Set the check box for extension auto completion. */ gtk_widget_set_sensitive(VISU_UI_DUMP_DIALOG(data)->checkFileExtension, TRUE); /* Get properties if exist for this format. */ iter.lst = (GList*)0; tool_file_format_iterNextProperty(TOOL_FILE_FORMAT(dumpTypes->data), &iter); if (!iter.lst) { gtk_widget_set_sensitive(VISU_UI_DUMP_DIALOG(data)->expanderToolFileFormat, FALSE); return; } gtk_widget_set_sensitive(VISU_UI_DUMP_DIALOG(data)->expanderToolFileFormat, TRUE); vbox = gtk_vbox_new(FALSE, 0); gtk_container_add(GTK_CONTAINER(VISU_UI_DUMP_DIALOG(data)->expanderToolFileFormat), vbox); iter.lst = (GList*)0; for (tool_file_format_iterNextProperty(TOOL_FILE_FORMAT(dumpTypes->data), &iter); iter.lst; tool_file_format_iterNextProperty(TOOL_FILE_FORMAT(dumpTypes->data), &iter)) { hbox = gtk_hbox_new(FALSE, 0); gtk_box_pack_start(GTK_BOX(vbox), hbox, FALSE, FALSE, 0); label = gtk_label_new(iter.label); gtk_label_set_xalign(GTK_LABEL(label), 1.); gtk_widget_set_margin_start(label, 10); gtk_box_pack_start(GTK_BOX(hbox), label, TRUE, TRUE, 0); switch (G_VALUE_TYPE(iter.val)) { case G_TYPE_INT: wd = gtk_spin_button_new_with_range(0., 100., 1.); gtk_spin_button_set_value(GTK_SPIN_BUTTON(wd), (gdouble)g_value_get_int(iter.val)); gtk_box_pack_start(GTK_BOX(hbox), wd, FALSE, FALSE, 0); g_signal_connect(G_OBJECT(wd), "value-changed", G_CALLBACK(onSpinPropertyChange), iter.val); break; case G_TYPE_BOOLEAN: wd = gtk_check_button_new(); gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON(wd), g_value_get_boolean(iter.val)); gtk_box_pack_start(GTK_BOX(hbox), wd, FALSE, FALSE, 0); g_signal_connect(G_OBJECT(wd), "toggled", G_CALLBACK(onCheckPropertyChange), iter.val); break; default: g_warning("Unknown, or nsupprted file format property" " given to 'onComboToolFileFormatChange'."); }; } gtk_widget_show_all(vbox); /* Expand the option expander. */ gtk_expander_set_expanded(GTK_EXPANDER(VISU_UI_DUMP_DIALOG(data)->expanderToolFileFormat), TRUE); } static void onVisuUiDumpDialogResponse(GtkDialog *dialog, gint id, gpointer *data) { gchar *filename; int formatInt; gchar *ext, *pattern; GList *dumpTypes; VisuUiDumpDialog *dumpDialog; VisuUiDumpDialogClass *klass; g_return_if_fail(VISU_IS_UI_DUMP_DIALOG(data)); dumpDialog = VISU_UI_DUMP_DIALOG(data); DBG_fprintf(stderr, "Gtk VisuUiDumpDialog: catch the 'response' signal:" " %d (ACCEPT is %d).\n", id, GTK_RESPONSE_ACCEPT); /* Get the filename. */ filename = (gchar*)0; formatInt = -1; if (id == GTK_RESPONSE_ACCEPT) { filename = gtk_file_chooser_get_filename(GTK_FILE_CHOOSER(dumpDialog->fileChooser)); formatInt = gtk_combo_box_get_active(GTK_COMBO_BOX(dumpDialog->comboType)); if (!filename) { /* Autodetect failed, no format match the given filename */ visu_ui_raiseWarning(_("Saving a file"), _("No filename chosen."), GTK_WINDOW(dialog)); g_signal_stop_emission_by_name(G_OBJECT(dumpDialog), "response"); return; } } if (formatInt >= 0) { dumpTypes = visu_dump_pool_getAllModules(); if (formatInt == 0) /* The automatic format has been selected, we look in the pattern list to find a matching pattern. */ while (dumpTypes && !tool_file_format_match (TOOL_FILE_FORMAT(dumpTypes->data), filename)) dumpTypes = g_list_next(dumpTypes); else dumpTypes = g_list_nth(dumpTypes, formatInt - 1); if (!dumpTypes) { /* Autodetect failed, no format match the given filename */ visu_ui_raiseWarning(_("Saving a file"), _("The filename doesn't match any known format."), GTK_WINDOW(dialog)); g_free(filename); g_signal_stop_emission_by_name(G_OBJECT(dumpDialog), "response"); return; } DBG_fprintf(stderr, "Gtk VisuUiDumpDialog: export to dump %p.\n", dumpTypes->data); /* Special warning for non bitmap exportation with translations. */ #if GTK_MAJOR_VERSION > 2 || GTK_MINOR_VERSION > 17 if (VISU_IS_DUMP_DATA(dumpTypes->data) && visu_pointset_getTranslationPeriodicStatus(VISU_POINTSET(dumpDialog->dataObj)) && !gtk_widget_get_visible(dumpDialog->infoBar)) { gtk_widget_show(dumpDialog->infoBar); g_free(filename); g_signal_stop_emission_by_name(G_OBJECT(dumpDialog), "response"); return; } #endif if (formatInt > 0 && gtk_toggle_button_get_active(GTK_TOGGLE_BUTTON(dumpDialog->checkFileExtension))) { if (tool_file_format_canMatch(TOOL_FILE_FORMAT(dumpTypes->data)) && !tool_file_format_match(TOOL_FILE_FORMAT(dumpTypes->data), filename)) { pattern = (gchar*) tool_file_format_getFilePatterns (TOOL_FILE_FORMAT(dumpTypes->data))->data; ext = g_strrstr(pattern, "."); dumpDialog->dumpFileName = g_strdup_printf("%s%s", filename, ext); g_free(filename); } else dumpDialog->dumpFileName = filename; } else dumpDialog->dumpFileName = filename; dumpDialog->selectedToolFileFormat = VISU_DUMP(dumpTypes->data); DBG_fprintf(stderr, "Gtk VisuUiDumpDialog: '%s' file format chosen.\n", tool_file_format_getName(TOOL_FILE_FORMAT(dumpDialog->selectedToolFileFormat))); /* Save the filename in a property of the VisuData object. */ filename = g_path_get_basename(dumpDialog->dumpFileName); g_object_set_data_full(G_OBJECT(dumpDialog->dataObj), "visu_ui_dump_dialog_filename", (gpointer)filename, g_free); /* Save the dirname in the class. */ klass = VISU_UI_DUMP_DIALOG_CLASS(G_OBJECT_GET_CLASS(dumpDialog)); if (klass->current_dir) g_free(klass->current_dir); klass->current_dir = g_path_get_dirname(dumpDialog->dumpFileName); } } static void onWidthHeightChanged(GtkSpinButton *spin, gpointer data) { *(guint*)data = (guint)gtk_spin_button_get_value(spin); } /******************/ /* Public methods */ /******************/ gchar* visu_ui_dump_dialog_getFilename(VisuUiDumpDialog *dialog) { g_return_val_if_fail(dialog, (gchar*)0); return dialog->dumpFileName; } VisuDump* visu_ui_dump_dialog_getType(VisuUiDumpDialog *dialog) { g_return_val_if_fail(dialog, (VisuDump*)0); return dialog->selectedToolFileFormat; } GtkProgressBar* visu_ui_dump_dialog_getProgressBar(VisuUiDumpDialog *dialog) { g_return_val_if_fail(dialog, (GtkProgressBar*)0); return GTK_PROGRESS_BAR(dialog->progressBar); } GtkButton* visu_ui_dump_dialog_getCancelButton(VisuUiDumpDialog *dialog) { g_return_val_if_fail(dialog, (GtkButton*)0); return GTK_BUTTON(dialog->cancelButton); } gint visu_ui_dump_dialog_getWidth(VisuUiDumpDialog *dialog) { g_return_val_if_fail(dialog, 0); return (gint)gtk_spin_button_get_value(GTK_SPIN_BUTTON(dialog->spinWidth)); } gint visu_ui_dump_dialog_getHeight(VisuUiDumpDialog *dialog) { g_return_val_if_fail(dialog, 0); return (gint)gtk_spin_button_get_value(GTK_SPIN_BUTTON(dialog->spinHeight)); } void visu_ui_dump_dialog_start(VisuUiDumpDialog *dialog) { /* Put everything except the progress bar insensitive */ gtk_widget_set_sensitive(dialog->fileChooser, FALSE); gtk_widget_set_sensitive(dialog->hBoxOptions, FALSE); } void visu_ui_dump_dialog_stop(VisuUiDumpDialog *dialog) { /* Put everything except the progress bar sensitive */ gtk_widget_set_sensitive(dialog->fileChooser, TRUE); gtk_widget_set_sensitive(dialog->hBoxOptions, TRUE); } v_sim-3.8.0/src/extraGtkFunctions/gtk_dumpDialogWidget.h000066400000000000000000000136331370110300500233530ustar00rootroot00000000000000/* EXTRAITS DE LA LICENCE Copyright CEA, contributeurs : Luc BILLARD et Damien CALISTE, laboratoire L_Sim, (2001-2005) Adresse mèl : BILLARD, non joignable par mèl ; CALISTE, damien P caliste AT cea P fr. Ce logiciel est un programme informatique servant à visualiser des structures atomiques dans un rendu pseudo-3D. Ce logiciel est régi par la licence CeCILL soumise au droit français et respectant les principes de diffusion des logiciels libres. Vous pouvez utiliser, modifier et/ou redistribuer ce programme sous les conditions de la licence CeCILL telle que diffusée par le CEA, le CNRS et l'INRIA sur le site "http://www.cecill.info". Le fait que vous puissiez accéder à cet en-tête signifie que vous avez pris connaissance de la licence CeCILL, et que vous en avez accepté les termes (cf. le fichier Documentation/licence.fr.txt fourni avec ce logiciel). */ /* LICENCE SUM UP Copyright CEA, contributors : Luc BILLARD et Damien CALISTE, laboratoire L_Sim, (2001-2005) E-mail address: BILLARD, not reachable any more ; CALISTE, damien P caliste AT cea P fr. This software is a computer program whose purpose is to visualize atomic configurations in 3D. This software is governed by the CeCILL license under French law and abiding by the rules of distribution of free software. You can use, modify and/ or redistribute the software under the terms of the CeCILL license as circulated by CEA, CNRS and INRIA at the following URL "http://www.cecill.info". The fact that you are presently reading this means that you have had knowledge of the CeCILL license and that you accept its terms. You can find a copy of this licence shipped with this software at Documentation/licence.en.txt. */ #ifndef GTK_DUMPDIALOG_H #define GTK_DUMPDIALOG_H #include #include #include #include #include G_BEGIN_DECLS /** * VISU_TYPE_UI_DUMP_DIALOG: * * Return the associated #GType to the VisuUiDumpDialog objects. */ #define VISU_TYPE_UI_DUMP_DIALOG (visu_ui_dump_dialog_get_type ()) /** * VISU_UI_DUMP_DIALOG: * @obj: the widget to cast. * * Cast the given object to a #VisuUiDumpDialog object. */ #define VISU_UI_DUMP_DIALOG(obj) (G_TYPE_CHECK_INSTANCE_CAST ((obj), VISU_TYPE_UI_DUMP_DIALOG, VisuUiDumpDialog)) /** * VISU_UI_DUMP_DIALOG_CLASS: * @klass: the class to cast. * * Cast the given class to a #VisuUiDumpDialogClass object. */ #define VISU_UI_DUMP_DIALOG_CLASS(klass) (G_TYPE_CHECK_CLASS_CAST ((klass), VISU_TYPE_UI_DUMP_DIALOG, VisuUiDumpDialogClass)) /** * VISU_IS_UI_DUMP_DIALOG: * @obj: the object to test. * * Return if the given object is a valid #VisuUiDumpDialog object. */ #define VISU_IS_UI_DUMP_DIALOG(obj) (G_TYPE_CHECK_INSTANCE_TYPE ((obj), VISU_TYPE_UI_DUMP_DIALOG)) /** * VISU_IS_UI_DUMP_DIALOG_CLASS: * @klass: the class to test. * * Return if the given class is a valid #VisuUiDumpDialogClass class. */ #define VISU_IS_UI_DUMP_DIALOG_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE ((klass), VISU_TYPE_UI_DUMP_DIALOG)) /** * VISU_UI_DUMP_DIALOG_GET_CLASS: * @obj: the widget to get the class of. * * Get the class of the given object. */ #define VISU_UI_DUMP_DIALOG_GET_CLASS(obj) (G_TYPE_INSTANCE_GET_CLASS(obj, VISU_TYPE_UI_DUMP_DIALOG, VisuUiDumpDialogClass)) /** * VisuUiDumpDialog * * Private structure to store informations of a #VisuUiDumpDialog object. */ typedef struct _VisuUiDumpDialog VisuUiDumpDialog; /** * VisuUiDumpDialogClass * * Private structure to store informations of a #VisuUiDumpDialogClass object. */ typedef struct _VisuUiDumpDialogClass VisuUiDumpDialogClass; /** * visu_ui_dump_dialog_get_type * * #GType are unique numbers to identify objects. * * Returns: the #GType associated with #VisuUiDumpDialog objects. */ GType visu_ui_dump_dialog_get_type (void); GtkWidget* visu_ui_dump_dialog_new(VisuData *dataObj, GtkWindow *parent, const gchar *suggestedFilename, gint suggestedWidth, gint suggestedHeight); /** * visu_ui_dump_dialog_getFilename: * @dialog: a #VisuUiDumpDialog object. * * Retrieve the chosen filename. * * Returns: a read-only string. */ gchar* visu_ui_dump_dialog_getFilename(VisuUiDumpDialog *dialog); /** * visu_ui_dump_dialog_getType: * @dialog: a #VisuUiDumpDialog object. * * Retrieve the chosen VisuDump. * * Returns: (transfer none): the selected format (ToolFileFormat and write method). */ VisuDump* visu_ui_dump_dialog_getType(VisuUiDumpDialog *dialog); /** * visu_ui_dump_dialog_getProgressBar: * @dialog: a #VisuUiDumpDialog object. * * Retrieve interesting widget. * * Returns: (transfer none): a pointer to the progress bar. */ GtkProgressBar* visu_ui_dump_dialog_getProgressBar(VisuUiDumpDialog *dialog); /** * visu_ui_dump_dialog_getCancelButton: * @dialog: a #VisuUiDumpDialog object. * * Retrieve interesting widget. * * Returns: (transfer none): a pointer to the cancel button. */ GtkButton* visu_ui_dump_dialog_getCancelButton(VisuUiDumpDialog *dialog); /** * visu_ui_dump_dialog_getWidth: * @dialog: a #VisuUiDumpDialog object. * * Retrieve request image size. * * Returns: the width value. */ gint visu_ui_dump_dialog_getWidth(VisuUiDumpDialog *dialog); /** * visu_ui_dump_dialog_getHeight: * @dialog: a #VisuUiDumpDialog object. * * Retrieve request image size. * * Returns: the height value. */ gint visu_ui_dump_dialog_getHeight(VisuUiDumpDialog *dialog); /** * visu_ui_dump_dialog_start: * @dialog: a #VisuUiDumpDialog object. * * Make the file chooser part insensitive during dump, only the * progress bar and the abort button are kept sensitive. */ void visu_ui_dump_dialog_start(VisuUiDumpDialog *dialog); /** * visu_ui_dump_dialog_stop: * @dialog: a #VisuUiDumpDialog object. * * Return the filechooser to a sensitive state. */ void visu_ui_dump_dialog_stop(VisuUiDumpDialog *dialog); G_END_DECLS #endif v_sim-3.8.0/src/extraGtkFunctions/gtk_elementComboBox.c000066400000000000000000000522761370110300500232050ustar00rootroot00000000000000/* EXTRAITS DE LA LICENCE Copyright CEA, contributeurs : Damien CALISTE, laboratoire L_Sim, (2001-2005) Adresse mèl : CALISTE, damien P caliste AT cea P fr. Ce logiciel est un programme informatique servant à visualiser des structures atomiques dans un rendu pseudo-3D. Ce logiciel est régi par la licence CeCILL soumise au droit français et respectant les principes de diffusion des logiciels libres. Vous pouvez utiliser, modifier et/ou redistribuer ce programme sous les conditions de la licence CeCILL telle que diffusée par le CEA, le CNRS et l'INRIA sur le site "http://www.cecill.info". Le fait que vous puissiez accéder à cet en-tête signifie que vous avez pris connaissance de la licence CeCILL, et que vous en avez accepté les termes (cf. le fichier Documentation/licence.fr.txt fourni avec ce logiciel). */ /* LICENCE SUM UP Copyright CEA, contributors : Damien CALISTE, laboratoire L_Sim, (2001-2005) E-mail address: CALISTE, damien P caliste AT cea P fr. This software is a computer program whose purpose is to visualize atomic configurations in 3D. This software is governed by the CeCILL license under French law and abiding by the rules of distribution of free software. You can use, modify and/ or redistribute the software under the terms of the CeCILL license as circulated by CEA, CNRS and INRIA at the following URL "http://www.cecill.info". The fact that you are presently reading this means that you have had knowledge of the CeCILL license and that you accept its terms. You can find a copy of this licence shipped with this software at Documentation/licence.en.txt. */ #include #include #include "gtk_elementComboBox.h" #include #include /** * SECTION:gtk_elementComboBox * @short_description: Defines a specialised #GtkComboBox to choose #VisuElement. * * This widget looks like a #GtkComboBox and it displays a list * of #VisuElement currently used by the displayed data. * * Since: 3.6 */ enum { ELEMENT_SELECTED_SIGNAL, LAST_SIGNAL }; /* This enum is used to access the column of the GtkListStore that contains the informations of stroed shades. */ enum { /* This a pointer to the VisuElement */ COLUMN_ELEMENT_POINTER_TO, N_COLUMN_ELEMENT }; enum { PROP_0, NODES_PROP, ELEMENT_PROP, N_PROP }; static GParamSpec *_properties[N_PROP]; static void visu_ui_element_combobox_dispose (GObject *obj); static void visu_ui_element_combobox_finalize(GObject *obj); static void visu_ui_element_combobox_get_property(GObject* obj, guint property_id, GValue *value, GParamSpec *pspec); static void visu_ui_element_combobox_set_property(GObject* obj, guint property_id, const GValue *value, GParamSpec *pspec); static guint _signals[LAST_SIGNAL] = { 0 }; /** * VisuUiElementCombobox: * * An opaque structure defining a #VisuUiElementCombobox widget. * * Since: 3.6 */ struct _VisuUiElementCombobox { GtkComboBox parent; GtkTreeModel *filter; VisuNodeArray *nodes; gulong popDef_signal; gulong onChanged; gpointer previousSelection; gboolean hasAllSelector; gboolean hasNoneSelector; gboolean showUnPhysical; gchar *format; /* Memory gestion. */ gboolean dispose_has_run; }; /** * VisuUiElementComboboxClass: * * An opaque structure defining the class of a #VisuUiElementCombobox widget. * * Since: 3.6 */ struct _VisuUiElementComboboxClass { GtkComboBoxClass parent_class; void (*elementComboBox) (VisuUiElementCombobox *shadeCombo); /* This listStore contains all the elements known by widgets of this class. It is used as TreeModel for the combobox in the widget. */ GtkListStore *storedElements; gulong newElementSignalId; }; /* Local callbacks. */ static void onChanged(GtkComboBox *widget, gpointer user_data); static gboolean onElementNewHook(GSignalInvocationHint *ihint, guint nvalues, const GValue *param_values, gpointer data); /* Local methods. */ static void addElementToModel(GtkTreeIter *iter, VisuUiElementComboboxClass* klass, gpointer element); static void printLabel(GtkCellLayout *layout, GtkCellRenderer *cell, GtkTreeModel *model, GtkTreeIter *iter, gpointer data); static gboolean showLabel(GtkTreeModel *model, GtkTreeIter *iter, gpointer data); /** * visu_ui_element_combobox_get_type: * * Internal routine, retrieves the type of #VisuUiElementCombobox * objects. Use VISU_TYPE_UI_ELEMENT_COMBOBOX macro instead. * * Since: 3.6 */ G_DEFINE_TYPE(VisuUiElementCombobox, visu_ui_element_combobox, GTK_TYPE_COMBO_BOX) static void visu_ui_element_combobox_class_init(VisuUiElementComboboxClass *klass) { GtkTreeIter iter; GList *elementLst; DBG_fprintf(stderr, "VisuUi ElementCombobox: creating the class of the widget.\n"); DBG_fprintf(stderr, " - adding new signals ;\n"); /** * VisuUiElementCombobox::element-selected: * @combo: the #VisuUiElementCombobox that emits the signal ; * @element: the newly selected #VisuElement. * * This signal is emitted when a new element is selected. * * Since: 3.6 */ _signals[ELEMENT_SELECTED_SIGNAL] = g_signal_new ("element-selected", G_TYPE_FROM_CLASS (klass), G_SIGNAL_RUN_FIRST | G_SIGNAL_ACTION, G_STRUCT_OFFSET (VisuUiElementComboboxClass, elementComboBox), NULL, NULL, g_cclosure_marshal_VOID__POINTER, G_TYPE_NONE, 1, G_TYPE_POINTER); DBG_fprintf(stderr, " - initializing the listStore of elements.\n"); /* Init the listStore of elements. */ klass->storedElements = gtk_list_store_new(N_COLUMN_ELEMENT, G_TYPE_POINTER); addElementToModel(&iter, klass, (gpointer)0); addElementToModel(&iter, klass, GINT_TO_POINTER(1)); for (elementLst = (GList*)visu_element_getAllElements(); elementLst; elementLst = g_list_next(elementLst)) addElementToModel(&iter, klass, elementLst->data); /* Connect freeing methods. */ G_OBJECT_CLASS(klass)->dispose = visu_ui_element_combobox_dispose; G_OBJECT_CLASS(klass)->finalize = visu_ui_element_combobox_finalize; G_OBJECT_CLASS(klass)->set_property = visu_ui_element_combobox_set_property; G_OBJECT_CLASS(klass)->get_property = visu_ui_element_combobox_get_property; /** * VisuUiElementCombobox::nodes: * * Store the #VisuNodeArray object used to filter the elements. * * Since: 3.8 */ _properties[NODES_PROP] = g_param_spec_object("nodes", "Nodes", "storing nodes used as filter model", VISU_TYPE_NODE_ARRAY, G_PARAM_READWRITE); /** * VisuUiElementCombobox::element: * * Store the #VisuElement currently selected. * * Since: 3.8 */ _properties[ELEMENT_PROP] = g_param_spec_object("element", "Element", "currently selected element", VISU_TYPE_ELEMENT, G_PARAM_READWRITE); g_object_class_install_properties(G_OBJECT_CLASS(klass), N_PROP, _properties); g_type_class_ref(VISU_TYPE_ELEMENT); g_signal_add_emission_hook(g_signal_lookup("ElementNew", VISU_TYPE_ELEMENT), 0, onElementNewHook, (gpointer)klass, (GDestroyNotify)0); } static void visu_ui_element_combobox_dispose(GObject *obj) { DBG_fprintf(stderr, "VisuUi ElementCombobox: dispose object %p.\n", (gpointer)obj); if (VISU_UI_ELEMENT_COMBOBOX(obj)->dispose_has_run) return; VISU_UI_ELEMENT_COMBOBOX(obj)->dispose_has_run = TRUE; visu_ui_element_combobox_setModel(VISU_UI_ELEMENT_COMBOBOX(obj), (VisuNodeArray*)0); /* Chain up to the parent class */ G_OBJECT_CLASS(visu_ui_element_combobox_parent_class)->dispose(obj); } static void visu_ui_element_combobox_finalize(GObject *obj) { g_return_if_fail(obj); DBG_fprintf(stderr, "VisuUi ElementCombobox: finalize object %p.\n", (gpointer)obj); g_free(VISU_UI_ELEMENT_COMBOBOX(obj)->format); /* Chain up to the parent class */ G_OBJECT_CLASS(visu_ui_element_combobox_parent_class)->finalize(obj); DBG_fprintf(stderr, " | freeing ... OK.\n"); } static void visu_ui_element_combobox_get_property(GObject* obj, guint property_id, GValue *value, GParamSpec *pspec) { VisuUiElementCombobox *self = VISU_UI_ELEMENT_COMBOBOX(obj); GtkTreeIter iter; gpointer data; DBG_fprintf(stderr, "VisuUi ElementCombobox: get property '%s' -> ", g_param_spec_get_name(pspec)); switch (property_id) { case NODES_PROP: g_value_set_object(value, self->nodes); DBG_fprintf(stderr, "%p.\n", g_value_get_object(value)); break; case ELEMENT_PROP: if (gtk_combo_box_get_active_iter(GTK_COMBO_BOX(obj), &iter)) { gtk_tree_model_get(self->filter, &iter, COLUMN_ELEMENT_POINTER_TO, &data, -1); g_value_set_object(value, (GPOINTER_TO_INT(data) == 1) ? NULL : data); } else g_value_set_object(value, (GObject*)0); DBG_fprintf(stderr, "%p.\n", g_value_get_object(value)); break; default: /* We don't have any other property... */ G_OBJECT_WARN_INVALID_PROPERTY_ID(obj, property_id, pspec); break; } } static void visu_ui_element_combobox_set_property(GObject* obj, guint property_id, const GValue *value, GParamSpec *pspec) { VisuUiElementCombobox *self = VISU_UI_ELEMENT_COMBOBOX(obj); DBG_fprintf(stderr, "VisuUi ElementCombobox: set property '%s' -> ", g_param_spec_get_name(pspec)); switch (property_id) { case NODES_PROP: DBG_fprintf(stderr, "%p\n", g_value_get_object(value)); visu_ui_element_combobox_setModel(self, VISU_NODE_ARRAY(g_value_get_object(value))); break; case ELEMENT_PROP: DBG_fprintf(stderr, "%p\n", g_value_get_object(value)); visu_ui_element_combobox_setElement(self, VISU_ELEMENT(g_value_get_object(value))); break; default: /* We don't have any other property... */ G_OBJECT_WARN_INVALID_PROPERTY_ID(obj, property_id, pspec); break; } } static void visu_ui_element_combobox_init(VisuUiElementCombobox *elementComboBox) { DBG_fprintf(stderr, "VisuUi ElementCombobox: initializing new object (%p).\n", (gpointer)elementComboBox); elementComboBox->hasAllSelector = FALSE; elementComboBox->hasNoneSelector = FALSE; elementComboBox->showUnPhysical = FALSE; elementComboBox->format = g_strdup("%s"); elementComboBox->dispose_has_run = FALSE; elementComboBox->previousSelection = (gpointer)0; elementComboBox->nodes = (VisuNodeArray*)0; } /** * visu_ui_element_combobox_new: * @hasAllSelector: a boolean. * @hasNoneSelector: a boolean. * @format: (allow-none): a string (can be NULL). * * Creates a #GtkComboBox with a list of available #VisuElement. This * list can contain in addition a "all" value if @hasAllSelector is * TRUE, or a "None" value if @hasNoneSelector is TRUE. The @format * parameter is used to specify the text for each row of the * #GtkComboBox. If @formt is NULL, just the name of the element is printed. * * Since: 3.6 * * Returns: (transfer full): a newly created widget. */ GtkWidget* visu_ui_element_combobox_new(gboolean hasAllSelector, gboolean hasNoneSelector, const gchar *format) { VisuUiElementCombobox *wd; GObjectClass *klass; GtkCellRenderer *renderer; DBG_fprintf(stderr, "VisuUi ElementCombobox: creating new object with format: '%s'.\n", format); wd = VISU_UI_ELEMENT_COMBOBOX(g_object_new(VISU_TYPE_UI_ELEMENT_COMBOBOX, NULL)); wd->hasAllSelector = hasAllSelector; wd->hasNoneSelector = hasNoneSelector; if (format) { g_free(wd->format); wd->format = g_strdup(format); } DBG_fprintf(stderr, "VisuUi ElementCombobox: build widgets.\n"); klass = G_OBJECT_GET_CLASS(wd); wd->filter = gtk_tree_model_filter_new (GTK_TREE_MODEL(VISU_UI_ELEMENT_COMBOBOX_CLASS(klass)->storedElements), (GtkTreePath*)0); gtk_combo_box_set_model(GTK_COMBO_BOX(wd), wd->filter); g_object_unref(wd->filter); gtk_tree_model_filter_set_visible_func(GTK_TREE_MODEL_FILTER(wd->filter), showLabel, wd, (GDestroyNotify)0); gtk_tree_model_filter_refilter(GTK_TREE_MODEL_FILTER(wd->filter)); DBG_fprintf(stderr, "VisuUi ElementCombobox: use filter %p.\n", (gpointer)wd->filter); renderer = gtk_cell_renderer_text_new(); gtk_cell_layout_pack_start(GTK_CELL_LAYOUT(wd), renderer, TRUE); gtk_cell_layout_set_cell_data_func(GTK_CELL_LAYOUT(wd), renderer, printLabel, (gpointer)wd, (GDestroyNotify)0); wd->onChanged = g_signal_connect(G_OBJECT(wd), "changed", G_CALLBACK(onChanged), (gpointer)wd); gtk_combo_box_set_active(GTK_COMBO_BOX(wd), (hasAllSelector)?1:0); return GTK_WIDGET(wd); } /** * visu_ui_element_combobox_setModel: * @combo: a #VisuUiElementCombobox object. * @nodes: a #VisuNodeArray object. * * Binds @nodes to @combo, so the list is always displaying the * #VisuElement used by @nodes. * * Since: 3.8 * * Returns: TRUE if model is actually changed. **/ gboolean visu_ui_element_combobox_setModel(VisuUiElementCombobox *combo, VisuNodeArray *nodes) { g_return_val_if_fail(VISU_IS_UI_ELEMENT_COMBOBOX(combo), FALSE); if (combo->nodes == nodes) return FALSE; if (combo->nodes) { g_signal_handler_disconnect(combo->nodes, combo->popDef_signal); g_object_unref(combo->nodes); } combo->nodes = nodes; if (nodes) { g_object_ref(nodes); combo->popDef_signal = g_signal_connect_swapped(nodes, "notify::elements", G_CALLBACK(gtk_tree_model_filter_refilter), combo->filter); } gtk_tree_model_filter_refilter(GTK_TREE_MODEL_FILTER(combo->filter)); if (gtk_combo_box_get_active(GTK_COMBO_BOX(combo)) < 0) gtk_combo_box_set_active(GTK_COMBO_BOX(combo), MIN((combo->hasAllSelector)?1:0, gtk_tree_model_iter_n_children(combo->filter, (GtkTreeIter*)0) - 1)); return TRUE; } static gboolean onElementNewHook(GSignalInvocationHint *ihint _U_, guint nvalues _U_, const GValue *param_values, gpointer data) { GtkTreeIter iter; VisuElement *ele; DBG_fprintf(stderr, "VisuUi ElementCombobox: found a new element.\n"); ele = VISU_ELEMENT(g_value_get_object(param_values)); addElementToModel(&iter, VISU_UI_ELEMENT_COMBOBOX_CLASS(data), (gpointer)ele); return TRUE; } static void onChanged(GtkComboBox *widget, gpointer user_data _U_) { GtkTreeIter iter; gpointer *data; GList *lst; if (!gtk_combo_box_get_active_iter(widget, &iter)) return; DBG_fprintf(stderr, "VisuUi ElementCombobox: internal combobox changed signal.\n"); gtk_tree_model_get(VISU_UI_ELEMENT_COMBOBOX(widget)->filter, &iter, COLUMN_ELEMENT_POINTER_TO, &data, -1); if (data != VISU_UI_ELEMENT_COMBOBOX(widget)->previousSelection) { VISU_UI_ELEMENT_COMBOBOX(widget)->previousSelection = data; lst = visu_ui_element_combobox_getSelection(VISU_UI_ELEMENT_COMBOBOX(widget)); DBG_fprintf(stderr, "VisuUi ElementCombobox: emitting 'element-selected'" " signal with list %p.\n", (gpointer)lst); g_signal_emit(widget, _signals[ELEMENT_SELECTED_SIGNAL], 0, (gpointer)lst); DBG_fprintf(stderr, " | free list\n"); if (lst) g_list_free(lst); DBG_fprintf(stderr, " | OK\n"); g_object_notify_by_pspec(G_OBJECT(widget), _properties[ELEMENT_PROP]); } else DBG_fprintf(stderr, "VisuUi ElementCombobox: aborting 'element-selected' signal.\n"); } static void addElementToModel(GtkTreeIter *iter, VisuUiElementComboboxClass* klass, gpointer element) { g_return_if_fail(iter && klass); DBG_fprintf(stderr, "VisuUi ElementCombobox: appending a new element '%p'.\n", element); gtk_list_store_append(klass->storedElements, iter); gtk_list_store_set(klass->storedElements, iter, COLUMN_ELEMENT_POINTER_TO , element, -1); } static void printLabel(GtkCellLayout *layout _U_, GtkCellRenderer *cell, GtkTreeModel *model, GtkTreeIter *iter, gpointer data) { gpointer pt; gchar *str; gtk_tree_model_get(model, iter, COLUMN_ELEMENT_POINTER_TO, &pt, -1); if (!pt) g_object_set(G_OBJECT(cell), "text", _("None"), NULL); else if (GPOINTER_TO_INT(pt) == 1) g_object_set(G_OBJECT(cell), "text", _("All elements"), NULL); else { str = g_strdup_printf(VISU_UI_ELEMENT_COMBOBOX(data)->format, ((VisuElement*)pt)->name); g_object_set(G_OBJECT(cell), "text", str, NULL); g_free(str); } } static gboolean showLabel(GtkTreeModel *model, GtkTreeIter *iter, gpointer data) { gpointer pt; VisuUiElementCombobox *combo; combo = VISU_UI_ELEMENT_COMBOBOX(data); if (!combo->nodes) return FALSE; gtk_tree_model_get(model, iter, COLUMN_ELEMENT_POINTER_TO, &pt, -1); return (!pt && combo->hasNoneSelector) || (pt && GPOINTER_TO_INT(pt) == 1 && combo->hasAllSelector) || (pt && GPOINTER_TO_INT(pt) != 1 && visu_node_array_containsElement(combo->nodes, VISU_ELEMENT(pt)) && (combo->showUnPhysical || visu_element_getPhysical(VISU_ELEMENT(pt)))); } /** * visu_ui_element_combobox_setSelection: * @wd: a #VisuUiElementCombobox widget. * @name: a string. * * Select a #VisuElement by providing its name. * * Since: 3.6 * * Returns: TRUE if the given element exists. */ gboolean visu_ui_element_combobox_setSelection(VisuUiElementCombobox* wd, const gchar *name) { GtkTreeIter iter; gboolean valid; gpointer *pt; g_return_val_if_fail(VISU_IS_UI_ELEMENT_COMBOBOX(wd) && name, FALSE); DBG_fprintf(stderr, "VisuUi ElementCombobox: select a new element '%s'.\n", name); for (valid = gtk_tree_model_get_iter_first(wd->filter, &iter); valid; valid = gtk_tree_model_iter_next(wd->filter, &iter)) { gtk_tree_model_get(wd->filter, &iter, COLUMN_ELEMENT_POINTER_TO, &pt, -1); if (pt && GPOINTER_TO_INT(pt) != 1 && !strcmp(visu_element_getName(VISU_ELEMENT(pt)), name)) { gtk_combo_box_set_active_iter(GTK_COMBO_BOX(wd), &iter); return TRUE; } } return FALSE; } /** * visu_ui_element_combobox_setElement: * @wd: a #VisuUiElementCombobox widget. * @element: a #VisuElement object. * * Select a #VisuElement. * * Since: 3.8 * * Returns: TRUE if the given element exists. */ gboolean visu_ui_element_combobox_setElement(VisuUiElementCombobox* wd, const VisuElement *element) { GtkTreeIter iter; gboolean valid; gpointer pt; g_return_val_if_fail(VISU_IS_UI_ELEMENT_COMBOBOX(wd), FALSE); for (valid = gtk_tree_model_get_iter_first(wd->filter, &iter); valid; valid = gtk_tree_model_iter_next(wd->filter, &iter)) { gtk_tree_model_get(wd->filter, &iter, COLUMN_ELEMENT_POINTER_TO, &pt, -1); if (pt == element) { gtk_combo_box_set_active_iter(GTK_COMBO_BOX(wd), &iter); return TRUE; } } gtk_combo_box_set_active(GTK_COMBO_BOX(wd), -1); return FALSE; } /** * visu_ui_element_combobox_getSelection: * @wd: a #VisuUiElementCombobox widget. * * Provide a list of selected elements. * * Since: 3.6 * * Returns: (transfer container) (element-type VisuElement*): a newly * created list of #VisuElement. It should be freed later with * g_list_free(). */ GList* visu_ui_element_combobox_getSelection(VisuUiElementCombobox *wd) { GtkTreeIter iter; gpointer *data; GList *lst; gboolean valid; g_return_val_if_fail(VISU_IS_UI_ELEMENT_COMBOBOX(wd), (GList*)0); if (!gtk_combo_box_get_active_iter(GTK_COMBO_BOX(wd), &iter)) return (GList*)0; gtk_tree_model_get(wd->filter, &iter, COLUMN_ELEMENT_POINTER_TO, &data, -1); lst = (GList*)0; if (GPOINTER_TO_INT(data) == 1) for (valid = gtk_tree_model_get_iter_first(wd->filter, &iter); valid; valid = gtk_tree_model_iter_next(wd->filter, &iter)) { gtk_tree_model_get(wd->filter, &iter, COLUMN_ELEMENT_POINTER_TO, &data, -1); if (data && GPOINTER_TO_INT(data) != 1 && visu_element_getPhysical(VISU_ELEMENT(data))) lst = g_list_prepend(lst, data); } else if (data) lst = g_list_prepend(lst, data); DBG_fprintf(stderr, "VisuUi ElementCombobox: return a list of %d elements.\n", g_list_length(lst)); return lst; } /** * visu_ui_element_combobox_setUnphysicalStatus: * @wd: a #VisuUiElementCombobox object ; * @status: a boolean * * If @status is TRUE, the combobox will also show elements that are * tagged unphysical, see visu_element_getPhysical(). * * Since: 3.7 */ void visu_ui_element_combobox_setUnphysicalStatus(VisuUiElementCombobox* wd, gboolean status) { g_return_if_fail(VISU_IS_UI_ELEMENT_COMBOBOX(wd)); wd->showUnPhysical = status; } v_sim-3.8.0/src/extraGtkFunctions/gtk_elementComboBox.h000066400000000000000000000105361370110300500232030ustar00rootroot00000000000000/* EXTRAITS DE LA LICENCE Copyright CEA, contributeurs : Damien CALISTE, laboratoire L_Sim, (2001-2005) Adresse mèl : CALISTE, damien P caliste AT cea P fr. Ce logiciel est un programme informatique servant à visualiser des structures atomiques dans un rendu pseudo-3D. Ce logiciel est régi par la licence CeCILL soumise au droit français et respectant les principes de diffusion des logiciels libres. Vous pouvez utiliser, modifier et/ou redistribuer ce programme sous les conditions de la licence CeCILL telle que diffusée par le CEA, le CNRS et l'INRIA sur le site "http://www.cecill.info". Le fait que vous puissiez accéder à cet en-tête signifie que vous avez pris connaissance de la licence CeCILL, et que vous en avez accepté les termes (cf. le fichier Documentation/licence.fr.txt fourni avec ce logiciel). */ /* LICENCE SUM UP Copyright CEA, contributors : Damien CALISTE, laboratoire L_Sim, (2001-2005) E-mail address: CALISTE, damien P caliste AT cea P fr. This software is a computer program whose purpose is to visualize atomic configurations in 3D. This software is governed by the CeCILL license under French law and abiding by the rules of distribution of free software. You can use, modify and/ or redistribute the software under the terms of the CeCILL license as circulated by CEA, CNRS and INRIA at the following URL "http://www.cecill.info". The fact that you are presently reading this means that you have had knowledge of the CeCILL license and that you accept its terms. You can find a copy of this licence shipped with this software at Documentation/licence.en.txt. */ #ifndef GTK_ELEMENTCOMBOBOX_H #define GTK_ELEMENTCOMBOBOX_H #include #include G_BEGIN_DECLS /** * VISU_TYPE_UI_ELEMENT_COMBOBOX: * * Return the associated #GType to the #VisuUiElementCombobox objects. * * Since: 3.6 */ #define VISU_TYPE_UI_ELEMENT_COMBOBOX (visu_ui_element_combobox_get_type ()) /** * VISU_UI_ELEMENT_COMBOBOX: * @obj: the widget to cast. * * Cast the given object to a #VisuUiElementCombobox object. * * Since: 3.6 */ #define VISU_UI_ELEMENT_COMBOBOX(obj) (G_TYPE_CHECK_INSTANCE_CAST ((obj), VISU_TYPE_UI_ELEMENT_COMBOBOX, VisuUiElementCombobox)) /** * VISU_UI_ELEMENT_COMBOBOX_CLASS: * @klass: the class to cast. * * Cast the given class to a #VisuUiElementCombobox object. * * Since: 3.6 */ #define VISU_UI_ELEMENT_COMBOBOX_CLASS(klass) (G_TYPE_CHECK_CLASS_CAST ((klass), VISU_TYPE_UI_ELEMENT_COMBOBOX, VisuUiElementComboboxClass)) /** * VISU_IS_UI_ELEMENT_COMBOBOX: * @obj: the object to test. * * Return if the given object is a valid #VisuUiElementCombobox object. * * Since: 3.6 */ #define VISU_IS_UI_ELEMENT_COMBOBOX(obj) (G_TYPE_CHECK_INSTANCE_TYPE ((obj), VISU_TYPE_UI_ELEMENT_COMBOBOX)) /** * VISU_IS_UI_ELEMENT_COMBOBOX_CLASS: * @klass: the class to test. * * Return if the given class is a valid #VisuUiElementComboboxClass class. * * Since: 3.6 */ #define VISU_IS_UI_ELEMENT_COMBOBOX_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE ((klass), VISU_TYPE_UI_ELEMENT_COMBOBOX)) /** * VISU_UI_ELEMENT_COMBOBOX_GET_CLASS: * @obj: the widget to get the class of. * * Get the class of the given object. * * Since: 3.6 */ #define VISU_UI_ELEMENT_COMBOBOX_GET_CLASS(obj) (G_TYPE_INSTANCE_GET_CLASS(obj, VISU_TYPE_UI_ELEMENT_COMBOBOX, VisuUiElementComboboxClass)) typedef struct _VisuUiElementCombobox VisuUiElementCombobox; typedef struct _VisuUiElementComboboxClass VisuUiElementComboboxClass; GType visu_ui_element_combobox_get_type(void); GtkWidget* visu_ui_element_combobox_new(gboolean hasAllSelector, gboolean hasNoneSelector, const gchar *format); gboolean visu_ui_element_combobox_setModel(VisuUiElementCombobox *combo, VisuNodeArray *nodes); GList* visu_ui_element_combobox_getSelection(VisuUiElementCombobox *wd); gboolean visu_ui_element_combobox_setSelection(VisuUiElementCombobox* wd, const gchar *name); gboolean visu_ui_element_combobox_setElement(VisuUiElementCombobox* wd, const VisuElement *element); void visu_ui_element_combobox_setUnphysicalStatus(VisuUiElementCombobox* wd, gboolean status); G_END_DECLS #endif v_sim-3.8.0/src/extraGtkFunctions/gtk_fieldChooser.c000066400000000000000000000314371370110300500225250ustar00rootroot00000000000000/* EXTRAITS DE LA LICENCE Copyright CEA, contributeurs : Damien CALISTE, laboratoire L_Sim, (2011-2011) Adresse mèl : CALISTE, damien P caliste AT cea P fr. Ce logiciel est un programme informatique servant à visualiser des structures atomiques dans un rendu pseudo-3D. Ce logiciel est régi par la licence CeCILL soumise au droit français et respectant les principes de diffusion des logiciels libres. Vous pouvez utiliser, modifier et/ou redistribuer ce programme sous les conditions de la licence CeCILL telle que diffusée par le CEA, le CNRS et l'INRIA sur le site "http://www.cecill.info". Le fait que vous puissiez accéder à cet en-tête signifie que vous avez pris connaissance de la licence CeCILL, et que vous en avez accepté les termes (cf. le fichier Documentation/licence.fr.txt fourni avec ce logiciel). */ /* LICENCE SUM UP Copyright CEA, contributors : Damien CALISTE, laboratoire L_Sim, (2011-2011) E-mail address: CALISTE, damien P caliste AT cea P fr. This software is a computer program whose purpose is to visualize atomic configurations in 3D. This software is governed by the CeCILL license under French law and abiding by the rules of distribution of free software. You can use, modify and/ or redistribute the software under the terms of the CeCILL license as circulated by CEA, CNRS and INRIA at the following URL "http://www.cecill.info". The fact that you are presently reading this means that you have had knowledge of the CeCILL license and that you accept its terms. You can find a copy of this licence shipped with this software at Documentation/licence.en.txt. */ #include #include #include "gtk_fieldChooser.h" #include #include #include #include #include /** * SECTION:gtk_fieldChooser * @short_description: Defines a widget to choose a scalar field or an * isosurface. * * TODO. */ enum { VALIDATE_SIGNAL, LAST_SIGNAL }; static void visu_ui_field_chooser_dispose (GObject *obj); static void visu_ui_field_chooser_finalize(GObject *obj); struct _VisuUiFieldChooser { GtkFileChooserDialog dialog; GtkWidget *fitToBox, *fitToSurface, *fitNone; VisuScalarFieldMethod *validFormat; GList* allFilters; GtkWidget *vbox, *addWd; gchar *preFilename; /* Memory gestion. */ gboolean dispose_has_run; }; struct _VisuUiFieldChooserClass { GtkFileChooserDialogClass parent_class; }; /* Local callbacks */ static void onFieldChooserResponse(GtkDialog *dialog, gint id, gpointer *data); static guint visu_ui_field_chooser_signals[LAST_SIGNAL] = { 0 }; G_DEFINE_TYPE(VisuUiFieldChooser, visu_ui_field_chooser, GTK_TYPE_FILE_CHOOSER_DIALOG) static void visu_ui_field_chooser_class_init(VisuUiFieldChooserClass *klass) { DBG_fprintf(stderr, "VisuUi FieldChooser: creating the class of the widget.\n"); DBG_fprintf(stderr, " - adding new signals ;\n"); /** * VisuUiFieldChooser::validate: * @chooser: the object which emit the signal ; * @field: the chosen #VisuScalarField object. * * Gets emitted when the user choose a file and a format has been * validated for it. * * Since: 3.7 */ visu_ui_field_chooser_signals[VALIDATE_SIGNAL] = g_signal_new("validate", G_TYPE_FROM_CLASS(klass), G_SIGNAL_RUN_LAST | G_SIGNAL_NO_RECURSE, 0, NULL, NULL, g_cclosure_marshal_VOID__OBJECT, G_TYPE_NONE, 1, VISU_TYPE_SCALAR_FIELD_METHOD, NULL); G_OBJECT_CLASS(klass)->dispose = visu_ui_field_chooser_dispose; G_OBJECT_CLASS(klass)->finalize = visu_ui_field_chooser_finalize; } static void visu_ui_field_chooser_init(VisuUiFieldChooser *fieldChooser) { DBG_fprintf(stderr, "VisuUi FieldChooser: initializing new object (%p).\n", (gpointer)fieldChooser); fieldChooser->validFormat = (VisuScalarFieldMethod*)0; fieldChooser->allFilters = (GList*)0; fieldChooser->addWd = (GtkWidget*)0; fieldChooser->preFilename = g_strdup(""); g_signal_connect(G_OBJECT(fieldChooser), "response", G_CALLBACK(onFieldChooserResponse), (gpointer)fieldChooser); } static void visu_ui_field_chooser_dispose(GObject *obj) { DBG_fprintf(stderr, "VisuUi FieldChooser: dispose object %p.\n", (gpointer)obj); if (VISU_UI_FIELD_CHOOSER(obj)->dispose_has_run) return; VISU_UI_FIELD_CHOOSER(obj)->dispose_has_run = TRUE; /* Chain up to the parent class */ G_OBJECT_CLASS(visu_ui_field_chooser_parent_class)->dispose(obj); } static void visu_ui_field_chooser_finalize(GObject *obj) { VisuUiFieldChooser *dialog; GList *tmpLst; g_return_if_fail(obj); DBG_fprintf(stderr, "VisuUi FieldChooser: finalize object %p.\n", (gpointer)obj); dialog = VISU_UI_FIELD_CHOOSER(obj); for (tmpLst = dialog->allFilters; tmpLst; tmpLst = g_list_next(tmpLst)) g_free(tmpLst->data); g_list_free(dialog->allFilters); if (dialog->preFilename) g_free(dialog->preFilename); /* Chain up to the parent class */ G_OBJECT_CLASS(visu_ui_field_chooser_parent_class)->finalize(obj); DBG_fprintf(stderr, "VisuUi FieldChooser: freeing ... OK.\n"); } /** * visu_ui_field_chooser_new: * @parent: (allow-none): the parent window. * * Create a filechooser, specific for #VisuScalarField files. * * Since: 3.7 * * Returns: (transfer full): a newly created file chooser. **/ GtkWidget* visu_ui_field_chooser_new(GtkWindow *parent) { VisuUiFieldChooser *fieldChooser; const gchar *directory; GList *scalarMethods, *allMethods; const gchar *type[] = {"*.surf", (char*)0}; const gchar *descr = _("Isosurfaces files"); if (!parent) parent = visu_ui_getRenderWindow(); DBG_fprintf(stderr, "VisuUi FieldChooser: creating a new VisuUiFieldChooser object.\n"); fieldChooser = VISU_UI_FIELD_CHOOSER(g_object_new(VISU_TYPE_UI_FIELD_CHOOSER, NULL)); gtk_window_set_title(GTK_WINDOW(fieldChooser), _("Open a surface/density file")); /* This is to avoid a bug in gtk 2.4 */ #if GTK_MAJOR_VERSION > 2 || GTK_MINOR_VERSION > 5 gtk_window_set_modal(GTK_WINDOW(fieldChooser), TRUE); #endif gtk_window_set_transient_for(GTK_WINDOW(fieldChooser), GTK_WINDOW(parent)); gtk_window_set_position(GTK_WINDOW(fieldChooser), GTK_WIN_POS_CENTER_ON_PARENT); gtk_dialog_add_button(GTK_DIALOG(fieldChooser), TOOL_ICON_CANCEL, GTK_RESPONSE_CANCEL); gtk_dialog_add_button(GTK_DIALOG(fieldChooser), TOOL_ICON_OPEN, GTK_RESPONSE_ACCEPT); gtk_dialog_set_default_response(GTK_DIALOG(fieldChooser), GTK_RESPONSE_ACCEPT); directory = visu_ui_main_getLastOpenDirectory(visu_ui_main_class_getCurrentPanel()); if (directory) gtk_file_chooser_set_current_folder(GTK_FILE_CHOOSER(fieldChooser), directory); fieldChooser->fitNone = gtk_radio_button_new_with_label(NULL, _("Keep surface box as defined")); gtk_widget_set_tooltip_text(fieldChooser->fitNone, _("Don't modify the surface coordinates.")); fieldChooser->fitToBox = gtk_radio_button_new_with_label_from_widget (GTK_RADIO_BUTTON(fieldChooser->fitNone), _("Fit surfaces to box")); gtk_widget_set_tooltip_text(fieldChooser->fitToBox, _("Makes surfaces fit to the current" " loaded bounding box.")); fieldChooser->fitToSurface = gtk_radio_button_new_with_label_from_widget (GTK_RADIO_BUTTON(fieldChooser->fitToBox), _("Fit box to surfaces")); gtk_widget_set_tooltip_text(fieldChooser->fitToSurface, _("Makes the current bounding box fit" " to the surfaces.")); gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON(fieldChooser->fitNone), TRUE); fieldChooser->vbox = gtk_vbox_new(FALSE, 0); gtk_box_pack_start(GTK_BOX(fieldChooser->vbox), fieldChooser->fitNone, FALSE, FALSE, 0); gtk_box_pack_start(GTK_BOX(fieldChooser->vbox), fieldChooser->fitToBox, FALSE, FALSE, 0); gtk_box_pack_start(GTK_BOX(fieldChooser->vbox), fieldChooser->fitToSurface, FALSE, FALSE, 0); gtk_file_chooser_set_extra_widget(GTK_FILE_CHOOSER(fieldChooser), fieldChooser->vbox); allMethods = (GList*)0; allMethods = g_list_append(allMethods, tool_file_format_new(descr, type)); for (scalarMethods = visu_scalar_field_method_getAll(); scalarMethods; scalarMethods = g_list_next(scalarMethods)) allMethods = g_list_append(allMethods, TOOL_FILE_FORMAT(g_object_ref(scalarMethods->data))); fieldChooser->allFilters = visu_ui_createFilter(allMethods, GTK_WIDGET(fieldChooser)); g_list_free_full(allMethods, (GDestroyNotify)g_object_unref); gtk_widget_show_all(GTK_WIDGET(fieldChooser)); return GTK_WIDGET(fieldChooser); } /*******************/ /* Local callbacks */ /*******************/ static void onFieldChooserResponse(GtkDialog *dialog, gint id, gpointer *data _U_) { gchar *filename, *directory; VisuUiFieldChooser *fieldChooser; GList *scalarMethods; g_return_if_fail(VISU_IS_UI_FIELD_CHOOSER(dialog)); fieldChooser = VISU_UI_FIELD_CHOOSER(dialog); fieldChooser->validFormat = (VisuScalarFieldMethod*)0; DBG_fprintf(stderr, "VisuUi FieldChooser: catch the 'response' signal:" " %d (ACCEPT is %d).\n", id, GTK_RESPONSE_ACCEPT); if (id == GTK_RESPONSE_ACCEPT) { /* Get the filename. */ filename = gtk_file_chooser_get_filename(GTK_FILE_CHOOSER(fieldChooser)); if (!filename) { /* Autodetect failed, no format match the given filename */ visu_ui_raiseWarning(_("Opening a file"), _("No filename chosen."), GTK_WINDOW(dialog)); g_signal_stop_emission_by_name(G_OBJECT(dialog), "response"); return; } /* Get the directory. */ directory = (char*)gtk_file_chooser_get_current_folder(GTK_FILE_CHOOSER(fieldChooser)); visu_ui_main_setLastOpenDirectory(visu_ui_main_class_getCurrentPanel(), directory, VISU_UI_DIR_SURFACE); /* We test here the file format for formats that support poking. */ for (scalarMethods = visu_scalar_field_method_getAll(); scalarMethods; scalarMethods = g_list_next(scalarMethods)) if (tool_file_format_validate(TOOL_FILE_FORMAT(scalarMethods->data), filename)) break; if (scalarMethods && strcmp(fieldChooser->preFilename, filename)) { fieldChooser->validFormat = VISU_SCALAR_FIELD_METHOD(scalarMethods->data); /* Call hook in case we found a valid file format. */ DBG_fprintf(stderr, "VisuUi FieldChooser: '%s' is a valid %s format.\n", filename, tool_file_format_getName (TOOL_FILE_FORMAT(fieldChooser->validFormat))); g_signal_emit(G_OBJECT(fieldChooser), visu_ui_field_chooser_signals[VALIDATE_SIGNAL], 0, scalarMethods->data, NULL); } if (fieldChooser->preFilename) g_free(fieldChooser->preFilename); fieldChooser->preFilename = filename; } } /******************/ /* Public methods */ /******************/ /** * visu_ui_field_chooser_getFileFormat: * @dialog: a #VisuUiFieldChooser object. * * After the @dialog returns, it has validate the selected file on * possible file formats. * * Since: 3.7 * * Returns: (transfer none): the #VisuScalarFieldMethod that correspond to the selected file. **/ VisuScalarFieldMethod* visu_ui_field_chooser_getFileFormat(VisuUiFieldChooser *dialog) { g_return_val_if_fail(dialog, (VisuScalarFieldMethod*)0); return dialog->validFormat; } /** * visu_ui_field_chooser_getFit: * @dialog: a #VisuUiFieldChooser object. * * The #VisuScalarField objects can be fitted on the #visuData box or * impose their boxes to #VisuData. * * Since: 3.7 * * Returns: if the box should be fitted or not. **/ VisuUiBoxFit visu_ui_field_chooser_getFit(VisuUiFieldChooser *dialog) { g_return_val_if_fail(dialog, VISU_UI_FIT_TO_BOX); if (gtk_toggle_button_get_active(GTK_TOGGLE_BUTTON(dialog->fitNone))) return VISU_UI_NO_FIT; else if (gtk_toggle_button_get_active(GTK_TOGGLE_BUTTON(dialog->fitToBox))) return VISU_UI_FIT_TO_BOX; else if (gtk_toggle_button_get_active(GTK_TOGGLE_BUTTON(dialog->fitToSurface))) return VISU_UI_FIT_TO_SURFACE; else return VISU_UI_NO_FIT; } /** * visu_ui_field_chooser_setOptions: * @dialog: a #VisuUiFieldChooser object. * @wd: some additional options to add to the dialog. * * One can add widgets to add more options to the chooser. If the * chooser already has some option widgets, they are destroyed. * * Since: 3.7 **/ void visu_ui_field_chooser_setOptions(VisuUiFieldChooser *dialog, GtkWidget *wd) { g_return_if_fail(dialog); if (dialog->addWd) gtk_widget_destroy(dialog->addWd); /* Add the new widgets to provide additional options. */ dialog->addWd = wd; gtk_box_pack_end(GTK_BOX(dialog->vbox), wd, FALSE, FALSE, 0); gtk_widget_show_all(wd); /* Freeze the filechooser itself. */ /* Stop the response action. */ g_signal_stop_emission_by_name(G_OBJECT(dialog), "response"); } v_sim-3.8.0/src/extraGtkFunctions/gtk_fieldChooser.h000066400000000000000000000110331370110300500225200ustar00rootroot00000000000000/* EXTRAITS DE LA LICENCE Copyright CEA, contributeurs : Damien CALISTE, laboratoire L_Sim, (2011-2011) Adresse mèl : CALISTE, damien P caliste AT cea P fr. Ce logiciel est un programme informatique servant à visualiser des structures atomiques dans un rendu pseudo-3D. Ce logiciel est régi par la licence CeCILL soumise au droit français et respectant les principes de diffusion des logiciels libres. Vous pouvez utiliser, modifier et/ou redistribuer ce programme sous les conditions de la licence CeCILL telle que diffusée par le CEA, le CNRS et l'INRIA sur le site "http://www.cecill.info". Le fait que vous puissiez accéder à cet en-tête signifie que vous avez pris connaissance de la licence CeCILL, et que vous en avez accepté les termes (cf. le fichier Documentation/licence.fr.txt fourni avec ce logiciel). */ /* LICENCE SUM UP Copyright CEA, contributors : Damien CALISTE, laboratoire L_Sim, (2011-2011) E-mail address: CALISTE, damien P caliste AT cea P fr. This software is a computer program whose purpose is to visualize atomic configurations in 3D. This software is governed by the CeCILL license under French law and abiding by the rules of distribution of free software. You can use, modify and/ or redistribute the software under the terms of the CeCILL license as circulated by CEA, CNRS and INRIA at the following URL "http://www.cecill.info". The fact that you are presently reading this means that you have had knowledge of the CeCILL license and that you accept its terms. You can find a copy of this licence shipped with this software at Documentation/licence.en.txt. */ #ifndef GTK_FIELDCHOOSER_H #define GTK_FIELDCHOOSER_H #include #include #include G_BEGIN_DECLS /** * VISU_TYPE_UI_FIELD_CHOOSER: * * Return the associated #GType to the VisuUiFieldChooser objects. */ #define VISU_TYPE_UI_FIELD_CHOOSER (visu_ui_field_chooser_get_type ()) /** * VISU_UI_FIELD_CHOOSER: * @obj: the widget to cast. * * Cast the given object to a #VisuUiFieldChooser object. */ #define VISU_UI_FIELD_CHOOSER(obj) (G_TYPE_CHECK_INSTANCE_CAST ((obj), VISU_TYPE_UI_FIELD_CHOOSER, VisuUiFieldChooser)) /** * VISU_UI_FIELD_CHOOSER_CLASS: * @klass: the class to cast. * * Cast the given class to a #VisuUiFieldChooserClass object. */ #define VISU_UI_FIELD_CHOOSER_CLASS(klass) (G_TYPE_CHECK_CLASS_CAST ((klass), VISU_TYPE_UI_FIELD_CHOOSER, VisuUiFieldChooserClass)) /** * VISU_IS_UI_FIELD_CHOOSER: * @obj: the object to test. * * Return if the given object is a valid #VisuUiFieldChooser object. */ #define VISU_IS_UI_FIELD_CHOOSER(obj) (G_TYPE_CHECK_INSTANCE_TYPE ((obj), VISU_TYPE_UI_FIELD_CHOOSER)) /** * VISU_IS_UI_FIELD_CHOOSER_CLASS: * @klass: the class to test. * * Return if the given class is a valid #VisuUiFieldChooserClass class. */ #define VISU_IS_UI_FIELD_CHOOSER_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE ((klass), VISU_TYPE_UI_FIELD_CHOOSER)) /** * VISU_UI_FIELD_CHOOSER_GET_CLASS: * @obj: the widget to get the class of. * * Get the class of the given object. */ #define VISU_UI_FIELD_CHOOSER_GET_CLASS(obj) (G_TYPE_INSTANCE_GET_CLASS(obj, VISU_TYPE_UI_FIELD_CHOOSER, VisuUiFieldChooserClass)) /** * VisuUiFieldChooser * * Private structure to store informations of a #VisuUiFieldChooser object. */ typedef struct _VisuUiFieldChooser VisuUiFieldChooser; /** * VisuUiFieldChooserClass * * Private structure to store informations of a #VisuUiFieldChooserClass object. */ typedef struct _VisuUiFieldChooserClass VisuUiFieldChooserClass; /** * visu_ui_field_chooser_get_type * * #GType are unique numbers to identify objects. * * Returns: the #GType associated with #VisuUiFieldChooser objects. */ GType visu_ui_field_chooser_get_type (void); /** * VisuUiBoxFit: * @VISU_UI_NO_FIT: don't change the box. * @VISU_UI_FIT_TO_BOX: adapt the box of the field to the box of the * loaded #VisuData. * @VISU_UI_FIT_TO_SURFACE: adapt the box of the loaded #VisuData to * the box of the field. * * Possible value to adapt the boxes of structure and field. * * Since: 3.7 */ typedef enum { VISU_UI_NO_FIT, VISU_UI_FIT_TO_BOX, VISU_UI_FIT_TO_SURFACE } VisuUiBoxFit; GtkWidget* visu_ui_field_chooser_new(GtkWindow *parent); VisuScalarFieldMethod* visu_ui_field_chooser_getFileFormat(VisuUiFieldChooser *dialog); VisuUiBoxFit visu_ui_field_chooser_getFit(VisuUiFieldChooser *dialog); void visu_ui_field_chooser_setOptions(VisuUiFieldChooser *dialog, GtkWidget *wd); G_END_DECLS #endif v_sim-3.8.0/src/extraGtkFunctions/gtk_lineObjectWidget.c000066400000000000000000000574151370110300500233450ustar00rootroot00000000000000/* EXTRAITS DE LA LICENCE Copyright CEA, contributeurs : Luc BILLARD et Damien CALISTE, laboratoire L_Sim, (2001-2005) Adresse mèl : BILLARD, non joignable par mèl ; CALISTE, damien P caliste AT cea P fr. Ce logiciel est un programme informatique servant à visualiser des structures atomiques dans un rendu pseudo-3D. Ce logiciel est régi par la licence CeCILL soumise au droit français et respectant les principes de diffusion des logiciels libres. Vous pouvez utiliser, modifier et/ou redistribuer ce programme sous les conditions de la licence CeCILL telle que diffusée par le CEA, le CNRS et l'INRIA sur le site "http://www.cecill.info". Le fait que vous puissiez accéder à cet en-tête signifie que vous avez pris connaissance de la licence CeCILL, et que vous en avez accepté les termes (cf. le fichier Documentation/licence.fr.txt fourni avec ce logiciel). */ /* LICENCE SUM UP Copyright CEA, contributors : Luc BILLARD et Damien CALISTE, laboratoire L_Sim, (2001-2005) E-mail address: BILLARD, not reachable any more ; CALISTE, damien P caliste AT cea P fr. This software is a computer program whose purpose is to visualize atomic configurations in 3D. This software is governed by the CeCILL license under French law and abiding by the rules of distribution of free software. You can use, modify and/ or redistribute the software under the terms of the CeCILL license as circulated by CEA, CNRS and INRIA at the following URL "http://www.cecill.info". The fact that you are presently reading this means that you have had knowledge of the CeCILL license and that you accept its terms. You can find a copy of this licence shipped with this software at Documentation/licence.en.txt. */ #include #include #include "gtk_lineObjectWidget.h" #include "gtk_stippleComboBoxWidget.h" #include "gtk_colorComboBoxWidget.h" #include /** * SECTION:gtk_lineObjectWidget * @short_description: Defines a specialised #GtkBox to choose * all characteristic of lines. * @see_also: #VisuUiColorCombobox and #VisuUiStippleCombobox * * * * Since: 3.4 */ enum { LINE_USE_CHANGED_SIGNAL, LINE_WIDTH_CHANGED_SIGNAL, LINE_STIPPLE_CHANGED_SIGNAL, LINE_COLOR_CHANGED_SIGNAL, LAST_SIGNAL }; enum { PROP_0, LABEL_PROP, COLOR_PROP, N_PROP }; static GParamSpec *properties[N_PROP]; static void visu_ui_line_dispose (GObject *obj); static void visu_ui_line_finalize(GObject *obj); static void visu_ui_line_get_property(GObject* obj, guint property_id, GValue *value, GParamSpec *pspec); static void visu_ui_line_set_property(GObject* obj, guint property_id, const GValue *value, GParamSpec *pspec); static guint visu_ui_line_signals[LAST_SIGNAL] = { 0 }; /** * VisuUiLine: * * Private structure to store informations of a #VisuUiLine object. * * Since: 3.4 */ /** * VisuUiLinePrivate: * * Private data. */ struct _VisuUiLinePrivate { GtkWidget *expand; GtkWidget *label; GtkWidget *used; GtkWidget *width; GtkWidget *stipple; GtkWidget *rgRGB[3]; GtkWidget *color; GtkWidget *btColor; gulong rgSignals[3]; gulong colorSignal; /* Binding to a VisuGlExt object. */ VisuGlExtLined *model; GBinding *bind_active, *bind_width, *bind_stipple, *bind_color; /* Memory gestion. */ gboolean dispose_has_run; }; /* Local callbacks. */ static void onUseChanged(GtkCheckButton *check, VisuUiLine *line); static void onWidthChanged(GtkSpinButton *spin, VisuUiLine *line); static void onStippleChanged(VisuUiStippleCombobox *wd, guint stipple, VisuUiLine *line); static void onRGBValueChanged(GtkRange *rg, VisuUiLine *line); static void onAddClicked(GtkButton *bt, VisuUiLine *line); static void onColorChanged(VisuUiColorCombobox *combo, ToolColor *color, VisuUiLine *line); /* Local methods. */ /** * visu_ui_line_get_type * * #GType are unique numbers to identify objects. * * Returns: the #GType associated with #VisuUiLine objects. * * Since: 3.4 */ G_DEFINE_TYPE_WITH_CODE(VisuUiLine, visu_ui_line, GTK_TYPE_BOX, G_ADD_PRIVATE(VisuUiLine)) static void visu_ui_line_class_init(VisuUiLineClass *klass) { DBG_fprintf(stderr, "Gtk VisuUiLine: creating the class of the widget.\n"); DBG_fprintf(stderr, " - adding new signals ;\n"); /** * VisuUiLine::use-changed: * @line: the #VisuUiLine that emits the signal ; * @used: TRUE if the line is used. * * This signal is emitted when the usage check box is changed. * * Since: 3.4 */ visu_ui_line_signals[LINE_USE_CHANGED_SIGNAL] = g_signal_new ("use-changed", G_TYPE_FROM_CLASS (klass), G_SIGNAL_RUN_FIRST | G_SIGNAL_ACTION, G_STRUCT_OFFSET (VisuUiLineClass, lineObject), NULL, NULL, g_cclosure_marshal_VOID__BOOLEAN, G_TYPE_NONE, 1, G_TYPE_BOOLEAN); /** * VisuUiLine::width-changed: * @line: the #VisuUiLine that emits the signal ; * @width: the new width. * * This signal is emitted when the width of the line is changed. * * Since: 3.4 */ visu_ui_line_signals[LINE_WIDTH_CHANGED_SIGNAL] = g_signal_new ("width-changed", G_TYPE_FROM_CLASS (klass), G_SIGNAL_RUN_FIRST | G_SIGNAL_ACTION, G_STRUCT_OFFSET (VisuUiLineClass, lineObject), NULL, NULL, g_cclosure_marshal_VOID__INT, G_TYPE_NONE, 1, G_TYPE_INT); /** * VisuUiLine::stipple-changed: * @line: the #VisuUiLine that emits the signal ; * @stipple: the new stipple pattern. * * This signal is emitted when the stipple pattern of the line is changed. * * Since: 3.4 */ visu_ui_line_signals[LINE_STIPPLE_CHANGED_SIGNAL] = g_signal_new ("stipple-changed", G_TYPE_FROM_CLASS (klass), G_SIGNAL_RUN_FIRST | G_SIGNAL_ACTION, G_STRUCT_OFFSET (VisuUiLineClass, lineObject), NULL, NULL, g_cclosure_marshal_VOID__UINT, G_TYPE_NONE, 1, G_TYPE_UINT); /** * VisuUiLine::color-changed: * @line: the #VisuUiLine that emits the signal ; * @color: the new color values (three RGB values). * * This signal is emitted when the colour of the line is changed. * * Since: 3.4 */ visu_ui_line_signals[LINE_COLOR_CHANGED_SIGNAL] = g_signal_new ("color-changed", G_TYPE_FROM_CLASS (klass), G_SIGNAL_RUN_FIRST | G_SIGNAL_ACTION, G_STRUCT_OFFSET (VisuUiLineClass, lineObject), NULL, NULL, g_cclosure_marshal_VOID__POINTER, G_TYPE_NONE, 1, G_TYPE_POINTER); /* Connect freeing methods. */ G_OBJECT_CLASS(klass)->dispose = visu_ui_line_dispose; G_OBJECT_CLASS(klass)->finalize = visu_ui_line_finalize; G_OBJECT_CLASS(klass)->set_property = visu_ui_line_set_property; G_OBJECT_CLASS(klass)->get_property = visu_ui_line_get_property; /** * VisuUiLine::label: * * Store the label. * * Since: 3.8 */ properties[LABEL_PROP] = g_param_spec_string("label", "line label", "displayed label on the expander", "parameters", G_PARAM_WRITABLE | G_PARAM_CONSTRUCT); g_object_class_install_property(G_OBJECT_CLASS(klass), LABEL_PROP, properties[LABEL_PROP]); /** * VisuUiLine::color: * * Store the current color. * * Since: 3.8 */ properties[COLOR_PROP] = g_param_spec_boxed("color", "line color", "selected color", TOOL_TYPE_COLOR, G_PARAM_READWRITE); g_object_class_install_property(G_OBJECT_CLASS(klass), COLOR_PROP, properties[COLOR_PROP]); } static void visu_ui_line_dispose(GObject *obj) { DBG_fprintf(stderr, "Gtk VisuUiLine: dispose object %p.\n", (gpointer)obj); if (VISU_UI_LINE(obj)->priv->dispose_has_run) return; visu_ui_line_bind(VISU_UI_LINE(obj), (VisuGlExtLined*)0); VISU_UI_LINE(obj)->priv->dispose_has_run = TRUE; /* Chain up to the parent class */ G_OBJECT_CLASS(visu_ui_line_parent_class)->dispose(obj); } static void visu_ui_line_finalize(GObject *obj) { g_return_if_fail(obj); DBG_fprintf(stderr, "Gtk VisuUiLine: finalize object %p.\n", (gpointer)obj); /* Chain up to the parent class */ G_OBJECT_CLASS(visu_ui_line_parent_class)->finalize(obj); DBG_fprintf(stderr, " | freeing ... OK.\n"); } static void visu_ui_line_get_property(GObject* obj, guint property_id, GValue *value, GParamSpec *pspec) { float rgba[4]; VisuUiLine *self = VISU_UI_LINE(obj); DBG_fprintf(stderr, "Gtk VisuUiLine: get property '%s' -> ", g_param_spec_get_name(pspec)); switch (property_id) { case COLOR_PROP: rgba[0] = gtk_range_get_value(GTK_RANGE(self->priv->rgRGB[0])); rgba[1] = gtk_range_get_value(GTK_RANGE(self->priv->rgRGB[1])); rgba[2] = gtk_range_get_value(GTK_RANGE(self->priv->rgRGB[2])); rgba[3] = 1.f; g_value_take_boxed(value, tool_color_new(rgba)); DBG_fprintf(stderr, "%gx%gx%g.\n", rgba[0], rgba[1], rgba[2]); break; default: /* We don't have any other property... */ G_OBJECT_WARN_INVALID_PROPERTY_ID(obj, property_id, pspec); break; } } static void visu_ui_line_set_property(GObject* obj, guint property_id, const GValue *value, GParamSpec *pspec) { ToolColor *color; gchar *markup; VisuUiLine *self = VISU_UI_LINE(obj); DBG_fprintf(stderr, "Gtk VisuUiLine: set property '%s' -> ", g_param_spec_get_name(pspec)); switch (property_id) { case LABEL_PROP: markup = g_markup_printf_escaped("%s", g_value_get_string(value)); gtk_label_set_markup(GTK_LABEL(self->priv->label), markup); DBG_fprintf(stderr, "%s.\n", markup); g_free(markup); break; case COLOR_PROP: color = (ToolColor*)g_value_get_boxed(value); visu_ui_line_setColor(self, color->rgba); DBG_fprintf(stderr, "%gx%gx%g.\n", color->rgba[0], color->rgba[1], color->rgba[2]); break; default: /* We don't have any other property... */ G_OBJECT_WARN_INVALID_PROPERTY_ID(obj, property_id, pspec); break; } } static void visu_ui_line_init(VisuUiLine *line) { GtkWidget *vbox, *hbox, *label, *table; char *rgb[3]; char *rgbName[3] = {"scroll_r", "scroll_g", "scroll_b"}; int i; DBG_fprintf(stderr, "Gtk VisuUiLine: initializing new object (%p).\n", (gpointer)line); line->priv = visu_ui_line_get_instance_private(line); line->priv->model = (VisuGlExtLined*)0; gtk_orientable_set_orientation(GTK_ORIENTABLE(line), GTK_ORIENTATION_VERTICAL); gtk_box_set_spacing(GTK_BOX(line), 5); /********************/ /* The header line. */ /********************/ hbox = gtk_hbox_new(FALSE, 0); gtk_box_pack_start(GTK_BOX(line), hbox, FALSE, FALSE, 0); /* The drawn checkbox. */ line->priv->used = gtk_check_button_new(); gtk_widget_set_valign(line->priv->used, GTK_ALIGN_START); gtk_box_pack_start(GTK_BOX(hbox), line->priv->used, FALSE, FALSE, 0); g_signal_connect(G_OBJECT(line->priv->used), "toggled", G_CALLBACK(onUseChanged), (gpointer)line); /* The expander. */ line->priv->expand = gtk_expander_new("");\ gtk_widget_set_margin_start(line->priv->expand, 5); gtk_box_pack_start(GTK_BOX(hbox), line->priv->expand, TRUE, TRUE, 0); /* The label. */ hbox = gtk_hbox_new(FALSE, 30); line->priv->label = gtk_label_new(""); gtk_widget_set_name(line->priv->label, "label_head"); gtk_box_pack_start(GTK_BOX(hbox), line->priv->label, TRUE, FALSE, 0); label = gtk_label_new(_("" "expand for options")); gtk_label_set_use_markup(GTK_LABEL(label), TRUE); gtk_box_pack_end(GTK_BOX(hbox), label, FALSE, FALSE, 0); gtk_expander_set_label_widget(GTK_EXPANDER(line->priv->expand), hbox); /* The insider. */ vbox = gtk_vbox_new(FALSE, 2); gtk_container_add(GTK_CONTAINER(line->priv->expand), vbox); /*******************/ /* The scale line. */ /*******************/ hbox = gtk_hbox_new(FALSE, 0); gtk_box_pack_start(GTK_BOX(vbox), hbox, FALSE, FALSE, 0); /* The label. */ label = gtk_label_new(_("Line style:")); gtk_label_set_xalign(GTK_LABEL(label), 0.); gtk_box_pack_start(GTK_BOX(hbox), label, TRUE, TRUE, 0); /* The scale width spin button. */ label = gtk_label_new(_("width:")); gtk_widget_set_margin_start(label, 5); gtk_box_pack_start(GTK_BOX(hbox), label, FALSE, FALSE, 0); line->priv->width = gtk_spin_button_new_with_range(1., 10., 1.); gtk_entry_set_width_chars(GTK_ENTRY(line->priv->width), 2); gtk_box_pack_start(GTK_BOX(hbox), line->priv->width, FALSE, FALSE, 0); g_signal_connect(G_OBJECT(line->priv->width), "value-changed", G_CALLBACK(onWidthChanged), (gpointer)line); /* px for pixel. */ label = gtk_label_new(_("px")); gtk_box_pack_start(GTK_BOX(hbox), label, FALSE, FALSE, 2); /* The stipple pattern. */ line->priv->stipple = visu_ui_stipple_combobox_new(); gtk_widget_set_margin_start(line->priv->stipple, 5); gtk_widget_set_hexpand(line->priv->stipple, FALSE); gtk_widget_set_halign(line->priv->stipple, GTK_ALIGN_END); gtk_box_pack_start(GTK_BOX(hbox), line->priv->stipple, TRUE, TRUE, 0); g_signal_connect(G_OBJECT(line->priv->stipple), "stipple-selected", G_CALLBACK(onStippleChanged), (gpointer)line); /********************/ /* The colour line. */ /********************/ hbox = gtk_hbox_new(FALSE, 10); gtk_box_pack_start(GTK_BOX(vbox), hbox, FALSE, FALSE, 0); /* The table for the box colour. */ table = gtk_grid_new(); tool_grid_resize(table, 3, 2); gtk_box_pack_end(GTK_BOX(hbox), table, TRUE, TRUE, 0); rgb[0] = _("R:"); rgb[1] = _("G:"); rgb[2] = _("B:"); for (i = 0; i < 3; i++) { label = gtk_label_new(rgb[i]); gtk_grid_attach(GTK_GRID(table), label, 0, i, 1, 1); line->priv->rgRGB[i] = gtk_hscale_new_with_range(0., 1., 0.001); gtk_widget_set_hexpand(line->priv->rgRGB[i], TRUE); gtk_scale_set_value_pos(GTK_SCALE(line->priv->rgRGB[i]), GTK_POS_RIGHT); gtk_range_set_value(GTK_RANGE(line->priv->rgRGB[i]), 0.741456963); gtk_widget_set_name(line->priv->rgRGB[i], rgbName[i]); gtk_grid_attach(GTK_GRID(table), line->priv->rgRGB[i], 1, i, 1, 1); line->priv->rgSignals[i] = g_signal_connect(G_OBJECT(line->priv->rgRGB[i]), "value-changed", G_CALLBACK(onRGBValueChanged), (gpointer)line); } vbox = gtk_vbox_new(FALSE, 0); gtk_box_pack_start(GTK_BOX(hbox), vbox, FALSE, FALSE, 0); label = gtk_label_new(_("color:")); line->priv->color = visu_ui_color_combobox_new(FALSE); line->priv->colorSignal = g_signal_connect(G_OBJECT(line->priv->color), "color-selected", G_CALLBACK(onColorChanged), (gpointer)line); gtk_label_set_xalign(GTK_LABEL(label), 0.); gtk_box_pack_start(GTK_BOX(vbox), label, FALSE, FALSE, 0); hbox = gtk_hbox_new(FALSE, 0); gtk_box_pack_start(GTK_BOX(vbox), hbox, FALSE, FALSE, 0); visu_ui_color_combobox_setPrintValues(VISU_UI_COLOR_COMBOBOX(line->priv->color), FALSE); gtk_box_pack_start(GTK_BOX(hbox), line->priv->color, FALSE, FALSE, 0); line->priv->btColor = gtk_button_new(); gtk_box_pack_end(GTK_BOX(hbox), line->priv->btColor, FALSE, FALSE, 0); gtk_container_add(GTK_CONTAINER(line->priv->btColor), gtk_image_new_from_icon_name("go-previous", GTK_ICON_SIZE_MENU)); label = gtk_label_new(_("(preset)")); gtk_label_set_use_markup(GTK_LABEL(label), TRUE); gtk_label_set_xalign(GTK_LABEL(label), 1.); gtk_box_pack_start(GTK_BOX(vbox), label, FALSE, FALSE, 0); g_signal_connect(G_OBJECT(line->priv->btColor), "clicked", G_CALLBACK(onAddClicked), (gpointer)line); gtk_widget_show_all(GTK_WIDGET(line)); } /** * visu_ui_line_new : * @label: the name of the group, output in bold. * * A #VisuUiLine widget is a widget allowing to choose the * properties of a line. These properties are the line stipple * pattern, its colour and its width. The colour is available through * #GtkRange and with a #VisuUiColorCombobox widget. There is also a * checkbox allowing to turn the line on or off. * * Returns: (transfer full): a newly created #VisuUiLine widget. * * Since: 3.4 */ GtkWidget* visu_ui_line_new(const gchar* label) { DBG_fprintf(stderr, "Gtk VisuUiLine: creating new object.\n"); return GTK_WIDGET(g_object_new(visu_ui_line_get_type(), "label", label, NULL)); } /** * visu_ui_line_bind: * @line: a #VisuUiLine object. * @model: (transfer none): a #VisuGlExtLined object. * * Bind the properties of @model to be displayed by @line. * * Since: 3.8 **/ void visu_ui_line_bind(VisuUiLine *line, VisuGlExtLined *model) { g_return_if_fail(VISU_IS_UI_LINE(line)); if (line->priv->model) { g_object_unref(G_OBJECT(line->priv->bind_active)); g_object_unref(G_OBJECT(line->priv->bind_width)); g_object_unref(G_OBJECT(line->priv->bind_stipple)); g_object_unref(G_OBJECT(line->priv->bind_color)); g_object_unref(G_OBJECT(line->priv->model)); } line->priv->model = model; if (model) { g_object_ref(G_OBJECT(model)); line->priv->bind_active = g_object_bind_property(model, "active", line->priv->used, "active", G_BINDING_BIDIRECTIONAL | G_BINDING_SYNC_CREATE); line->priv->bind_width = g_object_bind_property(model, "width", line->priv->width, "value", G_BINDING_BIDIRECTIONAL | G_BINDING_SYNC_CREATE); line->priv->bind_stipple = g_object_bind_property(model, "stipple", line->priv->stipple, "value", G_BINDING_BIDIRECTIONAL | G_BINDING_SYNC_CREATE); line->priv->bind_color = g_object_bind_property(model, "color", line, "color", G_BINDING_BIDIRECTIONAL | G_BINDING_SYNC_CREATE); } } static void onUseChanged(GtkCheckButton *check, VisuUiLine *line) { g_signal_emit(G_OBJECT(line), visu_ui_line_signals[LINE_USE_CHANGED_SIGNAL], 0, gtk_toggle_button_get_active(GTK_TOGGLE_BUTTON(check)), NULL); } static void onWidthChanged(GtkSpinButton *spin, VisuUiLine *line) { g_signal_emit(G_OBJECT(line), visu_ui_line_signals[LINE_WIDTH_CHANGED_SIGNAL], 0, (gint)gtk_spin_button_get_value(GTK_SPIN_BUTTON(spin)), NULL); } static void onStippleChanged(VisuUiStippleCombobox *wd _U_, guint stipple, VisuUiLine *line) { g_signal_emit(G_OBJECT(line), visu_ui_line_signals[LINE_STIPPLE_CHANGED_SIGNAL], 0, stipple, NULL); } static void onRGBValueChanged(GtkRange *rg _U_, VisuUiLine *line) { float rgba[4]; int i; g_return_if_fail(VISU_IS_UI_LINE(line)); rgba[0] = gtk_range_get_value(GTK_RANGE(line->priv->rgRGB[0])); rgba[1] = gtk_range_get_value(GTK_RANGE(line->priv->rgRGB[1])); rgba[2] = gtk_range_get_value(GTK_RANGE(line->priv->rgRGB[2])); rgba[3] = 1.f; tool_color_getByValues(&i, rgba[0], rgba[1], rgba[2], rgba[3]); g_signal_handler_block(G_OBJECT(line->priv->color), line->priv->colorSignal); if (i < 0) gtk_combo_box_set_active(GTK_COMBO_BOX(line->priv->color), -1); else gtk_combo_box_set_active(GTK_COMBO_BOX(line->priv->color), i + 1); g_signal_handler_unblock(G_OBJECT(line->priv->color), line->priv->colorSignal); gtk_widget_set_sensitive(line->priv->btColor, (i < 0)); g_object_notify_by_pspec(G_OBJECT(line), properties[COLOR_PROP]); g_signal_emit(G_OBJECT(line), visu_ui_line_signals[LINE_COLOR_CHANGED_SIGNAL], 0, (gpointer)rgba, NULL); } static void onAddClicked(GtkButton *bt _U_, VisuUiLine *line) { float rgba[4]; int selected; g_return_if_fail(VISU_IS_UI_LINE(line)); DBG_fprintf(stderr, "Gtk VisuUiLine: adding a new color from ranges.\n"); rgba[0] = gtk_range_get_value(GTK_RANGE(line->priv->rgRGB[0])); rgba[1] = gtk_range_get_value(GTK_RANGE(line->priv->rgRGB[1])); rgba[2] = gtk_range_get_value(GTK_RANGE(line->priv->rgRGB[2])); rgba[3] = 1.f; tool_color_addFloatRGBA(rgba, &selected); g_signal_handler_block(G_OBJECT(line->priv->color), line->priv->colorSignal); gtk_combo_box_set_active(GTK_COMBO_BOX(line->priv->color), selected); g_signal_handler_unblock(G_OBJECT(line->priv->color), line->priv->colorSignal); gtk_widget_set_sensitive(line->priv->btColor, FALSE); } static void onColorChanged(VisuUiColorCombobox *combo _U_, ToolColor *color, VisuUiLine *line) { visu_ui_line_setColor(line, color->rgba); } /** * visu_ui_line_setUsed: * @line: the object to modify ; * @status: a boolean. * * The line can be turn on or off, call this routine to change the * interface status. * * Since: 3.4 */ void visu_ui_line_setUsed(VisuUiLine *line, gboolean status) { g_return_if_fail(VISU_IS_UI_LINE(line)); gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON(line->priv->used), status); } /** * visu_ui_line_setWidth: * @line: the object to modify ; * @width: a value. * * The line can be drawn with a given width, call this routine to change the * interface value. * * Since: 3.4 */ void visu_ui_line_setWidth(VisuUiLine *line, gint width) { g_return_if_fail(VISU_IS_UI_LINE(line) && width > 0 && width < 11); gtk_spin_button_set_value(GTK_SPIN_BUTTON(line->priv->width), (gdouble)width); } /** * visu_ui_line_setColor: * @line: the object to modify ; * @rgb: a RGB array. * * The line can is drawn in a given colour. Change the interface * values using this routine. The colour ranges are updated and if it * correspond to a registered colour, it is selected in the combobox. * * Since: 3.4 */ void visu_ui_line_setColor(VisuUiLine *line, float rgb[3]) { gboolean change; g_return_if_fail(VISU_IS_UI_LINE(line)); g_signal_handler_block(G_OBJECT(line->priv->rgRGB[0]), line->priv->rgSignals[0]); g_signal_handler_block(G_OBJECT(line->priv->rgRGB[1]), line->priv->rgSignals[1]); g_signal_handler_block(G_OBJECT(line->priv->rgRGB[2]), line->priv->rgSignals[2]); change = FALSE; if ((float)gtk_range_get_value(GTK_RANGE(line->priv->rgRGB[0])) != rgb[0]) { change = TRUE; gtk_range_set_value(GTK_RANGE(line->priv->rgRGB[0]), rgb[0]); } if ((float)gtk_range_get_value(GTK_RANGE(line->priv->rgRGB[1])) != rgb[1]) { change = TRUE; gtk_range_set_value(GTK_RANGE(line->priv->rgRGB[1]), rgb[1]); } if ((float)gtk_range_get_value(GTK_RANGE(line->priv->rgRGB[2])) != rgb[2]) { change = TRUE; gtk_range_set_value(GTK_RANGE(line->priv->rgRGB[2]), rgb[2]); } g_signal_handler_unblock(G_OBJECT(line->priv->rgRGB[0]), line->priv->rgSignals[0]); g_signal_handler_unblock(G_OBJECT(line->priv->rgRGB[1]), line->priv->rgSignals[1]); g_signal_handler_unblock(G_OBJECT(line->priv->rgRGB[2]), line->priv->rgSignals[2]); if (change) onRGBValueChanged((GtkRange*)0, line); } /** * visu_ui_line_setStipple: * @line: the object to modify ; * @stipple: a value. * * The line can be drawn with a given stipple pattern, call this * routine to change the interface value. * * Since: 3.4 */ void visu_ui_line_setStipple(VisuUiLine *line, guint16 stipple) { g_return_if_fail(VISU_IS_UI_LINE(line)); visu_ui_stipple_combobox_set(VISU_UI_STIPPLE_COMBOBOX(line->priv->stipple), stipple); } /** * visu_ui_line_getOptionBox: * @line: the object to get the GtkVBox. * * Give access to the #GtkVBox of the expander. * * Since: 3.6 * * Returns: (transfer none): a #GtkWidget. */ GtkWidget* visu_ui_line_getOptionBox(VisuUiLine *line) { g_return_val_if_fail(VISU_IS_UI_LINE(line), (GtkWidget*)0); return gtk_bin_get_child(GTK_BIN(line->priv->expand)); } v_sim-3.8.0/src/extraGtkFunctions/gtk_lineObjectWidget.h000066400000000000000000000076651370110300500233540ustar00rootroot00000000000000/* EXTRAITS DE LA LICENCE Copyright CEA, contributeurs : Luc BILLARD et Damien CALISTE, laboratoire L_Sim, (2001-2005) Adresse mèl : BILLARD, non joignable par mèl ; CALISTE, damien P caliste AT cea P fr. Ce logiciel est un programme informatique servant à visualiser des structures atomiques dans un rendu pseudo-3D. Ce logiciel est régi par la licence CeCILL soumise au droit français et respectant les principes de diffusion des logiciels libres. Vous pouvez utiliser, modifier et/ou redistribuer ce programme sous les conditions de la licence CeCILL telle que diffusée par le CEA, le CNRS et l'INRIA sur le site "http://www.cecill.info". Le fait que vous puissiez accéder à cet en-tête signifie que vous avez pris connaissance de la licence CeCILL, et que vous en avez accepté les termes (cf. le fichier Documentation/licence.fr.txt fourni avec ce logiciel). */ /* LICENCE SUM UP Copyright CEA, contributors : Luc BILLARD et Damien CALISTE, laboratoire L_Sim, (2001-2005) E-mail address: BILLARD, not reachable any more ; CALISTE, damien P caliste AT cea P fr. This software is a computer program whose purpose is to visualize atomic configurations in 3D. This software is governed by the CeCILL license under French law and abiding by the rules of distribution of free software. You can use, modify and/ or redistribute the software under the terms of the CeCILL license as circulated by CEA, CNRS and INRIA at the following URL "http://www.cecill.info". The fact that you are presently reading this means that you have had knowledge of the CeCILL license and that you accept its terms. You can find a copy of this licence shipped with this software at Documentation/licence.en.txt. */ #ifndef GTK_LINEOBJECTWIDGET_H #define GTK_LINEOBJECTWIDGET_H #include #include #include #include #include G_BEGIN_DECLS /** * VISU_TYPE_UI_LINE: * * Get the associated #GType to the VisuUiLine objects. * * Since: 3.4 */ #define VISU_TYPE_UI_LINE (visu_ui_line_get_type ()) /** * VISU_UI_LINE: * @obj: the widget to cast. * * Cast the given object to a #VisuUiLine object. * * Since: 3.4 */ #define VISU_UI_LINE(obj) (G_TYPE_CHECK_INSTANCE_CAST ((obj), VISU_TYPE_UI_LINE, VisuUiLine)) /** * VISU_UI_LINE_CLASS: * @klass: the class to cast. * * Cast the given class to a #VisuUiLineClass object. * * Since: 3.4 */ #define VISU_UI_LINE_CLASS(klass) (G_TYPE_CHECK_CLASS_CAST ((klass), VISU_TYPE_UI_LINE, VisuUiLineClass)) /** * VISU_IS_UI_LINE: * @obj: the object to test. * * Get if the given object is a valid #VisuUiLine object. * * Since: 3.4 */ #define VISU_IS_UI_LINE(obj) (G_TYPE_CHECK_INSTANCE_TYPE ((obj), VISU_TYPE_UI_LINE)) /** * VISU_IS_UI_LINE_CLASS: * @klass: the class to test. * * Get if the given class is a valid #VisuUiLineClass class. * * Since: 3.4 */ #define VISU_IS_UI_LINE_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE ((klass), VISU_TYPE_UI_LINE)) typedef struct _VisuUiLine VisuUiLine; typedef struct _VisuUiLineClass VisuUiLineClass; typedef struct _VisuUiLinePrivate VisuUiLinePrivate; GType visu_ui_line_get_type(void); struct _VisuUiLine { GtkBox box; VisuUiLinePrivate *priv; }; /** * VisuUiLineClass: * @parent_class: private * @lineObject: to be removed. * * Private structure to store informations of a #VisuUiLineClass object. * * Since: 3.4 */ struct _VisuUiLineClass { GtkBoxClass parent_class; void (*lineObject) (VisuUiLine *box); }; GtkWidget* visu_ui_line_new(const gchar *label); void visu_ui_line_bind(VisuUiLine *line, VisuGlExtLined *model); void visu_ui_line_setUsed(VisuUiLine *line, gboolean status); void visu_ui_line_setWidth(VisuUiLine *line, gint width); void visu_ui_line_setColor(VisuUiLine *line, float rgb[3]); void visu_ui_line_setStipple(VisuUiLine *line, guint16 stipple); GtkWidget* visu_ui_line_getOptionBox(VisuUiLine *line); G_END_DECLS #endif v_sim-3.8.0/src/extraGtkFunctions/gtk_numericalEntryWidget.c000066400000000000000000000272261370110300500242650ustar00rootroot00000000000000/* EXTRAITS DE LA LICENCE Copyright CEA, contributeurs : Luc BILLARD et Damien CALISTE, laboratoire L_Sim, (2001-2005) Adresse mèl : BILLARD, non joignable par mèl ; CALISTE, damien P caliste AT cea P fr. Ce logiciel est un programme informatique servant à visualiser des structures atomiques dans un rendu pseudo-3D. Ce logiciel est régi par la licence CeCILL soumise au droit français et respectant les principes de diffusion des logiciels libres. Vous pouvez utiliser, modifier et/ou redistribuer ce programme sous les conditions de la licence CeCILL telle que diffusée par le CEA, le CNRS et l'INRIA sur le site "http://www.cecill.info". Le fait que vous puissiez accéder à cet en-tête signifie que vous avez pris connaissance de la licence CeCILL, et que vous en avez accepté les termes (cf. le fichier Documentation/licence.fr.txt fourni avec ce logiciel). */ /* LICENCE SUM UP Copyright CEA, contributors : Luc BILLARD et Damien CALISTE, laboratoire L_Sim, (2001-2005) E-mail address: BILLARD, not reachable any more ; CALISTE, damien P caliste AT cea P fr. This software is a computer program whose purpose is to visualize atomic configurations in 3D. This software is governed by the CeCILL license under French law and abiding by the rules of distribution of free software. You can use, modify and/ or redistribute the software under the terms of the CeCILL license as circulated by CEA, CNRS and INRIA at the following URL "http://www.cecill.info". The fact that you are presently reading this means that you have had knowledge of the CeCILL license and that you accept its terms. You can find a copy of this licence shipped with this software at Documentation/licence.en.txt. */ #include #include "gtk_numericalEntryWidget.h" /** * SECTION:gtk_numericalEntryWidget * @short_description: Defines a widget to enter numerical values without * any boundary or precision constrains. * * This widget is based on the #GtkEntry widget but behaves more * like a #GtkSpinButton is fact. It is designed to enter numerical * values, but without any boundary or precision constrains. One can * use either plain or scientific notations. */ enum { VALUE_CHANGED_SIGNAL, LAST_SIGNAL }; static guint _signals[LAST_SIGNAL] = { 0 }; enum { PROP_0, VALUE_PROP, N_PROP }; static GParamSpec *properties[N_PROP]; #define VISU_UI_NUMERICAL_ENTRY_FORMAT_DEFAULT "%g" struct _VisuUiNumericalEntry { GtkEntry entry; double value; double printed_value; gchar *format; /* VisuUiNumericalEntryPrivate *private; */ }; struct _VisuUiNumericalEntryClass { GtkEntryClass parent_class; void (*changed) (VisuUiNumericalEntry *numEntry, double oldValue); }; static void visu_ui_numerical_entry_finalize(GObject *obj); static void visu_ui_numerical_entry_get_property(GObject* obj, guint property_id, GValue *value, GParamSpec *pspec); static void visu_ui_numerical_entry_set_property(GObject* obj, guint property_id, const GValue *value, GParamSpec *pspec); static gboolean visu_ui_numerical_entry_focus_in(GtkWidget *wd, GdkEventFocus *event); static gboolean visu_ui_numerical_entry_focus_out(GtkWidget *wd, GdkEventFocus *event); static void visu_ui_numerical_entry_activate(GtkEntry *entry); G_DEFINE_TYPE(VisuUiNumericalEntry, visu_ui_numerical_entry, GTK_TYPE_ENTRY) /* Local methods. */ static void printStoredValue(VisuUiNumericalEntry* numericalEntry); static gboolean parsePrintedValue(VisuUiNumericalEntry *numericalEntry, double *value); static void visu_ui_numerical_entry_class_init(VisuUiNumericalEntryClass *klass) { DBG_fprintf(stderr, "Gtk VisuUiNumericalEntry : creating the class of the widget.\n"); DBG_fprintf(stderr, " - adding new signals ;\n"); /** * VisuUiNumericalEntry::value-changed: * @entry: the #VisuUiNumericalEntry that emits the signal ; * @oldValue: the previous value. * * This signal is emitted when a new valid numerical value is entered. * * Since: 3.1 */ _signals[VALUE_CHANGED_SIGNAL] = g_signal_new ("value-changed", G_TYPE_FROM_CLASS (klass), G_SIGNAL_RUN_FIRST | G_SIGNAL_ACTION, G_STRUCT_OFFSET (VisuUiNumericalEntryClass, changed), NULL, NULL, g_cclosure_marshal_VOID__DOUBLE, G_TYPE_NONE, 1, G_TYPE_DOUBLE); /* Connect freeing methods. */ G_OBJECT_CLASS(klass)->finalize = visu_ui_numerical_entry_finalize; G_OBJECT_CLASS(klass)->set_property = visu_ui_numerical_entry_set_property; G_OBJECT_CLASS(klass)->get_property = visu_ui_numerical_entry_get_property; GTK_WIDGET_CLASS(klass)->focus_in_event = visu_ui_numerical_entry_focus_in; GTK_WIDGET_CLASS(klass)->focus_out_event = visu_ui_numerical_entry_focus_out; GTK_ENTRY_CLASS(klass)->activate = visu_ui_numerical_entry_activate; /** * VisuUiNumericalEntry::value: * * Store the value in the entry. * * Since: 3.8 */ properties[VALUE_PROP] = g_param_spec_double("value", "Value", "numerical value", -G_MAXFLOAT, G_MAXFLOAT, 0., G_PARAM_CONSTRUCT | G_PARAM_READWRITE); g_object_class_install_properties(G_OBJECT_CLASS(klass), N_PROP, properties); } static void visu_ui_numerical_entry_finalize(GObject *obj) { VisuUiNumericalEntry *entry; g_return_if_fail(obj); DBG_fprintf(stderr, "Gtk VisuUiNumericalEntry: finalize object %p.\n", (gpointer)obj); entry = VISU_UI_NUMERICAL_ENTRY(obj); g_free(entry->format); /* Chain up to the parent class */ G_OBJECT_CLASS(visu_ui_numerical_entry_parent_class)->finalize(obj); DBG_fprintf(stderr, "Gtk VisuUiNumericalEntry: freeing ... OK.\n"); } static void visu_ui_numerical_entry_get_property(GObject* obj, guint property_id, GValue *value, GParamSpec *pspec) { VisuUiNumericalEntry *self = VISU_UI_NUMERICAL_ENTRY(obj); DBG_fprintf(stderr, "Gtk VisuUiNumericalEntry: get property '%s'.\n", g_param_spec_get_name(pspec)); switch (property_id) { case VALUE_PROP: g_value_set_double(value, self->value); break; default: /* We don't have any other property... */ G_OBJECT_WARN_INVALID_PROPERTY_ID(obj, property_id, pspec); break; } } static void visu_ui_numerical_entry_set_property(GObject* obj, guint property_id, const GValue *value, GParamSpec *pspec) { VisuUiNumericalEntry *self = VISU_UI_NUMERICAL_ENTRY(obj); DBG_fprintf(stderr, "Gtk VisuUiNumericalEntry: set property '%s'.\n", g_param_spec_get_name(pspec)); switch (property_id) { case VALUE_PROP: visu_ui_numerical_entry_setValue(self, g_value_get_double(value)); break; default: /* We don't have any other property... */ G_OBJECT_WARN_INVALID_PROPERTY_ID(obj, property_id, pspec); break; } } static void visu_ui_numerical_entry_init(VisuUiNumericalEntry *numericalEntry) { DBG_fprintf(stderr, "Gtk VisuUiNumericalEntry : initializing new object (%p).\n", (gpointer)numericalEntry); numericalEntry->format = g_strdup(VISU_UI_NUMERICAL_ENTRY_FORMAT_DEFAULT); } /** * visu_ui_numerical_entry_new : * @value: the initial value. * * A #VisuUiNumericalEntry widget is like a #GtkEntry widget, but it only accepts * double precision values (written in plain format, e.g. 1.23456, or scientific * notation, e.g. 1.2345e6). The widget can't be blank and there is always * a value printed in it. If the user erase the current value or enter something * that is not a recognised double precision value, the widget returns to its previous * valid value. * * Returns: a newly created #VisuUiNumericalEntry widget. */ GtkWidget* visu_ui_numerical_entry_new(double value) { return g_object_new(VISU_TYPE_UI_NUMERICAL_ENTRY, "value", value, NULL); } static void printStoredValue(VisuUiNumericalEntry* numericalEntry) { gchar *str; g_return_if_fail(VISU_IS_UI_NUMERICAL_ENTRY(numericalEntry)); str = g_strdup_printf(numericalEntry->format, numericalEntry->value); gtk_entry_set_text(GTK_ENTRY(numericalEntry), str); g_free(str); if (!parsePrintedValue(numericalEntry, &numericalEntry->printed_value)) numericalEntry->printed_value = G_MAXFLOAT; } static gboolean parsePrintedValue(VisuUiNumericalEntry *numericalEntry, double *value) { double valueDouble; gchar *last; g_return_val_if_fail(VISU_IS_UI_NUMERICAL_ENTRY(numericalEntry) && value, FALSE); valueDouble = g_ascii_strtod(gtk_entry_get_text(GTK_ENTRY(numericalEntry)), &last); if (*last != '\0') { /* Wrong number. */ visu_ui_numerical_entry_warnValue(numericalEntry, numericalEntry->value); return FALSE; } *value = valueDouble; return TRUE; } /** * visu_ui_numerical_entry_setValue: * @numericalEntry: a #VisuUiNumericalEntry widget ; * @value: a double precision value. * * Use this method to set the value for the given #numericalEntry widget. */ void visu_ui_numerical_entry_setValue(VisuUiNumericalEntry* numericalEntry, double value) { double valueOld; g_return_if_fail(VISU_IS_UI_NUMERICAL_ENTRY(numericalEntry)); if (value == numericalEntry->value) return; valueOld = numericalEntry->value; numericalEntry->value = value; printStoredValue(numericalEntry); DBG_fprintf(stderr, "Gtk VisuUiNumericalEntry : emitting 'value-changed' signal.\n"); g_object_notify_by_pspec(G_OBJECT(numericalEntry), properties[VALUE_PROP]); g_signal_emit(G_OBJECT(numericalEntry), _signals[VALUE_CHANGED_SIGNAL], 0, valueOld, NULL); } /** * visu_ui_numerical_entry_getValue: * @numericalEntry: a #VisuUiNumericalEntry widget. * * You can get the value contained in the given @numericalEntry using this method. * * Returns: the double precision value printed in the #VisuUiNumericalEntry. */ double visu_ui_numerical_entry_getValue(VisuUiNumericalEntry *numericalEntry) { g_return_val_if_fail(VISU_IS_UI_NUMERICAL_ENTRY(numericalEntry), 0.); return numericalEntry->value; } static void visu_ui_numerical_entry_activate(GtkEntry *entry) { VisuUiNumericalEntry *numericalEntry = VISU_UI_NUMERICAL_ENTRY(entry); double valueDouble; if (parsePrintedValue(numericalEntry, &valueDouble) && valueDouble != numericalEntry->printed_value) visu_ui_numerical_entry_setValue(numericalEntry, valueDouble); } static gboolean visu_ui_numerical_entry_focus_out(GtkWidget *wd, GdkEventFocus *event) { visu_ui_numerical_entry_activate(GTK_ENTRY(wd)); return GTK_WIDGET_CLASS(visu_ui_numerical_entry_parent_class)->focus_in_event(wd, event); } static gboolean visu_ui_numerical_entry_focus_in(GtkWidget *wd, GdkEventFocus *event) { /* gtk_editable_select_region(GTK_EDITABLE(numericalEntry), 0, -1); */ return GTK_WIDGET_CLASS(visu_ui_numerical_entry_parent_class)->focus_out_event(wd, event); } static gboolean _removeWarning(gpointer data) { gtk_entry_set_icon_from_icon_name(GTK_ENTRY(data), GTK_ENTRY_ICON_SECONDARY, NULL); return FALSE; } /** * visu_ui_numerical_entry_warnValue: * @numericalEntry: a #VisuUiNumericalEntry object. * @fallback: a floating point value. * * Display a warning sign in the entry and fallback to the given value. * * Since: 3.8 **/ void visu_ui_numerical_entry_warnValue(VisuUiNumericalEntry *numericalEntry, float fallback) { g_return_if_fail(VISU_IS_UI_NUMERICAL_ENTRY(numericalEntry)); gtk_entry_set_icon_from_icon_name(GTK_ENTRY(numericalEntry), GTK_ENTRY_ICON_SECONDARY, "dialog-warning"); g_timeout_add_seconds(2, _removeWarning, (gpointer)numericalEntry); numericalEntry->value = G_MAXDOUBLE; visu_ui_numerical_entry_setValue(numericalEntry, fallback); } v_sim-3.8.0/src/extraGtkFunctions/gtk_numericalEntryWidget.h000066400000000000000000000100341370110300500242570ustar00rootroot00000000000000/* EXTRAITS DE LA LICENCE Copyright CEA, contributeurs : Luc BILLARD et Damien CALISTE, laboratoire L_Sim, (2001-2005) Adresse mèl : BILLARD, non joignable par mèl ; CALISTE, damien P caliste AT cea P fr. Ce logiciel est un programme informatique servant à visualiser des structures atomiques dans un rendu pseudo-3D. Ce logiciel est régi par la licence CeCILL soumise au droit français et respectant les principes de diffusion des logiciels libres. Vous pouvez utiliser, modifier et/ou redistribuer ce programme sous les conditions de la licence CeCILL telle que diffusée par le CEA, le CNRS et l'INRIA sur le site "http://www.cecill.info". Le fait que vous puissiez accéder à cet en-tête signifie que vous avez pris connaissance de la licence CeCILL, et que vous en avez accepté les termes (cf. le fichier Documentation/licence.fr.txt fourni avec ce logiciel). */ /* LICENCE SUM UP Copyright CEA, contributors : Luc BILLARD et Damien CALISTE, laboratoire L_Sim, (2001-2005) E-mail address: BILLARD, not reachable any more ; CALISTE, damien P caliste AT cea P fr. This software is a computer program whose purpose is to visualize atomic configurations in 3D. This software is governed by the CeCILL license under French law and abiding by the rules of distribution of free software. You can use, modify and/ or redistribute the software under the terms of the CeCILL license as circulated by CEA, CNRS and INRIA at the following URL "http://www.cecill.info". The fact that you are presently reading this means that you have had knowledge of the CeCILL license and that you accept its terms. You can find a copy of this licence shipped with this software at Documentation/licence.en.txt. */ #ifndef GTK_NUMERICALENTRYWIDGET_H #define GTK_NUMERICALENTRYWIDGET_H #include #include #include #include G_BEGIN_DECLS /** * VISU_TYPE_UI_NUMERICAL_ENTRY: * * Return the associated #GType to the VisuUiNumericalEntry objects. */ #define VISU_TYPE_UI_NUMERICAL_ENTRY (visu_ui_numerical_entry_get_type ()) /** * VISU_UI_NUMERICAL_ENTRY: * @obj: the widget to cast. * * Cast the given object to a #VisuUiNumericalEntry object. */ #define VISU_UI_NUMERICAL_ENTRY(obj) (G_TYPE_CHECK_INSTANCE_CAST ((obj), VISU_TYPE_UI_NUMERICAL_ENTRY, VisuUiNumericalEntry)) /** * VISU_UI_NUMERICAL_ENTRY_CLASS: * @klass: the class to cast. * * Cast the given class to a #VisuUiNumericalEntryClass object. */ #define VISU_UI_NUMERICAL_ENTRY_CLASS(klass) (G_TYPE_CHECK_CLASS_CAST ((klass), VISU_TYPE_UI_NUMERICAL_ENTRY, VisuUiNumericalEntryClass)) /** * VISU_IS_UI_NUMERICAL_ENTRY: * @obj: the object to test. * * Return if the given object is a valid #VisuUiNumericalEntry object. */ #define VISU_IS_UI_NUMERICAL_ENTRY(obj) (G_TYPE_CHECK_INSTANCE_TYPE ((obj), VISU_TYPE_UI_NUMERICAL_ENTRY)) /** * VISU_IS_UI_NUMERICAL_ENTRY_CLASS: * @klass: the class to test. * * Return if the given class is a valid #VisuUiNumericalEntryClass class. */ #define VISU_IS_UI_NUMERICAL_ENTRY_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE ((klass), VISU_TYPE_UI_NUMERICAL_ENTRY)) /** * VisuUiNumericalEntry * * Short form for a #VisuUiNumericalEntry_struct structure. */ typedef struct _VisuUiNumericalEntry VisuUiNumericalEntry; /* typedef struct VisuUiNumericalEntryPrivate_struct VisuUiNumericalEntryPrivate; */ /** * VisuUiNumericalEntryClass * * Opaque structure. */ typedef struct _VisuUiNumericalEntryClass VisuUiNumericalEntryClass; /** * visu_ui_numerical_entry_get_type * * #GType are unique numbers to identify objects. * * Returns: the #GType associated with #VisuUiNumericalEntry objects. */ GType visu_ui_numerical_entry_get_type(void); GtkWidget* visu_ui_numerical_entry_new(double value); void visu_ui_numerical_entry_setValue(VisuUiNumericalEntry* numericalEntry, double value); double visu_ui_numerical_entry_getValue(VisuUiNumericalEntry *numericalEntry); void visu_ui_numerical_entry_warnValue(VisuUiNumericalEntry *numericalEntry, float fallback); G_END_DECLS #endif v_sim-3.8.0/src/extraGtkFunctions/gtk_orientationChooser.c000066400000000000000000000756511370110300500240030ustar00rootroot00000000000000/* EXTRAITS DE LA LICENCE Copyright CEA, contributeurs : Luc BILLARD et Damien CALISTE, laboratoire L_Sim, (2001-2005) Adresse mèl : BILLARD, non joignable par mèl ; CALISTE, damien P caliste AT cea P fr. Ce logiciel est un programme informatique servant à visualiser des structures atomiques dans un rendu pseudo-3D. Ce logiciel est régi par la licence CeCILL soumise au droit français et respectant les principes de diffusion des logiciels libres. Vous pouvez utiliser, modifier et/ou redistribuer ce programme sous les conditions de la licence CeCILL telle que diffusée par le CEA, le CNRS et l'INRIA sur le site "http://www.cecill.info". Le fait que vous puissiez accéder à cet en-tête signifie que vous avez pris connaissance de la licence CeCILL, et que vous en avez accepté les termes (cf. le fichier Documentation/licence.fr.txt fourni avec ce logiciel). */ /* LICENCE SUM UP Copyright CEA, contributors : Luc BILLARD et Damien CALISTE, laboratoire L_Sim, (2001-2005) E-mail address: BILLARD, not reachable any more ; CALISTE, damien P caliste AT cea P fr. This software is a computer program whose purpose is to visualize atomic configurations in 3D. This software is governed by the CeCILL license under French law and abiding by the rules of distribution of free software. You can use, modify and/ or redistribute the software under the terms of the CeCILL license as circulated by CEA, CNRS and INRIA at the following URL "http://www.cecill.info". The fact that you are presently reading this means that you have had knowledge of the CeCILL license and that you accept its terms. You can find a copy of this licence shipped with this software at Documentation/licence.en.txt. */ #include #include #include "gtk_orientationChooser.h" #include #include #include #include #include /** * SECTION:gtk_orientationChooser * @short_description: Defines a dialog widget to choose the camera position. * @include: coreTools/toolMatrix.h * * This widget is a #GtkDialog window that can be used to choose * an orientation for the camera, using either the cartesian * coordinates, the box coordinates or the spherical coordinates. */ enum { VALUES_CHANGED, LAST_SIGNAL }; typedef enum { visu_ui_orientation_chooser_ortho, visu_ui_orientation_chooser_box, visu_ui_orientation_chooser_angles } VisuUiOrientationChooserBasis; /** * VisuUiOrientationChooser: * * Short form for a #VisuUiOrientationChooser_struct structure. */ struct _VisuUiOrientationChooser { GtkDialog dialog; /* The kind of chooser in box coordinates. */ VisuUiOrientationChooserKind kind; /* The spins for the ortho selection. */ GtkWidget *spinsOrtho[3]; gulong signalsOrtho[3]; /* The spins for the box selection. */ GtkWidget *hboxBox; GtkWidget *spinsBox[3]; gulong signalsBox[3]; /* The spins for the angle selection. */ GtkWidget *spinsAngles[2]; gulong signalsAngles[2]; /* The check box for live update. */ GtkWidget *checkLiveUpdate; /* Associated VisuBox, if any. */ VisuBoxed *boxed; gulong box_sig; VisuBox *box; gulong size_sig; /* Transformation matrix associated to the box. */ float boxToOrtho[3][3]; float orthoToBox[3][3]; /* Memory gestion. */ gboolean dispose_has_run; }; /** * VisuUiOrientationChooserClass: * * Opaque structure. */ struct _VisuUiOrientationChooserClass { GtkDialogClass parent_class; void (*orientationChooser) (VisuUiOrientationChooser *orientation); }; /** * visu_ui_orientation_chooser_get_type * * #GType are unique numbers to identify objects. * * Returns: the #GType associated with #VisuUiOrientationChooser objects. */ G_DEFINE_TYPE(VisuUiOrientationChooser, visu_ui_orientation_chooser, GTK_TYPE_DIALOG) /* Local variables. */ static guint visu_ui_orientation_chooser_signals[LAST_SIGNAL] = { 0 }; /* Local methods. */ static void visu_ui_orientation_chooser_class_init(VisuUiOrientationChooserClass *klass); static void visu_ui_orientation_chooser_init(VisuUiOrientationChooser *orientationChooser); static void visu_ui_orientation_chooser_dispose(GObject *orientationChooser); static void visu_ui_orientation_chooser_finalize(GObject *obj); static void orientationChanged(VisuUiOrientationChooser *orientation, VisuUiOrientationChooserBasis changedBasis); static void _updateBox(VisuUiOrientationChooser *orientation); /* Local callbacks. */ static void onBox(VisuBoxed *boxed, VisuBox *box, gpointer data); static void onBoxSize(VisuBox *box, float extens, gpointer data); static void onResponse(VisuUiOrientationChooser *chooser, gint response, gpointer data); static void onOrthoChanged(GtkSpinButton *spin, gpointer data); static void onBoxChanged(GtkSpinButton *spin, gpointer data); static void onAnglesChanged(GtkSpinButton *spin, gpointer data); static void visu_ui_orientation_chooser_class_init(VisuUiOrientationChooserClass *klass) { DBG_fprintf(stderr, "Gtk VisuUiOrientationChooser: creating the class of the widget.\n"); DBG_fprintf(stderr, " - adding new signals ;\n"); /** * VisuUiOrientationChooser::values-changed: * @chooser: the #VisuUiOrientationChooser that emits the signal. * * This signal is emitted when the values are changed and when the * live update checkbox is active. * * Since: 3.4 */ visu_ui_orientation_chooser_signals[VALUES_CHANGED] = g_signal_new ("values-changed", G_TYPE_FROM_CLASS(klass), G_SIGNAL_RUN_FIRST | G_SIGNAL_ACTION, G_STRUCT_OFFSET(VisuUiOrientationChooserClass, orientationChooser), NULL, NULL, g_cclosure_marshal_VOID__VOID, G_TYPE_NONE, 0, NULL); /* Connect freeing methods. */ G_OBJECT_CLASS(klass)->dispose = visu_ui_orientation_chooser_dispose; G_OBJECT_CLASS(klass)->finalize = visu_ui_orientation_chooser_finalize; } /* This method can be called several times. It should unref all of its reference to GObjects. */ static void visu_ui_orientation_chooser_dispose(GObject *orientationChooser) { DBG_fprintf(stderr, "Gtk VisuUiOrientationChooser: dispose object %p.\n", (gpointer)orientationChooser); if (VISU_UI_ORIENTATION_CHOOSER(orientationChooser)->dispose_has_run) return; VISU_UI_ORIENTATION_CHOOSER(orientationChooser)->dispose_has_run = TRUE; /* Chain up to the parent class */ G_OBJECT_CLASS(visu_ui_orientation_chooser_parent_class)->dispose(orientationChooser); } /* This method is called once only. */ static void visu_ui_orientation_chooser_finalize(GObject *obj) { VisuUiOrientationChooser *orientationChooser; g_return_if_fail(obj); DBG_fprintf(stderr, "Gtk VisuUiOrientationChooser: finalize object %p.\n", (gpointer)obj); orientationChooser = VISU_UI_ORIENTATION_CHOOSER(obj); if (orientationChooser->box) { g_signal_handler_disconnect(G_OBJECT(orientationChooser->box), orientationChooser->size_sig); g_object_unref(orientationChooser->box); } if (orientationChooser->boxed) { g_signal_handler_disconnect(G_OBJECT(orientationChooser->boxed), orientationChooser->box_sig); g_object_unref(orientationChooser->boxed); } /* Chain up to the parent class */ G_OBJECT_CLASS(visu_ui_orientation_chooser_parent_class)->finalize(obj); DBG_fprintf(stderr, "Gtk VisuUiOrientationChooser: freeing ... OK.\n"); } static void visu_ui_orientation_chooser_init(VisuUiOrientationChooser *orientationChooser) { int i; DBG_fprintf(stderr, "Gtk VisuUiOrientationChooser: initializing new object (%p).\n", (gpointer)orientationChooser); orientationChooser->dispose_has_run = FALSE; orientationChooser->kind = VISU_UI_ORIENTATION_DIRECTION; orientationChooser->boxed = (VisuBoxed*)0; orientationChooser->box_sig = 0; orientationChooser->box = (VisuBox*)0; orientationChooser->size_sig = 0; for (i = 0; i < 3; i++) { orientationChooser->spinsOrtho[i] = gtk_spin_button_new_with_range(-1000, 1000, 1); gtk_spin_button_set_value (GTK_SPIN_BUTTON(orientationChooser->spinsOrtho[i]), 0); gtk_spin_button_set_digits (GTK_SPIN_BUTTON(orientationChooser->spinsOrtho[i]), 5); orientationChooser->signalsOrtho[i] = g_signal_connect(G_OBJECT(orientationChooser->spinsOrtho[i]), "value-changed", G_CALLBACK(onOrthoChanged), orientationChooser); } orientationChooser->hboxBox = gtk_hbox_new(FALSE, 0); for (i = 0; i < 3; i++) { orientationChooser->spinsBox[i] = gtk_spin_button_new_with_range(-1000, 1000, 1); gtk_spin_button_set_value (GTK_SPIN_BUTTON(orientationChooser->spinsBox[i]), 0); gtk_spin_button_set_digits (GTK_SPIN_BUTTON(orientationChooser->spinsBox[i]), 5); orientationChooser->signalsBox[i] = g_signal_connect(G_OBJECT(orientationChooser->spinsBox[i]), "value-changed", G_CALLBACK(onBoxChanged), orientationChooser); } for (i = 0; i < 2; i++) { orientationChooser->spinsAngles[i] = gtk_spin_button_new_with_range(-180, 180, 1); gtk_spin_button_set_value (GTK_SPIN_BUTTON(orientationChooser->spinsAngles[i]), 0); gtk_spin_button_set_digits (GTK_SPIN_BUTTON(orientationChooser->spinsAngles[i]), 5); orientationChooser->signalsAngles[i] = g_signal_connect(G_OBJECT(orientationChooser->spinsAngles[i]), "value-changed", G_CALLBACK(onAnglesChanged), orientationChooser); } orientationChooser->checkLiveUpdate = gtk_check_button_new_with_label(_("Update values on the fly.")); /* Connect a signal when the dialog is closed. */ g_signal_connect(G_OBJECT(orientationChooser), "response", G_CALLBACK(onResponse), (gpointer)0); } /** * visu_ui_orientation_chooser_new: * @kind: to set the box coordinates behavior ; * @liveUpdate: raise "values-changed" when a value is changed ; * @boxed: (allow-none): the associated #VisuData to get the box * definition (can be NULL); * @parent: (allow-none): give the parent window to set the modal * status and the position. * * Create a dialog box with three choices to choose a direction in space: the * classical orthogonal basis set, the spherical one or the basis set linked * to the box. If the @data argument is NULL, this last possibility is made * unsensitive. If the kind is set to VISU_UI_ORIENTATION_DIRECTION, the orthogonal * coordinates correspond exactly to the box coordinates (after transformation) ; * whereas @kind is VISU_UI_ORIENTATION_NORMAL, the cartesian coordinates are those * which give the right normal plane to the direction given in the box coordinates. * * Returns: (transfer full): a newly created object. */ GtkWidget* visu_ui_orientation_chooser_new(VisuUiOrientationChooserKind kind, gboolean liveUpdate, VisuBoxed *boxed, GtkWindow *parent) { VisuUiOrientationChooser *orientationChooser; GtkWidget *wd, *hbox, *hbox2, *vbox; int i; gchar *axesNames[3] = {"x:", "y:", "z:"}; gchar *anglesNames[2] = {"theta:", "phi:"}; orientationChooser = VISU_UI_ORIENTATION_CHOOSER(g_object_new(visu_ui_orientation_chooser_get_type(), NULL)); DBG_fprintf(stderr, "Gtk VisuUiOrientationChooser: creating new object: %p" " with parent %p.\n", (gpointer)orientationChooser, (gpointer)parent); gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON(orientationChooser->checkLiveUpdate), liveUpdate); gtk_dialog_add_buttons(GTK_DIALOG(orientationChooser), TOOL_ICON_CANCEL, GTK_RESPONSE_CANCEL, TOOL_ICON_CLOSE, GTK_RESPONSE_ACCEPT, NULL); gtk_dialog_set_default_response(GTK_DIALOG(orientationChooser), GTK_RESPONSE_ACCEPT); /* gtk_window_set_type_hint(GTK_WINDOW(orientationChooser), */ /* GDK_WINDOW_TYPE_HINT_UTILITY); */ gtk_window_set_skip_pager_hint(GTK_WINDOW(orientationChooser), TRUE); if (!parent) parent = visu_ui_getPanel(); gtk_window_set_transient_for(GTK_WINDOW(orientationChooser), parent); /* Title. */ wd = gtk_label_new(""); gtk_label_set_use_markup(GTK_LABEL(wd), TRUE); gtk_label_set_markup(GTK_LABEL(wd), _("Choose an orientation")); gtk_widget_set_name(wd, "label_head_2"); gtk_box_pack_start (GTK_BOX(gtk_dialog_get_content_area(GTK_DIALOG(orientationChooser))), wd, FALSE, FALSE, 5); /* Ortho orientation. */ hbox = gtk_hbox_new(FALSE, 0); gtk_box_pack_start (GTK_BOX(gtk_dialog_get_content_area(GTK_DIALOG(orientationChooser))), hbox, FALSE, FALSE, 3); wd = create_pixmap((GtkWidget*)0, "axes-ortho.png"); gtk_box_pack_start(GTK_BOX(hbox), wd, FALSE, FALSE, 0); vbox = gtk_vbox_new(FALSE, 0); gtk_box_pack_start(GTK_BOX(hbox), vbox, TRUE, TRUE, 0); wd = gtk_label_new(""); gtk_label_set_use_markup(GTK_LABEL(wd), TRUE); gtk_label_set_markup(GTK_LABEL(wd), _("On an orthonormal basis set")); gtk_label_set_xalign(GTK_LABEL(wd), 0.1); gtk_box_pack_start(GTK_BOX(vbox), wd, TRUE, TRUE, 15); hbox2 = gtk_hbox_new(FALSE, 0); gtk_box_pack_start(GTK_BOX(vbox), hbox2, FALSE, FALSE, 0); for (i = 0; i < 3; i++) { wd = gtk_label_new(axesNames[i]); gtk_label_set_xalign(GTK_LABEL(wd), 1.); gtk_box_pack_start(GTK_BOX(hbox2), wd, TRUE, TRUE, 2); gtk_box_pack_start(GTK_BOX(hbox2), orientationChooser->spinsOrtho[i], FALSE, FALSE, 0); } /* Box orientation. */ gtk_widget_set_sensitive(orientationChooser->hboxBox, boxed && visu_box_getBoundary(visu_boxed_getBox(boxed)) != VISU_BOX_FREE); gtk_box_pack_start(GTK_BOX (gtk_dialog_get_content_area(GTK_DIALOG(orientationChooser))), orientationChooser->hboxBox, FALSE, FALSE, 3); wd = create_pixmap((GtkWidget*)0, "axes-box.png"); gtk_box_pack_start(GTK_BOX(orientationChooser->hboxBox), wd, FALSE, FALSE, 0); vbox = gtk_vbox_new(FALSE, 0); gtk_box_pack_start(GTK_BOX(orientationChooser->hboxBox), vbox, TRUE, TRUE, 0); wd = gtk_label_new(""); gtk_label_set_use_markup(GTK_LABEL(wd), TRUE); gtk_label_set_markup(GTK_LABEL(wd), _("Following the box basis set")); gtk_label_set_xalign(GTK_LABEL(wd), 0.1); gtk_box_pack_start(GTK_BOX(vbox), wd, TRUE, TRUE, 7); hbox2 = gtk_hbox_new(FALSE, 0); gtk_box_pack_start(GTK_BOX(vbox), hbox2, FALSE, FALSE, 0); for (i = 0; i < 3; i++) { wd = gtk_label_new(axesNames[i]); gtk_label_set_xalign(GTK_LABEL(wd), 1.); gtk_box_pack_start(GTK_BOX(hbox2), wd, TRUE, TRUE, 2); gtk_box_pack_start(GTK_BOX(hbox2), orientationChooser->spinsBox[i], FALSE, FALSE, 0); } /* Ortho orientation. */ hbox = gtk_hbox_new(FALSE, 0); gtk_box_pack_start(GTK_BOX (gtk_dialog_get_content_area(GTK_DIALOG(orientationChooser))), hbox, FALSE, FALSE, 3); wd = create_pixmap((GtkWidget*)0, "axes-angles.png"); gtk_box_pack_start(GTK_BOX(hbox), wd, FALSE, FALSE, 0); vbox = gtk_vbox_new(FALSE, 0); gtk_box_pack_start(GTK_BOX(hbox), vbox, TRUE, TRUE, 0); wd = gtk_label_new(""); gtk_label_set_use_markup(GTK_LABEL(wd), TRUE); gtk_label_set_markup(GTK_LABEL(wd), _("On a spherical basis set")); gtk_label_set_xalign(GTK_LABEL(wd), 0.1); gtk_box_pack_start(GTK_BOX(vbox), wd, TRUE, TRUE, 15); hbox2 = gtk_hbox_new(FALSE, 0); gtk_box_pack_start(GTK_BOX(vbox), hbox2, FALSE, FALSE, 0); for (i = 0; i < 2; i++) { wd = gtk_label_new(anglesNames[i]); gtk_label_set_xalign(GTK_LABEL(wd), 1.); gtk_box_pack_start(GTK_BOX(hbox2), wd, TRUE, TRUE, 2); gtk_box_pack_start(GTK_BOX(hbox2), orientationChooser->spinsAngles[i], FALSE, FALSE, 0); } /* The live update checkbox. */ hbox = gtk_hbox_new(FALSE, 0); gtk_box_pack_start(GTK_BOX (gtk_dialog_get_content_area(GTK_DIALOG(orientationChooser))), hbox, FALSE, FALSE, 5); gtk_box_pack_start(GTK_BOX(hbox), orientationChooser->checkLiveUpdate, FALSE, FALSE, 90); gtk_widget_show_all(GTK_WIDGET(orientationChooser)); /* Set other internal values. */ orientationChooser->kind = kind; if (boxed) { orientationChooser->boxed = boxed; g_object_ref(G_OBJECT(boxed)); orientationChooser->box_sig = g_signal_connect (G_OBJECT(boxed), "setBox", G_CALLBACK(onBox), (gpointer)orientationChooser); onBox(boxed, visu_boxed_getBox(boxed), (gpointer)orientationChooser); } return GTK_WIDGET(orientationChooser); } static void onBox(VisuBoxed *boxed _U_, VisuBox *box, gpointer data) { VisuUiOrientationChooser *chooser = VISU_UI_ORIENTATION_CHOOSER(data); if (chooser->box) { g_signal_handler_disconnect(G_OBJECT(chooser->box), chooser->size_sig); g_object_unref(G_OBJECT(chooser->box)); } chooser->box = box; if (chooser->box) { g_object_ref(G_OBJECT(chooser->box)); chooser->size_sig = g_signal_connect(G_OBJECT(chooser->box), "SizeChanged", G_CALLBACK(onBoxSize), data); _updateBox(chooser); } } static void onBoxSize(VisuBox *box _U_, float extens _U_, gpointer data) { /* We recompute the transformation matrix. */ _updateBox(VISU_UI_ORIENTATION_CHOOSER(data)); } static void _updateBox(VisuUiOrientationChooser *orientation) { float tmpCoord[3], norm; float boxMatrix[3][3]; int i, j; g_return_if_fail(VISU_IS_UI_ORIENTATION_CHOOSER(orientation)); /* Set or unset the box coordinate choice. */ gtk_widget_set_sensitive(orientation->hboxBox, orientation->box && visu_box_getBoundary(orientation->box) != VISU_BOX_FREE); if (!orientation->box) return; /* Change the transformation matrix. */ for (j = 0; j < 3; j++) { tmpCoord[0] = (j == 0)?1.:0.; tmpCoord[1] = (j == 1)?1.:0.; tmpCoord[2] = (j == 2)?1.:0.; visu_box_convertBoxCoordinatestoXYZ(orientation->box, boxMatrix[j], tmpCoord); } DBG_fprintf(stderr, "Gtk VisuUiOrientationChooser: get the box matrix.\n"); DBG_fprintf(stderr, " | %8.4f %8.4f %8.4f\n", boxMatrix[0][0], boxMatrix[1][0], boxMatrix[2][0]); DBG_fprintf(stderr, " | %8.4f %8.4f %8.4f\n", boxMatrix[0][1], boxMatrix[1][1], boxMatrix[2][1]); DBG_fprintf(stderr, " | %8.4f %8.4f %8.4f\n", boxMatrix[0][2], boxMatrix[1][2], boxMatrix[2][2]); /* We create a matrix to transform the box coordinates to cartesian values keeping the orthogonality. */ for (i = 0; i < 3; i++) { norm = 0.; for (j = 0; j < 3; j++) { orientation->boxToOrtho[j][i] = boxMatrix[(i + 1)%3][(j + 1)%3] * boxMatrix[(i + 2)%3][(j + 2)%3] - boxMatrix[(i + 1)%3][(j + 2)%3] * boxMatrix[(i + 2)%3][(j + 1)%3]; norm += orientation->boxToOrtho[j][i] * orientation->boxToOrtho[j][i]; } /* We normalise the tranformation matrix. */ norm = sqrt(norm); for (j = 0; j < 3; j++) orientation->boxToOrtho[j][i] /= norm; } DBG_fprintf(stderr, "Gtk VisuUiOrientationChooser: normal case, boxToOrtho matrix.\n"); DBG_fprintf(stderr, " | %8.4f %8.4f %8.4f\n", orientation->boxToOrtho[0][0], orientation->boxToOrtho[0][1], orientation->boxToOrtho[0][2]); DBG_fprintf(stderr, " | %8.4f %8.4f %8.4f\n", orientation->boxToOrtho[1][0], orientation->boxToOrtho[1][1], orientation->boxToOrtho[1][2]); DBG_fprintf(stderr, " | %8.4f %8.4f %8.4f\n", orientation->boxToOrtho[2][0], orientation->boxToOrtho[2][1], orientation->boxToOrtho[2][2]); /* We inverse using the trick that the matrix is down (upper side is zeros. */ orientation->orthoToBox[0][0] = 1. / orientation->boxToOrtho[0][0]; orientation->orthoToBox[1][0] = - orientation->boxToOrtho[1][0] / orientation->boxToOrtho[1][1] / orientation->boxToOrtho[0][0]; orientation->orthoToBox[2][0] = (orientation->boxToOrtho[1][0] * orientation->boxToOrtho[2][1] - orientation->boxToOrtho[1][1] * orientation->boxToOrtho[2][0]) / orientation->boxToOrtho[0][0] / orientation->boxToOrtho[1][1] / orientation->boxToOrtho[2][2]; orientation->orthoToBox[0][1] = 0.; orientation->orthoToBox[1][1] = 1. / orientation->boxToOrtho[1][1]; orientation->orthoToBox[2][1] = - orientation->boxToOrtho[2][1] / orientation->boxToOrtho[1][1] / orientation->boxToOrtho[2][2]; orientation->orthoToBox[0][2] = 0.; orientation->orthoToBox[1][2] = 0.; orientation->orthoToBox[2][2] = 1. / orientation->boxToOrtho[2][2]; DBG_fprintf(stderr, "Gtk VisuUiOrientationChooser: normal case, orthoToBox matrix.\n"); DBG_fprintf(stderr, " | %8.4f %8.4f %8.4f\n", orientation->orthoToBox[0][0], orientation->orthoToBox[0][1], orientation->orthoToBox[0][2]); DBG_fprintf(stderr, " | %8.4f %8.4f %8.4f\n", orientation->orthoToBox[1][0], orientation->orthoToBox[1][1], orientation->orthoToBox[1][2]); DBG_fprintf(stderr, " | %8.4f %8.4f %8.4f\n", orientation->orthoToBox[2][0], orientation->orthoToBox[2][1], orientation->orthoToBox[2][2]); } static void orientationChanged(VisuUiOrientationChooser *orientation, VisuUiOrientationChooserBasis changedBasis) { int i; float xyz[3], boxXYZ[3], angles[3]; g_return_if_fail(changedBasis != visu_ui_orientation_chooser_box || orientation->box); /* Get the changed coordinates and update the others. */ switch (changedBasis) { case visu_ui_orientation_chooser_ortho: for (i = 0; i < 3; i++) xyz[i] = (float)gtk_spin_button_get_value (GTK_SPIN_BUTTON(orientation->spinsOrtho[i])); if (orientation->box) { if (orientation->kind == VISU_UI_ORIENTATION_DIRECTION) visu_box_convertXYZtoBoxCoordinates(orientation->box, boxXYZ, xyz); else if (orientation->kind == VISU_UI_ORIENTATION_NORMAL) tool_matrix_productVector(boxXYZ, orientation->orthoToBox, xyz); } tool_matrix_cartesianToSpherical(angles, xyz); if (angles[2] > 180.) angles[2] -= 360.; break; case visu_ui_orientation_chooser_box: for (i = 0; i < 3; i++) boxXYZ[i] = (float)gtk_spin_button_get_value (GTK_SPIN_BUTTON(orientation->spinsBox[i])); /* The conversion to cartesian coordinates depends on the attribute kind. */ if (orientation->kind == VISU_UI_ORIENTATION_DIRECTION) visu_box_convertBoxCoordinatestoXYZ(orientation->box, xyz, boxXYZ); else if (orientation->kind == VISU_UI_ORIENTATION_NORMAL) tool_matrix_productVector(xyz, orientation->boxToOrtho, boxXYZ); tool_matrix_cartesianToSpherical(angles, xyz); if (angles[2] > 180.) angles[2] -= 360.; break; case visu_ui_orientation_chooser_angles: for (i = 0; i < 3; i++) xyz[i] = (float)gtk_spin_button_get_value (GTK_SPIN_BUTTON(orientation->spinsOrtho[i])); angles[0] = sqrt(xyz[0] * xyz[0] + xyz[1] * xyz[1] + xyz[2] * xyz[2]); if (angles[0] == 0.) angles[0] = 1.; for (i = 1; i < 3; i++) angles[i] = (float)gtk_spin_button_get_value (GTK_SPIN_BUTTON(orientation->spinsAngles[i - 1])); tool_matrix_sphericalToCartesian(xyz, angles); if (orientation->box) { if (orientation->kind == VISU_UI_ORIENTATION_DIRECTION) visu_box_convertXYZtoBoxCoordinates(orientation->box, boxXYZ, xyz); else if (orientation->kind == VISU_UI_ORIENTATION_NORMAL) tool_matrix_productVector(boxXYZ, orientation->orthoToBox, xyz); } break; } DBG_fprintf(stderr, "Gtk VisuUiOrientationChooser: set coordinates.\n"); DBG_fprintf(stderr, " | ortho: %8.4g %8.4g %8.4g\n", xyz[0], xyz[1], xyz[2]); DBG_fprintf(stderr, " | box: %8.4g %8.4g %8.4g\n", boxXYZ[0], boxXYZ[1], boxXYZ[2]); DBG_fprintf(stderr, " | angles: %8.4g %8.4g\n", angles[1], angles[2]); /* Stop the internal spin signals, change the values and reset the signals. */ for (i = 0; i < 3; i++) { /* DBG_fprintf(stderr, "Gtk VisuUiOrientationChooser: change the ortho values\n"); */ g_signal_handler_block(G_OBJECT(orientation->spinsOrtho[i]), orientation->signalsOrtho[i]); gtk_spin_button_set_value(GTK_SPIN_BUTTON(orientation->spinsOrtho[i]), xyz[i]); g_signal_handler_unblock(G_OBJECT(orientation->spinsOrtho[i]), orientation->signalsOrtho[i]); } if (orientation->box) for (i = 0; i < 3; i++) { /* DBG_fprintf(stderr, "Gtk VisuUiOrientationChooser: change the box values\n"); */ g_signal_handler_block(G_OBJECT(orientation->spinsBox[i]), orientation->signalsBox[i]); gtk_spin_button_set_value(GTK_SPIN_BUTTON(orientation->spinsBox[i]), boxXYZ[i]); g_signal_handler_unblock(G_OBJECT(orientation->spinsBox[i]), orientation->signalsBox[i]); } for (i = 0; i < 2; i++) { /* DBG_fprintf(stderr, "Gtk VisuUiOrientationChooser: change the angles values\n"); */ g_signal_handler_block(G_OBJECT(orientation->spinsAngles[i]), orientation->signalsAngles[i]); gtk_spin_button_set_value(GTK_SPIN_BUTTON(orientation->spinsAngles[i]), angles[i + 1]); g_signal_handler_unblock(G_OBJECT(orientation->spinsAngles[i]), orientation->signalsAngles[i]); } if (gtk_toggle_button_get_active(GTK_TOGGLE_BUTTON(orientation->checkLiveUpdate))) { DBG_fprintf(stderr, "Gtk VisuUiOrientationChooser: emit value changed (%d).\n", changedBasis); g_signal_emit(G_OBJECT(orientation), visu_ui_orientation_chooser_signals[VALUES_CHANGED], 0 , NULL); } } static void onOrthoChanged(GtkSpinButton *spin _U_, gpointer data) { orientationChanged(VISU_UI_ORIENTATION_CHOOSER(data), visu_ui_orientation_chooser_ortho); } static void onBoxChanged(GtkSpinButton *spin _U_, gpointer data) { orientationChanged(VISU_UI_ORIENTATION_CHOOSER(data), visu_ui_orientation_chooser_box); } static void onAnglesChanged(GtkSpinButton *spin _U_, gpointer data) { orientationChanged(VISU_UI_ORIENTATION_CHOOSER(data), visu_ui_orientation_chooser_angles); } static void onResponse(VisuUiOrientationChooser *chooser, gint response, gpointer data _U_) { if (response == GTK_RESPONSE_ACCEPT && !gtk_toggle_button_get_active(GTK_TOGGLE_BUTTON(chooser->checkLiveUpdate))) { DBG_fprintf(stderr, "Gtk VisuUiOrientationChooser: emit value changed on out.\n"); g_signal_emit(G_OBJECT(chooser), visu_ui_orientation_chooser_signals[VALUES_CHANGED], 0 , NULL); } } /** * visu_ui_orientation_chooser_setOrthoValues: * @orientation: a #VisuUiOrientationChooser widget ; * @values: (array fixed-size=3): three floating point values. * * Change the direction using the one given in an orthogonal basis * set. Update all other values accordingly. */ void visu_ui_orientation_chooser_setOrthoValues(VisuUiOrientationChooser *orientation, float values[3]) { int i; gboolean update; GtkSpinButton *spin; g_return_if_fail(VISU_IS_UI_ORIENTATION_CHOOSER(orientation)); DBG_fprintf(stderr, "Gtk VisuUiOrientationChooser: change ortho.\n"); /* Block the internal spin signals and raise manually the signal for one spin. */ update = FALSE; for (i = 0; i < 3; i++) { spin = GTK_SPIN_BUTTON(orientation->spinsOrtho[i]); g_signal_handler_block(G_OBJECT(spin), orientation->signalsOrtho[i]); update = update || ((float)gtk_spin_button_get_value(spin) != values[i]); gtk_spin_button_set_value(spin, values[i]); g_signal_handler_unblock(G_OBJECT(spin), orientation->signalsOrtho[i]); } if (update) orientationChanged(orientation, visu_ui_orientation_chooser_ortho); } /** * visu_ui_orientation_chooser_setBoxValues: * @orientation: a #VisuUiOrientationChooser widget ; * @values: (array fixed-size=3): three floating point values. * * Change the direction using the one given in the box basis * set. Update all other values accordingly. */ void visu_ui_orientation_chooser_setBoxValues(VisuUiOrientationChooser *orientation, float values[3]) { int i; gboolean update; GtkSpinButton *spin; g_return_if_fail(VISU_IS_UI_ORIENTATION_CHOOSER(orientation)); DBG_fprintf(stderr, "Gtk VisuUiOrientationChooser: change box.\n"); /* Block the internal spin signals and raise manually the signal for one spin. */ update = FALSE; for (i = 0; i < 3; i++) { spin = GTK_SPIN_BUTTON(orientation->spinsBox[i]); g_signal_handler_block(G_OBJECT(spin), orientation->signalsBox[i]); update = update || ((float)gtk_spin_button_get_value(spin) != values[i]); gtk_spin_button_set_value(spin, values[i]); g_signal_handler_unblock(G_OBJECT(spin), orientation->signalsBox[i]); } if (update) orientationChanged(orientation, visu_ui_orientation_chooser_box); } /** * visu_ui_orientation_chooser_setAnglesValues: * @orientation: a #VisuUiOrientationChooser widget ; * @values: (array fixed-size=2): two floating point values. * * Change the direction using the one given in a spherical basis * set. Update all other values accordingly. */ void visu_ui_orientation_chooser_setAnglesValues(VisuUiOrientationChooser *orientation, float values[2]) { int i; gboolean update; GtkSpinButton *spin; g_return_if_fail(VISU_IS_UI_ORIENTATION_CHOOSER(orientation)); DBG_fprintf(stderr, "Gtk VisuUiOrientationChooser: change angles to %gx%g.\n", values[0], values[1]); update = FALSE; for (i = 0; i < 2; i++) { spin = GTK_SPIN_BUTTON(orientation->spinsAngles[i]); g_signal_handler_block(G_OBJECT(spin), orientation->signalsAngles[i]); update = update || ((float)gtk_spin_button_get_value(spin) != values[i]); gtk_spin_button_set_value(spin, values[i]); g_signal_handler_unblock(G_OBJECT(spin), orientation->signalsAngles[i]); } if (update) orientationChanged(orientation, visu_ui_orientation_chooser_angles); } /** * visu_ui_orientation_chooser_getOrthoValues: * @orientation: a #VisuUiOrientationChooser widget ; * @values: (array fixed-size=3) (out): a location for three floating point values. * * Get the current orientation in the orthogonal basis set. */ void visu_ui_orientation_chooser_getOrthoValues(VisuUiOrientationChooser *orientation, float values[3]) { int i; g_return_if_fail(VISU_IS_UI_ORIENTATION_CHOOSER(orientation)); for (i = 0; i < 3; i++) values[i] = (float)gtk_spin_button_get_value (GTK_SPIN_BUTTON(orientation->spinsOrtho[i])); } /** * visu_ui_orientation_chooser_getBoxValues: * @orientation: a #VisuUiOrientationChooser widget ; * @values: (array fixed-size=3) (out): a location for three floating point values. * * Get the current orientation in the box basis set. */ void visu_ui_orientation_chooser_getBoxValues(VisuUiOrientationChooser *orientation, float values[3]) { int i; g_return_if_fail(VISU_IS_UI_ORIENTATION_CHOOSER(orientation)); for (i = 0; i < 3; i++) values[i] = (float)gtk_spin_button_get_value (GTK_SPIN_BUTTON(orientation->spinsBox[i])); } /** * visu_ui_orientation_chooser_getAnglesValues: * @orientation: a #VisuUiOrientationChooser widget ; * @values: (array fixed-size=2) (out): a location for two floating point values. * * Get the current orientation in the spherical basis set. */ void visu_ui_orientation_chooser_getAnglesValues(VisuUiOrientationChooser *orientation, float values[2]) { int i; g_return_if_fail(VISU_IS_UI_ORIENTATION_CHOOSER(orientation)); for (i = 0; i < 2; i++) values[i] = (float)gtk_spin_button_get_value (GTK_SPIN_BUTTON(orientation->spinsAngles[i])); } v_sim-3.8.0/src/extraGtkFunctions/gtk_orientationChooser.h000066400000000000000000000116371370110300500240020ustar00rootroot00000000000000/* EXTRAITS DE LA LICENCE Copyright CEA, contributeurs : Luc BILLARD et Damien CALISTE, laboratoire L_Sim, (2001-2005) Adresse mèl : BILLARD, non joignable par mèl ; CALISTE, damien P caliste AT cea P fr. Ce logiciel est un programme informatique servant à visualiser des structures atomiques dans un rendu pseudo-3D. Ce logiciel est régi par la licence CeCILL soumise au droit français et respectant les principes de diffusion des logiciels libres. Vous pouvez utiliser, modifier et/ou redistribuer ce programme sous les conditions de la licence CeCILL telle que diffusée par le CEA, le CNRS et l'INRIA sur le site "http://www.cecill.info". Le fait que vous puissiez accéder à cet en-tête signifie que vous avez pris connaissance de la licence CeCILL, et que vous en avez accepté les termes (cf. le fichier Documentation/licence.fr.txt fourni avec ce logiciel). */ /* LICENCE SUM UP Copyright CEA, contributors : Luc BILLARD et Damien CALISTE, laboratoire L_Sim, (2001-2005) E-mail address: BILLARD, not reachable any more ; CALISTE, damien P caliste AT cea P fr. This software is a computer program whose purpose is to visualize atomic configurations in 3D. This software is governed by the CeCILL license under French law and abiding by the rules of distribution of free software. You can use, modify and/ or redistribute the software under the terms of the CeCILL license as circulated by CEA, CNRS and INRIA at the following URL "http://www.cecill.info". The fact that you are presently reading this means that you have had knowledge of the CeCILL license and that you accept its terms. You can find a copy of this licence shipped with this software at Documentation/licence.en.txt. */ #ifndef GTK_ORIENTATIONCHOOSER_H #define GTK_ORIENTATIONCHOOSER_H #include #include G_BEGIN_DECLS /** * VISU_TYPE_UI_ORIENTATION_CHOOSER: * * Return the associated #GType to the VisuUiOrientationChooser objects. */ #define VISU_TYPE_UI_ORIENTATION_CHOOSER (visu_ui_orientation_chooser_get_type ()) /** * VISU_UI_ORIENTATION_CHOOSER: * @obj: the widget to cast. * * Cast the given object to a #VisuUiOrientationChooser object. */ #define VISU_UI_ORIENTATION_CHOOSER(obj) (G_TYPE_CHECK_INSTANCE_CAST ((obj), VISU_TYPE_UI_ORIENTATION_CHOOSER, VisuUiOrientationChooser)) /** * VISU_UI_ORIENTATION_CHOOSER_CLASS: * @klass: the class to cast. * * Cast the given class to a #VisuUiOrientationChooserClass object. */ #define VISU_UI_ORIENTATION_CHOOSER_CLASS(klass) (G_TYPE_CHECK_CLASS_CAST ((klass), VISU_TYPE_UI_ORIENTATION_CHOOSER, VisuUiOrientationChooserClass)) /** * VISU_IS_UI_ORIENTATION_CHOOSER: * @obj: the object to test. * * Return if the given object is a valid #VisuUiOrientationChooser object. */ #define VISU_IS_UI_ORIENTATION_CHOOSER(obj) (G_TYPE_CHECK_INSTANCE_TYPE ((obj), VISU_TYPE_UI_ORIENTATION_CHOOSER)) /** * VISU_IS_UI_ORIENTATION_CHOOSER_CLASS: * @klass: the class to test. * * Return if the given class is a valid #VisuUiOrientationChooserClass class. */ #define VISU_IS_UI_ORIENTATION_CHOOSER_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE ((klass), VISU_TYPE_UI_ORIENTATION_CHOOSER)) typedef struct _VisuUiOrientationChooser VisuUiOrientationChooser; typedef struct _VisuUiOrientationChooserClass VisuUiOrientationChooserClass; /** * VisuUiOrientationChooserKind: * @VISU_UI_ORIENTATION_DIRECTION: this flag specifies that the box coordinates * are used to identity a direction ; * @VISU_UI_ORIENTATION_NORMAL: this flag specifies that the box coordinates * are used to identify a normal direction. * * These values are used when creating an #VisuUiOrientationChooser, to specify the * behavior of the box coordinates. This is due to the fact that the box coordinates * are not always orthoggonal. */ typedef enum { VISU_UI_ORIENTATION_DIRECTION, VISU_UI_ORIENTATION_NORMAL } VisuUiOrientationChooserKind; GType visu_ui_orientation_chooser_get_type (void); GtkWidget* visu_ui_orientation_chooser_new(VisuUiOrientationChooserKind kind, gboolean liveUpdate, VisuBoxed *boxed, GtkWindow *parent); void visu_ui_orientation_chooser_setOrthoValues(VisuUiOrientationChooser *orientation, float values[3]); void visu_ui_orientation_chooser_setBoxValues(VisuUiOrientationChooser *orientation, float values[3]); void visu_ui_orientation_chooser_setAnglesValues(VisuUiOrientationChooser *orientation, float values[2]); void visu_ui_orientation_chooser_getOrthoValues(VisuUiOrientationChooser *orientation, float values[3]); void visu_ui_orientation_chooser_getBoxValues(VisuUiOrientationChooser *orientation, float values[3]); void visu_ui_orientation_chooser_getAnglesValues(VisuUiOrientationChooser *orientation, float values[2]); G_END_DECLS #endif v_sim-3.8.0/src/extraGtkFunctions/gtk_shadeComboBoxWidget.c000066400000000000000000000564011370110300500237760ustar00rootroot00000000000000/* EXTRAITS DE LA LICENCE Copyright CEA, contributeurs : Luc BILLARD et Damien CALISTE, laboratoire L_Sim, (2001-2005) Adresse mèl : BILLARD, non joignable par mèl ; CALISTE, damien P caliste AT cea P fr. Ce logiciel est un programme informatique servant à visualiser des structures atomiques dans un rendu pseudo-3D. Ce logiciel est régi par la licence CeCILL soumise au droit français et respectant les principes de diffusion des logiciels libres. Vous pouvez utiliser, modifier et/ou redistribuer ce programme sous les conditions de la licence CeCILL telle que diffusée par le CEA, le CNRS et l'INRIA sur le site "http://www.cecill.info". Le fait que vous puissiez accéder à cet en-tête signifie que vous avez pris connaissance de la licence CeCILL, et que vous en avez accepté les termes (cf. le fichier Documentation/licence.fr.txt fourni avec ce logiciel). */ /* LICENCE SUM UP Copyright CEA, contributors : Luc BILLARD et Damien CALISTE, laboratoire L_Sim, (2001-2005) E-mail address: BILLARD, not reachable any more ; CALISTE, damien P caliste AT cea P fr. This software is a computer program whose purpose is to visualize atomic configurations in 3D. This software is governed by the CeCILL license under French law and abiding by the rules of distribution of free software. You can use, modify and/ or redistribute the software under the terms of the CeCILL license as circulated by CEA, CNRS and INRIA at the following URL "http://www.cecill.info". The fact that you are presently reading this means that you have had knowledge of the CeCILL license and that you accept its terms. You can find a copy of this licence shipped with this software at Documentation/licence.en.txt. */ #include #include "gtk_shadeComboBoxWidget.h" #include #include #include /** * SECTION:gtk_shadeComboBoxWidget * @short_description: Defines a specialised #GtkComboBox to choose * pre-built shades. * @see_also: #VisuUiStippleCombobox, #ToolShade * @include: coreTools/toolShade.h * * This widget looks like a #GtkComboBox and it displays a list * of preset colour shades. These patterns are defined by colour * parameters, see #ToolShade. * This widget can emit a #VisuUiShadeCombobox::shade-selected * signal that is a wrapper around the #GtkComboBox::changed signal, * but it is emitted only when a new shade is selected and this shade * is passed to the callback. * * Since: 3.3 */ enum { SHADE_SELECTED_SIGNAL, LAST_SIGNAL }; enum { PROP_0, SHADE_PROP, N_PROP }; static GParamSpec *properties[N_PROP]; /* This enum is used to access the column of the GtkListStore that contains the informations of stroed shades. */ enum { /* This has a pointer to a 48x16 image to represent the shade. */ COLUMN_SHADE_PIXBUF, /* This is a pointer to a label that describes the shade. */ COLUMN_SHADE_LABEL, /* This is a label with the shade id '(n)'. */ COLUMN_SHADE_ID, /* This a pointer to the #ToolShade as defined in toolShade.h */ COLUMN_SHADE_POINTER_TO, N_COLUMN_SHADE }; /* Store a tree model to remember shades. */ #define SHADE_BOX_WIDTH 48 #define SHADE_BOX_HEIGHT 16 #define SHADE_BOX_BITS 8 /* Entries in the parameter file. */ #define FLAG_PARAMETER_FAVSHADE "presetShade" #define DESC_PARAMETER_FAVSHADE "The id of a shade used as preset one in the shade selectors ; an integer ranging from 0" #define PARAMETER_FAVSHADE_DEFAULT 0 static void visu_ui_shade_combobox_dispose (GObject *obj); static void visu_ui_shade_combobox_finalize(GObject *obj); static void visu_ui_shade_combobox_get_property(GObject* obj, guint property_id, GValue *value, GParamSpec *pspec); static void visu_ui_shade_combobox_set_property(GObject* obj, guint property_id, const GValue *value, GParamSpec *pspec); static guint visu_ui_shade_combobox_signals[LAST_SIGNAL] = { 0 }; /** * VisuUiShadeCombobox * * Private structure to store informations of a #VisuUiShadeCombobox object. * * Since: 3.3 */ struct _VisuUiShadeCombobox { GtkComboBox comboToolShade; ToolShade* previouslySelectedToolShade; gboolean hasAlphaChannel; /* Memory gestion. */ gboolean dispose_has_run; }; /** * VisuUiShadeComboboxClass * * Private structure to store informations of a #VisuUiShadeComboboxClass object. * * Since: 3.3 */ struct _VisuUiShadeComboboxClass { GtkComboBoxClass parent_class; void (*shadeComboBox) (VisuUiShadeCombobox *shadeCombo); /* This listStore contains all the shades known by widgets of this class. It is used as TreeModel for the combobox in the widget. */ GtkListStore *listStoredToolShades; guint favToolShade; }; static VisuUiShadeComboboxClass *my_class = (VisuUiShadeComboboxClass*)0; /* Local callbacks. */ static void visu_ui_shade_combobox_changed(GtkWidget *widget, VisuUiShadeCombobox *shadeComboBox); /* Local methods. */ static void addToolShadeToModel(GtkTreeIter *iter, VisuUiShadeComboboxClass* klass, ToolShade* shade); static void onNewShadeAvailable(ToolPool *obj, ToolShade* newColor, gpointer data); static void buildWidgets(VisuUiShadeCombobox *shadeComboBox, gboolean showNames); static void exportParameters(GString *data, VisuData* dataObj); /** * visu_ui_shade_combobox_get_type * * #GType are unique numbers to identify objects. * * Returns: the #GType associated with #VisuUiShadeCombobox objects. * * Since: 3.3 */ G_DEFINE_TYPE(VisuUiShadeCombobox, visu_ui_shade_combobox, GTK_TYPE_COMBO_BOX) static void visu_ui_shade_combobox_class_init(VisuUiShadeComboboxClass *klass) { GtkTreeIter iter; GList *shadeLst; VisuConfigFileEntry *resourceEntry; int rgShade[2] = {0, 128}; DBG_fprintf(stderr, "Gtk VisuUiShadeCombobox: creating the class of the widget.\n"); DBG_fprintf(stderr, " - adding new signals ;\n"); /** * VisuUiShadeCombobox::shade-selected: * @combo: the #VisuUiShadeCombobox that emits the signal ; * @shade: the newly selected #ToolShade. * * This signal is emitted when a new valid colour shade is selected. * * Since: 3.3 */ visu_ui_shade_combobox_signals[SHADE_SELECTED_SIGNAL] = g_signal_new ("shade-selected", G_TYPE_FROM_CLASS (klass), G_SIGNAL_RUN_FIRST | G_SIGNAL_ACTION, G_STRUCT_OFFSET (VisuUiShadeComboboxClass, shadeComboBox), NULL, NULL, g_cclosure_marshal_VOID__POINTER, G_TYPE_NONE, 1, G_TYPE_POINTER); g_signal_connect(tool_shade_getStorage(), "new-element", G_CALLBACK(onNewShadeAvailable), (gpointer)klass); DBG_fprintf(stderr, " - initializing the listStore of shades.\n"); /* Init the listStore of shades. */ klass->listStoredToolShades = gtk_list_store_new(N_COLUMN_SHADE, GDK_TYPE_PIXBUF, G_TYPE_STRING, G_TYPE_STRING, G_TYPE_POINTER); for (shadeLst = tool_pool_asList(tool_shade_getStorage()); shadeLst; shadeLst = g_list_next(shadeLst)) addToolShadeToModel(&iter, klass, (ToolShade*)shadeLst->data); klass->favToolShade = 0; /* Dealing with parameters. */ resourceEntry = visu_config_file_addIntegerArrayEntry(VISU_CONFIG_FILE_PARAMETER, FLAG_PARAMETER_FAVSHADE, DESC_PARAMETER_FAVSHADE, 1, (int*)&klass->favToolShade, rgShade, FALSE); visu_config_file_entry_setVersion(resourceEntry, 3.5f); visu_config_file_addExportFunction(VISU_CONFIG_FILE_PARAMETER, exportParameters); /* Connect freeing methods. */ G_OBJECT_CLASS(klass)->dispose = visu_ui_shade_combobox_dispose; G_OBJECT_CLASS(klass)->finalize = visu_ui_shade_combobox_finalize; G_OBJECT_CLASS(klass)->set_property = visu_ui_shade_combobox_set_property; G_OBJECT_CLASS(klass)->get_property = visu_ui_shade_combobox_get_property; /** * VisuUiShadeCombobox::shade: * * Store the shade of the current selection. * * Since: 3.8 */ properties[SHADE_PROP] = g_param_spec_boxed("shade", "Shade", "shade of the current selection", TOOL_TYPE_SHADE, G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS); g_object_class_install_property(G_OBJECT_CLASS(klass), SHADE_PROP, properties[SHADE_PROP]); my_class = klass; } static void visu_ui_shade_combobox_dispose(GObject *obj) { DBG_fprintf(stderr, "Gtk VisuUiShadeCombobox: dispose object %p.\n", (gpointer)obj); if (VISU_UI_SHADE_COMBOBOX(obj)->dispose_has_run) return; VISU_UI_SHADE_COMBOBOX(obj)->dispose_has_run = TRUE; /* Chain up to the parent class */ G_OBJECT_CLASS(visu_ui_shade_combobox_parent_class)->dispose(obj); } static void visu_ui_shade_combobox_finalize(GObject *obj) { g_return_if_fail(obj); DBG_fprintf(stderr, "Gtk VisuUiShadeCombobox: finalize object %p.\n", (gpointer)obj); /* Chain up to the parent class */ G_OBJECT_CLASS(visu_ui_shade_combobox_parent_class)->finalize(obj); DBG_fprintf(stderr, " | freeing ... OK.\n"); } static void visu_ui_shade_combobox_get_property(GObject* obj, guint property_id, GValue *value, GParamSpec *pspec) { VisuUiShadeCombobox *self = VISU_UI_SHADE_COMBOBOX(obj); DBG_fprintf(stderr, "Gtk VisuUiShadeCombobox: get property '%s'.\n", g_param_spec_get_name(pspec)); switch (property_id) { case SHADE_PROP: g_value_set_static_boxed(value, visu_ui_shade_combobox_getSelection(self)); break; default: /* We don't have any other property... */ G_OBJECT_WARN_INVALID_PROPERTY_ID(obj, property_id, pspec); break; } } static void visu_ui_shade_combobox_set_property(GObject* obj, guint property_id, const GValue *value, GParamSpec *pspec) { VisuUiShadeCombobox *self = VISU_UI_SHADE_COMBOBOX(obj); DBG_fprintf(stderr, "Gtk VisuUiShadeCombobox: set property '%s'.\n", g_param_spec_get_name(pspec)); switch (property_id) { case SHADE_PROP: if (!visu_ui_shade_combobox_setSelectionByShade(self, (ToolShade*)g_value_get_boxed(value))) gtk_combo_box_set_active(GTK_COMBO_BOX(obj), -1); break; default: /* We don't have any other property... */ G_OBJECT_WARN_INVALID_PROPERTY_ID(obj, property_id, pspec); break; } } static void visu_ui_shade_combobox_init(VisuUiShadeCombobox *shadeComboBox) { DBG_fprintf(stderr, "Gtk VisuUiShadeCombobox: initializing new object (%p).\n", (gpointer)shadeComboBox); shadeComboBox->hasAlphaChannel = TRUE; shadeComboBox->dispose_has_run = FALSE; shadeComboBox->previouslySelectedToolShade = (ToolShade*)0; } static void buildWidgets(VisuUiShadeCombobox *shadeComboBox, gboolean showNames) { GObjectClass *klass; GtkCellRenderer *renderer; klass = G_OBJECT_GET_CLASS(shadeComboBox); gtk_combo_box_set_model(GTK_COMBO_BOX(shadeComboBox), GTK_TREE_MODEL(VISU_UI_SHADE_COMBOBOX_CLASS(klass)->listStoredToolShades)); renderer = gtk_cell_renderer_pixbuf_new(); gtk_cell_layout_pack_start(GTK_CELL_LAYOUT(shadeComboBox), renderer, FALSE); gtk_cell_layout_add_attribute(GTK_CELL_LAYOUT(shadeComboBox), renderer, "pixbuf", COLUMN_SHADE_PIXBUF); if (showNames) { renderer = gtk_cell_renderer_text_new(); g_object_set(G_OBJECT(renderer), "foreground", "#505050", "xpad", 0, "align-set", TRUE, "xalign", 1.0, NULL); gtk_cell_layout_pack_end(GTK_CELL_LAYOUT(shadeComboBox), renderer, FALSE); gtk_cell_layout_add_attribute(GTK_CELL_LAYOUT(shadeComboBox), renderer, "markup", COLUMN_SHADE_ID); renderer = gtk_cell_renderer_text_new(); /* g_object_set(G_OBJECT(renderer), "scale", 0.85, NULL); */ gtk_cell_layout_pack_start(GTK_CELL_LAYOUT(shadeComboBox), renderer, TRUE); gtk_cell_layout_add_attribute(GTK_CELL_LAYOUT(shadeComboBox), renderer, "text", COLUMN_SHADE_LABEL); } if ((gint)VISU_UI_SHADE_COMBOBOX_CLASS(klass)->favToolShade < gtk_tree_model_iter_n_children (GTK_TREE_MODEL(VISU_UI_SHADE_COMBOBOX_CLASS(klass)->listStoredToolShades), (GtkTreeIter*)0)) gtk_combo_box_set_active(GTK_COMBO_BOX(shadeComboBox), VISU_UI_SHADE_COMBOBOX_CLASS(klass)->favToolShade); else gtk_combo_box_set_active(GTK_COMBO_BOX(shadeComboBox), -1); g_signal_connect(G_OBJECT(shadeComboBox), "changed", G_CALLBACK(visu_ui_shade_combobox_changed), (gpointer)shadeComboBox); } /** * visu_ui_shade_combobox_new : * @hasAlphaChannel : a boolean. * @showNames: if TRUE, the names of the shades are displayed. * * A #VisuUiShadeCombobox widget is like a #GtkComboBox widget, but it is already filled * with the known shades. Using this widget * is a convienient way to share shades between all part of V_Sim and to give a consistent * look of all shade selection. If the argument @hasAlphaChannel is FALSE, the widget * display all shades but without their alpha channel, assuming it to be fully opaque. * * Returns: (transfer full): a newly created #VisuUiShadeCombobox widget. * * Since: 3.3 */ GtkWidget* visu_ui_shade_combobox_new(gboolean hasAlphaChannel, gboolean showNames) { VisuUiShadeCombobox *shadeComboBox; DBG_fprintf(stderr, "Gtk VisuUiShadeCombobox: creating new object with alpha: %d.\n", hasAlphaChannel); shadeComboBox = VISU_UI_SHADE_COMBOBOX(g_object_new(visu_ui_shade_combobox_get_type (), NULL)); shadeComboBox->hasAlphaChannel = hasAlphaChannel; DBG_fprintf(stderr, "Gtk VisuUiShadeCombobox: build widgets.\n"); buildWidgets(shadeComboBox, showNames); return GTK_WIDGET(shadeComboBox); } static void visu_ui_shade_combobox_changed(GtkWidget *widget _U_, VisuUiShadeCombobox *shadeComboBox) { int selected; GtkTreeIter iter; GObjectClass *klass; ToolShade *shade; selected = gtk_combo_box_get_active(GTK_COMBO_BOX(shadeComboBox)); DBG_fprintf(stderr, "Gtk VisuUiShadeCombobox: internal combobox changed signal -> %d.\n", selected); if (selected < 0) { shadeComboBox->previouslySelectedToolShade = (ToolShade*)0; /* DBG_fprintf(stderr, "Gtk VisuUiShadeCombobox: emitting 'shade-selected' signal.\n"); */ /* g_signal_emit(G_OBJECT(shadeComboBox), */ /* visu_ui_shade_combobox_signals[SHADE_SELECTED_SIGNAL], 0, (gpointer)0, NULL); */ return; } gtk_combo_box_get_active_iter(GTK_COMBO_BOX(shadeComboBox), &iter); klass = G_OBJECT_GET_CLASS(shadeComboBox); gtk_tree_model_get(GTK_TREE_MODEL(VISU_UI_SHADE_COMBOBOX_CLASS(klass)->listStoredToolShades), &iter, COLUMN_SHADE_POINTER_TO, &shade, -1); if (shade != shadeComboBox->previouslySelectedToolShade) { shadeComboBox->previouslySelectedToolShade = shade; DBG_fprintf(stderr, "Gtk VisuUiShadeCombobox: emitting 'shade-selected' signal for shade (%p).\n", (gpointer)shade); g_object_notify_by_pspec(G_OBJECT(shadeComboBox), properties[SHADE_PROP]); g_signal_emit(G_OBJECT(shadeComboBox), visu_ui_shade_combobox_signals[SHADE_SELECTED_SIGNAL], 0, (gpointer)shade, NULL); } else DBG_fprintf(stderr, "Gtk VisuUiShadeCombobox: aborting 'shade-selected' signal.\n"); } /** * visu_ui_shade_combobox_buildStamp: * @shade: a #ToolShade object ; * @pixbuf: (inout) (allow-none): an existing pixbuf (can be NULL). * * This method is used to create pixbuf representing shades. If @pixbuf is given, * it must be a valid pixbuf, and the shade is created in it. Otherwise, a new * pixbuf is created. * * Returns: (transfer full): a pixbuf pointer. * * Since: 3.3 */ GdkPixbuf* visu_ui_shade_combobox_buildStamp(ToolShade *shade, GdkPixbuf *pixbuf) { GdkPixbuf *pixbufToolShadeBox; int rowstride, x, y; guchar *pixels, *p; float grey; float **rgbVals; if (!pixbuf) pixbufToolShadeBox = gdk_pixbuf_new(GDK_COLORSPACE_RGB, FALSE, SHADE_BOX_BITS, SHADE_BOX_WIDTH, SHADE_BOX_HEIGHT); else pixbufToolShadeBox = pixbuf; rowstride = gdk_pixbuf_get_rowstride(pixbufToolShadeBox); pixels = gdk_pixbuf_get_pixels(pixbufToolShadeBox); rgbVals = g_malloc(sizeof(float*) * SHADE_BOX_WIDTH); rgbVals[0] = g_malloc(sizeof(float) * SHADE_BOX_WIDTH * 5); for (x = 0; x < SHADE_BOX_WIDTH; x++) { rgbVals[x] = rgbVals[0] + x * 5; rgbVals[x][0] = (float)x / (float)(SHADE_BOX_WIDTH - 1); tool_shade_valueToRGB(shade, &rgbVals[x][1], rgbVals[x][0]); } for (y = 0; y < SHADE_BOX_HEIGHT; y++) for (x = 0; x < SHADE_BOX_WIDTH; x++) { p = pixels + y * rowstride + x * 3; if (x < SHADE_BOX_WIDTH / 2) { if (y < SHADE_BOX_HEIGHT / 2) grey = 0.75; else grey = 0.5; } else { if (y < SHADE_BOX_HEIGHT / 2) grey = 0.5; else grey = 0.75; } p[0] = (guchar)((rgbVals[x][1] * rgbVals[x][4] + (1. - rgbVals[x][4]) * grey) * 255.); p[1] = (guchar)((rgbVals[x][2] * rgbVals[x][4] + (1. - rgbVals[x][4]) * grey) * 255.); p[2] = (guchar)((rgbVals[x][3] * rgbVals[x][4] + (1. - rgbVals[x][4]) * grey) * 255.); } g_free(rgbVals[0]); g_free(rgbVals); return pixbufToolShadeBox; } static void onNewShadeAvailable(ToolPool *obj _U_, ToolShade* newShade, gpointer data) { VisuUiShadeComboboxClass *klass; GtkTreeIter iter; g_return_if_fail(data); DBG_fprintf(stderr, "Gtk VisuUiShadeComboboxClass: catch the 'shadeNewAvailable' signal.\n"); klass = VISU_UI_SHADE_COMBOBOX_CLASS(data); addToolShadeToModel(&iter, klass, newShade); } static void addToolShadeToModel(GtkTreeIter *iter, VisuUiShadeComboboxClass* klass, ToolShade* shade) { GtkTreePath *path; gint *ids; gchar *idLbl; GdkPixbuf *pix; g_return_if_fail(iter && klass && shade); DBG_fprintf(stderr, "Gtk VisuUiShadeCombobox: appending a new shade '%s'.\n", tool_shade_getLabel(shade)); gtk_list_store_append(klass->listStoredToolShades, iter); path = gtk_tree_model_get_path(GTK_TREE_MODEL(klass->listStoredToolShades), iter); ids = gtk_tree_path_get_indices(path); idLbl = g_strdup_printf("(%d)", ids[0]); gtk_tree_path_free(path); pix = visu_ui_shade_combobox_buildStamp(shade, (GdkPixbuf*)0); gtk_list_store_set(klass->listStoredToolShades, iter, COLUMN_SHADE_PIXBUF , pix, COLUMN_SHADE_LABEL , tool_shade_getLabel(shade), COLUMN_SHADE_ID , idLbl, COLUMN_SHADE_POINTER_TO , (gpointer)shade, -1); g_object_unref(G_OBJECT(pix)); g_free(idLbl); DBG_fprintf(stderr, "Gtk VisuUiShadeCombobox: appending a new shade '%s'.\n", tool_shade_getLabel(shade)); } /** * visu_ui_shade_combobox_setSelectionByShade: * @shadeComboBox: a #VisuUiShadeCombobox widget ; * @shade: a #ToolShade object. * * Use this method to set the ComboBox on the given shade. This emits a 'shade-channel' * signal if the shade is changed, which means, a previous shade has been modified, * or a new shade is selected. * * Returns: TRUE if the @shade already exists in the model. * * Since: 3.3 */ gboolean visu_ui_shade_combobox_setSelectionByShade(VisuUiShadeCombobox* shadeComboBox, ToolShade *shade) { GtkTreeIter iter; gboolean validIter; GObjectClass *klass; GtkListStore *model; ToolShade *tmpToolShade; g_return_val_if_fail(VISU_IS_UI_SHADE_COMBOBOX(shadeComboBox), FALSE); DBG_fprintf(stderr, "Gtk VisuUiShadeCombobox: select a new shade %p.\n", (gpointer)shade); if (!shade) { gtk_combo_box_set_active(GTK_COMBO_BOX(shadeComboBox), -1); return TRUE; } klass = G_OBJECT_GET_CLASS(shadeComboBox); model = GTK_LIST_STORE(VISU_UI_SHADE_COMBOBOX_CLASS(klass)->listStoredToolShades); for (validIter = gtk_tree_model_get_iter_first(GTK_TREE_MODEL(model), &iter); validIter; validIter = gtk_tree_model_iter_next(GTK_TREE_MODEL(model), &iter)) { gtk_tree_model_get(GTK_TREE_MODEL(model), &iter, COLUMN_SHADE_POINTER_TO, &tmpToolShade, -1); if (tmpToolShade == shade || tool_shade_compare(tmpToolShade, shade)) { gtk_combo_box_set_active_iter(GTK_COMBO_BOX(shadeComboBox), &iter); return TRUE; } } return FALSE; } GdkPixbuf* shadeComboBoxGet_selectedPixbuf(VisuUiShadeCombobox *shadeComboBox) { gboolean validIter; GtkTreeIter iter; GdkPixbuf *pixbuf; GObjectClass *klass; g_return_val_if_fail(VISU_IS_UI_SHADE_COMBOBOX(shadeComboBox), (GdkPixbuf*)0); validIter = gtk_combo_box_get_active_iter(GTK_COMBO_BOX(shadeComboBox), &iter); if (!validIter) return (GdkPixbuf*)0; pixbuf = (GdkPixbuf*)0; klass = G_OBJECT_GET_CLASS(shadeComboBox); gtk_tree_model_get(GTK_TREE_MODEL(VISU_UI_SHADE_COMBOBOX_CLASS(klass)->listStoredToolShades), &iter, COLUMN_SHADE_PIXBUF, &pixbuf, -1); return pixbuf; } /** * visu_ui_shade_combobox_getSelection: * @shadeComboBox: a #VisuUiShadeCombobox widget. * * The user can access to the selected #ToolShade object using this method. * * Returns: (transfer none): a pointer to the selected #ToolShade * object (or NULL). This object is read-only. * * Since: 3.3 */ ToolShade* visu_ui_shade_combobox_getSelection(VisuUiShadeCombobox *shadeComboBox) { gboolean validIter; GtkTreeIter iter; ToolShade *shade; GObjectClass *klass; g_return_val_if_fail(VISU_IS_UI_SHADE_COMBOBOX(shadeComboBox), (ToolShade*)0); validIter = gtk_combo_box_get_active_iter(GTK_COMBO_BOX(shadeComboBox), &iter); if (!validIter) return (ToolShade*)0; shade = (ToolShade*)0; klass = G_OBJECT_GET_CLASS(shadeComboBox); gtk_tree_model_get(GTK_TREE_MODEL(VISU_UI_SHADE_COMBOBOX_CLASS(klass)->listStoredToolShades), &iter, COLUMN_SHADE_POINTER_TO, &shade, -1); return shade; } /** * visu_ui_shade_combobox_getStamp: * @shadeComboBox: a #VisuUiShadeCombobox widget ; * @shade: a #ToolShade object. * * The @shadeComboBox has little pixbufs to represent the shade. User methods can * use these pixbufs but should considered them read-only. * * Returns: (transfer none): a pixbuf pointer corresponding to the * little image shown on the @shadeComboBox. * * Since: 3.3 */ GdkPixbuf* visu_ui_shade_combobox_getStamp(VisuUiShadeCombobox *shadeComboBox, ToolShade *shade) { GtkTreeIter iter; gboolean validIter; GdkPixbuf *pixbuf; ToolShade *cl; GtkListStore *model; g_return_val_if_fail(VISU_IS_UI_SHADE_COMBOBOX(shadeComboBox) && shade, (GdkPixbuf*)0); model = VISU_UI_SHADE_COMBOBOX_CLASS(G_OBJECT_GET_CLASS(shadeComboBox))->listStoredToolShades; validIter = gtk_tree_model_get_iter_first(GTK_TREE_MODEL(model), &iter); while (validIter) { pixbuf = (GdkPixbuf*)0; cl = (ToolShade*)0; gtk_tree_model_get(GTK_TREE_MODEL(model), &iter, COLUMN_SHADE_PIXBUF, &pixbuf, COLUMN_SHADE_POINTER_TO, &cl, -1); if (shade == cl) return pixbuf; validIter = gtk_tree_model_iter_next(GTK_TREE_MODEL(model), &iter); } return (GdkPixbuf*)0; } static void exportParameters(GString *data, VisuData* dataObj _U_) { g_return_if_fail(my_class); g_string_append_printf(data, "# %s\n", DESC_PARAMETER_FAVSHADE); g_string_append_printf(data, "%s[gtk]: %d\n\n", FLAG_PARAMETER_FAVSHADE, my_class->favToolShade); } v_sim-3.8.0/src/extraGtkFunctions/gtk_shadeComboBoxWidget.h000066400000000000000000000076371370110300500240120ustar00rootroot00000000000000/* EXTRAITS DE LA LICENCE Copyright CEA, contributeurs : Luc BILLARD et Damien CALISTE, laboratoire L_Sim, (2001-2005) Adresse mèl : BILLARD, non joignable par mèl ; CALISTE, damien P caliste AT cea P fr. Ce logiciel est un programme informatique servant à visualiser des structures atomiques dans un rendu pseudo-3D. Ce logiciel est régi par la licence CeCILL soumise au droit français et respectant les principes de diffusion des logiciels libres. Vous pouvez utiliser, modifier et/ou redistribuer ce programme sous les conditions de la licence CeCILL telle que diffusée par le CEA, le CNRS et l'INRIA sur le site "http://www.cecill.info". Le fait que vous puissiez accéder à cet en-tête signifie que vous avez pris connaissance de la licence CeCILL, et que vous en avez accepté les termes (cf. le fichier Documentation/licence.fr.txt fourni avec ce logiciel). */ /* LICENCE SUM UP Copyright CEA, contributors : Luc BILLARD et Damien CALISTE, laboratoire L_Sim, (2001-2005) E-mail address: BILLARD, not reachable any more ; CALISTE, damien P caliste AT cea P fr. This software is a computer program whose purpose is to visualize atomic configurations in 3D. This software is governed by the CeCILL license under French law and abiding by the rules of distribution of free software. You can use, modify and/ or redistribute the software under the terms of the CeCILL license as circulated by CEA, CNRS and INRIA at the following URL "http://www.cecill.info". The fact that you are presently reading this means that you have had knowledge of the CeCILL license and that you accept its terms. You can find a copy of this licence shipped with this software at Documentation/licence.en.txt. */ #ifndef GTK_SHADECOMBOBOXWIDGET_H #define GTK_SHADECOMBOBOXWIDGET_H #include #include #include #include G_BEGIN_DECLS /** * VISU_TYPE_UI_SHADE_COMBOBOX: * * Return: the associated #GType to the VisuUiShadeCombobox objects. * * Since: 3.3 */ #define VISU_TYPE_UI_SHADE_COMBOBOX (visu_ui_shade_combobox_get_type ()) /** * VISU_UI_SHADE_COMBOBOX: * @obj: the widget to cast. * * Cast the given object to a #VisuUiShadeCombobox object. * * Since: 3.3 */ #define VISU_UI_SHADE_COMBOBOX(obj) (G_TYPE_CHECK_INSTANCE_CAST ((obj), VISU_TYPE_UI_SHADE_COMBOBOX, VisuUiShadeCombobox)) /** * VISU_UI_SHADE_COMBOBOX_CLASS: * @klass: the class to cast. * * Cast the given class to a #VisuUiShadeComboboxClass object. * * Since: 3.3 */ #define VISU_UI_SHADE_COMBOBOX_CLASS(klass) (G_TYPE_CHECK_CLASS_CAST ((klass), VISU_TYPE_UI_SHADE_COMBOBOX, VisuUiShadeComboboxClass)) /** * VISU_IS_UI_SHADE_COMBOBOX: * @obj: the object to test. * * Get if the given object is a valid #VisuUiShadeCombobox object. * * Since: 3.3 */ #define VISU_IS_UI_SHADE_COMBOBOX(obj) (G_TYPE_CHECK_INSTANCE_TYPE ((obj), VISU_TYPE_UI_SHADE_COMBOBOX)) /** * VISU_IS_UI_SHADE_COMBOBOX_CLASS: * @klass: the class to test. * * Get if the given class is a valid #VisuUiShadeComboboxClass class. * * Since: 3.3 */ #define VISU_IS_UI_SHADE_COMBOBOX_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE ((klass), VISU_TYPE_UI_SHADE_COMBOBOX)) typedef struct _VisuUiShadeCombobox VisuUiShadeCombobox; typedef struct _VisuUiShadeComboboxClass VisuUiShadeComboboxClass; GType visu_ui_shade_combobox_get_type(void); GtkWidget* visu_ui_shade_combobox_new(gboolean hasAlphaChannel, gboolean showNames); gboolean visu_ui_shade_combobox_setSelectionByShade(VisuUiShadeCombobox* shadeComboBox, ToolShade *shade); ToolShade* visu_ui_shade_combobox_getSelection(VisuUiShadeCombobox *shadeComboBox); GdkPixbuf* visu_ui_shade_combobox_getStamp(VisuUiShadeCombobox *shadeComboBox, ToolShade *shade); GdkPixbuf* visu_ui_shade_combobox_buildStamp(ToolShade *shade, GdkPixbuf *pixbuf); G_END_DECLS #endif v_sim-3.8.0/src/extraGtkFunctions/gtk_stippleComboBoxWidget.c000066400000000000000000000500531370110300500243670ustar00rootroot00000000000000/* EXTRAITS DE LA LICENCE Copyright CEA, contributeurs : Luc BILLARD et Damien CALISTE, laboratoire L_Sim, (2001-2005) Adresse mèl : BILLARD, non joignable par mèl ; CALISTE, damien P caliste AT cea P fr. Ce logiciel est un programme informatique servant à visualiser des structures atomiques dans un rendu pseudo-3D. Ce logiciel est régi par la licence CeCILL soumise au droit français et respectant les principes de diffusion des logiciels libres. Vous pouvez utiliser, modifier et/ou redistribuer ce programme sous les conditions de la licence CeCILL telle que diffusée par le CEA, le CNRS et l'INRIA sur le site "http://www.cecill.info". Le fait que vous puissiez accéder à cet en-tête signifie que vous avez pris connaissance de la licence CeCILL, et que vous en avez accepté les termes (cf. le fichier Documentation/licence.fr.txt fourni avec ce logiciel). */ /* LICENCE SUM UP Copyright CEA, contributors : Luc BILLARD et Damien CALISTE, laboratoire L_Sim, (2001-2005) E-mail address: BILLARD, not reachable any more ; CALISTE, damien P caliste AT cea P fr. This software is a computer program whose purpose is to visualize atomic configurations in 3D. This software is governed by the CeCILL license under French law and abiding by the rules of distribution of free software. You can use, modify and/ or redistribute the software under the terms of the CeCILL license as circulated by CEA, CNRS and INRIA at the following URL "http://www.cecill.info". The fact that you are presently reading this means that you have had knowledge of the CeCILL license and that you accept its terms. You can find a copy of this licence shipped with this software at Documentation/licence.en.txt. */ #include #include "gtk_stippleComboBoxWidget.h" #include /** * SECTION:gtk_stippleComboBoxWidget * @short_description: Defines a specialised #GtkComboBox to choose * patterns for lines. * @see_also: #VisuUiShadeCombobox * * This widget looks like a #GtkComboBox and it displays a list * of preset patterns for line. These patterns are defined by a * guint16 value that is given to OpenGL for line stipple. * This widget can emit a #VisuUiStippleCombobox::stipple-selected * signal that is a wrapper around the #GtkComboBox::changed signal, * but it is emitted only when a stipple is selected and this stipple * is passed to the call back. * * Since: 3.4 */ enum { STIPPLE_SELECTED_SIGNAL, LAST_SIGNAL }; static guint signals[LAST_SIGNAL] = { 0 }; enum { PROP_0, VALUE_PROP, N_PROP }; static GParamSpec *properties[N_PROP]; /* This enum is used to access the column of the GtkListStore that contains the informations of stroed shades. */ enum { /* This has a pointer to an image to represent the stipple. */ COLUMN_STIPPLE_PIXBUF, /* This is a pointer to a label that describes the stipple. */ COLUMN_STIPPLE_LABEL, /* This is the value of the stipple. */ COLUMN_STIPPLE_VALUE, N_COLUMN_STIPPLE }; /* Store a tree model to remember stipples. */ #define STIPPLE_BOX_WIDTH 32 #define STIPPLE_BOX_HEIGHT 3 #define STIPPLE_BOX_BITS 8 static void visu_ui_stipple_combobox_dispose (GObject *obj); static void visu_ui_stipple_combobox_finalize(GObject *obj); static void visu_ui_stipple_combobox_get_property(GObject* obj, guint property_id, GValue *value, GParamSpec *pspec); static void visu_ui_stipple_combobox_set_property(GObject* obj, guint property_id, const GValue *value, GParamSpec *pspec); /** * VisuUiStippleCombobox: * * Private structure to store informations of a #VisuUiStippleCombobox object. * * Since: 3.4 */ struct _VisuUiStippleCombobox { GtkComboBox comboStipple; guint16 previousStipple; /* Memory gestion. */ gboolean dispose_has_run; }; /** * VisuUiStippleComboboxClass * * Private structure to store informations of a #VisuUiStippleComboboxClass object. * * Since: 3.4 */ struct _VisuUiStippleComboboxClass { GtkComboBoxClass parent_class; void (*stippleComboBox) (VisuUiStippleCombobox *stippleCombo); /* This listStore contains all the stipples known by widgets of this class. It is used as TreeModel for the combobox in the widget. */ GtkListStore *listStoredStipples; gulong stippleAddedSignalId; }; /* Built-in stipple values. */ static guint16 builtInStipples[] = {65535, 43690, 52428, 61680, 65280, 58596, 57568, 49344, 65340, 0}; /* Local callbacks. */ static void visu_ui_stipple_combobox_changed(VisuUiStippleCombobox *stippleComboBox, gpointer data _U_); /* Local methods. */ static void addStippleToModel(GtkTreeIter *iter, VisuUiStippleComboboxClass* klass, guint16 value); static void buildWidgets(VisuUiStippleCombobox *stippleComboBox); /** * visu_ui_stipple_combobox_get_type * * #GType are unique numbers to identify objects. * * Returns: the #GType associated with #VisuUiStippleCombobox objects. * * Since: 3.4 */ G_DEFINE_TYPE(VisuUiStippleCombobox, visu_ui_stipple_combobox, GTK_TYPE_COMBO_BOX) static void visu_ui_stipple_combobox_class_init(VisuUiStippleComboboxClass *klass) { GtkTreeIter iter; int i; DBG_fprintf(stderr, "Gtk VisuUiStippleCombobox: creating the class of the widget.\n"); DBG_fprintf(stderr, " - adding new signals ;\n"); /** * VisuUiStippleCombobox::stipple-selected: * @combo: the #VisuUiStippleCombobox that emits the signal ; * @stipple: the value of the newly selected line patter. * * This signal is emitted when a new valid line pattern is selected. * * Since: 3.4 */ signals[STIPPLE_SELECTED_SIGNAL] = g_signal_new ("stipple-selected", G_TYPE_FROM_CLASS (klass), G_SIGNAL_RUN_FIRST | G_SIGNAL_ACTION, G_STRUCT_OFFSET (VisuUiStippleComboboxClass, stippleComboBox), NULL, NULL, g_cclosure_marshal_VOID__UINT, G_TYPE_NONE, 1, G_TYPE_UINT); DBG_fprintf(stderr, " - initializing the listStore of stipples.\n"); /* Init the listStore of stipples. */ klass->listStoredStipples = gtk_list_store_new(N_COLUMN_STIPPLE, GDK_TYPE_PIXBUF, G_TYPE_STRING, G_TYPE_UINT); for (i = 0; builtInStipples[i]; i++) addStippleToModel(&iter, klass, builtInStipples[i]); /* Connect freeing methods. */ G_OBJECT_CLASS(klass)->dispose = visu_ui_stipple_combobox_dispose; G_OBJECT_CLASS(klass)->finalize = visu_ui_stipple_combobox_finalize; G_OBJECT_CLASS(klass)->set_property = visu_ui_stipple_combobox_set_property; G_OBJECT_CLASS(klass)->get_property = visu_ui_stipple_combobox_get_property; /** * VisuUiStippleCombobox::value: * * Store the current stipple. * * Since: 3.8 */ properties[VALUE_PROP] = g_param_spec_uint("value", "stipple value", "stipple pattern for OpenGL", 0, 65535, (guint)builtInStipples[0], G_PARAM_READWRITE); g_object_class_install_property(G_OBJECT_CLASS(klass), VALUE_PROP, properties[VALUE_PROP]); } static void visu_ui_stipple_combobox_dispose(GObject *obj) { DBG_fprintf(stderr, "Gtk VisuUiStippleCombobox: dispose object %p.\n", (gpointer)obj); if (VISU_UI_STIPPLE_COMBOBOX(obj)->dispose_has_run) return; VISU_UI_STIPPLE_COMBOBOX(obj)->dispose_has_run = TRUE; /* Chain up to the parent class */ DBG_fprintf(stderr, " | chain to parent\n"); G_OBJECT_CLASS(visu_ui_stipple_combobox_parent_class)->dispose(obj); DBG_fprintf(stderr, " | disposing ... OK.\n"); } static void visu_ui_stipple_combobox_finalize(GObject *obj) { g_return_if_fail(obj); DBG_fprintf(stderr, "Gtk VisuUiStippleCombobox: finalize object %p.\n", (gpointer)obj); /* Chain up to the parent class */ G_OBJECT_CLASS(visu_ui_stipple_combobox_parent_class)->finalize(obj); DBG_fprintf(stderr, " | freeing ... OK.\n"); } static void visu_ui_stipple_combobox_get_property(GObject* obj, guint property_id, GValue *value, GParamSpec *pspec) { guint16 stipple; VisuUiStippleCombobox *self = VISU_UI_STIPPLE_COMBOBOX(obj); DBG_fprintf(stderr, "Gtk VisuUiStippleCombobox: get property '%s' -> ", g_param_spec_get_name(pspec)); switch (property_id) { case VALUE_PROP: stipple = visu_ui_stipple_combobox_getSelection(self); g_value_set_uint(value, (guint)stipple); DBG_fprintf(stderr, "%d.\n", stipple); break; default: /* We don't have any other property... */ G_OBJECT_WARN_INVALID_PROPERTY_ID(obj, property_id, pspec); break; } } static void visu_ui_stipple_combobox_set_property(GObject* obj, guint property_id, const GValue *value, GParamSpec *pspec) { guint16 stipple; VisuUiStippleCombobox *self = VISU_UI_STIPPLE_COMBOBOX(obj); DBG_fprintf(stderr, "Gtk VisuUiStippleCombobox: set property '%s' -> ", g_param_spec_get_name(pspec)); switch (property_id) { case VALUE_PROP: stipple = (guint16)g_value_get_uint(value); visu_ui_stipple_combobox_set(self, stipple); DBG_fprintf(stderr, "%d.\n", stipple); break; default: /* We don't have any other property... */ G_OBJECT_WARN_INVALID_PROPERTY_ID(obj, property_id, pspec); break; } } static void visu_ui_stipple_combobox_init(VisuUiStippleCombobox *stippleComboBox) { DBG_fprintf(stderr, "Gtk VisuUiStippleCombobox: initializing new object (%p).\n", (gpointer)stippleComboBox); stippleComboBox->previousStipple = (guint16)0; stippleComboBox->dispose_has_run = FALSE; } static void buildWidgets(VisuUiStippleCombobox *stippleComboBox) { GObjectClass *klass; GtkCellRenderer *renderer; klass = G_OBJECT_GET_CLASS(stippleComboBox); gtk_combo_box_set_model(GTK_COMBO_BOX(stippleComboBox), GTK_TREE_MODEL(VISU_UI_STIPPLE_COMBOBOX_CLASS(klass)->listStoredStipples)); renderer = gtk_cell_renderer_pixbuf_new(); gtk_cell_layout_pack_start(GTK_CELL_LAYOUT(stippleComboBox), renderer, FALSE); gtk_cell_layout_add_attribute(GTK_CELL_LAYOUT(stippleComboBox), renderer, "pixbuf", COLUMN_STIPPLE_PIXBUF); /* renderer = gtk_cell_renderer_text_new(); */ /* gtk_cell_layout_pack_start(GTK_CELL_LAYOUT(stippleComboBox), renderer, FALSE); */ /* gtk_cell_layout_add_attribute(GTK_CELL_LAYOUT(stippleComboBox), renderer, */ /* "markup", COLUMN_STIPPLE_LABEL); */ gtk_combo_box_set_active(GTK_COMBO_BOX(stippleComboBox), 0); g_signal_connect(G_OBJECT(stippleComboBox), "changed", G_CALLBACK(visu_ui_stipple_combobox_changed), (gpointer)0); } /** * visu_ui_stipple_combobox_new : * * A #VisuUiStippleCombobox widget is like a #GtkComboBox widget, but it is already filled * with predefined line patterns (call stipple). Using this widget is * a convienient way to share stipples between all part of V_Sim and * to give a consistent look of all stipple selection. * * Returns: (transfer full): a newly created #VisuUiStippleCombobox widget. * * Since: 3.4 */ GtkWidget* visu_ui_stipple_combobox_new() { VisuUiStippleCombobox *stippleComboBox; DBG_fprintf(stderr, "Gtk VisuUiStippleCombobox: creating new object.\n"); stippleComboBox = VISU_UI_STIPPLE_COMBOBOX(g_object_new(VISU_TYPE_UI_STIPPLE_COMBOBOX, NULL)); DBG_fprintf(stderr, "Gtk VisuUiStippleCombobox: build widgets.\n"); buildWidgets(stippleComboBox); return GTK_WIDGET(stippleComboBox); } static void visu_ui_stipple_combobox_changed(VisuUiStippleCombobox *stippleComboBox, gpointer data _U_) { int selected; guint16 stipple; selected = gtk_combo_box_get_active(GTK_COMBO_BOX(stippleComboBox)); DBG_fprintf(stderr, "Gtk VisuUiStippleCombobox: internal combobox changed signal -> %d.\n", selected); if (selected < 0) { stippleComboBox->previousStipple = (guint16)0; /* DBG_fprintf(stderr, "Gtk VisuUiStippleCombobox : emitting 'stipple-selected' signal.\n"); */ /* g_signal_emit(G_OBJECT(stippleComboBox), */ /* signals[STIPPLE_SELECTED_SIGNAL], 0, (gpointer)0, NULL); */ return; } stipple = visu_ui_stipple_combobox_getSelection(stippleComboBox); if (stipple && stipple != stippleComboBox->previousStipple) { stippleComboBox->previousStipple = stipple; DBG_fprintf(stderr, "Gtk VisuUiStippleCombobox: emitting 'stipple-selected'" " signal for value %d.\n", stipple); g_object_notify_by_pspec(G_OBJECT(stippleComboBox), properties[VALUE_PROP]); g_signal_emit(G_OBJECT(stippleComboBox), signals[STIPPLE_SELECTED_SIGNAL], 0, (guint)stipple, NULL); } else DBG_fprintf(stderr, "Gtk VisuUiStippleCombobox: aborting 'stipple-selected' signal.\n"); } /** * visu_ui_stipple_combobox_class_buildStamp: * @stipple: a pattern value. * * This method is used to create pixbuf representing stipples.A new * pixbuf is created. * * Returns: (transfer full): a pixbuf pointer. * * Since: 3.4 */ GdkPixbuf* visu_ui_stipple_combobox_class_buildStamp(guint16 stipple) { GdkPixbuf *pixbufStippleBox; int rowstride, x, y; guchar *pixels, *p; guint16 coul; pixbufStippleBox = gdk_pixbuf_new(GDK_COLORSPACE_RGB, TRUE, STIPPLE_BOX_BITS, STIPPLE_BOX_WIDTH, STIPPLE_BOX_HEIGHT); rowstride = gdk_pixbuf_get_rowstride(pixbufStippleBox); pixels = gdk_pixbuf_get_pixels(pixbufStippleBox); for (x = 0; x < STIPPLE_BOX_WIDTH; x++) { coul = stipple & (1 << ((x+3)%16)); for (y = 0; y < STIPPLE_BOX_HEIGHT; y++) { p = pixels + y * rowstride + x * 4; p[0] = 0; p[1] = 0; p[2] = 0; p[3] = (coul)?255:0; } } return pixbufStippleBox; } void addStippleToModel(GtkTreeIter *iter, VisuUiStippleComboboxClass* klass, guint16 stipple) { GdkPixbuf *pix; gchar *label; g_return_if_fail(iter && klass && stipple); label = g_markup_printf_escaped("(%d)", stipple); pix = visu_ui_stipple_combobox_class_buildStamp(stipple); gtk_list_store_append(klass->listStoredStipples, iter); gtk_list_store_set(klass->listStoredStipples, iter, COLUMN_STIPPLE_PIXBUF, pix, COLUMN_STIPPLE_LABEL, label, COLUMN_STIPPLE_VALUE, (guint)stipple, -1); g_object_unref(pix); g_free(label); DBG_fprintf(stderr, "Gtk VisuUiStippleCombobox: appending a new stipple '%d'.\n", stipple); } /** * visu_ui_stipple_combobox_setSelection: * @stippleComboBox: a #VisuUiStippleCombobox widget ; * @stipple: a pattern value. * * Use this method to set the ComboBox on the given stipple. This emits a 'stipple-channel' * signal if the stipple is changed, which means, a previous stipple has been modified, * or a new stipple is selected. * * Returns: TRUE if the @stipple already exists in the model. * * Since: 3.4 */ gboolean visu_ui_stipple_combobox_setSelection(VisuUiStippleCombobox* stippleComboBox, guint16 stipple) { GtkTreeIter iter; gboolean validIter; GObjectClass *klass; GtkListStore *model; guint tmpStipple; g_return_val_if_fail(stipple && VISU_IS_UI_STIPPLE_COMBOBOX(stippleComboBox), FALSE); DBG_fprintf(stderr, "Gtk VisuUiStippleCombobox: select a new stipple %d.\n", stipple); klass = G_OBJECT_GET_CLASS(stippleComboBox); model = GTK_LIST_STORE(VISU_UI_STIPPLE_COMBOBOX_CLASS(klass)->listStoredStipples); validIter = gtk_tree_model_get_iter_first(GTK_TREE_MODEL(model), &iter); while (validIter) { gtk_tree_model_get(GTK_TREE_MODEL(model), &iter, COLUMN_STIPPLE_VALUE, &tmpStipple, -1); if ((guint16)(tmpStipple) == stipple) { gtk_combo_box_set_active_iter(GTK_COMBO_BOX(stippleComboBox), &iter); return TRUE; } validIter = gtk_tree_model_iter_next(GTK_TREE_MODEL(model), &iter); } return FALSE; } GdkPixbuf* stippleComboBoxGet_selectedPixbuf(VisuUiStippleCombobox *stippleComboBox) { gboolean validIter; GtkTreeIter iter; GdkPixbuf *pixbuf; GObjectClass *klass; g_return_val_if_fail(VISU_IS_UI_STIPPLE_COMBOBOX(stippleComboBox), (GdkPixbuf*)0); validIter = gtk_combo_box_get_active_iter(GTK_COMBO_BOX(stippleComboBox), &iter); if (!validIter) return (GdkPixbuf*)0; pixbuf = (GdkPixbuf*)0; klass = G_OBJECT_GET_CLASS(stippleComboBox); gtk_tree_model_get(GTK_TREE_MODEL(VISU_UI_STIPPLE_COMBOBOX_CLASS(klass)->listStoredStipples), &iter, COLUMN_STIPPLE_PIXBUF, &pixbuf, -1); return pixbuf; } /** * visu_ui_stipple_combobox_getSelection: * @stippleComboBox: a #VisuUiStippleCombobox widget. * * The user can access to the selected stipple pattern using this method. * * Returns: a pattern value (or 65535). * * Since: 3.4 */ guint16 visu_ui_stipple_combobox_getSelection(VisuUiStippleCombobox *stippleComboBox) { gboolean validIter; GtkTreeIter iter; guint stipple; GObjectClass *klass; g_return_val_if_fail(VISU_IS_UI_STIPPLE_COMBOBOX(stippleComboBox), (guint16)0); validIter = gtk_combo_box_get_active_iter(GTK_COMBO_BOX(stippleComboBox), &iter); if (!validIter) return (guint16)0; klass = G_OBJECT_GET_CLASS(stippleComboBox); gtk_tree_model_get(GTK_TREE_MODEL(VISU_UI_STIPPLE_COMBOBOX_CLASS(klass)->listStoredStipples), &iter, COLUMN_STIPPLE_VALUE, &stipple, -1); return (guint16)stipple; } /** * visu_ui_stipple_combobox_getStamp: * @stippleComboBox: a #VisuUiStippleCombobox widget ; * @stipple: a pattern value. * * The @stippleComboBox has little pixbufs to represent the stipple. User methods can * use these pixbufs but should considered them read-only. * * Returns: (transfer none): a pixbuf pointer corresponding to the * little image shown on the @stippleComboBox. * * Since: 3.4 */ GdkPixbuf* visu_ui_stipple_combobox_getStamp(VisuUiStippleCombobox *stippleComboBox, guint16 stipple) { GtkTreeIter iter; gboolean validIter; GdkPixbuf *pixbuf; guint cl; GtkListStore *model; g_return_val_if_fail(VISU_IS_UI_STIPPLE_COMBOBOX(stippleComboBox) && stipple, (GdkPixbuf*)0); model = VISU_UI_STIPPLE_COMBOBOX_CLASS(G_OBJECT_GET_CLASS(stippleComboBox))->listStoredStipples; validIter = gtk_tree_model_get_iter_first(GTK_TREE_MODEL(model), &iter); while (validIter) { pixbuf = (GdkPixbuf*)0; gtk_tree_model_get(GTK_TREE_MODEL(model), &iter, COLUMN_STIPPLE_PIXBUF, &pixbuf, COLUMN_STIPPLE_VALUE, &cl, -1); if (stipple == (guint16)cl) return pixbuf; validIter = gtk_tree_model_iter_next(GTK_TREE_MODEL(model), &iter); } return (GdkPixbuf*)0; } /** * visu_ui_stipple_combobox_add: * @stippleComboBox: a #VisuUiStippleCombobox widget ; * @stipple: a pattern value. * * Create an entry in the ComboBox for the given @stipple pattern if * it does not already exist. * * Since: 3.4 */ void visu_ui_stipple_combobox_add(VisuUiStippleCombobox *stippleComboBox, guint16 stipple) { GtkTreeIter iter; gboolean validIter; GObjectClass *klass; GtkListStore *model; guint tmpStipple; g_return_if_fail(VISU_IS_UI_STIPPLE_COMBOBOX(stippleComboBox)); /* We test if the stipple already exist or not. */ klass = G_OBJECT_GET_CLASS(stippleComboBox); model = GTK_LIST_STORE(VISU_UI_STIPPLE_COMBOBOX_CLASS(klass)->listStoredStipples); validIter = gtk_tree_model_get_iter_first(GTK_TREE_MODEL(model), &iter); while (validIter) { gtk_tree_model_get(GTK_TREE_MODEL(model), &iter, COLUMN_STIPPLE_VALUE, &tmpStipple, -1); if ((guint16)(tmpStipple) == stipple) return ; validIter = gtk_tree_model_iter_next(GTK_TREE_MODEL(model), &iter); } addStippleToModel(&iter, VISU_UI_STIPPLE_COMBOBOX_CLASS(klass), stipple); } /** * visu_ui_stipple_combobox_set: * @stippleComboBox: a #VisuUiStippleCombobox object. * @stipple: a stipple value. * * Select the given stipple, if not exists in the model, add it. See * visu_ui_stipple_combobox_setSelection() for a set method that do * not add. * * Since: 3.8 **/ void visu_ui_stipple_combobox_set(VisuUiStippleCombobox *stippleComboBox, guint16 stipple) { if (!visu_ui_stipple_combobox_setSelection(stippleComboBox, stipple)) { visu_ui_stipple_combobox_add(stippleComboBox, stipple); visu_ui_stipple_combobox_setSelection(stippleComboBox, stipple); } } v_sim-3.8.0/src/extraGtkFunctions/gtk_stippleComboBoxWidget.h000066400000000000000000000077601370110300500244030ustar00rootroot00000000000000/* EXTRAITS DE LA LICENCE Copyright CEA, contributeurs : Luc BILLARD et Damien CALISTE, laboratoire L_Sim, (2001-2005) Adresse mèl : BILLARD, non joignable par mèl ; CALISTE, damien P caliste AT cea P fr. Ce logiciel est un programme informatique servant à visualiser des structures atomiques dans un rendu pseudo-3D. Ce logiciel est régi par la licence CeCILL soumise au droit français et respectant les principes de diffusion des logiciels libres. Vous pouvez utiliser, modifier et/ou redistribuer ce programme sous les conditions de la licence CeCILL telle que diffusée par le CEA, le CNRS et l'INRIA sur le site "http://www.cecill.info". Le fait que vous puissiez accéder à cet en-tête signifie que vous avez pris connaissance de la licence CeCILL, et que vous en avez accepté les termes (cf. le fichier Documentation/licence.fr.txt fourni avec ce logiciel). */ /* LICENCE SUM UP Copyright CEA, contributors : Luc BILLARD et Damien CALISTE, laboratoire L_Sim, (2001-2005) E-mail address: BILLARD, not reachable any more ; CALISTE, damien P caliste AT cea P fr. This software is a computer program whose purpose is to visualize atomic configurations in 3D. This software is governed by the CeCILL license under French law and abiding by the rules of distribution of free software. You can use, modify and/ or redistribute the software under the terms of the CeCILL license as circulated by CEA, CNRS and INRIA at the following URL "http://www.cecill.info". The fact that you are presently reading this means that you have had knowledge of the CeCILL license and that you accept its terms. You can find a copy of this licence shipped with this software at Documentation/licence.en.txt. */ #ifndef GTK_STIPPLECOMBOBOXWIDGET_H #define GTK_STIPPLECOMBOBOXWIDGET_H #include #include #include G_BEGIN_DECLS /** * VISU_TYPE_UI_STIPPLE_COMBOBOX: * * Get the associated #GType to the VisuUiStippleCombobox objects. * * Since: 3.4 */ #define VISU_TYPE_UI_STIPPLE_COMBOBOX (visu_ui_stipple_combobox_get_type ()) /** * VISU_UI_STIPPLE_COMBOBOX: * @obj: the widget to cast. * * Cast the given object to a #VisuUiStippleCombobox object. * * Since: 3.4 */ #define VISU_UI_STIPPLE_COMBOBOX(obj) (G_TYPE_CHECK_INSTANCE_CAST ((obj), VISU_TYPE_UI_STIPPLE_COMBOBOX, VisuUiStippleCombobox)) /** * VISU_UI_STIPPLE_COMBOBOX_CLASS: * @klass: the class to cast. * * Cast the given class to a #VisuUiStippleComboboxClass object. * * Since: 3.4 */ #define VISU_UI_STIPPLE_COMBOBOX_CLASS(klass) (G_TYPE_CHECK_CLASS_CAST ((klass), VISU_TYPE_UI_STIPPLE_COMBOBOX, VisuUiStippleComboboxClass)) /** * VISU_IS_UI_STIPPLE_COMBOBOX: * @obj: the object to test. * * Get if the given object is a valid #VisuUiStippleCombobox object. * * Since: 3.4 */ #define VISU_IS_UI_STIPPLE_COMBOBOX(obj) (G_TYPE_CHECK_INSTANCE_TYPE ((obj), VISU_TYPE_UI_STIPPLE_COMBOBOX)) /** * VISU_IS_UI_STIPPLE_COMBOBOX_CLASS: * @klass: the class to test. * * Get if the given class is a valid #VisuUiStippleComboboxClass class. * * Since: 3.4 */ #define VISU_IS_UI_STIPPLE_COMBOBOX_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE ((klass), VISU_TYPE_UI_STIPPLE_COMBOBOX)) typedef struct _VisuUiStippleCombobox VisuUiStippleCombobox; typedef struct _VisuUiStippleComboboxClass VisuUiStippleComboboxClass; GType visu_ui_stipple_combobox_get_type(void); GtkWidget* visu_ui_stipple_combobox_new(); void visu_ui_stipple_combobox_set(VisuUiStippleCombobox *stippleComboBox, guint16 stipple); gboolean visu_ui_stipple_combobox_setSelection(VisuUiStippleCombobox* stippleComboBox, guint16 stipple); guint16 visu_ui_stipple_combobox_getSelection(VisuUiStippleCombobox *stippleComboBox); GdkPixbuf* visu_ui_stipple_combobox_getStamp(VisuUiStippleCombobox *stippleComboBox, guint16 stipple); GdkPixbuf* visu_ui_stipple_combobox_class_buildStamp(guint16 stipple); void visu_ui_stipple_combobox_add(VisuUiStippleCombobox *stippleComboBox, guint16 stipple); G_END_DECLS #endif v_sim-3.8.0/src/extraGtkFunctions/gtk_toolPanelWidget.c000066400000000000000000001645151370110300500232240ustar00rootroot00000000000000/* EXTRAITS DE LA LICENCE Copyright CEA, contributeurs : Luc BILLARD et Damien CALISTE, laboratoire L_Sim, (2001-2005) Adresse mèl : BILLARD, non joignable par mèl ; CALISTE, damien P caliste AT cea P fr. Ce logiciel est un programme informatique servant à visualiser des structures atomiques dans un rendu pseudo-3D. Ce logiciel est régi par la licence CeCILL soumise au droit français et respectant les principes de diffusion des logiciels libres. Vous pouvez utiliser, modifier et/ou redistribuer ce programme sous les conditions de la licence CeCILL telle que diffusée par le CEA, le CNRS et l'INRIA sur le site "http://www.cecill.info". Le fait que vous puissiez accéder à cet en-tête signifie que vous avez pris connaissance de la licence CeCILL, et que vous en avez accepté les termes (cf. le fichier Documentation/licence.fr.txt fourni avec ce logiciel). */ /* LICENCE SUM UP Copyright CEA, contributors : Luc BILLARD et Damien CALISTE, laboratoire L_Sim, (2001-2005) E-mail address: BILLARD, not reachable any more ; CALISTE, damien P caliste AT cea P fr. This software is a computer program whose purpose is to visualize atomic configurations in 3D. This software is governed by the CeCILL license under French law and abiding by the rules of distribution of free software. You can use, modify and/ or redistribute the software under the terms of the CeCILL license as circulated by CEA, CNRS and INRIA at the following URL "http://www.cecill.info". The fact that you are presently reading this means that you have had knowledge of the CeCILL license and that you accept its terms. You can find a copy of this licence shipped with this software at Documentation/licence.en.txt. */ #include #include #include #include "gtk_toolPanelWidget.h" #include #include #include #include #include #include #include /** * SECTION:gtk_toolPanelWidget * @short_description: Defines a widget that hold a set of V_Sim panel. * * This widget is a complex association of a #GtkComboBox and a * #GtkNotebook with V_Sim panels. It can have its own window or be * attached into the main command panel. * * This widget also has a built-in menu to exchange V_Sim panel * between different instances of a #VisuUiPanel. A #VisuUiPanel is * refered by its name and has a position and a size. These values can * be stored in the parameter files. */ enum { NOTEBOOK_ENTERED, LAST_SIGNAL }; enum { TOOL_LIST_ICON, /* The icon shown */ TOOL_LIST_STOCK, /* or the stock icon shown */ TOOL_LIST_NAME, /* The label shown */ TOOL_LIST_POINTER_TO_DATA, /* Pointer to the tool panel. */ TOOL_LIST_N_COLUMNS }; /** * VisuUiDockWindow: * * Short name for the structure of containers of #VisuUiPanel. */ struct _VisuUiDockWindow { guint refCount; /* The name of the dock window. */ gchar *name; /* The window holding the notebook of tools. Maybe NULL if the VisuUiDockWindow is integrated in something else.*/ GtkWidget *window; /* The top container widget for the VisuUiDockWindow. */ GtkWidget *vbox; /* The header line with the combobox. */ GtkWidget *hbox; /* The notebook holding the tools. */ GtkWidget *notebook; /* The combo list of accessible tool panels. */ GtkWidget *combo; /* The list store associated to the combo. */ GtkListStore *list; /* Handler on the change signals. */ gulong notebookChanged, comboChanged; /* TRUE if the dock is visible. */ gboolean show; }; /** * VisuUiPanel * * Short form for a #VisuUiPanel_struct structure. */ struct _VisuUiPanel { GtkFrame alignment; /* Set if the visu_ui_panel can be separate from the main window and be hosted in its own window. */ gboolean dockable; /* An id, untranslated, used to identify the panel in a configuration file. It should not contain any space character. */ gchar *id; /* Value that is shown in the combo box, which is a "long" label. */ gchar *comboLabel; /* Value that appears in te tab of the GtkNoteBook */ gchar *tabLabel; /* An image representing the tool. */ GtkWidget *icon; gchar *stockIcon; /* The hosting container. */ VisuUiDockWindow *container; /* Internal widgets. */ GtkWidget *headerWidget; /* Memory gestion. */ gboolean dispose_has_run; }; /** * VisuUiPanelClass * * Opaque structure. */ struct _VisuUiPanelClass { GtkFrameClass parent_class; void (*visu_ui_panel) (VisuUiPanel *tool); /* This list holds pointer on active hosting windows. */ GList* hostingWindows; /* This list holds tools than have no containers. */ GList* orphanVisuUiPanel; /* This is the VisuUiDockWindow of the command panel. */ VisuUiDockWindow *commandPanel; /* Give a quick access from id of tool panels to pointers. */ GHashTable *allVisuUiPanels; /* Pointer on current handled VisuData. No reference is hold. */ VisuData *dataObj; VisuGlView *viewObj; /* If TRUE, the labels are always shown in the tabs. */ gboolean showHeader; }; /** * visu_ui_panel_get_type * * #GType are unique numbers to identify objects. * * Returns: the #GType associated with #VisuUiPanel objects. */ G_DEFINE_TYPE(VisuUiPanel, visu_ui_panel, GTK_TYPE_FRAME) #define MAIN_PANEL_NAME _("Command panel") #define FLAG_PARAMETER_TABVIEW_CONFIG "config_subPanelTabView" #define DESC_PARAMETER_TABVIEW_CONFIG "See or not the labels on tabs ; boolean 0 or 1" #define PARAMETER_CONFIG_TABVIEW_DEFAULT FALSE static gboolean _tabView = PARAMETER_CONFIG_TABVIEW_DEFAULT; /* Local variables. */ static VisuUiPanelClass *local_class = NULL; static GQuark CURRENT_TOOLPANEL_POINTER; static guint visu_ui_panel_signals[LAST_SIGNAL] = { 0 }; /* Local methods. */ static void visu_ui_panel_class_init(VisuUiPanelClass *klass); static void visu_ui_panel_init(VisuUiPanel *visu_ui_panel); static void visu_ui_panel_dispose(GObject *visu_ui_panel); static void visu_ui_panel_finalize(GObject *obj); static GtkWidget* buildDockMenu(VisuUiPanel *visu_ui_panel, GList *listOfDocks); static GtkWidget* buildMainMenu(VisuUiDockWindow *window); static VisuUiDockWindow* dock_window_new(gchar *name, gboolean withWindow); static VisuUiDockWindow* dock_window_ref(VisuUiDockWindow *dock); static void dock_window_unref(VisuUiDockWindow *dock); static void exportParameters(GString *data, VisuData* dataObj); /* Local callbacks. */ static gboolean onHomePressed(GtkWidget *widget _U_, GdkEventKey *event, gpointer data); static void onDockButtonClicked(VisuUiPanel *visu_ui_panel, gpointer data); static void onMainButtonClicked(GtkButton *button, gpointer data); static void onRaiseButtonClicked(GtkButton *button, gpointer data); static void onDockMenuClicked(GtkMenuItem *menuitem, gpointer user_data); static void onDockMenuNewClicked(GtkMenuItem *menuitem, gpointer user_data); static void onDockMenuHideClicked(GtkMenuItem *menuitem, gpointer user_data); static void onDockMenuSelected(GtkMenuShell *menushell, gpointer user_data); static void onMainMenuClicked(GtkMenuItem *menuitem, gpointer user_data); static void onMainMenuShowClicked(GtkMenuItem *menuitem, gpointer user_data); static void onMainMenuHideClicked(GtkMenuItem *menuitem, gpointer user_data); static void onMainMenuSelected(GtkMenuShell *menushell, gpointer user_data); static gboolean onKillVisuUiDockWindowEvent(GtkWidget *widget, GdkEvent *event, gpointer user_data); static void onPageChanged(GtkNotebook *book, GtkWidget *child, gint num, gpointer data); static void onComboChanged(GtkComboBox *combo, gpointer data); static void onEntryTabview(VisuConfigFile *obj, VisuConfigFileEntry *entry, VisuUiPanelClass *klass); static void visu_ui_panel_class_init(VisuUiPanelClass *klass) { DBG_fprintf(stderr, "Gtk VisuUiPanel : creating the class of the widget.\n"); local_class = klass; DBG_fprintf(stderr, " - adding new signals ;\n"); /** * VisuUiPanel::page-entered: * @panel: the #VisuUiPanel that emits the signal. * * This signal is emitted when a page of the #GtkNotebook with all * the V_Sim panels is entered. * * Since: 3.3 */ visu_ui_panel_signals[NOTEBOOK_ENTERED] = g_signal_new ("page-entered", G_TYPE_FROM_CLASS(klass), G_SIGNAL_RUN_FIRST | G_SIGNAL_ACTION, G_STRUCT_OFFSET(VisuUiPanelClass, visu_ui_panel), NULL, NULL, g_cclosure_marshal_VOID__VOID, G_TYPE_NONE, 0, NULL); DBG_fprintf(stderr, " - initializing the list of hosting windows.\n"); klass->hostingWindows = (GList*)0; klass->orphanVisuUiPanel = (GList*)0; klass->commandPanel = (VisuUiDockWindow*)0; klass->dataObj = (VisuData*)0; klass->viewObj = (VisuGlView*)0; klass->allVisuUiPanels = g_hash_table_new_full(g_str_hash, g_str_equal, NULL, NULL); klass->showHeader = PARAMETER_CONFIG_TABVIEW_DEFAULT; visu_config_file_addBooleanEntry(VISU_CONFIG_FILE_PARAMETER, FLAG_PARAMETER_TABVIEW_CONFIG, DESC_PARAMETER_TABVIEW_CONFIG, &_tabView, FALSE); g_signal_connect(VISU_CONFIG_FILE_PARAMETER, "parsed::" FLAG_PARAMETER_TABVIEW_CONFIG, G_CALLBACK(onEntryTabview), klass); visu_config_file_addExportFunction(VISU_CONFIG_FILE_PARAMETER, exportParameters); CURRENT_TOOLPANEL_POINTER = g_quark_from_static_string("VisuUiPanel_currentVisuUiPanel"); /* Set the pixmap directory for the Glade stuff. */ add_pixmap_directory(visu_basic_getPixmapsDir()); /* Connect freeing methods. */ G_OBJECT_CLASS(klass)->dispose = visu_ui_panel_dispose; G_OBJECT_CLASS(klass)->finalize = visu_ui_panel_finalize; } /* This method can be called several times. It should unref all of its reference to GObjects. */ static void visu_ui_panel_dispose(GObject *visu_ui_panel) { DBG_fprintf(stderr, "Gtk VisuUiPanel : dispose object %p (%s).\n", (gpointer)visu_ui_panel, VISU_UI_PANEL(visu_ui_panel)->id); if (VISU_UI_PANEL(visu_ui_panel)->dispose_has_run) return; VISU_UI_PANEL(visu_ui_panel)->dispose_has_run = TRUE; /* Chain up to the parent class */ G_OBJECT_CLASS(visu_ui_panel_parent_class)->dispose(visu_ui_panel); } /* This method is called once only. */ static void visu_ui_panel_finalize(GObject *obj) { VisuUiPanel *visu_ui_panel; g_return_if_fail(obj); DBG_fprintf(stderr, "Gtk VisuUiPanel : finalize object %p.\n", (gpointer)obj); visu_ui_panel = VISU_UI_PANEL(obj); /* Remove me from the list of visu_ui_panels. */ g_hash_table_remove(local_class->allVisuUiPanels, visu_ui_panel->id); if (visu_ui_panel->comboLabel) g_free(visu_ui_panel->comboLabel); if (visu_ui_panel->tabLabel) g_free(visu_ui_panel->tabLabel); if (visu_ui_panel->id) g_free(visu_ui_panel->id); if (visu_ui_panel->stockIcon) g_free(visu_ui_panel->stockIcon); if (visu_ui_panel->headerWidget) g_object_unref(visu_ui_panel->headerWidget); /* Chain up to the parent class */ G_OBJECT_CLASS(visu_ui_panel_parent_class)->finalize(obj); DBG_fprintf(stderr, "Gtk VisuUiPanel : freeing ... OK.\n"); } static void visu_ui_panel_init(VisuUiPanel *visu_ui_panel) { DBG_fprintf(stderr, "Gtk VisuUiPanel : initializing new object (%p).\n", (gpointer)visu_ui_panel); visu_ui_panel->dispose_has_run = FALSE; visu_ui_panel->dockable = FALSE; visu_ui_panel->id = (gchar*)0; visu_ui_panel->comboLabel = (gchar*)0; visu_ui_panel->tabLabel = (gchar*)0; visu_ui_panel->icon = (GtkWidget*)0; visu_ui_panel->stockIcon = (gchar*)0; visu_ui_panel->headerWidget = (GtkWidget*)0; visu_ui_panel->container = (VisuUiDockWindow*)0; gtk_frame_set_shadow_type(GTK_FRAME(visu_ui_panel), GTK_SHADOW_NONE); } /** * visu_ui_panel_new: * @id: (type filename): a string without space and non internationalised ; * @name: a string in UTF-8 that can be internationalised ; * @tabName: a shorter name than @name, in UTF-8 that can be * internationalised. * * Create a new #VisuUiPanel with the given @id, displaying @name in the * combo box of a #VisuUiDockWindow and @tabName in the tab of the page * notebook. * * Returns: a newly created widget. */ GtkWidget* visu_ui_panel_new(gchar *id, gchar* name, gchar *tabName) { VisuUiPanel *visu_ui_panel; g_return_val_if_fail(id && id[0] && !strstr(id, " "), (GtkWidget*)0); g_return_val_if_fail(name && name[0], (GtkWidget*)0); g_return_val_if_fail(tabName && tabName[0], (GtkWidget*)0); visu_ui_panel = VISU_UI_PANEL(g_object_new(visu_ui_panel_get_type(), NULL)); DBG_fprintf(stderr, "Gtk VisuUiPanel : creating new object '%s' : %p.\n", name, (gpointer)visu_ui_panel); visu_ui_panel->id = g_strdup(id); visu_ui_panel->comboLabel = g_strdup(name); visu_ui_panel->tabLabel = g_strdup(tabName); /* Add me to the list of visu_ui_panels. */ g_hash_table_insert(local_class->allVisuUiPanels, visu_ui_panel->id, (gpointer)visu_ui_panel); return GTK_WIDGET(visu_ui_panel); } /** * visu_ui_panel_newWithIconFromPath: * @id: a string without space and non internationalised ; * @name: a string in UTF-8 that can be internationalised ; * @tabName: a shorter name than @name, in UTF-8 that can be * internationalised ; * @iconPath: a path to an icon (should be 20x20). * * Create a new #VisuUiPanel with the given @id, displaying @name in the * combo box of a #VisuUiDockWindow and @tabName in the tab of the page * notebook. The displayed icon will be read from the @iconPath. * * Returns: (transfer full): a newly created widget. */ GtkWidget* visu_ui_panel_newWithIconFromPath(gchar *id, gchar* name, gchar *tabName, const gchar* iconPath) { VisuUiPanel *visu_ui_panel; visu_ui_panel = VISU_UI_PANEL(visu_ui_panel_new(id, name, tabName)); if (!visu_ui_panel) return (GtkWidget*)0; /* TODO : mettre un truc qui limite la taille des images effichées à 20x20 par exemple en chargeant de GdkImage et en regardant sa taille. */ visu_ui_panel->icon = create_pixmap((GtkWidget*)0, iconPath); return GTK_WIDGET(visu_ui_panel); } /** * visu_ui_panel_newWithIconFromIconName: * @id: a string without space and non internationalised ; * @name: a string in UTF-8 that can be internationalised ; * @tabName: a shorter name than @name, in UTF-8 that can be * internationalised ; * @icon: the name of a stock icon. * * Create a new #VisuUiPanel with the given @id, displaying @name in the * combo box of a #VisuUiDockWindow and @tabName in the tab of the page * notebook. The displayed icon will be taken from the @stock. * * Returns: (transfer full): a newly created widget. */ GtkWidget* visu_ui_panel_newWithIconFromIconName(gchar *id, gchar* name, gchar *tabName, const gchar* icon) { VisuUiPanel *visu_ui_panel; visu_ui_panel = VISU_UI_PANEL(visu_ui_panel_new(id, name, tabName)); if (!visu_ui_panel) return (GtkWidget*)0; visu_ui_panel->stockIcon = g_strdup(icon); visu_ui_panel->icon = gtk_image_new_from_icon_name(icon, GTK_ICON_SIZE_MENU); return GTK_WIDGET(visu_ui_panel); } /** * visu_ui_panel_getHeaderWidget: * @visu_ui_panel: a #VisuUiPanel. * * The #VisuUiPanel should be used in a page of a #GtkNotebook. This * routine is used to get the widget that should be used in the * tab. This widget is a container with an icon and a label. * * Returns: (transfer none): a container widget that should be put in the tab of a * #GtkNotebook. */ GtkWidget* visu_ui_panel_getHeaderWidget(VisuUiPanel *visu_ui_panel) { GtkWidget *label, *wd, *image; #if GTK_MAJOR_VERSION == 2 && GTK_MINOR_VERSION < 12 GtkTooltips *tooltips; #endif g_return_val_if_fail(visu_ui_panel, (GtkWidget*)0); /* If the header has never been created, we do it now. */ if (!visu_ui_panel->headerWidget) { #if GTK_MAJOR_VERSION == 2 && GTK_MINOR_VERSION < 12 tooltips = gtk_tooltips_new (); #endif visu_ui_panel->headerWidget = gtk_hbox_new(FALSE, 0); wd = gtk_event_box_new(); gtk_event_box_set_visible_window(GTK_EVENT_BOX(wd), FALSE); gtk_box_pack_start(GTK_BOX(visu_ui_panel->headerWidget), wd, FALSE, FALSE, 0); gtk_widget_set_tooltip_text(wd, visu_ui_panel->comboLabel); if (visu_ui_panel->icon) gtk_container_add(GTK_CONTAINER(wd), visu_ui_panel->icon); else gtk_container_add(GTK_CONTAINER(wd), gtk_image_new_from_icon_name("image-missing", GTK_ICON_SIZE_MENU)); label = gtk_label_new(visu_ui_panel->tabLabel); gtk_widget_set_margin_start(label, 2); gtk_box_pack_start(GTK_BOX(visu_ui_panel->headerWidget), label, FALSE, FALSE, 0); if (visu_ui_panel->dockable) { wd = gtk_button_new(); gtk_widget_set_no_show_all(wd, TRUE); gtk_box_pack_start(GTK_BOX(visu_ui_panel->headerWidget), wd, TRUE, TRUE, 0); gtk_button_set_relief(GTK_BUTTON(wd), GTK_RELIEF_NONE); g_signal_connect_swapped(G_OBJECT(wd), "clicked", G_CALLBACK(onDockButtonClicked), (gpointer)visu_ui_panel); image = create_pixmap((GtkWidget*)0, "stock-menu-detach.png"); gtk_container_add(GTK_CONTAINER(wd), image); gtk_widget_set_tooltip_text(wd, _("Manage this subpanel: attach/detach" " or hide it.")); gtk_widget_show(image); } g_object_ref(G_OBJECT(visu_ui_panel->headerWidget)); gtk_widget_show_all(visu_ui_panel->headerWidget); gtk_widget_hide(label); } return visu_ui_panel->headerWidget; } /** * visu_ui_panel_getLabel: * @visu_ui_panel: a #VisuUiPanel. * * The #VisuUiPanel has two label, a short one, used in the tab of a * #GtkNotebook and one longer. This routine gets the longer. * * Returns: an UTF-8 internationalised name (property of V_Sim, should * not be freed). */ const gchar* visu_ui_panel_getLabel(VisuUiPanel *visu_ui_panel) { g_return_val_if_fail(visu_ui_panel, (gchar*)0); return visu_ui_panel->comboLabel; } /** * visu_ui_panel_getId: * @visu_ui_panel: a #VisuUiPanel. * * The #VisuUiPanel can be identifyed by an id (a string without space, * usually using ASCII characters only). * * Returns: a constant string identifying this #VisuUiPanel. */ const gchar* visu_ui_panel_getId(VisuUiPanel *visu_ui_panel) { g_return_val_if_fail(visu_ui_panel, (gchar*)0); return visu_ui_panel->id; } /** * visu_ui_panel_setDockable: * @visu_ui_panel: a #VisuUiPanel ; * @value: a boolean. * * A #VisuUiPanel can be moved between different #VisuUiDockWindow or * not. This ability is controlled by the dockable flag. Change it * with this method. If @visu_ui_panel is set dockable, then, it can be * hidden or moved to another or a new #VisuUiDockWindow with the pop-up * memu that is triggered by a small button in the header widget (see * visu_ui_panel_getHeaderWidget()). */ void visu_ui_panel_setDockable(VisuUiPanel *visu_ui_panel, gboolean value) { g_return_if_fail(visu_ui_panel); visu_ui_panel->dockable = value; } /** * visu_ui_panel_getContainer: * @visu_ui_panel: a #VisuUiPanel. * * Return the #VisuUiDockWindow that the given @visu_ui_panel is attached to or * NULL if the @visu_ui_panel is currently dettached. * * Returns: a #VisuUiDockWindow object. */ VisuUiDockWindow* visu_ui_panel_getContainer(VisuUiPanel *visu_ui_panel) { g_return_val_if_fail(VISU_IS_UI_PANEL(visu_ui_panel), (VisuUiDockWindow*)0); return visu_ui_panel->container; } /** * visu_ui_panel_getContainerWindow: * @visu_ui_panel: a #VisuUiPanel. * * Return the #GtkWindow that the given @visu_ui_panel is rendered in or * NULL if the @visu_ui_panel is currently dettached. * * Returns: (transfer none): a #GtkWindow object. */ GtkWindow* visu_ui_panel_getContainerWindow(VisuUiPanel *visu_ui_panel) { g_return_val_if_fail(VISU_IS_UI_PANEL(visu_ui_panel), (GtkWindow*)0); if (visu_ui_panel->container) { if (visu_ui_panel->container->window) return GTK_WINDOW(visu_ui_panel->container->window); else return GTK_WINDOW(visu_ui_main_class_getCurrentPanel()); } else return (GtkWindow*)0; } /** * visu_ui_panel_setContainer: * @visu_ui_panel: a #VisuUiPanel ; * @window: a #VisuUiDockWindow. * * Change the container of a visu_ui_panel. If it is currently attached to * a #VisuUiDockWindow, it firstly detachs it. */ void visu_ui_panel_setContainer(VisuUiPanel *visu_ui_panel, VisuUiDockWindow *container) { g_return_if_fail(VISU_IS_UI_PANEL(visu_ui_panel)); if (container == visu_ui_panel->container) return; /* If the panel is already attached, we detach it. */ if (visu_ui_panel->container) { DBG_fprintf(stderr, "Gtk VisuUiPanel : detaching panel '%s' (%p).\n", visu_ui_panel->tabLabel, (gpointer)visu_ui_panel); g_object_ref(G_OBJECT(visu_ui_panel)); visu_ui_panel_detach(visu_ui_panel); } /* If a new container is given, we attach it. */ if (container) { DBG_fprintf(stderr, "Gtk VisuUiPanel : attaching panel '%s' (%p) to %p.\n", visu_ui_panel->tabLabel, (gpointer)visu_ui_panel, (gpointer)container); visu_ui_panel_attach(visu_ui_panel, container); g_object_unref(G_OBJECT(visu_ui_panel)); } } /** * visu_ui_panel_getContainerId: * @visu_ui_panel: a #VisuUiPanel. * * Return the identifying string of the #VisuUiDockWindow that the given * @visu_ui_panel is attached to or NULL if the @visu_ui_panel is currently dettached. * * Returns: a string owned by V_Sim. */ const gchar* visu_ui_panel_getContainerId(VisuUiPanel *visu_ui_panel) { g_return_val_if_fail(VISU_IS_UI_PANEL(visu_ui_panel), (gchar*)0); if (!visu_ui_panel->container) return "None"; if (visu_ui_panel->container == VISU_UI_PANEL_CLASS(G_OBJECT_GET_CLASS(visu_ui_panel))->commandPanel) return "Main"; return visu_ui_panel->container->name; } /** * visu_ui_panel_setContainerId: * @visu_ui_panel: a #VisuUiPanel ; * @id: a #VisuUiDockWindow identifier. * * Change the container of a visu_ui_panel using the given @id. If it is * currently attached to a #VisuUiDockWindow, it firstly detachs it. */ void visu_ui_panel_setContainerId(VisuUiPanel *visu_ui_panel, const gchar *id) { g_return_if_fail(VISU_IS_UI_PANEL(visu_ui_panel) && id && id[0]); visu_ui_panel_setContainer(visu_ui_panel, visu_ui_panel_class_getDockById(id)); } /** * visu_ui_panel_getData: * @visu_ui_panel: a #VisuUiPanel. * * The @visu_ui_panel is supposed to work on a #VisuData, this routine can * be used to get it. * * Returns: (transfer none): the currently focused #VisuData (can be NULL if none). */ VisuData* visu_ui_panel_getData(VisuUiPanel *visu_ui_panel) { g_return_val_if_fail(VISU_IS_UI_PANEL(visu_ui_panel), (VisuData*)0); return VISU_UI_PANEL_CLASS(G_OBJECT_GET_CLASS(visu_ui_panel))->dataObj; } /** * visu_ui_panel_getFocused: * @visu_ui_panel: a #VisuUiPanel. * * Retrieves the currently focused #VisuBoxed object in the default #VisuUiRenderingWindow. * * Since: 3.7 * * Returns: (transfer none) (allow-none): the currently focused * #VisuBoxed (can be %NULL if none). */ VisuBoxed* visu_ui_panel_getFocused(VisuUiPanel *visu_ui_panel) { g_return_val_if_fail(VISU_IS_UI_PANEL(visu_ui_panel), (VisuBoxed*)0); return VISU_BOXED(VISU_UI_PANEL_CLASS(G_OBJECT_GET_CLASS(visu_ui_panel))->dataObj); } /** * visu_ui_panel_getView: * @visu_ui_panel: a #VisuUiPanel object. * * Convenient routine to get the current #VisuGlView, see * visu_ui_panel_class_setCurrent(). * * Since: 3.7 * * Returns: (transfer none): the current #VisuGlView, or NULL. */ VisuGlView* visu_ui_panel_getView(VisuUiPanel *visu_ui_panel) { g_return_val_if_fail(VISU_IS_UI_PANEL(visu_ui_panel), (VisuGlView*)0); return VISU_UI_PANEL_CLASS(G_OBJECT_GET_CLASS(visu_ui_panel))->viewObj; } /** * visu_ui_panel_getVisible: * @visu_ui_panel: a #VisuUiPanel. * * This is used to retrieve if the @visu_ui_panel is currently realised * and the visualised page of the #GtkNotebook it is associated to. * * Returns: TRUE if the given @visu_ui_panel is potentialy visible to the user. */ gboolean visu_ui_panel_getVisible(VisuUiPanel *visu_ui_panel) { g_return_val_if_fail(VISU_IS_UI_PANEL(visu_ui_panel), FALSE); /* If the tool panel is not shown, we return fFALSE. */ if (!visu_ui_panel->container || !visu_ui_panel->container->show) return FALSE; /* If the tool panel is attached to a visible dock, we test if the current page of the notebook is our tool panel. */ return (visu_ui_panel == VISU_UI_PANEL(gtk_notebook_get_nth_page (GTK_NOTEBOOK(visu_ui_panel->container->notebook), gtk_notebook_get_current_page (GTK_NOTEBOOK(visu_ui_panel->container->notebook))))); } /*****************/ /* Menu gestion. */ /*****************/ static void onDockButtonClicked(VisuUiPanel *visu_ui_panel, gpointer data) { GtkWidget *wd; g_return_if_fail(VISU_IS_UI_PANEL(visu_ui_panel)); wd = buildDockMenu(visu_ui_panel, VISU_UI_PANEL_CLASS(G_OBJECT_GET_CLASS(visu_ui_panel))->hostingWindows); g_signal_connect(G_OBJECT(wd), "selection-done", G_CALLBACK(onDockMenuSelected), (gpointer)0); gtk_widget_show_all(wd); #if GTK_MAJOR_VERSION < 2 || (GTK_MAJOR_VERSION == 3 && GTK_MINOR_VERSION < 22) gtk_menu_popup(GTK_MENU(wd), NULL, NULL, NULL, NULL, 1, gtk_get_current_event_time()); (void)data; #else gtk_menu_popup_at_widget(GTK_MENU(wd), GTK_WIDGET(data), GDK_GRAVITY_SOUTH, GDK_GRAVITY_NORTH, NULL); #endif } static GtkWidget* buildDockMenu(VisuUiPanel *visu_ui_panel, GList *listOfDocks) { GtkWidget *menu, *item; VisuUiDockWindow *window; gchar *lbl; menu = gtk_menu_new(); /* All dock windows. */ while (listOfDocks) { window = (VisuUiDockWindow*)listOfDocks->data; if (window->show) { lbl = g_strdup_printf(_("Send to '%s'"), window->name); item = gtk_menu_item_new_with_label(lbl); g_free(lbl); g_signal_connect(G_OBJECT(item), "activate", G_CALLBACK(onDockMenuClicked), listOfDocks->data); g_object_set_qdata_full(G_OBJECT(item), CURRENT_TOOLPANEL_POINTER, (gpointer)visu_ui_panel, NULL); gtk_widget_set_sensitive(item, (visu_ui_panel->container != window)); gtk_menu_shell_append(GTK_MENU_SHELL(menu), item); } listOfDocks = g_list_next(listOfDocks); } /* Separator. */ item = gtk_separator_menu_item_new(); gtk_menu_shell_append(GTK_MENU_SHELL(menu), item); /* Create a new dock window. */ item = gtk_menu_item_new_with_label(_("New dock")); g_signal_connect(G_OBJECT(item), "activate", G_CALLBACK(onDockMenuNewClicked), (gpointer)visu_ui_panel); gtk_menu_shell_append(GTK_MENU_SHELL(menu), item); /* Remove the current tool panel. */ lbl = g_strdup_printf(_("Hide tool '%s'"), visu_ui_panel->tabLabel); item = gtk_menu_item_new_with_label(lbl); g_free(lbl); g_signal_connect(G_OBJECT(item), "activate", G_CALLBACK(onDockMenuHideClicked), (gpointer)visu_ui_panel); gtk_menu_shell_append(GTK_MENU_SHELL(menu), item); DBG_fprintf(stderr, "Gtk VisuUiPanel : create the dock menu %p.\n", (gpointer)menu); return menu; } static void onDockMenuClicked(GtkMenuItem *menuitem, gpointer user_data) { VisuUiPanel *visu_ui_panel; visu_ui_panel = (VisuUiPanel*)0; visu_ui_panel = VISU_UI_PANEL(g_object_get_qdata(G_OBJECT(menuitem), CURRENT_TOOLPANEL_POINTER)); g_return_if_fail(VISU_IS_UI_PANEL(visu_ui_panel)); visu_ui_panel_setContainer(visu_ui_panel, (VisuUiDockWindow*)user_data); } static void onDockMenuNewClicked(GtkMenuItem *menuitem _U_, gpointer user_data) { GList **lst; VisuUiPanel *visu_ui_panel; VisuUiDockWindow *window; guint nb; gchar *name; lst = &local_class->hostingWindows; nb = g_list_length(*lst); name = g_strdup_printf(_("Dock window (%d)"), nb); window = dock_window_new(name, TRUE); *lst = g_list_append(*lst, (gpointer)window); window->show = TRUE; gtk_widget_show_all(window->window); visu_ui_panel = VISU_UI_PANEL(user_data); if (visu_ui_panel) visu_ui_panel_setContainer(visu_ui_panel, window); } static void onDockMenuHideClicked(GtkMenuItem *menuitem _U_, gpointer user_data) { DBG_fprintf(stderr, "Gtk VisuUiPanel : hide the panel %p.\n", (gpointer)user_data); visu_ui_panel_setContainer(VISU_UI_PANEL(user_data), (VisuUiDockWindow*)0); } static void onDockMenuSelected(GtkMenuShell *menushell, gpointer user_data _U_) { DBG_fprintf(stderr, "Gtk VisuUiPanel : destroy the dock menu %p.\n", (gpointer)menushell); gtk_widget_destroy(GTK_WIDGET(menushell)); } static gboolean emitPageEnter(gpointer data) { g_return_val_if_fail(VISU_IS_UI_PANEL(data), FALSE); DBG_fprintf(stderr, "Gtk VisuUiPanel: '%s' (%p) emits 'page-entered' signal.\n", VISU_UI_PANEL(data)->id, data); g_signal_emit(G_OBJECT(data), visu_ui_panel_signals[NOTEBOOK_ENTERED], 0, NULL); return FALSE; } static void changeHeaderVisibility(VisuUiPanel *panel, gboolean status) { GList *list, *tmpLst; g_return_if_fail(VISU_IS_UI_PANEL(panel) && panel->headerWidget); list = gtk_container_get_children(GTK_CONTAINER(panel->headerWidget)); tmpLst = list->next; while(tmpLst) { if (status) gtk_widget_show(GTK_WIDGET(tmpLst->data)); else gtk_widget_hide(GTK_WIDGET(tmpLst->data)); tmpLst = g_list_next(tmpLst); } g_list_free(list); } static gboolean onHomePressed(GtkWidget *widget _U_, GdkEventKey *event, gpointer data) { DBG_fprintf(stderr, "Gtk VisuUiPanel: get key pressed.\n"); if(event->keyval == GDK_KEY_Home) { onRaiseButtonClicked((GtkButton*)0, data); return TRUE; } return FALSE; } static void onPageChanged(GtkNotebook *book, GtkWidget *child, gint num, gpointer data) { VisuUiDockWindow *window; int numOld; #if GTK_MAJOR_VERSION == 2 child = gtk_notebook_get_nth_page(book, num); #endif window = (VisuUiDockWindow*)data; g_return_if_fail(window); g_return_if_fail(VISU_IS_UI_PANEL(child)); DBG_fprintf(stderr, "Gtk VisuUiPanel: caught 'page-switch' signal, jump to %d.\n", num); /* Change the visibility of the header labels. */ if (!local_class->showHeader) { numOld = gtk_combo_box_get_active(GTK_COMBO_BOX(window->combo)); if ((gint)num != numOld) { /* We don't come from the combo so we change the visibility. */ changeHeaderVisibility (VISU_UI_PANEL(gtk_notebook_get_nth_page(book, numOld)), FALSE); changeHeaderVisibility (VISU_UI_PANEL(gtk_notebook_get_nth_page(book, num)), TRUE); } } /* Change the combo to the right one. */ g_signal_handler_block(G_OBJECT(window->combo), window->comboChanged); gtk_combo_box_set_active(GTK_COMBO_BOX(window->combo), num); g_signal_handler_unblock(G_OBJECT(window->combo), window->comboChanged); g_idle_add(emitPageEnter, child); } static void onComboChanged(GtkComboBox *combo, gpointer data) { int index, numOld; VisuUiDockWindow *window; GtkNotebook *book; window = (VisuUiDockWindow*)data; g_return_if_fail(window); index = gtk_combo_box_get_active(combo); /* Change the visibility of the header labels. */ if (!local_class->showHeader) { book = GTK_NOTEBOOK(window->notebook); numOld = gtk_notebook_get_current_page(book); changeHeaderVisibility (VISU_UI_PANEL(gtk_notebook_get_nth_page(book, numOld)), FALSE); changeHeaderVisibility (VISU_UI_PANEL(gtk_notebook_get_nth_page(book, index)), TRUE); } /* Change the page to the right one. */ gtk_notebook_set_current_page(GTK_NOTEBOOK(window->notebook), index); } static gboolean onKillVisuUiDockWindowEvent(GtkWidget *widget, GdkEvent *event _U_, gpointer user_data) { g_return_val_if_fail(user_data, TRUE); DBG_fprintf(stderr, "Gtk VisuUiPanel: delete or destroy event cancelled.\n"); gtk_widget_hide(widget); ((VisuUiDockWindow*)user_data)->show = FALSE; return TRUE; } /** * visu_ui_panel_attach: * @visu_ui_panel: a #VisuUiPanel ; * @dock: a #VisuUiDockWindow. * * Put the given @visu_ui_panel in the given @dock window. It adds in this * dock window a new page in the #GtkNotebook using as tab header the * widget returned by visu_ui_panel_getHeaderWidget(). */ void visu_ui_panel_attach(VisuUiPanel *visu_ui_panel, VisuUiDockWindow *dock) { GtkTreeIter iter; VisuUiPanelClass *klass; GdkPixbuf *pixbuf; DBG_fprintf(stderr, "Gtk VisuUiPanel: attach a visu_ui_panel (%p) to a dock" " window (%s).\n", (gpointer)visu_ui_panel, dock->name); g_return_if_fail(dock && visu_ui_panel); if (visu_ui_panel->icon && gtk_image_get_storage_type(GTK_IMAGE(visu_ui_panel->icon)) == GTK_IMAGE_PIXBUF) pixbuf = gtk_image_get_pixbuf(GTK_IMAGE(visu_ui_panel->icon)); else pixbuf = (GdkPixbuf*)0; /* We add the window in the list store. */ gtk_list_store_append(dock->list, &iter); gtk_list_store_set(dock->list, &iter, TOOL_LIST_ICON, pixbuf, TOOL_LIST_STOCK, visu_ui_panel->stockIcon, TOOL_LIST_NAME, visu_ui_panel->comboLabel, TOOL_LIST_POINTER_TO_DATA, visu_ui_panel, -1); gtk_notebook_append_page(GTK_NOTEBOOK(dock->notebook), GTK_WIDGET(visu_ui_panel), visu_ui_panel_getHeaderWidget(visu_ui_panel)); gtk_widget_show(GTK_WIDGET(visu_ui_panel)); visu_ui_panel->container = dock; if (gtk_notebook_get_n_pages(GTK_NOTEBOOK(dock->notebook)) > 1) gtk_widget_show(dock->hbox); else gtk_widget_hide(dock->hbox); klass = VISU_UI_PANEL_CLASS(G_OBJECT_GET_CLASS(visu_ui_panel)); klass->orphanVisuUiPanel = g_list_remove(klass->orphanVisuUiPanel, (gpointer)visu_ui_panel); } /** * visu_ui_panel_detach: * @visu_ui_panel: a #VisuUiPanel. * * Remove the given @visu_ui_panel from its current container and add it * to the list of hidden tool panels. It can be added again using the * pop-up menu of any #VisuUiDockWindow. */ void visu_ui_panel_detach(VisuUiPanel *visu_ui_panel) { gint page; VisuUiDockWindow *window; GtkTreeIter iter; GtkTreePath* path; gboolean valid; VisuUiPanelClass *klass; g_return_if_fail(visu_ui_panel && visu_ui_panel->container); window = visu_ui_panel->container; /* Get the id. */ page = gtk_notebook_page_num(GTK_NOTEBOOK(window->notebook), GTK_WIDGET(visu_ui_panel)); DBG_fprintf(stderr, "Gtk VisuUiPanel : detach a visu_ui_panel (%s) from page %d of dock" " (%s).\n", visu_ui_panel->tabLabel, page, window->name); /* We remove the page for the notebook. */ gtk_notebook_remove_page(GTK_NOTEBOOK(window->notebook), page); if (gtk_notebook_get_n_pages(GTK_NOTEBOOK(window->notebook)) < 2) gtk_widget_hide(window->hbox); /* We remove the tool from the combo list. */ path = gtk_tree_path_new_from_indices(page, -1); valid = gtk_tree_model_get_iter(GTK_TREE_MODEL(window->list), &iter, path); if (valid) gtk_list_store_remove(window->list, &iter); gtk_tree_path_free(path); /* If there is no more tool in this window, we delete it. */ if (gtk_notebook_get_n_pages(GTK_NOTEBOOK(window->notebook)) == 0 && window != VISU_UI_PANEL_CLASS(G_OBJECT_GET_CLASS(visu_ui_panel))->commandPanel) { DBG_fprintf(stderr, "Gtk VisuUiPanel: destroying dock window %p (%s).\n", (gpointer)window, window->name); gtk_widget_destroy(window->window); VISU_UI_PANEL_CLASS(G_OBJECT_GET_CLASS(visu_ui_panel))->hostingWindows = g_list_remove(VISU_UI_PANEL_CLASS(G_OBJECT_GET_CLASS(visu_ui_panel))->hostingWindows, (gconstpointer)window); g_free(window->name); g_object_unref(window->list); g_free(window); } visu_ui_panel->container = (VisuUiDockWindow*)0; klass = VISU_UI_PANEL_CLASS(G_OBJECT_GET_CLASS(visu_ui_panel)); klass->orphanVisuUiPanel = g_list_prepend(klass->orphanVisuUiPanel, (gpointer)visu_ui_panel); DBG_fprintf(stderr, "Gtk VisuUiPanel: number of orphan tool panels %d.\n", g_list_length(klass->orphanVisuUiPanel)); } static void onMainButtonClicked(GtkButton *button, gpointer data) { GtkWidget *wd; wd = buildMainMenu((VisuUiDockWindow*)data); g_signal_connect(G_OBJECT(wd), "selection-done", G_CALLBACK(onMainMenuSelected), (gpointer)0); gtk_widget_show_all(wd); #if GTK_MAJOR_VERSION < 2 || (GTK_MAJOR_VERSION == 3 && GTK_MINOR_VERSION < 22) gtk_menu_popup(GTK_MENU(wd), NULL, NULL, NULL, NULL, 1, gtk_get_current_event_time()); (void)button; #else gtk_menu_popup_at_widget(GTK_MENU(wd), GTK_WIDGET(button), GDK_GRAVITY_SOUTH, GDK_GRAVITY_NORTH, NULL); #endif } static GtkWidget* buildMainMenu(VisuUiDockWindow *window) { GtkWidget *menu, *item; GList* tmpLst; gchar *label; VisuUiPanel *panel; VisuUiDockWindow *dock; gboolean haveHiddenDock; menu = gtk_menu_new(); tmpLst = local_class->orphanVisuUiPanel; /* All dock windows. */ while (tmpLst) { panel = (VisuUiPanel*)tmpLst->data; label = g_strdup_printf(_("Show '%s'"), panel->comboLabel); item = gtk_menu_item_new_with_label(label); g_free(label); g_signal_connect(G_OBJECT(item), "activate", G_CALLBACK(onMainMenuClicked), window); g_object_set_qdata_full(G_OBJECT(item), CURRENT_TOOLPANEL_POINTER, (gpointer)panel, NULL); gtk_menu_shell_append(GTK_MENU_SHELL(menu), item); tmpLst = g_list_next(tmpLst); } if (!local_class->orphanVisuUiPanel) { item = gtk_menu_item_new_with_label(_("No hidden tool")); gtk_widget_set_sensitive(item, FALSE); gtk_menu_shell_append(GTK_MENU_SHELL(menu), item); } /* Separator. */ item = gtk_separator_menu_item_new(); gtk_menu_shell_append(GTK_MENU_SHELL(menu), item); /* Hidden dock. */ haveHiddenDock = FALSE; tmpLst = local_class->hostingWindows; while (tmpLst) { dock = (VisuUiDockWindow*)tmpLst->data; if (!dock->show) { haveHiddenDock = TRUE; label = g_strdup_printf(_("Show '%s'"), dock->name); item = gtk_menu_item_new_with_label(label); g_free(label); g_signal_connect(G_OBJECT(item), "activate", G_CALLBACK(onMainMenuShowClicked), dock); gtk_menu_shell_append(GTK_MENU_SHELL(menu), item); } tmpLst = g_list_next(tmpLst); } if (!haveHiddenDock) { item = gtk_menu_item_new_with_label(_("No hidden dock")); gtk_widget_set_sensitive(item, FALSE); gtk_menu_shell_append(GTK_MENU_SHELL(menu), item); } if (window->window) { /* Separator. */ item = gtk_separator_menu_item_new(); gtk_menu_shell_append(GTK_MENU_SHELL(menu), item); /* Hide action */ item = gtk_menu_item_new_with_label(_("Hide dock")); g_signal_connect(G_OBJECT(item), "activate", G_CALLBACK(onMainMenuHideClicked), window); gtk_menu_shell_append(GTK_MENU_SHELL(menu), item); } DBG_fprintf(stderr, "Gtk VisuUiPanel: create the main menu %p.\n", (gpointer)menu); return menu; } static void onMainMenuClicked(GtkMenuItem *menuitem, gpointer user_data) { VisuUiPanel *visu_ui_panel; VisuUiDockWindow *window; visu_ui_panel = (VisuUiPanel*)0; visu_ui_panel = VISU_UI_PANEL(g_object_get_qdata(G_OBJECT(menuitem), CURRENT_TOOLPANEL_POINTER)); g_return_if_fail(VISU_IS_UI_PANEL(visu_ui_panel)); window = (VisuUiDockWindow*)user_data; DBG_fprintf(stderr, "Gtk VisuUiPanel: attaching panel '%s' (%p) to %p.\n", visu_ui_panel->tabLabel, (gpointer)visu_ui_panel, (gpointer)window); visu_ui_panel_attach(visu_ui_panel, window); g_object_unref(G_OBJECT(visu_ui_panel)); } static void onMainMenuShowClicked(GtkMenuItem *menuitem _U_, gpointer user_data) { VisuUiDockWindow *dock; g_return_if_fail(user_data); dock = (VisuUiDockWindow*)user_data; if (dock->window) gtk_widget_show(dock->window); dock->show = TRUE; } static void onMainMenuHideClicked(GtkMenuItem *menuitem _U_, gpointer user_data) { VisuUiDockWindow *dock; g_return_if_fail(user_data); dock = (VisuUiDockWindow*)user_data; if (dock->window) gtk_widget_hide(dock->window); dock->show = FALSE; } static void onMainMenuSelected(GtkMenuShell *menushell, gpointer user_data _U_) { DBG_fprintf(stderr, "Gtk VisuUiPanel: destroy the main menu %p.\n", (gpointer)menushell); gtk_widget_destroy(GTK_WIDGET(menushell)); } static void onRaiseButtonClicked(GtkButton *button _U_, gpointer data _U_) { GtkWindow *window; window = visu_ui_getRenderWindow(); g_return_if_fail(window); /* We raised the rendering window, if required. */ gtk_window_present(window); } /******************/ /* Class methods. */ /******************/ /** * visu_ui_panel_class_getCommandPanel: * * There is always a #VisuUiDockWindow that is inside the command * panel. This routine gets it. * * Returns: (transfer none):the #VisuUiDockWindow that is inside the command panel. */ VisuUiDockWindow* visu_ui_panel_class_getCommandPanel(void) { if (!local_class) g_type_class_ref(VISU_TYPE_UI_PANEL); if (!local_class->commandPanel) { local_class->commandPanel = dock_window_new(MAIN_PANEL_NAME, FALSE); local_class->hostingWindows = g_list_prepend(local_class->hostingWindows, local_class->commandPanel); } return local_class->commandPanel; } /** * visu_ui_panel_class_setCurrent: * @dataObj: a #VisuData object. * @view: a #VisuGlView object. * * Set the currently focussed #VisuData. It then can be retrieve using * visu_ui_panel_getData(). * * Since: 3.7 */ void visu_ui_panel_class_setCurrent(VisuData *dataObj, VisuGlView *view) { if (!local_class) g_type_class_ref(VISU_TYPE_UI_PANEL); local_class->dataObj = dataObj; local_class->viewObj = view; } /** * visu_ui_panel_class_getPanelById: * @id: a #VisuUiPanel identifier. * * This routine associates a #VisuUiPanel identifier to the object pointer. * * Returns: (transfer none): the #VisuUiPanel that corresponds to this identifier or NULL * if none exists. */ VisuUiPanel* visu_ui_panel_class_getPanelById(const gchar *id) { gpointer panel; if (!local_class) g_type_class_ref(VISU_TYPE_UI_PANEL); DBG_fprintf(stderr, "Gtk VisuUiPanel: search panel '%s'.\n", id); panel = g_hash_table_lookup(local_class->allVisuUiPanels, id); if (!panel) return (VisuUiPanel*)0; else return VISU_UI_PANEL(panel); } /** * visu_ui_panel_class_getDockById: * @id: a #VisuUiDockWindow identifier. * * This routine associates a #VisuUiDockWindow identifier to the object pointer. * * Returns: the #VisuUiDockWindow that corresponds to this identifier. The * dock window is built if not currently exist. */ VisuUiDockWindow* visu_ui_panel_class_getDockById(const gchar *id) { VisuUiDockWindow *window; GList *tmplst; if (!local_class) g_type_class_ref(VISU_TYPE_UI_PANEL); if (!strcmp(id, "None")) return (VisuUiDockWindow*)0; if (!strcmp(id, "Main")) return local_class->commandPanel; tmplst = local_class->hostingWindows; while (tmplst) { if (!strcmp(((VisuUiDockWindow*)tmplst->data)->name, id)) return (VisuUiDockWindow*)tmplst->data; tmplst = g_list_next(tmplst); }; /* No matching name found, we create a new window. */ window = dock_window_new(g_strdup(id), TRUE); local_class->hostingWindows = g_list_prepend(local_class->hostingWindows, (gpointer)window); return window; } /** * visu_ui_panel_class_getAllPanels: * * This routine can be used to know all existing #VisuUiPanel. * * Returns: (transfer full) (element-type VisuUiPanel*): a newly * created list (use g_list_free() on it after use). */ GList* visu_ui_panel_class_getAllPanels(void) { GList *tmplst, *returnlst; gboolean valid; GtkTreeIter iter; VisuUiPanel *tool; GtkTreeModel *treeModel; if (!local_class) g_type_class_ref(VISU_TYPE_UI_PANEL); DBG_fprintf(stderr, "Gtk VisuUiPanel: create list of all panels.\n"); returnlst = (GList*)0; tmplst = local_class->hostingWindows; while (tmplst) { treeModel = GTK_TREE_MODEL(((VisuUiDockWindow*)tmplst->data)->list); valid = gtk_tree_model_get_iter_first(treeModel, &iter); while (valid) { gtk_tree_model_get(treeModel, &iter, TOOL_LIST_POINTER_TO_DATA, &tool, -1); DBG_fprintf(stderr, " | add '%s'\n", tool->id); returnlst = g_list_prepend(returnlst, (gpointer)tool); valid = gtk_tree_model_iter_next(treeModel, &iter); } tmplst = g_list_next(tmplst); } returnlst = g_list_concat(returnlst, g_list_copy(local_class->orphanVisuUiPanel)); return returnlst; } /** * visu_ui_panel_class_getAllWindows: * * This routine can be used to know all existing #VisuUiDockWindow. * * Returns: (transfer container) (element-type VisuUiDockWindow*): a * newly created list (use g_list_free() on it after use). */ GList* visu_ui_panel_class_getAllWindows(void) { GList *returnlst; if (!local_class) g_type_class_ref(VISU_TYPE_UI_PANEL); DBG_fprintf(stderr, "Gtk VisuUiPanel : create list of all windows.\n"); returnlst = g_list_copy(local_class->hostingWindows); returnlst = g_list_remove(returnlst, local_class->commandPanel); return returnlst; } /** * visu_ui_panel_class_setHeaderVisibility: * @status: a boolean. * * The header can be represented using the full image and label always * or only the image when the tab is not on top. */ void visu_ui_panel_class_setHeaderVisibility(gboolean status) { GList *tmpLst; int num, i; GtkNotebook *notebook; if (!local_class) g_type_class_ref(VISU_TYPE_UI_PANEL); DBG_fprintf(stderr, "Gtk VisuUiPanel : set the header visibility.\n"); if (local_class->showHeader == status) return; tmpLst = local_class->hostingWindows; while(tmpLst) { notebook = GTK_NOTEBOOK(((VisuUiDockWindow*)tmpLst->data)->notebook); num = gtk_notebook_get_current_page(notebook); for (i = 0; i < gtk_notebook_get_n_pages(notebook); i++) changeHeaderVisibility(VISU_UI_PANEL(gtk_notebook_get_nth_page(notebook, i)), status || (i == num)); tmpLst = g_list_next(tmpLst); } local_class->showHeader = status; } /** * visu_ui_panel_class_getHeaderVisibility: * * The header can be represented using the full image and label always * or only the image when the tab is not on top. * * Since: 3.8 * * Returns: TRUE if the header uses text and label. **/ gboolean visu_ui_panel_class_getHeaderVisibility(void) { if (!local_class) g_type_class_ref(VISU_TYPE_UI_PANEL); return local_class->showHeader; } /************************/ /* Dock window methods. */ /************************/ GType visu_ui_dock_window_get_type(void) { static GType g_define_type_id = 0; if (g_define_type_id == 0) g_define_type_id = g_boxed_type_register_static("VisuUiDockWindow", (GBoxedCopyFunc)dock_window_ref, (GBoxedFreeFunc)dock_window_unref); return g_define_type_id; } static VisuUiDockWindow* dock_window_new(gchar *name, gboolean withWindow) { VisuUiDockWindow *window; GtkWidget *wd, *image; GtkCellRenderer *renderer; /* GtkBindingSet *keys; */ #if GTK_MAJOR_VERSION == 2 && GTK_MINOR_VERSION < 12 GtkTooltips *tooltips; tooltips = gtk_tooltips_new (); #endif window = g_malloc(sizeof(VisuUiDockWindow)); window->refCount = 1; DBG_fprintf(stderr, "Gtk VisuUiPanel: create a new dock window %p (%s).\n", (gpointer)window, name); window->name = name; window->show = !strcmp(name, MAIN_PANEL_NAME); window->vbox = gtk_vbox_new(FALSE, 0); if (withWindow) { window->window = gtk_window_new(GTK_WINDOW_TOPLEVEL); gtk_window_set_title(GTK_WINDOW(window->window), window->name); gtk_window_set_default_size(GTK_WINDOW(window->window), 350, 350); gtk_window_set_type_hint(GTK_WINDOW(window->window), GDK_WINDOW_TYPE_HINT_UTILITY); gtk_window_set_skip_pager_hint(GTK_WINDOW(window->window), TRUE); g_signal_connect(G_OBJECT(window->window), "delete-event", G_CALLBACK(onKillVisuUiDockWindowEvent), (gpointer)window); g_signal_connect(G_OBJECT(window->window), "destroy-event", G_CALLBACK(onKillVisuUiDockWindowEvent), (gpointer)window); g_signal_connect(G_OBJECT(window->window), "key-press-event", G_CALLBACK(onHomePressed), (gpointer)window); gtk_container_set_border_width(GTK_CONTAINER(window->window), 3); gtk_container_add(GTK_CONTAINER(window->window), window->vbox); /* gtk_widget_show(window->window); */ } else window->window = (GtkWidget*)0; window->notebook = gtk_notebook_new(); gtk_widget_set_margin_top(window->notebook, 5); gtk_notebook_set_scrollable(GTK_NOTEBOOK(window->notebook), TRUE); gtk_box_pack_end(GTK_BOX(window->vbox), window->notebook, TRUE, TRUE, 0); window->notebookChanged = g_signal_connect(G_OBJECT(window->notebook), "switch-page", G_CALLBACK(onPageChanged), (gpointer)window); window->hbox = gtk_hbox_new(FALSE, 0); gtk_box_pack_start(GTK_BOX(window->vbox), window->hbox, FALSE, FALSE, 0); /* Define the key bindings. */ /* keys = gtk_binding_set_new("commandPanel"); */ /* gtk_binding_entry_add_signal(keys, GDK_KEY_space, 0, "clicked", 1, (gpointer)window); */ /* Raise render area. */ wd = gtk_button_new(); g_object_set(G_OBJECT(wd), "can-default", TRUE, "can-focus", TRUE, "has-default", FALSE, "has-focus", FALSE, NULL); /* gtk_button_set_relief(GTK_BUTTON(wd), GTK_RELIEF_NONE); */ gtk_box_pack_start(GTK_BOX(window->hbox), wd, FALSE, FALSE, 0); g_signal_connect(G_OBJECT(wd), "clicked", G_CALLBACK(onRaiseButtonClicked), (gpointer)window); image = gtk_image_new_from_icon_name("go-up", GTK_ICON_SIZE_MENU); gtk_container_add(GTK_CONTAINER(wd), image); gtk_widget_set_tooltip_text(wd, _("Raise the rendering window.\n" " Use as key binding.")); /* The Label to introduce the combo list. */ wd = gtk_label_new(_("Tool: ")); gtk_box_pack_start(GTK_BOX(window->hbox), wd, FALSE, FALSE, 2); /* We create the list store. */ window->list = gtk_list_store_new(TOOL_LIST_N_COLUMNS, GDK_TYPE_PIXBUF, G_TYPE_STRING, G_TYPE_STRING, G_TYPE_POINTER); /* The combo list. */ window->combo = gtk_combo_box_new_with_model(GTK_TREE_MODEL(window->list)); renderer = gtk_cell_renderer_pixbuf_new(); gtk_cell_renderer_set_fixed_size(renderer, 22, -1); gtk_cell_layout_pack_start(GTK_CELL_LAYOUT(window->combo), renderer, FALSE); gtk_cell_layout_add_attribute(GTK_CELL_LAYOUT(window->combo), renderer, "pixbuf", TOOL_LIST_ICON); gtk_cell_layout_add_attribute(GTK_CELL_LAYOUT(window->combo), renderer, "stock-id", TOOL_LIST_STOCK); renderer = gtk_cell_renderer_text_new(); gtk_cell_layout_pack_start(GTK_CELL_LAYOUT(window->combo), renderer, FALSE); gtk_cell_layout_add_attribute(GTK_CELL_LAYOUT(window->combo), renderer, "text", TOOL_LIST_NAME); gtk_box_pack_start(GTK_BOX(window->hbox), window->combo, TRUE, TRUE, 0); window->comboChanged = g_signal_connect(G_OBJECT(window->combo), "changed", G_CALLBACK(onComboChanged), (gpointer)window); /* Add a menu button. */ wd = gtk_button_new(); gtk_button_set_relief(GTK_BUTTON(wd), GTK_RELIEF_NONE); gtk_box_pack_start(GTK_BOX(window->hbox), wd, FALSE, FALSE, 2); g_signal_connect(G_OBJECT(wd), "clicked", G_CALLBACK(onMainButtonClicked), (gpointer)window); image = create_pixmap((GtkWidget*)0, "stock-menu-detach.png"); gtk_container_add(GTK_CONTAINER(wd), image); gtk_widget_set_tooltip_text(wd, _("Manage hidden subpanels and dock windows.")); /* Add a help tooltips. */ wd = gtk_event_box_new(); gtk_event_box_set_visible_window(GTK_EVENT_BOX(wd), FALSE); gtk_widget_set_tooltip_text(wd, _("Positions, sizes, names, contains... of dock" \ " windows are stored in the parameters file, " \ "see the 'Config. files' button on the command panel.")); gtk_box_pack_end(GTK_BOX(window->hbox), wd, FALSE, FALSE, 2); image = gtk_image_new_from_icon_name("help-browser", GTK_ICON_SIZE_MENU); gtk_container_add(GTK_CONTAINER(wd), image); gtk_widget_show_all(window->vbox); return window; } static VisuUiDockWindow* dock_window_ref(VisuUiDockWindow *dock) { dock->refCount += 1; return dock; } static void dock_window_unref(VisuUiDockWindow *dock) { dock->refCount -= 1; if (!dock->refCount) { if (dock->window) gtk_widget_destroy(dock->window); else gtk_widget_destroy(dock->vbox); } } /** * visu_ui_dock_window_getCharacteristics: * @dock: a #VisuUiDockWindow object ; * @id: a location to store the identifier (owned by V_Sim) ; * @visibility: a location to store the status of the dock, hidden or * not ; * @x: a location to store its x position on the root window ; * @y: a location to store its y position on the root window ; * @width: a location to store its width ; * @height: a location to store its height. * * A routine to know everything about a #VisuUiDockWindow. */ void visu_ui_dock_window_getCharacteristics(VisuUiDockWindow *dock, gchar **id, gboolean *visibility, gint *x, gint *y, gint *width, gint *height) { g_return_if_fail(dock); *id = dock->name; *visibility = dock->show; gtk_window_get_position(GTK_WINDOW(dock->window), x, y); gtk_window_get_size(GTK_WINDOW(dock->window), width, height); } /** * visu_ui_dock_window_getContainer: * @dock: a dock window descriptor. * * A dock window is a small utility window with a list of #VisuUiPanel. * This window can be embedded in a container or have its own * GtkWindow. This routine get the top-level container inside a given * #VisuUiDockWindow. If you prefer to get the GtkWindow containing the * #VisuUiDockWindow use visu_ui_dock_window_getWindow() instead. * * Returns: (transfer none): a top-level container (usually a #GtkVBox). */ GtkWidget* visu_ui_dock_window_getContainer(VisuUiDockWindow *dock) { g_return_val_if_fail(dock, (GtkWidget*)0); return dock->vbox; } /** * visu_ui_dock_window_getNotebook: * @dock: a dock window descriptor. * * A dock window is a small utility window with a list of #VisuUiPanel. * All #VisuUiPanel are contained in a #GtkNotebook. This routine gets it. * * Returns: (transfer none): the #GtkNotebook containing the #VisuUiPanel of this * #VisuUiDockWindow. */ GtkWidget* visu_ui_dock_window_getNotebook(VisuUiDockWindow *dock) { g_return_val_if_fail(dock, (GtkWidget*)0); return dock->notebook; } /** * visu_ui_dock_window_getWindow: * @dock: a dock window descriptor. * * A dock window is a small utility window with a list of #VisuUiPanel. * This window can be embedded in a container or have its own * GtkWindow. This routine get the #GtkWindow containing the * #VisuUiDockWindow in the case the dock is stand-alone. If not NULL is returned. * * Returns: (transfer none): a top-level container (usually a #GtkWindow) or NULL. */ GtkWidget* visu_ui_dock_window_getWindow(VisuUiDockWindow *dock) { g_return_val_if_fail(dock, (GtkWidget*)0); if (dock->window) return dock->window; else return GTK_WIDGET(visu_ui_main_class_getCurrentPanel()); } /** * visu_ui_dock_window_setSize: * @dock: a #VisuUiDockWindow object ; * @width: the requested width ; * @height: the requested height. * * Change the size of the given #VisuUiDockWindow. The size is possibly * adapted to avoid been out of screen. */ void visu_ui_dock_window_setSize(VisuUiDockWindow *dock, guint width, guint height) { GdkScreen *screen; gint widthScreen, heightScreen; gint widthSet, heightSet; g_return_if_fail(dock && dock->window); g_return_if_fail(dock != visu_ui_panel_class_getCommandPanel()); /* Before setting (width, height), we check that it is coherent with the screen size. */ if (gtk_widget_is_drawable(dock->window)) screen = gdk_window_get_screen (GDK_WINDOW(gtk_widget_get_window(dock->window))); else screen = gdk_screen_get_default(); #if GTK_MAJOR_VERSION < 3 || (GTK_MAJOR_VERSION == 3 && GTK_MINOR_VERSION < 22) widthScreen = gdk_screen_get_width(screen); heightScreen = gdk_screen_get_height(screen); #else (void)screen; widthScreen = 10240; heightScreen = 10240; #endif widthSet = ((gint)width > widthScreen)?widthScreen:(gint)width; heightSet = ((gint)height > heightScreen)?heightScreen:(gint)height; if (widthSet < 0) widthSet = 50; if (heightSet < 0) heightSet = 50; DBG_fprintf(stderr, "Gtk VisuUiPanel: set window (%s) size %dx%d.\n", dock->name, widthSet, heightSet); gtk_window_resize(GTK_WINDOW(dock->window), widthSet, heightSet); } /** * visu_ui_dock_window_setPosition: * @dock: a #VisuUiDockWindow object ; * @x: the requested x position ; * @y: the requested y position. * * Change the position of the given #VisuUiDockWindow. The position is possibly * adapted to avoid been out of screen. */ void visu_ui_dock_window_setPosition(VisuUiDockWindow *dock, guint x, guint y) { GdkScreen *screen; gint xScreen, yScreen; gint xPosition, yPosition; gint width, height; g_return_if_fail(dock && dock->window); g_return_if_fail(dock != visu_ui_panel_class_getCommandPanel()); /* Before setting (x, y), we check that it is coherent with the screen definition. */ if (gtk_widget_is_drawable(dock->window)) screen = gdk_window_get_screen (GDK_WINDOW(gtk_widget_get_window(dock->window))); else screen = gdk_screen_get_default(); #if GTK_MAJOR_VERSION < 3 || (GTK_MAJOR_VERSION == 3 && GTK_MINOR_VERSION < 22) xScreen = gdk_screen_get_width(screen); yScreen = gdk_screen_get_height(screen); #else (void)screen; xScreen = 10240; yScreen = 10240; #endif gtk_window_get_size(GTK_WINDOW(dock->window), &width, &height); xPosition = ((gint)x + width > xScreen)?xScreen - width:(gint)x; yPosition = ((gint)y + height > yScreen)?yScreen - height:(gint)y; if (xPosition < 0) xPosition = 0; if (yPosition < 0) yPosition = 0; DBG_fprintf(stderr, "Gtk VisuUiPanel: set window (%s) position %dx%d.\n", dock->name, xPosition, yPosition); gtk_window_move(GTK_WINDOW(dock->window), xPosition, yPosition); } /** * visu_ui_dock_window_setVisibility: * @dock: a #VisuUiDockWindow object ; * @visible: a boolean. * * Change the visibility of a #VisuUiDockWindow. If hidden, the dock is * added to the list of hidden #VisuUiDockWindow that can be shown again * using the pop-up menu on every visible #VisuUiDockWindow. The 'Main' dock * window can not be hidden. */ void visu_ui_dock_window_setVisibility(VisuUiDockWindow *dock, gboolean visible) { g_return_if_fail(dock && dock->window); g_return_if_fail(dock != visu_ui_panel_class_getCommandPanel()); dock->show = visible; if (!visible) gtk_widget_hide(dock->window); else gtk_widget_show(dock->window); } static void onEntryTabview(VisuConfigFile *obj _U_, VisuConfigFileEntry *entry _U_, VisuUiPanelClass *klass _U_) { visu_ui_panel_class_setHeaderVisibility(_tabView); } /* These functions write all the element list to export there associated resources. */ static void exportParameters(GString *data, VisuData *dataObj _U_) { g_string_append_printf(data, "# %s\n", DESC_PARAMETER_TABVIEW_CONFIG); g_string_append_printf(data, "%s[gtk]: %d\n\n", FLAG_PARAMETER_TABVIEW_CONFIG, local_class->showHeader); } v_sim-3.8.0/src/extraGtkFunctions/gtk_toolPanelWidget.h000066400000000000000000000144701370110300500232230ustar00rootroot00000000000000/* EXTRAITS DE LA LICENCE Copyright CEA, contributeurs : Luc BILLARD et Damien CALISTE, laboratoire L_Sim, (2001-2005) Adresse mèl : BILLARD, non joignable par mèl ; CALISTE, damien P caliste AT cea P fr. Ce logiciel est un programme informatique servant à visualiser des structures atomiques dans un rendu pseudo-3D. Ce logiciel est régi par la licence CeCILL soumise au droit français et respectant les principes de diffusion des logiciels libres. Vous pouvez utiliser, modifier et/ou redistribuer ce programme sous les conditions de la licence CeCILL telle que diffusée par le CEA, le CNRS et l'INRIA sur le site "http://www.cecill.info". Le fait que vous puissiez accéder à cet en-tête signifie que vous avez pris connaissance de la licence CeCILL, et que vous en avez accepté les termes (cf. le fichier Documentation/licence.fr.txt fourni avec ce logiciel). */ /* LICENCE SUM UP Copyright CEA, contributors : Luc BILLARD et Damien CALISTE, laboratoire L_Sim, (2001-2005) E-mail address: BILLARD, not reachable any more ; CALISTE, damien P caliste AT cea P fr. This software is a computer program whose purpose is to visualize atomic configurations in 3D. This software is governed by the CeCILL license under French law and abiding by the rules of distribution of free software. You can use, modify and/ or redistribute the software under the terms of the CeCILL license as circulated by CEA, CNRS and INRIA at the following URL "http://www.cecill.info". The fact that you are presently reading this means that you have had knowledge of the CeCILL license and that you accept its terms. You can find a copy of this licence shipped with this software at Documentation/licence.en.txt. */ #ifndef GTK_TOOLPANELWIDGET_H #define GTK_TOOLPANELWIDGET_H #include #include #include #include G_BEGIN_DECLS /** * VISU_TYPE_UI_PANEL: * * Return the associated #GType to the VisuUiPanel objects. */ #define VISU_TYPE_UI_PANEL (visu_ui_panel_get_type ()) /** * VISU_UI_PANEL: * @obj: the widget to cast. * * Cast the given object to a #VisuUiPanel object. */ #define VISU_UI_PANEL(obj) (G_TYPE_CHECK_INSTANCE_CAST ((obj), VISU_TYPE_UI_PANEL, VisuUiPanel)) /** * VISU_UI_PANEL_CLASS: * @klass: the class to cast. * * Cast the given class to a #VisuUiPanelClass object. */ #define VISU_UI_PANEL_CLASS(klass) (G_TYPE_CHECK_CLASS_CAST ((klass), VISU_TYPE_UI_PANEL, VisuUiPanelClass)) /** * VISU_IS_UI_PANEL: * @obj: the object to test. * * Return if the given object is a valid #VisuUiPanel object. */ #define VISU_IS_UI_PANEL(obj) (G_TYPE_CHECK_INSTANCE_TYPE ((obj), VISU_TYPE_UI_PANEL)) /** * VISU_IS_UI_PANEL_CLASS: * @klass: the class to test. * * Return if the given class is a valid #VisuUiPanelClass class. */ #define VISU_IS_UI_PANEL_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE ((klass), VISU_TYPE_UI_PANEL)) typedef struct _VisuUiPanel VisuUiPanel; typedef struct _VisuUiPanelClass VisuUiPanelClass; GType visu_ui_panel_get_type(void); typedef struct _VisuUiDockWindow VisuUiDockWindow; GType visu_ui_dock_window_get_type(void); /** * VISU_TYPE_UI_DOCK_WINDOW: * * The type of #VisuUiDockWindow objects. */ #define VISU_TYPE_UI_DOCK_WINDOW (visu_ui_dock_window_get_type()) GtkWidget* visu_ui_panel_new(gchar *id, gchar* name, gchar *tabName); GtkWidget* visu_ui_panel_newWithIconFromPath(gchar *id, gchar* name, gchar *tabName, const gchar* iconPath); GtkWidget* visu_ui_panel_newWithIconFromIconName(gchar *id, gchar* name, gchar *tabName, const gchar* icon); GtkWidget* visu_ui_panel_getHeaderWidget (VisuUiPanel *visu_ui_panel); const gchar* visu_ui_panel_getLabel (VisuUiPanel *visu_ui_panel); const gchar* visu_ui_panel_getId (VisuUiPanel *visu_ui_panel); GtkWindow* visu_ui_panel_getContainerWindow(VisuUiPanel *visu_ui_panel); VisuUiDockWindow* visu_ui_panel_getContainer (VisuUiPanel *visu_ui_panel); const gchar* visu_ui_panel_getContainerId (VisuUiPanel *visu_ui_panel); VisuData* visu_ui_panel_getData (VisuUiPanel *visu_ui_panel); VisuBoxed* visu_ui_panel_getFocused (VisuUiPanel *visu_ui_panel); VisuGlView* visu_ui_panel_getView (VisuUiPanel *visu_ui_panel); gboolean visu_ui_panel_getVisible (VisuUiPanel *visu_ui_panel); void visu_ui_panel_setDockable (VisuUiPanel *visu_ui_panel, gboolean value); void visu_ui_panel_setContainer (VisuUiPanel *visu_ui_panel, VisuUiDockWindow *window); void visu_ui_panel_setContainerId(VisuUiPanel *visu_ui_panel, const gchar *id); void visu_ui_panel_attach(VisuUiPanel *visu_ui_panel, VisuUiDockWindow *dock); void visu_ui_panel_detach(VisuUiPanel *visu_ui_panel); /* Associated variables and methods. */ GtkWidget* visu_ui_dock_window_getContainer(VisuUiDockWindow *dock); GtkWidget* visu_ui_dock_window_getNotebook(VisuUiDockWindow *dock); GtkWidget* visu_ui_dock_window_getWindow(VisuUiDockWindow *dock); void visu_ui_dock_window_getCharacteristics(VisuUiDockWindow *dock, gchar **id, gboolean *visibility, gint *x, gint *y, gint *width, gint *height); void visu_ui_dock_window_setSize(VisuUiDockWindow *dock, guint width, guint height); void visu_ui_dock_window_setPosition(VisuUiDockWindow *dock, guint x, guint y); void visu_ui_dock_window_setVisibility(VisuUiDockWindow *dock, gboolean visible); /* Class methods. */ void visu_ui_panel_class_setCurrent(VisuData *dataObj, VisuGlView *view); void visu_ui_panel_class_setHeaderVisibility(gboolean status); gboolean visu_ui_panel_class_getHeaderVisibility(); VisuUiDockWindow* visu_ui_panel_class_getCommandPanel(void); VisuUiDockWindow* visu_ui_panel_class_getDockById(const gchar *id); GList* visu_ui_panel_class_getAllPanels(void); GList* visu_ui_panel_class_getAllWindows(void); VisuUiPanel* visu_ui_panel_class_getPanelById(const gchar *id); G_END_DECLS #endif v_sim-3.8.0/src/extraGtkFunctions/gtk_valueIOWidget.c000066400000000000000000000530601370110300500226230ustar00rootroot00000000000000/* EXTRAITS DE LA LICENCE Copyright CEA, contributeurs : Luc BILLARD et Damien CALISTE, laboratoire L_Sim, (2001-2005) Adresse mèl : BILLARD, non joignable par mèl ; CALISTE, damien P caliste AT cea P fr. Ce logiciel est un programme informatique servant à visualiser des structures atomiques dans un rendu pseudo-3D. Ce logiciel est régi par la licence CeCILL soumise au droit français et respectant les principes de diffusion des logiciels libres. Vous pouvez utiliser, modifier et/ou redistribuer ce programme sous les conditions de la licence CeCILL telle que diffusée par le CEA, le CNRS et l'INRIA sur le site "http://www.cecill.info". Le fait que vous puissiez accéder à cet en-tête signifie que vous avez pris connaissance de la licence CeCILL, et que vous en avez accepté les termes (cf. le fichier Documentation/licence.fr.txt fourni avec ce logiciel). */ /* LICENCE SUM UP Copyright CEA, contributors : Luc BILLARD et Damien CALISTE, laboratoire L_Sim, (2001-2005) E-mail address: BILLARD, not reachable any more ; CALISTE, damien P caliste AT cea P fr. This software is a computer program whose purpose is to visualize atomic configurations in 3D. This software is governed by the CeCILL license under French law and abiding by the rules of distribution of free software. You can use, modify and/ or redistribute the software under the terms of the CeCILL license as circulated by CEA, CNRS and INRIA at the following URL "http://www.cecill.info". The fact that you are presently reading this means that you have had knowledge of the CeCILL license and that you accept its terms. You can find a copy of this licence shipped with this software at Documentation/licence.en.txt. */ #include #include "gtk_valueIOWidget.h" #include #include #include #include /** * SECTION:gtk_valueIOWidget * @short_description: Defines a specialised #GtkHBox with three * button to open, save and save as XML value files. * * * * Since: 3.5 */ enum { PROP_0, SAVE_SENSITIVE_PROP, N_PROP }; static GParamSpec *properties[N_PROP]; static void visu_ui_value_io_dispose (GObject *obj); static void visu_ui_value_io_finalize(GObject *obj); static void visu_ui_value_io_get_property(GObject* obj, guint property_id, GValue *value, GParamSpec *pspec); static void visu_ui_value_io_set_property(GObject* obj, guint property_id, const GValue *value, GParamSpec *pspec); /** * VisuUiValueIo: * * Private structure to store informations of a #VisuUiValueIo object. * * Since: 3.5 */ struct _VisuUiValueIo { GtkBox hbox; GtkWidget *btExportOpen, *btExportSave, *btExportSaveAs; #if GTK_MAJOR_VERSION == 2 && GTK_MINOR_VERSION < 12 GtkWidget *dialog; #endif GtkWindow *parent; VisuUiValueIoCallback ioOpen; gulong openSignalId; VisuUiValueIoCallback ioSave; gulong saveSignalId; gulong saveAsSignalId; /* Memory gestion. */ gboolean dispose_has_run; }; /** * VisuUiValueIoClass * * Private structure to store informations of a #VisuUiValueIoClass object. * * Since: 3.5 */ struct _VisuUiValueIoClass { GtkBoxClass parent_class; void (*valueio) (VisuUiValueIo *hbox); }; /* Local callbacks. */ #if GTK_MAJOR_VERSION > 2 || GTK_MINOR_VERSION > 11 static void onImportXML(GtkFileChooserButton *filechooserbutton, gpointer data); #else static void onImportXML(GtkDialog *dialog, gint response, gpointer data); #endif #if GTK_MAJOR_VERSION == 2 && GTK_MINOR_VERSION < 6 static void onOpenXMLClicked(GtkButton *bt, gpointer data); #endif static void onExportXML(GtkButton *button, gpointer data); /* Local methods. */ /** * visu_ui_value_io_get_type * * #GType are unique numbers to identify objects. * * Returns: the #GType associated with #VisuUiValueIo objects. * * Since: 3.5 */ G_DEFINE_TYPE(VisuUiValueIo, visu_ui_value_io, GTK_TYPE_BOX) static void visu_ui_value_io_class_init(VisuUiValueIoClass *klass) { DBG_fprintf(stderr, "Gtk VisuUiValueIo: creating the class of the widget.\n"); /* Connect freeing methods. */ G_OBJECT_CLASS(klass)->dispose = visu_ui_value_io_dispose; G_OBJECT_CLASS(klass)->finalize = visu_ui_value_io_finalize; G_OBJECT_CLASS(klass)->set_property = visu_ui_value_io_set_property; G_OBJECT_CLASS(klass)->get_property = visu_ui_value_io_get_property; /** * VisuUiValueIo::sensitive-save: * * The save and save-as buttons sensitivity. * * Since: 3.8 */ properties[SAVE_SENSITIVE_PROP] = g_param_spec_boolean("sensitive-save", "Sensitive save", "sensitivity of save buttons", FALSE, G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS); g_object_class_install_property(G_OBJECT_CLASS(klass), SAVE_SENSITIVE_PROP, properties[SAVE_SENSITIVE_PROP]); } static void visu_ui_value_io_dispose(GObject *obj) { DBG_fprintf(stderr, "Gtk VisuUiValueIo: dispose object %p.\n", (gpointer)obj); if (VISU_UI_VALUE_IO(obj)->dispose_has_run) return; VISU_UI_VALUE_IO(obj)->dispose_has_run = TRUE; /* Chain up to the parent class */ G_OBJECT_CLASS(visu_ui_value_io_parent_class)->dispose(obj); } static void visu_ui_value_io_finalize(GObject *obj) { g_return_if_fail(obj); DBG_fprintf(stderr, "Gtk VisuUiValueIo: finalize object %p.\n", (gpointer)obj); /* Chain up to the parent class */ G_OBJECT_CLASS(visu_ui_value_io_parent_class)->finalize(obj); DBG_fprintf(stderr, " | freeing ... OK.\n"); } static void visu_ui_value_io_get_property(GObject* obj, guint property_id, GValue *value, GParamSpec *pspec) { VisuUiValueIo *self = VISU_UI_VALUE_IO(obj); DBG_fprintf(stderr, "Gtk VisuUiValueIo: get property '%s'.\n", g_param_spec_get_name(pspec)); switch (property_id) { case SAVE_SENSITIVE_PROP: g_value_set_boolean(value, gtk_widget_get_sensitive(self->btExportSaveAs)); break; default: /* We don't have any other property... */ G_OBJECT_WARN_INVALID_PROPERTY_ID(obj, property_id, pspec); break; } } static void visu_ui_value_io_set_property(GObject* obj, guint property_id, const GValue *value, GParamSpec *pspec) { VisuUiValueIo *self = VISU_UI_VALUE_IO(obj); DBG_fprintf(stderr, "Gtk VisuUiValueIo: set property '%s'.\n", g_param_spec_get_name(pspec)); switch (property_id) { case SAVE_SENSITIVE_PROP: visu_ui_value_io_setSensitiveSave(self, g_value_get_boolean(value)); break; default: /* We don't have any other property... */ G_OBJECT_WARN_INVALID_PROPERTY_ID(obj, property_id, pspec); break; } } static void visu_ui_value_io_init(VisuUiValueIo *valueio) { DBG_fprintf(stderr, "Gtk VisuUiValueIo: initializing new object (%p).\n", (gpointer)valueio); valueio->ioOpen = (VisuUiValueIoCallback)0; valueio->openSignalId = 0; valueio->ioSave = (VisuUiValueIoCallback)0; valueio->saveSignalId = 0; valueio->saveAsSignalId = 0; } static void buildWidgets(VisuUiValueIo *valueio, GtkWindow *parent, const gchar*tipsOpen, const gchar*tipsSave, const gchar*tipsSaveAs) { GtkFileFilter *filter1, *filter2; const gchar *directory; #if GTK_MAJOR_VERSION == 2 && GTK_MINOR_VERSION < 12 GtkTooltips *tooltips; tooltips = gtk_tooltips_new(); #endif gtk_box_set_spacing(GTK_BOX(valueio), 2); valueio->parent = parent; /* The save as button. */ valueio->btExportSaveAs = gtk_button_new(); gtk_widget_set_tooltip_text(valueio->btExportSaveAs, tipsSaveAs); gtk_widget_set_sensitive(valueio->btExportSaveAs, FALSE); gtk_container_add(GTK_CONTAINER(valueio->btExportSaveAs), gtk_image_new_from_icon_name("document-save-as", GTK_ICON_SIZE_MENU)); gtk_box_pack_end(GTK_BOX(valueio), valueio->btExportSaveAs, FALSE, FALSE, 0); #if GTK_MAJOR_VERSION > 2 || GTK_MINOR_VERSION > 5 /* The save button. */ valueio->btExportSave = gtk_button_new(); gtk_widget_set_tooltip_text(valueio->btExportSave, tipsSave); gtk_widget_set_sensitive(valueio->btExportSave, FALSE); gtk_container_add(GTK_CONTAINER(valueio->btExportSave), gtk_image_new_from_icon_name("document-save", GTK_ICON_SIZE_MENU)); gtk_box_pack_end(GTK_BOX(valueio), valueio->btExportSave, FALSE, FALSE, 0); #endif /* The open button. */ filter1 = gtk_file_filter_new(); gtk_file_filter_set_name(filter1, _("V_Sim value file (*.xml)")); gtk_file_filter_add_pattern(filter1, "*.xml"); filter2 = gtk_file_filter_new (); gtk_file_filter_set_name(filter2, _("All files")); gtk_file_filter_add_pattern (filter2, "*"); #if GTK_MAJOR_VERSION > 2 || GTK_MINOR_VERSION > 11 valueio->btExportOpen = gtk_file_chooser_button_new(_("Open a V_Sim value file"), GTK_FILE_CHOOSER_ACTION_OPEN); gtk_file_chooser_add_filter(GTK_FILE_CHOOSER(valueio->btExportOpen), filter1); gtk_file_chooser_add_filter(GTK_FILE_CHOOSER(valueio->btExportOpen), filter2); #else valueio->dialog = gtk_file_chooser_dialog_new (_("Open a V_Sim value file"), parent, GTK_FILE_CHOOSER_ACTION_OPEN, GTK_STOCK_CANCEL, GTK_RESPONSE_CANCEL, GTK_STOCK_OPEN, GTK_RESPONSE_ACCEPT, NULL); gtk_file_chooser_add_filter(GTK_FILE_CHOOSER(valueio->dialog), filter1); gtk_file_chooser_add_filter(GTK_FILE_CHOOSER(valueio->dialog), filter2); #if GTK_MAJOR_VERSION > 2 || GTK_MINOR_VERSION > 5 valueio->btExportOpen = gtk_file_chooser_button_new_with_dialog(valueio->dialog); #else valueio->btExportOpen = gtk_button_new_from_stock(GTK_STOCK_OPEN); #endif #endif #if GTK_MAJOR_VERSION > 2 || GTK_MINOR_VERSION > 5 directory = visu_ui_main_getLastOpenDirectory(visu_ui_main_class_getCurrentPanel()); if (directory) gtk_file_chooser_set_current_folder(GTK_FILE_CHOOSER(valueio->btExportOpen), directory); #endif gtk_widget_set_tooltip_text(valueio->btExportOpen, tipsOpen); gtk_widget_set_sensitive(valueio->btExportOpen, FALSE); gtk_box_pack_end(GTK_BOX(valueio), valueio->btExportOpen, TRUE, TRUE, 0); /* The label. */ gtk_box_pack_end(GTK_BOX(valueio), gtk_label_new(_("I/O:")), FALSE, FALSE, 0); } /** * visu_ui_value_io_new: * @parent: the parent used to show the file dialog. * @tipsOpen: a tooltip to show on open button. * @tipsSave: a tooltip to show on save button. * @tipsSaveAs: a tooltip to show on save-as button. * * A #VisuUiValueIo widget is like a #GtkComboBox widget, but it is already filled * with predefined line patterns (call stipple). Using this widget is * a convienient way to share stipples between all part of V_Sim and * to give a consistent look of all stipple selection. * * Since: 3.5 * * Returns: (transfer full): a newly created #VisuUiValueIo widget. */ GtkWidget* visu_ui_value_io_new(GtkWindow *parent, const gchar*tipsOpen, const gchar*tipsSave, const gchar*tipsSaveAs) { VisuUiValueIo *valueio; DBG_fprintf(stderr, "Gtk VisuUiValueIo: creating new object.\n"); valueio = VISU_UI_VALUE_IO(g_object_new(visu_ui_value_io_get_type (), NULL)); DBG_fprintf(stderr, "Gtk VisuUiValueIo: build widgets.\n"); buildWidgets(valueio, parent, tipsOpen, tipsSave, tipsSaveAs); return GTK_WIDGET(valueio); } /** * visu_ui_value_io_connectOnOpen: * @valueio: a #VisuUiValueIo widget. * @open: a method. * * Set the function to call when the open button is clicked. * * Since: 3.5 */ void visu_ui_value_io_connectOnOpen(VisuUiValueIo *valueio, VisuUiValueIoCallback open) { g_return_if_fail(VISU_IS_UI_VALUE_IO(valueio)); if (valueio->openSignalId) { #if GTK_MAJOR_VERSION > 2 || GTK_MINOR_VERSION > 5 #if GTK_MAJOR_VERSION > 2 || GTK_MINOR_VERSION > 11 g_signal_handler_disconnect(G_OBJECT(valueio->btExportOpen), valueio->openSignalId); #else g_signal_handler_disconnect(G_OBJECT(valueio->dialog), valueio->openSignalId); #endif #else g_signal_handler_disconnect(G_OBJECT(valueio->btExportOpen), valueio->openSignalId); #endif } valueio->ioOpen = open; #if GTK_MAJOR_VERSION > 2 || GTK_MINOR_VERSION > 5 #if GTK_MAJOR_VERSION > 2 || GTK_MINOR_VERSION > 11 valueio->openSignalId = g_signal_connect(G_OBJECT(valueio->btExportOpen), "file-set", G_CALLBACK(onImportXML), (gpointer)valueio); #else valueio->openSignalId = g_signal_connect(G_OBJECT(valueio->dialog), "response", G_CALLBACK(onImportXML), (gpointer)valueio); #endif #else valueio->openSignalId = g_signal_connect(G_OBJECT(valueio->btExportOpen), "clicked", G_CALLBACK(onOpenXMLClicked), (gpointer)valueio); #endif } /** * visu_ui_value_io_connectOnSave: * @valueio: a #VisuUiValueIo widget. * @save: a method. * * Set the function to call when the save or save-as button is clicked. * * Since: 3.5 */ void visu_ui_value_io_connectOnSave(VisuUiValueIo *valueio, VisuUiValueIoCallback save) { g_return_if_fail(VISU_IS_UI_VALUE_IO(valueio)); #if GTK_MAJOR_VERSION > 2 || GTK_MINOR_VERSION > 5 if (valueio->saveSignalId) g_signal_handler_disconnect(G_OBJECT(valueio->btExportSave), valueio->saveSignalId); #endif if (valueio->saveAsSignalId) g_signal_handler_disconnect(G_OBJECT(valueio->btExportSaveAs), valueio->saveAsSignalId); valueio->ioSave = save; valueio->saveAsSignalId = g_signal_connect(G_OBJECT(valueio->btExportSaveAs), "clicked", G_CALLBACK(onExportXML), (gpointer)valueio); #if GTK_MAJOR_VERSION > 2 || GTK_MINOR_VERSION > 5 valueio->saveSignalId = g_signal_connect(G_OBJECT(valueio->btExportSave), "clicked", G_CALLBACK(onExportXML), (gpointer)valueio); #endif } static gboolean loadXMLFile(gpointer data) { gchar *filename; GError *error; g_return_val_if_fail(VISU_IS_UI_VALUE_IO(data), FALSE); g_return_val_if_fail(VISU_UI_VALUE_IO(data)->ioOpen, FALSE); filename = g_object_get_data(G_OBJECT(data), "filename"); g_return_val_if_fail(filename, FALSE); error = (GError*)0; if (!VISU_UI_VALUE_IO(data)->ioOpen(filename, &error)) { visu_ui_raiseWarning (_("Import V_Sim values from a file."), error->message, VISU_UI_VALUE_IO(data)->parent); g_error_free(error); #if GTK_MAJOR_VERSION > 2 || GTK_MINOR_VERSION > 5 gtk_file_chooser_unselect_all(GTK_FILE_CHOOSER(VISU_UI_VALUE_IO(data)->btExportOpen)); #endif } g_free(filename); g_object_set_data(G_OBJECT(data), "filename", (gpointer)0); return FALSE; } #if GTK_MAJOR_VERSION > 2 || GTK_MINOR_VERSION > 11 static void onImportXML(GtkFileChooserButton *filechooserbutton, gpointer data) { gchar *filename; filename = gtk_file_chooser_get_filename(GTK_FILE_CHOOSER(filechooserbutton)); if (!filename) return; g_object_set_data(G_OBJECT(data), "filename", filename); g_idle_add(loadXMLFile, (gpointer)data); } #else static void onImportXML(GtkDialog *dialog, gint response, gpointer data) { gchar *filename; if (response != GTK_RESPONSE_ACCEPT) return; filename = gtk_file_chooser_get_filename(GTK_FILE_CHOOSER(dialog)); g_object_set_data(G_OBJECT(data), "filename", filename); g_idle_add(loadXMLFile, (gpointer)data); } #endif #if GTK_MAJOR_VERSION == 2 && GTK_MINOR_VERSION < 6 static void onOpenXMLClicked(GtkButton *bt _U_, gpointer data) { gchar *filename; if (gtk_dialog_run(GTK_DIALOG(VISU_UI_VALUE_IO(data)->dialog)) != GTK_RESPONSE_ACCEPT) return; filename = gtk_file_chooser_get_filename(GTK_FILE_CHOOSER(VISU_UI_VALUE_IO(data)->dialog)); g_object_set_data(G_OBJECT(data), "filename", filename); g_idle_add(loadXMLFile, (gpointer)data); } #endif /** * visu_ui_value_io_getFilename: * @parent: a parent to display the dialog on. * * Open a save dialog window with XML filter to choose the name of a * file. This is the default action that can be connect to a #VisuUiValueIo * widget using visu_ui_value_io_connectOnSave(). * * Since: 3.5 * * Returns: a filename that should be freed later with g_free() by the caller. */ gchar* visu_ui_value_io_getFilename(GtkWindow *parent) { GtkWidget *saveDialog; gchar *filename; const gchar *directory; GtkFileFilter *filter; saveDialog = gtk_file_chooser_dialog_new (_("Export V_Sim values to a file."), parent, GTK_FILE_CHOOSER_ACTION_SAVE, TOOL_ICON_CANCEL, GTK_RESPONSE_CANCEL, TOOL_ICON_SAVE, GTK_RESPONSE_ACCEPT, NULL); gtk_window_set_modal(GTK_WINDOW(saveDialog), TRUE); gtk_window_set_transient_for(GTK_WINDOW(saveDialog), GTK_WINDOW(parent)); gtk_window_set_position(GTK_WINDOW(saveDialog), GTK_WIN_POS_CENTER_ON_PARENT); directory = visu_ui_main_getLastOpenDirectory(visu_ui_main_class_getCurrentPanel()); if (directory) gtk_file_chooser_set_current_folder(GTK_FILE_CHOOSER(saveDialog), directory); gtk_file_chooser_set_select_multiple(GTK_FILE_CHOOSER(saveDialog), FALSE); gtk_dialog_set_default_response(GTK_DIALOG(saveDialog), GTK_RESPONSE_ACCEPT); filter = gtk_file_filter_new (); gtk_file_filter_set_name(filter, _("V_Sim value files (*.xml)")); gtk_file_filter_add_pattern(filter, "*.xml"); gtk_file_chooser_add_filter(GTK_FILE_CHOOSER(saveDialog), filter); filter = gtk_file_filter_new (); gtk_file_filter_set_name(filter, _("All files")); gtk_file_filter_add_pattern (filter, "*"); gtk_file_chooser_add_filter(GTK_FILE_CHOOSER(saveDialog), filter); /* A suggested filename. */ gtk_file_chooser_set_current_name(GTK_FILE_CHOOSER(saveDialog), _("values.xml")); if (gtk_dialog_run(GTK_DIALOG(saveDialog)) != GTK_RESPONSE_ACCEPT) { gtk_widget_destroy(saveDialog); return (gchar*)0; } filename = gtk_file_chooser_get_filename(GTK_FILE_CHOOSER(saveDialog)); gtk_widget_destroy(saveDialog); return filename; } static gboolean saveXMLFile(gpointer data) { gchar *filename; GError *error; g_return_val_if_fail(VISU_IS_UI_VALUE_IO(data), FALSE); g_return_val_if_fail(VISU_UI_VALUE_IO(data)->ioSave, FALSE); filename = g_object_get_data(G_OBJECT(data), "filename"); g_return_val_if_fail(filename, FALSE); error = (GError*)0; if (!VISU_UI_VALUE_IO(data)->ioSave(filename, &error)) { visu_ui_raiseWarning (_("Export V_Sim values to a file."), error->message, VISU_UI_VALUE_IO(data)->parent); g_error_free(error); } #if GTK_MAJOR_VERSION > 2 || GTK_MINOR_VERSION > 5 else { #if GTK_MAJOR_VERSION > 2 || GTK_MINOR_VERSION > 11 g_signal_handler_block(G_OBJECT(VISU_UI_VALUE_IO(data)->btExportOpen), VISU_UI_VALUE_IO(data)->openSignalId); #endif gtk_file_chooser_set_filename (GTK_FILE_CHOOSER(VISU_UI_VALUE_IO(data)->btExportOpen), filename); #if GTK_MAJOR_VERSION > 2 || GTK_MINOR_VERSION > 11 g_signal_handler_unblock(G_OBJECT(VISU_UI_VALUE_IO(data)->btExportOpen), VISU_UI_VALUE_IO(data)->openSignalId); #endif } #endif g_free(filename); g_object_set_data(G_OBJECT(data), "filename", (gpointer)0); return FALSE; } static void onExportXML(GtkButton *button, gpointer data) { gchar *filename; if (button == GTK_BUTTON(VISU_UI_VALUE_IO(data)->btExportSave)) filename = gtk_file_chooser_get_filename(GTK_FILE_CHOOSER(VISU_UI_VALUE_IO(data)->btExportOpen)); else filename = visu_ui_value_io_getFilename(VISU_UI_VALUE_IO(data)->parent); if (filename) { g_object_set_data(G_OBJECT(data), "filename", filename); g_idle_add(saveXMLFile, (gpointer)data); } } /** * visu_ui_value_io_setSensitiveOpen: * @valueio: a #VisuUiValueIo widget. * @status: a boolean. * * Modify the sensitivity of the open button, depending on @status. * * Since: 3.5 */ void visu_ui_value_io_setSensitiveOpen(VisuUiValueIo *valueio, gboolean status) { g_return_if_fail(VISU_IS_UI_VALUE_IO(valueio)); gtk_widget_set_sensitive(valueio->btExportOpen, status); } /** * visu_ui_value_io_setSensitiveSave: * @valueio: a #VisuUiValueIo widget. * @status: a boolean. * * Modify the sensitivity of the save button, depending on @status. * * Since: 3.5 */ void visu_ui_value_io_setSensitiveSave(VisuUiValueIo *valueio, gboolean status) { gchar *filename; g_return_if_fail(VISU_IS_UI_VALUE_IO(valueio)); #if GTK_MAJOR_VERSION > 2 || GTK_MINOR_VERSION > 5 filename = gtk_file_chooser_get_filename(GTK_FILE_CHOOSER(valueio->btExportOpen)); gtk_widget_set_sensitive(valueio->btExportSave, status && filename); if (filename) g_free(filename); #endif gtk_widget_set_sensitive(valueio->btExportSaveAs, status); g_object_notify_by_pspec(G_OBJECT(valueio), properties[SAVE_SENSITIVE_PROP]); } /** * visu_ui_value_io_setFilename: * @valueio: a #VisuUiValueIo widget. * @filename: a location on disk. * * Call the open routine previously set by visu_ui_value_io_connectOnOpen() on * @filename and update the buttons accordingly. * * Since: 3.5 * * Returns: TRUE on success of the open routine. */ gboolean visu_ui_value_io_setFilename(VisuUiValueIo *valueio, const gchar *filename) { gboolean valid; GError *error; g_return_val_if_fail(VISU_IS_UI_VALUE_IO(valueio), FALSE); g_return_val_if_fail(valueio->ioOpen, FALSE); error = (GError*)0; valid = valueio->ioOpen(filename, &error); if (!valid) { visu_ui_raiseWarning (_("Export V_Sim values to a file."), error->message, valueio->parent); g_error_free(error); #if GTK_MAJOR_VERSION > 2 || GTK_MINOR_VERSION > 5 gtk_file_chooser_unselect_all(GTK_FILE_CHOOSER(valueio->btExportOpen)); gtk_widget_set_sensitive(valueio->btExportSave, FALSE); #endif } else { gtk_file_chooser_set_filename(GTK_FILE_CHOOSER(valueio->btExportOpen), filename); #if GTK_MAJOR_VERSION > 2 || GTK_MINOR_VERSION > 5 gtk_widget_set_sensitive(valueio->btExportSave, TRUE); #endif gtk_widget_set_sensitive(valueio->btExportSaveAs, TRUE); } return valid; } v_sim-3.8.0/src/extraGtkFunctions/gtk_valueIOWidget.h000066400000000000000000000103331370110300500226240ustar00rootroot00000000000000/* EXTRAITS DE LA LICENCE Copyright CEA, contributeurs : Luc BILLARD et Damien CALISTE, laboratoire L_Sim, (2001-2005) Adresse mèl : BILLARD, non joignable par mèl ; CALISTE, damien P caliste AT cea P fr. Ce logiciel est un programme informatique servant à visualiser des structures atomiques dans un rendu pseudo-3D. Ce logiciel est régi par la licence CeCILL soumise au droit français et respectant les principes de diffusion des logiciels libres. Vous pouvez utiliser, modifier et/ou redistribuer ce programme sous les conditions de la licence CeCILL telle que diffusée par le CEA, le CNRS et l'INRIA sur le site "http://www.cecill.info". Le fait que vous puissiez accéder à cet en-tête signifie que vous avez pris connaissance de la licence CeCILL, et que vous en avez accepté les termes (cf. le fichier Documentation/licence.fr.txt fourni avec ce logiciel). */ /* LICENCE SUM UP Copyright CEA, contributors : Luc BILLARD et Damien CALISTE, laboratoire L_Sim, (2001-2005) E-mail address: BILLARD, not reachable any more ; CALISTE, damien P caliste AT cea P fr. This software is a computer program whose purpose is to visualize atomic configurations in 3D. This software is governed by the CeCILL license under French law and abiding by the rules of distribution of free software. You can use, modify and/ or redistribute the software under the terms of the CeCILL license as circulated by CEA, CNRS and INRIA at the following URL "http://www.cecill.info". The fact that you are presently reading this means that you have had knowledge of the CeCILL license and that you accept its terms. You can find a copy of this licence shipped with this software at Documentation/licence.en.txt. */ #ifndef GTK_STIPPLECOMBOBOXWIDGET_H #define GTK_STIPPLECOMBOBOXWIDGET_H #include #include #include G_BEGIN_DECLS /** * VISU_TYPE_UI_VALUE_IO: * * Get the associated #GType to the VisuUiValueIo objects. * * Since: 3.5 */ #define VISU_TYPE_UI_VALUE_IO (visu_ui_value_io_get_type ()) /** * VISU_UI_VALUE_IO: * @obj: the widget to cast. * * Cast the given object to a #VisuUiValueIo object. * * Since: 3.5 */ #define VISU_UI_VALUE_IO(obj) (G_TYPE_CHECK_INSTANCE_CAST ((obj), VISU_TYPE_UI_VALUE_IO, VisuUiValueIo)) /** * VISU_UI_VALUE_IO_CLASS: * @klass: the class to cast. * * Cast the given class to a #VisuUiValueIoClass object. * * Since: 3.5 */ #define VISU_UI_VALUE_IO_CLASS(klass) (G_TYPE_CHECK_CLASS_CAST ((klass), VISU_TYPE_UI_VALUE_IO, VisuUiValueIoClass)) /** * VISU_IS_UI_VALUE_IO: * @obj: the object to test. * * Get if the given object is a valid #VisuUiValueIo object. * * Since: 3.5 */ #define VISU_IS_UI_VALUE_IO(obj) (G_TYPE_CHECK_INSTANCE_TYPE ((obj), VISU_TYPE_UI_VALUE_IO)) /** * VISU_IS_UI_VALUE_IO_CLASS: * @klass: the class to test. * * Get if the given class is a valid #VisuUiValueIoClass class. * * Since: 3.5 */ #define VISU_IS_UI_VALUE_IO_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE ((klass), VISU_TYPE_UI_VALUE_IO)) typedef struct _VisuUiValueIo VisuUiValueIo; typedef struct _VisuUiValueIoClass VisuUiValueIoClass; GType visu_ui_value_io_get_type(void); GtkWidget* visu_ui_value_io_new(GtkWindow *parent, const gchar*tipsOpen, const gchar*tipsSave, const gchar*tipsSaveAs); /** * VisuUiValueIoCallback: * @filename: the name of the file to be saved or opened ; * @error: a location to store a possible error. * * Prototypes of functions to be called when an IO file is saved or * opened, see visu_ui_value_io_connectOnOpen() and visu_ui_value_io_connectOnSave(). * * Returns: should return TRUE if the action of the callback succeed. */ typedef gboolean (*VisuUiValueIoCallback)(const gchar *filename, GError **error); void visu_ui_value_io_connectOnOpen(VisuUiValueIo *valueio, VisuUiValueIoCallback open); void visu_ui_value_io_connectOnSave(VisuUiValueIo *valueio, VisuUiValueIoCallback save); void visu_ui_value_io_setSensitiveOpen(VisuUiValueIo *valueio, gboolean status); void visu_ui_value_io_setSensitiveSave(VisuUiValueIo *valueio, gboolean status); gboolean visu_ui_value_io_setFilename(VisuUiValueIo *valueio, const gchar *filename); gchar* visu_ui_value_io_getFilename(GtkWindow *parent); G_END_DECLS #endif v_sim-3.8.0/src/glade/000077500000000000000000000000001370110300500144705ustar00rootroot00000000000000v_sim-3.8.0/src/glade/v_sim.glade000066400000000000000000005150311370110300500166100ustar00rootroot00000000000000 True Save session True center-on-parent 450 icone-dialog.png normal False True True True 1 10 5 save-bandeau.png False False 0 True True <span size="larger"><b>Manage configuration files</b></span> True False False 1 0 600 True True True 2 True True left True 15 True True 0 25 10 <b>Load from file</b> True False False 0 250 True 1 True 0.89999997615814209 0 3 gtk-open True False True True True False True False False 2 True gtk-open 3 False tab True 15 True True 0 25 10 <b>Save to file</b> True False False 0 True True 0 True 0 gtk-save True True True True False True False False 5 1 False False 1 Export resources related to rendered file only True False True False 5 True True False False 2 1 True gtk-save 3 1 False tab 0 True True 0 10 True fill True False False 1 True True gtk-dialog-warning 1 False False 0 True False 1 False False end 4 True <b>Resources</b> <span size="smaller"><i>(values related to rendering aspects)</i></span> True False tab True 2 True True gtk-floppy 3 False False 0 True 25 10 <b>Save to file</b> True False False 1 False False 3 0 True True 0 15 True 0 gtk-save True True True True False True False False 5 1 False False 1 True True gtk-dialog-warning 1 False False 0 True False 1 False False end 4 1 True <b>Parameters</b> <span size="smaller"><i>(Interface options)</i></span> True 1 False tab 5 1 True 0 True True 0 5 5 <span size="smaller">When saving, if you just specify a directory '<span font_desc="courier">dir/</span>', it will be save to '<span font_desc="courier">dir/v_sim.[res][par]</span>' by default, ortherwise speficy a full path.</span> True fill True False False 0 True True 0 5 5 <span size="smaller"><u>Tips</u>: think to create a <span font_desc="courier">$XDG_CONFIG_HOME/v_sim</span> directory and put your resource and parameter files in it. It is scanned at startup.</span> True True True False False 1 True True gtk-help 2 0 True Help False False 1 label_item False False end 2 1 1 True end gtk-close -7 True True True False True False False 0 False end 0 True Pick and observe session center-on-parent icone-dialog.png normal False True True 400 True 1 observe-bandeau.png False False 10 0 True True True True False True True 0 0 True 2 True gtk-zoom-fit False False 0 True Observe True False False 1 0 True True ( False False 0 constrained True True False Movement are along meridians when the mouse is dragged along y axis and along parallels when the movement is along x axis. True True False False 1 walker True True False Movements are those of a walking ant on a sphere, when mouse move along y axis, the ant goes strait on, when mouse is dragged along x axis, the ant translates on its right or on its left. True True radioObserveConstrained False False 2 True ) False False 3 False False 1 False False 0 True 3 3 7 2 True 0 Translations spinDx 2 1 2 GTK_FILL True 0 Scale spinGross 2 2 3 GTK_FILL True True 6 0 -360 360 5 10 0 1 1 True 5 6 True True 6 -50 -360 360 5 10 0 1 1 True 3 4 True True 6 0.5 -3 3 0.050000000745099998 0.10000000149 0 0.10000000149 3 True 3 4 1 2 True True 6 1 0.019999999553000001 999 0.10000000149 0.5 0 0.10000000149 3 True 3 4 2 3 True True 6 40 -360 360 5 10 0 1 1 True 1 2 True 1 omega: spinPhi 4 5 True 1 phi: spinPhi 2 3 True 1 dx: spinDx 2 3 1 2 True 1 zoom: spinGross 2 3 2 3 True 1 theta: spinTheta True True False True axes-button.png 6 7 GTK_FILL True 1 dy: spinDy 4 5 1 2 True 1 persp.: spinPersp 4 5 2 3 True True 6 0.5 -3 3 0.050000000745099998 0.10000000149 0 0.10000000149 3 True 5 6 1 2 True True 6 5 1.1000000238400001 100 0.5 10 0 2 1 True 5 6 2 3 False False 1 True True True True True True False True True 0 0 True 2 True gtk-color-picker False False 0 True Pick True False False 1 0 False False 0 True 10 10 True True True 100 True True never automatic True True True True 0 15 True True False False 0 True center True False False 1 0 True Persistent measures True True False True True True False False 0 True True False Remove all drawn measurements. False True gtk-clear 1 False False 1 True 1 5 Highlights <span size="small">(none)</span>: True 2 True True True False Add highlighted nodes to the list below. True gtk-go-down 1 False False 0 True True False Remove all highlight marks. True gtk-clear 1 False False end 2 False False 3 False False end 1 True False 152 True True True 0 <b>List of nodes <span size="small">(none)</span></b> True 0 True 3 gtk-help 1 False False 1 True <span size="smaller">Values in <span color="blue">blue</span> are editable</span> True False False 2 False False 0 True 1 True 0 <b>Draw data on nodes</b> True False False 2 True True 5 none True True False True True False False 0 listed True True False True True radioDrawNever False False 1 all True True False True True radioDrawNever 2 True 3 False False 3 True False 1 True Pick False tab True True True False True True 0 0 True 2 True gtk-jump-to False False 0 True Modify nodes (position, numbers...) True False False 1 False False 0 True 10 10 True True True 0 <b>Move or delete:</b> True False False 0 picked _node True True False True True False False 1 True 10 _selected nodes True True False True True radioMovePick False False 2 True 1 nb True False False 3 True True False Suppress node (either picked one or selected ones). True gtk-remove 2 False False end 5 False False 0 True 10 True 1 <span size="smaller">(selected nodes are listed in the pick tab)</span> True False False 1 True 5 True 3 8 5 True 1 15 Specific moving axis: True 1 2 GTK_FILL True 1 2 <b>z</b> True 5 7 GTK_FILL GTK_FILL True 1 2 <b>y</b> True 3 5 GTK_FILL GTK_FILL True 1 2 <b>x</b> True 1 3 GTK_FILL GTK_FILL True 1 15 Current pos./trans.: 2 3 35 True 0 True 2 3 2 3 GTK_FILL 35 True 0 True 4 5 2 3 GTK_FILL 35 True 0 True 6 7 2 3 GTK_FILL True True False Capture the perpendicular to the current view. True gtk-zoom-fit 2 7 8 1 2 GTK_FILL True True False Return coordinates to initial values. True gtk-redo 2 7 8 2 3 GTK_FILL False False 2 True 0 1 5 <b>Add a new node:</b> True False False 3 True 5 True 1 15 position: 1 True True False Add a new node. True gtk-add 2 False False end 5 False False 4 True True 0 1 <b>Screen basis set:</b> True False False 0 True 1 5 <i>horiz.</i> True 1 True False False 2 True 1 5 <i>vert.</i> True 3 True False False 4 False False end 5 1 1 True Geometry changes 1 False tab 2 True 3 0 True 0 2 True True True True gtk-help 1 0 True Help False False 1 label_item False False end 3 1 1 True end -7 True True True True False True 0 0 True 2 True gtk-go-back False False 0 True Back to command panel True False False 1 False False 0 False end 0 True About V_Sim True center icone-about.png dialog False True True True True 10 10 logo_rectangle.png False False 0 True True 3 2 True 1 <b>Version</b> : True GTK_FILL True 1 <b>Release Date</b> : True 1 2 GTK_FILL True 1 <b>Web site</b> : True 2 3 GTK_FILL True 0 5 2.99 1 2 GTK_FILL True 0 5 AAAA-MM-JJ 1 2 1 2 GTK_FILL True True 0 5 <u>http://</u> True True 1 2 2 3 GTK_FILL False 0 1 0 475 300 True True True True never automatic etched-in True True False word 2 2 False True Readme False tab True True never automatic etched-in True True False word 2 2 False 1 True Authors 1 False tab True True automatic etched-in True True False 2 2 False 2 True License 2 False tab True True 0 15 5 Loaded plug-ins: False False 0 True True automatic 1 3 True Plug-ins 3 False tab True True automatic etched-in True True False 2 2 False 4 True Changelog 4 False tab 1 1 True end gtk-close -7 True True True False True False False 0 False end 0 True set and customize pairs icone-dialog.png normal False True 2 True True liaison-bandeau.png False False 0 True True 0.25 <span size="larger"><b>Set parameters for pairs</b></span> True 0 True True Model: False False 0 False False end 1 1 False False 1 True True left True True 150 True True automatic automatic True True 0 0 True Pairs 90 False tab True 1 True Distances 90 1 False tab 2 True end gtk-close -7 True True True False True False False 0 False end 0 True Quit V_Sim True center-on-parent gtk-dialog-question dialog False True True True 6 gtk-dialog-question 6 False False 0 True True 10 <span size="larger"><b>Quit V_Sim?</b></span> True False False 0 True 0 Don't show this warning again. True True False True True 1 15 True gtk-dialog-warning 3 False False 5 0 True <i>Can't find a local configuration directory <span font_desc="courier">$XDG_CONFIG_HOME/v_sim</span>. Should one be added?</i> True fill True False False 1 True 0 gtk-add True True False True False False 2 2 15 True gtk-dialog-warning 3 False False 5 0 True <i>Can't find a <span font_desc="courier">v_sim.par</span> file with enough write permissions to store the preference, neither in the installation directory nor in the <span font_desc="courier">$XDG_CONFIG_HOME/v_sim</span> one.</i> True fill True False False 1 3 True 0 True 0 0 2 2 <span size="smaller">If you check the above box but you want to have this warning dialog again before closing, you can change this by editing the parameter file (<span font_desc="courier">v_sim.par</span>). The option is called 'main_confirmQuit'.</span> True True True True gtk-help 1 0 True 5 Help False False 1 label_item False False 4 1 1 True end gtk-cancel -6 True True True False True False False 0 gtk-quit -5 True True True False True False False 1 False end 0 v_sim-3.8.0/src/glade/v_sim.gladep000066400000000000000000000006421370110300500167650ustar00rootroot00000000000000 Glade glade FALSE FALSE FALSE FALSE v_sim-3.8.0/src/gtk_about.c000066400000000000000000000467051370110300500155530ustar00rootroot00000000000000/* EXTRAITS DE LA LICENCE Copyright CEA, contributeurs : Luc BILLARD et Damien CALISTE, laboratoire L_Sim, (2001-2005) Adresse mèl : BILLARD, non joignable par mèl ; CALISTE, damien P caliste AT cea P fr. Ce logiciel est un programme informatique servant à visualiser des structures atomiques dans un rendu pseudo-3D. Ce logiciel est régi par la licence CeCILL soumise au droit français et respectant les principes de diffusion des logiciels libres. Vous pouvez utiliser, modifier et/ou redistribuer ce programme sous les conditions de la licence CeCILL telle que diffusée par le CEA, le CNRS et l'INRIA sur le site "http://www.cecill.info". Le fait que vous puissiez accéder à cet en-tête signifie que vous avez pris connaissance de la licence CeCILL, et que vous en avez accepté les termes (cf. le fichier Documentation/licence.fr.txt fourni avec ce logiciel). */ /* LICENCE SUM UP Copyright CEA, contributors : Luc BILLARD et Damien CALISTE, laboratoire L_Sim, (2001-2005) E-mail address: BILLARD, not reachable any more ; CALISTE, damien P caliste AT cea P fr. This software is a computer program whose purpose is to visualize atomic configurations in 3D. This software is governed by the CeCILL license under French law and abiding by the rules of distribution of free software. You can use, modify and/ or redistribute the software under the terms of the CeCILL license as circulated by CEA, CNRS and INRIA at the following URL "http://www.cecill.info". The fact that you are presently reading this means that you have had knowledge of the CeCILL license and that you accept its terms. You can find a copy of this licence shipped with this software at Documentation/licence.en.txt. */ #include "gtk_about.h" #include #include #include "interface.h" #include "support.h" #include "visu_tools.h" #include "visu_basic.h" #include "visu_plugins.h" /** * SECTION: gtk_about * @short_description: The about dialog with a readme, the copyright, * the author list, the plug-in list and the version notes. * * The about dialog window is activated when clicking on the V_Sim * icon on bottom right part of the command panel. It contains a * summary of V_Sim purpose and capabilities, the list of authors, the * list of loaded plug-ins, the list of changes since the previous * version, and the licence file. It displays also the version of * V_Sim and provide a link to the web site. */ #define VISU_UI_ABOUT_LICENCE_FILE _("licence.en.txt") /* Translate if there is a authors file in another language. */ #define VISU_UI_ABOUT_AUTHORS_FILE _("authors") /* Translate if there is a readme file in another language. */ #define VISU_UI_ABOUT_README_FILE _("readme") /* Translate if there is a readme file in another language. */ #define VISU_UI_ABOUT_CHANGELOG_FILE _("ChangeLog.en") enum { GTK_PLUGINS_COLUMN_ICON, GTK_PLUGINS_COLUMN_NAME, GTK_PLUGINS_COLUMN_DESCRIPTION, GTK_PLUGINS_COLUMN_AUTHORS, N_GTK_PLUGINS_COLUMNS }; static void buildPluginsTab(); /* static gboolean onUrlClicked(GtkTextTag *tag, GObject *object, */ /* GdkEvent *event, GtkTextIter *iter, */ /* gpointer user_data); */ /* static gboolean onMouseMotion(GtkWidget *wd, GdkEventMotion *event, */ /* gpointer user_data); */ static void setChangelog(const gchar* buffer, gssize size, GtkTextBuffer *text); /** * visu_ui_about_initBuild: (skip) * @main: the command panel the about dialog is associated to. * * Create the about window. */ void visu_ui_about_initBuild(VisuUiMain *main) { GtkWidget *wd, *note; gchar *buffer, *utf8Buffer, *start, *end; GtkTextBuffer *text; GtkTextIter startIter, endIter; GtkTextTag *monoTag, *boldTag, *linkTag; gsize taille; GError *err; gchar *chemin; DBG_fprintf(stderr, "Gtk About : creating the dialog window.\n"); main->aboutDialog = create_infoDialog(); gtk_widget_set_name(main->aboutDialog, "message"); wd = lookup_widget(main->aboutDialog, "labelInfoVersion"); gtk_label_set_text(GTK_LABEL(wd), VISU_VERSION); wd = lookup_widget(main->aboutDialog, "labelInfoReleaseDate"); gtk_label_set_text(GTK_LABEL(wd), V_SIM_RELEASE_DATE); wd = lookup_widget(main->aboutDialog, "labelInfoWebSite"); /* #if GTK_MAJOR_VERSION > 2 || GTK_MINOR_VERSION > 9 */ /* gtk_widget_destroy(wd); */ /* wd = lookup_widget(main->aboutDialog, "table4"); */ /* gtk_table_attach(GTK_TABLE(wd), gtk_link_button_new(VISU_WEB_SITE), */ /* 1, 2, 2, 3, GTK_SHRINK, GTK_SHRINK, 5, 0); */ /* gtk_widget_show_all(wd); */ /* #else */ gtk_label_set_markup(GTK_LABEL(wd), "" VISU_WEB_SITE""); /* #endif */ note = lookup_widget(main->aboutDialog, "notebookAbout"); gtk_widget_set_name(note, "message_notebook"); /* Create the interior of the tabs. */ chemin = g_build_filename(V_SIM_LEGAL_DIR, VISU_UI_ABOUT_LICENCE_FILE, NULL); buffer = (gchar*)0; err = (GError*)0; if (!g_file_get_contents(chemin, &buffer, &taille, &err)) g_warning("Can't find the licence file, normally" " it should be in '%s'.\n", chemin); else { utf8Buffer = g_convert(buffer, taille, "UTF-8", "ISO-8859-1", NULL, NULL, NULL); g_free(buffer); wd = lookup_widget(main->aboutDialog, "textviewLicence"); text = gtk_text_view_get_buffer(GTK_TEXT_VIEW(wd)); gtk_text_buffer_get_start_iter(text, &startIter); monoTag = gtk_text_buffer_create_tag(text, "typewriter", "family", "monospace", NULL); gtk_text_buffer_insert_with_tags(text, &startIter, utf8Buffer, -1, monoTag, NULL); g_free(utf8Buffer); } g_free(chemin); chemin = g_build_filename(V_SIM_LEGAL_DIR, VISU_UI_ABOUT_README_FILE, NULL); buffer = (gchar*)0; err = (GError*)0; if (!g_file_get_contents(chemin, &buffer, &taille, &err)) g_warning("Can't find the readme file, normally it" " should be in '%s'.\n", chemin); else { utf8Buffer = g_convert(buffer, taille, "UTF-8", "ISO-8859-1", NULL, NULL, NULL); g_free(buffer); wd = lookup_widget(main->aboutDialog, "textviewReadme"); gtk_widget_add_events(wd, GDK_POINTER_MOTION_MASK); text = gtk_text_view_get_buffer(GTK_TEXT_VIEW(wd)); gtk_text_buffer_set_text (text, utf8Buffer, -1); start = strstr(utf8Buffer, "http://"); end = g_utf8_strchr(start, -1, ' '); if (*g_utf8_prev_char(end) == '.') end = g_utf8_prev_char(end); linkTag = gtk_text_buffer_create_tag(text, "link", "underline", PANGO_UNDERLINE_SINGLE, NULL); /* "foreground", "blue", NULL); */ /* g_signal_connect(G_OBJECT(linkTag), "event", */ /* G_CALLBACK(onUrlClicked), NULL); */ /* g_signal_connect(G_OBJECT(wd), "motion-notify-event", */ /* G_CALLBACK(onMouseMotion), (gpointer)linkTag); */ gtk_text_buffer_get_iter_at_offset (text, &startIter,(gint)g_utf8_pointer_to_offset(utf8Buffer, start)); gtk_text_buffer_get_iter_at_offset (text, &endIter, (gint)g_utf8_pointer_to_offset(utf8Buffer, end)); gtk_text_buffer_apply_tag(text, linkTag, &startIter, &endIter); g_free(utf8Buffer); } g_free(chemin); chemin = g_build_filename(V_SIM_LEGAL_DIR, VISU_UI_ABOUT_CHANGELOG_FILE, NULL); buffer = (gchar*)0; err = (GError*)0; if (!g_file_get_contents(chemin, &buffer, &taille, &err)) g_warning("Can't find the changelog file, normally" " it should be in '%s'.\n", chemin); else { wd = lookup_widget(main->aboutDialog, "textviewChangelog"); gtk_text_view_set_wrap_mode(GTK_TEXT_VIEW(wd), GTK_WRAP_WORD); gtk_text_view_set_justification (GTK_TEXT_VIEW(wd), GTK_JUSTIFY_LEFT); text = gtk_text_view_get_buffer(GTK_TEXT_VIEW(wd)); /* Parse here the XML to get only the relevant entries. */ setChangelog(buffer, taille, text); g_free(buffer); } chemin = g_build_filename(V_SIM_LEGAL_DIR, VISU_UI_ABOUT_AUTHORS_FILE, NULL); buffer = (gchar*)0; err = (GError*)0; if (!g_file_get_contents(chemin, &buffer, &taille, &err)) g_warning("Can't find the authors file, normally" " it should be in '%s'.\n", chemin); else { utf8Buffer = g_convert(buffer, taille, "UTF-8", "ISO-8859-1", NULL, NULL, NULL); g_free(buffer); wd = lookup_widget(main->aboutDialog, "textviewAuthors"); text = gtk_text_view_get_buffer(GTK_TEXT_VIEW(wd)); gtk_text_buffer_get_start_iter(text, &startIter); monoTag = gtk_text_buffer_create_tag(text, "typewriter", "family", "monospace", NULL); gtk_text_buffer_insert_with_tags(text, &startIter, utf8Buffer, -1, monoTag, NULL); boldTag = gtk_text_buffer_create_tag(text, "bold", "weight", PANGO_WEIGHT_BOLD, NULL); end = utf8Buffer; do { start = g_utf8_strchr(end, -1, '*'); if (start) { end = g_utf8_strchr(g_utf8_next_char(start), -1, '*'); if (end) { gtk_text_buffer_get_iter_at_offset (text, &startIter,(gint)g_utf8_pointer_to_offset(utf8Buffer, start)); gtk_text_buffer_get_iter_at_offset (text, &endIter, (gint)g_utf8_pointer_to_offset(utf8Buffer, end)); gtk_text_buffer_apply_tag(text, boldTag, &startIter, &endIter); end = g_utf8_next_char(end); } } } while (start); g_free(utf8Buffer); } g_free(chemin); buildPluginsTab(main); } /* static gboolean onMouseMotion(GtkWidget *wd, GdkEventMotion *event, */ /* gpointer user_data) */ /* { */ /* gint x, y; */ /* GtkTextIter iter; */ /* static GdkCursor *cur = NULL; */ /* gtk_text_view_window_to_buffer_coords(GTK_TEXT_VIEW(wd), GTK_TEXT_WINDOW_WIDGET, */ /* event->x, event->y, &x, &y); */ /* gtk_text_view_get_iter_at_location(GTK_TEXT_VIEW(wd), &iter, x, y); */ /* if (gtk_text_iter_has_tag(&iter, GTK_TEXT_TAG(user_data))) */ /* { */ /* if (!cur) */ /* cur = gdk_cursor_new(GDK_HAND1); */ /* gdk_window_set_cursor(event->window, cur); */ /* g_object_set(G_OBJECT(user_data), "underline", PANGO_UNDERLINE_SINGLE, NULL); */ /* } */ /* else */ /* { */ /* gdk_window_set_cursor(event->window, NULL); */ /* g_object_set(G_OBJECT(user_data), "underline", PANGO_UNDERLINE_NONE, NULL); */ /* } */ /* return FALSE; */ /* } */ /* static gboolean onUrlClicked(GtkTextTag *tag _U_, GObject *object _U_, */ /* GdkEvent *event, GtkTextIter *iter _U_, */ /* gpointer user_data _U_) */ /* { */ /* if (event->type == GDK_BUTTON_RELEASE) */ /* { */ /* if (((GdkEventButton*)event)->button != 1) */ /* return FALSE; */ /* DBG_fprintf(stderr, "Gtk About: clicked on URL.\n"); */ /* } */ /* return FALSE; */ /* } */ static void buildPluginsTab(VisuUiMain *main) { GtkListStore *liststore; GtkTreeIter iter; GList *pnt; GtkWidget *tree, *wd; GtkCellRenderer *renderer; GtkTreeViewColumn *column; GdkPixbuf *pixbuf; const gchar *str; VisuPlugin *plug; liststore = gtk_list_store_new(N_GTK_PLUGINS_COLUMNS, GDK_TYPE_PIXBUF, G_TYPE_STRING, G_TYPE_STRING, G_TYPE_STRING); gtk_tree_sortable_set_sort_column_id(GTK_TREE_SORTABLE(liststore), GTK_PLUGINS_COLUMN_NAME, GTK_SORT_ASCENDING); DBG_fprintf(stderr, "Gtk About: plugins:\n"); for (pnt = visu_plugins_getListLoaded(); pnt; pnt = g_list_next(pnt)) { plug = (VisuPlugin*)pnt->data; str = visu_plugin_getIconPath(plug); if (str) pixbuf = gdk_pixbuf_new_from_file_at_size(str, 32, 32, (GError**)0); else pixbuf = (GdkPixbuf*)0; gtk_list_store_append(liststore, &iter); gtk_list_store_set(liststore, &iter, GTK_PLUGINS_COLUMN_ICON, pixbuf, GTK_PLUGINS_COLUMN_NAME, visu_plugin_getName(plug), GTK_PLUGINS_COLUMN_DESCRIPTION, visu_plugin_getDescription(plug), GTK_PLUGINS_COLUMN_AUTHORS, visu_plugin_getAuthors(plug), -1); DBG_fprintf(stderr, " - %s (%s) from %s\n", visu_plugin_getName(plug), visu_plugin_getDescription(plug), visu_plugin_getAuthors(plug)); } /* Build the treeview. */ tree= gtk_tree_view_new_with_model(GTK_TREE_MODEL(liststore)); gtk_tree_selection_set_mode(gtk_tree_view_get_selection(GTK_TREE_VIEW(tree)), GTK_SELECTION_NONE); gtk_tree_view_set_headers_visible(GTK_TREE_VIEW(tree), TRUE); renderer = gtk_cell_renderer_pixbuf_new(); column = gtk_tree_view_column_new_with_attributes("", renderer, "pixbuf", GTK_PLUGINS_COLUMN_ICON, NULL); gtk_tree_view_append_column(GTK_TREE_VIEW(tree), column); renderer = gtk_cell_renderer_text_new(); g_object_set(renderer, "weight", 600, "weight-set", TRUE, NULL); column = gtk_tree_view_column_new_with_attributes(_("Name"), renderer, "text", GTK_PLUGINS_COLUMN_NAME, NULL); gtk_tree_view_column_set_alignment(column, 0.5); gtk_tree_view_append_column(GTK_TREE_VIEW(tree), column); renderer = gtk_cell_renderer_text_new(); g_object_set(renderer, "xalign", 0., NULL); column = gtk_tree_view_column_new_with_attributes(_("Description"), renderer, "markup", GTK_PLUGINS_COLUMN_DESCRIPTION, NULL); gtk_tree_view_column_set_expand(column, TRUE); gtk_tree_view_column_set_alignment(column, 0.5); gtk_tree_view_append_column(GTK_TREE_VIEW(tree), column); renderer = gtk_cell_renderer_text_new(); column = gtk_tree_view_column_new_with_attributes(_("Authors"), renderer, "text", GTK_PLUGINS_COLUMN_AUTHORS, NULL); gtk_tree_view_append_column(GTK_TREE_VIEW(tree), column); gtk_widget_show(tree); wd = lookup_widget(main->aboutDialog, "scrolledwindowPlugins"); gtk_container_add(GTK_CONTAINER(wd), tree); } /****************************/ /* XML files for changelog. */ /****************************/ /* All changes leading to 3.5.x series.

  • Implement a visualisation for the difference
  • */ /* Known elements. */ #define PICK_PARSER_ELEMENT_CHANGELOG "ChangeLog" #define PICK_PARSER_ELEMENT_MILESTONE "milestone" #define PICK_PARSER_ELEMENT_ENTRY "entry" #define PICK_PARSER_ELEMENT_LI "li" /* Known attributes. */ #define PICK_PARSER_ATTRIBUTES_VERSION "version" #define PICK_PARSER_ATTRIBUTES_TITRE "titre" #define PICK_PARSER_ATTRIBUTES_TYPE "type" static gboolean startAbout, startLi; /* This method is called for every element that is parsed. The user_data must be the text buffer to write into. */ static void aboutXML_element(GMarkupParseContext *context _U_, const gchar *element_name, const gchar **attribute_names, const gchar **attribute_values, gpointer user_data, GError **error _U_) { GtkTextBuffer *text; GtkTextIter iter; gchar **version, **refVersion; int minor, refMinor, i; g_return_if_fail(user_data); text = GTK_TEXT_BUFFER(user_data); DBG_fprintf(stderr, "ChangeLog parser: found '%s' element.\n", element_name); if (!strcmp(element_name, PICK_PARSER_ELEMENT_MILESTONE)) { startAbout = FALSE; /* Should have 1 mandatory attribute. */ for (i = 0; attribute_names[i]; i++) { if (!strcmp(attribute_names[i], PICK_PARSER_ATTRIBUTES_VERSION)) { refVersion = g_strsplit_set(VISU_VERSION, ".-", 4); version = g_strsplit_set(attribute_values[i], ".", 3); refMinor = (atoi(refVersion[2]) == 99)? atoi(refVersion[1]) + 1:atoi(refVersion[1]); minor = (version[1])?atoi(version[1]):-1; startAbout = (minor == refMinor); g_strfreev(version); g_strfreev(refVersion); } } } else if (!strcmp(element_name, PICK_PARSER_ELEMENT_ENTRY)) { if (startAbout) { /* Should have 1 mandatory attribute. */ for (i = 0; attribute_names[i]; i++) { if (!strcmp(attribute_names[i], PICK_PARSER_ATTRIBUTES_TITRE)) { gtk_text_buffer_get_end_iter(text, &iter); gtk_text_buffer_insert_with_tags_by_name(text, &iter, attribute_values[i], -1, "bold", NULL); gtk_text_buffer_get_end_iter(text, &iter); gtk_text_buffer_insert(text, &iter, _(":\n\n"), -1); } } } } else if (!strcmp(element_name, PICK_PARSER_ELEMENT_LI)) { if (startAbout) { gtk_text_buffer_get_end_iter(text, &iter); gtk_text_buffer_insert(text, &iter, "\342\200\242\t", -1); /* May have the type attribute. */ for (i = 0; attribute_names[i]; i++) { if (!strcmp(attribute_names[i], PICK_PARSER_ATTRIBUTES_TYPE)) { gtk_text_buffer_get_end_iter(text, &iter); gtk_text_buffer_insert_with_tags_by_name(text, &iter, attribute_values[i], -1, "italic", NULL); gtk_text_buffer_get_end_iter(text, &iter); gtk_text_buffer_insert(text, &iter, _(": "), -1); } } startLi = TRUE; } } } /* Check when a element is closed that everything required has been set. */ static void aboutXML_end(GMarkupParseContext *context _U_, const gchar *element_name, gpointer user_data, GError **error _U_) { GtkTextBuffer *text; GtkTextIter iter; g_return_if_fail(user_data); text = GTK_TEXT_BUFFER(user_data); DBG_fprintf(stderr, "ChangeLog parser: close '%s' element.\n", element_name); if (!strcmp(element_name, PICK_PARSER_ELEMENT_MILESTONE)) startAbout = FALSE; else if (!strcmp(element_name, PICK_PARSER_ELEMENT_ENTRY) && startAbout) { gtk_text_buffer_get_end_iter(text, &iter); gtk_text_buffer_insert(text, &iter, "\n", -1); } else if (!strcmp(element_name, PICK_PARSER_ELEMENT_LI) && startAbout) { startLi = FALSE; gtk_text_buffer_get_end_iter(text, &iter); gtk_text_buffer_insert(text, &iter, "\n", -1); } } static void aboutXML_text(GMarkupParseContext *context _U_, const gchar *buf, gsize text_len, gpointer user_data, GError **error _U_) { GtkTextBuffer *text; GtkTextIter iter; g_return_if_fail(user_data); text = GTK_TEXT_BUFFER(user_data); if (startAbout && startLi) { gtk_text_buffer_get_end_iter(text, &iter); gtk_text_buffer_insert(text, &iter, buf, text_len); /* gtk_text_buffer_get_end_iter(text, &iter); */ /* gtk_text_buffer_insert(text, &iter, "\n", -1); */ } } static void setChangelog(const gchar* buffer, gssize size, GtkTextBuffer *text) { GMarkupParseContext* xmlContext; GMarkupParser parser; gboolean status; GError *error; /* Create context. */ parser.start_element = aboutXML_element; parser.end_element = aboutXML_end; parser.text = aboutXML_text; parser.passthrough = NULL; parser.error = NULL; xmlContext = g_markup_parse_context_new(&parser, 0, text, NULL); gtk_text_buffer_create_tag(text, "bold", "weight", PANGO_WEIGHT_BOLD, NULL); gtk_text_buffer_create_tag(text, "italic", "style", PANGO_STYLE_ITALIC, NULL); /* Parse data. */ startAbout = FALSE; startLi = FALSE; error = (GError*)0; status = g_markup_parse_context_parse(xmlContext, buffer, size, &error); /* Free buffers. */ g_markup_parse_context_free(xmlContext); DBG_fprintf(stderr, "ChangeLog parser: done, status %d (%s).\n", status, (error)?error->message:"no error"); if (!status && error) g_warning("%s", error->message); if (error) g_error_free(error); } v_sim-3.8.0/src/gtk_about.h000066400000000000000000000035471370110300500155550ustar00rootroot00000000000000/* EXTRAITS DE LA LICENCE Copyright CEA, contributeurs : Luc BILLARD et Damien CALISTE, laboratoire L_Sim, (2001-2005) Adresse mèl : BILLARD, non joignable par mèl ; CALISTE, damien P caliste AT cea P fr. Ce logiciel est un programme informatique servant à visualiser des structures atomiques dans un rendu pseudo-3D. Ce logiciel est régi par la licence CeCILL soumise au droit français et respectant les principes de diffusion des logiciels libres. Vous pouvez utiliser, modifier et/ou redistribuer ce programme sous les conditions de la licence CeCILL telle que diffusée par le CEA, le CNRS et l'INRIA sur le site "http://www.cecill.info". Le fait que vous puissiez accéder à cet en-tête signifie que vous avez pris connaissance de la licence CeCILL, et que vous en avez accepté les termes (cf. le fichier Documentation/licence.fr.txt fourni avec ce logiciel). */ /* LICENCE SUM UP Copyright CEA, contributors : Luc BILLARD et Damien CALISTE, laboratoire L_Sim, (2001-2005) E-mail address: BILLARD, not reachable any more ; CALISTE, damien P caliste AT cea P fr. This software is a computer program whose purpose is to visualize atomic configurations in 3D. This software is governed by the CeCILL license under French law and abiding by the rules of distribution of free software. You can use, modify and/ or redistribute the software under the terms of the CeCILL license as circulated by CEA, CNRS and INRIA at the following URL "http://www.cecill.info". The fact that you are presently reading this means that you have had knowledge of the CeCILL license and that you accept its terms. You can find a copy of this licence shipped with this software at Documentation/licence.en.txt. */ #ifndef GTK_ABOUT_H #define GTK_ABOUT_H #include #include "gtk_main.h" void visu_ui_about_initBuild(VisuUiMain *main); #endif v_sim-3.8.0/src/gtk_interactive.c000066400000000000000000000607471370110300500167600ustar00rootroot00000000000000/* EXTRAITS DE LA LICENCE Copyright CEA, contributeurs : Luc BILLARD et Damien CALISTE, laboratoire L_Sim, (2001-2005) Adresse mèl : BILLARD, non joignable par mèl ; CALISTE, damien P caliste AT cea P fr. Ce logiciel est un programme informatique servant à visualiser des structures atomiques dans un rendu pseudo-3D. Ce logiciel est régi par la licence CeCILL soumise au droit français et respectant les principes de diffusion des logiciels libres. Vous pouvez utiliser, modifier et/ou redistribuer ce programme sous les conditions de la licence CeCILL telle que diffusée par le CEA, le CNRS et l'INRIA sur le site "http://www.cecill.info". Le fait que vous puissiez accéder à cet en-tête signifie que vous avez pris connaissance de la licence CeCILL, et que vous en avez accepté les termes (cf. le fichier Documentation/licence.fr.txt fourni avec ce logiciel). */ /* LICENCE SUM UP Copyright CEA, contributors : Luc BILLARD et Damien CALISTE, laboratoire L_Sim, (2001-2005) E-mail address: BILLARD, not reachable any more ; CALISTE, damien P caliste AT cea P fr. This software is a computer program whose purpose is to visualize atomic configurations in 3D. This software is governed by the CeCILL license under French law and abiding by the rules of distribution of free software. You can use, modify and/ or redistribute the software under the terms of the CeCILL license as circulated by CEA, CNRS and INRIA at the following URL "http://www.cecill.info". The fact that you are presently reading this means that you have had knowledge of the CeCILL license and that you accept its terms. You can find a copy of this licence shipped with this software at Documentation/licence.en.txt. */ #include #include "support.h" #include "interface.h" #include "gtk_interactive.h" #include "gtk_main.h" #include "visu_gtk.h" #include "gtk_pick.h" #include "gtk_move.h" #include "gtk_renderingWindowWidget.h" #include "openGLFunctions/interactive.h" #include "extraGtkFunctions/gtk_numericalEntryWidget.h" #include "extraGtkFunctions/gtk_orientationChooser.h" /** * SECTION: gtk_interactive * @short_description: The interactive dialog. * * This is the second main interface for V_Sim after the command * panel. It provides widgets to interact with the nodes. There is * three built-in interactive modes : the observe one (as in normal * behaviour), the pick one and the move one. * It is possible to add new action thanks to * visu_ui_interactive_addAction() function. It is also possible to * show a small warning message with visu_ui_interactive_setMessage() * that shows a GtkInfoBar. */ /* Local types. */ typedef struct ActionInterface_ { guint id; gchar *label; gchar *help; GtkWidget *radio; VisuUiInteractiveBuild build; VisuInteractiveId mode; VisuUiInteractiveStartStop onStart, onStop; } ActionInterface; /* Local variables. */ static ActionInterface* currentAction; static guint n_actions = 0; static GList *actions; static VisuInteractive *interObserve = NULL; static GBinding *theta_bind, *phi_bind, *omega_bind; static GBinding *xs_bind, *ys_bind, *gross_bind, *persp_bind; /* Callbacks. */ static gboolean onHomePressed(GtkWidget *widget _U_, GdkEventKey *event, gpointer data); static void onDataNotify(GtkButton *button, GParamSpec *pspec, VisuGlNodeScene *scene); static void observeMethodChanged(GtkToggleButton* button, gpointer data); static void radioObserveToggled(GtkToggleButton *togglebutton, gpointer user_data); static void onCloseButtonClicked(GtkButton *button, gpointer user_data); static void onTabActionChanged(GtkNotebook *book, GtkWidget *child, gint num, gpointer data); static void onVisuUiOrientationChooser(GtkButton *button, gpointer data); static gboolean onKillWindowEvent(GtkWidget *widget, GdkEvent *event, gpointer user_data); static void onRadioToggled(GtkToggleButton *toggle, gpointer data); static void onObserveStart(VisuUiRenderingWindow *window); static void onObserveStop(VisuUiRenderingWindow *window); /* Local methods. */ static void _setGlView(VisuGlView *view); static void connectSignalsObservePick(VisuUiRenderingWindow *window); static void setNamesGtkWidgetObservePick(VisuUiMain *main); static GtkWidget* gtkObserveBuild_interface(VisuUiMain *main, gchar **label, gchar **help, GtkWidget **radio); /* Widgets */ static GtkWidget *observeWindow, *infoBar; static GtkWidget *orientationChooser; static GtkWidget *spinOmega; /* Help message used in the help area. */ #define GTK_PICKOBSERVE_OBSERVE_INFO \ _("left-[control]-button\t\t\t: rotations " \ "(\316\270, \317\206, [control]\317\211)\n" \ "shift-left-button\t\t\t\t: translations (dx, dy)\n" \ "middle-[shift]-button or wheel\t: zoom or [shift]perspective\n" \ "key 's' / 'r'\t\t\t\t\t: save/restore camera position\n" \ "right-button\t\t\t\t\t: switch to current tabbed action") /** * visu_ui_interactive_init: (skip) * * Initialise the observe/pick window, connect the * signals, give names to widgets... */ void visu_ui_interactive_init() { orientationChooser = (GtkWidget*)0; /* Set the actions tabs. */ actions = (GList*)0; visu_ui_interactive_addAction(gtkObserveBuild_interface, onObserveStart, onObserveStop); currentAction = (ActionInterface*)actions->data; visu_ui_interactive_addAction(visu_ui_interactive_pick_initBuild, visu_ui_interactive_pick_start, visu_ui_interactive_pick_stop); visu_ui_interactive_addAction(visu_ui_interactive_move_initBuild, visu_ui_interactive_move_start, visu_ui_interactive_move_stop); } /** * visu_ui_interactive_addAction: * @build: a routine to build a tab. * @start: a routine to run when session is selected. * @stop: a routine to run when session is stopped. * * One can add new interactive mode with specific tab in the * interactive dialog. * * Since: 3.6 * * Returns: an id for this new action. */ guint visu_ui_interactive_addAction(VisuUiInteractiveBuild build, VisuUiInteractiveStartStop start, VisuUiInteractiveStartStop stop) { ActionInterface *action; g_return_val_if_fail(build && start && stop, 0); action = g_malloc(sizeof(ActionInterface)); action->id = n_actions; action->build = build; action->onStart = start; action->onStop = stop; actions = g_list_append(actions, action); n_actions += 1; return action->id; } static GtkWidget* gtkObserveBuild_interface(VisuUiMain *main _U_, gchar **label, gchar **help, GtkWidget **radio) { *label = g_strdup("Observe"); *help = g_strdup(GTK_PICKOBSERVE_OBSERVE_INFO); *radio = lookup_widget(observeWindow, "radioObserve"); return (GtkWidget*)0; } /** * visu_ui_interactive_initBuild: (skip) * @main: the command panel the about dialog is associated to. * * create the window. */ void visu_ui_interactive_initBuild(VisuUiMain *main) { GtkWidget *labelHelp, *wd; VisuUiRenderingWindow *window; VisuGlNodeScene *scene; VisuGlView *view; GList *tmpLst; ActionInterface *action; gchar *msg; GSList *lst; window = visu_ui_main_getRendering(main); scene = visu_ui_rendering_window_getGlScene(window); view = visu_gl_node_scene_getGlView(scene); DBG_fprintf(stderr, "Gtk Interactive: init build.\n"); interObserve = visu_interactive_new(interactive_observe); g_signal_connect_swapped(G_OBJECT(interObserve), "stop", G_CALLBACK(visu_ui_interactive_toggle), (gpointer)0); DBG_fprintf(stderr, "Gtk observePick: creating the window.\n"); main->interactiveDialog = create_observeDialog(); gtk_window_set_default_size(GTK_WINDOW(main->interactiveDialog), 100, -1); g_signal_connect_swapped(G_OBJECT(main->interactiveDialog), "destroy", G_CALLBACK(g_object_unref), interObserve); observeWindow = main->interactiveDialog; gtk_window_set_type_hint(GTK_WINDOW(main->interactiveDialog), GDK_WINDOW_TYPE_HINT_NORMAL); setNamesGtkWidgetObservePick(main); g_signal_connect(G_OBJECT(observeWindow), "key-press-event", G_CALLBACK(onHomePressed), (gpointer)observeWindow); /* Create the actions parts. */ DBG_fprintf(stderr, "Gtk Interactive: Create the actions parts.\n"); lst = (GSList*)0; for (tmpLst = actions; tmpLst; tmpLst = g_list_next(tmpLst)) { action = ((ActionInterface*)tmpLst->data); g_return_if_fail(action->build); wd = action->build(main, &action->label, &msg, &action->radio); DBG_fprintf(stderr, " | action '%s'\n", action->label); action->help = g_markup_printf_escaped("%s", msg); g_free(msg); if (wd) gtk_notebook_append_page (GTK_NOTEBOOK(lookup_widget(observeWindow, "notebookAction")), wd, gtk_label_new(action->label)); if (action->id > 0) gtk_radio_button_set_group(GTK_RADIO_BUTTON(action->radio), lst); lst = gtk_radio_button_get_group(GTK_RADIO_BUTTON(action->radio)); g_signal_connect(G_OBJECT(action->radio), "toggled", G_CALLBACK(onRadioToggled), (gpointer)action); DBG_fprintf(stderr, " | action '%s' OK\n", action->label); } /* Create and Set the help text. */ action = ((ActionInterface*)actions->data); labelHelp = lookup_widget(main->interactiveDialog, "labelInfoObservePick"); gtk_label_set_markup(GTK_LABEL(labelHelp), action->help); /* Add an info bar for warning and so on. */ #if GTK_MAJOR_VERSION > 2 || GTK_MINOR_VERSION > 17 infoBar = gtk_info_bar_new(); gtk_widget_set_no_show_all(infoBar, TRUE); gtk_info_bar_add_button(GTK_INFO_BAR(infoBar), _("_Ok"), GTK_RESPONSE_OK); g_signal_connect(infoBar, "response", G_CALLBACK(gtk_widget_hide), NULL); wd = gtk_label_new(""); gtk_label_set_xalign(GTK_LABEL(wd), 0.); gtk_container_add(GTK_CONTAINER(gtk_info_bar_get_content_area(GTK_INFO_BAR(infoBar))), wd); gtk_widget_show(wd); #else infoBar = gtk_label_new(""); gtk_misc_set_alignment(GTK_MISC(infoBar), 0., 0.5); #endif gtk_box_pack_end(GTK_BOX(lookup_widget(observeWindow, "vbox20")), infoBar, FALSE, FALSE, 2); /* connect the signals to the spins. */ connectSignalsObservePick(window); theta_bind = NULL; phi_bind = NULL; omega_bind = NULL; xs_bind = NULL; ys_bind = NULL; gross_bind = NULL; persp_bind = NULL; DBG_fprintf(stderr, "Gtk Interactive: Setup initial values.\n"); _setGlView(view); g_signal_connect_object(scene, "notify::data", G_CALLBACK(onDataNotify), lookup_widget(observeWindow, "buttonBackToCommandPanel"), G_CONNECT_SWAPPED); } /** * visu_ui_interactive_toggle: * * The user can switch between a current specific interactive action * and the observe mode. This routine is used to do this.* * * Since: 3.6 */ void visu_ui_interactive_toggle(void) { GtkWidget *wd; guint id; ActionInterface *action; if (currentAction->id == VISU_UI_ACTION_OBSERVE) { wd = lookup_widget(observeWindow, "notebookAction"); id = gtk_notebook_get_current_page(GTK_NOTEBOOK(wd)) + 1; } else id = VISU_UI_ACTION_OBSERVE; action = (ActionInterface*)g_list_nth_data(actions, id); /* We toggle on the radio of the new action. */ if (action->radio) gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON(action->radio), TRUE); } /** * visu_ui_interactive_start: * @window: the current rendering widget. * * Start the observe & pick session. */ void visu_ui_interactive_start(VisuUiRenderingWindow *window) { DBG_fprintf(stderr, "Gtk Interactive: initialise session.\n"); visu_ui_rendering_window_pushMessage(window, ""); currentAction->onStart(window); } /** * visu_ui_interactive_stop: * @window: a #VisuUiRenderingWindow object. * * Stop the observe and pick session from @window. * * Since: 3.8 **/ void visu_ui_interactive_stop(VisuUiRenderingWindow *window) { DBG_fprintf(stderr, "Gtk Interactive: stop session.\n"); visu_ui_rendering_window_popMessage(window); currentAction->onStop(window); } /** * visu_ui_interactive_setMessage: * @message: a string. * @type: the type of message. * * Show a message in the interactive dialog. * * Since: 3.6 */ void visu_ui_interactive_setMessage(const gchar *message, GtkMessageType type) { #if GTK_MAJOR_VERSION > 2 || GTK_MINOR_VERSION > 17 GList *lst; gtk_info_bar_set_message_type(GTK_INFO_BAR(infoBar), type); lst = gtk_container_get_children(GTK_CONTAINER(gtk_info_bar_get_content_area(GTK_INFO_BAR(infoBar)))); gtk_label_set_text(GTK_LABEL(lst->data), message); g_list_free(lst); #else gtk_label_set_text(GTK_LABEL(infoBar), message); #endif gtk_widget_show(infoBar); } /** * visu_ui_interactive_unsetMessage: * * Hide any message from the interactive dialog. See also * visu_ui_interactive_setMessage(). * * Since: 3.6 */ void visu_ui_interactive_unsetMessage() { gtk_widget_hide(infoBar); } static gboolean onKillWindowEvent(GtkWidget *widget _U_, GdkEvent *event _U_, gpointer user_data) { DBG_fprintf(stderr, "Gtk interactive: window killed.\n"); visu_ui_interactive_stop(VISU_UI_RENDERING_WINDOW(user_data)); return FALSE; } static void onCloseButtonClicked(GtkButton *button _U_, gpointer user_data) { DBG_fprintf(stderr, "Gtk interactive: click on close button.\n"); if (!gtk_widget_get_visible(observeWindow)) return; visu_ui_interactive_stop(VISU_UI_RENDERING_WINDOW(user_data)); } /****************/ /* Private part */ /****************/ /* Connect the listeners on the signal emitted by the OpenGL server. */ static void connectSignalsObservePick(VisuUiRenderingWindow *window) { GtkWidget *wd; g_signal_connect(G_OBJECT(observeWindow), "delete-event", G_CALLBACK(onKillWindowEvent), window); g_signal_connect(G_OBJECT(observeWindow), "destroy-event", G_CALLBACK(onKillWindowEvent), window); wd = lookup_widget(observeWindow, "buttonBackToCommandPanel"); g_signal_connect(G_OBJECT(wd), "clicked", G_CALLBACK(onCloseButtonClicked), window); wd = lookup_widget(observeWindow, "radioObserve"); g_signal_connect(G_OBJECT(wd), "toggled", G_CALLBACK(radioObserveToggled), (gpointer)0); wd = lookup_widget(observeWindow, "buttonVisuUiOrientationChooser"); g_signal_connect(G_OBJECT(wd), "clicked", G_CALLBACK(onVisuUiOrientationChooser), (gpointer)0); /* The observe widgets. */ wd = lookup_widget(observeWindow, "radioObserveConstrained"); g_signal_connect(G_OBJECT(wd), "toggled", G_CALLBACK(observeMethodChanged), GINT_TO_POINTER(interactive_constrained)); wd = lookup_widget(observeWindow, "radioObserveWalker"); g_signal_connect(G_OBJECT(wd), "toggled", G_CALLBACK(observeMethodChanged), GINT_TO_POINTER(interactive_walker)); wd = lookup_widget(observeWindow, "notebookAction"); g_signal_connect(G_OBJECT(wd), "switch-page", G_CALLBACK(onTabActionChanged), (gpointer)0); } static void _setGlView(VisuGlView *view) { if (theta_bind) g_object_unref(theta_bind); theta_bind = (GBinding*)0; if (phi_bind) g_object_unref(phi_bind); phi_bind = (GBinding*)0; if (omega_bind) g_object_unref(omega_bind); omega_bind = (GBinding*)0; if (xs_bind) g_object_unref(xs_bind); xs_bind = (GBinding*)0; if (ys_bind) g_object_unref(ys_bind); ys_bind = (GBinding*)0; if (gross_bind) g_object_unref(gross_bind); gross_bind = (GBinding*)0; if (persp_bind) g_object_unref(persp_bind); persp_bind = (GBinding*)0; if (view) { theta_bind = g_object_bind_property(view, "theta", lookup_widget(observeWindow, "spinTheta"), "value", G_BINDING_BIDIRECTIONAL | G_BINDING_SYNC_CREATE); phi_bind = g_object_bind_property(view, "phi", lookup_widget(observeWindow, "spinPhi"), "value", G_BINDING_BIDIRECTIONAL | G_BINDING_SYNC_CREATE); omega_bind = g_object_bind_property(view, "omega", lookup_widget(observeWindow, "spinOmega"), "value", G_BINDING_BIDIRECTIONAL | G_BINDING_SYNC_CREATE); xs_bind = g_object_bind_property(view, "trans-x", lookup_widget(observeWindow, "spinDx"), "value", G_BINDING_BIDIRECTIONAL | G_BINDING_SYNC_CREATE); ys_bind = g_object_bind_property(view, "trans-y", lookup_widget(observeWindow, "spinDy"), "value", G_BINDING_BIDIRECTIONAL | G_BINDING_SYNC_CREATE); gross_bind = g_object_bind_property(view, "zoom", lookup_widget(observeWindow, "spinGross"), "value", G_BINDING_BIDIRECTIONAL | G_BINDING_SYNC_CREATE); persp_bind = g_object_bind_property(view, "perspective", lookup_widget(observeWindow, "spinPersp"), "value", G_BINDING_BIDIRECTIONAL | G_BINDING_SYNC_CREATE); } } static void onDataNotify(GtkButton *button, GParamSpec *pspec _U_, VisuGlNodeScene *scene) { if (!visu_gl_node_scene_getData(scene)) gtk_button_clicked(button); } static void onObserveStart(VisuUiRenderingWindow *window) { visu_ui_rendering_window_pushInteractive(window, interObserve); } static void onObserveStop(VisuUiRenderingWindow *window) { visu_ui_rendering_window_popInteractive(window, interObserve); } static void observeMethodChanged(GtkToggleButton* button, gpointer data) { VisuInteractiveMethod method; if (!gtk_toggle_button_get_active(button)) return; method = (VisuInteractiveMethod)GPOINTER_TO_INT(data); visu_interactive_class_setPreferedObserveMethod(method); if (method == interactive_constrained) { gtk_widget_set_sensitive(spinOmega, FALSE); g_object_set(visu_gl_node_scene_getGlView(visu_ui_rendering_window_getGlScene (visu_ui_main_class_getDefaultRendering())), "omega", 0., NULL); } else gtk_widget_set_sensitive(spinOmega, TRUE); } /* Give a name to the widgets present in this window to be able to affect them with a theme. */ static void setNamesGtkWidgetObservePick(VisuUiMain *main) { GtkWidget *wd; int method; gtk_widget_set_name(main->interactiveDialog, "message"); /* wd = lookup_widget(main->interactiveDialog, "titreObserve"); */ /* gtk_widget_set_name(wd, "message_title"); */ wd = lookup_widget(main->interactiveDialog, "labelInfoObservePick"); gtk_widget_set_name(wd, "label_info"); wd = lookup_widget(main->interactiveDialog, "labelTranslation"); gtk_widget_set_name(wd, "label_head_2"); wd = lookup_widget(main->interactiveDialog, "labelZoom"); gtk_widget_set_name(wd, "label_head_2"); wd = lookup_widget(main->interactiveDialog, "radioObserve"); gtk_widget_set_name(wd, "message_radio"); wd = lookup_widget(main->interactiveDialog, "radioPick"); gtk_widget_set_name(wd, "message_radio"); wd = lookup_widget(main->interactiveDialog, "radioMove"); gtk_widget_set_name(wd, "message_radio"); spinOmega = lookup_widget(main->interactiveDialog, "spinOmega"); method = visu_interactive_class_getPreferedObserveMethod(); if (method == interactive_constrained) gtk_widget_set_sensitive(spinOmega, FALSE); wd = lookup_widget(main->interactiveDialog, "notebookAction"); gtk_widget_set_name(wd, "message_notebook"); wd = lookup_widget(main->interactiveDialog, "radioObserveConstrained"); gtk_widget_set_name(wd, "message_radio"); if (method == interactive_constrained) gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON(wd), TRUE); wd = lookup_widget(main->interactiveDialog, "radioObserveWalker"); gtk_widget_set_name(wd, "message_radio"); if (method == interactive_walker) gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON(wd), TRUE); } static gboolean onHomePressed(GtkWidget *widget _U_, GdkEventKey *event, gpointer data _U_) { GtkWindow *window; DBG_fprintf(stderr, "Gtk Interactive: get key pressed.\n"); if(event->keyval == GDK_KEY_Home) { window = visu_ui_getRenderWindow(); g_return_val_if_fail(window, FALSE); /* We raised the rendering window, if required. */ gtk_window_present(window); return TRUE; } return FALSE; } static void onRadioToggled(GtkToggleButton *toggle, gpointer data) { GtkWidget *labelHelp; VisuUiRenderingWindow *window; if (!gtk_toggle_button_get_active(toggle)) return; window = visu_ui_main_class_getDefaultRendering(); /* Before setting up the current action, we pop the previous one. */ if (currentAction) currentAction->onStop(window); /* Get the new action. */ currentAction = (ActionInterface*)data; DBG_fprintf(stderr, "Gtk Interactive: set the action %d current.\n", currentAction->id); labelHelp = lookup_widget(observeWindow, "labelInfoObservePick"); gtk_label_set_markup(GTK_LABEL(labelHelp), currentAction->help); currentAction->onStart(window); } static void radioObserveToggled(GtkToggleButton *togglebutton, gpointer user_data _U_) { gboolean value; GtkWidget *wd; value = gtk_toggle_button_get_active(togglebutton); wd = lookup_widget(observeWindow, "hboxObserve"); gtk_widget_set_sensitive(wd, value); wd = lookup_widget(observeWindow, "tableObserve"); gtk_widget_set_sensitive(wd, value); if (visu_interactive_class_getPreferedObserveMethod() == interactive_constrained) gtk_widget_set_sensitive(spinOmega, FALSE); else gtk_widget_set_sensitive(spinOmega, value); } static void onTabActionChanged(GtkNotebook *book _U_, GtkWidget *child _U_, gint num, gpointer data _U_) { ActionInterface *action; DBG_fprintf(stderr, "Gtk Interactive: change the action tab to %d.\n", num); action = (ActionInterface*)g_list_nth_data(actions, num + 1); if (action->radio) gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON(action->radio), TRUE); } static void onOrientationChanged(VisuUiOrientationChooser *orientationChooser, gpointer data _U_) { float values[2]; DBG_fprintf(stderr, "Gtk Observe: orientation changed.\n"); visu_ui_orientation_chooser_getAnglesValues(orientationChooser, values); g_object_set(visu_gl_node_scene_getGlView(visu_ui_rendering_window_getGlScene (visu_ui_main_class_getDefaultRendering())), "theta", values[0], "phi", values[1], NULL); } static void onVisuUiOrientationChooser(GtkButton *button _U_, gpointer data _U_) { float values[2]; VisuUiRenderingWindow *window; VisuGlView *view; window = visu_ui_main_class_getDefaultRendering(); view = visu_gl_node_scene_getGlView(visu_ui_rendering_window_getGlScene(window)); if (!orientationChooser) { orientationChooser = visu_ui_orientation_chooser_new (VISU_UI_ORIENTATION_DIRECTION, TRUE, VISU_BOXED(view), GTK_WINDOW(observeWindow)); /* gtk_window_set_modal(GTK_WINDOW(orientationChooser), TRUE); */ values[0] = (float)view->camera.theta; values[1] = (float)view->camera.phi; visu_ui_orientation_chooser_setAnglesValues(VISU_UI_ORIENTATION_CHOOSER(orientationChooser), values); g_signal_connect(G_OBJECT(orientationChooser), "values-changed", G_CALLBACK(onOrientationChanged), (gpointer)0); gtk_widget_show(orientationChooser); } else gtk_window_present(GTK_WINDOW(orientationChooser)); switch (gtk_dialog_run(GTK_DIALOG(orientationChooser))) { case GTK_RESPONSE_ACCEPT: DBG_fprintf(stderr, "Gtk Observe: accept changings on orientation.\n"); break; default: DBG_fprintf(stderr, "Gtk Observe: reset values on orientation.\n"); g_object_set(view, "theta", values[0], "phi", values[1], NULL); } DBG_fprintf(stderr, "Gtk Observe: orientation object destroy.\n"); gtk_widget_destroy(orientationChooser); orientationChooser = (GtkWidget*)0; } v_sim-3.8.0/src/gtk_interactive.h000066400000000000000000000074211370110300500167530ustar00rootroot00000000000000/* EXTRAITS DE LA LICENCE Copyright CEA, contributeurs : Luc BILLARD et Damien CALISTE, laboratoire L_Sim, (2001-2005) Adresse mèl : BILLARD, non joignable par mèl ; CALISTE, damien P caliste AT cea P fr. Ce logiciel est un programme informatique servant à visualiser des structures atomiques dans un rendu pseudo-3D. Ce logiciel est régi par la licence CeCILL soumise au droit français et respectant les principes de diffusion des logiciels libres. Vous pouvez utiliser, modifier et/ou redistribuer ce programme sous les conditions de la licence CeCILL telle que diffusée par le CEA, le CNRS et l'INRIA sur le site "http://www.cecill.info". Le fait que vous puissiez accéder à cet en-tête signifie que vous avez pris connaissance de la licence CeCILL, et que vous en avez accepté les termes (cf. le fichier Documentation/licence.fr.txt fourni avec ce logiciel). */ /* LICENCE SUM UP Copyright CEA, contributors : Luc BILLARD et Damien CALISTE, laboratoire L_Sim, (2001-2005) E-mail address: BILLARD, not reachable any more ; CALISTE, damien P caliste AT cea P fr. This software is a computer program whose purpose is to visualize atomic configurations in 3D. This software is governed by the CeCILL license under French law and abiding by the rules of distribution of free software. You can use, modify and/ or redistribute the software under the terms of the CeCILL license as circulated by CEA, CNRS and INRIA at the following URL "http://www.cecill.info". The fact that you are presently reading this means that you have had knowledge of the CeCILL license and that you accept its terms. You can find a copy of this licence shipped with this software at Documentation/licence.en.txt. */ #ifndef GTK_INTERACTIVE_H #define GTK_INTERACTIVE_H #include #include "gtk_main.h" #include "gtk_renderingWindowWidget.h" /** * VisuUiInteractiveActionId: * @VISU_UI_ACTION_OBSERVE: interactive session is observe ; * @VISU_UI_ACTION_PICK: interactive session is pick ; * @VISU_UI_ACTION_MOVE: interactive session is geometry changes. * @VISU_UI_ACTION_N_PRESET: private. * * Possibe actions. */ typedef enum { VISU_UI_ACTION_OBSERVE, VISU_UI_ACTION_PICK, VISU_UI_ACTION_MOVE, /*< private >*/ VISU_UI_ACTION_N_PRESET } VisuUiInteractiveActionId; /** * VisuUiInteractiveBuild: * @main: the main interface. * @label: a location to store the name of the tab ; * @help: a location to store the help message to be shown at the * bottom of the window ; * @radio: a location on the radio button that will be toggled when * the desired action is used. * * One can create new tab in the interactive dialog window by * providing routines with this prototype. * * Returns: a new container to be include as a tab in the interactive * dialog window. */ typedef GtkWidget* (*VisuUiInteractiveBuild)(VisuUiMain *main, gchar **label, gchar **help, GtkWidget **radio); /** * VisuUiInteractiveStartStop: * @window: the rendering window that starts or stops the interaction * defined in the tab. * * Routines of this prototype are called each time the interactive * mode should be changed. */ typedef void (*VisuUiInteractiveStartStop)(VisuUiRenderingWindow *window); guint visu_ui_interactive_addAction(VisuUiInteractiveBuild build, VisuUiInteractiveStartStop start, VisuUiInteractiveStartStop stop); void visu_ui_interactive_init(); void visu_ui_interactive_toggle(void); void visu_ui_interactive_initBuild(VisuUiMain *main); void visu_ui_interactive_start(VisuUiRenderingWindow *window); void visu_ui_interactive_stop(VisuUiRenderingWindow *window); void visu_ui_interactive_setMessage(const gchar *message, GtkMessageType type); void visu_ui_interactive_unsetMessage(); #endif v_sim-3.8.0/src/gtk_main.c000066400000000000000000001375011370110300500153600ustar00rootroot00000000000000/* EXTRAITS DE LA LICENCE Copyright CEA, contributeurs : Luc BILLARD et Damien CALISTE, laboratoire L_Sim, (2001-2006) Adresse mèl : BILLARD, non joignable par mèl ; CALISTE, damien P caliste AT cea P fr. Ce logiciel est un programme informatique servant à visualiser des structures atomiques dans un rendu pseudo-3D. Ce logiciel est régi par la licence CeCILL soumise au droit français et respectant les principes de diffusion des logiciels libres. Vous pouvez utiliser, modifier et/ou redistribuer ce programme sous les conditions de la licence CeCILL telle que diffusée par le CEA, le CNRS et l'INRIA sur le site "http://www.cecill.info". Le fait que vous puissiez accéder à cet en-tête signifie que vous avez pris connaissance de la licence CeCILL, et que vous en avez accepté les termes (cf. le fichier Documentation/licence.fr.txt fourni avec ce logiciel). */ /* LICENCE SUM UP Copyright CEA, contributors : Luc BILLARD et Damien CALISTE, laboratoire L_Sim, (2001-2005) E-mail address: BILLARD, not reachable any more ; CALISTE, damien P caliste AT cea P fr. This software is a computer program whose purpose is to visualize atomic configurations in 3D. This software is governed by the CeCILL license under French law and abiding by the rules of distribution of free software. You can use, modify and/ or redistribute the software under the terms of the CeCILL license as circulated by CEA, CNRS and INRIA at the following URL "http://www.cecill.info". The fact that you are presently reading this means that you have had knowledge of the CeCILL license and that you accept its terms. You can find a copy of this licence shipped with this software at Documentation/licence.en.txt. */ #include #include #include #include #include #include #include #include /* For the access markers R_OK, W_OK ... */ #include #include #include "interface.h" #include "support.h" #include "gtk_main.h" #include "gtk_interactive.h" #include "gtk_pick.h" #include "gtk_move.h" #include "gtk_pairs.h" #include "gtk_about.h" #include "gtk_save.h" #include "gtk_renderingWindowWidget.h" #include "extraGtkFunctions/gtk_colorComboBoxWidget.h" #include "extraGtkFunctions/gtk_shadeComboBoxWidget.h" #include "extraGtkFunctions/gtk_fieldChooser.h" #include "extraGtkFunctions/gtk_dataChooser.h" #include "panelModules/externalModules.h" #include "panelModules/panelElements.h" #include "panelModules/panelAxes.h" #include "panelModules/panelBrowser.h" #include "panelModules/panelDataFile.h" #include "panelModules/panelPlanes.h" #include "visu_gtk.h" #include "opengl.h" #include "visu_data.h" #include "visu_dataatomic.h" #include "visu_configFile.h" #include "visu_basic.h" /* To have loadDataFromFile */ #include "visu_commandLine.h" /* To have getArgFilename and getXWindowGeometry*/ #include "visu_extension.h" #include "visu_plugins.h" #include "coreTools/toolOptions.h" #include "coreTools/toolConfigFile.h" #include "extraFunctions/dataFile.h" #include "extraFunctions/scalarFieldSet.h" #include "extensions/pairs.h" #include "extensions/surfs.h" #include "extensions/geodiff.h" #include "extensions/mapset.h" /** * SECTION: gtk_main * @short_description: The command panel definition. * * This is the main interface in V_Sim. It hosts the common action * buttons, like open a file, save resources, switch to interactive * session... It also hosts the different panels. */ /** * VisuUiMain: * * Structure to describe the main interface of V_Sim. */ enum { DATA_FOCUSED_SIGNAL, DIR_SIGNAL, LAST_SIGNAL }; static guint visu_ui_main_signals[LAST_SIGNAL]; struct _VisuUiMainClass { GtkWindowClass parent; /* Gestion of the main window positioning. */ gboolean rememberWindowPosition; GHashTable *windowPosition; /* Alert or not when quiting. */ gboolean warningWhenQuit; }; /** * VisuUiMainPrivate: * * Private fields of a #VisuUiMain object. */ struct _VisuUiMainPrivate { gboolean dispose_has_run; /* Pointers on different inside widgets. */ GtkWidget *loadButton; GtkWidget *checkPairs; GtkWidget *pairsButton; GtkWidget *mouseActions; GtkWidget *saveButton; GtkWidget *quitButton; GtkWidget *aboutButton; GtkWidget *vboxMain; /* Variables. */ gboolean oneWindow; gboolean actionDialogIsShown; /* Store the last open directory. It is initialised to current working directory. */ gchar *lastDir; }; /* Local object method. */ static void visu_ui_main_class_init(VisuUiMainClass *klass); static void visu_ui_main_init (VisuUiMain *obj); static void visu_ui_main_dispose (GObject *obj); static void visu_ui_main_finalize (GObject *obj); /* Local variables. */ static GtkWindowClass *parent_class = NULL; static VisuUiMainClass *my_class = NULL; static VisuUiMain *currentVisuUiMain = NULL; static gint gtkFileChooserWidth = -1, gtkFileChooserHeight = -1; /* Miscelaneous functions with gtk */ static void hideWindow(GtkWindow *win); static void showWindow(GtkWindow *win); /* Local callbacks */ static gboolean onHomePressed(GtkWidget *widget _U_, GdkEventKey *event, gpointer data); static void onLoadButtonClicked(VisuUiMain *main, GtkButton *button); static void onPairsButtonClicked(VisuUiMain *main, GtkButton *button); static void onMouseActionsClicked(VisuUiMain *main, GtkButton *button); static void onSaveButtonClicked(VisuUiMain *main, GtkButton *button); static void onQuitButtonClicked(VisuUiMain *main, GtkButton *button); static void onAboutButtonClicked(VisuUiMain *main, GtkButton *button); static void onDataReady(VisuGlNodeScene *scene, GParamSpec *pspec, gpointer data); static void onShowActionDialog(VisuUiMain *main, VisuUiRenderingWindow *window); static void onShowMainPanel(VisuUiMain *main, VisuUiRenderingWindow *window); static gboolean onKillPairsDialog(VisuUiMain *main, GdkEvent *event, gpointer data); static gboolean onKillAboutDialog(VisuUiMain *main, GdkEvent *event, gpointer data); static gboolean onKillInteractiveDialog(VisuUiMain *main, GdkEvent *event, gpointer data); static gboolean onKillMainWindowEvent(GtkWidget *widget, GdkEvent *event, gpointer user_data); void onHideNextTime(GtkToggleButton *button, gpointer data); /* Parameter to store the position of windows. */ #define PARAMETER_GTKMAIN_REMEMBER_DEFAULT TRUE /* Parameter to change the policy of the warning quit dialog. */ #define FLAG_PARAMETER_GTKMAIN_QUIT "main_confirmQuit" #define DESC_PARAMETER_GTKMAIN_QUIT "Show up a dialog to confirm when quit button is clicked ; boolean 0 or 1" #define PARAMETER_GTKMAIN_QUIT_DEFAULT TRUE #define FLAG_PARAMETER_GTKMAIN_PANEL "main_panelStatus" #define DESC_PARAMETER_GTKMAIN_PANEL "Attach a panel to a tool window ; panel_name window_name (or None or Main)" static gboolean readMainPanelStatus(VisuConfigFileEntry *entry _U_, gchar **lines, int nbLines, int position, GError **error); #define FLAG_PARAMETER_GTKMAIN_DOCK "main_dock" #define DESC_PARAMETER_GTKMAIN_DOCK "Define the characteristic of a dock window ; visibility size(x,y) position(w,h) window_name" static gboolean readMainDock(VisuConfigFileEntry *entry _U_, gchar **lines, int nbLines, int position, GError **error); static void exportParametersVisuUiMain(GString *data, VisuData *dataObj); /* Number of time V_Sim try to attach the OpenGL context. */ #define VISU_UI_MAIN_N_MAX_OPENGL 10 /*******************/ /* Object methods. */ /*******************/ G_DEFINE_TYPE_WITH_CODE(VisuUiMain, visu_ui_main, GTK_TYPE_WINDOW, G_ADD_PRIVATE(VisuUiMain)) static void visu_ui_main_class_init(VisuUiMainClass *klass) { VisuConfigFileEntry *resourceEntry; DBG_fprintf(stderr, "Gtk Main: creating the class of the object.\n"); parent_class = g_type_class_peek_parent(klass); my_class = klass; /** * VisuUiMain::DataFocused: * @ui: the object which received the signal ; * @dataObj: the newly associated #VisuData object. * * This signal is emitted when @dataObj has been displayed on the * rendering window and is ready for use. * * Since: 3.7 */ visu_ui_main_signals[DATA_FOCUSED_SIGNAL] = g_signal_new("DataFocused", G_TYPE_FROM_CLASS(klass), G_SIGNAL_RUN_LAST | G_SIGNAL_NO_RECURSE | G_SIGNAL_NO_HOOKS, 0 , NULL, NULL, g_cclosure_marshal_VOID__OBJECT, G_TYPE_NONE, 1, VISU_TYPE_DATA); /** * VisuUiMain::DirectoryChanged: * @ui: the object emitting the signal. * @kind: a flag. * * The current directory has been changed. The kind of directory is * defined by @kind (see #). * * Since: 3.6 */ visu_ui_main_signals[DIR_SIGNAL] = g_signal_new("DirectoryChanged", G_TYPE_FROM_CLASS (klass), G_SIGNAL_RUN_LAST | G_SIGNAL_NO_RECURSE | G_SIGNAL_NO_HOOKS, 0, NULL, NULL, g_cclosure_marshal_VOID__UINT, G_TYPE_NONE, 1, G_TYPE_UINT); /* Connect freeing methods. */ G_OBJECT_CLASS(klass)->dispose = visu_ui_main_dispose; G_OBJECT_CLASS(klass)->finalize = visu_ui_main_finalize; /* Add the config file entries. */ visu_config_file_addKnownTag("gtk"); DBG_fprintf(stderr, " - add config file entries ;\n"); resourceEntry = visu_config_file_addBooleanEntry(VISU_CONFIG_FILE_PARAMETER, FLAG_PARAMETER_GTKMAIN_QUIT, DESC_PARAMETER_GTKMAIN_QUIT, &klass->warningWhenQuit, FALSE); visu_config_file_entry_setVersion(resourceEntry, 3.3f); resourceEntry = visu_config_file_addEntry(VISU_CONFIG_FILE_PARAMETER, FLAG_PARAMETER_GTKMAIN_PANEL, DESC_PARAMETER_GTKMAIN_PANEL, 1, readMainPanelStatus); visu_config_file_entry_setVersion(resourceEntry, 3.3f); resourceEntry = visu_config_file_addEntry(VISU_CONFIG_FILE_PARAMETER, FLAG_PARAMETER_GTKMAIN_DOCK, DESC_PARAMETER_GTKMAIN_DOCK, 1, readMainDock); visu_config_file_entry_setVersion(resourceEntry, 3.3f); visu_config_file_addExportFunction(VISU_CONFIG_FILE_PARAMETER, exportParametersVisuUiMain); /* Set static parameters. */ DBG_fprintf(stderr, " - miscelaneous ;\n"); klass->rememberWindowPosition = PARAMETER_GTKMAIN_REMEMBER_DEFAULT; klass->warningWhenQuit = PARAMETER_GTKMAIN_QUIT_DEFAULT; klass->windowPosition = g_hash_table_new_full(g_direct_hash, g_direct_equal, NULL, g_free); /* Force the creation of the VisuUiColorComboboxClass. */ g_type_class_ref(visu_ui_color_combobox_get_type()); g_type_class_ref(VISU_TYPE_UI_DATA_CHOOSER); g_type_class_ref(VISU_TYPE_UI_FIELD_CHOOSER); g_type_class_ref(VISU_TYPE_UI_PANEL); } static void _buildWidgets(VisuUiMain *obj, gboolean oneWindow) { int width, height; int i; GtkWidget *vbox, *hbox, *hbox2, *wd, *image, *label, *pane; VisuUiPanel *panel; VisuUiDockWindow *dockMain; VisuGlNodeScene *scene; #if GTK_MAJOR_VERSION == 2 && GTK_MINOR_VERSION < 12 GtkTooltips *tooltips; tooltips = gtk_tooltips_new (); #endif currentVisuUiMain = obj; /* Private data. */ DBG_fprintf(stderr, "--- Initialising the GTK interface ---\n"); DBG_fprintf(stderr, " | Gtk Main"); gtk_window_set_title(GTK_WINDOW(obj), _("Command panel")); #if GTK_MAJOR_VERSION < 3 || (GTK_MAJOR_VERSION == 3 && GTK_MINOR_VERSION < 22) gtk_window_set_wmclass(GTK_WINDOW(obj), "v_sim_commandPanel", "V_Sim"); #else gtk_window_set_role(GTK_WINDOW(obj), "v_sim_commandPanel"); #endif obj->priv->vboxMain = gtk_vbox_new(FALSE, 0); gtk_widget_set_size_request(obj->priv->vboxMain, 350, -1); gtk_container_set_border_width(GTK_CONTAINER(obj->priv->vboxMain), 7); obj->priv->oneWindow = oneWindow; DBG_fprintf(stderr,"--- Initialising the rendering window ---\n"); commandLineGet_XWindowGeometry(&width, &height); obj->renderingWindow = visu_ui_rendering_window_new(width, height, obj->priv->oneWindow, TRUE); g_signal_connect_swapped(G_OBJECT(obj->renderingWindow), "show-action-dialog", G_CALLBACK(onShowActionDialog), (gpointer)obj); g_signal_connect_swapped(G_OBJECT(obj->renderingWindow), "show-main-panel", G_CALLBACK(onShowMainPanel), (gpointer)obj); if (oneWindow) { pane = gtk_hpaned_new(); gtk_container_add(GTK_CONTAINER(obj), pane); gtk_widget_show(pane); gtk_paned_pack1(GTK_PANED(pane), obj->priv->vboxMain, FALSE, FALSE); gtk_paned_pack2(GTK_PANED(pane), obj->renderingWindow, TRUE, TRUE); } else gtk_container_add(GTK_CONTAINER(obj), obj->priv->vboxMain); scene = visu_ui_rendering_window_getGlScene(VISU_UI_RENDERING_WINDOW(obj->renderingWindow)); wd = gtk_frame_new(_("Actions")); gtk_box_pack_end(GTK_BOX(obj->priv->vboxMain), wd, FALSE, FALSE, 0); vbox = gtk_vbox_new(FALSE, 0); gtk_container_add(GTK_CONTAINER(wd), vbox); hbox = gtk_hbox_new(FALSE, 0); gtk_box_pack_start(GTK_BOX(vbox), hbox, FALSE, FALSE, 0); gtk_container_set_border_width(GTK_CONTAINER(hbox), 5); obj->priv->loadButton = gtk_button_new_from_icon_name("document-open", GTK_ICON_SIZE_BUTTON); gtk_box_pack_start(GTK_BOX(hbox), obj->priv->loadButton, TRUE, TRUE, 0); gtk_widget_set_tooltip_text(obj->priv->loadButton, _("Select a file to render.")); hbox2 = gtk_hbox_new(FALSE, 0); gtk_box_pack_start(GTK_BOX(hbox), hbox2, TRUE, TRUE, 10); obj->priv->checkPairs = gtk_check_button_new(); g_object_bind_property(visu_gl_node_scene_getPairs(scene), "active", obj->priv->checkPairs, "active", G_BINDING_BIDIRECTIONAL | G_BINDING_SYNC_CREATE); gtk_box_pack_start(GTK_BOX(hbox2), obj->priv->checkPairs, FALSE, FALSE, 0); gtk_widget_set_tooltip_text(obj->priv->checkPairs, _("Check to draw pairs between elements.")); obj->priv->pairsButton = gtk_button_new(); g_object_bind_property(obj->renderingWindow, "data", obj->priv->pairsButton, "sensitive", G_BINDING_SYNC_CREATE); gtk_box_pack_start(GTK_BOX(hbox2), obj->priv->pairsButton, TRUE, TRUE, 0); gtk_widget_set_tooltip_text(obj->priv->pairsButton, _("Configure parameters for bindings such as color, thickness...")); wd = gtk_hbox_new(FALSE, 2); gtk_container_add(GTK_CONTAINER(obj->priv->pairsButton), wd); image = gtk_image_new_from_icon_name("emblem-shared", GTK_ICON_SIZE_BUTTON); gtk_box_pack_start(GTK_BOX(wd), image, FALSE, FALSE, 0); label = gtk_label_new_with_mnemonic(_("_Pairs")); gtk_box_pack_start(GTK_BOX(wd), label, FALSE, FALSE, 0); obj->priv->mouseActions = gtk_button_new(); g_object_bind_property(obj->renderingWindow, "data", obj->priv->mouseActions, "sensitive", G_BINDING_SYNC_CREATE); gtk_box_pack_start(GTK_BOX(hbox), obj->priv->mouseActions, TRUE, TRUE, 0); gtk_widget_set_tooltip_text(obj->priv->mouseActions, _("Use the mouse to change the view and get position informations.")); wd = gtk_hbox_new(FALSE, 2); gtk_container_add(GTK_CONTAINER(obj->priv->mouseActions), wd); image = gtk_image_new_from_icon_name("zoom-fit-best", GTK_ICON_SIZE_BUTTON); gtk_box_pack_start(GTK_BOX(wd), image, FALSE, FALSE, 0); label = gtk_label_new_with_mnemonic(_("Mouse _actions")); gtk_box_pack_start(GTK_BOX(wd), label, FALSE, FALSE, 0); hbox = gtk_hbox_new(FALSE, 5); gtk_box_pack_start(GTK_BOX(vbox), hbox, FALSE, FALSE, 0); gtk_container_set_border_width(GTK_CONTAINER(hbox), 5); obj->priv->saveButton = gtk_button_new(); gtk_box_pack_start(GTK_BOX(hbox), obj->priv->saveButton, TRUE, TRUE, 5); gtk_widget_set_tooltip_text(obj->priv->saveButton, _("Click to save the parameters or the resources.")); wd = gtk_hbox_new(FALSE, 2); gtk_container_add(GTK_CONTAINER(obj->priv->saveButton), wd); image = gtk_image_new_from_icon_name("document-save", GTK_ICON_SIZE_BUTTON); gtk_box_pack_start(GTK_BOX(wd), image, FALSE, FALSE, 0); label = gtk_label_new_with_mnemonic(_("_Config. files")); gtk_box_pack_start(GTK_BOX(wd), label, FALSE, FALSE, 0); obj->priv->quitButton = gtk_button_new_from_icon_name("application-exit", GTK_ICON_SIZE_BUTTON); gtk_box_pack_start(GTK_BOX(hbox), obj->priv->quitButton, TRUE, TRUE, 5); obj->priv->aboutButton = gtk_button_new(); gtk_box_pack_start(GTK_BOX(hbox), obj->priv->aboutButton, FALSE, FALSE, 15); gtk_widget_set_tooltip_text(obj->priv->aboutButton, _("V_Sim program. Written by L. Billard, modified by D. Caliste.")); gtk_button_set_relief(GTK_BUTTON(obj->priv->aboutButton), GTK_RELIEF_NONE); image = create_pixmap(GTK_WIDGET(obj), "logo_petit.png"); gtk_container_add(GTK_CONTAINER(obj->priv->aboutButton), image); g_signal_connect_swapped(G_OBJECT(obj->priv->loadButton), "clicked", G_CALLBACK(onLoadButtonClicked), (gpointer)obj); g_signal_connect_swapped(G_OBJECT(obj->priv->pairsButton), "clicked", G_CALLBACK(onPairsButtonClicked), (gpointer)obj); g_signal_connect_swapped(G_OBJECT(obj->priv->mouseActions), "clicked", G_CALLBACK(onMouseActionsClicked), (gpointer)obj); g_signal_connect_swapped(G_OBJECT(obj->priv->saveButton), "clicked", G_CALLBACK(onSaveButtonClicked), (gpointer)obj); g_signal_connect_swapped(G_OBJECT(obj->priv->quitButton), "clicked", G_CALLBACK(onQuitButtonClicked), (gpointer)obj); g_signal_connect_swapped(G_OBJECT(obj->priv->aboutButton), "clicked", G_CALLBACK(onAboutButtonClicked), (gpointer)obj); g_signal_connect(G_OBJECT(obj), "delete-event", G_CALLBACK(onKillMainWindowEvent), (gpointer)obj); g_signal_connect(G_OBJECT(obj), "destroy-event", G_CALLBACK(onKillMainWindowEvent), (gpointer)obj); g_signal_connect_object(scene, "notify::data", G_CALLBACK(onDataReady), obj, G_CONNECT_AFTER); DBG_fprintf(stderr, " ... OK.\n"); /* init the sub panel contains. */ dockMain = visu_ui_panel_class_getCommandPanel(); wd = visu_ui_dock_window_getContainer(dockMain); gtk_box_pack_start(GTK_BOX(obj->priv->vboxMain), wd, TRUE, TRUE, 0); /* Show all. */ gtk_widget_show_all(obj->priv->vboxMain); #define ADD(P) visu_ui_panel_attach(VISU_UI_PANEL(P), dockMain) ADD(visu_ui_panel_elements_init(obj)); ADD(visu_ui_panel_axes_init(obj)); for (i = 0; panelListAll[i]; i++) { panel = panelListAll[i](obj); if (!panel) { g_error("Can't initialise subpanel number %d.\n", i); } visu_ui_panel_attach(panel, dockMain); if (i == 0) gtk_notebook_set_current_page(GTK_NOTEBOOK(visu_ui_dock_window_getNotebook(dockMain)), 0); DBG_fprintf(stderr, "Gtk Main: initialise '%s' subpanel OK.\n", visu_ui_panel_getLabel(panel)); } gtk_notebook_set_current_page(GTK_NOTEBOOK(visu_ui_dock_window_getNotebook(dockMain)), 0); DBG_fprintf(stderr, "Gtk Main: build widgets OK.\n"); } static void visu_ui_main_init(VisuUiMain *obj) { DBG_fprintf(stderr, "Gtk Main: initializing a new object (%p).\n", (gpointer)obj); obj->priv = visu_ui_main_get_instance_private(obj); obj->priv->dispose_has_run = FALSE; /* Public data. */ obj->renderingWindow = (GtkWidget*)0; obj->pairsDialog = (GtkWidget*)0; obj->interactiveDialog = (GtkWidget*)0; obj->aboutDialog = (GtkWidget*)0; /* Private variables. */ obj->priv->oneWindow = FALSE; obj->priv->actionDialogIsShown = FALSE; /* Retrieve the current working directory. */ obj->priv->lastDir = g_get_current_dir(); g_signal_connect(G_OBJECT(obj), "key-press-event", G_CALLBACK(onHomePressed), (gpointer)obj); /* Others elements linked to the main window. */ DBG_fprintf(stderr, " | Gtk Interactive\n"); visu_ui_interactive_init(); } /* This method can be called several times. It should unref all of its reference to GObjects. */ static void visu_ui_main_dispose(GObject* obj) { VisuUiMain *mainUI; DBG_fprintf(stderr, "Gtk Main: dispose object %p.\n", (gpointer)obj); mainUI = VISU_UI_MAIN(obj); if (mainUI->priv->dispose_has_run) return; mainUI->priv->dispose_has_run = TRUE; if (mainUI->renderingWindow && !mainUI->priv->oneWindow) { DBG_fprintf(stderr, "Gtk Main: destroying the rendering window.\n"); gtk_widget_destroy(mainUI->renderingWindow); } DBG_fprintf(stderr, "Gtk Main: destroying the dialogs.\n"); if (mainUI->pairsDialog) gtk_widget_destroy(mainUI->pairsDialog); if (mainUI->interactiveDialog) gtk_widget_destroy(mainUI->interactiveDialog); if (mainUI->aboutDialog) gtk_widget_destroy(mainUI->aboutDialog); /* Finish panels. */ visu_ui_panel_axes_setAxesExtension((VisuGlExtAxes*)0); DBG_fprintf(stderr, "Gtk Main: chain to parent.\n"); G_OBJECT_CLASS(parent_class)->dispose(obj); DBG_fprintf(stderr, "Gtk Main: dispose done.\n"); } /* This method is called once only. */ static void visu_ui_main_finalize(GObject* obj) { g_return_if_fail(obj); DBG_fprintf(stderr, "Gtk Main: finalize object %p.\n", (gpointer)obj); g_free(VISU_UI_MAIN(obj)->priv->lastDir); /* Chain up to the parent class */ G_OBJECT_CLASS(parent_class)->finalize(obj); DBG_fprintf(stderr, "Gtk Main: freeing ... OK.\n"); } GtkWidget* visu_ui_main_new(gboolean oneWindow) { VisuUiMain *commandPanel; commandPanel = VISU_UI_MAIN(g_object_new(VISU_TYPE_UI_MAIN, NULL)); if (!commandPanel) return (GtkWidget*)0; _buildWidgets(commandPanel, oneWindow); gtk_window_set_default_size(GTK_WINDOW(commandPanel), 100, -1); return GTK_WIDGET(commandPanel); } /** * visu_ui_main_getRendering: * @main: a #VisuUiMain object. * * Retrieve the rendering window controlled by @main. * * Since: 3.8 * * Returns: (transfer none): the #VisuUiRenderingWindow controled by * this @main panel. **/ VisuUiRenderingWindow* visu_ui_main_getRendering(VisuUiMain *main) { g_return_val_if_fail(VISU_IS_UI_MAIN(main), (VisuUiRenderingWindow*)0); return VISU_UI_RENDERING_WINDOW(main->renderingWindow); } /** * visu_ui_main_setLastOpenDirectory: * @main: a #VisuUiMain object. * @directory: a full path to a directory ; * @type: the kind of directory to set the remember flag on. * * V_Sim stores the last open directory to set the file chooser to * this one the next time it will come. Use this routine each time a * file chooser returns GTK_RESPONSE_OK. The given string will be * copied and can be freed after use. */ void visu_ui_main_setLastOpenDirectory(VisuUiMain *main, const char* directory, VisuUiDirectoryType type) { g_return_if_fail(VISU_IS_UI_MAIN(main)); g_free(main->priv->lastDir); if (!g_path_is_absolute(directory)) main->priv->lastDir = g_build_filename(g_get_current_dir(), directory, NULL); else main->priv->lastDir = g_build_filename(directory, NULL); DBG_fprintf(stderr, "Visu Gtk: set the last open directory to '%s', emit signal.\n", main->priv->lastDir); g_signal_emit(main, visu_ui_main_signals[DIR_SIGNAL], 0, type); DBG_fprintf(stderr, "Visu Gtk: emission done (DirectoryChanged).\n"); } /** * visu_ui_main_getLastOpenDirectory: * @main: a #VisuUiMain object. * * V_Sim stores the last open directory to set the file chooser to * this one the next time it will come. Use * visu_ui_main_setLastOpenDirectory() to store it after a GTK_RESPONSE_OK * has been returned by a file chooser and then initialise each new * with this routine. * * Returns: (transfer none): a string owned by V_Sim. */ const char* visu_ui_main_getLastOpenDirectory(VisuUiMain *main) { g_return_val_if_fail(VISU_IS_UI_MAIN(main), (gchar*)0); DBG_fprintf(stderr, "Visu Gtk: get the last open directory : '%s'.\n", main->priv->lastDir); return main->priv->lastDir; } /** * visu_ui_main_getSelectedDirectory: * @main: a #VisuUiMain object. * @parent: (allow-none): if NULL, the command panel window is used ; * @multiple: if TRUE, multiple directories can be selected ; * @dir: (allow-none): if not NULL, give the opening directory. * * General procedure to get the location of one or more directories. * In the multiple case, all selected directories shares a common ancestor * since the selection is done through the same selector that for single * directory but with multiple selection activated. If @dir is NULL * the last opened (and stored) directory is used (see * visu_ui_main_getLastOpenDirectory() and visu_ui_main_setLastOpenDirectory()). * * Returns: (array zero-terminated=1) (transfer full): a newly * allocated array of paths, NULL terminated. Use g_strfreev() to free * it after use. If no directory is selected, then NULL is returned. */ gchar** visu_ui_main_getSelectedDirectory(VisuUiMain *main, GtkWindow *parent, gboolean multiple, const gchar *dir) { GtkWidget *file_selector, *hbox, *wd; gchar **dirnames; GSList* names, *tmpLst; int i; /* Create the selector */ if (!parent) parent = GTK_WINDOW(main); file_selector = gtk_file_chooser_dialog_new(_("Choose a directory"), parent, GTK_FILE_CHOOSER_ACTION_SELECT_FOLDER, TOOL_ICON_CANCEL, GTK_RESPONSE_CANCEL, TOOL_ICON_OPEN, GTK_RESPONSE_OK, NULL); if (gtkFileChooserWidth > 0 || gtkFileChooserHeight > 0) gtk_window_set_default_size(GTK_WINDOW(file_selector), gtkFileChooserWidth, gtkFileChooserHeight); if (multiple) { hbox = gtk_hbox_new(FALSE, 0); gtk_file_chooser_set_extra_widget(GTK_FILE_CHOOSER(file_selector), hbox); wd = gtk_image_new_from_icon_name("help-browser", GTK_ICON_SIZE_MENU); gtk_box_pack_start(GTK_BOX(hbox), wd, FALSE, FALSE, 0); wd = gtk_label_new(""); gtk_box_pack_start(GTK_BOX(hbox), wd, TRUE, TRUE, 5); gtk_label_set_xalign(GTK_LABEL(wd), 0.); gtk_label_set_use_markup(GTK_LABEL(wd), TRUE); gtk_label_set_markup(GTK_LABEL(wd), _("Choose several" " directories using the" " " "Control key.")); gtk_widget_show_all(hbox); } if (!dir && visu_ui_main_getLastOpenDirectory(main)) { DBG_fprintf(stderr, "Visu Gtk: open a directory chooser, set on '%s'.\n", visu_ui_main_getLastOpenDirectory(main)); gtk_file_chooser_set_current_folder(GTK_FILE_CHOOSER(file_selector), visu_ui_main_getLastOpenDirectory(main)); } gtk_file_chooser_set_select_multiple(GTK_FILE_CHOOSER(file_selector), multiple); gtk_widget_set_name(file_selector, "filesel"); gtk_window_set_position(GTK_WINDOW(file_selector), GTK_WIN_POS_CENTER_ON_PARENT); gtk_window_set_modal(GTK_WINDOW (file_selector), TRUE); if (gtk_dialog_run (GTK_DIALOG (file_selector)) == GTK_RESPONSE_OK) { names = gtk_file_chooser_get_filenames(GTK_FILE_CHOOSER(file_selector)); dirnames = g_malloc(sizeof(gchar*) * (g_slist_length(names) + 1)); tmpLst = names; i = 0; while(tmpLst) { dirnames[i] = (gchar*)tmpLst->data; i += 1; tmpLst = g_slist_next(tmpLst); } dirnames[i] = (gchar*)0; g_slist_free(names); } else dirnames = (gchar**)0; gtk_window_get_size(GTK_WINDOW(file_selector), >kFileChooserWidth, >kFileChooserHeight); gtk_widget_destroy (file_selector); return dirnames; } /*******************/ /* Local callbacks */ /*******************/ static gboolean onHomePressed(GtkWidget *widget, GdkEventKey *event, gpointer data _U_) { GtkWidget *focus; DBG_fprintf(stderr, "Gtk Main: get key pressed.\n"); if(event->keyval == GDK_KEY_Home && !VISU_UI_MAIN(data)->priv->oneWindow) { focus = gtk_window_get_focus(GTK_WINDOW(widget)); if (GTK_IS_EDITABLE(focus)) return FALSE; gtk_window_present(visu_ui_getRenderWindow()); return TRUE; } return FALSE; } static void onShowMainPanel(VisuUiMain *main, VisuUiRenderingWindow *window _U_) { if (main->priv->actionDialogIsShown) gtk_window_present(GTK_WINDOW(main->interactiveDialog)); else gtk_window_present(GTK_WINDOW(main)); } static void onLoadButtonClicked(VisuUiMain *main, GtkButton *button _U_) { visu_ui_rendering_window_open(VISU_UI_RENDERING_WINDOW(main->renderingWindow), GTK_WINDOW(main)); } static void onPairsCloseClicked(VisuUiMain *main, GtkButton *button _U_) { hideWindow(GTK_WINDOW(main->pairsDialog)); } static gboolean onKillPairsDialog(VisuUiMain *main, GdkEvent *event _U_, gpointer data _U_) { hideWindow(GTK_WINDOW(main->pairsDialog)); return TRUE; } static void onPairsButtonClicked(VisuUiMain *main, GtkButton *button _U_) { GtkWidget *wd; if (!main->pairsDialog) { visu_ui_pairs_initBuild(main); wd = lookup_widget(main->pairsDialog, "closebutton3"); g_signal_connect_swapped(G_OBJECT(wd), "clicked", G_CALLBACK(onPairsCloseClicked), (gpointer)main); g_signal_connect_swapped(G_OBJECT(main->pairsDialog), "delete-event", G_CALLBACK(onKillPairsDialog), (gpointer)main); g_signal_connect_swapped(G_OBJECT(main->pairsDialog), "destroy-event", G_CALLBACK(onKillPairsDialog), (gpointer)main); } showWindow(GTK_WINDOW(main->pairsDialog)); } static void onActionsCloseClicked(VisuUiMain *main, GtkButton *button _U_) { hideWindow(GTK_WINDOW(main->interactiveDialog)); main->priv->actionDialogIsShown = FALSE; if (!main->priv->oneWindow) showWindow(GTK_WINDOW(main)); } static gboolean onKillInteractiveDialog(VisuUiMain *main, GdkEvent *event _U_, gpointer data _U_) { onActionsCloseClicked(main, (GtkButton*)0); return TRUE; } static void _raiseMouseActionDialog(VisuUiMain *main, VisuUiRenderingWindow *window) { gint posx, posy; if (!main->interactiveDialog) visu_ui_main_buildInteractiveDialog(main); /* Start new pick & observe session. */ visu_ui_interactive_start(window); if (!main->priv->oneWindow) { gtk_window_get_position(GTK_WINDOW(main), &posx, &posy); DBG_fprintf(stderr, "Gtk Main: get command panel position" " (%d,%d).\n", posx, posy); hideWindow(GTK_WINDOW(main)); DBG_fprintf(stderr, "Gtk Main: set observe position (%d,%d).\n", posx, posy); gtk_window_move(GTK_WINDOW(main->interactiveDialog), posx, posy); } showWindow(GTK_WINDOW(main->interactiveDialog)); main->priv->actionDialogIsShown = TRUE; } static void onMouseActionsClicked(VisuUiMain *main, GtkButton *button _U_) { _raiseMouseActionDialog(main, VISU_UI_RENDERING_WINDOW(main->renderingWindow)); } static void onShowActionDialog(VisuUiMain *main, VisuUiRenderingWindow *window) { _raiseMouseActionDialog(main, window); } static void onSaveButtonClicked(VisuUiMain *main _U_, GtkButton *button _U_) { visu_ui_save_initBuild(); } static void onQuitButtonClicked(VisuUiMain *main, GtkButton *button _U_) { visu_ui_main_quit(main, FALSE); } static gboolean onKillAboutDialog(VisuUiMain *main, GdkEvent *event _U_, gpointer data _U_) { hideWindow(GTK_WINDOW(main->aboutDialog)); return TRUE; } static void onAboutButtonClicked(VisuUiMain *main, GtkButton *button _U_) { if (!main->aboutDialog) { visu_ui_about_initBuild(main); g_signal_connect_swapped(G_OBJECT(main->aboutDialog), "delete-event", G_CALLBACK(onKillAboutDialog), (gpointer)main); g_signal_connect_swapped(G_OBJECT(main->aboutDialog), "destroy-event", G_CALLBACK(onKillAboutDialog), (gpointer)main); } showWindow(GTK_WINDOW(main->aboutDialog)); } static void onDataReady(VisuGlNodeScene *scene, GParamSpec *pspec _U_, gpointer data) { VisuData *dataObj; dataObj = visu_gl_node_scene_getData(scene); visu_ui_panel_class_setCurrent(dataObj, visu_gl_node_scene_getGlView(scene)); g_signal_emit(G_OBJECT(data), visu_ui_main_signals[DATA_FOCUSED_SIGNAL], 0, dataObj); } static gboolean onKillMainWindowEvent(GtkWidget *widget _U_, GdkEvent *event _U_, gpointer user_data) { visu_ui_main_quit(VISU_UI_MAIN(user_data), FALSE); return TRUE; } /*****************/ /* Miscellaneous */ /*****************/ void visu_ui_main_buildInteractiveDialog(VisuUiMain *main) { GtkWidget *wd; g_return_if_fail(VISU_IS_UI_MAIN(main) && !main->interactiveDialog); visu_ui_interactive_initBuild(main); wd = lookup_widget(main->interactiveDialog, "buttonBackToCommandPanel"); g_signal_connect_swapped(G_OBJECT(wd), "clicked", G_CALLBACK(onActionsCloseClicked), (gpointer)main); g_signal_connect_swapped(G_OBJECT(main->interactiveDialog), "delete-event", G_CALLBACK(onKillInteractiveDialog), (gpointer)main); g_signal_connect_swapped(G_OBJECT(main->interactiveDialog), "destroy-event", G_CALLBACK(onKillInteractiveDialog), (gpointer)main); } /* This method hides the specified window and save its coordinates if it is specified by a parameter. */ static void hideWindow(GtkWindow *win) { int *val; if (!win) return; if (my_class->rememberWindowPosition) { val = (int*)g_hash_table_lookup(my_class->windowPosition, win); if (!val) { val = g_malloc(sizeof(int) * 2); g_hash_table_insert(my_class->windowPosition, (gpointer)win, (gpointer)val); } gtk_window_get_position(win, &val[0], &val[1]); DBG_fprintf(stderr, "Gtk Main : store position (%d,%d) for window %d.\n", val[0], val[1], GPOINTER_TO_INT(win)); } gtk_widget_hide(GTK_WIDGET(win)); } /* This method shows the specified window and try to put it at its former position if the good parameter is used. */ static void showWindow(GtkWindow *win) { int *val; if (!win) return; if (my_class->rememberWindowPosition) { val = (int*)g_hash_table_lookup(my_class->windowPosition, win); if (val) { gtk_window_move(win, val[0], val[1]); DBG_fprintf(stderr, "Gtk Main : set position (%d,%d) for window %d.\n", val[0], val[1], GPOINTER_TO_INT(win)); } } gtk_window_present(win); } void onHideNextTime(GtkToggleButton *button, gpointer data) { char *posNext; gchar *path, *bufferR, *pos; GString *bufferW, *bufferW2; gboolean resOk; int lines; GIOChannel *file; GError *err; gsize taille; GIOStatus statOK; g_return_if_fail(data); path = (gchar*)data; DBG_fprintf(stderr, "Gtk Main : change the warning dialog parameter in file '%s'.\n", path); my_class->warningWhenQuit = !gtk_toggle_button_get_active(button); /* If no file exists in the given path, we create it. */ if (!g_file_test(path, G_FILE_TEST_EXISTS)) { err = (GError*)0; resOk = visu_config_file_save(VISU_CONFIG_FILE_PARAMETER, path, &lines, (VisuData*)0, &err); if (!resOk) { visu_ui_raiseWarningLong(_("Saving a file"), err->message, (GtkWindow*)0); g_error_free(err); } return; } /* If a parameter file already exist, we then just change the right line. */ bufferR = (gchar*)0; err = (GError*)0; if (!g_file_get_contents(path, &bufferR, &taille, &err)) { visu_ui_raiseWarningLong(_("Saving a file"), err->message, (GtkWindow*)0); g_error_free(err); return; } /* We reopen the channel in write acces. */ err = (GError*)0; file = g_io_channel_new_file(path, "w", &err); if (err) { visu_ui_raiseWarningLong(_("Saving a file"), err->message, (GtkWindow*)0); g_error_free(err); return; } g_return_if_fail(bufferR); bufferW = g_string_new(bufferR); g_free(bufferR); /* Try to find the flag of the parameter. */ pos = g_strrstr(bufferW->str, "\n"FLAG_PARAMETER_GTKMAIN_QUIT); if (!pos) { /* We append it at the end of the file. */ DBG_fprintf(stderr, " | Can't find the option, appending it.\n"); exportParametersVisuUiMain(bufferW, (VisuData*)0); err = (GError*)0; statOK = g_io_channel_write_chars(file, bufferW->str, -1, &taille, &err); if (statOK != G_IO_STATUS_NORMAL && err) { visu_ui_raiseWarningLong(_("Saving a file"), err->message, (GtkWindow*)0); g_error_free(err); } } else { DBG_fprintf(stderr, " | ToolOption found, changing its value.\n"); /* We erase the line and rewrite it. */ *(pos + 1) = '\0'; bufferW2 = g_string_new(bufferW->str); g_string_append_printf(bufferW2, "%s[gtk]: %i\n", FLAG_PARAMETER_GTKMAIN_QUIT, (int)my_class->warningWhenQuit); posNext = strstr(pos + 2, "\n"); if (posNext) g_string_append(bufferW2, posNext + 1); err = (GError*)0; statOK = g_io_channel_write_chars(file, bufferW2->str, -1, &taille, &err); if (err) { visu_ui_raiseWarningLong(_("Saving a file"), err->message, (GtkWindow*)0); g_error_free(err); } g_string_free(bufferW2, TRUE); } g_io_channel_shutdown(file, TRUE, (GError**)0); g_io_channel_unref(file); g_string_free(bufferW, TRUE); } static void onAddHomedir(GtkButton *button _U_, gpointer quitDialog) { GtkWidget *wd; GList *dirs, *tmplst; gchar *path; #if SYSTEM_X11 == 1 #define PERMS (S_IRWXU | S_IRGRP | S_IXGRP) #endif #if SYSTEM_WIN32 == 1 #define PERMS 0 #endif DBG_fprintf(stderr, "Gtk Main: try to create the local home directory.\n"); #if GLIB_MINOR_VERSION > 7 if (g_mkdir_with_parents(V_SIM_LOCAL_CONF_DIR, PERMS)) #else #if SYSTEM_X11 == 1 if (mkdir(V_SIM_LOCAL_CONF_DIR, PERMS)) #endif #if SYSTEM_WIN32 == 1 if (mkdir(V_SIM_LOCAL_CONF_DIR)) #endif #endif /* Failed. */ visu_ui_raiseWarning(_("I/O"), _("Can't create the directory '$XDG_CONFIG_HOME/v_sim'."), (GtkWindow*)0); else { /* Succeed hide the warning. */ wd = lookup_widget(GTK_WIDGET(quitDialog), "hboxHomedir"); gtk_widget_hide(wd); /* Retest the path. */ dirs = (GList*)0; dirs = g_list_prepend(dirs, (gpointer)V_SIM_DATA_DIR); dirs = g_list_prepend(dirs, (gpointer)V_SIM_LOCAL_CONF_DIR); tmplst = dirs; path = (gchar*)0; path = visu_config_file_getNextValidPath(VISU_CONFIG_FILE_PARAMETER, W_OK, &tmplst, 0); if (path) { wd = lookup_widget(GTK_WIDGET(quitDialog), "hboxWarning"); gtk_widget_hide(wd); wd = lookup_widget(GTK_WIDGET(quitDialog), "checkbuttonHideNextTime"); gtk_widget_set_sensitive(wd, TRUE); g_signal_connect(G_OBJECT(wd), "toggled", G_CALLBACK(onHideNextTime), (gpointer)path); } g_list_free(dirs); } } static void freeAllAndStop(VisuUiMain *main) { DBG_fprintf(stderr, "Gtk Main: kill command panel.\n"); gtk_widget_destroy(GTK_WIDGET(main)); visu_ui_rendering_window_class_finalize(); g_hash_table_destroy(my_class->windowPosition); DBG_fprintf(stderr, "Gtk Main: stopping GTK and that's all.\n"); gtk_main_quit(); } void visu_ui_main_quit(VisuUiMain *main, gboolean force) { GtkWidget *quitDialog, *wd; GList *dirs, *tmplst; gchar *path; if (force || !my_class->warningWhenQuit) { freeAllAndStop(main); return; } quitDialog = create_quitDialog(); gtk_window_set_transient_for(GTK_WINDOW(quitDialog), GTK_WINDOW(main)); /* Try to find installDir/v_sim.par or $XDG_CONFIG_HOME/v_sim/v_sim.par that is writable to store the preference of the hiding mode of the dialog. */ dirs = (GList*)0; dirs = g_list_prepend(dirs, (gpointer)V_SIM_DATA_DIR); dirs = g_list_prepend(dirs, (gpointer)V_SIM_LOCAL_CONF_DIR); tmplst = dirs; path = (gchar*)0; path = visu_config_file_getNextValidPath(VISU_CONFIG_FILE_PARAMETER, W_OK, &tmplst, 0); if (!path) { wd = lookup_widget(quitDialog, "hboxWarning"); gtk_widget_show(wd); } g_list_free(dirs); /* Attach a create the homedir method to the button. */ wd = lookup_widget(quitDialog, "buttonAddHomedir"); g_signal_connect(G_OBJECT(wd), "clicked", G_CALLBACK(onAddHomedir), (gpointer)quitDialog); /* Show the warning if the homedir is not existing and no path was found. */ if (!g_file_test(V_SIM_LOCAL_CONF_DIR, G_FILE_TEST_IS_DIR) && !path) { wd = lookup_widget(quitDialog, "hboxHomedir"); gtk_widget_show(wd); } /* Attach a modify the parameter to the checkbox. */ wd = lookup_widget(quitDialog, "checkbuttonHideNextTime"); if (!path) gtk_widget_set_sensitive(wd, FALSE); else g_signal_connect(G_OBJECT(wd), "toggled", G_CALLBACK(onHideNextTime), (gpointer)path); if (gtk_dialog_run(GTK_DIALOG(quitDialog)) == GTK_RESPONSE_OK) freeAllAndStop(main); else gtk_widget_destroy(quitDialog); } static gboolean readMainPanelStatus(VisuConfigFileEntry *entry _U_, gchar **lines, int nbLines, int position, GError **error) { gchar **tokens; VisuUiPanel *toolpanel; char *pt; g_return_val_if_fail(nbLines == 1, FALSE); if (!tool_config_file_readString(lines[0], position, &tokens, 2, TRUE, error)) return FALSE; toolpanel = visu_ui_panel_class_getPanelById(tokens[0]); if (toolpanel) { pt = strchr(tokens[1], '\n'); if (pt) *pt = ' '; visu_ui_panel_setContainerId(toolpanel, g_strchomp(tokens[1])); } g_strfreev(tokens); return TRUE; } static gboolean readMainDock(VisuConfigFileEntry *entry _U_, gchar **lines, int nbLines, int position, GError **error) { int res; gchar **tokens, *values; gboolean visible; int x, y, width, height; VisuUiDockWindow *dock; g_return_val_if_fail(nbLines == 1, FALSE); tokens = g_strsplit(g_strchug(lines[0]), " ", 4); if (!tokens[0] || !tokens[1] || !tokens[2] || !tokens[3]) { *error = g_error_new(TOOL_CONFIG_FILE_ERROR, TOOL_CONFIG_FILE_ERROR_VALUE, _("Parse error at line %d: awaited " "'id visible pos size'.\n"), position); g_strfreev(tokens); return FALSE; } values = g_strjoin(" ", tokens[0], tokens[1], tokens[2], NULL); res = sscanf(values, "%d %dx%d %dx%d", (int*)&visible, &x, &y, &width, &height); if (res != 5) { *error = g_error_new(TOOL_CONFIG_FILE_ERROR, TOOL_CONFIG_FILE_ERROR_VALUE, _("Parse error at line %d: can't read dock" " characteristic values from '%s'.\n"), position, values); g_strfreev(tokens); g_free(values); return FALSE; } g_free(values); /* Get the dock window associated to id, or create a new one. */ dock = visu_ui_panel_class_getDockById(g_strchomp(tokens[3])); visu_ui_dock_window_setSize(dock, (guint)width, (guint)height); visu_ui_dock_window_setPosition(dock, (guint)x, (guint)y); visu_ui_dock_window_setVisibility(dock, visible); g_strfreev(tokens); return TRUE; } static void exportParametersVisuUiMain(GString *data, VisuData* dataObj _U_) { GList *tmplst, *panelLst, *dockLst; gint x, y, width, height; gboolean visilibity; gchar *id; g_string_append_printf(data, "# %s\n", DESC_PARAMETER_GTKMAIN_QUIT); g_string_append_printf(data, "%s[gtk]: %i\n\n", FLAG_PARAMETER_GTKMAIN_QUIT, (int)my_class->warningWhenQuit); /* Write the panel list. */ panelLst = visu_ui_panel_class_getAllPanels(); if (panelLst) { g_string_append_printf(data, "# %s\n", DESC_PARAMETER_GTKMAIN_PANEL); for (tmplst = panelLst; tmplst; tmplst = g_list_next(tmplst)) g_string_append_printf(data, "%s[gtk]: %s %s\n", FLAG_PARAMETER_GTKMAIN_PANEL, visu_ui_panel_getId(VISU_UI_PANEL(tmplst->data)), visu_ui_panel_getContainerId(VISU_UI_PANEL(tmplst->data))); g_string_append_printf(data, "\n"); g_list_free(panelLst); } /* Write the panel list. */ dockLst = visu_ui_panel_class_getAllWindows(); if (dockLst) { g_string_append_printf(data, "# %s\n", DESC_PARAMETER_GTKMAIN_DOCK); for (tmplst = dockLst; tmplst; tmplst = g_list_next(tmplst)) { visu_ui_dock_window_getCharacteristics ((VisuUiDockWindow*)(tmplst->data), &id, &visilibity, &x, &y, &width, &height); g_string_append_printf(data, "%s[gtk]: %d %dx%d %dx%d %s\n", FLAG_PARAMETER_GTKMAIN_DOCK, (int)visilibity, x, y, width, height, id); } g_string_append_printf(data, "\n"); g_list_free(dockLst); } } gboolean visu_ui_main_initPanels(gpointer data) { GList *pnt; DBG_fprintf(stderr, "Gtk Main: initialise panels.\n"); for (pnt = visu_plugins_getListLoaded(); pnt; pnt = g_list_next(pnt)) visu_plugin_initGtk((VisuPlugin*)pnt->data); visu_ui_panel_browser_setCurrentDirectory(visu_ui_main_getLastOpenDirectory(VISU_UI_MAIN(data))); DBG_fprintf(stderr, " | done.\n"); return FALSE; } gboolean visu_ui_main_runCommandLine(gpointer data) { VisuUiMain *self; VisuGlNodeScene *scene; GError *error; self = VISU_UI_MAIN(data); scene = visu_ui_rendering_window_getGlScene(VISU_UI_RENDERING_WINDOW(self->renderingWindow)); if (!visu_gl_node_scene_getData(scene)) return G_SOURCE_REMOVE; error = (GError*)0; if (!visu_gl_node_scene_applyCLI(scene, &error)) { visu_ui_raiseWarning(_("Command line actions"), error ? error->message : _("Unknown error"), GTK_WINDOW(data)); g_clear_error(&error); } return G_SOURCE_REMOVE; } /*******************/ /* Class routines. */ /*******************/ /** * visu_ui_main_class_getCurrentPanel: * * This routine can be used to get the command panel, everywhere from * V_Sim. * * Returns: (transfer none): the command Panel. */ VisuUiMain* visu_ui_main_class_getCurrentPanel() { return currentVisuUiMain; } /** * visu_ui_main_class_setCurrentPanel: * @main: a command panel. * * After having created the command panel with visu_ui_main_new(), use this * routine to declare it as the current command panel. */ void visu_ui_main_class_setCurrentPanel(VisuUiMain *main) { g_return_if_fail(VISU_IS_UI_MAIN(main)); currentVisuUiMain = main; } void visu_ui_main_class_setRememberPosition(gboolean val) { g_return_if_fail(my_class); DBG_fprintf(stderr, "Gtk Main: set the remember parameter to %d.\n", val); my_class->rememberWindowPosition = val; } gboolean visu_ui_main_class_getRememberPosition() { g_return_val_if_fail(my_class, PARAMETER_GTKMAIN_REMEMBER_DEFAULT); return my_class->rememberWindowPosition; } /** * visu_ui_main_class_createMain: * @panel: a location for a #VisuUiMain panel ; * @renderWindow: a location for a #GtkWindow ; * @renderArea: a location for a #GtkWidget. * * A convenience routine to create a command panel, a rendering window * and links them together. */ void visu_ui_main_class_createMain(GtkWindow **panel, GtkWindow **renderWindow, GtkWidget **renderArea) { gboolean oneWindow; oneWindow = (!strcmp(commandLineGet_windowMode(), "oneWindow")); *panel = GTK_WINDOW(visu_ui_main_new(oneWindow)); *renderArea = GTK_WIDGET(VISU_UI_MAIN(*panel)->renderingWindow); DBG_fprintf(stderr, "Gtk Main: command panel -> %p.\n", (gpointer)(*panel)); if (!oneWindow) { *renderWindow = GTK_WINDOW(visu_ui_buildRenderingWindow(VISU_UI_RENDERING_WINDOW(*renderArea))); g_signal_connect(G_OBJECT(*renderWindow), "delete-event", G_CALLBACK(onKillMainWindowEvent), (gpointer)(*panel)); g_signal_connect(G_OBJECT(*renderWindow), "destroy-event", G_CALLBACK(onKillMainWindowEvent), (gpointer)(*panel)); gtk_widget_show(GTK_WIDGET(*renderWindow)); } else *renderWindow = *panel; g_object_bind_property(*renderArea, "label", *renderWindow, "title", G_BINDING_SYNC_CREATE); visu_ui_interactive_pick_init(); g_type_class_ref(visu_ui_shade_combobox_get_type()); gtk_widget_show(GTK_WIDGET(*panel)); return; } /** * visu_ui_main_class_getDefaultRendering: * * Get the rendering window of V_Sim. * * Returns: (transfer none): the rendering window. */ VisuUiRenderingWindow* visu_ui_main_class_getDefaultRendering() { g_return_val_if_fail(currentVisuUiMain, (VisuUiRenderingWindow*)0); DBG_fprintf(stderr, "Gtk Main: access the rendering window %p.\n", (gpointer)currentVisuUiMain->renderingWindow); return VISU_UI_RENDERING_WINDOW(currentVisuUiMain->renderingWindow); } v_sim-3.8.0/src/gtk_main.h000066400000000000000000000203751370110300500153650ustar00rootroot00000000000000/* EXTRAITS DE LA LICENCE Copyright CEA, contributeurs : Luc BILLARD et Damien CALISTE, laboratoire L_Sim, (2001-2005) Adresse mèl : BILLARD, non joignable par mèl ; CALISTE, damien P caliste AT cea P fr. Ce logiciel est un programme informatique servant à visualiser des structures atomiques dans un rendu pseudo-3D. Ce logiciel est régi par la licence CeCILL soumise au droit français et respectant les principes de diffusion des logiciels libres. Vous pouvez utiliser, modifier et/ou redistribuer ce programme sous les conditions de la licence CeCILL telle que diffusée par le CEA, le CNRS et l'INRIA sur le site "http://www.cecill.info". Le fait que vous puissiez accéder à cet en-tête signifie que vous avez pris connaissance de la licence CeCILL, et que vous en avez accepté les termes (cf. le fichier Documentation/licence.fr.txt fourni avec ce logiciel). */ /* LICENCE SUM UP Copyright CEA, contributors : Luc BILLARD et Damien CALISTE, laboratoire L_Sim, (2001-2005) E-mail address: BILLARD, not reachable any more ; CALISTE, damien P caliste AT cea P fr. This software is a computer program whose purpose is to visualize atomic configurations in 3D. This software is governed by the CeCILL license under French law and abiding by the rules of distribution of free software. You can use, modify and/ or redistribute the software under the terms of the CeCILL license as circulated by CEA, CNRS and INRIA at the following URL "http://www.cecill.info". The fact that you are presently reading this means that you have had knowledge of the CeCILL license and that you accept its terms. You can find a copy of this licence shipped with this software at Documentation/licence.en.txt. */ #ifndef VISU_PUBLIC_H #define VISU_PUBLIC_H #include #include #include #include "visu_tools.h" #include "visu_dump.h" #include "extraGtkFunctions/gtk_toolPanelWidget.h" #include "gtk_renderingWindowWidget.h" /** * VISU_TYPE_UI_MAIN: * * return the type of #VisuUiMain. */ #define VISU_TYPE_UI_MAIN (visu_ui_main_get_type ()) /** * VISU_UI_MAIN: * @obj: a #GObject to cast. * * Cast the given @obj into #VisuUiMain type. */ #define VISU_UI_MAIN(obj) (G_TYPE_CHECK_INSTANCE_CAST(obj, VISU_TYPE_UI_MAIN, VisuUiMain)) /** * VISU_UI_MAIN_CLASS: * @klass: a #GObjectClass to cast. * * Cast the given @klass into #VisuUiMainClass. */ #define VISU_UI_MAIN_CLASS(klass) (G_TYPE_CHECK_CLASS_CAST(klass, VISU_TYPE_UI_MAIN, VisuUiMainClass)) /** * VISU_IS_UI_MAIN: * @obj: a #GObject to test. * * Test if the given @ogj is of the type of #VisuUiMain object. */ #define VISU_IS_UI_MAIN(obj) (G_TYPE_CHECK_INSTANCE_TYPE(obj, VISU_TYPE_UI_MAIN)) /** * VISU_IS_UI_MAIN_CLASS: * @klass: a #GObjectClass to test. * * Test if the given @klass is of the type of #VisuUiMainClass class. */ #define VISU_IS_UI_MAIN_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE(klass, VISU_TYPE_UI_MAIN)) /** * VISU_UI_MAIN_GET_CLASS: * @obj: a #GObject to get the class of. * * It returns the class of the given @obj. */ #define VISU_UI_MAIN_GET_CLASS(obj) (G_TYPE_INSTANCE_GET_CLASS(obj, VISU_TYPE_UI_MAIN, VisuUiMainClass)) /** * VisuUiMain_private: * * Private fields for #VisuUiMain objects. */ typedef struct _VisuUiMainPrivate VisuUiMainPrivate; /** * _VisuUiMain: * @parent: the parent object, a #GtkWindow here ; * @renderingWindow: a pointer on the associated rendering window ; * @pairsDialog: a pointer to the corresponding pair dialog, or NULL * if not yet built ; * @interactiveDialog: idem for the interactive dialog ; * @aboutDialog: idem for the about dialog ; * @private: a pointer to the private data. * * This structure describes a #VisuUiMain object. */ typedef struct _VisuUiMain VisuUiMain; struct _VisuUiMain { GtkWindow parent; /* Pointers on permanent windows. */ GtkWidget *renderingWindow; GtkWidget *pairsDialog; GtkWidget *interactiveDialog; GtkWidget *aboutDialog; /* Private data. */ VisuUiMainPrivate *priv; }; /** * VisuUiMainClass: * * A short way to identify #_VisuUiMainClass structure. */ typedef struct _VisuUiMainClass VisuUiMainClass; /** * visu_ui_main_get_type: * * This method returns the type of #VisuUiMain, use VISU_TYPE_UI_MAIN instead. * * Returns: the type of #VisuUiMain. */ GType visu_ui_main_get_type(void); /** * VisuUiMainInitFunc: * @ui: the #VisuUiMain object. * * These methods are used by V_Sim to initialise some part of the * interface. They are called once on start-up. * * Since: 3.8 */ typedef void (*VisuUiMainInitFunc)(VisuUiMain *ui); /** * visu_ui_main_new: * @oneWindow: a boolean. * * Create the command panel window and is dependencies, such as the * associated rendering window... WARNING: some part are still currently * static, so only once instance can be created at a time. If * @oneWindow argument is TRUE, then the rendering area is creating in * the same #GtkWindow on the right of the panel. * * Returns: a newly create command panel. */ GtkWidget* visu_ui_main_new(gboolean oneWindow); /** * visu_ui_main_quit: * @main: a pointer to the main interface. * @force: if TRUE, override the preference of a quiting dialog and quit. * * Quit the program. If the preference to have a confirm dialog is set, * then it raises the little warning window before quiting (or not). */ void visu_ui_main_quit(VisuUiMain *main, gboolean force); /** * visu_ui_main_buildInteractiveDialog: * @main: a #VisuUiMain object. * * Create the mouse action dialog window (if not already done). */ void visu_ui_main_buildInteractiveDialog(VisuUiMain *main); /** * visu_ui_main_runCommandLine: * @data: a pointer on a #VisuUiMain object. * * Call the get routines from the command line module and associate * the different tasks to the different panels. For a version that do * not use the panels, call visu_ui_runCommandLine() instead. * * Returns: always FALSE. */ gboolean visu_ui_main_runCommandLine(gpointer data); /** * visu_ui_main_initPanels: * @data: a pointer on a #VisuUiMain object. * * Call the init routines for the different panels. * * Returns: always FALSE. */ gboolean visu_ui_main_initPanels(gpointer data); VisuUiRenderingWindow* visu_ui_main_getRendering(VisuUiMain *main); /** * visu_ui_main_class_setRememberPosition: * @val: an boolean. * * V_Sim can try to remember the position of its main windows, then * open them again will result in a positioning on screen equivalent * to previous position. */ void visu_ui_main_class_setRememberPosition(gboolean val); /** * visu_ui_main_class_getRememberPosition: * * V_Sim can store the position of its main windows. Use this routine * to get the status of this capability. * * Returns: TRUE if set. */ gboolean visu_ui_main_class_getRememberPosition(); /** * VisuUiDirectoryType: * @VISU_UI_DIR_FILE: default kind of directory ; * @VISU_UI_DIR_SURFACE: directory for surfaces ; * @VISU_UI_DIR_DATAFILE: directory for data files ; * @VISU_UI_DIR_CONF: directory for configuration files ; * @VISU_UI_DIR_BROWSER: directory used in the browser. * @VISU_UI_DIR_N_VALUES: private. * * V_Sim remembers the last open directory when presenting a new file * selector. This enum is used to specify different kind of * directories. Like that saving a configuration file in a given * directory will not affect the prefered directory for browsing a * list of files. */ typedef enum { VISU_UI_DIR_FILE, VISU_UI_DIR_SURFACE, VISU_UI_DIR_DATAFILE, VISU_UI_DIR_CONF, VISU_UI_DIR_BROWSER, /*< private >*/ VISU_UI_DIR_N_VALUES } VisuUiDirectoryType; const gchar* visu_ui_main_getLastOpenDirectory(VisuUiMain *main); void visu_ui_main_setLastOpenDirectory(VisuUiMain *main, const char* directory, VisuUiDirectoryType type); gchar** visu_ui_main_getSelectedDirectory(VisuUiMain *main, GtkWindow *parent, gboolean multiple, const gchar *dir); VisuUiMain* visu_ui_main_class_getCurrentPanel(); void visu_ui_main_class_setCurrentPanel(VisuUiMain *main); void visu_ui_main_class_createMain(GtkWindow **panel, GtkWindow **renderWindow, GtkWidget **renderArea); VisuUiRenderingWindow* visu_ui_main_class_getDefaultRendering(); #endif v_sim-3.8.0/src/gtk_move.c000066400000000000000000001213321370110300500153750ustar00rootroot00000000000000/* EXTRAITS DE LA LICENCE Copyright CEA, contributeurs : Luc BILLARD et Damien CALISTE, laboratoire L_Sim, (2001-2005) Adresse mèl : BILLARD, non joignable par mèl ; CALISTE, damien P caliste AT cea P fr. Ce logiciel est un programme informatique servant à visualiser des structures atomiques dans un rendu pseudo-3D. Ce logiciel est régi par la licence CeCILL soumise au droit français et respectant les principes de diffusion des logiciels libres. Vous pouvez utiliser, modifier et/ou redistribuer ce programme sous les conditions de la licence CeCILL telle que diffusée par le CEA, le CNRS et l'INRIA sur le site "http://www.cecill.info". Le fait que vous puissiez accéder à cet en-tête signifie que vous avez pris connaissance de la licence CeCILL, et que vous en avez accepté les termes (cf. le fichier Documentation/licence.fr.txt fourni avec ce logiciel). */ /* LICENCE SUM UP Copyright CEA, contributors : Luc BILLARD et Damien CALISTE, laboratoire L_Sim, (2001-2005) E-mail address: BILLARD, not reachable any more ; CALISTE, damien P caliste AT cea P fr. This software is a computer program whose purpose is to visualize atomic configurations in 3D. This software is governed by the CeCILL license under French law and abiding by the rules of distribution of free software. You can use, modify and/ or redistribute the software under the terms of the CeCILL license as circulated by CEA, CNRS and INRIA at the following URL "http://www.cecill.info". The fact that you are presently reading this means that you have had knowledge of the CeCILL license and that you accept its terms. You can find a copy of this licence shipped with this software at Documentation/licence.en.txt. */ #include "math.h" #include "support.h" #include "interface.h" #include "gtk_main.h" #include "gtk_move.h" #include "gtk_pick.h" #include "gtk_interactive.h" #include "gtk_renderingWindowWidget.h" #include "openGLFunctions/interactive.h" #include "extensions/marks.h" #include "extraFunctions/plane.h" #include "extraFunctions/translate.h" #include "extraGtkFunctions/gtk_numericalEntryWidget.h" #include "extraGtkFunctions/gtk_elementComboBox.h" #include "coreTools/toolMatrix.h" #include "extensions/box.h" /** * SECTION: gtk_move * @short_description: The move tab in the interactive dialog. * * This action tab provides widgets to move single or group of * atoms. It provides also widgets to remove or add atoms. And finally * it provides a way to change the basis-set by picking atoms to form * vertices of a new basis-set. */ /* Callbacks. */ static void refreshMoveAxesValues(VisuGlView *view); static void onAxeChoosen(VisuUiNumericalEntry *entry, double oldValue, gpointer data); static void onRemoveNodeClicked(GtkButton *button, gpointer user_data); static void onAddNodeClicked(GtkButton *button, gpointer user_data); static void onMoveMethod(GtkToggleButton *toggle, gpointer data); static void onDuplicate(GtkButton *button, gpointer data); static void onMoveToggled(GtkToggleButton *toggle, gpointer data); static void onSpinBasis(GtkSpinButton *spin, gpointer data); static gboolean removeHighlight(gpointer data); static void onChooseBasis(GtkToggleButton *toggle, gpointer data); static void onBasisSelected(VisuInteractive *inter, VisuInteractivePick pick, VisuData *dataObj, VisuNode *nodes0, VisuNode *node1, VisuNode *node2, gpointer data); static void onApplyBasis(GtkButton *button, gpointer data); static void _setDataModel(VisuData *dataObj); static void _setSpinRange(VisuData *dataObj); static void onPositionChanged(VisuData *dataObj, GArray *ids, gpointer data); static void onStartMove(VisuInteractive *inter, GArray* nodeIds, gpointer data); static void onGetAxisClicked(VisuGlView *view, GtkButton *button); static void onPickClickStop(VisuInteractive *inter, gpointer data); /* Local methods. */ static void setLabelsOrigin(VisuData *data, GArray *nodeIds); static void drawBasisCell(VisuBox *box, float O[3], float mat[3][3]); #define GTK_MOVE_INFO \ _("left-button\t\t\t\t: drag node(s) in the screen plane\n" \ "middle-button (wheel)\t\t: drag node(s) along specific axis\n" \ "shift-left-button\t\t\t: drag node(s) along x axis\n" \ "control-left-button\t\t\t: drag node(s) along y axis\n" \ "control-shift-left-button\t: drag node(s) along z axis\n" \ "right-button\t\t\t\t: switch to observe") /* Pick informations hook */ static VisuInteractive *interPick = NULL, *interMove = NULL; static int movedNode = -1; static float moveNodeOrigin[3]; #define GTK_MOVE_NO_NODE _("(none)") static gulong onSpin_id[4]; static VisuInteractiveId currentMode = interactive_move; static guint currentAxe; static VisuData *_dataModel = NULL; static gulong popInc_signal, popDec_signal, popChg_signal; static VisuNodeMoverTranslation *translator = NULL; /* Widgets */ static GtkWidget *notebookAction; static GtkWidget *observeWindow; static GtkWidget *entryAddXYZ[3]; static GtkWidget *entryAxeXYZ[3]; static GtkWidget *removeButton; static GtkWidget *comboElements; static GtkWidget *radioMovePick, *radioMoveRegion; enum { COLUMN_NAME, /* The label shown */ COLUMN_POINTER_TO_DATA, /* Pointer to the VisuElement. */ N_COLUMNS }; static GtkWidget *checkDuplicate, *comboDuplicate, *buttonDupplicate; static GtkWidget *labelOriginX, *labelOriginY, *labelOriginZ; static GtkWidget *labelScreenHorizontal, *labelScreenVertical; static GtkWidget *spinABC[4], *toggleABC[4], *applyBasis; static gchar *lblSpinABC[4] = {"orig.:", "X:", "Y:", "Z:"}; static gint prevBasis[4] = {0, 0, 0, 0}; static guint timeoutBasis[4]; static VisuGlExtBox *extBasis; /********************/ /* Public routines. */ /********************/ static gboolean toValue(GBinding *binding _U_, const GValue *from_value, GValue *to_value, gpointer user_data) { gfloat *delta = (gfloat*)g_value_get_boxed(from_value); g_return_val_if_fail(delta, FALSE); DBG_fprintf(stderr, "Gtk Move: set entry %d to %g.\n", GPOINTER_TO_INT(user_data), delta[GPOINTER_TO_INT(user_data)]); g_value_set_double(to_value, delta[GPOINTER_TO_INT(user_data)]); return TRUE; } static gboolean fromValue(GBinding *binding, const GValue *from_value, GValue *to_value, gpointer user_data) { gfloat delta[3]; visu_node_mover_translation_get(VISU_NODE_MOVER_TRANSLATION(g_binding_get_source(binding)), delta); delta[GPOINTER_TO_INT(user_data)] = g_value_get_double(from_value); g_value_set_boxed(to_value, delta); return TRUE; } static gboolean toNMoves(GBinding *binding _U_, const GValue *from_value, GValue *to_value, gpointer user_data _U_) { GArray *ids = (GArray*)g_value_get_boxed(from_value); gchar numero[128]; if (!ids || !ids->len) g_value_set_static_string(to_value, GTK_MOVE_NO_NODE); else if (ids->len == 1) { sprintf(numero, _("(node %d)"), g_array_index(ids, guint, 0) + 1); g_value_set_string(to_value, numero); } else { sprintf(numero, _("(%d nodes)"), ids->len); g_value_set_string(to_value, numero); } return TRUE; } static gboolean toDupSensitive(GBinding *binding _U_, const GValue *from_value, GValue *to_value, gpointer user_data _U_) { GArray *ids = (GArray*)g_value_get_boxed(from_value); g_value_set_boolean(to_value, (ids && ids->len)); return TRUE; } /** * visu_ui_interactive_move_initBuild: (skip) * @main: the main interface. * @label: a location to store the name of the move tab ; * @help: a location to store the help message to be shown at the * bottom of the window ; * @radio: a location on the radio button that will be toggled when * the move action is used. * * This routine should be called in conjonction to the * visu_ui_interactive_pick_initBuild() one. It completes the creation of widgets * (and also initialisation of values) for the move tab. */ GtkWidget* visu_ui_interactive_move_initBuild(VisuUiMain *main, gchar **label, gchar **help, GtkWidget **radio) { GtkWidget *wd, *hbox, *vbox, *bt, *lbl; VisuData *data; VisuGlView *view; VisuNodeArrayIter dataIter; guint i, idmax; VisuGlNodeScene *scene; GtkWidget *entryMoveXYZ[3], *cancelButton; #if GTK_MAJOR_VERSION == 2 && GTK_MINOR_VERSION < 12 GtkTooltips *tooltips; tooltips = gtk_tooltips_new (); #endif scene = visu_ui_rendering_window_getGlScene(visu_ui_main_class_getDefaultRendering()); extBasis = visu_gl_ext_box_new("New basis set highlight"); visu_gl_ext_lined_setWidth(VISU_GL_EXT_LINED(extBasis), 1.f); visu_gl_ext_lined_setStipple(VISU_GL_EXT_LINED(extBasis), 57568); visu_gl_ext_box_setExpandStipple(extBasis, 57568); visu_gl_ext_setActive(VISU_GL_EXT(extBasis), FALSE); visu_gl_ext_set_add(VISU_GL_EXT_SET(scene), VISU_GL_EXT(extBasis)); *label = g_strdup("Pick"); *help = g_strdup(GTK_MOVE_INFO); *radio = lookup_widget(main->interactiveDialog, "radioMove"); g_signal_connect(G_OBJECT(*radio), "toggled", G_CALLBACK(onMoveToggled), (gpointer)main->interactiveDialog); view = visu_gl_node_scene_getGlView(scene); data = visu_gl_node_scene_getData(scene); if (data) { visu_node_array_iter_new(VISU_NODE_ARRAY(data), &dataIter); idmax = dataIter.idMax + 1; } else idmax = 1; /* The node movers. */ translator = visu_node_mover_translation_new(); visu_gl_node_scene_addMover(scene, VISU_NODE_MOVER(translator)); /* We create here the two interactives. */ interMove = visu_interactive_new(interactive_move); g_signal_connect(G_OBJECT(interMove), "start-move", G_CALLBACK(onStartMove), (gpointer)scene); g_signal_connect_swapped(G_OBJECT(interMove), "move", G_CALLBACK(visu_node_mover_translation_add), (gpointer)translator); g_signal_connect_swapped(G_OBJECT(interMove), "stop-move", G_CALLBACK(visu_node_mover_push), (gpointer)translator); g_signal_connect(G_OBJECT(interMove), "stop", G_CALLBACK(visu_ui_interactive_toggle), (gpointer)0); interPick = visu_interactive_new(interactive_pick); visu_interactive_setMessage(interPick, _("Pick a node with the mouse")); g_signal_connect(G_OBJECT(interPick), "node-selection", G_CALLBACK(onBasisSelected), (gpointer)0); g_signal_connect(G_OBJECT(interPick), "stop", G_CALLBACK(onPickClickStop), (gpointer)0); observeWindow = main->interactiveDialog; vbox = lookup_widget(main->interactiveDialog, "vbox21"); notebookAction = lookup_widget(main->interactiveDialog, "notebookAction"); /* The move node action. */ removeButton = gtk_button_new(); gtk_box_pack_end(GTK_BOX(lookup_widget(main->interactiveDialog, "hbox72")), removeButton, FALSE, FALSE, 0); gtk_widget_set_tooltip_text(removeButton, _("Suppress node (either picked one or selected ones).")); gtk_container_add(GTK_CONTAINER(removeButton), gtk_image_new_from_icon_name("list-remove", GTK_ICON_SIZE_MENU)); g_signal_connect(G_OBJECT(removeButton), "clicked", G_CALLBACK(onRemoveNodeClicked), (gpointer)0); gtk_widget_show_all(removeButton); lbl = lookup_widget(main->interactiveDialog, "labelNMoves"); gtk_label_set_use_markup(GTK_LABEL(lbl), TRUE); g_object_bind_property_full(visu_ui_interactive_pick_getSelection(), "selection", lbl, "label", G_BINDING_SYNC_CREATE, toNMoves, NULL, (gpointer)0, (GDestroyNotify)0); radioMovePick = lookup_widget(main->interactiveDialog, "radioMovePick"); gtk_widget_set_name(radioMovePick, "message_radio"); radioMoveRegion = lookup_widget(main->interactiveDialog, "radioMoveRegion"); gtk_widget_set_name(radioMoveRegion, "message_radio"); labelOriginX = lookup_widget(main->interactiveDialog, "labelOriginalX"); labelOriginY = lookup_widget(main->interactiveDialog, "labelOriginalY"); labelOriginZ = lookup_widget(main->interactiveDialog, "labelOriginalZ"); labelScreenHorizontal = lookup_widget(main->interactiveDialog, "labelHorizontalAxe"); labelScreenVertical = lookup_widget(main->interactiveDialog, "labelVerticalAxe"); g_signal_connect_object(G_OBJECT(view), "notify::theta", G_CALLBACK(refreshMoveAxesValues), labelScreenHorizontal, 0); g_signal_connect_object(G_OBJECT(view), "notify::phi", G_CALLBACK(refreshMoveAxesValues), labelScreenHorizontal, 0); g_signal_connect_object(G_OBJECT(view), "notify::omega", G_CALLBACK(refreshMoveAxesValues), labelScreenHorizontal, 0); wd = lookup_widget(main->interactiveDialog, "tableMovePick"); entryMoveXYZ[0] = visu_ui_numerical_entry_new(0.); gtk_entry_set_width_chars(GTK_ENTRY(entryMoveXYZ[0]), 8); gtk_grid_attach(GTK_GRID(wd), entryMoveXYZ[0], 1, 2, 1, 1); g_object_bind_property_full(translator, "translation", entryMoveXYZ[0], "value", G_BINDING_SYNC_CREATE | G_BINDING_BIDIRECTIONAL, toValue, fromValue, GINT_TO_POINTER(0), (GDestroyNotify)0); entryMoveXYZ[1] = visu_ui_numerical_entry_new(0.); gtk_entry_set_width_chars(GTK_ENTRY(entryMoveXYZ[1]), 8); gtk_grid_attach(GTK_GRID(wd), entryMoveXYZ[1], 3, 2, 1, 1); g_object_bind_property_full(translator, "translation", entryMoveXYZ[1], "value", G_BINDING_SYNC_CREATE | G_BINDING_BIDIRECTIONAL, toValue, fromValue, GINT_TO_POINTER(1), (GDestroyNotify)0); entryMoveXYZ[2] = visu_ui_numerical_entry_new(0.); gtk_entry_set_width_chars(GTK_ENTRY(entryMoveXYZ[2]), 8); gtk_grid_attach(GTK_GRID(wd), entryMoveXYZ[2], 5, 2, 1, 1); g_object_bind_property_full(translator, "translation", entryMoveXYZ[2], "value", G_BINDING_SYNC_CREATE | G_BINDING_BIDIRECTIONAL, toValue, fromValue, GINT_TO_POINTER(2), (GDestroyNotify)0); entryAxeXYZ[0] = visu_ui_numerical_entry_new(0.); gtk_entry_set_width_chars(GTK_ENTRY(entryAxeXYZ[0]), 8); gtk_grid_attach(GTK_GRID(wd), entryAxeXYZ[0], 1, 1, 1, 1); entryAxeXYZ[1] = visu_ui_numerical_entry_new(0.); gtk_entry_set_width_chars(GTK_ENTRY(entryAxeXYZ[1]), 8); gtk_grid_attach(GTK_GRID(wd), entryAxeXYZ[1], 3, 1, 1, 1); entryAxeXYZ[2] = visu_ui_numerical_entry_new(0.); gtk_entry_set_width_chars(GTK_ENTRY(entryAxeXYZ[2]), 8); gtk_grid_attach(GTK_GRID(wd), entryAxeXYZ[2], 5, 1, 1, 1); bt = gtk_button_new(); gtk_grid_attach(GTK_GRID(wd), bt, 7, 1, 1, 1); gtk_widget_set_tooltip_text(bt, _("Capture the perpendicular axis to the current view.")); gtk_container_add(GTK_CONTAINER(bt), gtk_image_new_from_icon_name("zoom-fit-best", GTK_ICON_SIZE_MENU)); g_signal_connect_swapped(G_OBJECT(bt), "clicked", G_CALLBACK(onGetAxisClicked), (gpointer)view); hbox = gtk_hbox_new(FALSE, 0); gtk_grid_attach(GTK_GRID(wd), hbox, 7, 2, 1, 1); cancelButton = gtk_button_new(); gtk_box_pack_start(GTK_BOX(hbox), cancelButton, FALSE, FALSE, 0); gtk_widget_set_tooltip_text(cancelButton, _("Apply translation values to coordinates.")); gtk_container_add(GTK_CONTAINER(cancelButton), gtk_image_new_from_icon_name("edit-redo", GTK_ICON_SIZE_MENU)); g_signal_connect_swapped(G_OBJECT(cancelButton), "clicked", G_CALLBACK(visu_node_mover_animate), translator); g_object_bind_property(translator, "valid", cancelButton, "sensitive", G_BINDING_SYNC_CREATE); cancelButton = gtk_button_new(); gtk_box_pack_start(GTK_BOX(hbox), cancelButton, FALSE, FALSE, 0); gtk_widget_set_tooltip_text(cancelButton, _("Return coordinates to initial values.")); gtk_container_add(GTK_CONTAINER(cancelButton), gtk_image_new_from_icon_name("edit-undo", GTK_ICON_SIZE_MENU)); g_signal_connect_swapped(G_OBJECT(cancelButton), "clicked", G_CALLBACK(visu_node_mover_undo), translator); g_object_bind_property(translator, "undo-stack-depth", cancelButton, "sensitive", G_BINDING_SYNC_CREATE); gtk_widget_show_all(wd); /* The add line. */ wd = lookup_widget(main->interactiveDialog, "hboxAddNode"); entryAddXYZ[0] = visu_ui_numerical_entry_new(0.); gtk_entry_set_width_chars(GTK_ENTRY(entryAddXYZ[0]), 6); gtk_box_pack_start(GTK_BOX(wd), entryAddXYZ[0], FALSE, FALSE, 0); entryAddXYZ[1] = visu_ui_numerical_entry_new(0.); gtk_entry_set_width_chars(GTK_ENTRY(entryAddXYZ[1]), 6); gtk_box_pack_start(GTK_BOX(wd), entryAddXYZ[1], FALSE, FALSE, 0); entryAddXYZ[2] = visu_ui_numerical_entry_new(0.); gtk_entry_set_width_chars(GTK_ENTRY(entryAddXYZ[2]), 6); gtk_box_pack_start(GTK_BOX(wd), entryAddXYZ[2], FALSE, FALSE, 0); /* We create the structure that store the VisuElements */ comboElements = visu_ui_element_combobox_new(FALSE, FALSE, (const gchar*)0); g_object_bind_property(scene, "data", comboElements, "nodes", G_BINDING_SYNC_CREATE); gtk_box_pack_start(GTK_BOX(wd), comboElements, FALSE, FALSE, 0); gtk_box_reorder_child(GTK_BOX(wd), comboElements, 0); bt = gtk_button_new(); gtk_box_pack_end(GTK_BOX(wd), bt, FALSE, FALSE, 0); gtk_widget_set_tooltip_text(bt, _("Add a new node.")); gtk_container_add(GTK_CONTAINER(bt), gtk_image_new_from_icon_name("list-add", GTK_ICON_SIZE_MENU)); g_signal_connect(G_OBJECT(bt), "clicked", G_CALLBACK(onAddNodeClicked), (gpointer)0); gtk_widget_show_all(wd); /* The duplicate line. */ hbox = gtk_hbox_new(FALSE, 0); gtk_box_pack_start(GTK_BOX(vbox), hbox, FALSE, FALSE, 5); wd = gtk_label_new(_("Duplicate nodes:")); gtk_label_set_use_markup(GTK_LABEL(wd), TRUE); gtk_label_set_xalign(GTK_LABEL(wd), 0.); gtk_box_pack_start(GTK_BOX(hbox), wd, TRUE, TRUE, 0); wd = gtk_label_new(_("(the nodes listed in the pick tab)")); gtk_label_set_use_markup(GTK_LABEL(wd), TRUE); gtk_box_pack_start(GTK_BOX(hbox), wd, FALSE, FALSE, 0); gtk_widget_show_all(hbox); hbox = gtk_hbox_new(FALSE, 0); g_object_bind_property_full(visu_ui_interactive_pick_getSelection(), "selection", hbox, "sensitive", G_BINDING_SYNC_CREATE, toDupSensitive, NULL, (gpointer)0, (GDestroyNotify)0); gtk_box_pack_start(GTK_BOX(vbox), hbox, FALSE, FALSE, 0); wd = gtk_check_button_new_with_mnemonic(_("du_plicate nodes as they are")); gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON(wd), TRUE); gtk_box_pack_start(GTK_BOX(hbox), wd, FALSE, FALSE, 0); checkDuplicate = wd; wd = gtk_label_new(_(" or as new: ")); gtk_label_set_use_markup(GTK_LABEL(wd), TRUE); gtk_box_pack_start(GTK_BOX(hbox), wd, FALSE, FALSE, 0); wd = visu_ui_element_combobox_new(FALSE, FALSE, (const gchar*)0); g_object_bind_property(scene, "data", wd, "nodes", G_BINDING_SYNC_CREATE); g_object_bind_property(checkDuplicate, "active", wd, "sensitive", G_BINDING_SYNC_CREATE | G_BINDING_INVERT_BOOLEAN); comboDuplicate = wd; gtk_box_pack_start(GTK_BOX(hbox), wd, FALSE, FALSE, 0); wd = gtk_button_new_with_mnemonic(_("_duplicate")); gtk_box_pack_end(GTK_BOX(hbox), wd, FALSE, FALSE, 0); buttonDupplicate = wd; gtk_widget_show_all(hbox); /* The Basis line. */ hbox = gtk_hbox_new(FALSE, 0); gtk_box_pack_start(GTK_BOX(vbox), hbox, FALSE, FALSE, 5); wd = gtk_label_new(_("Change the basis set:")); gtk_label_set_use_markup(GTK_LABEL(wd), TRUE); gtk_label_set_xalign(GTK_LABEL(wd), 0.); gtk_box_pack_start(GTK_BOX(hbox), wd, FALSE, FALSE, 0); gtk_widget_show_all(hbox); hbox = gtk_hbox_new(FALSE, 0); gtk_box_pack_start(GTK_BOX(vbox), hbox, FALSE, FALSE, 0); for (i = 0; i < 4; i++) { /* if (i == 1) */ /* { */ /* gtk_widget_show_all(hbox); */ /* hbox = gtk_hbox_new(FALSE, 0); */ /* gtk_box_pack_start(GTK_BOX(vbox), hbox, FALSE, FALSE, 0); */ /* } */ wd = gtk_label_new(_(lblSpinABC[i])); gtk_label_set_xalign(GTK_LABEL(wd), 1.); gtk_box_pack_start(GTK_BOX(hbox), wd, TRUE, TRUE, 5); spinABC[i] = gtk_spin_button_new_with_range(0, idmax, 1); onSpin_id[i] = g_signal_connect(G_OBJECT(spinABC[i]), "value-changed", G_CALLBACK(onSpinBasis), GINT_TO_POINTER(i)); gtk_box_pack_start(GTK_BOX(hbox), spinABC[i], FALSE, FALSE, 0); toggleABC[i] = gtk_toggle_button_new(); gtk_button_set_relief(GTK_BUTTON(toggleABC[i]), GTK_RELIEF_NONE); gtk_box_pack_start(GTK_BOX(hbox), toggleABC[i], FALSE, FALSE, 0); gtk_container_add(GTK_CONTAINER(toggleABC[i]), gtk_image_new_from_icon_name("edit-find", GTK_ICON_SIZE_MENU)); gtk_widget_set_tooltip_text(toggleABC[i], _("Select node by picking it on the rendering area.")); g_signal_connect(G_OBJECT(toggleABC[i]), "toggled", G_CALLBACK(onChooseBasis), GINT_TO_POINTER(i)); } applyBasis = gtk_button_new_with_mnemonic(_("_Apply")); gtk_box_pack_start(GTK_BOX(hbox), applyBasis, FALSE, FALSE, 0); gtk_widget_set_sensitive(applyBasis, FALSE); g_signal_connect(G_OBJECT(applyBasis), "clicked", G_CALLBACK(onApplyBasis), (gpointer)0); gtk_widget_show_all(hbox); if (data) _setDataModel(data); for (i = 0; i < 3; i++) { g_signal_connect(G_OBJECT(entryAxeXYZ[i]), "value-changed", G_CALLBACK(onAxeChoosen), (gpointer)0); } wd = lookup_widget(main->interactiveDialog, "radioMovePick"); g_signal_connect(G_OBJECT(wd), "toggled", G_CALLBACK(onMoveMethod), (gpointer)0); wd = lookup_widget(main->interactiveDialog, "radioMoveRegion"); g_signal_connect(G_OBJECT(wd), "toggled", G_CALLBACK(onMoveMethod), (gpointer)0); g_signal_connect(G_OBJECT(buttonDupplicate), "clicked", G_CALLBACK(onDuplicate), (gpointer)0); g_signal_connect_swapped(hbox, "destroy", G_CALLBACK(_setDataModel), (gpointer)0); g_signal_connect_swapped(hbox, "destroy", G_CALLBACK(g_object_unref), extBasis); g_signal_connect_swapped(hbox, "destroy", G_CALLBACK(g_object_unref), interMove); g_signal_connect_swapped(hbox, "destroy", G_CALLBACK(g_object_unref), interPick); g_signal_connect_swapped(hbox, "destroy", G_CALLBACK(g_object_unref), translator); return (GtkWidget*)0; } static void setLabelsOrigin(VisuData *data, GArray *nodeIds) { gchar numero[256]; VisuNode *node; if (nodeIds && nodeIds->len > 0) { if (gtk_toggle_button_get_active(GTK_TOGGLE_BUTTON(radioMovePick))) { movedNode = g_array_index(nodeIds, gint, 0); node = visu_node_array_getFromId(VISU_NODE_ARRAY(data), movedNode); g_return_if_fail(node && node->number == (guint)movedNode); /* Set the origin position values. */ moveNodeOrigin[0] = node->xyz[0]; moveNodeOrigin[1] = node->xyz[1]; moveNodeOrigin[2] = node->xyz[2]; sprintf(numero, "/ %5.2f", moveNodeOrigin[0]); gtk_label_set_markup(GTK_LABEL(labelOriginX), numero); sprintf(numero, "/ %5.2f", moveNodeOrigin[1]); gtk_label_set_markup(GTK_LABEL(labelOriginY), numero); sprintf(numero, "/ %5.2f", moveNodeOrigin[2]); gtk_label_set_markup(GTK_LABEL(labelOriginZ), numero); } else { movedNode = -1; gtk_label_set_markup(GTK_LABEL(labelOriginX), ""); gtk_label_set_markup(GTK_LABEL(labelOriginY), ""); gtk_label_set_markup(GTK_LABEL(labelOriginZ), ""); } } else { movedNode = -1; gtk_label_set_markup(GTK_LABEL(labelOriginX), ""); gtk_label_set_markup(GTK_LABEL(labelOriginY), ""); gtk_label_set_markup(GTK_LABEL(labelOriginZ), ""); } /* Set the sensitivity. */ gtk_widget_set_sensitive(removeButton, (nodeIds && nodeIds->len > 0)); } static void setMovingNodes() { GArray *nodeIds; DBG_fprintf(stderr, "Gtk Move: set the moving list.\n"); nodeIds = (GArray*)0; if (!gtk_toggle_button_get_active(GTK_TOGGLE_BUTTON(radioMovePick))) nodeIds = visu_ui_selection_get(visu_ui_interactive_pick_getSelection()); visu_interactive_setMovingNodes(interMove, nodeIds); setLabelsOrigin((VisuData*)0, nodeIds); if (nodeIds) { visu_node_mover_setNodes(VISU_NODE_MOVER(translator), nodeIds); g_array_unref(nodeIds); } } /** * visu_ui_interactive_move_start: * @window: a #VisuUiRenderingWindow object. * * Initialise a moving session. */ void visu_ui_interactive_move_start(VisuUiRenderingWindow *window) { DBG_fprintf(stderr, "Gtk Move: start the move panel.\n"); visu_ui_rendering_window_pushInteractive(window, interMove); if (currentMode == interactive_pick) visu_ui_rendering_window_pushInteractive(window, interPick); /* Set the moving list. */ setMovingNodes(); } /** * visu_ui_interactive_move_stop: * @window: a #VisuUiRenderingWindow object. * * Finalise a moving session. */ void visu_ui_interactive_move_stop(VisuUiRenderingWindow *window) { DBG_fprintf(stderr, "Gtk Move: unset the move panel.\n"); if (currentMode == interactive_pick) visu_ui_rendering_window_popInteractive(window, interPick); visu_ui_rendering_window_popInteractive(window, interMove); } static void onStartMove(VisuInteractive *inter _U_, GArray* nodeIds, gpointer data) { DBG_fprintf(stderr, "Gtk Move: callback on start-move action.\n"); setLabelsOrigin(visu_gl_node_scene_getData(VISU_GL_NODE_SCENE(data)), nodeIds); visu_node_mover_setNodes(VISU_NODE_MOVER(translator), nodeIds); visu_node_mover_translation_reset(translator); return; } /****************/ /* Private part */ /****************/ static void _setDataModel(VisuData *dataObj) { if (_dataModel) { g_signal_handler_disconnect(_dataModel, popDec_signal); g_signal_handler_disconnect(_dataModel, popInc_signal); g_signal_handler_disconnect(_dataModel, popChg_signal); g_object_unref(_dataModel); } _dataModel = dataObj; if (dataObj) { g_object_ref(dataObj); popDec_signal = g_signal_connect(G_OBJECT(dataObj), "PopulationDecrease", G_CALLBACK(_setSpinRange), (gpointer)0); popInc_signal = g_signal_connect(G_OBJECT(dataObj), "PopulationIncrease", G_CALLBACK(_setSpinRange), (gpointer)0); popChg_signal = g_signal_connect(G_OBJECT(dataObj), "position-changed", G_CALLBACK(onPositionChanged), (gpointer)0); _setSpinRange(dataObj); } /* We remove the basisset drawing. */ visu_gl_ext_setActive(VISU_GL_EXT(extBasis), FALSE); } static void refreshMoveAxesValues(VisuGlView *view) { gint id; float x[3], y[3]; char tmpChr[20]; id = gtk_notebook_get_current_page(GTK_NOTEBOOK(notebookAction)); DBG_fprintf(stderr, "Gtk Move: refresh screen basis set.\n"); DBG_fprintf(stderr, " | %d %d\n", id + 1, VISU_UI_ACTION_MOVE); if (id + 1 == VISU_UI_ACTION_MOVE) { visu_gl_camera_getScreenAxes(&view->camera, x, y); sprintf(tmpChr, "(%4.2f;%4.2f;%4.2f)", x[0], x[1], x[2]); gtk_label_set_text(GTK_LABEL(labelScreenHorizontal), tmpChr); sprintf(tmpChr, "(%4.2f;%4.2f;%4.2f)", y[0], y[1], y[2]); gtk_label_set_text(GTK_LABEL(labelScreenVertical), tmpChr); } } static void onMoveMethod(GtkToggleButton *toggle, gpointer data _U_) { if (!gtk_toggle_button_get_active(toggle)) return; /* Set the moving list. */ setMovingNodes(); } static void onRemoveNodeClicked(GtkButton *button _U_, gpointer user_data _U_) { GArray *nodes; VisuData *dataObj; VisuNode *node; int i; VisuElement *ele; gfloat xyz[3]; DBG_fprintf(stderr, "Gtk Observe/pick: remove the selected node %d.\n", movedNode); dataObj = visu_gl_node_scene_getData(visu_ui_rendering_window_getGlScene(visu_ui_main_class_getDefaultRendering())); if (gtk_toggle_button_get_active(GTK_TOGGLE_BUTTON(radioMovePick))) { if (movedNode < 0) return; node = visu_node_array_getFromId(VISU_NODE_ARRAY(dataObj), movedNode); if (!node) return; xyz[0] = node->xyz[0]; xyz[1] = node->xyz[1]; xyz[2] = node->xyz[2]; ele = visu_node_array_getElement(VISU_NODE_ARRAY(dataObj), node); nodes = g_array_new(FALSE, FALSE, sizeof(guint)); g_array_append_val(nodes, movedNode); visu_node_array_removeNodes(VISU_NODE_ARRAY(dataObj), nodes); g_array_unref(nodes); /* Copy the coordinates to the add entries. */ for (i = 0; i < 3; i++) visu_ui_numerical_entry_setValue(VISU_UI_NUMERICAL_ENTRY(entryAddXYZ[i]), xyz[i]); visu_ui_element_combobox_setSelection(VISU_UI_ELEMENT_COMBOBOX(comboElements), ele->name); /* No need for rendering changed, the population decrease should take care of the rest. */ /* g_signal_emit_by_name(G_OBJECT(dataObj), "RenderingChanged", ele, NULL); */ } else { DBG_fprintf(stderr, "Gtk Move: get list of selected nodes.\n"); nodes = visu_ui_selection_get(visu_ui_interactive_pick_getSelection()); if (nodes->len > 0) visu_node_array_removeNodes(VISU_NODE_ARRAY(dataObj), nodes); g_array_unref(nodes); } /* We remove the node as selected one. */ setLabelsOrigin((VisuData*)0, (GArray*)0); } static void onAddNodeClicked(GtkButton *button _U_, gpointer user_data _U_) { VisuData *dataObj; GList *elements; VisuElement *element; float xyz[3]; dataObj = visu_gl_node_scene_getData(visu_ui_rendering_window_getGlScene(visu_ui_main_class_getDefaultRendering())); elements = visu_ui_element_combobox_getSelection(VISU_UI_ELEMENT_COMBOBOX(comboElements)); g_return_if_fail(elements); element = (VisuElement*)elements->data; g_list_free(elements); xyz[0] = (float)visu_ui_numerical_entry_getValue(VISU_UI_NUMERICAL_ENTRY(entryAddXYZ[0])); xyz[1] = (float)visu_ui_numerical_entry_getValue(VISU_UI_NUMERICAL_ENTRY(entryAddXYZ[1])); xyz[2] = (float)visu_ui_numerical_entry_getValue(VISU_UI_NUMERICAL_ENTRY(entryAddXYZ[2])); visu_data_addNodeFromElement(dataObj, element, xyz, FALSE); } static void onDuplicate(GtkButton *button _U_, gpointer data _U_) { VisuData *dataObj; GList *lst; GArray *arr, *newArr; gboolean custom; VisuElement *element; float coord[3], trans[3]; VisuNodeArrayIter iter; VisuNode *node; DBG_fprintf(stderr, "Gtk Move: duplicate selected nodes.\n"); dataObj = visu_gl_node_scene_getData(visu_ui_rendering_window_getGlScene(visu_ui_main_class_getDefaultRendering())); element = (VisuElement*)0; custom = !gtk_toggle_button_get_active(GTK_TOGGLE_BUTTON(checkDuplicate)); if (custom) { lst = visu_ui_element_combobox_getSelection(VISU_UI_ELEMENT_COMBOBOX(comboDuplicate)); g_return_if_fail(lst); element = (VisuElement*)lst->data; DBG_fprintf(stderr, "Gtk Move: change element to '%s'.\n", element->name); g_list_free(lst); } arr = visu_ui_selection_get(visu_ui_interactive_pick_getSelection()); if (!arr || !arr->len) { if (arr) g_array_free(arr, TRUE); return; } newArr = g_array_sized_new(FALSE, FALSE, sizeof(guint), arr->len); visu_pointset_getTranslation(VISU_POINTSET(dataObj), trans); visu_node_array_startAdding(VISU_NODE_ARRAY(dataObj)); visu_node_array_iter_new(VISU_NODE_ARRAY(dataObj), &iter); for (visu_node_array_iterStartArray(VISU_NODE_ARRAY(dataObj), &iter, arr); iter.node; visu_node_array_iterNextArray(VISU_NODE_ARRAY(dataObj), &iter)) { visu_data_getNodePosition(dataObj, iter.node, coord); coord[0] -= trans[0]; coord[1] -= trans[1]; coord[2] -= trans[2]; if (element) node = visu_data_addNodeFromElement(dataObj, element, coord, FALSE); else node = visu_data_addNodeFromIndex(dataObj, iter.iElement, coord, FALSE); g_array_append_val(newArr, node->number); } visu_node_array_completeAdding(VISU_NODE_ARRAY(dataObj)); visu_ui_selection_set(visu_ui_interactive_pick_getSelection(), newArr); g_array_unref(newArr); } static void onMoveToggled(GtkToggleButton *toggle, gpointer data) { GtkWidget *wd; gboolean value; value = gtk_toggle_button_get_active(toggle); wd = lookup_widget(GTK_WIDGET(data), "vbox21"); gtk_widget_set_sensitive(wd, value); } static gboolean setupBasisMatrix(VisuData *dataObj, float mat[3][3], float O[3]) { VisuNode *orig, *nodeA, *nodeB, *nodeC; float xyz[3]; orig = visu_node_array_getFromId(VISU_NODE_ARRAY(dataObj), (guint)gtk_spin_button_get_value (GTK_SPIN_BUTTON(spinABC[0])) - 1); nodeA = visu_node_array_getFromId(VISU_NODE_ARRAY(dataObj), (guint)gtk_spin_button_get_value (GTK_SPIN_BUTTON(spinABC[1])) - 1); nodeB = visu_node_array_getFromId(VISU_NODE_ARRAY(dataObj), (guint)gtk_spin_button_get_value (GTK_SPIN_BUTTON(spinABC[2])) - 1); nodeC = visu_node_array_getFromId(VISU_NODE_ARRAY(dataObj), (guint)gtk_spin_button_get_value (GTK_SPIN_BUTTON(spinABC[3])) - 1); if (!orig || !nodeA || !nodeB || !nodeC) return FALSE; visu_data_getNodePosition(dataObj, orig, O); visu_data_getNodePosition(dataObj, nodeA, xyz); mat[0][0] = xyz[0] - O[0]; mat[1][0] = xyz[1] - O[1]; mat[2][0] = xyz[2] - O[2]; visu_data_getNodePosition(dataObj, nodeB, xyz); mat[0][1] = xyz[0] - O[0]; mat[1][1] = xyz[1] - O[1]; mat[2][1] = xyz[2] - O[2]; visu_data_getNodePosition(dataObj, nodeC, xyz); mat[0][2] = xyz[0] - O[0]; mat[1][2] = xyz[1] - O[1]; mat[2][2] = xyz[2] - O[2]; return TRUE; } static void onSpinBasis(GtkSpinButton *spin, gpointer data) { int i; guint id; VisuGlNodeScene *scene; VisuGlExtMarks *marks; gboolean valid; VisuData *dataObj; GArray *ids; float mat[3][3], O[3]; i = GPOINTER_TO_INT(data); scene = visu_ui_rendering_window_getGlScene(visu_ui_main_class_getDefaultRendering()); dataObj = visu_gl_node_scene_getData(scene); marks = visu_gl_node_scene_getMarks(scene); /* Remove the previous one. */ if (prevBasis[i] > 0) removeHighlight(GINT_TO_POINTER(prevBasis[i])); if (timeoutBasis[i] > 0) g_source_remove(timeoutBasis[i]); prevBasis[i] = (gint)gtk_spin_button_get_value(spin); if (prevBasis[i] > 0 && visu_node_array_getFromId(VISU_NODE_ARRAY(dataObj), prevBasis[i])) { ids = g_array_new(FALSE, FALSE, sizeof(guint)); id = prevBasis[i] - 1; g_array_append_val(ids, id); visu_gl_ext_marks_setHighlight(marks, ids, MARKS_STATUS_SET); g_array_unref(ids); /* Add a new highlight. */ #if GLIB_MINOR_VERSION > 13 timeoutBasis[i] = g_timeout_add_seconds(1, removeHighlight, GINT_TO_POINTER(prevBasis[i])); #else timeoutBasis[i] = g_timeout_add(1000, removeHighlight, GINT_TO_POINTER(prevBasis[i])); #endif } valid = TRUE; for(i = 0; i < 4; i++) valid = valid && (gtk_spin_button_get_value(GTK_SPIN_BUTTON(spinABC[i])) > 0.); gtk_widget_set_sensitive(applyBasis, valid); if (valid && setupBasisMatrix(dataObj, mat, O)) { visu_gl_ext_setActive(VISU_GL_EXT(extBasis), TRUE); drawBasisCell(visu_boxed_getBox(VISU_BOXED(dataObj)), O, mat); if (tool_matrix_determinant(mat) < 0.f) visu_ui_interactive_setMessage(_("The new basis set will be indirect."), GTK_MESSAGE_WARNING); else visu_ui_interactive_unsetMessage(); } else visu_gl_ext_setActive(VISU_GL_EXT(extBasis), FALSE); } static gboolean removeHighlight(gpointer data) { int i; VisuGlExtMarks *marks; GArray *ids; i = GPOINTER_TO_INT(data) - 1; g_return_val_if_fail(i >= 0, FALSE); marks = visu_gl_node_scene_getMarks(visu_ui_rendering_window_getGlScene(visu_ui_main_class_getDefaultRendering())); /* Remove the previous one. */ ids = g_array_new(FALSE, FALSE, sizeof(guint)); g_array_append_val(ids, i); visu_gl_ext_marks_setHighlight(marks, ids, MARKS_STATUS_UNSET); g_array_unref(ids); return FALSE; } static void onChooseBasis(GtkToggleButton *toggle, gpointer data) { guint i; VisuUiRenderingWindow *window; gboolean valid; window = visu_ui_main_class_getDefaultRendering(); DBG_fprintf(stderr, "Gtk Move: one toggle chooser has been toggled.\n"); valid = gtk_toggle_button_get_active(toggle); if (valid) { currentMode = interactive_pick; currentAxe = GPOINTER_TO_INT(data); visu_ui_rendering_window_pushInteractive(window, interPick); } else { currentMode = interactive_move; visu_ui_rendering_window_popInteractive(window, interPick); } for(i = 0; i < 4; i++) gtk_widget_set_sensitive(toggleABC[i], (!valid || (i == currentAxe))); gtk_widget_set_sensitive(lookup_widget(observeWindow, "hbox72"), !valid); gtk_widget_set_sensitive(lookup_widget(observeWindow, "tableMovePick"), !valid); gtk_widget_set_sensitive(lookup_widget(observeWindow, "hboxAddNode"), !valid); } static void onBasisSelected(VisuInteractive *inter _U_, VisuInteractivePick pick _U_, VisuData *dataObj _U_, VisuNode *node0, VisuNode *node1 _U_, VisuNode *node2 _U_, gpointer data _U_) { g_return_if_fail(node0); gtk_spin_button_set_value(GTK_SPIN_BUTTON(spinABC[currentAxe]), node0->number + 1); gtk_toggle_button_set_active (GTK_TOGGLE_BUTTON(toggleABC[currentAxe]), FALSE); } static void onPickClickStop(VisuInteractive *inter _U_, gpointer data _U_) { int i; for(i = 0; i < 4; i++) gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON(toggleABC[i]), FALSE); } static void onApplyBasis(GtkButton *button _U_, gpointer data _U_) { VisuData *dataObj; float matA[3][3], O[3]; dataObj = visu_gl_node_scene_getData(visu_ui_rendering_window_getGlScene(visu_ui_main_class_getDefaultRendering())); if (setupBasisMatrix(dataObj, matA, O)) { if (!visu_data_setNewBasis(dataObj, matA, O)) visu_ui_interactive_setMessage (_("Cannot change the basis: given matrix is singular."), GTK_MESSAGE_ERROR); } g_signal_handler_block(G_OBJECT(spinABC[0]), onSpin_id[0]); gtk_spin_button_set_value(GTK_SPIN_BUTTON(spinABC[0]), 0); g_signal_handler_unblock(G_OBJECT(spinABC[0]), onSpin_id[0]); g_signal_handler_block(G_OBJECT(spinABC[1]), onSpin_id[1]); gtk_spin_button_set_value(GTK_SPIN_BUTTON(spinABC[1]), 0); g_signal_handler_unblock(G_OBJECT(spinABC[1]), onSpin_id[1]); g_signal_handler_block(G_OBJECT(spinABC[2]), onSpin_id[2]); gtk_spin_button_set_value(GTK_SPIN_BUTTON(spinABC[2]), 0); g_signal_handler_unblock(G_OBJECT(spinABC[2]), onSpin_id[2]); g_signal_handler_block(G_OBJECT(spinABC[3]), onSpin_id[3]); gtk_spin_button_set_value(GTK_SPIN_BUTTON(spinABC[3]), 0); g_signal_handler_unblock(G_OBJECT(spinABC[3]), onSpin_id[3]); visu_gl_ext_setActive(VISU_GL_EXT(extBasis), FALSE); } static void _setSpinRange(VisuData *dataObj) { VisuNodeArrayIter iter; visu_node_array_iter_new(VISU_NODE_ARRAY(dataObj), &iter); DBG_fprintf(stderr, "Gtk Move: caught 'population changed', update spin up to %d.\n", iter.idMax + 1); g_signal_handler_block(G_OBJECT(spinABC[0]), onSpin_id[0]); gtk_spin_button_set_range(GTK_SPIN_BUTTON(spinABC[0]), 0, iter.idMax + 1); g_signal_handler_unblock(G_OBJECT(spinABC[0]), onSpin_id[0]); g_signal_handler_block(G_OBJECT(spinABC[1]), onSpin_id[1]); gtk_spin_button_set_range(GTK_SPIN_BUTTON(spinABC[1]), 0, iter.idMax + 1); g_signal_handler_unblock(G_OBJECT(spinABC[1]), onSpin_id[1]); g_signal_handler_block(G_OBJECT(spinABC[2]), onSpin_id[2]); gtk_spin_button_set_range(GTK_SPIN_BUTTON(spinABC[2]), 0, iter.idMax + 1); g_signal_handler_unblock(G_OBJECT(spinABC[2]), onSpin_id[2]); g_signal_handler_block(G_OBJECT(spinABC[3]), onSpin_id[3]); gtk_spin_button_set_range(GTK_SPIN_BUTTON(spinABC[3]), 0, iter.idMax + 1); g_signal_handler_unblock(G_OBJECT(spinABC[3]), onSpin_id[3]); } static void onPositionChanged(VisuData *dataObj, GArray *ids _U_, gpointer data _U_) { float mat[3][3], O[3]; if (setupBasisMatrix(dataObj, mat, O)) drawBasisCell(visu_boxed_getBox(VISU_BOXED(dataObj)), O, mat); } static void onAxeChoosen(VisuUiNumericalEntry *entry _U_, double oldValue _U_, gpointer data _U_) { float axe[3]; axe[0] = (float)visu_ui_numerical_entry_getValue(VISU_UI_NUMERICAL_ENTRY(entryAxeXYZ[0])); axe[1] = (float)visu_ui_numerical_entry_getValue(VISU_UI_NUMERICAL_ENTRY(entryAxeXYZ[1])); axe[2] = (float)visu_ui_numerical_entry_getValue(VISU_UI_NUMERICAL_ENTRY(entryAxeXYZ[2])); visu_interactive_setMovingAxe(interMove, axe); } static void onGetAxisClicked(VisuGlView *view, GtkButton *button _U_) { visu_ui_numerical_entry_setValue(VISU_UI_NUMERICAL_ENTRY(entryAxeXYZ[0]), view->camera.eye[0]); visu_ui_numerical_entry_setValue(VISU_UI_NUMERICAL_ENTRY(entryAxeXYZ[1]), view->camera.eye[1]); visu_ui_numerical_entry_setValue(VISU_UI_NUMERICAL_ENTRY(entryAxeXYZ[2]), view->camera.eye[2]); } /********************/ /* Drawing methods. */ /********************/ static void drawBasisCell(VisuBox *box _U_, float O[3], float mat[3][3]) { DBG_fprintf(stderr, "Gtk Move: draw the new basis cell.\n"); visu_gl_ext_box_setBasis(extBasis, O, mat); } v_sim-3.8.0/src/gtk_move.h000066400000000000000000000042031370110300500153770ustar00rootroot00000000000000/* EXTRAITS DE LA LICENCE Copyright CEA, contributeurs : Luc BILLARD et Damien CALISTE, laboratoire L_Sim, (2001-2005) Adresse mèl : BILLARD, non joignable par mèl ; CALISTE, damien P caliste AT cea P fr. Ce logiciel est un programme informatique servant à visualiser des structures atomiques dans un rendu pseudo-3D. Ce logiciel est régi par la licence CeCILL soumise au droit français et respectant les principes de diffusion des logiciels libres. Vous pouvez utiliser, modifier et/ou redistribuer ce programme sous les conditions de la licence CeCILL telle que diffusée par le CEA, le CNRS et l'INRIA sur le site "http://www.cecill.info". Le fait que vous puissiez accéder à cet en-tête signifie que vous avez pris connaissance de la licence CeCILL, et que vous en avez accepté les termes (cf. le fichier Documentation/licence.fr.txt fourni avec ce logiciel). */ /* LICENCE SUM UP Copyright CEA, contributors : Luc BILLARD et Damien CALISTE, laboratoire L_Sim, (2001-2005) E-mail address: BILLARD, not reachable any more ; CALISTE, damien P caliste AT cea P fr. This software is a computer program whose purpose is to visualize atomic configurations in 3D. This software is governed by the CeCILL license under French law and abiding by the rules of distribution of free software. You can use, modify and/ or redistribute the software under the terms of the CeCILL license as circulated by CEA, CNRS and INRIA at the following URL "http://www.cecill.info". The fact that you are presently reading this means that you have had knowledge of the CeCILL license and that you accept its terms. You can find a copy of this licence shipped with this software at Documentation/licence.en.txt. */ #ifndef GTK_MOVE_H #define GTK_MOVE_H #include #include "gtk_main.h" #include "gtk_renderingWindowWidget.h" GtkWidget* visu_ui_interactive_move_initBuild(VisuUiMain *main, gchar **label, gchar **help, GtkWidget **radio); void visu_ui_interactive_move_start(VisuUiRenderingWindow *window); void visu_ui_interactive_move_stop(VisuUiRenderingWindow *window); #endif v_sim-3.8.0/src/gtk_openGLWidget.c000066400000000000000000001002001370110300500167460ustar00rootroot00000000000000/* EXTRAITS DE LA LICENCE Copyright CEA, contributeurs : Luc BILLARD et Damien CALISTE, laboratoire L_Sim, (2001-2006) Adresse mèl : BILLARD, non joignable par mèl ; CALISTE, damien P caliste AT cea P fr. Ce logiciel est un programme informatique servant à visualiser des structures atomiques dans un rendu pseudo-3D. Ce logiciel est régi par la licence CeCILL soumise au droit français et respectant les principes de diffusion des logiciels libres. Vous pouvez utiliser, modifier et/ou redistribuer ce programme sous les conditions de la licence CeCILL telle que diffusée par le CEA, le CNRS et l'INRIA sur le site "http://www.cecill.info". Le fait que vous puissiez accéder à cet en-tête signifie que vous avez pris connaissance de la licence CeCILL, et que vous en avez accepté les termes (cf. le fichier Documentation/licence.fr.txt fourni avec ce logiciel). */ /* LICENCE SUM UP Copyright CEA, contributors : Luc BILLARD et Damien CALISTE, laboratoire L_Sim, (2001-2006) E-mail address: BILLARD, not reachable any more ; CALISTE, damien P caliste AT cea P fr. This software is a computer program whose purpose is to visualize atomic configurations in 3D. This software is governed by the CeCILL license under French law and abiding by the rules of distribution of free software. You can use, modify and/ or redistribute the software under the terms of the CeCILL license as circulated by CEA, CNRS and INRIA at the following URL "http://www.cecill.info". The fact that you are presently reading this means that you have had knowledge of the CeCILL license and that you accept its terms. You can find a copy of this licence shipped with this software at Documentation/licence.en.txt. */ #ifdef HAVE_CONFIG_H #include #endif #include #include #include #include #include "visu_basic.h" #include "gtk_openGLWidget.h" #include "OSOpenGL/visu_openGL.h" #include "visu_tools.h" #include "visu_extension.h" #include "visu_gtk.h" #include "opengl.h" #include "openGLFunctions/text.h" /* OpenGL implementation dependencies */ #ifdef HAVE_GTKGLEXT #include #include #define IMPL_GTKGLEXT #else #if SYSTEM_X11 == 1 #include #include #define IMPL_BUILTIN_X11 #endif #if SYSTEM_WIN32 == 1 #include #include #define IMPL_BUILTIN_WIN32 #endif #if SYSTEM_QUARTZ == 1 #include #include #define IMPL_BUILTIN_QUARTZ #endif #endif /** * SECTION:gtk_openGLWidget * @short_description: defines an OpenGL capable GtkWidget. * * This is a simple implementation of GtkGlExt to create an * OpenGL surface that is a full GtkWidget. When creating such a * widget, one should give then a VisuUiGlWidgetRedrawMethod() to tell the widget * how to redraw itself when needed. * * The current implementation is working on X11 (built-in or * with GtkGlExt) and Win32. */ struct _VisuUiGlWidget { GtkWidget parent; gboolean sizeAllocation_has_run; gboolean dispose_has_run; /* Redraw method and user data. */ VisuGlExtSet *model; /* Default background pixbuf. */ cairo_surface_t *backLogo; /* OpenGL part, OS dependent. */ gboolean isContextDirect; GdkVisual *visual; #ifdef IMPL_GTKGLEXT GdkGLConfig *glconfig; GdkGLWindow *glwindow; GdkGLContext *context; #endif #ifdef IMPL_BUILTIN_X11 Display *dpy; XVisualInfo *vinfo; GLXContext context; #endif #ifdef IMPL_BUILTIN_WIN32 HDC hdc; HGLRC context; HWND windowId; #endif #ifdef IMPL_BUILTIN_QUARTZ NSWindow windowId; AGLContext context; AGLPixelFmtID pxlfmt; #endif }; struct _VisuUiGlWidgetClass { GtkWidgetClass parent_class; VisuUiGlWidget *contextCurrent; }; G_DEFINE_TYPE(VisuUiGlWidget, visu_ui_gl_widget, GTK_TYPE_WIDGET) /* Local variables. */ static VisuUiGlWidgetClass *myClass = (VisuUiGlWidgetClass*)0; /* Local callbacks. */ #if GTK_MAJOR_VERSION < 3 && GTK_MINOR_VERSION < 26 static gboolean visu_ui_gl_widgetEvent_expose(GtkWidget *widget, GdkEventExpose *event); static void visu_ui_gl_widgetEvent_sizeRequest(GtkWidget *widget, GtkRequisition *requisition); #else static gboolean visu_ui_gl_widgetEvent_draw(GtkWidget *widget, cairo_t *cr); static void visu_ui_gl_widgetEvent_getWidth(GtkWidget *widget, gint *minWidth, gint *width); static void visu_ui_gl_widgetEvent_getHeight(GtkWidget *widget, gint *minHeight, gint *height); #endif static gboolean visu_ui_gl_widgetEvent_visibility(GtkWidget *widget, GdkEventVisibility *event); static void visu_ui_gl_widgetEvent_sizeAllocate(GtkWidget *widget, GtkAllocation *allocation); static void visu_ui_gl_widgetEvent_realise(GtkWidget *widget); static void drawToGl(VisuUiGlWidget *render); static void drawToEmpty(VisuUiGlWidget *render, cairo_t *cr); static void swapGl(VisuUiGlWidget *render); /* Initialisation methods. */ static void visu_ui_gl_widgetInit_context(VisuUiGlWidget *render, gboolean contextIsDirect); /* Freeing methods. */ static void visu_ui_gl_widgetEvent_dispose(GObject *obj); static void visu_ui_gl_widgetFree_openGL(VisuUiGlWidget *render); /* Miscellaneous methods. */ static void setViewport(VisuUiGlWidget *render, guint width, guint height, gboolean redraw); static void visu_ui_gl_widgetSet_pixelFormat(VisuUiGlWidget *render); #if GTK_MAJOR_VERSION < 3 && GTK_MINOR_VERSION < 26 static GdkColormap* visu_ui_gl_widgetGet_openGLColormap(VisuUiGlWidget *render); #endif static void visu_ui_gl_widget_class_init(VisuUiGlWidgetClass *class) { GtkWidgetClass *widget_class; GObjectClass *gobject_class; /* Dealing with GObject events. */ gobject_class = G_OBJECT_CLASS(class); gobject_class->dispose = visu_ui_gl_widgetEvent_dispose; /* Dealing with widget events. */ widget_class = GTK_WIDGET_CLASS(class); #if GTK_MAJOR_VERSION < 3 && GTK_MINOR_VERSION < 26 widget_class->expose_event = visu_ui_gl_widgetEvent_expose; widget_class->size_request = visu_ui_gl_widgetEvent_sizeRequest; #else widget_class->draw = visu_ui_gl_widgetEvent_draw; widget_class->get_preferred_width = visu_ui_gl_widgetEvent_getWidth; widget_class->get_preferred_height = visu_ui_gl_widgetEvent_getHeight; #endif widget_class->visibility_notify_event = visu_ui_gl_widgetEvent_visibility; widget_class->realize = visu_ui_gl_widgetEvent_realise; widget_class->size_allocate = visu_ui_gl_widgetEvent_sizeAllocate; class->contextCurrent = (VisuUiGlWidget*)0; myClass = class; } static void visu_ui_gl_widget_init(VisuUiGlWidget *render) { DBG_fprintf(stderr, "Gtk OpenGL (init) : create object %p.\n", (gpointer)render); render->sizeAllocation_has_run = FALSE; render->dispose_has_run = FALSE; render->model = (VisuGlExtSet*)0; render->backLogo = (cairo_surface_t*)0; render->isContextDirect = FALSE; render->visual = (GdkVisual*)0; #ifdef IMPL_GTKGLEXT render->glconfig = (GdkGLConfig*)0; render->glwindow = (GdkGLWindow*)0; render->context = (GdkGLContext*)0; #endif #ifdef IMPL_BUILTIN_X11 render->dpy = (Display*)0; render->vinfo = (XVisualInfo*)0; render->context = (GLXContext)0; #endif #ifdef IMPL_BUILTIN_WIN32 render->hdc = (HDC)0; render->context = (HGLRC)0; render->windowId = (HWND)0; #endif /* Cancel the GTK double buffering since it is taken into account by OpenGL itself. */ #if GTK_MAJOR_VERSION < 3 || (GTK_MAJOR_VERSION == 3 && GTK_MINOR_VERSION < 14) gtk_widget_set_double_buffered(GTK_WIDGET(render), FALSE); #endif gtk_widget_set_has_window(GTK_WIDGET(render), TRUE); } GtkWidget* visu_ui_gl_widget_new(gboolean contextIsDirect) { VisuUiGlWidget *render; render = VISU_UI_GL_WIDGET(g_object_new(VISU_TYPE_UI_GL_WIDGET, NULL)); render->isContextDirect = contextIsDirect; return GTK_WIDGET(render); } /* Methods to deals with the events. */ static void visu_ui_gl_widgetEvent_dispose(GObject *obj) { VisuUiGlWidget *self; DBG_fprintf(stderr, "Gtk OpenGL (events) : dispose event for object %p.\n", (gpointer)obj); self = VISU_UI_GL_WIDGET(obj); if (self->dispose_has_run) return; self->dispose_has_run = TRUE; visu_ui_gl_widgetFree_openGL(self); if (self->backLogo) cairo_surface_destroy(self->backLogo); if (self->model) g_object_unref(self->model); /* Chain up to the parent class */ G_OBJECT_CLASS(visu_ui_gl_widget_parent_class)->dispose(obj); } #if GTK_MAJOR_VERSION < 3 && GTK_MINOR_VERSION < 26 static gboolean visu_ui_gl_widgetEvent_expose(GtkWidget *widget, GdkEventExpose *event _U_) { DBG_fprintf(stderr, "Gtk OpenGL (events): expose event for object %p.\n", (gpointer)widget); if (VISU_UI_GL_WIDGET(widget)->model) drawToGl(VISU_UI_GL_WIDGET(widget)); return FALSE; } #else static gboolean visu_ui_gl_widgetEvent_draw(GtkWidget *widget, cairo_t *cr) { DBG_fprintf(stderr, "Gtk OpenGL (events): draw event for object %p.\n", (gpointer)widget); if (VISU_UI_GL_WIDGET(widget)->model) drawToGl(VISU_UI_GL_WIDGET(widget)); else drawToEmpty(VISU_UI_GL_WIDGET(widget), cr); return FALSE; } #endif static gboolean visu_ui_gl_widgetEvent_visibility(GtkWidget *widget, GdkEventVisibility *event) { if (event->state != GDK_VISIBILITY_UNOBSCURED) return FALSE; DBG_fprintf(stderr, "Gtk OpenGL (events): visibility event for object %p.\n", (gpointer)widget); gtk_widget_queue_draw(widget); DBG_fprintf(stderr, "Gtk OpenGL (events): visibility OK.\n"); return FALSE; } #if GTK_MAJOR_VERSION < 3 && GTK_MINOR_VERSION < 26 static void visu_ui_gl_widgetEvent_sizeRequest(GtkWidget *widget, GtkRequisition *requisition) { VisuUiGlWidget *render; GtkAllocation allocation; DBG_fprintf(stderr, "Gtk OpenGL (events): size request event.\n"); render = VISU_UI_GL_WIDGET(widget); if (render->sizeAllocation_has_run) { gtk_widget_get_allocation(widget, &allocation); requisition->width = allocation.width; requisition->height = allocation.height; } else { requisition->width = 200; requisition->height = 200; } /* Chain up to default that simply reads current requisition */ /* GTK_WIDGET_CLASS(visu_ui_gl_widget_parent_class)->size_request(widget, requisition); */ DBG_fprintf(stderr, "Gtk OpenGL (events): size request event (%dx%d).\n", requisition->width, requisition->height); } #else static void visu_ui_gl_widgetEvent_getSize(GtkWidget *widget _U_, GtkOrientation orientation, gint *minSize, gint *size) { DBG_fprintf(stderr, "Gtk OpenGL (events): size request event.\n"); if (orientation == GTK_ORIENTATION_HORIZONTAL) { *minSize = 200; *size = 450; } else { *minSize = 200; *size = 450; } } static void visu_ui_gl_widgetEvent_getWidth(GtkWidget *widget, gint *minWidth, gint *width) { visu_ui_gl_widgetEvent_getSize(widget, GTK_ORIENTATION_HORIZONTAL, minWidth, width); } static void visu_ui_gl_widgetEvent_getHeight(GtkWidget *widget, gint *minHeight, gint *height) { visu_ui_gl_widgetEvent_getSize(widget, GTK_ORIENTATION_HORIZONTAL, minHeight, height); } #endif static void visu_ui_gl_widgetEvent_sizeAllocate(GtkWidget *widget, GtkAllocation *allocation) { VisuUiGlWidget *render; GtkAllocation wdAllocation; render = VISU_UI_GL_WIDGET(widget); gtk_widget_get_allocation(widget, &wdAllocation); if ((wdAllocation.width == allocation->width) && (wdAllocation.height == allocation->height)) return; DBG_fprintf(stderr, "Gtk OpenGL (events): size allocation event (%dx%d).\n", allocation->width, allocation->height); render->sizeAllocation_has_run = TRUE; /* Chain up to default that simply reads current requisition */ GTK_WIDGET_CLASS(visu_ui_gl_widget_parent_class)->size_allocate(widget, allocation); #ifdef IMPL_BUILTIN_X11 glXWaitX(); #endif setViewport(render, allocation->width, allocation->height, FALSE); } static void visu_ui_gl_widgetEvent_realise(GtkWidget *widget) { VisuUiGlWidget *render; GdkWindowAttr attributes; gint attributes_mask; #if GTK_MAJOR_VERSION < 3 && GTK_MINOR_VERSION < 26 GdkColormap *colormap; #else #define GDK_WA_COLORMAP 0 #endif GdkWindow *window; GtkAllocation allocation; DBG_fprintf(stderr, "Gtk OpenGL (events): realise event for %p.\n", (gpointer)widget); gtk_widget_set_realized(widget, TRUE); render = VISU_UI_GL_WIDGET(widget); #ifndef IMPL_BUILTIN_WIN32 visu_ui_gl_widgetSet_pixelFormat(render); #else render->visual = gdk_screen_get_system_visual(gdk_screen_get_default()); #endif gtk_widget_get_allocation(widget, &allocation); attributes.window_type = GDK_WINDOW_CHILD; attributes.x = allocation.x; attributes.y = allocation.y; attributes.width = allocation.width; attributes.height = allocation.height; attributes.wclass = GDK_INPUT_OUTPUT; #if GTK_MAJOR_VERSION < 3 && GTK_MINOR_VERSION < 26 colormap = visu_ui_gl_widgetGet_openGLColormap(render); DBG_fprintf(stderr, "Gtk OpenGL (debug): colormap is %p.\n", (gpointer)colormap); attributes.visual = gdk_colormap_get_visual(colormap); attributes.colormap = colormap; #else attributes.visual = render->visual; #endif attributes.event_mask = GDK_EXPOSURE_MASK | GDK_VISIBILITY_NOTIFY_MASK | GDK_BUTTON_PRESS_MASK | GDK_BUTTON_RELEASE_MASK | GDK_SCROLL_MASK | GDK_KEY_PRESS_MASK | GDK_POINTER_MOTION_MASK | GDK_POINTER_MOTION_HINT_MASK | GDK_ENTER_NOTIFY_MASK; #ifdef IMPL_GTKGLEXT attributes_mask = GDK_WA_X | GDK_WA_Y; #else attributes_mask = GDK_WA_X | GDK_WA_Y | GDK_WA_VISUAL | GDK_WA_COLORMAP; #endif window = gdk_window_new(gtk_widget_get_parent_window(widget), &attributes, attributes_mask); gtk_widget_set_window(widget, window); #if GTK_MAJOR_VERSION < 3 && GTK_MINOR_VERSION < 26 gdk_window_set_back_pixmap(window, NULL, FALSE); #elseif GTK_MAJOR_VERSION == 3 && GTK_MINOR_VERSION < 22 gdk_window_set_background_pattern(window, NULL); #endif #if GTK_MAJOR_VERSION < 3 || (GTK_MAJOR_VERSION == 3 && GTK_MINOR_VERSION < 8) gdk_window_set_user_data(window, widget); #else gtk_widget_register_window(widget, window); #endif G_GNUC_BEGIN_IGNORE_DEPRECATIONS gtk_widget_set_double_buffered(widget, FALSE); G_GNUC_END_IGNORE_DEPRECATIONS DBG_fprintf(stderr, "Gtk OpenGL (debug): GdkWindow is %p.\n", (gpointer)window); #if GTK_MAJOR_VERSION < 3 gtk_widget_style_attach(widget); #endif #if GTK_MAJOR_VERSION < 3 || (GTK_MAJOR_VERSION == 3 && GTK_MINOR_VERSION < 4) gdk_window_set_background(window, >k_widget_get_style(widget)->base[GTK_STATE_NORMAL]); #else { GtkCssProvider *css = gtk_css_provider_new(); gtk_css_provider_load_from_data(css, "VisuUiGlWidget {background-color: @theme_bg_color;}", -1, (GError**)0); gtk_style_context_add_provider(gtk_widget_get_style_context(widget), GTK_STYLE_PROVIDER(css), GTK_STYLE_PROVIDER_PRIORITY_APPLICATION); g_object_unref(css); } #endif gtk_widget_set_can_focus(widget, TRUE); gtk_widget_set_can_default(widget, TRUE); gdk_display_sync(gtk_widget_get_display(widget)); #ifdef IMPL_BUILTIN_X11 glXWaitX(); #endif /* Initialize context for OpenGL, OS dependent. */ #ifdef IMPL_BUILTIN_WIN32 visu_ui_gl_widgetSet_pixelFormat(render); #endif visu_ui_gl_widgetInit_context(render, render->isContextDirect); visu_ui_gl_widget_setCurrent(render, FALSE); } /** * visu_ui_gl_widget_class_getCurrentContext: * * Class routine that returns the OpenGL widget which has the current context. * * Returns: (transfer none): the #VisuUiGlWidget with the current OpenGL context. */ VisuUiGlWidget* visu_ui_gl_widget_class_getCurrentContext() { g_return_val_if_fail(myClass, (VisuUiGlWidget*)0); return myClass->contextCurrent; } static void setViewport(VisuUiGlWidget *render, guint width, guint height, gboolean redraw) { g_return_if_fail(VISU_IS_UI_GL_WIDGET(render)); if (VISU_UI_GL_WIDGET_GET_CLASS(render)->contextCurrent != render) return; DBG_fprintf(stderr, " | adjusting viewport to %dx%d.\n", width, height); glViewport(0, 0, width, height); if (redraw) { /* We synchronize the rendering area. */ gdk_display_sync(gtk_widget_get_display(GTK_WIDGET(render))); /* We clear the back buffer and swap because this buffer has still the wrong size. */ glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT); swapGl(render); } } static void drawToEmpty(VisuUiGlWidget *render, cairo_t *cr) { GtkAllocation allocation; gchar *path; DBG_fprintf(stderr, "Gtk OpenGL (action): Rebuild default background.\n"); gtk_widget_get_allocation(GTK_WIDGET(render), &allocation); gtk_render_background(gtk_widget_get_style_context(GTK_WIDGET(render)), cr, allocation.x, allocation.y, allocation.width, allocation.height); if (!render->backLogo) { path = g_build_filename(visu_basic_getPixmapsDir(), "logo_grey.png", NULL); render->backLogo = cairo_image_surface_create_from_png(path); g_free(path); } cairo_set_source_surface(cr, render->backLogo, allocation.x + allocation.width / 2 - cairo_image_surface_get_width(render->backLogo) / 2, allocation.y + allocation.height / 2 - cairo_image_surface_get_height(render->backLogo) / 2); cairo_paint(cr); } /** * visu_ui_gl_widget_setModel: * @render: a #VisuUiGlWidget object ; * @model: a #VisuGlExtSet object. * * This method is used to defined a redraw method for the OpenGL area. By doing this * the area will automatically redraw itself when necessary. Before doing it * it calls visu_ui_gl_widget_setCurrent(), and after it calls * swapGl(). */ void visu_ui_gl_widget_setModel(VisuUiGlWidget *render, VisuGlExtSet *model) { VisuGlExtSet *current; g_return_if_fail(VISU_IS_UI_GL_WIDGET(render)); DBG_fprintf(stderr, "Gtk OpenGL (action) : set redraw method for OpenGL area %p.\n", (gpointer)render); if (render->model == model) return; current = render->model; render->model = model; if (current) { g_object_unref(current); } if (model) { g_object_ref(model); } gtk_widget_queue_draw(GTK_WIDGET(render)); } static void drawToGl(VisuUiGlWidget *render) { #if DEBUG == 1 GTimer *timer; gulong fractionTimer; #endif g_return_if_fail(VISU_IS_UI_GL_WIDGET(render)); #if DEBUG == 1 timer = g_timer_new(); g_timer_start(timer); #endif DBG_fprintf(stderr, "Gtk OpenGL (action) : redraw OpenGL area for %p.\n", (gpointer)render); DBG_fprintf(stderr, " | set current.\n"); visu_ui_gl_widget_setCurrent(render, FALSE); DBG_fprintf(stderr, " | redraw inside.\n"); visu_gl_ext_set_draw(render->model); DBG_fprintf(stderr, " | swap buffers.\n"); swapGl(render); #if DEBUG == 1 g_timer_stop(timer); fprintf(stderr, "Gtk OpenGL: total redraw in %g micro-s.\n", g_timer_elapsed(timer, &fractionTimer)*1e6); g_timer_destroy(timer); #endif } /* OpenGL functions, OS dependent. */ #ifdef IMPL_GTKGLEXT static void visu_ui_gl_widgetSet_pixelFormat(VisuUiGlWidget *render) { GdkScreen *screen; DBG_fprintf(stderr, "Gtk OpenGL (glext): choose visual for %p.\n", render); /* Get the screen. */ if (gtk_widget_get_visible(GTK_WIDGET(render))) screen = gtk_widget_get_screen(GTK_WIDGET(render)); else screen = gdk_screen_get_default(); DBG_fprintf(stderr, " | get a screen number %d.\n", gdk_x11_screen_get_screen_number(screen)); render->glconfig = visu_gl_getGLConfig(screen); DBG_fprintf(stderr, " | get a visual.\n"); } static void visu_ui_gl_widgetInit_context(VisuUiGlWidget *render, gboolean contextIsDirect) { GtkWidget *wd; DBG_fprintf(stderr, "Gtk OpenGL (glext): create an OpenGL context (%d).\n", contextIsDirect); wd = GTK_WIDGET(render); /* Create a GL area on the widget window. */ render->glwindow = gdk_gl_window_new(render->glconfig, wd->window, NULL); /* Finaly, create the context. */ if (contextIsDirect) { render->context = gdk_gl_context_new(GDK_GL_DRAWABLE(render->glwindow), (GdkGLContext*)0, TRUE, GDK_GL_RGBA_TYPE); if (!render->context) { g_warning("Can't create a direct rendering context, try an inderect one.\n"); render->context = gdk_gl_context_new(GDK_GL_DRAWABLE(render->glwindow), (GdkGLContext*)0, FALSE, GDK_GL_RGBA_TYPE); render->isContextDirect = FALSE; } } else render->context = gdk_gl_context_new(GDK_GL_DRAWABLE(render->glwindow), (GdkGLContext*)0, FALSE, GDK_GL_RGBA_TYPE); DBG_fprintf(stderr, " | create the context %p (%d).\n", (gpointer)render->context, (int)render->isContextDirect); if (!render->context) { g_error("Cannot create a GtkGLExt context.\n"); } } static void visu_ui_gl_widgetFree_openGL(VisuUiGlWidget *render) { g_return_if_fail(VISU_IS_UI_GL_WIDGET(render)); DBG_fprintf(stderr, "Gtk OpenGL (glext): freeing context & window.\n"); if (render->glwindow) gdk_gl_window_destroy(render->glwindow); if (render->context) gdk_gl_context_destroy(render->context); } gboolean visu_ui_gl_widget_setCurrent(VisuUiGlWidget *render, gboolean force) { gboolean res; GtkWidget *wd; g_return_val_if_fail(VISU_IS_UI_GL_WIDGET(render), FALSE); if (!force && VISU_UI_GL_WIDGET_GET_CLASS(render)->contextCurrent == render) return TRUE; DBG_fprintf(stderr, "Gtk OpenGL (glext): %p is set current.\n", (gpointer)render); res = gdk_gl_drawable_make_current(GDK_GL_DRAWABLE(render->glwindow), render->context); visu_gl_text_onNewContext(); if (!res) { g_warning("Cannot make the visu_ui_gl_widget object %p current.\n", (gpointer)render); return FALSE; } DBG_fprintf(stderr, "Gtk OpenGL (glext): OK context changed.\n"); VISU_UI_GL_WIDGET_GET_CLASS(render)->contextCurrent = render; wd = GTK_WIDGET(render); setViewport(render, wd->allocation.width, wd->allocation.height, FALSE); return TRUE; } static void swapGl(VisuUiGlWidget *render) { g_return_if_fail(VISU_UI_GL_WIDGET_GET_CLASS(render)->contextCurrent == render); DBG_fprintf(stderr, "Gtk OpenGL (glext): swap buffers of area %p.\n", (gpointer)render); gdk_gl_drawable_swap_buffers(GDK_GL_DRAWABLE(render->glwindow)); } static GdkColormap* visu_ui_gl_widgetGet_openGLColormap(VisuUiGlWidget *render) { g_return_val_if_fail(render->glconfig, (GdkColormap*)0); return gdk_gl_config_get_colormap(render->glconfig); } #endif #ifdef IMPL_BUILTIN_X11 static void visu_ui_gl_widgetSet_pixelFormat(VisuUiGlWidget *render) { gint screenId; gboolean built; GdkScreen *screen; built = gtk_widget_get_visible(GTK_WIDGET(render)); DBG_fprintf(stderr, "Gtk OpenGL (X11): choose visual for %p.\n", (gpointer)render); if (built) render->dpy = GDK_DISPLAY_XDISPLAY(gtk_widget_get_display(GTK_WIDGET(render))); else render->dpy = gdk_x11_get_default_xdisplay(); DBG_fprintf(stderr, " | get the display %p.\n", (gpointer)render->dpy); /* XSynchronize(render->dpy, True); */ /* Get the screen id. */ if (built) screen = gtk_widget_get_screen(GTK_WIDGET(render)); else screen = gdk_screen_get_default(); screenId = gdk_x11_screen_get_screen_number(screen); DBG_fprintf(stderr, " | get a screen number %d.\n", screenId); render->vinfo = visu_gl_getVisualInfo(render->dpy, screenId); DBG_fprintf(stderr, " | get a visual %d.\n", (int)render->vinfo->visualid); render->visual = gdk_x11_screen_lookup_visual(screen, render->vinfo->visualid); } static void visu_ui_gl_widgetInit_context(VisuUiGlWidget *render, gboolean contextIsDirect) { DBG_fprintf(stderr, "Gtk OpenGL (X11): create an OpenGL context (%d).\n", contextIsDirect); /* Check for GLX. */ if (!glXQueryExtension(render->dpy, 0, 0)) { g_error("No GLX extension.\nYour X server" " does not support OpenGL extension. Please contact your" " system administrator to ask him to add the 'glx'" " extension to your X server.\n"); } /* Finaly, create the context. */ if (contextIsDirect) { render->context = glXCreateContext(render->dpy, render->vinfo, 0, GL_TRUE); if (!render->context) { g_warning("Can't create a direct rendering context, try an inderect one.\n"); render->context = glXCreateContext(render->dpy, render->vinfo, 0, GL_FALSE); render->isContextDirect = FALSE; } } else render->context = glXCreateContext(render->dpy, render->vinfo, 0, GL_FALSE); DBG_fprintf(stderr, " | create the context %p (%d).\n", (gpointer)render->context, (int)render->isContextDirect); if (!render->context) { g_error("Cannot create a GLX context.\n"); } } static void visu_ui_gl_widgetFree_openGL(VisuUiGlWidget *render) { g_return_if_fail(VISU_IS_UI_GL_WIDGET(render)); if (render->dpy) { DBG_fprintf(stderr, "Free (X11): freeing context (%p).\n", (gpointer)render->context); if (render->context) { glXMakeCurrent(render->dpy, None, NULL); glXWaitX(); glXDestroyContext(render->dpy, render->context); } if (render->vinfo) XFree(render->vinfo); /* We do NOT close the display since it is shared by all the application and thus dpy structure is unique and will be closed by GTK when quiting. */ /* XCloseDisplay(render->dpy); */ } } gboolean visu_ui_gl_widget_setCurrent(VisuUiGlWidget *render, gboolean force) { int res; GtkWidget *wd; XID windowId; GtkAllocation alloc; g_return_val_if_fail(VISU_IS_UI_GL_WIDGET(render), FALSE); if (!force && VISU_UI_GL_WIDGET_GET_CLASS(render)->contextCurrent == render) return TRUE; DBG_fprintf(stderr, "Gtk OpenGL (X11): unset the context.\n"); g_return_val_if_fail(render->dpy, FALSE); glXMakeCurrent(render->dpy, None, NULL); glXWaitX(); DBG_fprintf(stderr, "Gtk OpenGL (X11): widget visualID %d.\n", (int)gdk_x11_visual_get_xvisual (gtk_widget_get_visual(GTK_WIDGET(render)))->visualid); DBG_fprintf(stderr, "Gtk OpenGL (X11): %p is set current.\n", (gpointer)render); windowId = GDK_WINDOW_XID(GDK_WINDOW(gtk_widget_get_window(GTK_WIDGET(render)))); DBG_fprintf(stderr, "Gtk OpenGL (X11): widget windowID 0x%x.\n", (int)windowId); res = glXMakeCurrent(render->dpy, (GLXDrawable)windowId, render->context); if (!res) { g_warning("Cannot make the visu_ui_gl_widget object %p current.\n", (gpointer)render); return FALSE; } glXWaitX(); DBG_fprintf(stderr, "Gtk OpenGL (X11): OK context changed.\n"); visu_gl_text_onNewContext(); /* Now that the glx tunnel has been added, we need to specify again that we want a backing store because until now the backing store is only for the X window (and thus is black) but not for the glx screen. */ /* wattrs.backing_store = Always; */ /* XChangeWindowAttributes(render->dpy, windowId, */ /* CWBackingStore, &wattrs); */ VISU_UI_GL_WIDGET_GET_CLASS(render)->contextCurrent = render; wd = GTK_WIDGET(render); gtk_widget_get_allocation(wd, &alloc); setViewport(render, alloc.width, alloc.height, FALSE); return TRUE; } static void swapGl(VisuUiGlWidget *render) { g_return_if_fail(VISU_UI_GL_WIDGET_GET_CLASS(render)->contextCurrent == render); DBG_fprintf(stderr, "Gtk OpenGL (X11): swap buffers of area %p.\n", (gpointer)render); glXSwapBuffers(render->dpy, (GLXDrawable)GDK_WINDOW_XID(GDK_WINDOW(gtk_widget_get_window(GTK_WIDGET(render))))); DBG_fprintf(stderr, "Gtk OpenGL (X11): swap OK.\n"); } #if GTK_MAJOR_VERSION < 3 && GTK_MINOR_VERSION < 26 static GdkColormap* visu_ui_gl_widgetGet_openGLColormap(VisuUiGlWidget *render) { g_return_val_if_fail(VISU_IS_UI_GL_WIDGET(render), (GdkColormap*)0); g_return_val_if_fail(render->vinfo, (GdkColormap*)0); return gdk_colormap_new(gdkx_visual_get(render->vinfo->visualid), FALSE); } #endif #endif #ifdef IMPL_BUILTIN_WIN32 static void visu_ui_gl_widgetSet_pixelFormat(VisuUiGlWidget *render) { DBG_fprintf(stderr, "Gtk OpenGL (Win32): choose visual for %p.\n", render); render->windowId = (HWND)gdk_win32_window_get_handle(GDK_WINDOW(gtk_widget_get_window(GTK_WIDGET(render)))); render->hdc = GetDC(render->windowId); DBG_fprintf(stderr, " | get the hdc %d.\n", (int)render->hdc); visu_gl_setupPixelFormat(render->hdc); } static void visu_ui_gl_widgetInit_context(VisuUiGlWidget *render, gboolean contextIsDirect) { DBG_fprintf(stderr, "Gtk OpenGL (Win32): create an OpenGL context (%d).\n", contextIsDirect); /* Finaly, create the context. */ render->context = wglCreateContext(render->hdc); } static void visu_ui_gl_widgetFree_openGL(VisuUiGlWidget *render) { g_return_if_fail(VISU_IS_UI_GL_WIDGET(render)); if (render->context) wglDeleteContext(render->context); /* if (render->hdc) */ /* DeleteDC(render->hdc); */ } gboolean visu_ui_gl_widget_setCurrent(VisuUiGlWidget *render, gboolean force _U_) { GtkWidget *wd; GtkAllocation alloc; g_return_val_if_fail(VISU_IS_UI_GL_WIDGET(render), FALSE); DBG_fprintf(stderr, "Gtk OpenGL (action) : %p is set current.\n", (gpointer)render); wglMakeCurrent(NULL, NULL); wglMakeCurrent(render->hdc, render->context); visu_gl_text_onNewContext(); VISU_UI_GL_WIDGET_GET_CLASS(render)->contextCurrent = render; wd = GTK_WIDGET(render); gtk_widget_get_allocation(wd, &alloc); setViewport(render, alloc.width, alloc.height, FALSE); return TRUE; } static void swapGl(VisuUiGlWidget *render) { g_return_if_fail(VISU_UI_GL_WIDGET_GET_CLASS(render)->contextCurrent == render); DBG_fprintf(stderr, "Gtk OpenGL (action) : swap buffers of area %p.\n", (gpointer)render); SwapBuffers(render->hdc); } #if GTK_MAJOR_VERSION < 3 && GTK_MINOR_VERSION < 26 static GdkColormap* visu_ui_gl_widgetGet_openGLColormap(VisuUiGlWidget *render) { g_return_val_if_fail(VISU_IS_UI_GL_WIDGET(render), (GdkColormap*)0); return gdk_screen_get_system_colormap(gdk_screen_get_default()); } #endif #endif #ifdef IMPL_BUILTIN_QUARTZ static AGLPixelFmtID visu_gl_setupPixelFormat() { AGLPixelFmtID id; int list[] = { AGL_RGBA, AGL_RED_SIZE, 1, AGL_GREEN_SIZE, 1, AGL_BLUE_SIZE, 1, AGL_DEPTH_SIZE, 1, AGL_DOUBLEBUFFER, AGL_STEREO, AGL_NONE }; if ( (id = aglChoosePixelFmt(NULL, 0, list)) == NULL ) { list[10] = AGL_NONE; if ( (id = aglChoosePixelFmt(NULL, 0, list)) == NULL ) { g_error("Cannot find a pixel format."); } DBG_fprintf(stderr, " | not a stereo buffer.\n"); } else DBG_fprintf(stderr, " | stereo buffer.\n"); return id; } static void visu_ui_gl_widgetSet_pixelFormat(VisuUiGlWidget *render) { DBG_fprintf(stderr, "Gtk OpenGL (Quartz): choose visual for %p.\n", render); render->windowId = (NSWindow)gdk_quartz_window_get_nswindow(GDK_WINDOW(GTK_WIDGET(render)->window)); render->pxlfmt = visu_gl_setupPixelFormat(); render->visual = gdk_screen_get_system_visual(gdk_screen_get_default()); } static void visu_ui_gl_widgetInit_context(VisuUiGlWidget *render, gboolean contextIsDirect) { DBG_fprintf(stderr, "Gtk OpenGL (Quartz): create an OpenGL context (%d).\n", contextIsDirect); /* Finaly, create the context. */ render->context = aglCreateContext(render->pxlfmt, 0); } static void visu_ui_gl_widgetFree_openGL(VisuUiGlWidget *render) { g_return_if_fail(VISU_IS_UI_GL_WIDGET(render)); if (render->context) aglDestroyContext(render->context); /* if (render->hdc) */ /* DeleteDC(render->hdc); */ } gboolean visu_ui_gl_widget_setCurrent(VisuUiGlWidget *render, gboolean force _U_) { GtkWidget *wd; g_return_val_if_fail(VISU_IS_UI_GL_WIDGET(render), FALSE); DBG_fprintf(stderr, "Gtk OpenGL (Quartz): %p is set current.\n", (gpointer)render); aglMakeCurrent((AGLDrawable)render->windowId, render->context); /* visu_gl_text_onNewContext(); */ VISU_UI_GL_WIDGET_GET_CLASS(render)->contextCurrent = render; wd = GTK_WIDGET(render); setViewport(render, wd->allocation.width, wd->allocation.height, FALSE); return TRUE; } static void swapGl(VisuUiGlWidget *render) { g_return_if_fail(VISU_UI_GL_WIDGET_GET_CLASS(render)->contextCurrent == render); DBG_fprintf(stderr, "Gtk OpenGL (Quartz): swap buffers of area %p.\n", (gpointer)render); aglSwapBuffers((AGLDrawable)render->windowId); } #if GTK_MAJOR_VERSION < 3 && GTK_MINOR_VERSION < 26 static GdkColormap* visu_ui_gl_widgetGet_openGLColormap(VisuUiGlWidget *render) { g_return_val_if_fail(VISU_IS_UI_GL_WIDGET(render), (GdkColormap*)0); return gdk_screen_get_system_colormap(gdk_screen_get_default()); } #endif #endif v_sim-3.8.0/src/gtk_openGLWidget.h000066400000000000000000000110311370110300500167560ustar00rootroot00000000000000/* EXTRAITS DE LA LICENCE Copyright CEA, contributeurs : Luc BILLARD et Damien CALISTE, laboratoire L_Sim, (2001-2006) Adresse mèl : BILLARD, non joignable par mèl ; CALISTE, damien P caliste AT cea P fr. Ce logiciel est un programme informatique servant à visualiser des structures atomiques dans un rendu pseudo-3D. Ce logiciel est régi par la licence CeCILL soumise au droit français et respectant les principes de diffusion des logiciels libres. Vous pouvez utiliser, modifier et/ou redistribuer ce programme sous les conditions de la licence CeCILL telle que diffusée par le CEA, le CNRS et l'INRIA sur le site "http://www.cecill.info". Le fait que vous puissiez accéder à cet en-tête signifie que vous avez pris connaissance de la licence CeCILL, et que vous en avez accepté les termes (cf. le fichier Documentation/licence.fr.txt fourni avec ce logiciel). */ /* LICENCE SUM UP Copyright CEA, contributors : Luc BILLARD et Damien CALISTE, laboratoire L_Sim, (2001-2006) E-mail address: BILLARD, not reachable any more ; CALISTE, damien P caliste AT cea P fr. This software is a computer program whose purpose is to visualize atomic configurations in 3D. This software is governed by the CeCILL license under French law and abiding by the rules of distribution of free software. You can use, modify and/ or redistribute the software under the terms of the CeCILL license as circulated by CEA, CNRS and INRIA at the following URL "http://www.cecill.info". The fact that you are presently reading this means that you have had knowledge of the CeCILL license and that you accept its terms. You can find a copy of this licence shipped with this software at Documentation/licence.en.txt. */ #ifndef GTK_OPENGLWIDGET_H #define GTK_OPENGLWIDGET_H #include "visu_extset.h" /** * VisuUiGlWidget: * * Short name to address VisuUiGlWidget_struct objects. */ typedef struct _VisuUiGlWidget VisuUiGlWidget; /** * VisuUiGlWidgetClass: * * Short name to address VisuUiGlWidgetClass_struct objects. */ typedef struct _VisuUiGlWidgetClass VisuUiGlWidgetClass; /** * VISU_TYPE_UI_GL_WIDGET: * * The type of VisuUiGlWidget objects. */ #define VISU_TYPE_UI_GL_WIDGET (visu_ui_gl_widget_get_type()) /** * VISU_UI_GL_WIDGET: * @obj: a pointer. * * Cast @obj to VisuUiGlWidget if possible. */ #define VISU_UI_GL_WIDGET(obj) (G_TYPE_CHECK_INSTANCE_CAST((obj), \ VISU_TYPE_UI_GL_WIDGET, \ VisuUiGlWidget)) /** * VISU_UI_GL_WIDGET_CLASS: * @obj: a pointer. * * Cast @obj to VisuUiGlWidgetClass if possible. */ #define VISU_UI_GL_WIDGET_CLASS(obj) (G_TYPE_CHECK_CLASS_CAST((obj), \ VISU_TYPE_UI_GL_WIDGET, \ VisuUiGlWidgetClass)) /** * VISU_IS_UI_GL_WIDGET: * @obj: a pointer. * * Return TRUE is @obj is an VisuUiGlWidget object (or inherit from). */ #define VISU_IS_UI_GL_WIDGET(obj) (G_TYPE_CHECK_INSTANCE_TYPE((obj), \ VISU_TYPE_UI_GL_WIDGET)) /** * VISU_IS_UI_GL_WIDGET_CLASS: * @obj: a pointer. * * Return TRUE is @obj is an VisuUiGlWidgetClass object (or inherit from). */ #define VISU_IS_UI_GL_WIDGET_CLASS(obj) (G_TYPE_CHECK_CLASS_TYPE((obj), \ VISU_TYPE_UI_GL_WIDGET)) /** * VISU_UI_GL_WIDGET_GET_CLASS: * @obj: a pointer. * * Return the class of the given VisuUiGlWidget object. */ #define VISU_UI_GL_WIDGET_GET_CLASS(obj) (G_TYPE_INSTANCE_GET_CLASS((obj), \ VISU_TYPE_UI_GL_WIDGET, \ VisuUiGlWidgetClass)) /** * visu_ui_gl_widget_get_type: * * Retrive the type of VisuUiGlWidget objects. * * Returns: the id used by OBjects for VisuUiGlWidget objects. */ GType visu_ui_gl_widget_get_type(void); /** * visu_ui_gl_widget_new: * @contextIsDirect: a boolean. * * Create a new OpenGL area inside a GTK widget. If @contextIsDirect then * it tries to initialise the OpenGL context to a direct one. * * Returns: a newly created widget. */ GtkWidget* visu_ui_gl_widget_new(gboolean contextIsDirect); void visu_ui_gl_widget_setModel(VisuUiGlWidget *render, VisuGlExtSet *model); /** * visu_ui_gl_widget_setCurrent: * @render: a #VisuUiGlWidget object ; * @force: a boolean. * * Make this object current. This means that all future OpenGL primitive will be * rendered on this surface. If @force is TRUE, the GL routine is * actually called whereas in other cases, if @render believe being * already current, nothing is done. * * Returns: TRUE if succeed. */ gboolean visu_ui_gl_widget_setCurrent(VisuUiGlWidget *render, gboolean force); VisuUiGlWidget* visu_ui_gl_widget_class_getCurrentContext(); #endif v_sim-3.8.0/src/gtk_pairs.c000066400000000000000000000403171370110300500155500ustar00rootroot00000000000000/* EXTRAITS DE LA LICENCE Copyright CEA, contributeurs : Luc BILLARD et Damien CALISTE, laboratoire L_Sim, (2001-2005) Adresse mèl : BILLARD, non joignable par mèl ; CALISTE, damien P caliste AT cea P fr. Ce logiciel est un programme informatique servant à visualiser des structures atomiques dans un rendu pseudo-3D. Ce logiciel est régi par la licence CeCILL soumise au droit français et respectant les principes de diffusion des logiciels libres. Vous pouvez utiliser, modifier et/ou redistribuer ce programme sous les conditions de la licence CeCILL telle que diffusée par le CEA, le CNRS et l'INRIA sur le site "http://www.cecill.info". Le fait que vous puissiez accéder à cet en-tête signifie que vous avez pris connaissance de la licence CeCILL, et que vous en avez accepté les termes (cf. le fichier Documentation/licence.fr.txt fourni avec ce logiciel). */ /* LICENCE SUM UP Copyright CEA, contributors : Luc BILLARD et Damien CALISTE, laboratoire L_Sim, (2001-2005) E-mail address: BILLARD, not reachable any more ; CALISTE, damien P caliste AT cea P fr. This software is a computer program whose purpose is to visualize atomic configurations in 3D. This software is governed by the CeCILL license under French law and abiding by the rules of distribution of free software. You can use, modify and/ or redistribute the software under the terms of the CeCILL license as circulated by CEA, CNRS and INRIA at the following URL "http://www.cecill.info". The fact that you are presently reading this means that you have had knowledge of the CeCILL license and that you accept its terms. You can find a copy of this licence shipped with this software at Documentation/licence.en.txt. */ #include "gtk_pairs.h" #include "uiElements/ui_link.h" #include "uiElements/ui_pairtree.h" #include "extraGtkFunctions/gtk_curveWidget.h" #include "extraGtkFunctions/gtk_elementComboBox.h" #include "gtk_renderingWindowWidget.h" #include "interface.h" #include "support.h" #include #include #include "visu_tools.h" #include "visu_data.h" #include "visu_pairset.h" #include "extensions/pairs.h" /** * SECTION: gtk_pairs * @short_description: The pairs dialog. * * The pair dialog provides a list of pairs as min/max * distances between species to draw pairs. A set of two species can * have several pairs drawn. * This dialog also hosts widgets that depend on the pair method * that is used for a given link. * Finally, it has also a second tab where a graph of g(r) can * be drawn. */ /* static gulong unit_signal; */ static GtkWidget *uiLink, *uiTree; static GtkWidget *curve; static GtkWidget *spinDMin, *spinDMax, *spinDZoom; static GtkWidget *rangeHlStart, *rangeHlEnd, *checkHighlight, *labelIntegralDistance, *labelMeanDistance; /* Callbacks. */ static void _highlightRange(VisuUiCurveFrame *frame); #define GTK_PAIRS_HELP_TEXT _("Modifications, as color or wire width, are applied only to selected rows. Use to select more than one row at a time.") #define NO_DIST_INTEGRAL _("No distance analysis") #define DIST_INTEGRAL _("\342\200\242 there are %.3f neighbours per '%s'") #define NO_DIST_MEAN "" #define DIST_MEAN _("\342\200\242 mean distance is %.3f") static gboolean intToText(GBinding *bind, const GValue *source_value, GValue *target_value, gpointer data _U_) { gchar *label; if (g_value_get_float(source_value) > 0.f) { g_object_get(g_binding_get_source(bind), "label", &label, NULL); g_value_take_string(target_value, g_strdup_printf(DIST_INTEGRAL, g_value_get_float(source_value) * 2.f, label)); g_free(label); } else g_value_set_static_string(target_value, NO_DIST_INTEGRAL); return TRUE; } static gboolean meanToText(GBinding *bind _U_, const GValue *source_value, GValue *target_value, gpointer data _U_) { if (g_value_get_float(source_value) > 0.f) g_value_take_string(target_value, g_strdup_printf(DIST_MEAN, g_value_get_float(source_value))); else g_value_set_static_string(target_value, NO_DIST_MEAN); return TRUE; } void visu_ui_pairs_initBuild(VisuUiMain *main) { GtkWidget *wd, *vbox, *hbox, *vbox2; GtkWidget *viewport; GtkWidget *label; VisuGlNodeScene *scene; VisuGlExtPairs *pairs; VisuPairSet *pairSet; #if GTK_MAJOR_VERSION == 2 && GTK_MINOR_VERSION < 12 GtkTooltips *tooltips; tooltips = gtk_tooltips_new (); #endif scene = visu_ui_rendering_window_getGlScene(visu_ui_main_getRendering(main)); pairs = visu_gl_node_scene_getPairs(scene); DBG_fprintf(stderr, "Gtk Pairs: pairs has (%d) ref counts.\n", G_OBJECT(pairs)->ref_count); /* Create the listModel for pairs method*/ pairSet = visu_gl_ext_pairs_getSet(pairs); main->pairsDialog = create_pairsDialog(); gtk_window_set_type_hint(GTK_WINDOW(main->pairsDialog), GDK_WINDOW_TYPE_HINT_UTILITY); gtk_window_set_default_size(GTK_WINDOW(main->pairsDialog), 100, -1); gtk_widget_set_name(main->pairsDialog, "message"); wd = lookup_widget(main->pairsDialog, "labelTitlePairs"); gtk_widget_set_name(wd, "message_title"); wd = lookup_widget(main->pairsDialog, "scrolledwindowPairs"); gtk_scrolled_window_set_shadow_type(GTK_SCROLLED_WINDOW(wd), GTK_SHADOW_ETCHED_IN); gtk_widget_set_size_request(wd, -1, 175); viewport = lookup_widget(main->pairsDialog, "viewport1"); gtk_widget_set_name(viewport, "message_viewport"); gtk_widget_set_name(lookup_widget(main->pairsDialog, "notebookPairs"), "message_notebook"); wd = gtk_bin_get_child(GTK_BIN(viewport)); if (wd) gtk_widget_destroy(wd); /* Create the TreeView to represent the pairs data. */ DBG_fprintf(stderr, "Gtk Pairs: pairs has (%d) ref counts.\n", G_OBJECT(pairs)->ref_count); uiTree = visu_ui_pair_tree_new(pairs); visu_ui_pair_tree_bind(VISU_UI_PAIR_TREE(uiTree), pairSet); gtk_container_add(GTK_CONTAINER(viewport), uiTree); wd = lookup_widget(main->pairsDialog, "hbox73"); gtk_box_pack_start(GTK_BOX(wd), visu_ui_pair_tree_getToolbar(VISU_UI_PAIR_TREE(uiTree)), FALSE, FALSE, 0); vbox = lookup_widget(main->pairsDialog, "vboxPairsDialog"); uiLink = visu_ui_link_new(pairs); g_object_bind_property(uiTree, "selected-link", uiLink, "model", G_BINDING_SYNC_CREATE); g_object_bind_property(scene, "data", uiLink, "data", G_BINDING_SYNC_CREATE); g_signal_connect_swapped(G_OBJECT(uiTree), "selection-changed", G_CALLBACK(visu_ui_link_setAddLinks), uiLink); gtk_box_pack_start(GTK_BOX(vbox), uiLink, FALSE, FALSE, 0); gtk_widget_show_all(uiLink); hbox = lookup_widget(main->pairsDialog, "hboxPairsModel"); label = gtk_label_new("]"); gtk_box_pack_end(GTK_BOX(hbox), label, FALSE, FALSE, 0); wd = visu_ui_pair_tree_getFilter(VISU_UI_PAIR_TREE(uiTree)); gtk_box_pack_end(GTK_BOX(hbox), wd, FALSE, FALSE, 0); label = gtk_label_new(_("filter: ")); gtk_box_pack_end(GTK_BOX(hbox), label, FALSE, FALSE, 0); label = gtk_label_new("["); gtk_box_pack_end(GTK_BOX(hbox), label, FALSE, FALSE, 0); gtk_widget_show_all(hbox); /* The "Distances" page. */ vbox = lookup_widget(main->pairsDialog, "vboxDistances"); curve = visu_ui_curve_frame_new(0., 5.); visu_ui_curve_frame_setModel(VISU_UI_CURVE_FRAME(curve), pairSet); g_object_bind_property(visu_ui_pair_tree_getFilter(VISU_UI_PAIR_TREE(uiTree)), "element", curve, "filter", G_BINDING_SYNC_CREATE); gtk_widget_set_name(curve, "message_notebook"); visu_ui_curve_frame_setStyle(VISU_UI_CURVE_FRAME(curve), CURVE_LINEAR); gtk_box_pack_start(GTK_BOX(vbox), curve, TRUE, TRUE, 0); label = gtk_label_new(_("Parameters:")); gtk_label_set_use_markup(GTK_LABEL(label), TRUE); gtk_label_set_xalign(GTK_LABEL(label), 0.); gtk_box_pack_start(GTK_BOX(vbox), label, FALSE, FALSE, 0); hbox = gtk_hbox_new(FALSE, 3); gtk_box_pack_start(GTK_BOX(vbox), hbox, FALSE, FALSE, 0); label = gtk_label_new(_("min:")); gtk_label_set_xalign(GTK_LABEL(label), 1.); gtk_box_pack_start(GTK_BOX(hbox), label, TRUE, TRUE, 0); spinDMin = gtk_spin_button_new_with_range(0., 50., 0.1); gtk_spin_button_set_digits(GTK_SPIN_BUTTON(spinDMin), 2); g_object_bind_property(curve, "minimum", spinDMin, "value", G_BINDING_SYNC_CREATE | G_BINDING_BIDIRECTIONAL); gtk_box_pack_start(GTK_BOX(hbox), spinDMin, FALSE, FALSE, 0); label = gtk_label_new(_("max:")); gtk_label_set_xalign(GTK_LABEL(label), 1.); gtk_box_pack_start(GTK_BOX(hbox), label, TRUE, TRUE, 0); spinDMax = gtk_spin_button_new_with_range(0., 50., 0.1); gtk_spin_button_set_digits(GTK_SPIN_BUTTON(spinDMax), 2); g_object_bind_property(curve, "maximum", spinDMax, "value", G_BINDING_SYNC_CREATE | G_BINDING_BIDIRECTIONAL); gtk_box_pack_start(GTK_BOX(hbox), spinDMax, FALSE, FALSE, 0); label = gtk_label_new(_("step size:")); gtk_label_set_xalign(GTK_LABEL(label), 1.); gtk_box_pack_start(GTK_BOX(hbox), label, TRUE, TRUE, 0); spinDZoom = gtk_spin_button_new_with_range(1., 20., 1.); g_object_bind_property(curve, "zoom", spinDZoom, "value", G_BINDING_SYNC_CREATE); gtk_box_pack_start(GTK_BOX(hbox), spinDZoom, FALSE, FALSE, 0); label = gtk_label_new(_("Measurement tools:")); gtk_label_set_use_markup(GTK_LABEL(label), TRUE); gtk_label_set_xalign(GTK_LABEL(label), 0.); gtk_box_pack_start(GTK_BOX(vbox), label, FALSE, FALSE, 0); hbox = gtk_hbox_new(FALSE, 3); gtk_box_pack_start(GTK_BOX(vbox), hbox, FALSE, FALSE, 0); label = gtk_label_new(_("Range")); gtk_label_set_use_markup(GTK_LABEL(label), TRUE); gtk_label_set_xalign(GTK_LABEL(label), 1.); gtk_box_pack_start(GTK_BOX(hbox), label, FALSE, FALSE, 5); vbox2 = gtk_vbox_new(TRUE, 0); gtk_box_pack_start(GTK_BOX(hbox), vbox2, TRUE, TRUE, 0); rangeHlStart = gtk_hscale_new_with_range(0., 5., .05); g_object_bind_property(curve, "minimum", gtk_range_get_adjustment(GTK_RANGE(rangeHlStart)), "lower", G_BINDING_SYNC_CREATE); g_object_bind_property(curve, "maximum", gtk_range_get_adjustment(GTK_RANGE(rangeHlStart)), "upper", G_BINDING_SYNC_CREATE); g_object_bind_property(curve, "minimum-highlight", gtk_range_get_adjustment(GTK_RANGE(rangeHlStart)), "value", G_BINDING_SYNC_CREATE | G_BINDING_BIDIRECTIONAL); gtk_scale_set_draw_value(GTK_SCALE(rangeHlStart), FALSE); #if GTK_MAJOR_VERSION > 2 || GTK_MINOR_VERSION > 11 gtk_range_set_restrict_to_fill_level(GTK_RANGE(rangeHlStart), TRUE); gtk_range_set_show_fill_level(GTK_RANGE(rangeHlStart), TRUE); #endif gtk_box_pack_start(GTK_BOX(vbox2), rangeHlStart, FALSE, FALSE, 0); rangeHlEnd = gtk_hscale_new_with_range(0., 5., .05); g_object_bind_property(curve, "minimum", gtk_range_get_adjustment(GTK_RANGE(rangeHlEnd)), "lower", G_BINDING_SYNC_CREATE); g_object_bind_property(curve, "maximum", gtk_range_get_adjustment(GTK_RANGE(rangeHlEnd)), "upper", G_BINDING_SYNC_CREATE); g_object_bind_property(curve, "maximum-highlight", gtk_range_get_adjustment(GTK_RANGE(rangeHlEnd)), "value", G_BINDING_SYNC_CREATE | G_BINDING_BIDIRECTIONAL); #if GTK_MAJOR_VERSION > 2 || GTK_MINOR_VERSION > 11 g_object_bind_property(gtk_range_get_adjustment(GTK_RANGE(rangeHlEnd)), "value", rangeHlStart, "fill-level", G_BINDING_SYNC_CREATE); #endif gtk_scale_set_draw_value(GTK_SCALE(rangeHlEnd), FALSE); gtk_box_pack_start(GTK_BOX(vbox2), rangeHlEnd, FALSE, FALSE, 0); vbox2 = gtk_vbox_new(TRUE, 0); gtk_box_pack_start(GTK_BOX(hbox), vbox2, FALSE, FALSE, 0); checkHighlight = gtk_check_button_new_with_mnemonic(_("_Highlight nodes in range")); g_signal_connect_swapped(G_OBJECT(checkHighlight), "toggled", G_CALLBACK(_highlightRange), curve); gtk_box_pack_start(GTK_BOX(vbox2), checkHighlight, FALSE, FALSE, 0); labelIntegralDistance = gtk_label_new(NO_DIST_INTEGRAL); gtk_label_set_use_markup(GTK_LABEL(labelIntegralDistance), TRUE); gtk_label_set_xalign(GTK_LABEL(labelIntegralDistance), 0.); gtk_widget_set_margin_start(labelIntegralDistance, 10); g_object_bind_property_full(curve, "integral-in-range", labelIntegralDistance, "label", G_BINDING_SYNC_CREATE, intToText, NULL, NULL, NULL); gtk_box_pack_start(GTK_BOX(vbox2), labelIntegralDistance, FALSE, FALSE, 0); labelMeanDistance = gtk_label_new(NO_DIST_MEAN); gtk_label_set_use_markup(GTK_LABEL(labelMeanDistance), TRUE); gtk_label_set_xalign(GTK_LABEL(labelMeanDistance), 0.); gtk_widget_set_margin_start(labelMeanDistance, 10); g_object_bind_property_full(curve, "mean-in-range", labelMeanDistance, "label", G_BINDING_SYNC_CREATE, meanToText, NULL, NULL, NULL); gtk_box_pack_start(GTK_BOX(vbox2), labelMeanDistance, FALSE, FALSE, 0); g_signal_connect(curve, "notify::filter", G_CALLBACK(_highlightRange), (gpointer)0); g_signal_connect(curve, "notify::minimum-highlight", G_CALLBACK(_highlightRange), (gpointer)0); g_signal_connect(curve, "notify::maximum-highlight", G_CALLBACK(_highlightRange), (gpointer)0); gtk_widget_show_all(vbox); DBG_fprintf(stderr, "Gtk Pairs: Pairs are first built.\n"); } /*************/ /* Callbacks */ /*************/ static void _highlightRange(VisuUiCurveFrame *frame) { float range[2]; GArray *ids; gfloat d2, xyz1[3], xyz2[3]; VisuElement *ele; VisuData *dataObj; VisuNodeArrayIter iter1, iter2; VisuGlExtMarks *marks; VisuUiRenderingWindow *window; if (!visu_ui_curve_frame_getHighlightRange(frame, range)) return; range[0] *= range[0]; range[1] *= range[1]; g_object_get(frame, "filter", &ele, NULL); window = visu_ui_main_class_getDefaultRendering(); marks = visu_gl_node_scene_getMarks(visu_ui_rendering_window_getGlScene(window)); ids = g_object_get_data(G_OBJECT(frame), "HighlightRangeIds"); if (ids) { DBG_fprintf(stderr, "Gtk Pairs: remove %d highlights.\n", ids->len); visu_gl_ext_marks_setHighlight(marks, ids, MARKS_STATUS_UNSET); g_object_set_data(G_OBJECT(frame), "HighlightRangeIds", (gpointer)0); } if (gtk_toggle_button_get_active(GTK_TOGGLE_BUTTON(checkHighlight))) { ids = g_array_new(FALSE, FALSE, sizeof(guint)); dataObj = visu_gl_node_scene_getData(visu_ui_rendering_window_getGlScene(window)); visu_node_array_iter_new(VISU_NODE_ARRAY(dataObj), &iter1); visu_node_array_iter_new(VISU_NODE_ARRAY(dataObj), &iter2); for(visu_node_array_iterStart(VISU_NODE_ARRAY(dataObj), &iter1), visu_node_array_iterStart(VISU_NODE_ARRAY(dataObj), &iter2); iter1.node && iter2.node; visu_node_array_iter_next2(&iter1, &iter2)) if (visu_element_getRendered(iter1.element) && visu_element_getRendered(iter2.element) && iter1.node->rendered && iter2.node->rendered && (!ele || (ele && (iter1.element == ele || iter2.element == ele)))) { visu_data_getNodePosition(dataObj, iter1.node, xyz1); visu_data_getNodePosition(dataObj, iter2.node, xyz2); d2 = (xyz1[0] - xyz2[0]) * (xyz1[0] - xyz2[0]) + (xyz1[1] - xyz2[1]) * (xyz1[1] - xyz2[1]) + (xyz1[2] - xyz2[2]) * (xyz1[2] - xyz2[2]); if (d2 >= range[0] && d2 < range[1]) { g_array_append_val(ids, iter1.node->number); g_array_append_val(ids, iter2.node->number); /* DBG_fprintf(stderr, "Test pair %d-%d %f\n", */ /* iter1.node->number, iter2.node->number, d2); */ visu_node_array_iterNext(VISU_NODE_ARRAY(dataObj), &iter1); visu_node_array_iterStart(VISU_NODE_ARRAY(dataObj), &iter2); } } g_object_set_data_full(G_OBJECT(frame), "HighlightRangeIds", ids, (GDestroyNotify)g_array_unref); DBG_fprintf(stderr, "Gtk Pairs: add %d highlights.\n", ids->len); visu_gl_ext_marks_setHighlight(marks, ids, MARKS_STATUS_SET); } if (ele) g_object_unref(ele); } v_sim-3.8.0/src/gtk_pairs.h000066400000000000000000000065721370110300500155620ustar00rootroot00000000000000/* EXTRAITS DE LA LICENCE Copyright CEA, contributeurs : Luc BILLARD et Damien CALISTE, laboratoire L_Sim, (2001-2005) Adresse mèl : BILLARD, non joignable par mèl ; CALISTE, damien P caliste AT cea P fr. Ce logiciel est un programme informatique servant à visualiser des structures atomiques dans un rendu pseudo-3D. Ce logiciel est régi par la licence CeCILL soumise au droit français et respectant les principes de diffusion des logiciels libres. Vous pouvez utiliser, modifier et/ou redistribuer ce programme sous les conditions de la licence CeCILL telle que diffusée par le CEA, le CNRS et l'INRIA sur le site "http://www.cecill.info". Le fait que vous puissiez accéder à cet en-tête signifie que vous avez pris connaissance de la licence CeCILL, et que vous en avez accepté les termes (cf. le fichier Documentation/licence.fr.txt fourni avec ce logiciel). */ /* LICENCE SUM UP Copyright CEA, contributors : Luc BILLARD et Damien CALISTE, laboratoire L_Sim, (2001-2005) E-mail address: BILLARD, not reachable any more ; CALISTE, damien P caliste AT cea P fr. This software is a computer program whose purpose is to visualize atomic configurations in 3D. This software is governed by the CeCILL license under French law and abiding by the rules of distribution of free software. You can use, modify and/ or redistribute the software under the terms of the CeCILL license as circulated by CEA, CNRS and INRIA at the following URL "http://www.cecill.info". The fact that you are presently reading this means that you have had knowledge of the CeCILL license and that you accept its terms. You can find a copy of this licence shipped with this software at Documentation/licence.en.txt. */ #ifndef GTK_PAIRS_H #define GTK_PAIRS_H #include #include "interface.h" #include "support.h" #include "visu_pairs.h" #include "gtk_main.h" /** * VisuUiPairsInitFunc: * * Prototype of functions called once on V_Sim start-up. */ typedef void (*VisuUiPairsInitFunc)(void); /** * VisuUiPairsBuildWidgetsFunc: * * Prototype of functions that create a container #GtkWidgets will all * element needed to change characteristic of a model. * * Returns: a newly allocated #GtkWidget. */ typedef GtkWidget* (*VisuUiPairsBuildWidgetsFunc)(); /** * VisuUiPairsToLabelFunc: * @data: information about a pair. * * Create a string, internationalised and in UTF-8, that describes the * given pair @data. This string is used in a column tree view to * summarize the pair description. * * Returns: a newly created string. */ typedef gchar* (*VisuUiPairsToLabelFunc)(VisuPairLink *data); /** * VisuUiPairsSetValuesFunc: * @data: informations about a pair. * * Prototype of functions used to update the widgets with given pair @data. */ typedef void (*VisuUiPairsSetValuesFunc)(VisuPairLink *data); /** * visu_ui_pairs_initBuild: * @main: the command panel the about dialog is associated to. * * Create the dialog window for pairs. */ void visu_ui_pairs_initBuild(VisuUiMain *main); /** * visu_ui_pairs_setSpecificLabels: * @iter: the #GtkTreeIter to set the label ; * @label: the value of the label to be set. * * Change the specific label shown in the treeview of pairs for the * given iter. An iter in this treeview can be retrieve using the * #_VisuUiPairsIter objects. */ void visu_ui_pairs_setSpecificLabels(GtkTreeIter *iter, const gchar *label); #endif v_sim-3.8.0/src/gtk_pick.c000066400000000000000000001200551370110300500153560ustar00rootroot00000000000000/* EXTRAITS DE LA LICENCE Copyright CEA, contributeurs : Luc BILLARD et Damien CALISTE, laboratoire L_Sim, (2001-2005) Adresse mèl : BILLARD, non joignable par mèl ; CALISTE, damien P caliste AT cea P fr. Ce logiciel est un programme informatique servant à visualiser des structures atomiques dans un rendu pseudo-3D. Ce logiciel est régi par la licence CeCILL soumise au droit français et respectant les principes de diffusion des logiciels libres. Vous pouvez utiliser, modifier et/ou redistribuer ce programme sous les conditions de la licence CeCILL telle que diffusée par le CEA, le CNRS et l'INRIA sur le site "http://www.cecill.info". Le fait que vous puissiez accéder à cet en-tête signifie que vous avez pris connaissance de la licence CeCILL, et que vous en avez accepté les termes (cf. le fichier Documentation/licence.fr.txt fourni avec ce logiciel). */ /* LICENCE SUM UP Copyright CEA, contributors : Luc BILLARD et Damien CALISTE, laboratoire L_Sim, (2001-2005) E-mail address: BILLARD, not reachable any more ; CALISTE, damien P caliste AT cea P fr. This software is a computer program whose purpose is to visualize atomic configurations in 3D. This software is governed by the CeCILL license under French law and abiding by the rules of distribution of free software. You can use, modify and/ or redistribute the software under the terms of the CeCILL license as circulated by CEA, CNRS and INRIA at the following URL "http://www.cecill.info". The fact that you are presently reading this means that you have had knowledge of the CeCILL license and that you accept its terms. You can find a copy of this licence shipped with this software at Documentation/licence.en.txt. */ #include #include #include #include #include "support.h" #include "gtk_interactive.h" #include "visu_gtk.h" #include "gtk_main.h" #include "gtk_pick.h" #include "visu_basic.h" #include "gtk_renderingWindowWidget.h" #include "extensions/infos.h" #include "extensions/marks.h" #include "extraFunctions/idProp.h" #include "openGLFunctions/interactive.h" #include "extraGtkFunctions/gtk_valueIOWidget.h" #include "uiElements/ui_properties.h" /** * SECTION: gtk_pick * @short_description: The pick and measurement tab in the interactive * dialog. * * This action tab provides widgets to display information about * selected atoms, like distances or angles. In addition, measured * distances and angles are kept in a list when new files are * loaded. * With the list of selected nodes, one can modify properties * associated to nodes like their coordinates, the value of * colourisation if any, the forces on them, if any... One can also * decide to display information directly on nodes. */ #define GTK_PICK_INFO \ _("left-button\t\t\t: standard pick\n" \ "control-left-button\t\t: toggle highlihgt node\n" \ "middle-button\t\t: measure node neighbouring\n" \ "shift-middle-button\t: pick 1st reference\n" \ "ctrl-middle-button\t\t: pick 2nd reference\n" \ "drag-left-button\t\t: make a rectangular selection\n" \ "right-button\t\t\t: switch to observe") /* Treeview used to print data of nodes. */ static VisuUiSelection *listPickedNodes; static GtkWidget *treeviewPickedNodes, *labelSelection; #define GTK_PICK_EDITABLE_NODE "blue" #define GTK_PICK_UNEDITABLE_NODE "black" /* Draw data widgets. */ static GtkWidget *tglMarks; static VisuInteractive *interPick = NULL; /* The pick viewport. */ static GtkWidget *labelPickOut, *labelPickHistory = (GtkWidget*)0, *labelPickError; struct _PickHistory { VisuData *dataObj; gchar *str; }; static GList *pickHistory = (GList*)0; /* Signals that need to be suspended */ static VisuData *currentData; static gulong propAdd_signal, propRemoved_signal; /* Local callbacks. */ static void onEditedValue(GtkCellRendererText *cellrenderertext, gchar *path, gchar *text, gpointer user_data); static void onDrawDistanceChecked(GtkToggleButton* button, gpointer data); static void onEraseDistanceClicked(GtkButton *button, gpointer user_data); static gboolean onTreeviewInfosKey(GtkWidget *widget, GdkEventKey *event, gpointer user_data); static void onHighlightHideToggled(GtkToggleButton *button, gpointer user_data); static void onHighlightHideStatus(GtkButton *button, gpointer user_data); static void onNodeSelection(VisuInteractive *inter, VisuInteractivePick pick, VisuData *dataObj, VisuNode *node0, VisuNode *node1, VisuNode *node2, gpointer data); static void onSelectionError(VisuInteractive *inter, VisuInteractivePickError error, gpointer data); static void onMeasurementList(VisuGlExtMarks *marks, VisuData *dataObj, gpointer data); static void onNodeValueChanged(VisuNodeValues *values, VisuNode *node); static void onDataNotify(VisuGlNodeScene *scene); /* Local routines. */ static void _setData(VisuData *dataObj); static gboolean onLoadXML(const gchar *filename, GError **error); static gboolean onSaveXML(const gchar *filename, GError **error); static void _addColumn(GtkTreeView *view, VisuNodeValues *prop); static void _removeColumn(GtkTreeView *view, VisuNodeValues *prop); static void _togglePath(VisuUiSelection *selection, gchar *path); /********************/ /* Public routines. */ /********************/ /** * visu_ui_interactive_pick_init: (skip) * * Internal routine to setup the pick action of the interactive dialog. * * Since: 3.6 */ void visu_ui_interactive_pick_init() { listPickedNodes = visu_ui_selection_new(); labelSelection = gtk_box_new(GTK_ORIENTATION_HORIZONTAL, 0); currentData = (VisuData*)0; } static gboolean _haveNodes(GBinding *bind _U_, const GValue *from, GValue *to, gpointer data _U_) { GArray *ids; ids = (GArray*)g_value_get_boxed(from); g_value_set_boolean(to, ids && ids->len > 0); return TRUE; } static gboolean _toLblMarks(GBinding *bind _U_, const GValue *from, GValue *to, gpointer data _U_) { GArray *ids; ids = (GArray*)g_value_get_boxed(from); if (ids && ids->len) g_value_take_string(to, g_strdup_printf(_("Highlights (%d):"), ids->len)); else g_value_set_string(to, _("Highlights (none):")); return TRUE; } static gboolean _toLblList(GBinding *bind, const GValue *from _U_, GValue *to, gpointer data _U_) { gint n; n = gtk_tree_model_iter_n_children(GTK_TREE_MODEL(g_binding_get_source(bind)), NULL); if (n > 0) g_value_take_string(to, g_strdup_printf(_("List of %d node(s):"), n)); else g_value_set_string(to, _("List of nodes (none):")); return TRUE; } static gboolean _toDrawSelected(GBinding *bind, const GValue *from, GValue *to, gpointer data _U_) { GArray *nodes = g_value_get_boxed(from); g_value_set_boolean(to, (nodes && nodes->len) && visu_gl_ext_getActive(VISU_GL_EXT(g_binding_get_source(bind)))); return g_value_get_boolean(to); } static gboolean _fromDrawSelected(GBinding *bind _U_, const GValue *from, GValue *to, gpointer data) { if (g_value_get_boolean(from)) g_value_take_boxed(to, visu_ui_selection_get(VISU_UI_SELECTION(data))); return g_value_get_boolean(from); } static gboolean _toDrawAlways(GBinding *bind, const GValue *from, GValue *to, gpointer data _U_) { GArray *nodes = g_value_get_boxed(from); g_value_set_boolean(to, (!nodes || !nodes->len) && visu_gl_ext_getActive(VISU_GL_EXT(g_binding_get_source(bind)))); return g_value_get_boolean(to); } static gboolean _fromDrawAlways(GBinding *bind _U_, const GValue *from, GValue *to, gpointer data _U_) { if (g_value_get_boolean(from)) g_value_take_boxed(to, (gpointer)0); return g_value_get_boolean(from); } static gboolean _toSelection(GBinding *bind _U_, const GValue *from, GValue *to, gpointer data) { if (!gtk_toggle_button_get_active(GTK_TOGGLE_BUTTON(data))) return FALSE; g_value_set_boxed(to, g_value_get_boxed(from)); return TRUE; } /** * visu_ui_interactive_pick_initBuild: (skip) * @main: the main interface. * @label: a location to store the name of the pick tab ; * @help: a location to store the help message to be shown at the * bottom of the window ; * @radio: a location on the radio button that will be toggled when * the pick action is used. * * This routine should be called in conjonction to the * visu_ui_interactive_move_initBuild() one. It completes the creation of widgets * (and also initialisation of values) for the pick tab. */ GtkWidget* visu_ui_interactive_pick_initBuild(VisuUiMain *main, gchar **label, gchar **help, GtkWidget **radio) { GtkTreeViewColumn *column; GtkCellRenderer *renderer; GtkWidget *lbl, *wd, *wd2, *hbox, *vbox, *image; GtkWidget *valueIO, *hboxMarks, *comboDraw; GtkWidget *radioDrawNever, *radioDrawSelected, *radioDrawAlways; GSList *radioDrawNever_group = NULL; GtkToolItem *item; VisuUiRenderingWindow *window; VisuGlExtMarks *marks; VisuGlExtInfos *infos; VisuGlNodeScene *scene; #if GTK_MAJOR_VERSION == 2 && GTK_MINOR_VERSION < 12 GtkTooltips *tooltips; tooltips = gtk_tooltips_new (); #endif DBG_fprintf(stderr, "Gtk Pick: setup new action tab.\n"); window = visu_ui_main_class_getDefaultRendering(); interPick = visu_interactive_new(interactive_measure); scene = visu_ui_rendering_window_getGlScene(window); g_signal_connect(G_OBJECT(interPick), "node-selection", G_CALLBACK(onNodeSelection), (gpointer)0); g_signal_connect(G_OBJECT(interPick), "selection-error", G_CALLBACK(onSelectionError), (gpointer)0); g_signal_connect_swapped(G_OBJECT(interPick), "region-selection", G_CALLBACK(visu_ui_selection_append), listPickedNodes); g_signal_connect(G_OBJECT(interPick), "stop", G_CALLBACK(visu_ui_interactive_toggle), (gpointer)0); marks = visu_gl_node_scene_getMarks(scene); infos = visu_gl_node_scene_getInfos(scene); g_signal_connect(G_OBJECT(marks), "measurementChanged", G_CALLBACK(onMeasurementList), (gpointer)0); *label = g_strdup("Pick"); *help = g_strdup(GTK_PICK_INFO); *radio = lookup_widget(main->interactiveDialog, "radioPick"); vbox = lookup_widget(main->interactiveDialog, "vbox25"); hbox = gtk_hbox_new(FALSE, 0); gtk_box_pack_start(GTK_BOX(vbox), hbox, FALSE, FALSE, 0); lbl = gtk_label_new(""); gtk_box_pack_start(GTK_BOX(hbox), lbl, FALSE, FALSE, 0); gtk_label_set_use_markup(GTK_LABEL(lbl), TRUE); g_object_bind_property_full(listPickedNodes, "selection", lbl, "label", G_BINDING_SYNC_CREATE, _toLblList, NULL, (gpointer)0, (GDestroyNotify)0); gtk_box_pack_start(GTK_BOX(hbox), labelSelection, TRUE, TRUE, 0); lbl = gtk_label_new(_("Values in blue are editable")); gtk_box_pack_end(GTK_BOX(hbox), lbl, FALSE, FALSE, 0); gtk_label_set_use_markup(GTK_LABEL(lbl), TRUE); image = gtk_image_new_from_icon_name("help-browser", GTK_ICON_SIZE_MENU); gtk_box_pack_end(GTK_BOX(hbox), image, FALSE, FALSE, 0); gtk_widget_set_margin_end(image, 3); /* Create the treeview and related buttons. */ DBG_fprintf(stderr, "Gtk Pick: Create the treeview and related buttons.\n"); hbox = gtk_hbox_new(FALSE, 0); gtk_box_pack_start(GTK_BOX(vbox), hbox, TRUE, TRUE, 0); g_signal_connect_swapped(hbox, "destroy", G_CALLBACK(g_object_unref), interPick); wd = gtk_scrolled_window_new(NULL, NULL); gtk_widget_set_size_request(wd, -1, 120); gtk_box_pack_start(GTK_BOX(hbox), wd, TRUE, TRUE, 0); gtk_scrolled_window_set_policy(GTK_SCROLLED_WINDOW(wd), GTK_POLICY_AUTOMATIC, GTK_POLICY_AUTOMATIC); gtk_scrolled_window_set_shadow_type(GTK_SCROLLED_WINDOW(wd), GTK_SHADOW_IN); treeviewPickedNodes = gtk_tree_view_new (); gtk_container_add(GTK_CONTAINER(wd), treeviewPickedNodes); gtk_tree_view_set_model(GTK_TREE_VIEW(treeviewPickedNodes), GTK_TREE_MODEL(listPickedNodes)); g_object_unref(listPickedNodes); g_signal_connect(G_OBJECT(treeviewPickedNodes), "key-press-event", G_CALLBACK(onTreeviewInfosKey), (gpointer)0); gtk_tree_selection_set_mode (gtk_tree_view_get_selection(GTK_TREE_VIEW(treeviewPickedNodes)), GTK_SELECTION_MULTIPLE); wd = gtk_toolbar_new(); gtk_orientable_set_orientation(GTK_ORIENTABLE(wd), GTK_ORIENTATION_VERTICAL); gtk_toolbar_set_style(GTK_TOOLBAR(wd), GTK_TOOLBAR_ICONS); gtk_toolbar_set_icon_size(GTK_TOOLBAR(wd), GTK_ICON_SIZE_SMALL_TOOLBAR); gtk_box_pack_end(GTK_BOX(hbox), wd, FALSE, FALSE, 0); item = gtk_toggle_tool_button_new(); gtk_widget_set_tooltip_text(GTK_WIDGET(item), _("Set / unset highlight status following selection.")); gtk_toolbar_insert(GTK_TOOLBAR(wd), item, -1); gtk_tool_button_set_icon_widget(GTK_TOOL_BUTTON(item), create_pixmap((GtkWidget*)0, "stock-select-all_20.png")); g_object_bind_property(listPickedNodes, "highlight", item, "active", G_BINDING_SYNC_CREATE | G_BINDING_BIDIRECTIONAL); item = gtk_tool_button_new(NULL, NULL); gtk_widget_set_tooltip_text(GTK_WIDGET(item), _("Empty the selection list.")); gtk_tool_button_set_icon_name(GTK_TOOL_BUTTON(item), "edit-clear"); g_signal_connect_swapped(G_OBJECT(item), "clicked", G_CALLBACK(visu_ui_selection_clear), listPickedNodes); gtk_toolbar_insert(GTK_TOOLBAR(wd), item, -1); lbl = gtk_label_new(_("Draw data on nodes")); gtk_box_pack_start(GTK_BOX(vbox), lbl, FALSE, FALSE, 0); gtk_label_set_use_markup(GTK_LABEL(lbl), TRUE); gtk_label_set_xalign(GTK_LABEL(lbl), 0); hbox = gtk_hbox_new(FALSE, 0); gtk_box_pack_start(GTK_BOX(vbox), hbox, FALSE, FALSE, 0); radioDrawNever = gtk_radio_button_new_with_mnemonic(NULL, _("none")); g_object_bind_property(infos, "active", radioDrawNever, "active", G_BINDING_SYNC_CREATE | G_BINDING_BIDIRECTIONAL | G_BINDING_INVERT_BOOLEAN); gtk_widget_set_name(radioDrawNever, "message_radio"); gtk_box_pack_start(GTK_BOX(hbox), radioDrawNever, FALSE, FALSE, 0); gtk_radio_button_set_group(GTK_RADIO_BUTTON(radioDrawNever), radioDrawNever_group); radioDrawNever_group = gtk_radio_button_get_group(GTK_RADIO_BUTTON(radioDrawNever)); radioDrawSelected = gtk_radio_button_new_with_mnemonic(NULL, _("listed")); gtk_widget_set_name(radioDrawSelected, "message_radio"); g_object_bind_property_full(infos, "selection", radioDrawSelected, "active", G_BINDING_SYNC_CREATE | G_BINDING_BIDIRECTIONAL, _toDrawSelected, _fromDrawSelected, listPickedNodes, (GDestroyNotify)0); g_object_bind_property_full(listPickedNodes, "selection", radioDrawSelected, "sensitive", G_BINDING_SYNC_CREATE, _haveNodes, NULL, (gpointer)0, (GDestroyNotify)0); gtk_box_pack_start(GTK_BOX(hbox), radioDrawSelected, FALSE, FALSE, 0); gtk_radio_button_set_group(GTK_RADIO_BUTTON(radioDrawSelected), radioDrawNever_group); radioDrawNever_group = gtk_radio_button_get_group(GTK_RADIO_BUTTON(radioDrawSelected)); radioDrawAlways = gtk_radio_button_new_with_mnemonic (NULL, _("all")); gtk_widget_set_name(radioDrawAlways, "message_radio"); g_object_bind_property_full(infos, "selection", radioDrawAlways, "active", G_BINDING_SYNC_CREATE | G_BINDING_BIDIRECTIONAL, _toDrawAlways, _fromDrawAlways, (gpointer)0, (GDestroyNotify)0); gtk_box_pack_start(GTK_BOX(hbox), radioDrawAlways, TRUE, TRUE, 0); gtk_radio_button_set_group(GTK_RADIO_BUTTON(radioDrawAlways), radioDrawNever_group); radioDrawNever_group = gtk_radio_button_get_group(GTK_RADIO_BUTTON(radioDrawAlways)); comboDraw = visu_ui_combo_values_new(); gtk_widget_show(comboDraw); gtk_box_pack_start(GTK_BOX(hbox), comboDraw, TRUE, TRUE, 0); g_object_bind_property(scene, "data", comboDraw, "model", G_BINDING_SYNC_CREATE); g_object_bind_property(infos, "values", comboDraw, "active-values", G_BINDING_SYNC_CREATE | G_BINDING_BIDIRECTIONAL); gtk_widget_show_all(vbox); /* Building headers. */ DBG_fprintf(stderr, "Gtk Pick: Build the tree view.\n"); /* Highlight colum. */ renderer = gtk_cell_renderer_toggle_new(); g_signal_connect_swapped(G_OBJECT(renderer), "toggled", G_CALLBACK(_togglePath), listPickedNodes); g_object_set(G_OBJECT(renderer), "indicator-size", 10, NULL); column = gtk_tree_view_column_new_with_attributes("", renderer, "active", VISU_UI_SELECTION_HIGHLIGHT, NULL); gtk_tree_view_column_set_sort_column_id(column, VISU_UI_SELECTION_HIGHLIGHT); gtk_tree_view_append_column (GTK_TREE_VIEW(treeviewPickedNodes), column); /* Set the load/save widget. */ DBG_fprintf(stderr, "Gtk Pick: Add some widgets.\n"); valueIO = visu_ui_value_io_new(GTK_WINDOW(main->interactiveDialog), _("Import picked nodes from an existing XML file."), _("Export listed picked nodes to the current XML file."), _("Export listed picked nodes to a new XML file.")); visu_ui_value_io_setSensitiveOpen(VISU_UI_VALUE_IO(valueIO), TRUE); visu_ui_value_io_connectOnOpen(VISU_UI_VALUE_IO(valueIO), onLoadXML); visu_ui_value_io_connectOnSave(VISU_UI_VALUE_IO(valueIO), onSaveXML); g_object_bind_property_full(listPickedNodes, "selection", valueIO, "sensitive-save", G_BINDING_SYNC_CREATE, _haveNodes, NULL, (gpointer)0, (GDestroyNotify)0); gtk_widget_show_all(valueIO); wd = lookup_widget(main->interactiveDialog, "hboxPick"); gtk_box_pack_end(GTK_BOX(wd), valueIO, TRUE, TRUE, 10); /* Set the names and load the widgets. */ labelPickOut = lookup_widget(main->interactiveDialog, "pickInfo"); labelPickHistory = gtk_label_new(""); gtk_widget_show(labelPickHistory); gtk_box_pack_start(GTK_BOX(lookup_widget(main->interactiveDialog, "vbox24")), labelPickHistory, FALSE, FALSE, 0); gtk_label_set_use_markup(GTK_LABEL(labelPickHistory), TRUE); gtk_label_set_selectable(GTK_LABEL(labelPickHistory), TRUE); gtk_widget_set_margin_start(labelPickHistory, 15); labelPickError = lookup_widget(main->interactiveDialog, "pickComment"); gtk_widget_set_name(labelPickError, "label_error"); wd = lookup_widget(main->interactiveDialog, "viewportPick"); gtk_widget_set_name(wd, "message_viewport"); wd = lookup_widget(main->interactiveDialog, "checkDrawDistance"); gtk_widget_set_name(wd, "message_radio"); g_signal_connect(G_OBJECT(wd), "toggled", G_CALLBACK(onDrawDistanceChecked), (gpointer)marks); wd = lookup_widget(main->interactiveDialog, "buttonEraseDistances"); g_signal_connect(G_OBJECT(wd), "clicked", G_CALLBACK(onEraseDistanceClicked), (gpointer)marks); hboxMarks = lookup_widget(main->interactiveDialog, "hboxMarks"); g_object_bind_property_full(marks, "highlight", hboxMarks, "sensitive", G_BINDING_SYNC_CREATE, _haveNodes, NULL, (gpointer)0, (GDestroyNotify)0); wd = lookup_widget(main->interactiveDialog, "buttonEraseMarks"); g_signal_connect_swapped(G_OBJECT(wd), "clicked", G_CALLBACK(visu_gl_ext_marks_unHighlight), (gpointer)marks); wd = lookup_widget(main->interactiveDialog, "buttonSetMarks"); g_signal_connect_swapped(G_OBJECT(wd), "clicked", G_CALLBACK(visu_ui_selection_appendHighlightedNodes), listPickedNodes); tglMarks = gtk_toggle_button_new(); gtk_widget_set_tooltip_text(tglMarks, _("Hide nodes depending on highlight status.")); gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON(tglMarks), visu_gl_ext_marks_getHidingMode(marks) != HIDE_NONE); image = create_pixmap((GtkWidget*)0, "stock-masking.png"); gtk_container_add(GTK_CONTAINER(tglMarks), image); gtk_box_pack_start(GTK_BOX(hboxMarks), tglMarks, FALSE, FALSE, 0); g_signal_connect(G_OBJECT(tglMarks), "toggled", G_CALLBACK(onHighlightHideToggled), marks); gtk_box_pack_start(GTK_BOX(hboxMarks), gtk_label_new("("), FALSE, FALSE, 0); wd = gtk_radio_button_new_with_mnemonic((GSList*)0, _("_h.")); g_object_set_data(G_OBJECT(wd), "hiding-mode", GINT_TO_POINTER(HIDE_HIGHLIGHT)); if (visu_gl_ext_marks_getHidingMode(marks) == HIDE_HIGHLIGHT) gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON(wd), TRUE); gtk_widget_set_tooltip_text(wd, _("Hide button will hide highlighted nodes.")); gtk_widget_set_name(wd, "message_radio"); gtk_box_pack_start(GTK_BOX(hboxMarks), wd, FALSE, FALSE, 0); g_signal_connect(G_OBJECT(wd), "toggled", G_CALLBACK(onHighlightHideStatus), marks); wd2 = gtk_radio_button_new_with_mnemonic_from_widget(GTK_RADIO_BUTTON(wd), _("_non-h.")); g_object_set_data(G_OBJECT(wd2), "hiding-mode", GINT_TO_POINTER(HIDE_NON_HIGHLIGHT)); if (visu_gl_ext_marks_getHidingMode(marks) == HIDE_NON_HIGHLIGHT) gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON(wd2), TRUE); gtk_widget_set_tooltip_text(wd2, _("Hide button will hide non-highlighted nodes.")); gtk_widget_set_name(wd2, "message_radio"); gtk_box_pack_start(GTK_BOX(hboxMarks), wd2, FALSE, FALSE, 0); g_signal_connect(G_OBJECT(wd2), "toggled", G_CALLBACK(onHighlightHideStatus), marks); g_object_set_data(G_OBJECT(tglMarks), "hiding-mode", gtk_toggle_button_get_active(GTK_TOGGLE_BUTTON(wd)) ? GINT_TO_POINTER(HIDE_HIGHLIGHT) : GINT_TO_POINTER(HIDE_NON_HIGHLIGHT)); gtk_box_pack_start(GTK_BOX(hboxMarks), gtk_label_new(")"), FALSE, FALSE, 0); lbl = lookup_widget(main->interactiveDialog, "labelMarks"); gtk_label_set_use_markup(GTK_LABEL(lbl), TRUE); g_object_bind_property_full(marks, "highlight", lbl, "label", G_BINDING_SYNC_CREATE, _toLblMarks, NULL, (gpointer)0, (GDestroyNotify)0); gtk_widget_show_all(hboxMarks); g_object_bind_property(scene, "data", listPickedNodes, "model", G_BINDING_SYNC_CREATE); visu_ui_selection_setHighlightModel(listPickedNodes, marks); g_object_bind_property_full(listPickedNodes, "selection", infos, "selection", G_BINDING_SYNC_CREATE | G_BINDING_BIDIRECTIONAL, _toSelection, _toSelection, g_object_ref(radioDrawSelected), (GDestroyNotify)g_object_unref); /* Get the current VisuData object. */ g_signal_connect_object(scene, "notify::data", G_CALLBACK(onDataNotify), treeviewPickedNodes, 0); g_signal_connect_swapped(treeviewPickedNodes, "destroy", G_CALLBACK(_setData), (gpointer)0); onDataNotify(scene); return (GtkWidget*)0; } /** * visu_ui_interactive_pick_start: * @window: a #VisuUiRenderingWindow object. * * Initialise a pick session. */ void visu_ui_interactive_pick_start(VisuUiRenderingWindow *window) { VisuInteractive *inter; g_object_get(window, "interactive", &inter, NULL); visu_ui_rendering_window_pushInteractive(window, interPick); visu_interactive_setReferences(interPick, inter); g_object_unref(inter); } /** * visu_ui_interactive_pick_stop: * @window: a #VisuUiRenderingWindow object. * * Finalise a pick session. */ void visu_ui_interactive_pick_stop(VisuUiRenderingWindow *window) { VisuInteractive *inter; visu_ui_rendering_window_popInteractive(window, interPick); g_object_get(window, "interactive", &inter, NULL); visu_interactive_setReferences(inter, interPick); g_object_unref(inter); } static void onNodeSelection(VisuInteractive *inter _U_, VisuInteractivePick pick, VisuData *dataObj, VisuNode *node0, VisuNode *node1, VisuNode *node2, gpointer data _U_) { gchar *errors; GString *infos; float posRef1[3], posRef2[3], posSelect[3]; double dx, dy, dz, dr, dx1, dy1, dz1, dr1, dx2, dy2, dz2, dr2; double ang; DBG_fprintf(stderr, "Gtk Pick: one measurement done (%d).\n", pick); gtk_tree_selection_unselect_all(gtk_tree_view_get_selection (GTK_TREE_VIEW(treeviewPickedNodes))); /* Update the texts. */ infos = g_string_new(""); errors = (gchar*)0; if (pick == PICK_DISTANCE || pick == PICK_ANGLE || pick == PICK_REFERENCE_1 || pick == PICK_REFERENCE_2) g_string_append_printf(infos, _("Reference node\t" " #%d\n" "" " ( x = %7.3f ; y = %7.3f ; z = %7.3f)\n" ""), node1->number + 1, node1->xyz[0], node1->xyz[1], node1->xyz[2]); if (pick == PICK_ANGLE || pick == PICK_REFERENCE_2) { visu_data_getNodePosition(dataObj, node1, posRef1); visu_data_getNodePosition(dataObj, node2, posRef2); dx = posRef2[0] - posRef1[0]; dy = posRef2[1] - posRef1[1]; dz = posRef2[2] - posRef1[2]; dr = sqrt(dx*dx + dy*dy + dz*dz); g_string_append_printf(infos, _("2nd Reference node\t" " #%d\t" " (i.e. dr = %7.3f)\n" "" " ( x = %7.3f ; y = %7.3f ; z = %7.3f)\n" " (\316\264x = %7.3f ; \316\264y = %7.3f ; \316\264z = %7.3f)\n" ""), node2->number + 1, dr, node2->xyz[0], node2->xyz[1], node2->xyz[2], dx, dy, dz); } if (pick == PICK_SELECTED) g_string_append_printf(infos, _("Newly picked node\t" " #%d\n" "" " ( x = %7.3f ; y = %7.3f ; z = %7.3f)\n" ""), node0->number + 1, node0->xyz[0], node0->xyz[1], node0->xyz[2]); else if (pick == PICK_DISTANCE) { visu_data_getNodePosition(dataObj, node0, posSelect); visu_data_getNodePosition(dataObj, node1, posRef1); dx = posSelect[0] - posRef1[0]; dy = posSelect[1] - posRef1[1]; dz = posSelect[2] - posRef1[2]; dr = sqrt(dx*dx + dy*dy + dz*dz); g_string_append_printf(infos, _("Newly picked node\t" " #%d\t" " (i.e. dr = %7.3f)\n" "" " ( x = %7.3f ; y = %7.3f ; z = %7.3f)\n" " (\316\264x = %7.3f ; \316\264y = %7.3f ; \316\264z = %7.3f)\n" ""), node0->number + 1, dr, node0->xyz[0], node0->xyz[1], node0->xyz[2], dx, dy, dz); } else if (pick == PICK_ANGLE) { visu_data_getNodePosition(dataObj, node0, posSelect); visu_data_getNodePosition(dataObj, node1, posRef1); visu_data_getNodePosition(dataObj, node2, posRef2); dx1 = posSelect[0] - posRef1[0]; dy1 = posSelect[1] - posRef1[1]; dz1 = posSelect[2] - posRef1[2]; dx2 = posRef2[0] - posRef1[0]; dy2 = posRef2[1] - posRef1[1]; dz2 = posRef2[2] - posRef1[2]; dr1 = sqrt(dx1*dx1 + dy1*dy1 + dz1*dz1); g_string_append_printf(infos, _("Newly picked node\t" " #%d\t" " (i.e. dr = %7.3f)\n" "" " ( x = %7.3f ; y = %7.3f ; z = %7.3f)\n" " (\316\264x1 = %7.3f ; \316\264y1 = %7.3f ; \316\264z1 = %7.3f)\n" " (\316\264x2 = %7.3f ; \316\264y2 = %7.3f ; \316\264z2 = %7.3f)\n"), node0->number + 1, dr1, node0->xyz[0], node0->xyz[1], node0->xyz[2], dx1, dy1, dz1, dx2, dy2, dz2); dr2 = sqrt(dx2*dx2 + dy2*dy2 + dz2*dz2); ang = acos((dx2*dx1+dy2*dy1+dz2*dz1)/(dr2*dr1))/TOOL_PI180; g_string_append_printf(infos, _(" angle (Ref-Ref2, Ref-New) = %5.2f degrees" ""), ang); } if (pick == PICK_UNREFERENCE_1 || pick == PICK_UNREFERENCE_2) errors = g_strdup_printf(_("Unset reference %d."), (pick == PICK_UNREFERENCE_1)?1:2); /* Update the remaining of the interface. */ switch (pick) { case PICK_SELECTED: case PICK_DISTANCE: case PICK_ANGLE: case PICK_HIGHLIGHT: /* Add clicked node to list. */ visu_ui_selection_add(listPickedNodes, node0->number); /* Falls through. */ case PICK_UNREFERENCE_1: case PICK_UNREFERENCE_2: case PICK_REFERENCE_1: case PICK_REFERENCE_2: if (infos) { gtk_label_set_markup(GTK_LABEL(labelPickOut), infos->str); g_string_free(infos, TRUE); } gtk_label_set_text(GTK_LABEL(labelPickError), errors); if (errors) g_free(errors); return; case PICK_INFORMATION: break; default: g_warning("Not a pick event!"); } return; } static void onSelectionError(VisuInteractive *inter _U_, VisuInteractivePickError error, gpointer data _U_) { switch (error) { case PICK_ERROR_NO_SELECTION: gtk_label_set_text(GTK_LABEL(labelPickError), _("No node has been selected.")); return; case PICK_ERROR_SAME_REF: gtk_label_set_text(GTK_LABEL(labelPickError), _("Picked reference and second" " reference are the same.")); return; case PICK_ERROR_REF1: gtk_label_set_text(GTK_LABEL(labelPickError), _("Can't pick a second reference" " without any existing first one.")); return; case PICK_ERROR_REF2: gtk_label_set_text(GTK_LABEL(labelPickError), _("Can't remove first reference" " before removing the second one.")); return; default: return; } } /** * visu_ui_interactive_pick_getSelection: * * Retrieves the #VisuUiSelection of this panel. * * Since: 3.8 * * Returns: (transfer none): a #VisuUiSelection object. **/ VisuUiSelection* visu_ui_interactive_pick_getSelection(void) { return listPickedNodes; } /** * visu_ui_interactive_pick_getSelectionLabel: * * Retrieves the #GtkWidget used as label for the selection. * * Since: 3.8 * * Returns: (transfer none): a #GtkWidget object. **/ GtkWidget* visu_ui_interactive_pick_getSelectionLabel(void) { return labelSelection; } /*********************/ /* Private routines. */ /*********************/ static void displayProp(GtkTreeViewColumn *column _U_, GtkCellRenderer *renderer, GtkTreeModel *model, GtkTreeIter *iter, gpointer data) { VisuNodeValues *values = VISU_NODE_VALUES(data); gint number; gchar *text, *none; gboolean editable; gtk_tree_model_get(model, iter, VISU_UI_SELECTION_NUMBER, &number, -1); text = visu_node_values_toStringFromId(values, (guint)(number - 1)); if (!text || text[0] == '\0') { none = g_strdup_printf("%s", _("None")); g_object_set(renderer, "markup", none, NULL); g_free(none); } else g_object_set(renderer, "markup", text, NULL); editable = visu_node_values_getEditable(values); g_object_set(renderer, "editable", editable, NULL); if (editable) g_object_set(renderer, "foreground", GTK_PICK_EDITABLE_NODE, NULL); g_free(text); } /*************/ /* Callbacks */ /*************/ static void onNodeValueChanged(VisuNodeValues *values _U_, VisuNode *node) { GtkTreeIter iter; GtkTreePath *path; gboolean valid; guint number; for (valid = gtk_tree_model_get_iter_first(GTK_TREE_MODEL(listPickedNodes), &iter); valid; valid = gtk_tree_model_iter_next(GTK_TREE_MODEL(listPickedNodes), &iter)) { gtk_tree_model_get(GTK_TREE_MODEL(listPickedNodes), &iter, VISU_UI_SELECTION_NUMBER, &number, -1); if (!node || number == node->number + 1) { path = gtk_tree_model_get_path(GTK_TREE_MODEL(listPickedNodes), &iter); gtk_tree_model_row_changed(GTK_TREE_MODEL(listPickedNodes), path, &iter); gtk_tree_path_free(path); if (node) return; } } } static void onEditedValue(GtkCellRendererText *cellrenderertext _U_, gchar *path, gchar *text, gpointer user_data) { GtkTreeIter iter; guint number; VisuNodeValues *values = VISU_NODE_VALUES(user_data); gboolean valid; if (text && !strcmp(text, _("None"))) return; valid = gtk_tree_model_get_iter_from_string(GTK_TREE_MODEL(listPickedNodes), &iter, path); g_return_if_fail(valid); gtk_tree_model_get(GTK_TREE_MODEL(listPickedNodes), &iter, VISU_UI_SELECTION_NUMBER, &number, -1); valid = visu_node_values_setFromStringForId(values, number - 1, text); if (!valid) visu_ui_raiseWarning(_("Reading values"), _("Wrong format. Impossible to parse the data associated" " to the selected node."), (GtkWindow*)0); } static void onMeasurementList(VisuGlExtMarks *marks, VisuData *dataObj, gpointer data _U_) { gchar *lbl; struct _PickHistory *hist; GString *str; GList *lst, *rev; if (!dataObj) return; lbl = visu_gl_ext_marks_getMeasurementStrings(marks); if (!lbl) return; if (!pickHistory || ((struct _PickHistory*)pickHistory->data)->dataObj != dataObj) { hist = g_malloc(sizeof(struct _PickHistory)); hist->dataObj = dataObj; pickHistory = g_list_prepend(pickHistory, (gpointer)hist); } else { hist = (struct _PickHistory*)pickHistory->data; g_free(hist->str); } hist->str = lbl; if (labelPickHistory) { lbl = visu_gl_ext_marks_getMeasurementLabels(marks); str = g_string_new(lbl); g_free(lbl); rev = g_list_reverse(pickHistory); for (lst = rev; lst; lst = g_list_next(lst)) g_string_append(str, ((struct _PickHistory*)lst->data)->str); pickHistory = g_list_reverse(rev); lbl = g_markup_printf_escaped ("Measurement history, first 6 values (%d entry(ies)):\n" "%s", g_list_length(pickHistory), str->str); g_string_free(str, TRUE); gtk_label_set_markup(GTK_LABEL(labelPickHistory), lbl); g_free(lbl); } } static void _togglePath(VisuUiSelection *selection, gchar *path) { gboolean valid; GtkTreeIter iter; valid = gtk_tree_model_get_iter_from_string(GTK_TREE_MODEL(selection), &iter, path); g_return_if_fail(valid); visu_ui_selection_highlight(selection, &iter, MARKS_STATUS_TOGGLE); } static void onHighlightHideToggled(GtkToggleButton *button, gpointer user_data) { VisuGlExtMarksHidingModes mode; if (gtk_toggle_button_get_active(button)) { mode = GPOINTER_TO_INT(g_object_get_data(G_OBJECT(button), "hiding-mode")); visu_gl_ext_marks_setHidingMode(VISU_GL_EXT_MARKS(user_data), mode); } else visu_gl_ext_marks_setHidingMode(VISU_GL_EXT_MARKS(user_data), HIDE_NONE); } static void onHighlightHideStatus(GtkButton *button, gpointer user_data) { VisuGlExtMarksHidingModes mode; if (!gtk_toggle_button_get_active(GTK_TOGGLE_BUTTON(button))) return; mode = GPOINTER_TO_INT(g_object_get_data(G_OBJECT(button), "hiding-mode")); g_object_set_data(G_OBJECT(tglMarks), "hiding-mode", GINT_TO_POINTER(mode)); if (gtk_toggle_button_get_active(GTK_TOGGLE_BUTTON(tglMarks))) visu_gl_ext_marks_setHidingMode(VISU_GL_EXT_MARKS(user_data), mode); } static void onDrawDistanceChecked(GtkToggleButton* button, gpointer data) { visu_gl_ext_marks_setDrawValues(VISU_GL_EXT_MARKS(data), gtk_toggle_button_get_active(button)); } static void onEraseDistanceClicked(GtkButton *button _U_, gpointer user_data) { DBG_fprintf(stderr, "Gtk Pick: clicked on 'erase all measures' button.\n"); visu_gl_ext_marks_removeMeasures(VISU_GL_EXT_MARKS(user_data), -1); } static void onDataNotify(VisuGlNodeScene *scene) { _setData(visu_gl_node_scene_getData(scene)); } static void _setData(VisuData *dataObj) { GList *lst, *tmpLst; DBG_fprintf(stderr, "Gtk Pick: set data model to %p.\n", (gpointer)dataObj); if (currentData == dataObj) return; lst = gtk_tree_view_get_columns(GTK_TREE_VIEW(treeviewPickedNodes)); for (tmpLst = g_list_next(lst); tmpLst; tmpLst = g_list_next(tmpLst)) gtk_tree_view_remove_column(GTK_TREE_VIEW(treeviewPickedNodes), GTK_TREE_VIEW_COLUMN(tmpLst->data)); if (lst) g_list_free(lst); if (currentData) { g_signal_handler_disconnect(G_OBJECT(currentData), propAdd_signal); g_signal_handler_disconnect(G_OBJECT(currentData), propRemoved_signal); g_object_unref(currentData); } currentData = dataObj; if (dataObj) { g_object_ref(dataObj); DBG_fprintf(stderr, " | dataObj has %d ref counts.\n", G_OBJECT(dataObj)->ref_count); propAdd_signal = g_signal_connect_swapped (G_OBJECT(dataObj), "node-properties-added", G_CALLBACK(_addColumn), treeviewPickedNodes); propRemoved_signal = g_signal_connect_swapped (G_OBJECT(dataObj), "node-properties-removed", G_CALLBACK(_removeColumn), treeviewPickedNodes); lst = visu_data_getAllNodeProperties(dataObj); for (tmpLst = lst; tmpLst; tmpLst = g_list_next(tmpLst)) _addColumn(GTK_TREE_VIEW(treeviewPickedNodes), VISU_NODE_VALUES(tmpLst->data)); g_list_free(lst); DBG_fprintf(stderr, " | dataObj has %d ref counts.\n", G_OBJECT(dataObj)->ref_count); } } static void _addColumn(GtkTreeView *view, VisuNodeValues *prop) { GtkCellRenderer *renderer; GtkTreeViewColumn *column; GtkWidget *lbl; const gchar *title; gchar *markup; renderer = gtk_cell_renderer_text_new(); g_signal_connect(G_OBJECT(renderer), "edited", G_CALLBACK(onEditedValue), prop); g_object_set(G_OBJECT(renderer), "scale", 0.8, NULL); title = visu_node_values_getLabel(prop); DBG_fprintf(stderr, " | add column '%s'.\n", title); lbl = gtk_label_new(""); markup = g_markup_printf_escaped("%s", title); gtk_label_set_markup(GTK_LABEL(lbl), markup); g_free(markup); gtk_widget_show(lbl); column = gtk_tree_view_column_new(); g_object_set_data(G_OBJECT(column), "NodeProperties", prop); gtk_tree_view_column_set_widget(column, lbl); gtk_tree_view_column_pack_start(column, renderer, TRUE); gtk_tree_view_column_set_cell_data_func(column, renderer, displayProp, prop, (GDestroyNotify)0); gtk_tree_view_column_set_visible(column, TRUE); if (VISU_IS_NODE_VALUES_ID(prop)) gtk_tree_view_column_set_sort_column_id(column, VISU_UI_SELECTION_NUMBER); gtk_tree_view_append_column(view, column); g_signal_connect_object(G_OBJECT(prop), "changed", G_CALLBACK(onNodeValueChanged), renderer, 0); } static void _removeColumn(GtkTreeView *view, VisuNodeValues *prop) { GList *lst, *tmpLst; gpointer myprop; lst = gtk_tree_view_get_columns(view); for (tmpLst = lst; tmpLst; tmpLst = g_list_next(tmpLst)) { myprop = g_object_get_data(G_OBJECT(tmpLst->data), "NodeProperties"); if (myprop == (gpointer)prop) { gtk_tree_view_remove_column(view, GTK_TREE_VIEW_COLUMN(tmpLst->data)); break; } } g_list_free(lst); } static gboolean onTreeviewInfosKey(GtkWidget *widget, GdkEventKey *event, gpointer user_data _U_) { GList *selectedPaths; GtkTreeModel *model; DBG_fprintf(stderr, "Gtk Pick: key pressed on treeview '%d'.\n", event->keyval); if (event->keyval != GDK_KEY_Delete && event->keyval != GDK_KEY_BackSpace) return FALSE; selectedPaths = gtk_tree_selection_get_selected_rows (gtk_tree_view_get_selection(GTK_TREE_VIEW(widget)), &model); visu_ui_selection_removePaths(VISU_UI_SELECTION(model), selectedPaths); g_list_free_full(selectedPaths, (GDestroyNotify)gtk_tree_path_free); return TRUE; } static gboolean onLoadXML(const gchar *filename, GError **error) { return visu_gl_node_scene_setMarksFromFile(visu_ui_rendering_window_getGlScene(visu_ui_main_class_getDefaultRendering()), filename, error); } static gboolean onSaveXML(const gchar *filename, GError **error) { return visu_gl_node_scene_marksToFile(visu_ui_rendering_window_getGlScene(visu_ui_main_class_getDefaultRendering()), filename, error); } v_sim-3.8.0/src/gtk_pick.h000066400000000000000000000045101370110300500153600ustar00rootroot00000000000000/* EXTRAITS DE LA LICENCE Copyright CEA, contributeurs : Luc BILLARD et Damien CALISTE, laboratoire L_Sim, (2001-2005) Adresse mèl : BILLARD, non joignable par mèl ; CALISTE, damien P caliste AT cea P fr. Ce logiciel est un programme informatique servant à visualiser des structures atomiques dans un rendu pseudo-3D. Ce logiciel est régi par la licence CeCILL soumise au droit français et respectant les principes de diffusion des logiciels libres. Vous pouvez utiliser, modifier et/ou redistribuer ce programme sous les conditions de la licence CeCILL telle que diffusée par le CEA, le CNRS et l'INRIA sur le site "http://www.cecill.info". Le fait que vous puissiez accéder à cet en-tête signifie que vous avez pris connaissance de la licence CeCILL, et que vous en avez accepté les termes (cf. le fichier Documentation/licence.fr.txt fourni avec ce logiciel). */ /* LICENCE SUM UP Copyright CEA, contributors : Luc BILLARD et Damien CALISTE, laboratoire L_Sim, (2001-2005) E-mail address: BILLARD, not reachable any more ; CALISTE, damien P caliste AT cea P fr. This software is a computer program whose purpose is to visualize atomic configurations in 3D. This software is governed by the CeCILL license under French law and abiding by the rules of distribution of free software. You can use, modify and/ or redistribute the software under the terms of the CeCILL license as circulated by CEA, CNRS and INRIA at the following URL "http://www.cecill.info". The fact that you are presently reading this means that you have had knowledge of the CeCILL license and that you accept its terms. You can find a copy of this licence shipped with this software at Documentation/licence.en.txt. */ #ifndef GTK_PICK_H #define GTK_PICK_H #include #include "gtk_main.h" #include "gtk_renderingWindowWidget.h" #include "uiElements/ui_selection.h" GtkWidget* visu_ui_interactive_pick_initBuild(VisuUiMain *main, gchar **label, gchar **help, GtkWidget **radio); VisuUiSelection* visu_ui_interactive_pick_getSelection(void); GtkWidget* visu_ui_interactive_pick_getSelectionLabel(void); void visu_ui_interactive_pick_start(VisuUiRenderingWindow *window); void visu_ui_interactive_pick_stop(VisuUiRenderingWindow *window); void visu_ui_interactive_pick_init(); #endif v_sim-3.8.0/src/gtk_renderingWindowWidget.c000066400000000000000000003075451370110300500207540ustar00rootroot00000000000000/* EXTRAITS DE LA LICENCE Copyright CEA, contributeurs : Luc BILLARD et Damien CALISTE, laboratoire L_Sim, (2001-2006) Adresse mèl : BILLARD, non joignable par mèl ; CALISTE, damien P caliste AT cea P fr. Ce logiciel est un programme informatique servant à visualiser des structures atomiques dans un rendu pseudo-3D. Ce logiciel est régi par la licence CeCILL soumise au droit français et respectant les principes de diffusion des logiciels libres. Vous pouvez utiliser, modifier et/ou redistribuer ce programme sous les conditions de la licence CeCILL telle que diffusée par le CEA, le CNRS et l'INRIA sur le site "http://www.cecill.info". Le fait que vous puissiez accéder à cet en-tête signifie que vous avez pris connaissance de la licence CeCILL, et que vous en avez accepté les termes (cf. le fichier Documentation/licence.fr.txt fourni avec ce logiciel). */ /* LICENCE SUM UP Copyright CEA, contributors : Luc BILLARD et Damien CALISTE, laboratoire L_Sim, (2001-2006) E-mail address: BILLARD, not reachable any more ; CALISTE, damien P caliste AT cea P fr. This software is a computer program whose purpose is to visualize atomic configurations in 3D. This software is governed by the CeCILL license under French law and abiding by the rules of distribution of free software. You can use, modify and/ or redistribute the software under the terms of the CeCILL license as circulated by CEA, CNRS and INRIA at the following URL "http://www.cecill.info". The fact that you are presently reading this means that you have had knowledge of the CeCILL license and that you accept its terms. You can find a copy of this licence shipped with this software at Documentation/licence.en.txt. */ #ifdef HAVE_CONFIG_H #include #endif #define V_SIM_GDK #include "gtk_renderingWindowWidget.h" #include #include #include /* for sqrt function... */ #include #include #include "support.h" #include "visu_gtk.h" #include "visu_tools.h" #include "visu_basic.h" #include "visu_dataatomic.h" #include "visu_dataspin.h" #include "visu_configFile.h" #include "visu_glnodescene.h" #include "OSOpenGL/visu_openGL.h" #include "renderingBackend/visu_actionInterface.h" #include "gtk_openGLWidget.h" #include "coreTools/toolFileFormat.h" #include "coreTools/toolConfigFile.h" #include "extraGtkFunctions/gtk_dumpDialogWidget.h" #include "extraGtkFunctions/gtk_orientationChooser.h" #include "extraGtkFunctions/gtk_dataChooser.h" #include "openGLFunctions/objectList.h" #include "openGLFunctions/interactive.h" #include "opengl.h" #include "extensions/axes.h" #include "extensions/box.h" #include "extensions/box_legend.h" #include "extensions/frame.h" #include "extensions/legend.h" #include "extensions/nodes.h" #include "extensions/pairs.h" #include "extensions/scale.h" #include "extensions/planes.h" #include "extensions/forces.h" #include "dumpModules/dumpToSVG.h" #include "dumpModules/glDump.h" #include "gtk_main.h" /** * SECTION:gtk_renderingWindowWidget * @short_description: Defines a complex widget used to render files * and print information. * * This is a complex widget, inheriting from #GtkWindow, with a * rendering area and a status bar area. A #VisuData is always * attached to this widget, see visu_ui_rendering_window_setData(). If not * the V_Sim logo is displayed. * * The rendering area can receive keyboard or mouse events, see * visu_ui_rendering_window_class_getInteractive. * * The status bar area has different buttons to load or export a * file. It also display some usefull information like the number of * rendered nodes. It has also a real status bar location displaying * tips about current available actions. One can add news using * visu_ui_rendering_window_pushMessage(). */ typedef enum { event_button_press, event_button_release, event_motion_notify, event_key_press, event_key_release, event_scroll } InteractiveEventsId; struct InteractiveEvents_struct { gulong callbackId; InteractiveEventsId id; }; typedef struct InteractiveEvents_struct InteractiveEvents; struct GtkInfoArea_struct { GtkWidget *area; GtkWidget *infoBar; GtkWidget *searchEntry; GtkWidget *hboxFileInfo; GtkWidget *labelSize; GtkWidget *labelNb; GBinding *bind_nb; GtkWidget *labelFileInfo; GBinding *bind_info; gboolean fileInfoFreeze; GtkWidget *hboxTools; GtkWidget *dumpButton; GtkWidget *loadButton; GtkWidget *raiseButton; GtkWidget *reloadButton; GtkWidget *statusInfo, *progress; guint progressId, waitId; GtkWidget *cancelButton; GCancellable *cancel; GtkWidget *hboxInteractive; guint statusInfoId; }; typedef struct GtkInfoArea_struct GtkInfoArea; #define GTK_STATUSINFO_NOFILEINFO _("No description is available") #define GTK_STATUSINFO_NONB _("Nothing is loaded") #define FLAG_PARAMETER_RED_COORD "config_showReducedCoordinates" #define DESC_PARAMETER_RED_COORD "Display coordinates in reduced values when picking a node ; boolean 0 or 1" static gboolean _useReducedCoordinates = FALSE; #define MENU_CAMERA_SAVE "/Camera/Save" #define MENU_CAMERA_RESTORE "/Camera/Restore" #define MENU_CAMERA_ORIENT "/Camera/Orientation" #define MENU_CAMERA_1 "/Camera/select1" #define MENU_CAMERA_2 "/Camera/select2" #define MENU_CAMERA_3 "/Camera/select3" #define MENU_CAMERA_4 "/Camera/select4" #define MENU_CAMERA_5 "/Camera/select5" #define MENU_CAMERA_6 "/Camera/select6" #define MENU_CAMERA_7 "/Camera/select7" #define MENU_CAMERA_8 "/Camera/select8" #define MENU_CAMERA_9 "/Camera/select9" static const gchar* cameraAccels[] = {MENU_CAMERA_1, MENU_CAMERA_2, MENU_CAMERA_3, MENU_CAMERA_4, MENU_CAMERA_5, MENU_CAMERA_6, MENU_CAMERA_7, MENU_CAMERA_8, MENU_CAMERA_9}; static guint cameraKeys[] = {GDK_KEY_1, GDK_KEY_2, GDK_KEY_3, GDK_KEY_4, GDK_KEY_5, GDK_KEY_6, GDK_KEY_7, GDK_KEY_8, GDK_KEY_9}; enum { EXPORT_SIGNAL, OPEN_SIGNAL, RELOAD_SIGNAL, SHOW_ACTION_DIALOG_SIGNAL, SHOW_MAIN_PANEL_SIGNAL, SHOW_ORIENTATION_SIGNAL, LOAD_NEXT_FILE_SIGNAL, LOAD_PREV_FILE_SIGNAL, SEARCH_SIGNAL, LAST_SIGNAL }; enum { PROP_0, LABEL_PROP, DATA_PROP, VIEW_PROP, SCENE_PROP, INTER_PROP, COORD_PROP, SELECTION_PROP, TOOLBAR_PROP, N_PROP }; static GParamSpec *properties[N_PROP]; enum { TEXT_PLAIN, TEXT_URI_LIST }; /* Local variables. */ static VisuInteractive *interPickObs = NULL; static guint _signals[LAST_SIGNAL] = { 0 }; static VisuUiRenderingWindow *_defaultRendering = NULL; /* Local methods. */ static void exportParameters(GString *data, VisuData *dataObj); static void gtkStatusInfo_createBar(VisuUiRenderingWindow *window, gboolean withToolBar); static gulong addInteractiveEventListeners(VisuUiRenderingWindow *window, InteractiveEventsId id); static GtkWidget* buildCameraMenu(VisuUiRenderingWindow *window); static void _setLabelSize(GtkInfoArea *info, gint width, gint height); static void getOpenGLAreaSize(VisuUiRenderingWindow *window, guint *width, guint *height); static void _redraw(VisuUiRenderingWindow *window, gboolean forceRedraw); /* Local callbacks */ static void visu_ui_rendering_window_dispose (GObject* obj); static void visu_ui_rendering_window_finalize(GObject* obj); static void visu_ui_rendering_window_constructed (GObject* obj); static void visu_ui_rendering_window_get_property(GObject* obj, guint property_id, GValue *value, GParamSpec *pspec); static void visu_ui_rendering_window_set_property(GObject* obj, guint property_id, const GValue *value, GParamSpec *pspec); static gboolean toNNodeLabel(GBinding *binding, const GValue *source_value, GValue *target_value, gpointer data); static gboolean toFileInfo(GBinding *binding, const GValue *source_value, GValue *target_value, gpointer data); static void onDataNotify(VisuUiRenderingWindow *window, GParamSpec *psepc, VisuGlNodeScene *scene); static void onLoadingNotified(VisuUiRenderingWindow *window, GParamSpec *pspec, VisuGlNodeScene *scene); static void onMarkClearClicked(VisuUiRenderingWindow *window, GtkButton *button); static void onNodeInfoClicked(VisuUiRenderingWindow *window, GtkToggleButton *button); static void onRaiseButtonClicked(VisuUiRenderingWindow *window, gpointer user_data); static void onGlDirty(VisuUiRenderingWindow *window); static gboolean onDragMotion(GtkWidget *widget, GdkDragContext *context, gint x, gint y, guint t, gpointer user_data); static void onDropData(VisuUiRenderingWindow *window, GdkDragContext *context, gint x, gint y, GtkSelectionData *selection_data, guint target_type, guint time, GtkWidget *glArea); static gboolean onCameraMenu(VisuUiRenderingWindow *window, GdkEventButton *event, GtkEventBox *ev); static void onCameraMenuSelected(GtkMenuShell *menushell, gpointer user_data); static void onCameraMenuClicked(GtkMenuItem *menuitem, gpointer user_data); static void onCameraMenuCurrentClicked(GtkMenuItem *menuitem, gpointer user_data); static void onCameraMenuOrientationClicked(GtkMenuItem *menuitem, gpointer user_data); static void minimalPickInfo(VisuInteractive *inter, VisuInteractivePick pick, VisuData *dataObj, VisuNode *node0, VisuNode *node1, VisuNode *node2, gpointer data); static void minimalPickError(VisuInteractive *inter, VisuInteractivePickError error, gpointer data); static void onCancelButtonClicked(GtkButton *button, gpointer data); static gboolean onCameraAccel(GtkAccelGroup *accel, GObject *obj, guint key, GdkModifierType mod, gpointer data); #if GTK_MAJOR_VERSION > 2 || GTK_MINOR_VERSION > 17 static void _onSearchClose(GtkInfoBar *bar, gint response, gpointer data); static void _onSearchEdited(GtkEntry *entry, gpointer data); #endif static void onEntryCoord(VisuUiRenderingWindow *window); struct _VisuUiRenderingWindow { GtkVBox generalVBox; gboolean dispose_has_run; GdkCursor *cursorRotate; GdkCursor *cursorWatch; GdkCursor *cursorPointer; GdkCursor *cursorPirate; GdkCursor *cursorGrab; /*********************************/ /* Dealing with the OpenGL area. */ /*********************************/ /* The OpenGL area and it's notification zone. */ GtkWidget *openGLArea; /* This pointer give the handle to rule all interactive actions. */ GList *inters; /* This is a list of currently connected signal for the interactive mode. */ GList *interactiveEvents; /* A pointer on the current used cursor. */ GdkCursor *currentCursor; GdkCursor *refCursor; /* Rendered extensions. */ VisuGlNodeScene *glScene; gulong sig_data, sig_load; /*************************************/ /* Dealing with the information bar. */ /*************************************/ /* TO BE INTEGRATED. */ GtkInfoArea info; /* TO BE INTEGRATED. */ int nbStatusMessage; gboolean useReducedCoordinates; gint selectedNodeId; gboolean withToolbar; GtkAccelGroup *accel; }; struct _VisuUiRenderingWindowClass { GtkVBoxClass parent_class; void (*renderingWindow) (VisuUiRenderingWindow *window); /* Action signals for keybindings, do not connect to these */ void (*export) (VisuUiRenderingWindow *window); void (*open) (VisuUiRenderingWindow *window); void (*reload) (VisuUiRenderingWindow *window); void (*orient) (VisuUiRenderingWindow *window); void (*search) (VisuUiRenderingWindow *window); /* To be removed when redraw is a signal object. */ VisuUiRenderingWindow *redrawWidget; }; G_DEFINE_TYPE(VisuUiRenderingWindow, visu_ui_rendering_window, GTK_TYPE_BOX) /* Local callbacks */ static gboolean timeOutPopMessage(gpointer data); static gboolean onFocus(GtkWidget *wd, GdkEvent *event, gpointer data); static void onSizeChangeEvent(VisuUiRenderingWindow *window, GtkAllocation *allocation); static void onRealiseEvent(GtkWidget *wd, gpointer data); static void onExport(VisuUiRenderingWindow *window); static void onOpen(VisuUiRenderingWindow *window); static void _onSearch(VisuUiRenderingWindow *window); static void _orientationChooser(VisuUiRenderingWindow *window); static gboolean _onSearchEsc(GtkWidget *widget, GdkEventKey *event, gpointer data); /* Interactive mode listeners. */ static gboolean OnEvent(VisuUiRenderingWindow *window, GdkEvent *event, gpointer user_data); static void visu_ui_rendering_window_class_init(VisuUiRenderingWindowClass *klass) { GtkBindingSet *binding_set; VisuConfigFileEntry *resourceEntry; DBG_fprintf(stderr, "Gtk VisuUiRenderingWindow: creating the class of the widget.\n"); klass->export = onExport; klass->reload = visu_ui_rendering_window_reload; klass->open = onOpen; klass->orient = _orientationChooser; klass->search = _onSearch; interPickObs = visu_interactive_new(interactive_measureAndObserve); visu_interactive_setMessage(interPickObs, _("Rotate with left b.," " pick with right b.," " setup ref. with" " or b.")); DBG_fprintf(stderr, "Gtk VisuUiRenderingWindow: connect the signals.\n"); G_OBJECT_CLASS(klass)->dispose = visu_ui_rendering_window_dispose; G_OBJECT_CLASS(klass)->finalize = visu_ui_rendering_window_finalize; G_OBJECT_CLASS(klass)->constructed = visu_ui_rendering_window_constructed; G_OBJECT_CLASS(klass)->get_property = visu_ui_rendering_window_get_property; G_OBJECT_CLASS(klass)->set_property = visu_ui_rendering_window_set_property; /** * VisuUiRenderingWindow::export: * @window: the object emitting the signal. * * Signal emitted when the user ask for data export. * * Since: 3.6 */ _signals[EXPORT_SIGNAL] = g_signal_new("export", G_TYPE_FROM_CLASS(klass), G_SIGNAL_RUN_LAST | G_SIGNAL_ACTION, G_STRUCT_OFFSET(VisuUiRenderingWindowClass, export), NULL, NULL, g_cclosure_marshal_VOID__VOID, G_TYPE_NONE, 0); /** * VisuUiRenderingWindow::open: * @window: the object emitting the signal. * * Signal emitted when the user ask to open new data. * * Since: 3.6 */ _signals[OPEN_SIGNAL] = g_signal_new("open", G_TYPE_FROM_CLASS(klass), G_SIGNAL_RUN_LAST | G_SIGNAL_ACTION, G_STRUCT_OFFSET(VisuUiRenderingWindowClass, open), NULL, NULL, g_cclosure_marshal_VOID__VOID, G_TYPE_NONE, 0); /** * VisuUiRenderingWindow::reload: * @window: the object emitting the signal. * * Signal emitted when the user ask to reload current data. * * Since: 3.6 */ _signals[RELOAD_SIGNAL] = g_signal_new("reload", G_TYPE_FROM_CLASS(klass), G_SIGNAL_RUN_LAST | G_SIGNAL_ACTION, G_STRUCT_OFFSET(VisuUiRenderingWindowClass, reload), NULL, NULL, g_cclosure_marshal_VOID__VOID, G_TYPE_NONE, 0); /** * VisuUiRenderingWindow::search: * @window: the object emitting the signal. * * Signal emitted when the user ask to search info in current data. * * Since: 3.7 */ _signals[SEARCH_SIGNAL] = g_signal_new("search", G_TYPE_FROM_CLASS(klass), G_SIGNAL_RUN_LAST | G_SIGNAL_ACTION, G_STRUCT_OFFSET(VisuUiRenderingWindowClass, search), NULL, NULL, g_cclosure_marshal_VOID__VOID, G_TYPE_NONE, 0); /** * VisuUiRenderingWindow::show-action-dialog: * @window: the object emitting the signal. * * Signal emitted when the user ask to show the action dialog. * * Since: 3.6 */ _signals[SHOW_ACTION_DIALOG_SIGNAL] = g_signal_new("show-action-dialog", G_TYPE_FROM_CLASS(klass), G_SIGNAL_RUN_LAST | G_SIGNAL_NO_RECURSE | G_SIGNAL_NO_HOOKS | G_SIGNAL_ACTION, 0, NULL, NULL, g_cclosure_marshal_VOID__VOID, G_TYPE_NONE, 0); /** * VisuUiRenderingWindow::show-main-panel: * @window: the object emitting the signal. * * Signal emitted when the user ask to raise the main panel. * * Since: 3.6 */ _signals[SHOW_MAIN_PANEL_SIGNAL] = g_signal_new("show-main-panel", G_TYPE_FROM_CLASS(klass), G_SIGNAL_RUN_LAST | G_SIGNAL_NO_RECURSE | G_SIGNAL_NO_HOOKS | G_SIGNAL_ACTION, 0, NULL, NULL, g_cclosure_marshal_VOID__VOID, G_TYPE_NONE, 0); /** * VisuUiRenderingWindow::show-orientation-chooser: * @window: the object emitting the signal. * * Signal emitted when the user ask to precisely select a camera angle. * * Since: 3.7 */ _signals[SHOW_ORIENTATION_SIGNAL] = g_signal_new("show-orientation-chooser", G_TYPE_FROM_CLASS(klass), G_SIGNAL_RUN_LAST | G_SIGNAL_ACTION, G_STRUCT_OFFSET(VisuUiRenderingWindowClass, orient), NULL, NULL, g_cclosure_marshal_VOID__VOID, G_TYPE_NONE, 0); /** * VisuUiRenderingWindow::load-next-file: * @window: the object emitting the signal. * * Signal emitted when the user ask to load next file of a given list. * * Since: 3.7 */ _signals[LOAD_NEXT_FILE_SIGNAL] = g_signal_new("load-next-file", G_TYPE_FROM_CLASS(klass), G_SIGNAL_RUN_LAST | G_SIGNAL_NO_RECURSE | G_SIGNAL_NO_HOOKS | G_SIGNAL_ACTION, 0, NULL, NULL, g_cclosure_marshal_VOID__VOID, G_TYPE_NONE, 0); /** * VisuUiRenderingWindow::load-prev-file: * @window: the object emitting the signal. * * Signal emitted when the user ask to load previous file of a given list. * * Since: 3.7 */ _signals[LOAD_PREV_FILE_SIGNAL] = g_signal_new("load-prev-file", G_TYPE_FROM_CLASS(klass), G_SIGNAL_RUN_LAST | G_SIGNAL_NO_RECURSE | G_SIGNAL_NO_HOOKS | G_SIGNAL_ACTION, 0, NULL, NULL, g_cclosure_marshal_VOID__VOID, G_TYPE_NONE, 0); /** * VisuUiRenderingWindow::label: * * Store a label representing the currently loaded data. * * Since: 3.8 */ properties[LABEL_PROP] = g_param_spec_string("label", "Label", "Label representing the data", "", G_PARAM_READABLE); /** * VisuUiRenderingWindow::data: * * Store which #VisuData is rendered in the window. * * Since: 3.8 */ properties[DATA_PROP] = g_param_spec_object("data", "Data", "Data marks are applied to", VISU_TYPE_DATA, G_PARAM_READWRITE); /** * VisuUiRenderingWindow::gl-view: * * Store the #VisuGlView of the OpenGL area. * * Since: 3.8 */ properties[VIEW_PROP] = g_param_spec_object("gl-view", "GlView", "GlView mark labels are aligned with", VISU_TYPE_GL_VIEW, G_PARAM_READABLE); /** * VisuUiRenderingWindow::gl-scene: * * Store the #VisuGlNodeScene of the OpenGL area. * * Since: 3.8 */ properties[SCENE_PROP] = g_param_spec_object("gl-scene", "GlScene", "GlScene rendered in the window", VISU_TYPE_GL_NODE_SCENE, G_PARAM_READWRITE | G_PARAM_CONSTRUCT_ONLY); /** * VisuUiRenderingWindow::interactive: * * Store the current #VisuInteractive of the OpenGL area. * * Since: 3.8 */ properties[INTER_PROP] = g_param_spec_object("interactive", "Interactive", "current interactive session", VISU_TYPE_INTERACTIVE, G_PARAM_READABLE); /** * VisuUiRenderingWindow::coordinates-in-reduced: * * Display node coordinates in reduced values. * * Since: 3.8 */ properties[COORD_PROP] = g_param_spec_boolean("coordinates-in-reduced", "Coordinates in reduced values", "display node coordinates in reduced values", FALSE, G_PARAM_READWRITE); /** * VisuUiRenderingWindow::selection: * * Selected node, if any. * * Since: 3.8 */ properties[SELECTION_PROP] = g_param_spec_boxed("selection", "Selection", "currently selected node, if any", VISU_TYPE_NODE, G_PARAM_READABLE); /** * VisuUiRenderingWindow::with-toolbar: * * If the rendering widget has a toolbar or not. * * Since: 3.8 */ properties[TOOLBAR_PROP] = g_param_spec_boolean("with-toolbar", "With toolbar", "if the widget has a toolbar or not", TRUE, G_PARAM_WRITABLE | G_PARAM_CONSTRUCT_ONLY); g_object_class_install_properties(G_OBJECT_CLASS(klass), N_PROP, properties); DBG_fprintf(stderr, "Gtk VisuUiRenderingWindow: connect the bindings.\n"); binding_set = gtk_binding_set_by_class(klass); gtk_binding_entry_add_signal(binding_set, GDK_KEY_s, GDK_CONTROL_MASK, "export", 0); gtk_binding_entry_add_signal(binding_set, GDK_KEY_o, GDK_CONTROL_MASK, "open", 0); gtk_binding_entry_add_signal(binding_set, GDK_KEY_r, GDK_CONTROL_MASK, "reload", 0); gtk_binding_entry_add_signal(binding_set, GDK_KEY_v, GDK_CONTROL_MASK, "show-orientation-chooser", 0); gtk_binding_entry_add_signal(binding_set, GDK_KEY_i, GDK_CONTROL_MASK, "show-action-dialog", 0); gtk_binding_entry_add_signal(binding_set, GDK_KEY_f, GDK_CONTROL_MASK, "search", 0); gtk_binding_entry_add_signal(binding_set, GDK_KEY_Home, 0, "show-main-panel", 0); gtk_binding_entry_add_signal(binding_set, GDK_KEY_n, 0, "load-next-file", 0); gtk_binding_entry_add_signal(binding_set, GDK_KEY_p, 0, "load-prev-file", 0); DBG_fprintf(stderr, "Gtk VisuUiRenderingWindow: add the resources.\n"); resourceEntry = visu_config_file_addBooleanEntry(VISU_CONFIG_FILE_PARAMETER, FLAG_PARAMETER_RED_COORD, DESC_PARAMETER_RED_COORD, &_useReducedCoordinates, FALSE); visu_config_file_entry_setVersion(resourceEntry, 3.6f); visu_config_file_addExportFunction(VISU_CONFIG_FILE_PARAMETER, exportParameters); DBG_fprintf(stderr, " | interPickObs has %d ref counts.\n", G_OBJECT(interPickObs)->ref_count); } static void visu_ui_rendering_window_dispose(GObject* obj) { GList *ptList; InteractiveEvents *event; VisuUiRenderingWindow *window; VisuInteractive *inter; DBG_fprintf(stderr, "Gtk VisuUiRenderingWindow: dispose object %p.\n", (gpointer)obj); window = VISU_UI_RENDERING_WINDOW(obj); if (window->dispose_has_run) return; window->dispose_has_run = TRUE; if (window->cursorPirate) g_clear_object(&window->cursorPirate); if (window->cursorRotate) g_clear_object(&window->cursorRotate); if (window->cursorWatch) g_clear_object(&window->cursorWatch); if (window->cursorPointer) g_clear_object(&window->cursorPointer); if (window->cursorGrab) g_clear_object(&window->cursorGrab); ptList = window->inters; while (ptList) { inter = VISU_INTERACTIVE(ptList->data); ptList = g_list_next(ptList); visu_ui_rendering_window_popInteractive(window, inter); } DBG_fprintf(stderr, "Gtk VisuUiRenderingWindow: releasing current handles.\n"); if (window->info.progressId) g_source_remove(window->info.progressId); DBG_fprintf(stderr, "Gtk VisuUiRenderingWindow: release current data handle.\n"); g_clear_object(&window->info.cancel); DBG_fprintf(stderr, "Gtk VisuUiRenderingWindow: removing interactive listeners.\n"); for (ptList = window->interactiveEvents; ptList; ptList = g_list_next(ptList)) { event = (InteractiveEvents*)ptList->data; DBG_fprintf(stderr, " | disconnecting %d signal.\n", event->id); g_signal_handler_disconnect(G_OBJECT(window->openGLArea), event->callbackId); g_free(ptList->data); } if (window->interactiveEvents) g_list_free(window->interactiveEvents); window->interactiveEvents = (GList*)0; g_clear_object(&window->accel); if (window->sig_data) g_signal_handler_disconnect(window->glScene, window->sig_data); if (window->sig_load) g_signal_handler_disconnect(window->glScene, window->sig_load); g_clear_object(&window->glScene); DBG_fprintf(stderr, "Gtk VisuUiRenderingWindow: chain to parent.\n"); G_OBJECT_CLASS(visu_ui_rendering_window_parent_class)->dispose(obj); DBG_fprintf(stderr, "Gtk VisuUiRenderingWindow: dispose done.\n"); } static void visu_ui_rendering_window_finalize(GObject* obj) { DBG_fprintf(stderr, "Gtk VisuUiRenderingWindow: finalize object %p.\n", (gpointer)obj); /* Chain up to the parent class */ G_OBJECT_CLASS(visu_ui_rendering_window_parent_class)->finalize(obj); } static void visu_ui_rendering_window_get_property(GObject* obj, guint property_id, GValue *value, GParamSpec *pspec) { VisuUiRenderingWindow *self = VISU_UI_RENDERING_WINDOW(obj); VisuData *dataObj; DBG_fprintf(stderr, "Gtk VisuUiRenderingWindow: get property '%s' -> ", g_param_spec_get_name(pspec)); switch (property_id) { case LABEL_PROP: if (!visu_gl_node_scene_getData(self->glScene)) g_value_set_static_string(value, _("No file loaded")); else if (!VISU_IS_DATA_LOADABLE(visu_gl_node_scene_getData(self->glScene))) g_value_set_static_string(value, _("No filename")); else g_object_get_property(G_OBJECT(visu_gl_node_scene_getData(self->glScene)), "label", value); DBG_fprintf(stderr, "%s.\n", g_value_get_string(value)); break; case DATA_PROP: g_value_set_object(value, visu_gl_node_scene_getData(self->glScene)); DBG_fprintf(stderr, "%p.\n", (gpointer)g_value_get_object(value)); break; case VIEW_PROP: g_value_set_object(value, visu_gl_node_scene_getGlView(self->glScene)); DBG_fprintf(stderr, "%p.\n", (gpointer)g_value_get_object(value)); break; case SCENE_PROP: g_value_set_object(value,self->glScene); DBG_fprintf(stderr, "%p.\n", (gpointer)g_value_get_object(value)); break; case INTER_PROP: g_value_set_object(value, (self->inters) ? self->inters->data : (gpointer)0); DBG_fprintf(stderr, "%p.\n", g_value_get_object(value)); break; case COORD_PROP: g_value_set_boolean(value, self->useReducedCoordinates); DBG_fprintf(stderr, "%d.\n", g_value_get_boolean(value)); break; case SELECTION_PROP: dataObj = visu_gl_node_scene_getData(self->glScene); g_value_set_static_boxed(value, (self->selectedNodeId >= 0 && dataObj) ? visu_node_array_getFromId(VISU_NODE_ARRAY(dataObj), self->selectedNodeId) : (gconstpointer)0); DBG_fprintf(stderr, "%p.\n", g_value_get_boxed(value)); break; default: /* We don't have any other property... */ G_OBJECT_WARN_INVALID_PROPERTY_ID(obj, property_id, pspec); break; } } static void visu_ui_rendering_window_set_property(GObject* obj, guint property_id, const GValue *value, GParamSpec *pspec) { VisuUiRenderingWindow *self = VISU_UI_RENDERING_WINDOW(obj); DBG_fprintf(stderr, "Gtk VisuUiRenderingWindow: set property '%s' -> ", g_param_spec_get_name(pspec)); switch (property_id) { case SCENE_PROP: self->glScene = g_value_dup_object(value); break; case DATA_PROP: DBG_fprintf(stderr, "%p.\n", (gpointer)g_value_get_object(value)); visu_gl_node_scene_setData(self->glScene, VISU_DATA(g_value_get_object(value))); break; case COORD_PROP: DBG_fprintf(stderr, "%d.\n", g_value_get_boolean(value)); visu_ui_rendering_window_setDisplayCoordinatesInReduce(self, g_value_get_boolean(value)); break; case TOOLBAR_PROP: DBG_fprintf(stderr, "%d.\n", g_value_get_boolean(value)); self->withToolbar = g_value_get_boolean(value); break; default: /* We don't have any other property... */ G_OBJECT_WARN_INVALID_PROPERTY_ID(obj, property_id, pspec); break; } } static void visu_ui_rendering_window_constructed(GObject *obj) { VisuUiRenderingWindow *self = VISU_UI_RENDERING_WINDOW(obj); GtkTargetList *target_list; VisuGlView *view; if (!self->glScene) self->glScene = visu_gl_node_scene_new(); visu_interactive_setNodeList(interPickObs, visu_gl_node_scene_getNodes(self->glScene)); g_object_bind_property(self, "interactive", visu_gl_node_scene_getMarks(self->glScene), "interactive", G_BINDING_SYNC_CREATE); /* We create the statusinfo area. */ gtkStatusInfo_createBar(self, self->withToolbar); gtk_box_pack_end(GTK_BOX(self), self->info.area, FALSE, FALSE, 0); /* The OpenGL area. */ self->openGLArea = visu_ui_gl_widget_new(TRUE); view = visu_gl_node_scene_getGlView(self->glScene); g_return_if_fail(VISU_IS_GL_VIEW(view)); gtk_widget_set_size_request(self->openGLArea, MAX(100, view->window.width), MAX(100, view->window.height)); gtk_widget_set_can_focus(self->openGLArea, TRUE); g_signal_connect_swapped(G_OBJECT(self->openGLArea), "realize", G_CALLBACK(onRealiseEvent), self); g_signal_connect_swapped(G_OBJECT(self->openGLArea), "size-allocate", G_CALLBACK(onSizeChangeEvent), self); g_signal_connect(G_OBJECT(self->openGLArea), "enter-notify-event", G_CALLBACK(onFocus), (gpointer)self); /* DnD */ gtk_drag_dest_set(self->openGLArea, (GTK_DEST_DEFAULT_ALL), NULL, 0, GDK_ACTION_COPY); target_list = gtk_target_list_new(NULL, 0); gtk_target_list_add_uri_targets(target_list, TEXT_URI_LIST); gtk_target_list_add_text_targets(target_list, TEXT_PLAIN); gtk_drag_dest_set_target_list(self->openGLArea, target_list); gtk_target_list_unref(target_list); g_signal_connect(self->openGLArea, "drag-motion", G_CALLBACK(onDragMotion), NULL); g_signal_connect_swapped(self->openGLArea, "drag-data-received", G_CALLBACK(onDropData), self); gtk_box_pack_start(GTK_BOX(self), self->openGLArea, TRUE, TRUE, 0); gtk_widget_show_all(GTK_WIDGET(self)); } static void visu_ui_rendering_window_init(VisuUiRenderingWindow *renderingWindow) { guint n; GClosure *closure; DBG_fprintf(stderr, "Gtk VisuUiRenderingWindow: initializing new object (%p).\n", (gpointer)renderingWindow); if (!g_type_class_peek(VISU_TYPE_DATA)) visu_basic_init(); gtk_orientable_set_orientation(GTK_ORIENTABLE(renderingWindow), GTK_ORIENTATION_VERTICAL); /* Initialisation des curseurs utiles. */ renderingWindow->cursorPirate = (GdkCursor*)0; renderingWindow->cursorRotate = (GdkCursor*)0; renderingWindow->cursorWatch = (GdkCursor*)0; renderingWindow->cursorPointer = (GdkCursor*)0; renderingWindow->cursorGrab = (GdkCursor*)0; /* Set local variables. */ DBG_fprintf(stderr, " - setup the local variables.\n"); renderingWindow->sig_data = 0; renderingWindow->sig_load = 0; renderingWindow->nbStatusMessage = 0; renderingWindow->selectedNodeId = -1; renderingWindow->useReducedCoordinates = _useReducedCoordinates; renderingWindow->withToolbar = TRUE; renderingWindow->interactiveEvents = (GList*)0; renderingWindow->inters = (GList*)0; DBG_fprintf(stderr, "Gtk renderingWindow: bind interactive prop.\n"); DBG_fprintf(stderr, " | interPickObs has %d ref counts.\n", G_OBJECT(interPickObs)->ref_count); g_signal_connect_object(VISU_CONFIG_FILE_PARAMETER, "parsed::" FLAG_PARAMETER_RED_COORD, G_CALLBACK(onEntryCoord), (gpointer)renderingWindow, G_CONNECT_SWAPPED); /* Binding for the camera menu. */ DBG_fprintf(stderr, "Gtk VisuUiRenderingWindow: connect the camera bindings.\n"); renderingWindow->accel = gtk_accel_group_new(); gtk_accel_map_add_entry(g_intern_static_string(MENU_CAMERA_RESTORE), GDK_KEY_r, 0); gtk_accel_map_add_entry(g_intern_static_string(MENU_CAMERA_SAVE), GDK_KEY_s, 0); gtk_accel_map_add_entry(g_intern_static_string(MENU_CAMERA_ORIENT), GDK_KEY_v, GDK_CONTROL_MASK); DBG_fprintf(stderr, "Gtk VisuUiRenderingWindow: connect the camera numbered bindings.\n"); for (n = 0; n < 9; n++) { gtk_accel_map_add_entry(g_intern_static_string(cameraAccels[n]), cameraKeys[n], GDK_CONTROL_MASK); closure = g_cclosure_new(G_CALLBACK(onCameraAccel), (gpointer)renderingWindow, (GClosureNotify)0); gtk_accel_group_connect_by_path(renderingWindow->accel, g_intern_static_string(cameraAccels[n]), closure); g_closure_unref(closure); } g_signal_connect(G_OBJECT(interPickObs), "node-selection", G_CALLBACK(minimalPickInfo), (gpointer)renderingWindow); g_signal_connect(G_OBJECT(interPickObs), "selection-error", G_CALLBACK(minimalPickError), (gpointer)renderingWindow); DBG_fprintf(stderr, " | interPickObs has %d ref counts.\n", G_OBJECT(interPickObs)->ref_count); if (!_defaultRendering) _defaultRendering = renderingWindow; } /** * visu_ui_rendering_window_new: * @width: its desired width ; * @height: its desired height ; * @withFrame: a boolean ; * @withToolBar: a boolean. * * A #VisuUiRenderingWindow widget is a GtkWindow that have an area for * OpenGL drawing and a statusBar with many stuff like action buttons, * real status bar for notifications, ... The rendering area can be * drawn with a frame or not. With this routine, only the * #VisuUiRenderingWindow widget is created. * * Returns: a newly created #VisuUiRenderingWindow widget. */ GtkWidget* visu_ui_rendering_window_new(int width, int height, gboolean withFrame _U_, gboolean withToolBar) { VisuUiRenderingWindow *renderingWindow; DBG_fprintf(stderr, "Gtk VisuUiRenderingWindow: create a new VisuUiRenderingWindow object.\n"); renderingWindow = g_object_new(VISU_TYPE_UI_RENDERING_WINDOW, "with-toolbar", withToolBar, NULL); gtk_widget_set_size_request(renderingWindow->openGLArea, width, height); return GTK_WIDGET(renderingWindow); } /** * visu_ui_rendering_window_new_withGlScene: * @scene: a #VisuGlView object. * @withToolBar: a boolean. * * Like visu_ui_rendering_window_new(), but use an already existing @view. * * Since: 3.8 * * Returns: a newly created #VisuUiRenderingWindow widget. **/ GtkWidget* visu_ui_rendering_window_new_withGlScene(VisuGlNodeScene *scene, gboolean withToolBar) { return g_object_new(VISU_TYPE_UI_RENDERING_WINDOW, "gl-scene", scene, "with-toolbar", withToolBar, NULL); } static gboolean _selectionToTog(GBinding *bind _U_, const GValue *from, GValue *to, gpointer data) { VisuUiRenderingWindow *window = VISU_UI_RENDERING_WINDOW(data); VisuNode *node; node = (VisuNode*)g_value_get_boxed(from); g_value_set_boolean(to, (node) ? visu_gl_node_scene_getMarkActive(window->glScene, node->number) : FALSE); return TRUE; } static gboolean _selectionToSen(GBinding *bind _U_, const GValue *from, GValue *to, gpointer data _U_) { VisuNode *node; node = (VisuNode*)g_value_get_boxed(from); g_value_set_boolean(to, (node) ? TRUE : FALSE); return TRUE; } static void gtkStatusInfo_createBar(VisuUiRenderingWindow *window, gboolean withToolBar) { GtkWidget *hbox; GtkWidget *wd, *image, *ev; #if GTK_MAJOR_VERSION == 2 && GTK_MINOR_VERSION < 12 GtkTooltips *tooltips; tooltips = gtk_tooltips_new (); #endif window->info.waitId = 0; window->info.area = gtk_vbox_new(FALSE, 0); #if GTK_MAJOR_VERSION > 2 || GTK_MINOR_VERSION > 17 window->info.infoBar = gtk_info_bar_new(); wd = gtk_info_bar_add_button(GTK_INFO_BAR(window->info.infoBar), _("_Close"), GTK_RESPONSE_CLOSE); gtk_widget_set_focus_on_click(wd, FALSE); gtk_widget_set_no_show_all(window->info.infoBar, TRUE); g_signal_connect(G_OBJECT(window->info.infoBar), "response", G_CALLBACK(_onSearchClose), (gpointer)window); g_signal_connect(G_OBJECT(window->info.infoBar), "key-press-event", G_CALLBACK(_onSearchEsc), (gpointer)window); gtk_box_pack_start(GTK_BOX(window->info.area), window->info.infoBar, FALSE, FALSE, 0); hbox = gtk_hbox_new(FALSE, 0); gtk_container_add(GTK_CONTAINER(gtk_info_bar_get_content_area(GTK_INFO_BAR(window->info.infoBar))), hbox); wd = gtk_label_new(_("Toggle highlight for node: ")); gtk_box_pack_start(GTK_BOX(hbox), wd, FALSE, FALSE, 0); window->info.searchEntry = gtk_entry_new(); gtk_entry_set_width_chars(GTK_ENTRY(window->info.searchEntry), 20); g_signal_connect(G_OBJECT(window->info.searchEntry), "activate", G_CALLBACK(_onSearchEdited), (gpointer)window->glScene); gtk_box_pack_start(GTK_BOX(hbox), window->info.searchEntry, FALSE, FALSE, 0); gtk_widget_show_all(hbox); #endif window->info.fileInfoFreeze = FALSE; window->info.hboxFileInfo = gtk_hbox_new(FALSE, 0); gtk_box_pack_start(GTK_BOX(window->info.area), window->info.hboxFileInfo, FALSE, FALSE, 1); /* Size info */ wd = gtk_hbox_new(FALSE, 0); gtk_box_pack_start(GTK_BOX(window->info.hboxFileInfo), wd, FALSE, FALSE, 5); window->info.labelSize = gtk_label_new(""); gtk_label_set_use_markup(GTK_LABEL(window->info.labelSize), TRUE); gtk_box_pack_start(GTK_BOX(wd), window->info.labelSize, FALSE, FALSE, 0); wd = gtk_vseparator_new(); gtk_box_pack_start(GTK_BOX(window->info.hboxFileInfo), wd, FALSE, FALSE, 0); /* Nb nodes */ window->info.labelNb = gtk_label_new(""); gtk_label_set_use_markup(GTK_LABEL(window->info.labelNb), TRUE); gtk_box_pack_start(GTK_BOX(window->info.hboxFileInfo), window->info.labelNb, FALSE, FALSE, 5); wd = gtk_vseparator_new(); gtk_box_pack_start(GTK_BOX(window->info.hboxFileInfo), wd, FALSE, FALSE, 0); /* File info */ wd = gtk_hbox_new(FALSE, 0); gtk_box_pack_start(GTK_BOX(window->info.hboxFileInfo), wd, TRUE, TRUE, 0); #if GTK_MAJOR_VERSION > 2 || GTK_MINOR_VERSION > 7 image = gtk_image_new_from_icon_name("dialog-information", GTK_ICON_SIZE_MENU); #else image = gtk_image_new_from_stock(GTK_STOCK_SAVE, GTK_ICON_SIZE_MENU); #endif gtk_box_pack_start(GTK_BOX(wd), image, FALSE, FALSE, 5); window->info.labelFileInfo = gtk_label_new(""); gtk_label_set_use_markup(GTK_LABEL(window->info.labelFileInfo), TRUE); gtk_label_set_xalign(GTK_LABEL(window->info.labelFileInfo), 0.); gtk_widget_set_margin_start(window->info.labelFileInfo, 5); #if GTK_MAJOR_VERSION > 2 || GTK_MINOR_VERSION > 5 gtk_label_set_ellipsize(GTK_LABEL(window->info.labelFileInfo), PANGO_ELLIPSIZE_END); #endif gtk_box_pack_start(GTK_BOX(wd), window->info.labelFileInfo, TRUE, TRUE, 0); ev = gtk_event_box_new(); gtk_widget_set_tooltip_text(ev, _("Click here to get the list of" " saved camera positions.\n" "Use 's' and 'r' keys to save and" " restore camera settings. + 's'" " remove the current camera from the list.")); g_signal_connect_swapped(G_OBJECT(ev), "button-release-event", G_CALLBACK(onCameraMenu), (gpointer)window); gtk_box_pack_end(GTK_BOX(wd), ev, FALSE, FALSE, 0); image = gtk_image_new_from_icon_name("zoom-fit-best", GTK_ICON_SIZE_MENU); gtk_container_add(GTK_CONTAINER(ev), image); /* Status */ hbox = gtk_hbox_new(FALSE, 0); gtk_box_pack_start(GTK_BOX(window->info.area), hbox, FALSE, FALSE, 0); /* Handle box for action buttons. */ if (withToolBar) { /* The container */ window->info.hboxTools = gtk_hbox_new(TRUE, 0); gtk_box_pack_start(GTK_BOX(hbox), window->info.hboxTools, FALSE, FALSE, 0); /* Load button */ window->info.loadButton = gtk_button_new(); g_object_set(G_OBJECT(window->info.loadButton), "can-default", FALSE, "can-focus", FALSE, "has-default", FALSE, "has-focus", FALSE, NULL); gtk_widget_set_focus_on_click(window->info.loadButton, FALSE); gtk_widget_set_tooltip_text(window->info.loadButton, _("Open Ctrl+o")); g_signal_connect_swapped(G_OBJECT(window->info.loadButton), "clicked", G_CALLBACK(onOpen), (gpointer)window); image = gtk_image_new_from_icon_name("document-open", GTK_ICON_SIZE_MENU); gtk_container_add(GTK_CONTAINER(window->info.loadButton), image); gtk_box_pack_start(GTK_BOX(window->info.hboxTools), window->info.loadButton, FALSE, FALSE, 0); /* Refresh button */ wd = gtk_button_new(); g_object_bind_property(window, "data", wd, "sensitive", G_BINDING_SYNC_CREATE); g_object_set(G_OBJECT(wd), "can-default", FALSE, "can-focus", FALSE, "has-default", FALSE, "has-focus", FALSE, NULL); gtk_widget_set_focus_on_click(wd, FALSE); gtk_widget_set_tooltip_text(wd, _("Reload the current file Ctrl+r")); g_signal_connect_swapped(G_OBJECT(wd), "clicked", G_CALLBACK(visu_ui_rendering_window_reload), (gpointer)window); image = gtk_image_new_from_icon_name("view-refresh", GTK_ICON_SIZE_MENU); gtk_container_add(GTK_CONTAINER(wd), image); gtk_box_pack_start(GTK_BOX(window->info.hboxTools), wd, FALSE, FALSE, 0); window->info.reloadButton = wd; /* Save button */ window->info.dumpButton = gtk_button_new(); g_object_bind_property(window, "data", window->info.dumpButton, "sensitive", G_BINDING_SYNC_CREATE); g_object_set(G_OBJECT(window->info.dumpButton), "can-default", FALSE, "can-focus", FALSE, "has-default", FALSE, "has-focus", FALSE, NULL); gtk_widget_set_focus_on_click(window->info.dumpButton, FALSE); gtk_widget_set_tooltip_text(window->info.dumpButton, _("Export Ctrl+s")); g_signal_connect_swapped(G_OBJECT(window->info.dumpButton), "clicked", G_CALLBACK(onExport), (gpointer)window); gtk_widget_set_sensitive(window->info.dumpButton, FALSE); image = gtk_image_new_from_icon_name("document-save-as", GTK_ICON_SIZE_MENU); gtk_container_add(GTK_CONTAINER(window->info.dumpButton), image); gtk_box_pack_start(GTK_BOX(window->info.hboxTools), window->info.dumpButton, FALSE, FALSE, 0); /* Auto-raise command panel button */ window->info.raiseButton = gtk_button_new(); g_object_set(G_OBJECT(window->info.raiseButton), "can-default", FALSE, "can-focus", FALSE, "has-default", FALSE, "has-focus", FALSE, NULL); gtk_widget_set_focus_on_click(window->info.raiseButton, FALSE); gtk_widget_set_tooltip_text(window->info.raiseButton, _("Raise the command panel window.\n" " Use as key binding.")); g_signal_connect_swapped(G_OBJECT(window->info.raiseButton), "clicked", G_CALLBACK(onRaiseButtonClicked), (gpointer)window); image = gtk_image_new_from_icon_name("go-up", GTK_ICON_SIZE_MENU); gtk_widget_show(image); gtk_container_add(GTK_CONTAINER(window->info.raiseButton), image); /* gtk_widget_set_no_show_all(window->info.raiseButton, TRUE); */ gtk_box_pack_start(GTK_BOX(window->info.hboxTools), window->info.raiseButton, FALSE, FALSE, 0); } else { window->info.loadButton = (GtkWidget*)0; window->info.dumpButton = (GtkWidget*)0; window->info.raiseButton = (GtkWidget*)0; } /* The status bar or progress */ window->info.statusInfo = gtk_statusbar_new(); gtk_box_pack_start(GTK_BOX(hbox), window->info.statusInfo, TRUE, TRUE, 0); #if GTK_MAJOR_VERSION < 3 gtk_statusbar_set_has_resize_grip(GTK_STATUSBAR(window->info.statusInfo), FALSE); #endif window->info.statusInfoId = gtk_statusbar_get_context_id(GTK_STATUSBAR(window->info.statusInfo), "OpenGL statusbar."); gtk_widget_set_no_show_all(window->info.statusInfo, TRUE); gtk_widget_show(window->info.statusInfo); window->info.progressId = 0; window->info.progress = gtk_progress_bar_new(); g_object_bind_property(window->glScene, "loading-message", window->info.progress, "text", 0); gtk_box_pack_start(GTK_BOX(hbox), window->info.progress, TRUE, TRUE, 0); gtk_widget_set_no_show_all(window->info.progress, TRUE); window->info.cancelButton = gtk_button_new_with_mnemonic(_("_Cancel")); gtk_box_pack_start(GTK_BOX(hbox), window->info.cancelButton, FALSE, FALSE, 0); gtk_widget_set_no_show_all(window->info.cancelButton, TRUE); g_signal_connect(G_OBJECT(window->info.cancelButton), "clicked", G_CALLBACK(onCancelButtonClicked), (gpointer)window); window->info.cancel = g_cancellable_new(); /* The interactive button zone. */ window->info.hboxInteractive = gtk_hbox_new(TRUE, 0); gtk_box_pack_start(GTK_BOX(hbox), window->info.hboxInteractive, FALSE, FALSE, 0); /* Action button */ wd = gtk_toggle_button_new(); gtk_widget_set_sensitive(wd, FALSE); gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON(wd), FALSE); gtk_widget_set_focus_on_click(wd, FALSE); g_object_set(G_OBJECT(wd), "can-default", FALSE, "can-focus", FALSE, "has-default", FALSE, "has-focus", FALSE, NULL); g_object_bind_property_full(window, "selection", wd, "sensitive", G_BINDING_SYNC_CREATE, _selectionToSen, NULL, (gpointer)0, (GDestroyNotify)0); g_object_bind_property_full(window, "selection", wd, "active", G_BINDING_SYNC_CREATE, _selectionToTog, NULL, (gpointer)window, (GDestroyNotify)0); g_signal_connect_swapped(G_OBJECT(wd), "clicked", G_CALLBACK(onNodeInfoClicked), (gpointer)window); gtk_widget_set_tooltip_text(wd, _("Measure / remove information" " for the selected node.")); image = gtk_image_new_from_icon_name("document-properties", GTK_ICON_SIZE_MENU); gtk_container_add(GTK_CONTAINER(wd), image); gtk_box_pack_end(GTK_BOX(window->info.hboxInteractive), wd, FALSE, FALSE, 0); /* Clean marks button */ wd = gtk_button_new(); g_object_bind_property(window->glScene, "data", wd, "sensitive", G_BINDING_SYNC_CREATE); gtk_widget_set_focus_on_click(wd, FALSE); g_object_set(G_OBJECT(wd), "can-default", FALSE, "can-focus", FALSE, "has-default", FALSE, "has-focus", FALSE, NULL); g_signal_connect_swapped(G_OBJECT(wd), "clicked", G_CALLBACK(onMarkClearClicked), (gpointer)window); gtk_widget_set_tooltip_text(wd, _("Remove all measurement marks.")); image = gtk_image_new_from_icon_name("edit-clear", GTK_ICON_SIZE_MENU); gtk_container_add(GTK_CONTAINER(wd), image); gtk_box_pack_end(GTK_BOX(window->info.hboxInteractive), wd, FALSE, FALSE, 0); if (withToolBar) visu_ui_rendering_window_pushMessage(window, _("Use the 'open' button to render a file.")); } static gboolean onFocus(GtkWidget *wd _U_, GdkEvent *event _U_, gpointer data) { visu_ui_rendering_window_setCurrent(VISU_UI_RENDERING_WINDOW(data), FALSE); return FALSE; } static void onSizeChangeEvent(VisuUiRenderingWindow *window, GtkAllocation *allocation) { g_return_if_fail(VISU_IS_UI_RENDERING_WINDOW(window)); /* Return if no changes in size (this event is called even the size is not really changed but has been negociated. */ if (!visu_gl_view_setViewport(visu_gl_node_scene_getGlView(window->glScene), allocation->width, allocation->height)) return; _setLabelSize(&window->info, allocation->width, allocation->height); } static void onRealiseEvent(GtkWidget *wd, gpointer data _U_) { guint w, h; VisuUiRenderingWindow *window; DBG_fprintf(stderr, "Gtk VisuUiRenderingWindow: initializing OpenGL variable for" "the new OpenGL area.\n"); window = VISU_UI_RENDERING_WINDOW(wd); /* Initialisation des curseurs utiles. */ window->cursorPirate = gdk_cursor_new_for_display(gtk_widget_get_display(wd), GDK_PIRATE); window->cursorRotate = gdk_cursor_new_for_display(gtk_widget_get_display(wd), GDK_EXCHANGE); window->cursorWatch = gdk_cursor_new_for_display(gtk_widget_get_display(wd), GDK_WATCH); window->cursorPointer = gdk_cursor_new_for_display(gtk_widget_get_display(wd), GDK_DOTBOX); window->cursorGrab = gdk_cursor_new_for_display(gtk_widget_get_display(wd), GDK_FLEUR); window->currentCursor = window->cursorPirate; window->refCursor = window->cursorPirate; /* If we have a VisuData object attached, we set its size. */ w = h = 0; getOpenGLAreaSize(window, &w, &h); visu_gl_view_setViewport(visu_gl_node_scene_getGlView(window->glScene), w, h); _setLabelSize(&window->info, w, h); DBG_fprintf(stderr, "Gtk VisuUiRenderingWindow: changing the cursor.\n"); /* We set the cursor. */ gdk_window_set_cursor(gtk_widget_get_window(window->openGLArea), window->currentCursor); DBG_fprintf(stderr, " | cursor OK.\n"); gtk_widget_grab_focus(wd); visu_ui_rendering_window_setCurrent(window, FALSE); /* Attach no redraw redraw method. */ window->sig_load = g_signal_connect_object(window->glScene, "notify::loading", G_CALLBACK(onLoadingNotified), window, G_CONNECT_SWAPPED); window->sig_data = g_signal_connect_object(window->glScene, "notify::data", G_CALLBACK(onDataNotify), window, G_CONNECT_SWAPPED); onDataNotify(window, (GParamSpec*)0, window->glScene); g_signal_connect_object(G_OBJECT(window->glScene), "notify::dirty", G_CALLBACK(onGlDirty), window, G_CONNECT_SWAPPED); /* Set V_Sim OpenGL options. */ visu_gl_initContext(VISU_GL(window->glScene)); DBG_fprintf(stderr, " | openGL context OK\n"); _redraw(window, FALSE); } static gboolean onDragMotion(GtkWidget *widget, GdkDragContext *context, gint x _U_, gint y _U_, guint t, gpointer data _U_) { /* GList *tmpLst; */ GdkAtom atom; /* DBG_fprintf(stderr, "VisuUiRenderingWindow: Hey ! You dnd move something !\n"); */ /* for (tmpLst = context->targets; tmpLst; tmpLst = g_list_next(tmpLst)) */ /* { */ /* DBG_fprintf(stderr, " | dnd: '%s'\n", */ /* gdk_atom_name(GDK_POINTER_TO_ATOM(tmpLst->data))); */ /* } */ atom = gtk_drag_dest_find_target(widget, context, gtk_drag_dest_get_target_list(widget)); if (atom != GDK_NONE) gdk_drag_status(context, GDK_ACTION_COPY, t); else gdk_drag_status(context, 0, t); return (atom != GDK_NONE); } static void onDropData(VisuUiRenderingWindow *window, GdkDragContext *context, gint x _U_, gint y _U_, GtkSelectionData *data, guint type, guint time _U_, GtkWidget *glArea _U_) { gchar **filenames; int i, n, delta, delta2; VisuDataLoadable *newData; if (window == NULL || context == NULL || data == NULL || gtk_selection_data_get_length(data) < 0) return; #if GTK_MAJOR_VERSION > 2 || GTK_MINOR_VERSION > 21 if (gdk_drag_context_get_suggested_action(context) != GDK_ACTION_COPY) return; #else if (context->action != GDK_ACTION_COPY) return; #endif DBG_fprintf(stderr, " | data: '%d' -> '%s'\n", type, gtk_selection_data_get_data(data)); switch (type) { case TEXT_URI_LIST: filenames = gtk_selection_data_get_uris(data); break; case TEXT_PLAIN: filenames = g_strsplit((gchar*)gtk_selection_data_get_data(data), "\n", -1); break; default: filenames = g_malloc(sizeof(gchar*)); filenames[0] = (gchar*)0; break; } gtk_drag_finish(context, TRUE, TRUE, time); for (i = 0, n = 0; filenames[i]; i++) { g_strstrip(filenames[i]); if (filenames[i][0] != '\0') n +=1; } newData = (VisuDataLoadable*)0; if (n == 1 && filenames[0][0] != '\0') { delta = (strncmp("file://", filenames[0], 7))?0:7; newData = VISU_DATA_LOADABLE(visu_data_atomic_new(filenames[0] + delta, (VisuDataLoader*)0)); } else if (n == 2) { delta = (strncmp("file://", filenames[0], 7))?0:7; delta2 = (strncmp("file://", filenames[1], 7))?0:7; newData = VISU_DATA_LOADABLE(visu_data_spin_new(filenames[0] + delta, filenames[1] + delta2, (VisuDataLoader*)0, (VisuDataLoader*)0)); } else visu_ui_raiseWarning(_("Drag and drop"), _("Too many dropped files."), (GtkWindow*)0); g_strfreev(filenames); visu_ui_rendering_window_loadFile(window, newData, 0); } static void _pushNodeInfo(VisuUiRenderingWindow *window, const VisuData *dataObj, const VisuNode *node) { float posSelect[3], posRef[3]; GString *str; VisuElement *ele; const gchar *comment; g_return_if_fail(VISU_IS_UI_RENDERING_WINDOW(window)); if (window->useReducedCoordinates) { visu_data_getNodeUserPosition(dataObj, node, posRef); visu_box_convertXYZtoBoxCoordinates(visu_boxed_getBox(VISU_BOXED(dataObj)), posSelect, posRef); } else visu_data_getNodeUserPosition(dataObj, node, posSelect); str = g_string_new(_("Selected node number ")); ele = visu_node_array_getElement(VISU_NODE_ARRAY_CONST(dataObj), node); g_string_append_printf(str, "%d - %s (%7.3g;%7.3g;%7.3g)", node->number + 1, ele->name, posSelect[0], posSelect[1], posSelect[2]); comment = visu_data_getNodeLabelAt(dataObj, node); if (comment) g_string_append_printf(str, " %s", comment); visu_ui_rendering_window_pushMessage(window, str->str); g_string_free(str, TRUE); } static void minimalPickInfo(VisuInteractive *inter _U_, VisuInteractivePick pick, VisuData *dataObj, VisuNode *node0, VisuNode *node1, VisuNode *node2 _U_, gpointer data) { float posSelect[3], posRef[3], dist; GString *str; VisuUiRenderingWindow *window; int i; window = VISU_UI_RENDERING_WINDOW(data); g_return_if_fail(window); while (window->nbStatusMessage > 1) visu_ui_rendering_window_popMessage(window); window->selectedNodeId = -1; DBG_fprintf(stderr, "Gtk VisuUiRenderingWindow: update the status bar after pick.\n"); switch (pick) { case PICK_SELECTED: window->selectedNodeId = (gint)node0->number; g_object_notify_by_pspec(G_OBJECT(window), properties[SELECTION_PROP]); _pushNodeInfo(window, dataObj, node0); return; case PICK_DISTANCE: g_object_notify_by_pspec(G_OBJECT(window), properties[SELECTION_PROP]); /* Have a ref and a selected node, then distance informations is computed. */ visu_data_getNodePosition(dataObj, node0, posSelect); visu_data_getNodePosition(dataObj, node1, posRef); str = g_string_new(_("Distance between nodes ")); dist = 0.; for (i = 0; i < 3; i++) dist += (posRef[i] - posSelect[i]) * (posRef[i] - posSelect[i]); dist = sqrt(dist); g_string_append_printf(str, _("%d and %d : %7.3f"), node1->number + 1, node0->number + 1, dist); visu_ui_rendering_window_pushMessage(window, str->str); g_string_free(str, TRUE); return; case PICK_REFERENCE_1: g_object_notify_by_pspec(G_OBJECT(window), properties[SELECTION_PROP]); visu_ui_rendering_window_pushMessage(window, _(" right-click on" " background to unset reference.")); return; case PICK_REFERENCE_2: g_object_notify_by_pspec(G_OBJECT(window), properties[SELECTION_PROP]); visu_ui_rendering_window_pushMessage(window, _(" right-click on" " background to unset second reference.")); return; default: return; } } static void minimalPickError(VisuInteractive *inter _U_, VisuInteractivePickError error, gpointer data) { VisuUiRenderingWindow *window; window = VISU_UI_RENDERING_WINDOW(data); switch (error) { case PICK_ERROR_NO_SELECTION: window->selectedNodeId = -1; g_object_notify_by_pspec(G_OBJECT(window), properties[SELECTION_PROP]); visu_ui_rendering_window_pushMessage(window, _("No node has been selected.")); return; case PICK_ERROR_SAME_REF: visu_ui_rendering_window_pushMessage(window, _("Picked node is already used" " as a reference.")); return; case PICK_ERROR_REF1: visu_ui_rendering_window_pushMessage(window, _("Can't pick a second reference" " without any first one" " (use right-click).")); return; case PICK_ERROR_REF2: visu_ui_rendering_window_pushMessage(window, _("Can't remove first reference" " before removing the second one.")); return; default: return; } } static gulong addInteractiveEventListeners(VisuUiRenderingWindow *window, InteractiveEventsId id) { GList* ptList; InteractiveEvents *event; gboolean found; g_return_val_if_fail(VISU_IS_UI_RENDERING_WINDOW(window), (gulong)0); found = FALSE; for (ptList = window->interactiveEvents; ptList && !found; ptList = g_list_next(ptList)) { event = (InteractiveEvents*)ptList->data; if (event->id == id) found = TRUE; } if (found) return (gulong)0; event = g_malloc(sizeof(InteractiveEvents)); event->id = id; switch (id) { case event_button_press: event->callbackId = g_signal_connect_swapped(G_OBJECT(window->openGLArea), "button-press-event", G_CALLBACK(OnEvent), (gpointer)window); break; case event_button_release: event->callbackId = g_signal_connect_swapped(G_OBJECT(window->openGLArea), "button-release-event", G_CALLBACK(OnEvent), (gpointer)window); break; case event_motion_notify: event->callbackId = g_signal_connect_swapped(G_OBJECT(window->openGLArea), "motion-notify-event", G_CALLBACK(OnEvent), (gpointer)window); break; case event_key_press: event->callbackId = g_signal_connect_swapped(G_OBJECT(window->openGLArea), "key-press-event", G_CALLBACK(OnEvent), (gpointer)window); break; case event_key_release: event->callbackId = g_signal_connect_swapped(G_OBJECT(window->openGLArea), "key-release-event", G_CALLBACK(OnEvent), (gpointer)window); break; case event_scroll: event->callbackId = g_signal_connect_swapped(G_OBJECT(window->openGLArea), "scroll-event", G_CALLBACK(OnEvent), (gpointer)window); break; default: g_warning("Unknown event to add."); g_free(event); return (gulong)0; }; window->interactiveEvents = g_list_prepend(window->interactiveEvents, (gpointer)event); return event->callbackId; } static void setInteractiveType(VisuUiRenderingWindow *window, VisuInteractiveId type) { VisuUiRenderingWindowClass *klass; InteractiveEvents *event; gulong id; GList *ptList; g_return_if_fail(VISU_IS_UI_RENDERING_WINDOW(window)); klass = VISU_UI_RENDERING_WINDOW_CLASS(G_OBJECT_GET_CLASS(window)); g_return_if_fail(klass); /* We set the cursors. */ switch (type) { case interactive_observe: case interactive_measureAndObserve: if (gtk_widget_get_realized(GTK_WIDGET(window))) gdk_window_set_cursor(gtk_widget_get_window(window->openGLArea), window->cursorRotate); window->currentCursor = window->cursorRotate; window->refCursor = window->cursorRotate; break; case interactive_measure: case interactive_pick: case interactive_move: case interactive_mark: if (gtk_widget_get_realized(GTK_WIDGET(window))) gdk_window_set_cursor(gtk_widget_get_window(window->openGLArea), window->cursorPointer); window->currentCursor = window->cursorPointer; window->refCursor = window->cursorPointer; break; case interactive_none: if (gtk_widget_get_realized(GTK_WIDGET(window))) gdk_window_set_cursor(gtk_widget_get_window(window->openGLArea), window->cursorPirate); window->currentCursor = window->cursorPirate; window->refCursor = window->cursorPirate; break; case interactive_drag: if (gtk_widget_get_realized(GTK_WIDGET(window))) gdk_window_set_cursor(gtk_widget_get_window(window->openGLArea), window->cursorGrab); window->currentCursor = window->cursorGrab; window->refCursor = window->cursorGrab; break; } /* We set the listeners. */ if (type != interactive_none) { DBG_fprintf(stderr, "Gtk VisuUiRenderingWindow: setup signals.\n"); id = addInteractiveEventListeners(window, event_button_release); if (id) DBG_fprintf(stderr, " | connecting %ld signal.\n", id); id = addInteractiveEventListeners(window, event_button_press); if (id) DBG_fprintf(stderr, " | connecting %ld signal.\n", id); id = addInteractiveEventListeners(window, event_motion_notify); if (id) DBG_fprintf(stderr, " | connecting %ld signal.\n", id); id = addInteractiveEventListeners(window, event_key_press); if (id) DBG_fprintf(stderr, " | connecting %ld signal.\n", id); id = addInteractiveEventListeners(window, event_key_release); if (id) DBG_fprintf(stderr, " | connecting %ld signal.\n", id); id = addInteractiveEventListeners(window, event_scroll); if (id) DBG_fprintf(stderr, " | connecting %ld signal.\n", id); } else { DBG_fprintf(stderr, "Gtk VisuUiRenderingWindow: removing interactive listeners.\n"); for (ptList = window->interactiveEvents; ptList; ptList = g_list_next(ptList)) { event = (InteractiveEvents*)ptList->data; DBG_fprintf(stderr, " | disconnecting %d signal.\n", event->id); g_signal_handler_disconnect(G_OBJECT(window->openGLArea), event->callbackId); g_free(ptList->data); } if (window->interactiveEvents) g_list_free(window->interactiveEvents); window->interactiveEvents = (GList*)0; } } /** * visu_ui_rendering_window_pushInteractive: * @window: a #VisuUiRenderingWindow object. * @inter: a #VisuInteractive object. * * It adds @inter to the stack of interactive sessions currently * attached to @window and launch it. * * Since: 3.6 */ void visu_ui_rendering_window_pushInteractive(VisuUiRenderingWindow *window, VisuInteractive *inter) { VisuInteractiveId type; g_return_if_fail(VISU_IS_UI_RENDERING_WINDOW(window) && VISU_IS_INTERACTIVE(inter)); DBG_fprintf(stderr, " | interPickObs (%p) has %d ref counts.\n", (gpointer)interPickObs, G_OBJECT(interPickObs)->ref_count); type = visu_interactive_getType(inter); DBG_fprintf(stderr, "Gtk VisuUiRenderingWindow: push a new interactive" " session (%d / %d).\n", type, g_list_length(window->inters)); DBG_fprintf(stderr, " | inter (%p) has %d ref counts.\n", (gpointer)inter, G_OBJECT(inter)->ref_count); window->inters = g_list_prepend(window->inters, inter); g_object_ref(G_OBJECT(inter)); g_object_notify_by_pspec(G_OBJECT(window), properties[INTER_PROP]); DBG_fprintf(stderr, " | inter (%p) has %d ref counts.\n", (gpointer)inter, G_OBJECT(inter)->ref_count); if (visu_interactive_getMessage(inter)) visu_ui_rendering_window_pushMessage(window, visu_interactive_getMessage(inter)); visu_interactive_setNodeList(inter, visu_gl_node_scene_getNodes(window->glScene)); setInteractiveType(window, type); } /** * visu_ui_rendering_window_popInteractive: * @window: a #VisuUiRenderingWindow object. * @inter: a #VisuInteractive object. * * It removes @inter from the stack of interactive sessions currently * attached to @window. If @inter was first on the stack, the next * session is launched. * * Since: 3.6 */ void visu_ui_rendering_window_popInteractive(VisuUiRenderingWindow *window, VisuInteractive *inter) { g_return_if_fail(VISU_IS_UI_RENDERING_WINDOW(window)); visu_interactive_setNodeList(inter, (VisuGlExtNodes*)0); if (!window->inters || window->inters->data != inter) return; window->inters = g_list_remove(window->inters, inter); DBG_fprintf(stderr, "Gtk VisuUiRenderingWindow: pop an old interactive" " session (%d).\n", g_list_length(window->inters)); g_object_notify_by_pspec(G_OBJECT(window), properties[INTER_PROP]); if (visu_interactive_getMessage(inter)) visu_ui_rendering_window_popMessage(window); DBG_fprintf(stderr, " | inter has %d ref counts.\n", G_OBJECT(inter)->ref_count); g_object_unref(G_OBJECT(inter)); if (window->inters) setInteractiveType(window, visu_interactive_getType(VISU_INTERACTIVE(window->inters->data))); else setInteractiveType(window, interactive_none); } static gboolean OnEvent(VisuUiRenderingWindow *window, GdkEvent *event, gpointer user_data _U_) { ToolSimplifiedEvents ev; GList *cameras, *head; if (!window->inters) return FALSE; if (!tool_simplified_events_new_fromGdk(&ev, event)) return FALSE; if (ev.button || ev.letter != '\0' || ev.specialKey != Key_None) { gdk_window_set_cursor(gtk_widget_get_window(window->openGLArea), window->cursorWatch); visu_interactive_handleEvent(VISU_INTERACTIVE(window->inters->data), visu_gl_node_scene_getGlView(window->glScene), &ev); gdk_window_set_cursor(gtk_widget_get_window(window->openGLArea), window->currentCursor); } /* Specific handlings. */ if (ev.letter != '\0') { switch (ev.letter) { case 'r': /* If any camera, print a message. */ visu_interactive_getSavedCameras(VISU_INTERACTIVE(window->inters->data), &cameras, &head); if (cameras) visu_ui_rendering_window_pushMessage (window, _("Restore saved camera position.")); else visu_ui_rendering_window_pushMessage (window, _("No saved camera. Use 's' to save one.")); break; case 's': if (!ev.shiftMod) visu_ui_rendering_window_pushMessage (window, _("Save current camera position.")); else visu_ui_rendering_window_pushMessage (window, _("Pop current camera position.")); break; case 'x': visu_ui_rendering_window_pushMessage (window, _("Align camera with X box axis.")); break; case 'y': visu_ui_rendering_window_pushMessage (window, _("Align camera with Y box axis.")); break; case 'z': visu_ui_rendering_window_pushMessage (window, _("Align camera with Z box axis.")); break; default: break; } #if GLIB_MINOR_VERSION > 13 g_timeout_add_seconds(3, timeOutPopMessage, (gpointer)window); #else g_timeout_add(3000, timeOutPopMessage, (gpointer)window); #endif } if (event->type == GDK_KEY_PRESS && !ev.letter && ev.specialKey == Key_None && (event->key.keyval == GDK_KEY_Shift_L || event->key.keyval == GDK_KEY_Shift_R)) { gdk_window_set_cursor(gtk_widget_get_window(window->openGLArea), window->cursorGrab); window->currentCursor = window->cursorGrab; } else if (event->type == GDK_KEY_RELEASE && !ev.letter && ev.specialKey == Key_None && (event->key.keyval == GDK_KEY_Shift_L || event->key.keyval == GDK_KEY_Shift_R)) { gdk_window_set_cursor(gtk_widget_get_window(window->openGLArea), window->refCursor); window->currentCursor = window->refCursor; } return FALSE; } static gboolean timeOutPopMessage(gpointer data) { visu_ui_rendering_window_popMessage(VISU_UI_RENDERING_WINDOW(data)); return FALSE; } /** * visu_ui_rendering_window_pushMessage: * @window: a valid #VisuUiRenderingWindow object ; * @message: an UTF8 string to print on the status bar. * * Use this method to add some informations on the status bar. */ void visu_ui_rendering_window_pushMessage(VisuUiRenderingWindow *window, const gchar *message) { g_return_if_fail(VISU_IS_UI_RENDERING_WINDOW(window)); gtk_statusbar_push(GTK_STATUSBAR(window->info.statusInfo), window->info.statusInfoId, message); window->nbStatusMessage += 1; } /** * visu_ui_rendering_window_popMessage: * @window: a valid #VisuUiRenderingWindow object. * * Remove the last message. */ void visu_ui_rendering_window_popMessage(VisuUiRenderingWindow *window) { g_return_if_fail(VISU_IS_UI_RENDERING_WINDOW(window)); gtk_statusbar_pop(GTK_STATUSBAR(window->info.statusInfo), window->info.statusInfoId); window->nbStatusMessage -= 1; } static void getOpenGLAreaSize(VisuUiRenderingWindow *window, guint *width, guint *height) { GtkAllocation alloc; g_return_if_fail(VISU_IS_UI_RENDERING_WINDOW(window) && width && height); gtk_widget_get_allocation(window->openGLArea, &alloc); *width = alloc.width; *height = alloc.height; } static void onDataNotify(VisuUiRenderingWindow *window, GParamSpec *pspec _U_, VisuGlNodeScene *scene) { VisuData *data; DBG_fprintf(stderr, "##### VisuData association to a window #####\n"); data = visu_gl_node_scene_getData(scene); /* Reset the statusbar informations and other GUI parameters. */ while (window->nbStatusMessage > 1) visu_ui_rendering_window_popMessage(window); if (!window->inters && data) visu_ui_rendering_window_pushInteractive(window, interPickObs); else if (!data) visu_ui_rendering_window_popInteractive(window, interPickObs); g_clear_object(&window->info.bind_nb); g_clear_object(&window->info.bind_info); if (data) { DBG_fprintf(stderr, " | current data has %d ref counts.\n", G_OBJECT(data)->ref_count); /* Attach the default redraw method. */ visu_ui_gl_widget_setModel(VISU_UI_GL_WIDGET(window->openGLArea), VISU_GL_EXT_SET(window->glScene)); window->info.bind_nb = g_object_bind_property_full(data, "n-nodes", window->info.labelNb, "label", G_BINDING_SYNC_CREATE, toNNodeLabel, (GBindingTransformFunc)0, (gpointer)0, (GDestroyNotify)0); window->info.bind_info = g_object_bind_property_full(data, "description", window->info.labelFileInfo, "label", G_BINDING_SYNC_CREATE, toFileInfo, (GBindingTransformFunc)0, (gpointer)0, (GDestroyNotify)0); } else { /* Attach the default redraw method. */ visu_ui_gl_widget_setModel(VISU_UI_GL_WIDGET(window->openGLArea), (VisuGlExtSet*)0); } g_object_notify_by_pspec(G_OBJECT(window), properties[DATA_PROP]); g_object_notify_by_pspec(G_OBJECT(window), properties[LABEL_PROP]); if (!data) { #if GTK_MAJOR_VERSION > 2 || GTK_MINOR_VERSION > 17 gtk_widget_hide(GTK_WIDGET(window->info.infoBar)); #endif gtk_widget_grab_focus(window->openGLArea); } } /** * visu_ui_rendering_window_getGlScene: * @window: a valid #VisuUiRenderingWindow object. * * This method is used to get the #VisuGlExtSet attached to the * rendering window. * * Since: 3.8 * * Returns: (transfer none): the #VisuGlNodeScene attached to the @window * or NULL on error. **/ VisuGlNodeScene* visu_ui_rendering_window_getGlScene(VisuUiRenderingWindow *window) { g_return_val_if_fail(VISU_IS_UI_RENDERING_WINDOW(window), (VisuGlNodeScene*)0); return window->glScene; } /** * visu_ui_rendering_window_getAccelGroup: * @window: a #VisuUiRenderingWindow object. * * Retrieve the accelerator group of @window. * * Since: 3.7 * * Returns: (transfer none): the #GtkAccelGroup object of @window. **/ GtkAccelGroup* visu_ui_rendering_window_getAccelGroup(VisuUiRenderingWindow *window) { g_return_val_if_fail(VISU_IS_UI_RENDERING_WINDOW(window), (GtkAccelGroup*)0); return window->accel; } /***************************/ /* GtkStatusInfo functions */ /***************************/ static void _setLabelSize(GtkInfoArea *info, gint width, gint height) { gchar *str; g_return_if_fail(info); if (info->fileInfoFreeze) return; str = g_strdup_printf("%s %dx%d", _("Size:"), width, height); gtk_label_set_markup(GTK_LABEL(info->labelSize), str); g_free(str); } static void onNodeInfoClicked(VisuUiRenderingWindow *window, GtkToggleButton *button) { if (window->selectedNodeId >= 0) visu_gl_node_scene_setMark(window->glScene, window->selectedNodeId, gtk_toggle_button_get_active(button)); } static void onMarkClearClicked(VisuUiRenderingWindow *window, GtkButton *button _U_) { visu_gl_node_scene_removeMarks(window->glScene); } static gboolean onCameraMenu(VisuUiRenderingWindow *window, GdkEventButton *event, GtkEventBox *ev _U_) { GtkWidget *wd; DBG_fprintf(stderr, "Gtk VisuUiRenderingWindow: click on the camera menu.\n"); wd = buildCameraMenu(window); if (!wd) return TRUE; g_signal_connect(G_OBJECT(wd), "selection-done", G_CALLBACK(onCameraMenuSelected), (gpointer)window); gtk_widget_show_all(wd); #if GTK_MAJOR_VERSION < 2 || (GTK_MAJOR_VERSION == 3 && GTK_MINOR_VERSION < 22) gtk_menu_popup(GTK_MENU(wd), NULL, NULL, NULL, NULL, 1, event->time); #else gtk_menu_popup_at_pointer(GTK_MENU(wd), (const GdkEvent*)event); #endif return TRUE; } static GtkWidget* buildCameraMenu(VisuUiRenderingWindow *window) { GtkWidget *menu, *item; gchar *lbl; GList *cameras, *head, *tmpLst, *rCameras; VisuGlCamera *current; guint n; if (!window->inters) return (GtkWidget*)0; /* All camera. */ DBG_fprintf(stderr, "Gtk VisuUiRenderingWindow: get the cameras.\n"); visu_interactive_getSavedCameras(VISU_INTERACTIVE(window->inters->data), &cameras, &head); /* if (!cameras) */ /* return (GtkWidget*)0; */ DBG_fprintf(stderr, "Gtk VisuUiRenderingWindow: build the menu.\n"); menu = gtk_menu_new(); gtk_menu_set_accel_group(GTK_MENU(menu), window->accel); DBG_fprintf(stderr, "Gtk VisuUiRenderingWindow: create the camera menu %p.\n", (gpointer)menu); /* Set a title. */ item = gtk_menu_item_new_with_label(_("Camera menu (saved in 'v_sim.par'):")); gtk_widget_set_sensitive(item, FALSE); gtk_menu_shell_append(GTK_MENU_SHELL(menu), item); item = gtk_separator_menu_item_new(); gtk_menu_shell_append(GTK_MENU_SHELL(menu), item); /* Put the current camera. */ current = &visu_gl_node_scene_getGlView(window->glScene)->camera; lbl = g_strdup_printf(_("save current camera:\n" "(\316\270 %6.1f\302\260 ; \317\206 %6.1f\302\260 ; \317\211 %6.1f\302\260) " "dx %4.1f dy %4.1f"), current->theta, current->phi, current->omega, current->xs, current->ys); item = gtk_menu_item_new_with_label(lbl); g_free(lbl); g_signal_connect(G_OBJECT(item), "activate", G_CALLBACK(onCameraMenuCurrentClicked), window); gtk_menu_item_set_accel_path(GTK_MENU_ITEM(item), g_intern_static_string(MENU_CAMERA_SAVE)); gtk_menu_shell_append(GTK_MENU_SHELL(menu), item); /* Put an option to open the view selector. */ item = gtk_menu_item_new_with_label(_("select precisely a camera view")); g_signal_connect(G_OBJECT(item), "activate", G_CALLBACK(onCameraMenuOrientationClicked), window); gtk_menu_item_set_accel_path(GTK_MENU_ITEM(item), g_intern_static_string(MENU_CAMERA_ORIENT)); gtk_menu_shell_append(GTK_MENU_SHELL(menu), item); /* Separator. */ item = gtk_separator_menu_item_new(); gtk_menu_shell_append(GTK_MENU_SHELL(menu), item); if (!cameras) { item = gtk_menu_item_new_with_label(_("No saved camera. Use 's' to save one.")); gtk_menu_shell_append(GTK_MENU_SHELL(menu), item); } else { item = gtk_menu_item_new_with_label(_("List of saved cameras:")); gtk_widget_set_sensitive(item, FALSE); gtk_menu_shell_append(GTK_MENU_SHELL(menu), item); } rCameras = g_list_reverse(g_list_copy(cameras)); for (tmpLst = rCameras, n = 0; tmpLst; tmpLst = g_list_next(tmpLst), n+= 1) { current = (VisuGlCamera*)tmpLst->data; lbl = g_strdup_printf(_("(\316\270 %6.1f\302\260 ; \317\206 %6.1f\302\260 ; \317\211 %6.1f\302\260) " "dx %4.1f dy %4.1f"), current->theta, current->phi, current->omega, current->xs, current->ys); item = gtk_menu_item_new_with_label(lbl); DBG_fprintf(stderr, " | add menu item %p (%p)\n", (gpointer)item, (gpointer)window); g_free(lbl); if (current == (VisuGlCamera*)head->data) gtk_menu_item_set_accel_path(GTK_MENU_ITEM(item), g_intern_static_string(MENU_CAMERA_RESTORE)); else if (n < 9) gtk_menu_item_set_accel_path(GTK_MENU_ITEM(item), g_intern_static_string(cameraAccels[n])); g_signal_connect(G_OBJECT(item), "activate", G_CALLBACK(onCameraMenuClicked), window); g_object_set_data(G_OBJECT(item), "Camera", (gpointer)current); gtk_menu_shell_append(GTK_MENU_SHELL(menu), item); } g_list_free(rCameras); return menu; } static void _setCamera(VisuUiRenderingWindow *window, VisuGlCamera *camera) { g_return_if_fail(VISU_IS_UI_RENDERING_WINDOW(window)); if (!window->inters || !camera) return; visu_interactive_pushSavedCamera(VISU_INTERACTIVE(window->inters->data), camera); visu_gl_node_scene_setGlCamera(window->glScene, camera); } static gboolean onCameraAccel(GtkAccelGroup *accel _U_, GObject *obj, guint key, GdkModifierType mod _U_, gpointer data) { VisuUiRenderingWindow *window; GList *cameras, *head, *rCameras; VisuGlCamera *camera; DBG_fprintf(stderr, "Gtk VisuUiRenderingWindow: get accelerator for object %p.\n", (gpointer)obj); window = VISU_UI_RENDERING_WINDOW(data); /* All camera. */ DBG_fprintf(stderr, "Gtk VisuUiRenderingWindow: get the cameras.\n"); visu_interactive_getSavedCameras(VISU_INTERACTIVE(window->inters->data), &cameras, &head); if (!cameras) return TRUE; rCameras = g_list_reverse(g_list_copy(cameras)); camera = g_list_nth_data(rCameras, key - GDK_KEY_1); g_list_free(rCameras); _setCamera(window, camera); return TRUE; } static void onCameraMenuSelected(GtkMenuShell *menushell, gpointer user_data _U_) { DBG_fprintf(stderr, "Gtk VisuUiRenderingWindow: destroy the camera menu %p.\n", (gpointer)menushell); gtk_widget_destroy(GTK_WIDGET(menushell)); } static void onCameraMenuClicked(GtkMenuItem *menuitem, gpointer user_data) { _setCamera(VISU_UI_RENDERING_WINDOW(user_data), (VisuGlCamera*)g_object_get_data(G_OBJECT(menuitem), "Camera")); } static void onCameraMenuCurrentClicked(GtkMenuItem *menuitem _U_, gpointer user_data) { visu_interactive_pushSavedCamera(VISU_INTERACTIVE(VISU_UI_RENDERING_WINDOW(user_data)->inters->data), &visu_gl_node_scene_getGlView(VISU_UI_RENDERING_WINDOW(user_data)->glScene)->camera); } static void onOrientationChanged(VisuUiOrientationChooser *orientationChooser, gpointer data) { float values[2]; DBG_fprintf(stderr, "Gtk VisuUiRenderingWindow: orientation changed.\n"); visu_ui_orientation_chooser_getAnglesValues(orientationChooser, values); g_object_set(visu_gl_node_scene_getGlView(VISU_UI_RENDERING_WINDOW(data)->glScene), "theta", values[0], "phi", values[1], NULL); } static void _orientationChooser(VisuUiRenderingWindow *window) { GtkWidget *orientationChooser; VisuGlView *view; VisuGlCamera *current; float values[2]; view = visu_gl_node_scene_getGlView(window->glScene); orientationChooser = visu_ui_orientation_chooser_new (VISU_UI_ORIENTATION_DIRECTION, TRUE, VISU_BOXED(view), NULL); gtk_window_set_modal(GTK_WINDOW(orientationChooser), TRUE); current = &view->camera; values[0] = current->theta; values[1] = current->phi; visu_ui_orientation_chooser_setAnglesValues(VISU_UI_ORIENTATION_CHOOSER(orientationChooser), values); g_signal_connect(G_OBJECT(orientationChooser), "values-changed", G_CALLBACK(onOrientationChanged), window); gtk_widget_show(orientationChooser); switch (gtk_dialog_run(GTK_DIALOG(orientationChooser))) { case GTK_RESPONSE_ACCEPT: DBG_fprintf(stderr, "Gtk VisuUiRenderingWindow: accept changings on orientation.\n"); break; default: DBG_fprintf(stderr, "Gtk Observe: reset values on orientation.\n"); g_object_set(view, "theta", values[0], "phi", values[1], NULL); } DBG_fprintf(stderr, "Gtk Observe: orientation object destroy.\n"); gtk_widget_destroy(orientationChooser); } static void onCameraMenuOrientationClicked(GtkMenuItem *menuitem _U_, gpointer data) { _orientationChooser(VISU_UI_RENDERING_WINDOW(data)); } void visu_ui_rendering_window_lockUI(VisuUiRenderingWindow *window, gboolean status) { g_return_if_fail(VISU_IS_UI_RENDERING_WINDOW(window)); gtk_widget_set_sensitive(window->info.hboxTools, !status); gtk_widget_set_sensitive(window->info.hboxInteractive, !status); gtk_widget_set_sensitive(window->info.hboxFileInfo, !status); } struct _load_struct { VisuUiRenderingWindow *window; VisuDataLoadable *data; guint iSet; }; static void stopProgress(VisuUiRenderingWindow *window) { if (window->info.progressId) g_source_remove(window->info.progressId); window->info.progressId = 0; gtk_widget_hide(window->info.progress); gtk_widget_hide(window->info.cancelButton); gtk_widget_show(window->info.statusInfo); visu_ui_rendering_window_lockUI(window, FALSE); } static gboolean popProgress(gpointer data) { VisuUiRenderingWindow *window; window = VISU_UI_RENDERING_WINDOW(data); gtk_progress_bar_pulse(GTK_PROGRESS_BAR(window->info.progress)); return TRUE; } static gboolean showProgress(gpointer data) { VisuUiRenderingWindow *window; window = VISU_UI_RENDERING_WINDOW(data); visu_ui_rendering_window_lockUI(window, TRUE); gtk_widget_show(window->info.progress); gtk_widget_show(window->info.cancelButton); gtk_widget_hide(window->info.statusInfo); gtk_progress_bar_set_text(GTK_PROGRESS_BAR(window->info.progress), _("Loading file...")); if (window->info.progressId) g_source_remove(window->info.progressId); window->info.progressId = g_timeout_add(100, popProgress, data); window->info.waitId = 0; return FALSE; } static void onCancelButtonClicked(GtkButton *button _U_, gpointer data) { gtk_progress_bar_set_text(GTK_PROGRESS_BAR(VISU_UI_RENDERING_WINDOW(data)->info.progress), _("Cancellation request, waiting for reply...")); g_cancellable_cancel(VISU_UI_RENDERING_WINDOW(data)->info.cancel); } static void onLoadingNotified(VisuUiRenderingWindow *window, GParamSpec *pspec _U_, VisuGlNodeScene *scene) { gboolean loading; g_object_get(scene, "loading", &loading, NULL); if (loading) { if (window->info.waitId) return; window->info.waitId = g_timeout_add(500, showProgress, window); } else { if (!window->info.waitId) return; g_source_remove(window->info.waitId); window->info.waitId = 0; stopProgress(window); } } static gboolean _loadFile(gpointer data) { GError *error; gboolean res; VisuUiRenderingWindow *window; struct _load_struct *pt; /* obj is the new object and main the panel that handle the loading. */ pt = (struct _load_struct*)data; window = pt->window; DBG_fprintf(stderr, "VisuUiRenderingWindow: loading process ... %p points to" " previous VisuData.\n", (gpointer)visu_gl_node_scene_getData(window->glScene)); DBG_fprintf(stderr, " | loading data has %d ref counts.\n", G_OBJECT(pt->data)->ref_count); error = (GError*)0; res = visu_gl_node_scene_loadData(window->glScene, pt->data, pt->iSet, window->info.cancel, &error); DBG_fprintf(stderr, " | loaded data has %d ref counts.\n", G_OBJECT(pt->data)->ref_count); if (!res) { if (error) { visu_ui_raiseWarning(_("Loading a file"), error->message, NULL); g_error_free(error); } else g_warning("No error message."); } else visu_ui_storeRecent(visu_data_loadable_getFilename(pt->data, 0)); /* We release a ref on obj, since visu_ui_rendering_window_setData has increased it. */ g_object_unref(pt->data); g_free(pt); return FALSE; } /** * visu_ui_rendering_window_loadFile: * @window: a valid #VisuUiRenderingWindow object. * @data: (transfer full) (allow-none): the #VisuData to be loaded. * @iSet: the id of @data to load. * * This method calls the general function to load data from file * and deals with errors with gtkDialogs. The filenames must have * already been set into @data using visu_data_addFile(). */ void visu_ui_rendering_window_loadFile(VisuUiRenderingWindow *window, VisuDataLoadable *data, guint iSet) { struct _load_struct *pt; pt = g_malloc(sizeof(struct _load_struct)); pt->window = window; pt->data = data; pt->iSet = iSet; g_idle_add(_loadFile, pt); } /** * visu_ui_rendering_window_open: * @window: the window the file will by rendered on ; * @parent: (allow-none): the parent window for the filechooser dialog. * * Do as if the load button has been pushed, i.e. open a filechooser * dialog on the @parent window, and load the resulting file, * refreshing the view if necessary. */ void visu_ui_rendering_window_open(VisuUiRenderingWindow *window, GtkWindow *parent) { GtkWidget *chooser; VisuDataLoadable *newData; gchar *directory; const gchar *curDir; VisuUiMain *ui; ui = visu_ui_main_class_getCurrentPanel(); chooser = visu_ui_data_chooser_new(parent); if (ui && (curDir = visu_ui_main_getLastOpenDirectory(ui))) gtk_file_chooser_set_current_folder(GTK_FILE_CHOOSER(chooser), curDir); newData = visu_ui_data_chooser_run(VISU_UI_DATA_CHOOSER(chooser)); if (ui) { directory = gtk_file_chooser_get_current_folder(GTK_FILE_CHOOSER(chooser)); visu_ui_main_setLastOpenDirectory(ui, directory, VISU_UI_DIR_FILE); g_free(directory); } gtk_widget_destroy(GTK_WIDGET(chooser)); if (!newData) return; DBG_fprintf(stderr, "Gtk RenderingWindow: open file ref count %d.\n", G_OBJECT(newData)->ref_count); visu_ui_rendering_window_setCurrent(window, TRUE); if (newData && !visu_node_array_getNNodes(VISU_NODE_ARRAY(newData))) visu_ui_rendering_window_loadFile(window, g_object_ref(newData), 0); else if (newData) { visu_gl_node_scene_setData(window->glScene, VISU_DATA(newData)); visu_ui_storeRecent(visu_data_loadable_getFilename(newData, 0)); } g_object_unref(newData); } static void onOpen(VisuUiRenderingWindow *window) { visu_ui_rendering_window_open(window, (GtkWindow*)0); } static gboolean _reload(VisuUiRenderingWindow *window) { GError *error; VisuData *dataObj; g_return_val_if_fail(VISU_IS_UI_RENDERING_WINDOW(window), FALSE); DBG_fprintf(stderr, "Gtk VisuUiRenderingWindow: reload current file.\n"); dataObj = visu_gl_node_scene_getData(window->glScene); if (!VISU_IS_DATA_LOADABLE(dataObj)) return FALSE; error = (GError*)0; if (!visu_data_loadable_reload(VISU_DATA_LOADABLE(dataObj), window->info.cancel, &error) && error) { visu_ui_raiseWarning(_("Reloading file"), error->message, NULL); g_error_free(error); } return FALSE; } /** * visu_ui_rendering_window_reload: * @window: a #VisuUiRenderingWindow object. * * This routines reloads the current #VisuData object by rereading it * on disk. If there is no current #VisuData object, it reports an * error. * * Since: 3.7 */ void visu_ui_rendering_window_reload(VisuUiRenderingWindow *window) { g_idle_add((GSourceFunc)_reload, window); } static gboolean toNNodeLabel(GBinding *binding _U_, const GValue *source_value, GValue *target_value, gpointer data _U_) { gchar *str; if (g_value_get_uint(source_value) > 0) str = g_strdup_printf("%s %d", _("Nb nodes:"), g_value_get_uint(source_value)); else str = g_strdup_printf("%s", GTK_STATUSINFO_NONB); g_value_take_string(target_value, str); return TRUE; } static gboolean toFileInfo(GBinding *binding _U_, const GValue *source_value, GValue *target_value, gpointer data _U_) { const gchar *descr; descr = g_value_get_string(source_value); if (!descr || !descr[0]) descr = GTK_STATUSINFO_NOFILEINFO; g_value_take_string(target_value, g_strdup_printf("%s", descr)); return TRUE; } void updateDumpProgressBar(gpointer data) { gdouble val; g_return_if_fail(GTK_PROGRESS_BAR(data)); gtk_progress_bar_set_text(GTK_PROGRESS_BAR(data), _("Saving image...")); val = gtk_progress_bar_get_fraction(GTK_PROGRESS_BAR(data)); if (val + 0.01 <= 1.0 && val >= 0.) gtk_progress_bar_set_fraction(GTK_PROGRESS_BAR(data), val + 0.01); visu_ui_wait(); } static void onExport(VisuUiRenderingWindow *window) { GtkWidget *dump; char *filename; VisuDump *format; gboolean res; GError *error; GdkCursor *cursorWatch; GtkProgressBar *dumpBar; VisuGlView *view; g_return_if_fail(VISU_IS_UI_RENDERING_WINDOW(window)); view = visu_gl_node_scene_getGlView(window->glScene); dump = visu_ui_dump_dialog_new(visu_gl_node_scene_getData(window->glScene), (GtkWindow*)0, (const gchar*)0, view->window.width, view->window.height); if (gtk_dialog_run(GTK_DIALOG(dump)) != GTK_RESPONSE_ACCEPT) { gtk_widget_destroy(dump); return; } filename = visu_ui_dump_dialog_getFilename(VISU_UI_DUMP_DIALOG(dump)); format = visu_ui_dump_dialog_getType(VISU_UI_DUMP_DIALOG(dump)); g_return_if_fail(format && filename); DBG_fprintf(stderr, "Gtk VisuUiRenderingWindow: dump image to file '%s' (format : %s)\n", filename, tool_file_format_getName(TOOL_FILE_FORMAT(format))); cursorWatch = gdk_cursor_new_for_display(gtk_widget_get_display(dump), GDK_WATCH); dumpBar = visu_ui_dump_dialog_getProgressBar(VISU_UI_DUMP_DIALOG(dump)); visu_ui_dump_dialog_start(VISU_UI_DUMP_DIALOG(dump)); gtk_progress_bar_set_fraction(dumpBar, 0.); if (VISU_IS_DUMP_SCENE(format)) gtk_progress_bar_set_text(dumpBar, _("Waiting for generating image in memory...")); visu_ui_wait(); gdk_window_set_cursor(gtk_widget_get_window(dump), cursorWatch); error = (GError*)0; DBG_fprintf(stderr, " | starting dump.\n"); res = visu_gl_node_scene_dump(window->glScene, format, filename, visu_ui_dump_dialog_getWidth(VISU_UI_DUMP_DIALOG(dump)), visu_ui_dump_dialog_getHeight(VISU_UI_DUMP_DIALOG(dump)), updateDumpProgressBar, (gpointer)dumpBar, &error); if (res) /* Save file as recent. */ visu_ui_storeRecent(filename); if (!res && error) visu_ui_raiseWarning(_("Saving a file"), error->message, (GtkWindow*)0); gdk_window_set_cursor(gtk_widget_get_window(GTK_WIDGET(dump)), NULL); if (error) g_error_free(error); DBG_fprintf(stderr, " | release UI resources.\n"); gtk_widget_destroy(dump); visu_ui_gl_widget_setCurrent(VISU_UI_GL_WIDGET(window->openGLArea), TRUE); g_object_unref(cursorWatch); } static void onRaiseButtonClicked(VisuUiRenderingWindow *window, gpointer user_data _U_) { g_signal_emit(G_OBJECT(window), _signals[SHOW_MAIN_PANEL_SIGNAL], 0 /* details */, NULL); } static void _redraw(VisuUiRenderingWindow *window, gboolean forceRedraw) { VisuUiRenderingWindow *current; g_return_if_fail(VISU_IS_UI_RENDERING_WINDOW(window)); DBG_fprintf(stderr, "Gtk VisuUiRenderingWindow: redraw to visible %d.\n", gtk_widget_get_visible(GTK_WIDGET(window))); if (!gtk_widget_get_visible(GTK_WIDGET(window))) return; current = VISU_UI_RENDERING_WINDOW_GET_CLASS(window)->redrawWidget; DBG_fprintf(stderr, "Gtk VisuUiRenderingWindow: redraw if current %p %p.\n", (gpointer)current, (gpointer)window); if (!current || current != window) return; if (!visu_gl_getImmediate(VISU_GL(window->glScene)) && !forceRedraw) { DBG_fprintf(stderr, "Redraw rejected since drawing is deferred and not forced.\n"); return; } DBG_fprintf(stderr, "Redraw accepted let's go...\n"); gtk_widget_queue_draw(window->openGLArea); } /** * visu_ui_rendering_window_setCurrent: * @window: a valid #VisuUiRenderingWindow object ; * @force: a boolean. * * Set the OpenGL area as the current rendering area. If @force is TRUE * then the context is switched whatever buffered value. * * Since: 3.5 */ void visu_ui_rendering_window_setCurrent(VisuUiRenderingWindow *window, gboolean force) { g_return_if_fail(VISU_IS_UI_RENDERING_WINDOW(window)); visu_ui_gl_widget_setCurrent(VISU_UI_GL_WIDGET(window->openGLArea), force); VISU_UI_RENDERING_WINDOW_GET_CLASS(window)->redrawWidget = window; } static void onGlDirty(VisuUiRenderingWindow *window) { DBG_fprintf(stderr, "Gtk RenderingWindow: Gl is dirty, redrawing.\n"); _redraw(window, FALSE); } static void _onSearch(VisuUiRenderingWindow *window) { if (!visu_gl_node_scene_getData(window->glScene)) return; #if GTK_MAJOR_VERSION > 2 || GTK_MINOR_VERSION > 17 gtk_widget_show(window->info.infoBar); gtk_widget_grab_focus(window->info.searchEntry); gtk_entry_set_icon_from_icon_name(GTK_ENTRY(window->info.searchEntry), GTK_ENTRY_ICON_SECONDARY, NULL); gtk_entry_set_text(GTK_ENTRY(window->info.searchEntry), ""); #endif } #if GTK_MAJOR_VERSION > 2 || GTK_MINOR_VERSION > 17 static void _onSearchClose(GtkInfoBar *bar, gint response, gpointer data) { if (response == GTK_RESPONSE_CLOSE) { gtk_widget_hide(GTK_WIDGET(bar)); gtk_widget_grab_focus(VISU_UI_RENDERING_WINDOW(data)->openGLArea); } } static void _onSearchEdited(GtkEntry *entry, gpointer data) { VisuGlNodeScene *scene = VISU_GL_NODE_SCENE(data); gint i; gchar *end; const gchar *val; VisuNode *node; gtk_entry_set_icon_from_icon_name(entry, GTK_ENTRY_ICON_SECONDARY, NULL); val = gtk_entry_get_text(entry); DBG_fprintf(stderr, "Gtk RenderingWindow: search on '%s'.\n", val); i = strtol(val, &end, 10); if (end == val || i <= 0) { gtk_entry_set_icon_from_icon_name(entry, GTK_ENTRY_ICON_SECONDARY, "dialog-warning"); return; } i -= 1; node = visu_node_array_getFromId(VISU_NODE_ARRAY(visu_gl_node_scene_getData(scene)), i); if (!node) { gtk_entry_set_icon_from_icon_name(entry, GTK_ENTRY_ICON_SECONDARY, "dialog-warning"); return; } visu_interactive_highlight(interPickObs, i); } static gboolean _onSearchEsc(GtkWidget *widget, GdkEventKey *event, gpointer data _U_) { if (event->keyval == GDK_KEY_Escape) { gtk_info_bar_response(GTK_INFO_BAR(widget), GTK_RESPONSE_CLOSE); return TRUE; } return FALSE; } #endif /** * visu_ui_rendering_window_setDisplayCoordinatesInReduce: * @window: a #VisuUiRenderingWindow object. * @status: a boolean. * * If set, the coordinates of picked nodes are displayed in reduced values. * * Returns: TRUE if the value has been changed. * * Since: 3.6 */ gboolean visu_ui_rendering_window_setDisplayCoordinatesInReduce(VisuUiRenderingWindow *window, gboolean status) { VisuData *dataObj; g_return_val_if_fail(VISU_IS_UI_RENDERING_WINDOW(window), FALSE); if (status == window->useReducedCoordinates) return FALSE; window->useReducedCoordinates = status; g_object_notify_by_pspec(G_OBJECT(window), properties[COORD_PROP]); dataObj = visu_gl_node_scene_getData(window->glScene); if (window->selectedNodeId >= 0 && dataObj) { visu_ui_rendering_window_popMessage(window); _pushNodeInfo(window, dataObj, visu_node_array_getFromId(VISU_NODE_ARRAY(dataObj), window->selectedNodeId)); } return TRUE; } /** * visu_ui_rendering_window_getDisplayCoordinatesInReduce: * @window: a #VisuUiRenderingWindow object. * * Picked nodes have their coordinates displayed in the status bar of the rendering * window. This methods retrieves if they are printed in reduced values or not. * * Returns: TRUE if the coordinates are displayed in reduced values. * * Since: 3.6 */ gboolean visu_ui_rendering_window_getDisplayCoordinatesInReduce(const VisuUiRenderingWindow *window) { g_return_val_if_fail(VISU_IS_UI_RENDERING_WINDOW(window), FALSE); return window->useReducedCoordinates; } /** * visu_ui_rendering_window_class_finalize: (skip) * * Free memory related to the #VisuInteractive object used * * Since: 3.8 **/ void visu_ui_rendering_window_class_finalize(void) { if (interPickObs) g_object_unref(interPickObs); interPickObs = (VisuInteractive*)0; } /*************************************/ /* Routines related to config files. */ /*************************************/ static void onEntryCoord(VisuUiRenderingWindow *window) { visu_ui_rendering_window_setDisplayCoordinatesInReduce(window, _useReducedCoordinates); } static void exportParameters(GString *data, VisuData *dataObj _U_) { if (!_defaultRendering) return; g_string_append_printf(data, "# %s\n", DESC_PARAMETER_RED_COORD); g_string_append_printf(data, "%s[gtk]: %d\n\n", FLAG_PARAMETER_RED_COORD, _defaultRendering->useReducedCoordinates); } v_sim-3.8.0/src/gtk_renderingWindowWidget.h000066400000000000000000000130101370110300500207360ustar00rootroot00000000000000/* EXTRAITS DE LA LICENCE Copyright CEA, contributeurs : Luc BILLARD et Damien CALISTE, laboratoire L_Sim, (2001-2006) Adresse mèl : BILLARD, non joignable par mèl ; CALISTE, damien P caliste AT cea P fr. Ce logiciel est un programme informatique servant à visualiser des structures atomiques dans un rendu pseudo-3D. Ce logiciel est régi par la licence CeCILL soumise au droit français et respectant les principes de diffusion des logiciels libres. Vous pouvez utiliser, modifier et/ou redistribuer ce programme sous les conditions de la licence CeCILL telle que diffusée par le CEA, le CNRS et l'INRIA sur le site "http://www.cecill.info". Le fait que vous puissiez accéder à cet en-tête signifie que vous avez pris connaissance de la licence CeCILL, et que vous en avez accepté les termes (cf. le fichier Documentation/licence.fr.txt fourni avec ce logiciel). */ /* LICENCE SUM UP Copyright CEA, contributors : Luc BILLARD et Damien CALISTE, laboratoire L_Sim, (2001-2006) E-mail address: BILLARD, not reachable any more ; CALISTE, damien P caliste AT cea P fr. This software is a computer program whose purpose is to visualize atomic configurations in 3D. This software is governed by the CeCILL license under French law and abiding by the rules of distribution of free software. You can use, modify and/ or redistribute the software under the terms of the CeCILL license as circulated by CEA, CNRS and INRIA at the following URL "http://www.cecill.info". The fact that you are presently reading this means that you have had knowledge of the CeCILL license and that you accept its terms. You can find a copy of this licence shipped with this software at Documentation/licence.en.txt. */ #ifndef GTK_RENDERINGWINDOW_H #define GTK_RENDERINGWINDOW_H #include #include #include #include "visu_dataloadable.h" #include "visu_dump.h" #include "visu_glnodescene.h" #include "openGLFunctions/interactive.h" G_BEGIN_DECLS /** * VISU_TYPE_UI_RENDERING_WINDOW: * * Return the associated #GType to the Renderingwindow objects. */ #define VISU_TYPE_UI_RENDERING_WINDOW (visu_ui_rendering_window_get_type()) /** * VISU_UI_RENDERING_WINDOW: * @obj: the widget to cast. * * Cast the given object to a #VisuUiRenderingWindow object. */ #define VISU_UI_RENDERING_WINDOW(obj) (G_TYPE_CHECK_INSTANCE_CAST((obj), VISU_TYPE_UI_RENDERING_WINDOW, VisuUiRenderingWindow)) /** * VISU_UI_RENDERING_WINDOW_CLASS: * @klass: the class to cast. * * Cast the given class to a #VisuUiRenderingWindowClass object. */ #define VISU_UI_RENDERING_WINDOW_CLASS(klass) (G_TYPE_CHECK_CLASS_CAST((klass), VISU_TYPE_UI_RENDERING_WINDOW, VisuUiRenderingWindowClass)) /** * VISU_IS_UI_RENDERING_WINDOW: * @obj: the object to test. * * Return if the given object is a valid #VisuUiRenderingWindow object. */ #define VISU_IS_UI_RENDERING_WINDOW(obj) (G_TYPE_CHECK_INSTANCE_TYPE((obj), VISU_TYPE_UI_RENDERING_WINDOW)) /** * VISU_IS_UI_RENDERING_WINDOW_CLASS: * @klass: the class to test. * * Return if the given class is a valid #VisuUiRenderingWindowClass class. */ #define VISU_IS_UI_RENDERING_WINDOW_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE((klass), VISU_TYPE_UI_RENDERING_WINDOW)) /** * VISU_UI_RENDERING_WINDOW_GET_CLASS: * @obj: a #GObject to get the class of. * * It returns the class of the given @obj. */ #define VISU_UI_RENDERING_WINDOW_GET_CLASS(obj) (G_TYPE_INSTANCE_GET_CLASS(obj, VISU_TYPE_UI_RENDERING_WINDOW, VisuUiRenderingWindowClass)) /** * VisuUiRenderingWindow: * * Short form for a #VisuUiRenderingWindow_struct structure. */ typedef struct _VisuUiRenderingWindow VisuUiRenderingWindow; /** * VisuUiRenderingWindowClass: * * Opaque structure. */ typedef struct _VisuUiRenderingWindowClass VisuUiRenderingWindowClass; /** * visu_ui_rendering_window_get_type * * #GType are unique numbers to identify objects. * * Returns: the #GType associated with #VisuUiRenderingWindow objects. */ GType visu_ui_rendering_window_get_type (void); GtkWidget* visu_ui_rendering_window_new(int width, int height, gboolean withFrame, gboolean withToolBar); GtkWidget* visu_ui_rendering_window_new_withGlScene(VisuGlNodeScene *scene, gboolean withToolBar); void visu_ui_rendering_window_pushMessage(VisuUiRenderingWindow *window, const gchar *message); void visu_ui_rendering_window_popMessage(VisuUiRenderingWindow *window); VisuGlNodeScene* visu_ui_rendering_window_getGlScene(VisuUiRenderingWindow *window); void visu_ui_rendering_window_loadFile(VisuUiRenderingWindow *window, VisuDataLoadable *data, guint iSet); void visu_ui_rendering_window_open(VisuUiRenderingWindow *window, GtkWindow *parent); void visu_ui_rendering_window_reload(VisuUiRenderingWindow *window); GtkAccelGroup* visu_ui_rendering_window_getAccelGroup(VisuUiRenderingWindow *window); void visu_ui_rendering_window_setCurrent(VisuUiRenderingWindow *window, gboolean force); void visu_ui_rendering_window_pushInteractive(VisuUiRenderingWindow *window, VisuInteractive *inter); void visu_ui_rendering_window_popInteractive(VisuUiRenderingWindow *window, VisuInteractive *inter); gboolean visu_ui_rendering_window_setDisplayCoordinatesInReduce(VisuUiRenderingWindow *window, gboolean status); gboolean visu_ui_rendering_window_getDisplayCoordinatesInReduce(const VisuUiRenderingWindow *window); void visu_ui_rendering_window_class_finalize(void); G_END_DECLS #endif v_sim-3.8.0/src/gtk_save.c000066400000000000000000000554331370110300500153750ustar00rootroot00000000000000/* EXTRAITS DE LA LICENCE Copyright CEA, contributeurs : Luc BILLARD et Damien CALISTE, laboratoire L_Sim, (2001-2005) Adresse mèl : BILLARD, non joignable par mèl ; CALISTE, damien P caliste AT cea P fr. Ce logiciel est un programme informatique servant à visualiser des structures atomiques dans un rendu pseudo-3D. Ce logiciel est régi par la licence CeCILL soumise au droit français et respectant les principes de diffusion des logiciels libres. Vous pouvez utiliser, modifier et/ou redistribuer ce programme sous les conditions de la licence CeCILL telle que diffusée par le CEA, le CNRS et l'INRIA sur le site "http://www.cecill.info". Le fait que vous puissiez accéder à cet en-tête signifie que vous avez pris connaissance de la licence CeCILL, et que vous en avez accepté les termes (cf. le fichier Documentation/licence.fr.txt fourni avec ce logiciel). */ /* LICENCE SUM UP Copyright CEA, contributors : Luc BILLARD et Damien CALISTE, laboratoire L_Sim, (2001-2005) E-mail address: BILLARD, not reachable any more ; CALISTE, damien P caliste AT cea P fr. This software is a computer program whose purpose is to visualize atomic configurations in 3D. This software is governed by the CeCILL license under French law and abiding by the rules of distribution of free software. You can use, modify and/ or redistribute the software under the terms of the CeCILL license as circulated by CEA, CNRS and INRIA at the following URL "http://www.cecill.info". The fact that you are presently reading this means that you have had knowledge of the CeCILL license and that you accept its terms. You can find a copy of this licence shipped with this software at Documentation/licence.en.txt. */ #ifdef HAVE_CONFIG_H #include #endif #include /* For the access markers R_OK, W_OK ... */ #include #include "gtk_save.h" #include "visu_gtk.h" #include "gtk_main.h" #include "visu_configFile.h" #include "visu_tools.h" #include "visu_basic.h" #include "gtk_renderingWindowWidget.h" #include "visu_commandLine.h" #include "extensions/planes.h" #include "panelModules/panelPlanes.h" #include "panelModules/panelSurfaces.h" #include "panelModules/panelGeometry.h" /** * SECTION: gtk_save * @short_description: The load/save dialog for resources and * parameters. * * The save dialog proposes to load or save resources, both * parameters or resources. */ static guint saveResourcesContextId, saveParametersContextId; static gchar *lastParsedDir; static GtkWidget *checkXMLResources, *checkXMLParameters, *checkXMLCommandLine; static GtkWidget *checkExportXML; /* Local Callbacks. */ static void onLoadResButtonClicked(GtkButton *button, gpointer data); static void onSaveResButtonClicked(GtkButton *button, gpointer data); static void onSelectionResourcesChange(GtkFileChooser *fileChooser, gpointer *data); static void onLoadResourcesSelected(GtkFileChooser *fileChooser, gpointer *data); static void onTextEntryChange(GtkEditable *entry, gpointer data); static void onSaveParButtonClicked(GtkButton *button, gpointer data); /* Local methods. */ static void showAlertMessage(GtkWidget *saveDialog, gchar* message, gboolean warning, VisuConfigFileKind type); static void saveAction(VisuConfigFileKind kind, GtkWidget *saveDialog, GtkEntry *entry); /* The completion tree model. */ enum { GTK_SAVE_FILE_NAME, GTK_SAVE_NB_COLUMNS }; /** * visu_ui_save_initBuild: (skip) * * Create the save window, conect the signals and run it as a modal dialog. */ void visu_ui_save_initBuild() { GtkWidget *saveDialog; GtkWidget *wd, *label; GtkEntryCompletion *completion; const gchar *directory; gchar *file, *dir; GList *resList; GtkListStore *listOfFiles; const gchar *currentResPath; int i, j; GDir *gdir; const gchar *fileFromDir; saveDialog = create_saveDialog(); gtk_widget_set_name(saveDialog, "message"); /* Set style. */ wd = lookup_widget(saveDialog, "labelSaveDialog"); gtk_widget_set_name(wd, "message_title"); wd = lookup_widget(saveDialog, "notebookSave"); gtk_widget_set_name(wd, "message_notebook"); wd = lookup_widget(saveDialog, "labelResources"); gtk_widget_set_name(wd, "label_head"); wd = lookup_widget(saveDialog, "labelParameters"); gtk_widget_set_name(wd, "label_head"); wd = lookup_widget(saveDialog, "imageWarningResources"); gtk_widget_hide(wd); wd = lookup_widget(saveDialog, "imageWarningParameters"); gtk_widget_hide(wd); wd = lookup_widget(saveDialog, "statusbarResources"); gtk_widget_set_name(wd, "message_statusbar"); wd = lookup_widget(saveDialog, "statusbarParameters"); gtk_widget_set_name(wd, "message_statusbar"); wd = lookup_widget(saveDialog, "labelHelp"); gtk_widget_set_name(wd, "label_info"); wd = lookup_widget(saveDialog, "labelHelpTips"); gtk_widget_set_name(wd, "label_info"); /* Set default values. */ wd = lookup_widget(saveDialog, "checkLimitOnVisuData"); g_object_bind_property(visu_ui_main_class_getDefaultRendering(), "data", wd, "sensitive", G_BINDING_SYNC_CREATE); gtk_widget_set_name(wd, "message_radio"); wd = lookup_widget(saveDialog, "notebookResources"); gtk_notebook_set_current_page(GTK_NOTEBOOK(wd), 1); gtk_widget_set_name(wd, "message_notebook"); /* Local variables. */ listOfFiles = gtk_list_store_new(GTK_SAVE_NB_COLUMNS, G_TYPE_STRING); gtk_tree_sortable_set_sort_column_id(GTK_TREE_SORTABLE(listOfFiles), GTK_SAVE_FILE_NAME, GTK_SORT_ASCENDING); lastParsedDir = (gchar*)0; /* Set initial values. */ wd = lookup_widget(saveDialog, "filechooserwidgetResources"); directory = visu_ui_main_getLastOpenDirectory(visu_ui_main_class_getCurrentPanel()); if (directory) gtk_file_chooser_set_current_folder(GTK_FILE_CHOOSER(wd), directory); g_signal_connect(G_OBJECT(wd), "selection-changed", G_CALLBACK(onSelectionResourcesChange), (gpointer)lookup_widget(saveDialog, "buttonLoadResources")); g_signal_connect(G_OBJECT(wd), "file-activated", G_CALLBACK(onLoadResourcesSelected), (gpointer)saveDialog); wd = lookup_widget(saveDialog, "statusbarResources"); saveResourcesContextId = gtk_statusbar_get_context_id(GTK_STATUSBAR(wd), "Resources"); wd = lookup_widget(saveDialog, "comboboxentryParameters"); gtk_widget_set_name(wd, "message_entry"); resList = visu_config_file_getPathList(VISU_CONFIG_FILE_PARAMETER); for (file = visu_config_file_getNextValidPath(VISU_CONFIG_FILE_PARAMETER, W_OK, &resList, 1); file; file = visu_config_file_getNextValidPath(VISU_CONFIG_FILE_PARAMETER, W_OK, &resList, 1)) gtk_combo_box_text_append(GTK_COMBO_BOX_TEXT(wd), (const gchar*)0, file); completion = gtk_entry_completion_new(); gtk_entry_completion_set_model(completion, GTK_TREE_MODEL(listOfFiles)); gtk_entry_completion_set_text_column(completion, GTK_SAVE_FILE_NAME); #if GTK_MAJOR_VERSION > 2 || GTK_MINOR_VERSION > 5 gtk_entry_completion_set_inline_completion(completion, TRUE); #endif gtk_entry_set_completion(GTK_ENTRY(gtk_bin_get_child(GTK_BIN(wd))), completion); g_signal_connect(G_OBJECT(gtk_bin_get_child(GTK_BIN(wd))), "changed", G_CALLBACK(onTextEntryChange), (gpointer)0); gtk_combo_box_set_active(GTK_COMBO_BOX(wd), 0); wd = lookup_widget(saveDialog, "comboboxentryResources"); gtk_widget_set_name(wd, "message_entry"); currentResPath = visu_config_file_getPath(VISU_CONFIG_FILE_RESOURCE); DBG_fprintf(stderr, " | current resource path '%s'.\n", currentResPath); j = i = 0; resList = visu_config_file_getPathList(VISU_CONFIG_FILE_RESOURCE); for (file = visu_config_file_getNextValidPath(VISU_CONFIG_FILE_RESOURCE, W_OK, &resList, 1); file; file = visu_config_file_getNextValidPath(VISU_CONFIG_FILE_RESOURCE, W_OK, &resList, 1)) { if (!strcmp(file, currentResPath)) j = i; DBG_fprintf(stderr, " | '%s' (%s).\n", file, currentResPath); gtk_combo_box_text_append(GTK_COMBO_BOX_TEXT(wd), (const gchar*)0, file); i += 1; } /* Add all res file of the cwd. */ DBG_fprintf(stderr, "Gtk Save: looking for res files in '%s'.\n", currentResPath); dir = g_get_current_dir(); gdir = g_dir_open(dir, 0, NULL); if (gdir) { fileFromDir = g_dir_read_name(gdir); while(fileFromDir) { if (g_strrstr(fileFromDir, ".res") && strcmp(fileFromDir, "v_sim.res") && !access(fileFromDir, W_OK)) { file = g_build_filename(directory, fileFromDir, NULL); DBG_fprintf(stderr, " | '%s'.\n", file); gtk_combo_box_text_append(GTK_COMBO_BOX_TEXT(wd), (const gchar*)0, file); g_free(file); } fileFromDir = g_dir_read_name(gdir); } g_dir_close(gdir); } g_free(dir); completion = gtk_entry_completion_new(); gtk_entry_completion_set_model(completion, GTK_TREE_MODEL(listOfFiles)); gtk_entry_completion_set_text_column(completion, GTK_SAVE_FILE_NAME); #if GTK_MAJOR_VERSION > 2 || GTK_MINOR_VERSION > 5 gtk_entry_completion_set_inline_completion(completion, TRUE); #endif gtk_entry_set_completion(GTK_ENTRY(gtk_bin_get_child(GTK_BIN(wd))), completion); g_signal_connect(G_OBJECT(gtk_bin_get_child(GTK_BIN(wd))), "changed", G_CALLBACK(onTextEntryChange), (gpointer)0); gtk_combo_box_set_active(GTK_COMBO_BOX(wd), j); wd = lookup_widget(saveDialog, "labelTipsResources"); gtk_label_set_line_wrap(GTK_LABEL(wd), FALSE); gtk_label_set_markup(GTK_LABEL(wd), _("A description of all resource markups is" " available on:" "\n " VISU_WEB_SITE"/sample.html#resources" ".")); /* Set callbacks. */ wd = lookup_widget(saveDialog, "buttonLoadResources"); g_signal_connect(G_OBJECT(wd), "clicked", G_CALLBACK(onLoadResButtonClicked), (gpointer)saveDialog); wd = lookup_widget(saveDialog, "buttonSaveResources"); g_signal_connect(G_OBJECT(wd), "clicked", G_CALLBACK(onSaveResButtonClicked), (gpointer)saveDialog); wd = lookup_widget(saveDialog, "buttonSaveParameters"); g_signal_connect(G_OBJECT(wd), "clicked", G_CALLBACK(onSaveParButtonClicked), (gpointer)saveDialog); #if DEBUG == 1 wd = lookup_widget(saveDialog, "vbox16"); checkXMLResources = gtk_check_button_new_with_mnemonic(_("Export all resource descriptions" " to an _XML file")); gtk_box_pack_start(GTK_BOX(wd), checkXMLResources, FALSE, FALSE, 0); gtk_container_set_border_width(GTK_CONTAINER(checkXMLResources), 5); gtk_widget_set_name(checkXMLResources, "message_radio"); gtk_widget_show(checkXMLResources); wd = lookup_widget(saveDialog, "vbox18"); checkXMLParameters = gtk_check_button_new_with_mnemonic(_("Export all parameter descriptions" " to an _XML file")); gtk_box_pack_start(GTK_BOX(wd), checkXMLParameters, FALSE, FALSE, 0); gtk_container_set_border_width(GTK_CONTAINER(checkXMLParameters), 5); gtk_widget_set_name(checkXMLParameters, "message_radio"); gtk_widget_show(checkXMLParameters); checkXMLCommandLine = gtk_check_button_new_with_mnemonic(_("Export all command line _options" " to an XML file")); gtk_box_pack_start(GTK_BOX(wd), checkXMLCommandLine, FALSE, FALSE, 0); gtk_container_set_border_width(GTK_CONTAINER(checkXMLCommandLine), 5); gtk_widget_set_name(checkXMLCommandLine, "message_radio"); gtk_widget_show(checkXMLCommandLine); #else checkXMLResources = (GtkWidget*)0; checkXMLParameters = (GtkWidget*)0; checkXMLCommandLine = (GtkWidget*)0; #endif wd = lookup_widget(saveDialog, "vbox16"); checkExportXML = gtk_check_button_new_with_mnemonic(_("Append all settings in a single XML file (including planes, surfaces…)")); gtk_box_pack_start(GTK_BOX(wd), checkExportXML, FALSE, FALSE, 0); gtk_container_set_border_width(GTK_CONTAINER(checkExportXML), 5); gtk_widget_set_name(checkExportXML, "message_radio"); gtk_widget_show(checkExportXML); wd = lookup_widget(saveDialog, "vbox18"); label = gtk_label_new(""); gtk_label_set_line_wrap(GTK_LABEL(label), FALSE); gtk_label_set_markup(GTK_LABEL(label), _("A description of all parameter markups is" " available on:\n" " " VISU_WEB_SITE"/sample.html#parameters" ".")); gtk_label_set_xalign(GTK_LABEL(label), 0.); gtk_box_pack_end(GTK_BOX(wd), label, FALSE, FALSE, 10); gtk_widget_show(label); /* Run the dialog. */ gtk_dialog_run(GTK_DIALOG(saveDialog)); g_object_unref(listOfFiles); if (lastParsedDir) g_free(lastParsedDir); gtk_widget_destroy(saveDialog); } static void onLoadResourcesSelected(GtkFileChooser *fileChooser _U_, gpointer *data) { onLoadResButtonClicked((GtkButton*)0, data); } static void onSelectionResourcesChange(GtkFileChooser *fileChooser, gpointer *data) { gchar *filename; g_return_if_fail(GTK_BUTTON(data)); filename = gtk_file_chooser_get_filename(fileChooser); if (!filename) { gtk_widget_set_sensitive(GTK_WIDGET(data), FALSE); return; } DBG_fprintf(stderr, "Gtk Save : selected a new potential" " resources file : '%s'.\n", filename); gtk_widget_set_sensitive(GTK_WIDGET(data), !g_file_test(filename, G_FILE_TEST_IS_DIR)); g_free(filename); } static void onLoadResButtonClicked(GtkButton *button _U_, gpointer data) { GtkWidget *file_selector; gchar *filename, *basename; gchar *directory; int res; GString *message; GError *error; g_return_if_fail(GTK_DIALOG(data)); file_selector = lookup_widget(GTK_WIDGET(data), "filechooserwidgetResources"); g_return_if_fail(file_selector); filename = gtk_file_chooser_get_filename(GTK_FILE_CHOOSER(file_selector)); directory = gtk_file_chooser_get_current_folder(GTK_FILE_CHOOSER(file_selector)); visu_ui_main_setLastOpenDirectory(visu_ui_main_class_getCurrentPanel(), directory, VISU_UI_DIR_CONF); g_free(directory); error = (GError*)0; res = visu_config_file_load(VISU_CONFIG_FILE_RESOURCE, filename, &error); if (error) { visu_ui_raiseWarningLong(_("Loading a file"), error->message, GTK_WINDOW(data)); g_error_free(error); } basename = g_path_get_basename(filename); g_free (filename); message = g_string_new(""); if (res) g_string_append_printf(message, _("File '%s' succesfully loaded."), basename); else g_string_append_printf(message, _("File '%s' not or partially loaded."), basename); showAlertMessage(GTK_WIDGET(data), message->str, !res, VISU_CONFIG_FILE_KIND_RESOURCE); g_string_free(message, TRUE); g_free(basename); } static void onSaveResButtonClicked(GtkButton *button _U_, gpointer data) { GtkWidget *entry; g_return_if_fail(GTK_IS_DIALOG(data)); entry = gtk_bin_get_child (GTK_BIN(lookup_widget(GTK_WIDGET(data), "comboboxentryResources"))); if (!strstr(gtk_entry_get_text(GTK_ENTRY(entry)), ".xml") && gtk_toggle_button_get_active(GTK_TOGGLE_BUTTON(checkExportXML))) { showAlertMessage(GTK_WIDGET(data), _("Choose a filename with '.xml' to append other settings."), TRUE, VISU_CONFIG_FILE_KIND_RESOURCE); } else { saveAction(VISU_CONFIG_FILE_KIND_RESOURCE, GTK_WIDGET(data), GTK_ENTRY(entry)); gtk_widget_grab_default(lookup_widget(GTK_WIDGET(data), "closeButtonSave")); } } static void onSaveParButtonClicked(GtkButton *button _U_, gpointer data) { GtkWidget *entry; g_return_if_fail(GTK_IS_DIALOG(data)); entry = gtk_bin_get_child (GTK_BIN(lookup_widget(GTK_WIDGET(data), "comboboxentryParameters"))); saveAction(VISU_CONFIG_FILE_KIND_PARAMETER, GTK_WIDGET(data), GTK_ENTRY(entry)); gtk_widget_grab_default(lookup_widget(GTK_WIDGET(data), "closeButtonSave")); } static gboolean _appendAllSettings(const gchar *filename, GError **error) { VisuGlNodeScene *scene; VisuGlExtPlanes *planes; scene = visu_ui_rendering_window_getGlScene(visu_ui_main_class_getDefaultRendering()); planes = visu_gl_node_scene_addPlanes(scene); if (!visu_plane_set_exportXMLFile(planes->planes, filename, error)) return FALSE; if (!visu_gl_node_scene_marksToFile(scene, filename, error)) return FALSE; if (!visu_ui_panel_surfaces_exportXMLFile(filename, error)) return FALSE; if (!visu_gl_node_scene_exportPathsToXML(scene, filename, error)) return FALSE; return TRUE; } static void saveAction(VisuConfigFileKind kind, GtkWidget *saveDialog, GtkEntry *entry) { GtkWidget *wd; gchar *file, *tmpFile, *basename, *fileUTF8; GString *message; gboolean resOk; gsize ecrit, lu; int lines; VisuUiRenderingWindow *window; VisuData *dataObj; GError *error; GtkTreeIter iter; GtkListStore *listOfFiles; GtkEntryCompletion *completion; g_return_if_fail(saveDialog && entry); file = g_filename_from_utf8(gtk_entry_get_text(entry), -1, &lu, &ecrit, NULL); if (g_file_test(file, G_FILE_TEST_IS_DIR)) { tmpFile= g_build_filename(file, visu_config_file_getDefaultFilename(kind), NULL); g_free(file); file = tmpFile; } wd = lookup_widget(saveDialog, "checkLimitOnVisuData"); dataObj = (VisuData*)0; if (kind == VISU_CONFIG_FILE_KIND_RESOURCE) { window = visu_ui_main_class_getDefaultRendering(); if (gtk_toggle_button_get_active(GTK_TOGGLE_BUTTON(wd))) dataObj = visu_gl_node_scene_getData(visu_ui_rendering_window_getGlScene(window)); } error = (GError*)0; lines = 0; if (kind == VISU_CONFIG_FILE_KIND_RESOURCE && checkXMLResources && gtk_toggle_button_get_active(GTK_TOGGLE_BUTTON(checkXMLResources))) resOk = visu_config_file_exportToXML(VISU_CONFIG_FILE_RESOURCE, file, &error); else if (kind == VISU_CONFIG_FILE_KIND_RESOURCE && strstr(file, ".xml")) { resOk = visu_config_file_saveResourcesToXML(file, &lines, dataObj, &error); resOk = resOk && _appendAllSettings(file, &error); } else if (kind == VISU_CONFIG_FILE_KIND_PARAMETER && checkXMLParameters && gtk_toggle_button_get_active(GTK_TOGGLE_BUTTON(checkXMLParameters))) resOk = visu_config_file_exportToXML(VISU_CONFIG_FILE_PARAMETER, file, &error); else if (kind == VISU_CONFIG_FILE_KIND_PARAMETER && checkXMLCommandLine && gtk_toggle_button_get_active(GTK_TOGGLE_BUTTON(checkXMLCommandLine))) resOk = commandLineExport(file, &error); else if (kind == VISU_CONFIG_FILE_KIND_PARAMETER) resOk = visu_config_file_save(VISU_CONFIG_FILE_PARAMETER, file, &lines, dataObj, &error); else resOk = visu_config_file_save(VISU_CONFIG_FILE_RESOURCE, file, &lines, dataObj, &error); if (!resOk && error) { visu_ui_raiseWarningLong(_("Saving a file"), error->message, GTK_WINDOW(saveDialog)); g_error_free(error); } basename = g_path_get_basename(file); message = g_string_new(""); if (resOk) g_string_append_printf(message, _("File '%s' succesfully written (%d lines)."), basename, lines); else g_string_append_printf(message, _("File '%s' not written."), basename); showAlertMessage(saveDialog, message->str, !resOk, kind); g_string_free(message, TRUE); g_free(basename); /* If file is written, we add it to the completion list. */ if (resOk) { completion = gtk_entry_get_completion(GTK_ENTRY(entry)); g_return_if_fail(completion); listOfFiles = GTK_LIST_STORE(gtk_entry_completion_get_model(completion)); g_return_if_fail(listOfFiles); fileUTF8 = g_filename_from_utf8(file, -1, NULL, NULL, NULL); if(fileUTF8) { gtk_list_store_append(listOfFiles, &iter); gtk_list_store_set(listOfFiles, &iter, GTK_SAVE_FILE_NAME, fileUTF8, -1); g_free(fileUTF8); } } g_free(file); } static void showAlertMessage(GtkWidget *saveDialog, gchar* message, gboolean warning, VisuConfigFileKind type) { GtkWidget *wd; g_return_if_fail(saveDialog); if (type == VISU_CONFIG_FILE_KIND_RESOURCE) wd = lookup_widget(saveDialog, "imageWarningResources"); else wd = lookup_widget(saveDialog, "imageWarningParameters"); if (warning) gtk_widget_show(wd); else gtk_widget_hide(wd); if (type == VISU_CONFIG_FILE_KIND_RESOURCE) { wd = lookup_widget(saveDialog, "statusbarResources"); gtk_statusbar_pop(GTK_STATUSBAR(wd), saveResourcesContextId); gtk_statusbar_push(GTK_STATUSBAR(wd), saveResourcesContextId, message); } else { wd = lookup_widget(saveDialog, "statusbarParameters"); gtk_statusbar_pop(GTK_STATUSBAR(wd), saveParametersContextId); gtk_statusbar_push(GTK_STATUSBAR(wd), saveParametersContextId, message); } } static void onTextEntryChange(GtkEditable *entry, gpointer data _U_) { gboolean reParse; GtkTreeIter iter; GtkListStore *listOfFiles; GtkEntryCompletion *completion; gchar *dirEntry, *dirBrowsed; GDir *gdir; const gchar *fileFromDir, *fileEntry; gsize ecrit, lu; gchar *fileUTF8, *saveFile, *saveFileUTF8; fileEntry = gtk_entry_get_text(GTK_ENTRY(entry)); if (!fileEntry || !fileEntry[0]) return; DBG_fprintf(stderr, "Gtk Save : browse directory to populate the completion.\n"); completion = gtk_entry_get_completion(GTK_ENTRY(entry)); g_return_if_fail(completion); listOfFiles = GTK_LIST_STORE(gtk_entry_completion_get_model(completion)); g_return_if_fail(listOfFiles); reParse = FALSE; if (!lastParsedDir) reParse = TRUE; else { dirEntry = g_path_get_dirname(fileEntry); DBG_fprintf(stderr, "Gtk Save : current and last directories...\n %s\n %s\n", dirEntry, lastParsedDir); if (strcmp(dirEntry, lastParsedDir)) reParse = TRUE; g_free(dirEntry); } DBG_fprintf(stderr, "Gtk Save : reparse is needed : %d.\n", reParse); if (!reParse) { gtk_entry_completion_complete(completion); return; } gtk_list_store_clear(listOfFiles); dirEntry = g_path_get_dirname(fileEntry); g_free(lastParsedDir); lastParsedDir = dirEntry; dirBrowsed = g_filename_from_utf8(dirEntry, -1, &lu, &ecrit, NULL); gdir = g_dir_open(dirBrowsed, 0, NULL); if (!gdir) { g_free(dirBrowsed); return; } fileFromDir = g_dir_read_name(gdir); while (fileFromDir) { /* DBG_fprintf(stderr, "Gtk Save : adding '%s' to completion list.\n", fileFromDir); */ fileUTF8 = g_filename_from_utf8(fileFromDir, -1, NULL, NULL, NULL); if(fileUTF8) { saveFile = g_build_filename(dirBrowsed, fileFromDir, NULL); if (g_file_test(saveFile, G_FILE_TEST_IS_DIR)) saveFileUTF8 = g_build_filename(dirEntry, fileUTF8, "/", NULL); else saveFileUTF8 = g_build_filename(dirEntry, fileUTF8, NULL); gtk_list_store_append(listOfFiles, &iter); gtk_list_store_set(listOfFiles, &iter, GTK_SAVE_FILE_NAME, saveFileUTF8, -1); g_free(fileUTF8); g_free(saveFile); } fileFromDir = g_dir_read_name(gdir); } g_free(dirBrowsed); DBG_fprintf(stderr, "Gtk Save : summiting new list of completion.\n"); gtk_entry_completion_complete(completion); DBG_fprintf(stderr, "Gtk Save : summition OK.\n"); } v_sim-3.8.0/src/gtk_save.h000066400000000000000000000035531370110300500153760ustar00rootroot00000000000000/* EXTRAITS DE LA LICENCE Copyright CEA, contributeurs : Luc BILLARD et Damien CALISTE, laboratoire L_Sim, (2001-2005) Adresse mèl : BILLARD, non joignable par mèl ; CALISTE, damien P caliste AT cea P fr. Ce logiciel est un programme informatique servant à visualiser des structures atomiques dans un rendu pseudo-3D. Ce logiciel est régi par la licence CeCILL soumise au droit français et respectant les principes de diffusion des logiciels libres. Vous pouvez utiliser, modifier et/ou redistribuer ce programme sous les conditions de la licence CeCILL telle que diffusée par le CEA, le CNRS et l'INRIA sur le site "http://www.cecill.info". Le fait que vous puissiez accéder à cet en-tête signifie que vous avez pris connaissance de la licence CeCILL, et que vous en avez accepté les termes (cf. le fichier Documentation/licence.fr.txt fourni avec ce logiciel). */ /* LICENCE SUM UP Copyright CEA, contributors : Luc BILLARD et Damien CALISTE, laboratoire L_Sim, (2001-2005) E-mail address: BILLARD, not reachable any more ; CALISTE, damien P caliste AT cea P fr. This software is a computer program whose purpose is to visualize atomic configurations in 3D. This software is governed by the CeCILL license under French law and abiding by the rules of distribution of free software. You can use, modify and/ or redistribute the software under the terms of the CeCILL license as circulated by CEA, CNRS and INRIA at the following URL "http://www.cecill.info". The fact that you are presently reading this means that you have had knowledge of the CeCILL license and that you accept its terms. You can find a copy of this licence shipped with this software at Documentation/licence.en.txt. */ #ifndef GTK_SAVE_H #define GTK_SAVE_H #include #include "interface.h" #include "support.h" void visu_ui_save_initBuild(); #endif v_sim-3.8.0/src/iface_animatable.c000066400000000000000000000242161370110300500170110ustar00rootroot00000000000000/* EXTRAITS DE LA LICENCE Copyright CEA, contributeurs : Damien CALISTE, laboratoire L_Sim, (2017) Adresse mèl : CALISTE, damien P caliste AT cea P fr. Ce logiciel est un programme informatique servant à visualiser des structures atomiques dans un rendu pseudo-3D. Ce logiciel est régi par la licence CeCILL soumise au droit français et respectant les principes de diffusion des logiciels libres. Vous pouvez utiliser, modifier et/ou redistribuer ce programme sous les conditions de la licence CeCILL telle que diffusée par le CEA, le CNRS et l'INRIA sur le site "http://www.cecill.info". Le fait que vous puissiez accéder à cet en-tête signifie que vous avez pris connaissance de la licence CeCILL, et que vous en avez accepté les termes (cf. le fichier Documentation/licence.fr.txt fourni avec ce logiciel). */ /* LICENCE SUM UP Copyright CEA, contributors : Damien CALISTE, laboratoire L_Sim, (2017) E-mail address: BILLARD, not reachable any more ; CALISTE, damien P caliste AT cea P fr. This software is a computer program whose purpose is to visualize atomic configurations in 3D. This software is governed by the CeCILL license under French law and abiding by the rules of distribution of free software. You can use, modify and/ or redistribute the software under the terms of the CeCILL license as circulated by CEA, CNRS and INRIA at the following URL "http://www.cecill.info". The fact that you are presently reading this means that you have had knowledge of the CeCILL license and that you accept its terms. You can find a copy of this licence shipped with this software at Documentation/licence.en.txt. */ #include "iface_animatable.h" #include "config.h" /** * SECTION:iface_animatable * @short_description: an interface defining object with animatable properties. * * An object with properties that can be animated whould * implement this interface. */ /* enum { */ /* PROP_0, */ /* N_PROPS */ /* }; */ /* static GParamSpec *properties[N_PROPS]; */ enum { ANIMATE_SIGNAL, NB_SIGNAL }; static guint _signals[NB_SIGNAL] = { 0 }; /* NodeMasker interface. */ G_DEFINE_INTERFACE(VisuAnimatable, visu_animatable, G_TYPE_OBJECT) static void g_cclosure_marshal_ANIM_PARAM(GClosure *closure, GValue *return_value, guint n_param_values, const GValue *param_values, gpointer invocation_hint _U_, gpointer marshal_data) { typedef gboolean (*callbackFunc)(gpointer data1, VisuAnimation *anim, const GValue *to, gulong duration, gboolean loop, VisuAnimationType type, gpointer data2); register callbackFunc callback; register GCClosure *cc = (GCClosure*)closure; register gpointer data1, data2; g_return_if_fail(n_param_values == 6); if (G_CCLOSURE_SWAP_DATA(closure)) { data1 = closure->data; data2 = g_value_peek_pointer(param_values + 0); } else { data1 = g_value_peek_pointer(param_values + 0); data2 = closure->data; } callback = (callbackFunc)(size_t)(marshal_data ? marshal_data : cc->callback); DBG_fprintf(stderr, "Visu Animatable: marshall callback for animation %p.\n", (gpointer)g_value_get_object(param_values + 1)); g_value_set_boolean(return_value, callback(data1, g_value_get_object(param_values + 1), g_value_get_boxed(param_values + 2), g_value_get_ulong(param_values + 3), g_value_get_boolean(param_values + 4), g_value_get_uint(param_values + 5), data2)); } static void visu_animatable_default_init(VisuAnimatableInterface *iface) { /** * VisuAnimatable::animate: * @self: the object emitting the signal. * @animation: the object emitting the signal. * @value: the target value. * @at: the current tick time. * @loop: if animation should loop. * @type: the animation type. * * This signal is emitted when properties start an animation. * * Since: 3.8 * * Returns: TRUE if animation is successfully started. */ _signals[ANIMATE_SIGNAL] = g_signal_new("animate", G_TYPE_FROM_INTERFACE(iface), G_SIGNAL_RUN_LAST | G_SIGNAL_NO_RECURSE | G_SIGNAL_NO_HOOKS, 0, NULL, NULL, g_cclosure_marshal_ANIM_PARAM, G_TYPE_BOOLEAN, 5, VISU_TYPE_ANIMATION, G_TYPE_VALUE, G_TYPE_ULONG, G_TYPE_BOOLEAN, G_TYPE_UINT); } /** * visu_animatable_getAnimation: * @animatable: a #VisuAnimatable object. * @prop: a property name. * * A method to retrieve the #VisuAnimation from @animatable given the * property name @prop. * * Since: 3.8 * * Returns: (transfer none): a #VisuAnimation object or %NULL if none * is associated to @prop. **/ VisuAnimation* visu_animatable_getAnimation(const VisuAnimatable *animatable, const gchar *prop) { g_return_val_if_fail(VISU_IS_ANIMATABLE(animatable), (VisuAnimation*)0); g_return_val_if_fail(VISU_ANIMATABLE_GET_INTERFACE(animatable)->get_animation, (VisuAnimation*)0); return VISU_ANIMATABLE_GET_INTERFACE(animatable)->get_animation(animatable, prop); } /** * visu_animatable_animate: * @animatable: a #VisuAnimatable object. * @anim: a #VisuAnimation object. * @to: a destination value. * @duration: a duration in milliseconds. * @loop: a boolean. * @type: a type. * * Animates @anim from its current value to @to. The animation is * scheduled to last @duration and will follow the evolution described * by @type. If @loop is true, when the value of @anim reaches @to, it * goes back to its current value and animates again to reach @to. In * that case, use visu_animation_abort() on @anim to stop it. * * Since: 3.8 * * Returns: TRUE if animation is started. **/ gboolean visu_animatable_animate(VisuAnimatable *animatable, VisuAnimation *anim, const GValue *to, gulong duration, gboolean loop, VisuAnimationType type) { gboolean success; success = FALSE; g_signal_emit(animatable, _signals[ANIMATE_SIGNAL], 0, anim, to, duration * 1000, loop, type, &success); return success; } /** * visu_animatable_animateFloat: * @animatable: a #VisuAnimatable object. * @anim: a #VisuAnimation object. * @to: a destination value. * @duration: a duration in milliseconds. * @loop: a boolean. * @type: a type. * * Like visu_animatable_animate() for a float destination value. * * Since: 3.8 * * Returns: TRUE if animation is started. **/ gboolean visu_animatable_animateFloat(VisuAnimatable *animatable, VisuAnimation *anim, float to, gulong duration, gboolean loop, VisuAnimationType type) { GValue val = G_VALUE_INIT; gboolean success; DBG_fprintf(stderr, "Visu Animatable: emitting animate signal for %p.\n", (gpointer)animatable); g_value_init(&val, G_TYPE_FLOAT); g_value_set_float(&val, to); success = FALSE; g_signal_emit(animatable, _signals[ANIMATE_SIGNAL], 0, anim, &val, duration * 1000, loop, type, &success); return success; } /** * visu_animatable_animateFloatByName: * @animatable: a #VisuAnimatable object. * @prop: a property name from @animatable. * @to: a destination value. * @duration: a duration in milliseconds. * @loop: a boolean. * @type: a type. * * Like visu_animatable_animate() for a float destination value. * * Since: 3.8 * * Returns: TRUE if animation is started. **/ gboolean visu_animatable_animateFloatByName(VisuAnimatable *animatable, const gchar *prop, float to, gulong duration, gboolean loop, VisuAnimationType type) { VisuAnimation *anim; g_return_val_if_fail(VISU_IS_ANIMATABLE(animatable), FALSE); g_return_val_if_fail(VISU_ANIMATABLE_GET_INTERFACE(animatable)->get_animation, FALSE); anim = VISU_ANIMATABLE_GET_INTERFACE(animatable)->get_animation(animatable, prop); g_return_val_if_fail(anim, FALSE); return visu_animatable_animateFloat(animatable, anim, to, duration, loop, type); } /** * visu_animatable_animateDouble: * @animatable: a #VisuAnimatable object. * @anim: a #VisuAnimation object. * @to: a destination value. * @duration: a duration in milliseconds. * @loop: a boolean. * @type: a type. * * Like visu_animatable_animate() for a double destination value. * * Since: 3.8 * * Returns: TRUE if animation is started. **/ gboolean visu_animatable_animateDouble(VisuAnimatable *animatable, VisuAnimation *anim, double to, gulong duration, gboolean loop, VisuAnimationType type) { GValue val = G_VALUE_INIT; gboolean success; DBG_fprintf(stderr, "Visu Animatable: emitting animate signal for %p.\n", (gpointer)animatable); g_value_init(&val, G_TYPE_DOUBLE); g_value_set_double(&val, to); success = FALSE; g_signal_emit(animatable, _signals[ANIMATE_SIGNAL], 0, anim, &val, duration * 1000, loop, type, &success); return success; } /** * visu_animatable_animateDoubleByName: * @animatable: a #VisuAnimatable object. * @prop: a property name from @animatable. * @to: a destination value. * @duration: a duration in milliseconds. * @loop: a boolean. * @type: a type. * * Like visu_animatable_animate() for a double destination value. * * Since: 3.8 * * Returns: TRUE if animation is started. **/ gboolean visu_animatable_animateDoubleByName(VisuAnimatable *animatable, const gchar *prop, double to, gulong duration, gboolean loop, VisuAnimationType type) { VisuAnimation *anim; g_return_val_if_fail(VISU_IS_ANIMATABLE(animatable), FALSE); g_return_val_if_fail(VISU_ANIMATABLE_GET_INTERFACE(animatable)->get_animation, FALSE); anim = VISU_ANIMATABLE_GET_INTERFACE(animatable)->get_animation(animatable, prop); g_return_val_if_fail(anim, FALSE); return visu_animatable_animateDouble(animatable, anim, to, duration, loop, type); } v_sim-3.8.0/src/iface_animatable.h000066400000000000000000000077461370110300500170270ustar00rootroot00000000000000/* EXTRAITS DE LA LICENCE Copyright CEA, contributeurs : Damien CALISTE, laboratoire L_Sim, (2017) Adresse mèl : CALISTE, damien P caliste AT cea P fr. Ce logiciel est un programme informatique servant à visualiser des structures atomiques dans un rendu pseudo-3D. Ce logiciel est régi par la licence CeCILL soumise au droit français et respectant les principes de diffusion des logiciels libres. Vous pouvez utiliser, modifier et/ou redistribuer ce programme sous les conditions de la licence CeCILL telle que diffusée par le CEA, le CNRS et l'INRIA sur le site "http://www.cecill.info". Le fait que vous puissiez accéder à cet en-tête signifie que vous avez pris connaissance de la licence CeCILL, et que vous en avez accepté les termes (cf. le fichier Documentation/licence.fr.txt fourni avec ce logiciel). */ /* LICENCE SUM UP Copyright CEA, contributors : Damien CALISTE, laboratoire L_Sim, (2017) E-mail address: BILLARD, not reachable any more ; CALISTE, damien P caliste AT cea P fr. This software is a computer program whose purpose is to visualize atomic configurations in 3D. This software is governed by the CeCILL license under French law and abiding by the rules of distribution of free software. You can use, modify and/ or redistribute the software under the terms of the CeCILL license as circulated by CEA, CNRS and INRIA at the following URL "http://www.cecill.info". The fact that you are presently reading this means that you have had knowledge of the CeCILL license and that you accept its terms. You can find a copy of this licence shipped with this software at Documentation/licence.en.txt. */ #ifndef IFACE_ANIMATABLE_H #define IFACE_ANIMATABLE_H #include #include #include "visu_animation.h" G_BEGIN_DECLS /* Animatable interface. */ #define VISU_TYPE_ANIMATABLE (visu_animatable_get_type ()) #define VISU_ANIMATABLE(obj) (G_TYPE_CHECK_INSTANCE_CAST ((obj), VISU_TYPE_ANIMATABLE, VisuAnimatable)) #define VISU_IS_ANIMATABLE(obj) (G_TYPE_CHECK_INSTANCE_TYPE ((obj), VISU_TYPE_ANIMATABLE)) #define VISU_ANIMATABLE_GET_INTERFACE(inst) (G_TYPE_INSTANCE_GET_INTERFACE ((inst), VISU_TYPE_ANIMATABLE, VisuAnimatableInterface)) typedef struct _VisuAnimatableInterface VisuAnimatableInterface; typedef struct _VisuAnimatable VisuAnimatable; /* dummy object */ /** * VisuAnimatable: * * Interface object. * * Since: 3.8 */ /** * VisuAnimatableInterface: * @parent: its parent. * @get_animation: a method retrieve the #VisuAnimation object of the * given property. * * The different routines common to objects implementing a #VisuAnimatable interface. * * Since: 3.8 */ struct _VisuAnimatableInterface { GTypeInterface parent; VisuAnimation* (*get_animation)(const VisuAnimatable *self, const gchar *prop); }; GType visu_animatable_get_type(void); VisuAnimation* visu_animatable_getAnimation(const VisuAnimatable *animatable, const gchar *prop); gboolean visu_animatable_animate(VisuAnimatable *animatable, VisuAnimation *anim, const GValue *to, gulong duration, gboolean loop, VisuAnimationType type); gboolean visu_animatable_animateFloat(VisuAnimatable *animatable, VisuAnimation *anim, float to, gulong duration, gboolean loop, VisuAnimationType type); gboolean visu_animatable_animateFloatByName(VisuAnimatable *animatable, const gchar *prop, float to, gulong duration, gboolean loop, VisuAnimationType type); gboolean visu_animatable_animateDouble(VisuAnimatable *animatable, VisuAnimation *anim, double to, gulong duration, gboolean loop, VisuAnimationType type); gboolean visu_animatable_animateDoubleByName(VisuAnimatable *animatable, const gchar *prop, double to, gulong duration, gboolean loop, VisuAnimationType type); G_END_DECLS #endif v_sim-3.8.0/src/iface_boxed.c000066400000000000000000000116211370110300500160110ustar00rootroot00000000000000/* EXTRAITS DE LA LICENCE Copyright CEA, contributeurs : Luc BILLARD et Damien CALISTE, laboratoire L_Sim, (2001-2005) Adresse mèl : BILLARD, non joignable par mèl ; CALISTE, damien P caliste AT cea P fr. Ce logiciel est un programme informatique servant à visualiser des structures atomiques dans un rendu pseudo-3D. Ce logiciel est régi par la licence CeCILL soumise au droit français et respectant les principes de diffusion des logiciels libres. Vous pouvez utiliser, modifier et/ou redistribuer ce programme sous les conditions de la licence CeCILL telle que diffusée par le CEA, le CNRS et l'INRIA sur le site "http://www.cecill.info". Le fait que vous puissiez accéder à cet en-tête signifie que vous avez pris connaissance de la licence CeCILL, et que vous en avez accepté les termes (cf. le fichier Documentation/licence.fr.txt fourni avec ce logiciel). */ /* LICENCE SUM UP Copyright CEA, contributors : Luc BILLARD et Damien CALISTE, laboratoire L_Sim, (2001-2005) E-mail address: BILLARD, not reachable any more ; CALISTE, damien P caliste AT cea P fr. This software is a computer program whose purpose is to visualize atomic configurations in 3D. This software is governed by the CeCILL license under French law and abiding by the rules of distribution of free software. You can use, modify and/ or redistribute the software under the terms of the CeCILL license as circulated by CEA, CNRS and INRIA at the following URL "http://www.cecill.info". The fact that you are presently reading this means that you have had knowledge of the CeCILL license and that you accept its terms. You can find a copy of this licence shipped with this software at Documentation/licence.en.txt. */ #include "iface_boxed.h" #include "config.h" /** * SECTION:iface_boxed * @short_description: Defines a common interface for objects with a #VisuBox. * @See_also: #VisuBox, #VisuData, #VisuPlane, #VisuSurface, #VisuScalarField * and #VisuGlView * @Title: VisuBoxed * * */ enum { SET_BOX_SIGNAL, NB_SIGNAL }; /* Internal variables. */ static guint _signals[NB_SIGNAL] = { 0 }; enum { PROP_0, PROP_ADJUST, PROP_BOX, N_PROPS }; static GParamSpec *_properties[N_PROPS]; /* Boxed interface. */ G_DEFINE_INTERFACE(VisuBoxed, visu_boxed, G_TYPE_OBJECT) static void visu_boxed_default_init(VisuBoxedInterface *iface) { /** * VisuBoxed::setBox: * @boxed: the object which received the signal. * @box: the new box. * * Gets emitted when the bounding box is changed. * * Since: 3.7 */ _signals[SET_BOX_SIGNAL] = g_signal_new("setBox", G_TYPE_FROM_INTERFACE (iface), G_SIGNAL_RUN_LAST | G_SIGNAL_NO_RECURSE | G_SIGNAL_NO_HOOKS, 0, NULL, NULL, g_cclosure_marshal_VOID__OBJECT, G_TYPE_NONE, 1, VISU_TYPE_BOX); /** * VisuBoxed::auto-adjust: * * Wether to adjust or not the contain of the #VisuBoxed object when * a new box is set. * * Since: 3.8 */ _properties[PROP_ADJUST] = g_param_spec_boolean("auto-adjust", "Automatically adjust", "Adjust internals when box is set", FALSE, G_PARAM_READWRITE); g_object_interface_install_property(iface, _properties[PROP_ADJUST]); /** * VisuBoxed::box: * * The box used by the boxed object. * * Since: 3.8 */ _properties[PROP_BOX] = g_param_spec_object("box", "Box", "Box", VISU_TYPE_BOX, G_PARAM_READWRITE); g_object_interface_install_property(iface, _properties[PROP_BOX]); } /** * visu_boxed_getBox: * @self: a #VisuBoxed object. * * Retrieves the #VisuBox of @self. * * Since: 3.7 * * Returns: (transfer none): the #VisuBox of @self. **/ VisuBox* visu_boxed_getBox(VisuBoxed *self) { g_return_val_if_fail(VISU_IS_BOXED(self), (VisuBox*)0); return VISU_BOXED_GET_INTERFACE(self)->get_box(self); } /** * visu_boxed_setBox: * @self: a #VisuBoxed object. * @box: (transfer none): a #VisuBoxed object. * * Attach the #VisuBox of @box to @boxed. If @update is %TRUE, coordinates inside * @boxed are updated to fit into the new #VisuBox. A reference is * taken on the #VisuBox of @box. This routine emits #VisuBoxed::setBox * signal if the @self has changed its #VisuBox. * * Since: 3.7 * * Returns: FALSE @boxed was already boxed with the #VisuBox of @box. **/ gboolean visu_boxed_setBox(VisuBoxed *self, VisuBoxed *box) { VisuBox *boxObj; gboolean res; g_return_val_if_fail(VISU_IS_BOXED(self), FALSE); boxObj = (box) ? visu_boxed_getBox(box) : (VisuBox*)0; res = VISU_BOXED_GET_INTERFACE(self)->set_box(self, boxObj); if (res) { DBG_fprintf(stderr, "Iface Boxed: notify box.\n"); g_object_notify_by_pspec(G_OBJECT(self), _properties[PROP_BOX]); DBG_fprintf(stderr, "Iface Boxed: signal box.\n"); g_signal_emit(G_OBJECT(self), _signals[SET_BOX_SIGNAL], 0, boxObj); DBG_fprintf(stderr, "Iface Boxed: set box done.\n"); } return res; } v_sim-3.8.0/src/iface_boxed.h000066400000000000000000000057661370110300500160330ustar00rootroot00000000000000/* EXTRAITS DE LA LICENCE Copyright CEA, contributeurs : Luc BILLARD et Damien CALISTE, laboratoire L_Sim, (2001-2005) Adresse mèl : BILLARD, non joignable par mèl ; CALISTE, damien P caliste AT cea P fr. Ce logiciel est un programme informatique servant à visualiser des structures atomiques dans un rendu pseudo-3D. Ce logiciel est régi par la licence CeCILL soumise au droit français et respectant les principes de diffusion des logiciels libres. Vous pouvez utiliser, modifier et/ou redistribuer ce programme sous les conditions de la licence CeCILL telle que diffusée par le CEA, le CNRS et l'INRIA sur le site "http://www.cecill.info". Le fait que vous puissiez accéder à cet en-tête signifie que vous avez pris connaissance de la licence CeCILL, et que vous en avez accepté les termes (cf. le fichier Documentation/licence.fr.txt fourni avec ce logiciel). */ /* LICENCE SUM UP Copyright CEA, contributors : Luc BILLARD et Damien CALISTE, laboratoire L_Sim, (2001-2005) E-mail address: BILLARD, not reachable any more ; CALISTE, damien P caliste AT cea P fr. This software is a computer program whose purpose is to visualize atomic configurations in 3D. This software is governed by the CeCILL license under French law and abiding by the rules of distribution of free software. You can use, modify and/ or redistribute the software under the terms of the CeCILL license as circulated by CEA, CNRS and INRIA at the following URL "http://www.cecill.info". The fact that you are presently reading this means that you have had knowledge of the CeCILL license and that you accept its terms. You can find a copy of this licence shipped with this software at Documentation/licence.en.txt. */ #ifndef IFACE_BOXED_H #define IFACE_BOXED_H #include #include #include "visu_box.h" G_BEGIN_DECLS /* Boxed interface. */ #define VISU_TYPE_BOXED (visu_boxed_get_type ()) #define VISU_BOXED(obj) (G_TYPE_CHECK_INSTANCE_CAST ((obj), VISU_TYPE_BOXED, VisuBoxed)) #define VISU_IS_BOXED(obj) (G_TYPE_CHECK_INSTANCE_TYPE ((obj), VISU_TYPE_BOXED)) #define VISU_BOXED_GET_INTERFACE(inst) (G_TYPE_INSTANCE_GET_INTERFACE ((inst), VISU_TYPE_BOXED, VisuBoxedInterface)) typedef struct _VisuBoxedInterface VisuBoxedInterface; typedef struct _VisuBoxed VisuBoxed; /* dummy object */ /** * VisuBoxed: * * Interface for objects with #VisuBox. */ /** * VisuBoxedInterface: * @parent: yet, its parent. * @get_box: a routine to get a pointer on the #VisuBox. * @set_box: a routine to set a #VisuBox to a #VisuBoxed object. * * The different routines common to objects implementing a #VisuBoxed interface. * * Since: 3.7 */ struct _VisuBoxedInterface { GTypeInterface parent; VisuBox* (*get_box) (VisuBoxed *self); gboolean (*set_box) (VisuBoxed *self, VisuBox *box); }; GType visu_boxed_get_type (void); VisuBox* visu_boxed_getBox(VisuBoxed *self); gboolean visu_boxed_setBox(VisuBoxed *self, VisuBoxed *box); G_END_DECLS #endif v_sim-3.8.0/src/iface_maskable.c000066400000000000000000000104551370110300500164730ustar00rootroot00000000000000/* EXTRAITS DE LA LICENCE Copyright CEA, contributeurs : Damien CALISTE, laboratoire L_Sim, (2017) Adresse mèl : CALISTE, damien P caliste AT cea P fr. Ce logiciel est un programme informatique servant à visualiser des structures atomiques dans un rendu pseudo-3D. Ce logiciel est régi par la licence CeCILL soumise au droit français et respectant les principes de diffusion des logiciels libres. Vous pouvez utiliser, modifier et/ou redistribuer ce programme sous les conditions de la licence CeCILL telle que diffusée par le CEA, le CNRS et l'INRIA sur le site "http://www.cecill.info". Le fait que vous puissiez accéder à cet en-tête signifie que vous avez pris connaissance de la licence CeCILL, et que vous en avez accepté les termes (cf. le fichier Documentation/licence.fr.txt fourni avec ce logiciel). */ /* LICENCE SUM UP Copyright CEA, contributors : Damien CALISTE, laboratoire L_Sim, (2017) E-mail address: BILLARD, not reachable any more ; CALISTE, damien P caliste AT cea P fr. This software is a computer program whose purpose is to visualize atomic configurations in 3D. This software is governed by the CeCILL license under French law and abiding by the rules of distribution of free software. You can use, modify and/ or redistribute the software under the terms of the CeCILL license as circulated by CEA, CNRS and INRIA at the following URL "http://www.cecill.info". The fact that you are presently reading this means that you have had knowledge of the CeCILL license and that you accept its terms. You can find a copy of this licence shipped with this software at Documentation/licence.en.txt. */ #include "iface_maskable.h" #include "config.h" /** * SECTION:iface_maskable * @short_description: an interface for maskable objects. * * This interface describes objects that can be masked by * others. The implementation should provide one method to reset the * visibility to fully visible. In addition, it is defining a signal * that can be triggered when calling visu_maskable_visibilityChanged(). */ /* enum { */ /* PROP_0, */ /* N_PROPS */ /* }; */ /* static GParamSpec *properties[N_PROPS]; */ enum { REQUEST_SIGNAL, VISIBILITY_CHANGED_SIGNAL, NB_SIGNAL }; /* Internal variables. */ static guint _signals[NB_SIGNAL] = { 0 }; /* Maskable interface. */ G_DEFINE_INTERFACE(VisuMaskable, visu_maskable, G_TYPE_OBJECT) static void visu_maskable_default_init(VisuMaskableInterface *iface) { /** * VisuMaskable::visibility-changed: * @maskable: the object which received the signal ; * * Gets emitted when one or more nodes have changed of * visibility. Some may have appeared, some may have disappeared. * * Since: 3.2 */ _signals[VISIBILITY_CHANGED_SIGNAL] = g_signal_new("visibility-changed", G_TYPE_FROM_INTERFACE(iface), G_SIGNAL_RUN_LAST | G_SIGNAL_NO_RECURSE | G_SIGNAL_NO_HOOKS, 0, NULL, NULL, g_cclosure_marshal_VOID__VOID, G_TYPE_NONE, 0); } /** * visu_maskable_resetVisibility: * @maskable: a #VisuMaskable object. * * Reset the visibility of all elements in @maskable to visible. * * Since: 3.8 * * Returns: TRUE if any element visibility has changed. **/ gboolean visu_maskable_resetVisibility(VisuMaskable *maskable) { g_return_val_if_fail(VISU_IS_MASKABLE(maskable), FALSE); if (!VISU_MASKABLE_GET_INTERFACE(maskable)->reset_visibility) return FALSE; return VISU_MASKABLE_GET_INTERFACE(maskable)->reset_visibility(maskable); } /** * visu_maskable_getMasked: * @maskable: a #VisuMaskable object. * * Return a list of ids of masked elements. * * Since: 3.8 * * Returns: (element-type uint) (transfer full): a list of ids of * masked elements. **/ GArray* visu_maskable_getMasked(const VisuMaskable *maskable) { g_return_val_if_fail(VISU_IS_MASKABLE(maskable), (GArray*)0); if (!VISU_MASKABLE_GET_INTERFACE(maskable)->get_masked) return (GArray*)0; return VISU_MASKABLE_GET_INTERFACE(maskable)->get_masked(maskable); } /** * visu_maskable_visibilityChanged: * @maskable: a #VisuMaskable object. * * A convenience routine to emit the "visibility-changed" signal. * * Since: 3.8 **/ void visu_maskable_visibilityChanged(VisuMaskable *maskable) { g_return_if_fail(VISU_IS_MASKABLE(maskable)); g_signal_emit(maskable, _signals[VISIBILITY_CHANGED_SIGNAL], 0); } v_sim-3.8.0/src/iface_maskable.h000066400000000000000000000060731370110300500165010ustar00rootroot00000000000000/* EXTRAITS DE LA LICENCE Copyright CEA, contributeurs : Damien CALISTE, laboratoire L_Sim, (2017) Adresse mèl : CALISTE, damien P caliste AT cea P fr. Ce logiciel est un programme informatique servant à visualiser des structures atomiques dans un rendu pseudo-3D. Ce logiciel est régi par la licence CeCILL soumise au droit français et respectant les principes de diffusion des logiciels libres. Vous pouvez utiliser, modifier et/ou redistribuer ce programme sous les conditions de la licence CeCILL telle que diffusée par le CEA, le CNRS et l'INRIA sur le site "http://www.cecill.info". Le fait que vous puissiez accéder à cet en-tête signifie que vous avez pris connaissance de la licence CeCILL, et que vous en avez accepté les termes (cf. le fichier Documentation/licence.fr.txt fourni avec ce logiciel). */ /* LICENCE SUM UP Copyright CEA, contributors : Damien CALISTE, laboratoire L_Sim, (2017) E-mail address: BILLARD, not reachable any more ; CALISTE, damien P caliste AT cea P fr. This software is a computer program whose purpose is to visualize atomic configurations in 3D. This software is governed by the CeCILL license under French law and abiding by the rules of distribution of free software. You can use, modify and/ or redistribute the software under the terms of the CeCILL license as circulated by CEA, CNRS and INRIA at the following URL "http://www.cecill.info". The fact that you are presently reading this means that you have had knowledge of the CeCILL license and that you accept its terms. You can find a copy of this licence shipped with this software at Documentation/licence.en.txt. */ #ifndef IFACE_MASKABLE_H #define IFACE_MASKABLE_H #include #include G_BEGIN_DECLS /* Maskable interface. */ #define VISU_TYPE_MASKABLE (visu_maskable_get_type ()) #define VISU_MASKABLE(obj) (G_TYPE_CHECK_INSTANCE_CAST ((obj), VISU_TYPE_MASKABLE, VisuMaskable)) #define VISU_IS_MASKABLE(obj) (G_TYPE_CHECK_INSTANCE_TYPE ((obj), VISU_TYPE_MASKABLE)) #define VISU_MASKABLE_GET_INTERFACE(inst) (G_TYPE_INSTANCE_GET_INTERFACE ((inst), VISU_TYPE_MASKABLE, VisuMaskableInterface)) typedef struct _VisuMaskableInterface VisuMaskableInterface; typedef struct _VisuMaskable VisuMaskable; /* dummy object */ /** * VisuMaskable: * * Interface object. * * Since: 3.8 */ /** * VisuMaskableInterface: * @parent: its parent. * @reset_visibility: a method used to reset to %TRUE all node visibility. * @get_masked: a method used to get ids of masked nodes. * * The different routines common to objects implementing a #VisuMaskable interface. * * Since: 3.8 */ struct _VisuMaskableInterface { GTypeInterface parent; gboolean (*reset_visibility)(VisuMaskable *maskable); GArray* (*get_masked)(const VisuMaskable *maskable); }; GType visu_maskable_get_type(void); gboolean visu_maskable_resetVisibility(VisuMaskable *maskable); void visu_maskable_visibilityChanged(VisuMaskable *maskable); GArray* visu_maskable_getMasked(const VisuMaskable *maskable); G_END_DECLS #endif v_sim-3.8.0/src/iface_nodemasker.c000066400000000000000000000116241370110300500170430ustar00rootroot00000000000000/* EXTRAITS DE LA LICENCE Copyright CEA, contributeurs : Damien CALISTE, laboratoire L_Sim, (2017) Adresse mèl : CALISTE, damien P caliste AT cea P fr. Ce logiciel est un programme informatique servant à visualiser des structures atomiques dans un rendu pseudo-3D. Ce logiciel est régi par la licence CeCILL soumise au droit français et respectant les principes de diffusion des logiciels libres. Vous pouvez utiliser, modifier et/ou redistribuer ce programme sous les conditions de la licence CeCILL telle que diffusée par le CEA, le CNRS et l'INRIA sur le site "http://www.cecill.info". Le fait que vous puissiez accéder à cet en-tête signifie que vous avez pris connaissance de la licence CeCILL, et que vous en avez accepté les termes (cf. le fichier Documentation/licence.fr.txt fourni avec ce logiciel). */ /* LICENCE SUM UP Copyright CEA, contributors : Damien CALISTE, laboratoire L_Sim, (2017) E-mail address: BILLARD, not reachable any more ; CALISTE, damien P caliste AT cea P fr. This software is a computer program whose purpose is to visualize atomic configurations in 3D. This software is governed by the CeCILL license under French law and abiding by the rules of distribution of free software. You can use, modify and/ or redistribute the software under the terms of the CeCILL license as circulated by CEA, CNRS and INRIA at the following URL "http://www.cecill.info". The fact that you are presently reading this means that you have had knowledge of the CeCILL license and that you accept its terms. You can find a copy of this licence shipped with this software at Documentation/licence.en.txt. */ #include "iface_nodemasker.h" #include "config.h" /** * SECTION:iface_nodemasker * @short_description: an interface for objects with masking * capabilities on #VisuNode. * * Implementers of this interface are objects that can change * the visibility of #VisuNode through the visu_node_masker_apply() * routine. When an implementer has its masking parameters that have * changed, it should call visu_node_masker_emitDirty(). */ /* enum { */ /* PROP_0, */ /* N_PROPS */ /* }; */ /* static GParamSpec *properties[N_PROPS]; */ enum { DIRTY_SIGNAL, NB_SIGNAL }; static guint _signals[NB_SIGNAL] = { 0 }; /* NodeMasker interface. */ G_DEFINE_INTERFACE(VisuNodeMasker, visu_node_masker, G_TYPE_OBJECT) static void visu_node_masker_default_init(VisuNodeMaskerInterface *iface) { /** * VisuNodeMasker::masking-dirty: * @masker: the object emitting the signal. * * This signal is emitted when some masking parameters changed. * * Since: 3.8 */ _signals[DIRTY_SIGNAL] = g_signal_new("masking-dirty", G_TYPE_FROM_INTERFACE(iface), G_SIGNAL_RUN_LAST | G_SIGNAL_NO_RECURSE | G_SIGNAL_NO_HOOKS, 0, NULL, NULL, g_cclosure_marshal_VOID__VOID, G_TYPE_NONE, 0, NULL); } /** * visu_node_masker_setMaskFunc: * @masker: a #VisuNodeMasker object. * @func: (closure data) (scope notified) (allow-none): a #VisuNodeMaskerFunc object. * @data: (closure): some data. * @destroy: (destroy data): destroy function. * * If the implementation provides a user defined masking function, * this calls the #VisuNodeMaskerInterface::set_mask_func() routine. * * Since: 3.8 * * Returns: TRUE if value is actually changed. **/ gboolean visu_node_masker_setMaskFunc(VisuNodeMasker *masker, VisuNodeMaskerFunc func, gpointer data, GDestroyNotify destroy) { gboolean res; g_return_val_if_fail(VISU_IS_NODE_MASKER(masker), FALSE); if (!VISU_NODE_MASKER_GET_INTERFACE(masker)->set_mask_func) return FALSE; res = VISU_NODE_MASKER_GET_INTERFACE(masker)->set_mask_func(masker, func, data, destroy); if (res) visu_node_masker_emitDirty(masker); return res; } /** * visu_node_masker_apply: * @masker: a #VisuNodeMasker object. * @redraw: (out caller-allocates): a location for a boolean * @array: a #VisuNodeArray object. * * Apply the masking properties of @masker over @array. If any node * visibility has changed, @redraw is set to %TRUE. * * Since: 3.8 **/ void visu_node_masker_apply(const VisuNodeMasker *masker, gboolean *redraw, VisuNodeArray *array) { g_return_if_fail(VISU_IS_NODE_MASKER(masker)); if (!VISU_NODE_MASKER_GET_INTERFACE(masker)->apply) return; if (VISU_NODE_MASKER_GET_INTERFACE(masker)->apply(masker, array) && redraw) *redraw = TRUE; } /** * visu_node_masker_emitDirty: * @masker: a #VisuNodeMasker object. * * Emits the "masking-dirty" signal. To be used by implementation of * this interface to signal that some masking properties have changed. * * Since: 3.8 **/ void visu_node_masker_emitDirty(VisuNodeMasker *masker) { DBG_fprintf(stderr, "Visu Node Masker: emitting dirty signal for %p.\n", (gpointer)masker); g_signal_emit(masker, _signals[DIRTY_SIGNAL], 0); } v_sim-3.8.0/src/iface_nodemasker.h000066400000000000000000000076271370110300500170600ustar00rootroot00000000000000/* EXTRAITS DE LA LICENCE Copyright CEA, contributeurs : Damien CALISTE, laboratoire L_Sim, (2017) Adresse mèl : CALISTE, damien P caliste AT cea P fr. Ce logiciel est un programme informatique servant à visualiser des structures atomiques dans un rendu pseudo-3D. Ce logiciel est régi par la licence CeCILL soumise au droit français et respectant les principes de diffusion des logiciels libres. Vous pouvez utiliser, modifier et/ou redistribuer ce programme sous les conditions de la licence CeCILL telle que diffusée par le CEA, le CNRS et l'INRIA sur le site "http://www.cecill.info". Le fait que vous puissiez accéder à cet en-tête signifie que vous avez pris connaissance de la licence CeCILL, et que vous en avez accepté les termes (cf. le fichier Documentation/licence.fr.txt fourni avec ce logiciel). */ /* LICENCE SUM UP Copyright CEA, contributors : Damien CALISTE, laboratoire L_Sim, (2017) E-mail address: BILLARD, not reachable any more ; CALISTE, damien P caliste AT cea P fr. This software is a computer program whose purpose is to visualize atomic configurations in 3D. This software is governed by the CeCILL license under French law and abiding by the rules of distribution of free software. You can use, modify and/ or redistribute the software under the terms of the CeCILL license as circulated by CEA, CNRS and INRIA at the following URL "http://www.cecill.info". The fact that you are presently reading this means that you have had knowledge of the CeCILL license and that you accept its terms. You can find a copy of this licence shipped with this software at Documentation/licence.en.txt. */ #ifndef IFACE_NODE_MASKER_H #define IFACE_NODE_MASKER_H #include #include #include "visu_nodes.h" #include "extraFunctions/nodeProp.h" G_BEGIN_DECLS /* NodeMasker interface. */ #define VISU_TYPE_NODE_MASKER (visu_node_masker_get_type ()) #define VISU_NODE_MASKER(obj) (G_TYPE_CHECK_INSTANCE_CAST ((obj), VISU_TYPE_NODE_MASKER, VisuNodeMasker)) #define VISU_IS_NODE_MASKER(obj) (G_TYPE_CHECK_INSTANCE_TYPE ((obj), VISU_TYPE_NODE_MASKER)) #define VISU_NODE_MASKER_GET_INTERFACE(inst) (G_TYPE_INSTANCE_GET_INTERFACE ((inst), VISU_TYPE_NODE_MASKER, VisuNodeMaskerInterface)) typedef struct _VisuNodeMaskerInterface VisuNodeMaskerInterface; typedef struct _VisuNodeMasker VisuNodeMasker; /* dummy object */ /** * VisuNodeMasker: * * Interface object. * * Since: 3.8 */ /** * VisuNodeMaskerFunc: * @masker: a #VisuNodeMasker object ; * @at: a #VisuNodeValuesIter pointer * @data: (closure): some data. * * Function to decide to hide a node or not. * * Returns: TRUE to hide a node depending on values in @at. * * Since: 3.8 */ typedef gboolean (*VisuNodeMaskerFunc)(const VisuNodeMasker *masker, const VisuNodeValuesIter *at, gpointer data); /** * VisuNodeMaskerInterface: * @parent: its parent. * @set_mask_func: a method to specify a custom masking routine. * @apply: a method used to apply a visibility mask on a #VisuNodeArray. * * The different routines common to objects implementing a #VisuNodeMasker interface. * * Since: 3.8 */ struct _VisuNodeMaskerInterface { GTypeInterface parent; gboolean (*set_mask_func)(VisuNodeMasker *masker, VisuNodeMaskerFunc func, gpointer data, GDestroyNotify destroy); gboolean (*apply) (const VisuNodeMasker *masker, VisuNodeArray *array); }; GType visu_node_masker_get_type(void); gboolean visu_node_masker_setMaskFunc(VisuNodeMasker *masker, VisuNodeMaskerFunc func, gpointer data, GDestroyNotify destroy); void visu_node_masker_apply(const VisuNodeMasker *masker, gboolean *redraw, VisuNodeArray *array); void visu_node_masker_emitDirty(VisuNodeMasker *masker); G_END_DECLS #endif v_sim-3.8.0/src/iface_pointset.c000066400000000000000000000232511370110300500165570ustar00rootroot00000000000000/* EXTRAITS DE LA LICENCE Copyright CEA, contributeurs : Luc BILLARD et Damien CALISTE, laboratoire L_Sim, (2001-2005) Adresse mèl : BILLARD, non joignable par mèl ; CALISTE, damien P caliste AT cea P fr. Ce logiciel est un programme informatique servant à visualiser des structures atomiques dans un rendu pseudo-3D. Ce logiciel est régi par la licence CeCILL soumise au droit français et respectant les principes de diffusion des logiciels libres. Vous pouvez utiliser, modifier et/ou redistribuer ce programme sous les conditions de la licence CeCILL telle que diffusée par le CEA, le CNRS et l'INRIA sur le site "http://www.cecill.info". Le fait que vous puissiez accéder à cet en-tête signifie que vous avez pris connaissance de la licence CeCILL, et que vous en avez accepté les termes (cf. le fichier Documentation/licence.fr.txt fourni avec ce logiciel). */ /* LICENCE SUM UP Copyright CEA, contributors : Luc BILLARD et Damien CALISTE, laboratoire L_Sim, (2001-2005) E-mail address: BILLARD, not reachable any more ; CALISTE, damien P caliste AT cea P fr. This software is a computer program whose purpose is to visualize atomic configurations in 3D. This software is governed by the CeCILL license under French law and abiding by the rules of distribution of free software. You can use, modify and/ or redistribute the software under the terms of the CeCILL license as circulated by CEA, CNRS and INRIA at the following URL "http://www.cecill.info". The fact that you are presently reading this means that you have had knowledge of the CeCILL license and that you accept its terms. You can find a copy of this licence shipped with this software at Documentation/licence.en.txt. */ #include "iface_pointset.h" #include "config.h" /** * SECTION:iface_pointset * @short_description: Defines a common interface for objects with * points inside a box that can be translated or expanded. * @See_also: #VisuData, #VisuSurface, #VisuScalarField * @Title: VisuPointset * * */ enum { PROP_0, PROP_USE_TRANS, PROP_TRANS, PROP_RED_TRANS, PROP_MODULO, N_PROPS }; static GParamSpec *properties[N_PROPS]; /* enum */ /* { */ /* NB_SIGNAL */ /* }; */ /* /\* Internal variables. *\/ */ /* static guint _signals[NB_SIGNAL] = { 0 }; */ /* Pointset interface. */ G_DEFINE_INTERFACE(VisuPointset, visu_pointset, VISU_TYPE_BOXED) static void visu_pointset_default_init(VisuPointsetInterface *iface) { /** * VisuPointset::use-translation: * * Wether translations are applied or not. * * Since: 3.8 */ properties[PROP_USE_TRANS] = g_param_spec_boolean("use-translation", "Use translation", "Use translations along all axis", FALSE, G_PARAM_READWRITE); g_object_interface_install_property(iface, properties[PROP_USE_TRANS]); /** * VisuPointset::translation: * * The translation applied on [x,y,z] axis. * * Since: 3.8 */ properties[PROP_TRANS] = g_param_spec_boxed("translation", "Translations along all axis", "Translations along all axis", TOOL_TYPE_VECTOR, G_PARAM_READWRITE); g_object_interface_install_property(iface, properties[PROP_TRANS]); /** * VisuPointset::reduced-translation: * * The translation applied on the box axis, normalised by box lengths. * * Since: 3.8 */ properties[PROP_RED_TRANS] = g_param_spec_boxed("reduced-translation", "Translations along box axis", "Translations along box axis", TOOL_TYPE_VECTOR, G_PARAM_READWRITE); g_object_interface_install_property(iface, properties[PROP_RED_TRANS]); /** * VisuPointset::in-the-box: * * The status of the position of all nodes. * * Since: 3.8 */ properties[PROP_MODULO] = g_param_spec_boolean("in-the-box", "Constrain nodes in the box", "All nodes are constrained in the box", FALSE, G_PARAM_READWRITE); g_object_interface_install_property(iface, properties[PROP_MODULO]); } /** * visu_pointset_getTranslation: * @self: a #VisuPointset object. * @trans: (array fixed-size=3) (out): a location to store the * translation values. * * Retrieves the translations of @self. * * Since: 3.8 **/ void visu_pointset_getTranslation(VisuPointset *self, float trans[3]) { g_return_if_fail(VISU_IS_POINTSET(self)); VISU_POINTSET_GET_INTERFACE(self)->get_translation(self, trans); } /** * visu_pointset_setTranslation: * @self: a #VisuPointset object. * @trans: (array fixed-size=3): the translations. * @withModulo: a boolean. * * Apply the given translation values to @self. If @withModulo is * given, all points inside the pointset will be shifted inside the * periodic cell. * * Since: 3.8 * * Returns: FALSE @pointset was already pointset with the #VisuBox of @box. **/ gboolean visu_pointset_setTranslation(VisuPointset *self, float trans[3], gboolean withModulo) { g_return_val_if_fail(VISU_IS_POINTSET(self), FALSE); return VISU_POINTSET_GET_INTERFACE(self)->set_translation(self, trans, withModulo); } /** * visu_pointset_setTranslationActive: * @self: a #VisuPointset object. * @status: a boolean. * * Set the if the translations are applied or not to @self. * * Since: 3.8 * * Returns: TRUE if status is changed. **/ gboolean visu_pointset_setTranslationActive(VisuPointset *self, gboolean status) { g_return_val_if_fail(VISU_IS_POINTSET(self), FALSE); return VISU_POINTSET_GET_INTERFACE(self)->set_translationActive(self, status); } /** * visu_pointset_shift: * @self: a #VisuPointset object. * @delta: (array fixed-size=3): a translation. * @withModulo: a boolean. * * Shift the translation by @delta. * * Since: 3.8 * * Returns: TRUE if translation is changed. **/ gboolean visu_pointset_shift(VisuPointset *self, const gfloat delta[3], gboolean withModulo) { gfloat trans[3]; visu_pointset_getTranslation(self, trans); trans[0] += delta[0]; trans[1] += delta[1]; trans[2] += delta[2]; return visu_pointset_setTranslation(self, trans, withModulo); } /** * visu_pointset_setInTheBox: * @self: a #VisuPointset object. * @status: a boolean. * * Update all node positions inside @self to be constrained inside the * box (@status is TRUE), or release all previous position shift to * original position without constrain (@status is FALSE). * * Since: 3.8 * * Returns: TRUE, if any node has changed position. **/ gboolean visu_pointset_setInTheBox(VisuPointset *self, gboolean status) { g_return_val_if_fail(VISU_IS_POINTSET(self), FALSE); return VISU_POINTSET_GET_INTERFACE(self)->set_inTheBox(self, status); } /** * visu_pointset_setTranslationPeriodic: * @self: a #VisuPointset object ; * @trans: (in) (array fixed-size=3): an array of floating point * values. * @withModulo: a boolean. * * This sets the translations of the specified #VisuPointset only in * periodic boundary conditions. Points are also constrainted inside * the box in the periodic directions if @withModulo is TRUE. * * Returns: TRUE if any translations have been changed. */ gboolean visu_pointset_setTranslationPeriodic(VisuPointset* self, float trans[3], gboolean withModulo) { VisuBoxBoundaries bc; float xyz_[3]; g_return_val_if_fail(VISU_IS_POINTSET(self), FALSE); visu_pointset_getTranslation(self, xyz_); bc = visu_box_getBoundary(visu_boxed_getBox(VISU_BOXED(self))); if (bc & TOOL_XYZ_MASK_X) xyz_[0] = trans[0]; if (bc & TOOL_XYZ_MASK_Y) xyz_[1] = trans[1]; if (bc & TOOL_XYZ_MASK_Z) xyz_[2] = trans[2]; return visu_pointset_setTranslation(self, xyz_, withModulo); } /** * visu_pointset_setBoxTranslation: * @self: a #VisuPointset object ; * @boxTrans: (in) (array fixed-size=3): an array of floating point * values. * @withModulo: a boolean. * * This sets the translations of the specified #VisuPointset only along * periodic axis. The translation @boxTrans gives normalized values * along all box axis. Points are also constrainted inside * the box in the periodic directions if @withModulo is TRUE. * * Since: 3.8 * * Returns: TRUE if any translations have been changed. **/ gboolean visu_pointset_setBoxTranslation(VisuPointset* self, float boxTrans[3], gboolean withModulo) { VisuBox *box; gfloat trans[3], orig[3]; float zeros[3] = {0.f, 0.f, 0.f}; box = visu_boxed_getBox(VISU_BOXED(self)); visu_box_convertBoxCoordinatestoXYZ(box, orig, zeros); visu_box_convertBoxCoordinatestoXYZ(box, trans, boxTrans); trans[0] -= orig[0]; trans[1] -= orig[1]; trans[2] -= orig[2]; return visu_pointset_setTranslationPeriodic(self, trans, withModulo); } /** * visu_pointset_getTranslationPeriodicStatus: * @self: a #VisuPointset object. * * Tests if any of the translation in the periodic boundary * conditions are not null. * * Since: 3.8 * * Returns: TRUE if any of the translation in the periodic boundary * conditions are not null. **/ gboolean visu_pointset_getTranslationPeriodicStatus(VisuPointset *self) { VisuBoxBoundaries bc; float xyz_[3]; g_return_val_if_fail(VISU_IS_POINTSET(self), FALSE); visu_pointset_getTranslation(self, xyz_); bc = visu_box_getBoundary(visu_boxed_getBox(VISU_BOXED(self))); return ((bc & TOOL_XYZ_MASK_X) && xyz_[0] != 0.f) || ((bc & TOOL_XYZ_MASK_Y) && xyz_[1] != 0.f) || ((bc & TOOL_XYZ_MASK_Z) && xyz_[2] != 0.f); } /** * visu_pointset_applyTranslation: * @self: a #VisuPointset object. * * Apply all the translation (node and box) on each node coordinates * and reset both translations to zero. * * Since: 3.8 **/ void visu_pointset_applyTranslation(VisuPointset *self) { g_return_if_fail(VISU_IS_POINTSET(self)); VISU_POINTSET_GET_INTERFACE(self)->apply_translation(self); } v_sim-3.8.0/src/iface_pointset.h000066400000000000000000000104741370110300500165670ustar00rootroot00000000000000/* EXTRAITS DE LA LICENCE Copyright CEA, contributeurs : Luc BILLARD et Damien CALISTE, laboratoire L_Sim, (2001-2005) Adresse mèl : BILLARD, non joignable par mèl ; CALISTE, damien P caliste AT cea P fr. Ce logiciel est un programme informatique servant à visualiser des structures atomiques dans un rendu pseudo-3D. Ce logiciel est régi par la licence CeCILL soumise au droit français et respectant les principes de diffusion des logiciels libres. Vous pouvez utiliser, modifier et/ou redistribuer ce programme sous les conditions de la licence CeCILL telle que diffusée par le CEA, le CNRS et l'INRIA sur le site "http://www.cecill.info". Le fait que vous puissiez accéder à cet en-tête signifie que vous avez pris connaissance de la licence CeCILL, et que vous en avez accepté les termes (cf. le fichier Documentation/licence.fr.txt fourni avec ce logiciel). */ /* LICENCE SUM UP Copyright CEA, contributors : Luc BILLARD et Damien CALISTE, laboratoire L_Sim, (2001-2005) E-mail address: BILLARD, not reachable any more ; CALISTE, damien P caliste AT cea P fr. This software is a computer program whose purpose is to visualize atomic configurations in 3D. This software is governed by the CeCILL license under French law and abiding by the rules of distribution of free software. You can use, modify and/ or redistribute the software under the terms of the CeCILL license as circulated by CEA, CNRS and INRIA at the following URL "http://www.cecill.info". The fact that you are presently reading this means that you have had knowledge of the CeCILL license and that you accept its terms. You can find a copy of this licence shipped with this software at Documentation/licence.en.txt. */ #ifndef IFACE_POINTSET_H #define IFACE_POINTSET_H #include #include #include "iface_boxed.h" G_BEGIN_DECLS /* Pointset interface. */ #define VISU_TYPE_POINTSET (visu_pointset_get_type ()) #define VISU_POINTSET(obj) (G_TYPE_CHECK_INSTANCE_CAST ((obj), VISU_TYPE_POINTSET, VisuPointset)) #define VISU_IS_POINTSET(obj) (G_TYPE_CHECK_INSTANCE_TYPE ((obj), VISU_TYPE_POINTSET)) #define VISU_POINTSET_GET_INTERFACE(inst) (G_TYPE_INSTANCE_GET_INTERFACE ((inst), VISU_TYPE_POINTSET, VisuPointsetInterface)) typedef struct _VisuPointsetInterface VisuPointsetInterface; typedef struct _VisuPointset VisuPointset; /* dummy object */ /** * VisuPointset: * * Interface object. * * Since: 3.8 */ /** * VisuPointsetInterface: * @parent: yet, its parent. * @set_inTheBox: a routine to translate every content in the box. * @set_translationActive: a routine to activate or not the translation. * @get_translation: a routine to get the current translation status. * @set_translation: a routine to set the translation status. * @apply_translation: a routine to apply the stored translations. * * The different routines common to objects implementing a #VisuPointset interface. * * Since: 3.8 */ struct _VisuPointsetInterface { VisuBoxedInterface parent; gboolean (*set_inTheBox) (VisuPointset *self, gboolean status); gboolean (*set_translationActive) (VisuPointset *self, gboolean status); void (*get_translation) (VisuPointset *self, float translation[3]); gboolean (*set_translation) (VisuPointset *self, float translation[3], gboolean withModulo); void (*apply_translation) (VisuPointset *set); }; GType visu_pointset_get_type (void); gboolean visu_pointset_setInTheBox(VisuPointset *self, gboolean status); gboolean visu_pointset_setTranslationActive(VisuPointset *self, gboolean status); void visu_pointset_applyTranslation(VisuPointset *self); void visu_pointset_getTranslation(VisuPointset *self, float trans[3]); gboolean visu_pointset_setTranslation(VisuPointset *self, float trans[3], gboolean withModulo); gboolean visu_pointset_setTranslationPeriodic(VisuPointset* self, float trans[3], gboolean withModulo); gboolean visu_pointset_setBoxTranslation(VisuPointset* self, float boxTrans[3], gboolean withModulo); gboolean visu_pointset_shift(VisuPointset *self, const gfloat delta[3], gboolean withModulo); gboolean visu_pointset_getTranslationPeriodicStatus(VisuPointset *self); G_END_DECLS #endif v_sim-3.8.0/src/interface.c000066400000000000000000002243521370110300500155300ustar00rootroot00000000000000/* * DO NOT EDIT THIS FILE - it is generated by Glade. */ #ifdef HAVE_CONFIG_H # include #endif #include #include #include #include #include #include #include #include "interface.h" #include "support.h" #define GLADE_HOOKUP_OBJECT(component,widget,name) \ g_object_set_data_full (G_OBJECT (component), name, \ gtk_widget_ref (widget), (GDestroyNotify) gtk_widget_unref) #define GLADE_HOOKUP_OBJECT_NO_REF(component,widget,name) \ g_object_set_data (G_OBJECT (component), name, widget) GtkWidget* create_saveDialog (void) { GtkWidget *saveDialog; GdkPixbuf *saveDialog_icon_pixbuf; GtkWidget *dialog_vbox1; GtkWidget *hbox30; GtkWidget *image25; GtkWidget *vbox4; GtkWidget *labelSaveDialog; GtkWidget *notebookSave; GtkWidget *vbox14; GtkWidget *notebookResources; GtkWidget *vbox15; GtkWidget *label75; GtkWidget *filechooserwidgetResources; GtkWidget *buttonLoadResources; GtkWidget *image48; GtkWidget *vbox16; GtkWidget *label76; GtkWidget *hbox65; GtkWidget *comboboxentryResources; GtkWidget *buttonSaveResources; GtkWidget *checkLimitOnVisuData; GtkWidget *image49; GtkWidget *labelTipsResources; GtkWidget *hbox55; GtkWidget *imageWarningResources; GtkWidget *statusbarResources; GtkWidget *labelResources; GtkWidget *vbox18; GtkWidget *hbox54; GtkWidget *image42; GtkWidget *label83; GtkWidget *hbox66; GtkWidget *comboboxentryParameters; GtkWidget *buttonSaveParameters; GtkWidget *hbox56; GtkWidget *imageWarningParameters; GtkWidget *statusbarParameters; GtkWidget *labelParameters; GtkWidget *frame6; GtkWidget *vbox17; GtkWidget *labelHelp; GtkWidget *labelHelpTips; GtkWidget *hbox51; GtkWidget *image40; GtkWidget *label80; GtkWidget *closeButtonSave; saveDialog = gtk_dialog_new (); gtk_window_set_title (GTK_WINDOW (saveDialog), _("Save session")); gtk_window_set_position (GTK_WINDOW (saveDialog), GTK_WIN_POS_CENTER_ON_PARENT); gtk_window_set_modal (GTK_WINDOW (saveDialog), TRUE); gtk_window_set_default_size (GTK_WINDOW (saveDialog), 450, -1); saveDialog_icon_pixbuf = create_pixbuf ("icone-dialog.png"); if (saveDialog_icon_pixbuf) { gtk_window_set_icon (GTK_WINDOW (saveDialog), saveDialog_icon_pixbuf); g_object_unref (saveDialog_icon_pixbuf); } dialog_vbox1 = gtk_dialog_get_content_area(GTK_DIALOG(saveDialog)); gtk_widget_show (dialog_vbox1); hbox30 = gtk_hbox_new (FALSE, 0); gtk_widget_show (hbox30); gtk_box_pack_start (GTK_BOX (dialog_vbox1), hbox30, TRUE, TRUE, 0); image25 = create_pixmap (saveDialog, "save-bandeau.png"); gtk_widget_show (image25); gtk_box_pack_start (GTK_BOX (hbox30), image25, FALSE, FALSE, 0); gtk_widget_set_valign(image25, GTK_ALIGN_END); gtk_widget_set_margin_start(image25, 10); gtk_widget_set_margin_end(image25, 10); gtk_widget_set_margin_top(image25, 5); gtk_widget_set_margin_bottom(image25, 5); vbox4 = gtk_vbox_new (FALSE, 0); gtk_widget_show (vbox4); gtk_box_pack_start (GTK_BOX (hbox30), vbox4, TRUE, TRUE, 0); labelSaveDialog = gtk_label_new (_("Manage configuration files")); gtk_widget_show (labelSaveDialog); gtk_box_pack_start (GTK_BOX (vbox4), labelSaveDialog, FALSE, FALSE, 1); gtk_label_set_use_markup (GTK_LABEL (labelSaveDialog), TRUE); notebookSave = gtk_notebook_new (); gtk_widget_show (notebookSave); gtk_box_pack_start (GTK_BOX (vbox4), notebookSave, TRUE, TRUE, 5); gtk_widget_set_size_request (notebookSave, 600, -1); vbox14 = gtk_vbox_new (FALSE, 0); gtk_widget_show (vbox14); gtk_container_add (GTK_CONTAINER (notebookSave), vbox14); gtk_container_set_border_width (GTK_CONTAINER (vbox14), 2); notebookResources = gtk_notebook_new (); gtk_widget_show (notebookResources); gtk_box_pack_start (GTK_BOX (vbox14), notebookResources, TRUE, TRUE, 0); gtk_notebook_set_tab_pos (GTK_NOTEBOOK (notebookResources), GTK_POS_LEFT); vbox15 = gtk_vbox_new (FALSE, 0); gtk_widget_set_margin_top(vbox15, 15); gtk_widget_show (vbox15); gtk_container_add (GTK_CONTAINER (notebookResources), vbox15); label75 = gtk_label_new (_("Load from file")); gtk_widget_show (label75); gtk_box_pack_start (GTK_BOX (vbox15), label75, FALSE, FALSE, 0); gtk_label_set_use_markup (GTK_LABEL (label75), TRUE); gtk_label_set_xalign(GTK_LABEL(label75), 0); gtk_widget_set_margin_top(label75, 10); gtk_widget_set_margin_start(label75, 25); filechooserwidgetResources = gtk_file_chooser_widget_new (GTK_FILE_CHOOSER_ACTION_OPEN); gtk_widget_show (filechooserwidgetResources); gtk_box_pack_start (GTK_BOX (vbox15), filechooserwidgetResources, TRUE, TRUE, 0); gtk_widget_set_size_request (filechooserwidgetResources, -1, 250); buttonLoadResources = gtk_button_new_from_icon_name("document-open", GTK_ICON_SIZE_BUTTON); gtk_widget_show (buttonLoadResources); gtk_box_pack_start (GTK_BOX (vbox15), buttonLoadResources, FALSE, FALSE, 0); gtk_widget_set_sensitive (buttonLoadResources, FALSE); gtk_widget_set_can_default (buttonLoadResources, TRUE); image48 = gtk_image_new_from_icon_name("document-open", GTK_ICON_SIZE_LARGE_TOOLBAR); gtk_widget_show (image48); gtk_notebook_set_tab_label (GTK_NOTEBOOK (notebookResources), gtk_notebook_get_nth_page (GTK_NOTEBOOK (notebookResources), 0), image48); vbox16 = gtk_vbox_new (FALSE, 0); gtk_widget_set_margin_top(vbox16, 15); gtk_widget_show (vbox16); gtk_container_add (GTK_CONTAINER (notebookResources), vbox16); label76 = gtk_label_new (_("Save to file")); gtk_widget_show (label76); gtk_box_pack_start (GTK_BOX (vbox16), label76, FALSE, FALSE, 0); gtk_label_set_use_markup (GTK_LABEL (label76), TRUE); gtk_label_set_xalign(GTK_LABEL(label76), 0.); gtk_widget_set_margin_top(label76, 10); gtk_widget_set_margin_start(label76, 25); hbox65 = gtk_hbox_new (FALSE, 0); gtk_widget_show (hbox65); gtk_box_pack_start (GTK_BOX (vbox16), hbox65, FALSE, FALSE, 0); comboboxentryResources = gtk_combo_box_text_new_with_entry(); gtk_widget_show (comboboxentryResources); gtk_box_pack_start (GTK_BOX (hbox65), comboboxentryResources, TRUE, TRUE, 0); buttonSaveResources = gtk_button_new_from_icon_name("document-save", GTK_ICON_SIZE_BUTTON); gtk_widget_show (buttonSaveResources); gtk_box_pack_start (GTK_BOX (hbox65), buttonSaveResources, FALSE, FALSE, 5); gtk_widget_set_can_default (buttonSaveResources, TRUE); checkLimitOnVisuData = gtk_check_button_new_with_mnemonic (_("Export resources related to rendered file only")); gtk_widget_show (checkLimitOnVisuData); gtk_box_pack_start (GTK_BOX (vbox16), checkLimitOnVisuData, FALSE, FALSE, 0); gtk_container_set_border_width (GTK_CONTAINER (checkLimitOnVisuData), 5); gtk_widget_set_sensitive (checkLimitOnVisuData, FALSE); image49 = gtk_image_new_from_icon_name("document-save", GTK_ICON_SIZE_LARGE_TOOLBAR); gtk_widget_show (image49); gtk_notebook_set_tab_label (GTK_NOTEBOOK (notebookResources), gtk_notebook_get_nth_page (GTK_NOTEBOOK (notebookResources), 1), image49); labelTipsResources = gtk_label_new (""); gtk_widget_show (labelTipsResources); gtk_box_pack_start (GTK_BOX (vbox14), labelTipsResources, FALSE, FALSE, 0); gtk_widget_set_can_focus (labelTipsResources, TRUE); gtk_label_set_use_markup (GTK_LABEL (labelTipsResources), TRUE); gtk_label_set_justify (GTK_LABEL (labelTipsResources), GTK_JUSTIFY_FILL); gtk_label_set_selectable (GTK_LABEL (labelTipsResources), TRUE); gtk_label_set_xalign(GTK_LABEL(labelTipsResources), 0.); gtk_widget_set_margin_top(labelTipsResources, 10); hbox55 = gtk_hbox_new (FALSE, 0); gtk_widget_show (hbox55); gtk_box_pack_end (GTK_BOX (vbox14), hbox55, FALSE, FALSE, 0); imageWarningResources = gtk_image_new_from_icon_name ("gtk-dialog-warning", GTK_ICON_SIZE_MENU); gtk_widget_show (imageWarningResources); gtk_box_pack_start (GTK_BOX (hbox55), imageWarningResources, FALSE, FALSE, 0); statusbarResources = gtk_statusbar_new (); gtk_widget_show (statusbarResources); gtk_box_pack_start (GTK_BOX (hbox55), statusbarResources, TRUE, TRUE, 0); #if GTK_MAJOR_VERSION < 3 && GTK_MINOR_VERSION < 24 gtk_statusbar_set_has_resize_grip (GTK_STATUSBAR (statusbarResources), FALSE); #endif labelResources = gtk_label_new (_("Resources (values related to rendering aspects)")); gtk_widget_show (labelResources); gtk_notebook_set_tab_label (GTK_NOTEBOOK (notebookSave), gtk_notebook_get_nth_page (GTK_NOTEBOOK (notebookSave), 0), labelResources); gtk_label_set_use_markup (GTK_LABEL (labelResources), TRUE); vbox18 = gtk_vbox_new (FALSE, 0); gtk_widget_show (vbox18); gtk_container_add (GTK_CONTAINER (notebookSave), vbox18); gtk_container_set_border_width (GTK_CONTAINER (vbox18), 2); hbox54 = gtk_hbox_new (FALSE, 0); gtk_widget_show (hbox54); gtk_box_pack_start (GTK_BOX (vbox18), hbox54, FALSE, FALSE, 3); image42 = gtk_image_new_from_icon_name("document-save", GTK_ICON_SIZE_LARGE_TOOLBAR); gtk_widget_show (image42); gtk_box_pack_start (GTK_BOX (hbox54), image42, FALSE, FALSE, 0); label83 = gtk_label_new (_("Save to file")); gtk_widget_show (label83); gtk_box_pack_start (GTK_BOX (hbox54), label83, FALSE, FALSE, 0); gtk_label_set_use_markup (GTK_LABEL (label83), TRUE); gtk_widget_set_margin_top(label83, 10); gtk_widget_set_margin_start(label83, 25); hbox66 = gtk_hbox_new (FALSE, 0); gtk_widget_show (hbox66); gtk_box_pack_start (GTK_BOX (vbox18), hbox66, FALSE, FALSE, 0); comboboxentryParameters = gtk_combo_box_text_new_with_entry(); gtk_widget_set_margin_top(comboboxentryParameters, 15); gtk_widget_show (comboboxentryParameters); gtk_box_pack_start (GTK_BOX (hbox66), comboboxentryParameters, TRUE, TRUE, 0); buttonSaveParameters = gtk_button_new_from_icon_name("document-save", GTK_ICON_SIZE_BUTTON); gtk_widget_show (buttonSaveParameters); gtk_box_pack_start (GTK_BOX (hbox66), buttonSaveParameters, FALSE, FALSE, 5); gtk_widget_set_can_default(buttonSaveParameters, TRUE); hbox56 = gtk_hbox_new (FALSE, 0); gtk_widget_show (hbox56); gtk_box_pack_end (GTK_BOX (vbox18), hbox56, FALSE, FALSE, 0); imageWarningParameters = gtk_image_new_from_icon_name ("gtk-dialog-warning", GTK_ICON_SIZE_MENU); gtk_widget_show (imageWarningParameters); gtk_box_pack_start (GTK_BOX (hbox56), imageWarningParameters, FALSE, FALSE, 0); statusbarParameters = gtk_statusbar_new (); gtk_widget_show (statusbarParameters); gtk_box_pack_start (GTK_BOX (hbox56), statusbarParameters, TRUE, TRUE, 0); #if GTK_MAJOR_VERSION < 3 && GTK_MINOR_VERSION < 24 gtk_statusbar_set_has_resize_grip (GTK_STATUSBAR (statusbarParameters), FALSE); #endif labelParameters = gtk_label_new (_("Parameters (Interface options)")); gtk_widget_show (labelParameters); gtk_notebook_set_tab_label (GTK_NOTEBOOK (notebookSave), gtk_notebook_get_nth_page (GTK_NOTEBOOK (notebookSave), 1), labelParameters); gtk_label_set_use_markup (GTK_LABEL (labelParameters), TRUE); frame6 = gtk_frame_new (NULL); gtk_widget_show (frame6); gtk_box_pack_end (GTK_BOX (vbox4), frame6, FALSE, FALSE, 0); vbox17 = gtk_vbox_new (FALSE, 0); gtk_widget_show (vbox17); gtk_container_add (GTK_CONTAINER (frame6), vbox17); labelHelp = gtk_label_new (_("When saving, if you just specify a directory 'dir/', it will be save to 'dir/v_sim.[res][par]' by default, ortherwise speficy a full path.")); gtk_widget_show (labelHelp); gtk_box_pack_start (GTK_BOX (vbox17), labelHelp, FALSE, FALSE, 0); gtk_label_set_use_markup (GTK_LABEL (labelHelp), TRUE); gtk_label_set_justify (GTK_LABEL (labelHelp), GTK_JUSTIFY_FILL); gtk_label_set_line_wrap (GTK_LABEL (labelHelp), TRUE); gtk_label_set_xalign(GTK_LABEL(labelHelp), 0); gtk_widget_set_margin_start(labelHelp, 5); gtk_widget_set_margin_top(labelHelp, 5); labelHelpTips = gtk_label_new (_("Tips: think to create a $XDG_CONFIG_HOME/v_sim directory and put your resource and parameter files in it. It is scanned at startup.")); gtk_widget_show (labelHelpTips); gtk_box_pack_start (GTK_BOX (vbox17), labelHelpTips, FALSE, FALSE, 0); gtk_widget_set_can_focus(labelHelpTips, TRUE); gtk_label_set_use_markup (GTK_LABEL (labelHelpTips), TRUE); gtk_label_set_line_wrap (GTK_LABEL (labelHelpTips), TRUE); gtk_label_set_selectable (GTK_LABEL (labelHelpTips), TRUE); gtk_label_set_xalign(GTK_LABEL(labelHelpTips), 0); gtk_widget_set_margin_start(labelHelpTips, 5); gtk_widget_set_margin_top(labelHelpTips, 5); hbox51 = gtk_hbox_new (FALSE, 0); gtk_widget_show (hbox51); gtk_frame_set_label_widget (GTK_FRAME (frame6), hbox51); image40 = gtk_image_new_from_icon_name("help-browser", GTK_ICON_SIZE_SMALL_TOOLBAR); gtk_widget_show (image40); gtk_box_pack_start (GTK_BOX (hbox51), image40, TRUE, TRUE, 0); label80 = gtk_label_new (_("Help")); gtk_widget_show (label80); gtk_box_pack_start (GTK_BOX (hbox51), label80, FALSE, FALSE, 0); closeButtonSave = gtk_button_new_from_icon_name("window-close", GTK_ICON_SIZE_BUTTON); gtk_widget_show (closeButtonSave); gtk_dialog_add_action_widget (GTK_DIALOG (saveDialog), closeButtonSave, GTK_RESPONSE_CLOSE); gtk_widget_set_can_default(closeButtonSave, TRUE); /* Store pointers to all widgets, for use by lookup_widget(). */ GLADE_HOOKUP_OBJECT_NO_REF (saveDialog, saveDialog, "saveDialog"); GLADE_HOOKUP_OBJECT_NO_REF (saveDialog, dialog_vbox1, "dialog_vbox1"); GLADE_HOOKUP_OBJECT (saveDialog, hbox30, "hbox30"); GLADE_HOOKUP_OBJECT (saveDialog, image25, "image25"); GLADE_HOOKUP_OBJECT (saveDialog, vbox4, "vbox4"); GLADE_HOOKUP_OBJECT (saveDialog, labelSaveDialog, "labelSaveDialog"); GLADE_HOOKUP_OBJECT (saveDialog, notebookSave, "notebookSave"); GLADE_HOOKUP_OBJECT (saveDialog, vbox14, "vbox14"); GLADE_HOOKUP_OBJECT (saveDialog, notebookResources, "notebookResources"); GLADE_HOOKUP_OBJECT (saveDialog, vbox15, "vbox15"); GLADE_HOOKUP_OBJECT (saveDialog, label75, "label75"); GLADE_HOOKUP_OBJECT (saveDialog, filechooserwidgetResources, "filechooserwidgetResources"); GLADE_HOOKUP_OBJECT (saveDialog, buttonLoadResources, "buttonLoadResources"); GLADE_HOOKUP_OBJECT (saveDialog, image48, "image48"); GLADE_HOOKUP_OBJECT (saveDialog, vbox16, "vbox16"); GLADE_HOOKUP_OBJECT (saveDialog, label76, "label76"); GLADE_HOOKUP_OBJECT (saveDialog, hbox65, "hbox65"); GLADE_HOOKUP_OBJECT (saveDialog, comboboxentryResources, "comboboxentryResources"); GLADE_HOOKUP_OBJECT (saveDialog, buttonSaveResources, "buttonSaveResources"); GLADE_HOOKUP_OBJECT (saveDialog, checkLimitOnVisuData, "checkLimitOnVisuData"); GLADE_HOOKUP_OBJECT (saveDialog, image49, "image49"); GLADE_HOOKUP_OBJECT (saveDialog, labelTipsResources, "labelTipsResources"); GLADE_HOOKUP_OBJECT (saveDialog, hbox55, "hbox55"); GLADE_HOOKUP_OBJECT (saveDialog, imageWarningResources, "imageWarningResources"); GLADE_HOOKUP_OBJECT (saveDialog, statusbarResources, "statusbarResources"); GLADE_HOOKUP_OBJECT (saveDialog, labelResources, "labelResources"); GLADE_HOOKUP_OBJECT (saveDialog, vbox18, "vbox18"); GLADE_HOOKUP_OBJECT (saveDialog, hbox54, "hbox54"); GLADE_HOOKUP_OBJECT (saveDialog, image42, "image42"); GLADE_HOOKUP_OBJECT (saveDialog, label83, "label83"); GLADE_HOOKUP_OBJECT (saveDialog, hbox66, "hbox66"); GLADE_HOOKUP_OBJECT (saveDialog, comboboxentryParameters, "comboboxentryParameters"); GLADE_HOOKUP_OBJECT (saveDialog, buttonSaveParameters, "buttonSaveParameters"); GLADE_HOOKUP_OBJECT (saveDialog, hbox56, "hbox56"); GLADE_HOOKUP_OBJECT (saveDialog, imageWarningParameters, "imageWarningParameters"); GLADE_HOOKUP_OBJECT (saveDialog, statusbarParameters, "statusbarParameters"); GLADE_HOOKUP_OBJECT (saveDialog, labelParameters, "labelParameters"); GLADE_HOOKUP_OBJECT (saveDialog, frame6, "frame6"); GLADE_HOOKUP_OBJECT (saveDialog, vbox17, "vbox17"); GLADE_HOOKUP_OBJECT (saveDialog, labelHelp, "labelHelp"); GLADE_HOOKUP_OBJECT (saveDialog, labelHelpTips, "labelHelpTips"); GLADE_HOOKUP_OBJECT (saveDialog, hbox51, "hbox51"); GLADE_HOOKUP_OBJECT (saveDialog, image40, "image40"); GLADE_HOOKUP_OBJECT (saveDialog, label80, "label80"); GLADE_HOOKUP_OBJECT (saveDialog, closeButtonSave, "closeButtonSave"); gtk_widget_grab_default (buttonLoadResources); return saveDialog; } GtkWidget* create_observeDialog (void) { GtkWidget *observeDialog; GdkPixbuf *observeDialog_icon_pixbuf; GtkWidget *dialog_vbox3; GtkWidget *hbox20; GtkWidget *image15; GtkWidget *vbox20; GtkWidget *hbox60; GtkWidget *radioObserve; GSList *radioObserve_group = NULL; GtkWidget *hbox21; GtkWidget *image16; GtkWidget *labelObserve; GtkWidget *hboxObserve; GtkWidget *label66; GtkWidget *radioObserveConstrained; GSList *radioObserveConstrained_group = NULL; GtkWidget *radioObserveWalker; GtkWidget *label67; GtkWidget *tableObserve; GtkWidget *labelTranslation; GtkWidget *labelZoom; GtkWidget *spinOmega; GtkWidget *spinPhi; GtkWidget *spinDx; GtkWidget *spinGross; GtkWidget *spinTheta; GtkWidget *label58; GtkWidget *label32; GtkWidget *label33; GtkWidget *label35; GtkWidget *label31; GtkWidget *buttonVisuUiOrientationChooser; GtkWidget *image51; GtkWidget *label34; GtkWidget *label36; GtkWidget *spinDy; GtkWidget *spinPersp; GtkWidget *notebookAction; GtkWidget *vbox7; GtkWidget *hboxPick; GtkWidget *radioPick; GSList *radioPick_group = NULL; GtkWidget *hbox22; GtkWidget *image17; GtkWidget *labelPick; GtkWidget *vpaned1; GtkWidget *vbox26; GtkWidget *scrolledwindow6; GtkWidget *viewportPick; GtkWidget *vbox24; GtkWidget *pickInfo; GtkWidget *pickComment; GtkWidget *hbox57; GtkWidget *checkDrawDistance; GtkWidget *buttonEraseDistances; GtkWidget *image54; GtkWidget *labelMarks; GtkWidget *hboxMarks; GtkWidget *buttonSetMarks; GtkWidget *image56; GtkWidget *buttonEraseMarks; GtkWidget *image55; GtkWidget *vbox25; GtkWidget *label87; GtkWidget *vbox27; GtkWidget *radioMove; GSList *radioMove_group = NULL; GtkWidget *hbox59; GtkWidget *image44; GtkWidget *label111; GtkWidget *vbox21; GtkWidget *hbox72; GtkWidget *label90; GtkWidget *radioMovePick; GSList *radioMovePick_group = NULL; GtkWidget *radioMoveRegion; GtkWidget *labelNMoves; GtkWidget *label136; GtkWidget *tableMovePick; GtkWidget *label138; GtkWidget *label95; GtkWidget *label94; GtkWidget *label93; GtkWidget *label102; GtkWidget *labelOriginalX; GtkWidget *labelOriginalY; GtkWidget *labelOriginalZ; GtkWidget *label125; GtkWidget *hboxAddNode; GtkWidget *label126; GtkWidget *hbox67; GtkWidget *label120; GtkWidget *label121; GtkWidget *labelHorizontalAxe; GtkWidget *label123; GtkWidget *labelVerticalAxe; GtkWidget *label88; GtkWidget *frame2; GtkWidget *labelInfoObservePick; GtkWidget *hbox23; GtkWidget *image18; GtkWidget *label39; GtkWidget *buttonBackToCommandPanel; GtkWidget *hbox41; GtkWidget *image31; GtkWidget *label68; GtkAccelGroup *accel_group; #if GTK_MAJOR_VERSION == 2 && GTK_MINOR_VERSION < 12 GtkTooltips *tooltips; tooltips = gtk_tooltips_new (); #endif accel_group = gtk_accel_group_new (); observeDialog = gtk_dialog_new (); gtk_window_set_title (GTK_WINDOW (observeDialog), _("Pick and observe session")); gtk_window_set_position (GTK_WINDOW (observeDialog), GTK_WIN_POS_CENTER_ON_PARENT); observeDialog_icon_pixbuf = create_pixbuf ("icone-dialog.png"); if (observeDialog_icon_pixbuf) { gtk_window_set_icon (GTK_WINDOW (observeDialog), observeDialog_icon_pixbuf); g_object_unref (observeDialog_icon_pixbuf); } dialog_vbox3 = gtk_dialog_get_content_area(GTK_DIALOG(observeDialog)); gtk_widget_show (dialog_vbox3); hbox20 = gtk_hbox_new (FALSE, 0); gtk_widget_show (hbox20); gtk_box_pack_start (GTK_BOX (dialog_vbox3), hbox20, TRUE, TRUE, 0); image15 = create_pixmap (observeDialog, "observe-bandeau.png"); gtk_widget_show (image15); gtk_widget_set_valign(image15, GTK_ALIGN_END); gtk_box_pack_start (GTK_BOX (hbox20), image15, FALSE, FALSE, 0); /*gtk_widget_set_size_request (image15, -1, 400);*/ vbox20 = gtk_vbox_new (FALSE, 0); gtk_widget_show (vbox20); gtk_box_pack_start (GTK_BOX (hbox20), vbox20, TRUE, TRUE, 0); hbox60 = gtk_hbox_new (FALSE, 0); gtk_widget_show (hbox60); gtk_box_pack_start (GTK_BOX (vbox20), hbox60, FALSE, FALSE, 0); radioObserve = gtk_radio_button_new (NULL); gtk_widget_show (radioObserve); gtk_box_pack_start (GTK_BOX (hbox60), radioObserve, TRUE, TRUE, 0); gtk_widget_add_accelerator (radioObserve, "clicked", accel_group, GDK_KEY_o, (GdkModifierType) GDK_CONTROL_MASK, GTK_ACCEL_VISIBLE); gtk_radio_button_set_group (GTK_RADIO_BUTTON (radioObserve), radioObserve_group); radioObserve_group = gtk_radio_button_get_group (GTK_RADIO_BUTTON (radioObserve)); hbox21 = gtk_hbox_new (FALSE, 2); gtk_widget_show (hbox21); gtk_container_add (GTK_CONTAINER (radioObserve), hbox21); image16 = gtk_image_new_from_icon_name("zoom-fit-best", GTK_ICON_SIZE_BUTTON); gtk_widget_show (image16); gtk_box_pack_start (GTK_BOX (hbox21), image16, FALSE, FALSE, 0); labelObserve = gtk_label_new_with_mnemonic (_("Observe")); gtk_widget_show (labelObserve); gtk_box_pack_start (GTK_BOX (hbox21), labelObserve, FALSE, FALSE, 0); hboxObserve = gtk_hbox_new (FALSE, 0); gtk_widget_show (hboxObserve); gtk_box_pack_start (GTK_BOX (hbox60), hboxObserve, FALSE, FALSE, 0); label66 = gtk_label_new ("("); gtk_widget_show (label66); gtk_box_pack_start (GTK_BOX (hboxObserve), label66, FALSE, FALSE, 0); radioObserveConstrained = gtk_radio_button_new_with_mnemonic (NULL, _("constrained")); gtk_widget_show (radioObserveConstrained); gtk_box_pack_start (GTK_BOX (hboxObserve), radioObserveConstrained, FALSE, FALSE, 0); gtk_tooltips_set_tip (tooltips, radioObserveConstrained, _("Movement are along meridians when the mouse is dragged along y axis and along parallels when the movement is along x axis."), NULL); gtk_radio_button_set_group (GTK_RADIO_BUTTON (radioObserveConstrained), radioObserveConstrained_group); radioObserveConstrained_group = gtk_radio_button_get_group (GTK_RADIO_BUTTON (radioObserveConstrained)); radioObserveWalker = gtk_radio_button_new_with_mnemonic (NULL, _("walker")); gtk_widget_show (radioObserveWalker); gtk_box_pack_start (GTK_BOX (hboxObserve), radioObserveWalker, FALSE, FALSE, 0); gtk_tooltips_set_tip (tooltips, radioObserveWalker, _("Movements are those of a walking ant on a sphere, when mouse move along y axis, the ant goes strait on, when mouse is dragged along x axis, the ant translates on its right or on its left."), NULL); gtk_radio_button_set_group (GTK_RADIO_BUTTON (radioObserveWalker), radioObserveConstrained_group); radioObserveConstrained_group = gtk_radio_button_get_group (GTK_RADIO_BUTTON (radioObserveWalker)); label67 = gtk_label_new (")"); gtk_widget_show (label67); gtk_box_pack_start (GTK_BOX (hboxObserve), label67, FALSE, FALSE, 0); tableObserve = gtk_grid_new(); tool_grid_resize(tableObserve, 3, 7) gtk_widget_show (tableObserve); gtk_box_pack_start (GTK_BOX (vbox20), tableObserve, FALSE, FALSE, 0); gtk_container_set_border_width (GTK_CONTAINER (tableObserve), 3); gtk_grid_set_column_spacing(GTK_GRID(tableObserve), 2); labelTranslation = gtk_label_new (_("Translations")); gtk_widget_show (labelTranslation); gtk_grid_attach (GTK_GRID (tableObserve), labelTranslation, 0, 1, 2, 1); gtk_label_set_xalign(GTK_LABEL(labelTranslation), 1); gtk_widget_set_hexpand(labelTranslation, TRUE); labelZoom = gtk_label_new (_("Scale")); gtk_widget_show (labelZoom); gtk_grid_attach (GTK_GRID (tableObserve), labelZoom, 0, 2, 2, 1); gtk_label_set_xalign(GTK_LABEL(labelZoom), 1); gtk_widget_set_hexpand(labelZoom, TRUE); spinOmega = gtk_spin_button_new_with_range(-360, 360, 5); gtk_spin_button_set_value(GTK_SPIN_BUTTON(spinOmega), 0); gtk_spin_button_set_digits(GTK_SPIN_BUTTON(spinOmega), 1); gtk_entry_set_width_chars(GTK_ENTRY(spinOmega), 6); gtk_widget_show (spinOmega); gtk_grid_attach (GTK_GRID (tableObserve), spinOmega, 5, 0, 1, 1); gtk_spin_button_set_numeric (GTK_SPIN_BUTTON (spinOmega), TRUE); spinPhi = gtk_spin_button_new_with_range(-360, 360, 5); gtk_spin_button_set_value(GTK_SPIN_BUTTON(spinPhi), -50); gtk_spin_button_set_digits(GTK_SPIN_BUTTON(spinPhi), 1); gtk_entry_set_width_chars(GTK_ENTRY(spinPhi), 6); gtk_widget_show (spinPhi); gtk_grid_attach (GTK_GRID (tableObserve), spinPhi, 3, 0, 1, 1); gtk_spin_button_set_numeric (GTK_SPIN_BUTTON (spinPhi), TRUE); spinDx = gtk_spin_button_new_with_range(-3, 3, 0.05); gtk_spin_button_set_value(GTK_SPIN_BUTTON(spinDx), 0.5); gtk_spin_button_set_digits(GTK_SPIN_BUTTON(spinDx), 3); gtk_entry_set_width_chars(GTK_ENTRY(spinDx), 6); gtk_widget_show (spinDx); gtk_grid_attach (GTK_GRID (tableObserve), spinDx, 3, 1, 1, 1); gtk_spin_button_set_numeric (GTK_SPIN_BUTTON (spinDx), TRUE); spinGross = gtk_spin_button_new_with_range(0.02, 999, 0.1); gtk_spin_button_set_value(GTK_SPIN_BUTTON(spinGross), 1); gtk_spin_button_set_digits(GTK_SPIN_BUTTON(spinGross), 3); gtk_entry_set_width_chars(GTK_ENTRY(spinGross), 6); gtk_widget_show (spinGross); gtk_grid_attach (GTK_GRID (tableObserve), spinGross, 3, 2, 1, 1); gtk_spin_button_set_numeric (GTK_SPIN_BUTTON (spinGross), TRUE); spinTheta = gtk_spin_button_new_with_range(-360, 360, 5); gtk_spin_button_set_value(GTK_SPIN_BUTTON(spinTheta), 40); gtk_spin_button_set_digits(GTK_SPIN_BUTTON(spinTheta), 1); gtk_entry_set_width_chars(GTK_ENTRY(spinTheta), 6); gtk_widget_show (spinTheta); gtk_grid_attach (GTK_GRID (tableObserve), spinTheta, 1, 0, 1, 1); gtk_spin_button_set_numeric (GTK_SPIN_BUTTON (spinTheta), TRUE); label58 = gtk_label_new (_("omega:")); gtk_widget_show (label58); gtk_grid_attach (GTK_GRID (tableObserve), label58, 4, 0, 1, 1); gtk_label_set_xalign(GTK_LABEL(label58), 1); gtk_widget_set_hexpand(label58, TRUE); label32 = gtk_label_new (_("phi:")); gtk_widget_show (label32); gtk_grid_attach (GTK_GRID (tableObserve), label32, 2, 0, 1, 1); gtk_label_set_xalign(GTK_LABEL(label32), 1); gtk_widget_set_hexpand(label32, TRUE); label33 = gtk_label_new (_("dx:")); gtk_widget_show (label33); gtk_grid_attach (GTK_GRID (tableObserve), label33, 2, 1, 1, 1); gtk_label_set_xalign(GTK_LABEL(label33), 1); gtk_widget_set_hexpand(label33, TRUE); label35 = gtk_label_new (_("zoom:")); gtk_widget_show (label35); gtk_grid_attach (GTK_GRID (tableObserve), label35, 2, 2, 1, 1); gtk_label_set_xalign(GTK_LABEL(label35), 1); gtk_widget_set_hexpand(label35, TRUE); label31 = gtk_label_new (_("theta:")); gtk_widget_show (label31); gtk_grid_attach (GTK_GRID (tableObserve), label31, 0, 0, 1, 1); gtk_label_set_xalign(GTK_LABEL(label31), 1); gtk_widget_set_hexpand(label31, TRUE); buttonVisuUiOrientationChooser = gtk_button_new (); gtk_widget_show (buttonVisuUiOrientationChooser); gtk_grid_attach (GTK_GRID (tableObserve), buttonVisuUiOrientationChooser, 6, 0, 1, 1); image51 = create_pixmap (observeDialog, "axes-button.png"); gtk_widget_show (image51); gtk_container_add (GTK_CONTAINER (buttonVisuUiOrientationChooser), image51); label34 = gtk_label_new (_("dy:")); gtk_widget_show (label34); gtk_grid_attach (GTK_GRID (tableObserve), label34, 4, 1, 1, 1); gtk_label_set_xalign(GTK_LABEL(label34), 1); gtk_widget_set_hexpand(label34, TRUE); label36 = gtk_label_new (_("persp.:")); gtk_widget_show (label36); gtk_grid_attach (GTK_GRID (tableObserve), label36, 4, 2, 1, 1); gtk_label_set_xalign(GTK_LABEL(label36), 1); gtk_widget_set_hexpand(label36, TRUE); spinDy = gtk_spin_button_new_with_range(-3, 3, 0.05); gtk_spin_button_set_value(GTK_SPIN_BUTTON(spinDy), 0.5); gtk_spin_button_set_digits(GTK_SPIN_BUTTON(spinDy), 3); gtk_entry_set_width_chars(GTK_ENTRY(spinDy), 6); gtk_widget_show (spinDy); gtk_grid_attach (GTK_GRID (tableObserve), spinDy, 5, 1, 1, 1); gtk_spin_button_set_numeric (GTK_SPIN_BUTTON (spinDy), TRUE); spinPersp = gtk_spin_button_new_with_range(1.1, 100, 0.5); gtk_spin_button_set_value(GTK_SPIN_BUTTON(spinPersp), 5); gtk_spin_button_set_digits(GTK_SPIN_BUTTON(spinPersp), 1); gtk_entry_set_width_chars(GTK_ENTRY(spinPersp), 6); gtk_widget_show (spinPersp); gtk_grid_attach (GTK_GRID (tableObserve), spinPersp, 5, 2, 1, 1); gtk_spin_button_set_numeric (GTK_SPIN_BUTTON (spinPersp), TRUE); notebookAction = gtk_notebook_new (); gtk_widget_show (notebookAction); gtk_box_pack_start (GTK_BOX (vbox20), notebookAction, TRUE, TRUE, 0); vbox7 = gtk_vbox_new (FALSE, 0); gtk_widget_show (vbox7); gtk_container_add (GTK_CONTAINER (notebookAction), vbox7); hboxPick = gtk_hbox_new (FALSE, 0); gtk_widget_show (hboxPick); gtk_box_pack_start (GTK_BOX (vbox7), hboxPick, FALSE, FALSE, 0); radioPick = gtk_radio_button_new (NULL); gtk_widget_show (radioPick); gtk_box_pack_start (GTK_BOX (hboxPick), radioPick, TRUE, TRUE, 0); gtk_widget_add_accelerator (radioPick, "clicked", accel_group, GDK_KEY_p, (GdkModifierType) GDK_CONTROL_MASK, GTK_ACCEL_VISIBLE); gtk_radio_button_set_group (GTK_RADIO_BUTTON (radioPick), radioPick_group); radioPick_group = gtk_radio_button_get_group (GTK_RADIO_BUTTON (radioPick)); hbox22 = gtk_hbox_new (FALSE, 2); gtk_widget_show (hbox22); gtk_container_add (GTK_CONTAINER (radioPick), hbox22); image17 = gtk_image_new_from_icon_name("applications-graphics", GTK_ICON_SIZE_BUTTON); gtk_widget_show (image17); gtk_box_pack_start (GTK_BOX (hbox22), image17, FALSE, FALSE, 0); labelPick = gtk_label_new_with_mnemonic (_("Pick")); gtk_widget_show (labelPick); gtk_box_pack_start (GTK_BOX (hbox22), labelPick, FALSE, FALSE, 0); vpaned1 = gtk_vpaned_new (); gtk_widget_set_margin_top(vpaned1, 10); gtk_widget_set_margin_bottom(vpaned1, 10); gtk_widget_show (vpaned1); gtk_box_pack_start (GTK_BOX (vbox7), vpaned1, TRUE, TRUE, 0); vbox26 = gtk_vbox_new (FALSE, 0); gtk_widget_show (vbox26); gtk_paned_pack1 (GTK_PANED (vpaned1), vbox26, TRUE, FALSE); scrolledwindow6 = gtk_scrolled_window_new (NULL, NULL); gtk_widget_show (scrolledwindow6); gtk_box_pack_start (GTK_BOX (vbox26), scrolledwindow6, TRUE, TRUE, 0); gtk_widget_set_size_request (scrolledwindow6, -1, 100); gtk_scrolled_window_set_policy (GTK_SCROLLED_WINDOW (scrolledwindow6), GTK_POLICY_NEVER, GTK_POLICY_AUTOMATIC); viewportPick = gtk_viewport_new (NULL, NULL); gtk_widget_show (viewportPick); gtk_container_add (GTK_CONTAINER (scrolledwindow6), viewportPick); vbox24 = gtk_vbox_new (FALSE, 0); gtk_widget_show (vbox24); gtk_container_add (GTK_CONTAINER (viewportPick), vbox24); pickInfo = gtk_label_new (""); gtk_widget_show (pickInfo); gtk_box_pack_start (GTK_BOX (vbox24), pickInfo, FALSE, FALSE, 0); gtk_widget_set_can_focus (pickInfo, TRUE); gtk_label_set_line_wrap (GTK_LABEL (pickInfo), TRUE); gtk_label_set_selectable (GTK_LABEL (pickInfo), TRUE); gtk_label_set_xalign(GTK_LABEL(pickInfo), 0); gtk_widget_set_margin_start(pickInfo, 15); gtk_widget_set_margin_top(pickInfo, 0); pickComment = gtk_label_new (""); gtk_widget_show (pickComment); gtk_box_pack_start (GTK_BOX (vbox24), pickComment, FALSE, FALSE, 0); gtk_label_set_justify (GTK_LABEL (pickComment), GTK_JUSTIFY_CENTER); gtk_label_set_line_wrap (GTK_LABEL (pickComment), TRUE); hbox57 = gtk_hbox_new (FALSE, 0); gtk_widget_show (hbox57); gtk_box_pack_end (GTK_BOX (vbox26), hbox57, FALSE, FALSE, 0); checkDrawDistance = gtk_check_button_new_with_mnemonic (_("Persistent measures")); gtk_widget_show (checkDrawDistance); gtk_box_pack_start (GTK_BOX (hbox57), checkDrawDistance, FALSE, FALSE, 0); gtk_toggle_button_set_active (GTK_TOGGLE_BUTTON (checkDrawDistance), TRUE); buttonEraseDistances = gtk_button_new (); gtk_widget_show (buttonEraseDistances); gtk_box_pack_start (GTK_BOX (hbox57), buttonEraseDistances, FALSE, FALSE, 0); gtk_tooltips_set_tip (tooltips, buttonEraseDistances, _("Remove all drawn measurements."), NULL); gtk_widget_set_focus_on_click(buttonEraseDistances, FALSE); image54 = gtk_image_new_from_icon_name("edit-clear", GTK_ICON_SIZE_MENU); gtk_widget_show (image54); gtk_container_add (GTK_CONTAINER (buttonEraseDistances), image54); labelMarks = gtk_label_new (_("Highlights (none):")); gtk_widget_show (labelMarks); gtk_box_pack_start (GTK_BOX (hbox57), labelMarks, TRUE, TRUE, 0); gtk_label_set_use_markup (GTK_LABEL (labelMarks), TRUE); gtk_label_set_xalign(GTK_LABEL(labelMarks), 1); gtk_widget_set_margin_start(labelMarks, 5); gtk_widget_set_margin_top(labelMarks, 0); hboxMarks = gtk_hbox_new (FALSE, 0); gtk_widget_show (hboxMarks); gtk_box_pack_start (GTK_BOX (hbox57), hboxMarks, FALSE, FALSE, 0); buttonSetMarks = gtk_button_new (); gtk_widget_show (buttonSetMarks); gtk_box_pack_start (GTK_BOX (hboxMarks), buttonSetMarks, FALSE, FALSE, 0); gtk_tooltips_set_tip (tooltips, buttonSetMarks, _("Add highlighted nodes to the list below."), NULL); image56 = gtk_image_new_from_icon_name("go-down", GTK_ICON_SIZE_MENU); gtk_widget_show (image56); gtk_container_add (GTK_CONTAINER (buttonSetMarks), image56); buttonEraseMarks = gtk_button_new (); gtk_widget_show (buttonEraseMarks); gtk_box_pack_end (GTK_BOX (hboxMarks), buttonEraseMarks, FALSE, FALSE, 0); gtk_tooltips_set_tip (tooltips, buttonEraseMarks, _("Remove all highlight marks."), NULL); image55 = gtk_image_new_from_icon_name("edit-clear", GTK_ICON_SIZE_MENU); gtk_widget_show (image55); gtk_container_add (GTK_CONTAINER (buttonEraseMarks), image55); vbox25 = gtk_vbox_new (FALSE, 0); gtk_widget_show (vbox25); gtk_paned_pack2 (GTK_PANED (vpaned1), vbox25, TRUE, FALSE); gtk_widget_set_size_request (vbox25, -1, 152); label87 = gtk_label_new (_("Pick")); gtk_widget_show (label87); gtk_notebook_set_tab_label (GTK_NOTEBOOK (notebookAction), gtk_notebook_get_nth_page (GTK_NOTEBOOK (notebookAction), 0), label87); vbox27 = gtk_vbox_new (FALSE, 0); gtk_widget_show (vbox27); gtk_container_add (GTK_CONTAINER (notebookAction), vbox27); radioMove = gtk_radio_button_new (NULL); gtk_widget_show (radioMove); gtk_box_pack_start (GTK_BOX (vbox27), radioMove, FALSE, FALSE, 0); gtk_radio_button_set_group (GTK_RADIO_BUTTON (radioMove), radioMove_group); radioMove_group = gtk_radio_button_get_group (GTK_RADIO_BUTTON (radioMove)); hbox59 = gtk_hbox_new (FALSE, 2); gtk_widget_show (hbox59); gtk_container_add (GTK_CONTAINER (radioMove), hbox59); image44 = gtk_image_new_from_icon_name("go-jump", GTK_ICON_SIZE_BUTTON); gtk_widget_show (image44); gtk_box_pack_start (GTK_BOX (hbox59), image44, FALSE, FALSE, 0); label111 = gtk_label_new_with_mnemonic (_("Modify nodes (position, numbers...)")); gtk_widget_show (label111); gtk_box_pack_start (GTK_BOX (hbox59), label111, FALSE, FALSE, 0); vbox21 = gtk_vbox_new (FALSE, 0); gtk_widget_set_margin_top(vbox21, 10); gtk_widget_set_margin_bottom(vbox21, 10); gtk_widget_show (vbox21); gtk_box_pack_start (GTK_BOX (vbox27), vbox21, TRUE, TRUE, 0); hbox72 = gtk_hbox_new (FALSE, 0); gtk_widget_show (hbox72); gtk_box_pack_start (GTK_BOX (vbox21), hbox72, FALSE, FALSE, 0); label90 = gtk_label_new (_("Move or delete:")); gtk_widget_show (label90); gtk_box_pack_start (GTK_BOX (hbox72), label90, TRUE, TRUE, 0); gtk_label_set_use_markup (GTK_LABEL (label90), TRUE); gtk_label_set_xalign(GTK_LABEL(label90), 0); radioMovePick = gtk_radio_button_new_with_mnemonic (NULL, _("picked _node")); gtk_widget_show (radioMovePick); gtk_box_pack_start (GTK_BOX (hbox72), radioMovePick, FALSE, FALSE, 0); gtk_radio_button_set_group (GTK_RADIO_BUTTON (radioMovePick), radioMovePick_group); radioMovePick_group = gtk_radio_button_get_group (GTK_RADIO_BUTTON (radioMovePick)); radioMoveRegion = gtk_radio_button_new_with_mnemonic (NULL, _("_selected nodes")); gtk_widget_show (radioMoveRegion); gtk_box_pack_start (GTK_BOX (hbox72), radioMoveRegion, FALSE, FALSE, 0); gtk_radio_button_set_group (GTK_RADIO_BUTTON (radioMoveRegion), radioMovePick_group); radioMovePick_group = gtk_radio_button_get_group (GTK_RADIO_BUTTON (radioMoveRegion)); labelNMoves = gtk_label_new ("nb"); gtk_widget_show (labelNMoves); gtk_box_pack_start (GTK_BOX (hbox72), labelNMoves, FALSE, FALSE, 0); gtk_label_set_use_markup (GTK_LABEL (labelNMoves), TRUE); gtk_label_set_xalign(GTK_LABEL(labelNMoves), 1); label136 = gtk_label_new (_("(selected nodes are listed in the pick tab)")); gtk_widget_show (label136); gtk_box_pack_start (GTK_BOX (vbox21), label136, FALSE, FALSE, 0); gtk_label_set_use_markup (GTK_LABEL (label136), TRUE); gtk_label_set_xalign(GTK_LABEL(label136), 1); tableMovePick = gtk_grid_new(); tool_grid_resize(tableMovePick, 3, 8); gtk_widget_show (tableMovePick); gtk_box_pack_start (GTK_BOX (vbox21), tableMovePick, FALSE, FALSE, 0); gtk_grid_set_column_spacing(GTK_GRID(tableMovePick), 5); label138 = gtk_label_new (_("Specific moving axis:")); gtk_widget_show (label138); gtk_grid_attach (GTK_GRID (tableMovePick), label138, 0, 1, 1, 1); gtk_label_set_use_markup (GTK_LABEL (label138), TRUE); gtk_label_set_xalign(GTK_LABEL(label138), 1); gtk_widget_set_hexpand(label138, TRUE); gtk_widget_set_margin_start(label138, 15); gtk_widget_set_margin_top(label138, 0); label95 = gtk_label_new ("z"); gtk_widget_show (label95); gtk_grid_attach (GTK_GRID (tableMovePick), label95, 5, 0, 2, 1); gtk_label_set_use_markup (GTK_LABEL (label95), TRUE); gtk_label_set_xalign(GTK_LABEL(label95), 0.5); gtk_widget_set_margin_start(label95, 0); gtk_widget_set_margin_top(label95, 2); label94 = gtk_label_new ("y"); gtk_widget_show (label94); gtk_grid_attach (GTK_GRID (tableMovePick), label94, 3, 0, 2, 1); gtk_label_set_use_markup (GTK_LABEL (label94), TRUE); gtk_label_set_xalign(GTK_LABEL(label94), 0.5); gtk_widget_set_margin_start(label94, 0); gtk_widget_set_margin_top(label94, 2); label93 = gtk_label_new ("x"); gtk_widget_show (label93); gtk_grid_attach (GTK_GRID (tableMovePick), label93, 1, 0, 2, 1); gtk_label_set_use_markup (GTK_LABEL (label93), TRUE); gtk_label_set_xalign(GTK_LABEL(label93), 0.5); gtk_widget_set_margin_start(label93, 0); gtk_widget_set_margin_top(label93, 2); label102 = gtk_label_new (_("Current pos./trans.:")); gtk_widget_show (label102); gtk_grid_attach (GTK_GRID (tableMovePick), label102, 0, 2, 1, 1); gtk_label_set_xalign(GTK_LABEL(label102), 1); gtk_widget_set_hexpand(label102, TRUE); gtk_widget_set_margin_start(label102, 15); gtk_widget_set_margin_top(label102, 0); labelOriginalX = gtk_label_new (""); gtk_widget_show (labelOriginalX); gtk_grid_attach (GTK_GRID (tableMovePick), labelOriginalX, 2, 2, 1, 1); gtk_widget_set_size_request (labelOriginalX, 35, -1); gtk_label_set_use_markup (GTK_LABEL (labelOriginalX), TRUE); gtk_label_set_xalign(GTK_LABEL(labelOriginalX), 0); labelOriginalY = gtk_label_new (""); gtk_widget_show (labelOriginalY); gtk_grid_attach (GTK_GRID (tableMovePick), labelOriginalY, 4, 2, 1, 1); gtk_widget_set_size_request (labelOriginalY, 35, -1); gtk_label_set_use_markup (GTK_LABEL (labelOriginalY), TRUE); gtk_label_set_xalign(GTK_LABEL(labelOriginalY), 0); labelOriginalZ = gtk_label_new (""); gtk_widget_show (labelOriginalZ); gtk_grid_attach (GTK_GRID (tableMovePick), labelOriginalZ, 6, 2, 1, 1); gtk_widget_set_size_request (labelOriginalZ, 35, -1); gtk_label_set_use_markup (GTK_LABEL (labelOriginalZ), TRUE); gtk_label_set_xalign(GTK_LABEL(labelOriginalZ), 0); label125 = gtk_label_new (_("Add a new node:")); gtk_widget_show (label125); gtk_box_pack_start (GTK_BOX (vbox21), label125, FALSE, FALSE, 0); gtk_label_set_use_markup (GTK_LABEL (label125), TRUE); gtk_label_set_xalign(GTK_LABEL(label125), 0); gtk_widget_set_margin_start(label125, 0); gtk_widget_set_margin_top(label125, 5); hboxAddNode = gtk_hbox_new (FALSE, 5); gtk_widget_show (hboxAddNode); gtk_box_pack_start (GTK_BOX (vbox21), hboxAddNode, FALSE, FALSE, 0); label126 = gtk_label_new (_("position:")); gtk_widget_show (label126); gtk_box_pack_start (GTK_BOX (hboxAddNode), label126, TRUE, TRUE, 0); gtk_label_set_xalign(GTK_LABEL(label126), 1); gtk_widget_set_margin_start(label126, 15); gtk_widget_set_margin_top(label126, 0); hbox67 = gtk_hbox_new (FALSE, 0); gtk_widget_show (hbox67); gtk_box_pack_end (GTK_BOX (vbox21), hbox67, FALSE, FALSE, 0); label120 = gtk_label_new (_("Screen basis set:")); gtk_widget_show (label120); gtk_box_pack_start (GTK_BOX (hbox67), label120, FALSE, FALSE, 0); gtk_label_set_use_markup (GTK_LABEL (label120), TRUE); gtk_label_set_xalign(GTK_LABEL(label120), 0); label121 = gtk_label_new (_("horiz.")); gtk_widget_show (label121); gtk_box_pack_start (GTK_BOX (hbox67), label121, TRUE, TRUE, 0); gtk_label_set_use_markup (GTK_LABEL (label121), TRUE); gtk_label_set_xalign(GTK_LABEL(label121), 1); gtk_widget_set_margin_start(label121, 5); gtk_widget_set_margin_top(label121, 0); labelHorizontalAxe = gtk_label_new (""); gtk_widget_show (labelHorizontalAxe); gtk_box_pack_start (GTK_BOX (hbox67), labelHorizontalAxe, FALSE, FALSE, 0); label123 = gtk_label_new (_("vert.")); gtk_widget_show (label123); gtk_box_pack_start (GTK_BOX (hbox67), label123, TRUE, TRUE, 0); gtk_label_set_use_markup (GTK_LABEL (label123), TRUE); gtk_label_set_xalign(GTK_LABEL(label123), 1); gtk_widget_set_margin_start(label123, 5); gtk_widget_set_margin_top(label123, 0); labelVerticalAxe = gtk_label_new (""); gtk_widget_show (labelVerticalAxe); gtk_box_pack_start (GTK_BOX (hbox67), labelVerticalAxe, FALSE, FALSE, 0); label88 = gtk_label_new (_("Geometry changes")); gtk_widget_show (label88); gtk_notebook_set_tab_label (GTK_NOTEBOOK (notebookAction), gtk_notebook_get_nth_page (GTK_NOTEBOOK (notebookAction), 1), label88); frame2 = gtk_frame_new (NULL); gtk_widget_show (frame2); gtk_box_pack_end (GTK_BOX (vbox20), frame2, FALSE, FALSE, 0); gtk_container_set_border_width (GTK_CONTAINER (frame2), 3); labelInfoObservePick = gtk_label_new (""); gtk_widget_show (labelInfoObservePick); gtk_container_add (GTK_CONTAINER (frame2), labelInfoObservePick); gtk_label_set_use_markup (GTK_LABEL (labelInfoObservePick), TRUE); gtk_label_set_line_wrap (GTK_LABEL (labelInfoObservePick), TRUE); gtk_label_set_xalign(GTK_LABEL(labelInfoObservePick), 0); gtk_widget_set_margin_start(labelInfoObservePick, 2); gtk_widget_set_margin_top(labelInfoObservePick, 0); hbox23 = gtk_hbox_new (FALSE, 0); gtk_widget_show (hbox23); gtk_frame_set_label_widget (GTK_FRAME (frame2), hbox23); image18 = gtk_image_new_from_icon_name("help-browser", GTK_ICON_SIZE_MENU); gtk_widget_show (image18); gtk_box_pack_start (GTK_BOX (hbox23), image18, TRUE, TRUE, 0); label39 = gtk_label_new (_("Help")); gtk_widget_show (label39); gtk_box_pack_start (GTK_BOX (hbox23), label39, FALSE, FALSE, 0); buttonBackToCommandPanel = gtk_button_new (); gtk_widget_show (buttonBackToCommandPanel); gtk_dialog_add_action_widget (GTK_DIALOG (observeDialog), buttonBackToCommandPanel, GTK_RESPONSE_CLOSE); gtk_widget_set_can_default (buttonBackToCommandPanel, TRUE); hbox41 = gtk_hbox_new (FALSE, 2); gtk_widget_show (hbox41); gtk_container_add (GTK_CONTAINER (buttonBackToCommandPanel), hbox41); image31 = gtk_image_new_from_icon_name("go-previous", GTK_ICON_SIZE_BUTTON); gtk_widget_show (image31); gtk_box_pack_start (GTK_BOX (hbox41), image31, FALSE, FALSE, 0); label68 = gtk_label_new_with_mnemonic (_("Back to command panel")); gtk_widget_show (label68); gtk_box_pack_start (GTK_BOX (hbox41), label68, FALSE, FALSE, 0); /* Store pointers to all widgets, for use by lookup_widget(). */ GLADE_HOOKUP_OBJECT_NO_REF (observeDialog, observeDialog, "observeDialog"); GLADE_HOOKUP_OBJECT_NO_REF (observeDialog, dialog_vbox3, "dialog_vbox3"); GLADE_HOOKUP_OBJECT (observeDialog, hbox20, "hbox20"); GLADE_HOOKUP_OBJECT (observeDialog, image15, "image15"); GLADE_HOOKUP_OBJECT (observeDialog, vbox20, "vbox20"); GLADE_HOOKUP_OBJECT (observeDialog, hbox60, "hbox60"); GLADE_HOOKUP_OBJECT (observeDialog, radioObserve, "radioObserve"); GLADE_HOOKUP_OBJECT (observeDialog, hbox21, "hbox21"); GLADE_HOOKUP_OBJECT (observeDialog, image16, "image16"); GLADE_HOOKUP_OBJECT (observeDialog, labelObserve, "labelObserve"); GLADE_HOOKUP_OBJECT (observeDialog, hboxObserve, "hboxObserve"); GLADE_HOOKUP_OBJECT (observeDialog, label66, "label66"); GLADE_HOOKUP_OBJECT (observeDialog, radioObserveConstrained, "radioObserveConstrained"); GLADE_HOOKUP_OBJECT (observeDialog, radioObserveWalker, "radioObserveWalker"); GLADE_HOOKUP_OBJECT (observeDialog, label67, "label67"); GLADE_HOOKUP_OBJECT (observeDialog, tableObserve, "tableObserve"); GLADE_HOOKUP_OBJECT (observeDialog, labelTranslation, "labelTranslation"); GLADE_HOOKUP_OBJECT (observeDialog, labelZoom, "labelZoom"); GLADE_HOOKUP_OBJECT (observeDialog, spinOmega, "spinOmega"); GLADE_HOOKUP_OBJECT (observeDialog, spinPhi, "spinPhi"); GLADE_HOOKUP_OBJECT (observeDialog, spinDx, "spinDx"); GLADE_HOOKUP_OBJECT (observeDialog, spinGross, "spinGross"); GLADE_HOOKUP_OBJECT (observeDialog, spinTheta, "spinTheta"); GLADE_HOOKUP_OBJECT (observeDialog, label58, "label58"); GLADE_HOOKUP_OBJECT (observeDialog, label32, "label32"); GLADE_HOOKUP_OBJECT (observeDialog, label33, "label33"); GLADE_HOOKUP_OBJECT (observeDialog, label35, "label35"); GLADE_HOOKUP_OBJECT (observeDialog, label31, "label31"); GLADE_HOOKUP_OBJECT (observeDialog, buttonVisuUiOrientationChooser, "buttonVisuUiOrientationChooser"); GLADE_HOOKUP_OBJECT (observeDialog, image51, "image51"); GLADE_HOOKUP_OBJECT (observeDialog, label34, "label34"); GLADE_HOOKUP_OBJECT (observeDialog, label36, "label36"); GLADE_HOOKUP_OBJECT (observeDialog, spinDy, "spinDy"); GLADE_HOOKUP_OBJECT (observeDialog, spinPersp, "spinPersp"); GLADE_HOOKUP_OBJECT (observeDialog, notebookAction, "notebookAction"); GLADE_HOOKUP_OBJECT (observeDialog, vbox7, "vbox7"); GLADE_HOOKUP_OBJECT (observeDialog, hboxPick, "hboxPick"); GLADE_HOOKUP_OBJECT (observeDialog, radioPick, "radioPick"); GLADE_HOOKUP_OBJECT (observeDialog, hbox22, "hbox22"); GLADE_HOOKUP_OBJECT (observeDialog, image17, "image17"); GLADE_HOOKUP_OBJECT (observeDialog, labelPick, "labelPick"); GLADE_HOOKUP_OBJECT (observeDialog, vpaned1, "vpaned1"); GLADE_HOOKUP_OBJECT (observeDialog, vbox26, "vbox26"); GLADE_HOOKUP_OBJECT (observeDialog, scrolledwindow6, "scrolledwindow6"); GLADE_HOOKUP_OBJECT (observeDialog, viewportPick, "viewportPick"); GLADE_HOOKUP_OBJECT (observeDialog, vbox24, "vbox24"); GLADE_HOOKUP_OBJECT (observeDialog, pickInfo, "pickInfo"); GLADE_HOOKUP_OBJECT (observeDialog, pickComment, "pickComment"); GLADE_HOOKUP_OBJECT (observeDialog, hbox57, "hbox57"); GLADE_HOOKUP_OBJECT (observeDialog, checkDrawDistance, "checkDrawDistance"); GLADE_HOOKUP_OBJECT (observeDialog, buttonEraseDistances, "buttonEraseDistances"); GLADE_HOOKUP_OBJECT (observeDialog, image54, "image54"); GLADE_HOOKUP_OBJECT (observeDialog, labelMarks, "labelMarks"); GLADE_HOOKUP_OBJECT (observeDialog, hboxMarks, "hboxMarks"); GLADE_HOOKUP_OBJECT (observeDialog, buttonSetMarks, "buttonSetMarks"); GLADE_HOOKUP_OBJECT (observeDialog, image56, "image56"); GLADE_HOOKUP_OBJECT (observeDialog, buttonEraseMarks, "buttonEraseMarks"); GLADE_HOOKUP_OBJECT (observeDialog, image55, "image55"); GLADE_HOOKUP_OBJECT (observeDialog, vbox25, "vbox25"); GLADE_HOOKUP_OBJECT (observeDialog, label87, "label87"); GLADE_HOOKUP_OBJECT (observeDialog, vbox27, "vbox27"); GLADE_HOOKUP_OBJECT (observeDialog, radioMove, "radioMove"); GLADE_HOOKUP_OBJECT (observeDialog, hbox59, "hbox59"); GLADE_HOOKUP_OBJECT (observeDialog, image44, "image44"); GLADE_HOOKUP_OBJECT (observeDialog, label111, "label111"); GLADE_HOOKUP_OBJECT (observeDialog, vbox21, "vbox21"); GLADE_HOOKUP_OBJECT (observeDialog, hbox72, "hbox72"); GLADE_HOOKUP_OBJECT (observeDialog, label90, "label90"); GLADE_HOOKUP_OBJECT (observeDialog, radioMovePick, "radioMovePick"); GLADE_HOOKUP_OBJECT (observeDialog, radioMoveRegion, "radioMoveRegion"); GLADE_HOOKUP_OBJECT (observeDialog, labelNMoves, "labelNMoves"); GLADE_HOOKUP_OBJECT (observeDialog, label136, "label136"); GLADE_HOOKUP_OBJECT (observeDialog, tableMovePick, "tableMovePick"); GLADE_HOOKUP_OBJECT (observeDialog, label138, "label138"); GLADE_HOOKUP_OBJECT (observeDialog, label95, "label95"); GLADE_HOOKUP_OBJECT (observeDialog, label94, "label94"); GLADE_HOOKUP_OBJECT (observeDialog, label93, "label93"); GLADE_HOOKUP_OBJECT (observeDialog, label102, "label102"); GLADE_HOOKUP_OBJECT (observeDialog, labelOriginalX, "labelOriginalX"); GLADE_HOOKUP_OBJECT (observeDialog, labelOriginalY, "labelOriginalY"); GLADE_HOOKUP_OBJECT (observeDialog, labelOriginalZ, "labelOriginalZ"); GLADE_HOOKUP_OBJECT (observeDialog, label125, "label125"); GLADE_HOOKUP_OBJECT (observeDialog, hboxAddNode, "hboxAddNode"); GLADE_HOOKUP_OBJECT (observeDialog, label126, "label126"); GLADE_HOOKUP_OBJECT (observeDialog, hbox67, "hbox67"); GLADE_HOOKUP_OBJECT (observeDialog, label120, "label120"); GLADE_HOOKUP_OBJECT (observeDialog, label121, "label121"); GLADE_HOOKUP_OBJECT (observeDialog, labelHorizontalAxe, "labelHorizontalAxe"); GLADE_HOOKUP_OBJECT (observeDialog, label123, "label123"); GLADE_HOOKUP_OBJECT (observeDialog, labelVerticalAxe, "labelVerticalAxe"); GLADE_HOOKUP_OBJECT (observeDialog, label88, "label88"); GLADE_HOOKUP_OBJECT (observeDialog, frame2, "frame2"); GLADE_HOOKUP_OBJECT (observeDialog, labelInfoObservePick, "labelInfoObservePick"); GLADE_HOOKUP_OBJECT (observeDialog, hbox23, "hbox23"); GLADE_HOOKUP_OBJECT (observeDialog, image18, "image18"); GLADE_HOOKUP_OBJECT (observeDialog, label39, "label39"); GLADE_HOOKUP_OBJECT (observeDialog, buttonBackToCommandPanel, "buttonBackToCommandPanel"); GLADE_HOOKUP_OBJECT (observeDialog, hbox41, "hbox41"); GLADE_HOOKUP_OBJECT (observeDialog, image31, "image31"); GLADE_HOOKUP_OBJECT (observeDialog, label68, "label68"); gtk_widget_grab_default (buttonBackToCommandPanel); gtk_window_add_accel_group (GTK_WINDOW (observeDialog), accel_group); return observeDialog; } GtkWidget* create_infoDialog (void) { GtkWidget *infoDialog; GdkPixbuf *infoDialog_icon_pixbuf; GtkWidget *dialog_vbox4; GtkWidget *vbox10; GtkWidget *hbox31; GtkWidget *image26; GtkWidget *vbox11; GtkWidget *table4; GtkWidget *label55; GtkWidget *label56; GtkWidget *label57; GtkWidget *labelInfoVersion; GtkWidget *labelInfoReleaseDate; GtkWidget *labelInfoWebSite; GtkWidget *notebookAbout; GtkWidget *scrolledwindow4; GtkWidget *textviewReadme; GtkWidget *label46; GtkWidget *scrolledwindow3; GtkWidget *textviewAuthors; GtkWidget *label47; GtkWidget *scrolledwindow2; GtkWidget *textviewLicence; GtkWidget *labelLicense; GtkWidget *vbox23; GtkWidget *label116; GtkWidget *scrolledwindowPlugins; GtkWidget *label115; GtkWidget *scrolledwindow7; GtkWidget *textviewChangelog; GtkWidget *label137; GtkWidget *closebutton2; infoDialog = gtk_dialog_new (); gtk_window_set_title (GTK_WINDOW (infoDialog), _("About V_Sim")); gtk_window_set_position (GTK_WINDOW (infoDialog), GTK_WIN_POS_CENTER); gtk_window_set_modal (GTK_WINDOW (infoDialog), TRUE); infoDialog_icon_pixbuf = create_pixbuf ("icone-about.png"); if (infoDialog_icon_pixbuf) { gtk_window_set_icon (GTK_WINDOW (infoDialog), infoDialog_icon_pixbuf); g_object_unref (infoDialog_icon_pixbuf); } gtk_window_set_type_hint (GTK_WINDOW (infoDialog), GDK_WINDOW_TYPE_HINT_DIALOG); dialog_vbox4 = gtk_dialog_get_content_area(GTK_DIALOG(infoDialog)); gtk_widget_show (dialog_vbox4); vbox10 = gtk_vbox_new (FALSE, 0); gtk_widget_show (vbox10); gtk_box_pack_start (GTK_BOX (dialog_vbox4), vbox10, TRUE, TRUE, 0); hbox31 = gtk_hbox_new (FALSE, 0); gtk_widget_set_margin_bottom(hbox31, 10); gtk_widget_show (hbox31); gtk_box_pack_start (GTK_BOX (vbox10), hbox31, TRUE, TRUE, 0); image26 = create_pixmap (infoDialog, "logo_rectangle.png"); gtk_widget_show (image26); gtk_box_pack_start (GTK_BOX (hbox31), image26, FALSE, FALSE, 0); gtk_widget_set_margin_start(image26, 10); gtk_widget_set_margin_top(image26, 10); vbox11 = gtk_vbox_new (FALSE, 0); gtk_widget_show (vbox11); gtk_box_pack_start (GTK_BOX (hbox31), vbox11, TRUE, TRUE, 0); table4 = gtk_grid_new (); tool_grid_resize(table4, 3, 2); gtk_widget_show (table4); gtk_box_pack_start (GTK_BOX (vbox11), table4, TRUE, FALSE, 0); label55 = gtk_label_new (_("Version :")); gtk_widget_show (label55); gtk_grid_attach (GTK_GRID (table4), label55, 0, 0, 1, 1); gtk_label_set_use_markup (GTK_LABEL (label55), TRUE); gtk_label_set_xalign(GTK_LABEL(label55), 1); label56 = gtk_label_new (_("Release Date :")); gtk_widget_show (label56); gtk_grid_attach (GTK_GRID (table4), label56, 0, 1, 1, 1); gtk_label_set_use_markup (GTK_LABEL (label56), TRUE); gtk_label_set_xalign(GTK_LABEL(label56), 1); label57 = gtk_label_new (_("Web site :")); gtk_widget_show (label57); gtk_grid_attach (GTK_GRID (table4), label57, 0, 2, 1, 1); gtk_label_set_use_markup (GTK_LABEL (label57), TRUE); gtk_label_set_xalign(GTK_LABEL(label57), 1); labelInfoVersion = gtk_label_new ("2.99"); gtk_widget_show (labelInfoVersion); gtk_grid_attach (GTK_GRID (table4), labelInfoVersion, 1, 0, 1, 1); gtk_label_set_xalign(GTK_LABEL(labelInfoVersion), 0); gtk_widget_set_margin_start(labelInfoVersion, 5); gtk_widget_set_margin_top(labelInfoVersion, 0); labelInfoReleaseDate = gtk_label_new ("AAAA-MM-JJ"); gtk_widget_show (labelInfoReleaseDate); gtk_grid_attach (GTK_GRID (table4), labelInfoReleaseDate, 1, 1, 1, 1); gtk_label_set_xalign(GTK_LABEL(labelInfoReleaseDate), 0); gtk_widget_set_margin_start(labelInfoReleaseDate, 5); gtk_widget_set_margin_top(labelInfoReleaseDate, 0); labelInfoWebSite = gtk_label_new ("http://"); gtk_widget_show (labelInfoWebSite); gtk_grid_attach (GTK_GRID (table4), labelInfoWebSite, 1, 2, 1, 1); gtk_widget_set_can_focus (labelInfoWebSite, TRUE); gtk_label_set_use_markup (GTK_LABEL (labelInfoWebSite), TRUE); gtk_label_set_selectable (GTK_LABEL (labelInfoWebSite), TRUE); gtk_label_set_xalign(GTK_LABEL(labelInfoWebSite), 0); gtk_widget_set_margin_start(labelInfoWebSite, 5); gtk_widget_set_margin_top(labelInfoWebSite, 0); notebookAbout = gtk_notebook_new (); gtk_widget_show (notebookAbout); gtk_box_pack_start (GTK_BOX (vbox10), notebookAbout, TRUE, TRUE, 0); gtk_widget_set_size_request (notebookAbout, 475, 300); scrolledwindow4 = gtk_scrolled_window_new (NULL, NULL); gtk_widget_show (scrolledwindow4); gtk_container_add (GTK_CONTAINER (notebookAbout), scrolledwindow4); gtk_scrolled_window_set_policy (GTK_SCROLLED_WINDOW (scrolledwindow4), GTK_POLICY_NEVER, GTK_POLICY_AUTOMATIC); gtk_scrolled_window_set_shadow_type (GTK_SCROLLED_WINDOW (scrolledwindow4), GTK_SHADOW_ETCHED_IN); textviewReadme = gtk_text_view_new (); gtk_widget_show (textviewReadme); gtk_container_add (GTK_CONTAINER (scrolledwindow4), textviewReadme); gtk_text_view_set_editable (GTK_TEXT_VIEW (textviewReadme), FALSE); gtk_text_view_set_wrap_mode (GTK_TEXT_VIEW (textviewReadme), GTK_WRAP_WORD); gtk_text_view_set_cursor_visible (GTK_TEXT_VIEW (textviewReadme), FALSE); gtk_text_view_set_left_margin (GTK_TEXT_VIEW (textviewReadme), 2); gtk_text_view_set_right_margin (GTK_TEXT_VIEW (textviewReadme), 2); label46 = gtk_label_new (_("Readme")); gtk_widget_show (label46); gtk_notebook_set_tab_label (GTK_NOTEBOOK (notebookAbout), gtk_notebook_get_nth_page (GTK_NOTEBOOK (notebookAbout), 0), label46); scrolledwindow3 = gtk_scrolled_window_new (NULL, NULL); gtk_widget_show (scrolledwindow3); gtk_container_add (GTK_CONTAINER (notebookAbout), scrolledwindow3); gtk_scrolled_window_set_policy (GTK_SCROLLED_WINDOW (scrolledwindow3), GTK_POLICY_NEVER, GTK_POLICY_AUTOMATIC); gtk_scrolled_window_set_shadow_type (GTK_SCROLLED_WINDOW (scrolledwindow3), GTK_SHADOW_ETCHED_IN); textviewAuthors = gtk_text_view_new (); gtk_widget_show (textviewAuthors); gtk_container_add (GTK_CONTAINER (scrolledwindow3), textviewAuthors); gtk_text_view_set_editable (GTK_TEXT_VIEW (textviewAuthors), FALSE); gtk_text_view_set_wrap_mode (GTK_TEXT_VIEW (textviewAuthors), GTK_WRAP_WORD); gtk_text_view_set_cursor_visible (GTK_TEXT_VIEW (textviewAuthors), FALSE); gtk_text_view_set_left_margin (GTK_TEXT_VIEW (textviewAuthors), 2); gtk_text_view_set_right_margin (GTK_TEXT_VIEW (textviewAuthors), 2); label47 = gtk_label_new (_("Authors")); gtk_widget_show (label47); gtk_notebook_set_tab_label (GTK_NOTEBOOK (notebookAbout), gtk_notebook_get_nth_page (GTK_NOTEBOOK (notebookAbout), 1), label47); scrolledwindow2 = gtk_scrolled_window_new (NULL, NULL); gtk_widget_show (scrolledwindow2); gtk_container_add (GTK_CONTAINER (notebookAbout), scrolledwindow2); gtk_scrolled_window_set_policy (GTK_SCROLLED_WINDOW (scrolledwindow2), GTK_POLICY_AUTOMATIC, GTK_POLICY_ALWAYS); gtk_scrolled_window_set_shadow_type (GTK_SCROLLED_WINDOW (scrolledwindow2), GTK_SHADOW_ETCHED_IN); textviewLicence = gtk_text_view_new (); gtk_widget_show (textviewLicence); gtk_container_add (GTK_CONTAINER (scrolledwindow2), textviewLicence); gtk_text_view_set_editable (GTK_TEXT_VIEW (textviewLicence), FALSE); gtk_text_view_set_cursor_visible (GTK_TEXT_VIEW (textviewLicence), FALSE); gtk_text_view_set_left_margin (GTK_TEXT_VIEW (textviewLicence), 2); gtk_text_view_set_right_margin (GTK_TEXT_VIEW (textviewLicence), 2); labelLicense = gtk_label_new (_("License")); gtk_widget_show (labelLicense); gtk_notebook_set_tab_label (GTK_NOTEBOOK (notebookAbout), gtk_notebook_get_nth_page (GTK_NOTEBOOK (notebookAbout), 2), labelLicense); vbox23 = gtk_vbox_new (FALSE, 0); gtk_widget_show (vbox23); gtk_container_add (GTK_CONTAINER (notebookAbout), vbox23); label116 = gtk_label_new (_("Loaded plug-ins:")); gtk_widget_show (label116); gtk_box_pack_start (GTK_BOX (vbox23), label116, FALSE, FALSE, 0); gtk_label_set_xalign(GTK_LABEL(label116), 0); gtk_widget_set_margin_start(label116, 15); gtk_widget_set_margin_top(label116, 5); scrolledwindowPlugins = gtk_scrolled_window_new (NULL, NULL); gtk_widget_show (scrolledwindowPlugins); gtk_box_pack_start (GTK_BOX (vbox23), scrolledwindowPlugins, TRUE, TRUE, 0); gtk_scrolled_window_set_policy (GTK_SCROLLED_WINDOW (scrolledwindowPlugins), GTK_POLICY_ALWAYS, GTK_POLICY_AUTOMATIC); label115 = gtk_label_new (_("Plug-ins")); gtk_widget_show (label115); gtk_notebook_set_tab_label (GTK_NOTEBOOK (notebookAbout), gtk_notebook_get_nth_page (GTK_NOTEBOOK (notebookAbout), 3), label115); scrolledwindow7 = gtk_scrolled_window_new (NULL, NULL); gtk_widget_show (scrolledwindow7); gtk_container_add (GTK_CONTAINER (notebookAbout), scrolledwindow7); gtk_scrolled_window_set_policy (GTK_SCROLLED_WINDOW (scrolledwindow7), GTK_POLICY_AUTOMATIC, GTK_POLICY_ALWAYS); gtk_scrolled_window_set_shadow_type (GTK_SCROLLED_WINDOW (scrolledwindow7), GTK_SHADOW_ETCHED_IN); textviewChangelog = gtk_text_view_new (); gtk_widget_show (textviewChangelog); gtk_container_add (GTK_CONTAINER (scrolledwindow7), textviewChangelog); gtk_text_view_set_editable (GTK_TEXT_VIEW (textviewChangelog), FALSE); gtk_text_view_set_cursor_visible (GTK_TEXT_VIEW (textviewChangelog), FALSE); gtk_text_view_set_left_margin (GTK_TEXT_VIEW (textviewChangelog), 2); gtk_text_view_set_right_margin (GTK_TEXT_VIEW (textviewChangelog), 2); label137 = gtk_label_new (_("Changelog")); gtk_widget_show (label137); gtk_notebook_set_tab_label (GTK_NOTEBOOK (notebookAbout), gtk_notebook_get_nth_page (GTK_NOTEBOOK (notebookAbout), 4), label137); closebutton2 = gtk_button_new_from_icon_name("window-close", GTK_ICON_SIZE_BUTTON); gtk_widget_show (closebutton2); gtk_dialog_add_action_widget (GTK_DIALOG (infoDialog), closebutton2, GTK_RESPONSE_CLOSE); gtk_widget_set_can_default (closebutton2, TRUE); g_signal_connect_swapped ((gpointer) closebutton2, "clicked", G_CALLBACK (gtk_widget_hide), G_OBJECT(infoDialog)); /* Store pointers to all widgets, for use by lookup_widget(). */ GLADE_HOOKUP_OBJECT_NO_REF (infoDialog, infoDialog, "infoDialog"); GLADE_HOOKUP_OBJECT_NO_REF (infoDialog, dialog_vbox4, "dialog_vbox4"); GLADE_HOOKUP_OBJECT (infoDialog, vbox10, "vbox10"); GLADE_HOOKUP_OBJECT (infoDialog, hbox31, "hbox31"); GLADE_HOOKUP_OBJECT (infoDialog, image26, "image26"); GLADE_HOOKUP_OBJECT (infoDialog, vbox11, "vbox11"); GLADE_HOOKUP_OBJECT (infoDialog, table4, "table4"); GLADE_HOOKUP_OBJECT (infoDialog, label55, "label55"); GLADE_HOOKUP_OBJECT (infoDialog, label56, "label56"); GLADE_HOOKUP_OBJECT (infoDialog, label57, "label57"); GLADE_HOOKUP_OBJECT (infoDialog, labelInfoVersion, "labelInfoVersion"); GLADE_HOOKUP_OBJECT (infoDialog, labelInfoReleaseDate, "labelInfoReleaseDate"); GLADE_HOOKUP_OBJECT (infoDialog, labelInfoWebSite, "labelInfoWebSite"); GLADE_HOOKUP_OBJECT (infoDialog, notebookAbout, "notebookAbout"); GLADE_HOOKUP_OBJECT (infoDialog, scrolledwindow4, "scrolledwindow4"); GLADE_HOOKUP_OBJECT (infoDialog, textviewReadme, "textviewReadme"); GLADE_HOOKUP_OBJECT (infoDialog, label46, "label46"); GLADE_HOOKUP_OBJECT (infoDialog, scrolledwindow3, "scrolledwindow3"); GLADE_HOOKUP_OBJECT (infoDialog, textviewAuthors, "textviewAuthors"); GLADE_HOOKUP_OBJECT (infoDialog, label47, "label47"); GLADE_HOOKUP_OBJECT (infoDialog, scrolledwindow2, "scrolledwindow2"); GLADE_HOOKUP_OBJECT (infoDialog, textviewLicence, "textviewLicence"); GLADE_HOOKUP_OBJECT (infoDialog, labelLicense, "labelLicense"); GLADE_HOOKUP_OBJECT (infoDialog, vbox23, "vbox23"); GLADE_HOOKUP_OBJECT (infoDialog, label116, "label116"); GLADE_HOOKUP_OBJECT (infoDialog, scrolledwindowPlugins, "scrolledwindowPlugins"); GLADE_HOOKUP_OBJECT (infoDialog, label115, "label115"); GLADE_HOOKUP_OBJECT (infoDialog, scrolledwindow7, "scrolledwindow7"); GLADE_HOOKUP_OBJECT (infoDialog, textviewChangelog, "textviewChangelog"); GLADE_HOOKUP_OBJECT (infoDialog, label137, "label137"); GLADE_HOOKUP_OBJECT (infoDialog, closebutton2, "closebutton2"); return infoDialog; } GtkWidget* create_pairsDialog (void) { GtkWidget *pairsDialog; GdkPixbuf *pairsDialog_icon_pixbuf; GtkWidget *vbox; GtkWidget *hbox33; GtkWidget *image32; GtkWidget *vbox12; GtkWidget *labelTitlePairs; GtkWidget *hboxPairsModel; GtkWidget *notebookPairs; GtkWidget *vboxPairsDialog; GtkWidget *hbox73; GtkWidget *scrolledwindowPairs; GtkWidget *viewport1; GtkWidget *hboxViewportPairs; GtkWidget *label139; GtkWidget *vboxDistances; GtkWidget *label140; GtkWidget *closebutton3; pairsDialog = gtk_dialog_new (); gtk_window_set_title (GTK_WINDOW (pairsDialog), _("set and customize pairs")); pairsDialog_icon_pixbuf = create_pixbuf ("icone-dialog.png"); if (pairsDialog_icon_pixbuf) { gtk_window_set_icon (GTK_WINDOW (pairsDialog), pairsDialog_icon_pixbuf); g_object_unref (pairsDialog_icon_pixbuf); } vbox = gtk_dialog_get_content_area(GTK_DIALOG(pairsDialog)); gtk_widget_show (vbox); hbox33 = gtk_hbox_new (FALSE, 0); gtk_widget_show (hbox33); gtk_box_pack_start (GTK_BOX (vbox), hbox33, FALSE, FALSE, 0); image32 = create_pixmap (pairsDialog, "liaison-bandeau.png"); gtk_widget_show (image32); gtk_box_pack_start (GTK_BOX (hbox33), image32, FALSE, FALSE, 0); vbox12 = gtk_vbox_new (FALSE, 0); gtk_widget_show (vbox12); gtk_box_pack_start (GTK_BOX (hbox33), vbox12, TRUE, TRUE, 0); labelTitlePairs = gtk_label_new (_("Set parameters for pairs")); gtk_widget_show (labelTitlePairs); gtk_box_pack_start (GTK_BOX (vbox12), labelTitlePairs, TRUE, TRUE, 0); gtk_label_set_use_markup (GTK_LABEL (labelTitlePairs), TRUE); gtk_label_set_xalign(GTK_LABEL(labelTitlePairs), 0.5); hboxPairsModel = gtk_hbox_new (FALSE, 0); gtk_widget_show (hboxPairsModel); gtk_box_pack_end (GTK_BOX (vbox12), hboxPairsModel, FALSE, FALSE, 0); notebookPairs = gtk_notebook_new (); gtk_widget_show (notebookPairs); gtk_box_pack_start (GTK_BOX (vbox), notebookPairs, TRUE, TRUE, 0); gtk_notebook_set_tab_pos (GTK_NOTEBOOK (notebookPairs), GTK_POS_LEFT); vboxPairsDialog = gtk_vbox_new (FALSE, 0); gtk_widget_show (vboxPairsDialog); gtk_container_add (GTK_CONTAINER (notebookPairs), vboxPairsDialog); hbox73 = gtk_hbox_new (FALSE, 0); gtk_widget_show (hbox73); gtk_box_pack_start (GTK_BOX (vboxPairsDialog), hbox73, TRUE, TRUE, 0); scrolledwindowPairs = gtk_scrolled_window_new (NULL, NULL); gtk_widget_show (scrolledwindowPairs); gtk_box_pack_start (GTK_BOX (hbox73), scrolledwindowPairs, TRUE, TRUE, 0); gtk_widget_set_size_request (scrolledwindowPairs, -1, 150); gtk_scrolled_window_set_policy (GTK_SCROLLED_WINDOW (scrolledwindowPairs), GTK_POLICY_AUTOMATIC, GTK_POLICY_AUTOMATIC); viewport1 = gtk_viewport_new (NULL, NULL); gtk_widget_show (viewport1); gtk_container_add (GTK_CONTAINER (scrolledwindowPairs), viewport1); hboxViewportPairs = gtk_hbox_new (FALSE, 0); gtk_widget_show (hboxViewportPairs); gtk_container_add (GTK_CONTAINER (viewport1), hboxViewportPairs); label139 = gtk_label_new (_("Pairs")); gtk_widget_show (label139); gtk_notebook_set_tab_label (GTK_NOTEBOOK (notebookPairs), gtk_notebook_get_nth_page (GTK_NOTEBOOK (notebookPairs), 0), label139); gtk_label_set_angle (GTK_LABEL (label139), 90); vboxDistances = gtk_vbox_new (FALSE, 0); gtk_widget_show (vboxDistances); gtk_container_add (GTK_CONTAINER (notebookPairs), vboxDistances); label140 = gtk_label_new (_("Distances")); gtk_widget_show (label140); gtk_notebook_set_tab_label (GTK_NOTEBOOK (notebookPairs), gtk_notebook_get_nth_page (GTK_NOTEBOOK (notebookPairs), 1), label140); gtk_label_set_angle (GTK_LABEL (label140), 90); closebutton3 = gtk_button_new_from_icon_name("window-close", GTK_ICON_SIZE_BUTTON); gtk_widget_show (closebutton3); gtk_dialog_add_action_widget (GTK_DIALOG (pairsDialog), closebutton3, GTK_RESPONSE_CLOSE); gtk_widget_set_can_default (closebutton3, TRUE); /* Store pointers to all widgets, for use by lookup_widget(). */ GLADE_HOOKUP_OBJECT_NO_REF (pairsDialog, pairsDialog, "pairsDialog"); GLADE_HOOKUP_OBJECT_NO_REF (pairsDialog, vbox, "vbox"); GLADE_HOOKUP_OBJECT (pairsDialog, hbox33, "hbox33"); GLADE_HOOKUP_OBJECT (pairsDialog, image32, "image32"); GLADE_HOOKUP_OBJECT (pairsDialog, vbox12, "vbox12"); GLADE_HOOKUP_OBJECT (pairsDialog, labelTitlePairs, "labelTitlePairs"); GLADE_HOOKUP_OBJECT (pairsDialog, hboxPairsModel, "hboxPairsModel"); GLADE_HOOKUP_OBJECT (pairsDialog, notebookPairs, "notebookPairs"); GLADE_HOOKUP_OBJECT (pairsDialog, vboxPairsDialog, "vboxPairsDialog"); GLADE_HOOKUP_OBJECT (pairsDialog, hbox73, "hbox73"); GLADE_HOOKUP_OBJECT (pairsDialog, scrolledwindowPairs, "scrolledwindowPairs"); GLADE_HOOKUP_OBJECT (pairsDialog, viewport1, "viewport1"); GLADE_HOOKUP_OBJECT (pairsDialog, hboxViewportPairs, "hboxViewportPairs"); GLADE_HOOKUP_OBJECT (pairsDialog, label139, "label139"); GLADE_HOOKUP_OBJECT (pairsDialog, vboxDistances, "vboxDistances"); GLADE_HOOKUP_OBJECT (pairsDialog, label140, "label140"); GLADE_HOOKUP_OBJECT (pairsDialog, closebutton3, "closebutton3"); return pairsDialog; } GtkWidget* create_quitDialog (void) { GtkWidget *quitDialog; GtkWidget *dialog_vbox5; GtkWidget *hbox44; GtkWidget *image35; GtkWidget *vbox13; GtkWidget *label71; GtkWidget *checkbuttonHideNextTime; GtkWidget *hboxHomedir; GtkWidget *image50; GtkWidget *label119; GtkWidget *buttonAddHomedir; GtkWidget *hboxWarning; GtkWidget *image46; GtkWidget *label114; GtkWidget *frame5; GtkWidget *label73; GtkWidget *hbox45; GtkWidget *image36; GtkWidget *label72; GtkWidget *cancelbutton1; GtkWidget *okbutton1; quitDialog = gtk_dialog_new (); gtk_window_set_title (GTK_WINDOW (quitDialog), _("Quit V_Sim")); gtk_window_set_position (GTK_WINDOW (quitDialog), GTK_WIN_POS_CENTER_ON_PARENT); gtk_window_set_modal (GTK_WINDOW (quitDialog), TRUE); gtk_window_set_icon_name (GTK_WINDOW (quitDialog), "gtk-dialog-question"); gtk_window_set_type_hint (GTK_WINDOW (quitDialog), GDK_WINDOW_TYPE_HINT_DIALOG); dialog_vbox5 = gtk_dialog_get_content_area(GTK_DIALOG(quitDialog)); gtk_widget_show (dialog_vbox5); hbox44 = gtk_hbox_new (FALSE, 0); gtk_widget_show (hbox44); gtk_box_pack_start (GTK_BOX (dialog_vbox5), hbox44, TRUE, TRUE, 0); image35 = gtk_image_new_from_icon_name ("gtk-dialog-question", GTK_ICON_SIZE_DIALOG); gtk_widget_show (image35); gtk_box_pack_start (GTK_BOX (hbox44), image35, FALSE, FALSE, 0); gtk_widget_set_margin_start(image35, 6); gtk_widget_set_margin_top(image35, 0); vbox13 = gtk_vbox_new (FALSE, 0); gtk_widget_show (vbox13); gtk_box_pack_start (GTK_BOX (hbox44), vbox13, TRUE, TRUE, 0); label71 = gtk_label_new (_("Quit V_Sim?")); gtk_widget_show (label71); gtk_box_pack_start (GTK_BOX (vbox13), label71, FALSE, FALSE, 0); gtk_label_set_use_markup (GTK_LABEL (label71), TRUE); gtk_widget_set_margin_start(label71, 0); gtk_widget_set_margin_top(label71, 10); checkbuttonHideNextTime = gtk_check_button_new_with_mnemonic (_("Don't show this warning again.")); gtk_widget_show (checkbuttonHideNextTime); gtk_box_pack_start (GTK_BOX (vbox13), checkbuttonHideNextTime, TRUE, TRUE, 0); hboxHomedir = gtk_hbox_new (FALSE, 0); gtk_box_pack_start (GTK_BOX (vbox13), hboxHomedir, TRUE, TRUE, 0); gtk_container_set_border_width (GTK_CONTAINER (hboxHomedir), 15); image50 = gtk_image_new_from_icon_name("dialog-warning", GTK_ICON_SIZE_LARGE_TOOLBAR); gtk_widget_show (image50); gtk_box_pack_start (GTK_BOX (hboxHomedir), image50, FALSE, FALSE, 5); label119 = gtk_label_new (_("Can't find a local configuration directory $XDG_CONFIG_HOME/v_sim. Should one be added?")); gtk_widget_show (label119); gtk_box_pack_start (GTK_BOX (hboxHomedir), label119, FALSE, FALSE, 0); gtk_label_set_use_markup (GTK_LABEL (label119), TRUE); gtk_label_set_justify (GTK_LABEL (label119), GTK_JUSTIFY_FILL); gtk_label_set_line_wrap (GTK_LABEL (label119), TRUE); buttonAddHomedir = gtk_button_new_from_icon_name("list-add", GTK_ICON_SIZE_BUTTON); gtk_widget_show (buttonAddHomedir); gtk_box_pack_start (GTK_BOX (hboxHomedir), buttonAddHomedir, FALSE, FALSE, 0); hboxWarning = gtk_hbox_new (FALSE, 0); gtk_box_pack_start (GTK_BOX (vbox13), hboxWarning, TRUE, TRUE, 0); gtk_container_set_border_width (GTK_CONTAINER (hboxWarning), 15); image46 = gtk_image_new_from_icon_name("dialog-warning", GTK_ICON_SIZE_LARGE_TOOLBAR); gtk_widget_show (image46); gtk_box_pack_start (GTK_BOX (hboxWarning), image46, FALSE, FALSE, 5); label114 = gtk_label_new (_("Can't find a v_sim.par file with enough write permissions to store the preference, neither in the installation directory nor in the $XDG_CONFIG_HOME/v_sim one.")); gtk_widget_show (label114); gtk_box_pack_start (GTK_BOX (hboxWarning), label114, FALSE, FALSE, 0); gtk_label_set_use_markup (GTK_LABEL (label114), TRUE); gtk_label_set_justify (GTK_LABEL (label114), GTK_JUSTIFY_FILL); gtk_label_set_line_wrap (GTK_LABEL (label114), TRUE); frame5 = gtk_frame_new (NULL); gtk_widget_show (frame5); gtk_box_pack_start (GTK_BOX (vbox13), frame5, FALSE, FALSE, 0); label73 = gtk_label_new (_("If you check the above box but you want to have this warning dialog again before closing, you can change this by editing the parameter file (v_sim.par). The option is called 'main_confirmQuit'.")); gtk_widget_show (label73); gtk_container_add (GTK_CONTAINER (frame5), label73); gtk_label_set_use_markup (GTK_LABEL (label73), TRUE); gtk_label_set_line_wrap (GTK_LABEL (label73), TRUE); gtk_label_set_xalign(GTK_LABEL(label73), 0); gtk_widget_set_margin_start(label73, 2); gtk_widget_set_margin_top(label73, 2); hbox45 = gtk_hbox_new (FALSE, 0); gtk_widget_show (hbox45); gtk_frame_set_label_widget (GTK_FRAME (frame5), hbox45); image36 = gtk_image_new_from_icon_name ("gtk-help", GTK_ICON_SIZE_MENU); gtk_widget_show (image36); gtk_box_pack_start (GTK_BOX (hbox45), image36, TRUE, TRUE, 0); label72 = gtk_label_new (_("Help")); gtk_widget_show (label72); gtk_box_pack_start (GTK_BOX (hbox45), label72, FALSE, FALSE, 0); gtk_widget_set_margin_start(label72, 5); gtk_widget_set_margin_top(label72, 0); cancelbutton1 = gtk_button_new_with_mnemonic(_("_Cancel")); gtk_widget_show (cancelbutton1); gtk_dialog_add_action_widget (GTK_DIALOG (quitDialog), cancelbutton1, GTK_RESPONSE_CANCEL); gtk_widget_set_can_default (cancelbutton1, TRUE); okbutton1 = gtk_button_new_from_icon_name("application-exit", GTK_ICON_SIZE_BUTTON); gtk_widget_show (okbutton1); gtk_dialog_add_action_widget (GTK_DIALOG (quitDialog), okbutton1, GTK_RESPONSE_OK); gtk_widget_set_can_default (okbutton1, TRUE); /* Store pointers to all widgets, for use by lookup_widget(). */ GLADE_HOOKUP_OBJECT_NO_REF (quitDialog, quitDialog, "quitDialog"); GLADE_HOOKUP_OBJECT_NO_REF (quitDialog, dialog_vbox5, "dialog_vbox5"); GLADE_HOOKUP_OBJECT (quitDialog, hbox44, "hbox44"); GLADE_HOOKUP_OBJECT (quitDialog, image35, "image35"); GLADE_HOOKUP_OBJECT (quitDialog, vbox13, "vbox13"); GLADE_HOOKUP_OBJECT (quitDialog, label71, "label71"); GLADE_HOOKUP_OBJECT (quitDialog, checkbuttonHideNextTime, "checkbuttonHideNextTime"); GLADE_HOOKUP_OBJECT (quitDialog, hboxHomedir, "hboxHomedir"); GLADE_HOOKUP_OBJECT (quitDialog, image50, "image50"); GLADE_HOOKUP_OBJECT (quitDialog, label119, "label119"); GLADE_HOOKUP_OBJECT (quitDialog, buttonAddHomedir, "buttonAddHomedir"); GLADE_HOOKUP_OBJECT (quitDialog, hboxWarning, "hboxWarning"); GLADE_HOOKUP_OBJECT (quitDialog, image46, "image46"); GLADE_HOOKUP_OBJECT (quitDialog, label114, "label114"); GLADE_HOOKUP_OBJECT (quitDialog, frame5, "frame5"); GLADE_HOOKUP_OBJECT (quitDialog, label73, "label73"); GLADE_HOOKUP_OBJECT (quitDialog, hbox45, "hbox45"); GLADE_HOOKUP_OBJECT (quitDialog, image36, "image36"); GLADE_HOOKUP_OBJECT (quitDialog, label72, "label72"); GLADE_HOOKUP_OBJECT (quitDialog, cancelbutton1, "cancelbutton1"); GLADE_HOOKUP_OBJECT (quitDialog, okbutton1, "okbutton1"); return quitDialog; } v_sim-3.8.0/src/interface.h000066400000000000000000000015561370110300500155340ustar00rootroot00000000000000/* * DO NOT EDIT THIS FILE - it is generated by Glade. */ #if GTK_MAJOR_VERSION == 2 && GTK_MINOR_VERSION < 5 #define gtk_image_new_from_icon_name(name, size) gtk_image_new_from_stock(name,size) #define gtk_window_set_icon_name(window, name) gtk_window_set_icon(window, (GdkPixbuf*)0) #endif #ifndef gtk_widget_ref #define gtk_widget_ref(Obj) g_object_ref(G_OBJECT(Obj)) #endif #ifndef gtk_widget_unref #define gtk_widget_unref g_object_unref #endif #if GTK_MAJOR_VERSION > 2 || GTK_MINOR_VERSION > 10 #define gtk_tooltips_set_tip(T, Obj, tt, ctx) gtk_widget_set_tooltip_text(Obj, tt) #define gtk_tool_item_set_tooltip(Obj, T, tt, ctx) gtk_tool_item_set_tooltip_text(Obj, tt) #endif GtkWidget* create_saveDialog (void); GtkWidget* create_observeDialog (void); GtkWidget* create_infoDialog (void); GtkWidget* create_pairsDialog (void); GtkWidget* create_quitDialog (void); v_sim-3.8.0/src/loaders/000077500000000000000000000000001370110300500150455ustar00rootroot00000000000000v_sim-3.8.0/src/loaders/atomic_ascii.c000066400000000000000000000500451370110300500176410ustar00rootroot00000000000000/* EXTRAITS DE LA LICENCE Copyright CEA, contributeurs : Luc BILLARD et Damien CALISTE, laboratoire L_Sim, (2001-2005) Adresse mèl : BILLARD, non joignable par mèl ; CALISTE, damien P caliste AT cea P fr. Ce logiciel est un programme informatique servant à visualiser des structures atomiques dans un rendu pseudo-3D. Ce logiciel est régi par la licence CeCILL soumise au droit français et respectant les principes de diffusion des logiciels libres. Vous pouvez utiliser, modifier et/ou redistribuer ce programme sous les conditions de la licence CeCILL telle que diffusée par le CEA, le CNRS et l'INRIA sur le site "http://www.cecill.info". Le fait que vous puissiez accéder à cet en-tête signifie que vous avez pris connaissance de la licence CeCILL, et que vous en avez accepté les termes (cf. le fichier Documentation/licence.fr.txt fourni avec ce logiciel). */ /* LICENCE SUM UP Copyright CEA, contributors : Luc BILLARD et Damien CALISTE, laboratoire L_Sim, (2001-2005) E-mail address: BILLARD, not reachable any more ; CALISTE, damien P caliste AT cea P fr. This software is a computer program whose purpose is to visualize atomic configurations in 3D. This software is governed by the CeCILL license under French law and abiding by the rules of distribution of free software. You can use, modify and/ or redistribute the software under the terms of the CeCILL license as circulated by CEA, CNRS and INRIA at the following URL "http://www.cecill.info". The fact that you are presently reading this means that you have had knowledge of the CeCILL license and that you accept its terms. You can find a copy of this licence shipped with this software at Documentation/licence.en.txt. */ #include "atomic_ascii.h" #include "atomic_yaml.h" #include #include #include #include #include #include #include #include #include /** * SECTION:atomic_ascii * @short_description: Method to load ASCII position file. * * ASCII file format is a plain text format. The mandatory * information are a box description and a list of coordinates with * symbols. Additional information can be added by keywords or meta * data, like forces, units or total energy from a DFT calculation. */ typedef struct AsciiKeywordData_ { gboolean reduced; gboolean angdeg; ToolUnits unit; VisuBoxBoundaries bc; } AsciiKeywordData; typedef struct AsciiMetaData_ { guint nqpt; gdouble totalEnergy; gboolean forces; } AsciiMetaData; static VisuDataLoader *asciiLoader = NULL; static double readTotalEnergy(const gchar *str); static gboolean loadAscii(VisuDataLoader *self, VisuDataLoadable *data, guint type, guint nSet, GCancellable *cancel, GError **error); static int read_ascii_file(VisuDataLoadable *data, guint iType, GError **error); static gboolean readFile_is_comment(char *str, AsciiKeywordData *kw, AsciiMetaData *md); /** * visu_data_loader_ascii_getStatic: * * Retrieve the instance of the atomic loader used to parse ASCII files. * * Since: 3.8 * * Returns: (transfer none): a #VisuDataLoader owned by V_Sim. **/ VisuDataLoader* visu_data_loader_ascii_getStatic(void) { const gchar *typeASCII[] = {"*.ascii", (char*)0}; if (asciiLoader) return asciiLoader; return asciiLoader = visu_data_loader_new(_("'x y z Element' format"), typeASCII, FALSE, loadAscii, 50); } /******************************************************************************/ static gboolean readFile_is_comment(char *str, AsciiKeywordData *kw, AsciiMetaData *md) { gchar **tokens; int i; if (kw && !strncmp(str + 1, "keyword", 7)) { tokens = g_strsplit_set(str + 9, " ,\n\t\r", -1); for (i = 0; tokens[i]; i++) if (tokens[i][0] != '\0') { /* tokens[i] = g_strstrip(tokens[i]); */ DBG_fprintf(stderr, "Atomic ASCII: get keyword '%s'.\n", tokens[i]); if (!g_ascii_strcasecmp(tokens[i], "reduced")) kw->reduced = TRUE; else if (!g_ascii_strcasecmp(tokens[i], "angdeg")) kw->angdeg = TRUE; else if (!g_ascii_strcasecmp(tokens[i], "atomic") || !g_ascii_strcasecmp(tokens[i], "atomicd0") || !g_ascii_strcasecmp(tokens[i], "bohr") || !g_ascii_strcasecmp(tokens[i], "bohrd0")) kw->unit = TOOL_UNITS_BOHR; else if (!g_ascii_strcasecmp(tokens[i], "angstroem") || !g_ascii_strcasecmp(tokens[i], "angstroemd0")) kw->unit = TOOL_UNITS_ANGSTROEM; else if (!g_ascii_strcasecmp(tokens[i], "periodic")) kw->bc = VISU_BOX_PERIODIC; else if (!g_ascii_strcasecmp(tokens[i], "surface")) kw->bc = VISU_BOX_SURFACE_ZX; else if (!g_ascii_strcasecmp(tokens[i], "surfaceXY")) kw->bc = VISU_BOX_SURFACE_XY; else if (!g_ascii_strcasecmp(tokens[i], "freeBC")) kw->bc = VISU_BOX_FREE; } g_strfreev(tokens); } if (md && !g_ascii_strncasecmp(str + 1, "metaData", 8)) { tokens = g_strsplit_set(str + 10, " ,\n\t\r", -1); for (i = 0; tokens[i]; i++) if (tokens[i][0] != '\0') { /* tokens[i] = g_strstrip(tokens[i]); */ DBG_fprintf(stderr, "Atomic ASCII: get meta data '%s'.\n", tokens[i]); if (!g_ascii_strncasecmp(tokens[i], "qpt", 3)) md->nqpt += 1; else if (!g_ascii_strncasecmp(tokens[i], "totalEnergy", 11)) md->totalEnergy = readTotalEnergy(str + 10); else if (!g_ascii_strncasecmp(tokens[i], "forces", 6)) md->forces = TRUE; } g_strfreev(tokens); } if(str[0] == '#' || str[0] == '!') return TRUE; str = g_strstrip(str); return (str[0] == '\0'); } static double readTotalEnergy(const gchar *str) { gchar *chr, *tmpStr; int res, pos; double val; chr = strstr(str, "totalEnergy"); chr = strchr(chr, '='); chr += 1; val = 999.; res = (chr)?sscanf(chr, "%lf%n", &val, &pos):0; if (res != 1) g_warning("syntax error for meta data 'totalEnergy' in '%s'.", chr); else if (chr[pos] != '\0') { tmpStr = g_strdup(chr + pos); tmpStr = g_strstrip(tmpStr); if (!g_ascii_strncasecmp(tmpStr, "Ht", 2)) val *= 27.21138386; else if (!g_ascii_strncasecmp(tmpStr, "Ry", 2)) val *= .5 * 27.21138386; g_free(tmpStr); } DBG_fprintf(stderr, "Atomic ASCII: found 'totalEnergy' at %geV.\n", val); return val; } static gboolean readQpt(gchar *str, float qpt[4], GArray *disp, guint natom) { gchar **values; gchar *ptr; guint j, k; gfloat f; ptr = strstr(str, "qpt"); if (!ptr) return FALSE; ptr = strstr(ptr, "="); if (!ptr) { g_warning("syntax error for meta data 'qpt' in '%s'.", str); return FALSE; } DBG_fprintf(stderr, "Atomic ASCII: read qpt from '%s'\n", ptr); g_array_set_size(disp, 0); values = g_strsplit_set(ptr + 1, " [];\n\r\\\t", -1); k = 0; for (j = 0; values[j] && k < 4; j++) if (values[j][0] != '\0') { if (sscanf(values[j], "%f", qpt + k) != 1) { g_warning("Can't read a float value from qpt" " keyword in '%s'.", values[j]); qpt[k] = 0.f; } DBG_fprintf(stderr, " | qpt[%d] = %g\n", k, qpt[k]); k += 1; } if (k != 4) g_warning("Can't read 4 float values from qpt" " keyword in '%s'.", ptr); for (; values[j]; j++) if (values[j][0] != '\0' && sscanf(values[j], "%f", &f) == 1) g_array_append_val(disp, f); if (disp->len != natom * 6) g_warning("Can't read enough displacement values," " %d read while %d were awaited.", disp->len, natom * 6); g_strfreev(values); return TRUE; } static gboolean readForces(gchar *str, GArray *forces, guint natom) { gchar **values; gchar *ptr; guint j, k; gfloat f; ptr = strstr(str, "forces"); if (!ptr) return FALSE; ptr = strstr(ptr, "="); if (!ptr) { g_warning("syntax error for meta data 'forces' in '%s'.", str); return FALSE; } DBG_fprintf(stderr, "Atomic ASCII: read forces from '%s'\n", ptr); g_array_set_size(forces, 0); values = g_strsplit_set(ptr + 1, " [];\n\r\\\t", -1); for (k = 0, j = 0; values[j] && k < 3 * natom; j++) if (values[j][0] != '\0') { if (sscanf(values[j], "%f", &f) == 1) { g_array_append_val(forces, f); k += 1; } } if (k != natom * 3) g_warning("Can't read enough force values," " %d read while %d were awaited.", k, natom * 3); g_strfreev(values); return TRUE; } static gboolean continuousLine(GString *line) { gsize len; len = line->len - 1; while (line->str[len] == '\n' || line->str[len] == '\r' || line->str[len] == '\t' || line->str[len] == ' ') len -= 1; return (line->str[len] == '\\'); } /******************************************************************************/ static gboolean loadAscii(VisuDataLoader *self _U_, VisuDataLoadable *data, guint type, guint nSet _U_, GCancellable *cancel _U_, GError **error) { g_return_val_if_fail(error && *error == (GError*)0, FALSE); /* Do the job of parsing. */ return (read_ascii_file(data, type, error) >= 0); } static int read_ascii_file(VisuDataLoadable *data, guint iType, GError **error) { gchar *info; GString *line, *bufLine; double xu, yu, zu; guint i, iph; int pos; char nomloc[TOOL_MAX_LINE_LENGTH]; VisuElement *type; VisuDataLoaderIter *iter; guint nbLine, natom; double boxGeometry[6], abc[3], ang[3]; float xyz[3]; gchar *infoUTF8, **nodeComments; gboolean hasNodeComments; GIOStatus status; ToolFiles *flux; float qpt[4]; GArray *forces, *dcoord; AsciiKeywordData kw; AsciiMetaData md; VisuBox *box; VisuVibration *vib; VisuNodeValuesString *labels; g_return_val_if_fail(error && *error == (GError*)0, FALSE); g_return_val_if_fail(VISU_IS_DATA_ATOMIC(data), FALSE); flux = tool_files_new(); if (!tool_files_open(flux, visu_data_loadable_getFilename(data, iType), error)) { g_object_unref(flux); return -1; } line = g_string_new(""); /* The first line is a commentry. */ if (tool_files_read_line_string(flux, line, NULL, error) != G_IO_STATUS_NORMAL) { g_object_unref(flux); g_string_free(line, TRUE); /* The file doesn't conform to ascii norm, we exit with a wrong type flag. */ return -1; } info = g_strdup(line->str); /* The second line contains xx, xy and yy */ if (tool_files_read_line_string(flux, line, NULL, error) != G_IO_STATUS_NORMAL) { g_object_unref(flux); g_string_free(line, TRUE); g_free(info); /* The file doesn't conform to ascii norm, we exit with a wrong type flag. */ return -2; } if(sscanf(line->str, "%lf %lf %lf", &(boxGeometry[0]), &(boxGeometry[1]), &(boxGeometry[2])) != 3) { *error = g_error_new(VISU_DATA_LOADABLE_ERROR, DATA_LOADABLE_ERROR_FORMAT, _("Cannot read dxx dyx dyy" " on 2nd line of ASCII file.\n")); g_object_unref(flux); g_string_free(line, TRUE); g_free(info); /* The file doesn't conform to ascii norm, we exit with a wrong type flag. */ return -3; } /* The third line contains xz, yz and zz */ if (tool_files_read_line_string(flux, line, NULL, error) != G_IO_STATUS_NORMAL) { g_object_unref(flux); g_string_free(line, TRUE); g_free(info); /* The file doesn't conform to ascii norm, we exit with a wrong type flag. */ return -4; } if(sscanf(line->str, "%lf %lf %lf", &boxGeometry[3], &boxGeometry[4], &boxGeometry[5]) != 3) { *error = g_error_new(VISU_DATA_LOADABLE_ERROR, DATA_LOADABLE_ERROR_FORMAT, _("Cannot read dzx dzy dzz" " on 3rd line of ASCII file.\n")); g_object_unref(flux); g_string_free(line, TRUE); g_free(info); /* The file doesn't conform to ascii norm, we exit with a wrong type flag. */ return -5; } /* Ok, from this point we assert that the file is in ascii format. All following errors are treated as syntax errors and the corresponding flag is return. */ DBG_fprintf(stderr, "Atomic ASCII: read box is %f x %f x %f\n" " %f x %f x %f\n", boxGeometry[0], boxGeometry[1], boxGeometry[2], boxGeometry[3], boxGeometry[4], boxGeometry[5]); /* Set the commentary. */ g_strstrip(info); if (info[0] == '#') infoUTF8 = g_locale_to_utf8(info + 1, -1, NULL, NULL, NULL); else infoUTF8 = g_locale_to_utf8(info, -1, NULL, NULL, NULL); if (infoUTF8) { visu_data_setDescription(VISU_DATA(data), infoUTF8); g_free(infoUTF8); } else g_warning("Can't convert '%s' to UTF8.\n", info); /* 1st pass to count ntype */ kw.reduced = FALSE; kw.angdeg = FALSE; kw.unit = TOOL_UNITS_UNDEFINED; kw.bc = VISU_BOX_PERIODIC; md.nqpt = 0; md.totalEnergy = 999.; md.forces = FALSE; dcoord = (GArray*)0; forces = (GArray*)0; nbLine = 4; iter = visu_data_loader_iter_new(); for(status = tool_files_read_line_string(flux, line, NULL, error); status == G_IO_STATUS_NORMAL; status = tool_files_read_line_string(flux, line, NULL, error)) { nbLine += 1; if(readFile_is_comment(line->str, &kw, &md)) continue; if(sscanf(line->str, "%lf %lf %lf %s", &xu, &yu, &zu, nomloc) != 4) { *error = g_error_new(VISU_DATA_LOADABLE_ERROR, DATA_LOADABLE_ERROR_FORMAT, _("Cannot read x, y, z," " name in ASCII file at line %d.\n\n" "Quoting '%s'.\n"), nbLine, line->str); g_object_unref(flux); g_string_free(line, TRUE); return 1; } nomloc[8] = '\0'; visu_data_loader_iter_addNode(iter, visu_element_retrieveFromName(nomloc, (gboolean*)0)); } if (status != G_IO_STATUS_EOF) { g_object_unref(flux); g_string_free(line, TRUE); visu_data_loader_iter_unref(iter); return 1; } natom = visu_data_loader_iter_allocate(iter, VISU_NODE_ARRAY(data)); visu_data_loader_iter_unref(iter); if (natom <= 0) { g_object_unref(flux); g_string_free(line, TRUE); *error = g_error_new(VISU_DATA_LOADABLE_ERROR, DATA_LOADABLE_ERROR_FORMAT, _("The file contains no atom coordinates.\n")); return 1; } /* We build boxGeometry according to angdeg flag. */ DBG_fprintf(stderr, "Atomic ASCII: build the box if any.\n"); if (kw.angdeg) { abc[0] = boxGeometry[0]; abc[1] = boxGeometry[1]; abc[2] = boxGeometry[2]; ang[0] = boxGeometry[3]; ang[1] = boxGeometry[4]; ang[2] = boxGeometry[5]; if (sin(ang[2]) == 0.f) { *error = g_error_new(VISU_DATA_LOADABLE_ERROR, DATA_LOADABLE_ERROR_FORMAT, _("Wrong (ab) angle, should be" " different from 0[pi].\n\n" " Quoting '%g'.\n"), ang[2]); g_object_unref(flux); g_string_free(line, TRUE); return 1; } boxGeometry[0] = abc[0]; boxGeometry[1] = abc[1] * cos(G_PI * ang[2] / 180.); boxGeometry[2] = abc[1] * sin(G_PI * ang[2] / 180.); boxGeometry[3] = abc[2] * cos(G_PI * ang[1] / 180.); boxGeometry[4] = abc[2] * (cos(G_PI * ang[0] / 180.) - cos(G_PI * ang[1] / 180.) * cos(G_PI * ang[2] / 180.)) / sin(G_PI * ang[2] / 180.); boxGeometry[5] = sqrt(abc[2] * abc[2] - boxGeometry[3] * boxGeometry[3] - boxGeometry[4] * boxGeometry[4]); boxGeometry[5] *= (ang[1] < 0.)?-1.:+1.; } /* Always set the given box, in case coordinates are reduced. */ box = visu_box_new(boxGeometry, kw.bc); visu_box_setUnit(box, kw.unit); visu_boxed_setBox(VISU_BOXED(data), VISU_BOXED(box)); g_object_unref(box); /* Test phonons. */ vib = (VisuVibration*)0; if (md.nqpt > 0) { DBG_fprintf(stderr, "Atomic ASCII: initialise phonon storage for %d data.\n", natom * 6); vib = visu_data_getVibration(VISU_DATA(data), md.nqpt); dcoord = g_array_sized_new(FALSE, FALSE, sizeof(float), natom * 6); } if (md.forces) { DBG_fprintf(stderr, "Atomic ASCII: initialise forces storage for %d data.\n", natom * 3); forces = g_array_sized_new(FALSE, FALSE, sizeof(float), natom * 3); } DBG_fprintf(stderr, "Atomic ASCII: reread file for node positions.\n"); /* Allocate the storage of the node comments. */ nodeComments = g_malloc(sizeof(gchar*) * natom); hasNodeComments = FALSE; if (tool_files_rewind(flux, error) != G_IO_STATUS_NORMAL) { g_object_unref(flux); g_string_free(line, TRUE); return 1; } /* reread the file to store the coordinates */ tool_files_read_line_string(flux, line, NULL, error); tool_files_read_line_string(flux, line, NULL, error); tool_files_read_line_string(flux, line, NULL, error); i = 0; iph = 0; bufLine = g_string_new((gchar*)0); for(status = tool_files_read_line_string(flux, line, NULL, error); status == G_IO_STATUS_NORMAL; status = tool_files_read_line_string(flux, line, NULL, error)) { if(readFile_is_comment(line->str, (AsciiKeywordData*)0, (AsciiMetaData*)0)) { while (continuousLine(line) && status == G_IO_STATUS_NORMAL) { status = tool_files_read_line_string(flux, bufLine, NULL, error); g_string_append(line, bufLine->str); } if (vib && readQpt(line->str, qpt, dcoord, natom)) { visu_vibration_setCharacteristic(vib, iph, qpt, qpt[3], 1.f); visu_vibration_setDisplacements(vib, iph, dcoord, TRUE); iph += 1; } if (md.forces && readForces(line->str, forces, natom)) visu_node_values_vector_set (visu_data_atomic_getForces(VISU_DATA_ATOMIC(data), TRUE), forces); continue; } pos = 0; sscanf(line->str, "%lf %lf %lf %s %n", &xu, &yu, &zu, nomloc, &pos); nomloc[8] = '\0'; type = visu_element_lookup(nomloc); if (!type) { g_warning("The input file must" " have been modified when loading since" " at the second reading the element '%s'" " seems to be new.\n", nomloc); g_object_unref(flux); g_string_free(line, TRUE); g_string_free(bufLine, TRUE); return 1; } xyz[0] = (float)xu; if (!(kw.bc & 1) && kw.reduced) xyz[0] /= boxGeometry[0]; xyz[1] = (float)yu; if (!(kw.bc & 2) && kw.reduced) xyz[1] /= boxGeometry[2]; xyz[2] = (float)zu; if (!(kw.bc & 4) && kw.reduced) xyz[2] /= boxGeometry[5]; visu_data_addNodeFromElement(VISU_DATA(data), type, xyz, kw.reduced); /* Store a possible comment. */ if (line->str[pos] != '\0') { nodeComments[i] = (line->str[pos] == '#')?g_strdup(line->str + pos + 1): g_strdup(line->str + pos); g_strstrip(nodeComments[i]); if (nodeComments[i][0] == '\0') { g_free(nodeComments[i]); nodeComments[i] = (gchar*)0; } else hasNodeComments = TRUE; } else nodeComments[i] = (gchar*)0; i++; } g_string_free(line, TRUE); g_string_free(bufLine, TRUE); g_object_unref(flux); /* In free boundary conditions, find the bounding box. */ if (kw.bc != VISU_BOX_PERIODIC) visu_data_setTightBox(VISU_DATA(data)); /* We apply the comments, if any. */ if (hasNodeComments) { labels = visu_data_getNodeLabels(VISU_DATA(data)); for (i = 0; i < natom; i++) if (nodeComments[i]) { if (nodeComments[i][0] == '{' && nodeComments[i][strlen(nodeComments[i]) - 1] == '}') visu_data_loader_yaml_setNodeProp (VISU_DATA(data), visu_node_array_getFromId(VISU_NODE_ARRAY(data), i), nodeComments[i]); else visu_node_values_string_setAt (labels, visu_node_array_getFromId(VISU_NODE_ARRAY(data), i), nodeComments[i]); g_free(nodeComments[i]); } } g_free(nodeComments); /* Add some other meta data. */ if (md.totalEnergy != 999.) g_object_set(G_OBJECT(data), "totalEnergy", md.totalEnergy, NULL); if (dcoord) g_array_free(dcoord, TRUE); if (forces) g_array_free(forces, TRUE); DBG_fprintf(stderr, "Atomic ASCII: parse done.\n"); return 0; } v_sim-3.8.0/src/loaders/atomic_ascii.h000066400000000000000000000035471370110300500176530ustar00rootroot00000000000000/* EXTRAITS DE LA LICENCE Copyright CEA, contributeurs : Luc BILLARD et Damien CALISTE, laboratoire L_Sim, (2001-2005) Adresse mèl : BILLARD, non joignable par mèl ; CALISTE, damien P caliste AT cea P fr. Ce logiciel est un programme informatique servant à visualiser des structures atomiques dans un rendu pseudo-3D. Ce logiciel est régi par la licence CeCILL soumise au droit français et respectant les principes de diffusion des logiciels libres. Vous pouvez utiliser, modifier et/ou redistribuer ce programme sous les conditions de la licence CeCILL telle que diffusée par le CEA, le CNRS et l'INRIA sur le site "http://www.cecill.info". Le fait que vous puissiez accéder à cet en-tête signifie que vous avez pris connaissance de la licence CeCILL, et que vous en avez accepté les termes (cf. le fichier Documentation/licence.fr.txt fourni avec ce logiciel). */ /* LICENCE SUM UP Copyright CEA, contributors : Luc BILLARD et Damien CALISTE, laboratoire L_Sim, (2001-2005) E-mail address: BILLARD, not reachable any more ; CALISTE, damien P caliste AT cea P fr. This software is a computer program whose purpose is to visualize atomic configurations in 3D. This software is governed by the CeCILL license under French law and abiding by the rules of distribution of free software. You can use, modify and/ or redistribute the software under the terms of the CeCILL license as circulated by CEA, CNRS and INRIA at the following URL "http://www.cecill.info". The fact that you are presently reading this means that you have had knowledge of the CeCILL license and that you accept its terms. You can find a copy of this licence shipped with this software at Documentation/licence.en.txt. */ #ifndef ATOMIC_ASCII_H #define ATOMIC_ASCII_H #include VisuDataLoader* visu_data_loader_ascii_getStatic(void); #endif v_sim-3.8.0/src/loaders/atomic_d3.c000066400000000000000000000431741370110300500170640ustar00rootroot00000000000000/* EXTRAITS DE LA LICENCE Copyright CEA, contributeurs : Luc BILLARD et Damien CALISTE, laboratoire L_Sim, (2001-2005) Adresse mèl : BILLARD, non joignable par mèl ; CALISTE, damien P caliste AT cea P fr. Ce logiciel est un programme informatique servant à visualiser des structures atomiques dans un rendu pseudo-3D. Ce logiciel est régi par la licence CeCILL soumise au droit français et respectant les principes de diffusion des logiciels libres. Vous pouvez utiliser, modifier et/ou redistribuer ce programme sous les conditions de la licence CeCILL telle que diffusée par le CEA, le CNRS et l'INRIA sur le site "http://www.cecill.info". Le fait que vous puissiez accéder à cet en-tête signifie que vous avez pris connaissance de la licence CeCILL, et que vous en avez accepté les termes (cf. le fichier Documentation/licence.fr.txt fourni avec ce logiciel). */ /* LICENCE SUM UP Copyright CEA, contributors : Luc BILLARD et Damien CALISTE, laboratoire L_Sim, (2001-2005) E-mail address: BILLARD, not reachable any more ; CALISTE, damien P caliste AT cea P fr. This software is a computer program whose purpose is to visualize atomic configurations in 3D. This software is governed by the CeCILL license under French law and abiding by the rules of distribution of free software. You can use, modify and/ or redistribute the software under the terms of the CeCILL license as circulated by CEA, CNRS and INRIA at the following URL "http://www.cecill.info". The fact that you are presently reading this means that you have had knowledge of the CeCILL license and that you accept its terms. You can find a copy of this licence shipped with this software at Documentation/licence.en.txt. */ #include #include "atomic_d3.h" #include #include #include /** * SECTION:atomic_d3 * @short_description: Method to load d3 position file. * * D3 format is a binary format to store elements and their * position. */ static gboolean read_nattyp_natnom(ToolFiles *flux, GError **error, ToolFortranEndianId endian, gboolean store); static int free_read_d3(); static int read_d3_file(VisuDataLoadable *data, ToolFiles *flux, int set, GError **error); static guint nat, ntypeD3; static GArray *nattyp; static char **natnom; static GArray *x, *y, *z; static GList *lst; static VisuDataLoader *d3Loader = NULL; static gboolean loadD3(VisuDataLoader *loader, VisuDataLoadable *data, guint type, guint nSet, GCancellable *cancel, GError **error); /******************************************************************************/ /** * visu_data_loader_d3_getStatic: * * Retrieve the instance of the atomic loader used to parse d3 files. * * Since: 3.8 * * Returns: (transfer none): a #VisuDataLoader owned by V_Sim. **/ VisuDataLoader* visu_data_loader_d3_getStatic(void) { const gchar *typeD3[] = {"*.d3", "*-posi.d3", "*.d3-posi", (char*)0}; if (d3Loader) return d3Loader; return d3Loader = visu_data_loader_new(_("Native binary format"), typeD3, FALSE, loadD3, 10); } /******************************************************************************/ static gboolean read_nattyp_natnom(ToolFiles *flux, GError **error, ToolFortranEndianId endian, gboolean store) { guint k; gboolean valid; gsize ncheck; gchar *name; g_return_val_if_fail((store && !nattyp && natnom) || !store, FALSE); DBG_fprintf(stderr, "Atomic D3: read nattyp and nattom (%d).\n", store); if (!tool_files_fortran_readFlag(flux, &ncheck, endian, error)) return FALSE; valid = tool_files_fortran_readIntegerArray(flux, store ? &nattyp : NULL, ntypeD3, endian, FALSE, error); if (!valid) return valid; for(k = 0; k < ntypeD3; k++) { name = (store)?natnom[k]:(gchar*)0; valid = tool_files_fortran_readCharacter(flux, name, 8, error, endian, FALSE, store); if (!valid) return valid; if (store) { natnom[k][8] = '\0'; g_strchomp(natnom[k]); } } return tool_files_fortran_checkFlag(flux, ncheck, endian, error); } static gboolean read_npas_temps(ToolFiles *flux, GError **error, ToolFortranEndianId endian, guint *npas) { if (!tool_files_fortran_readInteger(flux, (gint*)npas, endian, error)) return FALSE; if (!tool_files_fortran_readDouble(flux, NULL, endian, error)) return FALSE; return TRUE; } static gboolean read_npas_temps_energy(ToolFiles *flux, GError **error, ToolFortranEndianId endian, guint *npas, gdouble *energy) { if (!tool_files_fortran_readInteger(flux, (gint*)npas, endian, error)) return FALSE; if (!tool_files_fortran_readDouble(flux, NULL, endian, error)) return FALSE; if (!tool_files_fortran_readDouble(flux, energy, endian, error)) return FALSE; return TRUE; } static gboolean read_unit(ToolFiles *flux, GError **error, ToolUnits *unit) { gchar units[17]; DBG_fprintf(stderr, "Atomic D3 : read units.\n"); if (tool_files_read(flux, units, 16, error) != G_IO_STATUS_NORMAL) return FALSE; units[16] = '\0'; g_strchomp(units); *unit = tool_physic_getUnitFromName(units); DBG_fprintf(stderr, " | '%s' (%d)\n", units, *unit); return TRUE; } static gboolean read_periodicity(ToolFiles *flux, GError **error, VisuBoxBoundaries *bc) { gchar periodicity[5]; DBG_fprintf(stderr, "Atomic D3 : read periodicity.\n"); if (tool_files_read(flux, periodicity, 4, error) != G_IO_STATUS_NORMAL) return FALSE; periodicity[4] = '\0'; g_strchomp(periodicity); DBG_fprintf(stderr, " | '%s'\n", periodicity); if (!g_ascii_strcasecmp(periodicity, "Oxyz")) *bc = VISU_BOX_PERIODIC; else if (!g_ascii_strcasecmp(periodicity, "Ozx")) *bc = VISU_BOX_SURFACE_ZX; else if (!g_ascii_strcasecmp(periodicity, "Oxy")) *bc = VISU_BOX_SURFACE_XY; else if (!g_ascii_strcasecmp(periodicity, "Oyz")) *bc = VISU_BOX_SURFACE_YZ; else if (!g_ascii_strcasecmp(periodicity, "Ox")) *bc = VISU_BOX_WIRE_X; else if (!g_ascii_strcasecmp(periodicity, "Oy")) *bc = VISU_BOX_WIRE_Y; else if (!g_ascii_strcasecmp(periodicity, "Oz")) *bc = VISU_BOX_WIRE_Z; else if (!g_ascii_strcasecmp(periodicity, "O")) *bc = VISU_BOX_FREE; else *error = g_error_new(VISU_DATA_LOADABLE_ERROR, DATA_LOADABLE_ERROR_FORMAT, _("unknwon peridicity flag '%s'"), periodicity); return (*error == (GError*)0); } /******************************************************************************/ static gboolean loadD3(VisuDataLoader *loader _U_, VisuDataLoadable *data, guint type, guint nSet, GCancellable *cancel _U_, GError **error) { int res; ToolFiles *readFrom; g_return_val_if_fail(error && *error == (GError*)0, FALSE); readFrom = tool_files_new(); if (!tool_files_fortran_open(readFrom, visu_data_loadable_getFilename(data, type), error)) return FALSE; res = read_d3_file(data, readFrom, nSet, error); g_object_unref(G_OBJECT(readFrom)); if (res < 0) /* The file is not a D3 file. */ return FALSE; else if (res > 0) /* The file is a D3 file but some errors occured. */ return TRUE; /* Everything is OK. */ *error = (GError*)0; return TRUE; } static int read_d3_file(VisuDataLoadable *data, ToolFiles *flux, int set, GError **error) { int iSet; char title[129]; guint snat; VisuElement *type; GArray *types; gchar *infoUTF8; gboolean valid, store, readDouble, storeDouble; ToolFortranEndianId endian; guint i, j; gsize ncheck; GArray *boxGeometry; float xyz[3]; GList *tmpLst; VisuBox *box; ToolUnits unit; VisuBoxBoundaries bc; gdouble energy; guint npas; g_return_val_if_fail(error && *error == (GError*)0, FALSE); natnom = (gchar**)0; nattyp = (GArray*)0; x = (GArray*)0; y = (GArray*)0; z = (GArray*)0; iSet = 0; storeDouble = TRUE; unit = TOOL_UNITS_UNDEFINED; bc = VISU_BOX_PERIODIC; /* Check the first element to find the endianness. The first element is an int equal to 128. */ DBG_fprintf(stderr, "Atomic D3 : test for endianness.\n"); if (!tool_files_fortran_testEndianness(flux, 128, &endian)) return -1; /* We read the set number @set and store the number of sets in nSet. */ lst = (GList*)0; do { store = (iSet == set); /* TITLE */ DBG_fprintf(stderr, "Atomic D3 : read title.\n"); if (tool_files_read(flux, title, 128, error) != G_IO_STATUS_NORMAL) return free_read_d3(); if (!tool_files_fortran_checkFlag(flux, 128, endian, error)) return free_read_d3(); title[128] = '\0'; g_strchomp(title); DBG_fprintf(stderr, " | '%s'\n", title); /* NPAS-TEMPS(-ENERGY) (optional) */ energy = G_MAXDOUBLE; npas = G_MAXUINT; valid = tool_files_fortran_readFlag(flux, &ncheck, endian, error); if (!valid) return free_read_d3(); if (ncheck == 12) valid = read_npas_temps(flux, error, endian, &npas); else if (ncheck == 16) valid = read_npas_temps_energy(flux, error, endian, &npas, &energy); else { valid = (ncheck == 8); if (!valid) g_set_error_literal(error, VISU_DATA_LOADABLE_ERROR, DATA_LOADABLE_ERROR_FORMAT, _("wrong d3 syntax, awaiting Nat and Ntypes.")); } if (!valid) return free_read_d3(); if (ncheck != 8 && !tool_files_fortran_checkFlag(flux, ncheck, endian, error)) return free_read_d3(); readDouble = (npas == G_MAXUINT); if (store && energy != G_MAXDOUBLE) g_object_set(G_OBJECT(data), "totalEnergy", energy, NULL); if (npas != G_MAXUINT) lst = g_list_prepend(lst, g_strdup_printf("%04d - %s", npas, title)); else lst = g_list_prepend(lst, g_strdup(title)); /* NAT-NTYPE */ DBG_fprintf(stderr, "Atomic D3 : read nat and ntype.\n"); valid = tool_files_fortran_readInteger(flux, (gint*)&nat, endian, error); if (!valid) return free_read_d3(); valid = tool_files_fortran_readInteger(flux, (gint*)&ntypeD3, endian, error); if (!valid) return free_read_d3(); if (!tool_files_fortran_checkFlag(flux, 8, endian, error)) return free_read_d3(); DBG_fprintf(stderr, " | %d %d\n", nat, ntypeD3); /* NATI-NOM */ if (store) { DBG_fprintf(stderr, " | store nattyp and natom.\n"); natnom = g_malloc(ntypeD3 * sizeof(char *)); for(i=0; imessage); return free_read_d3(); } /* X */ if (readDouble) valid = tool_files_fortran_readDoubleArray(flux, store ? &x : NULL, nat, endian, TRUE, error); else valid = tool_files_fortran_readRealArray(flux, store ? &x : NULL, nat, endian, TRUE, error); if (!valid) { DBG_fprintf(stderr, "! invalid x coordinates '%s' (%d).\n", (*error)->message, readDouble); return free_read_d3(); } /* Y */ if (readDouble) valid = tool_files_fortran_readDoubleArray(flux, store ? &y : NULL, nat, endian, TRUE, error); else valid = tool_files_fortran_readRealArray(flux, store ? &y : NULL, nat, endian, TRUE, error); if (!valid) { DBG_fprintf(stderr, "! invalid y coordinates '%s'.\n", (*error)->message); return free_read_d3(); } /* Z */ if (readDouble) valid = tool_files_fortran_readDoubleArray(flux, store ? &z : NULL, nat, endian, TRUE, error); else valid = tool_files_fortran_readRealArray(flux, store ? &z : NULL, nat, endian, TRUE, error); if (!valid) { DBG_fprintf(stderr, "! invalid z coordinates '%s'.\n", (*error)->message); return free_read_d3(); } iSet += 1; /* Go to the next fortran flag holding 128. */ do { /* There is a strange thing with Fortran file, they seems to finish with '0x0a' character... */ valid = tool_files_fortran_readFlag(flux, &ncheck, endian, error); if (!valid) g_clear_error(error); else if (ncheck == 16) { /* Special case of units. */ if (!read_unit(flux, error, &unit) || !tool_files_fortran_checkFlag(flux, ncheck, endian, error)) return free_read_d3(); } else if (ncheck == 4) { /* Special case of periodicity. */ if (!read_periodicity(flux, error, &bc) || !tool_files_fortran_checkFlag(flux, ncheck, endian, error)) return free_read_d3(); } else if (ncheck != 128) { if (tool_files_skip(flux, sizeof(gchar) * ncheck, error) != G_IO_STATUS_NORMAL || !tool_files_fortran_checkFlag(flux, ncheck, endian, error)) return free_read_d3(); } valid = valid && (ncheck == 128); } while (!tool_files_atEnd(flux) && !valid); } while (!tool_files_atEnd(flux) && valid); lst = g_list_reverse(lst); if(iSet < set) { *error = g_error_new(VISU_DATA_LOADABLE_ERROR, DATA_LOADABLE_ERROR_FORMAT, _("input file has no dataset number %d" " (%d have been read).\n"), set + 1, iSet); return free_read_d3(); } DBG_fprintf(stderr, "Atomic d3 : nat = %d | ntypeD3 = %d\n", nat, ntypeD3); for(i = 0; i < ntypeD3; i++) DBG_fprintf(stderr, " | natnom %d = '%s', nb %d\n", i, natnom[i], g_array_index(nattyp, guint, i)); DBG_fprintf(stderr, " | box = %g %g %g\n", g_array_index(boxGeometry, gdouble, 0), g_array_index(boxGeometry, gdouble, 1), g_array_index(boxGeometry, gdouble, 2)); DBG_fprintf(stderr, " | %g %g %g\n", g_array_index(boxGeometry, gdouble, 3), g_array_index(boxGeometry, gdouble, 4), g_array_index(boxGeometry, gdouble, 5)); /* Now we have all the element and the number of atoms per element. So we allocate the memory. */ types = g_array_sized_new(FALSE, FALSE, sizeof(VisuElement*), ntypeD3); for(i = 0; i < ntypeD3; i++) { /* adding nomloc to the hashtable */ type = visu_element_retrieveFromName(natnom[i], (gboolean*)0); if (!type) { g_warning("Cannot create a new type for '%s'\n", natnom[i]); return 1; } g_array_insert_val(types, i, type); } DBG_fprintf(stderr, " | begin to transfer data to VisuData.\n"); /* Begin the storage into VisuData. */ visu_data_loadable_setNSets(data, iSet); /* Set the commentaries. */ for (iSet = 0, tmpLst = lst; tmpLst; iSet++, tmpLst = g_list_next(tmpLst)) { infoUTF8 = g_locale_to_utf8((gchar*)tmpLst->data, -1, NULL, NULL, NULL); if (infoUTF8) { visu_data_loadable_setSetLabel(data, infoUTF8, iSet); g_free(infoUTF8); } else g_warning("Can't convert '%s' to UTF8.\n", (gchar*)tmpLst->data); } visu_node_array_allocate(VISU_NODE_ARRAY(data), types, nattyp); g_array_free(types, TRUE); nat = 0; for (i = 0; i < ntypeD3; i++) { for (j = 0; j < g_array_index(nattyp, guint, i); j++) { xyz[0] = storeDouble ? g_array_index(x, double, nat) : g_array_index(x, float, nat); xyz[1] = storeDouble ? g_array_index(y, double, nat) : g_array_index(y, float, nat); xyz[2] = storeDouble ? g_array_index(z, double, nat) : g_array_index(z, float, nat); visu_data_addNodeFromIndex(VISU_DATA(data), i, xyz, FALSE); nat++; } } /* We finish with the geometry. */ box = visu_box_new((double*)boxGeometry->data, bc); g_array_unref(boxGeometry); visu_box_setUnit(box, unit); visu_boxed_setBox(VISU_BOXED(data), VISU_BOXED(box)); g_object_unref(box); free_read_d3(); return 0; } static int free_read_d3() { guint i; DBG_fprintf(stderr, "Atomic d3: freeing tmp variables.\n"); if (natnom) { for(i = 0; i < ntypeD3; i++) if (natnom[i]) g_free(natnom[i]); g_free(natnom); } if(nattyp) g_array_free(nattyp, TRUE); if (x) g_array_unref(x); if (y) g_array_unref(y); if (z) g_array_unref(z); if (lst) g_list_free_full(lst, g_free); return 1; } /******************************************************************************/ /******************************************************************************/ v_sim-3.8.0/src/loaders/atomic_d3.h000066400000000000000000000035361370110300500170670ustar00rootroot00000000000000/* EXTRAITS DE LA LICENCE Copyright CEA, contributeurs : Luc BILLARD et Damien CALISTE, laboratoire L_Sim, (2001-2005) Adresse mèl : BILLARD, non joignable par mèl ; CALISTE, damien P caliste AT cea P fr. Ce logiciel est un programme informatique servant à visualiser des structures atomiques dans un rendu pseudo-3D. Ce logiciel est régi par la licence CeCILL soumise au droit français et respectant les principes de diffusion des logiciels libres. Vous pouvez utiliser, modifier et/ou redistribuer ce programme sous les conditions de la licence CeCILL telle que diffusée par le CEA, le CNRS et l'INRIA sur le site "http://www.cecill.info". Le fait que vous puissiez accéder à cet en-tête signifie que vous avez pris connaissance de la licence CeCILL, et que vous en avez accepté les termes (cf. le fichier Documentation/licence.fr.txt fourni avec ce logiciel). */ /* LICENCE SUM UP Copyright CEA, contributors : Luc BILLARD et Damien CALISTE, laboratoire L_Sim, (2001-2005) E-mail address: BILLARD, not reachable any more ; CALISTE, damien P caliste AT cea P fr. This software is a computer program whose purpose is to visualize atomic configurations in 3D. This software is governed by the CeCILL license under French law and abiding by the rules of distribution of free software. You can use, modify and/ or redistribute the software under the terms of the CeCILL license as circulated by CEA, CNRS and INRIA at the following URL "http://www.cecill.info". The fact that you are presently reading this means that you have had knowledge of the CeCILL license and that you accept its terms. You can find a copy of this licence shipped with this software at Documentation/licence.en.txt. */ #ifndef ATOMIC_D3_H #define ATOMIC_D3_H #include VisuDataLoader* visu_data_loader_d3_getStatic(void); #endif v_sim-3.8.0/src/loaders/atomic_xyz.c000066400000000000000000000570111370110300500174030ustar00rootroot00000000000000/* EXTRAITS DE LA LICENCE Copyright CEA, contributeurs : Luc BILLARD et Damien CALISTE, laboratoire L_Sim, (2001-2005) Adresse mèl : BILLARD, non joignable par mèl ; CALISTE, damien P caliste AT cea P fr. Ce logiciel est un programme informatique servant à visualiser des structures atomiques dans un rendu pseudo-3D. Ce logiciel est régi par la licence CeCILL soumise au droit français et respectant les principes de diffusion des logiciels libres. Vous pouvez utiliser, modifier et/ou redistribuer ce programme sous les conditions de la licence CeCILL telle que diffusée par le CEA, le CNRS et l'INRIA sur le site "http://www.cecill.info". Le fait que vous puissiez accéder à cet en-tête signifie que vous avez pris connaissance de la licence CeCILL, et que vous en avez accepté les termes (cf. le fichier Documentation/licence.fr.txt fourni avec ce logiciel). */ /* LICENCE SUM UP Copyright CEA, contributors : Luc BILLARD et Damien CALISTE, laboratoire L_Sim, (2001-2005) E-mail address: BILLARD, not reachable any more ; CALISTE, damien P caliste AT cea P fr. This software is a computer program whose purpose is to visualize atomic configurations in 3D. This software is governed by the CeCILL license under French law and abiding by the rules of distribution of free software. You can use, modify and/ or redistribute the software under the terms of the CeCILL license as circulated by CEA, CNRS and INRIA at the following URL "http://www.cecill.info". The fact that you are presently reading this means that you have had knowledge of the CeCILL license and that you accept its terms. You can find a copy of this licence shipped with this software at Documentation/licence.en.txt. */ #include "atomic_xyz.h" #include #include #include #include "atomic_yaml.h" #include #include #include #include #include /*#define TESTNEW*/ /** * SECTION:atomic_xyz * @short_description: Method to load xyz position file. * * XYZ formats are plain text format to store atomic * positions. This format is quite simple, first line must contain the * number of element, then * the second usually store a commentary (but this is not required), * then all lines that are not beginning with a '#' are tried to match * "label x y z":. If succeed a node is added, if not, the next line * is read as much time as specified on first line. This scheme can be * repeated as much time as required to store animation for instance. */ static VisuDataLoader *xyzLoader = NULL; static gboolean loadXyz(VisuDataLoader *self, VisuDataLoadable *data, guint type, guint nSet, GCancellable *cancel, GError **error); static int read_Xyz_File(VisuDataLoadable *data, guint iType, guint nSet, GError **error); #ifdef TESTNEW static gboolean test_Routine(float* coords, float* dcoord, VisuElement **nodeTypes); #endif /******************************************************************************/ /** * visu_data_loader_xyz_getStatic: * * Retrieve the instance of the atomic loader used to parse XYZ files. * * Since: 3.8 * * Returns: (transfer none): a #VisuDataLoader owned by V_Sim. **/ VisuDataLoader* visu_data_loader_xyz_getStatic(void) { const gchar *typeXYZ[] = {"*.xyz", (char*)0}; if (xyzLoader) return xyzLoader; return xyzLoader = visu_data_loader_new(_("'Element x y z' format"), typeXYZ, FALSE, loadXyz, 100); } static gboolean loadXyz(VisuDataLoader *self _U_, VisuDataLoadable *data, guint type, guint nSet, GCancellable *cancel _U_, GError **error) { int res; g_return_val_if_fail(error && *error == (GError*)0, FALSE); res = read_Xyz_File(data, type, nSet, error); if (res < 0) { g_clear_error(error); /* The file is not a XYZ file. */ return FALSE; } else if (res > 0) /* The file is a XYZ file but some errors occured. */ return TRUE; /* Everything is OK. */ *error = (GError*)0; return TRUE; } static gboolean readNextLine(ToolFiles *flux, gboolean mandatory, GString *line, GIOStatus *status, GError **error) { /*if there are commentaries */ do { *status = tool_files_read_line_string(flux, line, NULL, error); if (*status != G_IO_STATUS_NORMAL) { if (*status == G_IO_STATUS_EOF) { if (*error) g_error_free(*error); *error = (GError*)0; return !mandatory; } return FALSE; }; g_strstrip(line->str); } while (line->str[0] == '#' || line->str[0] == '!' || line->str[0] == '\0'); return TRUE; } static ToolUnits readUnit(const gchar *line) { ToolUnits unit; gchar *tmpStr; guint nNodes; unit = TOOL_UNITS_UNDEFINED; tmpStr = g_strdup(line); if (sscanf(line, "%u %s", &nNodes, tmpStr) == 2) unit = tool_physic_getUnitFromName(g_strstrip(tmpStr)); DBG_fprintf(stderr, " | units for the set is '%s' -> %d.\n", tmpStr, unit); g_free(tmpStr); return unit; } static gboolean readReduced(const gchar *line) { gboolean reduced; gchar *tmpStr; guint nNodes; reduced = FALSE; tmpStr = g_strdup(line); if (sscanf(line, "%u %s", &nNodes, tmpStr) == 2) reduced = (!g_ascii_strcasecmp(tmpStr, "reduced")); DBG_fprintf(stderr, " | coordinates are reduced %d.\n", reduced); g_free(tmpStr); return reduced; } static float readEnergy(const gchar *line) { gchar *tmpStr; guint nNodes; float ene; tmpStr = g_strdup(line); if (sscanf(line, "%u %s %f", &nNodes, tmpStr, &ene) != 3) ene = G_MAXFLOAT; else ene *= 27.21138386; g_free(tmpStr); DBG_fprintf(stderr, " | total energy for the set is %geV.\n", ene); return ene; } static VisuBoxBoundaries readBoundary(const gchar *line, const gchar *keyword, VisuBoxBoundaries bc, gdouble box[3]) { gchar *kwd; kwd = strstr(line, keyword); if (kwd && sscanf(kwd + 8, "%lf %lf %lf", box, box + 1, box + 2) == 3) return bc; return VISU_BOX_FREE; } static void readFree(ToolFiles *flux, GList *lst, VisuDataLoaderIter *iter, GString *line, VisuElement **nodeTypes, float *coords, GArray *dcoord, GArray *forces, GList *labels) { GList *tmpLst; if (flux) g_object_unref(flux); if (line) g_string_free(line, TRUE); visu_data_loader_iter_unref(iter); for (tmpLst = lst; tmpLst; tmpLst = g_list_next(tmpLst)) g_free(tmpLst->data); if (lst) g_list_free(lst); if (nodeTypes) g_free(nodeTypes); if (coords) g_free(coords); if (dcoord) g_array_free(dcoord, TRUE); if (forces) g_array_free(forces, TRUE); for (tmpLst = labels; tmpLst; tmpLst = g_list_next(tmpLst)) { tmpLst = g_list_next(tmpLst); g_free(tmpLst->data); } if (labels) g_list_free(labels); } static void readCoord(const gchar *line, guint iNodes, guint nNodes, float *xyz, GArray **dxyz, VisuDataLoaderIter *iter, VisuElement **nodeTypes, gchar **label, GError **error) { guint nbcolumn; float dxyz_[3]; gchar nomloc[TOOL_MAX_LINE_LENGTH]; VisuElement *type; int pos; *label = (gchar*)0; nbcolumn = sscanf(line, "%s %f %f %f %f %f %f", nomloc, xyz + 3 * iNodes + 0, xyz + 3 * iNodes + 1, xyz + 3 * iNodes + 2, dxyz_ + 0, dxyz_ + 1, dxyz_ + 2); if (nbcolumn < 4) { DBG_fprintf(stderr, "Atomic XYZ: can't read line values.\n"); *error = g_error_new(VISU_DATA_LOADABLE_ERROR, DATA_LOADABLE_ERROR_FORMAT, _("Wrong XYZ format, 'Atom X Y Z' awaited.")); } else if (((*dxyz) && nbcolumn != 7) || (!(*dxyz) && iNodes > 0 && nbcolumn == 7)) { DBG_fprintf(stderr, "Atomic XYZ: can't read vibration values.\n"); *error = g_error_new(VISU_DATA_LOADABLE_ERROR, DATA_LOADABLE_ERROR_FORMAT, _("Wrong XYZ + vibration format," " 'Atom X Y Z vx vy vz' awaited.")); } if (nbcolumn == 7) { if (!(*dxyz)) *dxyz = g_array_sized_new(FALSE, FALSE, sizeof(float), 3 * nNodes); g_array_append_vals(*dxyz, dxyz_, 3); } if (*error) return; nomloc[8] = '\0'; type = visu_element_retrieveFromName(nomloc, (gboolean*)0); nodeTypes[iNodes] = type; visu_data_loader_iter_addNode(iter, type); /* Store a possible comment. */ pos = 0; if (nbcolumn == 4) sscanf(line, "%s %f %f %f %n", nomloc, xyz + 3 * iNodes + 0, xyz + 3 * iNodes + 1, xyz + 3 * iNodes + 2, &pos); else sscanf(line, "%s %f %f %f %f %f %f %n", nomloc, xyz + 3 * iNodes + 0, xyz + 3 * iNodes + 1, xyz + 3 * iNodes + 2, dxyz_ + 0, dxyz_ + 1, dxyz_ + 2, &pos); if (line[pos] != '\0') { *label = g_strdup(line + pos + ((line[pos] == '#')?1:0)); g_strstrip(*label); if ((*label)[0] == '\0') { g_free(*label); *label = (gchar*)0; } } } static void readForces(ToolFiles *flux, GString *line, guint nNodes, GArray **forces, GIOStatus *status, GError **error) { gfloat fxyz[3]; guint iNodes; gchar nomloc[TOOL_MAX_LINE_LENGTH]; #define FORCES_TAG "forces" if (!g_ascii_strncasecmp(g_strchug(line->str), FORCES_TAG, sizeof(FORCES_TAG) - 1)) { DBG_fprintf(stderr, "Atomic XYZ: found a forces tag.\n"); if (forces) *forces = g_array_sized_new(FALSE, FALSE, sizeof(float), nNodes * 3); for (iNodes = 0; iNodes < nNodes && *status == G_IO_STATUS_NORMAL; iNodes++) { if (!readNextLine(flux, TRUE, line, status, error)) { *error = g_error_new(VISU_DATA_LOADABLE_ERROR, DATA_LOADABLE_ERROR_FORMAT, _("Missing forces (%d read but" " %d declared).\n"), iNodes, nNodes); return; } if (forces && sscanf(line->str, "%s %f %f %f", nomloc, fxyz + 0, fxyz + 1, fxyz + 2) != 4) { *error = g_error_new(VISU_DATA_LOADABLE_ERROR, DATA_LOADABLE_ERROR_FORMAT, _("Cannot read forces in '%s'.\n"), line->str); return; } if (forces) g_array_append_vals(*forces, fxyz, 3); } /* Eat blank or commentary lines between Sets */ readNextLine(flux, FALSE, line, status, error); } } /******************************************************************************/ static int read_Xyz_File(VisuDataLoadable *data, guint iType, guint nSet, GError **error) { GIOStatus status; ToolFiles *flux; GString *line; guint i; int res, nNodes, iNodes, nNodesSet; guint nSets; float *coords; GArray *forces, *dcoord; gchar *infoUTF8; GList *lst, *tmpLst; VisuDataLoaderIter *iter; float qpt[3], omega, totalEnergy; double box[3], boxGeometry[6]; ToolUnits unit; VisuElement **nodeTypes; guint natom; gchar *pt, *label; VisuBoxBoundaries bc; gboolean reduced; GList *nodeComments; VisuBox *boxObj; VisuVibration *vib; VisuNodeValuesString *labels; VisuNode *node; #if DEBUG == 1 GTimer *timer, *readTimer, *internalTimer; gulong fractionTimer; float time1, time2, time3; #endif flux = tool_files_new(); DBG_fprintf(stderr, "Atomic xyz: reading file as an xyz file.\n"); if (!tool_files_open(flux, visu_data_loadable_getFilename(data, iType), error)) { g_object_unref(flux); return -1; } line = g_string_new(""); unit = TOOL_UNITS_UNDEFINED; reduced = FALSE; /* Storage of number of elements per types. */ iter = visu_data_loader_iter_new(); /* We read the file completely to find the number of sets of points and we store only the one corresponding to @nSet. */ #if DEBUG == 1 timer = g_timer_new(); readTimer = g_timer_new(); internalTimer = g_timer_new(); g_timer_start(timer); g_timer_start(internalTimer); g_timer_stop(internalTimer); time3 = 0.f; #endif nSets = 0; nNodesSet = 0; nodeTypes = (VisuElement**)0; coords = (float*)0; dcoord = (GArray*)0; forces = (GArray*)0; lst = (GList*)0; nodeComments = (GList*)0; totalEnergy = G_MAXFLOAT; status = tool_files_read_line_string(flux, line, NULL, error); if ( status != G_IO_STATUS_NORMAL ) { readFree(flux, lst, iter, line, nodeTypes, coords, dcoord, forces, nodeComments); return -1; } while( status != ( G_IO_STATUS_EOF ) ) { DBG_fprintf(stderr, "Atomic xyz: read node set number %d (%d).\n", nSets, nSet); /*The Number Of Nodes*/ nNodes=0; DBG_fprintf(stderr, "Atomic xyz: get n atoms from '%s'.\n", line->str); res = sscanf(line->str, "%d", &nNodes); if ( res != 1 ) { *error = g_error_new(VISU_DATA_LOADABLE_ERROR, DATA_LOADABLE_ERROR_FORMAT, _("Wrong XYZ format, no number of atoms on line.\n '%s'"), line->str); readFree(flux, lst, iter, line, nodeTypes, coords, dcoord, forces, nodeComments); return (nSets > 0)?1:-1; } DBG_fprintf(stderr, " | number of declared nodes is %d.\n", nNodes); #if DEBUG == 1 if (nSets == nSet) g_timer_start(readTimer); else g_timer_continue(internalTimer); #endif if (nSets == nSet) { unit = readUnit(line->str); reduced = readReduced(line->str); totalEnergy = readEnergy(line->str); } /*The Commentary line */ if ( tool_files_read_line_string(flux, line, NULL, error) != G_IO_STATUS_NORMAL ) { readFree(flux, lst, iter, line, nodeTypes, coords, dcoord, forces, nodeComments); return -2; } g_strstrip(line->str); DBG_fprintf(stderr, " | set the commentary to '%s'.\n", line->str); if (line->str[0] == '#') infoUTF8 = g_locale_to_utf8(line->str + 1, -1, NULL, NULL, NULL); else infoUTF8 = g_locale_to_utf8(line->str, -1, NULL, NULL, NULL); if (infoUTF8) lst = g_list_append(lst, infoUTF8); else g_warning("Can't convert '%s' to UTF8.\n", line->str); /* The Data Lines.*/ if (nSets == nSet) { nNodesSet = nNodes; nodeTypes = g_malloc(sizeof(VisuElement*) * nNodes); coords = g_malloc(sizeof(float) * 3 * nNodes); dcoord = (GArray*)0; forces = (GArray*)0; qpt[0] = 0.f; qpt[1] = 0.f; qpt[2] = 0.f; } status = G_IO_STATUS_NORMAL; DBG_fprintf(stderr, " | read node coordinates.\n"); for (iNodes = 0; iNodes < nNodes && status == G_IO_STATUS_NORMAL; iNodes++) { if (!readNextLine(flux, TRUE, line, &status, error)) { *error = g_error_new(VISU_DATA_LOADABLE_ERROR, DATA_LOADABLE_ERROR_FORMAT, _("Missing coordinates (%d read but" " %d declared).\n"), iNodes, nNodes); readFree(flux, lst, iter, line, nodeTypes, coords, dcoord, forces, nodeComments); return 1; } /* if Reading the nSets, parse the data */ if (nSets == nSet) { /* Read the coordinates. */ readCoord(line->str, iNodes, nNodes, coords, &dcoord, iter, nodeTypes, &label, error); if (*error) { readFree(flux, lst, iter, line, nodeTypes, coords, dcoord, forces, nodeComments); return 1; } if (label) { nodeComments = g_list_prepend(nodeComments, label); nodeComments = g_list_prepend(nodeComments, GINT_TO_POINTER(iNodes)); } } #if DEBUG == 1 if (nSets == nSet) g_timer_stop(readTimer); else g_timer_stop(internalTimer); #endif } #if DEBUG == 1 g_timer_stop(timer); #endif /* Eat blank or commentary lines after coordinates. */ if (!readNextLine(flux, FALSE, line, &status, error)) { readFree(flux, lst, iter, line, nodeTypes, coords, dcoord, forces, nodeComments); return 1; } /* Maybe read forces (BigDFT addition). */ readForces(flux, line, nNodes, (nSets == nSet)?&forces:(GArray**)0, &status, error); if (*error) { readFree(flux, lst, iter, line, nodeTypes, coords, dcoord, forces, nodeComments); return 1; } /* OK, one set of nodes have been read. */ nSets++; DBG_fprintf(stderr, " | read OK %d %d.\n", status, G_IO_STATUS_EOF); } g_object_unref(flux); DBG_fprintf(stderr, " | finish to read the file.\n"); #if DEBUG == 1 g_timer_stop(timer); time1 = g_timer_elapsed(timer, &fractionTimer)/1e-6; time2 = g_timer_elapsed(readTimer, &fractionTimer)/1e-6; time3 = g_timer_elapsed(internalTimer, &fractionTimer)/1e-6; g_timer_destroy(readTimer); #endif #if DEBUG == 1 g_timer_start(timer); #endif /* Allocate the space for the nodes. */ natom = visu_data_loader_iter_allocate(iter, VISU_NODE_ARRAY(data)); if (natom <= 0) { readFree(NULL, lst, iter, line, nodeTypes, coords, dcoord, forces, nodeComments); *error = g_error_new(VISU_DATA_LOADABLE_ERROR, DATA_LOADABLE_ERROR_FORMAT, _("The file contains no atom coordinates.\n")); return 1; } visu_data_loader_iter_unref(iter); g_string_free(line, TRUE); /* Begin the storage into VisuData. */ visu_data_loadable_setNSets(data, nSets); /* Set the commentary. */ bc = VISU_BOX_FREE; for (i = 0, tmpLst = lst; i < nSets; i++, tmpLst = g_list_next(tmpLst)) { /* Try to see if the commentary contains some keywords. */ if (i == nSet) { if (bc == VISU_BOX_FREE) bc = readBoundary(tmpLst->data, "periodic", VISU_BOX_PERIODIC, box); if (bc == VISU_BOX_FREE) bc = readBoundary(tmpLst->data, "surface", VISU_BOX_SURFACE_ZX, box); DBG_fprintf(stderr, " | periodicity is %d (%g %g %g).\n", bc, box[0], box[1], box[2]); } visu_data_loadable_setSetLabel(data, (const gchar*)tmpLst->data, i); g_free(tmpLst->data); } g_list_free(lst); boxObj = (VisuBox*)0; if (bc != VISU_BOX_FREE) { DBG_fprintf(stderr, "Atomic xyz: the elements are in %fx%fx%f.\n", box[0], box[1], box[2]); boxGeometry[0] = box[0]; boxGeometry[1] = 0.; boxGeometry[2] = box[1]; boxGeometry[3] = 0.; boxGeometry[4] = 0.; boxGeometry[5] = box[2]; boxObj = visu_box_new(boxGeometry, bc); visu_boxed_setBox(VISU_BOXED(data), VISU_BOXED(boxObj)); g_object_unref(boxObj); } else { boxObj = visu_boxed_getBox(VISU_BOXED(data)); if (boxObj) visu_box_setBoundary(boxObj, bc); } /* Store the coordinates */ for(iNodes = 0; iNodes < nNodesSet; iNodes++) visu_data_addNodeFromElement(VISU_DATA(data), nodeTypes[iNodes], coords + 3 * iNodes, reduced); #ifdef TESTNEW if ( test_Routine(coords, dcoord, nodeTypes) == FALSE ) return -1; #endif g_free(nodeTypes); g_free(coords); if (bc != VISU_BOX_PERIODIC) boxObj = visu_data_setTightBox(VISU_DATA(data)); /* create the structure for phonons */ if (dcoord) { vib = visu_data_getVibration(VISU_DATA(data), nSets); for (i = 0; i < nSets; i++) { omega = 1.f; pt = strstr(visu_data_getDescription(VISU_DATA(data)), "freq="); if (pt) sscanf(pt + 5, "%f", &omega); if (omega < 0.) g_warning("Negative phonon frequency (%f).", omega); visu_vibration_setCharacteristic(vib, i, qpt, 0.f, omega); } visu_vibration_setDisplacements(vib, nSet, dcoord, FALSE); g_array_free(dcoord, TRUE); } /* Store the forces, if any. */ if (forces) { visu_node_values_vector_set (visu_data_atomic_getForces(VISU_DATA_ATOMIC(data), TRUE), forces); g_array_free(forces, TRUE); } /* We apply the comments, if any. */ labels = visu_data_getNodeLabels(VISU_DATA(data)); if (nodeComments) { for (tmpLst = nodeComments; tmpLst; tmpLst = g_list_next(g_list_next(tmpLst))) { node = visu_node_array_getFromId(VISU_NODE_ARRAY(data), GPOINTER_TO_INT(tmpLst->data)); label = (gchar*)tmpLst->next->data; if (label[0] == '{' && label[strlen(label) - 1] == '}') visu_data_loader_yaml_setNodeProp(VISU_DATA(data), node, label); else visu_node_values_string_setAt(labels, node, tmpLst->next->data); g_free(tmpLst->next->data); } g_list_free(nodeComments); } /* Add some other meta data. */ if (totalEnergy != G_MAXFLOAT) g_object_set(G_OBJECT(data), "totalEnergy", totalEnergy, NULL); DBG_fprintf(stderr, "Atomic XYZ: apply the box geometry and set the unit.\n"); visu_box_setUnit(boxObj, unit); #if DEBUG == 1 g_timer_stop(timer); fprintf(stderr, "Atomic XYZ: parse all file in %g micro-s.\n", time1); fprintf(stderr, "Atomic XYZ: parse coordinates in %g micro-s.\n", time2); fprintf(stderr, "Atomic XYZ: header parse in %g micro-s.\n", time3); fprintf(stderr, "Atomic XYZ: set all data in %g micro-s.\n", g_timer_elapsed(timer, &fractionTimer)/1e-6); g_timer_destroy(timer); #endif return 0; } /******************************************************************************/ #ifdef TESTNEW static gboolean test_Routine(float* coords, float* dcoord, VisuElement **nodeTypes) { float xyz[15] = {-0.440035, -0.000385, 2.123698, -1.765945, 0.000399, 2.377542, -2.249233, -0.001453, 3.679971, -1.338875, -0.004508, 4.739569, 0.024627, -0.005918, 4.466144}; float dxyz[15] = {0.001000, -0.151000, -0.002000, 0.001000, -0.175000, 0.000000, 0.003000, -0.198000, 0.001000, 0.005000, -0.183000, -0.000000, 0.005000, -0.146000, -0.003000}; char* waitedType[5]={ "N", "C", "C", "Co", "C"}; int i=0, j=0; /* Checking coordonates values and type values*/ DBG_fprintf(stderr, "+---------------------------------------------------------------+\n"); /* for each node : checking names and coordonates values using a difference.*/ while( (i<15) && (strcmp(nodeTypes[j]->name,waitedType[j])==0) && (ABS(coords[i]-xyz[i])<1e-6) && (ABS(dcoord[i]-dxyz[i])<1e-6) ) { if (i%3==0) { DBG_fprintf(stderr, "xyz parser : expected element: %s, found: %s \n", waitedType[j], nodeTypes[j]->name); DBG_fprintf(stderr, "xyz parser : expected x: %f, found: %f \t", xyz[i], coords[i]); DBG_fprintf(stderr, "xyz parser : expected dx: %f, found: %f \n", dxyz[i], dcoord[i]); } if (i%3==1) { DBG_fprintf(stderr, "xyz parser : expected y: %f, found: %f \t", xyz[i], coords[i]); DBG_fprintf(stderr, "xyz parser : expected dy: %f, found: %f \n", dxyz[i], dcoord[i]); } if (i%3==2) { DBG_fprintf(stderr, "xyz parser : expected z: %f, found: %f \t", xyz[i], coords[i]); DBG_fprintf(stderr, "xyz parser : expected dz: %f, found: %f \n", dxyz[i], dcoord[i]); j++; DBG_fprintf(stderr, "+---------------------------------------------------------------+\n"); } i++; } if (i!=15) { DBG_fprintf(stderr, "xyz parser : An error occured while reading the test file : node number %d encoutred an error \n", j+1); return FALSE; } else { DBG_fprintf(stderr, "xyz parser : parser ok ! \n"); return TRUE; } } #endif v_sim-3.8.0/src/loaders/atomic_xyz.h000066400000000000000000000035411370110300500174070ustar00rootroot00000000000000/* EXTRAITS DE LA LICENCE Copyright CEA, contributeurs : Luc BILLARD et Damien CALISTE, laboratoire L_Sim, (2001-2005) Adresse mèl : BILLARD, non joignable par mèl ; CALISTE, damien P caliste AT cea P fr. Ce logiciel est un programme informatique servant à visualiser des structures atomiques dans un rendu pseudo-3D. Ce logiciel est régi par la licence CeCILL soumise au droit français et respectant les principes de diffusion des logiciels libres. Vous pouvez utiliser, modifier et/ou redistribuer ce programme sous les conditions de la licence CeCILL telle que diffusée par le CEA, le CNRS et l'INRIA sur le site "http://www.cecill.info". Le fait que vous puissiez accéder à cet en-tête signifie que vous avez pris connaissance de la licence CeCILL, et que vous en avez accepté les termes (cf. le fichier Documentation/licence.fr.txt fourni avec ce logiciel). */ /* LICENCE SUM UP Copyright CEA, contributors : Luc BILLARD et Damien CALISTE, laboratoire L_Sim, (2001-2005) E-mail address: BILLARD, not reachable any more ; CALISTE, damien P caliste AT cea P fr. This software is a computer program whose purpose is to visualize atomic configurations in 3D. This software is governed by the CeCILL license under French law and abiding by the rules of distribution of free software. You can use, modify and/ or redistribute the software under the terms of the CeCILL license as circulated by CEA, CNRS and INRIA at the following URL "http://www.cecill.info". The fact that you are presently reading this means that you have had knowledge of the CeCILL license and that you accept its terms. You can find a copy of this licence shipped with this software at Documentation/licence.en.txt. */ #ifndef ATOMIC_XYZ_H #define ATOMIC_XYZ_H #include VisuDataLoader* visu_data_loader_xyz_getStatic(void); #endif v_sim-3.8.0/src/loaders/atomic_yaml.c000066400000000000000000000532521370110300500175160ustar00rootroot00000000000000/* EXTRAITS DE LA LICENCE Copyright CEA, contributeurs : Damien CALISTE, laboratoire L_Sim, (2001-2012) Adresse mèl : CALISTE, damien P caliste AT cea P fr. Ce logiciel est un programme informatique servant à visualiser des structures atomiques dans un rendu pseudo-3D. Ce logiciel est régi par la licence CeCILL soumise au droit français et respectant les principes de diffusion des logiciels libres. Vous pouvez utiliser, modifier et/ou redistribuer ce programme sous les conditions de la licence CeCILL telle que diffusée par le CEA, le CNRS et l'INRIA sur le site "http://www.cecill.info". Le fait que vous puissiez accéder à cet en-tête signifie que vous avez pris connaissance de la licence CeCILL, et que vous en avez accepté les termes (cf. le fichier Documentation/licence.fr.txt fourni avec ce logiciel). */ /* LICENCE SUM UP Copyright CEA, contributors : Damien CALISTE, laboratoire L_Sim, (2001-2012) E-mail address: CALISTE, damien P caliste AT cea P fr. This software is a computer program whose purpose is to visualize atomic configurations in 3D. This software is governed by the CeCILL license under French law and abiding by the rules of distribution of free software. You can use, modify and/ or redistribute the software under the terms of the CeCILL license as circulated by CEA, CNRS and INRIA at the following URL "http://www.cecill.info". The fact that you are presently reading this means that you have had knowledge of the CeCILL license and that you accept its terms. You can find a copy of this licence shipped with this software at Documentation/licence.en.txt. */ #define _ISOC99_SOURCE #include #include #include #include #include "atomic_yaml.h" #include #include #include #include #include #include #include #include #include #ifdef HAVE_YAML static VisuDataLoader *yamlLoader = NULL; static gboolean loadYaml(VisuDataLoader *self, VisuDataLoadable *data, guint iType, guint nSet, GCancellable *cancel, GError **error); #endif /** * SECTION:atomic_yaml * @short_description: Method to load YAML position file. * * YAML format is a plain text format to store atomic * positions. This format is defined and used by BigDFT. It has * meta-data available to store forces, total energy, units, boundary * conditions... */ /** * visu_data_loader_yaml_getStatic: * * Retrieve the instance of the atomic loader used to parse YAML files. * * Since: 3.8 * * Returns: (transfer none): a #VisuDataLoader owned by V_Sim. **/ VisuDataLoader* visu_data_loader_yaml_getStatic(void) { #ifdef HAVE_YAML const gchar *typeYAML[] = {"*.yaml", (char*)0}; if (yamlLoader) return yamlLoader; return yamlLoader = visu_data_loader_new(_("BigDFT YAML format"), typeYAML, FALSE, loadYaml, 110); #else g_message("No YAML support."); return (VisuDataLoader*)0; #endif } static void _setNodeProp(VisuData *data, VisuNode *node, const PosinpDict *dict) { guint j, k; VisuNodeValues *vals; GValue valI = G_VALUE_INIT; GValue valF = G_VALUE_INIT; GValue valS = G_VALUE_INIT; GValue valP = G_VALUE_INIT; gfloat *farr; if (!dict) return; g_value_init(&valI, G_TYPE_INT); g_value_init(&valF, G_TYPE_FLOAT); g_value_init(&valS, G_TYPE_STRING); g_value_init(&valP, G_TYPE_POINTER); for (j = 0; dict->items && dict->items[j].key && j < dict->len; j++) { if (!strcmp(dict->items[j].key, "frag")) vals = visu_data_getNodeProperties(data, _("Fragment")); else vals = visu_data_getNodeProperties(data, dict->items[j].key); if (!vals) { switch (dict->items[j].type) { case POSINP_TYPE_INT: vals = visu_node_values_new(VISU_NODE_ARRAY(data), dict->items[j].key, G_TYPE_INT, 1); break; case POSINP_TYPE_DBL: vals = VISU_NODE_VALUES (visu_node_values_farray_new(VISU_NODE_ARRAY(data), dict->items[j].key, 1)); break; case POSINP_TYPE_STR: vals = visu_node_values_new(VISU_NODE_ARRAY(data), dict->items[j].key, G_TYPE_STRING, 1); break; case POSINP_TYPE_DBL_ARR: if (dict->items[j].value.darr.len == 3) vals = VISU_NODE_VALUES (visu_node_values_vector_new(VISU_NODE_ARRAY(data), dict->items[j].key)); else vals = VISU_NODE_VALUES (visu_node_values_farray_new(VISU_NODE_ARRAY(data), dict->items[j].key, dict->items[j].value.darr.len)); break; case POSINP_TYPE_DICT: if (!strcmp(dict->items[j].key, "frag")) vals = VISU_NODE_VALUES (visu_node_values_frag_new(VISU_NODE_ARRAY(data), _("Fragment"))); break; default: vals = (VisuNodeValues*)0; break; } if (vals && !visu_data_addNodeProperties(data, vals)) g_warning("Cannot add node property '%s'.", visu_node_values_getLabel(vals)); } if (!vals) continue; switch (dict->items[j].type) { case POSINP_TYPE_INT: g_value_set_int(&valI, dict->items[j].value.ival); visu_node_values_setAt(vals, node, &valI); break; case POSINP_TYPE_DBL: g_value_set_float(&valF, dict->items[j].value.dval); visu_node_values_setAt(vals, node, &valF); break; case POSINP_TYPE_STR: g_value_set_static_string(&valS, dict->items[j].value.str); visu_node_values_setAt(vals, node, &valS); break; case POSINP_TYPE_DBL_ARR: if (VISU_IS_NODE_VALUES_VECTOR(vals)) visu_node_values_vector_setAtDbl (VISU_NODE_VALUES_VECTOR(vals), node, dict->items[j].value.darr.arr); else { farr = g_malloc0(sizeof(float) * visu_node_values_getDimension(vals)); g_value_set_pointer(&valP, farr); if (visu_node_values_getDimension(vals) == dict->items[j].value.darr.len) for (k = 0; k < dict->items[j].value.darr.len; k++) farr[k] = dict->items[j].value.darr.arr[k]; visu_node_values_setAt(vals, node, &valP); g_free(farr); } break; case POSINP_TYPE_DICT: if (VISU_IS_NODE_VALUES_FRAG(vals) && dict->items[j].value.dict.len >= 2 && dict->items[j].value.dict.items[0].key && dict->items[j].value.dict.items[0].type == POSINP_TYPE_STR && dict->items[j].value.dict.items[1].key && dict->items[j].value.dict.items[1].type == POSINP_TYPE_INT) { VisuNodeFragment frag; frag.label = dict->items[j].value.dict.items[0].value.str; frag.id = dict->items[j].value.dict.items[1].value.ival; visu_node_values_frag_setAt(VISU_NODE_VALUES_FRAG(vals), node, &frag); } break; default: break; } } } /** * visu_data_loader_yaml_setNodeProp: * @data: a #VisuData object. * @node: a #VisuNode structure. * @yamlStr: a YAML string. * * Parse @yamlStr and create #VisuNodeValues properties on @node. * * Since: 3.8 **/ void visu_data_loader_yaml_setNodeProp(VisuData *data, VisuNode *node, const gchar *yamlStr) { PosinpDict *dict; dict = posinp_yaml_parse_properties(yamlStr, (char**)0); _setNodeProp(data, node, dict); posinp_yaml_free_properties(dict); } #ifdef HAVE_YAML static gboolean loadYaml(VisuDataLoader *self _U_, VisuDataLoadable *data, guint iType, guint nSet, GCancellable *cancel _U_, GError **error) { gchar *dirname, *def; PosinpList *lst, *tmp; PosinpAtoms *atoms; guint nSets, i; GArray *types, *nattyp; VisuElement *type; double boxGeometry[6]; float xyz[3], uvw[3], fxyz[3]; GArray *forces; char *message; VisuBox *box; VisuNodeValuesString *labels; VisuNodeValues *igspin, *igchg; GValue ig = G_VALUE_INIT; g_return_val_if_fail(error && *error == (GError*)0, FALSE); message = (char*)0; lst = (PosinpList*)0; /* Start by looking for a default.yaml file. */ dirname = g_path_get_dirname(visu_data_loadable_getFilename(data, iType)); def = g_build_filename(dirname, "default.yaml", NULL); g_free(dirname); posinp_yaml_parse(&lst, def, (char**)0); if (DEBUG) for (nSets = 0, tmp = lst; tmp; tmp = tmp->next, nSets ++); DBG_fprintf(stderr, "Atomic YAML: default.yaml has %d documents (%d atoms).\n", nSets, (lst && lst->data) ? (int)lst->data->nat : -1); g_free(def); /* Overload with the given file. */ posinp_yaml_parse(&lst, visu_data_loadable_getFilename(data, iType), &message); if (!lst) { if (message) free(message); return FALSE; } if (DEBUG) for (nSets = 0, tmp = lst; tmp; tmp = tmp->next, nSets ++); DBG_fprintf(stderr, "Atomic YAML: loading '%s' as a YAML file (%d documents).\n", visu_data_loadable_getFilename(data, iType), nSets); for (nSets = 0, tmp = lst; tmp && nSets < (guint)nSet; tmp = tmp->next) nSets += 1; DBG_fprintf(stderr, " | found atoms at %p.\n", (gpointer)tmp); if (tmp && tmp->data && tmp->data->nat > 0) atoms = tmp->data; else { DBG_fprintf(stderr, "Atomic YAML: failing with nat = %d.\n", (tmp && tmp->data)?(int)tmp->data->nat:-1); if (message) free(message); posinp_yaml_free_list(lst); return FALSE; } DBG_fprintf(stderr, " | found %d atoms.\n", (atoms)?(int)atoms->nat:-1); if (message) { /* We don't have next tmp so the message is for us. */ if (!tmp->next) { *error = g_error_new(VISU_DATA_LOADABLE_ERROR, DATA_LOADABLE_ERROR_FORMAT, "%s", message); free(message); posinp_yaml_free_list(lst); return TRUE; } else free(message); } /* Counting the number of sets. */ nSets = 0; for (tmp = lst; tmp; tmp = tmp->next) nSets += 1; visu_data_loadable_setNSets(data, nSets); /* Set comments. */ for (tmp = lst, i = 0; tmp; tmp = tmp->next, i++) visu_data_loadable_setSetLabel(data, tmp->data->comment, i); /* Set metadata. */ if (!isnan(atoms->energy)) switch (atoms->eunits) { case (POSINP_ENERG_UNITS_HARTREE): g_object_set(G_OBJECT(data), "totalEnergy", atoms->energy * 27.2113834, NULL); break; case (POSINP_ENERG_UNITS_RYDBERG): g_object_set(G_OBJECT(data), "totalEnergy", atoms->energy * 0.5 * 27.2113834, NULL); break; case (POSINP_ENERG_UNITS_EV): default: g_object_set(G_OBJECT(data), "totalEnergy", atoms->energy, NULL); break; } /* Setup the population. */ types = g_array_sized_new(FALSE, FALSE, sizeof(VisuElement*), atoms->ntypes); for (i = 0; i < atoms->ntypes; i++) { type = visu_element_retrieveFromName(atoms->atomnames[i], (gboolean*)0); g_array_append_val(types, type); } nattyp = g_array_sized_new(FALSE, TRUE, sizeof(guint), atoms->ntypes); g_array_set_size(nattyp, atoms->ntypes); for (i = 0; i < atoms->nat; i++) *(&g_array_index(nattyp, guint, atoms->iatype[i])) += 1; visu_node_array_allocate(VISU_NODE_ARRAY(data), types, nattyp); DBG_fprintf(stderr, "Atomic YAML: there are %d types in this file.\n", atoms->ntypes); if (DEBUG) { for (i = 0; i < atoms->ntypes; i++) DBG_fprintf(stderr, " | %d atom(s) for type %d.\n", g_array_index(nattyp, guint, i), i); } g_array_free(nattyp, TRUE); g_array_free(types, TRUE); if (sin(atoms->angdeg[2]) == 0.f) { *error = g_error_new(VISU_DATA_LOADABLE_ERROR, DATA_LOADABLE_ERROR_FORMAT, _("Wrong (ab) angle, should be" " different from 0[pi].\n\n" " Quoting '%g'.\n"), atoms->angdeg[2]); posinp_yaml_free_list(lst); return TRUE; } /* We remove the infinity. */ if (!(atoms->BC & 1)) atoms->acell[2] = 1.; if (!(atoms->BC & 2)) atoms->acell[1] = 1.; if (!(atoms->BC & 4)) atoms->acell[0] = 1.; boxGeometry[0] = atoms->acell[0]; boxGeometry[1] = atoms->acell[1] * cos(G_PI * atoms->angdeg[2] / 180.); boxGeometry[2] = atoms->acell[1] * sin(G_PI * atoms->angdeg[2] / 180.); boxGeometry[3] = atoms->acell[2] * cos(G_PI * atoms->angdeg[1] / 180.); boxGeometry[4] = atoms->acell[2] * (cos(G_PI * atoms->angdeg[0] / 180.) - cos(G_PI * atoms->angdeg[1] / 180.) * cos(G_PI * atoms->angdeg[2] / 180.)) / sin(G_PI * atoms->angdeg[2] / 180.); boxGeometry[5] = sqrt(atoms->acell[2] * atoms->acell[2] - boxGeometry[3] * boxGeometry[3] - boxGeometry[4] * boxGeometry[4]); boxGeometry[5] *= (atoms->angdeg[1] < 0.)?-1.:+1.; /* Always set the given box, in case coordinates are reduced. */ box = (VisuBox*)0; switch (atoms->BC) { case (POSINP_BC_PERIODIC): box = visu_box_new(boxGeometry, VISU_BOX_PERIODIC); break; case (POSINP_BC_FREE): box = visu_box_new(boxGeometry, VISU_BOX_FREE); break; case (POSINP_BC_SURFACE_XZ): box = visu_box_new(boxGeometry, VISU_BOX_SURFACE_ZX); break; default: *error = g_error_new(VISU_DATA_LOADABLE_ERROR, DATA_LOADABLE_ERROR_FORMAT, _("Unsupported boundary conditions.\n")); posinp_yaml_free_list(lst); return TRUE; } visu_boxed_setBox(VISU_BOXED(data), VISU_BOXED(box)); g_object_unref(box); for (i = 0; i < atoms->nat; i++) { xyz[0] = uvw[0] = (float)atoms->rxyz[3 * i + 0]; xyz[1] = uvw[1] = (float)atoms->rxyz[3 * i + 1]; xyz[2] = uvw[2] = (float)atoms->rxyz[3 * i + 2]; if (atoms->units == POSINP_COORD_UNITS_REDUCED) visu_box_convertBoxCoordinatestoXYZ(box, xyz, uvw); visu_data_addNodeFromIndex(VISU_DATA(data), atoms->iatype[i], xyz, FALSE); } /* Add external potentials as nodes. */ if (atoms->npots) { VisuNodeValues *vals; VisuNodeValuesFrag *fragments; VisuNodeValuesFarray *sigmas; VisuNodeValuesPole *poles; vals = visu_data_getNodeProperties(VISU_DATA(data), _("Fragment")); if (vals && VISU_IS_NODE_VALUES_FRAG(vals)) fragments = VISU_NODE_VALUES_FRAG(vals); else { fragments = visu_node_values_frag_new(VISU_NODE_ARRAY(data), vals ? _("External potential") : _("Fragment")); visu_data_addNodeProperties(VISU_DATA(data), VISU_NODE_VALUES(fragments)); } sigmas = (VisuNodeValuesFarray*)0; if (atoms->psigma) { sigmas = visu_node_values_farray_new(VISU_NODE_ARRAY(data), _("sigma"), POSINP_SIGMA_SIZE); visu_data_addNodeProperties(VISU_DATA(data), VISU_NODE_VALUES(sigmas)); } poles = (VisuNodeValuesPole*)0; if (atoms->ppoles) { poles = visu_node_values_pole_new(VISU_NODE_ARRAY(data), _("poles")); visu_data_addNodeProperties(VISU_DATA(data), VISU_NODE_VALUES(poles)); } for (i = 0; i < atoms->npots; i++) { VisuElement *element; VisuNode *node; VisuNodeFragment frag; gchar *name; gboolean created; name = g_strdup_printf("%%%s_pot", atoms->potnames[i]); element = visu_element_retrieveFromName(name, &created); g_free(name); if (created) { VisuElementAtomic *renderer = visu_element_atomic_getFromPool(element); VisuElement *eleOrig = visu_element_lookup(atoms->potnames[i]); if (atoms->psigma) visu_element_atomic_setRadius(renderer, atoms->psigma[i][0]); switch (atoms->punits) { case (POSINP_CELL_UNITS_ANGSTROEM): visu_element_atomic_setUnits(renderer, TOOL_UNITS_ANGSTROEM); break; case (POSINP_CELL_UNITS_BOHR): visu_element_atomic_setUnits(renderer, TOOL_UNITS_BOHR); break; default: break; } if (eleOrig) { VisuElementRenderer *orig = visu_element_renderer_getFromPool(eleOrig); visu_element_renderer_setColor(VISU_ELEMENT_RENDERER(renderer), visu_element_renderer_getColor(orig)); visu_element_renderer_setMaterial(VISU_ELEMENT_RENDERER(renderer), visu_element_renderer_getMaterial(orig)); visu_element_renderer_setMaterialValue(VISU_ELEMENT_RENDERER(renderer), .2f, TOOL_MATERIAL_AMB); } } xyz[0] = (float)atoms->pxyz[3 * i + 0]; xyz[1] = (float)atoms->pxyz[3 * i + 1]; xyz[2] = (float)atoms->pxyz[3 * i + 2]; node = visu_data_addNodeFromElement(VISU_DATA(data), element, xyz, (atoms->punits == POSINP_COORD_UNITS_REDUCED)); frag.label = g_strdup(_("Pole")); frag.id = i; visu_node_values_frag_setAt(fragments, node, &frag); if (atoms->psigma) visu_node_values_farray_setAtDbl(sigmas, node, atoms->psigma[i], POSINP_SIGMA_SIZE); if (atoms->ppoles) { visu_node_values_pole_setMonoAtDbl(poles, node, atoms->ppoles[i].q0); visu_node_values_pole_setDiAtDbl(poles, node, atoms->ppoles[i].q1); visu_node_values_pole_setQuadAtDbl(poles, node, atoms->ppoles[i].q2); } } } /* We setup comments from ifrztyp. */ labels = visu_data_getNodeLabels(VISU_DATA(data)); if (atoms->ifrztyp) for (i = 0; i < atoms->nat; i++) switch (atoms->ifrztyp[i]) { case POSINP_FROZEN_FULL: visu_node_values_string_setAt(labels, visu_node_array_getFromId(VISU_NODE_ARRAY(data), i), "f"); break; case POSINP_FROZEN_Y: visu_node_values_string_setAt(labels, visu_node_array_getFromId(VISU_NODE_ARRAY(data), i), "fy"); break; case POSINP_FROZEN_XZ: visu_node_values_string_setAt(labels, visu_node_array_getFromId(VISU_NODE_ARRAY(data), i), "fxz"); break; case POSINP_FROZEN_FREE: default: break; } /* We setup igspin and igchg as properties. */ g_value_init(&ig, G_TYPE_INT); if (atoms->igspin) { igspin = visu_node_values_new(VISU_NODE_ARRAY(data), "IGSpin", G_TYPE_INT, 1); for (i = 0; i < atoms->nat; i++) { g_value_set_int(&ig, atoms->igspin[i]); visu_node_values_setAt(igspin, visu_node_array_getFromId(VISU_NODE_ARRAY(data), i), &ig); } visu_data_addNodeProperties(VISU_DATA(data), igspin); } if (atoms->igchg) { igchg = visu_node_values_new(VISU_NODE_ARRAY(data), "IGChg", G_TYPE_INT, 1); for (i = 0; i < atoms->nat; i++) { g_value_set_int(&ig, atoms->igspin[i]); visu_node_values_setAt(igchg, visu_node_array_getFromId(VISU_NODE_ARRAY(data), i), &ig); } visu_data_addNodeProperties(VISU_DATA(data), igchg); } /* Add node properties if any. */ if (atoms->props) for (i = 0; i < atoms->nat; i++) _setNodeProp(VISU_DATA(data), visu_node_array_getFromId(VISU_NODE_ARRAY(data), i), atoms->props + i); /* In free boundary conditions, find the bounding box. */ if (atoms->BC != POSINP_BC_PERIODIC) visu_data_setTightBox(VISU_DATA(data)); /* We finish with the box description. */ DBG_fprintf(stderr, "Atomic YAML: apply the box geometry and set the unit.\n"); switch (atoms->Units) { case (POSINP_CELL_UNITS_ANGSTROEM): visu_box_setUnit(box, TOOL_UNITS_ANGSTROEM); break; case (POSINP_CELL_UNITS_BOHR): visu_box_setUnit(box, TOOL_UNITS_BOHR); break; default: *error = g_error_new(VISU_DATA_LOADABLE_ERROR, DATA_LOADABLE_ERROR_FORMAT, _("Unsupported units.\n")); posinp_yaml_free_list(lst); return TRUE; } /* Store the forces, if any. */ if (atoms->fxyz) { forces = g_array_sized_new(FALSE, FALSE, sizeof(float), 3 * atoms->nat); for (i = 0; i < atoms->nat; i++) { fxyz[0] = (float)atoms->fxyz[3 * i + 0]; fxyz[1] = (float)atoms->fxyz[3 * i + 1]; fxyz[2] = (float)atoms->fxyz[3 * i + 2]; g_array_append_vals(forces, fxyz, 3); } visu_node_values_vector_set (visu_data_atomic_getForces(VISU_DATA_ATOMIC(data), TRUE), forces); g_array_free(forces, TRUE); } posinp_yaml_free_list(lst); return TRUE; } #endif v_sim-3.8.0/src/loaders/atomic_yaml.h000066400000000000000000000036071370110300500175220ustar00rootroot00000000000000/* EXTRAITS DE LA LICENCE Copyright CEA, contributeurs : Damien CALISTE, laboratoire L_Sim, (2001-2012) Adresse mèl : CALISTE, damien P caliste AT cea P fr. Ce logiciel est un programme informatique servant à visualiser des structures atomiques dans un rendu pseudo-3D. Ce logiciel est régi par la licence CeCILL soumise au droit français et respectant les principes de diffusion des logiciels libres. Vous pouvez utiliser, modifier et/ou redistribuer ce programme sous les conditions de la licence CeCILL telle que diffusée par le CEA, le CNRS et l'INRIA sur le site "http://www.cecill.info". Le fait que vous puissiez accéder à cet en-tête signifie que vous avez pris connaissance de la licence CeCILL, et que vous en avez accepté les termes (cf. le fichier Documentation/licence.fr.txt fourni avec ce logiciel). */ /* LICENCE SUM UP Copyright CEA, contributors : Damien CALISTE, laboratoire L_Sim, (2001-2012) E-mail address: CALISTE, damien P caliste AT cea P fr. This software is a computer program whose purpose is to visualize atomic configurations in 3D. This software is governed by the CeCILL license under French law and abiding by the rules of distribution of free software. You can use, modify and/ or redistribute the software under the terms of the CeCILL license as circulated by CEA, CNRS and INRIA at the following URL "http://www.cecill.info". The fact that you are presently reading this means that you have had knowledge of the CeCILL license and that you accept its terms. You can find a copy of this licence shipped with this software at Documentation/licence.en.txt. */ #ifndef ATOMIC_YAML_H #define ATOMIC_YAML_H #include VisuDataLoader* visu_data_loader_yaml_getStatic(void); void visu_data_loader_yaml_setNodeProp(VisuData *data, VisuNode *node, const gchar *yamlStr); #endif v_sim-3.8.0/src/openGLFunctions/000077500000000000000000000000001370110300500164715ustar00rootroot00000000000000v_sim-3.8.0/src/openGLFunctions/interactive.c000066400000000000000000002026121370110300500211550ustar00rootroot00000000000000/* EXTRAITS DE LA LICENCE Copyright CEA, contributeurs : Luc BILLARD et Damien CALISTE, laboratoire L_Sim, (2001-2005) Adresse mèl : BILLARD, non joignable par mèl ; CALISTE, damien P caliste AT cea P fr. Ce logiciel est un programme informatique servant à visualiser des structures atomiques dans un rendu pseudo-3D. Ce logiciel est régi par la licence CeCILL soumise au droit français et respectant les principes de diffusion des logiciels libres. Vous pouvez utiliser, modifier et/ou redistribuer ce programme sous les conditions de la licence CeCILL telle que diffusée par le CEA, le CNRS et l'INRIA sur le site "http://www.cecill.info". Le fait que vous puissiez accéder à cet en-tête signifie que vous avez pris connaissance de la licence CeCILL, et que vous en avez accepté les termes (cf. le fichier Documentation/licence.fr.txt fourni avec ce logiciel). */ /* LICENCE SUM UP Copyright CEA, contributors : Luc BILLARD et Damien CALISTE, laboratoire L_Sim, (2001-2005) E-mail address: BILLARD, not reachable any more ; CALISTE, damien P caliste AT cea P fr. This software is a computer program whose purpose is to visualize atomic configurations in 3D. This software is governed by the CeCILL license under French law and abiding by the rules of distribution of free software. You can use, modify and/ or redistribute the software under the terms of the CeCILL license as circulated by CEA, CNRS and INRIA at the following URL "http://www.cecill.info". The fact that you are presently reading this means that you have had knowledge of the CeCILL license and that you accept its terms. You can find a copy of this licence shipped with this software at Documentation/licence.en.txt. */ #include #include #include #include #include "view.h" #include "objectList.h" #include #include #include #include #include "interactive.h" #define FLAG_PARAMETER_OBSERVE_METHOD "opengl_observe_method" #define DESC_PARAMETER_OBSERVE_METHOD "Choose the observe method ; integer (0: constrained mode, 1: walker mode)" #define FLAG_PARAMETER_CAMERA_SETTINGS "opengl_prefered_camera_orientation" #define DESC_PARAMETER_CAMERA_SETTINGS "Saved prefered camera position ; three angles, two shifts, zoom and perspective level" static float cameraData[7]; /** * SECTION:interactive * @short_description: Gives tools to interact with the rendered * area. * * When one wants some interactions on the rendering area * (either from the mouse or from the keyboard), one should create a new * interactive object using visu_interactive_new(). Then, during the * interactive session, several modes have been implemented: * * * #interactive_mark, is a mode where the mouse can select * a node and this nodes become highlighted. * * * #interactive_move, the mouse is then used to move * picked nodes. Moves are possible in the plane of the screen or * constrained along axis of the bounding box. * * * #interactive_observe, in this mode, the mouse is used * to change the position of camera, its orientation and its zoom * characteristics. * * * #interactive_pick, this mode is the most complex * picking mode. It can select atoms up to two references and measure * distances and angles. * * * #interactive_pickAndObserve, this mode is a simplified * mix of obervation and picking. * * * The observe mode has two different moving algorithms that can be * changed using visu_interactive_class_setPreferedObserveMethod(). The * first, called 'constrained' (cf. #interactive_constrained) * corresponds to movements along parallels and meridians. When the * mouse is moved along x axis, the camera raotates along a * parallel. When the camera is moved along y axis, the camera rotate * along a meridian. The top is always pointing to the north pole (in * fact, omega is always forced to 0 in this mode). This mode has a * 'strange' behavior when the observer is near a pole: moving mouse * along x axis make the box rotates on itself. It is normal, because * movements on x axis is equivalent to movements on parallel and near * the poles, parallel are small circle around the z axis. This can be * unnatural in some occasion and the other mode, called 'walker' (see * #interactive_walker) can be used instead of the 'constrained' * mode. In the former, the moving is done has if the observer was a * walking ant on a sphere : moving the mouse along y axis makes the * ant go on or forward ; and x axis movements makes the ant goes on * its left or on it right. This is a more natural way to move the box * but it has the inconvient that it is hard to return in a given * position (omega has never the right value). * */ /** * VisuInteractiveClass: * @parent: the parent. * @preferedObserveMethod: the prefered method to move the camera. * @savedCameras: the list of saved cameras. * @lastCamera: a pointer on the last selected camera. * * An opaque structure representing the class of #VisuInteractive objects. */ /** * VisuInteractive: * * All fields are private. */ struct _VisuInteractive { VisuObject parent; /* Internal object gestion. */ gboolean dispose_has_run; /* The kind of interactive (pick, observe...) */ VisuInteractiveId id; /* Data needed in case of pick. */ /* The last selected node. */ gint idSelected; /* The current first reference. */ gint idRef1; /* The current second reference. */ gint idRef2; /* */ GArray *idRegion; /* The position of the pick. */ int xOrig, yOrig; int xPrev, yPrev; /* Data for the move action. */ gboolean movingPicked; GArray *movingNodes; float movingAxe[3]; /* The OpenGL list used to identify nodes. */ VisuGlExtNodes *nodeList; gulong data_sig; /* Signals to listen to. */ VisuData *dataObj; gulong popDec_signal; /* Copy of last event. */ ToolSimplifiedEvents ev; /* Some message explaining the purpose of the interactive session. */ gchar *message; }; enum { INTERACTIVE_OBSERVE_SIGNAL, INTERACTIVE_PICK_ERROR_SIGNAL, INTERACTIVE_PICK_NODE_SIGNAL, INTERACTIVE_PICK_REGION_SIGNAL, INTERACTIVE_PICK_MENU_SIGNAL, INTERACTIVE_START_MOVE_SIGNAL, INTERACTIVE_MOVE_SIGNAL, INTERACTIVE_STOP_MOVE_SIGNAL, INTERACTIVE_STOP_SIGNAL, /* INTERACTIVE_EVENT_SIGNAL, */ N_INTERACTIVE_SIGNALS }; static VisuInteractiveClass *local_class = NULL; /* Internal variables. */ static guint interactive_signals[N_INTERACTIVE_SIGNALS] = { 0 }; /* Object gestion methods. */ static void visu_interactive_dispose (GObject* obj); static void visu_interactive_finalize(GObject* obj); /* Local methods. */ static void exportParameters(GString *data, VisuData *dataObj); static void onReadCamera(VisuConfigFile *obj, VisuConfigFileEntry *entry, VisuInteractiveClass *klass); static void onPopulationChange(VisuInteractive *inter, GArray *nodes, VisuData *dataObj); static void _setData(VisuInteractive *inter, VisuData *dataObj); static gboolean observe(VisuInteractive *inter, VisuGlView *view, ToolSimplifiedEvents *ev); static gboolean pick(VisuInteractive *inter, ToolSimplifiedEvents *ev); static gboolean move(VisuInteractive *inter, VisuGlView *view, ToolSimplifiedEvents *ev); static gboolean mark(VisuInteractive *inter, ToolSimplifiedEvents *ev); static gboolean pickAndObserve(VisuInteractive *inter, VisuGlView *view, ToolSimplifiedEvents *ev); static gboolean drag(VisuInteractive *inter, VisuGlView *view, ToolSimplifiedEvents *ev); G_DEFINE_TYPE(VisuInteractive, visu_interactive, VISU_TYPE_OBJECT) static void g_cclosure_marshal_NODE_SELECTION(GClosure *closure, GValue *return_value _U_, guint n_param_values, const GValue *param_values, gpointer invocation_hint _U_, gpointer marshal_data) { typedef void (*callbackFunc)(gpointer data1, guint kind, VisuNodeArray *arr, VisuNode *node1, VisuNode *node2, VisuNode *node3, gpointer data2); register callbackFunc callback; register GCClosure *cc = (GCClosure*)closure; register gpointer data1, data2; g_return_if_fail(n_param_values == 6); if (G_CCLOSURE_SWAP_DATA(closure)) { data1 = closure->data; data2 = g_value_peek_pointer(param_values + 0); } else { data1 = g_value_peek_pointer(param_values + 0); data2 = closure->data; } callback = (callbackFunc)(size_t)(marshal_data ? marshal_data : cc->callback); DBG_fprintf(stderr, "Interactive: marshall callback for node-selection" " with nodes %p, %p, %p.\n", (gpointer)g_value_get_boxed(param_values + 3), (gpointer)g_value_get_boxed(param_values + 4), (gpointer)g_value_get_boxed(param_values + 5)); callback(data1, g_value_get_uint(param_values + 1), g_value_get_object(param_values + 2), (VisuNode*)g_value_get_boxed(param_values + 3), (VisuNode*)g_value_get_boxed(param_values + 4), (VisuNode*)g_value_get_boxed(param_values + 5), data2); } static void g_cclosure_marshal_NODE_MENU(GClosure *closure, GValue *return_value _U_, guint n_param_values, const GValue *param_values, gpointer invocation_hint _U_, gpointer marshal_data) { typedef void (*callbackFunc)(gpointer data1, gint x, gint y, VisuNode *node, gpointer data2); register callbackFunc callback; register GCClosure *cc = (GCClosure*)closure; register gpointer data1, data2; g_return_if_fail(n_param_values == 4); if (G_CCLOSURE_SWAP_DATA(closure)) { data1 = closure->data; data2 = g_value_peek_pointer(param_values + 0); } else { data1 = g_value_peek_pointer(param_values + 0); data2 = closure->data; } callback = (callbackFunc)(size_t)(marshal_data ? marshal_data : cc->callback); DBG_fprintf(stderr, "Interactive: marshall callback for menu at %dx%d" " with node %p.\n", g_value_get_int(param_values + 1), g_value_get_int(param_values + 2), (gpointer)g_value_get_boxed(param_values + 3)); callback(data1, g_value_get_int(param_values + 1), g_value_get_int(param_values + 2), (VisuNode*)g_value_get_boxed(param_values + 3), data2); } static void visu_interactive_class_init(VisuInteractiveClass *klass) { GType paramBool[1] = {G_TYPE_BOOLEAN}; GType paramUInt[1] = {G_TYPE_UINT}; VisuConfigFileEntry *resourceEntry; int rgMethod[2] = {interactive_constrained, interactive_walker}; float rgCamera[2] = {-G_MAXFLOAT, G_MAXFLOAT}; local_class = klass; DBG_fprintf(stderr, "visu Interactive: creating the class of the object.\n"); DBG_fprintf(stderr, " - adding new signals ;\n"); /** * VisuInteractive::observe: * @obj: the object emitting the signal. * @bool: a boolean. * * This signal is emitted each time an observe session is start * (@bool is TRUE) or finished (@bool is FALSE). * * Since: 3.6 */ interactive_signals[INTERACTIVE_OBSERVE_SIGNAL] = g_signal_newv("observe", G_TYPE_FROM_CLASS(klass), G_SIGNAL_RUN_LAST | G_SIGNAL_NO_RECURSE, NULL, NULL, NULL, g_cclosure_marshal_VOID__BOOLEAN, G_TYPE_NONE, 1, paramBool); /** * VisuInteractive::selection-error: * @obj: the object emitting the signal. * @err: an error value. * * This signal is emitted each time a selection fails, providing the * error in @err (see #VisuInteractivePickError). * * Since: 3.6 */ interactive_signals[INTERACTIVE_PICK_ERROR_SIGNAL] = g_signal_newv("selection-error", G_TYPE_FROM_CLASS(klass), G_SIGNAL_RUN_LAST | G_SIGNAL_NO_RECURSE | G_SIGNAL_NO_HOOKS, NULL, NULL, NULL, g_cclosure_marshal_VOID__UINT, G_TYPE_NONE, 1, paramUInt); /** * VisuInteractive::node-selection: * @obj: the object emitting the signal. * @kind: a flag, see #VisuInteractivePick. * @array: (type VisuNodeArray*) (transfer none): the #VisuNodeArray * hosting @node1, @node2 and @node3. * @node1: (type VisuNode*) (transfer none): the primary node. * @node2: (type VisuNode*) (transfer none): the secondary * node, if any. * @node3: (type VisuNode*) (transfer none): the tertiary * node, if any. * * This signal is emitted each time a single node selection succeed, providing the * kind in @kind (see #VisuInteractivePick). The corresponding nodes * are stored in @node1, @node2 and @node3. * * Since: 3.6 */ interactive_signals[INTERACTIVE_PICK_NODE_SIGNAL] = g_signal_new("node-selection", G_TYPE_FROM_CLASS(klass), G_SIGNAL_RUN_LAST | G_SIGNAL_NO_RECURSE, 0, NULL, NULL, g_cclosure_marshal_NODE_SELECTION, G_TYPE_NONE, 5, G_TYPE_UINT, VISU_TYPE_NODE_ARRAY, VISU_TYPE_NODE, VISU_TYPE_NODE, VISU_TYPE_NODE, NULL); /** * VisuInteractive::region-selection: * @obj: the object emitting the signal. * @nodes: (element-type guint): an array of node ids. * * This signal is emitted each time a region selection succeed. The corresponding nodes * are stored in @nodes. * * Since: 3.6 */ interactive_signals[INTERACTIVE_PICK_REGION_SIGNAL] = g_signal_new("region-selection", G_TYPE_FROM_CLASS(klass), G_SIGNAL_RUN_LAST | G_SIGNAL_NO_RECURSE | G_SIGNAL_NO_HOOKS, 0, NULL, NULL, g_cclosure_marshal_VOID__BOXED, G_TYPE_NONE, 1, G_TYPE_ARRAY); /** * VisuInteractive::menu: * @obj: the object emitting the signal. * @x: the x coordinate. * @y: the y coordinate. * @node: (type VisuNode*) (transfer none) (allow-none): a #VisuNode. * * This signal is emitted each time a menu key stroke is done. * * Since: 3.7 */ interactive_signals[INTERACTIVE_PICK_MENU_SIGNAL] = g_signal_new("menu", G_TYPE_FROM_CLASS(klass), G_SIGNAL_RUN_LAST | G_SIGNAL_NO_RECURSE, 0, NULL, NULL, g_cclosure_marshal_NODE_MENU, G_TYPE_NONE, 3, G_TYPE_INT, G_TYPE_INT, VISU_TYPE_NODE); /** * VisuInteractive::start-move: * @obj: the object emitting the signal. * @nodes: (element-type guint): an array of node ids. * * This signal is emitted each time a set of nodes are clicked to be * moved. The corresponding nodes are stored in @nodes. * * Since: 3.6 */ interactive_signals[INTERACTIVE_START_MOVE_SIGNAL] = g_signal_new("start-move", G_TYPE_FROM_CLASS(klass), G_SIGNAL_RUN_LAST | G_SIGNAL_NO_RECURSE | G_SIGNAL_NO_HOOKS, 0, NULL, NULL, g_cclosure_marshal_VOID__BOXED, G_TYPE_NONE, 1, G_TYPE_ARRAY); /** * VisuInteractive::move: * @obj: the object emitting the signal. * @delta: the delta of applied translation. * * This signal is emitted each time a set of nodes are moved. The * corresponding movement translation is stored in delta. * * Since: 3.6 */ interactive_signals[INTERACTIVE_MOVE_SIGNAL] = g_signal_new("move", G_TYPE_FROM_CLASS(klass), G_SIGNAL_RUN_LAST | G_SIGNAL_NO_RECURSE | G_SIGNAL_NO_HOOKS, 0, NULL, NULL, g_cclosure_marshal_VOID__BOXED, G_TYPE_NONE, 1, TOOL_TYPE_VECTOR); /** * VisuInteractive::stop-move: * @obj: the object emitting the signal. * @delta: the delta of applied translation. * * This signal is emitted when a set of nodes are finished moving. The * corresponding movement complete translation is stored in delta. * * Since: 3.8 */ interactive_signals[INTERACTIVE_STOP_MOVE_SIGNAL] = g_signal_new("stop-move", G_TYPE_FROM_CLASS(klass), G_SIGNAL_RUN_LAST | G_SIGNAL_NO_RECURSE | G_SIGNAL_NO_HOOKS, 0, NULL, NULL, g_cclosure_marshal_VOID__BOXED, G_TYPE_NONE, 1, TOOL_TYPE_VECTOR); /** * VisuInteractive::stop: * @obj: the object emitting the signal. * * This signal is emitted each time a set of nodes are stopped to be * moved. * * Since: 3.6 */ interactive_signals[INTERACTIVE_STOP_SIGNAL] = g_signal_newv("stop", G_TYPE_FROM_CLASS(klass), G_SIGNAL_RUN_LAST | G_SIGNAL_NO_RECURSE | G_SIGNAL_NO_HOOKS, NULL, NULL, NULL, g_cclosure_marshal_VOID__VOID, G_TYPE_NONE, 0, NULL); /* Connect freeing methods. */ G_OBJECT_CLASS(klass)->dispose = visu_interactive_dispose; G_OBJECT_CLASS(klass)->finalize = visu_interactive_finalize; DBG_fprintf(stderr, " - add the resources.\n"); visu_config_file_addIntegerArrayEntry(VISU_CONFIG_FILE_PARAMETER, FLAG_PARAMETER_OBSERVE_METHOD, DESC_PARAMETER_OBSERVE_METHOD, 1, (int*)&klass->preferedObserveMethod, rgMethod, FALSE); resourceEntry = visu_config_file_addFloatArrayEntry(VISU_CONFIG_FILE_PARAMETER, FLAG_PARAMETER_CAMERA_SETTINGS, DESC_PARAMETER_CAMERA_SETTINGS, 7, cameraData, rgCamera, FALSE); visu_config_file_entry_setVersion(resourceEntry, 3.7f); visu_config_file_addExportFunction(VISU_CONFIG_FILE_PARAMETER, exportParameters); g_signal_connect(VISU_CONFIG_FILE_PARAMETER, "parsed::" FLAG_PARAMETER_CAMERA_SETTINGS, G_CALLBACK(onReadCamera), klass); /* Set local variables to default. */ DBG_fprintf(stderr, " - setup the local variables.\n"); klass->preferedObserveMethod = interactive_constrained; } static void visu_interactive_init(VisuInteractive *obj) { DBG_fprintf(stderr, "Visu Interactive: creating a new interactive session (%p).\n", (gpointer)obj); obj->dispose_has_run = FALSE; obj->idRef1 = -99; obj->idRef2 = -99; obj->idSelected = -99; obj->idRegion = (GArray*)0; obj->movingAxe[0] = 1.f; obj->movingAxe[1] = 0.f; obj->movingAxe[2] = 0.f; obj->movingPicked = FALSE; obj->movingNodes = (GArray*)0; obj->nodeList = (VisuGlExtNodes*)0; obj->dataObj = (VisuData*)0; obj->popDec_signal = (gulong)0; obj->message = (gchar*)0; } static void onPopulationChange(VisuInteractive *inter, GArray *nodes, VisuData *dataObj _U_) { guint i; DBG_fprintf(stderr, "Visu Interactive: remove the specific nodes.\n"); for (i = 0; i < nodes->len; i++) { if (inter->idRef1 == g_array_index(nodes, gint, i)) inter->idRef1 = -1; if (inter->idRef2 == g_array_index(nodes, gint, i)) inter->idRef2 = -1; if (inter->idSelected == g_array_index(nodes, gint, i)) inter->idSelected = -1; } if (inter->idRegion) g_array_unref(inter->idRegion); inter->idRegion = (GArray*)0; } /* This method can be called several times. It should unref all of its reference to GObjects. */ static void visu_interactive_dispose(GObject* obj) { DBG_fprintf(stderr, "Visu Interactive: dispose object %p.\n", (gpointer)obj); if (VISU_INTERACTIVE(obj)->dispose_has_run) return; VISU_INTERACTIVE(obj)->dispose_has_run = TRUE; visu_interactive_setNodeList(VISU_INTERACTIVE(obj), (VisuGlExtNodes*)0); /* Chain up to the parent class */ G_OBJECT_CLASS(visu_interactive_parent_class)->dispose(obj); } /* This method is called once only. */ static void visu_interactive_finalize(GObject* obj) { g_return_if_fail(obj); DBG_fprintf(stderr, "Visu Interactive: finalize object %p.\n", (gpointer)obj); if (VISU_INTERACTIVE(obj)->movingNodes) g_array_unref(VISU_INTERACTIVE(obj)->movingNodes); if (VISU_INTERACTIVE(obj)->idRegion) g_array_unref(VISU_INTERACTIVE(obj)->idRegion); g_free(VISU_INTERACTIVE(obj)->message); /* Chain up to the parent class */ G_OBJECT_CLASS(visu_interactive_parent_class)->finalize(obj); } /** * visu_interactive_new: * @type: a #VisuInteractiveId flag. * * Creates a new interactive session of the given @type. * * Returns: (transfer full): a newly created object. */ VisuInteractive* visu_interactive_new(VisuInteractiveId type) { VisuInteractive *inter; inter = VISU_INTERACTIVE(g_object_new(VISU_TYPE_INTERACTIVE, NULL)); g_return_val_if_fail(inter, (VisuInteractive*)0); DBG_fprintf(stderr, "Visu Interactive: start new interactive session %p (%d).\n", (gpointer)inter, type); inter->id = type; return inter; } /** * visu_interactive_getType: * @inter: a #VisuInteractive object. * * It returns the kind of interactive session. * * Returns: a #VisuInteractiveId value. */ VisuInteractiveId visu_interactive_getType(VisuInteractive *inter) { g_return_val_if_fail(VISU_IS_INTERACTIVE(inter), interactive_none); return inter->id; } /** * visu_interactive_setType: * @inter: a #VisuInteractive object. * @id: a #VisuInteractiveId. * * It changes the kind of interactive session. * * Returns: TRUE if indeed changed. */ gboolean visu_interactive_setType(VisuInteractive *inter, VisuInteractiveId id) { g_return_val_if_fail(VISU_IS_INTERACTIVE(inter), FALSE); if (inter->id == id) return FALSE; inter->id = id; return TRUE; } static void onDataNotified(VisuInteractive *inter, GParamSpec *pspec _U_, VisuGlExtNodes *nodes) { _setData(inter, VISU_DATA(visu_node_array_renderer_getNodeArray(VISU_NODE_ARRAY_RENDERER(nodes)))); } /** * visu_interactive_setNodeList: * @inter: a #VisuInteractive object. * @nodes: (transfer full) (allow-none): a #VisuGlExtNodes object. * * Associate a #VisuGlExtNodes object for node selection. This is * mandatory for move, pick and mark actions. * * Since: 3.7 **/ void visu_interactive_setNodeList(VisuInteractive *inter, VisuGlExtNodes *nodes) { g_return_if_fail(VISU_IS_INTERACTIVE(inter)); if (inter->nodeList == nodes) return; if (inter->nodeList) { g_signal_handler_disconnect(inter->nodeList, inter->data_sig); g_object_unref(inter->nodeList); } if (nodes) { g_object_ref(nodes); inter->data_sig = g_signal_connect_swapped(nodes, "notify::data", G_CALLBACK(onDataNotified), inter); } inter->nodeList = nodes; _setData(inter, (nodes) ? VISU_DATA(visu_node_array_renderer_getNodeArray(VISU_NODE_ARRAY_RENDERER(nodes))) : (VisuData*)0); } static void _setData(VisuInteractive *inter, VisuData *dataObj) { if (inter->idRef1 >= 0 && (!dataObj || !visu_node_array_getFromId(VISU_NODE_ARRAY(dataObj), inter->idRef1))) inter->idRef1 = -99; if (inter->idRef2 >= 0 && (!dataObj || !visu_node_array_getFromId(VISU_NODE_ARRAY(dataObj), inter->idRef2))) inter->idRef2 = -99; if (inter->idSelected >= 0 && (!dataObj || !visu_node_array_getFromId(VISU_NODE_ARRAY(dataObj), inter->idSelected))) inter->idSelected = -99; DBG_fprintf(stderr, "Visu Interactive: specific nodes are now:\n"); DBG_fprintf(stderr, " - selected %d.\n", inter->idSelected); DBG_fprintf(stderr, " - ref. 1 %d.\n", inter->idRef1); DBG_fprintf(stderr, " - ref. 2 %d.\n", inter->idRef2); if (inter->idRegion) g_array_unref(inter->idRegion); inter->idRegion = (GArray*)0; if (inter->dataObj == dataObj) return; if (inter->dataObj) { g_signal_handler_disconnect(inter->dataObj, inter->popDec_signal); g_object_unref(inter->dataObj); } if (dataObj) { g_object_ref(dataObj); inter->popDec_signal = g_signal_connect_swapped(dataObj, "PopulationDecrease", G_CALLBACK(onPopulationChange), (gpointer)inter); } inter->dataObj = dataObj; } /** * visu_interactive_popSavedCamera: * @inter: a #VisuInteractive object. * * @inter object stores camera settings as a ring. This routine goes * to the next camera in the ring and returns the current one. The * popped camera is not actually removed from the ring. * * Since: 3.6 * * Returns: a pointer to the previously current #VisuGlCamera. It * is owned by V_Sim and should not be touched. */ VisuGlCamera* visu_interactive_popSavedCamera(VisuInteractive *inter) { VisuGlCamera *cur; VisuInteractiveClass *klass; klass = VISU_INTERACTIVE_GET_CLASS(inter); g_return_val_if_fail(klass, (VisuGlCamera*)0); if (!klass->lastCamera) return (VisuGlCamera*)0; cur = (VisuGlCamera*)klass->lastCamera->data; klass->lastCamera = g_list_next(klass->lastCamera); if (!klass->lastCamera) klass->lastCamera = klass->savedCameras; DBG_fprintf(stderr, "Interactive: pop, pointing now at camera %d.\n", g_list_position(klass->savedCameras, klass->lastCamera)); return cur; } /** * visu_interactive_getSavedCameras: * @inter: a #VisuInteractive object. * @cameras: (out) (element-type VisuGlCamera*): a location to store a list of cameras. * @head: (out) (element-type VisuGlCamera*): a location to store a list of cameras. * * @inter object stores camera settings as a ring. One can access the * set of saved cameras thanks to @cameras or to the current position * in the ring thanks to @head. @cameras or @head are not copied and * are owned by V_Sim. They should be considered read-only. * * Since: 3.6 */ void visu_interactive_getSavedCameras(VisuInteractive *inter, GList **cameras, GList **head) { VisuInteractiveClass *klass; klass = VISU_INTERACTIVE_GET_CLASS(inter); g_return_if_fail(klass); *cameras = klass->savedCameras; *head = klass->lastCamera; } static gboolean cmpCameras(VisuGlCamera *c1, VisuGlCamera *c2) { return (c1 == c2) || (c1->theta == c2->theta && c1->phi == c2->phi && c1->omega == c2->omega && c1->xs == c2->xs && c1->ys == c2->ys/* && */ /* c1->gross == c2->gross && */ /* c1->d_red == c2->d_red */); } static void _pushSavedCamera(VisuInteractiveClass *klass, VisuGlCamera *camera) { VisuGlCamera *tmp; g_return_if_fail(klass && camera); for (klass->lastCamera = klass->savedCameras ; klass->lastCamera && !cmpCameras((VisuGlCamera*)klass->lastCamera->data, camera); klass->lastCamera = g_list_next(klass->lastCamera)); /* Case we don't find it, we add. */ if (!klass->lastCamera || (VisuGlCamera*)klass->lastCamera->data != camera) { tmp = g_malloc(sizeof(VisuGlCamera)); *tmp = *camera; klass->savedCameras = g_list_prepend(klass->savedCameras, (gpointer)tmp); } klass->lastCamera = klass->savedCameras; DBG_fprintf(stderr, "Interactive: push, storing now %d cameras.\n", g_list_length(klass->savedCameras)); } /** * visu_interactive_pushSavedCamera: * @inter: a #VisuInteractive object. * @camera: a #VisuGlCamera object. * * @inter object stores camera settings as a ring. The given @camera * is copied in the ring if its values not already exist. The current camera * is set to this new one. * * Since: 3.6 */ void visu_interactive_pushSavedCamera(VisuInteractive *inter, VisuGlCamera *camera) { VisuInteractiveClass *klass; klass = VISU_INTERACTIVE_GET_CLASS(inter); _pushSavedCamera(klass, camera); } gboolean visuInteractiveRemove_savedCamera(VisuInteractive *inter, VisuGlCamera *camera) { VisuInteractiveClass *klass; GList *lst; klass = VISU_INTERACTIVE_GET_CLASS(inter); g_return_val_if_fail(klass, FALSE); for (lst = klass->savedCameras ; lst && !cmpCameras((VisuGlCamera*)lst->data, camera); lst = g_list_next(lst)); /* Case we don't find it, we return. */ if (!lst) return FALSE; g_free(lst->data); klass->savedCameras = g_list_delete_link(klass->savedCameras, lst); if (klass->lastCamera == lst) klass->lastCamera = lst->next; if (!klass->lastCamera) klass->lastCamera = klass->savedCameras; DBG_fprintf(stderr, "Interactive: remove, storing now %d cameras.\n", g_list_length(klass->savedCameras)); return TRUE; } /** * visu_interactive_handleEvent: * @inter: a #VisuInteractive object ; * @view: a #VisuGlView object the interaction happened on. * @ev: a simplified event. * * This routine should be called by the rendering window when some * event is raised on the rendering surface. */ void visu_interactive_handleEvent(VisuInteractive *inter, VisuGlView *view, ToolSimplifiedEvents *ev) { gboolean stop; g_return_if_fail(VISU_IS_INTERACTIVE(inter)); DBG_fprintf(stderr, "Visu Interactive: handle event at %dx%d (%d %d).\n", ev->x, ev->y, ev->button, ev->buttonType); inter->ev = *ev; switch (inter->id) { case interactive_observe: stop = observe(inter, view, ev); break; case interactive_measureAndObserve: stop = pickAndObserve(inter, view, ev); break; case interactive_measure: case interactive_pick: stop = pick(inter, ev); break; case interactive_move: stop = move(inter, view, ev); break; case interactive_mark: stop = mark(inter, ev); break; case interactive_drag: stop = drag(inter, view, ev); break; default: stop = FALSE; break; } if (stop) g_signal_emit(G_OBJECT(inter), interactive_signals[INTERACTIVE_STOP_SIGNAL], 0, NULL); } /** * visu_interactive_setReferences: * @inter: a #VisuInteractive object. * @from: another #VisuInteractive object. * * Copies all node ids used as reference from @from to @inter. */ void visu_interactive_setReferences(VisuInteractive *inter, VisuInteractive *from) { g_return_if_fail(VISU_IS_INTERACTIVE(inter) && VISU_IS_INTERACTIVE(from)); inter->idSelected = from->idSelected; inter->idRef1 = from->idRef1; inter->idRef2 = from->idRef2; } /** * visu_interactive_getEvent: * @inter: a #VisuInteractive object. * * This routine can be called in callbacks of @inter to get some * details about the event that raise signals like * VisuInteractive::node-selection. * * Since: 3.7 * * Returns: (transfer none): a location with details on the last event. **/ ToolSimplifiedEvents* visu_interactive_getEvent(VisuInteractive *inter) { g_return_val_if_fail(VISU_IS_INTERACTIVE(inter), (ToolSimplifiedEvents*)0); return &inter->ev; } /******************************************************************************/ static gboolean pickAndObserve(VisuInteractive *inter, VisuGlView *view, ToolSimplifiedEvents *ev) { /* If button 1 or 2, use observe mode */ if (ev->button != 3 && ev->specialKey != Key_Menu) return observe(inter, view, ev); /* If button 3, use pick mode with button 3 as button 1 */ else { if (ev->shiftMod && !ev->controlMod) { ev->button = 2; } else if (!ev->shiftMod && ev->controlMod) { ev->button = 2; } else if (ev->shiftMod && ev->controlMod) { ev->shiftMod = FALSE; ev->controlMod = TRUE; ev->button = 1; } else ev->button = 1; ev->motion = FALSE; return pick(inter, ev); } } static gboolean observe(VisuInteractive *inter, VisuGlView *view, ToolSimplifiedEvents *ev) { int sign_theta; int dx, dy; VisuGlCamera *camera; float angles[3], ratio; gdouble gross, persp; gboolean zoom; g_return_val_if_fail(ev && inter, TRUE); if (ev->button == 3) return (ev->buttonType == TOOL_BUTTON_TYPE_PRESS); /* If the realese event is triggered, we exit only if it's not a scroll event (button 4 and 5). */ if (ev->button > 0 && ev->buttonType == TOOL_BUTTON_TYPE_RELEASE) if (ev->button != 4 && ev->button != 5 ) { if (ev->button == 1) g_signal_emit(G_OBJECT(inter), interactive_signals[INTERACTIVE_OBSERVE_SIGNAL], 0 , FALSE, NULL); return FALSE; } g_return_val_if_fail(view, FALSE); /* fprintf(stderr, "%d %d, %d\n", ev->x, ev->y, ev->button); */ /* fprintf(stderr, "%d %d, %d\n", ev->shiftMod, ev->controlMod, ev->motion); */ /* Support de la roulette en zoom et perspective. */ if (ev->specialKey == Key_Page_Up || ev->specialKey == Key_Page_Down || ev->button == 4 || ev->button == 5) { g_object_get(view, "zoom", &gross, "perspective", &persp, NULL); if ((ev->button == 4 || ev->specialKey == Key_Page_Up) && !ev->shiftMod) g_object_set(view, "zoom", MIN(gross * 1.1, 999.), NULL); else if ((ev->button == 4 || ev->specialKey == Key_Page_Up) && ev->shiftMod) g_object_set(view, "perspective", MAX(persp / 1.1, 1.1), NULL); else if ((ev->button == 5 || ev->specialKey == Key_Page_Down) && !ev->shiftMod) g_object_set(view, "zoom", MAX(gross / 1.1, 0.2), NULL); else if ((ev->button == 5 || ev->specialKey == Key_Page_Down) && ev->shiftMod) g_object_set(view, "perspective", MIN(persp * 1.1, 100.), NULL); } else if (ev->button && !ev->motion) { inter->xOrig = ev->x; inter->yOrig = ev->y; if (ev->button == 1) g_signal_emit(G_OBJECT(inter), interactive_signals[INTERACTIVE_OBSERVE_SIGNAL], 0 , TRUE, NULL); } else if (ev->motion || ev->specialKey == Key_Arrow_Down || ev->specialKey == Key_Arrow_Up || ev->specialKey == Key_Arrow_Right || ev->specialKey == Key_Arrow_Left) { if (ev->motion) { dx = ev->x - inter->xOrig; dy = -(ev->y - inter->yOrig); } else { g_signal_emit(G_OBJECT(inter), interactive_signals[INTERACTIVE_OBSERVE_SIGNAL], 0 , TRUE, NULL); dx = 0; dy = 0; if (ev->specialKey == Key_Arrow_Left) dx = -10; else if (ev->specialKey == Key_Arrow_Right) dx = +10; else if (ev->specialKey == Key_Arrow_Down) dy = -10; else if (ev->specialKey == Key_Arrow_Up) dy = +10; } zoom = (ev->button == 2); if(!zoom && !ev->shiftMod && !ev->controlMod) { if (local_class->preferedObserveMethod == interactive_constrained) { if(view->camera.theta > 0.0) sign_theta = 1; else sign_theta = -1; visu_gl_view_rotateBox(view, dy * 180.0f / view->window.height, -dx * 180.0f / view->window.width * sign_theta, angles); if (ev->motion) visu_gl_view_setThetaPhiOmega(view, angles[0], angles[1], 0., VISU_GL_CAMERA_THETA | VISU_GL_CAMERA_PHI); else g_object_set(view, "theta", angles[0], "phi", angles[1], NULL); } else if (local_class->preferedObserveMethod == interactive_walker) { visu_gl_view_rotateCamera(view, dy * 180.0f / view->window.height, -dx * 180.0f / view->window.width, angles); if (ev->motion) visu_gl_view_setThetaPhiOmega(view, angles[0], angles[1], angles[2], VISU_GL_CAMERA_THETA | VISU_GL_CAMERA_PHI | VISU_GL_CAMERA_OMEGA); else g_object_set(view, "theta", angles[0], "phi", angles[1], "omega", angles[2], NULL); } } else if(!zoom && ev->shiftMod && !ev->controlMod) { ratio = 1. / MIN(view->window.width, view->window.height) / view->camera.gross * (view->camera.d_red - 1.f) / view->camera.d_red; visu_gl_view_setXsYs(view, view->camera.xs + (float)dx * ratio, view->camera.ys + (float)dy * ratio, VISU_GL_CAMERA_XS | VISU_GL_CAMERA_YS); } else if(!zoom && ev->controlMod && !ev->shiftMod) { if (ABS(dx) > ABS(dy)) visu_gl_view_setThetaPhiOmega(view, 0., 0., view->camera.omega + dx * 180.0f / view->window.width, VISU_GL_CAMERA_OMEGA); else visu_gl_view_setThetaPhiOmega(view, 0., 0., view->camera.omega + dy * 180.0f / view->window.height, VISU_GL_CAMERA_OMEGA); } else if(zoom && !ev->shiftMod) visu_gl_view_setGross(view, view->camera.gross * (1. + (float)dy * 3.0f / view->window.height)); else if(zoom && ev->shiftMod) visu_gl_view_setPersp(view, view->camera.d_red * (1. - (float)dy * 5.0f / view->window.height)); if (ev->motion) { inter->xOrig = ev->x; inter->yOrig = ev->y; } else g_signal_emit(G_OBJECT(inter), interactive_signals[INTERACTIVE_OBSERVE_SIGNAL], 0 , FALSE, NULL); } else if (ev->letter == 'r') { camera = visu_interactive_popSavedCamera(inter); if (camera) { g_object_set(view, "theta", camera->theta, "phi", camera->phi, "omega", camera->omega, "zoom", camera->gross, "perspective", camera->d_red, NULL); visu_gl_view_setXsYs(view, camera->xs, camera->ys, VISU_GL_CAMERA_XS | VISU_GL_CAMERA_YS); } } else if (ev->letter == 's' && !ev->shiftMod && !ev->controlMod) visu_interactive_pushSavedCamera(inter, &view->camera); else if (ev->letter == 's' && ev->shiftMod && !ev->controlMod) visuInteractiveRemove_savedCamera(inter, &view->camera); else if (ev->letter == 'x') visu_gl_view_alignToAxis(view, TOOL_XYZ_X); else if (ev->letter == 'y') visu_gl_view_alignToAxis(view, TOOL_XYZ_Y); else if (ev->letter == 'z') visu_gl_view_alignToAxis(view, TOOL_XYZ_Z); return FALSE; } static void glDrawSelection(VisuInteractive *inter, int x, int y) { int viewport[4]; glPushAttrib(GL_ENABLE_BIT); glDisable(GL_FOG); glEnable(GL_BLEND); glDisable(GL_DEPTH_TEST); glDisable(GL_LIGHTING); glBlendFunc(GL_ONE_MINUS_DST_COLOR, GL_ONE_MINUS_SRC_COLOR); glGetIntegerv(GL_VIEWPORT, viewport); glMatrixMode(GL_PROJECTION); glPushMatrix(); glLoadIdentity(); gluOrtho2D(0.0, (float)viewport[2], 0., (float)viewport[3]); glMatrixMode(GL_MODELVIEW); glPushMatrix(); glLoadIdentity(); glColor4f(1.f, 1.f, 1.f, 1.f); glLineWidth(2); glDrawBuffer(GL_FRONT); /* We erase the previous selecting rectangle. */ glBegin(GL_LINE_LOOP); glVertex3f(inter->xOrig, (float)viewport[3] - inter->yOrig, 0.f); glVertex3f(inter->xPrev, (float)viewport[3] - inter->yOrig, 0.f); glVertex3f(inter->xPrev, (float)viewport[3] - inter->yPrev, 0.f); glVertex3f(inter->xOrig, (float)viewport[3] - inter->yPrev, 0.f); glEnd(); glFlush(); /* We draw the new selecting rectangle. */ if (x > 0 && y > 0) { glBegin(GL_LINE_LOOP); glVertex3f(inter->xOrig, (float)viewport[3] - inter->yOrig, 0.f); glVertex3f(x, (float)viewport[3] - inter->yOrig, 0.f); glVertex3f(x, (float)viewport[3] - y, 0.f); glVertex3f(inter->xOrig, (float)viewport[3] - y, 0.f); glEnd(); glFlush(); } glDrawBuffer(GL_BACK); glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA); glPopMatrix(); glMatrixMode(GL_PROJECTION); glPopMatrix(); glMatrixMode(GL_MODELVIEW); glPopAttrib(); } static gboolean pick(VisuInteractive *inter, ToolSimplifiedEvents *ev) { int nodeId; gboolean pickOnly; VisuInteractivePick pick; VisuInteractivePickError error; VisuNodeArray *nodeArray; VisuNode *nodes[3]; g_return_val_if_fail(ev && inter, TRUE); /* We store the pickInfo into the VisuData on press, but we apply it only at release if there was no drag action. */ if (ev->button == 3) { if (ev->buttonType == TOOL_BUTTON_TYPE_PRESS) return TRUE; else return FALSE; } pickOnly = (inter->id == interactive_pick); if (ev->button == 1 && ev->motion && !pickOnly) { /* We drag a selecting area. */ /* A nodeInfo should have been stored, we retrieve it. */ DBG_fprintf(stderr, "Interactive: pick, drag to %dx%d.\n", ev->x, ev->y); glDrawSelection(inter, ev->x, ev->y); inter->xPrev = ev->x; inter->yPrev = ev->y; } else if (ev->buttonType == TOOL_BUTTON_TYPE_PRESS) { /* We create and store a nodeInfo data. */ DBG_fprintf(stderr, "Interactive: pick, press at %dx%d.\n", ev->x, ev->y); inter->xOrig = ev->x; inter->yOrig = ev->y; inter->xPrev = ev->x; inter->yPrev = ev->y; } else if (ev->buttonType == TOOL_BUTTON_TYPE_RELEASE) { g_return_val_if_fail(inter->nodeList, TRUE); /* Reset current selection. */ if (inter->idRegion) g_array_unref(inter->idRegion); inter->idRegion = (GArray*)0; inter->idSelected = -1; DBG_fprintf(stderr, "Interactive: pick, release from %dx%d.\n", inter->xOrig, inter->yOrig); /* Set new selection from click. */ pick = PICK_NONE; /* If no drag action, we select the node and compute the pick mesure. */ if ((inter->xOrig == inter->xPrev && inter->yOrig == inter->yPrev) || pickOnly) { nodeId = visu_gl_ext_nodes_getSelection(inter->nodeList, ev->x, ev->y); error = PICK_ERROR_NO_SELECTION; DBG_fprintf(stderr, "Visu Interactive: set selection (single %d %d).\n", ev->shiftMod, ev->controlMod); if (pickOnly && (ev->button == 1 || ev->button == 2)) { DBG_fprintf(stderr, "Visu Interactive: set pick node %d.\n", nodeId); inter->idSelected = nodeId; pick = (nodeId >= 0)?PICK_SELECTED:PICK_NONE; } else if (!pickOnly && ev->button == 1 && !ev->controlMod) { if (nodeId >= 0) { pick = PICK_SELECTED; if (nodeId == inter->idRef1 || nodeId == inter->idRef2) { error = PICK_ERROR_SAME_REF; pick = PICK_NONE; } if (pick != PICK_NONE) { inter->idSelected = nodeId; if (inter->idRef1 >= 0) pick = (inter->idRef2 < 0)?PICK_DISTANCE:PICK_ANGLE; } } else pick = PICK_NONE; } else if (!pickOnly && ev->button == 1 && ev->controlMod) pick = (nodeId < 0)?PICK_NONE:PICK_HIGHLIGHT; else if (!pickOnly && ev->button == 2 && ev->shiftMod && !ev->controlMod) { DBG_fprintf(stderr, "Visu Interactive: set ref1 info for node %d.\n", nodeId); pick = PICK_REFERENCE_1; /* The error case. */ if (nodeId >= 0 && inter->idRef2 == nodeId) { error = PICK_ERROR_SAME_REF; pick = PICK_NONE; } else if (nodeId < 0 && inter->idRef2 >= 0) { error = PICK_ERROR_REF2; pick = PICK_NONE; } if (pick != PICK_NONE) { inter->idRef1 = nodeId; pick = (nodeId < 0)?PICK_UNREFERENCE_1:PICK_REFERENCE_1; } } else if (!pickOnly && ev->button == 2 && !ev->shiftMod && ev->controlMod) { DBG_fprintf(stderr, "Visu Interactive: set ref2 info for node %d.\n", nodeId); pick = PICK_REFERENCE_2; /* The error case. */ if (nodeId >= 0 && inter->idRef1 < 0) { error = PICK_ERROR_REF1; pick = PICK_NONE; } else if (nodeId >= 0 && inter->idRef1 == nodeId) { error = PICK_ERROR_SAME_REF; pick = PICK_NONE; } if (pick != PICK_NONE) { inter->idRef2 = nodeId; pick = (nodeId < 0)?PICK_UNREFERENCE_2:PICK_REFERENCE_2; } } else if (!pickOnly && ev->button == 2 && !ev->shiftMod && !ev->controlMod) pick = (nodeId < 0)?PICK_NONE:PICK_INFORMATION; else return FALSE; DBG_fprintf(stderr, " | OK.\n"); if (pick != PICK_NONE) { nodeArray = VISU_NODE_ARRAY(inter->dataObj); nodes[0] = visu_node_array_getFromId(nodeArray, nodeId); nodes[1] = visu_node_array_getFromId (nodeArray, (pick != PICK_REFERENCE_1)?inter->idRef1:nodeId); nodes[2] = visu_node_array_getFromId (nodeArray, (pick != PICK_REFERENCE_2)?inter->idRef2:nodeId); DBG_fprintf(stderr, "Interactive: emit node-selection with nodes" " %p, %p, %p.\n", (gpointer)nodes[0], (gpointer)nodes[1], (gpointer)nodes[2]); switch (pick) { case (PICK_SELECTED): case (PICK_HIGHLIGHT): case (PICK_INFORMATION): if (nodes[0]) g_signal_emit(G_OBJECT(inter), interactive_signals[INTERACTIVE_PICK_NODE_SIGNAL], 0, pick, inter->dataObj, nodes[0], nodes[1], nodes[2]); break; case (PICK_REFERENCE_1): case (PICK_UNREFERENCE_1): g_signal_emit(G_OBJECT(inter), interactive_signals[INTERACTIVE_PICK_NODE_SIGNAL], 0 , pick, inter->dataObj, nodes[0], nodes[1], nodes[2]); break; case (PICK_REFERENCE_2): case (PICK_UNREFERENCE_2): if (nodes[1]) g_signal_emit(G_OBJECT(inter), interactive_signals[INTERACTIVE_PICK_NODE_SIGNAL], 0 , pick, inter->dataObj, nodes[0], nodes[1], nodes[2]); break; case (PICK_DISTANCE): if (nodes[0] && nodes[1]) g_signal_emit(G_OBJECT(inter), interactive_signals[INTERACTIVE_PICK_NODE_SIGNAL], 0 , pick, inter->dataObj, nodes[0], nodes[1], nodes[2]); break; case (PICK_ANGLE): if (nodes[0] && nodes[1] && nodes[2]) g_signal_emit(G_OBJECT(inter), interactive_signals[INTERACTIVE_PICK_NODE_SIGNAL], 0 , pick, inter->dataObj, nodes[0], nodes[1], nodes[2]); break; default: break; } } else if (pick == PICK_NONE && error != PICK_ERROR_NONE) g_signal_emit(G_OBJECT(inter), interactive_signals[INTERACTIVE_PICK_ERROR_SIGNAL], 0 , error, NULL); } /* If drag action, we compute all the nodes in the rectangle and we erase it. */ else { /* We get the list of selected nodes. */ glDrawSelection(inter, -1, -1); /* Get all nodes in the region. */ inter->idRegion = visu_gl_ext_nodes_getSelectionByRegion(inter->nodeList, inter->xOrig, inter->yOrig, ev->x, ev->y); DBG_fprintf(stderr, "Interactive: set selection (drag).\n"); /* Copy the region list. */ if (inter->idRegion) g_signal_emit(G_OBJECT(inter), interactive_signals[INTERACTIVE_PICK_REGION_SIGNAL], 0 , inter->idRegion, NULL); else g_signal_emit(G_OBJECT(inter), interactive_signals[INTERACTIVE_PICK_ERROR_SIGNAL], 0 , PICK_ERROR_NO_SELECTION, NULL); } } else if (ev->specialKey == Key_Menu) { g_return_val_if_fail(inter->nodeList, TRUE); /* Set new selection from click. */ pick = PICK_NONE; /* We select the node or none. */ nodeId = visu_gl_ext_nodes_getSelection(inter->nodeList, ev->x, ev->y); if (nodeId >= 0) { nodeArray = VISU_NODE_ARRAY(inter->dataObj); nodes[0] = visu_node_array_getFromId(nodeArray, nodeId); } else nodes[0] = (VisuNode*)0; g_signal_emit(G_OBJECT(inter), interactive_signals[INTERACTIVE_PICK_MENU_SIGNAL], 0, ev->root_x, ev->root_y, nodes[0], NULL); } return FALSE; } static gboolean move(VisuInteractive *inter, VisuGlView *view, ToolSimplifiedEvents *ev) { int dx, dy, nodeId; float ratio, z, xyz[3]; VisuNode *node; float delta[3], delta0[3], centre[3]; guint i; g_return_val_if_fail(ev && inter, TRUE); if (ev->button == 3) { if (ev->buttonType == TOOL_BUTTON_TYPE_PRESS) return TRUE; else return FALSE; } if (ev->button != 1 && ev->button != 2 && ev->button != 4 && ev->button != 5 && ev->specialKey != Key_Arrow_Left && ev->specialKey != Key_Arrow_Right && ev->specialKey != Key_Arrow_Up && ev->specialKey != Key_Arrow_Down) return FALSE; DBG_fprintf(stderr, "Visu Interactive: event (%d - %d, %d %d).\n", ev->button, ev->specialKey, ev->shiftMod, ev->controlMod); if ((ev->motion == 1 || ev->button == 4 || ev->button == 5 || ev->specialKey == Key_Arrow_Left || ev->specialKey == Key_Arrow_Right || ev->specialKey == Key_Arrow_Up || ev->specialKey == Key_Arrow_Down) && inter->movingNodes) { DBG_fprintf(stderr, "Visu Interactive: drag action (%dx%d).\n", ev->x, ev->y); if (ev->specialKey == Key_Arrow_Left) { ev->x = inter->xPrev - 1; ev->y = inter->yPrev; ev->button = 1; } else if (ev->specialKey == Key_Arrow_Right) { ev->x = inter->xPrev + 1; ev->y = inter->yPrev; ev->button = 1; } else if (ev->specialKey == Key_Arrow_Up) { ev->x = inter->xPrev; ev->y = inter->yPrev - 1; ev->button = 1; } else if (ev->specialKey == Key_Arrow_Down) { ev->x = inter->xPrev; ev->y = inter->yPrev + 1; ev->button = 1; } dx = ev->x - inter->xPrev; dy = -(ev->y - inter->yPrev); DBG_fprintf(stderr, " | dx x dy : %d x %d\n", dx, dy); g_return_val_if_fail(inter->nodeList, TRUE); /* Get the camera orientation. */ if (!ev->shiftMod && !ev->controlMod) { if (ev->button == 1) { visu_box_getCentre(visu_boxed_getBox(VISU_BOXED(view)), centre); glMatrixMode(GL_MODELVIEW); glPushMatrix(); glTranslated(-centre[0], -centre[1], -centre[2]); z = 0.f; for (i = 0; i < inter->movingNodes->len; i++) { node = visu_node_array_getFromId (VISU_NODE_ARRAY(inter->dataObj), g_array_index(inter->movingNodes, guint, i)); visu_data_getNodePosition(inter->dataObj, node, xyz); z += visu_gl_view_getZCoordinate(view, xyz); } z /= (float)inter->movingNodes->len; /* Now, z contains the prev real space coord z of the selected nodes (averaged). */ visu_gl_view_getRealCoordinates(view, delta, (float)ev->x, (float)ev->y, z); visu_gl_view_getRealCoordinates(view, delta0, (float)inter->xPrev, (float)inter->yPrev, z); glPopMatrix(); /* Now, delta contains the new real space coord. */ delta[0] -= delta0[0]; delta[1] -= delta0[1]; delta[2] -= delta0[2]; } else if (ev->button > 1) { if (ev->button == 4) dy = -5; else if (ev->button == 5) dy = +5; ratio = visu_gl_window_getFileUnitPerPixel(&view->window) * dy; delta[0] = inter->movingAxe[0] * ratio; delta[1] = inter->movingAxe[1] * ratio; delta[2] = inter->movingAxe[2] * ratio; } } else if (ev->button == 1) { delta[0] = 0.f; delta[1] = 0.f; delta[2] = 0.f; ratio = visu_gl_window_getFileUnitPerPixel(&view->window); if (ABS(dy) > ABS(dx)) ratio *= ((dy > 0)?1.f:-1.f); else ratio *= ((dx > 0)?1.f:-1.f); if (ev->shiftMod && !ev->controlMod) delta[0] = ratio * sqrt(dx * dx + dy * dy); else if (ev->controlMod && !ev->shiftMod) delta[1] = ratio * sqrt(dx * dx + dy * dy); else if (ev->controlMod && ev->shiftMod) delta[2] = ratio * sqrt(dx * dx + dy * dy); } else return FALSE; DBG_fprintf(stderr, "Visu Interactive: drag a list of %d nodes of %gx%gx%g.\n", inter->movingNodes->len, delta[0], delta[1], delta[2]); visu_node_array_shiftNodes(VISU_NODE_ARRAY(inter->dataObj), inter->movingNodes, delta); /* Update stored position for drag info. */ inter->xPrev = ev->x; inter->yPrev = ev->y; DBG_fprintf(stderr, "Visu Interactive: emit the 'move' signal.\n"); g_signal_emit(G_OBJECT(inter), interactive_signals[INTERACTIVE_MOVE_SIGNAL], 0 , delta, NULL); } else if ((ev->button == 1 || ev->button == 2) && ev->buttonType == TOOL_BUTTON_TYPE_PRESS) { /* Store the position to find the drag values. */ inter->xOrig = inter->xPrev = ev->x; inter->yOrig = inter->yPrev = ev->y; /* Empty previously picked movingNodes. */ if (inter->movingPicked) { g_array_unref(inter->movingNodes); inter->movingNodes = (GArray*)0; } /* Case no list set yet. */ if (inter->movingNodes == (GArray*)0) { g_return_val_if_fail(inter->nodeList, FALSE); nodeId = visu_gl_ext_nodes_getSelection(inter->nodeList, ev->x, ev->y); if (nodeId < 0) return FALSE; inter->movingNodes = g_array_new(FALSE, FALSE, sizeof(guint)); g_array_append_val(inter->movingNodes, nodeId); inter->movingPicked = TRUE; } DBG_fprintf(stderr, "Visu Interactive: emit the 'start-move' signal.\n"); g_signal_emit(G_OBJECT(inter), interactive_signals[INTERACTIVE_START_MOVE_SIGNAL], 0, inter->movingNodes, NULL); } else if ((ev->button == 1 || ev->button == 2) && ev->buttonType == TOOL_BUTTON_TYPE_RELEASE && inter->movingNodes) { /* DBG_fprintf(stderr, "Visu Interactive: stop dragging a list of %d nodes.\n", */ /* inter->movingNodes->len); */ /* node = (VisuNode*)0; */ DBG_fprintf(stderr, "Visu Interactive: emit the 'stop-move' signal.\n"); g_signal_emit(G_OBJECT(inter), interactive_signals[INTERACTIVE_STOP_MOVE_SIGNAL], 0, delta, NULL); } return FALSE; } /** * visu_interactive_setMovingNodes: * @inter: a #VisuInteractive object. * @nodeIds: (element-type guint) (allow-none): a list of node ids. * * Defines the nodes that should be moved if @inter is a move * action session. The list is actually copied. */ void visu_interactive_setMovingNodes(VisuInteractive *inter, GArray *nodeIds) { g_return_if_fail(VISU_IS_INTERACTIVE(inter) && inter->id == interactive_move); /* Empty the node list. */ if (inter->movingNodes) g_array_unref(inter->movingNodes); inter->movingNodes = (GArray*)0; if (nodeIds && nodeIds->len > 0) { inter->movingNodes = nodeIds; DBG_fprintf(stderr, "Visu Interactive: set the list of %d nodes to move.\n", nodeIds->len); g_array_ref(nodeIds); } inter->movingPicked = FALSE; } /** * visu_interactive_setMovingAxe: * @inter: a #VisuInteractive object. * @axe: a direction. * * Defines the axe that can be used to move along if @inter is a move * action session. */ void visu_interactive_setMovingAxe(VisuInteractive *inter, float axe[3]) { float norm; norm = 1.f / sqrt(axe[0] * axe[0] + axe[1] * axe[1] + axe[2] * axe[2]); inter->movingAxe[0] = axe[0] * norm; inter->movingAxe[1] = axe[1] * norm; inter->movingAxe[2] = axe[2] * norm; } static void getDeltaScreen(gfloat delta[3], VisuGlView *view, gint x, gint y, gint xOrig, gint yOrig) { float z, centre[3], delta0[3]; visu_box_getCentre(visu_boxed_getBox(VISU_BOXED(view)), centre); glMatrixMode(GL_MODELVIEW); glPushMatrix(); glTranslated(-centre[0], -centre[1], -centre[2]); z = visu_gl_view_getZCoordinate(view, centre); visu_gl_view_getRealCoordinates(view, delta, (float)x, (float)y, z); visu_gl_view_getRealCoordinates(view, delta0, (float)xOrig, (float)yOrig, z); glPopMatrix(); /* Now, delta contains the new real space coord. */ delta[0] -= delta0[0]; delta[1] -= delta0[1]; delta[2] -= delta0[2]; } static void getDeltaAlong(gfloat delta[3], VisuGlView *view, gfloat movingAxe[3]) { int dy; float ratio; dy = 5; ratio = visu_gl_window_getFileUnitPerPixel(&view->window) * dy; delta[0] = movingAxe[0] * ratio; delta[1] = movingAxe[1] * ratio; delta[2] = movingAxe[2] * ratio; } static void getDeltaAxis(gfloat delta[3], VisuGlView *view, ToolXyzDir dir, gint dx, gint dy) { float ratio; delta[0] = 0.f; delta[1] = 0.f; delta[2] = 0.f; ratio = visu_gl_window_getFileUnitPerPixel(&view->window); DBG_fprintf(stderr, " | dx x dy : %d x %d\n", dx, dy); if (ABS(dy) > ABS(dx)) ratio *= ((dy > 0)?1.f:-1.f); else ratio *= ((dx > 0)?1.f:-1.f); delta[dir] = ratio * sqrt(dx * dx + dy * dy); } static void getDelta(VisuInteractive *inter, VisuGlView *view, ToolSimplifiedEvents *ev, gfloat delta[3]) { int dx, dy; /* Get the real space shift. */ if (ev->button == 1) { dx = ev->x - inter->xOrig; dy = -(ev->y - inter->yOrig); if (!ev->shiftMod && !ev->controlMod) getDeltaScreen(delta, view, ev->x, ev->y, inter->xOrig, inter->yOrig); else if (ev->shiftMod && !ev->controlMod) getDeltaAxis(delta, view, TOOL_XYZ_X, dx, dy); else if (ev->controlMod && !ev->shiftMod) getDeltaAxis(delta, view, TOOL_XYZ_Y, dx, dy); else if (ev->controlMod && ev->shiftMod) getDeltaAxis(delta, view, TOOL_XYZ_Z, dx, dy); } else { getDeltaAlong(delta, view, inter->movingAxe); if (ev->button == 4) { delta[0] *= -1.f; delta[1] *= -1.f; delta[2] *= -1.f; } } } static gboolean drag(VisuInteractive *inter, VisuGlView *view, ToolSimplifiedEvents *ev) { float delta[3]; g_return_val_if_fail(ev && inter, TRUE); if (ev->button == 3) { if (ev->buttonType == TOOL_BUTTON_TYPE_PRESS) return TRUE; else return FALSE; } if (ev->button != 1 && ev->button != 4 && ev->button != 5 && ev->specialKey != Key_Arrow_Left && ev->specialKey != Key_Arrow_Right && ev->specialKey != Key_Arrow_Up && ev->specialKey != Key_Arrow_Down) return FALSE; DBG_fprintf(stderr, "Visu Interactive: event (%d - %d, %d %d).\n", ev->button, ev->specialKey, ev->shiftMod, ev->controlMod); if ((ev->motion == 1 || ev->button == 4 || ev->button == 5) || ev->specialKey == Key_Arrow_Left || ev->specialKey == Key_Arrow_Right || ev->specialKey == Key_Arrow_Up || ev->specialKey == Key_Arrow_Down) { if (ev->specialKey == Key_Arrow_Left) { ev->x = inter->xPrev - 1; ev->y = inter->yPrev; ev->button = 1; } else if (ev->specialKey == Key_Arrow_Right) { ev->x = inter->xPrev + 1; ev->y = inter->yPrev; ev->button = 1; } else if (ev->specialKey == Key_Arrow_Up) { ev->x = inter->xPrev; ev->y = inter->yPrev - 1; ev->button = 1; } else if (ev->specialKey == Key_Arrow_Down) { ev->x = inter->xPrev; ev->y = inter->yPrev + 1; ev->button = 1; } DBG_fprintf(stderr, "Visu Interactive: drag action at (%dx%d).\n", ev->x, ev->y); getDelta(inter, view, ev, delta); DBG_fprintf(stderr, "Visu Interactive: drag a mouse of %gx%gx%g.\n", delta[0], delta[1], delta[2]); /* Update stored position for drag info. */ inter->xPrev = ev->x; inter->yPrev = ev->y; DBG_fprintf(stderr, "Visu Interactive: emit the 'move' signal.\n"); g_signal_emit(G_OBJECT(inter), interactive_signals[INTERACTIVE_MOVE_SIGNAL], 0 , delta, NULL); } else if (ev->button == 1 && ev->buttonType == TOOL_BUTTON_TYPE_PRESS) { g_return_val_if_fail(inter->nodeList, TRUE); /* Store the position to find the drag values. */ inter->xOrig = inter->xPrev = ev->x; inter->yOrig = inter->yPrev = ev->y; /* DBG_fprintf(stderr, "Visu Interactive: emit the 'start-move' signal.\n"); */ /* g_signal_emit(G_OBJECT(inter), */ /* interactive_signals[INTERACTIVE_START_MOVE_SIGNAL], */ /* 0, inter->movingNodes, NULL); */ } else if (ev->button == 1 && ev->buttonType == TOOL_BUTTON_TYPE_RELEASE) { getDelta(inter, view, ev, delta); DBG_fprintf(stderr, "Visu Interactive: stop dragging mouse of %gx%gx%g.\n", delta[0], delta[1], delta[2]); g_signal_emit(G_OBJECT(inter), interactive_signals[INTERACTIVE_STOP_MOVE_SIGNAL], 0 , delta, NULL); } return FALSE; } /** * visu_interactive_highlight: * @inter: a #VisuInteractive object. * @nodeId: a node id. * * This routine simulates an highlight action on @nodeId. This triggers the signal * #VisuInteractive::node-selection, or #VisuInteractive::selection-error * if @nodeId is invalid. * * Since: 3.7 **/ void visu_interactive_highlight(VisuInteractive *inter, guint nodeId) { VisuNode *nodes; nodes = visu_node_array_getFromId(VISU_NODE_ARRAY(inter->dataObj), nodeId); if (nodes) g_signal_emit(G_OBJECT(inter), interactive_signals[INTERACTIVE_PICK_NODE_SIGNAL], 0 , PICK_HIGHLIGHT, inter->dataObj, nodes, (VisuNode*)0, (VisuNode*)0); else g_signal_emit(G_OBJECT(inter), interactive_signals[INTERACTIVE_PICK_ERROR_SIGNAL], 0 , PICK_ERROR_NO_SELECTION, NULL); } /** * visu_interactive_setMessage: * @inter: a #VisuInteractive object. * @message: some text. * * Set a describing @message to be shown when @inter is used. * * Since: 3.8 **/ void visu_interactive_setMessage(VisuInteractive *inter, const gchar *message) { g_return_if_fail(VISU_IS_INTERACTIVE(inter)); g_free(inter->message); inter->message = g_strdup(message); } /** * visu_interactive_getMessage: * @inter: a #VisuInteractive object. * * Retrieves the message associated to @inter. * * Since: 3.8 * * Returns: a message. **/ const gchar* visu_interactive_getMessage(VisuInteractive *inter) { g_return_val_if_fail(VISU_IS_INTERACTIVE(inter), (const gchar*)0); return inter->message; } static gboolean mark(VisuInteractive *inter, ToolSimplifiedEvents *ev) { int nodeId; g_return_val_if_fail(ev && inter, TRUE); if (ev->button == 3 && ev->buttonType == TOOL_BUTTON_TYPE_PRESS) return TRUE; if (ev->buttonType == TOOL_BUTTON_TYPE_RELEASE) return FALSE; g_return_val_if_fail(inter->nodeList, TRUE); nodeId = visu_gl_ext_nodes_getSelection(inter->nodeList, ev->x, ev->y); visu_interactive_highlight(inter, (guint)nodeId); return FALSE; } static void onReadCamera(VisuConfigFile *obj _U_, VisuConfigFileEntry *entry _U_, VisuInteractiveClass *klass) { VisuGlCamera camera; memset(&camera, 0, sizeof(VisuGlCamera)); visu_gl_camera_setThetaPhiOmega(&camera, cameraData[0], cameraData[1], cameraData[2], VISU_GL_CAMERA_THETA | VISU_GL_CAMERA_PHI | VISU_GL_CAMERA_OMEGA); visu_gl_camera_setXsYs(&camera, cameraData[3], cameraData[4], VISU_GL_CAMERA_XS | VISU_GL_CAMERA_YS); visu_gl_camera_setGross(&camera, cameraData[5]); visu_gl_camera_setPersp(&camera, cameraData[6]); _pushSavedCamera(klass, &camera); } static void exportParameters(GString *data, VisuData *dataObj _U_) { VisuGlCamera *camera; GList *tmp; if (!local_class) visu_interactive_get_type(); g_string_append_printf(data, "# %s\n", DESC_PARAMETER_OBSERVE_METHOD); g_string_append_printf(data, "%s[gtk]: %d\n\n", FLAG_PARAMETER_OBSERVE_METHOD, local_class->preferedObserveMethod); if (local_class->savedCameras) g_string_append_printf(data, "# %s\n", DESC_PARAMETER_CAMERA_SETTINGS); for (tmp = local_class->savedCameras; tmp; tmp = g_list_next(tmp)) { camera = (VisuGlCamera*)tmp->data; g_string_append_printf(data, "%s[gtk]: %7.5g %7.5g %7.5g %4.3g %4.3g %g %g\n", FLAG_PARAMETER_CAMERA_SETTINGS, camera->theta, camera->phi, camera->omega, camera->xs, camera->ys, camera->gross, camera->d_red); } if (local_class->savedCameras) g_string_append(data, "\n"); } void visu_interactive_class_setPreferedObserveMethod(VisuInteractiveMethod method) { g_return_if_fail(method == interactive_constrained || method == interactive_walker); if (!local_class) visu_interactive_get_type(); local_class->preferedObserveMethod = method; } VisuInteractiveMethod visu_interactive_class_getPreferedObserveMethod() { if (!local_class) visu_interactive_get_type(); return local_class->preferedObserveMethod; } /* From an array of nodes ids, we specify their 2D coordinates */ void visu_interactive_class_getNodes2DCoordinates(VisuData *dataObj, guint *nodeIds, guint nNodes, GLfloat *coordinates2D, guint *size) { int i,j; guint k; VisuNode *node; float xyz[3], centre[3]; GLfloat *coord; GLint nValues; visu_box_getCentre(visu_boxed_getBox(VISU_BOXED(dataObj)), centre); coord = g_malloc(sizeof(GLfloat) * nNodes * (1 + 2)); glFeedbackBuffer(nNodes * (2 + 1), GL_2D, coord); glRenderMode(GL_FEEDBACK); glPushMatrix(); glTranslated(-centre[0], -centre[1], -centre[2]); /* Get nodes from ids and store their 2D coordinates */ glBegin(GL_POINTS); for(k = 0; k < nNodes; k++){ node = visu_node_array_getFromId(VISU_NODE_ARRAY(dataObj), nodeIds[k]); if(node != NULL) { visu_data_getNodePosition(dataObj, node, xyz); glVertex3fv(xyz); } } glEnd(); glPopMatrix(); nValues = glRenderMode(GL_RENDER); i = 0; j = 0; /* Keep only the coordinates */ while (i < nValues) { if (coord[i] == GL_POINT_TOKEN) { coordinates2D[j] = coord[i + 1]; coordinates2D[j+1] = coord[i + 2]; i += 3; j += 2; } else i++; } *size = j; } v_sim-3.8.0/src/openGLFunctions/interactive.h000066400000000000000000000223461370110300500211660ustar00rootroot00000000000000/* EXTRAITS DE LA LICENCE Copyright CEA, contributeurs : Luc BILLARD et Damien CALISTE, laboratoire L_Sim, (2001-2005) Adresse mèl : BILLARD, non joignable par mèl ; CALISTE, damien P caliste AT cea P fr. Ce logiciel est un programme informatique servant à visualiser des structures atomiques dans un rendu pseudo-3D. Ce logiciel est régi par la licence CeCILL soumise au droit français et respectant les principes de diffusion des logiciels libres. Vous pouvez utiliser, modifier et/ou redistribuer ce programme sous les conditions de la licence CeCILL telle que diffusée par le CEA, le CNRS et l'INRIA sur le site "http://www.cecill.info". Le fait que vous puissiez accéder à cet en-tête signifie que vous avez pris connaissance de la licence CeCILL, et que vous en avez accepté les termes (cf. le fichier Documentation/licence.fr.txt fourni avec ce logiciel). */ /* LICENCE SUM UP Copyright CEA, contributors : Luc BILLARD et Damien CALISTE, laboratoire L_Sim, (2001-2005) E-mail address: BILLARD, not reachable any more ; CALISTE, damien P caliste AT cea P fr. This software is a computer program whose purpose is to visualize atomic configurations in 3D. This software is governed by the CeCILL license under French law and abiding by the rules of distribution of free software. You can use, modify and/ or redistribute the software under the terms of the CeCILL license as circulated by CEA, CNRS and INRIA at the following URL "http://www.cecill.info". The fact that you are presently reading this means that you have had knowledge of the CeCILL license and that you accept its terms. You can find a copy of this licence shipped with this software at Documentation/licence.en.txt. */ #ifndef INTERACTIVE_H #define INTERACTIVE_H #include #include "view.h" #include #include #include #include /** * VisuInteractiveMethod: * @interactive_constrained: the camera is moved keeping the north * pole up. The north pole is defined by the Z axis et periodic * boundary conditions and by normal to surface in surface conditions. * @interactive_walker: the camera is moved following the mouse moves, * orienting the view as a walker would do along a sphere. * * Describes the different possible methods for observe moves. */ typedef enum { interactive_constrained, interactive_walker } VisuInteractiveMethod; /** * VisuInteractiveId: * @interactive_none: no interaction ; * @interactive_observe: interaction to rotate the view ; * @interactive_measureAndObserve: interaction to rotate the view and * access limited pick action on the right click ; * @interactive_measure: interaction to pick and measure ; * @interactive_pick: interaction to select node ; * @interactive_move: interaction to move nodes ; * @interactive_mark: interaction to mark nodes ; * @interactive_drag: interaction to get drag moves of the mouse. * * These are the possible mouse interaction that are implemented. */ typedef enum { interactive_none, interactive_observe, interactive_measureAndObserve, interactive_measure, interactive_pick, interactive_move, interactive_mark, interactive_drag } VisuInteractiveId; /** * VisuInteractivePick: * @PICK_NONE: click to void ; * @PICK_SELECTED: click to select one node ; * @PICK_DISTANCE: click to measure a distance between two nodes ; * @PICK_ANGLE: click to measure an angle ; * @PICK_HIGHLIGHT: click to highlight a node ; * @PICK_REFERENCE_1: click to select a first reference ; * @PICK_UNREFERENCE_1: click to un-select a first reference ; * @PICK_REFERENCE_2: click to select a second reference ; * @PICK_UNREFERENCE_2: click to un-select a second reference ; * @PICK_INFORMATION: click to measure distances and angles around one * node ; * @PICK_REGION: click to select a list of nodes. * * Possible significations of a click. */ typedef enum { PICK_NONE, PICK_SELECTED, PICK_DISTANCE, PICK_ANGLE, PICK_HIGHLIGHT, PICK_REFERENCE_1, PICK_UNREFERENCE_1, PICK_REFERENCE_2, PICK_UNREFERENCE_2, PICK_INFORMATION, PICK_REGION } VisuInteractivePick; /** * VisuInteractivePickError: * @PICK_ERROR_NONE: no error during click ; * @PICK_ERROR_NO_SELECTION: click to sleect but nothing selected ; * @PICK_ERROR_SAME_REF: click to set a reference but reference * already exists ; * @PICK_ERROR_REF1: click to select a first reference but impossible * to choose this one ; * @PICK_ERROR_REF2: the same for second reference. * * Possible errors to occur when pick or measure. */ typedef enum { PICK_ERROR_NONE, PICK_ERROR_NO_SELECTION, PICK_ERROR_SAME_REF, PICK_ERROR_REF1, PICK_ERROR_REF2 } VisuInteractivePickError; /** * VISU_TYPE_INTERACTIVE: * * return the type of #VisuInteractive. */ #define VISU_TYPE_INTERACTIVE (visu_interactive_get_type ()) /** * VISU_INTERACTIVE: * @obj: a #GObject to cast. * * Cast the given @obj into #VisuInteractive type. */ #define VISU_INTERACTIVE(obj) (G_TYPE_CHECK_INSTANCE_CAST(obj, VISU_TYPE_INTERACTIVE, VisuInteractive)) /** * VISU_INTERACTIVE_CLASS: * @klass: a #GObjectClass to cast. * * Cast the given @klass into #VisuInteractiveClass. */ #define VISU_INTERACTIVE_CLASS(klass) (G_TYPE_CHECK_CLASS_CAST(klass, VISU_TYPE_INTERACTIVE, VisuInteractiveClass)) /** * VISU_IS_INTERACTIVE: * @obj: a #GObject to test. * * Test if the given @ogj is of the type of #VisuInteractive object. */ #define VISU_IS_INTERACTIVE(obj) (G_TYPE_CHECK_INSTANCE_TYPE(obj, VISU_TYPE_INTERACTIVE)) /** * VISU_IS_INTERACTIVE_CLASS: * @klass: a #GObjectClass to test. * * Test if the given @klass is of the type of #VisuInteractiveClass class. */ #define VISU_IS_INTERACTIVE_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE(klass, VISU_TYPE_INTERACTIVE)) /** * VISU_INTERACTIVE_GET_CLASS: * @obj: a #GObject to get the class of. * * It returns the class of the given @obj. */ #define VISU_INTERACTIVE_GET_CLASS(obj) (G_TYPE_INSTANCE_GET_CLASS(obj, VISU_TYPE_INTERACTIVE, VisuInteractiveClass)) typedef struct _VisuInteractiveClass VisuInteractiveClass; typedef struct _VisuInteractive VisuInteractive; /** * visu_interactive_get_type: * * This method returns the type of #VisuInteractive, use VISU_TYPE_INTERACTIVE instead. * * Returns: the type of #VisuInteractive. */ GType visu_interactive_get_type(void); struct _VisuInteractiveClass { VisuObjectClass parent; VisuInteractiveMethod preferedObserveMethod; /* The save camera positions are implemented as a circular list we a pointer on the current head. */ GList *savedCameras, *lastCamera; }; /** * visu_interactive_class_setPreferedObserveMethod: * @method: an integer that identify the method, see #OPENGL_OBSERVE_CONSTRAINED, * and #OPENGL_OBSERVE_WALKER flags. * * There are two methods to move the camera in a pick and observe sesion. These * two methods are described in the commentary of the keys #OPENGL_OBSERVE_CONSTRAINED * an d#OPENGL_OBSERVE_WALKER. */ void visu_interactive_class_setPreferedObserveMethod(VisuInteractiveMethod method); /** * visu_interactive_class_getPreferedObserveMethod: * * There are two methods to move the camera in a pick and observe sesion. These * two methods are described in the commentary of the keys #OPENGL_OBSERVE_CONSTRAINED * an d#OPENGL_OBSERVE_WALKER. * * Returns: an integer that identify the method, see #OPENGL_OBSERVE_CONSTRAINED, * and #OPENGL_OBSERVE_WALKER flags. */ VisuInteractiveMethod visu_interactive_class_getPreferedObserveMethod(); VisuInteractive* visu_interactive_new(VisuInteractiveId type); gboolean visu_interactive_setType(VisuInteractive *inter, VisuInteractiveId id); VisuInteractiveId visu_interactive_getType(VisuInteractive *inter); void visu_interactive_handleEvent(VisuInteractive *inter, VisuGlView *view, ToolSimplifiedEvents *ev); ToolSimplifiedEvents* visu_interactive_getEvent(VisuInteractive *inter); void visu_interactive_setNodeList(VisuInteractive *inter, VisuGlExtNodes *nodes); void visu_interactive_setMovingNodes(VisuInteractive *inter, GArray *nodeIds); void visu_interactive_setMovingAxe(VisuInteractive *inter, float axe[3]); void visu_interactive_highlight(VisuInteractive *inter, guint nodeId); VisuGlCamera* visu_interactive_popSavedCamera(VisuInteractive *inter); void visu_interactive_pushSavedCamera(VisuInteractive *inter, VisuGlCamera *camera); void visu_interactive_getSavedCameras(VisuInteractive *inter, GList **cameras, GList **head); void visu_interactive_setReferences(VisuInteractive *inter, VisuInteractive *from); void visu_interactive_setMessage(VisuInteractive *inter, const gchar *message); const gchar* visu_interactive_getMessage(VisuInteractive *inter); /** * visu_interactive_class_getNodes2DCoordinates: (skip) * @dataObj: a #VisuData object ; * @nodeIds: an array of #VisuNode ids ; * @nNodes: the number of nodes in the array ; * @coordinates2D: an array of nodes 2D coordinates ; * @size: the size of the coordinates array. * * From nodes ids, compute and store in @coordinates2D their 2D coordinates. */ void visu_interactive_class_getNodes2DCoordinates(VisuData *dataObj, guint *nodeIds, guint nNodes, float *coordinates2D, guint *size); #endif v_sim-3.8.0/src/openGLFunctions/light.c000066400000000000000000000264351370110300500177560ustar00rootroot00000000000000/* EXTRAITS DE LA LICENCE Copyright CEA, contributeurs : Luc BILLARD et Damien CALISTE, laboratoire L_Sim, (2001-2005) Adresse mèl : BILLARD, non joignable par mèl ; CALISTE, damien P caliste AT cea P fr. Ce logiciel est un programme informatique servant à visualiser des structures atomiques dans un rendu pseudo-3D. Ce logiciel est régi par la licence CeCILL soumise au droit français et respectant les principes de diffusion des logiciels libres. Vous pouvez utiliser, modifier et/ou redistribuer ce programme sous les conditions de la licence CeCILL telle que diffusée par le CEA, le CNRS et l'INRIA sur le site "http://www.cecill.info". Le fait que vous puissiez accéder à cet en-tête signifie que vous avez pris connaissance de la licence CeCILL, et que vous en avez accepté les termes (cf. le fichier Documentation/licence.fr.txt fourni avec ce logiciel). */ /* LICENCE SUM UP Copyright CEA, contributors : Luc BILLARD et Damien CALISTE, laboratoire L_Sim, (2001-2005) E-mail address: BILLARD, not reachable any more ; CALISTE, damien P caliste AT cea P fr. This software is a computer program whose purpose is to visualize atomic configurations in 3D. This software is governed by the CeCILL license under French law and abiding by the rules of distribution of free software. You can use, modify and/ or redistribute the software under the terms of the CeCILL license as circulated by CEA, CNRS and INRIA at the following URL "http://www.cecill.info". The fact that you are presently reading this means that you have had knowledge of the CeCILL license and that you accept its terms. You can find a copy of this licence shipped with this software at Documentation/licence.en.txt. */ #include "light.h" #include #include #include #include /** * SECTION:light * @short_description: Controls the use of lights in the rendering * window. * * One can defines several lights in OpenGL. The * #VisuGlLights is an object that stores several of them and * that can be applied to the current OpenGL context using * visu_gl_lights_apply(). The lights that are created with * visu_gl_light_newDefault() are ambiant light with a white colour. The * multiplier coefficient is use to soften lights when several are * used together. It is used as a factor for all light parameters * (ambient, diffuse...) ecept the specular one. */ /** * VisuGlLight: * @enabled: if the light is used or not ; * @ambient: the ambient color of the light ; * @diffuse: the diffuse color of the light ; * @specular: the specular color of the light ; * @position: the position in space of the light ; * @multiplier: a value that multiply all color values (should be in [0;1]). * * This structure is convenient to store lights as defined by OpenGL. */ /** * VisuGlLights: * * A short way to access #_VisuGlLights objects. */ struct _VisuGlLights { guint refCount; GList* list; /* Current size of the list. */ gint nbStoredVisuGlLights; /* Number of lights called by glEnable() when last applied. */ gint nbEnabledVisuGlLights; }; /* Local methods. */ static void lighting_set(gpointer data, gpointer user_data); static VisuGlLight* light_copy(VisuGlLight *light); /** * visu_gl_lights_get_type: * * Create and retrieve a #GType for a #VisuGlLights object. * * Since: 3.7 * * Returns: a new type for #VisuGlLights structures. */ GType visu_gl_lights_get_type(void) { static GType g_define_type_id = 0; if (g_define_type_id == 0) g_define_type_id = g_boxed_type_register_static("VisuGlLights", (GBoxedCopyFunc)visu_gl_lights_ref, (GBoxedFreeFunc)visu_gl_lights_unref); return g_define_type_id; } /** * visu_gl_lights_new: * * Create a new #VisuGlLights object. It contains no light when created. * Use visu_gl_lights_add() to add new lights and * visu_gl_lights_remove() to remove others. * * Returns: a newly created #VisuGlLights. Use visu_gl_lights_free() * to free such an object. */ VisuGlLights* visu_gl_lights_new() { VisuGlLights *env; env = g_malloc(sizeof(VisuGlLights)); env->refCount = 1; env->list = (GList*)0; env->nbStoredVisuGlLights = 0; env->nbEnabledVisuGlLights = 0; return env; } /** * visu_gl_lights_ref: * @env: a #VisuGlLights object. * * Increase the ref counter. * * Since: 3.7 * * Returns: itself. **/ VisuGlLights* visu_gl_lights_ref(VisuGlLights *env) { env->refCount += 1; return env; } /** * visu_gl_lights_unref: * @env: a #VisuGlLights object. * * Decrease the ref counter, free all memory if counter reachs zero. * * Since: 3.7 **/ void visu_gl_lights_unref(VisuGlLights *env) { env->refCount -= 1; if (!env->refCount) visu_gl_lights_free(env); } /** * visu_gl_lights_free: * @env: a #VisuGlLights object. * * Free memory occupied by the given environnement. */ void visu_gl_lights_free(VisuGlLights *env) { g_return_if_fail(env); visu_gl_lights_removeAll(env); /* Need to apply to disable all previously enbaled lights before freeing the object. */ visu_gl_lights_apply(env); g_free(env); } /** * visu_gl_lights_available: * @env: a #VisuGlLights object. * * Inquire if one can add more lights to the scene. * * Since: 3.8 * * Returns: TRUE if the maximum number of lights allowed by OpenGL * implementation is not reached yet. **/ gboolean visu_gl_lights_available(VisuGlLights *env) { g_return_val_if_fail(env, FALSE); return (env->nbStoredVisuGlLights < GL_MAX_LIGHTS); } /** * visu_gl_lights_add: * @env: a #VisuGlLights object ; * @light: a #VisuGlLight object. * * This method adds the given @light to the list of known lights declared * in the given environnement. The light is not copied and should not be freed * when stored in the environnement. * * Returns: TRUE if visu_gl_lights_apply() should be called. */ gboolean visu_gl_lights_add(VisuGlLights *env, VisuGlLight *light) { g_return_val_if_fail(env && light, FALSE); g_return_val_if_fail(env->nbStoredVisuGlLights < GL_MAX_LIGHTS, FALSE); DBG_fprintf(stderr, "VisuGlLight : add a new light (%p).\n", (gpointer)light); env->list = g_list_append(env->list, light); env->nbStoredVisuGlLights += 1; return TRUE; } /** * visu_gl_lights_remove: * @env: a #VisuGlLights object ; * @light: a #VisuGlLight object. * * This method removes the given @light from the list of known lights declared * in the given environnement. The @light argument is first removed and then freed * by a call to g_free(). * * Returns: TRUE if visu_gl_lights_apply() should be called. */ gboolean visu_gl_lights_remove(VisuGlLights *env, VisuGlLight *light) { g_return_val_if_fail(env && light, FALSE); DBG_fprintf(stderr, "VisuGlLight : remove a light (%p).\n", (gpointer)light); env->list = g_list_remove(env->list, light); g_free(light); env->nbStoredVisuGlLights -= 1; return TRUE; } /** * visu_gl_lights_getList: * @env: a #VisuGlLights object. * * Retrieve the list of known #VisuGlLight used by the given environnement. * * Returns: (transfer none) (element-type VisuGlLight*): a list of * #VisuGlLight objects. Should not be freed. */ GList* visu_gl_lights_getList(VisuGlLights *env) { g_return_val_if_fail(env, (GList*)0); return env->list; } /** * visu_gl_lights_removeAll: * @env: a #VisuGlLights object. * * Empty the list of stored lights. All stored lights objects are freed. * * Returns: TRUE if the visu_gl_lights_apply() should be called. */ gboolean visu_gl_lights_removeAll(VisuGlLights *env) { GList *list; int n; g_return_val_if_fail(env, FALSE); if (!env->list) return FALSE; DBG_fprintf(stderr, "VisuGlLight : emptying list of stored lights of" " environnement %p.\n", (gpointer)env); list = env->list; n = 0; while (list) { DBG_fprintf(stderr, " | removing light %p\n", list->data); g_free(list->data); n += 1; list = g_list_next(list); } g_list_free(env->list); env->list = (GList*)0; env->nbStoredVisuGlLights = 0; return TRUE; } /** * visu_gl_lights_apply: * @env: a #VisuGlLights object. * * Apply all stored informations about lights to the current OpenGL context. * * Returns: TRUE if OpenGL context has been changed. */ gboolean visu_gl_lights_apply(VisuGlLights *env) { gint nb; float lmodel_ambient[4] = {0.2f, 0.2f, 0.2f, 1.0f}; g_return_val_if_fail(env, FALSE); if (env->nbEnabledVisuGlLights == 0 && !env->list) return FALSE; /* glPushMatrix(); */ /* glLoadIdentity(); */ glLightModelfv(GL_LIGHT_MODEL_AMBIENT, lmodel_ambient); glLightModeli(GL_LIGHT_MODEL_LOCAL_VIEWER, GL_FALSE); glEnable(GL_LIGHTING); for (nb = 0; nb < env->nbEnabledVisuGlLights; nb++) glDisable(GL_LIGHT0 + nb); g_list_foreach(env->list, lighting_set, (gpointer)env); env->nbEnabledVisuGlLights = env->nbStoredVisuGlLights; /* glPopMatrix(); */ return TRUE; } /** * visu_gl_light_newDefault: * * Create a new light with default value (white color and position in * the front, right, top position of the screen). * * Returns: the newly created #VisuGlLight. Use g_free() to deallocate this light. */ VisuGlLight* visu_gl_light_newDefault() { float params[16] = {1.0f, 1.0f, 1.0f, 1.0f, 1.0f, 1.0f, 1.0f, 1.0f, 1.0f, 1.0f, 1.0f, 1.0f, 3.0f, 2.0f, 1.7f, 0.0f}; VisuGlLight *light; int i; light = g_malloc(sizeof(VisuGlLight)); light->enabled = TRUE; light->multiplier = 1.; for(i = 0; i < 4; i++) { light->ambient[i] = params[i]; light->diffuse[i] = params[4 + i]; light->specular[i] = params[8 + i]; light->position[i] = params[12 + i]; } return light; } /** * visu_gl_light_get_type: * * Create and retrieve a #GType for a #VisuGlLight object. * * Since: 3.7 * * Returns: a new type for #VisuGlLight structures. */ GType visu_gl_light_get_type(void) { static GType g_define_type_id = 0; if (g_define_type_id == 0) g_define_type_id = g_boxed_type_register_static("VisuGlLight", (GBoxedCopyFunc)light_copy, (GBoxedFreeFunc)g_free); return g_define_type_id; } static VisuGlLight* light_copy(VisuGlLight *light) { VisuGlLight *out; out = g_malloc(sizeof(VisuGlLight)); *out = *light; return out; } static void lighting_set(gpointer data, gpointer user_data) { VisuGlLight *light0 = data; int n; float values[4]; int i; VisuGlLights *env; g_return_if_fail(user_data); env = (VisuGlLights*)user_data; n = g_list_index(env->list, light0); if(light0->enabled == FALSE) { /* From glLightfv man page : "It is always the case that GL_LIGHTi = GL_LIGHT0 + i." */ glDisable(GL_LIGHT0 + n); return; } glEnable(GL_LIGHT0 + n); for (i = 0; i < 4; i++) values[i] = light0->ambient[i] * light0->multiplier; glLightfv(GL_LIGHT0 + n, GL_AMBIENT, values); for (i = 0; i < 4; i++) values[i] = light0->diffuse[i] * light0->multiplier; glLightfv(GL_LIGHT0 + n, GL_DIFFUSE, values); for (i = 0; i < 4; i++) values[i] = light0->specular[i] * 1.; glLightfv(GL_LIGHT0 + n, GL_SPECULAR, values); glLightfv(GL_LIGHT0 + n, GL_POSITION, light0->position); DBG_fprintf(stderr, "VisuGlLight : set light [%f][%f][%f][%f]\n", light0->position[0], light0->position[1], light0->position[2], light0->multiplier); } v_sim-3.8.0/src/openGLFunctions/light.h000066400000000000000000000056701370110300500177610ustar00rootroot00000000000000/* EXTRAITS DE LA LICENCE Copyright CEA, contributeurs : Luc BILLARD et Damien CALISTE, laboratoire L_Sim, (2001-2005) Adresse mèl : BILLARD, non joignable par mèl ; CALISTE, damien P caliste AT cea P fr. Ce logiciel est un programme informatique servant à visualiser des structures atomiques dans un rendu pseudo-3D. Ce logiciel est régi par la licence CeCILL soumise au droit français et respectant les principes de diffusion des logiciels libres. Vous pouvez utiliser, modifier et/ou redistribuer ce programme sous les conditions de la licence CeCILL telle que diffusée par le CEA, le CNRS et l'INRIA sur le site "http://www.cecill.info". Le fait que vous puissiez accéder à cet en-tête signifie que vous avez pris connaissance de la licence CeCILL, et que vous en avez accepté les termes (cf. le fichier Documentation/licence.fr.txt fourni avec ce logiciel). */ /* LICENCE SUM UP Copyright CEA, contributors : Luc BILLARD et Damien CALISTE, laboratoire L_Sim, (2001-2005) E-mail address: BILLARD, not reachable any more ; CALISTE, damien P caliste AT cea P fr. This software is a computer program whose purpose is to visualize atomic configurations in 3D. This software is governed by the CeCILL license under French law and abiding by the rules of distribution of free software. You can use, modify and/ or redistribute the software under the terms of the CeCILL license as circulated by CEA, CNRS and INRIA at the following URL "http://www.cecill.info". The fact that you are presently reading this means that you have had knowledge of the CeCILL license and that you accept its terms. You can find a copy of this licence shipped with this software at Documentation/licence.en.txt. */ #ifndef LIGHT_H #define LIGHT_H #include #include G_BEGIN_DECLS typedef struct _VisuGlLights VisuGlLights; GType visu_gl_lights_get_type(void); /** * VISU_TYPE_GL_LIGHTS: * * The type of #VisuGlLights objects. */ #define VISU_TYPE_GL_LIGHTS (visu_gl_lights_get_type()) VisuGlLights* visu_gl_lights_new(); VisuGlLights* visu_gl_lights_ref(VisuGlLights *env); void visu_gl_lights_unref(VisuGlLights *env); void visu_gl_lights_free(VisuGlLights *env); typedef struct _VisuGlLight VisuGlLight; struct _VisuGlLight { gboolean enabled; float ambient[4]; float diffuse[4]; float specular[4]; float position[4]; float multiplier; }; GType visu_gl_light_get_type(void); /** * VISU_TYPE_GL_LIGHT: * * The type of #VisuGlLight objects. */ #define VISU_TYPE_GL_LIGHT (visu_gl_light_get_type()) gboolean visu_gl_lights_available(VisuGlLights *env); gboolean visu_gl_lights_add(VisuGlLights *env, VisuGlLight *light); gboolean visu_gl_lights_remove(VisuGlLights *env, VisuGlLight *light); GList* visu_gl_lights_getList(VisuGlLights *env); gboolean visu_gl_lights_removeAll(VisuGlLights *env); gboolean visu_gl_lights_apply(VisuGlLights *env); VisuGlLight* visu_gl_light_newDefault(); G_END_DECLS #endif v_sim-3.8.0/src/openGLFunctions/objectList.c000066400000000000000000000516171370110300500207510ustar00rootroot00000000000000/* EXTRAITS DE LA LICENCE Copyright CEA, contributeurs : Luc BILLARD et Damien CALISTE, laboratoire L_Sim, (2001-2005) Adresse mèl : BILLARD, non joignable par mèl ; CALISTE, damien P caliste AT cea P fr. Ce logiciel est un programme informatique servant à visualiser des structures atomiques dans un rendu pseudo-3D. Ce logiciel est régi par la licence CeCILL soumise au droit français et respectant les principes de diffusion des logiciels libres. Vous pouvez utiliser, modifier et/ou redistribuer ce programme sous les conditions de la licence CeCILL telle que diffusée par le CEA, le CNRS et l'INRIA sur le site "http://www.cecill.info". Le fait que vous puissiez accéder à cet en-tête signifie que vous avez pris connaissance de la licence CeCILL, et que vous en avez accepté les termes (cf. le fichier Documentation/licence.fr.txt fourni avec ce logiciel). */ /* LICENCE SUM UP Copyright CEA, contributors : Luc BILLARD et Damien CALISTE, laboratoire L_Sim, (2001-2005) E-mail address: BILLARD, not reachable any more ; CALISTE, damien P caliste AT cea P fr. This software is a computer program whose purpose is to visualize atomic configurations in 3D. This software is governed by the CeCILL license under French law and abiding by the rules of distribution of free software. You can use, modify and/ or redistribute the software under the terms of the CeCILL license as circulated by CEA, CNRS and INRIA at the following URL "http://www.cecill.info". The fact that you are presently reading this means that you have had knowledge of the CeCILL license and that you accept its terms. You can find a copy of this licence shipped with this software at Documentation/licence.en.txt. */ #include "objectList.h" #include #include #include #include #include #include #include #include "text.h" /** * SECTION:objectList * @short_description: Gives storage for ids used by OpenGL lists and * provides primitive routine for common drawing operations * (distances, torus...). * * When using OpenGL list, one must specify ids. This module can * return unused ids when needed. * * Here are also defined the common primitive for drawing, see * visu_gl_drawDistance() for instance. */ /* Variables to store the glObjectList. */ /* The default size of the table to store the user lists. */ #define GLOBJECTLIST_INCREMENT 15 /* First value given to user to store their glObjectList. */ #define GLOBJECTLIST_FIRST 1001 /* The table that stores the identifier of user's glObjectList. */ static int *glObjectListRegistered; /* The allocated size of this table. */ static int glObjectListRegisteredSize; /* The number of stored elements. */ static int nbGlObjectListRegistered; /* The number of user's reserved numbers of the last entry in this table. */ static int lastGlObjectListSize; /** * visu_gl_objectlist_init: (skip) * * Used to initialise this part of code, don't use it. */ void visu_gl_objectlist_init(void) { /* Initialisation of the table that stores the user glObjectList. */ glObjectListRegistered = (int*)0; glObjectListRegisteredSize = 0; nbGlObjectListRegistered = 0; lastGlObjectListSize = 0; } /** * visu_gl_objectlist_new: * @size: the requested size. * * It returns the id that can be used to link glObjectList. * This number is also added to the list of glObjectList to be displayed. * The size parameter is the number of lists that could be used by * the user for this glObjectList. Then the next call to this function * will return the last value plus the size plus one. * * Returns: an identifier used by OpenGl as a list. */ int visu_gl_objectlist_new(int size) { if (nbGlObjectListRegistered >= glObjectListRegisteredSize) { glObjectListRegisteredSize += GLOBJECTLIST_INCREMENT; glObjectListRegistered = g_realloc(glObjectListRegistered, sizeof(int) * glObjectListRegisteredSize); } if (nbGlObjectListRegistered > 0) glObjectListRegistered[nbGlObjectListRegistered] = glObjectListRegistered[nbGlObjectListRegistered - 1] + lastGlObjectListSize; else glObjectListRegistered[0] = GLOBJECTLIST_FIRST; lastGlObjectListSize = size; nbGlObjectListRegistered++; DBG_fprintf(stderr, "Object List: request %d OpenGL lists -> %d %d.\n", size, glObjectListRegistered[nbGlObjectListRegistered - 1], glObjectListRegistered[nbGlObjectListRegistered - 1] + size - 1); return glObjectListRegistered[nbGlObjectListRegistered - 1]; } static void drawRoundedHat(GLUquadricObj *obj, float hat_length, float hat_height, float radius, int nlat) { gluCylinder(obj, hat_length, 0, hat_height, nlat, 1); glRotatef(180, 1, 0, 0); gluDisk(obj, 0, radius, nlat, 1); glRotatef(180, 1, 0, 0); } static void drawRoundedTail(GLUquadricObj *obj, float tail_length, float tail_height, int nlat) { if (tail_height <= 0.f) return; glTranslatef(0, 0, -tail_height); glRotatef(180, 1, 0, 0); gluDisk(obj, 0, (tail_length)*1.03, nlat, 1); glRotatef(180, 1, 0, 0); gluCylinder(obj, tail_length, tail_length, tail_height, nlat, 1); } static void drawEdgedHat(float hat_length, float hat_height) { glBegin(GL_TRIANGLE_FAN); glNormal3f(hat_height, 0, hat_length); glVertex3f(0, 0, hat_height); glVertex3f(hat_length,-hat_length,0); glVertex3f(hat_length,hat_length,0); glNormal3f(0, hat_height, hat_length); glVertex3f(-hat_length,hat_length,0); glNormal3f(-hat_height, 0, hat_length); glVertex3f(-hat_length,-hat_length,0); glNormal3f(-hat_height, 0, hat_length); glVertex3f(hat_length,-hat_length,0); glEnd(); glBegin(GL_QUADS); glNormal3f(0., 0., -1.); glVertex3f(hat_length ,hat_length ,0 ); glVertex3f(hat_length ,-hat_length ,0 ); glVertex3f(-hat_length ,-hat_length ,0 ); glVertex3f(-hat_length ,hat_length ,0 ); glEnd(); } static void drawEdgedTail(float tail_length, float tail_height) { glBegin(GL_QUADS); glNormal3f(0., 0., 1.); glVertex3f(tail_length , tail_length , 0 ); glVertex3f(-tail_length , tail_length , 0 ); glVertex3f(-tail_length , -tail_length , 0 ); glVertex3f(tail_length , -tail_length , 0 ); glNormal3f(0., 0., -1.); glVertex3f(tail_length ,tail_length ,-tail_height ); glVertex3f(tail_length ,-tail_length ,-tail_height ); glVertex3f(-tail_length ,-tail_length ,-tail_height ); glVertex3f(-tail_length ,tail_length ,-tail_height ); glNormal3f(1., 0., 0.); glVertex3f(tail_length ,tail_length ,0 ); glVertex3f(tail_length ,-tail_length ,0 ); glVertex3f(tail_length ,-tail_length ,-tail_height ); glVertex3f(tail_length ,tail_length ,-tail_height ); glNormal3f(-1., 0., 0.); glVertex3f(-tail_length ,tail_length ,0 ); glVertex3f(-tail_length ,tail_length ,-tail_height ); glVertex3f(-tail_length ,-tail_length ,-tail_height ); glVertex3f(-tail_length ,-tail_length ,0 ); glNormal3f(0., 1., 0.); glVertex3f(-tail_length ,tail_length ,-tail_height ); glVertex3f(-tail_length ,tail_length ,0 ); glVertex3f(tail_length ,tail_length ,0 ); glVertex3f(tail_length ,tail_length ,-tail_height ); glNormal3f(0., -1., 0.); glVertex3f(-tail_length ,-tail_length ,-tail_height ); glVertex3f(tail_length ,-tail_length ,-tail_height ); glVertex3f(tail_length ,-tail_length ,0 ); glVertex3f(-tail_length ,-tail_length ,0 ); glEnd(); } /** * visu_gl_drawSmoothArrow: * @obj: (type gpointer): ... * @centering: a flag. * @tailLength: length of tail part. * @tailRadius: length of edge of tail part. * @tailN: number of edges in the approximation. * @tailRenderer: (allow-none): a given #VisuElementRenderer to take * the rendering properties of. * @hatLength: length of hat part. * @hatRadius: length of edge of hat part. * @hatN: number of edges in the approximation. * @hatRenderer: (allow-none): a given #VisuElementRenderer to take * the rendering properties of. * * Draw arrows, using sqaure edges. For rounded arrows, see * visu_gl_drawEdgeArrow(). * * Since: 3.6 */ void visu_gl_drawSmoothArrow(GLUquadricObj *obj, VisuGlArrowCentering centering, float tailLength, float tailRadius, float tailN, const VisuElementRenderer *tailRenderer, float hatLength, float hatRadius, float hatN, const VisuElementRenderer *hatRenderer) { switch (centering) { case VISU_GL_ARROW_TAIL_CENTERED: glTranslatef(0.f, 0.f, tailLength / 2.f); break; case VISU_GL_ARROW_CENTERED: glTranslatef(0.f, 0.f, -(hatLength - tailLength) / 2.f); break; case VISU_GL_ARROW_BOTTOM_CENTERED: glTranslatef(0.f, 0.f, tailLength); break; default: break; } if (tailRenderer && hatRenderer) { visu_gl_setColor((VisuGl*)0, visu_element_renderer_getMaterial(hatRenderer), visu_element_renderer_getColor(hatRenderer)->rgba); drawRoundedHat(obj, hatRadius, hatLength, MAX(hatRadius, tailRadius)*1.03, hatN); visu_gl_setColor((VisuGl*)0, visu_element_renderer_getMaterial(tailRenderer), visu_element_renderer_getColor(tailRenderer)->rgba); drawRoundedTail(obj, tailRadius, tailLength, tailN); } else if (tailRenderer) { drawRoundedHat(obj, hatRadius, hatLength, MAX(hatRadius, tailRadius)*1.03, hatN); visu_gl_setColor((VisuGl*)0, visu_element_renderer_getMaterial(tailRenderer), visu_element_renderer_getColor(tailRenderer)->rgba); drawRoundedTail(obj, tailRadius, tailLength, tailN); } else if (hatRenderer) { drawRoundedTail(obj, tailRadius, tailLength, tailN); glTranslatef(0, 0, tailLength); visu_gl_setColor((VisuGl*)0, visu_element_renderer_getMaterial(hatRenderer), visu_element_renderer_getColor(hatRenderer)->rgba); drawRoundedHat(obj, hatRadius, hatLength, MAX(hatRadius, tailRadius)*1.03, hatN); } else { drawRoundedHat(obj, hatRadius, hatLength, MAX(hatRadius, tailRadius)*1.03, hatN); drawRoundedTail(obj, tailRadius, tailLength, tailN); } } /** * visu_gl_drawEdgeArrow: * @centering: a flag. * @tailLength: length of tail part. * @tailRadius: length of edge of tail part. * @tailRenderer: (allow-none): a given #VisuElementRenderer to take * the rendering properties of. * @hatLength: length of hat part. * @hatRadius: length of edge of hat part. * @hatRenderer: (allow-none): a given #VisuElementRenderer to take * the rendering properties of. * * Draw arrows, using sqaure edges. For rounded arrows, see * visu_gl_drawSmoothArrow(). * * Since: 3.6 */ void visu_gl_drawEdgeArrow(VisuGlArrowCentering centering, float tailLength, float tailRadius, const VisuElementRenderer *tailRenderer, float hatLength, float hatRadius, const VisuElementRenderer *hatRenderer) { /* This one is a edged arrow. */ switch (centering) { case VISU_GL_ARROW_TAIL_CENTERED: glTranslatef(0.f, 0.f, tailLength / 2.f); break; case VISU_GL_ARROW_CENTERED: glTranslatef(0.f, 0.f, tailLength - (hatLength + tailLength) / 2.f); break; case VISU_GL_ARROW_BOTTOM_CENTERED: glTranslatef(0.f, 0.f, tailLength); break; default: break; } if (tailRenderer && hatRenderer) { visu_gl_setColor((VisuGl*)0, visu_element_renderer_getMaterial(hatRenderer), visu_element_renderer_getColor(hatRenderer)->rgba); drawEdgedHat(hatRadius, hatLength); visu_gl_setColor((VisuGl*)0, visu_element_renderer_getMaterial(tailRenderer), visu_element_renderer_getColor(tailRenderer)->rgba); drawEdgedTail(tailRadius, tailLength); } else if (tailRenderer) { drawEdgedHat(hatRadius, hatLength); visu_gl_setColor((VisuGl*)0, visu_element_renderer_getMaterial(tailRenderer), visu_element_renderer_getColor(tailRenderer)->rgba); drawEdgedTail(tailRadius, tailLength); } else if (hatRenderer) { drawEdgedTail(tailRadius, tailLength); visu_gl_setColor((VisuGl*)0, visu_element_renderer_getMaterial(hatRenderer), visu_element_renderer_getColor(hatRenderer)->rgba); drawEdgedHat(hatRadius, hatLength); } else { drawEdgedHat(hatRadius, hatLength); drawEdgedTail(tailRadius, tailLength); } } /** * visu_gl_drawEllipsoid: * @obj: (type gpointer): ... * @aAxis: length of long axis. * @bAxis: length of short axis. * @n: number of edges for the sphere approximation. * @renderer: (allow-none): a given #VisuElementRenderer to take * the rendering properties of. * * Draw an ellipsoid. * * Since: 3.6 */ void visu_gl_drawEllipsoid(GLUquadricObj *obj, float aAxis, float bAxis, float n, const VisuElementRenderer *renderer) { if (bAxis == 0.f) glScalef(1.f, 1.f, 10.f); else glScalef(1.f, 1.f, aAxis / bAxis); if (renderer) visu_gl_setColor((VisuGl*)0, visu_element_renderer_getMaterial(renderer), visu_element_renderer_getColor(renderer)->rgba); gluSphere(obj, bAxis, n, n); } /** * visu_gl_drawTorus: * @obj: (type gpointer): ... * @radius: global radius. * @ratio: ratio on internal radius over global radius. * @nA: number of edges for the global radius. * @nB: number of edges for the internal radius. * @renderer: (allow-none): a given #VisuElementRenderer to take * the rendering properties of. * * Draw a torus. * * Since: 3.5 */ void visu_gl_drawTorus(GLUquadricObj *obj _U_, float radius, float ratio, int nA, int nB, const VisuElementRenderer *renderer) { int i, j; float tp, tc, dtA, dtB, xp1, yp1, xp2, yp2, xc1, yc1, xc2, yc2, alpha; float a[3], b[3], c[3], d[3], aa[3], bb[3], cc[3], dd[3]; if (renderer) visu_gl_setColor((VisuGl*)0, visu_element_renderer_getMaterial(renderer), visu_element_renderer_getColor(renderer)->rgba); glBegin(GL_QUADS); glEnable(GL_NORMALIZE); dtA = 2.f*G_PI/(float)nA; dtB = 2.f*G_PI/(float)nB; alpha = 1.f / ratio; /* loop on the position of the centre of the circle which stands vertical in the plane, and which is rotated to create the torus */ for (i = 0; i < nA; i++) { tp = (float)i*dtA; xp1 = radius*cos(tp); yp1 = radius*sin(tp); xp2 = radius*cos(tp+dtA); yp2 = radius*sin(tp+dtA); /* loop around the circle */ for (j = 0; j < nB; j++) { tc = (float)j*dtB; xc1 = alpha*cos(tc); yc1 = alpha*sin(tc); xc2 = alpha*cos(tc+dtB); yc2 = alpha*sin(tc+dtB); a[0] = xp1 * (1.f + xc1); a[1] = yp1 * (1.f + xc1); a[2] = yc1 * radius; b[0] = xp2 * (1.f + xc1); b[1] = yp2 * (1.f + xc1); b[2] = yc1 * radius; c[0] = xp1 * (1.f + xc2); c[1] = yp1 * (1.f + xc2); c[2] = yc2 * radius; d[0] = xp2 * (1.f + xc2); d[1] = yp2 * (1.f + xc2); d[2] = yc2 * radius; aa[0] = xp1 * xc1; aa[1] = yp1 * xc1; aa[2] = yc1 * radius; bb[0] = xp2 * xc1; bb[1] = yp2 * xc1; bb[2] = yc1 * radius; cc[0] = xp1 * xc2; cc[1] = yp1 * xc2; cc[2] = yc2 * radius; dd[0] = xp2 * xc2; dd[1] = yp2 * xc2; dd[2] = yc2 * radius; /* Point A */ glNormal3fv(aa); glVertex3fv(a); /* Point B */ glNormal3fv(bb); glVertex3fv(b); /* Point D */ glNormal3fv(dd); glVertex3fv(d); /* Point C */ glNormal3fv(cc); glVertex3fv(c); } } glDisable(GL_NORMALIZE); glEnd(); } /** * visu_gl_drawDistance: * @xyzRef: cartesian coordinates of first ref. * @xyz: cartesian coordinates of current point. * @drawLength: a boolean. * * Draw a distance mark between @xyzRef and @xyz. A distance mark is a * colour inverted line and two squared marks on node. @drawLength * is a flag to display or not the distance value. * * Since: 3.6 */ void visu_gl_drawDistance(float xyzRef[3], float xyz[3], gboolean drawLength) { float dist; int i; char distStr[8]; glLineWidth(1); glColor4f(1., 1., 1., 0.); glBegin(GL_LINES); glVertex3fv(xyzRef); glVertex3fv(xyz); glEnd(); glPointSize(8.); glBegin(GL_POINTS); glVertex3fv(xyzRef); glVertex3fv(xyz); glEnd(); if (drawLength) { dist = 0.; for (i = 0; i < 3; i++) dist += (xyzRef[i] - xyz[i]) * (xyzRef[i] - xyz[i]); sprintf(distStr, "%7.3f", sqrt(dist)); distStr[7] = '\0'; DBG_fprintf(stderr, "OpenGL Objects: draw a link with distance %s.\n", distStr); glRasterPos3f((xyzRef[0] + xyz[0]) / 2.f, (xyzRef[1] + xyz[1]) / 2.f, (xyzRef[2] + xyz[2]) / 2.f); visu_gl_text_drawChars(distStr, VISU_GL_TEXT_NORMAL); } } /** * visu_gl_drawAngle: * @xyzRef: cartesian coordinates of first ref. * @xyzRef2: cartesian coordinates of second ref. * @xyz: cartesian coordinates of current point. * @id: a counter. * @drawLength: a boolean. * * Draw an angle mark by to distance marks and a disk taking @xyzRef * as central point and @xyzRef2 and @xyz as the two positions. @id is * a counter to obtain different colours for the disk and @drawLength * is a flag to display or not the angle value in degrees. * * Since: 3.6 */ void visu_gl_drawAngle(float xyzRef[3], float xyzRef2[3], float xyz[3], guint id, gboolean drawLength) { float dist, u[3], v[3], M[3], c, s, theta, thetaM, l; int i, iM; char distStr[9]; /* We calculate the new basis set. */ u[0] = xyz[0] - xyzRef[0]; u[1] = xyz[1] - xyzRef[1]; u[2] = xyz[2] - xyzRef[2]; l = sqrt(u[0] * u[0] + u[1] * u[1] + u[2] * u[2]); dist = 1.f / l; u[0] *= dist; u[1] *= dist; u[2] *= dist; v[0] = xyzRef2[0] - xyzRef[0]; v[1] = xyzRef2[1] - xyzRef[1]; v[2] = xyzRef2[2] - xyzRef[2]; dist = sqrt(v[0] * v[0] + v[1] * v[1] + v[2] * v[2]); l = MIN(l, dist); dist = 1.f / dist; v[0] *= dist; v[1] *= dist; v[2] *= dist; l /= 4.f; dist = u[0] * v[0] + u[1] * v[1] + u[2] * v[2]; thetaM = acos(dist); iM = MAX((int)(thetaM / G_PI * 20.f), 2); if (drawLength) { sprintf(distStr, "%5.1f\302\260", thetaM * 180.f / G_PI); distStr[8] = '\0'; DBG_fprintf(stderr, "OpenGL Objects: the angle is %g.\n", thetaM * 180.f / G_PI); } v[0] -= dist * u[0]; v[1] -= dist * u[1]; v[2] -= dist * u[2]; dist = sqrt(v[0] * v[0] + v[1] * v[1] + v[2] * v[2]); if (dist < 1e-3) { v[0] = 1.f; v[1] = 1.f; v[2] = 1.f; i = 0; if (u[0] != 0.f) i = 0; else if (u[1] != 0.f) i = 1; else if (u[2] != 0.f) i = 2; else g_warning("Selected node and reference are the same."); v[i] = 1.f - (u[0] + u[1] + u[2]) / u[i]; dist = 1.f / sqrt(v[0] * v[0] + v[1] * v[1] + v[2] * v[2]); } else dist = 1.f / dist; v[0] *= dist; v[1] *= dist; v[2] *= dist; glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA); glColor4fv(tool_color_new_bright(id)->rgba); if (drawLength) { theta = 0.5f * thetaM; c = cos(theta); s = sin(theta); M[0] = xyzRef[0] + (u[0] * c + v[0] * s) * l * 1.33f; M[1] = xyzRef[1] + (u[1] * c + v[1] * s) * l * 1.33f; M[2] = xyzRef[2] + (u[2] * c + v[2] * s) * l * 1.33f; glRasterPos3fv(M); visu_gl_text_drawChars(distStr, VISU_GL_TEXT_SMALL); } glLineWidth(1); glBegin(GL_LINES); glVertex3fv(xyzRef); glVertex3fv(xyzRef2); glVertex3fv(xyzRef); glVertex3fv(xyz); glEnd(); glEnable(GL_POLYGON_OFFSET_FILL); glPolygonOffset(1.0, 1.0); glBegin(GL_POLYGON); glVertex3fv(xyzRef); for (i = 0; i < iM; i++) { theta = (float)i / ((float)iM - 1.f) * thetaM; c = cos(theta); s = sin(theta); M[0] = xyzRef[0] + (u[0] * c + v[0] * s) * l; M[1] = xyzRef[1] + (u[1] * c + v[1] * s) * l; M[2] = xyzRef[2] + (u[2] * c + v[2] * s) * l; glVertex3fv(M); } glEnd(); glPointSize(4.); glBegin(GL_POINTS); glVertex3fv(xyzRef2); glVertex3fv(xyz); glEnd(); glDisable(GL_POLYGON_OFFSET_FILL); glColor3f (0.0, 0.0, 0.0); glLineWidth(1.1); glPolygonMode(GL_FRONT_AND_BACK, GL_LINE); glBegin(GL_POLYGON); glVertex3fv(xyzRef); for (i = 0; i < iM; i++) { theta = (float)i / ((float)iM - 1.f) * thetaM; c = cos(theta); s = sin(theta); M[0] = xyzRef[0] + (u[0] * c + v[0] * s) * l; M[1] = xyzRef[1] + (u[1] * c + v[1] * s) * l; M[2] = xyzRef[2] + (u[2] * c + v[2] * s) * l; glVertex3fv(M); } glEnd(); glPolygonMode(GL_FRONT_AND_BACK, GL_FILL); /* glColor4f(0., 0., 0., 1.); */ /* glBegin(GL_LINE_LOOP); */ /* glVertex3fv(xyzRef); */ /* for (i = 0; i < iM; i++) */ /* { */ /* theta = (float)i / ((float)iM - 1.f) * thetaM; */ /* c = cos(theta); */ /* s = sin(theta); */ /* M[0] = xyzRef[0] + (u[0] * c + v[0] * s) * l; */ /* M[1] = xyzRef[1] + (u[1] * c + v[1] * s) * l; */ /* M[2] = xyzRef[2] + (u[2] * c + v[2] * s) * l; */ /* glVertex3fv(M); */ /* } */ /* glEnd(); */ glBlendFunc(GL_ONE_MINUS_DST_COLOR, GL_ONE_MINUS_SRC_COLOR); } v_sim-3.8.0/src/openGLFunctions/objectList.h000066400000000000000000000073541370110300500207550ustar00rootroot00000000000000/* EXTRAITS DE LA LICENCE Copyright CEA, contributeurs : Luc BILLARD et Damien CALISTE, laboratoire L_Sim, (2001-2005) Adresse mèl : BILLARD, non joignable par mèl ; CALISTE, damien P caliste AT cea P fr. Ce logiciel est un programme informatique servant à visualiser des structures atomiques dans un rendu pseudo-3D. Ce logiciel est régi par la licence CeCILL soumise au droit français et respectant les principes de diffusion des logiciels libres. Vous pouvez utiliser, modifier et/ou redistribuer ce programme sous les conditions de la licence CeCILL telle que diffusée par le CEA, le CNRS et l'INRIA sur le site "http://www.cecill.info". Le fait que vous puissiez accéder à cet en-tête signifie que vous avez pris connaissance de la licence CeCILL, et que vous en avez accepté les termes (cf. le fichier Documentation/licence.fr.txt fourni avec ce logiciel). */ /* LICENCE SUM UP Copyright CEA, contributors : Luc BILLARD et Damien CALISTE, laboratoire L_Sim, (2001-2005) E-mail address: BILLARD, not reachable any more ; CALISTE, damien P caliste AT cea P fr. This software is a computer program whose purpose is to visualize atomic configurations in 3D. This software is governed by the CeCILL license under French law and abiding by the rules of distribution of free software. You can use, modify and/ or redistribute the software under the terms of the CeCILL license as circulated by CEA, CNRS and INRIA at the following URL "http://www.cecill.info". The fact that you are presently reading this means that you have had knowledge of the CeCILL license and that you accept its terms. You can find a copy of this licence shipped with this software at Documentation/licence.en.txt. */ #ifndef OBJECTLIST_H #define OBJECTLIST_H #include #include #include int visu_gl_objectlist_new(int size); void visu_gl_objectlist_init(void); /** * VisuGlArrowCentering: * @VISU_GL_ARROW_ORIGIN_CENTERED: the arrows are positioned with respect to the * point between tail and hat. * @VISU_GL_ARROW_BOTTOM_CENTERED: the arrows are positioned with respect to the bottom * of the arrow ; * @VISU_GL_ARROW_TAIL_CENTERED: the arrows are positioned with respect to the * center of the tail part ; * @VISU_GL_ARROW_CENTERED: the arrows are centered. * * The way to draw arrows (see visu_gl_drawSmoothArrow() for instance). */ typedef enum { VISU_GL_ARROW_ORIGIN_CENTERED, VISU_GL_ARROW_BOTTOM_CENTERED, VISU_GL_ARROW_TAIL_CENTERED, VISU_GL_ARROW_CENTERED } VisuGlArrowCentering; void visu_gl_drawSmoothArrow(GLUquadricObj *obj, VisuGlArrowCentering centering, float tailLength, float tailRadius, float tailN, const VisuElementRenderer *tailRenderer, float hatLength, float hatRadius, float hatN, const VisuElementRenderer *hatRenderer); void visu_gl_drawEdgeArrow(VisuGlArrowCentering centering, float tailLength, float tailRadius, const VisuElementRenderer *tailRenderer, float hatLength, float hatRadius, const VisuElementRenderer *hatRenderer); void visu_gl_drawEllipsoid(GLUquadricObj *obj, float aAxis, float bAxis, float n,const VisuElementRenderer *renderer); void visu_gl_drawTorus(GLUquadricObj *obj, float radius, float ratio, int nA, int nB, const VisuElementRenderer *renderer); void visu_gl_drawDistance(float xyzRef[3], float xyz[3], gboolean drawLength); void visu_gl_drawAngle(float xyzRef[3], float xyzRef2[3], float xyz[3], guint id, gboolean drawLength); #endif v_sim-3.8.0/src/openGLFunctions/renderingMode.c000066400000000000000000000123001370110300500214130ustar00rootroot00000000000000/* EXTRAITS DE LA LICENCE Copyright CEA, contributeurs : Luc BILLARD et Damien CALISTE, laboratoire L_Sim, (2001-2005) Adresse mèl : BILLARD, non joignable par mèl ; CALISTE, damien P caliste AT cea P fr. Ce logiciel est un programme informatique servant à visualiser des structures atomiques dans un rendu pseudo-3D. Ce logiciel est régi par la licence CeCILL soumise au droit français et respectant les principes de diffusion des logiciels libres. Vous pouvez utiliser, modifier et/ou redistribuer ce programme sous les conditions de la licence CeCILL telle que diffusée par le CEA, le CNRS et l'INRIA sur le site "http://www.cecill.info". Le fait que vous puissiez accéder à cet en-tête signifie que vous avez pris connaissance de la licence CeCILL, et que vous en avez accepté les termes (cf. le fichier Documentation/licence.fr.txt fourni avec ce logiciel). */ /* LICENCE SUM UP Copyright CEA, contributors : Luc BILLARD et Damien CALISTE, laboratoire L_Sim, (2001-2005) E-mail address: BILLARD, not reachable any more ; CALISTE, damien P caliste AT cea P fr. This software is a computer program whose purpose is to visualize atomic configurations in 3D. This software is governed by the CeCILL license under French law and abiding by the rules of distribution of free software. You can use, modify and/ or redistribute the software under the terms of the CeCILL license as circulated by CEA, CNRS and INRIA at the following URL "http://www.cecill.info". The fact that you are presently reading this means that you have had knowledge of the CeCILL license and that you accept its terms. You can find a copy of this licence shipped with this software at Documentation/licence.en.txt. */ #include "renderingMode.h" #include #include #include #include /** * SECTION:renderingMode * @short_description: Controls the way OpenGL renders objects. * * * This modules creates an interface to access to the way OpenGL * renders the objects (glPolygonMode() and glToolShadeModel() * functions). There are then three rendering modes available in * V_Sim: wireframe, flat and smooth. They are controls by an enum * #RenderingModeId. When visu_gl_rendering_applyMode() is called, the * current rendering mode is changed for all future drawing calls that * uses polygons. * */ static const char *renderingStrings[VISU_GL_RENDERING_N_MODES + 1] = {"Wireframe", "Flat", "Smooth", "SmoothAndEdge", (const char*)0}; static const char *renderingStringsI18n[VISU_GL_RENDERING_N_MODES + 1]; /** * visu_gl_rendering_init: (skip) * * This method is used by opengl.c to initialise this module (declare config file * options...). It should not be called elsewhere. */ void visu_gl_rendering_init(void) { DBG_fprintf(stderr, "OpenGl RenderingMode : initialization.\n"); renderingStringsI18n[VISU_GL_RENDERING_WIREFRAME ] = _("Wireframe"); renderingStringsI18n[VISU_GL_RENDERING_FLAT ] = _("Flat"); renderingStringsI18n[VISU_GL_RENDERING_SMOOTH ] = _("Smooth"); renderingStringsI18n[VISU_GL_RENDERING_SMOOTH_AND_EDGE] = _("Smooth & edge"); renderingStringsI18n[VISU_GL_RENDERING_N_MODES] = (const char*)0; } /** * visu_gl_rendering_applyMode: * @mode: an integer. * * Change the rendering mode of current OpenGL context. */ void visu_gl_rendering_applyMode(VisuGlRenderingMode mode) { switch (mode) { case VISU_GL_RENDERING_WIREFRAME: glShadeModel(GL_FLAT); glPolygonMode(GL_FRONT_AND_BACK, GL_LINE); glLineWidth(1); break; case VISU_GL_RENDERING_FLAT: glShadeModel(GL_FLAT); glPolygonMode(GL_FRONT_AND_BACK, GL_FILL); break; case VISU_GL_RENDERING_SMOOTH: case VISU_GL_RENDERING_SMOOTH_AND_EDGE: glShadeModel(GL_SMOOTH); glPolygonMode(GL_FRONT_AND_BACK, GL_FILL); break; default: g_warning("Wrong value for parameter 'mode' in a call" " to 'visu_gl_rendering_applyMode'."); return; } DBG_fprintf(stderr, "Rendering Mode : switch rendering mode to '%s'.\n", renderingStrings[mode]); } /** * visu_gl_rendering_getAllModeLabels: * * This function retrieve al the names (translated) of available rendering modes. * * Returns: (transfer none): an array of string, NULL terminated that * is private (not to be freed). */ const char** visu_gl_rendering_getAllModeLabels(void) { return renderingStringsI18n; } /** * visu_gl_rendering_getAllModes: * * This function retrieve al the names of available rendering modes. * * Returns: (transfer none): an array of string, NULL terminated that * is private (not to be freed). */ const char** visu_gl_rendering_getAllModes(void) { return renderingStrings; } /** * visu_gl_rendering_getModeFromName: * @name: a string ; * @id: a location to store the resulting id. * * This function retrieve the rendering mode id associated to the name. * * Returns: TRUE if the name exists. */ gboolean visu_gl_rendering_getModeFromName(const char* name, VisuGlRenderingMode *id) { g_return_val_if_fail(name && id, FALSE); *id = 0; while (*id < VISU_GL_RENDERING_N_MODES && strcmp(name, renderingStrings[*id])) *id += 1; return (*id < VISU_GL_RENDERING_N_MODES); } v_sim-3.8.0/src/openGLFunctions/renderingMode.h000066400000000000000000000057231370110300500214330ustar00rootroot00000000000000/* EXTRAITS DE LA LICENCE Copyright CEA, contributeurs : Luc BILLARD et Damien CALISTE, laboratoire L_Sim, (2001-2005) Adresse mèl : BILLARD, non joignable par mèl ; CALISTE, damien P caliste AT cea P fr. Ce logiciel est un programme informatique servant à visualiser des structures atomiques dans un rendu pseudo-3D. Ce logiciel est régi par la licence CeCILL soumise au droit français et respectant les principes de diffusion des logiciels libres. Vous pouvez utiliser, modifier et/ou redistribuer ce programme sous les conditions de la licence CeCILL telle que diffusée par le CEA, le CNRS et l'INRIA sur le site "http://www.cecill.info". Le fait que vous puissiez accéder à cet en-tête signifie que vous avez pris connaissance de la licence CeCILL, et que vous en avez accepté les termes (cf. le fichier Documentation/licence.fr.txt fourni avec ce logiciel). */ /* LICENCE SUM UP Copyright CEA, contributors : Luc BILLARD et Damien CALISTE, laboratoire L_Sim, (2001-2005) E-mail address: BILLARD, not reachable any more ; CALISTE, damien P caliste AT cea P fr. This software is a computer program whose purpose is to visualize atomic configurations in 3D. This software is governed by the CeCILL license under French law and abiding by the rules of distribution of free software. You can use, modify and/ or redistribute the software under the terms of the CeCILL license as circulated by CEA, CNRS and INRIA at the following URL "http://www.cecill.info". The fact that you are presently reading this means that you have had knowledge of the CeCILL license and that you accept its terms. You can find a copy of this licence shipped with this software at Documentation/licence.en.txt. */ #ifndef RENDERINGMODE_H #define RENDERINGMODE_H #include G_BEGIN_DECLS /** * VisuGlRenderingMode: * @VISU_GL_RENDERING_WIREFRAME: objects are rendered with lines only ; * @VISU_GL_RENDERING_FLAT: objects are rendered with polygons whose colours are uniform * on each polygon ; * @VISU_GL_RENDERING_SMOOTH: objects are rendered with polygons whose colours * are shaded to be smooth all along the object. * @VISU_GL_RENDERING_SMOOTH_AND_EDGE: objects are rendered with lines hightlighting the * contours of polygons. * @VISU_GL_RENDERING_N_MODES: number of rendering mode. * @VISU_GL_RENDERING_FOLLOW: use this value not to choose any rendering mode. * * Implemented mode to draw objects. */ typedef enum { VISU_GL_RENDERING_WIREFRAME, VISU_GL_RENDERING_FLAT, VISU_GL_RENDERING_SMOOTH, VISU_GL_RENDERING_SMOOTH_AND_EDGE, VISU_GL_RENDERING_N_MODES, VISU_GL_RENDERING_FOLLOW } VisuGlRenderingMode; void visu_gl_rendering_init(void); gboolean visu_gl_rendering_getModeFromName(const char* name, VisuGlRenderingMode *id); const char** visu_gl_rendering_getAllModes(void); const char** visu_gl_rendering_getAllModeLabels(void); void visu_gl_rendering_applyMode(VisuGlRenderingMode mode); G_END_DECLS #endif v_sim-3.8.0/src/openGLFunctions/text.c000066400000000000000000000150721370110300500176260ustar00rootroot00000000000000/* EXTRAITS DE LA LICENCE Copyright CEA, contributeurs : Luc BILLARD et Damien CALISTE, laboratoire L_Sim, (2001-2005) Adresse mèl : BILLARD, non joignable par mèl ; CALISTE, damien P caliste AT cea P fr. Ce logiciel est un programme informatique servant à visualiser des structures atomiques dans un rendu pseudo-3D. Ce logiciel est régi par la licence CeCILL soumise au droit français et respectant les principes de diffusion des logiciels libres. Vous pouvez utiliser, modifier et/ou redistribuer ce programme sous les conditions de la licence CeCILL telle que diffusée par le CEA, le CNRS et l'INRIA sur le site "http://www.cecill.info". Le fait que vous puissiez accéder à cet en-tête signifie que vous avez pris connaissance de la licence CeCILL, et que vous en avez accepté les termes (cf. le fichier Documentation/licence.fr.txt fourni avec ce logiciel). */ /* LICENCE SUM UP Copyright CEA, contributors : Luc BILLARD et Damien CALISTE, laboratoire L_Sim, (2001-2005) E-mail address: BILLARD, not reachable any more ; CALISTE, damien P caliste AT cea P fr. This software is a computer program whose purpose is to visualize atomic configurations in 3D. This software is governed by the CeCILL license under French law and abiding by the rules of distribution of free software. You can use, modify and/ or redistribute the software under the terms of the CeCILL license as circulated by CEA, CNRS and INRIA at the following URL "http://www.cecill.info". The fact that you are presently reading this means that you have had knowledge of the CeCILL license and that you accept its terms. You can find a copy of this licence shipped with this software at Documentation/licence.en.txt. */ #include "text.h" #include #include #include #ifdef HAVE_FTGL #include #endif /** * SECTION:text * @short_description: Enables capabilities to write some text on rendering screen. * * For the moment, this module is very basic and the only fonts * available is the helvetica 12 one. This module is currently broken * under Windows. */ static GLuint BASE; /* for the font display list */ static GLuint SMALL; /* for the small font display list */ static gboolean textListHaveBeenBuilt = FALSE; #ifdef HAVE_FTGL static FTGLfont *font = NULL; #endif static float fontSize = 32.f; /* only used in the case of FTGL. */ static void _putGlText(const gchar *text, VisuGlTextSize size) { g_return_if_fail(textListHaveBeenBuilt); glPushAttrib(GL_LIST_BIT); if (size == VISU_GL_TEXT_SMALL && SMALL > 0) glListBase(SMALL); else glListBase(BASE); glCallLists((int)strlen(text), GL_UNSIGNED_BYTE, (GLubyte *)text); glPopAttrib(); } static VisuGlTextFunc renderText = _putGlText; /** * visu_gl_text_putTextWithFTGL: * @text: the text to write. * @size: the size. * * A #VisuGlTextFunc routine using FTGL to render text with Pixmap * lists, see visu_gl_text_setFunc(). * * Since: 3.7 **/ void visu_gl_text_putTextWithFTGL(const gchar *text, VisuGlTextSize size) { g_return_if_fail(textListHaveBeenBuilt); #ifdef HAVE_FTGL if (size == VISU_GL_TEXT_NORMAL) ftglSetFontFaceSize(font, fontSize, fontSize); else ftglSetFontFaceSize(font, fontSize * 0.75f, fontSize * 0.75f); /* glGetFloatv(GL_CURRENT_COLOR, color); */ /* glPixelTransferf(GL_RED_BIAS, 255.f * color[0]); */ /* glPixelTransferf(GL_GREEN_BIAS, 255.f * color[1]); */ /* glPixelTransferf(GL_BLUE_BIAS, 255.f * color[2]); */ ftglRenderFont(font, text, FTGL_RENDER_ALL); /* glPixelTransferf(GL_RED_BIAS, 0.f); */ /* glPixelTransferf(GL_GREEN_BIAS, 0.f); */ /* glPixelTransferf(GL_BLUE_BIAS, 0.f); */ #else g_warning("FTGL backend not compiled, unable to write '%s' at size %d.", text, size); #endif } /** * visu_gl_text_setFunc: * @func: (scope call) (allow-none): a #VisuGlTextFunc function * * Set the function to render text at the raster position. * * Since: 3.7 * * Returns: TRUE if the function is indeed changed. **/ gboolean visu_gl_text_setFunc(VisuGlTextFunc func) { if (func == renderText) return FALSE; renderText = (func)?func:_putGlText; return TRUE; } /** * visu_gl_text_setFontSize: * @size: a new size. * * Change the normal font size used by V_Sim (see * #VISU_GL_TEXT_NORMAL). The small font is scaled accordingly. This is working only * with the FTGL backend. * * Since: 3.7 * * Returns: TRUE if font size is indeed changed. **/ gboolean visu_gl_text_setFontSize(float size) { if (size == fontSize) return FALSE; fontSize = CLAMP(size, 12.f, 999.f); return TRUE; } /** * visu_gl_text_drawChars: * @s: a string. * @size: the size of the text to render. * * Draw the given string on the current raster position with default * font. */ void visu_gl_text_drawChars(const gchar *s, VisuGlTextSize size) { gsize nread, nwritten; GError *error; gchar *text; g_return_if_fail(s); DBG_fprintf(stderr, "OpenGL Text: put text '%s'.\n", s); error = (GError*)0; text = g_convert_with_fallback(s, -1, "iso-8859-1", "utf-8", "", &nread, &nwritten, &error); if (text) { renderText(text, size); g_free(text); } else { g_warning("%s", error->message); g_error_free(error); } } /** * visu_gl_text_initFontList: * * Initialise the font drawing with default font (depending on system). * It must be called before visu_gl_text_drawChars() and not in a glNewList(). * Can be called several times, fonts are initialized once only. Use * visu_gl_text_rebuildFontList() to force to build a new font list. */ void visu_gl_text_initFontList() { if (textListHaveBeenBuilt) return; BASE = visu_gl_initFontList(18); SMALL = visu_gl_initFontList(14); textListHaveBeenBuilt = (BASE > 0); DBG_fprintf(stderr, "OpenGL Text: creating font list: %d %d.\n", BASE, SMALL); g_return_if_fail(BASE > 0 && SMALL > 0); #ifdef HAVE_FTGL font = ftglCreatePixmapFont("/usr/share/fonts/truetype/ttf-dejavu/DejaVuSans.ttf"); #endif } /** * visu_gl_text_rebuildFontList: * * Force to buid a new font list (for example new context has changed. */ void visu_gl_text_rebuildFontList() { DBG_fprintf(stderr, "OpenGL Text: rebuilding font list.\n"); visu_gl_text_initFontList(); } /** * visu_gl_text_onNewContext: * * Set the flag for text list build to FALSE. It will force to rebuild * the text lists at next call of visu_gl_text_initFontList(). * * Since: 3.6 */ void visu_gl_text_onNewContext() { DBG_fprintf(stderr, "OpenGL Text: new context, forgetting fonts.\n"); textListHaveBeenBuilt = FALSE; } v_sim-3.8.0/src/openGLFunctions/text.h000066400000000000000000000051471370110300500176350ustar00rootroot00000000000000/* EXTRAITS DE LA LICENCE Copyright CEA, contributeurs : Luc BILLARD et Damien CALISTE, laboratoire L_Sim, (2001-2005) Adresse mèl : BILLARD, non joignable par mèl ; CALISTE, damien P caliste AT cea P fr. Ce logiciel est un programme informatique servant à visualiser des structures atomiques dans un rendu pseudo-3D. Ce logiciel est régi par la licence CeCILL soumise au droit français et respectant les principes de diffusion des logiciels libres. Vous pouvez utiliser, modifier et/ou redistribuer ce programme sous les conditions de la licence CeCILL telle que diffusée par le CEA, le CNRS et l'INRIA sur le site "http://www.cecill.info". Le fait que vous puissiez accéder à cet en-tête signifie que vous avez pris connaissance de la licence CeCILL, et que vous en avez accepté les termes (cf. le fichier Documentation/licence.fr.txt fourni avec ce logiciel). */ /* LICENCE SUM UP Copyright CEA, contributors : Luc BILLARD et Damien CALISTE, laboratoire L_Sim, (2001-2005) E-mail address: BILLARD, not reachable any more ; CALISTE, damien P caliste AT cea P fr. This software is a computer program whose purpose is to visualize atomic configurations in 3D. This software is governed by the CeCILL license under French law and abiding by the rules of distribution of free software. You can use, modify and/ or redistribute the software under the terms of the CeCILL license as circulated by CEA, CNRS and INRIA at the following URL "http://www.cecill.info". The fact that you are presently reading this means that you have had knowledge of the CeCILL license and that you accept its terms. You can find a copy of this licence shipped with this software at Documentation/licence.en.txt. */ #ifndef TEXT_H #define TEXT_H #include /** * VisuGlTextSize: * @VISU_GL_TEXT_NORMAL: normal size (14) ; * @VISU_GL_TEXT_SMALL: small text (12). * * Different text size available in V_Sim. */ typedef enum { VISU_GL_TEXT_NORMAL, VISU_GL_TEXT_SMALL } VisuGlTextSize; /** * VisuGlTextFunc: * @text: the text to render. * @size: the size for rendering. * * A function that render iso8859-1 text at the current raster * position. * * Since: 3.7 */ typedef void (*VisuGlTextFunc)(const gchar *text, VisuGlTextSize size); gboolean visu_gl_text_setFunc(VisuGlTextFunc func); gboolean visu_gl_text_setFontSize(float size); void visu_gl_text_drawChars(const gchar *s, VisuGlTextSize size); void visu_gl_text_initFontList(); void visu_gl_text_rebuildFontList(); void visu_gl_text_onNewContext(); void visu_gl_text_putTextWithFTGL(const gchar *text, VisuGlTextSize size); #endif v_sim-3.8.0/src/openGLFunctions/view.c000066400000000000000000002171051370110300500176150ustar00rootroot00000000000000/* EXTRAITS DE LA LICENCE Copyright CEA, contributeurs : Luc BILLARD et Damien CALISTE, laboratoire L_Sim, (2001-2005) Adresse mèl : BILLARD, non joignable par mèl ; CALISTE, damien P caliste AT cea P fr. Ce logiciel est un programme informatique servant à visualiser des structures atomiques dans un rendu pseudo-3D. Ce logiciel est régi par la licence CeCILL soumise au droit français et respectant les principes de diffusion des logiciels libres. Vous pouvez utiliser, modifier et/ou redistribuer ce programme sous les conditions de la licence CeCILL telle que diffusée par le CEA, le CNRS et l'INRIA sur le site "http://www.cecill.info". Le fait que vous puissiez accéder à cet en-tête signifie que vous avez pris connaissance de la licence CeCILL, et que vous en avez accepté les termes (cf. le fichier Documentation/licence.fr.txt fourni avec ce logiciel). */ /* LICENCE SUM UP Copyright CEA, contributors : Luc BILLARD et Damien CALISTE, laboratoire L_Sim, (2001-2005) E-mail address: BILLARD, not reachable any more ; CALISTE, damien P caliste AT cea P fr. This software is a computer program whose purpose is to visualize atomic configurations in 3D. This software is governed by the CeCILL license under French law and abiding by the rules of distribution of free software. You can use, modify and/ or redistribute the software under the terms of the CeCILL license as circulated by CEA, CNRS and INRIA at the following URL "http://www.cecill.info". The fact that you are presently reading this means that you have had knowledge of the CeCILL license and that you accept its terms. You can find a copy of this licence shipped with this software at Documentation/licence.en.txt. */ #include #include #include #include #include #include #include #include #include "view.h" /** * SECTION:view * @short_description: Defines all necessary informations for the * rendering of a view. * * The #VisuGlView stores two basic informations: one for the * position and orientation of the camera (#VisuGlCamera) and one last for the * definition of the viewing window (#VisuGlWindow, including volumic * informations). * * One resource is used by this part, defining the precision * desired by the user when drawing OpenGL objects. This precision can * be changed using visu_gl_view_setPrecision() and all V_Sim part * drawing something should use visu_gl_view_getDetailLevel() to * know the size of the vertices to be drawn depending on this * precision and the level of zoom. * * The rendering is done in an OpenGl viewport whose size is * given by the bounding box (plus 10%). The camera can be positionned * with three angles (theta, phi and omega) and has a zoom factor * (gross) and a perspective value (d_red). The angle theta is around * the z axis (box coordinates), phi is around the new x axis (after * the theta rotation) and omega is a rotation around the axis which * goes from the observer to the center of the bounding box. By * default the camera looks at the center of the bounding box but this * can be changed with the Xs and Ys parameters. These values are * stored and are readable through the #VisuGlCamera structure. They * must be changed with the following methods to ensure propery * signals are correctly emitted: * visu_gl_view_setThetaPhiOmega(), visu_gl_view_setGross(), * visu_gl_view_setPersp() and visu_gl_view_setXsYs(). */ /** * VisuGlCamera: * @d_red: a factor for perspective from 1. to inifnity. With one, the nose of * the observer is completly set on the rendered object, and the size * of the observer is neglectible compared to the size of the object. * @theta: the theta angle in spherical coordinates of the position of the observer ; * @phi: the phi angle in spherical coordinates of the position of the observer ; * @omega: rotation of the observer on itself ; * @xs: a value for translation of the viewport on x axis ; * @ys: a value for translation of the viewport on y axis ; * @gross: a value of zoom ; * @length0: a length reference to adimension all values, by default, * this is the longest diagonal of the current box (without * duplication) ; * @up: (in) (array fixed-size=3): the current up vector. * @upAxis: which axis define the north pole. * @centre: (in) (array fixed-size=3): position of the eye look at ; * @eye: (in) (array fixed-size=3): position of the eye. * @unit: the unit of @length0. * * Values to define the position of the observer. */ /** * VisuGlWindow: * @extens: additional length to add to length0 to obtain the global * viewable area. * @unit: the #ToolUnits of @extens. * @width : the width of the window ; * @height : the height of the window ; * @near : the beginning of the viewport on z axis (z for observer) ; * @far : the end of the viewport on z axis (z for observer) ; * @left : the left of the viewport on x axis ; * @right : the right of the viewport on x axis ; * @bottom : the bottom of the viewport on y axis ; * @top : the top of the viewport on y axis ; * * Values to describe the window where the render is done. */ /* Global value used as default when creating a new VisuGlView. */ static float anglesDefault[3] = {40., -50., 0.}; static float translatDefault[2] = {0.5, 0.5}; static float grossDefault = 1.; static float perspDefault = 5.; /* Local methods. */ static VisuGlCamera* camera_copy(VisuGlCamera *camera); /** * visu_gl_camera_get_type: * * Create and retrieve a #GType for a #VisuGlCamera object. * * Since: 3.7 * * Returns: a new type for #VisuGlCamera structures. */ GType visu_gl_camera_get_type(void) { static GType g_define_type_id = 0; if (g_define_type_id == 0) g_define_type_id = g_boxed_type_register_static("VisuGlCamera", (GBoxedCopyFunc)camera_copy, (GBoxedFreeFunc)g_free); return g_define_type_id; } /** * visu_gl_camera_copy: * @to: a location to copy values to * @from: a #VisuGlCamera to copy values from * * Do a deep copy of @from to @to. * * Since: 3.7 **/ void visu_gl_camera_copy(VisuGlCamera *to, const VisuGlCamera *from) { to->theta = from->theta; to->phi = from->phi; to->omega = from->omega; to->xs = from->xs; to->ys = from->ys; to->gross = from->gross; to->d_red = from->d_red; to->length0 = from->length0; to->unit = from->unit; to->upAxis = from->upAxis; to->centre[0] = from->centre[0]; to->centre[1] = from->centre[1]; to->centre[2] = from->centre[2]; to->up[0] = from->up[0]; to->up[1] = from->up[1]; to->up[2] = from->up[2]; to->eye[0] = from->eye[0]; to->eye[1] = from->eye[1]; to->eye[2] = from->eye[2]; } static VisuGlCamera* camera_copy(VisuGlCamera *camera) { VisuGlCamera *out; out = g_malloc(sizeof(VisuGlCamera)); visu_gl_camera_copy(out, camera); return out; } /** * visu_gl_camera_setThetaPhiOmega: * @camera: a valid #VisuGlCamera object ; * @valueTheta: a floatinf point value in degrees ; * @valuePhi: a floating point value in degrees ; * @valueOmega: a floating point value in degrees ; * @mask: to specified what values will be changed. * * Change the orientation of the camera to the specified angles. * * Returns: a mask of changed values. */ int visu_gl_camera_setThetaPhiOmega(VisuGlCamera *camera, float valueTheta, float valuePhi, float valueOmega, int mask) { float valT, valP, valO; int diff; g_return_val_if_fail(camera, FALSE); diff = 0; if (mask & VISU_GL_CAMERA_THETA) { valT = valueTheta; while (valT < -180.) valT += 360.; while (valT > 180.) valT -= 360.; if (camera->theta != valT) { diff += VISU_GL_CAMERA_THETA; camera->theta = valT; } } if (mask & VISU_GL_CAMERA_PHI) { valP = valuePhi; while (valP < -180.) valP += 360.; while (valP > 180.) valP -= 360.; if (camera->phi != valP) { diff += VISU_GL_CAMERA_PHI; camera->phi = valP; } } if (mask & VISU_GL_CAMERA_OMEGA) { valO = valueOmega; while (valO < -180.) valO += 360.; while (valO > 180.) valO -= 360.; if (camera->omega != valO) { diff += VISU_GL_CAMERA_OMEGA; camera->omega = valO; } } return diff; } /** * visu_gl_camera_setXsYs: * @camera: a valid #VisuGlCamera object ; * @valueX: a floatinf point value in the bounding box scale * (1 is the size of the bounding box) ; * @valueY: a floating point value in bounding box scale ; * @mask: to specified what values will be changed. * * Change the point where the camera is pointed to. * * Returns: a mask of changed values. */ int visu_gl_camera_setXsYs(VisuGlCamera *camera, float valueX, float valueY, int mask) { int diff; g_return_val_if_fail(camera, FALSE); diff = 0; if (mask & VISU_GL_CAMERA_XS) { valueX = CLAMP(valueX, -3., 3.); if (camera->xs != valueX) { diff += VISU_GL_CAMERA_XS; camera->xs = valueX; } } if (mask & VISU_GL_CAMERA_YS) { valueY = CLAMP(valueY, -3., 3.); if (camera->ys != valueY) { diff += VISU_GL_CAMERA_YS; camera->ys = valueY; } } return diff; /* g_signal_emit (visu, VISU_GET_CLASS (visu)->OpenGLXsYs_signal_id, */ /* 0 , NULL); */ /* project(view); */ /* Change the eyes position. */ /* O[0] = view->camera->centre[0] + view->box->dxxs2; */ /* O[1] = view->camera->centre[1] + view->box->dyys2; */ /* O[2] = view->camera->centre[2] + view->box->dzzs2; */ /* z = visu_gl_view_getZCoordinate(view, O); */ /* DBG_fprintf(stderr, "OpenGL View: new window coordinates (%f;%f;%f).\n", */ /* 0.5f * view->window->width, 0.5f * view->window->height, z); */ /* visu_gl_view_getRealCoordinates(view, view->camera->centre, */ /* 0.5f * view->window->width, */ /* 0.5f * view->window->height, z, FALSE); */ /* modelize(view); */ } /** * visu_gl_camera_setGross: * @camera: a valid #VisuGlCamera object ; * @value: a positive floating point value. * * Change the value of the camera zoom value. If the value is higher than 10 * it is set to 10 and if the value is negative it is set to 0.001. * * Returns: TRUE if value is actually changed. */ gboolean visu_gl_camera_setGross(VisuGlCamera *camera, float value) { float val; g_return_val_if_fail(camera, FALSE); val = value; if (val < 0.02) val = 0.02; else if (val > 999.) val = 999.; if (camera->gross == val) return FALSE; camera->gross = val; /* g_signal_emit (visu, VISU_GET_CLASS (visu)->OpenGLGross_signal_id, */ /* 0 , NULL); */ /* project(view); */ /* g_signal_emit (visu, VISU_GET_CLASS (visu)->OpenGLFacetteChanged_signal_id, */ /* 0 , NULL); */ return TRUE; } /** * visu_gl_camera_setPersp: * @camera: a valid #VisuGlCamera object ; * @value: a floating point value greater than 1.1. * * Change the value of the camera perspective value and put it in * bounds if needed. * * Returns: TRUE if value is actually changed. */ gboolean visu_gl_camera_setPersp(VisuGlCamera *camera, float value) { g_return_val_if_fail(camera, FALSE); DBG_fprintf(stderr, "Visu GlCamera: set persp to %g (%g).\n", value, camera->d_red); value = CLAMP(value, 1.1f, 100.f); if (camera->d_red == value) return FALSE; camera->d_red = value; /* project(view); */ /* modelize(view); */ return TRUE; } /** * visu_gl_window_setViewport: * @window: a valid #VisuGlWindow object ; * @width: the new horizontal size ; * @height: the new vertical size. * * It changes the size of the OpenGl area and reccompute the OpenGL viewport. * * Returns: TRUE the size of @window is actually changed. */ gboolean visu_gl_window_setViewport(VisuGlWindow *window, guint width, guint height) { DBG_fprintf(stderr, "OpenGL Window: set viewport size (%dx%d) for window %p.\n", width, height, (gpointer)window); g_return_val_if_fail(window, FALSE); if (window->width == width && window->height == height) return FALSE; DBG_fprintf(stderr, " | old values were %dx%d.\n", window->width, window->height); window->width = width; window->height = height; glViewport(0, 0, window->width, window->height); return TRUE; } /** * visu_gl_window_setAddLength: * @window: a #VisuGlWindow object. * @value: a float value (positive). * @unit: the unit of @value. * * The viewable area is defined by the #VisuGlCamera size, as set by * visu_gl_camera_setRefLength() and by additional space setup by this routine. * * Since: 3.7 * * Returns: TRUE if the value is indeed changed. **/ gboolean visu_gl_window_setAddLength(VisuGlWindow *window, float value, ToolUnits unit) { DBG_fprintf(stderr, "OpenGL Window: set additional length (%f) for window %p.\n", value, (gpointer)window); g_return_val_if_fail(window, FALSE); if (window->extens == value && window->unit == unit) return FALSE; window->extens = value; window->unit = unit; return TRUE; } /** * visu_gl_window_getAddLength: * @window: a #VisuGlWindow object. * @unit: (allow-none): a location for the unit of the returned value. * * The viewable area is defined by the #VisuGlCamera size, as set by * visu_gl_camera_setRefLength() and by additional space setup by * visu_gl_window_setAddLength(). * * Since: 3.7 * * Returns: the additional length to be added to the camera object * size to obtain the full viewable area. **/ float visu_gl_window_getAddLength(VisuGlWindow *window, ToolUnits *unit) { g_return_val_if_fail(window, FALSE); DBG_fprintf(stderr, "OpenGL Window: get additional length (%f) for window %p.\n", window->extens, (gpointer)window); if (unit) *unit = window->unit; return window->extens; } /** * visu_gl_camera_setUpAxis: * @camera: a #VisuGlCamera object. * @upAxis: a direction. * * In constraint observation mode, the "north" direction is a singular * one. Define this direction with this routine. * * Since: 3.6 */ void visu_gl_camera_setUpAxis(VisuGlCamera *camera, ToolXyzDir upAxis) { g_return_if_fail(camera); camera->upAxis = upAxis; } /** * visu_gl_camera_setRefLength: * @camera: a #VisuGlCamera object. * @value: a new length. * @unit: its measurement unit. * * Change the reference value that is used for the zoom. * * Since: 3.6 * * Returns: TRUE if the value is indeed changed. */ gboolean visu_gl_camera_setRefLength(VisuGlCamera *camera, float value, ToolUnits unit) { g_return_val_if_fail(camera, FALSE); DBG_fprintf(stderr, "Visu GlCamera: set ref length to %g %d (prev was %g %d)\n", value, unit, camera->length0, camera->unit); if (camera->length0 == value && camera->unit == unit) return FALSE; camera->length0 = value; camera->unit = unit; return TRUE; } /** * visu_gl_camera_getRefLength: * @camera: a #VisuGlCamera object. * @unit: a location for unit value (can be NULL). * * The zoom is define from a reference length in given unit. If @unit * is provided, the corresponding unit will be set. * * Since: 3.6 * * Returns: the current reference length. */ float visu_gl_camera_getRefLength(VisuGlCamera *camera, ToolUnits *unit) { g_return_val_if_fail(camera, -1.f); if (unit) *unit = camera->unit; return camera->length0; } /** * visu_gl_camera_modelize: * @camera: a #VisuGlCamera object. * * Set-up the orientation matrix, depending on the camera definition. */ static void visu_gl_camera_modelize(VisuGlCamera *camera) { double theta_rad, d_red; double phi_rad; double sth, cth, sph, cph, com, som; double distance; int permut[3][3] = {{1,2,0}, {2,0,1}, {0,1,2}}; g_return_if_fail(camera); DBG_fprintf(stderr, "OpenGL Camera: modelize view.\n"); DBG_fprintf(stderr, "OpenGL Camera: using ref length %g.\n", camera->length0); if (camera->d_red > 100.) d_red = 100.; else d_red = camera->d_red; theta_rad = camera->theta * TOOL_PI180; phi_rad = camera->phi * TOOL_PI180; distance = d_red * camera->length0; sth = sin(theta_rad); cth = cos(theta_rad); sph = sin(phi_rad); cph = cos(phi_rad); com = cos(camera->omega * TOOL_PI180); som = sin(camera->omega * TOOL_PI180); /* La matrice de rotation est la suivante pour passer des coordonnées transformées aux coordonnées de l'écran : /cph.cth -sph cph.sth\ |sph.cth cph sph.sth| (for z as north axis) \ -sth 0 cth/ / cph -sph.sth sph.cth\ | 0 cth sth| (for y as north axis) \-sph -sth.cph cph.cth/ Ainsi la caméra qui est situé en (0,0,Distance) dans le repère transformé devient dans le repère de l'écran : */ camera->eye[permut[camera->upAxis][0]] = distance*sth*cph; camera->eye[permut[camera->upAxis][1]] = distance*sth*sph; camera->eye[permut[camera->upAxis][2]] = distance*cth; /* Vecteur donnant la direction verticale. Dans le repère transformé il est (-1,0,0). */ camera->up[permut[camera->upAxis][0]] = -cth*cph*com + sph*som; camera->up[permut[camera->upAxis][1]] = -cth*sph*com - cph*som; camera->up[permut[camera->upAxis][2]] = sth*com; DBG_fprintf(stderr, "Visu GlView: modelize with:\n"); DBG_fprintf(stderr, " | %g %g %g %g %g %g %g %g %g\n", camera->eye[0], camera->eye[1], camera->eye[2], camera->centre[0], camera->centre[1], camera->centre[2], camera->up[0], camera->up[1], camera->up[2]); glMatrixMode(GL_MODELVIEW); glLoadIdentity(); gluLookAt(camera->eye[0], camera->eye[1], camera->eye[2], camera->centre[0], camera->centre[1], camera->centre[2], camera->up[0], camera->up[1], camera->up[2]); } /** * visu_gl_window_project: * @window: definition of the screen. * @camera: position of the camera. * * This method is used to set the projection and the OpenGL viewport. */ static void visu_gl_window_project(VisuGlWindow *window, const VisuGlCamera *camera) { double x, y, xmin, xmax, ymin, ymax, fact, rap; double rap_win, d_red; g_return_if_fail(camera && window); DBG_fprintf(stderr, "OpenGL View: project view (%d, %d).\n", camera->unit, window->unit); DBG_fprintf(stderr, " | %g %g.\n", camera->length0, window->extens); if (camera->length0 <= 0. || camera->unit != window->unit) return; if (camera->d_red > 100.) d_red = 100.; else d_red = camera->d_red; fact = d_red * camera->length0; window->near = MAX(0.01, fact - window->extens); window->far = fact + window->extens; fact = window->near / camera->gross / d_red; rap = 2. * window->near / (d_red - 1.); x = (0.5 - camera->xs) * rap; xmin = x - fact; xmax = x + fact; y = (0.5 - camera->ys) * rap; ymin = y - fact; ymax = y + fact; window->left = xmin; window->bottom = ymin; rap_win = (1.0*window->height)/window->width; if ( 1. > rap_win ) { window->top = ymax; fact = (ymax - ymin) / rap_win; window->left = 0.5 * (xmin + xmax - fact); window->right = 0.5 * (xmin + xmax + fact); } else if ( 1. < rap_win ) { window->right = xmax; fact = (xmax - xmin) * rap_win; window->bottom = 0.5 * (ymin + ymax - fact); window->top = 0.5 * (ymin + ymax + fact); } else { window->right = xmax; window->top = ymax; } DBG_fprintf(stderr, "Visu GlView: project:\n"); DBG_fprintf(stderr, " | %g %g %g %g %g %g\n", window->left, window->right, window->bottom, window->top, window->near, window->far); glMatrixMode(GL_PROJECTION); glLoadIdentity(); if (d_red == 100.) glOrtho(window->left, window->right, window->bottom, window->top, window->near, window->far); else glFrustum(window->left, window->right, window->bottom, window->top, window->near, window->far); glMatrixMode(GL_MODELVIEW); } /***************************/ /* The #VisuGlView object. */ /***************************/ enum { CHANGED_SIGNAL, WIDTH_HEIGHT_CHANGED_SIGNAL, REF_LENGTH_CHANGED_SIGNAL, FACETTES_CHANGED_SIGNAL, LAST_SIGNAL }; static guint _signals[LAST_SIGNAL] = { 0 }; enum { PROP_0, THETA_PROP, PHI_PROP, OMEGA_PROP, XS_PROP, YS_PROP, GROSS_PROP, PERSP_PROP, PRECISION_PROP, N_PROP, ADJUST_PROP, BOX_PROP }; static GParamSpec *properties[N_PROP]; struct _VisuGlViewPrivate { VisuBox *box; gulong box_signal, unit_signal, bc_signal; gboolean adjust; float precision; VisuAnimation *theta_anim, *phi_anim, *gross_anim, *persp_anim; GHashTable *animations; gboolean dispose_has_run; }; /* This is a positive float that enable to increase or decrease the rendering load by modifying the number of facettes. */ #define FLAG_PARAMETER_OPENGL_DETAILS "opengl_details" #define DESC_PARAMETER_OPENGL_DETAILS "Give a value to the quality of rendering (100 is normal) ; positive integer" static float _defaultDetails = 100.f; static void exportParametersVisuGlView(GString *data, VisuData *dataObj); #define FLAG_RESOURCE_OPENGL_ANGLES "opengl_theta_phi_omega" #define DESC_RESOURCE_OPENGL_ANGLES "3 real values (degrees) for user orientation with respect to sample" #define FLAG_RESOURCE_OPENGL_TRANSLAT "opengl_xs_ys" #define DESC_RESOURCE_OPENGL_TRANSLAT "2 real values for image position with respect to [0.0, 1.0]x[0.0, 1.0] window" #define FLAG_RESOURCE_OPENGL_GROSS "opengl_gross" #define DESC_RESOURCE_OPENGL_GROSS "gross factor (must be real > 0.0)" #define FLAG_RESOURCE_OPENGL_PERSP "opengl_d_red" #define DESC_RESOURCE_OPENGL_PERSP "reduced perspective distance (must be real > 1.0)" #define FLAG_PARAMETER_AUTO_ADJUST "config_autoAdjustCamera" #define DESC_PARAMETER_AUTO_ADJUST "Auto adjust zoom capability for the box to be full size at zoom level 1 ; boolean 0 or 1" static gboolean autoAdjustDefault = TRUE; static void exportResourcesVisuGlView(GString *data, VisuData *dataObj); static void visu_gl_view_dispose (GObject* obj); static void visu_gl_view_finalize (GObject* obj); static void visu_gl_view_get_property(GObject* obj, guint property_id, GValue *value, GParamSpec *pspec); static void visu_gl_view_set_property(GObject* obj, guint property_id, const GValue *value, GParamSpec *pspec); static void visu_boxed_interface_init(VisuBoxedInterface *iface); static void visu_animatable_interface_init(VisuAnimatableInterface *iface); /* Callbacks. */ static void onSizeChanged(VisuBox *box, gfloat extens, gpointer data); static void onUnitChanged(VisuBox *box, gfloat fact, gpointer data); static void onBoundaryChanged(VisuBox *box, GParamSpec *pspec, gpointer data); static void onEntryAngles(VisuGlView *view, VisuConfigFileEntry *entry, VisuConfigFile *obj); static void onEntryTrans(VisuGlView *view, VisuConfigFileEntry *entry, VisuConfigFile *obj); static void onEntryGross(VisuGlView *view, VisuConfigFileEntry *entry, VisuConfigFile *obj); static void onEntryPersp(VisuGlView *view, VisuConfigFileEntry *entry, VisuConfigFile *obj); static void onEntryPrecision(VisuGlView *view, VisuConfigFileEntry *entry, VisuConfigFile *obj); /* Local methods. */ static void _setBoundary(VisuGlView *view, VisuBox *box); static VisuBox* _getBox(VisuBoxed *boxed); static gboolean _setBox(VisuBoxed *boxed, VisuBox* box); static VisuAnimation* _getAnimation(const VisuAnimatable *animatable, const gchar *prop); G_DEFINE_TYPE_WITH_CODE(VisuGlView, visu_gl_view, VISU_TYPE_OBJECT, G_ADD_PRIVATE(VisuGlView) G_IMPLEMENT_INTERFACE(VISU_TYPE_BOXED, visu_boxed_interface_init) G_IMPLEMENT_INTERFACE(VISU_TYPE_ANIMATABLE, visu_animatable_interface_init)) static void visu_gl_view_class_init(VisuGlViewClass *klass) { float rg[2] = {-G_MAXFLOAT, G_MAXFLOAT}; float rgGross[2] = {0.02f, 999.f}; float rgPersp[2] = {1.1f, 100.f}; float rgDetails[2] = {0.f, 500.f}; VisuConfigFileEntry *resourceEntry; DBG_fprintf(stderr, "Visu GlView: creating the class of the object.\n"); /* Connect the overloading methods. */ G_OBJECT_CLASS(klass)->dispose = visu_gl_view_dispose; G_OBJECT_CLASS(klass)->finalize = visu_gl_view_finalize; G_OBJECT_CLASS(klass)->set_property = visu_gl_view_set_property; G_OBJECT_CLASS(klass)->get_property = visu_gl_view_get_property; DBG_fprintf(stderr, " - adding new signals ;\n"); /** * VisuGlView::changed: * @view: the object which emits the signal ; * * Gets emitted when the view is changed. * * Since: 3.8 */ _signals[CHANGED_SIGNAL] = g_signal_new("changed", G_TYPE_FROM_CLASS (klass), G_SIGNAL_RUN_LAST | G_SIGNAL_NO_RECURSE | G_SIGNAL_NO_HOOKS, 0, NULL, NULL, g_cclosure_marshal_VOID__VOID, G_TYPE_NONE, 0); /** * VisuGlView::WidthHeightChanged: * @view: the object which received the signal ; * * Gets emitted when the viewing frame has been changed. * * Since: 3.2 */ _signals[WIDTH_HEIGHT_CHANGED_SIGNAL] = g_signal_new("WidthHeightChanged", G_TYPE_FROM_CLASS (klass), G_SIGNAL_RUN_LAST | G_SIGNAL_NO_RECURSE | G_SIGNAL_NO_HOOKS, 0, NULL, NULL, g_cclosure_marshal_VOID__VOID, G_TYPE_NONE, 0); /** * VisuGlView::RefLengthChanged: * @view: the object which received the signal ; * * Gets emitted when the reference length of the camera has been changed. * * Since: 3.7 */ _signals[REF_LENGTH_CHANGED_SIGNAL] = g_signal_new("RefLengthChanged", G_TYPE_FROM_CLASS (klass), G_SIGNAL_RUN_LAST | G_SIGNAL_NO_RECURSE | G_SIGNAL_NO_HOOKS, 0, NULL, NULL, g_cclosure_marshal_VOID__VOID, G_TYPE_NONE, 0); /** * VisuGlView::DetailLevelChanged: * @view: the object which received the signal ; * * Gets emitted when precision of the drawn object has been changed. * * Since: 3.2 */ _signals[FACETTES_CHANGED_SIGNAL] = g_signal_new("DetailLevelChanged", G_TYPE_FROM_CLASS (klass), G_SIGNAL_RUN_LAST | G_SIGNAL_NO_RECURSE | G_SIGNAL_NO_HOOKS, 0, NULL, NULL, g_cclosure_marshal_VOID__VOID, G_TYPE_NONE, 0); /** * VisuGlView::theta: * * The theta angle of the camera. * * Since: 3.8 */ properties[THETA_PROP] = g_param_spec_double("theta", "Theta", "theta angle", -360., 360., 90., G_PARAM_READWRITE); /** * VisuGlView::phi: * * The phi angle of the camera. * * Since: 3.8 */ properties[PHI_PROP] = g_param_spec_double("phi", "Phi", "phi angle", -360., 360., 0., G_PARAM_READWRITE); /** * VisuGlView::omega: * * The omega angle of the camera. * * Since: 3.8 */ properties[OMEGA_PROP] = g_param_spec_double("omega", "Omega", "omega angle", -360., 360., 0., G_PARAM_READWRITE); /** * VisuGlView::trans-x: * * The translation of the object along the window x axis. * * Since: 3.8 */ properties[XS_PROP] = g_param_spec_double("trans-x", "X translation", "translation along x", -3., +3., 0.5, G_PARAM_READWRITE); /** * VisuGlView::trans-y: * * The translation of the object along the window y axis. * * Since: 3.8 */ properties[YS_PROP] = g_param_spec_double("trans-y", "Y translation", "translation along y", -3., +3., 0.5, G_PARAM_READWRITE); /** * VisuGlView::zoom: * * The magnification of the camera. * * Since: 3.8 */ properties[GROSS_PROP] = g_param_spec_double("zoom", "Zoom", "zoom level", .02, 999., 1., G_PARAM_READWRITE); /** * VisuGlView::perspective: * * The perspective of the camera. * * Since: 3.8 */ properties[PERSP_PROP] = g_param_spec_double("perspective", "Perspective", "perspective level", 1.1, 100., 5., G_PARAM_READWRITE); /** * VisuGlView::precision: * * The accuracy of the rendering. * * Since: 3.8 */ properties[PRECISION_PROP] = g_param_spec_float("precision", "Precision", "precision level", 0.f, 10.f, 1.f, G_PARAM_READWRITE); g_object_class_install_properties(G_OBJECT_CLASS(klass), N_PROP, properties); g_object_class_override_property(G_OBJECT_CLASS(klass), ADJUST_PROP, "auto-adjust"); g_object_class_override_property(G_OBJECT_CLASS(klass), BOX_PROP, "box"); DBG_fprintf(stderr, " - adding resources ;\n"); /* Parameters */ resourceEntry = visu_config_file_addFloatArrayEntry(VISU_CONFIG_FILE_PARAMETER, FLAG_PARAMETER_OPENGL_DETAILS, DESC_PARAMETER_OPENGL_DETAILS, 1, &_defaultDetails, rgDetails, FALSE); resourceEntry = visu_config_file_addBooleanEntry(VISU_CONFIG_FILE_PARAMETER, FLAG_PARAMETER_AUTO_ADJUST, DESC_PARAMETER_AUTO_ADJUST, &autoAdjustDefault, FALSE); visu_config_file_entry_setVersion(resourceEntry, 3.6f); visu_config_file_addExportFunction(VISU_CONFIG_FILE_PARAMETER, exportParametersVisuGlView); /* Resources */ resourceEntry = visu_config_file_addFloatArrayEntry(VISU_CONFIG_FILE_RESOURCE, FLAG_RESOURCE_OPENGL_ANGLES, DESC_RESOURCE_OPENGL_ANGLES, 3, anglesDefault, rg, FALSE); visu_config_file_entry_setVersion(resourceEntry, 3.1f); resourceEntry = visu_config_file_addFloatArrayEntry(VISU_CONFIG_FILE_RESOURCE, FLAG_RESOURCE_OPENGL_TRANSLAT, DESC_RESOURCE_OPENGL_TRANSLAT, 2, translatDefault, rg, FALSE); resourceEntry = visu_config_file_addFloatArrayEntry(VISU_CONFIG_FILE_RESOURCE, FLAG_RESOURCE_OPENGL_GROSS, DESC_RESOURCE_OPENGL_GROSS, 1, &grossDefault, rgGross, FALSE); resourceEntry = visu_config_file_addFloatArrayEntry(VISU_CONFIG_FILE_RESOURCE, FLAG_RESOURCE_OPENGL_PERSP, DESC_RESOURCE_OPENGL_PERSP, 1, &perspDefault, rgPersp, FALSE); visu_config_file_addExportFunction(VISU_CONFIG_FILE_RESOURCE, exportResourcesVisuGlView); } static void visu_boxed_interface_init(VisuBoxedInterface *iface) { iface->get_box = _getBox; iface->set_box = _setBox; } static void visu_animatable_interface_init(VisuAnimatableInterface *iface) { iface->get_animation = _getAnimation; } static void visu_gl_view_init(VisuGlView *view) { DBG_fprintf(stderr, "Visu GlView: initializing a new object (%p).\n", (gpointer)view); view->priv = visu_gl_view_get_instance_private(view); view->priv->dispose_has_run = FALSE; view->priv->box = (VisuBox*)0; view->priv->box_signal = 0; view->priv->unit_signal = 0; view->priv->bc_signal = 0; view->priv->adjust = autoAdjustDefault; view->priv->precision = _defaultDetails / 100.f; view->priv->animations = g_hash_table_new(g_str_hash, g_str_equal); view->priv->theta_anim = visu_animation_new(G_OBJECT(view), "theta"); g_hash_table_insert(view->priv->animations, "theta", view->priv->theta_anim); view->priv->phi_anim = visu_animation_new(G_OBJECT(view), "phi"); g_hash_table_insert(view->priv->animations, "phi", view->priv->phi_anim); view->priv->gross_anim = visu_animation_new(G_OBJECT(view), "zoom"); g_hash_table_insert(view->priv->animations, "zoom", view->priv->gross_anim); view->priv->persp_anim = visu_animation_new(G_OBJECT(view), "perspective"); g_hash_table_insert(view->priv->animations, "perspective", view->priv->persp_anim); view->window.extens = 0.; view->window.width = 0; view->window.height = 0; view->window.near = 0.; view->window.far = 0.; view->window.unit = TOOL_UNITS_UNDEFINED; view->camera.theta = anglesDefault[0]; view->camera.phi = anglesDefault[1]; view->camera.omega = anglesDefault[2]; view->camera.xs = translatDefault[0]; view->camera.ys = translatDefault[1]; view->camera.gross = grossDefault; view->camera.d_red = perspDefault; view->camera.length0 = -1.; view->camera.unit = TOOL_UNITS_UNDEFINED; view->camera.upAxis = TOOL_XYZ_Z; view->camera.centre[0] = 0.f; view->camera.centre[1] = 0.f; view->camera.centre[2] = 0.f; DBG_fprintf(stderr, " | theta = %g\n", view->camera.theta); DBG_fprintf(stderr, " | phi = %g\n", view->camera.phi); DBG_fprintf(stderr, " | omega = %g\n", view->camera.omega); DBG_fprintf(stderr, " | dx-dy = %g %g\n", view->camera.xs, view->camera.ys); DBG_fprintf(stderr, " | gross = %g\n", view->camera.gross); DBG_fprintf(stderr, " | persp = %g\n", view->camera.d_red); DBG_fprintf(stderr, " | width x height = %d x %d\n", view->window.width, view->window.height); g_signal_connect_object(VISU_CONFIG_FILE_RESOURCE, "parsed::" FLAG_RESOURCE_OPENGL_ANGLES, G_CALLBACK(onEntryAngles), (gpointer)view, G_CONNECT_SWAPPED); g_signal_connect_object(VISU_CONFIG_FILE_RESOURCE, "parsed::" FLAG_RESOURCE_OPENGL_TRANSLAT, G_CALLBACK(onEntryTrans), (gpointer)view, G_CONNECT_SWAPPED); g_signal_connect_object(VISU_CONFIG_FILE_RESOURCE, "parsed::" FLAG_RESOURCE_OPENGL_GROSS, G_CALLBACK(onEntryGross), (gpointer)view, G_CONNECT_SWAPPED); g_signal_connect_object(VISU_CONFIG_FILE_RESOURCE, "parsed::" FLAG_RESOURCE_OPENGL_PERSP, G_CALLBACK(onEntryPersp), (gpointer)view, G_CONNECT_SWAPPED); g_signal_connect_object(VISU_CONFIG_FILE_RESOURCE, "parsed::" FLAG_PARAMETER_OPENGL_DETAILS, G_CALLBACK(onEntryPrecision), (gpointer)view, G_CONNECT_SWAPPED); } /* This method can be called several times. It should unref all of its reference to GObjects. */ static void visu_gl_view_dispose(GObject* obj) { VisuGlView *view; DBG_fprintf(stderr, "Visu GlView: dispose object %p.\n", (gpointer)obj); view = VISU_GL_VIEW(obj); if (view->priv->dispose_has_run) return; view->priv->dispose_has_run = TRUE; _setBox(VISU_BOXED(view), (VisuBox*)0); g_object_unref(view->priv->theta_anim); g_object_unref(view->priv->phi_anim); g_object_unref(view->priv->gross_anim); g_object_unref(view->priv->persp_anim); /* Chain up to the parent class */ G_OBJECT_CLASS(visu_gl_view_parent_class)->dispose(obj); } /* This method is called once only. */ static void visu_gl_view_finalize(GObject* obj) { g_return_if_fail(obj); DBG_fprintf(stderr, "Visu GlView: finalize object %p.\n", (gpointer)obj); g_hash_table_destroy(VISU_GL_VIEW(obj)->priv->animations); /* Chain up to the parent class */ DBG_fprintf(stderr, "Visu GlView: chain to parent.\n"); G_OBJECT_CLASS(visu_gl_view_parent_class)->finalize(obj); DBG_fprintf(stderr, "Visu GlView: freeing ... OK.\n"); } static void visu_gl_view_get_property(GObject* obj, guint property_id, GValue *value, GParamSpec *pspec) { VisuGlView *self = VISU_GL_VIEW(obj); DBG_fprintf(stderr, "Visu GlView: get property '%s' -> ", g_param_spec_get_name(pspec)); switch (property_id) { case THETA_PROP: if (visu_animation_isRunning(self->priv->theta_anim)) visu_animation_getTo(self->priv->theta_anim, value); else g_value_set_double(value, self->camera.theta); DBG_fprintf(stderr, "%g.\n", self->camera.theta); break; case PHI_PROP: if (visu_animation_isRunning(self->priv->phi_anim)) visu_animation_getTo(self->priv->phi_anim, value); else g_value_set_double(value, self->camera.phi); DBG_fprintf(stderr, "%g.\n", self->camera.phi); break; case OMEGA_PROP: g_value_set_double(value, self->camera.omega); DBG_fprintf(stderr, "%g.\n", self->camera.omega); break; case XS_PROP: g_value_set_double(value, self->camera.xs); DBG_fprintf(stderr, "%g.\n", self->camera.xs); break; case YS_PROP: g_value_set_double(value, self->camera.ys); DBG_fprintf(stderr, "%g.\n", self->camera.ys); break; case GROSS_PROP: if (visu_animation_isRunning(self->priv->gross_anim)) visu_animation_getTo(self->priv->gross_anim, value); else g_value_set_double(value, self->camera.gross); DBG_fprintf(stderr, "%g.\n", self->camera.gross); break; case PERSP_PROP: if (visu_animation_isRunning(self->priv->persp_anim)) visu_animation_getTo(self->priv->persp_anim, value); else g_value_set_double(value, self->camera.d_red); DBG_fprintf(stderr, "%g.\n", self->camera.d_red); break; case ADJUST_PROP: g_value_set_boolean(value, self->priv->adjust); DBG_fprintf(stderr, "%d.\n", self->priv->adjust); break; case PRECISION_PROP: DBG_fprintf(stderr, "%g.\n", self->priv->precision); g_value_set_float(value, self->priv->precision); break; case BOX_PROP: DBG_fprintf(stderr, "%p.\n", (gpointer)self->priv->box); g_value_set_object(value, self->priv->box); break; default: /* We don't have any other property... */ G_OBJECT_WARN_INVALID_PROPERTY_ID(obj, property_id, pspec); break; } } static void visu_gl_view_set_property(GObject* obj, guint property_id, const GValue *value, GParamSpec *pspec) { VisuGlView *self = VISU_GL_VIEW(obj); DBG_fprintf(stderr, "Visu GlView: set property '%s' -> ", g_param_spec_get_name(pspec)); switch (property_id) { case THETA_PROP: DBG_fprintf(stderr, "%g.\n", g_value_get_double(value)); if (!visu_animatable_animateDouble(VISU_ANIMATABLE(self), self->priv->theta_anim, g_value_get_double(value), 200, FALSE, VISU_ANIMATION_QUAD)) visu_gl_view_setThetaPhiOmega(self, g_value_get_double(value), 0., 0., VISU_GL_CAMERA_THETA); break; case PHI_PROP: DBG_fprintf(stderr, "%g.\n", g_value_get_double(value)); if (!visu_animatable_animateDouble(VISU_ANIMATABLE(self), self->priv->phi_anim, g_value_get_double(value), 200, FALSE, VISU_ANIMATION_QUAD)) visu_gl_view_setThetaPhiOmega(self, 0., g_value_get_double(value), 0., VISU_GL_CAMERA_PHI); break; case OMEGA_PROP: visu_gl_view_setThetaPhiOmega(self, 0., 0., g_value_get_double(value), VISU_GL_CAMERA_OMEGA); DBG_fprintf(stderr, "%g.\n", self->camera.omega); break; case XS_PROP: visu_gl_view_setXsYs(self, g_value_get_double(value), 0., VISU_GL_CAMERA_XS); DBG_fprintf(stderr, "%g.\n", self->camera.xs); break; case YS_PROP: visu_gl_view_setXsYs(self, 0., g_value_get_double(value), VISU_GL_CAMERA_YS); DBG_fprintf(stderr, "%g.\n", self->camera.ys); break; case GROSS_PROP: DBG_fprintf(stderr, "%g.\n", g_value_get_double(value)); if (!visu_animatable_animateDouble(VISU_ANIMATABLE(self), self->priv->gross_anim, g_value_get_double(value), 200, FALSE, VISU_ANIMATION_QUAD)) visu_gl_view_setGross(self, g_value_get_double(value)); break; case PERSP_PROP: DBG_fprintf(stderr, "%g.\n", g_value_get_double(value)); if (!visu_animatable_animateDouble(VISU_ANIMATABLE(self), self->priv->persp_anim, g_value_get_double(value), 200, FALSE, VISU_ANIMATION_QUAD)) visu_gl_view_setPersp(self, g_value_get_double(value)); break; case ADJUST_PROP: self->priv->adjust = g_value_get_boolean(value); autoAdjustDefault = g_value_get_boolean(value); DBG_fprintf(stderr, "%d.\n", self->priv->adjust); break; case PRECISION_PROP: DBG_fprintf(stderr, "%g.\n", g_value_get_float(value)); visu_gl_view_setPrecision(self, g_value_get_float(value)); break; case BOX_PROP: DBG_fprintf(stderr, "%p.\n", g_value_get_object(value)); _setBox(VISU_BOXED(obj), VISU_BOX(g_value_get_object(value))); break; default: /* We don't have any other property... */ G_OBJECT_WARN_INVALID_PROPERTY_ID(obj, property_id, pspec); break; } } /** * visu_gl_view_new: * * Create a new #VisuGlView object with default values. * * Returns: (transfer full): the newly created object. */ VisuGlView* visu_gl_view_new(void) { VisuGlView *view; view = VISU_GL_VIEW(g_object_new(VISU_TYPE_GL_VIEW, NULL)); return view; } /** * visu_gl_view_new_withSize: * @w: the width ; * @h: the height. * * Create a new #VisuGlView object with default values and the given * window size. * * Since: 3.7 * * Returns: (transfer full): the newly created object. */ VisuGlView* visu_gl_view_new_withSize(guint w, guint h) { VisuGlView *view; view = VISU_GL_VIEW(g_object_new(VISU_TYPE_GL_VIEW, NULL)); visu_gl_window_setViewport(&view->window, w, h); return view; } /** * visu_gl_view_initContext: * @view: a #VisuGlView object. * * Modelize and project the view. Should be called when used in a new * OpenGL context. * * Since: 3.8 **/ void visu_gl_view_initContext(VisuGlView *view) { g_return_if_fail(VISU_IS_GL_VIEW(view)); visu_gl_camera_modelize(&view->camera); visu_gl_window_project(&view->window, &view->camera); } static gboolean _setBox(VisuBoxed *self, VisuBox *box) { VisuGlView *view; float fact; g_return_val_if_fail(VISU_IS_GL_VIEW(self), FALSE); view = VISU_GL_VIEW(self); DBG_fprintf(stderr, "OpenGL View: set box %p.\n", (gpointer)box); if (box == view->priv->box) return FALSE; if (view->priv->box) { g_signal_handler_disconnect(G_OBJECT(view->priv->box), view->priv->box_signal); g_signal_handler_disconnect(G_OBJECT(view->priv->box), view->priv->unit_signal); g_signal_handler_disconnect(G_OBJECT(view->priv->box), view->priv->bc_signal); g_object_unref(view->priv->box); } if (box) { g_object_ref(box); view->priv->box_signal = g_signal_connect(G_OBJECT(box), "SizeChanged", G_CALLBACK(onSizeChanged), (gpointer)view); view->priv->unit_signal = g_signal_connect(G_OBJECT(box), "UnitChanged", G_CALLBACK(onUnitChanged), (gpointer)view); view->priv->bc_signal = g_signal_connect(G_OBJECT(box), "notify::boundary", G_CALLBACK(onBoundaryChanged), (gpointer)view); /* Update lengths. */ if (view->priv->adjust || view->camera.length0 <= 0.f) visu_gl_view_setRefLength(view, visu_box_getGlobalSize(box, FALSE), visu_box_getUnit(box)); else { fact = 1.; if (view->camera.unit != TOOL_UNITS_UNDEFINED && visu_box_getUnit(box) != TOOL_UNITS_UNDEFINED) fact = tool_physic_getUnitValueInMeter(view->camera.unit) / tool_physic_getUnitValueInMeter(visu_box_getUnit(box)); DBG_fprintf(stderr, "Visu GlView: ref length factor %g (%d %d).\n", fact, view->camera.unit, visu_box_getUnit(box)); visu_gl_view_setRefLength(view, view->camera.length0 * fact, visu_box_getUnit(box)); } visu_gl_view_setObjectRadius(view, visu_box_getGlobalSize(box, TRUE), visu_box_getUnit(box)); /* Update camera. */ _setBoundary(view, box); } else { view->priv->box_signal = 0; view->priv->unit_signal = 0; view->priv->bc_signal = 0; } view->priv->box = box; return TRUE; } static void onSizeChanged(VisuBox *box, gfloat extens, gpointer data) { VisuGlView *view = VISU_GL_VIEW(data); DBG_fprintf(stderr, "Visu GlView: caught 'SizeChanged'.\n"); visu_gl_view_setObjectRadius(view, extens, visu_box_getUnit(box)); DBG_fprintf(stderr, "Visu GlView: done 'SizeChanged'.\n"); } static void onUnitChanged(VisuBox *box, gfloat fact, gpointer data) { VisuGlView *view = VISU_GL_VIEW(data); ToolUnits unit; DBG_fprintf(stderr, "Visu GlView: caught 'UnitChanged'.\n"); unit = visu_box_getUnit(box); if (view->camera.unit != TOOL_UNITS_UNDEFINED && unit != TOOL_UNITS_UNDEFINED) fact = tool_physic_getUnitValueInMeter(view->camera.unit) / tool_physic_getUnitValueInMeter(unit); visu_gl_view_setRefLength(view, view->camera.length0 * fact, unit); /* Box size changed will be emitted after, so the object radius will be updated automatically, except for undefined units. */ if (view->window.unit == TOOL_UNITS_UNDEFINED || unit == TOOL_UNITS_UNDEFINED) visu_gl_window_setAddLength(&view->window, view->window.extens, unit); DBG_fprintf(stderr, "Visu GlView: done 'UnitChanged'.\n"); } static void onBoundaryChanged(VisuBox *box, GParamSpec *pspec _U_, gpointer data) { _setBoundary(VISU_GL_VIEW(data), box); } static void _setBoundary(VisuGlView *view, VisuBox *box) { switch (visu_box_getBoundary(box)) { case (VISU_BOX_PERIODIC): case (VISU_BOX_FREE): case (VISU_BOX_WIRE_X): case (VISU_BOX_WIRE_Y): case (VISU_BOX_WIRE_Z): case (VISU_BOX_SURFACE_XY): visu_gl_camera_setUpAxis(&view->camera, TOOL_XYZ_Z); break; case (VISU_BOX_SURFACE_YZ): visu_gl_camera_setUpAxis(&view->camera, TOOL_XYZ_X); break; case (VISU_BOX_SURFACE_ZX): visu_gl_camera_setUpAxis(&view->camera, TOOL_XYZ_Y); break; } visu_gl_camera_modelize(&view->camera); g_signal_emit(view, _signals[CHANGED_SIGNAL], 0); } static VisuBox* _getBox(VisuBoxed *boxed) { g_return_val_if_fail(VISU_IS_GL_VIEW(boxed), (VisuBox*)0); return VISU_GL_VIEW(boxed)->priv->box; } static VisuAnimation* _getAnimation(const VisuAnimatable *animatable, const gchar *prop) { g_return_val_if_fail(VISU_IS_GL_VIEW(animatable), (VisuAnimation*)0); return g_hash_table_lookup(VISU_GL_VIEW(animatable)->priv->animations, prop); } /** * visu_gl_view_getDetailLevel: * @view: a valid #VisuGlView object ; * @dimension: the size of the object which asks for its number of facettes. * * This is a function to get the number of "facettes" advised * by the server (according to its policy on rendering) * to draw an object according to a given dimension. * * Returns: the number of facettes the object should used. */ gint visu_gl_view_getDetailLevel(const VisuGlView *view, float dimension) { gint rsize; gint nlat; #define NLAT_MIN 12 #define NLAT_MAX 50 #define RSIZE_MIN 10 #define RSIZE_MAX 250 #define NLAT_V_MIN 0 #define NLAT_V_MAX (NLAT_MIN) #define RSIZE_V_MIN 0 #define RSIZE_V_MAX (RSIZE_MIN) #define NLAT_MINI 3 #define NLAT_MAXI 100 static float fac = -1.0f, fac_v = -1.0f; g_return_val_if_fail(VISU_IS_GL_VIEW(view), 0); DBG_fprintf(stderr, "Visu GlView: get GL details for window %dx%d.\n", view->window.width, view->window.height); DBG_fprintf(stderr, " | gross = %g.\n", view->camera.gross); DBG_fprintf(stderr, " | persp = %g.\n", view->camera.d_red); DBG_fprintf(stderr, " | lgth0 = %g.\n", view->camera.length0); /* calculate once fac and fac_v!... */ if(fac < 0.0f) { fac = ((float)(NLAT_MAX - NLAT_MIN))/(RSIZE_MAX - RSIZE_MIN); fac_v = ((float)(NLAT_V_MAX - NLAT_V_MIN))/(RSIZE_V_MAX - RSIZE_V_MIN); } rsize = (int)((float)MIN(view->window.width, view->window.height) * (0.5 * dimension / view->camera.length0 * view->camera.gross * view->camera.d_red / (view->camera.d_red - 1.))); if(rsize < RSIZE_MIN) { nlat = (int)(NLAT_V_MIN + fac_v * (rsize - RSIZE_V_MIN)); if(nlat < NLAT_MINI) nlat = NLAT_MINI; } else if(rsize > RSIZE_MAX) { nlat = NLAT_MAX; } else { nlat = (int)(NLAT_MIN + fac * (rsize - RSIZE_MIN)); } nlat = (int)((float)nlat * view->priv->precision); nlat = CLAMP(nlat, NLAT_MINI, NLAT_MAXI); DBG_fprintf(stderr, " | nlat = %d.\n", nlat); return nlat; } /** * visu_gl_view_setPrecision: * @view: a #VisuGlView object. * @value: a positive value (1. is normal precision). * * This function change the value of the parameter precisionOfRendering. It * changes the number of facettes advised for every objects. It allows to * increase or decrease the number of polygons drawn and thus acts on the * speed of rendering. * * Returns: TRUE if value is actually changed. */ gboolean visu_gl_view_setPrecision(VisuGlView *view, float value) { g_return_val_if_fail(VISU_IS_GL_VIEW(view), FALSE); if (value <= 0. || value == view->priv->precision) return FALSE; view->priv->precision = value; _defaultDetails = value * 100.f; g_object_notify_by_pspec(G_OBJECT(view), properties[PRECISION_PROP]); g_signal_emit(G_OBJECT(view), _signals[FACETTES_CHANGED_SIGNAL], 0); return TRUE; } /** * visu_gl_view_getPrecision: * @view: a #VisuGlView object. * * This function retrieve the value of the parameter precisionOfRendering. * * Returns: the actual precision. */ float visu_gl_view_getPrecision(const VisuGlView *view) { g_return_val_if_fail(VISU_IS_GL_VIEW(view), 1.f); return view->priv->precision; } /** * visu_gl_window_getFileUnitPerPixel: * @window: a valid #VisuGlWindow object. * * This method is used to know the ratio of a pixel with the unit of the file. * WARNING : this method is valid only when the camera is position at infinity. * * Returns: how much of a unit of file is in a pixel. */ float visu_gl_window_getFileUnitPerPixel(VisuGlWindow *window) { float deltaH, deltaV; g_return_val_if_fail(window, 0.); deltaH = window->right - window->left; deltaV = window->top - window->bottom; if (deltaH < deltaV) return deltaH / (float)window->width; else return deltaV / (float)window->height; } /** * visu_gl_camera_getScreenAxes: * @camera: a valid #VisuGlCamera. * @xAxis: (in) (array fixed-size=3): three float values representing x axis ; * @yAxis: (in) (array fixed-size=3): three float values representing y axis. * * This method is used to get the coordinates in box frame of x axis and y axis * of the current camera view. */ void visu_gl_camera_getScreenAxes(VisuGlCamera *camera, float xAxis[3], float yAxis[3]) { double cth, sth, cph, sph, com, som; float matPhi[3][3], matTheta[3][3], matOmega[3][3]; float matRes[3][3], matRes2[3][3]; float axis[3]; g_return_if_fail(camera); cth = cos(camera->theta * TOOL_PI180); sth = sin(camera->theta * TOOL_PI180); cph = cos(camera->phi * TOOL_PI180); sph = sin(camera->phi * TOOL_PI180); com = cos(camera->omega * TOOL_PI180); som = sin(camera->omega * TOOL_PI180); matPhi[0][0] = cph; matPhi[1][0] = sph; matPhi[2][0] = 0.; matPhi[0][1] = -sph; matPhi[1][1] = cph; matPhi[2][1] = 0.; matPhi[0][2] = 0.; matPhi[1][2] = 0.; matPhi[2][2] = 1.; matTheta[0][0] = cth; matTheta[1][0] = 0.; matTheta[2][0] = -sth; matTheta[0][1] = 0.; matTheta[1][1] = 1.; matTheta[2][1] = 0.; matTheta[0][2] = sth; matTheta[1][2] = 0.; matTheta[2][2] = cth; matOmega[0][0] = com; matOmega[1][0] = som; matOmega[2][0] = 0.; matOmega[0][1] = -som; matOmega[1][1] = com; matOmega[2][1] = 0.; matOmega[0][2] = 0.; matOmega[1][2] = 0.; matOmega[2][2] = 1.; tool_matrix_productMatrix(matRes, matTheta, matOmega); tool_matrix_productMatrix(matRes2, matPhi, matRes); axis[0] = 0.; axis[1] = 1.; axis[2] = 0.; tool_matrix_productVector(xAxis, matRes2, axis); axis[0] = -1.; axis[1] = 0.; axis[2] = 0.; tool_matrix_productVector(yAxis, matRes2, axis); } /** * visu_gl_view_getZCoordinate: * @view: a #VisuGlView object. * @xyz: a cartesian point. * * Use this routine to know the Z value of a real point defined by * @xyz in caretsian coordinates. */ float visu_gl_view_getZCoordinate(VisuGlView *view, float xyz[3]) { GLdouble model[16], project[16]; GLint viewport[4]; GLdouble xyzGL[3], winGL[3]; g_return_val_if_fail(view, 0.5f); glGetDoublev(GL_MODELVIEW_MATRIX, model); glGetDoublev(GL_PROJECTION_MATRIX, project); glGetIntegerv(GL_VIEWPORT, viewport); xyzGL[0] = (GLdouble)xyz[0]; xyzGL[1] = (GLdouble)xyz[1]; xyzGL[2] = (GLdouble)xyz[2]; gluProject(xyzGL[0], xyzGL[1], xyzGL[2], model, project, viewport, winGL, winGL + 1, winGL + 2); DBG_fprintf(stderr, "OpenGL View: get z coordinates from %gx%gx%g: %g.\n", xyz[0], xyz[1], xyz[2], (float)winGL[2]); DBG_fprintf(stderr, " | win coords: %gx%g\n", (float)winGL[0], (float)winGL[1]); return (float)winGL[2]; } /** * visu_gl_view_getRealCoordinates: * @view: a #VisuGlView object. * @xyz: a location to store the result. * @winx: position on X axis of screen. * @winy: position on Y axis of screen. * @winz: height before projection on screen. * * Use this routine to get the cartesian coordinates in real space of * a point located at @winx and @winy on screen. */ void visu_gl_view_getRealCoordinates(VisuGlView *view, float xyz[3], float winx, float winy, float winz) { GLdouble model[16], project[16]; GLint viewport[4]; GLdouble xyzGL[3], winGL[3]; g_return_if_fail(view); glGetDoublev(GL_MODELVIEW_MATRIX, model); glGetDoublev(GL_PROJECTION_MATRIX, project); glGetIntegerv(GL_VIEWPORT, viewport); winGL[0] = (GLdouble)winx; winGL[1] = (GLdouble)(view->window.height - winy); winGL[2] = (GLdouble)winz; gluUnProject(winGL[0], winGL[1], winGL[2], model, project, viewport, xyzGL, xyzGL + 1, xyzGL + 2); xyz[0] = (float)xyzGL[0]; xyz[1] = (float)xyzGL[1]; xyz[2] = (float)xyzGL[2]; DBG_fprintf(stderr, "OpenGL View: get real coordinates from %gx%gx%g: %gx%gx%g.\n", winx, winy, winz, xyz[0], xyz[1], xyz[2]); } /** * visu_gl_view_alignToAxis: * @view: a #VisuGlView object. * @axis: an axis. * * Rotate the view to align it with the given box axis. * * Since: 3.8 **/ void visu_gl_view_alignToAxis(VisuGlView *view, ToolXyzDir axis) { float red[3], xyz[3], xyz_[3], sph[3]; int permut[3][3] = {{1,2,0}, {2,0,1}, {0,1,2}}; g_return_if_fail(VISU_IS_GL_VIEW(view)); if (!view->priv->box) return; red[0] = (axis == TOOL_XYZ_X) ? 1.f : 0.f; red[1] = (axis == TOOL_XYZ_Y) ? 1.f : 0.f; red[2] = (axis == TOOL_XYZ_Z) ? 1.f : 0.f; visu_box_convertBoxCoordinatestoXYZ(view->priv->box, xyz, red); xyz_[0] = xyz[permut[view->camera.upAxis][0]]; xyz_[1] = xyz[permut[view->camera.upAxis][1]]; xyz_[2] = xyz[permut[view->camera.upAxis][2]]; tool_matrix_cartesianToSpherical(sph, xyz_); g_object_set(view, "theta", sph[TOOL_MATRIX_SPHERICAL_THETA], "phi", sph[TOOL_MATRIX_SPHERICAL_PHI], NULL); } /** * visu_gl_view_setThetaPhiOmega: * @view: a #VisuGlView object ; * @valueTheta: a floatinf point value in degrees ; * @valuePhi: a floating point value in degrees ; * @valueOmega: a floating point value in degrees ; * @mask: to specified what values will be changed. * * This method is used to change the camera orientation for the given @view. * If necessary, this method will emit the 'ThetaPhiOmegaChanged' signal. * * Returns: TRUE if value is actually changed. */ gboolean visu_gl_view_setThetaPhiOmega(VisuGlView *view, float valueTheta, float valuePhi, float valueOmega, int mask) { int res; g_return_val_if_fail(VISU_IS_GL_VIEW(view), FALSE); DBG_fprintf(stderr, "OpenGL View: changing theta / phi / omega (%d).\n", mask); DBG_fprintf(stderr, "OpenGL View: to %g / %g / %g.\n", valueTheta, valuePhi, valueOmega); res = visu_gl_camera_setThetaPhiOmega(&view->camera, valueTheta, valuePhi, valueOmega, mask); DBG_fprintf(stderr, "OpenGL View: to %g / %g / %g.\n", view->camera.theta, view->camera.phi, view->camera.omega); if (res & VISU_GL_CAMERA_THETA) g_object_notify_by_pspec(G_OBJECT(view), properties[THETA_PROP]); if (res & VISU_GL_CAMERA_PHI) g_object_notify_by_pspec(G_OBJECT(view), properties[PHI_PROP]); if (res & VISU_GL_CAMERA_OMEGA) g_object_notify_by_pspec(G_OBJECT(view), properties[OMEGA_PROP]); if (res) { anglesDefault[0] = view->camera.theta; anglesDefault[1] = view->camera.phi; anglesDefault[2] = view->camera.omega; visu_gl_camera_modelize(&view->camera); g_signal_emit(view, _signals[CHANGED_SIGNAL], 0); } return (res > 0); } /** * visu_gl_view_setXsYs: * @view: a #VisuGlView object ; * @valueX: a floatinf point value in the bounding box scale * (1 is the size of the bounding box) ; * @valueY: a floating point value in bounding box scale ; * @mask: to specified what values will be changed. * * This method is used to change the camera position for the given @view. * If necessary, this method will emit the 'XsYsChanged' signal. * * Returns: TRUE if value is actually changed. */ gboolean visu_gl_view_setXsYs(VisuGlView *view, float valueX, float valueY, int mask) { int res; g_return_val_if_fail(VISU_IS_GL_VIEW(view), FALSE); res = visu_gl_camera_setXsYs(&view->camera, valueX, valueY, mask); if (res & VISU_GL_CAMERA_XS) g_object_notify_by_pspec(G_OBJECT(view), properties[XS_PROP]); if (res & VISU_GL_CAMERA_YS) g_object_notify_by_pspec(G_OBJECT(view), properties[YS_PROP]); if (res) { translatDefault[0] = view->camera.xs; translatDefault[1] = view->camera.ys; visu_gl_window_project(&view->window, &view->camera); g_signal_emit(view, _signals[CHANGED_SIGNAL], 0); } return (res > 0); } /** * visu_gl_view_setGross: * @view: a #VisuGlView object ; * @value: a positive floating point value. * * This method is used to change the camera zoom for the given @view. * If necessary, this method will emit the 'GrossChanged' signal and * the 'FacetteChangedChanged' signal. * * Returns: TRUE if value is actually changed. */ gboolean visu_gl_view_setGross(VisuGlView *view, float value) { gboolean res; g_return_val_if_fail(VISU_IS_GL_VIEW(view), FALSE); res = visu_gl_camera_setGross(&view->camera, value); if (res) { grossDefault = view->camera.gross; g_object_notify_by_pspec(G_OBJECT(view), properties[GROSS_PROP]); g_signal_emit(view, _signals[FACETTES_CHANGED_SIGNAL], 0, NULL); visu_gl_window_project(&view->window, &view->camera); g_signal_emit(view, _signals[CHANGED_SIGNAL], 0); } return res; } /** * visu_gl_view_setPersp: * @view: a #VisuGlView object ; * @value: a positive floating point value (> 1.1). * * This method is used to change the camera perspective for the given @view. * If necessary, this method will emit the 'PerspChanged' signal and * the 'FacetteChangedChanged' signal. * * Returns: TRUE if value is actually changed. */ gboolean visu_gl_view_setPersp(VisuGlView *view, float value) { gboolean res; g_return_val_if_fail(VISU_IS_GL_VIEW(view), FALSE); res = visu_gl_camera_setPersp(&view->camera, value); if (res) { perspDefault = view->camera.d_red; DBG_fprintf(stderr, "Visu GlView: emitting signals on persp changed.\n"); g_object_notify_by_pspec(G_OBJECT(view), properties[PERSP_PROP]); g_signal_emit(view, _signals[FACETTES_CHANGED_SIGNAL], 0, NULL); visu_gl_camera_modelize(&view->camera); visu_gl_window_project(&view->window, &view->camera); g_signal_emit(view, _signals[CHANGED_SIGNAL], 0); } return res; } /** * visu_gl_view_setViewport: * @view: a #VisuGlView object ; * @width: the new horizontal size ; * @height: the new vertical size. * * It changes the size of the OpenGl area and reccompute the OpenGL viewport. * Warning : it doesn't change the size of the window. * * Returns: TRUE if value is actually changed. */ gboolean visu_gl_view_setViewport(VisuGlView *view, guint width, guint height) { gboolean res; g_return_val_if_fail(VISU_IS_GL_VIEW(view), FALSE); res = visu_gl_window_setViewport(&view->window, width, height); if (res) { g_signal_emit(view, _signals[WIDTH_HEIGHT_CHANGED_SIGNAL], 0, NULL); g_signal_emit(view, _signals[FACETTES_CHANGED_SIGNAL], 0, NULL); visu_gl_window_project(&view->window, &view->camera); g_signal_emit(view, _signals[CHANGED_SIGNAL], 0); } return res; } /** * visu_gl_view_setRefLength: * @view: a #VisuGlView object ; * @lg: the new value. * @units: the unit to read @lg with. * * This method is used to change the camera reference length for the given @view. * If necessary, this method will modelize and emit the 'RefLengthChanged' signal. * * Returns: TRUE if value is actually changed. */ gboolean visu_gl_view_setRefLength(VisuGlView *view, float lg, ToolUnits units) { gboolean res; g_return_val_if_fail(VISU_IS_GL_VIEW(view), FALSE); res = visu_gl_camera_setRefLength(&view->camera, lg, units); if (res) { g_signal_emit(view, _signals[REF_LENGTH_CHANGED_SIGNAL], 0, NULL); g_signal_emit(view, _signals[FACETTES_CHANGED_SIGNAL], 0, NULL); visu_gl_camera_modelize(&view->camera); g_signal_emit(view, _signals[CHANGED_SIGNAL], 0); } return res; } /** * visu_gl_view_setObjectRadius: * @view: a #VisuGlView object ; * @lg: the new value. * @units: the unit to read @lg with. * * This method is used to change the window frustum for the given @view. * If necessary, this method will project and emit the * 'NearFarChanged' signal. * * Since: 3.7 * * Returns: TRUE if value is actually changed. */ gboolean visu_gl_view_setObjectRadius(VisuGlView *view, float lg, ToolUnits units) { gboolean res; g_return_val_if_fail(VISU_IS_GL_VIEW(view), FALSE); res = visu_gl_window_setAddLength(&view->window, lg, units); if (res) { visu_gl_window_project(&view->window, &view->camera); g_signal_emit(view, _signals[CHANGED_SIGNAL], 0); } return res; } /** * visu_gl_view_rotateBox: * @view: a valid #VisuGlView object ; * @dTheta: a float value ; * @dPhi: a float value ; * @angles: (out) (array fixed-size=2): a storing area two floats. * * This methods rotates the camera of the given @view of (@dTheta, @dPhi) and * put new theta and phi angles in @angles, first being theta and second phi. */ void visu_gl_view_rotateBox(VisuGlView *view, float dTheta, float dPhi, float angles[2]) { GValue val = G_VALUE_INIT; g_return_if_fail(view && angles); g_value_init(&val, G_TYPE_DOUBLE); if (visu_animation_isRunning(view->priv->theta_anim)) { visu_animation_getTo(view->priv->theta_anim, &val); angles[0] = g_value_get_double(&val) + dTheta; } else angles[0] = view->camera.theta + dTheta; if (visu_animation_isRunning(view->priv->phi_anim)) { visu_animation_getTo(view->priv->phi_anim, &val); angles[1] = g_value_get_double(&val) + dPhi; } else angles[1] = view->camera.phi + dPhi; } /** * visu_gl_view_rotateCamera: * @view: a valid #VisuGlView object ; * @dTheta: a float value ; * @dPhi: a float value ; * @angles: (out) (array fixed-size=3): a storing area three floats. * * This methods rotates the camera of the given @view of (@dTheta, @dPhi). * @dTheta is taken as displacement along camera x axis and dPhi along camera y axis. * Then, computations are done to obtain new theta, phi and omega values. They are * put in @angles, first being theta, second phi and third omega. */ void visu_gl_view_rotateCamera(VisuGlView *view, float dTheta, float dPhi, float angles[3]) { double cth, sth, cph, sph, com, som; double cdth, sdth, cdph, sdph; double Theta, Phi, Omega; #define RADTODEG 57.29577951 float MinRprime[3], MinR[3]; float Mspherical[3]; float matPhi[3][3], matTheta[3][3], matOmega[3][3], matdPhi[3][3], matdTheta[3][3]; float matPhiPrime[3][3], matThetaPrime[3][3]; float matRprime2R[3][3]; float matRes[3][3], matRes2[3][3]; g_return_if_fail(view && angles); cth = cos(view->camera.theta * TOOL_PI180); sth = sin(view->camera.theta * TOOL_PI180); cph = cos(view->camera.phi * TOOL_PI180); sph = sin(view->camera.phi * TOOL_PI180); com = cos(view->camera.omega * TOOL_PI180); som = sin(view->camera.omega * TOOL_PI180); cdth = cos(dTheta * TOOL_PI180); sdth = sin(dTheta * TOOL_PI180); cdph = cos(dPhi * TOOL_PI180); sdph = sin(dPhi * TOOL_PI180); matPhi[0][0] = cph; matPhi[1][0] = sph; matPhi[2][0] = 0.; matPhi[0][1] = -sph; matPhi[1][1] = cph; matPhi[2][1] = 0.; matPhi[0][2] = 0.; matPhi[1][2] = 0.; matPhi[2][2] = 1.; matTheta[0][0] = cth; matTheta[1][0] = 0.; matTheta[2][0] = -sth; matTheta[0][1] = 0.; matTheta[1][1] = 1.; matTheta[2][1] = 0.; matTheta[0][2] = sth; matTheta[1][2] = 0.; matTheta[2][2] = cth; matOmega[0][0] = com; matOmega[1][0] = som; matOmega[2][0] = 0.; matOmega[0][1] = -som; matOmega[1][1] = com; matOmega[2][1] = 0.; matOmega[0][2] = 0.; matOmega[1][2] = 0.; matOmega[2][2] = 1.; matdPhi[0][0] = 1.; matdPhi[1][0] = 0.; matdPhi[2][0] = 0.; matdPhi[0][1] = 0.; matdPhi[1][1] = cdph; matdPhi[2][1] = -sdph; matdPhi[0][2] = 0.; matdPhi[1][2] = sdph; matdPhi[2][2] = cdph; matdTheta[0][0] = cdth; matdTheta[1][0] = 0.; matdTheta[2][0] = -sdth; matdTheta[0][1] = 0.; matdTheta[1][1] = 1.; matdTheta[2][1] = 0.; matdTheta[0][2] = sdth; matdTheta[1][2] = 0.; matdTheta[2][2] = cdth; tool_matrix_productMatrix(matRes, matdPhi, matdTheta); tool_matrix_productMatrix(matRes2, matOmega, matRes); tool_matrix_productMatrix(matRes, matTheta, matRes2); tool_matrix_productMatrix(matRprime2R, matPhi, matRes); MinRprime[0] = 0.; MinRprime[1] = 0.; MinRprime[2] = 1.; tool_matrix_productVector(MinR, matRprime2R, MinRprime); /* fprintf(stderr, "M : %f %f %f -> %f\n", MinR[0], MinR[1], MinR[2], */ /* MinR[0]*MinR[0] + MinR[1]*MinR[1] + MinR[2]*MinR[2]); */ /* cartesian_to_spherical(Mspherical, MinR); */ Mspherical[0] = sqrt(MinR[0]*MinR[0] + MinR[1]*MinR[1] + MinR[2]*MinR[2]); if (MinR[1] == 0 && MinR[0] == 0) { Mspherical[1] = (MinR[2] > 0.)?0.:180.; Mspherical[2] = view->camera.phi; } else { Mspherical[1] = acos(MinR[2] / Mspherical[0]) * RADTODEG; if (MinR[0] == 0.) Mspherical[2] = (MinR[1] > 0.)?90.:-90.; else { Mspherical[2] = atan(MinR[1] / MinR[0]) * RADTODEG; if (MinR[0] < 0.) Mspherical[2] += 180.; } } /* fprintf(stderr, "avant %f %f\n", Mspherical[1], Mspherical[2]); */ while (Mspherical[1] - view->camera.theta < -90.) Mspherical[1] += 360.; while (Mspherical[1] - view->camera.theta > 90.) Mspherical[1] -= 360.; while (Mspherical[2] - view->camera.phi < -90.) Mspherical[2] += 360.; while (Mspherical[2] - view->camera.phi > 90.) Mspherical[2] -= 360.; /* fprintf(stderr, "après %f %f\n", Mspherical[1], Mspherical[2]); */ Theta = Mspherical[1]; Phi = Mspherical[2]; /* fprintf(stderr, "%f %f, %f %f\n", view->camera.theta, view->camera.phi, Theta, Phi); */ /* fprintf(stderr, "%f %f, %f %f\n", dTheta, dPhi, Theta - view->camera.theta, Phi - view->camera.phi); */ cth = cos(Theta * TOOL_PI180); sth = sin(Theta * TOOL_PI180); cph = cos(Phi * TOOL_PI180); sph = sin(Phi * TOOL_PI180); matPhiPrime[0][0] = cph; matPhiPrime[1][0] = -sph; matPhiPrime[2][0] = 0.; matPhiPrime[0][1] = sph; matPhiPrime[1][1] = cph; matPhiPrime[2][1] = 0.; matPhiPrime[0][2] = 0.; matPhiPrime[1][2] = 0.; matPhiPrime[2][2] = 1.; matThetaPrime[0][0] = cth; matThetaPrime[1][0] = 0.; matThetaPrime[2][0] = sth; matThetaPrime[0][1] = 0.; matThetaPrime[1][1] = 1.; matThetaPrime[2][1] = 0.; matThetaPrime[0][2] = -sth; matThetaPrime[1][2] = 0.; matThetaPrime[2][2] = cth; tool_matrix_productMatrix(matRes2, matPhiPrime, matRprime2R); tool_matrix_productMatrix(matRes, matThetaPrime, matRes2); MinRprime[0] = 0.; MinRprime[1] = 1.; MinRprime[2] = 0.; tool_matrix_productVector(MinR, matRes, MinRprime); /* fprintf(stderr, "vect u : %f %f %f -> %f\n", MinR[0], MinR[1], MinR[2], */ /* MinR[0]*MinR[0] + MinR[1]*MinR[1] + MinR[2]*MinR[2]); */ Omega = acos(CLAMP(MinR[1], -1.f, 1.f)) * RADTODEG; if (MinR[0] > 0.) Omega = -Omega; while (Omega - view->camera.omega < -90.) Omega += 360.; while (Omega - view->camera.omega > 90.) Omega -= 360.; /* fprintf(stderr, "Theta phi omega : %f %f %f\n", Theta, Phi, Omega); */ angles[0] = Theta; angles[1] = Phi; angles[2] = Omega; } /***************************/ /* Dealing with resources. */ /***************************/ static void exportParametersVisuGlView(GString *data, VisuData *dataObj _U_) { g_string_append_printf(data, "# %s\n", DESC_PARAMETER_OPENGL_DETAILS); g_string_append_printf(data, "%s: %d\n\n", FLAG_PARAMETER_OPENGL_DETAILS, (int)(_defaultDetails)); g_string_append_printf(data, "# %s\n", DESC_PARAMETER_AUTO_ADJUST); g_string_append_printf(data, "%s: %d\n\n", FLAG_PARAMETER_AUTO_ADJUST, autoAdjustDefault); } static void onEntryPrecision(VisuGlView *view, VisuConfigFileEntry *entry _U_, VisuConfigFile *obj _U_) { visu_gl_view_setPrecision(view, _defaultDetails / 100.f); } static void onEntryAngles(VisuGlView *view, VisuConfigFileEntry *entry _U_, VisuConfigFile *obj _U_) { visu_gl_view_setThetaPhiOmega (view, anglesDefault[0], anglesDefault[1], anglesDefault[2], VISU_GL_CAMERA_THETA | VISU_GL_CAMERA_PHI | VISU_GL_CAMERA_OMEGA); } static void onEntryTrans(VisuGlView *view, VisuConfigFileEntry *entry _U_, VisuConfigFile *obj _U_) { visu_gl_view_setXsYs(view, translatDefault[0], translatDefault[1], VISU_GL_CAMERA_XS | VISU_GL_CAMERA_YS); } static void onEntryGross(VisuGlView *view, VisuConfigFileEntry *entry _U_, VisuConfigFile *obj _U_) { visu_gl_view_setGross(view, grossDefault); } static void onEntryPersp(VisuGlView *view, VisuConfigFileEntry *entry _U_, VisuConfigFile *obj _U_) { visu_gl_view_setPersp(view, perspDefault); } static void exportResourcesVisuGlView(GString *data, VisuData *dataObj _U_) { visu_config_file_exportComment(data, DESC_RESOURCE_OPENGL_ANGLES); visu_config_file_exportEntry(data, FLAG_RESOURCE_OPENGL_ANGLES, NULL, "%9.3f %9.3f %9.3f", anglesDefault[0], anglesDefault[1], anglesDefault[2]); visu_config_file_exportComment(data, DESC_RESOURCE_OPENGL_TRANSLAT); visu_config_file_exportEntry(data, FLAG_RESOURCE_OPENGL_TRANSLAT, NULL, "%9.3f %9.3f", translatDefault[0], translatDefault[1]); visu_config_file_exportComment(data, DESC_RESOURCE_OPENGL_GROSS); visu_config_file_exportEntry(data, FLAG_RESOURCE_OPENGL_GROSS, NULL, "%9.3f", grossDefault); visu_config_file_exportComment(data, DESC_RESOURCE_OPENGL_PERSP); visu_config_file_exportEntry(data, FLAG_RESOURCE_OPENGL_PERSP, NULL, "%9.3f", perspDefault); visu_config_file_exportComment(data, ""); } v_sim-3.8.0/src/openGLFunctions/view.h000066400000000000000000000174101370110300500176170ustar00rootroot00000000000000/* EXTRAITS DE LA LICENCE Copyright CEA, contributeurs : Luc BILLARD et Damien CALISTE, laboratoire L_Sim, (2001-2005) Adresse mèl : BILLARD, non joignable par mèl ; CALISTE, damien P caliste AT cea P fr. Ce logiciel est un programme informatique servant à visualiser des structures atomiques dans un rendu pseudo-3D. Ce logiciel est régi par la licence CeCILL soumise au droit français et respectant les principes de diffusion des logiciels libres. Vous pouvez utiliser, modifier et/ou redistribuer ce programme sous les conditions de la licence CeCILL telle que diffusée par le CEA, le CNRS et l'INRIA sur le site "http://www.cecill.info". Le fait que vous puissiez accéder à cet en-tête signifie que vous avez pris connaissance de la licence CeCILL, et que vous en avez accepté les termes (cf. le fichier Documentation/licence.fr.txt fourni avec ce logiciel). */ /* LICENCE SUM UP Copyright CEA, contributors : Luc BILLARD et Damien CALISTE, laboratoire L_Sim, (2001-2005) E-mail address: BILLARD, not reachable any more ; CALISTE, damien P caliste AT cea P fr. This software is a computer program whose purpose is to visualize atomic configurations in 3D. This software is governed by the CeCILL license under French law and abiding by the rules of distribution of free software. You can use, modify and/ or redistribute the software under the terms of the CeCILL license as circulated by CEA, CNRS and INRIA at the following URL "http://www.cecill.info". The fact that you are presently reading this means that you have had knowledge of the CeCILL license and that you accept its terms. You can find a copy of this licence shipped with this software at Documentation/licence.en.txt. */ #ifndef CAMERA_H #define CAMERA_H #include #include #include #include #include G_BEGIN_DECLS typedef struct _VisuGlCamera VisuGlCamera; struct _VisuGlCamera { /* Perspective. */ double d_red; /* Orientation. */ double theta, phi, omega; /* Position. */ double xs, ys; /* Zoom. */ double gross; /* A length reference and its unit. */ double length0; ToolUnits unit; /* Up vector. */ double up[3]; /* Up axis. */ ToolXyzDir upAxis; /* Eye target and eye position. */ double centre[3], eye[3]; }; GType visu_gl_camera_get_type(void); /** * VISU_TYPE_GL_CAMERA: * * The type of #VisuGlCamera objects. */ #define VISU_TYPE_GL_CAMERA (visu_gl_camera_get_type()) void visu_gl_camera_copy(VisuGlCamera *to, const VisuGlCamera *from); /** * VISU_GL_CAMERA_THETA: * * Value used in the visu_gl_camera_setThetaPhiOmega() method to store the tetha angle. */ #define VISU_GL_CAMERA_THETA (1 << 1) /** * VISU_GL_CAMERA_PHI: * * Value used in the visu_gl_camera_setThetaPhiOmega() method to store the phi angle. */ #define VISU_GL_CAMERA_PHI (1 << 2) /** * VISU_GL_CAMERA_OMEGA: * * Value used in the visu_gl_camera_setThetaPhiOmega() method to store the omega angle. */ #define VISU_GL_CAMERA_OMEGA (1 << 3) int visu_gl_camera_setThetaPhiOmega(VisuGlCamera *camera, float valueTheta, float valuePhi, float valueOmega, int mask); /** * VISU_GL_CAMERA_XS: * * Value used in the visu_gl_camera_setXsYs() method to store the horizontal offset. */ #define VISU_GL_CAMERA_XS (1 << 1) /** * VISU_GL_CAMERA_YS: * * Value used in the visu_gl_camera_setXsYs() method to store the vertical offset. */ #define VISU_GL_CAMERA_YS (1 << 2) int visu_gl_camera_setXsYs(VisuGlCamera *camera, float valueX, float valueY, int mask); gboolean visu_gl_camera_setGross(VisuGlCamera *camera, float value); gboolean visu_gl_camera_setPersp(VisuGlCamera *camera, float value); gboolean visu_gl_camera_setRefLength(VisuGlCamera *camera, float value, ToolUnits unit); float visu_gl_camera_getRefLength(VisuGlCamera *camera, ToolUnits *unit); void visu_gl_camera_setUpAxis(VisuGlCamera *camera, ToolXyzDir upAxis); void visu_gl_camera_getScreenAxes(VisuGlCamera *camera, float xAxis[3], float yAxis[3]); #undef near #undef far typedef struct _VisuGlWindow VisuGlWindow; struct _VisuGlWindow { float extens; ToolUnits unit; guint width, height; double near, far; double left, right, bottom, top; }; gboolean visu_gl_window_setViewport(VisuGlWindow *window, guint width, guint height); gboolean visu_gl_window_setAddLength(VisuGlWindow *window, float value, ToolUnits unit); float visu_gl_window_getAddLength(VisuGlWindow *window, ToolUnits *unit); float visu_gl_window_getFileUnitPerPixel(VisuGlWindow *window); /***************************/ /* The #VisuGlView object. */ /***************************/ /** * VISU_TYPE_GL_VIEW: * * The type of #VisuGlView objects. */ #define VISU_TYPE_GL_VIEW (visu_gl_view_get_type()) /** * VISU_GL_VIEW: * @obj: a #GObject to cast. * * Cast the given @obj into #VisuGlView type. */ #define VISU_GL_VIEW(obj) (G_TYPE_CHECK_INSTANCE_CAST(obj, VISU_TYPE_GL_VIEW, VisuGlView)) /** * VISU_GL_VIEW_CLASS: * @klass: a #GObjectClass to cast. * * Cast the given @klass into #VisuGlViewClass. */ #define VISU_GL_VIEW_CLASS(klass) (G_TYPE_CHECK_CLASS_CAST(klass, VISU_TYPE_GL_VIEW, VisuGlViewClass)) /** * VISU_IS_GL_VIEW: * @obj: a #GObject to test. * * Test if the given @ogj is of the type of #VisuGlView object. */ #define VISU_IS_GL_VIEW(obj) (G_TYPE_CHECK_INSTANCE_TYPE(obj, VISU_TYPE_GL_VIEW)) /** * VISU_IS_GL_VIEW_CLASS: * @klass: a #GObjectClass to test. * * Test if the given @klass is of the type of #VisuGlViewClass class. */ #define VISU_IS_GL_VIEW_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE(klass, VISU_TYPE_GL_VIEW)) /** * VISU_GL_VIEW_GET_CLASS: * @obj: a #GObject to get the class of. * * It returns the class of the given @obj. */ #define VISU_GL_VIEW_GET_CLASS(obj) (G_TYPE_INSTANCE_GET_CLASS(obj, VISU_TYPE_GL_VIEW, VisuGlViewClass)) typedef struct _VisuGlViewPrivate VisuGlViewPrivate; typedef struct _VisuGlView VisuGlView; /** * VisuGlView: * * A container structure to deal with OpenGL observer position, size of rendering * viewport... */ struct _VisuGlView { VisuObject parent; VisuGlCamera camera; VisuGlWindow window; VisuGlViewPrivate *priv; }; typedef struct _VisuGlViewClass VisuGlViewClass; /** * VisuGlViewClass: * @parent: the parent class. * * An opaque structure. */ struct _VisuGlViewClass { VisuObjectClass parent; }; GType visu_gl_view_get_type(void); VisuGlView* visu_gl_view_new(void); VisuGlView* visu_gl_view_new_withSize(guint w, guint h); void visu_gl_view_initContext(VisuGlView *view); gboolean visu_gl_view_setThetaPhiOmega(VisuGlView *view, float valueTheta, float valuePhi, float valueOmega, int mask); gboolean visu_gl_view_setXsYs(VisuGlView *view, float valueX, float valueY, int mask); gboolean visu_gl_view_setGross(VisuGlView *view, float value); gboolean visu_gl_view_setPersp(VisuGlView *view, float value); gboolean visu_gl_view_setRefLength(VisuGlView *view, float lg, ToolUnits units); gboolean visu_gl_view_setObjectRadius(VisuGlView *view, float lg, ToolUnits units); gboolean visu_gl_view_setViewport(VisuGlView *view, guint width, guint height); gint visu_gl_view_getDetailLevel(const VisuGlView *view, float dimension); void visu_gl_view_rotateBox(VisuGlView *view, float dTheta, float dPhi, float angles[2]); void visu_gl_view_rotateCamera(VisuGlView *view, float dTheta, float dPhi, float angles[3]); void visu_gl_view_alignToAxis(VisuGlView *view, ToolXyzDir axis); float visu_gl_view_getZCoordinate(VisuGlView *view, float xyz[3]); void visu_gl_view_getRealCoordinates(VisuGlView *view, float xyz[3], float winx, float winy, float winz); gboolean visu_gl_view_setPrecision(VisuGlView *view, float value); float visu_gl_view_getPrecision(const VisuGlView *view); G_END_DECLS #endif v_sim-3.8.0/src/opengl.c000066400000000000000000001006551370110300500150530ustar00rootroot00000000000000/* EXTRAITS DE LA LICENCE Copyright CEA, contributeurs : Luc BILLARD et Damien CALISTE, laboratoire L_Sim, (2001-2005) Adresse mèl : BILLARD, non joignable par mèl ; CALISTE, damien P caliste AT cea P fr. Ce logiciel est un programme informatique servant à visualiser des structures atomiques dans un rendu pseudo-3D. Ce logiciel est régi par la licence CeCILL soumise au droit français et respectant les principes de diffusion des logiciels libres. Vous pouvez utiliser, modifier et/ou redistribuer ce programme sous les conditions de la licence CeCILL telle que diffusée par le CEA, le CNRS et l'INRIA sur le site "http://www.cecill.info". Le fait que vous puissiez accéder à cet en-tête signifie que vous avez pris connaissance de la licence CeCILL, et que vous en avez accepté les termes (cf. le fichier Documentation/licence.fr.txt fourni avec ce logiciel). */ /* LICENCE SUM UP Copyright CEA, contributors : Luc BILLARD et Damien CALISTE, laboratoire L_Sim, (2001-2005) E-mail address: BILLARD, not reachable any more ; CALISTE, damien P caliste AT cea P fr. This software is a computer program whose purpose is to visualize atomic configurations in 3D. This software is governed by the CeCILL license under French law and abiding by the rules of distribution of free software. You can use, modify and/ or redistribute the software under the terms of the CeCILL license as circulated by CEA, CNRS and INRIA at the following URL "http://www.cecill.info". The fact that you are presently reading this means that you have had knowledge of the CeCILL license and that you accept its terms. You can find a copy of this licence shipped with this software at Documentation/licence.en.txt. */ #include #include #include #include #include #include "opengl.h" #include "visu_extension.h" #include "visu_tools.h" #include "visu_configFile.h" #include "openGLFunctions/interactive.h" #include "openGLFunctions/objectList.h" #include "coreTools/toolColor.h" /** * SECTION:opengl * @short_description: This part is responsible for the pseudo3D * rendering through OpenGl and gives methods to adapt the view. * * There is a last parameter which controls when render is * done. There are two states : whenever a changing occurs (in fact * when the OpenGLAskForReDraw signal is received) or only the * OpenGLForceReDraw is received. * * Except when high performances are required, this module never * makes a redraw by itself, even when parameters such as the camera * position are changed. The redraw must be asked by the client by * emitting the OpenGLAskForReDraw signal or the OpenGLForceReDraw * signal. This is to avoid situations when the client makes different * changes but want just only one redraw at the end. All set methods * return a boolean which informs the client of the opportunity to * redraw after the set occurs. For example, if the client call a set * change on theta or phi but the server returns FALSE, it means that * not emission of OpenGLAskForReDraw is needed (for example because * theta or phi had already these values). */ /******************************************************************************/ struct _VisuGlPrivate { /* static int stereo; */ VisuGlLights *currentLights; gboolean antialias, immediate; gboolean trueTransparency, stereoStatus; float stereoAngle; VisuGlRenderingMode mode; guint hints; }; #define FLAG_PARAMETER_OPENGL_IMMEDIATE "opengl_immediateDrawing" #define DESC_PARAMETER_OPENGL_IMMEDIATE "If true, changes of parameters means immediate redrawing ; boolean 0 or 1" static gboolean immediate = TRUE; #define FLAG_PARAMETER_OPENGL_ANTIALIAS "opengl_antialias" #define DESC_PARAMETER_OPENGL_ANTIALIAS "If true, lines are drawn smoother ; boolean 0 or 1" static gboolean antialias = FALSE; #define FLAG_PARAMETER_OPENGL_FAKEBS "opengl_fakeBackingStore" #define DESC_PARAMETER_OPENGL_FAKEBS "If true, V_Sim catches the Expose event from the X server and calls a redraw ; boolean 0 or 1" #define PARAMETER_OPENGL_FAKEBS_DEFAULT 0 static int fakeBackingStore; #define FLAG_PARAMETER_OPENGL_TRANS "opengl_trueTransparency" #define DESC_PARAMETER_OPENGL_TRANSS "If true, the transparency rendering is enhanced ; boolean 0 or 1" static gboolean trueTransparency = FALSE; #define FLAG_PARAMETER_OPENGL_ANGLE "opengl_stereoAngle" #define DESC_PARAMETER_OPENGL_ANGLE "Give the angle of the two receivers in stereo output ; float positive" static float stereoAngle = 5.f; #define FLAG_PARAMETER_OPENGL_STEREO "opengl_stereo" #define DESC_PARAMETER_OPENGL_STEREO "If true, try to draw in stereo ; boolean 0 or 1" static gboolean stereoStatus = FALSE; #define FLAG_PARAMETER_OPENGL_RENDERING "opengl_render" #define DESC_PARAMETER_OPENGL_RENDERING "Rules the way OpenGl draws objects in general ; 4 possible strings : VISU_GL_RENDERING_WIREFRAME, VISU_GL_RENDERING_FLAT, VISU_GL_RENDERING_SMOOTH and VISU_GL_RENDERING_SMOOTH_AND_EDGE" #define FLAG_RESOURCE_OPENGL_RENDERING "gl_render" #define DESC_RESOURCE_OPENGL_RENDERING "Rules the way OpenGl draws objects in general ; 4 possible strings : VISU_GL_RENDERING_WIREFRAME, VISU_GL_RENDERING_FLAT, VISU_GL_RENDERING_SMOOTH and VISU_GL_RENDERING_SMOOTH_AND_EDGE" static guint renderingOption = VISU_GL_RENDERING_SMOOTH; enum { PROP_0, LIGHTS_PROP, ANTIALIAS_PROP, IMMEDIATE_PROP, TRANS_PROP, STEREO_PROP, ANGLE_PROP, MODE_PROP, N_PROP }; static GParamSpec* _properties[N_PROP]; static VisuGl *defaultGl = NULL; static void visu_gl_get_property(GObject* obj, guint property_id, GValue *value, GParamSpec *pspec); static void visu_gl_set_property(GObject* obj, guint property_id, const GValue *value, GParamSpec *pspec); static void glInitContext(VisuGl *gl); /* Local methods. */ static void onEntryAntialias(VisuGl *self, VisuConfigFileEntry *entry, VisuConfigFile *obj); static void onEntryImmediate(VisuGl *self, VisuConfigFileEntry *entry, VisuConfigFile *obj); static void onEntryTrans(VisuGl *self, VisuConfigFileEntry *entry, VisuConfigFile *obj); static void onEntryStereo(VisuGl *self, VisuConfigFileEntry *entry, VisuConfigFile *obj); static void onEntryAngle(VisuGl *self, VisuConfigFileEntry *entry, VisuConfigFile *obj); static void onEntryMode(VisuGl *self, VisuConfigFileEntry *entry, VisuConfigFile *obj); static void exportParametersOpenGL(GString *data, VisuData *dataObj); static void exportOpenGL(GString *data, VisuData *dataObj); static void glSetAntiAlias(VisuGlPrivate *gl); /******************************************************************************/ G_DEFINE_TYPE_WITH_CODE(VisuGl, visu_gl, VISU_TYPE_OBJECT, G_ADD_PRIVATE(VisuGl)) static void visu_gl_class_init(VisuGlClass *klass) { float rgAngle[2] = {-45.f,45.f}; VisuConfigFileEntry *resourceEntry, *oldEntry; DBG_fprintf(stderr, "Visu Gl: creating the class of the object.\n"); /* DBG_fprintf(stderr, " - adding new signals ;\n"); */ /* Parameters */ visu_config_file_addBooleanEntry(VISU_CONFIG_FILE_PARAMETER, FLAG_PARAMETER_OPENGL_ANTIALIAS, DESC_PARAMETER_OPENGL_ANTIALIAS, &antialias, FALSE); visu_config_file_addBooleanEntry(VISU_CONFIG_FILE_PARAMETER, FLAG_PARAMETER_OPENGL_IMMEDIATE, DESC_PARAMETER_OPENGL_IMMEDIATE, &immediate, FALSE); resourceEntry = visu_config_file_addBooleanEntry(VISU_CONFIG_FILE_PARAMETER, FLAG_PARAMETER_OPENGL_TRANS, DESC_PARAMETER_OPENGL_TRANSS, &trueTransparency, FALSE); visu_config_file_entry_setVersion(resourceEntry, 3.4f); resourceEntry = visu_config_file_addFloatArrayEntry(VISU_CONFIG_FILE_PARAMETER, FLAG_PARAMETER_OPENGL_ANGLE, DESC_PARAMETER_OPENGL_ANGLE, 1, &stereoAngle, rgAngle, FALSE); visu_config_file_entry_setVersion(resourceEntry, 3.4f); resourceEntry = visu_config_file_addBooleanEntry(VISU_CONFIG_FILE_PARAMETER, FLAG_PARAMETER_OPENGL_STEREO, DESC_PARAMETER_OPENGL_STEREO, &stereoStatus, FALSE); visu_config_file_entry_setVersion(resourceEntry, 3.4f); visu_config_file_addExportFunction(VISU_CONFIG_FILE_PARAMETER, exportParametersOpenGL); oldEntry = visu_config_file_addEntry(VISU_CONFIG_FILE_PARAMETER, FLAG_PARAMETER_OPENGL_RENDERING, DESC_PARAMETER_OPENGL_RENDERING, 1, NULL); resourceEntry = visu_config_file_addEnumEntry(VISU_CONFIG_FILE_RESOURCE, FLAG_RESOURCE_OPENGL_RENDERING, DESC_RESOURCE_OPENGL_RENDERING, &renderingOption, visu_gl_rendering_getModeFromName, FALSE); visu_config_file_entry_setVersion(resourceEntry, 3.4f); visu_config_file_entry_setReplace(resourceEntry, oldEntry); visu_config_file_addExportFunction(VISU_CONFIG_FILE_RESOURCE, exportOpenGL); visu_gl_rendering_init(); fakeBackingStore = PARAMETER_OPENGL_FAKEBS_DEFAULT; /* Connect the overloading methods. */ G_OBJECT_CLASS(klass)->set_property = visu_gl_set_property; G_OBJECT_CLASS(klass)->get_property = visu_gl_get_property; VISU_GL_CLASS(klass)->initContext = glInitContext; /** * VisuGl::lights: * * Lights environment used for this context. * * Since: 3.8 */ _properties[LIGHTS_PROP] = g_param_spec_boxed("lights", "Lights", "light environment", VISU_TYPE_GL_LIGHTS, G_PARAM_READABLE | G_PARAM_STATIC_STRINGS); g_object_class_install_property (G_OBJECT_CLASS(klass), LIGHTS_PROP, _properties[LIGHTS_PROP]); /** * VisuGl::antialias: * * Antialias line drawing or not. * * Since: 3.8 */ _properties[ANTIALIAS_PROP] = g_param_spec_boolean("antialias", "Antialias", "antialias line", antialias, G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS); g_object_class_install_property (G_OBJECT_CLASS(klass), ANTIALIAS_PROP, _properties[ANTIALIAS_PROP]); /** * VisuGl::immediate: * * Redraw immediately after any change. * * Since: 3.8 */ _properties[IMMEDIATE_PROP] = g_param_spec_boolean("immediate", "Immediate", "immediate redraw after change", immediate, G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS); g_object_class_install_property (G_OBJECT_CLASS(klass), IMMEDIATE_PROP, _properties[IMMEDIATE_PROP]); /** * VisuGl::true-transparency: * * Draw the scene twice to improve transparency rendering. * * Since: 3.8 */ _properties[TRANS_PROP] = g_param_spec_boolean("true-transparency", "True-Transparency", "draw in two passes to improve transparency", trueTransparency, G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS); g_object_class_install_property (G_OBJECT_CLASS(klass), TRANS_PROP, _properties[TRANS_PROP]); /** * VisuGl::stereo: * * Draw the scene differently in the right and the left buffer to * simulate stereo rendering. * * Since: 3.8 */ _properties[STEREO_PROP] = g_param_spec_boolean("stereo", "Stereo", "differenciate right and left buffer", stereoStatus, G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS); g_object_class_install_property (G_OBJECT_CLASS(klass), STEREO_PROP, _properties[STEREO_PROP]); /** * VisuGl::stereo-angle: * * Angle used to separate the left and right buffers (in fact half). * * Since: 3.8 */ _properties[ANGLE_PROP] = g_param_spec_float("stereo-angle", "Stereo-angle", "angle between left and right buffers", -45.f, 45.f, stereoAngle, G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS); g_object_class_install_property (G_OBJECT_CLASS(klass), ANGLE_PROP, _properties[ANGLE_PROP]); /** * VisuGl::mode: * * Global rendering mode. * * Since: 3.8 */ _properties[MODE_PROP] = g_param_spec_uint("mode", "Mode", "global rendering mode", 0, VISU_GL_RENDERING_N_MODES - 1, VISU_GL_RENDERING_SMOOTH, G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS); g_object_class_install_property (G_OBJECT_CLASS(klass), MODE_PROP, _properties[MODE_PROP]); } static void visu_gl_init(VisuGl *self) { DBG_fprintf(stderr, "Visu Gl: initializing a new object (%p).\n", (gpointer)self); self->priv = visu_gl_get_instance_private(self); self->priv->currentLights = (VisuGlLights*)0; self->priv->antialias = antialias; self->priv->immediate = immediate; self->priv->trueTransparency = trueTransparency; self->priv->stereoStatus = stereoStatus; self->priv->stereoAngle = stereoAngle; self->priv->mode = renderingOption; self->priv->hints = 0; g_signal_connect_object(VISU_CONFIG_FILE_PARAMETER, "parsed::" FLAG_PARAMETER_OPENGL_ANTIALIAS, G_CALLBACK(onEntryAntialias), (gpointer)self, G_CONNECT_SWAPPED); g_signal_connect_object(VISU_CONFIG_FILE_PARAMETER, "parsed::" FLAG_PARAMETER_OPENGL_IMMEDIATE, G_CALLBACK(onEntryImmediate), (gpointer)self, G_CONNECT_SWAPPED); g_signal_connect_object(VISU_CONFIG_FILE_PARAMETER, "parsed::" FLAG_PARAMETER_OPENGL_TRANS, G_CALLBACK(onEntryTrans), (gpointer)self, G_CONNECT_SWAPPED); g_signal_connect_object(VISU_CONFIG_FILE_PARAMETER, "parsed::" FLAG_PARAMETER_OPENGL_STEREO, G_CALLBACK(onEntryStereo), (gpointer)self, G_CONNECT_SWAPPED); g_signal_connect_object(VISU_CONFIG_FILE_PARAMETER, "parsed::" FLAG_PARAMETER_OPENGL_ANGLE, G_CALLBACK(onEntryAngle), (gpointer)self, G_CONNECT_SWAPPED); g_signal_connect_object(VISU_CONFIG_FILE_PARAMETER, "parsed::" FLAG_PARAMETER_OPENGL_RENDERING, G_CALLBACK(onEntryMode), (gpointer)self, G_CONNECT_SWAPPED); if (!defaultGl) defaultGl = self; } static void visu_gl_get_property(GObject* obj, guint property_id, GValue *value, GParamSpec *pspec) { VisuGl *self = VISU_GL(obj); DBG_fprintf(stderr, "Visu Gl: get property '%s' -> ", g_param_spec_get_name(pspec)); switch (property_id) { case LIGHTS_PROP: DBG_fprintf(stderr, "%p.\n", (gpointer)self->priv->currentLights); g_value_set_boxed(value, self->priv->currentLights); break; case ANTIALIAS_PROP: DBG_fprintf(stderr, "%d.\n", self->priv->antialias); g_value_set_boolean(value, self->priv->antialias); break; case IMMEDIATE_PROP: DBG_fprintf(stderr, "%d.\n", self->priv->immediate); g_value_set_boolean(value, self->priv->immediate); break; case TRANS_PROP: DBG_fprintf(stderr, "%d.\n", self->priv->trueTransparency); g_value_set_boolean(value, self->priv->trueTransparency); break; case STEREO_PROP: DBG_fprintf(stderr, "%d.\n", self->priv->stereoStatus); g_value_set_boolean(value, self->priv->stereoStatus); break; case ANGLE_PROP: DBG_fprintf(stderr, "%g.\n", self->priv->stereoAngle); g_value_set_float(value, self->priv->stereoAngle); break; case MODE_PROP: DBG_fprintf(stderr, "%d.\n", self->priv->mode); g_value_set_uint(value, self->priv->mode); break; default: /* We don't have any other property... */ G_OBJECT_WARN_INVALID_PROPERTY_ID(obj, property_id, pspec); break; } } static void visu_gl_set_property(GObject* obj, guint property_id, const GValue *value, GParamSpec *pspec) { VisuGl *self = VISU_GL(obj); DBG_fprintf(stderr, "Visu Gl: set property '%s' -> ", g_param_spec_get_name(pspec)); switch (property_id) { case ANTIALIAS_PROP: DBG_fprintf(stderr, "%d.\n", g_value_get_boolean(value)); visu_gl_setAntialias(self, g_value_get_boolean(value)); break; case IMMEDIATE_PROP: DBG_fprintf(stderr, "%d.\n", g_value_get_boolean(value)); visu_gl_setImmediate(self, g_value_get_boolean(value)); break; case TRANS_PROP: DBG_fprintf(stderr, "%d.\n", g_value_get_boolean(value)); visu_gl_setTrueTransparency(self, g_value_get_boolean(value)); break; case STEREO_PROP: DBG_fprintf(stderr, "%d.\n", g_value_get_boolean(value)); visu_gl_setStereo(self, g_value_get_boolean(value)); break; case ANGLE_PROP: DBG_fprintf(stderr, "%g.\n", g_value_get_float(value)); visu_gl_setStereoAngle(self, g_value_get_float(value)); break; case MODE_PROP: DBG_fprintf(stderr, "%d.\n", g_value_get_uint(value)); visu_gl_setMode(self, g_value_get_uint(value)); break; default: /* We don't have any other property... */ G_OBJECT_WARN_INVALID_PROPERTY_ID(obj, property_id, pspec); break; } } /** * visu_gl_getLights: * @gl: a #VisuGl object. * * V_Sim proposes a wrapper around the OpenGL light definitions. * * Returns: the set of current lights. */ VisuGlLights* visu_gl_getLights(VisuGl *gl) { g_return_val_if_fail(VISU_IS_GL(gl), (VisuGlLights*)0); DBG_fprintf(stderr, "lights %p\n", (gpointer)gl->priv->currentLights); if (!gl->priv->currentLights) { /* Deals with lights. */ gl->priv->currentLights = visu_gl_lights_new(); visu_gl_lights_add(gl->priv->currentLights, visu_gl_light_newDefault()); } return gl->priv->currentLights; } /** * visu_gl_applyLights: * @gl: a #VisuGl object. * * If @gl has some defined lights, it setup the OpenGL context with * them and notify the "lights" parameter. * * Since: 3.8 **/ void visu_gl_applyLights(VisuGl *gl) { g_return_if_fail(VISU_IS_GL(gl)); if (gl->priv->currentLights) { visu_gl_lights_apply(gl->priv->currentLights); g_object_notify_by_pspec(G_OBJECT(gl), _properties[LIGHTS_PROP]); } } /******************************************************************************/ /** * visu_gl_setColor: * @gl: a #VisuGl object. * @material: (array fixed-size=5): a 5 elements array with the material properties ; * @rgba: (array fixed-size=4): a 4 elements array with the color values. * * This method call glMaterial to create the right shiningness, emission, diffuse... */ void visu_gl_setColor(VisuGl *gl _U_, const float* material, const float* rgba) { float mm[4] = {0.0f, 0.0f, 0.0f, 0.0f}; g_return_if_fail(material && rgba); DBG_fprintf(stderr, "OpenGL: set rgba colours %gx%gx%gx%g.\n", rgba[0], rgba[1], rgba[2], rgba[3]); glColor4fv(rgba); mm[3] = rgba[3]; mm[0] = material[TOOL_MATERIAL_AMB] * rgba[0]; mm[1] = material[TOOL_MATERIAL_AMB] * rgba[1]; mm[2] = material[TOOL_MATERIAL_AMB] * rgba[2]; glMaterialfv(GL_FRONT, GL_AMBIENT, mm); mm[0] = material[TOOL_MATERIAL_DIF] * rgba[0]; mm[1] = material[TOOL_MATERIAL_DIF] * rgba[1]; mm[2] = material[TOOL_MATERIAL_DIF] * rgba[2]; glMaterialfv(GL_FRONT, GL_DIFFUSE, mm); glMaterialf(GL_FRONT, GL_SHININESS, material[TOOL_MATERIAL_SHI] * 128.0f); mm[0] = material[TOOL_MATERIAL_SPE]; mm[1] = material[TOOL_MATERIAL_SPE]; mm[2] = material[TOOL_MATERIAL_SPE]; glMaterialfv(GL_FRONT, GL_SPECULAR, mm); mm[0] = material[TOOL_MATERIAL_EMI] * rgba[0]; mm[1] = material[TOOL_MATERIAL_EMI] * rgba[1]; mm[2] = material[TOOL_MATERIAL_EMI] * rgba[2]; glMaterialfv(GL_FRONT, GL_EMISSION, mm); } /** * visu_gl_setHighlightColor: * @gl: a #VisuGl object. * @material: a 5 elements array with the material properties ; * @rgb: a 3 elements array with the color values. * @alpha: the alpha channel. * * This method try to set a colour that will contrast with @rgb. */ void visu_gl_setHighlightColor(VisuGl *gl, const float material[5], const float rgb[3], float alpha) { float rgba[4], hsl[3]; tool_color_convertRGBtoHSL(hsl, rgb); hsl[0] = tool_modulo_float(0.5f + hsl[0], 1); hsl[1] = 1.f; hsl[2] = .5f; tool_color_convertHSLtoRGB(rgba, hsl); rgba[3] = alpha; visu_gl_setColor(gl, material, rgba); } /** * visu_gl_drawArrow: * @gl: a #VisuGl object. * @origin: (array fixed-size=3): Position of the centre of the arrow. * @vect: (array fixed-size=3): Vector coordinates. * * Draw an arrow defined by @vect centred at @origin. For a lower * level function, see visu_gl_drawSmoothArrow(). * * Since: 3.8 **/ void visu_gl_drawArrow(VisuGl *gl _U_, const gfloat origin[3], const gfloat vect[3]) { GLUquadricObj *obj; gfloat sph[3]; obj = gluNewQuadric(); tool_matrix_cartesianToSpherical(sph, vect); DBG_fprintf(stderr, "OpenGL: draw an arrow at (%g, %g, %g) of size (%g, %g, %g)\n", origin[0], origin[1], origin[2], vect[0], vect[1], vect[2]); glPushMatrix(); glTranslatef(origin[0], origin[1], origin[2]); glRotated(sph[TOOL_MATRIX_SPHERICAL_PHI], 0, 0, 1); glRotated(sph[TOOL_MATRIX_SPHERICAL_THETA], 0, 1, 0); visu_gl_drawSmoothArrow(obj, VISU_GL_ARROW_CENTERED, sph[TOOL_MATRIX_SPHERICAL_MODULUS] * 0.6, sph[TOOL_MATRIX_SPHERICAL_MODULUS] * 0.1, 50, NULL, sph[TOOL_MATRIX_SPHERICAL_MODULUS] * 0.4, sph[TOOL_MATRIX_SPHERICAL_MODULUS] * 0.15, 50, NULL); glPopMatrix(); gluDeleteQuadric(obj); } static void glInitContext(VisuGl *gl) { g_return_if_fail(VISU_IS_GL(gl)); /* Set the openGL flags. */ glEnable(GL_DEPTH_TEST); glDepthFunc(GL_LEQUAL); glDepthRange(0.0, 1.0); glClearDepth(1.0); glEnable(GL_CULL_FACE); glCullFace(GL_BACK); glEnable(GL_NORMALIZE); glEnable(GL_BLEND); glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA); visu_gl_lights_apply(visu_gl_getLights(gl)); visu_gl_rendering_applyMode(gl->priv->mode); glSetAntiAlias(gl->priv); } /** * visu_gl_initContext: * @gl: a #VisuGl object. * * This method is called when an OpenGL surface is created for the first time. * It sets basic OpenGL options and calls other OpenGLFunctions used in V_Sim. */ void visu_gl_initContext(VisuGl *gl) { VisuGlClass *klass = VISU_GL_GET_CLASS(gl); g_return_if_fail(klass && klass->initContext); klass->initContext(gl); } /******************************************************************************/ /* To set the antialiasing on lines. */ static void glSetAntiAlias(VisuGlPrivate *gl) { if (gl->antialias) { /* Set blend if not present */ glEnable(GL_BLEND); glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA); /* glBlendFunc(GL_SRC_ALPHA_SATURATE,GL_ONE); */ /* Antialias */ glEnable(GL_LINE_SMOOTH); glHint(GL_LINE_SMOOTH_HINT, GL_DONT_CARE); } else { glDisable(GL_LINE_SMOOTH); /* glDisable(GL_BLEND); */ } } /** * visu_gl_setAntialias: * @gl: a #VisuGl object. * @value: a boolean to activate or not the lines antialias. * * To set the antialiasing on lines. * * Returns: TRUE if value is actually changed. */ gboolean visu_gl_setAntialias(VisuGl *gl, gboolean value) { g_return_val_if_fail(VISU_IS_GL(gl), FALSE); if (value == gl->priv->antialias) return FALSE; gl->priv->antialias = value; g_object_notify_by_pspec(G_OBJECT(gl), _properties[ANTIALIAS_PROP]); glSetAntiAlias(gl->priv); return TRUE; } /** * visu_gl_getAntialias: * @gl: a #VisuGl object. * * Get the value of the antialiasing parameter. * * Returns: wether or not the antialising for lines is activated. */ gboolean visu_gl_getAntialias(const VisuGl *gl) { g_return_val_if_fail(VISU_IS_GL(gl), FALSE); return gl->priv->antialias; } /** * visu_gl_setImmediate: * @gl: a #VisuGl object. * @value: a boolean to set or not the immediateDrawing option. * * If true all changes are applied only when the refresh button * is pushed. * * Returns: TRUE if the value is changed. */ gboolean visu_gl_setImmediate(VisuGl *gl, gboolean value) { g_return_val_if_fail(VISU_IS_GL(gl), FALSE); if (value == gl->priv->immediate) return FALSE; gl->priv->immediate = value; g_object_notify_by_pspec(G_OBJECT(gl), _properties[IMMEDIATE_PROP]); return TRUE; } /** * visu_gl_getImmediate: * @gl: a #VisuGl object. * * Get the value of the immediateDrawing option. * * Returns: the value of the immediateDrawing option. */ gboolean visu_gl_getImmediate(const VisuGl *gl) { g_return_val_if_fail(VISU_IS_GL(gl), FALSE); return gl->priv->immediate; } /** * visu_gl_getStereoCapability: * @gl: a #VisuGl object. * * Retrieve if the OpenGL window can render in stereo or not. * * Returns: TRUE if the OpenGL surface can draw in stereo. */ gboolean visu_gl_getStereoCapability(const VisuGl *gl _U_) { GLboolean glStereo; glGetBooleanv(GL_STEREO, &glStereo); return (gboolean)glStereo; } /** * visu_gl_setTrueTransparency: * @gl: a #VisuGl object. * @status: a boolean. * * If true the rendering is done twice to respect the transparency. * * Returns: TRUE if redraw should be done. */ gboolean visu_gl_setTrueTransparency(VisuGl *gl, gboolean status) { g_return_val_if_fail(VISU_IS_GL(gl), FALSE); if (status == gl->priv->trueTransparency) return FALSE; gl->priv->trueTransparency = status; g_object_notify_by_pspec(G_OBJECT(gl), _properties[TRANS_PROP]); return TRUE; } /** * visu_gl_getTrueTransparency: * @gl: a #VisuGl object. * * The drawing can be done in one pass or two to respect transparency. * * Returns: TRUE if the drawing is done twice. */ gboolean visu_gl_getTrueTransparency(const VisuGl *gl) { g_return_val_if_fail(VISU_IS_GL(gl), FALSE); return gl->priv->trueTransparency; } /** * visu_gl_setStereoAngle: * @gl: a #VisuGl object. * @angle: a positive floating point value. * * Change the angle of the eyes in the stereo output. * * Returns: TRUE if redraw should be done. */ gboolean visu_gl_setStereoAngle(VisuGl *gl, float angle) { g_return_val_if_fail(VISU_IS_GL(gl), FALSE); g_return_val_if_fail(angle > 0.f, FALSE); if (gl->priv->stereoAngle == angle) return FALSE; gl->priv->stereoAngle = angle; g_object_notify_by_pspec(G_OBJECT(gl), _properties[ANGLE_PROP]); return TRUE; } /** * visu_gl_getStereoAngle: * @gl: a #VisuGl object. * * Retrieve the angle of the eyes in the stereo output. * * Returns: the angle. */ float visu_gl_getStereoAngle(const VisuGl *gl) { g_return_val_if_fail(VISU_IS_GL(gl), 0.f); return gl->priv->stereoAngle; } /** * visu_gl_setStereo: * @gl: a #VisuGl object. * @status: a boolean. * * Change the type of rendering. The surface can be switch to stereo, * only if the OpenGL has stereo capabilities (see * visu_gl_getStereoCapability()). */ gboolean visu_gl_setStereo(VisuGl *gl, gboolean status) { g_return_val_if_fail(VISU_IS_GL(gl), FALSE); if (gl->priv->stereoStatus == status) return FALSE; gl->priv->stereoStatus = status; g_object_notify_by_pspec(G_OBJECT(gl), _properties[STEREO_PROP]); return TRUE; } /** * visu_gl_getStereo: * @gl: a #VisuGl object. * * Retrieve the status of the OpenGL surface. * * Returns: TRUE if the surface try to draw in stereo (may be TRUE, * even if visu_gl_getStereoCapability() returns FALSE, in * that case the stereo capability is not used). */ gboolean visu_gl_getStereo(const VisuGl *gl) { g_return_val_if_fail(VISU_IS_GL(gl), FALSE); return gl->priv->stereoStatus; } /** * visu_gl_setMode: * @gl: a #VisuGl object. * @value: an integer to represent the method of rendering. * * This function change the value of the parameter renderingOption. * It controls how V_Sim renders objects, in wireframe for example. * * Returns: TRUE if value is actually changed. */ gboolean visu_gl_setMode(VisuGl *gl, VisuGlRenderingMode value) { g_return_val_if_fail(VISU_IS_GL(gl), FALSE); g_return_val_if_fail(value < VISU_GL_RENDERING_N_MODES, FALSE); if (value == gl->priv->mode) return FALSE; gl->priv->mode = value; g_object_notify_by_pspec(G_OBJECT(gl), _properties[MODE_PROP]); visu_gl_rendering_applyMode(value); return TRUE; } /** * visu_gl_getMode: * @gl: a #VisuGl object. * * This function retrieve the value of the parameter renderingOption. * * Returns: the identifier of the current rendering option. */ VisuGlRenderingMode visu_gl_getMode(const VisuGl *gl) { g_return_val_if_fail(VISU_IS_GL(gl), renderingOption); return gl->priv->mode; } /** * visu_gl_addHint: * @gl: a #VisuGl object. * @value: a mask of hints. * * Set some additional hints to @gl. * * Since: 3.8 * * Returns: the mask of current hints. **/ guint visu_gl_addHint(VisuGl *gl, guint value) { g_return_val_if_fail(VISU_IS_GL(gl), 0); return (gl->priv->hints |= value); } /** * visu_gl_getHint: * @gl: a #VisuGl object. * * Retrieve hints of @gl. * * Since: 3.8 * * Returns: the mask of current hints. **/ guint visu_gl_getHint(VisuGl *gl) { g_return_val_if_fail(VISU_IS_GL(gl), 0); return gl->priv->hints; } /***************************/ /* Dealing with parameters */ /***************************/ static void onEntryAntialias(VisuGl *self, VisuConfigFileEntry *entry _U_, VisuConfigFile *obj _U_) { visu_gl_setAntialias(self, antialias); } static void onEntryImmediate(VisuGl *self, VisuConfigFileEntry *entry _U_, VisuConfigFile *obj _U_) { visu_gl_setImmediate(self, immediate); } static void onEntryTrans(VisuGl *self, VisuConfigFileEntry *entry _U_, VisuConfigFile *obj _U_) { visu_gl_setTrueTransparency(self, trueTransparency); } static void onEntryStereo(VisuGl *self, VisuConfigFileEntry *entry _U_, VisuConfigFile *obj _U_) { visu_gl_setStereo(self, stereoStatus); } static void onEntryAngle(VisuGl *self, VisuConfigFileEntry *entry _U_, VisuConfigFile *obj _U_) { visu_gl_setStereoAngle(self, stereoAngle); } static void onEntryMode(VisuGl *self, VisuConfigFileEntry *entry _U_, VisuConfigFile *obj _U_) { visu_gl_setMode(self, renderingOption); } static void exportParametersOpenGL(GString *data, VisuData *dataObj _U_) { g_string_append_printf(data, "# %s\n", DESC_PARAMETER_OPENGL_ANTIALIAS); g_string_append_printf(data, "%s: %d\n\n", FLAG_PARAMETER_OPENGL_ANTIALIAS, defaultGl->priv->antialias); g_string_append_printf(data, "# %s\n", DESC_PARAMETER_OPENGL_IMMEDIATE); g_string_append_printf(data, "%s: %d\n\n", FLAG_PARAMETER_OPENGL_IMMEDIATE, defaultGl->priv->immediate); g_string_append_printf(data, "# %s\n", DESC_PARAMETER_OPENGL_TRANSS); g_string_append_printf(data, "%s: %d\n\n", FLAG_PARAMETER_OPENGL_TRANS, defaultGl->priv->trueTransparency); g_string_append_printf(data, "# %s\n", DESC_PARAMETER_OPENGL_STEREO); g_string_append_printf(data, "%s: %d\n\n", FLAG_PARAMETER_OPENGL_STEREO, defaultGl->priv->stereoStatus); g_string_append_printf(data, "# %s\n", DESC_PARAMETER_OPENGL_ANGLE); g_string_append_printf(data, "%s: %f\n\n", FLAG_PARAMETER_OPENGL_ANGLE, defaultGl->priv->stereoAngle); } static void exportOpenGL(GString *data, VisuData *dataObj _U_) { visu_config_file_exportComment(data, DESC_RESOURCE_OPENGL_RENDERING); visu_config_file_exportEntry(data, FLAG_RESOURCE_OPENGL_RENDERING, NULL, "%s", visu_gl_rendering_getAllModes()[defaultGl->priv->mode]); visu_config_file_exportComment(data, ""); } v_sim-3.8.0/src/opengl.h000066400000000000000000000122661370110300500150600ustar00rootroot00000000000000/* EXTRAITS DE LA LICENCE Copyright CEA, contributeurs : Luc BILLARD et Damien CALISTE, laboratoire L_Sim, (2001-2005) Adresse mèl : BILLARD, non joignable par mèl ; CALISTE, damien P caliste AT cea P fr. Ce logiciel est un programme informatique servant à visualiser des structures atomiques dans un rendu pseudo-3D. Ce logiciel est régi par la licence CeCILL soumise au droit français et respectant les principes de diffusion des logiciels libres. Vous pouvez utiliser, modifier et/ou redistribuer ce programme sous les conditions de la licence CeCILL telle que diffusée par le CEA, le CNRS et l'INRIA sur le site "http://www.cecill.info". Le fait que vous puissiez accéder à cet en-tête signifie que vous avez pris connaissance de la licence CeCILL, et que vous en avez accepté les termes (cf. le fichier Documentation/licence.fr.txt fourni avec ce logiciel). */ /* LICENCE SUM UP Copyright CEA, contributors : Luc BILLARD et Damien CALISTE, laboratoire L_Sim, (2001-2005) E-mail address: BILLARD, not reachable any more ; CALISTE, damien P caliste AT cea P fr. This software is a computer program whose purpose is to visualize atomic configurations in 3D. This software is governed by the CeCILL license under French law and abiding by the rules of distribution of free software. You can use, modify and/ or redistribute the software under the terms of the CeCILL license as circulated by CEA, CNRS and INRIA at the following URL "http://www.cecill.info". The fact that you are presently reading this means that you have had knowledge of the CeCILL license and that you accept its terms. You can find a copy of this licence shipped with this software at Documentation/licence.en.txt. */ #ifndef OPENGL_H #define OPENGL_H #include #include #include "visu_tools.h" #include "openGLFunctions/view.h" #include "openGLFunctions/light.h" #include "openGLFunctions/renderingMode.h" G_BEGIN_DECLS /** * VISU_TYPE_GL: * * return the type of #VisuGl. */ #define VISU_TYPE_GL (visu_gl_get_type ()) /** * VISU_GL: * @obj: a #GObject to cast. * * Cast the given @obj into #VisuGl type. */ #define VISU_GL(obj) (G_TYPE_CHECK_INSTANCE_CAST(obj, VISU_TYPE_GL, VisuGl)) /** * VISU_GL_CLASS: * @klass: a #GObjectClass to cast. * * Cast the given @klass into #VisuGlClass. */ #define VISU_GL_CLASS(klass) (G_TYPE_CHECK_CLASS_CAST(klass, VISU_TYPE_GL, VisuGlClass)) /** * VISU_IS_GL: * @obj: a #GObject to test. * * Test if the given @ogj is of the type of #VisuGl object. */ #define VISU_IS_GL(obj) (G_TYPE_CHECK_INSTANCE_TYPE(obj, VISU_TYPE_GL)) /** * VISU_IS_GL_CLASS: * @klass: a #GObjectClass to test. * * Test if the given @klass is of the type of #VisuGlClass class. */ #define VISU_IS_GL_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE(klass, VISU_TYPE_GL)) /** * VISU_GL_GET_CLASS: * @obj: a #GObject to get the class of. * * It returns the class of the given @obj. */ #define VISU_GL_GET_CLASS(obj) (G_TYPE_INSTANCE_GET_CLASS(obj, VISU_TYPE_GL, VisuGlClass)) /** * VISU_GL_OFFSCREEN * * An hint mentioning that the OpenGL context is used for offscreen * rendering. * * Since: 3.8 */ #define VISU_GL_OFFSCREEN 1 << 0 /** * VisuGlPrivate: * * Private data for #VisuGl objects. */ typedef struct _VisuGlPrivate VisuGlPrivate; /** * VisuGl: * * Common name to refer to a #_VisuGl. */ typedef struct _VisuGl VisuGl; struct _VisuGl { VisuObject parent; VisuGlPrivate *priv; }; /** * VisuGlClass: * @parent: private. * @initContext: called when used in a new OpenGL context. * * Common name to refer to a #_VisuGlClass. */ typedef struct _VisuGlClass VisuGlClass; struct _VisuGlClass { VisuObjectClass parent; void (*initContext)(VisuGl* gl); }; /** * visu_gl_get_type: * * This method returns the type of #VisuGl, use * VISU_TYPE_GL instead. * * Since: 3.8 * * Returns: the type of #VisuGl. */ GType visu_gl_get_type(void); void visu_gl_setColor(VisuGl *gl, const float material[5], const float rgba[4]); void visu_gl_setHighlightColor(VisuGl *gl, const float material[5], const float rgb[3], float alpha); void visu_gl_drawArrow(VisuGl *gl, const gfloat origin[3], const gfloat vect[3]); /* Objects to play with lights. */ VisuGlLights* visu_gl_getLights(VisuGl *gl); void visu_gl_applyLights(VisuGl *gl); gboolean visu_gl_setAntialias(VisuGl *gl, gboolean value); gboolean visu_gl_getAntialias(const VisuGl *gl); gboolean visu_gl_setImmediate(VisuGl *gl, gboolean value); gboolean visu_gl_getImmediate(const VisuGl *gl); gboolean visu_gl_setTrueTransparency(VisuGl *gl, gboolean status); gboolean visu_gl_getTrueTransparency(const VisuGl *gl); gboolean visu_gl_getStereoCapability(const VisuGl *gl); gboolean visu_gl_setStereo(VisuGl *gl, gboolean status); gboolean visu_gl_getStereo(const VisuGl *gl); gboolean visu_gl_setStereoAngle(VisuGl *gl, float angle); float visu_gl_getStereoAngle(const VisuGl *gl); gboolean visu_gl_setMode(VisuGl *gl, VisuGlRenderingMode value); VisuGlRenderingMode visu_gl_getMode(const VisuGl *gl); guint visu_gl_addHint(VisuGl *gl, guint value); guint visu_gl_getHint(VisuGl *gl); /* redraw methods */ void visu_gl_initContext(VisuGl *gl); G_END_DECLS #endif v_sim-3.8.0/src/pairsModeling/000077500000000000000000000000001370110300500162115ustar00rootroot00000000000000v_sim-3.8.0/src/pairsModeling/cylinder_renderer.c000066400000000000000000000353561370110300500220700ustar00rootroot00000000000000/* EXTRAITS DE LA LICENCE Copyright CEA, contributeurs : Damien CALISTE, laboratoire L_Sim, (2016) Adresse mèl : BILLARD, non joignable par mèl ; CALISTE, damien P caliste AT cea P fr. Ce logiciel est un programme informatique servant à visualiser des structures atomiques dans un rendu pseudo-3D. Ce logiciel est régi par la licence CeCILL soumise au droit français et respectant les principes de diffusion des logiciels libres. Vous pouvez utiliser, modifier et/ou redistribuer ce programme sous les conditions de la licence CeCILL telle que diffusée par le CEA, le CNRS et l'INRIA sur le site "http://www.cecill.info". Le fait que vous puissiez accéder à cet en-tête signifie que vous avez pris connaissance de la licence CeCILL, et que vous en avez accepté les termes (cf. le fichier Documentation/licence.fr.txt fourni avec ce logiciel). */ /* LICENCE SUM UP Copyright CEA, contributors : Damien CALISTE, laboratoire L_Sim, (2016) E-mail address: BILLARD, not reachable any more ; CALISTE, damien P caliste AT cea P fr. This software is a computer program whose purpose is to visualize atomic configurations in 3D. This software is governed by the CeCILL license under French law and abiding by the rules of distribution of free software. You can use, modify and/ or redistribute the software under the terms of the CeCILL license as circulated by CEA, CNRS and INRIA at the following URL "http://www.cecill.info". The fact that you are presently reading this means that you have had knowledge of the CeCILL license and that you accept its terms. You can find a copy of this licence shipped with this software at Documentation/licence.en.txt. */ #include "cylinder_renderer.h" #include "iface_cylinder.h" #include #include #include #include #include /** * SECTION:cylinder_renderer * @short_description: a class to render #VisuPairLink as cylinders. * * This class is used to render #VisuPairLink as cylinders. */ struct _ElementRenderer { VisuElementRenderer *ele; gulong mat_sig, col_sig, siz_sig; }; struct _NodeColorizer { VisuDataColorizer *colorizer; gulong dirty_sig; }; struct _VisuPairCylinderRendererPrivate { gboolean dispose_has_run; guint nlat; gfloat radius; GLUquadricObj *obj; struct _NodeColorizer nodes; struct _ElementRenderer ele1; struct _ElementRenderer ele2; VisuGlView *view; gulong detail_signal; }; static void visu_pair_cylinder_renderer_dispose(GObject* obj); static void _start(VisuPairLinkRenderer *self, VisuPairLink *data, VisuElementRenderer *ele1, VisuElementRenderer *ele2, VisuDataColorizer *colorizer); static void _stop(VisuPairLinkRenderer *self, VisuPairLink *data); static void _draw(VisuPairLinkRenderer *self, const VisuPairLinkIter *iter); static gboolean _set_view(VisuPairLinkRenderer *renderer, VisuGlView *view); static void _setElementRenderer(VisuPairCylinderRenderer *self, struct _ElementRenderer *ele, VisuElementRenderer *renderer); static void _setNodeColorizer(VisuPairCylinderRenderer *self, struct _NodeColorizer *node, VisuDataColorizer *colorizer); enum { PROP_0, ID_PROP, LABEL_PROP, DESCR_PROP, N_PROP }; G_DEFINE_TYPE_WITH_CODE(VisuPairCylinderRenderer, visu_pair_cylinder_renderer, VISU_TYPE_PAIR_LINK_RENDERER, G_ADD_PRIVATE(VisuPairCylinderRenderer)) static void visu_pair_cylinder_renderer_class_init(VisuPairCylinderRendererClass *klass) { DBG_fprintf(stderr, "Visu Cylinder Renderer: creating the class of the object.\n"); /* Connect the overloading methods. */ G_OBJECT_CLASS(klass)->dispose = visu_pair_cylinder_renderer_dispose; VISU_PAIR_LINK_RENDERER_CLASS(klass)->start = _start; VISU_PAIR_LINK_RENDERER_CLASS(klass)->stop = _stop; VISU_PAIR_LINK_RENDERER_CLASS(klass)->draw = _draw; VISU_PAIR_LINK_RENDERER_CLASS(klass)->set_view = _set_view; } static void visu_pair_cylinder_renderer_init(VisuPairCylinderRenderer *obj) { DBG_fprintf(stderr, "Visu Cylinder Renderer: initializing a new object (%p).\n", (gpointer)obj); obj->priv = visu_pair_cylinder_renderer_get_instance_private(obj); obj->priv->dispose_has_run = FALSE; obj->priv->ele1.ele = (VisuElementRenderer*)0; obj->priv->ele2.ele = (VisuElementRenderer*)0; obj->priv->view = (VisuGlView*)0; } static void visu_pair_cylinder_renderer_dispose(GObject* obj) { VisuPairCylinderRenderer *data; data = VISU_PAIR_CYLINDER_RENDERER(obj); if (data->priv->dispose_has_run) return; data->priv->dispose_has_run = TRUE; _set_view(VISU_PAIR_LINK_RENDERER(data), (VisuGlView*)0); _setNodeColorizer(data, &data->priv->nodes, (VisuDataColorizer*)0); _setElementRenderer(data, &data->priv->ele1, (VisuElementRenderer*)0); _setElementRenderer(data, &data->priv->ele2, (VisuElementRenderer*)0); /* Chain up to the parent class */ G_OBJECT_CLASS(visu_pair_cylinder_renderer_parent_class)->dispose(obj); } /** * visu_pair_cylinder_renderer_new: * * The default renderer to draw linsk as cylinders. * * Since: 3.8 * * Returns: (transfer full): the default #VisuPairCylinderRenderer object. */ VisuPairCylinderRenderer* visu_pair_cylinder_renderer_new() { return VISU_PAIR_CYLINDER_RENDERER(g_object_new(VISU_TYPE_PAIR_CYLINDER_RENDERER, "id", "Cylinder pairs", "label", _("Cylinder pairs"), "description", _("Pairs are rendered by cylinders." " The color and the width can by chosen."), NULL)); } static void _setElementRenderer(VisuPairCylinderRenderer *self, struct _ElementRenderer *ele, VisuElementRenderer *renderer) { if (ele->ele == renderer) return; if (ele->ele) { g_signal_handler_disconnect(ele->ele, ele->mat_sig); g_signal_handler_disconnect(ele->ele, ele->col_sig); g_signal_handler_disconnect(ele->ele, ele->siz_sig); g_object_unref(ele->ele); } ele->ele = renderer; if (renderer) { g_object_ref(renderer); ele->mat_sig = g_signal_connect_swapped(renderer, "notify::material", G_CALLBACK(visu_pair_link_renderer_emitDirty), self); ele->col_sig = g_signal_connect_swapped(renderer, "notify::color", G_CALLBACK(visu_pair_link_renderer_emitDirty), self); ele->siz_sig = g_signal_connect_swapped(renderer, "size-changed", G_CALLBACK(visu_pair_link_renderer_emitDirty), self); } } static void _setNodeColorizer(VisuPairCylinderRenderer *self, struct _NodeColorizer *node, VisuDataColorizer *colorizer) { if (node->colorizer == colorizer) return; if (node->colorizer) { g_signal_handler_disconnect(node->colorizer, node->dirty_sig); g_object_unref(node->colorizer); } node->colorizer = colorizer; if (colorizer) { g_object_ref(colorizer); node->dirty_sig = g_signal_connect_swapped(colorizer, "dirty", G_CALLBACK(visu_pair_link_renderer_emitDirty), self); } } static void _start(VisuPairLinkRenderer *self, VisuPairLink *data, VisuElementRenderer *ele1, VisuElementRenderer *ele2, VisuDataColorizer *colorizer) { VisuPairCylinderRenderer *renderer; VisuPairCylinderColorId id; renderer = VISU_PAIR_CYLINDER_RENDERER(self); renderer->priv->radius = visu_pair_cylinder_getRadius(VISU_PAIR_CYLINDER(data)); renderer->priv->nlat = visu_gl_view_getDetailLevel(renderer->priv->view, renderer->priv->radius); id = visu_pair_cylinder_getColorType(VISU_PAIR_CYLINDER(data)); if (id == VISU_CYLINDER_COLOR_ELEMENT || id == VISU_CYLINDER_COLOR_NODE) { _setElementRenderer(renderer, &renderer->priv->ele1, ele1); _setElementRenderer(renderer, &renderer->priv->ele2, ele2); } else { _setElementRenderer(renderer, &renderer->priv->ele1, (VisuElementRenderer*)0); _setElementRenderer(renderer, &renderer->priv->ele2, (VisuElementRenderer*)0); } if (id == VISU_CYLINDER_COLOR_NODE) { _setNodeColorizer(renderer, &renderer->priv->nodes, colorizer); } else { _setNodeColorizer(renderer, &renderer->priv->nodes, (VisuDataColorizer*)0); } renderer->priv->obj = gluNewQuadric(); } static void _stop(VisuPairLinkRenderer *self, VisuPairLink *data _U_) { gluDeleteQuadric(VISU_PAIR_CYLINDER_RENDERER(self)->priv->obj); } static void _setElementColor(VisuElementRenderer *ele, float coeff) { const ToolColor *color; float rgba[4]; color = visu_element_renderer_getColor(ele); rgba[0] = color->rgba[0]; rgba[1] = color->rgba[1]; rgba[2] = color->rgba[2]; rgba[3] = coeff * color->rgba[3]; visu_gl_setColor((VisuGl*)0, visu_element_renderer_getMaterial(ele), rgba); } static void _setNodeColor(VisuElementRenderer *ele, VisuDataColorizer *colorizer, float coeff, VisuData *data, VisuNode *node) { const ToolColor *color; float rgba[4]; if (!colorizer || !visu_data_colorizer_getColor(colorizer, rgba, data, node)) { color = visu_element_renderer_getColor(ele); rgba[0] = color->rgba[0]; rgba[1] = color->rgba[1]; rgba[2] = color->rgba[2]; rgba[3] = color->rgba[3]; } rgba[3] *= coeff; visu_gl_setColor((VisuGl*)0, visu_element_renderer_getMaterial(ele), rgba); } static void _draw(VisuPairLinkRenderer *self, const VisuPairLinkIter *iter) { float rgba[4], mm[5] = {0.5, 0.5, 0., 0. , 0.}; const ToolColor *color; double vNorm[3]; /* vecteur normal aux vecteurs (0,0,1) et (x2-x1, y2-y1, z2-z1) */ double phi; #define RADTODEG 57.29577951 VisuPairCylinderRenderer *renderer; gfloat tSize, ratio, d; renderer = VISU_PAIR_CYLINDER_RENDERER(self); d = sqrt(iter->d2); if (iter->dxyz[0] != 0 || iter->dxyz[1] != 0) { vNorm[0] = - iter->dxyz[1]; vNorm[1] = iter->dxyz[0]; vNorm[2] = 0.; phi = acos(CLAMP(iter->dxyz[2] / d, -1., 1.)) * RADTODEG; } else { vNorm[0] = 1.; vNorm[1] = 0.; vNorm[2] = 0.; if (iter->dxyz[2] < 0.) phi = 180.; else phi = 0.; } glPushMatrix(); switch (visu_pair_cylinder_getColorType(VISU_PAIR_CYLINDER(iter->parent))) { case VISU_CYLINDER_COLOR_USER: /* Color is set by the _start() method before for this family of pairs, we change need to change it because of alpha. */ color = visu_pair_link_getColor(iter->parent); rgba[0] = color->rgba[0]; rgba[1] = color->rgba[1]; rgba[2] = color->rgba[2]; rgba[3] = iter->coeff * color->rgba[3]; visu_gl_setColor((VisuGl*)0, mm, rgba); glTranslated(iter->xyz1[0], iter->xyz1[1], iter->xyz1[2]); glRotated(phi, vNorm[0], vNorm[1], vNorm[2]); gluCylinder(renderer->priv->obj, renderer->priv->radius, renderer->priv->radius, (GLdouble)d * ((iter->periodic) ? 0.5 : 1.), (GLint)renderer->priv->nlat, (GLint)1); if (iter->periodic) { glTranslated(0, 0, d * 0.5); gluDisk(renderer->priv->obj, 0, renderer->priv->radius*1.03, renderer->priv->nlat, 1); glPopMatrix(); glPushMatrix(); glTranslated(iter->xyz2[0], iter->xyz2[1], iter->xyz2[2]); glRotated(phi - 180., vNorm[0], vNorm[1], vNorm[2]); gluCylinder(renderer->priv->obj, renderer->priv->radius, renderer->priv->radius, (GLdouble)d * 0.5, (GLint)renderer->priv->nlat, (GLint)1); glTranslated(0, 0, d * 0.5); gluDisk(renderer->priv->obj, 0, renderer->priv->radius*1.03, renderer->priv->nlat, 1); } break; case VISU_CYLINDER_COLOR_ELEMENT: case VISU_CYLINDER_COLOR_NODE: tSize = visu_element_renderer_getExtent(renderer->priv->ele1.ele) + visu_element_renderer_getExtent(renderer->priv->ele2.ele); ratio = visu_element_renderer_getExtent(renderer->priv->ele1.ele) / tSize; glTranslated(iter->xyz1[0], iter->xyz1[1], iter->xyz1[2]); glRotated(phi, vNorm[0], vNorm[1], vNorm[2]); if (visu_pair_cylinder_getColorType(VISU_PAIR_CYLINDER(iter->parent)) == VISU_CYLINDER_COLOR_ELEMENT) _setElementColor(renderer->priv->ele1.ele, iter->coeff); else _setNodeColor(renderer->priv->ele1.ele, renderer->priv->nodes.colorizer, iter->coeff, iter->data, iter->iter1.node); gluCylinder(renderer->priv->obj, renderer->priv->radius, renderer->priv->radius, (GLdouble)d * ratio, (GLint)renderer->priv->nlat, (GLint)1); if (!iter->periodic) { glPopMatrix(); glPushMatrix(); glTranslated(iter->xyz1[0] + ratio * iter->dxyz[0], iter->xyz1[1] + ratio * iter->dxyz[1], iter->xyz1[2] + ratio * iter->dxyz[2]); glRotated(phi, vNorm[0], vNorm[1], vNorm[2]); } else { glPopMatrix(); glPushMatrix(); glTranslated(iter->xyz2[0], iter->xyz2[1], iter->xyz2[2]); glRotated(phi - 180., vNorm[0], vNorm[1], vNorm[2]); } if (visu_pair_cylinder_getColorType(VISU_PAIR_CYLINDER(iter->parent)) == VISU_CYLINDER_COLOR_ELEMENT) _setElementColor(renderer->priv->ele2.ele, iter->coeff); else _setNodeColor(renderer->priv->ele2.ele, renderer->priv->nodes.colorizer, iter->coeff, iter->data, iter->iter2.node); gluCylinder(renderer->priv->obj, renderer->priv->radius, renderer->priv->radius, (GLdouble)d * (1.f - ratio), (GLint)renderer->priv->nlat, (GLint)1); break; default: break; } glPopMatrix(); } static gboolean _set_view(VisuPairLinkRenderer *renderer, VisuGlView *view) { VisuPairCylinderRenderer *self; g_return_val_if_fail(VISU_IS_PAIR_CYLINDER_RENDERER(renderer), FALSE); self = VISU_PAIR_CYLINDER_RENDERER(renderer); if (self->priv->view == view) return FALSE; if (self->priv->view) { g_signal_handler_disconnect(G_OBJECT(self->priv->view), self->priv->detail_signal); g_object_unref(self->priv->view); } if (view) { g_object_ref(view); self->priv->detail_signal = g_signal_connect_swapped(G_OBJECT(view), "DetailLevelChanged", G_CALLBACK(visu_pair_link_renderer_emitDirty), (gpointer)self); } self->priv->view = view; return TRUE; } v_sim-3.8.0/src/pairsModeling/cylinder_renderer.h000066400000000000000000000107121370110300500220620ustar00rootroot00000000000000/* EXTRAITS DE LA LICENCE Copyright CEA, contributeurs : Damien CALISTE, laboratoire L_Sim, (2016) Adresse mèl : BILLARD, non joignable par mèl ; CALISTE, damien P caliste AT cea P fr. Ce logiciel est un programme informatique servant à visualiser des structures atomiques dans un rendu pseudo-3D. Ce logiciel est régi par la licence CeCILL soumise au droit français et respectant les principes de diffusion des logiciels libres. Vous pouvez utiliser, modifier et/ou redistribuer ce programme sous les conditions de la licence CeCILL telle que diffusée par le CEA, le CNRS et l'INRIA sur le site "http://www.cecill.info". Le fait que vous puissiez accéder à cet en-tête signifie que vous avez pris connaissance de la licence CeCILL, et que vous en avez accepté les termes (cf. le fichier Documentation/licence.fr.txt fourni avec ce logiciel). */ /* LICENCE SUM UP Copyright CEA, contributors : Damien CALISTE, laboratoire L_Sim, (2016) E-mail address: BILLARD, not reachable any more ; CALISTE, damien P caliste AT cea P fr. This software is a computer program whose purpose is to visualize atomic configurations in 3D. This software is governed by the CeCILL license under French law and abiding by the rules of distribution of free software. You can use, modify and/ or redistribute the software under the terms of the CeCILL license as circulated by CEA, CNRS and INRIA at the following URL "http://www.cecill.info". The fact that you are presently reading this means that you have had knowledge of the CeCILL license and that you accept its terms. You can find a copy of this licence shipped with this software at Documentation/licence.en.txt. */ #ifndef CYLINDER_RENDERER_H #define CYLINDER_RENDERER_H #include #include #include "linkRenderer.h" /** * VISU_TYPE_PAIR_CYLINDER_RENDERER: * * return the type of #VisuPairCylinderRenderer. * * Since: 3.8 */ #define VISU_TYPE_PAIR_CYLINDER_RENDERER (visu_pair_cylinder_renderer_get_type ()) /** * VISU_PAIR_CYLINDER_RENDERER: * @obj: a #GObject to cast. * * Cast the given @obj into #VisuPairCylinderRenderer type. * * Since: 3.8 */ #define VISU_PAIR_CYLINDER_RENDERER(obj) (G_TYPE_CHECK_INSTANCE_CAST(obj, VISU_TYPE_PAIR_CYLINDER_RENDERER, VisuPairCylinderRenderer)) /** * VISU_PAIR_CYLINDER_RENDERER_CLASS: * @klass: a #GObjectClass to cast. * * Cast the given @klass into #VisuPairCylinderRendererClass. * * Since: 3.8 */ #define VISU_PAIR_CYLINDER_RENDERER_CLASS(klass) (G_TYPE_CHECK_CLASS_CAST(klass, VISU_TYPE_PAIR_CYLINDER_RENDERER, VisuPairCylinderRendererClass)) /** * VISU_IS_PAIR_CYLINDER_RENDERER: * @obj: a #GObject to test. * * Test if the given @ogj is of the type of #VisuPairCylinderRenderer object. * * Since: 3.8 */ #define VISU_IS_PAIR_CYLINDER_RENDERER(obj) (G_TYPE_CHECK_INSTANCE_TYPE(obj, VISU_TYPE_PAIR_CYLINDER_RENDERER)) /** * VISU_IS_PAIR_CYLINDER_RENDERER_CLASS: * @klass: a #GObjectClass to test. * * Test if the given @klass is of the type of #VisuPairCylinderRendererClass class. * * Since: 3.8 */ #define VISU_IS_PAIR_CYLINDER_RENDERER_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE(klass, VISU_TYPE_PAIR_CYLINDER_RENDERER)) /** * VISU_PAIR_CYLINDER_RENDERER_GET_CLASS: * @obj: a #GObject to get the class of. * * It returns the class of the given @obj. * * Since: 3.8 */ #define VISU_PAIR_CYLINDER_RENDERER_GET_CLASS(obj) (G_TYPE_INSTANCE_GET_CLASS(obj, VISU_TYPE_PAIR_CYLINDER_RENDERER, VisuPairCylinderRendererClass)) typedef struct _VisuPairCylinderRenderer VisuPairCylinderRenderer; typedef struct _VisuPairCylinderRendererPrivate VisuPairCylinderRendererPrivate; typedef struct _VisuPairCylinderRendererClass VisuPairCylinderRendererClass; /** * VisuPairCylinderRenderer: * * An opaque structure. */ struct _VisuPairCylinderRenderer { VisuPairLinkRenderer parent; VisuPairCylinderRendererPrivate *priv; }; /** * VisuPairCylinderRendererClass: * @parent: the parent class; * * A short way to identify #_VisuPairCylinderRendererClass structure. */ struct _VisuPairCylinderRendererClass { VisuPairLinkRendererClass parent; }; /** * visu_pair_cylinder_renderer_get_type: * * This method returns the type of #VisuPairCylinderRenderer, use * VISU_TYPE_PAIR_CYLINDER_RENDERER instead. * * Since: 3.8 * * Returns: the type of #VisuPairCylinderRenderer. */ GType visu_pair_cylinder_renderer_get_type(void); VisuPairCylinderRenderer* visu_pair_cylinder_renderer_new(); #endif v_sim-3.8.0/src/pairsModeling/iface_cylinder.c000066400000000000000000000312741370110300500213240ustar00rootroot00000000000000/* EXTRAITS DE LA LICENCE Copyright CEA, contributeurs : Damien CALISTE, laboratoire L_Sim, (2016) Adresse mèl : CALISTE, damien P caliste AT cea P fr. Ce logiciel est un programme informatique servant à visualiser des structures atomiques dans un rendu pseudo-3D. Ce logiciel est régi par la licence CeCILL soumise au droit français et respectant les principes de diffusion des logiciels libres. Vous pouvez utiliser, modifier et/ou redistribuer ce programme sous les conditions de la licence CeCILL telle que diffusée par le CEA, le CNRS et l'INRIA sur le site "http://www.cecill.info". Le fait que vous puissiez accéder à cet en-tête signifie que vous avez pris connaissance de la licence CeCILL, et que vous en avez accepté les termes (cf. le fichier Documentation/licence.fr.txt fourni avec ce logiciel). */ /* LICENCE SUM UP Copyright CEA, contributors : Damien CALISTE, laboratoire L_Sim, (2016) E-mail address: CALISTE, damien P caliste AT cea P fr. This software is a computer program whose purpose is to visualize atomic configurations in 3D. This software is governed by the CeCILL license under French law and abiding by the rules of distribution of free software. You can use, modify and/ or redistribute the software under the terms of the CeCILL license as circulated by CEA, CNRS and INRIA at the following URL "http://www.cecill.info". The fact that you are presently reading this means that you have had knowledge of the CeCILL license and that you accept its terms. You can find a copy of this licence shipped with this software at Documentation/licence.en.txt. */ #include "iface_cylinder.h" #include #include /** * SECTION:iface_cylinder * @short_description: An interface defining all the properties * required to draw a #VisuPair as a cylinder. * * #VisuPairCylinder interface introduces the "radius" property * for the cylinder rendering. Cylinders can also be rendered with a * solid color or with colors depending on the #VisuElement * their are linking. */ #define FLAG_RESOURCES_PAIR_RADIUS "pairCylinder_pairRadius" #define DESC_RESOURCES_PAIR_RADIUS "This value is the radius for specific pairs drawn as cylinders ; element1 elemen2 0 < real < 10" #define FLAG_RESOURCES_LINK_RADIUS "pairCylinder_linkRadius" #define DESC_RESOURCES_LINK_RADIUS "This value is the radius for specific drawn link as cylinders ; [element1] [element2] [min] [max] [0 < real < 10]" #define FLAG_RESOURCES_CYLINDER_RADIUS "pairCylinder_radius" #define DESC_RESOURCES_CYLINDER_RADIUS "This value is the default radius of the pairs drawn as cylinders ; 0 < real < 10" #define _RADIUS_DEFAULT 0.1f static float cylinderRadius, _linkRadius; #define FLAG_RESOURCES_CYLINDER_COLOR_TYPE "cylinder_colorType" #define DESC_RESOURCES_CYLINDER_COLOR_TYPE "It chooses the colors of the cylinders according differents criterion ;" #define FLAG_RESOURCES_LINK_COLOR_TYPE "pairCylinder_linkColorType" #define DESC_RESOURCES_LINK_COLOR_TYPE "It chooses the colors of the cylinders according differents criterion for each link ; [element1] [element2] [min] [max] [int id]" #define _COLOR_TYPE_DEFAULT VISU_CYLINDER_COLOR_USER static int cylinderColorType, _linkColorType; static void onEntryRadius(VisuConfigFile *obj, VisuConfigFileEntry *entry, gpointer data); static void onEntryType(VisuConfigFile *obj, VisuConfigFileEntry *entry, gpointer data); /* This function save the resources. */ static void exportResourcesCylinder(GString *data, VisuData *dataObj); enum { PROP_0, PROP_RADIUS, PROP_TYPE, N_PROPS }; static GParamSpec *_properties[N_PROPS]; /* Boxed interface. */ G_DEFINE_INTERFACE(VisuPairCylinder, visu_pair_cylinder, G_TYPE_OBJECT) static void visu_pair_cylinder_default_init(VisuPairCylinderInterface *iface) { VisuConfigFileEntry *resourceEntry, *oldEntry; gfloat rgRadius[2] = {VISU_PAIR_CYLINDER_RADIUS_MIN, VISU_PAIR_CYLINDER_RADIUS_MAX}; int rgType[2] = {VISU_CYLINDER_COLOR_USER, VISU_CYLINDER_COLOR_ELEMENT}; /** * VisuPairCylinder::radius: * * The cylinder radius. * * Since: 3.8 */ _properties[PROP_RADIUS] = g_param_spec_float("radius", "Radius", "cylinder radius", VISU_PAIR_CYLINDER_RADIUS_MIN, VISU_PAIR_CYLINDER_RADIUS_MAX, _RADIUS_DEFAULT, G_PARAM_READWRITE); g_object_interface_install_property(iface, _properties[PROP_RADIUS]); /** * VisuPairCylinder::color-type: * * The cylinder color type. * * Since: 3.8 */ _properties[PROP_TYPE] = g_param_spec_uint("color-type", "Color type", "cylinder color type", 0, VISU_CYLINDER_N_COLOR - 1, _COLOR_TYPE_DEFAULT, G_PARAM_READWRITE); g_object_interface_install_property(iface, _properties[PROP_TYPE]); resourceEntry = visu_config_file_addIntegerArrayEntry(VISU_CONFIG_FILE_RESOURCE, FLAG_RESOURCES_CYLINDER_COLOR_TYPE, DESC_RESOURCES_CYLINDER_COLOR_TYPE, 1, &cylinderColorType, rgType, FALSE); resourceEntry = visu_config_file_addIntegerArrayEntry(VISU_CONFIG_FILE_RESOURCE, FLAG_RESOURCES_LINK_COLOR_TYPE, DESC_RESOURCES_LINK_COLOR_TYPE, 1, &_linkColorType, rgType, TRUE); visu_config_file_entry_setVersion(resourceEntry, 3.8f); cylinderRadius = _RADIUS_DEFAULT; resourceEntry = visu_config_file_addFloatArrayEntry(VISU_CONFIG_FILE_RESOURCE, FLAG_RESOURCES_CYLINDER_RADIUS, DESC_RESOURCES_CYLINDER_RADIUS, 1, &cylinderRadius, rgRadius, FALSE); oldEntry = visu_config_file_addEntry(VISU_CONFIG_FILE_RESOURCE, FLAG_RESOURCES_PAIR_RADIUS, DESC_RESOURCES_PAIR_RADIUS, 1, NULL); visu_config_file_entry_setVersion(resourceEntry, 3.1f); resourceEntry = visu_config_file_addFloatArrayEntry(VISU_CONFIG_FILE_RESOURCE, FLAG_RESOURCES_LINK_RADIUS, DESC_RESOURCES_LINK_RADIUS, 1, &_linkRadius, rgRadius, TRUE); visu_config_file_entry_setVersion(resourceEntry, 3.4f); visu_config_file_entry_setReplace(resourceEntry, oldEntry); visu_config_file_addExportFunction(VISU_CONFIG_FILE_RESOURCE, exportResourcesCylinder); g_signal_connect(VISU_CONFIG_FILE_RESOURCE, "parsed::" FLAG_RESOURCES_LINK_RADIUS, G_CALLBACK(onEntryRadius), (gpointer)0); g_signal_connect(VISU_CONFIG_FILE_RESOURCE, "parsed::" FLAG_RESOURCES_LINK_COLOR_TYPE, G_CALLBACK(onEntryType), (gpointer)0); } /*****************************************/ /* Dealing with parameters and resources */ /*****************************************/ static void onEntryRadius(VisuConfigFile *obj _U_, VisuConfigFileEntry *entry, gpointer data _U_) { VisuPairLink *link; gchar *errMess; if (!visu_pair_pool_readLinkFromLabel(visu_config_file_entry_getLabel(entry), &link, &errMess)) { visu_config_file_entry_setErrorMessage(entry, errMess); g_free(errMess); return; } visu_pair_cylinder_setRadius(VISU_PAIR_CYLINDER(link), _linkRadius); } static void onEntryType(VisuConfigFile *obj _U_, VisuConfigFileEntry *entry, gpointer data _U_) { VisuPairLink *link; gchar *errMess; if (!visu_pair_pool_readLinkFromLabel(visu_config_file_entry_getLabel(entry), &link, &errMess)) { visu_config_file_entry_setErrorMessage(entry, errMess); g_free(errMess); return; } visu_pair_cylinder_setColorType(VISU_PAIR_CYLINDER(link), _linkColorType); } static void exportRadius(VisuPair *pair, VisuPairLink *data, gpointer userData) { struct _VisuConfigFileForeachFuncExport *str; VisuElement *ele1, *ele2; gchar *buf; str = ( struct _VisuConfigFileForeachFuncExport*)userData; visu_pair_getElements(pair, &ele1, &ele2); /* We export the resource only if the elements are part of the given VisuData. */ if (str->dataObj && (!visu_node_array_containsElement(VISU_NODE_ARRAY(str->dataObj), ele1) || !visu_node_array_containsElement(VISU_NODE_ARRAY(str->dataObj), ele2))) return; if (visu_pair_link_getDistance(data, VISU_DISTANCE_MIN) == 0.f && visu_pair_link_getDistance(data, VISU_DISTANCE_MAX) == 0.f) return; buf = g_strdup_printf("%s %s %4.3f %4.3f", ele1->name, ele2->name, visu_pair_link_getDistance(data, VISU_DISTANCE_MIN), visu_pair_link_getDistance(data, VISU_DISTANCE_MAX)); if (visu_pair_cylinder_getRadius(VISU_PAIR_CYLINDER(data)) != visu_pair_cylinder_getDefaultRadius()) visu_config_file_exportEntry(str->data, FLAG_RESOURCES_LINK_RADIUS, buf, "%4.3f", visu_pair_cylinder_getRadius(VISU_PAIR_CYLINDER(data))); if (visu_pair_cylinder_getColorType(VISU_PAIR_CYLINDER(data)) != visu_pair_cylinder_getDefaultColorType()) visu_config_file_exportEntry(str->data, FLAG_RESOURCES_LINK_COLOR_TYPE, buf, "%d", visu_pair_cylinder_getColorType(VISU_PAIR_CYLINDER(data))); g_free(buf); } static void exportPair(VisuPair *pair, gpointer data) { visu_pair_foreach(pair, exportRadius, data); } static void exportResourcesCylinder(GString *data, VisuData *dataObj) { struct _VisuConfigFileForeachFuncExport str; gchar *buf; buf = g_strdup_printf("%s 0 <= integer < %d", DESC_RESOURCES_CYLINDER_COLOR_TYPE, VISU_CYLINDER_N_COLOR); visu_config_file_exportComment(data, buf); g_free(buf); visu_config_file_exportEntry(data, FLAG_RESOURCES_CYLINDER_COLOR_TYPE, NULL, "%d", cylinderColorType); visu_config_file_exportComment(data, DESC_RESOURCES_CYLINDER_RADIUS); visu_config_file_exportEntry(data, FLAG_RESOURCES_CYLINDER_RADIUS, NULL, "%f", cylinderRadius); str.data = data; str.dataObj = dataObj; visu_config_file_exportComment(data, DESC_RESOURCES_PAIR_RADIUS); visu_pair_pool_foreach(exportPair, &str); visu_config_file_exportComment(data, ""); } /** * visu_pair_cylinder_setRadius: * @data: a #VisuPairCylinder object ; * @val: a float value. * * This method allows to change the radius value of a specific pair. * When a pair is rendered via a cylinder, it first checks if that pairs has * a specific radius value set by this method. If not, it uses the default value. * * Returns: TRUE if the value is changed. */ gboolean visu_pair_cylinder_setRadius(VisuPairCylinder *data, float val) { gboolean res; res = VISU_PAIR_CYLINDER_GET_INTERFACE(data)->set_radius(data, CLAMP(val, VISU_PAIR_CYLINDER_RADIUS_MIN, VISU_PAIR_CYLINDER_RADIUS_MAX)); if (res) g_object_notify_by_pspec(G_OBJECT(data), _properties[PROP_RADIUS]); return res; } /** * visu_pair_cylinder_getRadius: * @data: a #VisuPairCylinder object. * * Get the radius value for the specified pair. * * Returns: the radius value. */ gfloat visu_pair_cylinder_getRadius(VisuPairCylinder *data) { return VISU_PAIR_CYLINDER_GET_INTERFACE(data)->get_radius(data); } /** * visu_pair_cylinder_getDefaultRadius: * * Get the default value for cylinder radius. * * Returns: the default value for cylinder radius. */ float visu_pair_cylinder_getDefaultRadius() { return cylinderRadius; } /** * visu_pair_cylinder_setColorType: * @data: a #VisuPairCylinder object. * @val: a integer that identify the color scheme. * * It set the color scheme for cylinder pairs. It can be 0 or 1. * * Returns: TRUE if the calling method should take care of * #VisuGlExtPairs objects, FALSE if not. */ gboolean visu_pair_cylinder_setColorType(VisuPairCylinder *data, VisuPairCylinderColorId val) { gboolean res; res = VISU_PAIR_CYLINDER_GET_INTERFACE(data)->set_colorType(data, MIN(val, VISU_CYLINDER_N_COLOR - 1)); if (res) g_object_notify_by_pspec(G_OBJECT(data), _properties[PROP_TYPE]); return res; } /** * visu_pair_cylinder_getColorType: * @data: a #VisuPairCylinder object. * * Get the color type value for the specified pair. * * Returns: the color type value. */ VisuPairCylinderColorId visu_pair_cylinder_getColorType(VisuPairCylinder *data) { return VISU_PAIR_CYLINDER_GET_INTERFACE(data)->get_colorType(data); } /** * visu_pair_cylinder_getDefaultColorType: * * Get the color scheme. * * Returns: an integer corresponding to the color scheme (0 or 1). */ VisuPairCylinderColorId visu_pair_cylinder_getDefaultColorType() { return cylinderColorType; } v_sim-3.8.0/src/pairsModeling/iface_cylinder.h000066400000000000000000000111301370110300500213160ustar00rootroot00000000000000/* EXTRAITS DE LA LICENCE Copyright CEA, contributeurs : Damien CALISTE, laboratoire L_Sim, (2016) Adresse mèl : CALISTE, damien P caliste AT cea P fr. Ce logiciel est un programme informatique servant à visualiser des structures atomiques dans un rendu pseudo-3D. Ce logiciel est régi par la licence CeCILL soumise au droit français et respectant les principes de diffusion des logiciels libres. Vous pouvez utiliser, modifier et/ou redistribuer ce programme sous les conditions de la licence CeCILL telle que diffusée par le CEA, le CNRS et l'INRIA sur le site "http://www.cecill.info". Le fait que vous puissiez accéder à cet en-tête signifie que vous avez pris connaissance de la licence CeCILL, et que vous en avez accepté les termes (cf. le fichier Documentation/licence.fr.txt fourni avec ce logiciel). */ /* LICENCE SUM UP Copyright CEA, contributors : Damien CALISTE, laboratoire L_Sim, (2016) E-mail address: CALISTE, damien P caliste AT cea P fr. This software is a computer program whose purpose is to visualize atomic configurations in 3D. This software is governed by the CeCILL license under French law and abiding by the rules of distribution of free software. You can use, modify and/ or redistribute the software under the terms of the CeCILL license as circulated by CEA, CNRS and INRIA at the following URL "http://www.cecill.info". The fact that you are presently reading this means that you have had knowledge of the CeCILL license and that you accept its terms. You can find a copy of this licence shipped with this software at Documentation/licence.en.txt. */ #ifndef IFACE_CYLINDER_H #define IFACE_CYLINDER_H #include #include G_BEGIN_DECLS /** * VisuPairCylinderColorId: * @VISU_CYLINDER_COLOR_USER: color is chosen by the user. * @VISU_CYLINDER_COLOR_ELEMENT: color is chosen according to * the color of the #VisuElement the pair is linked to. * @VISU_CYLINDER_COLOR_NODE: color is chosen according to * the color of the #VisuNode the pair is linked to (relevant whenever * nodes are colorized). * @VISU_CYLINDER_N_COLOR: number of choices for the colourisation. * * Possible flags to colourise the cylinder pairs. */ typedef enum { VISU_CYLINDER_COLOR_USER, VISU_CYLINDER_COLOR_ELEMENT, VISU_CYLINDER_COLOR_NODE, VISU_CYLINDER_N_COLOR } VisuPairCylinderColorId; /** * VISU_PAIR_CYLINDER_RADIUS_MIN: * * Minimum value for the radius of cylinder pairs. */ #define VISU_PAIR_CYLINDER_RADIUS_MIN 0.01f /** * VISU_PAIR_CYLINDER_RADIUS_MAX: * * Maximum value for the radius of cylinder pairs. */ #define VISU_PAIR_CYLINDER_RADIUS_MAX 3.f /* Cylinder interface. */ #define VISU_TYPE_PAIR_CYLINDER (visu_pair_cylinder_get_type()) #define VISU_PAIR_CYLINDER(obj) (G_TYPE_CHECK_INSTANCE_CAST((obj), VISU_TYPE_PAIR_CYLINDER, VisuPairCylinder)) #define VISU_IS_PAIR_CYLINDER(obj) (G_TYPE_CHECK_INSTANCE_TYPE((obj), VISU_TYPE_PAIR_CYLINDER)) #define VISU_PAIR_CYLINDER_GET_INTERFACE(inst) (G_TYPE_INSTANCE_GET_INTERFACE((inst), VISU_TYPE_PAIR_CYLINDER, VisuPairCylinderInterface)) typedef struct _VisuPairCylinder VisuPairCylinder; /* dummy object */ typedef struct _VisuPairCylinderInterface VisuPairCylinderInterface; /** * VisuPairCylinder: * * Interface object. * * Since: 3.8 */ /** * VisuPairCylinderInterface: * @parent: its parent. * @set_radius: a method to change the radius of drawn cylinder * #VisuPairLink. * @get_radius: a method to get the radius. * @get_colorType: a method to get the coloring scheme. * @set_colorType: a method to change the coloring scheme. * * Interface for class that can represent #VisuPairLink as cylinders. * * Since: 3.8 */ struct _VisuPairCylinderInterface { GTypeInterface parent; gfloat (*get_radius) (VisuPairCylinder *self); gboolean (*set_radius) (VisuPairCylinder *self, gfloat val); VisuPairCylinderColorId (*get_colorType) (VisuPairCylinder *self); gboolean (*set_colorType) (VisuPairCylinder *self, VisuPairCylinderColorId val); }; GType visu_pair_cylinder_get_type (void); gfloat visu_pair_cylinder_getDefaultRadius(); VisuPairCylinderColorId visu_pair_cylinder_getDefaultColorType(); gboolean visu_pair_cylinder_setColorType(VisuPairCylinder *data, VisuPairCylinderColorId val); VisuPairCylinderColorId visu_pair_cylinder_getColorType(VisuPairCylinder *data); gboolean visu_pair_cylinder_setRadius(VisuPairCylinder *data, gfloat val); gfloat visu_pair_cylinder_getRadius(VisuPairCylinder *data); G_END_DECLS #endif v_sim-3.8.0/src/pairsModeling/iface_wire.c000066400000000000000000000360241370110300500204570ustar00rootroot00000000000000/* EXTRAITS DE LA LICENCE Copyright CEA, contributeurs : Damien CALISTE, laboratoire L_Sim, (2016) Adresse mèl : CALISTE, damien P caliste AT cea P fr. Ce logiciel est un programme informatique servant à visualiser des structures atomiques dans un rendu pseudo-3D. Ce logiciel est régi par la licence CeCILL soumise au droit français et respectant les principes de diffusion des logiciels libres. Vous pouvez utiliser, modifier et/ou redistribuer ce programme sous les conditions de la licence CeCILL telle que diffusée par le CEA, le CNRS et l'INRIA sur le site "http://www.cecill.info". Le fait que vous puissiez accéder à cet en-tête signifie que vous avez pris connaissance de la licence CeCILL, et que vous en avez accepté les termes (cf. le fichier Documentation/licence.fr.txt fourni avec ce logiciel). */ /* LICENCE SUM UP Copyright CEA, contributors : Damien CALISTE, laboratoire L_Sim, (2016) E-mail address: CALISTE, damien P caliste AT cea P fr. This software is a computer program whose purpose is to visualize atomic configurations in 3D. This software is governed by the CeCILL license under French law and abiding by the rules of distribution of free software. You can use, modify and/ or redistribute the software under the terms of the CeCILL license as circulated by CEA, CNRS and INRIA at the following URL "http://www.cecill.info". The fact that you are presently reading this means that you have had knowledge of the CeCILL license and that you accept its terms. You can find a copy of this licence shipped with this software at Documentation/licence.en.txt. */ #include "iface_wire.h" #include #include /** * SECTION:iface_wire * @short_description: An interface defining all the properties * required to draw a #VisuPair as a wire. * * #VisuPairWire interface introduces the "width" property of a * wire rendering, wether or not it should use a solid color or a * #ToolShade depending on its length... */ #define FLAG_PARAMETER_WIRE "wire_nonLinear" #define DESC_PARAMETER_WIRE "If the color of the pairs are corrected by their length ; boolean 0 or 1" #define FLAG_PARAMETER_SHADE "wire_shade" #define DESC_PARAMETER_SHADE "If positive, use a shade to colourise pairs depending on length ; -1 or a positive shade id" #define FLAG_RESOURCES_SHADE "pairWire_linkShade" #define DESC_RESOURCES_SHADE "For each given pair, if positive, use a shade to colourise pairs depending on length ; \"ele1\" \"ele2\" -1 or a positive shade id" static int _linkShade; #define FLAG_RESOURCES_PAIR_WIDTH "pairWire_pairWidth" #define DESC_RESOURCES_PAIR_WIDTH "Widths detail for each pair drawn ; \"ele1\" \"ele2\" 0 < integer < 10" #define FLAG_RESOURCES_WIRE_WIDTH "pairWire_width" #define DESC_RESOURCES_WIRE_WIDTH "This value is the width for all pairs drawn ; \"ele1\" \"ele2\" 0 < integer < 10" #define _WIDTH_MAX 10 #define _WIDTH_DEFAULT 2 static guint wireWidth = _WIDTH_DEFAULT; #define FLAG_RESOURCES_LINK_WIDTH "pairWire_linkWidth" #define DESC_RESOURCES_LINK_WIDTH "Widths detail for each drawn link ; \"ele1\" \"ele2\" 0 < integer < 10" static guint _linkWidth; #define FLAG_RESOURCES_LINK_STIPPLE "pairWire_linkStipple" #define DESC_RESOURCES_LINK_STIPPLE "Dot scheme detail for each drawn link ; \"ele1\" \"ele2\" 0 < integer < 2^16" static guint16 _linkStipple; static void onEntryShade(VisuConfigFile *obj, VisuConfigFileEntry *entry, gpointer data); static void onEntryStipple(VisuConfigFile *obj, VisuConfigFileEntry *entry, gpointer data); static void onEntryWidth(VisuConfigFile *obj, VisuConfigFileEntry *entry, gpointer data); /* This function save the resources. */ static void exportResourcesWire(GString *data, VisuData *dataObj); enum { PROP_0, PROP_WIDTH, PROP_SHADE, PROP_STIPPLE, N_PROPS }; static GParamSpec *_properties[N_PROPS]; /* Boxed interface. */ G_DEFINE_INTERFACE(VisuPairWire, visu_pair_wire, G_TYPE_OBJECT) static void visu_pair_wire_default_init(VisuPairWireInterface *iface) { VisuConfigFileEntry *resourceEntry, *oldEntry, *olderEntry; int rgWidth[2] = {0, _WIDTH_MAX}; int rgShade[2] = {-1, G_MAXINT}; /** * VisuPairWire::width: * * The wire width. * * Since: 3.8 */ _properties[PROP_WIDTH] = g_param_spec_uint("width", "Width", "wire width", 1, _WIDTH_MAX, _WIDTH_DEFAULT, G_PARAM_READWRITE); g_object_interface_install_property(iface, _properties[PROP_WIDTH]); /** * VisuPairWire::shade: * * If set, the wire is coloured with a shade depending on its length. * * Since: 3.8 */ _properties[PROP_SHADE] = g_param_spec_boxed("shade", "Shade", "wire shade", TOOL_TYPE_SHADE, G_PARAM_READWRITE); g_object_interface_install_property(iface, _properties[PROP_SHADE]); /** * VisuPairWire::stipple: * * The wire stipple. * * Since: 3.8 */ _properties[PROP_STIPPLE] = g_param_spec_uint("stipple", "Stipple", "wire stipple", 1, 65535, 65535, G_PARAM_READWRITE); g_object_interface_install_property(iface, _properties[PROP_STIPPLE]); resourceEntry = visu_config_file_addIntegerArrayEntry(VISU_CONFIG_FILE_RESOURCE, FLAG_RESOURCES_WIRE_WIDTH, DESC_RESOURCES_WIRE_WIDTH, 1, (int*)&wireWidth, rgWidth, FALSE); oldEntry = visu_config_file_addEntry(VISU_CONFIG_FILE_RESOURCE, FLAG_RESOURCES_PAIR_WIDTH, DESC_RESOURCES_PAIR_WIDTH, 1, NULL); visu_config_file_entry_setVersion(resourceEntry, 3.1f); resourceEntry = visu_config_file_addIntegerArrayEntry(VISU_CONFIG_FILE_RESOURCE, FLAG_RESOURCES_LINK_WIDTH, DESC_RESOURCES_LINK_WIDTH, 1, (int*)&_linkWidth, rgWidth, TRUE); visu_config_file_entry_setVersion(resourceEntry, 3.4f); visu_config_file_entry_setReplace(resourceEntry, oldEntry); g_signal_connect(VISU_CONFIG_FILE_RESOURCE, "parsed::" FLAG_RESOURCES_LINK_WIDTH, G_CALLBACK(onEntryWidth), (gpointer)0); resourceEntry = visu_config_file_addStippleArrayEntry(VISU_CONFIG_FILE_RESOURCE, FLAG_RESOURCES_LINK_STIPPLE, DESC_RESOURCES_LINK_STIPPLE, 1, &_linkStipple); visu_config_file_entry_setVersion(resourceEntry, 3.4f); g_signal_connect(VISU_CONFIG_FILE_RESOURCE, "parsed::" FLAG_RESOURCES_LINK_STIPPLE, G_CALLBACK(onEntryStipple), (gpointer)0); visu_config_file_addExportFunction(VISU_CONFIG_FILE_RESOURCE, exportResourcesWire); olderEntry = visu_config_file_addEntry(VISU_CONFIG_FILE_PARAMETER, FLAG_PARAMETER_WIRE, DESC_PARAMETER_WIRE, 1, NULL); oldEntry = visu_config_file_addEntry(VISU_CONFIG_FILE_PARAMETER, FLAG_PARAMETER_SHADE, DESC_PARAMETER_SHADE, 1, NULL); visu_config_file_entry_setVersion(oldEntry, 3.6f); visu_config_file_entry_setReplace(oldEntry, olderEntry); resourceEntry = visu_config_file_addIntegerArrayEntry(VISU_CONFIG_FILE_RESOURCE, FLAG_RESOURCES_SHADE, DESC_RESOURCES_SHADE, 1, &_linkShade, rgShade, TRUE); visu_config_file_entry_setVersion(resourceEntry, 3.7f); visu_config_file_entry_setReplace(resourceEntry, oldEntry); g_signal_connect(VISU_CONFIG_FILE_RESOURCE, "parsed::" FLAG_RESOURCES_SHADE, G_CALLBACK(onEntryShade), (gpointer)0); } /*****************************************/ /* Dealing with parameters and resources */ /*****************************************/ static void onEntryShade(VisuConfigFile *obj _U_, VisuConfigFileEntry *entry, gpointer data _U_) { VisuPairLink *link; gchar *errMess; GList *list; if (!visu_pair_pool_readLinkFromLabel(visu_config_file_entry_getLabel(entry), &link, &errMess)) { visu_config_file_entry_setErrorMessage(entry, errMess); g_free(errMess); return; } list = tool_pool_asList(tool_shade_getStorage()); if (_linkShade >= (int)g_list_length(list)) { visu_config_file_entry_setErrorMessage(entry, _("shade id must be in [%d;%d]"), 0, g_list_length(list) - 1); return; } else visu_pair_wire_setShade(VISU_PAIR_WIRE(link), (ToolShade*)g_list_nth_data(list, _linkShade)); } static void onEntryStipple(VisuConfigFile *obj _U_, VisuConfigFileEntry *entry, gpointer data _U_) { VisuPairLink *link; gchar *errMess; if (!visu_pair_pool_readLinkFromLabel(visu_config_file_entry_getLabel(entry), &link, &errMess)) { visu_config_file_entry_setErrorMessage(entry, errMess); g_free(errMess); return; } visu_pair_wire_setStipple(VISU_PAIR_WIRE(link), _linkStipple); } static void onEntryWidth(VisuConfigFile *obj _U_, VisuConfigFileEntry *entry, gpointer data _U_) { VisuPairLink *link; gchar *errMess; if (!visu_pair_pool_readLinkFromLabel(visu_config_file_entry_getLabel(entry), &link, &errMess)) { visu_config_file_entry_setErrorMessage(entry, errMess); g_free(errMess); return; } visu_pair_wire_setWidth(VISU_PAIR_WIRE(link), _linkWidth); } static void exportWidth(VisuPair *pair, VisuPairLink *data, gpointer userData) { struct _VisuConfigFileForeachFuncExport *str; VisuElement *ele1, *ele2; guint16 stipple; ToolShade *shade; gchar *buf; str = ( struct _VisuConfigFileForeachFuncExport*)userData; visu_pair_getElements(pair, &ele1, &ele2); if (str->dataObj && (!visu_node_array_containsElement(VISU_NODE_ARRAY(str->dataObj), ele1) || !visu_node_array_containsElement(VISU_NODE_ARRAY(str->dataObj), ele2))) return; if (visu_pair_link_getDistance(data, VISU_DISTANCE_MIN) == 0.f && visu_pair_link_getDistance(data, VISU_DISTANCE_MAX) == 0.f) return; buf = g_strdup_printf("%s %s %4.3f %4.3f", ele1->name, ele2->name, visu_pair_link_getDistance(data, VISU_DISTANCE_MIN), visu_pair_link_getDistance(data, VISU_DISTANCE_MAX)); if (visu_pair_wire_getWidth(VISU_PAIR_WIRE(data)) != visu_pair_wire_getDefaultWidth()) visu_config_file_exportEntry(str->data, FLAG_RESOURCES_LINK_WIDTH, buf, "%d", visu_pair_wire_getWidth(VISU_PAIR_WIRE(data))); stipple = visu_pair_wire_getStipple(VISU_PAIR_WIRE(data)); if (stipple != 65535) visu_config_file_exportEntry(str->data, FLAG_RESOURCES_LINK_STIPPLE, buf, "%d", stipple); shade = visu_pair_wire_getShade(VISU_PAIR_WIRE(data)); if (shade) visu_config_file_exportEntry(str->data, FLAG_RESOURCES_LINK_STIPPLE, buf, "%d", tool_pool_index(tool_shade_getStorage(), shade)); g_free(buf); } static void exportPair(VisuPair *pair, gpointer data) { visu_pair_foreach(pair, exportWidth, data); } static void exportResourcesWire(GString *data, VisuData *dataObj) { struct _VisuConfigFileForeachFuncExport str; visu_config_file_exportComment(data, DESC_RESOURCES_WIRE_WIDTH); visu_config_file_exportEntry(data, FLAG_RESOURCES_WIRE_WIDTH, NULL, "%d", wireWidth); str.data = data; str.dataObj = dataObj; visu_config_file_exportComment(data, DESC_RESOURCES_LINK_WIDTH); visu_config_file_exportComment(data, DESC_RESOURCES_LINK_STIPPLE); visu_config_file_exportComment(data, DESC_RESOURCES_SHADE); visu_pair_pool_foreach(exportPair, &str); visu_config_file_exportComment(data, ""); } /** * visu_pair_wire_setStipple: * @data: a #VisuPairWire object ; * @stipple: a pattern. * * Change the line pattern of @data. * * Returns: TRUE if the value is different from previous. */ gboolean visu_pair_wire_setStipple(VisuPairWire *data, guint16 stipple) { gboolean res; res = VISU_PAIR_WIRE_GET_INTERFACE(data)->set_stipple(data, stipple); if (res) g_object_notify_by_pspec(G_OBJECT(data), _properties[PROP_STIPPLE]); return res; } /** * visu_pair_wire_getStipple: * @data: a #VisuPairWire object. * * Get the line pattern of @data. * * Returns: a line pattern (default is 65535). */ guint16 visu_pair_wire_getStipple(VisuPairWire *data) { return VISU_PAIR_WIRE_GET_INTERFACE(data)->get_stipple(data); } /** * visu_pair_wire_setWidth: * @data: a #VisuPairWire object ; * @val: a positive integer. * * This method allows to change the width of line for a specific pair. * When a pair is rendered via with a line, it first checks if that pairs has * a specific width value set by this method. If not, it uses the default value. * * Returns: TRUE if the value is different from previous. */ gboolean visu_pair_wire_setWidth(VisuPairWire *data, guint val) { gboolean res; res = VISU_PAIR_WIRE_GET_INTERFACE(data)->set_width(data, MIN(_WIDTH_MAX, val)); if (res) g_object_notify_by_pspec(G_OBJECT(data), _properties[PROP_WIDTH]); return res; } /** * visu_pair_wire_getWidth: * @data: a #VisuPairWire object. * * Get the width of the given pair @data. If the given pair has no * specific width, the defaul value is returned. * * Returns: the width of the given pair. */ guint visu_pair_wire_getWidth(VisuPairWire *data) { return VISU_PAIR_WIRE_GET_INTERFACE(data)->get_width(data); } /** * visu_pair_wire_setShade: * @data: a #VisuPairWire object. * @shade: (allow-none): a #ToolShade object (can be NULL). * * If @shade is not NULL, make the colour of each pair varies with its * length according to @shade colour scheme. * * Since: 3.6 * * Returns: TRUE if shade is changed. */ gboolean visu_pair_wire_setShade(VisuPairWire *data, ToolShade *shade) { gboolean res; res = VISU_PAIR_WIRE_GET_INTERFACE(data)->set_shade(data, shade); if (res) g_object_notify_by_pspec(G_OBJECT(data), _properties[PROP_SHADE]); return res; } /** * visu_pair_wire_getShade: * @data: a #VisuPairWire object. * * Colour of wires can depend on length, following a #ToolShade scheme. * * Since: 3.6 * * Returns: (transfer none): the #ToolShade scheme if used, or NULL. */ ToolShade* visu_pair_wire_getShade(VisuPairWire *data) { return VISU_PAIR_WIRE_GET_INTERFACE(data)->get_shade(data); } /** * visu_pair_wire_getDefaultWidth: * * Retrieves the default width. * * Since: 3.8 * * Returns: the default width. **/ guint visu_pair_wire_getDefaultWidth() { return wireWidth; } /** * visu_pair_wire_getDefaultStipple: * * Retrieves the default stipple pattern. * * Since: 3.8 * * Returns: the default stipple pattern. **/ guint16 visu_pair_wire_getDefaultStipple() { return 65535; } v_sim-3.8.0/src/pairsModeling/iface_wire.h000066400000000000000000000075011370110300500204620ustar00rootroot00000000000000/* EXTRAITS DE LA LICENCE Copyright CEA, contributeurs : Damien CALISTE, laboratoire L_Sim, (2016) Adresse mèl : CALISTE, damien P caliste AT cea P fr. Ce logiciel est un programme informatique servant à visualiser des structures atomiques dans un rendu pseudo-3D. Ce logiciel est régi par la licence CeCILL soumise au droit français et respectant les principes de diffusion des logiciels libres. Vous pouvez utiliser, modifier et/ou redistribuer ce programme sous les conditions de la licence CeCILL telle que diffusée par le CEA, le CNRS et l'INRIA sur le site "http://www.cecill.info". Le fait que vous puissiez accéder à cet en-tête signifie que vous avez pris connaissance de la licence CeCILL, et que vous en avez accepté les termes (cf. le fichier Documentation/licence.fr.txt fourni avec ce logiciel). */ /* LICENCE SUM UP Copyright CEA, contributors : Damien CALISTE, laboratoire L_Sim, (2016) E-mail address: CALISTE, damien P caliste AT cea P fr. This software is a computer program whose purpose is to visualize atomic configurations in 3D. This software is governed by the CeCILL license under French law and abiding by the rules of distribution of free software. You can use, modify and/ or redistribute the software under the terms of the CeCILL license as circulated by CEA, CNRS and INRIA at the following URL "http://www.cecill.info". The fact that you are presently reading this means that you have had knowledge of the CeCILL license and that you accept its terms. You can find a copy of this licence shipped with this software at Documentation/licence.en.txt. */ #ifndef IFACE_WIRE_H #define IFACE_WIRE_H #include #include #include G_BEGIN_DECLS /* Boxed interface. */ #define VISU_TYPE_PAIR_WIRE (visu_pair_wire_get_type()) #define VISU_PAIR_WIRE(obj) (G_TYPE_CHECK_INSTANCE_CAST((obj), VISU_TYPE_PAIR_WIRE, VisuPairWire)) #define VISU_IS_PAIR_WIRE(obj) (G_TYPE_CHECK_INSTANCE_TYPE((obj), VISU_TYPE_PAIR_WIRE)) #define VISU_PAIR_WIRE_GET_INTERFACE(inst) (G_TYPE_INSTANCE_GET_INTERFACE((inst), VISU_TYPE_PAIR_WIRE, VisuPairWireInterface)) typedef struct _VisuPairWire VisuPairWire; /* dummy object */ typedef struct _VisuPairWireInterface VisuPairWireInterface; /** * VisuPairWire: * * Interface object. * * Since: 3.8 */ /** * VisuPairWireInterface: * @parent: its parent. * @set_width: a method to change the width of drawn wire * #VisuPairLink. * @get_width: a method to get the width. * @set_stipple: a method to change the stipple scheme of drawn wire * #VisuPairLink. * @get_stipple: a method to get the stipple scheme. * @set_shade: a method to set if the wire should be coloured * according to its length. * @get_shade: a method to get the shading colourisation of a wire. * * Interface for class that can represent #VisuPairLink as flat wires. * * Since: 3.8 */ struct _VisuPairWireInterface { GTypeInterface parent; guint (*get_width) (VisuPairWire *self); gboolean (*set_width) (VisuPairWire *self, guint val); ToolShade* (*get_shade) (VisuPairWire *self); gboolean (*set_shade) (VisuPairWire *self, ToolShade *val); guint16 (*get_stipple) (VisuPairWire *self); gboolean (*set_stipple) (VisuPairWire *self, guint16 val); }; GType visu_pair_wire_get_type (void); guint visu_pair_wire_getDefaultWidth(); guint16 visu_pair_wire_getDefaultStipple(); gboolean visu_pair_wire_setWidth(VisuPairWire *data, guint val); guint visu_pair_wire_getWidth(VisuPairWire *data); gboolean visu_pair_wire_setShade(VisuPairWire *data, ToolShade *shade); ToolShade* visu_pair_wire_getShade(VisuPairWire *data); gboolean visu_pair_wire_setStipple(VisuPairWire *data, guint16 stipple); guint16 visu_pair_wire_getStipple(VisuPairWire *data); G_END_DECLS #endif v_sim-3.8.0/src/pairsModeling/link.c000066400000000000000000001004071370110300500173140ustar00rootroot00000000000000/* EXTRAITS DE LA LICENCE Copyright CEA, contributeurs : Damien CALISTE, laboratoire L_Sim, (2016) Adresse mèl : BILLARD, non joignable par mèl ; CALISTE, damien P caliste AT cea P fr. Ce logiciel est un programme informatique servant à visualiser des structures atomiques dans un rendu pseudo-3D. Ce logiciel est régi par la licence CeCILL soumise au droit français et respectant les principes de diffusion des logiciels libres. Vous pouvez utiliser, modifier et/ou redistribuer ce programme sous les conditions de la licence CeCILL telle que diffusée par le CEA, le CNRS et l'INRIA sur le site "http://www.cecill.info". Le fait que vous puissiez accéder à cet en-tête signifie que vous avez pris connaissance de la licence CeCILL, et que vous en avez accepté les termes (cf. le fichier Documentation/licence.fr.txt fourni avec ce logiciel). */ /* LICENCE SUM UP Copyright CEA, contributors : Damien CALISTE, laboratoire L_Sim, (2016) E-mail address: BILLARD, not reachable any more ; CALISTE, damien P caliste AT cea P fr. This software is a computer program whose purpose is to visualize atomic configurations in 3D. This software is governed by the CeCILL license under French law and abiding by the rules of distribution of free software. You can use, modify and/ or redistribute the software under the terms of the CeCILL license as circulated by CEA, CNRS and INRIA at the following URL "http://www.cecill.info". The fact that you are presently reading this means that you have had knowledge of the CeCILL license and that you accept its terms. You can find a copy of this licence shipped with this software at Documentation/licence.en.txt. */ #include "link.h" #include "iface_wire.h" #include "iface_cylinder.h" #include #include /** * SECTION:link * @short_description: An object to store rendering properties of a * #VisuPair for a given distance criterion. * * #VisuPair describes pairs between two #VisuElement. Such a * pair can have several #VisuPairLink, depending on a distance * criterion. Each link then has several rendering parameters, such as * its color, its rendering method (wire or cylinder), if it is drawn... */ /* Parameters */ static ToolColor *defaultPairColor = NULL; /* static void exportConfig(GString *data, VisuData *dataObj); */ struct _VisuPairLinkPrivate { gboolean dispose_has_run; GWeakRef ele1; GWeakRef ele2; float minMax[2]; ToolUnits units; gboolean drawn; gboolean printLength; ToolColor color; guint width; ToolShade *shade; guint16 stipple; gfloat radius; VisuPairCylinderColorId colorType; }; static void visu_pair_link_dispose(GObject* obj); static void visu_pair_link_get_property(GObject* obj, guint property_id, GValue *value, GParamSpec *pspec); static void visu_pair_link_set_property(GObject* obj, guint property_id, const GValue *value, GParamSpec *pspec); static void visu_pair_wire_interface_init(VisuPairWireInterface *iface); static void visu_pair_cylinder_interface_init(VisuPairCylinderInterface *iface); static gboolean _setWidth(VisuPairWire *data, guint val); static guint _getWidth(VisuPairWire *data); static gboolean _setShade(VisuPairWire *data, ToolShade *shade); static ToolShade* _getShade(VisuPairWire *data); static gboolean _setStipple(VisuPairWire *data, guint16 stipple); static guint16 _getStipple(VisuPairWire *data); static gboolean _setRadius(VisuPairCylinder *data, gfloat val); static gfloat _getRadius(VisuPairCylinder *data); static gboolean _setColorType(VisuPairCylinder *data, VisuPairCylinderColorId val); static VisuPairCylinderColorId _getColorType(VisuPairCylinder *data); static void onEntryUnit(VisuPairLink *link, VisuConfigFileEntry *entry, VisuConfigFile *obj); /* enum { */ /* LAST_SIGNAL */ /* }; */ /* static guint _signals[LAST_SIGNAL] = { 0 }; */ enum { PROP_0, MIN_PROP, MAX_PROP, UNITS_PROP, USE_PROP, LENGTH_PROP, COLOR_PROP, WIDTH_PROP, SHADE_PROP, STIPPLE_PROP, RADIUS_PROP, TYPE_PROP, N_PROP }; static GParamSpec *_properties[N_PROP]; G_DEFINE_TYPE_WITH_CODE(VisuPairLink, visu_pair_link, VISU_TYPE_OBJECT, G_ADD_PRIVATE(VisuPairLink) G_IMPLEMENT_INTERFACE(VISU_TYPE_PAIR_WIRE, visu_pair_wire_interface_init) G_IMPLEMENT_INTERFACE(VISU_TYPE_PAIR_CYLINDER, visu_pair_cylinder_interface_init)) static void visu_pair_link_class_init(VisuPairLinkClass *klass) { float rgbOfPairs[4] = {1.0, 0.6, 0.2, 1.}; /* VisuConfigFileEntry *entry; */ DBG_fprintf(stderr, "Visu Pair Link: creating the class of the object.\n"); DBG_fprintf(stderr, " - adding new signals ;\n"); /* Connect the overloading methods. */ G_OBJECT_CLASS(klass)->dispose = visu_pair_link_dispose; G_OBJECT_CLASS(klass)->set_property = visu_pair_link_set_property; G_OBJECT_CLASS(klass)->get_property = visu_pair_link_get_property; /** * VisuPairLink::min: * * Store the link minimal distance. * * Since: 3.8 */ _properties[MIN_PROP] = g_param_spec_float("min", "Min", "minimal distance", 0.f, G_MAXFLOAT, 0.f, G_PARAM_READWRITE); g_object_class_install_property(G_OBJECT_CLASS(klass), MIN_PROP, _properties[MIN_PROP]); /** * VisuPairLink::max: * * Store the link maximal distance. * * Since: 3.8 */ _properties[MAX_PROP] = g_param_spec_float("max", "Max", "maximal distance", 0.f, G_MAXFLOAT, 0.f, G_PARAM_READWRITE); g_object_class_install_property(G_OBJECT_CLASS(klass), MAX_PROP, _properties[MAX_PROP]); /** * VisuPairLink::units: * * The units of the length dimensions. * * Since: 3.8 */ _properties[UNITS_PROP] = g_param_spec_uint("units", "Units", "Units of dimensions", TOOL_UNITS_UNDEFINED, TOOL_UNITS_N_VALUES - 1, TOOL_UNITS_UNDEFINED, G_PARAM_READWRITE); g_object_class_install_property(G_OBJECT_CLASS(klass), UNITS_PROP, _properties[UNITS_PROP]); /** * VisuPairLink::drawn: * * If the link should be drawn or not. * * Since: 3.8 */ _properties[USE_PROP] = g_param_spec_boolean("drawn", "Drawn", "link is displayed or not", TRUE, G_PARAM_READWRITE); g_object_class_install_property(G_OBJECT_CLASS(klass), USE_PROP, _properties[USE_PROP]); /** * VisuPairLink::display-length: * * If the link should display its length or not. * * Since: 3.8 */ _properties[LENGTH_PROP] = g_param_spec_boolean("display-length", "Display length", "link displays its length or not", FALSE, G_PARAM_READWRITE); g_object_class_install_property(G_OBJECT_CLASS(klass), LENGTH_PROP, _properties[LENGTH_PROP]); /** * VisuPairLink::color: * * Store the color of the link. * * Since: 3.8 */ _properties[COLOR_PROP] = g_param_spec_boxed("color", "color", "rendering color", TOOL_TYPE_COLOR, G_PARAM_READWRITE); g_object_class_install_property(G_OBJECT_CLASS(klass), COLOR_PROP, _properties[COLOR_PROP]); g_object_class_override_property(G_OBJECT_CLASS(klass), WIDTH_PROP, "width"); g_object_class_override_property(G_OBJECT_CLASS(klass), STIPPLE_PROP, "stipple"); g_object_class_override_property(G_OBJECT_CLASS(klass), SHADE_PROP, "shade"); g_object_class_override_property(G_OBJECT_CLASS(klass), RADIUS_PROP, "radius"); g_object_class_override_property(G_OBJECT_CLASS(klass), TYPE_PROP, "color-type"); /* entry = visu_config_file_addEnumEntry(VISU_CONFIG_FILE_RESOURCE, */ /* FLAG_PAIRS_UNIT, DESC_PAIRS_UNIT, */ /* &defaultUnits, _toUnit, FALSE); */ /* visu_config_file_entry_setVersion(entry, 3.8f); */ /* visu_config_file_addExportFunction(VISU_CONFIG_FILE_RESOURCE, */ /* exportConfig); */ defaultPairColor = tool_color_addFloatRGBA(rgbOfPairs, NULL); } static void visu_pair_wire_interface_init(VisuPairWireInterface *iface) { iface->set_width = _setWidth; iface->get_width = _getWidth; iface->set_stipple = _setStipple; iface->get_stipple = _getStipple; iface->set_shade = _setShade; iface->get_shade = _getShade; } static void visu_pair_cylinder_interface_init(VisuPairCylinderInterface *iface) { iface->set_radius = _setRadius; iface->get_radius = _getRadius; iface->set_colorType = _setColorType; iface->get_colorType = _getColorType; } static void visu_pair_link_init(VisuPairLink *obj) { DBG_fprintf(stderr, "Visu Pair Link: initializing a new object (%p).\n", (gpointer)obj); obj->priv = visu_pair_link_get_instance_private(obj); obj->priv->dispose_has_run = FALSE; /* Private data. */ g_weak_ref_init(&obj->priv->ele1, (gpointer)0); g_weak_ref_init(&obj->priv->ele2, (gpointer)0); obj->priv->units = visu_basic_getPreferedUnit(); obj->priv->minMax[VISU_DISTANCE_MIN] = G_MAXFLOAT; obj->priv->minMax[VISU_DISTANCE_MAX] = G_MAXFLOAT; obj->priv->drawn = TRUE; obj->priv->printLength = FALSE; tool_color_copy(&obj->priv->color, defaultPairColor); obj->priv->width = G_MAXUINT; obj->priv->stipple = G_MAXUINT16; obj->priv->shade = (ToolShade*)0; obj->priv->radius = G_MAXFLOAT; obj->priv->colorType = VISU_CYLINDER_N_COLOR; g_signal_connect_object(VISU_CONFIG_FILE_RESOURCE, "parsed::main_unit", G_CALLBACK(onEntryUnit), (gpointer)obj, G_CONNECT_SWAPPED); } static void visu_pair_link_dispose(GObject* obj) { VisuPairLink *data; DBG_fprintf(stderr, "Visu Pair Link: dispose object %p.\n", (gpointer)obj); data = VISU_PAIR_LINK(obj); if (data->priv->dispose_has_run) return; data->priv->dispose_has_run = TRUE; g_weak_ref_clear(&data->priv->ele1); g_weak_ref_clear(&data->priv->ele2); /* Chain up to the parent class */ G_OBJECT_CLASS(visu_pair_link_parent_class)->dispose(obj); } static void visu_pair_link_get_property(GObject* obj, guint property_id, GValue *value, GParamSpec *pspec) { VisuPairLink *self = VISU_PAIR_LINK(obj); DBG_fprintf(stderr, "Visu Pair Link: get property '%s' -> ", g_param_spec_get_name(pspec)); switch (property_id) { case COLOR_PROP: g_value_set_boxed(value, &self->priv->color); DBG_fprintf(stderr, "%gx%gx%g.\n", self->priv->color.rgba[0], self->priv->color.rgba[1], self->priv->color.rgba[2]); break; case MIN_PROP: g_value_set_float(value, self->priv->minMax[0]); DBG_fprintf(stderr, "%g.\n", self->priv->minMax[0]); break; case MAX_PROP: g_value_set_float(value, self->priv->minMax[1]); DBG_fprintf(stderr, "%g.\n", self->priv->minMax[1]); break; case UNITS_PROP: g_value_set_uint(value, self->priv->units); DBG_fprintf(stderr, "%d.\n", self->priv->units); break; case USE_PROP: g_value_set_boolean(value, self->priv->drawn); DBG_fprintf(stderr, "%d.\n", self->priv->drawn); break; case LENGTH_PROP: g_value_set_boolean(value, self->priv->printLength); DBG_fprintf(stderr, "%d.\n", self->priv->printLength); break; case WIDTH_PROP: g_value_set_uint(value, _getWidth(VISU_PAIR_WIRE(obj))); DBG_fprintf(stderr, "%d.\n", g_value_get_uint(value)); break; case STIPPLE_PROP: g_value_set_uint(value, _getStipple(VISU_PAIR_WIRE(obj))); DBG_fprintf(stderr, "%d.\n", g_value_get_uint(value)); break; case SHADE_PROP: g_value_set_boxed(value, self->priv->shade); DBG_fprintf(stderr, "%p.\n", (gpointer)self->priv->shade); break; case RADIUS_PROP: g_value_set_float(value, _getRadius(VISU_PAIR_CYLINDER(obj))); DBG_fprintf(stderr, "%g.\n", self->priv->radius); break; case TYPE_PROP: g_value_set_uint(value, _getColorType(VISU_PAIR_CYLINDER(obj))); DBG_fprintf(stderr, "%d.\n", g_value_get_uint(value)); break; default: /* We don't have any other property... */ G_OBJECT_WARN_INVALID_PROPERTY_ID(obj, property_id, pspec); break; } } static void visu_pair_link_set_property(GObject* obj, guint property_id, const GValue *value, GParamSpec *pspec) { VisuPairLink *self = VISU_PAIR_LINK(obj); DBG_fprintf(stderr, "Visu Pair Link: set property '%s' -> ", g_param_spec_get_name(pspec)); switch (property_id) { case COLOR_PROP: visu_pair_link_setColor(self, g_value_get_boxed(value)); DBG_fprintf(stderr, "%gx%gx%g.\n", self->priv->color.rgba[0], self->priv->color.rgba[1], self->priv->color.rgba[2]); break; case MIN_PROP: visu_pair_link_setDistance(self, g_value_get_float(value), VISU_DISTANCE_MIN); DBG_fprintf(stderr, "%g.\n", self->priv->minMax[0]); break; case MAX_PROP: visu_pair_link_setDistance(self, g_value_get_float(value), VISU_DISTANCE_MAX); DBG_fprintf(stderr, "%g.\n", self->priv->minMax[1]); break; case UNITS_PROP: DBG_fprintf(stderr, "%d.\n", g_value_get_uint(value)); visu_pair_link_setUnits(self, g_value_get_uint(value)); break; case USE_PROP: visu_pair_link_setDrawn(self, g_value_get_boolean(value)); DBG_fprintf(stderr, "%d.\n", self->priv->drawn); break; case LENGTH_PROP: visu_pair_link_setPrintLength(self, g_value_get_boolean(value)); DBG_fprintf(stderr, "%d.\n", self->priv->printLength); break; case WIDTH_PROP: DBG_fprintf(stderr, "%d.\n", g_value_get_uint(value)); visu_pair_wire_setWidth(VISU_PAIR_WIRE(obj), g_value_get_uint(value)); break; case STIPPLE_PROP: DBG_fprintf(stderr, "%d.\n", g_value_get_uint(value)); visu_pair_wire_setStipple(VISU_PAIR_WIRE(obj), (guint16)g_value_get_uint(value)); break; case SHADE_PROP: DBG_fprintf(stderr, "%p.\n", (gpointer)g_value_get_boxed(value)); visu_pair_wire_setShade(VISU_PAIR_WIRE(obj), (ToolShade*)g_value_dup_boxed(value)); break; case RADIUS_PROP: DBG_fprintf(stderr, "%g.\n", g_value_get_float(value)); visu_pair_cylinder_setRadius(VISU_PAIR_CYLINDER(obj), g_value_get_float(value)); break; case TYPE_PROP: DBG_fprintf(stderr, "%d.\n", g_value_get_uint(value)); visu_pair_cylinder_setColorType(VISU_PAIR_CYLINDER(obj), g_value_get_uint(value)); break; default: /* We don't have any other property... */ G_OBJECT_WARN_INVALID_PROPERTY_ID(obj, property_id, pspec); break; } } /** * visu_pair_link_new: * @ele1: a #VisuElement object ; * @ele2: a #VisuElement object ; * @minMax: (array fixed-size=2): the two min and max distances. * * A link between two elements is characterized by its boundary distances. * * Returns: (transfer none): the #VisuPairLink object associated to the given two * elements and distances. If none exists it is created. The * returned value should not be freed. */ VisuPairLink* visu_pair_link_new(VisuElement *ele1, VisuElement *ele2, const float minMax[2]) { VisuPairLink *data; data = VISU_PAIR_LINK(g_object_new(VISU_TYPE_PAIR_LINK, NULL)); data->priv->minMax[VISU_DISTANCE_MIN] = minMax[0]; data->priv->minMax[VISU_DISTANCE_MAX] = minMax[1]; g_weak_ref_set(&data->priv->ele1, ele1); g_weak_ref_set(&data->priv->ele2, ele2); DBG_fprintf(stderr, " | new %p %s-%s (%g %g).\n", (gpointer)data, ele1->name, ele2->name, data->priv->minMax[0], data->priv->minMax[1]); return data; } /** * visu_pair_link_getFirstElement: * @data: a #VisuPairLink object. * * Retrieve one of the #VisuElement @data is linking. * * Since: 3.8 * * Returns: (transfer full): a #VisuElement the link is linking. **/ VisuElement* visu_pair_link_getFirstElement(VisuPairLink *data) { g_return_val_if_fail(VISU_IS_PAIR_LINK(data), (VisuElement*)0); return g_weak_ref_get(&data->priv->ele1); } /** * visu_pair_link_getSecondElement: * @data: a #VisuPairLink object. * * Retrieve one of the #VisuElement @data is linking. * * Since: 3.8 * * Returns: (transfer full): a #VisuElement the link is linking. **/ VisuElement* visu_pair_link_getSecondElement(VisuPairLink *data) { g_return_val_if_fail(VISU_IS_PAIR_LINK(data), (VisuElement*)0); return g_weak_ref_get(&data->priv->ele2); } /** * visu_pair_link_setDrawn: * @data: a #VisuPairLink object ; * @drawn: a boolean. * * A pair can or cannot be drawn, use this method to tune it. * * Returns: TRUE if parameter has been changed. */ gboolean visu_pair_link_setDrawn(VisuPairLink *data, gboolean drawn) { g_return_val_if_fail(VISU_IS_PAIR_LINK(data), FALSE); DBG_fprintf(stderr, "Visu Pairs: set drawn status %d (%d) for %p.\n", (int)drawn, (int)data->priv->drawn, (gpointer)data); if (data->priv->drawn == drawn) return FALSE; data->priv->drawn = drawn; g_object_notify_by_pspec(G_OBJECT(data), _properties[USE_PROP]); return TRUE; } /** * visu_pair_link_setPrintLength: * @data: a #VisuPairLink object ; * @status: TRUE to print length near pairs. * * Set the attribute that controls if the length of pairs are drawn near pairs. * * Returns: TRUE if parameter has been changed. */ gboolean visu_pair_link_setPrintLength(VisuPairLink *data, gboolean status) { g_return_val_if_fail(VISU_IS_PAIR_LINK(data), FALSE); DBG_fprintf(stderr, "Visu Pairs: set print length status %d (%d) for %p.\n", (int)status, (int)data->priv->printLength, (gpointer)data); if (data->priv->printLength == status) return FALSE; data->priv->printLength = status; g_object_notify_by_pspec(G_OBJECT(data), _properties[LENGTH_PROP]); return TRUE; } /** * visu_pair_link_getDrawn: * @data: a #VisuPairLink object ; * * A pair can or cannot be drawn, use this method to retrieve its state. * * Returns: TRUE if pairs can be drawn. */ gboolean visu_pair_link_getDrawn(const VisuPairLink *data) { g_return_val_if_fail(VISU_IS_PAIR_LINK(data), FALSE); return data->priv->drawn; } /** * visu_pair_link_setColor: * @data: a #VisuPairLink object ; * @destColor: a #ToolColor object. * * Set the color of the given pair. * * Returns: TRUE if parameter has been changed. */ gboolean visu_pair_link_setColor(VisuPairLink *data, const ToolColor* destColor) { g_return_val_if_fail(VISU_IS_PAIR_LINK(data) && destColor, FALSE); DBG_fprintf(stderr, "Visu Pairs: set color [%g;%g;%g] for %p.\n", destColor->rgba[0], destColor->rgba[1], destColor->rgba[2], (gpointer)data); if (tool_color_equal(&data->priv->color, destColor)) return FALSE; /* Copy values of dest to current color. */ tool_color_copy(&data->priv->color, destColor); g_object_notify_by_pspec(G_OBJECT(data), _properties[COLOR_PROP]); return TRUE; } /** * visu_pair_link_getColor: * @data: a #VisuPairLink object. * * Look for the properties of the pair @data to find if a colour has * been defined. If none, the default colour is returned instead. * * Returns: (transfer none): a colour (don't free it). */ ToolColor* visu_pair_link_getColor(const VisuPairLink *data) { g_return_val_if_fail(VISU_IS_PAIR_LINK(data), defaultPairColor); return &data->priv->color; } /** * visu_pair_link_setDistance: * @val: a floating point value ; * @data: a #VisuPairLink object ; * @minOrMax: #VISU_DISTANCE_MAX or #VISU_DISTANCE_MIN. * * Set the minimum or the maximum length for the given pair. * * Returns: TRUE if parameter has been changed. */ gboolean visu_pair_link_setDistance(VisuPairLink *data, float val, VisuPairLinkDistances minOrMax) { g_return_val_if_fail(VISU_IS_PAIR_LINK(data) && (minOrMax == VISU_DISTANCE_MIN || minOrMax == VISU_DISTANCE_MAX), FALSE); if (data->priv->minMax[minOrMax] == val) return FALSE; data->priv->minMax[minOrMax] = val; g_object_notify_by_pspec(G_OBJECT(data), _properties[(minOrMax) ? MAX_PROP : MIN_PROP]); return TRUE; } /** * visu_pair_link_setUnits: * @data: a #VisuPairLink object. * @units: a unit. * * Define the unit used to store the distances. * * Since: 3.8 * * Returns: TRUE if value is actually changed. **/ gboolean visu_pair_link_setUnits(VisuPairLink *data, ToolUnits units) { ToolUnits unit_; double fact; g_return_val_if_fail(VISU_IS_PAIR_LINK(data), FALSE); if (data->priv->units == units) return FALSE; unit_ = data->priv->units; data->priv->units = units; g_object_notify_by_pspec(G_OBJECT(data), _properties[UNITS_PROP]); if (unit_ == TOOL_UNITS_UNDEFINED || units == TOOL_UNITS_UNDEFINED) return TRUE; fact = (double)tool_physic_getUnitValueInMeter(unit_) / tool_physic_getUnitValueInMeter(units); data->priv->minMax[VISU_DISTANCE_MIN] *= fact; g_object_notify_by_pspec(G_OBJECT(data), _properties[MIN_PROP]); data->priv->minMax[VISU_DISTANCE_MAX] *= fact; g_object_notify_by_pspec(G_OBJECT(data), _properties[MAX_PROP]); return TRUE; } /** * visu_pair_link_getUnits: * @data: a #VisuPairLink object. * * Get the units of distance definition of @data. * * Returns: TRUE if length are printed. */ ToolUnits visu_pair_link_getUnits(const VisuPairLink *data) { g_return_val_if_fail(VISU_IS_PAIR_LINK(data), FALSE); return data->priv->units; } /** * visu_pair_link_getPrintLength: * @data: a #VisuPairLink object. * * Get the print length parameter of a pair. This parameter is used to tell if * length should be drawn near pairs of this kind. * * Returns: TRUE if length are printed. */ gboolean visu_pair_link_getPrintLength(const VisuPairLink *data) { g_return_val_if_fail(VISU_IS_PAIR_LINK(data), FALSE); return data->priv->printLength; } /** * visu_pair_link_getDistance: * @data: a #VisuPairLink object ; * @minOrMax: #VISU_DISTANCE_MIN or #VISU_DISTANCE_MAX. * * A pair between @ele1 and @ele2 is drawn only if its length is between * a minimum and a maximum value. This method can get these values. * * Returns: the minimum or the maximum value for the pair between @ele1 and @ele2. */ float visu_pair_link_getDistance(const VisuPairLink *data, VisuPairLinkDistances minOrMax) { g_return_val_if_fail(VISU_IS_PAIR_LINK(data), 0.f); g_return_val_if_fail(minOrMax == VISU_DISTANCE_MIN || minOrMax == VISU_DISTANCE_MAX, 0.); return data->priv->minMax[minOrMax]; } /** * visu_pair_link_match: * @data: a #VisuPairLink object. * @minMax: (array fixed-size=2): two floats. * * Returns if @data is a link with distance criterions defined by @minMax. * * Since: 3.8 * * Returns: %TRUE, if @data matches @minMax. **/ gboolean visu_pair_link_match(const VisuPairLink *data, const float minMax[2]) { g_return_val_if_fail(VISU_IS_PAIR_LINK(data), FALSE); DBG_fprintf(stderr, " | test %p (%g %g).\n", (gpointer)data, data->priv->minMax[0], data->priv->minMax[1]); return (data->priv->minMax[0] == minMax[0] && data->priv->minMax[1] == minMax[1]); } /** * visu_pair_link_isDrawn: * @data: a #VisuPairLink object. * * A link is used or not depending on a distance criterion and a flag, * see visu_pair_link_setDrawn() and visu_pair_link_setDistance(). * * Since: 3.7 * * Returns: TRUE if the @data is indeed drawn or not. **/ gboolean visu_pair_link_isDrawn(const VisuPairLink *data) { g_return_val_if_fail(VISU_IS_PAIR_LINK(data), FALSE); return (data->priv->drawn && data->priv->minMax[VISU_DISTANCE_MAX] > data->priv->minMax[VISU_DISTANCE_MIN] && data->priv->minMax[VISU_DISTANCE_MAX] > 0.f); } static gboolean _setWidth(VisuPairWire *data, guint val) { if (VISU_PAIR_LINK(data)->priv->width == val) return FALSE; VISU_PAIR_LINK(data)->priv->width = val; return TRUE; } static guint _getWidth(VisuPairWire *data) { return VISU_PAIR_LINK(data)->priv->width == G_MAXUINT ? visu_pair_wire_getDefaultWidth() : VISU_PAIR_LINK(data)->priv->width; } static gboolean _setShade(VisuPairWire *data, ToolShade *shade) { if (tool_shade_compare(VISU_PAIR_LINK(data)->priv->shade, shade)) return FALSE; VISU_PAIR_LINK(data)->priv->shade = shade; return TRUE; } static ToolShade* _getShade(VisuPairWire *data) { return VISU_PAIR_LINK(data)->priv->shade; } static gboolean _setStipple(VisuPairWire *data, guint16 stipple) { if (VISU_PAIR_LINK(data)->priv->stipple == stipple) return FALSE; VISU_PAIR_LINK(data)->priv->stipple = stipple; return TRUE; } static guint16 _getStipple(VisuPairWire *data) { return VISU_PAIR_LINK(data)->priv->stipple == G_MAXUINT16 ? visu_pair_wire_getDefaultStipple() : VISU_PAIR_LINK(data)->priv->stipple; } static gboolean _setRadius(VisuPairCylinder *data, gfloat val) { if (VISU_PAIR_LINK(data)->priv->radius == val) return FALSE; VISU_PAIR_LINK(data)->priv->radius = val; return TRUE; } static gfloat _getRadius(VisuPairCylinder *data) { return VISU_PAIR_LINK(data)->priv->radius == G_MAXFLOAT ? visu_pair_cylinder_getDefaultRadius() : VISU_PAIR_LINK(data)->priv->radius; } static gboolean _setColorType(VisuPairCylinder *data, VisuPairCylinderColorId val) { if (VISU_PAIR_LINK(data)->priv->colorType == val) return FALSE; VISU_PAIR_LINK(data)->priv->colorType = val; return TRUE; } static VisuPairCylinderColorId _getColorType(VisuPairCylinder *data) { return VISU_PAIR_LINK(data)->priv->colorType >= VISU_CYLINDER_N_COLOR ? visu_pair_cylinder_getDefaultColorType() : VISU_PAIR_LINK(data)->priv->colorType; } static void onEntryUnit(VisuPairLink *link, VisuConfigFileEntry *entry _U_, VisuConfigFile *obj _U_) { if (link->priv->units != TOOL_UNITS_UNDEFINED) return; visu_pair_link_setUnits(link, visu_basic_getPreferedUnit()); } /* static void exportConfig(GString *data, VisuData *dataObj _U_) */ /* { */ /* const gchar **units; */ /* if (defaultUnits != TOOL_UNITS_UNDEFINED) */ /* { */ /* units = tool_physic_getUnitNames(); */ /* visu_config_file_exportComment(data, DESC_PAIRS_UNIT); */ /* visu_config_file_exportEntry(data, FLAG_PAIRS_UNIT, NULL, */ /* "%s", units[defaultUnits]); */ /* visu_config_file_exportComment(data, ""); */ /* } */ /* } */ static gboolean _next1(VisuPairLinkIter *iter, gboolean restart) { if (!visu_element_getRendered(iter->iter1.element)) return FALSE; if (restart) visu_node_array_iterRestartNode(VISU_NODE_ARRAY(iter->data), &iter->iter1); else visu_node_array_iterNextNode(VISU_NODE_ARRAY(iter->data), &iter->iter1); while (iter->iter1.node && !visu_node_getVisibility(iter->iter1.node)) visu_node_array_iterNextNode(VISU_NODE_ARRAY(iter->data), &iter->iter1); if (iter->iter1.node) visu_data_getNodePosition(iter->data, iter->iter1.node, iter->xyz1); return (iter->iter1.node != NULL); } static gboolean _next2(VisuPairLinkIter *iter, gboolean restart) { if (!visu_element_getRendered(iter->iter2.element)) return FALSE; if (restart) visu_node_array_iterRestartNode(VISU_NODE_ARRAY(iter->data), &iter->iter2); else visu_node_array_iterNextNode(VISU_NODE_ARRAY(iter->data), &iter->iter2); while (iter->iter2.node) { if (iter->iter1.element == iter->iter2.element && iter->iter2.node >= iter->iter1.node) return FALSE; if (visu_node_getVisibility(iter->iter2.node)) { visu_data_getNodePosition(iter->data, iter->iter2.node, iter->xyz2); iter->dxyz[0] = iter->xyz2[0] - iter->xyz1[0]; iter->dxyz[1] = iter->xyz2[1] - iter->xyz1[1]; iter->dxyz[2] = iter->xyz2[2] - iter->xyz1[2]; if (iter->box) iter->periodic = visu_box_getInside(iter->box, iter->dxyz, 0.6f); iter->d2 = iter->dxyz[0] * iter->dxyz[0] + iter->dxyz[1] * iter->dxyz[1] + iter->dxyz[2] * iter->dxyz[2]; if(iter->d2 >= iter->l2_buffered[0] && iter->d2 <= iter->l2_buffered[1]) { if (iter->d2 < iter->l2[0]) iter->coeff = (iter->d2 - iter->l2_buffered[0]) / (iter->l2[0] - iter->l2_buffered[0]); else if (iter->d2 > iter->l2[1]) iter->coeff = (iter->l2_buffered[1] - iter->d2) / (iter->l2_buffered[1] - iter->l2[1]); else iter->coeff = 1.f; return TRUE; } } visu_node_array_iterNextNode(VISU_NODE_ARRAY(iter->data), &iter->iter2); } return FALSE; } /** * VisuPairLinkIter: * @parent: the #VisuPairLink this iterator is inheriting his properties. * @data: the #VisuData this iterator have to work on. * @iter1: a #VisuNodeArrayIter. * @iter2: a second #VisuNodeArrayIter. * @buffer: the length of the buffer around links, in percents. * @l2: the current link length, squared. * @l2_buffered: like @l2, but including the buffer. * @box: (allow-none): a given box to apply periodicity if needed. * @periodic: a boolean specifying if periodicity is to be taken into * account when computing the vector linking two nodes. * @xyz1: the current coordinates of the starting node in the link. * @xyz2: the current coordinates of the ending node in the link. * @dxyz: the current vector (within periodicity) linking node1 to * node2. * @d2: the length of the link, squared. * @coeff: a value used to characterised link length with respect to * buffer (1. means that length is within link characteristics, while * 0. means that link is outside characteristics plus buffer). * * An iterator used to generate pairs with the characteristics given * by @parent, over the node in @data. * * Since: 3.8 */ /** * visu_pair_link_iter_new: * @link: a #VisuPairLink object. * @data: a #VisuData object. * @iter: (out caller-allocates): a pointer to a #VisuPairLinkIter * structure. * @usePeriodicty: a boolean. * * Initialise a new #VisuPairLinkIter structure to iterate over links * defined by @link in @data. If @usePeriodicty is %TRUE, all links * between two nodes are kept if their smallest vector, using the * periodicty, is within the @link distance criterion. * * Since: 3.8 * * Returns: TRUE if there is a valid link to draw. **/ gboolean visu_pair_link_iter_new(VisuPairLink *link, VisuData *data, VisuPairLinkIter *iter, gboolean usePeriodicty) { float mM[2], length; g_return_val_if_fail(VISU_IS_PAIR_LINK(link) && data && iter, FALSE); if (!visu_pair_link_isDrawn(link)) return FALSE; iter->parent = link; iter->data = data; visu_node_array_iter_new(VISU_NODE_ARRAY(data), &iter->iter1); visu_node_array_iter_new(VISU_NODE_ARRAY(data), &iter->iter2); iter->iter1.element = visu_pair_link_getFirstElement(link); iter->iter2.element = visu_pair_link_getSecondElement(link); g_object_unref(iter->iter2.element); g_object_unref(iter->iter1.element); iter->buffer = 0.15f; mM[0] = visu_pair_link_getDistance(link, VISU_DISTANCE_MIN); mM[1] = visu_pair_link_getDistance(link, VISU_DISTANCE_MAX); iter->l2[0] = mM[0] * mM[0]; iter->l2[1] = mM[1] * mM[1]; length = mM[1] - mM[0]; iter->l2_buffered[0] = (mM[0] - iter->buffer * length); iter->l2_buffered[0] *= iter->l2_buffered[0]; iter->l2_buffered[1] = (mM[1] + iter->buffer * length); iter->l2_buffered[1] *= iter->l2_buffered[1]; iter->box = (usePeriodicty) ? visu_boxed_getBox(VISU_BOXED(data)) : (VisuBox*)0; iter->periodic = FALSE; if (_next1(iter, TRUE)) { if (_next2(iter, TRUE)) return TRUE; while (_next1(iter, FALSE)) { if (_next2(iter, TRUE)) return TRUE; }; } return FALSE; } /** * visu_pair_link_iter_next: * @iter: a #VisuPairLinkIter object. * * Iterate to the next #VisuNode - #VisuNode pair. * * Since: 3.8 * * Returns: TRUE if iterator is still valid. **/ gboolean visu_pair_link_iter_next(VisuPairLinkIter *iter) { if (_next2(iter, FALSE)) return TRUE; while (_next1(iter, FALSE)) { if (_next2(iter, TRUE)) return TRUE; }; return FALSE; } v_sim-3.8.0/src/pairsModeling/link.h000066400000000000000000000140571370110300500173260ustar00rootroot00000000000000/* EXTRAITS DE LA LICENCE Copyright CEA, contributeurs : Damien CALISTE, laboratoire L_Sim, (2016) Adresse mèl : BILLARD, non joignable par mèl ; CALISTE, damien P caliste AT cea P fr. Ce logiciel est un programme informatique servant à visualiser des structures atomiques dans un rendu pseudo-3D. Ce logiciel est régi par la licence CeCILL soumise au droit français et respectant les principes de diffusion des logiciels libres. Vous pouvez utiliser, modifier et/ou redistribuer ce programme sous les conditions de la licence CeCILL telle que diffusée par le CEA, le CNRS et l'INRIA sur le site "http://www.cecill.info". Le fait que vous puissiez accéder à cet en-tête signifie que vous avez pris connaissance de la licence CeCILL, et que vous en avez accepté les termes (cf. le fichier Documentation/licence.fr.txt fourni avec ce logiciel). */ /* LICENCE SUM UP Copyright CEA, contributors : Damien CALISTE, laboratoire L_Sim, (2016) E-mail address: BILLARD, not reachable any more ; CALISTE, damien P caliste AT cea P fr. This software is a computer program whose purpose is to visualize atomic configurations in 3D. This software is governed by the CeCILL license under French law and abiding by the rules of distribution of free software. You can use, modify and/ or redistribute the software under the terms of the CeCILL license as circulated by CEA, CNRS and INRIA at the following URL "http://www.cecill.info". The fact that you are presently reading this means that you have had knowledge of the CeCILL license and that you accept its terms. You can find a copy of this licence shipped with this software at Documentation/licence.en.txt. */ #ifndef VISU_LINK #define VISU_LINK #include #include #include #include #include #include G_BEGIN_DECLS /** * VisuPairLinkDistances: * @VISU_DISTANCE_MIN: Flag used to define the minimum length to draw pair. * @VISU_DISTANCE_MAX: Flag used to define the maximum length to draw pair. * * This is useful with the visu_pair_link_getDistance() and the * visu_pair_link_setDistance() methods. * * Since: 3.8 */ typedef enum { VISU_DISTANCE_MIN, VISU_DISTANCE_MAX } VisuPairLinkDistances; /** * VISU_TYPE_PAIR_LINK: * * return the type of #VisuPairLink. * * Since: 3.7 */ #define VISU_TYPE_PAIR_LINK (visu_pair_link_get_type ()) /** * VISU_PAIR_LINK: * @obj: a #GObject to cast. * * Cast the given @obj into #VisuPairLink type. * * Since: 3.7 */ #define VISU_PAIR_LINK(obj) (G_TYPE_CHECK_INSTANCE_CAST(obj, VISU_TYPE_PAIR_LINK, VisuPairLink)) /** * VISU_PAIR_LINK_CLASS: * @klass: a #GObjectClass to cast. * * Cast the given @klass into #VisuPairLinkClass. * * Since: 3.7 */ #define VISU_PAIR_LINK_CLASS(klass) (G_TYPE_CHECK_CLASS_CAST(klass, VISU_TYPE_PAIR_LINK, VisuPairLinkClass)) /** * VISU_IS_PAIR_LINK: * @obj: a #GObject to test. * * Test if the given @ogj is of the type of #VisuPairLink object. * * Since: 3.7 */ #define VISU_IS_PAIR_LINK(obj) (G_TYPE_CHECK_INSTANCE_TYPE(obj, VISU_TYPE_PAIR_LINK)) /** * VISU_IS_PAIR_LINK_CLASS: * @klass: a #GObjectClass to test. * * Test if the given @klass is of the type of #VisuPairLinkClass class. * * Since: 3.7 */ #define VISU_IS_PAIR_LINK_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE(klass, VISU_TYPE_PAIR_LINK)) /** * VISU_PAIR_LINK_GET_CLASS: * @obj: a #GObject to get the class of. * * It returns the class of the given @obj. * * Since: 3.7 */ #define VISU_PAIR_LINK_GET_CLASS(obj) (G_TYPE_INSTANCE_GET_CLASS(obj, VISU_TYPE_PAIR_LINK, VisuPairLinkClass)) typedef struct _VisuPairLink VisuPairLink; typedef struct _VisuPairLinkPrivate VisuPairLinkPrivate; typedef struct _VisuPairLinkClass VisuPairLinkClass; /** * VisuPairLink: * * An opaque structure. */ struct _VisuPairLink { VisuObject parent; VisuPairLinkPrivate *priv; }; /** * VisuPairLinkClass: * @parent: the parent class; * * A short way to identify #_VisuPairLinkClass structure. */ struct _VisuPairLinkClass { VisuObjectClass parent; }; /** * visu_pair_link_get_type: * * This method returns the type of #VisuPairLink, use * VISU_TYPE_PAIR_LINK instead. * * Since: 3.7 * * Returns: the type of #VisuPairLink. */ GType visu_pair_link_get_type(void); VisuPairLink* visu_pair_link_new(VisuElement *ele1, VisuElement *ele2, const float minMax[2]); VisuElement* visu_pair_link_getFirstElement(VisuPairLink *data); VisuElement* visu_pair_link_getSecondElement(VisuPairLink *data); gboolean visu_pair_link_setDrawn (VisuPairLink *data, gboolean drawn); gboolean visu_pair_link_getDrawn (const VisuPairLink *data); gboolean visu_pair_link_setColor (VisuPairLink *data, const ToolColor* destColor); ToolColor* visu_pair_link_getColor (const VisuPairLink *data); gboolean visu_pair_link_setPrintLength(VisuPairLink *data, gboolean status); gboolean visu_pair_link_getPrintLength(const VisuPairLink *data); gboolean visu_pair_link_setDistance (VisuPairLink *data, float val, VisuPairLinkDistances minOrMax); float visu_pair_link_getDistance (const VisuPairLink *data, VisuPairLinkDistances minOrMax); gboolean visu_pair_link_setUnits (VisuPairLink *data, ToolUnits units); ToolUnits visu_pair_link_getUnits (const VisuPairLink *data); gboolean visu_pair_link_match (const VisuPairLink *data, const float minMax[2]); gboolean visu_pair_link_isDrawn (const VisuPairLink *data); typedef struct _VisuPairLinkIter VisuPairLinkIter; struct _VisuPairLinkIter { VisuPairLink *parent; VisuData *data; VisuNodeArrayIter iter1, iter2; float buffer; float l2[2], l2_buffered[2]; VisuBox *box; gboolean periodic; float xyz1[3], xyz2[3], dxyz[3]; float d2, coeff; }; gboolean visu_pair_link_iter_new(VisuPairLink *link, VisuData *data, VisuPairLinkIter *iter, gboolean usePeriodicty); gboolean visu_pair_link_iter_next(VisuPairLinkIter *iter); G_END_DECLS #endif v_sim-3.8.0/src/pairsModeling/linkRenderer.c000066400000000000000000000224501370110300500210040ustar00rootroot00000000000000/* EXTRAITS DE LA LICENCE Copyright CEA, contributeurs : Damien CALISTE, laboratoire L_Sim, (2016-2017) Adresse mèl : BILLARD, non joignable par mèl ; CALISTE, damien P caliste AT cea P fr. Ce logiciel est un programme informatique servant à visualiser des structures atomiques dans un rendu pseudo-3D. Ce logiciel est régi par la licence CeCILL soumise au droit français et respectant les principes de diffusion des logiciels libres. Vous pouvez utiliser, modifier et/ou redistribuer ce programme sous les conditions de la licence CeCILL telle que diffusée par le CEA, le CNRS et l'INRIA sur le site "http://www.cecill.info". Le fait que vous puissiez accéder à cet en-tête signifie que vous avez pris connaissance de la licence CeCILL, et que vous en avez accepté les termes (cf. le fichier Documentation/licence.fr.txt fourni avec ce logiciel). */ /* LICENCE SUM UP Copyright CEA, contributors : Damien CALISTE, laboratoire L_Sim, (2016-2017) E-mail address: BILLARD, not reachable any more ; CALISTE, damien P caliste AT cea P fr. This software is a computer program whose purpose is to visualize atomic configurations in 3D. This software is governed by the CeCILL license under French law and abiding by the rules of distribution of free software. You can use, modify and/ or redistribute the software under the terms of the CeCILL license as circulated by CEA, CNRS and INRIA at the following URL "http://www.cecill.info". The fact that you are presently reading this means that you have had knowledge of the CeCILL license and that you accept its terms. You can find a copy of this licence shipped with this software at Documentation/licence.en.txt. */ #include "linkRenderer.h" /** * SECTION:linkRenderer * @short_description: Defines a common class for #VisuPairLink renderers. * @Title: VisuPairLinkRenderer * * */ struct _VisuPairLinkRendererPrivate { gchar *id, *label, *descr; }; enum { DIRTY_SIGNAL, LAST_SIGNAL }; static guint _signals[LAST_SIGNAL] = { 0 }; enum { PROP_0, ID_PROP, LABEL_PROP, DESCR_PROP, N_PROPS }; static GParamSpec *_properties[N_PROPS]; static void visu_pair_link_renderer_finalize(GObject* obj); static void visu_pair_link_renderer_get_property(GObject* obj, guint property_id, GValue *value, GParamSpec *pspec); static void visu_pair_link_renderer_set_property(GObject* obj, guint property_id, const GValue *value, GParamSpec *pspec); /* Link_Renderer interface. */ G_DEFINE_TYPE_WITH_CODE(VisuPairLinkRenderer, visu_pair_link_renderer, VISU_TYPE_OBJECT, G_ADD_PRIVATE(VisuPairLinkRenderer)) static void visu_pair_link_renderer_class_init(VisuPairLinkRendererClass *klass) { G_OBJECT_CLASS(klass)->finalize = visu_pair_link_renderer_finalize; G_OBJECT_CLASS(klass)->get_property = visu_pair_link_renderer_get_property; G_OBJECT_CLASS(klass)->set_property = visu_pair_link_renderer_set_property; /** * VisuPairLinkRenderer::dirty: * @renderer: the object which emits the signal ; * * Gets emitted when some rendering parameter of @renderer has been changed. * * Since: 3.8 */ _signals[DIRTY_SIGNAL] = g_signal_new("dirty", G_TYPE_FROM_CLASS(klass), G_SIGNAL_RUN_LAST | G_SIGNAL_NO_RECURSE, 0, NULL, NULL, g_cclosure_marshal_VOID__VOID, G_TYPE_NONE, 0, NULL); /** * VisuPairLinkRenderer::id: * * A string defining this renderer, used for configuration files. * * Since: 3.8 */ _properties[ID_PROP] = g_param_spec_string("id", "Id", "id defining this renderer", "", G_PARAM_READWRITE | G_PARAM_CONSTRUCT_ONLY); /** * VisuPairLinkRenderer::label: * * A string defining this renderer, used for UI. * * Since: 3.8 */ _properties[LABEL_PROP] = g_param_spec_string("label", "Label", "label of this renderer", "", G_PARAM_READWRITE | G_PARAM_CONSTRUCT_ONLY); /** * VisuPairLinkRenderer::description: * * A string detailing this renderer, used for UI. * * Since: 3.8 */ _properties[DESCR_PROP] = g_param_spec_string("description", "Description", "description of this renderer", "", G_PARAM_READWRITE | G_PARAM_CONSTRUCT_ONLY); g_object_class_install_properties(G_OBJECT_CLASS(klass), N_PROPS, _properties); } static void visu_pair_link_renderer_init(VisuPairLinkRenderer *self) { self->priv = visu_pair_link_renderer_get_instance_private(self); self->priv->id = (gchar*)0; self->priv->label = (gchar*)0; self->priv->descr = (gchar*)0; } static void visu_pair_link_renderer_get_property(GObject* obj, guint property_id, GValue *value, GParamSpec *pspec) { VisuPairLinkRenderer *self = VISU_PAIR_LINK_RENDERER(obj); DBG_fprintf(stderr, "Link Renderer: get property '%s' -> ", g_param_spec_get_name(pspec)); switch (property_id) { case ID_PROP: g_value_set_string(value, self->priv->id); DBG_fprintf(stderr, "%s.\n", g_value_get_string(value)); break; case LABEL_PROP: g_value_set_string(value, self->priv->label); DBG_fprintf(stderr, "%s.\n", g_value_get_string(value)); break; case DESCR_PROP: g_value_set_string(value, self->priv->descr); DBG_fprintf(stderr, "%s.\n", g_value_get_string(value)); break; default: /* We don't have any other property... */ G_OBJECT_WARN_INVALID_PROPERTY_ID(obj, property_id, pspec); break; } } static void visu_pair_link_renderer_set_property(GObject* obj, guint property_id, const GValue *value, GParamSpec *pspec) { VisuPairLinkRenderer *self = VISU_PAIR_LINK_RENDERER(obj); DBG_fprintf(stderr, "Link Renderer: set property '%s' -> ", g_param_spec_get_name(pspec)); switch (property_id) { case ID_PROP: DBG_fprintf(stderr, "%s.\n", g_value_get_string(value)); self->priv->id = g_value_dup_string(value); break; case LABEL_PROP: DBG_fprintf(stderr, "%s.\n", g_value_get_string(value)); self->priv->label = g_value_dup_string(value); break; case DESCR_PROP: DBG_fprintf(stderr, "%s.\n", g_value_get_string(value)); self->priv->descr = g_value_dup_string(value); break; default: /* We don't have any other property... */ G_OBJECT_WARN_INVALID_PROPERTY_ID(obj, property_id, pspec); break; } } static void visu_pair_link_renderer_finalize(GObject *obj) { VisuPairLinkRenderer *self = VISU_PAIR_LINK_RENDERER(obj); g_free(self->priv->id); g_free(self->priv->label); g_free(self->priv->descr); G_OBJECT_CLASS(visu_pair_link_renderer_parent_class)->finalize(obj); } /** * visu_pair_link_renderer_start: * @renderer: a #VisuPairLinkRenderer object. * @data: a #VisuPairLink object. * @ele1: a #VisuElementRenderer object. * @ele2: a #VisuElementRenderer object. * @colorizer: a #VisuDataColorizer object. * * Calls the start() method of @renderer class. This method is * actually called each time a different @data pair is drawn. * * Since: 3.8 **/ void visu_pair_link_renderer_start(VisuPairLinkRenderer *renderer, VisuPairLink *data, VisuElementRenderer *ele1, VisuElementRenderer *ele2, VisuDataColorizer *colorizer) { VisuPairLinkRendererClass *klass; klass = VISU_PAIR_LINK_RENDERER_GET_CLASS(renderer); if (klass->start) klass->start(renderer, data, ele1, ele2, colorizer); } /** * visu_pair_link_renderer_stop: * @renderer: a #VisuPairLinkRenderer object. * @data: a #VisuPairLink object. * * Calls the stop() method of @renderer class. It is actually called * each time a different @data pair is finished. * * Since: 3.8 **/ void visu_pair_link_renderer_stop(VisuPairLinkRenderer *renderer, VisuPairLink *data) { VisuPairLinkRendererClass *klass; klass = VISU_PAIR_LINK_RENDERER_GET_CLASS(renderer); if (klass->stop) klass->stop(renderer, data); } /** * visu_pair_link_renderer_draw: * @renderer: a #VisuPairLinkRenderer object. * @iter: a #VisuPairLinkIter object. * * Calls the draw() method of @renderer for the current pair defined * by @iter. * * Since: 3.8 **/ void visu_pair_link_renderer_draw(VisuPairLinkRenderer *renderer, const VisuPairLinkIter *iter) { VISU_PAIR_LINK_RENDERER_GET_CLASS(renderer)->draw(renderer, iter); } /** * visu_pair_link_renderer_setGlView: * @renderer: a #VisuPairLinkRenderer object. * @view: a #VisuGlView object. * * If @renderer class has a #VisuPairLinkRenderer::set_view() method, * it binds @view to @renderer. * * Since: 3.8 * * Returns: TRUE if value is actually cahnged. **/ gboolean visu_pair_link_renderer_setGlView(VisuPairLinkRenderer *renderer, VisuGlView *view) { VisuPairLinkRendererClass *klass; klass = VISU_PAIR_LINK_RENDERER_GET_CLASS(renderer); if (klass->set_view) return klass->set_view(renderer, view); return FALSE; } /** * visu_pair_link_renderer_emitDirty: * @renderer: a #VisuPairLinkRenderer object. * * Emits the "dirty" signal of @renderer. * * Since: 3.8 **/ void visu_pair_link_renderer_emitDirty(VisuPairLinkRenderer *renderer) { g_signal_emit(renderer, _signals[DIRTY_SIGNAL], 0); } v_sim-3.8.0/src/pairsModeling/linkRenderer.h000066400000000000000000000115451370110300500210140ustar00rootroot00000000000000/* EXTRAITS DE LA LICENCE Copyright CEA, contributeurs : Damien CALISTE, laboratoire L_Sim, (2016-2017) Adresse mèl : BILLARD, non joignable par mèl ; CALISTE, damien P caliste AT cea P fr. Ce logiciel est un programme informatique servant à visualiser des structures atomiques dans un rendu pseudo-3D. Ce logiciel est régi par la licence CeCILL soumise au droit français et respectant les principes de diffusion des logiciels libres. Vous pouvez utiliser, modifier et/ou redistribuer ce programme sous les conditions de la licence CeCILL telle que diffusée par le CEA, le CNRS et l'INRIA sur le site "http://www.cecill.info". Le fait que vous puissiez accéder à cet en-tête signifie que vous avez pris connaissance de la licence CeCILL, et que vous en avez accepté les termes (cf. le fichier Documentation/licence.fr.txt fourni avec ce logiciel). */ /* LICENCE SUM UP Copyright CEA, contributors : Damien CALISTE, laboratoire L_Sim, (2016-2017) E-mail address: BILLARD, not reachable any more ; CALISTE, damien P caliste AT cea P fr. This software is a computer program whose purpose is to visualize atomic configurations in 3D. This software is governed by the CeCILL license under French law and abiding by the rules of distribution of free software. You can use, modify and/ or redistribute the software under the terms of the CeCILL license as circulated by CEA, CNRS and INRIA at the following URL "http://www.cecill.info". The fact that you are presently reading this means that you have had knowledge of the CeCILL license and that you accept its terms. You can find a copy of this licence shipped with this software at Documentation/licence.en.txt. */ #ifndef LINK_RENDERER_H #define LINK_RENDERER_H #include #include #include "link.h" #include #include #include G_BEGIN_DECLS /* Boxed interface. */ #define VISU_TYPE_PAIR_LINK_RENDERER (visu_pair_link_renderer_get_type()) #define VISU_PAIR_LINK_RENDERER(obj) (G_TYPE_CHECK_INSTANCE_CAST((obj), VISU_TYPE_PAIR_LINK_RENDERER, VisuPairLinkRenderer)) #define VISU_PAIR_LINK_RENDERER_CLASS(klass) (G_TYPE_CHECK_CLASS_CAST(klass, VISU_TYPE_PAIR_LINK_RENDERER, VisuPairLinkRendererClass)) #define VISU_IS_PAIR_LINK_RENDERER(obj) (G_TYPE_CHECK_INSTANCE_TYPE((obj), VISU_TYPE_PAIR_LINK_RENDERER)) #define VISU_IS_PAIR_LINK_RENDERER_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE(klass, VISU_TYPE_PAIR_LINK_RENDERER)) #define VISU_PAIR_LINK_RENDERER_GET_CLASS(obj) (G_TYPE_INSTANCE_GET_CLASS(obj, VISU_TYPE_PAIR_LINK_RENDERER, VisuPairLinkRendererClass)) typedef struct _VisuPairLinkRenderer VisuPairLinkRenderer; typedef struct _VisuPairLinkRendererPrivate VisuPairLinkRendererPrivate; typedef struct _VisuPairLinkRendererClass VisuPairLinkRendererClass; /** * VisuPairLinkRenderer: * * An opaque structure. */ struct _VisuPairLinkRenderer { VisuObject parent; VisuPairLinkRendererPrivate *priv; }; /** * VisuPairLinkRendererClass: * @parent: the parent class; * @start: a routine called before drawing every link defined by #VisuPairLink. * @stop: a routine called after drawing every link defined by #VisuPairLink. * @draw: a routine called for every link defined by #VisuPairLink. * @set_view: a routine called to set a different #VisuGlView object. * * The different routines common to objects implementing a #VisuPairLinkRenderer class. * * Since: 3.8 */ struct _VisuPairLinkRendererClass { VisuObjectClass parent; void (*start)(VisuPairLinkRenderer *renderer, VisuPairLink *data, VisuElementRenderer *ele1, VisuElementRenderer *ele2, VisuDataColorizer *colorizer); void (*stop)(VisuPairLinkRenderer *renderer, VisuPairLink *data); void (*draw)(VisuPairLinkRenderer *renderer, const VisuPairLinkIter *iter); gboolean (*set_view)(VisuPairLinkRenderer *renderer, VisuGlView *view); }; /** * visu_pair_link_renderer_get_type: * * This method returns the type of #VisuPairLinkRenderer, use * VISU_TYPE_PAIR_LINK_RENDERER instead. * * Since: 3.8 * * Returns: the type of #VisuPairLinkRenderer. */ GType visu_pair_link_renderer_get_type(void); void visu_pair_link_renderer_start(VisuPairLinkRenderer *renderer, VisuPairLink *data, VisuElementRenderer *ele1, VisuElementRenderer *ele2, VisuDataColorizer *colorizer); void visu_pair_link_renderer_stop(VisuPairLinkRenderer *renderer, VisuPairLink *data); void visu_pair_link_renderer_draw(VisuPairLinkRenderer *renderer, const VisuPairLinkIter *iter); gboolean visu_pair_link_renderer_setGlView(VisuPairLinkRenderer *renderer, VisuGlView *view); void visu_pair_link_renderer_emitDirty(VisuPairLinkRenderer *renderer); G_END_DECLS #endif v_sim-3.8.0/src/pairsModeling/wire_renderer.c000066400000000000000000000131241370110300500212120ustar00rootroot00000000000000/* EXTRAITS DE LA LICENCE Copyright CEA, contributeurs : Damien CALISTE, laboratoire L_Sim, (2016) Adresse mèl : BILLARD, non joignable par mèl ; CALISTE, damien P caliste AT cea P fr. Ce logiciel est un programme informatique servant à visualiser des structures atomiques dans un rendu pseudo-3D. Ce logiciel est régi par la licence CeCILL soumise au droit français et respectant les principes de diffusion des logiciels libres. Vous pouvez utiliser, modifier et/ou redistribuer ce programme sous les conditions de la licence CeCILL telle que diffusée par le CEA, le CNRS et l'INRIA sur le site "http://www.cecill.info". Le fait que vous puissiez accéder à cet en-tête signifie que vous avez pris connaissance de la licence CeCILL, et que vous en avez accepté les termes (cf. le fichier Documentation/licence.fr.txt fourni avec ce logiciel). */ /* LICENCE SUM UP Copyright CEA, contributors : Damien CALISTE, laboratoire L_Sim, (2016) E-mail address: BILLARD, not reachable any more ; CALISTE, damien P caliste AT cea P fr. This software is a computer program whose purpose is to visualize atomic configurations in 3D. This software is governed by the CeCILL license under French law and abiding by the rules of distribution of free software. You can use, modify and/ or redistribute the software under the terms of the CeCILL license as circulated by CEA, CNRS and INRIA at the following URL "http://www.cecill.info". The fact that you are presently reading this means that you have had knowledge of the CeCILL license and that you accept its terms. You can find a copy of this licence shipped with this software at Documentation/licence.en.txt. */ #include "wire_renderer.h" #include "iface_wire.h" #include #include #include /** * SECTION:wire_renderer * @short_description: a class to render #VisuPairLink as wires. * * This class is used to render #VisuPairLink as wires. */ static void _start(VisuPairLinkRenderer *self, VisuPairLink *data, VisuElementRenderer *ele1, VisuElementRenderer *ele2, VisuDataColorizer *colorizer); static void _stop(VisuPairLinkRenderer *self, VisuPairLink *data); static void _draw(VisuPairLinkRenderer *self, const VisuPairLinkIter *iter); G_DEFINE_TYPE(VisuPairWireRenderer, visu_pair_wire_renderer, VISU_TYPE_PAIR_LINK_RENDERER) static void visu_pair_wire_renderer_class_init(VisuPairWireRendererClass *klass) { DBG_fprintf(stderr, "Visu Wire Renderer: creating the class of the object.\n"); /* Connect the overloading methods. */ VISU_PAIR_LINK_RENDERER_CLASS(klass)->start = _start; VISU_PAIR_LINK_RENDERER_CLASS(klass)->stop = _stop; VISU_PAIR_LINK_RENDERER_CLASS(klass)->draw = _draw; } static void visu_pair_wire_renderer_init(VisuPairWireRenderer *obj _U_) { DBG_fprintf(stderr, "Visu Wire Renderer: initializing a new object (%p).\n", (gpointer)obj); } /** * visu_pair_wire_renderer_new: * * Creates a renderer to draw links as wires. * * Since: 3.8 * * Returns: (transfer full): a newly created #VisuPairWireRenderer object. */ VisuPairWireRenderer* visu_pair_wire_renderer_new() { return VISU_PAIR_WIRE_RENDERER(g_object_new(VISU_TYPE_PAIR_WIRE_RENDERER, "id", "Wire pairs", "label", _("Wire pairs"), "description", _("Pairs are rendered by flat lines." " The color and the width can by chosen."), NULL)); } static void _start(VisuPairLinkRenderer *self _U_, VisuPairLink *data, VisuElementRenderer *ele1 _U_, VisuElementRenderer *ele2 _U_, VisuDataColorizer *colorizer _U_) { ToolColor *color; guint16 stipple; glLineWidth(visu_pair_wire_getWidth(VISU_PAIR_WIRE(data))); color = visu_pair_link_getColor(data); glColor3fv(color->rgba); stipple = visu_pair_wire_getStipple(VISU_PAIR_WIRE(data)); if (stipple != 65535) { glEnable(GL_LINE_STIPPLE); glLineStipple(1, stipple); } glDisable(GL_LIGHTING); glDisable(GL_DITHER); } static void _stop(VisuPairLinkRenderer *self _U_, VisuPairLink *data _U_) { glDisable(GL_LINE_STIPPLE); glEnable(GL_DITHER); /* WARNING: it is the default! */ glEnable(GL_LIGHTING); } static void _draw(VisuPairLinkRenderer *self _U_, const VisuPairLinkIter *iter) { float ratio; ToolColor *color; float rgba[4], mM[2]; ToolShade *shade; color = visu_pair_link_getColor(iter->parent); shade = visu_pair_wire_getShade(VISU_PAIR_WIRE(iter->parent)); if (shade) { mM[0] = visu_pair_link_getDistance(iter->parent, VISU_DISTANCE_MIN); mM[1] = visu_pair_link_getDistance(iter->parent, VISU_DISTANCE_MAX); ratio = (sqrt(iter->d2) - mM[0]) / (mM[1] - mM[0]); tool_shade_valueToRGB(shade, rgba, ratio); rgba[3] = iter->coeff * color->rgba[3]; glColor4fv(rgba); } else glColor4f(color->rgba[0], color->rgba[1], color->rgba[2], iter->coeff * color->rgba[3]); glBegin(GL_LINES); glVertex3fv(iter->xyz1); if (iter->periodic) glVertex3f(iter->xyz1[0] + iter->dxyz[0] / 2.f, iter->xyz1[1] + iter->dxyz[1] / 2.f, iter->xyz1[2] + iter->dxyz[2] / 2.f); else glVertex3fv(iter->xyz2); glEnd(); if (iter->periodic) { glBegin(GL_LINES); glVertex3fv(iter->xyz2); glVertex3f(iter->xyz2[0] - iter->dxyz[0] / 2.f, iter->xyz2[1] - iter->dxyz[1] / 2.f, iter->xyz2[2] - iter->dxyz[2] / 2.f); glEnd(); } } v_sim-3.8.0/src/pairsModeling/wire_renderer.h000066400000000000000000000103341370110300500212170ustar00rootroot00000000000000/* EXTRAITS DE LA LICENCE Copyright CEA, contributeurs : Damien CALISTE, laboratoire L_Sim, (2016) Adresse mèl : BILLARD, non joignable par mèl ; CALISTE, damien P caliste AT cea P fr. Ce logiciel est un programme informatique servant à visualiser des structures atomiques dans un rendu pseudo-3D. Ce logiciel est régi par la licence CeCILL soumise au droit français et respectant les principes de diffusion des logiciels libres. Vous pouvez utiliser, modifier et/ou redistribuer ce programme sous les conditions de la licence CeCILL telle que diffusée par le CEA, le CNRS et l'INRIA sur le site "http://www.cecill.info". Le fait que vous puissiez accéder à cet en-tête signifie que vous avez pris connaissance de la licence CeCILL, et que vous en avez accepté les termes (cf. le fichier Documentation/licence.fr.txt fourni avec ce logiciel). */ /* LICENCE SUM UP Copyright CEA, contributors : Damien CALISTE, laboratoire L_Sim, (2016) E-mail address: BILLARD, not reachable any more ; CALISTE, damien P caliste AT cea P fr. This software is a computer program whose purpose is to visualize atomic configurations in 3D. This software is governed by the CeCILL license under French law and abiding by the rules of distribution of free software. You can use, modify and/ or redistribute the software under the terms of the CeCILL license as circulated by CEA, CNRS and INRIA at the following URL "http://www.cecill.info". The fact that you are presently reading this means that you have had knowledge of the CeCILL license and that you accept its terms. You can find a copy of this licence shipped with this software at Documentation/licence.en.txt. */ #ifndef WIRE_RENDERER_H #define WIRE_RENDERER_H #include #include #include "linkRenderer.h" /** * VISU_TYPE_PAIR_WIRE_RENDERER: * * return the type of #VisuPairWireRenderer. * * Since: 3.8 */ #define VISU_TYPE_PAIR_WIRE_RENDERER (visu_pair_wire_renderer_get_type ()) /** * VISU_PAIR_WIRE_RENDERER: * @obj: a #GObject to cast. * * Cast the given @obj into #VisuPairWireRenderer type. * * Since: 3.8 */ #define VISU_PAIR_WIRE_RENDERER(obj) (G_TYPE_CHECK_INSTANCE_CAST(obj, VISU_TYPE_PAIR_WIRE_RENDERER, VisuPairWireRenderer)) /** * VISU_PAIR_WIRE_RENDERER_CLASS: * @klass: a #GObjectClass to cast. * * Cast the given @klass into #VisuPairWireRendererClass. * * Since: 3.8 */ #define VISU_PAIR_WIRE_RENDERER_CLASS(klass) (G_TYPE_CHECK_CLASS_CAST(klass, VISU_TYPE_PAIR_WIRE_RENDERER, VisuPairWireRendererClass)) /** * VISU_IS_PAIR_WIRE_RENDERER: * @obj: a #GObject to test. * * Test if the given @ogj is of the type of #VisuPairWireRenderer object. * * Since: 3.8 */ #define VISU_IS_PAIR_WIRE_RENDERER(obj) (G_TYPE_CHECK_INSTANCE_TYPE(obj, VISU_TYPE_PAIR_WIRE_RENDERER)) /** * VISU_IS_PAIR_WIRE_RENDERER_CLASS: * @klass: a #GObjectClass to test. * * Test if the given @klass is of the type of #VisuPairWireRendererClass class. * * Since: 3.8 */ #define VISU_IS_PAIR_WIRE_RENDERER_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE(klass, VISU_TYPE_PAIR_WIRE_RENDERER)) /** * VISU_PAIR_WIRE_RENDERER_GET_CLASS: * @obj: a #GObject to get the class of. * * It returns the class of the given @obj. * * Since: 3.8 */ #define VISU_PAIR_WIRE_RENDERER_GET_CLASS(obj) (G_TYPE_INSTANCE_GET_CLASS(obj, VISU_TYPE_PAIR_WIRE_RENDERER, VisuPairWireRendererClass)) typedef struct _VisuPairWireRenderer VisuPairWireRenderer; typedef struct _VisuPairWireRendererPrivate VisuPairWireRendererPrivate; typedef struct _VisuPairWireRendererClass VisuPairWireRendererClass; /** * VisuPairWireRenderer: * * An opaque structure. */ struct _VisuPairWireRenderer { VisuPairLinkRenderer parent; }; /** * VisuPairWireRendererClass: * @parent: the parent class; * * A short way to identify #_VisuPairWireRendererClass structure. */ struct _VisuPairWireRendererClass { VisuPairLinkRendererClass parent; }; /** * visu_pair_wire_renderer_get_type: * * This method returns the type of #VisuPairWireRenderer, use * VISU_TYPE_PAIR_WIRE_RENDERER instead. * * Since: 3.8 * * Returns: the type of #VisuPairWireRenderer. */ GType visu_pair_wire_renderer_get_type(void); VisuPairWireRenderer* visu_pair_wire_renderer_new(); #endif v_sim-3.8.0/src/panelModules/000077500000000000000000000000001370110300500160445ustar00rootroot00000000000000v_sim-3.8.0/src/panelModules/externalModules.h000066400000000000000000000051621370110300500213740ustar00rootroot00000000000000/* EXTRAITS DE LA LICENCE Copyright CEA, contributeurs : Luc BILLARD et Damien CALISTE, laboratoire L_Sim, (2001-2005) Adresse mèl : BILLARD, non joignable par mèl ; CALISTE, damien P caliste AT cea P fr. Ce logiciel est un programme informatique servant à visualiser des structures atomiques dans un rendu pseudo-3D. Ce logiciel est régi par la licence CeCILL soumise au droit français et respectant les principes de diffusion des logiciels libres. Vous pouvez utiliser, modifier et/ou redistribuer ce programme sous les conditions de la licence CeCILL telle que diffusée par le CEA, le CNRS et l'INRIA sur le site "http://www.cecill.info". Le fait que vous puissiez accéder à cet en-tête signifie que vous avez pris connaissance de la licence CeCILL, et que vous en avez accepté les termes (cf. le fichier Documentation/licence.fr.txt fourni avec ce logiciel). */ /* LICENCE SUM UP Copyright CEA, contributors : Luc BILLARD et Damien CALISTE, laboratoire L_Sim, (2001-2005) E-mail address: BILLARD, not reachable any more ; CALISTE, damien P caliste AT cea P fr. This software is a computer program whose purpose is to visualize atomic configurations in 3D. This software is governed by the CeCILL license under French law and abiding by the rules of distribution of free software. You can use, modify and/ or redistribute the software under the terms of the CeCILL license as circulated by CEA, CNRS and INRIA at the following URL "http://www.cecill.info". The fact that you are presently reading this means that you have had knowledge of the CeCILL license and that you accept its terms. You can find a copy of this licence shipped with this software at Documentation/licence.en.txt. */ #ifndef EXTERNALMODULES_H #define EXTERNALMODULES_H /** * PanelInitFunc: * * Prototype of the functions used to initialise a new panel. * * Returns: a newly created #VisuUiPanel. */ typedef VisuUiPanel* (*PanelInitFunc) (VisuUiMain *main); #include "panelGeometry.h" #include "panelVibration.h" #include "panelOpenGL.h" #include "panelFogBgColor.h" #include "panelBrowser.h" #include "panelDataFile.h" #include "panelConfig.h" #include "panelPlanes.h" #include "panelSurfaces.h" #include "panelMethod.h" #include "panelMap.h" PanelInitFunc panelListAll[] = { visu_ui_panel_bg_init, visu_ui_panel_browser_init, visu_ui_panel_geometry_init, visu_ui_panel_colorization_init, visu_ui_panel_planes_init, visu_ui_panel_surfaces_init, visu_ui_panel_map_init, visu_ui_panel_vibration_init, visu_ui_panel_method_init, visu_ui_panel_gl_init, visu_ui_panel_config_init, (PanelInitFunc)0}; #endif v_sim-3.8.0/src/panelModules/gtkAtomic.c000066400000000000000000000214431370110300500201360ustar00rootroot00000000000000/* EXTRAITS DE LA LICENCE Copyright CEA, contributeurs : Luc BILLARD et Damien CALISTE, laboratoire L_Sim, (2001-2005) Adresse mèl : BILLARD, non joignable par mèl ; CALISTE, damien P caliste AT cea P fr. Ce logiciel est un programme informatique servant à visualiser des structures atomiques dans un rendu pseudo-3D. Ce logiciel est régi par la licence CeCILL soumise au droit français et respectant les principes de diffusion des logiciels libres. Vous pouvez utiliser, modifier et/ou redistribuer ce programme sous les conditions de la licence CeCILL telle que diffusée par le CEA, le CNRS et l'INRIA sur le site "http://www.cecill.info". Le fait que vous puissiez accéder à cet en-tête signifie que vous avez pris connaissance de la licence CeCILL, et que vous en avez accepté les termes (cf. le fichier Documentation/licence.fr.txt fourni avec ce logiciel). */ /* LICENCE SUM UP Copyright CEA, contributors : Luc BILLARD et Damien CALISTE, laboratoire L_Sim, (2001-2005) E-mail address: BILLARD, not reachable any more ; CALISTE, damien P caliste AT cea P fr. This software is a computer program whose purpose is to visualize atomic configurations in 3D. This software is governed by the CeCILL license under French law and abiding by the rules of distribution of free software. You can use, modify and/ or redistribute the software under the terms of the CeCILL license as circulated by CEA, CNRS and INRIA at the following URL "http://www.cecill.info". The fact that you are presently reading this means that you have had knowledge of the CeCILL license and that you accept its terms. You can find a copy of this licence shipped with this software at Documentation/licence.en.txt. */ #include "gtkAtomic.h" #include #include #include #include #include /** * SECTION:gtkAtomic * @short_description: The gtk interface elements that are specific to * the atomic rendering method. * * This part gathers all the routine specific to the widgets * related to the atomic rendering method. For the method itself, * there is no specific widgets. For the #VisuElement part, one can * tune the shape, the radius and the elipsoid orientation (when * selected). There is no specific #GtkFileChooser widget. */ /* the spin button to control the radius. */ static GtkWidget *checkForces = NULL; static GtkWidget *radioScaleAuto = NULL; static GtkWidget *entryScale = NULL; static VisuNodeValuesVector *model = NULL; static gulong chg_sig; /***************/ /* Public part */ /***************/ static void updateLabel(GtkWidget *label, VisuNode *node _U_, VisuNodeValuesVector *vect) { float max; gchar *str; if (!vect) gtk_label_set_text(GTK_LABEL(label), _("(No force data)")); else { max = visu_node_values_farray_max(VISU_NODE_VALUES_FARRAY(vect)); str = g_strdup_printf(_("(max. force is %.4g)"), max); gtk_label_set_text(GTK_LABEL(label), str); g_free(str); } } static void _setModel(GtkWidget *label, VisuNodeValuesVector *vect) { if (model) { g_signal_handler_disconnect(model, chg_sig); g_object_unref(model); } model = vect; if (vect) { g_object_ref(vect); chg_sig = g_signal_connect_swapped(vect, "changed", G_CALLBACK(updateLabel), label); } updateLabel(label, (VisuNode*)0, vect); } static void modelNotified(GtkWidget *label, GParamSpec *pspec _U_, VisuGlExtNodeVectors *forces) { _setModel(label, VISU_NODE_VALUES_VECTOR(visu_sourceable_getNodeModel(VISU_SOURCEABLE(forces)))); } static gboolean toAutoRadio(GBinding *bind _U_, const GValue *source_value, GValue *target_value, gpointer data _U_) { g_value_set_boolean(target_value, (g_value_get_float(source_value) <= 0.f)); return TRUE; } static gboolean fromAutoRadio(GBinding *bind _U_, const GValue *source_value, GValue *target_value, gpointer data _U_) { if (!g_value_get_boolean(source_value)) return FALSE; g_value_set_float(target_value, 0.f); return TRUE; } static gboolean toManualRadio(GBinding *bind _U_, const GValue *source_value, GValue *target_value, gpointer data _U_) { g_value_set_boolean(target_value, (g_value_get_float(source_value) > 0.f)); return TRUE; } static gboolean fromManualRadio(GBinding *bind _U_, const GValue *source_value, GValue *target_value, gpointer data _U_) { if (!g_value_get_boolean(source_value)) return FALSE; g_value_set_float(target_value, visu_ui_numerical_entry_getValue(VISU_UI_NUMERICAL_ENTRY(entryScale))); return TRUE; } static gboolean toEntry(GBinding *bind _U_, const GValue *source_value, GValue *target_value, gpointer data _U_) { if (g_value_get_float(source_value) <= 0.f) return FALSE; g_value_set_double(target_value, g_value_get_float(source_value)); return TRUE; } static gboolean fromEntry(GBinding *bind, const GValue *source_value, GValue *target_value, gpointer data _U_) { if (visu_gl_ext_node_vectors_getNormalisation(VISU_GL_EXT_NODE_VECTORS(g_binding_get_source(bind))) <= 0.f) return FALSE; g_value_set_float(target_value, g_value_get_double(source_value)); return TRUE; } static void onDestroy(GtkWidget *wd _U_, gpointer data _U_) { if (model) { g_signal_handler_disconnect(model, chg_sig); g_object_unref(model); } } /* Creates the vbox displayed in the config panel */ /** * visu_ui_panel_method_atomic_create: * @scene: a #VisuGlNodeScene object. * * Creates a widget with the options for atomic rendering. * * Since: 3.8 * * Returns: (transfer full): a newly create #GtkVBox object. **/ GtkWidget* visu_ui_panel_method_atomic_create(VisuGlNodeScene *scene) { GtkWidget *vbox, *wd, *hbox, *radio, *vbox2, *label; GSList *lst; VisuGlExtForces *forces; DBG_fprintf(stderr, "Gtk Atomic: building specific widgets for method.\n"); forces = visu_gl_node_scene_getForces(scene); vbox = gtk_vbox_new(FALSE, 0); checkForces = gtk_check_button_new_with_mnemonic (_("Display _forces (if available)")); g_object_bind_property(forces, "active", checkForces, "active", G_BINDING_SYNC_CREATE | G_BINDING_BIDIRECTIONAL); g_object_bind_property(forces, "model", checkForces, "sensitive", G_BINDING_SYNC_CREATE); gtk_box_pack_start(GTK_BOX(vbox), checkForces, FALSE, FALSE, 0); vbox2 = gtk_vbox_new(FALSE, 0); gtk_box_pack_start(GTK_BOX(vbox), vbox2, FALSE, FALSE, 0); wd = gtk_label_new(_("Policy to scale arrows:")); gtk_label_set_xalign(GTK_LABEL(wd), 0.); gtk_widget_set_margin_start(wd, 10); gtk_box_pack_start(GTK_BOX(vbox2), wd, FALSE, FALSE, 0); hbox = gtk_hbox_new(FALSE, 0); gtk_box_pack_start(GTK_BOX(vbox2), hbox, FALSE, FALSE, 0); radioScaleAuto = gtk_radio_button_new_with_label(NULL, _("automatic")); g_object_bind_property_full(forces, "normalisation", radioScaleAuto, "active", G_BINDING_SYNC_CREATE | G_BINDING_BIDIRECTIONAL, toAutoRadio, fromAutoRadio, (gpointer)0, (GDestroyNotify)0); gtk_radio_button_set_group(GTK_RADIO_BUTTON(radioScaleAuto), (GSList*)0); lst = gtk_radio_button_get_group(GTK_RADIO_BUTTON(radioScaleAuto)); gtk_box_pack_start(GTK_BOX(hbox), radioScaleAuto, TRUE, TRUE, 15); hbox = gtk_hbox_new(FALSE, 0); gtk_box_pack_start(GTK_BOX(vbox2), hbox, FALSE, FALSE, 0); radio = gtk_radio_button_new_with_label(NULL, _("manual")); gtk_radio_button_set_group(GTK_RADIO_BUTTON(radio), lst); g_object_bind_property_full(forces, "normalisation", radio, "active", G_BINDING_SYNC_CREATE | G_BINDING_BIDIRECTIONAL, toManualRadio, fromManualRadio, (gpointer)0, (GDestroyNotify)0); gtk_box_pack_start(GTK_BOX(hbox), radio, FALSE, FALSE, 15); entryScale = visu_ui_numerical_entry_new(1e-2); gtk_entry_set_width_chars(GTK_ENTRY(entryScale), 6); g_object_bind_property_full(forces, "normalisation", entryScale, "value", G_BINDING_SYNC_CREATE | G_BINDING_BIDIRECTIONAL, toEntry, fromEntry, (gpointer)0, (GDestroyNotify)0); gtk_box_pack_start(GTK_BOX(hbox), entryScale, FALSE, FALSE, 0); label = gtk_label_new(""); gtk_label_set_xalign(GTK_LABEL(label), 0.); gtk_box_pack_start(GTK_BOX(hbox), label, TRUE, TRUE, 5); g_signal_connect_object(forces, "notify::model", G_CALLBACK(modelNotified), label, G_CONNECT_SWAPPED); _setModel(label, VISU_NODE_VALUES_VECTOR(visu_sourceable_getNodeModel(VISU_SOURCEABLE(forces)))); gtk_widget_show_all(vbox); g_signal_connect(vbox, "destroy", G_CALLBACK(onDestroy), (gpointer)0); return vbox; } v_sim-3.8.0/src/panelModules/gtkAtomic.h000066400000000000000000000041121370110300500201350ustar00rootroot00000000000000/* EXTRAITS DE LA LICENCE Copyright CEA, contributeurs : Luc BILLARD et Damien CALISTE, laboratoire L_Sim, (2001-2005) Adresse mèl : BILLARD, non joignable par mèl ; CALISTE, damien P caliste AT cea P fr. Ce logiciel est un programme informatique servant à visualiser des structures atomiques dans un rendu pseudo-3D. Ce logiciel est régi par la licence CeCILL soumise au droit français et respectant les principes de diffusion des logiciels libres. Vous pouvez utiliser, modifier et/ou redistribuer ce programme sous les conditions de la licence CeCILL telle que diffusée par le CEA, le CNRS et l'INRIA sur le site "http://www.cecill.info". Le fait que vous puissiez accéder à cet en-tête signifie que vous avez pris connaissance de la licence CeCILL, et que vous en avez accepté les termes (cf. le fichier Documentation/licence.fr.txt fourni avec ce logiciel). */ /* LICENCE SUM UP Copyright CEA, contributors : Luc BILLARD et Damien CALISTE, laboratoire L_Sim, (2001-2005) E-mail address: BILLARD, not reachable any more ; CALISTE, damien P caliste AT cea P fr. This software is a computer program whose purpose is to visualize atomic configurations in 3D. This software is governed by the CeCILL license under French law and abiding by the rules of distribution of free software. You can use, modify and/ or redistribute the software under the terms of the CeCILL license as circulated by CEA, CNRS and INRIA at the following URL "http://www.cecill.info". The fact that you are presently reading this means that you have had knowledge of the CeCILL license and that you accept its terms. You can find a copy of this licence shipped with this software at Documentation/licence.en.txt. */ #ifndef ATOMIC_GTK_H #define ATOMIC_GTK_H /* This .h and .c give functions to create a gtk interface to adjust resources values introduced with the atomic render method. */ #include #include /***************/ /* Public part */ /***************/ GtkWidget* visu_ui_panel_method_atomic_create(VisuGlNodeScene *scene); #endif v_sim-3.8.0/src/panelModules/gtkSpin.c000066400000000000000000000437321370110300500176400ustar00rootroot00000000000000/* EXTRAITS DE LA LICENCE Copyright CEA, contributeurs : Luc BILLARD, Damien CALISTE, Olivier D'Astier, laboratoire L_Sim, (2001-2005) Adresses mèl : BILLARD, non joignable par mèl ; CALISTE, damien P caliste AT cea P fr. D'ASTIER, dastier AT iie P cnam P fr. Ce logiciel est un programme informatique servant à visualiser des structures atomiques dans un rendu pseudo-3D. Ce logiciel est régi par la licence CeCILL soumise au droit français et respectant les principes de diffusion des logiciels libres. Vous pouvez utiliser, modifier et/ou redistribuer ce programme sous les conditions de la licence CeCILL telle que diffusée par le CEA, le CNRS et l'INRIA sur le site "http://www.cecill.info". Le fait que vous puissiez accéder à cet en-tête signifie que vous avez pris connaissance de la licence CeCILL, et que vous en avez accepté les termes (cf. le fichier Documentation/licence.fr.txt fourni avec ce logiciel). */ /* LICENCE SUM UP Copyright CEA, contributors : Luc BILLARD and Damien CALISTE and Olivier D'Astier, laboratoire L_Sim, (2001-2005) E-mail addresses : BILLARD, not reachable any more ; CALISTE, damien P caliste AT cea P fr. D'ASTIER, dastier AT iie P cnam P fr. This software is a computer program whose purpose is to visualize atomic configurations in 3D. This software is governed by the CeCILL license under French law and abiding by the rules of distribution of free software. You can use, modify and/ or redistribute the software under the terms of the CeCILL license as circulated by CEA, CNRS and INRIA at the following URL "http://www.cecill.info". The fact that you are presently reading this means that you have had knowledge of the CeCILL license and that you accept its terms. You can find a copy of this licence shipped with this software at Documentation/licence.en.txt. */ #include "gtkSpin.h" #include #include #include #include #include #include #include #include #include "gtkAtomic.h" #include "panelElements.h" #include "panelMethod.h" #include #include #include #include /** * SECTION:gtkSpin * @short_description: The gtk interface elements that can interfere * with renderingSpin parameters. * * This is the gtk interface for all #VisuDataSpin module * parameters. They are split in two parts. The first part is placed * under the config tab and allows the user to modify the "global * properties" of the renderingSpin module such as cone's axe * orientation, and color repartition. The second part is under the * element panel and allows to modify each element resource. Size of * the arrows, and their shape can be modified. */ #define LABEL_ARROW_SIZE _("Shape size and color properties:") #define LABEL_SPIN_POLICY _("Drawing policy for spins with null modulus:") static void set_view(GtkWidget* button, gpointer data); /* A widget to select a shape for the arrows */ static GtkWidget *gtkw_cone_theta_angle = NULL; static GtkWidget *gtkw_cone_phi_angle = NULL; static GtkWidget *gtkw_color_wheel_angle = NULL; static GtkWidget *gtkw_x = NULL, *gtkw_y = NULL, *gtkw_z = NULL; static GtkWidget *gtkw_set_view; static GtkWidget *checkModulus, *checkAtomic; static GtkWidget *radioPerTypeMod, *radioGlobalMod; static GtkWidget *radioAlwaysSpin, *radioEmptySpin, *radioAtomicSpin; static gulong x_sig, y_sig, z_sig; static void _toSpherical(void) { gfloat cart[3], sph[3]; cart[0] = gtk_spin_button_get_value(GTK_SPIN_BUTTON(gtkw_x)); cart[1] = gtk_spin_button_get_value(GTK_SPIN_BUTTON(gtkw_y)); cart[2] = gtk_spin_button_get_value(GTK_SPIN_BUTTON(gtkw_z)); tool_matrix_cartesianToSpherical(sph, cart); gtk_spin_button_set_value(GTK_SPIN_BUTTON(gtkw_cone_theta_angle), sph[TOOL_MATRIX_SPHERICAL_THETA]); gtk_spin_button_set_value(GTK_SPIN_BUTTON(gtkw_cone_phi_angle), sph[TOOL_MATRIX_SPHERICAL_PHI]); } static void _fromSpherical(void) { gfloat cart[3], sph[3]; sph[TOOL_MATRIX_SPHERICAL_MODULUS] = 1.f; sph[TOOL_MATRIX_SPHERICAL_THETA] = gtk_spin_button_get_value(GTK_SPIN_BUTTON(gtkw_cone_theta_angle)); sph[TOOL_MATRIX_SPHERICAL_PHI] = gtk_spin_button_get_value(GTK_SPIN_BUTTON(gtkw_cone_phi_angle)); tool_matrix_sphericalToCartesian(cart, sph); g_signal_handler_block(gtkw_x, x_sig); gtk_spin_button_set_value(GTK_SPIN_BUTTON(gtkw_x), cart[0]); g_signal_handler_unblock(gtkw_x, x_sig); g_signal_handler_block(gtkw_y, y_sig); gtk_spin_button_set_value(GTK_SPIN_BUTTON(gtkw_y), cart[1]); g_signal_handler_unblock(gtkw_y, y_sig); g_signal_handler_block(gtkw_z, z_sig); gtk_spin_button_set_value(GTK_SPIN_BUTTON(gtkw_z), cart[2]); g_signal_handler_unblock(gtkw_z, z_sig); } /* Creates the hbox containing x,y,z spin buttons */ static GtkWidget *gtk_spin_create_direction() { GtkWidget *table; GtkWidget* label_x = gtk_label_new(_("x:")); GtkWidget* label_y = gtk_label_new(_("y:")); GtkWidget* label_z = gtk_label_new(_("z:")); GtkWidget* label_theta = gtk_label_new("\316\270:"); GtkWidget* label_phi = gtk_label_new("\317\206:"); #if GTK_MAJOR_VERSION == 2 && GTK_MINOR_VERSION < 12 GtkTooltips *tooltips; tooltips = gtk_tooltips_new(); #endif table = gtk_grid_new(); tool_grid_resize(tqble, 2, 6); gtk_label_set_xalign(GTK_LABEL(label_x), 1.); gtk_label_set_xalign(GTK_LABEL(label_y), 1.); gtk_label_set_xalign(GTK_LABEL(label_z), 1.); gtk_widget_set_hexpand(label_x, TRUE); gtk_widget_set_hexpand(label_y, TRUE); gtk_widget_set_hexpand(label_z, TRUE); gtkw_x = gtk_spin_button_new_with_range(-99.99, 99.99, 0.05); gtk_spin_button_set_value(GTK_SPIN_BUTTON(gtkw_x), 0.); gtkw_y = gtk_spin_button_new_with_range(-99.99, 99.99, 0.05); gtk_spin_button_set_value(GTK_SPIN_BUTTON(gtkw_y), 0.); gtkw_z = gtk_spin_button_new_with_range(-99.99, 99.99, 0.05); gtk_spin_button_set_value(GTK_SPIN_BUTTON(gtkw_z), 1.); gtk_grid_attach(GTK_GRID(table), label_x, 0, 0, 1, 1); gtk_grid_attach(GTK_GRID(table), label_y, 2, 0, 1, 1); gtk_grid_attach(GTK_GRID(table), label_z, 4, 0, 1, 1); gtk_grid_attach(GTK_GRID(table), gtkw_x, 1, 0, 1, 1); gtk_grid_attach(GTK_GRID(table), gtkw_y, 3, 0, 1, 1); gtk_grid_attach(GTK_GRID(table), gtkw_z, 5, 0, 1, 1); gtk_label_set_xalign(GTK_LABEL(label_theta), 1.); gtk_label_set_xalign(GTK_LABEL(label_phi), 1.); gtk_widget_set_hexpand(label_theta, TRUE); gtk_widget_set_hexpand(label_phi, TRUE); gtkw_cone_theta_angle = gtk_spin_button_new_with_range(0, 180., 3); gtkw_cone_phi_angle = gtk_spin_button_new_with_range(0, 360., 3); gtk_spin_button_set_wrap(GTK_SPIN_BUTTON(gtkw_cone_phi_angle), TRUE); gtkw_set_view = gtk_button_new_with_label(_("Set ortho.")); gtk_widget_set_tooltip_text(gtkw_set_view, _("Set the cone orientation to be orthogonal" " to the screen.")); g_signal_connect(gtkw_set_view, "clicked", G_CALLBACK(set_view), NULL); gtk_grid_attach(GTK_GRID(table), label_theta, 0, 1, 1, 1); gtk_grid_attach(GTK_GRID(table), label_phi, 2, 1, 1, 1); gtk_grid_attach(GTK_GRID(table), gtkw_cone_theta_angle, 1, 1, 1, 1); gtk_grid_attach(GTK_GRID(table), gtkw_cone_phi_angle, 3, 1, 1, 1); gtk_grid_attach(GTK_GRID(table), gtkw_set_view, 4, 1, 2, 1); x_sig = g_signal_connect(gtkw_x, "value-changed", G_CALLBACK(_toSpherical), (gpointer)0); y_sig = g_signal_connect(gtkw_y, "value-changed", G_CALLBACK(_toSpherical), (gpointer)0); z_sig = g_signal_connect(gtkw_z, "value-changed", G_CALLBACK(_toSpherical), (gpointer)0); g_signal_connect(gtkw_cone_theta_angle, "value-changed", G_CALLBACK(_fromSpherical), (gpointer)0); g_signal_connect(gtkw_cone_phi_angle, "value-changed", G_CALLBACK(_fromSpherical), (gpointer)0); return table; } /* Creates the hbox containing the color_wheel_angle button */ static GtkWidget *gtk_spin_create_color_wheel() { GtkWidget* hbox = gtk_hbox_new(FALSE, 0); GtkWidget* label = gtk_label_new(_("Rotate color wheel:")); gtk_label_set_xalign(GTK_LABEL(label), 0.); gtkw_color_wheel_angle = gtk_spin_button_new_with_range(0, 360., 3); gtk_spin_button_set_wrap(GTK_SPIN_BUTTON(gtkw_color_wheel_angle), TRUE); gtk_box_pack_start(GTK_BOX(hbox), label, TRUE, TRUE, 1); gtk_box_pack_start(GTK_BOX(hbox), gtkw_color_wheel_angle, FALSE, FALSE, 1); /* Degrees. */ label = gtk_label_new(_("deg.")); gtk_box_pack_start(GTK_BOX(hbox), label, FALSE, FALSE, 1); return hbox; } static GtkWidget* createHidingModeRadioWidgets() { GtkWidget *hbox; GSList *radiobutton_group; hbox = gtk_hbox_new(FALSE, 0); radioAlwaysSpin = gtk_radio_button_new_with_label(NULL, _("always")); gtk_radio_button_set_group(GTK_RADIO_BUTTON(radioAlwaysSpin), (GSList*)0); radiobutton_group = gtk_radio_button_get_group(GTK_RADIO_BUTTON(radioAlwaysSpin)); gtk_box_pack_start(GTK_BOX(hbox), radioAlwaysSpin, TRUE, TRUE, 1); radioEmptySpin = gtk_radio_button_new_with_label(NULL, _("never")); gtk_radio_button_set_group(GTK_RADIO_BUTTON(radioEmptySpin), radiobutton_group); radiobutton_group = gtk_radio_button_get_group(GTK_RADIO_BUTTON(radioEmptySpin)); gtk_box_pack_start(GTK_BOX(hbox), radioEmptySpin, TRUE, TRUE, 1); radioAtomicSpin = gtk_radio_button_new_with_label(NULL, _("atomic")); gtk_radio_button_set_group(GTK_RADIO_BUTTON(radioAtomicSpin), radiobutton_group); radiobutton_group = gtk_radio_button_get_group(GTK_RADIO_BUTTON(radioAtomicSpin)); gtk_box_pack_start(GTK_BOX(hbox), radioAtomicSpin, TRUE, TRUE, 1); return hbox; } static gboolean _fromModulus(GBinding *bind _U_, const GValue *source, GValue *target, gpointer data _U_) { g_value_set_boolean(target, g_value_get_uint(source) != VISU_METHOD_SPIN_CONSTANT); return TRUE; } static gboolean _toModulus(GBinding *bind _U_, const GValue *source, GValue *target, gpointer data _U_) { VisuMethodSpinModulusPolicy modPol; if (!g_value_get_boolean(source)) modPol = VISU_METHOD_SPIN_CONSTANT; else if (gtk_toggle_button_get_active(GTK_TOGGLE_BUTTON(radioPerTypeMod))) modPol = VISU_METHOD_SPIN_PER_TYPE; else if (gtk_toggle_button_get_active(GTK_TOGGLE_BUTTON(radioGlobalMod))) modPol = VISU_METHOD_SPIN_GLOBAL; else modPol = VISU_METHOD_SPIN_CONSTANT; g_value_set_uint(target, modPol); return TRUE; } static gboolean _fromType(GBinding *bind _U_, const GValue *source, GValue *target, gpointer data) { g_value_set_boolean(target, g_value_get_uint(source) == (guint)GPOINTER_TO_INT(data)); return TRUE; } static gboolean _toType(GBinding *bind _U_, const GValue *source, GValue *target, gpointer data) { if (!g_value_get_boolean(source)) return FALSE; g_value_set_uint(target, GPOINTER_TO_INT(data)); return TRUE; } static VisuMethodSpin *_spinModel = NULL; static GBinding *useModulus_bind, *usePerType_bind, *useGlobal_bind, *useAtomic_bind; static GBinding *useAlways_bind, *useNull_bind, *useAtom_bind; static GBinding *spinOmega_bind, *spinTheta_bind, *spinPhi_bind; static void _setModel(VisuMethodSpin *spin) { g_return_if_fail(!spin || VISU_IS_METHOD_SPIN(spin)); if (_spinModel) { g_object_unref(_spinModel); g_object_unref(useModulus_bind); g_object_unref(usePerType_bind); g_object_unref(useGlobal_bind); g_object_unref(useAtomic_bind); g_object_unref(useAlways_bind); g_object_unref(useNull_bind); g_object_unref(useAtom_bind); g_object_unref(spinTheta_bind); g_object_unref(spinPhi_bind); g_object_unref(spinOmega_bind); } if (spin) { g_object_ref(spin); useModulus_bind = g_object_bind_property_full (spin, "modulus-scaling", checkModulus, "active", G_BINDING_SYNC_CREATE | G_BINDING_BIDIRECTIONAL, _fromModulus, _toModulus, NULL, NULL); usePerType_bind = g_object_bind_property_full (spin, "modulus-scaling", radioPerTypeMod, "active", G_BINDING_SYNC_CREATE | G_BINDING_BIDIRECTIONAL, _fromType, _toType, GINT_TO_POINTER(VISU_METHOD_SPIN_PER_TYPE), NULL); useGlobal_bind = g_object_bind_property_full (spin, "modulus-scaling", radioGlobalMod, "active", G_BINDING_SYNC_CREATE | G_BINDING_BIDIRECTIONAL, _fromType, _toType, GINT_TO_POINTER(VISU_METHOD_SPIN_GLOBAL), NULL); useAtomic_bind = g_object_bind_property (spin, "use-atomic", checkAtomic, "active", G_BINDING_SYNC_CREATE | G_BINDING_BIDIRECTIONAL); useAlways_bind = g_object_bind_property_full (spin, "hiding-mode", radioAlwaysSpin, "active", G_BINDING_SYNC_CREATE | G_BINDING_BIDIRECTIONAL, _fromType, _toType, GINT_TO_POINTER(VISU_METHOD_SPIN_ALWAYS), NULL); useNull_bind = g_object_bind_property_full (spin, "hiding-mode", radioEmptySpin, "active", G_BINDING_SYNC_CREATE | G_BINDING_BIDIRECTIONAL, _fromType, _toType, GINT_TO_POINTER(VISU_METHOD_SPIN_HIDE_NULL), NULL); useAtom_bind = g_object_bind_property_full (spin, "hiding-mode", radioAtomicSpin, "active", G_BINDING_SYNC_CREATE | G_BINDING_BIDIRECTIONAL, _fromType, _toType, GINT_TO_POINTER(VISU_METHOD_SPIN_ATOMIC_NULL), NULL); spinTheta_bind = g_object_bind_property (spin, "cone-theta", gtkw_cone_theta_angle, "value", G_BINDING_SYNC_CREATE | G_BINDING_BIDIRECTIONAL); spinPhi_bind = g_object_bind_property (spin, "cone-phi", gtkw_cone_phi_angle, "value", G_BINDING_SYNC_CREATE | G_BINDING_BIDIRECTIONAL); spinOmega_bind = g_object_bind_property (spin, "cone-omega", gtkw_color_wheel_angle, "value", G_BINDING_SYNC_CREATE | G_BINDING_BIDIRECTIONAL); } _spinModel = spin; } /* Creates the vbox displayed in the config panel */ /** * visu_ui_panel_method_spin_create: * @scene: a #VisuGlNodeScene object. * * Creates a widget with the options for spin rendering. * * Since: 3.8 * * Returns: (transfer full): a newly create #GtkVBox object. **/ GtkWidget* visu_ui_panel_method_spin_create(VisuGlNodeScene *scene _U_) { GtkWidget *vbox = gtk_vbox_new(FALSE, 0); GtkWidget *label2 = gtk_label_new(_("Color cone orientation:")); GtkWidget *labelPolicy; GtkWidget *hbox, *label; GSList *radiobutton_group; DBG_fprintf(stderr, "Gtk Spin : building specific spin rendering method config widget.\n"); /* Use modulus. */ hbox = gtk_hbox_new(FALSE, 0); gtk_box_pack_start(GTK_BOX(vbox), hbox, FALSE, FALSE, 0); label = gtk_label_new(_("Spin lenght is proportional to modulus: ")); gtk_label_set_xalign(GTK_LABEL(label), 0.); gtk_widget_set_name(label, "label_head_2"); gtk_box_pack_start(GTK_BOX(hbox), label, FALSE, FALSE, 3); checkModulus = gtk_check_button_new(); gtk_box_pack_start(GTK_BOX(hbox), checkModulus, FALSE, FALSE, 10); hbox = gtk_hbox_new(FALSE, 0); radioPerTypeMod = gtk_radio_button_new_with_label(NULL, _("per node type")); gtk_radio_button_set_group(GTK_RADIO_BUTTON(radioPerTypeMod), (GSList*)0); radiobutton_group = gtk_radio_button_get_group(GTK_RADIO_BUTTON(radioPerTypeMod)); gtk_box_pack_start(GTK_BOX(hbox), radioPerTypeMod, TRUE, TRUE, 1); g_object_bind_property(checkModulus, "active", radioPerTypeMod, "sensitive", G_BINDING_SYNC_CREATE); radioGlobalMod = gtk_radio_button_new_with_label(NULL, _("globaly")); gtk_radio_button_set_group(GTK_RADIO_BUTTON(radioGlobalMod), radiobutton_group); radiobutton_group = gtk_radio_button_get_group(GTK_RADIO_BUTTON(radioGlobalMod)); gtk_box_pack_start(GTK_BOX(hbox), radioGlobalMod, TRUE, TRUE, 1); g_object_bind_property(checkModulus, "active", radioGlobalMod, "sensitive", G_BINDING_SYNC_CREATE); gtk_widget_show_all(hbox); gtk_box_pack_start(GTK_BOX(vbox), hbox, FALSE, FALSE, 0); /* Drawing atomic. */ hbox = gtk_hbox_new(FALSE, 0); gtk_box_pack_start(GTK_BOX(vbox), hbox, FALSE, FALSE, 0); label = gtk_label_new(_("Use atomic rendering in addition to spin: ")); gtk_label_set_xalign(GTK_LABEL(label), 0.); gtk_widget_set_name(label, "label_head_2"); gtk_box_pack_start(GTK_BOX(hbox), label, FALSE, FALSE, 3); checkAtomic = gtk_check_button_new(); gtk_box_pack_start(GTK_BOX(hbox), checkAtomic, FALSE, FALSE, 10); /* Drawing policy. */ labelPolicy = gtk_label_new(LABEL_SPIN_POLICY); gtk_label_set_xalign(GTK_LABEL(labelPolicy), 0.); gtk_widget_set_margin_start(labelPolicy, 3); gtk_widget_set_name(labelPolicy, "label_head_2"); gtk_box_pack_start(GTK_BOX(vbox), labelPolicy, FALSE, FALSE, 3); hbox = createHidingModeRadioWidgets(); gtk_box_pack_start(GTK_BOX(vbox), hbox, FALSE, FALSE, 0); label = gtk_label_new(""); gtk_label_set_markup(GTK_LABEL(label), _("Color distribution options:")); gtk_label_set_xalign(GTK_LABEL(label), 0.); gtk_widget_set_margin_start(label, 5); gtk_widget_set_name(label, "label_head_2"); gtk_box_pack_start(GTK_BOX(vbox), label, FALSE, FALSE, 3); hbox = gtk_spin_create_color_wheel(); gtk_box_pack_start(GTK_BOX(vbox), hbox, FALSE, FALSE, 3); gtk_box_pack_start(GTK_BOX(vbox), label2, FALSE, FALSE, 3); gtk_label_set_xalign(GTK_LABEL(label2), 0.); hbox = gtk_spin_create_direction(); gtk_box_pack_start(GTK_BOX(vbox), hbox, FALSE, FALSE, 3); _setModel(visu_method_spin_getDefault()); g_signal_connect_swapped(vbox, "destroy", G_CALLBACK(_setModel), (gpointer)0); gtk_widget_show_all(vbox); return vbox; } static void set_view(GtkWidget* button _U_, gpointer data _U_) { float theta; float phi; VisuGlView *view; view = visu_ui_panel_getView(VISU_UI_PANEL(VISU_UI_PANEL_ELEMENTS)); if (!view) return; theta = tool_modulo_float(view->camera.theta, 360); if(theta > 180) theta = 360 - theta; phi = tool_modulo_float(view->camera.phi, 360); gtk_spin_button_set_value(GTK_SPIN_BUTTON(gtkw_cone_theta_angle), theta); gtk_spin_button_set_value(GTK_SPIN_BUTTON(gtkw_cone_phi_angle), phi); } v_sim-3.8.0/src/panelModules/gtkSpin.h000066400000000000000000000042161370110300500176370ustar00rootroot00000000000000/* EXTRAITS DE LA LICENCE Copyright CEA, contributeurs : Luc BILLARD, Damien CALISTE, Olivier D'Astier, laboratoire L_Sim, (2001-2005) Adresses mèl : BILLARD, non joignable par mèl ; CALISTE, damien P caliste AT cea P fr. D'ASTIER, dastier AT iie P cnam P fr. Ce logiciel est un programme informatique servant à visualiser des structures atomiques dans un rendu pseudo-3D. Ce logiciel est régi par la licence CeCILL soumise au droit français et respectant les principes de diffusion des logiciels libres. Vous pouvez utiliser, modifier et/ou redistribuer ce programme sous les conditions de la licence CeCILL telle que diffusée par le CEA, le CNRS et l'INRIA sur le site "http://www.cecill.info". Le fait que vous puissiez accéder à cet en-tête signifie que vous avez pris connaissance de la licence CeCILL, et que vous en avez accepté les termes (cf. le fichier Documentation/licence.fr.txt fourni avec ce logiciel). */ /* LICENCE SUM UP Copyright CEA, contributors : Luc BILLARD and Damien CALISTE and Olivier D'Astier, laboratoire L_Sim, (2001-2005) E-mail addresses : BILLARD, not reachable any more ; CALISTE, damien P caliste AT cea P fr. D'ASTIER, dastier AT iie P cnam P fr. This software is a computer program whose purpose is to visualize atomic configurations in 3D. This software is governed by the CeCILL license under French law and abiding by the rules of distribution of free software. You can use, modify and/ or redistribute the software under the terms of the CeCILL license as circulated by CEA, CNRS and INRIA at the following URL "http://www.cecill.info". The fact that you are presently reading this means that you have had knowledge of the CeCILL license and that you accept its terms. You can find a copy of this licence shipped with this software at Documentation/licence.en.txt. */ #ifndef SPIN_GTK_H #define SPIN_GTK_H #include #include /** * visu_ui_panel_elements_spin_initMethod: (skip) * * Initialise the specific area in the config panel * for the spin rendering method. */ GtkWidget* visu_ui_panel_method_spin_create(VisuGlNodeScene *scene); #endif v_sim-3.8.0/src/panelModules/panelAxes.c000066400000000000000000000173011370110300500201320ustar00rootroot00000000000000/* EXTRAITS DE LA LICENCE Copyright CEA, contributeurs : Luc BILLARD et Damien CALISTE, laboratoire L_Sim, (2001-2005) Adresse mèl : BILLARD, non joignable par mèl ; CALISTE, damien P caliste AT cea P fr. Ce logiciel est un programme informatique servant à visualiser des structures atomiques dans un rendu pseudo-3D. Ce logiciel est régi par la licence CeCILL soumise au droit français et respectant les principes de diffusion des logiciels libres. Vous pouvez utiliser, modifier et/ou redistribuer ce programme sous les conditions de la licence CeCILL telle que diffusée par le CEA, le CNRS et l'INRIA sur le site "http://www.cecill.info". Le fait que vous puissiez accéder à cet en-tête signifie que vous avez pris connaissance de la licence CeCILL, et que vous en avez accepté les termes (cf. le fichier Documentation/licence.fr.txt fourni avec ce logiciel). */ /* LICENCE SUM UP Copyright CEA, contributors : Luc BILLARD et Damien CALISTE, laboratoire L_Sim, (2001-2005) E-mail address: BILLARD, not reachable any more ; CALISTE, damien P caliste AT cea P fr. This software is a computer program whose purpose is to visualize atomic configurations in 3D. This software is governed by the CeCILL license under French law and abiding by the rules of distribution of free software. You can use, modify and/ or redistribute the software under the terms of the CeCILL license as circulated by CEA, CNRS and INRIA at the following URL "http://www.cecill.info". The fact that you are presently reading this means that you have had knowledge of the CeCILL license and that you accept its terms. You can find a copy of this licence shipped with this software at Documentation/licence.en.txt. */ #include "panelAxes.h" #include #include #include #include #include #include /** * SECTION: panelAxes * @short_description: The tab where axes, box, scale and legend are * setup. * * Nothing tunable here. */ /* Sensitive widget in this subpanel. */ static GtkWidget *panelAxes = NULL; static GtkWidget *lineBox; static GtkWidget *lineAxes; static GtkWidget *lineScales; static GtkWidget *checkLegend; static GBinding *bind_legend = NULL; /* Private functions. */ static GtkWidget *createInteriorAxes(VisuGlNodeScene *scene); /* Local callbacks. */ /** * visu_ui_panel_axes_init: * @main: a #VisuUiMain object. * * This routine will create the #VisuUiPanel where the axes and the * label stuffs can be tuned, such as their colour, create scales... * * Returns: (transfer full): the #VisuUiPanel object dealing with axes. */ VisuUiPanel* visu_ui_panel_axes_init(VisuUiMain *main) { VisuGlNodeScene *scene; if (panelAxes) { g_object_ref(G_OBJECT(panelAxes)); return VISU_UI_PANEL(panelAxes); } panelAxes = visu_ui_panel_newWithIconFromPath("Panel_axes", _("Box, axes and labels"), _("Frames/labels"), "stock-axes_20.png"); g_return_val_if_fail(panelAxes, (VisuUiPanel*)0); scene = visu_ui_rendering_window_getGlScene(visu_ui_main_getRendering(main)); gtk_container_add(GTK_CONTAINER(panelAxes), createInteriorAxes(scene)); visu_ui_panel_setDockable(VISU_UI_PANEL(panelAxes), TRUE); g_object_ref(panelAxes); DBG_fprintf(stderr, "Panel Axes: new panel with ref count %d\n", G_OBJECT(panelAxes)->ref_count); return VISU_UI_PANEL(panelAxes); } /** * visu_ui_panel_axes_setAxesExtension: * @axes: (transfer full) (allow-none): a #VisuGlExtAxes object. * * Set the current axes extension handled by this #VisuUiPanel. * * Since: 3.7 **/ void visu_ui_panel_axes_setAxesExtension(VisuGlExtAxes *axes) { visu_ui_axes_bind(VISU_UI_AXES(lineAxes), axes); } /** * visu_ui_panel_axes_setBoxExtension: * @box: (transfer full) (allow-none): a #VisuGlExtBox object. * @legend: (transfer full) (allow-none): a #VisuGlExtBoxLegend object. * * Set the current box extension handled by this #VisuUiPanel. * * Since: 3.8 **/ void visu_ui_panel_axes_setBoxExtension(VisuGlExtBox *box, VisuGlExtBoxLegend *legend) { visu_ui_box_bind(VISU_UI_BOX(lineBox), box); visu_ui_box_bindLegend(VISU_UI_BOX(lineBox), legend); } /** * visu_ui_panel_axes_setLegendExtension: * @legend: (transfer full) (allow-none): a #VisuGlExtLegend object. * * Set the current legend extension handled by this #VisuUiPanel. * To be activated later ... * * Since: 3.8 **/ static void visu_ui_panel_axes_setLegendExtension(VisuGlExtLegend *legend) { if (bind_legend) g_object_unref(bind_legend); if (legend) bind_legend = g_object_bind_property(legend, "active", checkLegend, "active", G_BINDING_BIDIRECTIONAL | G_BINDING_SYNC_CREATE); } /** * visu_ui_panel_axes_setScaleExtension: * @scale: (transfer full) (allow-none): a #VisuGlExtScale object. * * Set the current scale extension handled by this #VisuUiPanel. * * Since: 3.8 **/ void visu_ui_panel_axes_setScaleExtension(VisuGlExtScale *scale) { visu_ui_scale_bind(VISU_UI_SCALE(lineScales), scale); } static GtkWidget *createInteriorAxes(VisuGlNodeScene *scene) { GtkWidget *vbox, *hbox, *scrollView; GtkWidget *label; scrollView = gtk_scrolled_window_new((GtkAdjustment*)0, (GtkAdjustment*)0); gtk_scrolled_window_set_policy(GTK_SCROLLED_WINDOW(scrollView), GTK_POLICY_AUTOMATIC, GTK_POLICY_AUTOMATIC); gtk_scrolled_window_set_shadow_type(GTK_SCROLLED_WINDOW(scrollView), GTK_SHADOW_NONE); vbox = gtk_vbox_new(FALSE, 0); gtk_widget_set_margin_top(vbox, 5); gtk_widget_set_margin_start(vbox, 5); gtk_widget_set_margin_end(vbox, 5); #if GTK_MAJOR_VERSION < 3 || (GTK_MAJOR_VERSION == 3 && GTK_MINOR_VERSION < 8) gtk_scrolled_window_add_with_viewport(GTK_SCROLLED_WINDOW(scrollView), vbox); #else gtk_container_add(GTK_CONTAINER(scrollView), vbox); #endif /*********************/ /* The Bounding box. */ /*********************/ lineBox = visu_ui_box_new(); gtk_box_pack_start(GTK_BOX(vbox), lineBox, FALSE, FALSE, 0); visu_ui_panel_axes_setBoxExtension(visu_gl_node_scene_getBox(scene), visu_gl_node_scene_getBoxLegend(scene)); /*************/ /* The Axes. */ /*************/ lineAxes = visu_ui_axes_new(); gtk_widget_set_margin_top(lineAxes, 15); gtk_box_pack_start(GTK_BOX(vbox), lineAxes, FALSE, FALSE, 0); visu_ui_panel_axes_setAxesExtension(visu_gl_node_scene_getAxes(scene)); g_object_bind_property(scene, "axes-from-box", visu_ui_axes_getBasisCheckButton(VISU_UI_AXES(lineAxes)), "active", G_BINDING_SYNC_CREATE | G_BINDING_BIDIRECTIONAL); /**************/ /* The legend */ /**************/ hbox = gtk_hbox_new(FALSE, 0); gtk_widget_set_margin_top(hbox, 15); gtk_box_pack_start(GTK_BOX(vbox), hbox, FALSE, FALSE, 0); /* The drawn checkbox. */ checkLegend = gtk_check_button_new(); gtk_box_pack_start(GTK_BOX(hbox), checkLegend, FALSE, FALSE, 0); /* The label. */ label = gtk_label_new(_("Legend")); gtk_label_set_use_markup(GTK_LABEL(label), TRUE); gtk_label_set_xalign(GTK_LABEL(label), 0.); gtk_widget_set_name(label, "label_head"); gtk_box_pack_start(GTK_BOX(hbox), label, FALSE, FALSE, 2); visu_ui_panel_axes_setLegendExtension(visu_gl_node_scene_getLegend(scene)); /*************************/ /* Adding scale widgets. */ /*************************/ lineScales = visu_ui_scale_new(); gtk_widget_set_margin_top(lineScales, 15); gtk_box_pack_start(GTK_BOX(vbox), lineScales, FALSE, FALSE, 0); visu_ui_panel_axes_setScaleExtension(visu_gl_node_scene_getScales(scene)); gtk_widget_show_all(scrollView); return scrollView; } v_sim-3.8.0/src/panelModules/panelAxes.h000066400000000000000000000045131370110300500201400ustar00rootroot00000000000000/* EXTRAITS DE LA LICENCE Copyright CEA, contributeurs : Luc BILLARD et Damien CALISTE, laboratoire L_Sim, (2001-2014) Adresse mèl : BILLARD, non joignable par mèl ; CALISTE, damien P caliste AT cea P fr. Ce logiciel est un programme informatique servant à visualiser des structures atomiques dans un rendu pseudo-3D. Ce logiciel est régi par la licence CeCILL soumise au droit français et respectant les principes de diffusion des logiciels libres. Vous pouvez utiliser, modifier et/ou redistribuer ce programme sous les conditions de la licence CeCILL telle que diffusée par le CEA, le CNRS et l'INRIA sur le site "http://www.cecill.info". Le fait que vous puissiez accéder à cet en-tête signifie que vous avez pris connaissance de la licence CeCILL, et que vous en avez accepté les termes (cf. le fichier Documentation/licence.fr.txt fourni avec ce logiciel). */ /* LICENCE SUM UP Copyright CEA, contributors : Luc BILLARD et Damien CALISTE, laboratoire L_Sim, (2001-2014) E-mail address: BILLARD, not reachable any more ; CALISTE, damien P caliste AT cea P fr. This software is a computer program whose purpose is to visualize atomic configurations in 3D. This software is governed by the CeCILL license under French law and abiding by the rules of distribution of free software. You can use, modify and/ or redistribute the software under the terms of the CeCILL license as circulated by CEA, CNRS and INRIA at the following URL "http://www.cecill.info". The fact that you are presently reading this means that you have had knowledge of the CeCILL license and that you accept its terms. You can find a copy of this licence shipped with this software at Documentation/licence.en.txt. */ #ifndef PANELAXES_H #define PANELAXES_H #include #include #include #include #include #include #include VisuUiPanel* visu_ui_panel_axes_init(VisuUiMain *main); void visu_ui_panel_axes_setAxesExtension(VisuGlExtAxes *axes); void visu_ui_panel_axes_setBoxExtension(VisuGlExtBox *box, VisuGlExtBoxLegend *legend); /* void visu_ui_panel_axes_setLegendExtension(VisuGlExtLegend *legend); */ void visu_ui_panel_axes_setScaleExtension(VisuGlExtScale *scale); #endif v_sim-3.8.0/src/panelModules/panelBrowser.c000066400000000000000000002276661370110300500206760ustar00rootroot00000000000000/* EXTRAITS DE LA LICENCE Copyright CEA, contributeurs : Luc BILLARD et Damien CALISTE, laboratoire L_Sim, (2001-2005) Adresse mèl : BILLARD, non joignable par mèl ; CALISTE, damien P caliste AT cea P fr. Ce logiciel est un programme informatique servant à visualiser des structures atomiques dans un rendu pseudo-3D. Ce logiciel est régi par la licence CeCILL soumise au droit français et respectant les principes de diffusion des logiciels libres. Vous pouvez utiliser, modifier et/ou redistribuer ce programme sous les conditions de la licence CeCILL telle que diffusée par le CEA, le CNRS et l'INRIA sur le site "http://www.cecill.info". Le fait que vous puissiez accéder à cet en-tête signifie que vous avez pris connaissance de la licence CeCILL, et que vous en avez accepté les termes (cf. le fichier Documentation/licence.fr.txt fourni avec ce logiciel). */ /* LICENCE SUM UP Copyright CEA, contributors : Luc BILLARD et Damien CALISTE, laboratoire L_Sim, (2001-2005) E-mail address: BILLARD, not reachable any more ; CALISTE, damien P caliste AT cea P fr. This software is a computer program whose purpose is to visualize atomic configurations in 3D. This software is governed by the CeCILL license under French law and abiding by the rules of distribution of free software. You can use, modify and/ or redistribute the software under the terms of the CeCILL license as circulated by CEA, CNRS and INRIA at the following URL "http://www.cecill.info". The fact that you are presently reading this means that you have had knowledge of the CeCILL license and that you accept its terms. You can find a copy of this licence shipped with this software at Documentation/licence.en.txt. */ #include "panelBrowser.h" #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include /** * SECTION: panelBrowser * @short_description: A tab to view a list of files and quickly * change from one to another. * * One can display a message about the file list by calling * visu_ui_panel_browser_setMessage(). It is possible also to change * the browser directory or directories with * visu_ui_panel_browser_setCurrentDirectory(). */ static GtkWidget *panelBrowser, *vbox1; static GtkTreeStore *treeStoreFiles; static GtkTreeModel *treeStoreFilesFilter; enum { COLUMN_BOOLEAN, /* Rendered or not. */ COLUMN_NAME, /* File name in locale of the file system. */ COLUMN_NAME_UTF8, /* File name in UTF8 (to view it in GTK). */ COLUMN_DATE, /* The modified time for the file. */ COLUMN_DATA, /* File info (size / date). */ COLUMN_ACTIVE, /* A boolean to set if this file is filtered or not. */ COLUMN_FILE_KIND, /* An integer that correspond to the file type. */ COLUMN_FILE_VALID, /* TRUE if the file is parsable. */ COLUMN_FILE_ERROR_ID, /* a stock icon id. */ N_COLUMNS }; static gboolean dirDirty; static GtkWidget *fileTree; static GtkWidget *scrolledwindow1, *infoBar, *labelInfo; static GtkWidget *labelDirectory; #if GTK_MAJOR_VERSION == 2 && GTK_MINOR_VERSION < 17 static GtkWidget *infoImg; #endif /* A list of array of directory names and the current position in the list. */ static GList *historyBrowseredDirectory, *currentHistory; /* A NULL terminated array of directories names, currently printed. */ static gchar **currentBrowseredDirectory; /* The string common to all paths in currentBrowseredDirectory. */ static gchar *commonBrowseredDirectory; #define HISTORY_TOOLTIP_PREV "Go to previously visited directories in history." #define HISTORY_TOOLTIP_NEXT "Go to next visited directories in history." static GtkWidget *entryFilterBrowser; enum { PANEL_BROWSER_COLUMN_FILTER_LABEL, PANEL_BROWSER_COLUMN_FILTER_ID, PANEL_BROWSER_N_COLUMN_FILTER }; static GtkWidget *comboFilter; struct TimerInfo_ { GtkWidget *bt; guint timer, label, nbFiles; gboolean abort; }; static GtkWidget *imagePlay; static GtkWidget *imageStop; static GtkWidget *buttonPlayStop; static GtkWidget *spinDelay; static GtkWidget *buttonPrevious; static GtkWidget *buttonNext; static GtkWidget *buttonDirPrev; static GtkWidget *buttonDirNext; static GtkWidget *buttonSelectAll; static GtkWidget *buttonUnselectAll; static GtkWidget *buttonDirectory; static GtkWidget *buttonRecurse; static GtkWidget *radioGoAround, *radioGoOnce, *radioGoAndBack; static int currentBrowseDirection; static GtkTreePath *startBrowsePath; static GtkWidget *buttonDumpAll; /* GtkProgressBar *progressBarDump; */ static GtkWidget *createInteriorBrowser(); static void browseDirectory(); static void addParsedDirectory(int commonPathLen, const gchar *root, GDir *gdir, gboolean recurse, GList *atFmt, gint atKind, GList *spFmt, gint spKind, struct TimerInfo_ *timer); static gboolean showProgressBar(gpointer data); static void hideProgressBar(struct TimerInfo_ *timer); /* Load and render the given file. The iter is given in the filter model. */ static gboolean browserLoad(gchar *filename, gchar* fileUTF8, GtkTreeIter *iter, int nSet); /* For the given iter load it. The iter must be given in the filter model. */ static gboolean navigateInFiles(GtkTreePath *path, GtkTreeIter *iterSelected); static void selectFile(GtkTreePath *path, GtkTreeIter *iter); gboolean gtk_tree_model_get_iter_last(GtkTreeModel *model, GtkTreeIter *last, GtkTreePath **path); void panelBrowserSet_labelCurrentDir(); /* Callbacks */ static void onCheckFile(GtkCellRendererToggle *cell_renderer, gchar *path, gpointer user_data); static void onTreeviewActivated(GtkTreeView *treeview, GtkTreePath *path, GtkTreeViewColumn *col, gpointer user_data); static void navigateClicked(GtkButton *button, gpointer data); static void checkFiles(GtkButton *button, gpointer data); static void onDirectoryClicked(GtkButton *button, gpointer data); static void onPlayStopClicked(GtkToggleButton *button _U_, gpointer data _U_); static void stopPlayStop(gpointer data); static void onSpinDelayChangeValue(GtkSpinButton *spinbutton, gpointer user_data); void onDumpButtonClicked(GtkButton *button, gpointer user_data); static void onFilterChanged(GtkEditable *entry, gpointer user_data); void abortDumpAll(GtkButton *button, gpointer data); void updateDumpAllProgressBar(gpointer data); static gboolean panelBrowserIsIterVisible(GtkTreeModel *model, GtkTreeIter *iter, gpointer data); static void onRefreshDir(GtkButton *button, gpointer data); static void onEnter(VisuUiPanel *visu_ui_panel, gpointer data); static gboolean checkFile(GtkTreeModel *model, GtkTreePath *path, GtkTreeIter *iter, gpointer data); #if GTK_MAJOR_VERSION == 2 && GTK_MINOR_VERSION < 17 static void onParseAbortClicked(GtkButton *button, gpointer data); #else static void onParseAbortClicked(GtkInfoBar *infoBar, gint response, gpointer data); #endif static void onRecurseToggled(GtkToggleButton *toggle, gpointer data); static void onNewDir(GObject *obj, VisuUiDirectoryType type, gpointer userData); static void onPrevClicked(GtkButton *button, gpointer data); static void onNextClicked(GtkButton *button, gpointer data); static gint onSortNames(GtkTreeModel *model, GtkTreeIter *a, GtkTreeIter *b, gpointer user_data); static void onNextPrevFile(VisuUiRenderingWindow *window, gpointer data); static void updateHistory(); static void updateDirectionalTooltips(); /* Parameters customising the dialog. */ #define FLAG_PARAMETER_BROWSER_HEADERS "browser_headersVisibility" #define DESC_PARAMETER_BROWSER_HEADERS "Show or hide the headers in the treeview ; boolean 0 or 1" static gboolean showHeaders; #define FLAG_PARAMETER_BROWSER_DATE "browser_dateVisibility" #define DESC_PARAMETER_BROWSER_DATE "Show or hide the date column in the treeview ; boolean 0 or 1" static gboolean showDate; static void exportParameters(GString *data, VisuData *dataObj); VisuUiPanel* visu_ui_panel_browser_init(VisuUiMain *ui) { char *cl = _("Browser"); char *tl = _("Browser"); VisuConfigFileEntry *entry; panelBrowser = visu_ui_panel_newWithIconFromPath("Panel_browser", cl, tl, "stock-browser_20.png"); if (!panelBrowser) return (VisuUiPanel*)0; vbox1 = gtk_vbox_new(FALSE, 0); fileTree = (GtkWidget*)0; buttonDirPrev = (GtkWidget*)0; buttonDirNext = (GtkWidget*)0; gtk_container_add(GTK_CONTAINER(panelBrowser), vbox1); gtk_container_set_border_width(GTK_CONTAINER(panelBrowser), 5); visu_ui_panel_setDockable(VISU_UI_PANEL(panelBrowser), TRUE); /* Create the configuration file entries. */ entry = visu_config_file_addBooleanEntry(VISU_CONFIG_FILE_PARAMETER, FLAG_PARAMETER_BROWSER_HEADERS, DESC_PARAMETER_BROWSER_HEADERS, &showHeaders, FALSE); visu_config_file_entry_setVersion(entry, 3.5f); entry = visu_config_file_addBooleanEntry(VISU_CONFIG_FILE_PARAMETER, FLAG_PARAMETER_BROWSER_DATE, DESC_PARAMETER_BROWSER_DATE, &showDate, FALSE); visu_config_file_entry_setVersion(entry, 3.5f); visu_config_file_addExportFunction(VISU_CONFIG_FILE_PARAMETER, exportParameters); /* Create the tree structure. */ treeStoreFiles = gtk_tree_store_new(N_COLUMNS, G_TYPE_BOOLEAN, G_TYPE_STRING, G_TYPE_STRING, G_TYPE_UINT, G_TYPE_STRING, G_TYPE_BOOLEAN, G_TYPE_INT, G_TYPE_BOOLEAN, G_TYPE_STRING); /* Use the COLUMN_ACTIVE as a flag to hide or not the rows that don't match the filter value. */ treeStoreFilesFilter = gtk_tree_model_filter_new(GTK_TREE_MODEL(treeStoreFiles), NULL); gtk_tree_model_filter_set_visible_func(GTK_TREE_MODEL_FILTER(treeStoreFilesFilter), panelBrowserIsIterVisible, (gpointer)0, (GDestroyNotify)0); /* gtk_tree_model_filter_set_visible_column(GTK_TREE_MODEL_FILTER(treeStoreFilesFilter), COLUMN_ACTIVE); */ gtk_tree_sortable_set_sort_func(GTK_TREE_SORTABLE(treeStoreFiles), COLUMN_NAME_UTF8, onSortNames, (gpointer)0, (GDestroyNotify)0); /* Add a new row to the model */ gtk_tree_sortable_set_sort_column_id(GTK_TREE_SORTABLE(treeStoreFiles), COLUMN_NAME_UTF8, GTK_SORT_ASCENDING); /* Initialise the values. */ currentBrowseredDirectory = (gchar**)0; commonBrowseredDirectory = (gchar*)0; historyBrowseredDirectory = (GList*)0; currentHistory = (GList*)0; currentBrowseDirection = VISU_UI_PANEL_BROWSER_NEXT; showHeaders = FALSE; showDate = FALSE; dirDirty = FALSE; /* Create the callbacks of all the sensitive widgets. */ g_signal_connect(G_OBJECT(panelBrowser), "page-entered", G_CALLBACK(onEnter), (gpointer)0); g_signal_connect(ui, "DirectoryChanged", G_CALLBACK(onNewDir), (gpointer)0); g_signal_connect(G_OBJECT(visu_ui_main_class_getDefaultRendering()), "load-next-file", G_CALLBACK(onNextPrevFile), GINT_TO_POINTER(VISU_UI_PANEL_BROWSER_NEXT)); g_signal_connect(G_OBJECT(visu_ui_main_class_getDefaultRendering()), "load-prev-file", G_CALLBACK(onNextPrevFile), GINT_TO_POINTER(VISU_UI_PANEL_BROWSER_PREVIOUS)); return VISU_UI_PANEL(panelBrowser); } static GtkWidget *createInteriorBrowser() { /* include from glade */ GtkWidget *image2; GtkWidget *image3; GtkWidget *image1; GtkWidget *hbox2; GtkWidget *label4; GtkWidget *label1; GtkWidget *hbox5; GtkWidget *image4; GtkWidget *refreshDirButton; GtkCellRenderer *renderer; GtkTreeViewColumn *column; GtkWidget *label; GtkWidget *hbox, *vbox; #if GTK_MAJOR_VERSION == 2 && GTK_MINOR_VERSION < 12 GtkTooltips *tooltips; tooltips = gtk_tooltips_new (); #endif GSList *radiobuttonCycle_group; hbox = gtk_hbox_new(FALSE, 0); gtk_box_pack_start(GTK_BOX(vbox1), hbox, FALSE, FALSE, 0); /* This is a label in the browser panel to introduce the entry that allows to enter a filter for files shown. */ label = gtk_label_new(_("Filter: ")); gtk_box_pack_start(GTK_BOX(hbox), label, FALSE, FALSE, 2); entryFilterBrowser = gtk_entry_new(); gtk_editable_set_editable(GTK_EDITABLE(entryFilterBrowser), TRUE); gtk_entry_set_text(GTK_ENTRY(entryFilterBrowser), "*"); gtk_box_pack_start(GTK_BOX(hbox), entryFilterBrowser, TRUE, TRUE, 0); comboFilter = gtk_combo_box_text_new(); gtk_combo_box_text_append(GTK_COMBO_BOX_TEXT(comboFilter), "atomic", _("atomic rendering")); gtk_combo_box_text_append(GTK_COMBO_BOX_TEXT(comboFilter), "spin", _("spin rendering")); gtk_combo_box_text_append(GTK_COMBO_BOX_TEXT(comboFilter), "spin_at", _("atomic part")); gtk_combo_box_text_append(GTK_COMBO_BOX_TEXT(comboFilter), "spin_sp", _("spin part")); gtk_box_pack_start(GTK_BOX(hbox), comboFilter, FALSE, FALSE, 2); gtk_combo_box_set_active(GTK_COMBO_BOX(comboFilter), 0); /*******************/ /* File lists part */ /*******************/ hbox = gtk_hbox_new(FALSE, 0); gtk_box_pack_start(GTK_BOX(vbox1), hbox, TRUE, TRUE, 0); vbox = gtk_vbox_new (FALSE, 0); gtk_box_pack_start(GTK_BOX(hbox), vbox, FALSE, FALSE, 2); buttonDirectory = gtk_button_new (); gtk_box_pack_start (GTK_BOX (vbox), buttonDirectory, FALSE, FALSE, 1); gtk_widget_set_tooltip_text(buttonDirectory, _("Choose a different directory.")); image3 = gtk_image_new_from_icon_name("document-open", GTK_ICON_SIZE_BUTTON); gtk_container_add (GTK_CONTAINER (buttonDirectory), image3); refreshDirButton = gtk_button_new (); gtk_widget_set_tooltip_text(refreshDirButton, _("Rescan current directory.")); gtk_box_pack_start(GTK_BOX(vbox), refreshDirButton, FALSE, FALSE, 1); image3 = gtk_image_new_from_icon_name("view-refresh", GTK_ICON_SIZE_BUTTON); gtk_container_add(GTK_CONTAINER(refreshDirButton), image3); g_signal_connect(G_OBJECT(refreshDirButton), "clicked", G_CALLBACK(onRefreshDir), (gpointer)entryFilterBrowser); buttonRecurse = gtk_toggle_button_new(); gtk_widget_set_tooltip_text(buttonRecurse, _("Read directories recursively.")); gtk_box_pack_start(GTK_BOX(vbox), buttonRecurse, FALSE, FALSE, 1); image3 = gtk_image_new_from_icon_name("zoom-in", GTK_ICON_SIZE_BUTTON); gtk_container_add(GTK_CONTAINER(buttonRecurse), image3); g_signal_connect(G_OBJECT(buttonRecurse), "toggled", G_CALLBACK(onRecurseToggled), (gpointer)entryFilterBrowser); buttonDirPrev = gtk_button_new(); gtk_widget_set_sensitive(buttonDirPrev, FALSE); gtk_widget_set_tooltip_text(buttonDirPrev, _(HISTORY_TOOLTIP_PREV)); gtk_box_pack_start(GTK_BOX(vbox), buttonDirPrev, FALSE, FALSE, 1); image3 = gtk_image_new_from_icon_name("go-previous", GTK_ICON_SIZE_BUTTON); gtk_container_add(GTK_CONTAINER(buttonDirPrev), image3); g_signal_connect(G_OBJECT(buttonDirPrev), "clicked", G_CALLBACK(onPrevClicked), (gpointer)0); buttonDirNext = gtk_button_new(); gtk_widget_set_sensitive(buttonDirNext, FALSE); gtk_widget_set_tooltip_text(buttonDirNext, _(HISTORY_TOOLTIP_NEXT)); gtk_box_pack_start(GTK_BOX(vbox), buttonDirNext, FALSE, FALSE, 1); image3 = gtk_image_new_from_icon_name("go-next", GTK_ICON_SIZE_BUTTON); gtk_container_add(GTK_CONTAINER(buttonDirNext), image3); g_signal_connect(G_OBJECT(buttonDirNext), "clicked", G_CALLBACK(onNextClicked), (gpointer)0); #if GTK_MAJOR_VERSION > 2 || GTK_MINOR_VERSION > 5 label = gtk_label_new(_("Dir.:")); gtk_label_set_angle(GTK_LABEL(label), 90.); gtk_box_pack_end(GTK_BOX(vbox), label, TRUE, TRUE, 0); #endif /* The infobar for cancel if to long and other messages. */ vbox = gtk_vbox_new(FALSE, 3); gtk_box_pack_start(GTK_BOX(hbox), vbox, TRUE, TRUE, 0); labelInfo = gtk_label_new(""); gtk_label_set_xalign(GTK_LABEL(labelInfo), 0.); #if GTK_MAJOR_VERSION > 2 || GTK_MINOR_VERSION > 17 infoBar = gtk_info_bar_new(); gtk_container_add(GTK_CONTAINER(gtk_info_bar_get_content_area(GTK_INFO_BAR(infoBar))), labelInfo); #else infoBar = gtk_hbox_new(FALSE, 5); infoImg = gtk_image_new_from_stock(GTK_STOCK_INFO, GTK_ICON_SIZE_MENU); gtk_box_pack_start(GTK_BOX(infoBar), infoImg, FALSE, FALSE, 0); gtk_box_pack_start(GTK_BOX(infoBar), labelInfo, TRUE, TRUE, 0); #endif gtk_widget_set_no_show_all(infoBar, TRUE); gtk_box_pack_start(GTK_BOX(vbox), infoBar, FALSE, FALSE, 0); scrolledwindow1 = gtk_scrolled_window_new (NULL, NULL); gtk_box_pack_start(GTK_BOX(vbox), scrolledwindow1, TRUE, TRUE, 0); gtk_scrolled_window_set_policy(GTK_SCROLLED_WINDOW(scrolledwindow1), GTK_POLICY_AUTOMATIC, GTK_POLICY_ALWAYS); gtk_scrolled_window_set_shadow_type(GTK_SCROLLED_WINDOW(scrolledwindow1), GTK_SHADOW_ETCHED_IN); fileTree = gtk_tree_view_new (); gtk_widget_set_tooltip_text(fileTree, _("Double click on a file to render it.")); gtk_container_add (GTK_CONTAINER (scrolledwindow1), fileTree); gtk_tree_view_set_headers_visible(GTK_TREE_VIEW(fileTree), showHeaders); renderer = gtk_cell_renderer_toggle_new (); g_signal_connect(G_OBJECT(renderer), "toggled", G_CALLBACK(onCheckFile), (gpointer)0); column = gtk_tree_view_column_new_with_attributes ("", renderer, "active", COLUMN_BOOLEAN, "sensitive", COLUMN_FILE_VALID, "activatable", COLUMN_FILE_VALID, NULL); gtk_tree_view_append_column (GTK_TREE_VIEW (fileTree), column); column = gtk_tree_view_column_new(); gtk_tree_view_column_set_title(GTK_TREE_VIEW_COLUMN(column), _("File")); renderer = gtk_cell_renderer_text_new (); gtk_tree_view_column_pack_end(GTK_TREE_VIEW_COLUMN(column), renderer, TRUE); gtk_tree_view_column_set_attributes(GTK_TREE_VIEW_COLUMN(column), renderer, "markup", COLUMN_NAME_UTF8, "sensitive", COLUMN_FILE_VALID, NULL); renderer = gtk_cell_renderer_pixbuf_new(); gtk_tree_view_column_pack_start(GTK_TREE_VIEW_COLUMN(column), renderer, FALSE); gtk_tree_view_column_set_attributes(GTK_TREE_VIEW_COLUMN(column), renderer, "icon-name", COLUMN_FILE_ERROR_ID, NULL); gtk_tree_view_column_set_sort_column_id(column, COLUMN_NAME_UTF8); gtk_tree_view_column_set_expand(column, TRUE); gtk_tree_view_append_column(GTK_TREE_VIEW (fileTree), column); if (showDate) { renderer = gtk_cell_renderer_text_new (); column = gtk_tree_view_column_new_with_attributes (_("Date"), renderer, "text", COLUMN_DATA, "sensitive", COLUMN_FILE_VALID, NULL); gtk_tree_view_column_set_sort_column_id(column, COLUMN_DATE); gtk_tree_view_append_column (GTK_TREE_VIEW (fileTree), column); } gtk_tree_selection_set_mode(gtk_tree_view_get_selection(GTK_TREE_VIEW(fileTree)), GTK_SELECTION_SINGLE); vbox = gtk_vbox_new (FALSE, 0); gtk_box_pack_start(GTK_BOX(hbox), vbox, FALSE, FALSE, 2); buttonUnselectAll = gtk_button_new(); gtk_widget_set_tooltip_text(buttonUnselectAll, _("Unselect all files.")); gtk_box_pack_start(GTK_BOX(vbox), buttonUnselectAll, FALSE, FALSE, 1); image2 = create_pixmap ((GtkWidget*)0, "stock-unselect-all_20.png"); gtk_container_add(GTK_CONTAINER(buttonUnselectAll), image2); buttonSelectAll = gtk_button_new(); gtk_widget_set_tooltip_text(buttonSelectAll, _("Select all files.")); gtk_box_pack_start(GTK_BOX (vbox), buttonSelectAll, FALSE, FALSE, 1); image2 = create_pixmap ((GtkWidget*)0, "stock-select-all_20.png"); gtk_container_add (GTK_CONTAINER (buttonSelectAll), image2); buttonDumpAll = gtk_button_new(); gtk_box_pack_start(GTK_BOX(vbox), buttonDumpAll, TRUE, FALSE, 0); image4 = gtk_image_new_from_icon_name("document-save-as", GTK_ICON_SIZE_BUTTON); gtk_container_add(GTK_CONTAINER(buttonDumpAll), image4); gtk_widget_set_tooltip_text(buttonDumpAll, _("Export the rendering of all selected files" " in other formats.")); buttonNext = gtk_button_new (); gtk_box_pack_end(GTK_BOX (vbox), buttonNext, FALSE, FALSE, 1); gtk_widget_set_tooltip_text(buttonNext, _("Render the next selected file.")); image1 = gtk_image_new_from_icon_name("go-down", GTK_ICON_SIZE_BUTTON); gtk_container_add (GTK_CONTAINER (buttonNext), image1); buttonPrevious = gtk_button_new (); gtk_box_pack_end(GTK_BOX (vbox), buttonPrevious, FALSE, FALSE, 1); gtk_widget_set_tooltip_text(buttonPrevious, _("Render the previous selected file.")); image2 = gtk_image_new_from_icon_name("go-up", GTK_ICON_SIZE_BUTTON); gtk_container_add (GTK_CONTAINER (buttonPrevious), image2); hbox = gtk_hbox_new(FALSE, 0); gtk_box_pack_start(GTK_BOX(vbox1), hbox, FALSE, FALSE, 0); label = gtk_label_new(_("Current dir.: ")); gtk_label_set_use_markup(GTK_LABEL(label), TRUE); gtk_box_pack_start(GTK_BOX(hbox), label, FALSE, FALSE, 0); labelDirectory = gtk_label_new(""); gtk_label_set_use_markup(GTK_LABEL(labelDirectory), TRUE); gtk_label_set_xalign(GTK_LABEL(labelDirectory), 0.); #if GTK_MAJOR_VERSION > 2 || GTK_MINOR_VERSION > 5 gtk_label_set_ellipsize(GTK_LABEL(labelDirectory), PANGO_ELLIPSIZE_START); #endif gtk_box_pack_start(GTK_BOX(hbox), labelDirectory, TRUE, TRUE, 0); panelBrowserSet_labelCurrentDir(); /***************/ /* Action part */ /***************/ hbox2 = gtk_hbox_new (FALSE, 0); gtk_box_pack_start (GTK_BOX (vbox1), hbox2, FALSE, TRUE, 1); hbox5 = gtk_hbox_new(FALSE, 0); gtk_widget_set_margin_end(hbox5, 5); gtk_box_pack_start(GTK_BOX(hbox2), hbox5, FALSE, FALSE, 0); radioGoAround = gtk_radio_button_new(NULL); gtk_radio_button_set_group(GTK_RADIO_BUTTON(radioGoAround), (GSList*)0); radiobuttonCycle_group = gtk_radio_button_get_group(GTK_RADIO_BUTTON(radioGoAround)); gtk_box_pack_start(GTK_BOX(hbox5), radioGoAround, FALSE, FALSE, 0); image1 = create_pixmap((GtkWidget*)0, "stock-go-around.png"); gtk_container_add(GTK_CONTAINER(radioGoAround), image1); radioGoOnce = gtk_radio_button_new(NULL); gtk_radio_button_set_group(GTK_RADIO_BUTTON(radioGoOnce), radiobuttonCycle_group); radiobuttonCycle_group = gtk_radio_button_get_group(GTK_RADIO_BUTTON(radioGoOnce)); gtk_box_pack_start(GTK_BOX(hbox5), radioGoOnce, FALSE, FALSE, 0); image1 = create_pixmap((GtkWidget*)0, "stock-go-once.png"); gtk_container_add(GTK_CONTAINER(radioGoOnce), image1); radioGoAndBack = gtk_radio_button_new(NULL); gtk_radio_button_set_group(GTK_RADIO_BUTTON(radioGoAndBack), radiobuttonCycle_group); radiobuttonCycle_group = gtk_radio_button_get_group(GTK_RADIO_BUTTON(radioGoAndBack)); gtk_box_pack_start(GTK_BOX(hbox5), radioGoAndBack, FALSE, FALSE, 0); image1 = create_pixmap((GtkWidget*)0, "stock-go-and-back.png"); gtk_container_add(GTK_CONTAINER(radioGoAndBack), image1); label4 = gtk_label_new (_("Play at ")); gtk_box_pack_start (GTK_BOX (hbox2), label4, TRUE, TRUE, 0); gtk_label_set_xalign(GTK_LABEL(label4), 1.); spinDelay = gtk_spin_button_new_with_range(10, 10000, 25); gtk_spin_button_set_value(GTK_SPIN_BUTTON(spinDelay), 500); gtk_box_pack_start (GTK_BOX (hbox2), spinDelay, FALSE, TRUE, 0); gtk_spin_button_set_numeric (GTK_SPIN_BUTTON (spinDelay), TRUE); /* Units: milliseconds */ label1 = gtk_label_new (_(" ms")); gtk_box_pack_start (GTK_BOX (hbox2), label1, TRUE, TRUE, 0); gtk_label_set_xalign(GTK_LABEL(label1), 0.); buttonPlayStop = gtk_toggle_button_new(); gtk_widget_set_tooltip_text(buttonPlayStop, _("Cycle through the selected files at the given rate.")); gtk_box_pack_start (GTK_BOX (hbox2), buttonPlayStop, FALSE, FALSE, 5); hbox5 = gtk_hbox_new (FALSE, 0); gtk_container_add (GTK_CONTAINER (buttonPlayStop), hbox5); #if GTK_MAJOR_VERSION == 2 && GTK_MINOR_VERSION < 5 imagePlay = create_pixmap ((GtkWidget*)0, "stock_media-play.png"); imageStop = create_pixmap ((GtkWidget*)0, "stock_media-stop.png"); #else imagePlay = gtk_image_new_from_icon_name("media-playback-start", GTK_ICON_SIZE_MENU); imageStop = gtk_image_new_from_icon_name("media-playback-stop", GTK_ICON_SIZE_MENU); #endif gtk_widget_set_no_show_all(imageStop, TRUE); gtk_box_pack_start (GTK_BOX (hbox5), imagePlay, TRUE, TRUE, 0); gtk_box_pack_start (GTK_BOX (hbox5), imageStop, TRUE, TRUE, 0); g_signal_connect(G_OBJECT(fileTree), "row-activated", G_CALLBACK(onTreeviewActivated), (gpointer)0); g_signal_connect(G_OBJECT(buttonPrevious), "clicked", G_CALLBACK(navigateClicked), GINT_TO_POINTER(VISU_UI_PANEL_BROWSER_PREVIOUS)); g_signal_connect(G_OBJECT(buttonNext), "clicked", G_CALLBACK(navigateClicked), GINT_TO_POINTER(VISU_UI_PANEL_BROWSER_NEXT)); g_signal_connect(G_OBJECT(buttonSelectAll), "clicked", G_CALLBACK(checkFiles), GINT_TO_POINTER(TRUE)); g_signal_connect(G_OBJECT(buttonUnselectAll), "clicked", G_CALLBACK(checkFiles), GINT_TO_POINTER(FALSE)); g_signal_connect(G_OBJECT(buttonDirectory), "clicked", G_CALLBACK(onDirectoryClicked), (gpointer)entryFilterBrowser); g_signal_connect(G_OBJECT(buttonPlayStop), "toggled", G_CALLBACK(onPlayStopClicked), (gpointer)0); g_signal_connect(G_OBJECT(spinDelay), "value-changed", G_CALLBACK(onSpinDelayChangeValue), (gpointer)buttonPlayStop); g_signal_connect(G_OBJECT(buttonDumpAll), "clicked", G_CALLBACK(onDumpButtonClicked), (gpointer)0); g_signal_connect(G_OBJECT(entryFilterBrowser), "changed", G_CALLBACK(onFilterChanged), (gpointer)0); g_signal_connect_swapped(G_OBJECT(comboFilter), "changed", G_CALLBACK(gtk_tree_model_filter_refilter), treeStoreFilesFilter); gtk_widget_show_all(vbox1); return vbox1; } /*************/ /* Callbacks */ /*************/ static void onFilterChanged(GtkEditable *entry, gpointer user_data _U_) { GPatternSpec *pattern; gboolean valid; GtkTreeIter iter; gboolean match; gchar *fileUTF8; /* fprintf(stderr, "'%s'\n", gtk_entry_get_text(GTK_ENTRY(entry))); */ pattern = g_pattern_spec_new(gtk_entry_get_text(GTK_ENTRY(entry))); for (valid = gtk_tree_model_get_iter_first(GTK_TREE_MODEL(treeStoreFiles), &iter); valid; valid = gtk_tree_model_iter_next(GTK_TREE_MODEL(treeStoreFiles), &iter)) { gtk_tree_model_get(GTK_TREE_MODEL(treeStoreFiles), &iter, COLUMN_NAME_UTF8, &fileUTF8, -1); match = g_pattern_match_string(pattern, fileUTF8); gtk_tree_store_set(treeStoreFiles, &iter, COLUMN_ACTIVE, match, -1); g_free(fileUTF8); } gtk_tree_model_filter_refilter(GTK_TREE_MODEL_FILTER(treeStoreFilesFilter)); g_pattern_spec_free(pattern); } static void onCheckFile(GtkCellRendererToggle *cell_renderer _U_, gchar *path, gpointer user_data _U_) { GtkTreeIter iter, childIter; gboolean checked; GtkTreePath *currentPath; currentPath = gtk_tree_path_new_from_string(path); gtk_tree_model_get_iter(GTK_TREE_MODEL(treeStoreFilesFilter), &iter, currentPath); gtk_tree_path_free(currentPath); gtk_tree_model_filter_convert_iter_to_child_iter (GTK_TREE_MODEL_FILTER(treeStoreFilesFilter), &childIter, &iter); gtk_tree_model_get(GTK_TREE_MODEL(treeStoreFiles), &childIter, COLUMN_BOOLEAN, &checked, -1); gtk_tree_store_set(treeStoreFiles, &childIter, COLUMN_BOOLEAN, !checked, -1); } static void onTreeviewActivated(GtkTreeView *treeview _U_, GtkTreePath *path, GtkTreeViewColumn *col _U_, gpointer user_data _U_) { GtkTreeIter iter, childIter, parentIter; gboolean checked; gchar* filename, *utf8; int nSet; DBG_fprintf(stderr, "Panel Browser: double click detected.\n"); gtk_tree_model_get_iter(GTK_TREE_MODEL(treeStoreFilesFilter), &iter, path); gtk_tree_model_filter_convert_iter_to_child_iter (GTK_TREE_MODEL_FILTER(treeStoreFilesFilter), &childIter, &iter); gtk_tree_model_get(GTK_TREE_MODEL(treeStoreFiles), &childIter, COLUMN_NAME, &filename, COLUMN_NAME_UTF8, &utf8, COLUMN_BOOLEAN, &checked, -1); if (!checked) gtk_tree_store_set(GTK_TREE_STORE(treeStoreFiles), &childIter, COLUMN_BOOLEAN, TRUE, -1); if (gtk_tree_model_iter_parent(GTK_TREE_MODEL(treeStoreFiles), &parentIter, &childIter)) gtk_tree_model_get(GTK_TREE_MODEL(treeStoreFiles), &childIter, COLUMN_DATE, &nSet, -1); else nSet = 0; DBG_fprintf(stderr, "Panel Browser: double click asks for loading (%s).\n", filename); browserLoad(filename, utf8, &childIter, nSet); g_free(filename); g_free(utf8); } static void navigateClicked(GtkButton *button _U_, gpointer data) { GtkTreeIter iter; GtkTreePath *path; gboolean res; res = visu_ui_panel_browser_getNextSelected(&path, &iter, GPOINTER_TO_INT(data)); if (!res) return; res = navigateInFiles(path, &iter); gtk_tree_path_free(path); } static void onNextPrevFile(VisuUiRenderingWindow *window _U_, gpointer data) { GtkTreeIter iter; GtkTreePath *path; gboolean res; res = visu_ui_panel_browser_getNextSelected(&path, &iter, GPOINTER_TO_INT(data)); if (!res) return; res = navigateInFiles(path, &iter); gtk_tree_path_free(path); } static void checkFiles(GtkButton *button _U_, gpointer data) { gtk_tree_model_foreach(GTK_TREE_MODEL(treeStoreFilesFilter), checkFile, data); } static void onRefreshDir(GtkButton *button _U_, gpointer data _U_) { browseDirectory((gchar*)0); } gboolean playSelectedFiles(gpointer data _U_) { GtkTreeIter iter; gboolean res, load; GtkTreePath *path; g_return_val_if_fail(startBrowsePath, FALSE); /* We try to get the next iter. */ res = visu_ui_panel_browser_getNextSelected(&path, &iter, currentBrowseDirection); if (!res) return FALSE; /* We follow the cycle policy to select the file. */ load = TRUE; if (gtk_toggle_button_get_active(GTK_TOGGLE_BUTTON(radioGoAndBack))) { if (!gtk_tree_path_compare(path, startBrowsePath)) { DBG_fprintf(stderr, "Panel browser: One round is done, applyng policy.\n"); if (currentBrowseDirection == VISU_UI_PANEL_BROWSER_PREVIOUS) currentBrowseDirection = VISU_UI_PANEL_BROWSER_NEXT; else { currentBrowseDirection = VISU_UI_PANEL_BROWSER_PREVIOUS; gtk_tree_path_free(path); res = visu_ui_panel_browser_getNextSelected(&path, &iter, currentBrowseDirection); g_return_val_if_fail(res, FALSE); } } } else if (gtk_toggle_button_get_active(GTK_TOGGLE_BUTTON(radioGoOnce))) { if (!gtk_tree_path_compare(path, startBrowsePath)) { DBG_fprintf(stderr, "Panel browser: One round is done, applyng policy.\n"); res = FALSE; load = FALSE; } } if (load) { /* We advance the select one. */ selectFile(path, &iter); /* We render it. */ res = navigateInFiles(path, &iter); } gtk_tree_path_free(path); return res; } static void onPlayStopClicked(GtkToggleButton *button, gpointer data _U_) { GtkTreeIter startIter; gboolean res, checked, hasChild; gulong *playCallbackId; DBG_fprintf(stderr, "Panel Browser: toggle on play button.\n"); /* if (!gtk_tree_model_get_iter_first(GTK_TREE_MODEL(panelBrowserListFilter), &startIter)) */ /* return; */ if (gtk_toggle_button_get_active(button)) { /* Button has been pushed. */ checked = FALSE; res = visu_ui_panel_browser_getCurrentSelected(&startBrowsePath, &startIter); if (res) { gtk_tree_model_get(GTK_TREE_MODEL(treeStoreFilesFilter), &startIter, COLUMN_BOOLEAN, &checked, -1); hasChild = gtk_tree_model_iter_has_child(GTK_TREE_MODEL(treeStoreFilesFilter), &startIter); } if (!res || !checked || hasChild) { res = visu_ui_panel_browser_getNextSelected(&startBrowsePath, &startIter, VISU_UI_PANEL_BROWSER_NEXT); if (!res) { startBrowsePath = gtk_tree_path_new(); /* No file selected. */ gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON(buttonPlayStop), FALSE); return; } } navigateInFiles(startBrowsePath, &startIter); /* Launch play */ gtk_widget_hide(imagePlay); gtk_widget_show(imageStop); currentBrowseDirection = VISU_UI_PANEL_BROWSER_NEXT; playCallbackId = g_malloc(sizeof(gulong)); *playCallbackId = g_timeout_add_full(G_PRIORITY_DEFAULT_IDLE, (gint)gtk_spin_button_get_value(GTK_SPIN_BUTTON(spinDelay)), playSelectedFiles, (gpointer)0, stopPlayStop); g_object_set_data(G_OBJECT(button), "playCallbackId", (gpointer)playCallbackId); DBG_fprintf(stderr, " | start play\n"); } else { /* Stop play */ playCallbackId = (gulong*)g_object_get_data(G_OBJECT(button), "playCallbackId"); if (playCallbackId) g_source_remove(*playCallbackId); DBG_fprintf(stderr, " | stop play\n"); } } void stopPlayStop(gpointer data _U_) { gtk_widget_hide(imageStop); gtk_widget_show(imagePlay); gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON(buttonPlayStop), FALSE); g_return_if_fail(startBrowsePath); gtk_tree_path_free(startBrowsePath); } static void onSpinDelayChangeValue(GtkSpinButton *spinbutton _U_, gpointer user_data) { GtkTreePath *startPath; GtkToggleButton *button; gulong *playCallbackId; g_return_if_fail(GTK_IS_TOGGLE_BUTTON(user_data)); button = GTK_TOGGLE_BUTTON(user_data); if (gtk_toggle_button_get_active(button)) { playCallbackId = (gulong*)g_object_get_data(G_OBJECT(button), "playCallbackId"); g_return_if_fail(playCallbackId); startPath = gtk_tree_path_copy(startBrowsePath); /* Stop playing at this rate */ g_source_remove(*playCallbackId); startBrowsePath = startPath; gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON(buttonPlayStop), TRUE); } } void onDumpButtonClicked(GtkButton *button _U_, gpointer user_data _U_) { GtkWidget *dump; GtkProgressBar *progressBarDump; char *filename; VisuDump *format; GError *error; GString *buffer; GtkButton *abort; char *chr, *chr2; int goodPattern, flagAbort, i; gint response; GString *fileNumbered; GtkTreeIter iter; gboolean valid, errors; GtkTreePath *currentPath, *startPath; VisuGlView *view; view = visu_ui_panel_getView(VISU_UI_PANEL(panelBrowser)); dump = visu_ui_dump_dialog_new (visu_ui_panel_getData(VISU_UI_PANEL(panelBrowser)), visu_ui_panel_getContainerWindow(VISU_UI_PANEL(panelBrowser)), _("foo%02d.png"), view->window.width, view->window.height); do { response = gtk_dialog_run(GTK_DIALOG(dump)); if (response != GTK_RESPONSE_ACCEPT) { gtk_widget_destroy(dump); return; } filename = visu_ui_dump_dialog_getFilename(VISU_UI_DUMP_DIALOG(dump)); format = visu_ui_dump_dialog_getType(VISU_UI_DUMP_DIALOG(dump)); g_return_if_fail(filename && format); DBG_fprintf(stderr, "Panel browser: dump all returns this filename" " pattern '%s' (format : %s)\n", filename, tool_file_format_getName(TOOL_FILE_FORMAT(format))); buffer = g_string_new(_("Dumping all selected files to images,")); g_string_append_printf(buffer, _(" format '%s'.\n\n"), tool_file_format_getName(TOOL_FILE_FORMAT(format))); /* Verify the name is regular */ if (g_pattern_match_simple("*%0?d*", filename)) { chr = strchr(filename, '%'); if ((int)*(chr + 2) <= '0' || (int)*(chr + 2) > '9') { goodPattern = 0; g_string_append_printf(buffer, _("Error! The numbering pattern is" " wrong.\n")); } else { chr2 = strchr(chr + 1, '%'); if (chr2) { goodPattern = 0; g_string_append_printf(buffer, _("Error! Only one '%s' character" " is allowed in the file name.\n"), "%"); } else goodPattern = 1; } } else { goodPattern = 0; g_string_append_printf(buffer, _("Error! Missing pattern in the filename.\n")); } if (!goodPattern) { g_string_append_printf(buffer, _("\nHelp : you must specify '%s' in" " the filename, where 'x' is a number [|1;9|]." " This allows V_Sim to number the dumped" " files.\n\n For example, with a pattern like this" " : 'foo%s.pdf', dumped files will be named" " : foo00.pdf, foo01.pdf..."), "%0xd", "%02d"); visu_ui_raiseWarning(_("Exporting files"), buffer->str, (GtkWindow*)0); g_string_free(buffer, TRUE); } } while (!goodPattern); error = (GError*)0; abort = visu_ui_dump_dialog_getCancelButton(VISU_UI_DUMP_DIALOG(dump)); progressBarDump = visu_ui_dump_dialog_getProgressBar(VISU_UI_DUMP_DIALOG(dump)); visu_ui_dump_dialog_start(VISU_UI_DUMP_DIALOG(dump)); g_signal_connect (G_OBJECT(abort), "clicked", G_CALLBACK(visu_dump_abort), (gpointer)&flagAbort); g_signal_connect (G_OBJECT(abort), "clicked", G_CALLBACK(abortDumpAll), (gpointer)progressBarDump); gtk_progress_bar_set_fraction(progressBarDump, 0.); fileNumbered = g_string_new(""); i = 0; flagAbort = 0; /* We write it only once to avoid blinking effects. */ gtk_progress_bar_set_text(progressBarDump, _("Waiting for generating image in memory...")); visu_ui_wait(); gtk_tree_selection_unselect_all(gtk_tree_view_get_selection(GTK_TREE_VIEW(fileTree))); errors = FALSE; valid = visu_ui_panel_browser_getNextSelected(&startPath, &iter, VISU_UI_PANEL_BROWSER_NEXT); if (valid) valid = navigateInFiles(startPath, &iter); while (valid && !errors && !flagAbort) { g_string_append_printf(buffer, _("Write to file %d ..."), i); g_string_printf(fileNumbered, filename, i); DBG_fprintf(stderr, "Panel browser: write '%s'\n", fileNumbered->str); errors = !visu_gl_node_scene_dump(visu_ui_rendering_window_getGlScene(visu_ui_main_class_getDefaultRendering()), format, fileNumbered->str, visu_ui_dump_dialog_getWidth(VISU_UI_DUMP_DIALOG(dump)), visu_ui_dump_dialog_getHeight(VISU_UI_DUMP_DIALOG(dump)), updateDumpAllProgressBar, (gpointer)progressBarDump, &error); if (errors) g_string_append_printf(buffer, _(" error\n")); else g_string_append_printf(buffer, _(" OK\n")); i += 1; valid = visu_ui_panel_browser_getNextSelected(¤tPath, &iter, VISU_UI_PANEL_BROWSER_NEXT); if (!gtk_tree_path_compare(currentPath, startPath)) valid = FALSE; if (valid) valid = navigateInFiles(currentPath, &iter); gtk_tree_path_free(currentPath); } gtk_tree_path_free(startPath); if (error) { visu_ui_raiseWarning(_("Exporting files"), error->message, (GtkWindow*)0); g_error_free(error); } g_string_free(fileNumbered, TRUE); gtk_widget_destroy(dump); } void updateDumpAllProgressBar(gpointer data) { gdouble val; gdouble percentage; gdouble nEle; g_return_if_fail(GTK_PROGRESS_BAR(data)); nEle = (gdouble)gtk_tree_model_iter_n_children(GTK_TREE_MODEL(treeStoreFilesFilter), NULL); val = gtk_progress_bar_get_fraction(GTK_PROGRESS_BAR(data)); /* if (((int)(val * nEle)) % 100 == 1) */ gtk_progress_bar_set_text(GTK_PROGRESS_BAR(data), ""); percentage = val + 0.01 / nEle; if (percentage > 1.0) percentage = 1.0; if (percentage < 0.) percentage = 0.; gtk_progress_bar_set_fraction(GTK_PROGRESS_BAR(data), percentage); visu_ui_wait(); } void abortDumpAll(GtkButton *button _U_, gpointer data) { gtk_progress_bar_set_text(GTK_PROGRESS_BAR(data), _("Abortion request, please wait...")); } /******************/ /* Public methods */ /******************/ gboolean visu_ui_panel_browser_getCurrentSelected(GtkTreePath **path, GtkTreeIter *iterSelected) { GtkTreeSelection *selection; gboolean res; GtkTreeModel *model; g_return_val_if_fail(path && iterSelected, FALSE); if (!gtk_tree_model_get_iter_first(GTK_TREE_MODEL(treeStoreFilesFilter), iterSelected)) return FALSE; selection = gtk_tree_view_get_selection(GTK_TREE_VIEW(fileTree)); res = gtk_tree_selection_get_selected(selection, &model, iterSelected); if (res) *path = gtk_tree_model_get_path(model, iterSelected); return res; } gboolean visu_ui_panel_browser_getNextSelected(GtkTreePath **path, GtkTreeIter *iterSelected, int direction) { GtkTreeSelection *selection; GtkTreePath *currentPath, *firstPath; GtkTreeIter iter, child, parent; gboolean res, checked; GtkTreeModel *model; int loopComplete; g_return_val_if_fail(path && iterSelected && (direction == VISU_UI_PANEL_BROWSER_NEXT || direction == VISU_UI_PANEL_BROWSER_PREVIOUS), FALSE); *path = (GtkTreePath*)0; if (!gtk_tree_model_get_iter_first(GTK_TREE_MODEL(treeStoreFilesFilter), &iter)) return FALSE; selection = gtk_tree_view_get_selection(GTK_TREE_VIEW(fileTree)); res = gtk_tree_selection_get_selected(selection, &model, &iter); /* Nothing is selected. */ if (!res) { if (direction == VISU_UI_PANEL_BROWSER_NEXT) res = gtk_tree_model_get_iter_last(GTK_TREE_MODEL(treeStoreFilesFilter), &iter, (GtkTreePath**)0); else if (GPOINTER_TO_INT(direction) == VISU_UI_PANEL_BROWSER_PREVIOUS) res = gtk_tree_model_get_iter_first(GTK_TREE_MODEL(treeStoreFilesFilter), &iter); } g_return_val_if_fail(res, FALSE); currentPath = gtk_tree_model_get_path(GTK_TREE_MODEL(treeStoreFilesFilter), &iter); firstPath = gtk_tree_path_copy(currentPath); do { if (direction == VISU_UI_PANEL_BROWSER_NEXT) { /* If the current iter has child, we select the first. */ if (gtk_tree_model_iter_has_child(GTK_TREE_MODEL(treeStoreFilesFilter), &iter)) { gtk_tree_model_iter_children(GTK_TREE_MODEL(treeStoreFilesFilter), &child, &iter); iter = child; gtk_tree_path_free(currentPath); currentPath = gtk_tree_model_get_path(GTK_TREE_MODEL(treeStoreFilesFilter), &iter); } /* If the current iter has no child, we go next. */ else { /* Avance d'un pas dans la liste */ gtk_tree_path_next(currentPath); child = iter; res = gtk_tree_model_get_iter(GTK_TREE_MODEL(treeStoreFilesFilter), &iter, currentPath); /* In case, there's no next iter. */ if (!res) { /* If the iter has no parent we go top. */ if (!gtk_tree_model_iter_parent (GTK_TREE_MODEL(treeStoreFilesFilter), &parent, &child)) { gtk_tree_model_get_iter_first (GTK_TREE_MODEL(treeStoreFilesFilter), &iter); gtk_tree_path_free(currentPath); currentPath = gtk_tree_model_get_path (GTK_TREE_MODEL(treeStoreFilesFilter), &iter); } /* If the iter has parent, we go next parent. */ else { iter = parent; gtk_tree_path_free(currentPath); currentPath = gtk_tree_model_get_path (GTK_TREE_MODEL(treeStoreFilesFilter), &iter); gtk_tree_path_next(currentPath); res = gtk_tree_model_get_iter (GTK_TREE_MODEL(treeStoreFilesFilter), &iter, currentPath); if (!res) { gtk_tree_model_get_iter_first (GTK_TREE_MODEL(treeStoreFilesFilter), &iter); gtk_tree_path_free(currentPath); currentPath = gtk_tree_model_get_path (GTK_TREE_MODEL(treeStoreFilesFilter), &iter); } } } } } else if (direction == VISU_UI_PANEL_BROWSER_PREVIOUS) { /* Recule d'un pas dans la liste */ res = gtk_tree_path_prev(currentPath); /* Recup�re l'it�ration recul�e d'un pas */ child = iter; res = res && gtk_tree_model_get_iter(GTK_TREE_MODEL(treeStoreFilesFilter), &iter, currentPath); /* If this prev iter does not exist. */ if (!res) { /* In the case the current iter has a parent, we select it. */ if (gtk_tree_model_iter_parent(GTK_TREE_MODEL(treeStoreFilesFilter), &parent, &child)) { iter = parent; gtk_tree_path_free(currentPath); currentPath = gtk_tree_model_get_path (GTK_TREE_MODEL(treeStoreFilesFilter), &iter); } /* Si ce path n'existe pas ou si cette iteration n'existe pas on va � la fin. */ else { gtk_tree_path_free(currentPath); res = gtk_tree_model_get_iter_last (GTK_TREE_MODEL(treeStoreFilesFilter), &iter, ¤tPath); if (!res) { g_warning("Panel browser: impossible to find" " the end of the list.\n"); gtk_tree_path_free(currentPath); gtk_tree_path_free(firstPath); return FALSE; } } } /* If the previous iter has children, we select last. */ else if (gtk_tree_model_iter_has_child(GTK_TREE_MODEL(treeStoreFilesFilter), &iter)) { parent = iter; res = gtk_tree_model_iter_nth_child (GTK_TREE_MODEL(treeStoreFilesFilter), &iter, &parent, gtk_tree_model_iter_n_children(GTK_TREE_MODEL(treeStoreFilesFilter), &parent) - 1); if (!res) { g_warning("Panel browser: impossible to find" " the last child of this iter.\n"); gtk_tree_path_free(currentPath); gtk_tree_path_free(firstPath); return FALSE; } gtk_tree_path_free(currentPath); currentPath = gtk_tree_model_get_path (GTK_TREE_MODEL(treeStoreFilesFilter), &iter); } } checked = FALSE; gtk_tree_model_get(GTK_TREE_MODEL(treeStoreFilesFilter), &iter, COLUMN_BOOLEAN, &checked, -1); checked = checked && !gtk_tree_model_iter_has_child(GTK_TREE_MODEL(treeStoreFilesFilter), &iter); /* fprintf(stderr, "%d '%s'\n", nbSteps, filename); */ loopComplete = !gtk_tree_path_compare(firstPath, currentPath); } while ( !checked && !loopComplete); gtk_tree_path_free(firstPath); if (!loopComplete) { *path = currentPath; *iterSelected = iter; return TRUE; } else { gtk_tree_path_free(currentPath); return FALSE; } } static void selectFile(GtkTreePath *path, GtkTreeIter *iter) { GtkTreeSelection *selection; g_return_if_fail(path && iter); selection = gtk_tree_view_get_selection(GTK_TREE_VIEW(fileTree)); gtk_tree_selection_select_iter(selection, iter); gtk_tree_view_scroll_to_cell(GTK_TREE_VIEW(fileTree), path, NULL, FALSE, 0., 0.); } static gboolean navigateInFiles(GtkTreePath *path, GtkTreeIter *iterSelected) { gboolean res; gchar *filename, *utf8; int nSet; GtkTreeIter parentIter, iter; g_return_val_if_fail(path && iterSelected, FALSE); /* We select the given iter. */ selectFile(path, iterSelected); /* Load the new selected file */ gtk_tree_model_filter_convert_iter_to_child_iter (GTK_TREE_MODEL_FILTER(treeStoreFilesFilter), &iter, iterSelected); if (gtk_tree_model_iter_parent(GTK_TREE_MODEL(treeStoreFiles), &parentIter, &iter)) gtk_tree_model_get(GTK_TREE_MODEL(treeStoreFiles), &iter, COLUMN_DATE, &nSet, -1); else nSet = 0; gtk_tree_model_get(GTK_TREE_MODEL(treeStoreFiles), &iter, COLUMN_NAME, &filename, COLUMN_NAME_UTF8, &utf8, -1); res = browserLoad(filename, utf8, &iter, nSet); g_free(filename); g_free(utf8); return res; } static VisuDataLoadable* setFiles(const gchar *filename, const gchar *utf8, VisuData *oldData) { gchar *pt, **tokens, *name, *name2; VisuDataAtomic *atomic; VisuDataSpin *spin; switch (gtk_combo_box_get_active(GTK_COMBO_BOX(comboFilter))) { case 0: atomic = visu_data_atomic_new(filename, (VisuDataLoader*)0); return VISU_DATA_LOADABLE(atomic); case 1: /* The case where the name is used for all files. */ pt = strrchr(utf8, ']'); *pt = '\0'; pt = strrchr(utf8, '['); tokens = g_strsplit(pt + 1, ",", 2); name = g_strdup_printf("%s.%s", filename, tokens[0]); name2 = g_strdup_printf("%s.%s", filename, tokens[1]); g_strfreev(tokens); spin = visu_data_spin_new(name, name2, (VisuDataLoader*)0, (VisuDataLoader*)0); g_free(name); g_free(name2); return VISU_DATA_LOADABLE(spin); case 2: g_return_val_if_fail(VISU_IS_DATA_LOADABLE(oldData), (VisuDataLoadable*)0); spin = visu_data_spin_new(filename, visu_data_loadable_getFilename(VISU_DATA_LOADABLE(oldData), 1), (VisuDataLoader*)0, (VisuDataLoader*)0); return VISU_DATA_LOADABLE(spin); case 3: g_return_val_if_fail(VISU_IS_DATA_LOADABLE(oldData), (VisuDataLoadable*)0); spin = visu_data_spin_new(visu_data_loadable_getFilename(VISU_DATA_LOADABLE(oldData), 0), filename, (VisuDataLoader*)0, (VisuDataLoader*)0); return VISU_DATA_LOADABLE(spin); default: return (VisuDataLoadable*)0; } } static gboolean browserLoad(gchar *filename, gchar *utf8, GtkTreeIter *iter, int nSet) { GError *error; VisuDataLoadable *data; VisuData *prevData; gboolean valid; GtkTreeIter parentIter, childIter; int iSet, nSets; GtkTreePath *path; const gchar *comment; gchar *buf, *commentFormat; g_return_val_if_fail(iter, FALSE); prevData = visu_ui_panel_getData(VISU_UI_PANEL(panelBrowser)); data = setFiles(filename, utf8, prevData); if (!data) { visu_ui_raiseWarning(_("Loading a file"), _("Can't load this file through the browser because it" " requires to read several files. You should use the 'Open'" " button on the main panel and then use the browser to vary" " one kind of file at a time."), (GtkWindow*)0); g_object_unref(data); gtk_tree_store_set(treeStoreFiles, iter, COLUMN_FILE_VALID, FALSE, COLUMN_BOOLEAN, FALSE, -1); return FALSE; } gtk_widget_set_sensitive(buttonPrevious, FALSE); gtk_widget_set_sensitive(buttonNext, FALSE); error = (GError*)0; if (!visu_gl_node_scene_loadData(visu_ui_rendering_window_getGlScene(visu_ui_main_class_getDefaultRendering()), data, nSet, (GCancellable*)0, &error)) { if (error) { visu_ui_raiseWarning(_("Loading a file"), error->message, (GtkWindow*)0); g_error_free(error); } g_object_unref(data); data = (VisuDataLoadable*)0; } gtk_widget_set_sensitive(buttonPrevious, TRUE); gtk_widget_set_sensitive(buttonNext, TRUE); if (!data) gtk_tree_store_set(treeStoreFiles, iter, COLUMN_FILE_ERROR_ID, "dialog-error", COLUMN_FILE_VALID, FALSE, COLUMN_BOOLEAN, FALSE, -1); else gtk_tree_store_set(treeStoreFiles, iter, COLUMN_FILE_ERROR_ID, (gchar*)0, COLUMN_FILE_VALID, TRUE, -1); if (data) { /* If the file has more than one node set, we create the child entries in the tree view. */ nSets = visu_data_loadable_getNSets(data); if (nSets > 1) { /* We get the parent iter. */ if (!gtk_tree_model_iter_parent(GTK_TREE_MODEL(treeStoreFiles), &parentIter, iter)) { /* We clear its children. */ valid = gtk_tree_model_iter_children (GTK_TREE_MODEL(treeStoreFiles), &childIter, iter); while (valid) { gtk_tree_store_remove(treeStoreFiles, &childIter); valid = gtk_tree_model_iter_children (GTK_TREE_MODEL(treeStoreFiles), &childIter, iter); } /* We create the new ones. */ commentFormat = g_strdup_printf(_("data set %s0%dd"), "%", (int)log10(nSets) + 1); for (iSet = 0; iSet < nSets; iSet++) { comment = visu_data_loadable_getSetLabel(data, iSet); if (!comment || !comment[0]) { buf = g_strdup_printf(commentFormat, iSet + 1); comment = buf; } else buf = (gchar*)0; #if GTK_MAJOR_VERSION > 2 || GTK_MINOR_VERSION > 9 gtk_tree_store_insert_with_values(treeStoreFiles, &childIter, iter, iSet, COLUMN_BOOLEAN, TRUE, COLUMN_NAME, filename, COLUMN_NAME_UTF8, comment, COLUMN_ACTIVE, TRUE, COLUMN_DATE, iSet, COLUMN_FILE_VALID, TRUE, -1); #else gtk_tree_store_insert(treeStoreFiles, &childIter, iter, iSet); gtk_tree_store_set(treeStoreFiles, &childIter, COLUMN_BOOLEAN, TRUE, COLUMN_NAME, filename, COLUMN_NAME_UTF8, comment, COLUMN_ACTIVE, TRUE, COLUMN_DATE, iSet, COLUMN_FILE_VALID, TRUE, -1); #endif if (buf) g_free(buf); } g_free(commentFormat); /* We expand the row. */ gtk_tree_model_filter_convert_child_iter_to_iter (GTK_TREE_MODEL_FILTER(treeStoreFilesFilter), &parentIter, iter); path = gtk_tree_model_get_path(GTK_TREE_MODEL(treeStoreFilesFilter), &parentIter); gtk_tree_view_expand_row(GTK_TREE_VIEW(fileTree), path, TRUE); /* We select the first. */ /* selectFile(path, iterSelected); */ gtk_tree_path_free(path); } } g_object_unref(data); } if (data) return TRUE; else return FALSE; } static gboolean checkFile(GtkTreeModel *model, GtkTreePath *path _U_, GtkTreeIter *iter, gpointer data) { gboolean filterOk, valid; GtkTreeIter iterList; GtkTreeStore *tree; /* If we check the row, the checkbutton is on only if the name is in accordance with the filter. */ gtk_tree_model_filter_convert_iter_to_child_iter(GTK_TREE_MODEL_FILTER(treeStoreFilesFilter), &iterList, iter); tree = GTK_TREE_STORE(gtk_tree_model_filter_get_model(GTK_TREE_MODEL_FILTER(treeStoreFilesFilter))); if (GPOINTER_TO_INT(data)) { gtk_tree_model_get(GTK_TREE_MODEL(model), iter, COLUMN_ACTIVE, &filterOk, COLUMN_FILE_VALID, &valid, -1); if (filterOk && valid) gtk_tree_store_set(tree, &iterList, COLUMN_BOOLEAN, TRUE, -1); /* else */ /* gtk_tree_store_set(tree, &iterList, COLUMN_BOOLEAN, */ /* FALSE, -1); */ } else { gtk_tree_store_set(tree, &iterList, COLUMN_BOOLEAN, FALSE, -1); } return FALSE; } void visu_ui_panel_browser_setCurrentDirectory(const gchar *dir) { g_return_if_fail(dir && dir[0]); if (currentBrowseredDirectory) DBG_fprintf(stderr, "Panel Browser: compare dirs '%s' and '%s'.\n", currentBrowseredDirectory[0], dir); /* Test if the new directory is not already the current one. */ if (currentBrowseredDirectory && currentBrowseredDirectory[0] && !strcmp(currentBrowseredDirectory[0], dir) && !currentBrowseredDirectory[1]) return; /* Set the new directory current. */ currentBrowseredDirectory = g_malloc(sizeof(gchar*) * 2); currentBrowseredDirectory[0] = g_strdup(dir); currentBrowseredDirectory[1] = (gchar*)0; DBG_fprintf(stderr, "Panel Browser: set currentBrowseredDirectory to '%s'.\n", currentBrowseredDirectory[0]); if (commonBrowseredDirectory) g_free(commonBrowseredDirectory); commonBrowseredDirectory = tool_path_normalize(dir); DBG_fprintf(stderr, "Panel Browser: set common path to '%s'.\n", commonBrowseredDirectory); /* Save the new list of current directories. */ updateHistory(); /* Refresh the list if visible, else let the page-enter signal do it. */ DBG_fprintf(stderr, "Panel Browser: ask for refresh.\n"); if (visu_ui_panel_getVisible(VISU_UI_PANEL(panelBrowser))) browseDirectory(); else dirDirty = TRUE; visu_ui_main_setLastOpenDirectory(visu_ui_main_class_getCurrentPanel(), commonBrowseredDirectory, VISU_UI_DIR_BROWSER); } static void setCurrentDirectories(gchar **dirs) { int i, j; gchar *tmp; /* Set the new directory current. */ currentBrowseredDirectory = dirs; DBG_fprintf(stderr, "Panel Browser: set currentBrowseredDirectory to the list:\n"); /* Try to find a common path for all directories. */ if (commonBrowseredDirectory) g_free(commonBrowseredDirectory); commonBrowseredDirectory = g_strdup(dirs[0]); for (i = 0; dirs[i]; i++) { DBG_fprintf(stderr, " | '%s'\n", dirs[i]); for (j = 0; dirs[i][j] && commonBrowseredDirectory[j]; j++) if (dirs[i][j] != commonBrowseredDirectory[j]) commonBrowseredDirectory[j] = '\0'; } tmp = commonBrowseredDirectory; commonBrowseredDirectory = tool_path_normalize(tmp); g_free(tmp); DBG_fprintf(stderr, "Panel Browser: set common path to '%s'.\n", commonBrowseredDirectory); /* Refresh the list if visible, else let the page-enter signal do it. */ if (visu_ui_panel_getVisible(VISU_UI_PANEL(panelBrowser))) browseDirectory(); else dirDirty = TRUE; visu_ui_main_setLastOpenDirectory(visu_ui_main_class_getCurrentPanel(), commonBrowseredDirectory, VISU_UI_DIR_BROWSER); } static void updateHistory() { GList *tmpLst, *del; g_return_if_fail(currentBrowseredDirectory); DBG_fprintf(stderr, "Panel Browser: update the history.\n"); /* We kill the history between historyBrowseredDirectory and currentHistory. */ tmpLst = historyBrowseredDirectory; while (tmpLst != currentHistory) { DBG_fprintf(stderr, "Panel Browser: removing a group of" " directories from history.\n"); g_strfreev((gchar**)tmpLst->data); del = tmpLst; tmpLst = g_list_next(tmpLst); g_list_free_1(del); } if (currentHistory) currentHistory->prev = (GList*)0; historyBrowseredDirectory = currentHistory; DBG_fprintf(stderr, "Panel Browser: adding a group of" " directories to history.\n"); historyBrowseredDirectory = g_list_prepend(historyBrowseredDirectory, currentBrowseredDirectory); currentHistory = historyBrowseredDirectory; DBG_fprintf(stderr, "Panel Browser: set current history to %p (%d).\n", (gpointer)currentHistory, g_list_length(currentHistory)); if (buttonDirPrev) gtk_widget_set_sensitive(buttonDirPrev, TRUE); if (buttonDirNext) gtk_widget_set_sensitive(buttonDirNext, FALSE); DBG_fprintf(stderr, "Panel Browser: history updated OK.\n"); updateDirectionalTooltips(); } void visu_ui_panel_browser_setCurrentDirectories(gchar **dirs) { g_return_if_fail(dirs && dirs[0]); /* Change the current directories. */ setCurrentDirectories(dirs); /* Save the new list of current directories. */ updateHistory(); DBG_fprintf(stderr, "Panel Browser: directories updated OK.\n"); } static void updateDirectionalTooltips() { GString *lbl; int i; gchar **history; #if GTK_MAJOR_VERSION == 2 && GTK_MINOR_VERSION < 12 GtkTooltips *tooltips; tooltips = gtk_tooltips_new (); #endif DBG_fprintf(stderr, "Panel Browser: update directional tooltips.\n"); if (currentHistory && currentHistory->prev && buttonDirNext) { history = (gchar**)(currentHistory->prev->data); lbl = g_string_new(_(HISTORY_TOOLTIP_NEXT)); if (history) { g_string_append_printf(lbl, "\n\n(%s", history[0]); for (i = 1; history[i]; i++) g_string_append_printf(lbl, ", %s", history[i]); g_string_append_printf(lbl, ")"); } gtk_widget_set_tooltip_text(buttonDirNext, lbl->str); g_string_free(lbl, TRUE); } if (currentHistory && currentHistory->next && buttonDirPrev) { history = (gchar**)(currentHistory->next->data); lbl = g_string_new(_(HISTORY_TOOLTIP_PREV)); if (history) { g_string_append_printf(lbl, "\n\n(%s", history[0]); for (i = 1; history[i]; i++) g_string_append_printf(lbl, ", %s", history[i]); g_string_append_printf(lbl, ")"); } gtk_widget_set_tooltip_text(buttonDirPrev, lbl->str); g_string_free(lbl, TRUE); } } gboolean panelBrowserSet_previousHistoryDirectories() { if (!currentHistory || !g_list_next(currentHistory)) return FALSE; currentHistory = g_list_next(currentHistory); DBG_fprintf(stderr, "Panel Browser: set current history to %p (%d).\n", (gpointer)currentHistory, g_list_length(currentHistory)); setCurrentDirectories((gchar**)(currentHistory->data)); updateDirectionalTooltips(); gtk_widget_set_sensitive(buttonDirPrev, g_list_next(currentHistory) != (gpointer)0); gtk_widget_set_sensitive(buttonDirNext, TRUE); return TRUE; } gboolean panelBrowserSet_nextHistoryDirectories() { if (!currentHistory || !g_list_previous(currentHistory)) return FALSE; currentHistory = g_list_previous(currentHistory); DBG_fprintf(stderr, "Panel Browser: set current history to %p (%d).\n", (gpointer)currentHistory, g_list_length(currentHistory)); setCurrentDirectories((gchar**)(currentHistory->data)); updateDirectionalTooltips(); gtk_widget_set_sensitive(buttonDirPrev, TRUE); gtk_widget_set_sensitive(buttonDirNext, g_list_previous(currentHistory) != (gpointer)0); return TRUE; } static void associateFiles(int nbKind, int commonPathLen) { gboolean valid; GtkTreeIter iter; int kind, searchKind, i; gchar *filename, *searchName, *pt, *fileUTF8; GList *tmpLst, *storeLst; gsize lu, ecrit; gchar **ext; /* Read all the stored files and try to associate them on their names. When the name matches the previous one without the extension, then the kind is stored. If a full set of names can be retrieved, then it is stored. The extensions are stored in the ext array. */ searchName = g_strdup("."); searchKind = 0; storeLst = (GList*)0; ext = g_malloc(sizeof(gchar*) * (nbKind + 1)); memset(ext, 0, sizeof(gchar*) * (nbKind + 1)); for (valid = gtk_tree_model_get_iter_first(GTK_TREE_MODEL(treeStoreFiles), &iter); valid; valid = gtk_tree_model_iter_next(GTK_TREE_MODEL(treeStoreFiles), &iter)) { gtk_tree_model_get(GTK_TREE_MODEL(treeStoreFiles), &iter, COLUMN_FILE_KIND, &kind, COLUMN_NAME, &filename, -1); pt = strrchr(filename, '.'); if (pt) *pt = '\0'; if (kind >= 0 && kind < nbKind) ext[kind] = g_strdup(pt + 1); /* fprintf(stderr, "'%s' %d %d\n", filename, kind, searchKind); */ if (kind >= 0 && kind < nbKind && !strcmp(searchName, filename)) { /* Ok, match, we continue. */ searchKind += kind; g_free(filename); if (searchKind == nbKind * (nbKind - 1) / 2) { pt = g_strjoinv(",", ext); /* We found a complete set. */ storeLst = g_list_prepend(storeLst, g_markup_printf_escaped("%s.[%s]", searchName, pt)); g_free(pt); for (i = 0; i < nbKind; i++) g_free(ext[i]); memset(ext, 0, sizeof(gchar*) * (nbKind + 1)); } } else { /* Doesn't match, try for new. */ g_free(searchName); for (i = 0; i < nbKind; i++) if (ext[i]) g_free(ext[i]); memset(ext, 0, sizeof(gchar*) * (nbKind + 1)); searchName = filename; searchKind = kind; if (kind >= 0 && kind < nbKind) ext[kind] = g_strdup(pt + 1); } } g_free(searchName); /* Store now the associated list. */ for (tmpLst = storeLst; tmpLst; tmpLst = g_list_next(tmpLst)) { fileUTF8 = g_filename_to_utf8((gchar*)tmpLst->data + commonPathLen + 1, -1, &lu, &ecrit, NULL); pt = g_strrstr((gchar*)tmpLst->data, " 2 || GTK_MINOR_VERSION > 9 gtk_tree_store_insert_with_values(treeStoreFiles, &iter, (GtkTreeIter*)0, 0, COLUMN_BOOLEAN, FALSE, COLUMN_NAME, tmpLst->data, COLUMN_NAME_UTF8, fileUTF8, COLUMN_ACTIVE, TRUE, COLUMN_FILE_KIND, nbKind, COLUMN_FILE_VALID, TRUE, -1); #else gtk_tree_store_prepend(treeStoreFiles, &iter, (GtkTreeIter*)0); gtk_tree_store_set(treeStoreFiles, &iter, COLUMN_BOOLEAN, FALSE, COLUMN_NAME, tmpLst->data, COLUMN_NAME_UTF8, fileUTF8, COLUMN_ACTIVE, TRUE, COLUMN_FILE_KIND, nbKind, COLUMN_FILE_VALID, TRUE, -1); #endif g_free(tmpLst->data); if (fileUTF8) g_free(fileUTF8); } g_list_free(storeLst); } static void browseDirectory() { GDir *gdir; gint len; int i; GList *atFmt, *spFmt; gint atKind, spKind; gboolean success; struct TimerInfo_ info; if (!currentBrowseredDirectory) return; dirDirty = FALSE; atFmt = spFmt = (GList*)0; atKind = spKind = -1; switch (gtk_combo_box_get_active(GTK_COMBO_BOX(comboFilter))) { case 0: atKind = 0; atFmt = visu_data_atomic_class_getLoaders(); break; case 1: atFmt = visu_data_atomic_class_getLoaders(); spFmt = visu_data_spin_class_getLoaders(); atKind = 2; spKind = 3; break; case 2: atFmt = visu_data_atomic_class_getLoaders(); atKind = 2; break; case 3: spFmt = visu_data_spin_class_getLoaders(); spKind = 3; break; default: break; } if (!atFmt && !spFmt) return; DBG_fprintf(stderr, "Panel browser: cleaning of the list.\n"); gtk_tree_store_clear(treeStoreFiles); /* Remove temporary the model. */ gtk_tree_view_set_model(GTK_TREE_VIEW(fileTree), (GtkTreeModel*)0); gtk_widget_set_sensitive(scrolledwindow1, FALSE); /* Add a timeout to show the progress bar if the scan is too long. */ info.abort = FALSE; info.nbFiles = 0; info.bt = (GtkWidget*)0; #if GLIB_MINOR_VERSION < 13 info.timer = g_timeout_add(1000, showProgressBar, (gpointer)(&info)); #else info.timer = g_timeout_add_seconds(1, showProgressBar, (gpointer)(&info)); #endif info.label = 0; success = TRUE; len = strlen(commonBrowseredDirectory); for (i = 0; success && currentBrowseredDirectory[i] && !info.abort; i++) { DBG_fprintf(stderr, "Panel browser: scanning directory '%s'.\n", currentBrowseredDirectory[i]); gdir = g_dir_open(currentBrowseredDirectory[i], 0, NULL); if (gdir) { addParsedDirectory(len, currentBrowseredDirectory[i], gdir, gtk_toggle_button_get_active (GTK_TOGGLE_BUTTON(buttonRecurse)), atFmt, atKind, spFmt, spKind, &info); g_dir_close(gdir); } else success = FALSE; } hideProgressBar(&info); panelBrowserSet_labelCurrentDir(); if (gtk_combo_box_get_active(GTK_COMBO_BOX(comboFilter)) == 1) associateFiles(2, len); onFilterChanged(GTK_EDITABLE(entryFilterBrowser), (gpointer)0); /* Reattach the model. */ gtk_tree_view_set_model(GTK_TREE_VIEW(fileTree), GTK_TREE_MODEL(treeStoreFilesFilter)); gtk_widget_set_sensitive(scrolledwindow1, TRUE); if (!success) visu_ui_raiseWarning(_("Browsing a directory"), _("The specified directory is unreadable."), (GtkWindow*)0); } static void addParsedDirectory(int commonPathLen, const gchar *root, GDir *gdir, gboolean recurse, GList *atFmt, gint atKind, GList *spFmt, gint spKind, struct TimerInfo_ *timer) { const gchar *fileFromDir; gchar *fileUTF8, *file; gint kind; gsize lu, ecrit; GDir *recursedDir; GtkTreeIter iter; GList *lst; #if GLIB_MINOR_VERSION > 5 struct stat buf; struct tm *tm; gchar data[256]; #endif g_return_if_fail(root && root[0]); DBG_fprintf(stderr, "Panel Browser: read dir '%s' %d.\n", root, (int)recurse); fileFromDir = g_dir_read_name(gdir); while(fileFromDir && !timer->abort) { file = g_build_filename(root, fileFromDir, NULL); fileUTF8 = g_filename_to_utf8(file + commonPathLen + 1, -1, &lu, &ecrit, NULL); if(fileUTF8) { if (g_file_test(file, G_FILE_TEST_IS_DIR)) { DBG_fprintf(stderr, "Panel Browser: read dir '%s'\n", file); if (recurse) { recursedDir = g_dir_open(file, 0, NULL); if (recursedDir) { addParsedDirectory(commonPathLen, file, recursedDir, TRUE, atFmt, atKind, spFmt, spKind, timer); g_dir_close(recursedDir); } } } else { kind = -1; for (lst = atFmt; lst && kind < 0; lst = g_list_next(lst)) if (tool_file_format_validate(TOOL_FILE_FORMAT(lst->data), fileUTF8)) kind = atKind; for (lst = spFmt; lst && kind < 0; lst = g_list_next(lst)) if (tool_file_format_validate(TOOL_FILE_FORMAT(lst->data), fileUTF8)) kind = spKind; #if GLIB_MINOR_VERSION > 5 if (showDate) { if (g_stat(file, &buf)) buf.st_mtime = 0; DBG_fprintf(stderr, "Panel Browser: mtime %d.\n", (int)buf.st_mtime); tm = localtime(&buf.st_mtime); strftime(data, 256, _("%Y-%m-%d %H:%M"), tm); } else { buf.st_mtime = 0; data[0] = '\0'; } #endif #if GTK_MAJOR_VERSION > 2 || GTK_MINOR_VERSION > 9 gtk_tree_store_insert_with_values(treeStoreFiles, &iter, (GtkTreeIter*)0, 0, COLUMN_BOOLEAN, FALSE, COLUMN_NAME, file, COLUMN_NAME_UTF8, fileUTF8, COLUMN_ACTIVE, TRUE, COLUMN_FILE_KIND, kind, COLUMN_FILE_VALID, (kind >= 0), #if GLIB_MINOR_VERSION > 5 COLUMN_DATE, buf.st_mtime, COLUMN_DATA, data, #endif -1); #else gtk_tree_store_append(treeStoreFiles, &iter, (GtkTreeIter*)0); gtk_tree_store_set(treeStoreFiles, &iter, COLUMN_BOOLEAN, FALSE, COLUMN_NAME, file, COLUMN_NAME_UTF8, fileUTF8, COLUMN_FILE_KIND, kind, COLUMN_ACTIVE, TRUE, COLUMN_FILE_VALID, (kind >= 0), #if GLIB_MINOR_VERSION > 5 COLUMN_DATE, buf.st_mtime, COLUMN_DATA, data, #endif -1); #endif timer->nbFiles += 1; } g_free(fileUTF8); } g_free(file); visu_ui_wait(); fileFromDir = g_dir_read_name(gdir); } } #if GTK_MAJOR_VERSION == 2 && GTK_MINOR_VERSION < 17 static void onParseAbortClicked(GtkButton *button _U_, gpointer data) { (*(gboolean*)data) = TRUE; } #else static void onParseAbortClicked(GtkInfoBar *infoBar _U_, gint response, gpointer data) { (*(gboolean*)data) = (response == GTK_RESPONSE_CANCEL); } #endif static void onEnter(VisuUiPanel *visu_ui_panel _U_, gpointer data _U_) { DBG_fprintf(stderr, "Panel Browser: enter, parse directory (%d).\n", !fileTree); if (!fileTree) createInteriorBrowser(); if (gtk_tree_model_iter_n_children(GTK_TREE_MODEL(treeStoreFiles), (GtkTreeIter*)0) == 0 || dirDirty) browseDirectory(); } static void onDirectoryClicked(GtkButton *button _U_, gpointer data _U_) { gchar **filenames; filenames = visu_ui_main_getSelectedDirectory (visu_ui_main_class_getCurrentPanel(), visu_ui_panel_getContainerWindow(VISU_UI_PANEL(panelBrowser)), TRUE, commonBrowseredDirectory); if (!filenames) return; visu_ui_panel_browser_setCurrentDirectories(filenames); } static void onRecurseToggled(GtkToggleButton *toggle _U_, gpointer data _U_) { browseDirectory(); } static void onPrevClicked(GtkButton *button _U_, gpointer data _U_) { panelBrowserSet_previousHistoryDirectories(); } static void onNextClicked(GtkButton *button _U_, gpointer data _U_) { panelBrowserSet_nextHistoryDirectories(); } static gboolean pulseProgressBar(gpointer data) { struct TimerInfo_ *timer; gchar nbFilesLabel[36]; timer = (struct TimerInfo_*)data; sprintf(nbFilesLabel, _("%4d files found."), timer->nbFiles); gtk_label_set_text(GTK_LABEL(labelInfo), nbFilesLabel); DBG_fprintf(stderr, "Panel browser: update label to '%s'.\n", nbFilesLabel); return TRUE; } static gboolean showProgressBar(gpointer data) { gchar nbFilesLabel[36]; struct TimerInfo_ *timer; DBG_fprintf(stderr, "Panel browser: scanning is too slow, showing progress bar.\n"); timer = (struct TimerInfo_*)data; #if GTK_MAJOR_VERSION == 2 && GTK_MINOR_VERSION < 17 timer->bt = gtk_button_new_from_stock(GTK_STOCK_CANCEL); gtk_box_pack_end(GTK_BOX(infoBar), timer->bt, FALSE, FALSE, 0); g_signal_connect(G_OBJECT(timer->bt), "clicked", G_CALLBACK(onParseAbortClicked), (gpointer)&timer->abort); #else timer->bt = gtk_info_bar_add_button(GTK_INFO_BAR(infoBar), TOOL_ICON_CANCEL, GTK_RESPONSE_CANCEL); g_signal_connect(G_OBJECT(infoBar), "response", G_CALLBACK(onParseAbortClicked), (gpointer)&timer->abort); #endif sprintf(nbFilesLabel, _("%4d files found."), timer->nbFiles); visu_ui_panel_browser_setMessage(nbFilesLabel, GTK_MESSAGE_INFO); timer->label = g_timeout_add(250, pulseProgressBar, data); return FALSE; } static void hideProgressBar(struct TimerInfo_ *timer) { DBG_fprintf(stderr, "Panel browser: scanning is finished, hiding progress bar.\n"); g_source_remove(timer->timer); if (timer->label) { g_source_remove(timer->label); visu_ui_panel_browser_setMessage((const gchar*)0, GTK_MESSAGE_INFO); } if (timer->bt) gtk_widget_destroy(timer->bt); } /***************************/ /* Miscellaneous functions */ /***************************/ gboolean gtk_tree_model_get_iter_last(GtkTreeModel *model, GtkTreeIter *last, GtkTreePath **path) { gboolean valid; gint n; g_return_val_if_fail(model && last, FALSE); n = gtk_tree_model_iter_n_children(model, (GtkTreeIter*)0); if (n == 0) return FALSE; valid = gtk_tree_model_iter_nth_child(model, last, (GtkTreeIter*)0, n - 1); g_return_val_if_fail(valid, FALSE); if (path) *path = gtk_tree_model_get_path(model, last); return TRUE; } static gboolean panelBrowserIsIterVisible(GtkTreeModel *model, GtkTreeIter *iter, gpointer data _U_) { gboolean passUserFilter; gint kind; gtk_tree_model_get(model, iter, COLUMN_FILE_KIND, &kind, COLUMN_ACTIVE, &passUserFilter, -1); return (passUserFilter && (kind == gtk_combo_box_get_active(GTK_COMBO_BOX(comboFilter)) || kind < 0)); } static gint onSortNames(GtkTreeModel *model, GtkTreeIter *a, GtkTreeIter *b, gpointer user_data _U_) { gint kindA, kindB; gchar *lblA, *lblB; gint diff, iSetA, iSetB; GtkTreeIter parentA, parentB; /* We always sort the kind first. */ gtk_tree_model_get(model, a, COLUMN_FILE_KIND, &kindA, -1); gtk_tree_model_get(model, b, COLUMN_FILE_KIND, &kindB, -1); if ((kindA < 0 && kindB >= 0) || (kindA >= 0 && kindB < 0)) return (kindB - kindA); else { if (gtk_tree_model_iter_parent(model, &parentA, a) && gtk_tree_model_iter_parent(model, &parentB, b)) { gtk_tree_model_get(model, a, COLUMN_DATE, &iSetA, -1); gtk_tree_model_get(model, b, COLUMN_DATE, &iSetB, -1); diff = iSetA - iSetB; } else { gtk_tree_model_get(model, a, COLUMN_NAME_UTF8, &lblA, -1); gtk_tree_model_get(model, b, COLUMN_NAME_UTF8, &lblB, -1); diff = g_utf8_collate(lblA, lblB); g_free(lblA); g_free(lblB); } return diff; } } void panelBrowserSet_labelCurrentDir() { gchar *directoryUTF8, *markup; if (!commonBrowseredDirectory) return; directoryUTF8 = g_filename_to_utf8(commonBrowseredDirectory, -1, NULL, NULL, NULL); g_return_if_fail(directoryUTF8); markup = g_markup_printf_escaped(_("%s"), directoryUTF8); g_free(directoryUTF8); gtk_label_set_markup(GTK_LABEL(labelDirectory), markup); g_free(markup); } static void onNewDir(GObject *obj _U_, VisuUiDirectoryType type, gpointer user _U_) { DBG_fprintf(stderr, "Panel Browser: caught 'DirectoryChanged'" " signal for type %d.\n", type); if (type == VISU_UI_DIR_FILE) visu_ui_panel_browser_setCurrentDirectory(visu_ui_main_getLastOpenDirectory(visu_ui_main_class_getCurrentPanel())); } static void exportParameters(GString *data, VisuData *dataObj _U_) { g_string_append_printf(data, "# %s\n", DESC_PARAMETER_BROWSER_HEADERS); g_string_append_printf(data, "%s[gtk]: %i\n\n", FLAG_PARAMETER_BROWSER_HEADERS, (int)showHeaders); g_string_append_printf(data, "# %s\n", DESC_PARAMETER_BROWSER_DATE); g_string_append_printf(data, "%s[gtk]: %i\n\n", FLAG_PARAMETER_BROWSER_DATE, (int)showDate); } /** * visu_ui_panel_browser_setMessage: * @message: a string to be displaied. * @message_type: the kind of message. * * This routine is used to give the user a message. This message can * be mere information or a warning or an error. * * Since: 3.6 */ void visu_ui_panel_browser_setMessage(const gchar* message, GtkMessageType message_type) { if (!fileTree) createInteriorBrowser(); if (message) { gtk_label_set_text(GTK_LABEL(labelInfo), message); #if GTK_MAJOR_VERSION > 2 || GTK_MINOR_VERSION > 17 gtk_info_bar_set_message_type(GTK_INFO_BAR(infoBar), message_type); #else switch (message_type) { case GTK_MESSAGE_INFO: gtk_image_set_from_stock(GTK_IMAGE(infoImg), GTK_STOCK_INFO, GTK_ICON_SIZE_BUTTON); break; default: gtk_image_clear(GTK_IMAGE(infoImg)); break; } #endif gtk_widget_set_no_show_all(infoBar, FALSE); gtk_widget_show_all(infoBar); } else { gtk_widget_hide(infoBar); } } v_sim-3.8.0/src/panelModules/panelBrowser.h000066400000000000000000000104231370110300500206600ustar00rootroot00000000000000/* EXTRAITS DE LA LICENCE Copyright CEA, contributeurs : Luc BILLARD et Damien CALISTE, laboratoire L_Sim, (2001-2005) Adresse mèl : BILLARD, non joignable par mèl ; CALISTE, damien P caliste AT cea P fr. Ce logiciel est un programme informatique servant à visualiser des structures atomiques dans un rendu pseudo-3D. Ce logiciel est régi par la licence CeCILL soumise au droit français et respectant les principes de diffusion des logiciels libres. Vous pouvez utiliser, modifier et/ou redistribuer ce programme sous les conditions de la licence CeCILL telle que diffusée par le CEA, le CNRS et l'INRIA sur le site "http://www.cecill.info". Le fait que vous puissiez accéder à cet en-tête signifie que vous avez pris connaissance de la licence CeCILL, et que vous en avez accepté les termes (cf. le fichier Documentation/licence.fr.txt fourni avec ce logiciel). */ /* LICENCE SUM UP Copyright CEA, contributors : Luc BILLARD et Damien CALISTE, laboratoire L_Sim, (2001-2005) E-mail address: BILLARD, not reachable any more ; CALISTE, damien P caliste AT cea P fr. This software is a computer program whose purpose is to visualize atomic configurations in 3D. This software is governed by the CeCILL license under French law and abiding by the rules of distribution of free software. You can use, modify and/ or redistribute the software under the terms of the CeCILL license as circulated by CEA, CNRS and INRIA at the following URL "http://www.cecill.info". The fact that you are presently reading this means that you have had knowledge of the CeCILL license and that you accept its terms. You can find a copy of this licence shipped with this software at Documentation/licence.en.txt. */ #ifndef PANELBROWSER_H #define PANELBROWSER_H #include #include #include /** * VISU_UI_PANEL_BROWSER_PREVIOUS: * * Value that give the direction when the selector is moved around file list. * See visu_ui_panel_browser_getNextSelected(). */ #define VISU_UI_PANEL_BROWSER_PREVIOUS 0 /** * VISU_UI_PANEL_BROWSER_NEXT: * * Value that give the direction when the selector is moved around file list. * See visu_ui_panel_browser_getNextSelected(). */ #define VISU_UI_PANEL_BROWSER_NEXT 1 /** * visu_ui_panel_browser_init: (skip) * * Should be used in the list declared in externalModules.h to be loaded by * V_Sim on start-up. This routine will create the #VisuUiPanel handling * the browser. * * Returns: a newly created #VisuUiPanel object. */ VisuUiPanel* visu_ui_panel_browser_init(); /** * visu_ui_panel_browser_getNextSelected: * @path: a pointer to returned the path of the newly selected file ; * @iterSelected: a pointer to store the newly selected iter ; * @direction: VISU_UI_PANEL_BROWSER_NEXT or VISU_UI_PANEL_BROWSER_PREVIOUS. * * Change the selected file in the browser given the direction. * * Returns: TRUE if one exists. */ gboolean visu_ui_panel_browser_getNextSelected(GtkTreePath **path, GtkTreeIter *iterSelected, int direction); /** * visu_ui_panel_browser_getCurrentSelected: * @path: a pointer to returned the path of the currently selected file ; * @iterSelected: a pointer to store the currently selected iter. * * Get iter and path of the currently sleected file. * * Returns: TRUE if one exists. */ gboolean visu_ui_panel_browser_getCurrentSelected(GtkTreePath **path, GtkTreeIter *iterSelected); /** * visu_ui_panel_browser_setCurrentDirectory: * @dir: the path of a directory. * * Change the directory for the browser. The directory is not parsed immediately * but only when the subpanel becomes visible. */ void visu_ui_panel_browser_setCurrentDirectory(const gchar *dir); /** * visu_ui_panel_browser_setCurrentDirectories: * @dirs: a NULL terminated array of directories to be loaded. * * Change the directories for the browser. It is the same routine than * visu_ui_panel_browser_setCurrentDirectory(), but several directories can be loaded * at once. But internally, contrary to visu_ui_panel_browser_setCurrentDirectory() * the given array must not be freed since it is not copied. */ void visu_ui_panel_browser_setCurrentDirectories(gchar **dirs); void visu_ui_panel_browser_setMessage(const gchar* message, GtkMessageType message_type); #endif v_sim-3.8.0/src/panelModules/panelConfig.c000066400000000000000000000420341370110300500204400ustar00rootroot00000000000000/* EXTRAITS DE LA LICENCE Copyright CEA, contributeurs : Luc BILLARD et Damien CALISTE, laboratoire L_Sim, (2001-2005) Adresse mèl : BILLARD, non joignable par mèl ; CALISTE, damien P caliste AT cea P fr. Ce logiciel est un programme informatique servant à visualiser des structures atomiques dans un rendu pseudo-3D. Ce logiciel est régi par la licence CeCILL soumise au droit français et respectant les principes de diffusion des logiciels libres. Vous pouvez utiliser, modifier et/ou redistribuer ce programme sous les conditions de la licence CeCILL telle que diffusée par le CEA, le CNRS et l'INRIA sur le site "http://www.cecill.info". Le fait que vous puissiez accéder à cet en-tête signifie que vous avez pris connaissance de la licence CeCILL, et que vous en avez accepté les termes (cf. le fichier Documentation/licence.fr.txt fourni avec ce logiciel). */ /* LICENCE SUM UP Copyright CEA, contributors : Luc BILLARD et Damien CALISTE, laboratoire L_Sim, (2001-2005) E-mail address: BILLARD, not reachable any more ; CALISTE, damien P caliste AT cea P fr. This software is a computer program whose purpose is to visualize atomic configurations in 3D. This software is governed by the CeCILL license under French law and abiding by the rules of distribution of free software. You can use, modify and/ or redistribute the software under the terms of the CeCILL license as circulated by CEA, CNRS and INRIA at the following URL "http://www.cecill.info". The fact that you are presently reading this means that you have had knowledge of the CeCILL license and that you accept its terms. You can find a copy of this licence shipped with this software at Documentation/licence.en.txt. */ #include "panelConfig.h" #include #include #include #include #include /** * SECTION: panelConfig * @short_description: The tab where miscellaneous options are setup. * * Nothing special here. */ #define FLAG_PARAMETER_SKIN_CONFIG "config_skin" #define FLAG_PARAMETER_REFRESH_CONFIG "config_refreshIsOn" #define FLAG_PARAMETER_PERIOD_CONFIG "config_refreshTimeout" #define FLAG_PARAMETER_OLD_PERIOD_CONFIG "config_refreshPeriod" #define DESC_PARAMETER_SKIN_CONFIG "Path to a gtkrc file ; chain" #define DESC_PARAMETER_REFRESH_CONFIG "When on V_Sim reloads the file at periodic time ; boolean 0 or 1" #define DESC_PARAMETER_PERIOD_CONFIG "The period of reloading in s ; integer (0 < v <= 10)" #define PARAMETER_CONFIG_SKIN_DEFAULT "None" static gchar *_skinDefault = NULL; #define PARAMETER_CONFIG_REFRESH_DEFAULT FALSE static gboolean _refreshDefault = PARAMETER_CONFIG_REFRESH_DEFAULT; #define PARAMETER_CONFIG_PERIOD_DEFAULT 1 static guint _periodDefault = PARAMETER_CONFIG_PERIOD_DEFAULT; static GtkWidget *comboUnit, *panelVBox; /* Private functions. */ static GtkWidget *createInteriorConfig(VisuUiRenderingWindow *window); static void setSkin(const char* label); /* These functions write all the element list to export there associated resources. */ static void exportParametersPanelConfig(GString *data, VisuData* dataObj); static void onUnitChanged(GtkComboBox *combo, gpointer data); static void initPanelConfigGtkPart(VisuUiRenderingWindow *window); static char *defaultSkinPath, *userSkinPath; static gboolean isPanelConfigInitialized; /* Specific widgets used in this panel. */ static VisuUiPanel *panelConfig; static GtkWidget *checkShowTab; static GtkWidget *checkRefreshAuto = NULL; static GtkWidget *checkStorePositions; static GtkWidget *checkRedCoord; static GtkWidget *spinRefresh = NULL; static GBinding *autoRefresh_bind = NULL, *periodRefresh_bind = NULL; /* Callbacks */ static void checkShowTabToggled(GtkToggleButton *button, gpointer data); static void checkRememberToggled(GtkToggleButton *button, gpointer data); void entryRcFilesChanged(GtkEntry *entry, gpointer data); void directorySelectedForResources(GtkButton *button, gpointer user_data); void openRcFileSelector(GtkButton *button, gpointer data); static void onDataFocused(GObject *obj, VisuData *dataObj, gpointer data); gboolean treePathClicked(GtkWidget *widget, GdkEventButton *event, gpointer user_data); void directoryRemoveFromResources(GtkButton *button, gpointer user_data); static void onConfigEnter(VisuUiPanel *visu_ui_panel, VisuUiRenderingWindow *window); static void onEntryRefresh(VisuConfigFile *obj, VisuConfigFileEntry *entry, gpointer data); static void onEntryPeriod(VisuConfigFile *obj, VisuConfigFileEntry *entry, gpointer data); static void onEntrySkin(VisuConfigFile *obj, VisuConfigFileEntry *entry, gpointer data); /** * visu_ui_panel_config_init: (skip) * @ui: a #VisuUiMain object. * * Should be used in the list declared in externalModules.h to be loaded by * V_Sim on start-up. This routine will create the #VisuUiPanel where the configuration * stuff can be done, such as the auto-reloading. * * Returns: a newly created #VisuUiPanel object. */ VisuUiPanel* visu_ui_panel_config_init(VisuUiMain *ui) { char *cl = _("Configure the interface"); char *tl = _("Configuration"); int rgPeriod[2] = {1, 10}; VisuConfigFileEntry *entry, *oldEntry; panelConfig = VISU_UI_PANEL(visu_ui_panel_newWithIconFromIconName("Panel_configuration", cl, tl, "preferences-system")); if (!panelConfig) return (VisuUiPanel*)0; visu_config_file_addStringEntry(VISU_CONFIG_FILE_PARAMETER, FLAG_PARAMETER_SKIN_CONFIG, DESC_PARAMETER_SKIN_CONFIG, &_skinDefault); g_signal_connect(VISU_CONFIG_FILE_PARAMETER, "parsed::" FLAG_PARAMETER_SKIN_CONFIG, G_CALLBACK(onEntrySkin), panelConfig); visu_config_file_addBooleanEntry(VISU_CONFIG_FILE_PARAMETER, FLAG_PARAMETER_REFRESH_CONFIG, DESC_PARAMETER_REFRESH_CONFIG, &_refreshDefault, FALSE); g_signal_connect(VISU_CONFIG_FILE_PARAMETER, "parsed::" FLAG_PARAMETER_REFRESH_CONFIG, G_CALLBACK(onEntryRefresh), panelConfig); oldEntry = visu_config_file_addEntry(VISU_CONFIG_FILE_PARAMETER, FLAG_PARAMETER_OLD_PERIOD_CONFIG, DESC_PARAMETER_PERIOD_CONFIG, 1, NULL); entry = visu_config_file_addIntegerArrayEntry(VISU_CONFIG_FILE_PARAMETER, FLAG_PARAMETER_PERIOD_CONFIG, DESC_PARAMETER_PERIOD_CONFIG, 1, (int*)&_periodDefault, rgPeriod, FALSE); visu_config_file_entry_setVersion(entry, 3.8f); visu_config_file_entry_setReplace(entry, oldEntry); g_signal_connect(VISU_CONFIG_FILE_PARAMETER, "parsed::" FLAG_PARAMETER_PERIOD_CONFIG, G_CALLBACK(onEntryPeriod), panelConfig); visu_config_file_addExportFunction(VISU_CONFIG_FILE_PARAMETER, exportParametersPanelConfig); #if GTK_MAJOR_VERSION < 3 defaultSkinPath = g_build_filename(visu_basic_getDataDir(), "v_sim.rc", NULL); userSkinPath = g_build_filename(visu_basic_getLocalDir(), "v_sim.rc", NULL); #else defaultSkinPath = g_build_filename(visu_basic_getDataDir(), "v_sim.css", NULL); userSkinPath = g_build_filename(visu_basic_getLocalDir(), "v_sim.css", NULL); #endif isPanelConfigInitialized = FALSE; /* Set global callbacks. */ g_signal_connect(G_OBJECT(ui), "DataFocused", G_CALLBACK(onDataFocused), (gpointer)0); g_signal_connect(G_OBJECT(panelConfig), "page-entered", G_CALLBACK(onConfigEnter), (gpointer)visu_ui_main_getRendering(ui)); return panelConfig; } static void initPanelConfigGtkPart(VisuUiRenderingWindow *window) { if (isPanelConfigInitialized) return; DBG_fprintf(stderr, "Panel Config : creating the config panel on demand.\n"); isPanelConfigInitialized = TRUE; panelVBox = createInteriorConfig(window); gtk_container_add(GTK_CONTAINER(panelConfig), panelVBox); /* Force the callbacks to initialise the values. */ checkShowTabToggled((GtkToggleButton*)0, (gpointer)0); } static GtkWidget *createInteriorConfig(VisuUiRenderingWindow *window) { GtkWidget *vbox; GtkWidget *hbox; GtkWidget *label; const gchar **units; int i; #if GTK_MAJOR_VERSION == 2 && GTK_MINOR_VERSION < 12 GtkTooltips *tooltips; tooltips = gtk_tooltips_new (); #endif vbox = gtk_vbox_new(FALSE, 0); checkShowTab = gtk_check_button_new_with_mnemonic(_("Always show _labels in tabs")); gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON(checkShowTab), visu_ui_panel_class_getHeaderVisibility()); gtk_box_pack_start(GTK_BOX(vbox), checkShowTab, FALSE, FALSE, 3); hbox = gtk_hbox_new(FALSE, 0); gtk_box_pack_start(GTK_BOX(vbox), hbox, FALSE, FALSE, 3); checkRefreshAuto = gtk_check_button_new_with_mnemonic(_("Automatic _refresh")); gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON(checkRefreshAuto), _refreshDefault); gtk_box_pack_start(GTK_BOX(hbox), checkRefreshAuto, FALSE, FALSE, 0); hbox = gtk_hbox_new(FALSE, 0); gtk_box_pack_start(GTK_BOX(vbox), hbox, FALSE, FALSE, 3); label = gtk_label_new(_(" s")); gtk_box_pack_end(GTK_BOX(hbox), label, FALSE, FALSE, 0); spinRefresh = gtk_spin_button_new_with_range(1., 10., 1.); gtk_spin_button_set_value(GTK_SPIN_BUTTON(spinRefresh), _periodDefault); gtk_box_pack_end(GTK_BOX(hbox), spinRefresh, FALSE, FALSE, 0); label = gtk_label_new(_("period:")); gtk_box_pack_end(GTK_BOX(hbox), label, FALSE, FALSE, 0); hbox = gtk_hbox_new(FALSE, 0); gtk_box_pack_start(GTK_BOX(vbox), hbox, FALSE, FALSE, 3); checkStorePositions = gtk_check_button_new_with_mnemonic(_("Remember _windows positions")); gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON(checkStorePositions), (gboolean)TRUE); gtk_box_pack_start(GTK_BOX(hbox), checkStorePositions, FALSE, FALSE, 0); checkRedCoord = gtk_check_button_new_with_mnemonic(_("Display _coordinates in reduce")); g_object_bind_property(window, "coordinates-in-reduced", checkRedCoord, "active", G_BINDING_SYNC_CREATE | G_BINDING_BIDIRECTIONAL); gtk_box_pack_start(GTK_BOX(vbox), checkRedCoord, FALSE, FALSE, 3); hbox = gtk_hbox_new(FALSE, 0); gtk_box_pack_start(GTK_BOX(vbox), hbox, FALSE, FALSE, 3); label = gtk_label_new(_("Set the prefered unit:")); gtk_box_pack_start(GTK_BOX(hbox), label, FALSE, FALSE, 5); comboUnit = gtk_combo_box_text_new(); units = tool_physic_getUnitNames(); for (i = 0; units[i]; i++) gtk_combo_box_text_append(GTK_COMBO_BOX_TEXT(comboUnit), (const gchar*)0, units[i]); gtk_combo_box_set_active(GTK_COMBO_BOX(comboUnit), visu_basic_getPreferedUnit()); g_signal_connect(G_OBJECT(comboUnit), "changed", G_CALLBACK(onUnitChanged), (gpointer)0); gtk_box_pack_start(GTK_BOX(hbox), comboUnit, FALSE, FALSE, 0); /* Set the callbacks. */ g_signal_connect(G_OBJECT(checkShowTab), "toggled", G_CALLBACK(checkShowTabToggled), (gpointer)0); g_signal_connect(G_OBJECT(checkStorePositions), "toggled", G_CALLBACK(checkRememberToggled), (gpointer)0); gtk_widget_show_all(vbox); return vbox; } /*************/ /* Callbacks */ /*************/ static void checkShowTabToggled(GtkToggleButton *button _U_, gpointer data _U_) { visu_ui_panel_class_setHeaderVisibility(gtk_toggle_button_get_active(GTK_TOGGLE_BUTTON(checkShowTab))); } static void checkRememberToggled(GtkToggleButton *button, gpointer data _U_) { visu_ui_main_class_setRememberPosition(gtk_toggle_button_get_active(GTK_TOGGLE_BUTTON(button))); } static void onConfigEnter(VisuUiPanel *visu_ui_panel _U_, VisuUiRenderingWindow *window) { if (!isPanelConfigInitialized) initPanelConfigGtkPart(window); gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON(checkStorePositions), visu_ui_main_class_getRememberPosition()); } void openRcFileSelector(GtkButton *button _U_, gpointer data _U_) { } static void setSkin(const char* label) { const char *tmp; #if GTK_MAJOR_VERSION < 3 GtkSettings *settings; #else GError *error; GtkCssProvider *css; #endif if (!label || label[0] == '\0' || !strcmp(label, "None")) return; if (!strcmp(label, "V_Sim")) { /* We try first a skin in the user config path. */ if (g_file_test(userSkinPath, G_FILE_TEST_EXISTS | G_FILE_TEST_IS_REGULAR)) tmp = userSkinPath; else tmp = defaultSkinPath; } else tmp = label; /* test if the file exists or fall back on default installation path */ DBG_fprintf(stderr,"Panel Config: Reading rc file '%s' ... %d\n", tmp, g_file_test(tmp, G_FILE_TEST_EXISTS | G_FILE_TEST_IS_REGULAR)); if (!g_file_test(tmp, G_FILE_TEST_EXISTS | G_FILE_TEST_IS_REGULAR)) return; #if GTK_MAJOR_VERSION < 3 gtk_rc_parse(tmp); DBG_fprintf(stderr, "Panel Config: get the settings.\n"); settings = gtk_settings_get_default (); gtk_rc_reparse_all_for_settings(settings, TRUE); DBG_fprintf(stderr,"Panel Config: applying RC file OK.\n"); #else css = gtk_css_provider_new(); error = (GError*)0; gtk_css_provider_load_from_path(css, tmp, &error); if (error) { g_warning("%s", error->message); g_error_free(error); } DBG_fprintf(stderr, "Panel Config: CSS file loaded.\n"); gtk_style_context_add_provider_for_screen(gdk_screen_get_default(), GTK_STYLE_PROVIDER(css), GTK_STYLE_PROVIDER_PRIORITY_APPLICATION); g_object_unref(G_OBJECT(css)); gtk_style_context_reset_widgets(gdk_screen_get_default()); #endif } static void onDataFocused(GObject *obj _U_, VisuData *dataObj, gpointer data _U_) { gboolean isLoadable; DBG_fprintf(stderr, "Panel Config: caught the 'DataFocused' signal\n"); if (!dataObj) return; isLoadable = VISU_IS_DATA_LOADABLE(dataObj); if (checkRefreshAuto && spinRefresh) { gtk_widget_set_sensitive(checkRefreshAuto, isLoadable); gtk_widget_set_sensitive(spinRefresh, isLoadable); if (!isLoadable) return; if (autoRefresh_bind) g_object_unref(autoRefresh_bind); autoRefresh_bind = g_object_bind_property(checkRefreshAuto, "active", dataObj, "auto-refresh", G_BINDING_SYNC_CREATE & G_BINDING_BIDIRECTIONAL); if (periodRefresh_bind) g_object_unref(periodRefresh_bind); periodRefresh_bind = g_object_bind_property(spinRefresh, "value", dataObj, "refresh-period", G_BINDING_SYNC_CREATE & G_BINDING_BIDIRECTIONAL); } else if (isLoadable) g_object_set(dataObj, "auto-refresh", _refreshDefault, "refresh-period", _periodDefault, NULL); } static void onUnitChanged(GtkComboBox *combo, gpointer data _U_) { visu_basic_setPreferedUnit(gtk_combo_box_get_active(combo)); } /**********************************/ /* Public method to change values */ /**********************************/ /** * visu_ui_panel_config_getArea: * * This routine can be used to extend the configure panel from plug-ins. * * Since: 3.7 * * Returns: (transfer none): a #GtkBox containing elements of the * configure panel. **/ GtkWidget* visu_ui_panel_config_getArea() { if (!isPanelConfigInitialized) initPanelConfigGtkPart(visu_ui_main_class_getDefaultRendering()); return panelVBox; } /********************/ /* In/Out functions */ /********************/ static void onEntrySkin(VisuConfigFile *obj _U_, VisuConfigFileEntry *entry _U_, gpointer data _U_) { setSkin(_skinDefault); } static void onEntryRefresh(VisuConfigFile *obj _U_, VisuConfigFileEntry *entry _U_, gpointer data) { VisuData *dataObj; dataObj = visu_ui_panel_getData(VISU_UI_PANEL(data)); if (VISU_IS_DATA_LOADABLE(dataObj)) g_object_set(dataObj, "auto-refresh", _refreshDefault, NULL); } static void onEntryPeriod(VisuConfigFile *obj _U_, VisuConfigFileEntry *entry _U_, gpointer data) { VisuData *dataObj; dataObj = visu_ui_panel_getData(VISU_UI_PANEL(data)); if (VISU_IS_DATA_LOADABLE(dataObj)) g_object_set(dataObj, "refresh-period", _periodDefault, NULL); } /* These functions write all the element list to export there associated resources. */ static void exportParametersPanelConfig(GString *data, VisuData *dataObj _U_) { g_string_append_printf(data, "# %s\n", DESC_PARAMETER_SKIN_CONFIG); g_string_append_printf(data, "%s[gtk]: %s\n\n", FLAG_PARAMETER_SKIN_CONFIG, _skinDefault); g_string_append_printf(data, "# %s\n", DESC_PARAMETER_REFRESH_CONFIG); g_string_append_printf(data, "%s[gtk]: %d\n\n", FLAG_PARAMETER_REFRESH_CONFIG, (checkRefreshAuto) ? gtk_toggle_button_get_active(GTK_TOGGLE_BUTTON(checkRefreshAuto)) : _refreshDefault); g_string_append_printf(data, "# %s\n", DESC_PARAMETER_PERIOD_CONFIG); g_string_append_printf(data, "%s[gtk]: %i\n\n", FLAG_PARAMETER_PERIOD_CONFIG, (spinRefresh) ? gtk_spin_button_get_value_as_int(GTK_SPIN_BUTTON(spinRefresh)) : (int)_periodDefault); } v_sim-3.8.0/src/panelModules/panelConfig.h000066400000000000000000000040231370110300500204410ustar00rootroot00000000000000/* EXTRAITS DE LA LICENCE Copyright CEA, contributeurs : Luc BILLARD et Damien CALISTE, laboratoire L_Sim, (2001-2005) Adresse mèl : BILLARD, non joignable par mèl ; CALISTE, damien P caliste AT cea P fr. Ce logiciel est un programme informatique servant à visualiser des structures atomiques dans un rendu pseudo-3D. Ce logiciel est régi par la licence CeCILL soumise au droit français et respectant les principes de diffusion des logiciels libres. Vous pouvez utiliser, modifier et/ou redistribuer ce programme sous les conditions de la licence CeCILL telle que diffusée par le CEA, le CNRS et l'INRIA sur le site "http://www.cecill.info". Le fait que vous puissiez accéder à cet en-tête signifie que vous avez pris connaissance de la licence CeCILL, et que vous en avez accepté les termes (cf. le fichier Documentation/licence.fr.txt fourni avec ce logiciel). */ /* LICENCE SUM UP Copyright CEA, contributors : Luc BILLARD et Damien CALISTE, laboratoire L_Sim, (2001-2005) E-mail address: BILLARD, not reachable any more ; CALISTE, damien P caliste AT cea P fr. This software is a computer program whose purpose is to visualize atomic configurations in 3D. This software is governed by the CeCILL license under French law and abiding by the rules of distribution of free software. You can use, modify and/ or redistribute the software under the terms of the CeCILL license as circulated by CEA, CNRS and INRIA at the following URL "http://www.cecill.info". The fact that you are presently reading this means that you have had knowledge of the CeCILL license and that you accept its terms. You can find a copy of this licence shipped with this software at Documentation/licence.en.txt. */ #ifndef PANELCONFIG_H #define PANELCONFIG_H #include #include #include #include #include VisuUiPanel* visu_ui_panel_config_init(VisuUiMain *ui); GtkWidget* visu_ui_panel_config_getArea(); #endif v_sim-3.8.0/src/panelModules/panelDataFile.c000066400000000000000000001653411370110300500207130ustar00rootroot00000000000000/* EXTRAITS DE LA LICENCE Copyright CEA, contributeurs : Luc BILLARD et Damien CALISTE, laboratoire L_Sim, (2001-2005) Adresse mèl : BILLARD, non joignable par mèl ; CALISTE, damien P caliste AT cea P fr. Ce logiciel est un programme informatique servant à visualiser des structures atomiques dans un rendu pseudo-3D. Ce logiciel est régi par la licence CeCILL soumise au droit français et respectant les principes de diffusion des logiciels libres. Vous pouvez utiliser, modifier et/ou redistribuer ce programme sous les conditions de la licence CeCILL telle que diffusée par le CEA, le CNRS et l'INRIA sur le site "http://www.cecill.info". Le fait que vous puissiez accéder à cet en-tête signifie que vous avez pris connaissance de la licence CeCILL, et que vous en avez accepté les termes (cf. le fichier Documentation/licence.fr.txt fourni avec ce logiciel). */ /* LICENCE SUM UP Copyright CEA, contributors : Luc BILLARD et Damien CALISTE, laboratoire L_Sim, (2001-2005) E-mail address: BILLARD, not reachable any more ; CALISTE, damien P caliste AT cea P fr. This software is a computer program whose purpose is to visualize atomic configurations in 3D. This software is governed by the CeCILL license under French law and abiding by the rules of distribution of free software. You can use, modify and/ or redistribute the software under the terms of the CeCILL license as circulated by CEA, CNRS and INRIA at the following URL "http://www.cecill.info". The fact that you are presently reading this means that you have had knowledge of the CeCILL license and that you accept its terms. You can find a copy of this licence shipped with this software at Documentation/licence.en.txt. */ #include "panelDataFile.h" #include #include #include #include #include #include #include #include #include #include #include #include #include /** * SECTION: panelDataFile * @short_description: The tab where to configure the action of an * external data file on colourisation of nodes. * * The widgets are organised in three categories. The first is * used to normalised the inputs, see visu_colorization_setMin() / * visu_colorization_setMax(). The second category is used for * colourisation, see visu_colorization_setShade(). Finally the last * category is about post-processing. */ /* Local variables. */ static GtkWidget *panelDataFile; static gboolean panelDataFileIsInitiated; static VisuColorization *attachedDt; #define RED_DATA_LABEL _("R") #define GREEN_DATA_LABEL _("G") #define BLUE_DATA_LABEL _("B") #define HUE_DATA_LABEL _("H") #define SAT_DATA_LABEL _("S") #define VAL_DATA_LABEL _("V") char* labelRGB[3]; char* labelHSV[3]; #define COL_ONE "1." #define COL_COORD_X _("coord. x") #define COL_COORD_Y _("coord. y") #define COL_COORD_Z _("coord. z") #define N_COORDS_COLS 3 #define COLOR_PREVIEW_WIDTH 120 #define COLOR_PREVIEW_HEIGHT 15 #define COLOR_PREVIEW_BITS 8 #define COLOR_TRANSFORMATION_WIDTH 60 #define COLOR_TRANSFORMATION_HEIGHT 40 #define MIN_MAX_NO_DATA_FILE _("No data file loaded") #define DATA_FILE_NO_FILE_MESSAGE _("No data file") /* Local methods. */ static void createInteriorDataFile(VisuGlNodeScene *scene); static void _createDialogFilters(GtkFileChooser *chooser, const gchar *ext); static void updateStatusBar(const VisuColorization *dt); static gboolean hideBelow(const VisuNodeMasker *masker, const VisuNodeValuesIter *at, gpointer data); /* Linkable widgets */ static GtkWidget *vBoxDataFileOption, *vboxNormalize; static GtkWidget *openDataFileButton; static GtkWidget *checkbuttonAutoLoad; static GBinding *bind_auto; static GtkWidget *statusbarDataFile; static guint statusDataFileContextId; static GtkWidget *expanderTransformation; static GtkWidget *expanderPostProcessing; static GtkWidget *readMinMaxValues; static GtkWidget *checkHideMinValues; static GtkWidget *spinHideMinValues; static GtkWidget *entryHideMinValues; static GtkWidget *entryFileExtension; static GBinding *bind_ext; static GtkWidget *comboboxRange; static GBinding *bind_box; static GtkListStore *colsModel; static GtkWidget *comboboxDataCh[3]; static GBinding *bind_cols[3]; static GtkWidget *checkRestrict; static GBinding *bind_restrict; static GtkWidget *checkbuttonData; static GBinding *bind_used; static GtkWidget *entryDataMin, *entryDataMax; static GBinding *bind_manualMin, *bind_manualMax; static GtkWidget *radioNormalized, *radioMinMax; static GBinding *bind_scaleAuto, *bind_scaleManual; static GtkWidget *comboPreSetColorRange; static GBinding *bind_preset/* , *bind_presetNot */; static GtkWidget *radiobuttonDataRGB, *radiobuttonDataHSV; static GBinding *bind_RGB, *bind_HSV; static GtkWidget *colorPreview, *labelPreview; static GdkPixbuf *pixbufColorPreview; static GBinding *bind_preview, *bind_warn, *bind_pixbuf; static GtkWidget *checkLegend; static GBinding *bind_legend; static GtkWidget *comboboxPresetCol; static GBinding *bind_presetCol; static GtkWidget *tableLinearToolShade; static GBinding *bind_linear; static GtkWidget *spinbuttonDataChA[3], *spinbuttonDataChB[3]; static GBinding *bind_spinA[3], *bind_spinB[3]; static GtkWidget *comboboxScaling, *checkScaleRadius; static GBinding *bind_scaling, *bind_radius; /* Signals that need to be suspended */ static gulong ncols_signal, file_signal, data_signal; /* Callbacks */ static void onLoadDataFile(GtkFileChooserButton *button, gpointer data); static void onComboManualChange(GtkComboBox *combo, gpointer data); static void onSpinHideMinValuesChange(GtkSpinButton *spin, gpointer data); static void onEntryHideMinValuesChange(VisuUiNumericalEntry *entry, double oldValue, gpointer data); static void onCheckHideMinValuesChange(GtkToggleButton *toggle, gpointer data); static void onDataFileEnter(VisuUiPanel *visu_ui_panel, gpointer data); static void onEntryExtChange(GtkEntry *entry, gpointer data); static gboolean onEntryExtFocus(GtkEntry *entry, GdkEventFocus *event, gpointer data); static void onColumns(VisuColorization *dt, GParamSpec *pspec, gpointer data); static void onFile(VisuColorization *dt, GParamSpec *pspec, gpointer data); static void onDataMM(VisuColorization *dt, GParamSpec *pspec, gpointer data); static void _set(VisuColorization *dt); static gboolean _setAttachedData(VisuColorization *dt); struct _HideBelowData { guint column; float value; }; static struct _HideBelowData hidingData; /** * visu_ui_panel_colorization_init: (skip) * @ui: a #VisuUiMain object. * * Should be used in the list declared in externalModules.h to be loaded by * V_Sim on start-up. This routine will create the #VisuUiPanel where the colouring * stuff can be done, such as choosing a colour shade, opening a file, * setting boundaries... * * Returns: a newly created #VisuUiPanel object. */ VisuUiPanel* visu_ui_panel_colorization_init(VisuUiMain *ui _U_) { char *cl = _("Colorize with data"); char *tl = _("Data color"); GtkTreeIter iter; VisuGlNodeScene *scene; labelRGB[0] = RED_DATA_LABEL; labelRGB[1] = GREEN_DATA_LABEL; labelRGB[2] = BLUE_DATA_LABEL; labelHSV[0] = HUE_DATA_LABEL; labelHSV[1] = SAT_DATA_LABEL; labelHSV[2] = VAL_DATA_LABEL; panelDataFile = visu_ui_panel_newWithIconFromPath("Panel_colorise", cl, tl, "stock-data_20.png"); if (!panelDataFile) return (VisuUiPanel*)0; visu_ui_panel_setDockable(VISU_UI_PANEL(panelDataFile), TRUE); /* Local variables */ colsModel = gtk_list_store_new(2, G_TYPE_INT, G_TYPE_STRING); gtk_list_store_append(colsModel, &iter); gtk_list_store_set(colsModel, &iter, 0, VISU_COLORIZATION_FROM_X, 1, COL_COORD_X, -1); gtk_list_store_append(colsModel, &iter); gtk_list_store_set(colsModel, &iter, 0, VISU_COLORIZATION_FROM_Y, 1, COL_COORD_Y, -1); gtk_list_store_append(colsModel, &iter); gtk_list_store_set(colsModel, &iter, 0, VISU_COLORIZATION_FROM_Z, 1, COL_COORD_Z, -1); entryFileExtension = (GtkWidget*)0; tableLinearToolShade = (GtkWidget*)0; panelDataFileIsInitiated = FALSE; attachedDt = (VisuColorization*)0; scene = visu_ui_rendering_window_getGlScene(visu_ui_main_class_getDefaultRendering()); /* Local callbacks. */ g_signal_connect(panelDataFile, "page-entered", G_CALLBACK(onDataFileEnter), scene); g_signal_connect_swapped(panelDataFile, "destroy", G_CALLBACK(_setAttachedData), (gpointer)0); return VISU_UI_PANEL(panelDataFile); } /* static gboolean fromSingle(GBinding *bind _U_, const GValue *from, GValue *to, gpointer data _U_) */ /* { */ /* g_value_set_boolean(to, g_value_get_int(from) != VISU_COLORIZATION_UNSET); */ /* return TRUE; */ /* } */ static gboolean setChLabels(GBinding *bind _U_, const GValue *from, GValue *to, gpointer data) { if (g_value_get_boolean(from)) g_value_set_static_string(to, labelRGB[GPOINTER_TO_INT(data)]); else g_value_set_static_string(to, labelHSV[GPOINTER_TO_INT(data)]); return TRUE; } static void createInteriorDataFile(VisuGlNodeScene *scene) { GtkWidget *containerDataFilePanel; GtkWidget *scrolledwindow1, *wd; GtkWidget *viewport1; GtkWidget *vbox; GtkWidget *vboxLimits, *vboxTransformation, *vboxPostProcessing; GtkWidget *hbox3; GtkWidget *hbox8; GSList *radioNormalized_group = NULL; GtkWidget *table2; GtkWidget *label7; GtkWidget *label8; GtkWidget *hbox6; GSList *radiobuttonDataRGB_group = NULL; GtkWidget *label; GtkWidget *label14; GtkWidget *label15; GtkWidget *label16; GtkWidget *label20; GtkWidget *label21; GtkWidget *hrule; GtkWidget *hboxPreSetColorRange; GtkCellRenderer *renderer; gint i; const gchar *dir; #if GTK_MAJOR_VERSION == 2 && GTK_MINOR_VERSION < 12 GtkTooltips *tooltips; tooltips = gtk_tooltips_new (); #endif DBG_fprintf(stderr, "Panel DataFile : creating subpanel.\n"); containerDataFilePanel = gtk_vbox_new (FALSE, 0); gtk_widget_set_margin_start(containerDataFilePanel, 5); gtk_widget_set_margin_end(containerDataFilePanel, 5); checkbuttonData = gtk_check_button_new_with_mnemonic(_("_Use color scheme")); gtk_box_pack_start (GTK_BOX (containerDataFilePanel), checkbuttonData, FALSE, FALSE, 0); scrolledwindow1 = gtk_scrolled_window_new (NULL, NULL); gtk_scrolled_window_set_shadow_type(GTK_SCROLLED_WINDOW (scrolledwindow1), GTK_SHADOW_IN); gtk_scrolled_window_set_policy (GTK_SCROLLED_WINDOW (scrolledwindow1), GTK_POLICY_AUTOMATIC, GTK_POLICY_AUTOMATIC); gtk_box_pack_start (GTK_BOX (containerDataFilePanel), scrolledwindow1, TRUE, TRUE, 0); viewport1 = gtk_viewport_new (NULL, NULL); gtk_container_add (GTK_CONTAINER (scrolledwindow1), viewport1); vbox = gtk_vbox_new (FALSE, 0); gtk_container_add (GTK_CONTAINER (viewport1), vbox); vBoxDataFileOption = vbox; g_object_bind_property(scene, "data", vBoxDataFileOption, "sensitive", G_BINDING_SYNC_CREATE); /********************/ /* The Data subset. */ /********************/ hbox3 = gtk_hbox_new(FALSE, 0); gtk_box_pack_start(GTK_BOX(vbox), hbox3, FALSE, FALSE, 0); checkbuttonAutoLoad = gtk_check_button_new_with_mnemonic(_("_Auto load data")); gtk_box_pack_end(GTK_BOX(hbox3), checkbuttonAutoLoad, FALSE, FALSE, 0); gtk_widget_set_tooltip_text(checkbuttonAutoLoad, _("Try to load a data file whenever a new V_Sim file is loaded." " For example, if 'example.ascii' has just been opened, V_Sim" " will look for 'example.dat' and will apply it.")); entryFileExtension = gtk_entry_new(); gtk_entry_set_width_chars(GTK_ENTRY(entryFileExtension), 4); g_signal_connect(G_OBJECT(entryFileExtension), "activate", G_CALLBACK(onEntryExtChange), (gpointer)0); g_signal_connect(G_OBJECT(entryFileExtension), "focus-out-event", G_CALLBACK(onEntryExtFocus), (gpointer)0); #if GTK_MAJOR_VERSION > 2 || GTK_MINOR_VERSION > 12 openDataFileButton = gtk_file_chooser_button_new(_("Load data file"), GTK_FILE_CHOOSER_ACTION_OPEN); dir = visu_ui_main_getLastOpenDirectory(visu_ui_main_class_getCurrentPanel()); gtk_file_chooser_set_current_folder(GTK_FILE_CHOOSER(openDataFileButton), dir); _createDialogFilters(GTK_FILE_CHOOSER(openDataFileButton), gtk_entry_get_text(GTK_ENTRY(entryFileExtension))); g_signal_connect(G_OBJECT(openDataFileButton), "file-set", G_CALLBACK(onLoadDataFile), (gpointer)0); #else openDataFileButton = gtk_button_new_from_stock (GTK_STOCK_OPEN); g_signal_connect(G_OBJECT(openDataFileButton), "clicked", G_CALLBACK(loadDataFile), (gpointer)0); #endif gtk_widget_set_tooltip_text(openDataFileButton, _("Choose a file to read the colorization data from.")); gtk_box_pack_start(GTK_BOX(hbox3), openDataFileButton, TRUE, TRUE, 0); gtk_box_pack_start(GTK_BOX(hbox3), entryFileExtension, FALSE, FALSE, 5); gtk_widget_set_tooltip_text(entryFileExtension, _("File extension used for the autoload option, its value is" " saved in the parameter file (see 'dataFile_fileExt').")); vboxNormalize = gtk_vbox_new(FALSE, 0); gtk_box_pack_start(GTK_BOX(vbox), vboxNormalize, FALSE, FALSE, 0); hbox3 = gtk_hbox_new (FALSE, 0); gtk_box_pack_start(GTK_BOX(vboxNormalize), hbox3, FALSE, FALSE, 0); label = gtk_label_new(_("Normalize input: ")); gtk_widget_set_name(label, "label_head"); gtk_label_set_xalign(GTK_LABEL(label), 0.); gtk_box_pack_start (GTK_BOX (hbox3), label, TRUE, TRUE, 0); radioNormalized = gtk_radio_button_new_with_mnemonic (NULL, _("auto")); gtk_box_pack_start (GTK_BOX (hbox3), radioNormalized, FALSE, FALSE, 0); gtk_radio_button_set_group (GTK_RADIO_BUTTON (radioNormalized), radioNormalized_group); radioNormalized_group = gtk_radio_button_get_group (GTK_RADIO_BUTTON (radioNormalized)); radioMinMax = gtk_radio_button_new_with_mnemonic (NULL, _("manual")); gtk_box_pack_start (GTK_BOX (hbox3), radioMinMax, FALSE, FALSE, 0); gtk_radio_button_set_group (GTK_RADIO_BUTTON (radioMinMax), radioNormalized_group); radioNormalized_group = gtk_radio_button_get_group (GTK_RADIO_BUTTON (radioMinMax)); wd = gtk_expander_new(_("More information")); gtk_box_pack_start(GTK_BOX(vboxNormalize), wd, FALSE, FALSE, 0); g_object_bind_property(radioMinMax, "active", wd, "expanded", G_BINDING_SYNC_CREATE); vboxLimits = gtk_vbox_new(FALSE, 0); gtk_widget_set_margin_start(vboxLimits, 15); gtk_container_add(GTK_CONTAINER(wd), vboxLimits); /* label = gtk_label_new(_("Read min/max values:")); */ /* gtk_label_set_use_markup(GTK_LABEL(label), TRUE); */ /* gtk_misc_set_alignment(GTK_MISC(label), 0., 0.5); */ /* gtk_box_pack_start(GTK_BOX(vboxLimits), label, FALSE, FALSE, 0); */ readMinMaxValues = gtk_box_new(GTK_ORIENTATION_VERTICAL, 0); gtk_box_pack_start(GTK_BOX(vboxLimits), readMinMaxValues, FALSE, FALSE, 0); label = gtk_label_new(MIN_MAX_NO_DATA_FILE); gtk_widget_set_margin_start(label, 10); gtk_label_set_use_markup(GTK_LABEL(label), TRUE); gtk_box_pack_start(GTK_BOX(readMinMaxValues), label, FALSE, FALSE, 0); label = gtk_label_new(_("Input data bounds:")); gtk_label_set_use_markup(GTK_LABEL(label), TRUE); gtk_label_set_xalign(GTK_LABEL(label), 0.); gtk_box_pack_start(GTK_BOX(vboxLimits), label, FALSE, FALSE, 0); table2 = gtk_grid_new(); tool_grid_resize(table2, 1, 6); gtk_widget_set_margin_start(table2, 10); gtk_box_pack_start(GTK_BOX(vboxLimits), table2, FALSE, FALSE, 0); gtk_grid_set_column_spacing(GTK_GRID(table2), 3); entryDataMax = visu_ui_numerical_entry_new(1.); gtk_entry_set_width_chars(GTK_ENTRY(entryDataMax), 6); gtk_grid_attach(GTK_GRID(table2), entryDataMax, 3, 0, 1, 1); g_object_bind_property(radioMinMax, "active", entryDataMax, "sensitive", G_BINDING_SYNC_CREATE); entryDataMin = visu_ui_numerical_entry_new(-1.); gtk_entry_set_width_chars(GTK_ENTRY(entryDataMin), 6); gtk_grid_attach(GTK_GRID(table2), entryDataMin, 1, 0, 1, 1); g_object_bind_property(radioMinMax, "active", entryDataMin, "sensitive", G_BINDING_SYNC_CREATE); renderer = gtk_cell_renderer_text_new(); comboboxRange = gtk_combo_box_new_with_model(GTK_TREE_MODEL(colsModel)); gtk_cell_layout_pack_start(GTK_CELL_LAYOUT(comboboxRange), renderer, TRUE); gtk_cell_layout_add_attribute(GTK_CELL_LAYOUT(comboboxRange), renderer, "text", 1); /* gtk_combo_box_set_id_column(GTK_COMBO_BOX(comboboxRange), 1); */ gtk_combo_box_set_active(GTK_COMBO_BOX(comboboxRange), 0); gtk_grid_attach(GTK_GRID(table2), comboboxRange, 5, 0, 1, 1); g_object_bind_property(radioMinMax, "active", comboboxRange, "sensitive", G_BINDING_SYNC_CREATE); label7 = gtk_label_new (_("Min:")); gtk_grid_attach(GTK_GRID(table2), label7, 0, 0, 1, 1); gtk_label_set_xalign(GTK_LABEL(label7), 1.); label8 = gtk_label_new (_("Max:")); gtk_grid_attach(GTK_GRID(table2), label8, 2, 0, 1, 1); gtk_label_set_xalign(GTK_LABEL(label8), 1.); label8 = gtk_label_new(_("Col.:")); gtk_grid_attach(GTK_GRID(table2), label8, 4, 0, 1, 1); gtk_label_set_xalign(GTK_LABEL(label8), 1.); /* Bar */ hrule = gtk_hseparator_new(); gtk_box_pack_start(GTK_BOX(vbox), hrule, FALSE, FALSE, 8); /***********************/ /* Transformation part */ /***********************/ label = gtk_label_new(_("Define the color scheme:")); gtk_widget_set_name(label, "label_head"); gtk_label_set_xalign(GTK_LABEL(label), 0.); gtk_box_pack_start(GTK_BOX(vbox), label, FALSE, FALSE, 0); hboxPreSetColorRange = gtk_hbox_new (FALSE, 0); gtk_box_pack_start(GTK_BOX(vbox), hboxPreSetColorRange, FALSE, FALSE, 0); /* label = gtk_label_new(_("Preset:")); */ /* gtk_misc_set_alignment(GTK_MISC(label), 0., 0.5); */ /* gtk_box_pack_start(GTK_BOX(hboxPreSetColorRange), label, TRUE, TRUE, 0); */ comboPreSetColorRange = visu_ui_shade_combobox_new(FALSE, TRUE); gtk_box_pack_start(GTK_BOX(hboxPreSetColorRange), comboPreSetColorRange, TRUE, TRUE, 0); renderer = gtk_cell_renderer_text_new(); comboboxPresetCol = gtk_combo_box_new_with_model(GTK_TREE_MODEL(colsModel)); gtk_cell_layout_pack_start(GTK_CELL_LAYOUT(comboboxPresetCol), renderer, TRUE); gtk_cell_layout_add_attribute(GTK_CELL_LAYOUT(comboboxPresetCol), renderer, "text", 1); gtk_box_pack_start(GTK_BOX(hboxPreSetColorRange), comboboxPresetCol, FALSE, FALSE, 0); expanderTransformation = gtk_expander_new(_("More options")); gtk_expander_set_expanded(GTK_EXPANDER(expanderTransformation), FALSE); gtk_box_pack_start(GTK_BOX (vbox), expanderTransformation, FALSE, FALSE, 0); vboxTransformation = gtk_vbox_new(FALSE, 0); gtk_widget_set_margin_start(vboxTransformation, 15); gtk_container_add(GTK_CONTAINER(expanderTransformation), vboxTransformation); hbox6 = gtk_hbox_new (FALSE, 0); gtk_box_pack_start (GTK_BOX (vboxTransformation), hbox6, FALSE, FALSE, 0); label = gtk_label_new(_("Color space: ")); gtk_label_set_use_markup(GTK_LABEL(label), TRUE); gtk_label_set_xalign(GTK_LABEL(label), 0.); gtk_box_pack_start (GTK_BOX (hbox6), label, TRUE, TRUE, 0); radiobuttonDataRGB = gtk_radio_button_new_with_mnemonic (NULL, _("RGB")); gtk_box_pack_start (GTK_BOX (hbox6), radiobuttonDataRGB, FALSE, FALSE, 0); gtk_radio_button_set_group (GTK_RADIO_BUTTON (radiobuttonDataRGB), radiobuttonDataRGB_group); radiobuttonDataRGB_group = gtk_radio_button_get_group (GTK_RADIO_BUTTON (radiobuttonDataRGB)); radiobuttonDataHSV = gtk_radio_button_new_with_mnemonic (NULL, _("HSV")); gtk_box_pack_start (GTK_BOX (hbox6), radiobuttonDataHSV, FALSE, FALSE, 0); gtk_radio_button_set_group (GTK_RADIO_BUTTON (radiobuttonDataHSV), radiobuttonDataRGB_group); radiobuttonDataRGB_group = gtk_radio_button_get_group (GTK_RADIO_BUTTON (radiobuttonDataHSV)); tableLinearToolShade = gtk_grid_new(); tool_grid_resize(tableLinearToolShade, 3, 7); gtk_box_pack_start (GTK_BOX (vboxTransformation), tableLinearToolShade, FALSE, FALSE, 0); gtk_container_set_border_width (GTK_CONTAINER (tableLinearToolShade), 3); gtk_grid_set_row_spacing(GTK_GRID(tableLinearToolShade), 3); wd= gtk_label_new (labelRGB[0]); gtk_grid_attach(GTK_GRID(tableLinearToolShade), wd, 0, 0, 1, 1); gtk_label_set_xalign(GTK_LABEL(wd), 0.); g_object_bind_property_full(radiobuttonDataRGB, "active", wd, "label", G_BINDING_SYNC_CREATE, setChLabels, (GBindingTransformFunc)0, GINT_TO_POINTER(0), (GDestroyNotify)0); wd = gtk_label_new (labelRGB[1]); gtk_grid_attach(GTK_GRID(tableLinearToolShade), wd, 0, 1, 1, 1); gtk_label_set_xalign(GTK_LABEL(wd), 0.); g_object_bind_property_full(radiobuttonDataRGB, "active", wd, "label", G_BINDING_SYNC_CREATE, setChLabels, (GBindingTransformFunc)0, GINT_TO_POINTER(1), (GDestroyNotify)0); wd = gtk_label_new (labelRGB[2]); gtk_grid_attach(GTK_GRID(tableLinearToolShade), wd, 0, 2, 1, 1); gtk_label_set_xalign(GTK_LABEL(wd), 0.); g_object_bind_property_full(radiobuttonDataRGB, "active", wd, "label", G_BINDING_SYNC_CREATE, setChLabels, (GBindingTransformFunc)0, GINT_TO_POINTER(2), (GDestroyNotify)0); label14 = gtk_label_new ("="); gtk_grid_attach(GTK_GRID(tableLinearToolShade), label14, 1, 0, 1, 1); label14 = gtk_label_new ("="); gtk_grid_attach(GTK_GRID(tableLinearToolShade), label14, 1, 1, 1, 1); label14 = gtk_label_new ("="); gtk_grid_attach(GTK_GRID(tableLinearToolShade), label14, 1, 2, 1, 1); label15 = gtk_label_new ("+"); gtk_grid_attach(GTK_GRID(tableLinearToolShade), label15, 3, 0, 1, 1); label15 = gtk_label_new ("+"); gtk_grid_attach(GTK_GRID(tableLinearToolShade), label15, 3, 1, 1, 1); label15 = gtk_label_new ("+"); gtk_grid_attach(GTK_GRID(tableLinearToolShade), label15, 3, 2, 1, 1); label16 = gtk_label_new ("\303\227"); gtk_grid_attach(GTK_GRID(tableLinearToolShade), label16, 5, 0, 1, 1); label20 = gtk_label_new ("\303\227"); gtk_grid_attach(GTK_GRID(tableLinearToolShade), label20, 5, 1, 1, 1); label21 = gtk_label_new ("\303\227"); gtk_grid_attach(GTK_GRID(tableLinearToolShade), label21, 5, 2, 1, 1); spinbuttonDataChA[0] = gtk_spin_button_new_with_range(-99, 99, 0.01); gtk_spin_button_set_value(GTK_SPIN_BUTTON(spinbuttonDataChA[0]), 1.); gtk_grid_attach(GTK_GRID(tableLinearToolShade), spinbuttonDataChA[0], 4, 0, 1, 1); gtk_spin_button_set_numeric (GTK_SPIN_BUTTON (spinbuttonDataChA[0]), TRUE); spinbuttonDataChA[1] = gtk_spin_button_new_with_range(-99, 99, 0.01); gtk_spin_button_set_value(GTK_SPIN_BUTTON(spinbuttonDataChA[1]), 1.); gtk_grid_attach(GTK_GRID(tableLinearToolShade), spinbuttonDataChA[1], 4, 1, 1, 1); gtk_spin_button_set_numeric (GTK_SPIN_BUTTON (spinbuttonDataChA[1]), TRUE); spinbuttonDataChA[2] = gtk_spin_button_new_with_range(-99, 99, 0.01); gtk_spin_button_set_value(GTK_SPIN_BUTTON(spinbuttonDataChA[2]), 1.); gtk_grid_attach(GTK_GRID(tableLinearToolShade), spinbuttonDataChA[2], 4, 2, 1, 1); gtk_spin_button_set_numeric (GTK_SPIN_BUTTON (spinbuttonDataChA[2]), TRUE); spinbuttonDataChB[0] = gtk_spin_button_new_with_range(-99, 99, 0.01); gtk_spin_button_set_value(GTK_SPIN_BUTTON(spinbuttonDataChB[0]), 0.); gtk_grid_attach(GTK_GRID(tableLinearToolShade), spinbuttonDataChB[0], 2, 0, 1, 1); gtk_spin_button_set_numeric (GTK_SPIN_BUTTON (spinbuttonDataChB[0]), TRUE); spinbuttonDataChB[1] = gtk_spin_button_new_with_range(-99, 99, 0.01); gtk_spin_button_set_value(GTK_SPIN_BUTTON(spinbuttonDataChB[1]), 0.); gtk_grid_attach(GTK_GRID(tableLinearToolShade), spinbuttonDataChB[1], 2, 1, 1, 1); gtk_spin_button_set_numeric (GTK_SPIN_BUTTON (spinbuttonDataChB[1]), TRUE); spinbuttonDataChB[2] = gtk_spin_button_new_with_range(-99, 99, 0.01); gtk_spin_button_set_value(GTK_SPIN_BUTTON(spinbuttonDataChB[2]), 0.); gtk_grid_attach(GTK_GRID(tableLinearToolShade), spinbuttonDataChB[2], 2, 2, 1, 1); gtk_spin_button_set_numeric (GTK_SPIN_BUTTON (spinbuttonDataChB[2]), TRUE); for (i = 0; i < 3; i++) { renderer = gtk_cell_renderer_text_new(); comboboxDataCh[i] = gtk_combo_box_new_with_model(GTK_TREE_MODEL(colsModel)); gtk_cell_layout_pack_start(GTK_CELL_LAYOUT(comboboxDataCh[i]), renderer, TRUE); gtk_cell_layout_add_attribute(GTK_CELL_LAYOUT(comboboxDataCh[i]), renderer, "text", 1); gtk_grid_attach(GTK_GRID(tableLinearToolShade), comboboxDataCh[i], 6, i, 1, 1); } hbox8 = gtk_hbox_new (FALSE, 0); gtk_box_pack_start(GTK_BOX(vboxTransformation), hbox8, FALSE, FALSE, 0); label = gtk_label_new(_("Color range preview: ")); gtk_box_pack_start (GTK_BOX (hbox8), label, FALSE, FALSE, 0); pixbufColorPreview = gdk_pixbuf_new(GDK_COLORSPACE_RGB, FALSE, COLOR_PREVIEW_BITS, COLOR_PREVIEW_WIDTH, COLOR_PREVIEW_HEIGHT); colorPreview = create_pixmap ((GtkWidget*)0, NULL); gtk_widget_set_size_request (colorPreview, COLOR_PREVIEW_WIDTH, COLOR_PREVIEW_HEIGHT); gtk_box_pack_start (GTK_BOX (hbox8), colorPreview, TRUE, TRUE, 0); labelPreview = gtk_label_new(_("No preview available")); gtk_label_set_use_markup(GTK_LABEL(labelPreview), TRUE); gtk_box_pack_start (GTK_BOX (hbox8), labelPreview, TRUE, TRUE, 0); /* Bar */ hrule = gtk_hseparator_new(); gtk_box_pack_start(GTK_BOX(vbox), hrule, FALSE, FALSE, 8); checkLegend = gtk_check_button_new_with_mnemonic(_("Display the colour range.")); gtk_box_pack_start(GTK_BOX(vboxTransformation), checkLegend, FALSE, FALSE, 0); g_object_bind_property(visu_gl_node_scene_getColorizationLegend(scene), "active", checkLegend, "active", G_BINDING_BIDIRECTIONAL | G_BINDING_SYNC_CREATE); /* g_object_bind_property_full(visu_gl_node_scene_getColorization(scene), */ /* "single-param", checkLegend, "sensitive", */ /* G_BINDING_SYNC_CREATE, fromSingle, NULL, NULL, NULL); */ /***********************/ /* Post treatment part */ /***********************/ expanderPostProcessing = gtk_expander_new(_("Post processing:")); gtk_widget_set_sensitive(expanderPostProcessing, FALSE); gtk_widget_set_name(gtk_expander_get_label_widget(GTK_EXPANDER(expanderPostProcessing)), "label_head"); gtk_expander_set_expanded(GTK_EXPANDER(expanderPostProcessing), TRUE); gtk_box_pack_start(GTK_BOX(vbox), expanderPostProcessing, FALSE, FALSE, 0); vboxPostProcessing = gtk_vbox_new(FALSE, 0); gtk_container_add(GTK_CONTAINER(expanderPostProcessing), vboxPostProcessing); hbox3 = gtk_hbox_new(FALSE, 0); gtk_box_pack_start(GTK_BOX(vboxPostProcessing), hbox3, FALSE, FALSE, 0); checkHideMinValues = gtk_check_button_new_with_mnemonic(_("_Hide elements")); gtk_box_pack_start(GTK_BOX(hbox3), checkHideMinValues, FALSE, FALSE, 0); gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON(checkHideMinValues), FALSE); label = gtk_label_new(_(" whose value from")); gtk_box_pack_start(GTK_BOX(hbox3), label, FALSE, FALSE, 0); hbox3 = gtk_hbox_new(FALSE, 0); gtk_box_pack_start(GTK_BOX(vboxPostProcessing), hbox3, FALSE, FALSE, 0); label = gtk_label_new(_("col. ")); gtk_label_set_xalign(GTK_LABEL(label), 1.); gtk_box_pack_start(GTK_BOX(hbox3), label, TRUE, TRUE, 0); /* The 2 here is to avoid a GTK bug in 2.4. */ spinHideMinValues = gtk_spin_button_new_with_range(1, 2, 1); gtk_box_pack_start(GTK_BOX(hbox3), spinHideMinValues, FALSE, FALSE, 0); label = gtk_label_new(_(" is lower than ")); gtk_box_pack_start(GTK_BOX(hbox3), label, FALSE, FALSE, 0); entryHideMinValues = visu_ui_numerical_entry_new(1.); gtk_entry_set_width_chars(GTK_ENTRY(entryHideMinValues), 10); gtk_box_pack_start(GTK_BOX(hbox3), entryHideMinValues, FALSE, FALSE, 0); hbox3 = gtk_hbox_new(FALSE, 0); gtk_box_pack_start(GTK_BOX(vboxPostProcessing), hbox3, FALSE, FALSE, 0); checkScaleRadius = gtk_check_button_new_with_mnemonic(_("_Scale shape according to ")); gtk_box_pack_start(GTK_BOX(hbox3), checkScaleRadius, FALSE, FALSE, 0); renderer = gtk_cell_renderer_text_new(); comboboxScaling = gtk_combo_box_new_with_model(GTK_TREE_MODEL(colsModel)); gtk_cell_layout_pack_start(GTK_CELL_LAYOUT(comboboxScaling), renderer, TRUE); gtk_cell_layout_add_attribute(GTK_CELL_LAYOUT(comboboxScaling), renderer, "text", 1); gtk_box_pack_start(GTK_BOX(hbox3), comboboxScaling, TRUE, TRUE, 0); hbox3 = gtk_hbox_new(FALSE, 0); gtk_box_pack_start(GTK_BOX(vboxPostProcessing), hbox3, FALSE, FALSE, 0); checkRestrict = gtk_check_button_new_with_mnemonic(_("_Restrict colourisation" " to values in range.")); gtk_box_pack_start(GTK_BOX(hbox3), checkRestrict, FALSE, FALSE, 0); /**************/ /* Status bar */ /**************/ statusbarDataFile = gtk_statusbar_new(); gtk_box_pack_end(GTK_BOX(containerDataFilePanel), statusbarDataFile, FALSE, FALSE, 0); #if GTK_MAJOR_VERSION < 3 && GTK_MINOR_VERSION < 24 gtk_statusbar_set_has_resize_grip (GTK_STATUSBAR (statusbarDataFile), FALSE); #endif statusDataFileContextId = gtk_statusbar_get_context_id(GTK_STATUSBAR(statusbarDataFile), _("Description of loaded data file.")); gtk_statusbar_push(GTK_STATUSBAR(statusbarDataFile), statusDataFileContextId, DATA_FILE_NO_FILE_MESSAGE); gtk_widget_show_all(containerDataFilePanel); gtk_widget_hide(colorPreview); /* All objects have been created. */ panelDataFileIsInitiated = TRUE; /********************/ /* Create callbacks */ /********************/ g_signal_connect(G_OBJECT(comboboxRange), "changed", G_CALLBACK(onComboManualChange), (gpointer)0); g_signal_connect(G_OBJECT(checkHideMinValues), "toggled", G_CALLBACK(onCheckHideMinValuesChange), (gpointer)0); g_signal_connect(G_OBJECT(entryHideMinValues), "value-changed", G_CALLBACK(onEntryHideMinValuesChange), (gpointer)0); g_signal_connect(G_OBJECT(spinHideMinValues), "value-changed", G_CALLBACK(onSpinHideMinValuesChange), (gpointer)0); DBG_fprintf(stderr, " | Creation OK.\n"); gtk_container_add(GTK_CONTAINER(panelDataFile), containerDataFilePanel); } static void _createDialogFilters(GtkFileChooser *chooser, const gchar *ext) { GString *label; GSList *lst, *tmp; GtkFileFilter *filter; lst = gtk_file_chooser_list_filters(chooser); DBG_fprintf(stderr, "Panel Colorization: creating file filter '%s'.\n", ext); if (ext && ext[0]) { filter = gtk_file_filter_new(); label = g_string_new(_("Data files")); g_string_append_printf(label, " (*%s)", ext); gtk_file_filter_set_name(filter, label->str); g_string_printf(label, "*%s", ext); gtk_file_filter_add_pattern(filter, label->str); g_string_free(label, TRUE); gtk_file_chooser_add_filter(chooser, filter); gtk_file_chooser_set_filter(chooser, filter); } filter = gtk_file_filter_new(); gtk_file_filter_set_name(filter, _("All files")); gtk_file_filter_add_pattern(filter, "*"); gtk_file_chooser_add_filter(chooser, filter); for (tmp = lst; tmp; tmp = g_slist_next(tmp)) gtk_file_chooser_remove_filter(chooser, GTK_FILE_FILTER(tmp->data)); g_slist_free(lst); } static void onLoadDataFile(GtkFileChooserButton *button, gpointer data _U_) { gchar *filename, *directory; VisuData *dataFile; VisuNodeValuesFarray *values; GError *error; g_return_if_fail(attachedDt); directory = (char*)gtk_file_chooser_get_current_folder(GTK_FILE_CHOOSER(button)); if (directory) visu_ui_main_setLastOpenDirectory(visu_ui_main_class_getCurrentPanel(), directory, VISU_UI_DIR_DATAFILE); g_free(directory); filename = gtk_file_chooser_get_filename(GTK_FILE_CHOOSER(button)); dataFile = visu_ui_panel_getData(VISU_UI_PANEL(panelDataFile)); error = (GError*)0; values = visu_node_values_farray_new_fromFile (VISU_NODE_ARRAY(dataFile), VISU_COLORIZATION_LABEL, filename, &error); if (!error) { visu_colorization_setNodeModel(attachedDt, values); visu_data_removeNodeProperties (dataFile, visu_node_values_getLabel(VISU_NODE_VALUES(values))); visu_data_addNodeProperties(dataFile, VISU_NODE_VALUES(values)); } else { gchar *errMess; errMess = g_strdup_printf(_("Reading data file '%s' reports:\n\t%s"), filename, error->message); visu_ui_raiseWarning(_("Loading a data file"), errMess, (GtkWindow*)0); g_free(errMess); g_error_free(error); if (values) g_object_unref(values); } g_free(filename); } static void updateStatusBar(const VisuColorization *dt) { gchar *fileUTF8, *basename; gchar *message; const gchar *currentDataFile; gint nbColumns; nbColumns = visu_colorization_getNColumns(dt); currentDataFile = visu_colorization_getFile(dt); /* Create the text of the status bar or empty it. */ gtk_statusbar_pop(GTK_STATUSBAR(statusbarDataFile), statusDataFileContextId); /* Create the text of the status bar or empty it. */ if (currentDataFile) { basename = g_path_get_basename(currentDataFile); fileUTF8 = g_filename_to_utf8(basename, -1, NULL, NULL, NULL); g_free(basename); g_return_if_fail(fileUTF8); if (nbColumns > 0) message = g_strdup_printf(_("%s: %d column(s)"), fileUTF8, nbColumns); else message = g_strdup_printf(_("%s: file error"), fileUTF8); g_free(fileUTF8); gtk_statusbar_push(GTK_STATUSBAR(statusbarDataFile), statusDataFileContextId, message); g_free(message); } else if (nbColumns > 0) { message = g_strdup_printf(_("%d column(s)"), nbColumns); gtk_statusbar_push(GTK_STATUSBAR(statusbarDataFile), statusDataFileContextId, message); g_free(message); } else gtk_statusbar_push(GTK_STATUSBAR(statusbarDataFile), statusDataFileContextId, DATA_FILE_NO_FILE_MESSAGE); } static gboolean getManual(GBinding *bind _U_, const GValue *from, GValue *to, gpointer data) { gint col; float *minmax; col = gtk_combo_box_get_active(GTK_COMBO_BOX(comboboxRange)); g_return_val_if_fail(col >= 0, FALSE); minmax = &g_array_index((GArray*)g_value_get_boxed(from), float, 2 * col); g_value_set_double(to, (double)minmax[GPOINTER_TO_INT(data)]); return TRUE; } static gboolean setManual(GBinding *bind, const GValue *from, GValue *to, gpointer data) { gint col; float *minmax; GArray *arr; col = gtk_combo_box_get_active(GTK_COMBO_BOX(comboboxRange)); g_return_val_if_fail(col >= 0, FALSE); g_object_get(g_binding_get_source(bind), "range-min-max", &arr, NULL); minmax = &g_array_index(arr, float, 2 * col); minmax[GPOINTER_TO_INT(data)] = (float)g_value_get_double(from); g_value_set_boxed(to, arr); return TRUE; } static gboolean getExt(GBinding *bind _U_, const GValue *from, GValue *to, gpointer data _U_) { g_value_set_string(to, g_value_get_string(from)); _createDialogFilters(GTK_FILE_CHOOSER(openDataFileButton), g_value_get_string(from)); return TRUE; } static gboolean setExt(GBinding *bind _U_, const GValue *from, GValue *to, gpointer data _U_) { g_value_set_string(to, g_value_get_string(from)); return TRUE; } /* static gboolean getPresetNot(GBinding *bind, const GValue *from, GValue *to, gpointer data _U_) */ /* { */ /* if (g_value_get_int(from) == VISU_COLORIZATION_UNSET) */ /* g_value_set_boxed(to, (gpointer)0); */ /* else */ /* g_value_set_boxed(to, visu_colorization_getShade(VISU_COLORIZATION(g_binding_get_source(bind)))); */ /* return TRUE; */ /* } */ static gboolean getScaling(GBinding *bind _U_, const GValue *from, GValue *to, gpointer data) { gboolean active; active = ((int)g_value_get_uint(from) == GPOINTER_TO_INT(data)); g_value_set_boolean(to, active); return active; } static gboolean setScaling(GBinding *bind _U_, const GValue *from, GValue *to, gpointer data) { if (g_value_get_boolean(from)) g_value_set_uint(to, GPOINTER_TO_INT(data)); return g_value_get_boolean(from); } static gboolean getColor(GBinding *bind _U_, const GValue *from, GValue *to, gpointer data) { gboolean active; active = ((int)tool_shade_getColorMode((ToolShade*)g_value_get_boxed(from)) == GPOINTER_TO_INT(data)); g_value_set_boolean(to, active); return active; } static gboolean setColor(GBinding *bind, const GValue *from, GValue *to, gpointer data) { ToolShade *shade; shade = tool_shade_copy(visu_data_colorizer_shaded_getShade(VISU_DATA_COLORIZER_SHADED(g_binding_get_source(bind)))); if (g_value_get_boolean(from)) tool_shade_setColorMode(shade, GPOINTER_TO_INT(data)); g_value_set_boxed(to, shade); return g_value_get_boolean(from); } static gboolean getPixbuf(GBinding *bind _U_, const GValue *from, GValue *to, gpointer data _U_) { int i; int rowstride, x, y; guchar *pixels, *p; float rgbValues[COLOR_PREVIEW_WIDTH][4]; ToolShade *shade; rowstride = gdk_pixbuf_get_rowstride(pixbufColorPreview); pixels = gdk_pixbuf_get_pixels(pixbufColorPreview); shade = (ToolShade*)g_value_get_boxed(from); for (i = 0; i < COLOR_PREVIEW_WIDTH; i++) tool_shade_valueToRGB(shade, rgbValues[i], (float)i / (float)(COLOR_PREVIEW_WIDTH - 1)); for (y = 0; y < COLOR_PREVIEW_HEIGHT; y++) for (x = 0; x < COLOR_PREVIEW_WIDTH; x++) { p = pixels + y * rowstride + x * 3; p[0] = (guchar)(rgbValues[x][0] * 255); p[1] = (guchar)(rgbValues[x][1] * 255); p[2] = (guchar)(rgbValues[x][2] * 255); } g_value_set_object(to, pixbufColorPreview); return TRUE; } static gboolean getSingle(GBinding *bind _U_, const GValue *from, GValue *to, gpointer data _U_) { g_value_set_boolean(to, g_value_get_int(from) != VISU_COLORIZATION_UNSET); return TRUE; } static gboolean getCol(GBinding *bind _U_, const GValue *from, GValue *to, gpointer data _U_) { g_value_set_int(to, g_value_get_int(from) + N_COORDS_COLS); return TRUE; } static gboolean setCol(GBinding *bind _U_, const GValue *from, GValue *to, gpointer data _U_) { g_value_set_int(to, g_value_get_int(from) - N_COORDS_COLS); return TRUE; } static gboolean getTransform(GBinding *bind _U_, const GValue *from, GValue *to, gpointer data _U_) { g_value_set_boolean(to, (tool_shade_getMode((ToolShade*)g_value_get_boxed(from)) == TOOL_SHADE_MODE_LINEAR)); return TRUE; } static gboolean getSpinA(GBinding *bind _U_, const GValue *from, GValue *to, gpointer data) { const float *vectA, *vectB; if (tool_shade_getMode((ToolShade*)g_value_get_boxed(from)) != TOOL_SHADE_MODE_LINEAR) return FALSE; tool_shade_getLinearCoeff((ToolShade*)g_value_get_boxed(from), &vectA, &vectB); g_return_val_if_fail(vectA, FALSE); g_value_set_double(to, vectA[GPOINTER_TO_INT(data)]); return TRUE; } static gboolean setSpinA(GBinding *bind, const GValue *from, GValue *to, gpointer data) { ToolShade *shade; gboolean res; shade = tool_shade_copy(visu_data_colorizer_shaded_getShade(VISU_DATA_COLORIZER_SHADED(g_binding_get_source(bind)))); res = tool_shade_setLinearCoeff(shade, g_value_get_double(from), GPOINTER_TO_INT(data), 1); g_value_set_boxed(to, shade); return res; } static gboolean getSpinB(GBinding *bind _U_, const GValue *from, GValue *to, gpointer data) { const float *vectA, *vectB; if (tool_shade_getMode((ToolShade*)g_value_get_boxed(from)) != TOOL_SHADE_MODE_LINEAR) return FALSE; tool_shade_getLinearCoeff((ToolShade*)g_value_get_boxed(from), &vectA, &vectB); g_return_val_if_fail(vectB, FALSE); g_value_set_double(to, vectB[GPOINTER_TO_INT(data)]); return TRUE; } static gboolean setSpinB(GBinding *bind, const GValue *from, GValue *to, gpointer data) { ToolShade *shade; gboolean res; shade = tool_shade_copy(visu_data_colorizer_shaded_getShade(VISU_DATA_COLORIZER_SHADED(g_binding_get_source(bind)))); res = tool_shade_setLinearCoeff(shade, g_value_get_double(from), GPOINTER_TO_INT(data), 0); g_value_set_boxed(to, shade); return res; } static gboolean getScalCol(GBinding *bind _U_, const GValue *from, GValue *to, gpointer data _U_) { int id; id = g_value_get_int(from); if (id == VISU_COLORIZATION_UNSET) return FALSE; g_value_set_int(to, id + N_COORDS_COLS); return TRUE; } static gboolean setScalCol(GBinding *bind _U_, const GValue *from, GValue *to, gpointer data _U_) { if (!gtk_toggle_button_get_active(GTK_TOGGLE_BUTTON(checkScaleRadius))) return FALSE; g_value_set_int(to, g_value_get_int(from) - N_COORDS_COLS); return TRUE; } static gboolean getScalRad(GBinding *bind _U_, const GValue *from, GValue *to, gpointer data _U_) { g_value_set_boolean(to, g_value_get_int(from) != VISU_COLORIZATION_UNSET); return TRUE; } static gboolean setScalRad(GBinding *bind _U_, const GValue *from, GValue *to, gpointer data _U_) { if (g_value_get_boolean(from)) g_value_set_int(to, gtk_combo_box_get_active(GTK_COMBO_BOX(comboboxScaling)) - N_COORDS_COLS); else g_value_set_int(to, VISU_COLORIZATION_UNSET); return TRUE; } static gboolean getPolicy(GBinding *bind _U_, const GValue *from, GValue *to, gpointer data _U_) { g_value_set_boolean(to, g_value_get_uint(from) == COLORIZATION_POLICY_FROM_FILE); return TRUE; } static gboolean setPolicy(GBinding *bind _U_, const GValue *from, GValue *to, gpointer data _U_) { g_value_set_uint(to, g_value_get_boolean(from) ? COLORIZATION_POLICY_FROM_FILE : COLORIZATION_POLICY_FROM_PREVIOUS); return TRUE; } static gboolean _setAttachedData(VisuColorization *dt) { if (attachedDt == dt) return FALSE; if (attachedDt) { g_signal_handler_disconnect(G_OBJECT(attachedDt), ncols_signal); g_signal_handler_disconnect(G_OBJECT(attachedDt), data_signal); g_signal_handler_disconnect(G_OBJECT(attachedDt), file_signal); g_object_unref(attachedDt); } if (dt) { g_object_ref(dt); ncols_signal = g_signal_connect(G_OBJECT(dt), "notify::n-columns", G_CALLBACK(onColumns), (gpointer)0); file_signal = g_signal_connect(G_OBJECT(dt), "notify::source-file", G_CALLBACK(onFile), (gpointer)0); data_signal = g_signal_connect(G_OBJECT(dt), "notify::data-min-max", G_CALLBACK(onDataMM), (gpointer)0); } attachedDt = dt; return TRUE; } static void _set(VisuColorization *dt) { VisuGlNodeScene *scene; VisuColorization *old; old = attachedDt; if (old) g_object_ref(old); if (!_setAttachedData(dt)) { if (old) g_object_unref(old); return; } if (old) { g_object_unref(bind_auto); g_object_unref(bind_ext); g_object_unref(bind_box); g_object_unref(bind_used); g_object_unref(bind_restrict); g_object_unref(bind_manualMin); g_object_unref(bind_manualMax); g_object_unref(bind_scaleAuto); g_object_unref(bind_scaleManual); g_object_unref(bind_preset); /* g_object_unref(bind_presetNot); */ g_object_unref(bind_RGB); g_object_unref(bind_HSV); g_object_unref(bind_preview); g_object_unref(bind_warn); g_object_unref(bind_pixbuf); g_object_unref(bind_legend); g_object_unref(bind_presetCol); g_object_unref(bind_cols[0]); g_object_unref(bind_cols[1]); g_object_unref(bind_cols[2]); g_object_unref(bind_linear); g_object_unref(bind_spinA[0]); g_object_unref(bind_spinA[1]); g_object_unref(bind_spinA[2]); g_object_unref(bind_spinB[0]); g_object_unref(bind_spinB[1]); g_object_unref(bind_spinB[2]); g_object_unref(bind_scaling); g_object_unref(bind_radius); g_object_unref(old); } if (dt) { scene = visu_ui_rendering_window_getGlScene(visu_ui_main_class_getDefaultRendering()); if (!panelDataFileIsInitiated) createInteriorDataFile(scene); bind_auto = g_object_bind_property_full (scene, "colorization-policy", checkbuttonAutoLoad, "active", G_BINDING_SYNC_CREATE | G_BINDING_BIDIRECTIONAL, getPolicy, setPolicy, (gpointer)0, (GDestroyNotify)0); bind_ext = g_object_bind_property_full (scene, "colorization-file-extension", entryFileExtension, "text", G_BINDING_SYNC_CREATE | G_BINDING_BIDIRECTIONAL, getExt, setExt, (gpointer)0, (GDestroyNotify)0); bind_box = g_object_bind_property(scene, "box", dt, "box", G_BINDING_SYNC_CREATE); onColumns(dt, (GParamSpec*)0, (gpointer)0); onFile(dt, (GParamSpec*)0, (gpointer)0); onDataMM(dt, (GParamSpec*)0, (gpointer)0); bind_used = g_object_bind_property(dt, "active", checkbuttonData, "active", G_BINDING_BIDIRECTIONAL | G_BINDING_SYNC_CREATE); bind_restrict = g_object_bind_property(dt, "apply-all", checkRestrict, "active", G_BINDING_BIDIRECTIONAL | G_BINDING_SYNC_CREATE | G_BINDING_INVERT_BOOLEAN); bind_manualMin = g_object_bind_property_full (dt, "range-min-max", entryDataMin, "value", G_BINDING_BIDIRECTIONAL | G_BINDING_SYNC_CREATE, getManual, setManual, GINT_TO_POINTER(0), (GDestroyNotify)0); bind_manualMax = g_object_bind_property_full (dt, "range-min-max", entryDataMax, "value", G_BINDING_BIDIRECTIONAL | G_BINDING_SYNC_CREATE, getManual, setManual, GINT_TO_POINTER(1), (GDestroyNotify)0); bind_scaleAuto = g_object_bind_property_full (dt, "normalisation", radioNormalized, "active", G_BINDING_BIDIRECTIONAL | G_BINDING_SYNC_CREATE, getScaling, setScaling, GINT_TO_POINTER(VISU_COLORIZATION_NORMALIZE), (GDestroyNotify)0); bind_scaleManual = g_object_bind_property_full (dt, "normalisation", radioMinMax, "active", G_BINDING_BIDIRECTIONAL | G_BINDING_SYNC_CREATE, getScaling, setScaling, GINT_TO_POINTER(VISU_COLORIZATION_MINMAX), (GDestroyNotify)0); bind_preset = g_object_bind_property(dt, "shade", comboPreSetColorRange, "shade", G_BINDING_BIDIRECTIONAL | G_BINDING_SYNC_CREATE); /* bind_presetNot = g_object_bind_property_full */ /* (dt, "single-param", comboPreSetColorRange, "shade", G_BINDING_SYNC_CREATE, */ /* getPresetNot, (GBindingTransformFunc)0, (gpointer)0, (GDestroyNotify)0); */ bind_RGB = g_object_bind_property_full (dt, "shade", radiobuttonDataRGB, "active", G_BINDING_BIDIRECTIONAL | G_BINDING_SYNC_CREATE, getColor, setColor, GINT_TO_POINTER(TOOL_SHADE_COLOR_MODE_RGB), (GDestroyNotify)0); bind_HSV = g_object_bind_property_full (dt, "shade", radiobuttonDataHSV, "active", G_BINDING_BIDIRECTIONAL | G_BINDING_SYNC_CREATE, getColor, setColor, GINT_TO_POINTER(TOOL_SHADE_COLOR_MODE_HSV), (GDestroyNotify)0); bind_preview = g_object_bind_property_full (dt, "single-param", colorPreview, "visible", G_BINDING_SYNC_CREATE, getSingle, (GBindingTransformFunc)0, (gpointer)0, (GDestroyNotify)0); bind_warn = g_object_bind_property (colorPreview, "visible", labelPreview, "visible", G_BINDING_SYNC_CREATE | G_BINDING_INVERT_BOOLEAN); bind_pixbuf = g_object_bind_property_full (dt, "shade", colorPreview, "pixbuf", G_BINDING_SYNC_CREATE, getPixbuf, (GBindingTransformFunc)0, (gpointer)0, (GDestroyNotify)0); bind_legend = g_object_bind_property (colorPreview, "visible", checkLegend, "sensitive", G_BINDING_SYNC_CREATE); bind_presetCol = g_object_bind_property_full (dt, "single-param", comboboxPresetCol, "active", G_BINDING_BIDIRECTIONAL | G_BINDING_SYNC_CREATE, getCol, setCol, (gpointer)0, (GDestroyNotify)0); bind_cols[0] = g_object_bind_property_full (dt, "column-red", comboboxDataCh[0], "active", G_BINDING_BIDIRECTIONAL | G_BINDING_SYNC_CREATE, getCol, setCol, (gpointer)0, (GDestroyNotify)0); bind_cols[1] = g_object_bind_property_full (dt, "column-green", comboboxDataCh[1], "active", G_BINDING_BIDIRECTIONAL | G_BINDING_SYNC_CREATE, getCol, setCol, (gpointer)0, (GDestroyNotify)0); bind_cols[2] = g_object_bind_property_full (dt, "column-blue", comboboxDataCh[2], "active", G_BINDING_BIDIRECTIONAL | G_BINDING_SYNC_CREATE, getCol, setCol, (gpointer)0, (GDestroyNotify)0); bind_linear = g_object_bind_property_full (dt, "shade", tableLinearToolShade, "sensitive", G_BINDING_SYNC_CREATE, getTransform, (GBindingTransformFunc)0, (gpointer)0, (GDestroyNotify)0); bind_spinA[0] = g_object_bind_property_full (dt, "shade", spinbuttonDataChA[0], "value", G_BINDING_SYNC_CREATE | G_BINDING_BIDIRECTIONAL, getSpinA, setSpinA, GINT_TO_POINTER(0), (GDestroyNotify)0); bind_spinA[1] = g_object_bind_property_full (dt, "shade", spinbuttonDataChA[1], "value", G_BINDING_SYNC_CREATE | G_BINDING_BIDIRECTIONAL, getSpinA, setSpinA, GINT_TO_POINTER(1), (GDestroyNotify)0); bind_spinA[2] = g_object_bind_property_full (dt, "shade", spinbuttonDataChA[2], "value", G_BINDING_SYNC_CREATE | G_BINDING_BIDIRECTIONAL, getSpinA, setSpinA, GINT_TO_POINTER(2), (GDestroyNotify)0); bind_spinB[0] = g_object_bind_property_full (dt, "shade", spinbuttonDataChB[0], "value", G_BINDING_SYNC_CREATE | G_BINDING_BIDIRECTIONAL, getSpinB, setSpinB, GINT_TO_POINTER(0), (GDestroyNotify)0); bind_spinB[1] = g_object_bind_property_full (dt, "shade", spinbuttonDataChB[1], "value", G_BINDING_SYNC_CREATE | G_BINDING_BIDIRECTIONAL, getSpinB, setSpinB, GINT_TO_POINTER(1), (GDestroyNotify)0); bind_spinB[2] = g_object_bind_property_full (dt, "shade", spinbuttonDataChB[2], "value", G_BINDING_SYNC_CREATE | G_BINDING_BIDIRECTIONAL, getSpinB, setSpinB, GINT_TO_POINTER(2), (GDestroyNotify)0); bind_scaling = g_object_bind_property_full (dt, "column-size", comboboxScaling, "active", G_BINDING_BIDIRECTIONAL | G_BINDING_SYNC_CREATE, getScalCol, setScalCol, (gpointer)0, (GDestroyNotify)0); bind_radius = g_object_bind_property_full (dt, "column-size", checkScaleRadius, "active", G_BINDING_BIDIRECTIONAL | G_BINDING_SYNC_CREATE, getScalRad, setScalRad, (gpointer)0, (GDestroyNotify)0); visu_gl_node_scene_setColorization(scene, dt); } } /** * visu_ui_panel_colorization_get: * * Retrieve the #VisuColorization object that the panel display the * status of. * * Since: 3.8 * * Returns: (transfer none): a private object attached to the panel. **/ VisuColorization* visu_ui_panel_colorization_get() { if (!panelDataFileIsInitiated) createInteriorDataFile(visu_ui_rendering_window_getGlScene(visu_ui_main_class_getDefaultRendering())); return attachedDt; } /*************/ /* Callbacks */ /*************/ static void onFile(VisuColorization *dt, GParamSpec *pspec _U_, gpointer data _U_) { const gchar *file; /* Update the widgets of this panel if necessary. */ file = visu_colorization_getFile(dt); if (file) gtk_file_chooser_set_filename(GTK_FILE_CHOOSER(openDataFileButton), file); /* Update status bar. */ updateStatusBar(dt); } static void onColumns(VisuColorization *dt, GParamSpec *pspec _U_, gpointer data _U_) { guint nbColumns, i; GString *labelStr; GtkTreeIter iter; gboolean valid; GtkAdjustment *adj; nbColumns = visu_colorization_getNColumns(dt); /* Rebuild the column comboboxes. */ for (i = 0, valid = gtk_tree_model_get_iter_first(GTK_TREE_MODEL(colsModel), &iter); valid; valid = gtk_tree_model_iter_next(GTK_TREE_MODEL(colsModel), &iter), i++) if (i > N_COORDS_COLS + nbColumns - 1) gtk_list_store_remove(colsModel, &iter); labelStr = g_string_new(""); for (i -= N_COORDS_COLS; i < nbColumns; i++) { g_string_printf(labelStr, _("Col. %d"), i + 1); gtk_list_store_append(colsModel, &iter); gtk_list_store_set(colsModel, &iter, 0, i, 1, labelStr->str, -1); } g_string_free(labelStr, TRUE); /* Update post-processing widgets. */ gtk_widget_set_sensitive(expanderPostProcessing, (nbColumns > 0)); adj = gtk_spin_button_get_adjustment(GTK_SPIN_BUTTON(spinHideMinValues)); gtk_adjustment_set_upper(adj, nbColumns); /* Update status bar. */ updateStatusBar(dt); } static void _destroyWidget(GtkWidget *widget, gpointer data _U_) { gtk_widget_destroy(widget); } static void onDataMM(VisuColorization *dt, GParamSpec *pspec _U_, gpointer data _U_) { guint nbColumns, i; GtkWidget *table, *label; float minMax[2]; GString *labelStr; VisuNodeValuesFarray *values; /* empty the child of the alignment */ gtk_container_foreach(GTK_CONTAINER(readMinMaxValues), (GtkCallback)_destroyWidget, (gpointer)0); nbColumns = visu_colorization_getNColumns(dt); if (nbColumns > 0) { table = gtk_grid_new(); tool_grid_resize(table, nbColumns + 1, 3); /* label = gtk_label_new(_("Column number")); */ /* gtk_widget_set_name(label, "label_head"); */ /* gtk_table_attach(GTK_TABLE(table), label, 0, 1, 0, 1, GTK_SHRINK, GTK_SHRINK, 2, 0); */ label = gtk_label_new(_("Min value")); gtk_widget_set_name(label, "label_head"); gtk_widget_set_hexpand(label, TRUE); gtk_grid_attach(GTK_GRID(table), label, 1, 0, 1, 1); label = gtk_label_new(_("Max value")); gtk_widget_set_name(label, "label_head"); gtk_widget_set_hexpand(label, TRUE); gtk_grid_attach(GTK_GRID(table), label, 2, 0, 1, 1); g_object_get(dt, "model", &values, NULL); labelStr = g_string_new(""); for (i = 0; i < nbColumns; i++) { g_string_printf(labelStr, _("Column %d"), i + 1); label = gtk_label_new(labelStr->str); gtk_grid_attach(GTK_GRID(table), label, 0, i + 1, 1, 1); if (visu_node_values_farray_getColumnMinMax(values, minMax, i)) { g_string_printf(labelStr, "%g", minMax[0]); label = gtk_label_new(labelStr->str); gtk_label_set_selectable(GTK_LABEL(label), TRUE); gtk_grid_attach(GTK_GRID(table), label, 1, i + 1, 1, 1); g_string_printf(labelStr, "%g", minMax[1]); label = gtk_label_new(labelStr->str); gtk_label_set_selectable(GTK_LABEL(label), TRUE); gtk_grid_attach(GTK_GRID(table), label, 2, i + 1, 1, 1); } else g_warning("Can't retrieve min/max values for column %d.\n", i); } g_object_unref(values); gtk_widget_show_all(table); g_string_free(labelStr, TRUE); gtk_container_add(GTK_CONTAINER(readMinMaxValues), table); } else { label = gtk_label_new(MIN_MAX_NO_DATA_FILE); gtk_label_set_use_markup(GTK_LABEL(label), TRUE); gtk_widget_show(label); gtk_container_add(GTK_CONTAINER(readMinMaxValues), label); } } #if GTK_MAJOR_VERSION < 3 && GTK_MINOR_VERSION < 5 static void loadDataFile(GtkButton *button _U_, gpointer data _U_) { GtkWidget *file_selector; VisuData *dataObj; dataObj = visu_ui_panel_getData(VISU_UI_PANEL(panelDataFile)); if (!dataObj) { g_warning("Can't click here since no visuData is available.\n"); return; } file_selector = _createLoadDataDialog(); gtk_dialog_run (GTK_DIALOG (file_selector)); gtk_widget_destroy(file_selector); } #endif static void onDataFileEnter(VisuUiPanel *visu_ui_panel _U_, gpointer data) { VisuGlNodeScene *scene = VISU_GL_NODE_SCENE(data); DBG_fprintf(stderr, "Panel dataFile: check values on enter.\n"); if (!panelDataFileIsInitiated) createInteriorDataFile(scene); if (!attachedDt) { VisuColorization *dt = visu_gl_node_scene_getColorization(scene); if (dt) _set(dt); else { dt = visu_colorization_new(); _set(dt); g_object_unref(dt); } } } static void onComboManualChange(GtkComboBox *combo, gpointer data _U_) { int iCol; VisuData *dataObj; dataObj = visu_ui_panel_getData(VISU_UI_PANEL(panelDataFile)); g_return_if_fail(dataObj); iCol = gtk_combo_box_get_active(combo); if (!attachedDt || iCol < 0) return; iCol -= N_COORDS_COLS; visu_ui_numerical_entry_setValue(VISU_UI_NUMERICAL_ENTRY(entryDataMin), (double)visu_colorization_getMin(attachedDt, iCol)); visu_ui_numerical_entry_setValue(VISU_UI_NUMERICAL_ENTRY(entryDataMax), (double)visu_colorization_getMax(attachedDt, iCol)); } static gboolean hideBelow(const VisuNodeMasker *masker _U_, const VisuNodeValuesIter *at, gpointer data) { struct _HideBelowData *st = (struct _HideBelowData*)data; return (visu_node_values_farray_getFloatAtIter(VISU_NODE_VALUES_FARRAY(at->vals), at, st->column) < st->value); } static void onCheckHideMinValuesChange(GtkToggleButton *toggle, gpointer data _U_) { if (!attachedDt) return; /* Set or unset the hiding mode for the current colorization. */ if (gtk_toggle_button_get_active(toggle)) visu_node_masker_setMaskFunc(VISU_NODE_MASKER(attachedDt), hideBelow, &hidingData, (GDestroyNotify)0); else visu_node_masker_setMaskFunc(VISU_NODE_MASKER(attachedDt), (VisuNodeMaskerFunc)0, (gpointer)0, (GDestroyNotify)0); } static void onEntryHideMinValuesChange(VisuUiNumericalEntry *entry, double oldValue _U_, gpointer data _U_) { DBG_fprintf(stderr, "Panel DataFile : change value on hide" " min values entry : %f\n", visu_ui_numerical_entry_getValue(entry)); hidingData.value = visu_ui_numerical_entry_getValue(entry); if (!visu_data_colorizer_getActive(VISU_DATA_COLORIZER(attachedDt)) || !gtk_toggle_button_get_active(GTK_TOGGLE_BUTTON(checkHideMinValues))) return; visu_node_masker_emitDirty(VISU_NODE_MASKER(attachedDt)); } static void onSpinHideMinValuesChange(GtkSpinButton *spinbutton, gpointer user_data _U_) { DBG_fprintf(stderr, "Panel DataFile : change value of spin column" " for hide function : %f\n", gtk_spin_button_get_value(spinbutton)); hidingData.column = (guint)gtk_spin_button_get_value_as_int(spinbutton) - 1; if (!visu_data_colorizer_getActive(VISU_DATA_COLORIZER(attachedDt)) || !gtk_toggle_button_get_active(GTK_TOGGLE_BUTTON(checkHideMinValues))) return; visu_node_masker_emitDirty(VISU_NODE_MASKER(attachedDt)); } static void onEntryExtChange(GtkEntry *entry, gpointer data _U_) { _createDialogFilters(GTK_FILE_CHOOSER(openDataFileButton), gtk_entry_get_text(entry)); } static gboolean onEntryExtFocus(GtkEntry *entry, GdkEventFocus *event _U_, gpointer data _U_) { _createDialogFilters(GTK_FILE_CHOOSER(openDataFileButton), gtk_entry_get_text(entry)); return FALSE; } v_sim-3.8.0/src/panelModules/panelDataFile.h000066400000000000000000000037011370110300500207070ustar00rootroot00000000000000/* EXTRAITS DE LA LICENCE Copyright CEA, contributeurs : Luc BILLARD et Damien CALISTE, laboratoire L_Sim, (2001-2005) Adresse mèl : BILLARD, non joignable par mèl ; CALISTE, damien P caliste AT cea P fr. Ce logiciel est un programme informatique servant à visualiser des structures atomiques dans un rendu pseudo-3D. Ce logiciel est régi par la licence CeCILL soumise au droit français et respectant les principes de diffusion des logiciels libres. Vous pouvez utiliser, modifier et/ou redistribuer ce programme sous les conditions de la licence CeCILL telle que diffusée par le CEA, le CNRS et l'INRIA sur le site "http://www.cecill.info". Le fait que vous puissiez accéder à cet en-tête signifie que vous avez pris connaissance de la licence CeCILL, et que vous en avez accepté les termes (cf. le fichier Documentation/licence.fr.txt fourni avec ce logiciel). */ /* LICENCE SUM UP Copyright CEA, contributors : Luc BILLARD et Damien CALISTE, laboratoire L_Sim, (2001-2005) E-mail address: BILLARD, not reachable any more ; CALISTE, damien P caliste AT cea P fr. This software is a computer program whose purpose is to visualize atomic configurations in 3D. This software is governed by the CeCILL license under French law and abiding by the rules of distribution of free software. You can use, modify and/ or redistribute the software under the terms of the CeCILL license as circulated by CEA, CNRS and INRIA at the following URL "http://www.cecill.info". The fact that you are presently reading this means that you have had knowledge of the CeCILL license and that you accept its terms. You can find a copy of this licence shipped with this software at Documentation/licence.en.txt. */ #ifndef PANELDATAFILE_H #define PANELDATAFILE_H #include #include #include VisuUiPanel* visu_ui_panel_colorization_init(VisuUiMain *ui); #endif v_sim-3.8.0/src/panelModules/panelElements.c000066400000000000000000000106141370110300500210060ustar00rootroot00000000000000/* EXTRAITS DE LA LICENCE Copyright CEA, contributeurs : Luc BILLARD et Damien CALISTE, laboratoire L_Sim, (2001-2005) Adresse mèl : BILLARD, non joignable par mèl ; CALISTE, damien P caliste AT cea P fr. Ce logiciel est un programme informatique servant à visualiser des structures atomiques dans un rendu pseudo-3D. Ce logiciel est régi par la licence CeCILL soumise au droit français et respectant les principes de diffusion des logiciels libres. Vous pouvez utiliser, modifier et/ou redistribuer ce programme sous les conditions de la licence CeCILL telle que diffusée par le CEA, le CNRS et l'INRIA sur le site "http://www.cecill.info". Le fait que vous puissiez accéder à cet en-tête signifie que vous avez pris connaissance de la licence CeCILL, et que vous en avez accepté les termes (cf. le fichier Documentation/licence.fr.txt fourni avec ce logiciel). */ /* LICENCE SUM UP Copyright CEA, contributors : Luc BILLARD et Damien CALISTE, laboratoire L_Sim, (2001-2005) E-mail address: BILLARD, not reachable any more ; CALISTE, damien P caliste AT cea P fr. This software is a computer program whose purpose is to visualize atomic configurations in 3D. This software is governed by the CeCILL license under French law and abiding by the rules of distribution of free software. You can use, modify and/ or redistribute the software under the terms of the CeCILL license as circulated by CEA, CNRS and INRIA at the following URL "http://www.cecill.info". The fact that you are presently reading this means that you have had knowledge of the CeCILL license and that you accept its terms. You can find a copy of this licence shipped with this software at Documentation/licence.en.txt. */ #include "panelElements.h" #include #include /** * SECTION: panelElements * @short_description: The tab where #VisuElement characteristics can * be tuned. * * It is possible to get the list of selected elements by * calling visu_ui_panel_elements_getSelected(). */ /** * panelElements: * * A pointer on the #VisuUiPanel that host the elements chooser. */ static GtkWidget *panelElements = NULL; /* Local methods. */ static void createInteriorElements(GtkWidget *visu_ui_panel); /** * visu_ui_panel_elements_init: (skip) * @ui: a #VisuUiMain object. * * Should be used in the list declared in externalModules.h to be loaded by * V_Sim on start-up. This routine will create the #VisuUiPanel where the element * stuff can be done, such as choosing a colour, setting the radius of * spheres... * * Returns: a newly created #VisuUiPanel object. */ VisuUiPanel* visu_ui_panel_elements_init(VisuUiMain *ui _U_) { gchar *cl = _("Set elements caracteristics"); gchar *tl = _("Elements"); panelElements = visu_ui_panel_newWithIconFromPath("Panel_elements", cl, tl, "stock-elements_20.png"); g_return_val_if_fail(panelElements, (VisuUiPanel*)0); createInteriorElements(panelElements); visu_ui_panel_setDockable(VISU_UI_PANEL(panelElements), TRUE); return VISU_UI_PANEL(panelElements); } static void createInteriorElements(GtkWidget *visu_ui_panel) { GtkWidget *vbox; GtkWidget *scrollView; VisuGlNodeScene *scene; scrollView = gtk_scrolled_window_new((GtkAdjustment*)0, (GtkAdjustment*)0); gtk_scrolled_window_set_policy (GTK_SCROLLED_WINDOW (scrollView), GTK_POLICY_AUTOMATIC, GTK_POLICY_AUTOMATIC); gtk_scrolled_window_set_shadow_type (GTK_SCROLLED_WINDOW (scrollView), GTK_SHADOW_NONE); scene = visu_ui_rendering_window_getGlScene(visu_ui_main_class_getDefaultRendering()); vbox = visu_ui_elements_new(VISU_NODE_ARRAY_RENDERER(visu_gl_node_scene_getNodes(scene))); #if GTK_MAJOR_VERSION < 3 || (GTK_MAJOR_VERSION == 3 && GTK_MINOR_VERSION < 8) gtk_scrolled_window_add_with_viewport(GTK_SCROLLED_WINDOW(scrollView), vbox); #else gtk_container_add(GTK_CONTAINER(scrollView), vbox); #endif gtk_widget_show_all(scrollView); gtk_container_add(GTK_CONTAINER(visu_ui_panel), scrollView); } /** * visu_ui_panel_elements_getStatic: * * Creates and retrieves the #VisuUiPanel used to handle #VisuElement. * * Since: 3.8 * * Returns: (transfer none): a #VisuUiPanel object. **/ GtkWidget* visu_ui_panel_elements_getStatic() { if (!panelElements) visu_ui_panel_elements_init((VisuUiMain*)0); return panelElements; } v_sim-3.8.0/src/panelModules/panelElements.h000066400000000000000000000042471370110300500210200ustar00rootroot00000000000000/* EXTRAITS DE LA LICENCE Copyright CEA, contributeurs : Luc BILLARD et Damien CALISTE, laboratoire L_Sim, (2001-2005) Adresse mèl : BILLARD, non joignable par mèl ; CALISTE, damien P caliste AT cea P fr. Ce logiciel est un programme informatique servant à visualiser des structures atomiques dans un rendu pseudo-3D. Ce logiciel est régi par la licence CeCILL soumise au droit français et respectant les principes de diffusion des logiciels libres. Vous pouvez utiliser, modifier et/ou redistribuer ce programme sous les conditions de la licence CeCILL telle que diffusée par le CEA, le CNRS et l'INRIA sur le site "http://www.cecill.info". Le fait que vous puissiez accéder à cet en-tête signifie que vous avez pris connaissance de la licence CeCILL, et que vous en avez accepté les termes (cf. le fichier Documentation/licence.fr.txt fourni avec ce logiciel). */ /* LICENCE SUM UP Copyright CEA, contributors : Luc BILLARD et Damien CALISTE, laboratoire L_Sim, (2001-2005) E-mail address: BILLARD, not reachable any more ; CALISTE, damien P caliste AT cea P fr. This software is a computer program whose purpose is to visualize atomic configurations in 3D. This software is governed by the CeCILL license under French law and abiding by the rules of distribution of free software. You can use, modify and/ or redistribute the software under the terms of the CeCILL license as circulated by CEA, CNRS and INRIA at the following URL "http://www.cecill.info". The fact that you are presently reading this means that you have had knowledge of the CeCILL license and that you accept its terms. You can find a copy of this licence shipped with this software at Documentation/licence.en.txt. */ #ifndef PANELELEMENTS_H #define PANELELEMENTS_H #include #include #include VisuUiPanel* visu_ui_panel_elements_init(VisuUiMain *ui); /** * VISU_UI_PANEL_ELEMENTS: * * Retrieve the widget of the panel of #VisuElement. * * Returns: a #GtkWidget owned by V_Sim. */ #define VISU_UI_PANEL_ELEMENTS visu_ui_panel_elements_getStatic() GtkWidget* visu_ui_panel_elements_getStatic(); #endif v_sim-3.8.0/src/panelModules/panelFogBgColor.c000066400000000000000000000402411370110300500212140ustar00rootroot00000000000000/* EXTRAITS DE LA LICENCE Copyright CEA, contributeurs : Luc BILLARD et Damien CALISTE, laboratoire L_Sim, (2001-2005) Adresse mèl : BILLARD, non joignable par mèl ; CALISTE, damien P caliste AT cea P fr. Ce logiciel est un programme informatique servant à visualiser des structures atomiques dans un rendu pseudo-3D. Ce logiciel est régi par la licence CeCILL soumise au droit français et respectant les principes de diffusion des logiciels libres. Vous pouvez utiliser, modifier et/ou redistribuer ce programme sous les conditions de la licence CeCILL telle que diffusée par le CEA, le CNRS et l'INRIA sur le site "http://www.cecill.info". Le fait que vous puissiez accéder à cet en-tête signifie que vous avez pris connaissance de la licence CeCILL, et que vous en avez accepté les termes (cf. le fichier Documentation/licence.fr.txt fourni avec ce logiciel). */ /* LICENCE SUM UP Copyright CEA, contributors : Luc BILLARD et Damien CALISTE, laboratoire L_Sim, (2001-2005) E-mail address: BILLARD, not reachable any more ; CALISTE, damien P caliste AT cea P fr. This software is a computer program whose purpose is to visualize atomic configurations in 3D. This software is governed by the CeCILL license under French law and abiding by the rules of distribution of free software. You can use, modify and/ or redistribute the software under the terms of the CeCILL license as circulated by CEA, CNRS and INRIA at the following URL "http://www.cecill.info". The fact that you are presently reading this means that you have had knowledge of the CeCILL license and that you accept its terms. You can find a copy of this licence shipped with this software at Documentation/licence.en.txt. */ #include "panelFogBgColor.h" #include #include #include #include #include #include #include #include #include #include #include /** * SECTION:panelFogBgColor * @short_description: The widget to tune the background and the fog. * * This is the user interface for fog and the background. The * background can be either uniform or use a bitmap picture. The fog * can be of different colours, custom or background. */ /* Sensitive widget in this subpanel. */ static GtkWidget *checkFogIsOn; static GtkWidget *rangeFogStart, *rangeFogEnd; static GtkWidget *radioBgFog, *radioOtherFog; static GtkWidget *rgbBgColor[4]; static GtkWidget *rgbFogColor[3]; static GtkWidget *bgImageWd, *checkFollowZoom, *checkImageTitle; /* Private functions. */ static GtkWidget *createInteriorFogBgColor(VisuUiMain *ui); static gboolean loadBgFile(gpointer data); /* Local callbacks. */ #if GTK_MAJOR_VERSION > 2 || GTK_MINOR_VERSION > 11 static void onBgImageSet(GtkFileChooserButton *filechooserbutton, gpointer data); static void onFileNotified(VisuGlExtBg *bg, GParamSpec *pspec, GtkFileChooserButton *button); #else static void onBgImageSet(GtkDialog *dialog, gint response, gpointer data); #endif #if GTK_MAJOR_VERSION == 2 && GTK_MINOR_VERSION < 6 static void onBgImageChoose(GtkButton *bt, gpointer data); #endif static void onBgImageUnset(GtkButton *bt, gpointer data); static void onBgImageFollow(GtkToggleButton *bt, gpointer data); static GtkWidget *panelFogBgColor; static int disableCallbacksFogBgColor; VisuUiPanel* visu_ui_panel_bg_init(VisuUiMain *ui) { char *cl = _("Fog and background color"); char *tl = _("Fog & bg"); panelFogBgColor = visu_ui_panel_newWithIconFromPath("Panel_fog_and_bg_color", cl, tl, "stock-fog_20.png"); if (!panelFogBgColor) return (VisuUiPanel*)0; gtk_container_add(GTK_CONTAINER(panelFogBgColor), createInteriorFogBgColor(ui)); visu_ui_panel_setDockable(VISU_UI_PANEL(panelFogBgColor), TRUE); /* Private parameters. */ disableCallbacksFogBgColor = 0; return VISU_UI_PANEL(panelFogBgColor); } static void update_preview_cb(GtkFileChooser *file_chooser, gpointer data) { GtkWidget *preview; char *filename; GdkPixbuf *pixbuf; gboolean have_preview; preview = GTK_WIDGET (data); filename = gtk_file_chooser_get_preview_filename (file_chooser); if (filename) pixbuf = gdk_pixbuf_new_from_file_at_size (filename, 128, 128, NULL); else pixbuf = (GdkPixbuf*)0; have_preview = (pixbuf != NULL); g_free (filename); gtk_image_set_from_pixbuf (GTK_IMAGE (preview), pixbuf); if (pixbuf) g_object_unref (pixbuf); gtk_file_chooser_set_preview_widget_active(file_chooser, have_preview); } static GtkWidget *createInteriorFogBgColor(VisuUiMain *ui) { GtkWidget *vbox, *hbox; GtkWidget *label; GtkWidget *table; #define RED_LABEL _("R:") #define GREEN_LABEL _("G:") #define BLUE_LABEL _("B:") #define ALPHA_LABEL _("A:") char *rgb[4]; const char *rgbName[4] = {"scroll_r", "scroll_g", "scroll_b", "scroll_a"}; const char *rgbProp[4] = {"bg-red", "bg-green", "bg-blue", "bg-alpha"}; const char *fogProp[4] = {"fog-red", "fog-green", "fog-blue", "fog-alpha"}; int i; GtkWidget *dialog, *bt, *preview; GtkFileFilter *filters; VisuGlNodeScene *scene; #if GTK_MAJOR_VERSION == 2 && GTK_MINOR_VERSION < 12 GtkTooltips *tooltips; tooltips = gtk_tooltips_new (); #endif rgb[0] = RED_LABEL; rgb[1] = GREEN_LABEL; rgb[2] = BLUE_LABEL; rgb[3] = ALPHA_LABEL; scene = visu_ui_rendering_window_getGlScene(visu_ui_main_getRendering(ui)); vbox = gtk_vbox_new(FALSE, 0); gtk_widget_set_margin_start(vbox, 5); gtk_widget_set_margin_end(vbox, 5); table = gtk_grid_new(); tool_grid_resize(table, 5, 2); gtk_box_pack_start(GTK_BOX(vbox), table, FALSE, FALSE, 5); hbox = gtk_hbox_new(FALSE, 0); gtk_grid_attach(GTK_GRID(table), hbox, 0, 0, 2, 1); label = gtk_label_new(_("Background:")); gtk_widget_set_name(label, "label_head"); gtk_box_pack_start(GTK_BOX(hbox), label, FALSE, FALSE, 2); for (i = 0; i < 4; i++) { label = gtk_label_new(rgb[i]); gtk_grid_attach(GTK_GRID(table), label, 0, i + 1, 1, 1); rgbBgColor[i] = gtk_hscale_new_with_range(0., 1., 0.001); g_object_bind_property(scene, rgbProp[i], gtk_range_get_adjustment(GTK_RANGE(rgbBgColor[i])), "value", G_BINDING_SYNC_CREATE | G_BINDING_BIDIRECTIONAL); gtk_scale_set_value_pos(GTK_SCALE(rgbBgColor[i]), GTK_POS_RIGHT); gtk_widget_set_name(rgbBgColor[i], rgbName[i]); gtk_widget_set_hexpand(rgbBgColor[i], TRUE); gtk_grid_attach(GTK_GRID(table), rgbBgColor[i], 1, i + 1, 1, 1); } hbox = gtk_hbox_new(FALSE, 0); gtk_box_pack_start(GTK_BOX(vbox), hbox, FALSE, FALSE, 0); label = gtk_label_new(_("Insert an image:")); gtk_box_pack_start(GTK_BOX(hbox), label, FALSE, FALSE, 5); dialog = gtk_file_chooser_dialog_new(_("Choose a background image"), (GtkWindow*)0, GTK_FILE_CHOOSER_ACTION_OPEN, TOOL_ICON_CANCEL, GTK_RESPONSE_CANCEL, TOOL_ICON_OPEN, GTK_RESPONSE_ACCEPT, NULL); filters = gtk_file_filter_new(); gtk_file_filter_add_pixbuf_formats(filters); gtk_file_chooser_set_filter(GTK_FILE_CHOOSER(dialog), filters); preview = gtk_image_new(); gtk_file_chooser_set_preview_widget(GTK_FILE_CHOOSER(dialog), preview); gtk_file_chooser_set_preview_widget_active(GTK_FILE_CHOOSER(dialog), FALSE); g_signal_connect(GTK_FILE_CHOOSER(dialog), "update-preview", G_CALLBACK(update_preview_cb), preview); #if GTK_MAJOR_VERSION > 2 || GTK_MINOR_VERSION > 5 bgImageWd = gtk_file_chooser_button_new_with_dialog(dialog); #if GTK_MAJOR_VERSION > 2 || GTK_MINOR_VERSION > 11 g_signal_connect(G_OBJECT(bgImageWd), "file-set", G_CALLBACK(onBgImageSet), (gpointer)0); g_signal_connect(visu_gl_node_scene_getBgImage(scene), "notify::background-file", G_CALLBACK(onFileNotified), bgImageWd); onFileNotified(visu_gl_node_scene_getBgImage(scene), (GParamSpec*)0, GTK_FILE_CHOOSER_BUTTON(bgImageWd)); #else g_signal_connect(G_OBJECT(dialog), "response", G_CALLBACK(onBgImageSet), (gpointer)bgImageWd); #endif #else bgImageWd = gtk_button_new_from_stock(GTK_STOCK_OPEN); g_signal_connect(G_OBJECT(dialog), "clicked", G_CALLBACK(onBgImageChoose), (gpointer)dialog); #endif gtk_box_pack_start(GTK_BOX(hbox), bgImageWd, TRUE, TRUE, 0); bt = gtk_button_new(); gtk_widget_set_tooltip_text(bt, _("Remove the background image.")); gtk_container_add(GTK_CONTAINER(bt), gtk_image_new_from_icon_name("edit-clear", GTK_ICON_SIZE_MENU)); gtk_box_pack_start(GTK_BOX(hbox), bt, FALSE, FALSE, 5); g_signal_connect(G_OBJECT(bt), "clicked", G_CALLBACK(onBgImageUnset), (gpointer)bgImageWd); hbox = gtk_hbox_new(FALSE, 0); gtk_box_pack_start(GTK_BOX(vbox), hbox, FALSE, FALSE, 5); checkFollowZoom = gtk_check_button_new_with_mnemonic(_("_follow camera")); g_signal_connect(G_OBJECT(checkFollowZoom), "toggled", G_CALLBACK(onBgImageFollow), (gpointer)0); gtk_box_pack_end(GTK_BOX(hbox), checkFollowZoom, FALSE, FALSE, 0); checkImageTitle = gtk_check_button_new_with_mnemonic(_("_display filename")); g_object_bind_property(visu_gl_node_scene_getBgImage(scene), "display-background-filename", checkImageTitle, "active", G_BINDING_SYNC_CREATE | G_BINDING_BIDIRECTIONAL); gtk_box_pack_end(GTK_BOX(hbox), checkImageTitle, FALSE, FALSE, 0); hbox = gtk_hbox_new(FALSE, 0); label = gtk_label_new(_("Use fog:")); gtk_widget_set_name(label, "label_head"); gtk_box_pack_start(GTK_BOX(hbox), label, FALSE, FALSE, 2); checkFogIsOn = gtk_check_button_new(); g_object_bind_property(scene, "fog-active", checkFogIsOn, "active", G_BINDING_SYNC_CREATE | G_BINDING_BIDIRECTIONAL); gtk_box_pack_start(GTK_BOX(hbox), checkFogIsOn, FALSE, FALSE, 2); gtk_box_pack_start(GTK_BOX(vbox), hbox, FALSE, FALSE, 5); table = gtk_grid_new(); tool_grid_resize(table, 2, 2); gtk_box_pack_start(GTK_BOX(vbox), table, FALSE, FALSE, 5); label = gtk_label_new(_("Start:")); gtk_label_set_xalign(GTK_LABEL(label), 1.); gtk_grid_attach(GTK_GRID(table), label, 0, 0, 1, 1); rangeFogStart = gtk_hscale_new_with_range(0., 1., 0.001); g_object_bind_property(scene, "fog-start", gtk_range_get_adjustment(GTK_RANGE(rangeFogStart)), "value", G_BINDING_SYNC_CREATE | G_BINDING_BIDIRECTIONAL); #if GTK_MAJOR_VERSION > 2 || GTK_MINOR_VERSION > 11 gtk_range_set_restrict_to_fill_level(GTK_RANGE(rangeFogStart), TRUE); gtk_range_set_show_fill_level(GTK_RANGE(rangeFogStart), TRUE); #endif gtk_scale_set_value_pos(GTK_SCALE(rangeFogStart), GTK_POS_RIGHT); gtk_widget_set_hexpand(rangeFogStart, TRUE); gtk_grid_attach(GTK_GRID(table), rangeFogStart, 1, 0, 1, 1); label = gtk_label_new(_("End:")); gtk_label_set_xalign(GTK_LABEL(label), 1.); gtk_grid_attach(GTK_GRID(table), label, 0, 1, 1, 1); rangeFogEnd = gtk_hscale_new_with_range(0., 1., 0.001); g_object_bind_property(scene, "fog-full", gtk_range_get_adjustment(GTK_RANGE(rangeFogEnd)), "value", G_BINDING_SYNC_CREATE | G_BINDING_BIDIRECTIONAL); #if GTK_MAJOR_VERSION > 2 || GTK_MINOR_VERSION > 11 g_object_bind_property(gtk_range_get_adjustment(GTK_RANGE(rangeFogEnd)), "value", rangeFogStart, "fill-level", G_BINDING_SYNC_CREATE); #endif gtk_scale_set_value_pos(GTK_SCALE(rangeFogEnd), GTK_POS_RIGHT); gtk_widget_set_hexpand(rangeFogEnd, TRUE); gtk_grid_attach(GTK_GRID(table), rangeFogEnd, 1, 1, 1, 1); hbox = gtk_hbox_new(FALSE, 0); gtk_box_pack_start(GTK_BOX(vbox), hbox, FALSE, FALSE, 5); label = gtk_label_new(_("Color:")); gtk_box_pack_start(GTK_BOX(hbox), label, FALSE, FALSE, 2); radioBgFog = gtk_radio_button_new_with_label(NULL, _("background color")); g_object_bind_property(scene, "fog-follows-bg", radioBgFog, "active", G_BINDING_SYNC_CREATE | G_BINDING_BIDIRECTIONAL); gtk_box_pack_start(GTK_BOX(hbox), radioBgFog, FALSE, FALSE, 2); radioOtherFog = gtk_radio_button_new_with_label_from_widget(GTK_RADIO_BUTTON(radioBgFog), _("specific color")); g_object_bind_property(scene, "fog-follows-bg", radioOtherFog, "active", G_BINDING_SYNC_CREATE | G_BINDING_BIDIRECTIONAL | G_BINDING_INVERT_BOOLEAN); gtk_box_pack_start(GTK_BOX(hbox), radioOtherFog, FALSE, FALSE, 2); table = gtk_grid_new(); tool_grid_resize(table, 5, 2); gtk_box_pack_start(GTK_BOX(vbox), table, FALSE, FALSE, 5); for (i = 0; i < 3; i++) { label = gtk_label_new(rgb[i]); gtk_grid_attach(GTK_GRID(table), label, 0, i + 1, 1, 1); rgbFogColor[i] = gtk_hscale_new_with_range(0., 1., 0.001); g_object_bind_property(scene, fogProp[i], gtk_range_get_adjustment(GTK_RANGE(rgbFogColor[i])), "value", G_BINDING_SYNC_CREATE | G_BINDING_BIDIRECTIONAL); g_object_bind_property(radioOtherFog, "active", rgbFogColor[i], "sensitive", G_BINDING_SYNC_CREATE); gtk_scale_set_value_pos(GTK_SCALE(rgbFogColor[i]), GTK_POS_RIGHT); gtk_widget_set_sensitive(rgbFogColor[i], FALSE); gtk_widget_set_name(rgbFogColor[i], rgbName[i]); gtk_widget_set_hexpand(rgbFogColor[i], TRUE); gtk_grid_attach(GTK_GRID(table), rgbFogColor[i], 1, i + 1, 1, 1); } gtk_widget_show_all(vbox); return vbox; } /*************/ /* Callbacks */ /*************/ #if GTK_MAJOR_VERSION > 2 || GTK_MINOR_VERSION > 11 static void onBgImageSet(GtkFileChooserButton *filechooserbutton, gpointer data _U_) { gchar *filename; DBG_fprintf(stderr, "Panel Fog & Bg: bg image changed.\n"); filename = gtk_file_chooser_get_filename(GTK_FILE_CHOOSER(filechooserbutton)); if (!filename) return; g_idle_add(loadBgFile, (gpointer)filename); } #else static void onBgImageSet(GtkDialog *dialog, gint response, gpointer data _U_) { gchar *filename; if (response != GTK_RESPONSE_ACCEPT) return; filename = gtk_file_chooser_get_filename(GTK_FILE_CHOOSER(dialog)); g_idle_add(loadBgFile, (gpointer)filename); } #endif #if GTK_MAJOR_VERSION == 2 && GTK_MINOR_VERSION < 6 static void onBgImageChoose(GtkButton *bt, gpointer data) { gchar *filename; if (gtk_dialog_run(GTK_DIALOG(data)) != GTK_RESPONSE_ACCEPT) return; filename = gtk_file_chooser_get_filename(GTK_FILE_CHOOSER(data)); g_idle_add(loadBgFile, (gpointer)filename); } #endif static gboolean loadBgFile(gpointer data) { GError *error; VisuGlNodeScene *scene; scene = visu_ui_rendering_window_getGlScene(visu_ui_main_class_getDefaultRendering()); error = (GError*)0; visu_gl_ext_bg_setFile(visu_gl_node_scene_getBgImage(scene), (const gchar*)data, &error); if (error) { visu_ui_raiseWarning(_("Load image file"), error->message, (GtkWindow*)0); g_error_free(error); } g_free(data); return G_SOURCE_REMOVE; } static void onBgImageUnset(GtkButton *bt _U_, gpointer data) { VisuGlNodeScene *scene; scene = visu_ui_rendering_window_getGlScene(visu_ui_main_class_getDefaultRendering()); visu_gl_ext_bg_setFile(visu_gl_node_scene_getBgImage(scene), (const gchar*)0, NULL); #if GTK_MAJOR_VERSION > 2 || GTK_MINOR_VERSION > 5 gtk_file_chooser_unselect_all(GTK_FILE_CHOOSER(data)); #endif } static void onBgImageFollow(GtkToggleButton *bt, gpointer data _U_) { VisuGlView *view; VisuGlNodeScene *scene; view = visu_ui_panel_getView(VISU_UI_PANEL(panelFogBgColor)); g_return_if_fail(view); scene = visu_ui_rendering_window_getGlScene(visu_ui_main_class_getDefaultRendering()); visu_gl_ext_bg_setFollowCamera(visu_gl_node_scene_getBgImage(scene), gtk_toggle_button_get_active(bt), view->camera.gross, view->camera.xs, view->camera.ys); } #if GTK_MAJOR_VERSION > 2 || GTK_MINOR_VERSION > 5 static void onFileNotified(VisuGlExtBg *bg, GParamSpec *pspec _U_, GtkFileChooserButton *button) { gchar *path; g_object_get(bg, "background-file", &path, NULL); if (path) gtk_file_chooser_set_filename(GTK_FILE_CHOOSER(button), path); else gtk_file_chooser_unselect_all(GTK_FILE_CHOOSER(button)); g_free(path); } #endif v_sim-3.8.0/src/panelModules/panelFogBgColor.h000066400000000000000000000043051370110300500212220ustar00rootroot00000000000000/* EXTRAITS DE LA LICENCE Copyright CEA, contributeurs : Luc BILLARD et Damien CALISTE, laboratoire L_Sim, (2001-2005) Adresse mèl : BILLARD, non joignable par mèl ; CALISTE, damien P caliste AT cea P fr. Ce logiciel est un programme informatique servant à visualiser des structures atomiques dans un rendu pseudo-3D. Ce logiciel est régi par la licence CeCILL soumise au droit français et respectant les principes de diffusion des logiciels libres. Vous pouvez utiliser, modifier et/ou redistribuer ce programme sous les conditions de la licence CeCILL telle que diffusée par le CEA, le CNRS et l'INRIA sur le site "http://www.cecill.info". Le fait que vous puissiez accéder à cet en-tête signifie que vous avez pris connaissance de la licence CeCILL, et que vous en avez accepté les termes (cf. le fichier Documentation/licence.fr.txt fourni avec ce logiciel). */ /* LICENCE SUM UP Copyright CEA, contributors : Luc BILLARD et Damien CALISTE, laboratoire L_Sim, (2001-2005) E-mail address: BILLARD, not reachable any more ; CALISTE, damien P caliste AT cea P fr. This software is a computer program whose purpose is to visualize atomic configurations in 3D. This software is governed by the CeCILL license under French law and abiding by the rules of distribution of free software. You can use, modify and/ or redistribute the software under the terms of the CeCILL license as circulated by CEA, CNRS and INRIA at the following URL "http://www.cecill.info". The fact that you are presently reading this means that you have had knowledge of the CeCILL license and that you accept its terms. You can find a copy of this licence shipped with this software at Documentation/licence.en.txt. */ #ifndef PANELFOGBGCOLOR_H #define PANELFOGBGCOLOR_H #include /** * visu_ui_panel_bg_init: * * Should be used in the list declared in externalModules.h to be loaded by * V_Sim on start-up. This routine will create the #VisuUiPanel where the fog * and the background colour stuff can be tuned, such the position of * the fog, its colour... * * Returns: a newly created #VisuUiPanel object. */ VisuUiPanel* visu_ui_panel_bg_init(); #endif v_sim-3.8.0/src/panelModules/panelGeometry.c000066400000000000000000000631061370110300500210310ustar00rootroot00000000000000/* EXTRAITS DE LA LICENCE Copyright CEA, contributeurs : Luc BILLARD et Damien CALISTE, laboratoire L_Sim, (2001-2005) Adresse mèl : BILLARD, non joignable par mèl ; CALISTE, damien P caliste AT cea P fr. Ce logiciel est un programme informatique servant à visualiser des structures atomiques dans un rendu pseudo-3D. Ce logiciel est régi par la licence CeCILL soumise au droit français et respectant les principes de diffusion des logiciels libres. Vous pouvez utiliser, modifier et/ou redistribuer ce programme sous les conditions de la licence CeCILL telle que diffusée par le CEA, le CNRS et l'INRIA sur le site "http://www.cecill.info". Le fait que vous puissiez accéder à cet en-tête signifie que vous avez pris connaissance de la licence CeCILL, et que vous en avez accepté les termes (cf. le fichier Documentation/licence.fr.txt fourni avec ce logiciel). */ /* LICENCE SUM UP Copyright CEA, contributors : Luc BILLARD et Damien CALISTE, laboratoire L_Sim, (2001-2005) E-mail address: BILLARD, not reachable any more ; CALISTE, damien P caliste AT cea P fr. This software is a computer program whose purpose is to visualize atomic configurations in 3D. This software is governed by the CeCILL license under French law and abiding by the rules of distribution of free software. You can use, modify and/ or redistribute the software under the terms of the CeCILL license as circulated by CEA, CNRS and INRIA at the following URL "http://www.cecill.info". The fact that you are presently reading this means that you have had knowledge of the CeCILL license and that you accept its terms. You can find a copy of this licence shipped with this software at Documentation/licence.en.txt. */ #include "panelGeometry.h" #include "panelBrowser.h" #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include /** * SECTION: panelGeometry * @short_description: This tab gathers the geometry operation on a * #VisuData, like periodic translation, physical units, ... * * Nothing tunable here. */ /* Local objects. */ static GtkWidget *panelGeometry; static GtkWidget *togglePathSave; static GtkWidget *hboxIOVisuPaths; static GtkWidget *copyGeodiff, *pasteGeodiff, *addGeodiff; /* Local variables. */ static gboolean disableCallbacks; static gboolean widgetsNotBuilt; static gchar *exportPathFile = NULL; #define NO_PATH _("No stored path") #define PATH _("Path has %d step(s)") /* Local routines. */ static GtkWidget *createInteriorBox(VisuGlNodeScene *scene); /* Local callbacks. */ static void onEnter(VisuUiPanel *visu_ui_panel, VisuUiRenderingWindow *window); static void onDataFocused(GObject *obj, VisuData* visuData, gpointer data); static void onPathSaveToggled(GtkToggleButton *toggle, gpointer data); static void onSavePathClicked(GtkButton *bt, gpointer data); static void onLoadPathClicked(GtkButton *bt, gpointer data); static void onDirBrowsed(VisuUiMain *obj, VisuUiDirectoryType type, gpointer user); static void onCopyDiff(GtkButton *button, gpointer data); static void onPasteDiff(GtkToggleButton *button, gpointer data); static void onAddDiff(GtkButton *button, gpointer data); /** * visu_ui_panel_geometry_init: (skip) * @ui: a #VisuUiMain object. * * Should be used in the list declared in externalModules.h to be loaded by * V_Sim on start-up. This routine will create the #VisuUiPanel where the box * stuff can be tuned, such as the bounding box, its colour, and the actions linked * to the periodicity (translation, dupplication...). * * Returns: a newly created #VisuUiPanel object. */ VisuUiPanel* visu_ui_panel_geometry_init(VisuUiMain *ui) { panelGeometry = visu_ui_panel_newWithIconFromPath("Panel_geometry", _("Geometry operations"), _("Geometry"), "stock-geometry_20.png"); if (!panelGeometry) return (VisuUiPanel*)0; visu_ui_panel_setDockable(VISU_UI_PANEL(panelGeometry), TRUE); /* Create the widgets that are needed even without the GTK interface be built. */ togglePathSave = gtk_toggle_button_new(); pasteGeodiff = gtk_toggle_button_new_with_label(_("Paste and align")); copyGeodiff = gtk_button_new_from_icon_name("edit-copy", GTK_ICON_SIZE_BUTTON); addGeodiff = gtk_button_new_from_icon_name("list-add", GTK_ICON_SIZE_BUTTON); /* Create the callbacks of all the sensitive widgets. */ g_signal_connect(panelGeometry, "page-entered", G_CALLBACK(onEnter), (gpointer)visu_ui_main_getRendering(ui)); g_signal_connect(ui, "DirectoryChanged", G_CALLBACK(onDirBrowsed), (gpointer)0); g_signal_connect(ui, "DataFocused", G_CALLBACK(onDataFocused), (gpointer)0); /* Private parameters. */ disableCallbacks = FALSE; widgetsNotBuilt = TRUE; return VISU_UI_PANEL(panelGeometry); } static gboolean fromPathLength(GBinding *binding _U_, const GValue *source_value, GValue *target_value, gpointer user_data _U_) { gchar *text; if (g_value_get_uint(source_value)) text = g_strdup_printf(PATH, g_value_get_uint(source_value)); else text = g_strdup(NO_PATH); g_value_take_string(target_value, text); return TRUE; } static gboolean toShadeToggle(GBinding *binding _U_, const GValue *source_value, GValue *target_value, gpointer user_data _U_) { g_value_set_boolean(target_value, (g_value_get_boxed(source_value) != (gpointer)0)); return TRUE; } static gboolean fromShadeToggle(GBinding *binding _U_, const GValue *source_value, GValue *target_value, gpointer user_data) { if (g_value_get_boolean(source_value)) g_value_set_boxed(target_value, visu_ui_shade_combobox_getSelection(VISU_UI_SHADE_COMBOBOX(user_data))); else g_value_set_boxed(target_value, (gconstpointer)0); return TRUE; } static gboolean toShadeCombo(GBinding *binding _U_, const GValue *source_value, GValue *target_value, gpointer user_data _U_) { g_value_set_boxed(target_value, g_value_get_boxed(source_value)); return TRUE; } static gboolean fromShadeCombo(GBinding *binding _U_, const GValue *source_value, GValue *target_value, gpointer user_data) { if (!gtk_toggle_button_get_active(GTK_TOGGLE_BUTTON(user_data))) return FALSE; g_value_set_boxed(target_value, g_value_get_boxed(source_value)); return TRUE; } static GtkWidget *createInteriorBox(VisuGlNodeScene *scene) { GtkWidget *vbox, *vbox2, *hbox, *bt, *wd, *checkDiff, *checkOrdering, *labelVisuPaths; GtkWidget *checkVisuPaths, *hboxVisuPaths, *hboxVisuPaths2, *checkAdjust; GtkWidget *label; GtkWidget *boxTransform; #define X_LABEL _("dx:") #define Y_LABEL _("dy:") #define Z_LABEL _("dz:") #if GTK_MAJOR_VERSION == 2 && GTK_MINOR_VERSION < 12 GtkTooltips *tooltips; tooltips = gtk_tooltips_new (); #endif vbox = gtk_vbox_new(FALSE, 0); boxTransform = visu_ui_box_transform_new(); g_object_bind_property(scene, "data", boxTransform, "pointset", G_BINDING_SYNC_CREATE); visu_ui_box_transform_bindGlExtBox(VISU_UI_BOX_TRANSFORM(boxTransform), visu_gl_node_scene_getBox(scene)); gtk_box_pack_start(GTK_BOX(vbox), boxTransform, FALSE, FALSE, 0); /************************/ /* The multifile stuff. */ /************************/ label = gtk_label_new(_("Multi file actions")); gtk_widget_set_margin_top(label, 15); gtk_label_set_xalign(GTK_LABEL(label), 0.); gtk_widget_set_name(label, "label_head"); gtk_label_set_use_markup(GTK_LABEL(label), TRUE); gtk_box_pack_start(GTK_BOX(vbox), label, FALSE, FALSE, 0); vbox2 = gtk_vbox_new(FALSE, 2); gtk_widget_set_margin_start(vbox2, 15); gtk_box_pack_start(GTK_BOX(vbox), vbox2, FALSE, FALSE, 0); checkAdjust = gtk_check_button_new_with_mnemonic(_("Automatic zoom _adjustment on file loading")); g_object_bind_property(visu_gl_node_scene_getGlView(scene), "auto-adjust", checkAdjust, "active", G_BINDING_SYNC_CREATE | G_BINDING_BIDIRECTIONAL); gtk_box_pack_start(GTK_BOX(vbox2), checkAdjust, FALSE, FALSE, 0); hbox = gtk_hbox_new(FALSE, 0); gtk_box_pack_start(GTK_BOX(vbox2), hbox, FALSE, FALSE, 0); checkOrdering = gtk_check_button_new_with_mnemonic(_("with re_ordering")); g_object_bind_property(scene, "reorder-reference", checkOrdering, "active", G_BINDING_BIDIRECTIONAL | G_BINDING_SYNC_CREATE); gtk_widget_set_tooltip_text(checkOrdering, _("On load of a new file, reorder the nodes to" " minimize displacements.")); gtk_box_pack_end(GTK_BOX(hbox), checkOrdering, FALSE, FALSE, 0); checkDiff = gtk_check_button_new_with_mnemonic(_("Show node _displacements")); g_object_bind_property(scene, "geometry-differences", checkDiff, "active", G_BINDING_BIDIRECTIONAL | G_BINDING_SYNC_CREATE); gtk_widget_set_tooltip_text(checkDiff, _("When a new file is loaded, draw arrows on nodes that" " represent their displacements with respect to their" " previous positions.")); gtk_box_pack_start(GTK_BOX(hbox), checkDiff, TRUE, TRUE, 0); hbox = gtk_hbox_new(FALSE, 2); gtk_widget_set_margin_start(hbox, 25); gtk_box_pack_start(GTK_BOX(vbox2), hbox, FALSE, FALSE, 0); gtk_box_pack_start(GTK_BOX(hbox), gtk_label_new("Current diff"), FALSE, FALSE, 0); g_object_bind_property(pasteGeodiff, "active", addGeodiff, "sensitive", G_BINDING_SYNC_CREATE); g_signal_connect(G_OBJECT(addGeodiff), "clicked", G_CALLBACK(onAddDiff), (gpointer)pasteGeodiff); gtk_box_pack_end(GTK_BOX(hbox), addGeodiff, FALSE, FALSE, 0); gtk_widget_set_sensitive(pasteGeodiff, FALSE); gtk_box_pack_end(GTK_BOX(hbox), pasteGeodiff, FALSE, FALSE, 0); gtk_button_set_image_position(GTK_BUTTON(pasteGeodiff), GTK_POS_LEFT); g_signal_connect(G_OBJECT(pasteGeodiff), "clicked", G_CALLBACK(onPasteDiff), (gpointer)copyGeodiff); gtk_widget_set_sensitive(copyGeodiff, FALSE); gtk_box_pack_end(GTK_BOX(hbox), copyGeodiff, FALSE, FALSE, 0); gtk_button_set_image_position(GTK_BUTTON(copyGeodiff), GTK_POS_LEFT); g_signal_connect(G_OBJECT(copyGeodiff), "clicked", G_CALLBACK(onCopyDiff), (gpointer)0); hbox = gtk_hbox_new(FALSE, 0); gtk_box_pack_start(GTK_BOX(vbox2), hbox, FALSE, FALSE, 0); checkVisuPaths = gtk_check_button_new_with_mnemonic(_("Use _paths")); g_object_bind_property(scene, "path-active", checkVisuPaths, "active", G_BINDING_SYNC_CREATE | G_BINDING_BIDIRECTIONAL); gtk_widget_set_tooltip_text(checkVisuPaths, _("Store differences between files and plot" " them as lines.")); gtk_box_pack_start(GTK_BOX(hbox), checkVisuPaths, TRUE, TRUE, 0); hboxVisuPaths = gtk_hbox_new(FALSE, 2); g_object_bind_property(checkVisuPaths, "active", hboxVisuPaths, "sensitive", G_BINDING_SYNC_CREATE); gtk_box_pack_start(GTK_BOX(hbox), hboxVisuPaths, FALSE, FALSE, 0); labelVisuPaths = gtk_label_new(NO_PATH); gtk_label_set_use_markup(GTK_LABEL(labelVisuPaths), TRUE); g_object_bind_property_full(scene, "path-length", labelVisuPaths, "label", G_BINDING_SYNC_CREATE, fromPathLength, (GBindingTransformFunc)0, (gpointer)0, (GDestroyNotify)0); gtk_box_pack_start(GTK_BOX(hboxVisuPaths), labelVisuPaths, FALSE, FALSE, 0); gtk_widget_set_tooltip_text(togglePathSave, _("When toggled, store differences" " between files as paths" " through nodes..")); gtk_container_add(GTK_CONTAINER(togglePathSave), gtk_image_new_from_icon_name("media-record", GTK_ICON_SIZE_MENU)); g_object_bind_property(scene, "record-path", togglePathSave, "active", G_BINDING_SYNC_CREATE | G_BINDING_BIDIRECTIONAL); g_signal_connect(G_OBJECT(togglePathSave), "toggled", G_CALLBACK(onPathSaveToggled), (gpointer)0); gtk_box_pack_start(GTK_BOX(hboxVisuPaths), togglePathSave, FALSE, FALSE, 0); bt = gtk_button_new(); gtk_widget_set_tooltip_text(bt, _("Remove all stored paths.")); gtk_container_add(GTK_CONTAINER(bt), gtk_image_new_from_icon_name("edit-clear", GTK_ICON_SIZE_MENU)); g_signal_connect_swapped(G_OBJECT(bt), "clicked", G_CALLBACK(visu_gl_node_scene_clearPaths), scene); gtk_box_pack_start(GTK_BOX(hboxVisuPaths), bt, FALSE, FALSE, 0); hboxVisuPaths2 = gtk_hbox_new(FALSE, 2); g_object_bind_property(checkVisuPaths, "active", hboxVisuPaths2, "sensitive", G_BINDING_SYNC_CREATE); gtk_box_pack_start(GTK_BOX(vbox2), hboxVisuPaths2, FALSE, FALSE, 0); bt = gtk_check_button_new_with_mnemonic(_("colourise with: ")); gtk_widget_set_tooltip_text(bt, _("If energy information was present" " when loading file, colourise the paths" " with shading colours.")); gtk_box_pack_start(GTK_BOX(hboxVisuPaths2), bt, TRUE, TRUE, 0); wd = visu_ui_shade_combobox_new(FALSE, FALSE); g_object_bind_property_full(scene, "path-shade", bt, "active", G_BINDING_SYNC_CREATE | G_BINDING_BIDIRECTIONAL, toShadeToggle, fromShadeToggle, wd, (GDestroyNotify)0); g_object_bind_property_full(scene, "path-shade", wd, "shade", G_BINDING_SYNC_CREATE | G_BINDING_BIDIRECTIONAL, toShadeCombo, fromShadeCombo, bt, (GDestroyNotify)0); g_object_bind_property(bt, "active", wd, "sensitive", G_BINDING_SYNC_CREATE); gtk_box_pack_start(GTK_BOX(hboxVisuPaths2), wd, FALSE, FALSE, 0); hboxIOVisuPaths = gtk_hbox_new(FALSE, 2); /* gtk_widget_set_sensitive(hboxIOVisuPaths, FALSE); */ gtk_box_pack_start(GTK_BOX(hboxVisuPaths2), hboxIOVisuPaths, FALSE, FALSE, 0); bt = gtk_button_new(); gtk_widget_set_tooltip_text(bt, _("Read a set of paths from a file and" " add them to the current set.")); gtk_container_add(GTK_CONTAINER(bt), gtk_image_new_from_icon_name("document-open", GTK_ICON_SIZE_MENU)); g_signal_connect(G_OBJECT(bt), "clicked", G_CALLBACK(onLoadPathClicked), scene); gtk_box_pack_start(GTK_BOX(hboxIOVisuPaths), bt, FALSE, FALSE, 0); bt = gtk_button_new(); gtk_widget_set_tooltip_text(bt, _("Save the current set of paths" " to an XML file.")); gtk_container_add(GTK_CONTAINER(bt), gtk_image_new_from_icon_name("document-save", GTK_ICON_SIZE_MENU)); g_object_bind_property(scene, "path-length", bt, "sensitive", G_BINDING_SYNC_CREATE); g_signal_connect(G_OBJECT(bt), "clicked", G_CALLBACK(onSavePathClicked), scene); gtk_box_pack_start(GTK_BOX(hboxIOVisuPaths), bt, FALSE, FALSE, 0); gtk_widget_show_all(vbox); widgetsNotBuilt = FALSE; return vbox; } static void updateSensitive(VisuData *dataObj) { VisuNodeValues *vals = dataObj ? visu_data_getNodeProperties(dataObj, VISU_DATA_DIFF_DEFAULT_ID) : (VisuNodeValues*)0; gtk_widget_set_sensitive(copyGeodiff, (vals != (VisuNodeValues*)0)); gtk_widget_set_sensitive(pasteGeodiff, g_object_get_data(G_OBJECT(copyGeodiff), "stored-geodiff") != NULL); } /*************/ /* Callbacks */ /*************/ static void onEnter(VisuUiPanel *visu_ui_panel _U_, VisuUiRenderingWindow *window) { VisuData *dataObj; if (widgetsNotBuilt) { DBG_fprintf(stderr, "Panel Geometry: first build on enter.\n"); gtk_container_set_border_width(GTK_CONTAINER(panelGeometry), 5); gtk_container_add(GTK_CONTAINER(panelGeometry), createInteriorBox(visu_ui_rendering_window_getGlScene(window))); } dataObj = visu_ui_panel_getData(VISU_UI_PANEL(panelGeometry)); updateSensitive(dataObj); } static void onDataFocused(GObject *obj _U_, VisuData* visuData, gpointer data _U_) { DBG_fprintf(stderr, "Panel Geometry: Catch 'DataFocused' signal," " update values.\n"); if (visuData) updateSensitive(visuData); } static guint highlightMatching(VisuGlExtMarks *marks, VisuData *dataObj, VisuNodeFinder *finder, const gfloat delta[3]) { VisuNodeArrayIter iter; GArray *ids; gfloat xyz[3]; gint id; guint ln; /* Remove previous marks. */ visu_gl_ext_marks_unHighlight(marks); /* Add matching nodes. */ ids = g_array_new(FALSE, FALSE, sizeof(guint)); if (dataObj) { visu_node_array_iter_new(VISU_NODE_ARRAY(dataObj), &iter); for (visu_node_array_iterStart(VISU_NODE_ARRAY(dataObj), &iter); iter.node; visu_node_array_iterNext(VISU_NODE_ARRAY(dataObj), &iter)) { visu_data_getNodePosition(dataObj, iter.node, xyz); xyz[0] += delta[0]; xyz[1] += delta[1]; xyz[2] += delta[2]; id = visu_node_finder_lookup(finder, xyz, 1.f); if (id >= 0) g_array_append_val(ids, id); } } visu_gl_ext_marks_setHighlight(marks, ids, MARKS_STATUS_SET); ln = ids->len; g_array_unref(ids); return ln; } static void onDragGeodiff(VisuInteractive *inter _U_, const gfloat delta[3], gpointer data) { VisuUiRenderingWindow *window; VisuGlExtGeodiff *extGeodiff; /* VisuGlExtMarks *marks; */ /* VisuNodeFinder *finder; */ /* VisuData *dataObj; */ guint ln; gchar *mess; window = visu_ui_main_class_getDefaultRendering(); extGeodiff = g_object_get_data(G_OBJECT(data), "ext-geodiff"); /* marks = visu_ui_rendering_window_getMarks(window); */ /* finder = g_object_get_data(G_OBJECT(data), "finder-geodiff"); */ /* dataObj = visu_gl_ext_node_vectors_getData(VISU_GL_EXT_NODE_VECTORS(extGeodiff)); */ /* ln = highlightMatching(marks, dataObj, finder, delta); */ ln = 123; mess = g_strdup_printf(_("Displacement field match %d node(s)."), ln); visu_ui_rendering_window_popMessage(window); visu_ui_rendering_window_pushMessage(window, mess); g_free(mess); visu_gl_ext_setTranslation(VISU_GL_EXT(extGeodiff), delta); } static void onDropGeodiff(VisuInteractive *inter _U_, const gfloat delta[3], gpointer data) { gfloat trans[3]; gfloat delta0[3] = {0.f, 0.f, 0.f}; VisuNodeValues *vect; VisuPointset *dataObj; visu_gl_ext_setTranslation(VISU_GL_EXT(data), delta0); vect = visu_sourceable_getNodeModel(VISU_SOURCEABLE(data)); dataObj = VISU_POINTSET(visu_node_values_getArray(vect)); visu_pointset_getTranslation(dataObj, trans); delta0[0] = delta[0] + trans[0]; delta0[1] = delta[1] + trans[1]; delta0[2] = delta[2] + trans[2]; visu_pointset_setTranslation(dataObj, delta0, FALSE); g_object_unref(dataObj); } static void onCopyDiff(GtkButton *button, gpointer data _U_) { VisuData *dataObj; dataObj = visu_ui_panel_getData(VISU_UI_PANEL(panelGeometry)); g_object_ref(dataObj); g_object_set_data_full(G_OBJECT(button), "stored-geodiff", (gpointer)dataObj, (GDestroyNotify)g_object_unref); gtk_widget_set_sensitive(pasteGeodiff, TRUE); } static void onPasteDiff(GtkToggleButton *button, gpointer data) { VisuData *dataObj; VisuNodeFinder *finder; VisuGlExtGeodiff *extGeodiff; VisuInteractive *inter; VisuUiRenderingWindow *window; VisuGlExtMarks *marks; gfloat delta[3] = {0.f, 0.f, 0.f}; dataObj = g_object_get_data(G_OBJECT(data), "stored-geodiff"); g_return_if_fail(dataObj); extGeodiff = g_object_get_data(G_OBJECT(button), "ext-geodiff"); if (!extGeodiff) { extGeodiff = visu_gl_ext_geodiff_new(NULL); visu_gl_ext_set_add (VISU_GL_EXT_SET(visu_ui_rendering_window_getGlScene(visu_ui_main_class_getDefaultRendering())), VISU_GL_EXT(extGeodiff)); g_object_set_data_full(G_OBJECT(button), "ext-geodiff", extGeodiff, g_object_unref); } finder = g_object_get_data(G_OBJECT(button), "finder-geodiff"); if (!finder) { finder = visu_node_finder_new(visu_ui_panel_getData(VISU_UI_PANEL(panelGeometry))); g_object_set_data_full(G_OBJECT(button), "finder-geodiff", finder, g_object_unref); } inter = g_object_get_data(G_OBJECT(button), "inter-geodiff"); if (!inter) { inter = visu_interactive_new(interactive_drag); visu_interactive_setMessage(inter, _("Drag the displacement field.")); g_object_set_data_full(G_OBJECT(button), "inter-geodiff", inter, g_object_unref); g_signal_connect(G_OBJECT(inter), "move", G_CALLBACK(onDragGeodiff), (gpointer)button); g_signal_connect(G_OBJECT(inter), "stop-move", G_CALLBACK(onDropGeodiff), (gpointer)extGeodiff); } window = visu_ui_main_class_getDefaultRendering(); marks = visu_gl_node_scene_getMarks(visu_ui_rendering_window_getGlScene(window)); if (gtk_toggle_button_get_active(button)) { VisuNodeValues *vals = visu_data_getNodeProperties(dataObj, VISU_DATA_DIFF_DEFAULT_ID); visu_sourceable_setNodeModel(VISU_SOURCEABLE(extGeodiff), VISU_NODE_VALUES(vals)); visu_gl_ext_node_vectors_setNodeRenderer(VISU_GL_EXT_NODE_VECTORS(extGeodiff), VISU_NODE_ARRAY_RENDERER(visu_gl_node_scene_getNodes(visu_ui_rendering_window_getGlScene(window)))); visu_gl_ext_setActive(VISU_GL_EXT(extGeodiff), TRUE); visu_ui_rendering_window_pushInteractive(window, inter); highlightMatching(marks, dataObj, finder, delta); } else { visu_sourceable_setNodeModel(VISU_SOURCEABLE(extGeodiff), (VisuNodeValues*)0); visu_gl_ext_setActive(VISU_GL_EXT(extGeodiff), FALSE); visu_ui_rendering_window_popInteractive(window, inter); highlightMatching(marks, (VisuData*)0, finder, delta); } } static void onAddDiff(GtkButton *button _U_, gpointer data) { VisuGlExtNodeVectors *extGeodiff; VisuNodeFinder *finder; VisuDataDiff *geodiff; extGeodiff = g_object_get_data(G_OBJECT(data), "ext-geodiff"); geodiff = VISU_DATA_DIFF(visu_sourceable_getNodeModel(VISU_SOURCEABLE(extGeodiff))); finder = g_object_get_data(G_OBJECT(data), "finder-geodiff"); visu_data_diff_applyWithFinder(geodiff, finder, 1.f); gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON(data), FALSE); } static void onPathSaveToggled(GtkToggleButton *toggle, gpointer data _U_) { if (gtk_toggle_button_get_active(toggle)) visu_ui_panel_browser_setMessage(_("Recording paths"), GTK_MESSAGE_INFO); else visu_ui_panel_browser_setMessage((const gchar*)0, GTK_MESSAGE_INFO); } static void onDirBrowsed(VisuUiMain *obj _U_, VisuUiDirectoryType type, gpointer user _U_) { if (type == VISU_UI_DIR_BROWSER) gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON(togglePathSave), FALSE); } static void onSavePathClicked(GtkButton *bt _U_, gpointer data) { GtkWidget *wd; gint response; GError *error; gchar *base; wd = gtk_file_chooser_dialog_new(_("Export current set of paths."), (GtkWindow*)0, GTK_FILE_CHOOSER_ACTION_SAVE, TOOL_ICON_CANCEL, GTK_RESPONSE_CANCEL, TOOL_ICON_SAVE, GTK_RESPONSE_ACCEPT, NULL); if (!exportPathFile) exportPathFile = g_build_filename(g_get_current_dir(), _("paths.xml"), NULL); base = g_path_get_basename(exportPathFile); gtk_file_chooser_set_current_name(GTK_FILE_CHOOSER(wd), base); g_free(base); #if GTK_MAJOR_VERSION > 2 || GTK_MINOR_VERSION > 7 gtk_file_chooser_set_do_overwrite_confirmation(GTK_FILE_CHOOSER(wd), TRUE); #endif do { response = gtk_dialog_run(GTK_DIALOG(wd)); if (exportPathFile) g_free(exportPathFile); exportPathFile = gtk_file_chooser_get_filename(GTK_FILE_CHOOSER(wd)); switch (response) { case GTK_RESPONSE_ACCEPT: error = (GError*)0; if (!visu_gl_node_scene_exportPathsToXML(VISU_GL_NODE_SCENE(data), exportPathFile, &error)) { visu_ui_raiseWarning(_("Export current set of paths."), error->message, GTK_WINDOW(wd)); g_error_free(error); response = GTK_RESPONSE_NONE; } break; default: response = GTK_RESPONSE_ACCEPT; break; } } while (response != GTK_RESPONSE_ACCEPT); gtk_widget_destroy(wd); } static void onLoadPathClicked(GtkButton *bt _U_, gpointer data) { GtkWidget *wd; gint response; GError *error; const gchar *directory; wd = gtk_file_chooser_dialog_new(_("Load a set of paths."), (GtkWindow*)0, GTK_FILE_CHOOSER_ACTION_OPEN, TOOL_ICON_CANCEL, GTK_RESPONSE_CANCEL, TOOL_ICON_OPEN, GTK_RESPONSE_ACCEPT, NULL); directory = visu_ui_main_getLastOpenDirectory(visu_ui_main_class_getCurrentPanel()); if (directory) gtk_file_chooser_set_current_folder(GTK_FILE_CHOOSER(wd), directory); do { response = gtk_dialog_run(GTK_DIALOG(wd)); if (exportPathFile) g_free(exportPathFile); exportPathFile = gtk_file_chooser_get_filename(GTK_FILE_CHOOSER(wd)); switch (response) { case GTK_RESPONSE_ACCEPT: error = (GError*)0; if (!visu_gl_node_scene_parsePathsFromXML(VISU_GL_NODE_SCENE(data), exportPathFile, &error)) { visu_ui_raiseWarning(_("Load a set of paths."), error->message, GTK_WINDOW(wd)); g_error_free(error); response = GTK_RESPONSE_NONE; } break; default: response = GTK_RESPONSE_ACCEPT; break; } } while (response != GTK_RESPONSE_ACCEPT); gtk_widget_destroy(wd); } v_sim-3.8.0/src/panelModules/panelGeometry.h000066400000000000000000000036751370110300500210430ustar00rootroot00000000000000/* EXTRAITS DE LA LICENCE Copyright CEA, contributeurs : Luc BILLARD et Damien CALISTE, laboratoire L_Sim, (2001-2005) Adresse mèl : BILLARD, non joignable par mèl ; CALISTE, damien P caliste AT cea P fr. Ce logiciel est un programme informatique servant à visualiser des structures atomiques dans un rendu pseudo-3D. Ce logiciel est régi par la licence CeCILL soumise au droit français et respectant les principes de diffusion des logiciels libres. Vous pouvez utiliser, modifier et/ou redistribuer ce programme sous les conditions de la licence CeCILL telle que diffusée par le CEA, le CNRS et l'INRIA sur le site "http://www.cecill.info". Le fait que vous puissiez accéder à cet en-tête signifie que vous avez pris connaissance de la licence CeCILL, et que vous en avez accepté les termes (cf. le fichier Documentation/licence.fr.txt fourni avec ce logiciel). */ /* LICENCE SUM UP Copyright CEA, contributors : Luc BILLARD et Damien CALISTE, laboratoire L_Sim, (2001-2005) E-mail address: BILLARD, not reachable any more ; CALISTE, damien P caliste AT cea P fr. This software is a computer program whose purpose is to visualize atomic configurations in 3D. This software is governed by the CeCILL license under French law and abiding by the rules of distribution of free software. You can use, modify and/ or redistribute the software under the terms of the CeCILL license as circulated by CEA, CNRS and INRIA at the following URL "http://www.cecill.info". The fact that you are presently reading this means that you have had knowledge of the CeCILL license and that you accept its terms. You can find a copy of this licence shipped with this software at Documentation/licence.en.txt. */ #ifndef PANELGEOMETRY_H #define PANELGEOMETRY_H #include #include #include VisuUiPanel* visu_ui_panel_geometry_init(VisuUiMain *ui); #endif v_sim-3.8.0/src/panelModules/panelMap.c000066400000000000000000001072111370110300500177470ustar00rootroot00000000000000/* EXTRAITS DE LA LICENCE Copyright CEA, contributeurs : Luc BILLARD, Damien CALISTE, Olivier D'Astier, laboratoire L_Sim, (2001-2005) Adresses mèl : BILLARD, non joignable par mèl ; CALISTE, damien P caliste AT cea P fr. D'ASTIER, dastier AT iie P cnam P fr. Ce logiciel est un programme informatique servant à visualiser des structures atomiques dans un rendu pseudo-3D. Ce logiciel est régi par la licence CeCILL soumise au droit français et respectant les principes de diffusion des logiciels libres. Vous pouvez utiliser, modifier et/ou redistribuer ce programme sous les conditions de la licence CeCILL telle que diffusée par le CEA, le CNRS et l'INRIA sur le site "http://www.cecill.info". Le fait que vous puissiez accéder à cet en-tête signifie que vous avez pris connaissance de la licence CeCILL, et que vous en avez accepté les termes (cf. le fichier Documentation/licence.fr.txt fourni avec ce logiciel). */ /* LICENCE SUM UP Copyright CEA, contributors : Luc BILLARD and Damien CALISTE and Olivier D'Astier, laboratoire L_Sim, (2001-2005) E-mail addresses : BILLARD, not reachable any more ; CALISTE, damien P caliste AT cea P fr. D'ASTIER, dastier AT iie P cnam P fr. This software is a computer program whose purpose is to visualize atomic configurations in 3D. This software is governed by the CeCILL license under French law and abiding by the rules of distribution of free software. You can use, modify and/ or redistribute the software under the terms of the CeCILL license as circulated by CEA, CNRS and INRIA at the following URL "http://www.cecill.info". The fact that you are presently reading this means that you have had knowledge of the CeCILL license and that you accept its terms. You can find a copy of this licence shipped with this software at Documentation/licence.en.txt. */ #include "panelMap.h" #include "panelPlanes.h" #include "panelSurfaces.h" #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include /** * SECTION:panelMap * @short_description: The widget to create coloured map. * * This is the user interface for the coloured maps. For a * plane, a scalar field and a shade, it is possible to draw one * coloured plane. The available planes are taken from the #panelVisuPlane * subpanel and the scalar field for the #panelSurfaces. */ /* Local variables. */ static GtkWidget *panelMap; static GtkWidget *comboVisuPlane; static GtkWidget *comboField; static GtkWidget *comboMap; static GtkWidget *rdLinear, *rdLog, *rdZero; static GtkWidget *ckColour, *cbColour; static GtkWidget *removeButton, *buildButton, *exportButton; static GtkWidget *radioNormalized, *radioMinMax; static GtkWidget *entryDataMax, *entryDataMin; static gboolean isMapInitialised; static GtkWidget *warnLabel; static gulong comboMap_signal; /* String used to labelled planes, dist. means 'distance' and norm. means 'normal' (50 chars max). */ #define LABEL_PLANE _("plane (%2d;%2d;%2d - %4.1f)") enum { MAP_OBJ, MAP_SIG, MAP_N_COLUMNS }; static GtkListStore *maps; /* Local methods. */ static void createGtkInterface(VisuUiPanel *panel); static void updateInterface(gboolean selectFirst); /* Local callbacks. */ static void onMapAdded(GtkListStore *model, VisuMap *map); static void onMapRemoved(GtkListStore *model, VisuMap *map); static void onBuildClicked(GtkButton *button, gpointer data); static void onRemoveClicked(GtkButton *button, gpointer data); static void onExportClicked(GtkButton *button, gpointer data); static void onFieldChanged(GtkComboBox *combo, gpointer data); static void onToolShadeChanged(VisuUiShadeCombobox *combo, ToolShade *shade, gpointer data); static void onPlaneChanged(GtkComboBox *combo, gpointer data); static void onComboMapChanged(GtkComboBox *combo, gpointer data); static void onMapEnter(VisuUiPanel *map, gpointer data); static void onPlaneDeleted(GtkTreeModel *tree_model, GtkTreePath *path, gpointer user_data); static void onSourceField(VisuGlExtMapSet *mapSet, GParamSpec *pspec, gpointer data); static void onMapChanged(VisuMap *map, gpointer data); static void onMapAdded(GtkListStore *model, VisuMap *map) { GtkTreeIter iter; gulong sig; sig = g_signal_connect_object(G_OBJECT(map), "changed", G_CALLBACK(onMapChanged), (gpointer)model, 0); gtk_list_store_append(model, &iter); gtk_list_store_set(model, &iter, MAP_OBJ, map, MAP_SIG, sig, -1); gtk_combo_box_set_active_iter(GTK_COMBO_BOX(comboMap), &iter); /* We update the interface. */ DBG_fprintf(stderr, "Panel Map: update interface.\n"); updateInterface(FALSE); } static void onMapRemoved(GtkListStore *model, VisuMap *map) { gboolean valid; GtkTreeIter iter; VisuMap *map_; gulong sig; DBG_fprintf(stderr, "Panel Map: %p removed.\n", (gpointer)map); for (valid = gtk_tree_model_get_iter_first(GTK_TREE_MODEL(model), &iter); valid; valid = gtk_tree_model_iter_next(GTK_TREE_MODEL(model), &iter)) { /* We stop the listener on the move signal. */ gtk_tree_model_get(GTK_TREE_MODEL(maps), &iter, MAP_OBJ, &map_, MAP_SIG, &sig, -1); if (map == map_) { g_signal_handler_disconnect(G_OBJECT(map), sig); g_object_unref(G_OBJECT(map_)); gtk_list_store_remove(model, &iter); return; } g_object_unref(G_OBJECT(map_)); } } static void _planeColor(GtkCellLayout *layout _U_, GtkCellRenderer *cell, GtkTreeModel *model, GtkTreeIter *iter, gpointer data _U_) { VisuPlane *plane; GdkPixbuf *pix; gtk_tree_model_get(model, iter, VISU_UI_PANEL_PLANES_POINTER, &plane, -1); pix = tool_color_get_stamp(visu_plane_getColor(plane), TRUE); g_object_set(cell, "pixbuf", pix, NULL); g_object_unref(pix); g_object_unref(plane); } static void _planeDesc(GtkCellLayout *layout _U_, GtkCellRenderer *cell, GtkTreeModel *model, GtkTreeIter *iter, gpointer data _U_) { VisuPlane *plane; gchar str[256]; float vect[3]; gtk_tree_model_get(model, iter, VISU_UI_PANEL_PLANES_POINTER, &plane, -1); visu_plane_getNVectUser(plane, vect); sprintf(str, _("norm.: (%3d;%3d;%3d) dist.: %6.2f"), (int)vect[0], (int)vect[1], (int)vect[2], visu_plane_getDistanceFromOrigin(plane)); g_object_set(cell, "markup", str, NULL); g_object_unref(plane); } static gboolean scaleToRadio(GBinding *binding _U_, const GValue *source_value, GValue *target_value, gpointer user_data) { if ((guint)GPOINTER_TO_INT(user_data) != g_value_get_uint(source_value)) return FALSE; g_value_set_boolean(target_value, TRUE); return TRUE; } static gboolean radioToScale(GBinding *binding _U_, const GValue *source_value, GValue *target_value, gpointer user_data) { if (!g_value_get_boolean(source_value)) return FALSE; g_value_set_uint(target_value, GPOINTER_TO_INT(user_data)); return TRUE; } static gboolean colorToCk(GBinding *binding _U_, const GValue *source_value, GValue *target_value, gpointer user_data _U_) { g_value_set_boolean(target_value, (g_value_get_boxed(source_value) != (gpointer)0)); return TRUE; } static gboolean ckToColor(GBinding *binding _U_, const GValue *source_value, GValue *target_value, gpointer user_data) { ToolColor *color; if (g_value_get_boolean(source_value)) { g_object_get(G_OBJECT(user_data), "color", &color, NULL); g_return_val_if_fail(color, FALSE); g_value_take_boxed(target_value, color); } else g_value_set_boxed(target_value, (gconstpointer)0); return TRUE; } static gboolean colorToCombo(GBinding *binding _U_, const GValue *source_value, GValue *target_value, gpointer user_data _U_) { if (!g_value_get_boxed(source_value)) return FALSE; g_value_set_boxed(target_value, g_value_get_boxed(source_value)); return TRUE; } static gboolean comboToColor(GBinding *binding, const GValue *source_value, GValue *target_value, gpointer user_data _U_) { ToolColor *color = (ToolColor*)0; g_object_get(g_binding_get_source(binding), "line-color", &color, NULL); if (!color) return FALSE; g_boxed_free(TOOL_TYPE_COLOR, color); g_value_set_boxed(target_value, g_value_get_boxed(source_value)); return TRUE; } static gboolean activeToVisible(GBinding *binding _U_, const GValue *source_value, GValue *target_value, gpointer user_data _U_) { g_value_set_boolean(target_value, g_value_get_int(source_value) < 0); return TRUE; } static void displayPlane(GtkCellLayout *cell _U_, GtkCellRenderer *renderer, GtkTreeModel *model, GtkTreeIter *iter, gpointer data) { VisuMap *map; VisuPlane *plane; gchar str[256]; float vect[3], dist; gtk_tree_model_get(model, iter, MAP_OBJ, &map, -1); plane = visu_gl_ext_map_set_getPlane(VISU_GL_EXT_MAP_SET(data), map); g_object_unref(map); if (plane) { visu_plane_getNVectUser(plane, vect); dist = visu_plane_getDistanceFromOrigin(plane); sprintf(str, LABEL_PLANE, (int)vect[0], (int)vect[1], (int)vect[2], dist); g_object_set(renderer, "markup", str, NULL); } else g_object_set(renderer, "markup", _("not plane based"), NULL); } static void createGtkInterface(VisuUiPanel *panel) { GtkWidget *vbox, *hbox, *label, *combo, *wd; GtkListStore *list; GtkCellRenderer *renderer; ToolColor *color; float black[4] = {0.f, 0.f, 0.f, 1.f}; int pos; VisuGlExtMapsIter iter; VisuGlNodeScene *scene; VisuGlExtMapSet *extMaps; scene = visu_ui_rendering_window_getGlScene(visu_ui_main_class_getDefaultRendering()); extMaps = visu_gl_node_scene_addMaps(scene, (VisuGlExtShade**)0); /* We create the list of maps. */ maps = gtk_list_store_new(MAP_N_COLUMNS, VISU_TYPE_MAP, G_TYPE_ULONG); g_signal_connect_object(extMaps, "added", G_CALLBACK(onMapAdded), maps, G_CONNECT_SWAPPED); g_signal_connect_object(extMaps, "removed", G_CALLBACK(onMapRemoved), maps, G_CONNECT_SWAPPED); g_signal_connect_swapped(panel, "destroy", G_CALLBACK(g_object_unref), maps); vbox = gtk_vbox_new(FALSE, 0); gtk_widget_set_margin_start(vbox, 5); gtk_widget_set_margin_end(vbox, 5); gtk_container_add(GTK_CONTAINER(panel), vbox); hbox = gtk_hbox_new(FALSE, 0); gtk_box_pack_start(GTK_BOX(vbox), hbox, FALSE, FALSE, 3); label = gtk_label_new(_("Map sources")); gtk_label_set_use_markup(GTK_LABEL(label), TRUE); gtk_widget_set_name(label, "label_head"); gtk_label_set_xalign(GTK_LABEL(label), 0.); gtk_box_pack_start(GTK_BOX(hbox), label, FALSE, FALSE, 0); warnLabel = gtk_hbox_new(FALSE, 0); gtk_box_pack_end(GTK_BOX(hbox), warnLabel, FALSE, FALSE, 0); wd = gtk_image_new_from_icon_name("dialog-warning", GTK_ICON_SIZE_BUTTON); gtk_box_pack_start(GTK_BOX(warnLabel), wd, FALSE, FALSE, 0); label = gtk_label_new(_("missing elements")); gtk_label_set_use_markup(GTK_LABEL(label), TRUE); gtk_box_pack_start(GTK_BOX(warnLabel), label, FALSE, FALSE, 0); /* The plane selector. */ hbox = gtk_hbox_new(FALSE, 0); gtk_box_pack_start(GTK_BOX(vbox), hbox, FALSE, FALSE, 0); label = gtk_label_new(_("Cutting plane:")); gtk_widget_set_margin_start(label, 5); gtk_label_set_xalign(GTK_LABEL(label), 0.); gtk_box_pack_start(GTK_BOX(hbox), label, FALSE, FALSE, 0); label = gtk_label_new(_("" "Create elements in the 'planes' tab")); gtk_label_set_use_markup(GTK_LABEL(label), TRUE); gtk_widget_set_margin_start(label, 5); gtk_label_set_xalign(GTK_LABEL(label), 1.); gtk_box_pack_end(GTK_BOX(hbox), label, FALSE, FALSE, 0); hbox = gtk_hbox_new(FALSE, 5); gtk_widget_set_margin_bottom(hbox, 15); gtk_box_pack_start(GTK_BOX(vbox), hbox, FALSE, FALSE, 2); list = visu_ui_panel_planes_getList(); g_signal_connect_object(G_OBJECT(list), "row-deleted", G_CALLBACK(onPlaneDeleted), extMaps, 0); combo = gtk_combo_box_new_with_model(GTK_TREE_MODEL(list)); renderer = gtk_cell_renderer_pixbuf_new(); gtk_cell_layout_pack_start(GTK_CELL_LAYOUT(combo), renderer, FALSE); g_object_set(G_OBJECT(renderer), "xpad", 10, NULL); gtk_cell_layout_set_cell_data_func(GTK_CELL_LAYOUT(combo), renderer, _planeColor, (gpointer)0, (GDestroyNotify)0); renderer = gtk_cell_renderer_text_new(); gtk_cell_layout_pack_start(GTK_CELL_LAYOUT(combo), renderer, FALSE); g_object_set(G_OBJECT(renderer), "xalign", 1.0, NULL); gtk_cell_layout_set_cell_data_func(GTK_CELL_LAYOUT(combo), renderer, _planeDesc, (gpointer)0, (GDestroyNotify)0); gtk_box_pack_start(GTK_BOX(hbox), combo, TRUE, TRUE, 0); comboVisuPlane = combo; g_signal_connect_object(G_OBJECT(combo), "changed", G_CALLBACK(onPlaneChanged), extMaps, 0); wd = gtk_image_new_from_icon_name("dialog-warning", GTK_ICON_SIZE_BUTTON); gtk_widget_set_no_show_all(wd, TRUE); g_object_bind_property_full(comboVisuPlane, "active", wd, "visible", G_BINDING_SYNC_CREATE, activeToVisible, (GBindingTransformFunc)0, (gpointer)0, (GDestroyNotify)0); gtk_box_pack_end(GTK_BOX(hbox), wd, FALSE, FALSE, 0); /* The scalar field selector. */ hbox = gtk_hbox_new(FALSE, 0); gtk_box_pack_start(GTK_BOX(vbox), hbox, FALSE, FALSE, 0); label = gtk_label_new(_("Scalar field:")); gtk_widget_set_margin_start(label, 5); gtk_label_set_xalign(GTK_LABEL(label), 0.); gtk_box_pack_start(GTK_BOX(hbox), label, FALSE, FALSE, 0); label = gtk_label_new(_("" "Import fields in the 'isosurfaces' tab")); gtk_label_set_use_markup(GTK_LABEL(label), TRUE); gtk_widget_set_margin_start(label, 5); gtk_label_set_xalign(GTK_LABEL(label), 1.); gtk_box_pack_end(GTK_BOX(hbox), label, FALSE, FALSE, 0); hbox = gtk_hbox_new(FALSE, 5); gtk_widget_set_margin_bottom(hbox, 15); gtk_box_pack_start(GTK_BOX(vbox), hbox, FALSE, FALSE, 2); list = visu_ui_panel_surfaces_getFields(); combo = gtk_combo_box_new_with_model(GTK_TREE_MODEL(list)); renderer = gtk_cell_renderer_text_new(); gtk_cell_layout_pack_start(GTK_CELL_LAYOUT(combo), renderer, FALSE); g_object_set(G_OBJECT(renderer), "xalign", 1.0, NULL); gtk_cell_layout_add_attribute(GTK_CELL_LAYOUT(combo), renderer, "markup", VISU_UI_SURFACES_FIELD_LABEL); gtk_box_pack_start(GTK_BOX(hbox), combo, TRUE, TRUE, 0); comboField = combo; g_signal_connect_object(G_OBJECT(combo), "changed", G_CALLBACK(onFieldChanged), extMaps, 0); g_signal_connect_object(extMaps, "notify::field", G_CALLBACK(onSourceField), (gpointer)combo, 0); wd = gtk_image_new_from_icon_name("dialog-warning", GTK_ICON_SIZE_BUTTON); gtk_widget_set_no_show_all(wd, TRUE); g_object_bind_property_full(comboVisuPlane, "active", wd, "visible", G_BINDING_SYNC_CREATE, activeToVisible, (GBindingTransformFunc)0, (gpointer)0, (GDestroyNotify)0); gtk_box_pack_end(GTK_BOX(hbox), wd, FALSE, FALSE, 0); /* The shade selector. */ hbox = gtk_hbox_new(FALSE, 0); gtk_box_pack_start(GTK_BOX(vbox), hbox, FALSE, FALSE, 0); label = gtk_label_new(_("Shade:")); gtk_widget_set_margin_start(label, 5); gtk_label_set_xalign(GTK_LABEL(label), 0.); gtk_box_pack_start(GTK_BOX(hbox), label, FALSE, FALSE, 0); wd = gtk_check_button_new_with_mnemonic(_("with _transparency")); g_object_bind_property(extMaps, "transparent", wd, "active", G_BINDING_SYNC_CREATE | G_BINDING_BIDIRECTIONAL); gtk_box_pack_end(GTK_BOX(hbox), wd, FALSE, FALSE, 0); combo = visu_ui_shade_combobox_new(TRUE, TRUE); gtk_combo_box_set_active(GTK_COMBO_BOX(combo), -1); gtk_widget_set_margin_bottom(combo, 15); gtk_box_pack_start(GTK_BOX(vbox), combo, FALSE, FALSE, 2); g_object_bind_property(extMaps, "shade", combo, "shade", G_BINDING_SYNC_CREATE | G_BINDING_BIDIRECTIONAL); g_signal_connect(G_OBJECT(combo), "shade-selected", G_CALLBACK(onToolShadeChanged), (gpointer)0); /* ToolOptions. */ hbox = gtk_hbox_new(FALSE, 0); gtk_box_pack_start(GTK_BOX(vbox), hbox, FALSE, FALSE, 3); label = gtk_label_new(_("Options")); gtk_label_set_use_markup(GTK_LABEL(label), TRUE); gtk_widget_set_name(label, "label_head"); gtk_label_set_xalign(GTK_LABEL(label), 0.); gtk_box_pack_start(GTK_BOX(hbox), label, FALSE, FALSE, 0); label = gtk_label_new("%"); gtk_widget_set_margin_start(label, 5); gtk_box_pack_end(GTK_BOX(hbox), label, FALSE, FALSE, 0); wd = gtk_spin_button_new_with_range(0, 200, 5); gtk_entry_set_width_chars(GTK_ENTRY(wd), 3); gtk_spin_button_set_digits(GTK_SPIN_BUTTON(wd), 0); g_object_bind_property(extMaps, "precision", wd, "value", G_BINDING_SYNC_CREATE | G_BINDING_BIDIRECTIONAL); gtk_box_pack_end(GTK_BOX(hbox), wd, FALSE, FALSE, 0); label = gtk_label_new(_("Precision:")); gtk_label_set_xalign(GTK_LABEL(label), 0.); gtk_box_pack_end(GTK_BOX(hbox), label, FALSE, FALSE, 5); hbox = gtk_hbox_new(FALSE, 0); gtk_box_pack_start(GTK_BOX(vbox), hbox, FALSE, FALSE, 0); label = gtk_label_new(_("Scale:")); gtk_label_set_xalign(GTK_LABEL(label), 0.); gtk_box_pack_start(GTK_BOX(hbox), label, TRUE, TRUE, 5); rdLinear = gtk_radio_button_new_with_mnemonic((GSList*)0, _("_linear")); g_object_bind_property_full (extMaps, "scale", rdLinear, "active", G_BINDING_SYNC_CREATE | G_BINDING_BIDIRECTIONAL, scaleToRadio, radioToScale, GINT_TO_POINTER(TOOL_MATRIX_SCALING_LINEAR), (GDestroyNotify)0); gtk_box_pack_start(GTK_BOX(hbox), rdLinear, FALSE, FALSE, 0); rdLog = gtk_radio_button_new_with_mnemonic_from_widget(GTK_RADIO_BUTTON(rdLinear), _("lo_g.")); g_object_bind_property_full (extMaps, "scale", rdLog, "active", G_BINDING_SYNC_CREATE | G_BINDING_BIDIRECTIONAL, scaleToRadio, radioToScale, GINT_TO_POINTER(TOOL_MATRIX_SCALING_LOG), (GDestroyNotify)0); gtk_box_pack_start(GTK_BOX(hbox), rdLog, FALSE, FALSE, 0); rdZero = gtk_radio_button_new_with_mnemonic_from_widget(GTK_RADIO_BUTTON(rdLinear), _("_zero centred log.")); g_object_bind_property_full (extMaps, "scale", rdZero, "active", G_BINDING_SYNC_CREATE | G_BINDING_BIDIRECTIONAL, scaleToRadio, radioToScale, GINT_TO_POINTER(TOOL_MATRIX_SCALING_ZERO_CENTRED_LOG), (GDestroyNotify)0); gtk_box_pack_start(GTK_BOX(hbox), rdZero, FALSE, FALSE, 0); hbox = gtk_hbox_new(FALSE, 0); gtk_box_pack_start(GTK_BOX(vbox), hbox, FALSE, FALSE, 0); label = gtk_label_new(_("Number of isolines:")); gtk_label_set_xalign(GTK_LABEL(label), 0.); gtk_box_pack_start(GTK_BOX(hbox), label, FALSE, FALSE, 5); wd = gtk_spin_button_new_with_range(0, 20, 1); gtk_spin_button_set_digits(GTK_SPIN_BUTTON(wd), 0); gtk_entry_set_width_chars(GTK_ENTRY(wd), 2); g_object_bind_property(extMaps, "n-lines", wd, "value", G_BINDING_SYNC_CREATE | G_BINDING_BIDIRECTIONAL); gtk_box_pack_start(GTK_BOX(hbox), wd, FALSE, FALSE, 0); ckColour = gtk_check_button_new_with_mnemonic(_("_colour:")); gtk_box_pack_start(GTK_BOX(hbox), ckColour, TRUE, TRUE, 0); cbColour = visu_ui_color_combobox_new(FALSE); visu_ui_color_combobox_setPrintValues(VISU_UI_COLOR_COMBOBOX(cbColour), FALSE); color = tool_color_addFloatRGBA(black, &pos); visu_ui_color_combobox_setSelection(VISU_UI_COLOR_COMBOBOX(cbColour), color); g_object_bind_property_full (extMaps, "line-color", cbColour, "color", G_BINDING_SYNC_CREATE | G_BINDING_BIDIRECTIONAL, colorToCombo, comboToColor, (gpointer)0, (GDestroyNotify)0); g_object_bind_property_full (extMaps, "line-color", ckColour, "active", G_BINDING_SYNC_CREATE | G_BINDING_BIDIRECTIONAL, colorToCk, ckToColor, (gpointer)cbColour, (GDestroyNotify)0); gtk_box_pack_start(GTK_BOX(hbox), cbColour, FALSE, FALSE, 5); /* The normalisation. */ hbox = gtk_hbox_new (FALSE, 0); gtk_box_pack_start(GTK_BOX(vbox), hbox, FALSE, FALSE, 0); label = gtk_label_new(_("Normalise:")); gtk_box_pack_start(GTK_BOX(hbox), label, FALSE, FALSE, 5); radioNormalized = gtk_radio_button_new_with_mnemonic(NULL, _("auto")); g_object_bind_property(extMaps, "use-manual-range", radioNormalized, "active", G_BINDING_SYNC_CREATE | G_BINDING_BIDIRECTIONAL | G_BINDING_INVERT_BOOLEAN); gtk_box_pack_start(GTK_BOX(hbox), radioNormalized, FALSE, FALSE, 0); radioMinMax = gtk_radio_button_new_with_mnemonic_from_widget (GTK_RADIO_BUTTON(radioNormalized), _("manual")); g_object_bind_property(extMaps, "use-manual-range", radioMinMax, "active", G_BINDING_SYNC_CREATE | G_BINDING_BIDIRECTIONAL); gtk_box_pack_start(GTK_BOX(hbox), radioMinMax, FALSE, FALSE, 0); wd = gtk_hbox_new (FALSE, 0); g_object_bind_property(radioMinMax, "active", wd, "sensitive", G_BINDING_SYNC_CREATE); gtk_box_pack_end(GTK_BOX(hbox), wd, FALSE, FALSE, 0); label = gtk_label_new("["); gtk_label_set_xalign(GTK_LABEL(label), 1); gtk_box_pack_start(GTK_BOX(wd), label, TRUE, TRUE, 0); entryDataMin = visu_ui_numerical_entry_new(-1.); gtk_entry_set_width_chars(GTK_ENTRY(entryDataMin), 5); gtk_box_pack_start(GTK_BOX(wd), entryDataMin, FALSE, FALSE, 0); g_object_bind_property(extMaps, "manual-range-min", entryDataMin, "value", G_BINDING_SYNC_CREATE | G_BINDING_BIDIRECTIONAL); label = gtk_label_new(";"); gtk_label_set_xalign(GTK_LABEL(label), 1); gtk_box_pack_start(GTK_BOX(wd), label, FALSE, FALSE, 0); entryDataMax = visu_ui_numerical_entry_new(1.); gtk_entry_set_width_chars(GTK_ENTRY(entryDataMax), 5); gtk_box_pack_start(GTK_BOX(wd), entryDataMax, FALSE, FALSE, 0); g_object_bind_property(extMaps, "manual-range-max", entryDataMax, "value", G_BINDING_SYNC_CREATE | G_BINDING_BIDIRECTIONAL); label = gtk_label_new("]"); gtk_box_pack_start(GTK_BOX(wd), label, FALSE, FALSE, 0); /* The action buttons. */ hbox = gtk_hbox_new(FALSE, 0); gtk_box_pack_end(GTK_BOX(vbox), hbox, FALSE, FALSE, 5); wd = gtk_label_new(_("List of maps:")); gtk_box_pack_start(GTK_BOX(hbox), wd, FALSE, FALSE, 5); comboMap = gtk_combo_box_new_with_model(GTK_TREE_MODEL(maps)); gtk_widget_set_sensitive(comboMap, FALSE); renderer = gtk_cell_renderer_text_new(); gtk_cell_layout_pack_start(GTK_CELL_LAYOUT(comboMap), renderer, FALSE); gtk_cell_layout_set_cell_data_func(GTK_CELL_LAYOUT(comboMap), renderer, displayPlane, extMaps, (GDestroyNotify)0); gtk_box_pack_start(GTK_BOX(hbox), comboMap, TRUE, FALSE, 0); comboMap_signal = g_signal_connect_object(G_OBJECT(comboMap), "changed", G_CALLBACK(onComboMapChanged), extMaps, 0); buildButton = gtk_button_new(); wd = gtk_image_new_from_icon_name("list-add", GTK_ICON_SIZE_MENU); gtk_container_add(GTK_CONTAINER(buildButton), wd); gtk_box_pack_end(GTK_BOX(hbox), buildButton, FALSE, FALSE, 2); g_signal_connect_object(G_OBJECT(buildButton), "clicked", G_CALLBACK(onBuildClicked), extMaps, 0); removeButton = gtk_button_new(); wd = gtk_image_new_from_icon_name("list-remove", GTK_ICON_SIZE_MENU); gtk_container_add(GTK_CONTAINER(removeButton), wd); gtk_widget_set_sensitive(removeButton, FALSE); gtk_box_pack_end(GTK_BOX(hbox), removeButton, FALSE, FALSE, 2); g_signal_connect_object(G_OBJECT(removeButton), "clicked", G_CALLBACK(onRemoveClicked), extMaps, 0); exportButton = gtk_button_new(); wd = gtk_image_new_from_icon_name("document-save-as", GTK_ICON_SIZE_MENU); gtk_container_add(GTK_CONTAINER(exportButton), wd); gtk_widget_set_sensitive(exportButton, FALSE); gtk_box_pack_end(GTK_BOX(hbox), exportButton, FALSE, FALSE, 2); g_signal_connect_object(G_OBJECT(exportButton), "clicked", G_CALLBACK(onExportClicked), extMaps, 0); gtk_widget_show_all(vbox); gtk_widget_hide(warnLabel); isMapInitialised = TRUE; for (visu_gl_ext_maps_iter_new(VISU_GL_EXT_MAPS(extMaps), &iter); iter.valid; visu_gl_ext_maps_iter_next(&iter)) onMapAdded(maps, iter.map); onSourceField(extMaps, (GParamSpec*)0, comboField); } static void onMapChanged(VisuMap *map, gpointer data) { gboolean valid; GtkTreeIter iter; VisuMap *map_; GtkTreePath *path; for (valid = gtk_tree_model_get_iter_first(GTK_TREE_MODEL(data), &iter); valid; valid = gtk_tree_model_iter_next(GTK_TREE_MODEL(data), &iter)) { gtk_tree_model_get(GTK_TREE_MODEL(data), &iter, MAP_OBJ, &map_, -1); g_object_unref(G_OBJECT(map_)); if (map == map_) { path = gtk_tree_model_get_path(GTK_TREE_MODEL(data), &iter); gtk_tree_model_row_changed(GTK_TREE_MODEL(data), path, &iter); gtk_tree_path_free(path); return; } } } static void onBuildClicked(GtkButton *button _U_, gpointer data) { GtkTreeModel *model; GtkTreeIter iter; gboolean valid; VisuPlane *plane; /* We get the plane to listen to its signals. */ model = gtk_combo_box_get_model(GTK_COMBO_BOX(comboVisuPlane)); valid = gtk_combo_box_get_active_iter(GTK_COMBO_BOX(comboVisuPlane), &iter); if (!model || !valid) return; gtk_tree_model_get(model, &iter, VISU_UI_PANEL_PLANES_POINTER, &plane, -1); visu_gl_ext_map_set_addFromPlane(VISU_GL_EXT_MAP_SET(data), plane); g_object_unref(plane); } static void onToolShadeChanged(VisuUiShadeCombobox *combo _U_, ToolShade *shade _U_, gpointer data _U_) { gtk_widget_hide(warnLabel); } static void onFieldChanged(GtkComboBox *combo, gpointer data) { GtkTreeIter iter; VisuScalarField *field; gtk_widget_hide(warnLabel); if (!gtk_combo_box_get_active_iter(combo, &iter)) return; field = visu_ui_panel_surfaces_fieldsAt(gtk_combo_box_get_model(combo), &iter); visu_gl_ext_map_set_setField(VISU_GL_EXT_MAP_SET(data), field); g_object_unref(field); } static void onSourceField(VisuGlExtMapSet *mapSet, GParamSpec *pspec _U_, gpointer data) { GtkTreeModel *model; GtkTreeIter iter; gboolean valid; VisuScalarField *field, *field_; model = gtk_combo_box_get_model(GTK_COMBO_BOX(data)); if (!model) return; g_object_get(mapSet, "field", &field, NULL); if (!field) return; for (valid = gtk_tree_model_get_iter_first(model, &iter); valid; valid = gtk_tree_model_iter_next(model, &iter)) { field_ = visu_ui_panel_surfaces_fieldsAt(model, &iter); g_object_unref(field_); if (field == field_) { gtk_combo_box_set_active_iter(GTK_COMBO_BOX(data), &iter); break; } } g_object_unref(field); } static void onPlaneChanged(GtkComboBox *combo, gpointer data) { GtkTreeIter iter; VisuPlane *plane; VisuMap *map; gtk_widget_hide(warnLabel); if (!gtk_combo_box_get_active_iter(combo, &iter)) return; gtk_tree_model_get(gtk_combo_box_get_model(combo), &iter, VISU_UI_PANEL_PLANES_POINTER, &plane, -1); if (!gtk_combo_box_get_active_iter(GTK_COMBO_BOX(comboMap), &iter)) { g_object_unref(plane); return; } gtk_tree_model_get(GTK_TREE_MODEL(maps), &iter, MAP_OBJ, &map, -1); visu_gl_ext_map_set_setPlane(VISU_GL_EXT_MAP_SET(data), map, plane); g_object_unref(plane); g_object_unref(map); } static void onComboMapChanged(GtkComboBox *combo, gpointer data) { GtkTreeIter iter; gboolean valid; VisuMap *map; VisuPlane *plane, *tmpVisuPlane; GtkTreeModel *model; DBG_fprintf(stderr, "Panel Map: set map list to %d.\n", gtk_combo_box_get_active(combo)); valid = gtk_combo_box_get_active_iter(combo, &iter); if (!valid) return; gtk_tree_model_get(GTK_TREE_MODEL(maps), &iter, MAP_OBJ, &map, -1); plane = visu_gl_ext_map_set_getPlane(VISU_GL_EXT_MAP_SET(data), map); g_object_unref(map); visu_gl_ext_setActive(VISU_GL_EXT(data), FALSE); model = gtk_combo_box_get_model(GTK_COMBO_BOX(comboVisuPlane)); for (valid = gtk_tree_model_get_iter_first(model, &iter); valid; valid = gtk_tree_model_iter_next(model, &iter)) { gtk_tree_model_get(model, &iter, VISU_UI_PANEL_PLANES_POINTER, &tmpVisuPlane, -1); g_object_unref(G_OBJECT(tmpVisuPlane)); if (plane == tmpVisuPlane) { gtk_combo_box_set_active_iter(GTK_COMBO_BOX(comboVisuPlane), &iter); break; } } visu_gl_ext_setActive(VISU_GL_EXT(data), TRUE); } static void onPlaneDeleted(GtkTreeModel *tree_model, GtkTreePath *path _U_, gpointer user_data) { gboolean valid, valid2, found; GtkTreeIter iterMap, iterVisuPlane; VisuMap *map; VisuPlane *plane, *tmpVisuPlane; DBG_fprintf(stderr, "Panel Map: plane deleted.\n"); /* We try to find the plane in maps that is not existing anymore in planes. */ for (valid = gtk_tree_model_get_iter_first(GTK_TREE_MODEL(maps), &iterMap); valid; valid = gtk_tree_model_iter_next(GTK_TREE_MODEL(maps), &iterMap)) { gtk_tree_model_get(GTK_TREE_MODEL(maps), &iterMap, MAP_OBJ, &map, -1); tmpVisuPlane = visu_gl_ext_map_set_getPlane(VISU_GL_EXT_MAP_SET(user_data), map); found = FALSE; for (valid2 = gtk_tree_model_get_iter_first(tree_model, &iterVisuPlane); valid2 && !found && tmpVisuPlane; valid2 = gtk_tree_model_iter_next(tree_model, &iterVisuPlane)) { gtk_tree_model_get(tree_model, &iterVisuPlane, VISU_UI_PANEL_PLANES_POINTER, &plane, -1); g_object_unref(G_OBJECT(plane)); found = found || (plane == tmpVisuPlane); } if (!found && tmpVisuPlane) { DBG_fprintf(stderr, "Panel Map: removing map %p after plane %p deletion.\n", (gpointer)map, (gpointer)plane); visu_gl_ext_maps_remove(VISU_GL_EXT_MAPS(user_data), map); g_object_unref(G_OBJECT(map)); updateInterface(TRUE); break; } g_object_unref(G_OBJECT(map)); } } static void onRemoveClicked(GtkButton *button _U_, gpointer data) { gboolean valid; GtkTreeIter iter; VisuMap *map; /* We get the current map, if no, we do nothing. */ valid = gtk_combo_box_get_active_iter(GTK_COMBO_BOX(comboMap), &iter); if (!valid) return; gtk_tree_model_get(GTK_TREE_MODEL(maps), &iter, MAP_OBJ, &map, -1); visu_gl_ext_maps_remove(VISU_GL_EXT_MAPS(data), map); g_object_unref(map); updateInterface(TRUE); } static void updateInterface(gboolean selectFirst) { gboolean valid; /* Update the interface. */ valid = (gtk_tree_model_iter_n_children(GTK_TREE_MODEL(maps), (GtkTreeIter*)0) > 0); DBG_fprintf(stderr, "Panel Map: status of maps %d.\n", valid); gtk_widget_set_sensitive(removeButton, valid); gtk_widget_set_sensitive(exportButton, valid); gtk_widget_set_sensitive(comboMap, valid); if (valid && selectFirst) gtk_combo_box_set_active(GTK_COMBO_BOX(comboMap), 0); } static void onExportClicked(GtkButton *button _U_, gpointer data) { GtkWidget *dialog; gchar *name, *filename; const gchar *directory; GtkFileFilter *filterPDF, *filterSVG, *filter; VisuData *dataObj; VisuMapExportFormat format; gboolean valid; GError *error; GtkTreeIter iter; VisuMap *map; dialog = gtk_file_chooser_dialog_new (_("Export to SVG or PDF."), visu_ui_panel_getContainerWindow(VISU_UI_PANEL(panelMap)), GTK_FILE_CHOOSER_ACTION_SAVE, TOOL_ICON_CANCEL, GTK_RESPONSE_CANCEL, TOOL_ICON_SAVE, GTK_RESPONSE_ACCEPT, NULL); #if GTK_MAJOR_VERSION > 2 || GTK_MINOR_VERSION > 7 gtk_file_chooser_set_do_overwrite_confirmation(GTK_FILE_CHOOSER (dialog), TRUE); #endif filterPDF = filter = gtk_file_filter_new(); gtk_file_filter_set_name(filter, _("PDF document (*.pdf)")); gtk_file_filter_add_pattern(filter, "*.pdf"); gtk_file_chooser_add_filter(GTK_FILE_CHOOSER(dialog), filter); filterSVG = filter = gtk_file_filter_new(); gtk_file_filter_set_name(filter, _("SVG document (*.svg)")); gtk_file_filter_add_pattern(filter, "*.svg"); gtk_file_chooser_add_filter(GTK_FILE_CHOOSER(dialog), filter); /* We set the suggested filename, either a previous one or the one given. */ dataObj = visu_ui_panel_getData(VISU_UI_PANEL(panelMap)); directory = visu_ui_main_getLastOpenDirectory(visu_ui_main_class_getCurrentPanel()); if (directory) gtk_file_chooser_set_current_folder(GTK_FILE_CHOOSER(dialog), directory); filename = (gchar*)0; if (dataObj) filename = g_object_get_data(G_OBJECT(dataObj), "exportMap_filename"); if (!filename) filename = _("map.pdf"); gtk_file_chooser_set_current_name(GTK_FILE_CHOOSER(dialog), filename); if (gtk_dialog_run(GTK_DIALOG(dialog)) == GTK_RESPONSE_ACCEPT) { filename = gtk_file_chooser_get_filename(GTK_FILE_CHOOSER(dialog)); name = g_path_get_basename(filename); g_object_set_data_full(G_OBJECT(dataObj), "exportMap_filename", (gpointer)name, g_free); /* We detect the format. */ filter = gtk_file_chooser_get_filter(GTK_FILE_CHOOSER(dialog)); if (filter == filterPDF) format = VISU_MAP_EXPORT_PDF; else if (filter == filterSVG) format = VISU_MAP_EXPORT_SVG; else format = VISU_MAP_EXPORT_PDF; /* We get the data. */ valid = gtk_combo_box_get_active_iter(GTK_COMBO_BOX(comboMap), &iter); g_return_if_fail(valid); gtk_tree_model_get(GTK_TREE_MODEL(maps), &iter, MAP_OBJ, &map, -1); g_return_if_fail(map); /* We export. */ error = (GError*)0; if (!visu_gl_ext_map_set_export(VISU_GL_EXT_MAP_SET(data), map, filename, format, &error) && error) { visu_ui_raiseWarning(_("Export a coloured map"), error->message, GTK_WINDOW(dialog)); g_error_free(error); } g_object_unref(G_OBJECT(map)); g_free(filename); } gtk_widget_destroy(dialog); } static void onMapEnter(VisuUiPanel *map, gpointer data _U_) { DBG_fprintf(stderr, "Panel Map: caught the 'page-entered' signal %d.\n", isMapInitialised); if (!isMapInitialised) createGtkInterface(map); if (gtk_tree_model_iter_n_children (gtk_combo_box_get_model(GTK_COMBO_BOX(comboVisuPlane)), (GtkTreeIter*)0) > 0 && gtk_combo_box_get_active(GTK_COMBO_BOX(comboVisuPlane)) < 0) gtk_combo_box_set_active(GTK_COMBO_BOX(comboVisuPlane), 0); updateInterface(FALSE); } /** * visu_ui_panel_map_init: (skip) * * Should be used in the list declared in externalModules.h to be loaded by * V_Sim on start-up. This routine will create the #VisuUiPanel where * the coloured map stuff can be done, such as choosing a plane, * associating a scalar field... * * Returns: a newly created #VisuUiPanel object. */ VisuUiPanel* visu_ui_panel_map_init(VisuUiMain *ui _U_) { /* Long description */ char *cl = _("Map projections"); /* Short description */ char *tl = _("Maps"); panelMap = visu_ui_panel_newWithIconFromPath("Panel_map", cl, tl, "stock-map_20.png"); g_return_val_if_fail(panelMap, (VisuUiPanel*)0); isMapInitialised = FALSE; g_signal_connect(G_OBJECT(panelMap), "page-entered", G_CALLBACK(onMapEnter), (gpointer)0); visu_ui_panel_setDockable(VISU_UI_PANEL(panelMap), TRUE); return VISU_UI_PANEL(panelMap); } v_sim-3.8.0/src/panelModules/panelMap.h000066400000000000000000000037351370110300500177620ustar00rootroot00000000000000/* EXTRAITS DE LA LICENCE Copyright CEA, contributeurs : Luc BILLARD, Damien CALISTE, Olivier D'Astier, laboratoire L_Sim, (2001-2005) Adresses mèl : BILLARD, non joignable par mèl ; CALISTE, damien P caliste AT cea P fr. D'ASTIER, dastier AT iie P cnam P fr. Ce logiciel est un programme informatique servant à visualiser des structures atomiques dans un rendu pseudo-3D. Ce logiciel est régi par la licence CeCILL soumise au droit français et respectant les principes de diffusion des logiciels libres. Vous pouvez utiliser, modifier et/ou redistribuer ce programme sous les conditions de la licence CeCILL telle que diffusée par le CEA, le CNRS et l'INRIA sur le site "http://www.cecill.info". Le fait que vous puissiez accéder à cet en-tête signifie que vous avez pris connaissance de la licence CeCILL, et que vous en avez accepté les termes (cf. le fichier Documentation/licence.fr.txt fourni avec ce logiciel). */ /* LICENCE SUM UP Copyright CEA, contributors : Luc BILLARD and Damien CALISTE and Olivier D'Astier, laboratoire L_Sim, (2001-2005) E-mail addresses : BILLARD, not reachable any more ; CALISTE, damien P caliste AT cea P fr. D'ASTIER, dastier AT iie P cnam P fr. This software is a computer program whose purpose is to visualize atomic configurations in 3D. This software is governed by the CeCILL license under French law and abiding by the rules of distribution of free software. You can use, modify and/ or redistribute the software under the terms of the CeCILL license as circulated by CEA, CNRS and INRIA at the following URL "http://www.cecill.info". The fact that you are presently reading this means that you have had knowledge of the CeCILL license and that you accept its terms. You can find a copy of this licence shipped with this software at Documentation/licence.en.txt. */ #ifndef PANELMAP_H #define PANELMAP_H #include VisuUiPanel* visu_ui_panel_map_init(); #endif v_sim-3.8.0/src/panelModules/panelMethod.c000066400000000000000000000164751370110300500204650ustar00rootroot00000000000000/* EXTRAITS DE LA LICENCE Copyright CEA, contributeurs : Luc BILLARD et Damien CALISTE, laboratoire L_Sim, (2001-2005) Adresse mèl : BILLARD, non joignable par mèl ; CALISTE, damien P caliste AT cea P fr. Ce logiciel est un programme informatique servant à visualiser des structures atomiques dans un rendu pseudo-3D. Ce logiciel est régi par la licence CeCILL soumise au droit français et respectant les principes de diffusion des logiciels libres. Vous pouvez utiliser, modifier et/ou redistribuer ce programme sous les conditions de la licence CeCILL telle que diffusée par le CEA, le CNRS et l'INRIA sur le site "http://www.cecill.info". Le fait que vous puissiez accéder à cet en-tête signifie que vous avez pris connaissance de la licence CeCILL, et que vous en avez accepté les termes (cf. le fichier Documentation/licence.fr.txt fourni avec ce logiciel). */ /* LICENCE SUM UP Copyright CEA, contributors : Luc BILLARD et Damien CALISTE, laboratoire L_Sim, (2001-2005) E-mail address: BILLARD, not reachable any more ; CALISTE, damien P caliste AT cea P fr. This software is a computer program whose purpose is to visualize atomic configurations in 3D. This software is governed by the CeCILL license under French law and abiding by the rules of distribution of free software. You can use, modify and/ or redistribute the software under the terms of the CeCILL license as circulated by CEA, CNRS and INRIA at the following URL "http://www.cecill.info". The fact that you are presently reading this means that you have had knowledge of the CeCILL license and that you accept its terms. You can find a copy of this licence shipped with this software at Documentation/licence.en.txt. */ #include "panelMethod.h" #include #include #include #include #include #include #include "gtkAtomic.h" #include "gtkSpin.h" /** * SECTION: panelMethod * @short_description: The tab where drawing method is chosen (atomic * or spin). * * This tab has an area to display custom widgets according to * the selected rendering method, see visu_ui_panel_method_set(). */ /* Local variables. */ /* Store the toolpanel object, can be interesting to fetch the current visuData object for instance. */ static GtkWidget* panelMethod; /* A flag to control if the GTK part of the panel has been initialated or not. */ static gboolean isPanelInitialised; /* Widgets that can be accessed during the run. */ static GtkWidget *descrLabel; static GtkWidget *labelMethod; static GtkWidget *viewport; static GType currentMethod; /* Callbacks */ static void onMethodPanelEnter(VisuUiMain *ui); static void onDataNotified(VisuGlNodeScene *scene, GParamSpec *pspec, gpointer data); VisuUiPanel* visu_ui_panel_method_init(VisuUiMain *ui) { char *cl = _("Rendering method"); char *tl = _("Draw"); /* Now that everything has a value, we create the panel. */ panelMethod = visu_ui_panel_newWithIconFromPath("Panel_method", cl, tl, "stock-method_20.png"); if (!panelMethod) return (VisuUiPanel*)0; visu_ui_panel_setDockable(VISU_UI_PANEL(panelMethod), TRUE); /* Initialisation of loacl variables. */ isPanelInitialised = FALSE; currentMethod = 0; /* Set global callbacks. */ g_signal_connect_swapped(G_OBJECT(panelMethod), "page-entered", G_CALLBACK(onMethodPanelEnter), (gpointer)ui); return VISU_UI_PANEL(panelMethod); } static void onMethodPanelEnter(VisuUiMain *ui) { GtkWidget *label, *vbox, *scrollView, *hbox; VisuGlNodeScene *scene; /* On page enter, we just create the GTK objects if required. */ if (isPanelInitialised) return; vbox = gtk_vbox_new(FALSE, 0); hbox = gtk_hbox_new(FALSE, 0); gtk_box_pack_start(GTK_BOX(vbox), hbox, FALSE, FALSE, 2); label = gtk_label_new(_("Input method:")); gtk_label_set_xalign(GTK_LABEL(label), 0.); gtk_widget_set_margin_start(label, 5); gtk_widget_set_name(label, "label_head"); gtk_label_set_use_markup(GTK_LABEL(label), TRUE); gtk_box_pack_start(GTK_BOX(hbox), label, FALSE, FALSE, 0); labelMethod = gtk_label_new(""); gtk_box_pack_start(GTK_BOX(hbox), labelMethod, TRUE, TRUE, 0); descrLabel = gtk_label_new(""); gtk_widget_set_name(descrLabel, "label_info"); gtk_widget_set_margin_start(descrLabel, 15); gtk_box_pack_start(GTK_BOX(vbox), descrLabel, FALSE, FALSE, 2); gtk_label_set_use_markup(GTK_LABEL(descrLabel), TRUE); gtk_label_set_line_wrap(GTK_LABEL(descrLabel), TRUE); gtk_label_set_justify(GTK_LABEL(descrLabel), GTK_JUSTIFY_FILL); label = gtk_label_new(_("Options:")); gtk_label_set_xalign(GTK_LABEL(label), 0.); gtk_widget_set_margin_start(label, 5); gtk_widget_set_name(label, "label_head"); gtk_label_set_use_markup(GTK_LABEL(label), TRUE); gtk_box_pack_start(GTK_BOX(vbox), label, FALSE, FALSE, 0); scrollView = gtk_scrolled_window_new((GtkAdjustment*)0, (GtkAdjustment*)0); gtk_scrolled_window_set_policy(GTK_SCROLLED_WINDOW (scrollView), GTK_POLICY_NEVER, GTK_POLICY_AUTOMATIC); gtk_scrolled_window_set_shadow_type(GTK_SCROLLED_WINDOW (scrollView), GTK_SHADOW_NONE); gtk_box_pack_start(GTK_BOX(vbox), scrollView, TRUE, TRUE, 2); viewport = gtk_viewport_new (NULL, NULL); gtk_container_add(GTK_CONTAINER(scrollView), viewport); isPanelInitialised = TRUE; gtk_widget_show_all(vbox); scene = visu_ui_rendering_window_getGlScene(visu_ui_main_getRendering(ui)); g_signal_connect(G_OBJECT(scene), "notify::data", G_CALLBACK(onDataNotified), (gpointer)0); onDataNotified(scene, (GParamSpec*)0, (gpointer)0); gtk_container_add(GTK_CONTAINER(panelMethod), vbox); } static void onDataNotified(VisuGlNodeScene *scene, GParamSpec *pspec _U_, gpointer data _U_) { VisuData *dataObj; gchar *markup; GtkWidget *wd; GType type; dataObj = visu_gl_node_scene_getData(scene); type = dataObj ? G_OBJECT_TYPE(dataObj) : 0; if (type == currentMethod) return; currentMethod = type; /* Remove the current widget. */ wd = gtk_bin_get_child(GTK_BIN(viewport)); if (wd) gtk_widget_destroy(wd); if (VISU_IS_DATA_SPIN(dataObj)) { gtk_label_set_text(GTK_LABEL(labelMethod), _("Spin visualisation")); markup = g_markup_printf_escaped ("%s", _("It draws arrows at given positions to represent an atom " "and its spin.")); gtk_label_set_markup(GTK_LABEL(descrLabel), markup); g_free(markup); gtk_container_add(GTK_CONTAINER(viewport), visu_ui_panel_method_spin_create(scene)); } else if (VISU_IS_DATA_ATOMIC(dataObj)) { gtk_label_set_text(GTK_LABEL(labelMethod), _("Atom visualisation")); markup = g_markup_printf_escaped ("%s", _("It draws spheres at specified positions to represent atoms." " The radius of the sphere can vary.")); gtk_label_set_markup(GTK_LABEL(descrLabel), markup); g_free(markup); gtk_container_add(GTK_CONTAINER(viewport), visu_ui_panel_method_atomic_create(scene)); } else { gtk_label_set_text(GTK_LABEL(labelMethod), ""); gtk_label_set_markup(GTK_LABEL(descrLabel), ""); } gtk_widget_show_all(viewport); } v_sim-3.8.0/src/panelModules/panelMethod.h000066400000000000000000000043161370110300500204610ustar00rootroot00000000000000/* EXTRAITS DE LA LICENCE Copyright CEA, contributeurs : Luc BILLARD et Damien CALISTE, laboratoire L_Sim, (2001-2005) Adresse mèl : BILLARD, non joignable par mèl ; CALISTE, damien P caliste AT cea P fr. Ce logiciel est un programme informatique servant à visualiser des structures atomiques dans un rendu pseudo-3D. Ce logiciel est régi par la licence CeCILL soumise au droit français et respectant les principes de diffusion des logiciels libres. Vous pouvez utiliser, modifier et/ou redistribuer ce programme sous les conditions de la licence CeCILL telle que diffusée par le CEA, le CNRS et l'INRIA sur le site "http://www.cecill.info". Le fait que vous puissiez accéder à cet en-tête signifie que vous avez pris connaissance de la licence CeCILL, et que vous en avez accepté les termes (cf. le fichier Documentation/licence.fr.txt fourni avec ce logiciel). */ /* LICENCE SUM UP Copyright CEA, contributors : Luc BILLARD et Damien CALISTE, laboratoire L_Sim, (2001-2005) E-mail address: BILLARD, not reachable any more ; CALISTE, damien P caliste AT cea P fr. This software is a computer program whose purpose is to visualize atomic configurations in 3D. This software is governed by the CeCILL license under French law and abiding by the rules of distribution of free software. You can use, modify and/ or redistribute the software under the terms of the CeCILL license as circulated by CEA, CNRS and INRIA at the following URL "http://www.cecill.info". The fact that you are presently reading this means that you have had knowledge of the CeCILL license and that you accept its terms. You can find a copy of this licence shipped with this software at Documentation/licence.en.txt. */ #ifndef PANELMETHOD_H #define PANELMETHOD_H #include #include /** * visu_ui_panel_method_init: * * Should be used in the list declared in externalModules.h to be loaded by * V_Sim on start-up. This routine will create the #VisuUiPanel where the * stuff about a rendering method can be tuned, such as choosing the * current rendering method, its parameters... * * Returns: a newly created #VisuUiPanel object. */ VisuUiPanel* visu_ui_panel_method_init(); #endif v_sim-3.8.0/src/panelModules/panelOpenGL.c000066400000000000000000000676511370110300500203730ustar00rootroot00000000000000/* EXTRAITS DE LA LICENCE Copyright CEA, contributeurs : Luc BILLARD et Damien CALISTE, laboratoire L_Sim, (2001-2005) Adresse mèl : BILLARD, non joignable par mèl ; CALISTE, damien P caliste AT cea P fr. Ce logiciel est un programme informatique servant à visualiser des structures atomiques dans un rendu pseudo-3D. Ce logiciel est régi par la licence CeCILL soumise au droit français et respectant les principes de diffusion des logiciels libres. Vous pouvez utiliser, modifier et/ou redistribuer ce programme sous les conditions de la licence CeCILL telle que diffusée par le CEA, le CNRS et l'INRIA sur le site "http://www.cecill.info". Le fait que vous puissiez accéder à cet en-tête signifie que vous avez pris connaissance de la licence CeCILL, et que vous en avez accepté les termes (cf. le fichier Documentation/licence.fr.txt fourni avec ce logiciel). */ /* LICENCE SUM UP Copyright CEA, contributors : Luc BILLARD et Damien CALISTE, laboratoire L_Sim, (2001-2005) E-mail address: BILLARD, not reachable any more ; CALISTE, damien P caliste AT cea P fr. This software is a computer program whose purpose is to visualize atomic configurations in 3D. This software is governed by the CeCILL license under French law and abiding by the rules of distribution of free software. You can use, modify and/ or redistribute the software under the terms of the CeCILL license as circulated by CEA, CNRS and INRIA at the following URL "http://www.cecill.info". The fact that you are presently reading this means that you have had knowledge of the CeCILL license and that you accept its terms. You can find a copy of this licence shipped with this software at Documentation/licence.en.txt. */ #include "panelOpenGL.h" #include #include #include #include #include #include #include #include #include #include #include #include #include /** * SECTION: panelOpenGL * @short_description: The tab where OpenGL options like lights or * quality are setup. * * Nothing tunable here. */ static int disableCallbacksOpenGL; static GtkListStore *light_list_store; static GtkWidget *panelOpenGL; #if GTK_MAJOR_VERSION > 2 || GTK_MINOR_VERSION > 5 static GtkListStore *renderingListStore; #endif #define OPENGL_FOLLOW_GLOBAL_RENDERING_MODE _("Follow global setting") #define DEFAULT_GL VISU_GL(visu_ui_rendering_window_getGlScene(visu_ui_main_class_getDefaultRendering())) /* Private functions. */ static GtkWidget *createInteriorOpenGL(); /* Local callbacks. */ void addPresetOneLightClicked(GtkButton *button, gpointer data); void addPresetFourLightsClicked(GtkButton *button, gpointer data); static void selectionChanged(GtkTreeSelection *tree, gpointer data); static void addNewLightClicked(GtkButton *button, gpointer data); static void removeSelectedLightsClicked(GtkButton *button, gpointer data); #if GTK_MAJOR_VERSION > 2 || GTK_MINOR_VERSION > 5 static void renderingModeEdited(GtkCellRendererText *cellrenderertext, gchar *path, gchar *text, gpointer user_data); #endif static void onOpenGLEnter(VisuUiPanel *visu_ui_panel, gpointer data); VisuUiPanel* visu_ui_panel_gl_init(VisuUiMain *ui _U_) { char *cl = _("Set OpenGL parameters"); char *tl = _("OpenGL"); panelOpenGL = visu_ui_panel_newWithIconFromPath("Panel_opengl", cl, tl, "stock-opengl_20.png"); if (!panelOpenGL) return (VisuUiPanel*)0; gtk_container_add(GTK_CONTAINER(panelOpenGL), createInteriorOpenGL()); visu_ui_panel_setDockable(VISU_UI_PANEL(panelOpenGL), TRUE); /* Create the callbacks of all the sensitive widgets. */ g_signal_connect(G_OBJECT(panelOpenGL), "page-entered", G_CALLBACK(onOpenGLEnter), (gpointer)0); /* Private parameters. */ disableCallbacksOpenGL = 0; return VISU_UI_PANEL(panelOpenGL); } enum { LIGHT_POINTER_TO, LIGHT_ENABLED, LIGHT_POSITION0, LIGHT_POSITION1, LIGHT_POSITION2, LIGHT_MULTIPLIER, LIGHT_N_PARAMETERS }; enum { RENDERING_POINTER_TO, RENDERING_NAME, RENDERING_MODE, RENDERING_N_PARAMETERS }; void light_store_in_list_store(gpointer data, gpointer user_data) { VisuGlLight *light0 = data; GtkTreeIter iter; GtkListStore *list; g_return_if_fail(user_data); list = GTK_LIST_STORE(user_data); gtk_list_store_append(list, &iter); gtk_list_store_set(list, &iter, LIGHT_POINTER_TO, (gpointer)light0, LIGHT_ENABLED, light0->enabled, LIGHT_POSITION0, light0->position[0], LIGHT_POSITION1, light0->position[1], LIGHT_POSITION2, light0->position[2], LIGHT_MULTIPLIER, light0->multiplier, -1); } void light_tree_show_hide(GtkCellRendererToggle *cell_renderer, gchar *string_path, gpointer user_data) { GtkTreePath* path = gtk_tree_path_new_from_string(string_path); GtkTreeIter iter; gboolean status; VisuGlLight *light0; GtkListStore *list; g_return_if_fail(user_data); list = GTK_LIST_STORE(user_data); if(gtk_tree_model_get_iter(GTK_TREE_MODEL(light_list_store), &iter, path) == FALSE) return; status = gtk_cell_renderer_toggle_get_active(cell_renderer) ? FALSE : TRUE; gtk_list_store_set(list, &iter, LIGHT_ENABLED, status, -1); gtk_tree_model_get(GTK_TREE_MODEL(list), &iter, LIGHT_POINTER_TO, &light0, -1); light0->enabled = status; visu_gl_applyLights(DEFAULT_GL); } void light_update(GtkCellRendererText *cellrenderertext _U_, gchar *path, gchar *text, gpointer user_data) { GtkTreeIter iter; float new_value = atof(text); VisuGlLight *light0; if(gtk_tree_model_get_iter_from_string(GTK_TREE_MODEL(light_list_store), &iter, path)) { gtk_list_store_set(light_list_store, &iter, GPOINTER_TO_INT(user_data), new_value, -1); gtk_tree_model_get(GTK_TREE_MODEL(light_list_store), &iter, LIGHT_POINTER_TO, &light0, -1); } if (GPOINTER_TO_INT(user_data) == LIGHT_MULTIPLIER) light0->multiplier = new_value; else light0->position[GPOINTER_TO_INT(user_data)-LIGHT_POSITION0] = new_value; visu_gl_applyLights(DEFAULT_GL); } static void light_sync_lists(GtkListStore *list) { g_return_if_fail(list); gtk_list_store_clear(list); g_list_foreach(visu_gl_lights_getList(visu_gl_getLights(DEFAULT_GL)), light_store_in_list_store, (gpointer)list); } GtkWidget* lights_make_tree_view() { GtkTreeViewColumn* column; GtkCellRenderer *cell_show = gtk_cell_renderer_toggle_new(); GtkCellRenderer *cell_float; GtkWidget *light_tree_view; light_list_store = gtk_list_store_new(LIGHT_N_PARAMETERS, G_TYPE_POINTER, G_TYPE_BOOLEAN, G_TYPE_FLOAT, G_TYPE_FLOAT, G_TYPE_FLOAT, G_TYPE_FLOAT); light_tree_view = gtk_tree_view_new_with_model(GTK_TREE_MODEL(light_list_store)); light_sync_lists(light_list_store); g_signal_connect(cell_show, "toggled", G_CALLBACK(light_tree_show_hide), (gpointer)light_list_store); column = gtk_tree_view_column_new_with_attributes(_("Use"), cell_show, "active", LIGHT_ENABLED, NULL); gtk_tree_view_column_set_expand(column, FALSE); gtk_tree_view_column_set_alignment(column, 0.5); gtk_tree_view_append_column (GTK_TREE_VIEW (light_tree_view), column); cell_float = gtk_cell_renderer_text_new(); g_object_set(G_OBJECT(cell_float), "editable", TRUE, NULL); g_signal_connect(G_OBJECT(cell_float), "edited", G_CALLBACK(light_update), GINT_TO_POINTER(LIGHT_POSITION0)); column = gtk_tree_view_column_new_with_attributes(_("x"), cell_float, "text", LIGHT_POSITION0, NULL); gtk_tree_view_append_column (GTK_TREE_VIEW (light_tree_view), column); cell_float = gtk_cell_renderer_text_new(); g_object_set(G_OBJECT(cell_float), "editable", TRUE, NULL); g_signal_connect(G_OBJECT(cell_float), "edited", G_CALLBACK(light_update), GINT_TO_POINTER(LIGHT_POSITION1)); column = gtk_tree_view_column_new_with_attributes(_("y"), cell_float, "text", LIGHT_POSITION1, NULL); gtk_tree_view_append_column (GTK_TREE_VIEW (light_tree_view), column); cell_float = gtk_cell_renderer_text_new(); g_object_set(G_OBJECT(cell_float), "editable", TRUE, NULL); g_signal_connect(G_OBJECT(cell_float), "edited", G_CALLBACK(light_update), GINT_TO_POINTER(LIGHT_POSITION2)); column = gtk_tree_view_column_new_with_attributes(_("z"), cell_float, "text", LIGHT_POSITION2, NULL); gtk_tree_view_append_column (GTK_TREE_VIEW (light_tree_view), column); cell_float = gtk_cell_renderer_text_new(); g_object_set(G_OBJECT(cell_float), "editable", TRUE, NULL); g_signal_connect(G_OBJECT(cell_float), "edited", G_CALLBACK(light_update), GINT_TO_POINTER(LIGHT_MULTIPLIER)); column = gtk_tree_view_column_new_with_attributes(_("power"), cell_float, "text", LIGHT_MULTIPLIER, NULL); gtk_tree_view_append_column (GTK_TREE_VIEW (light_tree_view), column); gtk_tree_view_set_headers_visible (GTK_TREE_VIEW (light_tree_view), TRUE); gtk_tree_selection_set_mode(gtk_tree_view_get_selection(GTK_TREE_VIEW(light_tree_view)), GTK_SELECTION_MULTIPLE); return light_tree_view; } GtkWidget* make_renderingTreeView() { #if GTK_MAJOR_VERSION > 2 || GTK_MINOR_VERSION > 5 GtkTreeViewColumn* column; GtkCellRenderer *renderer; GtkWidget *renderingTreeView; GtkListStore *namesListStore; GtkTreeIter iter; const char** names; int i; GList *list, *all; VisuGlRenderingMode mode; gchar *label; const char *modeName; /* Initialize the model that store the possibilities for the cellRendererComboBox. */ namesListStore = gtk_list_store_new(1, G_TYPE_STRING); gtk_list_store_append(namesListStore, &iter); gtk_list_store_set(namesListStore, &iter, 0, OPENGL_FOLLOW_GLOBAL_RENDERING_MODE, -1); names = visu_gl_rendering_getAllModeLabels(); for (i = 0; names[i]; i++) { gtk_list_store_append(namesListStore, &iter); gtk_list_store_set(namesListStore, &iter, 0, names[i], -1); } /* Initialize the model that stores the extensions. */ renderingListStore = gtk_list_store_new(RENDERING_N_PARAMETERS, G_TYPE_POINTER, G_TYPE_STRING, G_TYPE_STRING); all = visu_gl_ext_set_getAll (VISU_GL_EXT_SET(visu_ui_rendering_window_getGlScene(visu_ui_main_class_getDefaultRendering()))); for (list = all; list; list = g_list_next(list)) { mode = visu_gl_ext_getPreferedRenderingMode(VISU_GL_EXT(list->data)); if (mode == VISU_GL_RENDERING_FOLLOW) modeName = OPENGL_FOLLOW_GLOBAL_RENDERING_MODE; else modeName = names[mode]; g_object_get(G_OBJECT(list->data), "label", &label, NULL); gtk_list_store_append(renderingListStore, &iter); gtk_list_store_set(renderingListStore, &iter, RENDERING_POINTER_TO, list->data, RENDERING_NAME, label, RENDERING_MODE, modeName, -1); g_free(label); } g_list_free(all); renderingTreeView = gtk_tree_view_new_with_model(GTK_TREE_MODEL(renderingListStore)); renderer = gtk_cell_renderer_text_new(); column = gtk_tree_view_column_new_with_attributes(_("name of extension"), renderer, "text", RENDERING_NAME, NULL); gtk_tree_view_column_set_alignment(column, 0.); gtk_tree_view_append_column(GTK_TREE_VIEW(renderingTreeView), column); renderer = gtk_cell_renderer_combo_new(); g_object_set(G_OBJECT(renderer), "has-entry", FALSE, "model", namesListStore, "text-column", 0, "editable", TRUE, NULL); g_signal_connect(G_OBJECT(renderer), "edited", G_CALLBACK(renderingModeEdited), (gpointer)renderingListStore); column = gtk_tree_view_column_new_with_attributes(_("mode"), renderer, "text", RENDERING_MODE, NULL); gtk_tree_view_column_set_expand(column, TRUE); gtk_tree_view_column_set_alignment(column, 0.5); gtk_tree_view_append_column(GTK_TREE_VIEW(renderingTreeView), column); g_object_unref(namesListStore); return renderingTreeView; #else return (GtkWidget*)0; #endif } void addNewLightClicked(GtkButton *button _U_, gpointer data) { VisuGlLight *light0; GtkTreeIter iter; gboolean status; g_return_if_fail(data); if (!visu_gl_lights_available(visu_gl_getLights(DEFAULT_GL))) { visu_ui_raiseWarning(_("OpenGL"), _("The maximm number of lights allowed by OpenGL" " has been reached, can't add more."), (GtkWindow*)0); return; } light0 = visu_gl_light_newDefault(); status = visu_gl_lights_add(visu_gl_getLights(DEFAULT_GL), light0); if (!status) return; gtk_list_store_append(GTK_LIST_STORE(data), &iter); gtk_list_store_set(GTK_LIST_STORE(data), &iter, LIGHT_POINTER_TO, (gpointer)light0, LIGHT_ENABLED, light0->enabled, LIGHT_POSITION0, light0->position[0], LIGHT_POSITION1, light0->position[1], LIGHT_POSITION2, light0->position[2], LIGHT_MULTIPLIER, light0->multiplier, -1); visu_gl_applyLights(DEFAULT_GL); } void removeSelectedLightsClicked(GtkButton *button _U_, gpointer data) { GList *tmpLst, *selectedRows; GtkTreeIter iter; gboolean validIter; VisuGlLight *light0; GtkTreeIter *removableIter; g_return_if_fail(GTK_TREE_SELECTION(data)); selectedRows = gtk_tree_selection_get_selected_rows(GTK_TREE_SELECTION(data), NULL); tmpLst = selectedRows; while (tmpLst) { validIter = gtk_tree_model_get_iter(GTK_TREE_MODEL(light_list_store), &iter, (GtkTreePath*)tmpLst->data); gtk_tree_path_free((GtkTreePath*)tmpLst->data); tmpLst->data = (gpointer)0; if (!validIter) g_warning("Wrong 'path' variable in 'removeSelectedLightsClicked' method.\n"); else { gtk_tree_model_get(GTK_TREE_MODEL(light_list_store), &iter, LIGHT_POINTER_TO, &light0, -1); visu_gl_lights_remove(visu_gl_getLights(DEFAULT_GL), light0); removableIter = g_malloc(sizeof(GtkTreeIter)); *removableIter = iter; tmpLst->data = (gpointer)removableIter; } tmpLst = g_list_next(tmpLst); } tmpLst = selectedRows; while (tmpLst) { if (tmpLst->data) { gtk_list_store_remove(light_list_store, (GtkTreeIter*)tmpLst->data); g_free(tmpLst->data); } tmpLst = g_list_next(tmpLst); } g_list_free(selectedRows); visu_gl_applyLights(DEFAULT_GL); } void selectionChanged(GtkTreeSelection *tree, gpointer data) { gint nb; g_return_if_fail(GTK_WIDGET(data)); nb = gtk_tree_selection_count_selected_rows(tree); if (nb == 0) gtk_widget_set_sensitive(GTK_WIDGET(data), FALSE); else gtk_widget_set_sensitive(GTK_WIDGET(data), TRUE); } static gboolean precToSpin(GBinding *binding _U_, const GValue *source_value, GValue *target_value, gpointer user_data _U_) { g_value_set_double(target_value, 100. * g_value_get_float(source_value)); return TRUE; } static gboolean precFromSpin(GBinding *binding _U_, const GValue *source_value, GValue *target_value, gpointer user_data _U_) { g_value_set_float(target_value, g_value_get_double(source_value) / 100.); return TRUE; } static GtkWidget *createInteriorOpenGL() { GtkWidget *vbox, *hbox; GtkWidget *label; GtkWidget *scrollLight; GtkWidget *button; GtkWidget *image; GtkWidget *scroll, *viewport; GtkWidget *expanderLight, *vbox2, *expand; GtkWidget *light_tree_view; GtkWidget *checkAntialiasing, *checkImmediateDrawing, *checkTransparency; GtkWidget *checkStereo, *spinStereoAngle, *comboOpenGLRendering, *spinPrecision; const char** names, **ids; int i; VisuGl *gl = DEFAULT_GL; VisuGlView *view; #if GTK_MAJOR_VERSION > 2 || GTK_MINOR_VERSION > 5 GtkWidget *scrollRendering, *expanderRendering, *renderingTreeView; #endif scroll = gtk_scrolled_window_new(NULL, NULL); gtk_scrolled_window_set_policy(GTK_SCROLLED_WINDOW(scroll), GTK_POLICY_AUTOMATIC, GTK_POLICY_AUTOMATIC); viewport = gtk_viewport_new(NULL, NULL); gtk_container_add(GTK_CONTAINER(scroll), viewport); vbox = gtk_vbox_new(FALSE, 0); gtk_container_add(GTK_CONTAINER(viewport), vbox); /*************************/ /* Rendering parameters. */ /*************************/ view = visu_gl_node_scene_getGlView(visu_ui_rendering_window_getGlScene(visu_ui_main_class_getDefaultRendering())); expand = gtk_expander_new(_("Rendering options:")); gtk_expander_set_expanded(GTK_EXPANDER(expand), TRUE); label = gtk_expander_get_label_widget(GTK_EXPANDER(expand)); gtk_label_set_use_markup(GTK_LABEL(label), TRUE); gtk_widget_set_name(label, "label_head"); gtk_box_pack_start(GTK_BOX(vbox), expand, FALSE, FALSE, 5); vbox2 = gtk_vbox_new(FALSE, 0); gtk_widget_set_margin_start(vbox2, 5); gtk_container_add(GTK_CONTAINER(expand), vbox2); hbox = gtk_hbox_new(FALSE, 0); gtk_box_pack_start(GTK_BOX(vbox2), hbox, FALSE, FALSE, 2); label = gtk_label_new(_("Precision:")); gtk_box_pack_start(GTK_BOX(hbox), label, FALSE, FALSE, 2); spinPrecision = gtk_spin_button_new_with_range(10, 500, 5); g_object_bind_property_full(view, "precision", spinPrecision, "value", G_BINDING_SYNC_CREATE | G_BINDING_BIDIRECTIONAL, precToSpin, precFromSpin, (gpointer)0, (GDestroyNotify)0); gtk_box_pack_start(GTK_BOX(hbox), spinPrecision, FALSE, FALSE, 2); label = gtk_label_new("%"); gtk_box_pack_start(GTK_BOX(hbox), label, FALSE, FALSE, 2); comboOpenGLRendering = gtk_combo_box_text_new(); names = visu_gl_rendering_getAllModeLabels(); ids = visu_gl_rendering_getAllModes(); if (names && ids) for (i = 0; names[i] && ids[i]; i++) gtk_combo_box_text_append(GTK_COMBO_BOX_TEXT(comboOpenGLRendering), ids[i], names[i]); else g_warning("No OpenGL rendering mode available."); g_object_bind_property(gl, "mode", comboOpenGLRendering, "active", G_BINDING_SYNC_CREATE | G_BINDING_BIDIRECTIONAL); gtk_box_pack_end(GTK_BOX(hbox), comboOpenGLRendering, FALSE, FALSE, 2); label = gtk_label_new(_("Mode:")); gtk_box_pack_end(GTK_BOX(hbox), label, FALSE, FALSE, 2); hbox = gtk_hbox_new(FALSE, 0); gtk_box_pack_start(GTK_BOX(vbox2), hbox, FALSE, FALSE, 2); label = gtk_label_new(_("Antialiase lines:")); gtk_box_pack_start(GTK_BOX(hbox), label, FALSE, FALSE, 2); checkAntialiasing = gtk_check_button_new(); g_object_bind_property(gl, "antialias", checkAntialiasing, "active", G_BINDING_SYNC_CREATE | G_BINDING_BIDIRECTIONAL); gtk_box_pack_start(GTK_BOX(hbox), checkAntialiasing, FALSE, FALSE, 2); checkTransparency = gtk_check_button_new(); g_object_bind_property(gl, "true-transparency", checkTransparency, "active", G_BINDING_SYNC_CREATE | G_BINDING_BIDIRECTIONAL); gtk_box_pack_end(GTK_BOX(hbox), checkTransparency, FALSE, FALSE, 2); label = gtk_label_new(_("Enhanced transparency:")); gtk_box_pack_end(GTK_BOX(hbox), label, FALSE, FALSE, 2); hbox = gtk_hbox_new(FALSE, 0); gtk_widget_set_sensitive(hbox, visu_gl_getStereoCapability(DEFAULT_GL)); gtk_box_pack_start(GTK_BOX(vbox2), hbox, FALSE, FALSE, 5); label = gtk_label_new(_("Use stereo rendering:")); gtk_box_pack_start(GTK_BOX(hbox), label, FALSE, FALSE, 2); checkStereo = gtk_check_button_new(); g_object_bind_property(gl, "stereo", checkStereo, "active", G_BINDING_SYNC_CREATE | G_BINDING_BIDIRECTIONAL); gtk_box_pack_start(GTK_BOX(hbox), checkStereo, FALSE, FALSE, 2); /* Degrees. */ label = gtk_label_new(_("deg.")); gtk_box_pack_end(GTK_BOX(hbox), label, FALSE, FALSE, 2); spinStereoAngle = gtk_spin_button_new_with_range(0.5,25.,0.1); g_object_bind_property(gl, "stereo-angle", spinStereoAngle, "value", G_BINDING_SYNC_CREATE | G_BINDING_BIDIRECTIONAL); gtk_box_pack_end(GTK_BOX(hbox), spinStereoAngle, FALSE, FALSE, 2); label = gtk_label_new(_("angle:")); gtk_box_pack_end(GTK_BOX(hbox), label, FALSE, FALSE, 1); /******************************/ /* Rendering mode parameters. */ /******************************/ #if GTK_MAJOR_VERSION > 2 || GTK_MINOR_VERSION > 5 expanderRendering = gtk_expander_new(_("Per extension rendering mode:")); label = gtk_expander_get_label_widget(GTK_EXPANDER(expanderRendering)); gtk_box_pack_start(GTK_BOX(vbox2), expanderRendering, TRUE, TRUE, 5); scrollRendering = gtk_scrolled_window_new(NULL, NULL); gtk_scrolled_window_set_policy(GTK_SCROLLED_WINDOW(scrollRendering), GTK_POLICY_AUTOMATIC, GTK_POLICY_AUTOMATIC); gtk_widget_set_size_request(scrollRendering, -1, 125); gtk_container_add(GTK_CONTAINER(expanderRendering), scrollRendering); renderingTreeView = make_renderingTreeView(); gtk_container_add(GTK_CONTAINER(scrollRendering), renderingTreeView); #endif /******************/ /* Other options. */ /******************/ hbox = gtk_hbox_new(FALSE, 0); label = gtk_label_new(_("Redraw immediately after changes:")); gtk_label_set_use_markup(GTK_LABEL(label), TRUE); gtk_widget_set_name(label, "label_head"); gtk_box_pack_start(GTK_BOX(hbox), label, FALSE, FALSE, 2); checkImmediateDrawing = gtk_check_button_new(); g_object_bind_property(gl, "immediate", checkImmediateDrawing, "active", G_BINDING_SYNC_CREATE | G_BINDING_BIDIRECTIONAL); gtk_box_pack_start(GTK_BOX(hbox), checkImmediateDrawing, FALSE, FALSE, 2); gtk_widget_show(checkImmediateDrawing); gtk_box_pack_start(GTK_BOX(vbox), hbox, FALSE, FALSE, 5); /*********************/ /* VisuGlLight parameters. */ /*********************/ expanderLight = gtk_expander_new(_("Light sources:")); label = gtk_expander_get_label_widget(GTK_EXPANDER(expanderLight)); gtk_label_set_use_markup(GTK_LABEL(label), TRUE); gtk_widget_set_name(label, "label_head"); gtk_box_pack_start(GTK_BOX(vbox), expanderLight, FALSE, FALSE, 5); hbox = gtk_hbox_new(FALSE, 0); gtk_container_add(GTK_CONTAINER(expanderLight), hbox); scrollLight = gtk_scrolled_window_new (NULL, NULL); gtk_scrolled_window_set_policy(GTK_SCROLLED_WINDOW(scrollLight), GTK_POLICY_AUTOMATIC, GTK_POLICY_AUTOMATIC); gtk_box_pack_start(GTK_BOX(hbox), scrollLight, TRUE, TRUE, 0); light_tree_view = lights_make_tree_view(); gtk_container_add(GTK_CONTAINER(scrollLight), light_tree_view); vbox2 = gtk_vbox_new(FALSE, 0); gtk_box_pack_start(GTK_BOX(hbox), vbox2, FALSE, FALSE, 0); button = gtk_button_new(); image = gtk_image_new_from_icon_name("list-add", GTK_ICON_SIZE_BUTTON); gtk_container_add(GTK_CONTAINER(button), image); g_signal_connect(G_OBJECT(button), "clicked", G_CALLBACK(addNewLightClicked), (gpointer)gtk_tree_view_get_model(GTK_TREE_VIEW(light_tree_view))); gtk_box_pack_start(GTK_BOX(vbox2), button, FALSE, FALSE, 1); button = gtk_button_new(); gtk_widget_set_sensitive(button, FALSE); image = gtk_image_new_from_icon_name("list-remove", GTK_ICON_SIZE_BUTTON); gtk_container_add(GTK_CONTAINER(button), image); g_signal_connect(G_OBJECT(button), "clicked", G_CALLBACK(removeSelectedLightsClicked), (gpointer)gtk_tree_view_get_selection(GTK_TREE_VIEW(light_tree_view))); gtk_box_pack_start(GTK_BOX(vbox2), button, FALSE, FALSE, 1); g_signal_connect(G_OBJECT(gtk_tree_view_get_selection(GTK_TREE_VIEW(light_tree_view))), "changed", G_CALLBACK(selectionChanged), (gpointer)button); button = gtk_button_new(); image = create_pixmap((GtkWidget*)0, "stock-one-light_20.png"); gtk_container_add(GTK_CONTAINER(button), image); g_signal_connect(G_OBJECT(button), "clicked", G_CALLBACK(addPresetOneLightClicked), (gpointer)gtk_tree_view_get_model(GTK_TREE_VIEW(light_tree_view))); gtk_box_pack_end(GTK_BOX(vbox2), button, FALSE, FALSE, 1); button = gtk_button_new(); image = create_pixmap((GtkWidget*)0, "stock-four-lights_20.png"); gtk_container_add(GTK_CONTAINER(button), image); g_signal_connect(G_OBJECT(button), "clicked", G_CALLBACK(addPresetFourLightsClicked), (gpointer)gtk_tree_view_get_model(GTK_TREE_VIEW(light_tree_view))); gtk_box_pack_end(GTK_BOX(vbox2), button, FALSE, FALSE, 1); gtk_widget_show_all(scroll); return scroll; } /*************/ /* Callbacks */ /*************/ static void onOpenGLEnter(VisuUiPanel *visu_ui_panel _U_, gpointer data _U_) { #if GTK_MAJOR_VERSION > 2 || GTK_MINOR_VERSION > 5 const gchar **names; gchar *name; GtkTreeIter iter; gboolean valid; VisuGlExt *ext; VisuGlRenderingMode mode; #endif disableCallbacksOpenGL = 1; #if GTK_MAJOR_VERSION > 2 || GTK_MINOR_VERSION > 5 names = visu_gl_rendering_getAllModeLabels(); valid = gtk_tree_model_get_iter_first(GTK_TREE_MODEL(renderingListStore), &iter); while(valid) { gtk_tree_model_get(GTK_TREE_MODEL(renderingListStore), &iter, RENDERING_POINTER_TO, &ext, RENDERING_MODE, &name, -1); mode = visu_gl_ext_getPreferedRenderingMode(ext); if (mode < VISU_GL_RENDERING_N_MODES && strcmp(names[mode], name)) gtk_list_store_set(renderingListStore, &iter, RENDERING_MODE, names[mode], -1); else if (mode == VISU_GL_RENDERING_FOLLOW && strcmp(OPENGL_FOLLOW_GLOBAL_RENDERING_MODE, name)) gtk_list_store_set(renderingListStore, &iter, RENDERING_MODE, OPENGL_FOLLOW_GLOBAL_RENDERING_MODE, -1); g_free(name); valid = gtk_tree_model_iter_next(GTK_TREE_MODEL(renderingListStore), &iter); } #endif disableCallbacksOpenGL = 0; } void addPresetOneLightClicked(GtkButton *button _U_, gpointer data) { VisuGlLight *light; gboolean status; g_return_if_fail(data); status = visu_gl_lights_removeAll(visu_gl_getLights(DEFAULT_GL)); light = visu_gl_light_newDefault(); status = visu_gl_lights_add(visu_gl_getLights(DEFAULT_GL), light) || status; light_sync_lists(GTK_LIST_STORE(data)); visu_gl_applyLights(DEFAULT_GL); } void addPresetFourLightsClicked(GtkButton *button _U_, gpointer data) { VisuGlLight *light; gboolean status; g_return_if_fail(data); status = visu_gl_lights_removeAll(visu_gl_getLights(DEFAULT_GL)); light = visu_gl_light_newDefault(); light->multiplier = 0.25; status = visu_gl_lights_add(visu_gl_getLights(DEFAULT_GL), light) || status; light = visu_gl_light_newDefault(); light->position[0] *= -1.; light->multiplier = 0.25; status = visu_gl_lights_add(visu_gl_getLights(DEFAULT_GL), light) || status; light = visu_gl_light_newDefault(); light->position[1] *= -1.; light->multiplier = 0.25; status = visu_gl_lights_add(visu_gl_getLights(DEFAULT_GL), light) || status; light = visu_gl_light_newDefault(); light->position[0] *= -1.; light->position[1] *= -1.; light->multiplier = 0.25; status = visu_gl_lights_add(visu_gl_getLights(DEFAULT_GL), light) || status; light_sync_lists(GTK_LIST_STORE(data)); visu_gl_applyLights(DEFAULT_GL); } #if GTK_MAJOR_VERSION > 2 || GTK_MINOR_VERSION > 5 static void renderingModeEdited(GtkCellRendererText *cellrenderertext _U_, gchar *path, gchar *text, gpointer user_data) { GtkListStore *list; gboolean valid; GtkTreeIter iter; const char** names; int mode; VisuGlExt *ext; if (disableCallbacksOpenGL) return; list = GTK_LIST_STORE(user_data); g_return_if_fail(list); valid = gtk_tree_model_get_iter_from_string(GTK_TREE_MODEL(list), &iter, path); g_return_if_fail(valid); if (!strcmp(text, OPENGL_FOLLOW_GLOBAL_RENDERING_MODE)) { valid = TRUE; mode = VISU_GL_RENDERING_FOLLOW; } else { valid = FALSE; names = visu_gl_rendering_getAllModeLabels(); for (mode = 0; names[mode] && !valid; mode++) valid = !strcmp(text, names[mode]); mode -= 1; } g_return_if_fail(valid); gtk_tree_model_get(GTK_TREE_MODEL(list), &iter, RENDERING_POINTER_TO, &ext, -1); valid = visu_gl_ext_setPreferedRenderingMode(ext, mode); if (mode == VISU_GL_RENDERING_FOLLOW) gtk_list_store_set(list, &iter, RENDERING_MODE, OPENGL_FOLLOW_GLOBAL_RENDERING_MODE, -1); else { names = visu_gl_rendering_getAllModeLabels(); gtk_list_store_set(list, &iter, RENDERING_MODE, names[mode], -1); } } #endif v_sim-3.8.0/src/panelModules/panelOpenGL.h000066400000000000000000000042451370110300500203660ustar00rootroot00000000000000/* EXTRAITS DE LA LICENCE Copyright CEA, contributeurs : Luc BILLARD et Damien CALISTE, laboratoire L_Sim, (2001-2005) Adresse mèl : BILLARD, non joignable par mèl ; CALISTE, damien P caliste AT cea P fr. Ce logiciel est un programme informatique servant à visualiser des structures atomiques dans un rendu pseudo-3D. Ce logiciel est régi par la licence CeCILL soumise au droit français et respectant les principes de diffusion des logiciels libres. Vous pouvez utiliser, modifier et/ou redistribuer ce programme sous les conditions de la licence CeCILL telle que diffusée par le CEA, le CNRS et l'INRIA sur le site "http://www.cecill.info". Le fait que vous puissiez accéder à cet en-tête signifie que vous avez pris connaissance de la licence CeCILL, et que vous en avez accepté les termes (cf. le fichier Documentation/licence.fr.txt fourni avec ce logiciel). */ /* LICENCE SUM UP Copyright CEA, contributors : Luc BILLARD et Damien CALISTE, laboratoire L_Sim, (2001-2005) E-mail address: BILLARD, not reachable any more ; CALISTE, damien P caliste AT cea P fr. This software is a computer program whose purpose is to visualize atomic configurations in 3D. This software is governed by the CeCILL license under French law and abiding by the rules of distribution of free software. You can use, modify and/ or redistribute the software under the terms of the CeCILL license as circulated by CEA, CNRS and INRIA at the following URL "http://www.cecill.info". The fact that you are presently reading this means that you have had knowledge of the CeCILL license and that you accept its terms. You can find a copy of this licence shipped with this software at Documentation/licence.en.txt. */ #ifndef PANELOPENGL_H #define PANELOPENGL_H #include /** * visu_ui_panel_gl_init: * * Should be used in the list declared in externalModules.h to be loaded by * V_Sim on start-up. This routine will create the #VisuUiPanel where the OpenGL * stuff can be tuned, such as antialise lines, drawing precision... * * Returns: a newly created #VisuUiPanel object. */ VisuUiPanel* visu_ui_panel_gl_init(); #endif v_sim-3.8.0/src/panelModules/panelPlanes.c000066400000000000000000000347671370110300500204730ustar00rootroot00000000000000/* EXTRAITS DE LA LICENCE Copyright CEA, contributeurs : Luc BILLARD et Damien CALISTE, laboratoire L_Sim, (2001-2005) Adresse mèl : BILLARD, non joignable par mèl ; CALISTE, damien P caliste AT cea P fr. Ce logiciel est un programme informatique servant à visualiser des structures atomiques dans un rendu pseudo-3D. Ce logiciel est régi par la licence CeCILL soumise au droit français et respectant les principes de diffusion des logiciels libres. Vous pouvez utiliser, modifier et/ou redistribuer ce programme sous les conditions de la licence CeCILL telle que diffusée par le CEA, le CNRS et l'INRIA sur le site "http://www.cecill.info". Le fait que vous puissiez accéder à cet en-tête signifie que vous avez pris connaissance de la licence CeCILL, et que vous en avez accepté les termes (cf. le fichier Documentation/licence.fr.txt fourni avec ce logiciel). */ /* LICENCE SUM UP Copyright CEA, contributors : Luc BILLARD et Damien CALISTE, laboratoire L_Sim, (2001-2005) E-mail address: BILLARD, not reachable any more ; CALISTE, damien P caliste AT cea P fr. This software is a computer program whose purpose is to visualize atomic configurations in 3D. This software is governed by the CeCILL license under French law and abiding by the rules of distribution of free software. You can use, modify and/ or redistribute the software under the terms of the CeCILL license as circulated by CEA, CNRS and INRIA at the following URL "http://www.cecill.info". The fact that you are presently reading this means that you have had knowledge of the CeCILL license and that you accept its terms. You can find a copy of this licence shipped with this software at Documentation/licence.en.txt. */ #include "panelPlanes.h" #include #include #include #include #include #include #include #include #include #include #include #include #include /** * SECTION: panelPlanes * @short_description: The tab where planes are defined. * * It is possible to get the list of planes using * visu_ui_panel_planes_getModel(). One can also access to the list * store hosting the planes by calling visu_ui_panel_planes_getList(). */ #define PANEL_PLANES_NO_VISU_PLANE_LIST _("none") static GtkWidget *panelPlanes; static GtkWidget *vBoxVisuPlanes; static GtkWidget *checkUseVisuPlanes; static GtkWidget *entryDistFrom, *entryDistTo, *entryDistStep, *spinDistDelay; static GtkWidget *imageDistPlay, *imageDistStop; static GtkWidget *valueIO; static guint isPlayingDistanceId; static gdouble directionDist; /* Local callbacks. */ static void onSetCameraPosition(VisuUiPlaneList *list, VisuPlane *plane, gpointer data); static void onPlayStopDist(GtkButton *button, gpointer data); static void onSpinDistDelayChange(GtkSpinButton *spin, gpointer data); static void onVisuPlanesEnter(VisuUiPanel *ui, VisuGlExtPlanes *planes); /* Local methods. */ static void stopPlayStop(gpointer data); static gboolean playDistances(gpointer data); /* Call createInteriorVisuPlanes() to create all the widgets, and if dataObj is not null, it set callbacks as if a new VisuData has been loaded. */ static void createInteriorVisuPlanes(VisuGlExtPlanes *planes); static gboolean callbackOpen(const gchar* filename, GError **error); static gboolean callbackSave(const gchar* filename, GError **error); static gboolean isVisuPlanesInitialised; static VisuUiPlaneList *store; /** * visu_ui_panel_planes_init: (skip) * * Should be used in the list declared in externalModules.h to be loaded by * V_Sim on start-up. This routine will create the #VisuUiPanel where the plane * stuff can be done, such as creating a plane, masking nodes, * changing the orientation or the colour... * * Returns: a newly created #VisuUiPanel object. */ VisuUiPanel* visu_ui_panel_planes_init(VisuUiMain *ui) { /* Long description */ char *cl = _("Drawing planes"); /* Short description */ char *tl = _("Planes"); VisuGlNodeScene *scene; VisuGlExtPlanes *planes; panelPlanes = visu_ui_panel_newWithIconFromPath("Panel_planes", cl, tl, "stock-planes_20.png"); if (!panelPlanes) return (VisuUiPanel*)0; visu_ui_panel_setDockable(VISU_UI_PANEL(panelPlanes), TRUE); scene = visu_ui_rendering_window_getGlScene(visu_ui_main_getRendering(ui)); vBoxVisuPlanes = gtk_vbox_new (FALSE, 2); g_object_bind_property(scene, "data", vBoxVisuPlanes, "sensitive", G_BINDING_SYNC_CREATE); isVisuPlanesInitialised = FALSE; checkUseVisuPlanes = (GtkWidget*)0; store = visu_ui_plane_list_new(); planes = visu_gl_node_scene_addPlanes(scene); visu_ui_plane_list_setModel(store, planes->planes); g_signal_connect(G_OBJECT(store), "align", G_CALLBACK(onSetCameraPosition), (gpointer)0); isPlayingDistanceId = 0; valueIO = visu_ui_value_io_new(visu_ui_panel_getContainerWindow(VISU_UI_PANEL(panelPlanes)), _("Import planes from an existing XML file."), _("Export planes to the current XML file."), _("Export planes to a new XML file.")); visu_ui_value_io_connectOnOpen(VISU_UI_VALUE_IO(valueIO), callbackOpen); visu_ui_value_io_setSensitiveOpen(VISU_UI_VALUE_IO(valueIO), TRUE); visu_ui_value_io_connectOnSave(VISU_UI_VALUE_IO(valueIO), callbackSave); g_object_bind_property(planes->planes, "n-planes", valueIO, "sensitive-save", G_BINDING_SYNC_CREATE); /* Add the signal for the vBoxVisuPlanes. */ g_signal_connect(G_OBJECT(panelPlanes), "page-entered", G_CALLBACK(onVisuPlanesEnter), planes); g_signal_connect_swapped(G_OBJECT(panelPlanes), "destroy", G_CALLBACK(g_object_unref), store); return VISU_UI_PANEL(panelPlanes); } /** * visu_ui_panel_planes_getList: * * This method gives read access to the #GtkListStore used to store * the planes. * * Returns: (transfer none): the #GtkListStore used by this panel to * store its planes. It should be considered read-only. */ GtkListStore* visu_ui_panel_planes_getList() { return GTK_LIST_STORE(store); } static void onVisuPlanesEnter(VisuUiPanel *ui _U_, VisuGlExtPlanes *planes) { DBG_fprintf(stderr, "Panel VisuPlanes: caught the 'page-entered' signal %d.\n", isVisuPlanesInitialised); if (!isVisuPlanesInitialised) { createInteriorVisuPlanes(planes); isVisuPlanesInitialised = TRUE; } } static void createInteriorVisuPlanes(VisuGlExtPlanes *planes) { GtkWidget *hbox; GtkWidget *label; GtkWidget *vbox; GtkWidget *buttonDistPlayStop; GtkWidget *notebook; #if GTK_MAJOR_VERSION == 2 && GTK_MINOR_VERSION < 12 GtkTooltips *tooltips; tooltips = gtk_tooltips_new (); #endif gtk_container_set_border_width(GTK_CONTAINER(vBoxVisuPlanes), 5); checkUseVisuPlanes = gtk_check_button_new_with_mnemonic(_("_Use planes")); gtk_box_pack_start (GTK_BOX (vBoxVisuPlanes), checkUseVisuPlanes, FALSE, FALSE, 0); g_object_bind_property(planes, "active", checkUseVisuPlanes, "active", G_BINDING_BIDIRECTIONAL | G_BINDING_SYNC_CREATE); gtk_box_pack_start(GTK_BOX(vBoxVisuPlanes), visu_ui_plane_list_getView(store), TRUE, TRUE, 0); gtk_box_pack_start(GTK_BOX(vBoxVisuPlanes), valueIO, FALSE, FALSE, 0); notebook = gtk_notebook_new(); gtk_box_pack_start(GTK_BOX(vBoxVisuPlanes), notebook, FALSE, FALSE, 0); /* Page 1 : simple tools*/ vbox = GTK_WIDGET(visu_ui_plane_list_getControls(store)); gtk_notebook_append_page(GTK_NOTEBOOK(notebook), vbox, gtk_label_new(_("Simple tools"))); /* Page : advanced tools*/ vbox = gtk_vbox_new(FALSE, 0); g_object_bind_property(store, "selection", vbox, "sensitive", G_BINDING_SYNC_CREATE); label = gtk_label_new(_("Advanced tools")); gtk_notebook_append_page(GTK_NOTEBOOK(notebook), vbox, label); label = gtk_label_new(_("Change selected plane distance")); gtk_label_set_xalign(GTK_LABEL(label), 0.); gtk_box_pack_start(GTK_BOX(vbox), label, FALSE, FALSE, 3); hbox = gtk_hbox_new(FALSE, 0); gtk_box_pack_start(GTK_BOX(vbox), hbox, FALSE, FALSE, 0); label = gtk_label_new(_("From: ")); gtk_label_set_xalign(GTK_LABEL(label), 1.); gtk_box_pack_start(GTK_BOX(hbox), label, TRUE, TRUE, 0); entryDistFrom = visu_ui_numerical_entry_new(0.); gtk_entry_set_width_chars(GTK_ENTRY(entryDistFrom), 7); gtk_box_pack_start(GTK_BOX(hbox), entryDistFrom, FALSE, FALSE, 0); label = gtk_label_new(_("to: ")); gtk_label_set_xalign(GTK_LABEL(label), 1.); gtk_box_pack_start(GTK_BOX(hbox), label, TRUE, TRUE, 0); entryDistTo = visu_ui_numerical_entry_new(0.); gtk_entry_set_width_chars(GTK_ENTRY(entryDistTo), 7); gtk_box_pack_start(GTK_BOX(hbox), entryDistTo, FALSE, FALSE, 0); label = gtk_label_new(_("step: ")); gtk_label_set_xalign(GTK_LABEL(label), 1.); gtk_box_pack_start(GTK_BOX(hbox), label, TRUE, TRUE, 0); entryDistStep = visu_ui_numerical_entry_new(1.); gtk_entry_set_width_chars(GTK_ENTRY(entryDistStep), 7); gtk_box_pack_start(GTK_BOX(hbox), entryDistStep, FALSE, FALSE, 0); hbox = gtk_hbox_new(FALSE, 0); gtk_box_pack_start(GTK_BOX(vbox), hbox, FALSE, FALSE, 0); label = gtk_label_new (_("Play at ")); gtk_box_pack_start(GTK_BOX(hbox), label, TRUE, TRUE, 0); gtk_label_set_xalign(GTK_LABEL(label), 1.); spinDistDelay = gtk_spin_button_new_with_range(10, 10000, 25); gtk_spin_button_set_value(GTK_SPIN_BUTTON(spinDistDelay), 500.); gtk_box_pack_start(GTK_BOX(hbox), spinDistDelay, FALSE, TRUE, 0); gtk_spin_button_set_numeric(GTK_SPIN_BUTTON(spinDistDelay), TRUE); label = gtk_label_new(_(" ms")); gtk_box_pack_start(GTK_BOX(hbox), label, FALSE, FALSE, 0); gtk_label_set_xalign(GTK_LABEL(label), 0.); buttonDistPlayStop = gtk_button_new(); gtk_widget_set_tooltip_text(buttonDistPlayStop, _("Change the distance parameter of he selected file" " at the given rate.")); gtk_box_pack_start(GTK_BOX(hbox), buttonDistPlayStop, FALSE, FALSE, 15); hbox = gtk_hbox_new(FALSE, 0); gtk_container_add(GTK_CONTAINER(buttonDistPlayStop), hbox); #if GTK_MAJOR_VERSION == 2 && GTK_MINOR_VERSION < 5 imageDistPlay = create_pixmap((GtkWidget*)0, "stock_media-play.png"); imageDistStop = create_pixmap((GtkWidget*)0, "stock_media-stop.png"); #else imageDistPlay = gtk_image_new_from_icon_name("media-playback-start", GTK_ICON_SIZE_BUTTON); imageDistStop = gtk_image_new_from_icon_name("media-playback-stop", GTK_ICON_SIZE_BUTTON); #endif gtk_widget_set_no_show_all(imageDistPlay, TRUE); gtk_widget_set_no_show_all(imageDistStop, TRUE); gtk_widget_show(imageDistPlay); gtk_box_pack_start(GTK_BOX(hbox), imageDistPlay, TRUE, TRUE, 0); gtk_box_pack_start(GTK_BOX(hbox), imageDistStop, TRUE, TRUE, 0); /* Add the callback methods. */ g_signal_connect(G_OBJECT(buttonDistPlayStop), "clicked", G_CALLBACK(onPlayStopDist), (gpointer)0); g_signal_connect(G_OBJECT(spinDistDelay), "value-changed", G_CALLBACK(onSpinDistDelayChange), (gpointer)0); gtk_widget_show_all(vBoxVisuPlanes); gtk_notebook_set_current_page(GTK_NOTEBOOK(notebook), 0); gtk_container_add(GTK_CONTAINER(panelPlanes), vBoxVisuPlanes); } static void onSetCameraPosition(VisuUiPlaneList *list _U_, VisuPlane *plane, gpointer data _U_) { float spherical[3]; float nVisuPlane[3]; DBG_fprintf(stderr, "Panel VisuPlanes: Set the camera position to be" " normal to the selected plane (%p).\n", (gpointer)plane); visu_plane_getNVectUser(plane, nVisuPlane); tool_matrix_cartesianToSpherical(spherical, nVisuPlane); g_object_set(visu_ui_panel_getView(VISU_UI_PANEL(panelPlanes)), "theta", spherical[1], "phi", spherical[2], NULL); } static void stopPlayStop(gpointer data _U_) { isPlayingDistanceId = 0; gtk_widget_hide(imageDistStop); gtk_widget_show(imageDistPlay); } static void startPlayStop(VisuPlane *plane) { gtk_widget_hide(imageDistPlay); gtk_widget_show(imageDistStop); isPlayingDistanceId = g_timeout_add_full(G_PRIORITY_DEFAULT + 30, (gint)gtk_spin_button_get_value(GTK_SPIN_BUTTON(spinDistDelay)), playDistances, (gpointer)plane, stopPlayStop); } static void onPlayStopDist(GtkButton *button _U_, gpointer data _U_) { VisuPlane *plane; DBG_fprintf(stderr, "Panel VisuPlanes: push the play/stop button.\n"); if (!isPlayingDistanceId) { plane = visu_ui_plane_list_getSelection(store); if (plane) { visu_plane_setDistanceFromOrigin(plane, visu_ui_numerical_entry_getValue(VISU_UI_NUMERICAL_ENTRY(entryDistFrom))); directionDist = 1.; /* Launch play */ startPlayStop(plane); } } else { /* Stop play */ g_source_remove(isPlayingDistanceId); } } static gboolean playDistances(gpointer data) { gdouble val, step; gboolean changed; val = visu_plane_getDistanceFromOrigin(VISU_PLANE(data)); step = visu_ui_numerical_entry_getValue(VISU_UI_NUMERICAL_ENTRY(entryDistStep)); changed = FALSE; if (directionDist > 0.) { if (val + step > visu_ui_numerical_entry_getValue(VISU_UI_NUMERICAL_ENTRY(entryDistTo))) directionDist = -1.; else changed = TRUE; } else changed = TRUE; if (directionDist < 0.) { if (val - step < visu_ui_numerical_entry_getValue(VISU_UI_NUMERICAL_ENTRY(entryDistFrom))) directionDist = +1.; else changed = TRUE; } /* If the direction has been changed twice in a row, then the step is too wide for the range, we stop. */ if (!changed) return FALSE; DBG_fprintf(stderr, "Panel VisuPlanes: set new distance to %g.\n", val + directionDist * step); visu_plane_setDistanceFromOrigin(VISU_PLANE(data), val + directionDist * step); return TRUE; } static void onSpinDistDelayChange(GtkSpinButton *spin _U_, gpointer data _U_) { if (isPlayingDistanceId) { /* Stop play. */ g_source_remove(isPlayingDistanceId); /* Launch play. */ startPlayStop(visu_ui_plane_list_getSelection(store)); } } gboolean callbackOpen(const gchar *filename, GError **error) { return visu_plane_set_parseXMLFile(visu_ui_plane_list_getModel(store), filename, error); } static gboolean callbackSave(const gchar* filename, GError **error) { return visu_plane_set_exportXMLFile(visu_ui_plane_list_getModel(store), filename, error); } v_sim-3.8.0/src/panelModules/panelPlanes.h000066400000000000000000000050521370110300500204610ustar00rootroot00000000000000/* EXTRAITS DE LA LICENCE Copyright CEA, contributeurs : Luc BILLARD et Damien CALISTE, laboratoire L_Sim, (2001-2005) Adresse mèl : BILLARD, non joignable par mèl ; CALISTE, damien P caliste AT cea P fr. Ce logiciel est un programme informatique servant à visualiser des structures atomiques dans un rendu pseudo-3D. Ce logiciel est régi par la licence CeCILL soumise au droit français et respectant les principes de diffusion des logiciels libres. Vous pouvez utiliser, modifier et/ou redistribuer ce programme sous les conditions de la licence CeCILL telle que diffusée par le CEA, le CNRS et l'INRIA sur le site "http://www.cecill.info". Le fait que vous puissiez accéder à cet en-tête signifie que vous avez pris connaissance de la licence CeCILL, et que vous en avez accepté les termes (cf. le fichier Documentation/licence.fr.txt fourni avec ce logiciel). */ /* LICENCE SUM UP Copyright CEA, contributors : Luc BILLARD et Damien CALISTE, laboratoire L_Sim, (2001-2005) E-mail address: BILLARD, not reachable any more ; CALISTE, damien P caliste AT cea P fr. This software is a computer program whose purpose is to visualize atomic configurations in 3D. This software is governed by the CeCILL license under French law and abiding by the rules of distribution of free software. You can use, modify and/ or redistribute the software under the terms of the CeCILL license as circulated by CEA, CNRS and INRIA at the following URL "http://www.cecill.info". The fact that you are presently reading this means that you have had knowledge of the CeCILL license and that you accept its terms. You can find a copy of this licence shipped with this software at Documentation/licence.en.txt. */ #ifndef PANELPLANES_H #define PANELPLANES_H #include #include #include #include #include /** * VisuUiPanelPlanesColumnId: * @VISU_UI_PANEL_PLANES_POINTER: the pointer to the #VisuPlane * object. * @VISU_UI_PANEL_PLANES_NOTIFY: a handler of the VisuPlane::notify signal. * @VISU_UI_PANEL_PLANES_N_COLUMNS: the number of columns. * * Thesse are the description of the columns stored in the #GtkListStore * of this panel. See visu_ui_panel_planes_getList() to access this liststore. */ typedef enum { VISU_UI_PANEL_PLANES_POINTER, VISU_UI_PANEL_PLANES_NOTIFY, VISU_UI_PANEL_PLANES_N_COLUMNS } VisuUiPanelPlanesColumnId; VisuUiPanel* visu_ui_panel_planes_init(); GtkListStore* visu_ui_panel_planes_getList(); #endif v_sim-3.8.0/src/panelModules/panelSurfaces.c000066400000000000000000002663231370110300500210170ustar00rootroot00000000000000/* EXTRAITS DE LA LICENCE Copyright CEA, contributeurs : Luc BILLARD, Damien CALISTE, Olivier D'Astier, laboratoire L_Sim, (2001-2005) Adresse mèl : BILLARD, non joignable par mèl ; CALISTE, damien P caliste AT cea P fr. D'ASTIER, dastier AT iie P cnam P fr. Ce logiciel est un programme informatique servant à visualiser des structures atomiques dans un rendu pseudo-3D. Ce logiciel est régi par la licence CeCILL soumise au droit français et respectant les principes de diffusion des logiciels libres. Vous pouvez utiliser, modifier et/ou redistribuer ce programme sous les conditions de la licence CeCILL telle que diffusée par le CEA, le CNRS et l'INRIA sur le site "http://www.cecill.info". Le fait que vous puissiez accéder à cet en-tête signifie que vous avez pris connaissance de la licence CeCILL, et que vous en avez accepté les termes (cf. le fichier Documentation/licence.fr.txt fourni avec ce logiciel). */ /* LICENCE SUM UP Copyright CEA, contributors : Luc BILLARD and Damien CALISTE and Olivier D'Astier, laboratoire L_Sim, (2001-2005) E-mail addresses : BILLARD, not reachable any more ; CALISTE, damien P caliste AT cea P fr. D'ASTIER, dastier AT iie P cnam P fr. This software is a computer program whose purpose is to visualize atomic configurations in 3D. This software is governed by the CeCILL license under French law and abiding by the rules of distribution of free software. You can use, modify and/ or redistribute the software under the terms of the CeCILL license as circulated by CEA, CNRS and INRIA at the following URL "http://www.cecill.info". The fact that you are presently reading this means that you have had knowledge of the CeCILL license and that you accept its terms. You can find a copy of this licence shipped with this software at Documentation/licence.en.txt. */ #include "panelSurfaces.h" #include "panelSurfacesTools.h" #include "panelPlanes.h" #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include /** * SECTION:panelSurfaces * @short_description: Gtk interface to load isosurfaces. * * This module contains the panel used to draw isosurfaces. From * it, you can draw isosurfaces on screen after they are loaded * through the #VisuGlExtSurfaces object. You can also access tools to * manage and create .surf files, these tools are related to the panelSurfacesTools * module. */ /* Global variables. */ static GtkWidget *panelSurfaces; static GtkWidget *isosurfaces_gtk_vbox; static GtkTreeStore *treeStore; static GtkListStore *fields_data_list; static GtkWidget *treeView; static GtkTreeViewColumn *colorColumn; enum { SURFACE_FILE_DENPOT, /* The entry is a potential or a density file. */ SURFACE_FILE_SURF, /* The entry is a surfaces file. */ SURFACE_SURF /* The entry is a surface. */ }; enum { TYPE_COLUMN, LABEL_COLUMN, POTENTIAL_COLUMN, SHADE_COLUMN, ROW_FIELD_COLUMN, BOX_ROW_COLUMN, N_COLUMNS }; static void showHideVisuSurface(GtkTreeModel *model, GtkTreeIter *iter, gpointer value); static void changeSurfaceColor(GtkTreeModel *model, GtkTreeIter *iter, gpointer color); static gboolean isosurfaces_show_next(); static gboolean loadXMLFile(const gchar *filename, GError **error); /* Callbacks. */ static void onDataFocused(GObject *visu, VisuData *dataObj, gpointer data); static void onOpenClicked(GtkButton *button, gpointer data); static void onTreeSelectionChanged(GtkTreeSelection *tree, gpointer data); static void onAddButtonClicked(GtkButton *button, gpointer data); static void onAddSpecialButtonClicked(GtkButton *button, gpointer data); static void onGenerateChanged(GtkSpinButton *spin, gpointer data); static void onRemoveButtonClicked(GtkButton *button, gpointer data); static void onReorderToggled(GtkToggleButton *toggle, VisuGlExtSurfaces *surfs); static void onNameEdited(GtkCellRendererText *cellrenderertext, gchar *path, gchar *text, gpointer user_data); static void onPotentialValueEdited(GtkCellRendererText *cellrenderertext, gchar *path, gchar *text, gpointer user_data); static void onShowHideAllButton(GtkButton *button, gpointer visibility); static void onRangesChanged(VisuUiColorCombobox *colorComboBox, guint valId, gpointer data); static void onEditPropertiesClicked(GtkButton *button, gpointer data); static gboolean onTreeViewClicked(GtkWidget *widget, GdkEventButton *event, gpointer user_data); static gboolean onPropertiesClosed(GtkWidget *widget, GdkEvent *event, gpointer data); static void onToolShadeChange(VisuUiShadeCombobox *combo, ToolShade *shade, gpointer data); static void onMaskingToggled(GtkCellRendererToggle *cell_renderer, gchar *path, gpointer user_data); static void onTreeViewActivated(GtkTreeView *tree_view, GtkTreePath *path, GtkTreeViewColumn *column, gpointer user_data); static void panelIsosurfacesUpdate_surfaceProperties(); /* Global widgets. */ static GtkWidget *edit_window; static GtkWidget *edit_combo_color; static GtkWidget *vboxColorur; static GtkWidget *vboxToolShade; static GtkWidget *shadeCombo; static GtkWidget *auto_reorder; static GtkWidget *buttonAddSurface; static GtkWidget *buttonAddSpecial; static GtkWidget *buttonRemoveSurface; static GtkWidget *buttonEdit; static GtkWidget *buttonOpen; static GtkWidget *buttonConvert; static GtkWidget *checkAutoLoad; static GtkWidget *checkDrawIntra; static GtkWidget *valueIO; /* Global flags. */ static gboolean reverse_order = FALSE; static gboolean autoload_file = FALSE; /* New types. */ typedef void (*ChangesMethod)(GtkTreeModel *model, GtkTreeIter *iter, gpointer data); /* Get the iter of the selected row. */ static gboolean getSelectedRow(GtkTreeModel **model, GtkTreeIter *iter) { GtkTreeSelection* tree_selection = gtk_tree_view_get_selection(GTK_TREE_VIEW(treeView)); *model = gtk_tree_view_get_model(GTK_TREE_VIEW(treeView)); g_return_val_if_fail(GTK_IS_TREE_MODEL(*model), FALSE); if (!gtk_tree_selection_get_selected(tree_selection, NULL, iter)) return FALSE; return TRUE; } /* Call @method on iter depending on selection. - If there is no selection, changes are applied on all surfaces. - If selection is on a file, changes are applied on all surfaces on that file. - If selection is on a surface, changes are applied on all surfaces of the same file. */ static void applyChanges(ChangesMethod method, gpointer value) { gboolean valid; gboolean validParent, validChild; GtkTreeModel *model; GtkTreeIter iter, parent, child; DBG_fprintf(stderr, "Panel VisuSurface: run in the treeview to apply changes.\n"); valid = getSelectedRow(&model, &iter); if (!valid) { DBG_fprintf(stderr, " | run on all row without recurse.\n"); /* Nothing is selected, we call the changing method on all surfaces. */ for (validParent = gtk_tree_model_get_iter_first(model, &parent); validParent; validParent = gtk_tree_model_iter_next(model, &parent)) for (validChild = gtk_tree_model_iter_children(model, &child, &parent); validChild; validChild = gtk_tree_model_iter_next(model, &child)) method(model, &child, value); } else { DBG_fprintf(stderr, " | run on all row of the current file.\n"); /* Something is selected, run method on it and possible children. */ method(model, &iter, value); for (validChild = gtk_tree_model_iter_children(model, &child, &iter); validChild; validChild = gtk_tree_model_iter_next(model, &child)) method(model, &child, value); } } typedef struct _RowSurface RowSurface; struct _RowSurface { guint refcount; GtkTreeRowReference *row; VisuGlExtSurfaces *set; VisuSurface *surf; gulong sig_surf; VisuSurfaceResource *res; gulong sig_notify; }; static void onResourceNotify(VisuSurfaceResource *res _U_, GParamSpec *pspec _U_, RowSurface *row) { GtkTreeModel *model; GtkTreePath *path; GtkTreeIter iter; model = gtk_tree_row_reference_get_model(row->row); path = gtk_tree_row_reference_get_path(row->row); g_return_if_fail(path); g_return_if_fail(gtk_tree_model_get_iter(model, &iter, path)); gtk_tree_model_row_changed(model, path, &iter); gtk_tree_path_free(path); } static void onSurfaceNotify(VisuSurface *surf, GParamSpec *pspec _U_, RowSurface *row) { VisuSurfaceResource *res; res = visu_surface_getResource(surf); if (res == row->res) return; /* Update listeners. */ g_signal_handler_disconnect(G_OBJECT(row->res), row->sig_notify); g_object_unref(row->res); row->res = res; g_object_ref(row->res); row->sig_notify = g_signal_connect(G_OBJECT(row->res), "notify", G_CALLBACK(onResourceNotify), (gpointer)row); } static RowSurface* row_surface_copy(RowSurface *row) { if (row) row->refcount += 1; DBG_fprintf(stderr, "Panel Surfaces: ref row %p (%d).\n", (gpointer)row, (row) ? (int)row->refcount : -1); return row; } static void row_surface_free(RowSurface *row) { if (!row) return; row->refcount -= 1; DBG_fprintf(stderr, "Panel Surfaces: unref row %p (%d).\n", (gpointer)row, (row) ? (int)row->refcount : -1); if (!row->refcount) { g_signal_handler_disconnect(row->surf, row->sig_surf); g_object_unref(row->surf); g_signal_handler_disconnect(row->res, row->sig_notify); g_object_unref(row->res); gtk_tree_row_reference_free(row->row); visu_gl_ext_surfaces_remove(row->set, row->surf); g_free(row); } } #define TYPE_ROW_SURFACE (row_surface_get_type()) static GType row_surface_get_type(void) { static GType g_define_type_id = 0; if (g_define_type_id == 0) g_define_type_id = g_boxed_type_register_static("RowSurface", (GBoxedCopyFunc)row_surface_copy, (GBoxedFreeFunc)row_surface_free); return g_define_type_id; } typedef struct _RowPotential RowPotential; struct _RowPotential { guint refcount; GtkTreeRowReference *row; VisuScalarField *field; gulong sig_field; VisuScalarfieldSet *set; int labelId; }; static RowPotential* row_potential_copy(RowPotential *row) { if (row) row->refcount += 1; DBG_fprintf(stderr, "Panel Surfaces: ref pot row %p (%d).\n", (gpointer)row, (row) ? (int)row->refcount : -1); return row; } static void row_potential_free(RowPotential *row) { if (!row) return; row->refcount -= 1; DBG_fprintf(stderr, "Panel Surfaces: unref pot row %p (%d).\n", (gpointer)row, (row) ? (int)row->refcount : -1); if (!row->refcount) { g_object_unref(row->set); g_signal_handler_disconnect(row->field, row->sig_field); g_object_unref(row->field); gtk_tree_row_reference_free(row->row); g_free(row); } } #define TYPE_ROW_POTENTIAL (row_potential_get_type()) static GType row_potential_get_type(void) { static GType g_define_type_id = 0; if (g_define_type_id == 0) g_define_type_id = g_boxed_type_register_static("RowPotential", (GBoxedCopyFunc)row_potential_copy, (GBoxedFreeFunc)row_potential_free); return g_define_type_id; } static void connectSurface(GtkTreeStore *model, GtkTreeIter *iter, VisuGlExtSurfaces *set, VisuSurface *surf) { RowSurface *row; GtkTreePath *path = gtk_tree_model_get_path(GTK_TREE_MODEL(model), iter); float *pot; g_return_if_fail(VISU_IS_SURFACE(surf)); row = g_malloc(sizeof(RowSurface)); DBG_fprintf(stderr, "Panel Surfaces: create a new row %p for surface %p.\n", (gpointer)row, (gpointer)surf); row->refcount = 0; row->row = gtk_tree_row_reference_new(GTK_TREE_MODEL(model), path); gtk_tree_path_free(path); row->surf = surf; g_object_ref(row->surf); row->sig_surf = g_signal_connect(G_OBJECT(surf), "notify::resource", G_CALLBACK(onSurfaceNotify), (gpointer)row); row->res = visu_surface_getResource(surf); g_object_ref(row->res); row->sig_notify = g_signal_connect(G_OBJECT(row->res), "notify", G_CALLBACK(onResourceNotify), (gpointer)row); pot = visu_surface_getPropertyFloat(surf, VISU_SURFACE_PROPERTY_POTENTIAL); gtk_tree_store_set(model, iter, TYPE_COLUMN, SURFACE_SURF, BOX_ROW_COLUMN, row, POTENTIAL_COLUMN, (pot) ? pot[0] : G_MAXFLOAT, -1); row->set = set; visu_gl_ext_surfaces_add(set, surf); DBG_fprintf(stderr, "Panel Surfaces: creation done for %p (%d).\n", (gpointer)surf, G_OBJECT(surf)->ref_count); } static void onSurfaceAdded(VisuGlExtSurfaces *surfs, VisuSurface *surf, GtkTreeStore *model) { GtkTreeIter iter, child, *root; gboolean valid, valid2, found; RowSurface *row; RowPotential *field; VisuScalarField *origin; root = (GtkTreeIter*)0; origin = g_object_get_data(G_OBJECT(surf), "origin"); found = FALSE; for (valid = gtk_tree_model_get_iter_first(GTK_TREE_MODEL(model), &iter); valid && !found; valid = gtk_tree_model_iter_next(GTK_TREE_MODEL(model), &iter)) { gtk_tree_model_get(GTK_TREE_MODEL(model), &iter, ROW_FIELD_COLUMN, &field, BOX_ROW_COLUMN, &row, -1); if (row) { found = (row->surf == surf); row_surface_free(row); } if (field) { if (field->field == origin) root = gtk_tree_iter_copy(&iter); row_potential_free(field); } for (valid2 = gtk_tree_model_iter_children(GTK_TREE_MODEL(model), &child, &iter); valid2 && !found; valid2 = gtk_tree_model_iter_next(GTK_TREE_MODEL(model), &child)) { gtk_tree_model_get(GTK_TREE_MODEL(model), &child, BOX_ROW_COLUMN, &row, -1); if (row) { found = (row->surf == surf); row_surface_free(row); } } } if (found) return; gtk_tree_store_append(model, &iter, root); if (root) gtk_tree_iter_free(root); connectSurface(model, &iter, surfs, surf); } static void onSurfaceRemoved(VisuGlExtSurfaces *surfs _U_, VisuSurface *surf, GtkTreeStore *model) { GtkTreeIter iter; gboolean valid; RowSurface *row; valid = gtk_tree_model_get_iter_first(GTK_TREE_MODEL(model), &iter); while (valid) { gtk_tree_model_get(GTK_TREE_MODEL(model), &iter, BOX_ROW_COLUMN, &row, -1); if (row && row->surf == surf) valid = gtk_tree_store_remove(model, &iter); else valid = gtk_tree_model_iter_next(GTK_TREE_MODEL(model), &iter); if (row) row_surface_free(row); } } /***********************/ /* Visibility Handling */ /***********************/ static VisuSurfaceResource* resourceAt(GtkTreeModel *model, GtkTreeIter *iter) { RowSurface *row; VisuSurfaceResource *res; gtk_tree_model_get(model, iter, BOX_ROW_COLUMN, &row, -1); if (row) { res = row->res; row_surface_free(row); return res; } return (VisuSurfaceResource*)0; } /* Change the visibility of one surface (given by its iter). The visibility is in value (using GPOINTER_TO_INT) and recurse is a flag to tell if changes must be propagated to all elements with the same name or not. */ static void showHideVisuSurface(GtkTreeModel *model, GtkTreeIter *iter, gpointer value) { VisuSurfaceResource *res; res = resourceAt(model, iter); if (res) g_object_set(G_OBJECT(res), "rendered", (gboolean)GPOINTER_TO_INT(value), NULL); } /* Callback for the "Draw" check box. If the selected surface were drawn, hides it and uncheck the button. If it was hidden, shows it and check the button. */ static void onDisplayToggled(GtkCellRendererToggle *cell_renderer, gchar *string_path, gpointer user_data) { GtkTreePath* path = gtk_tree_path_new_from_string(string_path); GtkTreeIter iter; gboolean valid; valid = gtk_tree_model_get_iter(GTK_TREE_MODEL(user_data), &iter, path); gtk_tree_path_free(path); if (!valid) return; DBG_fprintf(stderr, "Panel VisuSurface: toggle show box on '%s'.\n", string_path); /* We change the visibility of the surface (both resource and check box). */ g_object_set(G_OBJECT(resourceAt(GTK_TREE_MODEL(user_data), &iter)), "rendered", !gtk_cell_renderer_toggle_get_active(cell_renderer), NULL); } static void onMaskingToggled(GtkCellRendererToggle *cell_renderer, gchar *string_path, gpointer user_data) { GtkTreePath* path = gtk_tree_path_new_from_string(string_path); GtkTreeIter iter; gboolean valid; valid = gtk_tree_model_get_iter(GTK_TREE_MODEL(user_data), &iter, path); gtk_tree_path_free(path); if (!valid) return; DBG_fprintf(stderr, "Panel VisuSurface: toggle show box on '%s'.\n", string_path); /* We change the visibility of the surface (both resource and check box). */ g_object_set(G_OBJECT(resourceAt(GTK_TREE_MODEL(user_data), &iter)), "maskable", !gtk_cell_renderer_toggle_get_active(cell_renderer), NULL); } /** * visu_ui_panel_surfaces_showAll: * @show: TRUE to show all surfaces, FALSE to hide them. * * Shows or hides all surfaces and check their "draw" status in the panel accordingly. * * Returns: TRUE if surface list should be rebuild and redraw. **/ gboolean visu_ui_panel_surfaces_showAll(gboolean show) { GtkTreeModel *model; GtkTreeIter iter, parent; gboolean valid; if (!getSelectedRow(&model, &iter)) return FALSE; parent = iter; if ((gtk_tree_model_iter_n_children(model, &iter) > 0) || gtk_tree_model_iter_parent(model, &parent, &iter)) for (valid = gtk_tree_model_iter_children(model, &iter, &parent); valid; valid = gtk_tree_model_iter_next(model, &iter)) showHideVisuSurface(model, &iter, GINT_TO_POINTER(show)); else showHideVisuSurface(model, &iter, GINT_TO_POINTER(show)); return TRUE; } void onShowHideAllButton(GtkButton *button _U_, gpointer visibility) { visu_ui_panel_surfaces_showAll(GPOINTER_TO_INT(visibility)); } /******************************/ /* Color & material Handling */ /******************************/ /* Changes the colour for a specific surface identified by its iter. If recurse is TRUE, changes are also applied on surfaces with the same name. */ void changeSurfaceColor(GtkTreeModel *model, GtkTreeIter *iter, gpointer colorComboBox) { VisuSurfaceResource *res; float *rgba, *material; ToolColor *color; res = resourceAt(model, iter); if (!res) return; /* We get a color from the values of the ranges. */ material = visu_ui_color_combobox_getRangeMaterial(VISU_UI_COLOR_COMBOBOX(colorComboBox)); rgba = visu_ui_color_combobox_getRangeColor(VISU_UI_COLOR_COMBOBOX(colorComboBox)); color = tool_color_new(rgba); g_object_set(G_OBJECT(res), "color", color, "material", material, NULL); g_free(material); g_free(rgba); g_free(color); } /* Callback for when the combo color is changed in the edit panel */ void onColorChanged(VisuUiColorCombobox *combo, ToolColor *color _U_, gpointer data _U_) { /* We change all surfaces depending on the selected one. */ DBG_fprintf(stderr, "Panel VisuSurface: caught the 'color-selected' signal.\n"); applyChanges(changeSurfaceColor, (gpointer)combo); } static void onRangesChanged(VisuUiColorCombobox *colorComboBox, guint valId _U_, gpointer data _U_) { /* We change all surfaces depending on the selected one. */ DBG_fprintf(stderr, "Panel VisuSurface: caught the " "'[material:color]-value-changed' signal.\n"); applyChanges(changeSurfaceColor, (gpointer)colorComboBox); } static void onToolShadeChange(VisuUiShadeCombobox *combo _U_, ToolShade *shade, gpointer data _U_) { gboolean valid; GtkTreeModel *model; GtkTreeIter iter, child; int type; RowPotential *field; float value, alpha; ToolColor color; double minmax[2]; RowSurface *row; VisuSurfaceResource *res; DBG_fprintf(stderr, "Panel VisuSurface: caught the " "'shade-selected' signal.\n"); valid = getSelectedRow(&model, &iter); g_return_if_fail(valid); gtk_tree_model_get(model, &iter, TYPE_COLUMN, &type, ROW_FIELD_COLUMN, &field, -1); g_return_if_fail(type == SURFACE_FILE_DENPOT && field); visu_scalar_field_getMinMax(field->field, minmax); row_potential_free(field); alpha = sqrt((float)gtk_tree_model_iter_n_children(model, &iter)); /* For each children, we apply the shade. */ for (valid = gtk_tree_model_iter_children(model, &child, &iter); valid; valid = gtk_tree_model_iter_next(model, &child)) { gtk_tree_model_get(model, &child, TYPE_COLUMN, &type, POTENTIAL_COLUMN, &value, BOX_ROW_COLUMN, &row, -1); g_return_if_fail(type == SURFACE_SURF); tool_shade_valueToRGB(shade, color.rgba, (value - minmax[0]) / (minmax[1] - minmax[0])); color.rgba[3] = exp(-alpha * (1. - (value - minmax[0]) / (minmax[1] - minmax[0]))); res = visu_surface_resource_new_fromCopy((const gchar*)0, visu_surface_getResource(row->surf)); g_object_set(G_OBJECT(res), "color", &color, NULL); visu_surface_setResource(row->surf, res); g_object_unref(G_OBJECT(res)); row_surface_free(row); } } /** * visu_ui_panel_surfaces_editProperties: * @iter: the currently selected row iter (or NULL). * * Opens a new window allowing to edit surface properties. */ void visu_ui_panel_surfaces_editProperties(GtkTreeIter *iter) { GtkWidget *hbox, *label, *expand, *notebook; gint type; if (!GTK_IS_WINDOW(edit_window)) { edit_window = gtk_dialog_new_with_buttons (_("Edit surface properties"), GTK_WINDOW(visu_ui_panel_getContainerWindow(VISU_UI_PANEL(panelSurfaces))), 0, TOOL_ICON_CLOSE, GTK_RESPONSE_ACCEPT, NULL); gtk_window_set_default_size(GTK_WINDOW(edit_window), 320, -1); gtk_window_set_type_hint(GTK_WINDOW(edit_window), GDK_WINDOW_TYPE_HINT_UTILITY); gtk_window_set_skip_pager_hint(GTK_WINDOW(edit_window), TRUE); gtk_container_set_border_width(GTK_CONTAINER(edit_window), 3); notebook = gtk_notebook_new(); gtk_box_pack_start(GTK_BOX(gtk_dialog_get_content_area(GTK_DIALOG(edit_window))), notebook, TRUE, TRUE, 0); /* Create the colour tab. */ vboxColorur = gtk_vbox_new(FALSE, 0); gtk_notebook_append_page(GTK_NOTEBOOK(notebook), vboxColorur, gtk_label_new(_("Color"))); hbox = gtk_hbox_new(FALSE, 0); gtk_box_pack_start(GTK_BOX(vboxColorur), hbox, FALSE, FALSE, 0); label = gtk_label_new(_("Color: ")); gtk_box_pack_start(GTK_BOX(hbox), label, FALSE, FALSE, 2); edit_combo_color = visu_ui_color_combobox_newWithRanges(TRUE); visu_ui_color_combobox_setExpanded(VISU_UI_COLOR_COMBOBOX(edit_combo_color), TRUE); gtk_box_pack_start(GTK_BOX(hbox), edit_combo_color, TRUE, TRUE, 2); expand = visu_ui_color_combobox_getRangeWidgets(VISU_UI_COLOR_COMBOBOX(edit_combo_color)); gtk_box_pack_start(GTK_BOX(vboxColorur), expand, FALSE, FALSE, 0); /* Set the callbacks. */ g_signal_connect(G_OBJECT(edit_window), "response", G_CALLBACK(gtk_widget_hide), (gpointer)0); g_signal_connect(G_OBJECT(edit_window), "delete-event", G_CALLBACK(onPropertiesClosed), (gpointer)0); g_signal_connect(G_OBJECT(edit_window), "destroy-event", G_CALLBACK(onPropertiesClosed), (gpointer)0); g_signal_connect(G_OBJECT(edit_combo_color), "color-selected", G_CALLBACK(onColorChanged), (gpointer)0); g_signal_connect(G_OBJECT(edit_combo_color), "material-value-changed", G_CALLBACK(onRangesChanged), (gpointer)0); g_signal_connect(G_OBJECT(edit_combo_color), "color-value-changed", G_CALLBACK(onRangesChanged), (gpointer)0); /* Create the shade tab. */ vboxToolShade = gtk_vbox_new(FALSE, 0); gtk_notebook_append_page(GTK_NOTEBOOK(notebook), vboxToolShade, gtk_label_new(_("Shade"))); label = gtk_label_new(_("Apply a shade to the current surfaces of" " the selected scalar field.")); gtk_label_set_justify(GTK_LABEL(label), GTK_JUSTIFY_FILL); gtk_label_set_line_wrap(GTK_LABEL(label), TRUE); gtk_box_pack_start(GTK_BOX(vboxToolShade), label, FALSE, FALSE, 5); hbox = gtk_hbox_new(FALSE, 0); gtk_box_pack_start(GTK_BOX(vboxToolShade), hbox, FALSE, FALSE, 5); label = gtk_label_new(_("ToolShade: ")); gtk_box_pack_start(GTK_BOX(hbox), label, FALSE, FALSE, 0); shadeCombo = visu_ui_shade_combobox_new(TRUE, TRUE); gtk_box_pack_start(GTK_BOX(hbox), shadeCombo, TRUE, TRUE, 0); /* Set the callbacks. */ g_signal_connect(G_OBJECT(shadeCombo), "shade-selected", G_CALLBACK(onToolShadeChange), (gpointer)0); gtk_widget_show_all(edit_window); } else gtk_window_present(GTK_WINDOW(edit_window)); /* Set the radio combo. */ if (iter) gtk_tree_model_get(GTK_TREE_MODEL(treeStore), iter, TYPE_COLUMN, &type, -1); else type = SURFACE_FILE_DENPOT; panelIsosurfacesUpdate_surfaceProperties(); } static void panelIsosurfacesUpdate_surfaceProperties() { gboolean valid; int type; GtkTreeModel *model; GtkTreeIter iter; ToolShade *shade; float material[5]; RowSurface *row; shade = (ToolShade*)0; type = SURFACE_SURF; valid = getSelectedRow(&model, &iter); if (valid) { gtk_tree_model_get(model, &iter, TYPE_COLUMN, &type, SHADE_COLUMN, &shade, -1); if (type == SURFACE_SURF) { gtk_tree_model_get(model, &iter, BOX_ROW_COLUMN, &row, -1); visu_ui_color_combobox_setRangeColor (VISU_UI_COLOR_COMBOBOX(edit_combo_color), visu_surface_resource_getColor(row->res)->rgba, FALSE); visu_ui_color_combobox_setRangeMaterial (VISU_UI_COLOR_COMBOBOX(edit_combo_color), visu_surface_resource_getMaterial(row->res), FALSE); row_surface_free(row); } else { material[0] = 0.2f; material[1] = 1.0f; material[2] = 0.5f; material[3] = 0.5f; material[4] = 0.0f; visu_ui_color_combobox_setRangeMaterial (VISU_UI_COLOR_COMBOBOX(edit_combo_color), material, FALSE); } } /* Set widgets sensitive or not. */ if (vboxToolShade) { gtk_widget_set_sensitive(vboxToolShade, (type == SURFACE_FILE_DENPOT)); visu_ui_shade_combobox_setSelectionByShade(VISU_UI_SHADE_COMBOBOX(shadeCombo), shade); } } static gboolean onPropertiesClosed(GtkWidget *widget, GdkEvent *event _U_, gpointer data _U_) { gtk_widget_hide(widget); return TRUE; } static void onEditPropertiesClicked(GtkButton *button _U_, gpointer data _U_) { GtkTreeModel *model; GtkTreeIter iter; gboolean valid; DBG_fprintf(stderr, "Panel VisuSurface: clicked on properties button.\n"); valid = getSelectedRow(&model, &iter); if (valid) visu_ui_panel_surfaces_editProperties(&iter); else visu_ui_panel_surfaces_editProperties((GtkTreeIter*)0); } /* See header for more info */ static void onOpenClicked(GtkButton *button _U_, gpointer data) { char *file_choosed; #if GTK_MAJOR_VERSION == 2 && GTK_MINOR_VERSION < 12 GtkTooltips *tooltips = gtk_tooltips_new (); #endif GtkWidget *dialog; gboolean invalid, redraw; VisuData *dataObj; float trans[3] = {0.f, 0.f, 0.f}; VisuScalarFieldMethod *fmt; GtkTreeModel *model; GtkTreeIter iter; RowSurface *row; RowPotential *field; dialog = visu_ui_field_chooser_new((GtkWindow*)0); dataObj = visu_ui_panel_getData(VISU_UI_PANEL(panelSurfaces)); redraw = FALSE; invalid = TRUE; while(invalid) { switch(gtk_dialog_run(GTK_DIALOG(dialog))) { case GTK_RESPONSE_ACCEPT: file_choosed = gtk_file_chooser_get_filename(GTK_FILE_CHOOSER(dialog)); fmt = visu_ui_field_chooser_getFileFormat(VISU_UI_FIELD_CHOOSER(dialog)); g_object_set(VISU_GL_NODE_SCENE(data), "auto-adjust", (visu_ui_field_chooser_getFit(VISU_UI_FIELD_CHOOSER(dialog)) == VISU_UI_FIT_TO_BOX), NULL); if(visu_ui_panel_surfaces_loadFile(file_choosed, &iter, (GHashTable*)0, fmt)) { redraw = TRUE; invalid = FALSE; } break; default: invalid = FALSE; } } /* We update the VisuData bounding box. */ if (redraw && visu_ui_field_chooser_getFit(VISU_UI_FIELD_CHOOSER(dialog)) == VISU_UI_FIT_TO_SURFACE) { getSelectedRow(&model, &iter); gtk_tree_model_get(model, &iter, BOX_ROW_COLUMN, &row, ROW_FIELD_COLUMN, &field, -1); DBG_fprintf(stderr, "Panel Surfaces: update data bounding box.\n"); if (field) { visu_boxed_setBox(VISU_BOXED(dataObj), VISU_BOXED(field->field)); row_potential_free(field); } else if (row) { visu_boxed_setBox(VISU_BOXED(dataObj), VISU_BOXED(row->surf)); row_surface_free(row); } visu_pointset_setTranslationPeriodic(VISU_POINTSET(dataObj), trans, FALSE); } /* Free everything. */ DBG_fprintf(stderr, "Panel Surfaces: free load dialog.\n"); gtk_widget_destroy(dialog); } static gchar* _getFieldLabel(const VisuScalarfieldSet *set, const VisuScalarField *field) { double minmax[2]; if (visu_scalar_field_isEmpty(field)) return g_strdup_printf(_("%s\n " "no data"), visu_scalarfield_set_getLabel(set, field)); else { visu_scalar_field_getMinMax(field, minmax); return g_strdup_printf(_("%s\n " "Den./pot. data (min|max)\n %g | %g"), visu_scalarfield_set_getLabel(set, field), minmax[0], minmax[1]); } } static void onFieldChanged(VisuScalarField *field _U_, RowPotential *row) { GtkTreeModel *model; GtkTreePath *path; GtkTreeIter iter; gchar *label; model = gtk_tree_row_reference_get_model(row->row); path = gtk_tree_row_reference_get_path(row->row); g_return_if_fail(path); g_return_if_fail(gtk_tree_model_get_iter(model, &iter, path)); gtk_tree_path_free(path); label = _getFieldLabel(row->set, row->field); if (GTK_IS_LIST_STORE(model)) gtk_list_store_set(GTK_LIST_STORE(model), &iter, row->labelId, label, -1); if (GTK_IS_TREE_STORE(model)) gtk_tree_store_set(GTK_TREE_STORE(model), &iter, row->labelId, label, -1); g_free(label); } static RowPotential* _newRowField(GtkTreeModel *model, GtkTreeIter *iter, int labelId, VisuScalarfieldSet *set, VisuScalarField *field) { RowPotential *row; GtkTreePath *path = gtk_tree_model_get_path(model, iter); row = g_malloc(sizeof(RowPotential)); DBG_fprintf(stderr, "Panel Surfaces: create a new row %p for potential %p.\n", (gpointer)row, (gpointer)field); row->refcount = 0; row->row = gtk_tree_row_reference_new(model, path); gtk_tree_path_free(path); row->labelId = labelId; row->set = g_object_ref(set); row->field = g_object_ref(field); row->sig_field = g_signal_connect(G_OBJECT(field), "changed", G_CALLBACK(onFieldChanged), (gpointer)row); DBG_fprintf(stderr, "Panel Surfaces: creation done for %p (%d).\n", (gpointer)field, G_OBJECT(field)->ref_count); return row; } static void _addField(VisuScalarfieldSet *set, VisuScalarField *field, GtkListStore *model) { gchar *label; GtkTreeIter iter; label = _getFieldLabel(set, field); gtk_list_store_append(model, &iter); gtk_list_store_set(model, &iter, VISU_UI_SURFACES_FIELD_LABEL, label, VISU_UI_SURFACES_FIELD_ROW, _newRowField(GTK_TREE_MODEL(model), &iter, VISU_UI_SURFACES_FIELD_LABEL, set, field), -1); gtk_tree_store_append(treeStore, &iter, (GtkTreeIter*)0); gtk_tree_store_set(treeStore, &iter, LABEL_COLUMN, label, TYPE_COLUMN, SURFACE_FILE_DENPOT, ROW_FIELD_COLUMN, _newRowField(GTK_TREE_MODEL(treeStore), &iter, LABEL_COLUMN, set, field), -1); DBG_fprintf(stderr, " | field %p.\n", (gpointer)field); g_free(label); } static void _removeField(VisuScalarfieldSet *set _U_, VisuScalarField *field, GtkListStore *model) { gboolean valid; GtkTreeIter iter; RowPotential *row; valid = gtk_tree_model_get_iter_first(GTK_TREE_MODEL(model), &iter); for (valid = gtk_tree_model_get_iter_first(GTK_TREE_MODEL(model), &iter); valid; valid = gtk_tree_model_iter_next(GTK_TREE_MODEL(model), &iter)) { gtk_tree_model_get(GTK_TREE_MODEL(model), &iter, VISU_UI_SURFACES_FIELD_ROW, &row, -1); if (row->field == field) { row_potential_free(row); gtk_list_store_remove(model, &iter); break; } row_potential_free(row); } valid = gtk_tree_model_get_iter_first(GTK_TREE_MODEL(treeStore), &iter); for (valid = gtk_tree_model_get_iter_first(GTK_TREE_MODEL(treeStore), &iter); valid; valid = gtk_tree_model_iter_next(GTK_TREE_MODEL(treeStore), &iter)) { gtk_tree_model_get(GTK_TREE_MODEL(treeStore), &iter, ROW_FIELD_COLUMN, &row, -1); if (row->field == field) { row_potential_free(row); gtk_tree_store_remove(treeStore, &iter); break; } row_potential_free(row); } } /** * visu_ui_panel_surfaces_addSurfaces: * @surfs: (element-type VisuSurface*): a #VisuSurface object. * @name: a name @surf comes from. * @iter: (out caller-allocates): a location to store the iter. * * This routine can be used to add a #VisuSurface to the tree * view. @iter is then populated with the row it has been inserted to. * * Since: 3.7 **/ void visu_ui_panel_surfaces_addSurfaces(GList *surfs, const gchar *name, GtkTreeIter *iter) { gchar *label; GList *it; GtkTreeIter child; label = g_strdup_printf(_("%s\n " "Surfaces data"), name); gtk_tree_store_append(treeStore, iter, (GtkTreeIter*)0); gtk_tree_store_set(treeStore, iter, LABEL_COLUMN, label, TYPE_COLUMN, SURFACE_FILE_SURF, -1); g_free(label); for (it = surfs; it; it = g_list_next(it)) visu_ui_panel_surfaces_addSurface(VISU_SURFACE(it->data), iter, &child); } /** * visu_ui_panel_surfaces_addSurface: * @surf: (transfer full): a #VisuSurface object. * @root: (allow-none): the iter to attach the surface to. * @iter: (out caller-allocates): a location to store the iter. * * This routine can be used to add a #VisuSurface to the tree * view. @iter is then populated with the row it has been inserted to. * * Since: 3.7 **/ void visu_ui_panel_surfaces_addSurface(VisuSurface *surf, GtkTreeIter *root, GtkTreeIter *iter) { GtkTreePath *path; VisuGlExtSurfaces *surfs; DBG_fprintf(stderr, "Panel Surfaces: adding surface %p (%d).\n", (gpointer)surf, G_OBJECT(surf)->ref_count); gtk_tree_store_append(treeStore, iter, root); surfs = visu_gl_node_scene_addSurfaces(visu_ui_rendering_window_getGlScene(visu_ui_main_class_getDefaultRendering())); connectSurface(treeStore, iter, surfs, surf); g_object_unref(surf); if (root) { path = gtk_tree_model_get_path(GTK_TREE_MODEL(treeStore), root); gtk_tree_view_expand_row(GTK_TREE_VIEW(treeView), path, TRUE); gtk_tree_path_free(path); } DBG_fprintf(stderr, "Panel Surfaces: addition done for surface %p (%d).\n", (gpointer)surf, G_OBJECT(surf)->ref_count); } static void onFieldReady(GObject *obj _U_, GAsyncResult *res, gpointer data _U_) { gboolean valid; GError *error; error = (GError*)0; valid = g_task_propagate_boolean(G_TASK(res), &error); if (!valid) visu_ui_raiseWarning(_("Loading a file"), (error) ? error->message : _("Unknown error"), (GtkWindow*)0); g_clear_error(&error); } static gboolean _loadScalarField(const gchar *filename, VisuScalarFieldMethod *meth, GHashTable *table) { return visu_scalarfield_set_addFromFile(visu_scalarfield_set_getDefault(), meth, filename, table, NULL, onFieldReady, NULL); } static gboolean visu_ui_panel_surfaces_loadSurface(const gchar *filename, GList **list) { gboolean valid; GError *error; GList *tmplst; g_return_val_if_fail(list, FALSE); error = (GError*)0; valid = visu_surface_loadFile(filename, list, &error); if (!valid) { if (error) g_error_free(error); return FALSE; } if (error) { visu_ui_raiseWarning(_("Loading a file"), error->message, (GtkWindow*)0); g_error_free(error); for (tmplst = *list; tmplst; tmplst = g_list_next(tmplst)) g_object_unref(G_OBJECT(tmplst->data)); g_list_free(*list); return TRUE; } return TRUE; } /** * visu_ui_panel_surfaces_loadFile: * @file_name: (type filename): the file you want to try to load * @iter: (out caller-allocates): a location to store the #GtkTreeIter * that will be set. * @table: (allow-none): a set of different #Option (can be NULL). * @meth: a #VisuScalarFieldMethod object. * * Tries to load the given @file_name and if it succeeds, adds loaded surfaces * to the isosurfaces panel. If @file_name is a #VisuScalarField then, * @meth is used to load it. If @fitToBox is not %NULL, the load * surfaces or scalar fields are fit to it. * * Return value: TRUE in case of success. */ gboolean visu_ui_panel_surfaces_loadFile(const char* file_name, GtkTreeIter *iter, GHashTable *table, VisuScalarFieldMethod *meth) { gchar *name; gboolean valid; /* gchar *filename; */ int type; GList *list; g_return_val_if_fail(file_name, FALSE); list = (GList*)0; valid = visu_ui_panel_surfaces_loadSurface(file_name, &list); if (valid) { if (!list) return FALSE; type = SURFACE_FILE_SURF; } else { valid = _loadScalarField(file_name, meth, table); if (valid) type = SURFACE_FILE_DENPOT; } if (!valid) /* Not a surface nor a density/potential file. */ return FALSE; /* Before adding it to the tree, we may remove all identic already existing file. */ /* DBG_fprintf(stderr, "Panel VisuSurface: may remove an existing entry.\n"); */ /* valid = gtk_tree_model_get_iter_first(GTK_TREE_MODEL(isosurfaces_data_list), */ /* &iter); */ /* while (valid) */ /* { */ /* gtk_tree_model_get(GTK_TREE_MODEL(isosurfaces_data_list), */ /* &iter, FILELABEL_COLUMN, &filename, -1); */ /* iter2 = iter; */ /* valid = gtk_tree_model_iter_next(GTK_TREE_MODEL(isosurfaces_data_list), */ /* &iter); */ /* if (!strcmp(filename, file_name)) */ /* panel_isosurfaces_remove(&iter2); */ /* } */ /* We create a root element for the file. */ DBG_fprintf(stderr, "Panel VisuSurface: add a new root entry '%s'.\n", file_name); name = g_path_get_basename(file_name); if (type == SURFACE_FILE_SURF) { visu_ui_panel_surfaces_addSurfaces(list, name, iter); gtk_tree_selection_select_iter (gtk_tree_view_get_selection(GTK_TREE_VIEW(treeView)), iter); } g_free(name); g_list_free(list); return TRUE; } /* See header file for more info */ static gboolean isosurfaces_show_next() { GtkTreeModel *model; GtkTreeIter iter, selected_iter; GtkTreeSelection* selection; if (!getSelectedRow(&model, &selected_iter)) return FALSE; if (gtk_tree_model_iter_children(model, &iter, &selected_iter)) selected_iter = iter; iter = selected_iter; if(reverse_order == FALSE) { if (!gtk_tree_model_iter_next(model, &iter)) { reverse_order = TRUE; iter = selected_iter; if (!gtk_tree_model_iter_previous(model, &iter)) return FALSE; } } else { if (!gtk_tree_model_iter_previous(model, &iter)) { reverse_order = FALSE; iter = selected_iter; if (!gtk_tree_model_iter_next(model, &iter)) return FALSE; } } showHideVisuSurface(model, &selected_iter, GINT_TO_POINTER(FALSE)); showHideVisuSurface(model, &iter, GINT_TO_POINTER(TRUE)); /* Set the selection to the new row. */ selection = gtk_tree_view_get_selection(GTK_TREE_VIEW(treeView)); gtk_tree_selection_select_iter(selection, &iter); return TRUE; } static void onPlayStop(gpointer data) { gtk_button_set_label(GTK_BUTTON(data), _("Play")); gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON(data), FALSE); } /* Callback for the "play" button. Registers the above function to be called at a specified time interval. */ static void isosurfaces_play(GtkToggleButton *play_stop, GtkWidget *time_interval) { static int event_id = 0; if(gtk_toggle_button_get_active(play_stop) == TRUE) { gtk_button_set_label(GTK_BUTTON(play_stop), _("Stop")); visu_ui_panel_surfaces_showAll(FALSE); event_id = g_timeout_add_full(G_PRIORITY_DEFAULT, gtk_spin_button_get_value(GTK_SPIN_BUTTON(time_interval)), isosurfaces_show_next, play_stop, onPlayStop); } else g_source_remove(event_id); } static void onDisplayLabel(GtkTreeViewColumn *column _U_, GtkCellRenderer *cell, GtkTreeModel *model, GtkTreeIter *iter, gpointer data _U_) { const gchar *resLbl; gchar *label; RowSurface *row; gtk_tree_model_get(model, iter, BOX_ROW_COLUMN, &row, -1); if (row) { resLbl = visu_surface_resource_getLabel(row->res); row_surface_free(row); label = g_strdup((resLbl) ? resLbl : VISU_UI_SURFACE_NAME_CHOOSE); } else gtk_tree_model_get(model, iter, LABEL_COLUMN, &label, -1); g_object_set(G_OBJECT(cell), "markup", label, "foreground", (row != NULL) ? "blue" : NULL, "editable", (row != NULL), NULL); g_free(label); } static void onDisplayShow(GtkTreeViewColumn *column _U_, GtkCellRenderer *cell, GtkTreeModel *model, GtkTreeIter *iter, gpointer data _U_) { RowSurface *row; gtk_tree_model_get(model, iter, BOX_ROW_COLUMN, &row, -1); g_object_set(G_OBJECT(cell), "visible", (row != NULL), "active", (row) ? visu_surface_resource_getRendered(row->res) : FALSE, NULL); if (row) row_surface_free(row); } static void onDisplayPot(GtkTreeViewColumn *column _U_, GtkCellRenderer *cell, GtkTreeModel *model, GtkTreeIter *iter, gpointer data _U_) { float pot; GtkTreeIter parent; int type, kind; gchar *lbl; gtk_tree_model_get(model, iter, POTENTIAL_COLUMN, &pot, TYPE_COLUMN, &kind, -1); type = SURFACE_SURF; if (gtk_tree_model_iter_parent(model, &parent, iter)) gtk_tree_model_get(model, &parent, TYPE_COLUMN, &type, -1); lbl = g_strdup_printf("%g", pot); g_object_set(G_OBJECT(cell), "visible", (kind == SURFACE_SURF && pot != G_MAXFLOAT), "text", lbl, "editable", (type == SURFACE_FILE_DENPOT), "foreground", (type == SURFACE_FILE_DENPOT) ? "blue" : NULL, NULL); g_free(lbl); } static void onDisplayColor(GtkTreeViewColumn *column _U_, GtkCellRenderer *cell, GtkTreeModel *model, GtkTreeIter *iter, gpointer data _U_) { RowSurface *row; GdkPixbuf *pixbuf; gtk_tree_model_get(model, iter, BOX_ROW_COLUMN, &row, -1); if (row) { pixbuf = tool_color_get_stamp(visu_surface_resource_getColor(row->res), TRUE); g_object_set(cell, "pixbuf", pixbuf, NULL); g_object_unref(pixbuf); row_surface_free(row); } g_object_set(cell, "visible", (row != NULL), NULL); } static void onDisplayMask(GtkTreeViewColumn *column _U_, GtkCellRenderer *cell, GtkTreeModel *model, GtkTreeIter *iter, gpointer data _U_) { RowSurface *row; gtk_tree_model_get(model, iter, BOX_ROW_COLUMN, &row, -1); g_object_set(G_OBJECT(cell), "visible", (row != NULL), "active", (row) ? visu_surface_resource_getMaskable(row->res) : FALSE, NULL); if (row) row_surface_free(row); } /* Sets up the model/view architecture used to store the surfaces info. */ static void isosurfaces_make_tree_view(VisuGlExtSurfaces *surfs) { GtkWidget *image; GtkCellRenderer *renderer; GtkTreeViewColumn *column = NULL; treeStore = gtk_tree_store_new(N_COLUMNS, G_TYPE_INT, /* TYPE_COLUMN */ G_TYPE_STRING, /* LABEL_COLUMN */ G_TYPE_FLOAT, /* POTENTIAL_COLUMN */ TOOL_TYPE_SHADE, /* SHADE_COLUMN */ TYPE_ROW_POTENTIAL, /* ROW_FIELD_COLUMN */ TYPE_ROW_SURFACE); /* BOX_ROW_COLUMN */ g_signal_connect(surfs, "added", G_CALLBACK(onSurfaceAdded), (gpointer)treeStore); g_signal_connect(surfs, "removed", G_CALLBACK(onSurfaceRemoved), (gpointer)treeStore); treeView = gtk_tree_view_new_with_model(GTK_TREE_MODEL(treeStore)); renderer = gtk_cell_renderer_text_new(); g_signal_connect(G_OBJECT(renderer), "edited", G_CALLBACK(onNameEdited), treeStore); column = gtk_tree_view_column_new(); gtk_tree_view_column_pack_start(column, renderer, TRUE); gtk_tree_view_column_set_cell_data_func(column, renderer, onDisplayLabel, (gpointer)0, (GDestroyNotify)0); gtk_tree_view_column_set_title(column, _("File / label")); gtk_tree_view_column_set_expand(column, TRUE); gtk_tree_view_column_set_alignment(column, 0); gtk_tree_view_column_set_resizable(column, TRUE); gtk_tree_view_append_column(GTK_TREE_VIEW(treeView), column); renderer = gtk_cell_renderer_toggle_new(); g_signal_connect(renderer, "toggled", G_CALLBACK(onDisplayToggled), treeStore); column = gtk_tree_view_column_new(); gtk_tree_view_column_pack_start(column, renderer, TRUE); gtk_tree_view_column_set_cell_data_func(column, renderer, onDisplayShow, treeStore, (GDestroyNotify)0); gtk_tree_view_column_set_expand(column, FALSE); gtk_tree_view_column_set_alignment(column, 0.5); gtk_tree_view_append_column(GTK_TREE_VIEW(treeView), column); renderer = gtk_cell_renderer_text_new(); g_signal_connect(G_OBJECT(renderer), "edited", G_CALLBACK(onPotentialValueEdited), treeStore); column = gtk_tree_view_column_new(); gtk_tree_view_column_pack_start(column, renderer, TRUE); gtk_tree_view_column_set_cell_data_func(column, renderer, onDisplayPot, treeStore, (GDestroyNotify)0); gtk_tree_view_column_set_title(column, _("Value")); gtk_tree_view_column_set_sort_column_id(GTK_TREE_VIEW_COLUMN(column), POTENTIAL_COLUMN); gtk_tree_view_append_column(GTK_TREE_VIEW(treeView), column); renderer = gtk_cell_renderer_pixbuf_new (); column = gtk_tree_view_column_new(); gtk_tree_view_column_pack_start(column, renderer, TRUE); gtk_tree_view_column_set_cell_data_func(column, renderer, onDisplayColor, treeStore, (GDestroyNotify)0); image = gtk_image_new_from_icon_name("applications-graphics", GTK_ICON_SIZE_SMALL_TOOLBAR); gtk_widget_show(image); gtk_tree_view_column_set_widget(column, image); gtk_tree_view_append_column(GTK_TREE_VIEW(treeView), column); colorColumn = column; renderer = gtk_cell_renderer_toggle_new(); g_signal_connect(G_OBJECT(renderer), "toggled", G_CALLBACK(onMaskingToggled), treeStore); column = gtk_tree_view_column_new(); gtk_tree_view_column_pack_start(column, renderer, TRUE); gtk_tree_view_column_set_cell_data_func(column, renderer, onDisplayMask, treeStore, (GDestroyNotify)0); image = create_pixmap((GtkWidget*)0, "stock-masking.png"); gtk_widget_show(image); gtk_tree_view_column_set_widget(column, image); gtk_tree_view_append_column(GTK_TREE_VIEW(treeView), column); gtk_tree_view_set_headers_visible(GTK_TREE_VIEW(treeView), TRUE); g_signal_connect(gtk_tree_view_get_selection(GTK_TREE_VIEW(treeView)), "changed", G_CALLBACK(onTreeSelectionChanged), (gpointer)0); g_signal_connect(G_OBJECT(treeView), "button-release-event", G_CALLBACK(onTreeViewClicked), (gpointer)0); g_signal_connect(G_OBJECT(treeView), "row-activated", G_CALLBACK(onTreeViewActivated), (gpointer)0); } /* Callback for time interval value spin button. Changes the frequency used to play the surfaces. */ static void isosurfaces_change_time_interval(GtkWidget *spin_button _U_, GtkWidget *play_stop) { gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON(play_stop), FALSE); } static void _compute(GtkTreeIter *iter, const float *values, const gchar **names, guint nValues) { VisuSurface *surf; RowPotential *row; guint i, type; GtkTreeIter child; gtk_tree_model_get(GTK_TREE_MODEL(treeStore), iter, TYPE_COLUMN, &type, ROW_FIELD_COLUMN, &row, -1); g_return_if_fail(type == SURFACE_FILE_DENPOT); for (i = 0; i < nValues; i++) { surf = visu_surface_new_fromScalarField(row->field, values[i], names[i]); if (surf) visu_ui_panel_surfaces_addSurface(surf, iter, &child); } row_potential_free(row); } static gboolean panel_isosurfaces_remove(GtkTreeModel *model, GtkTreeIter *iter) { int type; gboolean valid; GtkTreeIter parent, child; g_return_val_if_fail(iter, FALSE); gtk_tree_model_get(model, iter, TYPE_COLUMN, &type, -1); switch (type) { case SURFACE_FILE_DENPOT: /* If the denpot has children, we remove them. And don't delete the data. */ if (gtk_tree_model_iter_has_child(model, iter)) { for (valid = gtk_tree_model_iter_children(model, &child, iter); valid; valid = gtk_tree_model_iter_children(model, &child, iter)) gtk_tree_store_remove(GTK_TREE_STORE(model), &child); visu_ui_value_io_setSensitiveSave(VISU_UI_VALUE_IO(valueIO), FALSE); return TRUE; } else gtk_tree_store_remove(GTK_TREE_STORE(model), iter); return TRUE; case SURFACE_FILE_SURF: /* We remove the entry from the tree. */ gtk_tree_store_remove(GTK_TREE_STORE(model), iter); /* We need to rebuild the order list. */ return TRUE; case SURFACE_SURF: if (gtk_tree_model_iter_parent(model, &parent, iter)) { gtk_tree_model_get(model, &parent, TYPE_COLUMN, &type, -1); if (type == SURFACE_FILE_SURF && gtk_tree_model_iter_n_children(model, &parent) == 1) gtk_tree_store_remove(GTK_TREE_STORE(model), &parent); else gtk_tree_store_remove(GTK_TREE_STORE(model), iter); } else gtk_tree_store_remove(GTK_TREE_STORE(model), iter); /* We need to rebuild the order list. */ return TRUE; default: g_warning("Wrong type for the selected entry."); } return FALSE; } static void _destroyStore(GtkTreeStore *model) { DBG_fprintf(stderr, "Panel Surfaces: destroying surfaces model.\n"); gtk_tree_store_clear(model); g_object_unref(model); } /* Creates the main panel. */ void isosurfaces_create_gtk_interface(VisuUiPanel *visu_ui_panel) { #if GTK_MAJOR_VERSION == 2 && GTK_MINOR_VERSION < 12 GtkTooltips *tooltips = gtk_tooltips_new (); #endif GtkWidget *top_hbox = gtk_hbox_new (FALSE, 0); GtkWidget *h_box3 = gtk_hbox_new (FALSE, 0); GtkWidget *show_all = gtk_button_new(); GtkWidget *show_none = gtk_button_new(); GtkWidget *play_stop = gtk_toggle_button_new_with_label(_("Play")); GtkWidget *time_interval = gtk_spin_button_new_with_range (50, 2000, 10); GtkWidget *scrolled_window = gtk_scrolled_window_new (NULL, NULL); /* GtkWidget *reorder_button = gtk_button_new_with_label("Re-order"); */ GtkWidget *image_color = create_pixmap((GtkWidget*)0, "stock_effects-object-colorize_20.png"); GtkWidget *image_show = create_pixmap((GtkWidget*)0, "stock-select-all_20.png"); GtkWidget *image_hide = create_pixmap((GtkWidget*)0, "stock-unselect-all_20.png"); GtkWidget *tree_vbox = gtk_vbox_new(FALSE, 0); GtkWidget *tree_hbox = gtk_hbox_new(FALSE, 0); GtkWidget *image, *vbox, *wd; VisuGlExtSurfaces *surfs; VisuGlNodeScene *scene; vbox = gtk_vbox_new(FALSE, 0); scene = visu_ui_rendering_window_getGlScene(visu_ui_main_class_getDefaultRendering()); surfs = visu_gl_node_scene_addSurfaces(scene); wd = gtk_check_button_new_with_mnemonic(_("_Use isosurfaces")); g_object_bind_property(surfs, "active", wd, "active", G_BINDING_SYNC_CREATE | G_BINDING_BIDIRECTIONAL); gtk_box_pack_start(GTK_BOX(vbox), wd, FALSE, FALSE, 0); buttonEdit = gtk_button_new(); gtk_widget_set_sensitive(buttonEdit, FALSE); gtk_container_add(GTK_CONTAINER(buttonEdit), image_color); gtk_container_add(GTK_CONTAINER(show_all), image_show); gtk_container_add(GTK_CONTAINER(show_none), image_hide); /* The line about loading files. */ gtk_box_pack_start(GTK_BOX(vbox), top_hbox, FALSE, FALSE, 0); checkAutoLoad = gtk_check_button_new_with_mnemonic(_("Auto _load data file")); gtk_widget_set_margin_top(checkAutoLoad, 10); gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON(checkAutoLoad), autoload_file); gtk_widget_set_tooltip_text(checkAutoLoad, _("Try to load a data file whenever a new V_Sim file is loaded." " If the new file contains a scalar field, it is loaded, otherwise" " a surface file is tested using a .surf extension on the file name.")); gtk_box_pack_start(GTK_BOX(top_hbox), checkAutoLoad, TRUE, TRUE, 2); buttonOpen = gtk_button_new(); buttonConvert = gtk_button_new_with_mnemonic(_("_Convert")); gtk_widget_set_tooltip_text(buttonOpen, _("Load a surface file or a potential/density file.")); gtk_box_pack_end(GTK_BOX(top_hbox), buttonOpen, FALSE, FALSE, 2); image = gtk_image_new_from_icon_name("document-open", GTK_ICON_SIZE_BUTTON); gtk_container_add(GTK_CONTAINER( buttonOpen), image); gtk_widget_set_tooltip_text(buttonConvert, _("Several built-in tools to create .surf files.")); gtk_box_pack_end(GTK_BOX(top_hbox), buttonConvert, FALSE, FALSE, 2); isosurfaces_make_tree_view(surfs); g_signal_connect_swapped(visu_ui_panel, "destroy", G_CALLBACK(_destroyStore), treeStore); isosurfaces_gtk_vbox = gtk_vbox_new(FALSE, 0); gtk_box_pack_start(GTK_BOX(vbox), isosurfaces_gtk_vbox, TRUE, TRUE, 0); auto_reorder = gtk_check_button_new_with_mnemonic(_("_Reorder on the fly")); gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON(auto_reorder), FALSE); /* gtk_widget_set_sensitive(reorder_button, FALSE); */ gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON(play_stop), FALSE); g_signal_connect(G_OBJECT(auto_reorder), "toggled", G_CALLBACK(onReorderToggled), surfs); /* g_signal_connect(G_OBJECT(reorder_button), "clicked", */ /* G_CALLBACK(isosurfaces_rebuild_gl_list_in_order_and_redraw), NULL); */ g_signal_connect(G_OBJECT(buttonOpen), "clicked", G_CALLBACK(onOpenClicked), scene); g_signal_connect(G_OBJECT(buttonConvert), "clicked", G_CALLBACK(visu_ui_panel_surfaces_tools_init), (gpointer)0); g_signal_connect(G_OBJECT(buttonEdit), "clicked", G_CALLBACK(onEditPropertiesClicked), (gpointer)0); g_signal_connect(G_OBJECT(show_all), "clicked", G_CALLBACK(onShowHideAllButton), GINT_TO_POINTER(1)); g_signal_connect(G_OBJECT(show_none), "clicked", G_CALLBACK(onShowHideAllButton), GINT_TO_POINTER(0)); g_signal_connect(G_OBJECT(play_stop), "toggled", G_CALLBACK(isosurfaces_play), time_interval); g_signal_connect(G_OBJECT(time_interval), "value_changed", G_CALLBACK(isosurfaces_change_time_interval), play_stop); /* The main viewport. */ gtk_box_pack_start(GTK_BOX(isosurfaces_gtk_vbox), tree_hbox, TRUE, TRUE, 0); gtk_box_pack_start(GTK_BOX(tree_hbox), scrolled_window, TRUE, TRUE, 0); gtk_scrolled_window_set_policy(GTK_SCROLLED_WINDOW(scrolled_window), GTK_POLICY_AUTOMATIC, GTK_POLICY_AUTOMATIC); gtk_scrolled_window_set_shadow_type (GTK_SCROLLED_WINDOW (scrolled_window), GTK_SHADOW_IN); gtk_container_add (GTK_CONTAINER (scrolled_window), treeView); gtk_box_pack_start(GTK_BOX(tree_hbox), tree_vbox, FALSE, FALSE, 2); gtk_widget_set_tooltip_text(show_none, _("Hides all surfaces")); gtk_box_pack_start(GTK_BOX(tree_vbox), show_none, FALSE, FALSE, 2); gtk_widget_set_tooltip_text(show_all, _("Shows all surfaces")); gtk_box_pack_start(GTK_BOX(tree_vbox), show_all, FALSE, FALSE, 2); gtk_widget_set_tooltip_text(buttonEdit, _("Change color and material properties.")); gtk_box_pack_end(GTK_BOX(tree_vbox), buttonEdit, FALSE, FALSE, 2); buttonAddSurface = gtk_button_new(); gtk_widget_set_valign(buttonAddSurface, GTK_ALIGN_END); gtk_widget_set_sensitive(buttonAddSurface, FALSE); gtk_widget_set_tooltip_text(buttonAddSurface, _("Add a new surface.")); g_signal_connect(G_OBJECT(buttonAddSurface), "clicked", G_CALLBACK(onAddButtonClicked), NULL); gtk_box_pack_start(GTK_BOX(tree_vbox), buttonAddSurface, TRUE, TRUE, 2); image = gtk_image_new_from_icon_name("list-add", GTK_ICON_SIZE_BUTTON); gtk_container_add(GTK_CONTAINER(buttonAddSurface), image); buttonAddSpecial = gtk_button_new(); gtk_widget_set_sensitive(buttonAddSpecial, FALSE); gtk_widget_set_tooltip_text(buttonAddSpecial, _("Add many surfaces to the list of surfaces.")); g_signal_connect(G_OBJECT(buttonAddSpecial), "clicked", G_CALLBACK(onAddSpecialButtonClicked), NULL); gtk_box_pack_start(GTK_BOX(tree_vbox), buttonAddSpecial, FALSE, FALSE, 2); image = gtk_image_new_from_icon_name("system-run", GTK_ICON_SIZE_BUTTON); gtk_container_add(GTK_CONTAINER(buttonAddSpecial), image); buttonRemoveSurface = gtk_button_new (); gtk_widget_set_valign(buttonRemoveSurface, GTK_ALIGN_START); gtk_widget_set_sensitive(buttonRemoveSurface, FALSE); gtk_widget_set_tooltip_text(buttonRemoveSurface, _("Remove selected surface or file.")); g_signal_connect(G_OBJECT(buttonRemoveSurface), "clicked", G_CALLBACK(onRemoveButtonClicked), NULL); gtk_box_pack_start(GTK_BOX(tree_vbox), buttonRemoveSurface, TRUE, TRUE, 2); image = gtk_image_new_from_icon_name("list-remove", GTK_ICON_SIZE_BUTTON); gtk_container_add (GTK_CONTAINER(buttonRemoveSurface), image); /* The surfaces tool line. */ gtk_box_pack_start(GTK_BOX(isosurfaces_gtk_vbox), h_box3, FALSE, FALSE, 0); gtk_widget_set_tooltip_text(play_stop, _("Starts/stops showing isosurfaces at specified rate")); gtk_box_pack_start(GTK_BOX(h_box3), play_stop, FALSE, FALSE, 0); gtk_box_pack_start(GTK_BOX(h_box3), gtk_label_new(_("@")), FALSE, FALSE, 0); gtk_widget_set_tooltip_text(time_interval, _("Selects rate to show isosurfaces")); gtk_entry_set_width_chars(GTK_ENTRY(time_interval), 3); gtk_box_pack_start(GTK_BOX(h_box3), time_interval, FALSE, FALSE, 0); gtk_box_pack_start(GTK_BOX(h_box3), gtk_label_new(_("ms")), FALSE, FALSE, 0); valueIO = visu_ui_value_io_new(visu_ui_panel_getContainerWindow(VISU_UI_PANEL(panelSurfaces)), _("Import iso-values from an existing XML file."), _("Export iso-values to the current XML file."), _("Export iso-values to a new XML file.")); visu_ui_value_io_connectOnOpen(VISU_UI_VALUE_IO(valueIO), loadXMLFile); visu_ui_value_io_connectOnSave(VISU_UI_VALUE_IO(valueIO), visu_ui_panel_surfaces_exportXMLFile); gtk_widget_set_margin_start(valueIO, 20); gtk_box_pack_end(GTK_BOX(h_box3), valueIO, TRUE, TRUE, 0); /* The option line. */ h_box3 = gtk_hbox_new(FALSE, 0); gtk_box_pack_start(GTK_BOX(isosurfaces_gtk_vbox), h_box3, FALSE, FALSE, 0); checkDrawIntra = gtk_check_button_new_with_mnemonic(_("Draw _intra surfaces")); gtk_widget_set_tooltip_text(checkDrawIntra, _("Draw the interior of iso-surfaces with the complementary colour.")); g_object_bind_property(surfs, "draw-intra", checkDrawIntra, "active", G_BINDING_BIDIRECTIONAL | G_BINDING_SYNC_CREATE); gtk_box_pack_start(GTK_BOX(h_box3), checkDrawIntra, FALSE, FALSE, 0); gtk_box_pack_end(GTK_BOX(h_box3), auto_reorder, FALSE, FALSE, 0); gtk_widget_set_tooltip_text(auto_reorder, _("Automatically re-orders surfaces in back to front order" " whenever camera is modified (can be slow but get rid of" " transparency problems). This has no effect if the" " transparency option of the OpenGL panel is set")); gtk_widget_show_all(vbox); gtk_container_add(GTK_CONTAINER(visu_ui_panel), vbox); } /** * visu_ui_panel_surfaces_parseXMLFile: * @filename: a location to read the XML data. * @error: a location to store possible error. * * This routine reads an XML file and setup the resources and the * isovalues to the selected row accordingly. * * Returns: TRUE on success. */ gboolean visu_ui_panel_surfaces_parseXMLFile(const gchar *filename, GError **error) { GtkTreeModel *model; GtkTreeIter iter, child; GList *surfaces, *lst; RowPotential *row; int type; /* VisuData *dataObj; */ g_return_val_if_fail(getSelectedRow(&model, &iter), FALSE); gtk_tree_model_get(model, &iter, TYPE_COLUMN, &type, ROW_FIELD_COLUMN, &row, -1); g_return_val_if_fail(type == SURFACE_FILE_DENPOT, FALSE); if (!visu_surface_parseXMLFile(filename, &surfaces, row->field, error)) { row_potential_free(row); return FALSE; } row_potential_free(row); for (lst = surfaces; lst; lst = g_list_next(lst)) visu_ui_panel_surfaces_addSurface(VISU_SURFACE(lst->data), &iter, &child); g_list_free(surfaces); return TRUE; } static gboolean loadXMLFile(const gchar *filename, GError **error) { if (visu_ui_panel_surfaces_parseXMLFile(filename, error)) { /* Update the sensitivity. */ visu_ui_value_io_setSensitiveSave(VISU_UI_VALUE_IO(valueIO), TRUE); return TRUE; } else return FALSE; } /** * visu_ui_panel_surfaces_exportXMLFile: * @filename: a filename to export to. * @error: (allow-none): a location to store an error. * * Export to @filename the list of isosurfaces values of the selected * scalar-field file. * * Since: 3.7 * * Returns: TRUE if everything goes right. **/ gboolean visu_ui_panel_surfaces_exportXMLFile(const gchar *filename, GError **error) { GtkTreeModel *model; GtkTreeIter iter, child; int n; float *values; gboolean valid; RowSurface *row; VisuSurfaceResource **res; if (!getSelectedRow(&model, &iter)) return TRUE; n = gtk_tree_model_iter_n_children(model, &iter); values = g_malloc(sizeof(float) * n); res = g_malloc(sizeof(VisuSurfaceResource*) * n); for (valid = gtk_tree_model_iter_children(model, &child, &iter), n = 0; valid; valid = gtk_tree_model_iter_next(model, &child)) { gtk_tree_model_get(model, &child, BOX_ROW_COLUMN, &row, POTENTIAL_COLUMN, values + n, -1); res[n] = row->res; row_surface_free(row); if (values[n] != G_MAXFLOAT) n += 1; } valid = TRUE; if (n > 0) valid = visu_surface_exportXMLFile(filename, values, res, n, error); g_free(res); g_free(values); return valid; } /* static VisuSurface** getAllVisuSurfaceList() */ /* { */ /* int n; */ /* gboolean valid; */ /* GtkTreeIter iter; */ /* VisuSurface **surfaces; */ /* n = gtk_tree_model_iter_n_children(GTK_TREE_MODEL(isosurfaces_data_list), */ /* (GtkTreeIter*)0); */ /* surfaces = g_malloc(sizeof(VisuSurface*) * (n + 1)); */ /* n = 0; */ /* valid = gtk_tree_model_get_iter_first(GTK_TREE_MODEL(isosurfaces_data_list), &iter); */ /* while (valid) */ /* { */ /* gtk_tree_model_get(GTK_TREE_MODEL(isosurfaces_data_list), */ /* &iter, OBJ_SURF_COLUMN, surfaces + n, -1); */ /* /\* In case the surface n is NULL, we don't count it. *\/ */ /* if (surfaces[n]) */ /* n += 1; */ /* valid = gtk_tree_model_iter_next(GTK_TREE_MODEL(isosurfaces_data_list), &iter); */ /* } */ /* surfaces[n] = (VisuSurface*)0; */ /* DBG_fprintf(stderr, "Panel VisuSurface: get list of all surfaces (%d).\n", n); */ /* return surfaces; */ /* } */ static void onTreeSelectionChanged(GtkTreeSelection *tree, gpointer data _U_) { gboolean res; GtkTreeModel *model; GtkTreeIter iter; int type; RowPotential *row; double mimax[2]; gboolean empty, hasChildren; DBG_fprintf(stderr, "Panel VisuSurface: catch 'changed' signal from " "the gtkTreeSelection.\n"); res = gtk_tree_selection_get_selected(tree, &model, &iter); if (res) { gtk_tree_model_get(model, &iter, TYPE_COLUMN, &type, ROW_FIELD_COLUMN, &row, -1); hasChildren = (type == SURFACE_FILE_DENPOT) && gtk_tree_model_iter_has_child(model, &iter); if (type == SURFACE_FILE_DENPOT) visu_scalar_field_getMinMax(row->field, mimax); if (row) row_potential_free(row); } else { type = -1; mimax[0] = 0.; mimax[1] = 1.; hasChildren = FALSE; } empty = !gtk_tree_model_get_iter_first(GTK_TREE_MODEL(treeStore), &iter); gtk_widget_set_sensitive(buttonRemoveSurface, (type >= 0)); gtk_widget_set_sensitive(buttonAddSurface, (type == SURFACE_FILE_DENPOT)); gtk_widget_set_sensitive(buttonAddSpecial, (type == SURFACE_FILE_DENPOT && mimax[0] <= mimax[1])); gtk_widget_set_sensitive(buttonEdit, !empty); visu_ui_value_io_setSensitiveOpen(VISU_UI_VALUE_IO(valueIO), (type == SURFACE_FILE_DENPOT)); visu_ui_value_io_setSensitiveSave(VISU_UI_VALUE_IO(valueIO), (type == SURFACE_FILE_DENPOT && hasChildren)); if (GTK_IS_WINDOW(edit_window)) panelIsosurfacesUpdate_surfaceProperties(); } static void onAddButtonClicked(GtkButton *button _U_, gpointer data _U_) { gboolean valid; GtkTreeModel *model; GtkTreeIter iter, child; int type; RowPotential *row; VisuSurface *neg, *pos; valid = getSelectedRow(&model, &iter); g_return_if_fail(valid); gtk_tree_model_get(GTK_TREE_MODEL(treeStore), &iter, TYPE_COLUMN, &type, ROW_FIELD_COLUMN, &row, -1); g_return_if_fail(type == SURFACE_FILE_DENPOT); visu_surface_new_defaultFromScalarField(row->field, &neg, &pos); if (neg) visu_ui_panel_surfaces_addSurface(neg, &iter, &child); if (pos) visu_ui_panel_surfaces_addSurface(pos, &iter, &child); row_potential_free(row); } static void onAddSpecialButtonClicked(GtkButton *button _U_, gpointer data _U_) { gboolean valid; GtkTreeModel *model; GtkTreeIter iter; float *values; int nbValues; RowPotential *row; int type, i; double mimax[2]; gchar *name; const gchar *names[1]; GtkWidget *dialog, *progress; char mess[50]; GList *lst, *children; valid = getSelectedRow(&model, &iter); g_return_if_fail(valid); gtk_tree_model_get(model, &iter, TYPE_COLUMN, &type, ROW_FIELD_COLUMN, &row, -1); g_return_if_fail(type == SURFACE_FILE_DENPOT && row); visu_scalar_field_getMinMax(row->field, mimax); row_potential_free(row); g_return_if_fail(mimax[0] <= mimax[1]); values = (float*)0; name = (gchar*)0; dialog = visu_ui_panel_surfaces_generateValues(&nbValues, &values, &name, (float)mimax[0], (float)mimax[1]); names[0] = name; if (!dialog) return; progress = (GtkWidget*)0; children = gtk_container_get_children (GTK_CONTAINER(gtk_dialog_get_content_area(GTK_DIALOG(dialog)))); for (lst = children; lst; lst = lst->next) { gtk_widget_set_sensitive(GTK_WIDGET(lst->data), FALSE); if (GTK_IS_PROGRESS_BAR(lst->data)) progress = GTK_WIDGET(lst->data); } g_list_free(children); for (i = 0; i < nbValues; i++) { sprintf(mess, "%d/%d", i + 1, nbValues); gtk_progress_bar_set_text(GTK_PROGRESS_BAR(progress), mess); gtk_progress_bar_set_fraction(GTK_PROGRESS_BAR(progress), (float)i/(float)nbValues); visu_ui_wait(); _compute(&iter, values + i, names, 1); } gtk_widget_destroy(dialog); if (values) g_free(values); if (name) g_free(name); visu_ui_value_io_setSensitiveSave(VISU_UI_VALUE_IO(valueIO), TRUE); } static void onRemoveButtonClicked(GtkButton *button _U_, gpointer data _U_) { gboolean valid; GtkTreeModel *model; GtkTreeIter iter; valid = getSelectedRow(&model, &iter); g_return_if_fail(valid); panel_isosurfaces_remove(model, &iter); } static void onNameEdited(GtkCellRendererText *cellrenderertext _U_, gchar *path, gchar *text, gpointer user_data) { GtkTreeIter iter; gboolean status; int type; VisuSurfaceResource *res; RowSurface *row; if (!strcmp(text, VISU_UI_SURFACE_NAME_STR)) return; status = gtk_tree_model_get_iter_from_string(GTK_TREE_MODEL(user_data), &iter, path); g_return_if_fail(status); /* We get the VisuSurface of the edited object. */ gtk_tree_model_get(GTK_TREE_MODEL(user_data), &iter, BOX_ROW_COLUMN, &row, TYPE_COLUMN, &type, -1); g_return_if_fail(type == SURFACE_SURF && row); /* We change the resource of the edited surface. */ res = visu_surface_resource_new_fromCopy(text, row->res); DBG_fprintf(stderr, "Panel VisuSurface: new resources %p (%s).\n", (gpointer)res, visu_surface_resource_getLabel(res)); /* We set the new resource (may free the old one). */ visu_surface_setResource(row->surf, res); g_object_unref(res); row_surface_free(row); } static void onPotentialValueEdited(GtkCellRendererText *cell, gchar *path, gchar *text, gpointer user_data) { GtkTreeIter iter, parent; GtkTreePath *treePath; float value = atof(text); VisuSurface *surf; RowPotential *field; int type; double minmax[2]; gboolean status; gchar *str; RowSurface *row; VisuGlExtSurfaces *surfs; status = gtk_tree_model_get_iter_from_string(GTK_TREE_MODEL(user_data), &iter, path); g_return_if_fail(status); gtk_tree_model_iter_parent(GTK_TREE_MODEL(user_data), &parent, &iter); gtk_tree_model_get(GTK_TREE_MODEL(user_data), &parent, ROW_FIELD_COLUMN, &field, TYPE_COLUMN, &type, -1); g_return_if_fail(type == SURFACE_FILE_DENPOT && field); visu_scalar_field_getMinMax(field->field, minmax); g_return_if_fail(minmax[0] > minmax[1] || (value >= minmax[0] && value <= minmax[1])); /* We add the new surface. */ DBG_fprintf(stderr, "Panel VisuSurface: create surface with id %d.\n", 0); surf = visu_surface_new_fromScalarField(field->field, value, (const gchar*)0); row_potential_free(field); if (!surf) { /* Put back the old value. */ gtk_tree_model_get(GTK_TREE_MODEL(user_data), &iter, POTENTIAL_COLUMN, &value, -1); str = g_strdup_printf("%g", value); g_object_set(G_OBJECT(cell), "text", str, NULL); g_free(str); return; } gtk_tree_model_get(GTK_TREE_MODEL(user_data), &iter, BOX_ROW_COLUMN, &row, -1); visu_surface_setResource(surf, row->res); row_surface_free(row); surfs = visu_gl_node_scene_addSurfaces(visu_ui_rendering_window_getGlScene(visu_ui_main_class_getDefaultRendering())); connectSurface(GTK_TREE_STORE(user_data), &iter, surfs, surf); g_object_unref(surf); /* We reselect the right iter. */ treePath = gtk_tree_path_new_from_string(path); gtk_tree_selection_select_path (gtk_tree_view_get_selection(GTK_TREE_VIEW(treeView)), treePath); gtk_tree_path_free(treePath); } static void onReorderToggled(GtkToggleButton *toggle, VisuGlExtSurfaces *surfs) { visu_gl_ext_setGlView(VISU_GL_EXT(surfs), (gtk_toggle_button_get_active(toggle))?visu_ui_panel_getView(VISU_UI_PANEL(panelSurfaces)):(VisuGlView*)0); } static void onDataFocused(GObject *visu _U_, VisuData *dataObj, gpointer data _U_) { GtkTreeIter iter, child; gboolean valid, *flag; int type, n; gchar *fileCpy, *fileExtPosition; GString *dataFile; float *isoValues; int nValues; const gchar **isoNames; DBG_fprintf(stderr, "Panel Surfaces: caught the 'DataFocused'" " signal.\n | setting sensititvity.\n"); if (dataObj) { gtk_widget_set_sensitive(isosurfaces_gtk_vbox, TRUE); gtk_widget_set_sensitive(buttonOpen, TRUE); gtk_widget_set_sensitive(buttonConvert, TRUE); } else { gtk_widget_set_sensitive(isosurfaces_gtk_vbox, FALSE); gtk_widget_set_sensitive(buttonOpen, FALSE); gtk_widget_set_sensitive(buttonConvert, FALSE); } DBG_fprintf(stderr, " | update list of surfaces and fields.\n"); /* Store all isovalues into isoValues array. */ nValues = 0; isoValues = (float*)0; isoNames = (const gchar**)0; /* Remove all scalar-fields. */ for (valid = gtk_tree_model_get_iter_first(GTK_TREE_MODEL(treeStore), &iter); valid; valid = gtk_tree_model_iter_next(GTK_TREE_MODEL(treeStore), &iter)) { gtk_tree_model_get(GTK_TREE_MODEL(treeStore), &iter, TYPE_COLUMN, &type, -1); nValues = gtk_tree_model_iter_n_children(GTK_TREE_MODEL(treeStore), &iter); /* If the data is a field, we store all its values and names. */ if (type == SURFACE_FILE_DENPOT && nValues > 0 && !isoValues) { isoValues = g_malloc(sizeof(float) * nValues); isoNames = g_malloc(sizeof(const gchar*) * (nValues + 1)); for (valid = gtk_tree_model_iter_children(GTK_TREE_MODEL(treeStore), &child, &iter), n = 0; valid; valid = gtk_tree_model_iter_next(GTK_TREE_MODEL(treeStore), &child), n += 1) gtk_tree_model_get(GTK_TREE_MODEL(treeStore), &child, POTENTIAL_COLUMN, isoValues + n, LABEL_COLUMN, isoNames + n, -1); isoNames[nValues] = (gchar*)0; } } gtk_tree_store_clear(treeStore); /* If the flag of autoload is not checked or no data is available, we return. */ if (!dataObj || !gtk_toggle_button_get_active(GTK_TOGGLE_BUTTON(checkAutoLoad))) { g_free(isoValues); g_free(isoNames); return; } /* Read if the new file has the VISU_SCALAR_FIELD_DEFINED_IN_STRUCT_FILE flag. */ flag = (gboolean*)g_object_get_data(G_OBJECT(dataObj), VISU_SCALAR_FIELD_DEFINED_IN_STRUCT_FILE); fileCpy = g_strdup(visu_data_loadable_getFilename(VISU_DATA_LOADABLE(dataObj), 0)); if (!flag) { /* We try to find a surf file with the right name. */ fileExtPosition = g_strrstr(fileCpy, "."); if (fileExtPosition) *fileExtPosition = '\0'; dataFile = g_string_new(""); g_string_printf(dataFile, "%s.%s", fileCpy, "surf"); g_free(fileCpy); DBG_fprintf(stderr, "Panel VisuSurface: try to load a new surface file" " ('%s') from the name of the rendered file.\n", dataFile->str); fileCpy = dataFile->str; g_string_free(dataFile, FALSE); if (!g_file_test(fileCpy, G_FILE_TEST_EXISTS)) { g_free(fileCpy); fileCpy = (gchar*)0; DBG_fprintf(stderr, " | file doesn't exist.\n"); } } if (fileCpy) { visu_ui_panel_surfaces_loadFile(fileCpy, &iter, (GHashTable*)0, (VisuScalarFieldMethod*)0); g_free(fileCpy); /* We create the surfaces for the values readed from isoValues. */ valid = gtk_tree_model_get_iter_first(GTK_TREE_MODEL(treeStore), &iter); if (valid && isoValues) { gtk_tree_model_get(GTK_TREE_MODEL(treeStore), &iter, TYPE_COLUMN, &type, -1); if (type == SURFACE_FILE_DENPOT) _compute(&iter, isoValues, isoNames, nValues); } } g_free(isoValues); g_free(isoNames); } static gboolean onPopupClicked(GtkWidget *widget, GdkEventButton *event _U_, gpointer user_data _U_) { gtk_widget_destroy(widget); return FALSE; } static gboolean onTreeViewClicked(GtkWidget *widget, GdkEventButton *event, gpointer user_data _U_) { gboolean valid; GtkTreePath *path; GtkTreeIter iter; int type, row; RowPotential *field; GtkWidget *win, *vbox, *wd, *table; gchar *name, *markup; const gchar *comment; gint x, y; GList *options, *tmplst; if (event->button != 3) return FALSE; DBG_fprintf(stderr, "Panel VisuSurface: right clic detected.\n"); valid = gtk_tree_view_get_path_at_pos(GTK_TREE_VIEW(widget), (gint)event->x, (gint)event->y, &path, (GtkTreeViewColumn**)0, (gint*)0, (gint*)0); if (!valid) return FALSE; valid = gtk_tree_model_get_iter(GTK_TREE_MODEL(treeStore), &iter, path); gtk_tree_path_free(path); if (!valid) return FALSE; gtk_tree_model_get(GTK_TREE_MODEL(treeStore), &iter, ROW_FIELD_COLUMN, &field, TYPE_COLUMN, &type, -1); if (type != SURFACE_FILE_DENPOT) return FALSE; g_return_val_if_fail(field, FALSE); /* Ok, now, we have the scalar field. We create a popup window with info. */ win = gtk_window_new(GTK_WINDOW_POPUP); gtk_widget_set_events(win, GDK_BUTTON_PRESS_MASK | GDK_BUTTON_RELEASE_MASK | GDK_KEY_PRESS_MASK); gtk_grab_add(win); #if GTK_MAJOR_VERSION > 2 gdk_device_get_position(event->device, NULL, &x, &y); #else gdk_display_get_pointer(gdk_screen_get_display(gtk_widget_get_screen(widget)), (GdkScreen**)0, &x, &y, NULL); #endif gtk_window_move(GTK_WINDOW(win), x, y); g_signal_connect(G_OBJECT(win), "button-press-event", G_CALLBACK(onPopupClicked), (gpointer)0); gtk_container_set_border_width(GTK_CONTAINER(win), 20); vbox = gtk_vbox_new(FALSE, 0); gtk_container_add(GTK_CONTAINER(win), vbox); /* Print the File name. */ name = g_path_get_basename(visu_scalar_field_getLabel(field->field)); markup = g_markup_printf_escaped("%s", name); g_free(name); wd = gtk_label_new(""); gtk_label_set_xalign(GTK_LABEL(wd), 0.); gtk_label_set_markup(GTK_LABEL(wd), markup); g_free(markup); gtk_box_pack_start(GTK_BOX(vbox), wd, FALSE, FALSE, 0); /* Print a list of all interesting characteristics of the file. */ options = visu_scalar_field_getAllOptions(field->field); table = gtk_grid_new(); tool_grid_resize(table, 1 + g_list_length(options), 2); gtk_widget_set_margin_start(table, 15); gtk_widget_set_margin_top(table, 15); gtk_box_pack_start(GTK_BOX(vbox), table, FALSE, FALSE, 0); wd = gtk_label_new(""); gtk_label_set_xalign(GTK_LABEL(wd), 1.); gtk_label_set_markup(GTK_LABEL(wd), _("Comment:")); gtk_grid_attach(GTK_GRID(table), wd, 0, 0, 1, 1); comment = visu_scalar_field_getCommentary(field->field); if (comment) wd = gtk_label_new(comment); else wd = gtk_label_new(_("None")); gtk_label_set_xalign(GTK_LABEL(wd), 0.); gtk_grid_attach(GTK_GRID(table), wd, 1, 0, 1, 1); row = 1; tmplst = options; while(tmplst) { wd = gtk_label_new(""); gtk_label_set_xalign(GTK_LABEL(wd), 1.); markup = g_markup_printf_escaped("%s:", tool_option_getName((ToolOption*)tmplst->data)); gtk_label_set_markup(GTK_LABEL(wd), markup); g_free(markup); gtk_grid_attach(GTK_GRID(table), wd, 0, row, 1, 1); wd = gtk_label_new(""); gtk_label_set_xalign(GTK_LABEL(wd), 0.); markup = tool_option_getValueAndLabel((ToolOption*)tmplst->data); gtk_label_set_markup(GTK_LABEL(wd), markup); g_free(markup); gtk_grid_attach(GTK_GRID(table), wd, 1, row, 1, 1); row += 1; tmplst = g_list_next(tmplst); } g_list_free(options); gtk_widget_show_all(win); row_potential_free(field); return FALSE; } static void onTreeViewActivated(GtkTreeView *tree_view, GtkTreePath *path, GtkTreeViewColumn *column, gpointer user_data _U_) { GtkTreeIter iter; /* We do something only if the color column is activated for a surface. */ if (column != colorColumn) return; if (gtk_tree_path_get_depth(path) < 2) return; if (gtk_tree_model_get_iter(gtk_tree_view_get_model(tree_view), &iter, path)) visu_ui_panel_surfaces_editProperties(&iter); } /** * visu_ui_panel_surfaces_getFields: * * This method gives read access to the #GtkListStore used to store * the scalar field files. * * Returns: (transfer none): the #GtkListStore used by this panel to * store its scalar fields. It should be considered read-only. */ GtkListStore* visu_ui_panel_surfaces_getFields() { return fields_data_list; } /** * visu_ui_panel_surfaces_fieldsAt: * @model: a #GtkTreeModel object. * @iter: a #GtkTreeIter iter. * * Retrieves the #VisuScalarField object stored at @iter, if any. * * Since: 3.8 * * Returns: (transfer none): a #VisuScalarField object. **/ VisuScalarField* visu_ui_panel_surfaces_fieldsAt(GtkTreeModel *model, GtkTreeIter *iter) { RowPotential *row; VisuScalarField *field; gtk_tree_model_get(model, iter, VISU_UI_SURFACES_FIELD_ROW, &row, -1); if (!row) return (VisuScalarField*)0; field = g_object_ref(row->field); row_potential_free(row); return field; } struct GenerateWidgets_struct { GtkWidget *spin_start; GtkWidget *spin_end; GtkWidget *spin_step; GtkWidget *spin_delta; }; static void onSpecialModeToggled(GtkToggleButton *button, gpointer data) { gtk_widget_set_sensitive(GTK_WIDGET(data), gtk_toggle_button_get_active(button)); } static void onGenerateChanged(GtkSpinButton *spin, gpointer data) { struct GenerateWidgets_struct *wds; float delta; wds = (struct GenerateWidgets_struct*)data; g_return_if_fail(wds); delta = gtk_spin_button_get_value(GTK_SPIN_BUTTON(wds->spin_end)) - gtk_spin_button_get_value(GTK_SPIN_BUTTON(wds->spin_start)); if (spin == GTK_SPIN_BUTTON(wds->spin_step) || spin != GTK_SPIN_BUTTON(wds->spin_delta)) gtk_spin_button_set_value(GTK_SPIN_BUTTON(wds->spin_delta), delta / gtk_spin_button_get_value(GTK_SPIN_BUTTON (wds->spin_step))); if (spin == GTK_SPIN_BUTTON(wds->spin_delta) || spin != GTK_SPIN_BUTTON(wds->spin_step)) gtk_spin_button_set_value(GTK_SPIN_BUTTON(wds->spin_step), delta / gtk_spin_button_get_value(GTK_SPIN_BUTTON (wds->spin_delta))); } /** * visu_ui_panel_surfaces_generateValues: * @nbValues: a location of an integer to store the number of generated values ; * @values: a pointer on a float array. The target of this pointer must be * NULL and it will be allocated after a call to this method. Use * g_free() after use to free it. * @name: a pointer to store a name. The target of this pointer must be * NULL on enter. It is associated only if a name is given. * @minVal: the minimum value for the range ; * @maxVal: the maximum value for the range. * * This method opens a little dialog window that is made to help the * user enter a list of values for creation of iso-surfaces. These values * are generated between @minVal and @maxVal. * * Returns: (transfer full): the dialog widget. */ GtkWidget* visu_ui_panel_surfaces_generateValues(int *nbValues, float **values, gchar **name, float minVal, float maxVal) { GtkWidget *dialog, *table; float value, incr; #define MAX_NB_VALUES 99 struct GenerateWidgets_struct wds; GtkWidget *spin_start; GtkWidget *spin_end; GtkWidget *spin_step; GtkWidget *spin_delta; GtkWidget *radioStep, *radioDelta; GtkWidget *entry, *progress; GSList *radiobuttonCycle_group; g_return_val_if_fail(nbValues && values && !*values && name && !*name, (GtkWidget*)0); dialog = gtk_dialog_new_with_buttons (_("Generate iso-values"), NULL, GTK_DIALOG_MODAL, TOOL_ICON_CANCEL, GTK_RESPONSE_CANCEL, _("Generate"), GTK_RESPONSE_ACCEPT, NULL); table = gtk_grid_new(); tool_grid_resize(table, 6, 2); spin_start = gtk_spin_button_new_with_range(minVal, maxVal, 0.0000001); g_signal_connect(G_OBJECT(spin_start), "value_changed", G_CALLBACK(onGenerateChanged), (gpointer)&wds); spin_end = gtk_spin_button_new_with_range(minVal, maxVal, 0.0000001); gtk_spin_button_set_value(GTK_SPIN_BUTTON(spin_end), maxVal); g_signal_connect(G_OBJECT(spin_end), "value_changed", G_CALLBACK(onGenerateChanged), (gpointer)&wds); spin_step = gtk_spin_button_new_with_range(2, MAX_NB_VALUES, 1); g_signal_connect(G_OBJECT(spin_step), "value_changed", G_CALLBACK(onGenerateChanged), (gpointer)&wds); spin_delta = gtk_spin_button_new_with_range(0.000001, maxVal - minVal, (maxVal - minVal) / 200); g_signal_connect(G_OBJECT(spin_delta), "value_changed", G_CALLBACK(onGenerateChanged), (gpointer)&wds); wds.spin_start = spin_start; wds.spin_end = spin_end; wds.spin_step = spin_step; wds.spin_delta = spin_delta; gtk_spin_button_set_value(GTK_SPIN_BUTTON(spin_step), 10); radioStep = gtk_radio_button_new_with_label(NULL, _("Number of steps:")); gtk_radio_button_set_group(GTK_RADIO_BUTTON(radioStep), (GSList*)0); radiobuttonCycle_group = gtk_radio_button_get_group(GTK_RADIO_BUTTON(radioStep)); gtk_grid_attach(GTK_GRID(table), radioStep, 0, 2, 1, 1); g_signal_connect(G_OBJECT(radioStep), "toggled", G_CALLBACK(onSpecialModeToggled), (gpointer)spin_step); radioDelta = gtk_radio_button_new_with_label(NULL, _("Delta of steps:")); gtk_radio_button_set_group(GTK_RADIO_BUTTON(radioDelta), radiobuttonCycle_group); radiobuttonCycle_group = gtk_radio_button_get_group(GTK_RADIO_BUTTON(radioDelta)); gtk_grid_attach(GTK_GRID(table), radioDelta, 1, 2, 1, 1); g_signal_connect(G_OBJECT(radioDelta), "toggled", G_CALLBACK(onSpecialModeToggled), (gpointer)spin_delta); entry = gtk_entry_new(); progress = gtk_progress_bar_new(); gtk_grid_attach(GTK_GRID(table), spin_step, 0, 3, 1, 1); gtk_grid_attach(GTK_GRID(table), spin_delta, 1, 3, 1, 1); gtk_grid_attach(GTK_GRID(table), gtk_label_new(_("Start:")), 0, 0, 1, 1); gtk_grid_attach(GTK_GRID(table), gtk_label_new(_("End:")), 1, 0, 1, 1); gtk_grid_attach(GTK_GRID(table), spin_start, 0, 1, 1, 1); gtk_grid_attach(GTK_GRID(table), spin_end, 1, 1, 1, 1); gtk_grid_attach(GTK_GRID(table), gtk_label_new(_("Name (optional):")), 0, 4, 2, 1); gtk_grid_attach(GTK_GRID(table), entry, 0, 5, 2, 1); gtk_box_pack_start(GTK_BOX(gtk_dialog_get_content_area(GTK_DIALOG(dialog))), table, FALSE, FALSE, 0); gtk_box_pack_start(GTK_BOX(gtk_dialog_get_content_area(GTK_DIALOG(dialog))), progress, FALSE, FALSE, 5); gtk_widget_set_sensitive(spin_delta, FALSE); gtk_widget_show_all(dialog); *values = (float*)0; *nbValues = 0; switch(gtk_dialog_run(GTK_DIALOG(dialog))) { case GTK_RESPONSE_ACCEPT: { float start = gtk_spin_button_get_value(GTK_SPIN_BUTTON(spin_start)); float end = gtk_spin_button_get_value(GTK_SPIN_BUTTON(spin_end)); int step = floor(gtk_spin_button_get_value(GTK_SPIN_BUTTON(spin_step))); *values = g_malloc(sizeof(float) * MAX_NB_VALUES); value = start; if (gtk_toggle_button_get_active(GTK_TOGGLE_BUTTON(radioStep))) { if (fabsf(start - minVal) < 1e-6) step += 1; incr = (end - start) / step; } else incr = gtk_spin_button_get_value(GTK_SPIN_BUTTON(spin_delta)); if (fabsf(value - minVal) < 1e-6) value += incr; while ((incr > 0 && (value - end) < -1e-6) || (incr < 0 && (value - end) > 1e-6)) { if (value > minVal && value < maxVal) { DBG_fprintf(stderr, "Panel VisuSurface: create a new value, %d %f\n", *nbValues, value); (*values)[*nbValues] = value; *nbValues += 1; } value += incr; } *name = g_strdup(gtk_entry_get_text(GTK_ENTRY(entry))); break; } default: { gtk_widget_destroy(dialog); dialog = (GtkWidget*)0; break; } return dialog; } return dialog; } static void onInteractiveNotified(VisuUiRenderingWindow *window, GParamSpec *pspec _U_, VisuGlNodeScene *scene) { VisuInteractive *inter; g_object_get(window, "interactive", &inter, NULL); if (!inter) return; visu_gl_ext_surfaces_setOnObserveOrdering(visu_gl_node_scene_addSurfaces(scene), inter); g_object_unref(inter); } static void _destroyFields(GtkListStore *model) { DBG_fprintf(stderr, "Panel Surfaces: destroying fields model.\n"); gtk_list_store_clear(model); g_object_unref(model); } /** * visu_ui_panel_surfaces_init: (skip) * * Should be used in the list declared in externalModules.h to be loaded by * V_Sim on start-up. This routine will create the #VisuUiPanel where the iso-surfaces * stuff can be done, such as creating a surface, loading a scalar field, * changing the properties... * * Returns: a newly created #VisuUiPanel object. */ VisuUiPanel* visu_ui_panel_surfaces_init(VisuUiMain *ui) { /* Long description */ char *cl = _("Drawing iso-surfaces"); /* Short description */ char *tl = "Isosurfaces"; VisuScalarfieldSet *set; VisuScalarfieldSetIter iter; gboolean valid; panelSurfaces = visu_ui_panel_newWithIconFromPath("Panel_surfaces", cl, _(tl), "stock-isosurfaces_20.png"); visu_ui_panel_setDockable(VISU_UI_PANEL(panelSurfaces), TRUE); fields_data_list = gtk_list_store_new(VISU_UI_SURFACES_FIELD_N_COLUMNS, G_TYPE_STRING, TYPE_ROW_POTENTIAL); g_signal_connect_swapped(panelSurfaces, "destroy", G_CALLBACK(_destroyFields), fields_data_list); /* Create the widgets. */ isosurfaces_create_gtk_interface(VISU_UI_PANEL(panelSurfaces)); gtk_widget_set_sensitive(isosurfaces_gtk_vbox, FALSE); gtk_widget_set_sensitive(buttonOpen, FALSE); gtk_widget_set_sensitive(buttonConvert, FALSE); vboxColorur = (GtkWidget*)0; vboxToolShade = (GtkWidget*)0; /* Add the signal for the vBoxVisuPlanes. */ g_signal_connect(G_OBJECT(ui), "DataFocused", G_CALLBACK(onDataFocused), (gpointer)0); g_signal_connect(visu_ui_main_getRendering(ui), "notify::interactive", G_CALLBACK(onInteractiveNotified), visu_ui_rendering_window_getGlScene(visu_ui_main_getRendering(ui))); onInteractiveNotified(visu_ui_main_getRendering(ui), (GParamSpec*)0, visu_ui_rendering_window_getGlScene(visu_ui_main_getRendering(ui))); set = visu_scalarfield_set_getDefault(); g_signal_connect(set, "added", G_CALLBACK(_addField), fields_data_list); g_signal_connect(set, "removed", G_CALLBACK(_removeField), fields_data_list); visu_scalarfield_set_iter_new(set, &iter); for (valid = visu_scalarfield_set_iter_next(&iter); valid; valid = visu_scalarfield_set_iter_next(&iter)) _addField(set, iter.field, fields_data_list); if(!panelSurfaces) return NULL; return VISU_UI_PANEL(panelSurfaces); } v_sim-3.8.0/src/panelModules/panelSurfaces.h000066400000000000000000000103401370110300500210060ustar00rootroot00000000000000/* EXTRAITS DE LA LICENCE Copyright CEA, contributeurs : Luc BILLARD, Damien CALISTE, Olivier D'Astier, laboratoire L_Sim, (2001-2005) Adresses mèl : BILLARD, non joignable par mèl ; CALISTE, damien P caliste AT cea P fr. D'ASTIER, dastier AT iie P cnam P fr. Ce logiciel est un programme informatique servant à visualiser des structures atomiques dans un rendu pseudo-3D. Ce logiciel est régi par la licence CeCILL soumise au droit français et respectant les principes de diffusion des logiciels libres. Vous pouvez utiliser, modifier et/ou redistribuer ce programme sous les conditions de la licence CeCILL telle que diffusée par le CEA, le CNRS et l'INRIA sur le site "http://www.cecill.info". Le fait que vous puissiez accéder à cet en-tête signifie que vous avez pris connaissance de la licence CeCILL, et que vous en avez accepté les termes (cf. le fichier Documentation/licence.fr.txt fourni avec ce logiciel). */ /* LICENCE SUM UP Copyright CEA, contributors : Luc BILLARD and Damien CALISTE and Olivier D'Astier, laboratoire L_Sim, (2001-2005) E-mail addresses : BILLARD, not reachable any more ; CALISTE, damien P caliste AT cea P fr. D'ASTIER, dastier AT iie P cnam P fr. This software is a computer program whose purpose is to visualize atomic configurations in 3D. This software is governed by the CeCILL license under French law and abiding by the rules of distribution of free software. You can use, modify and/ or redistribute the software under the terms of the CeCILL license as circulated by CEA, CNRS and INRIA at the following URL "http://www.cecill.info". The fact that you are presently reading this means that you have had knowledge of the CeCILL license and that you accept its terms. You can find a copy of this licence shipped with this software at Documentation/licence.en.txt. */ #ifndef PANELSURFACES_H #define PANELSURFACES_H #include #include #include #include #include #include #include VisuUiPanel* visu_ui_panel_surfaces_init(); gboolean visu_ui_panel_surfaces_loadFile(const char* file_name, GtkTreeIter *iter, GHashTable *table, VisuScalarFieldMethod *meth); void visu_ui_panel_surfaces_addSurfaces(GList *surfs, const gchar *name, GtkTreeIter *iter); void visu_ui_panel_surfaces_addSurface(VisuSurface *surf, GtkTreeIter *root, GtkTreeIter *iter); gboolean visu_ui_panel_surfaces_parseXMLFile(const gchar *filename, GError **error); gboolean visu_ui_panel_surfaces_exportXMLFile(const gchar *filename, GError **error); gboolean visu_ui_panel_surfaces_showAll(gboolean show); void visu_ui_panel_surfaces_editProperties(GtkTreeIter *iter); /** * VisuUiSurfacesFieldId: * @VISU_UI_SURFACES_FIELD_LABEL: a string, the description of the scalar field. * @VISU_UI_SURFACES_FIELD_ROW: a column storing internal pointers. * @VISU_UI_SURFACES_FIELD_N_COLUMNS: the number of columns. * * Thesse are the description of the columns stored in the #GtkListStore * of this panel. See visu_ui_panel_surfaces_getFields() to access this liststore. */ typedef enum { VISU_UI_SURFACES_FIELD_LABEL, VISU_UI_SURFACES_FIELD_ROW, VISU_UI_SURFACES_FIELD_N_COLUMNS } VisuUiSurfacesFieldId; GtkListStore* visu_ui_panel_surfaces_getFields(); VisuScalarField* visu_ui_panel_surfaces_fieldsAt(GtkTreeModel *model, GtkTreeIter *iter); /** * VISU_UI_SURFACE_NAME_STR: * * The default string used to name surfaces that are not associated to * any public surface ressource. */ #define VISU_UI_SURFACE_NAME_STR "Choose an id name" /** * VISU_UI_SURFACE_NAME_CHOOSE: * * The string used in the tree view to represent the surfaces that * don't share surface resources. */ #define VISU_UI_SURFACE_NAME_CHOOSE ""VISU_UI_SURFACE_NAME_STR"" GtkWidget* visu_ui_panel_surfaces_generateValues(int *nbValues, float **values, gchar **name, float minVal, float maxVal); #endif v_sim-3.8.0/src/panelModules/panelSurfacesTools.c000066400000000000000000002362721370110300500220400ustar00rootroot00000000000000/* EXTRAITS DE LA LICENCE Copyright CEA, contributeurs : Luc BILLARD, Damien CALISTE, Olivier D'Astier, laboratoire L_Sim, (2001-2005) Adresses mèl : BILLARD, non joignable par mèl ; CALISTE, damien P caliste AT cea P fr. D'ASTIER, dastier AT iie P cnam P fr. Ce logiciel est un programme informatique servant à visualiser des structures atomiques dans un rendu pseudo-3D. Ce logiciel est régi par la licence CeCILL soumise au droit français et respectant les principes de diffusion des logiciels libres. Vous pouvez utiliser, modifier et/ou redistribuer ce programme sous les conditions de la licence CeCILL telle que diffusée par le CEA, le CNRS et l'INRIA sur le site "http://www.cecill.info". Le fait que vous puissiez accéder à cet en-tête signifie que vous avez pris connaissance de la licence CeCILL, et que vous en avez accepté les termes (cf. le fichier Documentation/licence.fr.txt fourni avec ce logiciel). */ /* LICENCE SUM UP Copyright CEA, contributors : Luc BILLARD and Damien CALISTE and Olivier D'Astier, laboratoire L_Sim, (2001-2005) E-mail addresses : BILLARD, not reachable any more ; CALISTE, damien P caliste AT cea P fr. D'ASTIER, dastier AT iie P cnam P fr. This software is a computer program whose purpose is to visualize atomic configurations in 3D. This software is governed by the CeCILL license under French law and abiding by the rules of distribution of free software. You can use, modify and/ or redistribute the software under the terms of the CeCILL license as circulated by CEA, CNRS and INRIA at the following URL "http://www.cecill.info". The fact that you are presently reading this means that you have had knowledge of the CeCILL license and that you accept its terms. You can find a copy of this licence shipped with this software at Documentation/licence.en.txt. */ #include "panelSurfacesTools.h" #include "panelSurfaces.h" #include #include #include #include #include #include #include #include #include #include /** * SECTION:panelSurfacesTools * @short_description: Gtk interface to manage isosurfaces. * * This module contains the panel used to manage your .surf * files. At the moment, only two tools are availiable for you to * use. pot2surf will allow you * to create .surf files from .pot files. There is also a .surf file * merger which is so short that we beliedved it didn't need it's own * module. */ static GtkWidget *convert_window; static gboolean convert_w_opened = FALSE; static GtkListStore* list_store = NULL; static GtkListStore* list_store_target = NULL; static GtkWidget* tree_view_source = NULL; static GtkWidget* tree_view_target = NULL; enum { MERGE_SURF_NAME, MERGE_NB_POINTS, MERGE_NB_VERTEX, MERGE_FILENAME, MERGE_NEW_SURF_NAME, MERGE_SHORT_FILENAME, MERGE_N_COLUMNS }; static GtkWidget *surfmerge_source_ddd[6]; static GtkWidget *surfmerge_target_ddd[6]; static GtkWidget *entry_current_file; static GtkWidget *entry_target_file; void surf_add_surf_to_target(); #if GTK_MAJOR_VERSION < 3 gboolean gtk_tree_model_iter_previous(GtkTreeModel *tree_model, GtkTreeIter *iter) { GtkTreePath *temp_to_free = gtk_tree_model_get_path(tree_model, iter); if (!temp_to_free) return FALSE; if(!gtk_tree_path_prev(temp_to_free)) { /* DBG_fprintf(stderr, "WARNING : custom gtk_tree_model_iter_previous couldn't retrieve previous element\n"); */ gtk_tree_path_free(temp_to_free); return FALSE; } if(!gtk_tree_model_get_iter(tree_model, iter, temp_to_free)) { /* DBG_fprintf(stderr, "WARNING : custom gtk_tree_model_iter_previous couldn't retrieve a valid iter\n"); */ gtk_tree_path_free(temp_to_free); return FALSE; } gtk_tree_path_free(temp_to_free); return TRUE; } #endif /* Parses target surf file to retrieve dxx, ..., dzz, as well as each surface name, nb of vertex and nb of points. */ gboolean surf_simply_parse_file(char *file_name) { GString *line = g_string_new(""); gchar **surf_names = NULL; gsize terminator_pos; int last_op_status; int number_of_surfaces; int i; int *nb_vertex, *nb_points; float ddd[6]; char float_to_string[128]; gboolean ddd_are_null = TRUE; gboolean ddd_are_equal = TRUE; GIOChannel* file_to_parse = g_io_channel_new_file(file_name, "r", NULL); if(file_to_parse == NULL) return FALSE; /* First line is arbitrary */ last_op_status = g_io_channel_read_line_string (file_to_parse, line, &terminator_pos, NULL); if(last_op_status != G_IO_STATUS_NORMAL) return FALSE; /* Second line contains dxx, dyx and dyy values */ last_op_status = g_io_channel_read_line_string (file_to_parse, line, &terminator_pos, NULL); if(last_op_status != G_IO_STATUS_NORMAL || sscanf(line->str, "%f %f %f", &ddd[0], &ddd[1], &ddd[2]) != 3) return FALSE; /* Third line contains dzx, dzy and dzz values */ last_op_status = g_io_channel_read_line_string (file_to_parse, line, &terminator_pos, NULL); if(last_op_status != G_IO_STATUS_NORMAL || sscanf(line->str, "%f %f %f", &ddd[3], &ddd[4], &ddd[5]) != 3) return FALSE; /* Fourth line contains nsurf values (as well as two other values) */ last_op_status = g_io_channel_read_line_string (file_to_parse, line, &terminator_pos, NULL); if(last_op_status != G_IO_STATUS_NORMAL || sscanf(line->str, "%d", &number_of_surfaces) != 1) return FALSE; if(number_of_surfaces <= 0) return FALSE; surf_names = g_malloc(number_of_surfaces * sizeof(gchar *)); nb_vertex = g_malloc(number_of_surfaces * sizeof(int)); nb_points = g_malloc(number_of_surfaces * sizeof(int)); for(i=0; istr[0] == '#'); surf_names[i] = g_strdup(line->str); g_strdelimit(surf_names[i], "\n", ' '); g_strstrip(surf_names[i]); last_op_status = g_io_channel_read_line_string (file_to_parse, line, &terminator_pos, NULL); if(last_op_status != G_IO_STATUS_NORMAL || sscanf(line->str, "%d %d", &nb_vertex[i], &nb_points[i]) != 2) return FALSE; for(j=0; j<(nb_vertex[i]+nb_points[i]); j++) { last_op_status = g_io_channel_read_line_string (file_to_parse, line, &terminator_pos, NULL); if(last_op_status != G_IO_STATUS_NORMAL) return FALSE; } } gtk_list_store_clear(list_store); for(i=0; i<6; i++) { sprintf(float_to_string, "%f", ddd[i]); gtk_entry_set_text(GTK_ENTRY(surfmerge_source_ddd[i]), float_to_string); ddd_are_null = ddd_are_null && (atof(gtk_entry_get_text(GTK_ENTRY(surfmerge_target_ddd[i]))) == 0.); ddd_are_equal = ddd_are_equal && (atof(gtk_entry_get_text(GTK_ENTRY(surfmerge_target_ddd[i]))) == ddd[i]); } if(ddd_are_null) for(i=0; i<6; i++) gtk_entry_set_text(GTK_ENTRY(surfmerge_target_ddd[i]), gtk_entry_get_text(GTK_ENTRY(surfmerge_source_ddd[i]))); else if(!ddd_are_equal) { GtkWidget* choice = gtk_dialog_new_with_buttons(_("Found different dxx, ..., dzz"), GTK_WINDOW(convert_window), GTK_DIALOG_MODAL, TOOL_ICON_CANCEL, GTK_RESPONSE_CANCEL, _("Keep current values"), GTK_RESPONSE_YES, _("Change values to new ones"), GTK_RESPONSE_NO, NULL); gtk_box_pack_start(GTK_BOX(gtk_dialog_get_content_area(GTK_DIALOG(choice))), gtk_label_new(_("Current dxx, ..., dzz, doesn't match the ones used in the " "file you are trying to load. Do you want to keep old " "dxx, ..., dzz ? (if you don't know exactly what you're doing, " "just cancel and load another file)")), TRUE, TRUE, 0); gtk_widget_show_all(choice); switch(gtk_dialog_run (GTK_DIALOG (choice))) { case GTK_RESPONSE_CANCEL: gtk_widget_destroy(choice); return FALSE; break; case GTK_RESPONSE_NO: for(i=0; i<6; i++) gtk_entry_set_text(GTK_ENTRY(surfmerge_target_ddd[i]), gtk_entry_get_text(GTK_ENTRY(surfmerge_source_ddd[i]))); gtk_widget_destroy(choice); break; case GTK_RESPONSE_YES: default: gtk_widget_destroy(choice); break; } } for(i=0; idata)) break; if(gtk_tree_selection_get_selected(tree_selection_target, &model_target, &iter_target)) { gtk_list_store_insert_after(list_store_target, &iter_target_new, &iter_target); gtk_tree_selection_select_iter(tree_selection_target, &iter_target_new); } else { iter_target_new = iter_target; gtk_list_store_append(list_store_target, &iter_target_new); } gtk_tree_model_get(GTK_TREE_MODEL(list_store), &iter_source, MERGE_SURF_NAME, &surf_name, MERGE_NB_POINTS, &nb_points, MERGE_NB_VERTEX, &nb_vertex, -1); short_filename = g_path_get_basename(gtk_entry_get_text(GTK_ENTRY(entry_current_file))); g_strdelimit(surf_name, " ", '_'); gtk_list_store_set(list_store_target, &iter_target_new, MERGE_SURF_NAME, surf_name, MERGE_NB_POINTS, nb_points, MERGE_NB_VERTEX, nb_vertex, MERGE_FILENAME, gtk_entry_get_text(GTK_ENTRY(entry_current_file)), MERGE_NEW_SURF_NAME, surf_name, MERGE_SHORT_FILENAME, short_filename, -1); g_free(surf_name); g_free(short_filename); gtk_tree_path_free(rows_browse->data); rows_browse = rows_browse->next; } g_list_free(rows_start); } /* Only used with a gtk_tree_model_foreach() Used to count the total of surfaces, nb_vertex, and nb_points to build a correct .surf file. */ gboolean surfmerge_init_export(GtkTreeModel *model, GtkTreePath *path _U_, GtkTreeIter *iter, gpointer data) { int *total = data; int nb_points; int nb_vertex; gtk_tree_model_get(GTK_TREE_MODEL(model), iter, MERGE_NB_POINTS, &nb_points, MERGE_NB_VERTEX, &nb_vertex, -1); total[0]++; total[1] += nb_vertex; total[2] += nb_points; return FALSE; } /* Only used with a gtk_tree_model_foreach() Used to write a surface in the file the user wants to write. */ gboolean surf_export_surf(GtkTreeModel *model, GtkTreePath *path _U_, GtkTreeIter *iter, gpointer data) { FILE *file_to_write = data; gchar *old_surf_name; gchar * file_name; gchar * surf_name; int nb_vertex, nb_points, i, j; GIOChannel* file_to_read; gsize terminator_pos; GString *line = g_string_new(""); int last_op_status; gtk_tree_model_get(GTK_TREE_MODEL(model), iter, MERGE_SURF_NAME, &old_surf_name, MERGE_FILENAME, &file_name, MERGE_NEW_SURF_NAME, &surf_name, MERGE_NB_VERTEX, &nb_vertex, MERGE_NB_POINTS, &nb_points, -1); file_to_read = g_io_channel_new_file(file_name, "r", NULL); DBG_fprintf(stderr, "Surface Merger : writing surface '%s' info \n", surf_name); for(i=0; i<4; i++) { last_op_status = g_io_channel_read_line_string (file_to_read, line, &terminator_pos, NULL); if(last_op_status != G_IO_STATUS_NORMAL) { g_free(file_name); g_free(surf_name); g_free(old_surf_name); g_string_free(line, TRUE); g_io_channel_unref(file_to_read); visu_ui_raiseWarning(_("Loading a file"), _("An unknown error occured. Your surf" " file is corrupted.\n"), (GtkWindow*)0); return TRUE; } } for(i=0; i>-1; i++) { gchar *cur_surf_name; int surf_nb_vertex, surf_nb_points; last_op_status = g_io_channel_read_line_string (file_to_read, line, &terminator_pos, NULL); if(last_op_status != G_IO_STATUS_NORMAL) { g_free(file_name); g_free(surf_name); g_free(old_surf_name); g_string_free(line, TRUE); g_io_channel_unref(file_to_read); visu_ui_raiseWarning(_("Loading a file"), _("An unknown error occured. Your surf" " file is corrupted.\n"), (GtkWindow*)0); return TRUE; } cur_surf_name = g_strdup(line->str); g_strdelimit(cur_surf_name, "\n", ' '); g_strstrip(cur_surf_name); DBG_fprintf(stderr, "%s, old:%s\n", cur_surf_name, old_surf_name); if(strcmp(cur_surf_name, old_surf_name) == 0) fprintf(file_to_write, "%s\n", surf_name); last_op_status = g_io_channel_read_line_string (file_to_read, line, &terminator_pos, NULL); if(last_op_status != G_IO_STATUS_NORMAL || sscanf(line->str, "%d %d", &surf_nb_vertex, &surf_nb_points) != 2) { g_free(file_name); g_free(surf_name); g_free(old_surf_name); g_string_free(line, TRUE); g_io_channel_unref(file_to_read); visu_ui_raiseWarning(_("Loading a file"), _("An unknown error occured. Your surf" " file is corrupted.\n"), (GtkWindow*)0); return TRUE; } DBG_fprintf(stderr, "%s, old:%s\n", cur_surf_name, old_surf_name); if(strcmp(cur_surf_name, old_surf_name) == 0) fprintf(file_to_write, "%s", line->str); for(j=0; j<(surf_nb_vertex+surf_nb_points); j++) { last_op_status = g_io_channel_read_line_string (file_to_read, line, &terminator_pos, NULL); if(last_op_status != G_IO_STATUS_NORMAL) { g_free(file_name); g_free(surf_name); g_free(old_surf_name); g_string_free(line, TRUE); g_io_channel_unref(file_to_read); visu_ui_raiseWarning(_("Loading a file"), _("An unknown error occured. Your surf" " file is corrupted.\n"), (GtkWindow*)0); return TRUE; } if(strcmp(cur_surf_name, old_surf_name) == 0) fprintf(file_to_write, "%s", line->str); } DBG_fprintf(stderr, "%s, old:%s\n", cur_surf_name, old_surf_name); if(strcmp(cur_surf_name, old_surf_name) == 0) { g_free(cur_surf_name); break; } g_free(cur_surf_name); DBG_fprintf(stderr, "%s, old:%s\n", cur_surf_name, old_surf_name); } g_free(file_name); g_free(old_surf_name); g_free(surf_name); g_string_free(line, TRUE); g_io_channel_unref(file_to_read); return FALSE; } /* If all parameters are correctly set, tries to write a valid .surf file from the surfaces selected by the user. */ void surf_gogogo() { FILE* file_to_write = fopen(gtk_entry_get_text(GTK_ENTRY(entry_target_file)), "wb"); int i; int total[3]; if(file_to_write == NULL) { visu_ui_raiseWarning(_("Saving a file"), _("Please choose a surf file to write\n"), (GtkWindow*)0); return; } for(i=0; i<3; i++) total[i] = 0; gtk_tree_model_foreach(GTK_TREE_MODEL(list_store_target), surfmerge_init_export, total); if(total[0] == 0) { visu_ui_raiseWarning(_("Saving a file"), _("No surface to write\n"), (GtkWindow*)0); return; } if(fprintf(file_to_write, "surf file generated by v_sim's merger\n") < 0) return; for(i=0; i<6; i++) { if(fprintf(file_to_write, "%s ", gtk_entry_get_text(GTK_ENTRY(surfmerge_target_ddd[i]))) < 0) return; if((i+1)%3==0) if(fprintf(file_to_write, "\n") < 0) return; } if(fprintf(file_to_write, "%d %d %d\n", total[0], total[1], total[2]) < 0) return; gtk_tree_model_foreach(GTK_TREE_MODEL(list_store_target), surf_export_surf, file_to_write); fclose(file_to_write); DBG_fprintf(stderr, "Surface Merger : wrote file %s\n", gtk_entry_get_text(GTK_ENTRY(entry_target_file))); } /* See header file for more info */ GtkWidget *visu_ui_panel_surfaces_tools_fileWidget() { enum { DXX, DYX, DYY, DZX, DZY, DZZ }; #if GTK_MAJOR_VERSION == 2 && GTK_MINOR_VERSION < 12 GtkTooltips *tooltips = gtk_tooltips_new (); #endif GtkWidget* scrolled_window_top = gtk_scrolled_window_new(NULL, NULL); GtkWidget* scrolled_window_bot = gtk_scrolled_window_new(NULL, NULL); GtkWidget *global_vbox = gtk_vbox_new(FALSE, 0); GtkWidget *hbox1 = gtk_hbox_new(FALSE, 0); GtkWidget *hbox_top_ddd = gtk_hbox_new(FALSE, 2); GtkWidget *hbox_top_ddd2 = gtk_hbox_new(FALSE, 2); GtkWidget *hbox_bot_ddd = gtk_hbox_new(FALSE, 2); GtkWidget *hbox_bot_ddd2 = gtk_hbox_new(FALSE, 2); GtkWidget *hbox_go = gtk_hbox_new(FALSE, 0); GtkWidget *bottom_frame = gtk_frame_new(_("Target info : ")); GtkWidget *top_frame = gtk_frame_new(_("Source info : ")); GtkWidget *vbox = gtk_vbox_new(FALSE, 2); GtkWidget *vbox_r = gtk_vbox_new(FALSE, 2); GtkWidget *add_surf_button = gtk_button_new(); GtkWidget *go_button = gtk_button_new_with_label("Build"); GtkWidget *save_file = gtk_button_new(); GtkWidget *hbox_target_file = gtk_hbox_new(FALSE, 0); char *ddd[] = {"dxx :", "dyx :", "dyy :", "dzx :", "dzy :", "dzz :"}; GtkWidget *label; GtkWidget *remove_surf_button = gtk_button_new(); GtkWidget *move_down_surf_button = gtk_button_new(); GtkWidget *move_up_surf_button = gtk_button_new(); int i; GtkWidget *open_file = gtk_button_new(); GtkWidget *manage_top_tview_vbox = gtk_vbox_new(FALSE, 0); GtkWidget *manage_bot_tview_vbox = gtk_vbox_new(FALSE, 0); GtkWidget *top_tview_hbox = gtk_hbox_new(FALSE, 0); GtkWidget *bot_tview_hbox = gtk_hbox_new(FALSE, 0); GtkWidget *image_add = gtk_image_new_from_icon_name("list-add", GTK_ICON_SIZE_BUTTON); GtkWidget *image_remove = gtk_image_new_from_icon_name("list-remove", GTK_ICON_SIZE_BUTTON); GtkWidget *image_go_down = gtk_image_new_from_icon_name("go-down", GTK_ICON_SIZE_BUTTON); GtkWidget *image_go_up = gtk_image_new_from_icon_name("go-up", GTK_ICON_SIZE_BUTTON); GtkWidget *image_open = gtk_image_new_from_icon_name("document-open", GTK_ICON_SIZE_BUTTON); entry_current_file = gtk_entry_new(); entry_target_file = gtk_entry_new(); gtk_scrolled_window_set_policy(GTK_SCROLLED_WINDOW(scrolled_window_top), GTK_POLICY_AUTOMATIC,GTK_POLICY_AUTOMATIC); gtk_scrolled_window_set_policy(GTK_SCROLLED_WINDOW(scrolled_window_bot), GTK_POLICY_AUTOMATIC,GTK_POLICY_AUTOMATIC); gtk_container_add (GTK_CONTAINER (add_surf_button), image_add); gtk_container_add (GTK_CONTAINER (remove_surf_button), image_remove); gtk_container_add (GTK_CONTAINER (move_down_surf_button), image_go_down); gtk_container_add (GTK_CONTAINER (move_up_surf_button), image_go_up); gtk_container_add (GTK_CONTAINER (open_file), image_open); image_open = gtk_image_new_from_icon_name("document-open", GTK_ICON_SIZE_BUTTON); gtk_container_add (GTK_CONTAINER (save_file), image_open); gtk_widget_set_tooltip_text(go_button, _("Build specified new .surf file")); gtk_widget_set_tooltip_text(entry_current_file, _("Contains the full path to the currently .surf selected file")); gtk_widget_set_tooltip_text(entry_target_file, _("Contains the full path to the .surf file you want to build")); gtk_widget_set_tooltip_text(open_file, _("Allows you to select a .surf file")); gtk_widget_set_tooltip_text(save_file, _("Selects the .surf file to write")); gtk_widget_set_tooltip_text(add_surf_button, _("Moves selected surface to the list of surfaces to build")); gtk_widget_set_tooltip_text(move_down_surf_button, _("Moves down selected surface in the list of surfaces to build")); gtk_widget_set_tooltip_text(move_up_surf_button, _("Moves up selected surface in the list of surfaces to build")); gtk_widget_set_tooltip_text(remove_surf_button, _("Removes selected surface from the list of surfaces to build")); for(i=0; i<6; i++) { surfmerge_source_ddd[i] = gtk_entry_new(); gtk_entry_set_text(GTK_ENTRY(surfmerge_source_ddd[i]), "0.0000000"); g_object_set(G_OBJECT(surfmerge_source_ddd[i]), "width-chars", 9, NULL); gtk_editable_set_editable(GTK_EDITABLE(surfmerge_source_ddd[i]), FALSE); gtk_widget_set_tooltip_text(surfmerge_source_ddd[i], _("The d__ of the current selected file")); } for(i=0; i<6; i++) { surfmerge_target_ddd[i] = gtk_entry_new(); gtk_entry_set_text(GTK_ENTRY(surfmerge_target_ddd[i]), "0.0000000"); g_object_set(G_OBJECT(surfmerge_target_ddd[i]), "width-chars", 9, NULL); gtk_widget_set_tooltip_text(surfmerge_target_ddd[i], _("The d__ of the file to build")); } surf_create_tree_views(); gtk_box_pack_start(GTK_BOX(global_vbox), top_frame, TRUE, TRUE, 0); gtk_box_pack_start(GTK_BOX(global_vbox), bottom_frame, TRUE, TRUE, 0); gtk_container_add(GTK_CONTAINER(top_frame), vbox); gtk_container_add(GTK_CONTAINER(scrolled_window_top), tree_view_source); gtk_box_pack_start(GTK_BOX(vbox), hbox1, FALSE, FALSE, 0); gtk_box_pack_start(GTK_BOX(vbox), hbox_top_ddd, FALSE, FALSE, 0); gtk_box_pack_start(GTK_BOX(vbox), hbox_top_ddd2, FALSE, FALSE, 0); gtk_box_pack_start(GTK_BOX(vbox), top_tview_hbox, TRUE, TRUE, 0); gtk_box_pack_start(GTK_BOX(hbox1), gtk_label_new(_("Current file : ")), FALSE, FALSE, 0); gtk_box_pack_start(GTK_BOX(hbox1), entry_current_file, TRUE, TRUE, 0); gtk_box_pack_start(GTK_BOX(hbox1), open_file, FALSE, FALSE, 0); for(i=0; i<3; i++) { label = gtk_label_new(ddd[i]); gtk_label_set_xalign(GTK_LABEL(label), 1.); gtk_box_pack_start(GTK_BOX(hbox_top_ddd), label, i==0 ? FALSE : TRUE, TRUE, 0); gtk_box_pack_start(GTK_BOX(hbox_top_ddd), surfmerge_source_ddd[i], FALSE, FALSE, 0); } for(i=3; i<6; i++) { label = gtk_label_new(ddd[i]); gtk_label_set_xalign(GTK_LABEL(label), 1.); gtk_box_pack_start(GTK_BOX(hbox_top_ddd2), label, i==3 ? FALSE : TRUE, TRUE, 0); gtk_box_pack_start(GTK_BOX(hbox_top_ddd2), surfmerge_source_ddd[i], FALSE, FALSE, 0); } gtk_box_pack_start(GTK_BOX(top_tview_hbox), scrolled_window_top, TRUE, TRUE, 0); gtk_box_pack_start(GTK_BOX(top_tview_hbox), manage_top_tview_vbox, FALSE, FALSE, 0); gtk_box_pack_start(GTK_BOX(manage_top_tview_vbox), add_surf_button, TRUE, FALSE, 0); gtk_container_add(GTK_CONTAINER(bottom_frame), vbox_r); gtk_container_add(GTK_CONTAINER(scrolled_window_bot), tree_view_target); gtk_box_pack_start(GTK_BOX(vbox_r), hbox_bot_ddd, FALSE, FALSE, 0); gtk_box_pack_start(GTK_BOX(vbox_r), hbox_bot_ddd2, FALSE, FALSE, 0); gtk_box_pack_start(GTK_BOX(vbox_r), bot_tview_hbox, TRUE, TRUE, 0); gtk_box_pack_start(GTK_BOX(vbox_r), hbox_target_file, FALSE, FALSE, 0); gtk_box_pack_start(GTK_BOX(vbox_r), hbox_go, FALSE, FALSE, 0); for(i=0; i<3; i++) { label = gtk_label_new(ddd[i]); gtk_label_set_xalign(GTK_LABEL(label), 1.); gtk_box_pack_start(GTK_BOX(hbox_bot_ddd), label, i==0 ? FALSE : TRUE, TRUE, 0); gtk_box_pack_start(GTK_BOX(hbox_bot_ddd), surfmerge_target_ddd[i], FALSE, FALSE, 0); } for(i=3; i<6; i++) { label = gtk_label_new(ddd[i]); gtk_label_set_xalign(GTK_LABEL(label), 1.); gtk_box_pack_start(GTK_BOX(hbox_bot_ddd2), label, i==3 ? FALSE : TRUE, TRUE, 0); gtk_box_pack_start(GTK_BOX(hbox_bot_ddd2), surfmerge_target_ddd[i], FALSE, FALSE, 0); } gtk_box_pack_start(GTK_BOX(bot_tview_hbox), scrolled_window_bot, TRUE, TRUE, 0); gtk_box_pack_start(GTK_BOX(bot_tview_hbox), manage_bot_tview_vbox, FALSE, FALSE, 0); gtk_box_pack_start(GTK_BOX(manage_bot_tview_vbox), remove_surf_button, FALSE, FALSE, 0); gtk_box_pack_end(GTK_BOX(manage_bot_tview_vbox), move_down_surf_button, FALSE, FALSE, 0); gtk_box_pack_end(GTK_BOX(manage_bot_tview_vbox), move_up_surf_button, FALSE, FALSE, 0); gtk_box_pack_start(GTK_BOX(hbox_target_file), gtk_label_new(_("Target file : ")), FALSE, FALSE, 0); gtk_box_pack_start(GTK_BOX(hbox_target_file), entry_target_file, TRUE, TRUE, 0); gtk_box_pack_start(GTK_BOX(hbox_target_file), save_file, FALSE, FALSE, 0); gtk_box_pack_end(GTK_BOX(hbox_go), go_button, FALSE, FALSE, 0); /* Signal connexion */ g_signal_connect(G_OBJECT(open_file), "clicked", G_CALLBACK(surf_open_file_chooser), entry_current_file); g_signal_connect(G_OBJECT(add_surf_button), "clicked", G_CALLBACK(surf_add_surf_to_target), NULL); g_signal_connect(G_OBJECT(go_button), "clicked", G_CALLBACK(surf_gogogo), NULL); g_signal_connect(G_OBJECT(remove_surf_button), "clicked", G_CALLBACK(surfmerge_remove_surf), NULL); g_signal_connect(G_OBJECT(move_up_surf_button), "clicked", G_CALLBACK(surfmerge_move_surf), GINT_TO_POINTER(-1)); g_signal_connect(G_OBJECT(move_down_surf_button), "clicked", G_CALLBACK(surfmerge_move_surf), GINT_TO_POINTER(1)); g_signal_connect(G_OBJECT(save_file), "clicked", G_CALLBACK(surfmerge_target_file_chooser), NULL); return global_vbox; } /*****************************************************************************/ /* */ /* POT2SURF */ /* */ /*****************************************************************************/ static GtkListStore *pot2surf_list_store = NULL; static GtkWidget *pot2surf_tree_view = NULL; static GtkWidget *pot2surf_entry_source_pot_file = NULL; static GtkWidget *pot2surf_entry_target_surf_file = NULL; static GtkWidget *pot2surf_potmax = NULL; static GtkWidget *pot2surf_potmin = NULL; enum { POT2SURF_NAME, POT2SURF_VALUE, POT2SURF_N_COLUMNS }; /* Pops up a window containing info about the pot2surf routine Currently unused. */ void pot2surf_popup_help() { GtkWidget *window; gsize length; gchar *text = NULL; GtkTextBuffer *text_buf; GtkWidget *text_view; GtkWidget *scrolled_window; gchar *chemin = g_build_filename(V_SIM_LEGAL_DIR, "pot2surf_help", NULL); if(!g_file_get_contents(chemin, &text, &length, (GError**)0)) { g_free(chemin); return; } g_free(chemin); text_buf = gtk_text_buffer_new(NULL); text_view = gtk_text_view_new_with_buffer(text_buf); scrolled_window = gtk_scrolled_window_new(NULL, NULL); gtk_text_buffer_insert_at_cursor(text_buf, text, -1); g_free(text); /* Create a new dialog window for the scrolled window to be * packed into. */ window = gtk_dialog_new_with_buttons(_("pot2surf_help"), NULL, 0, TOOL_ICON_OPEN, GTK_RESPONSE_ACCEPT, NULL); gtk_container_set_border_width (GTK_CONTAINER (window), 0); gtk_widget_set_size_request (window, 600, 300); /* create a new scrolled window. */ scrolled_window = gtk_scrolled_window_new (NULL, NULL); gtk_container_set_border_width (GTK_CONTAINER (scrolled_window), 10); gtk_scrolled_window_set_policy (GTK_SCROLLED_WINDOW (scrolled_window), GTK_POLICY_AUTOMATIC, GTK_POLICY_AUTOMATIC); /* The dialog window is created with a vbox packed into it. */ gtk_box_pack_start(GTK_BOX(gtk_dialog_get_content_area(GTK_DIALOG(window))), scrolled_window, TRUE, TRUE, 0); #if GTK_MAJOR_VERSION < 3 || (GTK_MAJOR_VERSION == 3 && GTK_MINOR_VERSION < 8) gtk_scrolled_window_add_with_viewport(GTK_SCROLLED_WINDOW (scrolled_window), text_view); #else gtk_container_add(GTK_CONTAINER(scrolled_window), text_view); #endif gtk_widget_show_all (window); switch(gtk_dialog_run(GTK_DIALOG(window))) { default: gtk_widget_destroy(window); } } /* Parses target to file to retrieve pot_min and pot_max Returns TRUE in case of success, FALSE otherwise. */ gboolean pot2surf_quick_parse(char *file_name, float *pot_min, float *pot_max) { GString *line = g_string_new(""); int last_op_status; int na, nb, nc; int i, j; float current_value; gsize terminator_pos; gchar **float_tab; GIOChannel* file_to_parse = g_io_channel_new_file(file_name, "r", NULL); if(file_to_parse == NULL) { visu_ui_raiseWarning(_("Loading a file"), _("Can't open given file for reading"), (GtkWindow*)0); g_io_channel_unref(file_to_parse); return FALSE; } /* Read the first five lines */ for(i=0; i<5; i++) { last_op_status = g_io_channel_read_line_string (file_to_parse, line, &terminator_pos, NULL); if(last_op_status != G_IO_STATUS_NORMAL) { visu_ui_raiseWarning(_("Loading a file"), _("This file doesn't seem to be a correct pot file"), (GtkWindow*)0); g_io_channel_unref(file_to_parse); return FALSE; } if(i==1) { sscanf(line->str, "%d %d %d", &na, &nb, &nc); if(na <= 0 || nb <= 0 || nc <= 0) { visu_ui_raiseWarning(_("Loading a file"), _("Second line seem to contain incorrect values"), (GtkWindow*)0); g_io_channel_unref(file_to_parse); return FALSE; } } } /* Retrieve pot values to find min & max in the following lines. According to .pot files specifications, the following lines are in free format */ for(i=0; istr, " ", -1); for(j=0; float_tab[j] != NULL; j++) { if(sscanf(float_tab[j], "%f", ¤t_value) == 1) { if(i==0) *pot_max = *pot_min = current_value; else if(current_value < *pot_min) *pot_min = current_value; else if(current_value > *pot_max) *pot_max = current_value; i++; } } g_strfreev(float_tab); } g_io_channel_unref(file_to_parse); return TRUE; } /* Opens a file chooser for the user to select a pot file. This file is parsed using pot2surf_quick_parse() to try to retrieve pot_in and pot_max. If parsing is successful, set entries to default values (ie : file_selected.surf and file_selected.instruc) */ void pot2surf_select_pot_file(GtkWidget *widget _U_, gpointer data _U_) { GtkFileFilter *filter_pot = gtk_file_filter_new(); GtkFileFilter *filter_none = gtk_file_filter_new(); GtkWidget* file_chooser = gtk_file_chooser_dialog_new("Select a .pot file", GTK_WINDOW(convert_window), GTK_FILE_CHOOSER_ACTION_OPEN, TOOL_ICON_CANCEL, GTK_RESPONSE_CANCEL, /* GTK_STOCK_HELP, GTK_RESPONSE_HELP, */ TOOL_ICON_OPEN, GTK_RESPONSE_ACCEPT, NULL); const gchar *directory = visu_ui_main_getLastOpenDirectory(visu_ui_main_class_getCurrentPanel()); gchar *dir; if (directory) gtk_file_chooser_set_current_folder(GTK_FILE_CHOOSER(file_chooser), directory); gtk_file_filter_add_pattern(filter_pot, "*.pot"); gtk_file_filter_add_pattern(filter_pot, "*.dat"); gtk_file_filter_set_name(filter_pot, "Potential files (*.pot, *.dat)"); gtk_file_chooser_add_filter (GTK_FILE_CHOOSER(file_chooser), filter_pot); gtk_file_filter_add_pattern(filter_none, "*"); gtk_file_filter_set_name(filter_none, "All files"); gtk_file_chooser_add_filter (GTK_FILE_CHOOSER(file_chooser), filter_none); while(1) { switch(gtk_dialog_run(GTK_DIALOG(file_chooser))) { float pot_min, pot_max; char float_to_string[128]; gchar *selected_file; GString *other_files; case GTK_RESPONSE_ACCEPT: selected_file = gtk_file_chooser_get_filename(GTK_FILE_CHOOSER(file_chooser)); if(pot2surf_quick_parse(selected_file, &pot_min, &pot_max)) { sprintf(float_to_string, "%f", pot_min); gtk_entry_set_text(GTK_ENTRY(pot2surf_potmin), float_to_string); sprintf(float_to_string, "%f", pot_max); gtk_entry_set_text(GTK_ENTRY(pot2surf_potmax), float_to_string); gtk_entry_set_text(GTK_ENTRY(pot2surf_entry_source_pot_file), selected_file); other_files = g_string_new(selected_file); if(g_str_has_suffix(other_files->str, ".pot")) g_string_erase(other_files, other_files->len-4, -1); g_string_append(other_files, ".surf"); gtk_entry_set_text(GTK_ENTRY(pot2surf_entry_target_surf_file), other_files->str); g_string_free(other_files, TRUE); dir = gtk_file_chooser_get_current_folder(GTK_FILE_CHOOSER (file_chooser)); visu_ui_main_setLastOpenDirectory(visu_ui_main_class_getCurrentPanel(), dir, VISU_UI_DIR_SURFACE); g_free(dir); gtk_list_store_clear(pot2surf_list_store); gtk_widget_destroy(file_chooser); return; } else break; case GTK_RESPONSE_HELP: break; case GTK_RESPONSE_CANCEL: default: dir = gtk_file_chooser_get_current_folder(GTK_FILE_CHOOSER (file_chooser)); visu_ui_main_setLastOpenDirectory(visu_ui_main_class_getCurrentPanel(), dir, VISU_UI_DIR_SURFACE); g_free(dir); gtk_widget_destroy (file_chooser); return; } } } /* Opens a file chooser to select an instruc file. */ /* void pot2surf_source_instruc_open(GtkWidget *widget, gpointer data) */ /* { */ /* GtkFileFilter *filter_pot = gtk_file_filter_new (); */ /* GtkFileFilter *filter_none = gtk_file_filter_new(); */ /* GtkWidget* file_chooser = */ /* gtk_file_chooser_dialog_new("Select an instruction file", GTK_WINDOW(convert_window), */ /* GTK_FILE_CHOOSER_ACTION_OPEN, */ /* GTK_STOCK_CANCEL, GTK_RESPONSE_CANCEL, */ /* /\* GTK_STOCK_HELP, GTK_RESPONSE_HELP, *\/ */ /* GTK_STOCK_OK, GTK_RESPONSE_ACCEPT, NULL); */ /* gchar *directory = visu_ui_getLastOpenDirectory(); */ /* if (directory) */ /* gtk_file_chooser_set_current_folder(GTK_FILE_CHOOSER(file_chooser), directory); */ /* gtk_file_filter_add_pattern(filter_pot, "*.instruc"); */ /* gtk_file_filter_set_name(filter_pot, "Instruction files (*.instruc)"); */ /* gtk_file_chooser_add_filter (GTK_FILE_CHOOSER(file_chooser), filter_pot); */ /* gtk_file_filter_add_pattern(filter_none, "*"); */ /* gtk_file_filter_set_name(filter_none, "All files"); */ /* gtk_file_chooser_add_filter (GTK_FILE_CHOOSER(file_chooser), filter_none); */ /* while(1) */ /* { */ /* switch(gtk_dialog_run(GTK_DIALOG(file_chooser))) */ /* { */ /* gchar *selected_file; */ /* case GTK_RESPONSE_ACCEPT: */ /* selected_file = */ /* gtk_file_chooser_get_filename(GTK_FILE_CHOOSER(file_chooser)); */ /* gtk_entry_set_text(GTK_ENTRY(pot2surf_entry_source_instruc_file), selected_file); */ /* directory = (char*)gtk_file_chooser_get_current_folder(GTK_FILE_CHOOSER (file_chooser)); */ /* visu_ui_setLastOpenDirectory(directory); */ /* g_free(directory); */ /* gtk_widget_destroy(file_chooser); */ /* return; */ /* case GTK_RESPONSE_HELP: */ /* break; */ /* case GTK_RESPONSE_CANCEL: */ /* default: */ /* directory = (char*)gtk_file_chooser_get_current_folder(GTK_FILE_CHOOSER (file_chooser)); */ /* visu_ui_setLastOpenDirectory(directory); */ /* g_free(directory); */ /* gtk_widget_destroy (file_chooser); */ /* return; */ /* } */ /* } */ /* } */ /* Opens a file chooser to select a surf file. */ void pot2surf_select_surf_file(GtkWidget *widget _U_, gpointer data _U_) { GtkFileFilter *filter_pot = gtk_file_filter_new (); GtkFileFilter *filter_none = gtk_file_filter_new(); GtkWidget* file_chooser = gtk_file_chooser_dialog_new("Select a .surf file", GTK_WINDOW(convert_window), GTK_FILE_CHOOSER_ACTION_SAVE, TOOL_ICON_CANCEL, GTK_RESPONSE_CANCEL, /* GTK_STOCK_HELP, GTK_RESPONSE_HELP, */ TOOL_ICON_OPEN, GTK_RESPONSE_ACCEPT, NULL); const gchar *directory = visu_ui_main_getLastOpenDirectory(visu_ui_main_class_getCurrentPanel()); gchar *dir; if (directory) gtk_file_chooser_set_current_folder(GTK_FILE_CHOOSER(file_chooser), directory); gtk_file_filter_add_pattern(filter_pot, "*.surf"); gtk_file_filter_set_name(filter_pot, "Isosurfaces files (*.surf)"); gtk_file_chooser_add_filter (GTK_FILE_CHOOSER(file_chooser), filter_pot); gtk_file_filter_add_pattern(filter_none, "*"); gtk_file_filter_set_name(filter_none, "All files"); gtk_file_chooser_add_filter (GTK_FILE_CHOOSER(file_chooser), filter_none); while(1) { switch(gtk_dialog_run(GTK_DIALOG(file_chooser))) { gchar *selected_file; case GTK_RESPONSE_ACCEPT: selected_file = gtk_file_chooser_get_filename(GTK_FILE_CHOOSER(file_chooser)); gtk_entry_set_text(GTK_ENTRY(pot2surf_entry_target_surf_file), selected_file); dir = gtk_file_chooser_get_current_folder(GTK_FILE_CHOOSER (file_chooser)); visu_ui_main_setLastOpenDirectory(visu_ui_main_class_getCurrentPanel(), dir, VISU_UI_DIR_SURFACE); g_free(dir); gtk_widget_destroy(file_chooser); return; case GTK_RESPONSE_HELP: break; case GTK_RESPONSE_CANCEL: default: dir = gtk_file_chooser_get_current_folder(GTK_FILE_CHOOSER (file_chooser)); visu_ui_main_setLastOpenDirectory(visu_ui_main_class_getCurrentPanel(), dir, VISU_UI_DIR_SURFACE); g_free(dir); gtk_widget_destroy (file_chooser); return; } } } /* Callback for when a surf name is changed in the gtk_tree_view */ void pot2surf_update_surf_name(GtkCellRendererText *cellrenderertext _U_, gchar *path, gchar *text, gpointer user_data _U_) { GtkTreeIter iter; g_return_if_fail(gtk_tree_model_get_iter_from_string (GTK_TREE_MODEL(pot2surf_list_store), &iter, path)); DBG_fprintf(stderr, "Panel VisuSurfaceTools: entered text '%s'.\n", text); if (!strcmp(text, VISU_UI_SURFACE_NAME_STR)) gtk_list_store_set(pot2surf_list_store, &iter, POT2SURF_NAME, VISU_UI_SURFACE_NAME_CHOOSE, -1); else if (text && text[0]) gtk_list_store_set(pot2surf_list_store, &iter, POT2SURF_NAME, g_strdelimit(text, " ", '_'), -1); else gtk_list_store_set(pot2surf_list_store, &iter, POT2SURF_NAME, VISU_UI_SURFACE_NAME_CHOOSE, -1); } /* Callback for when the pot of a surf to build is changed in the gtk_tree_view */ void pot2surf_update_surf_value(GtkCellRendererText *cellrenderertext _U_, gchar *path, gchar *text, gpointer user_data _U_) { GtkTreeIter iter; float value; float pot_min = atof(gtk_entry_get_text(GTK_ENTRY(pot2surf_potmin))); float pot_max = atof(gtk_entry_get_text(GTK_ENTRY(pot2surf_potmax))); if(sscanf(text, "%f", &value) != 1) return; if(value <= pot_min || value >= pot_max) return; if(gtk_tree_model_get_iter_from_string(GTK_TREE_MODEL(pot2surf_list_store), &iter, path)) gtk_list_store_set(pot2surf_list_store, &iter, POT2SURF_VALUE, value, -1); } /* Sets up the model/view used to represent the surfaces to build from a .pot file. */ void pot2surf_create_tree_view() { GtkCellRenderer* surf_name = gtk_cell_renderer_text_new (); GtkCellRenderer* surf_value = gtk_cell_renderer_text_new (); GtkTreeViewColumn* column1 = gtk_tree_view_column_new_with_attributes(_("Surface name"), surf_name, "markup", POT2SURF_NAME, NULL); GtkTreeViewColumn* column2 = gtk_tree_view_column_new_with_attributes(_("Pot value"), surf_value, "text", POT2SURF_VALUE, NULL); pot2surf_list_store = gtk_list_store_new (POT2SURF_N_COLUMNS, G_TYPE_STRING, G_TYPE_FLOAT); pot2surf_tree_view = gtk_tree_view_new_with_model(GTK_TREE_MODEL(pot2surf_list_store)); g_object_set(G_OBJECT(surf_name), "editable", TRUE, "foreground", "blue", NULL); g_object_set(G_OBJECT(surf_value), "editable", TRUE, "foreground", "blue", NULL); gtk_tree_view_column_set_expand (column1, TRUE); gtk_tree_view_column_set_expand(column2, FALSE); gtk_tree_view_insert_column(GTK_TREE_VIEW(pot2surf_tree_view), column1, -1); gtk_tree_view_insert_column(GTK_TREE_VIEW(pot2surf_tree_view), column2, -1); g_signal_connect(G_OBJECT(surf_name), "edited", G_CALLBACK(pot2surf_update_surf_name), NULL); g_signal_connect(G_OBJECT(surf_value), "edited", G_CALLBACK(pot2surf_update_surf_value), NULL); } /* Adds a new surface to the list of surfaces to build from a .pot file. */ void pot2surf_add_surf(GtkWidget *button _U_, gpointer data _U_) { GtkTreeIter iter, new_row; GtkTreeModel *model; GtkTreeSelection* tree_selection = gtk_tree_view_get_selection(GTK_TREE_VIEW(pot2surf_tree_view)); if(strcmp("", gtk_entry_get_text(GTK_ENTRY(pot2surf_entry_source_pot_file))) == 0) return; tree_selection = gtk_tree_view_get_selection(GTK_TREE_VIEW(pot2surf_tree_view)); if (gtk_tree_selection_get_selected (tree_selection, &model, &iter)) gtk_list_store_insert_after(pot2surf_list_store, &new_row, &iter); else gtk_list_store_append(pot2surf_list_store, &new_row); gtk_tree_selection_select_iter(tree_selection, &new_row); gtk_list_store_set(pot2surf_list_store, &new_row, POT2SURF_NAME, VISU_UI_SURFACE_NAME_CHOOSE, POT2SURF_VALUE, (atof(gtk_entry_get_text(GTK_ENTRY(pot2surf_potmin))) + atof(gtk_entry_get_text(GTK_ENTRY(pot2surf_potmax)))) / 2, -1); } void onSpecialModeToggled(GtkToggleButton *button, gpointer data) { gtk_widget_set_sensitive(GTK_WIDGET(data), gtk_toggle_button_get_active(button)); } void pot2surf_special_add_surf(GtkWidget *button _U_, gpointer data _U_) { float *values, pot_min, pot_max; int nbValues, i; gchar *name; GtkTreeIter new_row; GtkTreeSelection* tree_selection = gtk_tree_view_get_selection(GTK_TREE_VIEW(pot2surf_tree_view)); GtkWidget *dialog; if(strcmp("", gtk_entry_get_text(GTK_ENTRY(pot2surf_entry_source_pot_file))) == 0) return; pot_min = g_ascii_strtod(gtk_entry_get_text(GTK_ENTRY(pot2surf_potmin)), NULL); pot_max = g_ascii_strtod(gtk_entry_get_text(GTK_ENTRY(pot2surf_potmax)), NULL); values = (float*)0; name = (gchar*)0; dialog = visu_ui_panel_surfaces_generateValues(&nbValues, &values, &name, pot_min, pot_max); if (!dialog) return; gtk_widget_destroy(dialog); for (i = 0; i < nbValues; i++) { gtk_list_store_append(pot2surf_list_store, &new_row); gtk_list_store_set(pot2surf_list_store, &new_row, POT2SURF_NAME, (name && name[0])?name:VISU_UI_SURFACE_NAME_CHOOSE, POT2SURF_VALUE, values[i], -1); } if (nbValues) gtk_tree_selection_select_iter(tree_selection, &new_row); if (values) g_free(values); if (name) g_free(name); } /* Removes selected surface from the list of surfaces to build from a .pot file. */ void pot2surf_remove_surf(GtkWidget *button _U_, gpointer data _U_) { GtkTreeIter iter, iter2; GtkTreeModel *model; GtkTreeSelection* tree_selection = gtk_tree_view_get_selection(GTK_TREE_VIEW(pot2surf_tree_view)); gboolean list_empty = TRUE; if (gtk_tree_selection_get_selected (tree_selection, &model, &iter)) { iter2 = iter; if(gtk_tree_model_iter_previous(model, &iter2)) list_empty = FALSE; if(gtk_list_store_remove(pot2surf_list_store, &iter)) gtk_tree_selection_select_iter(tree_selection, &iter); else if(list_empty == FALSE) gtk_tree_selection_select_iter(tree_selection, &iter2); } } /* Callback for when a user decides to move up or down a surface. data == GINT_TO_POINTER(1) : move up data == GINT_TO_POINTER(-1) : move down */ void pot2surf_move_surf(GtkWidget *button _U_, gpointer data) { GtkTreeIter iter, iter2; GtkTreeModel *model; int direction; GtkTreeSelection* tree_selection = gtk_tree_view_get_selection(GTK_TREE_VIEW(pot2surf_tree_view)); if(data == NULL) return; direction = GPOINTER_TO_INT(data); if(direction != -1 && direction != 1) return; if(!gtk_tree_selection_get_selected(tree_selection, &model, &iter)) return; iter2 = iter; if(direction == 1) { if(gtk_tree_model_iter_next(model, &iter2)) gtk_list_store_move_after(pot2surf_list_store, &iter, &iter2); } else if(direction == -1) { if(gtk_tree_model_iter_previous(model, &iter2)) gtk_list_store_move_before(pot2surf_list_store, &iter, &iter2); } } /* Only used through a gtk_tree_model_foreach() count the number of element present in a GtkTreeModel */ gboolean pot2surf_count_surf(GtkTreeModel *model _U_, GtkTreePath *path _U_, GtkTreeIter *iter _U_, gpointer data) { int *n = data; (*n)++; return FALSE; } /* Only used through a gtk_tree_model_foreach() Writes a surface name and value in an instruc file. */ gboolean pot2surf_write_surf(GtkTreeModel *model, GtkTreePath *path _U_, GtkTreeIter *iter, gpointer data) { FILE *instruc = data; char *surf_name=NULL; float surf_value; gtk_tree_model_get(GTK_TREE_MODEL(model), iter, POT2SURF_NAME, &surf_name, POT2SURF_VALUE, &surf_value, -1); fprintf(instruc, "%f %s\n", surf_value, surf_name); g_free(surf_name); return FALSE; } /* Tries to build a valid .instruc file. */ /* Returns : 0 in case of success n != 0 otherwise */ gboolean pot2surf_build_instruc_file(const gchar *pot_file, const gchar *surf_file, const gchar *instruc_file, int n) { FILE *instruc = NULL; if(instruc_file == NULL || strcmp(instruc_file, "") == 0) { visu_ui_raiseWarning(_("Loading a file"), _("Please select an instruc file to write"), (GtkWindow*)0); return FALSE; } if((instruc = fopen(instruc_file, "w")) == NULL) { visu_ui_raiseWarning(_("Loading a file"), _("Can't open selected instruc file for writing"), (GtkWindow*)0); return FALSE; } DBG_fprintf(stderr, "pot2surf : writing/overwriting %s file...\n", instruc_file); fprintf(instruc, "%s\n", pot_file); fprintf(instruc, "%s\n", surf_file); fprintf(instruc, "%d\n", n); gtk_tree_model_foreach(GTK_TREE_MODEL(pot2surf_list_store), pot2surf_write_surf, instruc); DBG_fprintf(stderr, "pot2surf : ...finished to write file\n"); fclose(instruc); return TRUE; } void pot2surf_select_instruc_file_to_save() { GtkFileFilter *filter_instruc; GtkFileFilter *filter_none; GtkWidget* file_chooser; const char *directory = visu_ui_main_getLastOpenDirectory(visu_ui_main_class_getCurrentPanel()); int n=0; const gchar *pot_file = gtk_entry_get_text(GTK_ENTRY(pot2surf_entry_source_pot_file)); const gchar *surf_file = gtk_entry_get_text(GTK_ENTRY(pot2surf_entry_target_surf_file)); GString *default_file = NULL; gtk_tree_model_foreach(GTK_TREE_MODEL(pot2surf_list_store), pot2surf_count_surf, &n); if(n == 0) { visu_ui_raiseWarning(_("Saving a file"), _("Please specify surfaces to draw"), (GtkWindow*)0); return; } if(strcmp(pot_file, "") == 0) { visu_ui_raiseWarning(_("Saving a file"), _("Please select a source pot file"), (GtkWindow*)0); return; } if(surf_file == NULL || strcmp(surf_file, "") == 0) { visu_ui_raiseWarning(_("Saving a file"), _("Please select a target surf file"), (GtkWindow*)0); return; } default_file = g_string_new(""); g_string_append(default_file, pot_file); g_string_append(default_file, ".instruc"); filter_instruc = gtk_file_filter_new (); filter_none = gtk_file_filter_new(); file_chooser = gtk_file_chooser_dialog_new("Save as a .instruc file", GTK_WINDOW(convert_window), GTK_FILE_CHOOSER_ACTION_SAVE, TOOL_ICON_CANCEL, GTK_RESPONSE_CANCEL, TOOL_ICON_SAVE, GTK_RESPONSE_ACCEPT, NULL); if(directory) gtk_file_chooser_set_current_folder(GTK_FILE_CHOOSER(file_chooser), directory); gtk_file_chooser_set_filename(GTK_FILE_CHOOSER(file_chooser),default_file->str); gtk_file_filter_add_pattern(filter_instruc, "*.instruc"); gtk_file_filter_set_name(filter_instruc, "Instruction files (*.instruc)"); gtk_file_chooser_add_filter (GTK_FILE_CHOOSER(file_chooser), filter_instruc); gtk_file_filter_add_pattern(filter_none, "*"); gtk_file_filter_set_name(filter_none, "All files"); gtk_file_chooser_add_filter (GTK_FILE_CHOOSER(file_chooser), filter_none); while(1) switch(gtk_dialog_run(GTK_DIALOG(file_chooser))) { case GTK_RESPONSE_ACCEPT: if(!pot2surf_build_instruc_file(pot_file, surf_file, gtk_file_chooser_get_filename(GTK_FILE_CHOOSER(file_chooser)), n)) break; visu_ui_main_setLastOpenDirectory(visu_ui_main_class_getCurrentPanel(), gtk_file_chooser_get_current_folder(GTK_FILE_CHOOSER (file_chooser)), VISU_UI_DIR_SURFACE); g_string_free(default_file, TRUE); gtk_widget_destroy(file_chooser); return; case GTK_RESPONSE_CANCEL: default: g_string_free(default_file, TRUE); gtk_widget_destroy (file_chooser); return; } } /* Only used through a gtk_tree_model_foreach() Writes a surface name and value in a struct surf array */ gboolean pot2surf_get_surfs(GtkTreeModel *model, GtkTreePath *path _U_, GtkTreeIter *iter, gpointer data) { struct surf { char *name; float value; }; struct surf *surfaces = data; int i; for(i=0; surfaces[i].name != NULL; i++); gtk_tree_model_get(GTK_TREE_MODEL(model), iter, POT2SURF_NAME, &surfaces[i].name, POT2SURF_VALUE, &surfaces[i].value, -1); return FALSE; } /* Tries to build a valid .instruc file and then to executes this file. */ gboolean pot2surf_build_surf_file(GtkWidget *button _U_, gpointer data) { struct surf { char *name; float value; }; float *values = NULL; gchar **names = NULL; struct surf *surfaces = NULL; int n=0, i; GtkTreeIter iter; const gchar *pot_file = gtk_entry_get_text(GTK_ENTRY(pot2surf_entry_source_pot_file)); const gchar *surf_file = gtk_entry_get_text(GTK_ENTRY(pot2surf_entry_target_surf_file)); gtk_tree_model_foreach(GTK_TREE_MODEL(pot2surf_list_store), pot2surf_count_surf, &n); if(n == 0) { visu_ui_raiseWarning(_("Saving a file"), _("Please specify surfaces to draw"), (GtkWindow*)0); return FALSE; } if(pot_file == NULL || strcmp(pot_file, "") == 0) { visu_ui_raiseWarning(_("Saving a file"), _("Please select a source pot file"), (GtkWindow*)0); return FALSE; } if(surf_file == NULL || strcmp(surf_file, "") == 0) { visu_ui_raiseWarning(_("Saving a file"), _("Please select a target surf file"), (GtkWindow*)0); return FALSE; } surfaces = g_malloc(n*sizeof(struct surf)); values = g_malloc(n*sizeof(float)); names = g_malloc(n*sizeof(gchar *)); for(i=0; istr, 0) == 0) */ /* { */ /* g_string_free(surf_file_wrote, TRUE); */ /* return FALSE; */ /* } */ /* return TRUE; */ /* } */ /* void pot2surf_select_build_surf(GtkWidget *radio_button, GtkWidget *hbox) */ /* { */ /* gtk_widget_set_sensitive(hbox, gtk_toggle_button_get_active(GTK_TOGGLE_BUTTON(radio_button))); */ /* } */ /* void pot2surf_select_build_instruc(GtkWidget *radio_button, GtkWidget *hbox) */ /* { */ /* gtk_widget_set_sensitive(hbox, gtk_toggle_button_get_active(GTK_TOGGLE_BUTTON(radio_button))); */ /* } */ gboolean pot2surf_load_instruc_file(const gchar *instruc_filename) { GIOChannel* instruc_file=NULL; GString *line=NULL; gchar *surf_file=NULL; gchar *pot_file=NULL; int n=0, i, j; gchar **surf_names; float *surf_values; GtkTreeIter iter; float pot_min, pot_max; char float_to_string[128]; instruc_file = g_io_channel_new_file(instruc_filename, "r", NULL); line = g_string_new(""); if(instruc_file == NULL) { visu_ui_raiseWarning(_("Loading a file"), _("Can't open selected file"), (GtkWindow*)0); return FALSE; } if(g_io_channel_read_line_string(instruc_file, line, NULL, NULL) != G_IO_STATUS_NORMAL) { visu_ui_raiseWarning(_("Loading a file"), _("Line 1 must contain the full path to the .pot" " file to read\n"), (GtkWindow*)0); g_string_free(line, TRUE); return FALSE; } pot_file = g_strstrip(g_strdup(line->str)); if(g_io_channel_read_line_string(instruc_file, line, NULL, NULL) != G_IO_STATUS_NORMAL) { visu_ui_raiseWarning(_("Loading a file"), _("Line 2 must contain the full path to the" " .surf file to read\n"), (GtkWindow*)0); g_string_free(line, TRUE); g_free(instruc_file); return FALSE; } surf_file = g_strstrip(g_strdup(line->str)); if((g_io_channel_read_line_string(instruc_file, line, NULL, NULL) != G_IO_STATUS_NORMAL) || (sscanf(line->str, "%d", &n) != 1)) { visu_ui_raiseWarning(_("Loading a file"), _("Line 3 must contain the number of" " surfaces to build\n"), (GtkWindow*)0); g_string_free(line, TRUE); g_free(instruc_file); g_free(surf_file); return FALSE; } surf_names = g_malloc(n*sizeof(gchar *)); surf_values = g_malloc(n*sizeof(gchar *)); for(i=0; istr, "%f %s", &surf_values[i], surf_names[i]) != 2)) { visu_ui_raiseWarning(_("Loading a file"), _("Lines must contain the value of the" " surface to build and its name\n"), (GtkWindow*)0); g_string_free(line, TRUE); g_free(instruc_file); g_free(surf_file); for(j=0; j #if GTK_MAJOR_VERSION < 3 /** * gtk_tree_model_iter_previous: * @tree_model: the #GtkTreeModel to get the previous iteration from ; * @iter: a location to a #GtkTreeIter to store the result. * * Similar to gtk_tree_model_iter_next(). See * www.gtk.org * for more info. * * Return value: TRUE if @iter has been changed to the next node. **/ gboolean gtk_tree_model_iter_previous(GtkTreeModel *tree_model, GtkTreeIter *iter); #endif /** * visu_ui_panel_surfaces_tools_fileWidget: * * Creates a widget containing an interface to merge surf files. * Don't use two of them simultaneously, * they would conflict. * * Return value: an allocated GtkWidget containing the interface. **/ GtkWidget *visu_ui_panel_surfaces_tools_fileWidget(); /** * visu_ui_panel_surfaces_tools_convertWidget: * * Creates a widget containing the whole pot2surf frontend. Don't use two of them simultaneously, * they would conflict. * * Return value: an allocated GtkWidget containing the interface. **/ GtkWidget *visu_ui_panel_surfaces_tools_convertWidget(); /** * visu_ui_panel_surfaces_tools_init: * * Opens a new window containing tools to operate on surf and pot files. **/ void visu_ui_panel_surfaces_tools_init(); #endif v_sim-3.8.0/src/panelModules/panelVibration.c000066400000000000000000000410751370110300500211740ustar00rootroot00000000000000/* EXTRAITS DE LA LICENCE Copyright CEA, contributeurs : Luc BILLARD, Damien CALISTE, laboratoire L_Sim, (2001-2005) Adresse mèl : BILLARD, non joignable par mèl ; CALISTE, damien P caliste AT cea P fr. Ce logiciel est un programme informatique servant à visualiser des structures atomiques dans un rendu pseudo-3D. Ce logiciel est régi par la licence CeCILL soumise au droit français et respectant les principes de diffusion des logiciels libres. Vous pouvez utiliser, modifier et/ou redistribuer ce programme sous les conditions de la licence CeCILL telle que diffusée par le CEA, le CNRS et l'INRIA sur le site "http://www.cecill.info". Le fait que vous puissiez accéder à cet en-tête signifie que vous avez pris connaissance de la licence CeCILL, et que vous en avez accepté les termes (cf. le fichier Documentation/licence.fr.txt fourni avec ce logiciel). */ /* LICENCE SUM UP Copyright CEA, contributors : Luc BILLARD and Damien CALISTE and Olivier D'Astier, laboratoire L_Sim, (2001-2005) E-mail addresses : BILLARD, not reachable any more ; CALISTE, damien P caliste AT cea P fr. This software is a computer program whose purpose is to visualize atomic configurations in 3D. This software is governed by the CeCILL license under French law and abiding by the rules of distribution of free software. You can use, modify and/ or redistribute the software under the terms of the CeCILL license as circulated by CEA, CNRS and INRIA at the following URL "http://www.cecill.info". The fact that you are presently reading this means that you have had knowledge of the CeCILL license and that you accept its terms. You can find a copy of this licence shipped with this software at Documentation/licence.en.txt. */ #include #include #include #include #include #include #include #include #include #include "panelVibration.h" /** * SECTION: panelVibration * @short_description: The tab where phonons are loaded and listed. * * Nothing tunable here. */ enum { NUM_COLUMN, FREQ_COLUMN, Q_COLUMN, ENERGY_COLUMN, N_COLUMN }; /* Local objects. */ static GtkWidget *panelVibration; static GtkWidget *vboxStart; static GtkWidget *buttonPlay, *buttonStop, *buttonReset; static GtkWidget *treeView; static GtkWidget *checkSpin, *spinAmpl, *spinFreq; /* Local variables. */ static gboolean widgetsNotBuilt; static GtkListStore *pListStore; static VisuVibration *vibs = NULL; static GBinding *bind_play, *bind_freq, *bind_ampl; /* Local routines. */ static GtkWidget *createInteriorVibe(VisuGlNodeScene *scene); /* Local callbacks. */ static void onVibeEnter(VisuUiPanel *visu_ui_panel, gpointer data); /* static void onDirectoryClicked(GtkButton *button , gpointer data); */ static void onPlayClicked(GtkButton *button, gpointer dataObj); static void onStopClicked(GtkButton *button, gpointer data); static void onResetClicked(GtkButton *button , gpointer dataObj); static void onDataFocused(GObject *obj, VisuData *dataObj, gpointer data); static void onViewClikcked(); static void onDestroy(); /* static void onFreqChecked(GtkToggleButton *toggle, gpointer data); */ /* Setup the selection handler */ static GtkTreeSelection *treeSelection; static gulong sel_sig; /* The string common to all paths in currentBrowseredDirectory. */ static gchar *commonBrowseredDirectory; VisuUiPanel* visu_ui_panel_vibration_init(VisuUiMain *ui) { VisuGlNodeScene *scene; GtkWidget *checkFreq; panelVibration = visu_ui_panel_newWithIconFromPath("panel_Vibration", _("Phonons"), _("Phonons"), "stock-phonons.png"); if (!panelVibration) return (VisuUiPanel*)0; scene = visu_ui_rendering_window_getGlScene(visu_ui_main_getRendering(ui)); visu_ui_panel_setDockable(VISU_UI_PANEL(panelVibration), TRUE); vboxStart = gtk_vbox_new(FALSE, 0); commonBrowseredDirectory = (char *)0; checkSpin = gtk_check_button_new_with_mnemonic(_("with _arrow")); checkFreq = gtk_check_button_new_with_mnemonic(_("use _fixed frequency")); g_object_bind_property(scene, "data", checkFreq, "sensitive", G_BINDING_SYNC_CREATE); /* Create the callbacks of all the sensitive widgets. */ g_signal_connect(G_OBJECT(panelVibration), "page-entered", G_CALLBACK(onVibeEnter), scene); g_signal_connect(G_OBJECT(ui), "DataFocused", G_CALLBACK(onDataFocused), (gpointer)0); pListStore = gtk_list_store_new(N_COLUMN, G_TYPE_INT, G_TYPE_FLOAT, G_TYPE_STRING, G_TYPE_FLOAT); widgetsNotBuilt = TRUE; return VISU_UI_PANEL(panelVibration); } static void onVibeEnter(VisuUiPanel *visu_ui_panel _U_, gpointer data) { if (widgetsNotBuilt) { DBG_fprintf(stderr, "Panel Vibe: first build on enter.\n"); widgetsNotBuilt = FALSE; gtk_container_add(GTK_CONTAINER(panelVibration), createInteriorVibe(VISU_GL_NODE_SCENE(data))); } } static GtkWidget *createInteriorVibe(VisuGlNodeScene *scene) { GtkWidget *vbox1; GtkWidget /* *hbox1, */*hbox2, *hbox; GtkWidget *label; /* GtkWidget *buttonDirectory; */ GtkWidget *image; GtkWidget *scrollbar; GtkCellRenderer *CellRender; GtkTreeViewColumn *column; VisuData *data; #if GTK_MAJOR_VERSION == 2 && GTK_MINOR_VERSION < 12 GtkTooltips *tooltips; tooltips = gtk_tooltips_new (); #endif vbox1 = gtk_vbox_new(FALSE, 0); /* hbox1 = gtk_hbox_new(FALSE, 0); */ hbox2 = gtk_hbox_new(FALSE, 0); /* the first hbox with the "open-file" button */ /* gtk_box_pack_start(GTK_BOX(vbox1), hbox1, FALSE, FALSE, 2); */ /* buttonDirectory = gtk_button_new (); */ /* gtk_box_pack_start (GTK_BOX (hbox1), buttonDirectory, FALSE, FALSE, 2); */ /* gtk_widget_set_tooltip_text(buttonDirectory, */ /* _("Choose a different directory.")); */ /* image = gtk_image_new_from_stock ("gtk-open", GTK_ICON_SIZE_BUTTON); */ /* gtk_container_add (GTK_CONTAINER (buttonDirectory), image); */ /* label = gtk_label_new("open phonon file"); */ /* gtk_container_add(GTK_CONTAINER(hbox1), label); */ /* gtk_misc_set_alignment (GTK_MISC (label), 0, 0.5); */ /* the checkboxes */ hbox = gtk_hbox_new(FALSE, 0); gtk_box_pack_start(GTK_BOX(vbox1), hbox, FALSE, FALSE, 0); gtk_widget_set_tooltip_text(checkSpin, _("Draw arrows on nodes that represent" " their displacements.")); g_object_bind_property(visu_gl_node_scene_getVibrations(scene), "active", checkSpin, "active", G_BINDING_SYNC_CREATE | G_BINDING_BIDIRECTIONAL); gtk_box_pack_start(GTK_BOX(hbox), checkSpin, TRUE, TRUE, 0); /* gtk_widget_set_tooltip_text(checkFreq, */ /* _("Use a given frequency for the" */ /* " vibration representation.")); */ /* g_signal_connect(G_OBJECT(checkFreq), "toggled", */ /* G_CALLBACK(onFreqChecked), (gpointer)0); */ /* gtk_box_pack_start(GTK_BOX(hbox), checkFreq, FALSE, FALSE, 0); */ /* gtk_widget_set_sensitive(checkFreq, FALSE); */ /* the second hbox with the treeview */ treeView = gtk_tree_view_new(); gtk_tree_view_set_model(GTK_TREE_VIEW(treeView), GTK_TREE_MODEL(pListStore)); CellRender = gtk_cell_renderer_text_new(); /* when clicking in the treeView */ treeSelection = gtk_tree_view_get_selection (GTK_TREE_VIEW (treeView)); gtk_tree_selection_set_mode (treeSelection, GTK_SELECTION_SINGLE); /* make and add the first column to the view */ column = gtk_tree_view_column_new_with_attributes(_("id"), CellRender, "text", NUM_COLUMN, NULL); gtk_tree_view_append_column(GTK_TREE_VIEW(treeView), column); /* make and add the second column to the view */ column = gtk_tree_view_column_new_with_attributes(_("q point"), CellRender, "text", Q_COLUMN, NULL); gtk_tree_view_append_column(GTK_TREE_VIEW(treeView), column); /* make and add the third column to the view */ column = gtk_tree_view_column_new_with_attributes(_("energy"), CellRender, "text", ENERGY_COLUMN, NULL); gtk_tree_view_append_column(GTK_TREE_VIEW(treeView), column); /* make and add the fourth column to the view */ column = gtk_tree_view_column_new_with_attributes("\317\211", CellRender, "text", FREQ_COLUMN, NULL); gtk_tree_view_append_column(GTK_TREE_VIEW(treeView), column); /* put the treeview with a scrollbar in the tab*/ scrollbar = gtk_scrolled_window_new(NULL, NULL); gtk_scrolled_window_set_policy(GTK_SCROLLED_WINDOW(scrollbar), GTK_POLICY_AUTOMATIC, GTK_POLICY_AUTOMATIC); gtk_scrolled_window_set_shadow_type(GTK_SCROLLED_WINDOW(scrollbar), GTK_SHADOW_ETCHED_IN); gtk_container_add(GTK_CONTAINER(scrollbar), treeView); gtk_box_pack_start(GTK_BOX(vbox1), scrollbar, TRUE, TRUE, 0); /* the third hbox with the timer, resetButton and PlayStop Button */ gtk_box_pack_end(GTK_BOX(vbox1), hbox2, FALSE, FALSE, 2); /* the timer */ label = gtk_label_new(_("Freq.: ")); gtk_box_pack_start(GTK_BOX(hbox2), label, FALSE, FALSE, 2); spinFreq = gtk_spin_button_new_with_range(0, 20, 1); gtk_box_pack_start(GTK_BOX(hbox2), spinFreq, FALSE, FALSE, 2); /* the amplitude */ label = gtk_label_new(_("Ampl.: ")); gtk_box_pack_start(GTK_BOX(hbox2), label, FALSE, FALSE, 2); spinAmpl = gtk_spin_button_new_with_range(0, 2, 0.1); gtk_box_pack_start(GTK_BOX(hbox2), spinAmpl, FALSE, FALSE, 2); /* Stop Button */ buttonStop = gtk_button_new (); gtk_box_pack_end(GTK_BOX (hbox2), buttonStop, FALSE, FALSE, 2); gtk_widget_set_tooltip_text(buttonStop, _("Stop the nodes at their given positions.")); image = gtk_image_new_from_icon_name("nedia-playback-stop", GTK_ICON_SIZE_BUTTON); gtk_container_add (GTK_CONTAINER (buttonStop), image); /* Play Button */ buttonPlay = gtk_button_new (); gtk_box_pack_end(GTK_BOX (hbox2), buttonPlay, FALSE, FALSE, 2); gtk_widget_set_tooltip_text(buttonPlay, _("Move the nodes according to their phonon vibration.")); image = gtk_image_new_from_icon_name("media-playback-start", GTK_ICON_SIZE_BUTTON); gtk_container_add (GTK_CONTAINER (buttonPlay), image); gtk_widget_set_sensitive(buttonPlay, FALSE); /* reset button */ buttonReset = gtk_button_new_with_label(_("Reset")); gtk_box_pack_end(GTK_BOX (hbox2), buttonReset, FALSE, FALSE, 2); gtk_widget_set_tooltip_text(buttonReset, _("Reset the node positions to input file coordinates.")); /* to show all the content of the tab */ gtk_widget_show_all(vbox1); gtk_widget_set_sensitive(buttonPlay, FALSE); g_object_bind_property(buttonPlay, "visible", buttonStop, "visible", G_BINDING_SYNC_CREATE | G_BINDING_INVERT_BOOLEAN); /* g_signal_connect(G_OBJECT(buttonDirectory), "clicked", */ /* G_CALLBACK(onDirectoryClicked), (gpointer)0); */ g_signal_connect(G_OBJECT(buttonPlay), "clicked", G_CALLBACK(onPlayClicked), (gpointer)0); g_signal_connect(G_OBJECT(treeView), "row-activated", G_CALLBACK(onPlayClicked), (gpointer)0); g_signal_connect(G_OBJECT(buttonStop), "clicked", G_CALLBACK(onStopClicked), (gpointer)0); g_signal_connect(G_OBJECT(buttonReset), "clicked", G_CALLBACK(onResetClicked), (gpointer)0); sel_sig = g_signal_connect(G_OBJECT(treeSelection), "changed", G_CALLBACK(onViewClikcked), (gpointer)0); g_signal_connect(G_OBJECT(vbox1), "destroy", G_CALLBACK(onDestroy), (gpointer)0); data = visu_ui_panel_getData(VISU_UI_PANEL(panelVibration)); if(data) onDataFocused((GObject*)0, data, (gpointer)0); return vbox1; } static void onDataFocused(GObject *obj _U_, VisuData *dataObj, gpointer data _U_) { VisuVibration *vib; gchar *sTexte; guint i; float qpt[3], en, omega; GtkTreeIter pIter; guint nSet; DBG_fprintf(stderr, "Panel Vibration: caught 'DataFocused' signal (%p).\n", (gpointer)dataObj); if (widgetsNotBuilt) return; g_signal_handler_block(treeSelection, sel_sig); gtk_list_store_clear(pListStore); if (vibs) { g_object_unref(bind_play); g_object_unref(bind_ampl); g_object_unref(bind_freq); g_object_unref(vibs); } vib = dataObj ? visu_data_getVibration(dataObj, 0) : (VisuVibration*)0; if (vib) { g_object_ref(vib); /* Fill TreeView Model */ DBG_fprintf(stderr, "panelVibration: filling treeView ...\n"); nSet = visu_vibration_getNPhonons(vib); for (i = 0; i < nSet; i++) { visu_vibration_getCharacteristic(vib, i, qpt, &en, &omega); sTexte = g_strdup_printf("(%g;%g;%g)", qpt[0], qpt[1], qpt[2]); /* Create a new line */ gtk_list_store_append(pListStore, &pIter); /* update data */ gtk_list_store_set(pListStore, &pIter, NUM_COLUMN, i+1, FREQ_COLUMN, omega, Q_COLUMN, sTexte, ENERGY_COLUMN, en, -1); g_free(sTexte); } bind_play = g_object_bind_property (visu_animatable_getAnimation(VISU_ANIMATABLE(vib), "reduced-time"), "running", buttonPlay, "visible", G_BINDING_SYNC_CREATE | G_BINDING_INVERT_BOOLEAN); bind_ampl = g_object_bind_property (vib, "amplitude", spinAmpl, "value", G_BINDING_SYNC_CREATE | G_BINDING_BIDIRECTIONAL); bind_freq = g_object_bind_property (vib, "frequency", spinFreq, "value", G_BINDING_SYNC_CREATE | G_BINDING_BIDIRECTIONAL); } vibs = vib; g_signal_handler_unblock(treeSelection, sel_sig); gtk_widget_set_sensitive(checkSpin, (vibs != (VisuVibration*)0)); gtk_widget_set_sensitive(buttonReset, (vibs != (VisuVibration*)0)); } /* static void onDirectoryClicked(GtkButton *button _U_, gpointer data _U_) */ /* { */ /* GtkWidget *file_selector; */ /* gchar *filename; */ /* GtkFileFilter *filter; */ /* file_selector = gtk_file_chooser_dialog_new(_("Choose a file to open"), NULL, */ /* GTK_FILE_CHOOSER_ACTION_OPEN, */ /* GTK_STOCK_CANCEL, GTK_RESPONSE_CANCEL, */ /* GTK_STOCK_OPEN, GTK_RESPONSE_ACCEPT, */ /* NULL); */ /* filter = gtk_file_filter_new (); */ /* gtk_file_filter_add_pattern (filter, "*.xyz"); */ /* gtk_file_chooser_add_filter (GTK_FILE_CHOOSER(file_selector), filter); */ /* if (gtk_dialog_run (GTK_DIALOG (file_selector)) == GTK_RESPONSE_ACCEPT) */ /* { */ /* filename = gtk_file_chooser_get_filename (GTK_FILE_CHOOSER (file_selector)); */ /* } */ /* else */ /* filename = (gchar*)0; */ /* gtk_widget_destroy (file_selector); */ /* if (filename) { */ /* DBG_fprintf(stderr, "panelVibration: opening file \" %s \" \n", filename); */ /* } */ /* } */ static void onPlayClicked(GtkButton *button _U_, gpointer timer _U_) { if (!vibs) return; visu_vibration_animate(vibs); } static void onStopClicked(GtkButton *button _U_, gpointer data _U_) { if (!vibs) return; visu_animation_abort(visu_animatable_getAnimation(VISU_ANIMATABLE(vibs), "reduced-time")); } static void onResetClicked(GtkButton *button _U_, gpointer dataObj _U_) { DBG_fprintf(stderr, "panelVibration: reseting all nodes position \n"); onStopClicked(NULL, NULL); if (vibs) visu_vibration_resetPosition(vibs); gtk_tree_selection_unselect_all(treeSelection); } static void onViewClikcked() { GtkTreeIter iter; GtkTreeModel *model; int num; GError *error; model = GTK_TREE_MODEL(pListStore); if (!gtk_tree_selection_get_selected(treeSelection, &model, &iter) || !vibs) { gtk_widget_set_sensitive(buttonPlay, FALSE); return; } gtk_widget_set_sensitive(buttonPlay, TRUE); gtk_tree_model_get(model, &iter, NUM_COLUMN, &num, -1); DBG_fprintf(stderr, "Panel Vibration: You have selected a new mode number %d.\n", num); error = (GError*)0; visu_vibration_setCurrentMode(vibs, (guint)(num - 1), &error); if (error) { visu_ui_raiseWarning(_("Vibration file reloading"), error->message, (GtkWindow*)0); g_error_free(error); visu_gl_node_scene_setData(visu_ui_rendering_window_getGlScene(visu_ui_main_class_getDefaultRendering()), (VisuData*)0); return; } /* Set the initiale phase properly. */ visu_vibration_setZeroTime(vibs); DBG_fprintf(stderr, "panelVibration: new proper mode loaded.\n"); } /* static void onFreqChecked(GtkToggleButton *toggle, gpointer data _U_) */ /* { */ /* if (gtk_toggle_button_get_active(toggle)) */ /* visu_vibration_setUserFrequency(visu_ui_panel_getData(VISU_UI_PANEL(panelVibration)), 50.f); */ /* else */ /* visu_vibration_setUserFrequency(visu_ui_panel_getData(VISU_UI_PANEL(panelVibration)), 0.f); */ /* } */ static void onDestroy() { onDataFocused((GObject*)0, (VisuData*)0, (gpointer)0); } v_sim-3.8.0/src/panelModules/panelVibration.h000066400000000000000000000041621370110300500211750ustar00rootroot00000000000000/* EXTRAITS DE LA LICENCE Copyright CEA, contributeurs : Luc BILLARD et Damien CALISTE, laboratoire L_Sim, (2001-2005) Adresse mèl : BILLARD, non joignable par mèl ; CALISTE, damien P caliste AT cea P fr. Ce logiciel est un programme informatique servant à visualiser des structures atomiques dans un rendu pseudo-3D. Ce logiciel est régi par la licence CeCILL soumise au droit français et respectant les principes de diffusion des logiciels libres. Vous pouvez utiliser, modifier et/ou redistribuer ce programme sous les conditions de la licence CeCILL telle que diffusée par le CEA, le CNRS et l'INRIA sur le site "http://www.cecill.info". Le fait que vous puissiez accéder à cet en-tête signifie que vous avez pris connaissance de la licence CeCILL, et que vous en avez accepté les termes (cf. le fichier Documentation/licence.fr.txt fourni avec ce logiciel). */ /* LICENCE SUM UP Copyright CEA, contributors : Luc BILLARD et Damien CALISTE, laboratoire L_Sim, (2001-2005) E-mail address: BILLARD, not reachable any more ; CALISTE, damien P caliste AT cea P fr. This software is a computer program whose purpose is to visualize atomic configurations in 3D. This software is governed by the CeCILL license under French law and abiding by the rules of distribution of free software. You can use, modify and/ or redistribute the software under the terms of the CeCILL license as circulated by CEA, CNRS and INRIA at the following URL "http://www.cecill.info". The fact that you are presently reading this means that you have had knowledge of the CeCILL license and that you accept its terms. You can find a copy of this licence shipped with this software at Documentation/licence.en.txt. */ #ifndef PANELVIBRATION_H #define PANELVIBRATION_H #include /** * visu_ui_panel_vibration_init: * * Should be used in the list declared in externalModules.h to be loaded by * V_Sim on start-up. This routine will create the #VisuUiPanel where the box * * Returns: a newly created #VisuUiPanel object. */ VisuUiPanel* visu_ui_panel_vibration_init(); #endif v_sim-3.8.0/src/renderingBackend/000077500000000000000000000000001370110300500166415ustar00rootroot00000000000000v_sim-3.8.0/src/renderingBackend/visu_actionInterface.h000066400000000000000000000103321370110300500231550ustar00rootroot00000000000000/* EXTRAITS DE LA LICENCE Copyright CEA, contributeurs : Luc BILLARD et Damien CALISTE, laboratoire L_Sim, (2001-2005) Adresse mèl : BILLARD, non joignable par mèl ; CALISTE, damien P caliste AT cea P fr. Ce logiciel est un programme informatique servant à visualiser des structures atomiques dans un rendu pseudo-3D. Ce logiciel est régi par la licence CeCILL soumise au droit français et respectant les principes de diffusion des logiciels libres. Vous pouvez utiliser, modifier et/ou redistribuer ce programme sous les conditions de la licence CeCILL telle que diffusée par le CEA, le CNRS et l'INRIA sur le site "http://www.cecill.info". Le fait que vous puissiez accéder à cet en-tête signifie que vous avez pris connaissance de la licence CeCILL, et que vous en avez accepté les termes (cf. le fichier Documentation/licence.fr.txt fourni avec ce logiciel). */ /* LICENCE SUM UP Copyright CEA, contributors : Luc BILLARD et Damien CALISTE, laboratoire L_Sim, (2001-2005) E-mail address: BILLARD, not reachable any more ; CALISTE, damien P caliste AT cea P fr. This software is a computer program whose purpose is to visualize atomic configurations in 3D. This software is governed by the CeCILL license under French law and abiding by the rules of distribution of free software. You can use, modify and/ or redistribute the software under the terms of the CeCILL license as circulated by CEA, CNRS and INRIA at the following URL "http://www.cecill.info". The fact that you are presently reading this means that you have had knowledge of the CeCILL license and that you accept its terms. You can find a copy of this licence shipped with this software at Documentation/licence.en.txt. */ #ifndef VISU_ACTIONINTERFACE_H #define VISU_ACTIONINTERFACE_H #include /** * SECTION:visu_actionInterface * @short_description: Interface for defining actions and events. * * These definitions are used to give a library and plateform * independent simplified event handlers. */ /** * ToolButtonActionId: * @TOOL_BUTTON_TYPE_NONE: not a button event * @TOOL_BUTTON_TYPE_PRESS: a press button event * @TOOL_BUTTON_TYPE_RELEASE: a release button event * * Value that can be put into field buttonType of structure #ToolSimplifiedEvents. */ typedef enum { TOOL_BUTTON_TYPE_NONE, TOOL_BUTTON_TYPE_PRESS, TOOL_BUTTON_TYPE_RELEASE } ToolButtonActionId; /** * ToolSpecialKeyStroke: * @Key_None: no key pressed ; * @Key_Page_Up: key up ; * @Key_Page_Down: key down ; * @Key_Arrow_Left: key left ; * @Key_Arrow_Right: key right ; * @Key_Arrow_Up: key up ; * @Key_Arrow_Down: key down ; * @Key_Menu: key menu. * * Possible non ascii keys used in #ToolSimplifiedEvents. */ typedef enum { Key_None, Key_Page_Up, Key_Page_Down, Key_Arrow_Left, Key_Arrow_Right, Key_Arrow_Up, Key_Arrow_Down, Key_Menu } ToolSpecialKeyStroke; /** * ToolSimplifiedEvents: * @x: the position x (on parent) for the event ; * @y: the position y (on parent) for the event ; * @root_x: the position x (in root window) for the event ; * @root_y: the position y (in root window) for the event ; * @button: the number of the button, 0 if not a button event ; * @buttonType: #TOOL_BUTTON_TYPE_PRESS or #TOOL_BUTTON_TYPE_RELEASE ; * @shiftMod: TRUE if Shift key is pressed during the event ; * @controlMod: TRUE if Control key is pressed during the event ; * @motion: TRUE if the event is a motion ; * @letter: The value of the letter if the event is a key stroke '\0' if not ; * @specialKey: the value of a special key if the event is a key stroke * but not with an ascii letter. * * This structure is a common interface for events (inspired from X). We don't * use the one introduced by GDK because we don't want this dependency be a * limitation. */ typedef struct _ToolSimplifiedEvents ToolSimplifiedEvents; struct _ToolSimplifiedEvents { int x, y; int root_x, root_y; guint button; ToolButtonActionId buttonType; gboolean shiftMod, controlMod; gboolean motion; char letter; ToolSpecialKeyStroke specialKey; }; #ifdef V_SIM_GDK #include gboolean tool_simplified_events_new_fromGdk(ToolSimplifiedEvents *ev, const GdkEvent *event); #endif #endif v_sim-3.8.0/src/renderingBackend/visu_action_gdk.c000066400000000000000000000152261370110300500221630ustar00rootroot00000000000000/* EXTRAITS DE LA LICENCE Copyright CEA, contributeurs : Luc BILLARD et Damien CALISTE, laboratoire L_Sim, (2001-2005) Adresse mèl : BILLARD, non joignable par mèl ; CALISTE, damien P caliste AT cea P fr. Ce logiciel est un programme informatique servant à visualiser des structures atomiques dans un rendu pseudo-3D. Ce logiciel est régi par la licence CeCILL soumise au droit français et respectant les principes de diffusion des logiciels libres. Vous pouvez utiliser, modifier et/ou redistribuer ce programme sous les conditions de la licence CeCILL telle que diffusée par le CEA, le CNRS et l'INRIA sur le site "http://www.cecill.info". Le fait que vous puissiez accéder à cet en-tête signifie que vous avez pris connaissance de la licence CeCILL, et que vous en avez accepté les termes (cf. le fichier Documentation/licence.fr.txt fourni avec ce logiciel). */ /* LICENCE SUM UP Copyright CEA, contributors : Luc BILLARD et Damien CALISTE, laboratoire L_Sim, (2001-2005) E-mail address: BILLARD, not reachable any more ; CALISTE, damien P caliste AT cea P fr. This software is a computer program whose purpose is to visualize atomic configurations in 3D. This software is governed by the CeCILL license under French law and abiding by the rules of distribution of free software. You can use, modify and/ or redistribute the software under the terms of the CeCILL license as circulated by CEA, CNRS and INRIA at the following URL "http://www.cecill.info". The fact that you are presently reading this means that you have had knowledge of the CeCILL license and that you accept its terms. You can find a copy of this licence shipped with this software at Documentation/licence.en.txt. */ #define V_SIM_GDK #include "visu_actionInterface.h" #include #include #include /** * tool_simplified_events_new_fromGdk: * @ev: a #ToolSimplifiedEvents structure. * @event: an incoming #GdkEvent structure. * * Transfer the given @event into the internal @ev structure. * * Since: 3.7 * * Returns: if the event @ev is captured or not. **/ gboolean tool_simplified_events_new_fromGdk(ToolSimplifiedEvents *ev, const GdkEvent *event) { g_return_val_if_fail(ev && event, FALSE); ev->button = 0; ev->buttonType = TOOL_BUTTON_TYPE_NONE; ev->motion = FALSE; ev->letter = '\0'; ev->specialKey = Key_None; switch (event->type) { case (GDK_BUTTON_PRESS): case (GDK_BUTTON_RELEASE): /* case (GDK_DOUBLE_BUTTON_PRESS): */ /* case (GDK_TRIPLE_BUTTON_PRESS): */ ev->x = event->button.x; ev->y = event->button.y; ev->button = event->button.button; ev->shiftMod = event->button.state & GDK_SHIFT_MASK; ev->controlMod = event->button.state & GDK_CONTROL_MASK; if (event->type == GDK_BUTTON_PRESS) ev->buttonType = TOOL_BUTTON_TYPE_PRESS; else if (event->type == GDK_BUTTON_RELEASE) ev->buttonType = TOOL_BUTTON_TYPE_RELEASE; return TRUE; case (GDK_SCROLL): ev->x = event->scroll.x; ev->y = event->scroll.y; if (event->scroll.direction == GDK_SCROLL_UP) ev->button = 4; else if (event->scroll.direction == GDK_SCROLL_DOWN) ev->button = 5; ev->shiftMod = event->scroll.state & GDK_SHIFT_MASK; ev->controlMod = event->scroll.state & GDK_CONTROL_MASK; return TRUE; case (GDK_MOTION_NOTIFY): ev->motion = 1; ev->x = event->motion.x; ev->y = event->motion.y; gdk_window_get_root_coords(event->motion.window, ev->x, ev->y, &ev->root_x, &ev->root_y); if (event->motion.state & GDK_BUTTON1_MASK) ev->button = 1; else if (event->motion.state & GDK_BUTTON2_MASK) ev->button = 2; else if (event->motion.state & GDK_BUTTON3_MASK) ev->button = 3; ev->buttonType = 0; ev->shiftMod = event->motion.state & GDK_SHIFT_MASK; ev->controlMod = event->motion.state & GDK_CONTROL_MASK; if (event->motion.is_hint) { #if GDK_MAJOR_VERSION > 2 || GDK_MINOR_VERSION > 11 gdk_event_request_motions(&event->motion); #else gdk_window_get_pointer(event->motion.window, NULL, NULL, NULL); #endif } return TRUE; case(GDK_KEY_PRESS): if ((event->key.keyval == GDK_KEY_r || event->key.keyval == GDK_KEY_R) && !(event->key.state & GDK_CONTROL_MASK)) ev->letter = 'r'; else if ((event->key.keyval == GDK_KEY_s || event->key.keyval == GDK_KEY_S) && !(event->key.state & GDK_CONTROL_MASK)) ev->letter = 's'; else if ((event->key.keyval == GDK_KEY_x || event->key.keyval == GDK_KEY_X) && !(event->key.state & GDK_CONTROL_MASK)) ev->letter = 'x'; else if ((event->key.keyval == GDK_KEY_y || event->key.keyval == GDK_KEY_Y) && !(event->key.state & GDK_CONTROL_MASK)) ev->letter = 'y'; else if ((event->key.keyval == GDK_KEY_z || event->key.keyval == GDK_KEY_Z) && !(event->key.state & GDK_CONTROL_MASK)) ev->letter = 'z'; /* else if(event->key.keyval == GDK_KEY_space) */ /* ev->letter = ' '; */ else if(event->key.keyval == GDK_KEY_Page_Up) ev->specialKey = Key_Page_Up; else if(event->key.keyval == GDK_KEY_Page_Down) ev->specialKey = Key_Page_Down; else if(event->key.keyval == GDK_KEY_Down) ev->specialKey = Key_Arrow_Down; else if(event->key.keyval == GDK_KEY_Up) ev->specialKey = Key_Arrow_Up; else if(event->key.keyval == GDK_KEY_Left) ev->specialKey = Key_Arrow_Left; else if(event->key.keyval == GDK_KEY_Right) ev->specialKey = Key_Arrow_Right; #if GDK_MAJOR_VERSION > 2 else if(event->key.keyval == GDK_KEY_Menu) { gdk_window_get_device_position(event->key.window, #if GDK_MAJOR_VERSION < 3 || (GDK_MAJOR_VERSION == 3 && GDK_MINOR_VERSION < 20) gdk_device_manager_get_client_pointer (gdk_display_get_device_manager (gdk_window_get_display(event->key.window))), #else gdk_seat_get_pointer(gdk_event_get_seat(event)), #endif &ev->x, &ev->y, NULL); gdk_window_get_root_coords(event->key.window, ev->x, ev->y, &ev->root_x, &ev->root_y); ev->specialKey = Key_Menu; } #endif ev->shiftMod = event->key.state & GDK_SHIFT_MASK; ev->controlMod = event->key.state & GDK_CONTROL_MASK; return TRUE; case(GDK_KEY_RELEASE): return TRUE; default: return FALSE; } return TRUE; } v_sim-3.8.0/src/renderingBackend/visu_windowX11.c000066400000000000000000000274601370110300500216650ustar00rootroot00000000000000/* EXTRAITS DE LA LICENCE Copyright CEA, contributeurs : Luc BILLARD et Damien CALISTE, laboratoire L_Sim, (2001-2005) Adresse mèl : BILLARD, non joignable par mèl ; CALISTE, damien P caliste AT cea P fr. Ce logiciel est un programme informatique servant à visualiser des structures atomiques dans un rendu pseudo-3D. Ce logiciel est régi par la licence CeCILL soumise au droit français et respectant les principes de diffusion des logiciels libres. Vous pouvez utiliser, modifier et/ou redistribuer ce programme sous les conditions de la licence CeCILL telle que diffusée par le CEA, le CNRS et l'INRIA sur le site "http://www.cecill.info". Le fait que vous puissiez accéder à cet en-tête signifie que vous avez pris connaissance de la licence CeCILL, et que vous en avez accepté les termes (cf. le fichier Documentation/licence.fr.txt fourni avec ce logiciel). */ /* LICENCE SUM UP Copyright CEA, contributors : Luc BILLARD et Damien CALISTE, laboratoire L_Sim, (2001-2005) E-mail address: BILLARD, not reachable any more ; CALISTE, damien P caliste AT cea P fr. This software is a computer program whose purpose is to visualize atomic configurations in 3D. This software is governed by the CeCILL license under French law and abiding by the rules of distribution of free software. You can use, modify and/ or redistribute the software under the terms of the CeCILL license as circulated by CEA, CNRS and INRIA at the following URL "http://www.cecill.info". The fact that you are presently reading this means that you have had knowledge of the CeCILL license and that you accept its terms. You can find a copy of this licence shipped with this software at Documentation/licence.en.txt. */ #include "visu_windowInterface.h" #define __USE_BSD #include #include #include #include #include #include #include #include #include "visu_tools.h" #include #include Cursor cursorRotate; Cursor cursorWatch; Cursor cursorPointer; Cursor cursorPirate; Cursor *currentCursor; static long currentWindowEventMask; static guint XeventCallbackFunc; CallbackFunctions standardCallback; gboolean XTestEvent(gpointer data) { CallbackFunctions *callbacks; ToolSimplifiedEvents ev; XEvent report; int action; Window root, child; int root_x, root_y, pos_x, pos_y; guint keys_buttons; KeySym keysym; callbacks = (CallbackFunctions*)data; if (!callbacks) { fprintf(stderr, "INTERNAL ERROR! 'XTestEvent' has been called" " with a null data parameter.\n"); return FALSE; } if (!XPending(dpy)) { usleep(10000); return TRUE; } (void)XDefineCursor(dpy, *window, cursorWatch); (void)XFlush(dpy); (void)XNextEvent(dpy, &report); action = 0; ev.button = 0; ev.motion = 0; ev.letter = '\0'; switch(report.type) { case ButtonPress: ev.x = report.xbutton.x; ev.y = report.xbutton.y; ev.button = report.xbutton.button; ev.shiftMod = report.xbutton.state & ShiftMask; ev.controlMod = report.xbutton.state & ControlMask; action = 1; break; case MotionNotify: if(!XQueryPointer(dpy, report.xmotion.window, &root, &child, &root_x, &root_y, &pos_x, &pos_y, &keys_buttons)) break; ev.x = report.xmotion.x; ev.y = report.xmotion.y; if (report.xmotion.state & Button1Mask) ev.button = 1; else if (report.xmotion.state & Button2Mask) ev.button = 2; else if (report.xmotion.state & Button3Mask) ev.button = 3; ev.shiftMod = report.xmotion.state & ShiftMask; ev.controlMod = report.xmotion.state & ControlMask; ev.motion = 1; action = 1; break; case KeyRelease: keysym = XKeycodeToKeysym(dpy, report.xkey.keycode, 0); if(keysym == XK_r || keysym == XK_R) ev.letter = 'r'; action = 1; break; default: action = 0; } if (action) { if (callbacks->action(&ev) && callbacks->stop) callbacks->stop((gpointer)0); } (void)XDefineCursor(dpy, *window, *currentCursor); (void)XFlush(dpy); return TRUE; } gboolean checkForXEvent(gpointer data) { XEvent report; if (!XPending(dpy)) return TRUE; /* Bouffe la pile pour éviter de faire 15 000 reDraw inutiles. */ while (XPending(dpy)) (void)XNextEvent(dpy, &report); switch(report.type) { case Expose: if (report.xexpose.count == 0 && standardCallback.action) standardCallback.action((ToolSimplifiedEvents*)0); break; /* case ResizeRequest: */ /* if (setNewWindowSize(report.xresizerequest.width, */ /* report.xresizerequest.height)) */ /* reDraw((GObject*)0, (gpointer)1); */ /* break; */ } return TRUE; } GList* setObserveEventListener(CallbackFunctions *userCallbacks) { GList *listId; guint *idEve; (void)XDefineCursor(dpy, *window, cursorRotate); (void)XSelectInput(dpy, *window, KeyReleaseMask| ButtonPressMask|ButtonReleaseMask| ButtonMotionMask|PointerMotionHintMask); (void)XFlush(dpy); currentCursor = &cursorRotate; listId = (GList*)0; idEve = malloc(sizeof(guint)); if (!idEve) { allocationProblems(); exit(1); } *idEve = g_idle_add_full(G_PRIORITY_HIGH_IDLE + 20, XTestEvent, (gpointer)userCallbacks, userCallbacks->stop); listId = g_list_append(listId, (gpointer)idEve); return listId; } GList* setPickEventListener(CallbackFunctions *userCallbacks) { GList *listId; guint *idEve; (void)XDefineCursor(dpy, *window, cursorPointer); (void)XSelectInput(dpy, *window, ButtonPressMask); (void)XFlush(dpy); currentCursor = &cursorPointer; listId = (GList*)0; idEve = malloc(sizeof(guint)); if (!idEve) { allocationProblems(); exit(1); } *idEve = g_idle_add_full(G_PRIORITY_HIGH_IDLE + 20, XTestEvent, (gpointer)userCallbacks, userCallbacks->stop); listId = g_list_append(listId, (gpointer)idEve); return listId; } void removeEventListener(GList *listId) { GList* ptList; ptList = listId; while (ptList) { if (*(guint*)ptList->data) g_source_remove(*(guint*)ptList->data); free(ptList->data); ptList = g_list_next(ptList); } if (listId) g_list_free(listId); listId = (GList*)0; } void restoreStandardEventListener() { (void)XSelectInput(dpy, *window, currentWindowEventMask); (void)XDefineCursor(dpy, *window, cursorPirate); (void)XFlush(dpy); if (currentWindowEventMask) { DBG_fprintf(stderr, "Visu OpenGl : adding timer.\n"); XeventCallbackFunc = g_timeout_add(50, checkForXEvent, (gpointer)0); } } void stopStandardEventListener() { if (XeventCallbackFunc) g_source_remove(XeventCallbackFunc); XeventCallbackFunc = 0; } void addExposureEvent(ActionFunc action) { currentWindowEventMask = currentWindowEventMask | ExposureMask; (void)XSelectInput(dpy, *window, currentWindowEventMask); XFlush(dpy); standardCallback.action = action; if (!XeventCallbackFunc) XeventCallbackFunc = g_timeout_add(50, checkForXEvent, (gpointer)0); } void removeExposureEvent() { currentWindowEventMask = currentWindowEventMask ^ ExposureMask; (void)XSelectInput(dpy, *window, currentWindowEventMask); XFlush(dpy); standardCallback.action = (ActionFunc)0; if (!currentWindowEventMask) g_source_remove(XeventCallbackFunc); XeventCallbackFunc = 0; } int initVisuUiRenderingWindow(char* windowRef, char* iconRef, char* window_name, char* class_name, int width, int height) { int d_depth; ToolColormap cmap; XSetWindowAttributes wattrs; /* window manager : WMProperties */ XTextProperty window_name_txt, icon_name_txt; XSizeHints shints; XWMHints whints; XClassHint chints; XEvent event; Atom wm_delete_window; XpmAttributes attributes; int res; res = initDisplay(); res = initOpenGLContext() || res; if (!res) return 0; cmap = XCreateColormap(dpy, RootWindow(dpy, vinfo->screen), vinfo->visual, AllocNone); wattrs.backing_store = 0; wattrs.background_pixel = wattrs.border_pixel = BlackPixel(dpy, DefaultScreen(dpy)); wattrs.event_mask = ExposureMask ; wattrs.colormap = cmap; window = malloc(sizeof(Window)); if (!window) { allocationProblems(); exit(1); } *window = XCreateWindow(dpy, RootWindow(dpy, vinfo->screen), 0, 0, width, height, 0, vinfo->depth, InputOutput, vinfo->visual, CWBackingStore|CWBackPixel|CWBorderPixel|CWEventMask|CWToolColormap, &wattrs); (void)XStringListToTextProperty(&windowRef, 1, &window_name_txt); (void)XStringListToTextProperty(&iconRef, 1, &icon_name_txt); shints.x = 0; shints.y = 0; shints.width = shints.min_aspect.x = shints.max_aspect.x = width; shints.height = shints.min_aspect.y = shints.max_aspect.y = height; shints.flags = PSize | PAspect; d_depth = DefaultDepth(dpy,DefaultScreen(dpy) ); whints.initial_state = NormalState; /* whints.icon_pixmap = XCreateBitmapFromData(dpy, *window, (char *)visu_btmp_bits, */ /* visu_btmp_width, visu_btmp_height); */ whints.icon_pixmap = XCreatePixmap(dpy, *window, 16, 16, d_depth); attributes.valuemask = (XpmReturnPixels | XpmReturnExtensions); XpmCreatePixmapFromData(dpy, *window, icone_observe_xpm, &whints.icon_pixmap, NULL, &attributes); XCreatePixmapFromBitmapData(dpy, *window, (char *)icone_observe_xpm, 16, 16, 0, 128, d_depth); whints.flags = StateHint | IconPixmapHint; chints.res_name = window_name; chints.res_class = class_name; (void)XSetWMProperties (dpy, *window, &window_name_txt, &icon_name_txt, NULL, 0, &shints, &whints, &chints); wm_delete_window = XInternAtom(dpy, "WM_DELETE_WINDOW", False); (void)XSetWMProtocols(dpy, *window, &wm_delete_window, 1); (void)XMapWindow(dpy, *window); event.type = 0; while (event.type != Expose) (void)XNextEvent(dpy, &event); currentWindowEventMask = 0; cursorPirate = XCreateFontCursor(dpy, XC_pirate); cursorRotate = XCreateFontCursor(dpy, XC_box_spiral); cursorWatch = XCreateFontCursor(dpy, XC_watch); cursorPointer = XCreateFontCursor(dpy, XC_dotbox); (void)XDefineCursor(dpy, *window, cursorPirate); (void)XSelectInput(dpy, *window, currentWindowEventMask); (void)XFlush(dpy); res = setWindowHandler(window); /* attachOpenGlContext((gpointer)window, TRUE, FALSE); */ /* Now that the glx tunnel has been added, we need to specify again that we want a backing store because until now the backing store is only for the X window (and thus is black) but not for the glx screen. */ startBackingStore(); /* The automatic resize is not working... */ /* XeventCallbackFunc = g_timeout_add(50, checkForXEvent, (gpointer)0); */ XeventCallbackFunc = 0; return 1; } void checkWindowSize(guint *width, guint *height) { Window root; int xu, yu; guint bdr, dpth; /* not used */ if(!XGetGeometry(dpy, *window, &root, &xu, &yu, width, height, &bdr, &dpth)) { DBG_fprintf(stderr, "INTERNAL ERROR! XGetGeometry failed!\n"); exit(1); } } gpointer getWindowHandler() { return (gpointer)window; } void raiseRenderWindow() { XRaiseWindow(dpy, *window); XFlush(dpy); } void rename_window(char *nom) { char *window_name_L[1]; XTextProperty window_name_txt; window_name_L[0] = nom; (void)XStringListToTextProperty(window_name_L, 1, &window_name_txt); (void)XSetWMName (dpy, *window, &window_name_txt); (void)XFlush(dpy); } void visuRenderigWindowGet_backgroundColor(float rgb[3]) { rgb[0] = 0.5; rgb[1] = 0.5; rgb[2] = 0.5; } gpointer visuRenderigWindowGet_backgroundImage(guchar **rowData, gboolean *hasAlphaChannel, int *width, int *height) { return (gpointer)0; } void visuRenderigWindowFree_backgroundImage(gpointer image) { } v_sim-3.8.0/src/renderingMethods/000077500000000000000000000000001370110300500167155ustar00rootroot00000000000000v_sim-3.8.0/src/renderingMethods/elementAtomic.c000066400000000000000000001053271370110300500216570ustar00rootroot00000000000000/* EXTRAITS DE LA LICENCE Copyright CEA, contributeurs : Damien CALISTE, laboratoire L_Sim, (2016) Adresse mèl : CALISTE, damien P caliste AT cea P fr. Ce logiciel est un programme informatique servant à visualiser des structures atomiques dans un rendu pseudo-3D. Ce logiciel est régi par la licence CeCILL soumise au droit français et respectant les principes de diffusion des logiciels libres. Vous pouvez utiliser, modifier et/ou redistribuer ce programme sous les conditions de la licence CeCILL telle que diffusée par le CEA, le CNRS et l'INRIA sur le site "http://www.cecill.info". Le fait que vous puissiez accéder à cet en-tête signifie que vous avez pris connaissance de la licence CeCILL, et que vous en avez accepté les termes (cf. le fichier Documentation/licence.fr.txt fourni avec ce logiciel). */ /* LICENCE SUM UP Copyright CEA, contributors : Damien CALISTE, laboratoire L_Sim, (2016) E-mail address: CALISTE, damien P caliste AT cea P fr. This software is a computer program whose purpose is to visualize atomic configurations in 3D. This software is governed by the CeCILL license under French law and abiding by the rules of distribution of free software. You can use, modify and/ or redistribute the software under the terms of the CeCILL license as circulated by CEA, CNRS and INRIA at the following URL "http://www.cecill.info". The fact that you are presently reading this means that you have had knowledge of the CeCILL license and that you accept its terms. You can find a copy of this licence shipped with this software at Documentation/licence.en.txt. */ #include "elementAtomic.h" #include #include #include #include #include #include #include /** * SECTION:elementAtomic * @short_description: a class implementing rendering for * #VisuDataAtomic objects. * * This class implements the virtual method of * #VisuElementRenderer class to display nodes as 0D objects at a * given point. The specific shape is defined by * #VisuElementAtomicShapeId enumeration. The size of the 0D object is * given by the "radius" property which is a length with a given * "units" property. * visu_element_atomic_getFromPool() is a specific function to * associate a unique #VisuElementAtomic to a given #VisuElement. */ /** * VisuElementAtomicClass: * @parent: its parent. * * Interface for class that can represent #VisuElement of the same * kind in the same way (usually spheres). * * Since: 3.8 */ #define _DEFAULT_RADIUS 1.f #define FLAG_RESOURCE_RADIUS_SHAPE "atomic_radius_shape" #define DESC_RESOURCE_RADIUS_SHAPE "The radius of the element and its shape, a real > 0. & [Sphere Cube Elipsoid Point]" /* These functions write all the element list to export there associated resources. */ static void exportAtomic(GString *data, VisuData* dataObj); #define FLAG_PARAMETER_SHAPE "atomic_sphere_method" #define DESC_PARAMETER_SHAPE "The sphere drawing method, [GluSphere Icosahedron]" static void exportAtomicShape(GString *data, VisuData* dataObj); /* Read routines for the config file. */ static void onEntryRadiusShape(VisuConfigFile *object, VisuConfigFileEntry *entry, gpointer data); static void onEntryUnit(VisuElementAtomic *ele, VisuConfigFileEntry *entry, VisuConfigFile *obj); enum { sphere_glu, sphere_icosahedron, sphere_nb }; static guint _sphereMethod = sphere_glu; static const char* _sphereName[sphere_nb + 1] = {"GluSphere", "Icosahedron", (const char*)0}; static const char* _shapeName[VISU_ELEMENT_ATOMIC_N_SHAPES + 1] = {"Sphere", "Cube", "Elipsoid", "Point", "Torus", (const char*)0}; static const char* _shapeNameI18n[VISU_ELEMENT_ATOMIC_N_SHAPES + 1]; /** * VisuElementAtomic: * * Structure used to define #VisuElementAtomic objects. * * Since: 3.8 */ struct _VisuElementAtomicPrivate { gfloat radius; ToolUnits units; VisuElementAtomicShapeId shape; gfloat ratio, phi, theta; GLuint glElement; }; enum { PROP_0, PROP_RADIUS, PROP_UNITS, PROP_SHAPE, PROP_RATIO, PROP_PHI, PROP_THETA, N_PROPS }; static GParamSpec *_properties[N_PROPS]; static GList *_pool; static gboolean _sphereFromName(const gchar *name, guint *value); static gboolean _shapeFromName(const gchar *name, VisuElementAtomicShapeId *shape); static void visu_element_atomic_get_property(GObject* obj, guint property_id, GValue *value, GParamSpec *pspec); static void visu_element_atomic_set_property(GObject* obj, guint property_id, const GValue *value, GParamSpec *pspec); static void _compile (VisuElementRenderer *element, const VisuGlView *view); static void _call (const VisuElementRenderer *element); static void _callAt (const VisuElementRenderer *element, const VisuDataColorizer *colorizer, const VisuData *data, const VisuNode *node); static gfloat _getExtent (const VisuElementRenderer *self); G_DEFINE_TYPE_WITH_CODE(VisuElementAtomic, visu_element_atomic, VISU_TYPE_ELEMENT_RENDERER, G_ADD_PRIVATE(VisuElementAtomic)) static void visu_element_atomic_class_init(VisuElementAtomicClass *klass) { VisuConfigFileEntry *resourceEntry; /* Connect the overloading methods. */ G_OBJECT_CLASS(klass)->set_property = visu_element_atomic_set_property; G_OBJECT_CLASS(klass)->get_property = visu_element_atomic_get_property; VISU_ELEMENT_RENDERER_CLASS(klass)->compile = _compile; VISU_ELEMENT_RENDERER_CLASS(klass)->call = _call; VISU_ELEMENT_RENDERER_CLASS(klass)->callAt = _callAt; VISU_ELEMENT_RENDERER_CLASS(klass)->getExtent = _getExtent; /** * VisuElementAtomic::radius: * * The atomic radius. * * Since: 3.8 */ _properties[PROP_RADIUS] = g_param_spec_float("radius", "Radius", "atomic radius", 0.001f, G_MAXFLOAT, _DEFAULT_RADIUS, G_PARAM_READWRITE); g_object_class_install_property(G_OBJECT_CLASS(klass), PROP_RADIUS, _properties[PROP_RADIUS]); /** * VisuElementAtomic::units: * * The unit in which the radius is defined. * * Since: 3.8 */ _properties[PROP_UNITS] = g_param_spec_uint("units", "Units", "radius units", 0, TOOL_UNITS_N_VALUES - 1, TOOL_UNITS_UNDEFINED, G_PARAM_READWRITE); g_object_class_install_property(G_OBJECT_CLASS(klass), PROP_UNITS, _properties[PROP_UNITS]); /** * VisuElementAtomic::shape: * * The shape used to represent a given element. * * Since: 3.8 */ _properties[PROP_SHAPE] = g_param_spec_uint("shape", "Shape", "atomic shape", 0, VISU_ELEMENT_ATOMIC_N_SHAPES - 1, VISU_ELEMENT_ATOMIC_SPHERE, G_PARAM_READWRITE); g_object_class_install_property(G_OBJECT_CLASS(klass), PROP_SHAPE, _properties[PROP_SHAPE]); /** * VisuElementAtomic::elipsoid-ratio: * * The ratio used to represent an elongated shape like an elipsoid. * * Since: 3.8 */ _properties[PROP_RATIO] = g_param_spec_float("elipsoid-ratio", "Elipsoid ratio", "Elipsoid ratio", 0.f, G_MAXFLOAT, 1.f, G_PARAM_READWRITE); g_object_class_install_property(G_OBJECT_CLASS(klass), PROP_RATIO, _properties[PROP_RATIO]); /** * VisuElementAtomic::elipsoid-angle-phi: * * The angle phi used to aligned an elongated shape like an elipsoid. * * Since: 3.8 */ _properties[PROP_PHI] = g_param_spec_float("elipsoid-angle-phi", "Elipsoid angle phi", "Elipsoid angle phi", 0.f, 360.f, 0.f, G_PARAM_READWRITE); g_object_class_install_property(G_OBJECT_CLASS(klass), PROP_PHI, _properties[PROP_PHI]); /** * VisuElementAtomic::elipsoid-angle-theta: * * The angle tetha used to aligned an elongated shape like an elipsoid. * * Since: 3.8 */ _properties[PROP_THETA] = g_param_spec_float("elipsoid-angle-theta", "Elipsoid angle theta", "Elipsoid angle theta", 0.f, 180.f, 90.f, G_PARAM_READWRITE); g_object_class_install_property(G_OBJECT_CLASS(klass), PROP_THETA, _properties[PROP_THETA]); resourceEntry = visu_config_file_addTokenizedEntry(VISU_CONFIG_FILE_RESOURCE, FLAG_RESOURCE_RADIUS_SHAPE, DESC_RESOURCE_RADIUS_SHAPE, TRUE); g_signal_connect(VISU_CONFIG_FILE_RESOURCE, "parsed::" FLAG_RESOURCE_RADIUS_SHAPE, G_CALLBACK(onEntryRadiusShape), (gpointer)0); visu_config_file_addExportFunction(VISU_CONFIG_FILE_RESOURCE, exportAtomic); resourceEntry = visu_config_file_addEnumEntry(VISU_CONFIG_FILE_PARAMETER, FLAG_PARAMETER_SHAPE, DESC_PARAMETER_SHAPE, &_sphereMethod, _sphereFromName, FALSE); visu_config_file_entry_setVersion(resourceEntry, 3.4f); visu_config_file_addExportFunction(VISU_CONFIG_FILE_PARAMETER, exportAtomicShape); _pool = (GList*)0; _shapeNameI18n[0] = _("Sphere"); _shapeNameI18n[1] = _("Cube"); _shapeNameI18n[2] = _("Elipsoid"); _shapeNameI18n[3] = _("Point"); _shapeNameI18n[4] = _("Torus"); _shapeNameI18n[5] = (const char*)0; } static void visu_element_atomic_init(VisuElementAtomic *obj) { DBG_fprintf(stderr, "Visu Pair Atomic: initializing a new object (%p).\n", (gpointer)obj); obj->priv = visu_element_atomic_get_instance_private(obj); /* Private data. */ obj->priv->radius = _DEFAULT_RADIUS; obj->priv->units = visu_basic_getPreferedUnit(); obj->priv->shape = VISU_ELEMENT_ATOMIC_SPHERE; obj->priv->ratio = 1.f; obj->priv->phi = 0.f; obj->priv->theta = 90.f; obj->priv->glElement = 0; g_signal_connect_object(VISU_CONFIG_FILE_PARAMETER, "parsed::main_unit", G_CALLBACK(onEntryUnit), (gpointer)obj, G_CONNECT_SWAPPED); } static void visu_element_atomic_get_property(GObject* obj, guint property_id, GValue *value, GParamSpec *pspec) { VisuElementAtomic *self = VISU_ELEMENT_ATOMIC(obj); DBG_fprintf(stderr, "Visu Element Atomic: get property '%s' -> ", g_param_spec_get_name(pspec)); switch (property_id) { case PROP_RADIUS: g_value_set_float(value, self->priv->radius); DBG_fprintf(stderr, "%g.\n", self->priv->radius); break; case PROP_UNITS: g_value_set_uint(value, self->priv->units); DBG_fprintf(stderr, "%d.\n", self->priv->units); break; case PROP_SHAPE: g_value_set_uint(value, self->priv->shape); DBG_fprintf(stderr, "%d.\n", self->priv->shape); break; case PROP_RATIO: g_value_set_float(value, self->priv->ratio); DBG_fprintf(stderr, "%g.\n", self->priv->ratio); break; case PROP_PHI: g_value_set_float(value, self->priv->phi); DBG_fprintf(stderr, "%g.\n", self->priv->phi); break; case PROP_THETA: g_value_set_float(value, self->priv->theta); DBG_fprintf(stderr, "%g.\n", self->priv->theta); break; default: /* We don't have any other property... */ G_OBJECT_WARN_INVALID_PROPERTY_ID(obj, property_id, pspec); break; } } static void visu_element_atomic_set_property(GObject* obj, guint property_id, const GValue *value, GParamSpec *pspec) { VisuElementAtomic *self = VISU_ELEMENT_ATOMIC(obj); DBG_fprintf(stderr, "Visu Element Atomic: set property '%s' -> ", g_param_spec_get_name(pspec)); switch (property_id) { case PROP_RADIUS: DBG_fprintf(stderr, "%g.\n", self->priv->radius); visu_element_atomic_setRadius(self, g_value_get_float(value)); break; case PROP_UNITS: DBG_fprintf(stderr, "%d.\n", g_value_get_uint(value)); visu_element_atomic_setUnits(self, g_value_get_uint(value)); break; case PROP_SHAPE: visu_element_atomic_setShape(self, g_value_get_uint(value)); DBG_fprintf(stderr, "%d.\n", self->priv->shape); break; case PROP_RATIO: visu_element_atomic_setElipsoidRatio(self, g_value_get_float(value)); DBG_fprintf(stderr, "%g.\n", self->priv->ratio); break; case PROP_PHI: visu_element_atomic_setElipsoidPhi(self, g_value_get_float(value)); DBG_fprintf(stderr, "%g.\n", self->priv->phi); break; case PROP_THETA: visu_element_atomic_setElipsoidTheta(self, g_value_get_float(value)); DBG_fprintf(stderr, "%g.\n", self->priv->theta); break; default: /* We don't have any other property... */ G_OBJECT_WARN_INVALID_PROPERTY_ID(obj, property_id, pspec); break; } } /** * visu_element_atomic_new: * @element: a #VisuElement object. * * Creates a new #VisuElementAtomic object used to render @element. * * Since: 3.8 * * Returns: (transfer full): a newly created #VisuElementAtomic object. **/ VisuElementAtomic* visu_element_atomic_new(VisuElement *element) { return VISU_ELEMENT_ATOMIC(g_object_new(VISU_TYPE_ELEMENT_ATOMIC, "element", element, NULL)); } /** * visu_element_atomic_getFromPool: * @element: a #VisuElement object. * * Retrieve a #VisuElementAtomic representing @element. This * #VisuElementAtomic is unique and its parent properties are bound to * the unique #VisuElementRenderer for @element. * * Since: 3.8 * * Returns: (transfer none): a #VisuElementAtomic for @element. **/ VisuElementAtomic* visu_element_atomic_getFromPool(VisuElement *element) { GList *lst; VisuElementAtomic *atomic; for (lst = _pool; lst; lst = g_list_next(lst)) if (visu_element_renderer_getElement(VISU_ELEMENT_RENDERER(lst->data)) == element) return VISU_ELEMENT_ATOMIC(lst->data); atomic = visu_element_atomic_new(element); visu_element_renderer_bindToPool(VISU_ELEMENT_RENDERER(atomic)); _pool = g_list_prepend(_pool, atomic); return atomic; } /** * visu_element_atomic_bindToPool: * @atomic: a #VisuElementAtomic object. * * Bind all properties of @atomic to the #VisuElementAtomic object * corresponding to the same #VisuElement from the pool. The binding * is bidirectional. This method is usefull to create a pool of * objects inheriting from #VisuElementAtomic. * * Since: 3.8 **/ void visu_element_atomic_bindToPool(VisuElementAtomic *atomic) { VisuElementAtomic *pool; visu_element_renderer_bindToPool(VISU_ELEMENT_RENDERER(atomic)); pool = visu_element_atomic_getFromPool(visu_element_renderer_getElement(VISU_ELEMENT_RENDERER(atomic))); g_object_bind_property(pool, "radius", atomic, "radius", G_BINDING_SYNC_CREATE | G_BINDING_BIDIRECTIONAL); g_object_bind_property(pool, "units", atomic, "units", G_BINDING_SYNC_CREATE | G_BINDING_BIDIRECTIONAL); g_object_bind_property(pool, "shape", atomic, "shape", G_BINDING_SYNC_CREATE | G_BINDING_BIDIRECTIONAL); g_object_bind_property(pool, "elipsoid-ratio", atomic, "elipsoid-ratio", G_BINDING_SYNC_CREATE | G_BINDING_BIDIRECTIONAL); g_object_bind_property(pool, "elipsoid-angle-phi", atomic, "elipsoid-angle-phi", G_BINDING_SYNC_CREATE | G_BINDING_BIDIRECTIONAL); g_object_bind_property(pool, "elipsoid-angle-theta", atomic, "elipsoid-angle-theta", G_BINDING_SYNC_CREATE | G_BINDING_BIDIRECTIONAL); } /** * visu_element_atomic_pool_finalize: (skip) * * Destroy the internal list of known #VisuElementAtomic objects, see * visu_element_atomic_getFromPool(). * * Since: 3.8 **/ void visu_element_atomic_pool_finalize(void) { g_list_free_full(_pool, (GDestroyNotify)g_object_unref); _pool = (GList*)0; } static gfloat _getExtent(const VisuElementRenderer *self) { g_return_val_if_fail(VISU_IS_ELEMENT_ATOMIC(self), 0.f); return VISU_ELEMENT_ATOMIC(self)->priv->radius; } /** * visu_element_atomic_getRadius: * @self: a #VisuElementAtomic object. * * Retrieve the radius used to draw @self. The unit of the value is * given by visu_element_atomic_getUnits(). * * Since: 3.8 * * Returns: a radius value. **/ gfloat visu_element_atomic_getRadius(const VisuElementAtomic *self) { g_return_val_if_fail(VISU_IS_ELEMENT_ATOMIC(self), 0.f); return self->priv->radius; } /** * visu_element_atomic_setRadius: * @self: a #VisuElementAtomic object. * @val: a positive float value. * * Change the radius (or long axe) of the representation of @self. * * Since: 3.8 * * Returns: TRUE if value is actually changed. **/ gboolean visu_element_atomic_setRadius(VisuElementAtomic *self, gfloat val) { g_return_val_if_fail(VISU_IS_ELEMENT_ATOMIC(self), FALSE); if (self->priv->radius == val) return FALSE; DBG_fprintf(stderr, "Element Atomic: changing radius from %g to %g.\n", self->priv->radius, val); self->priv->radius = val; g_object_notify_by_pspec(G_OBJECT(self), _properties[PROP_RADIUS]); g_signal_emit_by_name(self, "size-changed", _getExtent(VISU_ELEMENT_RENDERER(self))); _compile(VISU_ELEMENT_RENDERER(self), visu_element_renderer_getConstGlView(VISU_ELEMENT_RENDERER(self))); return TRUE; } /** * visu_element_atomic_getUnits: * @self: a #VisuElementAtomic object. * * The units in which the radius value is given. * * Since: 3.8 * * Returns: a unit. **/ ToolUnits visu_element_atomic_getUnits(const VisuElementAtomic *self) { g_return_val_if_fail(VISU_IS_ELEMENT_ATOMIC(self), TOOL_UNITS_UNDEFINED); return self->priv->units; } /** * visu_element_atomic_setUnits: * @self: a #VisuElementAtomic object. * @val: a #ToolUnits value. * * Change the unit in wich the radius is given, see * visu_element_atomic_setRadius(). * * Since: 3.8 * * Returns: TRUE if value is actually changed. **/ gboolean visu_element_atomic_setUnits(VisuElementAtomic *self, ToolUnits val) { ToolUnits unit_; double fact; g_return_val_if_fail(VISU_IS_ELEMENT_ATOMIC(self), FALSE); if (self->priv->units == val) return FALSE; unit_ = self->priv->units; self->priv->units = val; g_object_notify_by_pspec(G_OBJECT(self), _properties[PROP_UNITS]); if (unit_ == TOOL_UNITS_UNDEFINED || val == TOOL_UNITS_UNDEFINED) return TRUE; fact = (double)tool_physic_getUnitValueInMeter(unit_) / tool_physic_getUnitValueInMeter(val); self->priv->radius *= fact; g_object_notify_by_pspec(G_OBJECT(self), _properties[PROP_RADIUS]); _compile(VISU_ELEMENT_RENDERER(self), visu_element_renderer_getConstGlView(VISU_ELEMENT_RENDERER(self))); return TRUE; } /** * visu_element_atomic_getShape: * @self: a #VisuElementAtomic object. * * Retrieve the #VisuElementAtomicShapeId that @self is using for representation. * * Since: 3.8 * * Returns: the shape used by @self. **/ VisuElementAtomicShapeId visu_element_atomic_getShape(const VisuElementAtomic *self) { g_return_val_if_fail(VISU_IS_ELEMENT_ATOMIC(self), VISU_ELEMENT_ATOMIC_SPHERE); return self->priv->shape; } /** * visu_element_atomic_setShape: * @self: a #VisuElementAtomic object. * @val: a #VisuElementAtomicShapeId value. * * Change the representation shape of @self. * * Since: 3.8 * * Returns: TRUE if value is actually changed. **/ gboolean visu_element_atomic_setShape(VisuElementAtomic *self, VisuElementAtomicShapeId val) { g_return_val_if_fail(VISU_IS_ELEMENT_ATOMIC(self), FALSE); if (self->priv->shape == val) return FALSE; self->priv->shape = val; g_object_notify_by_pspec(G_OBJECT(self), _properties[PROP_SHAPE]); _compile(VISU_ELEMENT_RENDERER(self), visu_element_renderer_getConstGlView(VISU_ELEMENT_RENDERER(self))); return TRUE; } /** * visu_element_atomic_getElipsoidRatio: * @self: a #VisuElementAtomic object. * * When @self is used to draw constant elipsoid or torus, this value * is used to adjust the ratio between the two angles. * * Since: 3.8 * * Returns: a ratio value. **/ gfloat visu_element_atomic_getElipsoidRatio(const VisuElementAtomic *self) { g_return_val_if_fail(VISU_IS_ELEMENT_ATOMIC(self), 1.f); return self->priv->ratio; } /** * visu_element_atomic_setElipsoidRatio: * @self: a #VisuElementAtomic object. * @val: a positive float value. * * Change the ratio between the long axe and the short axe of the * representation for shapes that are not isotropic. * * Since: 3.8 * * Returns: TRUE if value is actually changed. **/ gboolean visu_element_atomic_setElipsoidRatio(VisuElementAtomic *self, gfloat val) { g_return_val_if_fail(VISU_IS_ELEMENT_ATOMIC(self), FALSE); if (self->priv->ratio == val) return FALSE; self->priv->ratio = val; g_object_notify_by_pspec(G_OBJECT(self), _properties[PROP_RATIO]); if (self->priv->shape == VISU_ELEMENT_ATOMIC_ELLIPSOID || self->priv->shape == VISU_ELEMENT_ATOMIC_TORUS) _compile(VISU_ELEMENT_RENDERER(self), visu_element_renderer_getConstGlView(VISU_ELEMENT_RENDERER(self))); return TRUE; } /** * visu_element_atomic_getElipsoidPhi: * @self: a #VisuElementAtomic object. * * Retrieve the phi angle used to draw elipsoid shape with this renderer. * * Since: 3.8 * * Returns: the phi angle. **/ gfloat visu_element_atomic_getElipsoidPhi(const VisuElementAtomic *self) { g_return_val_if_fail(VISU_IS_ELEMENT_ATOMIC(self), 0.f); return self->priv->phi; } /** * visu_element_atomic_setElipsoidPhi: * @self: a #VisuElementAtomic object. * @val: a float value. * * Change the phi angle of the representation for shapes that are not isotropic. * * Since: 3.8 * * Returns: TRUE if value is actually changed. **/ gboolean visu_element_atomic_setElipsoidPhi(VisuElementAtomic *self, gfloat val) { g_return_val_if_fail(VISU_IS_ELEMENT_ATOMIC(self), FALSE); if (self->priv->phi == val) return FALSE; self->priv->phi = val; g_object_notify_by_pspec(G_OBJECT(self), _properties[PROP_PHI]); if (self->priv->shape == VISU_ELEMENT_ATOMIC_ELLIPSOID || self->priv->shape == VISU_ELEMENT_ATOMIC_TORUS) _compile(VISU_ELEMENT_RENDERER(self), visu_element_renderer_getConstGlView(VISU_ELEMENT_RENDERER(self))); return TRUE; } /** * visu_element_atomic_getElipsoidTheta: * @self: a #VisuElementAtomic object. * * Retrieve the theta angle used to draw elipsoid shape with this renderer. * * Since: 3.8 * * Returns: a theta value. **/ gfloat visu_element_atomic_getElipsoidTheta(const VisuElementAtomic *self) { g_return_val_if_fail(VISU_IS_ELEMENT_ATOMIC(self), 90.f); return self->priv->theta; } /** * visu_element_atomic_setElipsoidTheta: * @self: a #VisuElementAtomic object. * @val: a float value. * * Change the theta angle of the representation for shapes that are not isotropic. * * Since: 3.8 * * Returns: TRUE if value is actually changed. **/ gboolean visu_element_atomic_setElipsoidTheta(VisuElementAtomic *self, gfloat val) { g_return_val_if_fail(VISU_IS_ELEMENT_ATOMIC(self), FALSE); if (self->priv->theta == val) return FALSE; self->priv->theta = val; g_object_notify_by_pspec(G_OBJECT(self), _properties[PROP_THETA]); if (self->priv->shape == VISU_ELEMENT_ATOMIC_ELLIPSOID || self->priv->shape == VISU_ELEMENT_ATOMIC_TORUS) _compile(VISU_ELEMENT_RENDERER(self), visu_element_renderer_getConstGlView(VISU_ELEMENT_RENDERER(self))); return TRUE; } /* The icosahedron drawing. */ #define X .525731112119133606 #define Z .850650808352039932 static GLfloat vdata[12][3] = { {X, 0.0, -Z}, {-X, 0.0, -Z}, {X, 0.0, Z}, {-X, 0.0, Z}, {0.0, -Z, -X}, {0.0, -Z, X}, {0.0, Z, -X}, {0.0, Z, X}, {-Z, -X, 0.0}, {Z, -X, 0.0}, {-Z, X, 0.0}, {Z, X, 0.0} }; static GLuint tindices[20][3] = { {0,4,1}, {0,9,4}, {9,5,4}, {4,5,8}, {4,8,1}, {8,10,1}, {8,3,10}, {5,3,8}, {5,2,3}, {2,7,3}, {7,10,3}, {7,6,10}, {7,11,6}, {11,0,6}, {0,1,6}, {6,1,10}, {9,0,11}, {9,11,2}, {9,2,5}, {7,2,11} }; static void drawtriangle(float *v1, float *v2, float *v3) { glBegin(GL_TRIANGLES); glNormal3fv(v1); glVertex3fv(v1); glNormal3fv(v2); glVertex3fv(v2); glNormal3fv(v3); glVertex3fv(v3); glEnd(); } static void normalize(float v[3]) { GLfloat d = 1.f / sqrt(v[0]*v[0]+v[1]*v[1]+v[2]*v[2]); g_return_if_fail(d > 0.); v[0] *= d; v[1] *= d; v[2] *= d; } static void subdivide(float *v1, float *v2, float *v3, int depth) { GLfloat v12[3], v23[3], v31[3]; GLint i; if (depth == 0) { drawtriangle(v1, v2, v3); return; } for (i = 0; i < 3; i++) { v12[i] = v1[i]+v2[i]; v23[i] = v2[i]+v3[i]; v31[i] = v3[i]+v1[i]; } normalize(v12); normalize(v23); normalize(v31); subdivide(v1, v12, v31, depth - 1); subdivide(v2, v23, v12, depth - 1); subdivide(v3, v31, v23, depth - 1); subdivide(v12, v23, v31, depth - 1); } static void _renderAtomic(const VisuElementAtomic *ele, int nlat, gfloat gross) { int i, nfac; GLUquadricObj *obj; obj = gluNewQuadric(); switch (ele->priv->shape) { case VISU_ELEMENT_ATOMIC_SPHERE: DBG_fprintf(stderr, " | use sphere method %d\n", _sphereMethod); if (_sphereMethod == sphere_glu) gluSphere(obj, (double)ele->priv->radius, nlat, nlat); else if (_sphereMethod == sphere_icosahedron) { nfac = (int)(log((float)(nlat + 2) / 4.f) / log(2.f)); DBG_fprintf(stderr, " | glusphere vs. icosahedron %dx%d\n", nlat * nlat, 20 * (int)pow(4, nfac)); glPushMatrix(); glScalef(ele->priv->radius, ele->priv->radius, ele->priv->radius); glBegin(GL_TRIANGLES); for (i = 0; i < 20; i++) subdivide(&vdata[tindices[i][0]][0], &vdata[tindices[i][1]][0], &vdata[tindices[i][2]][0], nfac); glEnd(); glPopMatrix(); } else g_warning("Wrong sphere method."); break; case VISU_ELEMENT_ATOMIC_ELLIPSOID: glPushMatrix(); glRotatef(ele->priv->phi, 0., 0., 1.); glRotatef(ele->priv->theta, 0., 1., 0.); glScalef(1.0, 1.0, ele->priv->ratio); gluSphere(obj, (double)ele->priv->radius, nlat, nlat); glPopMatrix(); break; case VISU_ELEMENT_ATOMIC_POINT: glPointSize(MAX(1, (int)(ele->priv->radius * gross * 5.))); glBegin(GL_POINTS); glVertex3f(0., 0., 0.); glEnd(); break; case VISU_ELEMENT_ATOMIC_CUBE: glBegin(GL_QUADS); glNormal3f(0., 0., 1.); glVertex3f(ele->priv->radius / 2., ele->priv->radius / 2., ele->priv->radius / 2.); glVertex3f(-ele->priv->radius / 2., ele->priv->radius / 2., ele->priv->radius / 2.); glVertex3f(-ele->priv->radius / 2., -ele->priv->radius / 2., ele->priv->radius / 2.); glVertex3f(ele->priv->radius / 2., -ele->priv->radius / 2., ele->priv->radius / 2.); glNormal3f(0., 0., -1.); glVertex3f(ele->priv->radius / 2.,ele->priv->radius / 2.,-ele->priv->radius / 2.); glVertex3f(ele->priv->radius / 2.,-ele->priv->radius / 2.,-ele->priv->radius / 2.); glVertex3f(-ele->priv->radius / 2.,-ele->priv->radius / 2.,-ele->priv->radius / 2.); glVertex3f(-ele->priv->radius / 2.,ele->priv->radius / 2.,-ele->priv->radius / 2.); glNormal3f(1., 0., 0.); glVertex3f(ele->priv->radius / 2.,ele->priv->radius / 2.,ele->priv->radius / 2.); glVertex3f(ele->priv->radius / 2.,-ele->priv->radius / 2.,ele->priv->radius / 2.); glVertex3f(ele->priv->radius / 2.,-ele->priv->radius / 2.,-ele->priv->radius / 2.); glVertex3f(ele->priv->radius / 2.,ele->priv->radius / 2.,-ele->priv->radius / 2.); glNormal3f(-1., 0., 0.); glVertex3f(-ele->priv->radius / 2.,ele->priv->radius / 2.,ele->priv->radius / 2.); glVertex3f(-ele->priv->radius / 2.,ele->priv->radius / 2.,-ele->priv->radius / 2.); glVertex3f(-ele->priv->radius / 2.,-ele->priv->radius / 2.,-ele->priv->radius / 2.); glVertex3f(-ele->priv->radius / 2.,-ele->priv->radius / 2.,ele->priv->radius / 2.); glNormal3f(0., 1., 0.); glVertex3f(-ele->priv->radius / 2.,ele->priv->radius / 2.,-ele->priv->radius / 2.); glVertex3f(-ele->priv->radius / 2.,ele->priv->radius / 2.,ele->priv->radius / 2.); glVertex3f(ele->priv->radius / 2.,ele->priv->radius / 2.,ele->priv->radius / 2.); glVertex3f(ele->priv->radius / 2.,ele->priv->radius / 2.,-ele->priv->radius / 2.); glNormal3f(0., -1., 0.); glVertex3f(-ele->priv->radius / 2.,-ele->priv->radius / 2.,-ele->priv->radius / 2.); glVertex3f(ele->priv->radius / 2.,-ele->priv->radius / 2.,-ele->priv->radius / 2.); glVertex3f(ele->priv->radius / 2.,-ele->priv->radius / 2.,ele->priv->radius / 2.); glVertex3f(-ele->priv->radius / 2.,-ele->priv->radius / 2.,ele->priv->radius / 2.); glEnd(); break; case VISU_ELEMENT_ATOMIC_TORUS: glPushMatrix(); glRotatef(ele->priv->phi, 0., 0., 1.); glRotatef(ele->priv->theta, 0., 1., 0.); visu_gl_drawTorus(obj, ele->priv->radius, ele->priv->ratio, nlat, nlat, NULL); glPopMatrix(); break; default: g_warning("Unsupported shape id."); } gluDeleteQuadric(obj); } static void _compile(VisuElementRenderer *element, const VisuGlView *view) { int nlat; VisuElementAtomic *ele; ele = VISU_ELEMENT_ATOMIC(element); if (ele->priv->glElement) glDeleteLists(ele->priv->glElement, 1); if (!view) return; nlat = visu_gl_view_getDetailLevel(view, ele->priv->radius); DBG_fprintf(stderr, "Rendering Atomic: creating '%s' for %s (%d - fac %d)\n", _shapeName[ele->priv->shape], visu_element_getName(visu_element_renderer_getConstElement(element)), visu_element_renderer_getConstElement(element)->typeNumber, nlat); if (nlat < 0) return; if (!ele->priv->glElement) ele->priv->glElement = visu_gl_objectlist_new(1); glNewList(ele->priv->glElement, GL_COMPILE); _renderAtomic(ele, nlat, view->camera.gross); glEndList(); } static void _call(const VisuElementRenderer *element) { VisuElementAtomic *ele; ele = VISU_ELEMENT_ATOMIC(element); g_return_if_fail(ele->priv->glElement); glCallList(ele->priv->glElement); } static void _callAt(const VisuElementRenderer *element, const VisuDataColorizer *colorizer, const VisuData *data, const VisuNode *node) { float rgba[4]; float xyz[3]; float scale; if (colorizer && visu_data_colorizer_getColor(colorizer, rgba, data, node)) visu_gl_setColor((VisuGl*)0, visu_element_renderer_getMaterial(element), rgba); else if (colorizer && visu_data_colorizer_getActive(colorizer)) visu_element_renderer_colorize(element, VISU_ELEMENT_RENDERER_NO_EFFECT); visu_data_getNodePosition(data, node, xyz); scale = (colorizer) ? visu_data_colorizer_getScalingFactor(colorizer, data, node) : 1.f; glPushMatrix(); glTranslated(xyz[0], xyz[1], xyz[2]); glScalef(scale, scale, scale); glCallList(VISU_ELEMENT_ATOMIC(element)->priv->glElement); glPopMatrix(); } /** * visu_element_atomic_getShapeNames: * @asLabel: a boolean. * * Get the string defining #VisuElementAtomicShapeId. If @asLabel is * %TRUE, then the string are translated and stored in UTF8. * * Since: 3.8 * * Returns: (transfer none) (array zero-terminated=1): strings * representing #VisuElementAtomicShapeId. **/ const gchar ** visu_element_atomic_getShapeNames(gboolean asLabel) { if (asLabel) return _shapeNameI18n; else return _shapeName; } /*****************************************/ /* Dealing with parameters and resources */ /*****************************************/ static gboolean _sphereFromName(const gchar *name, guint *value) { g_return_val_if_fail(name && value, FALSE); for (*value = 0; *value < sphere_nb; *value += 1) if (!strcmp(name, _sphereName[*value])) return TRUE; return FALSE; } static gboolean _shapeFromName(const gchar *name, VisuElementAtomicShapeId *shape) { g_return_val_if_fail(name && shape, FALSE); for (*shape = 0; *shape < VISU_ELEMENT_ATOMIC_N_SHAPES; *shape += 1) if (!strcmp(name, _shapeName[*shape])) return TRUE; return FALSE; } static VisuElementAtomic* _fromEntry(VisuConfigFileEntry *entry) { const gchar *label; VisuElement *ele; label = visu_config_file_entry_getLabel(entry); ele = visu_element_retrieveFromName(label, (gboolean*)0); if (!ele) { visu_config_file_entry_setErrorMessage(entry, _("'%s' wrong element name"), label); return (VisuElementAtomic*)0; } return visu_element_atomic_getFromPool(ele); } static void onEntryRadiusShape(VisuConfigFile *obj _U_, VisuConfigFileEntry *entry, gpointer data _U_) { VisuElementAtomic *ele; float rgRadius[2] = {0.f, G_MAXFLOAT}; float radius; VisuElementAtomicShapeId shape; DBG_fprintf(stderr, "Rendering Atomic: parse line.\n"); /* Get the element. */ ele = _fromEntry(entry); if (!ele) return; /* Read 1 float. */ if (!visu_config_file_entry_popTokenAsFloat(entry, 1, &radius, rgRadius)) return; /* Read 1 string. */ if (!visu_config_file_entry_popTokenAsEnum(entry, &shape, _shapeFromName)) return; DBG_fprintf(stderr, "Rendering Atomic: store values.\n"); visu_element_atomic_setUnits(ele, TOOL_UNITS_UNDEFINED); visu_element_atomic_setRadius(ele, radius); visu_element_atomic_setUnits(ele, visu_basic_getPreferedUnit()); visu_element_atomic_setShape(ele, shape); } static void onEntryUnit(VisuElementAtomic *ele, VisuConfigFileEntry *entry _U_, VisuConfigFile *obj _U_) { if (ele->priv->units != TOOL_UNITS_UNDEFINED) return; visu_element_atomic_setUnits(ele, visu_basic_getPreferedUnit()); } /* These functions write all the element list to export there associated resources. */ static void exportAtomic(GString *data, VisuData *dataObj) { GList *pos; VisuElementAtomic *ele; const VisuElement *element; visu_config_file_exportComment(data, DESC_RESOURCE_RADIUS_SHAPE); for (pos = _pool; pos; pos = g_list_next(pos)) { ele = VISU_ELEMENT_ATOMIC(pos->data); element = visu_element_renderer_getConstElement(VISU_ELEMENT_RENDERER(ele)); if (!dataObj || visu_node_array_containsElement(VISU_NODE_ARRAY(dataObj), element)) visu_config_file_exportEntry(data, FLAG_RESOURCE_RADIUS_SHAPE, visu_element_getName(element), "%10.3f %s", ele->priv->radius, _shapeName[ele->priv->shape]); } visu_config_file_exportComment(data, ""); } static void exportAtomicShape(GString *data, VisuData* dataObj _U_) { g_string_append_printf(data, "# %s\n", DESC_PARAMETER_SHAPE); g_string_append_printf(data, "%s: %s\n\n", FLAG_PARAMETER_SHAPE, _sphereName[_sphereMethod]); } v_sim-3.8.0/src/renderingMethods/elementAtomic.h000066400000000000000000000134341370110300500216610ustar00rootroot00000000000000/* EXTRAITS DE LA LICENCE Copyright CEA, contributeurs : Damien CALISTE, laboratoire L_Sim, (2016) Adresse mèl : CALISTE, damien P caliste AT cea P fr. Ce logiciel est un programme informatique servant à visualiser des structures atomiques dans un rendu pseudo-3D. Ce logiciel est régi par la licence CeCILL soumise au droit français et respectant les principes de diffusion des logiciels libres. Vous pouvez utiliser, modifier et/ou redistribuer ce programme sous les conditions de la licence CeCILL telle que diffusée par le CEA, le CNRS et l'INRIA sur le site "http://www.cecill.info". Le fait que vous puissiez accéder à cet en-tête signifie que vous avez pris connaissance de la licence CeCILL, et que vous en avez accepté les termes (cf. le fichier Documentation/licence.fr.txt fourni avec ce logiciel). */ /* LICENCE SUM UP Copyright CEA, contributors : Damien CALISTE, laboratoire L_Sim, (2016) E-mail address: CALISTE, damien P caliste AT cea P fr. This software is a computer program whose purpose is to visualize atomic configurations in 3D. This software is governed by the CeCILL license under French law and abiding by the rules of distribution of free software. You can use, modify and/ or redistribute the software under the terms of the CeCILL license as circulated by CEA, CNRS and INRIA at the following URL "http://www.cecill.info". The fact that you are presently reading this means that you have had knowledge of the CeCILL license and that you accept its terms. You can find a copy of this licence shipped with this software at Documentation/licence.en.txt. */ #ifndef ELEMENT_ATOMIC_H #define ELEMENT_ATOMIC_H #include #include "elementRenderer.h" #include G_BEGIN_DECLS /** * VisuElementAtomicShapeId: * @VISU_ELEMENT_ATOMIC_SPHERE: draw sphere ; * @VISU_ELEMENT_ATOMIC_CUBE: draw cube ; * @VISU_ELEMENT_ATOMIC_ELLIPSOID: draw elipsoid ; * @VISU_ELEMENT_ATOMIC_POINT: draw square dot ; * @VISU_ELEMENT_ATOMIC_TORUS: draw torus ; * @VISU_ELEMENT_ATOMIC_N_SHAPES: number of shapes. * * This enum is used as identifier for shapes managed by the * attomic element method. */ typedef enum { VISU_ELEMENT_ATOMIC_SPHERE, VISU_ELEMENT_ATOMIC_CUBE, VISU_ELEMENT_ATOMIC_ELLIPSOID, VISU_ELEMENT_ATOMIC_POINT, VISU_ELEMENT_ATOMIC_TORUS, VISU_ELEMENT_ATOMIC_N_SHAPES } VisuElementAtomicShapeId; /** * VISU_TYPE_ELEMENT_ATOMIC: * * return the type of #VisuElementAtomic. */ #define VISU_TYPE_ELEMENT_ATOMIC (visu_element_atomic_get_type ()) /** * VISU_ELEMENT_ATOMIC: * @obj: a #GObject to cast. * * Cast the given @obj into #VisuElementAtomic type. */ #define VISU_ELEMENT_ATOMIC(obj) (G_TYPE_CHECK_INSTANCE_CAST(obj, VISU_TYPE_ELEMENT_ATOMIC, VisuElementAtomic)) /** * VISU_ELEMENT_ATOMIC_CLASS: * @klass: a #GObjectClass to cast. * * Cast the given @klass into #VisuElementAtomicClass. */ #define VISU_ELEMENT_ATOMIC_CLASS(klass) (G_TYPE_CHECK_CLASS_CAST(klass, VISU_TYPE_ELEMENT_ATOMIC, VisuElementAtomicClass)) /** * VISU_IS_ELEMENT_ATOMIC: * @obj: a #GObject to test. * * Test if the given @ogj is of the type of #VisuElementAtomic object. */ #define VISU_IS_ELEMENT_ATOMIC(obj) (G_TYPE_CHECK_INSTANCE_TYPE(obj, VISU_TYPE_ELEMENT_ATOMIC)) /** * VISU_IS_ELEMENT_ATOMIC_CLASS: * @klass: a #GObjectClass to test. * * Test if the given @klass is of the type of #VisuElementAtomicClass class. */ #define VISU_IS_ELEMENT_ATOMIC_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE(klass, VISU_TYPE_ELEMENT_ATOMIC)) /** * VISU_ELEMENT_ATOMIC_GET_CLASS: * @obj: a #GObject to get the class of. * * It returns the class of the given @obj. */ #define VISU_ELEMENT_ATOMIC_GET_CLASS(obj) (G_TYPE_INSTANCE_GET_CLASS(obj, VISU_TYPE_ELEMENT_ATOMIC, VisuElementAtomicClass)) typedef struct _VisuElementAtomicClass VisuElementAtomicClass; typedef struct _VisuElementAtomic VisuElementAtomic; typedef struct _VisuElementAtomicPrivate VisuElementAtomicPrivate; /** * visu_element_atomic_get_type: * * This method returns the type of #VisuElementAtomic, use VISU_TYPE_ELEMENT_ATOMIC instead. * * Returns: the type of #VisuElementAtomic. */ GType visu_element_atomic_get_type(void); /** * _VisuElementAtomic: * @parent: parent. * @priv: private data. * * This structure describes a set of pairs. */ struct _VisuElementAtomic { VisuElementRenderer parent; VisuElementAtomicPrivate *priv; }; struct _VisuElementAtomicClass { VisuElementRendererClass parent; }; VisuElementAtomic* visu_element_atomic_new(VisuElement *element); VisuElementAtomic* visu_element_atomic_getFromPool(VisuElement *element); void visu_element_atomic_bindToPool(VisuElementAtomic *atomic); gfloat visu_element_atomic_getRadius(const VisuElementAtomic *self); gboolean visu_element_atomic_setRadius(VisuElementAtomic *self, gfloat val); ToolUnits visu_element_atomic_getUnits (const VisuElementAtomic *self); gboolean visu_element_atomic_setUnits (VisuElementAtomic *self, ToolUnits val); VisuElementAtomicShapeId visu_element_atomic_getShape (const VisuElementAtomic *self); gboolean visu_element_atomic_setShape (VisuElementAtomic *self, VisuElementAtomicShapeId val); gfloat visu_element_atomic_getElipsoidRatio(const VisuElementAtomic *self); gboolean visu_element_atomic_setElipsoidRatio(VisuElementAtomic *self, gfloat val); gfloat visu_element_atomic_getElipsoidPhi (const VisuElementAtomic *self); gboolean visu_element_atomic_setElipsoidPhi (VisuElementAtomic *self, gfloat val); gfloat visu_element_atomic_getElipsoidTheta(const VisuElementAtomic *self); gboolean visu_element_atomic_setElipsoidTheta(VisuElementAtomic *self, gfloat val); const gchar ** visu_element_atomic_getShapeNames(gboolean asLabel); void visu_element_atomic_pool_finalize(void); G_END_DECLS #endif v_sim-3.8.0/src/renderingMethods/elementRenderer.c000066400000000000000000000675741370110300500222240ustar00rootroot00000000000000/* EXTRAITS DE LA LICENCE Copyright CEA, contributeurs : Damien CALISTE, laboratoire L_Sim, (2016) Adresse mèl : CALISTE, damien P caliste AT cea P fr. Ce logiciel est un programme informatique servant à visualiser des structures atomiques dans un rendu pseudo-3D. Ce logiciel est régi par la licence CeCILL soumise au droit français et respectant les principes de diffusion des logiciels libres. Vous pouvez utiliser, modifier et/ou redistribuer ce programme sous les conditions de la licence CeCILL telle que diffusée par le CEA, le CNRS et l'INRIA sur le site "http://www.cecill.info". Le fait que vous puissiez accéder à cet en-tête signifie que vous avez pris connaissance de la licence CeCILL, et que vous en avez accepté les termes (cf. le fichier Documentation/licence.fr.txt fourni avec ce logiciel). */ /* LICENCE SUM UP Copyright CEA, contributors : Damien CALISTE, laboratoire L_Sim, (2016) E-mail address: CALISTE, damien P caliste AT cea P fr. This software is a computer program whose purpose is to visualize atomic configurations in 3D. This software is governed by the CeCILL license under French law and abiding by the rules of distribution of free software. You can use, modify and/ or redistribute the software under the terms of the CeCILL license as circulated by CEA, CNRS and INRIA at the following URL "http://www.cecill.info". The fact that you are presently reading this means that you have had knowledge of the CeCILL license and that you accept its terms. You can find a copy of this licence shipped with this software at Documentation/licence.en.txt. */ #include "elementRenderer.h" #include #include #include #define FLAG_ELEMENT_COLOR "element_color" #define DESC_ELEMENT_COLOR "Codes the main color in RedGreenBlueAlpha format" \ "and the light effects on material, nine floats between 0. and 1." static gfloat _elementColor[9]; static ToolColor *_defaultColor; static gfloat _defaultMaterial[TOOL_MATERIAL_N_VALUES] = {0.25f, 0.25f, 0.25f, 0.25f, 0.25f}; /** * SECTION:elementRenderer * @short_description: a virtual class to render #VisuElement. * * This class is virtual and doesn't provide any rendering * method itself. It just gathers the basics generic to all * #VisuElement rendering classes. It provides in addition two * properties, the color and the material. * visu_element_renderer_getFromPool() is a specific function to * associate a unique #VisuElementRenderer to a given #VisuElement. */ /** * VisuElementRendererClass: * @parent: its parent. * @compile: a virtual method to compile an OpenGL list representing * the shape for a given #VisuElement. * @call: a virtual method to call the OpenGL list used for elements. * @callAt: a virtual method to position and draw a specific #VisuNode. * @getExtent: a virtual method to get the size of a given #VisuElement. * * Interface for class that can represent #VisuElementRenderer. * * Since: 3.8 */ /** * VisuElementRenderer: * * Structure used to define #VisuElementRenderer objects. * * Since: 3.8 */ struct _VisuElementRendererPrivate { gboolean dispose_has_run; VisuElement *element; VisuGlView *view; gulong precId; ToolColor color; gfloat material[TOOL_MATERIAL_N_VALUES]; }; enum { PROP_0, PROP_ELEMENT, PROP_RENDERED, PROP_MASKABLE, PROP_COLOR, PROP_MATERIAL, PROP_CACHE_MATERIAL, N_PROPS }; static GParamSpec *_properties[N_PROPS]; enum { ELEMENT_SIZE_CHANGED, LAST_SIGNAL }; static guint _signals[LAST_SIGNAL]; static GList *_pool = NULL; static void visu_element_renderer_dispose(GObject* obj); static void visu_element_renderer_get_property(GObject* obj, guint property_id, GValue *value, GParamSpec *pspec); static void visu_element_renderer_set_property(GObject* obj, guint property_id, const GValue *value, GParamSpec *pspec); static void notifyRendered(VisuElementRenderer *renderer); static void notifyMaskable(VisuElementRenderer *renderer); static void exportRenderer(GString *data, VisuData* dataObj); static void onEntryColor(VisuConfigFile *obj, VisuConfigFileEntry *entry, gpointer data); G_DEFINE_TYPE_WITH_CODE(VisuElementRenderer, visu_element_renderer, VISU_TYPE_OBJECT, G_ADD_PRIVATE(VisuElementRenderer)) static void visu_element_renderer_class_init(VisuElementRendererClass *klass) { VisuConfigFileEntry *resourceEntry, *oldEntry; float rgColor[2] = {0.f, 1.f}; gfloat rgba[4] = {1.f, 1.f, 1.f, 1.f}; /* Connect the overloading methods. */ G_OBJECT_CLASS(klass)->dispose = visu_element_renderer_dispose; G_OBJECT_CLASS(klass)->set_property = visu_element_renderer_set_property; G_OBJECT_CLASS(klass)->get_property = visu_element_renderer_get_property; /** * VisuElementRenderer::size-changed: * @obj: the object emitting the signal. * @size: the new size. * * Emitted when the size of a element is changed. * * Since: 3.8 */ _signals[ELEMENT_SIZE_CHANGED] = g_signal_new("size-changed", G_TYPE_FROM_CLASS (klass), G_SIGNAL_RUN_LAST | G_SIGNAL_NO_RECURSE, 0, NULL /* accumulator */, NULL /* accu_data */, g_cclosure_marshal_VOID__FLOAT, G_TYPE_NONE, 1, G_TYPE_FLOAT); /** * VisuElementRenderer::element: * * The element the renderer refers to. * * Since: 3.8 */ _properties[PROP_ELEMENT] = g_param_spec_object("element", "Element", "element", VISU_TYPE_ELEMENT, G_PARAM_READWRITE | G_PARAM_CONSTRUCT_ONLY); /** * VisuElementRenderer::rendered: * * If element is rendered or not. * * Since: 3.8 */ _properties[PROP_RENDERED] = g_param_spec_boolean("rendered", "Rendered", "if element is rendered", TRUE, G_PARAM_READWRITE); /** * VisuElementRenderer::maskable: * * If element is maskable or not. * * Since: 3.8 */ _properties[PROP_MASKABLE] = g_param_spec_boolean("maskable", "Maskable", "if element is maskable", TRUE, G_PARAM_READWRITE); /** * VisuElementRenderer::color: * * The element color. * * Since: 3.8 */ _properties[PROP_COLOR] = g_param_spec_boxed("color", "Color", "element color", TOOL_TYPE_COLOR, G_PARAM_READWRITE); /** * VisuElementRenderer::material: * * The element material properties. * * Since: 3.8 */ _properties[PROP_MATERIAL] = g_param_spec_boxed("material", "Material", "element material", TOOL_TYPE_MATERIAL, G_PARAM_READWRITE); /** * VisuElementRenderer::cache-material: * * The element can cache material properties. * * Since: 3.8 */ _properties[PROP_CACHE_MATERIAL] = g_param_spec_boolean("cache-material", "Cache material", "can put material in cache.", TRUE, G_PARAM_READABLE); g_object_class_install_properties(G_OBJECT_CLASS(klass), N_PROPS, _properties); oldEntry = visu_config_file_addEntry(VISU_CONFIG_FILE_RESOURCE, "material", "Obsolete entry for element_color", 1, NULL); resourceEntry = visu_config_file_addFloatArrayEntry(VISU_CONFIG_FILE_RESOURCE, FLAG_ELEMENT_COLOR, DESC_ELEMENT_COLOR, 9, _elementColor, rgColor, TRUE); visu_config_file_entry_setVersion(resourceEntry, 3.4f); visu_config_file_entry_setReplace(resourceEntry, oldEntry); g_signal_connect(VISU_CONFIG_FILE_RESOURCE, "parsed::" FLAG_ELEMENT_COLOR, G_CALLBACK(onEntryColor), (gpointer)0); visu_config_file_addExportFunction(VISU_CONFIG_FILE_RESOURCE, exportRenderer); _defaultColor = tool_color_addFloatRGBA(rgba, NULL); } static void visu_element_renderer_init(VisuElementRenderer *obj) { DBG_fprintf(stderr, "Visu Pair Renderer: initializing a new object (%p).\n", (gpointer)obj); obj->priv = visu_element_renderer_get_instance_private(obj); obj->priv->dispose_has_run = FALSE; obj->priv->view = (VisuGlView*)0; /* Private data. */ tool_color_copy(&obj->priv->color, _defaultColor); memcpy(&obj->priv->material, _defaultMaterial, sizeof(gfloat) * TOOL_MATERIAL_N_VALUES); } static void visu_element_renderer_dispose(GObject* obj) { VisuElementRenderer *data; DBG_fprintf(stderr, "Visu Element Renderer: dispose object %p.\n", (gpointer)obj); data = VISU_ELEMENT_RENDERER(obj); if (data->priv->dispose_has_run) return; data->priv->dispose_has_run = TRUE; g_object_unref(data->priv->element); visu_element_renderer_setGlView(data, (VisuGlView*)0); /* Chain up to the parent class */ G_OBJECT_CLASS(visu_element_renderer_parent_class)->dispose(obj); } static void visu_element_renderer_get_property(GObject* obj, guint property_id, GValue *value, GParamSpec *pspec) { VisuElementRenderer *self = VISU_ELEMENT_RENDERER(obj); DBG_fprintf(stderr, "Visu Element Renderer: get property '%s' -> ", g_param_spec_get_name(pspec)); switch (property_id) { case PROP_ELEMENT: g_value_set_object(value, self->priv->element); DBG_fprintf(stderr, "%p.\n", (gpointer)self->priv->element); break; case PROP_RENDERED: g_value_set_boolean(value, visu_element_getRendered(self->priv->element)); DBG_fprintf(stderr, "%d.\n", visu_element_getRendered(self->priv->element)); break; case PROP_MASKABLE: g_value_set_boolean(value, visu_element_getMaskable(self->priv->element)); DBG_fprintf(stderr, "%d.\n", visu_element_getMaskable(self->priv->element)); break; case PROP_COLOR: g_value_set_boxed(value, &self->priv->color); DBG_fprintf(stderr, "%gx%gx%g.\n", self->priv->color.rgba[0], self->priv->color.rgba[1], self->priv->color.rgba[2]); break; case PROP_MATERIAL: g_value_set_boxed(value, &self->priv->material); DBG_fprintf(stderr, "%gx%gx%gx%gx%g.\n", self->priv->material[0], self->priv->material[1], self->priv->material[2], self->priv->material[3], self->priv->material[4]); break; case PROP_CACHE_MATERIAL: g_value_set_boolean(value, TRUE); DBG_fprintf(stderr, "%d.\n", TRUE); break; default: /* We don't have any other property... */ G_OBJECT_WARN_INVALID_PROPERTY_ID(obj, property_id, pspec); break; } } static void visu_element_renderer_set_property(GObject* obj, guint property_id, const GValue *value, GParamSpec *pspec) { VisuElementRenderer *self = VISU_ELEMENT_RENDERER(obj); DBG_fprintf(stderr, "Visu Element Renderer: set property '%s' -> ", g_param_spec_get_name(pspec)); switch (property_id) { case PROP_ELEMENT: DBG_fprintf(stderr, "%p.\n", g_value_get_object(value)); self->priv->element = VISU_ELEMENT(g_value_dup_object(value)); g_signal_connect_swapped(self->priv->element, "notify::rendered", G_CALLBACK(notifyRendered), obj); g_signal_connect_swapped(self->priv->element, "notify::maskable", G_CALLBACK(notifyMaskable), obj); break; case PROP_RENDERED: DBG_fprintf(stderr, "%d.\n", g_value_get_boolean(value)); if (visu_element_setRendered(self->priv->element, g_value_get_boolean(value))) g_object_notify(obj, "rendered"); break; case PROP_MASKABLE: DBG_fprintf(stderr, "%d.\n", g_value_get_boolean(value)); if (visu_element_setMaskable(self->priv->element, g_value_get_boolean(value))) g_object_notify(obj, "maskable"); break; case PROP_COLOR: visu_element_renderer_setColor(VISU_ELEMENT_RENDERER(self), (ToolColor*)g_value_get_boxed(value)); DBG_fprintf(stderr, "%gx%gx%g.\n", self->priv->color.rgba[0], self->priv->color.rgba[1], self->priv->color.rgba[2]); break; case PROP_MATERIAL: visu_element_renderer_setMaterial(VISU_ELEMENT_RENDERER(self), (gfloat*)g_value_get_boxed(value)); DBG_fprintf(stderr, "%gx%gx%gx%gx%g.\n", self->priv->material[0], self->priv->material[1], self->priv->material[2], self->priv->material[3], self->priv->material[4]); break; default: /* We don't have any other property... */ G_OBJECT_WARN_INVALID_PROPERTY_ID(obj, property_id, pspec); break; } } /** * visu_element_renderer_getFromPool: * @element: a #VisuElement object. * * Retrieve a #VisuElementRenderer representing @element. This * #VisuElementRenderer is unique. * * Since: 3.8 * * Returns: (transfer none): a #VisuElementRenderer for @element. **/ VisuElementRenderer* visu_element_renderer_getFromPool(VisuElement *element) { GList *lst; for (lst = _pool; lst; lst = g_list_next(lst)) if (visu_element_renderer_getElement(VISU_ELEMENT_RENDERER(lst->data)) == element) return VISU_ELEMENT_RENDERER(lst->data); _pool = g_list_prepend(_pool, g_object_new(VISU_TYPE_ELEMENT_RENDERER, "element", element, NULL)); return VISU_ELEMENT_RENDERER(_pool->data); } /** * visu_element_renderer_bindToPool: * @element: a #VisuElementRenderer object. * * Bind @element to the corresponding #VisuElementRenderer of the * pool. This allows to have #VisuElement renderers that follow the * same color or maskable properties for instance of a given #VisuElement. * * Since: 3.8 **/ void visu_element_renderer_bindToPool(VisuElementRenderer *element) { VisuElementRenderer *pool; g_return_if_fail(VISU_IS_ELEMENT_RENDERER(element)); pool = visu_element_renderer_getFromPool(element->priv->element); g_object_bind_property(pool, "rendered", element, "rendered", G_BINDING_SYNC_CREATE | G_BINDING_BIDIRECTIONAL); g_object_bind_property(pool, "maskable", element, "maskable", G_BINDING_SYNC_CREATE | G_BINDING_BIDIRECTIONAL); g_object_bind_property(pool, "color", element, "color", G_BINDING_SYNC_CREATE | G_BINDING_BIDIRECTIONAL); g_object_bind_property(pool, "material", element, "material", G_BINDING_SYNC_CREATE | G_BINDING_BIDIRECTIONAL); } /** * visu_element_renderer_pool_finalize: (skip) * * Destroy the list of known #VisuElementRenderer, see * visu_element_renderer_getFromPool(). * * Since: 3.8 **/ void visu_element_renderer_pool_finalize(void) { g_list_free_full(_pool, (GDestroyNotify)g_object_unref); _pool = (GList*)0; } /** * visu_element_renderer_getExtent: * @element: a #VisuElementRenderer object. * * Retrives the radius of a sphere containing the representation of @element. * * Since: 3.8 * * Returns: a positive float value. **/ gfloat visu_element_renderer_getExtent(const VisuElementRenderer *element) { return VISU_ELEMENT_RENDERER_GET_CLASS(element)->getExtent(element); } /** * visu_element_renderer_getColor: * @element: a #VisuElementRenderer object. * * Retrieve the #ToolColor used by @element to represent a #VisuElement. * * Since: 3.8 * * Returns: (transfer none) (allow-none): a #ToolColor or %NULL. **/ const ToolColor* visu_element_renderer_getColor(const VisuElementRenderer *element) { g_return_val_if_fail(VISU_IS_ELEMENT_RENDERER(element), (const ToolColor*)0); return &VISU_ELEMENT_RENDERER(element)->priv->color; } /** * visu_element_renderer_setColor: * @ele: a #VisuElementRenderer object. * @color: a #ToolColor object. * * Changes the representation of @ele to use @color. * * Since: 3.8 * * Returns: TRUE if value is actually changed. **/ gboolean visu_element_renderer_setColor(VisuElementRenderer* ele, const ToolColor *color) { g_return_val_if_fail(VISU_IS_ELEMENT_RENDERER(ele), FALSE); if (tool_color_equal(&VISU_ELEMENT_RENDERER(ele)->priv->color, color)) return FALSE; tool_color_copy(&VISU_ELEMENT_RENDERER(ele)->priv->color, color); g_object_notify_by_pspec(G_OBJECT(ele), _properties[PROP_COLOR]); return TRUE; } /** * visu_element_renderer_setRGBAValue: * @ele: a #VisuElementRenderer object. * @value: a float vlaue in [0;1]. * @id: an value in [0;3]. * * Change one of the RGBA channel of the representation of @ele. * * Since: 3.8 * * Returns: TRUE if value is actually changed. **/ gboolean visu_element_renderer_setRGBAValue(VisuElementRenderer* ele, gfloat value, guint id) { ToolColor *color; gboolean res; g_return_val_if_fail(id < 4, FALSE); color = g_boxed_copy(TOOL_TYPE_COLOR, visu_element_renderer_getColor(ele)); color->rgba[id] = CLAMP(value, 0.f, 1.f); res = visu_element_renderer_setColor(ele, color); g_boxed_free(TOOL_TYPE_COLOR, color); return res; } /** * visu_element_renderer_getMaterial: * @element: a #VisuElementRenderer object. * * Retrieve the #ToolMaterial used by @element to represent a #VisuElement. * * Since: 3.8 * * Returns: (transfer none) (allow-none): a #ToolMaterial or %NULL. **/ const gfloat* visu_element_renderer_getMaterial(const VisuElementRenderer *element) { g_return_val_if_fail(VISU_IS_ELEMENT_RENDERER(element), (const gfloat*)0); return VISU_ELEMENT_RENDERER(element)->priv->material; } /** * visu_element_renderer_setMaterial: * @ele: a #VisuElementRenderer object. * @material: (type ToolMaterial): an array of float values in [0;1]. * * Changes all the material channel of @ele. * * Since: 3.8 * * Returns: TRUE if any value is actually changed. **/ gboolean visu_element_renderer_setMaterial(VisuElementRenderer* ele, const gfloat material[TOOL_MATERIAL_N_VALUES]) { g_return_val_if_fail(VISU_IS_ELEMENT_RENDERER(ele), FALSE); if (VISU_ELEMENT_RENDERER(ele)->priv->material[0] == material[0] && VISU_ELEMENT_RENDERER(ele)->priv->material[1] == material[1] && VISU_ELEMENT_RENDERER(ele)->priv->material[2] == material[2] && VISU_ELEMENT_RENDERER(ele)->priv->material[3] == material[3] && VISU_ELEMENT_RENDERER(ele)->priv->material[4] == material[4]) return FALSE; memcpy(VISU_ELEMENT_RENDERER(ele)->priv->material, material, sizeof(gfloat) * TOOL_MATERIAL_N_VALUES); g_object_notify_by_pspec(G_OBJECT(ele), _properties[PROP_MATERIAL]); return TRUE; } /** * visu_element_renderer_setMaterialValue: * @ele: a #VisuElementRenderer object. * @value: a float in [0;1]. * @id: a #ToolMaterialIds value. * * Changes the material channel @id with @value. * * Since: 3.8 * * Returns: TRUE if value is actually changed. **/ gboolean visu_element_renderer_setMaterialValue(VisuElementRenderer* ele, gfloat value, ToolMaterialIds id) { gfloat *material; gboolean res; material = g_boxed_copy(TOOL_TYPE_MATERIAL, visu_element_renderer_getMaterial(ele)); material[id] = CLAMP(value, 0.f, 1.f); res = visu_element_renderer_setMaterial(ele, material); g_boxed_free(TOOL_TYPE_MATERIAL, material); return res; } /** * visu_element_renderer_colorize: * @element: a #VisuElementRenderer object. * @effect: a #VisuElementRendererEffects value. * * Change the current OpenGL color, according to the color of * @element. An additional @effect can be added. * * Since: 3.8 **/ void visu_element_renderer_colorize(const VisuElementRenderer *element, VisuElementRendererEffects effect) { const ToolColor *color; const gfloat *material; float rgba[4], hsl[3], mat[TOOL_MATERIAL_N_VALUES]; float hmaterial[5] = {1.f, 1.f, 1.f, 0.f, 0.f}; DBG_fprintf(stderr, "Visu Element Renderer: colorize with effect %d.\n", effect); color = visu_element_renderer_getColor(element); g_return_if_fail(color); material = visu_element_renderer_getMaterial(element); if (effect == VISU_ELEMENT_RENDERER_FLATTEN || effect == VISU_ELEMENT_RENDERER_FLATTEN_DARK || effect == VISU_ELEMENT_RENDERER_FLATTEN_LIGHT) { switch (effect) { case (VISU_ELEMENT_RENDERER_FLATTEN_DARK): mat[TOOL_MATERIAL_AMB] = .2f; break; case (VISU_ELEMENT_RENDERER_FLATTEN): mat[TOOL_MATERIAL_AMB] = .75f; break; case (VISU_ELEMENT_RENDERER_FLATTEN_LIGHT): mat[TOOL_MATERIAL_AMB] = 1.f; break; default: break; } mat[TOOL_MATERIAL_DIF] = 0.f; mat[TOOL_MATERIAL_SHI] = 0.f; mat[TOOL_MATERIAL_SPE] = 0.f; mat[TOOL_MATERIAL_EMI] = 0.f; visu_gl_setColor((VisuGl*)0, mat, color->rgba); } else if (effect == VISU_ELEMENT_RENDERER_INVERT) { tool_color_invertRGBA(rgba, color->rgba); visu_gl_setColor((VisuGl*)0, material, rgba); } else if (effect == VISU_ELEMENT_RENDERER_HIGHLIGHT) { visu_gl_setHighlightColor((VisuGl*)0, material, color->rgba, color->rgba[3]); } else if (effect == VISU_ELEMENT_RENDERER_HIGHLIGHT_SEMI) { visu_gl_setHighlightColor((VisuGl*)0, hmaterial, color->rgba, 0.5f); } else if (effect != VISU_ELEMENT_RENDERER_NO_EFFECT) { tool_color_convertRGBtoHSL(hsl, color->rgba); switch (effect) { case (VISU_ELEMENT_RENDERER_DESATURATE): hsl[1] = 0.f; break; case (VISU_ELEMENT_RENDERER_SATURATE): hsl[1] = 1.f; break; case (VISU_ELEMENT_RENDERER_DARKEN): hsl[2] -= 0.2f; break; case (VISU_ELEMENT_RENDERER_LIGHTEN): hsl[2] += 0.2f; break; default: break; } tool_color_convertHSLtoRGB(rgba, hsl); rgba[3] = color->rgba[3]; visu_gl_setColor((VisuGl*)0, material, rgba); } else { visu_gl_setColor((VisuGl*)0, material, color->rgba); } } /** * visu_element_renderer_setGlView: * @element: a #VisuElementRenderer object. * @view: a #VisuGlView object. * * Associates @view to @element, so any changes to the rendering * precision happening in @view can imply a rebuild of the * representation of @element. * * Since: 3.8 **/ void visu_element_renderer_setGlView(VisuElementRenderer *element, VisuGlView *view) { g_return_if_fail(VISU_IS_ELEMENT_RENDERER(element)); if (element->priv->view == view) return; if (element->priv->view) { g_signal_handler_disconnect(element->priv->view, element->priv->precId); g_object_unref(element->priv->view); } element->priv->view = view; if (view) { g_object_ref(view); element->priv->precId = g_signal_connect_swapped(view, "DetailLevelChanged", G_CALLBACK(visu_element_renderer_rebuild), (gpointer)element); } visu_element_renderer_rebuild(element, view); } /** * visu_element_renderer_getConstGlView: * @element: a #VisuElementRenderer object. * * Retrieves the #VisuGlView associated to @element, see * visu_element_renderer_setGlView(). * * Since: 3.8 * * Returns: (transfer none): a const #VisuGlView object. **/ const VisuGlView* visu_element_renderer_getConstGlView(const VisuElementRenderer *element) { g_return_val_if_fail(VISU_IS_ELEMENT_RENDERER(element), (const VisuGlView*)0); return element->priv->view; } /** * visu_element_renderer_call: * @element: a #VisuElementRenderer object. * * A convenience function to run the call method of @element. * * Since: 3.8 **/ void visu_element_renderer_call(const VisuElementRenderer *element) { VISU_ELEMENT_RENDERER_GET_CLASS(element)->call(element); } /** * visu_element_renderer_callAt: * @element: a #VisuElementRenderer object. * @colorizer: (allow-none): a #VisuDataColorizer object. * @data: a #VisuData object. * @node: a #VisuNode belonging to @data. * * A convenience function to run the callAt method of @element. This * will represent @node of @data with the given @colorizer at the * coordinates of @node. * * Since: 3.8 **/ void visu_element_renderer_callAt(const VisuElementRenderer *element, const VisuDataColorizer *colorizer, const VisuData *data, const VisuNode *node) { VISU_ELEMENT_RENDERER_GET_CLASS(element)->callAt(element, colorizer, data, node); } /** * visu_element_renderer_featureMaterialCache: * @element: a #VisuElementRenderer object. * * Inquires if the given @element renderer can use Gl list to store * its material representation. * * Since: 3.8 * * Returns: TRUE if material representation can be stored in a Gl list. **/ gboolean visu_element_renderer_featureMaterialCache(const VisuElementRenderer *element) { gboolean feature; g_object_get(G_OBJECT(element), "cache-material", &feature, NULL); return feature; } /** * visu_element_renderer_getElement: * @element: a #VisuElementRenderer object. * * Retrieve the #VisuElement that is represented by @element. See * visu_element_renderer_getConstElement() if the returned value * should not be modified. * * Since: 3.8 * * Returns: (transfer none): the #VisuElement represented by @element. **/ VisuElement* visu_element_renderer_getElement(VisuElementRenderer *element) { g_return_val_if_fail(VISU_IS_ELEMENT_RENDERER(element), (VisuElement*)0); return VISU_ELEMENT_RENDERER(element)->priv->element; } /** * visu_element_renderer_getConstElement: * @element: a #VisuElementRenderer object. * * Retrieve the #VisuElement represented by @element. See * visu_element_renderer_getElement() if the return value should be modified. * * Since: 3.8 * * Returns: (transfer none): a const #VisuElement. **/ const VisuElement* visu_element_renderer_getConstElement(const VisuElementRenderer *element) { g_return_val_if_fail(VISU_IS_ELEMENT_RENDERER(element), (const VisuElement*)0); return VISU_ELEMENT_RENDERER(element)->priv->element; } /** * visu_element_renderer_rebuild: * @element: a #VisuElementRenderer object. * @view: a #VisuGlView object. * * Rebuild the OpenGL list representing @element for @view. * * Since: 3.8 **/ void visu_element_renderer_rebuild(VisuElementRenderer *element, const VisuGlView *view) { VISU_ELEMENT_RENDERER_GET_CLASS(element)->compile(element, view); } static void notifyRendered(VisuElementRenderer *renderer) { g_object_notify_by_pspec(G_OBJECT(renderer), _properties[PROP_RENDERED]); } static void notifyMaskable(VisuElementRenderer *renderer) { g_object_notify_by_pspec(G_OBJECT(renderer), _properties[PROP_MASKABLE]); } static void onEntryColor(VisuConfigFile *obj _U_, VisuConfigFileEntry *entry, gpointer data _U_) { VisuElementRenderer *ele; const gchar *label; VisuElement *element; label = visu_config_file_entry_getLabel(entry); element = visu_element_retrieveFromName(label, (gboolean*)0); if (!element) { visu_config_file_entry_setErrorMessage(entry, _("'%s' wrong element name"), label); return; } ele = visu_element_renderer_getFromPool(element); visu_element_renderer_setColor(ele, tool_color_addFloatRGBA(_elementColor, (int*)0)); visu_element_renderer_setMaterial(ele, _elementColor + 4); } static void exportRenderer(GString *data, VisuData *dataObj) { GList *pos; VisuElementRenderer *ele; visu_config_file_exportComment(data, DESC_ELEMENT_COLOR); for (pos = _pool; pos; pos = g_list_next(pos)) { ele = VISU_ELEMENT_RENDERER(pos->data); if (!dataObj || visu_node_array_containsElement(VISU_NODE_ARRAY(dataObj), ele->priv->element)) visu_config_file_exportEntry(data, FLAG_ELEMENT_COLOR, visu_element_getName(ele->priv->element), "%4.3f %4.3f %4.3f %4.3f %4.2f %4.2f %4.2f %4.2f %4.2f", ele->priv->color.rgba[0], ele->priv->color.rgba[1], ele->priv->color.rgba[2], ele->priv->color.rgba[3], ele->priv->material[0], ele->priv->material[1], ele->priv->material[2], ele->priv->material[3], ele->priv->material[4]); } visu_config_file_exportComment(data, ""); } v_sim-3.8.0/src/renderingMethods/elementRenderer.h000066400000000000000000000154201370110300500222100ustar00rootroot00000000000000/* EXTRAITS DE LA LICENCE Copyright CEA, contributeurs : Damien CALISTE, laboratoire L_Sim, (2016) Adresse mèl : CALISTE, damien P caliste AT cea P fr. Ce logiciel est un programme informatique servant à visualiser des structures atomiques dans un rendu pseudo-3D. Ce logiciel est régi par la licence CeCILL soumise au droit français et respectant les principes de diffusion des logiciels libres. Vous pouvez utiliser, modifier et/ou redistribuer ce programme sous les conditions de la licence CeCILL telle que diffusée par le CEA, le CNRS et l'INRIA sur le site "http://www.cecill.info". Le fait que vous puissiez accéder à cet en-tête signifie que vous avez pris connaissance de la licence CeCILL, et que vous en avez accepté les termes (cf. le fichier Documentation/licence.fr.txt fourni avec ce logiciel). */ /* LICENCE SUM UP Copyright CEA, contributors : Damien CALISTE, laboratoire L_Sim, (2016) E-mail address: CALISTE, damien P caliste AT cea P fr. This software is a computer program whose purpose is to visualize atomic configurations in 3D. This software is governed by the CeCILL license under French law and abiding by the rules of distribution of free software. You can use, modify and/ or redistribute the software under the terms of the CeCILL license as circulated by CEA, CNRS and INRIA at the following URL "http://www.cecill.info". The fact that you are presently reading this means that you have had knowledge of the CeCILL license and that you accept its terms. You can find a copy of this licence shipped with this software at Documentation/licence.en.txt. */ #ifndef ELEMENT_RENDERER_H #define ELEMENT_RENDERER_H #include #include #include #include #include #include G_BEGIN_DECLS /** * VisuElementRendererEffects: * @VISU_ELEMENT_RENDERER_NO_EFFECT: no effect (apply pristine element * color and material). * @VISU_ELEMENT_RENDERER_INVERT: invert colour. * @VISU_ELEMENT_RENDERER_HIGHLIGHT: highlight colour (same material). * @VISU_ELEMENT_RENDERER_HIGHLIGHT_SEMI: semi-transparent highlight * colour with neutral material. * @VISU_ELEMENT_RENDERER_DESATURATE: desaturate colour. * @VISU_ELEMENT_RENDERER_SATURATE: saturate colour. * @VISU_ELEMENT_RENDERER_DARKEN: darken colour. * @VISU_ELEMENT_RENDERER_LIGHTEN: lighten colour. * @VISU_ELEMENT_RENDERER_FLATTEN_DARK: render darker without light efect. * @VISU_ELEMENT_RENDERER_FLATTEN: render without light efect. * @VISU_ELEMENT_RENDERER_FLATTEN_LIGHT: render lighter without light efect. * * The rendering done by #VisuGlExtNodes can alter the color and * material of rendered nodes. * * Since: 3.7 */ typedef enum { VISU_ELEMENT_RENDERER_NO_EFFECT, VISU_ELEMENT_RENDERER_INVERT, VISU_ELEMENT_RENDERER_HIGHLIGHT, VISU_ELEMENT_RENDERER_HIGHLIGHT_SEMI, VISU_ELEMENT_RENDERER_DESATURATE, VISU_ELEMENT_RENDERER_SATURATE, VISU_ELEMENT_RENDERER_DARKEN, VISU_ELEMENT_RENDERER_LIGHTEN, VISU_ELEMENT_RENDERER_FLATTEN_DARK, VISU_ELEMENT_RENDERER_FLATTEN, VISU_ELEMENT_RENDERER_FLATTEN_LIGHT } VisuElementRendererEffects; /* ElementRenderer interface. */ #define VISU_TYPE_ELEMENT_RENDERER (visu_element_renderer_get_type()) #define VISU_ELEMENT_RENDERER(obj) (G_TYPE_CHECK_INSTANCE_CAST((obj), VISU_TYPE_ELEMENT_RENDERER, VisuElementRenderer)) #define VISU_ELEMENT_RENDERER_CLASS(klass) (G_TYPE_CHECK_CLASS_CAST(klass, VISU_TYPE_ELEMENT_RENDERER, VisuElementRendererClass)) #define VISU_IS_ELEMENT_RENDERER(obj) (G_TYPE_CHECK_INSTANCE_TYPE((obj), VISU_TYPE_ELEMENT_RENDERER)) #define VISU_IS_ELEMENT_RENDERER_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE(klass, VISU_TYPE_ELEMENT_RENDERER)) #define VISU_ELEMENT_RENDERER_GET_CLASS(obj) (G_TYPE_INSTANCE_GET_CLASS(obj, VISU_TYPE_ELEMENT_RENDERER, VisuElementRendererClass)) typedef struct _VisuElementRendererClass VisuElementRendererClass; typedef struct _VisuElementRenderer VisuElementRenderer; typedef struct _VisuElementRendererPrivate VisuElementRendererPrivate; /** * visu_element_renderer_get_type: * * This method returns the type of #VisuElementRenderer, use VISU_TYPE_ELEMENT_RENDERER instead. * * Returns: the type of #VisuElementRenderer. */ GType visu_element_renderer_get_type(void); struct _VisuElementRenderer { VisuObject parent; VisuElementRendererPrivate *priv; }; struct _VisuElementRendererClass { VisuObjectClass parent; gfloat (*getExtent)(const VisuElementRenderer *element); void (*compile) (VisuElementRenderer *element, const VisuGlView *view); void (*call) (const VisuElementRenderer *element); void (*callAt) (const VisuElementRenderer *element, const VisuDataColorizer *colorizer, const VisuData *data, const VisuNode *node); }; VisuElement* visu_element_renderer_getElement(VisuElementRenderer *element); const VisuElement* visu_element_renderer_getConstElement(const VisuElementRenderer *element); const ToolColor* visu_element_renderer_getColor(const VisuElementRenderer *element); gboolean visu_element_renderer_setColor(VisuElementRenderer* ele, const ToolColor *color); gboolean visu_element_renderer_setRGBAValue(VisuElementRenderer* ele, gfloat value, guint id); const gfloat* visu_element_renderer_getMaterial(const VisuElementRenderer *element); gboolean visu_element_renderer_setMaterial(VisuElementRenderer* ele, const gfloat material[TOOL_MATERIAL_N_VALUES]); gboolean visu_element_renderer_setMaterialValue(VisuElementRenderer* ele, gfloat value, ToolMaterialIds id); void visu_element_renderer_colorize(const VisuElementRenderer *element, VisuElementRendererEffects effect); void visu_element_renderer_setGlView(VisuElementRenderer *element, VisuGlView *view); const VisuGlView* visu_element_renderer_getConstGlView(const VisuElementRenderer *element); void visu_element_renderer_rebuild(VisuElementRenderer *element, const VisuGlView *view); void visu_element_renderer_call(const VisuElementRenderer *element); void visu_element_renderer_callAt(const VisuElementRenderer *element, const VisuDataColorizer *colorizer, const VisuData *data, const VisuNode *node); gfloat visu_element_renderer_getExtent(const VisuElementRenderer *element); gboolean visu_element_renderer_featureMaterialCache(const VisuElementRenderer *element); VisuElementRenderer* visu_element_renderer_getFromPool(VisuElement *element); void visu_element_renderer_bindToPool(VisuElementRenderer *element); void visu_element_renderer_pool_finalize(void); G_END_DECLS #endif v_sim-3.8.0/src/renderingMethods/elementSpin.c000066400000000000000000001005161370110300500213470ustar00rootroot00000000000000/* EXTRAITS DE LA LICENCE Copyright CEA, contributeurs : Damien CALISTE, laboratoire L_Sim, (2016) Adresse mèl : CALISTE, damien P caliste AT cea P fr. Ce logiciel est un programme informatique servant à visualiser des structures atomiques dans un rendu pseudo-3D. Ce logiciel est régi par la licence CeCILL soumise au droit français et respectant les principes de diffusion des logiciels libres. Vous pouvez utiliser, modifier et/ou redistribuer ce programme sous les conditions de la licence CeCILL telle que diffusée par le CEA, le CNRS et l'INRIA sur le site "http://www.cecill.info". Le fait que vous puissiez accéder à cet en-tête signifie que vous avez pris connaissance de la licence CeCILL, et que vous en avez accepté les termes (cf. le fichier Documentation/licence.fr.txt fourni avec ce logiciel). */ /* LICENCE SUM UP Copyright CEA, contributors : Damien CALISTE, laboratoire L_Sim, (2016) E-mail address: CALISTE, damien P caliste AT cea P fr. This software is a computer program whose purpose is to visualize atomic configurations in 3D. This software is governed by the CeCILL license under French law and abiding by the rules of distribution of free software. You can use, modify and/ or redistribute the software under the terms of the CeCILL license as circulated by CEA, CNRS and INRIA at the following URL "http://www.cecill.info". The fact that you are presently reading this means that you have had knowledge of the CeCILL license and that you accept its terms. You can find a copy of this licence shipped with this software at Documentation/licence.en.txt. */ #include "elementSpin.h" #include #include #include #include #include #include #include #include #include "spinMethod.h" /** * SECTION:elementSpin * @short_description: a class implementing rendering for * #VisuDataSpin method. * * This class implements the virtual method of * #VisuElementRenderer class to display nodes as 1D objects at a * given point in a given direction. The specific shape is defined by * #VisuElementSpinShapeId enumeration. The size and orientation of * the 1D object is given per node by a #VisuNodeValuesVector * property. * visu_element_spin_getFromPool() is a specific function to * associate a unique #VisuElementSpin to a given #VisuElement. */ /** * VisuElementSpinClass: * @parent: its parent. * * Interface for class that can represent #VisuElement of the same * kind in the same way (usually spheres). * * Since: 3.8 */ #define FLAG_RESOURCES_SPIN "spin_resources" #define DESC_RESOURCES_SPIN "Global or element resource for rendering spin module" #define FLAG_SPIN_SHAPE "spin_shape" #define DESC_SPIN_SHAPE "shape used to render spin for one element." static VisuElementSpinShapeId _shape = VISU_ELEMENT_SPIN_ARROW_SMOOTH; /* Default values. */ #define SPIN_ELEMENT_HAT_RADIUS_DEFAULT 0.8 #define SPIN_ELEMENT_HAT_LENGTH_DEFAULT 2.0 #define SPIN_ELEMENT_TAIL_RADIUS_DEFAULT 0.33 #define SPIN_ELEMENT_TAIL_LENGTH_DEFAULT 0.8 #define SPIN_ELEMENT_HAT_COLOR_DEFAULT FALSE #define SPIN_ELEMENT_TAIL_COLOR_DEFAULT FALSE #define FLAG_SPIN_ARROW "spin_arrow" #define DESC_SPIN_ARROW "arrow definition used to render spin for one element." static gfloat _arrow[] = {SPIN_ELEMENT_HAT_LENGTH_DEFAULT, SPIN_ELEMENT_HAT_RADIUS_DEFAULT, SPIN_ELEMENT_TAIL_LENGTH_DEFAULT, SPIN_ELEMENT_TAIL_RADIUS_DEFAULT, SPIN_ELEMENT_HAT_COLOR_DEFAULT, SPIN_ELEMENT_TAIL_COLOR_DEFAULT}; #define SPIN_ELEMENT_AAXIS_DEFAULT 1.5 #define SPIN_ELEMENT_BAXIS_DEFAULT 0.6 #define SPIN_ELEMENT_ELIP_COLOR_DEFAULT FALSE #define FLAG_SPIN_ELIP "spin_elipsoid" #define DESC_SPIN_ELIP "elipsoid definition used to render spin for one element." static gfloat _elip[] = {SPIN_ELEMENT_AAXIS_DEFAULT, SPIN_ELEMENT_BAXIS_DEFAULT, SPIN_ELEMENT_ELIP_COLOR_DEFAULT}; static const char* _shapeName[VISU_ELEMENT_SPIN_N_SHAPES + 1] = {"Rounded", "Edged", "Elipsoid", "Torus", (const char*)0}; static const char* _shapeNameI18n[VISU_ELEMENT_SPIN_N_SHAPES + 1] = {NULL}; /* Read routines for the config file. */ /** * VisuElementSpin: * * Structure used to define #VisuElementSpin objects. * * Since: 3.8 */ struct _VisuElementSpinPrivate { VisuElementAtomic *fromPool; /* Params for the arrow shapes. */ /* The radius and the length of the hat. */ float length, height; /* The radius and the length of the tail. */ float u_length, u_height; /* The coloring pattern. */ gboolean use_element_color, use_element_color_hat; /* Params for the elipsoid shapes. */ /* The long and the short axis. */ float aAxis, bAxis; /* The coloring pattern. */ gboolean elipsoidColor; /* The shape used. */ VisuElementSpinShapeId shape; GLuint glElement; }; enum { PROP_0, PROP_H_LENGTH, PROP_H_RADIUS, PROP_T_LENGTH, PROP_T_RADIUS, PROP_H_USE, PROP_T_USE, PROP_A, PROP_B, PROP_USE, PROP_SHAPE, N_PROPS, PROP_CACHE, N_PROP_TOT }; static GParamSpec *_properties[N_PROP_TOT]; static gboolean _shapeFromName(const gchar *name, VisuElementSpinShapeId *shape); static void visu_element_spin_get_property(GObject* obj, guint property_id, GValue *value, GParamSpec *pspec); static void visu_element_spin_set_property(GObject* obj, guint property_id, const GValue *value, GParamSpec *pspec); static void _compile(VisuElementRenderer *element, const VisuGlView *view); static void _call(const VisuElementRenderer *element); static void _callAt(const VisuElementRenderer *element, const VisuDataColorizer *colorizer, const VisuData *data, const VisuNode *node); static gfloat _getExtent (const VisuElementRenderer *self); static void onEntryShape(VisuConfigFile *obj, VisuConfigFileEntry *entry, gpointer data); static void onEntryArrow(VisuConfigFile *obj, VisuConfigFileEntry *entry, gpointer data); static void onEntryElip(VisuConfigFile *obj, VisuConfigFileEntry *entry, gpointer data); static void exportSpin(GString *data, VisuData *dataObj); static GList *_pool; G_DEFINE_TYPE_WITH_CODE(VisuElementSpin, visu_element_spin, VISU_TYPE_ELEMENT_ATOMIC, G_ADD_PRIVATE(VisuElementSpin)) static void visu_element_spin_class_init(VisuElementSpinClass *klass) { VisuConfigFileEntry *resourceEntry; gfloat rgArrow[2] = {0.f, 999.f}; /* Connect the overloading methods. */ G_OBJECT_CLASS(klass)->set_property = visu_element_spin_set_property; G_OBJECT_CLASS(klass)->get_property = visu_element_spin_get_property; VISU_ELEMENT_RENDERER_CLASS(klass)->compile = _compile; VISU_ELEMENT_RENDERER_CLASS(klass)->call = _call; VISU_ELEMENT_RENDERER_CLASS(klass)->callAt = _callAt; VISU_ELEMENT_RENDERER_CLASS(klass)->getExtent = _getExtent; /** * VisuElementSpin::spin-shape: * * The shape used to represent a given element. * * Since: 3.8 */ _properties[PROP_SHAPE] = g_param_spec_uint("spin-shape", "Spin shape", "spin shape", 0, VISU_ELEMENT_SPIN_N_SHAPES - 1, _shape, G_PARAM_READWRITE); /** * VisuElementSpin::hat-length: * * . * * Since: 3.8 */ _properties[PROP_H_LENGTH] = g_param_spec_float("hat-length", "Hat length", "hat length", 0.f, G_MAXFLOAT, SPIN_ELEMENT_HAT_LENGTH_DEFAULT, G_PARAM_READWRITE); /** * VisuElementSpin::hat-radius: * * . * * Since: 3.8 */ _properties[PROP_H_RADIUS] = g_param_spec_float("hat-radius", "Hat radius", "hat radius", 0.f, G_MAXFLOAT, SPIN_ELEMENT_HAT_RADIUS_DEFAULT, G_PARAM_READWRITE); /** * VisuElementSpin::tail-length: * * . * * Since: 3.8 */ _properties[PROP_T_LENGTH] = g_param_spec_float("tail-length", "Tail length", "tail length", 0.f, G_MAXFLOAT, SPIN_ELEMENT_TAIL_LENGTH_DEFAULT, G_PARAM_READWRITE); /** * VisuElementSpin::tail-radius: * * . * * Since: 3.8 */ _properties[PROP_T_RADIUS] = g_param_spec_float("tail-radius", "Tail radius", "tail radius", 0.f, G_MAXFLOAT, SPIN_ELEMENT_TAIL_RADIUS_DEFAULT, G_PARAM_READWRITE); /** * VisuElementSpin::hat-spin-colored: * * . * * Since: 3.8 */ _properties[PROP_H_USE] = g_param_spec_boolean("hat-spin-colored", "Hat spin colored", "hat is colored by spin", SPIN_ELEMENT_HAT_COLOR_DEFAULT, G_PARAM_READWRITE); /** * VisuElementSpin::tail-spin-colored: * * . * * Since: 3.8 */ _properties[PROP_T_USE] = g_param_spec_boolean("tail-spin-colored", "Tail spin colored", "tail is colored by spin", SPIN_ELEMENT_TAIL_COLOR_DEFAULT, G_PARAM_READWRITE); /** * VisuElementSpin::a-axis: * * . * * Since: 3.8 */ _properties[PROP_A] = g_param_spec_float("a-axis", "A axis", "A axis length", 0.f, G_MAXFLOAT, SPIN_ELEMENT_AAXIS_DEFAULT, G_PARAM_READWRITE); /** * VisuElementSpin::b-axis: * * . * * Since: 3.8 */ _properties[PROP_B] = g_param_spec_float("b-axis", "B axis", "B axis length", 0.f, G_MAXFLOAT, SPIN_ELEMENT_BAXIS_DEFAULT, G_PARAM_READWRITE); /** * VisuElementSpin::spin-colored: * * . * * Since: 3.8 */ _properties[PROP_USE] = g_param_spec_boolean("spin-colored", "Spin colored", "shape is colored by spin", SPIN_ELEMENT_ELIP_COLOR_DEFAULT, G_PARAM_READWRITE); g_object_class_install_properties(G_OBJECT_CLASS(klass), N_PROPS, _properties); g_object_class_override_property(G_OBJECT_CLASS(klass), PROP_CACHE, "cache-material"); /* Dealing with config files. */ resourceEntry = visu_config_file_addEnumEntry(VISU_CONFIG_FILE_RESOURCE, FLAG_SPIN_SHAPE, DESC_SPIN_SHAPE, &_shape, _shapeFromName, TRUE); visu_config_file_entry_setVersion(resourceEntry, 3.8f); g_signal_connect(VISU_CONFIG_FILE_RESOURCE, "parsed::" FLAG_SPIN_SHAPE, G_CALLBACK(onEntryShape), (gpointer)0); resourceEntry = visu_config_file_addFloatArrayEntry(VISU_CONFIG_FILE_RESOURCE, FLAG_SPIN_ARROW, DESC_SPIN_ARROW, 6, _arrow, rgArrow, TRUE); visu_config_file_entry_setVersion(resourceEntry, 3.8f); g_signal_connect(VISU_CONFIG_FILE_RESOURCE, "parsed::" FLAG_SPIN_ARROW, G_CALLBACK(onEntryArrow), (gpointer)0); resourceEntry = visu_config_file_addFloatArrayEntry(VISU_CONFIG_FILE_RESOURCE, FLAG_SPIN_ELIP, DESC_SPIN_ELIP, 3, _elip, rgArrow, TRUE); visu_config_file_entry_setVersion(resourceEntry, 3.8f); g_signal_connect(VISU_CONFIG_FILE_RESOURCE, "parsed::" FLAG_SPIN_ELIP, G_CALLBACK(onEntryElip), (gpointer)0); visu_config_file_addExportFunction(VISU_CONFIG_FILE_RESOURCE, exportSpin); _pool = (GList*)0; } static void visu_element_spin_init(VisuElementSpin *obj) { DBG_fprintf(stderr, "Visu Element Spin: initializing a new object (%p).\n", (gpointer)obj); obj->priv = visu_element_spin_get_instance_private(obj); /* Private data. */ obj->priv->fromPool = (VisuElementAtomic*)0; obj->priv->length = _arrow[1]; obj->priv->height = _arrow[0]; obj->priv->u_length = _arrow[3]; obj->priv->u_height = _arrow[2]; obj->priv->use_element_color = (_arrow[4] == TRUE); obj->priv->use_element_color_hat = (_arrow[5] == TRUE); obj->priv->aAxis = SPIN_ELEMENT_AAXIS_DEFAULT; obj->priv->bAxis = SPIN_ELEMENT_BAXIS_DEFAULT; obj->priv->elipsoidColor = SPIN_ELEMENT_ELIP_COLOR_DEFAULT; obj->priv->shape = _shape; } static void visu_element_spin_get_property(GObject* obj, guint property_id, GValue *value, GParamSpec *pspec) { VisuElementSpin *self = VISU_ELEMENT_SPIN(obj); DBG_fprintf(stderr, "Visu Element Spin: get property '%s'\n", g_param_spec_get_name(pspec)); switch (property_id) { case PROP_H_LENGTH: g_value_set_float(value, self->priv->height); break; case PROP_H_RADIUS: g_value_set_float(value, self->priv->length); break; case PROP_T_LENGTH: g_value_set_float(value, self->priv->u_height); break; case PROP_T_RADIUS: g_value_set_float(value, self->priv->u_length); break; case PROP_T_USE: g_value_set_boolean(value, self->priv->use_element_color); break; case PROP_H_USE: g_value_set_boolean(value, self->priv->use_element_color_hat); break; case PROP_A: g_value_set_float(value, self->priv->aAxis); break; case PROP_B: g_value_set_float(value, self->priv->bAxis); break; case PROP_USE: g_value_set_boolean(value, self->priv->elipsoidColor); break; case PROP_SHAPE: g_value_set_uint(value, self->priv->shape); break; case PROP_CACHE: g_value_set_boolean(value, FALSE); break; default: /* We don't have any other property... */ G_OBJECT_WARN_INVALID_PROPERTY_ID(obj, property_id, pspec); break; } } static void visu_element_spin_set_property(GObject* obj, guint property_id, const GValue *value, GParamSpec *pspec) { VisuElementSpin *self = VISU_ELEMENT_SPIN(obj); DBG_fprintf(stderr, "Visu Element Spin: set property '%s'\n", g_param_spec_get_name(pspec)); switch (property_id) { case PROP_H_LENGTH: self->priv->height = g_value_get_float(value); if (self->priv->shape == VISU_ELEMENT_SPIN_ARROW_SMOOTH || self->priv->shape == VISU_ELEMENT_SPIN_ARROW_SHARP) { g_signal_emit_by_name(self, "size-changed", _getExtent(VISU_ELEMENT_RENDERER(self))); _compile(VISU_ELEMENT_RENDERER(self), visu_element_renderer_getConstGlView(VISU_ELEMENT_RENDERER(self))); } break; case PROP_H_RADIUS: self->priv->length = g_value_get_float(value); if (self->priv->shape == VISU_ELEMENT_SPIN_ARROW_SMOOTH || self->priv->shape == VISU_ELEMENT_SPIN_ARROW_SHARP) _compile(VISU_ELEMENT_RENDERER(self), visu_element_renderer_getConstGlView(VISU_ELEMENT_RENDERER(self))); break; case PROP_T_LENGTH: self->priv->u_height = g_value_get_float(value); if (self->priv->shape == VISU_ELEMENT_SPIN_ARROW_SMOOTH || self->priv->shape == VISU_ELEMENT_SPIN_ARROW_SHARP) { g_signal_emit_by_name(self, "size-changed", _getExtent(VISU_ELEMENT_RENDERER(self))); _compile(VISU_ELEMENT_RENDERER(self), visu_element_renderer_getConstGlView(VISU_ELEMENT_RENDERER(self))); } break; case PROP_T_RADIUS: self->priv->u_length = g_value_get_float(value); if (self->priv->shape == VISU_ELEMENT_SPIN_ARROW_SMOOTH || self->priv->shape == VISU_ELEMENT_SPIN_ARROW_SHARP) _compile(VISU_ELEMENT_RENDERER(self), visu_element_renderer_getConstGlView(VISU_ELEMENT_RENDERER(self))); break; case PROP_T_USE: self->priv->use_element_color = g_value_get_boolean(value); if (self->priv->shape == VISU_ELEMENT_SPIN_ARROW_SMOOTH || self->priv->shape == VISU_ELEMENT_SPIN_ARROW_SHARP) _compile(VISU_ELEMENT_RENDERER(self), visu_element_renderer_getConstGlView(VISU_ELEMENT_RENDERER(self))); break; case PROP_H_USE: self->priv->use_element_color_hat = g_value_get_boolean(value); if (self->priv->shape == VISU_ELEMENT_SPIN_ARROW_SMOOTH || self->priv->shape == VISU_ELEMENT_SPIN_ARROW_SHARP) _compile(VISU_ELEMENT_RENDERER(self), visu_element_renderer_getConstGlView(VISU_ELEMENT_RENDERER(self))); break; case PROP_A: self->priv->aAxis = g_value_get_float(value); if (self->priv->shape == VISU_ELEMENT_SPIN_ELLIPSOID || self->priv->shape == VISU_ELEMENT_SPIN_TORUS) { g_signal_emit_by_name(self, "size-changed", _getExtent(VISU_ELEMENT_RENDERER(self))); _compile(VISU_ELEMENT_RENDERER(self), visu_element_renderer_getConstGlView(VISU_ELEMENT_RENDERER(self))); } break; case PROP_B: self->priv->bAxis = g_value_get_float(value); if (self->priv->shape == VISU_ELEMENT_SPIN_ELLIPSOID || self->priv->shape == VISU_ELEMENT_SPIN_TORUS) { g_signal_emit_by_name(self, "size-changed", _getExtent(VISU_ELEMENT_RENDERER(self))); _compile(VISU_ELEMENT_RENDERER(self), visu_element_renderer_getConstGlView(VISU_ELEMENT_RENDERER(self))); } break; case PROP_USE: self->priv->elipsoidColor = g_value_get_boolean(value); if (self->priv->shape == VISU_ELEMENT_SPIN_ELLIPSOID || self->priv->shape == VISU_ELEMENT_SPIN_TORUS) _compile(VISU_ELEMENT_RENDERER(self), visu_element_renderer_getConstGlView(VISU_ELEMENT_RENDERER(self))); break; case PROP_SHAPE: self->priv->shape = g_value_get_uint(value); g_signal_emit_by_name(self, "size-changed", _getExtent(VISU_ELEMENT_RENDERER(self))); _compile(VISU_ELEMENT_RENDERER(self), visu_element_renderer_getConstGlView(VISU_ELEMENT_RENDERER(self))); break; default: /* We don't have any other property... */ G_OBJECT_WARN_INVALID_PROPERTY_ID(obj, property_id, pspec); break; } } /** * visu_element_spin_new: * @element: a #VisuElement object. * * Creates a new #VisuElementSpin object to draw @element. * * Since: 3.8 * * Returns: (transfer full): a newly created #VisuElementSpin object. **/ VisuElementSpin* visu_element_spin_new(VisuElement *element) { return VISU_ELEMENT_SPIN(g_object_new(VISU_TYPE_ELEMENT_SPIN, "element", element, NULL)); } /** * visu_element_spin_getFromPool: * @element: a #VisuElement object. * * Retrieve a #VisuElementSpin representing @element. This * #VisuElementSpin is unique and its parent properties are bound to * the unique #VisuElementAtomic for @element. * * Since: 3.8 * * Returns: (transfer none): a #VisuElementSpin for @element. **/ VisuElementSpin* visu_element_spin_getFromPool(VisuElement *element) { GList *lst; VisuElementSpin *spin; for (lst = _pool; lst; lst = g_list_next(lst)) if (visu_element_renderer_getElement(VISU_ELEMENT_RENDERER(lst->data)) == element) return VISU_ELEMENT_SPIN(lst->data); spin = visu_element_spin_new(element); visu_element_atomic_bindToPool(VISU_ELEMENT_ATOMIC(spin)); _pool = g_list_prepend(_pool, spin); return spin; } /** * visu_element_spin_bindToPool: * @spin: A #VisuElementSpin object. * * Bind all properties of @spin to the properties of the * #VisuElementSpin object from the pool used for the same #VisuElement. * * Since: 3.8 **/ void visu_element_spin_bindToPool(VisuElementSpin *spin) { VisuElementSpin *pool; visu_element_atomic_bindToPool(VISU_ELEMENT_ATOMIC(spin)); pool = visu_element_spin_getFromPool(visu_element_renderer_getElement(VISU_ELEMENT_RENDERER(spin))); g_object_bind_property(pool, "spin-shape", spin, "spin-shape", G_BINDING_SYNC_CREATE | G_BINDING_BIDIRECTIONAL); g_object_bind_property(pool, "hat-length", spin, "hat-length", G_BINDING_SYNC_CREATE | G_BINDING_BIDIRECTIONAL); g_object_bind_property(pool, "hat-radius", spin, "hat-radius", G_BINDING_SYNC_CREATE | G_BINDING_BIDIRECTIONAL); g_object_bind_property(pool, "tail-length", spin, "tail-length", G_BINDING_SYNC_CREATE | G_BINDING_BIDIRECTIONAL); g_object_bind_property(pool, "tail-radius", spin, "tail-radius", G_BINDING_SYNC_CREATE | G_BINDING_BIDIRECTIONAL); g_object_bind_property(pool, "hat-spin-colored", spin, "hat-spin-colored", G_BINDING_SYNC_CREATE | G_BINDING_BIDIRECTIONAL); g_object_bind_property(pool, "tail-spin-colored", spin, "tail-spin-colored", G_BINDING_SYNC_CREATE | G_BINDING_BIDIRECTIONAL); g_object_bind_property(pool, "a-axis", spin, "a-axis", G_BINDING_SYNC_CREATE | G_BINDING_BIDIRECTIONAL); g_object_bind_property(pool, "b-axis", spin, "b-axis", G_BINDING_SYNC_CREATE | G_BINDING_BIDIRECTIONAL); g_object_bind_property(pool, "spin-colored", spin, "spin-colored", G_BINDING_SYNC_CREATE | G_BINDING_BIDIRECTIONAL); } /** * visu_element_spin_getShape: * @self: a #VisuElementSpin object. * * Retrieves the shape of @self. * * Since: 3.8 * * Returns: a #VisuElementSpinShapeId value. **/ VisuElementSpinShapeId visu_element_spin_getShape(const VisuElementSpin *self) { g_return_val_if_fail(VISU_IS_ELEMENT_SPIN(self), _shape); return self->priv->shape; } static gfloat _getExtent(const VisuElementRenderer *self) { VisuElementSpin *spin; g_return_val_if_fail(VISU_IS_ELEMENT_SPIN(self), 0.f); spin = VISU_ELEMENT_SPIN(self); if (spin->priv->shape == VISU_ELEMENT_SPIN_ARROW_SMOOTH || spin->priv->shape == VISU_ELEMENT_SPIN_ARROW_SHARP) return MAX(VISU_ELEMENT_RENDERER_CLASS(visu_element_spin_parent_class)->getExtent(self), (spin->priv->height + spin->priv->u_height) / 2.f); else if (spin->priv->shape == VISU_ELEMENT_SPIN_ELLIPSOID) return MAX(VISU_ELEMENT_RENDERER_CLASS(visu_element_spin_parent_class)->getExtent(self), MAX(spin->priv->aAxis, spin->priv->bAxis) / 2.f); else return MAX(VISU_ELEMENT_RENDERER_CLASS(visu_element_spin_parent_class)->getExtent(self), (spin->priv->aAxis - spin->priv->bAxis * spin->priv->bAxis / spin->priv->aAxis) / 2.f); } static void _compile(VisuElementRenderer *element, const VisuGlView *view) { int nlatl=0, nlatul=0, nlatoh=0; GLUquadricObj *obj; VisuElementSpin *ele; g_return_if_fail(VISU_IS_ELEMENT_SPIN(element)); ele = VISU_ELEMENT_SPIN(element); if (ele->priv->glElement) glDeleteLists(ele->priv->glElement, 1); if (!view) { VISU_ELEMENT_RENDERER_CLASS(visu_element_spin_parent_class)->compile(element, view); return; } nlatul = visu_gl_view_getDetailLevel(view, ele->priv->u_length) ; nlatl = visu_gl_view_getDetailLevel(view, ele->priv->length); nlatoh = visu_gl_view_getDetailLevel(view, ele->priv->height); DBG_fprintf(stderr, "Rendering Spin : creating arrow for %s, nlatl = %d," " nlatul = %d, nlatoh = %d\n", visu_element_getName(visu_element_renderer_getElement((VisuElementRenderer*)element)), nlatl, nlatul, nlatoh); if (!ele->priv->glElement) ele->priv->glElement = visu_gl_objectlist_new(1); glNewList(ele->priv->glElement, GL_COMPILE); obj = gluNewQuadric(); switch (ele->priv->shape) { case VISU_ELEMENT_SPIN_ARROW_SMOOTH: visu_gl_drawSmoothArrow(obj, VISU_GL_ARROW_CENTERED, ele->priv->u_height, ele->priv->u_length, nlatul, (ele->priv->use_element_color) ? element : NULL, ele->priv->height, ele->priv->length, nlatl, (ele->priv->use_element_color_hat) ? element : NULL); break; case VISU_ELEMENT_SPIN_ARROW_SHARP: visu_gl_drawEdgeArrow(VISU_GL_ARROW_CENTERED, ele->priv->u_height, ele->priv->u_length, (ele->priv->use_element_color) ? element : NULL, ele->priv->height, ele->priv->length, (ele->priv->use_element_color_hat) ? element : NULL); break; case VISU_ELEMENT_SPIN_ELLIPSOID: nlatl = visu_gl_view_getDetailLevel(view, ele->priv->bAxis); visu_gl_drawEllipsoid(obj, ele->priv->aAxis, ele->priv->bAxis, nlatl, (ele->priv->elipsoidColor) ? element : NULL); break; case VISU_ELEMENT_SPIN_TORUS: nlatul = visu_gl_view_getDetailLevel(view, ele->priv->aAxis); nlatl = visu_gl_view_getDetailLevel(view, ele->priv->bAxis); visu_gl_drawTorus(obj, ele->priv->aAxis - ele->priv->bAxis, ele->priv->aAxis / ele->priv->bAxis, nlatul, nlatl, (ele->priv->elipsoidColor) ? element : NULL); break; default: g_warning("Unknown shape."); break; } gluDeleteQuadric(obj); glEndList(); /* We always build atomic shapes in case we need them. */ VISU_ELEMENT_RENDERER_CLASS(visu_element_spin_parent_class)->compile(element, view); } static void _call(const VisuElementRenderer *element) { VisuElementSpin *ele; ele = VISU_ELEMENT_SPIN(element); g_return_if_fail(ele->priv->glElement); glCallList(ele->priv->glElement); } static void _callAt(const VisuElementRenderer *element, const VisuDataColorizer *colorizer, const VisuData *data, const VisuNode *node) { VisuElementSpin *self = VISU_ELEMENT_SPIN(element); const VisuDataSpin *dataSpin; float mm[4]; float rgba[4]; float xyz[3]; const gfloat *spinValues; float scale, ratio; gboolean withAtomic; const gfloat *material; const ToolColor *color; color = visu_element_renderer_getColor(element); material = visu_element_renderer_getMaterial(element); dataSpin = VISU_DATA_SPIN(data); /* Test the modulus. */ scale = (colorizer) ? visu_data_colorizer_getScalingFactor(colorizer, data, node) : 1.f; visu_data_getNodePosition(data, node, xyz); if ((spinValues = visu_method_spin_getSpinVector(visu_method_spin_getDefault(), dataSpin, node, &ratio, mm, &withAtomic))) { /* The following is the part responsible for the rotation of the atoms according to their spins. */ glPushMatrix(); /* Translate to the rendering position. */ glTranslated(xyz[0], xyz[1], xyz[2]); /* If we need to draw also an atom shape. */ if (withAtomic) { visu_element_renderer_colorize(element, VISU_ELEMENT_RENDERER_NO_EFFECT); VISU_ELEMENT_RENDERER_CLASS(visu_element_spin_parent_class)->call(element); } /* We rotate the spin shape into the right direction. */ glRotated(spinValues[TOOL_MATRIX_SPHERICAL_PHI], 0, 0, 1); glRotated(spinValues[TOOL_MATRIX_SPHERICAL_THETA], 0, 1, 0); /* We change its color if required. */ if (colorizer && visu_data_colorizer_getColor(colorizer, rgba, data, node)) visu_gl_setColor((VisuGl*)0, material, rgba); else { mm[3] = color->rgba[3]; visu_gl_setColor((VisuGl*)0, material, mm); } /* We finaly put the spin shape. */ glScalef(scale * ratio, scale * ratio, scale * ratio); glCallList(self->priv->glElement); glPopMatrix(); } else if (withAtomic) { glPushMatrix(); glTranslated(xyz[0], xyz[1], xyz[2]); glScalef(scale, scale, scale); if (colorizer && visu_data_colorizer_getColor(colorizer, rgba, data, node)) visu_gl_setColor((VisuGl*)0, material, rgba); else visu_element_renderer_colorize(element, VISU_ELEMENT_RENDERER_NO_EFFECT); VISU_ELEMENT_RENDERER_CLASS(visu_element_spin_parent_class)->call(element); glPopMatrix(); } } /** * visu_element_spin_getShapeNames: * @asLabel: a boolean. * * Get the string defining #VisuElementSpinShapeId. If @asLabel is * %TRUE, then the string are translated and stored in UTF8. * * Since: 3.8 * * Returns: (transfer none) (array zero-terminated=1): strings * representing #VisuElementSpinShapeId. **/ const gchar ** visu_element_spin_getShapeNames(gboolean asLabel) { if (!_shapeNameI18n[0]) { _shapeNameI18n[0] = _("Rounded arrow"); _shapeNameI18n[1] = _("Edged arrow"); _shapeNameI18n[2] = _("Elipsoid"); _shapeNameI18n[3] = _("Torus"); _shapeNameI18n[4] = (const char*)0; } if (asLabel) return _shapeNameI18n; else return _shapeName; } /*****************************************/ /* Dealing with parameters and resources */ /*****************************************/ static gboolean _shapeFromName(const gchar *name, VisuElementSpinShapeId *shape) { g_return_val_if_fail(name && shape, FALSE); for (*shape = 0; *shape < VISU_ELEMENT_SPIN_N_SHAPES; *shape += 1) if (!strcmp(name, _shapeName[*shape])) return TRUE; return FALSE; } static VisuElementSpin* _fromEntry(VisuConfigFileEntry *entry) { const gchar *label; VisuElement *ele; label = visu_config_file_entry_getLabel(entry); ele = visu_element_retrieveFromName(label, (gboolean*)0); if (!ele) { visu_config_file_entry_setErrorMessage(entry, _("'%s' wrong element name"), label); return (VisuElementSpin*)0; } return visu_element_spin_getFromPool(ele); } static void onEntryShape(VisuConfigFile *obj _U_, VisuConfigFileEntry *entry, gpointer data _U_) { VisuElementSpin *ele; ele = _fromEntry(entry); if (!ele) return; g_object_set(ele, "shape", _shape, NULL); } static void onEntryArrow(VisuConfigFile *obj _U_, VisuConfigFileEntry *entry, gpointer data _U_) { VisuElementSpin *ele; ele = _fromEntry(entry); if (!ele) return; g_object_set(ele, "hat-length", _arrow[0], "hat-radius", _arrow[1], "tail-length", _arrow[2], "tail-radius", _arrow[3], "hat-spin-colored", (_arrow[4] == TRUE), "tail-spin-colored", (_arrow[5] == TRUE), NULL); } static void onEntryElip(VisuConfigFile *obj _U_, VisuConfigFileEntry *entry, gpointer data _U_) { VisuElementSpin *ele; ele = _fromEntry(entry); if (!ele) return; g_object_set(ele, "a-axis", _elip[0], "b-axis", _elip[1], "spin-colored", (_elip[2] == TRUE), NULL); } /* These functions write all the element list to export there associated resources. */ static void exportSpin(GString *data, VisuData* dataObj) { GList *pos; VisuElementSpin *spin; const VisuElement *ele; /* If dataObj is given and the rendering method is not spin, we return. */ if (dataObj && VISU_IS_DATA_SPIN(dataObj)) return; DBG_fprintf(stderr, "Rendering Spin: exporting element resources...\n"); visu_config_file_exportComment(data, DESC_RESOURCES_SPIN); /* We create a list of elements, or get the whole list. */ for (pos = _pool; pos; pos = g_list_next(pos)) { spin = VISU_ELEMENT_SPIN(pos->data); ele = visu_element_renderer_getConstElement(VISU_ELEMENT_RENDERER(spin)); if (!dataObj || visu_node_array_containsElement(VISU_NODE_ARRAY(dataObj), ele)) { if (spin->priv->shape != _shape) visu_config_file_exportEntry(data, FLAG_SPIN_SHAPE, visu_element_getName(ele), "%s", _shapeName[spin->priv->shape]); if (ABS(spin->priv->height - SPIN_ELEMENT_HAT_LENGTH_DEFAULT) > 1e-6 || ABS(spin->priv->u_height - SPIN_ELEMENT_TAIL_LENGTH_DEFAULT) > 1e-6 || ABS(spin->priv->length - SPIN_ELEMENT_HAT_RADIUS_DEFAULT) > 1e-6 || ABS(spin->priv->u_length - SPIN_ELEMENT_TAIL_RADIUS_DEFAULT) > 1e-6 || spin->priv->use_element_color != SPIN_ELEMENT_TAIL_COLOR_DEFAULT || spin->priv->use_element_color_hat != SPIN_ELEMENT_HAT_COLOR_DEFAULT) visu_config_file_exportEntry(data, FLAG_SPIN_ARROW, visu_element_getName(ele), "%f %f %f %f %d %d", spin->priv->height, spin->priv->u_height, spin->priv->length, spin->priv->u_length, spin->priv->use_element_color, spin->priv->use_element_color_hat); if (ABS(spin->priv->aAxis - SPIN_ELEMENT_AAXIS_DEFAULT) > 1e-6 || ABS(spin->priv->bAxis - SPIN_ELEMENT_BAXIS_DEFAULT) > 1e-6 || spin->priv->elipsoidColor != SPIN_ELEMENT_ELIP_COLOR_DEFAULT) visu_config_file_exportEntry(data, FLAG_SPIN_ELIP, visu_element_getName(ele), "%f %f %d", spin->priv->aAxis, spin->priv->bAxis, spin->priv->elipsoidColor); } } visu_config_file_exportComment(data, ""); } /** * visu_element_spin_pool_finalize: (skip) * * Destroy the internal list of known #VisuElementSpin objects, see * visu_element_spin_getFromPool(). * * Since: 3.8 **/ void visu_element_spin_pool_finalize(void) { g_list_free_full(_pool, (GDestroyNotify)g_object_unref); _pool = (GList*)0; } v_sim-3.8.0/src/renderingMethods/elementSpin.h000066400000000000000000000113761370110300500213610ustar00rootroot00000000000000/* EXTRAITS DE LA LICENCE Copyright CEA, contributeurs : Damien CALISTE, laboratoire L_Sim, (2016) Adresse mèl : CALISTE, damien P caliste AT cea P fr. Ce logiciel est un programme informatique servant à visualiser des structures atomiques dans un rendu pseudo-3D. Ce logiciel est régi par la licence CeCILL soumise au droit français et respectant les principes de diffusion des logiciels libres. Vous pouvez utiliser, modifier et/ou redistribuer ce programme sous les conditions de la licence CeCILL telle que diffusée par le CEA, le CNRS et l'INRIA sur le site "http://www.cecill.info". Le fait que vous puissiez accéder à cet en-tête signifie que vous avez pris connaissance de la licence CeCILL, et que vous en avez accepté les termes (cf. le fichier Documentation/licence.fr.txt fourni avec ce logiciel). */ /* LICENCE SUM UP Copyright CEA, contributors : Damien CALISTE, laboratoire L_Sim, (2016) E-mail address: CALISTE, damien P caliste AT cea P fr. This software is a computer program whose purpose is to visualize atomic configurations in 3D. This software is governed by the CeCILL license under French law and abiding by the rules of distribution of free software. You can use, modify and/ or redistribute the software under the terms of the CeCILL license as circulated by CEA, CNRS and INRIA at the following URL "http://www.cecill.info". The fact that you are presently reading this means that you have had knowledge of the CeCILL license and that you accept its terms. You can find a copy of this licence shipped with this software at Documentation/licence.en.txt. */ #ifndef ELEMENT_SPIN_H #define ELEMENT_SPIN_H #include #include "elementAtomic.h" G_BEGIN_DECLS /** * VisuElementSpinShapeId: * @VISU_ELEMENT_SPIN_ARROW_SMOOTH: the shape is smooth and rounded ; * @VISU_ELEMENT_SPIN_ARROW_SHARP: the shape is built on squares ; * @VISU_ELEMENT_SPIN_ELLIPSOID: the shape is an ellipsoid ; * @VISU_ELEMENT_SPIN_TORUS: the shape is a torus (direction of the arrow is * normal to the torus plane). * @VISU_ELEMENT_SPIN_N_SHAPES: private. * * An identifier for the different shapes to draw elements. */ typedef enum { VISU_ELEMENT_SPIN_ARROW_SMOOTH, VISU_ELEMENT_SPIN_ARROW_SHARP, VISU_ELEMENT_SPIN_ELLIPSOID, VISU_ELEMENT_SPIN_TORUS, /*< private >*/ VISU_ELEMENT_SPIN_N_SHAPES } VisuElementSpinShapeId; /** * VISU_TYPE_ELEMENT_SPIN: * * return the type of #VisuElementSpin. */ #define VISU_TYPE_ELEMENT_SPIN (visu_element_spin_get_type ()) /** * VISU_ELEMENT_SPIN: * @obj: a #GObject to cast. * * Cast the given @obj into #VisuElementSpin type. */ #define VISU_ELEMENT_SPIN(obj) (G_TYPE_CHECK_INSTANCE_CAST(obj, VISU_TYPE_ELEMENT_SPIN, VisuElementSpin)) /** * VISU_ELEMENT_SPIN_CLASS: * @klass: a #GObjectClass to cast. * * Cast the given @klass into #VisuElementSpinClass. */ #define VISU_ELEMENT_SPIN_CLASS(klass) (G_TYPE_CHECK_CLASS_CAST(klass, VISU_TYPE_ELEMENT_SPIN, VisuElementSpinClass)) /** * VISU_IS_ELEMENT_SPIN: * @obj: a #GObject to test. * * Test if the given @ogj is of the type of #VisuElementSpin object. */ #define VISU_IS_ELEMENT_SPIN(obj) (G_TYPE_CHECK_INSTANCE_TYPE(obj, VISU_TYPE_ELEMENT_SPIN)) /** * VISU_IS_ELEMENT_SPIN_CLASS: * @klass: a #GObjectClass to test. * * Test if the given @klass is of the type of #VisuElementSpinClass class. */ #define VISU_IS_ELEMENT_SPIN_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE(klass, VISU_TYPE_ELEMENT_SPIN)) /** * VISU_ELEMENT_SPIN_GET_CLASS: * @obj: a #GObject to get the class of. * * It returns the class of the given @obj. */ #define VISU_ELEMENT_SPIN_GET_CLASS(obj) (G_TYPE_INSTANCE_GET_CLASS(obj, VISU_TYPE_ELEMENT_SPIN, VisuElementSpinClass)) typedef struct _VisuElementSpinClass VisuElementSpinClass; typedef struct _VisuElementSpin VisuElementSpin; typedef struct _VisuElementSpinPrivate VisuElementSpinPrivate; /** * visu_element_spin_get_type: * * This method returns the type of #VisuElementSpin, use VISU_TYPE_ELEMENT_SPIN instead. * * Returns: the type of #VisuElementSpin. */ GType visu_element_spin_get_type(void); /** * _VisuElementSpin: * @parent: parent. * @priv: private data. * * This structure describes a set of pairs. */ struct _VisuElementSpin { VisuElementAtomic parent; VisuElementSpinPrivate *priv; }; struct _VisuElementSpinClass { VisuElementAtomicClass parent; }; VisuElementSpin* visu_element_spin_new(VisuElement *element); VisuElementSpin* visu_element_spin_getFromPool(VisuElement *element); void visu_element_spin_bindToPool(VisuElementSpin *spin); VisuElementSpinShapeId visu_element_spin_getShape(const VisuElementSpin *self); const gchar ** visu_element_spin_getShapeNames(gboolean asLabel); void visu_element_spin_pool_finalize(void); G_END_DECLS #endif v_sim-3.8.0/src/renderingMethods/iface_nodeArrayRenderer.c000066400000000000000000000326531370110300500236340ustar00rootroot00000000000000/* EXTRAITS DE LA LICENCE Copyright CEA, contributeurs : Damien CALISTE, laboratoire L_Sim, (2016) Adresse mèl : CALISTE, damien P caliste AT cea P fr. Ce logiciel est un programme informatique servant à visualiser des structures atomiques dans un rendu pseudo-3D. Ce logiciel est régi par la licence CeCILL soumise au droit français et respectant les principes de diffusion des logiciels libres. Vous pouvez utiliser, modifier et/ou redistribuer ce programme sous les conditions de la licence CeCILL telle que diffusée par le CEA, le CNRS et l'INRIA sur le site "http://www.cecill.info". Le fait que vous puissiez accéder à cet en-tête signifie que vous avez pris connaissance de la licence CeCILL, et que vous en avez accepté les termes (cf. le fichier Documentation/licence.fr.txt fourni avec ce logiciel). */ /* LICENCE SUM UP Copyright CEA, contributors : Damien CALISTE, laboratoire L_Sim, (2016) E-mail address: CALISTE, damien P caliste AT cea P fr. This software is a computer program whose purpose is to visualize atomic configurations in 3D. This software is governed by the CeCILL license under French law and abiding by the rules of distribution of free software. You can use, modify and/ or redistribute the software under the terms of the CeCILL license as circulated by CEA, CNRS and INRIA at the following URL "http://www.cecill.info". The fact that you are presently reading this means that you have had knowledge of the CeCILL license and that you accept its terms. You can find a copy of this licence shipped with this software at Documentation/licence.en.txt. */ #include "iface_nodeArrayRenderer.h" #include /** * SECTION:iface_nodeArrayRenderer * @short_description: An interface grouping all the * #VisuElementRenderer used to represent a set of #VisuNode. * * This interface provides common methods for object displaying * #VisuData information. In particular, it provides access to all the * #VisuElementRenderer used to render the nodes and an iterator to * run over #VisuElementRenderer. */ /** * VisuNodeArrayRendererIter: * @self: the #VisuNodeArrayRenderer this iterator is working on. * @element: the current #VisuElement. * @renderer: the #VisuElementRenderer of @element. * @nStoredNodes: the number of nodes of @element. * @parent: the #VisuNodeArrayIter this iter is based upon. * * An iterator over #VisuElementRenderer of @self. */ enum { PROP_0, PROP_NODE_ARRAY, PROP_TYPE, PROP_MAX_NODE_SIZE, PROP_COLORIZER, N_PROPS }; static GParamSpec *_properties[N_PROPS]; enum { ELEMENT_SIGNAL, SIZE_SIGNAL, NODES_SIGNAL, NB_SIGNAL }; static guint _signals[NB_SIGNAL] = { 0 }; /* Boxed interface. */ G_DEFINE_INTERFACE(VisuNodeArrayRenderer, visu_node_array_renderer, G_TYPE_OBJECT) static void g_cclosure_marshal_ELEMENT_FLOAT(GClosure *closure, GValue *return_value _U_, guint n_param_values, const GValue *param_values, gpointer invocation_hint _U_, gpointer marshal_data) { typedef void (*callbackFunc)(gpointer data1, VisuElementRenderer *ele, gfloat size, gpointer data2); register callbackFunc callback; register GCClosure *cc = (GCClosure*)closure; register gpointer data1, data2; g_return_if_fail(n_param_values == 3); if (G_CCLOSURE_SWAP_DATA(closure)) { data1 = closure->data; data2 = g_value_peek_pointer(param_values + 0); } else { data1 = g_value_peek_pointer(param_values + 0); data2 = closure->data; } callback = (callbackFunc)(size_t)(marshal_data ? marshal_data : cc->callback); callback(data1, VISU_ELEMENT_RENDERER(g_value_get_object(param_values + 1)), g_value_get_float(param_values + 2), data2); } static void visu_node_array_renderer_default_init(VisuNodeArrayRendererInterface *iface) { /** * VisuNodeArrayRenderer::element-notify: * @self: the object emitting the signal. * @renderer: the #VisuElementRenderer that has been changed. * * This signal is emitted each time one of the #VisuElementRenderer * used to represent the #VisuNodeArray is changed. * * Since: 3.8 */ _signals[ELEMENT_SIGNAL] = g_signal_new("element-notify", G_TYPE_FROM_INTERFACE(iface), G_SIGNAL_RUN_LAST | G_SIGNAL_NO_RECURSE | G_SIGNAL_NO_HOOKS | G_SIGNAL_DETAILED, 0, NULL, NULL, g_cclosure_marshal_VOID__OBJECT, G_TYPE_NONE, 1, VISU_TYPE_ELEMENT_RENDERER); /** * VisuNodeArrayRenderer::element-size-changed: * @self: the object emitting the signal. * @renderer: the #VisuElementRenderer that has been changed. * @extent: the new size. * * This signal is emitted each time one of the #VisuElementRenderer * used to represent the #VisuNodeArray has changed its size. * * Since: 3.8 */ _signals[SIZE_SIGNAL] = g_signal_new("element-size-changed", G_TYPE_FROM_INTERFACE(iface), G_SIGNAL_RUN_LAST | G_SIGNAL_NO_RECURSE | G_SIGNAL_NO_HOOKS, 0, NULL, NULL, g_cclosure_marshal_ELEMENT_FLOAT, G_TYPE_NONE, 2, VISU_TYPE_ELEMENT_RENDERER, G_TYPE_FLOAT); /** * VisuNodeArrayRenderer::nodes: * @self: the object emitting the signal. * @nodeIds: (element-type uint): the id of modified nodes. * * This signal is emitted when node rendering properties are changed * because of population change, visibility change, position change... * * Since: 3.8 */ _signals[NODES_SIGNAL] = g_signal_new("nodes", G_TYPE_FROM_INTERFACE(iface), G_SIGNAL_RUN_LAST | G_SIGNAL_NO_RECURSE | G_SIGNAL_NO_HOOKS | G_SIGNAL_DETAILED, 0, NULL, NULL, g_cclosure_marshal_VOID__BOXED, G_TYPE_NONE, 1, G_TYPE_ARRAY); /** * VisuNodeArrayRenderer::data: * * The node_array the renderer refers to. * * Since: 3.8 */ _properties[PROP_NODE_ARRAY] = g_param_spec_object("data", "Data", "data associated to this renderer", VISU_TYPE_NODE_ARRAY, G_PARAM_READWRITE); g_object_interface_install_property(iface, _properties[PROP_NODE_ARRAY]); /** * VisuNodeArrayRenderer::type: * * Store the actual type of the node_array. * * Since: 3.8 */ _properties[PROP_TYPE] = g_param_spec_gtype("type", "Type", "type of 'data'", VISU_TYPE_DATA_LOADABLE, G_PARAM_READABLE); g_object_interface_install_property(iface, _properties[PROP_TYPE]); /** * VisuNodeArrayRenderer::max-element-size: * * Store the maximum size of a rendered element in the node array. * * Since: 3.8 */ _properties[PROP_MAX_NODE_SIZE] = g_param_spec_float("max-element-size", "Maximum element size", "maximum size of anyrendered element", 0.f, G_MAXFLOAT, 1.f, G_PARAM_READABLE); g_object_interface_install_property(iface, _properties[PROP_MAX_NODE_SIZE]); /** * VisuNodeArrayRenderer::colorizer: * * Store the current colorizer. * * Since: 3.8 */ _properties[PROP_COLORIZER] = g_param_spec_object("colorizer", "Colorizer", "current node colorizer.", VISU_TYPE_DATA_COLORIZER, G_PARAM_READWRITE); g_object_interface_install_property(iface, _properties[PROP_COLORIZER]); } /** * visu_node_array_renderer_getMaxElementSize: * @node_array: a #VisuNodeArrayRenderer object. * @n: (out caller-allocates): a location to store an integer. * * Retrieves the maximum rendering size for all #VisuElementRenderer * used by @node_array. @n stores on aoutput the number of * #VisuElementRenderer used by @node_array. * * Since: 3.8 * * Returns: a positive float value. **/ gfloat visu_node_array_renderer_getMaxElementSize(VisuNodeArrayRenderer *node_array, guint *n) { return VISU_NODE_ARRAY_RENDERER_GET_INTERFACE(node_array)->getExtent(node_array, n); } /** * visu_node_array_renderer_get: * @node_array: a #VisuNodeArrayRenderer object. * @element: a #VisuElementRenderer object. * * Retrieve the #VisuElementRenderer that is used by @node_array to represent @element. * * Since: 3.8 * * Returns: (transfer none): the #VisuElementRenderer used for @element. **/ VisuElementRenderer* visu_node_array_renderer_get(VisuNodeArrayRenderer *node_array, const VisuElement *element) { return VISU_NODE_ARRAY_RENDERER_GET_INTERFACE(node_array)->getElement(node_array, element); } /** * visu_node_array_renderer_getNodeArray: * @self: a #VisuNodeArrayRenderer object. * * Retrieve the #VisuNodeArray represented by @self. * * Since: 3.8 * * Returns: (transfer none): the #VisuNodeArray represented by @element. **/ VisuNodeArray* visu_node_array_renderer_getNodeArray(VisuNodeArrayRenderer *self) { return VISU_NODE_ARRAY_RENDERER_GET_INTERFACE(self)->getNodeArray(self); } /** * visu_node_array_renderer_setNodeArray: * @self: a #VisuNodeArrayRenderer object. * @array: (allow-none): a #VisuNodeArray object. * * Changes the #VisuNodeArray that is used as a model for @self. * * Since: 3.8 * * Returns: TRUE if value is actually changed. **/ gboolean visu_node_array_renderer_setNodeArray(VisuNodeArrayRenderer *self, VisuNodeArray *array) { if (!VISU_NODE_ARRAY_RENDERER_GET_INTERFACE(self)->setNodeArray(self, array)) return FALSE; g_object_notify_by_pspec(G_OBJECT(self), _properties[PROP_NODE_ARRAY]); g_object_notify_by_pspec(G_OBJECT(self), _properties[PROP_TYPE]); return TRUE; } /** * visu_node_array_renderer_pushColorizer: * @self: a #VisuNodeArrayRenderer object. * @colorizer: a #VisuDataColorizer object. * * Changes the #VisuDataColorizer of @self. * * Since: 3.8 * * Returns: TRUE if the value is actually changed. **/ gboolean visu_node_array_renderer_pushColorizer(VisuNodeArrayRenderer *self, VisuDataColorizer *colorizer) { gboolean res; res = VISU_NODE_ARRAY_RENDERER_GET_INTERFACE(self)->pushColorizer(self, colorizer); if (res) g_object_notify_by_pspec(G_OBJECT(self), _properties[PROP_COLORIZER]); return res; } /** * visu_node_array_renderer_removeColorizer: * @self: a #VisuNodeArrayRenderer object. * @colorizer: a #VisuDataColorizer object. * * Remove the #VisuDataColorizer from the stack of colorizers of @self. * * Since: 3.8 * * Returns: TRUE if the current colorizer is actually changed. **/ gboolean visu_node_array_renderer_removeColorizer(VisuNodeArrayRenderer *self, VisuDataColorizer *colorizer) { gboolean res; res = VISU_NODE_ARRAY_RENDERER_GET_INTERFACE(self)->removeColorizer(self, colorizer); if (res) g_object_notify_by_pspec(G_OBJECT(self), _properties[PROP_COLORIZER]); return res; } /** * visu_node_array_renderer_getColorizer: * @self: a #VisuNodeArrayRenderer object. * * The renderer @self can use a #VisuDataColorizer object to modify * the pristine color of nodes. * * Since: 3.8 * * Returns: (transfer none): a #VisuDataColorizer object, owned by V_Sim. **/ VisuDataColorizer* visu_node_array_renderer_getColorizer(VisuNodeArrayRenderer *self) { return VISU_NODE_ARRAY_RENDERER_GET_INTERFACE(self)->getColorizer(self); } /** * visu_node_array_renderer_iter_new: * @self: a #VisuNodeArrayRenderer object. * @iter: (out caller-allocates): a location to an uninitialised * #VisuNodeArrayRendererIter object. * @physical: a boolean. * * Creates an iterator to run over all #VisuElementRenderer of * @self. The iterator runs only over physical #VisuElement when * @physical is %TRUE, see visu_element_getPhysical(). * * Since: 3.8 * * Returns: TRUE if the iterator is in a valid state. **/ gboolean visu_node_array_renderer_iter_new(VisuNodeArrayRenderer *self, VisuNodeArrayRendererIter *iter, gboolean physical) { g_return_val_if_fail(VISU_IS_NODE_ARRAY_RENDERER(self) && iter, FALSE); iter->self = self; iter->physical = physical; visu_node_array_iter_new(visu_node_array_renderer_getNodeArray(self), &iter->parent); return visu_node_array_renderer_iter_next(iter); } /** * visu_node_array_renderer_iter_next: * @iter: a #VisuNodeArrayRendererIter object. * * Iterates to the next #VisuElementRenderer object. * * Since: 3.8 * * Returns: TRUE if the iterator is still valid. **/ gboolean visu_node_array_renderer_iter_next(VisuNodeArrayRendererIter *iter) { g_return_val_if_fail(iter, FALSE); if (!iter->parent.init) visu_node_array_iterStart(visu_node_array_renderer_getNodeArray(iter->self), &iter->parent); else visu_node_array_iterNextElement(visu_node_array_renderer_getNodeArray(iter->self), &iter->parent, TRUE); while (iter->physical && iter->parent.element && !visu_element_getPhysical(iter->parent.element)) visu_node_array_iterNextElement(visu_node_array_renderer_getNodeArray(iter->self), &iter->parent, TRUE); iter->element = iter->parent.element; iter->renderer = (VisuElementRenderer*)0; iter->nStoredNodes = 0; if (!iter->element) return FALSE; iter->nStoredNodes = iter->parent.nStoredNodes; iter->renderer = VISU_NODE_ARRAY_RENDERER_GET_INTERFACE(iter->self)->getElement(iter->self, iter->element); return TRUE; } v_sim-3.8.0/src/renderingMethods/iface_nodeArrayRenderer.h000066400000000000000000000125701370110300500236350ustar00rootroot00000000000000/* EXTRAITS DE LA LICENCE Copyright CEA, contributeurs : Damien CALISTE, laboratoire L_Sim, (2016) Adresse mèl : CALISTE, damien P caliste AT cea P fr. Ce logiciel est un programme informatique servant à visualiser des structures atomiques dans un rendu pseudo-3D. Ce logiciel est régi par la licence CeCILL soumise au droit français et respectant les principes de diffusion des logiciels libres. Vous pouvez utiliser, modifier et/ou redistribuer ce programme sous les conditions de la licence CeCILL telle que diffusée par le CEA, le CNRS et l'INRIA sur le site "http://www.cecill.info". Le fait que vous puissiez accéder à cet en-tête signifie que vous avez pris connaissance de la licence CeCILL, et que vous en avez accepté les termes (cf. le fichier Documentation/licence.fr.txt fourni avec ce logiciel). */ /* LICENCE SUM UP Copyright CEA, contributors : Damien CALISTE, laboratoire L_Sim, (2016) E-mail address: CALISTE, damien P caliste AT cea P fr. This software is a computer program whose purpose is to visualize atomic configurations in 3D. This software is governed by the CeCILL license under French law and abiding by the rules of distribution of free software. You can use, modify and/ or redistribute the software under the terms of the CeCILL license as circulated by CEA, CNRS and INRIA at the following URL "http://www.cecill.info". The fact that you are presently reading this means that you have had knowledge of the CeCILL license and that you accept its terms. You can find a copy of this licence shipped with this software at Documentation/licence.en.txt. */ #ifndef IFACE_NODE_ARRAY_RENDERER_H #define IFACE_NODE_ARRAY_RENDERER_H #include #include #include #include "elementRenderer.h" #include G_BEGIN_DECLS /* NodeArrayRenderer interface. */ #define VISU_TYPE_NODE_ARRAY_RENDERER (visu_node_array_renderer_get_type()) #define VISU_NODE_ARRAY_RENDERER(obj) (G_TYPE_CHECK_INSTANCE_CAST((obj), VISU_TYPE_NODE_ARRAY_RENDERER, VisuNodeArrayRenderer)) #define VISU_IS_NODE_ARRAY_RENDERER(obj) (G_TYPE_CHECK_INSTANCE_TYPE((obj), VISU_TYPE_NODE_ARRAY_RENDERER)) #define VISU_NODE_ARRAY_RENDERER_GET_INTERFACE(inst) (G_TYPE_INSTANCE_GET_INTERFACE((inst), VISU_TYPE_NODE_ARRAY_RENDERER, VisuNodeArrayRendererInterface)) typedef struct _VisuNodeArrayRenderer VisuNodeArrayRenderer; /* dummy object */ typedef struct _VisuNodeArrayRendererInterface VisuNodeArrayRendererInterface; /** * VisuNodeArrayRenderer: * * Interface object. * * Since: 3.8 */ /** * VisuNodeArrayRendererInterface: * @parent: its parent. * @getNodeArray: a method to get the #VisuNodeArray this renderer is * working on. * @setNodeArray: a method to change the #VisuNodeArray this renderer * is working on. * @getElement: a method to get the #VisuElementRenderer of the given * #VisuElement. * @getExtent: a method to get the maximum element size. * @pushColorizer: a method used to change the current #VisuNode * colorizer. * @removeColorizer: a method to remove a given colorizer. * @getColorizer: a method used to get the current #VisuNode colorizer. * * Interface for class that can represent #VisuNodeArray. * * Since: 3.8 */ struct _VisuNodeArrayRendererInterface { GTypeInterface parent; VisuNodeArray* (*getNodeArray)(VisuNodeArrayRenderer *self); gboolean (*setNodeArray)(VisuNodeArrayRenderer *self, VisuNodeArray *array); VisuElementRenderer* (*getElement)(VisuNodeArrayRenderer *self, const VisuElement *element); gfloat (*getExtent)(VisuNodeArrayRenderer *self, guint *n); gboolean (*pushColorizer)(VisuNodeArrayRenderer *self, VisuDataColorizer *colorizer); gboolean (*removeColorizer)(VisuNodeArrayRenderer *self, VisuDataColorizer *colorizer); VisuDataColorizer * (*getColorizer)(VisuNodeArrayRenderer *self); }; GType visu_node_array_renderer_get_type (void); VisuNodeArray* visu_node_array_renderer_getNodeArray(VisuNodeArrayRenderer *self); gboolean visu_node_array_renderer_setNodeArray(VisuNodeArrayRenderer *self, VisuNodeArray *array); VisuElementRenderer* visu_node_array_renderer_get(VisuNodeArrayRenderer *node_array, const VisuElement *element); gfloat visu_node_array_renderer_getMaxElementSize(VisuNodeArrayRenderer *node_array, guint *n); gboolean visu_node_array_renderer_pushColorizer(VisuNodeArrayRenderer *self, VisuDataColorizer *colorizer); gboolean visu_node_array_renderer_removeColorizer(VisuNodeArrayRenderer *self, VisuDataColorizer *colorizer); VisuDataColorizer* visu_node_array_renderer_getColorizer(VisuNodeArrayRenderer *self); typedef struct _VisuNodeArrayRendererIter VisuNodeArrayRendererIter; struct _VisuNodeArrayRendererIter { VisuNodeArrayRenderer *self; VisuNodeArrayIter parent; VisuElement *element; VisuElementRenderer *renderer; guint nStoredNodes; /*< private >*/ gboolean physical; }; gboolean visu_node_array_renderer_iter_new(VisuNodeArrayRenderer *self, VisuNodeArrayRendererIter *iter, gboolean physical); gboolean visu_node_array_renderer_iter_next(VisuNodeArrayRendererIter *iter); G_END_DECLS #endif v_sim-3.8.0/src/renderingMethods/spinMethod.c000066400000000000000000000453271370110300500212060ustar00rootroot00000000000000/* EXTRAITS DE LA LICENCE Copyright CEA, contributeurs : Damien CALISTE, laboratoire L_Sim, (2017) Adresse mèl : CALISTE, damien P caliste AT cea P fr. Ce logiciel est un programme informatique servant à visualiser des structures atomiques dans un rendu pseudo-3D. Ce logiciel est régi par la licence CeCILL soumise au droit français et respectant les principes de diffusion des logiciels libres. Vous pouvez utiliser, modifier et/ou redistribuer ce programme sous les conditions de la licence CeCILL telle que diffusée par le CEA, le CNRS et l'INRIA sur le site "http://www.cecill.info". Le fait que vous puissiez accéder à cet en-tête signifie que vous avez pris connaissance de la licence CeCILL, et que vous en avez accepté les termes (cf. le fichier Documentation/licence.fr.txt fourni avec ce logiciel). */ /* LICENCE SUM UP Copyright CEA, contributors : Damien CALISTE, laboratoire L_Sim, (2017) E-mail address: CALISTE, damien P caliste AT cea P fr. This software is a computer program whose purpose is to visualize atomic configurations in 3D. This software is governed by the CeCILL license under French law and abiding by the rules of distribution of free software. You can use, modify and/ or redistribute the software under the terms of the CeCILL license as circulated by CEA, CNRS and INRIA at the following URL "http://www.cecill.info". The fact that you are presently reading this means that you have had knowledge of the CeCILL license and that you accept its terms. You can find a copy of this licence shipped with this software at Documentation/licence.en.txt. */ #include "spinMethod.h" #include #include #include #include /** * SECTION:spinMethod * @short_description: a class defining how a set of spin should be rendered. * * Defines global properties for the rendering of spin data, * like should atomic rendering be used in addition? How to orientate * the colourisation cone? */ #define FLAG_RESOURCES_SPIN "spin_resources" #define DESC_RESOURCES_SPIN "Global or element resource for rendering spin module" #define FLAG_SPIN_CONE_ANGLE "spin_global_color_cone" #define FLAG_SPIN_WHEEL_ANGLE "spin_global_color_wheel" #define FLAG_SPIN_HIDING_MODE "spin_global_hiding_mode" #define FLAG_SPIN_AND_ATOMIC "spin_global_atomic" #define FLAG_SPIN_MODULUS "spin_global_modulus" static gfloat _coneOrientation[2] = {0.f, 0.f}; static gfloat _colorWheel = 0.f; static VisuMethodSpinDrawingPolicy _spinPolicy = VISU_METHOD_SPIN_ALWAYS; static gboolean _spinAndAtomicRendering = FALSE; static VisuMethodSpinModulusPolicy _spinModulusUsage = VISU_METHOD_SPIN_CONSTANT; static const char* policyNameSpin[VISU_METHOD_SPIN_N_MODES + 1] = {"always", "never", "atomic", (const char*)0}; enum { PROP_0, PROP_CONETHETA, PROP_CONEPHI, PROP_COLORWHEEL, PROP_HIDINGMODE, PROP_ATOMIC, PROP_MODULUS, N_PROP, }; static GParamSpec *_properties[N_PROP]; static VisuMethodSpin* _default = NULL; struct _VisuMethodSpinPrivate { gfloat coneOrientation[2]; gfloat colorWheel; VisuMethodSpinDrawingPolicy spinPolicy; gboolean spinAndAtomicRendering; VisuMethodSpinModulusPolicy spinModulusUsage; }; static void visu_method_spin_get_property(GObject* obj, guint property_id, GValue *value, GParamSpec *pspec); static void visu_method_spin_set_property(GObject* obj, guint property_id, const GValue *value, GParamSpec *pspec); /* Local methods. */ static void onEntrySpin(VisuMethodSpin *method, VisuConfigFileEntry *entry, VisuConfigFile *obj); static void exportResourcesRenderingSpin(GString *method, VisuData *dataObj); G_DEFINE_TYPE_WITH_CODE(VisuMethodSpin, visu_method_spin, VISU_TYPE_OBJECT, G_ADD_PRIVATE(VisuMethodSpin)) static void visu_method_spin_class_init(VisuMethodSpinClass *klass) { VisuConfigFileEntry *resourceEntry; /* Connect the overloading methods. */ G_OBJECT_CLASS(klass)->get_property = visu_method_spin_get_property; G_OBJECT_CLASS(klass)->set_property = visu_method_spin_set_property; /** * VisuMethodSpin::cone-theta: * * The theta angle to orientate the colourisation cone. * * Since: 3.8 */ _properties[PROP_CONETHETA] = g_param_spec_float("cone-theta", _("Theta angle"), _("The theta angle to orientate the colourisation cone."), 0, 180, 0, G_PARAM_READWRITE); /** * VisuMethodSpin::cone-phi: * * The phi angle to orientate the colourisation cone. * * Since: 3.8 */ _properties[PROP_CONEPHI] = g_param_spec_float("cone-phi", _("Phi angle"), _("The phi angle to orientate the colourisation cone."), 0, 360, 0, G_PARAM_READWRITE); /** * VisuMethodSpin::cone-omega: * * The omega angle to orientate the colourisation cone. * * Since: 3.8 */ _properties[PROP_COLORWHEEL] = g_param_spec_float("cone-omega", _("Omega angle"), _("The omega angle to orientate the colourisation cone."), 0, 360, 0, G_PARAM_READWRITE); /** * VisuMethodSpin::hiding-mode: * * The hiding policy for spin with a null modulus. * * Since: 3.8 */ _properties[PROP_HIDINGMODE] = g_param_spec_uint("hiding-mode", _("Hiding policy for null modulus"), _("The hiding policy for spin with a null modulus."), 0, VISU_METHOD_SPIN_N_MODES, VISU_METHOD_SPIN_ALWAYS, G_PARAM_READWRITE); /** * VisuMethodSpin::modulus-scaling: * * The scaling policy based on modulus value. * * Since: 3.8 */ _properties[PROP_MODULUS] = g_param_spec_uint("modulus-scaling", _("Scaling of spin depending on modulus value"), _("The scaling policy based on modulus value."), 0, VISU_METHOD_SPIN_N_MODULUS_MODES, VISU_METHOD_SPIN_CONSTANT, G_PARAM_READWRITE); /** * VisuMethodSpin::use-atomic: * * If atomic rendering is used in addition to spin rendering. * * Since: 3.8 */ _properties[PROP_ATOMIC] = g_param_spec_boolean("use-atomic", _("Use atomic rendering"), _("If atomic rendering is used in addition to spin rendering."), FALSE, G_PARAM_READWRITE); g_object_class_install_properties(G_OBJECT_CLASS(klass), N_PROP, _properties); /* Dealing with config files. */ resourceEntry = visu_config_file_addTokenizedEntry(VISU_CONFIG_FILE_RESOURCE, FLAG_RESOURCES_SPIN, DESC_RESOURCES_SPIN, TRUE); visu_config_file_entry_setVersion(resourceEntry, 3.1f); g_signal_connect_swapped(VISU_CONFIG_FILE_RESOURCE, "parsed::" FLAG_RESOURCES_SPIN, G_CALLBACK(onEntrySpin), (gpointer)0); visu_config_file_addExportFunction(VISU_CONFIG_FILE_RESOURCE, exportResourcesRenderingSpin); } static void visu_method_spin_init(VisuMethodSpin *obj) { obj->priv = visu_method_spin_get_instance_private(obj); /* Private method. */ obj->priv->spinPolicy = _spinPolicy; obj->priv->spinAndAtomicRendering = _spinAndAtomicRendering; obj->priv->spinModulusUsage = _spinModulusUsage; obj->priv->coneOrientation[0] = _coneOrientation[0]; obj->priv->coneOrientation[1] = _coneOrientation[1]; obj->priv->colorWheel = _colorWheel; g_signal_connect_object(VISU_CONFIG_FILE_RESOURCE, "parsed::" FLAG_RESOURCES_SPIN, G_CALLBACK(onEntrySpin), obj, G_CONNECT_SWAPPED); } static void visu_method_spin_get_property(GObject* obj, guint property_id, GValue *value, GParamSpec *pspec) { VisuMethodSpin *self = VISU_METHOD_SPIN(obj); switch (property_id) { case PROP_CONETHETA: g_value_set_float(value, self->priv->coneOrientation[0]); break; case PROP_CONEPHI: g_value_set_float(value, self->priv->coneOrientation[1]); break; case PROP_COLORWHEEL: g_value_set_float(value, self->priv->colorWheel); break; case PROP_HIDINGMODE: g_value_set_uint(value, self->priv->spinPolicy); break; case PROP_ATOMIC: g_value_set_boolean(value, self->priv->spinAndAtomicRendering); break; case PROP_MODULUS: g_value_set_uint(value, self->priv->spinModulusUsage); break; default: /* We don't have any other property... */ G_OBJECT_WARN_INVALID_PROPERTY_ID(obj, property_id, pspec); break; } } static void visu_method_spin_set_property(GObject* obj, guint property_id, const GValue *value, GParamSpec *pspec) { VisuMethodSpin *self = VISU_METHOD_SPIN(obj); switch (property_id) { case PROP_CONETHETA: self->priv->coneOrientation[0] = g_value_get_float(value); break; case PROP_CONEPHI: self->priv->coneOrientation[1] = g_value_get_float(value); break; case PROP_COLORWHEEL: self->priv->colorWheel = g_value_get_float(value); break; case PROP_HIDINGMODE: self->priv->spinPolicy = g_value_get_uint(value); break; case PROP_ATOMIC: self->priv->spinAndAtomicRendering = g_value_get_boolean(value); break; case PROP_MODULUS: self->priv->spinModulusUsage = g_value_get_uint(value); break; default: /* We don't have any other property... */ G_OBJECT_WARN_INVALID_PROPERTY_ID(obj, property_id, pspec); break; } } /** * visu_method_spin_new: * * Creates a #VisuMethodSpin object. * * Since: 3.8 * * Returns: a newly allocated #VisuMethodSpin object. **/ VisuMethodSpin* visu_method_spin_new(void) { return g_object_new(VISU_TYPE_METHOD_SPIN, NULL); } /** * visu_method_spin_getDefault: * * Access the default spin method object. * * Since: 3.8 * * Returns: (transfer none): the default spin method object. **/ VisuMethodSpin* visu_method_spin_getDefault(void) { if (!_default) _default = g_object_new(VISU_TYPE_METHOD_SPIN, NULL); return _default; } static void _getOrientationColor(const VisuMethodSpin *method, gfloat rgb[3], const gfloat spinValues[3]) { #ifndef DEG2RAD #define DEG2RAD(x) (0.01745329251994329509 * x) /* pi / 180 * x */ #endif gfloat spherical[3]; float cosCone, sinCone; float matrix_rot_theta[3][3]; float matrix_rot_phi[3][3]; float cartesian[3]; float cartesian_prime[3]; float cartesian_second[3]; float hsl[3]; g_return_if_fail(VISU_IS_METHOD_SPIN(method)); /* We draw a spin shape. */ spherical[0] = 1; spherical[1] = spinValues[TOOL_MATRIX_SPHERICAL_THETA]; spherical[2] = spinValues[TOOL_MATRIX_SPHERICAL_PHI]; cosCone = cos(DEG2RAD(method->priv->coneOrientation[0])); sinCone = sin(DEG2RAD(method->priv->coneOrientation[0])); matrix_rot_theta[0][0] = cosCone; matrix_rot_theta[0][1] = 0; matrix_rot_theta[0][2] = -sinCone; matrix_rot_theta[1][0] = 0; matrix_rot_theta[1][1] = 1; matrix_rot_theta[1][2] = 0; matrix_rot_theta[2][0] = sinCone; matrix_rot_theta[2][1] = 0; matrix_rot_theta[2][2] = cosCone; cosCone = cos(DEG2RAD(-method->priv->coneOrientation[1])); sinCone = sin(DEG2RAD(-method->priv->coneOrientation[1])); matrix_rot_phi[0][0] = cosCone; matrix_rot_phi[0][1] = -sinCone; matrix_rot_phi[0][2] = 0; matrix_rot_phi[1][0] = sinCone; matrix_rot_phi[1][1] = cosCone; matrix_rot_phi[1][2] = 0; matrix_rot_phi[2][0] = 0; matrix_rot_phi[2][1] = 0; matrix_rot_phi[2][2] = 1; cartesian[0] = sin(DEG2RAD(spinValues[TOOL_MATRIX_SPHERICAL_THETA])) * cos(DEG2RAD(spinValues[TOOL_MATRIX_SPHERICAL_PHI])); cartesian[1] = sin(DEG2RAD(spinValues[TOOL_MATRIX_SPHERICAL_THETA])) * sin(DEG2RAD(spinValues[TOOL_MATRIX_SPHERICAL_PHI])); cartesian[2] = cos(DEG2RAD(spinValues[TOOL_MATRIX_SPHERICAL_THETA])); tool_matrix_productVector(cartesian_prime, matrix_rot_phi, cartesian); tool_matrix_productVector(cartesian_second, matrix_rot_theta, cartesian_prime); tool_matrix_cartesianToSpherical(spherical, cartesian_second); hsl[0] = tool_modulo_float(spherical[2] - method->priv->colorWheel, 360.f) / 360.f; hsl[1] = 1.f; hsl[2] = 1.f - spherical[1] / 180.f; tool_color_convertHSLtoRGB(rgb, hsl); } /** * visu_method_spin_getSpinVector: * @method: a #VisuMethodSpin object. * @dataSpin: a #VisuDataSpin object. * @node: a #VisuNode from @dataSpin. * @ratio: (out): the ratio to apply when drawing the spin. * @rgb: (out): a location to store the colour. * @withAtomic: (out): a location to store if atomic rendering is * required. * * Retrieves the spin of @node in spherical coordinates. According to * rendering policy from @method, @ratio, @rgb and @withAtomic will be * set to their respective values. If no spin should be rendered for * @node, %NULL is returned. * * Since: 3.8 * * Returns: three floats representing the spin. **/ const gfloat* visu_method_spin_getSpinVector(const VisuMethodSpin *method, const VisuDataSpin *dataSpin, const VisuNode *node, gfloat *ratio, gfloat rgb[3], gboolean *withAtomic) { const gfloat *spinValues; gfloat globalMax; guint iele; spinValues = visu_node_values_vector_getAtSpherical(visu_data_spin_get(dataSpin), node); if (withAtomic) *withAtomic = (method->priv->spinPolicy == VISU_METHOD_SPIN_ATOMIC_NULL && spinValues[TOOL_MATRIX_SPHERICAL_MODULUS] == 0.f) || method->priv->spinAndAtomicRendering; if (spinValues && (spinValues[TOOL_MATRIX_SPHERICAL_MODULUS] != 0. || method->priv->spinPolicy == VISU_METHOD_SPIN_ALWAYS)) { if (ratio) /* Get the scaling factor for this element. */ switch (method->priv->spinModulusUsage) { case VISU_METHOD_SPIN_PER_TYPE: *ratio = spinValues[TOOL_MATRIX_SPHERICAL_MODULUS] / visu_data_spin_getMaxModulus(dataSpin, node->posElement); break; case VISU_METHOD_SPIN_GLOBAL: globalMax = -G_MAXFLOAT; for (iele = 0; iele < visu_node_array_getNElements(VISU_NODE_ARRAY_CONST(dataSpin), FALSE); iele++) globalMax = MAX(visu_data_spin_getMaxModulus(dataSpin, iele), globalMax); *ratio = spinValues[TOOL_MATRIX_SPHERICAL_MODULUS] / globalMax; break; case VISU_METHOD_SPIN_CONSTANT: *ratio = 1.f; break; default: *ratio = spinValues[TOOL_MATRIX_SPHERICAL_MODULUS]; break; } _getOrientationColor(method, rgb, spinValues); return spinValues; } else return (const gfloat*)0; } /** * visu_method_spin_getHidingPolicyFromName: * @name: (type filename): a string. * @policy: a location. * * In the config file, the hiding policy resource is stored with its name (untranslated). * This method is used to retrieve the id from the name. * * Returns: FALSE if the name does not match any value. */ gboolean visu_method_spin_getHidingPolicyFromName(const char *name, VisuMethodSpinDrawingPolicy *policy) { g_return_val_if_fail(name && policy, FALSE); for (*policy = 0; *policy < VISU_METHOD_SPIN_N_MODES; *policy += 1) if (!g_strcmp0(name, policyNameSpin[*policy])) return TRUE; return FALSE; } static void onEntrySpin(VisuMethodSpin *self, VisuConfigFileEntry *entry, VisuConfigFile *object _U_) { const gchar *label; label = visu_config_file_entry_getLabel(entry); if (!g_strcmp0(label, FLAG_SPIN_CONE_ANGLE)) { float angles[2]; float rg[2] = {0.f, 360.f}; if (!visu_config_file_entry_popTokenAsFloat(entry, 2, angles, rg)) return; if (self) g_object_set(self, "cone-theta", angles[0], "cone-phi", angles[1], NULL); else { _coneOrientation[0] = angles[0]; _coneOrientation[1] = angles[1]; } } else if (!g_strcmp0(label, FLAG_SPIN_WHEEL_ANGLE)) { float angle; float rg[2] = {0.f, 360.f}; if (!visu_config_file_entry_popTokenAsFloat(entry, 1, &angle, rg)) return; if (self) g_object_set(self, "cone-omega", angle, NULL); else _colorWheel = angle; } else if (!g_strcmp0(label, FLAG_SPIN_HIDING_MODE)) { VisuMethodSpinDrawingPolicy modeId; if (!visu_config_file_entry_popTokenAsEnum(entry, &modeId, visu_method_spin_getHidingPolicyFromName)) return; if (self) g_object_set(self, "hiding-mode", modeId, NULL); else _spinPolicy = modeId; } else if (!g_strcmp0(label, FLAG_SPIN_AND_ATOMIC)) { gboolean use; if (!visu_config_file_entry_popTokenAsBoolean(entry, 1, &use)) return; if (self) g_object_set(self, "use-atomic", use, NULL); else _spinAndAtomicRendering = use; } else if (!g_strcmp0(label, FLAG_SPIN_MODULUS)) { int modeId; int rg[2] = {0, VISU_METHOD_SPIN_N_MODULUS_MODES - 1}; if (!visu_config_file_entry_popTokenAsInt(entry, 1, &modeId, rg)) return; if (self) g_object_set(self, "modulus-scaling", modeId, NULL); else _spinModulusUsage = modeId; } else { g_warning(_("Unknown flag '%s', value ignored."), label); } } static void exportResourcesRenderingSpin(GString *method, VisuData* dataObj _U_) { DBG_fprintf(stderr, "Method Spin: exporting resources...\n"); visu_config_file_exportComment(method, DESC_RESOURCES_SPIN); visu_config_file_exportEntry(method, FLAG_RESOURCES_SPIN, FLAG_SPIN_CONE_ANGLE, "%f %f", _coneOrientation[0], _coneOrientation[1]); visu_config_file_exportEntry(method, FLAG_RESOURCES_SPIN, FLAG_SPIN_WHEEL_ANGLE, "%f", _colorWheel); visu_config_file_exportEntry(method, FLAG_RESOURCES_SPIN, FLAG_SPIN_HIDING_MODE, "%s", policyNameSpin[_spinPolicy]); visu_config_file_exportEntry(method, FLAG_RESOURCES_SPIN, FLAG_SPIN_AND_ATOMIC, "%d", _spinAndAtomicRendering); visu_config_file_exportEntry(method, FLAG_RESOURCES_SPIN, FLAG_SPIN_MODULUS, "%d", _spinModulusUsage); DBG_fprintf(stderr, "Method Spin: resources succesfully exported\n"); } v_sim-3.8.0/src/renderingMethods/spinMethod.h000066400000000000000000000126611370110300500212060ustar00rootroot00000000000000/* EXTRAITS DE LA LICENCE Copyright CEA, contributeurs : Damien CALISTE, laboratoire L_Sim, (2017) Adresse mèl : CALISTE, damien P caliste AT cea P fr. Ce logiciel est un programme informatique servant à visualiser des structures atomiques dans un rendu pseudo-3D. Ce logiciel est régi par la licence CeCILL soumise au droit français et respectant les principes de diffusion des logiciels libres. Vous pouvez utiliser, modifier et/ou redistribuer ce programme sous les conditions de la licence CeCILL telle que diffusée par le CEA, le CNRS et l'INRIA sur le site "http://www.cecill.info". Le fait que vous puissiez accéder à cet en-tête signifie que vous avez pris connaissance de la licence CeCILL, et que vous en avez accepté les termes (cf. le fichier Documentation/licence.fr.txt fourni avec ce logiciel). */ /* LICENCE SUM UP Copyright CEA, contributors : Damien CALISTE, laboratoire L_Sim, (2017) E-mail address: CALISTE, damien P caliste AT cea P fr. This software is a computer program whose purpose is to visualize atomic configurations in 3D. This software is governed by the CeCILL license under French law and abiding by the rules of distribution of free software. You can use, modify and/ or redistribute the software under the terms of the CeCILL license as circulated by CEA, CNRS and INRIA at the following URL "http://www.cecill.info". The fact that you are presently reading this means that you have had knowledge of the CeCILL license and that you accept its terms. You can find a copy of this licence shipped with this software at Documentation/licence.en.txt. */ #ifndef VISU_METHODSPIN_H #define VISU_METHODSPIN_H #include #include #include #include G_BEGIN_DECLS /** * VISU_TYPE_METHOD_SPIN: * * return the type of #VisuMethodSpin. */ #define VISU_TYPE_METHOD_SPIN (visu_method_spin_get_type ()) /** * VISU_METHOD_SPIN: * @obj: a #GObject to cast. * * Cast the given @obj into #VisuMethodSpin type. */ #define VISU_METHOD_SPIN(obj) (G_TYPE_CHECK_INSTANCE_CAST(obj, VISU_TYPE_METHOD_SPIN, VisuMethodSpin)) /** * VISU_METHOD_SPIN_CLASS: * @klass: a #GObjectClass to cast. * * Cast the given @klass into #VisuMethodSpinClass. */ #define VISU_METHOD_SPIN_CLASS(klass) (G_TYPE_CHECK_CLASS_CAST(klass, VISU_TYPE_METHOD_SPIN, VisuMethodSpinClass)) /** * VISU_IS_METHOD_SPIN: * @obj: a #GObject to test. * * Test if the given @ogj is of the type of #VisuMethodSpin object. */ #define VISU_IS_METHOD_SPIN(obj) (G_TYPE_CHECK_INSTANCE_TYPE(obj, VISU_TYPE_METHOD_SPIN)) /** * VISU_IS_METHOD_SPIN_CLASS: * @klass: a #GObjectClass to test. * * Test if the given @klass is of the type of #VisuMethodSpinClass class. */ #define VISU_IS_METHOD_SPIN_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE(klass, VISU_TYPE_METHOD_SPIN)) /** * VISU_METHOD_SPIN_GET_CLASS: * @obj: a #GObject to get the class of. * * It returns the class of the given @obj. */ #define VISU_METHOD_SPIN_GET_CLASS(obj) (G_TYPE_INSTANCE_GET_CLASS(obj, VISU_TYPE_METHOD_SPIN, VisuMethodSpinClass)) typedef struct _VisuMethodSpinPrivate VisuMethodSpinPrivate; typedef struct _VisuMethodSpin VisuMethodSpin; /** * VisuMethodSpin: * * Structure used to define #VisuMethodSpin objects. * * Since: 3.8 */ struct _VisuMethodSpin { VisuObject parent; VisuMethodSpinPrivate *priv; }; /** * VisuMethodSpinClass: * @parent: the parent class. * * A short way to identify #_VisuMethodSpinClass structure. */ typedef struct _VisuMethodSpinClass VisuMethodSpinClass; struct _VisuMethodSpinClass { VisuObjectClass parent; }; /** * visu_method_spin_get_type: * * This method returns the type of #VisuMethodSpin, use VISU_TYPE_METHOD_SPIN instead. * * Returns: the type of #VisuMethodSpin. */ GType visu_method_spin_get_type(void); /** * VisuMethodSpinDrawingPolicy: * @VISU_METHOD_SPIN_ALWAYS: Arrows are drawn whatever the modulus value. * @VISU_METHOD_SPIN_HIDE_NULL: Spin with a null modulus are hidden. * @VISU_METHOD_SPIN_ATOMIC_NULL: Follow atomic method for null modulus. * @VISU_METHOD_SPIN_N_MODES: a flag to count the number of modes. * * Different policy to render the spin when the modulus is null. This * policy is applied for all #VisuElement. */ typedef enum { VISU_METHOD_SPIN_ALWAYS, VISU_METHOD_SPIN_HIDE_NULL, VISU_METHOD_SPIN_ATOMIC_NULL, VISU_METHOD_SPIN_N_MODES } VisuMethodSpinDrawingPolicy; /** * VisuMethodSpinModulusPolicy: * @VISU_METHOD_SPIN_CONSTANT: arrows have all the same size, whatever the * modulus value. * @VISU_METHOD_SPIN_PER_TYPE: arrows are scaled per node type. * @VISU_METHOD_SPIN_GLOBAL: arrows are scaled globaly. * @VISU_METHOD_SPIN_N_MODULUS_MODES: a flag to count the number of modes. * * Different policy to render the spin depending on the modulus. */ typedef enum { VISU_METHOD_SPIN_CONSTANT, VISU_METHOD_SPIN_PER_TYPE, VISU_METHOD_SPIN_GLOBAL, VISU_METHOD_SPIN_N_MODULUS_MODES } VisuMethodSpinModulusPolicy; VisuMethodSpin* visu_method_spin_new(void); VisuMethodSpin* visu_method_spin_getDefault(void); const gfloat* visu_method_spin_getSpinVector(const VisuMethodSpin *method, const VisuDataSpin *dataSpin, const VisuNode *node, gfloat *ratio, gfloat rgb[3], gboolean *withAtomic); G_END_DECLS #endif v_sim-3.8.0/src/support.c000066400000000000000000000071521370110300500153010ustar00rootroot00000000000000/* * DO NOT EDIT THIS FILE - it is generated by Glade. */ #ifdef HAVE_CONFIG_H # include #endif #include #include #include #include #include #include #include "support.h" GtkWidget* lookup_widget (GtkWidget *widget, const gchar *widget_name) { GtkWidget *parent, *found_widget; for (;;) { if (GTK_IS_MENU (widget)) parent = gtk_menu_get_attach_widget (GTK_MENU (widget)); else parent = gtk_widget_get_parent(widget); if (!parent) parent = (GtkWidget*) g_object_get_data (G_OBJECT (widget), "GladeParentKey"); if (parent == NULL) break; widget = parent; } found_widget = (GtkWidget*) g_object_get_data (G_OBJECT (widget), widget_name); if (!found_widget) g_warning ("Widget not found: %s", widget_name); return found_widget; } static GList *pixmaps_directories = NULL; /* Use this function to set the directory containing installed pixmaps. */ void add_pixmap_directory (const gchar *directory) { pixmaps_directories = g_list_prepend (pixmaps_directories, g_strdup (directory)); } /* This is an internally used function to find pixmap files. */ static gchar* find_pixmap_file (const gchar *filename) { GList *elem; /* We step through each of the pixmaps directory to find it. */ elem = pixmaps_directories; while (elem) { gchar *pathname = g_strdup_printf ("%s%s%s", (gchar*)elem->data, G_DIR_SEPARATOR_S, filename); if (g_file_test (pathname, G_FILE_TEST_EXISTS)) return pathname; g_free (pathname); elem = elem->next; } return NULL; } /* This is an internally used function to create pixmaps. */ GtkWidget* create_pixmap (GtkWidget *widget _U_, const gchar *filename) { gchar *pathname = NULL; GtkWidget *pixmap; if (!filename || !filename[0]) return gtk_image_new (); pathname = find_pixmap_file (filename); if (!pathname) { g_warning (_("Couldn't find pixmap file: %s"), filename); return gtk_image_new (); } pixmap = gtk_image_new_from_file (pathname); g_free (pathname); return pixmap; } /* This is an internally used function to create pixmaps. */ GdkPixbuf* create_pixbuf (const gchar *filename) { gchar *pathname = NULL; GdkPixbuf *pixbuf; GError *error = NULL; if (!filename || !filename[0]) return NULL; pathname = find_pixmap_file (filename); if (!pathname) { g_warning (_("Couldn't find pixmap file: %s"), filename); return NULL; } pixbuf = gdk_pixbuf_new_from_file (pathname, &error); if (!pixbuf) { fprintf (stderr, "Failed to load pixbuf file: %s: %s\n", pathname, error->message); g_error_free (error); } g_free (pathname); return pixbuf; } /* This is used to set ATK action descriptions. */ void glade_set_atk_action_description (AtkAction *action, const gchar *action_name, const gchar *description) { gint n_actions, i; n_actions = atk_action_get_n_actions (action); for (i = 0; i < n_actions; i++) { if (!strcmp (atk_action_get_name (action, i), action_name)) atk_action_set_description (action, i, description); } } v_sim-3.8.0/src/support.h000066400000000000000000000176451370110300500153160ustar00rootroot00000000000000/* * DO NOT EDIT THIS FILE - it is generated by Glade. */ #ifdef HAVE_CONFIG_H # include #endif #include /* * Standard gettext macros. */ #ifdef ENABLE_NLS # include # undef _ # define _(String) dgettext (PACKAGE, String) # define Q_(String) g_strip_context ((String), gettext (String)) # ifdef gettext_noop # define N_(String) gettext_noop (String) # else # define N_(String) (String) # endif #else # define textdomain(String) (String) # define gettext(String) (String) # define dgettext(Domain,Message) (Message) # define dcgettext(Domain,Message,Type) (Message) # define bindtextdomain(Domain,Directory) (Domain) # define _(String) (String) # define Q_(String) g_strip_context ((String), (String)) # define N_(String) (String) #endif #if GTK_MAJOR_VERSION < 3 || (GTK_MAJOR_VERSION == 3 && GTK_MINOR_VERSION < 12) #define gtk_widget_set_margin_start(W, M) gtk_widget_set_margin_left(W, M) #define gtk_widget_set_margin_end(W, M) gtk_widget_set_margin_right(W, M) #endif #if GTK_MAJOR_VERSION < 3 || (GTK_MAJOR_VERSION == 3 && GTK_MINOR_VERSION < 4) #define GTK_GRID(W) GTK_TABLE(W) #define gtk_grid_new() gtk_table_new(10, 10, FALSE) #define gtk_grid_attach(G, W, L, T, W, H) gtk_table_attach(G, W, L, L + W, T, T + H, 0, 0, 0, 0) #endif #if GTK_MAJOR_VERSION < 3 || (GTK_MAJOR_VERSION == 3 && GTK_MINOR_VERSION < 20) #define gtk_widget_set_focus_on_click(A, B) gtk_button_set_focus_on_click(GTK_BUTTON(A), B) #endif #if GTK_MAJOR_VERSION == 3 && GTK_MINOR_VERSION < 15 #define gtk_label_set_xalign(A, B) gtk_misc_set_alignment(GTK_MISC(A), B, 0.5) #define gtk_label_set_yalign(A, B) gtk_misc_set_alignment(GTK_MISC(A), 0.5, B) #define gtk_button_new_from_icon_name(A, B) gtk_button_new_with_label(A) #endif #if GTK_MAJOR_VERSION == 3 && GTK_MINOR_VERSION > 9 #define TOOL_ICON_CANCEL _("_Cancel") #define TOOL_ICON_SAVE _("_Save") #define TOOL_ICON_OPEN _("_Open") #define TOOL_ICON_CLOSE _("_Close") #else #define TOOL_ICON_CANCEL GTK_STOCK_CANCEL #define TOOL_ICON_SAVE GTK_STOCK_SAVE #define TOOL_ICON_OPEN GTK_STOCK_OPEN #define TOOL_ICON_CLOSE GTK_STOCK_CLOSE #endif #if GTK_MAJOR_VERSION == 3 && GTK_MINOR_VERSION < 4 #define GTK_GRID(A) GTK_TABLE(A) #define gtk_grid_new() gtk_table_new(1, 1, FALSE) #define tool_grid_resize(A, B, C) gtk_table_resize(GTK_TABLE(A), B, C) #define gtk_grid_attach(A, B, X, Y, W, H) gtk_table_attach(A, B, X, X+W, Y, Y+H, 0, 0, 0, 0) #else #define tool_grid_resize(A, B, C) #endif #if GTK_MAJOR_VERSION == 3 && GTK_MINOR_VERSION < 2 #endif #if GTK_MAJOR_VERSION == 3 && GTK_MINOR_VERSION > 2 #define gtk_hbox_new(A, B) gtk_box_new(GTK_ORIENTATION_HORIZONTAL, B) #define gtk_vbox_new(A, B) gtk_box_new(GTK_ORIENTATION_VERTICAL, B) #define gtk_hseparator_new() gtk_separator_new(GTK_ORIENTATION_HORIZONTAL) #define gtk_vseparator_new() gtk_separator_new(GTK_ORIENTATION_VERTICAL) #define gtk_hscale_new_with_range(A, B, C) gtk_scale_new_with_range(GTK_ORIENTATION_HORIZONTAL, A, B, C) #define gtk_vscale_new_with_range(A, B, C) gtk_scale_new_with_range(GTK_ORIENTATION_VERTICAL, A, B, C) #define gtk_hpaned_new() gtk_paned_new(GTK_ORIENTATION_HORIZONTAL) #define gtk_vpaned_new() gtk_paned_new(GTK_ORIENTATION_VERTICAL) #endif #if GTK_MAJOR_VERSION < 3 #define cairo_region_t GdkRegion #define cairo_region_destroy(Obj) gdk_region_destroy(Obj) #define gdk_window_get_clip_region(Obj) gdk_drawable_get_clip_region(GDK_DRAWABLE(Obj)) #endif #if GTK_MAJOR_VERSION == 2 && GTK_MINOR_VERSION < 26 && GTK_MINOR_VERSION > 23 #define gtk_combo_box_text_append(Obj, id, tt) gtk_combo_box_text_append_text(Obj, tt) #define gtk_combo_box_text_remove(Obj, id) gtk_combo_box_remove_text(GTK_COMBO_BOX(Obj), id) #endif #if GTK_MAJOR_VERSION == 2 && GTK_MINOR_VERSION < 24 #define GTK_COMBO_BOX_TEXT(Obj) GTK_COMBO_BOX(Obj) #define gtk_combo_box_text_new() gtk_combo_box_new_text() #define gtk_combo_box_text_new_with_entry() gtk_combo_box_entry_new_text() #define gtk_combo_box_text_append_text(Obj, tt) gtk_combo_box_append_text(Obj, tt) #define gtk_combo_box_text_append(Obj, id, tt) gtk_combo_box_append_text(Obj, tt) #define gtk_combo_box_text_remove(Obj, id) gtk_combo_box_remove_text(GTK_COMBO_BOX(Obj), id) #define gdk_window_get_screen(Obj) gdk_drawable_get_screen(Obj) #endif #if GTK_MAJOR_VERSION == 2 && GTK_MINOR_VERSION < 22 #define gtk_dialog_get_content_area(Obj) (Obj->vbox) #define gtk_dialog_get_action_area(Obj) (Obj->action_area) #define gtk_color_selection_dialog_get_color_selection(Obj) (Obj->colorsel) #define GDK_KEY_Home GDK_Home #define GDK_KEY_0 GDK_0 #define GDK_KEY_1 GDK_1 #define GDK_KEY_2 GDK_2 #define GDK_KEY_3 GDK_3 #define GDK_KEY_4 GDK_4 #define GDK_KEY_5 GDK_5 #define GDK_KEY_6 GDK_6 #define GDK_KEY_7 GDK_7 #define GDK_KEY_8 GDK_8 #define GDK_KEY_9 GDK_9 #define GDK_KEY_f GDK_f #define GDK_KEY_F GDK_F #define GDK_KEY_i GDK_i #define GDK_KEY_I GDK_I #define GDK_KEY_n GDK_n #define GDK_KEY_o GDK_o #define GDK_KEY_p GDK_p #define GDK_KEY_r GDK_r #define GDK_KEY_R GDK_R #define GDK_KEY_s GDK_s #define GDK_KEY_S GDK_S #define GDK_KEY_v GDK_v #define GDK_KEY_V GDK_V #define GDK_KEY_Menu GDK_Menu #define GDK_KEY_Escape GDK_Escape #define GDK_KEY_space GDK_space #define GDK_KEY_Page_Up GDK_Page_Up #define GDK_KEY_Page_Down GDK_Page_Down #define GDK_KEY_Up GDK_Up #define GDK_KEY_Down GDK_Down #define GDK_KEY_Right GDK_Right #define GDK_KEY_Left GDK_Left #define GDK_KEY_Shift_L GDK_Shift_L #define GDK_KEY_Shift_R GDK_Shift_R #define GDK_KEY_Delete GDK_Delete #define GDK_KEY_BackSpace GDK_BackSpace #define gtk_widget_is_drawable(Obj) GDK_IS_DRAWABLE(Obj->window) #define gtk_widget_get_window(Obj) (Obj->window) #define gtk_widget_get_visible(Obj) GTK_WIDGET_VISIBLE(Obj) #define gtk_widget_get_allocation(Obj, alloc) {(alloc)->x = Obj->allocation.x; (alloc)->y = Obj->allocation.y; (alloc)->width = Obj->allocation.width; (alloc)->height = Obj->allocation.height;} #define gtk_widget_set_can_default(Obj, test) {if (test) {GTK_WIDGET_SET_FLAGS(Obj, GTK_CAN_DEFAULT);};} #define gtk_widget_set_can_focus(Obj, test) {if (test) {GTK_WIDGET_SET_FLAGS(Obj, GTK_CAN_FOCUS);};} #define gtk_widget_set_window(Obj, win) {Obj->window = win;} #define gtk_widget_set_realized(Obj, test) {if (test) {GTK_WIDGET_SET_FLAGS(Obj, GTK_REALIZED);};} #define gtk_widget_set_has_window(Obj, test) {} #endif #if GTK_MAJOR_VERSION == 2 && GTK_MINOR_VERSION < 20 #define gtk_widget_style_attach(Obj) {Obj->style = gtk_style_attach(Obj->style, Obj->window);} #define gtk_widget_get_mapped(Obj) GTK_WIDGET_MAPPED(Obj) #endif #if GTK_MAJOR_VERSION == 2 && GTK_MINOR_VERSION < 12 #define gtk_widget_set_tooltip_text(Obj, tt) gtk_tooltips_set_tip(tooltips, Obj, tt, NULL) #define gtk_tool_item_set_tooltip_text(Obj, tt) gtk_tool_item_set_tooltip(Obj, tooltips, tt, NULL) #endif #if GTK_MAJOR_VERSION == 2 && GTK_MINOR_VERSION < 5 #define GTK_STOCK_EDIT GTK_STOCK_PROPERTIES #endif /* * Public Functions. */ /* * This function returns a widget in a component created by Glade. * Call it with the toplevel widget in the component (i.e. a window/dialog), * or alternatively any widget in the component, and the name of the widget * you want returned. */ GtkWidget* lookup_widget (GtkWidget *widget, const gchar *widget_name); /* Use this function to set the directory containing installed pixmaps. */ void add_pixmap_directory (const gchar *directory); /* * Private Functions. */ /* This is used to create the pixmaps used in the interface. */ GtkWidget* create_pixmap (GtkWidget *widget, const gchar *filename); /* This is used to create the pixbufs used in the interface. */ GdkPixbuf* create_pixbuf (const gchar *filename); /* This is used to set ATK action descriptions. */ void glade_set_atk_action_description (AtkAction *action, const gchar *action_name, const gchar *description); v_sim-3.8.0/src/uiElements/000077500000000000000000000000001370110300500155265ustar00rootroot00000000000000v_sim-3.8.0/src/uiElements/ui_atomic.c000066400000000000000000000304321370110300500176450ustar00rootroot00000000000000/* EXTRAITS DE LA LICENCE Copyright CEA, contributeurs : Damien CALISTE, laboratoire L_Sim, (2016) Adresse mèl : CALISTE, damien P caliste AT cea P fr. Ce logiciel est un programme informatique servant à visualiser des structures atomiques dans un rendu pseudo-3D. Ce logiciel est régi par la licence CeCILL soumise au droit français et respectant les principes de diffusion des logiciels libres. Vous pouvez utiliser, modifier et/ou redistribuer ce programme sous les conditions de la licence CeCILL telle que diffusée par le CEA, le CNRS et l'INRIA sur le site "http://www.cecill.info". Le fait que vous puissiez accéder à cet en-tête signifie que vous avez pris connaissance de la licence CeCILL, et que vous en avez accepté les termes (cf. le fichier Documentation/licence.fr.txt fourni avec ce logiciel). */ /* LICENCE SUM UP Copyright CEA, contributors : Damien CALISTE, laboratoire L_Sim, (2016) E-mail address: CALISTE, damien P caliste AT cea P fr. This software is a computer program whose purpose is to visualize atomic configurations in 3D. This software is governed by the CeCILL license under French law and abiding by the rules of distribution of free software. You can use, modify and/ or redistribute the software under the terms of the CeCILL license as circulated by CEA, CNRS and INRIA at the following URL "http://www.cecill.info". The fact that you are presently reading this means that you have had knowledge of the CeCILL license and that you accept its terms. You can find a copy of this licence shipped with this software at Documentation/licence.en.txt. */ #include "ui_atomic.h" #include #include #include /** * SECTION:ui_atomic * @short_description: Defines a widget to setup a atomic. * * A set of widgets to setup the rendring of a atomic. */ /** * VisuUiAtomicClass: * @parent: the parent class; * * A short way to identify #_VisuUiAtomicClass structure. * * Since: 3.8 */ /** * VisuUiAtomic: * * An opaque structure. * * Since: 3.8 */ /** * VisuUiAtomicPrivate: * * Private fields for #VisuUiAtomic objects. * * Since: 3.8 */ struct _VisuUiAtomicPrivate { gboolean dispose_has_run; GtkWidget *spinRadius; GtkWidget *entryShape; GtkWidget *spinRatio; GtkWidget *spinPhi; GtkWidget *spinTheta; VisuNodeArrayRenderer *renderer; VisuElementAtomic *model; gulong units_sig; GBinding *radius_bind, *shape_bind, *ratio_bind, *phi_bind, *theta_bind; GList *targets; }; static void visu_ui_atomic_finalize(GObject* obj); static void visu_ui_atomic_dispose(GObject* obj); /* Local callbacks. */ static gboolean formatRadius(GtkSpinButton *button, const VisuUiAtomic *atomic); G_DEFINE_TYPE_WITH_CODE(VisuUiAtomic, visu_ui_atomic, GTK_TYPE_BOX, G_ADD_PRIVATE(VisuUiAtomic)) static void visu_ui_atomic_class_init(VisuUiAtomicClass *klass) { DBG_fprintf(stderr, "Ui Atomic: creating the class of the widget.\n"); DBG_fprintf(stderr, " - adding new signals ;\n"); /* Connect freeing methods. */ G_OBJECT_CLASS(klass)->dispose = visu_ui_atomic_dispose; G_OBJECT_CLASS(klass)->finalize = visu_ui_atomic_finalize; } static void visu_ui_atomic_dispose(GObject *obj) { VisuUiAtomic *self = VISU_UI_ATOMIC(obj); DBG_fprintf(stderr, "Ui Atomic: dispose object %p.\n", (gpointer)obj); if (self->priv->dispose_has_run) return; self->priv->dispose_has_run = TRUE; visu_ui_atomic_bind(self, (GList*)0); /* Chain up to the parent class */ G_OBJECT_CLASS(visu_ui_atomic_parent_class)->dispose(obj); } static void visu_ui_atomic_finalize(GObject *obj) { g_return_if_fail(obj); DBG_fprintf(stderr, "Ui Atomic: finalize object %p.\n", (gpointer)obj); /* Chain up to the parent class */ G_OBJECT_CLASS(visu_ui_atomic_parent_class)->finalize(obj); DBG_fprintf(stderr, " | freeing ... OK.\n"); } static void visu_ui_atomic_init(VisuUiAtomic *obj) { GtkWidget *label, *hbox; const char **names, **ids; int i; #if GTK_MAJOR_VERSION == 2 && GTK_MINOR_VERSION < 12 GtkTooltips *tooltips; tooltips = gtk_tooltips_new (); #endif DBG_fprintf(stderr, "Extension Atomic: initializing a new object (%p).\n", (gpointer)obj); gtk_orientable_set_orientation(GTK_ORIENTABLE(obj), GTK_ORIENTATION_VERTICAL); obj->priv = visu_ui_atomic_get_instance_private(obj); obj->priv->dispose_has_run = FALSE; obj->priv->renderer = (VisuNodeArrayRenderer*)0; obj->priv->model = (VisuElementAtomic*)0; obj->priv->targets = (GList*)0; gtk_widget_set_sensitive(GTK_WIDGET(obj), FALSE); hbox = gtk_hbox_new(FALSE, 0); gtk_box_pack_start(GTK_BOX(obj), hbox, FALSE, FALSE, 5); label = gtk_label_new(""); gtk_label_set_text(GTK_LABEL(label), _("Radius:")); gtk_box_pack_start(GTK_BOX(hbox), label, FALSE, FALSE, 0); obj->priv->spinRadius = gtk_spin_button_new_with_range(0.001, 999., 0.05); g_signal_connect(obj->priv->spinRadius, "output", G_CALLBACK(formatRadius), obj); gtk_spin_button_set_numeric(GTK_SPIN_BUTTON(obj->priv->spinRadius), FALSE); gtk_entry_set_width_chars(GTK_ENTRY(obj->priv->spinRadius), 10); gtk_box_pack_start(GTK_BOX(hbox), obj->priv->spinRadius, FALSE,FALSE, 3); label = gtk_label_new(_("Shape: ")); gtk_box_pack_start(GTK_BOX(hbox), label, TRUE, TRUE, 1); gtk_label_set_xalign(GTK_LABEL(label), 1.); obj->priv->entryShape = gtk_combo_box_text_new(); names = visu_element_atomic_getShapeNames(TRUE); ids = visu_element_atomic_getShapeNames(FALSE); for (i = 0; names[i] && ids[i]; i++) gtk_combo_box_text_append(GTK_COMBO_BOX_TEXT(obj->priv->entryShape), ids[i], names[i]); gtk_combo_box_set_active(GTK_COMBO_BOX(obj->priv->entryShape), 0); gtk_box_pack_start(GTK_BOX(hbox), obj->priv->entryShape, FALSE, FALSE, 0); /* Set widgets for the elipsoid parameters. */ label = gtk_label_new(""); gtk_label_set_markup(GTK_LABEL(label), _("Parameters for elipsoid shape")); gtk_box_pack_start(GTK_BOX(obj), label, FALSE, FALSE, 5); gtk_label_set_xalign(GTK_LABEL(label), 0.); hbox = gtk_hbox_new(FALSE, 0); gtk_box_pack_start(GTK_BOX(obj), hbox, FALSE, FALSE, 2); label = gtk_label_new(_("Ratio: ")); gtk_box_pack_start(GTK_BOX(hbox), label, FALSE, FALSE, 0); gtk_label_set_xalign(GTK_LABEL(label), 0.); gtk_widget_set_margin_start(label, 10); obj->priv->spinRatio = gtk_spin_button_new_with_range(1., 10., 0.1); gtk_box_pack_end(GTK_BOX(hbox), obj->priv->spinRatio, FALSE, FALSE, 0); hbox = gtk_hbox_new(FALSE, 0); gtk_box_pack_start(GTK_BOX(obj), hbox, FALSE, FALSE, 2); label = gtk_label_new(_("Phi: ")); gtk_box_pack_start(GTK_BOX(hbox), label, FALSE, FALSE, 0); gtk_label_set_xalign(GTK_LABEL(label), 0.); gtk_widget_set_margin_start(label, 10); obj->priv->spinPhi = gtk_spin_button_new_with_range(-180., 180., 1.); gtk_box_pack_end(GTK_BOX(hbox), obj->priv->spinPhi, FALSE, FALSE, 0); hbox = gtk_hbox_new(FALSE, 0); gtk_box_pack_start(GTK_BOX(obj), hbox, FALSE, FALSE, 2); label = gtk_label_new(_("Theta: ")); gtk_box_pack_start(GTK_BOX(hbox), label, FALSE, FALSE, 0); gtk_label_set_xalign(GTK_LABEL(label), 0.); gtk_widget_set_margin_start(label, 10); obj->priv->spinTheta = gtk_spin_button_new_with_range(-180., 180., 1.); gtk_box_pack_end(GTK_BOX(hbox), obj->priv->spinTheta, FALSE, FALSE, 0); } /** * visu_ui_atomic_new: * @renderer: a #VisuNodeArrayRenderer object. * * Creates a new #VisuUiAtomic to allow to setup atomic rendering characteristics. * * Since: 3.8 * * Returns: a pointer to the newly created widget. */ GtkWidget* visu_ui_atomic_new(VisuNodeArrayRenderer *renderer) { VisuUiAtomic *atomic; DBG_fprintf(stderr,"Ui Atomic: new object.\n"); atomic = VISU_UI_ATOMIC(g_object_new(VISU_TYPE_UI_ATOMIC, NULL)); atomic->priv->renderer = renderer; return GTK_WIDGET(atomic); } static gboolean formatRadius(GtkSpinButton *button, const VisuUiAtomic *atomic) { gchar *str; ToolUnits units; if (!atomic->priv->model) return FALSE; units = visu_element_atomic_getUnits(atomic->priv->model); if (units == TOOL_UNITS_UNDEFINED) str = g_strdup_printf("%0.3f", gtk_spin_button_get_value(button)); else str = g_strdup_printf("%0.3f %s", gtk_spin_button_get_value(button), tool_physic_getUnitLabel(units)); gtk_entry_set_text(GTK_ENTRY(button), str); g_free(str); return TRUE; } static gboolean setForAll(GBinding *bind, const GValue *source_value, GValue *target_value, gpointer data) { VisuUiAtomic *atomic = VISU_UI_ATOMIC(data); GList *lst; for (lst = atomic->priv->targets; lst; lst = g_list_next(lst)) if (lst->data != atomic->priv->model) g_object_set_property(lst->data, g_binding_get_source_property(bind), source_value); return g_value_transform(source_value, target_value); } static void _bind(VisuUiAtomic *atomic, VisuElementAtomic *element) { if (atomic->priv->model == element) return; if (atomic->priv->model) { g_object_unref(atomic->priv->radius_bind); g_object_unref(atomic->priv->shape_bind); g_object_unref(atomic->priv->ratio_bind); g_object_unref(atomic->priv->phi_bind); g_object_unref(atomic->priv->theta_bind); g_signal_handler_disconnect(atomic->priv->model, atomic->priv->units_sig); g_object_unref(atomic->priv->model); } atomic->priv->model = element; if (element) { g_object_ref(element); atomic->priv->radius_bind = g_object_bind_property_full(element, "radius", atomic->priv->spinRadius, "value", G_BINDING_SYNC_CREATE | G_BINDING_BIDIRECTIONAL, NULL, setForAll, atomic, (GDestroyNotify)0); atomic->priv->shape_bind = g_object_bind_property_full(element, "shape", atomic->priv->entryShape, "active", G_BINDING_SYNC_CREATE | G_BINDING_BIDIRECTIONAL, NULL, setForAll, atomic, (GDestroyNotify)0); atomic->priv->ratio_bind = g_object_bind_property_full(element, "elipsoid-ratio", atomic->priv->spinRatio, "value", G_BINDING_SYNC_CREATE | G_BINDING_BIDIRECTIONAL, NULL, setForAll, atomic, (GDestroyNotify)0); atomic->priv->phi_bind = g_object_bind_property_full(element, "elipsoid-angle-phi", atomic->priv->spinPhi, "value", G_BINDING_SYNC_CREATE | G_BINDING_BIDIRECTIONAL, NULL, setForAll, atomic, (GDestroyNotify)0); atomic->priv->theta_bind = g_object_bind_property_full(element, "elipsoid-angle-theta", atomic->priv->spinTheta, "value", G_BINDING_SYNC_CREATE | G_BINDING_BIDIRECTIONAL, NULL, setForAll, atomic, (GDestroyNotify)0); atomic->priv->units_sig = g_signal_connect_swapped(element, "notify::units", G_CALLBACK(gtk_spin_button_update), atomic->priv->spinRadius); } } /** * visu_ui_atomic_bind: * @atomic: a #VisuUiAtomic object. * @eleList: (element-type VisuElement): a list of #VisuElement. * * Use the list @eleList to be handled by @elements. Any change in * @elements will be applied to the #VisuElementRenderer corresponding * to each #VisuElement of @eleList. * * Since: 3.8 **/ void visu_ui_atomic_bind(VisuUiAtomic *atomic, GList *eleList) { GList *lst; g_return_if_fail(VISU_IS_UI_ATOMIC(atomic)); g_return_if_fail(atomic->priv->renderer); if (!eleList) _bind(atomic, (VisuElementAtomic*)0); else { if (!atomic->priv->model || !g_list_find(eleList, visu_element_renderer_getElement(VISU_ELEMENT_RENDERER(atomic->priv->model)))) _bind(atomic, VISU_ELEMENT_ATOMIC(visu_node_array_renderer_get(atomic->priv->renderer, VISU_ELEMENT(eleList->data)))); } if (atomic->priv->targets) g_list_free(atomic->priv->targets); atomic->priv->targets = (GList*)0; for (lst = eleList; lst; lst = g_list_next(lst)) atomic->priv->targets = g_list_prepend(atomic->priv->targets, visu_node_array_renderer_get(atomic->priv->renderer, VISU_ELEMENT(lst->data))); gtk_widget_set_sensitive(GTK_WIDGET(atomic), (atomic->priv->model != (VisuElementAtomic*)0)); } v_sim-3.8.0/src/uiElements/ui_atomic.h000066400000000000000000000073111370110300500176520ustar00rootroot00000000000000/* EXTRAITS DE LA LICENCE Copyright CEA, contributeurs : Damien CALISTE, laboratoire L_Sim, (2016) Adresse mèl : CALISTE, damien P caliste AT cea P fr. Ce logiciel est un programme informatique servant à visualiser des structures atomiques dans un rendu pseudo-3D. Ce logiciel est régi par la licence CeCILL soumise au droit français et respectant les principes de diffusion des logiciels libres. Vous pouvez utiliser, modifier et/ou redistribuer ce programme sous les conditions de la licence CeCILL telle que diffusée par le CEA, le CNRS et l'INRIA sur le site "http://www.cecill.info". Le fait que vous puissiez accéder à cet en-tête signifie que vous avez pris connaissance de la licence CeCILL, et que vous en avez accepté les termes (cf. le fichier Documentation/licence.fr.txt fourni avec ce logiciel). */ /* LICENCE SUM UP Copyright CEA, contributors : Damien CALISTE, laboratoire L_Sim, (2016) E-mail address: CALISTE, damien P caliste AT cea P fr. This software is a computer program whose purpose is to visualize atomic configurations in 3D. This software is governed by the CeCILL license under French law and abiding by the rules of distribution of free software. You can use, modify and/ or redistribute the software under the terms of the CeCILL license as circulated by CEA, CNRS and INRIA at the following URL "http://www.cecill.info". The fact that you are presently reading this means that you have had knowledge of the CeCILL license and that you accept its terms. You can find a copy of this licence shipped with this software at Documentation/licence.en.txt. */ #ifndef UI_ATOMIC_H #define UI_ATOMIC_H #include #include /** * VISU_TYPE_UI_ATOMIC: * * return the type of #VisuUiAtomic. * * Since: 3.8 */ #define VISU_TYPE_UI_ATOMIC (visu_ui_atomic_get_type ()) /** * VISU_UI_ATOMIC: * @obj: a #GObject to cast. * * Cast the given @obj into #VisuUiAtomic type. * * Since: 3.8 */ #define VISU_UI_ATOMIC(obj) (G_TYPE_CHECK_INSTANCE_CAST(obj, VISU_TYPE_UI_ATOMIC, VisuUiAtomic)) /** * VISU_UI_ATOMIC_CLASS: * @klass: a #GObjectClass to cast. * * Cast the given @klass into #VisuUiAtomicClass. * * Since: 3.8 */ #define VISU_UI_ATOMIC_CLASS(klass) (G_TYPE_CHECK_CLASS_CAST(klass, VISU_TYPE_UI_ATOMIC, VisuUiAtomicClass)) /** * VISU_IS_UI_ATOMIC: * @obj: a #GObject to test. * * Test if the given @ogj is of the type of #VisuUiAtomic object. * * Since: 3.8 */ #define VISU_IS_UI_ATOMIC(obj) (G_TYPE_CHECK_INSTANCE_TYPE(obj, VISU_TYPE_UI_ATOMIC)) /** * VISU_IS_UI_ATOMIC_CLASS: * @klass: a #GObjectClass to test. * * Test if the given @klass is of the type of #VisuUiAtomicClass class. * * Since: 3.8 */ #define VISU_IS_UI_ATOMIC_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE(klass, VISU_TYPE_UI_ATOMIC)) /** * VISU_UI_ATOMIC_GET_CLASS: * @obj: a #GObject to get the class of. * * It returns the class of the given @obj. * * Since: 3.8 */ #define VISU_UI_ATOMIC_GET_CLASS(obj) (G_TYPE_INSTANCE_GET_CLASS(obj, VISU_TYPE_UI_ATOMIC, VisuUiAtomicClass)) typedef struct _VisuUiAtomic VisuUiAtomic; typedef struct _VisuUiAtomicPrivate VisuUiAtomicPrivate; typedef struct _VisuUiAtomicClass VisuUiAtomicClass; struct _VisuUiAtomic { GtkBox parent; VisuUiAtomicPrivate *priv; }; struct _VisuUiAtomicClass { GtkBoxClass parent; }; /** * visu_ui_atomic_get_type: * * This method returns the type of #VisuUiAtomic, use * VISU_TYPE_UI_ATOMIC instead. * * Since: 3.8 * * Returns: the type of #VisuUiAtomic. */ GType visu_ui_atomic_get_type(void); GtkWidget* visu_ui_atomic_new(VisuNodeArrayRenderer *renderer); void visu_ui_atomic_bind(VisuUiAtomic *atomic, GList *eleList); #endif v_sim-3.8.0/src/uiElements/ui_axes.c000066400000000000000000000176101370110300500173340ustar00rootroot00000000000000/* EXTRAITS DE LA LICENCE Copyright CEA, contributeurs : Damien CALISTE, laboratoire L_Sim, (2001-2014) Adresse mèl : CALISTE, damien P caliste AT cea P fr. Ce logiciel est un programme informatique servant à visualiser des structures atomiques dans un rendu pseudo-3D. Ce logiciel est régi par la licence CeCILL soumise au droit français et respectant les principes de diffusion des logiciels libres. Vous pouvez utiliser, modifier et/ou redistribuer ce programme sous les conditions de la licence CeCILL telle que diffusée par le CEA, le CNRS et l'INRIA sur le site "http://www.cecill.info". Le fait que vous puissiez accéder à cet en-tête signifie que vous avez pris connaissance de la licence CeCILL, et que vous en avez accepté les termes (cf. le fichier Documentation/licence.fr.txt fourni avec ce logiciel). */ /* LICENCE SUM UP Copyright CEA, contributors : Damien CALISTE, laboratoire L_Sim, (2001-2014) E-mail address: CALISTE, damien P caliste AT cea P fr. This software is a computer program whose purpose is to visualize atomic configurations in 3D. This software is governed by the CeCILL license under French law and abiding by the rules of distribution of free software. You can use, modify and/ or redistribute the software under the terms of the CeCILL license as circulated by CEA, CNRS and INRIA at the following URL "http://www.cecill.info". The fact that you are presently reading this means that you have had knowledge of the CeCILL license and that you accept its terms. You can find a copy of this licence shipped with this software at Documentation/licence.en.txt. */ #include "ui_axes.h" #include #include /** * SECTION:ui_axes * @short_description: Defines a widget to setup axes. * * A set of widgets to setup the rendring of axes. */ /** * VisuUiAxesClass: * @parent: the parent class; * * A short way to identify #_VisuUiAxesClass structure. * * Since: 3.8 */ /** * VisuUiAxes: * * An opaque structure. * * Since: 3.8 */ /** * VisuUiAxesPrivate: * * Private fields for #VisuUiAxes objects. * * Since: 3.8 */ struct _VisuUiAxesPrivate { gboolean dispose_has_run; GtkWidget *checkAxes; GtkWidget *spinFactor; GtkWidget *spinXPos, *spinYPos; GtkWidget *entryLbl[3]; VisuGlExtAxes *model; GBinding *bind_factor; GBinding *bind_xpos, *bind_ypos; GBinding *bindLbl[3]; }; static void visu_ui_axes_dispose(GObject* obj); /* Local callbacks. */ G_DEFINE_TYPE_WITH_CODE(VisuUiAxes, visu_ui_axes, VISU_TYPE_UI_LINE, G_ADD_PRIVATE(VisuUiAxes)) static void visu_ui_axes_class_init(VisuUiAxesClass *klass) { DBG_fprintf(stderr, "Ui Axes: creating the class of the widget.\n"); DBG_fprintf(stderr, " - adding new signals ;\n"); /* Connect freeing methods. */ G_OBJECT_CLASS(klass)->dispose = visu_ui_axes_dispose; } static void visu_ui_axes_dispose(GObject *obj) { DBG_fprintf(stderr, "Ui Axes: dispose object %p.\n", (gpointer)obj); if (VISU_UI_AXES(obj)->priv->dispose_has_run) return; visu_ui_axes_bind(VISU_UI_AXES(obj), (VisuGlExtAxes*)0); VISU_UI_AXES(obj)->priv->dispose_has_run = TRUE; /* Chain up to the parent class */ G_OBJECT_CLASS(visu_ui_axes_parent_class)->dispose(obj); } static void visu_ui_axes_init(VisuUiAxes *obj) { GtkWidget *vbox, *hbox; #define SET_LABEL(I) {obj->priv->entryLbl[I] = gtk_entry_new(); \ gtk_entry_set_width_chars(GTK_ENTRY(obj->priv->entryLbl[I]), 6); \ gtk_box_pack_start(GTK_BOX(hbox), obj->priv->entryLbl[I], TRUE, TRUE, 0);} DBG_fprintf(stderr, "Extension Axes: initializing a new object (%p).\n", (gpointer)obj); obj->priv = visu_ui_axes_get_instance_private(obj); obj->priv->dispose_has_run = FALSE; obj->priv->model = (VisuGlExtAxes*)0; vbox = visu_ui_line_getOptionBox(VISU_UI_LINE(obj)); hbox = gtk_hbox_new(FALSE, 0); gtk_box_pack_start(GTK_BOX(vbox), hbox, FALSE, FALSE, 0); obj->priv->checkAxes = gtk_check_button_new_with_mnemonic(_("Use _box basis-set")); gtk_box_pack_start(GTK_BOX(hbox), obj->priv->checkAxes, TRUE, TRUE, 0); gtk_box_pack_start(GTK_BOX(hbox), gtk_label_new(_("size: ")), TRUE, TRUE, 0); obj->priv->spinFactor = gtk_spin_button_new_with_range(0., 1., 0.01); gtk_box_pack_start(GTK_BOX(hbox), obj->priv->spinFactor, FALSE, FALSE, 0); hbox = gtk_hbox_new(FALSE, 0); gtk_box_pack_start(GTK_BOX(vbox), hbox, FALSE, FALSE, 0); gtk_box_pack_start(GTK_BOX(hbox), gtk_label_new(_("x pos.: ")), TRUE, TRUE, 0); obj->priv->spinXPos = gtk_spin_button_new_with_range(0., 1., 0.1); gtk_box_pack_start(GTK_BOX(hbox), obj->priv->spinXPos, FALSE, FALSE, 0); gtk_box_pack_start(GTK_BOX(hbox), gtk_label_new(_("y pos.: ")), TRUE, TRUE, 0); obj->priv->spinYPos = gtk_spin_button_new_with_range(0., 1., 0.1); gtk_box_pack_start(GTK_BOX(hbox), obj->priv->spinYPos, FALSE, FALSE, 0); hbox = gtk_hbox_new(FALSE, 5); gtk_box_pack_start(GTK_BOX(vbox), hbox, FALSE, FALSE, 0); gtk_box_pack_start(GTK_BOX(hbox), gtk_label_new(_("Axis labels: ")), TRUE, TRUE, 0); SET_LABEL(0); SET_LABEL(1); SET_LABEL(2); gtk_widget_show_all(GTK_WIDGET(vbox)); } /** * visu_ui_axes_new: * * Creates a new #VisuUiAxes to allow to setup axes rendering characteristics. * * Since: 3.8 * * Returns: a pointer to the newly created widget. */ GtkWidget* visu_ui_axes_new() { DBG_fprintf(stderr,"Ui Axes: new object.\n"); return GTK_WIDGET(g_object_new(VISU_TYPE_UI_AXES, "label", _("Basis set"), NULL)); } /** * visu_ui_axes_bind: * @axes: a #VisuUiAxes object. * @model: (transfer full): a #VisuGlExtAxes object. * * Bind the properties of @model to be displayed by @axes. * * Since: 3.8 **/ void visu_ui_axes_bind(VisuUiAxes *axes, VisuGlExtAxes *model) { g_return_if_fail(VISU_IS_UI_AXES(axes)); #define BIND_LBL(I, L) {axes->priv->bindLbl[I] = \ g_object_bind_property(model, L, axes->priv->entryLbl[I], "text", \ G_BINDING_BIDIRECTIONAL | G_BINDING_SYNC_CREATE);} if (axes->priv->model == model) return; visu_ui_line_bind(VISU_UI_LINE(axes), VISU_GL_EXT_LINED(model)); if (axes->priv->model) { g_object_unref(axes->priv->bind_factor); g_object_unref(axes->priv->bind_xpos); g_object_unref(axes->priv->bind_ypos); g_object_unref(axes->priv->bindLbl[0]); g_object_unref(axes->priv->bindLbl[1]); g_object_unref(axes->priv->bindLbl[2]); g_object_unref(axes->priv->model); } axes->priv->model = model; if (model) { g_object_ref(model); axes->priv->bind_factor = g_object_bind_property(model, "size", axes->priv->spinFactor, "value", G_BINDING_BIDIRECTIONAL | G_BINDING_SYNC_CREATE); axes->priv->bind_xpos = g_object_bind_property(model, "x-pos", axes->priv->spinXPos, "value", G_BINDING_BIDIRECTIONAL | G_BINDING_SYNC_CREATE); axes->priv->bind_ypos = g_object_bind_property(model, "y-pos", axes->priv->spinYPos, "value", G_BINDING_BIDIRECTIONAL | G_BINDING_SYNC_CREATE); BIND_LBL(0, "x-label"); BIND_LBL(1, "y-label"); BIND_LBL(2, "z-label"); } } /** * visu_ui_axes_getBasisCheckButton: * @axes: a #VisuUiAxes object. * * Retrieve the check button used to indicate if axes are orthogonal * or follow the box basis set. * * Since: 3.8 * * Returns: (transfer none): a #GtkCheckButton widget. **/ GtkWidget* visu_ui_axes_getBasisCheckButton(VisuUiAxes *axes) { g_return_val_if_fail(VISU_IS_UI_AXES(axes), (GtkWidget*)0); return axes->priv->checkAxes; } v_sim-3.8.0/src/uiElements/ui_axes.h000066400000000000000000000074461370110300500173470ustar00rootroot00000000000000/* EXTRAITS DE LA LICENCE Copyright CEA, contributeurs : Luc BILLARD et Damien CALISTE, laboratoire L_Sim, (2001-2014) Adresse mèl : BILLARD, non joignable par mèl ; CALISTE, damien P caliste AT cea P fr. Ce logiciel est un programme informatique servant à visualiser des structures atomiques dans un rendu pseudo-3D. Ce logiciel est régi par la licence CeCILL soumise au droit français et respectant les principes de diffusion des logiciels libres. Vous pouvez utiliser, modifier et/ou redistribuer ce programme sous les conditions de la licence CeCILL telle que diffusée par le CEA, le CNRS et l'INRIA sur le site "http://www.cecill.info". Le fait que vous puissiez accéder à cet en-tête signifie que vous avez pris connaissance de la licence CeCILL, et que vous en avez accepté les termes (cf. le fichier Documentation/licence.fr.txt fourni avec ce logiciel). */ /* LICENCE SUM UP Copyright CEA, contributors : Luc BILLARD et Damien CALISTE, laboratoire L_Sim, (2001-2014) E-mail address: BILLARD, not reachable any more ; CALISTE, damien P caliste AT cea P fr. This software is a computer program whose purpose is to visualize atomic configurations in 3D. This software is governed by the CeCILL license under French law and abiding by the rules of distribution of free software. You can use, modify and/ or redistribute the software under the terms of the CeCILL license as circulated by CEA, CNRS and INRIA at the following URL "http://www.cecill.info". The fact that you are presently reading this means that you have had knowledge of the CeCILL license and that you accept its terms. You can find a copy of this licence shipped with this software at Documentation/licence.en.txt. */ #ifndef UI_AXES_H #define UI_AXES_H #include #include #include /** * VISU_TYPE_UI_AXES: * * return the type of #VisuUiAxes. * * Since: 3.8 */ #define VISU_TYPE_UI_AXES (visu_ui_axes_get_type ()) /** * VISU_UI_AXES: * @obj: a #GObject to cast. * * Cast the given @obj into #VisuUiAxes type. * * Since: 3.8 */ #define VISU_UI_AXES(obj) (G_TYPE_CHECK_INSTANCE_CAST(obj, VISU_TYPE_UI_AXES, VisuUiAxes)) /** * VISU_UI_AXES_CLASS: * @klass: a #GObjectClass to cast. * * Cast the given @klass into #VisuUiAxesClass. * * Since: 3.8 */ #define VISU_UI_AXES_CLASS(klass) (G_TYPE_CHECK_CLASS_CAST(klass, VISU_TYPE_UI_AXES, VisuUiAxesClass)) /** * VISU_IS_UI_AXES: * @obj: a #GObject to test. * * Test if the given @ogj is of the type of #VisuUiAxes object. * * Since: 3.8 */ #define VISU_IS_UI_AXES(obj) (G_TYPE_CHECK_INSTANCE_TYPE(obj, VISU_TYPE_UI_AXES)) /** * VISU_IS_UI_AXES_CLASS: * @klass: a #GObjectClass to test. * * Test if the given @klass is of the type of #VisuUiAxesClass class. * * Since: 3.8 */ #define VISU_IS_UI_AXES_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE(klass, VISU_TYPE_UI_AXES)) /** * VISU_UI_AXES_GET_CLASS: * @obj: a #GObject to get the class of. * * It returns the class of the given @obj. * * Since: 3.8 */ #define VISU_UI_AXES_GET_CLASS(obj) (G_TYPE_INSTANCE_GET_CLASS(obj, VISU_TYPE_UI_AXES, VisuUiAxesClass)) typedef struct _VisuUiAxes VisuUiAxes; typedef struct _VisuUiAxesPrivate VisuUiAxesPrivate; typedef struct _VisuUiAxesClass VisuUiAxesClass; struct _VisuUiAxes { VisuUiLine parent; VisuUiAxesPrivate *priv; }; struct _VisuUiAxesClass { VisuUiLineClass parent; }; /** * visu_ui_axes_get_type: * * This method returns the type of #VisuUiAxes, use * VISU_TYPE_UI_AXES instead. * * Since: 3.8 * * Returns: the type of #VisuUiAxes. */ GType visu_ui_axes_get_type(void); GtkWidget* visu_ui_axes_new(); void visu_ui_axes_bind(VisuUiAxes *axes, VisuGlExtAxes *model); GtkWidget* visu_ui_axes_getBasisCheckButton(VisuUiAxes *axes); #endif v_sim-3.8.0/src/uiElements/ui_box.c000066400000000000000000000242241370110300500171630ustar00rootroot00000000000000/* EXTRAITS DE LA LICENCE Copyright CEA, contributeurs : Damien CALISTE, laboratoire L_Sim, (2001-2014) Adresse mèl : CALISTE, damien P caliste AT cea P fr. Ce logiciel est un programme informatique servant à visualiser des structures atomiques dans un rendu pseudo-3D. Ce logiciel est régi par la licence CeCILL soumise au droit français et respectant les principes de diffusion des logiciels libres. Vous pouvez utiliser, modifier et/ou redistribuer ce programme sous les conditions de la licence CeCILL telle que diffusée par le CEA, le CNRS et l'INRIA sur le site "http://www.cecill.info". Le fait que vous puissiez accéder à cet en-tête signifie que vous avez pris connaissance de la licence CeCILL, et que vous en avez accepté les termes (cf. le fichier Documentation/licence.fr.txt fourni avec ce logiciel). */ /* LICENCE SUM UP Copyright CEA, contributors : Damien CALISTE, laboratoire L_Sim, (2001-2014) E-mail address: CALISTE, damien P caliste AT cea P fr. This software is a computer program whose purpose is to visualize atomic configurations in 3D. This software is governed by the CeCILL license under French law and abiding by the rules of distribution of free software. You can use, modify and/ or redistribute the software under the terms of the CeCILL license as circulated by CEA, CNRS and INRIA at the following URL "http://www.cecill.info". The fact that you are presently reading this means that you have had knowledge of the CeCILL license and that you accept its terms. You can find a copy of this licence shipped with this software at Documentation/licence.en.txt. */ #include "ui_box.h" #include #include /** * SECTION:ui_box * @short_description: Defines a widget to setup box. * * A set of widgets to setup the rendring of a box. */ /** * VisuUiBoxClass: * @parent: the parent class; * * A short way to identify #_VisuUiBoxClass structure. * * Since: 3.8 */ /** * VisuUiBox: * * An opaque structure. * * Since: 3.8 */ /** * VisuUiBoxPrivate: * * Private fields for #VisuUiBox objects. * * Since: 3.8 */ struct _VisuUiBoxPrivate { gboolean dispose_has_run; GtkWidget *checkBox; GtkWidget *spinXPos, *spinYPos; VisuGlExtBox *model; VisuGlExtBoxLegend *legend; GBinding *bind_active, *bind_xpos, *bind_ypos; VisuBox *box; }; enum { SHOW_SIZE_SIGNAL, X_POS_SIGNAL, Y_POS_SIGNAL, LAST_SIGNAL }; static guint signals[LAST_SIGNAL] = { 0 }; static void visu_ui_box_finalize(GObject* obj); static void visu_ui_box_dispose(GObject* obj); /* Local callbacks. */ static void onShowSizeChanged(GtkToggleButton *toggle, VisuUiBox *box); static void onXPosChanged(GtkSpinButton *spin, VisuUiBox *box); static void onYPosChanged(GtkSpinButton *spin, VisuUiBox *box); G_DEFINE_TYPE_WITH_CODE(VisuUiBox, visu_ui_box, VISU_TYPE_UI_LINE, G_ADD_PRIVATE(VisuUiBox)) static void visu_ui_box_class_init(VisuUiBoxClass *klass) { DBG_fprintf(stderr, "Ui Box: creating the class of the widget.\n"); DBG_fprintf(stderr, " - adding new signals ;\n"); /** * VisuUiBox::show-size-changed: * @box: the #VisuUiBox that emits the signal ; * @used: TRUE if the box follow the box basis-set. * * This signal is emitted when the box legend check box is changed. * * Since: 3.8 */ signals[SHOW_SIZE_SIGNAL] = g_signal_new ("show-size-changed", G_TYPE_FROM_CLASS (klass), G_SIGNAL_RUN_LAST | G_SIGNAL_NO_RECURSE | G_SIGNAL_NO_HOOKS, 0, NULL, NULL, g_cclosure_marshal_VOID__BOOLEAN, G_TYPE_NONE, 1, G_TYPE_BOOLEAN); /** * VisuUiBox::x-pos-changed: * @box: the #VisuUiBox that emits the signal ; * @pos: the new position. * * This signal is emitted when the box legend rendering position is changed. * * Since: 3.8 */ signals[X_POS_SIGNAL] = g_signal_new ("x-pos-changed", G_TYPE_FROM_CLASS (klass), G_SIGNAL_RUN_LAST | G_SIGNAL_NO_RECURSE | G_SIGNAL_NO_HOOKS, 0, NULL, NULL, g_cclosure_marshal_VOID__DOUBLE, G_TYPE_NONE, 1, G_TYPE_DOUBLE); /** * VisuUiBox::y-pos-changed: * @box: the #VisuUiBox that emits the signal ; * @pos: the new position. * * This signal is emitted when the box legend rendering position is changed. * * Since: 3.8 */ signals[Y_POS_SIGNAL] = g_signal_new ("y-pos-changed", G_TYPE_FROM_CLASS (klass), G_SIGNAL_RUN_LAST | G_SIGNAL_NO_RECURSE | G_SIGNAL_NO_HOOKS, 0, NULL, NULL, g_cclosure_marshal_VOID__DOUBLE, G_TYPE_NONE, 1, G_TYPE_DOUBLE); /* Connect freeing methods. */ G_OBJECT_CLASS(klass)->dispose = visu_ui_box_dispose; G_OBJECT_CLASS(klass)->finalize = visu_ui_box_finalize; } static void visu_ui_box_dispose(GObject *obj) { DBG_fprintf(stderr, "Ui Box: dispose object %p.\n", (gpointer)obj); if (VISU_UI_BOX(obj)->priv->dispose_has_run) return; visu_ui_box_bind(VISU_UI_BOX(obj), (VisuGlExtBox*)0); visu_ui_box_bindLegend(VISU_UI_BOX(obj), (VisuGlExtBoxLegend*)0); VISU_UI_BOX(obj)->priv->dispose_has_run = TRUE; /* Chain up to the parent class */ G_OBJECT_CLASS(visu_ui_box_parent_class)->dispose(obj); } static void visu_ui_box_finalize(GObject *obj) { g_return_if_fail(obj); DBG_fprintf(stderr, "Ui Box: finalize object %p.\n", (gpointer)obj); /* Chain up to the parent class */ G_OBJECT_CLASS(visu_ui_box_parent_class)->finalize(obj); DBG_fprintf(stderr, " | freeing ... OK.\n"); } static void visu_ui_box_init(VisuUiBox *obj) { GtkWidget *vbox, *hbox; DBG_fprintf(stderr, "Extension Box: initializing a new object (%p).\n", (gpointer)obj); obj->priv = visu_ui_box_get_instance_private(obj); obj->priv->dispose_has_run = FALSE; obj->priv->model = (VisuGlExtBox*)0; obj->priv->legend = (VisuGlExtBoxLegend*)0; vbox = visu_ui_line_getOptionBox(VISU_UI_LINE(obj)); obj->priv->checkBox = gtk_check_button_new_with_mnemonic(_("Show box _lengths")); gtk_box_pack_start(GTK_BOX(vbox), obj->priv->checkBox, FALSE, FALSE, 0); g_signal_connect(G_OBJECT(obj->priv->checkBox), "toggled", G_CALLBACK(onShowSizeChanged), (gpointer)obj); hbox = gtk_hbox_new(FALSE, 0); gtk_box_pack_start(GTK_BOX(vbox), hbox, FALSE, FALSE, 0); gtk_box_pack_start(GTK_BOX(hbox), gtk_label_new(_("x pos.")), TRUE, TRUE, 0); obj->priv->spinXPos = gtk_spin_button_new_with_range(0., 1., 0.1); gtk_box_pack_start(GTK_BOX(hbox), obj->priv->spinXPos, FALSE, FALSE, 0); g_signal_connect(G_OBJECT(obj->priv->spinXPos), "value-changed", G_CALLBACK(onXPosChanged), (gpointer)obj); gtk_box_pack_start(GTK_BOX(hbox), gtk_label_new(_("y pos.")), TRUE, TRUE, 0); obj->priv->spinYPos = gtk_spin_button_new_with_range(0., 1., 0.1); gtk_box_pack_start(GTK_BOX(hbox), obj->priv->spinYPos, FALSE, FALSE, 0); g_signal_connect(G_OBJECT(obj->priv->spinYPos), "value-changed", G_CALLBACK(onYPosChanged), (gpointer)obj); /* label = gtk_label_new(_("Draw basis set:")); */ /* gtk_misc_set_alignment(GTK_MISC(label), 1., 0.5); */ /* gtk_box_pack_start(GTK_BOX(hbox), label, TRUE, TRUE, 0); */ /* checkBasis = gtk_check_button_new(); */ /* gtk_box_pack_start(GTK_BOX(hbox), checkBasis, FALSE, FALSE, 0); */ gtk_widget_show_all(GTK_WIDGET(vbox)); } /** * visu_ui_box_new: * * Creates a new #VisuUiBox to allow to setup box rendering characteristics. * * Since: 3.8 * * Returns: a pointer to the newly created widget. */ GtkWidget* visu_ui_box_new() { DBG_fprintf(stderr,"Ui Box: new object.\n"); return GTK_WIDGET(g_object_new(VISU_TYPE_UI_BOX, "label", _("Bounding box"), NULL)); } /** * visu_ui_box_bind: * @box: a #VisuUiBox object. * @model: (transfer full): a #VisuGlExtBox object. * * Bind the properties of @model to be displayed by @box. * * Since: 3.8 **/ void visu_ui_box_bind(VisuUiBox *box, VisuGlExtBox *model) { g_return_if_fail(VISU_IS_UI_BOX(box)); if (box->priv->model == model) return; visu_ui_line_bind(VISU_UI_LINE(box), VISU_GL_EXT_LINED(model)); if (box->priv->model) g_object_unref(G_OBJECT(box->priv->model)); box->priv->model = model; if (model) g_object_ref(G_OBJECT(model)); } /** * visu_ui_box_bindLegend: * @box: a #VisuUiBox object. * @legend: (transfer full): a #VisuGlExtBoxLegend object. * * Bind the properties of @model to be displayed by @legend. * * Since: 3.8 **/ void visu_ui_box_bindLegend(VisuUiBox *box, VisuGlExtBoxLegend *legend) { g_return_if_fail(VISU_IS_UI_BOX(box)); if (box->priv->legend == legend) return; if (box->priv->legend) { g_object_unref(G_OBJECT(box->priv->bind_active)); g_object_unref(G_OBJECT(box->priv->bind_xpos)); g_object_unref(G_OBJECT(box->priv->bind_ypos)); g_object_unref(G_OBJECT(box->priv->legend)); } box->priv->legend = legend; if (legend) { g_object_ref(G_OBJECT(legend)); box->priv->bind_active = g_object_bind_property(legend, "active", box->priv->checkBox, "active", G_BINDING_BIDIRECTIONAL | G_BINDING_SYNC_CREATE); box->priv->bind_xpos = g_object_bind_property(legend, "x-pos", box->priv->spinXPos, "value", G_BINDING_BIDIRECTIONAL | G_BINDING_SYNC_CREATE); box->priv->bind_ypos = g_object_bind_property(legend, "y-pos", box->priv->spinYPos, "value", G_BINDING_BIDIRECTIONAL | G_BINDING_SYNC_CREATE); } } static void onShowSizeChanged(GtkToggleButton *toggle, VisuUiBox *box) { g_signal_emit(G_OBJECT(box), signals[SHOW_SIZE_SIGNAL], 0, gtk_toggle_button_get_active(toggle), NULL); } static void onXPosChanged(GtkSpinButton *spin, VisuUiBox *box) { g_signal_emit(G_OBJECT(box), signals[X_POS_SIGNAL], 0, gtk_spin_button_get_value(spin), NULL); } static void onYPosChanged(GtkSpinButton *spin, VisuUiBox *box) { g_signal_emit(G_OBJECT(box), signals[Y_POS_SIGNAL], 0, gtk_spin_button_get_value(spin), NULL); } v_sim-3.8.0/src/uiElements/ui_box.h000066400000000000000000000074121370110300500171700ustar00rootroot00000000000000/* EXTRAITS DE LA LICENCE Copyright CEA, contributeurs : Luc BILLARD et Damien CALISTE, laboratoire L_Sim, (2001-2014) Adresse mèl : BILLARD, non joignable par mèl ; CALISTE, damien P caliste AT cea P fr. Ce logiciel est un programme informatique servant à visualiser des structures atomiques dans un rendu pseudo-3D. Ce logiciel est régi par la licence CeCILL soumise au droit français et respectant les principes de diffusion des logiciels libres. Vous pouvez utiliser, modifier et/ou redistribuer ce programme sous les conditions de la licence CeCILL telle que diffusée par le CEA, le CNRS et l'INRIA sur le site "http://www.cecill.info". Le fait que vous puissiez accéder à cet en-tête signifie que vous avez pris connaissance de la licence CeCILL, et que vous en avez accepté les termes (cf. le fichier Documentation/licence.fr.txt fourni avec ce logiciel). */ /* LICENCE SUM UP Copyright CEA, contributors : Luc BILLARD et Damien CALISTE, laboratoire L_Sim, (2001-2014) E-mail address: BILLARD, not reachable any more ; CALISTE, damien P caliste AT cea P fr. This software is a computer program whose purpose is to visualize atomic configurations in 3D. This software is governed by the CeCILL license under French law and abiding by the rules of distribution of free software. You can use, modify and/ or redistribute the software under the terms of the CeCILL license as circulated by CEA, CNRS and INRIA at the following URL "http://www.cecill.info". The fact that you are presently reading this means that you have had knowledge of the CeCILL license and that you accept its terms. You can find a copy of this licence shipped with this software at Documentation/licence.en.txt. */ #ifndef UI_BOX_H #define UI_BOX_H #include #include #include /** * VISU_TYPE_UI_BOX: * * return the type of #VisuUiBox. * * Since: 3.8 */ #define VISU_TYPE_UI_BOX (visu_ui_box_get_type ()) /** * VISU_UI_BOX: * @obj: a #GObject to cast. * * Cast the given @obj into #VisuUiBox type. * * Since: 3.8 */ #define VISU_UI_BOX(obj) (G_TYPE_CHECK_INSTANCE_CAST(obj, VISU_TYPE_UI_BOX, VisuUiBox)) /** * VISU_UI_BOX_CLASS: * @klass: a #GObjectClass to cast. * * Cast the given @klass into #VisuUiBoxClass. * * Since: 3.8 */ #define VISU_UI_BOX_CLASS(klass) (G_TYPE_CHECK_CLASS_CAST(klass, VISU_TYPE_UI_BOX, VisuUiBoxClass)) /** * VISU_IS_UI_BOX: * @obj: a #GObject to test. * * Test if the given @ogj is of the type of #VisuUiBox object. * * Since: 3.8 */ #define VISU_IS_UI_BOX(obj) (G_TYPE_CHECK_INSTANCE_TYPE(obj, VISU_TYPE_UI_BOX)) /** * VISU_IS_UI_BOX_CLASS: * @klass: a #GObjectClass to test. * * Test if the given @klass is of the type of #VisuUiBoxClass class. * * Since: 3.8 */ #define VISU_IS_UI_BOX_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE(klass, VISU_TYPE_UI_BOX)) /** * VISU_UI_BOX_GET_CLASS: * @obj: a #GObject to get the class of. * * It returns the class of the given @obj. * * Since: 3.8 */ #define VISU_UI_BOX_GET_CLASS(obj) (G_TYPE_INSTANCE_GET_CLASS(obj, VISU_TYPE_UI_BOX, VisuUiBoxClass)) typedef struct _VisuUiBox VisuUiBox; typedef struct _VisuUiBoxPrivate VisuUiBoxPrivate; typedef struct _VisuUiBoxClass VisuUiBoxClass; struct _VisuUiBox { VisuUiLine parent; VisuUiBoxPrivate *priv; }; struct _VisuUiBoxClass { VisuUiLineClass parent; }; /** * visu_ui_box_get_type: * * This method returns the type of #VisuUiBox, use * VISU_TYPE_UI_BOX instead. * * Since: 3.8 * * Returns: the type of #VisuUiBox. */ GType visu_ui_box_get_type(void); GtkWidget* visu_ui_box_new(); void visu_ui_box_bind(VisuUiBox *box, VisuGlExtBox *model); void visu_ui_box_bindLegend(VisuUiBox *box, VisuGlExtBoxLegend *legend); #endif v_sim-3.8.0/src/uiElements/ui_boxTransform.c000066400000000000000000000666331370110300500210710ustar00rootroot00000000000000/* EXTRAITS DE LA LICENCE Copyright CEA, contributeurs : Damien CALISTE, laboratoire L_Sim, (2001-2014) Adresse mèl : CALISTE, damien P caliste AT cea P fr. Ce logiciel est un programme informatique servant à visualiser des structures atomiques dans un rendu pseudo-3D. Ce logiciel est régi par la licence CeCILL soumise au droit français et respectant les principes de diffusion des logiciels libres. Vous pouvez utiliser, modifier et/ou redistribuer ce programme sous les conditions de la licence CeCILL telle que diffusée par le CEA, le CNRS et l'INRIA sur le site "http://www.cecill.info". Le fait que vous puissiez accéder à cet en-tête signifie que vous avez pris connaissance de la licence CeCILL, et que vous en avez accepté les termes (cf. le fichier Documentation/licence.fr.txt fourni avec ce logiciel). */ /* LICENCE SUM UP Copyright CEA, contributors : Damien CALISTE, laboratoire L_Sim, (2001-2014) E-mail address: CALISTE, damien P caliste AT cea P fr. This software is a computer program whose purpose is to visualize atomic configurations in 3D. This software is governed by the CeCILL license under French law and abiding by the rules of distribution of free software. You can use, modify and/ or redistribute the software under the terms of the CeCILL license as circulated by CEA, CNRS and INRIA at the following URL "http://www.cecill.info". The fact that you are presently reading this means that you have had knowledge of the CeCILL license and that you accept its terms. You can find a copy of this licence shipped with this software at Documentation/licence.en.txt. */ #include "ui_boxTransform.h" #include #include #include #include #include /** * SECTION:ui_boxTransform * @short_description: Defines a widget to setup box transformations. * * A set of widgets to setup the transformation applied to a box * (translations, expansions...). */ /** * VisuUiBoxTransformClass: * @parent: the parent class; * * A short way to identify #_VisuUiBoxTransformClass structure. * * Since: 3.8 */ /** * VisuUiBoxTransform: * * An opaque structure. * * Since: 3.8 */ /** * VisuUiBoxTransformPrivate: * * Private fields for #VisuUiBoxTransform objects. * * Since: 3.8 */ struct _VisuUiBoxTransformPrivate { gboolean dispose_has_run; GtkWidget *checkAllowTranslations, *checkInBox, *checkAllowExpand; GtkWidget *spinTransXYZ[3], *spinExpandXYZ[3]; GtkWidget *stippleExpandBox, *colorExpandBox; GtkWidget *labelBc, *warnBc; GtkWidget *comboUnit, *comboHide; VisuPointset *pointset; gulong sig_box; VisuBox *box; GBinding *bind_bc, *bind_bcWarn; GBinding *bind_trans[3], *bind_allowTrans, *bind_boxTrans; GBinding *bind_expand[3], *bind_allowExpand; GBinding *bind_units, *bind_hide; gulong sig_boundary; VisuGlExtBox *glBox; GBinding *bind_stipple, *bind_color; }; enum { PROP_0, POINTSET_PROP, GL_BOX_PROP, N_PROP }; static GParamSpec *properties[N_PROP]; static void visu_ui_box_transform_finalize(GObject* obj); static void visu_ui_box_transform_dispose(GObject* obj); static void visu_ui_box_transform_get_property(GObject* obj, guint property_id, GValue *value, GParamSpec *pspec); static void visu_ui_box_transform_set_property(GObject* obj, guint property_id, const GValue *value, GParamSpec *pspec); G_DEFINE_TYPE_WITH_CODE(VisuUiBoxTransform, visu_ui_box_transform, GTK_TYPE_BOX, G_ADD_PRIVATE(VisuUiBoxTransform)) static void visu_ui_box_transform_class_init(VisuUiBoxTransformClass *klass) { DBG_fprintf(stderr, "Ui BoxTransform: creating the class of the widget.\n"); DBG_fprintf(stderr, " - adding new signals ;\n"); /* Connect freeing methods. */ G_OBJECT_CLASS(klass)->dispose = visu_ui_box_transform_dispose; G_OBJECT_CLASS(klass)->finalize = visu_ui_box_transform_finalize; G_OBJECT_CLASS(klass)->set_property = visu_ui_box_transform_set_property; G_OBJECT_CLASS(klass)->get_property = visu_ui_box_transform_get_property; /** * VisuUiBoxTransform::pointset: * * Store the #VisuPointset model. * * Since: 3.8 */ properties[POINTSET_PROP] = g_param_spec_object("pointset", "Pointset", "Pointset to transform", VISU_TYPE_POINTSET, G_PARAM_READWRITE); g_object_class_install_property(G_OBJECT_CLASS(klass), POINTSET_PROP, properties[POINTSET_PROP]); /** * VisuUiBoxTransform::gl-box: * * Store the rendering box object of box. * * Since: 3.8 */ properties[GL_BOX_PROP] = g_param_spec_object("gl-box", "OpenGL box object", "rendering object used for box", VISU_TYPE_GL_EXT_BOX, G_PARAM_READWRITE); g_object_class_install_property(G_OBJECT_CLASS(klass), GL_BOX_PROP, properties[GL_BOX_PROP]); } static void visu_ui_box_transform_dispose(GObject *obj) { DBG_fprintf(stderr, "Ui BoxTransform: dispose object %p.\n", (gpointer)obj); if (VISU_UI_BOX_TRANSFORM(obj)->priv->dispose_has_run) return; visu_ui_box_transform_bind(VISU_UI_BOX_TRANSFORM(obj), (VisuPointset*)0); visu_ui_box_transform_bindGlExtBox(VISU_UI_BOX_TRANSFORM(obj), (VisuGlExtBox*)0); VISU_UI_BOX_TRANSFORM(obj)->priv->dispose_has_run = TRUE; /* Chain up to the parent class */ G_OBJECT_CLASS(visu_ui_box_transform_parent_class)->dispose(obj); } static void visu_ui_box_transform_finalize(GObject *obj) { g_return_if_fail(obj); DBG_fprintf(stderr, "Ui BoxTransform: finalize object %p.\n", (gpointer)obj); /* Chain up to the parent class */ G_OBJECT_CLASS(visu_ui_box_transform_parent_class)->finalize(obj); DBG_fprintf(stderr, " | freeing ... OK.\n"); } static void visu_ui_box_transform_get_property(GObject* obj, guint property_id, GValue *value, GParamSpec *pspec) { VisuUiBoxTransform *self = VISU_UI_BOX_TRANSFORM(obj); DBG_fprintf(stderr, "Ui BoxTransform: get property '%s'.\n", g_param_spec_get_name(pspec)); switch (property_id) { case POINTSET_PROP: g_value_set_object(value, self->priv->pointset); break; case GL_BOX_PROP: g_value_set_object(value, self->priv->glBox); break; default: /* We don't have any other property... */ G_OBJECT_WARN_INVALID_PROPERTY_ID(obj, property_id, pspec); break; } } static void visu_ui_box_transform_set_property(GObject* obj, guint property_id, const GValue *value, GParamSpec *pspec) { VisuUiBoxTransform *self = VISU_UI_BOX_TRANSFORM(obj); DBG_fprintf(stderr, "Ui BoxTransform: set property '%s'.\n", g_param_spec_get_name(pspec)); switch (property_id) { case POINTSET_PROP: visu_ui_box_transform_bind(self, VISU_POINTSET(g_value_get_object(value))); break; case GL_BOX_PROP: visu_ui_box_transform_bindGlExtBox(self, VISU_GL_EXT_BOX(g_value_get_object(value))); break; default: /* We don't have any other property... */ G_OBJECT_WARN_INVALID_PROPERTY_ID(obj, property_id, pspec); break; } } static gboolean setPeriodicityWarning(GBinding *bind _U_, const GValue *source, GValue *target, gpointer user_data _U_) { g_value_set_boolean(target, g_value_get_uint(source) == VISU_BOX_FREE); return TRUE; } static gboolean setPeriodicity(GBinding *bind _U_, const GValue *source, GValue *target, gpointer user_data _U_) { gchar *lbl; switch (g_value_get_uint(source)) { case VISU_BOX_FREE: lbl = g_markup_printf_escaped("%s", _("non periodic data")); g_value_take_string(target, lbl); return TRUE; case VISU_BOX_WIRE_X: g_value_set_static_string(target, _("(wire X)")); return TRUE; case VISU_BOX_WIRE_Y: g_value_set_static_string(target, _("(wire Y)")); return TRUE; case VISU_BOX_WIRE_Z: g_value_set_static_string(target, _("(wire Z)")); return TRUE; case VISU_BOX_SURFACE_XY: g_value_set_static_string(target, _("(surface XY)")); return TRUE; case VISU_BOX_SURFACE_YZ: g_value_set_static_string(target, _("(surface YZ)")); return TRUE; case VISU_BOX_SURFACE_ZX: g_value_set_static_string(target, _("(surface ZX)")); return TRUE; case VISU_BOX_PERIODIC: g_value_set_static_string(target, _("(periodic)")); return TRUE; default: g_value_set_static_string(target, _("unknown periodicity")); return TRUE; } return TRUE; } static void setSensitive(VisuUiBoxTransform *obj) { gboolean expanded; VisuBoxBoundaries bc; expanded = gtk_toggle_button_get_active(GTK_TOGGLE_BUTTON(obj->priv->checkAllowExpand)); bc = (obj->priv->box) ? visu_box_getBoundary(obj->priv->box) : VISU_BOX_PERIODIC; /* For the translations. */ gtk_widget_set_sensitive(obj->priv->checkInBox, !expanded && obj->priv->box && (bc != VISU_BOX_FREE)); gtk_widget_set_sensitive(obj->priv->checkAllowTranslations, !expanded && obj->priv->box && (bc != VISU_BOX_FREE)); gtk_widget_set_sensitive(obj->priv->spinTransXYZ[0], !expanded && obj->priv->box && (bc & TOOL_XYZ_MASK_X)); gtk_widget_set_sensitive(obj->priv->spinTransXYZ[1], !expanded && obj->priv->box && (bc & TOOL_XYZ_MASK_Y)); gtk_widget_set_sensitive(obj->priv->spinTransXYZ[2], !expanded && obj->priv->box && (bc & TOOL_XYZ_MASK_Z)); /* For the extensions. */ gtk_widget_set_sensitive(obj->priv->checkAllowExpand, obj->priv->box && (bc != VISU_BOX_FREE)); gtk_widget_set_sensitive(obj->priv->spinExpandXYZ[0], obj->priv->box && (bc & TOOL_XYZ_MASK_X)); gtk_widget_set_sensitive(obj->priv->spinExpandXYZ[1], obj->priv->box && (bc & TOOL_XYZ_MASK_Y)); gtk_widget_set_sensitive(obj->priv->spinExpandXYZ[2], obj->priv->box && (bc & TOOL_XYZ_MASK_Z)); } static void visu_ui_box_transform_init(VisuUiBoxTransform *obj) { GtkWidget *hbox, *label, *vbox; guint i; #define X_LABEL _("dx:") #define Y_LABEL _("dy:") #define Z_LABEL _("dz:") char *xyz[3]; const gchar **units; #if GTK_MAJOR_VERSION == 2 && GTK_MINOR_VERSION < 12 GtkTooltips *tooltips; tooltips = gtk_tooltips_new (); #endif DBG_fprintf(stderr, "Extension BoxTransform: initializing a new object (%p).\n", (gpointer)obj); gtk_orientable_set_orientation(GTK_ORIENTABLE(obj), GTK_ORIENTATION_VERTICAL); obj->priv = visu_ui_box_transform_get_instance_private(obj); obj->priv->dispose_has_run = FALSE; obj->priv->box = (VisuBox*)0; obj->priv->glBox = (VisuGlExtBox*)0; /**************************/ /* The periodicity stuff. */ /**************************/ hbox = gtk_hbox_new(FALSE, 0); gtk_box_pack_start(GTK_BOX(obj), hbox, FALSE, FALSE, 0); label = gtk_label_new(_("Periodic operations")); gtk_widget_set_name(label, "label_head"); gtk_label_set_xalign(GTK_LABEL(label), 0.); gtk_label_set_use_markup(GTK_LABEL(label), TRUE); gtk_box_pack_start(GTK_BOX(hbox), label, TRUE, TRUE, 0); obj->priv->labelBc = gtk_label_new(""); gtk_box_pack_end(GTK_BOX(hbox), obj->priv->labelBc, FALSE, FALSE, 0); gtk_label_set_use_markup(GTK_LABEL(obj->priv->labelBc), TRUE); obj->priv->warnBc = gtk_image_new_from_icon_name("dialog-warning", GTK_ICON_SIZE_MENU); gtk_widget_set_no_show_all(obj->priv->warnBc, TRUE); gtk_box_pack_end(GTK_BOX(hbox), obj->priv->warnBc, FALSE, FALSE, 0); vbox = gtk_vbox_new(FALSE, 2); gtk_widget_set_margin_start(vbox, 15); gtk_box_pack_start(GTK_BOX(obj), vbox, FALSE, FALSE, 0); /* The translations. */ hbox = gtk_hbox_new(FALSE, 0); g_object_bind_property(obj, "pointset", hbox, "sensitive", G_BINDING_SYNC_CREATE); gtk_box_pack_start(GTK_BOX(vbox), hbox, FALSE, FALSE, 0); obj->priv->checkAllowTranslations = gtk_check_button_new_with_mnemonic(_("_Translations")); gtk_widget_set_tooltip_text(obj->priv->checkAllowTranslations, _("Translations are given in box coordinates.")); gtk_box_pack_start(GTK_BOX(hbox), obj->priv->checkAllowTranslations, TRUE, TRUE, 0); obj->priv->checkInBox = gtk_check_button_new_with_mnemonic(_("_Put in the box")); gtk_widget_set_tooltip_text(obj->priv->checkInBox, _("Nodes are automatically translated back into the bounding box.")); gtk_box_pack_start(GTK_BOX(hbox), obj->priv->checkInBox, TRUE, TRUE, 0); hbox = gtk_hbox_new(FALSE, 2); g_object_bind_property(obj, "pointset", hbox, "sensitive", G_BINDING_SYNC_CREATE); gtk_box_pack_start(GTK_BOX(vbox), hbox, FALSE, FALSE, 0); xyz[0] = X_LABEL; xyz[1] = Y_LABEL; xyz[2] = Z_LABEL; for (i = 0; i < 3; i++) { label = gtk_label_new(xyz[i]); gtk_box_pack_start(GTK_BOX(hbox), label, TRUE, TRUE, 0); gtk_label_set_xalign(GTK_LABEL(label), 1.); obj->priv->spinTransXYZ[i] = gtk_spin_button_new_with_range(-1, 1, 0.05); gtk_spin_button_set_value(GTK_SPIN_BUTTON(obj->priv->spinTransXYZ[i]), 0.); gtk_spin_button_set_numeric(GTK_SPIN_BUTTON(obj->priv->spinTransXYZ[i]), TRUE); gtk_box_pack_start(GTK_BOX(hbox), obj->priv->spinTransXYZ[i], FALSE, FALSE, 0); } /* The replication. */ hbox = gtk_hbox_new(FALSE, 2); g_object_bind_property(obj, "pointset", hbox, "sensitive", G_BINDING_SYNC_CREATE); gtk_box_pack_start(GTK_BOX(vbox), hbox, FALSE, FALSE, 0); obj->priv->checkAllowExpand = gtk_check_button_new_with_mnemonic(_("_Expand nodes")); gtk_widget_set_tooltip_text(obj->priv->checkAllowExpand, _("The size of the expansion is given in box coordinates." " Nodes are automatically translated back into the new" " defined area. The drawn bounding box is kept to the" " original size.")); gtk_box_pack_start(GTK_BOX(hbox), obj->priv->checkAllowExpand, TRUE, TRUE, 0); g_signal_connect_object(G_OBJECT(obj->priv->checkAllowExpand), "toggled", G_CALLBACK(setSensitive), (gpointer)obj, G_CONNECT_SWAPPED); /* The rendering parameters. */ label = gtk_label_new(_("param.:")); gtk_box_pack_start(GTK_BOX(hbox), label, FALSE, FALSE, 0); /* The stipple pattern. */ obj->priv->stippleExpandBox = visu_ui_stipple_combobox_new(); gtk_box_pack_start(GTK_BOX(hbox), obj->priv->stippleExpandBox, FALSE, FALSE, 0); /* The color widget. */ obj->priv->colorExpandBox = visu_ui_color_combobox_new(TRUE); visu_ui_color_combobox_setPrintValues(VISU_UI_COLOR_COMBOBOX(obj->priv->colorExpandBox), FALSE); gtk_box_pack_start(GTK_BOX(hbox), obj->priv->colorExpandBox, FALSE, FALSE, 0); hbox = gtk_hbox_new(FALSE, 2); g_object_bind_property(obj, "pointset", hbox, "sensitive", G_BINDING_SYNC_CREATE); gtk_box_pack_start(GTK_BOX(vbox), hbox, FALSE, FALSE, 0); xyz[0] = X_LABEL; xyz[1] = Y_LABEL; xyz[2] = Z_LABEL; for (i = 0; i < 3; i++) { label = gtk_label_new(xyz[i]); gtk_box_pack_start(GTK_BOX(hbox), label, TRUE, TRUE, 0); gtk_label_set_xalign(GTK_LABEL(label), 1.); obj->priv->spinExpandXYZ[i] = gtk_spin_button_new_with_range(0, 5, 0.05); gtk_spin_button_set_numeric(GTK_SPIN_BUTTON(obj->priv->spinExpandXYZ[i]), TRUE); gtk_box_pack_start(GTK_BOX(hbox), obj->priv->spinExpandXYZ[i], FALSE, FALSE, 0); } /********************/ /* The units stuff. */ /********************/ hbox = gtk_hbox_new(FALSE, 0); gtk_box_pack_start(GTK_BOX(obj), hbox, FALSE, FALSE, 0); label = gtk_label_new(_("Box settings")); gtk_widget_set_name(label, "label_head"); gtk_label_set_xalign(GTK_LABEL(label), 0.); gtk_label_set_use_markup(GTK_LABEL(label), TRUE); gtk_box_pack_start(GTK_BOX(hbox), label, TRUE, TRUE, 0); hbox = gtk_hbox_new(FALSE, 2); gtk_widget_set_margin_start(hbox, 15); g_object_bind_property(obj, "pointset", hbox, "sensitive", G_BINDING_SYNC_CREATE); gtk_box_pack_start(GTK_BOX(obj), hbox, FALSE, FALSE, 0); label = gtk_label_new(_("Set the unit of the file:")); gtk_box_pack_start(GTK_BOX(hbox), label, FALSE, FALSE, 0); obj->priv->comboUnit = gtk_combo_box_text_new(); units = tool_physic_getUnitNames(); for (i = 0; units[i]; i++) gtk_combo_box_text_append(GTK_COMBO_BOX_TEXT(obj->priv->comboUnit), (const gchar*)0, units[i]); gtk_box_pack_start(GTK_BOX(hbox), obj->priv->comboUnit, FALSE, FALSE, 0); hbox = gtk_hbox_new(FALSE, 2); gtk_widget_set_margin_start(hbox, 15); g_object_bind_property(obj, "pointset", hbox, "sensitive", G_BINDING_SYNC_CREATE); gtk_box_pack_start(GTK_BOX(obj), hbox, FALSE, FALSE, 0); label = gtk_label_new(_("Hide nodes with respect to box:")); gtk_box_pack_start(GTK_BOX(hbox), label, FALSE, FALSE, 0); obj->priv->comboHide = gtk_combo_box_text_new(); gtk_combo_box_text_append(GTK_COMBO_BOX_TEXT(obj->priv->comboHide), (const gchar*)0, _("never")); gtk_combo_box_text_append(GTK_COMBO_BOX_TEXT(obj->priv->comboHide), (const gchar*)0, _("outside")); gtk_combo_box_text_append(GTK_COMBO_BOX_TEXT(obj->priv->comboHide), (const gchar*)0, _("inside")); gtk_box_pack_start(GTK_BOX(hbox), obj->priv->comboHide, FALSE, FALSE, 0); gtk_widget_show_all(GTK_WIDGET(obj)); } /** * visu_ui_box_transform_new: * * Creates a new #VisuUiBoxTransform to allow to setup box_transform rendering characteristics. * * Since: 3.8 * * Returns: a pointer to the newly created widget. */ GtkWidget* visu_ui_box_transform_new() { DBG_fprintf(stderr,"Ui BoxTransform: new object.\n"); return GTK_WIDGET(g_object_new(VISU_TYPE_UI_BOX_TRANSFORM, "orientation", GTK_ORIENTATION_VERTICAL, NULL)); } static gboolean fromExpandToSpin(GBinding *bind, const GValue *source, GValue *target, gpointer data) { float *expand; VisuUiBoxTransform *boxT = VISU_UI_BOX_TRANSFORM(data); expand = (float*)g_value_get_boxed(source); if (g_binding_get_target(bind) == (gpointer)boxT->priv->spinExpandXYZ[0]) g_value_set_double(target, (double)expand[0]); else if (g_binding_get_target(bind) == (gpointer)boxT->priv->spinExpandXYZ[1]) g_value_set_double(target, (double)expand[1]); else if (g_binding_get_target(bind) == (gpointer)boxT->priv->spinExpandXYZ[2]) g_value_set_double(target, (double)expand[2]); return TRUE; } static gboolean fromSpinToExpand(GBinding *bind, const GValue *source, GValue *target, gpointer data) { float expand[3]; VisuUiBoxTransform *boxT = VISU_UI_BOX_TRANSFORM(data); visu_box_getExtension(VISU_BOX(g_binding_get_source(bind)), expand); if (g_binding_get_target(bind) == (gpointer)boxT->priv->spinExpandXYZ[0]) expand[0] = (float)g_value_get_double(source); else if (g_binding_get_target(bind) == (gpointer)boxT->priv->spinExpandXYZ[1]) expand[1] = (float)g_value_get_double(source); else if (g_binding_get_target(bind) == (gpointer)boxT->priv->spinExpandXYZ[2]) expand[2] = (float)g_value_get_double(source); g_value_set_boxed(target, expand); return TRUE; } static void _bindBox(VisuUiBoxTransform *box_transform, VisuBox *box, VisuPointset *model _U_) { int i; if (box_transform->priv->box == box) return; if (box_transform->priv->box) { g_object_unref(G_OBJECT(box_transform->priv->bind_allowExpand)); g_object_unref(G_OBJECT(box_transform->priv->bind_expand[0])); g_object_unref(G_OBJECT(box_transform->priv->bind_expand[1])); g_object_unref(G_OBJECT(box_transform->priv->bind_expand[2])); g_object_unref(G_OBJECT(box_transform->priv->bind_bc)); g_object_unref(G_OBJECT(box_transform->priv->bind_bcWarn)); g_signal_handler_disconnect(G_OBJECT(box_transform->priv->box), box_transform->priv->sig_boundary); g_object_unref(G_OBJECT(box_transform->priv->bind_units)); g_object_unref(G_OBJECT(box_transform->priv->bind_hide)); g_object_unref(G_OBJECT(box_transform->priv->box)); } box_transform->priv->box = box; if (box) { g_object_ref(G_OBJECT(box)); box_transform->priv->bind_allowExpand = g_object_bind_property(box, "use-expansion", box_transform->priv->checkAllowExpand, "active", G_BINDING_BIDIRECTIONAL | G_BINDING_SYNC_CREATE); for (i = 0; i < 3; i++) { box_transform->priv->bind_expand[i] = g_object_bind_property_full(box, "expansion", box_transform->priv->spinExpandXYZ[i], "value", G_BINDING_BIDIRECTIONAL | G_BINDING_SYNC_CREATE, fromExpandToSpin, fromSpinToExpand, box_transform, (GDestroyNotify)0); } box_transform->priv->sig_boundary = g_signal_connect_object(G_OBJECT(box), "notify::boundary", G_CALLBACK(setSensitive), box_transform, G_CONNECT_SWAPPED); setSensitive(box_transform); box_transform->priv->bind_bc = g_object_bind_property_full(box, "boundary", box_transform->priv->labelBc, "label", G_BINDING_SYNC_CREATE, setPeriodicity, NULL, (gpointer)0, (GDestroyNotify)0); box_transform->priv->bind_bcWarn = g_object_bind_property_full(box, "boundary", box_transform->priv->warnBc, "visible", G_BINDING_SYNC_CREATE, setPeriodicityWarning, NULL, (gpointer)0, (GDestroyNotify)0); box_transform->priv->bind_units = g_object_bind_property(box, "units", box_transform->priv->comboUnit, "active", G_BINDING_SYNC_CREATE | G_BINDING_BIDIRECTIONAL); box_transform->priv->bind_hide = g_object_bind_property(box, "hidding-scheme", box_transform->priv->comboHide, "active", G_BINDING_SYNC_CREATE | G_BINDING_BIDIRECTIONAL); } } static gboolean fromTransToSpin(GBinding *bind, const GValue *source, GValue *target, gpointer data) { gfloat *box; VisuUiBoxTransform *boxT = VISU_UI_BOX_TRANSFORM(data); box = (gfloat*)g_value_get_boxed(source); if (g_binding_get_target(bind) == (gpointer)boxT->priv->spinTransXYZ[0]) g_value_set_double(target, (double)box[0]); else if (g_binding_get_target(bind) == (gpointer)boxT->priv->spinTransXYZ[1]) g_value_set_double(target, (double)box[1]); else if (g_binding_get_target(bind) == (gpointer)boxT->priv->spinTransXYZ[2]) g_value_set_double(target, (double)box[2]); return TRUE; } static gboolean fromSpinToTrans(GBinding *bind _U_, const GValue *source _U_, GValue *target, gpointer data) { float trans[3]; VisuUiBoxTransformPrivate *priv = VISU_UI_BOX_TRANSFORM(data)->priv; trans[0] = gtk_spin_button_get_value(GTK_SPIN_BUTTON(priv->spinTransXYZ[0])); trans[1] = gtk_spin_button_get_value(GTK_SPIN_BUTTON(priv->spinTransXYZ[1])); trans[2] = gtk_spin_button_get_value(GTK_SPIN_BUTTON(priv->spinTransXYZ[2])); g_value_set_boxed(target, trans); return TRUE; } /** * visu_ui_box_transform_bind: * @box_transform: a #VisuUiBoxTransform object. * @model: (transfer none): a #VisuPointset object. * * Bind the properties of @model to be displayed by @box_transform. * * Since: 3.8 **/ void visu_ui_box_transform_bind(VisuUiBoxTransform *box_transform, VisuPointset *model) { guint i; g_return_if_fail(VISU_IS_UI_BOX_TRANSFORM(box_transform)); if (box_transform->priv->pointset == model) return; _bindBox(box_transform, (model) ? visu_boxed_getBox(VISU_BOXED(model)) : (VisuBox*)0, model); if (box_transform->priv->pointset) { g_signal_handler_disconnect(G_OBJECT(box_transform->priv->pointset), box_transform->priv->sig_box); g_object_unref(G_OBJECT(box_transform->priv->bind_trans[0])); g_object_unref(G_OBJECT(box_transform->priv->bind_trans[1])); g_object_unref(G_OBJECT(box_transform->priv->bind_trans[2])); g_object_unref(G_OBJECT(box_transform->priv->bind_allowTrans)); g_object_unref(G_OBJECT(box_transform->priv->bind_boxTrans)); g_object_unref(G_OBJECT(box_transform->priv->pointset)); } box_transform->priv->pointset = model; g_object_notify_by_pspec(G_OBJECT(box_transform), properties[POINTSET_PROP]); if (model) { g_object_ref(G_OBJECT(model)); box_transform->priv->sig_box = g_signal_connect_object (G_OBJECT(model), "setBox", G_CALLBACK(_bindBox), box_transform, G_CONNECT_SWAPPED); for (i = 0; i < 3; i++) box_transform->priv->bind_trans[i] = g_object_bind_property_full(model, "reduced-translation", box_transform->priv->spinTransXYZ[i], "value", G_BINDING_BIDIRECTIONAL | G_BINDING_SYNC_CREATE, fromTransToSpin, fromSpinToTrans, box_transform, (GDestroyNotify)0); box_transform->priv->bind_allowTrans = g_object_bind_property(model, "use-translation", box_transform->priv->checkAllowTranslations, "active", G_BINDING_BIDIRECTIONAL | G_BINDING_SYNC_CREATE); box_transform->priv->bind_boxTrans = g_object_bind_property(model, "in-the-box", box_transform->priv->checkInBox, "active", G_BINDING_BIDIRECTIONAL | G_BINDING_SYNC_CREATE); } } /** * visu_ui_box_transform_bindGlExtBox: * @box_transform: a #VisuUiBoxTransform object. * @model: (transfer none): a #VisuGlExtBox object. * * Bind the properties of @model to be displayed by @box_transform. * * Since: 3.8 **/ void visu_ui_box_transform_bindGlExtBox(VisuUiBoxTransform *box_transform, VisuGlExtBox *model) { g_return_if_fail(VISU_IS_UI_BOX_TRANSFORM(box_transform)); if (box_transform->priv->glBox == model) return; if (box_transform->priv->glBox) { g_object_unref(G_OBJECT(box_transform->priv->bind_stipple)); g_object_unref(G_OBJECT(box_transform->priv->bind_color)); g_object_unref(G_OBJECT(box_transform->priv->glBox)); } box_transform->priv->glBox = model; g_object_notify_by_pspec(G_OBJECT(box_transform), properties[GL_BOX_PROP]); if (model) { g_object_ref(G_OBJECT(model)); box_transform->priv->bind_stipple = g_object_bind_property(model, "expand-stipple", box_transform->priv->stippleExpandBox, "value", G_BINDING_BIDIRECTIONAL | G_BINDING_SYNC_CREATE); box_transform->priv->bind_color = g_object_bind_property(model, "side-color", box_transform->priv->colorExpandBox, "color", G_BINDING_BIDIRECTIONAL | G_BINDING_SYNC_CREATE); } } v_sim-3.8.0/src/uiElements/ui_boxTransform.h000066400000000000000000000103261370110300500210620ustar00rootroot00000000000000/* EXTRAITS DE LA LICENCE Copyright CEA, contributeurs : Luc BILLARD et Damien CALISTE, laboratoire L_Sim, (2001-2014) Adresse mèl : BILLARD, non joignable par mèl ; CALISTE, damien P caliste AT cea P fr. Ce logiciel est un programme informatique servant à visualiser des structures atomiques dans un rendu pseudo-3D. Ce logiciel est régi par la licence CeCILL soumise au droit français et respectant les principes de diffusion des logiciels libres. Vous pouvez utiliser, modifier et/ou redistribuer ce programme sous les conditions de la licence CeCILL telle que diffusée par le CEA, le CNRS et l'INRIA sur le site "http://www.cecill.info". Le fait que vous puissiez accéder à cet en-tête signifie que vous avez pris connaissance de la licence CeCILL, et que vous en avez accepté les termes (cf. le fichier Documentation/licence.fr.txt fourni avec ce logiciel). */ /* LICENCE SUM UP Copyright CEA, contributors : Luc BILLARD et Damien CALISTE, laboratoire L_Sim, (2001-2014) E-mail address: BILLARD, not reachable any more ; CALISTE, damien P caliste AT cea P fr. This software is a computer program whose purpose is to visualize atomic configurations in 3D. This software is governed by the CeCILL license under French law and abiding by the rules of distribution of free software. You can use, modify and/ or redistribute the software under the terms of the CeCILL license as circulated by CEA, CNRS and INRIA at the following URL "http://www.cecill.info". The fact that you are presently reading this means that you have had knowledge of the CeCILL license and that you accept its terms. You can find a copy of this licence shipped with this software at Documentation/licence.en.txt. */ #ifndef UI_BOX_TRANSFORM_H #define UI_BOX_TRANSFORM_H #include #include #include /** * VISU_TYPE_UI_BOX_TRANSFORM: * * return the type of #VisuUiBoxTransform. * * Since: 3.8 */ #define VISU_TYPE_UI_BOX_TRANSFORM (visu_ui_box_transform_get_type ()) /** * VISU_UI_BOX_TRANSFORM: * @obj: a #GObject to cast. * * Cast the given @obj into #VisuUiBoxTransform type. * * Since: 3.8 */ #define VISU_UI_BOX_TRANSFORM(obj) (G_TYPE_CHECK_INSTANCE_CAST(obj, VISU_TYPE_UI_BOX_TRANSFORM, VisuUiBoxTransform)) /** * VISU_UI_BOX_TRANSFORM_CLASS: * @klass: a #GObjectClass to cast. * * Cast the given @klass into #VisuUiBoxTransformClass. * * Since: 3.8 */ #define VISU_UI_BOX_TRANSFORM_CLASS(klass) (G_TYPE_CHECK_CLASS_CAST(klass, VISU_TYPE_UI_BOX_TRANSFORM, VisuUiBoxTransformClass)) /** * VISU_IS_UI_BOX_TRANSFORM: * @obj: a #GObject to test. * * Test if the given @ogj is of the type of #VisuUiBoxTransform object. * * Since: 3.8 */ #define VISU_IS_UI_BOX_TRANSFORM(obj) (G_TYPE_CHECK_INSTANCE_TYPE(obj, VISU_TYPE_UI_BOX_TRANSFORM)) /** * VISU_IS_UI_BOX_TRANSFORM_CLASS: * @klass: a #GObjectClass to test. * * Test if the given @klass is of the type of #VisuUiBoxTransformClass class. * * Since: 3.8 */ #define VISU_IS_UI_BOX_TRANSFORM_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE(klass, VISU_TYPE_UI_BOX_TRANSFORM)) /** * VISU_UI_BOX_TRANSFORM_GET_CLASS: * @obj: a #GObject to get the class of. * * It returns the class of the given @obj. * * Since: 3.8 */ #define VISU_UI_BOX_TRANSFORM_GET_CLASS(obj) (G_TYPE_INSTANCE_GET_CLASS(obj, VISU_TYPE_UI_BOX_TRANSFORM, VisuUiBoxTransformClass)) typedef struct _VisuUiBoxTransform VisuUiBoxTransform; typedef struct _VisuUiBoxTransformPrivate VisuUiBoxTransformPrivate; typedef struct _VisuUiBoxTransformClass VisuUiBoxTransformClass; struct _VisuUiBoxTransform { GtkVBox parent; VisuUiBoxTransformPrivate *priv; }; struct _VisuUiBoxTransformClass { GtkVBoxClass parent; }; /** * visu_ui_box_transform_get_type: * * This method returns the type of #VisuUiBoxTransform, use * VISU_TYPE_UI_BOX_TRANSFORM instead. * * Since: 3.8 * * Returns: the type of #VisuUiBoxTransform. */ GType visu_ui_box_transform_get_type(void); GtkWidget* visu_ui_box_transform_new(); void visu_ui_box_transform_bind(VisuUiBoxTransform *box_transform, VisuPointset *model); void visu_ui_box_transform_bindGlExtBox(VisuUiBoxTransform *box_transform, VisuGlExtBox *model); #endif v_sim-3.8.0/src/uiElements/ui_elements.c000066400000000000000000000357531370110300500202200ustar00rootroot00000000000000/* EXTRAITS DE LA LICENCE Copyright CEA, contributeurs : Damien CALISTE, laboratoire L_Sim, (2016) Adresse mèl : CALISTE, damien P caliste AT cea P fr. Ce logiciel est un programme informatique servant à visualiser des structures atomiques dans un rendu pseudo-3D. Ce logiciel est régi par la licence CeCILL soumise au droit français et respectant les principes de diffusion des logiciels libres. Vous pouvez utiliser, modifier et/ou redistribuer ce programme sous les conditions de la licence CeCILL telle que diffusée par le CEA, le CNRS et l'INRIA sur le site "http://www.cecill.info". Le fait que vous puissiez accéder à cet en-tête signifie que vous avez pris connaissance de la licence CeCILL, et que vous en avez accepté les termes (cf. le fichier Documentation/licence.fr.txt fourni avec ce logiciel). */ /* LICENCE SUM UP Copyright CEA, contributors : Damien CALISTE, laboratoire L_Sim, (2016) E-mail address: CALISTE, damien P caliste AT cea P fr. This software is a computer program whose purpose is to visualize atomic configurations in 3D. This software is governed by the CeCILL license under French law and abiding by the rules of distribution of free software. You can use, modify and/ or redistribute the software under the terms of the CeCILL license as circulated by CEA, CNRS and INRIA at the following URL "http://www.cecill.info". The fact that you are presently reading this means that you have had knowledge of the CeCILL license and that you accept its terms. You can find a copy of this licence shipped with this software at Documentation/licence.en.txt. */ #include "ui_elements.h" #include #include #include #include #include #include #include "ui_atomic.h" #include "ui_spin.h" /** * SECTION:ui_elements * @short_description: Defines a widget to setup a elements. * * A set of widgets to setup the rendring of a elements. */ /** * VisuUiPanelElementsNewFunc: * @renderer: a #VisuNodeArrayRenderer object. * * Methods from this interface are called to create new interface for * the given node renderer. */ typedef GtkWidget* (*VisuUiElementsNewFunc)(VisuNodeArrayRenderer *renderer); /** * VisuUiPanelElementsChangeFunc: * @elements: a list of all #VisuElements that are selected. * * Methods from this interface are called whenever the currently selected * elements are changed. */ typedef void (*VisuUiElementsBindFunc)(GtkWidget *widget, GList *elements); struct _IfaceUiRendering { /* setSensitiveFunc sensitiveInterface; */ VisuUiElementsBindFunc bind; VisuUiElementsNewFunc createInterface; }; /** * VisuUiElementsClass: * @parent: the parent class; * * A short way to identify #_VisuUiElementsClass structure. * * Since: 3.8 */ /** * VisuUiElements: * * An opaque structure. * * Since: 3.8 */ /** * VisuUiElementsPrivate: * * Private fields for #VisuUiElements objects. * * Since: 3.8 */ struct _VisuUiElementsPrivate { gboolean dispose_has_run; GtkWidget *combo; GtkWidget *checkRendered; GtkWidget *checkMaskable; GtkWidget *checkColorizable; GtkWidget *color; GtkWidget *childMethod; GHashTable *listOfRenderingInterfaces; struct _IfaceUiRendering *funcs; VisuNodeArrayRenderer *renderer; VisuElementRenderer *model; GBinding *rendered_bind, *maskable_bind, *colorizable_bind; GBinding *color_bind, *material_bind; GList *targets; }; static void visu_ui_elements_dispose(GObject* obj); static void onTypeChanged(VisuNodeArrayRenderer *renderer, GParamSpec *pspec, gpointer data); G_DEFINE_TYPE_WITH_CODE(VisuUiElements, visu_ui_elements, GTK_TYPE_BOX, G_ADD_PRIVATE(VisuUiElements)) static void visu_ui_elements_class_init(VisuUiElementsClass *klass) { DBG_fprintf(stderr, "Ui Elements: creating the class of the widget.\n"); DBG_fprintf(stderr, " - adding new signals ;\n"); /* Connect freeing methods. */ G_OBJECT_CLASS(klass)->dispose = visu_ui_elements_dispose; } static void visu_ui_elements_dispose(GObject *obj) { VisuUiElements *self = VISU_UI_ELEMENTS(obj); DBG_fprintf(stderr, "Ui Elements: dispose object %p.\n", (gpointer)obj); if (self->priv->dispose_has_run) return; self->priv->dispose_has_run = TRUE; visu_ui_elements_bind(self, (GList*)0); /* Chain up to the parent class */ G_OBJECT_CLASS(visu_ui_elements_parent_class)->dispose(obj); } static void visu_ui_elements_init(VisuUiElements *obj) { GtkWidget *label, *expand, *image; GtkWidget *hbox; struct _IfaceUiRendering *wd; #if GTK_MAJOR_VERSION == 2 && GTK_MINOR_VERSION < 12 GtkTooltips *tooltips; tooltips = gtk_tooltips_new (); #endif gtk_orientable_set_orientation(GTK_ORIENTABLE(obj), GTK_ORIENTATION_VERTICAL); obj->priv = visu_ui_elements_get_instance_private(obj); obj->priv->dispose_has_run = FALSE; obj->priv->renderer = (VisuNodeArrayRenderer*)0; obj->priv->model = (VisuElementRenderer*)0; obj->priv->targets = (GList*)0; obj->priv->childMethod = (GtkWidget*)0; obj->priv->funcs = (struct _IfaceUiRendering*)0; obj->priv->listOfRenderingInterfaces = g_hash_table_new_full(g_direct_hash, g_direct_equal, NULL, g_free); wd = g_malloc(sizeof(struct _IfaceUiRendering)); wd->bind = (VisuUiElementsBindFunc)visu_ui_atomic_bind; wd->createInterface = visu_ui_atomic_new; g_hash_table_insert(obj->priv->listOfRenderingInterfaces, GINT_TO_POINTER(VISU_TYPE_DATA_ATOMIC), wd); wd = g_malloc(sizeof(struct _IfaceUiRendering)); wd->bind = (VisuUiElementsBindFunc)visu_ui_spin_bind; wd->createInterface = visu_ui_spin_new; g_hash_table_insert(obj->priv->listOfRenderingInterfaces, GINT_TO_POINTER(VISU_TYPE_DATA_SPIN), wd); gtk_widget_set_margin_start(GTK_WIDGET(obj), 5); gtk_widget_set_margin_end(GTK_WIDGET(obj), 5); hbox = gtk_hbox_new(FALSE, 0); gtk_box_pack_start(GTK_BOX(obj), hbox, FALSE, FALSE, 5); label = gtk_label_new(_("Set caracteristics of: ")); gtk_widget_set_name(label, "label_head"); gtk_label_set_xalign(GTK_LABEL(label), 0.); gtk_label_set_use_markup(GTK_LABEL(label), TRUE); gtk_box_pack_start(GTK_BOX(hbox), label, FALSE, FALSE, 0); /* We create the tree widget that show the methods. */ obj->priv->combo = visu_ui_element_combobox_new(TRUE, FALSE, _("Element '%s'")); visu_ui_element_combobox_setUnphysicalStatus(VISU_UI_ELEMENT_COMBOBOX(obj->priv->combo), TRUE); g_signal_connect_swapped(obj->priv->combo, "element-selected", G_CALLBACK(visu_ui_elements_bind), obj); gtk_box_pack_start(GTK_BOX(hbox), obj->priv->combo, TRUE, TRUE, 0); label = gtk_label_new(""); gtk_label_set_markup(GTK_LABEL(label), _("Standard resources")); gtk_label_set_xalign(GTK_LABEL(label), 0.); gtk_widget_set_name(label, "label_head_2"); gtk_box_pack_start(GTK_BOX(obj), label, FALSE, FALSE, 5); hbox = gtk_hbox_new(FALSE, 0); gtk_box_pack_start(GTK_BOX(obj), hbox, FALSE, FALSE, 0); /* label = gtk_label_new(_("Color: ")); */ /* gtk_box_pack_start(GTK_BOX(hbox), label, FALSE, FALSE, 2); */ obj->priv->color = visu_ui_color_combobox_newWithRanges(TRUE); gtk_box_pack_start(GTK_BOX(hbox), obj->priv->color, FALSE, FALSE, 0); obj->priv->checkRendered = gtk_check_button_new_with_label(_("rendered")); gtk_widget_set_halign(obj->priv->checkRendered, GTK_ALIGN_END); gtk_box_pack_start(GTK_BOX(hbox), obj->priv->checkRendered, TRUE, TRUE, 2); obj->priv->checkMaskable = gtk_check_button_new(); gtk_box_pack_start(GTK_BOX(hbox), obj->priv->checkMaskable, FALSE, FALSE, 0); image = create_pixmap((GtkWidget*)0, "stock-masking.png"); gtk_container_add(GTK_CONTAINER(obj->priv->checkMaskable), image); gtk_widget_set_tooltip_text(obj->priv->checkMaskable, _("Make nodes sensitive to a colorization effect.")); obj->priv->checkColorizable = gtk_check_button_new_with_label(_("colorizable")); gtk_box_pack_start(GTK_BOX(hbox), obj->priv->checkColorizable, FALSE, FALSE, 0); gtk_widget_set_tooltip_text(obj->priv->checkColorizable, _("Make nodes sensitive to the masking effect of planes.")); expand = visu_ui_color_combobox_getRangeWidgets(VISU_UI_COLOR_COMBOBOX(obj->priv->color)); gtk_box_pack_start(GTK_BOX(obj), expand, FALSE, FALSE, 0); label = gtk_label_new(_("Rendering specific resources")); gtk_widget_set_name(label, "label_head_2"); gtk_label_set_xalign(GTK_LABEL(label), 0.); gtk_label_set_use_markup(GTK_LABEL(label), TRUE); gtk_box_pack_start(GTK_BOX(obj), label, FALSE, FALSE, 5); } /** * visu_ui_elements_new: * @renderer: a #VisuNodeArrayRenderer object. * * Creates a new #VisuUiElements to allow to setup elements rendering characteristics. * * Since: 3.8 * * Returns: a pointer to the newly created widget. */ GtkWidget* visu_ui_elements_new(VisuNodeArrayRenderer *renderer) { VisuUiElements *elements; DBG_fprintf(stderr,"Ui Elements: new object.\n"); elements = VISU_UI_ELEMENTS(g_object_new(VISU_TYPE_UI_ELEMENTS, NULL)); elements->priv->renderer = renderer; g_object_bind_property(renderer, "data", elements->priv->combo, "nodes", G_BINDING_SYNC_CREATE); g_object_bind_property(renderer, "data", elements, "sensitive", G_BINDING_SYNC_CREATE); g_signal_connect_object(renderer, "notify::type", G_CALLBACK(onTypeChanged), elements, 0); onTypeChanged(renderer, (GParamSpec*)0, elements); return GTK_WIDGET(elements); } static void _update(VisuUiElements *elements, GtkWidget* wd) { GList *lst; DBG_fprintf(stderr, "Panel Element: change method specific UI.\n"); if (elements->priv->childMethod) { /* note that gtk_destroy automatically remove renderingMethodElements for its container, so a call to gtk_container_remove is not necessary. */ DBG_fprintf(stderr, "Panel Element: removing old rendering specific widget.\n"); gtk_widget_destroy(elements->priv->childMethod); } elements->priv->childMethod = wd; if (wd) { gtk_box_pack_start(GTK_BOX(elements), wd, FALSE, FALSE, 5); gtk_box_reorder_child(GTK_BOX(elements), wd, 6); gtk_widget_show_all(wd); } /* Force refresh on the specific area. */ if (elements->priv->funcs && wd) { lst = visu_ui_element_combobox_getSelection(VISU_UI_ELEMENT_COMBOBOX(elements->priv->combo)); elements->priv->funcs->bind(wd, lst); g_list_free(lst); } } static void onTypeChanged(VisuNodeArrayRenderer *renderer, GParamSpec *pspec _U_, gpointer data) { GType type; struct _IfaceUiRendering *wd; VisuUiElements *elements = VISU_UI_ELEMENTS(data); g_object_get(renderer, "type", &type, NULL); wd = g_hash_table_lookup(elements->priv->listOfRenderingInterfaces, GINT_TO_POINTER(type)); if (wd == elements->priv->funcs) return; elements->priv->funcs = wd; if (wd && wd->createInterface) _update(elements, wd->createInterface(elements->priv->renderer)); else _update(elements, (GtkWidget*)0); } static gboolean setForAll(GBinding *bind, const GValue *source_value, GValue *target_value, gpointer data) { VisuUiElements *elements = VISU_UI_ELEMENTS(data); GList *lst; for (lst = elements->priv->targets; lst; lst = g_list_next(lst)) if (lst->data != elements->priv->model) g_object_set_property(lst->data, g_binding_get_source_property(bind), source_value); return g_value_transform(source_value, target_value); } static void _bind(VisuUiElements *elements, VisuElementRenderer *element) { if (elements->priv->model == element) return; if (elements->priv->model) { g_object_unref(elements->priv->rendered_bind); g_object_unref(elements->priv->maskable_bind); g_object_unref(elements->priv->colorizable_bind); g_object_unref(elements->priv->color_bind); g_object_unref(elements->priv->material_bind); g_object_unref(elements->priv->model); } elements->priv->model = element; if (element) { g_object_ref(element); elements->priv->rendered_bind = g_object_bind_property_full(element, "rendered", elements->priv->checkRendered, "active", G_BINDING_SYNC_CREATE | G_BINDING_BIDIRECTIONAL, NULL, setForAll, elements, (GDestroyNotify)0); elements->priv->maskable_bind = g_object_bind_property_full(element, "maskable", elements->priv->checkMaskable, "active", G_BINDING_SYNC_CREATE | G_BINDING_BIDIRECTIONAL, NULL, setForAll, elements, (GDestroyNotify)0); elements->priv->colorizable_bind = g_object_bind_property_full(visu_element_renderer_getElement(element), "colorizable", elements->priv->checkColorizable, "active", G_BINDING_SYNC_CREATE | G_BINDING_BIDIRECTIONAL, NULL, setForAll, elements, (GDestroyNotify)0); elements->priv->color_bind = g_object_bind_property_full(element, "color", elements->priv->color, "color", G_BINDING_SYNC_CREATE | G_BINDING_BIDIRECTIONAL, NULL, setForAll, elements, (GDestroyNotify)0); elements->priv->material_bind = g_object_bind_property_full(element, "material", elements->priv->color, "material", G_BINDING_SYNC_CREATE | G_BINDING_BIDIRECTIONAL, NULL, setForAll, elements, (GDestroyNotify)0); } } /** * visu_ui_elements_bind: * @elements: a #VisuUiElements object. * @eleList: (element-type VisuElement): a list of #VisuElement. * * Use the list @eleList to be handled by @elements. Any change in * @elements will be applied to the #VisuElementRenderer corresponding * to each #VisuElement of @eleList. * * Since: 3.8 **/ void visu_ui_elements_bind(VisuUiElements *elements, GList *eleList) { GList *lst; g_return_if_fail(VISU_IS_UI_ELEMENTS(elements)); g_return_if_fail(elements->priv->renderer); if (!eleList) _bind(elements, (VisuElementRenderer*)0); else { if (!elements->priv->model || !g_list_find(eleList, visu_element_renderer_getElement(VISU_ELEMENT_RENDERER(elements->priv->model)))) _bind(elements, visu_node_array_renderer_get(elements->priv->renderer, VISU_ELEMENT(eleList->data))); } if (elements->priv->targets) g_list_free(elements->priv->targets); elements->priv->targets = (GList*)0; for (lst = eleList; lst; lst = g_list_next(lst)) elements->priv->targets = g_list_prepend(elements->priv->targets, visu_node_array_renderer_get(elements->priv->renderer, VISU_ELEMENT(lst->data))); if (elements->priv->funcs) elements->priv->funcs->bind(elements->priv->childMethod, eleList); } v_sim-3.8.0/src/uiElements/ui_elements.h000066400000000000000000000074451370110300500202220ustar00rootroot00000000000000/* EXTRAITS DE LA LICENCE Copyright CEA, contributeurs : Damien CALISTE, laboratoire L_Sim, (2016) Adresse mèl : CALISTE, damien P caliste AT cea P fr. Ce logiciel est un programme informatique servant à visualiser des structures atomiques dans un rendu pseudo-3D. Ce logiciel est régi par la licence CeCILL soumise au droit français et respectant les principes de diffusion des logiciels libres. Vous pouvez utiliser, modifier et/ou redistribuer ce programme sous les conditions de la licence CeCILL telle que diffusée par le CEA, le CNRS et l'INRIA sur le site "http://www.cecill.info". Le fait que vous puissiez accéder à cet en-tête signifie que vous avez pris connaissance de la licence CeCILL, et que vous en avez accepté les termes (cf. le fichier Documentation/licence.fr.txt fourni avec ce logiciel). */ /* LICENCE SUM UP Copyright CEA, contributors : Damien CALISTE, laboratoire L_Sim, (2016) E-mail address: CALISTE, damien P caliste AT cea P fr. This software is a computer program whose purpose is to visualize atomic configurations in 3D. This software is governed by the CeCILL license under French law and abiding by the rules of distribution of free software. You can use, modify and/ or redistribute the software under the terms of the CeCILL license as circulated by CEA, CNRS and INRIA at the following URL "http://www.cecill.info". The fact that you are presently reading this means that you have had knowledge of the CeCILL license and that you accept its terms. You can find a copy of this licence shipped with this software at Documentation/licence.en.txt. */ #ifndef UI_ELEMENTS_H #define UI_ELEMENTS_H #include #include /** * VISU_TYPE_UI_ELEMENTS: * * return the type of #VisuUiElements. * * Since: 3.8 */ #define VISU_TYPE_UI_ELEMENTS (visu_ui_elements_get_type ()) /** * VISU_UI_ELEMENTS: * @obj: a #GObject to cast. * * Cast the given @obj into #VisuUiElements type. * * Since: 3.8 */ #define VISU_UI_ELEMENTS(obj) (G_TYPE_CHECK_INSTANCE_CAST(obj, VISU_TYPE_UI_ELEMENTS, VisuUiElements)) /** * VISU_UI_ELEMENTS_CLASS: * @klass: a #GObjectClass to cast. * * Cast the given @klass into #VisuUiElementsClass. * * Since: 3.8 */ #define VISU_UI_ELEMENTS_CLASS(klass) (G_TYPE_CHECK_CLASS_CAST(klass, VISU_TYPE_UI_ELEMENTS, VisuUiElementsClass)) /** * VISU_IS_UI_ELEMENTS: * @obj: a #GObject to test. * * Test if the given @ogj is of the type of #VisuUiElements object. * * Since: 3.8 */ #define VISU_IS_UI_ELEMENTS(obj) (G_TYPE_CHECK_INSTANCE_TYPE(obj, VISU_TYPE_UI_ELEMENTS)) /** * VISU_IS_UI_ELEMENTS_CLASS: * @klass: a #GObjectClass to test. * * Test if the given @klass is of the type of #VisuUiElementsClass class. * * Since: 3.8 */ #define VISU_IS_UI_ELEMENTS_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE(klass, VISU_TYPE_UI_ELEMENTS)) /** * VISU_UI_ELEMENTS_GET_CLASS: * @obj: a #GObject to get the class of. * * It returns the class of the given @obj. * * Since: 3.8 */ #define VISU_UI_ELEMENTS_GET_CLASS(obj) (G_TYPE_INSTANCE_GET_CLASS(obj, VISU_TYPE_UI_ELEMENTS, VisuUiElementsClass)) typedef struct _VisuUiElements VisuUiElements; typedef struct _VisuUiElementsPrivate VisuUiElementsPrivate; typedef struct _VisuUiElementsClass VisuUiElementsClass; struct _VisuUiElements { GtkBox parent; VisuUiElementsPrivate *priv; }; struct _VisuUiElementsClass { GtkBoxClass parent; }; /** * visu_ui_elements_get_type: * * This method returns the type of #VisuUiElements, use * VISU_TYPE_UI_ELEMENTS instead. * * Since: 3.8 * * Returns: the type of #VisuUiElements. */ GType visu_ui_elements_get_type(void); GtkWidget* visu_ui_elements_new(VisuNodeArrayRenderer *renderer); void visu_ui_elements_bind(VisuUiElements *elements, GList *eleList); #endif v_sim-3.8.0/src/uiElements/ui_link.c000066400000000000000000000702751370110300500173370ustar00rootroot00000000000000/* EXTRAITS DE LA LICENCE Copyright CEA, contributeurs : Damien CALISTE, laboratoire L_Sim, (2016) Adresse mèl : CALISTE, damien P caliste AT cea P fr. Ce logiciel est un programme informatique servant à visualiser des structures atomiques dans un rendu pseudo-3D. Ce logiciel est régi par la licence CeCILL soumise au droit français et respectant les principes de diffusion des logiciels libres. Vous pouvez utiliser, modifier et/ou redistribuer ce programme sous les conditions de la licence CeCILL telle que diffusée par le CEA, le CNRS et l'INRIA sur le site "http://www.cecill.info". Le fait que vous puissiez accéder à cet en-tête signifie que vous avez pris connaissance de la licence CeCILL, et que vous en avez accepté les termes (cf. le fichier Documentation/licence.fr.txt fourni avec ce logiciel). */ /* LICENCE SUM UP Copyright CEA, contributors : Damien CALISTE, laboratoire L_Sim, (2016) E-mail address: CALISTE, damien P caliste AT cea P fr. This software is a computer program whose purpose is to visualize atomic configurations in 3D. This software is governed by the CeCILL license under French law and abiding by the rules of distribution of free software. You can use, modify and/ or redistribute the software under the terms of the CeCILL license as circulated by CEA, CNRS and INRIA at the following URL "http://www.cecill.info". The fact that you are presently reading this means that you have had knowledge of the CeCILL license and that you accept its terms. You can find a copy of this licence shipped with this software at Documentation/licence.en.txt. */ #include "ui_link.h" #include #include #include #include #include #include #include #include /** * SECTION:ui_link * @short_description: Defines a widget to setup a link. * * A set of widgets to setup the rendring of a link. */ /** * VisuUiLinkClass: * @parent: the parent class; * * A short way to identify #_VisuUiLinkClass structure. * * Since: 3.8 */ /** * VisuUiLink: * * An opaque structure. * * Since: 3.8 */ /** * VisuUiLinkPrivate: * * Private fields for #VisuUiLink objects. * * Since: 3.8 */ struct _VisuUiLinkPrivate { gboolean dispose_has_run; VisuGlExtPairs *ext; VisuData *dataObj; VisuPairLink *model; GList *addLinks; GtkWidget *spinMin, *spinMax, *comboColor; GBinding *bind_min, *bind_max, *bind_color; GList *renderers; GtkWidget *comboExt; gulong renderer_sig; GtkWidget *vboxWire; GtkWidget *spinThickness, *comboStipple, *comboToolShade, *checkNonLinear; GBinding *bind_width, *bind_stipple, *bind_shade, *bind_useShade; GtkWidget *vboxCylinder; GtkWidget *spinCylinderRadius, *radioCylinderUser, *radioCylinderElement, *radioCylinderNode; GBinding *bind_radius, *bind_user, *bind_element, *bind_node; }; static void visu_ui_link_finalize(GObject* obj); static void visu_ui_link_dispose(GObject* obj); static void visu_ui_link_get_property(GObject* obj, guint property_id, GValue *value, GParamSpec *pspec); static void visu_ui_link_set_property(GObject* obj, guint property_id, const GValue *value, GParamSpec *pspec); enum { PROP_0, MODEL_PROP, EXT_PROP, DATA_PROP, N_PROP }; static GParamSpec *_properties[N_PROP]; static void _setRenderer(VisuUiLink *link, VisuGlExtPairs *ext); static void _bind(VisuUiLink *link, GObject *obj, const gchar *source, const gchar *target); static void _bindFull(VisuUiLink *link, GObject *obj, const gchar *source, const gchar *target, GBindingTransformFunc func, gpointer data); /* Local callbacks. */ static void onDistanceAutoSet(GtkButton *button, VisuUiLink *link); static void onRendererChanged(VisuUiLink *ui, VisuPairLink *link, VisuGlExtPairs *ext); static void onComboChanged(VisuUiLink *ui, GtkComboBox *combo); static gboolean _toCheck(GBinding *binding, const GValue *source_value, GValue *target_value, gpointer data); static gboolean _toEqual(GBinding *binding, const GValue *source_value, GValue *target_value, gpointer data); G_DEFINE_TYPE_WITH_CODE(VisuUiLink, visu_ui_link, GTK_TYPE_BOX, G_ADD_PRIVATE(VisuUiLink)) static void visu_ui_link_class_init(VisuUiLinkClass *klass) { DBG_fprintf(stderr, "Ui Link: creating the class of the widget.\n"); DBG_fprintf(stderr, " - adding new signals ;\n"); /* Connect freeing methods. */ G_OBJECT_CLASS(klass)->dispose = visu_ui_link_dispose; G_OBJECT_CLASS(klass)->finalize = visu_ui_link_finalize; G_OBJECT_CLASS(klass)->set_property = visu_ui_link_set_property; G_OBJECT_CLASS(klass)->get_property = visu_ui_link_get_property; /** * VisuUiLink::model: * * Store the link to display properties of. * * Since: 3.8 */ _properties[MODEL_PROP] = g_param_spec_object("model", "Model", "link to display properties of", VISU_TYPE_PAIR_LINK, G_PARAM_READWRITE); g_object_class_install_property(G_OBJECT_CLASS(klass), MODEL_PROP, _properties[MODEL_PROP]); /** * VisuUiLink::renderer: * * Store the renderer used to draw links. * * Since: 3.8 */ _properties[EXT_PROP] = g_param_spec_object("renderer", "Renderer", "renderer object to draw links", VISU_TYPE_GL_EXT_PAIRS, G_PARAM_READWRITE | G_PARAM_CONSTRUCT_ONLY); g_object_class_install_property(G_OBJECT_CLASS(klass), EXT_PROP, _properties[EXT_PROP]); /** * VisuUiLink::data: * * The full set of nodes, used to calculate the auto-distance. * * Since: 3.8 */ _properties[DATA_PROP] = g_param_spec_object("data", "Data", "full set of nodes", VISU_TYPE_DATA, G_PARAM_READWRITE); g_object_class_install_property(G_OBJECT_CLASS(klass), DATA_PROP, _properties[DATA_PROP]); } static void visu_ui_link_get_property(GObject* obj, guint property_id, GValue *value, GParamSpec *pspec) { VisuUiLink *self = VISU_UI_LINK(obj); DBG_fprintf(stderr, "Ui Link: get property '%s' -> ", g_param_spec_get_name(pspec)); switch (property_id) { case MODEL_PROP: g_value_set_object(value, self->priv->model); DBG_fprintf(stderr, "%p.\n", (gpointer)self->priv->model); break; case EXT_PROP: g_value_set_object(value, self->priv->ext); DBG_fprintf(stderr, "%p.\n", (gpointer)self->priv->ext); break; case DATA_PROP: g_value_set_object(value, self->priv->dataObj); DBG_fprintf(stderr, "%p.\n", g_value_get_object(value)); break; default: /* We don't have any other property... */ G_OBJECT_WARN_INVALID_PROPERTY_ID(obj, property_id, pspec); break; } } static void visu_ui_link_set_property(GObject* obj, guint property_id, const GValue *value, GParamSpec *pspec) { VisuUiLink *self = VISU_UI_LINK(obj); DBG_fprintf(stderr, "Ui Link: set property '%s' -> ", g_param_spec_get_name(pspec)); switch (property_id) { case MODEL_PROP: DBG_fprintf(stderr, "%p.\n", g_value_get_object(value)); visu_ui_link_bind(self, VISU_PAIR_LINK(g_value_get_object(value))); break; case EXT_PROP: DBG_fprintf(stderr, "%p.\n", g_value_get_object(value)); _setRenderer(self, VISU_GL_EXT_PAIRS(g_value_get_object(value))); break; case DATA_PROP: DBG_fprintf(stderr, "%p.\n", g_value_get_object(value)); g_set_object(&self->priv->dataObj, g_value_get_object(value)); break; default: /* We don't have any other property... */ G_OBJECT_WARN_INVALID_PROPERTY_ID(obj, property_id, pspec); break; } } static void visu_ui_link_dispose(GObject *obj) { VisuUiLink *self = VISU_UI_LINK(obj); DBG_fprintf(stderr, "Ui Link: dispose object %p.\n", (gpointer)obj); if (self->priv->dispose_has_run) return; self->priv->dispose_has_run = TRUE; visu_ui_link_bind(self, (VisuPairLink*)0); _setRenderer(self, (VisuGlExtPairs*)0); visu_ui_link_setAddLinks(self, (GList*)0); /* Chain up to the parent class */ G_OBJECT_CLASS(visu_ui_link_parent_class)->dispose(obj); } static void visu_ui_link_finalize(GObject *obj) { g_return_if_fail(obj); DBG_fprintf(stderr, "Ui Link: finalize object %p.\n", (gpointer)obj); g_list_free_full(VISU_UI_LINK(obj)->priv->renderers, g_object_unref); /* Chain up to the parent class */ G_OBJECT_CLASS(visu_ui_link_parent_class)->finalize(obj); DBG_fprintf(stderr, " | freeing ... OK.\n"); } static void visu_ui_link_init(VisuUiLink *obj) { GtkWidget *label, *vbox, *hbox, *wd; #if GTK_MAJOR_VERSION == 2 && GTK_MINOR_VERSION < 12 GtkTooltips *tooltips; tooltips = gtk_tooltips_new (); #endif DBG_fprintf(stderr, "Extension Link: initializing a new object (%p).\n", (gpointer)obj); gtk_orientable_set_orientation(GTK_ORIENTABLE(obj), GTK_ORIENTATION_VERTICAL); obj->priv = visu_ui_link_get_instance_private(obj); obj->priv->dispose_has_run = FALSE; obj->priv->model = (VisuPairLink*)0; obj->priv->ext = (VisuGlExtPairs*)0; obj->priv->dataObj = (VisuData*)0; obj->priv->renderers = (GList*)0; obj->priv->addLinks = (GList*)0; /* Create the part for the link parameters. */ label = gtk_label_new(_("Link parameters:\t " "(apply to one or more selected rows)")); gtk_label_set_use_markup(GTK_LABEL(label), TRUE); gtk_label_set_xalign(GTK_LABEL(label), 0.); gtk_box_pack_start(GTK_BOX(obj), label, FALSE, FALSE, 5); /* Create widgets that apply to all checked pairs. */ vbox = gtk_vbox_new(FALSE, 0); g_object_bind_property(obj, "model", vbox, "sensitive", G_BINDING_SYNC_CREATE); gtk_widget_set_margin_start(vbox, 10); gtk_box_pack_start(GTK_BOX(obj), vbox, FALSE, FALSE, 0); hbox = gtk_hbox_new(FALSE, 3); gtk_box_pack_start(GTK_BOX(vbox), hbox, FALSE, FALSE, 0); label = gtk_label_new(_("From: ")); gtk_box_pack_start(GTK_BOX(hbox), label, FALSE, FALSE, 0); gtk_label_set_xalign(GTK_LABEL(label), 1.0); obj->priv->spinMin = gtk_spin_button_new_with_range(0, 100, 0.05); _bind(obj, G_OBJECT(obj->priv->spinMin), "value", "min"); gtk_spin_button_set_numeric(GTK_SPIN_BUTTON(obj->priv->spinMin), TRUE); gtk_entry_set_width_chars(GTK_ENTRY(obj->priv->spinMin), 4); gtk_box_pack_start(GTK_BOX(hbox), obj->priv->spinMin, FALSE, FALSE, 0); label = gtk_label_new(_(" to: ")); gtk_box_pack_start(GTK_BOX(hbox), label, FALSE, FALSE, 0); gtk_label_set_xalign(GTK_LABEL(label), 1.0); obj->priv->spinMax = gtk_spin_button_new_with_range(0, 100, 0.05); _bind(obj, G_OBJECT(obj->priv->spinMax), "value", "max"); gtk_spin_button_set_numeric(GTK_SPIN_BUTTON(obj->priv->spinMax), TRUE); gtk_entry_set_width_chars(GTK_ENTRY(obj->priv->spinMax), 4); gtk_box_pack_start(GTK_BOX(hbox), obj->priv->spinMax, FALSE, FALSE, 0); wd = gtk_button_new_with_mnemonic(_("_Auto set")); gtk_box_pack_start(GTK_BOX(hbox), wd, FALSE, FALSE, 0); g_signal_connect(G_OBJECT(wd), "clicked", G_CALLBACK(onDistanceAutoSet), obj); gtk_tooltips_set_tip(tooltips, wd, _("Set the distance criterion to select the first" " pick in the distance distribution between all" " nodes of the selected types."), NULL); obj->priv->comboColor = visu_ui_color_combobox_new(TRUE); _bind(obj, G_OBJECT(obj->priv->comboColor), "color", "color"); gtk_box_pack_end(GTK_BOX(hbox), obj->priv->comboColor, FALSE, FALSE, 0); /* The pair method line. */ hbox = gtk_hbox_new(FALSE, 0); gtk_box_pack_start(GTK_BOX(vbox), hbox, FALSE, FALSE, 0); obj->priv->comboExt = gtk_combo_box_text_new(); gtk_box_pack_start(GTK_BOX(hbox), obj->priv->comboExt, FALSE, FALSE, 0); gtk_widget_set_valign(obj->priv->comboExt, GTK_ALIGN_START); obj->priv->vboxWire = gtk_vbox_new(FALSE, 0); gtk_box_pack_end(GTK_BOX(hbox), obj->priv->vboxWire, TRUE, TRUE, 0); obj->priv->vboxCylinder = gtk_vbox_new(FALSE, 0); gtk_box_pack_end(GTK_BOX(hbox), obj->priv->vboxCylinder, TRUE, TRUE, 0); /* The wire interface. */ hbox = gtk_hbox_new(FALSE, 10); gtk_box_pack_start(GTK_BOX(obj->priv->vboxWire), hbox, FALSE, FALSE, 0); label = gtk_label_new(_("Thickness:")); gtk_box_pack_start(GTK_BOX(hbox), label, TRUE, TRUE, 0); gtk_label_set_xalign(GTK_LABEL(label), 1.); obj->priv->spinThickness = gtk_spin_button_new_with_range(1, 10, 1); _bind(obj, G_OBJECT(obj->priv->spinThickness), "value", "width"); gtk_box_pack_start(GTK_BOX(hbox), obj->priv->spinThickness, FALSE, FALSE, 0); gtk_spin_button_set_numeric(GTK_SPIN_BUTTON(obj->priv->spinThickness), TRUE); gtk_entry_set_width_chars(GTK_ENTRY(obj->priv->spinThickness), 3); label = gtk_label_new(_("Pattern:")); gtk_box_pack_start(GTK_BOX(hbox), label, TRUE, TRUE, 0); gtk_label_set_xalign(GTK_LABEL(label), 1.); obj->priv->comboStipple = visu_ui_stipple_combobox_new(); _bind(obj, G_OBJECT(obj->priv->comboStipple), "value", "stipple"); gtk_box_pack_start(GTK_BOX(hbox), obj->priv->comboStipple, FALSE, FALSE, 0); hbox = gtk_hbox_new(FALSE, 0); gtk_box_pack_start(GTK_BOX(obj->priv->vboxWire), hbox, FALSE, FALSE, 0); obj->priv->comboToolShade = visu_ui_shade_combobox_new(TRUE, FALSE); _bind(obj, G_OBJECT(obj->priv->comboToolShade), "shade", "shade"); gtk_box_pack_end(GTK_BOX(hbox), obj->priv->comboToolShade, FALSE, FALSE, 0); obj->priv->checkNonLinear = gtk_check_button_new_with_mnemonic (_("Color _varies with length:")); _bindFull(obj, G_OBJECT(obj->priv->comboToolShade), "active", "shade", _toCheck, obj); gtk_box_pack_end(GTK_BOX(hbox), obj->priv->checkNonLinear, FALSE, FALSE, 0); g_object_bind_property(obj->priv->checkNonLinear, "active", obj->priv->comboToolShade, "sensitive", G_BINDING_SYNC_CREATE); /* The cylinder interface. */ hbox = gtk_hbox_new(FALSE, 10); gtk_box_pack_start(GTK_BOX(obj->priv->vboxCylinder), hbox, FALSE, FALSE, 0); label = gtk_label_new(_("Radius:")); gtk_box_pack_start(GTK_BOX(hbox), label, TRUE, TRUE, 0); gtk_label_set_xalign(GTK_LABEL(label), 1.); obj->priv->spinCylinderRadius = gtk_spin_button_new_with_range(VISU_PAIR_CYLINDER_RADIUS_MIN, VISU_PAIR_CYLINDER_RADIUS_MAX, 0.02); _bind(obj, G_OBJECT(obj->priv->spinCylinderRadius), "value", "radius"); gtk_box_pack_start(GTK_BOX(hbox), obj->priv->spinCylinderRadius, FALSE, FALSE, 0); hbox = gtk_hbox_new(FALSE, 0); gtk_box_pack_start(GTK_BOX(obj->priv->vboxCylinder), hbox, FALSE, FALSE, 0); label = gtk_label_new(_("Color:")); gtk_label_set_xalign(GTK_LABEL(label), 1.); gtk_box_pack_start(GTK_BOX(hbox), label, TRUE, TRUE, 0); obj->priv->radioCylinderUser = gtk_radio_button_new_with_mnemonic(NULL, _("_user defined")); _bindFull(obj, G_OBJECT(obj->priv->radioCylinderUser), "active", "color-type", _toEqual, GINT_TO_POINTER(VISU_CYLINDER_COLOR_USER)); gtk_widget_set_name(obj->priv->radioCylinderUser, "message_radio"); gtk_box_pack_start(GTK_BOX(hbox), obj->priv->radioCylinderUser, FALSE, FALSE, 0); obj->priv->radioCylinderElement = gtk_radio_button_new_with_mnemonic(NULL, _("_elements")); _bindFull(obj, G_OBJECT(obj->priv->radioCylinderElement), "active", "color-type", _toEqual, GINT_TO_POINTER(VISU_CYLINDER_COLOR_ELEMENT)); gtk_widget_set_name(obj->priv->radioCylinderElement, "message_radio"); gtk_box_pack_start(GTK_BOX(hbox), obj->priv->radioCylinderElement, FALSE, FALSE, 0); #if GTK_MAJOR_VERSION >= 3 gtk_radio_button_join_group(GTK_RADIO_BUTTON(obj->priv->radioCylinderElement), GTK_RADIO_BUTTON(obj->priv->radioCylinderUser)); #else gtk_radio_button_set_group(GTK_RADIO_BUTTON(obj->priv->radioCylinderElement), gtk_radio_button_get_group(GTK_RADIO_BUTTON(obj->priv->radioCylinderUser))); #endif obj->priv->radioCylinderNode = gtk_radio_button_new_with_mnemonic(NULL, _("_nodes")); _bindFull(obj, G_OBJECT(obj->priv->radioCylinderNode), "active", "color-type", _toEqual, GINT_TO_POINTER(VISU_CYLINDER_COLOR_NODE)); gtk_widget_set_name(obj->priv->radioCylinderNode, "message_radio"); gtk_box_pack_start(GTK_BOX(hbox), obj->priv->radioCylinderNode, FALSE, FALSE, 0); #if GTK_MAJOR_VERSION >= 3 gtk_radio_button_join_group(GTK_RADIO_BUTTON(obj->priv->radioCylinderNode), GTK_RADIO_BUTTON(obj->priv->radioCylinderUser)); #else gtk_radio_button_set_group(GTK_RADIO_BUTTON(obj->priv->radioCylinderNode), gtk_radio_button_get_group(GTK_RADIO_BUTTON(obj->priv->radioCylinderUser))); #endif gtk_widget_show_all(GTK_WIDGET(obj)); gtk_widget_set_no_show_all(obj->priv->vboxWire, TRUE); gtk_widget_set_no_show_all(obj->priv->vboxCylinder, TRUE); gtk_widget_hide(obj->priv->vboxCylinder); } /** * visu_ui_link_new: * @pairs: a #VisuGlExtPairs object. * * Creates a new #VisuUiLink to allow to setup link rendering characteristics. * * Since: 3.8 * * Returns: a pointer to the newly created widget. */ GtkWidget* visu_ui_link_new(VisuGlExtPairs *pairs) { DBG_fprintf(stderr,"Ui Link: new object.\n"); return GTK_WIDGET(g_object_new(VISU_TYPE_UI_LINK, "renderer", pairs, NULL)); } static GObject* _objectCopy(GObject *data, gpointer add _U_) { return g_object_ref(data); } static void _setRenderer(VisuUiLink *link, VisuGlExtPairs *ext) { GList *lst; gchar *id; if (ext) { g_object_ref(ext); link->priv->renderer_sig = g_signal_connect_swapped(G_OBJECT(ext), "renderer-changed", G_CALLBACK(onRendererChanged), link); } if (link->priv->ext) { g_signal_handler_disconnect(G_OBJECT(link->priv->ext), link->priv->renderer_sig); g_object_unref(link->priv->ext); } link->priv->ext = ext; if (!ext) return; if (link->priv->renderers) g_list_free_full(link->priv->renderers, g_object_unref); link->priv->renderers = g_list_copy_deep(visu_gl_ext_pairs_getAllLinkRenderer(ext), (GCopyFunc)_objectCopy, (gpointer)0); for (lst = link->priv->renderers; lst; lst = g_list_next(lst)) { g_object_get(G_OBJECT(lst->data), "label", &id, NULL); gtk_combo_box_text_append(GTK_COMBO_BOX_TEXT(link->priv->comboExt), NULL, id); g_free(id); } g_signal_connect_swapped(G_OBJECT(link->priv->comboExt), "changed", G_CALLBACK(onComboChanged), link); } static void onRendererChanged(VisuUiLink *ui, VisuPairLink *link, VisuGlExtPairs *ext) { VisuPairLinkRenderer *renderer; if (link != ui->priv->model) return; renderer = visu_gl_ext_pairs_getLinkRenderer(ext, link); gtk_combo_box_set_active(GTK_COMBO_BOX(ui->priv->comboExt), g_list_index(ui->priv->renderers, renderer)); g_object_set(G_OBJECT(ui->priv->vboxWire), "visible", VISU_IS_PAIR_WIRE_RENDERER(renderer) || !ui->priv->model, NULL); g_object_set(G_OBJECT(ui->priv->vboxCylinder), "visible", VISU_IS_PAIR_CYLINDER_RENDERER(renderer), NULL); } static void onComboChanged(VisuUiLink *ui, GtkComboBox *combo) { VisuPairLinkRenderer *renderer; GList *it; renderer = g_list_nth_data(ui->priv->renderers, gtk_combo_box_get_active(combo)); visu_gl_ext_pairs_setLinkRenderer(ui->priv->ext, ui->priv->model, renderer); for (it = ui->priv->addLinks; it; it = g_list_next(it)) visu_gl_ext_pairs_setLinkRenderer(ui->priv->ext, VISU_PAIR_LINK(it->data), renderer); } static gboolean _fromShade(GBinding *binding _U_, const GValue *source_value, GValue *target_value, gpointer data) { VisuUiLink *self = VISU_UI_LINK(data); ToolShade *shade; shade = (ToolShade*)g_value_get_boxed(source_value); gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON(self->priv->checkNonLinear), (shade != (ToolShade*)0)); if (!shade) return FALSE; g_value_set_boxed(target_value, shade); return TRUE; } static gboolean _notNull(GBinding *binding _U_, const GValue *source_value, GValue *target_value, gpointer data _U_) { g_value_set_boolean(target_value, g_value_get_boxed(source_value) != (gpointer)0); return TRUE; } static gboolean _toCheck(GBinding *binding _U_, const GValue *source_value, GValue *target_value, gpointer data) { VisuUiLink *self = VISU_UI_LINK(data); ToolShade *shade; if (g_value_get_boolean(source_value)) shade = visu_ui_shade_combobox_getSelection(VISU_UI_SHADE_COMBOBOX(self->priv->comboToolShade)); else shade = (ToolShade*)0; g_value_set_boxed(target_value, shade); return TRUE; } static gboolean _fromEqual(GBinding *binding _U_, const GValue *source_value, GValue *target_value, gpointer data) { if (g_value_get_uint(source_value) != (guint)GPOINTER_TO_INT(data)) return FALSE; g_value_set_boolean(target_value, TRUE); return TRUE; } static gboolean _toEqual(GBinding *binding _U_, const GValue *source_value, GValue *target_value, gpointer data) { if (!g_value_get_boolean(source_value)) return FALSE; g_value_set_uint(target_value, (guint)GPOINTER_TO_INT(data)); return TRUE; } /** * visu_ui_link_bind: * @link: a #VisuUiLink object. * @model: (transfer full): a #VisuPairLink object. * * Bind the properties of @model to be displayed by @link. * * Since: 3.8 **/ void visu_ui_link_bind(VisuUiLink *link, VisuPairLink *model) { g_return_if_fail(VISU_IS_UI_LINK(link)); if (link->priv->model == model) return; if (link->priv->model) { g_object_unref(G_OBJECT(link->priv->bind_min)); g_object_unref(G_OBJECT(link->priv->bind_max)); g_object_unref(G_OBJECT(link->priv->bind_color)); g_object_unref(G_OBJECT(link->priv->bind_width)); g_object_unref(G_OBJECT(link->priv->bind_stipple)); g_object_unref(G_OBJECT(link->priv->bind_shade)); g_object_unref(G_OBJECT(link->priv->bind_useShade)); g_object_unref(G_OBJECT(link->priv->bind_radius)); g_object_unref(G_OBJECT(link->priv->bind_user)); g_object_unref(G_OBJECT(link->priv->bind_element)); g_object_unref(G_OBJECT(link->priv->bind_node)); g_object_unref(G_OBJECT(link->priv->model)); } link->priv->model = model; if (model) { g_object_ref(G_OBJECT(model)); link->priv->bind_min = g_object_bind_property(model, "min", link->priv->spinMin, "value", G_BINDING_SYNC_CREATE | G_BINDING_BIDIRECTIONAL); link->priv->bind_max = g_object_bind_property(model, "max", link->priv->spinMax, "value", G_BINDING_SYNC_CREATE | G_BINDING_BIDIRECTIONAL); link->priv->bind_color = g_object_bind_property(model, "color", link->priv->comboColor, "color", G_BINDING_SYNC_CREATE | G_BINDING_BIDIRECTIONAL); link->priv->bind_width = g_object_bind_property(model, "width", link->priv->spinThickness, "value", G_BINDING_SYNC_CREATE | G_BINDING_BIDIRECTIONAL); link->priv->bind_stipple = g_object_bind_property(model, "stipple", link->priv->comboStipple, "value", G_BINDING_SYNC_CREATE | G_BINDING_BIDIRECTIONAL); link->priv->bind_shade = g_object_bind_property_full(model, "shade", link->priv->comboToolShade, "shade", G_BINDING_SYNC_CREATE | G_BINDING_BIDIRECTIONAL, _fromShade, NULL, link, (GDestroyNotify)0); link->priv->bind_useShade = g_object_bind_property_full(model, "shade", link->priv->checkNonLinear, "active", G_BINDING_SYNC_CREATE | G_BINDING_BIDIRECTIONAL, _notNull, _toCheck, link, (GDestroyNotify)0); link->priv->bind_radius = g_object_bind_property(model, "radius", link->priv->spinCylinderRadius, "value", G_BINDING_SYNC_CREATE | G_BINDING_BIDIRECTIONAL); link->priv->bind_user = g_object_bind_property_full (model, "color-type", link->priv->radioCylinderUser, "active", G_BINDING_SYNC_CREATE | G_BINDING_BIDIRECTIONAL, _fromEqual, _toEqual, GINT_TO_POINTER(VISU_CYLINDER_COLOR_USER), (GDestroyNotify)0); link->priv->bind_element = g_object_bind_property_full (model, "color-type", link->priv->radioCylinderElement, "active", G_BINDING_SYNC_CREATE | G_BINDING_BIDIRECTIONAL, _fromEqual, _toEqual, GINT_TO_POINTER(VISU_CYLINDER_COLOR_ELEMENT), (GDestroyNotify)0); link->priv->bind_node = g_object_bind_property_full (model, "color-type", link->priv->radioCylinderNode, "active", G_BINDING_SYNC_CREATE | G_BINDING_BIDIRECTIONAL, _fromEqual, _toEqual, GINT_TO_POINTER(VISU_CYLINDER_COLOR_NODE), (GDestroyNotify)0); onRendererChanged(link, model, link->priv->ext); } g_object_notify_by_pspec(G_OBJECT(link), _properties[MODEL_PROP]); } struct _BindData { VisuUiLink *link; const gchar *target; GBindingTransformFunc func; gpointer data; }; static void _freeBind(gpointer data, GClosure *closure _U_) { g_free(data); } static void onNotify(struct _BindData *str, GParamSpec *pspec, GObject *obj) { GValue value = G_VALUE_INIT; GValue target = G_VALUE_INIT; GList *it; if (!str->link->priv->addLinks) return; g_value_init(&value, G_PARAM_SPEC_VALUE_TYPE(pspec)); g_object_get_property(obj, g_param_spec_get_name(pspec), &value); if (!str->func) for (it = str->link->priv->addLinks; it; it = g_list_next(it)) g_object_set_property(G_OBJECT(it->data), str->target, &value); else { pspec = g_object_class_find_property(G_OBJECT_GET_CLASS(str->link->priv->model), str->target); g_value_init(&target, G_PARAM_SPEC_VALUE_TYPE(pspec)); if (str->func((GBinding*)0, &value, &target, str->data)) for (it = str->link->priv->addLinks; it; it = g_list_next(it)) g_object_set_property(G_OBJECT(it->data), str->target, &target); g_value_unset(&target); } g_value_unset(&value); } static void _bind(VisuUiLink *link, GObject *obj, const gchar *source, const gchar *target) { _bindFull(link, obj, source, target, NULL, NULL); } static void _bindFull(VisuUiLink *link, GObject *obj, const gchar *source, const gchar *target, GBindingTransformFunc func, gpointer data) { gchar *id; struct _BindData *str; str = g_malloc(sizeof(struct _BindData)); str->link = link; str->target = target; str->func = func; str->data = data; id = g_strdup_printf("notify::%s", source); g_signal_connect_data(obj, id, G_CALLBACK(onNotify), str, _freeBind, G_CONNECT_SWAPPED); g_free(id); } /** * visu_ui_link_setAddLinks: * @link: a #VisuUiLink object. * @lst: (element-type VisuPairLink): a list of #VisuPairLink objects. * * Set the list of additional #VisuPairLink to be updated when the * model of @link is updated, see visu_ui_link_bind(). * * Since: 3.8 **/ void visu_ui_link_setAddLinks(VisuUiLink *link, GList *lst) { GList *it; g_return_if_fail(VISU_IS_UI_LINK(link)); g_list_free_full(link->priv->addLinks, g_object_unref); link->priv->addLinks = (GList*)0; for (it = lst; it; it = g_list_next(it)) if (it->data != (gpointer)link->priv->model) { g_object_ref(G_OBJECT(it->data)); link->priv->addLinks = g_list_prepend(link->priv->addLinks, it->data); } } static void onDistanceAutoSet(GtkButton *button _U_, VisuUiLink *link) { gfloat from, to; visu_pair_getBondDistance(visu_pair_set_getFromLink(visu_gl_ext_pairs_getSet(link->priv->ext), link->priv->model), link->priv->dataObj, &from, &to); visu_pair_link_setDistance(link->priv->model, from, VISU_DISTANCE_MIN); visu_pair_link_setDistance(link->priv->model, to, VISU_DISTANCE_MAX); } v_sim-3.8.0/src/uiElements/ui_link.h000066400000000000000000000072551370110300500173420ustar00rootroot00000000000000/* EXTRAITS DE LA LICENCE Copyright CEA, contributeurs : Damien CALISTE, laboratoire L_Sim, (2016) Adresse mèl : CALISTE, damien P caliste AT cea P fr. Ce logiciel est un programme informatique servant à visualiser des structures atomiques dans un rendu pseudo-3D. Ce logiciel est régi par la licence CeCILL soumise au droit français et respectant les principes de diffusion des logiciels libres. Vous pouvez utiliser, modifier et/ou redistribuer ce programme sous les conditions de la licence CeCILL telle que diffusée par le CEA, le CNRS et l'INRIA sur le site "http://www.cecill.info". Le fait que vous puissiez accéder à cet en-tête signifie que vous avez pris connaissance de la licence CeCILL, et que vous en avez accepté les termes (cf. le fichier Documentation/licence.fr.txt fourni avec ce logiciel). */ /* LICENCE SUM UP Copyright CEA, contributors : Damien CALISTE, laboratoire L_Sim, (2016) E-mail address: CALISTE, damien P caliste AT cea P fr. This software is a computer program whose purpose is to visualize atomic configurations in 3D. This software is governed by the CeCILL license under French law and abiding by the rules of distribution of free software. You can use, modify and/ or redistribute the software under the terms of the CeCILL license as circulated by CEA, CNRS and INRIA at the following URL "http://www.cecill.info". The fact that you are presently reading this means that you have had knowledge of the CeCILL license and that you accept its terms. You can find a copy of this licence shipped with this software at Documentation/licence.en.txt. */ #ifndef UI_LINK_H #define UI_LINK_H #include #include #include /** * VISU_TYPE_UI_LINK: * * return the type of #VisuUiLink. * * Since: 3.8 */ #define VISU_TYPE_UI_LINK (visu_ui_link_get_type ()) /** * VISU_UI_LINK: * @obj: a #GObject to cast. * * Cast the given @obj into #VisuUiLink type. * * Since: 3.8 */ #define VISU_UI_LINK(obj) (G_TYPE_CHECK_INSTANCE_CAST(obj, VISU_TYPE_UI_LINK, VisuUiLink)) /** * VISU_UI_LINK_CLASS: * @klass: a #GObjectClass to cast. * * Cast the given @klass into #VisuUiLinkClass. * * Since: 3.8 */ #define VISU_UI_LINK_CLASS(klass) (G_TYPE_CHECK_CLASS_CAST(klass, VISU_TYPE_UI_LINK, VisuUiLinkClass)) /** * VISU_IS_UI_LINK: * @obj: a #GObject to test. * * Test if the given @ogj is of the type of #VisuUiLink object. * * Since: 3.8 */ #define VISU_IS_UI_LINK(obj) (G_TYPE_CHECK_INSTANCE_TYPE(obj, VISU_TYPE_UI_LINK)) /** * VISU_IS_UI_LINK_CLASS: * @klass: a #GObjectClass to test. * * Test if the given @klass is of the type of #VisuUiLinkClass class. * * Since: 3.8 */ #define VISU_IS_UI_LINK_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE(klass, VISU_TYPE_UI_LINK)) /** * VISU_UI_LINK_GET_CLASS: * @obj: a #GObject to get the class of. * * It returns the class of the given @obj. * * Since: 3.8 */ #define VISU_UI_LINK_GET_CLASS(obj) (G_TYPE_INSTANCE_GET_CLASS(obj, VISU_TYPE_UI_LINK, VisuUiLinkClass)) typedef struct _VisuUiLink VisuUiLink; typedef struct _VisuUiLinkPrivate VisuUiLinkPrivate; typedef struct _VisuUiLinkClass VisuUiLinkClass; struct _VisuUiLink { GtkBox parent; VisuUiLinkPrivate *priv; }; struct _VisuUiLinkClass { GtkBoxClass parent; }; /** * visu_ui_link_get_type: * * This method returns the type of #VisuUiLink, use * VISU_TYPE_UI_LINK instead. * * Since: 3.8 * * Returns: the type of #VisuUiLink. */ GType visu_ui_link_get_type(void); GtkWidget* visu_ui_link_new(VisuGlExtPairs *pairs); void visu_ui_link_bind(VisuUiLink *link, VisuPairLink *model); void visu_ui_link_setAddLinks(VisuUiLink *link, GList *lst); #endif v_sim-3.8.0/src/uiElements/ui_pairtree.c000066400000000000000000001260351370110300500202110ustar00rootroot00000000000000/* EXTRAITS DE LA LICENCE Copyright CEA, contributeurs : Damien CALISTE, laboratoire L_Sim, (2016) Adresse mèl : CALISTE, damien P caliste AT cea P fr. Ce logiciel est un programme informatique servant à visualiser des structures atomiques dans un rendu pseudo-3D. Ce logiciel est régi par la licence CeCILL soumise au droit français et respectant les principes de diffusion des logiciels libres. Vous pouvez utiliser, modifier et/ou redistribuer ce programme sous les conditions de la licence CeCILL telle que diffusée par le CEA, le CNRS et l'INRIA sur le site "http://www.cecill.info". Le fait que vous puissiez accéder à cet en-tête signifie que vous avez pris connaissance de la licence CeCILL, et que vous en avez accepté les termes (cf. le fichier Documentation/licence.fr.txt fourni avec ce logiciel). */ /* LICENCE SUM UP Copyright CEA, contributors : Damien CALISTE, laboratoire L_Sim, (2016) E-mail address: CALISTE, damien P caliste AT cea P fr. This software is a computer program whose purpose is to visualize atomic configurations in 3D. This software is governed by the CeCILL license under French law and abiding by the rules of distribution of free software. You can use, modify and/ or redistribute the software under the terms of the CeCILL license as circulated by CEA, CNRS and INRIA at the following URL "http://www.cecill.info". The fact that you are presently reading this means that you have had knowledge of the CeCILL license and that you accept its terms. You can find a copy of this licence shipped with this software at Documentation/licence.en.txt. */ #include "ui_pairtree.h" #include #include #include #include #include #include #include #include #include #include #include /** * SECTION:ui_pairtree * @short_description: Defines a widget to setup a link. * * A set of widgets to setup the rendring of a link. */ /** * VisuUiPairTreeClass: * @parent: the parent class; * * A short way to identify #_VisuUiPairTreeClass structure. * * Since: 3.8 */ /** * VisuUiPairTree: * * An opaque structure. * * Since: 3.8 */ /** * VisuUiPairTreePrivate: * * Private fields for #VisuUiPairTree objects. * * Since: 3.8 */ struct _VisuUiPairTreePrivate { gboolean dispose_has_run; VisuGlExtPairs *ext; gulong renderer_sig; VisuPairSet *model; GBinding *model_bind; gulong pairs_sig; GtkTreeModel *treemodel, *filtermodel, *sortmodel; GtkWidget *toolbar, *filter; GtkToolItem *hideBt; VisuPairLink *selectedLink; }; static void visu_ui_pair_tree_finalize(GObject* obj); static void visu_ui_pair_tree_dispose(GObject* obj); static void visu_ui_pair_tree_get_property(GObject* obj, guint property_id, GValue *value, GParamSpec *pspec); static void visu_ui_pair_tree_set_property(GObject* obj, guint property_id, const GValue *value, GParamSpec *pspec); enum { PROP_0, MODEL_PROP, EXT_PROP, LINK_PROP, N_PROP }; static GParamSpec *_properties[N_PROP]; enum { SEL_SIGNAL, LAST_SIGNAL }; static guint _signals[LAST_SIGNAL] = { 0 }; /* This enum is used to access the column of the liststore have the data of pairs. */ enum { POINTER_TO_LINK, COL_SIGNALS, N_COLUMNS }; typedef struct _RowLink { guint refcount; VisuPairLink *link; gulong notify_sig; VisuPair *pair; gulong links_sig; } RowLink; #define TYPE_ROW_LINK (row_link_get_type()) static GType row_link_get_type(void); static void _setRenderer(VisuUiPairTree *tree, VisuGlExtPairs *ext); static void _formatElements(GtkTreeViewColumn *column, GtkCellRenderer *cell, GtkTreeModel *model, GtkTreeIter *iter, gpointer data); static void _formatDrawn(GtkTreeViewColumn *column, GtkCellRenderer *cell, GtkTreeModel *model, GtkTreeIter *iter, gpointer data); static void _formatDistance(GtkTreeViewColumn *column, GtkCellRenderer *cell, GtkTreeModel *model, GtkTreeIter *iter, gpointer data); static void _formatPrintLength(GtkTreeViewColumn *column, GtkCellRenderer *cell, GtkTreeModel *model, GtkTreeIter *iter, gpointer data); static void _formatColor(GtkTreeViewColumn *column, GtkCellRenderer *cell, GtkTreeModel *model, GtkTreeIter *iter, gpointer data); static void _formatDescription(GtkTreeViewColumn *column, GtkCellRenderer *cell, GtkTreeModel *model, GtkTreeIter *iter, gpointer data); static gint _sortLinks(GtkTreeModel *model, GtkTreeIter *a, GtkTreeIter *b, gpointer data); static gboolean _filter(GtkTreeModel *model, GtkTreeIter *iter, gpointer data); static void _expandLink(VisuUiPairTree *tree, VisuPairLink *link); static void _selectLink(VisuUiPairTree *tree, VisuPairLink *link); static void _selectPair(VisuUiPairTree *tree, VisuPair *pair); /* Local callbacks. */ static void onPairsNotified(VisuPairSet *set, GParamSpec *pspec, VisuUiPairTree *tree); static void onRendererChanged(VisuUiPairTree *tree, VisuPairLink *link, VisuGlExtPairs *ext); static void onDrawnToggled(GtkCellRendererToggle *cell_renderer, gchar *path, VisuUiPairTree *self); static void onDistanceMinEdited(GtkCellRendererText *cellrenderertext, gchar *path, gchar *text, VisuUiPairTree *self); static void onDistanceMaxEdited(GtkCellRendererText *cellrenderertext, gchar *path, gchar *text, VisuUiPairTree *self); static void onLengthToggled(GtkCellRendererToggle *cell_renderer, gchar *path, VisuUiPairTree *self); static void onSelectionChanged(VisuUiPairTree *self, GtkTreeSelection *selection); static void onLinkNotified(GtkTreeRowReference *ref, GParamSpec *pspec, VisuPairLink *link); static void onLinksNotified(GtkTreeRowReference *ref, GParamSpec *pspec, VisuPair *pair); static void onAdd(VisuUiPairTree *tree, GtkButton *button); static void onRemove(VisuUiPairTree *tree, GtkButton *button); static void onFilter(VisuUiPairTree *tree, GtkButton *button); static void onFilterChanged(VisuUiPairTree *tree, GList *elements, VisuUiElementCombobox *combobox); G_DEFINE_TYPE_WITH_CODE(VisuUiPairTree, visu_ui_pair_tree, GTK_TYPE_TREE_VIEW, G_ADD_PRIVATE(VisuUiPairTree)) static void visu_ui_pair_tree_class_init(VisuUiPairTreeClass *klass) { DBG_fprintf(stderr, "Ui PairTree: creating the class of the widget.\n"); DBG_fprintf(stderr, " - adding new signals ;\n"); /* Connect freeing methods. */ G_OBJECT_CLASS(klass)->dispose = visu_ui_pair_tree_dispose; G_OBJECT_CLASS(klass)->finalize = visu_ui_pair_tree_finalize; G_OBJECT_CLASS(klass)->set_property = visu_ui_pair_tree_set_property; G_OBJECT_CLASS(klass)->get_property = visu_ui_pair_tree_get_property; /** * VisuUiPairTree::model: * * Store the link to display properties of. * * Since: 3.8 */ _properties[MODEL_PROP] = g_param_spec_object("model", "Model", "link to display properties of", VISU_TYPE_PAIR_LINK, G_PARAM_READWRITE); g_object_class_install_property(G_OBJECT_CLASS(klass), MODEL_PROP, _properties[MODEL_PROP]); /** * VisuUiPairTree::renderer: * * Store the renderer used to draw links. * * Since: 3.8 */ _properties[EXT_PROP] = g_param_spec_object("renderer", "Renderer", "renderer object to draw links", VISU_TYPE_GL_EXT_PAIRS, G_PARAM_READWRITE | G_PARAM_CONSTRUCT_ONLY); g_object_class_install_property(G_OBJECT_CLASS(klass), EXT_PROP, _properties[EXT_PROP]); /** * VisuUiPairTree::selected-link: * * Store the currently selected link. In case of multi-selection, * this property stores the first selection in the list. * * Since: 3.8 */ _properties[LINK_PROP] = g_param_spec_object("selected-link", "Selected link", "currently selected link (first one in a list)", VISU_TYPE_PAIR_LINK, G_PARAM_READABLE); g_object_class_install_property(G_OBJECT_CLASS(klass), LINK_PROP, _properties[LINK_PROP]); /** * VisuUiPairTree::selection-changed: * @tree: the object which emits the signal ; * @links: (type VisuPairLink) (transfer none): a list of * #VisuPairLink objects. * * Gets emitted when the selection change. * * Since: 3.8 */ _signals[SEL_SIGNAL] = g_signal_new("selection-changed", G_TYPE_FROM_CLASS(klass), G_SIGNAL_RUN_LAST | G_SIGNAL_NO_RECURSE | G_SIGNAL_NO_HOOKS, 0 , NULL, NULL, g_cclosure_marshal_VOID__POINTER, G_TYPE_NONE, 1, G_TYPE_POINTER); } static void visu_ui_pair_tree_get_property(GObject* obj, guint property_id, GValue *value, GParamSpec *pspec) { VisuUiPairTree *self = VISU_UI_PAIR_TREE(obj); DBG_fprintf(stderr, "Ui PairTree: get property '%s' -> ", g_param_spec_get_name(pspec)); switch (property_id) { case MODEL_PROP: g_value_set_object(value, self->priv->model); DBG_fprintf(stderr, "%p.\n", (gpointer)self->priv->model); break; case EXT_PROP: g_value_set_object(value, self->priv->ext); DBG_fprintf(stderr, "%p.\n", (gpointer)self->priv->ext); break; case LINK_PROP: g_value_set_object(value, self->priv->selectedLink); DBG_fprintf(stderr, "%p.\n", (gpointer)self->priv->selectedLink); break; default: /* We don't have any other property... */ G_OBJECT_WARN_INVALID_PROPERTY_ID(obj, property_id, pspec); break; } } static void visu_ui_pair_tree_set_property(GObject* obj, guint property_id, const GValue *value, GParamSpec *pspec) { VisuUiPairTree *self = VISU_UI_PAIR_TREE(obj); DBG_fprintf(stderr, "Ui PairTree: set property '%s' -> ", g_param_spec_get_name(pspec)); switch (property_id) { case MODEL_PROP: DBG_fprintf(stderr, "%p.\n", (gpointer)g_value_get_object(value)); visu_ui_pair_tree_bind(self, VISU_PAIR_SET(g_value_get_object(value))); break; case EXT_PROP: DBG_fprintf(stderr, "%p.\n", (gpointer)g_value_get_object(value)); _setRenderer(self, VISU_GL_EXT_PAIRS(g_value_get_object(value))); break; default: /* We don't have any other property... */ G_OBJECT_WARN_INVALID_PROPERTY_ID(obj, property_id, pspec); break; } } static void visu_ui_pair_tree_dispose(GObject *obj) { VisuUiPairTree *self = VISU_UI_PAIR_TREE(obj); DBG_fprintf(stderr, "Ui PairTree: dispose object %p.\n", (gpointer)obj); if (self->priv->dispose_has_run) return; self->priv->dispose_has_run = TRUE; visu_ui_pair_tree_bind(self, (VisuPairSet*)0); _setRenderer(self, (VisuGlExtPairs*)0); if (self->priv->selectedLink) g_object_unref(self->priv->selectedLink); if (self->priv->toolbar) g_object_unref(self->priv->toolbar); if (self->priv->filter) g_object_unref(self->priv->filter); gtk_tree_store_clear(GTK_TREE_STORE(VISU_UI_PAIR_TREE(obj)->priv->treemodel)); /* Chain up to the parent class */ G_OBJECT_CLASS(visu_ui_pair_tree_parent_class)->dispose(obj); } static void visu_ui_pair_tree_finalize(GObject *obj) { g_return_if_fail(obj); DBG_fprintf(stderr, "Ui PairTree: finalize object %p.\n", (gpointer)obj); DBG_fprintf(stderr, " | sort has (%d) ref counts.\n", G_OBJECT(VISU_UI_PAIR_TREE(obj)->priv->sortmodel)->ref_count); g_object_unref(VISU_UI_PAIR_TREE(obj)->priv->sortmodel); DBG_fprintf(stderr, " | filter has (%d) ref counts.\n", G_OBJECT(VISU_UI_PAIR_TREE(obj)->priv->filtermodel)->ref_count); g_object_unref(VISU_UI_PAIR_TREE(obj)->priv->filtermodel); DBG_fprintf(stderr, " | model has (%d) ref counts.\n", G_OBJECT(VISU_UI_PAIR_TREE(obj)->priv->treemodel)->ref_count); g_object_unref(VISU_UI_PAIR_TREE(obj)->priv->treemodel); /* Chain up to the parent class */ G_OBJECT_CLASS(visu_ui_pair_tree_parent_class)->finalize(obj); DBG_fprintf(stderr, " | freeing ... OK.\n"); } static void visu_ui_pair_tree_init(VisuUiPairTree *obj) { GtkCellRenderer *renderer; GtkTreeViewColumn *column; #if GTK_MAJOR_VERSION == 2 && GTK_MINOR_VERSION < 12 GtkTooltips *tooltips; tooltips = gtk_tooltips_new (); #endif DBG_fprintf(stderr, "Extension PairTree: initializing a new object (%p).\n", (gpointer)obj); obj->priv = visu_ui_pair_tree_get_instance_private(obj); obj->priv->dispose_has_run = FALSE; obj->priv->model = (VisuPairSet*)0; obj->priv->model_bind = (GBinding*)0; obj->priv->ext = (VisuGlExtPairs*)0; obj->priv->selectedLink = (VisuPairLink*)0; obj->priv->toolbar = (GtkWidget*)0; obj->priv->hideBt = (GtkToolItem*)0; g_object_set(G_OBJECT(obj), "rules-hint", TRUE, NULL); gtk_tree_view_set_headers_visible(GTK_TREE_VIEW(obj), TRUE); /* Create the listModel for pairs data*/ obj->priv->treemodel = GTK_TREE_MODEL(gtk_tree_store_new(N_COLUMNS, VISU_TYPE_PAIR_LINK, TYPE_ROW_LINK)); /* Render the associated tree */ renderer = gtk_cell_renderer_text_new (); column = gtk_tree_view_column_new(); gtk_tree_view_column_set_title(column, _("Pair")); gtk_tree_view_column_set_sort_indicator(column, TRUE); gtk_tree_view_column_set_sort_order(column, GTK_SORT_ASCENDING); gtk_tree_view_column_pack_start(column, renderer, TRUE); gtk_tree_view_column_set_cell_data_func(column, renderer, _formatElements, (gpointer)0, (GDestroyNotify)0); gtk_tree_view_column_set_sort_column_id(column, POINTER_TO_LINK); renderer = gtk_cell_renderer_toggle_new (); g_signal_connect(G_OBJECT(renderer), "toggled", G_CALLBACK(onDrawnToggled), obj); gtk_tree_view_column_pack_end(column, renderer, FALSE); gtk_tree_view_column_set_cell_data_func(column, renderer, _formatDrawn, (gpointer)0, (GDestroyNotify)0); gtk_tree_view_append_column(GTK_TREE_VIEW(obj), column); renderer = gtk_cell_renderer_text_new(); g_object_set(G_OBJECT(renderer), "editable", TRUE, "foreground", "blue", NULL); g_signal_connect(G_OBJECT(renderer), "edited", G_CALLBACK(onDistanceMinEdited), obj); column = gtk_tree_view_column_new(); gtk_tree_view_column_set_title(column, _("From")); gtk_tree_view_column_pack_start(column, renderer, TRUE); gtk_tree_view_column_set_cell_data_func(column, renderer, _formatDistance, GINT_TO_POINTER(VISU_DISTANCE_MIN), (GDestroyNotify)0); gtk_tree_view_append_column(GTK_TREE_VIEW(obj), column); renderer = gtk_cell_renderer_text_new(); g_object_set(G_OBJECT(renderer), "editable", TRUE, "foreground", "blue", NULL); g_signal_connect(G_OBJECT(renderer), "edited", G_CALLBACK(onDistanceMaxEdited), obj); column = gtk_tree_view_column_new(); gtk_tree_view_column_set_title(column, _("To")); gtk_tree_view_column_pack_start(column, renderer, TRUE); gtk_tree_view_column_set_cell_data_func(column, renderer, _formatDistance, GINT_TO_POINTER(VISU_DISTANCE_MAX), (GDestroyNotify)0); gtk_tree_view_append_column(GTK_TREE_VIEW(obj), column); renderer = gtk_cell_renderer_toggle_new (); g_signal_connect(G_OBJECT(renderer), "toggled", G_CALLBACK(onLengthToggled), obj); column = gtk_tree_view_column_new(); gtk_tree_view_column_set_title(column, _("Lg.")); gtk_tree_view_column_pack_start(column, renderer, TRUE); gtk_tree_view_column_set_cell_data_func(column, renderer, _formatPrintLength, (gpointer)0, (GDestroyNotify)0); gtk_tree_view_append_column(GTK_TREE_VIEW(obj), column); column = gtk_tree_view_column_new(); gtk_tree_view_column_set_title(column, _("Parameters")); renderer = gtk_cell_renderer_pixbuf_new(); gtk_tree_view_column_pack_start(column, renderer, FALSE); gtk_tree_view_column_set_cell_data_func(column, renderer, _formatColor, (gpointer)0, (GDestroyNotify)0); renderer = gtk_cell_renderer_text_new(); gtk_tree_view_column_pack_start(column, renderer, TRUE); gtk_tree_view_column_set_cell_data_func(column, renderer, _formatDescription, (gpointer)obj, (GDestroyNotify)0); gtk_tree_view_append_column(GTK_TREE_VIEW(obj), column); gtk_widget_show_all(GTK_WIDGET(obj)); DBG_fprintf(stderr, "Ui PairTree: model has %d ref counts.\n", G_OBJECT(obj->priv->treemodel)->ref_count); obj->priv->filtermodel = gtk_tree_model_filter_new(obj->priv->treemodel, NULL); gtk_tree_model_filter_set_visible_func(GTK_TREE_MODEL_FILTER(obj->priv->filtermodel), _filter, (gpointer)obj, (GDestroyNotify)0); obj->priv->sortmodel = gtk_tree_model_sort_new_with_model(obj->priv->filtermodel); gtk_tree_sortable_set_sort_column_id(GTK_TREE_SORTABLE(obj->priv->sortmodel), POINTER_TO_LINK, GTK_SORT_ASCENDING); gtk_tree_sortable_set_sort_func(GTK_TREE_SORTABLE(obj->priv->sortmodel), POINTER_TO_LINK, _sortLinks, (gpointer)0, NULL); gtk_tree_selection_set_mode(gtk_tree_view_get_selection(GTK_TREE_VIEW(obj)), GTK_SELECTION_MULTIPLE); gtk_tree_view_set_model(GTK_TREE_VIEW(obj), obj->priv->sortmodel); g_signal_connect_swapped(G_OBJECT(gtk_tree_view_get_selection(GTK_TREE_VIEW(obj))), "changed", G_CALLBACK(onSelectionChanged), obj); DBG_fprintf(stderr, "Ui PairTree: model has %d ref counts.\n", G_OBJECT(obj->priv->treemodel)->ref_count); } /** * visu_ui_pair_tree_new: * @pairs: a #VisuGlExtPairs object. * * Creates a new #VisuUiPairTree to allow to setup link rendering characteristics. * * Since: 3.8 * * Returns: a pointer to the newly created widget. */ GtkWidget* visu_ui_pair_tree_new(VisuGlExtPairs *pairs) { DBG_fprintf(stderr,"Ui PairTree: new object.\n"); return GTK_WIDGET(g_object_new(VISU_TYPE_UI_PAIR_TREE, "renderer", pairs, NULL)); } /** * visu_ui_pair_tree_bind: * @tree: a #VisuUiPairTree object. * @model: a #VisuPairSet object. * * Binds @model to @tree, so every #VisuPairLink of @model are always * listed into @tree. * * Since: 3.8 **/ void visu_ui_pair_tree_bind(VisuUiPairTree *tree, VisuPairSet *model) { if (tree->priv->model) { if (tree->priv->model_bind && tree->priv->filter) g_object_unref(tree->priv->model_bind); /* g_signal_handler_disconnect(G_OBJECT(tree->priv->ext), tree->priv->renderer_sig); */ g_signal_handler_disconnect(tree->priv->model, tree->priv->pairs_sig); g_object_unref(tree->priv->model); } if (model) { g_object_ref(model); /* tree->priv->renderer_sig = g_signal_connect_swapped(G_OBJECT(ext), "renderer-changed", */ /* G_CALLBACK(onRendererChanged), tree); */ if (tree->priv->filter) tree->priv->model_bind = g_object_bind_property(model, "data", tree->priv->filter, "nodes", G_BINDING_SYNC_CREATE); tree->priv->pairs_sig = g_signal_connect(model, "notify::pairs", G_CALLBACK(onPairsNotified), tree); onPairsNotified(model, (GParamSpec*)0, tree); } tree->priv->model = model; g_object_notify_by_pspec(G_OBJECT(tree), _properties[MODEL_PROP]); } static void _setRenderer(VisuUiPairTree *tree, VisuGlExtPairs *ext) { if (tree->priv->ext) { g_signal_handler_disconnect(G_OBJECT(tree->priv->ext), tree->priv->renderer_sig); g_object_unref(tree->priv->ext); } if (ext) { g_object_ref(ext); tree->priv->renderer_sig = g_signal_connect_swapped(G_OBJECT(ext), "renderer-changed", G_CALLBACK(onRendererChanged), tree); } tree->priv->ext = ext; } static void _notifyFor(GtkTreeModel *model, GtkTreeIter *iter, VisuPairLink *link) { VisuPairLink *tmp; GtkTreePath *path; gtk_tree_model_get(model, iter, POINTER_TO_LINK, &tmp, -1); if (tmp == link) { path = gtk_tree_model_get_path(model, iter); gtk_tree_model_row_changed(model, path, iter); gtk_tree_path_free(path); } g_object_unref(G_OBJECT(tmp)); } static void onRendererChanged(VisuUiPairTree *tree, VisuPairLink *link, VisuGlExtPairs *ext _U_) { GtkTreeIter it, child; gboolean valid, valid2; DBG_fprintf(stderr, "Ui PairTree: (onRendererChanged) model has %d ref counts.\n", G_OBJECT(tree->priv->treemodel)->ref_count); for (valid = gtk_tree_model_get_iter_first(tree->priv->treemodel, &it); valid; valid = gtk_tree_model_iter_next(tree->priv->treemodel, &it)) { _notifyFor(tree->priv->treemodel, &it, link); for (valid2 = gtk_tree_model_iter_children(tree->priv->treemodel, &child, &it); valid2; valid2 = gtk_tree_model_iter_next(tree->priv->treemodel, &child)) _notifyFor(tree->priv->treemodel, &child, link); } DBG_fprintf(stderr, "Ui PairTree: (onRendererChanged) model has %d ref counts.\n", G_OBJECT(tree->priv->treemodel)->ref_count); } static void _formatElements(GtkTreeViewColumn *column _U_, GtkCellRenderer *cell, GtkTreeModel *model, GtkTreeIter *iter, gpointer data _U_) { gchar lbl[128]; VisuElement *ele1, *ele2; VisuPairLink *link; GtkTreeIter parent; if (gtk_tree_model_iter_parent(model, &parent, iter)) lbl[0] = '\0'; else { gtk_tree_model_get(model, iter, POINTER_TO_LINK, &link, -1); ele1 = visu_pair_link_getFirstElement(link); ele2 = visu_pair_link_getSecondElement(link); if (strcmp(ele1->name, ele2->name) < 0) sprintf(lbl, "%s - %s", ele1->name, ele2->name); else sprintf(lbl, "%s - %s", ele2->name, ele1->name); g_object_unref(G_OBJECT(link)); g_object_unref(G_OBJECT(ele1)); g_object_unref(G_OBJECT(ele2)); } g_object_set(G_OBJECT(cell), "text", lbl, NULL); } static void _formatDrawn(GtkTreeViewColumn *column _U_, GtkCellRenderer *cell, GtkTreeModel *model, GtkTreeIter *iter, gpointer data _U_) { VisuPairLink *link; gtk_tree_model_get(model, iter, POINTER_TO_LINK, &link, -1); g_object_set(G_OBJECT(cell), "active", visu_pair_link_getDrawn(link), NULL); g_object_unref(G_OBJECT(link)); } static void _formatDistance(GtkTreeViewColumn *column _U_, GtkCellRenderer *cell, GtkTreeModel *model, GtkTreeIter *iter, gpointer data) { gchar dist[18]; VisuPairLink *link; ToolUnits units; gtk_tree_model_get(model, iter, POINTER_TO_LINK, &link, -1); units = visu_pair_link_getUnits(link); if (units == TOOL_UNITS_UNDEFINED) sprintf(dist, "%6.3f", visu_pair_link_getDistance(link, GPOINTER_TO_INT(data))); else sprintf(dist, "%6.3f %s", visu_pair_link_getDistance(link, GPOINTER_TO_INT(data)), tool_physic_getUnitLabel(units)); g_object_set(G_OBJECT(cell), "markup", dist, NULL); g_object_unref(G_OBJECT(link)); } static void _formatPrintLength(GtkTreeViewColumn *column _U_, GtkCellRenderer *cell, GtkTreeModel *model, GtkTreeIter *iter, gpointer data _U_) { VisuPairLink *link; gtk_tree_model_get(model, iter, POINTER_TO_LINK, &link, -1); g_object_set(G_OBJECT(cell), "active", visu_pair_link_getPrintLength(link), NULL); g_object_unref(G_OBJECT(link)); } static void _formatColor(GtkTreeViewColumn *column _U_, GtkCellRenderer *cell, GtkTreeModel *model, GtkTreeIter *iter, gpointer data _U_) { VisuPairLink *link; ToolColor *color; GdkPixbuf *pixColor; gtk_tree_model_get(model, iter, POINTER_TO_LINK, &link, -1); color = visu_pair_link_getColor(link); pixColor = tool_color_get_stamp(color, TRUE); g_object_unref(link); g_object_set(G_OBJECT(cell), "pixbuf", pixColor, NULL); g_object_unref(pixColor); } static void _formatDescription(GtkTreeViewColumn *column _U_, GtkCellRenderer *cell, GtkTreeModel *model, GtkTreeIter *iter, gpointer data) { VisuPairLink *link; VisuPairLinkRenderer *renderer; gchar *str; ToolUnits units; static gchar* cylinderTypes[VISU_CYLINDER_N_COLOR] = { "user color", "element color", "node color", }; gtk_tree_model_get(model, iter, POINTER_TO_LINK, &link, -1); renderer = visu_gl_ext_pairs_getLinkRenderer(VISU_UI_PAIR_TREE(data)->priv->ext, link); str = (gchar*)0; if (VISU_IS_PAIR_WIRE_RENDERER(renderer)) /* px is for pixels and pat. for pattern. */ str = g_strdup_printf("%s %2d%s, %s %d", _("wire:"), visu_pair_wire_getWidth(VISU_PAIR_WIRE(link)), _("px"), _("pattern:"), visu_pair_wire_getStipple(VISU_PAIR_WIRE(link))); else if (VISU_IS_PAIR_CYLINDER_RENDERER(renderer)) { units = visu_pair_link_getUnits(link); if (units == TOOL_UNITS_UNDEFINED) /* a.u. is for arbitrary units. */ str = g_strdup_printf("%s %3.2f %s, %s", _("radius:"), visu_pair_cylinder_getRadius(VISU_PAIR_CYLINDER(link)), _("a.u."), _(cylinderTypes[visu_pair_cylinder_getColorType(VISU_PAIR_CYLINDER(link))])); else str = g_strdup_printf("%s %3.2f %s, %s", _("radius:"), visu_pair_cylinder_getRadius(VISU_PAIR_CYLINDER(link)), tool_physic_getUnitLabel(units), _(cylinderTypes[visu_pair_cylinder_getColorType(VISU_PAIR_CYLINDER(link))])); } g_object_unref(link); g_object_set(G_OBJECT(cell), "text", str, NULL); g_free(str); } static gint _sortLinks(GtkTreeModel *model, GtkTreeIter *a, GtkTreeIter *b, gpointer data _U_) { VisuPairLink *aLink, *bLink; VisuElement *a_ele1, *a_ele2; VisuElement *b_ele1, *b_ele2; int cmp1, cmp2; gint diff; float a_from, a_to, b_from, b_to; gtk_tree_model_get(model, a, POINTER_TO_LINK, &aLink, -1); gtk_tree_model_get(model, b, POINTER_TO_LINK, &bLink, -1); a_ele1 = visu_pair_link_getFirstElement(aLink); a_ele2 = visu_pair_link_getSecondElement(aLink); b_ele1 = visu_pair_link_getFirstElement(bLink); b_ele2 = visu_pair_link_getSecondElement(bLink); cmp1 = strcmp(a_ele1->name, b_ele1->name); cmp2 = strcmp(a_ele2->name, b_ele2->name); DBG_fprintf(stderr, "Ui Pair Tree: comparing %d - %d.\n", cmp1, cmp2); diff = (cmp1 == 0) ? cmp2 : cmp1; if (diff == 0) { a_from = visu_pair_link_getDistance(aLink, VISU_DISTANCE_MIN); a_to = visu_pair_link_getDistance(aLink, VISU_DISTANCE_MAX); b_from = visu_pair_link_getDistance(bLink, VISU_DISTANCE_MIN); b_to = visu_pair_link_getDistance(bLink, VISU_DISTANCE_MAX); DBG_fprintf(stderr, "Ui Pair Tree: compare distances %g / %g.\n", (a_to + a_from), (b_to + b_from)); if ((a_to + a_from) == (b_to + b_from)) diff = 0; else diff = ((a_to + a_from) < (b_to + b_from)) ? -1 : +1; } DBG_fprintf(stderr, "Ui Pair Tree: sort '%s - %s' with '%s - %s' -> %d.\n", a_ele1->name, a_ele2->name, b_ele1->name, b_ele2->name, diff); g_object_unref(G_OBJECT(a_ele1)); g_object_unref(G_OBJECT(a_ele2)); g_object_unref(G_OBJECT(b_ele1)); g_object_unref(G_OBJECT(b_ele2)); g_object_unref(G_OBJECT(aLink)); g_object_unref(G_OBJECT(bLink)); return diff; } static gboolean _filter(GtkTreeModel *model, GtkTreeIter *iter, gpointer data) { VisuUiPairTree *tree = VISU_UI_PAIR_TREE(data); VisuPairLink *link; GList *elements; float start, stop; VisuElement *ele1, *ele2; const gchar *label; gboolean visible; gtk_tree_model_get(model, iter, POINTER_TO_LINK, &link, -1); start = visu_pair_link_getDistance(link, VISU_DISTANCE_MIN); stop = visu_pair_link_getDistance(link, VISU_DISTANCE_MAX); ele1 = visu_pair_link_getFirstElement(link); ele2 = visu_pair_link_getSecondElement(link); g_object_unref(link); elements = (tree->priv->filter) ? visu_ui_element_combobox_getSelection(VISU_UI_ELEMENT_COMBOBOX(tree->priv->filter)) : (GList*)0; if (elements) { label = visu_element_getName(VISU_ELEMENT(elements->data)); visible = !strcmp(label, ele1->name) || !strcmp(label, ele2->name); g_list_free(elements); } else visible = TRUE; g_object_unref(ele1); g_object_unref(ele2); /* Add the visibility tag due to the hide button. */ visible = visible && (!tree->priv->hideBt || !gtk_toggle_tool_button_get_active(GTK_TOGGLE_TOOL_BUTTON(tree->priv->hideBt)) || (stop > start)); return visible; } static RowLink* row_link_copy(RowLink *row) { if (row) { row->refcount += 1; DBG_fprintf(stderr, "Ui Pair Tree: ref row (%d).\n", row->refcount); } return row; } static void row_link_free(RowLink *row) { if (!row) return; DBG_fprintf(stderr, "Ui Pair Tree: unref row (%d).\n", row->refcount); row->refcount -= 1; if (!row->refcount) { if (row->link) { g_signal_handler_disconnect(row->link, row->notify_sig); g_object_unref(row->link); } if (row->pair) { g_signal_handler_disconnect(row->pair, row->links_sig); g_object_unref(row->pair); } g_free(row); } } static GType row_link_get_type(void) { static GType g_define_type_id = 0; if (g_define_type_id == 0) g_define_type_id = g_boxed_type_register_static("RowLink", (GBoxedCopyFunc)row_link_copy, (GBoxedFreeFunc)row_link_free); return g_define_type_id; } static void _freeRow(GtkTreeRowReference *ref, GClosure *closure _U_) { gtk_tree_row_reference_free(ref); } static void _addLink(GtkTreeStore *store, GtkTreeIter *iter, GtkTreeIter *parent, VisuPair *pair, VisuPairLink *link) { GtkTreePath *path; GtkTreeRowReference *ref; RowLink *row; #if GTK_MAJOR_VERSION > 2 || GTK_MINOR_VERSION > 9 gtk_tree_store_insert_with_values(store, iter, parent, 0, POINTER_TO_LINK, link, -1); #else gtk_tree_store_append(store, iter, parent); gtk_tree_store_set(store, iter, POINTER_TO_LINK, link, -1); #endif path = gtk_tree_model_get_path(GTK_TREE_MODEL(store), iter); ref = gtk_tree_row_reference_new(GTK_TREE_MODEL(store), path); gtk_tree_path_free(path); row = g_malloc0(sizeof(RowLink)); row->link = g_object_ref(link); row->notify_sig = g_signal_connect_data(G_OBJECT(link), "notify", G_CALLBACK(onLinkNotified), ref, (GClosureNotify)_freeRow, G_CONNECT_SWAPPED); row->pair = pair; if (pair) { g_object_ref(pair); row->links_sig = g_signal_connect_swapped(G_OBJECT(pair), "notify::links", G_CALLBACK(onLinksNotified), ref); } gtk_tree_store_set(store, iter, COL_SIGNALS, row, -1); } static void onPairsNotified(VisuPairSet *set, GParamSpec *pspec _U_, VisuUiPairTree *tree) { guint i, j; GtkTreeIter iter, child; VisuPair *pair; VisuPairLink *link; DBG_fprintf(stderr, "Ui PairTree: (onPairsNotified) model has %d ref counts.\n", G_OBJECT(tree->priv->treemodel)->ref_count); gtk_tree_store_clear(GTK_TREE_STORE(tree->priv->treemodel)); i = 0; while ((pair = visu_pair_set_getNthPair(set, i++))) { j = 0; link = visu_pair_getNthLink(pair, j++); _addLink(GTK_TREE_STORE(tree->priv->treemodel), &iter, (GtkTreeIter*)0, pair, link); while ((link = visu_pair_getNthLink(pair, j++))) _addLink(GTK_TREE_STORE(tree->priv->treemodel), &child, &iter, (VisuPair*)0, link); }; DBG_fprintf(stderr, "Ui PairTree: (onPairsNotified) model has %d ref counts.\n", G_OBJECT(tree->priv->treemodel)->ref_count); } static void onDrawnToggled(GtkCellRendererToggle *cell_renderer, gchar *path, VisuUiPairTree *self) { GtkTreeIter iter; VisuPairLink *link; gtk_tree_model_get_iter_from_string(self->priv->sortmodel, &iter, path); gtk_tree_model_get(self->priv->sortmodel, &iter, POINTER_TO_LINK, &link, -1); visu_pair_link_setDrawn(link, !gtk_cell_renderer_toggle_get_active(cell_renderer)); g_object_unref(G_OBJECT(link)); } static void _changeDistance(VisuUiPairTree *self, const gchar *text, GtkTreeIter *iter, VisuPairLinkDistances at) { float value; char *error; GtkTreePath *_path; VisuPairLink *link; value = (float)strtod(text, &error); if ((value == 0.f && error == text) || value < 0.f) { _path = gtk_tree_model_get_path(self->priv->sortmodel, iter); gtk_tree_model_row_changed(self->priv->sortmodel, _path, iter); gtk_tree_path_free(_path); } else { gtk_tree_model_get(self->priv->sortmodel, iter, POINTER_TO_LINK, &link, -1); visu_pair_link_setDistance(link, value, at); g_object_unref(G_OBJECT(link)); } } static void onDistanceMinEdited(GtkCellRendererText *cellrenderertext _U_, gchar *path, gchar *text, VisuUiPairTree *self) { GtkTreeIter iter; gtk_tree_model_get_iter_from_string(self->priv->sortmodel, &iter, path); _changeDistance(self, text, &iter, VISU_DISTANCE_MIN); } static void onDistanceMaxEdited(GtkCellRendererText *cellrenderertext _U_, gchar *path, gchar *text, VisuUiPairTree *self) { GtkTreeIter iter; gtk_tree_model_get_iter_from_string(self->priv->sortmodel, &iter, path); _changeDistance(self, text, &iter, VISU_DISTANCE_MAX); } static void onLengthToggled(GtkCellRendererToggle *cell_renderer, gchar *path, VisuUiPairTree *self) { GtkTreeIter iter; VisuPairLink *link; gtk_tree_model_get_iter_from_string(self->priv->sortmodel, &iter, path); gtk_tree_model_get(self->priv->sortmodel, &iter, POINTER_TO_LINK, &link, -1); visu_pair_link_setPrintLength(link, !gtk_cell_renderer_toggle_get_active(cell_renderer)); g_object_unref(G_OBJECT(link)); } static void onSelectionChanged(VisuUiPairTree *self, GtkTreeSelection *selection) { GList *rows; GtkTreeModel *model; GtkTreeIter iter; GList *it, *links; VisuPairLink *link; if (self->priv->selectedLink) g_object_unref(self->priv->selectedLink); rows = it = gtk_tree_selection_get_selected_rows(selection, &model); self->priv->selectedLink = (VisuPairLink*)0; if (rows && gtk_tree_model_get_iter(model, &iter, (GtkTreePath*)rows->data)) gtk_tree_model_get(model, &iter, POINTER_TO_LINK, &self->priv->selectedLink, -1); g_object_notify_by_pspec(G_OBJECT(self), _properties[LINK_PROP]); links = (GList*)0; while (it && gtk_tree_model_get_iter(model, &iter, (GtkTreePath*)it->data)) { gtk_tree_model_get(model, &iter, POINTER_TO_LINK, &link, -1); links = g_list_prepend(links, link); it = g_list_next(it); } g_signal_emit(G_OBJECT(self), _signals[SEL_SIGNAL], 0, links); g_list_free_full(links, (GDestroyNotify)g_object_unref); g_list_free_full(rows, (GDestroyNotify)gtk_tree_path_free); } static void onLinkNotified(GtkTreeRowReference *ref, GParamSpec *pspec _U_, VisuPairLink *link _U_) { GtkTreeModel *model; GtkTreePath *path; GtkTreeIter iter; model = gtk_tree_row_reference_get_model(ref); path = gtk_tree_row_reference_get_path(ref); g_return_if_fail(gtk_tree_model_get_iter(model, &iter, path)); gtk_tree_model_row_changed(model, path, &iter); gtk_tree_path_free(path); } static void onLinksNotified(GtkTreeRowReference *ref, GParamSpec *pspec _U_, VisuPair *pair) { GtkTreeStore *model; GtkTreePath *path; GtkTreeIter iter, child; guint j; VisuPairLink *link; model = GTK_TREE_STORE(gtk_tree_row_reference_get_model(ref)); path = gtk_tree_row_reference_get_path(ref); g_return_if_fail(gtk_tree_model_get_iter(GTK_TREE_MODEL(model), &iter, path)); gtk_tree_store_remove(model, &iter); gtk_tree_path_free(path); j = 0; link = visu_pair_getNthLink(pair, j++); _addLink(model, &iter, (GtkTreeIter*)0, pair, link); while ((link = visu_pair_getNthLink(pair, j++))) _addLink(model, &child, &iter, (VisuPair*)0, link); } /** * visu_ui_pair_tree_getToolbar: * @tree: a #VisuUiPairTree object. * * Creates a #GtkToolbar with the action button used to add or remove * #VisuPairLink in a @tree. * * Since: 3.8 * * Returns: (transfer none): a #GtkToolbar object. **/ GtkWidget* visu_ui_pair_tree_getToolbar(VisuUiPairTree *tree) { GtkToolItem *item; GtkWidget *wd; g_return_val_if_fail(VISU_IS_UI_PAIR_TREE(tree), (GtkWidget*)0); if (tree->priv->toolbar) return tree->priv->toolbar; tree->priv->toolbar = gtk_vbox_new(FALSE, 0); #if GTK_MAJOR_VERSION > 2 || GTK_MINOR_VERSION > 5 wd = gtk_label_new(_("Manage links: ")); gtk_label_set_angle(GTK_LABEL(wd), 90.); gtk_box_pack_end(GTK_BOX(tree->priv->toolbar), wd, FALSE, FALSE, 0); #endif wd = gtk_toolbar_new(); gtk_box_pack_start(GTK_BOX(tree->priv->toolbar), wd, TRUE, TRUE, 0); gtk_orientable_set_orientation(GTK_ORIENTABLE(wd), GTK_ORIENTATION_VERTICAL); gtk_toolbar_set_style(GTK_TOOLBAR(wd), GTK_TOOLBAR_ICONS); gtk_toolbar_set_icon_size(GTK_TOOLBAR(wd), GTK_ICON_SIZE_SMALL_TOOLBAR); item = gtk_toggle_tool_button_new(); gtk_tool_button_set_icon_name(GTK_TOOL_BUTTON(item), "edit-find"); g_signal_connect_swapped(G_OBJECT(item), "clicked", G_CALLBACK(onFilter), (gpointer)tree); gtk_toolbar_insert(GTK_TOOLBAR(wd), item, -1); gtk_tool_item_set_tooltip_text(item, _("Show/hide the undrawn pairs.")); tree->priv->hideBt = item; item = gtk_tool_button_new(NULL, NULL); g_object_bind_property(tree, "selected-link", item, "sensitive", G_BINDING_SYNC_CREATE); gtk_tool_button_set_icon_name(GTK_TOOL_BUTTON(item), "list-add"); g_signal_connect_swapped(G_OBJECT(item), "clicked", G_CALLBACK(onAdd), (gpointer)tree); gtk_toolbar_insert(GTK_TOOLBAR(wd), item, -1); item = gtk_tool_button_new(NULL, NULL); g_object_bind_property(tree, "selected-link", item, "sensitive", G_BINDING_SYNC_CREATE); gtk_tool_button_set_icon_name(GTK_TOOL_BUTTON(item), "list-remove"); g_signal_connect_swapped(G_OBJECT(item), "clicked", G_CALLBACK(onRemove), (gpointer)tree); gtk_toolbar_insert(GTK_TOOLBAR(wd), item, -1); gtk_widget_show_all(tree->priv->toolbar); return g_object_ref(tree->priv->toolbar); } static void onAdd(VisuUiPairTree *tree, GtkButton *button _U_) { VisuPair *pair; gfloat zeros[2] = {0.f, 0.f}; VisuPairLink *link; pair = visu_pair_set_getFromLink(tree->priv->model, tree->priv->selectedLink); link = visu_pair_addLink(pair, zeros); _expandLink(tree, link); _selectLink(tree, link); } static void onRemove(VisuUiPairTree *tree, GtkButton *button _U_) { VisuPair *pair; pair = visu_pair_set_getFromLink(tree->priv->model, tree->priv->selectedLink); visu_pair_removeLink(pair, tree->priv->selectedLink); _selectPair(tree, pair); } static void onFilter(VisuUiPairTree *tree, GtkButton *button _U_) { gtk_tree_model_filter_refilter(GTK_TREE_MODEL_FILTER(tree->priv->filtermodel)); } /** * visu_ui_pair_tree_getFilter: * @tree: a #VisuUiPairTree object. * * Creates a #VisuElement combo widget to be used to filter the list * of pairs. * * Since: 3.8 * * Returns: (transfer none): a #VisuUiElementCombobox object. **/ GtkWidget* visu_ui_pair_tree_getFilter(VisuUiPairTree *tree) { #if GTK_MAJOR_VERSION > 2 || GTK_MINOR_VERSION > 11 GList *lst; #endif g_return_val_if_fail(VISU_IS_UI_PAIR_TREE(tree), (GtkWidget*)0); if (tree->priv->filter) return tree->priv->filter; tree->priv->filter = visu_ui_element_combobox_new(FALSE, TRUE, (const gchar*)0); g_signal_connect(tree->priv->filter, "destroy", G_CALLBACK(gtk_widget_destroyed), &tree->priv->filter); #if GTK_MAJOR_VERSION > 2 || GTK_MINOR_VERSION > 11 lst = gtk_cell_layout_get_cells(GTK_CELL_LAYOUT(tree->priv->filter)); if (lst) { g_object_set(G_OBJECT(lst->data), "scale", 0.75, NULL); g_list_free(lst); } #endif if (tree->priv->model) tree->priv->model_bind = g_object_bind_property(tree->priv->model, "data", tree->priv->filter, "nodes", G_BINDING_SYNC_CREATE); g_signal_connect_swapped(G_OBJECT(tree->priv->filter), "element-selected", G_CALLBACK(onFilterChanged), (gpointer)tree); return g_object_ref(tree->priv->filter); } static void onFilterChanged(VisuUiPairTree *tree, GList *elements _U_, VisuUiElementCombobox *combobox _U_) { gtk_tree_model_filter_refilter(GTK_TREE_MODEL_FILTER(tree->priv->filtermodel)); } static void _expandLink(VisuUiPairTree *tree, VisuPairLink *link) { gboolean valid; GtkTreeIter iter; RowLink *row; GtkTreePath *path; for (valid = gtk_tree_model_get_iter_first(tree->priv->sortmodel, &iter); valid; valid = gtk_tree_model_iter_next(tree->priv->sortmodel, &iter)) { gtk_tree_model_get(tree->priv->sortmodel, &iter, COL_SIGNALS, &row, -1); if (visu_pair_contains(row->pair, link)) { g_boxed_free(TYPE_ROW_LINK, row); path = gtk_tree_model_get_path(tree->priv->sortmodel, &iter); gtk_tree_view_expand_row(GTK_TREE_VIEW(tree), path, TRUE); gtk_tree_path_free(path); return; } g_boxed_free(TYPE_ROW_LINK, row); } } static gboolean _selectLinkAt(VisuUiPairTree *tree, VisuPairLink *link, GtkTreeIter *at) { RowLink *row; gtk_tree_model_get(tree->priv->sortmodel, at, COL_SIGNALS, &row, -1); if (row->link == link) { g_boxed_free(TYPE_ROW_LINK, row); gtk_tree_selection_select_iter (gtk_tree_view_get_selection(GTK_TREE_VIEW(tree)), at); return TRUE; } g_boxed_free(TYPE_ROW_LINK, row); return FALSE; } static void _selectLink(VisuUiPairTree *tree, VisuPairLink *link) { gboolean valid, valid2; GtkTreeIter iter, child; gtk_tree_selection_unselect_all(gtk_tree_view_get_selection(GTK_TREE_VIEW(tree))); for (valid = gtk_tree_model_get_iter_first(tree->priv->sortmodel, &iter); valid; valid = gtk_tree_model_iter_next(tree->priv->sortmodel, &iter)) { if (_selectLinkAt(tree, link, &iter)) return; for (valid2 = gtk_tree_model_iter_children(tree->priv->sortmodel, &child, &iter); valid2; valid2 = gtk_tree_model_iter_next(tree->priv->sortmodel, &child)) if (_selectLinkAt(tree, link, &child)) return; } } static void _selectPair(VisuUiPairTree *tree, VisuPair *pair) { gboolean valid; GtkTreeIter iter; RowLink *row; gtk_tree_selection_unselect_all(gtk_tree_view_get_selection(GTK_TREE_VIEW(tree))); for (valid = gtk_tree_model_get_iter_first(tree->priv->sortmodel, &iter); valid; valid = gtk_tree_model_iter_next(tree->priv->sortmodel, &iter)) { gtk_tree_model_get(tree->priv->sortmodel, &iter, COL_SIGNALS, &row, -1); if (row->pair == pair) { g_boxed_free(TYPE_ROW_LINK, row); gtk_tree_selection_select_iter (gtk_tree_view_get_selection(GTK_TREE_VIEW(tree)), &iter); return; } g_boxed_free(TYPE_ROW_LINK, row); } } v_sim-3.8.0/src/uiElements/ui_pairtree.h000066400000000000000000000077271370110300500202240ustar00rootroot00000000000000/* EXTRAITS DE LA LICENCE Copyright CEA, contributeurs : Damien CALISTE, laboratoire L_Sim, (2016) Adresse mèl : CALISTE, damien P caliste AT cea P fr. Ce logiciel est un programme informatique servant à visualiser des structures atomiques dans un rendu pseudo-3D. Ce logiciel est régi par la licence CeCILL soumise au droit français et respectant les principes de diffusion des logiciels libres. Vous pouvez utiliser, modifier et/ou redistribuer ce programme sous les conditions de la licence CeCILL telle que diffusée par le CEA, le CNRS et l'INRIA sur le site "http://www.cecill.info". Le fait que vous puissiez accéder à cet en-tête signifie que vous avez pris connaissance de la licence CeCILL, et que vous en avez accepté les termes (cf. le fichier Documentation/licence.fr.txt fourni avec ce logiciel). */ /* LICENCE SUM UP Copyright CEA, contributors : Damien CALISTE, laboratoire L_Sim, (2016) E-mail address: CALISTE, damien P caliste AT cea P fr. This software is a computer program whose purpose is to visualize atomic configurations in 3D. This software is governed by the CeCILL license under French law and abiding by the rules of distribution of free software. You can use, modify and/ or redistribute the software under the terms of the CeCILL license as circulated by CEA, CNRS and INRIA at the following URL "http://www.cecill.info". The fact that you are presently reading this means that you have had knowledge of the CeCILL license and that you accept its terms. You can find a copy of this licence shipped with this software at Documentation/licence.en.txt. */ #ifndef UI_PAIRTREE_H #define UI_PAIRTREE_H #include #include #include G_BEGIN_DECLS /** * VISU_TYPE_UI_PAIR_TREE: * * return the type of #VisuUiPairTree. * * Since: 3.8 */ #define VISU_TYPE_UI_PAIR_TREE (visu_ui_pair_tree_get_type ()) /** * VISU_UI_PAIR_TREE: * @obj: a #GObject to cast. * * Cast the given @obj into #VisuUiPairTree type. * * Since: 3.8 */ #define VISU_UI_PAIR_TREE(obj) (G_TYPE_CHECK_INSTANCE_CAST(obj, VISU_TYPE_UI_PAIR_TREE, VisuUiPairTree)) /** * VISU_UI_PAIR_TREE_CLASS: * @klass: a #GObjectClass to cast. * * Cast the given @klass into #VisuUiPairTreeClass. * * Since: 3.8 */ #define VISU_UI_PAIR_TREE_CLASS(klass) (G_TYPE_CHECK_CLASS_CAST(klass, VISU_TYPE_UI_PAIR_TREE, VisuUiPairTreeClass)) /** * VISU_IS_UI_PAIR_TREE: * @obj: a #GObject to test. * * Test if the given @ogj is of the type of #VisuUiPairTree object. * * Since: 3.8 */ #define VISU_IS_UI_PAIR_TREE(obj) (G_TYPE_CHECK_INSTANCE_TYPE(obj, VISU_TYPE_UI_PAIR_TREE)) /** * VISU_IS_UI_PAIR_TREE_CLASS: * @klass: a #GObjectClass to test. * * Test if the given @klass is of the type of #VisuUiPairTreeClass class. * * Since: 3.8 */ #define VISU_IS_UI_PAIR_TREE_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE(klass, VISU_TYPE_UI_PAIR_TREE)) /** * VISU_UI_PAIR_TREE_GET_CLASS: * @obj: a #GObject to get the class of. * * It returns the class of the given @obj. * * Since: 3.8 */ #define VISU_UI_PAIR_TREE_GET_CLASS(obj) (G_TYPE_INSTANCE_GET_CLASS(obj, VISU_TYPE_UI_PAIR_TREE, VisuUiPairTreeClass)) typedef struct _VisuUiPairTree VisuUiPairTree; typedef struct _VisuUiPairTreePrivate VisuUiPairTreePrivate; typedef struct _VisuUiPairTreeClass VisuUiPairTreeClass; struct _VisuUiPairTree { GtkTreeView parent; VisuUiPairTreePrivate *priv; }; struct _VisuUiPairTreeClass { GtkTreeViewClass parent; }; /** * visu_ui_pair_tree_get_type: * * This method returns the type of #VisuUiPairTree, use * VISU_TYPE_UI_PAIR_TREE instead. * * Since: 3.8 * * Returns: the type of #VisuUiPairTree. */ GType visu_ui_pair_tree_get_type(void); GtkWidget* visu_ui_pair_tree_new(VisuGlExtPairs *pairs); void visu_ui_pair_tree_bind(VisuUiPairTree *tree, VisuPairSet *model); GtkWidget* visu_ui_pair_tree_getToolbar(VisuUiPairTree *tree); GtkWidget* visu_ui_pair_tree_getFilter(VisuUiPairTree *tree); G_END_DECLS #endif v_sim-3.8.0/src/uiElements/ui_planetree.c000066400000000000000000001167361370110300500203640ustar00rootroot00000000000000/* EXTRAITS DE LA LICENCE Copyright CEA, contributeurs : Damien CALISTE, laboratoire L_Sim, (2015) Adresse mèl : CALISTE, damien P caliste AT cea P fr. Ce logiciel est un programme informatique servant à visualiser des structures atomiques dans un rendu pseudo-3D. Ce logiciel est régi par la licence CeCILL soumise au droit français et respectant les principes de diffusion des logiciels libres. Vous pouvez utiliser, modifier et/ou redistribuer ce programme sous les conditions de la licence CeCILL telle que diffusée par le CEA, le CNRS et l'INRIA sur le site "http://www.cecill.info". Le fait que vous puissiez accéder à cet en-tête signifie que vous avez pris connaissance de la licence CeCILL, et que vous en avez accepté les termes (cf. le fichier Documentation/licence.fr.txt fourni avec ce logiciel). */ /* LICENCE SUM UP Copyright CEA, contributors : Damien CALISTE, laboratoire L_Sim, (2015) E-mail address: CALISTE, damien P caliste AT cea P fr. This software is a computer program whose purpose is to visualize atomic configurations in 3D. This software is governed by the CeCILL license under French law and abiding by the rules of distribution of free software. You can use, modify and/ or redistribute the software under the terms of the CeCILL license as circulated by CEA, CNRS and INRIA at the following URL "http://www.cecill.info". The fact that you are presently reading this means that you have had knowledge of the CeCILL license and that you accept its terms. You can find a copy of this licence shipped with this software at Documentation/licence.en.txt. */ #include "ui_planetree.h" #include #include #include #include #include #include /** * SECTION:ui_planetree * @short_description: Defines a #GtkListStore specialised to store #VisuPlanes. * * It provides a Gtk wrapper around #VisuPlaneSet object to * store #VisuPlanes. * It also can creates #GtkTreeView and control widgets to * display itself. */ struct _VisuUiPlaneListPrivate { gboolean dispose_has_run; VisuPlaneSet *planes; gulong add_sig, remove_sig, box_sig; VisuBox *box; gulong size_sig; GtkWidget *hbox; GtkTreeView *view; VisuPlane *selection; GtkBox *controls; GtkBox *boxHidingMode; VisuUiOrientationChooser *orientationChooser; VisuUiNumericalEntry *entryNVect[3]; GBinding *bindVect[3]; GtkSpinButton *spinDistance; GBinding *bindDist; VisuUiColorCombobox *comboColor; GBinding *bindColor; }; enum { ALIGN_SIGNAL, NB_SIGNAL }; static guint _signals[NB_SIGNAL] = { 0 }; enum { PROP_0, SELECTION_PROP, N_PROP }; static GParamSpec *properties[N_PROP]; static void visu_ui_plane_list_dispose (GObject* obj); static void visu_ui_plane_list_finalize (GObject* obj); static void visu_ui_plane_list_get_property(GObject* obj, guint property_id, GValue *value, GParamSpec *pspec); static void visu_ui_plane_list_set_property(GObject* obj, guint property_id, const GValue *value, GParamSpec *pspec); G_DEFINE_TYPE_WITH_CODE(VisuUiPlaneList, visu_ui_plane_list, GTK_TYPE_LIST_STORE, G_ADD_PRIVATE(VisuUiPlaneList)) /* Local callbacks. */ static void onBox(VisuBoxed *boxed, VisuBox *box, gpointer data); static void onSize(VisuBox *box, float extens, gpointer data); static void onSelectionChanged(GtkTreeSelection *list, gpointer data); static void onSetAdd(VisuPlaneSet *set, VisuPlane *plane, gpointer data); static void onSetRemove(VisuPlaneSet *set, VisuPlane *plane, gpointer data); static void onDrawnToggled(GtkCellRendererToggle *cell_renderer, gchar *path, gpointer user_data); static void onHideToggled(GtkCellRendererToggle *cell_renderer, gchar *path, gpointer user_data); static void onSideToggled(GtkCellRendererToggle *cell_renderer, gchar *path, gpointer user_data); /* Local routines. */ static void _bindControls(VisuUiPlaneList *list, VisuPlane *plane); static gboolean _getPlane(VisuUiPlaneList *list, VisuPlane *plane, GtkTreeIter *iter); static void _addPlane(VisuUiPlaneList *list, VisuPlane *plane, GtkTreeIter *iter); static void _setBox(VisuUiPlaneList *list, VisuBoxed *boxed); static void _adjustBoxSpan(VisuUiPlaneList *list); static void _resetModel(VisuUiPlaneList *list); static void visu_ui_plane_list_class_init(VisuUiPlaneListClass *klass) { DBG_fprintf(stderr, "Visu UiPlaneList: creating the class of the object.\n"); /* DBG_fprintf(stderr, " - adding new signals ;\n"); */ /* Connect the overloading methods. */ G_OBJECT_CLASS(klass)->dispose = visu_ui_plane_list_dispose; G_OBJECT_CLASS(klass)->finalize = visu_ui_plane_list_finalize; G_OBJECT_CLASS(klass)->set_property = visu_ui_plane_list_set_property; G_OBJECT_CLASS(klass)->get_property = visu_ui_plane_list_get_property; /** * VisuUiPlaneList::align: * @list: the object emitting the signal. * @plane: the requested #VisuPlane object for alignment. * * This signal is emitted each time the user request to align with a * plane. * * Since: 3.8 */ _signals[ALIGN_SIGNAL] = g_signal_new("align", G_TYPE_FROM_CLASS(klass), G_SIGNAL_RUN_LAST | G_SIGNAL_NO_RECURSE | G_SIGNAL_NO_HOOKS, 0, NULL, NULL, g_cclosure_marshal_VOID__OBJECT, G_TYPE_NONE, 1, VISU_TYPE_PLANE, NULL); /** * VisuUiPlaneList::selection: * * Current selection. * * Since: 3.8 */ properties[SELECTION_PROP] = g_param_spec_object ("selection", "Selection", "current selection", VISU_TYPE_PLANE, G_PARAM_READWRITE); g_object_class_install_property(G_OBJECT_CLASS(klass), SELECTION_PROP, properties[SELECTION_PROP]); } static void visu_ui_plane_list_init(VisuUiPlaneList *list) { GType types[VISU_UI_PLANE_LIST_N_COLUMNS] = {VISU_TYPE_PLANE, G_TYPE_ULONG, G_TYPE_INT}; DBG_fprintf(stderr, "Visu UiPlaneList: initializing a new object (%p).\n", (gpointer)list); list->priv = visu_ui_plane_list_get_instance_private(list); list->priv->dispose_has_run = FALSE; gtk_list_store_set_column_types(GTK_LIST_STORE(list), VISU_UI_PLANE_LIST_N_COLUMNS, types); list->priv->planes = (VisuPlaneSet*)0; list->priv->box = (VisuBox*)0; list->priv->hbox = (GtkWidget*)0; list->priv->view = (GtkTreeView*)0; list->priv->controls = (GtkBox*)0; list->priv->boxHidingMode = (GtkBox*)0; list->priv->orientationChooser = (VisuUiOrientationChooser*)0; list->priv->bindVect[0] = (GBinding*)0; list->priv->bindVect[1] = (GBinding*)0; list->priv->bindVect[2] = (GBinding*)0; list->priv->bindDist = (GBinding*)0; list->priv->bindColor = (GBinding*)0; } /* This method can be called several times. It should unref all of its reference to GObjects. */ static void visu_ui_plane_list_dispose(GObject* obj) { VisuUiPlaneList *list; DBG_fprintf(stderr, "Visu UiPlaneList: dispose object %p.\n", (gpointer)obj); list = VISU_UI_PLANE_LIST(obj); if (list->priv->dispose_has_run) return; list->priv->dispose_has_run = TRUE; _resetModel(list); /* Chain up to the parent class */ G_OBJECT_CLASS(visu_ui_plane_list_parent_class)->dispose(obj); } /* This method is called once only. */ static void visu_ui_plane_list_finalize(GObject* obj) { VisuUiPlaneListPrivate *list; g_return_if_fail(obj); DBG_fprintf(stderr, "Visu UiPlaneList: finalize object %p.\n", (gpointer)obj); list = VISU_UI_PLANE_LIST(obj)->priv; if (list->hbox) g_object_unref(list->hbox); if (list->controls) g_object_unref(list->controls); if (list->orientationChooser) g_object_unref(list->orientationChooser); /* Chain up to the parent class */ DBG_fprintf(stderr, "Visu UiPlaneList: chain to parent.\n"); G_OBJECT_CLASS(visu_ui_plane_list_parent_class)->finalize(obj); DBG_fprintf(stderr, "Visu UiPlaneList: freeing ... OK.\n"); } static void visu_ui_plane_list_get_property(GObject* obj, guint property_id, GValue *value, GParamSpec *pspec) { DBG_fprintf(stderr, "Visu UiPlaneList: get property '%s' -> ", g_param_spec_get_name(pspec)); switch (property_id) { case SELECTION_PROP: g_value_set_object(value, VISU_UI_PLANE_LIST(obj)->priv->selection); DBG_fprintf(stderr, "%p.\n", g_value_get_object(value)); break; default: /* We don't have any other property... */ G_OBJECT_WARN_INVALID_PROPERTY_ID(obj, property_id, pspec); break; } } static void visu_ui_plane_list_set_property(GObject* obj, guint property_id, const GValue *value, GParamSpec *pspec) { VisuUiPlaneList *list = VISU_UI_PLANE_LIST(obj); GtkTreeIter iter; DBG_fprintf(stderr, "Visu UiPlaneList: set property '%s' -> ", g_param_spec_get_name(pspec)); switch (property_id) { case SELECTION_PROP: if (list->priv->view && _getPlane(list, VISU_PLANE(g_value_get_object(value)), &iter)) gtk_tree_selection_select_iter(gtk_tree_view_get_selection(list->priv->view), &iter); break; default: /* We don't have any other property... */ G_OBJECT_WARN_INVALID_PROPERTY_ID(obj, property_id, pspec); break; } } /** * visu_ui_plane_list_new: * * Create a new #GtkListStore to store planes. * * Since: 3.8 * * Returns: a newly created object. **/ VisuUiPlaneList* visu_ui_plane_list_new() { VisuUiPlaneList *list; list = VISU_UI_PLANE_LIST(g_object_new(VISU_TYPE_UI_PLANE_LIST, NULL)); return list; } /** * visu_ui_plane_list_getModel: * @list: a #VisuUiPlaneList object. * * Retrieve the #VisuPlaneSet object that @list is built upon. * * Since: 3.8 * * Returns: (transfer none): a #VisuPlaneSet object. **/ VisuPlaneSet* visu_ui_plane_list_getModel(const VisuUiPlaneList *list) { g_return_val_if_fail(VISU_IS_UI_PLANE_LIST(list), (VisuPlaneSet*)0); return list->priv->planes; } static void _setBox(VisuUiPlaneList *list, VisuBoxed *boxed) { DBG_fprintf(stderr, "VisuUi Planes: set box from boxed %p.\n", (gpointer)boxed); if (list->priv->box) { g_signal_handler_disconnect(G_OBJECT(list->priv->box), list->priv->size_sig); g_object_unref(G_OBJECT(list->priv->box)); } list->priv->box = (boxed) ? visu_boxed_getBox(boxed) : (VisuBox*)0; if (list->priv->box) { g_object_ref(G_OBJECT(list->priv->box)); list->priv->size_sig = g_signal_connect(G_OBJECT(list->priv->box), "SizeChanged", G_CALLBACK(onSize), (gpointer)list); } } static void _resetModel(VisuUiPlaneList *list) { if (list->priv->planes) { DBG_fprintf(stderr, "Visu UiPlaneList: disconnecting old plane set %p.\n", (gpointer)list->priv->planes); g_signal_handler_disconnect(G_OBJECT(list->priv->planes), list->priv->add_sig); g_signal_handler_disconnect(G_OBJECT(list->priv->planes), list->priv->remove_sig); g_signal_handler_disconnect(G_OBJECT(list->priv->planes), list->priv->box_sig); g_object_unref(G_OBJECT(list->priv->planes)); DBG_fprintf(stderr, "Visu UiPlaneList: done."); } _setBox(list, (VisuBoxed*)0); list->priv->planes = (VisuPlaneSet*)0; } /** * visu_ui_plane_list_setModel: * @list: a #VisuUiPlaneList object. * @set: (allow-none): a #VisuPlaneSet object. * * Bind the @set object to @list. * * Returns: TRUE if @set is changed **/ gboolean visu_ui_plane_list_setModel(VisuUiPlaneList *list, VisuPlaneSet *set) { VisuPlaneSetIter iter; g_return_val_if_fail(VISU_IS_UI_PLANE_LIST(list), FALSE); if (list->priv->planes == set) return FALSE; DBG_fprintf(stderr, "Visu UiPlaneList: resetting model.\n"); gtk_list_store_clear(GTK_LIST_STORE(list)); DBG_fprintf(stderr, "Visu UiPlaneList: done.\n"); _resetModel(list); list->priv->planes = set; /* Populate the listview with existing planes in the model. */ if (set) { g_object_ref(set); visu_plane_set_iter_new(set, &iter); for (visu_plane_set_iter_next(&iter); iter.plane; visu_plane_set_iter_next(&iter)) _addPlane(list, iter.plane, (GtkTreeIter*)0); list->priv->add_sig = g_signal_connect(G_OBJECT(set), "added", G_CALLBACK(onSetAdd), (gpointer)list); list->priv->remove_sig = g_signal_connect(G_OBJECT(set), "removed", G_CALLBACK(onSetRemove), (gpointer)list); list->priv->box_sig = g_signal_connect(G_OBJECT(set), "setBox", G_CALLBACK(onBox), (gpointer)list); _setBox(list, VISU_BOXED(set)); _adjustBoxSpan(list); } return TRUE; } static gboolean _getPlane(VisuUiPlaneList *list, VisuPlane *plane, GtkTreeIter *iter) { gboolean valid; VisuPlane *pl; GtkTreeModel *model = GTK_TREE_MODEL(list); pl = (VisuPlane*)0; for (valid = gtk_tree_model_get_iter_first(model, iter); valid; valid = gtk_tree_model_iter_next(model, iter)) { gtk_tree_model_get(model, iter, VISU_UI_PLANE_LIST_POINTER, &pl, -1); g_object_unref(pl); if (pl == plane) break; else pl = (VisuPlane*)0; } return (pl != (VisuPlane*)0); } static void onBox(VisuBoxed *boxed, VisuBox *box _U_, gpointer data) { _setBox(VISU_UI_PLANE_LIST(data), boxed); _adjustBoxSpan(VISU_UI_PLANE_LIST(data)); } static void onPlaneNotify(GObject *obj, GParamSpec *pspec, gpointer data) { GtkTreeIter iter; GtkTreePath *path; if (_getPlane(VISU_UI_PLANE_LIST(data), VISU_PLANE(obj), &iter)) { if (!strcmp(g_param_spec_get_name(pspec), "hidding-side") && visu_plane_getHiddenState(VISU_PLANE(obj)) != VISU_PLANE_SIDE_NONE) gtk_list_store_set(GTK_LIST_STORE(data), &iter, VISU_UI_PLANE_LIST_MODE, visu_plane_getHiddenState(VISU_PLANE(obj)), -1); else { path = gtk_tree_model_get_path(GTK_TREE_MODEL(data), &iter); g_signal_emit_by_name(G_OBJECT(data), "row-changed", path, &iter, NULL); gtk_tree_path_free(path); } } } static void _addPlane(VisuUiPlaneList *list, VisuPlane *plane, GtkTreeIter *iter) { GtkTreeIter it; gulong sig; gint mode; /* String used to labelled planes, dist. means 'distance' and norm. means 'normal' (50 chars max). */ sig = g_signal_connect_object(G_OBJECT(plane), "notify", G_CALLBACK(onPlaneNotify), (gpointer)list, 0); mode = visu_plane_getHiddenState(plane); gtk_list_store_append(GTK_LIST_STORE(list), &it); gtk_list_store_set(GTK_LIST_STORE(list), &it, VISU_UI_PLANE_LIST_POINTER, (gpointer)plane, VISU_UI_PLANE_LIST_NOTIFY, sig, VISU_UI_PLANE_LIST_MODE, (mode != VISU_PLANE_SIDE_NONE) ? mode : VISU_PLANE_SIDE_PLUS, -1); if (list->priv->boxHidingMode) gtk_widget_set_sensitive(GTK_WIDGET(list->priv->boxHidingMode), (gtk_tree_model_iter_n_children(GTK_TREE_MODEL(list), (GtkTreeIter*)0) > 1)); if (iter) *iter = it; DBG_fprintf(stderr, "Ui PlaneTree: %p has %d ref counts.\n", (gpointer)plane, G_OBJECT(plane)->ref_count); } static void onSetAdd(VisuPlaneSet *set _U_, VisuPlane *plane, gpointer data) { GtkTreeIter iter; VisuUiPlaneList *list = VISU_UI_PLANE_LIST(data); _addPlane(list, plane, &iter); if (list->priv->view) gtk_tree_selection_select_iter (gtk_tree_view_get_selection(list->priv->view), &iter); } static void onSetRemove(VisuPlaneSet *set _U_, VisuPlane *plane, gpointer data) { GtkTreeIter iter; gboolean valid; gulong sig; VisuUiPlaneList *list = VISU_UI_PLANE_LIST(data); GtkTreeModel *model = GTK_TREE_MODEL(list); if (_getPlane(list, plane, &iter)) { gtk_tree_model_get(model, &iter, VISU_UI_PLANE_LIST_NOTIFY, &sig, -1); g_signal_handler_disconnect(G_OBJECT(plane), sig); valid = TRUE; if (!gtk_list_store_remove(GTK_LIST_STORE(list), &iter)) valid = gtk_tree_model_get_iter_first(model, &iter); if (valid && list->priv->view) gtk_tree_selection_select_iter (gtk_tree_view_get_selection(list->priv->view), &iter); if (list->priv->boxHidingMode && gtk_tree_model_iter_n_children(model, (GtkTreeIter*)0) < 2) gtk_widget_set_sensitive(GTK_WIDGET(list->priv->boxHidingMode), FALSE); DBG_fprintf(stderr, "Visu UiPlaneList: OK plane found and removed.\n"); } } static void onSize(VisuBox *box _U_, float extens _U_, gpointer data) { _adjustBoxSpan(VISU_UI_PLANE_LIST(data)); } static void onAdd(GtkButton *button _U_, gpointer userData) { VisuPlane* plane; float vect[3]; const ToolColor *color; float dist; VisuUiPlaneList *list = VISU_UI_PLANE_LIST(userData); /* We create a new plane. */ vect[0] = (float)visu_ui_numerical_entry_getValue(list->priv->entryNVect[0]); vect[1] = (float)visu_ui_numerical_entry_getValue(list->priv->entryNVect[1]); vect[2] = (float)visu_ui_numerical_entry_getValue(list->priv->entryNVect[2]); dist = (float)gtk_spin_button_get_value(list->priv->spinDistance); color = visu_ui_color_combobox_getSelection(list->priv->comboColor); plane = visu_plane_new((VisuBox*)0, vect, dist, color); /* We add it to the model. */ visu_plane_set_add(list->priv->planes, plane); /* We count down the counter on plane since it has been added to the list. */ g_object_unref(G_OBJECT(plane)); DBG_fprintf(stderr, "Ui PlaneTree: plane added.\n"); } static void onRemove(GtkButton *button _U_, gpointer data) { VisuPlane *plane; VisuUiPlaneList *list = VISU_UI_PLANE_LIST(data); plane = visu_ui_plane_list_getSelection(list); if (!plane) return; visu_plane_set_remove(list->priv->planes, plane); } static void onAlign(GtkButton *button _U_, gpointer data) { VisuPlane *plane; plane = visu_ui_plane_list_getSelection(VISU_UI_PLANE_LIST(data)); if (!plane) return; g_signal_emit(G_OBJECT(data), _signals[ALIGN_SIGNAL], 0, plane); } static void _displayRender(GtkTreeViewColumn *tree_column _U_, GtkCellRenderer *cell, GtkTreeModel *tree_model, GtkTreeIter *iter, gpointer data _U_) { VisuPlane *plane; gtk_tree_model_get(tree_model, iter, VISU_UI_PLANE_LIST_POINTER, &plane, -1); g_object_set(cell, "active", visu_plane_getRendered(plane), NULL); g_object_unref(plane); } static void _displayParam(GtkTreeViewColumn *tree_column _U_, GtkCellRenderer *cell, GtkTreeModel *tree_model, GtkTreeIter *iter, gpointer data _U_) { VisuPlane *plane; gchar str[256]; float vect[3]; gtk_tree_model_get(tree_model, iter, VISU_UI_PLANE_LIST_POINTER, &plane, -1); visu_plane_getNVectUser(plane, vect); sprintf(str, _("norm.: (%3d;%3d;%3d)\ndistance: %6.2f"), (int)vect[0], (int)vect[1], (int)vect[2], visu_plane_getDistanceFromOrigin(plane)); g_object_set(cell, "markup", str, NULL); g_object_unref(plane); } static void _displayMask(GtkTreeViewColumn *tree_column _U_, GtkCellRenderer *cell, GtkTreeModel *tree_model, GtkTreeIter *iter, gpointer data _U_) { VisuPlane *plane; gtk_tree_model_get(tree_model, iter, VISU_UI_PLANE_LIST_POINTER, &plane, -1); g_object_set(cell, "active", (visu_plane_getHiddenState(plane) != VISU_PLANE_SIDE_NONE), NULL); g_object_unref(plane); } static void _displaySide(GtkTreeViewColumn *tree_column _U_, GtkCellRenderer *cell, GtkTreeModel *tree_model, GtkTreeIter *iter, gpointer data _U_) { VisuPlane *plane; gint mode; gtk_tree_model_get(tree_model, iter, VISU_UI_PLANE_LIST_POINTER, &plane, VISU_UI_PLANE_LIST_MODE, &mode, -1); if (visu_plane_getHiddenState(plane) != VISU_PLANE_SIDE_NONE) g_object_set(cell, "active", (visu_plane_getHiddenState(plane) == VISU_PLANE_SIDE_MINUS), NULL); else g_object_set(cell, "active", (mode == VISU_PLANE_SIDE_MINUS), NULL); g_object_unref(plane); } static void _displayColor(GtkTreeViewColumn *tree_column _U_, GtkCellRenderer *cell, GtkTreeModel *tree_model, GtkTreeIter *iter, gpointer data _U_) { VisuPlane *plane; GdkPixbuf *pix; gtk_tree_model_get(tree_model, iter, VISU_UI_PLANE_LIST_POINTER, &plane, -1); pix = tool_color_get_stamp(visu_plane_getColor(plane), TRUE); g_object_set(cell, "pixbuf", pix, NULL); g_object_unref(pix); g_object_unref(plane); } /** * visu_ui_plane_list_getView: * @list: a #VisuUiPlaneList object. * * Retrieve a treeview and a side toolbar that displays the list * of planes of the model. * * Since: 3.8 * * Returns: (transfer full): widgets are created if needed. **/ GtkWidget* visu_ui_plane_list_getView(VisuUiPlaneList *list) { GtkCellRenderer *renderer; GtkTreeViewColumn *column; GtkWidget *image, *wd; GtkToolItem *item; #if GTK_MAJOR_VERSION == 2 && GTK_MINOR_VERSION < 12 GtkTooltips *tooltips; tooltips = gtk_tooltips_new (); #endif g_return_val_if_fail(VISU_IS_UI_PLANE_LIST(list), (GtkWidget*)0); if (list->priv->hbox) { g_object_ref(list->priv->hbox); return list->priv->hbox; } list->priv->hbox = gtk_hbox_new(FALSE, 0); wd = gtk_scrolled_window_new(NULL, NULL); gtk_box_pack_start(GTK_BOX(list->priv->hbox), wd, TRUE, TRUE, 0); gtk_scrolled_window_set_policy(GTK_SCROLLED_WINDOW(wd), GTK_POLICY_AUTOMATIC, GTK_POLICY_AUTOMATIC); gtk_scrolled_window_set_shadow_type(GTK_SCROLLED_WINDOW(wd), GTK_SHADOW_IN); list->priv->view = GTK_TREE_VIEW(gtk_tree_view_new()); gtk_container_add(GTK_CONTAINER(wd), GTK_WIDGET(list->priv->view)); gtk_tree_view_set_headers_visible(list->priv->view, TRUE); /* Render the associated list */ renderer = gtk_cell_renderer_toggle_new (); g_signal_connect(G_OBJECT(renderer), "toggled", G_CALLBACK(onDrawnToggled), (gpointer)list); column = gtk_tree_view_column_new_with_attributes(_("Drawn"), renderer, NULL); gtk_tree_view_append_column(list->priv->view, column); gtk_tree_view_column_set_cell_data_func(column, renderer, _displayRender, (gpointer)0, (GDestroyNotify)0); renderer = gtk_cell_renderer_text_new (); column = gtk_tree_view_column_new_with_attributes(_("Parameters"), renderer, NULL); gtk_tree_view_column_set_expand(column, TRUE); gtk_tree_view_column_set_alignment(column, 0.5); gtk_tree_view_append_column (list->priv->view, column); gtk_tree_view_column_set_cell_data_func(column, renderer, _displayParam, (gpointer)0, (GDestroyNotify)0); renderer = gtk_cell_renderer_toggle_new (); g_signal_connect(G_OBJECT(renderer), "toggled", G_CALLBACK(onHideToggled), (gpointer)list); column = gtk_tree_view_column_new_with_attributes (_("Mask"), renderer, NULL); image = create_pixmap((GtkWidget*)0, "stock-masking.png"); gtk_tree_view_column_set_widget(column, image); gtk_tree_view_append_column (list->priv->view, column); gtk_tree_view_column_set_cell_data_func(column, renderer, _displayMask, (gpointer)0, (GDestroyNotify)0); renderer = gtk_cell_renderer_toggle_new (); g_signal_connect(G_OBJECT(renderer), "toggled", G_CALLBACK(onSideToggled), (gpointer)list); column = gtk_tree_view_column_new_with_attributes (_("Invert"), renderer, NULL); gtk_tree_view_append_column (list->priv->view, column); gtk_tree_view_column_set_cell_data_func(column, renderer, _displaySide, (gpointer)0, (GDestroyNotify)0); renderer = gtk_cell_renderer_pixbuf_new (); column = gtk_tree_view_column_new_with_attributes (_("Color"), renderer, NULL); image = gtk_image_new_from_icon_name("applications-graphics", GTK_ICON_SIZE_SMALL_TOOLBAR); gtk_tree_view_column_set_widget(column, image); gtk_tree_view_append_column (list->priv->view, column); gtk_tree_view_column_set_cell_data_func(column, renderer, _displayColor, (gpointer)0, (GDestroyNotify)0); gtk_tree_selection_set_mode(gtk_tree_view_get_selection(list->priv->view), GTK_SELECTION_SINGLE); g_signal_connect(gtk_tree_view_get_selection(list->priv->view), "changed", G_CALLBACK(onSelectionChanged), (gpointer)list); gtk_tree_view_set_model(list->priv->view, GTK_TREE_MODEL(list)); wd = gtk_toolbar_new(); gtk_orientable_set_orientation(GTK_ORIENTABLE(wd), GTK_ORIENTATION_VERTICAL); gtk_toolbar_set_style(GTK_TOOLBAR(wd), GTK_TOOLBAR_ICONS); gtk_toolbar_set_icon_size(GTK_TOOLBAR(wd), GTK_ICON_SIZE_SMALL_TOOLBAR); gtk_box_pack_start(GTK_BOX(list->priv->hbox), wd, FALSE, FALSE, 0); item = gtk_tool_button_new(NULL, NULL); gtk_tool_button_set_icon_name(GTK_TOOL_BUTTON(item), "list-add"); g_signal_connect(G_OBJECT(item), "clicked", G_CALLBACK(onAdd), (gpointer)list); gtk_toolbar_insert(GTK_TOOLBAR(wd), item, -1); item = gtk_tool_button_new(NULL, NULL); gtk_tool_button_set_icon_name(GTK_TOOL_BUTTON(item), "list-remove"); g_signal_connect(G_OBJECT(item), "clicked", G_CALLBACK(onRemove), (gpointer)list); gtk_toolbar_insert(GTK_TOOLBAR(wd), item, -1); item = gtk_tool_button_new(create_pixmap((GtkWidget*)0, "stock_rotate_20.png"), _("align")); g_signal_connect(G_OBJECT(item), "clicked", G_CALLBACK(onAlign), (gpointer)list); gtk_toolbar_insert(GTK_TOOLBAR(wd), item, -1); gtk_widget_set_tooltip_text(GTK_WIDGET(item), _("Set the camera to look in the direction" " normal to the selected plane.")); g_object_ref(list->priv->hbox); return list->priv->hbox; } /** * visu_ui_plane_list_getAt: * @list: a #VisuUiPlaneList object. * @i: an integer. * * Retrieve the #VisuPlane object, stored at the place @i in @list. * * Since: 3.8 * * Returns: (transfer full): a #VisuPlane object or NULL. **/ VisuPlane* visu_ui_plane_list_getAt(VisuUiPlaneList *list, guint i) { GtkTreeIter iter; VisuPlane *plane; if (!gtk_tree_model_iter_nth_child(GTK_TREE_MODEL(list), &iter, NULL, i)) return (VisuPlane*)0; gtk_tree_model_get(GTK_TREE_MODEL(list), &iter, VISU_UI_PLANE_LIST_POINTER, &plane, -1); return plane; } /** * visu_ui_plane_list_getSelection: * @list: a #VisuUiPlaneList object. * * Retrieve the selected #VisuPlane, or NULL if no selection. * * Since: 3.8 * * Returns: (transfer none): a #VisuPlane object or NULL. **/ VisuPlane* visu_ui_plane_list_getSelection(const VisuUiPlaneList *list) { g_return_val_if_fail(VISU_IS_UI_PLANE_LIST(list), (VisuPlane*)0); return list->priv->selection; } static void onSelectionChanged(GtkTreeSelection *tree, gpointer data) { VisuUiPlaneList *list = VISU_UI_PLANE_LIST(data); GtkTreeIter it; list->priv->selection = (VisuPlane*)0; if (gtk_tree_selection_get_selected(tree, NULL, &it)) { gtk_tree_model_get(GTK_TREE_MODEL(data), &it, VISU_UI_PLANE_LIST_POINTER, &list->priv->selection, -1); g_object_unref(G_OBJECT(list->priv->selection)); } _bindControls(list, list->priv->selection); g_object_notify_by_pspec(G_OBJECT(data), properties[SELECTION_PROP]); } static void onDrawnToggled(GtkCellRendererToggle *cell_renderer, gchar *path, gpointer user_data) { gboolean validIter; GtkTreeIter iter; VisuPlane *plane; validIter = gtk_tree_model_get_iter_from_string(GTK_TREE_MODEL(user_data), &iter, path); g_return_if_fail(validIter); gtk_tree_model_get(GTK_TREE_MODEL(user_data), &iter, VISU_UI_PLANE_LIST_POINTER, &plane, -1); g_object_unref(G_OBJECT(plane)); g_object_set(plane, "rendered", !gtk_cell_renderer_toggle_get_active(cell_renderer), NULL); } static void onHideToggled(GtkCellRendererToggle *cell_renderer _U_, gchar *path, gpointer user_data) { gboolean validIter; GtkTreeIter iter; VisuPlane *plane; gint mode; validIter = gtk_tree_model_get_iter_from_string(GTK_TREE_MODEL(user_data), &iter, path); g_return_if_fail(validIter); gtk_tree_model_get(GTK_TREE_MODEL(user_data), &iter, VISU_UI_PLANE_LIST_POINTER, &plane, VISU_UI_PLANE_LIST_MODE, &mode, -1); g_object_unref(G_OBJECT(plane)); if (visu_plane_getHiddenState(plane) != VISU_PLANE_SIDE_NONE) visu_plane_setHiddenState(plane, VISU_PLANE_SIDE_NONE); else visu_plane_setHiddenState(plane, mode); } static void onSideToggled(GtkCellRendererToggle *cell_renderer _U_, gchar *path, gpointer user_data) { gboolean validIter; GtkTreeIter iter; VisuPlane *plane; gint mode; validIter = gtk_tree_model_get_iter_from_string(GTK_TREE_MODEL(user_data), &iter, path); g_return_if_fail(validIter); gtk_tree_model_get(GTK_TREE_MODEL(user_data), &iter, VISU_UI_PLANE_LIST_POINTER, &plane, VISU_UI_PLANE_LIST_MODE, &mode, -1); g_object_unref(G_OBJECT(plane)); if (visu_plane_getHiddenState(plane) == VISU_PLANE_SIDE_MINUS) visu_plane_setHiddenState(plane, VISU_PLANE_SIDE_PLUS); else if (visu_plane_getHiddenState(plane) == VISU_PLANE_SIDE_PLUS) visu_plane_setHiddenState(plane, VISU_PLANE_SIDE_MINUS); else gtk_list_store_set(GTK_LIST_STORE(user_data), &iter, VISU_UI_PLANE_LIST_MODE, mode * -1, -1); } static gboolean _getVect(GBinding *binding _U_, const GValue *from, GValue *to, gpointer data) { float *vect; vect = (float*)g_value_get_boxed(from); g_value_set_double(to, vect[GPOINTER_TO_INT(data)]); return TRUE; } static gboolean _setVect(GBinding *binding, const GValue *from, GValue *to, gpointer data) { float vect[3], oldValue; visu_plane_getNVectUser(VISU_PLANE(g_binding_get_source(binding)), vect); oldValue = vect[GPOINTER_TO_INT(data)]; vect[GPOINTER_TO_INT(data)] = (float)g_value_get_double(from); if (vect[0] == 0.f && vect[1] == 0.f && vect[2] == 0.f) { visu_ui_numerical_entry_warnValue(VISU_UI_NUMERICAL_ENTRY(g_binding_get_target(binding)), oldValue); return FALSE; } g_value_set_boxed(to, vect); return TRUE; } static void _bindControls(VisuUiPlaneList *list, VisuPlane *plane) { #define BIND_VECT(I) {list->priv->bindVect[I] = g_object_bind_property_full \ (plane, "n-vector", list->priv->entryNVect[I], "value", \ G_BINDING_BIDIRECTIONAL | G_BINDING_SYNC_CREATE, _getVect, _setVect, \ GINT_TO_POINTER(I), (GDestroyNotify)0);} if (list->priv->bindVect[0]) g_object_unref(list->priv->bindVect[0]); if (list->priv->bindVect[1]) g_object_unref(list->priv->bindVect[1]); if (list->priv->bindVect[2]) g_object_unref(list->priv->bindVect[2]); if (list->priv->bindDist) g_object_unref(list->priv->bindDist); if (list->priv->bindColor) g_object_unref(list->priv->bindColor); if (plane && list->priv->controls) { BIND_VECT(0); BIND_VECT(1); BIND_VECT(2); list->priv->bindDist = g_object_bind_property (plane, "distance", list->priv->spinDistance, "value", G_BINDING_BIDIRECTIONAL | G_BINDING_SYNC_CREATE); list->priv->bindColor = g_object_bind_property (plane, "color", list->priv->comboColor, "color", G_BINDING_BIDIRECTIONAL | G_BINDING_SYNC_CREATE); } else { list->priv->bindVect[0] = (GBinding*)0; list->priv->bindVect[1] = (GBinding*)0; list->priv->bindVect[2] = (GBinding*)0; list->priv->bindDist = (GBinding*)0; list->priv->bindColor = (GBinding*)0; } } static void onOrientationChanged(VisuUiOrientationChooser *orientationChooser, gpointer data) { float values[3]; VisuUiPlaneList *list = VISU_UI_PLANE_LIST(data); visu_ui_orientation_chooser_getOrthoValues(orientationChooser, values); visu_ui_numerical_entry_setValue(list->priv->entryNVect[0], (double)values[0]); visu_ui_numerical_entry_setValue(list->priv->entryNVect[1], (double)values[1]); visu_ui_numerical_entry_setValue(list->priv->entryNVect[2], (double)values[2]); } static void onOrientation(GtkButton *button _U_, gpointer data) { float values[3]; VisuUiPlaneList *list = VISU_UI_PLANE_LIST(data); if (!list->priv->orientationChooser) { list->priv->orientationChooser = VISU_UI_ORIENTATION_CHOOSER (visu_ui_orientation_chooser_new(VISU_UI_ORIENTATION_NORMAL, TRUE, VISU_BOXED(list->priv->planes), NULL)); /* gtk_window_set_modal(GTK_WINDOW(orientationChooser), TRUE); */ values[0] = (float)visu_ui_numerical_entry_getValue(list->priv->entryNVect[0]); values[1] = (float)visu_ui_numerical_entry_getValue(list->priv->entryNVect[1]); values[2] = (float)visu_ui_numerical_entry_getValue(list->priv->entryNVect[2]); visu_ui_orientation_chooser_setOrthoValues(list->priv->orientationChooser, values); g_signal_connect(G_OBJECT(list->priv->orientationChooser), "values-changed", G_CALLBACK(onOrientationChanged), data); } else gtk_window_present(GTK_WINDOW(list->priv->orientationChooser)); gtk_widget_show(GTK_WIDGET(list->priv->orientationChooser)); switch (gtk_dialog_run(GTK_DIALOG(list->priv->orientationChooser))) { case GTK_RESPONSE_ACCEPT: DBG_fprintf(stderr, "Visu UiPlaneList: accept changings on orientation.\n"); break; default: DBG_fprintf(stderr, "Visu UiPlaneList: reset values on orientation.\n"); visu_ui_numerical_entry_setValue(list->priv->entryNVect[0], (double)values[0]); visu_ui_numerical_entry_setValue(list->priv->entryNVect[1], (double)values[1]); visu_ui_numerical_entry_setValue(list->priv->entryNVect[2], (double)values[2]); } gtk_widget_destroy(GTK_WIDGET(list->priv->orientationChooser)); list->priv->orientationChooser = (VisuUiOrientationChooser*)0; } static gboolean _setMode(GBinding *binding _U_, const GValue *from, GValue *to, gpointer data) { if (!g_value_get_boolean(from)) return FALSE; g_value_set_uint(to, GPOINTER_TO_INT(data)); return TRUE; } static gboolean _getMode(GBinding *binding _U_, const GValue *from, GValue *to, gpointer data) { if (g_value_get_uint(from) != (guint)GPOINTER_TO_INT(data)) return FALSE; g_value_set_boolean(to, TRUE); return TRUE; } static void _buildHidingMode(VisuUiPlaneList *list) { GtkWidget *hbox, *label, *wd; GSList *group; #if GTK_MAJOR_VERSION == 2 && GTK_MINOR_VERSION < 12 GtkTooltips *tooltips; tooltips = gtk_tooltips_new (); #endif #define DEFINE_RADIO(K, G) {wd = gtk_radio_button_new(NULL); \ gtk_box_pack_start(GTK_BOX(list->priv->boxHidingMode), wd, FALSE, FALSE, 0); \ gtk_radio_button_set_group(GTK_RADIO_BUTTON(wd), G); \ g_object_bind_property_full(list->priv->planes, "hidding-mode", wd, "active", \ G_BINDING_BIDIRECTIONAL | G_BINDING_SYNC_CREATE, \ _getMode, _setMode, GINT_TO_POINTER(K), (GDestroyNotify)0);} #define SET_LABEL(I, T) {hbox = gtk_hbox_new(FALSE, 2); \ gtk_container_add(GTK_CONTAINER(wd), hbox); \ gtk_box_pack_start(GTK_BOX(hbox), create_pixmap(NULL, I), FALSE, FALSE, 0); \ gtk_box_pack_start(GTK_BOX(hbox), gtk_label_new(T), FALSE, FALSE, 0);} list->priv->boxHidingMode = GTK_BOX(gtk_hbox_new(FALSE, 0)); label = gtk_label_new(_("Hiding mode: ")); gtk_box_pack_start(GTK_BOX(list->priv->boxHidingMode), label, FALSE, FALSE, 0); DEFINE_RADIO(VISU_PLANE_SET_HIDE_UNION, (GSList*)0); group = gtk_radio_button_get_group(GTK_RADIO_BUTTON(wd)); gtk_widget_set_tooltip_text(wd, _("Hide all elements that are hidden by at least one plane.")); SET_LABEL("stock-union.png", _("Union")); DEFINE_RADIO(VISU_PLANE_SET_HIDE_INTER, group); gtk_widget_set_tooltip_text(wd, _("Hide elements only if they are hidden by all planes.")); SET_LABEL("stock-inter.png", _("Intersection")); gtk_widget_set_sensitive(GTK_WIDGET(list->priv->boxHidingMode), (gtk_tree_model_iter_n_children(GTK_TREE_MODEL(list), (GtkTreeIter*)0) > 1)); } static void _adjustBoxSpan(VisuUiPlaneList *list) { float span[2]; float diag[3], ext[3], red[3] = {1.f, 1.f, 1.f}; if (!list->priv->spinDistance) return; if (list->priv->box) { visu_box_convertBoxCoordinatestoXYZ(list->priv->box, diag, red); visu_box_getExtension(list->priv->box, ext); diag[0] *= diag[0]; diag[1] *= diag[1]; diag[2] *= diag[2]; span[0] = -sqrt(ext[0] * ext[0] * diag[0] + ext[1] * ext[1] * diag[1] + ext[2] * ext[2] * diag[2]); span[1] = sqrt((ext[0] + 1.f) * (ext[0] + 1.f) * diag[0] + (ext[1] + 1.f) * (ext[1] + 1.f) * diag[1] + (ext[2] + 1.f) * (ext[2] + 1.f) * diag[2]); } else { span[0] = -998.f; span[1] = 1000.f; } gtk_spin_button_set_range(list->priv->spinDistance, span[0], span[1]); } /** * visu_ui_plane_list_getControls: * @list: a #VisuUiPlaneList object. * * Retrieve the #GtkBox object with the #GtkWidget to control the * selected plane in the treeview of @list. * * Since: 3.8 * * Returns: (transfer full): widgets are created if needed. **/ GtkBox* visu_ui_plane_list_getControls(VisuUiPlaneList *list) { GtkWidget *hbox, *label, *wd, *image; guint i; double span[2]; #define PARAM_LINE(T) { hbox = gtk_hbox_new(FALSE, 2); \ gtk_box_pack_start(GTK_BOX(list->priv->controls), hbox, FALSE, FALSE, 0); \ label = gtk_label_new(T); \ gtk_label_set_xalign(GTK_LABEL(label), 0.); \ gtk_box_pack_start(GTK_BOX(hbox), label, TRUE, TRUE, 0);} g_return_val_if_fail(VISU_IS_UI_PLANE_LIST(list), (GtkBox*)0); if (list->priv->controls) { g_object_ref(list->priv->controls); return list->priv->controls; } list->priv->controls = GTK_BOX(gtk_vbox_new(FALSE, 2)); gtk_container_set_border_width(GTK_CONTAINER(list->priv->controls), 5); g_object_ref(list->priv->controls); /* Hiding Mode */ _buildHidingMode(list); gtk_box_pack_start(GTK_BOX(list->priv->controls), GTK_WIDGET(list->priv->boxHidingMode), TRUE, TRUE, 2); /* VisuPlanes parameters */ PARAM_LINE(_("Normal: ")); for (i = 0; i < 3; i++) { list->priv->entryNVect[i] = VISU_UI_NUMERICAL_ENTRY(visu_ui_numerical_entry_new(1.)); gtk_entry_set_width_chars(GTK_ENTRY(list->priv->entryNVect[i]), 5); gtk_box_pack_start(GTK_BOX(hbox), GTK_WIDGET(list->priv->entryNVect[i]), FALSE, FALSE, 0); } wd = gtk_button_new(); gtk_box_pack_start(GTK_BOX(hbox), wd, FALSE, FALSE, 0); g_signal_connect(G_OBJECT(wd), "clicked", G_CALLBACK(onOrientation), (gpointer)list); image = create_pixmap((GtkWidget*)0, "axes-button.png"); gtk_container_add(GTK_CONTAINER(wd), image); PARAM_LINE(_("Distance from origin: ")); list->priv->spinDistance = GTK_SPIN_BUTTON(gtk_spin_button_new_with_range(-1, 1., 0.25)); _adjustBoxSpan(list); gtk_spin_button_set_digits(list->priv->spinDistance, 2); gtk_spin_button_get_range(list->priv->spinDistance, span, span + 1); gtk_spin_button_set_value(list->priv->spinDistance, (span[0] + span[1]) / 2.); gtk_spin_button_set_numeric(list->priv->spinDistance, TRUE); gtk_box_pack_start(GTK_BOX(hbox), GTK_WIDGET(list->priv->spinDistance), FALSE, FALSE, 0); PARAM_LINE(_("Color: ")); list->priv->comboColor = VISU_UI_COLOR_COMBOBOX(visu_ui_color_combobox_new(TRUE)); gtk_box_pack_start(GTK_BOX(hbox), GTK_WIDGET(list->priv->comboColor), FALSE, FALSE, 0); g_object_ref(list->priv->controls); return list->priv->controls; } v_sim-3.8.0/src/uiElements/ui_planetree.h000066400000000000000000000117741370110300500203650ustar00rootroot00000000000000/* EXTRAITS DE LA LICENCE Copyright CEA, contributeurs : Damien CALISTE, laboratoire L_Sim, (2015) Adresse mèl : CALISTE, damien P caliste AT cea P fr. Ce logiciel est un programme informatique servant à visualiser des structures atomiques dans un rendu pseudo-3D. Ce logiciel est régi par la licence CeCILL soumise au droit français et respectant les principes de diffusion des logiciels libres. Vous pouvez utiliser, modifier et/ou redistribuer ce programme sous les conditions de la licence CeCILL telle que diffusée par le CEA, le CNRS et l'INRIA sur le site "http://www.cecill.info". Le fait que vous puissiez accéder à cet en-tête signifie que vous avez pris connaissance de la licence CeCILL, et que vous en avez accepté les termes (cf. le fichier Documentation/licence.fr.txt fourni avec ce logiciel). */ /* LICENCE SUM UP Copyright CEA, contributors : Damien CALISTE, laboratoire L_Sim, (2015) E-mail address: CALISTE, damien P caliste AT cea P fr. This software is a computer program whose purpose is to visualize atomic configurations in 3D. This software is governed by the CeCILL license under French law and abiding by the rules of distribution of free software. You can use, modify and/ or redistribute the software under the terms of the CeCILL license as circulated by CEA, CNRS and INRIA at the following URL "http://www.cecill.info". The fact that you are presently reading this means that you have had knowledge of the CeCILL license and that you accept its terms. You can find a copy of this licence shipped with this software at Documentation/licence.en.txt. */ #ifndef VISU_UI_PLANE_LIST_H #define VISU_UI_PLANE_LIST_H #include #include #include #include /***************/ /* Public part */ /***************/ /** * VISU_TYPE_UI_PLANE_LIST: * * return the type of #VisuUiPlaneList. */ #define VISU_TYPE_UI_PLANE_LIST (visu_ui_plane_list_get_type ()) /** * VISU_UI_PLANE_LIST: * @obj: a #GObject to cast. * * Cast the given @obj into #VisuUiPlaneList type. */ #define VISU_UI_PLANE_LIST(obj) (G_TYPE_CHECK_INSTANCE_CAST(obj, VISU_TYPE_UI_PLANE_LIST, VisuUiPlaneList)) /** * VISU_UI_PLANE_LIST_CLASS: * @klass: a #GObjectClass to cast. * * Cast the given @klass into #VisuUiPlaneListClass. */ #define VISU_UI_PLANE_LIST_CLASS(klass) (G_TYPE_CHECK_CLASS_CAST(klass, VISU_TYPE_UI_PLANE_LIST, VisuUiPlaneListClass)) /** * VISU_IS_UI_PLANE_LIST: * @obj: a #GObject to test. * * Test if the given @ogj is of the type of #VisuUiPlaneList object. */ #define VISU_IS_UI_PLANE_LIST(obj) (G_TYPE_CHECK_INSTANCE_TYPE(obj, VISU_TYPE_UI_PLANE_LIST)) /** * VISU_IS_UI_PLANE_LIST_CLASS: * @klass: a #GObjectClass to test. * * Test if the given @klass is of the type of #VisuUiPlaneListClass class. */ #define VISU_IS_UI_PLANE_LIST_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE(klass, VISU_TYPE_UI_PLANE_LIST)) /** * VISU_UI_PLANE_LIST_GET_CLASS: * @obj: a #GObject to get the class of. * * It returns the class of the given @obj. */ #define VISU_UI_PLANE_LIST_GET_CLASS(obj) (G_TYPE_INSTANCE_GET_CLASS(obj, VISU_TYPE_UI_PLANE_LIST, VisuUiPlaneListClass)) /** * VisuUiPlaneListPrivate: * * Private data for #VisuUiPlaneList objects. */ typedef struct _VisuUiPlaneListPrivate VisuUiPlaneListPrivate; /** * VisuUiPlaneList: * * Common name to refer to a #_VisuUiPlaneList. */ typedef struct _VisuUiPlaneList VisuUiPlaneList; struct _VisuUiPlaneList { GtkListStore parent; VisuUiPlaneListPrivate *priv; }; /** * VisuUiPlaneListClass: * @parent: private. * * Common name to refer to a #_VisuUiPlaneListClass. */ typedef struct _VisuUiPlaneListClass VisuUiPlaneListClass; struct _VisuUiPlaneListClass { GtkListStoreClass parent; }; /** * visu_ui_plane_list_get_type: * * This method returns the type of #VisuUiPlaneList, use * VISU_TYPE_UI_PLANE_LIST instead. * * Since: 3.8 * * Returns: the type of #VisuUiPlaneList. */ GType visu_ui_plane_list_get_type(void); /** * VisuUiPlaneListColumnId: * @VISU_UI_PLANE_LIST_POINTER: the pointer to the #VisuPlane object. * @VISU_UI_PLANE_LIST_NOTIFY: a handler of the VisuPlane::notify signal. * @VISU_UI_PLANE_LIST_MODE: cache the hidding side of the plane when * plane is not hiding. * @VISU_UI_PLANE_LIST_N_COLUMNS: the number of columns. * * Thesse are the description of the columns stored in the object. */ typedef enum { VISU_UI_PLANE_LIST_POINTER, VISU_UI_PLANE_LIST_NOTIFY, VISU_UI_PLANE_LIST_MODE, VISU_UI_PLANE_LIST_N_COLUMNS } VisuUiPlaneListColumnId; VisuUiPlaneList* visu_ui_plane_list_new(); VisuPlaneSet* visu_ui_plane_list_getModel(const VisuUiPlaneList *list); gboolean visu_ui_plane_list_setModel(VisuUiPlaneList *list, VisuPlaneSet *set); GtkWidget* visu_ui_plane_list_getView(VisuUiPlaneList *list); GtkBox* visu_ui_plane_list_getControls(VisuUiPlaneList *list); VisuPlane* visu_ui_plane_list_getSelection(const VisuUiPlaneList *list); VisuPlane* visu_ui_plane_list_getAt(VisuUiPlaneList *list, guint i); #endif v_sim-3.8.0/src/uiElements/ui_properties.c000066400000000000000000000342771370110300500206000ustar00rootroot00000000000000/* EXTRAITS DE LA LICENCE Copyright CEA, contributeurs : Damien CALISTE, laboratoire L_Sim, (2017) Adresse mèl : CALISTE, damien P caliste AT cea P fr. Ce logiciel est un programme informatique servant à visualiser des structures atomiques dans un rendu pseudo-3D. Ce logiciel est régi par la licence CeCILL soumise au droit français et respectant les principes de diffusion des logiciels libres. Vous pouvez utiliser, modifier et/ou redistribuer ce programme sous les conditions de la licence CeCILL telle que diffusée par le CEA, le CNRS et l'INRIA sur le site "http://www.cecill.info". Le fait que vous puissiez accéder à cet en-tête signifie que vous avez pris connaissance de la licence CeCILL, et que vous en avez accepté les termes (cf. le fichier Documentation/licence.fr.txt fourni avec ce logiciel). */ /* LICENCE SUM UP Copyright CEA, contributors : Damien CALISTE, laboratoire L_Sim, (2017) E-mail address: CALISTE, damien P caliste AT cea P fr. This software is a computer program whose purpose is to visualize atomic configurations in 3D. This software is governed by the CeCILL license under French law and abiding by the rules of distribution of free software. You can use, modify and/ or redistribute the software under the terms of the CeCILL license as circulated by CEA, CNRS and INRIA at the following URL "http://www.cecill.info". The fact that you are presently reading this means that you have had knowledge of the CeCILL license and that you accept its terms. You can find a copy of this licence shipped with this software at Documentation/licence.en.txt. */ #include "ui_properties.h" /** * SECTION:ui_properties * @short_description: A specialised combo box to list node properties * of a #VisuData object. * * This object is a specialised combo box that lists the node * properties of a given #VisuData object. */ struct _VisuUiComboValuesPrivate { gboolean dispose_has_run; VisuData *data; gulong propAdd_signal, propRemoved_signal; GtkListStore *model; }; enum { PROP_0, MODEL_PROP, VALUES_PROP, N_PROP }; static GParamSpec *_properties[N_PROP]; /* The ids of the columns used in the combobox that identify each data node. */ enum { COLUMN_COMBO_LABEL, COLUMN_COMBO_STOCK, COLUMN_COMBO_OBJECT, NB_COLUMN_COMBO }; static void visu_ui_combo_values_dispose (GObject* obj); static void visu_ui_combo_values_finalize (GObject* obj); static void visu_ui_combo_values_get_property(GObject* obj, guint property_id, GValue *value, GParamSpec *pspec); static void visu_ui_combo_values_set_property(GObject* obj, guint property_id, const GValue *value, GParamSpec *pspec); G_DEFINE_TYPE_WITH_CODE(VisuUiComboValues, visu_ui_combo_values, GTK_TYPE_COMBO_BOX, G_ADD_PRIVATE(VisuUiComboValues)) /* Local callbacks. */ static void onPropAdded(VisuUiComboValues *combo, VisuNodeValues *prop); static void onPropRemoved(VisuUiComboValues *combo, VisuNodeValues *prop); static void emitValuesNotify(GObject *combo); /* Local routines. */ static void visu_ui_combo_values_class_init(VisuUiComboValuesClass *klass) { DBG_fprintf(stderr, "Visu UiCombo_Values: creating the class of the object.\n"); /* DBG_fprintf(stderr, " - adding new signals ;\n"); */ /* Connect the overloading methods. */ G_OBJECT_CLASS(klass)->dispose = visu_ui_combo_values_dispose; G_OBJECT_CLASS(klass)->finalize = visu_ui_combo_values_finalize; G_OBJECT_CLASS(klass)->set_property = visu_ui_combo_values_set_property; G_OBJECT_CLASS(klass)->get_property = visu_ui_combo_values_get_property; /** * VisuUiComboValues::model: * * The #VisuData this combo_values is operating on. * * Since: 3.8 */ _properties[MODEL_PROP] = g_param_spec_object ("model", "Model", "node model.", VISU_TYPE_DATA, G_PARAM_READWRITE); /** * VisuUiComboValues::active-values: * * The currently selected #VisuNodeValues. * * Since: 3.8 */ _properties[VALUES_PROP] = g_param_spec_object ("active-values", "Active values", "current selection.", VISU_TYPE_NODE_VALUES, G_PARAM_READWRITE); g_object_class_install_properties(G_OBJECT_CLASS(klass), N_PROP, _properties); } static void visu_ui_combo_values_init(VisuUiComboValues *list) { GtkCellRenderer *renderer; DBG_fprintf(stderr, "Visu UiCombo_Values: initializing a new object (%p).\n", (gpointer)list); list->priv = visu_ui_combo_values_get_instance_private(list); list->priv->dispose_has_run = FALSE; list->priv->data = (VisuData*)0; list->priv->model = gtk_list_store_new(NB_COLUMN_COMBO, G_TYPE_STRING, G_TYPE_STRING, VISU_TYPE_NODE_VALUES); gtk_combo_box_set_model(GTK_COMBO_BOX(list), GTK_TREE_MODEL(list->priv->model)); renderer = gtk_cell_renderer_pixbuf_new(); gtk_cell_layout_pack_start(GTK_CELL_LAYOUT(list), renderer, FALSE); gtk_cell_layout_add_attribute(GTK_CELL_LAYOUT(list), renderer, "stock-id", COLUMN_COMBO_STOCK); renderer = gtk_cell_renderer_text_new(); gtk_cell_layout_pack_start(GTK_CELL_LAYOUT(list), renderer, FALSE); gtk_cell_layout_add_attribute(GTK_CELL_LAYOUT(list), renderer, "markup", COLUMN_COMBO_LABEL); g_signal_connect(list, "changed", G_CALLBACK(emitValuesNotify), (gpointer)0); } static void visu_ui_combo_values_dispose(GObject* obj) { VisuUiComboValues *list; DBG_fprintf(stderr, "Visu UiCombo_Values: dispose object %p.\n", (gpointer)obj); list = VISU_UI_COMBO_VALUES(obj); if (list->priv->dispose_has_run) return; list->priv->dispose_has_run = TRUE; visu_ui_combo_values_setNodeModel(list, (VisuData*)0); gtk_combo_box_set_model(GTK_COMBO_BOX(list), NULL); /* Chain up to the parent class */ G_OBJECT_CLASS(visu_ui_combo_values_parent_class)->dispose(obj); } static void visu_ui_combo_values_finalize(GObject* obj) { VisuUiComboValues *list; DBG_fprintf(stderr, "Visu UiCombo_Values: finalize object %p.\n", (gpointer)obj); list = VISU_UI_COMBO_VALUES(obj); DBG_fprintf(stderr, " | model (%d)\n", G_OBJECT(list->priv->model)->ref_count); g_object_unref(list->priv->model); /* Chain up to the parent class */ G_OBJECT_CLASS(visu_ui_combo_values_parent_class)->finalize(obj); } static void visu_ui_combo_values_get_property(GObject* obj, guint property_id, GValue *value, GParamSpec *pspec) { DBG_fprintf(stderr, "Visu UiCombo_Values: get property '%s' -> ", g_param_spec_get_name(pspec)); switch (property_id) { case MODEL_PROP: g_value_set_object(value, VISU_UI_COMBO_VALUES(obj)->priv->data); DBG_fprintf(stderr, "%p.\n", g_value_get_object(value)); break; case VALUES_PROP: g_value_set_object(value, visu_ui_combo_values_getActive(VISU_UI_COMBO_VALUES(obj))); DBG_fprintf(stderr, "%p.\n", g_value_get_object(value)); break; default: /* We don't have any other property... */ G_OBJECT_WARN_INVALID_PROPERTY_ID(obj, property_id, pspec); break; } } static void visu_ui_combo_values_set_property(GObject* obj, guint property_id, const GValue *value, GParamSpec *pspec) { VisuUiComboValues *list = VISU_UI_COMBO_VALUES(obj); DBG_fprintf(stderr, "Visu UiCombo_Values: set property '%s' -> ", g_param_spec_get_name(pspec)); switch (property_id) { case MODEL_PROP: DBG_fprintf(stderr, "%p.\n", g_value_get_object(value)); visu_ui_combo_values_setNodeModel(list, VISU_DATA(g_value_get_object(value))); break; case VALUES_PROP: DBG_fprintf(stderr, "%p.\n", g_value_get_object(value)); visu_ui_combo_values_setActive(list, VISU_NODE_VALUES(g_value_get_object(value))); break; default: /* We don't have any other property... */ G_OBJECT_WARN_INVALID_PROPERTY_ID(obj, property_id, pspec); break; } } /** * visu_ui_combo_values_new: * * Create a new #GtkListStore to store planes. * * Since: 3.8 * * Returns: a newly created object. **/ GtkWidget* visu_ui_combo_values_new() { return g_object_new(VISU_TYPE_UI_COMBO_VALUES, NULL); } /** * visu_ui_combo_values_setNodeModel: * @combo: a #VisuUiComboValues object. * @data: (allow-none): a #VisuData object. * * Bind the @set object to @list. * * Returns: TRUE if @set is changed **/ gboolean visu_ui_combo_values_setNodeModel(VisuUiComboValues *combo, VisuData *data) { GList *lst, *tmpLst; VisuNodeValues *values; g_return_val_if_fail(VISU_IS_UI_COMBO_VALUES(combo), FALSE); if (combo->priv->data == data) return FALSE; values = visu_ui_combo_values_getActive(combo); if (values) g_object_ref(values); gtk_list_store_clear(combo->priv->model); if (combo->priv->data) { g_signal_handler_disconnect(G_OBJECT(combo->priv->data), combo->priv->propAdd_signal); g_signal_handler_disconnect(G_OBJECT(combo->priv->data), combo->priv->propRemoved_signal); g_object_unref(combo->priv->data); } combo->priv->data = data; if (data) { g_object_ref(data); combo->priv->propAdd_signal = g_signal_connect_swapped (G_OBJECT(data), "node-properties-added", G_CALLBACK(onPropAdded), combo); combo->priv->propRemoved_signal = g_signal_connect_swapped (G_OBJECT(data), "node-properties-removed", G_CALLBACK(onPropRemoved), combo); lst = visu_data_getAllNodeProperties(data); for (tmpLst = lst; tmpLst; tmpLst = g_list_next(tmpLst)) onPropAdded(combo, VISU_NODE_VALUES(tmpLst->data)); g_list_free(lst); if (values) visu_ui_combo_values_setActiveByLabel(combo, visu_node_values_getLabel(values)); } if (values) g_object_unref(values); return TRUE; } static void onPropAdded(VisuUiComboValues *combo, VisuNodeValues *prop) { gchar *markup; GtkTreeIter iter; markup = g_markup_printf_escaped("%s", visu_node_values_getLabel(prop)); gtk_list_store_append(combo->priv->model, &iter); gtk_list_store_set(combo->priv->model, &iter, COLUMN_COMBO_LABEL, markup, COLUMN_COMBO_OBJECT, prop, -1); g_free(markup); if (visu_node_values_getEditable(prop)) gtk_list_store_set(combo->priv->model, &iter, COLUMN_COMBO_STOCK, "gtk-edit", -1); } static void onPropRemoved(VisuUiComboValues *combo, VisuNodeValues *prop) { VisuNodeValues *myprop; gboolean valid; GtkTreeIter iter; for (valid = gtk_tree_model_get_iter_first(GTK_TREE_MODEL(combo->priv->model), &iter); valid; ) { gtk_tree_model_get(GTK_TREE_MODEL(combo->priv->model), &iter, COLUMN_COMBO_OBJECT, &myprop, -1); if (myprop) g_object_unref(myprop); if (myprop == prop) valid = gtk_list_store_remove(combo->priv->model, &iter); else valid = gtk_tree_model_iter_next(GTK_TREE_MODEL(combo->priv->model), &iter); } } /** * visu_ui_combo_values_getActive: * @combo: a #VisuUiComboValues object. * * Retrieves the currently selected #VisuNodeValues object. * * Since: 3.8 * * Returns: (transfer none): the selected #VisuNodeValues object. **/ VisuNodeValues* visu_ui_combo_values_getActive(VisuUiComboValues *combo) { GtkTreeIter iter; VisuNodeValues *values; g_return_val_if_fail(VISU_IS_UI_COMBO_VALUES(combo), (VisuNodeValues*)0); if (!gtk_combo_box_get_active_iter(GTK_COMBO_BOX(combo), &iter)) return (VisuNodeValues*)0; gtk_tree_model_get(GTK_TREE_MODEL(combo->priv->model), &iter, COLUMN_COMBO_OBJECT, &values, -1); if (values) g_object_unref(values); return values; } /** * visu_ui_combo_values_setActive: * @combo: a #VisuUiComboValues object. * @values: a #VisuNodeValues object. * * Changes current selection of @combo to be on @values. If @values is * not part of @combo, nothing is changed and %FALSE is returned. * * Since: 3.8 * * Returns: TRUE if @values exists in @combo. **/ gboolean visu_ui_combo_values_setActive(VisuUiComboValues *combo, const VisuNodeValues *values) { GtkTreeIter iter; gboolean valid; VisuNodeValues *prop; g_return_val_if_fail(VISU_IS_UI_COMBO_VALUES(combo), FALSE); for (valid = gtk_tree_model_get_iter_first(GTK_TREE_MODEL(combo->priv->model), &iter); valid; valid = gtk_tree_model_iter_next(GTK_TREE_MODEL(combo->priv->model), &iter)) { gtk_tree_model_get(GTK_TREE_MODEL(combo->priv->model), &iter, COLUMN_COMBO_OBJECT, &prop, -1); g_object_unref(prop); if (prop == values) { gtk_combo_box_set_active_iter(GTK_COMBO_BOX(combo), &iter); return TRUE; } } return FALSE; } /** * visu_ui_combo_values_setActiveByLabel: * @combo: a #VisuUiComboValues object. * @label: a label. * * Changes current selection of @combo to match a #VisuNodeValues * property that is defined by @label. If none exists, nothing is * changed and %FALSE is returned. * * Since: 3.8 * * Returns: TRUE if @label exists in @combo. **/ gboolean visu_ui_combo_values_setActiveByLabel(VisuUiComboValues *combo, const gchar* label) { GtkTreeIter iter; gboolean valid; VisuNodeValues *prop; g_return_val_if_fail(VISU_IS_UI_COMBO_VALUES(combo), FALSE); if (!label) return FALSE; for (valid = gtk_tree_model_get_iter_first(GTK_TREE_MODEL(combo->priv->model), &iter); valid; valid = gtk_tree_model_iter_next(GTK_TREE_MODEL(combo->priv->model), &iter)) { gtk_tree_model_get(GTK_TREE_MODEL(combo->priv->model), &iter, COLUMN_COMBO_OBJECT, &prop, -1); g_object_unref(prop); if (!strcmp(visu_node_values_getLabel(prop), label)) { gtk_combo_box_set_active_iter(GTK_COMBO_BOX(combo), &iter); return TRUE; } } return FALSE; } static void emitValuesNotify(GObject *combo) { DBG_fprintf(stderr, "Visu UiComboValues: emitting active-values notification.\n"); g_object_notify_by_pspec(combo, _properties[VALUES_PROP]); } v_sim-3.8.0/src/uiElements/ui_properties.h000066400000000000000000000111021370110300500205630ustar00rootroot00000000000000/* EXTRAITS DE LA LICENCE Copyright CEA, contributeurs : Damien CALISTE, laboratoire L_Sim, (2017) Adresse mèl : CALISTE, damien P caliste AT cea P fr. Ce logiciel est un programme informatique servant à visualiser des structures atomiques dans un rendu pseudo-3D. Ce logiciel est régi par la licence CeCILL soumise au droit français et respectant les principes de diffusion des logiciels libres. Vous pouvez utiliser, modifier et/ou redistribuer ce programme sous les conditions de la licence CeCILL telle que diffusée par le CEA, le CNRS et l'INRIA sur le site "http://www.cecill.info". Le fait que vous puissiez accéder à cet en-tête signifie que vous avez pris connaissance de la licence CeCILL, et que vous en avez accepté les termes (cf. le fichier Documentation/licence.fr.txt fourni avec ce logiciel). */ /* LICENCE SUM UP Copyright CEA, contributors : Damien CALISTE, laboratoire L_Sim, (2017) E-mail address: CALISTE, damien P caliste AT cea P fr. This software is a computer program whose purpose is to visualize atomic configurations in 3D. This software is governed by the CeCILL license under French law and abiding by the rules of distribution of free software. You can use, modify and/ or redistribute the software under the terms of the CeCILL license as circulated by CEA, CNRS and INRIA at the following URL "http://www.cecill.info". The fact that you are presently reading this means that you have had knowledge of the CeCILL license and that you accept its terms. You can find a copy of this licence shipped with this software at Documentation/licence.en.txt. */ #ifndef VISU_UI_COMBO_VALUES_H #define VISU_UI_COMBO_VALUES_H #include #include #include #include #include /***************/ /* Public part */ /***************/ /** * VISU_TYPE_UI_COMBO_VALUES: * * return the type of #VisuUiComboValues. */ #define VISU_TYPE_UI_COMBO_VALUES (visu_ui_combo_values_get_type ()) /** * VISU_UI_COMBO_VALUES: * @obj: a #GObject to cast. * * Cast the given @obj into #VisuUiComboValues type. */ #define VISU_UI_COMBO_VALUES(obj) (G_TYPE_CHECK_INSTANCE_CAST(obj, VISU_TYPE_UI_COMBO_VALUES, VisuUiComboValues)) /** * VISU_UI_COMBO_VALUES_CLASS: * @klass: a #GObjectClass to cast. * * Cast the given @klass into #VisuUiComboValuesClass. */ #define VISU_UI_COMBO_VALUES_CLASS(klass) (G_TYPE_CHECK_CLASS_CAST(klass, VISU_TYPE_UI_COMBO_VALUES, VisuUiComboValuesClass)) /** * VISU_IS_UI_COMBO_VALUES: * @obj: a #GObject to test. * * Test if the given @ogj is of the type of #VisuUiComboValues object. */ #define VISU_IS_UI_COMBO_VALUES(obj) (G_TYPE_CHECK_INSTANCE_TYPE(obj, VISU_TYPE_UI_COMBO_VALUES)) /** * VISU_IS_UI_COMBO_VALUES_CLASS: * @klass: a #GObjectClass to test. * * Test if the given @klass is of the type of #VisuUiComboValuesClass class. */ #define VISU_IS_UI_COMBO_VALUES_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE(klass, VISU_TYPE_UI_COMBO_VALUES)) /** * VISU_UI_COMBO_VALUES_GET_CLASS: * @obj: a #GObject to get the class of. * * It returns the class of the given @obj. */ #define VISU_UI_COMBO_VALUES_GET_CLASS(obj) (G_TYPE_INSTANCE_GET_CLASS(obj, VISU_TYPE_UI_COMBO_VALUES, VisuUiComboValuesClass)) /** * VisuUiComboValuesPrivate: * * Private data for #VisuUiComboValues objects. */ typedef struct _VisuUiComboValuesPrivate VisuUiComboValuesPrivate; /** * VisuUiComboValues: * * Common name to refer to a #_VisuUiComboValues. */ typedef struct _VisuUiComboValues VisuUiComboValues; struct _VisuUiComboValues { GtkComboBox parent; VisuUiComboValuesPrivate *priv; }; /** * VisuUiComboValuesClass: * @parent: private. * * Common name to refer to a #_VisuUiComboValuesClass. */ typedef struct _VisuUiComboValuesClass VisuUiComboValuesClass; struct _VisuUiComboValuesClass { GtkComboBoxClass parent; }; /** * visu_ui_combo_values_get_type: * * This method returns the type of #VisuUiComboValues, use * VISU_TYPE_UI_COMBO_VALUES instead. * * Since: 3.8 * * Returns: the type of #VisuUiComboValues. */ GType visu_ui_combo_values_get_type(void); GtkWidget* visu_ui_combo_values_new(); gboolean visu_ui_combo_values_setNodeModel(VisuUiComboValues *combo, VisuData *data); VisuNodeValues* visu_ui_combo_values_getActive(VisuUiComboValues *combo); gboolean visu_ui_combo_values_setActive(VisuUiComboValues *combo, const VisuNodeValues *values); gboolean visu_ui_combo_values_setActiveByLabel(VisuUiComboValues *combo, const gchar* label); #endif v_sim-3.8.0/src/uiElements/ui_scale.c000066400000000000000000000247031370110300500174640ustar00rootroot00000000000000/* EXTRAITS DE LA LICENCE Copyright CEA, contributeurs : Damien CALISTE, laboratoire L_Sim, (2001-2014) Adresse mèl : CALISTE, damien P caliste AT cea P fr. Ce logiciel est un programme informatique servant à visualiser des structures atomiques dans un rendu pseudo-3D. Ce logiciel est régi par la licence CeCILL soumise au droit français et respectant les principes de diffusion des logiciels libres. Vous pouvez utiliser, modifier et/ou redistribuer ce programme sous les conditions de la licence CeCILL telle que diffusée par le CEA, le CNRS et l'INRIA sur le site "http://www.cecill.info". Le fait que vous puissiez accéder à cet en-tête signifie que vous avez pris connaissance de la licence CeCILL, et que vous en avez accepté les termes (cf. le fichier Documentation/licence.fr.txt fourni avec ce logiciel). */ /* LICENCE SUM UP Copyright CEA, contributors : Damien CALISTE, laboratoire L_Sim, (2001-2014) E-mail address: CALISTE, damien P caliste AT cea P fr. This software is a computer program whose purpose is to visualize atomic configurations in 3D. This software is governed by the CeCILL license under French law and abiding by the rules of distribution of free software. You can use, modify and/ or redistribute the software under the terms of the CeCILL license as circulated by CEA, CNRS and INRIA at the following URL "http://www.cecill.info". The fact that you are presently reading this means that you have had knowledge of the CeCILL license and that you accept its terms. You can find a copy of this licence shipped with this software at Documentation/licence.en.txt. */ #include "ui_scale.h" #include #include #include /** * SECTION:ui_scale * @short_description: Defines a widget to setup scale. * * A set of widgets to setup the rendring of a scale. */ /** * VisuUiScaleClass: * @parent: the parent class; * * A short way to identify #_VisuUiScaleClass structure. * * Since: 3.8 */ /** * VisuUiScale: * * An opaque structure. * * Since: 3.8 */ /** * VisuUiScalePrivate: * * Private fields for #VisuUiScale objects. * * Since: 3.8 */ struct _VisuUiScalePrivate { gboolean dispose_has_run; GtkWidget *lblScales; GtkWidget *spinScaleLength; GtkWidget *entryScale; GtkWidget *originespin[3]; GtkWidget *orientationspin[3]; VisuGlExtScale *model; GBinding *bind_warn; GBinding *bind_lg, *bind_lbl; GBinding *bind_orig[3]; GBinding *bind_dir[3]; }; static void visu_ui_scale_finalize(GObject* obj); static void visu_ui_scale_dispose(GObject* obj); G_DEFINE_TYPE_WITH_CODE(VisuUiScale, visu_ui_scale, VISU_TYPE_UI_LINE, G_ADD_PRIVATE(VisuUiScale)) static void visu_ui_scale_class_init(VisuUiScaleClass *klass) { DBG_fprintf(stderr, "Ui Scale: creating the class of the widget.\n"); DBG_fprintf(stderr, " - adding new signals ;\n"); /* Connect freeing methods. */ G_OBJECT_CLASS(klass)->dispose = visu_ui_scale_dispose; G_OBJECT_CLASS(klass)->finalize = visu_ui_scale_finalize; } static void visu_ui_scale_dispose(GObject *obj) { DBG_fprintf(stderr, "Ui Scale: dispose object %p.\n", (gpointer)obj); if (VISU_UI_SCALE(obj)->priv->dispose_has_run) return; visu_ui_scale_bind(VISU_UI_SCALE(obj), (VisuGlExtScale*)0); VISU_UI_SCALE(obj)->priv->dispose_has_run = TRUE; /* Chain up to the parent class */ G_OBJECT_CLASS(visu_ui_scale_parent_class)->dispose(obj); } static void visu_ui_scale_finalize(GObject *obj) { g_return_if_fail(obj); DBG_fprintf(stderr, "Ui Scale: finalize object %p.\n", (gpointer)obj); /* Chain up to the parent class */ G_OBJECT_CLASS(visu_ui_scale_parent_class)->finalize(obj); DBG_fprintf(stderr, " | freeing ... OK.\n"); } static void visu_ui_scale_init(VisuUiScale *obj) { GtkWidget *vbox, *hbox; GtkWidget *table, *label; gchar *lblXYZ[3] = {"X", "Y", "Z"}; int i; #if GTK_MAJOR_VERSION == 2 && GTK_MINOR_VERSION < 12 GtkTooltips *tooltips; tooltips = gtk_tooltips_new (); #endif obj->priv = visu_ui_scale_get_instance_private(obj); obj->priv->dispose_has_run = FALSE; obj->priv->model = (VisuGlExtScale*)0; vbox = visu_ui_line_getOptionBox(VISU_UI_LINE(obj)); /* To be removed. */ obj->priv->lblScales = gtk_label_new(_("Several scales are defined from resource files, " "but only one is editable.")); gtk_label_set_line_wrap(GTK_LABEL(obj->priv->lblScales), TRUE); gtk_label_set_use_markup(GTK_LABEL(obj->priv->lblScales), TRUE); gtk_box_pack_end(GTK_BOX(vbox), obj->priv->lblScales, FALSE, FALSE, 10); gtk_widget_set_no_show_all(obj->priv->lblScales, TRUE); hbox = gtk_hbox_new(FALSE,0); gtk_box_pack_start(GTK_BOX(vbox),hbox,FALSE,FALSE,5); label = gtk_label_new(_("Legend:")); gtk_box_pack_start(GTK_BOX(hbox),label, FALSE, FALSE, 0); obj->priv->entryScale = gtk_entry_new(); #if GTK_MAJOR_VERSION > 3 || (GTK_MAJOR_VERSION == 3 && GTK_MINOR_VERSION > 1) gtk_entry_set_placeholder_text(GTK_ENTRY(obj->priv->entryScale), _("Default legend displays the length.")); #endif gtk_widget_set_tooltip_text(obj->priv->entryScale, _("Use blank legend to print the default" " value with the distance.")); gtk_box_pack_start(GTK_BOX(hbox), obj->priv->entryScale, TRUE, TRUE, 0); hbox = gtk_hbox_new(FALSE,0); gtk_box_pack_start(GTK_BOX(vbox), hbox, FALSE, FALSE, 5); label = gtk_label_new(_("Length:")); gtk_box_pack_start(GTK_BOX(hbox), label, FALSE, FALSE, 0); obj->priv->spinScaleLength = gtk_spin_button_new_with_range(0., 1000., 1.); gtk_spin_button_set_digits(GTK_SPIN_BUTTON(obj->priv->spinScaleLength), 2); gtk_widget_set_halign(obj->priv->spinScaleLength, GTK_ALIGN_END); gtk_box_pack_start(GTK_BOX(hbox), obj->priv->spinScaleLength, TRUE, TRUE, 0); table = gtk_grid_new(); tool_grid_resize(table, 3, 3); gtk_box_pack_start(GTK_BOX(vbox), table, FALSE, FALSE, 5); label = gtk_label_new(_("Origin:")); gtk_widget_set_hexpand(label, TRUE); gtk_label_set_xalign(GTK_LABEL(label), 0.); gtk_grid_attach(GTK_GRID(table), label, 0, 0, 1, 1); for (i = 0; i < 3; i++) { gtk_grid_attach(GTK_GRID(table), gtk_label_new(lblXYZ[i]), 1, i, 1, 1); obj->priv->originespin[i] = gtk_spin_button_new_with_range(-999., 999., 1.); gtk_spin_button_set_digits(GTK_SPIN_BUTTON(obj->priv->originespin[i]), 2); gtk_grid_attach(GTK_GRID(table), obj->priv->originespin[i], 2, i, 1, 1); } table = gtk_grid_new(); tool_grid_resize(table, 3, 3); gtk_box_pack_start(GTK_BOX(vbox), table, FALSE, FALSE, 5); label = gtk_label_new(_("Orientation:")); gtk_widget_set_hexpand(label, TRUE); gtk_label_set_xalign(GTK_LABEL(label), 0.); gtk_grid_attach(GTK_GRID(table), label, 0, 0, 1, 1); for (i = 0; i < 3; i++) { gtk_grid_attach(GTK_GRID(table), gtk_label_new(lblXYZ[i]), 1, i, 1, 1); obj->priv->orientationspin[i] = gtk_spin_button_new_with_range(-999., 999., 1.); gtk_spin_button_set_digits(GTK_SPIN_BUTTON(obj->priv->orientationspin[i]), 2); gtk_grid_attach(GTK_GRID(table), obj->priv->orientationspin[i], 2, i, 1, 1); } gtk_widget_show_all(GTK_WIDGET(vbox)); } /** * visu_ui_scale_new: * * Creates a new #VisuUiScale to allow to setup scale rendering characteristics. * * Since: 3.8 * * Returns: a pointer to the newly created widget. */ GtkWidget* visu_ui_scale_new() { DBG_fprintf(stderr,"Ui Scale: new object.\n"); return GTK_WIDGET(g_object_new(VISU_TYPE_UI_SCALE, "label", _("Label"), NULL)); } static gboolean showWarning(GBinding *bind _U_, const GValue *source, GValue *target, gpointer user_data _U_) { g_value_set_boolean(target, g_value_get_uint(source) > 1); return TRUE; } /** * visu_ui_scale_bind: * @scale: a #VisuUiScale object. * @model: (transfer full): a #VisuGlExtScale object. * * Bind the properties of @model to be displayed by @scale. * * Since: 3.8 **/ void visu_ui_scale_bind(VisuUiScale *scale, VisuGlExtScale *model) { const gchar *orig[3] = { "current-origin-x", "current-origin-y", "current-origin-z" }; const gchar *dir[3] = { "current-orientation-x", "current-orientation-y", "current-orientation-z" }; guint i; g_return_if_fail(VISU_IS_UI_SCALE(scale)); if (scale->priv->model == model) return; visu_ui_line_bind(VISU_UI_LINE(scale), VISU_GL_EXT_LINED(model)); if (scale->priv->model) { g_object_unref(G_OBJECT(scale->priv->bind_lg)); g_object_unref(G_OBJECT(scale->priv->bind_lbl)); g_object_unref(G_OBJECT(scale->priv->bind_orig[0])); g_object_unref(G_OBJECT(scale->priv->bind_orig[1])); g_object_unref(G_OBJECT(scale->priv->bind_orig[2])); g_object_unref(G_OBJECT(scale->priv->bind_dir[0])); g_object_unref(G_OBJECT(scale->priv->bind_dir[1])); g_object_unref(G_OBJECT(scale->priv->bind_dir[2])); g_object_unref(G_OBJECT(scale->priv->bind_warn)); g_object_unref(G_OBJECT(scale->priv->model)); } scale->priv->model = model; if (model) { g_object_ref(G_OBJECT(model)); scale->priv->bind_lg = g_object_bind_property(model, "current-length", scale->priv->spinScaleLength, "value", G_BINDING_BIDIRECTIONAL | G_BINDING_SYNC_CREATE); scale->priv->bind_lbl = g_object_bind_property(model, "current-label", scale->priv->entryScale, "text", G_BINDING_BIDIRECTIONAL | G_BINDING_SYNC_CREATE); for (i = 0; i < 3; i++) { scale->priv->bind_orig[i] = g_object_bind_property(model, orig[i], scale->priv->originespin[i], "value", G_BINDING_BIDIRECTIONAL | G_BINDING_SYNC_CREATE); scale->priv->bind_dir[i] = g_object_bind_property(model, dir[i], scale->priv->orientationspin[i], "value", G_BINDING_BIDIRECTIONAL | G_BINDING_SYNC_CREATE); } scale->priv->bind_warn = g_object_bind_property_full(model, "n-arrows", scale->priv->lblScales, "visible", G_BINDING_DEFAULT | G_BINDING_SYNC_CREATE, showWarning, NULL, NULL, NULL); } } v_sim-3.8.0/src/uiElements/ui_scale.h000066400000000000000000000073761370110300500175000ustar00rootroot00000000000000/* EXTRAITS DE LA LICENCE Copyright CEA, contributeurs : Luc BILLARD et Damien CALISTE, laboratoire L_Sim, (2001-2014) Adresse mèl : BILLARD, non joignable par mèl ; CALISTE, damien P caliste AT cea P fr. Ce logiciel est un programme informatique servant à visualiser des structures atomiques dans un rendu pseudo-3D. Ce logiciel est régi par la licence CeCILL soumise au droit français et respectant les principes de diffusion des logiciels libres. Vous pouvez utiliser, modifier et/ou redistribuer ce programme sous les conditions de la licence CeCILL telle que diffusée par le CEA, le CNRS et l'INRIA sur le site "http://www.cecill.info". Le fait que vous puissiez accéder à cet en-tête signifie que vous avez pris connaissance de la licence CeCILL, et que vous en avez accepté les termes (cf. le fichier Documentation/licence.fr.txt fourni avec ce logiciel). */ /* LICENCE SUM UP Copyright CEA, contributors : Luc BILLARD et Damien CALISTE, laboratoire L_Sim, (2001-2014) E-mail address: BILLARD, not reachable any more ; CALISTE, damien P caliste AT cea P fr. This software is a computer program whose purpose is to visualize atomic configurations in 3D. This software is governed by the CeCILL license under French law and abiding by the rules of distribution of free software. You can use, modify and/ or redistribute the software under the terms of the CeCILL license as circulated by CEA, CNRS and INRIA at the following URL "http://www.cecill.info". The fact that you are presently reading this means that you have had knowledge of the CeCILL license and that you accept its terms. You can find a copy of this licence shipped with this software at Documentation/licence.en.txt. */ #ifndef UI_SCALE_H #define UI_SCALE_H #include #include /** * VISU_TYPE_UI_SCALE: * * return the type of #VisuUiScale. * * Since: 3.8 */ #define VISU_TYPE_UI_SCALE (visu_ui_scale_get_type ()) /** * VISU_UI_SCALE: * @obj: a #GObject to cast. * * Cast the given @obj into #VisuUiScale type. * * Since: 3.8 */ #define VISU_UI_SCALE(obj) (G_TYPE_CHECK_INSTANCE_CAST(obj, VISU_TYPE_UI_SCALE, VisuUiScale)) /** * VISU_UI_SCALE_CLASS: * @klass: a #GObjectClass to cast. * * Cast the given @klass into #VisuUiScaleClass. * * Since: 3.8 */ #define VISU_UI_SCALE_CLASS(klass) (G_TYPE_CHECK_CLASS_CAST(klass, VISU_TYPE_UI_SCALE, VisuUiScaleClass)) /** * VISU_IS_UI_SCALE: * @obj: a #GObject to test. * * Test if the given @ogj is of the type of #VisuUiScale object. * * Since: 3.8 */ #define VISU_IS_UI_SCALE(obj) (G_TYPE_CHECK_INSTANCE_TYPE(obj, VISU_TYPE_UI_SCALE)) /** * VISU_IS_UI_SCALE_CLASS: * @klass: a #GObjectClass to test. * * Test if the given @klass is of the type of #VisuUiScaleClass class. * * Since: 3.8 */ #define VISU_IS_UI_SCALE_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE(klass, VISU_TYPE_UI_SCALE)) /** * VISU_UI_SCALE_GET_CLASS: * @obj: a #GObject to get the class of. * * It returns the class of the given @obj. * * Since: 3.8 */ #define VISU_UI_SCALE_GET_CLASS(obj) (G_TYPE_INSTANCE_GET_CLASS(obj, VISU_TYPE_UI_SCALE, VisuUiScaleClass)) typedef struct _VisuUiScale VisuUiScale; typedef struct _VisuUiScalePrivate VisuUiScalePrivate; typedef struct _VisuUiScaleClass VisuUiScaleClass; struct _VisuUiScale { VisuUiLine parent; VisuUiScalePrivate *priv; }; struct _VisuUiScaleClass { VisuUiLineClass parent; }; /** * visu_ui_scale_get_type: * * This method returns the type of #VisuUiScale, use * VISU_TYPE_UI_SCALE instead. * * Since: 3.8 * * Returns: the type of #VisuUiScale. */ GType visu_ui_scale_get_type(void); GtkWidget* visu_ui_scale_new(); void visu_ui_scale_bind(VisuUiScale *scale, VisuGlExtScale *model); #endif v_sim-3.8.0/src/uiElements/ui_selection.c000066400000000000000000000543711370110300500203660ustar00rootroot00000000000000/* EXTRAITS DE LA LICENCE Copyright CEA, contributeurs : Damien CALISTE, laboratoire L_Sim, (2017) Adresse mèl : CALISTE, damien P caliste AT cea P fr. Ce logiciel est un programme informatique servant à visualiser des structures atomiques dans un rendu pseudo-3D. Ce logiciel est régi par la licence CeCILL soumise au droit français et respectant les principes de diffusion des logiciels libres. Vous pouvez utiliser, modifier et/ou redistribuer ce programme sous les conditions de la licence CeCILL telle que diffusée par le CEA, le CNRS et l'INRIA sur le site "http://www.cecill.info". Le fait que vous puissiez accéder à cet en-tête signifie que vous avez pris connaissance de la licence CeCILL, et que vous en avez accepté les termes (cf. le fichier Documentation/licence.fr.txt fourni avec ce logiciel). */ /* LICENCE SUM UP Copyright CEA, contributors : Damien CALISTE, laboratoire L_Sim, (2017) E-mail address: CALISTE, damien P caliste AT cea P fr. This software is a computer program whose purpose is to visualize atomic configurations in 3D. This software is governed by the CeCILL license under French law and abiding by the rules of distribution of free software. You can use, modify and/ or redistribute the software under the terms of the CeCILL license as circulated by CEA, CNRS and INRIA at the following URL "http://www.cecill.info". The fact that you are presently reading this means that you have had knowledge of the CeCILL license and that you accept its terms. You can find a copy of this licence shipped with this software at Documentation/licence.en.txt. */ #include "ui_selection.h" /** * SECTION:ui_selection * @short_description: A specialised list store handling node selection. * * This is a specialised #GtkListStore to handle list of * nodes. It is storing the node ids and their highlight status. Their * highlight status is driven by a #VisuGlExtMarks model, see * visu_ui_selection_setHighlightModel(). If a #VisuData model is * provided by visu_ui_selection_setNodeModel(), then on population * changes, the non existing nodes are removed from the selection list. */ struct _VisuUiSelectionPrivate { gboolean dispose_has_run; VisuData *data; gulong popDec_signal; VisuGlExtMarks *marks; gulong hl_signal; gboolean highlight; }; enum { PROP_0, MODEL_PROP, MARKS_PROP, SELECTION_PROP, HIGHLIGHT_PROP, N_PROP }; static GParamSpec *_properties[N_PROP]; static void visu_ui_selection_dispose (GObject* obj); static void visu_ui_selection_get_property(GObject* obj, guint property_id, GValue *value, GParamSpec *pspec); static void visu_ui_selection_set_property(GObject* obj, guint property_id, const GValue *value, GParamSpec *pspec); G_DEFINE_TYPE_WITH_CODE(VisuUiSelection, visu_ui_selection, GTK_TYPE_LIST_STORE, G_ADD_PRIVATE(VisuUiSelection)) /* Local callbacks. */ /* Local routines. */ static void _updateHighlight(VisuUiSelection *selection); static void visu_ui_selection_class_init(VisuUiSelectionClass *klass) { DBG_fprintf(stderr, "Visu UiSelection: creating the class of the object.\n"); /* DBG_fprintf(stderr, " - adding new signals ;\n"); */ /* Connect the overloading methods. */ G_OBJECT_CLASS(klass)->dispose = visu_ui_selection_dispose; G_OBJECT_CLASS(klass)->set_property = visu_ui_selection_set_property; G_OBJECT_CLASS(klass)->get_property = visu_ui_selection_get_property; /** * VisuUiSelection::model: * * The #VisuData this selection is operating on. * * Since: 3.8 */ _properties[MODEL_PROP] = g_param_spec_object ("model", "Model", "node model.", VISU_TYPE_DATA, G_PARAM_READWRITE); /** * VisuUiSelection::marks: * * The #VisuGlExtMarks the highlight info are taken from. * * Since: 3.8 */ _properties[MARKS_PROP] = g_param_spec_object ("marks", "Marks", "highlight model.", VISU_TYPE_GL_EXT_MARKS, G_PARAM_READWRITE); /** * VisuUiSelection::selection: * * The ids of selected nodes. * * Since: 3.8 */ _properties[SELECTION_PROP] = g_param_spec_boxed ("selection", "Selection", "ids of selected nodes.", G_TYPE_ARRAY, G_PARAM_READWRITE); /** * VisuUiSelection::highlight: * * Highlight all nodes and all newly selected ones when TRUE. * * Since: 3.8 */ _properties[HIGHLIGHT_PROP] = g_param_spec_boolean ("highlight", "Highlight", "highlight the selection.", FALSE, G_PARAM_READWRITE); g_object_class_install_properties(G_OBJECT_CLASS(klass), N_PROP, _properties); } static void visu_ui_selection_init(VisuUiSelection *list) { GType types[VISU_UI_SELECTION_N_COLUMNS] = {G_TYPE_UINT, G_TYPE_BOOLEAN}; DBG_fprintf(stderr, "Visu UiSelection: initializing a new object (%p).\n", (gpointer)list); list->priv = visu_ui_selection_get_instance_private(list); list->priv->dispose_has_run = FALSE; gtk_list_store_set_column_types(GTK_LIST_STORE(list), VISU_UI_SELECTION_N_COLUMNS, types); list->priv->data = (VisuData*)0; list->priv->marks = (VisuGlExtMarks*)0; list->priv->highlight = FALSE; } static void visu_ui_selection_dispose(GObject* obj) { VisuUiSelection *list; DBG_fprintf(stderr, "Visu UiSelection: dispose object %p.\n", (gpointer)obj); list = VISU_UI_SELECTION(obj); if (list->priv->dispose_has_run) return; list->priv->dispose_has_run = TRUE; visu_ui_selection_setNodeModel(list, (VisuData*)0); visu_ui_selection_setHighlightModel(list, (VisuGlExtMarks*)0); /* Chain up to the parent class */ G_OBJECT_CLASS(visu_ui_selection_parent_class)->dispose(obj); } static void visu_ui_selection_get_property(GObject* obj, guint property_id, GValue *value, GParamSpec *pspec) { DBG_fprintf(stderr, "Visu UiSelection: get property '%s' -> ", g_param_spec_get_name(pspec)); switch (property_id) { case MODEL_PROP: g_value_set_object(value, VISU_UI_SELECTION(obj)->priv->data); DBG_fprintf(stderr, "%p.\n", g_value_get_object(value)); break; case MARKS_PROP: g_value_set_object(value, VISU_UI_SELECTION(obj)->priv->marks); DBG_fprintf(stderr, "%p.\n", g_value_get_object(value)); break; case SELECTION_PROP: g_value_take_boxed(value, visu_ui_selection_get(VISU_UI_SELECTION(obj))); DBG_fprintf(stderr, "%p.\n", g_value_get_boxed(value)); break; case HIGHLIGHT_PROP: g_value_set_boolean(value, VISU_UI_SELECTION(obj)->priv->highlight); DBG_fprintf(stderr, "%d.\n", g_value_get_boolean(value)); break; default: /* We don't have any other property... */ G_OBJECT_WARN_INVALID_PROPERTY_ID(obj, property_id, pspec); break; } } static void visu_ui_selection_set_property(GObject* obj, guint property_id, const GValue *value, GParamSpec *pspec) { VisuUiSelection *list = VISU_UI_SELECTION(obj); DBG_fprintf(stderr, "Visu UiSelection: set property '%s'\n", g_param_spec_get_name(pspec)); switch (property_id) { case MODEL_PROP: visu_ui_selection_setNodeModel(list, VISU_DATA(g_value_get_object(value))); break; case MARKS_PROP: visu_ui_selection_setHighlightModel(list, VISU_GL_EXT_MARKS(g_value_get_object(value))); break; case SELECTION_PROP: visu_ui_selection_set(list, (GArray*)g_value_get_boxed(value)); break; case HIGHLIGHT_PROP: visu_ui_selection_highlight(list, (GtkTreeIter*)0, g_value_get_boolean(value) ? MARKS_STATUS_SET : MARKS_STATUS_UNSET); list->priv->highlight = g_value_get_boolean(value); break; default: /* We don't have any other property... */ G_OBJECT_WARN_INVALID_PROPERTY_ID(obj, property_id, pspec); break; } } /** * visu_ui_selection_new: * * Create a new #GtkListStore to store planes. * * Since: 3.8 * * Returns: a newly created object. **/ VisuUiSelection* visu_ui_selection_new() { VisuUiSelection *list; list = VISU_UI_SELECTION(g_object_new(VISU_TYPE_UI_SELECTION, NULL)); return list; } /** * visu_ui_selection_setNodeModel: * @selection: a #VisuUiSelection object. * @data: (allow-none): a #VisuData object. * * Bind the @set object to @list. * * Returns: TRUE if @set is changed **/ gboolean visu_ui_selection_setNodeModel(VisuUiSelection *selection, VisuData *data) { GtkTreeIter iter; guint number; gboolean valid; VisuNode *node; g_return_val_if_fail(VISU_IS_UI_SELECTION(selection), FALSE); if (selection->priv->data == data) return FALSE; if (selection->priv->data) { g_signal_handler_disconnect(G_OBJECT(selection->priv->data), selection->priv->popDec_signal); g_object_unref(selection->priv->data); } selection->priv->data = data; if (data) { g_object_ref(data); selection->priv->popDec_signal = g_signal_connect_swapped(G_OBJECT(data), "PopulationDecrease", G_CALLBACK(visu_ui_selection_remove), selection); /* Try to match the selected nodes to new ones in the new visuData. */ valid = gtk_tree_model_get_iter_first(GTK_TREE_MODEL(selection), &iter); while (valid) { gtk_tree_model_get(GTK_TREE_MODEL(selection), &iter, VISU_UI_SELECTION_NUMBER, &number, -1); node = visu_node_array_getFromId(VISU_NODE_ARRAY(data), number - 1); if (node) valid = gtk_tree_model_iter_next(GTK_TREE_MODEL(selection), &iter); else valid = gtk_list_store_remove(GTK_LIST_STORE(selection), &iter); } } else gtk_list_store_clear(GTK_LIST_STORE(selection)); g_object_notify_by_pspec(G_OBJECT(selection), _properties[SELECTION_PROP]); return TRUE; } /** * visu_ui_selection_setHighlightModel: * @selection: a #VisuUiSelection object. * @marks: (allow-none): a #VisuGlExtMarks object. * * Bind the @set object to @list. * * Returns: TRUE if @set is changed **/ gboolean visu_ui_selection_setHighlightModel(VisuUiSelection *selection, VisuGlExtMarks *marks) { g_return_val_if_fail(VISU_IS_UI_SELECTION(selection), FALSE); if (selection->priv->marks == marks) return FALSE; if (selection->priv->marks) { g_signal_handler_disconnect(selection->priv->marks, selection->priv->hl_signal); g_object_unref(selection->priv->marks); } selection->priv->marks = marks; if (marks) { g_object_ref(marks); selection->priv->hl_signal = g_signal_connect_swapped (marks, "notify::highlight", G_CALLBACK(_updateHighlight), selection); } _updateHighlight(selection); return TRUE; } /** * visu_ui_selection_at: * @selection: a #VisuUiSelection object. * @iter: a #GtkTreeIter structure. * @id: a node id. * * Inquires if the model @selection is storing node @id at @iter. * * Since: 3.8 * * Returns: TRUE if node @id is set at @iter. **/ gboolean visu_ui_selection_at(VisuUiSelection *selection, GtkTreeIter *iter, guint id) { gboolean valid; guint currentNodeId; g_return_val_if_fail(iter, FALSE); /* Search if @node is already in the tree. */ for (valid = gtk_tree_model_get_iter_first(GTK_TREE_MODEL(selection), iter); valid; valid = gtk_tree_model_iter_next(GTK_TREE_MODEL(selection), iter)) { gtk_tree_model_get(GTK_TREE_MODEL(selection), iter, VISU_UI_SELECTION_NUMBER, ¤tNodeId, -1); if (id + 1 == currentNodeId) return TRUE; } return FALSE; } /** * visu_ui_selection_add: * @selection: a #VisuUiSelection object. * @id: a node id. * * Add the node identified by @id to @selection. If the node already * exists or if @selection has no current node model, nothing is * done. If there are several nodes to insert at once, use * visu_ui_selection_append() instead to ensure that the selection * signalis only emitted once. * * Since: 3.8 * * Returns: TRUE if @id can be added to the model. **/ gboolean visu_ui_selection_add(VisuUiSelection *selection, guint id) { GtkTreeIter it; VisuNode *node; gboolean newRow; g_return_val_if_fail(VISU_IS_UI_SELECTION(selection), FALSE); if (!selection->priv->data) return FALSE; node = visu_node_array_getFromId(VISU_NODE_ARRAY(selection->priv->data), id); if (!node) return FALSE; newRow = !visu_ui_selection_at(selection, &it, id); if (newRow) gtk_list_store_append(GTK_LIST_STORE(selection), &it); /* Store the base data. */ gtk_list_store_set(GTK_LIST_STORE(selection), &it, VISU_UI_SELECTION_NUMBER, id + 1, VISU_UI_SELECTION_HIGHLIGHT, selection->priv->marks ? visu_gl_ext_marks_getHighlightStatus(selection->priv->marks, id) : FALSE, -1); if (selection->priv->highlight) visu_ui_selection_highlight(selection, &it, MARKS_STATUS_SET); if (newRow) g_object_notify_by_pspec(G_OBJECT(selection), _properties[SELECTION_PROP]); return newRow; } /** * visu_ui_selection_get: * @selection: a #VisuUiSelection object. * * Retrieves the list of node ids in the selection. * * Since: 3.8 * * Returns: (transfer full) (element-type guint): a list of node ids. **/ GArray* visu_ui_selection_get(const VisuUiSelection *selection) { GArray *ids; gboolean valid; GtkTreeIter it; guint id; g_return_val_if_fail(VISU_IS_UI_SELECTION(selection), (GArray*)0); ids = g_array_new(FALSE, FALSE, sizeof(guint)); for (valid = gtk_tree_model_get_iter_first(GTK_TREE_MODEL(selection), &it); valid; valid = gtk_tree_model_iter_next(GTK_TREE_MODEL(selection), &it)) { gtk_tree_model_get(GTK_TREE_MODEL(selection), &it, VISU_UI_SELECTION_NUMBER, &id, -1); id -= 1; g_array_append_val(ids, id); } return ids; } /** * visu_ui_selection_append: * @selection: a #VisuUiSelection object. * @ids: (element-type uint): a list of node ids. * * Inserts every node from @ids into @selection. The selection signal * is only emitted once. * * Since: 3.8 **/ void visu_ui_selection_append(VisuUiSelection *selection, const GArray *ids) { guint i; GtkTreeIter it; VisuNode *node; g_return_if_fail(VISU_IS_UI_SELECTION(selection)); if (!selection->priv->data) return; for (i = 0; i < ids->len; i++) { node = visu_node_array_getFromId(VISU_NODE_ARRAY(selection->priv->data), g_array_index(ids, guint, i)); if (node && !visu_ui_selection_at(selection, &it, g_array_index(ids, guint, i))) { gtk_list_store_append(GTK_LIST_STORE(selection), &it); /* Store the base data. */ gtk_list_store_set(GTK_LIST_STORE(selection), &it, VISU_UI_SELECTION_NUMBER, g_array_index(ids, guint, i) + 1, VISU_UI_SELECTION_HIGHLIGHT, selection->priv->marks ? visu_gl_ext_marks_getHighlightStatus(selection->priv->marks, g_array_index(ids, guint, i)) : FALSE, -1); if (selection->priv->highlight) visu_ui_selection_highlight(selection, &it, MARKS_STATUS_SET); } } g_object_notify_by_pspec(G_OBJECT(selection), _properties[SELECTION_PROP]); } /** * visu_ui_selection_set: * @selection: a #VisuUiSelection object. * @ids: (element-type uint): a list of node ids. * * Clear the @selection and update it with the nodes from @ids. * * Since: 3.8 **/ void visu_ui_selection_set(VisuUiSelection *selection, const GArray *ids) { g_return_if_fail(VISU_IS_UI_SELECTION(selection)); gtk_list_store_clear(GTK_LIST_STORE(selection)); visu_ui_selection_append(selection, ids); } /** * visu_ui_selection_appendHighlightedNodes: * @selection: a #VisuUiSelection object. * * A convenient method to get the highlighted nodes and add them to * the @selection. * * Since: 3.8 **/ void visu_ui_selection_appendHighlightedNodes(VisuUiSelection *selection) { GArray *ids; g_return_if_fail(VISU_IS_UI_SELECTION(selection)); if (!selection->priv->marks) return; ids = visu_gl_ext_marks_getHighlighted(selection->priv->marks); visu_ui_selection_append(selection, ids); } /** * visu_ui_selection_remove: * @selection: a #VisuUiSelection object. * @ids: (element-type uint): a list of node ids. * * Remove a list of nodes from @selection. * * Since: 3.8 **/ void visu_ui_selection_remove(VisuUiSelection *selection, const GArray *ids) { GtkTreeIter iter, removeIter; gboolean valid; guint number; guint i; gboolean found; g_return_if_fail(VISU_IS_UI_SELECTION(selection)); valid = gtk_tree_model_get_iter_first(GTK_TREE_MODEL(selection), &iter); while (valid) { gtk_tree_model_get(GTK_TREE_MODEL(selection), &iter, VISU_UI_SELECTION_NUMBER, &number, -1); found = FALSE; for (i = 0; !found && i < ids->len; i++) if (number == (g_array_index(ids, guint, i) + 1)) { removeIter = iter; found = TRUE; } valid = gtk_tree_model_iter_next(GTK_TREE_MODEL(selection), &iter); if (found) { if (selection->priv->highlight) visu_ui_selection_highlight(selection, &removeIter, MARKS_STATUS_UNSET); gtk_list_store_remove(GTK_LIST_STORE(selection), &removeIter); } }; g_object_notify_by_pspec(G_OBJECT(selection), _properties[SELECTION_PROP]); } /** * visu_ui_selection_clear: * @selection: a #VisuUiSelection object. * * An overloaded method of gtk_list_store_clear() to ensure that the * selection signal is properly emitted. * * Since: 3.8 **/ void visu_ui_selection_clear(VisuUiSelection *selection) { g_return_if_fail(VISU_IS_UI_SELECTION(selection)); if (!gtk_tree_model_iter_n_children(GTK_TREE_MODEL(selection), (GtkTreeIter*)0)) return; gtk_list_store_clear(GTK_LIST_STORE(selection)); g_object_notify_by_pspec(G_OBJECT(selection), _properties[SELECTION_PROP]); if (selection->priv->highlight) visu_ui_selection_highlight(selection, (GtkTreeIter*)0, MARKS_STATUS_UNSET); } /** * visu_ui_selection_removeAt: * @selection: a #VisuUiSelection object. * @iter: a #GtkTreeIter structure. * * Remove the node stored at iter from @selection. This is an * overloaded function of gtk_list_store_remove() to emit the selection * signal after change. * * Since: 3.8 * * Returns: TRUE if @iter was actually removed. **/ gboolean visu_ui_selection_removeAt(VisuUiSelection *selection, GtkTreeIter *iter) { gboolean valid; g_return_val_if_fail(VISU_IS_UI_SELECTION(selection), FALSE); if (selection->priv->highlight) visu_ui_selection_highlight(selection, iter, MARKS_STATUS_UNSET); valid = gtk_list_store_remove(GTK_LIST_STORE(selection), iter); g_object_notify_by_pspec(G_OBJECT(selection), _properties[SELECTION_PROP]); return valid; } /** * visu_ui_selection_removePaths: * @selection: a #VisuUiSelection object. * @paths: (element-type GtkTreePath): a list of #GtkTreePath * * Remove all given paths from @selection. * * Since: 3.8 **/ void visu_ui_selection_removePaths(VisuUiSelection *selection, const GList *paths) { GList *lst, *sorted; GtkTreeIter iter; g_return_if_fail(VISU_IS_UI_SELECTION(selection)); sorted = g_list_reverse(g_list_sort(g_list_copy((GList*)paths), (GCompareFunc)gtk_tree_path_compare)); for (lst = sorted; lst; lst = g_list_next(lst)) if (gtk_tree_model_get_iter(GTK_TREE_MODEL(selection), &iter, (GtkTreePath*)lst->data)) { if (selection->priv->highlight) visu_ui_selection_highlight(selection, &iter, MARKS_STATUS_UNSET); gtk_list_store_remove(GTK_LIST_STORE(selection), &iter); } g_list_free(sorted); g_object_notify_by_pspec(G_OBJECT(selection), _properties[SELECTION_PROP]); } /** * visu_ui_selection_highlight: * @selection: a #VisuUiSelection object. * @iter: (allow-none): a #GtkTreeIter structure. * @status: a mark status. * * Apply the new @status to nodes. If @iter is %NULL, all nodes stored * in @selection are modified, otherwise, only the node at @iter. * * Since: 3.8 **/ void visu_ui_selection_highlight(VisuUiSelection *selection, GtkTreeIter *iter, VisuGlExtMarksStatus status) { GtkTreeIter iter_; gboolean valid, hl, only; guint node; GArray *ids; g_return_if_fail(VISU_IS_UI_SELECTION(selection)); if (!selection->priv->marks) return; only = (iter != (GtkTreeIter*)0); if (!iter) iter = &iter_; DBG_fprintf(stderr, "Gtk Pick: change highlight status.\n"); ids = g_array_new(FALSE, FALSE, sizeof(guint)); for (valid = (!only)?gtk_tree_model_get_iter_first(GTK_TREE_MODEL(selection), iter):TRUE; valid; valid = (!only)?gtk_tree_model_iter_next(GTK_TREE_MODEL(selection), iter):FALSE) { gtk_tree_model_get(GTK_TREE_MODEL(selection), iter, VISU_UI_SELECTION_HIGHLIGHT, &hl, VISU_UI_SELECTION_NUMBER, &node, -1); DBG_fprintf(stderr, " | process %d\n", node - 1); if (status == MARKS_STATUS_TOGGLE) gtk_list_store_set(GTK_LIST_STORE(selection), iter, VISU_UI_SELECTION_HIGHLIGHT, !hl, -1); else if (status == MARKS_STATUS_SET) gtk_list_store_set(GTK_LIST_STORE(selection), iter, VISU_UI_SELECTION_HIGHLIGHT, TRUE, -1); else if (status == MARKS_STATUS_UNSET) gtk_list_store_set(GTK_LIST_STORE(selection), iter, VISU_UI_SELECTION_HIGHLIGHT, FALSE, -1); node -= 1; g_array_append_val(ids, node); } g_signal_handler_block(selection->priv->marks, selection->priv->hl_signal); visu_gl_ext_marks_setHighlight(selection->priv->marks, ids, status); g_signal_handler_unblock(selection->priv->marks, selection->priv->hl_signal); g_array_unref(ids); } static void _updateHighlight(VisuUiSelection *selection) { gboolean valid; GtkTreeIter it; guint id; g_return_if_fail(VISU_IS_UI_SELECTION(selection)); for (valid = gtk_tree_model_get_iter_first(GTK_TREE_MODEL(selection), &it); valid; valid = gtk_tree_model_iter_next(GTK_TREE_MODEL(selection), &it)) { gtk_tree_model_get(GTK_TREE_MODEL(selection), &it, VISU_UI_SELECTION_NUMBER, &id, -1); gtk_list_store_set(GTK_LIST_STORE(selection), &it, VISU_UI_SELECTION_HIGHLIGHT, selection->priv->marks ? visu_gl_ext_marks_getHighlightStatus(selection->priv->marks, id - 1) : FALSE, -1); } } v_sim-3.8.0/src/uiElements/ui_selection.h000066400000000000000000000131721370110300500203650ustar00rootroot00000000000000/* EXTRAITS DE LA LICENCE Copyright CEA, contributeurs : Damien CALISTE, laboratoire L_Sim, (2017) Adresse mèl : CALISTE, damien P caliste AT cea P fr. Ce logiciel est un programme informatique servant à visualiser des structures atomiques dans un rendu pseudo-3D. Ce logiciel est régi par la licence CeCILL soumise au droit français et respectant les principes de diffusion des logiciels libres. Vous pouvez utiliser, modifier et/ou redistribuer ce programme sous les conditions de la licence CeCILL telle que diffusée par le CEA, le CNRS et l'INRIA sur le site "http://www.cecill.info". Le fait que vous puissiez accéder à cet en-tête signifie que vous avez pris connaissance de la licence CeCILL, et que vous en avez accepté les termes (cf. le fichier Documentation/licence.fr.txt fourni avec ce logiciel). */ /* LICENCE SUM UP Copyright CEA, contributors : Damien CALISTE, laboratoire L_Sim, (2017) E-mail address: CALISTE, damien P caliste AT cea P fr. This software is a computer program whose purpose is to visualize atomic configurations in 3D. This software is governed by the CeCILL license under French law and abiding by the rules of distribution of free software. You can use, modify and/ or redistribute the software under the terms of the CeCILL license as circulated by CEA, CNRS and INRIA at the following URL "http://www.cecill.info". The fact that you are presently reading this means that you have had knowledge of the CeCILL license and that you accept its terms. You can find a copy of this licence shipped with this software at Documentation/licence.en.txt. */ #ifndef VISU_UI_SELECTION_H #define VISU_UI_SELECTION_H #include #include #include #include #include /***************/ /* Public part */ /***************/ /** * VISU_TYPE_UI_SELECTION: * * return the type of #VisuUiSelection. */ #define VISU_TYPE_UI_SELECTION (visu_ui_selection_get_type ()) /** * VISU_UI_SELECTION: * @obj: a #GObject to cast. * * Cast the given @obj into #VisuUiSelection type. */ #define VISU_UI_SELECTION(obj) (G_TYPE_CHECK_INSTANCE_CAST(obj, VISU_TYPE_UI_SELECTION, VisuUiSelection)) /** * VISU_UI_SELECTION_CLASS: * @klass: a #GObjectClass to cast. * * Cast the given @klass into #VisuUiSelectionClass. */ #define VISU_UI_SELECTION_CLASS(klass) (G_TYPE_CHECK_CLASS_CAST(klass, VISU_TYPE_UI_SELECTION, VisuUiSelectionClass)) /** * VISU_IS_UI_SELECTION: * @obj: a #GObject to test. * * Test if the given @ogj is of the type of #VisuUiSelection object. */ #define VISU_IS_UI_SELECTION(obj) (G_TYPE_CHECK_INSTANCE_TYPE(obj, VISU_TYPE_UI_SELECTION)) /** * VISU_IS_UI_SELECTION_CLASS: * @klass: a #GObjectClass to test. * * Test if the given @klass is of the type of #VisuUiSelectionClass class. */ #define VISU_IS_UI_SELECTION_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE(klass, VISU_TYPE_UI_SELECTION)) /** * VISU_UI_SELECTION_GET_CLASS: * @obj: a #GObject to get the class of. * * It returns the class of the given @obj. */ #define VISU_UI_SELECTION_GET_CLASS(obj) (G_TYPE_INSTANCE_GET_CLASS(obj, VISU_TYPE_UI_SELECTION, VisuUiSelectionClass)) /** * VisuUiSelectionPrivate: * * Private data for #VisuUiSelection objects. */ typedef struct _VisuUiSelectionPrivate VisuUiSelectionPrivate; /** * VisuUiSelection: * * Common name to refer to a #_VisuUiSelection. */ typedef struct _VisuUiSelection VisuUiSelection; struct _VisuUiSelection { GtkListStore parent; VisuUiSelectionPrivate *priv; }; /** * VisuUiSelectionClass: * @parent: private. * * Common name to refer to a #_VisuUiSelectionClass. */ typedef struct _VisuUiSelectionClass VisuUiSelectionClass; struct _VisuUiSelectionClass { GtkListStoreClass parent; }; /** * visu_ui_selection_get_type: * * This method returns the type of #VisuUiSelection, use * VISU_TYPE_UI_SELECTION instead. * * Since: 3.8 * * Returns: the type of #VisuUiSelection. */ GType visu_ui_selection_get_type(void); /** * VisuUiSelectionColumnId: * @VISU_UI_SELECTION_NUMBER: column displaying the node id. * @VISU_UI_SELECTION_HIGHLIGHT:column checked when the node is highlighted. * @VISU_UI_SELECTION_N_COLUMNS: the number of columns. * * Thesse are the description of the columns stored in the object. */ typedef enum { VISU_UI_SELECTION_NUMBER, VISU_UI_SELECTION_HIGHLIGHT, VISU_UI_SELECTION_N_COLUMNS } VisuUiSelectionColumnId; VisuUiSelection* visu_ui_selection_new(); gboolean visu_ui_selection_setNodeModel(VisuUiSelection *selection, VisuData *data); gboolean visu_ui_selection_setHighlightModel(VisuUiSelection *selection, VisuGlExtMarks *marks); gboolean visu_ui_selection_add(VisuUiSelection *selection, guint id); void visu_ui_selection_append(VisuUiSelection *selection, const GArray *ids); void visu_ui_selection_appendHighlightedNodes(VisuUiSelection *selection); /* GtkBox* visu_ui_selection_getControls(VisuUiSelection *list); */ void visu_ui_selection_highlight(VisuUiSelection *selection, GtkTreeIter *iter, VisuGlExtMarksStatus status); void visu_ui_selection_remove(VisuUiSelection *selection, const GArray *ids); void visu_ui_selection_removePaths(VisuUiSelection *selection, const GList *paths); void visu_ui_selection_clear(VisuUiSelection *selection); gboolean visu_ui_selection_removeAt(VisuUiSelection *selection, GtkTreeIter *iter); gboolean visu_ui_selection_at(VisuUiSelection *selection, GtkTreeIter *iter, guint id); GArray* visu_ui_selection_get(const VisuUiSelection *selection); void visu_ui_selection_set(VisuUiSelection *selection, const GArray *ids); #endif v_sim-3.8.0/src/uiElements/ui_spin.c000066400000000000000000000424771370110300500173560ustar00rootroot00000000000000/* EXTRAITS DE LA LICENCE Copyright CEA, contributeurs : Damien CALISTE, laboratoire L_Sim, (2016) Adresse mèl : CALISTE, damien P caliste AT cea P fr. Ce logiciel est un programme informatique servant à visualiser des structures atomiques dans un rendu pseudo-3D. Ce logiciel est régi par la licence CeCILL soumise au droit français et respectant les principes de diffusion des logiciels libres. Vous pouvez utiliser, modifier et/ou redistribuer ce programme sous les conditions de la licence CeCILL telle que diffusée par le CEA, le CNRS et l'INRIA sur le site "http://www.cecill.info". Le fait que vous puissiez accéder à cet en-tête signifie que vous avez pris connaissance de la licence CeCILL, et que vous en avez accepté les termes (cf. le fichier Documentation/licence.fr.txt fourni avec ce logiciel). */ /* LICENCE SUM UP Copyright CEA, contributors : Damien CALISTE, laboratoire L_Sim, (2016) E-mail address: CALISTE, damien P caliste AT cea P fr. This software is a computer program whose purpose is to visualize atomic configurations in 3D. This software is governed by the CeCILL license under French law and abiding by the rules of distribution of free software. You can use, modify and/ or redistribute the software under the terms of the CeCILL license as circulated by CEA, CNRS and INRIA at the following URL "http://www.cecill.info". The fact that you are presently reading this means that you have had knowledge of the CeCILL license and that you accept its terms. You can find a copy of this licence shipped with this software at Documentation/licence.en.txt. */ #include "ui_spin.h" #include #include #include #include #include "ui_atomic.h" /** * SECTION:ui_spin * @short_description: Defines a widget to setup a spin. * * A set of widgets to setup the rendring of a spin. */ /** * VisuUiSpinClass: * @parent: the parent class; * * A short way to identify #_VisuUiSpinClass structure. * * Since: 3.8 */ /** * VisuUiSpin: * * An opaque structure. * * Since: 3.8 */ /** * VisuUiSpinPrivate: * * Private fields for #VisuUiSpin objects. * * Since: 3.8 */ struct _VisuUiSpinPrivate { gboolean dispose_has_run; GtkWidget *comboShape; GtkWidget *hLengthSpin; GtkWidget *tLengthSpin; GtkWidget *hRadiusSpin; GtkWidget *tRadiusSpin; GtkWidget *tFollowCheck; GtkWidget *hFollowCheck; GtkWidget *ratioElipsoidSpin; GtkWidget *lengthElipsoidSpin; GtkWidget *elipFollowCheck; GtkWidget *expandAtomic; VisuUiAtomic *atomic; VisuNodeArrayRenderer *renderer; VisuElementSpin *model; GBinding *bind_shape, *bind_tl, *bind_tr, *bind_hl, *bind_hr, *bind_tf, *bind_hf; GBinding *bind_a, *bind_b, *bind_follow; GList *targets; }; static void visu_ui_spin_finalize(GObject* obj); static void visu_ui_spin_dispose(GObject* obj); /* Local callbacks. */ G_DEFINE_TYPE_WITH_CODE(VisuUiSpin, visu_ui_spin, GTK_TYPE_BOX, G_ADD_PRIVATE(VisuUiSpin)) static void visu_ui_spin_class_init(VisuUiSpinClass *klass) { DBG_fprintf(stderr, "Ui Spin: creating the class of the widget.\n"); DBG_fprintf(stderr, " - adding new signals ;\n"); /* Connect freeing methods. */ G_OBJECT_CLASS(klass)->dispose = visu_ui_spin_dispose; G_OBJECT_CLASS(klass)->finalize = visu_ui_spin_finalize; } static void visu_ui_spin_dispose(GObject *obj) { VisuUiSpin *self = VISU_UI_SPIN(obj); DBG_fprintf(stderr, "Ui Spin: dispose object %p.\n", (gpointer)obj); if (self->priv->dispose_has_run) return; self->priv->dispose_has_run = TRUE; visu_ui_spin_bind(self, (GList*)0); /* Chain up to the parent class */ G_OBJECT_CLASS(visu_ui_spin_parent_class)->dispose(obj); } static void visu_ui_spin_finalize(GObject *obj) { g_return_if_fail(obj); DBG_fprintf(stderr, "Ui Spin: finalize object %p.\n", (gpointer)obj); /* Chain up to the parent class */ G_OBJECT_CLASS(visu_ui_spin_parent_class)->finalize(obj); DBG_fprintf(stderr, " | freeing ... OK.\n"); } static gboolean toArrowVisible(GBinding *bind _U_, const GValue *source_value, GValue *target_value, gpointer data _U_) { guint id; id = (guint)g_value_get_int(source_value); g_value_set_boolean(target_value, (id == VISU_ELEMENT_SPIN_ARROW_SMOOTH || id == VISU_ELEMENT_SPIN_ARROW_SHARP)); return TRUE; } static gboolean toElipVisible(GBinding *bind _U_, const GValue *source_value, GValue *target_value, gpointer data _U_) { guint id; id = (guint)g_value_get_int(source_value); g_value_set_boolean(target_value, (id == VISU_ELEMENT_SPIN_ELLIPSOID || id == VISU_ELEMENT_SPIN_TORUS)); return TRUE; } /* static gboolean toAtomic(GBinding *bind, const GValue *source_value _U_, */ /* GValue *target_value, gpointer data _U_) */ /* { */ /* VisuDataSpinDrawingPolicy hide; */ /* gboolean useAt; */ /* g_object_get(g_binding_get_source(bind), "hiding-mode", &hide, */ /* "use-atomic", &useAt, NULL); */ /* g_value_set_boolean(target_value, (useAt || hide == VISU_DATA_SPIN_ATOMIC_NULL)); */ /* return TRUE; */ /* } */ static void visu_ui_spin_init(VisuUiSpin *obj) { GtkWidget *label, *hbox; GtkWidget *vboxArrowShape; GtkWidget *vboxElipsoidShape; int i; const gchar **shapes; gtk_orientable_set_orientation(GTK_ORIENTABLE(obj), GTK_ORIENTATION_VERTICAL); obj->priv = visu_ui_spin_get_instance_private(obj); obj->priv->dispose_has_run = FALSE; obj->priv->renderer = (VisuNodeArrayRenderer*)0; obj->priv->model = (VisuElementSpin*)0; obj->priv->targets = (GList*)0; gtk_widget_set_sensitive(GTK_WIDGET(obj), FALSE); /* Shape */ hbox = gtk_hbox_new(FALSE, 0); gtk_box_pack_start(GTK_BOX(obj), hbox, FALSE, FALSE, 0); label = gtk_label_new(""); gtk_label_set_markup(GTK_LABEL(label), _("Shape: ")); gtk_box_pack_start(GTK_BOX(hbox), label, FALSE, FALSE, 0); obj->priv->comboShape = gtk_combo_box_text_new(); shapes = visu_element_spin_getShapeNames(TRUE); for (i=0; shapes[i]; i++) gtk_combo_box_text_append(GTK_COMBO_BOX_TEXT(obj->priv->comboShape), (const gchar*)0, shapes[i]); gtk_box_pack_end(GTK_BOX(hbox), obj->priv->comboShape, FALSE, FALSE, 0); /* Sizes */ label = gtk_label_new(""); gtk_label_set_markup(GTK_LABEL(label), _("Size and color properties:")); gtk_label_set_xalign(GTK_LABEL(label), 0.); gtk_box_pack_start(GTK_BOX(obj), label, FALSE, FALSE, 0); /* Arrow sizes. */ vboxArrowShape = gtk_vbox_new(FALSE, 0); g_object_bind_property_full(obj->priv->comboShape, "active", vboxArrowShape, "visible", G_BINDING_SYNC_CREATE, toArrowVisible, NULL, (gpointer)0, (GDestroyNotify)0); gtk_box_pack_start(GTK_BOX(obj), vboxArrowShape, FALSE, FALSE, 0); hbox = gtk_hbox_new(FALSE, 0); gtk_box_pack_start(GTK_BOX(vboxArrowShape), hbox, FALSE, FALSE, 2); label = gtk_label_new(_("Hat length:")); gtk_widget_set_margin_start(label, 10); gtk_box_pack_start(GTK_BOX(hbox), label, FALSE, FALSE, 0); obj->priv->hLengthSpin = gtk_spin_button_new_with_range(0, 9, 0.05); gtk_box_pack_end(GTK_BOX(hbox), obj->priv->hLengthSpin, FALSE, FALSE, 0); hbox = gtk_hbox_new(FALSE, 0); gtk_box_pack_start(GTK_BOX(vboxArrowShape), hbox, FALSE, FALSE, 2); label = gtk_label_new(_("Tail length:")); gtk_widget_set_margin_start(label, 10); gtk_box_pack_start(GTK_BOX(hbox), label, FALSE, FALSE, 0); obj->priv->tLengthSpin = gtk_spin_button_new_with_range(0, 9, 0.05); gtk_box_pack_end(GTK_BOX(hbox), obj->priv->tLengthSpin, FALSE, FALSE, 0); hbox = gtk_hbox_new(FALSE, 0); gtk_box_pack_start(GTK_BOX(vboxArrowShape), hbox, FALSE, FALSE, 2); label = gtk_label_new(_("Hat radius:")); gtk_widget_set_margin_start(label, 10); gtk_box_pack_start(GTK_BOX(hbox), label, FALSE, FALSE, 0); obj->priv->hRadiusSpin = gtk_spin_button_new_with_range(0, 9, 0.05); gtk_box_pack_end(GTK_BOX(hbox), obj->priv->hRadiusSpin, FALSE, FALSE, 0); hbox = gtk_hbox_new(FALSE, 0); gtk_box_pack_start(GTK_BOX(vboxArrowShape), hbox, FALSE, FALSE, 2); label = gtk_label_new(_("Tail radius:")); gtk_widget_set_margin_start(label, 10); gtk_box_pack_start(GTK_BOX(hbox), label, FALSE, FALSE, 0); obj->priv->tRadiusSpin = gtk_spin_button_new_with_range(0, 9, 0.05); gtk_box_pack_end(GTK_BOX(hbox), obj->priv->tRadiusSpin, FALSE, FALSE, 0); hbox = gtk_hbox_new(FALSE, 0); gtk_box_pack_start(GTK_BOX(vboxArrowShape), hbox, FALSE, FALSE, 2); label = gtk_label_new(_("Use element color on:")); gtk_widget_set_margin_start(label, 10); gtk_box_pack_start(GTK_BOX(hbox), label, FALSE, FALSE, 0); obj->priv->tFollowCheck = gtk_check_button_new_with_label(_(" tail")); gtk_box_pack_end(GTK_BOX(hbox), obj->priv->tFollowCheck, FALSE, FALSE, 0); obj->priv->hFollowCheck = gtk_check_button_new_with_label(_(" hat")); gtk_box_pack_end(GTK_BOX(hbox), obj->priv->hFollowCheck, FALSE, FALSE, 0); /* Elipsoid sizes. */ vboxElipsoidShape = gtk_vbox_new(FALSE, 0); g_object_bind_property_full(obj->priv->comboShape, "active", vboxElipsoidShape, "visible", G_BINDING_SYNC_CREATE, toElipVisible, NULL, (gpointer)0, (GDestroyNotify)0); gtk_box_pack_start(GTK_BOX(obj), vboxElipsoidShape, FALSE, FALSE, 0); hbox = gtk_hbox_new(FALSE, 0); gtk_box_pack_start(GTK_BOX(vboxElipsoidShape), hbox, FALSE, FALSE, 0); label = gtk_label_new(_("A axis: ")); gtk_label_set_xalign(GTK_LABEL(label), 1.); gtk_box_pack_start(GTK_BOX(hbox), label, TRUE, TRUE, 0); obj->priv->lengthElipsoidSpin = gtk_spin_button_new_with_range(0, 9, 0.05); gtk_box_pack_end(GTK_BOX(hbox), obj->priv->lengthElipsoidSpin, FALSE, FALSE, 0); hbox = gtk_hbox_new(FALSE, 0); gtk_box_pack_start(GTK_BOX(vboxElipsoidShape), hbox, FALSE, FALSE, 0); label = gtk_label_new(_("B axis: ")); gtk_label_set_xalign(GTK_LABEL(label), 1.); gtk_box_pack_start(GTK_BOX(hbox), label, TRUE, TRUE, 0); obj->priv->ratioElipsoidSpin = gtk_spin_button_new_with_range(0, 9, 0.05); gtk_box_pack_end(GTK_BOX(hbox), obj->priv->ratioElipsoidSpin, FALSE, FALSE, 0); obj->priv->elipFollowCheck = gtk_check_button_new_with_label(_("Use element color")); gtk_box_pack_start(GTK_BOX(vboxElipsoidShape), obj->priv->elipFollowCheck, FALSE, FALSE, 0); /* Atomic options. */ obj->priv->expandAtomic = gtk_expander_new(_("Atomic rendering options")); gtk_box_pack_start(GTK_BOX(obj), obj->priv->expandAtomic, FALSE, FALSE, 0); g_object_bind_property(obj->priv->expandAtomic, "sensitive", obj->priv->expandAtomic, "expanded", G_BINDING_SYNC_CREATE); label = gtk_label_new(_("Enable the atomic rendering in the method tab.")); gtk_label_set_use_markup(GTK_LABEL(label), TRUE); gtk_box_pack_start(GTK_BOX(obj), label, FALSE, FALSE, 0); g_object_bind_property(obj->priv->expandAtomic, "sensitive", label, "visible", G_BINDING_SYNC_CREATE | G_BINDING_INVERT_BOOLEAN); /* g_object_bind_property_full(spin, "hiding-mode", obj->priv->expandAtomic, "sensitive", */ /* G_BINDING_SYNC_CREATE, toAtomic, NULL, */ /* (gpointer)0, (GDestroyNotify)0); */ /* g_object_bind_property_full(spin, "use-atomic", obj->priv->expandAtomic, "sensitive", */ /* G_BINDING_SYNC_CREATE, toAtomic, NULL, */ /* (gpointer)0, (GDestroyNotify)0); */ } /** * visu_ui_spin_new: * @renderer: a #VisuNodeArrayRenderer object. * * Creates a new #VisuUiSpin to allow to setup spin rendering characteristics. * * Since: 3.8 * * Returns: a pointer to the newly created widget. */ GtkWidget* visu_ui_spin_new(VisuNodeArrayRenderer *renderer) { VisuUiSpin *spin; DBG_fprintf(stderr,"Ui Spin: new object.\n"); spin = VISU_UI_SPIN(g_object_new(VISU_TYPE_UI_SPIN, NULL)); spin->priv->renderer = renderer; spin->priv->atomic = VISU_UI_ATOMIC(visu_ui_atomic_new(renderer)); gtk_container_add(GTK_CONTAINER(spin->priv->expandAtomic), GTK_WIDGET(spin->priv->atomic)); return GTK_WIDGET(spin); } static gboolean setForAll(GBinding *bind, const GValue *source_value, GValue *target_value, gpointer data) { VisuUiSpin *spin = VISU_UI_SPIN(data); GList *lst; for (lst = spin->priv->targets; lst; lst = g_list_next(lst)) if (lst->data != spin->priv->model) g_object_set_property(lst->data, g_binding_get_source_property(bind), source_value); return g_value_transform(source_value, target_value); } static void _bind(VisuUiSpin *spin, VisuElementSpin *element) { if (spin->priv->model == element) return; if (spin->priv->model) { g_object_unref(spin->priv->bind_shape); g_object_unref(spin->priv->bind_tl); g_object_unref(spin->priv->bind_tr); g_object_unref(spin->priv->bind_hl); g_object_unref(spin->priv->bind_hr); g_object_unref(spin->priv->bind_tf); g_object_unref(spin->priv->bind_hf); g_object_unref(spin->priv->bind_a); g_object_unref(spin->priv->bind_b); g_object_unref(spin->priv->bind_follow); g_object_unref(spin->priv->model); } spin->priv->model = element; if (element) { g_object_ref(element); spin->priv->bind_shape = g_object_bind_property_full(element, "spin-shape", spin->priv->comboShape, "active", G_BINDING_SYNC_CREATE | G_BINDING_BIDIRECTIONAL, NULL, setForAll, spin, (GDestroyNotify)0); spin->priv->bind_tl = g_object_bind_property_full(element, "tail-length", spin->priv->tLengthSpin, "value", G_BINDING_SYNC_CREATE | G_BINDING_BIDIRECTIONAL, NULL, setForAll, spin, (GDestroyNotify)0); spin->priv->bind_tr = g_object_bind_property_full(element, "tail-radius", spin->priv->tRadiusSpin, "value", G_BINDING_SYNC_CREATE | G_BINDING_BIDIRECTIONAL, NULL, setForAll, spin, (GDestroyNotify)0); spin->priv->bind_hl = g_object_bind_property_full(element, "hat-length", spin->priv->hLengthSpin, "value", G_BINDING_SYNC_CREATE | G_BINDING_BIDIRECTIONAL, NULL, setForAll, spin, (GDestroyNotify)0); spin->priv->bind_hr = g_object_bind_property_full(element, "hat-radius", spin->priv->hRadiusSpin, "value", G_BINDING_SYNC_CREATE | G_BINDING_BIDIRECTIONAL, NULL, setForAll, spin, (GDestroyNotify)0); spin->priv->bind_tf = g_object_bind_property_full(element, "tail-spin-colored", spin->priv->tFollowCheck, "active", G_BINDING_SYNC_CREATE | G_BINDING_BIDIRECTIONAL, NULL, setForAll, spin, (GDestroyNotify)0); spin->priv->bind_hf = g_object_bind_property_full(element, "hat-spin-colored", spin->priv->hFollowCheck, "active", G_BINDING_SYNC_CREATE | G_BINDING_BIDIRECTIONAL, NULL, setForAll, spin, (GDestroyNotify)0); spin->priv->bind_a = g_object_bind_property_full(element, "a-axis", spin->priv->lengthElipsoidSpin, "value", G_BINDING_SYNC_CREATE | G_BINDING_BIDIRECTIONAL, NULL, setForAll, spin, (GDestroyNotify)0); spin->priv->bind_b = g_object_bind_property_full(element, "b-axis", spin->priv->ratioElipsoidSpin, "value", G_BINDING_SYNC_CREATE | G_BINDING_BIDIRECTIONAL, NULL, setForAll, spin, (GDestroyNotify)0); spin->priv->bind_follow = g_object_bind_property_full(element, "spin-colored", spin->priv->elipFollowCheck, "active", G_BINDING_SYNC_CREATE | G_BINDING_BIDIRECTIONAL, NULL, setForAll, spin, (GDestroyNotify)0); } } /** * visu_ui_spin_bind: * @spin: a #VisuUiSpin object. * @eleList: (element-type VisuElement): a list of #VisuElement. * * Use the list @eleList to be handled by @elements. Any change in * @elements will be applied to the #VisuElementRenderer corresponding * to each #VisuElement of @eleList. * * Since: 3.8 **/ void visu_ui_spin_bind(VisuUiSpin *spin, GList *eleList) { GList *lst; g_return_if_fail(VISU_IS_UI_SPIN(spin)); g_return_if_fail(spin->priv->renderer); if (!eleList) _bind(spin, (VisuElementSpin*)0); else { if (!spin->priv->model || !g_list_find(eleList, visu_element_renderer_getElement(VISU_ELEMENT_RENDERER(spin->priv->model)))) _bind(spin, VISU_ELEMENT_SPIN(visu_node_array_renderer_get(spin->priv->renderer, VISU_ELEMENT(eleList->data)))); } if (spin->priv->targets) g_list_free(spin->priv->targets); spin->priv->targets = (GList*)0; for (lst = eleList; lst; lst = g_list_next(lst)) spin->priv->targets = g_list_prepend(spin->priv->targets, visu_node_array_renderer_get(spin->priv->renderer, VISU_ELEMENT(lst->data))); gtk_widget_set_sensitive(GTK_WIDGET(spin), (spin->priv->model != (VisuElementSpin*)0)); visu_ui_atomic_bind(spin->priv->atomic, eleList); } v_sim-3.8.0/src/uiElements/ui_spin.h000066400000000000000000000071551370110300500173550ustar00rootroot00000000000000/* EXTRAITS DE LA LICENCE Copyright CEA, contributeurs : Damien CALISTE, laboratoire L_Sim, (2016) Adresse mèl : CALISTE, damien P caliste AT cea P fr. Ce logiciel est un programme informatique servant à visualiser des structures atomiques dans un rendu pseudo-3D. Ce logiciel est régi par la licence CeCILL soumise au droit français et respectant les principes de diffusion des logiciels libres. Vous pouvez utiliser, modifier et/ou redistribuer ce programme sous les conditions de la licence CeCILL telle que diffusée par le CEA, le CNRS et l'INRIA sur le site "http://www.cecill.info". Le fait que vous puissiez accéder à cet en-tête signifie que vous avez pris connaissance de la licence CeCILL, et que vous en avez accepté les termes (cf. le fichier Documentation/licence.fr.txt fourni avec ce logiciel). */ /* LICENCE SUM UP Copyright CEA, contributors : Damien CALISTE, laboratoire L_Sim, (2016) E-mail address: CALISTE, damien P caliste AT cea P fr. This software is a computer program whose purpose is to visualize atomic configurations in 3D. This software is governed by the CeCILL license under French law and abiding by the rules of distribution of free software. You can use, modify and/ or redistribute the software under the terms of the CeCILL license as circulated by CEA, CNRS and INRIA at the following URL "http://www.cecill.info". The fact that you are presently reading this means that you have had knowledge of the CeCILL license and that you accept its terms. You can find a copy of this licence shipped with this software at Documentation/licence.en.txt. */ #ifndef UI_SPIN_H #define UI_SPIN_H #include #include /** * VISU_TYPE_UI_SPIN: * * return the type of #VisuUiSpin. * * Since: 3.8 */ #define VISU_TYPE_UI_SPIN (visu_ui_spin_get_type ()) /** * VISU_UI_SPIN: * @obj: a #GObject to cast. * * Cast the given @obj into #VisuUiSpin type. * * Since: 3.8 */ #define VISU_UI_SPIN(obj) (G_TYPE_CHECK_INSTANCE_CAST(obj, VISU_TYPE_UI_SPIN, VisuUiSpin)) /** * VISU_UI_SPIN_CLASS: * @klass: a #GObjectClass to cast. * * Cast the given @klass into #VisuUiSpinClass. * * Since: 3.8 */ #define VISU_UI_SPIN_CLASS(klass) (G_TYPE_CHECK_CLASS_CAST(klass, VISU_TYPE_UI_SPIN, VisuUiSpinClass)) /** * VISU_IS_UI_SPIN: * @obj: a #GObject to test. * * Test if the given @ogj is of the type of #VisuUiSpin object. * * Since: 3.8 */ #define VISU_IS_UI_SPIN(obj) (G_TYPE_CHECK_INSTANCE_TYPE(obj, VISU_TYPE_UI_SPIN)) /** * VISU_IS_UI_SPIN_CLASS: * @klass: a #GObjectClass to test. * * Test if the given @klass is of the type of #VisuUiSpinClass class. * * Since: 3.8 */ #define VISU_IS_UI_SPIN_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE(klass, VISU_TYPE_UI_SPIN)) /** * VISU_UI_SPIN_GET_CLASS: * @obj: a #GObject to get the class of. * * It returns the class of the given @obj. * * Since: 3.8 */ #define VISU_UI_SPIN_GET_CLASS(obj) (G_TYPE_INSTANCE_GET_CLASS(obj, VISU_TYPE_UI_SPIN, VisuUiSpinClass)) typedef struct _VisuUiSpin VisuUiSpin; typedef struct _VisuUiSpinPrivate VisuUiSpinPrivate; typedef struct _VisuUiSpinClass VisuUiSpinClass; struct _VisuUiSpin { GtkBox parent; VisuUiSpinPrivate *priv; }; struct _VisuUiSpinClass { GtkBoxClass parent; }; /** * visu_ui_spin_get_type: * * This method returns the type of #VisuUiSpin, use * VISU_TYPE_UI_SPIN instead. * * Since: 3.8 * * Returns: the type of #VisuUiSpin. */ GType visu_ui_spin_get_type(void); GtkWidget* visu_ui_spin_new(VisuNodeArrayRenderer *renderer); void visu_ui_spin_bind(VisuUiSpin *spin, GList *eleList); #endif v_sim-3.8.0/src/visu_animation.c000066400000000000000000000271761370110300500166220ustar00rootroot00000000000000/* EXTRAITS DE LA LICENCE Copyright CEA, contributeurs : Damien CALISTE, laboratoire L_Sim, (2017) Adresse mèl : CALISTE, damien P caliste AT cea P fr. Ce logiciel est un programme informatique servant à visualiser des structures atomiques dans un rendu pseudo-3D. Ce logiciel est régi par la licence CeCILL soumise au droit français et respectant les principes de diffusion des logiciels libres. Vous pouvez utiliser, modifier et/ou redistribuer ce programme sous les conditions de la licence CeCILL telle que diffusée par le CEA, le CNRS et l'INRIA sur le site "http://www.cecill.info". Le fait que vous puissiez accéder à cet en-tête signifie que vous avez pris connaissance de la licence CeCILL, et que vous en avez accepté les termes (cf. le fichier Documentation/licence.fr.txt fourni avec ce logiciel). */ /* LICENCE SUM UP Copyright CEA, contributors : Damien CALISTE, laboratoire L_Sim, (2017) E-mail address: CALISTE, damien P caliste AT cea P fr. This software is a computer program whose purpose is to visualize atomic configurations in 3D. This software is governed by the CeCILL license under French law and abiding by the rules of distribution of free software. You can use, modify and/ or redistribute the software under the terms of the CeCILL license as circulated by CEA, CNRS and INRIA at the following URL "http://www.cecill.info". The fact that you are presently reading this means that you have had knowledge of the CeCILL license and that you accept its terms. You can find a copy of this licence shipped with this software at Documentation/licence.en.txt. */ #include "visu_animation.h" #include /** * SECTION:visu_animation * @short_description: Defines a class to setup animation of a property. * * Use this object to animate smoothly a change between to * values ofg a given object property. */ struct _VisuAnimationPrivate { gboolean dispose_has_run; GWeakRef obj; gchar *prop; GValue from, to; gboolean blocked, loop; gulong ref, duration; VisuAnimationType type; }; enum { PROP_0, RUNNING_PROP, N_PROP }; static GParamSpec *_properties[N_PROP]; static void visu_animation_dispose (GObject* obj); static void visu_animation_finalize (GObject* obj); static void visu_animation_get_property(GObject* obj, guint property_id, GValue *value, GParamSpec *pspec); G_DEFINE_TYPE_WITH_CODE(VisuAnimation, visu_animation, VISU_TYPE_OBJECT, G_ADD_PRIVATE(VisuAnimation)) static void visu_animation_class_init(VisuAnimationClass *klass) { DBG_fprintf(stderr, "Visu Animation: creating the class of the object.\n"); /* DBG_fprintf(stderr, " - adding new signals ;\n"); */ /* Connect the overloading methods. */ G_OBJECT_CLASS(klass)->dispose = visu_animation_dispose; G_OBJECT_CLASS(klass)->finalize = visu_animation_finalize; G_OBJECT_CLASS(klass)->get_property = visu_animation_get_property; /** * VisuAnimation::running: * * Wether the animation is running. * * Since: 3.8 */ _properties[RUNNING_PROP] = g_param_spec_boolean("running", "Running", "animation is running", FALSE, G_PARAM_READABLE); g_object_class_install_properties(G_OBJECT_CLASS(klass), N_PROP, _properties); } static void visu_animation_init(VisuAnimation *self) { GValue init = G_VALUE_INIT; DBG_fprintf(stderr, "Visu Animation: initializing a new object (%p).\n", (gpointer)self); self->priv = visu_animation_get_instance_private(self); self->priv->dispose_has_run = FALSE; self->priv->prop = (gchar*)0; self->priv->from = init; self->priv->to = init; self->priv->ref = 0; self->priv->blocked = FALSE; self->priv->loop = TRUE; } /* This method can be called several times. It should unref all of its reference to GObjects. */ static void visu_animation_dispose(GObject* obj) { VisuAnimation *self; DBG_fprintf(stderr, "Visu Animation: dispose object %p.\n", (gpointer)obj); self = VISU_ANIMATION(obj); if (self->priv->dispose_has_run) return; self->priv->dispose_has_run = TRUE; visu_animation_abort(self); /* Chain up to the parent class */ DBG_fprintf(stderr, "Visu Animation: chain up to parent.\n"); G_OBJECT_CLASS(visu_animation_parent_class)->dispose(obj); DBG_fprintf(stderr, "Visu Animation: dispose ... OK.\n"); } static void visu_animation_finalize(GObject* obj) { VisuAnimation *self; self = VISU_ANIMATION(obj); g_free(self->priv->prop); G_OBJECT_CLASS(visu_animation_parent_class)->finalize(obj); } static void visu_animation_get_property(GObject* obj, guint property_id, GValue *value, GParamSpec *pspec) { VisuAnimation *self = VISU_ANIMATION(obj); switch (property_id) { case RUNNING_PROP: g_value_set_boolean(value, (self->priv->ref > 0)); break; default: /* We don't have any other property... */ G_OBJECT_WARN_INVALID_PROPERTY_ID(obj, property_id, pspec); break; } } /** * visu_animation_new: * @obj: (transfer none): a #GObject object. * @property: a property name. * * Create an animation for @property of @obj. * * Since: 3.8 * * Returns: (transfer full): a new #VisuAnimation object. **/ VisuAnimation* visu_animation_new(GObject *obj, const gchar *property) { GParamSpec *pspec; VisuAnimation *anim; pspec = g_object_class_find_property(G_OBJECT_GET_CLASS(obj), property); g_return_val_if_fail(pspec, (VisuAnimation*)0); anim = g_object_new(VISU_TYPE_ANIMATION, NULL); anim->priv->prop = g_strdup(property); g_value_init(&anim->priv->from, G_PARAM_SPEC_VALUE_TYPE(pspec)); g_value_init(&anim->priv->to, G_PARAM_SPEC_VALUE_TYPE(pspec)); g_weak_ref_set(&anim->priv->obj, obj); return anim; } /** * visu_animation_start: * @anim: a #VisuAnimation object. * @to: a final value. * @tick: the current clock time. * @duration: a duration in micro-seconds. * @loop: a boolean. * @type: a type. * * Starts @anim, to go to the value @to from its current value * following @type evolution. @tick is the current clock time and the * animation is scheduled to last for @duration. If @loop is true, * when the animation reaches @to it restarts again from the initial * value. Use visu_animation_abort() to stop it. * * Since: 3.8 * * Returns: TRUE if the animation is actually started. **/ gboolean visu_animation_start(VisuAnimation *anim, const GValue *to, gulong tick, gulong duration, gboolean loop, VisuAnimationType type) { gpointer obj; g_return_val_if_fail(VISU_IS_ANIMATION(anim), FALSE); if (anim->priv->blocked) return FALSE; if (!anim->priv->ref) { obj = g_weak_ref_get(&anim->priv->obj); if (!obj) return FALSE; g_object_get_property(obj, anim->priv->prop, &anim->priv->from); g_object_unref(obj); } else { anim->priv->ref = 0; g_value_copy(&anim->priv->to, &anim->priv->from); } g_value_copy(to, &anim->priv->to); switch (G_VALUE_TYPE(&anim->priv->to)) { case G_TYPE_FLOAT: if (g_value_get_float(&anim->priv->from) == g_value_get_float(&anim->priv->to)) return FALSE; break; case G_TYPE_DOUBLE: if (g_value_get_double(&anim->priv->from) == g_value_get_double(&anim->priv->to)) return FALSE; break; default: g_warning("Type not implemented in animation for %s.", anim->priv->prop); }; anim->priv->ref = tick; anim->priv->duration = duration; anim->priv->loop = loop; anim->priv->type = type; g_object_notify_by_pspec(G_OBJECT(anim), _properties[RUNNING_PROP]); DBG_fprintf(stderr, "Visu Animation: start animation at %ld for %ld.\n", tick, duration); return TRUE; } /** * visu_animation_animate: * @anim: a #VisuAnimation object. * @tick: a time clock. * * Update the property animated by @anim to the value it should take * at @tick. * * Since: 3.8 * * Returns: TRUE if the animation is finished. **/ gboolean visu_animation_animate(VisuAnimation *anim, gulong tick) { double alpha; gboolean finished; gpointer obj; GValue at = G_VALUE_INIT; g_return_val_if_fail(VISU_IS_ANIMATION(anim), FALSE); if (!anim->priv->ref) return FALSE; alpha = (double)(tick - anim->priv->ref) / (double)anim->priv->duration; DBG_fprintf(stderr, "Visu Animation: alpha is %g for %s (%ld).\n", alpha, anim->priv->prop, tick); finished = (alpha > 1.); alpha = CLAMP(alpha, 0., 1.); switch (anim->priv->type) { case VISU_ANIMATION_LINEAR: break; case VISU_ANIMATION_QUAD: alpha = (alpha < 0.5) ? 2. * alpha * alpha : 1. - 2. * (1. - alpha) * (1. - alpha) ; break; case VISU_ANIMATION_SIN: alpha = 0.5 - 0.5 * cos(G_PI * alpha); break; }; g_value_init(&at, G_VALUE_TYPE(&anim->priv->to)); switch (G_VALUE_TYPE(&anim->priv->to)) { case G_TYPE_FLOAT: g_value_set_float(&at, g_value_get_float(&anim->priv->from) + alpha * (g_value_get_float(&anim->priv->to) - g_value_get_float(&anim->priv->from))); DBG_fprintf(stderr, "Visu Animation: set float value to %g.\n", g_value_get_float(&at)); break; case G_TYPE_DOUBLE: g_value_set_double(&at, g_value_get_double(&anim->priv->from) + alpha * (g_value_get_double(&anim->priv->to) - g_value_get_double(&anim->priv->from))); DBG_fprintf(stderr, "Visu Animation: set double value to %g.\n", g_value_get_double(&at)); break; default: g_warning("Type not implemented in animation for %s.", anim->priv->prop); }; obj = g_weak_ref_get(&anim->priv->obj); if (!obj) return FALSE; anim->priv->blocked = TRUE; g_object_set_property(obj, anim->priv->prop, &at); anim->priv->blocked = FALSE; g_value_unset(&at); if (finished && anim->priv->loop) { finished = FALSE; anim->priv->ref = tick; anim->priv->blocked = TRUE; g_object_set_property(obj, anim->priv->prop, &anim->priv->from); anim->priv->blocked = FALSE; } else if (finished) visu_animation_abort(anim); g_object_unref(obj); return !finished; } /** * visu_animation_abort: * @anim: a #VisuAnimation object. * * Stop the current animation. * * Since: 3.8 **/ void visu_animation_abort(VisuAnimation *anim) { g_return_if_fail(VISU_IS_ANIMATION(anim)); anim->priv->ref = 0; g_object_notify_by_pspec(G_OBJECT(anim), _properties[RUNNING_PROP]); g_value_reset(&anim->priv->from); g_value_reset(&anim->priv->to); } /** * visu_animation_isRunning: * @anim: a #VisuAnimation object. * * Inquires if @anim is currently running. * * Since: 3.8 * * Returns: TRUE if @anim is running. **/ gboolean visu_animation_isRunning(const VisuAnimation *anim) { g_return_val_if_fail(VISU_IS_ANIMATION(anim), FALSE); return (anim->priv->ref > 0); } /** * visu_animation_getFrom: * @anim: a #VisuAnimation object. * @from: (out caller-allocates): a location to store the initial * value of @anim. * * Retrieves the initial value of @anim. The animation should be * running for this value to be defined. * * Since: 3.8 **/ void visu_animation_getFrom(const VisuAnimation *anim, GValue *from) { g_return_if_fail(VISU_IS_ANIMATION(anim)); g_value_copy(&anim->priv->from, from); } /** * visu_animation_getTo: * @anim: a #VisuAnimation object. * @to: (out caller-allocates): a location to store the final * value of @anim. * * Retrieves the final value of @anim. The animation should be * running for this value to be defined. * * Since: 3.8 **/ void visu_animation_getTo(const VisuAnimation *anim, GValue *to) { g_return_if_fail(VISU_IS_ANIMATION(anim)); g_value_copy(&anim->priv->to, to); } v_sim-3.8.0/src/visu_animation.h000066400000000000000000000107061370110300500166160ustar00rootroot00000000000000/* EXTRAITS DE LA LICENCE Copyright CEA, contributeurs : Damien CALISTE, laboratoire L_Sim, (2017) Adresse mèl : CALISTE, damien P caliste AT cea P fr. Ce logiciel est un programme informatique servant à visualiser des structures atomiques dans un rendu pseudo-3D. Ce logiciel est régi par la licence CeCILL soumise au droit français et respectant les principes de diffusion des logiciels libres. Vous pouvez utiliser, modifier et/ou redistribuer ce programme sous les conditions de la licence CeCILL telle que diffusée par le CEA, le CNRS et l'INRIA sur le site "http://www.cecill.info". Le fait que vous puissiez accéder à cet en-tête signifie que vous avez pris connaissance de la licence CeCILL, et que vous en avez accepté les termes (cf. le fichier Documentation/licence.fr.txt fourni avec ce logiciel). */ /* LICENCE SUM UP Copyright CEA, contributors : Damien CALISTE, laboratoire L_Sim, (2017) E-mail address: CALISTE, damien P caliste AT cea P fr. This software is a computer program whose purpose is to visualize atomic configurations in 3D. This software is governed by the CeCILL license under French law and abiding by the rules of distribution of free software. You can use, modify and/ or redistribute the software under the terms of the CeCILL license as circulated by CEA, CNRS and INRIA at the following URL "http://www.cecill.info". The fact that you are presently reading this means that you have had knowledge of the CeCILL license and that you accept its terms. You can find a copy of this licence shipped with this software at Documentation/licence.en.txt. */ #ifndef VISU_ANIMATION_H #define VISU_ANIMATION_H #include #include #include G_BEGIN_DECLS /***************/ /* Public part */ /***************/ /** * VisuAnimationType: * @VISU_ANIMATION_LINEAR: a linear evolution. * @VISU_ANIMATION_QUAD: a quadratic evolution. * @VISU_ANIMATION_SIN: a sinusoid evolution. * * Various type of time evolution. */ typedef enum _VisuAnimationType { VISU_ANIMATION_LINEAR, VISU_ANIMATION_QUAD, VISU_ANIMATION_SIN } VisuAnimationType; /** * VISU_TYPE_ANIMATION: * * return the type of #VisuAnimation. */ #define VISU_TYPE_ANIMATION (visu_animation_get_type ()) /** * VISU_ANIMATION: * @obj: a #GObject to cast. * * Cast the given @obj into #VisuAnimation type. */ #define VISU_ANIMATION(obj) (G_TYPE_CHECK_INSTANCE_CAST(obj, VISU_TYPE_ANIMATION, VisuAnimation)) /** * VISU_ANIMATION_CLASS: * @klass: a #GObjectClass to cast. * * Cast the given @klass into #VisuAnimationClass. */ #define VISU_ANIMATION_CLASS(klass) (G_TYPE_CHECK_CLASS_CAST(klass, VISU_TYPE_ANIMATION, VisuAnimationClass)) /** * VISU_IS_ANIMATION: * @obj: a #GObject to test. * * Test if the given @ogj is of the type of #VisuAnimation object. */ #define VISU_IS_ANIMATION(obj) (G_TYPE_CHECK_INSTANCE_TYPE(obj, VISU_TYPE_ANIMATION)) /** * VISU_IS_ANIMATION_CLASS: * @klass: a #GObjectClass to test. * * Test if the given @klass is of the type of #VisuAnimationClass class. */ #define VISU_IS_ANIMATION_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE(klass, VISU_TYPE_ANIMATION)) /** * VISU_ANIMATION_GET_CLASS: * @obj: a #GObject to get the class of. * * It returns the class of the given @obj. */ #define VISU_ANIMATION_GET_CLASS(obj) (G_TYPE_INSTANCE_GET_CLASS(obj, VISU_TYPE_ANIMATION, VisuAnimationClass)) typedef struct _VisuAnimationPrivate VisuAnimationPrivate; /** * VisuAnimation: * * Common name to refer to a #_VisuAnimation. */ typedef struct _VisuAnimation VisuAnimation; struct _VisuAnimation { VisuObject parent; VisuAnimationPrivate *priv; }; /** * VisuAnimationClass: * @parent: private. * * Common name to refer to a #_VisuAnimationClass. */ typedef struct _VisuAnimationClass VisuAnimationClass; struct _VisuAnimationClass { VisuObjectClass parent; }; GType visu_animation_get_type(void); VisuAnimation* visu_animation_new(GObject *obj, const gchar *property); gboolean visu_animation_start(VisuAnimation *anim, const GValue *to, gulong tick, gulong duration, gboolean loop, VisuAnimationType type); gboolean visu_animation_animate(VisuAnimation *anim, gulong tick); gboolean visu_animation_isRunning(const VisuAnimation *anim); void visu_animation_getFrom(const VisuAnimation *anim, GValue *from); void visu_animation_getTo(const VisuAnimation *anim, GValue *to); void visu_animation_abort(VisuAnimation *anim); G_END_DECLS #endif v_sim-3.8.0/src/visu_basic.c000066400000000000000000000744021370110300500157160ustar00rootroot00000000000000/* EXTRAITS DE LA LICENCE Copyright CEA, contributeurs : Luc BILLARD et Damien CALISTE, laboratoire L_Sim, (2001-2005) Adresse mèl : BILLARD, non joignable par mèl ; CALISTE, damien P caliste AT cea P fr. Ce logiciel est un programme informatique servant à visualiser des structures atomiques dans un rendu pseudo-3D. Ce logiciel est régi par la licence CeCILL soumise au droit français et respectant les principes de diffusion des logiciels libres. Vous pouvez utiliser, modifier et/ou redistribuer ce programme sous les conditions de la licence CeCILL telle que diffusée par le CEA, le CNRS et l'INRIA sur le site "http://www.cecill.info". Le fait que vous puissiez accéder à cet en-tête signifie que vous avez pris connaissance de la licence CeCILL, et que vous en avez accepté les termes (cf. le fichier Documentation/licence.fr.txt fourni avec ce logiciel). */ /* LICENCE SUM UP Copyright CEA, contributors : Luc BILLARD et Damien CALISTE, laboratoire L_Sim, (2001-2005) E-mail address: BILLARD, not reachable any more ; CALISTE, damien P caliste AT cea P fr. This software is a computer program whose purpose is to visualize atomic configurations in 3D. This software is governed by the CeCILL license under French law and abiding by the rules of distribution of free software. You can use, modify and/ or redistribute the software under the terms of the CeCILL license as circulated by CEA, CNRS and INRIA at the following URL "http://www.cecill.info". The fact that you are presently reading this means that you have had knowledge of the CeCILL license and that you accept its terms. You can find a copy of this licence shipped with this software at Documentation/licence.en.txt. */ #include "visu_basic.h" #include "visu_extension.h" #include "visu_dataatomic.h" #include "visu_dataspin.h" #include "visu_elements.h" #include "visu_commandLine.h" #include "visu_plugins.h" #include "opengl.h" #include "dumpModules/fileDump.h" #include "dumpModules/glDump.h" #include "visu_pairset.h" #include "visu_tools.h" #include "visu_configFile.h" #include "extraFunctions/plane.h" #include "extraFunctions/pot2surf.h" #include "extraFunctions/map.h" #include "extraFunctions/surfaces_resources.h" #include "extraFunctions/sfielddata.h" #include "extraFunctions/scalarFieldSet.h" #include "openGLFunctions/objectList.h" #include "openGLFunctions/text.h" #include "openGLFunctions/interactive.h" #include "OSOpenGL/visu_openGL.h" #include "extensions/fogAndBGColor.h" #include "extensions/scale.h" #include "extensions/marks.h" #include "extensions/axes.h" #include "extensions/box.h" #include "extensions/box_legend.h" #include "extensions/legend.h" #include "extensions/pairs.h" #include "extensions/shade.h" #include "extensions/node_vectors.h" #include "extensions/planes.h" #include "extensions/surfs.h" #include "extensions/maps.h" #include "extensions/forces.h" #include "extensions/geodiff.h" #include "extensions/paths.h" #include "coreTools/toolConfigFile.h" #include "extraFunctions/geometry.h" #include "renderingMethods/elementAtomic.h" #include "renderingMethods/elementSpin.h" #include "renderingMethods/spinMethod.h" #include #include #include /* For the access markers R_OK, W_OK ... */ #include #include /** * SECTION:visu_basic * @short_description: Main functions of V_Sim (except graphical * ones). * * There are here the main functions of V_Sim (except for * graphical methods) such as open file. */ #if SYSTEM_X11 == 1 #define V_SIM_DATA_DIR_DEFAULT "/usr/local/share/v_sim" #define V_SIM_LEGAL_DIR_DEFAULT "/usr/local/share/v_sim" #define V_SIM_PIXMAPS_DIR_DEFAULT "/usr/local/share/v_sim/pixmaps" #define V_SIM_ICONS_DIR_DEFAULT "/usr/local/share/icons" #define V_SIM_PLUGINS_DIR_DEFAULT "/usr/local/lib/v_sim/plug-ins" #define V_SIM_LOCALE_DIR_DEFAULT "/usr/local/share/locale" #endif #if SYSTEM_WIN32 == 1 #define V_SIM_DATA_DIR_DEFAULT "C:\\PROGRAM FILES\\V_Sim\\share\\v_sim" #define V_SIM_LEGAL_DIR_DEFAULT "C:\\PROGRAM FILES\\V_Sim\\share\\doc\\v_sim" #define V_SIM_PIXMAPS_DIR_DEFAULT "C:\\PROGRAM FILES\\V_Sim\\share\\v_sim\\pixmaps" #define V_SIM_ICONS_DIR_DEFAULT "C:\\PROGRAM FILES\\V_Sim\\share\\icons" #define V_SIM_PLUGINS_DIR_DEFAULT "C:\\PROGRAM FILES\\V_Sim\\lib\\v_sim\\plug-ins" #define V_SIM_LOCALE_DIR_DEFAULT "C:\\PROGRAM FILES\\V_Sim\\share\\locale" #endif static gchar *exeLocation = NULL; static gchar *v_sim_data_dir = NULL; static gchar *v_sim_legal_dir = NULL; static gchar *v_sim_pixmaps_dir = NULL; static gchar *v_sim_icons_dir = NULL; static gchar *v_sim_local_conf_dir = NULL; static gchar *v_sim_old_local_conf_dir = NULL; static gchar *v_sim_plugins_dir = NULL; static gchar *v_sim_locale_dir = NULL; static ToolUnits preferedUnit; /* Local methods. */ static gboolean dumpData(gpointer data); static gboolean _toUnit(const gchar *label, ToolUnits *unit); #define FLAG_PARAMETER_UNIT "main_unit" #define DESC_PARAMETER_UNIT "Define the prefered unit to display files ; string" static void exportParameters(GString *data, VisuData *dataObj); static void _notNull(const GValue *from, GValue *to) { g_value_set_boolean(to, (g_value_get_object(from) != NULL)); } static void _notNullBoxed(const GValue *from, GValue *to) { g_value_set_boolean(to, (g_value_get_boxed(from) != NULL)); } /** * visu_basic_init: * * A call to this method is done at startup after having probe the locale of the file * system and having initialized the rendering window. It makes the following actions : * create the visu object to store the signals, initialize the module part (parameters, * and resources), initialize the dump part, the OpenGL part and its extensions, the * storage of elements and the 'colorize with data' part. */ void visu_basic_init(void) { static gboolean done = FALSE; VisuConfigFileEntry *entry; if (done) return; DBG_fprintf(stderr,"--- Initialising variables ---\n"); /* We want to read . as floating point separator : in french it is , */ setlocale(LC_NUMERIC, "C"); tool_matrix_init(); tool_shade_get_type(); preferedUnit = TOOL_UNITS_UNDEFINED; /* Force the creation of the main object class. */ g_type_class_ref(VISU_TYPE_CONFIG_FILE); /* initialise OpenGL. */ DBG_fprintf(stderr,"--- Initialising OpenGL ---\n"); g_type_class_ref(VISU_TYPE_GL); g_type_class_ref(VISU_TYPE_GL_VIEW); g_type_class_ref(VISU_TYPE_GL_NODE_SCENE); g_type_class_ref(VISU_TYPE_INTERACTIVE); /* Initialise extra functions. */ DBG_fprintf(stderr,"--- Initialising extra functions ---\n"); g_type_class_ref(VISU_TYPE_SURFACE); g_type_class_ref(VISU_TYPE_SURFACE_RESOURCE); g_type_class_ref(VISU_TYPE_SCALAR_FIELD); g_type_class_ref(VISU_TYPE_SCALAR_FIELD_DATA); g_type_class_ref(VISU_TYPE_COLORIZATION); g_type_class_ref(VISU_TYPE_MAP); /* Force the creation of some internal classes. */ DBG_fprintf(stderr,"--- Initialising internal classes ---\n"); g_type_class_ref(VISU_TYPE_PAIR_LINK); g_type_class_ref(VISU_TYPE_ELEMENT_ATOMIC); g_type_class_ref(VISU_TYPE_GL_EXT_SET); g_type_class_ref(VISU_TYPE_GL_EXT); g_type_class_ref(VISU_TYPE_GL_EXT_AXES); g_type_class_ref(VISU_TYPE_GL_EXT_BOX); g_type_class_ref(VISU_TYPE_GL_EXT_BOX_LEGEND); g_type_class_ref(VISU_TYPE_GL_EXT_LEGEND); g_type_class_ref(VISU_TYPE_GL_EXT_PAIRS); g_type_class_ref(VISU_TYPE_GL_EXT_PLANES); g_type_class_ref(VISU_TYPE_GL_EXT_SURFACES); g_type_class_ref(VISU_TYPE_GL_EXT_BG); g_type_class_ref(VISU_TYPE_GL_EXT_MARKS); g_type_class_ref(VISU_TYPE_GL_EXT_NODE_VECTORS); g_type_class_ref(VISU_TYPE_GL_EXT_INFOS); g_type_class_ref(VISU_TYPE_GL_EXT_SCALE); g_type_class_ref(VISU_TYPE_GL_EXT_FORCES); g_type_class_ref(VISU_TYPE_GL_EXT_GEODIFF); g_type_class_ref(VISU_TYPE_GL_EXT_PATHS); g_type_class_ref(VISU_TYPE_ELEMENT); g_type_class_ref(VISU_TYPE_DATA_ATOMIC); g_type_class_ref(VISU_TYPE_DATA_SPIN); g_type_class_ref(VISU_TYPE_METHOD_SPIN); visu_config_file_ignoreEntry(VISU_CONFIG_FILE_PARAMETER, "rendering_favoriteMethod", 1); entry = visu_config_file_addEnumEntry(VISU_CONFIG_FILE_PARAMETER, FLAG_PARAMETER_UNIT, DESC_PARAMETER_UNIT, &preferedUnit, _toUnit, FALSE); visu_config_file_entry_setVersion(entry, 3.5f); visu_config_file_addExportFunction(VISU_CONFIG_FILE_PARAMETER, exportParameters); g_value_register_transform_func(G_TYPE_BOXED, G_TYPE_BOOLEAN, _notNullBoxed); g_value_register_transform_func(G_TYPE_OBJECT, G_TYPE_BOOLEAN, _notNull); g_value_register_transform_func(VISU_TYPE_POINTSET, G_TYPE_BOOLEAN, _notNull); done = TRUE; } /** * visu_basic_parseConfigFiles: * @error: location for an error. * * Parse the parameter and the resource file. Used once at startup. * * Returns: a newly allocated #GString if some error occured. */ gboolean visu_basic_parseConfigFiles(GError **error) { char* path; gboolean res; char *resFile; if (!g_type_class_peek(VISU_TYPE_CONFIG_FILE)) visu_basic_init(); DBG_fprintf(stderr,"--- Initialising the parameters ---\n"); /* Look for parameters file */ path = visu_config_file_getValidPath(VISU_CONFIG_FILE_PARAMETER, R_OK, 0); if (path) { res = visu_config_file_load(VISU_CONFIG_FILE_PARAMETER, path, error); g_free(path); if (!res) return FALSE; } DBG_fprintf(stderr,"--- Initialising resources ---\n"); /* Look for resources file */ resFile = commandLineGet_resourcesFile(); if (!resFile) path = visu_config_file_getValidPath(VISU_CONFIG_FILE_RESOURCE, R_OK, 0); else path = g_strdup(resFile); if (path) { res = visu_config_file_load(VISU_CONFIG_FILE_RESOURCE, path, error); g_free(path); if (!res) return FALSE; } /* Overload with commandline options. */ res = visu_config_file_loadCommandLine(error); if (!res) return FALSE; return TRUE; } /** * visu_basic_initConfigFiles: * @error: an error location. * * Same as visu_basic_parseConfigFiles(), but perform the operation * only once. * * Since: 3.8 **/ void visu_basic_initConfigFiles(GError **error) { static gboolean done = FALSE; if (done) return; visu_basic_parseConfigFiles(error); done = TRUE; } struct _dump { GMainLoop *loop; VisuDump *format; gchar *exportFileName; VisuDataLoadable *dataObj; /* Return. */ int status; }; /** * visu_basic_mainExport: * * This method is called when V_Sim is in export mode from the command line. * * Returns: 0 if everything is normal, 1 if an error occured. */ int visu_basic_mainExport(void) { GError *error; gboolean res; struct _dump dt; GList *pnt; GHashTable *opts; ToolOption *id; VisuGlNodeScene *scene; guint width, height; dt.exportFileName = commandLineGet_ExportFileName(); if (!dt.exportFileName) { g_error("This method should be called with" " an argument that is the file name to export to.\n"); } id = (ToolOption*)0; opts = commandLineGet_options(); if (opts) id = (ToolOption*)g_hash_table_lookup(opts, "fileFormatId"); pnt = visu_dump_pool_getAllModules(); if (!id) while (pnt && !tool_file_format_match(TOOL_FILE_FORMAT(pnt->data), dt.exportFileName)) pnt = g_list_next(pnt); else pnt = g_list_nth(pnt, g_value_get_int(tool_option_getValue(id)) - 1); if (!pnt) { g_warning(_("The format can't be found from the" " filename '%s' entered.\n"), dt.exportFileName); g_print(_("Use -o fileFormatId=id to specify a file format" " when the autodetection fails. Get a list of ids" " with option -o list:\n\n")); visu_basic_showOptionHelp(TRUE); return 1; } dt.format = VISU_DUMP(pnt->data); /* We transfer some options to file format. */ tool_file_format_setPropertiesFromCLI(TOOL_FILE_FORMAT(dt.format)); #if ! GLIB_CHECK_VERSION(2, 36, 0) g_type_init(); #endif visu_basic_init(); dt.dataObj = visu_data_loadable_new_fromCLI(); if (!dt.dataObj) { g_error(_("a file to render is mandatory with the '--export' option.")); } error = (GError*)0; if (VISU_IS_DUMP_SCENE(dt.format) && !visu_basic_parseConfigFiles(&error)) { g_warning("%s", error->message); g_error_free(error); } error = (GError*)0; res = visu_data_loadable_load(dt.dataObj, 0, (GCancellable*)0, &error); if (!res) { g_object_unref(dt.dataObj); g_error("%s", (error)?error->message:"No error message!"); } dt.status = 0; if (VISU_IS_DUMP_SCENE(dt.format)) { DBG_fprintf(stderr, "Visu Basic: begin dump exportation.\n"); scene = visu_gl_node_scene_new(); visu_gl_node_scene_setData(scene, VISU_DATA(dt.dataObj)); error = (GError*)0; if (!visu_gl_node_scene_applyCLI(scene, &error)) dt.status = 1; else { DBG_fprintf(stderr, "Visu Basic: adding the load call back in the queue.\n"); /* Start the elements related to the main loop. */ dt.loop = g_main_loop_new(NULL, FALSE); g_idle_add_full(G_PRIORITY_LOW + 100, dumpData, (gpointer)&dt, NULL); g_main_loop_run(dt.loop); DBG_fprintf(stderr, "Visu Basic: calling exportation routine.\n"); commandLineGet_XWindowGeometry((int*)&width, (int*)&height); error = (GError*)0; if (!visu_gl_node_scene_dump(scene, dt.format, dt.exportFileName, width, height, (ToolVoidDataFunc)0, (gpointer)0, &error)) dt.status = 1; } g_object_unref(scene); } else { error = (GError*)0; if (!visu_data_applyTransformationsFromCLI(VISU_DATA(dt.dataObj), &error)) dt.status = 1; /* Direct export. */ else if (!visu_dump_data_write(VISU_DUMP_DATA(dt.format), dt.exportFileName, VISU_DATA(dt.dataObj), &error)) dt.status = 1; } if (error) { g_warning("%s", error->message); g_error_free(error); } g_object_unref(dt.dataObj); return dt.status; } static gboolean dumpData(gpointer data) { struct _dump *dt = (struct _dump*)data; DBG_fprintf(stderr, "Visu Basic: stopping the main loop.\n"); g_main_loop_quit(dt->loop); return FALSE; } /** * visu_basic_showOptionHelp: * @force: a boolean. * * Display a small help for some options. The output is different from * the -h command line options, here some details about running time * options is displayed like the available file format for * exportation... If @force is TRUE, all possible values are output, * otherwise only those relevant to the user provided command line * options. * * Since: 3.6 * * Returns: TRUE if something is displayed. */ gboolean visu_basic_showOptionHelp(gboolean force) { ToolFileFormatIter iter; GList *pnt; GHashTable *opts; ToolFileFormat *format; guint i; if (!force) { opts = commandLineGet_options(); if (!opts || !g_hash_table_lookup(opts, "list")) return FALSE; } i = 1; for (pnt = visu_dump_pool_getAllModules(); pnt; pnt = g_list_next(pnt)) { format = TOOL_FILE_FORMAT(pnt->data); fprintf(stdout, _("\n#%2d - exportation file format '%s':\n"), i++, tool_file_format_getName(format)); iter.lst = (GList*)0; for (tool_file_format_iterNextProperty(format, &iter); iter.lst; tool_file_format_iterNextProperty(format, &iter)) { fprintf(stdout, " - '%25s'", iter.name); switch (G_VALUE_TYPE(iter.val)) { case G_TYPE_INT: fprintf(stdout, " %10s (%5d): ", _("integer"), g_value_get_int(iter.val)); break; case G_TYPE_BOOLEAN: fprintf(stdout, " %10s (%5d): ", _("boolean"), g_value_get_boolean(iter.val)); break; case G_TYPE_STRING: fprintf(stdout, " %10s: ", _("string")); break; default: g_warning("Unknown type for file format property."); break; } fprintf(stdout, "%s.\n", iter.label); } tool_file_format_iterNextProperty(format, &iter); if (!iter.lst) fprintf(stdout, _("No option for this file format.\n")); } i = 1; for (pnt = visu_data_atomic_class_getLoaders(); pnt; pnt = g_list_next(pnt)) { format = TOOL_FILE_FORMAT(pnt->data); fprintf(stdout, _("\n#%2d - input file format '%s':\n"), i++, tool_file_format_getName(format)); iter.lst = (GList*)0; for (tool_file_format_iterNextProperty(format, &iter); iter.lst; tool_file_format_iterNextProperty(format, &iter)) { fprintf(stdout, " - '%25s'", iter.name); switch (G_VALUE_TYPE(iter.val)) { case G_TYPE_INT: fprintf(stdout, " %10s (%5d): ", _("integer"), g_value_get_int(iter.val)); break; case G_TYPE_BOOLEAN: fprintf(stdout, " %10s (%5d): ", _("boolean"), g_value_get_boolean(iter.val)); break; case G_TYPE_STRING: fprintf(stdout, " %10s: ", _("string")); break; default: g_warning("Unknown type for file format property."); break; } fprintf(stdout, "%s.\n", iter.label); } tool_file_format_iterNextProperty(format, &iter); if (!iter.lst) fprintf(stdout, _("No option for this file format.\n")); } return TRUE; } static gchar* setDir(const gchar* const *sysDirs, const gchar *prefix, const gchar* subDir, const gchar* defaultDir) { gchar *dir; int i; dir = g_build_filename(prefix, subDir, NULL); if (!g_file_test(dir, G_FILE_TEST_IS_DIR)) { g_free(dir); dir = (gchar*)0; /* We try the XDG stuff. */ for (i = 0; sysDirs[i]; i++) { dir = g_build_filename(sysDirs[i], subDir, NULL); if (g_file_test(dir, G_FILE_TEST_IS_DIR)) break; else g_free(dir); dir = (gchar*)0; } } if (!dir) dir = g_strdup(defaultDir); return dir; } /** * visu_basic_setExePath: * @exePath: a path where the V_Sim executable is running in. * * This method is used to tell V_Sim where V_Sim is running (usually * reading from argv[0]. This makes it possible to relocate everything * on the fly. @exePath is copied. * * Since: 3.6 */ void visu_basic_setExePath(const gchar *exePath) { if (exeLocation) g_free(exeLocation); exeLocation = g_strdup(exePath); } /** * setVisuPaths: * * This method sets the paths. On Unix systems, this method sets the paths * from macros defined by configure. On Win32 systems, it reads paths in * a v_sim.ini file found in the current directory or in the C:\windows. */ static void setVisuPaths(void) { #if SYSTEM_WIN32 == 1 #define V_SIM_INI_FILE PACKAGE".ini" GIOChannel *iniFile; gchar *iniPath, *tmp, *me, *prefix; gchar *buffer, *line; GIOStatus res; GError *err; gchar **tokens; gsize length; if (!exeLocation) exeLocation = g_strdup(PACKAGE_TARNAME); v_sim_data_dir = g_strdup(V_SIM_DATA_DIR_DEFAULT); v_sim_legal_dir = g_strdup(V_SIM_LEGAL_DIR_DEFAULT); v_sim_pixmaps_dir = g_strdup(V_SIM_PIXMAPS_DIR_DEFAULT); v_sim_icons_dir = g_strdup(V_SIM_ICONS_DIR_DEFAULT); v_sim_plugins_dir = g_strdup(V_SIM_PLUGINS_DIR_DEFAULT); v_sim_locale_dir = g_strdup(V_SIM_LOCALE_DIR_DEFAULT); iniPath = g_strdup(V_SIM_INI_FILE); /* Try to find the INI file from cwd. */ prefix = (gchar*)0; iniFile = g_io_channel_new_file(iniPath, "r", (GError**)0); if (iniFile) prefix = g_get_current_dir(); /* Try to find the INI file from the name of the executable. */ if (!iniFile) { g_free(iniPath); if (g_file_test(exeLocation, G_FILE_TEST_IS_SYMLINK)) tmp = g_file_read_link(exeLocation, (GError**)0); else tmp = g_strdup(exeLocation); me = tool_path_normalize(tmp); g_free(tmp); DBG_fprintf(stderr, "Visu Basic: running program is '%s'.\n", me); /* From the location of the executable, we take the base dir. */ prefix = g_path_get_dirname(me); g_free(me); iniPath = g_build_filename(prefix, V_SIM_INI_FILE, NULL); iniFile = g_io_channel_new_file(iniPath, "r", (GError**)0); } /* Try to find the INI file in the Windows directory. */ if (!iniFile) { g_free(iniPath); prefix = g_strdup("C:\\WINDOWS"); iniPath = g_build_filename(prefix, V_SIM_INI_FILE, NULL); iniFile = g_io_channel_new_file(iniPath, "r", (GError**)0); } if (iniFile) { buffer = (gchar*)0; err = (GError*)0; do { res = g_io_channel_read_line(iniFile, &line, &length, NULL, &err); if (line && res == G_IO_STATUS_NORMAL) { tokens = g_strsplit(line, "=", 2); if (!strcmp(g_strstrip(tokens[0]), "data_dir") && tokens[1]) { g_free(v_sim_data_dir); tmp = g_strstrip(tokens[1]); if (g_path_is_absolute(tmp)) v_sim_data_dir = g_strdup(tmp); else v_sim_data_dir = g_build_filename(prefix, tmp, NULL); } if (!strcmp(g_strstrip(tokens[0]), "legal_dir") && tokens[1]) { g_free(v_sim_legal_dir); tmp = g_strstrip(tokens[1]); if (g_path_is_absolute(tmp)) v_sim_legal_dir = g_strdup(tmp); else v_sim_legal_dir = g_build_filename(prefix, tmp, NULL); } if (!strcmp(g_strstrip(tokens[0]), "pixmaps_dir") && tokens[1]) { g_free(v_sim_pixmaps_dir); tmp = g_strstrip(tokens[1]); if (g_path_is_absolute(tmp)) v_sim_pixmaps_dir = g_strdup(tmp); else v_sim_pixmaps_dir = g_build_filename(prefix, tmp, NULL); } if (!strcmp(g_strstrip(tokens[0]), "icons_dir") && tokens[1]) { g_free(v_sim_icons_dir); tmp = g_strstrip(tokens[1]); if (g_path_is_absolute(tmp)) v_sim_icons_dir = g_strdup(tmp); else v_sim_icons_dir = g_build_filename(prefix, tmp, NULL); } if (!strcmp(g_strstrip(tokens[0]), "plugins_dir") && tokens[1]) { g_free(v_sim_plugins_dir); tmp = g_strstrip(tokens[1]); if (g_path_is_absolute(tmp)) v_sim_plugins_dir = g_strdup(tmp); else v_sim_plugins_dir = g_build_filename(prefix, tmp, NULL); } if (!strcmp(g_strstrip(tokens[0]), "locale_dir") && tokens[1]) { g_free(v_sim_locale_dir); tmp = g_strstrip(tokens[1]); if (g_path_is_absolute(tmp)) v_sim_locale_dir = g_strdup(tmp); else v_sim_locale_dir = g_build_filename(prefix, tmp, NULL); } g_strfreev(tokens); g_free(line); } } while (res != G_IO_STATUS_EOF); g_io_channel_shutdown (iniFile, FALSE, (GError**)0); g_io_channel_unref (iniFile); } g_free(iniPath); #endif #if SYSTEM_X11 == 1 const gchar* const *sysDirs; gchar *me, *prefix, *tmp; #if DEBUG == 1 int i; #endif /* We try to get the dirs from XDG specs, otherwise we fall back to hard coded values at compilation time. */ #if GLIB_MINOR_VERSION > 5 sysDirs = g_get_system_data_dirs(); #if DEBUG == 1 fprintf(stderr, "Visu Basic: available data dirs:\n"); for (i = 0; sysDirs[i]; i++) fprintf(stderr, " | '%s'.\n", sysDirs[i]); #endif #else sysDirs = g_malloc(sizeof(const gchar*)); sysDirs[0] = (const gchar*)0; #endif if (!exeLocation) exeLocation = g_strdup(PACKAGE_TARNAME); if (g_file_test(exeLocation, G_FILE_TEST_IS_SYMLINK)) tmp = g_file_read_link(exeLocation, (GError**)0); else tmp = g_strdup(exeLocation); me = tool_path_normalize(tmp); g_free(tmp); DBG_fprintf(stderr, "Visu Basic: running program is '%s'.\n", me); /* From the location of the executable, we take the base dir or its parents if the basedir is bin. */ prefix = g_path_get_dirname(me); g_free(me); me = g_path_get_basename(prefix); if (!strcmp(me, "bin")) { g_free(me); me = prefix; prefix = g_path_get_dirname(me); } g_free(me); DBG_fprintf(stderr, " | prefix is '%s'.\n", prefix); v_sim_data_dir = setDir(sysDirs, prefix, "share/" PACKAGE, DATA_DIR); v_sim_legal_dir = setDir(sysDirs, prefix, "share/doc/" PACKAGE, LEGAL_DIR); v_sim_pixmaps_dir = setDir(sysDirs, prefix, "share/" PACKAGE "/pixmaps", PIXMAPS_DIR); v_sim_icons_dir = setDir(sysDirs, prefix, "share/icons", ICONS_DIR); v_sim_plugins_dir = setDir(sysDirs, prefix, "lib/" PACKAGE "/plug-ins", PLUGINS_DIR); v_sim_locale_dir = setDir(sysDirs, prefix, "share/locale", LOCALE_DIR); g_free(prefix); #endif /* Create the local dirs. */ #if GLIB_MINOR_VERSION > 5 v_sim_local_conf_dir = g_build_filename(g_get_user_config_dir(), "v_sim", NULL); #else v_sim_local_conf_dir = g_build_filename(g_get_home_dir(), ".config/v_sim", NULL); #endif if (!v_sim_local_conf_dir) g_warning("WARNING! Impossible to get the default" " path $XDG_CONFIG_HOME/v_sim.\n"); v_sim_old_local_conf_dir = g_build_filename(g_get_home_dir(), ".v_sim", NULL); DBG_fprintf(stderr, "Visu Basic: data directory : '%s'.\n", v_sim_data_dir); DBG_fprintf(stderr, "Visu Basic: local conf directory: '%s'.\n", v_sim_local_conf_dir); DBG_fprintf(stderr, "Visu Basic: legal directory : '%s'.\n", v_sim_legal_dir); DBG_fprintf(stderr, "Visu Basic: pixmaps directory : '%s'.\n", v_sim_pixmaps_dir); DBG_fprintf(stderr, "Visu Basic: icons directory : '%s'.\n", v_sim_icons_dir); DBG_fprintf(stderr, "Visu Basic: plug-ins directory : '%s'.\n", v_sim_plugins_dir); DBG_fprintf(stderr, "Visu Basic: locale directory : '%s'.\n", v_sim_locale_dir); } /** * visu_basic_getDataDir: * * Get the static string where V_Sim looks for its data files. * * Since: 3.4 * * Returns: (transfer none): a string owned by V_Sim. */ const gchar* visu_basic_getDataDir(void) { if (!v_sim_data_dir) setVisuPaths(); return v_sim_data_dir; } /** * visu_basic_getLegalDir: * * Get the static string where V_Sim looks for its legal files. * * Since: 3.4 * * Returns: (transfer none): a string owned by V_Sim. */ const gchar* visu_basic_getLegalDir(void) { if (!v_sim_legal_dir) setVisuPaths(); return v_sim_legal_dir; } /** * visu_basic_getPixmapsDir: * * Get the static string where V_Sim looks for its pixmap files. * * Since: 3.4 * * Returns: (transfer none): a string owned by V_Sim. */ const gchar* visu_basic_getPixmapsDir(void) { if (!v_sim_pixmaps_dir) setVisuPaths(); return v_sim_pixmaps_dir; } /** * visu_basic_getIconsDir: * * Get the static string where V_Sim looks for its icon files. * * Since: 3.4 * * Returns: (transfer none): a string owned by V_Sim. */ const gchar* visu_basic_getIconsDir(void) { if (!v_sim_icons_dir) setVisuPaths(); return v_sim_icons_dir; } /** * visu_basic_getLocalDir: * * Get the static string where V_Sim looks for its user configuration files. * * Since: 3.4 * * Returns: (transfer none): a string owned by V_Sim. */ const gchar* visu_basic_getLocalDir(void) { if (!v_sim_local_conf_dir) setVisuPaths(); return v_sim_local_conf_dir; } /** * visu_basic_getOldLocalDir: * * Get the static string where V_Sim looks for its user configuration * files (old location). * * Since: 3.4 * * Returns: (transfer none): a string owned by V_Sim. */ const gchar* visu_basic_getOldLocalDir(void) { if (!v_sim_old_local_conf_dir) setVisuPaths(); return v_sim_old_local_conf_dir; } /** * visu_basic_getPluginsDir: * * Get the static string where V_Sim looks for its plug-in files. * * Since: 3.4 * * Returns: (transfer none): a string owned by V_Sim. */ const gchar* visu_basic_getPluginsDir(void) { if (!v_sim_plugins_dir) setVisuPaths(); return v_sim_plugins_dir; } /** * visu_basic_getLocaleDir: * * Get the static string where V_Sim looks for its localisation files. * * Since: 3.4 * * Returns: (transfer none): a string owned by V_Sim. */ const gchar* visu_basic_getLocaleDir(void) { if (!v_sim_locale_dir) setVisuPaths(); return v_sim_locale_dir; } /** * visu_basic_freeAll: * * This routine is called by V_Sim when quiting and it frees the memory * used by visu_basic. * * Since: 3.5 */ void visu_basic_freeAll(void) { DBG_fprintf(stderr, "Visu Basic: free all.\n - the paths\n"); g_free(v_sim_data_dir); g_free(v_sim_legal_dir); g_free(v_sim_pixmaps_dir); g_free(v_sim_plugins_dir); g_free(v_sim_locale_dir); g_free(v_sim_local_conf_dir); g_free(v_sim_old_local_conf_dir); DBG_fprintf(stderr, " - the color storage\n"); g_object_unref(tool_color_getStorage()); g_object_unref(tool_shade_getStorage()); visu_surface_resource_pool_finalize(); visu_scalar_field_method_class_finalize(); visu_scalarfield_set_class_finalize(); visu_dump_pool_finalize(); visu_pair_pool_finalize(); visu_element_renderer_pool_finalize(); visu_element_atomic_pool_finalize(); visu_element_spin_pool_finalize(); visu_element_pool_finalize(); g_object_unref(visu_method_spin_getDefault()); visu_data_atomic_class_finalize(); visu_data_spin_class_finalize(); g_object_unref(VISU_CONFIG_FILE_RESOURCE); g_object_unref(VISU_CONFIG_FILE_PARAMETER); visu_plugins_free(); #if DEBUG == 1 tool_dbg_obj_class_summarize(); #endif } /** * visu_basic_getMainContext: * * Even without GUI, V_Sim requires to run a main loop. This method is * to get the main loop. * * Since: 3.6 * * Returns: (transfer none): the main loop, as defined in GLib. */ GMainContext* visu_basic_getMainContext(void) { return g_main_context_default(); } /* Resources. */ /** * visu_basic_getPreferedUnit: * * By setting the prefered unit, when a file is load, V_Sim tries to * render it in this prefered unit. * * Since: 3.5 * * Returns: the prefered unit set by the user (default is * #TOOL_UNITS_UNDEFINED). */ ToolUnits visu_basic_getPreferedUnit(void) { return preferedUnit; } /** * visu_basic_setPreferedUnit: * @unit: a #ToolUnits value. * * By setting the prefered unit, when a file is load, V_Sim tries to * render it in this prefered unit. * * Since: 3.5 * * Returns: TRUE if the prefered unit is actually changed. */ gboolean visu_basic_setPreferedUnit(ToolUnits unit) { if (unit == preferedUnit) return FALSE; preferedUnit = unit; return TRUE; } static gboolean _toUnit(const gchar *label, ToolUnits *unit) { ToolUnits val; val = tool_physic_getUnitFromName(label); if (val != TOOL_UNITS_UNDEFINED) *unit = val; return (val != TOOL_UNITS_UNDEFINED); } static void exportParameters(GString *data, VisuData *dataObj _U_) { const gchar **units; if (preferedUnit != TOOL_UNITS_UNDEFINED) { units = tool_physic_getUnitNames(); g_string_append_printf(data, "# %s\n", DESC_PARAMETER_UNIT); g_string_append_printf(data, "%s: %s\n\n", FLAG_PARAMETER_UNIT, units[preferedUnit]); } } v_sim-3.8.0/src/visu_basic.h000066400000000000000000000101311370110300500157100ustar00rootroot00000000000000/* EXTRAITS DE LA LICENCE Copyright CEA, contributeurs : Luc BILLARD et Damien CALISTE, laboratoire L_Sim, (2001-2005) Adresse mèl : BILLARD, non joignable par mèl ; CALISTE, damien P caliste AT cea P fr. Ce logiciel est un programme informatique servant à visualiser des structures atomiques dans un rendu pseudo-3D. Ce logiciel est régi par la licence CeCILL soumise au droit français et respectant les principes de diffusion des logiciels libres. Vous pouvez utiliser, modifier et/ou redistribuer ce programme sous les conditions de la licence CeCILL telle que diffusée par le CEA, le CNRS et l'INRIA sur le site "http://www.cecill.info". Le fait que vous puissiez accéder à cet en-tête signifie que vous avez pris connaissance de la licence CeCILL, et que vous en avez accepté les termes (cf. le fichier Documentation/licence.fr.txt fourni avec ce logiciel). */ /* LICENCE SUM UP Copyright CEA, contributors : Luc BILLARD et Damien CALISTE, laboratoire L_Sim, (2001-2005) E-mail address: BILLARD, not reachable any more ; CALISTE, damien P caliste AT cea P fr. This software is a computer program whose purpose is to visualize atomic configurations in 3D. This software is governed by the CeCILL license under French law and abiding by the rules of distribution of free software. You can use, modify and/ or redistribute the software under the terms of the CeCILL license as circulated by CEA, CNRS and INRIA at the following URL "http://www.cecill.info". The fact that you are presently reading this means that you have had knowledge of the CeCILL license and that you accept its terms. You can find a copy of this licence shipped with this software at Documentation/licence.en.txt. */ #ifndef VISU_BASIC_H #define VISU_BASIC_H #include #include "visu_tools.h" #include "coreTools/toolPhysic.h" G_BEGIN_DECLS void visu_basic_init(void); void visu_basic_initConfigFiles(GError **error); /* Common parse routines. */ gboolean visu_basic_parseConfigFiles(GError **error); gboolean visu_basic_showOptionHelp(gboolean force); /* Export routines. */ int visu_basic_mainExport(void); /* Some resources. */ ToolUnits visu_basic_getPreferedUnit(void); gboolean visu_basic_setPreferedUnit(ToolUnits unit); /** * VISU_VERSION: * * The value of current compiled version. */ #define VISU_VERSION VERSION /** * VISU_WEB_SITE: * * URL where to find info on V_Sim. */ #define VISU_WEB_SITE "http://inac.cea.fr/L_Sim/V_Sim" /* Main paths. */ void visu_basic_setExePath(const gchar *exePath); /** * V_SIM_DATA_DIR: * * The directory where data files are stored. */ #define V_SIM_DATA_DIR visu_basic_getDataDir() /** * V_SIM_LEGAL_DIR: * * The directory where copyright and author files are stored. */ #define V_SIM_LEGAL_DIR visu_basic_getLegalDir() /** * V_SIM_PIXMAPS_DIR: * * The directory where pixmap files are stored. */ #define V_SIM_PIXMAPS_DIR visu_basic_getPixmapsDir() /** * V_SIM_ICONS_DIR: * * The directory where icon files are stored. */ #define V_SIM_ICONS_DIR visu_basic_getIconsDir() /** * V_SIM_LOCAL_CONF_DIR: * * The directory where user configuration files are stored. */ #define V_SIM_LOCAL_CONF_DIR visu_basic_getLocalDir() /** * V_SIM_OLD_LOCAL_CONF_DIR: * * Old value of #V_SIM_LOCAL_CONF_DIR. */ #define V_SIM_OLD_LOCAL_CONF_DIR visu_basic_getOldLocalDir() /** * V_SIM_PLUGINS_DIR: * * The directory where plugin files are stored. */ #define V_SIM_PLUGINS_DIR visu_basic_getPluginsDir() /** * V_SIM_LOCALE_DIR: * * The directory where locale files are stored. */ #define V_SIM_LOCALE_DIR visu_basic_getLocaleDir() const gchar* visu_basic_getDataDir(void); const gchar* visu_basic_getLegalDir(void); const gchar* visu_basic_getPixmapsDir(void); const gchar* visu_basic_getIconsDir(void); const gchar* visu_basic_getLocalDir(void); const gchar* visu_basic_getOldLocalDir(void); const gchar* visu_basic_getPluginsDir(void); const gchar* visu_basic_getLocaleDir(void); /* Miscellaneous. */ GMainContext* visu_basic_getMainContext(void); void visu_basic_freeAll(void); G_END_DECLS #endif v_sim-3.8.0/src/visu_box.c000066400000000000000000001372541370110300500154320ustar00rootroot00000000000000/* EXTRAITS DE LA LICENCE Copyright CEA, contributeurs : Luc BILLARD et Damien CALISTE, laboratoire L_Sim, (2001-2005) Adresse mèl : BILLARD, non joignable par mèl ; CALISTE, damien P caliste AT cea P fr. Ce logiciel est un programme informatique servant à visualiser des structures atomiques dans un rendu pseudo-3D. Ce logiciel est régi par la licence CeCILL soumise au droit français et respectant les principes de diffusion des logiciels libres. Vous pouvez utiliser, modifier et/ou redistribuer ce programme sous les conditions de la licence CeCILL telle que diffusée par le CEA, le CNRS et l'INRIA sur le site "http://www.cecill.info". Le fait que vous puissiez accéder à cet en-tête signifie que vous avez pris connaissance de la licence CeCILL, et que vous en avez accepté les termes (cf. le fichier Documentation/licence.fr.txt fourni avec ce logiciel). */ /* LICENCE SUM UP Copyright CEA, contributors : Luc BILLARD et Damien CALISTE, laboratoire L_Sim, (2001-2005) E-mail address: BILLARD, not reachable any more ; CALISTE, damien P caliste AT cea P fr. This software is a computer program whose purpose is to visualize atomic configurations in 3D. This software is governed by the CeCILL license under French law and abiding by the rules of distribution of free software. You can use, modify and/ or redistribute the software under the terms of the CeCILL license as circulated by CEA, CNRS and INRIA at the following URL "http://www.cecill.info". The fact that you are presently reading this means that you have had knowledge of the CeCILL license and that you accept its terms. You can find a copy of this licence shipped with this software at Documentation/licence.en.txt. */ #include "visu_box.h" #include #include "visu_tools.h" #include "visu_data.h" /* To be removed! */ #include "iface_boxed.h" #include "iface_nodemasker.h" #include "coreTools/toolMatrix.h" /** * SECTION:visu_box * @short_description: Defines a bounding box. * * */ /* Local methods. */ static gfloat _getBoxExtens(const VisuBox *box, gboolean withExt); static void _setUpGeometry(VisuBox *box, gboolean emit); static void _setUpMatrixFromCell(VisuBox *box); /** * VisuBoxPrivate: * * Opaque structure to store private attributes of #VisuBox objects. */ struct _VisuBoxPrivate { gboolean dispose_has_run; /* The unit for length. */ ToolUnits units; /* The periodicity. */ VisuBoxBoundaries bc; /* The extension of the box. */ gboolean extActive; float extension[3]; /* This is the geometry of the box. Array position 1 to 6 correspond to xx, xy, yy, zx, zy and zz. */ double cell[6]; /* This is the origin in cartesian coordinates of the box origin. */ double origin[3]; /* The longest length in the box (with or without extension), and the margin to add. */ float extens[2], margin; /* Transformation matrices. */ /* This is the matrix that transform cartesian coordinates to coordinates in the box geometry. Use visu_data_convertXYZtoBoxCoordinates() to access this matrix. */ double fromXYZtoBox[3][3]; /* This is the matrix that transform box coordinates to cartesian coordinates. Use visu_data_convertBoxCoordinatestoXYZ() to access this matrix. */ double fromBoxtoXYZ[3][3]; /* This matrix is set up if the box was given in full [3][3] matrix and that cartesian coordinates need rotation before storing them. */ float fromFullToCell[3][3]; VisuBoxHiddingStatus hidding; }; enum { SIZE_CHANGED_SIGNAL, UNIT_CHANGED_SIGNAL, LAST_SIGNAL }; static guint signals[LAST_SIGNAL] = { 0 }; enum { PROP_0, UNITS_PROP, EXPAND_PROP, USE_EXPAND_PROP, BC_PROP, HIDDING_PROP, N_PROP, ADJUST_PROP, BOX_PROP }; static GParamSpec *properties[N_PROP]; static void visu_box_dispose (GObject* obj); static void visu_box_finalize (GObject* obj); static void visu_box_get_property(GObject* obj, guint property_id, GValue *value, GParamSpec *pspec); static void visu_box_set_property(GObject* obj, guint property_id, const GValue *value, GParamSpec *pspec); static void visu_boxed_interface_init(VisuBoxedInterface *iface); static void visu_node_masker_interface_init(VisuNodeMaskerInterface *iface); G_DEFINE_TYPE_WITH_CODE(VisuBox, visu_box, VISU_TYPE_OBJECT, G_ADD_PRIVATE(VisuBox) G_IMPLEMENT_INTERFACE(VISU_TYPE_NODE_MASKER, visu_node_masker_interface_init) G_IMPLEMENT_INTERFACE(VISU_TYPE_BOXED, visu_boxed_interface_init)) static VisuBox* _getBox(VisuBoxed *self); static gboolean _maskApply(const VisuNodeMasker *self, VisuNodeArray *array); static void visu_box_class_init(VisuBoxClass *klass) { DBG_fprintf(stderr, "Visu Box: creating the class of the object.\n"); DBG_fprintf(stderr, " - adding new signals ;\n"); /** * VisuBox::SizeChanged: * @box: the object which received the signal ; * @extens: the new longuest distance in the box taking into account * the extension. * * Gets emitted when the box size is changed (because of box * duplication for instance). * * Since: 3.7 */ signals[SIZE_CHANGED_SIGNAL] = g_signal_new("SizeChanged", G_TYPE_FROM_CLASS(klass), G_SIGNAL_RUN_LAST | G_SIGNAL_NO_RECURSE | G_SIGNAL_NO_HOOKS, 0, NULL, NULL, g_cclosure_marshal_VOID__FLOAT, G_TYPE_NONE, 1, G_TYPE_FLOAT, NULL); /** * VisuBox::UnitChanged: * @box: the object which received the signal ; * @factor: the factor that has been applied. * * Gets emitted when the units are changed. * * Since: 3.7 */ signals[UNIT_CHANGED_SIGNAL] = g_signal_new("UnitChanged", G_TYPE_FROM_CLASS(klass), G_SIGNAL_RUN_LAST | G_SIGNAL_NO_RECURSE | G_SIGNAL_NO_HOOKS, 0, NULL, NULL, g_cclosure_marshal_VOID__FLOAT, G_TYPE_NONE, 1, G_TYPE_FLOAT, NULL); /* Connect the overloading methods. */ G_OBJECT_CLASS(klass)->dispose = visu_box_dispose; G_OBJECT_CLASS(klass)->finalize = visu_box_finalize; G_OBJECT_CLASS(klass)->set_property = visu_box_set_property; G_OBJECT_CLASS(klass)->get_property = visu_box_get_property; /** * VisuBox::units: * * The units of the length dimensions. * * Since: 3.8 */ properties[UNITS_PROP] = g_param_spec_uint("units", "Units", "Units of dimensions", TOOL_UNITS_UNDEFINED, TOOL_UNITS_N_VALUES - 1, TOOL_UNITS_UNDEFINED, G_PARAM_READWRITE); /** * VisuBox::expansion: * * The expansion applied on [x,y,z] axis. * * Since: 3.8 */ properties[EXPAND_PROP] = g_param_spec_boxed("expansion", "Expansion on all axis", "Expanion on all axis", TOOL_TYPE_VECTOR, G_PARAM_READWRITE); /** * VisuBox::use-expansion: * * Wether the expansion is applied or not. * * Since: 3.8 */ properties[USE_EXPAND_PROP] = g_param_spec_boolean("use-expansion", "Use expansion", "Expanion is active or not", FALSE, G_PARAM_READWRITE); /** * VisuBox::boundary: * * The boundary conditions of the box. * * Since: 3.8 */ properties[BC_PROP] = g_param_spec_uint("boundary", "Boundary", "Boundary conditions", VISU_BOX_FREE, VISU_BOX_PERIODIC, VISU_BOX_PERIODIC, G_PARAM_READWRITE); /** * VisuBox::hidding-scheme: * * The hidding scheme used by the box, if any. * * Since: 3.8 */ properties[HIDDING_PROP] = g_param_spec_uint("hidding-scheme", "Hidding scheme", "hidding scheme used by the box.", VISU_BOX_HIDE_NONE, VISU_BOX_HIDE_INSIDE, VISU_BOX_HIDE_NONE, G_PARAM_READWRITE); g_object_class_install_properties(G_OBJECT_CLASS(klass), N_PROP, properties); g_object_class_override_property(G_OBJECT_CLASS(klass), ADJUST_PROP, "auto-adjust"); g_object_class_override_property(G_OBJECT_CLASS(klass), BOX_PROP, "box"); } static void visu_boxed_interface_init(VisuBoxedInterface *iface) { iface->get_box = _getBox; } static void visu_node_masker_interface_init(VisuNodeMaskerInterface *iface) { iface->apply = _maskApply; } static void visu_box_init(VisuBox *box) { guint i; DBG_fprintf(stderr, "Visu Box: initializing a new object (%p).\n", (gpointer)box); box->priv = visu_box_get_instance_private(box); box->priv->dispose_has_run = FALSE; box->priv->extActive = FALSE; for (i = 0; i < 3; i++) box->priv->extension[i] = 0.; for (i = 0; i < 6; i++) box->priv->cell[i] = G_MAXFLOAT; box->priv->origin[0] = 0.; box->priv->origin[1] = 0.; box->priv->origin[2] = 0.; box->priv->bc = VISU_BOX_FREE; box->priv->extens[0] = G_MAXFLOAT; box->priv->extens[1] = G_MAXFLOAT; box->priv->margin = G_MAXFLOAT; box->priv->fromFullToCell[0][0] = G_MAXFLOAT; box->priv->units = TOOL_UNITS_UNDEFINED; box->priv->hidding = VISU_BOX_HIDE_NONE; } /* This method can be called several times. It should unref all of its reference to GObjects. */ static void visu_box_dispose(GObject* obj) { VisuBox *box; DBG_fprintf(stderr, "Visu Box: dispose object %p.\n", (gpointer)obj); box = VISU_BOX(obj); if (box->priv->dispose_has_run) return; box->priv->dispose_has_run = TRUE; /* Chain up to the parent class */ G_OBJECT_CLASS(visu_box_parent_class)->dispose(obj); } /* This method is called once only. */ static void visu_box_finalize(GObject* obj) { /* VisuBoxPrivate *box; */ g_return_if_fail(obj); DBG_fprintf(stderr, "Visu Box: finalize object %p.\n", (gpointer)obj); /* box = VISU_BOX(obj)->priv; */ /* Chain up to the parent class */ DBG_fprintf(stderr, "Visu Box: chain to parent.\n"); G_OBJECT_CLASS(visu_box_parent_class)->finalize(obj); DBG_fprintf(stderr, "Visu Box: freeing ... OK.\n"); } static void visu_box_get_property(GObject* obj, guint property_id, GValue *value, GParamSpec *pspec) { VisuBox *self = VISU_BOX(obj); DBG_fprintf(stderr, "Visu Box: get property '%s'.\n", g_param_spec_get_name(pspec)); switch (property_id) { case BOX_PROP: g_value_set_object(value, obj); break; case UNITS_PROP: g_value_set_uint(value, self->priv->units); break; case USE_EXPAND_PROP: g_value_set_boolean(value, self->priv->extActive); break; case EXPAND_PROP: g_value_set_static_boxed(value, (gpointer)self->priv->extension); break; case BC_PROP: g_value_set_uint(value, self->priv->bc); break; case HIDDING_PROP: g_value_set_uint(value, self->priv->hidding); break; default: /* We don't have any other property... */ G_OBJECT_WARN_INVALID_PROPERTY_ID(obj, property_id, pspec); break; } } static void visu_box_set_property(GObject* obj, guint property_id, const GValue *value, GParamSpec *pspec) { VisuBox *self = VISU_BOX(obj); DBG_fprintf(stderr, "Visu Box: set property '%s'.\n", g_param_spec_get_name(pspec)); switch (property_id) { case UNITS_PROP: visu_box_setUnit(self, g_value_get_uint(value)); break; case USE_EXPAND_PROP: visu_box_setExtensionActive(self, g_value_get_boolean(value)); break; case EXPAND_PROP: visu_box_setExtension(self, (gfloat*)g_value_get_boxed(value)); break; case BC_PROP: visu_box_setBoundary(self, g_value_get_uint(value)); break; case HIDDING_PROP: visu_box_setHiddingStatus(self, g_value_get_uint(value)); break; default: /* We don't have any other property... */ G_OBJECT_WARN_INVALID_PROPERTY_ID(obj, property_id, pspec); break; } } /** * visu_box_new: * @geometry: (array fixed-size=6): a cell definition. * @bc: a boundary condition. * * A #VisuBox object store the definition of a cell. * * Since: 3.7 * * Returns: (transfer full): create a new #VisuBox object. **/ VisuBox* visu_box_new(double geometry[VISU_BOX_N_VECTORS], VisuBoxBoundaries bc) { VisuBox *box; DBG_fprintf(stderr, "Visu Box: create a new VisuBox object of type %d.\n", (int)VISU_TYPE_BOX); box = VISU_BOX(g_object_new(VISU_TYPE_BOX, NULL)); visu_box_setBoundary(box, bc); visu_box_setGeometry(box, geometry); return box; } /** * visu_box_new_full: * @full: (array fixed-size=9): a cell definition (full matrix). * @bc: a boundary condition. * * A #VisuBox object stores the definition of a cell. This may fail, * if @full does not define a 3D basis set (the three vectors are not * linearly independant). To check this, use visu_box_getGeometry() to * test if the first vector is #G_MAXFLOAT. * * Since: 3.7 * * Returns: (transfer full): create a new #VisuBox object. **/ VisuBox* visu_box_new_full(double full[3][3], VisuBoxBoundaries bc) { VisuBox *box; DBG_fprintf(stderr, "Visu Box: create a new VisuBox object of type %d.\n", (int)VISU_TYPE_BOX); box = VISU_BOX(g_object_new(VISU_TYPE_BOX, NULL)); visu_box_setBoundary(box, bc); visu_box_setGeometryFull(box, full); return box; } /** * visu_box_setBoundary: * @box: a #VisuBox object. * @bc: a boundary condition. * * Set up the boundary conditions of @box. * * Since: 3.7 * * Returns: TRUE if the boundary conditions of @box are changed. **/ gboolean visu_box_setBoundary(VisuBox *box, VisuBoxBoundaries bc) { g_return_val_if_fail(VISU_IS_BOX(box), FALSE); DBG_fprintf(stderr, "Visu Box: setting bounding box.\n"); if (box->priv->bc == bc) return FALSE; box->priv->bc = bc; DBG_fprintf(stderr, "Visu Box: emit 'BoundaryChanged'.\n"); g_object_notify_by_pspec(G_OBJECT(box), properties[BC_PROP]); DBG_fprintf(stderr, "Visu Box: emission done (BoundaryChanged).\n"); return TRUE; } /** * visu_box_getBoundary: * @box: a #VisuBox object. * * Get the boundary conditions defined for @box. * * Since: 3.7 * * Returns: a #VisuBoxBoundaries flag. */ VisuBoxBoundaries visu_box_getBoundary(VisuBox *box) { g_return_val_if_fail(VISU_IS_BOX(box), VISU_BOX_FREE); return box->priv->bc; } /** * visu_box_getPeriodicity: * @box: a #VisuBox object. * @per: (out caller-allocates) (array fixed-size=3): a location to * store three periodicties. * * Get for each {x, y, z} directions if the @box is periodic. * * Since: 3.7 */ void visu_box_getPeriodicity(VisuBox *box, gboolean per[3]) { g_return_if_fail(VISU_IS_BOX(box)); per[0] = box->priv->bc & TOOL_XYZ_MASK_X; per[1] = box->priv->bc & TOOL_XYZ_MASK_Y; per[2] = box->priv->bc & TOOL_XYZ_MASK_Z; } /** * visu_box_setOrigin: * @box: a #VisuBox orbject. * @orig: (array fixed-size=3): the new origin * * Change the origin of @box. * * Since: 3.8 * * Returns: TRUE if origin is indeed changed. **/ gboolean visu_box_setOrigin(VisuBox *box, const float orig[3]) { g_return_val_if_fail(VISU_IS_BOX(box), FALSE); if (orig[0] == box->priv->origin[0] && orig[1] == box->priv->origin[1] && orig[2] == box->priv->origin[2]) return FALSE; box->priv->origin[0] = orig[0]; box->priv->origin[1] = orig[1]; box->priv->origin[2] = orig[2]; return TRUE; } /** * visu_box_setGeometryFull: * @box: a #VisuBox object. * @full: a matrix defining a basis-set. * * As visu_box_setGeometry(), but using a full matrix. * * Since: 3.7 * * Returns: TRUE if the geometry is valid and changed. **/ gboolean visu_box_setGeometryFull(VisuBox *box, double full[3][3]) { double geometry[VISU_BOX_N_VECTORS]; if (tool_matrix_reducePrimitiveVectors(geometry, full)) { tool_matrix_getRotationFromFull(box->priv->fromFullToCell, full, geometry); visu_box_setGeometry(box, geometry); return TRUE; } return FALSE; } /** * visu_box_setGeometry: * @box: a #VisuBox object ; * @geometry: (in) (array fixed-size=6):a 6 floating point array ; * * This methods set the size of the box. * * Returns: TRUE if the geometry is indeed changed. * * Since: 3.7 */ gboolean visu_box_setGeometry(VisuBox *box, double geometry[VISU_BOX_N_VECTORS]) { int i; g_return_val_if_fail(VISU_IS_BOX(box), FALSE); for (i = 0; i < VISU_BOX_N_VECTORS; i++) box->priv->cell[i] = geometry[i]; _setUpGeometry(box, TRUE); return TRUE; } /** * visu_box_getGeometry: * @box: a #VisuBox object ; * @vector: an int corresponding to a vector of the box. * * Retrieve the value of a vector defining the bounding box. The vector * is chosen with an int, see the #VisuBoxVector enum for more * details. * * Since: 3.7 * * Returns: the value of the required vector (always a positive value * for vector = 0, 2 or 5 !), or G_MAXFLOAT if the box has not been initialised. */ double visu_box_getGeometry(VisuBox *box, VisuBoxVector vector) { g_return_val_if_fail(VISU_IS_BOX(box) && vector < VISU_BOX_N_VECTORS, G_MAXFLOAT); return (float)box->priv->cell[vector]; } static void _setUpGeometry(VisuBox *box, gboolean emit) { DBG_fprintf(stderr, "Visu Box: the bounding box is set to:\n %f %f %f\n %f %f %f\n", box->priv->cell[0], box->priv->cell[1], box->priv->cell[2], box->priv->cell[3], box->priv->cell[4], box->priv->cell[5]); _setUpMatrixFromCell(box); box->priv->extens[0] = _getBoxExtens(box, FALSE); box->priv->extens[1] = _getBoxExtens(box, TRUE); DBG_fprintf(stderr, "Visu Box: set box geometry done (%g %g).\n", box->priv->extens[0], box->priv->extens[1]); if (box->priv->cell[0] != G_MAXFLOAT && box->priv->margin != G_MAXFLOAT && emit) { DBG_fprintf(stderr, "Visu Box: emit SizeChanged.\n"); g_signal_emit(box, signals[SIZE_CHANGED_SIGNAL], 0, box->priv->extens[1] + box->priv->margin, NULL); DBG_fprintf(stderr, "Visu Box: emission done (SizeChanged).\n"); } } static void _setUpMatrixFromCell(VisuBox *box) { /* Create the transformation matrix. */ box->priv->fromXYZtoBox[0][0] = 1. / box->priv->cell[VISU_BOX_DXX]; box->priv->fromXYZtoBox[0][1] = - box->priv->cell[VISU_BOX_DYX] / box->priv->cell[VISU_BOX_DXX] / box->priv->cell[VISU_BOX_DYY]; box->priv->fromXYZtoBox[0][2] = - (box->priv->cell[VISU_BOX_DZX] / box->priv->cell[VISU_BOX_DXX] - box->priv->cell[VISU_BOX_DYX] * box->priv->cell[VISU_BOX_DZY] / box->priv->cell[VISU_BOX_DXX] / box->priv->cell[VISU_BOX_DYY] ) / box->priv->cell[VISU_BOX_DZZ]; box->priv->fromXYZtoBox[1][0] = 0.; box->priv->fromXYZtoBox[1][1] = 1. / box->priv->cell[VISU_BOX_DYY]; box->priv->fromXYZtoBox[1][2] = - box->priv->cell[VISU_BOX_DZY] / box->priv->cell[VISU_BOX_DYY] / box->priv->cell[VISU_BOX_DZZ]; box->priv->fromXYZtoBox[2][0] = 0.; box->priv->fromXYZtoBox[2][1] = 0.; box->priv->fromXYZtoBox[2][2] = 1. / box->priv->cell[VISU_BOX_DZZ]; box->priv->fromBoxtoXYZ[0][0] = box->priv->cell[VISU_BOX_DXX]; box->priv->fromBoxtoXYZ[0][1] = box->priv->cell[VISU_BOX_DYX]; box->priv->fromBoxtoXYZ[0][2] = box->priv->cell[VISU_BOX_DZX]; box->priv->fromBoxtoXYZ[1][0] = 0.; box->priv->fromBoxtoXYZ[1][1] = box->priv->cell[VISU_BOX_DYY]; box->priv->fromBoxtoXYZ[1][2] = box->priv->cell[VISU_BOX_DZY]; box->priv->fromBoxtoXYZ[2][0] = 0.; box->priv->fromBoxtoXYZ[2][1] = 0.; box->priv->fromBoxtoXYZ[2][2] = box->priv->cell[VISU_BOX_DZZ]; } static gfloat _getBoxExtens(const VisuBox *box, gboolean withExt) { float dz2, dy2, dx, dy, dz, su, sc; float geometry[VISU_BOX_N_VECTORS]; /* calculate bare = 1/2 radius of centered sample */ geometry[VISU_BOX_DXX] = (withExt && box->priv->extActive)?box->priv->cell[VISU_BOX_DXX] * (1. + 2. * box->priv->extension[0]):box->priv->cell[VISU_BOX_DXX]; geometry[VISU_BOX_DYX] = (withExt && box->priv->extActive)?box->priv->cell[VISU_BOX_DYX] * (1. + 2. * box->priv->extension[1]):box->priv->cell[VISU_BOX_DYX]; geometry[VISU_BOX_DZX] = (withExt && box->priv->extActive)?box->priv->cell[VISU_BOX_DZX] * (1. + 2. * box->priv->extension[2]):box->priv->cell[VISU_BOX_DZX]; geometry[VISU_BOX_DYY] = (withExt && box->priv->extActive)?box->priv->cell[VISU_BOX_DYY] * (1. + 2. * box->priv->extension[1]):box->priv->cell[VISU_BOX_DYY]; geometry[VISU_BOX_DZY] = (withExt && box->priv->extActive)?box->priv->cell[VISU_BOX_DZY] * (1. + 2. * box->priv->extension[2]):box->priv->cell[VISU_BOX_DZY]; geometry[VISU_BOX_DZZ] = (withExt && box->priv->extActive)?box->priv->cell[VISU_BOX_DZZ] * (1. + 2. * box->priv->extension[2]):box->priv->cell[VISU_BOX_DZZ]; dz = geometry[VISU_BOX_DZZ]; dz2 = dz * dz; dy = (geometry[VISU_BOX_DYY] + geometry[VISU_BOX_DZY]); dy2 = dy * dy; dx = (geometry[VISU_BOX_DXX] + geometry[VISU_BOX_DYX] + geometry[VISU_BOX_DZX]); su = dx * dx + dy2 + dz2; dx = (-geometry[VISU_BOX_DXX] + geometry[VISU_BOX_DYX] + geometry[VISU_BOX_DZX]); sc = dx * dx + dy2 + dz2; if (sc > su) su = sc; dx = (geometry[VISU_BOX_DXX] - geometry[VISU_BOX_DYX] + geometry[VISU_BOX_DZX]); dy = (geometry[VISU_BOX_DYY] - geometry[VISU_BOX_DZY]); dy2 = dy * dy; sc = dx * dx + dy2 + dz2; if (sc > su) su = sc; dx = (geometry[VISU_BOX_DXX] + geometry[VISU_BOX_DYX] - geometry[VISU_BOX_DZX]); sc = dx * dx + dy2 + dz2; if (sc > su) su = sc; return sqrt(su) * 0.5f; } /** * visu_box_setMargin: * @box: a #VisuBox object. * @margin: a float value. * @emit: TRUE to emit #VisuBox::SizeChanged signal. * * This routine add some margin to defined the OpenGL rendering zone * of @box. * * Since: 3.7 * * Returns: TRUE if the margin is actually changed. **/ gboolean visu_box_setMargin(VisuBox *box, gfloat margin, gboolean emit) { g_return_val_if_fail(VISU_IS_BOX(box), FALSE); if (margin < 0.f || margin == box->priv->margin) return FALSE; DBG_fprintf(stderr, "Visu Box: set margin to %g (was %g).\n", margin, box->priv->margin); box->priv->margin = margin; if (box->priv->cell[0] != G_MAXFLOAT && box->priv->margin != G_MAXFLOAT && emit) { DBG_fprintf(stderr, "Visu Box: emit SizeChanged.\n"); g_signal_emit(box, signals[SIZE_CHANGED_SIGNAL], 0, box->priv->extens[1] + box->priv->margin, NULL); DBG_fprintf(stderr, "Visu Box: emission done (SizeChanged).\n"); } return TRUE; } /** * visu_box_getCentre: * @box: a #VisuBox object ; * @centre: (out) (array fixed-size=3): coordinates of the centre. * * @centre contains on output the cartesian coordinates of the centre * of the bounding box. * * Since: 3.7 */ void visu_box_getCentre(VisuBox *box, float centre[3]) { g_return_if_fail(VISU_IS_BOX(box)); centre[0] = box->priv->origin[0] + 0.5f * (box->priv->cell[VISU_BOX_DXX] + box->priv->cell[VISU_BOX_DYX] + box->priv->cell[VISU_BOX_DZX]); centre[1] = box->priv->origin[1] + 0.5f * (box->priv->cell[VISU_BOX_DYY] + box->priv->cell[VISU_BOX_DZY]); centre[2] = box->priv->origin[2] + 0.5f * (box->priv->cell[VISU_BOX_DZZ]); } /** * visu_box_convertFullToCell: * @box: a #VisuBox object. * @cell: (out caller-allocates) (array fixed-size=3): * @full: (in) (array fixed-size=3): * * Convert given cartesian coordinates of a full matrix definition * (see visu_box_setGeometryFull()) to cartesian coordinates in the * cell definition used by V_Sim. It corresponds to two applied rotations. * * Since: 3.7 */ void visu_box_convertFullToCell(VisuBox *box, float cell[3], float full[3]) { g_return_if_fail(VISU_IS_BOX(box)); if (box->priv->fromFullToCell[0][0] != G_MAXFLOAT) tool_matrix_productVector(cell, box->priv->fromFullToCell, full); else { cell[0] = full[0]; cell[1] = full[1]; cell[2] = full[2]; } } /** * visu_box_convertXYZtoBoxCoordinates: (skip) * @box: a #VisuBox object ; * @boxCoord:an array of floating point values to store the result ; * @xyz: an array of floating point values describing coordinates in cartesian. * * Use this method to transform cartesian coordinates to the box * coordinates. * * Since: 3.7 */ void visu_box_convertXYZtoBoxCoordinates(const VisuBox *box, float boxCoord[3], float xyz[3]) { int i, j; g_return_if_fail(VISU_IS_BOX(box) && boxCoord && xyz); for (i = 0; i < 3; i++) { boxCoord[i] = 0.; for (j = 0; j < 3; j++) boxCoord[i] += (float)box->priv->fromXYZtoBox[i][j] * (xyz[j] - box->priv->origin[j]); } } /** * visu_box_convertXYZToReduced: * @box: a #VisuBox object ; * @xyz: (in) (array fixed-size=3) (element-type gfloat): floating * point values that describes the cartesian coordinates. * @u: (out caller-allocates): the x coordinate. * @v: (out caller-allocates): the y coordinate. * @w: (out caller-allocates): the z coordinate. * * Use this method to transform cartesian into box coordinates. * * Since: 3.7 */ void visu_box_convertXYZToReduced(VisuBox *box, GArray *xyz, float *u, float *v, float *w) { float red_[3]; g_return_if_fail(xyz && u && v && w && xyz->len == 3); visu_box_convertXYZtoBoxCoordinates(box, red_, (float*)xyz->data); *u = red_[0]; *v = red_[1]; *w = red_[2]; } /** * visu_box_convertBoxCoordinatestoXYZ: (skip) * @box: a #VisuBox object ; * @xyz: an array of floating point values to store the result ; * @boxCoord: an array of floating point values that describes the box coordinates. * * Use this method to transform box coordinates into cartesian. * * Since: 3.7 */ void visu_box_convertBoxCoordinatestoXYZ(VisuBox *box, float xyz[3], const float boxCoord[3]) { int i, j; g_return_if_fail(VISU_IS_BOX(box) && boxCoord && xyz); for (i = 0; i < 3; i++) { xyz[i] = box->priv->origin[i]; for (j = 0; j < 3; j++) xyz[i] += (float)box->priv->fromBoxtoXYZ[i][j] * boxCoord[j]; } } /** * visu_box_convertReducedToXYZ: * @box: a #VisuBox object ; * @red: (in) (array fixed-size=3) (element-type gfloat): floating * point values that describes the cartesian coordinates. * @x: (out caller-allocates): the x coordinate. * @y: (out caller-allocates): the y coordinate. * @z: (out caller-allocates): the z coordinate. * * Use this method to transform box coordinates into cartesian. * * Since: 3.7 */ void visu_box_convertReducedToXYZ(VisuBox *box, GArray *red, float *x, float *y, float *z) { float xyz_[3]; g_return_if_fail(red && x && y && z && red->len == 3); visu_box_convertBoxCoordinatestoXYZ(box, xyz_, (float*)red->data); *x = xyz_[0]; *y = xyz_[1]; *z = xyz_[2]; } /** * visu_box_getInvMatrix: (skip) * @box: a #VisuBox object ; * @matrix: an area to store the matrix. * * This method is used when the inverse box matrix is required. This matrix can transform * a vector given in cartesian coordinates into a box vector. If a simple vector * multication is required, then the use of visu_box_convertXYZtoBoxCoordinates() * should be prefered. * * Since: 3.7 */ void visu_box_getInvMatrix(VisuBox *box, double matrix[3][3]) { int i, j; g_return_if_fail(VISU_IS_BOX(box) && matrix); /* Mind the transposition here. */ for (i = 0; i < 3; i++) for (j = 0; j < 3; j++) matrix[i][j] = box->priv->fromXYZtoBox[i][j]; } /** * visu_box_getCellMatrix: (skip) * @box: a #VisuBox object ; * @matrix: an area to store the matrix. * * This method is used when the box matrix is required. This matrix can transform * a vector given in box coordinates into a cartesian vector. If a simple vector * multication is required, then the use of visu_box_convertBoxCoordinatestoXYZ() * should be prefered. * * Since: 3.7 */ void visu_box_getCellMatrix(VisuBox *box, double matrix[3][3]) { int i, j; g_return_if_fail(VISU_IS_BOX(box) && matrix); /* Mind the transposition here. */ for (i = 0; i < 3; i++) for (j = 0; j < 3; j++) matrix[i][j] = box->priv->fromBoxtoXYZ[i][j]; } /** * visu_box_getCellMatrixv: * @box: a #VisuBox object ; * @m11: (out): an area to store the matrix. * @m12: (out): an area to store the matrix. * @m13: (out): an area to store the matrix. * @m21: (out): an area to store the matrix. * @m22: (out): an area to store the matrix. * @m23: (out): an area to store the matrix. * @m31: (out): an area to store the matrix. * @m32: (out): an area to store the matrix. * @m33: (out): an area to store the matrix. * * This method is a binding method for visu_box_getCellMatrix(). * * Since: 3.7 */ void visu_box_getCellMatrixv(VisuBox *box, double *m11, double *m12, double *m13, double *m21, double *m22, double *m23, double *m31, double *m32, double *m33) { double m[3][3]; g_return_if_fail(m11 && m12 && m13 && m21 && m22 && m23 && m31 && m32 && m33); visu_box_getCellMatrix(box, m); *m11 = m[0][0]; *m12 = m[0][1]; *m13 = m[0][2]; *m21 = m[1][0]; *m22 = m[1][1]; *m23 = m[1][2]; *m31 = m[2][0]; *m32 = m[2][1]; *m33 = m[2][2]; } /** * visu_box_constrainInside: * @box: a #VisuBox object. * @translat: a translation in cartesian coordinates (out values). * @xyz: a set of cartesian coordinates. * @withExt: TRUE to take into account the box expansions. * * Given the box defintion @box and the initial @xyz cartesian coordinates, it * returns the translation @translat to be applied to @xyz to move the * node into the box. * * Since: 3.7 * * Returns: TRUE if @translat is not (0;0;0). */ gboolean visu_box_constrainInside(VisuBox *box, float translat[3], float xyz[3], gboolean withExt) { float boxCoord[3], bounds[3], size[3]; gboolean moved; int k; if (withExt && box->priv->extActive) { bounds[0] = ceil(box->priv->extension[0]); bounds[1] = ceil(box->priv->extension[1]); bounds[2] = ceil(box->priv->extension[2]); } else { bounds[0] = 0.f; bounds[1] = 0.f; bounds[2] = 0.f; } size[0] = 1. + 2. * bounds[0]; size[1] = 1. + 2. * bounds[1]; size[2] = 1. + 2. * bounds[2]; visu_box_convertXYZtoBoxCoordinates(box, boxCoord, xyz); moved = FALSE; for (k = 0; k < 3; k++) { while (boxCoord[k] < - bounds[k]) { moved = TRUE; boxCoord[k] += size[k]; } while (boxCoord[k] >= 1. + bounds[k]) { moved = TRUE; boxCoord[k] -= size[k]; } } if (moved) { visu_box_convertBoxCoordinatestoXYZ(box, translat, boxCoord); translat[0] -= xyz[0]; translat[1] -= xyz[1]; translat[2] -= xyz[2]; DBG_fprintf(stderr, "Tool Matrix: move coord. from %gx%gx%g to %gx%gx%g.\n", xyz[0], xyz[1], xyz[2], boxCoord[0], boxCoord[1], boxCoord[2]); } else { translat[0] = 0.f; translat[1] = 0.f; translat[2] = 0.f; } return moved; } /** * visu_box_getVertices: * @box: a #VisuBox object. * @v: (out caller-allocates) (type VisuBoxVertices*): the position of * the eight vertices of the bounding box. * @withExtension: a boolean. * * All nodes are rendered inside a bounding box, this method can be used to retrieve * it. This box is not the drawn box but the box containing all the * nodes, included possible extension. To get the box itself, use * visu_box_getCellMatrix() instead. One can also get the vertices of * the box itself using FALSE as @withExtension argument. */ void visu_box_getVertices(VisuBox *box, float v[8][3], gboolean withExtension) { int i; float transX[3], transY[3], transZ[3], ext[3]; double *boxGeometry; g_return_if_fail(VISU_IS_BOX(box)); if (withExtension && box->priv->extActive) { ext[0] = box->priv->extension[0]; ext[1] = box->priv->extension[1]; ext[2] = box->priv->extension[2]; } else { ext[0] = 0.f; ext[1] = 0.f; ext[2] = 0.f; } DBG_fprintf(stderr, "Visu Box: get the box vertices with" " extension %d (%g;%g;%g).\n", withExtension, ext[0], ext[1], ext[2]); boxGeometry = box->priv->cell; transX[0] = ext[0] * boxGeometry[0]; transX[1] = 0.f; transX[2] = 0.f; transY[0] = ext[1] * boxGeometry[1]; transY[1] = ext[1] * boxGeometry[2]; transY[2] = 0.f; transZ[0] = ext[2] * boxGeometry[3]; transZ[1] = ext[2] * boxGeometry[4]; transZ[2] = ext[2] * boxGeometry[5]; /* [0;0;0] */ DBG_fprintf(stderr, " | v is %p.\n", (gpointer)v); DBG_fprintf(stderr, " | v[0] is %p.\n", (gpointer)v[0]); v[0][0] = 0.f - transX[0] - transY[0] - transZ[0]; v[0][1] = 0.f - transX[1] - transY[1] - transZ[1]; v[0][2] = 0.f - transX[2] - transY[2] - transZ[2]; /* [1;0;0] */ DBG_fprintf(stderr, " | v[1] is %p.\n", (gpointer)v[1]); v[1][0] = boxGeometry[0] + transX[0] - transY[0] - transZ[0]; v[1][1] = 0.f + transX[1] - transY[1] - transZ[1]; v[1][2] = 0.f + transX[2] - transY[2] - transZ[2]; /* [0;1;0] */ DBG_fprintf(stderr, " | v[3] is %p.\n", (gpointer)v[3]); v[3][0] = boxGeometry[1] - transX[0] + transY[0] - transZ[0]; v[3][1] = boxGeometry[2] - transX[1] + transY[1] - transZ[1]; v[3][2] = 0.f - transX[2] + transY[2] - transZ[2]; /* [0;0;1] */ DBG_fprintf(stderr, " | v[4] is %p.\n", (gpointer)v[4]); v[4][0] = boxGeometry[3] - transX[0] - transY[0] + transZ[0]; v[4][1] = boxGeometry[4] - transX[1] - transY[1] + transZ[1]; v[4][2] = boxGeometry[5] - transX[2] - transY[2] + transZ[2]; /* [1;1;0] */ v[2][0] = boxGeometry[0] + boxGeometry[1] + transX[0] + transY[0] - transZ[0]; v[2][1] = 0.f + boxGeometry[2] + transX[1] + transY[1] - transZ[1]; v[2][2] = 0.f + 0.f + transX[2] + transY[2] - transZ[2]; /* [1;0;1] */ v[5][0] = boxGeometry[3] + boxGeometry[0] + transX[0] - transY[0] + transZ[0]; v[5][1] = boxGeometry[4] + 0.f + transX[1] - transY[1] + transZ[1]; v[5][2] = boxGeometry[5] + 0.f + transX[2] - transY[2] + transZ[2]; /* [1;1;1] */ v[6][0] = boxGeometry[3] + boxGeometry[0] + boxGeometry[1] + transX[0] + transY[0] + transZ[0]; v[6][1] = boxGeometry[4] + boxGeometry[2] + transX[1] + transY[1] + transZ[1]; v[6][2] = boxGeometry[5] + 0.f + transX[2] + transY[2] + transZ[2]; /* [0;1;1] */ v[7][0] = boxGeometry[3] + boxGeometry[1] - transX[0] + transY[0] + transZ[0]; v[7][1] = boxGeometry[4] + boxGeometry[2] - transX[1] + transY[1] + transZ[1]; v[7][2] = boxGeometry[5] + 0.f - transX[2] + transY[2] + transZ[2]; for (i = 0; i < 8; i++) { v[i][0] += box->priv->origin[0]; v[i][1] += box->priv->origin[1]; v[i][2] += box->priv->origin[2]; } DBG_fprintf(stderr, " | done.\n"); } /** * visu_box_getExtensionActive: * @box: a #VisuBox object. * * Retrieve if extensions are applied or not. * * Since: 3.8 * * Returns: TRUE if extensions are applied. **/ gboolean visu_box_getExtensionActive(VisuBox *box) { g_return_val_if_fail(VISU_IS_BOX(box), FALSE); return box->priv->extActive; } /** * visu_box_setExtensionActive: * @box: a #VisuBox object. * @status: a boolean. * * Change if extension values are used not not. * * Since: 3.8 * * Returns: TRUE if status has changed. **/ gboolean visu_box_setExtensionActive(VisuBox *box, gboolean status) { float oldExtens; g_return_val_if_fail(VISU_IS_BOX(box), FALSE); if (box->priv->extActive == status) return FALSE; box->priv->extActive = status; g_object_notify_by_pspec(G_OBJECT(box), properties[USE_EXPAND_PROP]); oldExtens = box->priv->extens[1]; box->priv->extens[1] = _getBoxExtens(box, TRUE); if (box->priv->cell[0] != G_MAXFLOAT && box->priv->margin != G_MAXFLOAT && box->priv->extens[1] != oldExtens) { DBG_fprintf(stderr, "Visu Box: emit SizeChanged.\n"); g_signal_emit(box, signals[SIZE_CHANGED_SIGNAL], 0, box->priv->extens[1] + box->priv->margin, NULL); DBG_fprintf(stderr, "Visu Box: emission done (SizeChanged).\n"); } return TRUE; } /** * visu_box_getExtension: * @boxObj: a #VisuBox object ; * @extension: (out) (array fixed-size=3): an allocated array to store the values. * * Using visu_box_setExtension(), it is possible to duplicate the primitive box * in each directions. Use this method to know the current extension. Returned * values are positive floating point values. An extension of 0. means that * only the primitive box exists, while a value of one means a duplication of * one box in each direction of the coordinate. * * Since: 3.7 */ void visu_box_getExtension(const VisuBox *boxObj, float extension[3]) { g_return_if_fail(VISU_IS_BOX(boxObj)); extension[0] = boxObj->priv->extension[0]; extension[1] = boxObj->priv->extension[1]; extension[2] = boxObj->priv->extension[2]; } /** * visu_box_setExtension: * @boxObj: a #VisuBox object ; * @extension: (in) (array fixed-size=3): an allocated array to store the values. * * Change the duplication of the box in the three directions. * * Since: 3.7 * * Returns: TRUE if the extension of @box is actually changed. */ gboolean visu_box_setExtension(VisuBox *boxObj, float extension[3]) { float oldExtens; g_return_val_if_fail(VISU_IS_BOX(boxObj), FALSE); if (extension[0] == boxObj->priv->extension[0] && extension[1] == boxObj->priv->extension[1] && extension[2] == boxObj->priv->extension[2]) return FALSE; boxObj->priv->extension[0] = extension[0]; boxObj->priv->extension[1] = extension[1]; boxObj->priv->extension[2] = extension[2]; DBG_fprintf(stderr, "Visu Box: emit ExtensionChanged.\n"); g_object_notify_by_pspec(G_OBJECT(boxObj), properties[EXPAND_PROP]); DBG_fprintf(stderr, "Visu Box: emission done (ExtensionChanged).\n"); oldExtens = boxObj->priv->extens[1]; boxObj->priv->extens[1] = _getBoxExtens(boxObj, TRUE); if (boxObj->priv->cell[0] != G_MAXFLOAT && boxObj->priv->margin != G_MAXFLOAT && boxObj->priv->extens[1] != oldExtens) { DBG_fprintf(stderr, "Visu Box: emit SizeChanged.\n"); g_signal_emit(boxObj, signals[SIZE_CHANGED_SIGNAL], 0, boxObj->priv->extens[1] + boxObj->priv->margin, NULL); DBG_fprintf(stderr, "Visu Box: emission done (SizeChanged).\n"); } return TRUE; } /** * visu_box_getGlobalSize: * @box: a #VisuBox object. * @withExt: a boolean. * * The box has a whole size that contains it (including margin, see * visu_box_setMargin()), this size can be retrieve taking into * account the extension of the box, or not. * * Since: 3.7 * * Returns: %G_MAXFLOAT on failure, otherwise a length for the biggest * diagonal distance of the box, with or without extension. **/ float visu_box_getGlobalSize(VisuBox *box, gboolean withExt) { g_return_val_if_fail(VISU_IS_BOX(box), G_MAXFLOAT); if (withExt) return box->priv->extens[1] + box->priv->margin; else return box->priv->extens[0]; } /** * visu_box_getUnit: * @box: a #VisuBox object. * * The lengths of @box may be given in a certain unit using * visu_box_setUnit(). * * Since: 3.7 * * Returns: the #ToolUnits of @box or #TOOL_UNITS_UNDEFINED. */ ToolUnits visu_box_getUnit(VisuBox *box) { g_return_val_if_fail(VISU_IS_BOX(box), TOOL_UNITS_UNDEFINED); return box->priv->units; } /** * visu_box_setUnit: * @box: a #VisuBox object. * @unit: a #ToolUnits flag. * * The lengths of @box may be given in a certain unit by calling this * routine. If the unit is different from the previously defined, the * coordinate are scaled accordingly. * * Since: 3.7 * * Returns: TRUE if the unit has been changed. */ gboolean visu_box_setUnit(VisuBox *box, ToolUnits unit) { ToolUnits unit_; double fact; g_return_val_if_fail(VISU_IS_BOX(box), FALSE); DBG_fprintf(stderr, "Visu Box: set unit to %d (%d).\n", unit, box->priv->units); if (box->priv->units == unit) return FALSE; unit_ = box->priv->units; box->priv->units = unit; g_object_notify_by_pspec(G_OBJECT(box), properties[UNITS_PROP]); if (unit_ == TOOL_UNITS_UNDEFINED || unit == TOOL_UNITS_UNDEFINED) { DBG_fprintf(stderr, "Visu Box: emit UnitChanged.\n"); g_signal_emit(box, signals[UNIT_CHANGED_SIGNAL], 0, 1.f); DBG_fprintf(stderr, "Visu Box: emission done (UnitChanged).\n"); return TRUE; } fact = (double)tool_physic_getUnitValueInMeter(unit_) / tool_physic_getUnitValueInMeter(unit); DBG_fprintf(stderr, "Visu Box: multiplying factor is %g.\n", fact); /* We do an homothety on the box. */ box->priv->cell[0] *= fact; box->priv->cell[1] *= fact; box->priv->cell[2] *= fact; box->priv->cell[3] *= fact; box->priv->cell[4] *= fact; box->priv->cell[5] *= fact; _setUpGeometry(box, FALSE); DBG_fprintf(stderr, "Visu Box: emit UnitChanged.\n"); g_signal_emit(box, signals[UNIT_CHANGED_SIGNAL], 0, fact); DBG_fprintf(stderr, "Visu Box: emission done (UnitChanged).\n"); if (box->priv->cell[0] != G_MAXFLOAT && box->priv->margin != G_MAXFLOAT) { DBG_fprintf(stderr, "Visu Box: emit SizeChanged.\n"); box->priv->margin *= fact; g_signal_emit(box, signals[SIZE_CHANGED_SIGNAL], 0, box->priv->extens[1] + box->priv->margin); DBG_fprintf(stderr, "Visu Box: emission done (SizeChanged).\n"); } return TRUE; } /** * visu_box_getInside: * @box: a #VisuBox object. * @vect: (array fixed-size=3) (inout): some cartesian coordinates. * @ratio: a ratio in [0;1]. * * Update @vect, taking into consideration the particular periodicity * of @box, for @vect expressed in reduced coordinates to be within * [-ratio;ratio]. * * Since: 3.8 * * Returns: TRUE if vect is actually changed. **/ gboolean visu_box_getInside(VisuBox *box, float vect[3], float ratio) { int i, j; float red[3]; VisuBoxBoundaries bc; gboolean mod; g_return_val_if_fail(VISU_IS_BOX(box), FALSE); mod = FALSE; bc = box->priv->bc; if (bc == VISU_BOX_FREE) return mod; /* DBG_fprintf(stderr, "Visu Box: transform %gx%gx%g into", red[0], red[1], red[2]); */ red[0] = 0.; for (j = 0; j < 3; j++) red[0] += (float)box->priv->fromXYZtoBox[0][j] * vect[j]; if (bc & TOOL_XYZ_MASK_X) { mod = (red[0] < -ratio || red[0] >= ratio); while (red[0] >= ratio) red[0] -= 1.f; while (red[0] < -ratio) red[0] += 1.f; } red[1] = 0.; for (j = 0; j < 3; j++) red[1] += (float)box->priv->fromXYZtoBox[1][j] * vect[j]; if (bc & TOOL_XYZ_MASK_Y) { mod = mod || (red[1] < -ratio || red[1] >= ratio); while (red[1] >= ratio) red[1] -= 1.f; while (red[1] < -ratio) red[1] += 1.f; } red[2] = 0.; for (j = 0; j < 3; j++) red[2] += (float)box->priv->fromXYZtoBox[2][j] * vect[j]; if (bc & TOOL_XYZ_MASK_Z) { mod = mod || (red[2] < -ratio || red[2] >= ratio); while (red[2] >= ratio) red[2] -= 1.f; while (red[2] < -ratio) red[2] += 1.f; } /* DBG_fprintf(stderr, " %gx%gx%g.\n", red[0], red[1], red[2]); */ for (i = 0; i < 3; i++) { vect[i] = 0.f; for (j = 0; j < 3; j++) vect[i] += (float)box->priv->fromBoxtoXYZ[i][j] * red[j]; } return mod; } /** * visu_box_getPeriodicVector: (skip) * @box: a #VisuBox object. * @vect: (inout) (array fixed-size=3): a vector. * * Modify @vect to get the shortest equivalent vector, taking into * account the periodicity. * * Since: 3.7 * * Returns: %TRUE if @vect has been modified. **/ gboolean visu_box_getPeriodicVector(VisuBox *box, float vect[3]) { return visu_box_getInside(box, vect, 0.5f); } /** * visu_box_getPeriodicVectorv: (rename-to visu_box_getPeriodicVector) * @box: a #VisuBox object. * @x: (out): the new x part. * @y: (out): the new y part. * @z: (out): the new z part. * @vect: (array fixed-size=3): a vector. * * Equivalent of visu_box_getPeriodicVector() used for bindings. * * Since: 3.7 **/ void visu_box_getPeriodicVectorv(VisuBox *box, float *x, float *y, float *z, float vect[3]) { g_return_if_fail(x && y && z); visu_box_getInside(box, vect, 0.5f); *x = vect[0]; *y = vect[1]; *z = vect[2]; } /** * visu_box_getPeriodicArray: * @box: a #VisuBox object. * @array: (type gint64): an array of @nEle * 3 floats. * @nEle: number of elements in @array * * Used for bindings. * * Since: 3.7 **/ void visu_box_getPeriodicArray(VisuBox *box, float *array, guint nEle) { guint i; DBG_fprintf(stderr, "Visu Box: apply periodic distance on array %p (%d).\n", (gpointer)array, nEle); for (i = 0; i < nEle; i++) visu_box_getPeriodicVector(box, array + i * 3); DBG_fprintf(stderr, " | done.\n"); } /** * visu_box_getHiddingStatus: * @box: a #VisuBox object. * * Retrieves the masking status of @box. * * Since: 3.8 * * Returns: the current masking status. **/ VisuBoxHiddingStatus visu_box_getHiddingStatus(const VisuBox *box) { g_return_val_if_fail(VISU_IS_BOX(box), VISU_BOX_HIDE_NONE); return box->priv->hidding; } /** * visu_box_setHiddingStatus: * @box: a #VisuBox object. * @status: a status. * * Changes the masking status of @box for @status. * * Since: 3.8 * * Returns: TRUE if the status is actually changed. **/ gboolean visu_box_setHiddingStatus(VisuBox *box, VisuBoxHiddingStatus status) { g_return_val_if_fail(VISU_IS_BOX(box), FALSE); if (box->priv->hidding == status) return FALSE; box->priv->hidding = status; g_object_notify_by_pspec(G_OBJECT(box), properties[HIDDING_PROP]); visu_node_masker_emitDirty(VISU_NODE_MASKER(box)); return TRUE; } /** * visu_box_getVolume: * @box: a #VisuBox object. * * Compute the volume of the box. * * Since: 3.8 * * Returns: the box volume. **/ float visu_box_getVolume(const VisuBox *box) { g_return_val_if_fail(VISU_IS_BOX(box), 0.f); return box->priv->cell[VISU_BOX_DXX] * box->priv->cell[VISU_BOX_DYY] * box->priv->cell[VISU_BOX_DZZ]; } static VisuBox* _getBox(VisuBoxed *self) { return VISU_BOX(self); } static gboolean _maskApply(const VisuNodeMasker *self, VisuNodeArray *array) { gboolean reDraw, outside; float point[3], red[3]; VisuNodeArrayIter iter; VisuBox *box; g_return_val_if_fail(VISU_IS_BOX(self), FALSE); box = VISU_BOX(self); DBG_fprintf(stderr, "Visu Box: applying masking properties.\n"); if (!visu_box_getHiddingStatus(box)) return FALSE; reDraw = FALSE; /* We change the rendered attribute of all nodes, very expensive... */ visu_node_array_iter_new(array, &iter); for (visu_node_array_iterStart(array, &iter); iter.element; visu_node_array_iterNextElement(array, &iter, FALSE)) if (visu_element_getMaskable(iter.element) && visu_element_getRendered(iter.element)) { DBG_fprintf(stderr, " | element '%s'\n", iter.element->name); for (visu_node_array_iterRestartNode(array, &iter); iter.node; visu_node_array_iterNextNode(array, &iter)) { /* If node is already hiden, well, we go to the next. */ if (!iter.node->rendered) continue; visu_data_getNodePosition(VISU_DATA(array), iter.node, point); visu_box_convertXYZtoBoxCoordinates(box, red, point); outside = (red[0] < -box->priv->extension[0] || red[1] < -box->priv->extension[1] || red[2] < -box->priv->extension[2] || red[0] >= 1.f + box->priv->extension[0] || red[1] >= 1.f + box->priv->extension[1] || red[2] >= 1.f + box->priv->extension[2]); if ((box->priv->hidding == VISU_BOX_HIDE_OUTSIDE && outside) || (box->priv->hidding == VISU_BOX_HIDE_INSIDE && !outside)) reDraw = visu_node_setVisibility(iter.node, FALSE) || reDraw; DBG_fprintf(stderr, " | node '%d' -> %d\n", iter.node->number, iter.node->rendered); } } return reDraw; } v_sim-3.8.0/src/visu_box.h000066400000000000000000000205501370110300500154250ustar00rootroot00000000000000/* EXTRAITS DE LA LICENCE Copyright CEA, contributeurs : Luc BILLARD et Damien CALISTE, laboratoire L_Sim, (2001-2005) Adresse mèl : BILLARD, non joignable par mèl ; CALISTE, damien P caliste AT cea P fr. Ce logiciel est un programme informatique servant à visualiser des structures atomiques dans un rendu pseudo-3D. Ce logiciel est régi par la licence CeCILL soumise au droit français et respectant les principes de diffusion des logiciels libres. Vous pouvez utiliser, modifier et/ou redistribuer ce programme sous les conditions de la licence CeCILL telle que diffusée par le CEA, le CNRS et l'INRIA sur le site "http://www.cecill.info". Le fait que vous puissiez accéder à cet en-tête signifie que vous avez pris connaissance de la licence CeCILL, et que vous en avez accepté les termes (cf. le fichier Documentation/licence.fr.txt fourni avec ce logiciel). */ /* LICENCE SUM UP Copyright CEA, contributors : Luc BILLARD et Damien CALISTE, laboratoire L_Sim, (2001-2005) E-mail address: BILLARD, not reachable any more ; CALISTE, damien P caliste AT cea P fr. This software is a computer program whose purpose is to visualize atomic configurations in 3D. This software is governed by the CeCILL license under French law and abiding by the rules of distribution of free software. You can use, modify and/ or redistribute the software under the terms of the CeCILL license as circulated by CEA, CNRS and INRIA at the following URL "http://www.cecill.info". The fact that you are presently reading this means that you have had knowledge of the CeCILL license and that you accept its terms. You can find a copy of this licence shipped with this software at Documentation/licence.en.txt. */ #ifndef VISU_BOX_H #define VISU_BOX_H #include #include #include "visu_tools.h" #include "coreTools/toolMatrix.h" #include "coreTools/toolPhysic.h" G_BEGIN_DECLS /** * VISU_TYPE_BOX: * * return the type of #VisuBox. */ #define VISU_TYPE_BOX (visu_box_get_type ()) /** * VISU_BOX: * @obj: a #GObject to cast. * * Cast the given @obj into #VisuBox type. */ #define VISU_BOX(obj) (G_TYPE_CHECK_INSTANCE_CAST(obj, VISU_TYPE_BOX, VisuBox)) /** * VISU_BOX_CLASS: * @klass: a #GObjectClass to cast. * * Cast the given @klass into #VisuBoxClass. */ #define VISU_BOX_CLASS(klass) (G_TYPE_CHECK_CLASS_CAST(klass, VISU_TYPE_BOX, VisuBoxClass)) /** * VISU_IS_BOX: * @obj: a #GObject to test. * * Test if the given @ogj is of the type of #VisuBox object. */ #define VISU_IS_BOX(obj) (G_TYPE_CHECK_INSTANCE_TYPE(obj, VISU_TYPE_BOX)) /** * VISU_IS_BOX_CLASS: * @klass: a #GObjectClass to test. * * Test if the given @klass is of the type of #VisuBoxClass class. */ #define VISU_IS_BOX_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE(klass, VISU_TYPE_BOX)) /** * VISU_BOX_GET_CLASS: * @obj: a #GObject to get the class of. * * It returns the class of the given @obj. */ #define VISU_BOX_GET_CLASS(obj) (G_TYPE_INSTANCE_GET_CLASS(obj, VISU_TYPE_BOX, VisuBoxClass)) typedef struct _VisuBoxClass VisuBoxClass; typedef struct _VisuBox VisuBox; typedef struct _VisuBoxPrivate VisuBoxPrivate; /** * visu_box_get_type: * * This method returns the type of #VisuBox, use VISU_TYPE_BOX instead. * * Returns: the type of #VisuBox. */ GType visu_box_get_type(void); /** * VisuBox: * * Opaque structure to stores #VisuBox object. */ struct _VisuBox { VisuObject parent; VisuBoxPrivate *priv; }; /** * VisuBoxClass: * @parent: private. * * Class structure of #VisuBox objects. */ struct _VisuBoxClass { VisuObjectClass parent; }; /** * VisuBoxVector: * @VISU_BOX_DXX: x box vector along X; * @VISU_BOX_DYX: y box vector along X; * @VISU_BOX_DYY: y box vector along Y; * @VISU_BOX_DZX: z box vector along X; * @VISU_BOX_DZY: z box vector along Y; * @VISU_BOX_DZZ: z box vector along Z; * @VISU_BOX_N_VECTORS: number of elements. * * Identifier of every projection of the box super-cell on an * orthogonal basis-set. * * Since: 3.7 **/ typedef enum { VISU_BOX_DXX, VISU_BOX_DYX, VISU_BOX_DYY, VISU_BOX_DZX, VISU_BOX_DZY, VISU_BOX_DZZ, VISU_BOX_N_VECTORS } VisuBoxVector; /** * VisuBoxBoundaries: * @VISU_BOX_PERIODIC: the full 3D periodicity ; * @VISU_BOX_SURFACE_XY: the Z axis is a free axis ; * @VISU_BOX_SURFACE_YZ: the X axis is a free axis ; * @VISU_BOX_SURFACE_ZX: the Y axis is a free axis ; * @VISU_BOX_WIRE_X: the periodicity is along X axis only ; * @VISU_BOX_WIRE_Y: the periodicity is along Y axis only ; * @VISU_BOX_WIRE_Z: the periodicity is along Z axis only ; * @VISU_BOX_FREE: the system is isolated. * * This describes the periodicity of the bounding box in the three directions. */ typedef enum { VISU_BOX_PERIODIC = 7, VISU_BOX_SURFACE_XY = 3, VISU_BOX_SURFACE_YZ = 6, VISU_BOX_SURFACE_ZX = 5, VISU_BOX_WIRE_X = 1, VISU_BOX_WIRE_Y = 2, VISU_BOX_WIRE_Z = 4, VISU_BOX_FREE = 0 } VisuBoxBoundaries; /** * VisuBoxHiddingStatus: * @VISU_BOX_HIDE_NONE: don't apply masking. * @VISU_BOX_HIDE_OUTSIDE: hide nodes outside the box. * @VISU_BOX_HIDE_INSIDE: hide nodes inside the box. * * This describes the possibilty to use the box as a masking objects * for nodes. * * Since: 3.8 */ typedef enum { VISU_BOX_HIDE_NONE, VISU_BOX_HIDE_OUTSIDE, VISU_BOX_HIDE_INSIDE } VisuBoxHiddingStatus; /* These structures are used for bindings. */ typedef struct _VisuBoxVertices VisuBoxVertices; struct _VisuBoxVertices { float vertices[8][3]; }; typedef struct _VisuBoxCell VisuBoxCell; struct _VisuBoxCell { double box[VISU_BOX_N_VECTORS]; }; VisuBox* visu_box_new(double geometry[VISU_BOX_N_VECTORS], VisuBoxBoundaries bc); VisuBox* visu_box_new_full(double full[3][3], VisuBoxBoundaries bc); void visu_box_convertFullToCell(VisuBox *box, float cell[3], float full[3]); void visu_box_convertXYZtoBoxCoordinates(const VisuBox *box, float boxCoord[3], float xyz[3]); void visu_box_convertXYZToReduced(VisuBox *box, GArray *xyz, float *u, float *v, float *w); void visu_box_convertBoxCoordinatestoXYZ(VisuBox *box, float xyz[3], const float boxCoord[3]); void visu_box_convertReducedToXYZ(VisuBox *box, GArray *red, float *x, float *y, float *z); gboolean visu_box_constrainInside(VisuBox *box, float translat[3], float xyz[3], gboolean withExt); void visu_box_getInvMatrix(VisuBox *box, double matrix[3][3]); void visu_box_getCellMatrix(VisuBox *box, double matrix[3][3]); void visu_box_getCellMatrixv(VisuBox *box, double *m11, double *m12, double *m13, double *m21, double *m22, double *m23, double *m31, double *m32, double *m33); void visu_box_getVertices(VisuBox *box, float v[8][3], gboolean withExtension); void visu_box_getExtension(const VisuBox *boxObj, float extension[3]); VisuBoxBoundaries visu_box_getBoundary(VisuBox *box); void visu_box_getPeriodicity(VisuBox *box, gboolean per[3]); double visu_box_getGeometry(VisuBox *box, VisuBoxVector vector); void visu_box_getCentre(VisuBox *box, float centre[3]); float visu_box_getGlobalSize(VisuBox *box, gboolean withExt); ToolUnits visu_box_getUnit(VisuBox *box); gboolean visu_box_getInside(VisuBox *box, float vect[3], float ratio); gboolean visu_box_getPeriodicVector(VisuBox *box, float vect[3]); void visu_box_getPeriodicVectorv(VisuBox *box, float *x, float *y, float *z, float vect[3]); void visu_box_getPeriodicArray(VisuBox *box, float *array, guint nEle); gboolean visu_box_getExtensionActive(VisuBox *box); VisuBoxHiddingStatus visu_box_getHiddingStatus(const VisuBox *box); float visu_box_getVolume(const VisuBox *box); gboolean visu_box_setExtensionActive(VisuBox *box, gboolean status); gboolean visu_box_setBoundary(VisuBox *box, VisuBoxBoundaries bc); gboolean visu_box_setGeometry(VisuBox *box, double geometry[VISU_BOX_N_VECTORS]); gboolean visu_box_setGeometryFull(VisuBox *box, double full[3][3]); gboolean visu_box_setMargin(VisuBox *box, gfloat margin, gboolean emit); gboolean visu_box_setExtension(VisuBox *boxObj, float extension[3]); gboolean visu_box_setUnit(VisuBox *box, ToolUnits unit); gboolean visu_box_setOrigin(VisuBox *box, const float orig[3]); gboolean visu_box_setHiddingStatus(VisuBox *box, VisuBoxHiddingStatus status); G_END_DECLS #endif v_sim-3.8.0/src/visu_commandLine.c000066400000000000000000001275201370110300500170630ustar00rootroot00000000000000/* EXTRAITS DE LA LICENCE Copyright CEA, contributeurs : Luc BILLARD et Damien CALISTE, laboratoire L_Sim, (2001-2005) Adresse mèl : BILLARD, non joignable par mèl ; CALISTE, damien P caliste AT cea P fr. Ce logiciel est un programme informatique servant à visualiser des structures atomiques dans un rendu pseudo-3D. Ce logiciel est régi par la licence CeCILL soumise au droit français et respectant les principes de diffusion des logiciels libres. Vous pouvez utiliser, modifier et/ou redistribuer ce programme sous les conditions de la licence CeCILL telle que diffusée par le CEA, le CNRS et l'INRIA sur le site "http://www.cecill.info". Le fait que vous puissiez accéder à cet en-tête signifie que vous avez pris connaissance de la licence CeCILL, et que vous en avez accepté les termes (cf. le fichier Documentation/licence.fr.txt fourni avec ce logiciel). */ /* LICENCE SUM UP Copyright CEA, contributors : Luc BILLARD et Damien CALISTE, laboratoire L_Sim, (2001-2005) E-mail address: BILLARD, not reachable any more ; CALISTE, damien P caliste AT cea P fr. This software is a computer program whose purpose is to visualize atomic configurations in 3D. This software is governed by the CeCILL license under French law and abiding by the rules of distribution of free software. You can use, modify and/ or redistribute the software under the terms of the CeCILL license as circulated by CEA, CNRS and INRIA at the following URL "http://www.cecill.info". The fact that you are presently reading this means that you have had knowledge of the CeCILL license and that you accept its terms. You can find a copy of this licence shipped with this software at Documentation/licence.en.txt. */ #include "visu_commandLine.h" #include "visu_tools.h" #include "visu_basic.h" #include #include #include #include #include /** * SECTION:visu_commandLine * @short_description: All methods needed to parse options from the * command line. * * V_Sim parses the command line at startup and store data in * private variables. All this values can be retrieve later by the * program through calls to commandLineGet_* methods. */ static char *argFileName, *argProgName; /* Forced resources file. */ static gchar *argResources; /* Spin arguments. */ static char *argSpinFileName; static int spinHidingMode; static gboolean spinAndAtomic; /* Miscelaneous arguments. */ static gchar *argExportFileName; static gchar *argWindowMode; static guint argISet; static gchar *argValueFile; /* Colorisation tool. */ #define COLORIZATION_PROP_FLAG "property#" static gchar *argColorizeFileName; static gboolean argColorizationIsFile; static int argColorizeColUsed[3]; static int argColorizePresetColor; static GArray *argColorizeRange; static gboolean argColorizeColUsed_isPresent; static int argScalingColumn; /* Iso-surfaces tool. */ static GList *argScalarfieldFilenames; static gchar *argIsoVisuSurfaceFileName; static float *argIsoValues; static gchar **argIsoNames; static float argNbIsoValues; static gboolean argFitToBox; /* Translations stuffs. */ static gboolean argTranslationsIsSet; static float argTranslations[3]; static gboolean argBoxTranslationsIsSet; static float argBoxTranslations[3]; /* Extension stuffs. */ static gboolean argExpandIsSet; static float argExtension[3]; /* Colored map. */ static int *argMapVisuPlaneId; static ToolMatrixScalingFlag argLogScale; static int argNIsoLines; static float *argIsoLinesColor; static guint argMapPrecision; static float *argMapMinMax; /* Background image. */ static gchar *argBgImageFile; /* Phonons. */ static gint argPhononMode; static gfloat argPhononTime; static gfloat argPhononAmpl; /* Extended options. */ static GHashTable *argOptionTable; /* Miscelaneous options */ static gchar* argVisuPlanesFileName; static gchar *argGeoDiff; static int withGtk; static int xWindowWidth, xWindowHeight; static GQuark quark = 0; /** * visu_command_line_getErrorQuark: * * Internal routine for error handling. * * Since: 3.8 * * Returns: (transfer none): the #GQuark associated to errors related to data * files. */ GQuark visu_command_line_getErrorQuark() { if (!quark) quark = g_quark_from_static_string("VisuCommandLine"); return quark; } struct option_desc { struct option *opt; const gchar *desc; const gchar *arg; const gchar *def; float version; }; /* Remaining letters... j, k, l, y, z */ #define N_OPTIONS 36 static GString *short_options; static struct option *long_options; static struct option_desc *ext_options; void alignPrint(GString *str, const gchar* value, int ln, gchar *pad) { gchar *sp; gchar *tmp; if (g_utf8_strlen(value, -1) <= ln) { g_string_append_printf(str, "%s%s", pad, value); return; } sp = g_utf8_strrchr(value, ln, ' '); g_return_if_fail(sp); tmp = g_strndup(value, (gsize)(sp - value)); g_string_append_printf(str, "%s%s\n", pad, tmp); g_free(tmp); alignPrint(str, sp + 1, ln, pad); } #define OUT stdout #define P fprintf #define offset 25 void printInfoMessage(void) { int i; GString *desc, *expl; gchar format[128], pad[128], arg[128]; P(OUT, _("V_Sim is a software to visualize atomic structures with" " OpenGl rendering.\n\n")); desc = g_string_new(_("usage:")); g_string_append_printf(desc, " %s [", PACKAGE_TARNAME); for (i = 0; ext_options[i].opt->name; i++) if (ext_options[i].opt->val) { if (i > 0) g_string_append(desc, " | "); g_string_append_printf(desc, "-%c", ext_options[i].opt->val); if (ext_options[i].arg) g_string_append_printf(desc, " %s", ext_options[i].arg); } g_string_append_printf(desc, "] [fileToRender]\n\n"); P(OUT, "%s", desc->str); expl = g_string_new(""); sprintf(format, "%%%ds", offset); sprintf(pad, format, " "); for (i = 0; ext_options[i].opt->name; i++) { if (ext_options[i].opt->val) g_string_printf(desc, " -%c,", ext_options[i].opt->val); else g_string_assign(desc, " "); if (ext_options[i].arg) sprintf(arg, "%s %s", ext_options[i].opt->name, ext_options[i].arg); else sprintf(arg, "%s", ext_options[i].opt->name); g_string_erase(expl, 0, -1); alignPrint(expl, ext_options[i].desc, 80 - offset, pad); g_string_append_printf(desc, " --%s (from v%3.1f.0)\n%s\n", arg, ext_options[i].version, expl->str); sprintf(format, "%%%ds", offset); g_string_append_printf(desc, format, " "); if (ext_options[i].def) g_string_append_printf(desc, _("(Default value: %s)\n\n"), ext_options[i].def); else g_string_append(desc, _("(Default value: unset)\n\n")); P(OUT, "%s", desc->str); } g_string_free(expl, TRUE); g_string_free(desc, TRUE); } void optionSet(int i, const gchar *lg, gchar sh, const gchar *desc, const gchar *arg, const gchar *def, float version) { long_options[i].name = lg; long_options[i].has_arg = (arg)?required_argument:no_argument; long_options[i].flag = (int*)0; long_options[i].val = (int)sh; ext_options[i].opt = long_options + i; ext_options[i].desc = desc; ext_options[i].arg = arg; ext_options[i].def = def; ext_options[i].version = version; if (arg && sh) g_string_append_printf(short_options, "%c:", sh); else if (sh) g_string_append_printf(short_options, "%c", sh); } void optionsInit(void) { int i; short_options = g_string_new(""); ext_options = g_malloc(sizeof(struct option_desc) * N_OPTIONS); long_options = g_malloc(sizeof(struct option) * N_OPTIONS); i = 0; optionSet(i++, "export", 'e', _("make an image from the fileToRender argument. The format is" " specified through the extension of the argument or by the" " -o fileFormatId=id option (get the id of available file" " formats with -o list)."), _("file"), (gchar*)0, 3.0f); optionSet(i++, "resources", 'r', _("load the given resources file on startup instead of looking" " for a valid resources file in the standard locations."), _("file"), (gchar*)0, 3.4f); optionSet(i++, "help", 'h', _("show this little help."), (gchar*)0, (gchar*)0, 3.0f); optionSet(i++, "geometry", 'g', _("specify the size of the rendering window, the size argument must" " have the following format: x with positive non null" " values."), _("x"), "600x600", 3.0f); optionSet(i++, "spin-file", 's', _("use the given argument as a spin indicator. If this option is used," " V_Sim switches automatically to spin rendering whatever method" " is specified in the parameter file."), _("file"), (gchar*)0, 3.1f); optionSet(i++, "hiding-mode", 'm', _("policy used to show or not null modulus spins possible values are" " positives."), _("id"), "0", 3.2f); optionSet(i++, "spin-and-atomic", 'a', _("always draws atomic rendering on node position in addition to spin" " rendering."), (gchar*)0, (gchar*)0, 3.3f); optionSet(i++, "colorize", 'c', _("the argument fileToRender must be called, then the given file of" " the option is used to colorize the elements. If argument is" " starting with 'property#', colorization data are taken" " from node property propName."), _("{file,property#propName}"), (gchar*)0, 3.1f); optionSet(i++, "use-column", 'u', _("it specifies the columns to use from the data file for the three colour" " channels [l;m;n]. Columns are counted from 1. Use -3, -2, -1 and 0" " to use the special values, constant 1, coord. x, coord. y," " and coord. z, respectively."), "l:m:n", (gchar*)0, 3.1f); optionSet(i++, "color-preset", 'd', _("this option can be used with the '--colorize' one or the" " '--build-map' one. It chooses a preset color scheme. The id" " argument is an integer that corresponds to a defined color" " shade (ranging from 0)."), _("id"), (gchar*)0, 3.1f); optionSet(i++, "translate", 't', _("a file must be loaded. It applies the given translations to the" " loaded file. The units are those of the file. This is available" " for periodic file formats only."), "x:y:z", (gchar*)0, 3.3f); optionSet(i++, "box-translate", 'q', _("a file must be loaded. It applies the given translations to the" " loaded file. The translation is applied along box axis, normalised" " to 1. This is available for periodic file formats only."), "a:b:c", (gchar*)0, 3.8f); optionSet(i++, "expand", 'x', _("a file must be loaded. It applies the given expansion to the loaded" " file. The values are given in box coordinates. This is available" " for periodic file formats only."), "x:y:z", (gchar*)0, 3.4f); optionSet(i++, "planes", 'p', _("the argument fileToRender must be called, then the given file of" " the option is parsed as a list of planes and they are rendered."), _("file"), (gchar*)0, 3.2f); optionSet(i++, "scalar-field", 'f', _("the argument fileToRender must be called, then the given file of" " the option is parsed as a scalar field and loaded. Use '.'" " as a special value to reuse the main filename."), _("{file,.}"), (gchar*)0, 3.3f); optionSet(i++, "iso-values", 'v', _("must be used with the '--scalar-field' option, then the given" " surfaces are built and rendered. If a name is appended to a" " value using '#' as a separator, this name is used as the name" " for the iso-surface (i.e. 0.25#Blue). Use specific value" " 'auto' to compute isosurfaces at half max and min value."), "v[:v]", (gchar*)0, 3.3f); optionSet(i++, "iso-surfaces", 'i', _("the argument fileToRender must be given, then the given file of" " the option is parsed and surfaces are rendered."), _("file"), (gchar*)0, 3.2f); optionSet(i++, "build-map", 'b', _("the argument fileToRender must be given, as the '--planes'," " '--color-preset' and '--scalar-field' options used, then the" " given plane 'id' is replaced by a coloured map using given" " scalar field and shade. 'id' ranges from 0. If several ids" " are given, several maps are built."), _("id[:id]"), (gchar*)0, 3.4f); optionSet(i++, "log-scale", 0, _("select the scaling method to use with gradients (0: linear," " 1: log scaled and 2 is zero-centred log scale), default is linear scale."), _("id"), (gchar*)0, 3.4f); optionSet(i++, "n-iso-lines", 'n', _("when positive, val isolines are plotted on the coloured map."), _("val"), (gchar*)0, 3.4f); optionSet(i++, "color-iso-lines", 0, _("when given, generated iso-lines are colourised [R:G:B] or auto" " with the values. The specific value 'auto' will produced" " iso-lines in inversed colours."), _("[R:G:B] or auto"), "[0:0:0]", 3.5f); optionSet(i++, "fit-to-box", 0, _("if val is not TRUE, the surfaces use their own bounding box."), _("val"), "TRUE", 3.3f); optionSet(i++, "bg-image", 0, _("draw the given image on the background."), _("file"), (gchar*)0, 3.4f); optionSet(i++, "option", 'o', _("this is a generic way to give extended option. to V_Sim. As much" " as -o can be used. Each one store a key and its value (boolean," " integer or float)."), _("id=value"), (gchar*)0, 3.3f); optionSet(i++, "window-mode", 'w', _("used to choose the windowing mode. By default the command panel " "and the rendering window are separated. In the 'oneWindow' mode " "they are joined. In the 'renderOnly' mode, the command panel is " "not used."), _("mode"), "classic", 3.5f); optionSet(i++, "i-set", 0, _("this flag is used to choose the id of the loaded file if the" " format has support for multiple ids in one file (see XYZ" " format or -posi.d3 ones)."), _("i"), "0", 3.5f); optionSet(i++, "value-file", 0, _("specify an XML file with some value information for V_Sim," " like a list of planes, highlighted nodes... It replaces" " and extend the previous --planes option."), _("file"), (gchar*)0, 3.5f); optionSet(i++, "map-precision", 0, _("Give the precision in percent to render the coloured map."), _("prec"), "100", 3.5f); optionSet(i++, "map-clamp", 0, _("Set the minimum and maximum values for the coloured map rendering."), _("min:max or auto"), "auto", 3.6f); optionSet(i++, "color-clamp", 0, _("Range to adjust values into for colourisation. col specifies" "the column to apply the range to. Use -2, -1 and 0 for x, y" "and z directions respectively."), _("col#min:max or auto"), "auto", 3.7f); optionSet(i++, "scaling-column", 0, _("used with a data file (see -c), it specifies the " "column id to be used to scale the nodes."), _("id"), (gchar*)0, 3.7f); optionSet(i++, "diff-from", 0, _("Compute the geometric difference between load file and this argument."), _("file"), (gchar*)0, 3.8f); optionSet(i++, "phonon-mode", 0, _("Load the given phonon mode."), _("mode"), "0", 3.8f); optionSet(i++, "time-offset", 0, _("Displace nodes according to phonons at the given reduced time in [0;1]."), _("offset"), "0", 3.8f); optionSet(i++, "phonon-amplitude", 0, _("Maximum displacement for phonons."), _("ampl"), "1.", 3.8f); optionSet(i++, NULL, 0, NULL, NULL, NULL, 0.f); g_return_if_fail(i == N_OPTIONS); } gboolean commandLineExport(const gchar *filename, GError **error) { GString *xml; int i; gboolean status; gchar *desc, *def, *arg; xml = g_string_new("\n"); xml = g_string_append(xml, "\n"); for (i = 0; ext_options[i].opt->name; i++) { if (ext_options[i].opt->val) g_string_append_printf (xml, " \n"); } g_string_append(xml, "\n"); status = g_file_set_contents(filename, xml->str, -1, error); g_string_free(xml, TRUE); return status; } int commandLineParse(int argc, char **argv) { int res, i, nb; int option_index; gchar **tokens, **tokens2; ToolOption *option; float min, max; gchar *endptr; gdouble vald; gint64 vali; VisuColorRange rg; GString *errmess; /* We want to read . as floating point separator : in french it is , */ setlocale(LC_NUMERIC, "C"); argProgName = g_strdup(argv[0]); argFileName = (char*)0; argSpinFileName = (char *)0; spinHidingMode = 1; spinAndAtomic = FALSE; argExportFileName = (char*)0; argColorizeFileName = (gchar*)0; for (i = 0; i < 2; i++) argColorizeColUsed[i] = 0; argColorizeColUsed_isPresent = FALSE; argColorizePresetColor = -1; argColorizeRange = g_array_new(FALSE, FALSE, sizeof(VisuColorRange)); argTranslationsIsSet = FALSE; argBoxTranslationsIsSet = FALSE; argExpandIsSet = FALSE; xWindowWidth = 600; xWindowHeight = 600; argVisuPlanesFileName = (gchar*)0; argScalarfieldFilenames = (GList*)0; argIsoVisuSurfaceFileName = (gchar*)0; argIsoValues = (float*)0; argFitToBox = TRUE; argOptionTable = (GHashTable*)0; argMapVisuPlaneId = (int*)0; argLogScale = FALSE; argNIsoLines = 0; argBgImageFile = (gchar*)0; argIsoLinesColor = g_malloc0(sizeof(float) * 3); argMapMinMax = (float*)0; argWindowMode = g_strdup("classic"); argISet = 0; argValueFile = (gchar*)0; argMapPrecision = 100; argScalingColumn = -1; argPhononMode = -1; argPhononTime = -1.f; argPhononAmpl = -1.f; withGtk = 1; optionsInit(); option = (ToolOption*)0; option_index = 0; opterr = 0; DBG_fprintf(stderr, "Visu CommandLine: short options '%s'.\n", short_options->str); while (1) { res = getopt_long (argc, argv, short_options->str, long_options, &option_index); /* test if there's no more option available. */ if (res == -1) break; switch (res) { case 'e': DBG_fprintf(stderr, "Visu Command: option '%s' found with arg '%s'.\n", long_options[option_index].name, optarg); if (!optarg) g_error("The option 'export' needs a parameter.\n"); else argExportFileName = g_strdup(optarg); /* This option does not need gtk. */ withGtk = 0; break; case 'r': DBG_fprintf(stderr, "Visu Command: option '%s' found with arg '%s'.\n", long_options[option_index].name, optarg); if (!optarg) g_error("The option 'resources' needs a parameter.\n"); else argResources = g_strdup(optarg); break; case 'h': DBG_fprintf(stderr, "Visu Command: option '%s' found.\n", long_options[option_index].name); printInfoMessage(); exit(0); break; case 'g': DBG_fprintf(stderr, "Visu Command: set the geometry of the X window (%s).\n", optarg); res = sscanf(optarg, "%dx%d", &xWindowWidth, &xWindowHeight); if (res != 2 || xWindowWidth <= 0 || xWindowHeight <=0) { g_warning("Wrong format for geometry" " option (x awaited).\n"); xWindowWidth = 600; xWindowHeight = 600; break; } break; case 's': DBG_fprintf(stderr, "Visu Command: set the filenane for" " spin rendering to '%s'.\n", optarg); if (!optarg) { g_error("The option 'spin-file' needs a parameter.\n"); } argSpinFileName = g_strdup(optarg); break; case 'm': DBG_fprintf(stderr, "Visu Command: set hiding-mode to '%s' in spin rendering.\n", optarg); res = sscanf(optarg, "%d", &spinHidingMode); if (res != 1 || spinHidingMode < 0) { g_warning("Wrong format for hiding-mode" " option (integer awaited).\n"); spinHidingMode = 0; } break; case 'a': DBG_fprintf(stderr, "Visu Command: set spin-and-atomic to TRUE in spin rendering.\n"); spinAndAtomic = TRUE; break; case 'b': DBG_fprintf(stderr, "Visu Command: get the values for" " maps '%s'.\n", optarg); if (!optarg) { g_error("The option 'build-map' needs a parameter.\n"); } tokens = g_strsplit(optarg, ":", -1); /* Count number of tokens. */ for (nb = 0; tokens[nb]; nb++); DBG_fprintf(stderr, " | allocate %d ids.\n", nb + 1); argMapVisuPlaneId = g_malloc(sizeof(int) * (nb + 1)); nb = 1; for (i = 0; tokens[i]; i++) { res = sscanf(tokens[i], "%d", argMapVisuPlaneId + nb); if (res != 1 || argMapVisuPlaneId[nb] < 0) g_warning("Parse error reading values from option " "'build-map', unknown plane id '%s'.\n", tokens[i]); else nb += 1; } DBG_fprintf(stderr, " | found %d valid ids.\n", nb - 1); argMapVisuPlaneId[0] = nb - 1; g_strfreev(tokens); break; case 'n': res = sscanf(optarg, "%d", &argNIsoLines); if (res != 1 || argNIsoLines < 0) { g_warning("Wrong format for n-iso-lines option (id >= 0 awaited).\n"); argNIsoLines = 0; break; } DBG_fprintf(stderr, "Visu Command: set the number of isolines" " for coloured map '%d'.\n", argNIsoLines); break; case 'c': DBG_fprintf(stderr, "Visu Command: set the filenane for colorization to '%s'.\n", optarg); if (!optarg) { g_error("The option 'colorize' needs a parameter.\n"); } argColorizationIsFile = TRUE; if (strstr(optarg, COLORIZATION_PROP_FLAG) == optarg) { argColorizeFileName = g_strdup(optarg + strlen(COLORIZATION_PROP_FLAG)); argColorizationIsFile = FALSE; } else argColorizeFileName = g_strdup(optarg); break; case 'u': DBG_fprintf(stderr, "Visu Command: set the used columns for" " colorize data (%s).\n", optarg); res = sscanf(optarg, "%d:%d:%d", argColorizeColUsed, argColorizeColUsed + 1, argColorizeColUsed + 2); if (res != 3 || argColorizeColUsed[0] < -3 || argColorizeColUsed[1] < -3 || argColorizeColUsed[2] < -3) { g_warning("Wrong format for use-column" " option (:: awaited).\n"); for (i = 0; i < 2; i++) argColorizeColUsed[i] = -3; break; } argColorizeColUsed_isPresent = TRUE; break; case 'd': DBG_fprintf(stderr, "Visu Command: set a previously defined color scheme (%s).\n", optarg); res = sscanf(optarg, "%d", &argColorizePresetColor); if (res != 1 || argColorizePresetColor < 0) { g_warning("Wrong format for color-preset" " option (positive integer awaited).\n"); argColorizePresetColor = -1; break; } break; case 't': DBG_fprintf(stderr, "Visu Command: set the translations (%s).\n", optarg); res = sscanf(optarg, "%f:%f:%f", argTranslations, argTranslations + 1, argTranslations + 2); if (res != 3) { g_warning("Wrong format for translation" " option (:: awaited).\n"); break; } else argTranslationsIsSet = TRUE; break; case 'q': DBG_fprintf(stderr, "Visu Command: set the box translations (%s).\n", optarg); res = sscanf(optarg, "%f:%f:%f", argBoxTranslations, argBoxTranslations + 1, argBoxTranslations + 2); if (res != 3) { g_warning("Wrong format for translation" " option (:: awaited).\n"); break; } else argBoxTranslationsIsSet = TRUE; break; case 'x': DBG_fprintf(stderr, "Visu Command: set the extension (%s).\n", optarg); res = sscanf(optarg, "%f:%f:%f", argExtension, argExtension + 1, argExtension + 2); if (res != 3 || argExtension[0] < 0. || argExtension[1] < 0. || argExtension[2] < 0.) { g_warning("Wrong format for expand" " option (:: awaited >= 0.).\n"); break; } else argExpandIsSet = TRUE; break; case 'p': DBG_fprintf(stderr, "Visu Command: set the filenane for planes to '%s'.\n", optarg); if (!optarg) { g_error("The option 'planes' needs a parameter.\n"); } argVisuPlanesFileName = g_strdup(optarg); break; case 'f': DBG_fprintf(stderr, "Visu Command: set the filenane for" " a scalar field '%s'.\n", optarg); if (!optarg) { g_error("The option 'field' needs a parameter.\n"); } if (strcmp(".", optarg)) argScalarfieldFilenames = g_list_append(argScalarfieldFilenames, g_strdup(optarg)); else argScalarfieldFilenames = g_list_append(argScalarfieldFilenames, g_strdup(argv[argc - 1])); break; case 'v': DBG_fprintf(stderr, "Visu Command: get the values for" " a scalar field '%s'.\n", optarg); if (!optarg) { g_error("The option 'iso-values' needs a parameter.\n"); } tokens = g_strsplit(optarg, ":", -1); /* Count number of tokens. */ for (nb = 0; tokens[nb]; nb++); argIsoValues = g_malloc(sizeof(float) * (nb + 1)); argIsoNames = g_malloc(sizeof(gchar*) * (nb + 1)); nb = 0; for (i = 0; tokens[i]; i++) { if (!g_strcmp0(tokens[i], "auto")) { argIsoValues[nb] = G_MAXFLOAT; argIsoNames[nb] = (gchar*)0; nb += 1; } else { tokens2 = g_strsplit(tokens[i], "#", 2); res = sscanf(tokens2[0], "%f", argIsoValues + nb); if (res != 1) g_warning("Parse error reading values from option " "'iso-values', unknown number '%s'.\n", tokens[i]); else { if (tokens2[1]) /* A name for the value is given. */ argIsoNames[nb] = g_strdup(tokens2[1]); else argIsoNames[nb] = (gchar*)0; nb += 1; } g_strfreev(tokens2); } } argIsoNames[nb] = (gchar*)0; argNbIsoValues = nb; g_strfreev(tokens); break; case 'i': DBG_fprintf(stderr, "Visu Command: set the filenane for" " an isosurfaces '%s'.\n", optarg); if (!optarg) { g_error("The option 'iso-surfaces' needs a parameter.\n"); } argIsoVisuSurfaceFileName = g_strdup(optarg); break; case 'o': DBG_fprintf(stderr, "Visu Command: read an extended option.\n"); if (!optarg) { g_error("The option 'option' needs a parameter.\n"); } tokens = g_strsplit(optarg, "=", 2); if (!argOptionTable) argOptionTable = g_hash_table_new_full(g_str_hash, g_str_equal, NULL, \ (GDestroyNotify)tool_option_free); if (tokens[1] && tokens[1][0] == 'T' && !tokens[1][1]) { option = tool_option_new(tokens[0], tokens[0], G_TYPE_BOOLEAN); g_value_set_boolean(tool_option_getValue(option), TRUE); DBG_fprintf(stderr, " | boolean : T\n"); } else if (tokens[1] && tokens[1][0] == 'F' && !tokens[1][1]) { option = tool_option_new(tokens[0], tokens[0], G_TYPE_BOOLEAN); g_value_set_boolean(tool_option_getValue(option), FALSE); DBG_fprintf(stderr, " | boolean : F\n"); } else if (tokens[1]) { vald = g_ascii_strtod(tokens[1], &endptr); if (endptr != tokens[1] && !endptr) { vali = g_ascii_strtoll(tokens[1], &endptr, 10); if (endptr != tokens[1] && !endptr) { option = tool_option_new(tokens[0], tokens[0], G_TYPE_INT); g_value_set_int(tool_option_getValue(option), (int)vali); DBG_fprintf(stderr, " | float : '%d'\n", (int)vali); } else { option = tool_option_new(tokens[0], tokens[0], G_TYPE_FLOAT); g_value_set_float(tool_option_getValue(option), (float)vald); DBG_fprintf(stderr, " | float : '%g'\n", (float)vald); } } else { option = tool_option_new(tokens[0], tokens[0], G_TYPE_STRING); g_value_set_string(tool_option_getValue(option), tokens[1]); DBG_fprintf(stderr, " | string : '%s'\n", tokens[1]); } } else if (!tokens[1]) { option = tool_option_new(tokens[0], tokens[0], G_TYPE_BOOLEAN); g_value_set_boolean(tool_option_getValue(option), TRUE); DBG_fprintf(stderr, " | boolean : T\n"); } else { g_error("Unparsable value for option 'option'.\n"); } g_hash_table_insert(argOptionTable, (gpointer)tool_option_getName(option), (gpointer)option); g_strfreev(tokens); break; case 'w': DBG_fprintf(stderr, "Visu Command: set the window mode to" " '%s'.\n", optarg); if (!optarg) { g_error("The option 'window-mode' needs a parameter.\n"); } argWindowMode = g_strdup(optarg); if (strcmp(argWindowMode, "classic") && strcmp(argWindowMode, "renderOnly") && strcmp(argWindowMode, "oneWindow")) { g_error("The option 'window-mode' accepts only 'calssic'" ", 'oneWindow' and 'renderOnly' as a parameter.\n"); } break; case 0: /* Long option only. */ if (!strcmp(long_options[option_index].name, "fit-to-box")) argFitToBox = (!strcmp(optarg, "TRUE")); else if (!strcmp(long_options[option_index].name, "log-scale")) { if (sscanf(optarg, "%ud", &argLogScale) != 1) argLogScale = TOOL_MATRIX_SCALING_LINEAR; if (argLogScale >= TOOL_MATRIX_SCALING_N_VALUES) argLogScale = TOOL_MATRIX_SCALING_LINEAR; } else if (!strcmp(long_options[option_index].name, "bg-image")) { if (strcmp(optarg, "V_Sim")) argBgImageFile = g_strdup(optarg); else argBgImageFile = g_build_filename(V_SIM_PIXMAPS_DIR, "logo_grey.png", NULL); } else if (!strcmp(long_options[option_index].name, "color-iso-lines")) { if (sscanf(optarg, "[%f:%f:%f]", argIsoLinesColor, argIsoLinesColor + 1, argIsoLinesColor + 2) != 3) { if (!strcmp(optarg, "auto") || !strcmp(optarg, "Auto")) { g_free(argIsoLinesColor); argIsoLinesColor = (float*)0; } else { g_error("Can't read any color from '%s' following" " the [R:G:B] scheme or the 'auto' keyword.\n", optarg); } } if (argIsoLinesColor) { argIsoLinesColor[0] = CLAMP(argIsoLinesColor[0], 0.f, 1.f); argIsoLinesColor[1] = CLAMP(argIsoLinesColor[1], 0.f, 1.f); argIsoLinesColor[2] = CLAMP(argIsoLinesColor[2], 0.f, 1.f); } } else if (!strcmp(long_options[option_index].name, "i-set")) { if (sscanf(optarg, "%u", &argISet) != 1) { g_warning("Wrong format for i-set" " option (integer awaited >= 0).\n"); argISet = 0; break; } } else if (!strcmp(long_options[option_index].name, "value-file")) argValueFile = g_strdup(optarg); else if (!strcmp(long_options[option_index].name, "map-precision")) { if (sscanf(optarg, "%u", &argMapPrecision) != 1 || argMapPrecision == 0) { g_warning("Wrong value for map-precision" " option (integer awaited > 0).\n"); argMapPrecision = 100; break; } DBG_fprintf(stderr, "Visu CommandLine: read map precision %u.\n", argMapPrecision); } else if (!strcmp(long_options[option_index].name, "map-clamp")) { argMapMinMax = g_malloc0(sizeof(float) * 2); if (sscanf(optarg, "%f:%f", argMapMinMax, argMapMinMax + 1) != 2) { if (!strcmp(optarg, "auto") || !strcmp(optarg, "Auto")) { g_free(argMapMinMax); argMapMinMax = (float*)0; } else { g_error("Can't read any bounds from '%s' following" " the min:max scheme or the 'auto' keyword.\n", optarg); } } if (argMapMinMax && argMapMinMax[1] <= argMapMinMax[0]) { g_error("Bounds given in '%s' are wrong," " min value is greater than max value.\n", optarg); g_free(argMapMinMax); argMapMinMax = (float*)0; } } else if (!strcmp(long_options[option_index].name, "color-clamp")) { if (sscanf(optarg, "%d#%f:%f", &i, &min, &max) == 3) { if (max <= min) { g_error("Bounds given in '%s' are wrong," " min value is greater than max value.\n", optarg); } DBG_fprintf(stderr, "Visu Command: found color range %d -> [%g;%g].\n", i, min, max); rg.column = i; rg.min = min; rg.max = max; g_array_append_val(argColorizeRange, rg); } else { g_error("Can't read any bounds from '%s' following" " the col#min:max scheme or the 'auto' keyword.\n", optarg); } } else if (!strcmp(long_options[option_index].name, "scaling-column")) { if (sscanf(optarg, "%d", &argScalingColumn) != 1 || argScalingColumn < 1) { g_warning("Wrong value for scaling-column" " option (integer awaited > 0).\n"); argScalingColumn = -1; break; } else argScalingColumn -= 1; } else if (!strcmp(long_options[option_index].name, "diff-from")) { argGeoDiff = g_strdup(optarg); } else if (!strcmp(long_options[option_index].name, "phonon-mode")) { if (sscanf(optarg, "%d", &argPhononMode) != 1 || argPhononMode < 1) { g_warning("Wrong value for phonon-mode" " option (integer awaited > 0).\n"); argPhononMode = -1; break; } else argPhononMode -= 1; } else if (!strcmp(long_options[option_index].name, "time-offset")) { if (sscanf(optarg, "%f", &argPhononTime) != 1 || argPhononTime < 0. || argPhononTime >= 1.) { g_warning("Wrong value for time-offset" " option (float in [0;1[).\n"); argPhononTime = -1.f; break; } } else if (!strcmp(long_options[option_index].name, "phonon-amplitude")) { if (sscanf(optarg, "%f", &argPhononAmpl) != 1 || argPhononAmpl < 0.) { g_warning("Wrong value for phonon-amplitude" " option (positive float).\n"); argPhononAmpl = -1.f; break; } } else { g_error("Unknown long option '--%s'.\n", long_options[option_index].name); } break; default: g_warning("Unknown option '%s'.", argv[optind - 1]); printInfoMessage(); exit(0); } } if (argc - optind == 1) { DBG_fprintf(stderr, "Visu Command: there is one argument '%s'.\n", argv[optind]); argFileName = tool_path_normalize(argv[optind]); } else if (argc - optind == 0) return 0; else { errmess = g_string_new("This program allows only up to one argument, found:"); for (i = optind; i < argc; i++) g_string_append_printf(errmess, "\n- %s", argv[i]); g_warning("%s", errmess->str); g_string_free(errmess, TRUE); } /* Consistency check between options. */ if (argScalarfieldFilenames && argIsoVisuSurfaceFileName) { g_error("The options --iso-surfaces and --scalar-field are exclusive."); } if (argValueFile && argVisuPlanesFileName) { g_error("The options --planes and --value-file are exclusive."); } return 0; } char* commandLineGet_ArgFilename(void) { return argFileName; } char* commandLineGet_ArgSpinFileName(void) { return argSpinFileName; } int commandLineGet_WithGtk(void) { return withGtk; } char* commandLineGet_ExportFileName(void) { return argExportFileName; } void commandLineGet_XWindowGeometry(int *width, int *height) { *width = xWindowWidth; *height = xWindowHeight; } /** * commandLineGet_colorizeSource: * @isFile: a location to store if the source is a filename. * * Retrieve the string given on command line that is used to identify * the source of colourisation, either a #VisuNodeValues name or a filename. * * Since: 3.8 * * Returns: a string used to identify a #VisuNodeValues object or a filename. **/ const gchar* commandLineGet_colorizeSource(gboolean *isFile) { if (isFile) *isFile = argColorizationIsFile; return argColorizeFileName; } int* commandLineGet_colorizeColUsed(void) { if (argColorizeColUsed_isPresent) return argColorizeColUsed; else return (int*)0; } /** * commandLineGet_translation: * @boxTranslation: a location to store if returned translation is * given is cartesian or box coordinates. * * This method retrieves the value of the option --translate or -t. This value consists * of three floating values. If -q or --box-translation is present, * the returned value is the translations along box axis. * * Returns: the three values of the option --translate. */ float* commandLineGet_translation(gboolean *boxTranslation) { if (boxTranslation) *boxTranslation = argBoxTranslationsIsSet; if (argTranslationsIsSet) return argTranslations; else if (argBoxTranslationsIsSet) return argBoxTranslations; else return (float*)0; } float* commandLineGet_extension(void) { if (argExpandIsSet) return argExtension; else return (float*)0; } int commandLineGet_presetColor(void) { return argColorizePresetColor; } gchar* commandLineGet_planesFileName(void) { return argVisuPlanesFileName; } int commandLineGet_spinHidingMode(void) { return spinHidingMode; } gboolean commandLineGet_spinAndAtomic(void) { return spinAndAtomic; } float* commandLineGet_isoValues(int *nb) { g_return_val_if_fail(nb, (float*)0); *nb = argNbIsoValues; return argIsoValues; } const gchar** commandLineGet_isoNames(int *nb) { g_return_val_if_fail(nb, (const gchar**)0); *nb = argNbIsoValues; return (const gchar**)argIsoNames; } /** * commandLineGet_scalarFieldFileNames: * * This method retrieves the filename given by the option --scalar-field or -f. * * Returns: (element-type filename) (transfer none): a filename, the * string is owned by V_Sim. */ const GList* commandLineGet_scalarFieldFileNames(void) { return argScalarfieldFilenames; } gchar* commandLineGet_isoVisuSurfaceFileName(void) { return argIsoVisuSurfaceFileName; } gboolean commandLineGet_fitToBox(void) { DBG_fprintf(stderr, "Visu CommandLine: get fit to box option %d.\n", argFitToBox); return argFitToBox; } GHashTable* commandLineGet_options(void) { return argOptionTable; } gchar* commandLineGet_resourcesFile(void) { return argResources; } /** * commandLineGet_coloredMap: * * One can pass options on the command line to create colored maps on planes. * * Returns: an array of plane indexes to be maped, -1 terminated. * * Since: 3.6 */ int* commandLineGet_coloredMap(void) { if (argMapVisuPlaneId && argMapVisuPlaneId[0]) return argMapVisuPlaneId; else return (int*)0; } ToolMatrixScalingFlag commandLineGet_logScale(void) { return argLogScale; } guint commandLineGet_nIsoLines(void) { return (guint)argNIsoLines; } gchar* commandLineGet_bgImage(void) { return argBgImageFile; } float* commandLineGet_isoLinesColor(void) { return argIsoLinesColor; } gchar* commandLineGet_windowMode(void) { return argWindowMode; } guint commandLineGet_iSet(void) { return (guint)argISet; } gchar* commandLineGet_valueFile(void) { return argValueFile; } /** * commandLineGet_mapPrecision: * * The coloured maps can be rendered with more or less accuracy. * * Since: 3.6 * * Returns: the precision requested by the user. */ guint commandLineGet_mapPrecision(void) { return argMapPrecision; } /** * commandLineGet_mapMinMax: * * The coloured maps can be manually scaled. * * Since: 3.6 * * Returns: the scaling values for manual scaling of coloured maps. */ float* commandLineGet_mapMinMax(void) { return argMapMinMax; } /** * commandLineGet_colorMinMax: * * The external data file colourisation can be manually scaled. * * Since: 3.7 * * Returns: the scaling values for manual scaling of external data values. */ GArray* commandLineGet_colorMinMax(void) { return argColorizeRange; } /** * commandLineGet_programName: * * Get argv[0]. * * Since: 3.7 * * Returns: the program name used to run V_Sim. */ const gchar* commandLineGet_programName(void) { return argProgName; } /** * commandLineGet_scalingColumn: * * Get the column used to scale nodes, if any given. * * Since: 3.7 * * Returns: -1 if not provided, or a column id. */ int commandLineGet_scalingColumn(void) { return argScalingColumn; } /** * commandLineGet_geodiff: * * Get the name of the file to compute the difference from, if any given. * * Since: 3.8 * * Returns: #NULL if not provided, or a filename. */ const gchar* commandLineGet_geodiff(void) { return argGeoDiff; } /** * commandLineGet_phononMode: * * Get the desired phonon mode. * * Since: 3.8 * * Returns: -1 if option is not set. **/ gint commandLineGet_phononMode(void) { return argPhononMode; } /** * commandLineGet_phononTime: * * Get the time offset to apply dislacement from phonons. * * Since: 3.8 * * Returns: -1.f if the option is not set. **/ gfloat commandLineGet_phononTime(void) { return argPhononTime; } /** * commandLineGet_phononAmpl: * * Get the amplitude to apply dislacement from phonons. * * Since: 3.8 * * Returns: -1.f if the option is not set. **/ gfloat commandLineGet_phononAmpl(void) { return argPhononAmpl; } /** * commandLineFree_all: * * Release all allocated memory related to the command line options. * * Since: 3.5 */ void commandLineFree_all(void) { DBG_fprintf(stderr, "Command Line: free all.\n - the arguments\n"); if (argProgName) g_free(argProgName); if (argFileName) g_free(argFileName); if (argResources) g_free(argResources); if (argSpinFileName) g_free(argSpinFileName); if (argExportFileName) g_free(argExportFileName); if (argWindowMode) g_free(argWindowMode); if (argValueFile) g_free(argValueFile); if (argColorizeFileName) g_free(argColorizeFileName); if (argColorizeRange) g_array_free(argColorizeRange, TRUE); if (argScalarfieldFilenames) g_list_free_full(argScalarfieldFilenames, g_free); if (argIsoVisuSurfaceFileName) g_free(argIsoVisuSurfaceFileName); if (argIsoValues) g_free(argIsoValues); if (argIsoNames) g_strfreev(argIsoNames); if (argMapVisuPlaneId) g_free(argMapVisuPlaneId); if (argIsoLinesColor) g_free(argIsoLinesColor); if (argBgImageFile) g_free(argBgImageFile); if (argOptionTable) g_hash_table_destroy(argOptionTable); if (argVisuPlanesFileName) g_free(argVisuPlanesFileName); if (argGeoDiff) g_free(argGeoDiff); g_free(argMapMinMax); DBG_fprintf(stderr, " - the descriptions\n"); g_string_free(short_options, TRUE); g_free(ext_options); g_free(long_options); } v_sim-3.8.0/src/visu_commandLine.h000066400000000000000000000251071370110300500170660ustar00rootroot00000000000000/* EXTRAITS DE LA LICENCE Copyright CEA, contributeurs : Luc BILLARD et Damien CALISTE, laboratoire L_Sim, (2001-2005) Adresse mèl : BILLARD, non joignable par mèl ; CALISTE, damien P caliste AT cea P fr. Ce logiciel est un programme informatique servant à visualiser des structures atomiques dans un rendu pseudo-3D. Ce logiciel est régi par la licence CeCILL soumise au droit français et respectant les principes de diffusion des logiciels libres. Vous pouvez utiliser, modifier et/ou redistribuer ce programme sous les conditions de la licence CeCILL telle que diffusée par le CEA, le CNRS et l'INRIA sur le site "http://www.cecill.info". Le fait que vous puissiez accéder à cet en-tête signifie que vous avez pris connaissance de la licence CeCILL, et que vous en avez accepté les termes (cf. le fichier Documentation/licence.fr.txt fourni avec ce logiciel). */ /* LICENCE SUM UP Copyright CEA, contributors : Luc BILLARD et Damien CALISTE, laboratoire L_Sim, (2001-2005) E-mail address: BILLARD, not reachable any more ; CALISTE, damien P caliste AT cea P fr. This software is a computer program whose purpose is to visualize atomic configurations in 3D. This software is governed by the CeCILL license under French law and abiding by the rules of distribution of free software. You can use, modify and/ or redistribute the software under the terms of the CeCILL license as circulated by CEA, CNRS and INRIA at the following URL "http://www.cecill.info". The fact that you are presently reading this means that you have had knowledge of the CeCILL license and that you accept its terms. You can find a copy of this licence shipped with this software at Documentation/licence.en.txt. */ #ifndef VISU_COMMANDLINE_H #define VISU_COMMANDLINE_H /* This .h and .c are here to read parameters from the command line. */ #include #include #include /** * VISU_COMMAND_LINE_ERROR: (skip) * * Internal function for error handling. */ #define VISU_COMMAND_LINE_ERROR visu_command_line_getErrorQuark() GQuark visu_command_line_getErrorQuark(); /** * VisuCommandLineErrorFlag: * @ERROR_ARGUMENT: invalid argument. * * Possible errors when reading a file with column data. */ typedef enum { ERROR_ARGUMENT } VisuCommandLineErrorFlag; /** * commandLineParse: * @argc: the number of arguments. * @argv: the values of all arguments. * * This method is called at startup to parse the command line * and store all important information. If --help is given, or an unknown * option, a little help is printed on the standard output. * * Returns: 0 if everything goes well. */ int commandLineParse(int argc, char **argv); /** * commandLineExport: * @filename: a path to a filename to create ; * @error: a location to store a possible error. * * Export the known command line options to an XML file. * * Returns: TRUE on success. * * Since: 3.5 */ gboolean commandLineExport(const gchar *filename, GError **error); /** * commandLineGet_ArgFilename: * * This method retrieves the first argument. All other arguments are ignored. * * Returns: the value of the first argument. */ char* commandLineGet_ArgFilename(void); /** * commandLineGet_ArgSpinFileName: * * This method retrieves the second argument. All other arguments are ignored. * * Returns: the value of the second argument. */ char* commandLineGet_ArgSpinFileName(void); /** * commandLineGet_ExportFileName: * * This method retrieves the value of the option --export or -e. This value must * be a valid filename, with an extension known by V_Sim to do the export. * * Returns: the value of the option --export. */ char* commandLineGet_ExportFileName(void); /** * commandLineGet_WithGtk: * * This method tells V_Sim is the GTK interface is needed or not. * * Returns: 1 if the interface is needed. */ int commandLineGet_WithGtk(void); /** * commandLineGet_XWindowGeometry: * @width: an integer to stores the desired width. * @height: an integer to stores the desired height. * * This method retrieves the values of the option --geometry or -g. * These values must be formatted with the following format : &dx&d and they give * the size of the rendering window. * */ void commandLineGet_XWindowGeometry(int *width, int *height); /** * commandLineGet_colorizeFileName: * * This method retrieves the value of the option --colorize or -c. This value must * be a valid filename. If this option is called, V_Sim actually enable * the colorization, even if parameter file doesn't. * * Returns: the value of the option --colorize. */ const gchar* commandLineGet_colorizeSource(gboolean *isFile); /** * commandLineGet_colorizeColUsed: * * This method retrieves the value of the option --use-column or -u. This value consists * of three integer values. * * Returns: the three values of the option --use-column, or NULL if this option * is not present. */ int* commandLineGet_colorizeColUsed(void); /** * commandLineGet_colorizePresetColor: * * DEPRECATED, use commandLineGet_presetColor() instead. * * Returns: the value of option --color-preset if set, -1 if not. */ #define commandLineGet_colorizePresetColor() commandLineGet_presetColor(); /** * commandLineGet_presetColor: * * This method returns the value of option --color-preset. * * Returns: the value of option --color-preset if set, -1 if not. */ int commandLineGet_presetColor(void); float* commandLineGet_translation(gboolean *boxTranslation); /** * commandLineGet_extension: * * This method retrieves the value of the option --expand or -x. This value consists * of three floating values. * * Returns: the three values of the option --expand. */ float* commandLineGet_extension(void); /** * commandLineGet_planesFileName: * * This method retrieves the value of the option --planes or -p. This value must * be a valid filename. * * Returns: the value of the option --planes. */ gchar* commandLineGet_planesFileName(void); /** * commandLineGet_spinHidingMode: * * This method retrieves if the option --hiding-mode or -m has been set. * * Returns: the value of the option. */ int commandLineGet_spinHidingMode(void); /** * commandLineGet_spinAndAtomic: * * This method retrieves if the option --spin-and-atomic or -a has been set. * * Returns: the TRUE if the option exists. */ gboolean commandLineGet_spinAndAtomic(void); /** * commandLineGet_isoValues: * @nb: a location to store an integer. * * This method retrieves the values of the option --ios-values or -v. * * Returns: an array with the values of a size stored in @nb. */ float* commandLineGet_isoValues(int *nb); /** * commandLineGet_isoNames: * @nb: a location to store an integer. * * This method retrieves the names associated to the values of the option --ios-values or -v. * It returns an array of size @nb, but not all element are set since names are not * mandatory. The @nb value is guarantied to by equal to the one returned by * commandLineGet_isoValues(void); * * Returns: an array with the values of a size stored in @nb. */ const gchar** commandLineGet_isoNames(int *nb); const GList* commandLineGet_scalarFieldFileNames(void); /** * commandLineGet_isoVisuSurfaceFileName: * * This method retrieves the filename given by the option --iso-surfaces or -i. * * Returns: a filename, the string is owned by V_Sim. */ gchar* commandLineGet_isoVisuSurfaceFileName(void); /** * commandLineGet_fitToBox: * * This method gets if the surface should be adapted to the bounding box of the structure. * * Returns: TRUE if the surface should be fitted. */ gboolean commandLineGet_fitToBox(void); /** * commandLineGet_resourcesFile: * * This method gets if a resources file has been given. * * Returns: the name (owned by V_Sim) of the given resources file or NULL if none * was present. */ gchar* commandLineGet_resourcesFile(void); /** * commandLineGet_options: * * This method gets the contents of all -o options. The value is first parsed as * letters to check for a boolean value (F/T), then, a float is used and finally * an integer. If nothing parsed, the option is dismissed. * * Returns: a #GHashTable pointer owned by V_Sim. */ GHashTable* commandLineGet_options(void); int* commandLineGet_coloredMap(void); /** * commandLineGet_logScale: * * Retrieve if a log scale is required for various plots. * * Returns: the logscale method. */ ToolMatrixScalingFlag commandLineGet_logScale(void); /** * commandLineGet_nIsoLines: * * Retrieve if the user asked for isolines on the coloured map (see * commandLineGet_coloredMap()). * * Returns: a positive number if some isolines are required, 0 if not. */ guint commandLineGet_nIsoLines(void); /** * commandLineGet_bgImage: * * Retrieve if the filename to be loaded as a background image. * * Returns: a string or NULL if option is not used. */ gchar* commandLineGet_bgImage(void); /** * commandLineGet_isoLinesColor: * * Retrieve the chosen colour for the iso-lines. * * Returns: an array of three floats or NULL if the colour is auto. * * Since: 3.5 */ float* commandLineGet_isoLinesColor(void); /** * commandLineGet_windowMode: * * Retrieve the windowing mode for V_Sim, 'classic' with the two * rendering and command panel windows ; 'oneWindow' with a joined * version of the two windows or 'renderOnly' with only the rendering window. * * Returns: one of the three strings. * * Since: 3.5 */ gchar* commandLineGet_windowMode(void); /** * commandLineGet_iSet: * * Retrieve the desired id for multi dataset file to render. * * Returns: 0 as default value. * * Since: 3.5 */ guint commandLineGet_iSet(void); /** * commandLineGet_valueFile: * * Retrieve the name of a possible value file, if any has been given. * * Returns: a path (absolute) or NULL if the option has not been * passed. Data are static. * * Since: 3.5 */ gchar* commandLineGet_valueFile(void); void commandLineFree_all(void); guint commandLineGet_mapPrecision(void); float* commandLineGet_mapMinMax(void); typedef struct _VisuColorRange VisuColorRange; /** * VisuColorRange: * @column: a column identifgier. * @min: the minimum value for clamping. * @max: the maximum value for clamping. * * A structure to pass information from the command line to the code * on clamping values for column. * * Since: 3.8 */ struct _VisuColorRange { int column; float min, max; }; GArray* commandLineGet_colorMinMax(void); const gchar* commandLineGet_programName(void); int commandLineGet_scalingColumn(void); const gchar* commandLineGet_geodiff(void); gint commandLineGet_phononMode(void); gfloat commandLineGet_phononTime(void); gfloat commandLineGet_phononAmpl(void); #endif v_sim-3.8.0/src/visu_configFile.c000066400000000000000000002300501370110300500166730ustar00rootroot00000000000000/* EXTRAITS DE LA LICENCE Copyright CEA, contributeurs : Luc BILLARD et Damien CALISTE, laboratoire L_Sim, (2001-2005) Adresse mèl : BILLARD, non joignable par mèl ; CALISTE, damien P caliste AT cea P fr. Ce logiciel est un programme informatique servant à visualiser des structures atomiques dans un rendu pseudo-3D. Ce logiciel est régi par la licence CeCILL soumise au droit français et respectant les principes de diffusion des logiciels libres. Vous pouvez utiliser, modifier et/ou redistribuer ce programme sous les conditions de la licence CeCILL telle que diffusée par le CEA, le CNRS et l'INRIA sur le site "http://www.cecill.info". Le fait que vous puissiez accéder à cet en-tête signifie que vous avez pris connaissance de la licence CeCILL, et que vous en avez accepté les termes (cf. le fichier Documentation/licence.fr.txt fourni avec ce logiciel). */ /* LICENCE SUM UP Copyright CEA, contributors : Luc BILLARD et Damien CALISTE, laboratoire L_Sim, (2001-2005) E-mail address: BILLARD, not reachable any more ; CALISTE, damien P caliste AT cea P fr. This software is a computer program whose purpose is to visualize atomic configurations in 3D. This software is governed by the CeCILL license under French law and abiding by the rules of distribution of free software. You can use, modify and/ or redistribute the software under the terms of the CeCILL license as circulated by CEA, CNRS and INRIA at the following URL "http://www.cecill.info". The fact that you are presently reading this means that you have had knowledge of the CeCILL license and that you accept its terms. You can find a copy of this licence shipped with this software at Documentation/licence.en.txt. */ #include "visu_configFile.h" #include "visu_tools.h" #include "visu_basic.h" #include "visu_commandLine.h" #include "coreTools/toolConfigFile.h" #include #include #include /* For the access markers R_OK, W_OK ... */ /** * SECTION:visu_configFile * @short_description: Defines methods to access (read/write) to * config files and to create different entries. * * V_Sim uses two different configuration files. The first * stores the configuration of the program itself and is called * parameters file. The second stores differents values that control * the way files are rendered. It is called resources file. For * example, their is an entry in the parameters file that controls * your favorite rendering method ; and there is an entry in the * resources file that codes that vacancy elements are rendered by * cube in the atomic rendering method. Most methods of this part uses * a first argument usually called 'kind', that control if the method * will apply on the parameters file or on the resources * file. #VISU_CONFIG_FILE_PARAMETER and #VISU_CONFIG_FILE_RESOURCE are * the two flags that should be used for the 'kind' argument. * * There are different paths where these files can be * stored. These paths are stored in V_Sim with an order : for example * parameters file are first looked for in the current working * directory, then in the $HOME/.v_sim directory and finally in the * installation directory. This is transparent for the user and * visu_config_file_getValidPath() is the right method to access to the * best readable configuration file. * * Different part of V_Sim can add entries in these files. The * method visu_config_file_addEntry() is designed to this purpose. The * entries are defined by their name and they appear in the * configuration file as 'name:' followed by the data associated to * this entry. In the parameters file, the data are on the same * line. In the resources file, the data begin the line after and can * be longer that one line. When a configuration file is read, the * method associated to each entry (VisuConfigFileReadFunc()) is * called with a copy of their data lines. The method * visu_config_file_addExportFunction() should be used to add a callback * when the configurations files are written, then each part of V_Sim * that have entries can put some lines in the configuration * files. */ #define PARAMETER_HEADER "#V_Sim parameters file" #define RESOURCE_HEADER "#V_Sim resources file" #define VERSION_HEADER "3.0" static const gchar *RESOURCES_FILENAMES[] = {"v_sim.res.xml", "v_sim.res", (gchar*)0}; static const gchar *PARAMETERS_FILENAMES[] = {"v_sim.par", (gchar*)0}; #define FLAG_RESOURCES_PATH "main_resourcesPath" #define DESC_RESOURCES_PATH "Favorite paths to find and save the resources file ; chain[:chain]" #define DEFAULT_RESOURCES_PATH "" static gboolean readResourcesPaths(VisuConfigFileEntry *entry, gchar **lines, int nbLines, int position, GError **error); static void exportResourcesPaths(GString *data, VisuData *dataObj); static void _addPath(VisuConfigFile *conf, char* dir); /** * VisuConfigFileEntry: * * This is the common name of the structure. */ struct _VisuConfigFileEntry { guint refCount; /* Name of the key. */ gchar *key; gchar *description; GQuark kquark; /* Quark associated to the key. */ /* Version, default is 3.0. */ float version; /* If set, entry is obsolete and newKey should replaces it. */ gchar *newKey; /* A parameter or a resource */ int kind; /* Number of line used by this resources. This is not used if the entry is a parameter since, parameters are on the same line than the key and are one line. */ guint nbLines; /* This method is called when a file is read and the entry is found. */ VisuConfigFileReadFunc read; gboolean withLabel; gchar *label; guint nValues; guint iToken; gchar **tokens; gpointer storage; union { int i[2]; float f[2]; } range; VisuConfigFileEnumFunc toEnum; gchar *errMess; /* Tag, tags are used to ignore or not some entries when a file is read. */ gchar *tag; }; typedef enum { _format_raw, _format_xml } _format_export; _format_export format = _format_raw; struct writeFunc_struct { VisuConfigFileExportFunc writeFunc; }; /* This hashtable stores all the known entries. The keys are the name of the entry (its key), and the value is a pointer to a VisuConfigFileEntry. */ static GHashTable *knownTags = NULL; static VisuConfigFile *resources = NULL, *parameters = NULL; /* Local methods. */ static VisuConfigFileEntry* entry_ref(VisuConfigFileEntry *entry); static void entry_unref(VisuConfigFileEntry *entry); /* Generic reading routines. */ static gboolean _readTokens(VisuConfigFileEntry *entry, gchar **lines, int nbLines, int position, GError **error); static gboolean _readBooleanv(VisuConfigFileEntry *entry, gchar **lines, int nbLines, int position, GError **error); static gboolean _readIntv(VisuConfigFileEntry *entry, gchar **lines, int nbLines, int position, GError **error); static gboolean _readFloatv(VisuConfigFileEntry *entry, gchar **lines, int nbLines, int position, GError **error); static gboolean _readStipplev(VisuConfigFileEntry *entry, gchar **lines, int nbLines, int position, GError **error); static gboolean _readEnum(VisuConfigFileEntry *entry, gchar **lines, int nbLines, int position, GError **error); static gboolean _readString(VisuConfigFileEntry *entry, gchar **lines, int nbLines, int position, GError **error); static gint compareStringsInGList(gconstpointer a, gconstpointer b) { return strcmp((char*)a, (char*)b); } /** * visu_config_file_entry_get_type: * * Create and retrieve a #GType for a #VisuConfigFileEntry object. * * Since: 3.7 * * Returns: a new type for #VisuConfigFileEntry structures. */ GType visu_config_file_entry_get_type(void) { static GType g_define_type_id = 0; if (g_define_type_id == 0) g_define_type_id = g_boxed_type_register_static("VisuConfigFileEntry", (GBoxedCopyFunc)entry_ref, (GBoxedFreeFunc)entry_unref); return g_define_type_id; } static VisuConfigFileEntry* entry_init(const gchar *key, const gchar *description, VisuConfigFileKind kind, guint nbLines) { VisuConfigFileEntry *entry; g_return_val_if_fail(key && *key, (VisuConfigFileEntry*)0); g_return_val_if_fail(description, (VisuConfigFileEntry*)0); g_return_val_if_fail(nbLines > 0 && (kind == VISU_CONFIG_FILE_KIND_PARAMETER || kind == VISU_CONFIG_FILE_KIND_RESOURCE), (VisuConfigFileEntry*)0); entry = g_malloc(sizeof(VisuConfigFileEntry)); entry->refCount = 1; entry->key = g_strdup(key); entry->kquark = g_quark_from_static_string(entry->key); entry->description = g_strdup(description); entry->kind = kind; if (kind == VISU_CONFIG_FILE_KIND_PARAMETER) entry->nbLines = 1; else entry->nbLines = nbLines; entry->withLabel = FALSE; entry->label = (gchar*)0; entry->storage = (gpointer)0; entry->tokens = (gchar**)0; entry->errMess = (gchar*)0; entry->tag = (gchar*)0; entry->newKey = (gchar*)0; entry->version = 3.0f; return entry; } static VisuConfigFileEntry* entry_ref(VisuConfigFileEntry *entry) { if (!entry) return (VisuConfigFileEntry*)0; entry->refCount += 1; return entry; } static void entry_unref(VisuConfigFileEntry *entry) { entry->refCount -= 1; if (!entry->refCount) { g_free(entry->key); g_free(entry->description); g_free(entry->newKey); g_free(entry->tag); g_free(entry->label); g_free(entry->errMess); g_strfreev(entry->tokens); g_free(entry); } } /** * VisuConfigFile: * * Structure used to define #VisuConfigFile objects. * * Since: 3.8 */ struct _VisuConfigFilePrivate { VisuConfigFileKind kind; /* This hashtable stores all the known entries. The keys are the name of the entry (its key), and the value is a pointer to a VisuConfigFileEntry. */ GHashTable *entryList; GList *exportList; /* Store the paths to where it is possible to store and/or read resource files. This list is ordered and first element is the most prefered path. */ GList *paths; gchar *source; }; enum { ENTRYPARSED_SIGNAL, VISU_NB_SIGNAL }; static guint _signals[VISU_NB_SIGNAL]; static void visu_config_file_finalize (GObject* obj); G_DEFINE_TYPE_WITH_CODE(VisuConfigFile, visu_config_file, VISU_TYPE_OBJECT, G_ADD_PRIVATE(VisuConfigFile)) static void visu_config_file_class_init(VisuConfigFileClass *klass) { /* Connect the overloading methods. */ G_OBJECT_CLASS(klass)->finalize = visu_config_file_finalize; /** * VisuConfigFile::parsed: * @visuObj: the object emitting the signal. * @key: the key that has been parsed. * * The entry @key of a configuration file has just been successfully parsed. * * Since: 3.7 */ _signals[ENTRYPARSED_SIGNAL] = g_signal_new("parsed", G_TYPE_FROM_CLASS (klass), G_SIGNAL_RUN_LAST | G_SIGNAL_NO_RECURSE | G_SIGNAL_NO_HOOKS | G_SIGNAL_DETAILED, 0 , NULL, NULL, g_cclosure_marshal_VOID__BOXED, G_TYPE_NONE, 1, VISU_TYPE_CONFIG_FILE_ENTRY); knownTags = g_hash_table_new_full(g_str_hash, g_str_equal, NULL, NULL); } static void visu_config_file_init(VisuConfigFile *obj) { obj->priv = visu_config_file_get_instance_private(obj); obj->priv->entryList = g_hash_table_new_full(g_str_hash, g_str_equal, NULL, (GDestroyNotify)entry_unref); obj->priv->exportList = (GList*)0; obj->priv->source = (gchar*)0; obj->priv->paths = (GList*)0; obj->priv->paths = g_list_prepend(obj->priv->paths, g_strdup(V_SIM_DATA_DIR)); obj->priv->paths = g_list_prepend(obj->priv->paths, g_strdup(V_SIM_OLD_LOCAL_CONF_DIR)); obj->priv->paths = g_list_prepend(obj->priv->paths, g_strdup(V_SIM_LOCAL_CONF_DIR)); obj->priv->paths = g_list_prepend(obj->priv->paths, g_get_current_dir()); } static void visu_config_file_finalize(GObject *obj) { VisuConfigFile *conf; conf = VISU_CONFIG_FILE(obj); g_hash_table_destroy(conf->priv->entryList); g_list_free(conf->priv->exportList); g_list_free_full(conf->priv->paths, g_free); g_free(conf->priv->source); /* Chain up to the parent class */ G_OBJECT_CLASS(visu_config_file_parent_class)->finalize(obj); } /** * visu_config_file_getStatic: * @kind: a kind of configuration file. * * Retrieve the instance used by V_Sim to read resource or parameter files. * * Since: 3.8 * * Returns: (transfer none): a #VisuConfigFile object, owned by V_Sim. **/ VisuConfigFile* visu_config_file_getStatic(VisuConfigFileKind kind) { if (kind == VISU_CONFIG_FILE_KIND_PARAMETER) { if (!parameters) { parameters = g_object_new(VISU_TYPE_CONFIG_FILE, NULL); parameters->priv->kind = VISU_CONFIG_FILE_KIND_PARAMETER; /* Private data. */ visu_config_file_addEntry(parameters, FLAG_RESOURCES_PATH, DESC_RESOURCES_PATH, 1, readResourcesPaths); visu_config_file_addExportFunction(parameters, exportResourcesPaths); } return parameters; } if (kind == VISU_CONFIG_FILE_KIND_RESOURCE) { if (!resources) { resources = g_object_new(VISU_TYPE_CONFIG_FILE, NULL); resources->priv->kind = VISU_CONFIG_FILE_KIND_RESOURCE; } return resources; } return (VisuConfigFile*)0; } static gboolean entry_register(VisuConfigFile *conf, VisuConfigFileEntry *entry) { DBG_fprintf(stderr, "Visu ConfigFile: going to add key '%s'.\n", entry->key); if (g_hash_table_lookup(conf->priv->entryList, (gpointer)entry->key)) return FALSE; /* Store it. */ g_hash_table_insert(conf->priv->entryList, (gpointer)entry->key, (gpointer)entry); return TRUE; } /** * visu_config_file_ignoreEntry: * @conf: a #VisuConfigFile object ; * @key: a string (should not be NULL) ; * @nbLines: an integer ; * * Create a #VisuConfigFileEntry that will ignore @key when found in a * configuration file. This is used for deprecated keys. * * Since: 3.8 * * Returns: the newly created #VisuConfigFileEntry object. **/ VisuConfigFileEntry* visu_config_file_ignoreEntry(VisuConfigFile *conf, const gchar *key, guint nbLines) { VisuConfigFileEntry *entry; g_return_val_if_fail(VISU_IS_CONFIG_FILE(conf), (VisuConfigFileEntry*)0); entry = entry_init(key, "Ignored entry", conf->priv->kind, nbLines); if (!entry) return (VisuConfigFileEntry*)0; entry->read = NULL; if (!entry_register(conf, entry)) { g_free(entry); entry = (VisuConfigFileEntry*)0; g_warning("entry '%s' already exists!", key); } return entry; } /** * visu_config_file_addEntry: * @conf: a #VisuConfigFile object ; * @key: a string (should not be NULL) ; * @description: (allow-none): a string (can be NULL) ; * @nbLines: an integer ; * @readFunc: (scope call): a VisuConfigFileReadFunc. * * This creates a new #VisuConfigFileEntry object with the given * values. The key and description arguments are copied. * * Returns: the newly created #VisuConfigFileEntry object. */ VisuConfigFileEntry* visu_config_file_addEntry(VisuConfigFile *conf, const gchar *key, const gchar* description, int nbLines, VisuConfigFileReadFunc readFunc) { VisuConfigFileEntry *entry; g_return_val_if_fail(VISU_IS_CONFIG_FILE(conf), (VisuConfigFileEntry*)0); entry = entry_init(key, description, conf->priv->kind, nbLines); if (!entry) return (VisuConfigFileEntry*)0; entry->read = readFunc; if (!entry_register(conf, entry)) { g_free(entry); entry = (VisuConfigFileEntry*)0; g_warning("entry '%s' already exists!", key); } return entry; } /** * visu_config_file_addTokenizedEntry: * @conf: a #VisuConfigFile object ; * @key: a string (should not be %NULL) ; * @description: (allow-none): a string (can be %NULL) ; * @labelled: a boolean. * * Defines a new #VisuConfigFileEntry object characterized by * @key. When @key is found in a configuration file, the data line is * separated into tokens that can be retrieved later with * visu_config_file_entry_popToken() for instance. If @labelled is * %TRUE, the associated label to an entry in the file can be later * retrieved with visu_config_file_entry_getLabel(). * * Since: 3.8 * * Returns: the newly created #VisuConfigFileEntry object. **/ VisuConfigFileEntry* visu_config_file_addTokenizedEntry(VisuConfigFile *conf, const gchar *key, const gchar* description, gboolean labelled) { VisuConfigFileEntry *entry; g_return_val_if_fail(VISU_IS_CONFIG_FILE(conf), (VisuConfigFileEntry*)0); entry = entry_init(key, description, conf->priv->kind, 1); if (!entry) return (VisuConfigFileEntry*)0; entry->read = _readTokens; entry->withLabel = labelled; if (!entry_register(conf, entry)) { g_free(entry); entry = (VisuConfigFileEntry*)0; g_warning("entry '%s' already exists!", key); } return entry; } /** * visu_config_file_addBooleanEntry: * @conf: a #VisuConfigFile object ; * @key: a string (should not be NULL) ; * @description: (allow-none): a string (can be NULL) ; * @location: a pointer where to store a boolean when the entry is * parsed. * @labelled: a boolean. * * Defines a #VisuConfigFileEntry that will be a single boolean to * read and to store in @location. If @labelled is %TRUE, it retrieves * and store a string before the boolean value. It can be accessed * later with visu_config_file_entry_getLabel(). * * Since: 3.7 * * Returns: (transfer full): the newly created #VisuConfigFileEntry object. **/ VisuConfigFileEntry* visu_config_file_addBooleanEntry(VisuConfigFile *conf, const gchar *key, const gchar* description, gboolean *location, gboolean labelled) { VisuConfigFileEntry *entry; g_return_val_if_fail(location, (VisuConfigFileEntry*)0); g_return_val_if_fail(VISU_IS_CONFIG_FILE(conf), (VisuConfigFileEntry*)0); entry = entry_init(key, description, conf->priv->kind, 1); if (!entry) return (VisuConfigFileEntry*)0; entry->read = _readBooleanv; entry->storage = (gpointer)location; entry->nValues = 1; entry->withLabel = labelled; if (!entry_register(conf, entry)) { g_free(entry); entry = (VisuConfigFileEntry*)0; g_warning("entry '%s' already exists!", key); } return entry; } /** * visu_config_file_addBooleanArrayEntry: * @conf: a #VisuConfigFile object ; * @key: a string (should not be NULL) ; * @description: (allow-none): a string (can be NULL) ; * @nValues: the number of floats to read. * @location: a pointer where to store booleans when the entry is * parsed. * @labelled: a boolean. * * Defines a #VisuConfigFileEntry that will be several booleans to * read and to store in @location. If @labelled is %TRUE, it retrieves * and store a string before the boolean value. It can be accessed * later with visu_config_file_entry_getLabel(). * * Since: 3.8 * * Returns: (transfer full): the newly created #VisuConfigFileEntry object. **/ VisuConfigFileEntry* visu_config_file_addBooleanArrayEntry(VisuConfigFile *conf, const gchar *key, const gchar* description, guint nValues, gboolean *location, gboolean labelled) { VisuConfigFileEntry *entry; g_return_val_if_fail(location, (VisuConfigFileEntry*)0); g_return_val_if_fail(VISU_IS_CONFIG_FILE(conf), (VisuConfigFileEntry*)0); entry = entry_init(key, description, conf->priv->kind, 1); if (!entry) return (VisuConfigFileEntry*)0; entry->read = _readBooleanv; entry->storage = (gpointer)location; entry->nValues = nValues; entry->withLabel = labelled; if (!entry_register(conf, entry)) { g_free(entry); entry = (VisuConfigFileEntry*)0; g_warning("entry '%s' already exists!", key); } return entry; } /** * visu_config_file_addIntegerArrayEntry: * @conf: a #VisuConfigFile object ; * @key: a string (should not be NULL) ; * @description: (allow-none): a string (can be NULL) ; * @nValues: the number of floats to read. * @location: a pointer where to store floats when the entry is * parsed. * @clamp: the min and max values allowed. * @labelled: TRUE if the entry has a label. * * Defines a #VisuConfigFileEntry that will parse @nValues usable for stipple and * store them consecutively in @location. * * Since: 3.8 * * Returns: (transfer full): the newly created #VisuConfigFileEntry object. **/ VisuConfigFileEntry* visu_config_file_addIntegerArrayEntry(VisuConfigFile *conf, const gchar *key, const gchar* description, guint nValues, int *location, int clamp[2], gboolean labelled) { VisuConfigFileEntry *entry; g_return_val_if_fail(location, (VisuConfigFileEntry*)0); g_return_val_if_fail(VISU_IS_CONFIG_FILE(conf), (VisuConfigFileEntry*)0); entry = entry_init(key, description, conf->priv->kind, 1); if (!entry) return (VisuConfigFileEntry*)0; entry->read = _readIntv; entry->storage = (gpointer)location; entry->nValues = nValues; entry->range.i[0] = clamp[0]; entry->range.i[1] = clamp[1]; entry->withLabel = labelled; if (!entry_register(conf, entry)) { g_free(entry); entry = (VisuConfigFileEntry*)0; g_warning("entry '%s' already exists!", key); } return entry; } /** * visu_config_file_addFloatArrayEntry: * @conf: a #VisuConfigFile object ; * @key: a string (should not be NULL) ; * @description: (allow-none): a string (can be NULL) ; * @nValues: the number of floats to read. * @location: a pointer where to store floats when the entry is * parsed. * @clamp: the min and max values allowed. * @labelled: a boolean. * * Defines a #VisuConfigFileEntry that will parse @nValues floats and * store them consecutively in @location. The parsed values are * checked to be in @clamp. * * Since: 3.7 * * Returns: (transfer full): the newly created #VisuConfigFileEntry object. **/ VisuConfigFileEntry* visu_config_file_addFloatArrayEntry(VisuConfigFile *conf, const gchar *key, const gchar* description, guint nValues, float *location, float clamp[2], gboolean labelled) { VisuConfigFileEntry *entry; g_return_val_if_fail(location, (VisuConfigFileEntry*)0); g_return_val_if_fail(VISU_IS_CONFIG_FILE(conf), (VisuConfigFileEntry*)0); entry = entry_init(key, description, conf->priv->kind, 1); if (!entry) return (VisuConfigFileEntry*)0; entry->read = _readFloatv; entry->storage = (gpointer)location; entry->nValues = nValues; entry->range.f[0] = clamp[0]; entry->range.f[1] = clamp[1]; entry->withLabel = labelled; if (!entry_register(conf, entry)) { g_free(entry); entry = (VisuConfigFileEntry*)0; g_warning("entry '%s' already exists!", key); } return entry; } /** * visu_config_file_addStippleArrayEntry: * @conf: a #VisuConfigFile object ; * @key: a string (should not be NULL) ; * @description: (allow-none): a string (can be NULL) ; * @nValues: the number of floats to read. * @location: a pointer where to store floats when the entry is * parsed. * * Defines a #VisuConfigFileEntry that will parse @nValues usable for stipple and * store them consecutively in @location. * * Since: 3.8 * * Returns: (transfer full): the newly created #VisuConfigFileEntry object. **/ VisuConfigFileEntry* visu_config_file_addStippleArrayEntry(VisuConfigFile *conf, const gchar *key, const gchar* description, guint nValues, guint16 *location) { VisuConfigFileEntry *entry; g_return_val_if_fail(location, (VisuConfigFileEntry*)0); g_return_val_if_fail(VISU_IS_CONFIG_FILE(conf), (VisuConfigFileEntry*)0); entry = entry_init(key, description, conf->priv->kind, 1); if (!entry) return (VisuConfigFileEntry*)0; entry->read = _readStipplev; entry->storage = (gpointer)location; entry->nValues = nValues; if (!entry_register(conf, entry)) { g_free(entry); entry = (VisuConfigFileEntry*)0; g_warning("entry '%s' already exists!", key); } return entry; } /** * visu_config_file_addEnumEntry: * @conf: a #VisuConfigFile object ; * @key: a string (should not be NULL) ; * @description: (allow-none): a string (can be NULL) ; * @location: a location to store an enum value. * @toEnum: (scope call): a method to convert a string to an enum value. * @labelled: a boolean. * * Defines a #VisuConfigFileEntry that will parse a string and convert * it to an enum value with @toEnum function and store it in * @location. * * Since: 3.8 * * Returns: (transfer full): the newly created #VisuConfigFileEntry object. **/ VisuConfigFileEntry* visu_config_file_addEnumEntry(VisuConfigFile *conf, const gchar *key, const gchar* description, guint *location, VisuConfigFileEnumFunc toEnum, gboolean labelled) { VisuConfigFileEntry *entry; g_return_val_if_fail(location, (VisuConfigFileEntry*)0); g_return_val_if_fail(VISU_IS_CONFIG_FILE(conf), (VisuConfigFileEntry*)0); entry = entry_init(key, description, conf->priv->kind, 1); if (!entry) return (VisuConfigFileEntry*)0; entry->read = _readEnum; entry->storage = (gpointer)location; entry->toEnum = toEnum; entry->withLabel = labelled; if (!entry_register(conf, entry)) { g_free(entry); entry = (VisuConfigFileEntry*)0; g_warning("entry '%s' already exists!", key); } return entry; } /** * visu_config_file_addStringEntry: * @conf: a #VisuConfigFile object ; * @key: a string (should not be NULL) ; * @description: (allow-none): a string (can be NULL) ; * @location: a pointer where to store a string when the entry is * parsed. * * Defines a #VisuConfigFileEntry that will be a string to * read and to store in @location. If @location already contains a * string, it is g_free(). * * Since: 3.7 * * Returns: (transfer full): the newly created #VisuConfigFileEntry object. **/ VisuConfigFileEntry* visu_config_file_addStringEntry(VisuConfigFile *conf, const gchar *key, const gchar* description, gchar **location) { VisuConfigFileEntry *entry; g_return_val_if_fail(location, (VisuConfigFileEntry*)0); g_return_val_if_fail(VISU_IS_CONFIG_FILE(conf), (VisuConfigFileEntry*)0); entry = entry_init(key, description, conf->priv->kind, 1); if (!entry) return (VisuConfigFileEntry*)0; entry->read = _readString; entry->storage = (gpointer)location; if (!entry_register(conf, entry)) { g_free(entry); entry = (VisuConfigFileEntry*)0; g_warning("entry '%s' already exists!", key); } return entry; } /** * visu_config_file_getEntries: * @conf: a #VisuConfigFile object ; * * This routine should be used for introspections purpose, to know * what resources or parameters are available. * * Returns: (element-type utf8) (transfer none): a #GList own by V_Sim. */ GList* visu_config_file_getEntries(VisuConfigFile *conf) { g_return_val_if_fail(VISU_IS_CONFIG_FILE(conf), (GList*)0); return g_hash_table_get_values(conf->priv->entryList); } /** * visu_config_file_addKnownTag: * @tag: a string (not nul or empty). * * If parameter entries have a tag, they are ignored except if their tag * has been declared using this method. */ void visu_config_file_addKnownTag(gchar* tag) { g_return_if_fail(tag && *tag); if (!knownTags) g_type_class_ref(VISU_TYPE_CONFIG_FILE); g_hash_table_insert(knownTags, (gpointer)tag, GINT_TO_POINTER(1)); } /** * visu_config_file_addExportFunction: * @conf: a #VisuConfigFile object ; * @writeFunc: (scope call): a VisuConfigFileExportFunc method. * * This stores the @writeFunc given. It will be called when resources or parameters * will be exported to disk. */ void visu_config_file_addExportFunction(VisuConfigFile *conf, VisuConfigFileExportFunc writeFunc) { struct writeFunc_struct *str; if (!writeFunc) return; g_return_if_fail(VISU_IS_CONFIG_FILE(conf)); str = g_malloc(sizeof(struct writeFunc_struct)); str->writeFunc = writeFunc; conf->priv->exportList = g_list_prepend(conf->priv->exportList, str); } /** * visu_config_file_entry_setTag: * @entry: a #VisuConfigFileEntry object ; * @tag: a string. * * This method is used to set a tag to the given entry. This tag is used * to ignore or not the entry when the file is read. The @tag argument * is copied. */ void visu_config_file_entry_setTag(VisuConfigFileEntry *entry, const gchar *tag) { g_return_if_fail(entry); if (entry->tag) g_free(entry->tag); entry->tag = g_strdup(tag); } /** * visu_config_file_entry_setVersion: * @entry: a #VisuConfigFileEntry object ; * @version: the version the entry appear in. * * Set the version number the entry appear in. */ void visu_config_file_entry_setVersion(VisuConfigFileEntry *entry, float version) { g_return_if_fail(entry && version > 3.0f); entry->version = version; } /** * visu_config_file_entry_setReplace: * @newEntry: a #VisuConfigFileEntry object ; * @oldEntry: idem. * * Use this method to declare that @oldEntry has become obsolete and * has been replaced by @newEntry. */ void visu_config_file_entry_setReplace(VisuConfigFileEntry *newEntry, VisuConfigFileEntry *oldEntry) { g_return_if_fail(newEntry && oldEntry); if (oldEntry->newKey) g_free(oldEntry->newKey); oldEntry->newKey = g_strdup(newEntry->key); } /** * visu_config_file_entry_getKey: * @entry: a #VisuConfigFileEntry object. * * An entry is defined by its key. * * Since: 3.8 * * Returns: the key of @entry. **/ const gchar* visu_config_file_entry_getKey(const VisuConfigFileEntry *entry) { g_return_val_if_fail(entry, (const gchar*)0); return entry->key; } /** * visu_config_file_entry_getLabel: * @entry: a #VisuConfigFileEntry object. * * An entry can be defined as some values preceeded by a label. After * parsing an entry, this label, if it exists can be retrieve with * this function. See for instance * visu_config_file_addBooleanArrayEntry() to define an entry with a label. * * Since: 3.8 * * Returns: (allow-none): the label as parsed. **/ const gchar* visu_config_file_entry_getLabel(const VisuConfigFileEntry *entry) { g_return_val_if_fail(entry, (const gchar*)0); return entry->label; } /** * visu_config_file_entry_popToken: * @entry: a #VisuConfigFileEntry object. * @value: (out caller-allocates): a location to store a string. * * Pop a string from a tokenified data line corresponding to @entry in * a configuration file. * * Since: 3.8 * * Returns: TRUE if @entry still has tokens to be retrieved and @value * has be set. **/ gboolean visu_config_file_entry_popToken(VisuConfigFileEntry *entry, const gchar **value) { g_return_val_if_fail(entry && entry->tokens, FALSE); while (entry->tokens[entry->iToken] && !entry->tokens[entry->iToken][0]) entry->iToken += 1; if (entry->tokens[entry->iToken]) { *value = entry->tokens[entry->iToken]; entry->iToken += 1; return TRUE; } return FALSE; } /** * visu_config_file_entry_popTokenAsBoolean: * @entry: a #VisuConfigFileEntry object. * @nValues: an integer. * @values: (array length=nValues): an array of boolean. * * Read @nValues as boolean from @entry and stores them in * @values. These tokens are poped from the current list of tokens of @entry. * * Since: 3.8 * * Returns: TRUE if @entry has @nValues boolean tokens to be read. **/ gboolean visu_config_file_entry_popTokenAsBoolean(VisuConfigFileEntry *entry, guint nValues, gboolean *values) { int res; guint i, nb; int *vals; g_return_val_if_fail(entry && entry->tokens, FALSE); vals = g_malloc(sizeof(int) * nValues); /* Read @size inting point values from tokens. */ for (nb = 0; entry->tokens[entry->iToken] && nb < nValues; entry->iToken++) if (entry->tokens[entry->iToken][0] != '\0') { res = sscanf(entry->tokens[entry->iToken], "%d", vals + nb); if (res != 1) { visu_config_file_entry_setErrorMessage (entry, _("%d boolean value(s) should appear here"), nValues); g_free(vals); return FALSE; } nb += 1; } if (nb != nValues) { visu_config_file_entry_setErrorMessage (entry, _("%d boolean value(s) should appear here but %d has been found"), nValues, nb); g_free(vals); return FALSE; } for (i = 0; i < nValues; i++) values[i] = (vals[i] != FALSE); g_free(vals); return TRUE; } /** * visu_config_file_entry_popTokenAsInt: * @entry: a #VisuConfigFileEntry object. * @nValues: an integer. * @values: (array length=nValues): an array of integers. * @clamp: a range. * * Like visu_config_file_entry_popTokenAsBoolean() but for * integers. Additionally conduct a range check using @clamp. * * Since: 3.8 * * Returns: TRUE if @entry has @nValues integer tokens to be read. **/ gboolean visu_config_file_entry_popTokenAsInt(VisuConfigFileEntry *entry, guint nValues, int *values, const int clamp[2]) { int res; guint i, nb; int *vals; g_return_val_if_fail(entry && entry->tokens, FALSE); vals = g_malloc(sizeof(int) * nValues); /* Read @size inting point values from tokens. */ for (nb = 0; entry->tokens[entry->iToken] && nb < nValues; entry->iToken++) if (entry->tokens[entry->iToken][0] != '\0') { res = sscanf(entry->tokens[entry->iToken], "%d", vals + nb); if (res != 1) { visu_config_file_entry_setErrorMessage (entry, _("%d integer value(s) should appear here"), nValues); g_free(vals); return FALSE; } nb += 1; } if (nb != nValues) { visu_config_file_entry_setErrorMessage (entry, _("%d integer value(s) should appear here but %d has been found"), nValues, nb); g_free(vals); return FALSE; } for (i = 0; i < nValues; i++) if (tool_config_file_clampInt(vals + i, vals[i], clamp[0], clamp[1])) { visu_config_file_entry_setErrorMessage (entry, _("wrong range (%d <= v <= %d) for the %s markup"), clamp[0], clamp[1], entry->key); g_free(vals); return FALSE; } memcpy(values, vals, sizeof(int) * nValues); g_free(vals); return TRUE; } /** * visu_config_file_entry_popTokenAsColor: * @entry: a #VisuConfigFileEntry object. * @color: (out caller-allocates): a location to store a #ToolColor. * * Like visu_config_file_entry_popToken() but convert the token as a #ToolColor. * * Since: 3.8 * * Returns: TRUE if @entry has a color tokens to be read. **/ gboolean visu_config_file_entry_popTokenAsColor(VisuConfigFileEntry *entry, const ToolColor **color) { gfloat rgba[4]; gfloat rgColor[2] = {0.f, 1.f}; g_return_val_if_fail(entry && entry->tokens && color, FALSE); *color = tool_color_fromStr(entry->tokens[entry->iToken], (int*)0); if (*color) { entry->iToken += 1; return TRUE; } if (!visu_config_file_entry_popTokenAsFloat(entry, 3, rgba, rgColor)) return FALSE; rgba[3] = 1.f; *color = tool_color_getByValues((int*)0, rgba[0], rgba[1], rgba[2], rgba[3]); if (!*color) *color = tool_color_addFloatRGBA(rgba, (int*)0); return TRUE; } /** * visu_config_file_entry_popTokenAsFloat: * @entry: a #VisuConfigFileEntry object. * @nValues: an integer. * @values: (array length=nValues): an array of floats. * @clamp: a range. * * Like visu_config_file_entry_popTokenAsInt() but for floats. * * Since: 3.8 * * Returns: TRUE if @entry has @nValues float tokens to be read. **/ gboolean visu_config_file_entry_popTokenAsFloat(VisuConfigFileEntry *entry, guint nValues, float *values, const float clamp[2]) { int res; guint i, nb; float *vals; g_return_val_if_fail(entry && entry->tokens, FALSE); vals = g_malloc(sizeof(float) * nValues); /* Read @size floating point values from tokens. */ for (nb = 0; entry->tokens[entry->iToken] && nb < nValues; entry->iToken++) if (entry->tokens[entry->iToken][0] != '\0') { res = sscanf(entry->tokens[entry->iToken], "%f", vals + nb); if (res != 1) { visu_config_file_entry_setErrorMessage (entry, _("%d floating point values should appear here"), nValues); g_free(vals); return FALSE; } nb += 1; } if (nb != nValues) { visu_config_file_entry_setErrorMessage (entry, _("%d floating point value(s) should appear here but %d has been found"), nValues, nb); g_free(vals); return FALSE; } for (i = 0; i < nValues; i++) if (tool_config_file_clampFloat(vals + i, vals[i], clamp[0], clamp[1])) { visu_config_file_entry_setErrorMessage (entry, _("wrong range (%g <= v <= %g) for the %s markup"), clamp[0], clamp[1], entry->key); g_free(vals); return FALSE; } memcpy(values, vals, sizeof(float) * nValues); g_free(vals); return TRUE; } /** * visu_config_file_entry_popTokenAsEnum: * @entry: a #VisuConfigFileEntry object. * @value: (out): a location to store an enum value. * @toEnum: (scope call): a method to convert a string to an enum * value. * * Parse the next non null token in @entry and parse it with @toEnum * function. The result, if valid, is stored in @value. * * Since: 3.8 * * Returns: TRUE if a token can be found and the conversion succeed. **/ gboolean visu_config_file_entry_popTokenAsEnum(VisuConfigFileEntry *entry, guint *value, VisuConfigFileEnumFunc toEnum) { g_return_val_if_fail(entry && entry->tokens, FALSE); while (entry->tokens[entry->iToken] && !entry->tokens[entry->iToken][0]) entry->iToken += 1; if (!entry->tokens[entry->iToken]) { visu_config_file_entry_setErrorMessage (entry, _("missing string for %s markup"), entry->key); return FALSE; } if (!toEnum(entry->tokens[entry->iToken], value)) { visu_config_file_entry_setErrorMessage (entry, _("'%s' is not a valid value for %s markup"), entry->tokens[entry->iToken], entry->key); entry->iToken += 1; return FALSE; } entry->iToken += 1; return TRUE; } /** * visu_config_file_entry_popAllTokens: * @entry: a #VisuConfigFileEntry object. * * Join the remaining tokens of @entry into a string. * * Since: 3.8 * * Returns: a newly created string. **/ gchar* visu_config_file_entry_popAllTokens(VisuConfigFileEntry *entry) { g_return_val_if_fail(entry, (gchar*)0); return g_strjoinv(" ", entry->tokens + entry->iToken); } /** * visu_config_file_entry_setErrorMessage: * @entry: a #VisuConfigFileEntry object. * @mess: a string. * @...: additional values, like in printf. * * Set error to @entry and format a message. * * Since: 3.8 **/ void visu_config_file_entry_setErrorMessage(VisuConfigFileEntry *entry, const gchar *mess, ...) { va_list arglist; g_return_if_fail(entry && mess); va_start(arglist, mess); entry->errMess = g_strdup_vprintf(mess, arglist); va_end(arglist); } static gchar* _getKey(const gchar *buf, gchar **key, gchar **tag, guint iLine, GError **error) { gchar *key_, *tag_, *end, *ret; *key = (gchar*)0; *tag = (gchar*)0; ret = strchr(buf, ':'); if (!ret) return (gchar*)0; key_ = g_strndup(buf, ret - buf); key_ = g_strstrip(key_); *key = key_; /* Look for the tag */ tag_ = strchr(key_, '['); if (tag_) { *tag_ = '\0'; tag_ += 1; end = strchr(tag_, ']'); if (end) { *end = '\0'; tag_ = g_strdup(tag_); *tag = tag_; } else *error = g_error_new(TOOL_CONFIG_FILE_ERROR, TOOL_CONFIG_FILE_ERROR_TAG, _("Parse error at line %d," " the tag '%s' is not closed.\n"), iLine, tag_); } DBG_fprintf(stderr,"Visu ConfigFile: read a flag (tag): '%s' (%s).\n", key_, tag_); return ret; } static VisuConfigFileEntry* _getEntry(VisuConfigFile *conf, const gchar *key, guint iLine, GError **error) { VisuConfigFileEntry *entry; DBG_fprintf(stderr, "Visu ConfigFile: found entry '%s'.\n", key); entry = (VisuConfigFileEntry*)g_hash_table_lookup(conf->priv->entryList, (gpointer)key); if (!entry) *error = g_error_new(TOOL_CONFIG_FILE_ERROR, TOOL_CONFIG_FILE_ERROR_MARKUP, _("Parse error at line %d," " '%s' is an unknown markup.\n"), iLine, key); else if (entry->newKey) g_warning(_("Markup '%s' is obsolete, replaced by '%s'."), key, entry->newKey); return entry; } static void _appendMessage(GString *message, GError **error, const gchar *key, const gchar *context) { if (*error) { g_string_append(message, (*error)->message); if (key) g_string_append_printf(message, _(" read line (%s) : '%s'\n"), key, context); else g_string_append_printf(message, _(" read line : '%s'\n"), context); g_error_free(*error); *error = (GError*)0; } } static gboolean _parse(VisuConfigFile *conf, VisuConfigFileEntry *entry, gchar **tokens, guint iLine, GError **error) { gboolean ret; ret = TRUE; if (tokens) { if (entry->read) ret = entry->read(entry, tokens, entry->nbLines, iLine, error); else if (entry->newKey) g_warning("Deprecated entry '%s', use '%s' instead.", entry->key, entry->newKey); if (ret) { DBG_fprintf(stderr, "Visu ConfigFile: entry '%s' parsed (%d).\n", entry->key, ret); g_signal_emit(conf, _signals[ENTRYPARSED_SIGNAL], entry->kquark, entry); if (entry->errMess) { *error = g_error_new(TOOL_CONFIG_FILE_ERROR, TOOL_CONFIG_FILE_ERROR_READ, _("Parse error at line %d, %s.\n"), iLine, entry->errMess); g_free(entry->errMess); entry->errMess = (gchar*)0; } } g_strfreev(entry->tokens); entry->tokens = (gchar**)0; } return ret; } static gboolean _loadRaw(VisuConfigFile *conf, const char* fileName, GError **error) { GIOChannel *ioFile; GString *line= (GString*)0; GIOStatus status; guint nbLine, i, iLine; gchar *deuxPoints; gchar **tokens, **splits; gchar *key, *tag; char *startDef, *endDef; VisuConfigFileEntry *entry; GString *message; ioFile = g_io_channel_new_file(fileName, "r", error); if (*error) return FALSE; message = g_string_new(""); line = g_string_new(""); iLine = 0; status = G_IO_STATUS_NORMAL; while (status == G_IO_STATUS_NORMAL) { status = g_io_channel_read_line_string(ioFile, line, NULL, error); if (*error) { g_string_free(line, TRUE); g_string_free(message, TRUE); return FALSE; } iLine += 1; if (status == G_IO_STATUS_EOF || line->str[0] == '#' || line->str[0] == '\n') continue; entry = (VisuConfigFileEntry*)0; deuxPoints = _getKey(line->str, &key, &tag, iLine, error); _appendMessage(message, error, (const gchar*)0, line->str); if (key) { if (tag && !g_hash_table_lookup(knownTags, (gpointer)tag)) { entry = (VisuConfigFileEntry*)0; DBG_fprintf(stderr, "Visu ConfigFile: the entry '%s' has an unknown tag (%s)," " it will be dismissed.\n", key, tag); } else { entry = _getEntry(conf, key, iLine, error); _appendMessage(message, error, (const gchar*)0, line->str); } g_free(key); if (tag) g_free(tag); } if (entry) { nbLine = entry->nbLines; /* Tricks for backward compatibility. */ if (!strcmp(entry->key, "pair_link")) nbLine = 2; tokens = g_malloc0(sizeof(gchar*) * (nbLine + 1)); if (conf->priv->kind == VISU_CONFIG_FILE_KIND_RESOURCE) for (i = 0; i < nbLine; i++) { status = g_io_channel_read_line_string(ioFile, line, NULL, error); if (*error) { g_string_free(line, TRUE); g_string_free(message, TRUE); return FALSE; } iLine += 1; if (status != G_IO_STATUS_NORMAL) { g_strfreev(tokens); tokens = (gchar**)0; *error = g_error_new(TOOL_CONFIG_FILE_ERROR, TOOL_CONFIG_FILE_ERROR_MISSING, _("Parse error at line %d," " '%s' needs %d lines but only %d were read.\n"), iLine, entry->key, nbLine, i); break; } tokens[i] = g_strdup(line->str); } else tokens[0] = g_strdup(deuxPoints + 1); /* Tricks for backward compatibility. */ if (entry->withLabel || !strcmp(entry->key, "shade_palette")) { i = 0; if (!strcmp(entry->key, "isosurface_color") || !strcmp(entry->key, "isosurface_properties")) { splits = g_strsplit_set(tokens[0], "\"", 3); i += 1; } else if (!strcmp(entry->key, "shade_palette")) { splits = g_malloc0(sizeof(gchar*) * 3); startDef = strchr(tokens[0], '('); endDef = strchr(tokens[0], ')'); if (!startDef || !endDef) { *error = g_error_new(TOOL_CONFIG_FILE_ERROR, TOOL_CONFIG_FILE_ERROR_MISSING, _("Parse error at line %d, cannot find parenthesis" " containing the description of a shade.\n"), iLine); } else { splits[0] = g_strndup(tokens[0], startDef - tokens[0] - 1); splits[1] = g_strndup(startDef + 1, endDef - startDef - 1); } } else if (!strcmp(entry->key, "pair_link")) { nbLine = 1; i = 0; splits = g_malloc0(sizeof(gchar*) * 3); splits[0] = g_strdup(tokens[0]); splits[1] = g_strdup(tokens[1]); } else { splits = g_strsplit_set(tokens[0], " \n", TOOL_MAX_LINE_LENGTH); while (splits[i] && !splits[i][0]) i++; } g_free(entry->label); entry->label = g_strdup(splits[i]); g_free(tokens[0]); tokens[0] = (splits[i] && splits[i + 1]) ? g_strjoinv(" ", splits + i + 1) : g_strdup(""); g_strfreev(splits); } if (!error || !*error) _parse(conf, entry, tokens, iLine, error); _appendMessage(message, error, entry->key, tokens[0]); g_strfreev(tokens); } } g_string_free(line, TRUE); status = g_io_channel_shutdown(ioFile, FALSE, error); g_io_channel_unref(ioFile); if (status != G_IO_STATUS_NORMAL) { g_string_free(message, TRUE); return FALSE; } DBG_fprintf(stderr, "Visu ConfigFile: read OK (error len = %d).\n", (int)message->len); if (message->len > 0) { DBG_fprintf(stderr, " | %s\n", message->str); *error = g_error_new(TOOL_CONFIG_FILE_ERROR, TOOL_CONFIG_FILE_ERROR_READ, "%s", message->str); } g_string_free(message, TRUE); return (*error == (GError*)0); } struct _dt { VisuConfigFile *conf; gboolean parse; GString *message; VisuConfigFileEntry *entry; gchar *tag, *id, *text; }; static void _element(GMarkupParseContext *context _U_, const gchar *element_name, const gchar **attribute_names, const gchar **attribute_values, gpointer user_data, GError **error) { struct _dt *dt = (struct _dt*)user_data; guint i; if (!strcmp(element_name, "resources")) dt->parse = TRUE; else if (!strcmp(element_name, "entry")) { dt->tag = (gchar*)0; dt->id = (gchar*)0; dt->text = (gchar*)0; for (i = 0; attribute_names[i]; i++) { if (!strcmp(attribute_names[i], "name")) { dt->entry = _getEntry(dt->conf, attribute_values[i], 0, error); _appendMessage(dt->message, error, (const gchar*)0, attribute_values[i]); } else if (!strcmp(attribute_names[i], "id")) dt->id = g_strdup(attribute_values[i]); } } } static void _endElement(GMarkupParseContext *context _U_, const gchar *element_name, gpointer user_data, GError **error) { struct _dt *dt = (struct _dt*)user_data; if (!strcmp(element_name, "resources")) dt->parse = FALSE; else if (!strcmp(element_name, "entry") && dt->entry) { g_free(dt->entry->label); dt->entry->label = g_strdup(dt->id); _parse(dt->conf, dt->entry, &dt->text, 0, error); _appendMessage(dt->message, error, dt->entry->key, dt->text); dt->entry = (VisuConfigFileEntry*)0; g_free(dt->tag); g_free(dt->id); g_free(dt->text); } } static void _text(GMarkupParseContext *context _U_, const gchar *text, gsize text_len _U_, gpointer user_data, GError **error _U_) { struct _dt *dt = (struct _dt*)user_data; if (dt->entry) dt->text = g_strdup(text); } static gboolean _loadXML(VisuConfigFile *conf, const gchar *filename, GError **error) { GMarkupParseContext* xmlContext; GMarkupParser parser; gsize size; gchar *buffer; struct _dt dt; /* Read file. */ buffer = (gchar*)0; if (!g_file_get_contents(filename, &buffer, &size, error)) return FALSE; /* Create context. */ parser.start_element = _element; parser.end_element = _endElement; parser.text = _text; parser.passthrough = NULL; parser.error = NULL; dt.conf = conf; dt.parse = FALSE; dt.message = g_string_new(""); dt.entry = (VisuConfigFileEntry*)0; dt.tag = (gchar*)0; dt.id = (gchar*)0; dt.text = (gchar*)0; xmlContext = g_markup_parse_context_new(&parser, 0, &dt, NULL); /* Parse data. */ g_markup_parse_context_parse(xmlContext, buffer, size, error); /* Free buffers. */ g_markup_parse_context_free(xmlContext); g_free(buffer); if (!*error && dt.message->len > 0) *error = g_error_new(TOOL_CONFIG_FILE_ERROR, TOOL_CONFIG_FILE_ERROR_READ, "%s", dt.message->str); g_string_free(dt.message, TRUE); return (*error == (GError*)0); } static void _setSource(VisuConfigFile *conf, const gchar *filename) { gchar *dirname; g_return_if_fail(VISU_IS_CONFIG_FILE(conf)); g_free(conf->priv->source); conf->priv->source = g_strdup(filename); dirname = g_path_get_dirname(filename); _addPath(resources, dirname); } /** * visu_config_file_load: * @conf: a #VisuConfigFile object ; * @filename: the path to file to read ; * @error: (allow-none): a pointer to a GError pointer. * * Try to load the resources/parameters from the file name given in * parameter. * * Returns: TRUE if everything goes right. If @error is not NULL it * should be freed with g_error_free(). */ gboolean visu_config_file_load(VisuConfigFile *conf, const char* filename, GError **error) { gboolean res; DBG_fprintf(stderr, "Visu ConfigFile: parsing '%s' file for" " resources/parameters...\n", filename); g_return_val_if_fail(VISU_IS_CONFIG_FILE(conf), FALSE); if (conf->priv->kind == VISU_CONFIG_FILE_KIND_RESOURCE && strstr(filename, ".xml")) res = _loadXML(conf, filename, error); else res = _loadRaw(conf, filename, error); /* We save the current path. */ _setSource(conf, filename); return res; } /** * visu_config_file_loadCommandLine: * @error: a location for a #GError pointer. * * For every command line option (e.g. -o axes_line_width=3), call the * corresponding ressource callback. * * Since: 3.8 * * Returns: TRUE on success. **/ gboolean visu_config_file_loadCommandLine(GError **error) { GHashTable *options; GHashTableIter iter; gpointer key; ToolOption *value; VisuConfigFile *conf; VisuConfigFileEntry *entry; gchar **tokens; if (!parameters || !resources) g_type_class_ref(VISU_TYPE_CONFIG_FILE); options = commandLineGet_options(); if (!options) return TRUE; g_hash_table_iter_init(&iter, options); while (g_hash_table_iter_next(&iter, &key, (gpointer*)&value)) { tokens = g_strsplit_set(key, "[]", 3); conf = resources; entry = (VisuConfigFileEntry*)g_hash_table_lookup(conf->priv->entryList, tokens[0]); if (!entry) { conf = parameters; entry = (VisuConfigFileEntry*)g_hash_table_lookup(conf->priv->entryList, tokens[0]); } if (entry && tokens[1]) { g_free(entry->label); entry->label = g_strdup(tokens[1]); } g_strfreev(tokens); if (entry) { tokens = g_malloc0(sizeof(gchar*) * 2); tokens[0] = g_strdelimit(g_strdup_value_contents(tool_option_getValue(value)), "\"", ' '); tokens[1] = NULL; DBG_fprintf(stderr, "Visu ConfigFile: read '%s' = '%s' from command line.\n", (gchar*)key, tokens[0]); if (!_parse(conf, entry, tokens, 0, error)) return FALSE; } } return TRUE; } /** * visu_config_file_exportComment: * @buffer: the buffer to add a comment to. * @comment: a comment. * * Append to @buffer the given @comment, using the current output * style (raw text or XML as instance). * * Since: 3.7 **/ void visu_config_file_exportComment(GString *buffer, const gchar *comment) { g_return_if_fail(buffer && comment); if (!comment[0]) { g_string_append(buffer, "\n"); return; } switch (format) { case (_format_raw): g_string_append_printf(buffer, "# %s\n", comment); break; case (_format_xml): g_string_append_printf(buffer, " \n", comment); break; } } /** * visu_config_file_exportEntry: * @buffer: the buffer to write the entry to. * @name: the name of the entry. * @id_value: (allow-none): an id for the entry. * @format_: the formatting string for the message. * @...: the values to print. * * Append to @buffer the given @entry, using the current output * style (raw text or XML as instance). @id_value can be used to * specify the entry apply to, for instance, the name of the * #VisuElement the colour property entry apply to. * * Since: 3.7 **/ void visu_config_file_exportEntry(GString *buffer, const gchar *name, const gchar *id_value, const gchar *format_, ...) { va_list arglist; gchar *buf; g_return_if_fail(buffer && name && format_); va_start(arglist, format_); buf = g_strdup_vprintf(format_, arglist); va_end(arglist); switch (format) { case (_format_raw): /* Special case for backward compatibility. */ if (!strcmp(name, "pair_link")) g_string_append_printf(buffer, "%s:\n %s\n %s\n", name, (id_value)?id_value:"", buf); else if (!strcmp(name, "isosurface_color") || !strcmp(name, "isosurface_properties")) g_string_append_printf(buffer, "%s:\n \"%s\" %s\n", name, (id_value)?id_value:"", buf); else g_string_append_printf(buffer, "%s:\n %s %s\n", name, (id_value)?id_value:"", buf); break; case (_format_xml): g_string_append_printf(buffer, " %s\n", buf); break; } g_free(buf); } /** * visu_config_file_saveResourcesToXML: * @filename: the path to file to read ; * @lines: (out): a pointer to an integer (can be NULL) ; * @dataObj: (allow-none): a #VisuData object (can be NULL) ; * @error: a location to store a possible error. * * Same routine as visu_config_file_save() but use an XML format instead. * * Since: 3.7 * * Returns: TRUE if everything goes right. */ gboolean visu_config_file_saveResourcesToXML(const char* filename, int *lines, VisuData *dataObj, GError **error) { gchar *ptCh; GString *buffer; int nbLine; GList *pos; gboolean success; g_return_val_if_fail(error && !*error, FALSE); DBG_fprintf(stderr, "Visu ConfigFile: exporting '%s' file for" " XML resources...\n", filename); format = _format_xml; buffer = g_string_new("\n", VERSION_HEADER); for (pos = resources->priv->exportList; pos; pos = g_list_next(pos)) { /* g_string_append_printf(" \n", ((VisuConfigFileEntry*)pos->data)->key); */ ((struct writeFunc_struct*)(pos->data))->writeFunc(buffer, dataObj); } g_string_append(buffer, " "); nbLine = 0; ptCh = buffer->str; while ((ptCh = strchr(ptCh + 1, '\n'))) nbLine += 1; DBG_fprintf(stderr, "Visu ConfigFile: export OK to string," " preparing to write file.\n"); success = tool_XML_substitute(buffer, filename, "resources", error); if (!success) { g_string_free(buffer, TRUE); return FALSE; } success = g_file_set_contents(filename, buffer->str, -1, error); DBG_fprintf(stderr, "Visu ConfigFile: write %d lines (%d).\n", nbLine, success); g_string_free(buffer, TRUE); /* We save the current path. */ if (success) { DBG_fprintf(stderr, " | save path '%s' as current.\n", filename); _setSource(resources, filename); } if (lines) *lines = nbLine; return success; } /** * visu_config_file_save: * @conf: a #VisuConfigFile object ; * @fileName: the path to file to read ; * @lines: a pointer to an integer (can be NULL) ; * @dataObj: (allow-none): a #VisuData object (can be NULL) ; * @error: a location to store a possible error. * * Try to export the resources/parameters to the file name given in * parameter. If @lines argument * is not NULL, and everything went right, it stores the number of written lines. * If the argument @dataObj is not null, only resources related * to the #VisuData object should be exported (for parameters files, @dataObj is * always NULL). * * Returns: TRUE if everything goes right. */ gboolean visu_config_file_save(VisuConfigFile *conf, const char* fileName, int *lines, VisuData *dataObj, GError **error) { gchar *ptCh; GString *exportString; int nbLine; GList *pos, *lst; gboolean success; g_return_val_if_fail(error && !*error, FALSE); DBG_fprintf(stderr, "Visu ConfigFile: exporting '%s' file for" " resources/parameters...\n", fileName); g_return_val_if_fail(VISU_IS_CONFIG_FILE(conf), FALSE); format = _format_raw; exportString = g_string_new(""); if (conf->priv->kind == VISU_CONFIG_FILE_KIND_RESOURCE) g_string_append_printf(exportString, RESOURCE_HEADER); else if (conf->priv->kind == VISU_CONFIG_FILE_KIND_PARAMETER) g_string_append_printf(exportString, PARAMETER_HEADER); g_string_append_printf(exportString, " v"VERSION_HEADER "\n" "#====================\n" "\n" "#WARNING: this file format is DIFFERENT from that for\n" "#standard v_sim version <= 2.x\n" "\n" "#Line beginning with a # are not parsed.\n" "\n"); if (conf->priv->kind == VISU_CONFIG_FILE_KIND_RESOURCE) g_string_append_printf(exportString, "#The only \"useful\" lines must have the following contents\n" "#several two or more lines patterns:\n" "#resource_name:\n" "#values separeted by blank characters\n" "\n" "#The following resource names are valid :\n"); else g_string_append_printf(exportString, "#The only \"useful\" lines must have the following pattern:\n" "#parameter_name: value\n" "\n" "#The following parameter names are valid :\n"); lst = visu_config_file_getEntries(conf); for (pos = lst; pos; pos = g_list_next(pos)) if (!((VisuConfigFileEntry*)(pos->data))->newKey) g_string_append_printf(exportString, "# %s\n", ((VisuConfigFileEntry*)(pos->data))->key); g_string_append_printf(exportString, "\n"); g_list_free(lst); for (pos = conf->priv->exportList; pos; pos = g_list_next(pos)) ((struct writeFunc_struct*)(pos->data))->writeFunc(exportString, dataObj); nbLine = 0; ptCh = exportString->str; while ((ptCh = strchr(ptCh + 1, '\n'))) nbLine += 1; DBG_fprintf(stderr, "Visu ConfigFile: export OK to string," " preparing to write file.\n"); success = g_file_set_contents(fileName, exportString->str, -1, error); g_string_free(exportString, TRUE); DBG_fprintf(stderr, "Visu ConfigFile: write %d lines (%d).\n", nbLine, success); /* We save the current path. */ _setSource(conf, fileName); if (lines) *lines = nbLine; return success; } static gboolean _validateHeader(const gchar *filename, VisuConfigFile *conf) { FILE *file; float version; char *msg, *header; char line[TOOL_MAX_LINE_LENGTH]; DBG_fprintf(stderr, "Visu ConfigFile: looking for header of \n '%s' ... ", filename); if (strstr(filename, ".xml")) { DBG_fprintf(stderr, "accepted.\n"); return TRUE; } file = fopen(filename, "r"); if (!file) { g_warning("The file '%s' should be readable but something goes" " nasty when one wants to open it.\n", filename); return FALSE; } version = 0.; msg = fgets(line, TOOL_MAX_LINE_LENGTH, file); fclose(file); if (conf->priv->kind == VISU_CONFIG_FILE_KIND_RESOURCE) header = RESOURCE_HEADER; else header = PARAMETER_HEADER; if (msg && !strncmp(line, header, strlen(header)) && sscanf(line + strlen(header) + 2, "%f", &version)) if (version >= 3.) { DBG_fprintf(stderr, "ok.\n"); return TRUE; } DBG_fprintf(stderr, "wrong.\n"); return FALSE; } static gchar* getValidFileWithHeader(int mode, VisuConfigFile *conf, GList **list) { gchar *res; const gchar** filenames; if (conf->priv->kind == VISU_CONFIG_FILE_KIND_RESOURCE) filenames = RESOURCES_FILENAMES; else filenames = PARAMETERS_FILENAMES; /* Look for a valid file. If it is for writing, a valid file is just given by a valid path. If it is for reading, a valid file is a valid path AND has a valid header. */ /* We get the next valid path. */ res = tool_getValidPath(list, filenames, mode); if (!res) { DBG_fprintf(stderr, "Visu ConfigFile: no file available.\n"); return (gchar*)0; } /* if we are in reading mode, we test the header. */ if ((mode & R_OK) && !_validateHeader(res, conf)) { g_free(res); res = (gchar*)0; } return res; } /** * visu_config_file_getPath: * @conf: a #VisuConfigFile object. * * The resource file can be read from different places. * * Since: 3.6 * * Returns: the path used to read the last resource file. */ const gchar* visu_config_file_getPath(VisuConfigFile *conf) { g_return_val_if_fail(VISU_IS_CONFIG_FILE(conf), (const gchar*)0); return conf->priv->source; } /** * visu_config_file_getValidPath: * @conf: a #VisuConfigFile object ; * @mode: a value from R_OK, W_OK and X_OK as described in unistd.h. * @utf8: if 1, the path is return in UTF-8 format, otherwise, the locale * of the file system is used. * * Test the entries of the hadoc list to find * a valid position to read or write a config file. * It tests access for the specified file. * * Returns: the first valid path find in the list of known paths. */ gchar* visu_config_file_getValidPath(VisuConfigFile *conf, int mode, int utf8) { gchar* file; gchar* fileUTF8; GList *lst; g_return_val_if_fail(VISU_IS_CONFIG_FILE(conf), (gchar*)0); lst = conf->priv->paths; file = getValidFileWithHeader(mode, conf, &lst); if (!file) return file; if (utf8) { fileUTF8 = g_filename_from_utf8(file, -1, NULL, NULL, NULL); g_free(file); return fileUTF8; } else return file; } /** * visu_config_file_getNextValidPath: * @conf: a #VisuConfigFile object ; * @accessMode: a value from R_OK, W_OK and X_OK as described in unistd.h ; * @list: (element-type filename) (inout) (transfer none): a pointer to a valid *GList ; * @utf8: if 1, the path is return in UTF-8 format, otherwise, the locale * of the file system is used. * * Test the entries of the given list to find * a valid position to read or write a config file. * It tests access for the specified file. After a call to this * method the @list argument points to the next entry in the list, after * the one found. * * Returns: the first valid path find in the given list of paths. */ gchar* visu_config_file_getNextValidPath(VisuConfigFile *conf, int accessMode, GList **list, int utf8) { gchar* file; gchar* fileUTF8; g_return_val_if_fail(VISU_IS_CONFIG_FILE(conf), (gchar*)0); g_return_val_if_fail(list, (gchar*)0); if (!*list) return (gchar*)0; file = getValidFileWithHeader(accessMode, conf, list); if (*list) *list = g_list_next(*list); if (!file) return file; if (utf8) { fileUTF8 = g_filename_from_utf8(file, -1, NULL, NULL, NULL); g_free(file); return fileUTF8; } else return file; } /** * visu_config_file_getDefaultFilename: * @kind: an integer identifier. * * This methods is used to get the filename used for different * config files. * * Returns: the filename of config file. The returned *gchar is * owned by V_Sim and should not be freed or modified. */ const gchar* visu_config_file_getDefaultFilename(VisuConfigFileKind kind) { if (kind == VISU_CONFIG_FILE_KIND_RESOURCE) return RESOURCES_FILENAMES[0]; else return PARAMETERS_FILENAMES[0]; } /** * visu_config_file_getPathList: * @conf: a #VisuConfigFile object ; * * V_Sim stores a list of paths where to look for resources or parameters * files, this method is used to get these lists. * * Returns: (transfer none) (element-type filename): the list of the * parameters or resources paths. This list is read-only. */ GList* visu_config_file_getPathList(VisuConfigFile *conf) { g_return_val_if_fail(VISU_IS_CONFIG_FILE(conf), (GList*)0); return conf->priv->paths; } static void _addPath(VisuConfigFile *conf, char* dir) { g_return_if_fail(VISU_IS_CONFIG_FILE(conf)); g_return_if_fail(dir && dir[0]); if (g_list_find_custom(conf->priv->paths, (gconstpointer)dir, compareStringsInGList)) return; DBG_fprintf(stderr, "Visu ConfigFile: add a new resource directory" " to the path :\n '%s'\n", dir); conf->priv->paths = g_list_prepend(conf->priv->paths, (gpointer)dir); } /** * visu_config_file_exportToXML: * @conf: a #VisuConfigFile object ; * @filename: a string in the encoding of the file system ; * @error: a location to store an error. * * Export all the registered entries for resources or parameters to an * XML file. * * Returns: TRUE if the file is written with success. */ gboolean visu_config_file_exportToXML(VisuConfigFile *conf, const gchar *filename, GError **error) { GString *str; GList *tmpLst, *lst; VisuConfigFileEntry *entry; gboolean status; gchar *desc; g_return_val_if_fail(filename && *filename, FALSE); g_return_val_if_fail(VISU_IS_CONFIG_FILE(conf), FALSE); str = g_string_new("\n"); if (conf->priv->kind == VISU_CONFIG_FILE_KIND_PARAMETER) g_string_append_printf(str, "\n"); else g_string_append_printf(str, "\n"); lst = visu_config_file_getEntries(conf); for (tmpLst = lst; tmpLst; tmpLst = g_list_next(tmpLst)) { entry = (VisuConfigFileEntry*)tmpLst->data; if (entry->tag) g_string_append_printf(str, " \n", entry->key, entry->tag, entry->version); else g_string_append_printf(str, " \n", entry->key, entry->version); desc = g_markup_escape_text(entry->description, -1); g_string_append_printf(str, " %s\n", desc); g_free(desc); if (entry->newKey) g_string_append_printf(str, " \n", entry->newKey); g_string_append_printf(str, " \n"); } g_string_append_printf(str, "\n"); g_list_free(lst); status = g_file_set_contents(filename, str->str, -1, error); g_string_free(str, TRUE); return status; } static gboolean readResourcesPaths(VisuConfigFileEntry *entry _U_, gchar **lines, int nbLines, int position _U_, GError **error _U_) { int i; gchar **tokens; gchar *key; g_return_val_if_fail(nbLines == 1, FALSE); tokens = g_strsplit_set(lines[0], ":", -1); for (i = 0; tokens[i]; i++) { key = g_strdup(tokens[i]); key = g_strstrip(key); if (key[0]) _addPath(VISU_CONFIG_FILE_RESOURCE, key); } g_strfreev(tokens); return TRUE; } static void exportResourcesPaths(GString *data, VisuData *dataObj _U_) { GList *pnt; g_string_append_printf(data, "# %s\n", DESC_RESOURCES_PATH); g_string_append_printf(data, "%s: ", FLAG_RESOURCES_PATH); pnt = visu_config_file_getPathList(resources); while(pnt) { /* We cancel the first and the last because it's the current working dir and the install dir. */ if (pnt->prev && pnt->next && pnt->next->next) g_string_append_printf(data, "%s", (char*)pnt->data); if (pnt->prev && pnt->next && pnt->next->next && pnt->next->next->next) g_string_append_printf(data, ":"); pnt = g_list_next(pnt); } g_string_append_printf(data, "\n\n"); } /* Specific routines. */ static gboolean _readTokens(VisuConfigFileEntry *entry, gchar **lines, int nbLines, int position _U_, GError **error _U_) { g_return_val_if_fail(nbLines == 1 && !entry->tokens, FALSE); /* Tokenize the line of values. */ entry->tokens = g_strsplit_set(g_strchug(lines[0]), " \n", TOOL_MAX_LINE_LENGTH); entry->iToken = 0; return TRUE; } static gboolean _readBooleanv(VisuConfigFileEntry *entry, gchar **lines, int nbLines, int position, GError **error) { gboolean *vals; g_return_val_if_fail(nbLines == 1 && entry->storage && entry->nValues > 0, FALSE); vals = g_malloc(sizeof(gboolean) * entry->nValues); if (!tool_config_file_readBoolean(lines[0], position, vals, entry->nValues, error)) { g_free(vals); return FALSE; } memcpy(entry->storage, vals, sizeof(gboolean) * entry->nValues); g_free(vals); return TRUE; } static gboolean _readEnum(VisuConfigFileEntry *entry, gchar **lines, int nbLines, int position, GError **error) { guint val; g_return_val_if_fail(nbLines == 1 && entry->storage, FALSE); if (!entry->toEnum(g_strstrip(lines[0]), &val)) { *error = g_error_new(TOOL_CONFIG_FILE_ERROR, TOOL_CONFIG_FILE_ERROR_VALUE, _("Parse error at line %d: '%s' is not a valid" " value for %s markup.\n"), position, lines[0], entry->key); return FALSE; } *(guint*)entry->storage = val; return TRUE; } static gboolean _readString(VisuConfigFileEntry *entry, gchar **lines, int nbLines, int position, GError **error) { gchar **str; g_return_val_if_fail(nbLines == 1 && entry->storage, FALSE); lines[0] = g_strstrip(lines[0]); if (!lines[0][0]) { *error = g_error_new(TOOL_CONFIG_FILE_ERROR, TOOL_CONFIG_FILE_ERROR_VALUE, _("Parse error at line %d: 1 string value must appear" " after the %s markup.\n"), position, entry->key); return FALSE; } str = (gchar**)entry->storage; g_free(*str); *str = g_strdup(lines[0]); return TRUE; } static gboolean _readIntv(VisuConfigFileEntry *entry, gchar **lines, int nbLines, int position, GError **error) { guint i; int *vals; g_return_val_if_fail(nbLines == 1 && entry->storage && entry->nValues > 0, FALSE); vals = g_malloc(sizeof(int) * entry->nValues); if (!tool_config_file_readInteger(lines[0], position, vals, entry->nValues, error)) { g_free(vals); return FALSE; } for (i = 0; i < entry->nValues; i++) if (tool_config_file_clampInt(vals + i, vals[i], entry->range.i[0], entry->range.i[1])) { *error = g_error_new(TOOL_CONFIG_FILE_ERROR, TOOL_CONFIG_FILE_ERROR_VALUE, _("Parse error at line %d: %d integer values" "(%d <= v <= %d) must appear after the %s markup.\n"), position, entry->nValues, entry->range.i[0], entry->range.i[1], entry->key); g_free(vals); return FALSE; } memcpy(entry->storage, vals, sizeof(int) * entry->nValues); g_free(vals); return TRUE; } static gboolean _readFloatv(VisuConfigFileEntry *entry, gchar **lines, int nbLines, int position, GError **error) { guint i; float *vals; g_return_val_if_fail(nbLines == 1 && entry->storage && entry->nValues > 0, FALSE); vals = g_malloc(sizeof(float) * entry->nValues); if (!tool_config_file_readFloat(lines[0], position, vals, entry->nValues, error)) { g_free(vals); return FALSE; } for (i = 0; i < entry->nValues; i++) if (tool_config_file_clampFloat(vals + i, vals[i], entry->range.f[0], entry->range.f[1])) { *error = g_error_new(TOOL_CONFIG_FILE_ERROR, TOOL_CONFIG_FILE_ERROR_VALUE, _("Parse error at line %d: %d floating points " "(%g <= v <= %g) must appear after the %s markup." " Read line was '%s'.\n"), position, entry->nValues, entry->range.f[0], entry->range.f[1], entry->key, lines[0]); g_free(vals); return FALSE; } memcpy(entry->storage, vals, sizeof(float) * entry->nValues); g_free(vals); return TRUE; } static gboolean _readStipplev(VisuConfigFileEntry *entry, gchar **lines, int nbLines, int position, GError **error) { guint i; gint *vals; guint16 *storage; g_return_val_if_fail(nbLines == 1 && entry->storage && entry->nValues > 0, FALSE); vals = g_malloc(sizeof(float) * entry->nValues); if (!tool_config_file_readInteger(lines[0], position, vals, entry->nValues, error)) { g_free(vals); return FALSE; } storage = (guint16*)entry->storage; for (i = 0; i < entry->nValues; i++) storage[i] = (guint16)vals[i]; g_free(vals); return TRUE; } v_sim-3.8.0/src/visu_configFile.h000066400000000000000000000313101370110300500166760ustar00rootroot00000000000000/* EXTRAITS DE LA LICENCE Copyright CEA, contributeurs : Luc BILLARD et Damien CALISTE, laboratoire L_Sim, (2001-2005) Adresse mèl : BILLARD, non joignable par mèl ; CALISTE, damien P caliste AT cea P fr. Ce logiciel est un programme informatique servant à visualiser des structures atomiques dans un rendu pseudo-3D. Ce logiciel est régi par la licence CeCILL soumise au droit français et respectant les principes de diffusion des logiciels libres. Vous pouvez utiliser, modifier et/ou redistribuer ce programme sous les conditions de la licence CeCILL telle que diffusée par le CEA, le CNRS et l'INRIA sur le site "http://www.cecill.info". Le fait que vous puissiez accéder à cet en-tête signifie que vous avez pris connaissance de la licence CeCILL, et que vous en avez accepté les termes (cf. le fichier Documentation/licence.fr.txt fourni avec ce logiciel). */ /* LICENCE SUM UP Copyright CEA, contributors : Luc BILLARD et Damien CALISTE, laboratoire L_Sim, (2001-2005) E-mail address: BILLARD, not reachable any more ; CALISTE, damien P caliste AT cea P fr. This software is a computer program whose purpose is to visualize atomic configurations in 3D. This software is governed by the CeCILL license under French law and abiding by the rules of distribution of free software. You can use, modify and/ or redistribute the software under the terms of the CeCILL license as circulated by CEA, CNRS and INRIA at the following URL "http://www.cecill.info". The fact that you are presently reading this means that you have had knowledge of the CeCILL license and that you accept its terms. You can find a copy of this licence shipped with this software at Documentation/licence.en.txt. */ #ifndef VISU_CONFIG_FILE_H #define VISU_CONFIG_FILE_H #include #include #include #include #include typedef struct _VisuConfigFileEntry VisuConfigFileEntry; /** * VisuConfigFileKind: * @VISU_CONFIG_FILE_KIND_PARAMETER: a kind of configuration that is * used to change settings in the way V_Sim is working. * @VISU_CONFIG_FILE_KIND_RESOURCE: a kind of configuartion that is * used to change the rendering output of V_Sim. * * This defines a parameter entry in the config files. */ typedef enum { VISU_CONFIG_FILE_KIND_PARAMETER, VISU_CONFIG_FILE_KIND_RESOURCE } VisuConfigFileKind; /** * VISU_TYPE_CONFIG_FILE: * * return the type of #VisuConfigFile. */ #define VISU_TYPE_CONFIG_FILE (visu_config_file_get_type ()) /** * VISU_CONFIG_FILE: * @obj: a #GObject to cast. * * Cast the given @obj into #VisuConfigFile type. */ #define VISU_CONFIG_FILE(obj) (G_TYPE_CHECK_INSTANCE_CAST(obj, VISU_TYPE_CONFIG_FILE, VisuConfigFile)) /** * VISU_CONFIG_FILE_CLASS: * @klass: a #GObjectClass to cast. * * Cast the given @klass into #VisuConfigFileClass. */ #define VISU_CONFIG_FILE_CLASS(klass) (G_TYPE_CHECK_CLASS_CAST(klass, VISU_TYPE_CONFIG_FILE, VisuConfigFileClass)) /** * VISU_IS_CONFIG_FILE: * @obj: a #GObject to test. * * Test if the given @ogj is of the type of #VisuConfigFile object. */ #define VISU_IS_CONFIG_FILE(obj) (G_TYPE_CHECK_INSTANCE_TYPE(obj, VISU_TYPE_CONFIG_FILE)) /** * VISU_IS_CONFIG_FILE_CLASS: * @klass: a #GObjectClass to test. * * Test if the given @klass is of the type of #VisuConfigFileClass class. */ #define VISU_IS_CONFIG_FILE_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE(klass, VISU_TYPE_CONFIG_FILE)) /** * VISU_CONFIG_FILE_GET_CLASS: * @obj: a #GObject to get the class of. * * It returns the class of the given @obj. */ #define VISU_CONFIG_FILE_GET_CLASS(obj) (G_TYPE_INSTANCE_GET_CLASS(obj, VISU_TYPE_CONFIG_FILE, VisuConfigFileClass)) typedef struct _VisuConfigFilePrivate VisuConfigFilePrivate; typedef struct _VisuConfigFile VisuConfigFile; struct _VisuConfigFile { VisuObject parent; VisuConfigFilePrivate *priv; }; /** * VisuConfigFileClass: * @parent: the parent class. * * A short way to identify #_VisuConfigFileClass structure. */ typedef struct _VisuConfigFileClass VisuConfigFileClass; struct _VisuConfigFileClass { VisuObjectClass parent; }; /** * visu_config_file_get_type: * * This method returns the type of #VisuConfigFile, use VISU_TYPE_CONFIG_FILE instead. * * Returns: the type of #VisuConfigFile. */ GType visu_config_file_get_type(void); VisuConfigFile* visu_config_file_getStatic(VisuConfigFileKind kind); /** * VISU_CONFIG_FILE_RESOURCE: * * Default instance of #VisuConfigFile object handling resource data. * * Since: 3.8 */ #define VISU_CONFIG_FILE_RESOURCE visu_config_file_getStatic(VISU_CONFIG_FILE_KIND_RESOURCE) /** * VISU_CONFIG_FILE_PARAMETER: * * Default instance of #VisuConfigFile object handling parameter data. * * Since: 3.8 */ #define VISU_CONFIG_FILE_PARAMETER visu_config_file_getStatic(VISU_CONFIG_FILE_KIND_PARAMETER) /** * VisuConfigFileReadFunc: * @entry: the #VisuConfigFileEntry that raises this callback. * @lines: an array of strings ; * @nbLines: an integer ; * @position: an integer ; * @error: a pointer to a GError pointer. * * This prototype corresponds to methods called when an entry is * found. The @lines argument is an array of lines read from the files. * These strings are copies and can be modified but not freed. There are * @nbLines and this value correspond to the number of lines defined * for the entry. The @error argument is used to store some text * messages and error ids. They should be in UTF8. The @error argument * must be initialised with (GError*)0. The @position argument give the number * of the first line given in @lines argument. * * Returns: TRUE if everything goes right, FALSE otherwise. */ typedef gboolean (*VisuConfigFileReadFunc)(VisuConfigFileEntry *entry, gchar **lines, int nbLines, int position, GError **error); /** * VisuConfigFileExportFunc: * @data: an empty GString to store the export ; * @dataObj: (allow-none): a #VisuData object ; * * This prototype defines a method that is used to export some resources * or parameters. The @data argument is an empty GString where the export has * to be written. If the argument @dataObj is not null, only resources related * to the #VisuData object should be exported (for parameters files, @dataObj is * always NULL). */ typedef void (*VisuConfigFileExportFunc)(GString *data, VisuData* dataObj); /** * VisuConfigFileEnumFunc: * @label: a string. * @value: a location to store an enum value. * * Try to match @label with a enum @value. * * Since: 3.8 * * Returns: TRUE if found. */ typedef gboolean (*VisuConfigFileEnumFunc)(const gchar *label, guint *value); /** * VisuConfigFileForeachFuncExport: * @data: the string where the values are exported to ; * @dataObj: the current #VisuData object, values are related to. * * This structure can be used to encapsulate the arguments of an export method * when used in a foreach glib loop. */ struct _VisuConfigFileForeachFuncExport { GString *data; VisuData *dataObj; }; GType visu_config_file_entry_get_type(void); #define VISU_TYPE_CONFIG_FILE_ENTRY (visu_config_file_entry_get_type()) VisuConfigFileEntry* visu_config_file_addEntry(VisuConfigFile *conf, const gchar *key, const gchar* description, int nbLines, VisuConfigFileReadFunc readFunc); VisuConfigFileEntry* visu_config_file_ignoreEntry(VisuConfigFile *conf, const gchar *key, guint nbLines); VisuConfigFileEntry* visu_config_file_addTokenizedEntry(VisuConfigFile *conf, const gchar *key, const gchar* description, gboolean labelled); VisuConfigFileEntry* visu_config_file_addBooleanEntry(VisuConfigFile *conf, const gchar *key, const gchar* description, gboolean *location, gboolean labelled); VisuConfigFileEntry* visu_config_file_addBooleanArrayEntry(VisuConfigFile *conf, const gchar *key, const gchar* description, guint nValues, gboolean *location, gboolean labelled); VisuConfigFileEntry* visu_config_file_addIntegerArrayEntry(VisuConfigFile *conf, const gchar *key, const gchar* description, guint nValues, int *location, int clamp[2], gboolean labelled); VisuConfigFileEntry* visu_config_file_addFloatArrayEntry(VisuConfigFile *conf, const gchar *key, const gchar* description, guint nValues, float *location, float clamp[2], gboolean labelled); VisuConfigFileEntry* visu_config_file_addEnumEntry(VisuConfigFile *conf, const gchar *key, const gchar* description, guint *location, VisuConfigFileEnumFunc toEnum, gboolean labelled); VisuConfigFileEntry* visu_config_file_addStringEntry(VisuConfigFile *conf, const gchar *key, const gchar* description, gchar **location); VisuConfigFileEntry* visu_config_file_addStippleArrayEntry(VisuConfigFile *conf, const gchar *key, const gchar* description, guint nValues, guint16 *location); void visu_config_file_addExportFunction(VisuConfigFile *conf, VisuConfigFileExportFunc writeFunc); void visu_config_file_entry_setTag(VisuConfigFileEntry *entry, const gchar *tag); void visu_config_file_entry_setVersion(VisuConfigFileEntry *entry, float version); void visu_config_file_entry_setReplace(VisuConfigFileEntry *newEntry, VisuConfigFileEntry *oldEntry); const gchar* visu_config_file_entry_getKey(const VisuConfigFileEntry *entry); const gchar* visu_config_file_entry_getLabel(const VisuConfigFileEntry *entry); gboolean visu_config_file_entry_popToken(VisuConfigFileEntry *entry, const gchar **value); gboolean visu_config_file_entry_popTokenAsBoolean(VisuConfigFileEntry *entry, guint nValues, gboolean *values); gboolean visu_config_file_entry_popTokenAsInt(VisuConfigFileEntry *entry, guint nValues, int *values, const int clamp[2]); gboolean visu_config_file_entry_popTokenAsColor(VisuConfigFileEntry *entry, const ToolColor **color); gboolean visu_config_file_entry_popTokenAsFloat(VisuConfigFileEntry *entry, guint nValues, float *values, const float clamp[2]); gboolean visu_config_file_entry_popTokenAsEnum(VisuConfigFileEntry *entry, guint *value, VisuConfigFileEnumFunc toEnum); gchar* visu_config_file_entry_popAllTokens(VisuConfigFileEntry *entry); void visu_config_file_entry_setErrorMessage(VisuConfigFileEntry *entry, const gchar *mess, ...); gboolean visu_config_file_load(VisuConfigFile *conf, const char* filename, GError **error); gboolean visu_config_file_loadCommandLine(GError **error); gboolean visu_config_file_save(VisuConfigFile *conf, const char* fileName, int *lines, VisuData *dataObj, GError **error); gboolean visu_config_file_saveResourcesToXML(const char* filename, int *lines, VisuData *dataObj, GError **error); void visu_config_file_addKnownTag(gchar* tag); void visu_config_file_exportComment(GString *buffer, const gchar *comment); void visu_config_file_exportEntry(GString *buffer, const gchar *name, const gchar *id_value, const gchar *format_, ...); gchar* visu_config_file_getValidPath(VisuConfigFile *conf, int mode, int utf8); gchar* visu_config_file_getNextValidPath(VisuConfigFile *conf, int accessMode, GList **list, int utf8); const gchar* visu_config_file_getDefaultFilename(VisuConfigFileKind kind); GList* visu_config_file_getPathList(VisuConfigFile *conf); GList* visu_config_file_getEntries(VisuConfigFile *conf); gboolean visu_config_file_exportToXML(VisuConfigFile *conf, const gchar *filename, GError **error); const gchar* visu_config_file_getPath(VisuConfigFile *conf); #endif v_sim-3.8.0/src/visu_data.c000066400000000000000000001714361370110300500155530ustar00rootroot00000000000000/* EXTRAITS DE LA LICENCE Copyright CEA, contributeurs : Luc BILLARD et Damien CALISTE, laboratoire L_Sim, (2001-2005) Adresse mèl : BILLARD, non joignable par mèl ; CALISTE, damien P caliste AT cea P fr. Ce logiciel est un programme informatique servant à visualiser des structures atomiques dans un rendu pseudo-3D. Ce logiciel est régi par la licence CeCILL soumise au droit français et respectant les principes de diffusion des logiciels libres. Vous pouvez utiliser, modifier et/ou redistribuer ce programme sous les conditions de la licence CeCILL telle que diffusée par le CEA, le CNRS et l'INRIA sur le site "http://www.cecill.info". Le fait que vous puissiez accéder à cet en-tête signifie que vous avez pris connaissance de la licence CeCILL, et que vous en avez accepté les termes (cf. le fichier Documentation/licence.fr.txt fourni avec ce logiciel). */ /* LICENCE SUM UP Copyright CEA, contributors : Luc BILLARD et Damien CALISTE, laboratoire L_Sim, (2001-2005) E-mail address: BILLARD, not reachable any more ; CALISTE, damien P caliste AT cea P fr. This software is a computer program whose purpose is to visualize atomic configurations in 3D. This software is governed by the CeCILL license under French law and abiding by the rules of distribution of free software. You can use, modify and/ or redistribute the software under the terms of the CeCILL license as circulated by CEA, CNRS and INRIA at the following URL "http://www.cecill.info". The fact that you are presently reading this means that you have had knowledge of the CeCILL license and that you accept its terms. You can find a copy of this licence shipped with this software at Documentation/licence.en.txt. */ #include "visu_data.h" #include #include #include #include #include "visu_commandLine.h" #include "extraFunctions/idProp.h" #include "extraFunctions/typeProp.h" #include "extraFunctions/coordProp.h" #include "extraFunctions/geometry.h" #include "extraFunctions/vibration.h" #include "coreTools/toolMatrix.h" /** * SECTION:visu_data * @short_description: Give methods to store and manage data from * input file(s). * * The main goal of V_Sim is to draw lists of elements. For * example, when used to render atoms, a box that contains 24 silicon * atoms and 46 germanium atoms is a box with two elements (silicon * and germanium) where the silicon element has 24 nodes and the * germanium element has 46 nodes. This module gives then methods to * create nodes (see #VisuElement to create and managed * elements). * * All nodes are stored in a structure called #VisuNodeArray and * #VisuNodeArray is encapsulated in a #VisuData for all not-node related * information. V_Sim uses one #VisuData per input file(s). This * structure contains a list of pointers on all the #VisuElement used * in this file. * * To iterate on nodes, one should use the provided iterators * (see #VisuNodeArrayIter) methods, like visu_node_array_iter_next(). */ enum { NODE_PROP_ADDED_SIGNAL, NODE_PROP_REMOVED_SIGNAL, LAST_SIGNAL }; enum { PROP_0, DESCR_PROP, TOTAL_ENERGY_PROP, N_PROP, TRANS_PROP, RED_TRANS_PROP, USE_TRANS_PROP, MODULO_PROP, BOX_PROP, ADJUST_PROP }; static GParamSpec *properties[N_PROP]; struct _VisuDataPrivate { gboolean dispose_has_run; gchar* commentary; /******************/ /* Box attributes */ /******************/ VisuBox *box; float extension[3]; gulong unit_signal, expand_signal, expAct_signal; /* Translation applied to all nodes when rendered. */ gboolean inTheBox, inTheBox_replicate; gboolean translationActive; float translation[3]; /********************/ /* Misc. attributes */ /********************/ /* The total energy of the system in eV. */ gdouble totalEnergy; /* The list of known VisuNodeValues. */ GHashTable *nodeProperties; }; static void visu_data_dispose (GObject* obj); static void visu_data_finalize (GObject* obj); static void visu_data_get_property(GObject* obj, guint property_id, GValue *value, GParamSpec *pspec); static void visu_data_set_property(GObject* obj, guint property_id, const GValue *value, GParamSpec *pspec); static gboolean _inTheBox(VisuPointset *self, gboolean status); static void _getTranslation(VisuPointset *self, float trans[3]); static gboolean _setTranslation(VisuPointset *self, float trans[3], gboolean withModulo); static gboolean _setTranslationActive(VisuPointset *self, gboolean status); static void _applyTranslation(VisuPointset *self); static void visu_boxed_interface_init(VisuBoxedInterface *iface); static void visu_pointset_interface_init(VisuPointsetInterface *iface); /* Local callbacks. */ static void onBoxUnitChanged(VisuData *data, gfloat fact); static void onBoxExtensChanged(VisuBox *box, GParamSpec *pspec, gpointer user_data); static void onBoxExtensActive(VisuBox *box, GParamSpec *pspec, gpointer user_data); /* Local routines. */ static VisuBox* visu_data_getBox(VisuBoxed *self); static gboolean visu_data_setBox(VisuBoxed *self, VisuBox *box); static GArray* shrinkNodeList(VisuData *data, int coord, float valueTo); static void extendNodeList(VisuData *data, int coord, float valueFrom, float valueTo); static void _replicate(VisuData *data, gfloat extension[3]); static gboolean _constrainedInTheBox(VisuData *data, gboolean emit); static gboolean _constrainedFree(VisuData *data, gboolean emit); static guint visu_data_signals[LAST_SIGNAL] = { 0 }; G_DEFINE_TYPE_WITH_CODE(VisuData, visu_data, VISU_TYPE_NODE_ARRAY, G_ADD_PRIVATE(VisuData) G_IMPLEMENT_INTERFACE(VISU_TYPE_BOXED, visu_boxed_interface_init) G_IMPLEMENT_INTERFACE(VISU_TYPE_POINTSET, visu_pointset_interface_init)) static void visu_data_class_init(VisuDataClass *klass) { DBG_fprintf(stderr, "Visu Data: creating the class of the object.\n"); DBG_fprintf(stderr, " - adding new signals ;\n"); /** * VisuData::node-properties-added: * @dataObj: the object which received the signal ; * @values: a #VisuNodeValues object. * * Gets emitted when @values node properties is added to @dataObj. * * Since: 3.8 */ visu_data_signals[NODE_PROP_ADDED_SIGNAL] = g_signal_new("node-properties-added", G_TYPE_FROM_CLASS(klass), G_SIGNAL_RUN_LAST | G_SIGNAL_NO_RECURSE | G_SIGNAL_NO_HOOKS, 0, NULL, NULL, g_cclosure_marshal_VOID__OBJECT, G_TYPE_NONE, 1, VISU_TYPE_NODE_VALUES, NULL); /** * VisuData::node-properties-removed: * @dataObj: the object which received the signal ; * @values: a #VisuNodeValues object. * * Gets emitted when @values node properties is removed from @dataObj. * * Since: 3.8 */ visu_data_signals[NODE_PROP_REMOVED_SIGNAL] = g_signal_new("node-properties-removed", G_TYPE_FROM_CLASS(klass), G_SIGNAL_RUN_LAST | G_SIGNAL_NO_RECURSE | G_SIGNAL_NO_HOOKS, 0, NULL, NULL, g_cclosure_marshal_VOID__OBJECT, G_TYPE_NONE, 1, VISU_TYPE_NODE_VALUES, NULL); /* Connect the overloading methods. */ G_OBJECT_CLASS(klass)->dispose = visu_data_dispose; G_OBJECT_CLASS(klass)->finalize = visu_data_finalize; G_OBJECT_CLASS(klass)->set_property = visu_data_set_property; G_OBJECT_CLASS(klass)->get_property = visu_data_get_property; /** * VisuData::description: * * Store a description for the data. * * Since: 3.8 */ properties[DESCR_PROP] = g_param_spec_string("description", "Description", "a description of the data", "", G_PARAM_READWRITE); /** * VisuData::totalEnergy: * * Store the total energy of the system in eV. * * Since: 3.6 */ properties[TOTAL_ENERGY_PROP] = g_param_spec_double("totalEnergy", "Total energy", "Total energy of the system (eV)", -G_MAXFLOAT, G_MAXFLOAT, G_MAXFLOAT, G_PARAM_CONSTRUCT | G_PARAM_READWRITE); g_object_class_install_properties(G_OBJECT_CLASS(klass), N_PROP, properties); g_object_class_override_property(G_OBJECT_CLASS(klass), USE_TRANS_PROP, "use-translation"); g_object_class_override_property(G_OBJECT_CLASS(klass), TRANS_PROP, "translation"); g_object_class_override_property(G_OBJECT_CLASS(klass), RED_TRANS_PROP, "reduced-translation"); g_object_class_override_property(G_OBJECT_CLASS(klass), MODULO_PROP, "in-the-box"); g_object_class_override_property(G_OBJECT_CLASS(klass), ADJUST_PROP, "auto-adjust"); g_object_class_override_property(G_OBJECT_CLASS(klass), BOX_PROP, "box"); } static void visu_boxed_interface_init(VisuBoxedInterface *iface) { iface->get_box = visu_data_getBox; iface->set_box = visu_data_setBox; } static void visu_pointset_interface_init(VisuPointsetInterface *iface) { iface->set_inTheBox = _inTheBox; iface->apply_translation = _applyTranslation; iface->get_translation = _getTranslation; iface->set_translation = _setTranslation; iface->set_translationActive = _setTranslationActive; } static void visu_data_init(VisuData *obj) { DBG_fprintf(stderr, "Visu Data: initializing a new object (%p).\n", (gpointer)obj); obj->priv = visu_data_get_instance_private(obj); obj->priv->dispose_has_run = FALSE; /* Private data. */ obj->priv->commentary = g_strdup(""); obj->priv->box = (VisuBox*)0; obj->priv->unit_signal = 0; obj->priv->expand_signal = 0; obj->priv->extension[0] = 0.f; obj->priv->extension[1] = 0.f; obj->priv->extension[2] = 0.f; obj->priv->inTheBox = FALSE; obj->priv->inTheBox_replicate = FALSE; obj->priv->translationActive = FALSE; obj->priv->translation[0] = 0.f; obj->priv->translation[1] = 0.f; obj->priv->translation[2] = 0.f; obj->priv->nodeProperties = g_hash_table_new_full(g_str_hash, g_str_equal, NULL, (GDestroyNotify)g_object_unref);; /* Ensure that the base (label, ...) property exists. */ visu_data_addNodeProperties(obj, VISU_NODE_VALUES(visu_node_values_id_new(VISU_NODE_ARRAY(obj)))); visu_data_addNodeProperties(obj, VISU_NODE_VALUES(visu_node_values_type_new(VISU_NODE_ARRAY(obj)))); visu_data_addNodeProperties(obj, VISU_NODE_VALUES(visu_node_values_coord_new(obj))); visu_data_getNodeLabels(obj); } /* This method can be called several times. It should unref all of its reference to GObjects. */ static void visu_data_dispose(GObject* obj) { VisuData *data; DBG_fprintf(stderr, "Visu Data: dispose object %p.\n", (gpointer)obj); data = VISU_DATA(obj); if (data->priv->dispose_has_run) return; data->priv->dispose_has_run = TRUE; visu_data_setBox(VISU_BOXED(data), (VisuBox*)0); /* Chain up to the parent class */ G_OBJECT_CLASS(visu_data_parent_class)->dispose(obj); } /* This method is called once only. */ static void visu_data_finalize(GObject* obj) { VisuData *data; g_return_if_fail(obj); DBG_fprintf(stderr, "Visu Data: finalize object %p.\n", (gpointer)obj); data = VISU_DATA(obj); /* Free privs elements. */ if (data->priv) { DBG_fprintf(stderr, "Visu data: free private data.\n"); g_free(data->priv->commentary); g_hash_table_destroy(data->priv->nodeProperties); } /* The free is called by g_type_free_instance... */ /* g_free(data); */ /* Chain up to the parent class */ DBG_fprintf(stderr, "Visu data: chain to parent.\n"); G_OBJECT_CLASS(visu_data_parent_class)->finalize(obj); DBG_fprintf(stderr, "Visu data: freeing ... OK.\n"); } static void visu_data_get_property(GObject* obj, guint property_id, GValue *value, GParamSpec *pspec) { VisuData *self = VISU_DATA(obj); gfloat *redTrans; DBG_fprintf(stderr, "Visu Data: get property '%s' -> ", g_param_spec_get_name(pspec)); switch (property_id) { case DESCR_PROP: g_value_set_string(value, self->priv->commentary); DBG_fprintf(stderr, "%s.\n", self->priv->commentary); break; case TOTAL_ENERGY_PROP: g_value_set_double(value, self->priv->totalEnergy); DBG_fprintf(stderr, "%geV.\n", self->priv->totalEnergy); break; case USE_TRANS_PROP: g_value_set_boolean(value, self->priv->translationActive); DBG_fprintf(stderr, "%d.\n", self->priv->translationActive); break; case TRANS_PROP: g_value_set_static_boxed(value, self->priv->translation); DBG_fprintf(stderr, "%gx%gx%g.\n", self->priv->translation[0], self->priv->translation[1], self->priv->translation[2]); break; case RED_TRANS_PROP: redTrans = g_malloc(sizeof(gfloat) * 3); visu_box_convertXYZtoBoxCoordinates(self->priv->box, redTrans, self->priv->translation); g_value_take_boxed(value, redTrans); DBG_fprintf(stderr, "%gx%gx%g.\n", redTrans[0], redTrans[1], redTrans[2]); break; case MODULO_PROP: g_value_set_boolean(value, self->priv->inTheBox); DBG_fprintf(stderr, "%d.\n", self->priv->inTheBox); break; case BOX_PROP: g_value_set_object(value, self->priv->box); DBG_fprintf(stderr, "%p.\n", (gpointer)self->priv->box); break; case ADJUST_PROP: g_object_get_property(G_OBJECT(self->priv->box), "auto-adjust", value); DBG_fprintf(stderr, "%d.\n", g_value_get_boolean(value)); break; default: /* We don't have any other property... */ G_OBJECT_WARN_INVALID_PROPERTY_ID(obj, property_id, pspec); break; } } static void visu_data_set_property(GObject* obj, guint property_id, const GValue *value, GParamSpec *pspec) { VisuData *self = VISU_DATA(obj); DBG_fprintf(stderr, "Visu Data: set property '%s' -> ", g_param_spec_get_name(pspec)); switch (property_id) { case DESCR_PROP: DBG_fprintf(stderr, "%s.\n", g_value_get_string(value)); visu_data_setDescription(self, g_value_get_string(value)); break; case TOTAL_ENERGY_PROP: self->priv->totalEnergy = g_value_get_double(value); DBG_fprintf(stderr, "%geV.\n", self->priv->totalEnergy); break; case USE_TRANS_PROP: visu_pointset_setTranslationActive(VISU_POINTSET(self), g_value_get_boolean(value)); DBG_fprintf(stderr, "%d.\n", self->priv->translationActive); break; case TRANS_PROP: visu_pointset_setTranslationPeriodic(VISU_POINTSET(self), (gfloat*)g_value_get_boxed(value), self->priv->inTheBox); DBG_fprintf(stderr, "%gx%gx%g.\n", self->priv->translation[0], self->priv->translation[1], self->priv->translation[2]); break; case RED_TRANS_PROP: visu_pointset_setBoxTranslation(VISU_POINTSET(self), (gfloat*)g_value_get_boxed(value), self->priv->inTheBox); DBG_fprintf(stderr, "%gx%gx%g.\n", self->priv->translation[0], self->priv->translation[1], self->priv->translation[2]); break; case MODULO_PROP: visu_pointset_setInTheBox(VISU_POINTSET(self), g_value_get_boolean(value)); DBG_fprintf(stderr, "%d.\n", self->priv->inTheBox); break; case BOX_PROP: DBG_fprintf(stderr, "%p.\n", g_value_get_object(value)); visu_data_setBox(VISU_BOXED(obj), VISU_BOX(g_value_get_object(value))); break; case ADJUST_PROP: DBG_fprintf(stderr, "%d.\n", g_value_get_boolean(value)); g_object_set_property(G_OBJECT(self->priv->box), "auto-adjust", value); break; default: /* We don't have any other property... */ G_OBJECT_WARN_INVALID_PROPERTY_ID(obj, property_id, pspec); break; } } /** * visu_data_new: * * This creates an empty #VisuData object. * * Returns: a newly created #VisuData object (its ref count is set to 1). */ VisuData* visu_data_new(void) { VisuData *data; DBG_fprintf(stderr, "Visu Data: create a new VisuData object of type %d.\n", (int)VISU_TYPE_DATA); data = VISU_DATA(g_object_new(VISU_TYPE_DATA, NULL)); if (!data) return (VisuData*)0; return data; } /** * visu_data_freePopulation: * @data: a VisuData to be freed. * * This method frees only the allocated memory that deals with * the nodes (i.e. everything except the data of the files, * the properties and the setColor method. */ void visu_data_freePopulation(VisuData *data) { float zeros[3] = {0.f, 0.f, 0.f}; if (!data) return; DBG_fprintf(stderr, "Visu Data: freeing the population of VisuData %p ...\n", (gpointer)data); visu_node_array_freeNodes(VISU_NODE_ARRAY(data)); if (data->priv->box) { visu_box_setExtension(data->priv->box, zeros); visu_box_setExtensionActive(data->priv->box, FALSE); visu_pointset_setTranslationPeriodic(VISU_POINTSET(data), zeros, FALSE); } DBG_fprintf(stderr, "Visu Data: freeing ... OK.\n"); } /** * visu_data_setDescription: * @data: a #VisuData object ; * @commentary: the message to be stored (null terminated) ; * * This method is used to store a description of the given @data. This * string is copied and @commentary can be freed. */ void visu_data_setDescription(VisuData *data, const gchar* commentary) { g_return_if_fail(VISU_IS_DATA(data)); g_free(data->priv->commentary); data->priv->commentary = g_strdup(commentary); g_object_notify_by_pspec(G_OBJECT(data), properties[DESCR_PROP]); } /** * visu_data_getDescription: * @data: a #VisuData object ; * * Get the commentary associated to the given @data. * * Returns: (transfer none): a string description (possibly * empty). This string is own by V_Sim and should not be freed. */ const gchar* visu_data_getDescription(const VisuData *data) { g_return_val_if_fail(VISU_IS_DATA(data), (gchar*)0); return data->priv->commentary; } /*************************/ /* The geometry routines */ /*************************/ static VisuBox* visu_data_getBox(VisuBoxed *self) { g_return_val_if_fail(VISU_IS_DATA(self), (VisuBox*)0); return VISU_DATA(self)->priv->box; } static gboolean visu_data_setBox(VisuBoxed *self, VisuBox *box) { VisuData *data; g_return_val_if_fail(VISU_IS_DATA(self), FALSE); data = VISU_DATA(self); if (data->priv->box == box) return FALSE; if (data->priv->box) { g_signal_handler_disconnect(G_OBJECT(data->priv->box), data->priv->unit_signal); g_signal_handler_disconnect(G_OBJECT(data->priv->box), data->priv->expand_signal); g_signal_handler_disconnect(G_OBJECT(data->priv->box), data->priv->expAct_signal); g_object_unref(data->priv->box); } data->priv->box = box; if (box) { g_object_ref(box); data->priv->unit_signal = g_signal_connect_swapped(G_OBJECT(data->priv->box), "UnitChanged", G_CALLBACK(onBoxUnitChanged), data); data->priv->expand_signal = g_signal_connect(G_OBJECT(data->priv->box), "notify::expansion", G_CALLBACK(onBoxExtensChanged), (gpointer)data); data->priv->expAct_signal = g_signal_connect(G_OBJECT(data->priv->box), "notify::use-expansion", G_CALLBACK(onBoxExtensActive), (gpointer)data); } return TRUE; } static gboolean _inTheBox(VisuPointset *self, gboolean status) { if (status) _constrainedInTheBox(VISU_DATA(self), TRUE); else _constrainedFree(VISU_DATA(self), TRUE); return TRUE; } static void _applyTranslation(VisuPointset *self) { VisuNodeArrayIter iter; float xyz[3], zeros[3] = {0.f, 0.f, 0.f}; gboolean rendered; visu_node_array_iter_new(VISU_NODE_ARRAY(self), &iter); for (visu_node_array_iterStart(VISU_NODE_ARRAY(self), &iter); iter.node; visu_node_array_iterNext(VISU_NODE_ARRAY(self), &iter)) { visu_data_getNodePosition(VISU_DATA(self), iter.node, xyz); rendered = visu_node_getVisibility(iter.node); visu_node_newValues(iter.node, xyz); visu_node_setVisibility(iter.node, rendered); } _setTranslation(self, zeros, FALSE); } static void _getTranslation(VisuPointset *self, float trans[3]) { VisuDataPrivate *priv; g_return_if_fail(VISU_IS_DATA(self)); priv = VISU_DATA(self)->priv; trans[0] = priv->translation[0]; trans[1] = priv->translation[1]; trans[2] = priv->translation[2]; } static gboolean _setTranslation(VisuPointset *self, float trans[3], gboolean withModulo) { VisuDataPrivate *priv; gboolean res, changed; g_return_val_if_fail(VISU_IS_DATA(self), FALSE); priv = VISU_DATA(self)->priv; res = FALSE; if (priv->translation[0] != trans[0]) { priv->translation[0] = trans[0]; res = TRUE; } if (priv->translation[1] != trans[1]) { priv->translation[1] = trans[1]; res = TRUE; } if (priv->translation[2] != trans[2]) { priv->translation[2] = trans[2]; res = TRUE; } DBG_fprintf(stderr, "Visu Data: force translation to: %f %f %f\n", priv->translation[0], priv->translation[1], priv->translation[2]); if (res) g_object_notify(G_OBJECT(self), "translation"); changed = FALSE; if (withModulo) changed = _constrainedInTheBox(VISU_DATA(self), FALSE); if ((res && priv->translationActive) || changed) g_signal_emit_by_name(G_OBJECT(self), "position-changed", (GArray*)0, NULL); return res; } static gboolean _setTranslationActive(VisuPointset *self, gboolean status) { VisuData *data; gboolean changed; g_return_val_if_fail(VISU_IS_DATA(self), FALSE); data = VISU_DATA(self); if (data->priv->translationActive == status) return FALSE; data->priv->translationActive = status; g_object_notify(G_OBJECT(self), "use-translation"); changed = FALSE; if (data->priv->inTheBox) changed = _constrainedInTheBox(VISU_DATA(self), FALSE); if (data->priv->translation[0] != 0.f || data->priv->translation[1] != 0.f || data->priv->translation[2] != 0.f || changed) g_signal_emit_by_name(G_OBJECT(self), "position-changed", (GArray*)0, NULL); return TRUE; } /** * visu_data_getNodeBoxFromNumber: * @data: a #VisuData object. * @nodeId: the index of the node considered. * @nodeBox: (in) (array fixed-size=3): the array to store the box of the node. * * This method retrieves the value of the box associated to a node (with respect to the unit cell). * * Returns: TRUE if everything went well, FALSE otherwise. The box is stored in the nodeBox array. */ gboolean visu_data_getNodeBoxFromNumber(VisuData *data, guint nodeId, int nodeBox[3]) { float xcart[3]; g_return_val_if_fail(VISU_IS_DATA(data), FALSE); visu_data_getNodePosition(data, visu_node_array_getFromId(VISU_NODE_ARRAY(data),nodeId), xcart); visu_data_getNodeBoxFromCoord(data, xcart, nodeBox); return TRUE; } /** * visu_data_getNodeBoxFromCoord: * @data: a #VisuData object. * @xcart: (in) (array fixed-size=3): the coordinates of a node. * @nodeBox: (in) (array fixed-size=3): the array to store the box of the node. * * This method retrieves the value of the box associated to the coordinates of the node (with respect to the unit cell). * * Returns: TRUE if everything went well, FALSE otherwise. The box is stored in the nodeBox array. */ gboolean visu_data_getNodeBoxFromCoord(VisuData *data, float xcart[3], int nodeBox[3]) { float xred[3]; visu_box_convertXYZtoBoxCoordinates(data->priv->box, xred, xcart); nodeBox[0] = floor(xred[0]); nodeBox[1] = floor(xred[1]); nodeBox[2] = floor(xred[2]); DBG_fprintf(stderr, "Visu Data: nodeBox found for atom at %f %f %f : %d %d %d.\n", xcart[0], xcart[1], xcart[2], nodeBox[0], nodeBox[1], nodeBox[2]); return TRUE; } static void onBoxUnitChanged(VisuData *data, gfloat fact) { VisuNodeArrayIter iter; DBG_fprintf(stderr, "Visu Data: caught 'UnitChanged' signal with factor %g.\n", fact); /* We do an homothety on the nodes. */ data->priv->translation[0] *= fact; data->priv->translation[1] *= fact; data->priv->translation[2] *= fact; visu_node_array_iter_new(VISU_NODE_ARRAY(data), &iter); for( visu_node_array_iterStart(VISU_NODE_ARRAY(data), &iter); iter.node; visu_node_array_iterNext(VISU_NODE_ARRAY(data), &iter)) { iter.node->xyz[0] *= fact; iter.node->xyz[1] *= fact; iter.node->xyz[2] *= fact; iter.node->translation[0] *= fact; iter.node->translation[1] *= fact; iter.node->translation[2] *= fact; } /* We raise the signals. */ g_signal_emit_by_name(G_OBJECT(data), "position-changed", (GArray*)0, NULL); DBG_fprintf(stderr, "Visu Data: done 'UnitChanged'.\n"); } static void onBoxExtensChanged(VisuBox *box, GParamSpec *pspec _U_, gpointer user_data) { gfloat ext[3]; if (!visu_box_getExtensionActive(box)) return; visu_box_getExtension(box, ext); _replicate(VISU_DATA(user_data), ext); } static void onBoxExtensActive(VisuBox *box, GParamSpec *pspec _U_, gpointer user_data) { VisuData *data; gfloat ext[3]; if (visu_box_getExtensionActive(box)) { visu_box_getExtension(box, ext); _replicate(VISU_DATA(user_data), ext); } else { visu_node_array_removeAllDuplicateNodes(VISU_NODE_ARRAY(user_data)); data = VISU_DATA(user_data); data->priv->extension[0] = 0.f; data->priv->extension[1] = 0.f; data->priv->extension[2] = 0.f; if (data->priv->inTheBox_replicate) { _constrainedFree(data, TRUE); data->priv->inTheBox_replicate = FALSE; } } } static gboolean _constrainedElementInTheBox(VisuData *data, VisuElement *element, gboolean emit) { gboolean changed; float cartCoord[3], t[3]; VisuNodeArrayIter iter; g_return_val_if_fail(VISU_IS_DATA(data) && element, FALSE); if (!visu_element_getRendered(element)) return FALSE; DBG_fprintf(stderr, "Visu Data: Checking for nodes of element '%s'" " to be in the box.\n", element->name); changed = FALSE; visu_node_array_iter_new(VISU_NODE_ARRAY(data), &iter); iter.element = element; for(visu_node_array_iterRestartNode(VISU_NODE_ARRAY(data), &iter); iter.node; visu_node_array_iterNextNode(VISU_NODE_ARRAY(data), &iter)) { visu_data_getNodePosition(data, iter.node, cartCoord); if (visu_box_constrainInside(data->priv->box, t, cartCoord, FALSE)) { changed = TRUE; iter.node->translation[0] += t[0]; iter.node->translation[1] += t[1]; iter.node->translation[2] += t[2]; } } if (changed && emit) g_signal_emit_by_name(G_OBJECT(data), "position-changed", (GArray*)0, NULL); return changed; } static gboolean _constrainedInTheBox(VisuData *data, gboolean emit) { VisuNodeArrayIter iter; gboolean changed; g_return_val_if_fail(VISU_IS_DATA(data), FALSE); data->priv->inTheBox = TRUE; g_object_notify(G_OBJECT(data), "in-the-box"); changed = FALSE; visu_node_array_iter_new(VISU_NODE_ARRAY(data), &iter); for (visu_node_array_iterStart(VISU_NODE_ARRAY(data), &iter); iter.element; visu_node_array_iterNextElement(VISU_NODE_ARRAY(data), &iter, FALSE)) changed = _constrainedElementInTheBox(data, iter.element, emit) || changed; return changed; } static gboolean _constrainedFree(VisuData *data, gboolean emit) { VisuNodeArrayIter iter; gboolean moved; g_return_val_if_fail(VISU_IS_DATA(data), FALSE); data->priv->inTheBox = FALSE; g_object_notify(G_OBJECT(data), "in-the-box"); moved = FALSE; visu_node_array_iter_new(VISU_NODE_ARRAY(data), &iter); for (visu_node_array_iterStart(VISU_NODE_ARRAY(data), &iter); iter.node; visu_node_array_iterNext(VISU_NODE_ARRAY(data), &iter)) { moved = moved || iter.node->translation[0] != 0. || iter.node->translation[1] != 0. || iter.node->translation[2] != 0.; iter.node->translation[0] = 0.; iter.node->translation[1] = 0.; iter.node->translation[2] = 0.; } if (emit && moved) g_signal_emit_by_name(G_OBJECT(data), "position-changed", (GArray*)0, NULL); return TRUE; } /** * visu_data_setTightBox: * @data: a #VisuData object. * * Calculate the box geometry to have a tight box in directions that * are not periodic. If some directions are still periodic, the box * size in these directions should be setup first with * visu_box_setGeometry(). * * Returns: (transfer none): a new #VisuBox if @data had not one * before, or the modified box of @data. */ VisuBox* visu_data_setTightBox(VisuData *data) { double xMin, yMin, zMin, xMax, yMax, zMax, xFree, yFree, zFree; double boxGeometry[6], boxGeometry_[6]; float xyz[3]; VisuNodeArrayIter iter; VisuBoxBoundaries bc; guint i; VisuBox *box; g_return_val_if_fail(VISU_IS_DATA(data), (VisuBox*)0); if (!data->priv->box) { for (i = 0; i < VISU_BOX_N_VECTORS; i++) boxGeometry_[i] = 0.; box = visu_box_new(boxGeometry_, VISU_BOX_FREE); visu_boxed_setBox(VISU_BOXED(data), VISU_BOXED(box)); g_object_unref(box); } bc = visu_box_getBoundary(data->priv->box); if (bc == VISU_BOX_PERIODIC) return data->priv->box; /* Store the coordinates */ xMin = 1e5; yMin = 1e5; zMin = 1e5; xMax = -1e5; yMax = -1e5; zMax = -1e5; xFree = (bc & TOOL_XYZ_MASK_X)?0.:1.; yFree = (bc & TOOL_XYZ_MASK_Y)?0.:1.; zFree = (bc & TOOL_XYZ_MASK_Z)?0.:1.; visu_node_array_iter_new(VISU_NODE_ARRAY(data), &iter); for (visu_node_array_iterStart(VISU_NODE_ARRAY(data), &iter); iter.node; visu_node_array_iterNext(VISU_NODE_ARRAY(data), &iter)) { xMin = MIN(xMin, iter.node->xyz[0]); yMin = MIN(yMin, iter.node->xyz[1]); zMin = MIN(zMin, iter.node->xyz[2]); xMax = MAX(xMax, iter.node->xyz[0]); yMax = MAX(yMax, iter.node->xyz[1]); zMax = MAX(zMax, iter.node->xyz[2]); } DBG_fprintf(stderr, "Visu Data: the elements are in [%f, %f]x[%f, %f]x[%f, %f].\n", xMin, xMax, yMin, yMax, zMin, zMax); for (i = 0; i < VISU_BOX_N_VECTORS; i++) boxGeometry_[i] = visu_box_getGeometry(data->priv->box, i); boxGeometry[0] = (xMax - xMin + 1e-5) * xFree + (1. - xFree) * boxGeometry_[0]; boxGeometry[1] = 0. + (1. - yFree) * boxGeometry_[1]; boxGeometry[2] = (yMax - yMin + 1e-5) * yFree + (1. - yFree) * boxGeometry_[2]; boxGeometry[3] = 0. + (1. - zFree) * boxGeometry_[3]; boxGeometry[4] = 0. + (1. - zFree) * boxGeometry_[4]; boxGeometry[5] = (zMax - zMin + 1e-5) * zFree + (1. - zFree) * boxGeometry_[5]; visu_box_setGeometry(data->priv->box, boxGeometry); xyz[0] = -xMin * xFree; xyz[1] = -yMin * yFree; xyz[2] = -zMin * zFree; visu_pointset_setTranslation(VISU_POINTSET(data), xyz, FALSE); visu_pointset_setTranslationActive(VISU_POINTSET(data), TRUE); return data->priv->box; } static void _replicate(VisuData *data, gfloat extension[3]) { int i; GArray *index; g_return_if_fail(VISU_IS_DATA(data)); g_return_if_fail(extension[0] >= 0. && extension[1] >= 0. && extension[2] >= 0.); DBG_fprintf(stderr, "Visu Data: modify extension from (%g, %g, %g).\n", data->priv->extension[0], data->priv->extension[1], data->priv->extension[2]); if (!data->priv->inTheBox) { _constrainedInTheBox(data, TRUE); data->priv->inTheBox_replicate = TRUE; } /* Keep only three digits for the extension to avoid rounding troubles. */ extension[0] = (float)((int)(extension[0] * 1000)) / 1000; extension[1] = (float)((int)(extension[1] * 1000)) / 1000; extension[2] = (float)((int)(extension[2] * 1000)) / 1000; for (i = 0; i < 3; i++) { if (data->priv->extension[i] > extension[i]) { index = shrinkNodeList(data, i, extension[i]); if (index->len > 0) visu_node_array_removeNodes(VISU_NODE_ARRAY(data), index); g_array_unref(index); } else if (data->priv->extension[i] < extension[i]) extendNodeList(data, i, data->priv->extension[i], extension[i]); data->priv->extension[i] = extension[i]; } g_object_notify(G_OBJECT(data), "n-nodes"); if (DEBUG) visu_node_array_traceProperty(VISU_NODE_ARRAY(data), "originalId"); } static GArray* shrinkNodeList(VisuData *data, int coord, float valueTo) { float cartCoord[3], boxCoord[3]; GArray *index; VisuNodeArrayIter iter; g_return_val_if_fail(coord == 0 || coord == 1 || coord == 2, FALSE); g_return_val_if_fail(valueTo >= 0.f, FALSE); DBG_fprintf(stderr, "Visu Data: shrink to %g (%d).\n", valueTo, coord); index = g_array_new(FALSE, FALSE, sizeof(guint)); visu_node_array_iter_new(VISU_NODE_ARRAY(data), &iter); for (visu_node_array_iterStart(VISU_NODE_ARRAY(data), &iter); iter.node; visu_node_array_iterNext(VISU_NODE_ARRAY(data), &iter)) { visu_data_getNodePosition(data, iter.node, cartCoord); visu_box_convertXYZtoBoxCoordinates(data->priv->box, boxCoord, cartCoord); if ((boxCoord[coord] < - valueTo - 1e-6 || /* We are out on the low coord. */ boxCoord[coord] >= 1.f + valueTo -1e-6) && /* We are out on the high coord. */ visu_node_array_getOriginal(VISU_NODE_ARRAY(data), iter.node->number) >= 0) /* We remove the element. */ g_array_append_val(index, iter.node->number); DBG_fprintf(stderr, "Visu Data: test shrink for %d: %d %15.12fx%15.12fx%15.12f.\n", iter.node->number, index->len, boxCoord[0], boxCoord[1], boxCoord[2]); } return index; } static void extendNodeList(VisuData *data, int coord, float valueFrom, float valueTo) { int k, id; unsigned nb, nbInit; VisuNode *newNode; float cartCoord[3], boxCoord[3], ratio; VisuNodeArrayIter iter; VisuBoxBoundaries bc; g_return_if_fail(coord == 0 || coord == 1 || coord == 2); g_return_if_fail(valueTo > valueFrom); DBG_fprintf(stderr, "Visu Data: expand in %d direction to %g.\n", coord, valueTo); DBG_fprintf(stderr, " | k runs in [%d %d[ ]%d %d].\n", (int)floor(-valueTo), -(int)valueFrom, (int)valueFrom, (int)ceil(valueTo)); DBG_fprintf(stderr, " | keeps new ele in [%g %g] [%g %g].\n", -valueTo, -valueFrom, valueFrom + 1.f, valueTo + 1.f); /* We estimate the number of data to be added and we call a realloc of this amount now to avoid to much small reallocations. The slab of box to be extend is 2*(valueTo-extension[coord]). So the volume in box coordinates is the same value and since the volume in box coordinates is product(1+2*extension), the ratio of new space is the fraction. So we realloc all elements on this ratio. */ ratio = (2.f * (valueTo - valueFrom)) / (1.f + 2.f * valueFrom); visu_node_array_iter_new(VISU_NODE_ARRAY(data), &iter); for (visu_node_array_iterStart(VISU_NODE_ARRAY(data), &iter); iter.element; visu_node_array_iterNextElement(VISU_NODE_ARRAY(data), &iter, FALSE)) { nb = (int)ceil((float)iter.nStoredNodes * ratio); visu_node_array_allocateNodesForElement(VISU_NODE_ARRAY(data), iter.iElement, iter.nStoredNodes + nb); } bc = visu_box_getBoundary(data->priv->box); /* All node with an id higher than nbInit are considered as new nodes. */ nbInit = G_MAXUINT; visu_node_array_startAdding(VISU_NODE_ARRAY(data)); for (visu_node_array_iterStartNumber(VISU_NODE_ARRAY(data), &iter); iter.node; visu_node_array_iterNextNodeNumber(VISU_NODE_ARRAY(data), &iter)) { /* Do not duplicate the new nodes. */ if (iter.node->number > nbInit) continue; visu_data_getNodePosition(data, iter.node, cartCoord); visu_box_convertXYZtoBoxCoordinates(data->priv->box, boxCoord, cartCoord); for (k = (int)floor(-valueTo); k < (int)ceil(valueTo) + 1; k++) { if (k >= -(int)valueFrom && k < (int)valueFrom + 1) continue; boxCoord[coord] += (float)k; if ((boxCoord[coord] >= -valueTo && boxCoord[coord] < -valueFrom ) || (boxCoord[coord] < valueTo + 1.f && boxCoord[coord] >= valueFrom + 1.f)) { DBG_fprintf(stderr, "Visu Data: replicating node %d, (%d)" " (%15.12fx%15.12fx%15.12f).\n", iter.node->number, coord, boxCoord[0], boxCoord[1], boxCoord[2]); /* We save the current node id, because the pointer may be relocated by the visu_node_array_copyNode() call. */ id = iter.node->number; /* We create and add a new element. */ newNode = visu_node_array_copyNode(VISU_NODE_ARRAY(data), iter.node); if (nbInit == G_MAXUINT) nbInit = newNode->number - 1; visu_box_convertBoxCoordinatestoXYZ(data->priv->box, newNode->xyz, boxCoord); if (!(bc & TOOL_XYZ_MASK_X) || data->priv->translationActive) newNode->xyz[0] -= data->priv->translation[0]; if (!(bc & TOOL_XYZ_MASK_Y) || data->priv->translationActive) newNode->xyz[1] -= data->priv->translation[1]; if (!(bc & TOOL_XYZ_MASK_Z) || data->priv->translationActive) newNode->xyz[2] -= data->priv->translation[2]; if (data->priv->inTheBox) { newNode->xyz[0] -= newNode->translation[0]; newNode->xyz[1] -= newNode->translation[1]; newNode->xyz[2] -= newNode->translation[2]; } /* We reset the iter.node pointer. */ iter.node = visu_node_array_getFromId(VISU_NODE_ARRAY(data), id); } boxCoord[coord] -= (float)k; } } visu_node_array_completeAdding(VISU_NODE_ARRAY(data)); } /** * visu_data_getAllNodeExtens: * @dataObj: a #VisuData object. * @box: (allow-none): a #VisuBox object. * * Calculate the longest distance between the surface of @box (without * extension) and all the nodes. If @box is NULL, then the internal * box of @dataObj is used. * * Since: 3.7 * * Returns: the longest distance between the surface of @box (without * extension) and all the nodes. **/ gfloat visu_data_getAllNodeExtens(VisuData *dataObj, VisuBox *box) { VisuNodeArrayIter iter; float xyz[2][3], t[3], lg[2], coord[3]; g_return_val_if_fail(VISU_IS_DATA(dataObj), 0.f); if (!box) box = dataObj->priv->box; t[0] = (float)(visu_box_getGeometry(box, VISU_BOX_DXX) + visu_box_getGeometry(box, VISU_BOX_DYX) + visu_box_getGeometry(box, VISU_BOX_DZX)); t[1] = (float)(visu_box_getGeometry(box, VISU_BOX_DYY) + visu_box_getGeometry(box, VISU_BOX_DZY)); t[2] = (float)(visu_box_getGeometry(box, VISU_BOX_DZZ)); xyz[0][0] = xyz[0][1] = xyz[0][2] = 0.f; xyz[1][0] = xyz[1][1] = xyz[1][2] = 0.f; visu_node_array_iter_new(VISU_NODE_ARRAY(dataObj), &iter); for (visu_node_array_iterStart(VISU_NODE_ARRAY(dataObj), &iter); iter.node; visu_node_array_iterNext(VISU_NODE_ARRAY(dataObj), &iter)) { visu_data_getNodePosition(dataObj, iter.node, coord); xyz[0][0] = MIN(xyz[0][0], coord[0]); xyz[0][1] = MIN(xyz[0][1], coord[1]); xyz[0][2] = MIN(xyz[0][2], coord[2]); xyz[1][0] = MAX(xyz[1][0], coord[0]); xyz[1][1] = MAX(xyz[1][1], coord[1]); xyz[1][2] = MAX(xyz[1][2], coord[2]); } xyz[1][0] -= t[0]; xyz[1][1] -= t[1]; xyz[1][2] -= t[2]; /* Compute the longest vector out of the box. */ lg[0] = sqrt(xyz[0][0] * xyz[0][0] + xyz[0][1] * xyz[0][1] + xyz[0][2] * xyz[0][2]); lg[1] = sqrt(xyz[1][0] * xyz[1][0] + xyz[1][1] * xyz[1][1] + xyz[1][2] * xyz[1][2]); DBG_fprintf(stderr, "VisuData: vectors outside of the box %g %g.\n", lg[0], lg[1]); return MAX(lg[0], lg[1]); } /** * visu_data_setNewBasisFromNodes: * @data: a #VisuData object. * @nO: the index of node as origin. * @nA: the index of node on X axis. * @nB: the index of node as Y axis. * @nC: the index of node as Z axis. * * Change the basis set by providing the new basis set from a list of * nodes. See also visu_data_setNewBasis(). Nodes outside the new box * are killed. * * Since: 3.6 * * Returns: TRUE if the new basis set is valid. */ gboolean visu_data_setNewBasisFromNodes(VisuData *data, guint nO, guint nA, guint nB, guint nC) { VisuNode *orig, *nodeA, *nodeB, *nodeC; float matA[3][3], O[3], xyz[3]; orig = visu_node_array_getFromId(VISU_NODE_ARRAY(data), nO); DBG_fprintf(stderr, " orig = %p\n", (gpointer)orig); nodeA = visu_node_array_getFromId(VISU_NODE_ARRAY(data), nA); DBG_fprintf(stderr, " nodeA = %p\n", (gpointer)nodeA); nodeB = visu_node_array_getFromId(VISU_NODE_ARRAY(data), nB); DBG_fprintf(stderr, " nodeB = %p\n", (gpointer)nodeB); nodeC = visu_node_array_getFromId(VISU_NODE_ARRAY(data), nC); DBG_fprintf(stderr, " nodeC = %p\n", (gpointer)nodeC); g_return_val_if_fail(orig && nodeA && nodeB && nodeC, FALSE); visu_data_getNodePosition(data, orig, O); visu_data_getNodePosition(data, nodeA, xyz); matA[0][0] = xyz[0] - O[0]; matA[1][0] = xyz[1] - O[1]; matA[2][0] = xyz[2] - O[2]; visu_data_getNodePosition(data, nodeB, xyz); matA[0][1] = xyz[0] - O[0]; matA[1][1] = xyz[1] - O[1]; matA[2][1] = xyz[2] - O[2]; visu_data_getNodePosition(data, nodeC, xyz); matA[0][2] = xyz[0] - O[0]; matA[1][2] = xyz[1] - O[1]; matA[2][2] = xyz[2] - O[2]; return visu_data_setNewBasis(data, matA, O); } /** * visu_data_setNewBasis: * @data: a #VisuData object. * @matA: a basis set definition. * @O: the origin cartesian coordinates. * * Change the basis set of @data according to the new definition given * by @matA and @O. Nodes outside the new box are killed. See also * visu_data_setNewBasisFromNodes() for a convenient function using * nodes as basis set definition. * * Since: 3.6 * * Returns: TRUE if the new basis set is valid. */ gboolean visu_data_setNewBasis(VisuData *data, float matA[3][3], float O[3]) { double mat_[3][3]; float inv[3][3], vect[3], xred[3]; double box[6]; float vectEps[3], deltaEps[3]; VisuNodeArrayIter iter; GArray *rmNodes; float zeros[3] = {0.f, 0.f, 0.f}; #define EPS 1.e-5 DBG_fprintf(stderr, "Visu Data: basis matrice:\n"); DBG_fprintf(stderr, " (%10.5f %10.5f %10.5f)\n", matA[0][0], matA[0][1], matA[0][2]); DBG_fprintf(stderr, " (%10.5f %10.5f %10.5f)\n", matA[1][0], matA[1][1], matA[1][2]); DBG_fprintf(stderr, " (%10.5f %10.5f %10.5f)\n", matA[2][0], matA[2][1], matA[2][2]); if (!tool_matrix_invert(inv, matA)) return FALSE; DBG_fprintf(stderr, "Visu Data: transformation matrice:\n"); DBG_fprintf(stderr, " (%10.5f %10.5f %10.5f)\n", inv[0][0], inv[0][1], inv[0][2]); DBG_fprintf(stderr, " (%10.5f %10.5f %10.5f)\n", inv[1][0], inv[1][1], inv[1][2]); DBG_fprintf(stderr, " (%10.5f %10.5f %10.5f)\n", inv[2][0], inv[2][1], inv[2][2]); mat_[0][0] = (double)matA[0][0]; mat_[1][0] = (double)matA[0][1]; mat_[2][0] = (double)matA[0][2]; mat_[0][1] = (double)matA[1][0]; mat_[1][1] = (double)matA[1][1]; mat_[2][1] = (double)matA[1][2]; mat_[0][2] = (double)matA[2][0]; mat_[1][2] = (double)matA[2][1]; mat_[2][2] = (double)matA[2][2]; if (!tool_matrix_reducePrimitiveVectors(box, mat_)) return FALSE; DBG_fprintf(stderr, "Visu Data: new box:\n"); DBG_fprintf(stderr, " (%10.5f %10.5f %10.5f)\n", box[0], box[1], box[2]); DBG_fprintf(stderr, " (%10.5f %10.5f %10.5f)\n", box[3], box[4], box[5]); visu_box_setBoundary(data->priv->box, VISU_BOX_PERIODIC); /* Trick to avoid the emission of SizeChanged signal. */ visu_box_setMargin(data->priv->box, G_MAXFLOAT, FALSE); visu_box_setGeometry(data->priv->box, box); /* Remove possible extension. */ g_signal_handler_block(G_OBJECT(data->priv->box), data->priv->expand_signal); visu_box_setExtension(data->priv->box, zeros); g_signal_handler_unblock(G_OBJECT(data->priv->box), data->priv->expand_signal); /* We need to move all the atoms of (eps, eps, eps) in the new box to avoid rounding problems. */ xred[0] = 1.f; xred[1] = 1.f; xred[2] = 1.f; tool_matrix_productVector(vect, matA, xred); vectEps[0] = (vect[0] >= 0.f)?EPS:-EPS; vectEps[1] = (vect[1] >= 0.f)?EPS:-EPS; vectEps[2] = (vect[2] >= 0.f)?EPS:-EPS; tool_matrix_productVector(xred, inv, vectEps); visu_box_convertBoxCoordinatestoXYZ(data->priv->box, deltaEps, xred); DBG_fprintf(stderr, "Visu Data: applied epsilon (%10.5f %10.5f %10.5f)\n", vectEps[0], vectEps[1], vectEps[2]); /* Transform each atomic coordinates using this matrice. */ DBG_fprintf(stderr, "Visu Data: reset the coordinates for all nodes.\n"); visu_node_array_iter_new(VISU_NODE_ARRAY(data), &iter); rmNodes = g_array_new(FALSE, FALSE, sizeof(guint)); for (visu_node_array_iterStart(VISU_NODE_ARRAY(data), &iter); iter.node; visu_node_array_iterNext(VISU_NODE_ARRAY(data), &iter)) { visu_data_getNodePosition(data, iter.node, vect); vect[0] += - O[0] + vectEps[0]; vect[1] += - O[1] + vectEps[1]; vect[2] += - O[2] + vectEps[2]; tool_matrix_productVector(xred, inv, vect); if (xred[0] < 0.f || xred[0] >= 1.f || xred[1] < 0.f || xred[1] >= 1.f || xred[2] < 0.f || xred[2] >= 1.f) { g_array_append_val(rmNodes, iter.node->number); DBG_fprintf(stderr, " | %d (%6.1f %6.1f %6.1f)" " %10.5f %10.5f %10.5f -> removed\n", iter.node->number, vect[0], vect[1], vect[2], xred[0], xred[1], xred[2]); } else { visu_box_convertBoxCoordinatestoXYZ(data->priv->box, iter.node->xyz, xred); iter.node->xyz[0] -= deltaEps[0]; iter.node->xyz[1] -= deltaEps[1]; iter.node->xyz[2] -= deltaEps[2]; iter.node->translation[0] = 0.f; iter.node->translation[1] = 0.f; iter.node->translation[2] = 0.f; visu_node_array_setOriginal(VISU_NODE_ARRAY(data), iter.node->number); DBG_fprintf(stderr, " | %d (%6.1f %6.1f %6.1f)" " %10.5f %10.5f %10.5f -> %10.5f %10.5f %10.5f\n", iter.node->number, vect[0], vect[1], vect[2], xred[0], xred[1], xred[2], iter.node->xyz[0], iter.node->xyz[1], iter.node->xyz[2]); } } visu_node_array_removeNodes(VISU_NODE_ARRAY(data), rmNodes); g_array_free(rmNodes, TRUE); /* Remove possible translation. */ visu_pointset_setTranslation(VISU_POINTSET(data), zeros, FALSE); visu_pointset_setTranslationActive(VISU_POINTSET(data), FALSE); visu_pointset_setInTheBox(VISU_POINTSET(data), FALSE); g_signal_emit_by_name(G_OBJECT(data), "position-changed", (GArray*)0, NULL); return TRUE; } /** * visu_data_reorder: * @data: a #VisuData object, to reorder. * @dataRef: a #VisuData object, to take the order from. * * This routine modifies the node ordering of @data using the order in * @dataRef. The association is done by nearest neigbours conditions. * * Since: 3.6 * * Returns: TRUE is the reordering is successfull (i.e. all nodes of * @data correspond to one of @dataRef). */ gboolean visu_data_reorder(VisuData *data, const VisuData *dataRef) { VisuNodeArrayIter iter, iterRef; float d, diff[3], xyz[3], dMin; guint id; g_return_val_if_fail(VISU_IS_DATA(dataRef), FALSE); g_return_val_if_fail(VISU_IS_DATA(data), FALSE); DBG_fprintf(stderr, "Geometry: reorder between %p and %p.\n", (gpointer)dataRef, (gpointer)data); DBG_fprintf(stderr, " | %d - %d.\n", visu_node_array_getNNodes(VISU_NODE_ARRAY(data)), visu_node_array_getNNodes(VISU_NODE_ARRAY_CONST(dataRef))); if (visu_node_array_getNNodes(VISU_NODE_ARRAY(data)) != visu_node_array_getNNodes(VISU_NODE_ARRAY_CONST(dataRef))) return FALSE; visu_node_array_iter_new(VISU_NODE_ARRAY(data), &iter); for (visu_node_array_iterStart(VISU_NODE_ARRAY(data), &iter); iter.node; visu_node_array_iterNext(VISU_NODE_ARRAY(data), &iter)) { id = 0; dMin = G_MAXFLOAT; visu_data_getNodePosition(data, iter.node, xyz); visu_node_array_iter_new(VISU_NODE_ARRAY((VisuNodeArray*)dataRef), &iterRef); iterRef.element = iter.element; for (visu_node_array_iterRestartNode(VISU_NODE_ARRAY((VisuNodeArray*)dataRef), &iterRef); iterRef.node; visu_node_array_iterNextNode(VISU_NODE_ARRAY((VisuNodeArray*)dataRef), &iterRef)) { visu_data_getNodePosition(dataRef, iterRef.node, diff); diff[0] -= xyz[0]; diff[1] -= xyz[1]; diff[2] -= xyz[2]; visu_box_getPeriodicVector(visu_boxed_getBox(VISU_BOXED(data)), diff); d = diff[0] * diff[0] + diff[1] * diff[1] + diff[2] * diff[2]; if (d < dMin) { id = iterRef.node->number; dMin = d; } } DBG_fprintf(stderr, " | %d %d -> %g\n", iter.node->number, id, dMin); visu_node_array_switchNumber(VISU_NODE_ARRAY(data), iter.node->number, id); } return TRUE; } /*****************************/ /* The node related routines */ /*****************************/ static VisuNode* _addNode(VisuData *data, VisuNode *node, float xyz[3], gboolean reduced) { float coord[3]; g_return_val_if_fail(VISU_IS_DATA(data) && node, (VisuNode*)0); /* If coordinates are reduced, we expand them. */ DBG_fprintf(stderr, "Visu Data: set node coordinates from (%g;%g;%g).\n", xyz[0], xyz[1], xyz[2]); if (reduced) visu_box_convertBoxCoordinatestoXYZ(data->priv->box, coord, xyz); else { coord[0] = xyz[0]; coord[1] = xyz[1]; coord[2] = xyz[2]; } visu_node_newValues(node, coord); return node; } /** * visu_data_addNodeFromIndex: * @data: the #VisuData where to add the new #VisuNode ; * @position: a integer corresponding to the position of * a #VisuElement in the array **nodes in the structure; * @xyz: (in) (array fixed-size=3): its coordinates ; * @reduced: coordinates are in reduced coordinates ; * * This method adds a new #VisuNode to the specified #VisuData. Position must be * chosen between 0 and (ntype - 1) and corresponds to the position of the array * in #VisuNodeArray of a #VisuElement. If several node should be added in * a row, consider using visu_node_array_startAdding() and * visu_node_array_completeAdding(). * * Returns: (transfer none): a pointer to the newly created node. */ VisuNode* visu_data_addNodeFromIndex(VisuData *data, guint position, float xyz[3], gboolean reduced) { return _addNode(data, visu_node_array_getNewNodeForId(VISU_NODE_ARRAY(data), position), xyz, reduced); } /** * visu_data_addNodeFromElement: * @data: the #VisuData where to add the new #VisuNode ; * @ele: the #VisuElement kind of the new #VisuNode ; * @xyz: (in) (array fixed-size=3): its coordinates ; * @reduced: coordinates are in reduced coordinates ; * * This method adds a new #VisuNode to the specified #VisuData. If * several node should be added in a row, consider using * visu_node_array_startAdding() and * visu_node_array_completeAdding(). * * Returns: (transfer none): a pointer to the newly created node. */ VisuNode* visu_data_addNodeFromElement(VisuData *data, VisuElement *ele, float xyz[3], gboolean reduced) { return _addNode(data, visu_node_array_getNewNode(VISU_NODE_ARRAY(data), ele), xyz, reduced); } /** * visu_data_addNodeFromElementName: * @data: the #VisuData where to add the new #VisuNode ; * @name: the name of the element ; * @xyz: (in) (array fixed-size=3): its coordinates ; * @reduced: coordinates are in reduced coordinates ; * * This method adds a new #VisuNode to the specified #VisuData. If * several node should be added in a row, consider using * visu_node_array_startAdding() and * visu_node_array_completeAdding(). * * Returns: (transfer none): a pointer to the newly created node. * * Since: 3.6 */ VisuNode* visu_data_addNodeFromElementName(VisuData *data, const gchar *name, float xyz[3], gboolean reduced) { return visu_data_addNodeFromElement(data, visu_element_retrieveFromName(name, (gboolean*)0), xyz, reduced); } /** * visu_data_getNodeCoordinates: * @data: a #VisuData object ; * @node: a #VisuNode object ; * @user: a boolean. * @x: (out caller-allocates): the x coordinate. * @y: (out caller-allocates): the y coordinate. * @z: (out caller-allocates): the z coordinate. * * Wrapper for the function visu_data_getNodePosition() in case of call * from python. If @user is TRUE, it wraps * visu_data_getNodeUserPosition() instead. * * Since: 3.6 */ void visu_data_getNodeCoordinates(VisuData *data, VisuNode *node, gboolean user, float *x, float *y, float *z) { float xyz[3]; g_return_if_fail(x && y && z); if (user) visu_data_getNodeUserPosition(data, node, xyz); else visu_data_getNodePosition(data, node, xyz); *x = xyz[0]; *y = xyz[1]; *z = xyz[2]; } /** * visu_data_getNodePosition: (skip) * @data: a #VisuData object ; * @node: a #VisuNode object ; * @coord: (array fixed-size=3) (out caller-allocates): an array of 3 * floating point values to store the position. * * Position of nodes are subject to various translations and different transformations. * Their coordinates should not be access directly through node.[xyz]. This method * is used to retrieve the given node position. * */ void visu_data_getNodePosition(const VisuData *data, const VisuNode *node, float coord[3]) { VisuBoxBoundaries bc; g_return_if_fail(VISU_IS_DATA(data) && node && coord); coord[0] = node->xyz[0]; coord[1] = node->xyz[1]; coord[2] = node->xyz[2]; bc = (data->priv->box) ? visu_box_getBoundary(data->priv->box) : VISU_BOX_PERIODIC; if (!(bc & TOOL_XYZ_MASK_X) || data->priv->translationActive) coord[0] += data->priv->translation[0]; if (!(bc & TOOL_XYZ_MASK_Y) || data->priv->translationActive) coord[1] += data->priv->translation[1]; if (!(bc & TOOL_XYZ_MASK_Z) || data->priv->translationActive) coord[2] += data->priv->translation[2]; if (data->priv->inTheBox) { coord[0] += node->translation[0]; coord[1] += node->translation[1]; coord[2] += node->translation[2]; } } /** * visu_data_getNodeUserPosition: (skip) * @data: a #VisuData object ; * @node: a #VisuNode object ; * @coord: (array fixed-size=3) (out caller-allocates): an array of 3 * floating point values to store the position. * * This routine is equivalent to visu_data_getNodePosition() except * that it's not applying internal box translation for non periodic * directions. * * Since: 3.7 */ void visu_data_getNodeUserPosition(const VisuData *data, const VisuNode *node, float coord[3]) { VisuBoxBoundaries bc; g_return_if_fail(VISU_IS_DATA(data) && node && coord); visu_data_getNodePosition(data, node, coord); bc = visu_box_getBoundary(data->priv->box); if (!(bc & TOOL_XYZ_MASK_X)) coord[0] -= data->priv->translation[0]; if (!(bc & TOOL_XYZ_MASK_Y)) coord[1] -= data->priv->translation[1]; if (!(bc & TOOL_XYZ_MASK_Z)) coord[2] -= data->priv->translation[2]; } /*****************/ /* Miscellaneous */ /*****************/ /** * visu_data_addNodeProperties: * @data: a #VisuData object. * @values: (transfer full): a #VisuNodeValues object. * * Add @values as a known #VisuNodeValues property of @data. * * Since: 3.8 * * Returns: TRUE if @values is added as a valid node property of @data. **/ gboolean visu_data_addNodeProperties(VisuData *data, VisuNodeValues *values) { g_return_val_if_fail(VISU_IS_DATA(data), FALSE); g_return_val_if_fail(visu_node_values_fromArray(values, VISU_NODE_ARRAY(data)), FALSE); if (g_hash_table_contains(data->priv->nodeProperties, visu_node_values_getLabel(values))) return FALSE; g_hash_table_insert(data->priv->nodeProperties, (gpointer)visu_node_values_getLabel(values), values); g_signal_emit(data, visu_data_signals[NODE_PROP_ADDED_SIGNAL], 0, values); return TRUE; } /** * visu_data_removeNodeProperties: * @data: a #VisuData object. * @label: a string. * * Look for a #VisuNodeValues object labelled by @label and remove it. * * Since: 3.8 * * Returns: TRUE if @label was indeed attached to @data. **/ gboolean visu_data_removeNodeProperties(VisuData *data, const gchar *label) { VisuNodeValues *values; g_return_val_if_fail(VISU_IS_DATA(data), FALSE); values = g_hash_table_lookup(data->priv->nodeProperties, label); if (!values) return FALSE; g_object_ref(values); g_hash_table_remove(data->priv->nodeProperties, label); g_signal_emit(data, visu_data_signals[NODE_PROP_REMOVED_SIGNAL], 0, values); g_object_unref(values); return TRUE; } static gint _sortProperties(const VisuNodeValues *propA, const VisuNodeValues *propB) { if (VISU_IS_NODE_VALUES_ID(propA)) return -1; else if (VISU_IS_NODE_VALUES_ID(propB)) return +1; else if (VISU_IS_NODE_VALUES(propA)) return -1; else if (VISU_IS_NODE_VALUES(propB)) return +1; else if (VISU_IS_NODE_VALUES_COORD(propA)) return -1; else if (VISU_IS_NODE_VALUES_COORD(propB)) return +1; else return g_strcmp0(visu_node_values_getLabel(propA), visu_node_values_getLabel(propB)); } /** * visu_data_getAllNodeProperties: * @data: a #VisuData object. * * Retrieve all the #VisuNodeValues objects attached to @data * formatted as a list. * * Since: 3.8 * * Returns: (transfer container) (element-type VisuNodeValues): a * newly created list of #VisuNodeValues objects. **/ GList* visu_data_getAllNodeProperties(VisuData *data) { g_return_val_if_fail(VISU_IS_DATA(data), (GList*)0); return g_list_sort(g_hash_table_get_values(data->priv->nodeProperties), (GCompareFunc)_sortProperties); } /** * visu_data_getNodeProperties: * @data: a #VisuData object. * @label: a string. * * Look for the #VisuNodeValues labelled by @label. * * Since: 3.8 * * Returns: (transfer none): the #VisuNodeValues object attached to * @data with @label, if any. **/ VisuNodeValues* visu_data_getNodeProperties(VisuData *data, const gchar *label) { g_return_val_if_fail(VISU_IS_DATA(data), (VisuNodeValues*)0); return g_hash_table_lookup(data->priv->nodeProperties, label); } #define DATA_LABEL_ID _("Label") /** * visu_data_getNodeLabels: * @data: a #VisuData object. * * Retrieve the #VisuNodeValuesString object that is used to store * labels, creating it if necessary. * * Since: 3.8 * * Returns: (transfer none): the #VisuNodeValuesString object used to * store labels. **/ VisuNodeValuesString* visu_data_getNodeLabels(VisuData *data) { VisuNodeValues *vals; vals = visu_data_getNodeProperties(data, DATA_LABEL_ID); if (!vals) { vals = VISU_NODE_VALUES(visu_node_values_string_new(VISU_NODE_ARRAY(data), DATA_LABEL_ID)); visu_data_addNodeProperties(data, vals); } return VISU_NODE_VALUES_STRING(vals); } /** * visu_data_getNodeLabelAt: * @data: a #VisuData object. * @node: a #VisuNode from @data. * * Retrieves the label associated to @node in @data. * * Since: 3.8 * * Returns: a label. **/ const gchar* visu_data_getNodeLabelAt(const VisuData *data, const VisuNode *node) { const VisuNodeValues *vals; vals = g_hash_table_lookup(data->priv->nodeProperties, DATA_LABEL_ID); if (!vals) return (const gchar*)0; return visu_node_values_string_getAt(VISU_NODE_VALUES_STRING(vals), node); } /** * visu_data_applyTransformationsFromCLI: * @data: a #VisuData object. * @error: an error location. * * Apply the extension and translation expressed in the command-line * arguments to @data. * * Since: 3.8 * * Returns: TRUE on success. **/ gboolean visu_data_applyTransformationsFromCLI(VisuData *data, GError **error) { gboolean isBox; float *translations, *extension; VisuVibration *vib; /* translate argument */ translations = commandLineGet_translation(&isBox); if (translations && !isBox) visu_pointset_setTranslationPeriodic(VISU_POINTSET(data), translations, TRUE); else if (translations && isBox) visu_pointset_setBoxTranslation(VISU_POINTSET(data), translations, TRUE); visu_pointset_setTranslationActive(VISU_POINTSET(data), (translations != (float*)0)); /* expand argument */ extension = commandLineGet_extension(); if (extension) visu_box_setExtension(visu_boxed_getBox(VISU_BOXED(data)), extension); visu_box_setExtensionActive(visu_boxed_getBox(VISU_BOXED(data)), (extension != (float*)0)); /* Vibration displacements. */ vib = visu_data_getVibration(data, 0); if (commandLineGet_phononMode() >= 0 && !vib) g_warning(_("option '--phonon-mode' has been given but" " no phonons are available.")); else if (commandLineGet_phononMode() >= 0) visu_vibration_setCurrentMode(vib, commandLineGet_phononMode(), error); if (error && *error) return FALSE; if (commandLineGet_phononTime() >= 0.f && !vib) g_warning(_("option '--time-opffset' has been given but" " no phonons are available.")); else if (commandLineGet_phononTime() >= 0) visu_vibration_setTime(vib, commandLineGet_phononTime()); if (commandLineGet_phononAmpl() >= 0.f && !vib) g_warning(_("option '--phonon-amplitude' has been given but" " no phonons are available.")); else if (commandLineGet_phononAmpl() >= 0) visu_vibration_setAmplitude(vib, commandLineGet_phononAmpl()); return TRUE; } v_sim-3.8.0/src/visu_data.h000066400000000000000000000135001370110300500155430ustar00rootroot00000000000000/* EXTRAITS DE LA LICENCE Copyright CEA, contributeurs : Luc BILLARD et Damien CALISTE, laboratoire L_Sim, (2001-2005) Adresse mèl : BILLARD, non joignable par mèl ; CALISTE, damien P caliste AT cea P fr. Ce logiciel est un programme informatique servant à visualiser des structures atomiques dans un rendu pseudo-3D. Ce logiciel est régi par la licence CeCILL soumise au droit français et respectant les principes de diffusion des logiciels libres. Vous pouvez utiliser, modifier et/ou redistribuer ce programme sous les conditions de la licence CeCILL telle que diffusée par le CEA, le CNRS et l'INRIA sur le site "http://www.cecill.info". Le fait que vous puissiez accéder à cet en-tête signifie que vous avez pris connaissance de la licence CeCILL, et que vous en avez accepté les termes (cf. le fichier Documentation/licence.fr.txt fourni avec ce logiciel). */ /* LICENCE SUM UP Copyright CEA, contributors : Luc BILLARD et Damien CALISTE, laboratoire L_Sim, (2001-2005) E-mail address: BILLARD, not reachable any more ; CALISTE, damien P caliste AT cea P fr. This software is a computer program whose purpose is to visualize atomic configurations in 3D. This software is governed by the CeCILL license under French law and abiding by the rules of distribution of free software. You can use, modify and/ or redistribute the software under the terms of the CeCILL license as circulated by CEA, CNRS and INRIA at the following URL "http://www.cecill.info". The fact that you are presently reading this means that you have had knowledge of the CeCILL license and that you accept its terms. You can find a copy of this licence shipped with this software at Documentation/licence.en.txt. */ #ifndef VISU_DATA_H #define VISU_DATA_H #include #include #include "visu_tools.h" #include "visu_elements.h" #include "visu_nodes.h" #include "extraFunctions/nodeProp.h" #include "extraFunctions/stringProp.h" #include "visu_box.h" #include "iface_boxed.h" #include "iface_pointset.h" #include "coreTools/toolPhysic.h" #include "coreTools/toolFileFormat.h" G_BEGIN_DECLS /** * VISU_TYPE_DATA: * * return the type of #VisuData. */ #define VISU_TYPE_DATA (visu_data_get_type ()) /** * VISU_DATA: * @obj: a #GObject to cast. * * Cast the given @obj into #VisuData type. */ #define VISU_DATA(obj) (G_TYPE_CHECK_INSTANCE_CAST(obj, VISU_TYPE_DATA, VisuData)) /** * VISU_DATA_CLASS: * @klass: a #GObjectClass to cast. * * Cast the given @klass into #VisuDataClass. */ #define VISU_DATA_CLASS(klass) (G_TYPE_CHECK_CLASS_CAST(klass, VISU_TYPE_DATA, VisuDataClass)) /** * VISU_IS_DATA: * @obj: a #GObject to test. * * Test if the given @ogj is of the type of #VisuData object. */ #define VISU_IS_DATA(obj) (G_TYPE_CHECK_INSTANCE_TYPE(obj, VISU_TYPE_DATA)) /** * VISU_IS_DATA_CLASS: * @klass: a #GObjectClass to test. * * Test if the given @klass is of the type of #VisuDataClass class. */ #define VISU_IS_DATA_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE(klass, VISU_TYPE_DATA)) /** * VISU_DATA_GET_CLASS: * @obj: a #GObject to get the class of. * * It returns the class of the given @obj. */ #define VISU_DATA_GET_CLASS(obj) (G_TYPE_INSTANCE_GET_CLASS(obj, VISU_TYPE_DATA, VisuDataClass)) typedef struct _VisuDataPrivate VisuDataPrivate; typedef struct _VisuData VisuData; /** * VisuData: * * Opaque structure for #VisuData objects. */ struct _VisuData { VisuNodeArray parent; VisuDataPrivate *priv; }; /** * VisuDataClass: * @parent: the parent class. * * A short way to identify #_VisuDataClass structure. */ typedef struct _VisuDataClass VisuDataClass; struct _VisuDataClass { VisuNodeArrayClass parent; }; /** * visu_data_get_type: * * This method returns the type of #VisuData, use VISU_TYPE_DATA instead. * * Returns: the type of #VisuData. */ GType visu_data_get_type(void); VisuData* visu_data_new(void); void visu_data_freePopulation(VisuData *data); void visu_data_setDescription(VisuData *data, const gchar* commentary); const gchar* visu_data_getDescription(const VisuData *data); gfloat visu_data_getAllNodeExtens(VisuData *dataObj, VisuBox *box); VisuNode* visu_data_addNodeFromElement(VisuData *data, VisuElement *ele, float xyz[3], gboolean reduced); VisuNode* visu_data_addNodeFromElementName(VisuData *data, const gchar *name, float xyz[3], gboolean reduced); VisuNode* visu_data_addNodeFromIndex(VisuData *data, guint position, float xyz[3], gboolean reduced); VisuBox* visu_data_setTightBox(VisuData *data); gboolean visu_data_getNodeBoxFromNumber(VisuData *data, guint nodeId, int nodeBox[3]); gboolean visu_data_getNodeBoxFromCoord(VisuData *data, float xcart[3], int nodeBox[3]); void visu_data_getNodeCoordinates(VisuData *data, VisuNode *node, gboolean user, float *x, float *y, float *z); void visu_data_getNodePosition(const VisuData *data, const VisuNode *node, float coord[3]); void visu_data_getNodeUserPosition(const VisuData *data, const VisuNode *node, float coord[3]); gboolean visu_data_setNewBasisFromNodes(VisuData *data, guint nO, guint nA, guint nB, guint nC); gboolean visu_data_setNewBasis(VisuData *data, float matA[3][3], float O[3]); gboolean visu_data_reorder(VisuData *data, const VisuData *dataRef); gboolean visu_data_addNodeProperties(VisuData *data, VisuNodeValues *values); gboolean visu_data_removeNodeProperties(VisuData *data, const gchar *label); GList* visu_data_getAllNodeProperties(VisuData *data); VisuNodeValues* visu_data_getNodeProperties(VisuData *data, const gchar *label); VisuNodeValuesString* visu_data_getNodeLabels(VisuData *data); const gchar* visu_data_getNodeLabelAt(const VisuData *data, const VisuNode *node); gboolean visu_data_applyTransformationsFromCLI(VisuData *data, GError **error); G_END_DECLS #endif v_sim-3.8.0/src/visu_dataatomic.c000066400000000000000000000324031370110300500167360ustar00rootroot00000000000000/* EXTRAITS DE LA LICENCE Copyright CEA, contributeurs : Damien CALISTE, laboratoire L_Sim, (2016) Adresse mèl : CALISTE, damien P caliste AT cea P fr. Ce logiciel est un programme informatique servant à visualiser des structures atomiques dans un rendu pseudo-3D. Ce logiciel est régi par la licence CeCILL soumise au droit français et respectant les principes de diffusion des logiciels libres. Vous pouvez utiliser, modifier et/ou redistribuer ce programme sous les conditions de la licence CeCILL telle que diffusée par le CEA, le CNRS et l'INRIA sur le site "http://www.cecill.info". Le fait que vous puissiez accéder à cet en-tête signifie que vous avez pris connaissance de la licence CeCILL, et que vous en avez accepté les termes (cf. le fichier Documentation/licence.fr.txt fourni avec ce logiciel). */ /* LICENCE SUM UP Copyright CEA, contributors : Damien CALISTE, laboratoire L_Sim, (2016) E-mail address: CALISTE, damien P caliste AT cea P fr. This software is a computer program whose purpose is to visualize atomic configurations in 3D. This software is governed by the CeCILL license under French law and abiding by the rules of distribution of free software. You can use, modify and/ or redistribute the software under the terms of the CeCILL license as circulated by CEA, CNRS and INRIA at the following URL "http://www.cecill.info". The fact that you are presently reading this means that you have had knowledge of the CeCILL license and that you accept its terms. You can find a copy of this licence shipped with this software at Documentation/licence.en.txt. */ #include "visu_dataatomic.h" #include "visu_basic.h" #include "loaders/atomic_ascii.h" #include "loaders/atomic_d3.h" #include "loaders/atomic_xyz.h" #include "loaders/atomic_yaml.h" /** * SECTION: visu_dataatomic * @short_description: a class of nodes representing atomic data and * providing associated loading methods. * * This class provides #VisuDataLoader for atomic data representation. */ enum { PROP_0, PROP_FILE, PROP_FORMAT, N_PROP, PROP_LABEL }; static GParamSpec *_properties[N_PROP]; struct _VisuDataAtomicPrivate { gchar *file; VisuDataLoader *format; }; static GList *_atomicFormats = NULL; static void _initAtomicFormats(void) { visu_data_atomic_class_addLoader(visu_data_loader_ascii_getStatic()); visu_data_atomic_class_addLoader(visu_data_loader_d3_getStatic()); visu_data_atomic_class_addLoader(visu_data_loader_xyz_getStatic()); if (visu_data_loader_yaml_getStatic()) visu_data_atomic_class_addLoader(visu_data_loader_yaml_getStatic()); } static void visu_data_atomic_finalize (GObject* obj); static void visu_data_atomic_get_property(GObject* obj, guint property_id, GValue *value, GParamSpec *pspec); static void visu_data_atomic_set_property(GObject* obj, guint property_id, const GValue *value, GParamSpec *pspec); static gboolean visu_data_atomic_load(VisuDataLoadable *self, guint iSet, GCancellable *cancel, GError **error); static const gchar* visu_data_atomic_getFilename(const VisuDataLoadable *self, guint fileType); G_DEFINE_TYPE_WITH_CODE(VisuDataAtomic, visu_data_atomic, VISU_TYPE_DATA_LOADABLE, G_ADD_PRIVATE(VisuDataAtomic)) static void visu_data_atomic_class_init(VisuDataAtomicClass *klass) { /* Connect the overloading methods. */ G_OBJECT_CLASS(klass)->finalize = visu_data_atomic_finalize; G_OBJECT_CLASS(klass)->get_property = visu_data_atomic_get_property; G_OBJECT_CLASS(klass)->set_property = visu_data_atomic_set_property; VISU_DATA_LOADABLE_CLASS(klass)->load = visu_data_atomic_load; VISU_DATA_LOADABLE_CLASS(klass)->getFilename = visu_data_atomic_getFilename; g_object_class_override_property(G_OBJECT_CLASS(klass), PROP_LABEL, "label"); /** * VisuDataAtomic::atomic-filename: * * The path to the source filename. * * Since: 3.8 */ _properties[PROP_FILE] = g_param_spec_string("atomic-filename", "Atomic filename", "source filename", (gchar*)0, G_PARAM_READWRITE | G_PARAM_CONSTRUCT_ONLY); /** * VisuDataAtomic::atomic-format: * * The format of the source filename, if known. * * Since: 3.8 */ _properties[PROP_FORMAT] = g_param_spec_object("atomic-format", "Atomic format", "source format", VISU_TYPE_DATA_LOADER, G_PARAM_READWRITE | G_PARAM_CONSTRUCT_ONLY); g_object_class_install_properties(G_OBJECT_CLASS(klass), N_PROP, _properties); _initAtomicFormats(); } static void visu_data_atomic_init(VisuDataAtomic *obj) { obj->priv = visu_data_atomic_get_instance_private(obj); /* Private data. */ obj->priv->file = (gchar*)0; obj->priv->format = (VisuDataLoader*)0; } static void visu_data_atomic_finalize(GObject* obj) { VisuDataAtomic *data; data = VISU_DATA_ATOMIC(obj); g_free(data->priv->file); /* Chain up to the parent class */ G_OBJECT_CLASS(visu_data_atomic_parent_class)->finalize(obj); } static void visu_data_atomic_get_property(GObject* obj, guint property_id, GValue *value, GParamSpec *pspec) { VisuDataAtomic *self = VISU_DATA_ATOMIC(obj); switch (property_id) { case PROP_LABEL: g_value_take_string(value, g_path_get_basename(self->priv->file)); break; case PROP_FILE: g_value_set_string(value, self->priv->file); break; case PROP_FORMAT: g_value_set_object(value, self->priv->format); break; default: /* We don't have any other property... */ G_OBJECT_WARN_INVALID_PROPERTY_ID(obj, property_id, pspec); break; } } static void visu_data_atomic_set_property(GObject* obj, guint property_id, const GValue *value, GParamSpec *pspec) { VisuDataAtomic *self = VISU_DATA_ATOMIC(obj); switch (property_id) { case PROP_FILE: self->priv->file = tool_path_normalize(g_value_get_string(value)); break; case PROP_FORMAT: self->priv->format = g_value_get_object(value); break; default: /* We don't have any other property... */ G_OBJECT_WARN_INVALID_PROPERTY_ID(obj, property_id, pspec); break; } } /** * visu_data_atomic_new: * @file: a filename. * @format: (allow-none): a #VisuDataLoader format, if known. * * Creates a #VisuDataAtomic object and set @file to it. * * Since: 3.8 * * Returns: a newly allocated #VisuDataAtomic object. **/ VisuDataAtomic* visu_data_atomic_new(const gchar *file, VisuDataLoader *format) { return g_object_new(VISU_TYPE_DATA_ATOMIC, "n-files", 1, "atomic-filename", file, "atomic-format", format, NULL); } /** * visu_data_atomic_class_addLoader: * @loader: (transfer full): a #VisuDataLoader object. * * Add @loader to the list of #VisuDataLoader to be used when * visu_data_loadable_load() is called. * * Since: 3.8 **/ void visu_data_atomic_class_addLoader(VisuDataLoader *loader) { if (g_list_find(_atomicFormats, loader)) return; g_return_if_fail(VISU_IS_DATA_LOADER(loader)); DBG_fprintf(stderr, "Data Atomic: adding a new loader '%s'.\n", tool_file_format_getName(TOOL_FILE_FORMAT(loader))); tool_file_format_setPropertiesFromCLI(TOOL_FILE_FORMAT(loader)); _atomicFormats = g_list_prepend(_atomicFormats, loader); _atomicFormats = g_list_sort(_atomicFormats, (GCompareFunc)visu_data_loader_comparePriority); } /** * visu_data_atomic_class_getLoaders: * * Returns a list of available #VisuDataLoader. * * Since: 3.8 * * Returns: (transfer none) (element-type VisuDataLoader): a list of * #VisuDataLoader owned by V_Sim. **/ GList* visu_data_atomic_class_getLoaders(void) { return _atomicFormats; } /** * visu_data_atomic_class_getFileDescription: * * Returns a translated string describing what is files loaded by * #VisuDataAtomic objects. * * Since: 3.8 * * Returns: a string owned by V_Sim. **/ const gchar* visu_data_atomic_class_getFileDescription(void) { return _("Position files"); } /** * visu_data_atomic_class_finalize: * * Empty the list of known loaders. * * Since: 3.8 **/ void visu_data_atomic_class_finalize(void) { g_list_free_full(_atomicFormats, (GDestroyNotify)g_object_unref); _atomicFormats = (GList*)0; } /** * visu_data_atomic_getFile: * @data: a #VisuDataAtomic object. * @format: (out caller-allocates): a location to store a * #VisuDataLoader object. * * Returns the file defined in @data and its associated @format, if any. * * Since: 3.8 * * Returns: a string owned by V_Sim. **/ const gchar* visu_data_atomic_getFile(VisuDataAtomic *data, VisuDataLoader **format) { g_return_val_if_fail(VISU_IS_DATA_ATOMIC(data), (const gchar*)0); if (format) *format = data->priv->format; return data->priv->file; } static const gchar* visu_data_atomic_getFilename(const VisuDataLoadable *self, guint fileType) { g_return_val_if_fail(fileType == 0, (const gchar*)0); return visu_data_atomic_getFile(VISU_DATA_ATOMIC(self), (VisuDataLoader**)0); } static gboolean _finalize(VisuDataAtomic *data, VisuDataLoader *loader) { VisuNodeArrayIter iter; ToolUnits unit, preferedUnit; VisuBox *box; /* We do a last check on population... in case. */ visu_node_array_iter_new(VISU_NODE_ARRAY(data), &iter); g_return_val_if_fail(iter.nAllStoredNodes, FALSE); DBG_fprintf(stderr, "Data Atomic: loading OK (%d nodes).\n", iter.nAllStoredNodes); /* Setup additional infos. */ box = visu_boxed_getBox(VISU_BOXED(data)); unit = visu_box_getUnit(box); preferedUnit = visu_basic_getPreferedUnit(); if (preferedUnit != TOOL_UNITS_UNDEFINED && unit != TOOL_UNITS_UNDEFINED && unit != preferedUnit) visu_box_setUnit(box, preferedUnit); visu_node_array_completeAdding(VISU_NODE_ARRAY(data)); data->priv->format = loader; return TRUE; } static gboolean _abort(VisuDataAtomic *data) { visu_node_array_completeAdding(VISU_NODE_ARRAY(data)); return FALSE; } static gboolean visu_data_atomic_load(VisuDataLoadable *self, guint iSet, GCancellable *cancel, GError **error) { VisuDataAtomic *data; GList *lst; VisuDataLoader *loader; g_return_val_if_fail(VISU_IS_DATA_ATOMIC(self), FALSE); data = VISU_DATA_ATOMIC(self); if (!visu_data_loadable_checkFile(self, 0, error)) return FALSE; visu_node_array_startAdding(VISU_NODE_ARRAY(self)); for (lst = _atomicFormats; lst; lst = g_list_next(lst)) { loader = VISU_DATA_LOADER(lst->data); /* Each load may set error even if the format is not recognise and loadOK is FALSE, then we need to free the error. */ g_clear_error(error); if (!data->priv->format || loader == data->priv->format) { DBG_fprintf(stderr,"Data Atomic: testing '%s' with format: %s.\n", data->priv->file, tool_file_format_getName(TOOL_FILE_FORMAT(loader))); if (visu_data_loader_load(loader, self, 0, iSet, cancel, error)) return (*error) ? _abort(data) : _finalize(data, loader); if (*error && (*error)->domain == G_FILE_ERROR) return _abort(data); if (*error && data->priv->format) return _abort(data); } } g_clear_error(error); g_set_error(error, VISU_DATA_LOADABLE_ERROR, DATA_LOADABLE_ERROR_UNKNOWN, _("Impossible to load '%s', unrecognised format.\n"), data->priv->file); return _abort(data); } /** * visu_data_atomic_loadAt: * @data: a #VisuDataAtomic object. * @filename: a filename. * @iSet: an id. * @cancel: a #GCancellable object. * @error: an error location. * * Specific routine to load an atomic file that is not stored in the * location declared at construction. This is only used for archive plug-in. * * Since: 3.8 * * Returns: TRUE on success. **/ gboolean visu_data_atomic_loadAt(VisuDataAtomic *data, const gchar *filename, guint iSet, GCancellable *cancel, GError **error) { gchar *old; gboolean res; g_return_val_if_fail(VISU_IS_DATA_ATOMIC(data), FALSE); old = data->priv->file; data->priv->file = (gchar*)filename; res = visu_data_atomic_load(VISU_DATA_LOADABLE(data), iSet, cancel, error); data->priv->file = old; return res; } /** * visu_data_atomic_getForces: * @dataObj: a #VisuDataAtomic object. * @create: a boolean. * * Retrieves the #VisuNodeValuesVector used to store forces for * @dataObj, create it depending on @create if not exists. * * Since: 3.8 * * Returns: (transfer none): a #VisuNodeValuesVector object, owned by V_Sim. **/ VisuNodeValuesVector* visu_data_atomic_getForces(VisuDataAtomic *dataObj, gboolean create) { VisuNodeValuesVector *vect; if (!dataObj) return (VisuNodeValuesVector*)0; vect = (VisuNodeValuesVector*)visu_data_getNodeProperties(VISU_DATA(dataObj), _("Forces")); if (!vect && create) { vect = visu_node_values_vector_new(VISU_NODE_ARRAY(dataObj), _("Forces")); visu_node_values_setEditable(VISU_NODE_VALUES(vect), FALSE); visu_data_addNodeProperties(VISU_DATA(dataObj), VISU_NODE_VALUES(vect)); } return vect; } v_sim-3.8.0/src/visu_dataatomic.h000066400000000000000000000110061370110300500167370ustar00rootroot00000000000000/* EXTRAITS DE LA LICENCE Copyright CEA, contributeurs : Damien CALISTE, laboratoire L_Sim, (2016) Adresse mèl : CALISTE, damien P caliste AT cea P fr. Ce logiciel est un programme informatique servant à visualiser des structures atomiques dans un rendu pseudo-3D. Ce logiciel est régi par la licence CeCILL soumise au droit français et respectant les principes de diffusion des logiciels libres. Vous pouvez utiliser, modifier et/ou redistribuer ce programme sous les conditions de la licence CeCILL telle que diffusée par le CEA, le CNRS et l'INRIA sur le site "http://www.cecill.info". Le fait que vous puissiez accéder à cet en-tête signifie que vous avez pris connaissance de la licence CeCILL, et que vous en avez accepté les termes (cf. le fichier Documentation/licence.fr.txt fourni avec ce logiciel). */ /* LICENCE SUM UP Copyright CEA, contributors : Damien CALISTE, laboratoire L_Sim, (2016) E-mail address: CALISTE, damien P caliste AT cea P fr. This software is a computer program whose purpose is to visualize atomic configurations in 3D. This software is governed by the CeCILL license under French law and abiding by the rules of distribution of free software. You can use, modify and/ or redistribute the software under the terms of the CeCILL license as circulated by CEA, CNRS and INRIA at the following URL "http://www.cecill.info". The fact that you are presently reading this means that you have had knowledge of the CeCILL license and that you accept its terms. You can find a copy of this licence shipped with this software at Documentation/licence.en.txt. */ #ifndef VISU_DATAATOMIC_H #define VISU_DATAATOMIC_H #include #include #include "visu_dataloadable.h" #include "visu_dataloader.h" #include "extraFunctions/vectorProp.h" G_BEGIN_DECLS /** * VISU_TYPE_DATA_ATOMIC: * * return the type of #VisuDataAtomic. */ #define VISU_TYPE_DATA_ATOMIC (visu_data_atomic_get_type ()) /** * VISU_DATA_ATOMIC: * @obj: a #GObject to cast. * * Cast the given @obj into #VisuDataAtomic type. */ #define VISU_DATA_ATOMIC(obj) (G_TYPE_CHECK_INSTANCE_CAST(obj, VISU_TYPE_DATA_ATOMIC, VisuDataAtomic)) /** * VISU_DATA_ATOMIC_CLASS: * @klass: a #GObjectClass to cast. * * Cast the given @klass into #VisuDataAtomicClass. */ #define VISU_DATA_ATOMIC_CLASS(klass) (G_TYPE_CHECK_CLASS_CAST(klass, VISU_TYPE_DATA_ATOMIC, VisuDataAtomicClass)) /** * VISU_IS_DATA_ATOMIC: * @obj: a #GObject to test. * * Test if the given @ogj is of the type of #VisuDataAtomic object. */ #define VISU_IS_DATA_ATOMIC(obj) (G_TYPE_CHECK_INSTANCE_TYPE(obj, VISU_TYPE_DATA_ATOMIC)) /** * VISU_IS_DATA_ATOMIC_CLASS: * @klass: a #GObjectClass to test. * * Test if the given @klass is of the type of #VisuDataAtomicClass class. */ #define VISU_IS_DATA_ATOMIC_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE(klass, VISU_TYPE_DATA_ATOMIC)) /** * VISU_DATA_ATOMIC_GET_CLASS: * @obj: a #GObject to get the class of. * * It returns the class of the given @obj. */ #define VISU_DATA_ATOMIC_GET_CLASS(obj) (G_TYPE_INSTANCE_GET_CLASS(obj, VISU_TYPE_DATA_ATOMIC, VisuDataAtomicClass)) typedef struct _VisuDataAtomicPrivate VisuDataAtomicPrivate; typedef struct _VisuDataAtomic VisuDataAtomic; /** * VisuDataAtomic: * * Structure used to define #VisuDataAtomic objects. * * Since: 3.8 */ struct _VisuDataAtomic { VisuDataLoadable parent; VisuDataAtomicPrivate *priv; }; /** * VisuDataAtomicClass: * @parent: the parent class. * * A short way to identify #_VisuDataAtomicClass structure. */ typedef struct _VisuDataAtomicClass VisuDataAtomicClass; struct _VisuDataAtomicClass { VisuDataLoadableClass parent; }; /** * visu_data_atomic_get_type: * * This method returns the type of #VisuDataAtomic, use VISU_TYPE_DATA_ATOMIC instead. * * Returns: the type of #VisuDataAtomic. */ GType visu_data_atomic_get_type(void); VisuDataAtomic* visu_data_atomic_new(const gchar *file, VisuDataLoader *format); const gchar* visu_data_atomic_getFile(VisuDataAtomic *data, VisuDataLoader **format); gboolean visu_data_atomic_loadAt(VisuDataAtomic *data, const gchar *filename, guint iSet, GCancellable *cancel, GError **error); VisuNodeValuesVector* visu_data_atomic_getForces(VisuDataAtomic *dataObj, gboolean create); void visu_data_atomic_class_addLoader(VisuDataLoader *loader); GList* visu_data_atomic_class_getLoaders(void); const gchar* visu_data_atomic_class_getFileDescription(void); void visu_data_atomic_class_finalize(void); G_END_DECLS #endif v_sim-3.8.0/src/visu_dataloadable.c000066400000000000000000000442041370110300500172270ustar00rootroot00000000000000/* EXTRAITS DE LA LICENCE Copyright CEA, contributeurs : Damien CALISTE, laboratoire L_Sim, (2016) Adresse mèl : CALISTE, damien P caliste AT cea P fr. Ce logiciel est un programme informatique servant à visualiser des structures atomiques dans un rendu pseudo-3D. Ce logiciel est régi par la licence CeCILL soumise au droit français et respectant les principes de diffusion des logiciels libres. Vous pouvez utiliser, modifier et/ou redistribuer ce programme sous les conditions de la licence CeCILL telle que diffusée par le CEA, le CNRS et l'INRIA sur le site "http://www.cecill.info". Le fait que vous puissiez accéder à cet en-tête signifie que vous avez pris connaissance de la licence CeCILL, et que vous en avez accepté les termes (cf. le fichier Documentation/licence.fr.txt fourni avec ce logiciel). */ /* LICENCE SUM UP Copyright CEA, contributors : Damien CALISTE, laboratoire L_Sim, (2016) E-mail address: CALISTE, damien P caliste AT cea P fr. This software is a computer program whose purpose is to visualize atomic configurations in 3D. This software is governed by the CeCILL license under French law and abiding by the rules of distribution of free software. You can use, modify and/ or redistribute the software under the terms of the CeCILL license as circulated by CEA, CNRS and INRIA at the following URL "http://www.cecill.info". The fact that you are presently reading this means that you have had knowledge of the CeCILL license and that you accept its terms. You can find a copy of this licence shipped with this software at Documentation/licence.en.txt. */ #include "visu_dataloadable.h" #include #include #include "visu_commandLine.h" #include "visu_dataatomic.h" #include "visu_dataspin.h" /** * SECTION: visu_dataloadable * @short_description: a base class for all loadable representation of * #VisuData objects. * * #VisuData is a memory representation of node data. This class * is defining common methods for all #VisuDataLoadable object that * provide disk method to load #VisuData objects. */ enum { PROP_0, PROP_N_SOURCES, PROP_LABEL, PROP_LOADING, PROP_STATUS, PROP_AUTO_REFRESH, PROP_REFRESH_PERIOD, N_PROPS }; static GParamSpec *_properties[N_PROPS]; /** * VisuDataLoadable: * * An opaque structure storing #VisuDataLoadable objects. * * Since: 3.8 */ struct _VisuDataLoadablePrivate { guint nFiles; guint nSets; guint iSet; gchar **labels; gboolean loading; gchar *status; gboolean autoRefresh; guint refreshPeriod, refreshId; time_t *lastReadTime; }; static void visu_data_loadable_finalize(GObject* obj); static void visu_data_loadable_get_property(GObject* obj, guint property_id, GValue *value, GParamSpec *pspec); static void visu_data_loadable_set_property(GObject* obj, guint property_id, const GValue *value, GParamSpec *pspec); static gboolean _reload(VisuDataLoadable *loadable); G_DEFINE_TYPE_WITH_CODE(VisuDataLoadable, visu_data_loadable, VISU_TYPE_DATA, G_ADD_PRIVATE(VisuDataLoadable)) static void visu_data_loadable_class_init(VisuDataLoadableClass *klass) { G_OBJECT_CLASS(klass)->finalize = visu_data_loadable_finalize; G_OBJECT_CLASS(klass)->get_property = visu_data_loadable_get_property; G_OBJECT_CLASS(klass)->set_property = visu_data_loadable_set_property; /** * VisuDataLoadable::n-files: * * Number of input files. * * Since: 3.8 */ _properties[PROP_N_SOURCES] = g_param_spec_uint("n-files", "N files", "number of input files", 1, 10, 1, G_PARAM_READWRITE | G_PARAM_CONSTRUCT_ONLY); /** * VisuDataLoadable::label: * * A string that can be displayed representing the file names. * * Since: 3.8 */ _properties[PROP_LABEL] = g_param_spec_string("label", "Label", "representation of the filenames", _("No input files"), G_PARAM_READABLE); /** * VisuDataLoadable::loading: * * TRUE during the loading of a file. * * Since: 3.8 */ _properties[PROP_LOADING] = g_param_spec_boolean("loading", "Loading", "TRUE when a file is loading", FALSE, G_PARAM_READABLE); /** * VisuDataLoadable::status: * * A string describing the current status of the load process. * * Since: 3.8 */ _properties[PROP_STATUS] = g_param_spec_string("status", "Status", "loading status", "", G_PARAM_READABLE); /** * VisuDataLoadable::auto-refresh: * * TRUE if any modification on input file should produce a refresh. * * Since: 3.8 */ _properties[PROP_AUTO_REFRESH] = g_param_spec_boolean("auto-refresh", "Auto refresh", "automatically reload on modification", FALSE, G_PARAM_READWRITE); /** * VisuDataLoadable::refresh-period: * * Polling period for automatic reload in seconds. * * Since: 3.8 */ _properties[PROP_REFRESH_PERIOD] = g_param_spec_uint("refresh-period", "Refresh period", "Refresh period in seconds", 1, 3600, 1, G_PARAM_READWRITE); g_object_class_install_properties(G_OBJECT_CLASS(klass), N_PROPS, _properties); } static void visu_data_loadable_init(VisuDataLoadable *obj) { obj->priv = visu_data_loadable_get_instance_private(obj); obj->priv->iSet = 0; obj->priv->nSets = 0; obj->priv->status = (gchar*)0; obj->priv->refreshId = 0; obj->priv->autoRefresh = FALSE; obj->priv->refreshPeriod = 1; obj->priv->lastReadTime = (time_t*)0; obj->priv->labels = (gchar**)0; visu_data_loadable_setNSets(obj, 1); } static void visu_data_loadable_get_property(GObject* obj, guint property_id, GValue *value, GParamSpec *pspec) { VisuDataLoadable *self = VISU_DATA_LOADABLE(obj); switch (property_id) { case PROP_N_SOURCES: g_value_set_uint(value, self->priv->nFiles); break; case PROP_LABEL: g_value_set_static_string(value, _("No file")); break; case PROP_LOADING: g_value_set_boolean(value, self->priv->loading); break; case PROP_STATUS: if (self->priv->loading) g_value_set_string(value, self->priv->status); else g_value_set_string(value, (const gchar*)0); break; case PROP_AUTO_REFRESH: g_value_set_boolean(value, self->priv->autoRefresh); break; case PROP_REFRESH_PERIOD: g_value_set_uint(value, self->priv->refreshPeriod); break; default: /* We don't have any other property... */ G_OBJECT_WARN_INVALID_PROPERTY_ID(obj, property_id, pspec); break; } } static void visu_data_loadable_set_property(GObject* obj, guint property_id, const GValue *value, GParamSpec *pspec) { VisuDataLoadable *self = VISU_DATA_LOADABLE(obj); switch (property_id) { case PROP_N_SOURCES: self->priv->nFiles = g_value_get_uint(value); self->priv->lastReadTime = g_malloc0(sizeof(time_t) * self->priv->nFiles); break; case PROP_AUTO_REFRESH: if (g_value_get_boolean(value) == self->priv->autoRefresh) return; self->priv->autoRefresh = g_value_get_boolean(value); if (self->priv->refreshId && !self->priv->autoRefresh) { g_source_remove(self->priv->refreshId); self->priv->refreshId = 0; } if (!self->priv->refreshId && self->priv->autoRefresh) self->priv->refreshId = g_timeout_add_seconds(self->priv->refreshPeriod, (GSourceFunc)_reload, obj); break; case PROP_REFRESH_PERIOD: if (g_value_get_uint(value) == self->priv->refreshPeriod) return; self->priv->refreshPeriod = g_value_get_uint(value); if (self->priv->refreshId) { g_source_remove(self->priv->refreshId); self->priv->refreshId = 0; } if (self->priv->autoRefresh) self->priv->refreshId = g_timeout_add_seconds(self->priv->refreshPeriod, (GSourceFunc)_reload, obj); break; default: /* We don't have any other property... */ G_OBJECT_WARN_INVALID_PROPERTY_ID(obj, property_id, pspec); break; } } static void visu_data_loadable_finalize(GObject* obj) { VisuDataLoadable *self; self = VISU_DATA_LOADABLE(obj); g_free(self->priv->status); if (self->priv->refreshId) g_source_remove(self->priv->refreshId); g_free(self->priv->lastReadTime); g_strfreev(self->priv->labels); /* Chain up to the parent class */ G_OBJECT_CLASS(visu_data_loadable_parent_class)->finalize(obj); } static GQuark quark = (GQuark)0; /** * visu_data_loadable_getErrorQuark: * * Internal function to handle error. * * Returns: a #GQuark for #VisuDataLoadable method errors. */ GQuark visu_data_loadable_getErrorQuark(void) { if (!quark) quark = g_quark_from_static_string("visu_data_loadable"); return quark; } /** * visu_data_loadable_getFilename: * @self: a #VisuDataLoadable object. * @type: when the loadable is multi-files, the type of file. * * Returns the source filename for @type. * * Since: 3.8 * * Returns: a filename. **/ const gchar* visu_data_loadable_getFilename(const VisuDataLoadable *self, guint type) { g_return_val_if_fail(VISU_IS_DATA_LOADABLE(self), (const gchar*)0); if (VISU_DATA_LOADABLE_GET_CLASS(self)->getFilename) return VISU_DATA_LOADABLE_GET_CLASS(self)->getFilename(self, type); else return (const gchar*)0; } static gboolean _reload(VisuDataLoadable *loadable) { struct stat statBuf; gboolean res; const gchar *file; guint i; GError *error; for (i = 0; i < loadable->priv->nFiles; i++) { file = visu_data_loadable_getFilename(loadable, i); g_return_val_if_fail(file, FALSE); if (!stat(file, &statBuf) && statBuf.st_ctime > loadable->priv->lastReadTime[i]) { error = (GError*)0; res = visu_data_loadable_reload(loadable, (GCancellable*)0, &error); return loadable->priv->autoRefresh && res; } } return loadable->priv->autoRefresh; } /** * visu_data_loadable_checkFile: * @self: a #VisuDataLoadable object. * @fileType: a file type. * @error: an error location. * * Tests if the provided file for a given @fileType is a valid file. * * Since: 3.8 * * Returns: TRUE if the file set for @fileType is a valid file. **/ gboolean visu_data_loadable_checkFile(VisuDataLoadable *self, guint fileType, GError **error) { const gchar *file; #if GLIB_MINOR_VERSION > 5 struct stat buf; #endif g_return_val_if_fail(!error || !*error, FALSE); file = visu_data_loadable_getFilename(self, fileType); if (!file) { *error = g_error_new(VISU_DATA_LOADABLE_ERROR, DATA_LOADABLE_ERROR_FILE, _("No filename available.")); return FALSE; } if (!g_file_test(file, G_FILE_TEST_IS_REGULAR)) { *error = g_error_new(VISU_DATA_LOADABLE_ERROR, DATA_LOADABLE_ERROR_FILE, _("File '%s' is not a regular file or may not exist."), file); return FALSE; } #if GLIB_MINOR_VERSION > 5 if (!g_stat(file, &buf) && buf.st_size == 0) { *error = g_error_new(VISU_DATA_LOADABLE_ERROR, DATA_LOADABLE_ERROR_FILE, _("File '%s' is empty."), file); return FALSE; } #endif return TRUE; } #define USE_TASK 0 #if GLIB_MINOR_VERSION > 35 && USE_TASK == 1 static void _load(GTask *task _U_, VisuDataLoadable *self, gpointer data, GCancellable *cancel) { GError *error; error = (GError*)0; VISU_DATA_LOADABLE_GET_CLASS(self)->load(self, GPOINTER_TO_INT(data), cancel, &error); if (error) g_task_return_error(task, error); else g_task_return_boolean(task, TRUE); } #endif /** * visu_data_loadable_load: * @self: a #VisuDataLoadable object. * @iSet: an integer. * @cancel: (allow-none): a cancellation object. * @error: an error location. * * Call the load class method of @self. Also store the last read time * for each file of @self. * * Since: 3.8 * * Returns: TRUE if @delf is successfully loaded. **/ gboolean visu_data_loadable_load(VisuDataLoadable *self, guint iSet, GCancellable *cancel, GError **error) { gboolean res; guint i; const gchar *file; struct stat statBuf; #if GLIB_MINOR_VERSION > 35 && USE_TASK == 1 GTask *task; #endif g_return_val_if_fail(VISU_IS_DATA_LOADABLE(self), FALSE); g_return_val_if_fail(!self->priv->loading && VISU_DATA_LOADABLE_GET_CLASS(self)->load, FALSE); g_return_val_if_fail(!visu_node_array_getNNodes(VISU_NODE_ARRAY(self)), FALSE); self->priv->loading = TRUE; g_object_notify_by_pspec(G_OBJECT(self), _properties[PROP_LOADING]); #if GLIB_MINOR_VERSION > 35 && USE_TASK == 1 task = g_task_new(self, cancel, NULL, NULL); g_task_set_task_data(task, GINT_TO_POINTER(iSet), (GDestroyNotify)0); g_task_run_in_thread_sync(task, (GTaskThreadFunc)_load); res = GPOINTER_TO_INT(g_task_propagate_pointer(task, error)); g_object_unref(task); #else res = VISU_DATA_LOADABLE_GET_CLASS(self)->load(self, iSet, cancel, error); #endif self->priv->iSet = iSet; self->priv->loading = FALSE; g_object_notify_by_pspec(G_OBJECT(self), _properties[PROP_LOADING]); if (res) for (i = 0; i < self->priv->nFiles; i++) { file = visu_data_loadable_getFilename(self, i); g_return_val_if_fail(file, res); if (!stat(file, &statBuf)) self->priv->lastReadTime[i] = statBuf.st_ctime; } return res; } /** * visu_data_loadable_reload: * @self: a #VisuDataLoadable object. * @cancel: (allow-none): a cancellation object. * @error: an error location. * * A wrapper to load again the same sub set of self. * * Since: 3.8 * * Returns: TRUE if reload of @self is successful. **/ gboolean visu_data_loadable_reload(VisuDataLoadable *self, GCancellable *cancel, GError **error) { g_return_val_if_fail(VISU_IS_DATA_LOADABLE(self), FALSE); visu_data_freePopulation(VISU_DATA(self)); return visu_data_loadable_load(self, self->priv->iSet, cancel, error); } /** * visu_data_loadable_getSetId: * @self: a #VisuDataLoadable object. * * Some loadable format can store several #VisuData (like a MD * trajectory), see the @iSet attribute in visu_data_loadable_load(). * * Since: 3.8 * * Returns: the set id that has been loaded. **/ guint visu_data_loadable_getSetId(const VisuDataLoadable *self) { g_return_val_if_fail(VISU_IS_DATA_LOADABLE(self), G_MAXUINT); return self->priv->iSet; } /** * visu_data_loadable_setNSets: * @self: a #VisuDataLoadable object. * @nSets: a positive number. * * Setup the number of #VisuData that @self is storing on disk. * * Since: 3.8 * * Returns: TRUE if the actual number of sets for @self has changed. **/ gboolean visu_data_loadable_setNSets(VisuDataLoadable *self, guint nSets) { guint i; g_return_val_if_fail(VISU_IS_DATA_LOADABLE(self), FALSE); if (self->priv->nSets == nSets) return FALSE; self->priv->nSets = nSets; if (self->priv->labels) g_strfreev(self->priv->labels); self->priv->labels = g_malloc(sizeof(gchar*) * (nSets + 1)); for (i = 0; i < nSets; i++) self->priv->labels[i] = g_strdup(""); self->priv->labels[nSets] = (gchar*)0; return TRUE; } /** * visu_data_loadable_getNSets: * @self: a #VisuDataLoadable object. * * Some loadable format can store several #VisuData (like a MD * trajectory), see the @iSet attribute in visu_data_loadable_load(). * * Since: 3.8 * * Returns: the set number of sets that has been read. **/ guint visu_data_loadable_getNSets(const VisuDataLoadable *self) { g_return_val_if_fail(VISU_IS_DATA_LOADABLE(self), G_MAXUINT); return self->priv->nSets; } /** * visu_data_loadable_getSetLabel: * @self: a #VisuDataLoadable object. * @iSet: an id. * * Retrieves a possible label for the given set. If @iSet is the * currently loaded set, then this method is equivalent to calling * visu_data_getDescription(). * * Since: 3.8 * * Returns: a label. **/ const gchar* visu_data_loadable_getSetLabel(const VisuDataLoadable *self, guint iSet) { g_return_val_if_fail(VISU_IS_DATA_LOADABLE(self) && iSet < self->priv->nSets, (const gchar*)0); if (iSet == self->priv->iSet) return visu_data_getDescription(VISU_DATA(self)); else return self->priv->labels[iSet]; } /** * visu_data_loadable_setSetLabel: * @self: a #VisuDataLoadable object ; * @label: the message to be stored (null terminated) ; * @iSet: an integer. * * This method is used to store a description of the given @data. Before using this * method, the number of possible node sets must have been defined * using visu_data_loadable_setNSets(), if not, only iSet == 0 is allowed. */ void visu_data_loadable_setSetLabel(VisuDataLoadable *self, const gchar* label, guint iSet) { g_return_if_fail(VISU_IS_DATA_LOADABLE(self) && iSet < self->priv->nSets); g_free(self->priv->labels[iSet]); self->priv->labels[iSet] = g_strdup(label); if (self->priv->iSet == iSet) visu_data_setDescription(VISU_DATA(self), label); } /** * visu_data_loadable_new_fromCLI: * * Read the command line option and set the filenames for a new * #VisuData. The object is not loaded (files are not parsed), just prepared. * * Returns: (transfer full): a newly allocated #VisuData if required. */ VisuDataLoadable* visu_data_loadable_new_fromCLI(void) { char* filename, *spin_filename; VisuDataLoadable *newData; newData = (VisuDataLoadable*)0; DBG_fprintf(stderr, "Visu DataLoadable: create data from command line arguments.\n"); filename = commandLineGet_ArgFilename(); spin_filename = commandLineGet_ArgSpinFileName(); if (filename && !spin_filename) newData = VISU_DATA_LOADABLE(visu_data_atomic_new(filename, (VisuDataLoader*)0)); else if(filename && spin_filename) newData = VISU_DATA_LOADABLE(visu_data_spin_new(filename, spin_filename, (VisuDataLoader*)0, (VisuDataLoader*)0)); return newData; } v_sim-3.8.0/src/visu_dataloadable.h000066400000000000000000000117141370110300500172340ustar00rootroot00000000000000/* EXTRAITS DE LA LICENCE Copyright CEA, contributeurs : Damien CALISTE, laboratoire L_Sim, (2016) Adresse mèl : CALISTE, damien P caliste AT cea P fr. Ce logiciel est un programme informatique servant à visualiser des structures atomiques dans un rendu pseudo-3D. Ce logiciel est régi par la licence CeCILL soumise au droit français et respectant les principes de diffusion des logiciels libres. Vous pouvez utiliser, modifier et/ou redistribuer ce programme sous les conditions de la licence CeCILL telle que diffusée par le CEA, le CNRS et l'INRIA sur le site "http://www.cecill.info". Le fait que vous puissiez accéder à cet en-tête signifie que vous avez pris connaissance de la licence CeCILL, et que vous en avez accepté les termes (cf. le fichier Documentation/licence.fr.txt fourni avec ce logiciel). */ /* LICENCE SUM UP Copyright CEA, contributors : Damien CALISTE, laboratoire L_Sim, (2016) E-mail address: CALISTE, damien P caliste AT cea P fr. This software is a computer program whose purpose is to visualize atomic configurations in 3D. This software is governed by the CeCILL license under French law and abiding by the rules of distribution of free software. You can use, modify and/ or redistribute the software under the terms of the CeCILL license as circulated by CEA, CNRS and INRIA at the following URL "http://www.cecill.info". The fact that you are presently reading this means that you have had knowledge of the CeCILL license and that you accept its terms. You can find a copy of this licence shipped with this software at Documentation/licence.en.txt. */ #ifndef VISU_DATA_LOADABLE_H #define VISU_DATA_LOADABLE_H #include #include #include #include "visu_data.h" G_BEGIN_DECLS #define VISU_TYPE_DATA_LOADABLE (visu_data_loadable_get_type ()) #define VISU_DATA_LOADABLE(obj) (G_TYPE_CHECK_INSTANCE_CAST ((obj), VISU_TYPE_DATA_LOADABLE, VisuDataLoadable)) #define VISU_DATA_LOADABLE_CLASS(klass) (G_TYPE_CHECK_CLASS_CAST ((klass), VISU_TYPE_DATA_LOADABLE, VisuDataLoadableClass)) #define VISU_IS_DATA_LOADABLE(obj) (G_TYPE_CHECK_INSTANCE_TYPE ((obj), VISU_TYPE_DATA_LOADABLE)) #define VISU_IS_DATA_LOADABLE_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE ((klass), VISU_TYPE_DATA_LOADABLE)) #define VISU_DATA_LOADABLE_GET_CLASS(obj) (G_TYPE_INSTANCE_GET_CLASS(obj, VISU_TYPE_DATA_LOADABLE, VisuDataLoadableClass)) typedef struct _VisuDataLoadable VisuDataLoadable; typedef struct _VisuDataLoadablePrivate VisuDataLoadablePrivate; struct _VisuDataLoadable { VisuData parent; VisuDataLoadablePrivate *priv; }; typedef struct _VisuDataLoadableClass VisuDataLoadableClass; /** * VisuDataLoadableClass: * @parent: the parent class. * @getFilename: a method used to get the filename associated to * specific type. * @load: the loading method. * * The #VisuDataLoadableClass definition. * * Since: 3.8 */ struct _VisuDataLoadableClass { VisuDataClass parent; const gchar* (*getFilename) (const VisuDataLoadable *self, guint type); gboolean (*load) (VisuDataLoadable *self, guint iSet, GCancellable *cancel, GError **error); }; GType visu_data_loadable_get_type (void); /** * VisuDataLoadableErrorFlag: * @DATA_LOADABLE_ERROR_METHOD: Error from the #VisuDataLoadable method. * @DATA_LOADABLE_ERROR_FILE: Error when opening. * @DATA_LOADABLE_ERROR_FORMAT: Wrongness in format. * @DATA_LOADABLE_ERROR_UNKNOWN: an error without specification. * @DATA_LOADABLE_ERROR_CANCEL: the #VisuDataLoadable operation has been cancelled. * * Thiese are flags used when reading a file with a #VisuDataLoadable method. */ typedef enum { DATA_LOADABLE_ERROR_METHOD, DATA_LOADABLE_ERROR_FILE, DATA_LOADABLE_ERROR_FORMAT, DATA_LOADABLE_ERROR_UNKNOWN, DATA_LOADABLE_ERROR_CANCEL } VisuDataLoadableErrorFlag; /** * VISU_DATA_LOADABLE_ERROR: * * Domain of error for #VisuDataLoadable objects. */ #define VISU_DATA_LOADABLE_ERROR visu_data_loadable_getErrorQuark() GQuark visu_data_loadable_getErrorQuark(void); VisuDataLoadable* visu_data_loadable_new_fromCLI(void); gboolean visu_data_loadable_checkFile(VisuDataLoadable *self, guint fileType, GError **error); const gchar* visu_data_loadable_getFilename(const VisuDataLoadable *self, guint type); gboolean visu_data_loadable_load(VisuDataLoadable *self, guint iSet, GCancellable *cancel, GError **error); gboolean visu_data_loadable_reload(VisuDataLoadable *self, GCancellable *cancel, GError **error); guint visu_data_loadable_getSetId(const VisuDataLoadable *self); gboolean visu_data_loadable_setNSets(VisuDataLoadable *self, guint nSets); guint visu_data_loadable_getNSets(const VisuDataLoadable *self); const gchar* visu_data_loadable_getSetLabel(const VisuDataLoadable *self, guint iSet); void visu_data_loadable_setSetLabel(VisuDataLoadable *self, const gchar* label, guint iSet); G_END_DECLS #endif v_sim-3.8.0/src/visu_dataloader.c000066400000000000000000000324701370110300500167340ustar00rootroot00000000000000/* EXTRAITS DE LA LICENCE Copyright CEA, contributeurs : Damien CALISTE, laboratoire L_Sim, (2016) Adresse mèl : CALISTE, damien P caliste AT cea P fr. Ce logiciel est un programme informatique servant à visualiser des structures atomiques dans un rendu pseudo-3D. Ce logiciel est régi par la licence CeCILL soumise au droit français et respectant les principes de diffusion des logiciels libres. Vous pouvez utiliser, modifier et/ou redistribuer ce programme sous les conditions de la licence CeCILL telle que diffusée par le CEA, le CNRS et l'INRIA sur le site "http://www.cecill.info". Le fait que vous puissiez accéder à cet en-tête signifie que vous avez pris connaissance de la licence CeCILL, et que vous en avez accepté les termes (cf. le fichier Documentation/licence.fr.txt fourni avec ce logiciel). */ /* LICENCE SUM UP Copyright CEA, contributors : Damien CALISTE, laboratoire L_Sim, (2016) E-mail address: CALISTE, damien P caliste AT cea P fr. This software is a computer program whose purpose is to visualize atomic configurations in 3D. This software is governed by the CeCILL license under French law and abiding by the rules of distribution of free software. You can use, modify and/ or redistribute the software under the terms of the CeCILL license as circulated by CEA, CNRS and INRIA at the following URL "http://www.cecill.info". The fact that you are presently reading this means that you have had knowledge of the CeCILL license and that you accept its terms. You can find a copy of this licence shipped with this software at Documentation/licence.en.txt. */ #include "visu_dataloader.h" /** * SECTION: visu_dataloader * @short_description: a base class for all load methods. * * This is a base class to define load methods for atomic or * spin data. */ struct _VisuDataLoaderPrivate { VisuDataLoaderFunc load; GDestroyNotify notify; gpointer data; guint priority; gchar *status; }; enum { PROP_0, PROP_STATUS, N_PROP }; static GParamSpec *_properties[N_PROP]; static void visu_data_loader_finalize (GObject* obj); static void visu_data_loader_get_property(GObject* obj, guint property_id, GValue *value, GParamSpec *pspec); G_DEFINE_TYPE_WITH_CODE(VisuDataLoader, visu_data_loader, TOOL_TYPE_FILE_FORMAT, G_ADD_PRIVATE(VisuDataLoader)) static void visu_data_loader_class_init(VisuDataLoaderClass *klass) { G_OBJECT_CLASS(klass)->finalize = visu_data_loader_finalize; G_OBJECT_CLASS(klass)->get_property = visu_data_loader_get_property; /** * VisuDataLoader::status: * * A string describing the current status of the load process. * * Since: 3.8 */ _properties[PROP_STATUS] = g_param_spec_string("status", "Status", "loading status", "", G_PARAM_READABLE); } static void visu_data_loader_init(VisuDataLoader *obj) { obj->priv = visu_data_loader_get_instance_private(obj); obj->priv->status = (gchar*)0; obj->priv->load = (VisuDataLoaderFunc)0; obj->priv->notify = (GDestroyNotify)0; obj->priv->data = (gpointer)0; } static void visu_data_loader_get_property(GObject* obj, guint property_id, GValue *value, GParamSpec *pspec) { VisuDataLoader *self = VISU_DATA_LOADER(obj); switch (property_id) { case PROP_STATUS: g_value_set_string(value, self->priv->status); break; default: /* We don't have any other property... */ G_OBJECT_WARN_INVALID_PROPERTY_ID(obj, property_id, pspec); break; } } static void visu_data_loader_finalize(GObject* obj) { VisuDataLoader *data; data = VISU_DATA_LOADER(obj); g_free(data->priv->status); if (data->priv->notify) data->priv->notify(data->priv->data); /* Chain up to the parent class */ G_OBJECT_CLASS(visu_data_loader_parent_class)->finalize(obj); } /** * visu_data_loader_new: (skip) * @descr: a string describing the object, translated and in UTF8. * @patterns: (array zero-terminated=1): the patterns used to identify files of this type. * @restricted: a boolean. * @func: a loading method. * @priority: a integer. * * Creates a new #VisuDataLoader with the given description. * * Since: 3.8 * * Returns: (transfer full): a newly created #VisuDataLoader object. **/ VisuDataLoader* visu_data_loader_new(const gchar* descr, const gchar** patterns, gboolean restricted, VisuDataLoaderFunc func, guint priority) { return visu_data_loader_new_full(descr, patterns, restricted, func, priority, (GDestroyNotify)0, (gpointer)0); } /** * visu_data_loader_new_full: (rename-to visu_data_loader_new) * @descr: a string describing the object, translated and in UTF8. * @patterns: (array zero-terminated=1): the patterns used to identify files of this type. * @restricted: a boolean. * @func: (scope notified): a loading method. * @priority: a integer. * @notify: (allow-none): a function. * @data: (closure): some data. * * Creates a new #VisuDataLoader with the given description. * * Since: 3.8 * * Returns: (transfer full): a newly created #VisuDataLoader object. **/ VisuDataLoader* visu_data_loader_new_full(const gchar* descr, const gchar** patterns, gboolean restricted, VisuDataLoaderFunc func, guint priority, GDestroyNotify notify, gpointer data) { VisuDataLoader *loader; loader = g_object_new(VISU_TYPE_DATA_LOADER, "name", descr, "ignore-type", restricted, NULL); tool_file_format_addPatterns(TOOL_FILE_FORMAT(loader), patterns); loader->priv->load = func; loader->priv->notify = notify; loader->priv->data = data; loader->priv->priority = priority; return loader; } /** * visu_data_loader_comparePriority: * @a: a #VisuDataLoader object. * @b: a #VisuDataLoader object. * * Compare the priority of @a and @b. * * Since: 3.8 * * Returns: -1 if @a is at a lower priority than @b, +1 otherwise and * 0 in case of equality. **/ gint visu_data_loader_comparePriority(const VisuDataLoader *a, const VisuDataLoader *b) { g_return_val_if_fail(VISU_IS_DATA_LOADER(a) && VISU_IS_DATA_LOADER(b), 0); if (a->priv->priority < b->priv->priority) return -1; else if (a->priv->priority > b->priv->priority) return +1; else return 0; } /** * visu_data_loader_load: * @loader: a #VisuDataLoader object. * @data: a #VisuDataLoadable object to be populated. * @type: a file type. * @iSet: an integer. * @cancel: (allow-none): a cancellation object. * @error: an error location. * * Try to load @filename as a file format corresponding to * @loader. @error is not set if @filename is not of this format, * simply %FALSE is returned. * * Since: 3.8 * * Returns: TRUE if @filename is of a format handled by @loader. **/ gboolean visu_data_loader_load(VisuDataLoader *loader, VisuDataLoadable *data, guint type, guint iSet, GCancellable *cancel, GError **error) { gboolean res; g_return_val_if_fail(VISU_IS_DATA_LOADER(loader), FALSE); if (loader->priv->load) { visu_data_loader_setStatus(loader, _("Loading...")); DBG_fprintf(stderr, "Visu Loader: data obj has %d ref count.\n", G_OBJECT(data)->ref_count); res = loader->priv->load(loader, data, type, iSet, cancel, error); DBG_fprintf(stderr, "Visu Loader: data obj has %d ref count.\n", G_OBJECT(data)->ref_count); return res; } else return FALSE; } /** * visu_data_loader_setStatus: * @loader: a #VisuDataLoader object. * @status: a string. * * Change the current status of @loader. This can be used to notify * changes when visu_data_loader_load() is taking long time. * * Since: 3.8 **/ void visu_data_loader_setStatus(VisuDataLoader *loader, const gchar *status) { g_return_if_fail(VISU_IS_DATA_LOADER(loader)); g_free(loader->priv->status); loader->priv->status = g_strdup(status); g_object_notify_by_pspec(G_OBJECT(loader), _properties[PROP_STATUS]); } /** * VisuDataLoaderIter: * * Structure used to define #VisuDataLoaderIter objects. * * Since: 3.8 */ struct _VisuDataLoaderIter { guint refcount; GHashTable *elements; }; struct _OneElement { const VisuElement *ele; guint pos; guint nbNodes; }; GType visu_data_loader_iter_get_type(void) { static GType g_define_type_id = 0; if (g_define_type_id == 0) g_define_type_id = g_boxed_type_register_static ("VisuDataLoaderIter", (GBoxedCopyFunc)visu_data_loader_iter_ref, (GBoxedFreeFunc)visu_data_loader_iter_unref); return g_define_type_id; } /** * visu_data_loader_iter_new: * * Creates a newly allocated iterator. This iterator can be used to * accumulate nodes when parsing a file. When parsing is finished, use * visu_data_loader_iter_allocate() to allocate enough memory in a * #VisuNodeArray to store the parsed data. * * Since: 3.8 * * Returns: (transfer full): a newly allocated #VisuDataLoaderIter * object. Use visu_data_loader_iter_unref() when no longer needed. **/ VisuDataLoaderIter* visu_data_loader_iter_new() { VisuDataLoaderIter *iter; iter = g_malloc(sizeof(VisuDataLoaderIter)); iter->refcount = 1; iter->elements = g_hash_table_new_full(g_direct_hash, g_direct_equal, NULL, g_free); return iter; } /** * visu_data_loader_iter_addNode: * @iter: a #VisuDataLoaderIter object. * @element: a #VisuElement object. * * Register an additional node of type @element. * * Since: 3.8 **/ void visu_data_loader_iter_addNode(VisuDataLoaderIter *iter, const VisuElement *element) { struct _OneElement *infos; g_return_if_fail(iter); infos = (struct _OneElement*)g_hash_table_lookup(iter->elements, element); if (!infos) { infos = g_malloc(sizeof(struct _OneElement)); infos->ele = element; infos->pos = g_hash_table_size(iter->elements); infos->nbNodes = 1; g_hash_table_insert(iter->elements, (gpointer)element, infos); } else infos->nbNodes += 1; } static void _valToType(gpointer key _U_, gpointer value, gpointer data) { struct _OneElement *infos; infos = (struct _OneElement *)value; DBG_fprintf(stderr, " | %d -> '%s' (%p).\n", infos->pos, infos->ele->name, (gpointer)infos->ele); g_array_index((GArray*)data, const VisuElement*, infos->pos) = infos->ele; } static GArray* _createElementArray(const VisuDataLoaderIter *iter) { GArray *types; g_return_val_if_fail(iter, (GArray*)0); types = g_array_sized_new(FALSE, FALSE, sizeof(VisuElement*), g_hash_table_size(iter->elements)); g_array_set_size(types, g_hash_table_size(iter->elements)); g_hash_table_foreach(iter->elements, _valToType, types); return types; } static void _valToNb(gpointer key _U_, gpointer value, gpointer data) { struct _OneElement *infos; infos = (struct _OneElement *)value; DBG_fprintf(stderr, " | %d -> %d.\n", infos->pos, infos->nbNodes); g_array_index((GArray*)data, guint, infos->pos) = infos->nbNodes; } static GArray* _createSizeArray(const VisuDataLoaderIter *iter) { GArray *nattyp; g_return_val_if_fail(iter, (GArray*)0); nattyp = g_array_sized_new(FALSE, FALSE, sizeof(guint), g_hash_table_size(iter->elements)); g_array_set_size(nattyp, g_hash_table_size(iter->elements)); g_hash_table_foreach(iter->elements, _valToNb, nattyp); return nattyp; } /** * visu_data_loader_iter_allocate: * @iter: a #VisuDataLoaderIter object. * @array: a #VisuNodeArray object. * * Call visu_node_array_allocate() on @array with the proper * #VisuElement list and number of nodes as registered in @iter. * * Since: 3.8 * * Returns: the total number of nodes registered in @iter. **/ guint visu_data_loader_iter_allocate(VisuDataLoaderIter *iter, VisuNodeArray *array) { GArray *types, *nattyp; guint i, natom; g_return_val_if_fail(iter && VISU_IS_NODE_ARRAY(array), 0); DBG_fprintf(stderr, "Visu Data Loader: allocate for %d elements.\n", g_hash_table_size(iter->elements)); types = _createElementArray(iter); nattyp = _createSizeArray(iter); natom = 0; for (i = 0; i < types->len; i++) natom += g_array_index(nattyp, guint, i); if (!natom) { g_array_free(nattyp, TRUE); g_array_free(types, TRUE); return 0; } /* Allocate the space for the nodes. */ visu_node_array_allocate(array, types, nattyp); g_array_free(nattyp, TRUE); g_array_free(types, TRUE); return natom; } /** * visu_data_loader_iter_unref: * @iter: a #VisuDataLoaderIter object. * * Decrement the reference counter of @iter. When counter reaches 0, * the memory occupied by @iter is freed. * * Since: 3.8 **/ void visu_data_loader_iter_unref(VisuDataLoaderIter *iter) { g_return_if_fail(iter); iter->refcount -= 1; if (!iter->refcount) { g_hash_table_destroy(iter->elements); g_free(iter); } } /** * visu_data_loader_iter_ref: * @iter: a #VisuDataLoaderIter object. * * Increment the reference counter on @iter. * * Since: 3.8 * * Returns: (transfer full): a pointer on @iter. **/ VisuDataLoaderIter* visu_data_loader_iter_ref(VisuDataLoaderIter *iter) { g_return_val_if_fail(iter, (VisuDataLoaderIter*)0); iter->refcount += 1; return iter; } v_sim-3.8.0/src/visu_dataloader.h000066400000000000000000000136611370110300500167420ustar00rootroot00000000000000/* EXTRAITS DE LA LICENCE Copyright CEA, contributeurs : Damien CALISTE, laboratoire L_Sim, (2016) Adresse mèl : CALISTE, damien P caliste AT cea P fr. Ce logiciel est un programme informatique servant à visualiser des structures atomiques dans un rendu pseudo-3D. Ce logiciel est régi par la licence CeCILL soumise au droit français et respectant les principes de diffusion des logiciels libres. Vous pouvez utiliser, modifier et/ou redistribuer ce programme sous les conditions de la licence CeCILL telle que diffusée par le CEA, le CNRS et l'INRIA sur le site "http://www.cecill.info". Le fait que vous puissiez accéder à cet en-tête signifie que vous avez pris connaissance de la licence CeCILL, et que vous en avez accepté les termes (cf. le fichier Documentation/licence.fr.txt fourni avec ce logiciel). */ /* LICENCE SUM UP Copyright CEA, contributors : Damien CALISTE, laboratoire L_Sim, (2016) E-mail address: CALISTE, damien P caliste AT cea P fr. This software is a computer program whose purpose is to visualize atomic configurations in 3D. This software is governed by the CeCILL license under French law and abiding by the rules of distribution of free software. You can use, modify and/ or redistribute the software under the terms of the CeCILL license as circulated by CEA, CNRS and INRIA at the following URL "http://www.cecill.info". The fact that you are presently reading this means that you have had knowledge of the CeCILL license and that you accept its terms. You can find a copy of this licence shipped with this software at Documentation/licence.en.txt. */ #ifndef VISU_DATA_LOADER_H #define VISU_DATA_LOADER_H #include #include #include #include "coreTools/toolFileFormat.h" #include "visu_dataloadable.h" G_BEGIN_DECLS /** * VISU_TYPE_DATA_LOADER: * * Return the associated #GType to the VisuDataLoader objects. */ #define VISU_TYPE_DATA_LOADER (visu_data_loader_get_type ()) /** * VISU_DATA_LOADER: * @obj: the widget to cast. * * Cast the given object to a #VisuDataLoader object. */ #define VISU_DATA_LOADER(obj) (G_TYPE_CHECK_INSTANCE_CAST ((obj), VISU_TYPE_DATA_LOADER, VisuDataLoader)) /** * VISU_DATA_LOADER_CLASS: * @klass: the class to cast. * * Cast the given class to a #VisuDataLoaderClass object. */ #define VISU_DATA_LOADER_CLASS(klass) (G_TYPE_CHECK_CLASS_CAST ((klass), VISU_TYPE_DATA_LOADER, VisuDataLoaderClass)) /** * VISU_IS_DATA_LOADER: * @obj: the object to test. * * Return if the given object is a valid #VisuDataLoader object. */ #define VISU_IS_DATA_LOADER(obj) (G_TYPE_CHECK_INSTANCE_TYPE ((obj), VISU_TYPE_DATA_LOADER)) /** * VISU_IS_DATA_LOADER_CLASS: * @klass: the class to test. * * Return if the given class is a valid #VisuDataLoaderClass class. */ #define VISU_IS_DATA_LOADER_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE ((klass), VISU_TYPE_DATA_LOADER)) /** * VISU_DATA_LOADER_GET_CLASS: * @obj: the widget to get the class of. * * Get the class of the given object. */ #define VISU_DATA_LOADER_GET_CLASS(obj) (G_TYPE_INSTANCE_GET_CLASS(obj, VISU_TYPE_DATA_LOADER, VisuDataLoaderClass)) /** * VisuDataLoader: * * An opaque structure. */ typedef struct _VisuDataLoader VisuDataLoader; typedef struct _VisuDataLoaderPrivate VisuDataLoaderPrivate; struct _VisuDataLoader { ToolFileFormat parent; VisuDataLoaderPrivate *priv; }; /** * VisuDataLoaderClass: * @parent: the parent class. * * An opaque structure. */ typedef struct _VisuDataLoaderClass VisuDataLoaderClass; struct _VisuDataLoaderClass { ToolFileFormatClass parent; }; /** * VisuDataLoaderFunc: * @self: a #VisuDataLoader object. * @data: the #VisuDataLoadable object to populate. * @type: the type of file to populate in @data. * @iSet: an integer specifying the set to load, if any. * @cancel: (allow-none): a #GCancellable object. * @error: (allow-none): an error location. * * Prototype of function to load a file and populate @data * accordingly. The file is taken from * visu_data_loadable_getFilename() using @type. * * Since: 3.8 * * Returns: TRUE if the file matches the format defined by @self, * even if some parsing errors may occur. */ typedef gboolean (*VisuDataLoaderFunc)(VisuDataLoader *self, VisuDataLoadable *data, guint type, guint iSet, GCancellable *cancel, GError **error); /** * visu_data_loader_get_type * * #GType are unique numbers to identify objects. * * Returns: the #GType associated with #VisuDataLoader objects. */ GType visu_data_loader_get_type(void); VisuDataLoader* visu_data_loader_new(const gchar* descr, const gchar** patterns, gboolean restricted, VisuDataLoaderFunc func, guint priority); VisuDataLoader* visu_data_loader_new_full(const gchar* descr, const gchar** patterns, gboolean restricted, VisuDataLoaderFunc func, guint priority, GDestroyNotify notify, gpointer data); gint visu_data_loader_comparePriority(const VisuDataLoader *a, const VisuDataLoader *b); gboolean visu_data_loader_load(VisuDataLoader *loader, VisuDataLoadable *data, guint type, guint iSet, GCancellable *cancel, GError **error); void visu_data_loader_setStatus(VisuDataLoader *loader, const gchar *status); typedef struct _VisuDataLoaderIter VisuDataLoaderIter; GType visu_data_loader_iter_get_type(void); VisuDataLoaderIter* visu_data_loader_iter_new(); void visu_data_loader_iter_addNode(VisuDataLoaderIter *iter, const VisuElement *element); guint visu_data_loader_iter_allocate(VisuDataLoaderIter *iter, VisuNodeArray *array); void visu_data_loader_iter_unref(VisuDataLoaderIter *iter); VisuDataLoaderIter* visu_data_loader_iter_ref(VisuDataLoaderIter *iter); G_END_DECLS #endif v_sim-3.8.0/src/visu_dataspin.c000066400000000000000000000520251370110300500164350ustar00rootroot00000000000000/* EXTRAITS DE LA LICENCE Copyright CEA, contributeurs : Damien CALISTE, laboratoire L_Sim, (2016) Adresse mèl : CALISTE, damien P caliste AT cea P fr. Ce logiciel est un programme informatique servant à visualiser des structures atomiques dans un rendu pseudo-3D. Ce logiciel est régi par la licence CeCILL soumise au droit français et respectant les principes de diffusion des logiciels libres. Vous pouvez utiliser, modifier et/ou redistribuer ce programme sous les conditions de la licence CeCILL telle que diffusée par le CEA, le CNRS et l'INRIA sur le site "http://www.cecill.info". Le fait que vous puissiez accéder à cet en-tête signifie que vous avez pris connaissance de la licence CeCILL, et que vous en avez accepté les termes (cf. le fichier Documentation/licence.fr.txt fourni avec ce logiciel). */ /* LICENCE SUM UP Copyright CEA, contributors : Damien CALISTE, laboratoire L_Sim, (2016) E-mail address: CALISTE, damien P caliste AT cea P fr. This software is a computer program whose purpose is to visualize atomic configurations in 3D. This software is governed by the CeCILL license under French law and abiding by the rules of distribution of free software. You can use, modify and/ or redistribute the software under the terms of the CeCILL license as circulated by CEA, CNRS and INRIA at the following URL "http://www.cecill.info". The fact that you are presently reading this means that you have had knowledge of the CeCILL license and that you accept its terms. You can find a copy of this licence shipped with this software at Documentation/licence.en.txt. */ #include "visu_dataspin.h" #include "coreTools/toolFortran.h" /** * SECTION: visu_dataspin * @short_description: a class of nodes representing spin data and * providing associated loading methods. * * This class provides #VisuDataLoader for spin data representation. */ #define SPIN_PROP_ID _("Spin (\316\270, \317\206, mod.)") #define SPIN_MAX_MOD_ID "spin_max_modulus_id" enum { PROP_0, PROP_FILE, PROP_FORMAT, N_PROP, PROP_LABEL, N_PROP_TOT }; static GParamSpec *_properties[N_PROP]; struct _VisuDataSpinPrivate { gchar *file; VisuDataLoader *format; /* These are cached pointers to the values. */ GArray *maxModulus; VisuNodeValuesVector *spin; }; static GList *_spinFormats = NULL; static void visu_data_spin_finalize (GObject* obj); static void visu_data_spin_get_property(GObject* obj, guint property_id, GValue *value, GParamSpec *pspec); static void visu_data_spin_set_property(GObject* obj, guint property_id, const GValue *value, GParamSpec *pspec); static const gchar* visu_data_spin_getFilename(const VisuDataLoadable *self, guint fileType); static gboolean visu_data_spin_load(VisuDataLoadable *self, guint iSet, GCancellable *cancel, GError **error); static gboolean read_spin_file(VisuDataLoader *loader, VisuDataLoadable *data, guint type, guint nSet, GCancellable *cancel, GError **error); static gboolean read_binary_file(VisuDataLoader *loader, VisuDataLoadable *data, guint type, guint nSet, GCancellable *cancel, GError **error); static void _initSpinFormats(void) { const gchar *typeSpin[] = {"*.spin", "*.sp", NULL}; const gchar *typeBinary[] = {"*.bspin", "*.bsp", NULL}; visu_data_spin_class_addLoader(visu_data_loader_new (_("Ascii spin files"), typeSpin, FALSE, read_spin_file, 100)); visu_data_spin_class_addLoader(visu_data_loader_new (_("Binary spin files"), typeBinary, FALSE, read_binary_file, 10)); } /* Local methods. */ G_DEFINE_TYPE_WITH_CODE(VisuDataSpin, visu_data_spin, VISU_TYPE_DATA_ATOMIC, G_ADD_PRIVATE(VisuDataSpin)) static void visu_data_spin_class_init(VisuDataSpinClass *klass) { /* Connect the overloading methods. */ G_OBJECT_CLASS(klass)->finalize = visu_data_spin_finalize; G_OBJECT_CLASS(klass)->get_property = visu_data_spin_get_property; G_OBJECT_CLASS(klass)->set_property = visu_data_spin_set_property; VISU_DATA_LOADABLE_CLASS(klass)->load = visu_data_spin_load; VISU_DATA_LOADABLE_CLASS(klass)->getFilename = visu_data_spin_getFilename; g_object_class_override_property(G_OBJECT_CLASS(klass), PROP_LABEL, "label"); /** * VisuDataAtomic::spin-filename: * * The path to the source filename. * * Since: 3.8 */ _properties[PROP_FILE] = g_param_spec_string("spin-filename", "Spin filename", "source filename", (gchar*)0, G_PARAM_READWRITE | G_PARAM_CONSTRUCT_ONLY); /** * VisuDataAtomic::spin-format: * * The format of the source filename, if known. * * Since: 3.8 */ _properties[PROP_FORMAT] = g_param_spec_object("spin-format", "Spin format", "source format", VISU_TYPE_DATA_LOADER, G_PARAM_READWRITE | G_PARAM_CONSTRUCT_ONLY); g_object_class_install_properties(G_OBJECT_CLASS(klass), N_PROP, _properties); _initSpinFormats(); } static void visu_data_spin_init(VisuDataSpin *obj) { obj->priv = visu_data_spin_get_instance_private(obj); /* Private data. */ obj->priv->file = (gchar*)0; obj->priv->format = (VisuDataLoader*)0; } static void visu_data_spin_finalize(GObject* obj) { VisuDataSpin *data; data = VISU_DATA_SPIN(obj); g_free(data->priv->file); /* Chain up to the parent class */ G_OBJECT_CLASS(visu_data_spin_parent_class)->finalize(obj); } static void visu_data_spin_get_property(GObject* obj, guint property_id, GValue *value, GParamSpec *pspec) { gchar *at, *sp; VisuDataSpin *self = VISU_DATA_SPIN(obj); switch (property_id) { case PROP_LABEL: at = g_path_get_basename(visu_data_atomic_getFile(VISU_DATA_ATOMIC(self), (VisuDataLoader**)0)); sp = g_path_get_basename(self->priv->file); g_value_take_string(value, g_strdup_printf("%s \302\240\342\200\224 %s", at, sp)); g_free(at); g_free(sp); break; case PROP_FILE: g_value_set_string(value, self->priv->file); break; case PROP_FORMAT: g_value_set_object(value, self->priv->format); break; default: /* We don't have any other property... */ G_OBJECT_WARN_INVALID_PROPERTY_ID(obj, property_id, pspec); break; } } static void visu_data_spin_set_property(GObject* obj, guint property_id, const GValue *value, GParamSpec *pspec) { VisuDataSpin *self = VISU_DATA_SPIN(obj); switch (property_id) { case PROP_FILE: self->priv->file = tool_path_normalize(g_value_get_string(value)); break; case PROP_FORMAT: self->priv->format = g_value_get_object(value); break; default: /* We don't have any other property... */ G_OBJECT_WARN_INVALID_PROPERTY_ID(obj, property_id, pspec); break; } } /** * visu_data_spin_new: * @atomic: a filename. * @spin: a filename. * @atomicFormat: (allow-none): a #VisuDataLoader format, if known. * @spinFormat: (allow-none): a #VisuDataLoader format, if known. * * Creates a #VisuDataSpin object and set @atomic as its atomic file * source and @file for the spin source. * * Since: 3.8 * * Returns: a newly allocated #VisuDataSpin object. **/ VisuDataSpin* visu_data_spin_new(const gchar *atomic, const gchar *spin, VisuDataLoader *atomicFormat, VisuDataLoader *spinFormat) { return g_object_new(VISU_TYPE_DATA_SPIN, "n-files", 2, "atomic-filename", atomic, "spin-filename", spin, "atomic-format", atomicFormat, "spin-format", spinFormat, NULL); } /** * visu_data_spin_class_addLoader: * @loader: (transfer full): a #VisuDataSpin object. * * Add @loader to the list of #VisuDataLoader to be used when * visu_data_loadable_load() is called. * * Since: 3.8 **/ void visu_data_spin_class_addLoader(VisuDataLoader *loader) { if (g_list_find(_spinFormats, loader)) return; _spinFormats = g_list_prepend(_spinFormats, loader); _spinFormats = g_list_sort(_spinFormats, (GCompareFunc)visu_data_loader_comparePriority); } /** * visu_data_spin_class_getLoaders: * * Returns a list of available #VisuDataLoader. * * Since: 3.8 * * Returns: (transfer none) (element-type VisuDataLoader): a list of * #VisuDataLoader owned by V_Sim. **/ GList* visu_data_spin_class_getLoaders(void) { return _spinFormats; } /** * visu_data_spin_class_getFileDescription: * * Returns a translated string describing what is files loaded by * #VisuDataSpin objects. * * Since: 3.8 * * Returns: a string owned by V_Sim. **/ const gchar* visu_data_spin_class_getFileDescription(void) { return _("Spin files"); } /** * visu_data_spin_class_finalize: * * Empty the list of known loaders. * * Since: 3.8 **/ void visu_data_spin_class_finalize(void) { g_list_free_full(_spinFormats, (GDestroyNotify)g_object_unref); _spinFormats = (GList*)0; } static const gchar* visu_data_spin_getFilename(const VisuDataLoadable *self, guint fileType) { g_return_val_if_fail(VISU_IS_DATA_SPIN(self) && fileType < 2, (const gchar*)0); if (fileType == 1) return visu_data_spin_getFile(VISU_DATA_SPIN(self), (VisuDataLoader**)0); else return visu_data_atomic_getFile(VISU_DATA_ATOMIC(self), (VisuDataLoader**)0); } /** * visu_data_spin_getFile: * @data: a #VisuDataSpin object. * @format: (out caller-allocates): a location to store the format. * * Retrieve the spin filename. Optionally provides also the format of * this file. If the file has been parsed this is the detected * format. If not, this is the supposed format, as proposed by user. * * Since: 3.8 * * Returns: a filename. **/ const gchar* visu_data_spin_getFile(VisuDataSpin *data, VisuDataLoader **format) { g_return_val_if_fail(VISU_IS_DATA_SPIN(data), (const gchar*)0); if (format) *format = data->priv->format; return data->priv->file; } static gboolean visu_data_spin_load(VisuDataLoadable *self, guint iSet, GCancellable *cancel, GError **error) { VisuDataSpin *data; GList *lst; VisuDataLoader *loader; g_return_val_if_fail(VISU_IS_DATA_SPIN(self), FALSE); if (!VISU_DATA_LOADABLE_CLASS(visu_data_spin_parent_class)->load(self, iSet, cancel, error)) return FALSE; data = VISU_DATA_SPIN(self); if (!visu_data_loadable_checkFile(self, 1, error)) return FALSE; for (lst = _spinFormats; lst; lst = g_list_next(lst)) { loader = VISU_DATA_LOADER(lst->data); /* Each load may set error even if the format is not recognise and loadOK is FALSE, then we need to free the error. */ g_clear_error(error); if (!data->priv->format || loader == data->priv->format) { DBG_fprintf(stderr,"Data Spin: testing '%s' with format: %s.\n", data->priv->file, tool_file_format_getName(TOOL_FILE_FORMAT(loader))); if (visu_data_loader_load(loader, self, 1, iSet, cancel, error)) return TRUE; if (*error && (*error)->domain == G_FILE_ERROR) return FALSE; } } g_clear_error(error); g_set_error(error, VISU_DATA_LOADABLE_ERROR, DATA_LOADABLE_ERROR_UNKNOWN, _("Impossible to load '%s', unrecognised format.\n"), data->priv->file); return FALSE; } static void initMaxModulus(VisuElement *ele _U_, GValue *val) { DBG_fprintf(stderr, " | init max modulus of val %p.\n", (gpointer)val); g_value_init(val, G_TYPE_FLOAT); g_value_set_float(val, -G_MAXFLOAT); } /** * visu_data_spin_get: * @dataObj: a #VisuDataSpin object. * * Retrieve the #VisuNodeValuesVector object stroing the spin * components per #VisuNode. * * Since: 3.8 * * Returns: (transfer none): the #VisuNodeValuesVector storing the spi * components of @dataObj. **/ const VisuNodeValuesVector* visu_data_spin_get(const VisuDataSpin *dataObj) { return VISU_NODE_VALUES_VECTOR(visu_data_getNodeProperties(VISU_DATA(dataObj), SPIN_PROP_ID)); } /** * visu_data_spin_setAt: * @dataObj: a #VisuDataSpin object. * @node: a #VisuNode object. * @vals: (array fixed-size=3): a vector in cartesian coordinates. * * Store @vals as the spin representation for @node in @dataObj. * * Since: 3.8 **/ void visu_data_spin_setAt(VisuDataSpin *dataObj, const VisuNode *node, const gfloat vals[3]) { GValue *val; const gfloat* sph; g_return_if_fail(VISU_IS_DATA_SPIN(dataObj)); if (!dataObj->priv->spin) { dataObj->priv->spin = visu_node_values_vector_new(VISU_NODE_ARRAY(dataObj), SPIN_PROP_ID); visu_data_addNodeProperties(VISU_DATA(dataObj), VISU_NODE_VALUES(dataObj->priv->spin)); } visu_node_values_vector_setAt(dataObj->priv->spin, node, vals); sph = visu_node_values_vector_getAtSpherical(dataObj->priv->spin, node); if (!dataObj->priv->maxModulus) dataObj->priv->maxModulus = visu_node_array_setElementProperty (VISU_NODE_ARRAY(dataObj), SPIN_MAX_MOD_ID, initMaxModulus); val = &g_array_index(dataObj->priv->maxModulus, GValue, node->posElement); g_value_set_float(val, MAX(sph[TOOL_MATRIX_SPHERICAL_MODULUS], g_value_get_float(val))); } /** * visu_data_spin_setAtSpherical: * @dataObj: a #VisuDataSpin object. * @node: a #VisuNode object. * @vals: (array fixed-size=3): a vector in spherical coordinates. * * Store @vals as the spin representation for @node in @dataObj. * * Since: 3.8 **/ void visu_data_spin_setAtSpherical(VisuDataSpin *dataObj, const VisuNode *node, const gfloat vals[3]) { GValue *val; g_return_if_fail(VISU_IS_DATA_SPIN(dataObj)); if (!dataObj->priv->spin) { dataObj->priv->spin = visu_node_values_vector_new(VISU_NODE_ARRAY(dataObj), SPIN_PROP_ID); visu_data_addNodeProperties(VISU_DATA(dataObj), VISU_NODE_VALUES(dataObj->priv->spin)); } visu_node_values_vector_setAtSpherical(dataObj->priv->spin, node, vals); if (!dataObj->priv->maxModulus) dataObj->priv->maxModulus = visu_node_array_setElementProperty (VISU_NODE_ARRAY(dataObj), SPIN_MAX_MOD_ID, initMaxModulus); val = &g_array_index(dataObj->priv->maxModulus, GValue, node->posElement); g_value_set_float(val, MAX(vals[TOOL_MATRIX_SPHERICAL_MODULUS], g_value_get_float(val))); } /** * visu_data_spin_getMaxModulus: * @dataObj: a #VisuDataSpin object. * @iElement: an integer. * * Inquires the max spin modulous from @dataObj for the given * #VisuElement represented by @iElement. * * Since: 3.8 * * Returns: a positive float. **/ gfloat visu_data_spin_getMaxModulus(const VisuDataSpin *dataObj, guint iElement) { GValue *val; g_return_val_if_fail(VISU_IS_DATA_SPIN(dataObj), 1.f); g_return_val_if_fail(dataObj->priv->maxModulus && iElement < dataObj->priv->maxModulus->len, 1.f); val = &g_array_index(dataObj->priv->maxModulus, GValue, iElement); return g_value_get_float(val); } /*****************************************************************************/ /* */ /*****************************************************************************/ /* The following are the methods responsible of dealing with the reading of files. */ /*****************************************************************************/ /* */ /*****************************************************************************/ /* This is the method associated to the reading of supported spin files. */ static gboolean read_spin_file(VisuDataLoader *loader _U_, VisuDataLoadable *data, guint type, guint nSet _U_, GCancellable *cancel _U_, GError **error) { char line[TOOL_MAX_LINE_LENGTH] = "\0"; float vals[3]; int itrash, iLine; VisuNodeArrayIter iter; FILE *readFrom; gboolean readContinue; g_return_val_if_fail(error && *error == (GError*)0, FALSE); readFrom = fopen(visu_data_loadable_getFilename(data, type), "r"); if (!readFrom) { *error = g_error_new(VISU_DATA_LOADABLE_ERROR, DATA_LOADABLE_ERROR_FILE, _("impossible to open this spin file.\n")); return FALSE; } iLine = 1; /* The first line is a commentry. */ if(!fgets(line, TOOL_MAX_LINE_LENGTH, readFrom) || feof(readFrom)) { *error = g_error_new(VISU_DATA_LOADABLE_ERROR, DATA_LOADABLE_ERROR_FORMAT, _("spin file should have one line at least.\n")); fclose(readFrom); return FALSE; } iLine += 1; readContinue = TRUE; visu_node_array_iter_new(VISU_NODE_ARRAY(data), &iter); for(visu_node_array_iterStartNumber(VISU_NODE_ARRAY(data), &iter); iter.node; visu_node_array_iterNextNodeNumber(VISU_NODE_ARRAY(data), &iter)) { if (readContinue) { if(!fgets(line, TOOL_MAX_LINE_LENGTH, readFrom) || feof(readFrom)) readContinue = FALSE; else { if(sscanf(line, "%d %f %f %f", &itrash, vals + TOOL_MATRIX_SPHERICAL_MODULUS, vals + TOOL_MATRIX_SPHERICAL_THETA, vals + TOOL_MATRIX_SPHERICAL_PHI) != 4) { g_warning("line number #%d is invalid." " Setting node parameters to default ones...", iLine); vals[TOOL_MATRIX_SPHERICAL_THETA] = 0.f; vals[TOOL_MATRIX_SPHERICAL_PHI] = 0.f; vals[TOOL_MATRIX_SPHERICAL_MODULUS] = 0.f; } } iLine += 1; } else { vals[TOOL_MATRIX_SPHERICAL_THETA] = 0.f; vals[TOOL_MATRIX_SPHERICAL_PHI] = 0.f; vals[TOOL_MATRIX_SPHERICAL_MODULUS] = 0.f; } visu_data_spin_setAtSpherical(VISU_DATA_SPIN(data), iter.node, vals); } fclose(readFrom); return TRUE; } /* This is the method associated to the reading of binary spin files. */ static gboolean read_binary_file(VisuDataLoader *loader _U_, VisuDataLoadable *data, guint type, guint nSet _U_, GCancellable *cancel _U_, GError **error) { ToolFiles *readFrom; gboolean valid; ToolFortranEndianId endian; guint nspins; GArray *mods, *thetas, *phis; int i; float vals[3]; VisuNodeArrayIter iter; g_return_val_if_fail(error && *error == (GError*)0, FALSE); readFrom = tool_files_new(); if (!tool_files_fortran_open(readFrom, visu_data_loadable_getFilename(data, type), error)) return FALSE; /* Try to find the endianness. */ if (!tool_files_fortran_testEndianness(readFrom, 4, &endian)) { g_object_unref(readFrom); return FALSE; } /* Try to the number of spins. */ if (!tool_files_fortran_readInteger(readFrom, (gint*)&nspins, endian, error)) { g_object_unref(readFrom); return FALSE; } if (!tool_files_fortran_checkFlag(readFrom, 4, endian, error)) { g_object_unref(readFrom); return FALSE; } /* From now on, we consider to a have valid spin file. */ visu_node_array_iter_new(VISU_NODE_ARRAY(data), &iter); if (nspins != iter.nAllStoredNodes) { g_set_error(error, VISU_DATA_LOADABLE_ERROR, DATA_LOADABLE_ERROR_FORMAT, _("number of spin differs from number of nodes.\n")); g_object_unref(readFrom); return TRUE; } /* Read module. */ valid = tool_files_fortran_readDoubleArray(readFrom, &mods, nspins, endian, TRUE, error); if (!valid) { g_object_unref(readFrom); return TRUE; } /* Read theta. */ valid = tool_files_fortran_readDoubleArray(readFrom, &thetas, nspins, endian, TRUE, error); if (!valid) { g_array_unref(mods); g_object_unref(readFrom); return TRUE; } /* Read phi. */ valid = tool_files_fortran_readDoubleArray(readFrom, &phis, nspins, endian, TRUE, error); if (!valid) { g_array_unref(mods); g_array_unref(thetas); g_object_unref(readFrom); return TRUE; } /* Close the file. */ g_object_unref(readFrom); for(visu_node_array_iterStart(VISU_NODE_ARRAY(data), &iter), i = 0; iter.node; visu_node_array_iterNext(VISU_NODE_ARRAY(data), &iter), i++) { vals[TOOL_MATRIX_SPHERICAL_MODULUS] = g_array_index(mods, double, i); vals[TOOL_MATRIX_SPHERICAL_THETA] = g_array_index(thetas, double, i); vals[TOOL_MATRIX_SPHERICAL_PHI] = g_array_index(phis, double, i); visu_data_spin_setAtSpherical(VISU_DATA_SPIN(data), iter.node, vals); } g_array_unref(mods); g_array_unref(thetas); g_array_unref(phis); return TRUE; } v_sim-3.8.0/src/visu_dataspin.h000066400000000000000000000111361370110300500164400ustar00rootroot00000000000000/* EXTRAITS DE LA LICENCE Copyright CEA, contributeurs : Damien CALISTE, laboratoire L_Sim, (2016) Adresse mèl : CALISTE, damien P caliste AT cea P fr. Ce logiciel est un programme informatique servant à visualiser des structures atomiques dans un rendu pseudo-3D. Ce logiciel est régi par la licence CeCILL soumise au droit français et respectant les principes de diffusion des logiciels libres. Vous pouvez utiliser, modifier et/ou redistribuer ce programme sous les conditions de la licence CeCILL telle que diffusée par le CEA, le CNRS et l'INRIA sur le site "http://www.cecill.info". Le fait que vous puissiez accéder à cet en-tête signifie que vous avez pris connaissance de la licence CeCILL, et que vous en avez accepté les termes (cf. le fichier Documentation/licence.fr.txt fourni avec ce logiciel). */ /* LICENCE SUM UP Copyright CEA, contributors : Damien CALISTE, laboratoire L_Sim, (2016) E-mail address: CALISTE, damien P caliste AT cea P fr. This software is a computer program whose purpose is to visualize atomic configurations in 3D. This software is governed by the CeCILL license under French law and abiding by the rules of distribution of free software. You can use, modify and/ or redistribute the software under the terms of the CeCILL license as circulated by CEA, CNRS and INRIA at the following URL "http://www.cecill.info". The fact that you are presently reading this means that you have had knowledge of the CeCILL license and that you accept its terms. You can find a copy of this licence shipped with this software at Documentation/licence.en.txt. */ #ifndef VISU_DATASPIN_H #define VISU_DATASPIN_H #include #include #include "visu_dataatomic.h" G_BEGIN_DECLS /** * VISU_TYPE_DATA_SPIN: * * return the type of #VisuDataSpin. */ #define VISU_TYPE_DATA_SPIN (visu_data_spin_get_type ()) /** * VISU_DATA_SPIN: * @obj: a #GObject to cast. * * Cast the given @obj into #VisuDataSpin type. */ #define VISU_DATA_SPIN(obj) (G_TYPE_CHECK_INSTANCE_CAST(obj, VISU_TYPE_DATA_SPIN, VisuDataSpin)) /** * VISU_DATA_SPIN_CLASS: * @klass: a #GObjectClass to cast. * * Cast the given @klass into #VisuDataSpinClass. */ #define VISU_DATA_SPIN_CLASS(klass) (G_TYPE_CHECK_CLASS_CAST(klass, VISU_TYPE_DATA_SPIN, VisuDataSpinClass)) /** * VISU_IS_DATA_SPIN: * @obj: a #GObject to test. * * Test if the given @ogj is of the type of #VisuDataSpin object. */ #define VISU_IS_DATA_SPIN(obj) (G_TYPE_CHECK_INSTANCE_TYPE(obj, VISU_TYPE_DATA_SPIN)) /** * VISU_IS_DATA_SPIN_CLASS: * @klass: a #GObjectClass to test. * * Test if the given @klass is of the type of #VisuDataSpinClass class. */ #define VISU_IS_DATA_SPIN_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE(klass, VISU_TYPE_DATA_SPIN)) /** * VISU_DATA_SPIN_GET_CLASS: * @obj: a #GObject to get the class of. * * It returns the class of the given @obj. */ #define VISU_DATA_SPIN_GET_CLASS(obj) (G_TYPE_INSTANCE_GET_CLASS(obj, VISU_TYPE_DATA_SPIN, VisuDataSpinClass)) typedef struct _VisuDataSpinPrivate VisuDataSpinPrivate; typedef struct _VisuDataSpin VisuDataSpin; /** * VisuDataSpin: * * Structure used to define #VisuDataSpin objects. * * Since: 3.8 */ struct _VisuDataSpin { VisuDataAtomic parent; VisuDataSpinPrivate *priv; }; /** * VisuDataSpinClass: * @parent: the parent class. * * A short way to identify #_VisuDataSpinClass structure. */ typedef struct _VisuDataSpinClass VisuDataSpinClass; struct _VisuDataSpinClass { VisuDataAtomicClass parent; }; /** * visu_data_spin_get_type: * * This method returns the type of #VisuDataSpin, use VISU_TYPE_DATA_SPIN instead. * * Returns: the type of #VisuDataSpin. */ GType visu_data_spin_get_type(void); VisuDataSpin* visu_data_spin_new(const gchar *atomic, const gchar *spin, VisuDataLoader *atomicFormat, VisuDataLoader *spinFormat); const gchar* visu_data_spin_getFile(VisuDataSpin *data, VisuDataLoader **format); void visu_data_spin_class_addLoader(VisuDataLoader *loader); GList* visu_data_spin_class_getLoaders(void); const gchar* visu_data_spin_class_getFileDescription(void); void visu_data_spin_setAt(VisuDataSpin *dataObj, const VisuNode *node, const gfloat vals[3]); void visu_data_spin_setAtSpherical(VisuDataSpin *dataObj, const VisuNode *node, const gfloat vals[3]); gfloat visu_data_spin_getMaxModulus(const VisuDataSpin *dataObj, guint iElement); const VisuNodeValuesVector* visu_data_spin_get(const VisuDataSpin *dataObj); void visu_data_spin_class_finalize(void); G_END_DECLS #endif v_sim-3.8.0/src/visu_dump.c000066400000000000000000000133011370110300500155710ustar00rootroot00000000000000/* EXTRAITS DE LA LICENCE Copyright CEA, contributeurs : Luc BILLARD et Damien CALISTE, laboratoire L_Sim, (2001-2005) Adresse mèl : BILLARD, non joignable par mèl ; CALISTE, damien P caliste AT cea P fr. Ce logiciel est un programme informatique servant à visualiser des structures atomiques dans un rendu pseudo-3D. Ce logiciel est régi par la licence CeCILL soumise au droit français et respectant les principes de diffusion des logiciels libres. Vous pouvez utiliser, modifier et/ou redistribuer ce programme sous les conditions de la licence CeCILL telle que diffusée par le CEA, le CNRS et l'INRIA sur le site "http://www.cecill.info". Le fait que vous puissiez accéder à cet en-tête signifie que vous avez pris connaissance de la licence CeCILL, et que vous en avez accepté les termes (cf. le fichier Documentation/licence.fr.txt fourni avec ce logiciel). */ /* LICENCE SUM UP Copyright CEA, contributors : Luc BILLARD et Damien CALISTE, laboratoire L_Sim, (2001-2005) E-mail address: BILLARD, not reachable any more ; CALISTE, damien P caliste AT cea P fr. This software is a computer program whose purpose is to visualize atomic configurations in 3D. This software is governed by the CeCILL license under French law and abiding by the rules of distribution of free software. You can use, modify and/ or redistribute the software under the terms of the CeCILL license as circulated by CEA, CNRS and INRIA at the following URL "http://www.cecill.info". The fact that you are presently reading this means that you have had knowledge of the CeCILL license and that you accept its terms. You can find a copy of this licence shipped with this software at Documentation/licence.en.txt. */ #include "visu_dump.h" #include "visu_tools.h" #include "dumpModules/externalDumpModules.h" #include "dumpModules/dumpToAscii.h" #include "dumpModules/dumpToXyz.h" #include "dumpModules/dumpToYaml.h" #include "dumpModules/dumpToABINIT.h" /** * SECTION:visu_dump * @short_description: Some resources to add the ability to export the * rendered data to an other format (usually image format). * * V_Sim can export loaded data to othe formats. This module * descibes the methods and structure to create a dumping * extension. Basically, a dumping extension is just a #ToolFileFormat and * a method that is called when exporting is required. * * The #writeDumpFunc should suspend its process to allow the * calling program to refresh itself if the dump process is * slow. Ideally, the argument @waitFunction should be called exactly * 100 times. */ static GQuark quark; static GList *allDumpModuleList = (GList*)0; static int nbDumpModules = 0; static gboolean internalInit = FALSE; static VisuDumpClass *my_class = (VisuDumpClass*)0; /** * VisuDump: * @bitmap: (in): TRUE if the format requires to export the view * into a bitmap ; * @glRequired: (in): TRUE if the method requires to run OpenGL. * @fileType: a #ToolFileFormat ; * @hasAlpha: TRUE if the format support alpha channel ; * @writeFunc: (scope call): a pointer to a write func. * * This structure is used to store a dumping extension. Such an * extension is characterized by its #ToolFileFormat and a method that can * write a file from the current rendered data. */ static void initDumpList(); G_DEFINE_TYPE(VisuDump, visu_dump, TOOL_TYPE_FILE_FORMAT) static void visu_dump_class_init(VisuDumpClass *klass) { DBG_fprintf(stderr, "Visu Dump: creating the class of the object.\n"); my_class = klass; quark = g_quark_from_static_string("visu_dump"); } static void visu_dump_init(VisuDump *obj) { DBG_fprintf(stderr, "Visu Dump: initializing a new object (%p).\n", (gpointer)obj); nbDumpModules += 1; allDumpModuleList = g_list_append(allDumpModuleList, obj); } /** * visu_dump_pool_getAllModules: * * All dumping extensions are stored in an opaque way in V_Sim. But * they can be listed by a call to this method. * * Returns: (transfer none) (element-type VisuDump*): a list of all * the known dumping extensions. This list is own by V_Sim and should * be considered read-only. */ GList* visu_dump_pool_getAllModules() { if (!internalInit) initDumpList(); DBG_fprintf(stderr, "Visu Dump: give list of dumps (%p).\n", (gpointer)allDumpModuleList); return allDumpModuleList; } /** * visu_dump_getNModules: * * A convenient way to know how many dumping extensions are registered. * * Returns: the number of known dumping extensions. */ gint visu_dump_getNModules() { if (!internalInit) initDumpList(); return nbDumpModules; } /** * visu_dump_pool_finalize: * * Free the list of #VisuDump modules. * * Since: 3.8 **/ void visu_dump_pool_finalize(void) { g_list_free_full(allDumpModuleList, (GDestroyNotify)g_object_unref); allDumpModuleList = (GList*)0; } static void initDumpList() { int i; const VisuDump *dump; DBG_fprintf(stderr, "Visu Dump: Init export list.\n"); visu_dump_ascii_getStatic(); visu_dump_xyz_getStatic(); visu_dump_yaml_getStatic(); visu_dump_abinit_getStatic(); for (i = 0; listInitDumpModuleFunc[i]; i++) { dump = listInitDumpModuleFunc[i](); if (dump) DBG_fprintf(stderr, " | %s\n", tool_file_format_getLabel(TOOL_FILE_FORMAT(dump))); } internalInit = TRUE; DBG_fprintf(stderr, "Visu Dump: %d valid dump module(s) found.\n", nbDumpModules); } /** * visu_dump_getQuark: (skip) * * Internal routine to get the #GQuark to handle error related to dump * actions. */ GQuark visu_dump_getQuark() { return quark; } void visu_dump_abort(GObject *obj _U_, gpointer data) { /* TODO : mettre un stop dans le fichier en cours. */ DBG_fprintf(stderr, "Visu dump : abortion requested.\n"); *((int*)data) = 1; } v_sim-3.8.0/src/visu_dump.h000066400000000000000000000112061370110300500156000ustar00rootroot00000000000000/* EXTRAITS DE LA LICENCE Copyright CEA, contributeurs : Luc BILLARD et Damien CALISTE, laboratoire L_Sim, (2001-2005) Adresse mèl : BILLARD, non joignable par mèl ; CALISTE, damien P caliste AT cea P fr. Ce logiciel est un programme informatique servant à visualiser des structures atomiques dans un rendu pseudo-3D. Ce logiciel est régi par la licence CeCILL soumise au droit français et respectant les principes de diffusion des logiciels libres. Vous pouvez utiliser, modifier et/ou redistribuer ce programme sous les conditions de la licence CeCILL telle que diffusée par le CEA, le CNRS et l'INRIA sur le site "http://www.cecill.info". Le fait que vous puissiez accéder à cet en-tête signifie que vous avez pris connaissance de la licence CeCILL, et que vous en avez accepté les termes (cf. le fichier Documentation/licence.fr.txt fourni avec ce logiciel). */ /* LICENCE SUM UP Copyright CEA, contributors : Luc BILLARD et Damien CALISTE, laboratoire L_Sim, (2001-2005) E-mail address: BILLARD, not reachable any more ; CALISTE, damien P caliste AT cea P fr. This software is a computer program whose purpose is to visualize atomic configurations in 3D. This software is governed by the CeCILL license under French law and abiding by the rules of distribution of free software. You can use, modify and/ or redistribute the software under the terms of the CeCILL license as circulated by CEA, CNRS and INRIA at the following URL "http://www.cecill.info". The fact that you are presently reading this means that you have had knowledge of the CeCILL license and that you accept its terms. You can find a copy of this licence shipped with this software at Documentation/licence.en.txt. */ #ifndef VISU_DUMP_H #define VISU_DUMP_H #include #include #include "visu_tools.h" #include "coreTools/toolFileFormat.h" #include "visu_data.h" G_BEGIN_DECLS /** * VISU_TYPE_DUMP: * * Return the associated #GType to the VisuDump objects. */ #define VISU_TYPE_DUMP (visu_dump_get_type ()) /** * VISU_DUMP: * @obj: the widget to cast. * * Cast the given object to a #VisuDump object. */ #define VISU_DUMP(obj) (G_TYPE_CHECK_INSTANCE_CAST ((obj), VISU_TYPE_DUMP, VisuDump)) /** * VISU_DUMP_CLASS: * @klass: the class to cast. * * Cast the given class to a #VisuDumpClass object. */ #define VISU_DUMP_CLASS(klass) (G_TYPE_CHECK_CLASS_CAST ((klass), VISU_TYPE_DUMP, VisuDumpClass)) /** * VISU_IS_DUMP: * @obj: the object to test. * * Return if the given object is a valid #VisuDump object. */ #define VISU_IS_DUMP(obj) (G_TYPE_CHECK_INSTANCE_TYPE ((obj), VISU_TYPE_DUMP)) /** * VISU_IS_DUMP_CLASS: * @klass: the class to test. * * Return if the given class is a valid #VisuDumpClass class. */ #define VISU_IS_DUMP_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE ((klass), VISU_TYPE_DUMP)) /** * VISU_DUMP_GET_CLASS: * @obj: the widget to get the class of. * * Get the class of the given object. */ #define VISU_DUMP_GET_CLASS(obj) (G_TYPE_INSTANCE_GET_CLASS(obj, VISU_TYPE_DUMP, VisuDumpClass)) typedef struct _VisuDump VisuDump; struct _VisuDump { ToolFileFormat parent; }; /** * VisuDumpClass: * @parent: the parent class. * * An opaque structure. */ typedef struct _VisuDumpClass VisuDumpClass; struct _VisuDumpClass { ToolFileFormatClass parent; }; /** * visu_dump_get_type * * #GType are unique numbers to identify objects. * * Returns: the #GType associated with #VisuDump objects. */ GType visu_dump_get_type(void); /** * VISU_DUMP_ERROR: (skip) * * Internal function for error handling. */ #define VISU_DUMP_ERROR visu_dump_getQuark() GQuark visu_dump_getQuark(); /** * VisuDumpErrorFlag: * @DUMP_ERROR_OPENGL: Error with OpenGL dumping. * @DUMP_ERROR_FILE: Error when opening. * @DUMP_ERROR_ENCODE: Wrongness when computing the encoding format. * * These are flags used when dumping to a file. */ typedef enum { DUMP_ERROR_OPENGL, DUMP_ERROR_FILE, DUMP_ERROR_ENCODE } VisuDumpErrorFlag; /** * VisuDumpInitFunc: (skip) * * This protoype defines initializing function for dumping extension. * Create such a function and add its name in the list #listInitDumpModuleFunc * defined in dumpModules/externalDumpModules.h thus the new dumping extension * will be initialized on startup. * * Returns: a newly allocated #VisuDump. */ typedef const VisuDump* (*VisuDumpInitFunc) (); GList* visu_dump_pool_getAllModules(); gint visu_dump_getNModules(); void visu_dump_pool_finalize(void); /** * visu_dump_abort: * @obj: an object ; * @data: some data. * * Does nothing for the moment. */ void visu_dump_abort(GObject *obj, gpointer data); G_END_DECLS #endif v_sim-3.8.0/src/visu_elements.c000066400000000000000000000433111370110300500164440ustar00rootroot00000000000000/* EXTRAITS DE LA LICENCE Copyright CEA, contributeurs : Luc BILLARD et Damien CALISTE, laboratoire L_Sim, (2001-2005) Adresse mèl : BILLARD, non joignable par mèl ; CALISTE, damien P caliste AT cea P fr. Ce logiciel est un programme informatique servant à visualiser des structures atomiques dans un rendu pseudo-3D. Ce logiciel est régi par la licence CeCILL soumise au droit français et respectant les principes de diffusion des logiciels libres. Vous pouvez utiliser, modifier et/ou redistribuer ce programme sous les conditions de la licence CeCILL telle que diffusée par le CEA, le CNRS et l'INRIA sur le site "http://www.cecill.info". Le fait que vous puissiez accéder à cet en-tête signifie que vous avez pris connaissance de la licence CeCILL, et que vous en avez accepté les termes (cf. le fichier Documentation/licence.fr.txt fourni avec ce logiciel). */ /* LICENCE SUM UP Copyright CEA, contributors : Luc BILLARD et Damien CALISTE, laboratoire L_Sim, (2001-2005) E-mail address: BILLARD, not reachable any more ; CALISTE, damien P caliste AT cea P fr. This software is a computer program whose purpose is to visualize atomic configurations in 3D. This software is governed by the CeCILL license under French law and abiding by the rules of distribution of free software. You can use, modify and/ or redistribute the software under the terms of the CeCILL license as circulated by CEA, CNRS and INRIA at the following URL "http://www.cecill.info". The fact that you are presently reading this means that you have had knowledge of the CeCILL license and that you accept its terms. You can find a copy of this licence shipped with this software at Documentation/licence.en.txt. */ #include "visu_elements.h" #include #include #include "visu_configFile.h" #include "coreTools/toolColor.h" /** * SECTION:visu_elements * @short_description: defines methods to create and acccess to * #VisuElement. * * V_Sim is used to rendered at given position several object of * the same kind. The #VisuElement object is used to control that * kind. Typically, it corresponds to chemical element. It can * represent the silicon, the iron... * * #VisuElement are defined by their name and have some * characteristic like if they are rendered or not, or masked or not. */ /** * VisuElement: * * Structure to stores #VisuElement objects. */ /** * VisuElementClass: * @parent: the parent. * * An opaque structure representing the class of #VisuElement objects. */ #define FLAG_ELEMENT_PROPERTIES "element_properties" #define DESC_ELEMENT_PROPERTIES "Define some properties ; rendered (0 or 1) masked" \ "(0 or 1)." static gboolean _elementProperties[3]; static void exportResources(GString *data, VisuData* dataObj); /** * _VisuElement: * @parent: the parent. * @name: Name of the key used in the hashtable to find * this element. The int variable is the number * of this type. * @typeNumber: An integer unique for each VisuElement, it is * used as a name for the opengl material associated * with it. * @rgb: main color of the element in [r, g, b, a] format. * @material: lighting effects for material in [amb, dif, shi, spe, * emi] format. * @rendered: A flag to store if all nodes of this element are rendered or not. * Its default value is TRUE. * @sensitiveToPlanes: a flag to say if nodes of this element are sensitive * to the masking effect of planes (default is TRUE). * @physical: TRUE if the element is a physical one. * @dispose_has_run: internal. * * Structure to store the description of an element. */ enum { PROP_0, PROP_RENDERED, PROP_MASKABLE, PROP_COLORIZABLE, N_PROPS }; static GParamSpec *_properties[N_PROPS]; enum { ELEMENT_NEW_SIGNAL, LAST_SIGNAL }; /* This hashtable contains a list of all different elements loaded in visu. */ static GHashTable *allElements_table = NULL; static GList *allElements_list = NULL; /* These functions write all the element list to export there associated resources. */ static void visu_element_finalize(GObject* obj); static void visu_element_get_property(GObject* obj, guint property_id, GValue *value, GParamSpec *pspec); static void visu_element_set_property(GObject* obj, guint property_id, const GValue *value, GParamSpec *pspec); static void onEntryProperties(VisuConfigFile *obj, VisuConfigFileEntry *entry, gpointer data); static guint visu_element_signals[LAST_SIGNAL] = { 0 }; G_DEFINE_TYPE(VisuElement, visu_element, VISU_TYPE_OBJECT) static void visu_element_class_init(VisuElementClass *klass) { VisuConfigFileEntry *resourceEntry, *oldEntry; DBG_fprintf(stderr, "Visu Element: creating the class of the object.\n"); DBG_fprintf(stderr, " - adding new signals ;\n"); /** * VisuElement::ElementNew: * @element: the object emitting the signal. * * A new element is available. * * Since: 3.6 */ visu_element_signals[ELEMENT_NEW_SIGNAL] = g_signal_new("ElementNew", G_TYPE_FROM_CLASS (klass), G_SIGNAL_RUN_LAST | G_SIGNAL_NO_RECURSE, 0, NULL, NULL, g_cclosure_marshal_VOID__VOID, G_TYPE_NONE, 0); /* Connect the overloading methods. */ G_OBJECT_CLASS(klass)->finalize = visu_element_finalize; G_OBJECT_CLASS(klass)->set_property = visu_element_set_property; G_OBJECT_CLASS(klass)->get_property = visu_element_get_property; /** * VisuElement::rendered: * * If element is rendered or not. * * Since: 3.8 */ _properties[PROP_RENDERED] = g_param_spec_boolean("rendered", "Rendered", "if element is rendered", TRUE, G_PARAM_READWRITE); /** * VisuElement::maskable: * * If element is maskable by planes or not. * * Since: 3.8 */ _properties[PROP_MASKABLE] = g_param_spec_boolean("maskable", "Maskable", "if element is maskable", TRUE, G_PARAM_READWRITE); /** * VisuElement::colorizable: * * If element is colorizable or not. * * Since: 3.8 */ _properties[PROP_COLORIZABLE] = g_param_spec_boolean("colorizable", "Colorizable", "if element is colorizable", TRUE, G_PARAM_READWRITE); g_object_class_install_properties(G_OBJECT_CLASS(klass), N_PROPS, _properties); oldEntry = visu_config_file_addEntry(VISU_CONFIG_FILE_RESOURCE, "element_is_rendered", "Obsolete entry included in element_properties", 1, NULL); visu_config_file_entry_setVersion(oldEntry, 3.1f); resourceEntry = visu_config_file_addBooleanArrayEntry(VISU_CONFIG_FILE_RESOURCE, FLAG_ELEMENT_PROPERTIES, DESC_ELEMENT_PROPERTIES, 2, _elementProperties, TRUE); visu_config_file_entry_setVersion(resourceEntry, 3.4f); visu_config_file_entry_setReplace(resourceEntry, oldEntry); g_signal_connect(VISU_CONFIG_FILE_RESOURCE, "parsed::" FLAG_ELEMENT_PROPERTIES, G_CALLBACK(onEntryProperties), (gpointer)0); visu_config_file_addExportFunction(VISU_CONFIG_FILE_RESOURCE, exportResources); /* Set internal parameters. */ allElements_table = g_hash_table_new_full(g_str_hash, g_str_equal, NULL, (GDestroyNotify)g_object_unref); } static void visu_element_init(VisuElement *ele) { DBG_fprintf(stderr, "Visu Element: initializing a new object (%p).\n", (gpointer)ele); ele->physical = TRUE; ele->_rendered = TRUE; ele->_maskable = TRUE; ele->_colorizable = TRUE; } /* This method is called once only. */ static void visu_element_finalize(GObject* obj) { VisuElement *ele; g_return_if_fail(obj); DBG_fprintf(stderr, "Visu Element: finalize object %p.\n", (gpointer)obj); ele = VISU_ELEMENT(obj); g_free(ele->name); g_hash_table_steal(allElements_table, ele); allElements_list = g_list_remove(allElements_list, ele); /* Chain up to the parent class */ DBG_fprintf(stderr, "Visu Element: chain to parent.\n"); G_OBJECT_CLASS(visu_element_parent_class)->finalize(obj); DBG_fprintf(stderr, "Visu Element: freeing ... OK.\n"); } static void visu_element_get_property(GObject* obj, guint property_id, GValue *value, GParamSpec *pspec) { VisuElement *self = VISU_ELEMENT(obj); DBG_fprintf(stderr, "Visu Element: get property '%s' -> ", g_param_spec_get_name(pspec)); switch (property_id) { case PROP_RENDERED: g_value_set_boolean(value, self->_rendered); DBG_fprintf(stderr, "%d.\n", self->_rendered); break; case PROP_MASKABLE: g_value_set_boolean(value, self->_maskable); DBG_fprintf(stderr, "%d.\n", self->_maskable); break; case PROP_COLORIZABLE: g_value_set_boolean(value, self->_colorizable); DBG_fprintf(stderr, "%d.\n", self->_colorizable); break; default: /* We don't have any other property... */ G_OBJECT_WARN_INVALID_PROPERTY_ID(obj, property_id, pspec); break; } } static void visu_element_set_property(GObject* obj, guint property_id, const GValue *value, GParamSpec *pspec) { VisuElement *self = VISU_ELEMENT(obj); DBG_fprintf(stderr, "Visu Element: set property '%s' -> ", g_param_spec_get_name(pspec)); switch (property_id) { case PROP_RENDERED: DBG_fprintf(stderr, "%d.\n", g_value_get_boolean(value)); visu_element_setRendered(self, g_value_get_boolean(value)); break; case PROP_MASKABLE: DBG_fprintf(stderr, "%d.\n", g_value_get_boolean(value)); visu_element_setMaskable(self, g_value_get_boolean(value)); break; case PROP_COLORIZABLE: DBG_fprintf(stderr, "%d.\n", g_value_get_boolean(value)); visu_element_setColorizable(self, g_value_get_boolean(value)); break; default: /* We don't have any other property... */ G_OBJECT_WARN_INVALID_PROPERTY_ID(obj, property_id, pspec); break; } } /** * visu_element_new: * @key: the name of the new element to create. * * Allocate a new visuElement with the specified name. Remember * that names must be unique since they identify the element. * * Returns: (transfer none): the newly created VisuElement or 0 if something goes * wrong in the process (if the name already exist for example). */ VisuElement *visu_element_new(const char *key) { VisuElement *ele; ele = visu_element_lookup(key); if (ele) { g_warning("Element '%s' already exists.", key); return ele; } ele = VISU_ELEMENT(g_object_new(VISU_TYPE_ELEMENT, NULL)); ele->name = g_strdup((key[0] == '%')?key + 1:key); ele->physical = (key[0] != '%') && strcmp(key, "g") && strcmp(key, "G"); g_hash_table_insert(allElements_table, (gpointer)ele->name, (gpointer)ele); allElements_list = g_list_append(allElements_list, (gpointer)ele); DBG_fprintf(stderr, "Visu Elements: create a new VisuElement '%s' -> %p.\n", key, (gpointer)ele); g_signal_emit(G_OBJECT(ele), visu_element_signals[ELEMENT_NEW_SIGNAL], 0, NULL); DBG_fprintf(stderr, "Visu Elements: new element signal OK.\n"); return ele; } /** * visu_element_getAllElements: * * This method returns a list of all the registered #VisuElement. * The returned list is read-only. * * Returns: (element-type VisuElement) (transfer none): the list of * all known #VisuElement. */ const GList *visu_element_getAllElements(void) { return allElements_list; } /** * visu_element_pool_finalize: (skip) * * Destroy the internal list of existing #VisuElement. * * Since: 3.8 **/ void visu_element_pool_finalize(void) { GList *lst; lst = g_list_copy(allElements_list); g_list_free_full(lst, (GDestroyNotify)g_object_unref); } /** * visu_element_retrieveFromName: * @name: a string that identify the #VisuElement (in UTF8) ; * @nw: (out caller-allocates): a location to store a boolean. * * Try to find a #VisuElement already associated to that @name or * create a new one if none has been found. If @nw is not NULL it is * set to FALSE if @name was found. * * Returns: (transfer none): a #VisuElement associated to this @name. */ VisuElement *visu_element_retrieveFromName(const gchar *name, gboolean *nw) { VisuElement *ele; if (!allElements_table) g_type_class_ref(VISU_TYPE_ELEMENT); DBG_fprintf(stderr, "Visu Element: retrieve '%s' (%d).\n", name, g_hash_table_size(allElements_table)); if (nw) *nw = FALSE; ele = g_hash_table_lookup(allElements_table, (name[0] == '%')?name + 1:name); if (ele) return ele; if (nw) *nw = TRUE; return visu_element_new(name); } /** * visu_element_lookup: * @name: a string. * * Lookup for element @name in the base. Do not create it if not * found. To do this, use visu_element_retrieveFromName(). * * Since: 3.6 * * Returns: (transfer none): the found #VisuElement or NULL. */ VisuElement *visu_element_lookup(const gchar *name) { if (!allElements_table) g_type_class_ref(VISU_TYPE_ELEMENT); DBG_fprintf(stderr, "Visu Element: lookup '%s' (%d).\n", name, g_hash_table_size(allElements_table)); return g_hash_table_lookup(allElements_table, (name[0] == '%')?name + 1:name); } /** * visu_element_getName: * @ele: a #VisuElement object. * * This routines returns the name of the given @ele. * * Since: 3.7 * * Returns: a string owned by V_Sim. */ const gchar* visu_element_getName(const VisuElement *ele) { g_return_val_if_fail(VISU_IS_ELEMENT(ele), (const gchar*)0); return ele->name; } /** * visu_element_getPhysical: * @ele: a #VisuElement object. * * This routine gets if @ele is physical or not. A not physical * element can be used for instance to represent specific points... * * Since: 3.7 * * Returns: TRUE if @ele is indeed physical. */ gboolean visu_element_getPhysical(VisuElement *ele) { g_return_val_if_fail(VISU_IS_ELEMENT(ele), FALSE); return ele->physical; } /** * visu_element_getRendered: * @self: a #VisuElement object. * * Retrieve wether all #VisuNode of @self are currently hidden or not. * * Since: 3.8 * * Returns: TRUE if @self is hidden or not. **/ gboolean visu_element_getRendered(const VisuElement *self) { g_return_val_if_fail(VISU_IS_ELEMENT(self), FALSE); return self->_rendered; } /** * visu_element_setRendered: * @self: a #VisuElement object. * @val: a boolean. * * Changes if all #VisuNode of type @self are hidden or not. * * Since: 3.8 * * Returns: TRUE if value is actually changed. **/ gboolean visu_element_setRendered(VisuElement *self, gboolean val) { g_return_val_if_fail(VISU_IS_ELEMENT(self), FALSE); if (self->_rendered == val) return FALSE; self->_rendered = val; g_object_notify_by_pspec(G_OBJECT(self), _properties[PROP_RENDERED]); return TRUE; } /** * visu_element_getMaskable: * @self: a #VisuElement object. * * Retrieve whether #VisuNode of type @self can be hidden by planes or any * #VisuNodeMasker object. * * Since: 3.8 * * Returns: TRUE if @self is maskable. **/ gboolean visu_element_getMaskable(const VisuElement *self) { g_return_val_if_fail(VISU_IS_ELEMENT(self), FALSE); return self->_maskable; } /** * visu_element_setMaskable: * @self: a #VisuElement object. * @val: a boolean value. * * Changes if all #VisuNode of type @self can be affected by a * #VisuNodeMasker object. * * Since: 3.8 * * Returns: TRUE if value is actually changed. **/ gboolean visu_element_setMaskable(VisuElement *self, gboolean val) { g_return_val_if_fail(VISU_IS_ELEMENT(self), FALSE); if (self->_maskable == val) return FALSE; self->_maskable = val; g_object_notify_by_pspec(G_OBJECT(self), _properties[PROP_MASKABLE]); return TRUE; } /** * visu_element_getColorizable: * @self: a #VisuElement object. * * Retrieve whether #VisuNode of type @self can be colorized by any * #VisuDataColorizer object. * * Since: 3.8 * * Returns: TRUE if @self is colorizable. **/ gboolean visu_element_getColorizable(const VisuElement *self) { g_return_val_if_fail(VISU_IS_ELEMENT(self), FALSE); return self->_colorizable; } /** * visu_element_setColorizable: * @self: a #VisuElement object. * @val: a boolean value. * * Changes if all #VisuNode of type @self can be affected by a * #VisuDataColorizer object. * * Since: 3.8 * * Returns: TRUE if value is actually changed. **/ gboolean visu_element_setColorizable(VisuElement *self, gboolean val) { g_return_val_if_fail(VISU_IS_ELEMENT(self), FALSE); if (self->_colorizable == val) return FALSE; self->_colorizable = val; g_object_notify_by_pspec(G_OBJECT(self), _properties[PROP_COLORIZABLE]); return TRUE; } static void onEntryProperties(VisuConfigFile *obj _U_, VisuConfigFileEntry *entry, gpointer data _U_) { VisuElement *ele; ele = visu_element_retrieveFromName(visu_config_file_entry_getLabel(entry), (int*)0); if (!ele) return; visu_element_setRendered(ele, _elementProperties[0]); visu_element_setMaskable(ele, _elementProperties[1]); /* visu_element_setColorizable(ele, _elementProperties[2]); */ } static void exportResources(GString *data, VisuData *dataObj) { GList *pos; VisuElement *ele; visu_config_file_exportComment(data, DESC_ELEMENT_PROPERTIES); for (pos = allElements_list; pos; pos = g_list_next(pos)) { ele = VISU_ELEMENT(pos->data); if (!dataObj || visu_node_array_containsElement(VISU_NODE_ARRAY(dataObj), ele)) visu_config_file_exportEntry(data, FLAG_ELEMENT_PROPERTIES, ele->name, "%d %d %d", ele->_rendered, ele->_maskable, ele->_colorizable); } visu_config_file_exportComment(data, ""); } v_sim-3.8.0/src/visu_elements.h000066400000000000000000000112411370110300500164460ustar00rootroot00000000000000/* EXTRAITS DE LA LICENCE Copyright CEA, contributeurs : Luc BILLARD et Damien CALISTE, laboratoire L_Sim, (2001-2005) Adresse mèl : BILLARD, non joignable par mèl ; CALISTE, damien P caliste AT cea P fr. Ce logiciel est un programme informatique servant à visualiser des structures atomiques dans un rendu pseudo-3D. Ce logiciel est régi par la licence CeCILL soumise au droit français et respectant les principes de diffusion des logiciels libres. Vous pouvez utiliser, modifier et/ou redistribuer ce programme sous les conditions de la licence CeCILL telle que diffusée par le CEA, le CNRS et l'INRIA sur le site "http://www.cecill.info". Le fait que vous puissiez accéder à cet en-tête signifie que vous avez pris connaissance de la licence CeCILL, et que vous en avez accepté les termes (cf. le fichier Documentation/licence.fr.txt fourni avec ce logiciel). */ /* LICENCE SUM UP Copyright CEA, contributors : Luc BILLARD et Damien CALISTE, laboratoire L_Sim, (2001-2005) E-mail address: BILLARD, not reachable any more ; CALISTE, damien P caliste AT cea P fr. This software is a computer program whose purpose is to visualize atomic configurations in 3D. This software is governed by the CeCILL license under French law and abiding by the rules of distribution of free software. You can use, modify and/ or redistribute the software under the terms of the CeCILL license as circulated by CEA, CNRS and INRIA at the following URL "http://www.cecill.info". The fact that you are presently reading this means that you have had knowledge of the CeCILL license and that you accept its terms. You can find a copy of this licence shipped with this software at Documentation/licence.en.txt. */ #ifndef VISU_ELEMENTS_H #define VISU_ELEMENTS_H #include #include #include "visu_tools.h" G_BEGIN_DECLS /** * VISU_TYPE_ELEMENT: * * return the type of #VisuElement. */ #define VISU_TYPE_ELEMENT (visu_element_get_type ()) /** * VISU_ELEMENT: * @obj: a #GObject to cast. * * Cast the given @obj into #VisuElement type. */ #define VISU_ELEMENT(obj) (G_TYPE_CHECK_INSTANCE_CAST(obj, VISU_TYPE_ELEMENT, VisuElement)) /** * VISU_ELEMENT_CLASS: * @klass: a #GObjectClass to cast. * * Cast the given @klass into #VisuElementClass. */ #define VISU_ELEMENT_CLASS(klass) (G_TYPE_CHECK_CLASS_CAST(klass, VISU_TYPE_ELEMENT, VisuElementClass)) /** * VISU_IS_ELEMENT: * @obj: a #GObject to test. * * Test if the given @ogj is of the type of #VisuElement object. */ #define VISU_IS_ELEMENT(obj) (G_TYPE_CHECK_INSTANCE_TYPE(obj, VISU_TYPE_ELEMENT)) /** * VISU_IS_ELEMENT_CLASS: * @klass: a #GObjectClass to test. * * Test if the given @klass is of the type of #VisuElementClass class. */ #define VISU_IS_ELEMENT_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE(klass, VISU_TYPE_ELEMENT)) /** * VISU_ELEMENT_GET_CLASS: * @obj: a #GObject to get the class of. * * It returns the class of the given @obj. */ #define VISU_ELEMENT_GET_CLASS(obj) (G_TYPE_INSTANCE_GET_CLASS(obj, VISU_TYPE_ELEMENT, VisuElementClass)) typedef struct _VisuElementClass VisuElementClass; typedef struct _VisuElement VisuElement; /** * visu_element_get_type: * * This method returns the type of #VisuElement, use VISU_TYPE_ELEMENT instead. * * Returns: the type of #VisuElement. */ GType visu_element_get_type(void); struct _VisuElementClass { VisuObjectClass parent; }; struct _VisuElement { VisuObject parent; /* Name of the key used in the hashtable to find this element. The int variable is the number of this type. */ char* name; /* An integer unique for each VisuElement, it is used as a name for the opengl material associated with it. */ int typeNumber; /* If the element should appear in the display list of elements or if this element is an internal substitute. */ gboolean physical; gboolean _rendered, _maskable, _colorizable; }; const GList *visu_element_getAllElements(void); VisuElement *visu_element_retrieveFromName(const gchar *name, gboolean *nw); VisuElement *visu_element_lookup(const gchar *name); VisuElement *visu_element_new(const char *key); gboolean visu_element_getRendered(const VisuElement *self); gboolean visu_element_setRendered(VisuElement *self, gboolean val); gboolean visu_element_getMaskable(const VisuElement *self); gboolean visu_element_setMaskable(VisuElement *self, gboolean val); gboolean visu_element_getColorizable(const VisuElement *self); gboolean visu_element_setColorizable(VisuElement *self, gboolean val); const gchar* visu_element_getName(const VisuElement *ele); gboolean visu_element_getPhysical(VisuElement *ele); void visu_element_pool_finalize(void); G_END_DECLS #endif v_sim-3.8.0/src/visu_extension.c000066400000000000000000000732271370110300500166550ustar00rootroot00000000000000/* EXTRAITS DE LA LICENCE Copyright CEA, contributeurs : Luc BILLARD et Damien CALISTE, laboratoire L_Sim, (2001-2005) Adresse mèl : BILLARD, non joignable par mèl ; CALISTE, damien P caliste AT cea P fr. Ce logiciel est un programme informatique servant à visualiser des structures atomiques dans un rendu pseudo-3D. Ce logiciel est régi par la licence CeCILL soumise au droit français et respectant les principes de diffusion des logiciels libres. Vous pouvez utiliser, modifier et/ou redistribuer ce programme sous les conditions de la licence CeCILL telle que diffusée par le CEA, le CNRS et l'INRIA sur le site "http://www.cecill.info". Le fait que vous puissiez accéder à cet en-tête signifie que vous avez pris connaissance de la licence CeCILL, et que vous en avez accepté les termes (cf. le fichier Documentation/licence.fr.txt fourni avec ce logiciel). */ /* LICENCE SUM UP Copyright CEA, contributors : Luc BILLARD et Damien CALISTE, laboratoire L_Sim, (2001-2005) E-mail address: BILLARD, not reachable any more ; CALISTE, damien P caliste AT cea P fr. This software is a computer program whose purpose is to visualize atomic configurations in 3D. This software is governed by the CeCILL license under French law and abiding by the rules of distribution of free software. You can use, modify and/ or redistribute the software under the terms of the CeCILL license as circulated by CEA, CNRS and INRIA at the following URL "http://www.cecill.info". The fact that you are presently reading this means that you have had knowledge of the CeCILL license and that you accept its terms. You can find a copy of this licence shipped with this software at Documentation/licence.en.txt. */ #include "visu_extension.h" #include "visu_configFile.h" #include "openGLFunctions/objectList.h" #include #include #include #include "visu_tools.h" /** * SECTION:visu_extension * @short_description: All objects drawn by V_Sim are defined in by a * #VisuGlExt object * * All objects that are drawn by V_Sim are handled by a * #VisuGlExt object. Such an object has an OpenGL list. This * list is only COMPILED. When V_Sim receives the 'OpenGLAskForReDraw' * or the 'OpenGLForceReDraw' signals, each list of all known * #VisuGlExt are excecuted. This excecution can be canceled if * the used flag of the #VisuGlExt object is set to FALSE. The * order in which the lists are called depends on the priority of the * #VisuGlExt object. This priority is set to * #VISU_GL_EXT_PRIORITY_NORMAL as default value, but it can be * tune by a call to visu_gl_ext_setPriority(). This priority is * an integer, the lower it is, the sooner the list is * excecuted. * * The method registerVisuGlExt() is used to declare to * V_Sim that there is a new #VisuGlExt object available. This * allows to create extension when V_Sim is already * running. Nevertheless, an extension must be initialized in the * initialisation process, it is better to add an * #initVisuGlExtFunc method in the listInitExtensionFunc array * declared in extensions/externalVisuGlExts.h. * * Once again, the OpenGL list corresponding to an OpenGL * extension is COMPILE only. Then, OpenGL methods like glIsenabled() * are totally unusefull because it is called when the list is * compiled not when the list is called. If the extension needs to * alter some OpenGL state, such as desable GL_LIGHTING, it needs to * set a flag for the extension. With this flag, V_Sim will save the * OpenGL states and restore it when the list is called. Use * visu_gl_ext_setSaveState() to set this flag. */ #define FLAG_PARAMETER_MODE "extension_render" #define DESC_PARAMETER_MODE "Rules the way OpenGl draws extensions (see opengl_render); name (string) value (string)" #define FLAG_RESOURCE_MODE "glExtension_render" #define DESC_RESOURCE_MODE "Rules the way OpenGl draws extensions (see gl_render); name (string) value (string)" static guint _rMode; static void exportRendering(GString *data, VisuData *dataObj); static void callList(GList *lst, VisuGlRenderingMode *renderingMode, VisuGlRenderingMode globalRenderingMode); enum { PROP_0, NAME_PROP, ACTIVE_PROP, LABEL_PROP, DESCRIPTION_PROP, PRIORITY_PROP, SAVE_STATE_PROP, DIRTY_PROP, NGLOBJ_PROP, RMODE_PROP, N_PROP }; static GParamSpec *properties[N_PROP]; struct _VisuGlExtPrivate { gboolean dispose_has_run; /* Some variable to describe this OpenGL extension. The attribute name is mandatory since it is used to identify the method. */ gchar *name, *nameI18n; gchar *description; /* The id of the possible objects list brings by the extension is refered by this int. */ guint nGlObj; int objectListId; /* Global translation to apply to the list before displaying. */ float trans[3]; /* A priority for the extension. */ guint priority; /* If set, V_Sim save the OpenGL state before the list id is called and restore all states after. */ gboolean saveState; /* Fine tune of rendering mode (VISU_GL_RENDERING_WIREFRAME, smooth...). When FOLLOW, the global value for rendering mode is used. Otherwise the value is stored in preferedRenderingMode. */ VisuGlRenderingMode preferedRenderingMode; /* A boolean to know if this extension is actually used or not. */ gboolean used; /* Set to FALSE to skip draw calls. */ gboolean dirty; /* The context with gl options the extension is drawing to. */ VisuGl *gl; }; static VisuGlExtClass *my_class = NULL; static void visu_gl_ext_dispose (GObject* obj); static void visu_gl_ext_finalize (GObject* obj); static void visu_gl_ext_get_property(GObject* obj, guint property_id, GValue *value, GParamSpec *pspec); static void visu_gl_ext_set_property(GObject* obj, guint property_id, const GValue *value, GParamSpec *pspec); static void onEntryMode(VisuGlExt *ext, VisuConfigFileEntry *entry, VisuConfigFile *obj); G_DEFINE_TYPE_WITH_CODE(VisuGlExt, visu_gl_ext, VISU_TYPE_OBJECT, G_ADD_PRIVATE(VisuGlExt)) static void visu_gl_ext_class_init(VisuGlExtClass *klass) { VisuConfigFileEntry *confEntry, *oldEntry; DBG_fprintf(stderr, "Visu Extension: creating the class of the object.\n"); /* DBG_fprintf(stderr, " - adding new signals ;\n"); */ /* Connect the overloading methods. */ G_OBJECT_CLASS(klass)->dispose = visu_gl_ext_dispose; G_OBJECT_CLASS(klass)->finalize = visu_gl_ext_finalize; G_OBJECT_CLASS(klass)->set_property = visu_gl_ext_set_property; G_OBJECT_CLASS(klass)->get_property = visu_gl_ext_get_property; /** * VisuGlExt::name: * * The name of the extension (used as an id). * * Since: 3.7 */ g_object_class_install_property (G_OBJECT_CLASS(klass), NAME_PROP, g_param_spec_string("name", "Name", "name (id) of extension", "", G_PARAM_CONSTRUCT_ONLY | G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS)); /** * VisuGlExt::active: * * The extension is used or not. * * Since: 3.7 */ properties[ACTIVE_PROP] = g_param_spec_boolean("active", "Active", "extension is used or not", FALSE, G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS); g_object_class_install_property(G_OBJECT_CLASS(klass), ACTIVE_PROP, properties[ACTIVE_PROP]); /** * VisuGlExt::label: * * The label of extension (translated). * * Since: 3.7 */ g_object_class_install_property (G_OBJECT_CLASS(klass), LABEL_PROP, g_param_spec_string("label", "Label", "label (translated) of extension", "", G_PARAM_CONSTRUCT | G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS)); /** * VisuGlExt::description: * * The description of the extension. * * Since: 3.7 */ g_object_class_install_property (G_OBJECT_CLASS(klass), DESCRIPTION_PROP, g_param_spec_string("description", "Description", "description of extension", "", G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS)); /** * VisuGlExt::priority: * * The drawing priority of the extension. * * Since: 3.7 */ g_object_class_install_property (G_OBJECT_CLASS(klass), PRIORITY_PROP, g_param_spec_uint("priority", "Priority", "drawing priority of extension", VISU_GL_EXT_PRIORITY_BACKGROUND, VISU_GL_EXT_PRIORITY_LAST, VISU_GL_EXT_PRIORITY_NORMAL, G_PARAM_CONSTRUCT | G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS)); /** * VisuGlExt::saveState: * * When set, save the OpenGL state, so the extension can modify * OpenGL parameters like light, depth test... * * Since: 3.7 */ g_object_class_install_property (G_OBJECT_CLASS(klass), SAVE_STATE_PROP, g_param_spec_boolean("saveState", "Save state", "save OpenGL state", FALSE, G_PARAM_CONSTRUCT | G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS)); /** * VisuGlExt::nGlObj: * * The number of GL list the extension is dealing with. * * Since: 3.7 */ g_object_class_install_property (G_OBJECT_CLASS(klass), NGLOBJ_PROP, g_param_spec_uint("nGlObj", "N GL objects", "number of GL lists dealt with", 1, 2048, 1, G_PARAM_CONSTRUCT_ONLY | G_PARAM_READWRITE)); /** * VisuGlExt::dirty: * * Rendering properties have changed and the object should be drawn again. * * Since: 3.8 */ properties[DIRTY_PROP] = g_param_spec_boolean("dirty", "Dirty", "object rendering is out of date", FALSE, G_PARAM_READWRITE); g_object_class_install_property(G_OBJECT_CLASS(klass), DIRTY_PROP, properties[DIRTY_PROP]); /** * VisuGlExt::rendering-mode: * * The specific rendering mode of the extension or follow global setting. * * Since: 3.8 */ properties[RMODE_PROP] = g_param_spec_uint("rendering-mode", "Rendering mode", "specific rendering mode for the extension", VISU_GL_RENDERING_WIREFRAME, VISU_GL_RENDERING_FOLLOW, VISU_GL_RENDERING_FOLLOW, G_PARAM_READWRITE); g_object_class_install_property(G_OBJECT_CLASS(klass), RMODE_PROP, properties[RMODE_PROP]); oldEntry = visu_config_file_addEntry(VISU_CONFIG_FILE_PARAMETER, FLAG_PARAMETER_MODE, DESC_PARAMETER_MODE, 1, NULL); visu_config_file_entry_setVersion(oldEntry, 3.4f); confEntry = visu_config_file_addEnumEntry(VISU_CONFIG_FILE_RESOURCE, FLAG_RESOURCE_MODE, DESC_RESOURCE_MODE, &_rMode, visu_gl_rendering_getModeFromName, TRUE); visu_config_file_entry_setVersion(confEntry, 3.8f); visu_config_file_entry_setReplace(confEntry, oldEntry); visu_config_file_addExportFunction(VISU_CONFIG_FILE_RESOURCE, exportRendering); klass->allExtensions = (GList*)0; my_class = klass; } static void visu_gl_ext_init(VisuGlExt *ext) { DBG_fprintf(stderr, "Visu Extension: initializing a new object (%p).\n", (gpointer)ext); ext->priv = visu_gl_ext_get_instance_private(ext); ext->priv->dispose_has_run = FALSE; /* Set-up all not parameters attributes. */ ext->priv->used = TRUE; ext->priv->dirty = TRUE; ext->priv->priority = VISU_GL_EXT_PRIORITY_NORMAL; ext->priv->objectListId = 0; ext->priv->preferedRenderingMode = VISU_GL_RENDERING_FOLLOW; ext->priv->trans[0] = 0.f; ext->priv->trans[1] = 0.f; ext->priv->trans[2] = 0.f; ext->priv->gl = (VisuGl*)0; g_signal_connect_object(VISU_CONFIG_FILE_RESOURCE, "parsed::" FLAG_RESOURCE_MODE, G_CALLBACK(onEntryMode), (gpointer)ext, G_CONNECT_SWAPPED); my_class->allExtensions = g_list_append(my_class->allExtensions, (gpointer)ext); } /* This method can be called several times. It should unref all of its reference to GObjects. */ static void visu_gl_ext_dispose(GObject* obj) { VisuGlExt *ext; DBG_fprintf(stderr, "Visu Extension: dispose object %p.\n", (gpointer)obj); ext = VISU_GL_EXT(obj); if (ext->priv->dispose_has_run) return; ext->priv->dispose_has_run = TRUE; /* Chain up to the parent class */ G_OBJECT_CLASS(visu_gl_ext_parent_class)->dispose(obj); } /* This method is called once only. */ static void visu_gl_ext_finalize(GObject* obj) { VisuGlExtPrivate *ext; g_return_if_fail(obj); DBG_fprintf(stderr, "Visu Extension: finalize object %p.\n", (gpointer)obj); ext = VISU_GL_EXT(obj)->priv; if (ext->name) g_free(ext->name); if (ext->nameI18n) g_free(ext->nameI18n); if (ext->description) g_free(ext->description); glDeleteLists(ext->objectListId, ext->nGlObj); my_class->allExtensions = g_list_remove_all(my_class->allExtensions, (gpointer)obj); /* Chain up to the parent class */ DBG_fprintf(stderr, "Visu Extension: chain to parent.\n"); G_OBJECT_CLASS(visu_gl_ext_parent_class)->finalize(obj); DBG_fprintf(stderr, "Visu Extension: freeing ... OK.\n"); } static void visu_gl_ext_get_property(GObject* obj, guint property_id, GValue *value, GParamSpec *pspec) { VisuGlExtPrivate *self = VISU_GL_EXT(obj)->priv; DBG_fprintf(stderr, "Visu Extension: get property '%s' -> ", g_param_spec_get_name(pspec)); switch (property_id) { case NAME_PROP: g_value_set_string(value, self->name); DBG_fprintf(stderr, "%s.\n", self->name); break; case LABEL_PROP: if (self->nameI18n && self->nameI18n[0]) g_value_set_string(value, self->nameI18n); else g_value_set_string(value, self->name); DBG_fprintf(stderr, "%s.\n", self->nameI18n); break; case DESCRIPTION_PROP: g_value_set_string(value, self->description); DBG_fprintf(stderr, "%s.\n", self->description); break; case ACTIVE_PROP: g_value_set_boolean(value, self->used); DBG_fprintf(stderr, "%d.\n", self->used); break; case SAVE_STATE_PROP: g_value_set_boolean(value, self->saveState); DBG_fprintf(stderr, "%d.\n", self->saveState); break; case PRIORITY_PROP: g_value_set_uint(value, self->priority); DBG_fprintf(stderr, "%d.\n", self->priority); break; case NGLOBJ_PROP: g_value_set_uint(value, self->nGlObj); DBG_fprintf(stderr, "%d.\n", self->nGlObj); break; case DIRTY_PROP: g_value_set_boolean(value, self->dirty); DBG_fprintf(stderr, "%d.\n", self->dirty); break; case RMODE_PROP: g_value_set_uint(value, self->preferedRenderingMode); DBG_fprintf(stderr, "%d.\n", self->preferedRenderingMode); break; default: /* We don't have any other property... */ G_OBJECT_WARN_INVALID_PROPERTY_ID(obj, property_id, pspec); break; } } static void visu_gl_ext_set_property(GObject* obj, guint property_id, const GValue *value, GParamSpec *pspec) { VisuGlExtPrivate *self = VISU_GL_EXT(obj)->priv; DBG_fprintf(stderr, "Visu Extension: set property '%s' -> ", g_param_spec_get_name(pspec)); switch (property_id) { case NAME_PROP: self->name = g_value_dup_string(value); DBG_fprintf(stderr, "%s.\n", self->name); break; case LABEL_PROP: self->nameI18n = g_value_dup_string(value); DBG_fprintf(stderr, "%s.\n", self->nameI18n); break; case DESCRIPTION_PROP: self->description = g_value_dup_string(value); DBG_fprintf(stderr, "%s.\n", self->description); break; case ACTIVE_PROP: visu_gl_ext_setActive(VISU_GL_EXT(obj), g_value_get_boolean(value)); DBG_fprintf(stderr, "%d.\n", self->used); /* visu_gl_ext_draw(VISU_GL_EXT(obj)); */ break; case SAVE_STATE_PROP: self->saveState = g_value_get_boolean(value); DBG_fprintf(stderr, "%d.\n", self->saveState); break; case PRIORITY_PROP: self->priority = g_value_get_uint(value); DBG_fprintf(stderr, "%d.\n", self->priority); break; case NGLOBJ_PROP: self->nGlObj = g_value_get_uint(value); DBG_fprintf(stderr, "%d.\n", self->nGlObj); self->objectListId = visu_gl_objectlist_new(self->nGlObj); break; case DIRTY_PROP: DBG_fprintf(stderr, "%d.\n", self->nGlObj); visu_gl_ext_setDirty(VISU_GL_EXT(obj), g_value_get_boolean(value)); break; case RMODE_PROP: DBG_fprintf(stderr, "%d.\n", g_value_get_uint(value)); visu_gl_ext_setPreferedRenderingMode(VISU_GL_EXT(obj), g_value_get_uint(value)); break; default: /* We don't have any other property... */ G_OBJECT_WARN_INVALID_PROPERTY_ID(obj, property_id, pspec); break; } } /** * visu_gl_ext_setDirty: * @ext: a #VisuGlExt object. * @status: a boolean. * * Set an internal flag to mark that @ext should be redrawn before * next OpenGL frame view. * * Since: 3.8 * * Returns: TRUE is status is actually changed. **/ gboolean visu_gl_ext_setDirty(VisuGlExt *ext, gboolean status) { g_return_val_if_fail(VISU_IS_GL_EXT(ext), FALSE); /* It's an exception here, it's VisuGlExtSet that will ignore redundant call to dirty status. */ if (ext->priv->dirty == status) return FALSE; DBG_fprintf(stderr, "Visu Extension: '%s' becomes dirty (%d).\n", ext->priv->name, status); ext->priv->dirty = status; if (status) g_object_notify_by_pspec(G_OBJECT(ext), properties[DIRTY_PROP]); return TRUE; } /** * visu_gl_ext_getActive: * @extension: the extension. * * Get if the extension is used or not. If not its ObjectList * is not rendered. * * Returns: TRUE if used, FALSE otherwise. */ gboolean visu_gl_ext_getActive(VisuGlExt* extension) { g_return_val_if_fail(VISU_IS_GL_EXT(extension), FALSE); if (extension) return extension->priv->used; else return FALSE; } /** * visu_gl_ext_setActive: * @extension: the extension, * @value: the new value. * * Set if an extension is actually used or not. */ gboolean visu_gl_ext_setActive(VisuGlExt* extension, gboolean value) { g_return_val_if_fail(VISU_IS_GL_EXT(extension), FALSE); if (extension->priv->used == value) return FALSE; DBG_fprintf(stderr, "Visu Extension: '%s' becomes active (%d).\n", extension->priv->name, value); extension->priv->used = value; g_object_notify_by_pspec(G_OBJECT(extension), properties[ACTIVE_PROP]); return TRUE; } /** * visu_gl_ext_getPriority: * @extension: a #VisuGlExt object. * * Inquire the priority of @extension. * * Since: 3.8 * * Returns: the #VisuGlExt priority. **/ guint visu_gl_ext_getPriority(VisuGlExt *extension) { g_return_val_if_fail(VISU_IS_GL_EXT(extension), VISU_GL_EXT_PRIORITY_BACKGROUND); return extension->priv->priority; } /** * visu_gl_ext_setPreferedRenderingMode: * @extension: a #VisuGlExt object ; * @value: see #VisuGlRenderingMode to choose one. * * This method is used to specify the rendering mode that the extension should use * to be drawn. If the @value is set to #VISU_GL_RENDERING_FOLLOW, the * extension follows the global setting for rendering mode. * * Returns: TRUE if value is actually changed. */ gboolean visu_gl_ext_setPreferedRenderingMode(VisuGlExt* extension, VisuGlRenderingMode value) { g_return_val_if_fail(VISU_IS_GL_EXT(extension), FALSE); g_return_val_if_fail(value < VISU_GL_RENDERING_N_MODES || value == VISU_GL_RENDERING_FOLLOW, FALSE); if (extension->priv->preferedRenderingMode == value) return FALSE; extension->priv->preferedRenderingMode = value; g_object_notify_by_pspec(G_OBJECT(extension), properties[RMODE_PROP]); return TRUE; } /** * visu_gl_ext_getPreferedRenderingMode: * @extension: a #VisuGlExt method. * * Each #VisuGlExt method can draw in a mode different from the * global one, see #VisuGlRenderingMode. See also * visu_gl_ext_setPreferedRenderingMode(). * * Since: 3.7 * * Returns: the prefered rendering mode of this @extension. **/ VisuGlRenderingMode visu_gl_ext_getPreferedRenderingMode(VisuGlExt* extension) { g_return_val_if_fail(VISU_IS_GL_EXT(extension), VISU_GL_RENDERING_FOLLOW); return extension->priv->preferedRenderingMode; } /** * visu_gl_ext_getGlList: * @extension: a #VisuGlExt method. * * All #VisuGlExt objects have a master OpenGL list to draw * to. This routine gets the identifier of this list. * * Since: 3.7 * * Returns: an OpenGL identifier id for @extension. **/ guint visu_gl_ext_getGlList(VisuGlExt *extension) { g_return_val_if_fail(VISU_IS_GL_EXT(extension), 0); return extension->priv->objectListId; } /** * visu_gl_ext_setTranslation: * @extension: a #VisuGlExt method. * @trans: (array fixed-size=3): a translation vector in real space. * * Change the translation the extension is drawn at. * * Since: 3.8 * * Returns: TRUE if the translations are indeed changed. **/ gboolean visu_gl_ext_setTranslation(VisuGlExt *extension, const gfloat trans[3]) { g_return_val_if_fail(VISU_IS_GL_EXT(extension), FALSE); if (extension->priv->trans[0] == trans[0] && extension->priv->trans[1] == trans[1] && extension->priv->trans[2] == trans[2]) return FALSE; extension->priv->trans[0] = trans[0]; extension->priv->trans[1] = trans[1]; extension->priv->trans[2] = trans[2]; return TRUE; } /********************/ /* Class functions. */ /********************/ /** * visu_gl_ext_call: * @extension: a #VisuGlExt object. * @lastOnly: a boolean. * * Select the #VisuGlExt matching the given @name and call * it. The call is indeed done only if the extension is used. If * @lastOnly is TRUE, the list is called only if it has a * #VISU_GL_EXT_PRIORITY_LAST priority. On the contrary the list * is called only if its priority is lower than * #VISU_GL_EXT_PRIORITY_LAST. */ void visu_gl_ext_call(VisuGlExt *ext, gboolean lastOnly) { VisuGlRenderingMode renderingMode, globalRenderingMode; GList lst; g_return_if_fail(VISU_IS_GL_EXT(ext)); /* DBG_fprintf(stderr, "Visu Extension: call '%s' list.\n", ext->priv->name); */ /* DBG_fprintf(stderr, "| has %d ref counts.\n", G_OBJECT(ext)->ref_count); */ if (!ext->priv->used || ext->priv->objectListId < 1000) return; if ((lastOnly && ext->priv->priority == VISU_GL_EXT_PRIORITY_LAST) || (!lastOnly && ext->priv->priority < VISU_GL_EXT_PRIORITY_LAST)) { /* Rebuild it if necessary. */ if (VISU_GL_EXT_GET_CLASS(ext)->draw && ext->priv->dirty) VISU_GL_EXT_GET_CLASS(ext)->draw(ext); globalRenderingMode = visu_gl_getMode(ext->priv->gl); renderingMode = globalRenderingMode; lst.data = (gpointer)ext; lst.next = lst.prev = (GList*)0; glTranslatef(ext->priv->trans[0], ext->priv->trans[1], ext->priv->trans[2]); callList(&lst, &renderingMode, globalRenderingMode); glTranslatef(-ext->priv->trans[0], -ext->priv->trans[1], -ext->priv->trans[2]); if (renderingMode != globalRenderingMode) /* Return the rendering mode to normal. */ visu_gl_rendering_applyMode(globalRenderingMode); } } /** * visu_gl_ext_rebuild: * @self: a #VisuGlExt object. * * This routine does not sort the extension on their priority and * should be used only to draw some selected extensions. This method * is called automatically for all extensions in a #VisuGlExtSet when required. */ void visu_gl_ext_rebuild(VisuGlExt *self) { g_return_if_fail(VISU_IS_GL_EXT(self)); DBG_fprintf(stderr, "Visu Extension: rebuilding '%s' list.\n", self->priv->name); if (self->priv->used && VISU_GL_EXT_GET_CLASS(self)->rebuild) VISU_GL_EXT_GET_CLASS(self)->rebuild(self); } /** * visu_gl_ext_setGlView: * @ext: a #VisuGlExt object. * @view: a #VisuGlView object. * * Attach a @view to the @self extension. * * Since: 3.8 * * Returns: TRUE if the @view is changed. */ gboolean visu_gl_ext_setGlView(VisuGlExt *ext, VisuGlView *view) { g_return_val_if_fail(VISU_IS_GL_EXT(ext), FALSE); DBG_fprintf(stderr, "Visu Extension: set view %p to '%s' (%d).\n", (gpointer)view, ext->priv->name, ext->priv->used); return (VISU_GL_EXT_GET_CLASS(ext)->setGlView && VISU_GL_EXT_GET_CLASS(ext)->setGlView(ext, view)); } /** * visu_gl_ext_getGlContext: * @extension: a #VisuGlExt object. * * The #VisuGl object this extension draws to. * * Since: 3.8 * * Returns: (transfer none) (allow-none): the #VisuGl object this * extension draws to. **/ VisuGl* visu_gl_ext_getGlContext(VisuGlExt* extension) { g_return_val_if_fail(VISU_IS_GL_EXT(extension), (VisuGl*)0); return extension->priv->gl; } /** * visu_gl_ext_setGlContext: * @extension: a #VisuGlExt object. * @gl: (transfer none): a #VisuGl object. * * Associate @gl to @extension. * * Since: 3.8 * * Returns: TRUE if the value is actually changed. **/ gboolean visu_gl_ext_setGlContext(VisuGlExt* extension, VisuGl *gl) { g_return_val_if_fail(VISU_IS_GL_EXT(extension), FALSE); if (extension->priv->gl == gl) return FALSE; extension->priv->gl = gl; return TRUE; } /** * visu_gl_ext_getName: * @extension: a #VisuGlExt object. * * Retrieve the name of the extension. * * Since: 3.8 * * Returns: the name of the extension. **/ const gchar* visu_gl_ext_getName(const VisuGlExt *extension) { g_return_val_if_fail(VISU_IS_GL_EXT(extension), (const gchar*)0); return extension->priv->name; } /** * visu_gl_ext_startDrawing: * @extension: a #VisuGlExt object. * * Method to be called in the draw function to start compiling the * list. Wghen drawing primitives are all done, call * visu_gl_ext_completeDrawing(). * * Since: 3.8 **/ void visu_gl_ext_startDrawing(VisuGlExt *extension) { g_return_if_fail(VISU_IS_GL_EXT(extension)); glNewList(extension->priv->objectListId, GL_COMPILE); } /** * visu_gl_ext_completeDrawing: * @extension: a #VisuGlExt object. * * A method to be called after calling visu_gl_ext_startDrawing(), * when the drawing primitives have all been called. It also reset the * dirty flag for this extension. * * Since: 3.8 **/ void visu_gl_ext_completeDrawing(VisuGlExt *extension) { g_return_if_fail(VISU_IS_GL_EXT(extension)); visu_gl_ext_setDirty(extension, FALSE); glEndList(); } /****************/ /* Private area */ /****************/ static void callList(GList *lst, VisuGlRenderingMode *renderingMode, VisuGlRenderingMode globalRenderingMode) { VisuGlExt *ext; GTimer *timer; gulong fractionTimer; #if DEBUG == 1 timer = g_timer_new(); g_timer_start(timer); #endif for (; lst; lst = g_list_next(lst)) { ext = (VisuGlExt*)lst->data; /* The extension needs its own rendering mode. */ if (ext->priv->preferedRenderingMode < VISU_GL_RENDERING_N_MODES) { if (ext->priv->preferedRenderingMode != *renderingMode) { visu_gl_rendering_applyMode(ext->priv->preferedRenderingMode); *renderingMode = ext->priv->preferedRenderingMode; } } else { if (*renderingMode != globalRenderingMode) { visu_gl_rendering_applyMode(globalRenderingMode); *renderingMode = globalRenderingMode; } } /* Save OpenGL state if necessary. */ if (ext->priv->saveState) { DBG_fprintf(stderr, "Visu Extension: save state.\n"); glPushAttrib(GL_ENABLE_BIT); } if (ext->priv->preferedRenderingMode < VISU_GL_RENDERING_N_MODES && *renderingMode == VISU_GL_RENDERING_SMOOTH_AND_EDGE) { glPushAttrib(GL_ENABLE_BIT); glEnable(GL_POLYGON_OFFSET_FILL); glPolygonOffset(1.0, 1.0); } /* Call the compiled list. */ DBG_fprintf(stderr, "Visu Extension: call list %d (%s %d)", ext->priv->objectListId, ext->priv->name, ext->priv->used); glCallList(ext->priv->objectListId); DBG_fprintf(stderr, " at %g micro-s", g_timer_elapsed(timer, &fractionTimer)*1e6); DBG_fprintf(stderr, ".\n"); /* Add a wireframe draw if renderingMode is VISU_GL_RENDERING_SMOOTH_AND_EDGE. */ if (ext->priv->preferedRenderingMode < VISU_GL_RENDERING_N_MODES && *renderingMode == VISU_GL_RENDERING_SMOOTH_AND_EDGE) { glDisable(GL_POLYGON_OFFSET_FILL); glDisable(GL_LIGHTING); glColor3f (0.0, 0.0, 0.0); glLineWidth(1); glPolygonMode(GL_FRONT_AND_BACK, GL_LINE); glCallList(ext->priv->objectListId); glPolygonMode(GL_FRONT_AND_BACK, GL_FILL); glPopAttrib(); } if (ext->priv->saveState) { DBG_fprintf(stderr, "Visu Extension: restore state.\n"); glPopAttrib(); } } #if DEBUG == 1 g_timer_stop(timer); g_timer_destroy(timer); #endif } static void onEntryMode(VisuGlExt *ext, VisuConfigFileEntry *entry, VisuConfigFile *obj _U_) { if (strcmp(ext->priv->name, visu_config_file_entry_getLabel(entry))) return; visu_gl_ext_setPreferedRenderingMode(ext, _rMode); } static void exportRendering(GString *data, VisuData *dataObj _U_) { GList *tmp; VisuGlExt *ext; const char **names; if (!my_class) g_type_class_ref(VISU_TYPE_GL_EXT); visu_config_file_exportComment(data, DESC_RESOURCE_MODE); names = visu_gl_rendering_getAllModes(); for (tmp = my_class->allExtensions; tmp; tmp = g_list_next(tmp)) { ext = (VisuGlExt*)tmp->data; if (ext->priv->preferedRenderingMode < VISU_GL_RENDERING_N_MODES) visu_config_file_exportEntry(data, FLAG_RESOURCE_MODE, ext->priv->name, "%s", names[ext->priv->preferedRenderingMode]); } visu_config_file_exportComment(data, ""); } v_sim-3.8.0/src/visu_extension.h000066400000000000000000000144241370110300500166540ustar00rootroot00000000000000/* EXTRAITS DE LA LICENCE Copyright CEA, contributeurs : Luc BILLARD et Damien CALISTE, laboratoire L_Sim, (2001-2005) Adresse mèl : BILLARD, non joignable par mèl ; CALISTE, damien P caliste AT cea P fr. Ce logiciel est un programme informatique servant à visualiser des structures atomiques dans un rendu pseudo-3D. Ce logiciel est régi par la licence CeCILL soumise au droit français et respectant les principes de diffusion des logiciels libres. Vous pouvez utiliser, modifier et/ou redistribuer ce programme sous les conditions de la licence CeCILL telle que diffusée par le CEA, le CNRS et l'INRIA sur le site "http://www.cecill.info". Le fait que vous puissiez accéder à cet en-tête signifie que vous avez pris connaissance de la licence CeCILL, et que vous en avez accepté les termes (cf. le fichier Documentation/licence.fr.txt fourni avec ce logiciel). */ /* LICENCE SUM UP Copyright CEA, contributors : Luc BILLARD et Damien CALISTE, laboratoire L_Sim, (2001-2005) E-mail address: BILLARD, not reachable any more ; CALISTE, damien P caliste AT cea P fr. This software is a computer program whose purpose is to visualize atomic configurations in 3D. This software is governed by the CeCILL license under French law and abiding by the rules of distribution of free software. You can use, modify and/ or redistribute the software under the terms of the CeCILL license as circulated by CEA, CNRS and INRIA at the following URL "http://www.cecill.info". The fact that you are presently reading this means that you have had knowledge of the CeCILL license and that you accept its terms. You can find a copy of this licence shipped with this software at Documentation/licence.en.txt. */ #ifndef VISU_GL_EXT_H #define VISU_GL_EXT_H #include #include #include "visu_tools.h" #include "opengl.h" #include "openGLFunctions/renderingMode.h" #include "openGLFunctions/view.h" G_BEGIN_DECLS /***************/ /* Public part */ /***************/ /** * VISU_GL_EXT_PRIORITY_BACKGROUND * * An extension with this priority is drawn first. */ #define VISU_GL_EXT_PRIORITY_BACKGROUND 0 /** * VISU_GL_EXT_PRIORITY_NODES * * An extension with this priority is drawn alsmost first with the nodes. */ #define VISU_GL_EXT_PRIORITY_NODES 2 /** * VISU_GL_EXT_PRIORITY_NODE_DECORATIONS * * An extension with this priority is drawn just after the nodes. */ #define VISU_GL_EXT_PRIORITY_NODE_DECORATIONS 5 /** * VISU_GL_EXT_PRIORITY_HIGH * * An extension with this priority is drawn after the higher priorities. */ #define VISU_GL_EXT_PRIORITY_HIGH 20 /** * VISU_GL_EXT_PRIORITY_NORMAL * * An extension with this priority is drawn after the higher priorities. */ #define VISU_GL_EXT_PRIORITY_NORMAL 50 /** * VISU_GL_EXT_PRIORITY_LOW * * An extension with this priority is drawn among last extensions. */ #define VISU_GL_EXT_PRIORITY_LOW 80 /** * VISU_GL_EXT_PRIORITY_LAST * * An extension with this priority is drawn last. */ #define VISU_GL_EXT_PRIORITY_LAST 100 /** * VISU_TYPE_GL_EXT: * * return the type of #VisuGlExt. */ #define VISU_TYPE_GL_EXT (visu_gl_ext_get_type ()) /** * VISU_GL_EXT: * @obj: a #GObject to cast. * * Cast the given @obj into #VisuGlExt type. */ #define VISU_GL_EXT(obj) (G_TYPE_CHECK_INSTANCE_CAST(obj, VISU_TYPE_GL_EXT, VisuGlExt)) /** * VISU_GL_EXT_CLASS: * @klass: a #GObjectClass to cast. * * Cast the given @klass into #VisuGlExtClass. */ #define VISU_GL_EXT_CLASS(klass) (G_TYPE_CHECK_CLASS_CAST(klass, VISU_TYPE_GL_EXT, VisuGlExtClass)) /** * VISU_IS_GL_EXT: * @obj: a #GObject to test. * * Test if the given @ogj is of the type of #VisuGlExt object. */ #define VISU_IS_GL_EXT(obj) (G_TYPE_CHECK_INSTANCE_TYPE(obj, VISU_TYPE_GL_EXT)) /** * VISU_IS_GL_EXT_CLASS: * @klass: a #GObjectClass to test. * * Test if the given @klass is of the type of #VisuGlExtClass class. */ #define VISU_IS_GL_EXT_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE(klass, VISU_TYPE_GL_EXT)) /** * VISU_GL_EXT_GET_CLASS: * @obj: a #GObject to get the class of. * * It returns the class of the given @obj. */ #define VISU_GL_EXT_GET_CLASS(obj) (G_TYPE_INSTANCE_GET_CLASS(obj, VISU_TYPE_GL_EXT, VisuGlExtClass)) /** * VisuGlExtPrivate: * * Private data for #VisuGlExt objects. */ typedef struct _VisuGlExtPrivate VisuGlExtPrivate; /** * VisuGlExt: * * Common name to refer to a #_VisuGlExt. */ typedef struct _VisuGlExt VisuGlExt; struct _VisuGlExt { VisuObject parent; VisuGlExtPrivate *priv; }; /** * VisuGlExtClass: * @parent: private. * @setGlView: a method to attach a #VisuGlView object to this extension. * @rebuild: a rebuilding function for this extension. * @draw: a draw method for this extension. * @allExtensions: the list of all stored #VisuGlExt objects. * * Common name to refer to a #_VisuGlExtClass. */ typedef struct _VisuGlExtClass VisuGlExtClass; struct _VisuGlExtClass { VisuObjectClass parent; gboolean (*setGlView)(VisuGlExt *ext, VisuGlView *view); void (*rebuild)(VisuGlExt *self); void (*draw)(VisuGlExt *self); GList *allExtensions; }; /** * visu_gl_ext_get_type: * * This method returns the type of #VisuGlExt, use * VISU_TYPE_GL_EXT instead. * * Since: 3.7 * * Returns: the type of #VisuGlExt. */ GType visu_gl_ext_get_type(void); gboolean visu_gl_ext_setDirty(VisuGlExt *ext, gboolean status); guint visu_gl_ext_getPriority(VisuGlExt *extension); gboolean visu_gl_ext_getActive(VisuGlExt* extension); gboolean visu_gl_ext_setActive(VisuGlExt* extension, gboolean value); VisuGl* visu_gl_ext_getGlContext(VisuGlExt* extension); gboolean visu_gl_ext_setGlContext(VisuGlExt* extension, VisuGl *gl); gboolean visu_gl_ext_setPreferedRenderingMode(VisuGlExt* extension, VisuGlRenderingMode value); VisuGlRenderingMode visu_gl_ext_getPreferedRenderingMode(VisuGlExt* extension); gboolean visu_gl_ext_setTranslation(VisuGlExt *extension, const gfloat trans[3]); guint visu_gl_ext_getGlList(VisuGlExt *extension); const gchar* visu_gl_ext_getName(const VisuGlExt *extension); void visu_gl_ext_startDrawing(VisuGlExt *extension); void visu_gl_ext_completeDrawing(VisuGlExt *extension); void visu_gl_ext_call(VisuGlExt *extension, gboolean lastOnly); void visu_gl_ext_rebuild(VisuGlExt *self); gboolean visu_gl_ext_setGlView(VisuGlExt *ext, VisuGlView *view); G_END_DECLS #endif v_sim-3.8.0/src/visu_extset.c000066400000000000000000001513341370110300500161510ustar00rootroot00000000000000/* EXTRAITS DE LA LICENCE Copyright CEA, contributeurs : Damien CALISTE, laboratoire L_Sim, (2015) Adresse mèl : CALISTE, damien P caliste AT cea P fr. Ce logiciel est un programme informatique servant à visualiser des structures atomiques dans un rendu pseudo-3D. Ce logiciel est régi par la licence CeCILL soumise au droit français et respectant les principes de diffusion des logiciels libres. Vous pouvez utiliser, modifier et/ou redistribuer ce programme sous les conditions de la licence CeCILL telle que diffusée par le CEA, le CNRS et l'INRIA sur le site "http://www.cecill.info". Le fait que vous puissiez accéder à cet en-tête signifie que vous avez pris connaissance de la licence CeCILL, et que vous en avez accepté les termes (cf. le fichier Documentation/licence.fr.txt fourni avec ce logiciel). */ /* LICENCE SUM UP Copyright CEA, contributors : Damien CALISTE, laboratoire L_Sim, (2015) E-mail address: CALISTE, damien P caliste AT cea P fr. This software is a computer program whose purpose is to visualize atomic configurations in 3D. This software is governed by the CeCILL license under French law and abiding by the rules of distribution of free software. You can use, modify and/ or redistribute the software under the terms of the CeCILL license as circulated by CEA, CNRS and INRIA at the following URL "http://www.cecill.info". The fact that you are presently reading this means that you have had knowledge of the CeCILL license and that you accept its terms. You can find a copy of this licence shipped with this software at Documentation/licence.en.txt. */ #include "visu_extset.h" #include #include #include "opengl.h" #include "visu_tools.h" #include "iface_boxed.h" #include "visu_configFile.h" #include "openGLFunctions/objectList.h" #include "coreTools/toolConfigFile.h" #include "OSOpenGL/visu_openGL.h" #include "extensions/mapset.h" /** * SECTION:visu_extset * @short_description: Defines a storage object to handle a bunch of * #VisuGlExt objects. * * A storage to display several #VisuGlExt objects. It takes * care of ordering display, following priority of each object. */ /* Parameters & resources*/ /* A resource to control the color of the background. */ #define FLAG_RESOURCE_BG_COLOR "backgroundColor_color" #define DESC_RESOURCE_BG_COLOR "Set the background of the background ; four floating point values (0. <= v <= 1.)" static float bgRGBDefault[4] = {0., 0., 0., 1.}; /* This is a boolean to control is the axes is render or not. */ #define FLAG_RESOURCE_FOG_USED "fog_is_on" #define DESC_RESOURCE_FOG_USED "Control if the fog is used ; boolean (0 or 1)" static gboolean fogActiveDefault = TRUE; #define FLAG_RESOURCE_FOG_SPECIFIC "fog_color_is_specific" #define DESC_RESOURCE_FOG_SPECIFIC "Control if the fog uses a specific color ; boolean (0 or 1)" static gboolean fogSpecificDefault = FALSE; #define FLAG_RESOURCE_FOG_COLOR "fog_specific_color" #define DESC_RESOURCE_FOG_COLOR "Define the color of the fog ; four floating point values (0. <= v <= 1.)" static float fogRGBDefault[4] = {0.f, 0.f, 0.f, 1.f}; #define FLAG_RESOURCE_FOG_STARTEND "fog_start_end" #define DESC_RESOURCE_FOG_STARTEND "Define the position of the fog ; two floating point values (0. <= v <= 1.)" static float fogStartEndDefault[2] = {0.3f, 0.7f}; struct _GlExt { VisuGlExt *ext; gulong priority_sig, dirty_sig, active_sig; }; struct _VisuGlExtSetPrivate { gboolean dispose_has_run; /* A list to store all the available OpenGL extensions. */ GArray *set; gboolean reorderingNeeded, dirty; guint dirtyPending; /* The view extensions are rendered on. */ VisuGlView *view; gulong widthHeight_signal, chg_signal; /* Handling the background color and the fog. */ float bgRGB[4]; int chessList; gboolean bgDirty; gboolean fogActive; float fogStartEnd[2]; gboolean fogFollowsBg; float fogRGB[4]; }; enum { PROP_0, BG_R_PROP, BG_G_PROP, BG_B_PROP, BG_A_PROP, FOG_ACTIVE_PROP, FOG_START_PROP, FOG_FULL_PROP, FOG_FOLLOWS_PROP, FOG_R_PROP, FOG_G_PROP, FOG_B_PROP, FOG_A_PROP, DIRTY_PROP, N_PROP }; static GParamSpec *properties[N_PROP]; static VisuGlExtSet *defaultSet = NULL; static GLuint texName = 0; static void visu_gl_ext_set_dispose (GObject* obj); static void visu_gl_ext_set_finalize (GObject* obj); static void visu_gl_ext_set_get_property(GObject* obj, guint property_id, GValue *value, GParamSpec *pspec); static void visu_gl_ext_set_set_property(GObject* obj, guint property_id, const GValue *value, GParamSpec *pspec); static void visu_gl_ext_initContext (VisuGl *gl); /* Local callbacks */ static void onWidthHeight(VisuGlView *view, gpointer data); static void onCamera(VisuGlView *view, gpointer data); static void onEntryBgColor(VisuGlExtSet *set, VisuConfigFileEntry *entry, VisuConfigFile *obj); static void onEntryFogActive(VisuGlExtSet *set, VisuConfigFileEntry *entry, VisuConfigFile *obj); static void onEntryFogSpecific(VisuGlExtSet *set, VisuConfigFileEntry *entry, VisuConfigFile *obj); static void onEntryFogColor(VisuGlExtSet *set, VisuConfigFileEntry *entry, VisuConfigFile *obj); static void onEntryFogStartEnd(VisuGlExtSet *set, VisuConfigFileEntry *entry, VisuConfigFile *obj); static void _appendDirty(VisuGlExtSet *set); static void _chessDraw(VisuGlExtSet *set); static void exportResources(GString *data, VisuData *dataObj); G_DEFINE_TYPE_WITH_CODE(VisuGlExtSet, visu_gl_ext_set, VISU_TYPE_GL, G_ADD_PRIVATE(VisuGlExtSet)) static void visu_gl_ext_set_class_init(VisuGlExtSetClass *klass) { float rgColor[2] = {0.f, 1.f}; DBG_fprintf(stderr, "Visu Extension Set: creating the class of the object.\n"); /* DBG_fprintf(stderr, " - adding new signals ;\n"); */ /* Parameters */ visu_config_file_addFloatArrayEntry(VISU_CONFIG_FILE_RESOURCE, FLAG_RESOURCE_BG_COLOR, DESC_RESOURCE_BG_COLOR, 4, bgRGBDefault, rgColor, FALSE); visu_config_file_addBooleanEntry(VISU_CONFIG_FILE_RESOURCE, FLAG_RESOURCE_FOG_USED, DESC_RESOURCE_FOG_USED, &fogActiveDefault, FALSE); visu_config_file_addBooleanEntry(VISU_CONFIG_FILE_RESOURCE, FLAG_RESOURCE_FOG_SPECIFIC, DESC_RESOURCE_FOG_SPECIFIC, &fogSpecificDefault, FALSE); visu_config_file_addFloatArrayEntry(VISU_CONFIG_FILE_RESOURCE, FLAG_RESOURCE_FOG_COLOR, DESC_RESOURCE_FOG_COLOR, 4, fogRGBDefault, rgColor, FALSE); visu_config_file_addFloatArrayEntry(VISU_CONFIG_FILE_RESOURCE, FLAG_RESOURCE_FOG_STARTEND, DESC_RESOURCE_FOG_STARTEND, 2, fogStartEndDefault, rgColor, FALSE); visu_config_file_addExportFunction(VISU_CONFIG_FILE_RESOURCE, exportResources); /* Connect the overloading methods. */ G_OBJECT_CLASS(klass)->dispose = visu_gl_ext_set_dispose; G_OBJECT_CLASS(klass)->finalize = visu_gl_ext_set_finalize; G_OBJECT_CLASS(klass)->set_property = visu_gl_ext_set_set_property; G_OBJECT_CLASS(klass)->get_property = visu_gl_ext_set_get_property; VISU_GL_CLASS(klass)->initContext = visu_gl_ext_initContext; /** * VisuGlExtSet::dirty: * * TRUE when at least one of the active #VisuGlExt gets dirty. * * Since: 3.8 */ properties[DIRTY_PROP] = g_param_spec_boolean("dirty", "Dirty", "one of the object rendering is out of date", FALSE, G_PARAM_READABLE); g_object_class_install_property(G_OBJECT_CLASS(klass), DIRTY_PROP, properties[DIRTY_PROP]); /** * VisuGlExtSet::bg-red: * * Store the red channel of the background color. * * Since: 3.8 */ properties[BG_R_PROP] = g_param_spec_float("bg-red", "red channel", "background red channel", 0., 1., 0., G_PARAM_READWRITE); g_object_class_install_property(G_OBJECT_CLASS(klass), BG_R_PROP, properties[BG_R_PROP]); /** * VisuGlExtSet::bg-green: * * Store the green channel of the background color. * * Since: 3.8 */ properties[BG_G_PROP] = g_param_spec_float("bg-green", "green channel", "background green channel", 0., 1., 0., G_PARAM_READWRITE); g_object_class_install_property(G_OBJECT_CLASS(klass), BG_G_PROP, properties[BG_G_PROP]); /** * VisuGlExtSet::bg-blue: * * Store the blue channel of the background color. * * Since: 3.8 */ properties[BG_B_PROP] = g_param_spec_float("bg-blue", "blue channel", "background blue channel", 0., 1., 0., G_PARAM_READWRITE); g_object_class_install_property(G_OBJECT_CLASS(klass), BG_B_PROP, properties[BG_B_PROP]); /** * VisuGlExtSet::bg-alpha: * * Store the alpha channel of the background color. * * Since: 3.8 */ properties[BG_A_PROP] = g_param_spec_float("bg-alpha", "alpha channel", "background alpha channel", 0., 1., 0., G_PARAM_READWRITE); g_object_class_install_property(G_OBJECT_CLASS(klass), BG_A_PROP, properties[BG_A_PROP]); /** * VisuGlExtSet::fog-active: * * Store if the fog is used. * * Since: 3.8 */ properties[FOG_ACTIVE_PROP] = g_param_spec_boolean("fog-active", "Fog active", "Fog is used", TRUE, G_PARAM_READWRITE); g_object_class_install_property(G_OBJECT_CLASS(klass), FOG_ACTIVE_PROP, properties[FOG_ACTIVE_PROP]); /** * VisuGlExtSet::fog-start: * * Store the starting depth of the fog. * * Since: 3.8 */ properties[FOG_START_PROP] = g_param_spec_float("fog-start", "Fog start", "starting fog depth", 0., 1., 0.3, G_PARAM_READWRITE); g_object_class_install_property(G_OBJECT_CLASS(klass), FOG_START_PROP, properties[FOG_START_PROP]); /** * VisuGlExtSet::fog-full: * * Store the depth where the fog hides all. * * Since: 3.8 */ properties[FOG_FULL_PROP] = g_param_spec_float("fog-full", "Fog full", "depth where fog hides all", 0., 1., 0.7, G_PARAM_READWRITE); g_object_class_install_property(G_OBJECT_CLASS(klass), FOG_FULL_PROP, properties[FOG_FULL_PROP]); /** * VisuGlExtSet::fog-follows-bg: * * Store if the fog follows the background color. * * Since: 3.8 */ properties[FOG_FOLLOWS_PROP] = g_param_spec_boolean("fog-follows-bg", "Fog follows bg", "Fog color is the bg color", TRUE, G_PARAM_READWRITE); g_object_class_install_property(G_OBJECT_CLASS(klass), FOG_FOLLOWS_PROP, properties[FOG_FOLLOWS_PROP]); /** * VisuGlExtSet::fog-red: * * Store the red channel of the specific fog color. * * Since: 3.8 */ properties[FOG_R_PROP] = g_param_spec_float("fog-red", "red channel", "specific fog red channel", 0., 1., 0., G_PARAM_READWRITE); g_object_class_install_property(G_OBJECT_CLASS(klass), FOG_R_PROP, properties[FOG_R_PROP]); /** * VisuGlExtSet::fog-green: * * Store the green channel of the specific fog color. * * Since: 3.8 */ properties[FOG_G_PROP] = g_param_spec_float("fog-green", "green channel", "specific fog green channel", 0., 1., 0., G_PARAM_READWRITE); g_object_class_install_property(G_OBJECT_CLASS(klass), FOG_G_PROP, properties[FOG_G_PROP]); /** * VisuGlExtSet::fog-blue: * * Store the blue channel of the specific fog color. * * Since: 3.8 */ properties[FOG_B_PROP] = g_param_spec_float("fog-blue", "blue channel", "specific fog blue channel", 0., 1., 0., G_PARAM_READWRITE); g_object_class_install_property(G_OBJECT_CLASS(klass), FOG_B_PROP, properties[FOG_B_PROP]); /** * VisuGlExtSet::fog-alpha: * * Store the alpha channel of the specific fog color. * * Since: 3.8 */ properties[FOG_A_PROP] = g_param_spec_float("fog-alpha", "alpha channel", "specific fog alpha channel", 0., 1., 1., G_PARAM_READWRITE); g_object_class_install_property(G_OBJECT_CLASS(klass), FOG_A_PROP, properties[FOG_A_PROP]); visu_gl_objectlist_init(); } static void visu_gl_ext_set_init(VisuGlExtSet *ext) { DBG_fprintf(stderr, "Visu Extension Set: initializing a new object (%p).\n", (gpointer)ext); ext->priv = visu_gl_ext_set_get_instance_private(ext); ext->priv->dispose_has_run = FALSE; ext->priv->set = g_array_new(FALSE, FALSE, sizeof(struct _GlExt)); ext->priv->reorderingNeeded = FALSE; ext->priv->dirty = FALSE; ext->priv->dirtyPending = 0; ext->priv->view = (VisuGlView*)0; g_signal_connect(G_OBJECT(ext), "notify::lights", G_CALLBACK(_appendDirty), (gpointer)0); g_signal_connect(G_OBJECT(ext), "notify::antialias", G_CALLBACK(_appendDirty), (gpointer)0); g_signal_connect(G_OBJECT(ext), "notify::immediate", G_CALLBACK(_appendDirty), (gpointer)0); g_signal_connect(G_OBJECT(ext), "notify::true-transparency", G_CALLBACK(_appendDirty), (gpointer)0); g_signal_connect(G_OBJECT(ext), "notify::stereo", G_CALLBACK(_appendDirty), (gpointer)0); g_signal_connect(G_OBJECT(ext), "notify::stereo-angle", G_CALLBACK(_appendDirty), (gpointer)0); g_signal_connect(G_OBJECT(ext), "notify::mode", G_CALLBACK(_appendDirty), (gpointer)0); ext->priv->bgRGB[0] = bgRGBDefault[0]; ext->priv->bgRGB[1] = bgRGBDefault[1]; ext->priv->bgRGB[2] = bgRGBDefault[2]; ext->priv->bgRGB[3] = bgRGBDefault[3]; g_signal_connect_object(VISU_CONFIG_FILE_RESOURCE, "parsed::" FLAG_RESOURCE_BG_COLOR, G_CALLBACK(onEntryBgColor), (gpointer)ext, G_CONNECT_SWAPPED); ext->priv->chessList = visu_gl_objectlist_new(1); ext->priv->bgDirty = FALSE; ext->priv->fogActive = fogActiveDefault; ext->priv->fogStartEnd[0] = fogStartEndDefault[0]; ext->priv->fogStartEnd[1] = fogStartEndDefault[1]; ext->priv->fogFollowsBg = !fogSpecificDefault; ext->priv->fogRGB[0] = fogRGBDefault[0]; ext->priv->fogRGB[1] = fogRGBDefault[1]; ext->priv->fogRGB[2] = fogRGBDefault[2]; ext->priv->fogRGB[3] = fogRGBDefault[3]; g_signal_connect_object(VISU_CONFIG_FILE_RESOURCE, "parsed::" FLAG_RESOURCE_FOG_USED, G_CALLBACK(onEntryFogActive), (gpointer)ext, G_CONNECT_SWAPPED); g_signal_connect_object(VISU_CONFIG_FILE_RESOURCE, "parsed::" FLAG_RESOURCE_FOG_SPECIFIC, G_CALLBACK(onEntryFogSpecific), (gpointer)ext, G_CONNECT_SWAPPED); g_signal_connect_object(VISU_CONFIG_FILE_RESOURCE, "parsed::" FLAG_RESOURCE_FOG_COLOR, G_CALLBACK(onEntryFogColor), (gpointer)ext, G_CONNECT_SWAPPED); g_signal_connect_object(VISU_CONFIG_FILE_RESOURCE, "parsed::" FLAG_RESOURCE_FOG_STARTEND, G_CALLBACK(onEntryFogStartEnd), (gpointer)ext, G_CONNECT_SWAPPED); if (!defaultSet) defaultSet = ext; } /* This method can be called several times. It should unref all of its reference to GObjects. */ static void visu_gl_ext_set_dispose(GObject* obj) { VisuGlExtSet *ext; guint i; struct _GlExt *s; gchar *name; DBG_fprintf(stderr, "Visu Extension Set: dispose object %p.\n", (gpointer)obj); ext = VISU_GL_EXT_SET(obj); if (ext->priv->dispose_has_run) return; ext->priv->dispose_has_run = TRUE; visu_gl_ext_set_setGlView(ext, (VisuGlView*)0); DBG_fprintf(stderr, "Visu Extension Set: releasing %d extensions.\n", ext->priv->set->len); for (i = 0; i < ext->priv->set->len; i++) { s = &g_array_index(ext->priv->set, struct _GlExt, i); if (DEBUG) { DBG_fprintf(stderr, "Visu Extension Set: releasing extension %p.\n", (gpointer)s->ext); g_object_get(s->ext, "name", &name, NULL); DBG_fprintf(stderr, " | %s (%d)\n", name, G_OBJECT(s->ext)->ref_count); g_free(name); } g_signal_handler_disconnect(G_OBJECT(s->ext), s->priority_sig); g_signal_handler_disconnect(G_OBJECT(s->ext), s->dirty_sig); g_signal_handler_disconnect(G_OBJECT(s->ext), s->active_sig); g_object_unref(G_OBJECT(s->ext)); } /* Chain up to the parent class */ G_OBJECT_CLASS(visu_gl_ext_set_parent_class)->dispose(obj); } /* This method is called once only. */ static void visu_gl_ext_set_finalize(GObject* obj) { VisuGlExtSetPrivate *ext; g_return_if_fail(obj); DBG_fprintf(stderr, "Visu Extension Set: finalize object %p.\n", (gpointer)obj); ext = VISU_GL_EXT_SET(obj)->priv; if (ext->dirtyPending) g_source_remove(ext->dirtyPending); g_array_free(ext->set, TRUE); glDeleteLists(ext->chessList, 1); /* Chain up to the parent class */ DBG_fprintf(stderr, "Visu Extension Set: chain to parent.\n"); G_OBJECT_CLASS(visu_gl_ext_set_parent_class)->finalize(obj); DBG_fprintf(stderr, "Visu Extension Set: freeing ... OK.\n"); } static void visu_gl_ext_set_get_property(GObject* obj, guint property_id, GValue *value, GParamSpec *pspec) { VisuGlExtSet *self = VISU_GL_EXT_SET(obj); DBG_fprintf(stderr, "Visu Extension Set: get property '%s' -> ", g_param_spec_get_name(pspec)); switch (property_id) { case DIRTY_PROP: g_value_set_boolean(value, (self->priv->dirtyPending > 0)); DBG_fprintf(stderr, "%d.\n", (self->priv->dirtyPending > 0)); break; case BG_R_PROP: g_value_set_float(value, self->priv->bgRGB[0]); DBG_fprintf(stderr, "%g.\n", self->priv->bgRGB[0]); break; case BG_G_PROP: g_value_set_float(value, self->priv->bgRGB[1]); DBG_fprintf(stderr, "%g.\n", self->priv->bgRGB[1]); break; case BG_B_PROP: g_value_set_float(value, self->priv->bgRGB[2]); DBG_fprintf(stderr, "%g.\n", self->priv->bgRGB[2]); break; case BG_A_PROP: g_value_set_float(value, self->priv->bgRGB[3]); DBG_fprintf(stderr, "%g.\n", self->priv->bgRGB[3]); break; case FOG_ACTIVE_PROP: g_value_set_boolean(value, self->priv->fogActive); DBG_fprintf(stderr, "%d.\n", self->priv->fogActive); break; case FOG_START_PROP: g_value_set_float(value, self->priv->fogStartEnd[0]); DBG_fprintf(stderr, "%g.\n", self->priv->fogStartEnd[0]); break; case FOG_FULL_PROP: g_value_set_float(value, self->priv->fogStartEnd[1]); DBG_fprintf(stderr, "%g.\n", self->priv->fogStartEnd[1]); break; case FOG_FOLLOWS_PROP: g_value_set_boolean(value, self->priv->fogFollowsBg); DBG_fprintf(stderr, "%d.\n", self->priv->fogFollowsBg); break; case FOG_R_PROP: g_value_set_float(value, self->priv->fogRGB[0]); DBG_fprintf(stderr, "%g.\n", self->priv->fogRGB[0]); break; case FOG_G_PROP: g_value_set_float(value, self->priv->fogRGB[1]); DBG_fprintf(stderr, "%g.\n", self->priv->fogRGB[1]); break; case FOG_B_PROP: g_value_set_float(value, self->priv->fogRGB[2]); DBG_fprintf(stderr, "%g.\n", self->priv->fogRGB[2]); break; case FOG_A_PROP: g_value_set_float(value, self->priv->fogRGB[3]); DBG_fprintf(stderr, "%g.\n", self->priv->fogRGB[3]); break; default: /* We don't have any other property... */ G_OBJECT_WARN_INVALID_PROPERTY_ID(obj, property_id, pspec); break; } } static void visu_gl_ext_set_set_property(GObject* obj, guint property_id, const GValue *value, GParamSpec *pspec) { VisuGlExtSet *self = VISU_GL_EXT_SET(obj); float rgba[4], startEnd[2]; DBG_fprintf(stderr, "Visu Extension Set: set property '%s' -> ", g_param_spec_get_name(pspec)); switch (property_id) { case BG_R_PROP: rgba[0] = g_value_get_float(value); visu_gl_ext_set_setBgColor(self, rgba, TOOL_COLOR_MASK_R); DBG_fprintf(stderr, "%g.\n", self->priv->bgRGB[0]); break; case BG_G_PROP: rgba[1] = g_value_get_float(value); visu_gl_ext_set_setBgColor(self, rgba, TOOL_COLOR_MASK_G); DBG_fprintf(stderr, "%g.\n", self->priv->bgRGB[1]); break; case BG_B_PROP: rgba[2] = g_value_get_float(value); visu_gl_ext_set_setBgColor(self, rgba, TOOL_COLOR_MASK_B); DBG_fprintf(stderr, "%g.\n", self->priv->bgRGB[2]); break; case BG_A_PROP: rgba[3] = g_value_get_float(value); visu_gl_ext_set_setBgColor(self, rgba, TOOL_COLOR_MASK_A); DBG_fprintf(stderr, "%g.\n", self->priv->bgRGB[3]); break; case FOG_ACTIVE_PROP: visu_gl_ext_set_setFogActive(self, g_value_get_boolean(value)); DBG_fprintf(stderr, "%d.\n", self->priv->fogActive); break; case FOG_START_PROP: startEnd[0] = g_value_get_float(value); visu_gl_ext_set_setFogStartFull(self, startEnd, VISU_GL_EXT_SET_FOG_MASK_START); DBG_fprintf(stderr, "%g.\n", self->priv->fogStartEnd[0]); break; case FOG_FULL_PROP: startEnd[1] = g_value_get_float(value); visu_gl_ext_set_setFogStartFull(self, startEnd, VISU_GL_EXT_SET_FOG_MASK_FULL); DBG_fprintf(stderr, "%g.\n", self->priv->fogStartEnd[1]); break; case FOG_FOLLOWS_PROP: visu_gl_ext_set_setFogFollowsBg(self, g_value_get_boolean(value)); DBG_fprintf(stderr, "%d.\n", self->priv->fogFollowsBg); break; case FOG_R_PROP: rgba[0] = g_value_get_float(value); visu_gl_ext_set_setFogColor(self, rgba, TOOL_COLOR_MASK_R); DBG_fprintf(stderr, "%g.\n", self->priv->fogRGB[0]); break; case FOG_G_PROP: rgba[1] = g_value_get_float(value); visu_gl_ext_set_setFogColor(self, rgba, TOOL_COLOR_MASK_G); DBG_fprintf(stderr, "%g.\n", self->priv->fogRGB[1]); break; case FOG_B_PROP: rgba[2] = g_value_get_float(value); visu_gl_ext_set_setFogColor(self, rgba, TOOL_COLOR_MASK_B); DBG_fprintf(stderr, "%g.\n", self->priv->fogRGB[2]); break; case FOG_A_PROP: rgba[3] = g_value_get_float(value); visu_gl_ext_set_setFogColor(self, rgba, TOOL_COLOR_MASK_A); DBG_fprintf(stderr, "%g.\n", self->priv->fogRGB[3]); break; default: /* We don't have any other property... */ G_OBJECT_WARN_INVALID_PROPERTY_ID(obj, property_id, pspec); break; } } static void visu_gl_ext_initContext(VisuGl *gl) { VisuGlExtSet *self = VISU_GL_EXT_SET(gl); guint i; g_return_if_fail(VISU_IS_GL_EXT_SET(self)); VISU_GL_CLASS(visu_gl_ext_set_parent_class)->initContext(gl); if (self->priv->view) visu_gl_view_initContext(self->priv->view); for (i = 0; i < self->priv->set->len; i++) visu_gl_ext_rebuild(g_array_index(self->priv->set, struct _GlExt, i).ext); } /** * visu_gl_ext_set_new: * * Create an object to handle a set of #VisuGlExt objects and draw * them together. * * Since: 3.8 * * Returns: (transfer full): a newly created #VisuGlExtSet object. **/ VisuGlExtSet* visu_gl_ext_set_new() { VisuGlExtSet *set; set = VISU_GL_EXT_SET(g_object_new(VISU_TYPE_GL_EXT_SET, NULL)); return set; } /** * visu_gl_ext_set_setGlView: * @set: a #VisuGlExtSet object. * @view: a #VisuGlView object. * * Apply the given @view on all #VisuGlExt objects stored in @set. * * Since: 3.8 * * Returns: TRUE if the @view actually change. **/ gboolean visu_gl_ext_set_setGlView(VisuGlExtSet *set, VisuGlView *view) { guint i; g_return_val_if_fail(VISU_IS_GL_EXT_SET(set), FALSE); if (set->priv->view == view) return FALSE; if (set->priv->view) { g_object_unref(G_OBJECT(set->priv->view)); g_signal_handler_disconnect(G_OBJECT(set->priv->view), set->priv->widthHeight_signal); g_signal_handler_disconnect(G_OBJECT(set->priv->view), set->priv->chg_signal); } if (view) { g_object_ref(G_OBJECT(view)); set->priv->widthHeight_signal = g_signal_connect(G_OBJECT(view), "WidthHeightChanged", G_CALLBACK(onWidthHeight), (gpointer)set); set->priv->chg_signal = g_signal_connect(G_OBJECT(view), "changed", G_CALLBACK(onCamera), (gpointer)set); } set->priv->view = view; for (i = 0; i < set->priv->set->len; i++) visu_gl_ext_setGlView(g_array_index(set->priv->set, struct _GlExt, i).ext, view); return TRUE; } /** * visu_gl_ext_set_getAll: * @set: a #VisuGlExtSet object. * * Retrieve as a #GList all the #VisuGlExt objects drawn by @set. * * Since: 3.8 * * Returns: (transfer container) (element-type VisuGlExt*): only the * container list should be freed after. **/ GList* visu_gl_ext_set_getAll(VisuGlExtSet *set) { GList *lst; guint i; g_return_val_if_fail(VISU_IS_GL_EXT_SET(set), (GList*)0); lst = (GList*)0; for (i = 0; i < set->priv->set->len; i++) lst = g_list_append(lst, g_array_index(set->priv->set, struct _GlExt, i).ext); return lst; } /** * visu_gl_ext_set_getByName: * @set: a #VisuGlExtSet object. * @name: a name to look for. * * Retrieve the #VisuGlExt object with @name that is stored in * @set. If several #VisuGlExt objects have the same name, the first * one is returned. * * Since: 3.8 * * Returns: (transfer none): a #VisuGlExt with @name. **/ VisuGlExt* visu_gl_ext_set_getByName(const VisuGlExtSet *set, const gchar *name) { guint i; g_return_val_if_fail(VISU_IS_GL_EXT_SET(set), (VisuGlExt*)0); for (i = 0; i < set->priv->set->len; i++) if (!strcmp(visu_gl_ext_getName(g_array_index(set->priv->set, struct _GlExt, i).ext), name)) return g_array_index(set->priv->set, struct _GlExt, i).ext; return (VisuGlExt*)0; } static gboolean _emitDirty(gpointer data) { /* if (!VISU_GL_EXT_SET(data)->priv->dirty) */ /* return FALSE; */ g_object_notify_by_pspec(G_OBJECT(data), properties[DIRTY_PROP]); VISU_GL_EXT_SET(data)->priv->dirtyPending = 0; return FALSE; } static void _appendDirty(VisuGlExtSet *set) { /* if (set->priv->dirtyPending) */ /* g_source_remove(set->priv->dirtyPending); */ set->priv->dirty = TRUE; if (!set->priv->dirtyPending) set->priv->dirtyPending = g_idle_add_full(G_PRIORITY_HIGH_IDLE, _emitDirty, (gpointer)set, (GDestroyNotify)0); } static void onExtPriority(VisuGlExtSet *set) { set->priv->reorderingNeeded = TRUE; } static void onExtDirty(VisuGlExtSet *set, GParamSpec *pspec _U_, VisuGlExt *ext) { if (!visu_gl_ext_getActive(ext)) return; DBG_fprintf(stderr, "Visu Extension Set: extension '%s' is dirty.\n", visu_gl_ext_getName(ext)); _appendDirty(set); } /** * visu_gl_ext_set_add: * @set: a #VisuGlExtSet object. * @ext: a #VisuGlExt object. * * Add @ext in the list of drawn #VisuGlExt by @set. * * Since: 3.8 * * Returns: TRUE if not already existing. **/ gboolean visu_gl_ext_set_add(VisuGlExtSet *set, VisuGlExt *ext) { struct _GlExt s; guint i; g_return_val_if_fail(VISU_IS_GL_EXT_SET(set), FALSE); /* Lookup first for ext in the set. */ for (i = 0; i < set->priv->set->len; i++) if (g_array_index(set->priv->set, struct _GlExt, i).ext == ext) return FALSE; g_object_ref(G_OBJECT(ext)); s.ext = ext; s.priority_sig = g_signal_connect_swapped(G_OBJECT(ext), "notify::priority", G_CALLBACK(onExtPriority), set); s.dirty_sig = g_signal_connect_swapped(G_OBJECT(ext), "notify::dirty", G_CALLBACK(onExtDirty), set); s.active_sig = g_signal_connect_swapped(G_OBJECT(ext), "notify::active", G_CALLBACK(_appendDirty), set); if (set->priv->view) visu_gl_ext_setGlView(ext, set->priv->view); visu_gl_ext_setGlContext(ext, VISU_GL(set)); set->priv->reorderingNeeded = TRUE; g_array_append_val(set->priv->set, s); if (VISU_GL_EXT_SET_GET_CLASS(set)->added) VISU_GL_EXT_SET_GET_CLASS(set)->added(set, ext); onExtDirty(set, NULL, ext); return TRUE; } /** * visu_gl_ext_set_remove: * @set: a #VisuGlExtSet object. * @ext: a #VisuGlExt object. * * Remove @ext in the list of drawn #VisuGlExt by @set. * * Since: 3.8 * * Returns: TRUE if successfully removed. **/ gboolean visu_gl_ext_set_remove(VisuGlExtSet *set, VisuGlExt *ext) { struct _GlExt *s; guint i; gboolean dirty; g_return_val_if_fail(VISU_IS_GL_EXT_SET(set), FALSE); for (i = 0; i < set->priv->set->len; i++) { s = &g_array_index(set->priv->set, struct _GlExt, i); if (s->ext == ext) { dirty = visu_gl_ext_getActive(s->ext); g_signal_handler_disconnect(G_OBJECT(s->ext), s->priority_sig); g_signal_handler_disconnect(G_OBJECT(s->ext), s->dirty_sig); g_signal_handler_disconnect(G_OBJECT(s->ext), s->active_sig); g_object_unref(s->ext); g_array_remove_index(set->priv->set, i); if (dirty) _appendDirty(set); if (VISU_GL_EXT_SET_GET_CLASS(set)->removed) VISU_GL_EXT_SET_GET_CLASS(set)->removed(set, ext); return TRUE; } } return FALSE; } static gint compareExtensionPriority(gconstpointer a, gconstpointer b) { guint pa = visu_gl_ext_getPriority(((struct _GlExt*)a)->ext); guint pb = visu_gl_ext_getPriority(((struct _GlExt*)b)->ext); if (pa < pb) return (gint)-1; else if (pa > pb) return (gint)+1; else return (gint)0; } static void mayReorder(VisuGlExtSet *set) { if (set->priv->reorderingNeeded) { DBG_fprintf(stderr, "Visu Extension Set: sorting known extension" " depending on their priority.\n"); g_array_sort(set->priv->set, compareExtensionPriority); set->priv->reorderingNeeded = FALSE; } } /** * visu_gl_ext_set_draw: * @set: a #VisuGlExtSet object. * * Basic drawing method : it clears the OpenGL area and call all lists * stored in @set. * * Since: 3.8 */ void visu_gl_ext_set_draw(VisuGlExtSet *set) { int i_stereo, stereo; guint i; static int stereo_buf[2] = {GL_BACK_LEFT, GL_BACK_RIGHT}; GLboolean glStereo; float centre[3]; VisuBox *box; float start, stop, bSize, fogCentre; #if DEBUG == 1 GTimer *timer; gulong fractionTimer; #endif g_return_if_fail(VISU_IS_GL_EXT_SET(set) && set->priv->view); #if DEBUG == 1 timer = g_timer_new(); g_timer_start(timer); #endif mayReorder(set); box = visu_boxed_getBox(VISU_BOXED(set->priv->view)); if (box) visu_box_getCentre(box, centre); else { centre[0] = 0.f; centre[1] = 0.f; centre[2] = 0.f; } _chessDraw(set); glClearColor(set->priv->bgRGB[0], set->priv->bgRGB[1], set->priv->bgRGB[2], set->priv->bgRGB[3]); if (set->priv->fogActive && set->priv->view && visu_boxed_getBox(VISU_BOXED(set->priv->view))) { glEnable(GL_FOG); glFogi(GL_FOG_MODE, GL_LINEAR); /* glFogi(GL_FOG_MODE, GL_EXP); */ /* glFogf(GL_FOG_DENSITY, 0.03f); */ if (set->priv->fogFollowsBg) glFogfv(GL_FOG_COLOR, set->priv->bgRGB); else glFogfv(GL_FOG_COLOR, set->priv->fogRGB); bSize = visu_box_getGlobalSize(visu_boxed_getBox(VISU_BOXED(set->priv->view)), FALSE); fogCentre = ((set->priv->view->camera.d_red > 100.f) ? 100.f : set->priv->view->camera.d_red) * set->priv->view->camera.length0; start = fogCentre - bSize + 2.f * bSize * set->priv->fogStartEnd[0]; stop = fogCentre - bSize + 2.f * bSize * set->priv->fogStartEnd[1]; /* start = visuBox->extens * visuCamera->d_red * (1. - fog_start); */ /* stop = visuBox->extens * visuCamera->d_red * (1. + fog_end); */ /* start = visuBox->extens * visuCamera->d_red * (1. - 1 / 1.1); */ /* stop = visuBox->extens * visuCamera->d_red * (1. + 1 / 1.1); */ /* fprintf(stderr, "----------> %f %f %f %f\n", (float)(view->window->near + */ /* (view->window->far - view->window->near) * fog_start), (float)(view->window->near + */ /* (view->window->far - view->window->near) * fog_end), start, stop); */ glFogf(GL_FOG_START, start); glFogf(GL_FOG_END, stop); } else glDisable(GL_FOG); glGetBooleanv(GL_STEREO, &glStereo); stereo = (set->priv->view && glStereo && visu_gl_getStereo(VISU_GL(set))) ? 1 : 0; for(i_stereo = 0; i_stereo <= stereo; i_stereo++) { if (stereo == 1) { glRotatef(visu_gl_getStereoAngle(VISU_GL(set)) * (2.f * i_stereo - 1.f), set->priv->view->camera.up[0], set->priv->view->camera.up[1], set->priv->view->camera.up[2]); glDrawBuffer(stereo_buf[i_stereo]); DBG_fprintf(stderr, "Visu Extension Set: draw on buffer %d.\n", i_stereo); } else glDrawBuffer(GL_BACK); glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT); glPushAttrib(GL_ENABLE_BIT); glCallList(set->priv->chessList); glPopAttrib(); glPushMatrix(); glTranslated(-centre[0], -centre[1], -centre[2]); glEnable(GL_DEPTH_TEST); /* if (!lists && !trueTransparency) */ /* { */ /* visu_gl_ext_callAll(FALSE); */ /* visu_gl_ext_callAll(TRUE); */ /* } */ /* else if (!lists && trueTransparency) */ /* { */ /* glDepthMask(1); */ /* glEnable(GL_ALPHA_TEST); */ /* glAlphaFunc(GL_EQUAL, 1.); */ /* visu_gl_ext_callAll(FALSE); */ /* DBG_fprintf(stderr, "OpenGL: second pass for transparency.\n"); */ /* glAlphaFunc(GL_LESS, 1.); */ /* glDepthMask(0); */ /* visu_gl_ext_callAll(FALSE); */ /* glDepthMask(1); */ /* glAlphaFunc(GL_ALWAYS, 1.); */ /* glDisable(GL_ALPHA_TEST); */ /* visu_gl_ext_callAll(TRUE); */ /* } */ /* else */ if (!visu_gl_getTrueTransparency(VISU_GL(set))) for (i = 0; i < set->priv->set->len; i++) visu_gl_ext_call(g_array_index(set->priv->set, struct _GlExt, i).ext, FALSE); else { glDepthMask(1); glEnable(GL_ALPHA_TEST); glAlphaFunc(GL_EQUAL, 1.); for (i = 0; i < set->priv->set->len; i++) visu_gl_ext_call(g_array_index(set->priv->set, struct _GlExt, i).ext, FALSE); DBG_fprintf(stderr, "Visu Extension Set: second pass for transparency.\n"); glAlphaFunc(GL_LESS, 1.); glDepthMask(0); for (i = 0; i < set->priv->set->len; i++) visu_gl_ext_call(g_array_index(set->priv->set, struct _GlExt, i).ext, FALSE); glDepthMask(1); glAlphaFunc(GL_ALWAYS, 1.); glDisable(GL_ALPHA_TEST); } for (i = 0; i < set->priv->set->len; i++) visu_gl_ext_call(g_array_index(set->priv->set, struct _GlExt, i).ext, TRUE); glPopMatrix(); } set->priv->dirty = FALSE; #if DEBUG == 1 glFlush(); g_timer_stop(timer); fprintf(stderr, "Visu Extension Set: lists drawn in %g micro-s.\n", g_timer_elapsed(timer, &fractionTimer)*1e6); g_timer_destroy(timer); #endif } /** * visu_gl_ext_set_setBgColor: * @set: a #VisuGlExtSet object. * @rgba: (in) (array fixed-size=4): a three floats array with values * (0 <= values <= 1) for the red, the green and the blue color. Only * values specified by the mask are really relevant. * @mask: use #TOOL_COLOR_MASK_R, #TOOL_COLOR_MASK_G, * #TOOL_COLOR_MASK_B, #TOOL_COLOR_MASK_RGBA or a combinaison to * indicate what values in the rgb array must be taken into account. * * Method used to change the value of the parameter background_color. * * Since: 3.8 * * Returns: TRUE if changed. */ gboolean visu_gl_ext_set_setBgColor(VisuGlExtSet *set, float rgba[4], int mask) { g_return_val_if_fail(VISU_IS_GL_EXT_SET(set), FALSE); g_object_freeze_notify(G_OBJECT(set)); if (mask & TOOL_COLOR_MASK_R && set->priv->bgRGB[0] != rgba[0]) { set->priv->bgRGB[0] = CLAMP(rgba[0], 0.f, 1.f); g_object_notify_by_pspec(G_OBJECT(set), properties[BG_R_PROP]); set->priv->bgDirty = TRUE; } if (mask & TOOL_COLOR_MASK_G && set->priv->bgRGB[1] != rgba[1]) { set->priv->bgRGB[1] = CLAMP(rgba[1], 0.f, 1.f); g_object_notify_by_pspec(G_OBJECT(set), properties[BG_G_PROP]); set->priv->bgDirty = TRUE; } if (mask & TOOL_COLOR_MASK_B && set->priv->bgRGB[2] != rgba[2]) { set->priv->bgRGB[2] = CLAMP(rgba[2], 0.f, 1.f); g_object_notify_by_pspec(G_OBJECT(set), properties[BG_B_PROP]); set->priv->bgDirty = TRUE; } if (mask & TOOL_COLOR_MASK_A && set->priv->bgRGB[3] != rgba[3]) { set->priv->bgRGB[3] = CLAMP(rgba[3], 0.f, 1.f); g_object_notify_by_pspec(G_OBJECT(set), properties[BG_A_PROP]); set->priv->bgDirty = TRUE; } g_object_thaw_notify(G_OBJECT(set)); if (set->priv->bgDirty) _appendDirty(set); return set->priv->bgDirty; } /** * visu_gl_ext_set_getBgColor: * @set: a #VisuGlExtSet object. * @rgba: (array fixed-size=4) (out): a storage for four values. * * Read the RGBA value of the specific background colour (in [0;1]). * * Since: 3.8 */ void visu_gl_ext_set_getBgColor(const VisuGlExtSet *set, float rgba[4]) { g_return_if_fail(VISU_IS_GL_EXT_SET(set)); memcpy(rgba, set->priv->bgRGB, sizeof(float) * 4); } static void _chessDraw(VisuGlExtSet *set) { GLubyte chessboard[32][32][3]; int viewport[4]; int i, j, c; if (!set->priv->bgDirty) return; if (set->priv->bgRGB[3] < 1.f && !(visu_gl_getHint(VISU_GL(set)) & VISU_GL_OFFSCREEN)) { DBG_fprintf(stderr, "Visu Extension Set: set background chess board (alpha = %g).\n", set->priv->bgRGB[3]); if (texName == 0) glGenTextures(1, &texName); /* We create the chessboard texture with the right colour. */ for (i = 0; i < 32; i++) for (j = 0; j < 32; j++) { c = 128 + ( ((i&0x10)==0) ^ ((j&0x10) == 0) ) * 64; chessboard[i][j][0] = (GLubyte)(255.f * set->priv->bgRGB[0] * set->priv->bgRGB[3] + (1.f - set->priv->bgRGB[3]) * c); chessboard[i][j][1] = (GLubyte)(255.f * set->priv->bgRGB[1] * set->priv->bgRGB[3] + (1.f - set->priv->bgRGB[3]) * c); chessboard[i][j][2] = (GLubyte)(255.f * set->priv->bgRGB[2] * set->priv->bgRGB[3] + (1.f - set->priv->bgRGB[3]) * c); } /* We bind the texture. */ glBindTexture(GL_TEXTURE_2D, texName); glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_REPEAT); glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_REPEAT); glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST); glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST); glPixelStorei(GL_UNPACK_ALIGNMENT, 1); glTexImage2D(GL_TEXTURE_2D, 0, GL_RGB, 32, 32, 0, GL_RGB, GL_UNSIGNED_BYTE, chessboard); glGetIntegerv(GL_VIEWPORT, viewport); glNewList(set->priv->chessList, GL_COMPILE); glDisable(GL_CULL_FACE); glDisable(GL_LIGHTING); glEnable(GL_TEXTURE_2D); glTexEnvf(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_DECAL); glBindTexture(GL_TEXTURE_2D, texName); glMatrixMode(GL_PROJECTION); glPushMatrix(); glLoadIdentity(); gluOrtho2D(0., (float)viewport[2], 0., (float)viewport[3]); glMatrixMode(GL_MODELVIEW); glPushMatrix(); glLoadIdentity(); glDepthMask(0); glBegin(GL_QUADS); glTexCoord2f(0.0, 0.0); glVertex3f(0.0, 0.0, 0.0); glTexCoord2f(0.0, (float)viewport[3] / 32.f); glVertex3f(0.0, (float)viewport[3], 0.0); glTexCoord2f((float)viewport[2] / 32.f, (float)viewport[3] / 32.f); glVertex3f((float)viewport[2], (float)viewport[3], 0.0); glTexCoord2f((float)viewport[2] / 32.f, 0.0); glVertex3f((float)viewport[2], 0.0, 0.0); glEnd(); glDepthMask(1); glPopMatrix(); glMatrixMode(GL_PROJECTION); glPopMatrix(); glMatrixMode(GL_MODELVIEW); glDisable(GL_TEXTURE_2D); glEndList(); } else glDeleteLists(set->priv->chessList, 1); set->priv->bgDirty = FALSE; } /** * visu_gl_ext_set_setFogColor: * @set: a #VisuGlExtSet object. * @rgba: (array fixed-size=4): four [0;1] float values. * @mask: a mask, see %TOOL_COLOR_MASK_R for instance. * * Change the fog specific colour. Activate it with * visu_gl_ext_set_setFogFollowsBg(). * * Since: 3.8 * * Returns: TRUE if value is actually changed. **/ gboolean visu_gl_ext_set_setFogColor(VisuGlExtSet *set, float rgba[4], int mask) { gboolean diff; g_return_val_if_fail(VISU_IS_GL_EXT_SET(set), FALSE); diff = FALSE; g_object_freeze_notify(G_OBJECT(set)); if (mask & TOOL_COLOR_MASK_R && set->priv->fogRGB[0] != rgba[0]) { set->priv->fogRGB[0] = CLAMP(rgba[0], 0.f, 1.f); g_object_notify_by_pspec(G_OBJECT(set), properties[FOG_R_PROP]); diff = TRUE; } if (mask & TOOL_COLOR_MASK_G && set->priv->fogRGB[1] != rgba[1]) { set->priv->fogRGB[1] = CLAMP(rgba[1], 0.f, 1.f); g_object_notify_by_pspec(G_OBJECT(set), properties[FOG_G_PROP]); diff = TRUE; } if (mask & TOOL_COLOR_MASK_B && set->priv->fogRGB[2] != rgba[2]) { set->priv->fogRGB[2] = CLAMP(rgba[2], 0.f, 1.f); g_object_notify_by_pspec(G_OBJECT(set), properties[FOG_B_PROP]); diff = TRUE; } if (mask & TOOL_COLOR_MASK_A && set->priv->fogRGB[3] != rgba[3]) { set->priv->fogRGB[3] = CLAMP(rgba[3], 0.f, 1.f); g_object_notify_by_pspec(G_OBJECT(set), properties[FOG_A_PROP]); diff = TRUE; } g_object_thaw_notify(G_OBJECT(set)); if (diff && set->priv->fogActive) _appendDirty(set); return diff; } /** * visu_gl_ext_set_setFogActive: * @set: a #VisuGlExtSet object. * @value: a boolean. * * Activates the fog rendering, or not. * * Since: 3.8 * * Returns: TRUE if value is actually changed. **/ gboolean visu_gl_ext_set_setFogActive(VisuGlExtSet *set, gboolean value) { g_return_val_if_fail(VISU_IS_GL_EXT_SET(set), FALSE); if (set->priv->fogActive == value) return FALSE; set->priv->fogActive = value; g_object_notify_by_pspec(G_OBJECT(set), properties[FOG_ACTIVE_PROP]); _appendDirty(set); return TRUE; } /** * visu_gl_ext_set_setFogFollowsBg: * @set: a #VisuGlExtSet object. * @value: a boolean. * * Specifies if the fog is coloured with the background colour or with * its own colour, see visu_gl_ext_set_setFogColor(). * * Since: 3.8 * * Returns: TRUE if value is actually changed. **/ gboolean visu_gl_ext_set_setFogFollowsBg(VisuGlExtSet *set, gboolean value) { g_return_val_if_fail(VISU_IS_GL_EXT_SET(set), FALSE); if (set->priv->fogFollowsBg == value) return FALSE; set->priv->fogFollowsBg = value; g_object_notify_by_pspec(G_OBJECT(set), properties[FOG_FOLLOWS_PROP]); if (set->priv->fogActive) _appendDirty(set); return TRUE; } /** * visu_gl_ext_set_setFogStartFull: * @set: a #VisuGlExtSet object. * @startEnd: (array fixed-size=2): two [0;1] floating point values. * @mask: a mask, see %VISU_GL_EXT_SET_FOG_MASK_START and * %VISU_GL_EXT_SET_FOG_MASK_FULL. * * Change the starting and ending point of fog. * * Since: 3.8 * * Returns: TRUE if values are actually changed. **/ gboolean visu_gl_ext_set_setFogStartFull(VisuGlExtSet *set, float startEnd[2], int mask) { gboolean diff; g_return_val_if_fail(VISU_IS_GL_EXT_SET(set), FALSE); diff = FALSE; g_object_freeze_notify(G_OBJECT(set)); if (mask & VISU_GL_EXT_SET_FOG_MASK_START && set->priv->fogStartEnd[0] != startEnd[0]) { set->priv->fogStartEnd[0] = CLAMP(startEnd[0], 0.f, 1.f); if (mask & VISU_GL_EXT_SET_FOG_MASK_FULL) { if (set->priv->fogStartEnd[0] >= startEnd[1]) set->priv->fogStartEnd[0] = startEnd[1] - 0.001; } else if (set->priv->fogStartEnd[0] >= set->priv->fogStartEnd[1]) set->priv->fogStartEnd[0] = set->priv->fogStartEnd[1] - 0.001; g_object_notify_by_pspec(G_OBJECT(set), properties[FOG_START_PROP]); diff = TRUE; } if (mask & VISU_GL_EXT_SET_FOG_MASK_FULL && set->priv->fogStartEnd[1] != startEnd[1]) { set->priv->fogStartEnd[1] = CLAMP(startEnd[1], 0.f, 1.f); if (set->priv->fogStartEnd[1] <= set->priv->fogStartEnd[0]) set->priv->fogStartEnd[1] = set->priv->fogStartEnd[0] + 0.001; g_object_notify_by_pspec(G_OBJECT(set), properties[FOG_FULL_PROP]); diff = TRUE; } g_object_thaw_notify(G_OBJECT(set)); if (diff && set->priv->fogActive) _appendDirty(set); return diff; } /** * visu_gl_ext_set_getFogColor: * @set: a #VisuGlExtSet object. * @rgba: (out) (array fixed-size=4): a storage for three values. * * Gives the actual fog color, for the specific color, use * visu_gl_ext_set_getFogSpecificColor(). * * Since: 3.8 */ void visu_gl_ext_set_getFogColor(VisuGlExtSet *set, float rgba[4]) { g_return_if_fail(VISU_IS_GL_EXT_SET(set)); if (set->priv->fogFollowsBg) memcpy(rgba, set->priv->bgRGB, sizeof(float) * 4); else memcpy(rgba, set->priv->fogRGB, sizeof(float) * 4); } /** * visu_gl_ext_set_getFogSpecificColor: * @set: a #VisuGlExtSet object. * @rgba: (out) (array fixed-size=4): a storage for three values. * * Gives the specific fog color, for the actual color, use * visu_gl_ext_set_getFogColor(). * * Since: 3.8 */ void visu_gl_ext_set_getFogSpecificColor(VisuGlExtSet *set, float rgba[4]) { g_return_if_fail(VISU_IS_GL_EXT_SET(set)); memcpy(rgba, set->priv->fogRGB, sizeof(float) * 4); } /** * visu_gl_ext_set_getFogActive: * @set: a #VisuGlExtSet object. * * Read if fog is used or not. * * Since: 3.8 * * Returns: TRUE if the fog is rendered, FALSE otherwise. */ gboolean visu_gl_ext_set_getFogActive(VisuGlExtSet *set) { g_return_val_if_fail(VISU_IS_GL_EXT_SET(set), FALSE); return set->priv->fogActive; } /** * visu_gl_ext_set_getFogFollowsBg: * @set: a #VisuGlExtSet object. * * Read if fog uses a specific colour or not. * * Since: 3.8 * * Returns: TRUE if the fog uses its own color or FALSE if it uses * the color of the background. */ gboolean visu_gl_ext_set_getFogFollowsBg(VisuGlExtSet *set) { g_return_val_if_fail(VISU_IS_GL_EXT_SET(set), FALSE); return set->priv->fogFollowsBg; } /** * visu_gl_ext_set_getFogStartFull: * @set: a #VisuGlExtSet object. * @startFull: (out caller-allocates) (array fixed-size=2): two float * location. * * Retrieves the starting and ending value (reduced) of fog extension. * * Since: 3.8 **/ void visu_gl_ext_set_getFogStartFull(VisuGlExtSet *set, float startFull[2]) { g_return_if_fail(VISU_IS_GL_EXT_SET(set)); memcpy(startFull, set->priv->fogStartEnd, sizeof(float) * 2); } /** * visu_gl_ext_set_getPixmapData: * @set: a #VisuGlExtSet object ; * @width: the desired width or 0 for current ; * @height: the desired height or 0 for current ; * @hasAlpha: if TRUE, the returned data is RGBA, else only RGB. * * Create an image from the OpenGL area. The size can be changed, using @width and * @height. If these pointers contains positive values, then they are used to set the * size for the image. If not, the size of the current #VisuGlView is used and * stored in these pointers. * * Since: 3.8 * * Returns: (transfer full) (element-type int): image data, row by row. */ GArray* visu_gl_ext_set_getPixmapData(VisuGlExtSet *set, guint width, guint height, gboolean hasAlpha) { GArray *image; VisuPixmapContext *dumpData; guint row_length; gint m, n1, n2; guchar *row_tab; guint oldW, oldH; g_return_val_if_fail(VISU_IS_GL_EXT_SET(set), (GArray*)0); g_return_val_if_fail(VISU_IS_GL_VIEW(set->priv->view), (GArray*)0); /* We may change the actual drawing size. */ width = (width > 0) ? width : set->priv->view->window.width; height = (height > 0) ? height : set->priv->view->window.height; oldW = set->priv->view->window.width; oldH = set->priv->view->window.height; visu_gl_view_setViewport(set->priv->view, width, height); /* We create a pixmap context and make this context current. */ dumpData = visu_pixmap_context_new(width, height); if (!dumpData) { g_warning("can't create off-screen pixmap."); return (GArray*)0; } /* We set the glViewport of this new context. */ visu_gl_initContext(VISU_GL(set)); /* We call the given draw method. */ visu_gl_ext_set_draw(set); /* We copy the pixmap into generic data. */ if (hasAlpha) row_length = 4 * width; else row_length = 3 * width; row_tab = g_malloc(sizeof(guchar) * row_length); image = g_array_sized_new(FALSE, FALSE, sizeof(guchar), row_length * height); glPixelStorei(GL_PACK_ALIGNMENT, 1); /* just in case */ /* Copy the image into our buffer */ n2 = 0; for(m = height - 1; m >= 0; m--) { if (hasAlpha) glReadPixels(0, m, width, 1, GL_RGBA, GL_UNSIGNED_BYTE, row_tab); else glReadPixels(0, m, width, 1, GL_RGB, GL_UNSIGNED_BYTE, row_tab); n1 = n2; n2 = n1 + row_length; image = g_array_insert_vals(image, n1, row_tab, n2 - n1); } g_free(row_tab); DBG_fprintf(stderr, " | save to array %p.\n", (gpointer)image); /* We free the pixmap context. */ visu_pixmap_context_free(dumpData); /* We put back the viewport. */ visu_gl_view_setViewport(set->priv->view, oldW, oldH); return image; } /***************************/ /* Dealing with parameters */ /***************************/ static void onEntryBgColor(VisuGlExtSet *set, VisuConfigFileEntry *entry _U_, VisuConfigFile *obj _U_) { visu_gl_ext_set_setBgColor(set, bgRGBDefault, TOOL_COLOR_MASK_RGBA); } static void onEntryFogActive(VisuGlExtSet *set, VisuConfigFileEntry *entry _U_, VisuConfigFile *obj _U_) { visu_gl_ext_set_setFogActive(set, fogActiveDefault); } static void onEntryFogSpecific(VisuGlExtSet *set, VisuConfigFileEntry *entry _U_, VisuConfigFile *obj _U_) { visu_gl_ext_set_setFogFollowsBg(set, !fogSpecificDefault); } static void onEntryFogColor(VisuGlExtSet *set, VisuConfigFileEntry *entry _U_, VisuConfigFile *obj _U_) { visu_gl_ext_set_setFogColor(set, fogRGBDefault, TOOL_COLOR_MASK_RGBA); } static void onEntryFogStartEnd(VisuGlExtSet *set, VisuConfigFileEntry *entry _U_, VisuConfigFile *obj _U_) { visu_gl_ext_set_setFogStartFull(set, fogStartEndDefault, VISU_GL_EXT_SET_FOG_MASK_START | VISU_GL_EXT_SET_FOG_MASK_FULL); } static void onWidthHeight(VisuGlView *view _U_, gpointer data) { VisuGlExtSetPrivate *priv = VISU_GL_EXT_SET(data)->priv; DBG_fprintf(stderr, "Visu Extension Set: caught the 'WidthHeightChanged' signal.\n"); if (priv->bgRGB[3] < 1.f) priv->bgDirty = TRUE; } static void onCamera(VisuGlView *view _U_, gpointer data) { _appendDirty(VISU_GL_EXT_SET(data)); } static void exportResources(GString *data, VisuData *dataObj _U_) { if (!defaultSet) return; visu_config_file_exportComment(data, DESC_RESOURCE_BG_COLOR); visu_config_file_exportEntry(data, FLAG_RESOURCE_BG_COLOR, NULL, "%4.3f %4.3f %4.3f %4.3f", defaultSet->priv->bgRGB[0], defaultSet->priv->bgRGB[1], defaultSet->priv->bgRGB[2], defaultSet->priv->bgRGB[3]); visu_config_file_exportComment(data, DESC_RESOURCE_FOG_USED); visu_config_file_exportEntry(data, FLAG_RESOURCE_FOG_USED, NULL, "%d", defaultSet->priv->fogActive); visu_config_file_exportComment(data, DESC_RESOURCE_FOG_SPECIFIC); visu_config_file_exportEntry(data, FLAG_RESOURCE_FOG_SPECIFIC, NULL, "%d", !defaultSet->priv->fogFollowsBg); visu_config_file_exportComment(data, DESC_RESOURCE_FOG_COLOR); visu_config_file_exportEntry(data, FLAG_RESOURCE_FOG_COLOR, NULL, "%4.3f %4.3f %4.3f %4.3f", defaultSet->priv->fogRGB[0], defaultSet->priv->fogRGB[1], defaultSet->priv->fogRGB[2], defaultSet->priv->fogRGB[3]); visu_config_file_exportComment(data, DESC_RESOURCE_FOG_STARTEND); visu_config_file_exportEntry(data, FLAG_RESOURCE_FOG_STARTEND, NULL, "%4.3f %4.3f", defaultSet->priv->fogStartEnd[0], defaultSet->priv->fogStartEnd[1]); visu_config_file_exportComment(data, ""); } v_sim-3.8.0/src/visu_extset.h000066400000000000000000000137341370110300500161570ustar00rootroot00000000000000/* EXTRAITS DE LA LICENCE Copyright CEA, contributeurs : Damien CALISTE, laboratoire L_Sim, (2015) Adresse mèl : CALISTE, damien P caliste AT cea P fr. Ce logiciel est un programme informatique servant à visualiser des structures atomiques dans un rendu pseudo-3D. Ce logiciel est régi par la licence CeCILL soumise au droit français et respectant les principes de diffusion des logiciels libres. Vous pouvez utiliser, modifier et/ou redistribuer ce programme sous les conditions de la licence CeCILL telle que diffusée par le CEA, le CNRS et l'INRIA sur le site "http://www.cecill.info". Le fait que vous puissiez accéder à cet en-tête signifie que vous avez pris connaissance de la licence CeCILL, et que vous en avez accepté les termes (cf. le fichier Documentation/licence.fr.txt fourni avec ce logiciel). */ /* LICENCE SUM UP Copyright CEA, contributors : Damien CALISTE, laboratoire L_Sim, (2015) E-mail address: CALISTE, damien P caliste AT cea P fr. This software is a computer program whose purpose is to visualize atomic configurations in 3D. This software is governed by the CeCILL license under French law and abiding by the rules of distribution of free software. You can use, modify and/ or redistribute the software under the terms of the CeCILL license as circulated by CEA, CNRS and INRIA at the following URL "http://www.cecill.info". The fact that you are presently reading this means that you have had knowledge of the CeCILL license and that you accept its terms. You can find a copy of this licence shipped with this software at Documentation/licence.en.txt. */ #ifndef VISU_GL_EXT_SET_H #define VISU_GL_EXT_SET_H #include #include #include "opengl.h" #include "visu_extension.h" #include "openGLFunctions/view.h" #include "coreTools/toolColor.h" G_BEGIN_DECLS /***************/ /* Public part */ /***************/ /** * VISU_TYPE_GL_EXT_SET: * * return the type of #VisuGlExtSet. */ #define VISU_TYPE_GL_EXT_SET (visu_gl_ext_set_get_type ()) /** * VISU_GL_EXT_SET: * @obj: a #GObject to cast. * * Cast the given @obj into #VisuGlExtSet type. */ #define VISU_GL_EXT_SET(obj) (G_TYPE_CHECK_INSTANCE_CAST(obj, VISU_TYPE_GL_EXT_SET, VisuGlExtSet)) /** * VISU_GL_EXT_SET_CLASS: * @klass: a #GObjectClass to cast. * * Cast the given @klass into #VisuGlExtSetClass. */ #define VISU_GL_EXT_SET_CLASS(klass) (G_TYPE_CHECK_CLASS_CAST(klass, VISU_TYPE_GL_EXT_SET, VisuGlExtSetClass)) /** * VISU_IS_GL_EXT_SET: * @obj: a #GObject to test. * * Test if the given @ogj is of the type of #VisuGlExtSet object. */ #define VISU_IS_GL_EXT_SET(obj) (G_TYPE_CHECK_INSTANCE_TYPE(obj, VISU_TYPE_GL_EXT_SET)) /** * VISU_IS_GL_EXT_SET_CLASS: * @klass: a #GObjectClass to test. * * Test if the given @klass is of the type of #VisuGlExtSetClass class. */ #define VISU_IS_GL_EXT_SET_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE(klass, VISU_TYPE_GL_EXT_SET)) /** * VISU_GL_EXT_SET_GET_CLASS: * @obj: a #GObject to get the class of. * * It returns the class of the given @obj. */ #define VISU_GL_EXT_SET_GET_CLASS(obj) (G_TYPE_INSTANCE_GET_CLASS(obj, VISU_TYPE_GL_EXT_SET, VisuGlExtSetClass)) /** * VISU_GL_EXT_SET_FOG_MASK_START: * * Value used by the second parameter of visu_gl_ext_set_setFogStartFull() to * specified the value that must be changed. This actually changes * the fog_start value. */ #define VISU_GL_EXT_SET_FOG_MASK_START (1 << 0) /** * VISU_GL_EXT_SET_FOG_MASK_FULL: * * Value used by the second parameter of visu_gl_ext_set_setFogStartFull() to * specified the value that must be changed. This actually changes * the fog_end value. */ #define VISU_GL_EXT_SET_FOG_MASK_FULL (1 << 1) /** * VisuGlExtSetPrivate: * * Private data for #VisuGlExtSet objects. */ typedef struct _VisuGlExtSetPrivate VisuGlExtSetPrivate; /** * VisuGlExtSet: * * Common name to refer to a #_VisuGlExtSet. */ typedef struct _VisuGlExtSet VisuGlExtSet; struct _VisuGlExtSet { VisuGl parent; VisuGlExtSetPrivate *priv; }; /** * VisuGlExtSetClass: * @parent: private. * @added: executed when @ext is added. * @removed: executed when @ext is removed. * * Common name to refer to a #_VisuGlExtSetClass. */ typedef struct _VisuGlExtSetClass VisuGlExtSetClass; struct _VisuGlExtSetClass { VisuGlClass parent; void (*added)(VisuGlExtSet *self, VisuGlExt *ext); void (*removed)(VisuGlExtSet *self, VisuGlExt *ext); }; /** * visu_gl_ext_set_get_type: * * This method returns the type of #VisuGlExtSet, use * VISU_TYPE_GL_EXT_SET instead. * * Since: 3.7 * * Returns: the type of #VisuGlExtSet. */ GType visu_gl_ext_set_get_type(void); VisuGlExtSet* visu_gl_ext_set_new(); gboolean visu_gl_ext_set_add(VisuGlExtSet *set, VisuGlExt *ext); gboolean visu_gl_ext_set_remove(VisuGlExtSet *set, VisuGlExt *ext); gboolean visu_gl_ext_set_setGlView(VisuGlExtSet *set, VisuGlView *view); VisuGlExt* visu_gl_ext_set_getByName(const VisuGlExtSet *set, const gchar *name); GList* visu_gl_ext_set_getAll(VisuGlExtSet *set); void visu_gl_ext_set_draw(VisuGlExtSet *set); GArray* visu_gl_ext_set_getPixmapData(VisuGlExtSet *set, guint width, guint height, gboolean hasAlpha); gboolean visu_gl_ext_set_setBgColor(VisuGlExtSet *set, float rgba[4], int mask); void visu_gl_ext_set_getBgColor(const VisuGlExtSet *set, float rgba[4]); gboolean visu_gl_ext_set_setFogColor(VisuGlExtSet *set, float rgba[4], int mask); gboolean visu_gl_ext_set_setFogActive(VisuGlExtSet *set, gboolean value); gboolean visu_gl_ext_set_setFogFollowsBg(VisuGlExtSet *set, gboolean value); gboolean visu_gl_ext_set_setFogStartFull(VisuGlExtSet *set, float startEnd[2], int mask); void visu_gl_ext_set_getFogColor(VisuGlExtSet *set, float rgba[4]); void visu_gl_ext_set_getFogSpecificColor(VisuGlExtSet *set, float rgba[4]); gboolean visu_gl_ext_set_getFogActive(VisuGlExtSet *set); gboolean visu_gl_ext_set_getFogFollowsBg(VisuGlExtSet *set); void visu_gl_ext_set_getFogStartFull(VisuGlExtSet *set, float startFull[2]); G_END_DECLS #endif v_sim-3.8.0/src/visu_glnodescene.c000066400000000000000000002516071370110300500171270ustar00rootroot00000000000000/* EXTRAITS DE LA LICENCE Copyright CEA, contributeurs : Damien CALISTE, laboratoire L_Sim, (2016) Adresse mèl : CALISTE, damien P caliste AT cea P fr. Ce logiciel est un programme informatique servant à visualiser des structures atomiques dans un rendu pseudo-3D. Ce logiciel est régi par la licence CeCILL soumise au droit français et respectant les principes de diffusion des logiciels libres. Vous pouvez utiliser, modifier et/ou redistribuer ce programme sous les conditions de la licence CeCILL telle que diffusée par le CEA, le CNRS et l'INRIA sur le site "http://www.cecill.info". Le fait que vous puissiez accéder à cet en-tête signifie que vous avez pris connaissance de la licence CeCILL, et que vous en avez accepté les termes (cf. le fichier Documentation/licence.fr.txt fourni avec ce logiciel). */ /* LICENCE SUM UP Copyright CEA, contributors : Damien CALISTE, laboratoire L_Sim, (2016) E-mail address: CALISTE, damien P caliste AT cea P fr. This software is a computer program whose purpose is to visualize atomic configurations in 3D. This software is governed by the CeCILL license under French law and abiding by the rules of distribution of free software. You can use, modify and/ or redistribute the software under the terms of the CeCILL license as circulated by CEA, CNRS and INRIA at the following URL "http://www.cecill.info". The fact that you are presently reading this means that you have had knowledge of the CeCILL license and that you accept its terms. You can find a copy of this licence shipped with this software at Documentation/licence.en.txt. */ #include #include "visu_glnodescene.h" #include "extraFunctions/geometry.h" #include "extraFunctions/scalarFieldSet.h" #include "extraFunctions/shellProp.h" #include "extraFunctions/idProp.h" #include "extraFunctions/typeProp.h" #include "extraFunctions/pot2surf.h" #include "extraFunctions/vibration.h" #include "dumpModules/fileDump.h" #include "dumpModules/glDump.h" #include "iface_boxed.h" #include "iface_animatable.h" #include "visu_configFile.h" #include "visu_dataspin.h" #include "extensions/paths.h" #include "extensions/infos.h" #include "visu_commandLine.h" #include "renderingMethods/spinMethod.h" /** * SECTION:visu_glnodescene * @short_description: Defines a storage object to handle all * #VisuGlExt used to render nodes and associated data. * * */ #define FLAG_PARAMETER_FILEEXT "dataFile_fileExtension" #define DESC_PARAMETER_FILEEXT "The extension used for data file ; chain e.g. '.dat'" static gchar *fileExt = NULL; struct _VisuGlNodeScenePrivate { gboolean dispose_has_run; VisuBox *prevBox; gulong pos_sig, mar_sig, popMar_sig, popInc_sig, box_sig, vis_sig, mask_sig; gulong load_sig, mess_sig, vib_sig; GBinding *bind_theta, *bind_phi, *bind_omega; GList *maskers, *movers; VisuDataColorizerFragment *shellColorizer; VisuDataColorizerFragment *fragColorizer; VisuColorization *dt; gulong single_sig, active_sig, colorizer_sig; GBinding *bind_shade, *vib_bind; VisuGlView *view; gulong view_anim; /* Rendered extensions. */ VisuGlExtNodes *nodes; VisuGlExtMarks *marks; VisuGlExtPairs *pairs; VisuGlExtBg *bg; VisuGlExtAxes *axes; VisuGlExtBox *box; VisuGlExtBoxLegend *boxLegend; VisuGlExtLegend *legend; VisuGlExtPlanes *planes; VisuGlExtSurfaces *surfaces; VisuGlExtInfos *infos; VisuGlExtScale *scales; VisuGlExtForces *forces; VisuGlExtGeodiff *diff; VisuGlExtVibrations *vibrations; VisuGlExtMapSet *maps; VisuGlExtShade *mapLegend; VisuGlExtPaths *extPaths; VisuGlExtShade *colorizationLegend; gulong planes_anim; VisuPaths *paths; gboolean reorder, record; gboolean fitToBox; gboolean axesFollowBox; VisuGlNodeSceneColorizationPolicies dtPolicy; gchar *dtFileExtension; /* Animations */ GTimer *timer; guint tickId; GList *animations; }; enum { PROP_0, DATA_PROP, VIEW_PROP, DIFF_PROP, REORDER_PROP, PATH_PROP, RECORD_PROP, PATH_LENGTH_PROP, PATH_SHADE_PROP, LOADING_PROP, LOADMESS_PROP, AXES_BOX_PROP, AUTO_COLORIZATION_PROP, SCHEME_COLORIZATION_PROP, SHELL_COLORIZATION_PROP, N_PROP, ADJUST_PROP, BOX_PROP }; static GParamSpec *_properties[N_PROP]; static void visu_gl_node_scene_dispose (GObject* obj); static void visu_gl_node_scene_finalize (GObject* obj); static void visu_gl_node_scene_get_property(GObject* obj, guint property_id, GValue *value, GParamSpec *pspec); static void visu_gl_node_scene_set_property(GObject* obj, guint property_id, const GValue *value, GParamSpec *pspec); static void visu_gl_node_scene_added(VisuGlExtSet *self, VisuGlExt *ext); static void visu_gl_node_scene_removed(VisuGlExtSet *self, VisuGlExt *ext); static VisuBox* _getBox(VisuBoxed *self); static gboolean _setBox(VisuBoxed *self, VisuBox *box); static void visu_boxed_interface_init(VisuBoxedInterface *iface); static void _applyMaskers(VisuGlNodeScene *scene); static void _ensureBoxMargin(VisuGlNodeScene *scene); static void _propagateBox(VisuGlNodeScene *scene); static void _applyColorizationPolicy(VisuGlNodeScene *scene); static gboolean _onAnimate(VisuGlNodeScene *scene, VisuAnimation *anim, const GValue *to, gulong duration, gboolean loop, VisuAnimationType type); static void exportParameters(GString *data, VisuData* dataObj); static VisuData* _getData(VisuGlNodeScene *self); struct _masker { VisuNodeMasker *masker; gulong dirty_sig; }; struct _mover { VisuNodeMover *mover; gulong animate_sig; GBinding *bind; }; /* Local callbacks */ static void onEntryScale(VisuGlNodeScene *scene, VisuConfigFileEntry *entry, VisuConfigFile *obj); static void onDiffActive(VisuGlNodeScene *scene, GParamSpec *pspec, VisuGlExtGeodiff *diff); static void onPathActive(VisuGlNodeScene *scene, GParamSpec *pspec, VisuGlExtPaths *paths); static void onLoading(VisuGlNodeScene *scene, GParamSpec *pspec, VisuDataLoadable *data); static void onLoadingMessage(VisuGlNodeScene *scene, GParamSpec *pspec, VisuDataLoadable *data); static void _freeMasker(struct _masker *str); static void _freeMover(struct _mover *str); G_DEFINE_TYPE_WITH_CODE(VisuGlNodeScene, visu_gl_node_scene, VISU_TYPE_GL_EXT_SET, G_ADD_PRIVATE(VisuGlNodeScene) G_IMPLEMENT_INTERFACE(VISU_TYPE_BOXED, visu_boxed_interface_init)) static void visu_gl_node_scene_class_init(VisuGlNodeSceneClass *klass) { VisuConfigFileEntry *resourceEntry; DBG_fprintf(stderr, "Visu Node Scene: creating the class of the object.\n"); /* DBG_fprintf(stderr, " - adding new signals ;\n"); */ /* Connect the overloading methods. */ G_OBJECT_CLASS(klass)->dispose = visu_gl_node_scene_dispose; G_OBJECT_CLASS(klass)->finalize = visu_gl_node_scene_finalize; G_OBJECT_CLASS(klass)->set_property = visu_gl_node_scene_set_property; G_OBJECT_CLASS(klass)->get_property = visu_gl_node_scene_get_property; VISU_GL_EXT_SET_CLASS(klass)->added = visu_gl_node_scene_added; VISU_GL_EXT_SET_CLASS(klass)->removed = visu_gl_node_scene_removed; /** * VisuGlNodeScene::data: * * Store the data object. * * Since: 3.8 */ _properties[DATA_PROP] = g_param_spec_object("data", "Data", "storing data for nodes", VISU_TYPE_DATA, G_PARAM_READWRITE); /** * VisuGlNodeScene::view: * * Store the #VisuGlView used to render the scene. * * Since: 3.8 */ _properties[VIEW_PROP] = g_param_spec_object("view", "View", "storing the view to represent the data", VISU_TYPE_GL_VIEW, G_PARAM_READABLE); /** * VisuGlNodeScene::geometry-differences: * * If the scene displays arrows to represent geometry differences * between two #VisuData. * * Since: 3.8 */ _properties[DIFF_PROP] = g_param_spec_boolean("geometry-differences", "Geometry differences", "display arrows to represent differences", FALSE, G_PARAM_READWRITE); /** * VisuGlNodeScene::reorder-reference: * * If the reference #VisuData is reordered before doing geometry differences. * * Since: 3.8 */ _properties[REORDER_PROP] = g_param_spec_boolean("reorder-reference", "Reorder reference", "reorder reference data before comparing", FALSE, G_PARAM_READWRITE | G_PARAM_CONSTRUCT); /** * VisuGlNodeScene::path-active: * * If the differences between #VisuData is displayed. * * Since: 3.8 */ _properties[PATH_PROP] = g_param_spec_boolean("path-active", "Path is active", "display stored paths", FALSE, G_PARAM_READWRITE | G_PARAM_CONSTRUCT); /** * VisuGlNodeScene::record-path: * * If the differences between #VisuData is stored. * * Since: 3.8 */ _properties[RECORD_PROP] = g_param_spec_boolean("record-path", "Record path", "save differences between data", FALSE, G_PARAM_READWRITE | G_PARAM_CONSTRUCT); /** * VisuGlNodeScene::path-length: * * Store the length of the current path. * * Since: 3.8 */ _properties[PATH_LENGTH_PROP] = g_param_spec_uint("path-length", "Path length", "store the path length", 0, G_MAXUINT, 0, G_PARAM_READABLE); /** * VisuGlNodeScene::path-shade: * * Store a shade to colourize the path. * * Since: 3.8 */ _properties[PATH_SHADE_PROP] = g_param_spec_boxed("path-shade", "Path shade", "store the path shade", TOOL_TYPE_SHADE, G_PARAM_READWRITE); /** * VisuGlNodeScene::loading: * * Flag signaling that #VisuData is laoding or not. * * Since: 3.8 */ _properties[LOADING_PROP] = g_param_spec_boolean("loading", "Loading", "flag indicating that data are loading.", FALSE, G_PARAM_READABLE); /** * VisuGlNodeScene::loading-message: * * Message to be informed what happens during loding. * * Since: 3.8 */ _properties[LOADMESS_PROP] = g_param_spec_string("loading-message", "Loading message", "message when loading.", "", G_PARAM_READABLE); /** * VisuGlNodeScene::axes-from-box: * * Flag for the axes to be orthorombic or following the #VisuData super-cell. * * Since: 3.8 */ _properties[AXES_BOX_PROP] = g_param_spec_boolean("axes-from-box", "Axes from box", "axes follow the data super-cell.", FALSE, G_PARAM_READWRITE); /** * VisuGlNodeScene::colorization-policy: * * Flag to automatically load colourisation data. * * Since: 3.8 */ _properties[AUTO_COLORIZATION_PROP] = g_param_spec_uint("colorization-policy", "Colorization policy", "colorization load policy.", 0, COLORIZATION_N_POLICIES - 1, COLORIZATION_POLICY_FROM_PREVIOUS, G_PARAM_READWRITE); /** * VisuGlNodeScene::colorization-file-extension: * * File extension used to discover colourisation file from data file. * * Since: 3.8 */ _properties[SCHEME_COLORIZATION_PROP] = g_param_spec_string("colorization-file-extension", "Colorization file extension", "extension used to discover colourisation file.", ".dat", G_PARAM_READWRITE); /** * VisuGlNodeScene::shell-colorizer: * * Object used to colorize neighbouring shells. * * Since: 3.8 */ _properties[SHELL_COLORIZATION_PROP] = g_param_spec_object("shell-colorizer", "Shell colorizer object", "used to colorize neighbouring shells.", VISU_TYPE_DATA_COLORIZER_FRAGMENT, G_PARAM_READABLE); g_object_class_install_properties(G_OBJECT_CLASS(klass), N_PROP, _properties); g_object_class_override_property(G_OBJECT_CLASS(klass), ADJUST_PROP, "auto-adjust"); g_object_class_override_property(G_OBJECT_CLASS(klass), BOX_PROP, "box"); resourceEntry = visu_config_file_addStringEntry(VISU_CONFIG_FILE_PARAMETER, FLAG_PARAMETER_FILEEXT, DESC_PARAMETER_FILEEXT, &fileExt); visu_config_file_entry_setVersion(resourceEntry, 3.4f); visu_config_file_addExportFunction(VISU_CONFIG_FILE_PARAMETER, exportParameters); } static void visu_boxed_interface_init(VisuBoxedInterface *iface) { iface->get_box = _getBox; iface->set_box = _setBox; } static void visu_gl_node_scene_init(VisuGlNodeScene *self) { float zeros[3] = {0.f, 0.f, 0.f}; VisuGlExtSet *set; #define SET(V, I) self->priv->V = I; visu_gl_ext_set_add(set, VISU_GL_EXT(self->priv->V)) DBG_fprintf(stderr, "Visu Node Scene: initializing a new object (%p).\n", (gpointer)self); self->priv = visu_gl_node_scene_get_instance_private(self); self->priv->dispose_has_run = FALSE; self->priv->prevBox = (VisuBox*)0; self->priv->fragColorizer = (VisuDataColorizerFragment*)0; self->priv->shellColorizer = (VisuDataColorizerFragment*)0; self->priv->dt = (VisuColorization*)0; self->priv->view = visu_gl_view_new(); self->priv->view_anim = g_signal_connect_swapped(self->priv->view, "animate", G_CALLBACK(_onAnimate), self); set = VISU_GL_EXT_SET(self); SET(nodes, visu_gl_ext_nodes_new()); SET(marks, visu_gl_ext_marks_new((const gchar*)0)); visu_gl_ext_set_add(set, visu_gl_ext_marks_getInternalList(self->priv->marks)); SET(pairs, visu_gl_ext_pairs_new((const gchar*)0)); SET(bg, visu_gl_ext_bg_new((const gchar*)0)); SET(axes, visu_gl_ext_axes_new((const gchar*)0)); SET(box, visu_gl_ext_box_new((const gchar*)0)); SET(boxLegend, visu_gl_ext_box_legend_new((const gchar*)0)); SET(legend, visu_gl_ext_legend_new((const gchar*)0)); SET(infos, visu_gl_ext_infos_new((const gchar*)0)); SET(scales, visu_gl_ext_scale_new((const gchar*)0)); SET(forces, visu_gl_ext_forces_new((const gchar*)0)); SET(diff, visu_gl_ext_geodiff_new((const gchar*)0)); SET(vibrations, visu_gl_ext_vibrations_new((const gchar*)0)); SET(extPaths, visu_gl_ext_paths_new((const gchar*)0)); /* Optional extensions. */ self->priv->planes = (VisuGlExtPlanes*)0; self->priv->surfaces = (VisuGlExtSurfaces*)0; self->priv->maps = (VisuGlExtMapSet*)0; self->priv->mapLegend = (VisuGlExtShade*)0; self->priv->colorizationLegend = (VisuGlExtShade*)0; visu_gl_ext_pairs_setDataRenderer(self->priv->pairs, VISU_NODE_ARRAY_RENDERER(self->priv->nodes)); visu_gl_ext_legend_setNodes(self->priv->legend, VISU_NODE_ARRAY_RENDERER(self->priv->nodes)); visu_gl_ext_infos_setDataRenderer(self->priv->infos, VISU_NODE_ARRAY_RENDERER(self->priv->nodes)); visu_gl_ext_marks_setDataRenderer(self->priv->marks, VISU_NODE_ARRAY_RENDERER(self->priv->nodes)); visu_gl_ext_set_setGlView(set, self->priv->view); g_signal_connect_swapped(self->priv->nodes, "notify::max-element-size", G_CALLBACK(_ensureBoxMargin), self); g_signal_connect_swapped(VISU_CONFIG_FILE_RESOURCE, "parsed::scale_definition", G_CALLBACK(onEntryScale), self); g_signal_connect_swapped(self->priv->diff, "notify::active", G_CALLBACK(onDiffActive), self); visu_gl_ext_setActive(VISU_GL_EXT(self->priv->diff), FALSE); g_signal_connect_swapped(self->priv->extPaths, "notify::active", G_CALLBACK(onPathActive), self); visu_gl_ext_setActive(VISU_GL_EXT(self->priv->extPaths), FALSE); visu_gl_ext_setActive(VISU_GL_EXT(self->priv->infos), FALSE); self->priv->paths = visu_paths_new(zeros); visu_gl_ext_paths_set(self->priv->extPaths, self->priv->paths); self->priv->axesFollowBox = FALSE; self->priv->dtPolicy = COLORIZATION_POLICY_FROM_PREVIOUS; self->priv->dtFileExtension = g_strdup(fileExt ? fileExt : ".dat"); self->priv->maskers = (GList*)0; visu_gl_node_scene_addMasker(self, VISU_NODE_MASKER(self->priv->marks)); self->priv->movers = (GList*)0; self->priv->timer = g_timer_new(); self->priv->animations = (GList*)0; self->priv->tickId = 0; } /* This method can be called several times. It should unref all of its reference to GObjects. */ static void visu_gl_node_scene_dispose(GObject* obj) { VisuGlNodeScene *ext; DBG_fprintf(stderr, "Visu Node Scene: dispose object %p.\n", (gpointer)obj); ext = VISU_GL_NODE_SCENE(obj); if (ext->priv->dispose_has_run) return; ext->priv->dispose_has_run = TRUE; visu_gl_node_scene_setData(ext, (VisuData*)0); if (ext->priv->fragColorizer) g_object_unref(ext->priv->fragColorizer); if (ext->priv->shellColorizer) g_object_unref(ext->priv->shellColorizer); if (ext->priv->dt) g_object_unref(ext->priv->dt); g_signal_handler_disconnect(ext->priv->view, ext->priv->view_anim); g_object_unref(ext->priv->view); g_object_unref(ext->priv->nodes); g_object_unref(ext->priv->marks); g_object_unref(ext->priv->pairs); g_object_unref(ext->priv->bg); g_object_unref(ext->priv->axes); g_object_unref(ext->priv->box); g_object_unref(ext->priv->boxLegend); g_object_unref(ext->priv->legend); g_object_unref(ext->priv->infos); g_object_unref(ext->priv->scales); g_object_unref(ext->priv->forces); g_object_unref(ext->priv->diff); g_object_unref(ext->priv->vibrations); g_object_unref(ext->priv->extPaths); if (ext->priv->planes) { g_signal_handler_disconnect(ext->priv->planes->planes, ext->priv->planes_anim); g_object_unref(ext->priv->planes); } if (ext->priv->surfaces) g_object_unref(ext->priv->surfaces); if (ext->priv->maps) g_object_unref(ext->priv->maps); if (ext->priv->mapLegend) g_object_unref(ext->priv->mapLegend); if (ext->priv->colorizationLegend) g_object_unref(ext->priv->colorizationLegend); if (ext->priv->paths) visu_paths_unref(ext->priv->paths); g_list_free_full(ext->priv->maskers, (GDestroyNotify)_freeMasker); g_list_free_full(ext->priv->movers, (GDestroyNotify)_freeMover); if (ext->priv->tickId) g_source_remove(ext->priv->tickId); g_list_free_full(ext->priv->animations, g_object_unref); /* Chain up to the parent class */ DBG_fprintf(stderr, "Visu Node Scene: chain up to parent.\n"); G_OBJECT_CLASS(visu_gl_node_scene_parent_class)->dispose(obj); DBG_fprintf(stderr, "Visu Node Scene: dispose ... OK.\n"); } static void visu_gl_node_scene_finalize(GObject* obj) { VisuGlNodeScene *ext; ext = VISU_GL_NODE_SCENE(obj); g_free(ext->priv->dtFileExtension); g_timer_destroy(ext->priv->timer); G_OBJECT_CLASS(visu_gl_node_scene_parent_class)->finalize(obj); } static void visu_gl_node_scene_get_property(GObject* obj, guint property_id, GValue *value, GParamSpec *pspec) { VisuGlNodeScene *self = VISU_GL_NODE_SCENE(obj); VisuData *data; DBG_fprintf(stderr, "Visu Node Scene: get property '%s' -> ", g_param_spec_get_name(pspec)); switch (property_id) { case DATA_PROP: g_value_set_object(value, _getData(self)); DBG_fprintf(stderr, "%p.\n", g_value_get_object(value)); break; case VIEW_PROP: g_value_set_object(value, self->priv->view); DBG_fprintf(stderr, "%p.\n", (gpointer)self->priv->view); break; case DIFF_PROP: g_value_set_boolean(value, visu_gl_ext_getActive(VISU_GL_EXT(self->priv->diff))); DBG_fprintf(stderr, "%d.\n", g_value_get_boolean(value)); break; case REORDER_PROP: g_value_set_boolean(value, self->priv->reorder); DBG_fprintf(stderr, "%d.\n", g_value_get_boolean(value)); break; case RECORD_PROP: g_value_set_boolean(value, self->priv->record); DBG_fprintf(stderr, "%d.\n", g_value_get_boolean(value)); break; case PATH_PROP: g_value_set_boolean(value, visu_gl_ext_getActive(VISU_GL_EXT(self->priv->extPaths))); DBG_fprintf(stderr, "%d.\n", g_value_get_boolean(value)); break; case PATH_LENGTH_PROP: g_value_set_uint(value, (self->priv->paths) ? visu_paths_getLength(self->priv->paths) : 0); DBG_fprintf(stderr, "%d.\n", g_value_get_uint(value)); break; case PATH_SHADE_PROP: g_value_set_boxed(value, (self->priv->paths) ? visu_paths_getToolShade(self->priv->paths) : (gconstpointer)0); DBG_fprintf(stderr, "%p.\n", g_value_get_boxed(value)); break; case LOADING_PROP: data = _getData(self); if (data && VISU_IS_DATA_LOADABLE(data)) g_object_get_property(G_OBJECT(data), "loading", value); else g_value_set_boolean(value, FALSE); DBG_fprintf(stderr, "%d.\n", g_value_get_boolean(value)); break; case LOADMESS_PROP: data = _getData(self); if (data && VISU_IS_DATA_LOADABLE(data)) g_object_get_property(G_OBJECT(data), "status", value); else g_value_set_static_string(value, (const gchar*)0); DBG_fprintf(stderr, "%s.\n", g_value_get_string(value)); break; case AXES_BOX_PROP: g_value_set_boolean(value, self->priv->axesFollowBox); DBG_fprintf(stderr, "%d.\n", g_value_get_boolean(value)); break; case BOX_PROP: g_value_set_object(value, _getBox(VISU_BOXED(self))); DBG_fprintf(stderr, "%p.\n", g_value_get_object(value)); break; case ADJUST_PROP: g_value_set_boolean(value, self->priv->fitToBox); DBG_fprintf(stderr, "%d.\n", g_value_get_boolean(value)); break; case AUTO_COLORIZATION_PROP: g_value_set_uint(value, self->priv->dtPolicy); DBG_fprintf(stderr, "%d.\n", g_value_get_uint(value)); break; case SCHEME_COLORIZATION_PROP: g_value_set_string(value, self->priv->dtFileExtension); DBG_fprintf(stderr, "%s.\n", g_value_get_string(value)); break; case SHELL_COLORIZATION_PROP: g_value_set_object(value, self->priv->shellColorizer); DBG_fprintf(stderr, "%p.\n", g_value_get_object(value)); break; default: /* We don't have any other property... */ G_OBJECT_WARN_INVALID_PROPERTY_ID(obj, property_id, pspec); break; } } static void visu_gl_node_scene_set_property(GObject* obj, guint property_id, const GValue *value, GParamSpec *pspec) { VisuGlNodeScene *self = VISU_GL_NODE_SCENE(obj); VisuBox *box; DBG_fprintf(stderr, "Visu Node Scene: set property '%s' -> ", g_param_spec_get_name(pspec)); switch (property_id) { case DATA_PROP: DBG_fprintf(stderr, "%p\n", g_value_get_object(value)); visu_gl_node_scene_setData(self, VISU_DATA(g_value_get_object(value))); break; case DIFF_PROP: DBG_fprintf(stderr, "%d.\n", g_value_get_boolean(value)); visu_gl_ext_setActive(VISU_GL_EXT(self->priv->diff), g_value_get_boolean(value)); break; case REORDER_PROP: DBG_fprintf(stderr, "%d.\n", g_value_get_boolean(value)); self->priv->reorder = g_value_get_boolean(value); break; case RECORD_PROP: DBG_fprintf(stderr, "%d.\n", g_value_get_boolean(value)); self->priv->record = g_value_get_boolean(value); if (self->priv->paths && self->priv->record) visu_paths_pinPositions(self->priv->paths, _getData(self)); break; case PATH_PROP: DBG_fprintf(stderr, "%d.\n", g_value_get_boolean(value)); visu_gl_ext_setActive(VISU_GL_EXT(self->priv->extPaths), g_value_get_boolean(value)); break; case PATH_SHADE_PROP: DBG_fprintf(stderr, "%p.\n", g_value_get_boxed(value)); if (self->priv->paths) { visu_paths_setToolShade(self->priv->paths, (ToolShade*)g_value_get_boxed(value)); visu_gl_ext_setDirty(VISU_GL_EXT(self->priv->extPaths), TRUE); } break; case AXES_BOX_PROP: DBG_fprintf(stderr, "%d.\n", g_value_get_boolean(value)); self->priv->axesFollowBox = g_value_get_boolean(value); visu_gl_ext_axes_setBasisFromBox(self->priv->axes, (self->priv->axesFollowBox) ? _getBox(VISU_BOXED(self)): (VisuBox*)0); break; case BOX_PROP: DBG_fprintf(stderr, "%p.\n", g_value_get_object(value)); _setBox(VISU_BOXED(self), VISU_BOX(g_value_get_object(value))); break; case ADJUST_PROP: DBG_fprintf(stderr, "%d.\n", g_value_get_boolean(value)); self->priv->fitToBox = g_value_get_boolean(value); box = _getBox(VISU_BOXED(self)); if (self->priv->surfaces && box && self->priv->fitToBox) visu_gl_ext_surfaces_setFittingBox(self->priv->surfaces, box); break; case AUTO_COLORIZATION_PROP: DBG_fprintf(stderr, "%d.\n", g_value_get_uint(value)); visu_gl_node_scene_setColorizationPolicy(self, g_value_get_uint(value)); break; case SCHEME_COLORIZATION_PROP: DBG_fprintf(stderr, "%s.\n", g_value_get_string(value)); g_free(self->priv->dtFileExtension); self->priv->dtFileExtension = g_value_dup_string(value); g_free(fileExt); fileExt = g_value_dup_string(value); break; default: /* We don't have any other property... */ G_OBJECT_WARN_INVALID_PROPERTY_ID(obj, property_id, pspec); break; } } /** * visu_gl_node_scene_new: * * Create an object to handle a set of #VisuGlExt objects and draw * them together. * * Since: 3.8 * * Returns: (transfer full): a newly created #VisuGlNodeScene object. **/ VisuGlNodeScene* visu_gl_node_scene_new() { return g_object_new(VISU_TYPE_GL_NODE_SCENE, NULL); } static void visu_gl_node_scene_added(VisuGlExtSet *self, VisuGlExt *ext) { VisuGlNodeScene *scene = VISU_GL_NODE_SCENE(self); g_return_if_fail(VISU_IS_GL_NODE_SCENE(self)); if (VISU_IS_SOURCEABLE(ext)) visu_sourceable_follow(VISU_SOURCEABLE(ext), _getData(scene)); } static void visu_gl_node_scene_removed(VisuGlExtSet *self _U_, VisuGlExt *ext) { if (VISU_IS_SOURCEABLE(ext)) visu_sourceable_follow(VISU_SOURCEABLE(ext), (VisuData*)0); } static VisuBox* _getBox(VisuBoxed *self) { VisuData *data; g_return_val_if_fail(VISU_IS_GL_NODE_SCENE(self), (VisuBox*)0); data = _getData(VISU_GL_NODE_SCENE(self)); return data ? visu_boxed_getBox(VISU_BOXED(data)) : (VisuBox*)0; } static gboolean _setBox(VisuBoxed *self, VisuBox *box) { VisuData *data; g_return_val_if_fail(VISU_IS_GL_NODE_SCENE(self), FALSE); data = _getData(VISU_GL_NODE_SCENE(self)); if (!data) return FALSE; return visu_boxed_setBox(VISU_BOXED(data), VISU_BOXED(box)); } static VisuData* _getData(VisuGlNodeScene *self) { return VISU_DATA(visu_node_array_renderer_getNodeArray(VISU_NODE_ARRAY_RENDERER(self->priv->nodes))); } /** * visu_gl_node_scene_setData: * @scene: a #VisuGlNodeScene object. * @data: a #VisuData object. * * Apply the given @view on all #VisuGlExt objects stored in @set. * * Since: 3.8 * * Returns: TRUE if the @view actually change. **/ gboolean visu_gl_node_scene_setData(VisuGlNodeScene *scene, VisuData *data) { VisuBox *boxOld, *box; VisuData *dataRef, *dataOld; VisuVibration *vib; ToolUnits units; VisuBoxBoundaries bc; float *vect; gboolean active, inTheBox; float t[3]; GList *lst; g_return_val_if_fail(VISU_IS_GL_NODE_SCENE(scene), FALSE); boxOld = _getBox(VISU_BOXED(scene)); dataOld = _getData(scene); if (data == dataOld) return FALSE; if (boxOld) g_object_ref(boxOld); if (dataOld) g_object_ref(dataOld); visu_node_array_renderer_setNodeArray(VISU_NODE_ARRAY_RENDERER(scene->priv->nodes), VISU_NODE_ARRAY(data)); box = _getBox(VISU_BOXED(scene)); if ((visu_gl_ext_getActive(VISU_GL_EXT(scene->priv->diff)) || scene->priv->record) && dataOld) dataRef = dataOld; else dataRef = (VisuData*)0; if (dataOld && data) { DBG_fprintf(stderr, "Visu Node Scene: applying current translations.\n"); bc = visu_box_getBoundary(boxOld); g_object_get(G_OBJECT(dataOld), "use-translation", &active, "translation", &vect, "in-the-box", &inTheBox, NULL); if (!(bc & TOOL_XYZ_MASK_X)) vect[0] = 0.f; if (!(bc & TOOL_XYZ_MASK_Y)) vect[1] = 0.f; if (!(bc & TOOL_XYZ_MASK_Z)) vect[2] = 0.f; g_object_set(G_OBJECT(data), "use-translation", active, "translation", vect, "in-the-box", inTheBox, NULL); g_object_get(G_OBJECT(boxOld), "use-expansion", &active, "expansion", &vect, NULL); g_object_set(G_OBJECT(box), "use-expansion", active, "expansion", vect, NULL); /* Update the units if necessary. */ units = visu_box_getUnit(boxOld); if (units != TOOL_UNITS_UNDEFINED) g_object_set(G_OBJECT(box), "units", units, NULL); } if (dataOld) { g_signal_handler_disconnect(dataOld, scene->priv->pos_sig); g_signal_handler_disconnect(dataOld, scene->priv->mar_sig); g_signal_handler_disconnect(dataOld, scene->priv->popMar_sig); g_signal_handler_disconnect(dataOld, scene->priv->popInc_sig); g_signal_handler_disconnect(dataOld, scene->priv->box_sig); g_signal_handler_disconnect(dataOld, scene->priv->vis_sig); g_signal_handler_disconnect(dataOld, scene->priv->mask_sig); if (VISU_IS_DATA_LOADABLE(dataOld)) { g_signal_handler_disconnect(dataOld, scene->priv->load_sig); g_signal_handler_disconnect(dataOld, scene->priv->mess_sig); } if (VISU_IS_DATA_SPIN(dataOld)) { g_object_unref(scene->priv->bind_theta); g_object_unref(scene->priv->bind_phi); g_object_unref(scene->priv->bind_omega); } vib = visu_data_getVibration(dataOld, 0); if (vib) { g_signal_handler_disconnect(vib, scene->priv->vib_sig); g_object_unref(scene->priv->vib_bind); } } if (data) { vib = visu_data_getVibration(data, 0); if (vib) { scene->priv->vib_sig = g_signal_connect_swapped(vib, "animate", G_CALLBACK(_onAnimate), scene); scene->priv->vib_bind = g_object_bind_property(vib, "amplitude", scene->priv->vibrations, "rendering-size", G_BINDING_SYNC_CREATE); } if (VISU_IS_DATA_LOADABLE(data)) { scene->priv->load_sig = g_signal_connect_swapped(data, "notify::loading", G_CALLBACK(onLoading), (gpointer)scene); scene->priv->mess_sig = g_signal_connect_swapped(data, "notify::loading-message", G_CALLBACK(onLoadingMessage), (gpointer)scene); } if (VISU_IS_DATA_SPIN(data)) { scene->priv->bind_theta = g_object_bind_property(visu_method_spin_getDefault(), "cone-theta", scene->priv->axes, "orientation-theta", G_BINDING_SYNC_CREATE); scene->priv->bind_phi = g_object_bind_property(visu_method_spin_getDefault(), "cone-phi", scene->priv->axes, "orientation-phi", G_BINDING_SYNC_CREATE); scene->priv->bind_omega = g_object_bind_property(visu_method_spin_getDefault(), "cone-omega", scene->priv->axes, "orientation-omega", G_BINDING_SYNC_CREATE); } scene->priv->pos_sig = g_signal_connect_swapped(data, "position-changed", G_CALLBACK(_applyMaskers), (gpointer)scene); scene->priv->mar_sig = g_signal_connect_swapped(data, "position-changed", G_CALLBACK(_ensureBoxMargin), (gpointer)scene); scene->priv->popInc_sig = g_signal_connect_swapped(data, "PopulationIncrease", G_CALLBACK(_applyMaskers), (gpointer)scene); scene->priv->popMar_sig = g_signal_connect_swapped(data, "PopulationIncrease", G_CALLBACK(_ensureBoxMargin), (gpointer)scene); scene->priv->box_sig = g_signal_connect_swapped(VISU_BOXED(data), "setBox", G_CALLBACK(_propagateBox), (gpointer)scene); scene->priv->vis_sig = g_signal_connect_swapped(data, "ElementVisibilityChanged", G_CALLBACK(_applyMaskers), (gpointer)scene); scene->priv->mask_sig = g_signal_connect_swapped(data, "ElementMaskableChanged", G_CALLBACK(_applyMaskers), (gpointer)scene); visu_pointset_getTranslation(VISU_POINTSET(data), t); visu_paths_setTranslation(scene->priv->paths, t); } /* Adapt the view to the new box. */ _propagateBox(scene); /* Update all Gl extension. */ visu_sourceable_setNodeModel (VISU_SOURCEABLE(scene->priv->forces), VISU_IS_DATA_ATOMIC(data) ? VISU_NODE_VALUES(visu_data_atomic_getForces(VISU_DATA_ATOMIC(data), FALSE)) : NULL); visu_gl_ext_node_vectors_setNodeRenderer (VISU_GL_EXT_NODE_VECTORS(scene->priv->forces), VISU_NODE_ARRAY_RENDERER(scene->priv->nodes)); visu_sourceable_setNodeModel (VISU_SOURCEABLE(scene->priv->vibrations), data ? VISU_NODE_VALUES(visu_data_getVibration(VISU_DATA(data), 0)) : NULL); visu_gl_ext_node_vectors_setNodeRenderer (VISU_GL_EXT_NODE_VECTORS(scene->priv->vibrations), VISU_NODE_ARRAY_RENDERER(scene->priv->nodes)); visu_gl_ext_pairs_setData(scene->priv->pairs, data); if (scene->priv->maps) visu_gl_ext_maps_removeAll(VISU_GL_EXT_MAPS(scene->priv->maps)); visu_gl_ext_axes_useOrientation(scene->priv->axes, VISU_IS_DATA_SPIN(data)); for (lst = visu_gl_ext_set_getAll(VISU_GL_EXT_SET(scene)); lst; lst = g_list_next(lst)) if (VISU_IS_SOURCEABLE(lst->data)) visu_sourceable_follow(VISU_SOURCEABLE(lst->data), data); if (data) { _applyMaskers(scene); _applyColorizationPolicy(scene); } g_object_notify_by_pspec(G_OBJECT(scene), _properties[DATA_PROP]); g_object_notify_by_pspec(G_OBJECT(scene), _properties[PATH_LENGTH_PROP]); if (dataRef && data) visu_gl_node_scene_setDiffFromData(scene, dataRef); if (dataOld) g_object_unref(dataOld); if (boxOld) g_object_unref(boxOld); return TRUE; } /** * visu_gl_node_scene_getData: * @scene: a #VisuGlNodeScene object. * * Retrives the #VisuData represented by #VisuGlNodeScene. * * Since: 3.8 * * Returns: (transfer none): a #VisuData object. **/ VisuData* visu_gl_node_scene_getData(VisuGlNodeScene *scene) { g_return_val_if_fail(VISU_IS_GL_NODE_SCENE(scene), (VisuData*)0); return _getData(scene); } static void onLoading(VisuGlNodeScene *scene, GParamSpec *pspec _U_, VisuDataLoadable *data) { gboolean loading; g_object_get(data, "loading", &loading, NULL); if (loading) { g_signal_handler_block(data, scene->priv->box_sig); } else { g_signal_handler_unblock(data, scene->priv->box_sig); _propagateBox(scene); } g_object_notify_by_pspec(G_OBJECT(scene), _properties[LOADING_PROP]); } static void onLoadingMessage(VisuGlNodeScene *scene, GParamSpec *pspec _U_, VisuDataLoadable *data _U_) { g_object_notify_by_pspec(G_OBJECT(scene), _properties[LOADMESS_PROP]); } static void _ensureBoxMargin(VisuGlNodeScene *scene) { VisuBox *box; VisuNodeArrayRenderer *nodes; box = _getBox(VISU_BOXED(scene)); if (!box) return; nodes = VISU_NODE_ARRAY_RENDERER(scene->priv->nodes); visu_box_setMargin(box, visu_node_array_renderer_getMaxElementSize(nodes, NULL) + visu_data_getAllNodeExtens(VISU_DATA(visu_node_array_renderer_getNodeArray(nodes)), (VisuBox*)0), TRUE); } static void _propagateBox(VisuGlNodeScene *scene) { VisuScalarfieldSetIter iter; gboolean valid; VisuBox *box; box = _getBox(VISU_BOXED(scene)); /* Ensure that the box has enough margin for all nodes. */ if (box) _ensureBoxMargin(scene); if (scene->priv->prevBox) visu_gl_node_scene_removeMasker(scene, VISU_NODE_MASKER(scene->priv->prevBox)); if (box) visu_gl_node_scene_addMasker(scene, VISU_NODE_MASKER(box)); scene->priv->prevBox = box; visu_boxed_setBox(VISU_BOXED(scene->priv->view), VISU_BOXED(box)); visu_gl_ext_box_setBox(scene->priv->box, box); visu_gl_ext_box_legend_setBox(scene->priv->boxLegend, box); if (scene->priv->planes) visu_gl_ext_planes_setBox(scene->priv->planes, box); if (scene->priv->surfaces && scene->priv->fitToBox) visu_gl_ext_surfaces_setFittingBox(scene->priv->surfaces, box); if (scene->priv->fitToBox) for (valid = visu_scalarfield_set_iter_new(visu_scalarfield_set_getDefault(), &iter) && visu_scalarfield_set_iter_next(&iter); valid; valid = visu_scalarfield_set_iter_next(&iter)) visu_boxed_setBox(VISU_BOXED(iter.field), VISU_BOXED(box)); DBG_fprintf(stderr, "Visu GlNodeScene: notify box.\n"); g_object_notify(G_OBJECT(scene), "box"); DBG_fprintf(stderr, "Visu GlNodeScene: notify box done.\n"); } /** * visu_gl_node_scene_loadData: * @scene: a #VisuGlNodeScene object. * @loadable: a #VisuDataLoadable object. * @iSet: an id. * @cancel: (allow-none): a cancellable. * @error: an error location. * * A convenience function that tries to load @loadable, see * visu_data_loadable_load(). On success, @loadable is associated to * @scene, see visu_gl_node_scene_setData(). * * Since: 3.8 * * Returns: TRUE on success. **/ gboolean visu_gl_node_scene_loadData(VisuGlNodeScene *scene, VisuDataLoadable *loadable, guint iSet, GCancellable *cancel, GError **error) { if (!visu_data_loadable_load(loadable, iSet, cancel, error)) return FALSE; visu_gl_node_scene_setData(scene, VISU_DATA(loadable)); return TRUE; } /** * visu_gl_node_scene_getGlView: * @scene: a #VisuGlNodeScene object. * * Retrieves the #VisuGlView used by @scene to render nodes. * * Since: 3.8 * * Returns: (transfer none): a #VisuGlView object. **/ VisuGlView* visu_gl_node_scene_getGlView(VisuGlNodeScene *scene) { g_return_val_if_fail(VISU_IS_GL_NODE_SCENE(scene), (VisuGlView*)0); return scene->priv->view; } /** * visu_gl_node_scene_setGlCamera: * @scene: a #VisuGlNodeScene object. * @camera: a #VisuGlCamera object. * * A convenience function to change the view all at once with animations. * * Since: 3.8 **/ void visu_gl_node_scene_setGlCamera(VisuGlNodeScene *scene, VisuGlCamera *camera) { g_return_if_fail(VISU_IS_GL_NODE_SCENE(scene) && camera); g_object_set(scene->priv->view, "theta", camera->theta, "phi", camera->phi, "omega", camera->omega, "zoom", camera->gross, "perspective", camera->d_red, NULL); visu_gl_view_setXsYs(scene->priv->view, camera->xs, camera->ys, VISU_GL_CAMERA_XS | VISU_GL_CAMERA_YS); } /** * visu_gl_node_scene_getNodes: * @scene: a #VisuGlNodeScene object. * * Retrieve the #VisuGlExtNodes object used by @scene to render nodes. * * Since: 3.8 * * Returns: (transfer none): a #VisuGlExtNodes object. **/ VisuGlExtNodes* visu_gl_node_scene_getNodes(VisuGlNodeScene *scene) { g_return_val_if_fail(VISU_IS_GL_NODE_SCENE(scene), (VisuGlExtNodes*)0); return scene->priv->nodes; } /** * visu_gl_node_scene_getPairs: * @scene: a #VisuGlNodeScene object. * * Retrieve the #VisuGlExtPairs object used by @scene to render pairs. * * Since: 3.8 * * Returns: (transfer none): a #VisuGlExtPairs object. **/ VisuGlExtPairs* visu_gl_node_scene_getPairs(VisuGlNodeScene *scene) { g_return_val_if_fail(VISU_IS_GL_NODE_SCENE(scene), (VisuGlExtPairs*)0); return scene->priv->pairs; } /** * visu_gl_node_scene_getAxes: * @scene: a #VisuGlNodeScene object. * * Retrieve the #VisuGlExtAxes object used by @scene to render axes. * * Since: 3.8 * * Returns: (transfer none): a #VisuGlExtAxes object. **/ VisuGlExtAxes* visu_gl_node_scene_getAxes(VisuGlNodeScene *scene) { g_return_val_if_fail(VISU_IS_GL_NODE_SCENE(scene), (VisuGlExtAxes*)0); return scene->priv->axes; } /** * visu_gl_node_scene_getBox: * @scene: a #VisuGlNodeScene object. * * Retrieve the #VisuGlExtBox object used by @scene to render the box. * * Since: 3.8 * * Returns: (transfer none): a #VisuGlExtBox object. **/ VisuGlExtBox* visu_gl_node_scene_getBox(VisuGlNodeScene *scene) { g_return_val_if_fail(VISU_IS_GL_NODE_SCENE(scene), (VisuGlExtBox*)0); return scene->priv->box; } /** * visu_gl_node_scene_getBoxLegend: * @scene: a #VisuGlNodeScene object. * * Retrieve the #VisuGlExtBoxLegend object used by @scene to render * the lgened of the box. * * Since: 3.8 * * Returns: (transfer none): a #VisuGlExtBoxLegend object. **/ VisuGlExtBoxLegend* visu_gl_node_scene_getBoxLegend(VisuGlNodeScene *scene) { g_return_val_if_fail(VISU_IS_GL_NODE_SCENE(scene), (VisuGlExtBoxLegend*)0); return scene->priv->boxLegend; } /** * visu_gl_node_scene_getLegend: * @scene: a #VisuGlNodeScene object. * * Retrieve the #VisuGlExtLegend object used by @scene to render the * node legend. * * Since: 3.8 * * Returns: (transfer none): a #VisuGlExtLegend object. **/ VisuGlExtLegend* visu_gl_node_scene_getLegend(VisuGlNodeScene *scene) { g_return_val_if_fail(VISU_IS_GL_NODE_SCENE(scene), (VisuGlExtLegend*)0); return scene->priv->legend; } /** * visu_gl_node_scene_getBgImage: * @scene: a #VisuGlNodeScene object. * * Retrieve the #VisuGlExtBg object used by @scene to render images on * the background. * * Since: 3.8 * * Returns: (transfer none): a #VisuGlExtBg object. **/ VisuGlExtBg* visu_gl_node_scene_getBgImage(VisuGlNodeScene *scene) { g_return_val_if_fail(VISU_IS_GL_NODE_SCENE(scene), (VisuGlExtBg*)0); return scene->priv->bg; } /** * visu_gl_node_scene_getScales: * @scene: a #VisuGlNodeScene object. * * Retrieve the #VisuGlExtScale object used by @scene to render scales. * * Since: 3.8 * * Returns: (transfer none): a #VisuGlExtScale object. **/ VisuGlExtScale* visu_gl_node_scene_getScales(VisuGlNodeScene *scene) { g_return_val_if_fail(VISU_IS_GL_NODE_SCENE(scene), (VisuGlExtScale*)0); return scene->priv->scales; } /** * visu_gl_node_scene_getForces: * @scene: a #VisuGlNodeScene object. * * Retrieve the #VisuGlExtForces object used by @scene to render forces. * * Since: 3.8 * * Returns: (transfer none): a #VisuGlExtForces object. **/ VisuGlExtForces* visu_gl_node_scene_getForces(VisuGlNodeScene *scene) { g_return_val_if_fail(VISU_IS_GL_NODE_SCENE(scene), (VisuGlExtForces*)0); return scene->priv->forces; } /** * visu_gl_node_scene_getVibrations: * @scene: a #VisuGlNodeScene object. * * Retrieves the associated #VisuGlExtVibrations used to represent * periodic displacements of nodes. * * Since: 3.8 * * Returns: (transfer none): the attached #VisuGlExtVibrations, owned * by V_Sim. **/ VisuGlExtVibrations* visu_gl_node_scene_getVibrations(VisuGlNodeScene *scene) { g_return_val_if_fail(VISU_IS_GL_NODE_SCENE(scene), (VisuGlExtVibrations*)0); return scene->priv->vibrations; } /** * visu_gl_node_scene_getMarks: * @scene: a #VisuGlNodeScene object. * * Retrieve the #VisuGlExtMarks object used by @scene to render marks. * * Since: 3.8 * * Returns: (transfer none): a #VisuGlExtMarks object. **/ VisuGlExtMarks* visu_gl_node_scene_getMarks(VisuGlNodeScene *scene) { g_return_val_if_fail(VISU_IS_GL_NODE_SCENE(scene), (VisuGlExtMarks*)0); return scene->priv->marks; } /** * visu_gl_node_scene_getMarkActive: * @scene: a #VisuGlNodeScene obejct. * @nodeId: a node id. * * Tests if @nodeId from @scene has some marks on it. * * Since: 3.8 * * Returns: TRUE if @nodeId has some marks on it. **/ gboolean visu_gl_node_scene_getMarkActive(const VisuGlNodeScene *scene, guint nodeId) { g_return_val_if_fail(VISU_IS_GL_NODE_SCENE(scene), FALSE); return visu_gl_ext_marks_getActive(scene->priv->marks, nodeId); } /** * visu_gl_node_scene_setMark: * @scene: a #VisuGlNodeScene object. * @nodeId: a node id. * @status: a boolean. * * Display or removes marks on @nodeId, depending on @status. * * Since: 3.8 * * Returns: TRUE if @nodeId mark status changed. **/ gboolean visu_gl_node_scene_setMark(VisuGlNodeScene *scene, guint nodeId, gboolean status) { g_return_val_if_fail(VISU_IS_GL_NODE_SCENE(scene), FALSE); return visu_gl_ext_marks_setInfos(scene->priv->marks, nodeId, status); } /** * visu_gl_node_scene_removeMarks: * @scene: a #VisuGlNodeScene object. * * Remove all marks on @scene. * * Since: 3.8 **/ void visu_gl_node_scene_removeMarks(VisuGlNodeScene *scene) { g_return_if_fail(VISU_IS_GL_NODE_SCENE(scene)); visu_gl_ext_marks_removeMeasures(scene->priv->marks, -1); } /** * visu_gl_node_scene_colorizeShell: * @scene: a #VisuGlNodeScene object. * @nodeId: a node id. * * Apply colorization depending on neighbouring shell of @nodeId. * * Since: 3.8 * * Returns: (transfer none): the #VisuDataColorizerFragment used for * the colorization. **/ VisuDataColorizerFragment* visu_gl_node_scene_colorizeShell(VisuGlNodeScene *scene, gint nodeId) { VisuNodeValues *shell; VisuData *data; gboolean valid; g_return_val_if_fail(VISU_IS_GL_NODE_SCENE(scene), (VisuDataColorizerFragment*)0); data = _getData(scene); if (!data) return (VisuDataColorizerFragment*)0; if (!scene->priv->shellColorizer) { scene->priv->shellColorizer = visu_data_colorizer_fragment_new(); visu_gl_node_scene_addMasker(scene, VISU_NODE_MASKER(scene->priv->shellColorizer)); } shell = visu_data_getNodeProperties(data, "shell"); if (!shell) { shell = VISU_NODE_VALUES(visu_node_values_shell_new(VISU_NODE_ARRAY(data), "shell")); visu_data_addNodeProperties(data, shell); visu_sourceable_setNodeModel(VISU_SOURCEABLE(scene->priv->shellColorizer), shell); } valid = (nodeId >= 0); if (valid && visu_node_values_shell_getRoot(VISU_NODE_VALUES_SHELL(shell)) != nodeId) valid = visu_node_values_shell_compute(VISU_NODE_VALUES_SHELL(shell), nodeId, 0.2); if (visu_data_colorizer_getActive(VISU_DATA_COLORIZER(scene->priv->shellColorizer)) == valid) return valid ? scene->priv->shellColorizer : (VisuDataColorizerFragment*)0; visu_data_colorizer_setActive(VISU_DATA_COLORIZER(scene->priv->shellColorizer), valid); if (valid) visu_node_array_renderer_pushColorizer (VISU_NODE_ARRAY_RENDERER(scene->priv->nodes), VISU_DATA_COLORIZER(scene->priv->shellColorizer)); else visu_node_array_renderer_removeColorizer (VISU_NODE_ARRAY_RENDERER(scene->priv->nodes), VISU_DATA_COLORIZER(scene->priv->shellColorizer)); return valid ? scene->priv->shellColorizer : (VisuDataColorizerFragment*)0; } static void _applyMaskers(VisuGlNodeScene *scene) { gboolean redraw; GList *lst; VisuData *data; DBG_fprintf(stderr, "Visu Node Scene: applying %d maskers.\n", g_list_length(scene->priv->maskers)); data = _getData(scene); if (!data || !scene->priv->maskers) return; redraw = visu_maskable_resetVisibility(VISU_MASKABLE(data)); for (lst = scene->priv->maskers; lst; lst = g_list_next(lst)) visu_node_masker_apply(((struct _masker*)lst->data)->masker, &redraw, VISU_NODE_ARRAY(data)); if (redraw) visu_maskable_visibilityChanged(VISU_MASKABLE(data)); } /** * visu_gl_node_scene_addPlanes: * @scene: a #VisuGlNodeScene object. * * Add or retrieve the #VisuGlExtPlanes object used by @scene to render planes. * * Since: 3.8 * * Returns: (transfer none): a #VisuGlExtPlanes object. **/ VisuGlExtPlanes* visu_gl_node_scene_addPlanes(VisuGlNodeScene *scene) { VisuBox *box; g_return_val_if_fail(VISU_IS_GL_NODE_SCENE(scene), (VisuGlExtPlanes*)0); if (scene->priv->planes) return scene->priv->planes; scene->priv->planes = visu_gl_ext_planes_new((const gchar*)0); visu_gl_ext_set_add(VISU_GL_EXT_SET(scene), VISU_GL_EXT(scene->priv->planes)); visu_gl_node_scene_addMasker(scene, VISU_NODE_MASKER(scene->priv->planes->planes)); box = _getBox(VISU_BOXED(scene)); if (box) visu_gl_ext_planes_setBox(scene->priv->planes, box); scene->priv->planes_anim = g_signal_connect_swapped(scene->priv->planes->planes, "animate", G_CALLBACK(_onAnimate), scene); if (scene->priv->surfaces) visu_gl_ext_surfaces_setMask(scene->priv->surfaces, scene->priv->planes->planes); return scene->priv->planes; } /** * visu_gl_node_scene_addSurfaces: * @scene: a #VisuGlNodeScene object. * * Add or retrieve the #VisuGlExtSurfaces object used by @scene to render surfaces. * * Since: 3.8 * * Returns: (transfer none): a #VisuGlExtSurfaces object. **/ VisuGlExtSurfaces* visu_gl_node_scene_addSurfaces(VisuGlNodeScene *scene) { g_return_val_if_fail(VISU_IS_GL_NODE_SCENE(scene), (VisuGlExtSurfaces*)0); if (scene->priv->surfaces) return scene->priv->surfaces; scene->priv->surfaces = visu_gl_ext_surfaces_new((const gchar*)0); visu_gl_ext_set_add(VISU_GL_EXT_SET(scene), VISU_GL_EXT(scene->priv->surfaces)); if (scene->priv->planes) visu_gl_ext_surfaces_setMask(scene->priv->surfaces, scene->priv->planes->planes); return scene->priv->surfaces; } /** * visu_gl_node_scene_addMaps: * @scene: a #VisuGlNodeScene object. * @mapLegend: (out) (transfer none): a pointer to retrieve the associated #VisuGlExtShade * legend of the coloured map. * * Add or retrieve the #VisuGlExtMapSet object used by @scene to render maps. * * Since: 3.8 * * Returns: (transfer none): a #VisuGlExtMapSet object. **/ VisuGlExtMapSet* visu_gl_node_scene_addMaps(VisuGlNodeScene *scene, VisuGlExtShade **mapLegend) { g_return_val_if_fail(VISU_IS_GL_NODE_SCENE(scene), (VisuGlExtMapSet*)0); if (!scene->priv->maps) { scene->priv->maps = visu_gl_ext_map_set_new((const gchar*)0); visu_gl_ext_set_add(VISU_GL_EXT_SET(scene), VISU_GL_EXT(scene->priv->maps)); scene->priv->mapLegend = visu_gl_ext_map_set_getLegend(scene->priv->maps); g_object_ref(scene->priv->mapLegend); visu_gl_ext_set_add(VISU_GL_EXT_SET(scene), VISU_GL_EXT(scene->priv->mapLegend)); } if (mapLegend) *mapLegend = scene->priv->mapLegend; return scene->priv->maps; } /** * visu_gl_node_scene_dump: * @scene:a valid #VisuGlNodeScene object ; * @format: a #VisuDump object, corresponding to the write method ; * @fileName: (type filename): a string that defined the file to write to ; * @width: an integer, or 0 for current ; * @height: an integer, or 0 for current ; * @functionWait: (allow-none) (closure data) (scope call): a method to call * periodically during the dump ; * @data: (closure): some pointer on object to be passed to the wait function. * @error: a location to store some error (not NULL) ; * * Call this method to dump the given @scene to a file. * * Returns: TRUE if everything went right. */ gboolean visu_gl_node_scene_dump(VisuGlNodeScene *scene, VisuDump *format, const char* fileName, guint width, guint height, ToolVoidDataFunc functionWait, gpointer data, GError **error) { g_return_val_if_fail(VISU_IS_GL_NODE_SCENE(scene), FALSE); g_return_val_if_fail(error && !*error, FALSE); g_return_val_if_fail(format && fileName, FALSE); if (VISU_IS_DUMP_SCENE(format)) { DBG_fprintf(stderr, "Visu Node Scene: dumping current OpenGL area.\n"); DBG_fprintf(stderr, " | requested size %dx%d.\n", width, height); return visu_dump_scene_write(VISU_DUMP_SCENE(format), fileName, scene, width, height, functionWait, data, error); } else if (VISU_IS_DUMP_DATA(format)) { VisuData *data = _getData(scene); DBG_fprintf(stderr, "Visu Node Scene: dumping data only.\n"); if (!data) return FALSE; return visu_dump_data_write(VISU_DUMP_DATA(format), fileName, data, error); } return FALSE; } /** * visu_gl_node_scene_setMarksFromFile: * @scene: a #VisuGlNodeScene object. * @filename: a filename * @error: an error location. * * Try to parse @filename and put marks on nodes of @scene accordingly. * * Since: 3.8 * * Returns: TRUE on success. **/ gboolean visu_gl_node_scene_setMarksFromFile(VisuGlNodeScene *scene, const gchar *filename, GError **error) { GList *tmplst, *list; GArray *nodes; VisuGlExtInfosDrawId mode; guint info, i; g_return_val_if_fail(VISU_IS_GL_NODE_SCENE(scene), FALSE); if (!visu_gl_ext_marks_parseXMLFile(scene->priv->marks, filename, &list, &mode, &info, error)) return FALSE; nodes = (GArray*)0; if (mode == DRAW_SELECTED) { nodes = g_array_new(FALSE, FALSE, sizeof(guint)); for (tmplst = list; tmplst; tmplst = g_list_next(tmplst)) { if (GPOINTER_TO_INT(tmplst->data) == PICK_SELECTED) { tmplst = g_list_next(tmplst); i = GPOINTER_TO_INT(tmplst->data) - 1; g_array_append_val(nodes, i); } else if (GPOINTER_TO_INT(tmplst->data) == PICK_REFERENCE_1) { tmplst = g_list_next(tmplst); /* We add the last selection. */ tmplst = g_list_next(tmplst); i = GPOINTER_TO_INT(tmplst->data) - 1; g_array_append_val(nodes, i); } else if (GPOINTER_TO_INT(tmplst->data) == PICK_HIGHLIGHT) tmplst = g_list_next(tmplst); } g_list_free(list); } if (mode != DRAW_NEVER) { switch (info) { case 0: visu_gl_ext_infos_drawIds(scene->priv->infos, nodes); visu_gl_ext_setActive(VISU_GL_EXT(scene->priv->infos), TRUE); break; case 1: visu_gl_ext_infos_drawElements(scene->priv->infos, nodes); visu_gl_ext_setActive(VISU_GL_EXT(scene->priv->infos), TRUE); break; default: i = 2; for (tmplst = visu_data_getAllNodeProperties(_getData(scene)); tmplst; tmplst = g_list_next(tmplst)) { if (i == info) break; i += 1; } if (tmplst) { visu_gl_ext_infos_drawNodeProperties(scene->priv->infos, VISU_NODE_VALUES(tmplst->data), nodes); visu_gl_ext_setActive(VISU_GL_EXT(scene->priv->infos), TRUE); } break; } } if (nodes) g_array_unref(nodes); return TRUE; } /** * visu_gl_node_scene_marksToFile: * @scene: a #VisuGlNodeScene object. * @filename: a path. * @error: a error location. * * Export the current selection and marks into @filename. * * Since: 3.8 * * Returns: FALSE if an error occured. **/ gboolean visu_gl_node_scene_marksToFile(VisuGlNodeScene *scene, const gchar *filename, GError **error) { GArray *nodes; VisuGlExtInfosDrawId mode; guint info; gboolean valid; GList *tmplst; VisuNodeValues *values; g_return_val_if_fail(VISU_IS_GL_NODE_SCENE(scene), FALSE); g_object_get(scene->priv->infos, "selection", &nodes, "values", &values, NULL); if (!visu_gl_ext_getActive(VISU_GL_EXT(scene->priv->infos))) mode = DRAW_NEVER; else if (nodes) mode = DRAW_SELECTED; else mode = DRAW_ALWAYS; info = 0; if (values && VISU_IS_NODE_VALUES_ID(values)) info = 1; else if (values && VISU_IS_NODE_VALUES(values)) info = 2; else if (values) for (tmplst = visu_data_getAllNodeProperties(_getData(scene)), info = 3; tmplst; tmplst = g_list_next(tmplst)) { if (tmplst->data == values) break; info += 1; } valid = visu_gl_ext_marks_exportXMLFile(scene->priv->marks, filename, nodes, mode, info, error); if (nodes) g_array_unref(nodes); if (values) g_object_unref(values); return valid; } /** * visu_gl_node_scene_getInfos: * @scene: a #VisuGlNodeScene object. * * Retrieves the #VisuGlExtInfos object used by @scene to display info * on nodes. * * Since: 3.8 * * Returns: (transfer none): a #VisuGlExtInfos object. **/ VisuGlExtInfos* visu_gl_node_scene_getInfos(VisuGlNodeScene *scene) { g_return_val_if_fail(VISU_IS_GL_NODE_SCENE(scene), (VisuGlExtInfos*)0); return scene->priv->infos; } static void onEntryScale(VisuGlNodeScene *scene, VisuConfigFileEntry *entry, VisuConfigFile *obj _U_) { float xyz[3], orientation[3], len; float rg[2] = {-G_MAXFLOAT, G_MAXFLOAT}; float rgLen[2] = {0.f, G_MAXFLOAT}; gchar *legend; if (!visu_config_file_entry_popTokenAsFloat(entry, 3, xyz, rg)) return; if (!visu_config_file_entry_popTokenAsFloat(entry, 3, orientation, rg)) return; if (!visu_config_file_entry_popTokenAsFloat(entry, 1, &len, rgLen)) return; legend = visu_config_file_entry_popAllTokens(entry); g_strstrip(legend); visu_gl_ext_scale_add(scene->priv->scales, xyz, orientation, len, legend); g_free(legend); } /** * visu_gl_node_scene_setDiffFromLoadable: * @scene: a #VisuGlNodeScene object. * @ref: a #VisuData object. * @error: an error location. * * Same as visu_gl_node_scene_setDiffFromData(), but load first @ref * before doing the difference. * * Since: 3.8 * * Returns: TRUE on success. **/ gboolean visu_gl_node_scene_setDiffFromLoadable(VisuGlNodeScene *scene, VisuDataLoadable *ref, GError **error) { g_object_ref(ref); if (!visu_data_loadable_load(ref, 0, (GCancellable*)0, error)) { g_object_unref(ref); return FALSE; } visu_gl_node_scene_setDiffFromData(scene, VISU_DATA(ref)); g_object_unref(ref); return TRUE; } /** * visu_gl_node_scene_setDiffFromData: * @scene: a #VisuGlNodeScene object. * @dataRef: a #VisuData object. * * Creates a #VisuDataDiff from the current #VisuData and @dataRef. If * the scene is in recording mode (see "record-path" property), the * difference is appended to the current path. * * Since: 3.8 **/ void visu_gl_node_scene_setDiffFromData(VisuGlNodeScene *scene, const VisuData *dataRef) { VisuDataDiff *vect; VisuData *data; gboolean new; gdouble energy; data = _getData(scene); if (!data) return; vect = visu_data_diff_new(dataRef, data, scene->priv->reorder, VISU_DATA_DIFF_DEFAULT_ID); visu_sourceable_setNodeModel(VISU_SOURCEABLE(scene->priv->diff), VISU_NODE_VALUES(vect)); visu_gl_ext_node_vectors_setNodeRenderer(VISU_GL_EXT_NODE_VECTORS(scene->priv->diff), VISU_NODE_ARRAY_RENDERER(scene->priv->nodes)); if (vect && scene->priv->record) { g_object_get(data, "totalEnergy", &energy, NULL); new = visu_paths_addFromDiff(scene->priv->paths, vect, energy); if (new) visu_paths_constrainInBox(scene->priv->paths, data); visu_gl_ext_setDirty(VISU_GL_EXT(scene->priv->extPaths), TRUE); g_object_notify_by_pspec(G_OBJECT(scene), _properties[PATH_LENGTH_PROP]); } g_object_unref(vect); } /** * visu_gl_node_scene_getGeometryDifferences: * @scene: a #VisuGlNodeScene object. * * Retrieve the #VisuGlExtGeodiff used to draw geometry differences. * * Since: 3.8 * * Returns: (transfer none): a #VisuGlExtGeodiff object. **/ VisuGlExtGeodiff* visu_gl_node_scene_getGeometryDifferences(VisuGlNodeScene *scene) { g_return_val_if_fail(VISU_IS_GL_NODE_SCENE(scene), (VisuGlExtGeodiff*)0); return scene->priv->diff; } static void onDiffActive(VisuGlNodeScene *scene, GParamSpec *pspec _U_, VisuGlExtGeodiff *diff _U_) { g_object_notify_by_pspec(G_OBJECT(scene), _properties[DIFF_PROP]); } static void onPathActive(VisuGlNodeScene *scene, GParamSpec *pspec _U_, VisuGlExtPaths *paths _U_) { g_object_notify_by_pspec(G_OBJECT(scene), _properties[PATH_PROP]); } /** * visu_gl_node_scene_clearPaths: * @scene: a #VisuGlNodeScene object. * * Remove any #VisuPaths from @scene. * * Since: 3.8 **/ void visu_gl_node_scene_clearPaths(VisuGlNodeScene *scene) { g_return_if_fail(VISU_IS_GL_NODE_SCENE(scene)); if (!scene->priv->paths) return; visu_paths_empty(scene->priv->paths); visu_gl_ext_setDirty(VISU_GL_EXT(scene->priv->extPaths), TRUE); g_object_notify_by_pspec(G_OBJECT(scene), _properties[PATH_LENGTH_PROP]); } /** * visu_gl_node_scene_parsePathsFromXML: * @scene: a #VisuGlNodeScene object. * @filename: a filename. * @error: an error location. * * Try to parse @filename to load some #VisuPaths into @scene. * * Since: 3.8 * * Returns: TRUE on success. **/ gboolean visu_gl_node_scene_parsePathsFromXML(VisuGlNodeScene *scene, const gchar *filename, GError **error) { g_return_val_if_fail(VISU_IS_GL_NODE_SCENE(scene), FALSE); if (!scene->priv->paths) return FALSE; if (!visu_paths_parseFromXML(filename, scene->priv->paths, error)) return FALSE; visu_gl_ext_setDirty(VISU_GL_EXT(scene->priv->extPaths), TRUE); g_object_notify_by_pspec(G_OBJECT(scene), _properties[PATH_LENGTH_PROP]); return TRUE; } /** * visu_gl_node_scene_exportPathsToXML: * @scene: a #VisuGlNodeScene object. * @filename: a filename. * @error: an error location. * * If @scene has some #VisuPaths, it exports them to an XML file * defined by @filename. * * Since: 3.8 * * Returns: TRUE on success. **/ gboolean visu_gl_node_scene_exportPathsToXML(VisuGlNodeScene *scene, const gchar *filename, GError **error) { g_return_val_if_fail(VISU_IS_GL_NODE_SCENE(scene), FALSE); if (!scene->priv->paths) return TRUE; return visu_paths_exportXMLFile(scene->priv->paths, filename, error); } static gint _findMasker(const struct _masker *lst, const VisuNodeMasker *item) { if (lst->masker == item) return 0; return 1; } static struct _masker* _newMasker(VisuNodeMasker *masker, VisuGlNodeScene *scene) { struct _masker *str; str = g_malloc(sizeof(struct _masker)); str->masker = g_object_ref(masker); str->dirty_sig = g_signal_connect_swapped(masker, "masking-dirty", G_CALLBACK(_applyMaskers), scene); DBG_fprintf(stderr, "Visu Node Scene: connect signal %ld for %p.\n", str->dirty_sig, (gpointer)masker); return str; } static void _freeMasker(struct _masker *str) { DBG_fprintf(stderr, "Visu Node Scene: disconnect signal %ld for %p.\n", str->dirty_sig, (gpointer)str->masker); g_signal_handler_disconnect(str->masker, str->dirty_sig); g_object_unref(str->masker); g_free(str); } /** * visu_gl_node_scene_addMasker: * @scene: a #VisuGlNodeScene object. * @masker: a #VisuNodeMasker object. * * Add @masker to @scene, so when @masker is modified, #VisuNode of * @scene are hidden accordingly. * * Since: 3.8 * * Returns: FALSE if @masker already exists. **/ gboolean visu_gl_node_scene_addMasker(VisuGlNodeScene *scene, VisuNodeMasker *masker) { g_return_val_if_fail(VISU_IS_GL_NODE_SCENE(scene), FALSE); DBG_fprintf(stderr, "Visu Node Scene: add a new masker %p.\n", (gpointer)masker); if (g_list_find_custom(scene->priv->maskers, masker, (GCompareFunc)_findMasker)) return FALSE; scene->priv->maskers = g_list_prepend(scene->priv->maskers, _newMasker(masker, scene)); _applyMaskers(scene); return TRUE; } /** * visu_gl_node_scene_removeMasker: * @scene: a #VisuGlNodeScene object. * @masker: a #VisuNodeMasker object. * * Remove @masker from the list of objects that may hide nodes in @scene. * * Since: 3.8 * * Returns: TRUE on successful removal. **/ gboolean visu_gl_node_scene_removeMasker(VisuGlNodeScene *scene, VisuNodeMasker *masker) { GList *item; VisuData *data; g_return_val_if_fail(VISU_IS_GL_NODE_SCENE(scene), FALSE); DBG_fprintf(stderr, "Visu Node Scene: remove a masker %p.\n", (gpointer)masker); item = g_list_find_custom(scene->priv->maskers, masker, (GCompareFunc)_findMasker); if (!item) return FALSE; _freeMasker((struct _masker*)item->data); scene->priv->maskers = g_list_delete_link(scene->priv->maskers, item); data = _getData(scene); if (!scene->priv->maskers && data && visu_maskable_resetVisibility(VISU_MASKABLE(data))) visu_maskable_visibilityChanged(VISU_MASKABLE(data)); else _applyMaskers(scene); return TRUE; } static gint _findMover(const struct _mover *lst, const VisuNodeMover *item) { if (lst->mover == item) return 0; return 1; } static struct _mover* _newMover(VisuNodeMover *mover, VisuGlNodeScene *scene) { struct _mover *str; str = g_malloc(sizeof(struct _mover)); str->mover = g_object_ref(mover); str->animate_sig = g_signal_connect_swapped(mover, "animate", G_CALLBACK(_onAnimate), scene); str->bind = g_object_bind_property(scene, "data", mover, "nodes", G_BINDING_SYNC_CREATE); DBG_fprintf(stderr, "Visu Node Scene: connect signal %ld for %p.\n", str->animate_sig, (gpointer)mover); return str; } static void _freeMover(struct _mover *str) { DBG_fprintf(stderr, "Visu Node Scene: disconnect signal %ld for %p.\n", str->animate_sig, (gpointer)str->mover); g_signal_handler_disconnect(str->mover, str->animate_sig); g_object_unref(str->bind); g_object_unref(str->mover); g_free(str); } /** * visu_gl_node_scene_addMover: * @scene: a #VisuGlNodeScene object. * @mover: a #VisuNodeMover object. * * Add @mover to @scene. * * Since: 3.8 * * Returns: FALSE if @mover already exists. **/ gboolean visu_gl_node_scene_addMover(VisuGlNodeScene *scene, VisuNodeMover *mover) { g_return_val_if_fail(VISU_IS_GL_NODE_SCENE(scene), FALSE); DBG_fprintf(stderr, "Visu Node Scene: add a new mover %p.\n", (gpointer)mover); if (g_list_find_custom(scene->priv->movers, mover, (GCompareFunc)_findMover)) return FALSE; scene->priv->movers = g_list_prepend(scene->priv->movers, _newMover(mover, scene)); return TRUE; } /** * visu_gl_node_scene_removeMover: * @scene: a #VisuGlNodeScene object. * @mover: a #VisuNodeMover object. * * Remove @mover from the list of objects that may move nodes in @scene. * * Since: 3.8 * * Returns: TRUE on successful removal. **/ gboolean visu_gl_node_scene_removeMover(VisuGlNodeScene *scene, VisuNodeMover *mover) { GList *item; g_return_val_if_fail(VISU_IS_GL_NODE_SCENE(scene), FALSE); DBG_fprintf(stderr, "Visu Node Scene: remove a mover %p.\n", (gpointer)mover); item = g_list_find_custom(scene->priv->movers, mover, (GCompareFunc)_findMover); if (!item) return FALSE; _freeMover((struct _mover*)item->data); scene->priv->movers = g_list_delete_link(scene->priv->movers, item); return TRUE; } static void minMaxFromColorization(VisuGlNodeScene *scene) { float *mm = (float*)0; gboolean active; g_return_if_fail(VISU_IS_GL_NODE_SCENE(scene)); if (scene->priv->dt) g_object_get(G_OBJECT(scene->priv->dt), "single-range", &mm, NULL); active = scene->priv->dt && mm && visu_data_colorizer_getActive(VISU_DATA_COLORIZER(scene->priv->dt)) && visu_node_array_renderer_getColorizer (VISU_NODE_ARRAY_RENDERER(scene->priv->nodes)) == VISU_DATA_COLORIZER(scene->priv->dt); visu_gl_ext_setActive(VISU_GL_EXT(scene->priv->colorizationLegend), active); if (active) visu_gl_ext_shade_setMinMax(scene->priv->colorizationLegend, mm[0], mm[1]); if (mm) g_boxed_free(TOOL_TYPE_MINMAX, mm); } /** * visu_gl_node_scene_setColorization: * @scene: a #VisuGlNodeScene object. * @dt: (allow-none): a #VisuColorization object. * * Associates @dt with @scene to colorize nodes. * * Since: 3.8 * * Returns: TRUE if value is actually changed. **/ gboolean visu_gl_node_scene_setColorization(VisuGlNodeScene *scene, VisuColorization *dt) { VisuGlExtShade *legend; g_return_val_if_fail(VISU_IS_GL_NODE_SCENE(scene), FALSE); if (scene->priv->dt == dt) return FALSE; if (scene->priv->dt) { g_object_unref(scene->priv->bind_shade); visu_gl_node_scene_removeMasker(scene, VISU_NODE_MASKER(scene->priv->dt)); visu_node_array_renderer_removeColorizer (VISU_NODE_ARRAY_RENDERER(scene->priv->nodes), VISU_DATA_COLORIZER(scene->priv->dt)); g_signal_handler_disconnect(scene->priv->dt, scene->priv->single_sig); g_signal_handler_disconnect(scene->priv->dt, scene->priv->active_sig); g_signal_handler_disconnect(scene->priv->nodes, scene->priv->colorizer_sig); g_object_unref(scene->priv->dt); } if (dt) { g_object_ref(dt); visu_gl_node_scene_addMasker(scene, VISU_NODE_MASKER(dt)); visu_node_array_renderer_pushColorizer (VISU_NODE_ARRAY_RENDERER(scene->priv->nodes), VISU_DATA_COLORIZER(dt)); legend = visu_gl_node_scene_getColorizationLegend(scene); scene->priv->bind_shade = g_object_bind_property (dt, "shade", legend, "shade", G_BINDING_SYNC_CREATE); scene->priv->single_sig = g_signal_connect_swapped (G_OBJECT(dt), "notify::single-range", G_CALLBACK(minMaxFromColorization), scene); scene->priv->active_sig = g_signal_connect_swapped (G_OBJECT(dt), "notify::active", G_CALLBACK(minMaxFromColorization), scene); scene->priv->colorizer_sig = g_signal_connect_swapped (G_OBJECT(scene->priv->nodes), "notify::colorizer", G_CALLBACK(minMaxFromColorization), scene); } scene->priv->dt = dt; minMaxFromColorization(scene); return TRUE; } /** * visu_gl_node_scene_getColorization: * @scene: a #VisuGlNodeScene object. * * The attached #VisuColorization object, if any. * * Since: 3.8 * * Returns: (transfer none): a #VisuColorization object, or %NULL. **/ VisuColorization* visu_gl_node_scene_getColorization(VisuGlNodeScene *scene) { g_return_val_if_fail(VISU_IS_GL_NODE_SCENE(scene), (VisuColorization*)0); return scene->priv->dt; } /** * visu_gl_node_scene_getColorizationLegend: * @scene: a #VisuGlNodeScene object. * * Retrieve the #VisuGlExtShade object, used to represent the color * variation of an attached #VisuColorization object. The returned * object is created if none already exists. * * Since: 3.8 * * Returns: (transfer none): a #VisuGlExtShade. **/ VisuGlExtShade* visu_gl_node_scene_getColorizationLegend(VisuGlNodeScene *scene) { g_return_val_if_fail(VISU_IS_GL_NODE_SCENE(scene), (VisuGlExtShade*)0); if (!scene->priv->colorizationLegend) { scene->priv->colorizationLegend = visu_gl_ext_shade_new("Colorization legend"); visu_gl_ext_set_add(VISU_GL_EXT_SET(scene), VISU_GL_EXT(scene->priv->colorizationLegend)); } return scene->priv->colorizationLegend; } static void _applyColorizationPolicy(VisuGlNodeScene *scene) { VisuNodeValuesFarray *values; VisuNodeValues *old; VisuData *data; GError *error; gchar *dtFile, *file, *fileExtPosition; g_return_if_fail(VISU_IS_GL_NODE_SCENE(scene)); data = _getData(scene); values = (VisuNodeValuesFarray*)0; switch (scene->priv->dtPolicy) { case COLORIZATION_POLICY_FROM_FILE: if (!VISU_IS_DATA_LOADABLE(data)) return; file = g_strdup(visu_data_loadable_getFilename(VISU_DATA_LOADABLE(data), 0)); fileExtPosition = g_strrstr(file, "."); if (fileExtPosition) *fileExtPosition = '\0'; dtFile = g_strdup_printf("%s%s", file, scene->priv->dtFileExtension); g_free(file); error = (GError*)0; values = visu_node_values_farray_new_fromFile (VISU_NODE_ARRAY(data), VISU_COLORIZATION_LABEL, dtFile, &error); g_free(dtFile); if (error) { g_warning("%s", error->message); g_error_free(error); } if (!scene->priv->dt) { visu_gl_node_scene_setColorization(scene, visu_colorization_new()); g_object_unref(scene->priv->dt); } break; case COLORIZATION_POLICY_FROM_PREVIOUS: if (!scene->priv->dt) return; old = visu_sourceable_getNodeModel(VISU_SOURCEABLE(scene->priv->dt)); if (!old) return; values = visu_node_values_farray_new(VISU_NODE_ARRAY(data), visu_node_values_getLabel(old), visu_node_values_getDimension(old)); visu_node_values_copy(VISU_NODE_VALUES(values), old); break; default: return; } visu_colorization_setNodeModel(scene->priv->dt, values); if (values) { visu_data_removeNodeProperties (data, visu_node_values_getLabel(VISU_NODE_VALUES(values))); visu_data_addNodeProperties(data, VISU_NODE_VALUES(values)); } } /** * visu_gl_node_scene_setColorizationPolicy: * @scene: a #VisuGlNodeScene object. * @policy: a #VisuGlNodeSceneColorizationPolicies value. * * Specifies how the colorization should be modified when a new * #VisuData is associated to @scene. * * Since: 3.8 * * Returns: TRUE if value is actually changed. **/ gboolean visu_gl_node_scene_setColorizationPolicy(VisuGlNodeScene *scene, VisuGlNodeSceneColorizationPolicies policy) { g_return_val_if_fail(VISU_IS_GL_NODE_SCENE(scene), FALSE); if (scene->priv->dtPolicy == policy) return FALSE; scene->priv->dtPolicy = policy; g_object_notify_by_pspec(G_OBJECT(scene), _properties[AUTO_COLORIZATION_PROP]); return TRUE; } /** * visu_gl_node_scene_colorizeFragments: * @scene: a #VisuGlNodeScene object. * * Apply colorization depending on fragments if they are defined. * * Since: 3.8 * * Returns: (transfer none): the associated #VisuDataColorizerFragment * object. **/ VisuDataColorizerFragment* visu_gl_node_scene_colorizeFragments(VisuGlNodeScene *scene) { VisuNodeValues *frags; VisuData *data; g_return_val_if_fail(VISU_IS_GL_NODE_SCENE(scene), FALSE); data = _getData(scene); if (!data) return (VisuDataColorizerFragment*)0; if (!scene->priv->fragColorizer) { scene->priv->fragColorizer = visu_data_colorizer_fragment_new(); visu_gl_node_scene_addMasker(scene, VISU_NODE_MASKER(scene->priv->fragColorizer)); } frags = visu_data_getNodeProperties(data, _("Fragment")); visu_data_colorizer_fragment_setNodeModel(scene->priv->fragColorizer, VISU_NODE_VALUES_FRAG(frags)); visu_data_colorizer_setActive(VISU_DATA_COLORIZER(scene->priv->fragColorizer), frags != (VisuNodeValues*)0); if (frags != (VisuNodeValues*)0) visu_node_array_renderer_pushColorizer (VISU_NODE_ARRAY_RENDERER(scene->priv->nodes), VISU_DATA_COLORIZER(scene->priv->fragColorizer)); else visu_node_array_renderer_removeColorizer (VISU_NODE_ARRAY_RENDERER(scene->priv->nodes), VISU_DATA_COLORIZER(scene->priv->fragColorizer)); return visu_data_colorizer_getActive(VISU_DATA_COLORIZER(scene->priv->fragColorizer)) ? scene->priv->fragColorizer : (VisuDataColorizerFragment*)0; } /** * visu_gl_node_scene_getFragmentColorizer: * @scene: a #VisuGlNodeScene object. * * Retrieves the default fragment colorizer object of @scene. * * Since: 3.8 * * Returns: (transfer none): the default #VisuDataColorizerFragment. **/ VisuDataColorizerFragment* visu_gl_node_scene_getFragmentColorizer(VisuGlNodeScene *scene) { g_return_val_if_fail(VISU_IS_GL_NODE_SCENE(scene), (VisuDataColorizerFragment*)0); return scene->priv->fragColorizer; } gboolean _doTick(VisuGlNodeScene *scene) { GList *lst, *del; gulong msecs; gdouble secs; for (lst = scene->priv->animations; lst;) { secs = g_timer_elapsed(scene->priv->timer, &msecs); if (visu_animation_animate(VISU_ANIMATION(lst->data), msecs + (gulong)secs * 1e6)) lst = g_list_next(lst); else { del = lst; g_object_unref(del->data); if (del->prev) del->prev->next = g_list_next(del); else scene->priv->animations = g_list_next(del); lst = g_list_next(del); if (lst) lst->prev = del->prev; g_list_free_1(del); } } if (scene->priv->animations) return G_SOURCE_CONTINUE; g_timer_stop(scene->priv->timer); scene->priv->tickId = 0; return G_SOURCE_REMOVE; } static gboolean _onAnimate(VisuGlNodeScene *scene, VisuAnimation *anim, const GValue *to, gulong duration, gboolean loop, VisuAnimationType type) { gulong msecs; gdouble secs; g_return_val_if_fail(VISU_IS_GL_NODE_SCENE(scene), FALSE); DBG_fprintf(stderr, "Visu GlNodeScene: caught 'animate' signal.\n"); if ((scene->priv->animations == (GList*)0)) { g_timer_start(scene->priv->timer); scene->priv->tickId = g_timeout_add(15, (GSourceFunc)_doTick, scene); } if (!g_list_find(scene->priv->animations, anim)) scene->priv->animations = g_list_prepend(scene->priv->animations, g_object_ref(anim)); secs = g_timer_elapsed(scene->priv->timer, &msecs); return visu_animation_start(anim, to, msecs + (gulong)secs * 1e6, duration, loop, type); } static void exportParameters(GString *data, VisuData* dataObj _U_) { g_string_append_printf(data, "# %s\n", DESC_PARAMETER_FILEEXT); g_string_append_printf(data, "%s: %s\n\n", FLAG_PARAMETER_FILEEXT, fileExt); } /** * visu_gl_node_scene_applyCLI: * @scene: a #VisuGlNodeScene object to apply the options on ; * @error: a location for error report. * * Call all the get methods on the command line options to tune the * given @data. * * Returns: TRUE if complete without error. */ gboolean visu_gl_node_scene_applyCLI(VisuGlNodeScene *scene, GError **error) { gchar *planesFile, *surfFile; const GList *fieldFiles; int i, nb; gboolean somethingIsLoaded, valid; float *values; const gchar **names; const GList *it; GHashTable *table; VisuSurface *surf, *neg; VisuScalarfieldSetIter itField; ToolShade *shade; GList *surfsList, *lst; gint *mapPlaneId; VisuScalarField *field; ToolColor *color; VisuMap *map; VisuColorization *dt; const gchar *geoFile; VisuDataAtomic *geoRef; VisuData *data; g_return_val_if_fail(VISU_IS_GL_NODE_SCENE(scene), FALSE); g_return_val_if_fail(error && !*error, FALSE); data = _getData(scene); /* The shade option. */ shade = tool_pool_getById(tool_shade_getStorage(), MAX(commandLineGet_presetColor(), 0)); if (!shade) shade = tool_pool_getById(tool_shade_getStorage(), 0); /* Marks from file. */ if (commandLineGet_valueFile() && !visu_gl_node_scene_setMarksFromFile(scene, commandLineGet_valueFile(), error)) return FALSE; /* colorize argument */ dt = visu_colorization_new_fromCLI(data, error); if (error && *error) return FALSE; visu_gl_node_scene_setColorization(scene, dt); if (dt) g_object_unref(dt); visu_data_applyTransformationsFromCLI(data, error); if (error && *error) return FALSE; /* VisuPlanes argument. */ planesFile = commandLineGet_planesFileName() ? commandLineGet_planesFileName() : commandLineGet_valueFile(); if (planesFile) { DBG_fprintf(stderr, "Visu Basic: create plane extension.\n"); visu_gl_node_scene_addPlanes(scene); somethingIsLoaded = visu_plane_set_parseXMLFile(scene->priv->planes->planes, planesFile, error); if (!somethingIsLoaded) return FALSE; } /* Iso-surfaces arguments. */ surfFile = commandLineGet_isoVisuSurfaceFileName(); surfsList = (GList*)0; if (surfFile) { somethingIsLoaded = visu_surface_loadFile(surfFile, &surfsList, error); if (!somethingIsLoaded) return FALSE; else if (commandLineGet_fitToBox()) for (lst = surfsList; lst; lst = g_list_next(lst)) { g_object_set(lst->data, "auto-adjust", TRUE, NULL); visu_boxed_setBox(VISU_BOXED(lst->data), VISU_BOXED(data)); } } /* Scalar-field arguments. */ field = (VisuScalarField*)0; fieldFiles = commandLineGet_scalarFieldFileNames(); if (fieldFiles) { /* Create an option table for possible spin or complex modifiers. */ table = commandLineGet_options(); for (it = fieldFiles; it; it = g_list_next(it)) if (!visu_scalarfield_set_addFromFileSync (visu_scalarfield_set_getDefault(), NULL, (const gchar*)it->data, table, NULL, error)) return FALSE; visu_scalarfield_set_iter_new(visu_scalarfield_set_getDefault(), &itField); if (commandLineGet_fitToBox()) for (valid = visu_scalarfield_set_iter_next(&itField); valid; valid = visu_scalarfield_set_iter_next(&itField)) { g_object_set(G_OBJECT(itField.field), "auto-adjust", TRUE, NULL); visu_boxed_setBox(VISU_BOXED(itField.field), VISU_BOXED(data)); } values = commandLineGet_isoValues(&nb); names = commandLineGet_isoNames(&nb); visu_scalarfield_set_iter_new(visu_scalarfield_set_getDefault(), &itField); if (values) for (valid = visu_scalarfield_set_iter_next(&itField); valid; valid = visu_scalarfield_set_iter_next(&itField)) for (i = 0; i < nb; i++) { if (values[i] != G_MAXFLOAT) surf = visu_surface_new_fromScalarField(itField.field, values[i], names[i]); else { visu_surface_new_defaultFromScalarField(itField.field, &neg, &surf); if (neg) surfsList = g_list_append(surfsList, neg); } if (surf) surfsList = g_list_append(surfsList, surf); } field = visu_scalarfield_set_getAt(visu_scalarfield_set_getDefault(), 0); /* We may add the iso-values from a file. */ if (commandLineGet_valueFile() && field) { somethingIsLoaded = visu_surface_parseXMLFile(commandLineGet_valueFile(), &surfsList, field, error); if (!somethingIsLoaded) return FALSE; } } /* We create the surface extension. */ if (surfsList) { DBG_fprintf(stderr, "Visu Basic: create surface extension.\n"); visu_gl_node_scene_addSurfaces(scene); for (lst = surfsList; lst; lst = g_list_next(lst)) visu_gl_ext_surfaces_add(scene->priv->surfaces, VISU_SURFACE(lst->data)); g_list_free_full(surfsList, (GDestroyNotify)g_object_unref); } /* The coloured map argument. */ mapPlaneId = (gint*)commandLineGet_coloredMap(); if (mapPlaneId && !scene->priv->planes) g_warning(_("option '--build-map' has been given but" " no plane is available (use '--planes').")); else if (mapPlaneId && !field) g_warning(_("option '--build-map' has been given but" " no scalar field is available (use '--scalar-field').")); else if (mapPlaneId && !shade) g_warning(_("option '--build-map' has been given but" " no shade is available (use '--color-preset').")); else if (mapPlaneId && field && shade) { visu_gl_node_scene_addMaps(scene, NULL); visu_gl_ext_map_set_setField(scene->priv->maps, field); visu_gl_ext_map_set_setPrecision(scene->priv->maps, commandLineGet_mapPrecision()); visu_gl_ext_map_set_setShade(scene->priv->maps, shade); color = tool_color_new(commandLineGet_isoLinesColor()); visu_gl_ext_map_set_setLineColor(scene->priv->maps, color); g_free(color); visu_gl_ext_map_set_setLines(scene->priv->maps, commandLineGet_nIsoLines()); visu_gl_ext_map_set_setScaling(scene->priv->maps, commandLineGet_logScale()); visu_gl_ext_map_set_setScalingRange(scene->priv->maps, commandLineGet_mapMinMax()); for (i = 1; i <= mapPlaneId[0]; i++) { map = visu_gl_ext_map_set_addFromPlane(scene->priv->maps, visu_plane_set_getAt(scene->priv->planes->planes, mapPlaneId[i])); visu_map_compute_sync(map); } } /* We set the background image. */ visu_gl_ext_bg_setFile(scene->priv->bg, commandLineGet_bgImage(), error); if (error && *error) return FALSE; /* The geometry diff. */ geoFile = commandLineGet_geodiff(); if (geoFile) { geoRef = visu_data_atomic_new(geoFile, (VisuDataLoader*)0); if (!visu_gl_node_scene_setDiffFromLoadable(scene, VISU_DATA_LOADABLE(geoRef), error)) return FALSE; g_object_unref(geoRef); } return TRUE; } v_sim-3.8.0/src/visu_glnodescene.h000066400000000000000000000221541370110300500171250ustar00rootroot00000000000000/* EXTRAITS DE LA LICENCE Copyright CEA, contributeurs : Damien CALISTE, laboratoire L_Sim, (2016) Adresse mèl : CALISTE, damien P caliste AT cea P fr. Ce logiciel est un programme informatique servant à visualiser des structures atomiques dans un rendu pseudo-3D. Ce logiciel est régi par la licence CeCILL soumise au droit français et respectant les principes de diffusion des logiciels libres. Vous pouvez utiliser, modifier et/ou redistribuer ce programme sous les conditions de la licence CeCILL telle que diffusée par le CEA, le CNRS et l'INRIA sur le site "http://www.cecill.info". Le fait que vous puissiez accéder à cet en-tête signifie que vous avez pris connaissance de la licence CeCILL, et que vous en avez accepté les termes (cf. le fichier Documentation/licence.fr.txt fourni avec ce logiciel). */ /* LICENCE SUM UP Copyright CEA, contributors : Damien CALISTE, laboratoire L_Sim, (2016) E-mail address: CALISTE, damien P caliste AT cea P fr. This software is a computer program whose purpose is to visualize atomic configurations in 3D. This software is governed by the CeCILL license under French law and abiding by the rules of distribution of free software. You can use, modify and/ or redistribute the software under the terms of the CeCILL license as circulated by CEA, CNRS and INRIA at the following URL "http://www.cecill.info". The fact that you are presently reading this means that you have had knowledge of the CeCILL license and that you accept its terms. You can find a copy of this licence shipped with this software at Documentation/licence.en.txt. */ #ifndef VISU_GL_NODE_SCENE_H #define VISU_GL_NODE_SCENE_H #include #include #include "visu_dump.h" #include "visu_extset.h" #include "visu_dataloadable.h" #include "iface_nodemasker.h" #include "openGLFunctions/view.h" #include "extensions/marks.h" #include "extensions/pairs.h" #include "extensions/planes.h" #include "extensions/surfs.h" #include "extensions/mapset.h" #include "extensions/axes.h" #include "extensions/box.h" #include "extensions/box_legend.h" #include "extensions/legend.h" #include "extensions/fogAndBGColor.h" #include "extensions/scale.h" #include "extensions/forces.h" #include "extensions/vibrations.h" #include "extensions/geodiff.h" #include "extraFunctions/dataFile.h" #include "extraFunctions/fragColorizer.h" #include "extraFunctions/mover.h" G_BEGIN_DECLS /***************/ /* Public part */ /***************/ /** * VisuGlNodeSceneColorizationPolicies: * @COLORIZATION_POLICY_NONE: no policy. * @COLORIZATION_POLICY_FROM_FILE: try to load colourisation data from * file matching file name. * @COLORIZATION_POLICY_FROM_PREVIOUS: copy previous colourisation * data to new #VisuData. * * The different policies to apply when a new #VisuData is associated to * a #VisuGlNodeScene object. * * Since: 3.8 */ typedef enum { COLORIZATION_POLICY_NONE, COLORIZATION_POLICY_FROM_FILE, COLORIZATION_POLICY_FROM_PREVIOUS, /*< private >*/ COLORIZATION_N_POLICIES } VisuGlNodeSceneColorizationPolicies; /** * VISU_TYPE_GL_NODE_SCENE: * * return the type of #VisuGlNodeScene. */ #define VISU_TYPE_GL_NODE_SCENE (visu_gl_node_scene_get_type ()) /** * VISU_GL_NODE_SCENE: * @obj: a #GObject to cast. * * Cast the given @obj into #VisuGlNodeScene type. */ #define VISU_GL_NODE_SCENE(obj) (G_TYPE_CHECK_INSTANCE_CAST(obj, VISU_TYPE_GL_NODE_SCENE, VisuGlNodeScene)) /** * VISU_GL_NODE_SCENE_CLASS: * @klass: a #GObjectClass to cast. * * Cast the given @klass into #VisuGlNodeSceneClass. */ #define VISU_GL_NODE_SCENE_CLASS(klass) (G_TYPE_CHECK_CLASS_CAST(klass, VISU_TYPE_GL_NODE_SCENE, VisuGlNodeSceneClass)) /** * VISU_IS_GL_NODE_SCENE: * @obj: a #GObject to test. * * Test if the given @ogj is of the type of #VisuGlNodeScene object. */ #define VISU_IS_GL_NODE_SCENE(obj) (G_TYPE_CHECK_INSTANCE_TYPE(obj, VISU_TYPE_GL_NODE_SCENE)) /** * VISU_IS_GL_NODE_SCENE_CLASS: * @klass: a #GObjectClass to test. * * Test if the given @klass is of the type of #VisuGlNodeSceneClass class. */ #define VISU_IS_GL_NODE_SCENE_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE(klass, VISU_TYPE_GL_NODE_SCENE)) /** * VISU_GL_NODE_SCENE_GET_CLASS: * @obj: a #GObject to get the class of. * * It returns the class of the given @obj. */ #define VISU_GL_NODE_SCENE_GET_CLASS(obj) (G_TYPE_INSTANCE_GET_CLASS(obj, VISU_TYPE_GL_NODE_SCENE, VisuGlNodeSceneClass)) typedef struct _VisuGlNodeScenePrivate VisuGlNodeScenePrivate; /** * VisuGlNodeScene: * * Common name to refer to a #_VisuGlNodeScene. */ typedef struct _VisuGlNodeScene VisuGlNodeScene; struct _VisuGlNodeScene { VisuGlExtSet parent; VisuGlNodeScenePrivate *priv; }; /** * VisuGlNodeSceneClass: * @parent: private. * * Common name to refer to a #_VisuGlNodeSceneClass. */ typedef struct _VisuGlNodeSceneClass VisuGlNodeSceneClass; struct _VisuGlNodeSceneClass { VisuGlExtSetClass parent; }; GType visu_gl_node_scene_get_type(void); VisuGlNodeScene* visu_gl_node_scene_new(); gboolean visu_gl_node_scene_applyCLI(VisuGlNodeScene *scene, GError **error); gboolean visu_gl_node_scene_dump(VisuGlNodeScene *scene, VisuDump *format, const char* fileName, guint width, guint height, ToolVoidDataFunc functionWait, gpointer data, GError **error); gboolean visu_gl_node_scene_setData(VisuGlNodeScene *scene, VisuData *data); gboolean visu_gl_node_scene_loadData(VisuGlNodeScene *scene, VisuDataLoadable *loadable, guint iSet, GCancellable *cancel, GError **error); VisuData* visu_gl_node_scene_getData(VisuGlNodeScene *scene); gboolean visu_gl_node_scene_setColorization(VisuGlNodeScene *scene, VisuColorization *dt); VisuColorization* visu_gl_node_scene_getColorization(VisuGlNodeScene *scene); gboolean visu_gl_node_scene_setColorizationPolicy(VisuGlNodeScene *scene, VisuGlNodeSceneColorizationPolicies policy); VisuDataColorizerFragment* visu_gl_node_scene_getFragmentColorizer(VisuGlNodeScene *scene); VisuGlView* visu_gl_node_scene_getGlView(VisuGlNodeScene *scene); void visu_gl_node_scene_setGlCamera(VisuGlNodeScene *scene, VisuGlCamera *camera); VisuGlExtNodes* visu_gl_node_scene_getNodes(VisuGlNodeScene *scene); VisuGlExtPairs* visu_gl_node_scene_getPairs(VisuGlNodeScene *scene); VisuGlExtAxes* visu_gl_node_scene_getAxes(VisuGlNodeScene *scene); VisuGlExtBox* visu_gl_node_scene_getBox(VisuGlNodeScene *scene); VisuGlExtBoxLegend* visu_gl_node_scene_getBoxLegend(VisuGlNodeScene *scene); VisuGlExtLegend* visu_gl_node_scene_getLegend(VisuGlNodeScene *scene); VisuGlExtBg* visu_gl_node_scene_getBgImage(VisuGlNodeScene *scene); VisuGlExtScale* visu_gl_node_scene_getScales(VisuGlNodeScene *scene); VisuGlExtForces* visu_gl_node_scene_getForces(VisuGlNodeScene *scene); VisuGlExtVibrations* visu_gl_node_scene_getVibrations(VisuGlNodeScene *scene); VisuGlExtShade* visu_gl_node_scene_getColorizationLegend(VisuGlNodeScene *scene); VisuGlExtGeodiff* visu_gl_node_scene_getGeometryDifferences(VisuGlNodeScene *scene); VisuGlExtPlanes* visu_gl_node_scene_addPlanes(VisuGlNodeScene *scene); VisuGlExtSurfaces* visu_gl_node_scene_addSurfaces(VisuGlNodeScene *scene); VisuGlExtMapSet* visu_gl_node_scene_addMaps(VisuGlNodeScene *scene, VisuGlExtShade **mapLegend); VisuGlExtMarks* visu_gl_node_scene_getMarks(VisuGlNodeScene *scene); gboolean visu_gl_node_scene_setMarksFromFile(VisuGlNodeScene *scene, const gchar *filename, GError **error); gboolean visu_gl_node_scene_marksToFile(VisuGlNodeScene *scene, const gchar *filename, GError **error); gboolean visu_gl_node_scene_getMarkActive(const VisuGlNodeScene *scene, guint nodeId); gboolean visu_gl_node_scene_setMark(VisuGlNodeScene *scene, guint nodeId, gboolean status); VisuDataColorizerFragment* visu_gl_node_scene_colorizeShell(VisuGlNodeScene *scene, gint nodeId); VisuDataColorizerFragment* visu_gl_node_scene_colorizeFragments(VisuGlNodeScene *scene); void visu_gl_node_scene_removeMarks(VisuGlNodeScene *scene); VisuGlExtInfos* visu_gl_node_scene_getInfos(VisuGlNodeScene *scene); gboolean visu_gl_node_scene_setDiffFromLoadable(VisuGlNodeScene *scene, VisuDataLoadable *ref, GError **error); void visu_gl_node_scene_setDiffFromData(VisuGlNodeScene *scene, const VisuData *dataRef); void visu_gl_node_scene_clearPaths(VisuGlNodeScene *scene); gboolean visu_gl_node_scene_parsePathsFromXML(VisuGlNodeScene *scene, const gchar *filename, GError **error); gboolean visu_gl_node_scene_exportPathsToXML(VisuGlNodeScene *scene, const gchar *filename, GError **error); gboolean visu_gl_node_scene_addMasker(VisuGlNodeScene *scene, VisuNodeMasker *masker); gboolean visu_gl_node_scene_removeMasker(VisuGlNodeScene *scene, VisuNodeMasker *masker); gboolean visu_gl_node_scene_addMover(VisuGlNodeScene *scene, VisuNodeMover *mover); gboolean visu_gl_node_scene_removeMover(VisuGlNodeScene *scene, VisuNodeMover *mover); G_END_DECLS #endif v_sim-3.8.0/src/visu_gtk.c000066400000000000000000000437521370110300500154260ustar00rootroot00000000000000/* EXTRAITS DE LA LICENCE Copyright CEA, contributeurs : Luc BILLARD et Damien CALISTE, laboratoire L_Sim, (2001-2005) Adresse mèl : BILLARD, non joignable par mèl ; CALISTE, damien P caliste AT cea P fr. Ce logiciel est un programme informatique servant à visualiser des structures atomiques dans un rendu pseudo-3D. Ce logiciel est régi par la licence CeCILL soumise au droit français et respectant les principes de diffusion des logiciels libres. Vous pouvez utiliser, modifier et/ou redistribuer ce programme sous les conditions de la licence CeCILL telle que diffusée par le CEA, le CNRS et l'INRIA sur le site "http://www.cecill.info". Le fait que vous puissiez accéder à cet en-tête signifie que vous avez pris connaissance de la licence CeCILL, et que vous en avez accepté les termes (cf. le fichier Documentation/licence.fr.txt fourni avec ce logiciel). */ /* LICENCE SUM UP Copyright CEA, contributors : Luc BILLARD et Damien CALISTE, laboratoire L_Sim, (2001-2005) E-mail address: BILLARD, not reachable any more ; CALISTE, damien P caliste AT cea P fr. This software is a computer program whose purpose is to visualize atomic configurations in 3D. This software is governed by the CeCILL license under French law and abiding by the rules of distribution of free software. You can use, modify and/ or redistribute the software under the terms of the CeCILL license as circulated by CEA, CNRS and INRIA at the following URL "http://www.cecill.info". The fact that you are presently reading this means that you have had knowledge of the CeCILL license and that you accept its terms. You can find a copy of this licence shipped with this software at Documentation/licence.en.txt. */ #include #ifdef HAVE_LIBGTKGLEXT_X11_1_0 #include #endif #include /* For the access markers R_OK, W_OK ... */ #include #include "support.h" #include "opengl.h" #include "visu_gtk.h" #include "visu_basic.h" #include "visu_commandLine.h" #include "visu_extension.h" #include "visu_plugins.h" #include "coreTools/toolShade.h" #include "coreTools/toolConfigFile.h" #include "extraFunctions/plane.h" #include "extraFunctions/dataFile.h" #include "panelModules/panelSurfaces.h" #include "gtk_renderingWindowWidget.h" #include "extraGtkFunctions/gtk_colorComboBoxWidget.h" #include "OSOpenGL/visu_openGL.h" #include "visu_extset.h" #include "extensions/nodes.h" #include "extensions/box.h" #include "extensions/scale.h" #include /** * SECTION: visu_gtk * @short_description: Basic GUI routines, standard * dialogs... * * There are some common UI routines here. Error messages can be * displayed via dialogs, see visu_ui_raiseWarning()... */ /* This hashtable associate a #RenderingMethod with a Gtk dialog to choose files. */ static GHashTable *visuGtkLoadMethods = NULL; static GtkWindow *visuGtkPanel; static GtkWindow *visuGtkRender; static GtkWidget *visuGtkRenderArea = (GtkWidget*)0; /* Local routines. */ static void initVisuGtk(); /** * visu_ui_raiseWarning: * @action: a string ; * @message: another string ; * @window: (allow-none): the parent window to raise the warning on. * * Raise a warning window with the action in bold and the message written * underneath. */ void visu_ui_raiseWarning(gchar *action, gchar *message, GtkWindow *window) { GtkWidget *alert; gchar *str; if (!window) window = visuGtkRender; DBG_fprintf(stderr, "Visu Gtk: raise the error dialog (parent %p).\n", (gpointer)window); #if GTK_MAJOR_VERSION > 2 || GTK_MINOR_VERSION > 5 str = action; #else str = message; #endif alert = gtk_message_dialog_new(GTK_WINDOW(window), GTK_DIALOG_MODAL | GTK_DIALOG_DESTROY_WITH_PARENT, GTK_MESSAGE_WARNING, GTK_BUTTONS_OK, "%s", str); gtk_window_set_title(GTK_WINDOW(alert), _("V_Sim error message")); #if GTK_MAJOR_VERSION > 2 || GTK_MINOR_VERSION > 5 gtk_widget_set_name(alert, "error"); #else gtk_widget_set_name(alert, action); #endif #if GTK_MAJOR_VERSION > 2 || GTK_MINOR_VERSION > 5 gtk_message_dialog_format_secondary_text(GTK_MESSAGE_DIALOG(alert), "%s", message); #endif gtk_widget_show_all(alert); /* block in a loop waiting for reply. */ gtk_dialog_run(GTK_DIALOG(alert)); gtk_widget_destroy(alert); } /** * visu_ui_raiseWarningLong: * @action: a string ; * @message: another string ; * @window: the parent window to raise the warning on. * * Same as visu_ui_raiseWarning() except that the message is displayed * in a text buffer, ideal for a log. */ void visu_ui_raiseWarningLong(gchar *action, gchar *message, GtkWindow *window) { GtkWidget *alert; GtkWidget *text, *scroll; GtkTextBuffer *buf; if (!window) window = visuGtkRender; alert = gtk_message_dialog_new(GTK_WINDOW(window), GTK_DIALOG_MODAL | GTK_DIALOG_DESTROY_WITH_PARENT, GTK_MESSAGE_WARNING, GTK_BUTTONS_OK, "%s", action); gtk_window_set_resizable(GTK_WINDOW(alert), TRUE); gtk_widget_set_name(alert, "error"); #if GTK_MAJOR_VERSION > 2 || GTK_MINOR_VERSION > 5 gtk_message_dialog_format_secondary_text(GTK_MESSAGE_DIALOG(alert), _("Output errors:")); #endif scroll = gtk_scrolled_window_new((GtkAdjustment*)0, (GtkAdjustment*)0); gtk_widget_set_size_request(scroll, 300, 200); gtk_scrolled_window_set_policy(GTK_SCROLLED_WINDOW(scroll), GTK_POLICY_AUTOMATIC, GTK_POLICY_AUTOMATIC); gtk_scrolled_window_set_shadow_type(GTK_SCROLLED_WINDOW(scroll), GTK_SHADOW_ETCHED_IN); gtk_box_pack_start(GTK_BOX(gtk_dialog_get_content_area(GTK_DIALOG(alert))), scroll, TRUE, TRUE, 2); text = gtk_text_view_new(); gtk_text_view_set_editable(GTK_TEXT_VIEW(text), FALSE); gtk_text_view_set_cursor_visible(GTK_TEXT_VIEW(text), FALSE); gtk_container_add(GTK_CONTAINER(scroll), text); buf = gtk_text_view_get_buffer (GTK_TEXT_VIEW(text)); gtk_text_buffer_set_text(GTK_TEXT_BUFFER(buf), message, -1); gtk_widget_show_all(alert); /* block in a loop waiting for reply. */ gtk_dialog_run (GTK_DIALOG (alert)); gtk_widget_destroy(alert); } /** * visu_ui_wait: * * It runs the Gtk event loop, flushing it before returning. */ void visu_ui_wait(void) { while(gtk_events_pending()) gtk_main_iteration(); } /** * visu_ui_createInterface: * @panel: always NULL here. * @renderWindow: a location for a #GtkWindow ; * @renderArea: a location for a #GtkWidget. * * A convenient routine that creates a #VisuUiRenderingWindow alone. To * create also a command panel, visu_ui_main_class_createMain() should be * used instead. */ void visu_ui_createInterface(GtkWindow **panel, GtkWindow **renderWindow, GtkWidget **renderArea) { int width, height; /* Force the creation of the Scale class. */ commandLineGet_XWindowGeometry(&width, &height); DBG_fprintf(stderr,"Visu Gtk: create a rendering window (%dx%d).\n", width, height); *renderArea = visu_ui_rendering_window_new(width, height, FALSE, TRUE); *renderWindow = GTK_WINDOW(visu_ui_buildRenderingWindow(VISU_UI_RENDERING_WINDOW(*renderArea))); g_signal_connect(G_OBJECT(*renderWindow), "delete-event", G_CALLBACK(gtk_main_quit), (gpointer)0); g_signal_connect(G_OBJECT(*renderWindow), "destroy-event", G_CALLBACK(gtk_main_quit), (gpointer)0); g_object_bind_property(*renderArea, "label", *renderWindow, "title", G_BINDING_SYNC_CREATE); gtk_widget_show(GTK_WIDGET(*renderWindow)); *panel = (GtkWindow*)0; return; } /** * visu_ui_buildRenderingWindow: * @renderWindow: a #VisuUiRenderingWindow object. * * Create a #GtkWindow with V_sim render window icon and wmclass set * to "V_Sim:v_sim_render". It also set the accelerators of * @renderWindow to the newly created window and pack @renderWindow inside. * * Returns: (transfer full): a newly created #GtkWindow. * * Since: 3.7 **/ GtkWidget* visu_ui_buildRenderingWindow(VisuUiRenderingWindow *renderWindow) { GtkWidget *window; const gchar *window_name = "v_sim_render"; const gchar *class_name = "V_Sim"; GdkPixbuf *iconPixBuf; /* We create the rendering window. */ window = gtk_window_new(GTK_WINDOW_TOPLEVEL); gtk_window_set_title(GTK_WINDOW(window), class_name); #if GTK_MAJOR_VERSION == 3 && GTK_MINOR_VERSION < 14 gtk_window_set_has_resize_grip(GTK_WINDOW(window), FALSE); #endif #if GTK_MAJOR_VERSION < 3 || (GTK_MAJOR_VERSION == 3 && GTK_MINOR_VERSION < 22) gtk_window_set_wmclass(GTK_WINDOW(window), window_name, class_name); #else gtk_window_set_role(GTK_WINDOW(window), window_name); #endif iconPixBuf = gdk_pixbuf_new_from_xpm_data((const char**)icone_observe_xpm); gtk_window_set_icon(GTK_WINDOW(window), iconPixBuf); g_object_unref(iconPixBuf); gtk_window_add_accel_group(GTK_WINDOW(window), visu_ui_rendering_window_getAccelGroup(renderWindow)); gtk_container_add(GTK_CONTAINER(window), GTK_WIDGET(renderWindow)); return window; } static void initVisuGtk(void) { visuGtkLoadMethods = g_hash_table_new_full(g_direct_hash, g_direct_equal, NULL, g_free); } /** * visu_ui_mainCreate: * @panelFunc: (scope call): function to be called to create the different windows. * * It initializses the GTK part of V_Sim. During this initialisation, * the @panelFunc is called. It should create all the windows needed * by V_Sim, like the command panel and the rendering area. The return * widget is the widget returned itself by @panelFunc. It must be the * main widget: it is the command panel if used, the window containing * the rendering area if no command panel or the rendering area itself * if no container window. */ void visu_ui_mainCreate(VisuUiInitWidgetFunc panelFunc) { GError *error; g_return_if_fail(panelFunc); if (!visuGtkLoadMethods) initVisuGtk(); panelFunc(&visuGtkPanel, &visuGtkRender, &visuGtkRenderArea); g_return_if_fail(visuGtkRender && visuGtkRenderArea); DBG_fprintf(stderr,"--- Initialising plugins ---\n"); error = (GError*)0; visu_plugins_init(&error); if (error) { visu_ui_raiseWarningLong(_("Loading plug-ins"), error->message, visuGtkRender); g_clear_error(&error); } if (!visu_basic_parseConfigFiles(&error)) { visu_ui_raiseWarningLong(_("Reading the configuration files"), error->message, visuGtkRender); g_clear_error(&error); } return; } /** * visu_ui_runCommandLine: * @data: a pointer to the command panel (see #VisuUiMain). * * Call the get routines from the command line module and deal with * them. This method is not aware of the panels and is intended to be * called only when the command panel is not used. In the opposite * case, use visu_ui_main_runCommandLine() instead. * * Returns: FALSE always. */ gboolean visu_ui_runCommandLine(gpointer data _U_) { VisuGlNodeScene *scene; GError *error; scene = visu_ui_rendering_window_getGlScene(VISU_UI_RENDERING_WINDOW(visuGtkRenderArea)); error = (GError*)0; if (!visu_gl_node_scene_applyCLI(scene, &error)) { visu_ui_raiseWarning(_("Parsing command line"), error->message, (GtkWindow*)0); g_error_free(error); } return FALSE; } /** * visu_ui_createFilter: * @list: (element-type ToolFileFormat*): a GList of #ToolFileFormat ; * @fileChooser: a file chooser to associate filters with. * * Create a list of GtkFileFilter created from the given list of file formats * and attach it to the given @fileChooser. * * Returns: (element-type VisuUiFileFilter) (transfer full): a list of * #VisuUiFileFilter. This list should be freed after use. */ GList* visu_ui_createFilter(GList *list, GtkWidget *fileChooser) { GtkFileFilter *filter, *filterAll; GList *tmpLst; const GList *tmpLst2; const char *name; VisuUiFileFilter *data; GList *returnedFilters; DBG_fprintf(stderr, "Visu Gtk: creating list of filters.\n"); returnedFilters = (GList*)0; filterAll = gtk_file_filter_new (); gtk_file_filter_set_name(filterAll, _("All supported formats")); for (tmpLst = list; tmpLst; tmpLst = g_list_next(tmpLst)) { filter = gtk_file_filter_new (); name = tool_file_format_getLabel((ToolFileFormat*)tmpLst->data); if (name) gtk_file_filter_set_name(filter, name); else gtk_file_filter_set_name(filter, _("No description")); for (tmpLst2 = tool_file_format_getFilePatterns((ToolFileFormat*)tmpLst->data); tmpLst2; tmpLst2 = g_list_next(tmpLst2)) { gtk_file_filter_add_pattern (filter, (gchar*)tmpLst2->data); gtk_file_filter_add_pattern (filterAll, (gchar*)tmpLst2->data); } data = g_malloc(sizeof(VisuUiFileFilter)); data->gtkFilter = filter; data->visuFilter = (ToolFileFormat*)tmpLst->data; returnedFilters = g_list_append(returnedFilters, (gpointer)data); } data = g_malloc(sizeof(VisuUiFileFilter)); data->gtkFilter = filterAll; data->visuFilter = (ToolFileFormat*)0; returnedFilters = g_list_append(returnedFilters, (gpointer)data); filter = gtk_file_filter_new (); gtk_file_filter_set_name(filter, _("All files")); gtk_file_filter_add_pattern (filter, "*"); data = g_malloc(sizeof(VisuUiFileFilter)); data->gtkFilter = filter; data->visuFilter = (ToolFileFormat*)0; returnedFilters = g_list_append(returnedFilters, (gpointer)data); DBG_fprintf(stderr, "Gtk Main : attach list to the given filechooser.\n"); tmpLst = returnedFilters; while(tmpLst) { gtk_file_chooser_add_filter(GTK_FILE_CHOOSER(fileChooser), ((VisuUiFileFilter*)tmpLst->data)->gtkFilter); tmpLst = g_list_next(tmpLst); } gtk_file_chooser_set_filter(GTK_FILE_CHOOSER(fileChooser), filterAll); return returnedFilters; } /** * visu_ui_createPixbuf: * @filename: (type filename): a file name (must be a base name). * * Replace the create_pixbuf() routine from Glade. It looks only in * the default pixmap directory of V_Sim to find the given file. * * Returns: (transfer full): a newly created GdkPixbuf on success. */ GdkPixbuf* visu_ui_createPixbuf(const gchar *filename) { gchar *pathname = NULL; GdkPixbuf *pixbuf; GError *error = NULL; g_return_val_if_fail(filename && filename[0], (GdkPixbuf*)0); pathname = g_build_filename(V_SIM_PIXMAPS_DIR, filename, NULL); pixbuf = gdk_pixbuf_new_from_file(pathname, &error); if (!pixbuf) { g_warning(_("failed to load pixbuf file '%s': %s\n"), pathname, error->message); g_error_free(error); } g_free(pathname); return pixbuf; } /** * visu_ui_getRenderWindow: * * A convenient function to get the rendering area window. * * Returns: (transfer none): a #GtkWindow. */ GtkWindow* visu_ui_getRenderWindow(void) { return visuGtkRender; } /** * visu_ui_getPanel: * * A convenient function to get the command panel window. * * Returns: (transfer none): a #GtkWindow. */ GtkWindow* visu_ui_getPanel(void) { return visuGtkPanel; } /** * visu_ui_getRenderWidget: * * A convenient function to get the rendering area widget. * * Returns: (transfer none): a #GtkWidget. */ GtkWidget* visu_ui_getRenderWidget(void) { return visuGtkRenderArea; } /** * visu_ui_setRenderWidget: * @render: a #VisuUiRenderingWindow widget. * * A convenient function to set the rendering area widget. * * Since: 3.7 */ void visu_ui_setRenderWidget(VisuUiRenderingWindow *render) { visuGtkRenderArea = GTK_WIDGET(render); } /* Store a tree model to remember colors. */ #define COLOR_BOX_WIDTH 16 #define COLOR_BOX_HEIGHT 16 #define COLOR_BOX_BITS 8 /** * tool_color_get_stamp: * @color: a #ToolColor object ; * @alpha: a boolean. * * This method is used by #VisuUiColorCombobox object to create little stamps * representing the color. If the pixbuf of such stamps are needed, use * visu_ui_color_combobox_getPixbufFromColor() if the color is registered in an * already existing #VisuUiColorCombobox object or use this method to create * a new stamp. * * Returns: (transfer full): a pixbuf pointer corresponding to the * little image as shown on a @colorComboBox (use g_object_unref() to * free this pixbuf). * * Since: 3.7 */ GdkPixbuf* tool_color_get_stamp(const ToolColor *color, gboolean alpha) { GdkPixbuf *pixbufColorBox; int rowstride, x, y; guchar *pixels, *p; float grey; pixbufColorBox = gdk_pixbuf_new(GDK_COLORSPACE_RGB, FALSE, COLOR_BOX_BITS, COLOR_BOX_WIDTH, COLOR_BOX_HEIGHT); rowstride = gdk_pixbuf_get_rowstride(pixbufColorBox); pixels = gdk_pixbuf_get_pixels(pixbufColorBox); for (y = 0; y < COLOR_BOX_HEIGHT; y++) for (x = 0; x < COLOR_BOX_WIDTH; x++) { p = pixels + y * rowstride + x * 3; if (x < COLOR_BOX_WIDTH / 2) { if (y < COLOR_BOX_HEIGHT / 2) grey = 0.75; else grey = 0.5; } else { if (y < COLOR_BOX_HEIGHT / 2) grey = 0.5; else grey = 0.75; } if (alpha) { p[0] = (guchar)((color->rgba[0] * color->rgba[3] + (1. - color->rgba[3]) * grey) * 255.); p[1] = (guchar)((color->rgba[1] * color->rgba[3] + (1. - color->rgba[3]) * grey) * 255.); p[2] = (guchar)((color->rgba[2] * color->rgba[3] + (1. - color->rgba[3]) * grey) * 255.); } else { p[0] = (guchar)(color->rgba[0] * 255.); p[1] = (guchar)(color->rgba[1] * 255.); p[2] = (guchar)(color->rgba[2] * 255.); } } return pixbufColorBox; } /** * visu_ui_storeRecent: * @filename: a filename. * * Add @filename to the list of recent files. * * Since: 3.8 **/ void visu_ui_storeRecent(const gchar *filename) { #if GTK_MAJOR_VERSION > 2 || GTK_MINOR_VERSION > 9 GtkRecentManager *manager; gchar *uri, *absolut; GError *error; manager = gtk_recent_manager_get_default(); error = (GError*)0; uri = g_filename_to_uri(filename, NULL, &error); if (error && error->code == G_CONVERT_ERROR_NOT_ABSOLUTE_PATH) { g_error_free(error); error = (GError*)0; absolut = tool_path_normalize(filename); uri = g_filename_to_uri(absolut, NULL, &error); g_free(absolut); } if (error) { g_warning("%s", error->message); g_error_free(error); return; } DBG_fprintf(stderr, "VisuUiRenderingWindow: add '%s' to recent files.\n", uri); gtk_recent_manager_add_item(manager, uri); g_free(uri); #endif } v_sim-3.8.0/src/visu_gtk.h000066400000000000000000000101251370110300500154170ustar00rootroot00000000000000/* EXTRAITS DE LA LICENCE Copyright CEA, contributeurs : Luc BILLARD et Damien CALISTE, laboratoire L_Sim, (2001-2005) Adresse mèl : BILLARD, non joignable par mèl ; CALISTE, damien P caliste AT cea P fr. Ce logiciel est un programme informatique servant à visualiser des structures atomiques dans un rendu pseudo-3D. Ce logiciel est régi par la licence CeCILL soumise au droit français et respectant les principes de diffusion des logiciels libres. Vous pouvez utiliser, modifier et/ou redistribuer ce programme sous les conditions de la licence CeCILL telle que diffusée par le CEA, le CNRS et l'INRIA sur le site "http://www.cecill.info". Le fait que vous puissiez accéder à cet en-tête signifie que vous avez pris connaissance de la licence CeCILL, et que vous en avez accepté les termes (cf. le fichier Documentation/licence.fr.txt fourni avec ce logiciel). */ /* LICENCE SUM UP Copyright CEA, contributors : Luc BILLARD et Damien CALISTE, laboratoire L_Sim, (2001-2005) E-mail address: BILLARD, not reachable any more ; CALISTE, damien P caliste AT cea P fr. This software is a computer program whose purpose is to visualize atomic configurations in 3D. This software is governed by the CeCILL license under French law and abiding by the rules of distribution of free software. You can use, modify and/ or redistribute the software under the terms of the CeCILL license as circulated by CEA, CNRS and INRIA at the following URL "http://www.cecill.info". The fact that you are presently reading this means that you have had knowledge of the CeCILL license and that you accept its terms. You can find a copy of this licence shipped with this software at Documentation/licence.en.txt. */ #ifndef VISU_GTK_H #define VISU_GTK_H #include #include #include #include "coreTools/toolColor.h" #include "coreTools/toolFileFormat.h" #include "visu_data.h" #include "gtk_renderingWindowWidget.h" /** * VisuUiNewWidgetFunc: * * This prototype is used whenever a method is required to create a GtkWidget. * * Returns: (transfer full): a newly created GtkWidget. */ typedef GtkWidget* (*VisuUiNewWidgetFunc)(void); /** * VisuUiInitWidgetFunc: * @panel: a location for a #GtkWindow describing the panel. * @renderWindow: a location for a #GtkWindow ; * @renderArea: a location for a #GtkWidget. * * This prototype is used whenever a method is required to initialise * the GTK interface of V_Sim. @panel must be set to point on the * window of the command panel, @renderWindow must point to the window * containing the rendering area (can be the same than @panel) and * @renderArea contains the widget that does the OpenGL rendering. */ typedef void (*VisuUiInitWidgetFunc)(GtkWindow **panel, GtkWindow **renderWindow, GtkWidget **renderArea); void visu_ui_raiseWarning(gchar *action, gchar *message, GtkWindow *window); void visu_ui_raiseWarningLong(gchar *action, gchar *message, GtkWindow *window); void visu_ui_mainCreate(VisuUiInitWidgetFunc panelFunc); gboolean visu_ui_runCommandLine(gpointer data); void visu_ui_wait(void); /** * VisuUiFileFilter: * @gtkFilter: the #GtkFileFilter associate to @visuFilter. * @visuFilter: a #ToolFileFormat object. * * Structure used to associate the V_Sim way to store file filters * with the Gtk way. */ typedef struct _VisuUiFileFilter VisuUiFileFilter; struct _VisuUiFileFilter { GtkFileFilter *gtkFilter; ToolFileFormat* visuFilter; }; GList* visu_ui_createFilter(GList *list, GtkWidget *fileChooser); GdkPixbuf* visu_ui_createPixbuf(const gchar *filename); GdkPixbuf* tool_color_get_stamp(const ToolColor *color, gboolean alpha); void visu_ui_storeRecent(const gchar *filename); void visu_ui_createInterface(GtkWindow **panel, GtkWindow **renderWindow, GtkWidget **renderArea); GtkWidget* visu_ui_buildRenderingWindow(VisuUiRenderingWindow *renderWindow); GtkWindow* visu_ui_getPanel(void); GtkWindow* visu_ui_getRenderWindow(void); GtkWidget* visu_ui_getRenderWidget(void); void visu_ui_setRenderWidget(VisuUiRenderingWindow *render); #endif v_sim-3.8.0/src/visu_main.c000066400000000000000000000145761370110300500155670ustar00rootroot00000000000000/* EXTRAITS DE LA LICENCE Copyright CEA, contributeurs : Luc BILLARD et Damien CALISTE, laboratoire L_Sim, (2001-2005) Adresse mèl : BILLARD, non joignable par mèl ; CALISTE, damien P caliste AT cea P fr. Ce logiciel est un programme informatique servant à visualiser des structures atomiques dans un rendu pseudo-3D. Ce logiciel est régi par la licence CeCILL soumise au droit français et respectant les principes de diffusion des logiciels libres. Vous pouvez utiliser, modifier et/ou redistribuer ce programme sous les conditions de la licence CeCILL telle que diffusée par le CEA, le CNRS et l'INRIA sur le site "http://www.cecill.info". Le fait que vous puissiez accéder à cet en-tête signifie que vous avez pris connaissance de la licence CeCILL, et que vous en avez accepté les termes (cf. le fichier Documentation/licence.fr.txt fourni avec ce logiciel). */ /* LICENCE SUM UP Copyright CEA, contributors : Luc BILLARD et Damien CALISTE, laboratoire L_Sim, (2001-2005) E-mail address: BILLARD, not reachable any more ; CALISTE, damien P caliste AT cea P fr. This software is a computer program whose purpose is to visualize atomic configurations in 3D. This software is governed by the CeCILL license under French law and abiding by the rules of distribution of free software. You can use, modify and/ or redistribute the software under the terms of the CeCILL license as circulated by CEA, CNRS and INRIA at the following URL "http://www.cecill.info". The fact that you are presently reading this means that you have had knowledge of the CeCILL license and that you accept its terms. You can find a copy of this licence shipped with this software at Documentation/licence.en.txt. */ #include "visu_basic.h" #include "visu_commandLine.h" #include "visu_tools.h" #include "visu_basic.h" #include "opengl.h" #include "visu_plugins.h" #include "visu_gtk.h" #include "gtk_main.h" #include "visu_dataloadable.h" #include "extensions/scale.h" #include "gtk_renderingWindowWidget.h" #include #include #include #include #include #include #ifdef HAVE_GTKGLEXT #include #endif #define VISU_MEM_CHECK 0 int main (int argc, char *argv[]) { int res; char *arg; VisuDataLoadable *newData; gchar *dirname, *normDir; GError *error; gboolean GUIerror; VisuUiRenderingWindow *window; #if DEBUG == 1 && VISU_MEM_CHECK == 1 g_mem_set_vtable(glib_mem_profiler_table); #endif #if GLIB_MAJOR_VERSION < 2 || (GLIB_MAJOR_VERSION == 2 && GLIB_MINOR_VERSION < 36) g_type_init(); #endif DBG_fprintf(stderr, "--- Get the default path ---\n"); visu_basic_setExePath(argv[0]); #ifdef G_THREADS_ENABLED DBG_fprintf(stderr, "--- Initialise threads ---\n"); #if GLIB_MAJOR_VERSION < 2 || (GLIB_MAJOR_VERSION == 2 && GLIB_MINOR_VERSION < 32) g_thread_init(NULL); #endif #endif #ifdef ENABLE_NLS setlocale (LC_ALL, ""); bindtextdomain (GETTEXT_PACKAGE, V_SIM_LOCALE_DIR); bind_textdomain_codeset (GETTEXT_PACKAGE, "UTF-8"); textdomain (GETTEXT_PACKAGE); #endif DBG_fprintf(stderr, "Visu Main: initialise Gtk.\n"); GUIerror = gtk_init_check(&argc, &argv); DBG_fprintf(stderr, "--- Parse the command line ---\n"); res = commandLineParse(argc, argv); if (res) exit(1); /* 5444o still allocated by GLIB. */ /* if arg is not null, v_sim is in export mode. */ arg = commandLineGet_ExportFileName(); if (arg) { #ifdef HAVE_GTKGLEXT DBG_fprintf(stderr, "Visu Main: initialise Gtk.\n"); gtk_init(&argc, &argv); DBG_fprintf(stderr, "Visu Main: initialise GtkGlExt.\n"); gdk_gl_init(&argc, &argv); #endif DBG_fprintf(stderr,"--- Initialising plugins ---\n"); error = (GError*)0; visu_plugins_init(&error); if (error) { g_message("Plugin error: %s", error->message); g_error_free(error); } DBG_fprintf(stderr, "Visu Main: test for help message.\n"); if (visu_basic_showOptionHelp(FALSE)) exit(0); DBG_fprintf(stderr, "Visu Main: V_Sim has been called in an export session," " with parameter '%s'.\n", arg); res = visu_basic_mainExport(); return res; } g_return_val_if_fail(GUIerror, 1); gtk_window_set_default_icon_name("v_sim"); gtk_icon_theme_append_search_path(gtk_icon_theme_get_default(), V_SIM_ICONS_DIR); g_set_application_name(_("Visualise atomic simulations")); #ifdef HAVE_GTKGLEXT DBG_fprintf(stderr, "Visu Main: initialise GtkGlExt.\n"); gdk_gl_init(&argc, &argv); #endif /* 38713o still allocated by GLIB and GTK. */ visu_basic_init(); /* the default is V_Sim with gtk interface. */ if (!strcmp(commandLineGet_windowMode(), "renderOnly")) visu_ui_mainCreate(visu_ui_createInterface); else visu_ui_mainCreate(visu_ui_main_class_createMain); window = VISU_UI_RENDERING_WINDOW(visu_ui_getRenderWidget()); DBG_fprintf(stderr, "Visu Main: test for help message.\n"); if (visu_basic_showOptionHelp(FALSE)) exit(0); newData = visu_data_loadable_new_fromCLI(); if (newData) { dirname = g_path_get_dirname(visu_data_loadable_getFilename(newData, 0)); normDir = tool_path_normalize(dirname); visu_ui_main_setLastOpenDirectory(visu_ui_main_class_getCurrentPanel(), (char*)normDir, VISU_UI_DIR_FILE); g_free(dirname); g_free(normDir); visu_ui_rendering_window_loadFile(window, newData, commandLineGet_iSet()); /* Run the command line. */ if (!strcmp(commandLineGet_windowMode(), "renderOnly")) g_idle_add(visu_ui_runCommandLine, (gpointer)0); else { g_idle_add(visu_ui_main_initPanels, visu_ui_main_class_getCurrentPanel()); g_idle_add(visu_ui_main_runCommandLine, (gpointer)visu_ui_getPanel()); } } else { visu_gl_node_scene_setData(visu_ui_rendering_window_getGlScene(window), (VisuData*)0); /* Run the command line. */ if (strcmp(commandLineGet_windowMode(), "renderOnly")) g_idle_add(visu_ui_main_initPanels, visu_ui_main_class_getCurrentPanel()); } DBG_fprintf(stderr, "Visu Main: starting main GTK loop.\n"); gtk_main(); DBG_fprintf(stderr, "Visu Main: quit main GTK loop.\n"); visu_basic_freeAll(); commandLineFree_all(); #if DEBUG == 1 #if GLIB_MAJOR_VERSION < 2 || (GLIB_MAJOR_VERSION == 2 && GLIB_MINOR_VERSION < 46) g_mem_profile(); #endif #endif return 0; } v_sim-3.8.0/src/visu_nodes.c000066400000000000000000003352441370110300500157510ustar00rootroot00000000000000/* EXTRAITS DE LA LICENCE Copyright CEA, contributeurs : Luc BILLARD et Damien CALISTE, laboratoire L_Sim, (2001-2005) Adresse mèl : BILLARD, non joignable par mèl ; CALISTE, damien P caliste AT cea P fr. Ce logiciel est un programme informatique servant à visualiser des structures atomiques dans un rendu pseudo-3D. Ce logiciel est régi par la licence CeCILL soumise au droit français et respectant les principes de diffusion des logiciels libres. Vous pouvez utiliser, modifier et/ou redistribuer ce programme sous les conditions de la licence CeCILL telle que diffusée par le CEA, le CNRS et l'INRIA sur le site "http://www.cecill.info". Le fait que vous puissiez accéder à cet en-tête signifie que vous avez pris connaissance de la licence CeCILL, et que vous en avez accepté les termes (cf. le fichier Documentation/licence.fr.txt fourni avec ce logiciel). */ /* LICENCE SUM UP Copyright CEA, contributors : Luc BILLARD et Damien CALISTE, laboratoire L_Sim, (2001-2005) E-mail address: BILLARD, not reachable any more ; CALISTE, damien P caliste AT cea P fr. This software is a computer program whose purpose is to visualize atomic configurations in 3D. This software is governed by the CeCILL license under French law and abiding by the rules of distribution of free software. You can use, modify and/ or redistribute the software under the terms of the CeCILL license as circulated by CEA, CNRS and INRIA at the following URL "http://www.cecill.info". The fact that you are presently reading this means that you have had knowledge of the CeCILL license and that you accept its terms. You can find a copy of this licence shipped with this software at Documentation/licence.en.txt. */ #include "visu_nodes.h" #include #include #include "visu_tools.h" #include "coreTools/toolMatrix.h" /** * SECTION:visu_nodes * @short_description: Defines the elementary structure to store * informations about an element in a box. * * In V_Sim, elements are drawn in a box. The #VisuNode * structure is used to represent an instance of an element position * somewhere in the box. This element can have several characteristics * such as its translation or its visibility. * * All nodes are stored in a #VisuData object in a two * dimensional array. The first dimension is indexed by the * #VisuElement of the node and the second corresponds to the number * of this node for this element. When a node is own by a #VisuData, * the two integers, that control the indexes in this array, are not * negative. See the #VisuNode structure for further * explanations. * * The only basic informations own by the #VisuNode structure is * basicaly its position. To add further informations (such as * orientation for the spin), define a node property using * visu_node_array_property_newPointer(). */ /** * VisuNode: * @xyz: (in) (array fixed-size=3): an array of three floating point values that positions the node in (x, y, z) ; * @translation: (in) (array fixed-size=3): an array of three floating point values that translates the * node to its drawn position from (x, y, z) ; * @number: an integer that corresponds to its position in the entry file, it references * also the node itself in the array 'fromNumberToVisuNode' of the #VisuData * that contains the node ; * @posElement: an integer that is the position of the #VisuElement of the node * in the array 'fromIntToVisuElement' of the #VisuData object that * contains the node ; * @posNode: an integer that is the position of the node itself in the array * 'nodes' of the #VisuData object that contains the node ; * @rendered: a boolean to store if the node is drwn or not. * * Structure to store primary data of a node. */ /* Local routines. */ static void freeNodePropStruct(gpointer data); static void removeNodeProperty(gpointer key, gpointer value, gpointer data); static void removeNodePropertyForElement(gpointer key, gpointer value, gpointer data); static void reallocNodeProperty(gpointer key, gpointer value, gpointer data); static void allocateNodeProp(gpointer key, gpointer value, gpointer data); static void createNodeproperty(gpointer key, gpointer value, gpointer data); static VisuNode* newOrCopyNode(VisuNodeArray *nodeArray, int iEle, int oldNodeId); static void freeElePropStruct(gpointer data); /* The number of nodes to be reallocated each time the visu_node_array_getNewNode() is called. */ #define REALLOCATION_STEP 100 /* The key of the original node property. */ #define ORIGINAL_ID "originalId" struct twoNodes { VisuNode *oldNode; VisuNode *newNode; }; typedef struct _VisuNodeArrayPrivate VisuNodeArrayPrivate; struct _VisuNodeProperty { /* A label to define the property. */ gchar *name; /* A pointer to the array of nodes these properties are related to. */ VisuNodeArray *array; /* The type of the property. */ GType gtype; /* This table has the same size and structure than the node array object it is related to. Only one of the following data array is allocated. */ gpointer **data_pointer; int **data_int; /* In the case of pointer data, one can give the new, copy and free routine. */ /* This method is called for each stored token, if not NULL when the table is freed. */ GFunc freeTokenFunc; /* This method is used to create/copy a token of the data array. */ GCopyFunc newOrCopyTokenFunc; /* This value stores a pointer on a user data given when the object is created. This pointer is given to the copy or the free function. */ gpointer user_data; }; struct _ElementProperty { VisuNodeArrayElementPropertyInit init; GArray *array; }; /* static gpointer node_copy(gpointer boxed) */ /* { */ /* VisuNode *node; */ /* node = g_malloc(sizeof(VisuNode)); */ /* DBG_fprintf(stderr, "Visu Node: copying node %p to %p.\n", boxed, (gpointer)node); */ /* *node = *(VisuNode*)boxed; */ /* return (gpointer)node; */ /* } */ static gpointer node_no_copy(gpointer boxed) { return boxed; } static void node_no_free(gpointer boxed _U_) { } GType visu_node_get_type(void) { static GType g_define_type_id = 0; if (g_define_type_id == 0) g_define_type_id = g_boxed_type_register_static("VisuNode", node_no_copy, node_no_free); return g_define_type_id; } /** * visu_node_setCoordinates: * @node: a #VisuNode object ; * @xyz: (array fixed-size=3): new cartesian coordinates. * * This method is used to change coordinates of @node. * * Since: 3.7 * * Returns: TRUE if the calling method should emit * #VisuNodeArray::position-changed signal. */ gboolean visu_node_setCoordinates(VisuNode* node, float xyz[3]) { g_return_val_if_fail(node, FALSE); if (node->xyz[0] == xyz[0] && node->xyz[1] == xyz[1] && node->xyz[2] == xyz[2]) return FALSE; node->xyz[0] = xyz[0]; node->xyz[1] = xyz[1]; node->xyz[2] = xyz[2]; return TRUE; } /** * visu_node_setVisibility: * @node: a #VisuNode object ; * @visibility: a boolean. * * This method is used to turn on or off the drawing of the specified node. * * Returns: %TRUE if the visibility has changed. */ gboolean visu_node_setVisibility(VisuNode* node, gboolean visibility) { g_return_val_if_fail(node, FALSE); if (node->rendered == visibility) return FALSE; node->rendered = visibility; return TRUE; } /** * visu_node_getVisibility: * @node: a #VisuNode object. * * This method is used get the status of the drawing state of a node. * * Returns: true if the node is rendered, false otherwise. */ gboolean visu_node_getVisibility(VisuNode* node) { g_return_val_if_fail(node, FALSE); return node->rendered; } /** * visu_node_newValues: * @node: an allocated #VisuNode object ; * @xyz: (in) (array fixed-size=3): the coordinates to set. * * Set the coordinates and set all other values to default. */ void visu_node_newValues(VisuNode *node, float xyz[3]) { g_return_if_fail(node); DBG_fprintf(stderr, "Visu Node: set new position for node %d (%g;%g;%g).\n", node->number, xyz[0], xyz[1], xyz[2]); node->xyz[0] = xyz[0]; node->xyz[1] = xyz[1]; node->xyz[2] = xyz[2]; node->translation[0] = 0.; node->translation[1] = 0.; node->translation[2] = 0.; node->rendered = TRUE; } /***************/ /* Node Arrays */ /***************/ typedef struct _eleArr { VisuElement *ele; /* Listeners on VisuElement signals. */ gulong rendered, maskable; /* Number of nodes allocated (size of the nodes array) and number of nodes physically present in the array for this element. */ guint nNodes, nStoredNodes; /* Allocated space for nodes of this element. */ VisuNode *nodes; } EleArr; typedef struct _nodeTable { /* A counter. */ guint idCounter; /* This array gives access to the good VisuNode when one has its number. This number is an integer ranging in [0;idCounter[. This value is readable in the #VisuNode structure as the number attribute. The current allocated size is stored in @nNodes. */ /* GArray *array. */ VisuNode **array; /* The total of allocated VisuNodes. */ guint nNodes; /* The total of stored VisuNodes. */ guint nStoredNodes; GArray *popIncIds, *posChgIds; } NodeTable; /* Local methods. */ static void onElementRenderChanged(VisuNodeArray *data, GParamSpec *pspec, VisuElement *element); static void onElementPlaneChanged(VisuNodeArray *data, GParamSpec *pspec, VisuElement *element); static void _freeNodes(VisuNodeArray *nodeArray); #define _getEleArr(priv, i) (&g_array_index(priv->elements, EleArr, i)) #define _getElement(priv, i) _getEleArr(priv, i)->ele static void allocateEleProp(gpointer key, gpointer value, gpointer data); /* static void freeEleProp(gpointer key, gpointer value, gpointer data); */ /** * VisuNodeArray: * * Opaque structure representing array of nodes object. */ struct _VisuNodeArrayPrivate { gboolean dispose_has_run; /****************/ /* The elements */ /****************/ /* Stores for each element some related informations (see EleArr). */ GArray *elements; /*************/ /* The nodes */ /*************/ NodeTable nodeTable; /***********************/ /* The property arrays */ /***********************/ /* Properties of elements. */ GHashTable *eleProp; /* This is a table to store data, reachable with string keys. It should be accessed via visu_node_setproperty() and visu_node_array_getProperty(). */ GHashTable *nodeProp; /* A convenient pointer on the original node property. */ VisuNodeProperty *origProp; /* Total of original nodes. */ guint nOrigNodes; }; enum { POPULATION_INCREASE_SIGNAL, POPULATION_DECREASE_SIGNAL, POSITION_CHANGED_SIGNAL, ELEMENT_VISIBILITY_CHANGED_SIGNAL, ELEMENT_PLANE_CHANGED_SIGNAL, LAST_SIGNAL }; static guint visu_node_array_signals[LAST_SIGNAL] = { 0 }; enum { PROP_0, NNODES_PROP, NORIGS_PROP, ELES_PROP, N_PROP }; static GParamSpec *properties[N_PROP]; static void visu_node_array_dispose (GObject* obj); static void visu_node_array_finalize (GObject* obj); static void visu_node_array_get_property(GObject* obj, guint property_id, GValue *value, GParamSpec *pspec); static void visu_maskable_interface_init(VisuMaskableInterface *iface); G_DEFINE_TYPE_WITH_CODE(VisuNodeArray, visu_node_array, VISU_TYPE_OBJECT, G_ADD_PRIVATE(VisuNodeArray) G_IMPLEMENT_INTERFACE(VISU_TYPE_MASKABLE, visu_maskable_interface_init)) static gboolean _resetVisibility(VisuMaskable *self); static GArray* _getMasked(const VisuMaskable *self); static void visu_node_array_class_init(VisuNodeArrayClass *klass) { DBG_fprintf(stderr, "Visu NodeArray: creating the class of the object.\n"); /* Connect the overloading methods. */ G_OBJECT_CLASS(klass)->dispose = visu_node_array_dispose; G_OBJECT_CLASS(klass)->finalize = visu_node_array_finalize; G_OBJECT_CLASS(klass)->get_property = visu_node_array_get_property; DBG_fprintf(stderr, " - adding new signals ;\n"); /** * VisuNodeArray::PopulationDecrease: * @nodes: the object which received the signal ; * @ids: (element-type guint) (array): an array of #VisuNode ids. * * Gets emitted when the number of nodes has changed, * decreasing. @ids contains all removed ids. * When emitted, nodes have already been removed, so no external * routines should keep pointers on these nodes. * * Since: 3.4 */ visu_node_array_signals[POPULATION_DECREASE_SIGNAL] = g_signal_new("PopulationDecrease", G_TYPE_FROM_CLASS (klass), G_SIGNAL_RUN_LAST | G_SIGNAL_NO_RECURSE | G_SIGNAL_NO_HOOKS, 0, NULL, NULL, g_cclosure_marshal_VOID__BOXED, G_TYPE_NONE, 1, G_TYPE_ARRAY); /** * VisuNodeArray::PopulationIncrease: * @nodes: the object which received the signal ; * @ids: (element-type guint) (array): an array of #VisuNode ids. * * Gets emitted when the number of nodes has changed, * increasing. @ids contains all new ids. * * Since: 3.4 */ visu_node_array_signals[POPULATION_INCREASE_SIGNAL] = g_signal_new("PopulationIncrease", G_TYPE_FROM_CLASS (klass), G_SIGNAL_RUN_LAST | G_SIGNAL_NO_RECURSE | G_SIGNAL_NO_HOOKS, 0, NULL, NULL, g_cclosure_marshal_VOID__BOXED, G_TYPE_NONE, 1, G_TYPE_ARRAY); /** * VisuNodeArray::position-changed: * @nodes: the object which received the signal ; * @ids: (allow-none) (element-type guint): ids of moved nodes. * * Gets emitted when one or more nodes have moved, because of * translations or because the user has moved them manually. * * Since: 3.2 */ visu_node_array_signals[POSITION_CHANGED_SIGNAL] = g_signal_new("position-changed", G_TYPE_FROM_CLASS (klass), G_SIGNAL_RUN_LAST | G_SIGNAL_NO_RECURSE | G_SIGNAL_NO_HOOKS, 0, NULL, NULL, g_cclosure_marshal_VOID__BOXED, G_TYPE_NONE, 1, G_TYPE_ARRAY, NULL); /** * VisuNodeArray::ElementVisibilityChanged: * @nodes: the object which received the signal ; * @ele: the #VisuElement that has its visibility changed * * Gets emitted when the visibility characteristic of one element changes. * * Since: 3.8 */ visu_node_array_signals[ELEMENT_VISIBILITY_CHANGED_SIGNAL] = g_signal_new("ElementVisibilityChanged", G_TYPE_FROM_CLASS(klass), G_SIGNAL_RUN_LAST | G_SIGNAL_NO_RECURSE | G_SIGNAL_NO_HOOKS, 0, NULL, NULL, g_cclosure_marshal_VOID__OBJECT, G_TYPE_NONE, 1, VISU_TYPE_ELEMENT, NULL); /** * VisuNodeArray::ElementMaskableChanged: * @nodes: the object which received the signal ; * @ele: the #VisuElement that has its visibility changed * * Gets emitted when the maskable characteristic of one element changes. * * Since: 3.8 */ visu_node_array_signals[ELEMENT_PLANE_CHANGED_SIGNAL] = g_signal_new("ElementMaskableChanged", G_TYPE_FROM_CLASS(klass), G_SIGNAL_RUN_LAST | G_SIGNAL_NO_RECURSE | G_SIGNAL_NO_HOOKS, 0, NULL, NULL, g_cclosure_marshal_VOID__OBJECT, G_TYPE_NONE, 1, VISU_TYPE_ELEMENT, NULL); /** * VisuNodeArray::n-nodes: * * Total number of nodes. * * Since: 3.8 */ properties[NNODES_PROP] = g_param_spec_uint("n-nodes", "# nodes", "total number of nodes", 0, G_MAXUINT, 0, G_PARAM_READABLE); /** * VisuNodeArray::n-original-nodes: * * Total number of original nodes. * * Since: 3.8 */ properties[NORIGS_PROP] = g_param_spec_uint("n-original-nodes", "# original nodes", "total number of original nodes", 0, G_MAXUINT, 0, G_PARAM_READABLE); /** * VisuNodeArray::elements: * * An array with the elements. * * Since: 3.8 */ properties[ELES_PROP] = g_param_spec_boxed("elements", "Elements", "all elements", G_TYPE_ARRAY, G_PARAM_READABLE); g_object_class_install_properties(G_OBJECT_CLASS(klass), N_PROP, properties); /* Create the boxed type of nodes. */ visu_node_get_type(); } static void visu_maskable_interface_init(VisuMaskableInterface *iface) { iface->reset_visibility = _resetVisibility; iface->get_masked = _getMasked; } static void visu_node_array_init(VisuNodeArray *array) { VisuNodeArrayPrivate *priv = visu_node_array_get_instance_private(array); DBG_fprintf(stderr, "Visu NodeArray: initializing a new object (%p).\n", (gpointer)array); priv->dispose_has_run = FALSE; priv->elements = g_array_new(FALSE, FALSE, sizeof(EleArr)); priv->nodeTable.idCounter = 0; priv->nodeTable.nNodes = 0; priv->nodeTable.nStoredNodes = 0; priv->nodeTable.array = (VisuNode**)0; priv->nodeTable.popIncIds = (GArray*)0; priv->nodeTable.posChgIds = (GArray*)0; priv->eleProp = g_hash_table_new_full(g_str_hash, g_str_equal, NULL, freeElePropStruct); priv->nodeProp = g_hash_table_new_full(g_str_hash, g_str_equal, NULL, freeNodePropStruct); /* We add a node property that is > 0 if the node is a duplicate node and negative if not. The value is the node id that the duplicate refers to. */ DBG_fprintf(stderr, " | create the original node property.\n"); priv->origProp = visu_node_array_property_newInteger(array, ORIGINAL_ID); priv->nOrigNodes = 0; } /* This method can be called several times. It should unref all of its reference to GObjects. */ static void visu_node_array_dispose(GObject* obj) { VisuNodeArrayPrivate *priv = visu_node_array_get_instance_private(VISU_NODE_ARRAY(obj)); guint i; EleArr *ele; DBG_fprintf(stderr, "Visu NodeArray: dispose object %p.\n", (gpointer)obj); g_return_if_fail(priv); if (priv->dispose_has_run) return; priv->dispose_has_run = TRUE; for (i = 0; i < priv->elements->len; i++) { ele = _getEleArr(priv, i); g_signal_handler_disconnect(ele->ele, ele->rendered); g_signal_handler_disconnect(ele->ele, ele->maskable); g_object_unref(ele->ele); } /* Chain up to the parent class */ G_OBJECT_CLASS(visu_node_array_parent_class)->dispose(obj); } /* This method is called once only. */ static void visu_node_array_finalize(GObject* obj) { VisuNodeArrayPrivate *priv = visu_node_array_get_instance_private(VISU_NODE_ARRAY(obj)); g_return_if_fail(priv); DBG_fprintf(stderr, "Visu NodeArray: finalize object %p.\n", (gpointer)obj); /* We first remove the properties, before the node description because these descriptions may be relevant. */ if (priv->nodeProp) g_hash_table_destroy(priv->nodeProp); if (priv->eleProp) g_hash_table_destroy(priv->eleProp); _freeNodes(VISU_NODE_ARRAY(obj)); g_array_free(priv->elements, TRUE); /* Chain up to the parent class */ DBG_fprintf(stderr, "Visu NodeArray: chain to parent.\n"); G_OBJECT_CLASS(visu_node_array_parent_class)->finalize(obj); DBG_fprintf(stderr, "Visu NodeArray: freeing ... OK.\n"); } static void visu_node_array_get_property(GObject* obj, guint property_id, GValue *value, GParamSpec *pspec) { VisuNodeArrayPrivate *priv = visu_node_array_get_instance_private(VISU_NODE_ARRAY(obj)); GArray *eles; guint i; EleArr *arr; DBG_fprintf(stderr, "Visu NodeArray: get property '%s' -> ", g_param_spec_get_name(pspec)); switch (property_id) { case NNODES_PROP: g_value_set_uint(value, priv->nodeTable.nStoredNodes); DBG_fprintf(stderr, "%d.\n", priv->nodeTable.nStoredNodes); break; case NORIGS_PROP: g_value_set_uint(value, priv->nOrigNodes); DBG_fprintf(stderr, "%d.\n", priv->nOrigNodes); break; case ELES_PROP: eles = g_array_sized_new(FALSE, FALSE, sizeof(VisuElement*), priv->elements->len); for (i = 0; i < priv->elements->len; i++) { arr = _getEleArr(priv, i); g_array_append_val(eles, arr->ele); } g_value_take_boxed(value, eles); DBG_fprintf(stderr, "%p.\n", g_value_get_boxed(value)); break; default: /* We don't have any other property... */ G_OBJECT_WARN_INVALID_PROPERTY_ID(obj, property_id, pspec); break; } } #if DEBUG == 1 static void _checkNodeTable(NodeTable *table) { guint j; for (j = 0; j < table->idCounter; j++) if (table->array[j] && table->array[j]->number != j) g_warning("inconsistency on node number %d.", j); } #endif static gboolean _validNodeTableId(NodeTable *table, guint id) { g_return_val_if_fail(table, FALSE); return id < table->idCounter; } static void _increaseNodeTable(NodeTable *table, guint delta) { table->nNodes += delta; table->array = g_realloc(table->array, sizeof(VisuNode*) * table->nNodes); memset(table->array + table->nNodes - delta, '\0', sizeof(VisuNode*) * delta); } static void _compactNodeTable(NodeTable *table) { DBG_fprintf(stderr, "Visu NodeArray: compaction required (%d %d).\n", table->idCounter, table->nNodes); g_return_if_fail(table && table->idCounter <= table->nNodes); /* We get the last non NULL node pointer in the array array to make the idCounter having this value to avoid to much reallocation of the array array. */ for (; table->idCounter > 0 && !table->array[table->idCounter - 1]; table->idCounter -= 1); DBG_fprintf(stderr, "Visu NodeArray: idCounter is set to %d.\n", table->idCounter); } static VisuNode* _getFromId(NodeTable *table, guint number) { g_return_val_if_fail(table && number < table->nNodes, (VisuNode*)0); return table->array[number]; } static void _setAtId(NodeTable *table, guint number, VisuNode *node) { g_return_if_fail(table && number < table->nNodes); if (node && !table->array[number]) table->nStoredNodes += 1; else if (!node && table->array[number]) table->nStoredNodes -= 1; table->array[number] = node; } static void _addNodeTable(NodeTable *table, VisuNode *node) { g_return_if_fail(table && node); if (table->idCounter == table->nNodes) _increaseNodeTable(table, REALLOCATION_STEP); node->number = table->idCounter; _setAtId(table, node->number, node); table->idCounter += 1; } /** * visu_node_array_allocate: * @array: a #VisuNodeArray object. * @elements: (in) (element-type VisuElement*):the size of nNodes. * @nNodes: (in) (element-type guint): an array giving the number of nodes per element. * * Reallocate the internal arrays to match @elements and @nNodes. */ void visu_node_array_allocate(VisuNodeArray *array, GArray *elements, GArray *nNodes) { guint i, j; EleArr ele; VisuElement *element; VisuNodeArrayPrivate *priv = visu_node_array_get_instance_private(array); g_return_if_fail(priv); g_return_if_fail(nNodes && nNodes->len > 0); g_return_if_fail(elements && elements->len > 0); g_return_if_fail(nNodes->len == elements->len); DBG_fprintf(stderr, "Visu NodeArray: allocating VisuElement data (+%d elements).\n", elements->len); for(i = 0; i < elements->len; i++) { element = g_array_index(elements, VisuElement*, i); if (visu_node_array_getElementId(array, element) < 0) { /* Create new element. */ ele.ele = g_object_ref(element); ele.rendered = g_signal_connect_swapped(G_OBJECT(element), "notify::rendered", G_CALLBACK(onElementRenderChanged), array); ele.maskable = g_signal_connect_swapped(G_OBJECT(element), "notify::maskable", G_CALLBACK(onElementPlaneChanged), array); ele.nNodes = g_array_index(nNodes, guint, i); ele.nStoredNodes = 0; ele.nodes = g_malloc(sizeof(VisuNode) * ele.nNodes); for (j = 0; j < ele.nNodes; j++) { ele.nodes[j].posElement = priv->elements->len; ele.nodes[j].posNode = j; } priv->elements = g_array_append_val(priv->elements, ele); /* Increase the node table. */ _increaseNodeTable(&priv->nodeTable, ele.nNodes); /* Expand element properties for new element. */ g_hash_table_foreach(priv->eleProp, allocateEleProp, (gpointer)ele.ele); /* Expand node properties for new element. */ g_hash_table_foreach(priv->nodeProp, allocateNodeProp, (gpointer)0); DBG_fprintf(stderr, " | add VisuElement '%p' -> '%s' (%ld) at %p.\n", (gpointer)element, element->name, ele.rendered, (gpointer)_getEleArr(priv, priv->elements->len - 1)); DBG_fprintf(stderr, " | %d nodes allocated.\n", ele.nNodes); } else /* Reallocate existing element. */ visu_node_array_allocateNodesForElement(array, i, g_array_index(nNodes, guint, i)); } DBG_fprintf(stderr, " | has now %d elements.\n", priv->elements->len); DBG_fprintf(stderr, " | total number of allocated nodes %d.\n", priv->nodeTable.nNodes); DBG_fprintf(stderr, " | size = %do\n", (int)(priv->elements->len * sizeof(EleArr) + sizeof(GArray) + sizeof(VisuNode) * priv->nodeTable.nNodes + sizeof(VisuNode*) * priv->nodeTable.nNodes + sizeof(VisuNodeArray))); g_object_notify_by_pspec(G_OBJECT(array), properties[ELES_PROP]); } /** * visu_node_array_allocateByNames: * @array: a #VisuNodeArray object; * @nNodesPerElement: (in) (element-type guint): number of #VisuNode per VisuElement; * @elementNames: (in) (element-type utf8): names of elements; * * This method allocates the storing part of the given #VisuNodeArray structure and * store all the #VisuNodes. */ void visu_node_array_allocateByNames(VisuNodeArray *array, GArray *nNodesPerElement, GArray *elementNames) { GArray *elements; guint i; VisuElement *ele; DBG_fprintf(stderr, "Visu NodeArray: allocating %p from names.\n", (gpointer)array); elements = g_array_sized_new(FALSE, FALSE, sizeof(VisuElement*), elementNames->len); for (i = 0; i < elementNames->len; i++) { ele = visu_element_retrieveFromName(g_array_index(elementNames, gchar*, i), (gboolean*)0); g_array_append_val(elements, ele); } visu_node_array_allocate(array, elements, nNodesPerElement); g_array_free(elements, TRUE); } static void _freeNodes(VisuNodeArray *nodeArray) { guint i; EleArr *ele; VisuNodeArrayPrivate *priv = visu_node_array_get_instance_private(nodeArray); DBG_fprintf(stderr, "Visu NodeArray: free storages of %p.\n", (gpointer)nodeArray); g_return_if_fail(priv); if (priv->elements) { for (i = 0; i < priv->elements->len; i++) { ele = _getEleArr(priv, i); if (!priv->dispose_has_run) { g_signal_handler_disconnect(G_OBJECT(ele->ele), ele->rendered); g_signal_handler_disconnect(G_OBJECT(ele->ele), ele->maskable); g_object_unref(ele->ele); } g_free(ele->nodes); } g_array_set_size(priv->elements, 0); } g_free(priv->nodeTable.array); if (priv->nodeTable.popIncIds) g_array_unref(priv->nodeTable.popIncIds); if (priv->nodeTable.posChgIds) g_array_unref(priv->nodeTable.posChgIds); priv->nodeTable.array = (VisuNode**)0; priv->nodeTable.idCounter = 0; priv->nodeTable.nNodes = 0; priv->nodeTable.nStoredNodes = 0; priv->nodeTable.popIncIds = (GArray*)0; priv->nodeTable.posChgIds = (GArray*)0; DBG_fprintf(stderr, "Visu NodeArray: freeing node array ... OK.\n"); } /** * visu_node_array_freeNodes: * @nodeArray: a #VisuNodeArray object. * * Deallocate all nodes of the object and related properties but keep * the object alive. **/ void visu_node_array_freeNodes(VisuNodeArray *nodeArray) { guint i; VisuNodeArrayPrivate *priv = visu_node_array_get_instance_private(nodeArray); /* We first remove the properties, before the node description because these descriptions may be relevant. */ g_return_if_fail(priv); if (priv->nodeProp) for (i = 0; i < priv->elements->len; i++) g_hash_table_foreach(priv->nodeProp, removeNodePropertyForElement, GINT_TO_POINTER(i)); if (priv->eleProp) g_hash_table_remove_all(priv->eleProp); _freeNodes(nodeArray); g_object_notify_by_pspec(G_OBJECT(nodeArray), properties[NNODES_PROP]); g_object_notify_by_pspec(G_OBJECT(nodeArray), properties[ELES_PROP]); priv->origProp = visu_node_array_property_newInteger(nodeArray, ORIGINAL_ID); priv->nOrigNodes = 0; } /** * visu_node_array_removeNodes: * @nodeArray: a #VisuNodeArray object. * @nodeNumbers: (element-type guint): an array of integers (negative terminated). * * Remove the given #VisuNode from the @nodeArray. The properties * are also updated. */ void visu_node_array_removeNodes(VisuNodeArray *nodeArray, GArray *nodeNumbers) { VisuNode *node; guint i, iEle, iNode, number; EleArr *ele; VisuNodeArrayPrivate *priv = visu_node_array_get_instance_private(nodeArray); g_return_if_fail(priv && nodeNumbers); if (nodeNumbers->len == 0) return; /* For each element in the given node array, we take the last node of the same element and it takes it position. */ DBG_fprintf(stderr, "Visu Node: removing nodes from array %p (%d).\n", (gpointer)nodeArray, nodeNumbers->len); for (i = 0; i < nodeNumbers->len; i++) { number = g_array_index(nodeNumbers, guint, i); node = _getFromId(&priv->nodeTable, number); if (!node) continue; g_return_if_fail(node->number == number); iEle = node->posElement; iNode = node->posNode; ele = _getEleArr(priv, iEle); ele->nStoredNodes -= 1; if (priv->origProp->data_int[iEle][iNode] < 0) priv->nOrigNodes -= 1; if (ele->nStoredNodes > 0) { /* First, we copy the properties following the same scheme, the last node of the given element is copy instead of the given one. */ g_hash_table_foreach(priv->nodeProp, removeNodeProperty, ele->nodes + iNode); /* Then, we copy the node values themselves. */ ele->nodes[iNode] = ele->nodes[ele->nStoredNodes]; /* We update the index values. */ ele->nodes[iNode].posNode = iNode; ele->nodes[iNode].number = ele->nodes[ele->nStoredNodes].number; _setAtId(&priv->nodeTable, ele->nodes[iNode].number, ele->nodes + iNode); } /* Nullify the removed node. */ _setAtId(&priv->nodeTable, number, (VisuNode*)0); DBG_fprintf(stderr, "Visu NodeArray: %d removed, population for element %d is now:", number, iEle); DBG_fprintf(stderr, " %d/%d # %d/%d\n", priv->nodeTable.nStoredNodes, priv->nodeTable.nNodes, ele->nStoredNodes, ele->nNodes); } _compactNodeTable(&priv->nodeTable); DBG_fprintf(stderr, " | size = %do\n", (int)(priv->elements->len * sizeof(EleArr) + sizeof(GArray) + sizeof(VisuNode) * priv->nodeTable.nNodes + sizeof(VisuNode*) * priv->nodeTable.nNodes + sizeof(VisuNodeArray))); DBG_fprintf(stderr, "Visu NodeArray: emit a 'NodePopulationDecrease' signal.\n"); g_object_notify_by_pspec(G_OBJECT(nodeArray), properties[NNODES_PROP]); g_signal_emit(G_OBJECT(nodeArray), visu_node_array_signals[POPULATION_DECREASE_SIGNAL], 0, (gpointer)nodeNumbers, NULL); } /** * visu_node_array_removeNodesOfElement: * @nodeArray: a #VisuNodeArray object. * @element: a #VisuElement object. * * Remove all the #VisuNode from the element @element. The properties * are also updated. * * Since: 3.7 */ void visu_node_array_removeNodesOfElement(VisuNodeArray *nodeArray, VisuElement *element) { guint i; gint iEle; EleArr *ele; GArray *nodeNumbers; VisuNodeArrayPrivate *priv = visu_node_array_get_instance_private(nodeArray); g_return_if_fail(priv && element); iEle = visu_node_array_getElementId(nodeArray, element); if (iEle < 0) return; /* We keep the allocation to avoid deallocating, reallocating. */ /* Begin by removing the the node properties. */ g_hash_table_foreach(priv->nodeProp, removeNodePropertyForElement, GINT_TO_POINTER(iEle)); ele = _getEleArr(priv, iEle); if (ele->nStoredNodes == 0) return; /* We update the node table. */ nodeNumbers = g_array_new(FALSE, FALSE, sizeof(guint)); for (i = 0; i < ele->nStoredNodes; i++) { g_array_append_val(nodeNumbers, ele->nodes[i].number); if (priv->origProp->data_int[ele->nodes[i].posElement][ele->nodes[i].posNode] < 0) priv->nOrigNodes -= 1; _setAtId(&priv->nodeTable, ele->nodes[i].number, (VisuNode*)0); } ele->nStoredNodes = 0; _compactNodeTable(&priv->nodeTable); DBG_fprintf(stderr, "Visu NodeArray: emit a 'NodePopulationDecrease' signal.\n"); g_object_notify_by_pspec(G_OBJECT(nodeArray), properties[NNODES_PROP]); g_signal_emit(G_OBJECT(nodeArray), visu_node_array_signals[POPULATION_DECREASE_SIGNAL], 0, (gpointer)nodeNumbers, NULL); g_array_unref(nodeNumbers); } /** * visu_node_array_removeAllDuplicateNodes: * @nodeArray: a #VisuNodeArray object. * * Remove all nodes that are not original in the box. * * Returns: TRUE if some nodes have been removed. */ gboolean visu_node_array_removeAllDuplicateNodes(VisuNodeArray *nodeArray) { GArray *tmp; guint i, j; EleArr *ele; VisuNodeArrayPrivate *priv = visu_node_array_get_instance_private(nodeArray); g_return_val_if_fail(priv, FALSE); tmp = g_array_new(FALSE, FALSE, sizeof(int)); for (i = 0; i < priv->elements->len; i++) { ele = _getEleArr(priv, i); for (j = 0; j < ele->nStoredNodes; j++) if (priv->origProp->data_int[i][j] >= 0) tmp = g_array_append_val(tmp, ele->nodes[j].number); } if (tmp->len > 0) { visu_node_array_removeNodes(nodeArray, tmp); g_array_unref(tmp); return TRUE; } g_array_free(tmp, TRUE); return FALSE; } /** * visu_node_array_getFromId: * @array: a #VisuNodeArray structure which stores the nodes. * @number: an integer. * * This methods retrieves the #VisuNode identified by the integer @number. * The number must be strictly positive. No error is raised if no node corresponds * to the given number. * * Returns: (transfer none): the found #VisuNode or NULL if none corresponds to number. */ VisuNode* visu_node_array_getFromId(VisuNodeArray *array, guint number) { VisuNodeArrayPrivate *priv = visu_node_array_get_instance_private(array); g_return_val_if_fail(priv, (VisuNode*)0); /* DBG_fprintf(stderr, "Visu NodeArray: get VisuNode from number %d.\n", number); */ if (_validNodeTableId(&priv->nodeTable, number)) return _getFromId(&priv->nodeTable, number); else return (VisuNode*)0; } /** * visu_node_array_getOriginal: * @nodeArray: a #VisuNodeArray object. * @nodeId: a node id. * * Test if the given @nodeId is an original or a replica for the * periodisation. * * Returns: the original node index or -1 if @nodeId is original. */ gint visu_node_array_getOriginal(VisuNodeArray *nodeArray, guint nodeId) { VisuNode *node; gint orig; VisuNodeArrayPrivate *priv = visu_node_array_get_instance_private(nodeArray); g_return_val_if_fail(priv && priv->origProp, -1); g_return_val_if_fail(_validNodeTableId(&priv->nodeTable, nodeId), -1); orig = (gint)nodeId; do { node = _getFromId(&priv->nodeTable, orig); orig = priv->origProp->data_int[node->posElement][node->posNode]; } while (orig >= 0); /* DBG_fprintf(stderr, "Visu Node: get original from %d: %d (%d).\n", */ /* nodeId, node->number, */ /* nodeArray->priv->origProp->data_int[node->posElement][node->posNode]); */ return (node->number == nodeId)?-1:(gint)node->number; } /** * visu_node_array_setOriginal: * @nodeArray: a #VisuNodeArray object. * @nodeId: a node id. * * Make @nodeId an original node. * * Returns: TRUE if @nodeId was not original. */ gboolean visu_node_array_setOriginal(VisuNodeArray *nodeArray, guint nodeId) { VisuNode *node; gint orig; VisuNodeArrayPrivate *priv = visu_node_array_get_instance_private(nodeArray); g_return_val_if_fail(priv && priv->origProp, -1); g_return_val_if_fail(_validNodeTableId(&priv->nodeTable, nodeId), -1); node = _getFromId(&priv->nodeTable, nodeId); g_return_val_if_fail(node, FALSE); orig = priv->origProp->data_int[node->posElement][node->posNode]; priv->origProp->data_int[node->posElement][node->posNode] = -1; if (orig != -1) priv->nOrigNodes += 1; DBG_fprintf(stderr, "Visu Node: set original for %d (%d).\n", nodeId, orig); return (orig != -1); } /** * visu_node_array_switchNumber: * @nodeArray: a #VisuNodeArray object. * @from: a node id. * @to: another node id. * * Two nodes of @nodeArray switches their number. * * Since: 3.6 * * Returns: TRUE if number is switched. */ gboolean visu_node_array_switchNumber(VisuNodeArray *nodeArray, guint from, guint to) { VisuNode *nodeFrom, *nodeTo; VisuNodeArrayPrivate *priv = visu_node_array_get_instance_private(nodeArray); if (from == to) return FALSE; g_return_val_if_fail(priv, FALSE); nodeFrom = _getFromId(&priv->nodeTable, from); nodeTo = _getFromId(&priv->nodeTable, to); _setAtId(&priv->nodeTable, from, nodeTo); _setAtId(&priv->nodeTable, to, nodeFrom); nodeFrom->number = to; nodeTo->number = from; return TRUE; } /** * visu_node_array_compareElements: * @data1: a #VisuData object ; * @data2: an other #VisuData object. * * This method is used to compare the composition of the given two #VisuData objects. * The test is only done on #VisuElement lists. * * Returns: TRUE if the two objects contains exactly the same #VisuElement objects (not * one more or one less or one different), FALSE otherwise. */ gboolean visu_node_array_compareElements(VisuNodeArray *data1, VisuNodeArray *data2) { guint i, j; gboolean found; VisuNodeArrayPrivate *priv1 = visu_node_array_get_instance_private(data1); VisuNodeArrayPrivate *priv2 = visu_node_array_get_instance_private(data2); g_return_val_if_fail(priv1 && priv2, FALSE); DBG_fprintf(stderr, "Visu NodeArray: comparing composition of '%p' and '%p'.\n", (gpointer)data1, (gpointer)data2); if (data1 == data2) return TRUE; if (priv1->elements->len != priv2->elements->len) return FALSE; for (i = 0; i < priv1->elements->len; i++) { found = FALSE; for (j = 0; !found && j < priv2->elements->len; j++) found = (_getElement(priv1, i) == _getElement(priv2, j)); if (!found) return FALSE; } return TRUE; } static gint _appendElement(VisuNodeArray *nodeArray, const VisuElement *element) { GArray *ele, *nEle; guint one = 1; VisuNodeArrayPrivate *priv = visu_node_array_get_instance_private(nodeArray); g_return_val_if_fail(VISU_IS_ELEMENT(element), -1); ele = g_array_sized_new(FALSE, FALSE, sizeof(VisuElement*), 1); g_array_append_val(ele, element); nEle = g_array_sized_new(FALSE, FALSE, sizeof(guint), 1); g_array_append_val(nEle, one); visu_node_array_allocate(nodeArray, ele, nEle); g_array_free(ele, TRUE); g_array_free(nEle, TRUE); return priv->elements->len - 1; } /** * visu_node_array_getElement: * @data: a #VisuNodeArray object ; * @node: a #VisuNode of this array. * * This routine gets the #VisuElement the @node belongs to. * * Since: 3.7 * * Returns: (transfer none): a #VisuElement, owned by V_Sim. */ VisuElement* visu_node_array_getElement(const VisuNodeArray *data, const VisuNode *node) { VisuNodeArrayPrivate *priv = visu_node_array_get_instance_private((VisuNodeArray*)data); g_return_val_if_fail(priv && node, (VisuElement*)0); return _getElement(priv, node->posElement); } /** * visu_node_array_setElement: * @data: a #VisuNodeArray object. * @node: a #VisuNode pointer. * @element: a #VisuElement object. * * Change the nature of the #VisuElement of @node to be @element. * * Since: 3.8 * * Returns: (transfer none): the new location of the #VisuNode. **/ VisuNode* visu_node_array_setElement(VisuNodeArray *data, VisuNode *node, const VisuElement *element) { VisuNode* out; gint iEle; GArray *arr; VisuNodeArrayPrivate *priv = visu_node_array_get_instance_private(data); g_return_val_if_fail(priv && node, (VisuNode*)0); iEle = visu_node_array_getElementId(data, element); if ((gint)node->posElement == iEle) return node; if (iEle < 0) iEle = _appendElement(data, element); DBG_fprintf(stderr, "Visu Node: copy a new node from node %d (%d-%d).\n", node->number, iEle, node->posNode); visu_node_array_startAdding(data); out = newOrCopyNode(data, iEle, node->number); _setAtId(&priv->nodeTable, out->number, (VisuNode*)0); out->number = node->number; arr = g_array_sized_new(FALSE, FALSE, sizeof(guint), 1); g_array_append_val(arr, node->number); visu_node_array_removeNodes(data, arr); g_array_free(arr, TRUE); _setAtId(&priv->nodeTable, out->number, out); priv->origProp->data_int[out->posElement][out->posNode] = -1; priv->nOrigNodes += 1; g_array_insert_val(priv->nodeTable.popIncIds, 0, out->number); visu_node_array_completeAdding(data); DBG_fprintf(stderr, "Visu Node: copy a new node from node -> %d.\n", out->number); return out; } /** * visu_node_array_containsElement: * @array: a #VisuNodeArray object. * @element: a #VisuElement object. * * Tests if @element is contained in @array. @element may be part of * @array but without nodes. * * Since: 3.8 * * Returns: TRUE, if @array contains @element. **/ gboolean visu_node_array_containsElement(const VisuNodeArray *array, const VisuElement *element) { guint i; const VisuNodeArrayPrivate *priv = visu_node_array_get_instance_private((VisuNodeArray*)array); g_return_val_if_fail(priv, FALSE); for (i = 0; i < priv->elements->len; i++) if (_getElement(priv, i) == element) return TRUE; return FALSE; } /** * visu_node_array_getElementId: * @array: a #VisuNodeArray object ; * @element: a #VisuElement object. * * This routines returns the internal id used to represent @element, * or -1 if not found. * * Since: 3.7 * * Returns: a positive number or -1 if not found. */ gint visu_node_array_getElementId(const VisuNodeArray *array, const VisuElement *element) { guint i; VisuNodeArrayPrivate *priv = visu_node_array_get_instance_private((VisuNodeArray*)array); g_return_val_if_fail(priv, -1); for (i = 0; i < priv->elements->len; i++) if (_getElement(priv, i) == element) return i; return -1; } /** * visu_node_array_getNNodes: * @array: a #VisuNodeArray object. * * This routines returns the number of #VisuNode stored in @array. * * Since: 3.7 * * Returns: a positive number. */ guint visu_node_array_getNNodes(const VisuNodeArray *array) { VisuNodeArrayPrivate *priv = visu_node_array_get_instance_private((VisuNodeArray*)array); g_return_val_if_fail(priv, 0); return priv->nodeTable.nStoredNodes; } /** * visu_node_array_getNOriginalNodes: * @array: a #VisuNodeArray object. * * This routines returns the number of original #VisuNode stored in @array. * * Since: 3.7 * * Returns: a positive number. */ guint visu_node_array_getNOriginalNodes(const VisuNodeArray *array) { VisuNodeArrayPrivate *priv = visu_node_array_get_instance_private((VisuNodeArray*)array); g_return_val_if_fail(priv, 0); return priv->nOrigNodes; } /** * visu_node_array_getNElements: * @array: a #VisuNodeArray object ; * @physical: a boolean. * * The parameter @array stores several #VisuNode of #VisuElement. This * routine is used to get the number of #VisuElement that are used by * this @array. Depending on @physical value, the number of * #VisuElement representing physical element or not is retrieved. The * actual returned number of #VisuElement take into account only * elements with a positive number of nodes. * * Since: 3.7 * * Returns: a positive number. */ guint visu_node_array_getNElements(const VisuNodeArray *array, gboolean physical) { guint nEle, i; VisuNodeArrayPrivate *priv = visu_node_array_get_instance_private((VisuNodeArray*)array); g_return_val_if_fail(priv, 0); nEle = 0; for (i = 0; i < priv->elements->len; i++) if (_getEleArr(priv, i)->nStoredNodes > 0) { if (physical && visu_element_getPhysical(_getElement(priv, i))) nEle += 1; else if (!physical) nEle += 1; } return nEle; } /** * visu_node_array_allocateNodesForElement: * @array: a #VisuNodeArray object ; * @eleId: an internal #VisuElement id ; * @nNodes: a positive number of nodes. * * This routine is used to allocate space for @nNodes of a * #VisuElement. This #VisuElement is identified by its internal id, * see visu_node_array_getElementId(). If this #VisuElement has * already enough space in this @array, nothing is done, otherwise * space is reallocated. * * Since: 3.7 */ void visu_node_array_allocateNodesForElement(VisuNodeArray *array, guint eleId, guint nNodes) { guint j, delta; VisuNode *oldNodeList; EleArr *ele; VisuNodeArrayPrivate *priv = visu_node_array_get_instance_private(array); g_return_if_fail(priv && eleId < priv->elements->len); ele = _getEleArr(priv, eleId); if (ele->nNodes >= nNodes) return; delta = nNodes - ele->nNodes; oldNodeList = ele->nodes; DBG_fprintf(stderr, "Visu Node: reallocation needed for element " "%d with %d nodes.\n", eleId, delta); ele->nNodes = nNodes; ele->nodes = g_realloc(ele->nodes, sizeof(VisuNode) * ele->nNodes); _increaseNodeTable(&priv->nodeTable, delta); DBG_fprintf(stderr, " | (all)%d/%d # (%d)%d/%d\n", priv->nodeTable.nStoredNodes, priv->nodeTable.nNodes, eleId, ele->nStoredNodes, ele->nNodes); /* We set the default values for the new nodes. */ for (j = ele->nStoredNodes; j < ele->nNodes; j++) { ele->nodes[j].posElement = eleId; ele->nodes[j].posNode = j; } /* If the node list has been moved, we need to reassign pointers of array nodeTable. */ if (oldNodeList != ele->nodes) for (j = 0; j < ele->nStoredNodes; j++) _setAtId(&priv->nodeTable, ele->nodes[j].number, ele->nodes + j); /* We reallocate the table properties. */ g_hash_table_foreach(priv->nodeProp, reallocNodeProperty, GINT_TO_POINTER(eleId)); /* Test part for the nodeTable array. */ #if DEBUG == 1 _checkNodeTable(&priv->nodeTable); #endif DBG_fprintf(stderr, "Visu Node: reallocation OK.\n"); DBG_fprintf(stderr, " | size = %do\n", (int)(priv->elements->len * sizeof(EleArr) + sizeof(GArray) + sizeof(VisuNode) * priv->nodeTable.nNodes + sizeof(VisuNode*) * priv->nodeTable.nNodes + sizeof(VisuNodeArray))); } /** * visu_node_array_getNewNode: * @nodeArray: a #VisuNodeArray object ; * @element: a #VisuElement object. * * Return the location of an unstored node for the given #VisuElement. * The returned node is then added in the list of used nodes. * * Since: 3.8 * * Returns: (transfer none): the location of a newly used node. */ VisuNode* visu_node_array_getNewNode(VisuNodeArray *nodeArray, const VisuElement *element) { gint iEle; iEle = visu_node_array_getElementId(nodeArray, element); if (iEle < 0) iEle = _appendElement(nodeArray, element); DBG_fprintf(stderr, "Visu Node: create a new node of element %d.\n", iEle); return newOrCopyNode(nodeArray, iEle, -1); } /** * visu_node_array_getNewNodeForId: * @nodeArray: a #VisuNodeArray object ; * @iEle: the id used in @nodeArray to index a #VisuElement. * * Return the location of an unstored node for the given #VisuElement. * The returned node is then added in the list of used nodes. * * Returns: (transfer none): the location of a newly used node. */ VisuNode* visu_node_array_getNewNodeForId(VisuNodeArray *nodeArray, guint iEle) { DBG_fprintf(stderr, "Visu Node: create a new node of element %d.\n", iEle); return newOrCopyNode(nodeArray, iEle, -1); } /** * visu_node_array_copyNode: * @nodeArray: a #VisuNodeArray object ; * @node: a node of the given #VisuNodeArray. * * Return the location of an unstored node that is the deep copy of the given node. * The returned node is then added in the list of used nodes. * * Returns: (transfer none): the location of a newly used node. */ VisuNode* visu_node_array_copyNode(VisuNodeArray *nodeArray, VisuNode *node) { VisuNode* out; DBG_fprintf(stderr, "Visu Node: copy a new node from node %d (%d-%d).\n", node->number, node->posElement, node->posNode); out = newOrCopyNode(nodeArray, node->posElement, node->number); DBG_fprintf(stderr, "Visu Node: copy a new node from node -> %d.\n", out->number); return out; } static gboolean _emitPopInc(gpointer data) { visu_node_array_completeAdding(VISU_NODE_ARRAY(data)); g_object_unref(G_OBJECT(data)); return FALSE; } static VisuNode* newOrCopyNode(VisuNodeArray *nodeArray, int iEle, int oldNodeId) { EleArr *ele; VisuNode *node, *oldNode; struct twoNodes nodes; VisuNodeArrayPrivate *priv = visu_node_array_get_instance_private(nodeArray); g_return_val_if_fail(priv, (VisuNode*)0); g_return_val_if_fail((oldNodeId >= 0 && _validNodeTableId(&priv->nodeTable, (guint)oldNodeId)) || (iEle >= 0 && iEle < (int)priv->elements->len), (VisuNode*)0); ele = _getEleArr(priv, iEle); if (ele->nStoredNodes == ele->nNodes) /* We need to realloc... */ visu_node_array_allocateNodesForElement(nodeArray, iEle, ele->nNodes + REALLOCATION_STEP); /* Get the new node. */ node = ele->nodes + ele->nStoredNodes; _addNodeTable(&priv->nodeTable, node); /* Update the node internal values. */ ele->nStoredNodes += 1; /* Set default values. */ node->xyz[0] = 0.f; node->xyz[1] = 0.f; node->xyz[2] = 0.f; node->translation[0] = 0.f; node->translation[1] = 0.f; node->translation[2] = 0.f; node->rendered = FALSE; /* We copy the values from oldNode. */ oldNode = (VisuNode*)0; if (oldNodeId >= 0 && (oldNode = _getFromId(&priv->nodeTable, oldNodeId))) { node->xyz[0] = oldNode->xyz[0]; node->xyz[1] = oldNode->xyz[1]; node->xyz[2] = oldNode->xyz[2]; node->translation[0] = oldNode->translation[0]; node->translation[1] = oldNode->translation[1]; node->translation[2] = oldNode->translation[2]; node->rendered = oldNode->rendered; } /* Create new properties for the node. */ nodes.newNode = node; nodes.oldNode = oldNode; g_hash_table_foreach(priv->nodeProp, createNodeproperty, (gpointer)&nodes); /* If we have an old node, we use it as original node id, or we put -1 if not. */ priv->origProp->data_int[node->posElement][node->posNode] = oldNodeId; if (oldNodeId < 0) priv->nOrigNodes += 1; if (!priv->nodeTable.popIncIds) { visu_node_array_startAdding(nodeArray); g_array_append_val(priv->nodeTable.popIncIds, node->number); g_idle_add(_emitPopInc, g_object_ref(nodeArray)); } else { g_array_append_val(priv->nodeTable.popIncIds, node->number); } return node; } /** * visu_node_array_startAdding: * @array: a #VisuNodeArray object. * * Begin to accumulate the node ids that are added to the * structure. When addition is finished, call * visu_node_array_completeAdding() to ensure completion and emit signals. * * Since: 3.8 **/ void visu_node_array_startAdding(VisuNodeArray *array) { VisuNodeArrayPrivate *priv = visu_node_array_get_instance_private(array); g_return_if_fail(priv && !priv->nodeTable.popIncIds); priv->nodeTable.popIncIds = g_array_new(FALSE, FALSE, sizeof(guint)); } /** * visu_node_array_completeAdding: * @array: a #VisuNodeArray object. * * After new nodes have been added, call this routine to ensure that * proper signals are emitted. See visu_node_array_startAdding() to * start a bunch addition of new nodes. * * Since: 3.8 **/ void visu_node_array_completeAdding(VisuNodeArray *array) { VisuNodeArrayPrivate *priv = visu_node_array_get_instance_private(array); g_return_if_fail(priv && priv->nodeTable.popIncIds); if (priv->nodeTable.popIncIds->len > 0) { g_object_notify_by_pspec(G_OBJECT(array), properties[NNODES_PROP]); DBG_fprintf(stderr, "Visu NodeArray: emit a 'PopulationIncrease' signal.\n"); g_signal_emit(G_OBJECT(array), visu_node_array_signals[POPULATION_INCREASE_SIGNAL], 0, priv->nodeTable.popIncIds, NULL); } g_array_unref(priv->nodeTable.popIncIds); priv->nodeTable.popIncIds = (GArray*)0; } static gboolean _resetVisibility(VisuMaskable *self) { gboolean redraw; guint i, j; EleArr *ele; VisuNodeArrayPrivate *priv = visu_node_array_get_instance_private(VISU_NODE_ARRAY(self)); g_return_val_if_fail(priv, FALSE); redraw = FALSE; for (i = 0; i < priv->elements->len; i++) for(ele = _getEleArr(priv, i), j = 0; j < ele->nStoredNodes; j++) redraw = visu_node_setVisibility(ele->nodes + j, TRUE) || redraw; return redraw; } static GArray* _getMasked(const VisuMaskable *self) { GArray *masked; guint i, j; EleArr *ele; const VisuNodeArrayPrivate *priv = visu_node_array_get_instance_private((VisuNodeArray*)self); g_return_val_if_fail(priv, FALSE); masked = g_array_sized_new(FALSE, FALSE, sizeof(guint), priv->nodeTable.nStoredNodes / 10); for (i = 0; i < priv->elements->len; i++) for(ele = _getEleArr(priv, i), j = 0; j < ele->nStoredNodes; j++) if (!visu_node_getVisibility(ele->nodes + j)) g_array_append_val(masked, ele->nodes[j].number); return masked; } /** * visu_node_array_setNodeVisibility: * @nodeArray: a #VisuNodeArray object. * @id: a node id. * @status: a boolean. * * Change the visibility of node @id in @nodeArray. If @id is out of * bound, nothing is done and no error raised. If visibility is indeed * changed, then #VisuNodeArray::VisibilityChanged signal is emitted. * * Since: 3.8 * * Returns: TRUE if visibility of node @id is indeed changed. **/ gboolean visu_node_array_setNodeVisibility(VisuNodeArray *nodeArray, guint id, gboolean status) { VisuNode *node; g_return_val_if_fail(VISU_IS_NODE_ARRAY(nodeArray), FALSE); node = visu_node_array_getFromId(nodeArray, id); if (!node) return FALSE; if (!visu_node_setVisibility(node, status)) return FALSE; visu_maskable_visibilityChanged(VISU_MASKABLE(nodeArray)); return TRUE; } /** * visu_node_array_startMoving: * @array: a #VisuNodeArray object. * * Begin to accumulate the node ids that are moved in the * structure. When moving is finished, call * visu_node_array_completeMoving() to ensure completion and emit signals. * * Since: 3.8 **/ void visu_node_array_startMoving(VisuNodeArray *array) { VisuNodeArrayPrivate *priv = visu_node_array_get_instance_private(array); g_return_if_fail(priv && !priv->nodeTable.posChgIds); DBG_fprintf(stderr, "Visu Nodes: starting moving nodes.\n"); priv->nodeTable.posChgIds = g_array_new(FALSE, FALSE, sizeof(guint)); } /** * visu_node_array_completeMoving: * @array: a #VisuNodeArray object. * * After new nodes have been moved, call this routine to ensure that * proper signals are emitted. See visu_node_array_startMoving() to * start a bunch movements of new nodes. * * Since: 3.8 **/ void visu_node_array_completeMoving(VisuNodeArray *array) { VisuNodeArrayPrivate *priv = visu_node_array_get_instance_private(array); g_return_if_fail(priv && priv->nodeTable.posChgIds); if (priv->nodeTable.posChgIds->len > 0) { DBG_fprintf(stderr, "Visu NodeArray: emit a 'position-changed' signal.\n"); g_signal_emit(G_OBJECT(array), visu_node_array_signals[POSITION_CHANGED_SIGNAL], 0, priv->nodeTable.posChgIds, NULL); } DBG_fprintf(stderr, "Visu Nodes: complete moving nodes.\n"); g_array_unref(priv->nodeTable.posChgIds); priv->nodeTable.posChgIds = (GArray*)0; } static gboolean _emitPosChg(gpointer data) { visu_node_array_completeMoving(VISU_NODE_ARRAY(data)); g_object_unref(G_OBJECT(data)); return FALSE; } /** * visu_node_array_shiftNode: * @array: a #VisuNodeArray object. * @id: a node id. * @delta: (array fixed-size=3): a shift in cartesian coordinates. * * Move the node @id of the quantity @delta given in cartesian * coordinates. If several nodes should be shifted, consider using * visu_node_array_shiftNodes() or encapsulate the calls within * visu_node_array_startMoving() and visu_node_array_completeMoving(). * * Since: 3.8 **/ void visu_node_array_shiftNode(VisuNodeArray *array, guint id, const gfloat delta[3]) { VisuNode *node; VisuNodeArrayPrivate *priv = visu_node_array_get_instance_private(array); g_return_if_fail(priv); node = visu_node_array_getFromId(array, id); if (node) { node->xyz[0] += delta[0]; node->xyz[1] += delta[1]; node->xyz[2] += delta[2]; } if (!priv->nodeTable.posChgIds) { visu_node_array_startMoving(array); g_array_append_val(priv->nodeTable.posChgIds, node->number); g_idle_add(_emitPosChg, g_object_ref(array)); } else { g_array_append_val(priv->nodeTable.posChgIds, node->number); } } /** * visu_node_array_shiftNodes: * @array: a #VisuNodeArray object. * @ids: (element-type uint): a set of #VisuNode ids. * @delta: (array fixed-size=3): a shift in cartesian coordinates. * * Apply @delta on the coordinates of every nodes in @ids. * * Since: 3.8 **/ void visu_node_array_shiftNodes(VisuNodeArray *array, const GArray *ids, const float delta[3]) { guint i; gboolean inside; VisuNodeArrayPrivate *priv = visu_node_array_get_instance_private(array); g_return_if_fail(priv); inside = (priv->nodeTable.posChgIds != (GArray*)0); if (!inside) visu_node_array_startMoving(array); for (i = 0; i < ids->len; i++) visu_node_array_shiftNode(array, g_array_index(ids, guint, i), delta); if (!inside) visu_node_array_completeMoving(array); } /** * visu_node_array_moveNode: * @array: a #VisuNodeArray object. * @id: a node id. * @at: (array fixed-size=3): a position in cartesian coordinates. * * Move the node @id at the posityion @at given in cartesian * coordinates. If several nodes should be moved, consider using * visu_node_array_moveNodes() or encapsulate the calls within * visu_node_array_startMoving() and visu_node_array_completeMoving(). * * Since: 3.8 **/ void visu_node_array_moveNode(VisuNodeArray *array, guint id, const float at[3]) { VisuNode *node; VisuNodeArrayPrivate *priv = visu_node_array_get_instance_private(array); g_return_if_fail(priv); node = visu_node_array_getFromId(array, id); if (node) { node->xyz[0] = at[0]; node->xyz[1] = at[1]; node->xyz[2] = at[2]; } if (!priv->nodeTable.posChgIds) { visu_node_array_startMoving(array); g_array_append_val(priv->nodeTable.posChgIds, node->number); g_idle_add(_emitPosChg, g_object_ref(array)); } else { g_array_append_val(priv->nodeTable.posChgIds, node->number); } } /** * visu_node_array_moveNodes: * @array: a #VisuNodeArray object. * @ids: (element-type uint): a set of #VisuNode ids. * @xyz: (element-type float): a set of cartesian displacements. * * Apply translations on all nodes defined by @ids. Displacements are * read from @xyz which is an array containing as many float triplets * as nodes in ids. * * Since: 3.8 **/ void visu_node_array_moveNodes(VisuNodeArray *array, const GArray *ids, const GArray *xyz) { guint i; gboolean inside; VisuNodeArrayPrivate *priv = visu_node_array_get_instance_private(array); g_return_if_fail(priv && ids && xyz && ids->len * 3 == xyz->len); inside = (priv->nodeTable.posChgIds != (GArray*)0); if (!inside) visu_node_array_startMoving(array); for (i = 0; i < ids->len; i++) visu_node_array_moveNode(array, g_array_index(ids, guint, i), &g_array_index(xyz, float, 3 * i)); if (!inside) visu_node_array_completeMoving(array); } /** * visu_node_array_rotateNodes: * @array: a #VisuNodeArray object. * @ids: (element-type uint): a set of #VisuNode ids. * @axis: (array fixed-size=3): an axis orientation. * @center: (array fixed-size=3): point coordinates. * @angle: an angle in degrees. * * Apply the rotation defined by @angle along @axis passing by @center * to all nodes referenced in @ids. * * Since: 3.8 **/ void visu_node_array_rotateNodes(VisuNodeArray *array, const GArray *ids, const float axis[3], const float center[3], float angle) { VisuNode *node; guint i; float sph[3], mat[3][3], work[3]; VisuNodeArrayPrivate *priv = visu_node_array_get_instance_private(array); g_return_if_fail(priv); g_return_if_fail(axis[0] != 0.f || axis[1] != 0.f || axis[2] != 0.f); tool_matrix_cartesianToSpherical(sph, axis); DBG_fprintf(stderr, "Visu Nodes: rotation along %g %g.\n", sph[TOOL_MATRIX_SPHERICAL_THETA], sph[TOOL_MATRIX_SPHERICAL_PHI]); tool_matrix_setIdentity(mat); tool_matrix_rotate(mat, -sph[TOOL_MATRIX_SPHERICAL_PHI], TOOL_XYZ_Z); tool_matrix_rotate(mat, -sph[TOOL_MATRIX_SPHERICAL_THETA], TOOL_XYZ_Y); tool_matrix_rotate(mat, angle, TOOL_XYZ_Z); tool_matrix_rotate(mat, sph[TOOL_MATRIX_SPHERICAL_THETA], TOOL_XYZ_Y); tool_matrix_rotate(mat, sph[TOOL_MATRIX_SPHERICAL_PHI], TOOL_XYZ_Z); for (i = 0; i < ids->len; i++) { node = visu_node_array_getFromId(array, g_array_index(ids, guint, i)); if (node) { node->xyz[0] -= center[0]; node->xyz[1] -= center[1]; node->xyz[2] -= center[2]; tool_matrix_productVector(work, mat, node->xyz); node->xyz[0] = work[0] + center[0]; node->xyz[1] = work[1] + center[1]; node->xyz[2] = work[2] + center[2]; } } if (priv->nodeTable.posChgIds) g_array_append_vals(priv->nodeTable.posChgIds, ids->data, ids->len); else g_signal_emit(array, visu_node_array_signals[POSITION_CHANGED_SIGNAL], 0, ids); } /** * visu_node_array_join: * @array: a #VisuNodeArray object. * @frag: another #VisuNodeArray object. * @at: (array fixed-size=3): a position in cartesian coordinates. * * Add all nodes from @frag to @array and position them centred at @at. * * Since: 3.8 * * Returns: (transfer full) (element-type guint): the ids of the added * nodes in @array. **/ GArray* visu_node_array_join(VisuNodeArray *array, const VisuNodeArray *frag, const gfloat at[3]) { GArray *ids; guint i; GArray *elements, *nElements; VisuNodeArrayIter iter; gfloat centre[3], xyz[3]; VisuNodeArrayPrivate *priv = visu_node_array_get_instance_private(array); VisuNodeArrayPrivate *fpriv = visu_node_array_get_instance_private((VisuNodeArray*)frag); g_return_val_if_fail(priv && fpriv, NULL); elements = g_array_sized_new(FALSE, FALSE, sizeof(VisuElement*), fpriv->elements->len); nElements = g_array_sized_new(FALSE, FALSE, sizeof(guint), fpriv->elements->len); for (i = 0; i < fpriv->elements->len; i++) { EleArr *ele = _getEleArr(fpriv, i);; g_array_append_val(elements, ele->ele); g_array_append_val(nElements, ele->nStoredNodes); } visu_node_array_allocate(array, elements, nElements); g_array_unref(elements); g_array_unref(nElements); visu_node_array_iter_new(VISU_NODE_ARRAY((VisuNodeArray*)frag), &iter); centre[0] = 0.f; centre[1] = 0.f; centre[2] = 0.f; for (visu_node_array_iterStart(VISU_NODE_ARRAY((VisuNodeArray*)frag), &iter); iter.node; visu_node_array_iterNext(VISU_NODE_ARRAY((VisuNodeArray*)frag), &iter)) { centre[0] += iter.node->xyz[0]; centre[1] += iter.node->xyz[1]; centre[2] += iter.node->xyz[2]; } centre[0] = at[0] - centre[0] / (float)fpriv->nodeTable.nStoredNodes; centre[1] = at[1] - centre[1] / (float)fpriv->nodeTable.nStoredNodes; centre[2] = at[2] - centre[2] / (float)fpriv->nodeTable.nStoredNodes; visu_node_array_startAdding(array); for (visu_node_array_iterStart(VISU_NODE_ARRAY((VisuNodeArray*)frag), &iter); iter.node; visu_node_array_iterNext(VISU_NODE_ARRAY((VisuNodeArray*)frag), &iter)) { VisuNode *node = visu_node_array_getNewNode(array, iter.element); if (node) { xyz[0] = iter.node->xyz[0] + centre[0]; xyz[1] = iter.node->xyz[1] + centre[1]; xyz[2] = iter.node->xyz[2] + centre[2]; visu_node_setCoordinates(node, xyz); } } ids = g_array_ref(priv->nodeTable.popIncIds); visu_node_array_completeAdding(array); return ids; } /*******************/ /* Local routines. */ /*******************/ static void onElementRenderChanged(VisuNodeArray *data, GParamSpec *pspec _U_, VisuElement *element) { DBG_fprintf(stderr, "Visu NodeArray: caught the 'ElementVisibilityChanged' signal," " emitting node render signal.\n"); g_signal_emit(G_OBJECT(data), visu_node_array_signals[ELEMENT_VISIBILITY_CHANGED_SIGNAL], 0, element); visu_maskable_visibilityChanged(VISU_MASKABLE(data)); } static void onElementPlaneChanged(VisuNodeArray *data, GParamSpec *pspec _U_, VisuElement *element) { DBG_fprintf(stderr, "Visu NodeArray: caught the 'ElementMaskableChanged' signal," " emitting node render signal.\n"); g_signal_emit(G_OBJECT(data), visu_node_array_signals[ELEMENT_PLANE_CHANGED_SIGNAL], 0, element); } /**************************/ /* The property routines. */ /**************************/ static void freeNodePropStruct(gpointer data) { VisuNodeProperty *prop; guint i, j; EleArr *ele; VisuNodeArrayPrivate *priv; prop = (VisuNodeProperty*)data; DBG_fprintf(stderr, "Visu Node: freeing node property '%s'.\n", prop->name); g_free(prop->name); priv = visu_node_array_get_instance_private(prop->array); /* The pointer case. */ if (priv && prop->data_pointer) { for (i = 0; i < priv->elements->len; i++) { for (ele = _getEleArr(priv, i), j = 0; j < ele->nNodes; j++) if (prop->data_pointer[i][j]) { if (prop->freeTokenFunc) prop->freeTokenFunc(prop->data_pointer[i][j], prop->user_data); else g_free(prop->data_pointer[i][j]); } g_free(prop->data_pointer[i]); } g_free(prop->data_pointer); } /* The integer case */ if (priv && prop->data_int) { for (i = 0; i < priv->elements->len; i++) g_free(prop->data_int[i]); g_free(prop->data_int); } g_free(prop); DBG_fprintf(stderr, "Visu Node: freeing property ... OK.\n"); } /* Remove the property of all nodes of the element given in data. */ static void removeNodePropertyForElement(gpointer key, gpointer value, gpointer data) { guint iEle; guint j; EleArr *ele; VisuNodeProperty *prop; VisuNodeArrayPrivate *priv; prop = (VisuNodeProperty*)value; iEle= GPOINTER_TO_INT(data); priv = visu_node_array_get_instance_private(prop->array); g_return_if_fail(priv && iEle < priv->elements->len); ele = _getEleArr(priv, iEle); DBG_fprintf(stderr, "Visu Node: remove node property '%s' for all nodes of element '%s'.\n", (gchar*)key, ele->ele->name); /* We first remove the property tokens. */ switch (prop->gtype) { case G_TYPE_POINTER: for (j = 0; j < ele->nNodes; j++) if (prop->data_pointer[iEle][j]) { if (prop->freeTokenFunc) prop->freeTokenFunc(prop->data_pointer[iEle][j], prop->user_data); else g_free(prop->data_pointer[iEle][j]); prop->data_pointer[iEle][j] = (gpointer)0; } break; case G_TYPE_INT: for (j = 0; j < ele->nNodes; j++) prop->data_int[iEle][j] = 0; break; default: g_warning("Unsupported GValue type for property '%s'.", prop->name); } } /* Remove the property of the node given in data and move the last property of this element at the place of the removed node. */ static void removeNodeProperty(gpointer key, gpointer value, gpointer data) { EleArr *ele; VisuNode *node; VisuNodeProperty *prop; VisuNodeArrayPrivate *priv; node = (VisuNode*)data; prop = (VisuNodeProperty*)value; priv = visu_node_array_get_instance_private(prop->array); g_return_if_fail(priv); ele = _getEleArr(priv, node->posElement); g_return_if_fail(ele->nStoredNodes > 0); DBG_fprintf(stderr, "Visu Node: remove node property '%s' from %d %d.\n", (gchar*)key, node->posElement, node->posNode); /* We first remove the property token. */ switch (prop->gtype) { case G_TYPE_POINTER: if (prop->data_pointer[node->posElement][node->posNode]) { if (prop->freeTokenFunc) prop->freeTokenFunc(prop->data_pointer[node->posElement][node->posNode], prop->user_data); else g_free(prop->data_pointer[node->posElement][node->posNode]); } break; case G_TYPE_INT: prop->data_int[node->posElement][node->posNode] = 0; break; default: g_warning("Unsupported GValue type for property '%s'.", prop->name); } /* Then we copy the pointer from the last position to the given one. The last position is given by nStoredNodesPerEle since this counter has already been lowered. */ switch (prop->gtype) { case G_TYPE_POINTER: prop->data_pointer[node->posElement][node->posNode] = prop->data_pointer[node->posElement][ele->nStoredNodes]; prop->data_pointer[node->posElement][ele->nStoredNodes] = (gpointer)0; break; case G_TYPE_INT: prop->data_int[node->posElement][node->posNode] = prop->data_int[node->posElement][ele->nStoredNodes]; prop->data_int[node->posElement][ele->nStoredNodes] = 0; break; default: g_warning("Unsupported GValue type for property '%s'.", prop->name); } } static void reallocNodeProperty(gpointer key, gpointer value, gpointer data) { EleArr *ele; VisuNodeProperty *prop; guint iEle, j; VisuNodeArrayPrivate *priv; iEle = (guint)GPOINTER_TO_INT(data); prop = (VisuNodeProperty*)value; DBG_fprintf(stderr, "Visu Node: realloc node property '%s' for element %d.\n", (gchar*)key, iEle); priv = visu_node_array_get_instance_private(prop->array); g_return_if_fail(priv && iEle < priv->elements->len); ele = _getEleArr(priv, iEle); switch (prop->gtype) { case G_TYPE_POINTER: prop->data_pointer[iEle] = g_realloc(prop->data_pointer[iEle], sizeof(gpointer) * ele->nNodes); /* We nullify the newly created properties. */ for (j = ele->nStoredNodes; j < ele->nNodes; j++) prop->data_pointer[iEle][j] = (gpointer)0; break; case G_TYPE_INT: prop->data_int[iEle] = g_realloc(prop->data_int[iEle], sizeof(int) * ele->nNodes); /* We nullify the newly created properties. */ for (j = ele->nStoredNodes; j < ele->nNodes; j++) prop->data_int[iEle][j] = 0; break; default: g_warning("Unsupported GValue type for property '%s'.", prop->name); } } static void allocateNodeProp(gpointer key, gpointer value, gpointer data _U_) { guint i; VisuNodeProperty *prop; VisuNodeArrayPrivate *priv; prop = (VisuNodeProperty*)value; DBG_fprintf(stderr, "Visu Node: realloc node property '%s' for 1 new element.\n", (gchar*)key); priv = visu_node_array_get_instance_private(prop->array); g_return_if_fail(priv); switch (prop->gtype) { case G_TYPE_POINTER: prop->data_pointer = g_realloc(prop->data_pointer, sizeof(gpointer*) * priv->elements->len); i = priv->elements->len - 1; prop->data_pointer[i] = g_malloc0(sizeof(gpointer) * _getEleArr(priv, i)->nNodes); break; case G_TYPE_INT: prop->data_int = g_realloc(prop->data_int, sizeof(int*) * priv->elements->len); i = priv->elements->len - 1; prop->data_int[i] = g_malloc0(sizeof(int) * _getEleArr(priv, i)->nNodes); break; default: g_warning("Unsupported GValue type for property '%s'.", prop->name); } } static void createNodeproperty(gpointer key, gpointer value, gpointer data) { VisuNodeProperty *prop; struct twoNodes *nodes; prop = (VisuNodeProperty*)value; nodes = (struct twoNodes*)data; DBG_fprintf(stderr, "Visu Node: create/copy node property '%s' for node %d-%d.\n", (gchar*)key, nodes->newNode->posElement, nodes->newNode->posNode); switch (prop->gtype) { case G_TYPE_POINTER: if (nodes->oldNode) prop->data_pointer[nodes->newNode->posElement][nodes->newNode->posNode] = prop->newOrCopyTokenFunc((gconstpointer)prop->data_pointer[nodes->oldNode->posElement][nodes->oldNode->posNode], prop->user_data); else prop->data_pointer[nodes->newNode->posElement][nodes->newNode->posNode] = (gpointer)0; break; case G_TYPE_INT: if (nodes->oldNode) prop->data_int[nodes->newNode->posElement][nodes->newNode->posNode] = prop->data_int[nodes->oldNode->posElement][nodes->oldNode->posNode]; else prop->data_int[nodes->newNode->posElement][nodes->newNode->posNode] = 0; break; default: g_warning("Unsupported GValue type for property '%s'.", prop->name); } } /*****************************/ /* Public property routines. */ /*****************************/ /** * visu_node_property_getArray: * @nodeProp: a #VisuNodeProperty structure. * * Retrieve the #VisuNodeArray @nodeProp is attached to. * * Since: 3.8 * * Returns: (transfer none): the #VisuNodeArray @nodeProp is attached to. **/ VisuNodeArray* visu_node_property_getArray(const VisuNodeProperty* nodeProp) { g_return_val_if_fail(nodeProp, (VisuNodeArray*)0); return nodeProp->array; } /** * visu_node_property_setValue: * @nodeProp: a #VisuNodeProperty object ; * @node: a #VisuNode object ; * @value: A GValue pointer this the value to be stored. * * This method is used to store some values associated with * the given @node of the given @nodeArray. These values can be pointers to * anything allocated (will be free automatically when the property is deleted) or * they can be static values. This depends on the construction of the node property. * These values can be retrieved with the visu_node_property_getValue() method. * * See visu_node_array_getProperty() to get a property by its name. */ void visu_node_property_setValue(VisuNodeProperty* nodeProp, const VisuNode* node, const GValue *value) { float fval; VisuNodeArrayPrivate *priv; g_return_if_fail(nodeProp && value); priv = visu_node_array_get_instance_private(nodeProp->array); g_return_if_fail(priv && node && node->posElement < priv->elements->len && node->posNode < _getEleArr(priv, node->posElement)->nStoredNodes); switch (nodeProp->gtype) { case G_TYPE_POINTER: /* Quick return if in place. */ if (G_VALUE_HOLDS_BOXED(value) && g_value_get_boxed(value) == nodeProp->data_pointer[node->posElement][node->posNode]) return; if (G_VALUE_HOLDS_POINTER(value) && g_value_get_pointer(value) == nodeProp->data_pointer[node->posElement][node->posNode]) return; /* We free previous pointer. */ if (nodeProp->freeTokenFunc && nodeProp->data_pointer[node->posElement][node->posNode]) nodeProp->freeTokenFunc(nodeProp->data_pointer[node->posElement][node->posNode], nodeProp->user_data); else g_free(nodeProp->data_pointer[node->posElement][node->posNode]); /* We set the value. */ if (G_VALUE_HOLDS_STRING(value)) nodeProp->data_pointer[node->posElement][node->posNode] = nodeProp->newOrCopyTokenFunc((gpointer)g_value_get_string(value), nodeProp->user_data); else if (G_VALUE_HOLDS_FLOAT(value)) { fval = g_value_get_float(value); nodeProp->data_pointer[node->posElement][node->posNode] = nodeProp->newOrCopyTokenFunc(&fval, nodeProp->user_data); } else if (G_VALUE_HOLDS_BOXED(value)) nodeProp->data_pointer[node->posElement][node->posNode] = nodeProp->newOrCopyTokenFunc(g_value_get_boxed(value), nodeProp->user_data); else nodeProp->data_pointer[node->posElement][node->posNode] = nodeProp->newOrCopyTokenFunc(g_value_get_pointer(value), nodeProp->user_data); break; case G_TYPE_INT: if (G_VALUE_HOLDS_BOOLEAN(value)) nodeProp->data_int[node->posElement][node->posNode] = (int)g_value_get_boolean(value); else nodeProp->data_int[node->posElement][node->posNode] = g_value_get_int(value); break; default: g_warning("Unsupported GValue type for property '%s'.", nodeProp->name); } } /** * visu_node_property_getValue: * @nodeProp: a #VisuNodeArray object ; * @node: a #VisuNode object ; * @value: an initialise GValue location. * * This method is used to retrieve some data associated to * the specified @node, stored in the given @data. These return data * should not be freed after used. The read value is stored in the given * GValue pointer. This GValue must be of the right type, depending on the * creation of the #VisuNodeProperty. * * Returns: some data associated to the key, stored the given GValue location. */ GValue* visu_node_property_getValue(const VisuNodeProperty* nodeProp, const VisuNode* node, GValue *value) { VisuNodeArrayPrivate *priv = visu_node_array_get_instance_private(nodeProp->array); g_return_val_if_fail(priv, value); g_return_val_if_fail(nodeProp && value, value); g_return_val_if_fail(node && node->posElement < priv->elements->len && node->posNode < _getEleArr(priv, node->posElement)->nStoredNodes, value); switch (nodeProp->gtype) { case G_TYPE_POINTER: if (G_VALUE_HOLDS_STRING(value)) g_value_set_string(value, (gchar*)nodeProp->data_pointer[node->posElement][node->posNode]); else if (G_VALUE_HOLDS_BOXED(value)) g_value_set_static_boxed(value, nodeProp->data_pointer[node->posElement][node->posNode]); else { DBG_fprintf(stderr, "Visu Node: get '%s' for node %d(%d,%d) as pointer %p.\n", nodeProp->name, node->number, node->posElement, node->posNode, (gpointer)nodeProp->data_pointer[node->posElement][node->posNode]); g_value_set_pointer(value, nodeProp->data_pointer[node->posElement][node->posNode]); } return value; case G_TYPE_INT: if (G_VALUE_HOLDS_POINTER(value)) { DBG_fprintf(stderr, "Visu Node: get property '%s' for node %d as pointer %d.\n", nodeProp->name, node->number, nodeProp->data_int[node->posElement][node->posNode]); g_value_set_pointer(value, &nodeProp->data_int[node->posElement][node->posNode]); } else if (G_VALUE_HOLDS_BOOLEAN(value)) g_value_set_boolean(value, (gboolean)nodeProp->data_int[node->posElement][node->posNode]); else { DBG_fprintf(stderr, "Visu Node: get property '%s' for node %d as integer %d.\n", nodeProp->name, node->number, nodeProp->data_int[node->posElement][node->posNode]); g_value_set_int(value, nodeProp->data_int[node->posElement][node->posNode]); } return value; break; default: g_warning("Unsupported GValue type for property '%s'.", nodeProp->name); } return value; } /** * visu_node_array_getProperty: * @nodeArray: a #VisuNodeArray object ; * @key: a string. * * This method is used to retrieve the node property associated to the given @key. * * Returns: (transfer none): a #VisuNodeProperty. */ VisuNodeProperty* visu_node_array_getProperty(VisuNodeArray* nodeArray, const char* key) { VisuNodeProperty *prop; VisuNodeArrayPrivate *priv = visu_node_array_get_instance_private(nodeArray); g_return_val_if_fail(priv && key, (VisuNodeProperty*)0); prop = (VisuNodeProperty*)g_hash_table_lookup(priv->nodeProp, (gpointer)key); return prop; } /** * visu_node_array_freeProperty: * @nodeArray: a #VisuNodeArray object. * @key: the name of the property to be removed. * * This method free the given property and all associated data. */ void visu_node_array_freeProperty(VisuNodeArray* nodeArray, const char* key) { VisuNodeArrayPrivate *priv = visu_node_array_get_instance_private(nodeArray); g_return_if_fail(priv && key); g_hash_table_remove(priv->nodeProp, key); DBG_fprintf(stderr, "Visu Node: removing the property called '%s'.\n", key); } /** * visu_node_array_property_newPointer: * @nodeArray: a #VisuNodeArray object ; * @key: a string ; * @freeFunc: (allow-none) (scope call): a method to free each token (can be NULL). * @newAndCopyFunc: (scope call): a method to create or copy each token. * @user_data: (closure): a user defined pointer that will be given to * the free and copy routine. * * This method creates and allocates a new area to store nodes associated data that * can be retrieve with the @key. These data are pointers on allocated memory * locations. When the property is removed with the #visu_node_freePropertry (or the * associated #VisuNodeArray is free) the area is free and @freeFunc is called for * each token (or g_free() if @freeFunc is NULL). * * The method @newAndCopyFunc is used when the number of nodes is increased, * if the const gpointer of the GCopyFunc is not NULL, then we require a copy, * if it is NULL, then the routine must create a new token with * default values. * * If the property already exists, it is returned. * * Returns: (transfer none): the newly created #VisuNodeProperty * object or the existing one. */ VisuNodeProperty* visu_node_array_property_newPointer(VisuNodeArray* nodeArray, const char* key, GFunc freeFunc, GCopyFunc newAndCopyFunc, gpointer user_data) { VisuNodeProperty *prop; EleArr *ele; VisuNodeArrayPrivate *priv = visu_node_array_get_instance_private(nodeArray); guint i; g_return_val_if_fail(priv && key && newAndCopyFunc, (VisuNodeProperty*)0); prop = (VisuNodeProperty*)g_hash_table_lookup(priv->nodeProp, key); if (prop) return prop; DBG_fprintf(stderr, "Visu Node: adding a new pointer" " property, called '%s'.\n", key); prop = g_malloc(sizeof(VisuNodeProperty)); prop->gtype = G_TYPE_POINTER; prop->name = g_strdup(key); prop->array = nodeArray; prop->data_pointer = (gpointer**)0; prop->data_int = (int**)0; if (priv->elements->len > 0) prop->data_pointer = g_malloc(sizeof(gpointer*) * priv->elements->len); for (i = 0; i < priv->elements->len; i++) { ele = _getEleArr(priv, i); DBG_fprintf(stderr, " | allocate (%d,%d)\n", i, ele->nNodes); prop->data_pointer[i] = g_malloc0(sizeof(gpointer) * ele->nNodes); } prop->freeTokenFunc = freeFunc; prop->newOrCopyTokenFunc = newAndCopyFunc; prop->user_data = user_data; g_hash_table_insert(priv->nodeProp, (gpointer)key, (gpointer)prop); return prop; } static void freeFloatArray(gpointer obj, gpointer data) { #if GLIB_MINOR_VERSION > 9 g_slice_free1(sizeof(float) * GPOINTER_TO_INT(data), obj); #else if (GPOINTER_TO_INT(data) > 0) g_free(obj); #endif } static gpointer newAndCopyFloatArray(gconstpointer orig, gpointer user_data) { float *data; int nb; if (!orig) return (gpointer)0; nb = GPOINTER_TO_INT(user_data); #if GLIB_MINOR_VERSION > 9 data = g_slice_alloc(sizeof(float) * nb); #else data = g_malloc(sizeof(float) * nb); #endif if (orig) memcpy(data, orig, sizeof(float) * nb); else memset(data, 0, sizeof(float) * nb); return (gpointer)data; } /** * visu_node_array_property_newFloatArray: * @nodeArray: a #VisuNodeArray object ; * @key: a string ; * @len: the number of floats to be stored per node. * * This method creates and allocates a new area to store nodes associated data that * can be retrieve with the @key. These data are constant float arrays * of length @len. * * If the property already exists, it is returned. * * Since: 3.8 * * Returns: (transfer none): the newly created #VisuNodeProperty * object or the existing one. */ VisuNodeProperty* visu_node_array_property_newFloatArray(VisuNodeArray* nodeArray, const char* key, guint len) { VisuNodeProperty *prop; EleArr *ele; VisuNodeArrayPrivate *priv = visu_node_array_get_instance_private(nodeArray); guint i; g_return_val_if_fail(priv && key && len > 0, (VisuNodeProperty*)0); prop = (VisuNodeProperty*)g_hash_table_lookup(priv->nodeProp, key); if (prop) return prop; DBG_fprintf(stderr, "Visu Node: adding a new float array" " property, called '%s'.\n", key); prop = g_malloc(sizeof(VisuNodeProperty)); prop->gtype = G_TYPE_POINTER; prop->name = g_strdup(key); prop->array = nodeArray; prop->data_pointer = (gpointer**)0; prop->data_int = (int**)0; if (priv->elements->len > 0) prop->data_pointer = g_malloc(sizeof(gpointer*) * priv->elements->len); for (i = 0; i < priv->elements->len; i++) { ele = _getEleArr(priv, i); DBG_fprintf(stderr, " | allocate (%d,%d)\n", i, ele->nNodes); prop->data_pointer[i] = g_malloc0(sizeof(gpointer) * ele->nNodes); } prop->freeTokenFunc = freeFloatArray; prop->newOrCopyTokenFunc = newAndCopyFloatArray; prop->user_data = GINT_TO_POINTER(len); g_hash_table_insert(priv->nodeProp, (gpointer)key, (gpointer)prop); return prop; } /** * visu_node_array_property_newInteger: * @nodeArray: a #VisuNodeArray object ; * @key: a string. * * This method creates and allocates a new area to store nodes associated integer * values. This is the same than visu_node_array_property_newPointer() but for static * integers instead of pointers as data. * * Returns: (transfer none): the newly created #VisuNodeProperty object. */ VisuNodeProperty* visu_node_array_property_newInteger(VisuNodeArray* nodeArray, const char* key) { VisuNodeProperty *prop; EleArr *ele; VisuNodeArrayPrivate *priv = visu_node_array_get_instance_private(nodeArray); guint i; g_return_val_if_fail(priv && key, (VisuNodeProperty*)0); prop = (VisuNodeProperty*)g_hash_table_lookup(priv->nodeProp, key); if (prop) return prop; DBG_fprintf(stderr, "Visu Node: adding a new int property, called '%s'.\n", key); prop = g_malloc(sizeof(VisuNodeProperty)); prop->gtype = G_TYPE_INT; prop->name = g_strdup(key); prop->array = nodeArray; prop->data_pointer = (gpointer**)0; prop->data_int = (int**)0; if (priv->elements->len > 0) prop->data_int = g_malloc(sizeof(int*) * priv->elements->len); for (i = 0; i < priv->elements->len; i++) { ele = _getEleArr(priv, i); DBG_fprintf(stderr, " | allocate (%d,%d)\n", i, ele->nNodes); prop->data_int[i] = g_malloc0(sizeof(int) * ele->nNodes); } prop->freeTokenFunc = (GFunc)0; prop->newOrCopyTokenFunc = (GCopyFunc)0; prop->user_data = (gpointer)0; g_hash_table_insert(priv->nodeProp, (gpointer)key, (gpointer)prop); return prop; } /** * visu_node_property_reset: * @prop: A #VisuNodeProperty object. * * Reset to zero all values, deallocating allocated memory, if any. * * Since: 3.8 **/ void visu_node_property_reset(VisuNodeProperty* prop) { guint i, j; EleArr *ele; VisuNodeArrayPrivate *priv = visu_node_array_get_instance_private(prop->array); g_return_if_fail(prop && priv); switch (prop->gtype) { case G_TYPE_POINTER: for (i = 0; i < priv->elements->len; i++) { ele = _getEleArr(priv, i); if (prop->freeTokenFunc) for (j = 0; j < ele->nNodes; j++) if (prop->data_pointer[i][j]) prop->freeTokenFunc(prop->data_pointer[i][j], prop->user_data); memset(prop->data_pointer[i], '\0', sizeof(gpointer) * ele->nNodes); } break; case G_TYPE_INT: for (i = 0; i < priv->elements->len; i++) { ele = _getEleArr(priv, i); memset(prop->data_int[i], '\0', sizeof(int) * ele->nNodes); } break; default: g_warning("Unsupported type for property '%s'.", prop->name); } } /** * visu_node_array_traceProperty: * @array: a #VisuNodeArray object ; * @id: a property name. * * This is a debug method. It outputs on stderr the values for all * nodes of the property @id. */ void visu_node_array_traceProperty(VisuNodeArray *array, const gchar *id) { VisuNodeProperty* prop; EleArr *ele; guint i, j; VisuNodeArrayPrivate *priv = visu_node_array_get_instance_private(array); prop = visu_node_array_getProperty(array, id); fprintf(stderr, "Visu Node: output node property '%s'.\n", id); fprintf(stderr, " | type= %d\n", (int)prop->gtype); g_return_if_fail(priv); if (prop->data_int) { for (i = 0; i < priv->elements->len; i++) for (ele = _getEleArr(priv, i), j = 0; j < ele->nStoredNodes; j++) fprintf(stderr, " | %7d %3d %7d -> %d\n", ele->nodes[j].number, i, j, prop->data_int[i][j]); } if (prop->data_pointer) { for (i = 0; i < priv->elements->len; i++) for (ele = _getEleArr(priv, i), j = 0; j < ele->nStoredNodes; j++) fprintf(stderr, " | %7d %3d %7d -> %p\n", ele->nodes[j].number, i, j, prop->data_pointer[i][j]); } } /**********************/ /* Element properties */ /**********************/ static void allocateEleProp(gpointer key, gpointer value, gpointer data) { struct _ElementProperty *prop = (struct _ElementProperty*)value; VisuElement *ele = VISU_ELEMENT(data); GValue val = G_VALUE_INIT; DBG_fprintf(stderr, "Visu Data: allocate element property '%s'.\n", (gchar*)key); prop->init(ele, &val); g_array_append_val(prop->array, val); DBG_fprintf(stderr, " | now has %d elements.\n", prop->array->len); } /* static void freeEleProp(gpointer key, gpointer value, gpointer data _U_) */ /* { */ /* struct _ElementProperty *prop = (struct _ElementProperty*)value; */ /* gint i; */ /* DBG_fprintf(stderr, "Visu Data: free element property '%s'.\n", (gchar*)key); */ /* for (i = prop->array->priv->n_values - 1; i >= 0; i--) */ /* g_value_array_remove(prop->array, i); */ /* } */ static void freeElePropStruct(gpointer data) { struct _ElementProperty *prop = (struct _ElementProperty*)data; g_array_free(prop->array, TRUE); g_free(data); } /** * visu_node_array_setElementProperty: * @data: a #VisuNodeArray object. * @name: a string to identify the property. * @init: (scope call): an init routine. * * Create a new array to stores properties related to elements. If the * property @name already exists the previous one is destroyed. The * @init routine is called for each #VisuElement of the @data. * * Since: 3.7 * * Returns: (transfer none) (element-type GLib.Value): a newly allocated array. **/ GArray* visu_node_array_setElementProperty(VisuNodeArray *data, const gchar *name, VisuNodeArrayElementPropertyInit init) { struct _ElementProperty *prop; guint i; GValue val = G_VALUE_INIT; VisuNodeArrayPrivate *priv = visu_node_array_get_instance_private(data); g_return_val_if_fail(priv, (GArray*)0); g_return_val_if_fail(name && name[0] && init, (GArray*)0); DBG_fprintf(stderr, "Visu Data: add a new element property '%s'.\n", name); prop = g_malloc(sizeof(struct _ElementProperty)); prop->init = init; prop->array = g_array_sized_new(FALSE, FALSE, sizeof(GValue), priv->elements->len); g_hash_table_insert(priv->eleProp, (gpointer)name, (gpointer)prop); for (i = 0; i < priv->elements->len; i++) { memset(&val, '\0', sizeof(GValue)); init(_getElement(priv, i), &val); g_array_insert_val(prop->array, i, val); } return prop->array; } /** * visu_node_array_getElementProperty: * @data: a #VisuNodeArray object ; * @name: an identifier string. * * This routine is used to retrieve an array of #GValue for each * element of the @data array. * * Since: 3.7 * * Returns: (transfer none) (element-type GLib.Value): an array of #GValue, indexed by the id of * each #VisuElement of @data. */ GArray* visu_node_array_getElementProperty(VisuNodeArray *data, const gchar *name) { struct _ElementProperty *prop; VisuNodeArrayPrivate *priv = visu_node_array_get_instance_private(data); g_return_val_if_fail(priv, (GArray*)0); DBG_fprintf(stderr, "Visu Data: get element property '%s'.\n", name); prop = (struct _ElementProperty*)g_hash_table_lookup(priv->eleProp, name); return prop ? prop->array : (GArray*)0; } /****************/ /* The iterator */ /****************/ /** * visu_node_array_iter_new: * @array: a #VisuNodeArray object ; * @iter: (out caller-allocates) (transfer full): an alocated iterator. * * Set values to a #VisuNodeArrayIter object to iterate over nodes. * Its contain is initialised with the array size (number of elements, * number of nodes per element...). */ void visu_node_array_iter_new(VisuNodeArray *array, VisuNodeArrayIter *iter) { VisuNodeArrayPrivate *priv = visu_node_array_get_instance_private(array); g_return_if_fail(iter && priv); iter->nAllStoredNodes = 0; iter->nElements = 0; iter->nStoredNodes = 0; iter->node = (VisuNode*)0; iter->element = (VisuElement*)0; iter->type = ITER_NODES_BY_TYPE; iter->init = FALSE; g_return_if_fail(VISU_IS_NODE_ARRAY(array)); iter->array = array; iter->idMax = priv->nodeTable.idCounter - 1; iter->nAllStoredNodes = priv->nodeTable.nStoredNodes; iter->nElements = priv->elements->len; iter->iElement = -1; iter->itLst = (GList*)0; iter->arr = (GArray*)0; g_return_if_fail(priv->nodeTable.idCounter >= priv->nodeTable.nStoredNodes); } /** * visu_node_array_iterStart: * @array: a #VisuNodeArray object ; * @iter: a #VisuNodeArrayIter object. * * Initialise the node and element internal pointers for a run over the nodes. */ void visu_node_array_iterStart(VisuNodeArray *array, VisuNodeArrayIter *iter) { EleArr *ele; VisuNodeArrayPrivate *priv = visu_node_array_get_instance_private(array); g_return_if_fail(priv && iter && array == iter->array); iter->init = TRUE; iter->iElement = -1; iter->node = (VisuNode*)0; iter->element = (VisuElement*)0; if (priv->elements->len == 0) return; ele = _getEleArr(priv, 0); iter->iElement = 0; iter->element = ele->ele; /* We look for an element with stored nodes. */ while (ele->nStoredNodes == 0) { iter->iElement += 1; if (iter->iElement >= priv->elements->len) { /* We found nothing. */ iter->iElement = -1; iter->element = (VisuElement*)0; return; } ele = _getEleArr(priv, iter->iElement); iter->element = ele->ele; iter->nStoredNodes = ele->nStoredNodes; } iter->node = ele->nodes; iter->nStoredNodes = ele->nStoredNodes; } /** * visu_node_array_iterStartNumber: * @array: a #VisuNodeArray object ; * @iter: a #VisuNodeArrayIter object. * * Initialise the node and element internal pointers for a run * following the node oder. */ void visu_node_array_iterStartNumber(VisuNodeArray *array, VisuNodeArrayIter *iter) { guint i; VisuNodeArrayPrivate *priv = visu_node_array_get_instance_private(array); g_return_if_fail(priv && iter && array == iter->array); iter->init = TRUE; iter->iElement = -1; iter->node = (VisuNode*)0; iter->element = (VisuElement*)0; if (priv->elements->len == 0) return; i = 0; iter->node = (VisuNode*)0; do { iter->node = visu_node_array_getFromId(VISU_NODE_ARRAY(array), i); i += 1; } while (!iter->node && i < priv->nodeTable.idCounter); if (!iter->node) return; iter->iElement = iter->node->posElement; iter->element = _getElement(priv, iter->iElement); iter->nStoredNodes = _getEleArr(priv, iter->iElement)->nStoredNodes; } /** * visu_node_array_iterStartVisible: * @array: a #VisuNodeArray object ; * @iter: a #VisuNodeArrayIter object. * * Initialise the node and element internal pointers for a run over the * visible nodes (see visu_node_array_iterNextVisible). */ void visu_node_array_iterStartVisible(VisuNodeArray *array, VisuNodeArrayIter *iter) { visu_node_array_iterStart(array, iter); if (iter->node && iter->node->rendered && visu_element_getRendered(iter->element)) /* Ok, first is good. */ return; /* First was not visible, we go next. */ visu_node_array_iterNextVisible(array, iter); } /** * visu_node_array_iterStartList: * @array: a #VisuNodeArray object ; * @iter: (out caller-allocates) (transfer full): an alocated * iterator. * @lst: (element-type guint) (transfer none): a list of node ids to * iterate on. * * Set values to a #VisuNodeArrayIter object to iterate over nodes of * the given list. * * Since: 3.7 */ void visu_node_array_iterStartList(VisuNodeArray *array, VisuNodeArrayIter *iter, GList *lst) { GList init; g_return_if_fail(iter); iter->init = TRUE; iter->type = ITER_NODES_FROM_LIST; init.next = lst; iter->itLst = &init; visu_node_array_iterNextList(array, iter); } /** * visu_node_array_iterStartArray: * @array: a #VisuNodeArray object ; * @iter: (out caller-allocates) (transfer full): an alocated * iterator. * @arr: (element-type guint) (transfer full): an array of node ids to * iterate on. * * Set values to a #VisuNodeArrayIter object to iterate over nodes of * the given array. * * Since: 3.8 */ void visu_node_array_iterStartArray(VisuNodeArray *array, VisuNodeArrayIter *iter, GArray *arr) { g_return_if_fail(iter); iter->init = TRUE; iter->type = ITER_NODES_FROM_ARRAY; iter->arr = arr; iter->itArr = 0; visu_node_array_iterNextArray(array, iter); } /** * visu_node_array_iterWhere: * @array: a #VisuNodeArray object ; * @iter: (out caller-allocates) (transfer full): an alocated * iterator. * @where: (closure data) (scope call): the function to evaluate on * each node. * @data: (closure) (allow-none): user data. * * Starts @iter to iterate on nodes of @array, when the condition * defined by @where evaluates to TRUE. @iter is then to be used with * visu_node_array_iterNextArray(). * * Since: 3.8 **/ void visu_node_array_iterWhere(VisuNodeArray *array, VisuNodeArrayIter *iter, VisuNodeArrayIterFunc where, gpointer data) { GArray *arr; VisuNodeArrayIter it; g_return_if_fail(where); arr = g_array_new(FALSE, FALSE, sizeof(guint)); visu_node_array_iter_new(array, &it); for (visu_node_array_iterStart(array, &it); it.node; visu_node_array_iterNext(array, &it)) if (where(array, &it, data)) g_array_append_val(arr, it.node->number); visu_node_array_iter_new(array, iter); visu_node_array_iterStartArray(array, iter, arr); } /** * visu_node_array_iterRestartNode: * @array: a #VisuNodeArray object ; * @iter: a #VisuNodeArrayIter object. * * The element internal pointer must be associated. Then, it returns the * node pointer to the first node for this element. */ void visu_node_array_iterRestartNode(VisuNodeArray *array, VisuNodeArrayIter *iter) { gint iEle; EleArr *ele; VisuNodeArrayPrivate *priv = visu_node_array_get_instance_private(array); g_return_if_fail(priv && iter && array == iter->array); iEle = visu_node_array_getElementId(array, iter->element); g_return_if_fail(iEle >= 0); iter->init = TRUE; iter->iElement = (guint)iEle; ele = _getEleArr(priv, iEle); if (ele->nStoredNodes) iter->node = ele->nodes; else iter->node = (VisuNode*)0; iter->nStoredNodes = ele->nStoredNodes; } /** * visu_node_array_iterNext: * @array: a #VisuNodeArray object ; * @iter: a #VisuNodeArrayIter object. * * Modify node and element internal pointers to the next node, or NULL if * none remains. */ void visu_node_array_iterNext(VisuNodeArray *array, VisuNodeArrayIter *iter) { guint iNode; EleArr *ele; VisuNodeArrayPrivate *priv = visu_node_array_get_instance_private(array); g_return_if_fail(priv && iter && array == iter->array); g_return_if_fail(iter->init && iter->node && iter->iElement == iter->node->posElement); ele = _getEleArr(priv, iter->iElement); iNode = iter->node->posNode + 1; if (iNode < ele->nStoredNodes) iter->node = ele->nodes + iNode; else { iter->iElement += 1; if (iter->iElement >= priv->elements->len) { iter->node = (VisuNode*)0; iter->iElement = -1; iter->element = (VisuElement*)0; iter->nStoredNodes = 0; } else { ele = _getEleArr(priv, iter->iElement); iter->node = ele->nodes; iter->element = ele->ele; iter->nStoredNodes = ele->nStoredNodes; } } } /** * visu_node_array_iterNextList: * @array: a #VisuNodeArray object ; * @iter: a #VisuNodeArrayIter object. * * Modify node and element internal pointers to the next node from the * starting list, or NULL if none remains. * * Since: 3.7 */ void visu_node_array_iterNextList(VisuNodeArray *array, VisuNodeArrayIter *iter) { EleArr *ele; VisuNodeArrayPrivate *priv = visu_node_array_get_instance_private(array); g_return_if_fail(priv && iter && array == iter->array); g_return_if_fail(iter->init && iter->type == ITER_NODES_FROM_LIST); g_return_if_fail(iter->itLst); do { iter->itLst = g_list_next(iter->itLst); iter->node = (iter->itLst)?visu_node_array_getFromId(array, GPOINTER_TO_INT(iter->itLst->data)):(VisuNode*)0; } while (iter->itLst && !iter->node); if (!iter->itLst) { iter->itLst = (GList*)0; iter->node = (VisuNode*)0; } /* We set additional elements. */ if (!iter->node) { iter->iElement = -1; iter->element = (VisuElement*)0; iter->nStoredNodes = 0; } else { ele = _getEleArr(priv, iter->node->posElement); iter->iElement = iter->node->posElement; iter->element = ele->ele; iter->nStoredNodes = ele->nStoredNodes; } } /** * visu_node_array_iterNextArray: * @array: a #VisuNodeArray object ; * @iter: a #VisuNodeArrayIter object. * * Modify node and element internal pointers to the next node from the * starting array, or NULL if none remains. * * Since: 3.8 */ void visu_node_array_iterNextArray(VisuNodeArray *array, VisuNodeArrayIter *iter) { EleArr *ele; VisuNodeArrayPrivate *priv = visu_node_array_get_instance_private(array); g_return_if_fail(priv && iter && array == iter->array); g_return_if_fail(iter->init && iter->type == ITER_NODES_FROM_ARRAY); if (iter->itArr < iter->arr->len) iter->node = visu_node_array_getFromId(array, g_array_index(iter->arr, guint, iter->itArr)); else { iter->node = (VisuNode*)0; g_array_unref(iter->arr); } iter->itArr += 1; /* We set additional elements. */ if (!iter->node) { iter->iElement = -1; iter->element = (VisuElement*)0; iter->nStoredNodes = 0; } else { ele = _getEleArr(priv, iter->node->posElement); iter->iElement = iter->node->posElement; iter->element = ele->ele; iter->nStoredNodes = ele->nStoredNodes; } } /** * visu_node_array_iterNextVisible: * @array: a #VisuNodeArray object ; * @iter: a #VisuNodeArrayIter object. * * Go to the next rendered node (changing element if required). */ void visu_node_array_iterNextVisible(VisuNodeArray *array, VisuNodeArrayIter *iter) { g_return_if_fail(VISU_IS_NODE_ARRAY(array) && iter && array == iter->array); /* Get the next node, and test if it is rendered. */ visu_node_array_iterNext(array, iter); if (!iter->node || (visu_element_getRendered(iter->element) && iter->node->rendered)) return; /* From the current node, we go next to find one that is rendred. */ for (; iter->element; visu_node_array_iterNextElement(array, iter, FALSE)) if (visu_element_getRendered(iter->element)) for (; iter->node; visu_node_array_iterNextNode(array, iter)) if (iter->node->rendered) return; } /** * visu_node_array_iterNextNode: * @array: a #VisuNodeArray object ; * @iter: a #VisuNodeArrayIter object. * * Modify node internal pointer to the next node, or NULL if * none remains. Contrary to visu_node_array_iterNext() it does not go to the * next element if one exists. */ void visu_node_array_iterNextNode(VisuNodeArray *array, VisuNodeArrayIter *iter) { EleArr *ele; VisuNodeArrayPrivate *priv = visu_node_array_get_instance_private(array); g_return_if_fail(priv && iter && array == iter->array); g_return_if_fail(iter->init && iter->node); ele = _getEleArr(priv, iter->node->posElement); if (iter->node->posNode + 1 < ele->nStoredNodes) iter->node = iter->node + 1; else iter->node = (VisuNode*)0; } /** * visu_node_array_iterNextNodeOriginal: * @array: a #VisuNodeArray object ; * @iter: a #VisuNodeArrayIter object. * * Modify node internal pointer to the next original node, or NULL if * none remains. Contrary to visu_node_array_iterNext() it does not go to the * next element if one exists. * * Since: 3.6 */ void visu_node_array_iterNextNodeOriginal(VisuNodeArray *array, VisuNodeArrayIter *iter) { EleArr *ele; VisuNodeArrayPrivate *priv = visu_node_array_get_instance_private(array); g_return_if_fail(priv && iter && array == iter->array); g_return_if_fail(iter->init && iter->node); do { ele = _getEleArr(priv, iter->node->posElement); if (iter->node->posNode + 1 < ele->nStoredNodes) iter->node = iter->node + 1; else iter->node = (VisuNode*)0; } while (iter->node && visu_node_array_getOriginal(array, iter->node->number) >= 0); } /** * visu_node_array_iterNextNodeNumber: * @array: a #VisuNodeArray object ; * @iter: a #VisuNodeArrayIter object. * * Modify node internal pointer to the next node, increasing the id of * the current node. The element internal pointer is also updated * accordingly. If no more nodes exist after the given one, node and * element internal pointers are set to NULL. */ void visu_node_array_iterNextNodeNumber(VisuNodeArray *array, VisuNodeArrayIter *iter) { guint i; EleArr *ele; VisuNodeArrayPrivate *priv = visu_node_array_get_instance_private(array); g_return_if_fail(priv && iter && array == iter->array); g_return_if_fail(iter->init && iter->node); for (i = iter->node->number + 1; !(iter->node = visu_node_array_getFromId(VISU_NODE_ARRAY(array), i)) && (i < priv->nodeTable.idCounter) ; i++); if (iter->node) { ele = _getEleArr(priv, iter->node->posElement); iter->iElement = iter->node->posElement; iter->element = ele->ele; iter->nStoredNodes = ele->nStoredNodes; } else { iter->element = (VisuElement*)0; iter->nStoredNodes = 0; } } /** * visu_node_array_iterNextElement: * @array: a #VisuNodeArray object ; * @iter: a #VisuNodeArrayIter object ; * @allowEmpty: a boolean. * * Modify element internal pointer to the next element and set node * to the first one, or NULL if none remains. If @allowEmpty is TRUE, * this iterator may return an element with no nodes, otherwise, it * skips elements with no nodes. */ void visu_node_array_iterNextElement(VisuNodeArray *array, VisuNodeArrayIter *iter, gboolean allowEmpty) { EleArr *ele; VisuNodeArrayPrivate *priv = visu_node_array_get_instance_private(array); g_return_if_fail(priv && iter && array == iter->array); g_return_if_fail(iter->init && iter->iElement < priv->elements->len); do iter->iElement += 1; while(iter->iElement < priv->elements->len && (!allowEmpty && _getEleArr(priv, iter->iElement)->nStoredNodes == 0)); if (iter->iElement == priv->elements->len) { iter->iElement = -1; iter->node = (VisuNode*)0; iter->element = (VisuElement*)0; iter->nStoredNodes = 0; } else { ele = _getEleArr(priv, iter->iElement); iter->node = ele->nodes; iter->element = ele->ele; iter->nStoredNodes = ele->nStoredNodes; } } /*************************************/ /* Additionnal routines for bindings */ /*************************************/ /** * visu_node_array_iter_next: * @iter: a #VisuNodeArrayIter object. * * Run the iterator to go to next item. * * Since: 3.6 * * Returns: TRUE if any item is found, FALSE otherwise. */ gboolean visu_node_array_iter_next(VisuNodeArrayIter *iter) { if (!iter->init) switch (iter->type) { case ITER_NODES_BY_TYPE: case ITER_ELEMENTS: visu_node_array_iterStart(iter->array, iter); break; case ITER_NODES_BY_NUMBER: case ITER_NODES_ORIGINAL: visu_node_array_iterStartNumber(iter->array, iter); break; case ITER_NODES_VISIBLE: visu_node_array_iterStartVisible(iter->array, iter); break; case ITER_NODES_FOR_ELEMENT: visu_node_array_iterRestartNode(iter->array, iter); break; case ITER_NODES_FROM_LIST: case ITER_NODES_FROM_ARRAY: g_warning("nodes from list or array not handled."); break; } else switch (iter->type) { case ITER_NODES_BY_TYPE: visu_node_array_iterNext(iter->array, iter); break; case ITER_NODES_BY_NUMBER: visu_node_array_iterNextNodeNumber(iter->array, iter); break; case ITER_NODES_VISIBLE: visu_node_array_iterNextVisible(iter->array, iter); break; case ITER_NODES_ORIGINAL: visu_node_array_iterNextNodeOriginal(iter->array, iter); break; case ITER_NODES_FOR_ELEMENT: visu_node_array_iterNextNode(iter->array, iter); break; case ITER_NODES_FROM_LIST: visu_node_array_iterNextList(iter->array, iter); break; case ITER_NODES_FROM_ARRAY: visu_node_array_iterNextArray(iter->array, iter); break; case ITER_ELEMENTS: visu_node_array_iterNextElement(iter->array, iter, FALSE); break; } if (iter->node) return TRUE; else return FALSE; } /** * visu_node_array_iter_next2: * @iter1: a #VisuNodeArrayIter object. * @iter2: a #VisuNodeArrayIter object. * * Iterator to run on a pair of different nodes. * * Returns: TRUE if any item is found, FALSE otherwise. * * Since: 3.6 */ gboolean visu_node_array_iter_next2(VisuNodeArrayIter *iter1, VisuNodeArrayIter *iter2) { if (!iter1->init) { visu_node_array_iterStart(iter1->array, iter1); visu_node_array_iterStart(iter1->array, iter2); } else { if (!iter1->node) return FALSE; /* DBG_fprintf(stderr, "go next %p-%p ->", (gpointer)iter1->node, (gpointer)iter2->node); */ visu_node_array_iterNext(iter1->array, iter2); if (!iter2->node || iter2->node->posElement > iter1->node->posElement || (iter2->node->posElement == iter1->node->posElement && iter2->node->posNode >= iter1->node->posNode)) { visu_node_array_iterNext(iter1->array, iter1); if (iter1->node) visu_node_array_iterStart(iter1->array, iter2); else iter2->node = (VisuNode*)0; } /* DBG_fprintf(stderr, " %p-%p\n", (gpointer)iter1->node, (gpointer)iter2->node); */ } if (!iter1->node && !iter2->node) return FALSE; else return TRUE; } v_sim-3.8.0/src/visu_nodes.h000066400000000000000000000344511370110300500157520ustar00rootroot00000000000000/* EXTRAITS DE LA LICENCE Copyright CEA, contributeurs : Luc BILLARD et Damien CALISTE, laboratoire L_Sim, (2001-2005) Adresse mèl : BILLARD, non joignable par mèl ; CALISTE, damien P caliste AT cea P fr. Ce logiciel est un programme informatique servant à visualiser des structures atomiques dans un rendu pseudo-3D. Ce logiciel est régi par la licence CeCILL soumise au droit français et respectant les principes de diffusion des logiciels libres. Vous pouvez utiliser, modifier et/ou redistribuer ce programme sous les conditions de la licence CeCILL telle que diffusée par le CEA, le CNRS et l'INRIA sur le site "http://www.cecill.info". Le fait que vous puissiez accéder à cet en-tête signifie que vous avez pris connaissance de la licence CeCILL, et que vous en avez accepté les termes (cf. le fichier Documentation/licence.fr.txt fourni avec ce logiciel). */ /* LICENCE SUM UP Copyright CEA, contributors : Luc BILLARD et Damien CALISTE, laboratoire L_Sim, (2001-2005) E-mail address: BILLARD, not reachable any more ; CALISTE, damien P caliste AT cea P fr. This software is a computer program whose purpose is to visualize atomic configurations in 3D. This software is governed by the CeCILL license under French law and abiding by the rules of distribution of free software. You can use, modify and/ or redistribute the software under the terms of the CeCILL license as circulated by CEA, CNRS and INRIA at the following URL "http://www.cecill.info". The fact that you are presently reading this means that you have had knowledge of the CeCILL license and that you accept its terms. You can find a copy of this licence shipped with this software at Documentation/licence.en.txt. */ #ifndef VISU_NODES_H #define VISU_NODES_H #include #include #include "visu_elements.h" #include "iface_maskable.h" G_BEGIN_DECLS typedef struct _VisuNode VisuNode; struct _VisuNode { /* coordinates of the node in cartesian coordinates. */ float xyz[3]; /* translation */ float translation[3]; /* Number of this element in the input file. */ guint number; /* Position in the #VisuData structure. */ guint posElement, posNode; /* A boolean to specify if this node is rendered or not. */ gboolean rendered; }; /** * VisuNodeProperty: * * This structure defines a storage for one property for each node of a given * #VisuNodeArray. Use visu_node_array_property_newPointer() or * visu_node_array_property_newInteger() to create one property. */ typedef struct _VisuNodeProperty VisuNodeProperty; GType visu_node_get_type(void); #define VISU_TYPE_NODE (visu_node_get_type()) void visu_node_newValues(VisuNode *node, float xyz[3]); gboolean visu_node_setVisibility(VisuNode* node, gboolean visibility); gboolean visu_node_getVisibility(VisuNode* node); gboolean visu_node_setCoordinates(VisuNode* node, float xyz[3]); /** * VISU_TYPE_NODE_ARRAY: * * return the type of #VisuNodeArray. */ #define VISU_TYPE_NODE_ARRAY (visu_node_array_get_type ()) G_DECLARE_DERIVABLE_TYPE(VisuNodeArray, visu_node_array, VISU, NODE_ARRAY, VisuObject) VISU_DECLARE_CONST(VisuNodeArray, visu_node_array, VISU, NODE_ARRAY) /** * VisuNodeArrayElementPropertyInit: * @element: a #VisuElement object ; * @value: a #GValue. * * Prototype of routine used to initialise an element property. * * Since: 3.7 */ typedef void (*VisuNodeArrayElementPropertyInit)(VisuElement *element, GValue *value); /** * VisuNodeArrayClass: * @parent: private. * * Class structure of #VisuNodeArray objects. */ struct _VisuNodeArrayClass { VisuObjectClass parent; }; void visu_node_array_allocate(VisuNodeArray *array, GArray *elements, GArray *nNodes); void visu_node_array_allocateByNames(VisuNodeArray *array, GArray *nNodesPerElement, GArray *elementNames); void visu_node_array_freeNodes(VisuNodeArray *nodeArray); void visu_node_array_allocateNodesForElement(VisuNodeArray *array, guint eleId, guint nNodes); void visu_node_array_startAdding(VisuNodeArray *array); void visu_node_array_completeAdding(VisuNodeArray *array); void visu_node_array_startMoving(VisuNodeArray *array); void visu_node_array_completeMoving(VisuNodeArray *array); void visu_node_array_removeNodes(VisuNodeArray *nodeArray, GArray *nodeNumbers); void visu_node_array_removeNodesOfElement(VisuNodeArray *nodeArray, VisuElement *element); gboolean visu_node_array_removeAllDuplicateNodes(VisuNodeArray *nodeArray); gint visu_node_array_getOriginal(VisuNodeArray *nodeArray, guint nodeId); gboolean visu_node_array_setOriginal(VisuNodeArray *nodeArray, guint nodeId); gboolean visu_node_array_compareElements(VisuNodeArray *data1, VisuNodeArray *data2); VisuElement* visu_node_array_getElement(const VisuNodeArray *data, const VisuNode *node); VisuNode* visu_node_array_setElement(VisuNodeArray *data, VisuNode *node, const VisuElement *element); gboolean visu_node_array_containsElement(const VisuNodeArray *array, const VisuElement *element); gint visu_node_array_getElementId(const VisuNodeArray *array, const VisuElement *element); guint visu_node_array_getNNodes(const VisuNodeArray *array); guint visu_node_array_getNOriginalNodes(const VisuNodeArray *array); guint visu_node_array_getNElements(const VisuNodeArray *array, gboolean physical); GArray* visu_node_array_setElementProperty(VisuNodeArray *data, const gchar *name, VisuNodeArrayElementPropertyInit init); GArray* visu_node_array_getElementProperty(VisuNodeArray *data, const gchar *name); VisuNode* visu_node_array_getNewNode(VisuNodeArray *nodeArray, const VisuElement *element); VisuNode* visu_node_array_getNewNodeForId(VisuNodeArray *nodeArray, guint iEle); gboolean visu_node_array_switchNumber(VisuNodeArray *nodeArray, guint from, guint to); VisuNode* visu_node_array_copyNode(VisuNodeArray *nodeArray, VisuNode *node); VisuNode* visu_node_array_getFromId(VisuNodeArray *array, guint number); gboolean visu_node_array_setNodeVisibility(VisuNodeArray *nodeArray, guint id, gboolean status); void visu_node_array_shiftNode(VisuNodeArray *array, guint id, const gfloat delta[3]); void visu_node_array_shiftNodes(VisuNodeArray *array, const GArray *ids, const float delta[3]); void visu_node_array_moveNode(VisuNodeArray *array, guint id, const float at[3]); void visu_node_array_moveNodes(VisuNodeArray *array, const GArray *ids, const GArray *xyz); void visu_node_array_rotateNodes(VisuNodeArray *array, const GArray *ids, const float axis[3], const float center[3], float angle); GArray* visu_node_array_join(VisuNodeArray *array, const VisuNodeArray *frag, const gfloat at[3]); /*************************/ /* The property methods. */ /*************************/ VisuNodeProperty* visu_node_array_property_newPointer(VisuNodeArray* nodeArray, const char* key, GFunc freeFunc, GCopyFunc newAndCopyFunc, gpointer user_data); VisuNodeProperty* visu_node_array_property_newFloatArray(VisuNodeArray* nodeArray, const char* key, guint len); VisuNodeProperty* visu_node_array_property_newInteger(VisuNodeArray* nodeArray, const char* key); void visu_node_array_freeProperty(VisuNodeArray* nodeArray, const char* key); void visu_node_array_traceProperty(VisuNodeArray *array, const gchar *id); VisuNodeProperty* visu_node_array_getProperty(VisuNodeArray* nodeArray, const char* key); /** * visu_node_setpropertyValue: * @nodeArray: a #VisuNodeArray object ; * @node: a #VisuNode object ; * @key: a string ; * @value: A GValue pointer this the value to be stored. * * This method is used to store some values associated with * the given @node of the given @nodeArray. These values can be pointers to * anything allocated (will be free automatically when the property is deleted) or * they can be static values. This depends on the construction of the node property. * These values are described by the @key, and can be retrieved with the * visu_node_array_getPropertyValue() method. * * See visu_node_property_setValue() to directly set a value associated to a node. */ #define visu_node_setpropertyValue(nodeArray, node, key, value) \ visu_node_property_setValue(visu_node_array_getProperty(nodeArray, key), node, value) void visu_node_property_setValue(VisuNodeProperty* nodeProp, const VisuNode* node, const GValue *value); /** * visu_node_array_getPropertyValue: * @nodeArray: a #VisuNodeArray object ; * @node: a #VisuNode object ; * @key: a string ; * @value: an initialise GValue location. * * This method is used to retrieve some data associated to * the specified @node, stored in the given @data. These return data * should not be freed after used. The read value is stored in the given * GValue pointer. This GValue must be of the right type, depending on the * creation of the #VisuNodeProperty. * * Returns: some data associated to the key, stored the given GValue location. */ #define visu_node_array_getPropertyValue(nodeArray, node, key, value) \ visu_node_property_getValue(visu_node_array_getProperty(nodeArray, key), node, value) GValue* visu_node_property_getValue(const VisuNodeProperty* nodeProp, const VisuNode* node, GValue *value); VisuNodeArray* visu_node_property_getArray(const VisuNodeProperty* nodeProp); void visu_node_property_reset(VisuNodeProperty* prop); /* Iterators. */ /** * VisuNodeArrayIterType: * @ITER_NODES_BY_TYPE: run on nodes, as V_Sim internal storage, * fastest. * @ITER_NODES_BY_NUMBER: run on nodes as entered in the input file. * @ITER_NODES_FROM_LIST: run on nodes as given in a #GList. * @ITER_NODES_FROM_ARRAY: run on nodes as given in a #GArray. * @ITER_NODES_VISIBLE: run on visible nodes only (internal sort). * @ITER_NODES_ORIGINAL: run on original nodes only (internal sort). * @ITER_NODES_FOR_ELEMENT: run on all nodes of a specific element. * @ITER_ELEMENTS: run on elements only. * * The kind of iterator to be used on #VisuData objects. * * Since: 3.6 */ typedef enum { ITER_NODES_BY_TYPE, ITER_NODES_BY_NUMBER, ITER_NODES_FROM_LIST, ITER_NODES_FROM_ARRAY, ITER_NODES_VISIBLE, ITER_NODES_ORIGINAL, ITER_NODES_FOR_ELEMENT, ITER_ELEMENTS } VisuNodeArrayIterType; /** * VisuNodeArrayIter: * @array: a pointer the iterator is associated to ; * @idMax: current higher id used to identified nodes. * @nAllStoredNodes: the total number of stored nodes for the * associated #VisuData ; * @nElements: the number of #VisuElement for the associated #VisuData ; * @nStoredNodes: the number of stored nodes for the current @element ; * @iElement: the index corresponding to @element (or -1 if no set); * @node: a pointer on a current node ; * @element: a pointer on a current element. * @type: the kind of iterator, see #VisuNodeArrayIterType. * @init: an internal flag. * @itLst: an internal list iterator. * @arr: an iternal list of nodes to iterate on. * @itArr: an internal iterator on array. * * This structure is an iterator over the nodes of a #VisuData object. * Create it with visu_node_array_iter_new(). Then the numbers are allocated and * correspond to the value of the #VisuData object. Use visu_node_array_iterStart() * to initialise the iterator for a run over the nodes, visu_node_array_iterNext() * to associate @node and @element to the next node, or NULL if there is no * more node to run over. */ typedef struct _VisuNodeArrayIter VisuNodeArrayIter; struct _VisuNodeArrayIter { VisuNodeArray *array; guint idMax; guint nAllStoredNodes; guint nElements; guint iElement; guint nStoredNodes; VisuNode *node; VisuElement *element; VisuNodeArrayIterType type; gboolean init; GList *itLst; GArray *arr; guint itArr; }; /** * VisuNodeArrayIterFunc: * @array: (transfer full): the #VisuNodeArray object the function deals with. * @iter: the #VisuNodeArrayIter object the function works on. * @data: (closure): some user data. * * Prototype of function that evaluates a boolean condition on a given * node in a node iteration. * * Since: 3.8 */ typedef gboolean (*VisuNodeArrayIterFunc)(VisuNodeArray *array, const VisuNodeArrayIter *iter, gpointer data); void visu_node_array_iter_new(VisuNodeArray *array, VisuNodeArrayIter *iter); void visu_node_array_iterStart(VisuNodeArray *array, VisuNodeArrayIter *iter); void visu_node_array_iterStartVisible(VisuNodeArray *array, VisuNodeArrayIter *iter); void visu_node_array_iterStartNumber(VisuNodeArray *array, VisuNodeArrayIter *iter); void visu_node_array_iterStartList(VisuNodeArray *array, VisuNodeArrayIter *iter, GList *lst); void visu_node_array_iterStartArray(VisuNodeArray *array, VisuNodeArrayIter *iter, GArray *arr); void visu_node_array_iterRestartNode(VisuNodeArray *array, VisuNodeArrayIter *iter); void visu_node_array_iterWhere(VisuNodeArray *array, VisuNodeArrayIter *iter, VisuNodeArrayIterFunc where, gpointer data); void visu_node_array_iterNext(VisuNodeArray *array, VisuNodeArrayIter *iter); void visu_node_array_iterNextNode(VisuNodeArray *array, VisuNodeArrayIter *iter); void visu_node_array_iterNextNodeNumber(VisuNodeArray *array, VisuNodeArrayIter *iter); void visu_node_array_iterNextNodeOriginal(VisuNodeArray *array, VisuNodeArrayIter *iter); void visu_node_array_iterNextList(VisuNodeArray *array, VisuNodeArrayIter *iter); void visu_node_array_iterNextArray(VisuNodeArray *array, VisuNodeArrayIter *iter); void visu_node_array_iterNextElement(VisuNodeArray *array, VisuNodeArrayIter *iter, gboolean allowEmpty); void visu_node_array_iterNextVisible(VisuNodeArray *array, VisuNodeArrayIter *iter); gboolean visu_node_array_iter_next(VisuNodeArrayIter *iter); gboolean visu_node_array_iter_next2(VisuNodeArrayIter *iter1, VisuNodeArrayIter *iter2); G_END_DECLS #endif v_sim-3.8.0/src/visu_pairs.c000066400000000000000000000553601370110300500157550ustar00rootroot00000000000000/* EXTRAITS DE LA LICENCE Copyright CEA, contributeurs : Luc BILLARD et Damien CALISTE, laboratoire L_Sim, (2001-2005) Adresse mèl : BILLARD, non joignable par mèl ; CALISTE, damien P caliste AT cea P fr. Ce logiciel est un programme informatique servant à visualiser des structures atomiques dans un rendu pseudo-3D. Ce logiciel est régi par la licence CeCILL soumise au droit français et respectant les principes de diffusion des logiciels libres. Vous pouvez utiliser, modifier et/ou redistribuer ce programme sous les conditions de la licence CeCILL telle que diffusée par le CEA, le CNRS et l'INRIA sur le site "http://www.cecill.info". Le fait que vous puissiez accéder à cet en-tête signifie que vous avez pris connaissance de la licence CeCILL, et que vous en avez accepté les termes (cf. le fichier Documentation/licence.fr.txt fourni avec ce logiciel). */ /* LICENCE SUM UP Copyright CEA, contributors : Luc BILLARD et Damien CALISTE, laboratoire L_Sim, (2001-2005) E-mail address: BILLARD, not reachable any more ; CALISTE, damien P caliste AT cea P fr. This software is a computer program whose purpose is to visualize atomic configurations in 3D. This software is governed by the CeCILL license under French law and abiding by the rules of distribution of free software. You can use, modify and/ or redistribute the software under the terms of the CeCILL license as circulated by CEA, CNRS and INRIA at the following URL "http://www.cecill.info". The fact that you are presently reading this means that you have had knowledge of the CeCILL license and that you accept its terms. You can find a copy of this licence shipped with this software at Documentation/licence.en.txt. */ #include "visu_pairs.h" #include #include #include "visu_nodes.h" /** * SECTION:visu_pairs * @short_description: V_Sim can draw link between nodes. This part * defines a pair object and interface to draw pairs. * * The visu_pairs.c defines only general methods to draw * pairs. It introduces a new object called #VisuPairLink. This stores * some characteristics on links between two #VisuElement. The main * characteristic is that pairs are drawn only if the length between * two nodes is in a specific range. Use visu_pair_link_setDistance() and * visu_pair_link_getDistance() to tune this range. * * This file does not draw any pairs. But it gives some * interface to create rendering capabilities. To create a new pair * rendering module, called #VisuGlExtPairs, use * visu_gl_ext_pairs_new(). Basically, a #VisuGlExtPairs is characterized * by it drawing method. But it can have other methods that are called * in different cases. See main() and * startStop() prototypes to have more informations. */ /** * VisuPairClass: * @parent: the parent class. * * Class of #VisuPair objects. */ /** * VisuPair: * * An opaque structure to define links (i.e. several #VisuPairLink) * between elements. */ /* This structure is made to store pairs information between two elements. */ struct _VisuPairPrivate { gboolean dispose_has_run; VisuElement *ele1; VisuElement *ele2; /* This is a set of link (VisuPairLink). */ GArray *links; }; enum { PROP_0, ELE1_PROP, ELE2_PROP, LINKS_PROP, N_PROP }; static GParamSpec *_properties[N_PROP]; /* Local methods. */ static void visu_pair_dispose(GObject* obj); static void visu_pair_finalize(GObject* obj); static void visu_pair_get_property(GObject* obj, guint property_id, GValue *value, GParamSpec *pspec); static void visu_pair_set_property(GObject* obj, guint property_id, const GValue *value, GParamSpec *pspec); G_DEFINE_TYPE_WITH_CODE(VisuPair, visu_pair, VISU_TYPE_OBJECT, G_ADD_PRIVATE(VisuPair)) /********************/ /* Visu pair stuff. */ /********************/ static void visu_pair_class_init(VisuPairClass *klass) { DBG_fprintf(stderr, "Visu Pair: creating the class of the object.\n"); DBG_fprintf(stderr, " - adding new signals ;\n"); /* Connect the overloading methods. */ G_OBJECT_CLASS(klass)->dispose = visu_pair_dispose; G_OBJECT_CLASS(klass)->finalize = visu_pair_finalize; G_OBJECT_CLASS(klass)->set_property = visu_pair_set_property; G_OBJECT_CLASS(klass)->get_property = visu_pair_get_property; /** * VisuPair::first-element: * * Store the link first element. * * Since: 3.8 */ _properties[ELE1_PROP] = g_param_spec_object("first-element", "First element", "first element", VISU_TYPE_ELEMENT, G_PARAM_READWRITE | G_PARAM_CONSTRUCT_ONLY); g_object_class_install_property(G_OBJECT_CLASS(klass), ELE1_PROP, _properties[ELE1_PROP]); /** * VisuPair::second-element: * * Store the link second element. * * Since: 3.8 */ _properties[ELE2_PROP] = g_param_spec_object("second-element", "Second element", "second element", VISU_TYPE_ELEMENT, G_PARAM_READWRITE | G_PARAM_CONSTRUCT_ONLY); g_object_class_install_property(G_OBJECT_CLASS(klass), ELE2_PROP, _properties[ELE2_PROP]); /** * VisuPair::links: * * Store the set of links of this pair. * * Since: 3.8 */ _properties[LINKS_PROP] = g_param_spec_boxed("links", "Links", "array of links", G_TYPE_ARRAY, G_PARAM_READABLE); g_object_class_install_property(G_OBJECT_CLASS(klass), LINKS_PROP, _properties[LINKS_PROP]); } static void visu_pair_init(VisuPair *pair) { DBG_fprintf(stderr, "Visu Pair: initializing a new object (%p).\n", (gpointer)pair); pair->priv = visu_pair_get_instance_private(pair); pair->priv->dispose_has_run = FALSE; pair->priv->ele1 = (VisuElement*)0; pair->priv->ele2 = (VisuElement*)0; pair->priv->links = g_array_new(FALSE, FALSE, sizeof(VisuPairLink*)); } static void visu_pair_get_property(GObject* obj, guint property_id, GValue *value, GParamSpec *pspec) { VisuPair *self = VISU_PAIR(obj); DBG_fprintf(stderr, "Visu Pair: get property '%s' -> ", g_param_spec_get_name(pspec)); switch (property_id) { case ELE1_PROP: g_value_set_object(value, self->priv->ele1); DBG_fprintf(stderr, "%p.\n", (gpointer)self->priv->ele1); break; case ELE2_PROP: g_value_set_object(value, self->priv->ele2); DBG_fprintf(stderr, "%p.\n", (gpointer)self->priv->ele2); break; case LINKS_PROP: g_value_set_boxed(value, self->priv->links); DBG_fprintf(stderr, "%p.\n", (gpointer)self->priv->links); break; default: /* We don't have any other property... */ G_OBJECT_WARN_INVALID_PROPERTY_ID(obj, property_id, pspec); break; } } static void visu_pair_set_property(GObject* obj, guint property_id, const GValue *value, GParamSpec *pspec) { VisuPair *self = VISU_PAIR(obj); float mM[2] = {0.f, 0.f}; VisuPairLink *link; DBG_fprintf(stderr, "Visu Pair: set property '%s' -> ", g_param_spec_get_name(pspec)); switch (property_id) { case ELE1_PROP: DBG_fprintf(stderr, "%p.\n", (gpointer)g_value_get_object(value)); self->priv->ele1 = g_value_dup_object(value); break; case ELE2_PROP: DBG_fprintf(stderr, "%p.\n", (gpointer)g_value_get_object(value)); self->priv->ele2 = g_value_dup_object(value); break; default: /* We don't have any other property... */ G_OBJECT_WARN_INVALID_PROPERTY_ID(obj, property_id, pspec); break; } if (self->priv->ele1 && self->priv->ele2 && !self->priv->links->len) { link = visu_pair_link_new(self->priv->ele1, self->priv->ele2, mM); g_array_append_val(self->priv->links, link); } } static void visu_pair_dispose(GObject* obj) { VisuPair *data; guint i; data = VISU_PAIR(obj); DBG_fprintf(stderr, "Visu Pair: dispose object %p (%s - %s).\n", (gpointer)obj, data->priv->ele1->name, data->priv->ele2->name); if (data->priv->dispose_has_run) return; data->priv->dispose_has_run = TRUE; g_object_unref(data->priv->ele1); g_object_unref(data->priv->ele2); for (i = 0; i < data->priv->links->len; i++) g_object_unref(g_array_index(data->priv->links, GObject*, i)); /* Chain up to the parent class */ G_OBJECT_CLASS(visu_pair_parent_class)->dispose(obj); } static void visu_pair_finalize(GObject* obj) { VisuPair *data; g_return_if_fail(obj); DBG_fprintf(stderr, "Visu Pair: finalize object %p.\n", (gpointer)obj); data = VISU_PAIR(obj); g_array_free(data->priv->links, TRUE); /* Chain up to the parent class */ DBG_fprintf(stderr, "Visu Pair: chain to parent.\n"); G_OBJECT_CLASS(visu_pair_parent_class)->finalize(obj); DBG_fprintf(stderr, "Visu Pair: freeing ... OK.\n"); } /** * visu_pair_new: * @ele1: a #VisuElement object. * @ele2: a #VisuElement object. * * Creates a #VisuPair between @ele1 and @ele2. * * Since: 3.8 * * Returns: (transfer full): a newly created object. **/ VisuPair* visu_pair_new(VisuElement *ele1, VisuElement *ele2) { return VISU_PAIR(g_object_new(VISU_TYPE_PAIR, "first-element", ele1, "second-element", ele2, NULL)); } /** * visu_pair_getElements: * @pair: a #VisuPair object. * @ele1: (out) (allow-none) (transfer none): a location to store a * #VisuElement object pointer. * @ele2: (out) (allow-none) (transfer none): a location to store a * #VisuElement object pointer. * * Retrieve the #VisuElement constituting the pair. * * Since: 3.7 **/ void visu_pair_getElements(const VisuPair *pair, VisuElement **ele1, VisuElement **ele2) { g_return_if_fail(VISU_IS_PAIR(pair)); if (ele1) *ele1 = pair->priv->ele1; if (ele2) *ele2 = pair->priv->ele2; } /** * visu_pair_foreach: * @pair: a #VisuPair object. * @whatToDo: (scope call) (closure user_data): method to apply. * @user_data: (closure): some user data. * * Apply @whatToDo on every #VisuPairLink of @pair. * * Since: 3.8 **/ void visu_pair_foreach(VisuPair *pair, VisuPairForeachFunc whatToDo, gpointer user_data) { guint i; g_return_if_fail(VISU_IS_PAIR(pair)); for (i = 0; i < pair->priv->links->len; i++) whatToDo(pair, g_array_index(pair->priv->links, VisuPairLink*, i), user_data); } /** * visu_pair_getLinks: * @pair: a #VisuPair object. * * There can be one or several links between elements, retrieve them * with this routine. * * Returns: (element-type VisuPairLink*) (transfer container): a list of * #VisuPairLink. The list content is owned by V_Sim but the list * should be freed with g_list_free() after use. */ GList* visu_pair_getLinks(VisuPair *pair) { GList *lst; guint i; g_return_val_if_fail(VISU_IS_PAIR(pair), (GList*)0); lst = (GList*)0; for (i = 0; i < pair->priv->links->len; i++) lst = g_list_append(lst, g_array_index(pair->priv->links, gpointer, i)); return lst; } /** * visu_pair_getNthLink: * @pair: a #VisuPair object. * @pos: the position in the list of links. * * A link can also be retrieved by its position. * * Returns: (transfer none): the #VisuPairLink object associated to the given two * elements and distances. If none exists NULL is returned. */ VisuPairLink* visu_pair_getNthLink(VisuPair *pair, guint pos) { g_return_val_if_fail(VISU_IS_PAIR(pair), (VisuPairLink*)0); return (pos < pair->priv->links->len) ? g_array_index(pair->priv->links, VisuPairLink*, pos) : (VisuPairLink*)0; } /** * visu_pair_addLink: * @pair: a #VisuPair object. * @minMax: (array fixed-size=2): the two min and max distances. * * A link between two elements is characterized by its boundary distances. * * Returns: (transfer none): the #VisuPairLink object associated to the given two * elements and distances. If none exists it is created. The * returned value should not be freed. */ VisuPairLink* visu_pair_addLink(VisuPair *pair, const float minMax[2]) { guint i; VisuPairLink *data; const gfloat zeros[2] = {0.f, 0.f}; g_return_val_if_fail(VISU_IS_PAIR(pair), (VisuPairLink*)0); DBG_fprintf(stderr, "Visu Pair: look for link %g - %g.\n", minMax[0], minMax[1]); for (i = 0; i < pair->priv->links->len; i++) if (visu_pair_link_match(g_array_index(pair->priv->links, VisuPairLink*, i), minMax)) return g_array_index(pair->priv->links, VisuPairLink*, i); if (pair->priv->links->len == 1 && visu_pair_link_match(g_array_index(pair->priv->links, VisuPairLink*, 0), zeros)) { data = g_array_index(pair->priv->links, VisuPairLink*, 0); visu_pair_link_setDistance(data, minMax[0], VISU_DISTANCE_MIN); visu_pair_link_setDistance(data, minMax[1], VISU_DISTANCE_MAX); DBG_fprintf(stderr, "Visu Pair: updating 0 - 0.\n"); } else { data = visu_pair_link_new(pair->priv->ele1, pair->priv->ele2, minMax); g_array_append_val(pair->priv->links, data); g_object_notify_by_pspec(G_OBJECT(pair), _properties[LINKS_PROP]); DBG_fprintf(stderr, "Visu Pair: create a new link.\n"); } return data; } /** * visu_pair_removeLink: * @pair: a #VisuPair object. * @data: a link object. * * Delete the given link. * * Returns: TRUE if the link exists and has been successfully removed. */ gboolean visu_pair_removeLink(VisuPair *pair, VisuPairLink *data) { guint i; gfloat zeros[2] = {0.f, 0.f}; g_return_val_if_fail(VISU_IS_PAIR(pair), FALSE); for (i = 0; i < pair->priv->links->len; i++) if (g_array_index(pair->priv->links, VisuPairLink*, i) == data) { g_array_remove_index(pair->priv->links, i); g_object_unref(data); if (!pair->priv->links->len) visu_pair_addLink(pair, zeros); else g_object_notify_by_pspec(G_OBJECT(pair), _properties[LINKS_PROP]); return TRUE; } return FALSE; } /** * visu_pair_contains: * @pair: a #VisuPair object. * @link: a #VisuPairLink object. * * Tests if @link is contained in @pair. * * Since: 3.8 * * Returns: TRUE if @link is a member of @pair. **/ gboolean visu_pair_contains(const VisuPair *pair, const VisuPairLink *link) { guint i; g_return_val_if_fail(VISU_IS_PAIR(pair), FALSE); for (i = 0; i < pair->priv->links->len; i++) if (g_array_index(pair->priv->links, VisuPairLink*, i) == link) return TRUE; return FALSE; } /** * visu_pair_getBondDistance: * @pair: a #VisuPair object. * @dataObj: a #VisuData object. * @from: (out caller-allocates): a location for a float. * @to: (out caller-allocates): a location for a float. * * Compute the bond distribution for the given @pair and look for the * first peak and returns its span. When given, @from and @to contains * the lengths between which the bond for @pair is the most probable. * * Since: 3.8 * * Returns: TRUE if a significant bond length can be found. **/ gboolean visu_pair_getBondDistance(VisuPair *pair, VisuData *dataObj, gfloat *from, gfloat *to) { VisuPairDistribution *dd; guint sum, startStopId[2]; g_return_val_if_fail(VISU_IS_PAIR(pair), FALSE); dd = visu_pair_getDistanceDistribution(pair, dataObj, -1.f, -1.f, -1.f); g_return_val_if_fail(dd, FALSE); startStopId[0] = 0; startStopId[1] = dd->nValues - 1; if (!visu_pair_distribution_getNextPick(dd, startStopId, &sum, (guint*)0, (guint*)0)) return FALSE; if (from) *from = dd->initValue + startStopId[0] * dd->stepValue; if (to) *to = dd->initValue + startStopId[1] * dd->stepValue; return TRUE; } /****************************/ /* Pair distribution stuff. */ /****************************/ #define BONDHISTOGRAM_ID "bondDistribution_data" #define BONDHISTOGRAM_STEP 0.1f #define BONDHISTOGRAM_MIN 0.f #define BONDHISTOGRAM_MAX 10.f static void freeHistoData(gpointer data) { DBG_fprintf(stderr, "Visu Pair: free '%s' data.\n", BONDHISTOGRAM_ID); g_free(((VisuPairDistribution*)data)->histo); g_free(data); } /** * visu_pair_getDistanceDistribution: * @pair: a #VisuPair ; * @dataObj: a #VisuData ; * @step: a float for the distance mesh (negative value to use * built-in default) ; * @min: a float for the minimum scanning value (negative value to use * built-in default). * @max: a float for the maximum scanning value (negative value to use * built-in default). * * This will compute the distance distribution of nodes for the given * @pair. * * Returns: a structure defining the distance distribution. This * structure is private and should not be freed. */ VisuPairDistribution* visu_pair_getDistanceDistribution(VisuPair *pair, VisuData *dataObj, float step, float min, float max) { VisuPairDistribution *dd; guint i; VisuNodeArrayIter iter1, iter2; float d2, inv; float xyz1[3], xyz2[3]; #if DEBUG == 1 guint nRef; GTimer *timer; gulong fractionTimer; #endif g_return_val_if_fail(VISU_IS_PAIR(pair) && VISU_IS_DATA(dataObj), (VisuPairDistribution*)0); #if DEBUG == 1 timer = g_timer_new(); g_timer_start(timer); #endif /* We create the storage structure. */ dd = (VisuPairDistribution*)g_object_get_data(G_OBJECT(pair), BONDHISTOGRAM_ID); if (dd) g_free(dd->histo); else { dd = g_malloc(sizeof(VisuPairDistribution)); g_object_set_data_full(G_OBJECT(pair), BONDHISTOGRAM_ID, (gpointer)dd, freeHistoData); } visu_pair_getElements(pair, &dd->ele1, &dd->ele2); dd->nNodesEle1 = 0; dd->nNodesEle2 = 0; dd->stepValue = (step > 0.f)?step:BONDHISTOGRAM_STEP; dd->initValue = (min > 0.f)?min:BONDHISTOGRAM_MIN; dd->nValues = (int)((((max > 0.f)?max:BONDHISTOGRAM_MAX) - dd->initValue) / dd->stepValue) + 1; dd->histo = g_malloc0(sizeof(int) * dd->nValues); DBG_fprintf(stderr, "Visu Pair: compute distance distribution (%p %g %d).\n", (gpointer)dd, dd->stepValue, dd->nValues); /* We compute the distribution. */ visu_node_array_iter_new(VISU_NODE_ARRAY(dataObj), &iter1); inv = 1.f / dd->stepValue; visu_pair_getElements(pair, &iter1.element, NULL); for(visu_node_array_iterRestartNode(VISU_NODE_ARRAY(dataObj), &iter1); iter1.node; visu_node_array_iterNextNodeOriginal(VISU_NODE_ARRAY(dataObj), &iter1)) { if (!iter1.node->rendered) continue; dd->nNodesEle1 += 1; visu_data_getNodePosition(dataObj, iter1.node, xyz1); visu_node_array_iter_new(VISU_NODE_ARRAY(dataObj), &iter2); visu_pair_getElements(pair, NULL, &iter2.element); /* fprintf(stderr, "## %d\n", dd->histo[177]); */ for(visu_node_array_iterRestartNode(VISU_NODE_ARRAY(dataObj), &iter2); iter2.node; visu_node_array_iterNextNode(VISU_NODE_ARRAY(dataObj), &iter2)) { if (!iter2.node->rendered) continue; /* Don't count the inter element pairs two times. */ if (iter1.element == iter2.element && iter2.node == iter1.node) continue; visu_data_getNodePosition(dataObj, iter2.node, xyz2); d2 = (xyz1[0] - xyz2[0]) * (xyz1[0] - xyz2[0]) + (xyz1[1] - xyz2[1]) * (xyz1[1] - xyz2[1]) + (xyz1[2] - xyz2[2]) * (xyz1[2] - xyz2[2]); /* We put the distance into the histogram. */ dd->histo[MIN((guint)((sqrt(d2) - dd->initValue) * inv), dd->nValues - 1)] += 1; /* fprintf(stderr, "%d-%d %d\n", iter1.node->number, iter2.node->number, dd->histo[177]); */ } /* fprintf(stderr, "-> %d\n", dd->histo[177]); */ } for(visu_node_array_iterRestartNode(VISU_NODE_ARRAY(dataObj), &iter2); iter2.node; visu_node_array_iterNextNode(VISU_NODE_ARRAY(dataObj), &iter2)) if (iter2.node->rendered) dd->nNodesEle2 += 1; if (iter1.element == iter2.element) for (i = 0; i < dd->nValues; i++) dd->histo[i] /= 2; #if DEBUG == 1 g_timer_stop(timer); for (nRef = 0; nRef < dd->nValues; nRef++) fprintf(stderr, " | %03d -> %6.3f, %5d\n", nRef, dd->initValue + dd->stepValue * nRef, dd->histo[nRef]); fprintf(stderr, "Visu Pair: distances analysed in %g micro-s.\n", g_timer_elapsed(timer, &fractionTimer)/1e-6); g_timer_destroy(timer); #endif return dd; } /** * visu_pair_distribution_getNextPick: * @dd: a #VisuPairDistribution object. * @startStopId: two ids. * @integral: a location for a guint value, can be NULL. * @max: a location to store the value ; * @posMax: a location to store the position of the pick. * * Try to find the next pick in the distribution. A pick is a group of * consecutive non-null values, with a significant integral. On enter, * @startStopId contains the span to look into for the pick, and on * output, it contains the span of the pick itself. * * Since: 3.6 * * Returns: TRUE if a pick is found. */ gboolean visu_pair_distribution_getNextPick(VisuPairDistribution *dd, guint startStopId[2], guint *integral, guint *max, guint *posMax) { float min, start, stop; guint i, iStart, iStop, sum, _posMax, _max; g_return_val_if_fail(dd, FALSE); g_return_val_if_fail(startStopId[1] < dd->nValues, FALSE); iStart = startStopId[0]; iStop = startStopId[1]; _max = 0; _posMax = 0; min = 1.5f * MIN(dd->nNodesEle1, dd->nNodesEle2); DBG_fprintf(stderr, "Visu Pair: look for one pick in %d-%d.\n", startStopId[0], startStopId[1]); do { min *= 0.5f; start = -1.f; stop = -1.f; sum = 0; for (i = startStopId[0] ; i < startStopId[1]; i++) { if (start < 0.f && dd->histo[i] > 0) { start = dd->stepValue * i + dd->initValue; sum = dd->histo[i]; iStart = i; _max = dd->histo[i]; _posMax = i; } else if (start > 0.f) { if (dd->histo[i] == 0) { if (sum >= min) { stop = dd->stepValue * i + dd->initValue; iStop = i; break; } else start = -1.f; } else { sum += dd->histo[i]; if (dd->histo[i] > _max) { _max = dd->histo[i]; _posMax = i; } } } } DBG_fprintf(stderr, "Visu Pair: found one pick at %d-%d (%d).\n", iStart, iStop, sum); } while (start < 0.f && min > 0.1f * MIN(dd->nNodesEle1, dd->nNodesEle2)); DBG_fprintf(stderr, "Visu Pair: set start and stop at %f, %f (%f %d).\n", start, stop, min, sum); if (start <= 0.f || stop <= 0.f) return FALSE; startStopId[0] = iStart; startStopId[1] = iStop; if (integral) *integral = sum; if (max) *max = _max; if (posMax) *posMax = _posMax; return TRUE; } v_sim-3.8.0/src/visu_pairs.h000066400000000000000000000133371370110300500157600ustar00rootroot00000000000000/* EXTRAITS DE LA LICENCE Copyright CEA, contributeurs : Luc BILLARD et Damien CALISTE, laboratoire L_Sim, (2001-2005) Adresse mèl : BILLARD, non joignable par mèl ; CALISTE, damien P caliste AT cea P fr. Ce logiciel est un programme informatique servant à visualiser des structures atomiques dans un rendu pseudo-3D. Ce logiciel est régi par la licence CeCILL soumise au droit français et respectant les principes de diffusion des logiciels libres. Vous pouvez utiliser, modifier et/ou redistribuer ce programme sous les conditions de la licence CeCILL telle que diffusée par le CEA, le CNRS et l'INRIA sur le site "http://www.cecill.info". Le fait que vous puissiez accéder à cet en-tête signifie que vous avez pris connaissance de la licence CeCILL, et que vous en avez accepté les termes (cf. le fichier Documentation/licence.fr.txt fourni avec ce logiciel). */ /* LICENCE SUM UP Copyright CEA, contributors : Luc BILLARD et Damien CALISTE, laboratoire L_Sim, (2001-2005) E-mail address: BILLARD, not reachable any more ; CALISTE, damien P caliste AT cea P fr. This software is a computer program whose purpose is to visualize atomic configurations in 3D. This software is governed by the CeCILL license under French law and abiding by the rules of distribution of free software. You can use, modify and/ or redistribute the software under the terms of the CeCILL license as circulated by CEA, CNRS and INRIA at the following URL "http://www.cecill.info". The fact that you are presently reading this means that you have had knowledge of the CeCILL license and that you accept its terms. You can find a copy of this licence shipped with this software at Documentation/licence.en.txt. */ #ifndef VISU_PAIRS #define VISU_PAIRS #include #include "visu_data.h" #include "pairsModeling/link.h" G_BEGIN_DECLS /** * VISU_TYPE_PAIR: * * return the type of #VisuPair. */ #define VISU_TYPE_PAIR (visu_pair_get_type ()) /** * VISU_PAIR: * @obj: a #GObject to cast. * * Cast the given @obj into #VisuPair type. */ #define VISU_PAIR(obj) (G_TYPE_CHECK_INSTANCE_CAST(obj, VISU_TYPE_PAIR, VisuPair)) /** * VISU_PAIR_CLASS: * @klass: a #GObjectClass to cast. * * Cast the given @klass into #VisuPairClass. */ #define VISU_PAIR_CLASS(klass) (G_TYPE_CHECK_CLASS_CAST(klass, VISU_TYPE_PAIR, VisuPairClass)) /** * VISU_IS_PAIR: * @obj: a #GObject to test. * * Test if the given @ogj is of the type of #VisuPair object. */ #define VISU_IS_PAIR(obj) (G_TYPE_CHECK_INSTANCE_TYPE(obj, VISU_TYPE_PAIR)) /** * VISU_IS_PAIR_CLASS: * @klass: a #GObjectClass to test. * * Test if the given @klass is of the type of #VisuPairClass class. */ #define VISU_IS_PAIR_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE(klass, VISU_TYPE_PAIR)) /** * VISU_PAIR_GET_CLASS: * @obj: a #GObject to get the class of. * * It returns the class of the given @obj. */ #define VISU_PAIR_GET_CLASS(obj) (G_TYPE_INSTANCE_GET_CLASS(obj, VISU_TYPE_PAIR, VisuPairClass)) typedef struct _VisuPairClass VisuPairClass; typedef struct _VisuPair VisuPair; typedef struct _VisuPairPrivate VisuPairPrivate; /** * visu_pair_get_type: * * This method returns the type of #VisuPair, use VISU_TYPE_PAIR instead. * * Returns: the type of #VisuPair. */ GType visu_pair_get_type(void); /** * _VisuPair: * @parent: parent. * @priv: private data. * * This structure describes a pair. */ struct _VisuPair { VisuObject parent; VisuPairPrivate *priv; }; struct _VisuPairClass { VisuObjectClass parent; }; VisuPair* visu_pair_new(VisuElement *ele1, VisuElement *ele2); void visu_pair_getElements(const VisuPair *pair, VisuElement **ele1, VisuElement **ele2); VisuPairLink* visu_pair_addLink(VisuPair *pair, const float minMax[2]); gboolean visu_pair_removeLink(VisuPair *pair, VisuPairLink *data); GList* visu_pair_getLinks(VisuPair *pair); VisuPairLink* visu_pair_getNthLink(VisuPair *pair, guint pos); gboolean visu_pair_contains(const VisuPair *pair, const VisuPairLink *link); gboolean visu_pair_getBondDistance(VisuPair *pair, VisuData *dataObj, gfloat *from, gfloat *to); /** * VisuPairForeachFunc: * @pair: a #VisuPair object. * @data: a #VisuPairLink object ; * @user_data: some user defined data. * * Prototype of functions called with the foreach method apply to each * links in a pair. */ typedef void (*VisuPairForeachFunc)(VisuPair *pair, VisuPairLink *data, gpointer user_data); void visu_pair_foreach(VisuPair *pair, VisuPairForeachFunc whatToDo, gpointer user_data); /** * VisuPairDistribution: * @ele1: one #VisuElement. * @ele2: one #VisuElement. * @histo: an array containing the distribution ; * @nValues: the size of the array ; * @initValue: the initial distance value (usualy 0) ; * @stepValue: the step increase in distance at each value ; * @nNodesEle1: the number of nodes used during the computation ; * @nNodesEle2: idem for #VisuElement 2. * * This structure stores for a given pair, the distance distribution * on a given range [@initValue;@nValues * @stepValue[. */ typedef struct _VisuPairDistribution VisuPairDistribution; struct _VisuPairDistribution { VisuElement *ele1, *ele2; guint *histo; guint nValues; float initValue, stepValue; guint nNodesEle1, nNodesEle2; }; VisuPairDistribution* visu_pair_getDistanceDistribution(VisuPair *pair, VisuData *dataObj, float step, float min, float max); gboolean visu_pair_distribution_getNextPick(VisuPairDistribution *dd, guint startStopId[2], guint *integral, guint *max, guint *posMax); G_END_DECLS #endif v_sim-3.8.0/src/visu_pairset.c000066400000000000000000000501521370110300500163000ustar00rootroot00000000000000/* EXTRAITS DE LA LICENCE Copyright CEA, contributeurs : Damien CALISTE, laboratoire L_Sim, (2016) Adresse mèl : BILLARD, non joignable par mèl ; CALISTE, damien P caliste AT cea P fr. Ce logiciel est un programme informatique servant à visualiser des structures atomiques dans un rendu pseudo-3D. Ce logiciel est régi par la licence CeCILL soumise au droit français et respectant les principes de diffusion des logiciels libres. Vous pouvez utiliser, modifier et/ou redistribuer ce programme sous les conditions de la licence CeCILL telle que diffusée par le CEA, le CNRS et l'INRIA sur le site "http://www.cecill.info". Le fait que vous puissiez accéder à cet en-tête signifie que vous avez pris connaissance de la licence CeCILL, et que vous en avez accepté les termes (cf. le fichier Documentation/licence.fr.txt fourni avec ce logiciel). */ /* LICENCE SUM UP Copyright CEA, contributors : Damien CALISTE, laboratoire L_Sim, (2016) E-mail address: BILLARD, not reachable any more ; CALISTE, damien P caliste AT cea P fr. This software is a computer program whose purpose is to visualize atomic configurations in 3D. This software is governed by the CeCILL license under French law and abiding by the rules of distribution of free software. You can use, modify and/ or redistribute the software under the terms of the CeCILL license as circulated by CEA, CNRS and INRIA at the following URL "http://www.cecill.info". The fact that you are presently reading this means that you have had knowledge of the CeCILL license and that you accept its terms. You can find a copy of this licence shipped with this software at Documentation/licence.en.txt. */ #include "visu_pairset.h" #include /** * SECTION: visu_pairset * @short_description: a base class for all loadable representation of * #VisuData objects. * * This object is storing dynamically all the #VisuPair objects * that exist for a given #VisuData object. */ /** * VisuPairSetClass: * @parent: the parent class; * * A short way to identify #_VisuPairSetClass structure. */ /** * VisuPairSet: * * An opaque structure. */ /** * VisuPairSetIter: * @set: the #VisuPairSet this iterator is based on. * @pair: the current #VisuPair. * @link: the current #VisuPairLink. * * Iterator structure to run over all #VisuPairLink of a given set of #VisuPair. */ /** * VisuPairSetPrivate: * @minMax: storage for the length bounds for drawn pairs ; * @drawn: a boolean to say if the pair is drawn or not ; * @printLength: a boolean to say if length of pairs are drawn near * them ; * * This structure is used to describe a link between two elements. A * link is drawn only its length is between the minimum and the * maximum value stored in the minMax array. */ struct _VisuPairSetPrivate { gboolean dispose_has_run; GArray *pairs; VisuData *nodes; gulong popDef_sig, box_sig; VisuBox *box; gulong unit_sig; }; struct _PairData { VisuPair *pair; gulong links_sig; }; static void _freePairData(struct _PairData *dt) { g_signal_handler_disconnect(G_OBJECT(dt->pair), dt->links_sig); g_object_unref(G_OBJECT(dt->pair)); } static void visu_pair_set_dispose(GObject* obj); static void visu_pair_set_finalize(GObject* obj); static void visu_pair_set_get_property(GObject* obj, guint property_id, GValue *value, GParamSpec *pspec); static void _setup(VisuPairSet *set, GParamSpec *pspec, VisuNodeArray *nodes); static void _setBox(VisuPairSet *set, VisuBox *box); static void onLinksNotified(VisuPair *pair, GParamSpec *pspec, VisuPairSet *set); static void onUnits(VisuPairSet *set, gfloat fact, VisuBox *box); static VisuPair* _pair_pool_get(VisuElement *ele1, VisuElement *ele2); enum { PROP_0, PAIRS_PROP, DATA_PROP, N_PROP }; static GParamSpec *_properties[N_PROP]; enum { LINKS_SIGNAL, LAST_SIGNAL }; static guint _signals[LAST_SIGNAL] = { 0 }; G_DEFINE_TYPE_WITH_CODE(VisuPairSet, visu_pair_set, VISU_TYPE_OBJECT, G_ADD_PRIVATE(VisuPairSet)) static void visu_pair_set_class_init(VisuPairSetClass *klass) { DBG_fprintf(stderr, "Visu PairSet: creating the class of the object.\n"); DBG_fprintf(stderr, " - adding new signals ;\n"); /* Connect the overloading methods. */ G_OBJECT_CLASS(klass)->dispose = visu_pair_set_dispose; G_OBJECT_CLASS(klass)->finalize = visu_pair_set_finalize; G_OBJECT_CLASS(klass)->get_property = visu_pair_set_get_property; /** * VisuPairSet::pairs: * * Store the set of #VisuPair for the current model. * * Since: 3.8 */ _properties[PAIRS_PROP] = g_param_spec_boxed("pairs", "Pairs", "set of pairs", G_TYPE_ARRAY, G_PARAM_READABLE); g_object_class_install_property(G_OBJECT_CLASS(klass), PAIRS_PROP, _properties[PAIRS_PROP]); /** * VisuPairSet::data: * * Store the #VisuData from which the #VisuElement are extracted. * * Since: 3.8 */ _properties[DATA_PROP] = g_param_spec_object("data", "Data", "data elements come from", VISU_TYPE_DATA, G_PARAM_READABLE); g_object_class_install_property(G_OBJECT_CLASS(klass), DATA_PROP, _properties[DATA_PROP]); /** * VisuPairSet::links-changed: * @set: the object which emits the signal ; * @pair: (type VisuPair): the #VisuPair that has changing links. * * Gets emitted when any of the #VisuPair of @set has a change * (addition or removal) in its list of #VisuPairLink. * * Since: 3.8 */ _signals[LINKS_SIGNAL] = g_signal_new("links-changed", G_TYPE_FROM_CLASS(klass), G_SIGNAL_RUN_LAST | G_SIGNAL_NO_RECURSE | G_SIGNAL_NO_HOOKS, 0 , NULL, NULL, g_cclosure_marshal_VOID__OBJECT, G_TYPE_NONE, 1, VISU_TYPE_PAIR); } static void visu_pair_set_init(VisuPairSet *obj) { DBG_fprintf(stderr, "Visu PairSet: initializing a new object (%p).\n", (gpointer)obj); obj->priv = visu_pair_set_get_instance_private(obj); obj->priv->dispose_has_run = FALSE; /* Private data. */ obj->priv->pairs = g_array_new(FALSE, FALSE, sizeof(struct _PairData)); obj->priv->nodes = (VisuData*)0; obj->priv->box = (VisuBox*)0; } static void visu_pair_set_dispose(GObject* obj) { VisuPairSet *data; DBG_fprintf(stderr, "Visu PairSet: dispose object %p.\n", (gpointer)obj); data = VISU_PAIR_SET(obj); if (data->priv->dispose_has_run) return; data->priv->dispose_has_run = TRUE; visu_pair_set_setModel(data, (VisuData*)0); /* Chain up to the parent class */ G_OBJECT_CLASS(visu_pair_set_parent_class)->dispose(obj); } static void visu_pair_set_finalize(GObject* obj) { VisuPairSet *data; DBG_fprintf(stderr, "Visu PairSet: finalize object %p.\n", (gpointer)obj); data = VISU_PAIR_SET(obj); g_array_free(data->priv->pairs, TRUE); /* Chain up to the parent class */ G_OBJECT_CLASS(visu_pair_set_parent_class)->finalize(obj); } static void visu_pair_set_get_property(GObject* obj, guint property_id, GValue *value, GParamSpec *pspec) { VisuPairSet *self = VISU_PAIR_SET(obj); GArray *pairs; guint i; DBG_fprintf(stderr, "Visu PairSet: get property '%s' -> ", g_param_spec_get_name(pspec)); switch (property_id) { case PAIRS_PROP: pairs = g_array_sized_new(FALSE, FALSE, sizeof(VisuPair*), self->priv->pairs->len); for (i = 0; i < self->priv->pairs->len; i++) g_array_append_val(pairs, g_array_index(self->priv->pairs, struct _PairData, i).pair); g_value_take_boxed(value, pairs); DBG_fprintf(stderr, "%p.\n", (gpointer)self->priv->pairs); break; case DATA_PROP: g_value_set_object(value, self->priv->nodes); DBG_fprintf(stderr, "%p.\n", g_value_get_object(value)); break; default: /* We don't have any other property... */ G_OBJECT_WARN_INVALID_PROPERTY_ID(obj, property_id, pspec); break; } } /** * visu_pair_set_new: * * Define an object to handle all possible #VisuPair for a given * #VisuNodeArray. * * Since: 3.8 * * Returns: (transfer full): a new #VisuPairSet object. */ VisuPairSet* visu_pair_set_new() { return VISU_PAIR_SET(g_object_new(VISU_TYPE_PAIR_SET, NULL)); } /** * visu_pair_set_setModel: * @set: a #VisuPairSet object. * @nodes: a #VisuData object. * * Binds @nodes population and unit to @set. * * Since: 3.8 * * Returns: TRUE if model is actually changed. **/ gboolean visu_pair_set_setModel(VisuPairSet *set, VisuData *nodes) { g_return_val_if_fail(VISU_IS_PAIR_SET(set), FALSE); if (set->priv->nodes == nodes) return FALSE; if (set->priv->nodes) { g_signal_handler_disconnect(set->priv->nodes, set->priv->popDef_sig); g_signal_handler_disconnect(set->priv->nodes, set->priv->box_sig); g_object_unref(G_OBJECT(set->priv->nodes)); _setBox(set, (VisuBox*)0); } if (nodes) { g_object_ref(G_OBJECT(nodes)); set->priv->popDef_sig = g_signal_connect_swapped(nodes, "notify::elements", G_CALLBACK(_setup), set); set->priv->box_sig = g_signal_connect_swapped(nodes, "setBox", G_CALLBACK(_setBox), set); _setBox(set, visu_boxed_getBox(VISU_BOXED(nodes))); } set->priv->nodes = nodes; _setup(set, (GParamSpec*)0, VISU_NODE_ARRAY(nodes)); g_object_notify_by_pspec(G_OBJECT(set), _properties[DATA_PROP]); return TRUE; } /** * visu_pair_set_getNthPair: * @set: a #VisuPairSet object. * @pos: an integer. * * Retrieve the nth #VisuPair stored in @set. * * Since: 3.8 * * Returns: (transfer none): the nth #VisuPair in @set. **/ VisuPair* visu_pair_set_getNthPair(VisuPairSet *set, guint pos) { g_return_val_if_fail(VISU_IS_PAIR_SET(set), (VisuPair*)0); return (pos < set->priv->pairs->len) ? g_array_index(set->priv->pairs, struct _PairData, pos).pair : (VisuPair*)0; } /** * visu_pair_set_get: * @set: a #VisuPairSet object. * @ele1: a #VisuElement object. * @ele2: a #VisuElement object. * * Retrieve the #VisuPair linking @ele1 and @ele2 as stroed in @set if * it exists, or %NULL if not. * * Since: 3.8 * * Returns: (transfer none): the #VisuPair stored in @set linking * @ele1 and @ele2. **/ VisuPair* visu_pair_set_get(VisuPairSet *set, const VisuElement *ele1, const VisuElement *ele2) { guint i; VisuElement *e1, *e2; g_return_val_if_fail(VISU_IS_PAIR_SET(set), (VisuPair*)0); for (i = 0; i < set->priv->pairs->len; i++) { visu_pair_getElements(g_array_index(set->priv->pairs, struct _PairData, i).pair, &e1, &e2); if ((e1 == ele1 && e2 == ele2 ) || (e1 == ele2 && e2 == ele1)) return g_array_index(set->priv->pairs, struct _PairData, i).pair; } return (VisuPair*)0; } /** * visu_pair_set_getFromLink: * @set: a #VisuPairSet object. * @link: a #VisuPairLink object. * * Retrieve the #VisuPair stored in @set that contains @link, or %NULL * if none. * * Since: 3.8 * * Returns: (transfer none): the #VisuPair stored in @set containing @link. **/ VisuPair* visu_pair_set_getFromLink(VisuPairSet *set, const VisuPairLink *link) { guint i; g_return_val_if_fail(VISU_IS_PAIR_SET(set), (VisuPair*)0); for (i = 0; i < set->priv->pairs->len; i++) if (visu_pair_contains(g_array_index(set->priv->pairs, struct _PairData, i).pair, link)) return g_array_index(set->priv->pairs, struct _PairData, i).pair; return (VisuPair*)0; } static void _setup(VisuPairSet *set, GParamSpec *pspec _U_, VisuNodeArray *nodes) { guint i, j; GArray *pairs, *elements; struct _PairData dt; if (nodes) { g_object_get(nodes, "elements", &elements, NULL); pairs = g_array_sized_new(FALSE, FALSE, sizeof(struct _PairData), elements->len * (elements->len + 1) / 2); for(i = 0; i < elements->len; i++) for(j = i; j < elements->len; j++) { dt.pair = visu_pair_set_get(set, g_array_index(elements, VisuElement*, i), g_array_index(elements, VisuElement*, j)); if (!dt.pair) dt.pair = _pair_pool_get(g_array_index(elements, VisuElement*, i), g_array_index(elements, VisuElement*, j)); g_object_ref(dt.pair); dt.links_sig = g_signal_connect(G_OBJECT(dt.pair), "notify::links", G_CALLBACK(onLinksNotified), set); g_array_append_val(pairs, dt); } g_array_unref(elements); } else pairs = g_array_new(FALSE, FALSE, sizeof(struct _PairData)); g_array_set_clear_func(pairs, (GDestroyNotify)_freePairData); if (set->priv->pairs) g_array_free(set->priv->pairs, TRUE); set->priv->pairs = pairs; DBG_fprintf(stderr, "Visu Pair Set: new set of %d pairs.\n", pairs->len); g_object_notify_by_pspec(G_OBJECT(set), _properties[PAIRS_PROP]); if (set->priv->box) onUnits(set, 0.f, set->priv->box); } static void _setBox(VisuPairSet *set, VisuBox *box) { if (set->priv->box) { g_signal_handler_disconnect(G_OBJECT(set->priv->box), set->priv->unit_sig); g_object_unref(G_OBJECT(set->priv->box)); } set->priv->box = box; if (box) { g_object_ref(G_OBJECT(box)); set->priv->unit_sig = g_signal_connect_swapped(G_OBJECT(box), "UnitChanged", G_CALLBACK(onUnits), set); } } static void onLinksNotified(VisuPair *pair, GParamSpec *pspec _U_, VisuPairSet *set) { g_signal_emit(G_OBJECT(set), _signals[LINKS_SIGNAL], 0, pair); } static void onUnits(VisuPairSet *set, gfloat fact _U_, VisuBox *box) { VisuPairSetIter iter; ToolUnits units; units = visu_box_getUnit(box); for (visu_pair_set_iter_new(set, &iter, TRUE); iter.link; visu_pair_set_iter_next(&iter)) visu_pair_link_setUnits(iter.link, units); } /** * visu_pair_set_iter_new: * @set: a #VisuPairSet object. * @iter: (out caller-allocates): a #VisuPairSetIter location. * @all: a boolean. * * Creates an iterator over all the #VisuPairLink of a set of * #VisuPair. If @all is %FALSE, only visible #VisuPairLink, see * visu_pair_link_setDrawn(), are iterated on. * * Since: 3.8 **/ void visu_pair_set_iter_new(VisuPairSet *set, VisuPairSetIter *iter, gboolean all) { VisuElement *ele1, *ele2; g_return_if_fail(VISU_IS_PAIR_SET(set) && iter); iter->all = all; iter->set = set; iter->i = 0; iter->j = 0; do { iter->pair = visu_pair_set_getNthPair(iter->set, (iter->i)++); if (iter->pair) visu_pair_getElements(iter->pair, &ele1, &ele2); } while (iter->pair && (!visu_element_getRendered(ele1) || !visu_element_getRendered(ele2))); visu_pair_set_iter_next(iter); } /** * visu_pair_set_iter_next: * @iter: a #VisuPairSetIter object. * * Iterates to the next #VisuPairLink. * * Since: 3.8 **/ void visu_pair_set_iter_next(VisuPairSetIter *iter) { VisuElement *ele1, *ele2; g_return_if_fail(iter); if (!iter->pair) { iter->link = (VisuPairLink*)0; return; } do { iter->link = visu_pair_getNthLink(iter->pair, (iter->j)++); } while (iter->link && !iter->all && !visu_pair_link_isDrawn(iter->link)); if (!iter->link) { do { iter->pair = visu_pair_set_getNthPair(iter->set, (iter->i)++); if (iter->pair) visu_pair_getElements(iter->pair, &ele1, &ele2); } while (iter->pair && (!visu_element_getRendered(ele1) || !visu_element_getRendered(ele2))); iter->j = 0; visu_pair_set_iter_next(iter); } } /*******************/ /* Pair set stuff. */ /*******************/ /* This hashtable as VisuElement* as keys and pointer to other hashtable as value. The main idea is to have an hashtable of 2 dimension, each two keys are VisuElement* and the final values are PairsData. Nevertheless, this hashtable must not be access directly but through the get and put methods. */ static GHashTable *DminDmax = NULL; static void _pair_pool_init() { DminDmax = g_hash_table_new_full(g_str_hash, g_str_equal, g_free, g_object_unref); } /** * visu_pair_pool_finalize: (skip) * * Free all associated memory. * * Since: 3.8 **/ void visu_pair_pool_finalize() { if (DminDmax) g_hash_table_destroy(DminDmax); DminDmax = NULL; } static VisuPair* _pair_pool_get(VisuElement *ele1, VisuElement *ele2) { VisuPair *pair; gchar *key; g_return_val_if_fail(ele1 && ele2, (VisuPair*)0); if (!DminDmax) _pair_pool_init(); if (strcmp(ele1->name, ele2->name) < 0) key = g_strdup_printf("%s %s", ele1->name, ele2->name); else key = g_strdup_printf("%s %s", ele2->name, ele1->name); pair = (VisuPair*)g_hash_table_lookup(DminDmax, (gpointer)key); DBG_fprintf(stderr, "Visu Pair Set: test key '%s' -> %p.\n", key, (gpointer)pair); if (!pair) { /* Ok, create one if none found. */ pair = visu_pair_new(ele1, ele2); g_hash_table_insert(DminDmax, (gpointer)key, (gpointer)pair); } else g_free(key); return pair; } struct foreachPairsData_struct { VisuPairPoolForeachFunc func; gpointer userData; }; static void foreachLevel2(gpointer key _U_, gpointer value, gpointer userData) { struct foreachPairsData_struct *storage; storage = (struct foreachPairsData_struct *)userData; storage->func((VisuPair*)value, storage->userData); } /** * visu_pair_pool_foreach: * @whatToDo: (scope call): a VisuPairSetForeachFunc() method ; * @user_data: some user defined data. * * The way #VisuPair are stored in V_Sim is private and could changed between version. * This method is used to apply some method each pairs. */ void visu_pair_pool_foreach(VisuPairPoolForeachFunc whatToDo, gpointer user_data) { struct foreachPairsData_struct storage; if (!DminDmax) _pair_pool_init(); storage.func = whatToDo; storage.userData = user_data; g_hash_table_foreach(DminDmax, (GHFunc)foreachLevel2, (gpointer)(&storage)); } /** * visu_pair_pool_readLinkFromLabel: * @label: a string. * @data: (out callee-allocates): a #VisuPairLink location. * @errorMessage: (out callee-allocates): a string location. * * Reads @label and parses it to detect the definition of a * #VisuPairLink. This pair link is added to the #VisuPair from the pool. * * Since: 3.8 * * Returns: TRUE on success. **/ gboolean visu_pair_pool_readLinkFromLabel(const gchar *label, VisuPairLink **data, gchar **errorMessage) { gchar **tokens; VisuElement *ele[2]; float minMax[2]; guint i, n; VisuPair *pair; g_return_val_if_fail(data && errorMessage, FALSE); DBG_fprintf(stderr, "Visu PairSet: look for link from label '%s'.\n", label); if (!label) return FALSE; *data = (VisuPairLink*)0; tokens = g_strsplit_set(label, " \n", TOOL_MAX_LINE_LENGTH); /* Read the two elements. */ for (i = 0, n = 0; tokens[i] && n < 2; i++) if (tokens[i][0]) { ele[n] = visu_element_retrieveFromName(tokens[i], (gboolean*)0); if (!ele[n]) { *errorMessage = g_strdup_printf(_("'%s' wrong element name"), tokens[i]); g_strfreev(tokens); return FALSE; } n += 1; } if (n != 2) { *errorMessage = g_strdup_printf(_("2 elements should appear here" " but %d has been found"),n); g_strfreev(tokens); return FALSE; } /* Read the two distances. */ for (n = 0; tokens[i] && n < 2; i++) if (tokens[i][0]) { if (sscanf(tokens[i], "%f", minMax + n) != 1 || minMax[n] < 0.f) { *errorMessage = g_strdup_printf(_("'%s' wrong floating point value"), tokens[i]); g_strfreev(tokens); return FALSE; } n += 1; } if (n != 2) { *errorMessage = g_strdup_printf(_("2 floating point values should appear here" " but %d has been found"),n); g_strfreev(tokens); return FALSE; } g_strfreev(tokens); /* Set the values. */ pair = _pair_pool_get(ele[0], ele[1]); *data = visu_pair_addLink(pair, minMax); return (*data != (VisuPairLink*)0); } v_sim-3.8.0/src/visu_pairset.h000066400000000000000000000114131370110300500163020ustar00rootroot00000000000000/* EXTRAITS DE LA LICENCE Copyright CEA, contributeurs : Damien CALISTE, laboratoire L_Sim, (2016) Adresse mèl : CALISTE, damien P caliste AT cea P fr. Ce logiciel est un programme informatique servant à visualiser des structures atomiques dans un rendu pseudo-3D. Ce logiciel est régi par la licence CeCILL soumise au droit français et respectant les principes de diffusion des logiciels libres. Vous pouvez utiliser, modifier et/ou redistribuer ce programme sous les conditions de la licence CeCILL telle que diffusée par le CEA, le CNRS et l'INRIA sur le site "http://www.cecill.info". Le fait que vous puissiez accéder à cet en-tête signifie que vous avez pris connaissance de la licence CeCILL, et que vous en avez accepté les termes (cf. le fichier Documentation/licence.fr.txt fourni avec ce logiciel). */ /* LICENCE SUM UP Copyright CEA, contributors : Damien CALISTE, laboratoire L_Sim, (2016) E-mail address: CALISTE, damien P caliste AT cea P fr. This software is a computer program whose purpose is to visualize atomic configurations in 3D. This software is governed by the CeCILL license under French law and abiding by the rules of distribution of free software. You can use, modify and/ or redistribute the software under the terms of the CeCILL license as circulated by CEA, CNRS and INRIA at the following URL "http://www.cecill.info". The fact that you are presently reading this means that you have had knowledge of the CeCILL license and that you accept its terms. You can find a copy of this licence shipped with this software at Documentation/licence.en.txt. */ #ifndef VISU_PAIRSET_H #define VISU_PAIRSET_H #include #include #include G_BEGIN_DECLS /** * VISU_TYPE_PAIR_SET: * * return the type of #VisuPairSet. */ #define VISU_TYPE_PAIR_SET (visu_pair_set_get_type ()) /** * VISU_PAIR_SET: * @obj: a #GObject to cast. * * Cast the given @obj into #VisuPairSet type. */ #define VISU_PAIR_SET(obj) (G_TYPE_CHECK_INSTANCE_CAST(obj, VISU_TYPE_PAIR_SET, VisuPairSet)) /** * VISU_PAIR_SET_CLASS: * @klass: a #GObjectClass to cast. * * Cast the given @klass into #VisuPairSetClass. */ #define VISU_PAIR_SET_CLASS(klass) (G_TYPE_CHECK_CLASS_CAST(klass, VISU_TYPE_PAIR_SET, VisuPairSetClass)) /** * VISU_IS_PAIR_SET: * @obj: a #GObject to test. * * Test if the given @ogj is of the type of #VisuPairSet object. */ #define VISU_IS_PAIR_SET(obj) (G_TYPE_CHECK_INSTANCE_TYPE(obj, VISU_TYPE_PAIR_SET)) /** * VISU_IS_PAIR_SET_CLASS: * @klass: a #GObjectClass to test. * * Test if the given @klass is of the type of #VisuPairSetClass class. */ #define VISU_IS_PAIR_SET_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE(klass, VISU_TYPE_PAIR_SET)) /** * VISU_PAIR_SET_GET_CLASS: * @obj: a #GObject to get the class of. * * It returns the class of the given @obj. */ #define VISU_PAIR_SET_GET_CLASS(obj) (G_TYPE_INSTANCE_GET_CLASS(obj, VISU_TYPE_PAIR_SET, VisuPairSetClass)) typedef struct _VisuPairSetClass VisuPairSetClass; typedef struct _VisuPairSet VisuPairSet; typedef struct _VisuPairSetPrivate VisuPairSetPrivate; /** * visu_pair_set_get_type: * * This method returns the type of #VisuPairSet, use VISU_TYPE_PAIR_SET instead. * * Returns: the type of #VisuPairSet. */ GType visu_pair_set_get_type(void); /** * _VisuPairSet: * @parent: parent. * @priv: private data. * * This structure describes a set of pairs. */ struct _VisuPairSet { VisuObject parent; VisuPairSetPrivate *priv; }; struct _VisuPairSetClass { VisuObjectClass parent; }; VisuPairSet* visu_pair_set_new(); gboolean visu_pair_set_setModel(VisuPairSet *set, VisuData *nodes); VisuPair* visu_pair_set_getNthPair(VisuPairSet *set, guint pos); VisuPair* visu_pair_set_get(VisuPairSet *set, const VisuElement *ele1, const VisuElement *ele2); VisuPair* visu_pair_set_getFromLink(VisuPairSet *set, const VisuPairLink *link); typedef struct _VisuPairSetIter VisuPairSetIter; struct _VisuPairSetIter { VisuPairSet *set; VisuPair *pair; VisuPairLink *link; /*< private >*/ guint i, j; gboolean all; }; void visu_pair_set_iter_new(VisuPairSet *set, VisuPairSetIter *iter, gboolean all); void visu_pair_set_iter_next(VisuPairSetIter *iter); /** * VisuPairPoolForeachFunc: * @pair: a #VisuPair object. * @user_data: some user defined data. * * Prototype of functions called with the foreach method apply to each * pairs. */ typedef void (*VisuPairPoolForeachFunc)(VisuPair *pair, gpointer user_data); void visu_pair_pool_foreach(VisuPairPoolForeachFunc whatToDo, gpointer user_data); void visu_pair_pool_finalize(); gboolean visu_pair_pool_readLinkFromLabel(const gchar *label, VisuPairLink **data, gchar **errorMessage); G_END_DECLS #endif v_sim-3.8.0/src/visu_plugins.c000066400000000000000000000271621370110300500163170ustar00rootroot00000000000000/* EXTRAITS DE LA LICENCE Copyright CEA, contributeurs : Luc BILLARD et Damien CALISTE, laboratoire L_Sim, (2001-2005) Adresse mèl : BILLARD, non joignable par mèl ; CALISTE, damien P caliste AT cea P fr. Ce logiciel est un programme informatique servant à visualiser des structures atomiques dans un rendu pseudo-3D. Ce logiciel est régi par la licence CeCILL soumise au droit français et respectant les principes de diffusion des logiciels libres. Vous pouvez utiliser, modifier et/ou redistribuer ce programme sous les conditions de la licence CeCILL telle que diffusée par le CEA, le CNRS et l'INRIA sur le site "http://www.cecill.info". Le fait que vous puissiez accéder à cet en-tête signifie que vous avez pris connaissance de la licence CeCILL, et que vous en avez accepté les termes (cf. le fichier Documentation/licence.fr.txt fourni avec ce logiciel). */ /* LICENCE SUM UP Copyright CEA, contributors : Luc BILLARD et Damien CALISTE, laboratoire L_Sim, (2001-2005) E-mail address: BILLARD, not reachable any more ; CALISTE, damien P caliste AT cea P fr. This software is a computer program whose purpose is to visualize atomic configurations in 3D. This software is governed by the CeCILL license under French law and abiding by the rules of distribution of free software. You can use, modify and/ or redistribute the software under the terms of the CeCILL license as circulated by CEA, CNRS and INRIA at the following URL "http://www.cecill.info". The fact that you are presently reading this means that you have had knowledge of the CeCILL license and that you accept its terms. You can find a copy of this licence shipped with this software at Documentation/licence.en.txt. */ #include #include "visu_plugins.h" #include "visu_tools.h" #include "visu_basic.h" /** * SECTION:visu_plugins * @short_description: Introduces the basic handling of plug-ins. * * * Plug-ins are made of shared library presenting some common routines. These routines are of kind: * * * pluginsInitFunc(), such a routine is called at V_Sim startup. It should initialise all things required by the module. For instance, if the module is used to add a load method for atomic rendering, it should call visu_rendering_addFileFormat() to declare itself to V_Sim. * * * pluginsDescriptionFunc(), is used to get a short description of the plug-in. * * * pluginsAuthorsFunc(), gives a list of authors for the plug-in. * * * pluginsIconFunc(), returns a path where a small icon representing the plug-in can be found. * * * All these routines must be named using the name of the module. When the module is loaded into memory, V_Sim will try to find these methods and will store them into the #VisuPlugin structure for future calls. * * * At the present time, only the Unix version is functional. Moreover, currently, no stable API is available from the main program. This should be corrected quickly. * */ /** * VisuPlugin_struct: * @hook: a pointer to the opened shared library ; * @name: the name of the module (on UNIX it is lib{name}.so) ; * @init: a pointer on the init method ; * @getDescription: a pointer to the description method ; * @getAuthors: a pointer to the author method. * @getIcon: a pointer to the icon method. * * This structure is used to deals with a plugin. It gives handles * to the public method of the plugin. */ struct _VisuPlugin { GModule *hook; gchar *name; VisuPluginInitFunc init; VisuPluginInitFunc initGtk; VisuPluginInfoFunc getDescription; VisuPluginInfoFunc getAuthors; VisuPluginInfoFunc getIcon; VisuPluginFreeFunc finalise; }; /* Local variables. */ GList *presentPlugins = NULL; /** * visu_plugins_getListLoaded: * * On startup, plugins are loaded according to a list present in the configuration * file. It is possible to access the list of all loaded plugins with this method. * * Returns: (element-type VisuPlugin) (transfer none): a #GList owned by V_Sim of #VisuPlugin objects. */ GList* visu_plugins_getListLoaded() { if (!presentPlugins) visu_plugins_init(NULL); return presentPlugins; } static gboolean visuPluginLoad_byPath(const gchar* path, GError **error) { gchar *func, *name, *ptChar, *libname; VisuPlugin *plugin; gboolean res; plugin = g_malloc(sizeof(VisuPlugin)); plugin->hook = g_module_open(path, 0); /* G_MODULE_BIND_LOCAL); */ if (plugin->hook) { libname = g_path_get_basename(path); name = g_strdup(libname + 3); g_free(libname); #if SYSTEM_WIN32 == 1 ptChar = g_strrstr(name, "-"); #endif #if SYSTEM_X11 == 1 ptChar = strchr(name, '.'); #endif if (ptChar) *ptChar = '\0'; func = g_strdup_printf("%sInit", name); res = g_module_symbol(plugin->hook, func, (void*)&(plugin->init)); g_free(func); if (!res) { g_set_error(error, G_FILE_ERROR, G_FILE_ERROR_FAILED, "The plugin '%s' doesn't have any %sInit() method.", name, name); g_free(plugin); g_free(name); return FALSE; } func = g_strdup_printf("%sGet_description", name); res = g_module_symbol(plugin->hook, func, (void*)&(plugin->getDescription)); g_free(func); if (!res) { g_set_error(error, G_FILE_ERROR, G_FILE_ERROR_FAILED, "The plugin '%s' doesn't have any %sGet_description() method.", name, name); g_free(plugin); g_free(name); return FALSE; } func = g_strdup_printf("%sGet_authors", name); res = g_module_symbol(plugin->hook, func, (void*)&(plugin->getAuthors)); g_free(func); if (!res) { g_set_error(error, G_FILE_ERROR, G_FILE_ERROR_FAILED, "The plugin '%s' doesn't have any %sGet_authors() method.", name, name); g_free(plugin); g_free(name); return FALSE; } func = g_strdup_printf("%sGet_icon", name); res = g_module_symbol(plugin->hook, func, (void*)&(plugin->getIcon)); if (!res) plugin->getIcon = (VisuPluginInfoFunc)0; g_free(func); func = g_strdup_printf("%sInitGtk", name); res = g_module_symbol(plugin->hook, func, (void*)&(plugin->initGtk)); g_free(func); if (!res) plugin->initGtk = (VisuPluginInitFunc)0; func = g_strdup_printf("%sFree", name); res = g_module_symbol(plugin->hook, func, (void*)&(plugin->finalise)); g_free(func); if (!res) plugin->finalise = (VisuPluginFreeFunc)0; plugin->name = g_strdup(name); g_free(name); presentPlugins = g_list_prepend(presentPlugins, (gpointer)plugin); } else { g_set_error(error, G_FILE_ERROR, G_FILE_ERROR_FAILED, "The plugin '%s' is not a loadable module, error:\n%s.", path, g_module_error()); g_free(plugin); return FALSE; } return TRUE; } static GList* visuPluginsParseDir(const gchar* path) { GDir *gdir; const gchar *fileFromDir; GPatternSpec *pattern; GList* lst; lst = (GList*)0; gdir = g_dir_open(path, 0, NULL); if (!gdir) return lst; pattern = g_pattern_spec_new("lib*."G_MODULE_SUFFIX); fileFromDir = g_dir_read_name(gdir); while (fileFromDir) { if (g_pattern_match_string(pattern, fileFromDir)) lst = g_list_prepend(lst, g_build_filename(path, fileFromDir, NULL)); fileFromDir = g_dir_read_name(gdir); } g_dir_close(gdir); g_pattern_spec_free(pattern); return lst; } /* Parse install directory and $XDG_CONFIG_HOME/v_sim/plugins to find files and create a gchar** array of names (as full path). */ static gchar** visuPluginsGet_installedPlugins() { gchar **data, *path; GList* lst_install, *lst_home, *tmpLst; int size; /* Try the install dir. */ lst_install = visuPluginsParseDir(V_SIM_PLUGINS_DIR); /* Try the home dir. */ path = g_build_filename(V_SIM_LOCAL_CONF_DIR, "plugins", NULL); lst_home = visuPluginsParseDir(path); g_free(path); size = g_list_length(lst_install) + g_list_length(lst_home) + 1; data = g_malloc(sizeof(gchar*) * size); size = 0; tmpLst = lst_install; while(tmpLst) { data[size] = (gchar*)tmpLst->data; size += 1; tmpLst = g_list_next(tmpLst); } g_list_free(lst_install); tmpLst = lst_home; while(tmpLst) { data[size] = (gchar*)tmpLst->data; size += 1; tmpLst = g_list_next(tmpLst); } g_list_free(lst_home); data[size] = (gchar*)0; return data; } /** * visu_plugins_init: * @error: an error location. * * Initialise this part of code. Should not be called (called once * by V_Sim on startup only). It try to load * all plugins found in the installation directory and in the user directory. */ void visu_plugins_init(GError **error) { gchar **plugins; GError *perr; int i; if (g_module_supported() && !presentPlugins) { plugins = visuPluginsGet_installedPlugins(); for (i = 0; plugins[i]; i++) { DBG_fprintf(stderr, "Visu Plugins : try to load the plugin '%s'.\n", plugins[i]); perr = (GError*)0; if (visuPluginLoad_byPath(plugins[i], &perr)) ((VisuPlugin*)presentPlugins->data)->init(); if ((!error || !*error) && perr) g_propagate_error(error, perr); else g_clear_error(&perr); } g_strfreev(plugins); } } /** * visu_plugins_free: * * Finalise the part of V_Sim related to plug-ins. Should not be * called (called once by V_Sim on stopping only). * * Since: 3.7 */ void visu_plugins_free() { GList *plugins; plugins = visu_plugins_getListLoaded(); for (plugins = visu_plugins_getListLoaded(); plugins; plugins = g_list_next(plugins)) { DBG_fprintf(stderr, "Visu Plugins: try to finalise the plugin '%s'.\n", ((VisuPlugin*)plugins->data)->name); if (((VisuPlugin*)plugins->data)->finalise) ((VisuPlugin*)plugins->data)->finalise(); } } /** * visu_plugin_getName: * @plug: a #VisuPlugin object. * * Return a string with the name. * * Returns: a private string. * * Since: 3.6 */ const gchar* visu_plugin_getName(VisuPlugin *plug) { g_return_val_if_fail(plug, (const gchar*)0); return plug->name; } /** * visu_plugin_getDescription: * @plug: a #VisuPlugin object. * * Return a string with the description of the plugin. * * Returns: a private string. * * Since: 3.6 */ const gchar* visu_plugin_getDescription(VisuPlugin *plug) { g_return_val_if_fail(plug, (const gchar*)0); if (plug->getDescription) return plug->getDescription(); else return (const gchar*)0; } /** * visu_plugin_getIconPath: * @plug: a #VisuPlugin object. * * Return a string with the path to find an icon representing the plugin. * * Returns: a private string. * * Since: 3.6 */ const gchar* visu_plugin_getIconPath(VisuPlugin *plug) { g_return_val_if_fail(plug, (const gchar*)0); if (plug->getIcon) return plug->getIcon(); else return (const gchar*)0; } /** * visu_plugin_getAuthors: * @plug: a #VisuPlugin object. * * Return a string with the list of authors. * * Returns: a private string. * * Since: 3.6 */ const gchar* visu_plugin_getAuthors(VisuPlugin *plug) { g_return_val_if_fail(plug, (const gchar*)0); if (plug->getAuthors) return plug->getAuthors(); else return (const gchar*)0; } /** * visu_plugin_initGtk: * @plug: a #VisuPlugin object. * * Run the initGtk() method of the plugin, if it exists. * * Since: 3.6 */ void visu_plugin_initGtk(VisuPlugin *plug) { g_return_if_fail(plug); if (plug->initGtk) plug->initGtk(); } v_sim-3.8.0/src/visu_plugins.h000066400000000000000000000057671370110300500163330ustar00rootroot00000000000000/* EXTRAITS DE LA LICENCE Copyright CEA, contributeurs : Luc BILLARD et Damien CALISTE, laboratoire L_Sim, (2001-2005) Adresse mèl : BILLARD, non joignable par mèl ; CALISTE, damien P caliste AT cea P fr. Ce logiciel est un programme informatique servant à visualiser des structures atomiques dans un rendu pseudo-3D. Ce logiciel est régi par la licence CeCILL soumise au droit français et respectant les principes de diffusion des logiciels libres. Vous pouvez utiliser, modifier et/ou redistribuer ce programme sous les conditions de la licence CeCILL telle que diffusée par le CEA, le CNRS et l'INRIA sur le site "http://www.cecill.info". Le fait que vous puissiez accéder à cet en-tête signifie que vous avez pris connaissance de la licence CeCILL, et que vous en avez accepté les termes (cf. le fichier Documentation/licence.fr.txt fourni avec ce logiciel). */ /* LICENCE SUM UP Copyright CEA, contributors : Luc BILLARD et Damien CALISTE, laboratoire L_Sim, (2001-2005) E-mail address: BILLARD, not reachable any more ; CALISTE, damien P caliste AT cea P fr. This software is a computer program whose purpose is to visualize atomic configurations in 3D. This software is governed by the CeCILL license under French law and abiding by the rules of distribution of free software. You can use, modify and/ or redistribute the software under the terms of the CeCILL license as circulated by CEA, CNRS and INRIA at the following URL "http://www.cecill.info". The fact that you are presently reading this means that you have had knowledge of the CeCILL license and that you accept its terms. You can find a copy of this licence shipped with this software at Documentation/licence.en.txt. */ #include #include /** * VisuPluginInitFunc: * * This kind of method should exist in all plugins with the * name '{module_name}Init'. It is called by V_Sim when the module is loaded. * * Returns: TRUE if it loads correctly. */ typedef gboolean (*VisuPluginInitFunc)(void); /** * VisuPluginFreeFunc: * * This kind of method may exist in all plugins with the * name '{module_name}Free'. It is called by V_Sim when it stops. * * Since: 3.7 */ typedef void (*VisuPluginFreeFunc)(void); /** * VisuPluginInfoFunc: * * This kind of method should exist in all plugins it give a description of * what the plugin does. It must be named '{module_name}Get_description'. * * Returns: a string in UTF-8 owned by the plugin. */ typedef const gchar* (*VisuPluginInfoFunc)(void); struct _VisuPlugin; /** * VisuPlugin: * * Short way to address #_VisuPlugin objects. */ typedef struct _VisuPlugin VisuPlugin; void visu_plugins_init(GError **error); GList* visu_plugins_getListLoaded(); void visu_plugins_free(); const gchar* visu_plugin_getName(VisuPlugin *plug); const gchar* visu_plugin_getDescription(VisuPlugin *plug); const gchar* visu_plugin_getIconPath(VisuPlugin *plug); const gchar* visu_plugin_getAuthors(VisuPlugin *plug); void visu_plugin_initGtk(VisuPlugin *plug); v_sim-3.8.0/src/visu_test.c000066400000000000000000000056451370110300500156170ustar00rootroot00000000000000/* EXTRAITS DE LA LICENCE Copyright CEA, contributeurs : Luc BILLARD et Damien CALISTE, laboratoire L_Sim, (2001-2005) Adresse mèl : BILLARD, non joignable par mèl ; CALISTE, damien P caliste AT cea P fr. Ce logiciel est un programme informatique servant à visualiser des structures atomiques dans un rendu pseudo-3D. Ce logiciel est régi par la licence CeCILL soumise au droit français et respectant les principes de diffusion des logiciels libres. Vous pouvez utiliser, modifier et/ou redistribuer ce programme sous les conditions de la licence CeCILL telle que diffusée par le CEA, le CNRS et l'INRIA sur le site "http://www.cecill.info". Le fait que vous puissiez accéder à cet en-tête signifie que vous avez pris connaissance de la licence CeCILL, et que vous en avez accepté les termes (cf. le fichier Documentation/licence.fr.txt fourni avec ce logiciel). */ /* LICENCE SUM UP Copyright CEA, contributors : Luc BILLARD et Damien CALISTE, laboratoire L_Sim, (2001-2005) E-mail address: BILLARD, not reachable any more ; CALISTE, damien P caliste AT cea P fr. This software is a computer program whose purpose is to visualize atomic configurations in 3D. This software is governed by the CeCILL license under French law and abiding by the rules of distribution of free software. You can use, modify and/ or redistribute the software under the terms of the CeCILL license as circulated by CEA, CNRS and INRIA at the following URL "http://www.cecill.info". The fact that you are presently reading this means that you have had knowledge of the CeCILL license and that you accept its terms. You can find a copy of this licence shipped with this software at Documentation/licence.en.txt. */ #include "visu_basic.h" #include "visu_commandLine.h" #include "visu_tools.h" #include "visu_gtk.h" #include "gtk_main.h" #include #include #include #include #include #ifdef HAVE_GTKGLEXT #include #endif int main (int argc, char *argv[]) { int res; DBG_fprintf(stderr, "--- Get the default path ---\n"); visuBasicSet_paths(argv[0]); #ifdef G_THREADS_ENABLED DBG_fprintf(stderr, "--- Initialise threads ---\n"); g_thread_init(NULL); #endif #ifdef ENABLE_NLS setlocale (LC_ALL, ""); bindtextdomain (GETTEXT_PACKAGE, v_sim_locale_dir); bind_textdomain_codeset (GETTEXT_PACKAGE, "UTF-8"); textdomain (GETTEXT_PACKAGE); #endif DBG_fprintf(stderr, "--- Parse the command line ---\n"); res = commandLineParse(argc, argv); if (res) exit(1); DBG_fprintf(stderr, "Visu Main: initialise Gtk.\n"); gtk_init(&argc, &argv); #ifdef HAVE_GTKGLEXT DBG_fprintf(stderr, "Visu Main: initialise GtkGlExt.\n"); gdk_gl_init(&argc, &argv); #endif /* the default is V_Sim with gtk interface. */ visu_ui_mainCreate(visu_ui_createInterface); DBG_fprintf(stderr, "Visu Main: starting main GTK loop.\n"); gtk_main(); return res; } v_sim-3.8.0/src/visu_tools.c000066400000000000000000000236511370110300500157750ustar00rootroot00000000000000/* EXTRAITS DE LA LICENCE Copyright CEA, contributeurs : Luc BILLARD et Damien CALISTE, laboratoire L_Sim, (2001-2005) Adresse mèl : BILLARD, non joignable par mèl ; CALISTE, damien P caliste AT cea P fr. Ce logiciel est un programme informatique servant à visualiser des structures atomiques dans un rendu pseudo-3D. Ce logiciel est régi par la licence CeCILL soumise au droit français et respectant les principes de diffusion des logiciels libres. Vous pouvez utiliser, modifier et/ou redistribuer ce programme sous les conditions de la licence CeCILL telle que diffusée par le CEA, le CNRS et l'INRIA sur le site "http://www.cecill.info". Le fait que vous puissiez accéder à cet en-tête signifie que vous avez pris connaissance de la licence CeCILL, et que vous en avez accepté les termes (cf. le fichier Documentation/licence.fr.txt fourni avec ce logiciel). */ /* LICENCE SUM UP Copyright CEA, contributors : Luc BILLARD et Damien CALISTE, laboratoire L_Sim, (2001-2005) E-mail address: BILLARD, not reachable any more ; CALISTE, damien P caliste AT cea P fr. This software is a computer program whose purpose is to visualize atomic configurations in 3D. This software is governed by the CeCILL license under French law and abiding by the rules of distribution of free software. You can use, modify and/ or redistribute the software under the terms of the CeCILL license as circulated by CEA, CNRS and INRIA at the following URL "http://www.cecill.info". The fact that you are presently reading this means that you have had knowledge of the CeCILL license and that you accept its terms. You can find a copy of this licence shipped with this software at Documentation/licence.en.txt. */ #include "visu_tools.h" #include #include #include #include /* For the access markers R_OK, W_OK ... */ #include /** * tool_getValidPath: * @pathList: (element-type filename): a pointer to a GList with all the possible path, * @filenames: (array zero-terminated=1) (element-type filename): an array of strings, * @accessMode: a value from R_OK, W_OK and X_OK as described in unistd.h. * * @pathList contains a list of directories (first is most prefered) * and fileName is the file name which one likes have informations on. This routine * look for the first directory where fileName can be writen or read (depending * on accessMode parameter). The pointer to the GList indicates at the end the * first valid entry in the GList. * * Returns: (transfer full): the first valid complete path (from * @pathList plus an entry of @filenames) if one can be found depnding * on @accessMode or NULL if none found. Free it with g_free() after * use. */ gchar* tool_getValidPath(GList **pathList, const char **filenames, int accessMode) { gchar *validPath; int fileOk; guint i; g_return_val_if_fail(pathList && filenames, (gchar*)0); DBG_fprintf(stderr, "Visu Tools : test access (%d) from list of %d elements.\n", accessMode, g_list_length(*pathList)); validPath = (char*)0; /* look for a directory to save or read a file. */ fileOk = 0; while (*pathList && !fileOk) { for (i = 0; filenames[i]; i++) { validPath = g_build_filename((gchar*)(*pathList)->data, filenames[i], NULL); DBG_fprintf(stderr, "Visu Tools : test access (%d) for '%s' ... ", accessMode, validPath); fileOk = !access((char*)validPath, accessMode); /* return 0 if success */ if (fileOk) break; /* if access mode is write access and the file does not already exist : we test if the directory has written permitions. */ if ( accessMode == W_OK && !g_file_test(validPath, G_FILE_TEST_EXISTS) ) fileOk = !access((char*)(*pathList)->data, accessMode); if (fileOk) break; DBG_fprintf(stderr, " failed.\n"); g_free(validPath); } if (!fileOk) *pathList = g_list_next(*pathList); } if (fileOk) { DBG_fprintf(stderr, " OK.\n"); return validPath; } else return (gchar*)0; } /** * tool_modulo_float: * @a: a float ; * @b: an int. * * This function is just like a%b except it works with a float @a argument. * @a can be negative, but the return value of the function is always positive. * * Returns: the new float value after the modulo. */ float tool_modulo_float(float a, int b) { float fb = (float)b; while(a < fb) a += fb; while(a >= fb) a -= fb; return a; } /** * tool_path_normalize: * @path: a string, NULL terminated. * * This function normalizes the path, i.e. it removes all . and .. It should * work also on Windows. It must take an absolute path as argument, if not it is converted * assuming the current working directory. * * Returns: a newly created string. */ gchar* tool_path_normalize(const gchar* path) { #if SYSTEM_X11 == 1 #define FILE_SYSTEM_SEP "/" #endif #if SYSTEM_WIN32 == 1 #define FILE_SYSTEM_SEP "\\" #endif gchar **tokens; int i; GString *normPath; GList *lst, *tmplst; gchar *allPath, *dir; if (!path) return (gchar*)0; if (!g_path_is_absolute(path)) { dir = g_get_current_dir(); allPath = g_build_filename(dir, path, NULL); g_free(dir); } else allPath = g_strdup(path); tokens = g_strsplit(allPath, FILE_SYSTEM_SEP, -1); normPath = g_string_new(""); lst = (GList*)0; for (i = 0; tokens[i]; i++) { /* If tokens[i] == . or is empty (because of //), we ignore. */ if (!strcmp(tokens[i], ".")) continue; if (!tokens[i][0]) continue; /* If token[i] == .. then we pop one element from lst. */ if (!strcmp(tokens[i], "..")) { lst = g_list_delete_link(lst, lst); continue; } /* Token[i] is a valid chain, then we prepend it to the list. */ lst = g_list_prepend(lst, tokens[i]); } /* Write the lst to the string. */ for (tmplst = lst; tmplst; tmplst = g_list_next(tmplst)) { g_string_prepend(normPath, (gchar*)tmplst->data); g_string_prepend(normPath, FILE_SYSTEM_SEP); } g_list_free(lst); #if SYSTEM_WIN32 == 1 g_string_erase(normPath, 0,1); #endif g_strfreev(tokens); g_free(allPath); if (!normPath->str[0]) g_string_append(normPath, FILE_SYSTEM_SEP); DBG_fprintf(stderr, "Visu Tools : normalizing path, from '%s' to '%s'.\n", path, normPath->str); return g_string_free(normPath, FALSE); } #if GLIB_MINOR_VERSION < 5 /** * g_file_set_contents: * @fileName: a string ; * @str: a string ; * @len: a length or -1 ; * @error: a location for an error. * * Compiled only if Glib is lower than 2.5. * * Returns: TRUE on success. */ gboolean g_file_set_contents(const gchar *fileName, const gchar *str, gsize len _U_, GError **error _U_) { FILE *f; f = fopen(fileName, "w"); if (!f) return FALSE; if (fwrite(str, strlen(str), 1, f) != strlen(str)) return FALSE; fclose(f); return TRUE; } #endif #if GLIB_MINOR_VERSION < 27 /** * g_list_free_full: * @list: a pointer to a #GList * @free_func: the function to be called to free each element's data * * Convenience method, which frees all the memory used by a #GList, and * calls the specified destroy function on every element's data. * * Compiled only if Glib is lower than 2.27. */ void g_list_free_full (GList *list, GDestroyNotify free_func) { g_list_foreach (list, (GFunc) free_func, NULL); g_list_free (list); } #endif static gchar* tagLookup(const gchar *tag, const gchar *buffer) { char *ptTag, *ptStart, *ptEnd; ptTag = strstr(buffer, tag); if (!ptTag) return (gchar*)0; /* We check that tag was not in a commentary section. */ ptStart = g_strrstr_len(buffer, (gssize)(ptTag - buffer), ""); if (ptEnd) return ptTag; return tagLookup(tag, ptTag + strlen(tag)); } /** * tool_XML_substitute: * @output: a GString to store the substitution ; * @filename: the file to read the data from ; * @tag: the tag to substitute ; * @error: a location to store possible errors. * * Read @filename (must be XML file) and remove the @tag zone from * it. At that place, it puts the contain of @output. * * Returns: TRUE if no error occured. */ gboolean tool_XML_substitute(GString *output, const gchar *filename, const gchar *tag, GError **error) { gchar *contents, *ptStart, *ptStop; gchar *tgStart, *tgEnd; gboolean valid; /* If file does exist, we read it and replace only the tag part. */ contents = (gchar*)0; ptStart = (gchar*)0; if (g_file_test(filename, G_FILE_TEST_EXISTS)) { valid = g_file_get_contents(filename, &contents, (gsize*)0, error); if (!valid) return FALSE; tgStart = g_strdup_printf("<%s", tag); ptStart = tagLookup(tgStart, contents); if (ptStart) g_string_prepend_len(output, contents, (gssize)(ptStart - contents)); else { g_string_prepend(output, " "); ptStop = tagLookup("", contents); if (ptStop) g_string_prepend_len(output, contents, (gssize)(ptStop - contents)); else { ptStop = tagLookup("", contents); if (ptStop) g_string_prepend(output, contents); else { g_string_prepend(output, contents); g_string_prepend(output, "\n"); } } } g_free(tgStart); } else g_string_prepend(output, "\n\n "); /* If file does exist, we add the remaining parts. */ if (contents && ptStart) { tgEnd = g_strdup_printf("", tag); ptStop = tagLookup(tgEnd, ptStart); if (ptStop) g_string_append(output, ptStop + strlen(tgEnd)); else g_string_append(output, "\n"); g_free(tgEnd); } else g_string_append(output, "\n"); if (contents) g_free(contents); return TRUE; } v_sim-3.8.0/src/visu_tools.h000066400000000000000000000101371370110300500157750ustar00rootroot00000000000000/* EXTRAITS DE LA LICENCE Copyright CEA, contributeurs : Luc BILLARD et Damien CALISTE, laboratoire L_Sim, (2001-2005) Adresse mèl : BILLARD, non joignable par mèl ; CALISTE, damien P caliste AT cea P fr. Ce logiciel est un programme informatique servant à visualiser des structures atomiques dans un rendu pseudo-3D. Ce logiciel est régi par la licence CeCILL soumise au droit français et respectant les principes de diffusion des logiciels libres. Vous pouvez utiliser, modifier et/ou redistribuer ce programme sous les conditions de la licence CeCILL telle que diffusée par le CEA, le CNRS et l'INRIA sur le site "http://www.cecill.info". Le fait que vous puissiez accéder à cet en-tête signifie que vous avez pris connaissance de la licence CeCILL, et que vous en avez accepté les termes (cf. le fichier Documentation/licence.fr.txt fourni avec ce logiciel). */ /* LICENCE SUM UP Copyright CEA, contributors : Luc BILLARD et Damien CALISTE, laboratoire L_Sim, (2001-2005) E-mail address: BILLARD, not reachable any more ; CALISTE, damien P caliste AT cea P fr. This software is a computer program whose purpose is to visualize atomic configurations in 3D. This software is governed by the CeCILL license under French law and abiding by the rules of distribution of free software. You can use, modify and/ or redistribute the software under the terms of the CeCILL license as circulated by CEA, CNRS and INRIA at the following URL "http://www.cecill.info". The fact that you are presently reading this means that you have had knowledge of the CeCILL license and that you accept its terms. You can find a copy of this licence shipped with this software at Documentation/licence.en.txt. */ #ifndef VISUTOOLS_H #define VISUTOOLS_H #ifdef HAVE_CONFIG_H #include #endif #include #include #include #include "coreTools/toolDbg.h" G_BEGIN_DECLS #ifndef DEBUG #define DEBUG 0 #endif #define DBG_fprintf if(DEBUG) (void)fprintf #if DEBUG == 1 #define VisuObject ToolDbgObj #define VisuObjectClass ToolDbgObjClass #define VISU_TYPE_OBJECT TOOL_TYPE_DBG_OBJ #else #define VisuObject GObject #define VisuObjectClass GObjectClass #define VISU_TYPE_OBJECT G_TYPE_OBJECT #endif #define VISU_DECLARE_CONST(ModuleObjName, module_obj_name, MODULE, OBJ_NAME) \ static inline const ModuleObjName * MODULE##_##OBJ_NAME##_CONST (gconstpointer ptr) { \ return G_TYPE_CHECK_INSTANCE_CAST (ptr, module_obj_name##_get_type (), ModuleObjName); } \ #ifdef ENABLE_NLS # include # undef _ # define _(String) dgettext (PACKAGE, String) # ifdef gettext_noop # define N_(String) gettext_noop (String) # else # define N_(String) (String) # endif #else # define textdomain(String) (String) # define gettext(String) (String) # define dgettext(Domain,Message) (Message) # define dcgettext(Domain,Message,Type) (Message) # define bindtextdomain(Domain,Directory) (Domain) # define _(String) (String) # define N_(String) (String) #endif /** * TOOL_MAX_LINE_LENGTH * * This is the maximum number of characters read on a * line of an input file. */ #define TOOL_MAX_LINE_LENGTH 256 /** * ToolVoidDataFunc: * @data: a pointer to some user defined object. * * These methods are used when no specific argument is required except * a user-defined object and when void is the return type. */ typedef void (*ToolVoidDataFunc)(gpointer data); /** * ToolInitFunc: * * These methods are used by V_Sim to initialise some part of the * program. They are called once on start-up. */ typedef void (*ToolInitFunc)(void); gchar* tool_getValidPath(GList **pathList, const char **filenames, int accessMode); float tool_modulo_float(float a, int b); gchar* tool_path_normalize(const gchar* path); #if GLIB_MINOR_VERSION < 5 gboolean g_file_set_contents(const gchar *fileName, const gchar *str, gsize len, GError **error); #endif #if GLIB_MINOR_VERSION < 27 void g_list_free_full(GList *list, GDestroyNotify free_func); #endif gboolean tool_XML_substitute(GString *output, const gchar *filename, const gchar *tag, GError **error); G_END_DECLS #endif v_sim-3.8.0/tests/000077500000000000000000000000001370110300500137675ustar00rootroot00000000000000v_sim-3.8.0/tests/Makefile.am000066400000000000000000000000451370110300500160220ustar00rootroot00000000000000SUBDIRS = core EXTRA_DIST = exports v_sim-3.8.0/tests/core/000077500000000000000000000000001370110300500147175ustar00rootroot00000000000000v_sim-3.8.0/tests/core/Box.py000077500000000000000000000035161370110300500160310ustar00rootroot00000000000000#!/usr/bin/env python import unittest import gi gi.require_version('v_sim', '3.8') from gi.repository import GLib, v_sim import signals class TestBox(unittest.TestCase): def setUp(self): super(TestBox, self).setUp() self.addTypeEqualityFunc(float, self.fuzzyFloat) def fuzzyFloat(self, a, b, msg = None): if abs(b-a) > 6e-8: raise self.failureException(msg) def _boundary(self, bc): # Creation box = v_sim.Box.new((1., 2., 3., 4., 5., 6.), bc) self.assertEqual(box.getBoundary(), bc) box = v_sim.Box.new_full((1., 2., 3., 4., 5., 6., 7., 8., 9.), bc) self.assertEqual(box.getBoundary(), bc) # Setter box = v_sim.Box.new((1., 2., 3., 4., 5., 6.), v_sim.BoxBoundaries.FREE) with signals.Listener(box, "notify::boundary") as boundary: self.assertEqual(boundary.triggered(), 0) self.assertEqual(box.setBoundary(bc), bc != v_sim.BoxBoundaries.FREE) self.assertEqual(box.getBoundary(), bc) self.assertEqual(boundary.triggered(), 1 if bc != v_sim.BoxBoundaries.FREE else 0) box.set_property("boundary", v_sim.BoxBoundaries.FREE) self.assertEqual(box.getBoundary(), v_sim.BoxBoundaries.FREE) self.assertEqual(boundary.triggered(), 2 if bc != v_sim.BoxBoundaries.FREE else 1) def test_boundaries(self): self._boundary(v_sim.BoxBoundaries.FREE) self._boundary(v_sim.BoxBoundaries.WIRE_X) self._boundary(v_sim.BoxBoundaries.WIRE_Y) self._boundary(v_sim.BoxBoundaries.WIRE_Z) self._boundary(v_sim.BoxBoundaries.SURFACE_XY) self._boundary(v_sim.BoxBoundaries.SURFACE_YZ) self._boundary(v_sim.BoxBoundaries.SURFACE_ZX) self._boundary(v_sim.BoxBoundaries.PERIODIC) if __name__ == '__main__': unittest.main() v_sim-3.8.0/tests/core/Loader.py000077500000000000000000000503371370110300500165120ustar00rootroot00000000000000#!/usr/bin/env python import sys, os, tempfile import unittest import gi gi.require_version('v_sim', '3.8') from gi.repository import GLib, v_sim import signals class TestLoader(unittest.TestCase): def setUp(self): super(TestLoader, self).setUp() self.addTypeEqualityFunc(float, self.fuzzyFloat) def fuzzyFloat(self, a, b, msg = None): if abs(b-a) > 1e-8: raise self.failureException(msg if msg is not None else "%g != %g (d = %g)" % (a, b, abs(a-b))) def _loader(self, l, path, expectation = {}): data = v_sim.DataAtomic.new(path, l) try: ok = data.load(0, None) except: ok = False self.assertEqual(ok, expectation["success"]) if ok: for (k, v) in expectation.items(): if k.startswith("data."): #print eval(k), v self.assertEqual(eval(k), v) def _tempFile(self, string): f = tempfile.NamedTemporaryFile() f.write(string) f.flush() return f def test_ascii_file(self): self._loader(v_sim.DataLoader.ascii_getStatic(), os.path.join(os.path.dirname(sys.argv[0]), "../../examples/demo.ascii"), {"success": True, "data.getNNodes()": 172, "data.getNElements(True)": 2, "data.containsElement(v_sim.Element.retrieveFromName(\"H\")[0])": False, "data.containsElement(v_sim.Element.lookup(\"Ni\"))": True, "data.containsElement(v_sim.Element.lookup(\"Au\"))": True, "data.getBox().getUnit()": v_sim.Units.ANGSTROEM, "data.getBox().getBoundary()": v_sim.BoxBoundaries.PERIODIC, "data.getBox().getPeriodicity()": [True, True, True], }) def test_ascii_wrong_file(self): self._loader(v_sim.DataLoader.ascii_getStatic(), os.path.join(os.path.dirname(sys.argv[0]), "../../examples/demo.xyz"), {"success": False}) def test_ascii_unit_bohr(self): with self._tempFile("""test 10 0 10 0 0 10 #keyword: bohr 0 0 0 Si """) as f: self._loader(v_sim.DataLoader.ascii_getStatic(), f.name, {"success": True, "data.getBox().getUnit()": v_sim.Units.BOHR}) def test_ascii_unit_angstroem(self): with self._tempFile("""test 10 0 10 0 0 10 #keyword: Angstroem 0 0 0 Si """) as f: self._loader(v_sim.DataLoader.ascii_getStatic(), f.name, {"success": True, "data.getBox().getUnit()": v_sim.Units.ANGSTROEM}) def test_ascii_unit_undefined(self): with self._tempFile("""test 10 0 10 0 0 10 0 0 0 Si """) as f: self._loader(v_sim.DataLoader.ascii_getStatic(), f.name, {"success": True, "data.getBox().getUnit()": v_sim.Units.UNDEFINED}) def test_ascii_box_periodic(self): with self._tempFile("""test 10 0 10 0 0 10 #keyword: periodic 0 0 0 Si """) as f: self._loader(v_sim.DataLoader.ascii_getStatic(), f.name, {"success": True, "data.getBox().getBoundary()": v_sim.BoxBoundaries.PERIODIC}) with self._tempFile("""test 10 0 10 0 0 10 0 0 0 Si """) as f: self._loader(v_sim.DataLoader.ascii_getStatic(), f.name, {"success": True, "data.getBox().getBoundary()": v_sim.BoxBoundaries.PERIODIC}) def test_ascii_box_free(self): with self._tempFile("""test 10 0 10 0 0 10 #keyword: freeBC 0 0 0 Si """) as f: self._loader(v_sim.DataLoader.ascii_getStatic(), f.name, {"success": True, "data.getBox().getBoundary()": v_sim.BoxBoundaries.FREE}) def test_ascii_box_surface(self): with self._tempFile("""test 10 0 10 0 0 10 #keyword: surface 0 0 0 Si """) as f: self._loader(v_sim.DataLoader.ascii_getStatic(), f.name, {"success": True, "data.getBox().getBoundary()": v_sim.BoxBoundaries.SURFACE_ZX}) def test_ascii_box(self): with self._tempFile("""test 1 2 3 4 5 6 0 0 0 Si """) as f: self._loader(v_sim.DataLoader.ascii_getStatic(), f.name, {"success": True, "data.getBox().getGeometry(v_sim.BoxVector.DXX)": 1., "data.getBox().getGeometry(v_sim.BoxVector.DYX)": 2., "data.getBox().getGeometry(v_sim.BoxVector.DYY)": 3., "data.getBox().getGeometry(v_sim.BoxVector.DZX)": 4., "data.getBox().getGeometry(v_sim.BoxVector.DZY)": 5., "data.getBox().getGeometry(v_sim.BoxVector.DZZ)": 6.}) def test_ascii_box_angdeg(self): with self._tempFile("""test 1 2 3 90 90 90 #keyword: angdeg 0 0 0 Si """) as f: self._loader(v_sim.DataLoader.ascii_getStatic(), f.name, {"success": True, "data.getBox().getGeometry(v_sim.BoxVector.DXX)": 1., "data.getBox().getGeometry(v_sim.BoxVector.DYX)": 0., "data.getBox().getGeometry(v_sim.BoxVector.DYY)": 2., "data.getBox().getGeometry(v_sim.BoxVector.DZX)": 0., "data.getBox().getGeometry(v_sim.BoxVector.DZY)": 0., "data.getBox().getGeometry(v_sim.BoxVector.DZZ)": 3.}) def test_ascii_reduced(self): with self._tempFile("""test 1 0 2 0 0 3 #keyword: reduced 0.5 0.75 0.333333333333 Si """) as f: self._loader(v_sim.DataLoader.ascii_getStatic(), f.name, {"success": True, "data.getNodeCoordinates(data.getFromId(0), False)": (0.5, 1.5, 1.)}) def test_ascii_coord(self): with self._tempFile("""test 1 0 2 0 0 3 1 2 3 Si """) as f: self._loader(v_sim.DataLoader.ascii_getStatic(), f.name, {"success": True, "data.getNodeCoordinates(data.getFromId(0), False)": (1., 2., 3.)}) def test_ascii_coord_user(self): with self._tempFile("""test 1 0 2 0 0 3 #keyword: freeBC 1 2 3 Si """) as f: self._loader(v_sim.DataLoader.ascii_getStatic(), f.name, {"success": True, "data.getNodeCoordinates(data.getFromId(0), True)": (1., 2., 3.), "data.getNodeCoordinates(data.getFromId(0), False)": (0., 0., 0.)}) def test_ascii_props(self): with self._tempFile("""test 1 0 2 0 0 3 1 2 3 Si hello 0 0 0 C {"IGSpin": -1} """) as f: self._loader(v_sim.DataLoader.ascii_getStatic(), f.name, {"success": True, "data.getNodeLabelAt(data.getFromId(0))": "hello", "data.getNodeProperties(\"IGSpin\").getAt(data.getFromId(1))[1]": -1}) def test_ascii_energy(self): with self._tempFile("""test 1 0 2 0 0 3 #metaData: totalEnergy = 10. 1 2 3 Si # """) as f: self._loader(v_sim.DataLoader.ascii_getStatic(), f.name, {"success": True, "data.get_property(\"totalEnergy\")": 10.}) def test_ascii_energy_ht(self): with self._tempFile("""test 1 0 2 0 0 3 #metaData: totalEnergy = 1. Ht 1 2 3 Si # """) as f: self._loader(v_sim.DataLoader.ascii_getStatic(), f.name, {"success": True, "data.get_property(\"totalEnergy\")": 27.21138386}) def test_ascii_forces(self): with self._tempFile("""test 1 0 2 0 0 3 1 2 3 Si 0 0 0 Si #metaData: forces = [\ # 1, 2, 3, \ # 4, 5, 6] # """) as f: self._loader(v_sim.DataLoader.ascii_getStatic(), f.name, {"success": True, "data.getForces(False).getAt(data.getFromId(0))": [1, 2, 3], "data.getForces(False).getAt(data.getFromId(1))": [4, 5, 6]}) def test_ascii_forces_none(self): with self._tempFile("""test 1 0 2 0 0 3 1 2 3 Si 0 0 0 Si """) as f: self._loader(v_sim.DataLoader.ascii_getStatic(), f.name, {"success": True, "data.getForces(False)": None, "data.getForces(True).getAt(data.getFromId(0))": [0, 0, 0]}) def test_xyz_file(self): self._loader(v_sim.DataLoader.xyz_getStatic(), os.path.join(os.path.dirname(sys.argv[0]), "../../examples/demo.xyz"), {"success": True, "data.getNNodes()": 950, "data.getNElements(True)": 2, "data.containsElement(v_sim.Element.retrieveFromName(\"H\")[0])": False, "data.containsElement(v_sim.Element.lookup(\"Ni\"))": True, "data.containsElement(v_sim.Element.lookup(\"C\"))": True, "data.getBox().getUnit()": v_sim.Units.UNDEFINED, "data.getBox().getBoundary()": v_sim.BoxBoundaries.FREE, "data.getBox().getPeriodicity()": [False, False, False], }) def test_xyz_wrong_file(self): self._loader(v_sim.DataLoader.xyz_getStatic(), os.path.join(os.path.dirname(sys.argv[0]), "../../examples/demo.ascii"), {"success": False}) def test_xyz_unit_bohr(self): with self._tempFile("""1 bohr Si 0 0 0 """) as f: self._loader(v_sim.DataLoader.xyz_getStatic(), f.name, {"success": True, "data.getBox().getUnit()": v_sim.Units.BOHR}) def test_xyz_unit_angstroem(self): with self._tempFile("""1 angstroem Si 0 0 0 """) as f: self._loader(v_sim.DataLoader.xyz_getStatic(), f.name, {"success": True, "data.getBox().getUnit()": v_sim.Units.ANGSTROEM}) def test_xyz_unit_undefined(self): with self._tempFile("""1 Si 0 0 0 """) as f: self._loader(v_sim.DataLoader.xyz_getStatic(), f.name, {"success": True, "data.getBox().getUnit()": v_sim.Units.UNDEFINED}) def test_xyz_box_periodic(self): with self._tempFile("""1 periodic 10 10 10 # coming from a surface file Si 0 0 0 """) as f: self._loader(v_sim.DataLoader.xyz_getStatic(), f.name, {"success": True, "data.getBox().getBoundary()": v_sim.BoxBoundaries.PERIODIC}) def test_xyz_box_free(self): with self._tempFile("""1 Si 0 0 0 """) as f: self._loader(v_sim.DataLoader.xyz_getStatic(), f.name, {"success": True, "data.getBox().getBoundary()": v_sim.BoxBoundaries.FREE}) def test_xyz_box_surface(self): with self._tempFile("""1 surface 10 10 10 # coming from a periodic file Si 0 0 0 """) as f: self._loader(v_sim.DataLoader.xyz_getStatic(), f.name, {"success": True, "data.getBox().getBoundary()": v_sim.BoxBoundaries.SURFACE_ZX}) def test_xyz_box(self): with self._tempFile("""1 periodic 1 2 3 Si 0 0 0 """) as f: self._loader(v_sim.DataLoader.xyz_getStatic(), f.name, {"success": True, "data.getBox().getGeometry(v_sim.BoxVector.DXX)": 1., "data.getBox().getGeometry(v_sim.BoxVector.DYX)": 0., "data.getBox().getGeometry(v_sim.BoxVector.DYY)": 2., "data.getBox().getGeometry(v_sim.BoxVector.DZX)": 0., "data.getBox().getGeometry(v_sim.BoxVector.DZY)": 0., "data.getBox().getGeometry(v_sim.BoxVector.DZZ)": 3.}) def test_xyz_coord(self): with self._tempFile("""1 periodic 10 10 10 Si 1 2 3 """) as f: self._loader(v_sim.DataLoader.xyz_getStatic(), f.name, {"success": True, "data.getNodeCoordinates(data.getFromId(0), False)": (1., 2., 3.)}) def test_xyz_coord_user(self): with self._tempFile("""1 Si 1 2 3 """) as f: self._loader(v_sim.DataLoader.xyz_getStatic(), f.name, {"success": True, "data.getNodeCoordinates(data.getFromId(0), True)": (1., 2., 3.), "data.getNodeCoordinates(data.getFromId(0), False)": (0., 0., 0.)}) def test_xyz_props(self): with self._tempFile("""2 Si 1 2 3 hello C 0 0 0 {"IGSpin": -1} """) as f: self._loader(v_sim.DataLoader.xyz_getStatic(), f.name, {"success": True, "data.getNodeLabelAt(data.getFromId(0))": "hello", "data.getNodeProperties(\"IGSpin\").getAt(data.getFromId(1))[1]": -1}) def test_xyz_forces(self): with self._tempFile("""2 Si 1 2 3 Si 0 0 0 FoRceS Si 1 2 3 Si 4 5 6 """) as f: self._loader(v_sim.DataLoader.xyz_getStatic(), f.name, {"success": True, "data.getForces(False).getAt(data.getFromId(0))": [1, 2, 3], "data.getForces(False).getAt(data.getFromId(1))": [4, 5, 6]}) def test_xyz_forces_none(self): with self._tempFile("""2 Si 1 2 3 Si 0 0 0 """) as f: self._loader(v_sim.DataLoader.xyz_getStatic(), f.name, {"success": True, "data.getForces(False)": None, "data.getForces(True).getAt(data.getFromId(0))": [0, 0, 0]}) def test_yaml_file(self): self._loader(v_sim.DataLoader.yaml_getStatic(), os.path.join(os.path.dirname(sys.argv[0]), "../../examples/cinchonidine.yaml"), {"success": True, "data.getNNodes()": 44, "data.getNElements(True)": 4, "data.containsElement(v_sim.Element.retrieveFromName(\"Ni\")[0])": False, "data.containsElement(v_sim.Element.lookup(\"H\"))": True, "data.containsElement(v_sim.Element.lookup(\"C\"))": True, "data.containsElement(v_sim.Element.lookup(\"O\"))": True, "data.containsElement(v_sim.Element.lookup(\"N\"))": True, "data.getBox().getUnit()": v_sim.Units.BOHR, "data.getBox().getBoundary()": v_sim.BoxBoundaries.FREE, "data.getBox().getPeriodicity()": [False, False, False], }) def test_yaml_wrong_file(self): self._loader(v_sim.DataLoader.yaml_getStatic(), os.path.join(os.path.dirname(sys.argv[0]), "../../examples/demo.ascii"), {"success": False}) def test_yaml_unit_bohr(self): with self._tempFile("""positions: - H: [0., 0., 0.] """) as f: self._loader(v_sim.DataLoader.yaml_getStatic(), f.name, {"success": True, "data.getBox().getUnit()": v_sim.Units.BOHR}) with self._tempFile("""units: bohr positions: - H: [0., 0., 0.] """) as f: self._loader(v_sim.DataLoader.yaml_getStatic(), f.name, {"success": True, "data.getBox().getUnit()": v_sim.Units.BOHR}) def test_yaml_unit_angstroem(self): with self._tempFile("""units: angstroem positions: - H: [0., 0., 0.] """) as f: self._loader(v_sim.DataLoader.yaml_getStatic(), f.name, {"success": True, "data.getBox().getUnit()": v_sim.Units.ANGSTROEM}) def test_yaml_box_periodic(self): with self._tempFile("""cell: [10., 10., 10.] positions: - H: [0., 0., 0.] """) as f: self._loader(v_sim.DataLoader.yaml_getStatic(), f.name, {"success": True, "data.getBox().getBoundary()": v_sim.BoxBoundaries.PERIODIC}) def test_yaml_box_free(self): with self._tempFile("""positions: - H: [0., 0., 0.] """) as f: self._loader(v_sim.DataLoader.yaml_getStatic(), f.name, {"success": True, "data.getBox().getBoundary()": v_sim.BoxBoundaries.FREE}) with self._tempFile("""cell: [.inf, .inf, .inf] positions: - H: [0., 0., 0.] """) as f: self._loader(v_sim.DataLoader.yaml_getStatic(), f.name, {"success": True, "data.getBox().getBoundary()": v_sim.BoxBoundaries.FREE}) def test_yaml_box_surface(self): with self._tempFile("""cell: [10., .inf, 10.] positions: - H: [0., 0., 0.] """) as f: self._loader(v_sim.DataLoader.yaml_getStatic(), f.name, {"success": True, "data.getBox().getBoundary()": v_sim.BoxBoundaries.SURFACE_ZX}) def test_yaml_box(self): with self._tempFile("""cell: [1., 2., 3.] positions: - H: [0., 0., 0.] """) as f: self._loader(v_sim.DataLoader.yaml_getStatic(), f.name, {"success": True, "data.getBox().getGeometry(v_sim.BoxVector.DXX)": 1., "data.getBox().getGeometry(v_sim.BoxVector.DYX)": 0., "data.getBox().getGeometry(v_sim.BoxVector.DYY)": 2., "data.getBox().getGeometry(v_sim.BoxVector.DZX)": 0., "data.getBox().getGeometry(v_sim.BoxVector.DZY)": 0., "data.getBox().getGeometry(v_sim.BoxVector.DZZ)": 3.}) def test_yaml_coord(self): with self._tempFile("""cell: [10., 10., 10.] positions: - Si: [1., 2., 3.] """) as f: self._loader(v_sim.DataLoader.yaml_getStatic(), f.name, {"success": True, "data.getNodeCoordinates(data.getFromId(0), False)": (1., 2., 3.)}) def test_yaml_coord_user(self): with self._tempFile("""positions: - Si: [1., 2., 3.] """) as f: self._loader(v_sim.DataLoader.yaml_getStatic(), f.name, {"success": True, "data.getNodeCoordinates(data.getFromId(0), True)": (1., 2., 3.), "data.getNodeCoordinates(data.getFromId(0), False)": (0., 0., 0.)}) def test_yaml_props(self): with self._tempFile("""positions: - {Si: [1., 2., 3.]} - {C: [0., 0., 0.], IGSpin: -1} """) as f: self._loader(v_sim.DataLoader.yaml_getStatic(), f.name, {"success": True, "data.getNodeLabelAt(data.getFromId(0))": None, "data.getNodeProperties(\"IGSpin\").getAt(data.getFromId(1))[1]": -1}) def test_yaml_forces(self): with self._tempFile("""positions: - Si: [1., 2., 3.] - C: [0., 0., 0.] forces: Values: - Si: [1., 2., 3.] - C: [4., 5., 6.] """) as f: self._loader(v_sim.DataLoader.yaml_getStatic(), f.name, {"success": True, "data.getForces(False).getAt(data.getFromId(0))": [1, 2, 3], "data.getForces(False).getAt(data.getFromId(1))": [4, 5, 6]}) def test_yaml_forces_none(self): with self._tempFile("""positions: - Si: [1., 2., 3.] - C: [0., 0., 0.] """) as f: self._loader(v_sim.DataLoader.yaml_getStatic(), f.name, {"success": True, "data.getForces(False)": None, "data.getForces(True).getAt(data.getFromId(0))": [0, 0, 0]}) def test_d3_file(self): self._loader(v_sim.DataLoader.d3_getStatic(), os.path.join(os.path.dirname(sys.argv[0]), "../../examples/aluminium.d3"), {"success": True, "data.getNNodes()": 134, "data.getNElements(True)": 1, "data.containsElement(v_sim.Element.retrieveFromName(\"Ni\")[0])": False, "data.containsElement(v_sim.Element.lookup(\"Al\"))": True, "data.getBox().getUnit()": v_sim.Units.UNDEFINED, "data.getBox().getBoundary()": v_sim.BoxBoundaries.PERIODIC, "data.getBox().getGeometry(v_sim.BoxVector.DXX)": 24.72848892, "data.getBox().getGeometry(v_sim.BoxVector.DYX)": -12.36424446, "data.getBox().getGeometry(v_sim.BoxVector.DYY)": 21.41550064, "data.getBox().getGeometry(v_sim.BoxVector.DZX)": 0., "data.getBox().getGeometry(v_sim.BoxVector.DZY)": 0., "data.getBox().getGeometry(v_sim.BoxVector.DZZ)": 24. }) if __name__ == '__main__': unittest.main() v_sim-3.8.0/tests/core/Makefile.am000066400000000000000000000004361370110300500167560ustar00rootroot00000000000000if WITH_GOBJECT_INTROSPECTION PyScripts = ToolFiles.py \ NodeArray.py \ Box.py \ Loader.py else PyScripts = endif EXTRA_DIST = signals.py TESTS = $(PyScripts) AM_TESTS_ENVIRONMENT = \ LD_LIBRARY_PATH=${top_builddir}/src/.libs \ GI_TYPELIB_PATH=${top_builddir}/src \ LANG=C v_sim-3.8.0/tests/core/NodeArray.py000077500000000000000000000253711370110300500171700ustar00rootroot00000000000000#!/usr/bin/env python import unittest import gi gi.require_version('v_sim', '3.8') from gi.repository import GLib, v_sim import signals class TestNodeArray(unittest.TestCase): def setUp(self): super(TestNodeArray, self).setUp() self.addTypeEqualityFunc(list, self.fuzzyList) self.addTypeEqualityFunc(float, self.fuzzyFloat) def fuzzyList(self, a, b, msg = None): if len(a) > 0 and isinstance(a[0], float) and len(a) == len(b): try: for i, j in zip(a, b): self.fuzzyFloat(i, j, msg) except (self.failureException): raise self.failureException(msg if msg is not None else "" + "delta %s" % ([abs(i - j) for i, j in zip(a, b)])) return return self.assertListEqual(a, b, msg) def fuzzyFloat(self, a, b, msg = None): if abs(b-a) > 6e-8: raise self.failureException(msg) def test_population(self): # Empty structure. array = v_sim.Data.new() self.assertEqual(array.getNElements(True), 0) self.assertEqual(array.getNElements(False), 0) self.assertEqual(array.getNNodes(), 0) # Population allocation array.allocateByNames((1, 2, 45), ("O", "H", "g")) self.assertTrue(v_sim.Element.lookup("O") is not None) self.assertTrue(v_sim.Element.lookup("H") is not None) self.assertTrue(v_sim.Element.lookup("g") is not None) self.assertEqual(array.getNElements(True), 0) self.assertEqual(array.getNElements(False), 0) self.assertEqual(array.getNNodes(), 0) self.assertTrue(array.containsElement(v_sim.Element.lookup("O"))) self.assertTrue(array.containsElement(v_sim.Element.lookup("H"))) self.assertTrue(array.containsElement(v_sim.Element.lookup("g"))) self.assertEqual(array.getElementId(v_sim.Element.lookup("O")), 0) self.assertEqual(array.getElementId(v_sim.Element.lookup("H")), 1) self.assertEqual(array.getElementId(v_sim.Element.lookup("g")), 2) # Population partial re-allocation array.allocateByNames((1, 4), ("C", "H")) self.assertTrue(v_sim.Element.lookup("C") is not None) self.assertEqual(array.getNElements(True), 0) self.assertEqual(array.getNElements(False), 0) self.assertEqual(array.getNNodes(), 0) self.assertTrue(array.containsElement(v_sim.Element.lookup("O"))) self.assertTrue(array.containsElement(v_sim.Element.lookup("H"))) self.assertTrue(array.containsElement(v_sim.Element.lookup("g"))) self.assertTrue(array.containsElement(v_sim.Element.lookup("C"))) self.assertEqual(array.getElementId(v_sim.Element.lookup("O")), 0) self.assertEqual(array.getElementId(v_sim.Element.lookup("H")), 1) self.assertEqual(array.getElementId(v_sim.Element.lookup("g")), 2) self.assertEqual(array.getElementId(v_sim.Element.lookup("C")), 3) # Node adding node = array.getNewNode(v_sim.Element.lookup("O")) self.assertTrue(node is not None) self.assertEqual(node.xyz, [0., 0., 0.]) self.assertEqual(node.translation, [0., 0., 0.]) self.assertTrue(not node.getVisibility()) node.newValues((1,2,3)) self.assertEqual(node.number, 0) self.assertEqual(node.xyz, [1., 2., 3.]) self.assertEqual(node.translation, [0., 0., 0.]) self.assertTrue(node.getVisibility()) self.assertEqual(array.getNElements(True), 1) self.assertEqual(array.getNElements(False), 1) self.assertEqual(array.getNNodes(), 1) self.assertEqual(array.getNOriginalNodes(), 1) self.assertTrue(array.getElement(node), v_sim.Element.lookup("O")) self.assertEqual(array.getFromId(0), node) self.assertTrue(array.getFromId(1) is None) self.assertEqual(array.getOriginal(0), -1) self.assertEqual(array.get_property("n-nodes"), 1) node = array.getNewNodeForId(1) self.assertTrue(node is not None) node.newValues((2,0,0)) self.assertEqual(node.number, 1) self.assertEqual(node.xyz, [2., 0., 0.]) self.assertEqual(node.translation, [0., 0., 0.]) self.assertTrue(node.getVisibility()) self.assertEqual(array.getNElements(True), 2) self.assertEqual(array.getNElements(False), 2) self.assertEqual(array.getNNodes(), 2) self.assertEqual(array.getNOriginalNodes(), 2) self.assertTrue(array.getElement(node), v_sim.Element.lookup("H")) self.assertEqual(array.getFromId(1), node) self.assertTrue(array.getFromId(0) is not None) self.assertTrue(array.getFromId(2) is None) self.assertEqual(array.getOriginal(1), -1) node = array.copyNode(node) self.assertTrue(node is not None) node.newValues((-2,0,0)) self.assertEqual(node.number, 2) self.assertEqual(node.xyz, [-2., 0., 0.]) self.assertEqual(node.translation, [0., 0., 0.]) self.assertTrue(node.getVisibility()) self.assertEqual(array.getNElements(True), 2) self.assertEqual(array.getNElements(False), 2) self.assertEqual(array.getNNodes(), 3) self.assertEqual(array.getNOriginalNodes(), 2) self.assertTrue(array.getElement(node), v_sim.Element.lookup("H")) self.assertEqual(array.getFromId(2), node) self.assertTrue(array.getFromId(1) is not None) self.assertTrue(array.getFromId(3) is None) self.assertEqual(array.getOriginal(2), 1) self.assertTrue(array.setOriginal(2)) self.assertEqual(array.getOriginal(2), -1) self.assertEqual(array.getNOriginalNodes(), 3) # Node removal array.removeNodes((0, 1)) self.assertEqual(array.getNElements(True), 1) self.assertEqual(array.getNNodes(), 1) self.assertTrue(array.getFromId(0) is None) self.assertTrue(array.getFromId(1) is None) self.assertTrue(array.getFromId(2) is not None) node = array.copyNode(node) self.assertTrue(array.getFromId(3) is not None) array.removeAllDuplicateNodes() self.assertTrue(array.getFromId(3) is None) self.assertEqual(array.getNElements(True), 1) self.assertEqual(array.getNNodes(), 1) array.removeNodesOfElement(v_sim.Element.lookup("H")) self.assertEqual(array.getNElements(True), 0) self.assertEqual(array.getNNodes(), 0) def test_populationSignals(self): array = v_sim.Data.new() with signals.Listener(array, "notify::n-nodes") as nodes: with signals.Listener(array, "notify::elements") as elems: with signals.Listener(array, "PopulationIncrease") as popInc: with signals.Listener(array, "PopulationDecrease") as popDec: self.assertEqual(nodes.triggered(), 0) self.assertEqual(elems.triggered(), 0) self.assertEqual(popInc.triggered(), 0) self.assertEqual(popDec.triggered(), 0) array.allocateByNames((1, 4), ("C", "H")) self.assertEqual(nodes.triggered(), 0) self.assertEqual(elems.triggered(), 1) self.assertEqual(popInc.triggered(), 0) self.assertEqual(popDec.triggered(), 0) elems.reset() array.getNewNodeForId(0) self.assertEqual(nodes.triggered(), 1) self.assertEqual(elems.triggered(), 0) self.assertEqual(popInc.triggered(), 1) self.assertEqual(popDec.triggered(), 0) nodes.reset() popInc.reset() array.startAdding() array.getNewNodeForId(1) array.getNewNodeForId(1) array.getNewNodeForId(1) array.getNewNodeForId(1) self.assertEqual(nodes.triggered(), 0) self.assertEqual(popInc.triggered(), 0) self.assertEqual(popDec.triggered(), 0) array.completeAdding() self.assertEqual(nodes.triggered(), 1) self.assertEqual(popInc.triggered(), 1) self.assertEqual(popDec.triggered(), 0) nodes.reset() popInc.reset() array.removeNodes((1, 2)) self.assertEqual(nodes.triggered(), 1) self.assertEqual(popInc.triggered(), 0) self.assertEqual(popDec.triggered(), 1) array.removeNodesOfElement(v_sim.Element.lookup("C")) self.assertEqual(nodes.triggered(), 2) self.assertEqual(popInc.triggered(), 0) self.assertEqual(popDec.triggered(), 2) array.freeNodes() self.assertEqual(nodes.triggered(), 3) self.assertEqual(elems.triggered(), 1) self.assertEqual(popInc.triggered(), 0) self.assertEqual(popDec.triggered(), 2) # freeNodes() does not emit PopulationDecrease def test_nodeMovements(self): array = v_sim.Data.new() array.allocateByNames((1, 4), ("C", "H")) array.getNewNodeForId(0).newValues(( 0, 0, 0)) array.getNewNodeForId(1).newValues((-1,-1,-1)) array.getNewNodeForId(1).newValues(( 1, 1,-1)) array.getNewNodeForId(1).newValues(( 1,-1, 1)) array.getNewNodeForId(1).newValues((-1, 1, 1)) with signals.Listener(array, "position-changed") as moves: array.getFromId(0).setCoordinates((2.,2.,2.)) self.assertEqual(array.getFromId(0).xyz, [2.,2.,2.]) self.assertEqual(moves.triggered(), 0) array.moveNode(0, (0.,0.,0.)) self.assertEqual(array.getFromId(0).xyz, [0.,0.,0.]) self.assertEqual(moves.triggered(), 1) array.moveNodes((3,4), (4.,5.,6.,7.,8.,9.)) self.assertEqual(array.getFromId(3).xyz, [4.,5.,6.]) self.assertEqual(array.getFromId(4).xyz, [7.,8.,9.]) self.assertEqual(moves.triggered(), 2) moves.reset() array.shiftNode(0, (1,2,3)) self.assertEqual(array.getFromId(0).xyz, [1,2,3]) self.assertEqual(moves.triggered(), 1) array.shiftNodes((3,4), (-3.,-2.,-1.)) self.assertEqual(array.getFromId(3).xyz, [1.,3.,5.]) self.assertEqual(array.getFromId(4).xyz, [4.,6.,8.]) self.assertEqual(moves.triggered(), 2) moves.reset() array.startMoving() array.shiftNode(0, (-1,-2,-3)) array.moveNodes((3, 4), (1,-1,1,-1,1,1)) array.rotateNodes((1,2), (0,0,1), (0,0,0), 45); self.assertEqual(moves.triggered(), 0) array.completeMoving() self.assertEqual(moves.triggered(), 1) moves.reset() array.rotateNodes((1,2), (0,0,1), (0,0,0), 45); self.assertEqual(array.getFromId(1).xyz, [1.,-1.,-1.]) self.assertEqual(array.getFromId(2).xyz, [-1.,1.,-1.]) self.assertEqual(moves.triggered(), 1) if __name__ == '__main__': unittest.main() v_sim-3.8.0/tests/core/ToolFiles.py000077500000000000000000000050411370110300500171740ustar00rootroot00000000000000#!/usr/bin/env python import sys, os import unittest import gi gi.require_version('v_sim', '3.8') from gi.repository import GLib, v_sim import signals class TestToolFiles(unittest.TestCase): def ascii_text(self, path = None, string = None): f = v_sim.Files.new() if path is not None: try: f.open(path) except GLib.Error as e: if e.code != GLib.FileError.FAILED: raise return if string is not None: f.fromMemory(string) (s, l, pos) = f.read_line_string() self.assertEqual(s, GLib.IOStatus.NORMAL) self.assertEqual(l.str, "Some ASCII data.\n") (s, l, pos) = f.read_line_string() self.assertEqual(s, GLib.IOStatus.NORMAL) self.assertEqual(l.str, "\n") (s, l, pos) = f.read_line_string() self.assertEqual(s, GLib.IOStatus.EOF) self.assertEqual(l.str, '') s = f.rewind() self.assertEqual(s, GLib.IOStatus.NORMAL) (s, l, pos) = f.read_line_string() self.assertEqual(s, GLib.IOStatus.NORMAL) self.assertEqual(l.str, "Some ASCII data.\n") def test_ascii_text(self): self.ascii_text(None, """Some ASCII data. """) self.ascii_text(os.path.join(os.path.dirname(sys.argv[0]), "ascii_text")) self.ascii_text(os.path.join(os.path.dirname(sys.argv[0]), "ascii_text.bz2")) def fortran_data(self, path): f = v_sim.Files.new() try: f.fortran_open(path) except GLib.Error as e: if e.code != GLib.FileError.FAILED: raise return (ok, endian) = f.fortran_testEndianness(128) self.assertTrue(ok) self.assertEqual(endian, v_sim.FortranEndianId.KEEP) (ok, lbl) = f.fortran_readString(128, endian, False) self.assertTrue(ok) self.assertEqual(lbl, "Some title text.") ok = f.fortran_checkFlag(128, endian) self.assertTrue(ok) (ok, n) = f.fortran_readFlag(endian) self.assertTrue(ok) self.assertEqual(n, 12) (ok, nat) = f.fortran_readInteger(endian) self.assertTrue(ok) self.assertEqual(nat, 3) (ok, dbl) = f.fortran_readDouble(endian) self.assertTrue(ok) self.assertEqual(dbl, 1.) ok = f.fortran_checkFlag(n, endian) self.assertTrue(ok) (ok, rxyz) = f.fortran_readDoubleArray(9, endian, True) self.assertTrue(ok) self.assertEqual(rxyz[0:3], [1., 2., 3.]) self.assertEqual(rxyz[3:6], [7., 8., 9.]) def test_fortran_data(self): self.fortran_data(os.path.join(os.path.dirname(sys.argv[0]), "fortran_data")) self.fortran_data(os.path.join(os.path.dirname(sys.argv[0]), "fortran_data.bz2")) if __name__ == '__main__': unittest.main() v_sim-3.8.0/tests/core/ascii_text000066400000000000000000000000221370110300500167700ustar00rootroot00000000000000Some ASCII data. v_sim-3.8.0/tests/core/ascii_text.bz2000066400000000000000000000000731370110300500174720ustar00rootroot00000000000000BZh91AY&SY<6W@( & 1ȀWeo^x)„ᵰv_sim-3.8.0/tests/core/fortran_data000066400000000000000000000003541370110300500173100ustar00rootroot00000000000000Some title text. ? H?@@@ @"@ZHv_sim-3.8.0/tests/core/fortran_data.bz2000066400000000000000000000001571370110300500200050ustar00rootroot00000000000000BZh91AY&SY 0DP@&@P@TP4MM @H cXJ0f re0<F';@/|]B@24v_sim-3.8.0/tests/core/signals.py000066400000000000000000000012241370110300500167300ustar00rootroot00000000000000#!/usr/bin/env python from gi.repository import GLib class Listener(): def __init__(self, obj, signal): self.trigger = 0 self.target = obj self.signal = obj.connect(signal, self.onTrigger) def __enter__(self): return self def __exit__(self, type, value, traceback): self.target.handler_disconnect(self.signal) self.target = None def onTrigger(self, obj, args): self.trigger += 1 def triggered(self): ctx = GLib.MainContext.default() while (ctx.pending()): ctx.iteration(False) return self.trigger def reset(self): self.trigger = 0 v_sim-3.8.0/tests/exports/000077500000000000000000000000001370110300500154735ustar00rootroot00000000000000v_sim-3.8.0/tests/exports/Makefile000066400000000000000000000057331370110300500171430ustar00rootroot00000000000000PNGS = aluminium \ field \ iso \ map \ planes \ color \ links \ vibs \ vibsxyz UIS = test_reload \ test_inter SVGS = cinchonidine TESTS = $(PNGS) $(SVGS) $(UIS) SRCDIR := ../examples aluminium.args := $(SRCDIR)/aluminium.d3 -r alu.xml field.args := $(SRCDIR)/aluminium.d3 -p $(SRCDIR)/planes.xml -f $(SRCDIR)/density-sih4.dat -v 0.01:0.05 iso.args := $(SRCDIR)/test_isosurfaces.ascii -i $(SRCDIR)/test_isosurfaces.surf map.args := $(SRCDIR)/aluminium.d3 -p $(SRCDIR)/planes.xml -f $(SRCDIR)/density-sih4.dat -b 1 -n 10 -o box_show_lengths=1 planes.args := $(SRCDIR)/demo.ascii -p $(SRCDIR)/planes.xml color.args := -c $(SRCDIR)/diff.dat $(SRCDIR)/diff.ascii -o main_unit=Bohr -d 12 -x 0.05:0:0 --color-clamp 1\#1e-3:5e-2 --scaling-column 2 links.args := link.ascii -o opengl_theta_phi_omega="90 -90 0" -o "pair_link[Au Mo 4.505 4.55]"="1.000 0.000 0.000 1 1 Wire pairs" -o "pair_link[Au Mo 5.495 5.505]"="0.000 1.000 0.000 1 0 Cylinder pairs" -o "pairCylinder_linkRadius[Au Mo 5.495 5.505]"=1. -o "pairCylinder_linkColorType[Au Mo 6.495 6.505]"=1 -o "pair_link[Au Mo 6.495 6.505]"="0.000 1.000 0.000 1 0 Cylinder pairs" -o fog_is_on=0 vibs.args := $(SRCDIR)/anime.ascii --phonon-mode 3 --time-offset 0.25 --phonon-amplitude 0.2 -x 0:0:1 -o fog_start_end="0.4 0.9" vibsxyz.args := $(SRCDIR)/coord_vib_g_co.xyz --phonon-mode 42 --time-offset 0.25 --phonon-amplitude 2. test_reload.args := $(SRCDIR)/aluminium.d3 test_inter.args := $(SRCDIR)/aluminium.d3 cinchonidine.args := $(SRCDIR)/cinchonidine.yaml -o opengl_theta_phi_omega="90 50 0" -o "backgroundColor_color"="0.538 0.667 0.699 1.0" BIN = ../tmp/src/v_sim-dev IMGDIFF = python imgdiff.py OUTPUTS = $(PNGS:=.png_diff) $(PNGS:=.PNGlog) $(SVGS:=.svg_diff) $(SVGS:=.svg) $(SVGS:=.png) $(SVGS:=.log) $(UIS:=.ui_diff) $(UIS:=.UIlog) test_resources.log test_resources.diff tmp.res.xml all: $(OUTPUTS) clean: rm -f $(TESTS:=.diff*) $(OUTPUTS) $(PNGS:=.png) $(PNGS:=.win.png) $(UIS:=.win.png) .PHONY: clean .SUFFIXES: .PNGlog .png_diff .svg .svg_diff .UIlog .ui_diff #$(PNGS:=.png_diff): $(PNGS:=.PNGlog) $(SVGS:=.svg_diff): $(SVGS:=.svg) %.PNGlog: $(@:.PNGlog=) $(BIN) $($(@:.PNGlog=.args)) -e $(@:.PNGlog=.png) > $@ 2>&1 $(BIN) $($(@:.PNGlog=.args)) -o pyScript=dump.v_sim.py >> $@ 2>&1 && mv out.win.png $(@:.PNGlog=.win.png) .PNGlog.png_diff: $(IMGDIFF) $(<:.PNGlog=) $(<:.PNGlog=.ref.png) $(<:.PNGlog=.png) $(<:.PNGlog=.win.png) > $@ %.svg: $(BIN) $($(@:.svg=.args)) -e $@ > $(@:.svg=.log) 2>&1 .svg.svg_diff: convert $< -resize 600x600 $(<:.svg=.png) $(IMGDIFF) $(<:.svg=) $(<:.svg=.ref.png) $(<:.svg=.png) $(<:.svg=.flat.png) > $@ %UIlog: $(@:.UIlog=) $(BIN) $($(@:.UIlog=.args)) -o pyScript=$(@:.UIlog=).v_sim.py >> $@ 2>&1 && mv out.win.png $(@:.UIlog=.win.png) .UIlog.ui_diff: $(IMGDIFF) $(<:.UIlog=) $(<:.UIlog=.ref.png) $(<:.UIlog=.win.png) > $@ test_resources.log tmp.res.xml: test_resources.v_sim.py $(BIN) -r ./v_sim.res.xml -o pyScript=$< > $@ 2>&1 test_resources.diff: tmp.res.xml diff ref.res.xml $< > $@ @cat $@ v_sim-3.8.0/tests/exports/alu.xml000066400000000000000000000435331370110300500170060ustar00rootroot00000000000000 (0 "Medium Spring Green" , 50 Purple, 300 Pale Goldenrod, 450 #fff) 1.175 Sphere 1.430 Sphere 1.437 Sphere 1.225 Sphere 0.5 Sphere 0.600 Sphere 1.490 Sphere 1.375 Sphere 1.430 Sphere 1.250 Sphere 1.240 Sphere 1.250 Sphere 0.500 Sphere 1.243 Sphere 1.385 Sphere 0.250 Point 0.500 Point 1.000 Sphere 1.170 Sphere 1.230 Sphere 0.000000 0.000000 0.000000 never 0 0 1 1.000 0.500 0.500 0.750 0.20 1.00 0.50 0.50 0.00 0 1 1.000 0.500 0.500 0.750 0.20 1.00 0.50 0.50 0.00 0 1 1.000 0.500 0.500 0.750 0.20 1.00 0.50 0.50 0.00 0 1 1.000 0.500 0.500 0.750 0.20 1.00 0.50 0.50 0.00 0 1 1.000 0.500 0.500 0.750 0.20 1.00 0.50 0.50 0.00 0 1 1.000 0.500 0.500 0.750 0.20 1.00 0.50 0.50 0.00 0 1 1.000 0.500 0.500 0.750 0.20 1.00 0.50 0.50 0.00 0 1 1.000 0.500 0.500 0.750 0.20 1.00 0.50 0.50 0.00 0 1 1.000 0.500 0.500 0.750 0.20 1.00 0.50 0.50 0.00 0 1 1.000 0.500 0.500 0.750 0.20 1.00 0.50 0.50 0.00 0 1 1.000 0.500 0.500 0.750 0.20 1.00 0.50 0.50 0.00 0 1 1.000 0.500 0.500 0.750 0.20 1.00 0.50 0.50 0.00 0 1 1.000 0.500 0.500 0.750 0.20 1.00 0.50 0.50 0.00 0 1 1.000 0.500 0.500 0.750 0.20 1.00 0.50 0.50 0.00 0 1 1.000 0.500 0.500 0.750 0.20 1.00 0.50 0.50 0.00 0 1 1.000 0.500 0.500 0.750 0.20 1.00 0.50 0.50 0.00 0 1 1.000 0.500 0.500 0.750 0.20 1.00 0.50 0.50 0.00 0 1 1.000 0.500 0.500 0.750 0.20 1.00 0.50 0.50 0.00 0 1 1.000 0.500 0.500 0.750 0.20 1.00 0.50 0.50 0.00 0 1 1.000 0.500 0.500 0.750 0.20 1.00 0.50 0.50 0.00 1 1 1.000000 0.000000 0.000000 1 0.823 0.884 0.849 1 65535 1.000 1.000 1 0.823 0.984 0.849 2 65535 65280 0 0.500 0.000 1 2 57568 2 10 0 0.150000 1 Wire pairs 1.000 0.600 0.200 1 0 Wire pairs 1.000 0.600 0.200 1 0 Wire pairs 0.000 1.000 0.800 1 1 Wire pairs 0.750 0.400 0.200 1 0 Cylinder pairs 0.750 0.400 0.200 1 0 Cylinder pairs 1.000 0.600 0.200 1 0 Wire pairs 0.750 0.400 0.200 1 0 Wire pairs 1.000 0.600 0.200 1 0 Wire pairs 1.000 0.600 0.200 1 0 Wire pairs 1.000 0.600 0.200 1 0 Wire pairs 1.000 0.600 0.200 1 0 Wire pairs 1.000 0.600 0.200 1 0 Wire pairs 1.000 0.600 0.200 1 0 Wire pairs 1.000 0.600 0.200 1 0 Wire pairs 1.000 0.600 0.200 1 0 Wire pairs 1.000 0.600 0.200 1 0 Wire pairs 1.000 0.600 0.200 1 0 Wire pairs 0.000 1.000 0.200 1 0 Wire pairs 1.000 0.600 0.200 1 0 Wire pairs 0 0.538 0.667 0.699 0.800 1 0 0.000 0.000 0.000 0.000 0.300 0.700 1.250000 0 0.000 0.000 0.000 1.000 1 65535 0 0 0 1 0 0 5 [auto] 0 0 0 1 1 1 2 [auto] 1 -1.000000 4.000000 0.200000 0.500000 0.300000 -1.000000 -0.300000 -0.900000 3.000000 60.100 -65.600 0.000 0.50 0.50 1. 5.000 0.000 1.000 0.200 1.000 0.20 0.54 0.69 0.50 0.20 0.600 0.600 1.000 1.000 0.25 0.80 0.50 0.70 0.00 1.000 1.000 1.000 1.000 0.20 0.60 0.50 1.00 0.00 1.000 0.750 0.040 1.000 0.54 0.54 0.16 0.52 0.00 0.000 1.000 0.800 1.000 0.20 0.54 0.69 0.50 0.20 1.000 0.200 0.200 1.000 0.60 0.60 0.00 0.00 0.00 0.300 0.300 0.300 1.000 0.20 0.54 0.69 0.50 0.20 0.000 0.800 1.000 1.000 0.50 0.00 0.12 0.50 0.20 1.000 1.000 0.800 1.000 0.50 0.00 0.12 0.50 0.20 0.900 0.400 0.100 1.000 0.20 0.54 0.69 0.50 0.20 1.000 0.500 0.800 1.000 0.50 0.00 0.12 0.50 0.20 1.000 0.500 0.000 1.000 0.50 0.00 0.12 0.50 0.20 1.000 0.560 0.340 1.000 0.20 0.70 0.10 0.24 0.15 1.000 1.000 1.000 1.000 0.60 0.60 0.00 0.00 0.00 1.000 0.300 0.300 1.000 0.50 0.00 0.12 0.50 0.20 1.000 0.800 0.800 1.000 0.50 0.00 0.12 0.50 0.20 1.000 0.750 0.040 1.000 0.50 0.00 0.12 0.50 0.20 0.600 0.600 1.000 1.000 0.50 0.00 0.12 0.50 0.20 1.000 1.000 1.000 1.000 0.25 0.25 0.25 0.25 0.25 1.000 1.000 1.000 1.000 0.25 0.25 0.25 0.25 0.25 1.000 1.000 1.000 1.000 0.25 0.25 0.25 0.25 0.25 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 v_sim-3.8.0/tests/exports/aluminium-3.3.png000066400000000000000000002000241370110300500205000ustar00rootroot00000000000000PNG  IHDRXX1sBITO IDATx[sYwD&XsF3:21̋ld&;=Mo Ӄ$d#tuwu 2/XdAd"h.ȝɽݗ-߁B*z Bn !!IC!$2i(B& BȤB4BB!BH!dP !L !!IC!$2i(B& BȤB4BB!BH!dP !L !!IC!$2i(B& BȤB4BB!BH!dP !L !!IC!$2i(B& BȤB4BB!BH!dP !L !!IC!$2i(B& BȤB4BB!BH!dP !L !!IC!$2i(B& BȤB4BB!BH!dP !L !!IC!$2i(B& BȤB4BB!BH!dP !L !!IC!$2i(B& BȤB4BB!BH!dP !L !!IC!$2i(B& BȤB4BB!BH!dP !L !!IC!$2i(B& BȤB4BB!BH!dP !L !!IC!$2i(B& BȤB4BB!BH!dP !L !!IC!$2i(B& BȤB4BB!BH!dP !L !!IC!$2iIB7=B(%4;aNi$L tQ fY7wEur;N bh@Bann  ! I`PM"" I_@US(ƔN5*#!d/N,n͌BThEyNa$ )w@T]Lb 8OD͌HA(Sʈp<ATE$%TUaf#i0Bn ࣩ~EAjE餤RcȐrP;D׹PҹM6T IsBUUvG$f)kB8]."E_G1 ڨ 4mOyTB5A!0|Y:֕QAJMUi.cݢE_ p,s# } !JAJ/cf_ !p\E+XtޏBT*a0b$w33B~ q;2xH ! C=  !P;2aŮߊHA8GΦh}LF=CFBp[kBF&E P$F=L qs nomh$ Uy﹚8! Ա [ܬ26j&i !dL{ !p8>mK.bueIhimp6mv豷.CFB qMdV[immZmZKą0BF}!#!{px2bכ owuICѦ B a.vY\]B8i,zDgBiZmmg4!mB3?(κuzBv q05kqnu\.OB mI E%U1 ӊ9u;HȍA!4N-7z;c*J64Y8zح-F:BȮA!4n;똽iu6 )dTնã֭: Ic h>}+*!Hۆv)T<]:v];.JGB8i "JMy٨ʨmo V >gSCFrP $05J> f~ϗCFvy3?Ayz@z՟/y}6GB8u͑BmZ"u6|ޤxmgwj_jٯ2pX4n@Av3_.{*iu>oA 2?h JȘ6께bMB8u7ASdG;i61-3AӶ:^n_<_T+!pDsi(dO!cI98lo=BH>NSǢ }-]go?=[ܹۺyNP DDBHrf%"X>A!$1 dy)%( d ˳}j!yo8AD7 /EÛ(tP/CzGã !?Rj=GU0W>fPH }1:AAno^3;J> !2dQbevh[~ZRJPù (ˍīK̐sA&ᛁ9ۿz H^Y;1&NX}((H`DH(*<_E}16kS&nG_zGA!$5J-!\w<;BH2BT SdyNm]~d#!k,H_~͠BRo;$h!BR AA&AK_~sBnz$ VQPIQ|@f^:??VNG2s0"$9e*?<}+9A)= <|tppH̤G2F 2^<_@ӆBH2\e/,"_Nw?Yd("9sDdZht/Wy3M !ɰ}Lr" ӅԓF[O7d'7iC~l!~àpPI @;[#N_|23Q8L%!GT1/W/a1-3SBH2]o`j'&5w'[SBH2}g I>-3 @ CDafΞx&o~˥G' td<-3SS X&$ǯxby菎G23-(d!S>wo -‰) D!;׊ '"k23-x@%{NJ~ p?)A!$} 7Dj!?B8!8呁!OEwt>~z VQBg_M|7=(G# H;=ce?~ ܥql"2h!g^ B2y>,ck=S`DHhiCZf tkKHNpp#05J ?rj%;״~x@(CDŁ,rѽxN$r"_ o9BB~sD??݁BH6?(BH)n{/oVO^Nޜ?jnz\\ZӇ|{_]BH6M)ͷt]:|m'G?}`N^^\^%[!oB!$U~ @'G??~rtx_|}7Ie~ML ^SHi;VB!$?Oُߟ%yQͷS@ S">QyJ(dYnt薋ϿD18EivMhP`$u|Ҷzw̯*.x`|,BBH.a>o//:4X\$}"b(dժGX\|T\whEK(@̭BH6֝wo u Sxiqg'W,.wͯ] iProT\#Y\$ӤFABHvb >:|(ŋ_<_0J>V(dPøCb Y\,*p!@-BH6gܡ ܡT$ eVB!$\Ycq*Wp['&h}P~S[uZfnBAE@sUq1_U\||$*yORB"X)PIvF*.0K-wEW_2sk ;4(.~R,.V~_/h5PD8[bqgA>k[<7ާev@!$t]lж:N!I-:mI!P6}gm6LyR,.,w݂g8[bq !eޣ;BM#3]2{KmS,{K]7"nDe&e xӳP6riq/\Qkޞ$~~#  !fGSūJE-u ȖI!c(\[{KmZB!p|]y/Zfn BHajX\|誽X\|Oߧu B!${ݛX\R=ueS(dժ0Ibz$cTh2JɎcȽvZf !ن].-.ֽR\O;B 2;o[ŭn}qQ k7)efϡap8[bq{K]5BMㆉpRXhBHaj{KaT\||GIT}"/BM6wFo!W-uiqq_ -3{ Vqqko-.efOm.fqiqqvCCv&5 Zf !٦ B8a޿ȽefB~n-Gk}BH0㽥._<_\R"ߕh}BH.[[j*3]\[jͷuo).xFG|Zf !MM(䃸w[Ww2Zy7ϟ2GP%tm˛ kūJ۴T.-3)[jxo...,wxwi(J+!WY#'GW-uUqQ noMJC!$Э Or=xowR7:w^?ef?K؍tybzi#(NL\e[}[Zf4rP%p'&;4fXeQeۿ@!q(BHvfggbFԸ zdei.8/PɥJHQ𑢥U{K],.^R2C!e(2]dyj-2w`.C!$wGPNX[c¨X|,Br ] d^ԥź/(.2P !{ǫeo-U\[ꃊ>Br >pMO\Z\-u쇳wth2P%4ː@߻Fyb[jH̎C!$W B.'R2Br w @JVq-uUq&JBH.QB~*.>z|"-\>Ku8 ?)?F_ssoݷ_E(*'l#LF.14r \kۛ !nmmM}g3tI)ay2mU[4e߱ڮ Nv /Ԯ4ˆo/ǮnM2p 77| _z3WgNˆ\N{ (d#O_A0 0N$'N?$pә`=G+XyowEۙ;![0"$RF]v;<$|4!!MQa~~x֛)*ѕACm.钭~(%p̚/+>Z;z?@92!CB>"3/65oqSQ//)Gu[Y\}R(ވ_[Ǯ}4qpw[ ˆ|?q*4Y 8v>cpV߃,jFH:*_~m,*?#zV|g'!|X>,A> Br9}D3qjb.'=P%dzZփ]6 ,FݘmFe܍U|~Ic'ۉ& > ȃHn!3T, ^|\糊T~P*~ xW7=#]BH6)Ɠ*:0\Y!̋%,7,2x=C)j uA EƏ, --yդoS7^Ѭ,i3ͳ BRWKpK IDAT|\4z^nZKn^/Wn?ۗP}C}_TapalpQ+.$)CFկ/ k@RMլw"P7D~I 7L/i,ŰA-&yUªdw"u QnXh.ޥOwfφ0w4"zRk>L%܉Wݭ;V"2 X&ate(d Ivmۦ)2TIWIQIKVsQs.Z=Ek0Ps`]̩BI*YW^N,2$|$%KNQHzQ(Iyp|g*S.pI0Fk}7E ]/DEO2{#]BH(q4yIʄ<‡ne9(2Lv%EaVY7Smng D]KLP.mIJNo+7n3g6>_mju ٘ҡ!{ǶjyZvpI Q57z>f208D^ 5pRGH̡\bZV > ea@2x^ã+|r7ShU\A:Jyg-SRw !ox.Fvaxb k[mCߤqpzzi⳧,dL|bU}W,VHc*6&{VU1K-KȰ3yUm/oVw*-L2?t^¦Mze†ɇ׺aFE*Z<٦F"L]niFWQ4c. ^ 0Y[%F6lKmO4E||7eG5y(QpE)4KM"CŻlDw/QI|aR,?z6VSӜ;۴AMJj!!]{jn^>s-c颾i߫nBPYmu} yuJ/ޓ" A $Dz5dCG!Pс J\.VVnEVƴ#SH~ǢRA4XLCrmeˁ|%ohy4HexNsP/ fy5B̀; FI!h*&DDz!2AW9G@Ӏ06GxN$Eu$HY) w !٤Lb]oA7į ,w-E5DR0sjȡ_fu:9T\ˇ].{#%7^U%hHs@: w-ʸECצҬ-iudi@At/ WsD^h o*AsW;N:OF`ݪKEБf#/a5 %R׃zϑ8nfOvGKX]3hء]FwnFPjFe%6NRmzc#p´Fq)IZGL; .NNkQP̪Yy^ӁDՓѻ[3g\}T?y< }(GWu&mR&@}fN2#JJnk˦r(27zDӉP+X l$ED@Į#uhqh!ۤyS,-J0O":Lj ьPB\zE~wF;lKYE<-m&j!}6#X1G" a.bg*_'n+d%jRA-!흰x{.}"[8\]X ɺ`#$HcQ@c!0Ɵ3rJmFº;R= ox(%gCGZ4A楸+VQƃ,BIɊ>dP V\AĦV;4bapǡm|ح{,]X4 x,"$FxZM Y+d-VJ$[Pd.ko&G,G c~;z)Q+r:4ݲ0fUKCIYn07 hp\qG\qCGIcJ(aIGX<&TP 4kdT"hд8%!iX-λ>>(`F?QC -G5^ % iEjejANbî'(6$^ZO *j08b$b;,Z9ZY -grsWONN Tzl[mnTlIf S"ׂH҈D.nnuW(`bRpyEO{#ۅA q5Aˏ>tT욗Ljv4Jr6?pW~B}QRPŵiVtqã}ϣԮX-4a}ڢ MW܌pNK%JuMEUmTl*P{ <u|Z0Lv;r*H9P@E\sq@˿Isw 1JDDird6 Mma7w ᤩn] Xs-YTꝃdzp=:Lnq$5b;P̬-Fbfo$%a Qu{fcȣrþ pF,U 񠂳Wj~gl Q#hf1M:P ͨL(S[j\SJ =ר"AD>Ve}֛eP֑)&%}#a'\z$^QS*h[0ˬMB }(d(jS<%W)@'ilgˏBjaWͷBƢ(ϙEV~4-Fh]ciru~dǑ+ir8{żل:Nչ;I0h}"Q-UgV"!˳\P2҅SѠd-UY_PU"nf-NF=?|b$'gK@oƛm+yާpstWaDPKh1\Y#Cj mfhP }AUGAaTߕfi"k̻.?*Ul5Eg?ӶIwa7}w-h^)#b{ǏsdR3ݝgVkqm>ϼ^(ݳqjWI>ZyיE/deX-)DL1[ji׋( Рi yՅ3預5݇f v28^Ex_}ژ!Mml&m!Hyg{ٗgKW:  z ڤ6j)u|{n})7iM6ʭurA߫;Rﶙ(ٷ<ι$M%I?|if-D%w=!O,\ [k:TM\a51@D!>@4Rroy^1(:JUΛA@U4AT/o?c1OξMZiڠj4՜ Z-#z(2ВX+Q>Z&@ᰈЈu9w SR"|ϊ }msJri|J;e4UJ|`am^I$oaG$K@j*&J-1.bb.nbIkvH3Ei#3/^\'EJEJ`6K1H0}-Қۣu'ٖ%vg0YCQ(3+b٢p.ecuM]^.t X= aiRQD8bNݚ,ӊ>HiWEv:!ZbD4:q ݃ؾ7'C!0eA/l8#y6LuJ<}KmLVfLNr4$[M7ڪ70h^Or//~ IIr0i[!s3:kLnp8 `zBRjrhAJڒP£mN5rK2qO;eo) %ǟz,EΖ)91il Aa% ɛfecEae͋(~C8w36@DE5hNk1ү<4iGapapԘJw `Tt˙ UC+ 'd8/}E}Ȑ+BwdXMmTa#c`zLNnκbſ>PJh%y&ȋy .b"EB^KEܑhpt<+,r gO>5y#_˂zEфg*4 ʻ$o߼. <8卿mynptbZm{vE}(ET]\L4}%/d{zQ@1dnLt! SBJ Q;_e2Ǹyl8Z[,hf1ZY#`rw7j2zby$dfѬvYqQeՊYE /n: D\ }狷g%DiHDa&x /$׋I5절l9TG=M'=x IDAT6V ̢'lRC}o1Z4^[jH[v Fpl44OHK{yx\˷g@Q؅ &&dȃ_CFz Eb1$[1}쇿?ț98ukF@y9ʢ'ٌ*/flq@]Q)Cr8_Bfn^?rcO$h~!_|2-3G!~h27[P,P/Aypb9Oﷸ^zm]W#!AX#}X#4"({ rO9zݷдگc*T ѤƼh=>4ןTMx'7ggIulyp7gd4'WKݖ| 8L!({8R^\ɾǘ`1Pubx1 QKI*`Q{ד;0PZv(E`0;h|c3:1wP1sh~~ϖ=;?ӹ9T–33uGoT>j (T$"ǵš)#]LŻ 7#}(S'c8Gu[7Yk*!ث$J~=fԀ :|dF~oN^{*[U m8VmC;۩_ wCP}p:Jfb˯.5 *kKs1]6O{['eJiKZs/]?"8U X !HfQe6NHi7gs9#`F),dMqyl&4HЀ 7ADUC|7saA݁>ISr5hfݥ3!y)\;>O{9xq_8D3iVuPGek0VuҍJ"3#fekg-Ba\!.1YRE`MuN'RRxY}[^}ԘXb=wGсGepAD\sHUڰR$ИHLuZbz}xf>WZOλBkߍhZoAFPX7<:R`_- 43 8OETEUQB bIȇC!4kp_{L͢*]#MZx&*i8Hm8XdDMmE^gCRڽoE>~ taԘ!*rW~sI![n7qOp ;kr2IH.݀> QI< H fDh:>Z^u*ފUd(o8**\dUEYEMZXK\Vi>I5:=MӢmRGFT[viM3/ԺƇ }wvS^@!:,NI {uV=mfb4rlBhr/HkӵB?Hm$HŠɒD 4^UU4xఘfy{ɫI`9HmŔbU,D"_~WSX5j4yU\nxڿ>ev]D' }`YdTGM)-i_R0Sok$:AWVPfV2R$-1iDi,ޞ lUMWuJyᄢ3>B40A?(=o<[oC9]Z{T;K<놛©svr6yzh $~yݐxHPMp8NjSZ.D3h8UI%D*A^kӸϨvEY/lq@Z[҃WF>y334R-`)m)#u*N/S78^IR h=ml')\wL_2"PnziDi`inMiԇx ?;);}\ Qk1 g˓?欬^Jrp3䄯VnSs%\TexuYG}jp,%2A@Q[Et籝~脩 m@dB4K^-m)4 坒(XyŃcj1Vc! ehɏ&<,{f.1@vP DP'2Yz5tVY͚!*I]4 *Gtd"UKJ5'!zf]iNߡΓVJUGR 2{huI9 \.%Y/ԴT[FT 3j [{ D募~B4(P=V9{ rQܝg}9!޾~4M3K{BOt-Ei{oO=h1I0#d2`GTփzt Eq&1#ILݸ}ﭪskerw528UUj/?ULDceDB8^<}29V:>U*UlND,Fl,@N)hy?RuU8f\;Z)%V)6mVI,PVP ׷)?yY!bx \adL @^z^V o&S65PDb@Y}iQמ9}z$ƁfwѬmn,G&|ނ_2)٘U$Aw$N,Nrx3gYk_]gÊb@ 83r6 ᅈ̏v4?nnF˟#PzE5PVcf~w*vg +Zst%gGtUć'sgș_JETNE:zV .Br ˙Kn>gfM[(2(vn;nZc_d~Cv^ Z.d~ٍu?`~2(4fN/R@}?Ȼ*[Qœ,܊j?'2u5e:'Śd^\uZ:=2o6= G:H`ήY_AS1b°)B8B^VZTr %-,"W'5ɜ}G!Պ)U~C rEu>+R&bjdtמ[ 7l[||`IF0R:؀Ph34m@;#Dxq35U0}rx2Y4-`DܧbY: o Dl.*= {ٿRH"tb@ ebIBCo~(0 G:eں_*kt3HeeA =+{p *~x쑟^f"9(NyTҳF@4$L?[TWV?g-3:Zd^fP2%! r]Ty@4s6ʘQmZ4W@]é`ācĺTg3QfXKܶci`QP~PAMBc-jrؾjPO ,Sj5oIuiLy,F/ߴ0̙5Z=i>DE4e'}Sp7}Ex!b ?2TaJR,L|{[ߤR{go^2:>/4We҇KjN!sI|FB(HHV"YɦQ8, RE,rM(M|7LxVɬ*d]6 !D:\!qb9#-d wy~lyTt-,aZ0pp@u!9RjlҘe2g} CȇA| ~KşcQ!wΚ6 F椪t#FQə9 ,\` mB0RyeF2lmt]WDw T8[̰Mӟnl??U3+,>ܜ9[J`8[kϹ*֡m93A&볧ȌȠ1vX$8Osrո؞m|0ķ%S"u(Zva{r֞2S07ZFP% ]g]Cϫ & 5^c“XS)sWL1˷E9GoӋ~6 BEd0@94LI(%![۳F/D>x,OvtR"֨"&&Ow:(j)͇ٝm9DE 2ټ҈)v@d g^$RmSH('B$jY7% 6v7ET虦sffPMJLSPjQt$`]:1^|Ef%#R9xYC(0>ė9ٞnje̹",Zxhm:h! paeNxۮ[Ÿ*LkxH@!\('\8íflƬZ` f/8_$}Ex!bHǬk堕 @?B+a+Q*9gYIќiAA0<3Xs~fw1s'VЊN$hZHvtTDDƝ;͹55i;pfiyf(dVV5&V1-NE1#Fι$ ~5lN-~ܬ"e.{ j91Oxim tG3:hI_%PUMIBbo#g?<.Nj.kx1+EBἢs,Sλv3?/Dt^94T"v3YF}*dqqi48JJ6%TtA9""s "Eh2b~М_jZ/im#~a \rvn'9WY&x?f-5RB@,JL5rZ:j83,ty:ʁ״<в; &ʜ5u͙(w),Y$g&G53@<.Ӎ-ڡvو03#h+x/n0fiEv[tVf*~ᅈ=4h*rm<hTYDr&pV-Jk` |BQ@F(нnoO?qte9.aȜ RRE٭KD<9 c <k eZȹ,x/߽B(Rx IlLFF0&3_ew&JR*U6G-M:3IaT^(8 IL׾r7/]CTkŤNTU#hT ,foVO_GI"MwI s"N)!'A`m+"PUc*jdc"&f;[1^Qg&]껃{>p/1pG̜ g$#(ON+N]W('G+YO!X,' )bX>%#GPbeu9CѨ)h1 4pPƪbL5(|^uRᎂԱJZ}T԰`_*?Uw h 7 (fS; (!;YEs_eBs \G@qۏyڗjэ0\(Cdj gzH AfoU>"BX,^06.++bjG`M"beR^O}5z/D6v] 8ѪkC"#(O'd;K1 E:UU!.v ̻t9Z=?*tPs5i-&v;!F( _ ^2jd؇a{dVC0} ]aZFFs׏' kS;ldJ"L*?/0w!tuR!UքD z׾Ji26}DB_ERC0qi˲n'Nn.c>kZY¬\#! F3`> ѸtݺX{u)䧺9!/8A8wnq[Ş2zQa۴|^9WB=c_Ʒr`99FC꺿uTa hߠQ'@$Yr2M-g#DEX}P%8^CzyY4G$2՛~V{KjI` p'^<ԊXAU_ܗHE%>J^>Au4tti=\mgl,b@vyVipBXE)XWfQ_(r @'B1ng)|XmqQ<w"s`b5ݦlUc: +h}GiɁP{OW S姾EsJJ>ŗyWs/<@qMYhly3+K@y&mDLJ؀>?*pH1c"9̢JvNδ۱*h<6%3Ef a4qKgNR=X? \'}Tz|{rXwg׭\ƲyR(KGwt>o{u…Z`=>W}tr`μsMʘ&LjiX)".EbB(vs CDZK'3Z^,_8B].RÇy]#Qݛ _SNܺ9';^w7_wQ3grj* ZY7%f02"rf@02.̧& Ua e**$ُsGV%U5#fKrJUjE_!VPl\O 1nW?\/J}G8mn嗹VUrhQI+/~UeZ T򨚙[ە IDAT,_Ӥ)N6&76UљhӉX#sd LeZjVdcpnhݔJq> 31KX{kkBC8$77gd֥C o<@wXTLǃCX ]ŨE^Ac)澻Ǯ#Y5hlH24U(*)Iy7f%wk!6F ^6;5\Vk}G՟"=‹p/"hL.ʟtK뺍351J.0'?kپn?j&bbqRN,g햳!8qwV`C.E{9,sC(F  Suᚅ F>yo%(  gZ)E2.aסD!ٔH; _2?:;|ṯfRSêuC^Fw8Į3f*[D̼#+D"7r1 9`u%v-TM$ e+͌~ 3T!B4b?ľ"7vK(.k=c ++txC"҂bERRyd嶔!*Ҫ,yͦvcz䱷{tvL2UgVȄXf3 PSU'd͗]5w?asBʠbVJd#K%v}8i7o0|{BTLK @u|wJ́b}xەGnGdTs[\_XZkErι=qjoj }[s+p&#vpXXn) E}"wg-sR?TU9{[Gtta@Do}?DA˱t1VTZsZWqVQr:]>vl,hgY]Qz~L]GrU߬IPELTd)YJX\rKXxG{/>p[.=|GݗVׯ=WUپ=Jb4=ؽIC)@B)?{XCH yVm^R mS"YjopΓuU4[yIYJNVӏOT8D %c6gf2D} I-znC)ecH"C'b9̔"Ȃg*WםV u.@],~jBޙ*3#0` `sz0t `s S;<ʽ5Q*?*e&ss[lQjB 6B rLN0Dͦu?bo'8J%RRac1 YZJa~ߦm~g^'}|,ʹ`u5,2 fq0Q-f!% TԺ7վ˂`dnҌdU7#>OKׯ\E;Yx|nW~ A ɂC Zmh|0p<ڻo;|KPS20CB fY Rtј93z_ #.BDvǝͯt!b*L߂ aD7|ׁ]Wи$ZB,k/Lald?ARVRQj4 &N=mAT#:](1U5BS?G?Q CZ1>a(P3|1og) ~[EDSEeE9uVE@{ ]@2̪h|p@nGu"im2UsAM5&̔"*$gUTs%Z?Ȓ$'RdLjfӤ9;%KE}EsD"R@%+JWY)qJ "uiRǽ\Fu`@!u[Ű [Āl3Sf6\ń?`e:77,Raa׃N .0#g{M_FFT9A?aEgT30(fDA/3DCo_}Hci$BiQcrryZphΏԑ^'VԍTSC5 ή:f`z(F-O?TId|6cVݕ 1 !cs87r`#YQM0 s,ǁE'9Sh1MEM(`ӿFxQbq>>$Umw!rm3)R)R"*Bf,9x[83u̡4J16,^qOR`?O?i9Ԕ n"0yd"B[{5I}# ^>]QbL*5T6[k?pa#7?Nab\},$cTU.3B`Od>̓M*wLMHF#-mlЌg^'}|(\5q<ffUVarV v`F)Sv,ʅO1*;55/fĒ|{o~R( (B RvEL]OilJֈf0u(PE҉,[,0Zc)yo*]O~OPf:YX?\blރ "Fc@ _h&&zK)VewT;?"iڍbD}?b?.ǹX\ѸQѬ".{$s|v&M>=UnY&1 <ZEY,EDV^R]xQNA2HrCst%sleiU~ҧ}*2s"Z['.vtHt|tk.OR. LE sb]8(i5B & ueu~֒d)eﶺݪ EԴ"ڝ̌mTd}^$BhH?_:\|\t4ubKNJR͢H&%gI5k~bO@q.YWlt%*dQV,\`f4Q  ThED4G9?-,1C/k:<)nhI+:7_z]j:)2kJ+]Q%" `U{_u3V3Zx`>*FV]E(e4<軾؞nEu*Z:D!\9ݾmLg:~_A&jD5FQJ!%n*jǜuL.Ʃz,nSbsBCb5_/3ȯ f*8NHZISg&y]*^'}̛>jZ%# .pE"At!Xr=IG,geu؇8fS!_PRq6UiE͗^uĸ 1Gg01?1*kVIhوK5TU9Sj3saJ9e7R1u4уw?o|kY7nf5t$qΫfxDܾd,[r*41C akf}D8kZ1[%U lΆ)9;֪Ј$E(qn<w!!1t\z93 2j^2>ۂPD@$3)!PMKrs-t.' \s]:mθݎXtסY#|ͤ g߸|ju!Pc̜F ,WGYBD@V먙)8*=f9LR >{eנC3}Z1spR$iSvG+{ 3bS-2Uc!M.y+EU2)K2v08*Vt1(pc092AWה2b$5&o鯵EJcwo[".X><Ͻ[^&]{(p/'mKêvCRn?&QȲی/6`JME9~#6V#R]UuF)348Pԩ<| '7(|Zs"#eĦ[hws]}CNA)44)Q{Uqq6Qv [ Tzf{OuݚSMTBgY gAw[s=̎Ug@kߊyU].pldcΖۥ|CŐEލI!0XSRDN)\b2Ս)T1x]?g^a(}<^okJ5].adzuz}%U s  cwr-rUSccʻF4s4):f)uQN))l5x0MVW{Q_#k 'g[ڱ{ٌ!s)RnuVw;qitS?&>kU`<ϻR-aW;z15Ӳ ;{91UVh]zjl˫W]\0tq:Uׇ]=}viQFScxSھ7 B'UHJ)OI[-2nqBscPӳ7o; M-t=I::1B;sL2X*:sj/n'ӔSʛm>=q4Q3*Q蹧;=HeVeI$f&p+x̓`M%r=SZ "] UyF2W||jR2;.vAhUe4f#ۭ X~ 藰P4iF{$^#0- ߫a{(p!ZQX{T *7* 11z7ʤ4`j. U\mƝ;ٍ6*eY..8hG0/Λ#1/N6Aɷ 5? Rl^2ۥ|zǝDzO%MUqW"[גv:Ṑ舸VG\,X&,`0nvyGo~L`ZbC{Oz! vy޲bZdI9iiY7nUĦXs[@ݓT#nx%)[.ܳF/P>sgmMٰjjQA81Qf*f%iڠ,)J)yuӼ8*TM4oX^y7NNO}+>u}Yy8zeXOpua˽b7k_9WG~vxeCyoyȞLٖCfM v,V<#Oy]nrH: aH{"U^x&a(}|ov @7ĶL6k;:C1ɩ 2=ʙ1Z&dN_?8u] &!FWa8fS;_$on[\-}&GEK *)4a1Rי;URLzK/"gT~A[o 3`]wR7 /^JEj"E+5U r6 IDAT5je}1/q""v*uHoZ]V-C"LB#6bUee,r)Wʆl6$eJӀw?EՓɍo"p_j"$E/Af!uɝw ܇?>~wMHmuh 0S?GG|._0PT:KEQ۰-55ٜif"6-89W]tuw EtITDRԛkWt,DLjYUeL,F=W8ΞxdqAcÿH0m3 [cFMۤdx9^je:p(H#~iZ^qa1l19P}tpWJ[A]UEQdA< mduٸ,tQjR5fn4* )ڷ"K jb*ltqӔNO^Ʀ9G-KW>=E+>sTJ0n' hfɠfJt Y'H]) 2 TLAg{}9k6 t|lNnyw}{/2KP Tun6@r&zVZHRyC"J"aJ+W|8qD '8e{j |$գA$0ٵ]ޜv!w{P$B@ !>Q&,"87VρDZF:͢AA4NGXBcjElhJFD} J"PX#VekbT@f>QW&2+p5|yX]3fLmjNq 3^?uV66p%oάXP/]ءG} }+mHQe 8O۾aЁ<}Q^  m%Oq*CD>=m6R = mHZU$ fG`quo\tΆ 6جP:+d0S̜Uæ9UkGHEͲǝ67Ϙ"4EɋV}`m,GGt } Fi`05qKVTs!Nc{fݍDȅw%~ξ"XOQRێO.HOͦ8YcN[/SR'H:qV0Ж9i.J|td@N]FFDnqOU43nwzL CCp@̰^*E7~, QvFOBډ@HDldeUcN-%YdLDVd8S22j]U}NoF>Jnh氠dicZo-\r*ʋXB؍n4U@yVbfu Pi5Z!0 䄔 _xﯾiEJٙ@C7nE׳QuCV]4F#b+>i#XGU)꒫m6՛UUR05铓^"*?WZn14ZrQwQq0u: bD;Q @5޼G ܅B֏\eP1'}]:h}Udy34 y8qggzєAnWA?xc\o^ gl"?puk)牊 "k#٪J I)O<'7Mo$w 1oZ&p*7BjeyQu{*e+NoF]sǮT6ޛےVuk2p[u((A@( ANhtO۶_tlv}OTĉ(J*"@{Cf~kx˽- oMcqjsɝKrW 4cY "C,mҖ sug17fAq?mJmK b|A`mKSz@Mj9w?.SM"8jA^-EЂ@ɪC΃|rONDNSg0r ͭt#ϦR-2 <pqqifF`Wl!gN9}D{{=*³.>C<񖧽s 6ezY`%Joo@%9s `/^Mq4.怨F$D*%,1dJm ,Lc.Ť'WC,}K*32H"3q} `^pP,h&s2 H]"N2E\BRmL~(iZe_#^Oupn`& U FHMȚm48kn)33p{DǡQL#0itP*w9jf}%O43/-|298 46f[7s*=\h*CEHQrBrr"]Wz Y/:_-c)T`CPMj3"7z*[]zTa*YC>ˠ2 }^0䜇u'uDӽ &UV7J=SG6xx92pѽXĮ""zEn#5S T )1'w%b#(sY,@<{h-pBQ2r!'H (dQԜSH@'ș. >|nGGKX j#gĭ mkYO'K&"C#IC~. F`u1PcΎӇ,G't [eͭgx^sLzdM7[_L)1`-g:^ r"8ׁ.aNm>ǃt[{4'6WUg#v.0(ǣ"lȿ8ɨx}.W˿|"Q;P:UC[ݠ n<I>9*w ,,2rŠ?Tin6ւ#8rܛ,1p¶I MH<#o,l\̓ ϝ)q11fN׉h&*1yd9X`u fA d낄Mm30 ZAe-ew i53!fu_}sDP37KXE+Uu| OqRj}"<\= ڹUe X-'AYcȘs֑ņWqK;j*!*U +i 2fP.n&۰2Q<8 XٌC;X, J1ihny8%jf#Fg+&CLםpGٹ ǷPJ'm}W U,"ȡN)%(DjwWo|׽?ҭ;wQ{:N n:Qr U9/yUM qf!a֛uZabg66S3-3$*qL}K'L6b7)a?2*нݙ%]|x-7/CUuy[1>^%&6D%2Ʌ?'LM3=(T1W09Z~_kQ\G_,œUu8bbDL՘mpX^ݺs󶝄6cOyAg#nO.bl-<"`pT7;O5CfY %ULܬxN-xB2#s ܭd 'SC Ħqw:%,a?(U5w~o` ܶ6ʹi&)Mq"N3GWVaZASQ DzdH¤!xnl}%RФ7895{!\.x-Oc.׋rxO -B!`&ODv[@VTl~dW(e6rswlfPMn uf"VUf.*YJqfw!NlݙF­6,?+%+icSz+Ȉ8`|Sw$FeeS% B}"CT V+6hwBKmo`)i =fAbIt}$Mm:npT$E_o~f֋dM]?!l ( ]U04/a(9l ݪ$4d; {;ZdevѳD=\`:/(ldARW3@P lFm)@o~MU7xX?\^<8%`iJ>% ]˔XuԻ[h;z Q: *6 ( :NRa&UraHu@Z`l "u=Ms-tC8:Wk _Dlw3tӇcTam|{PfJ#"1wŶ%ai[y3|*pW ijAR2;NhԯЯ)O0k%bfDsuv:%_f  xؾИ$3tuG5w$!tp",%'B%3#2I@c?8?A.SDh[(a6C$rlyfM3mi s UU5]_tC]vqE 00v7M}e7xq){ݼ!J<zb/:J2~[?,td{+@ٕr ֍\s %zS࣪yKƊuGd6@ՎR+ r:twh(SLFbUU" g3k'mbT)/OOfr"QG!掸D /vPg.v.(Tˌpq__Qg+M{SvlSֶ{‹o|ˉ)$g/{?6 |a6jP}}NrWE{>CDc$tIssOV+YaW|bV+BS]aX=c-[vh'ރDa37h|èb@XEϥ_/~sA3 6nUf]5Vu(kkVTsQ+YC%uTi`2 H/;./%Dtas95AawءF\*]\QO{,;Cˍڂ+ߘs͌E[8OA&SO-pu0ݚE*Jq(Z\%i=,2:+'2&Jj8jNrTIḁ1CQHX+ 0@hpGi .  @Rs0p#bBɂHxt` @':? j8xppmԴӶkYL4mi&&LGĉV'1A0xQ A@LԨfՆ(6ն6Q X|r-TMS`sVƍB$9(;33D+ S/G<1o7JFvAprΧq& x-;Tձ%3p{#{s@) Q3bhs5OlIY#ikf ]uz(2qـSJ1P\]<!` c.Oa T--,EA^76_X"Dٹ6c"N )1%N-31sS>`o}K90 0WTb*2D $*ͦ4 ^{u8IEg:6\BX,x:,* wOd;33D+ Qs;KmbTV\Xvdq" r"6u ֪LU%J[r}=w&ʮDu҇9"HbJLXם^Sr8n'4_4D̢ydO".\tBx t7a"yGnx"z!X{s?:&cPjY;T_fGb Mhۛ>V;}z=k]/ki@%@i@ȡP7$J;3hr;TnVƵ\^ùspgMl_IYbgFxbwqEpg=)w:YDd6$l{ԁCnA cY2=+~?Z3`CD7qDL/mG]C$/10qoL =o~OHTўr6L~%L&u< ݠ({GtEJ3&?FLPe1BAl :cnCȇV9SJ( yLX#yOPm |P0X7ocUS;<*.pqZ4pnGÌpg+vpWw>{Z닻+>՘ #5u4s׏[P"Mb.ni{/T=쉩d( Ȑ8yjDĉq2CqUw)ΩEe,LMP+4*)sp#7`shN sΘ9w@熂̇fI&L H01l> s\B }_}x׿ψX@F廑Î.r .:<< 8#feD*̔T!-ѢkfF 7>URh릁!S}׬ʉ0#!eV.(.yb0if D"g7s| @`ɗVͻ(j R~F&xalhv^biqJ}?6elL-\@͉Q bH{6,CL2Ky GЪ^3D *%s{==mSr[B LTnչ"mjRI~Rk@tDƯcZ6P6d<C XRwB8 ڱ` 3^/y_i"nX6]\TP0%l690dtǝ8[wqeqk+ʪ\wk'R C ]# fG4D)_0JslᦧŌ/ycBR,ZpjCͨ >D-~/9x}^ fH/9+]?,|b&4~HHT0` ^I|nS;=UDoZL48\ }戄XpIܐ6::47Gٜ bhL! tyap!_̫UX`Ȁ;U"J0sU)ո B"mo󹥤M[8 pwc+v2g1vpWv:S&ȃdm[կQTJS˷2ަq6xfZrJ_[/V$$"@7p-d D'*q`dDP-iu$V9!2b]u뜻_"yҤ)REj5dr>w]^-Tzzjm }ul2z*i:C '#(_ sɅ&0fCz}U4~L&V6Z?e*\ :Vj6 p1Ө`%”T5m mY9%ʜصFwqePDp31`U&OPψԜ@7jL$%nfhHHj`D|dgKp؍E_{TJ|6\Ҥ3^4$ R5!kf5Sc,F預Q5`9@]}{FkC$D/XN"DzᗿurpQJ@r4G|nxx|R *fpZ]Cɴif R$nOS5MR|Da nq[34BEDՆYf(Zvq&Tն嶅†~9eNNV,Ʈ"7S (JQ1+BbeTDCSK-(:Hrs'^w'U[} 4QlME-DbyX.马V2dQc~?Bƒ1&3 }Tw}Ӿn,q=jـX!b.C@sj#ts:U!/O- "iwQE&RkʣS].9' y.*+@ cbFADHlqTzvL0~AB·J/2\~:9dn a'Ν?<>]X)4s,_^1o΢yz[NNDNN$g7X"U%NV,Ʈ"EbPD<9O7+ bZ$317B!&yS`V,apa-DuOȈ>:8"Hi + "MmVF92BqVsVMDsRM!i\T>Fv­ }sns& " yN[_L]eYZV3"â昒m6]"7W4s䐨AL 8 GbOrԺKp;,U!UB/eMs(:|`3 oE\8\n尝Y]"ߝwyyF[Pe3:L儈zÓz&7[s ԸI0mݝF2@   "32ZQӛ oJ|~)1H6!fN0,>j]֜\=@BLDs + F&y oxlwDbJQ60+8ޭm7 p  ۓQłiFȁ:_Au>ZED}͏7}VQܥEQ!6vd@lBnbeag"qww~w? ap03ƹzD;-/x vVkth ^U_ )~>?;`Ց#˦Q[aqcjpKy{zrk-XT:\!B<{SCXK0%9m(ّ*^h#>7}Co=+3kYj&)MjSA`┘Dp5\dN̉-(&ѣeK} N0ID.G؉k\`*qW+SD'܃[ G*}fjf>zT!@`߇QIx_[5>*"LTrqMӅ nhu;^_ي]"ŕFŒxs*`|B2>;B)y``R tQň݈<2{2HZ`ΜJ\4T(dDʈ{~7{RG  M;zU Ssw/{g Wt7FM|J`݉<8Ӷ%I 0 5zURR&42z 5*ꎈZjDxeCY0*~pepN8E[_~׌AuXJfd$U[(`/ƌ %' WrkjsNOPg+vpWZû7K[FދndJf9ɍY؜30*jF*!"2emcIPڼ|23ČYu{[8XT3#b sc.աY0CT [bJ~L0r3aW(ohJYr\V+'4rQZwM}PhԣU;G\!O 9gOp}oJ/{ IDATY͕J"Twm/if}[h-R "W% yh=]4fa0 ZkW!`0DnQ%K4Wp>h2^ѭi M]Uqqrt &JiI04r>d汞󍟾'v3D+$;#,7T íp7Da$ĪCtKR[ntL@1@>Ra6 1?[B?o5ZqS\8R._zϼb)7%Og\U"V"B.ҢFse"6SkHȿt F6BI4a4_AS xlskugT,$/FubLB= qos߇#:h[L82E7g%LH8ε$ s$ajOf̦̍pT Rm*³D+PIwƒ^'=&xoʼ+M;w#18=%|Oy[/fSAV~YF9'""aAT2(+YJݵ@s}gZfg3QKd*2q [d,!H/ʑ !RoP! '#s!Vy:-ofwh.~.k9BHE4r2Tڜ8|) {Ӷ4>;.N[\]LAղG)͈bbJTr.eʌm?~m/N\QX[,ߕ.G3#{,§&C\T.ؖs^wk\5T%ڡ %S6Ļw5A=ɦ&ƴP1QS!KBkL,5d2Ʂʐ%x"OzV}ã,Cf`"@("Yrr tECU"4j}|m\\CՉTDnX.DSL"[;~WLP ^ tqr^%bⵄ-ΈMD4ٴY;[33#<wqb@w5z8/ꏺY2V0*nmgӇH`s͕)1A`O5WUaN&j¦nb**}BJ+`(n:ZNA,/ 76wSKlIIؘ(wx2˾w/CePQц &Jܲ06AP (=ב)QgO#hι;[[ g}ވ'_j]E)@fS}0Rˣi1 HAsc7fsQCEt7(fCC&TE5gڅ7̿0H#dt "*! *jffrT5kLFh 81HAmawo4{c`fyo߫[R2@D37 ^{iUDxFC|T10\>\PjCT(:;S Y;£~N;ę]"]b7KQ#k/y;~-qBO[x߁9Y)k(é7 ZT" Ȅ`cEUw39wWb"UiЬ>Ϲ/X D\-E}^W]б*/y o?"t"N&,r3p=KbE~Dxgc-PX1 ndfnLJFBDnjyR_/,19f!)+1 !00[New7?0J DLr6RAHXQʐWepz|x9֒ : j7?/"gl6XjlhE#φdf.!g^'rQG X4X9]cHe)Yj׹.!1آ(UaKlsptpr} z#%]\iČH"kԗ<K鍎RoTuw#7's7v5$*vL'cK#l-6RDyc@ٹuׂ_/%thn VcTH `WSY0߿ifm3o,i&)MS7EaBD0vT(CX65KY˯o-=^k03$D{km'O r[*t̂=O)4~t-\ u+>v2g4vۻ Xޗ{1?lGfVPETB Ը?b_FO$"_}Իy%=9]X%k*TTdw]oYfM3MEzH1VDJ{~__jS>|-p]a ">G>fr@ Y&gʅMbw5ƔY6T׀%{JBLۀ `Y!~#rdvWW W,k7UckTOscrXW" ?rZo/+]ο&}WS0֖֔e{|c[+_V܁F,z }GO3Tc_eYfe2YUdy1}˹ʘ,1UU_+oZemaҘšYlɪ*7&|$g S!mmZb}E1"v}ߕpEPRS(;.sq44ܔGA~k*4Fv)lb&Nu+`3!4?o_P{͖4d&k o[ꚜ[uh] w}:W8 AvpԤ- RZiK/K(lVjb@o{ZDDeh_ ݾm8gRk1eS,um?mBEFWBJ6/ϘVZij7f""g 5&Ҏ4:`M!iɑ?lXEy_~K^n4[/T7އ }0~>䧀v?xfMd z_E{ ,1!)Ρց@V5%"fp> E'Kj>P?8g*UQp,y>2+Q)S+p50hFVZnVz32|@!vR&ib6__eVŵAVhNU$HF?t G;Yf-_|XC)@VaQDJow>{k&^#u+$[}QDg9ڢBkKc0ĺteEjEضiڶDqo۷R܈ W3cpdV{|?y[K3CfbMd2D\`]9yٗo~BDDR B~#$Zq}O|g@kBZZbm% е+QXau8@GJ͸)O | xe^~;g:"Қ:[bKW?P3f@/.p^5UU6/m@Y+^AW&\ dz1zxCgP͸t:j%j0&7U=RUYe^VaG̈~K8\ 1ᅣT ]ti8ӽvfQoyRBP+?ԁK_5lΩo}167UnLn0U^YY,b~bsp8k6ԛrkv:ɿSUEYSjgd9GVZ箨 "a+pxTϘ{|#6<>o 5&/̘21Yerk\۟w&Z@]Oږn\B`CC~#fBjCX} /Qw۽=MTms2yRUUPe(EY-r{|sU_Rhԯp-kl\IUUTU9V;;[Y?k5ƞ4OOW&\L ͯ3u;ŶLrSTUݦʲ|ΧI:4V3@uȃsjUbcTGEP` UcsM<`o'_x-ܗfo".9ҟƘ,J*ʴҪJ_W-MYUYV>͏_+޾RUEV|^옽jl|ZkL[3Y`+}P 1(-BxCg|?"7vdyx<5w`59}ԃuڑ,%gUU*KLS͌ι( fs. n:XdcGo&]RC@4 [ |W@"XUPU,G?+tyiVfFLa"&⍹$v#d M*Lʬ"" 7/?%&B@f &tV{U\1>Zˬs!%G8td V%* ]XsXI\%Pf9S3>:1UgLe0g>~e=m[YgQ? X2{)8\Y1Ղ_޿Φ6OP,(I)LD=/_{Sy; Ws: :J7w>)ѯ{΅Z{A.7UdY~5(YMK {q!FLW{bKG ЇδnTQȥs1%32CTQeB&RHQ\&K;mZEEP ϚbFrmT22`v5(ʴUV1@yF o"M}D\O:AT$WCXkbN3|C?"D= j~ww:keVR!00-W?["͝P$.y&@$"c("( n7!\WB*"!<,;o:hY (D(CVZie@Dh A D:0ҌwTnTA9 ~Uſ[?eV4#7uZ[^w= {aA@GAhauChFn.!{J)7hgkA`,?L&(ɅW_Ud"B(\Lò)>DdՈ NU~}8!s BQJ8F|ޙA M"cc&qX+uۡ^z=f>S|ɖڔOXlkq1LgR'pu?*_QwEzEkMeLaiޞ3iZUeiMllEZ{NMP@S9,S~ 9t) !pa{~}9*c+k@Z E_?EZ>irk?2^7<+AQh&tddTFZ >#ʽck$7.1[&טNn"+)+)-ɍ)x@97ާud#cLYUe^"f37f9s* vhݚw&z%oA]=عc ϷJ 3,EQ,2mߊr,wwn.vUV9g/ (gTU` Va߈py.z9?fBi&h^FךmN#8L,]L 9oh zRD LSMSYFD "Y ~E*5\@V%ba4$~|=sRȰBTZZGZUo039g-D .pV vw jPTX*`TuKoϦ*ZaKݮ I(8}5%N{I^c4V*P(Zak$qO)$ {}K"B(\̀/xFtQ祔G3.wxIDAT3 G۹-Bzl51VQJ6P6&ȢCvB JiSX4tZ1! ?C= PZWFΒnUNz]vAkC@D@#Ι`TZf(I:HBԨ**T* ˯> \^%puQ0:y/x ֶNoM9Ru8ż$fIW&T>/+y?vYRƔUWUimYTEY^[Z[ZSXSYLerGBU;ӞBNF""EQIS"HLj'($СRV&}Ӗ$U)uEo]k!"puT7Pw{`w{aqot KM:T :Lμ> r{YN9Q)u)0_{.fSbiG G R8*DSk Cf; 00Yk|! *BGF9.ܐnGjg30u:98ψ}|ѐ &O%=an~wN>a3%p! ƸM't{aou{a^[zx1+ӹIxӻ_3Mo&g*"_\-o."wqO`2"#e `+h_!"wW*d@brZq8ew.ZkPE9fe,w!D#*_Yekw)6r 9p:x[!a+lR^/0ڸEn,p#yӻ ,AW4$r?Xę^~ء#riJm5 !KDLjrD ҋ p93nޡH1R7~fFkac<#|xT+knُf0RSDT0CMe-ѕFPf*x|'Aq& ut6)Hq;|7?g^hcD8y @4m6{ڼ"z*c7!,SH@0&_zf`d&Gހ`6h&LQ:`9 ]Qf!!(kƧ,M$aa`03([3O_18"u,lY 9t{aQn/CKSUYy7{\]?O{?U0(&!5*`"Α:4Y9ST*Xުa|R*(*JWnw7`\ݠ ~9,CK_sA x4N,ZFP5qozQH(r;l? Bvh^# 0h?E(i;^jFYwW>\z&"(֊zQ)m:6.r SrC |r*MW;Ǽ?}sUQ)P ]tp8!!)$ *vR4A8.0CQ*"FBDf Vα w?/ Q9"H3xߺ^ڪCTJJ3t[T:~Bee` D_mJ P@kC'r30(pm 76pcOfpA~sDwDog;p>kTPiג^? #=Q riZMtQ =GƍLֶ f"fLarΕJMQ^ƌv!_39RY?CZ&: Pg\5? 5.AZ/+B뜍"V?☻]"`4 HG$CQWBI&]#GAGazEU颒Qy~ß6ko9"3>D^i 恻\m`s͋-}/4hLL>Okl͊m㨔n&qs-E !Zc(0M&" v0 S+F#9.r;;|VR*tot6^2\pWqa[LDdXWYWGKU?hՉIU`st۱YrտW@oɥ^ߣV/ЁEČDY1g u zY:!pD)r[ {?z(jzoMf>yw?00EhИ "|_ "s ֍IQ3l_݋kAj@+VzmA"l j}PvNuqe1+DPdjt!:lZΦ%D 8&pDE5IY=ۤyٯ&Z}{zB Mպv M9۬jmujg"nG]zh-Jy 6pB1T;U(S+JTv?b qov:aoѩ ٤t.n(">3{}~>(lTG"B4JY%3ktĖؒ-b*8ݪ-ٯvZc?lb+aHe2&, cD烅eJ#B(*MQ7xkF̤ 9Y ?~+5Pz ^@f:g6Jʤ/~_lRdv~R`V3VIsQUeE D7yXWBaqgr6){NJ1tN7:ż鼒Qj3>D+E1#3ybUҁwhh~NH 5悺"UaMUT1ssXNWn*,54M Y"b=\K6ON'DIJ'Ƒ%'e:?˭QX[(ok̖Muw|?%DŽmRT[qBR 83d%X*"l]Wo܀p͑PiIU:xl5ג( (Fo33-*$p >ߪg {ytԡA୊(LvyM;t,bm{ `q{$: 2p5#6nDQoz-|Zo}s?ӂDd*_BTAJJ?pՔK'~@c_veA")'T(Yb$+މEZR{b.*fZNN7;nH4py_׌.e>y ``GUOR= TBn,KNźjfY*k˓w~Zڿunb^(־L\'QwWI)8|%Ŧtc@= ɛ~-O})'|̎H+euAqC#V)Mlr!Hkt!J[otx# b Gy/fsk64yU4[)e35~czQUUzq keVBA8@_ih88hƉ|Vͦb&3@~'?37W̌H[wd$~!M^QxzUI1+d?|ǧ~m%gV38rAd|pmVf!*v@ G`uza sn:Kb6);=\AڌJsO ר^/F ձU) Z6Nt6[]@R~a߬pO~W99=;="~>K^*-"X]3^0 }y3p!k96{'a Ur:)&a߬w|>zȗ%BG%QYV3ދ&a \cr>+{dZ[OFk`E88,5{R'wEr^Mb[^J*UGPQ;b텃a<ǃa텽_Y9+ӲaP/om…74/ow'/zMv'OF N `z'ury i9NN~sGa|%O0UGPtwCQ<ͦ|6-7teDw{:r#B(G,5Y:0(=7: i9+f;!̧et7˓ dRf!'z0J OlZN,dbBu;%O%AA+ ]•Ev\>%j8h8獬ܗ;̦% vS|oed&@PV:PQ P'NNB0iW$Lvfg}}.}爉&@PV gio' k8Ž~뇧3|[̦N bY[OBeM 0ޞx9NMU٤þcw'SA*›BA8.^Iaxmىĩĩ̦N!eEe-I'eg9# !cGYgOOZDõdki6)eIa=q>-7]:P25ڈ ±&]T 5\Z'fw}{Ǵw}.[m$º""\aDAN͓ZDAۆ0+v8N#6Ik[JEʈ p1eaϟ]?8'^Gd4N5kig;eM;yD[]L*0•FPbW7E@h:yK-=q:)vn7֓KI*p.};BDA"|蕠׏JqNG%7YtW e0nhs]V" \5~񿜁n$[$ 6[]( 냢.-VoD|["U( B(³N&A6h$IN|;٩q,AYLOJ  p=8zo_'AD ӽbNNN{dD!́ מt^kVwݗ`DwDNdEFlv3@ PlO/eXrDA޴#6I'Ɖn d&Gw:+zr|} X^RA!Q_@m`^}v1=N>^lBi^j  p(,敯@'8I:.j[dݣ;p>32,s)G,q)" &҅󙯱N6NNIѭdؽ]8M۲I'"Q*Dk}}"E< G"govI'k_n ]8䓝Pzg>wxb t9;컸:DA8Lv ISrj\' m; D UGP#r?֓z?\8zE޽Sͭ" 4T+ +y3X[llv6ONyyEnv :Ås֩)!a%n͓xt[n|Vb/fҞoov2H<3 w費eFPZ:cszg}3^ `n{!۹_ufi>3.Ú,!a1/b ['{뛝F7'NNԽsO,vልWayȤ3ǽ LjŬY A띍F N|V;SNYJ@=K1oe!8b N'otN7:a<Ʒ1b|}.3sѧ[z 7" wt4qQN޵a ?vw'nTϘZp7 쳷hFF'ۆo|Zg~RF*gɡEAPXCg)pDwZ|@}nN#B(4g|V> xEbq9Z!B( \cYւ^<&E3.Z}%\%" e[BGka/ӽE;ͮp0PPAqGva/v{rewfiy~βuʬaAHЉÍawB.CQ(X>B!\(SE?gka"QP`G+'OJVQr90\PtBy(c@)Ơm N`)!+ yke,0t!\3Xd*`-`[ ! J*̨@,5 UX150H![|,|>ER-./ PLNstVXZlw"QAE6k-|Yb-6v%+$Xj(Qm]R}ۤDŽB6 ,2 R:Ӻaq%pѶ& qkwBBE63h4 NWJ %SU4mCBn ,83jw՝q]-:=X %sHaƶ5hڐڟrP`jOQ$h 4 (pUdh[r5AӲ!Z((c,̪Eʟ/JP(ݗJ)TBUi`7\mܮ1t!P`Q`K(իN.O]eJ ebivܮ1Bȝg>X]QtT_U*%n6dvB6XdXk};4qnrS9[eUTPQ`]n6dZ4uvBXd[Zun3+‡˪ դ@@?5qֲR=!d"D\,|NWQM4ʲtG@SԍAj}M2^(80D8W-U,=_ eU!ƲPfWYivJ 3-!d"ic^8֢mԬυդdf4Ű 즄zvrՠ^9E!AEFYaMղũxbk2-ZaPe*0#!AEFZR ې 횝&K7q2)ӥ[j%e˅W~{ .,X,y.]eDW5Ѩ|.=)PMJOm|ݮ1X.⺌l7XdD(Fݮ%лe}6%E<P`fZ8g25)ZŐ} W VK] ,2I\w26b]+sMw\wR]9]N|!  \lX$=_*A-+zbkh؄ۇ!ka-&]r&#'&;e҅sۥŠEÌtY(hp!Bm !7j霪O\{Sb:)s mbK/! M|.K:X@S\CqgݗU2 ] ,2B;COt>iܮ|=vY,M 3.,vr%(h0BA`+cb`1KHUMAӝppF[҃c\!#]dZ`gԇJ&?ʥ,õ71!w ,2Lk\Q ,Bc,Ye1Y|Bc zMFS]x  \R 'i&cpBԕ @j,I6CEFC4Xl Ttn٬.3p"~-Bi dkO+j{)H "dLZ%R8:޹!F"mCE!cXn@EF5a&!/]BƂ.!~}C,r(EF1.LXh:XoPJm !T  !Z-bw.$d"„!!d4h }|g (Ȩ0( Z+X/HyӕQHERdT4MJȡn )Q c,#$dļ{;^dwp"m]{Y%d4Sr3p""Tr/XɝQJ46WYo^ϠpaBP`Q "d4XO7"l%Ȩh[ L8 m?Nbq6!F(Ȩh[k2b ,u`ݽF놣mE6bewuP`Qf*eqۇBaBJ;"_^0Ca-oGk!Pdt%dӹlɫN/v8B6J1DHȶS(>a;-h7!U~:KXdp"9X eYl:LB'PPx ,2:b;Cl>߮ '+T{k?,BPd(#l6G=E%MR ϴjbAGǻa;(qT!L}=<- !W%,@}{O&$ャ% 2>?BxnŢAYi<|dw28:Q>DH$K~z Ͽ:Xar#pt"O#E6Kvp]&qщZ l?Mc P# H"7z[(YZ(02\@ȦW_poX.Z8:]rP`Q2 =~G(| kb͇%MCXl, /??>xxQ4J)TUqۇB9u 1 J_|Il6Xd& \~egwLv' G'2Jں9XtTְh[m{3b`wăLv' %uc h" G@)|-],P`Q @DWB?N6^d(nDƮ/B}z)/d3"Ņ Y?}‘6P`!u`7s,f *?b;<(hEfs ¹X_"G&2Z-DwB6k9O;_^t>_0oBi~ *&?|=n ȝ<^{ 88. <|opx?_9>_G=|# ,r+P`Q#y=PUǏxGS<|ݽ {>ߏv߽Y>_J[& "۰Ov5i(R?p8U88ɳ{88{0Dw+8]"j(?4H^#|#bG8՘LtMqpD\[x|.BMW6"f4Jȹ[:uQ>כ3 V, mBEt}r]y=s\Z>W(|.rQ^`[XAEFr~zx|n\nBLv'5~.Y/>dߊ\.ג\d+`-}dwrP`Qs$&sRsEM Lv'!P>WptEB>&ۀYht,W*|n1l:XNn ,2j6-DtKE\TȆ!*dwrP`QsIY\!|W?T56)+dwrP`2d>W\\^~d;1(Ȩi|pL9X|P|g -'wX:"&`|n]<&Kf/OON ,BT\OgEsA{Cy^Lv'!w<KES g)K |!ɵBEFO]UG+|P*"`R7PշLv' =MmPUʪf.:~"DC8M@EC\Ǣ {gsy=û7 su %$?>(W{FɍS?p a@pv#b{pd)ɺ"g[&z^\!ƍ @Hv>}ۇC ,2zƸ]JEMc|P*y,J: Y/X[AhsmШ!d3Ǖ_ = ngs=|wb>?Ԉ~eew ,N(W~ C|VLnɥr\Ks#쾻WQAEFrS^w.sV>W\77=DݙEG$B փ8|7gt0 Lv'= !.Z|n13Q2 &&2P>W,|E.3ɺ"[`|uQ>׫NY*b `;Y7Xd4t\s]TH"&uBEFC亹(+s}=0pL!BdP`S e,C\ݺ(yLNٶ`zb;Y+X&b >BۖB#30ٝ ,2z"E6<KEѕP# Lv'bQQ`\TD*R:"[|ǻY{wn&u@E!P>ױ(ޙ\o^VRgx0dw(VP J4&d+k80+ܭZc懗qp䳡"[A](+*(ȝ|'EK\G>טgJ^~N> ,Ե.\e~C- "\P>W(<G}&ςBY*⏿?;뢥.sƶN/O3ٝ|Xd+H\!qV>{xp's -sQ>W[pd"WlEg2xCV**\.kՄkwdwru(V0exئ|.&υlr>򹂫x7G(+ƀLv~l7!AE`U"F閊L T>Wpn>ݿ4Xd+X-P`r((L&~yuz(f.ڄv2=.ID.E&|vtQK\^tz+Kd; Xd+r92|&sd$Xd+hjW,)MR939owL޾]d;d. ,u %YbRuQ>@|.&@E!d}@:d,qA>Yhs1ٝ\ ,ԬEFfRٽX*|W?^Te"[A$wB6Z;sBN. Xrs?JEdwr(V*3ɝ%eg(XD("[Cu1Y\w$7 ԟ^cT EANw[## "}I kqV:V =yE6f?|{ۇ@6SP|5w&Ʀ)'D XG,1r]])#Uoތo֋)k%ޮ~]BC3&ϯekEu^6`5֊ :brmWDe?jEVW 'dfuzLcR 9Vw1cr/^:D+w"$!V~,z81O'V=qۖt.WmS۴h6Tn,"ZdQ\Ah+o+ï mA8Dd,c$wX wFx0G 'jN؍W۞,=mpYmZ$e%,zo "˪_^K&˻vp 健>nQqY,@XdX1`y5A3@K 6P>1Zh M_5mU9@bJ$ 7bĕLJE Mc BqpNeTӶ^ӛ~jj; se`mm2$/gJ%CzY g+{w~ǝ5$<ċŕ!SG" WS eM q c]ԪSЬZ+d4¶b:u$B:XdH!P-әagmpr!1<@5\z$٫޴;'zNip)ZΈE:O7udʷ #U@LRd]*ӭ%fՙZ~d ԅazY#PpłR_eUFWjMrW"!;g p⪿|z箓5δAtevq}#Stv|jjbKUA/ٵҽFS1D {$se"?WR<>׋<4YCSYcc$sd:B{~eivtnP=gᶱ05`w,Ý6sIu31^[Ȯpk&]lȒY20DHƍ.b]> CM߅К w0P YXBAŪBA u)$.f߅9o&,B) BIʅthRL Չ)vV{_ƿ8~PUęM*9&8s$~V\~ݸ׬uOP*B(9_/s9|a\߅r`"^VE&3xA%E(DY >+>|ƆJ#+V-sh7[,UIYXB'}۲Sn1EreK7:IaJۉ;ޡX mBLva Gk]ySFn+ SE ECd<*Uԏ`E8,,K/z۷c)x1<KQŁc]/jԋSfKb។;614MyJ*In*(ɈЕ($9{!)U$vhv:z 1ɾmK9yBV6;BtP`"EN8r i,Li!TDi#g\. I!$y~ͩXig20)!vmr: V \,d~>@TԚˆC" u( J esbEDPi|u~P!D Q4,D,0\'1/5,OfPQ/Z^U} KAEFMUSUzJC$i(qra2,9s ŕM8]ȖfA'h;0j^UɕIJ rkBWhX},r*e=2,:"%l^6Pyn ߗ焉!k \uvVu6ؿvk]jV!oO ZݭӷI4Lp'AEFuZ(5V:ȧNdB* ej?ӯ݃8=Ex; P38l566$ >'CnU'wmQewXFI Nti H+ha|@Uڊe =]2aVxye8W屆B\I?yS^;BX%E0l~ ߤ /omCşPLW"܄m/BFXJJ I+Z`mAb?gqُA0Lrjyvl. *T x `}XrGCJC|3SBK;1%˳QjUݹNJ}gnBC۝gRj,k>2|#ŘĬ^b^ 3e"'"~.mχLuIz/RӋW?S3}ڴi1 ک;Jiu֮c+H!VO)hGO|1bD#֊n`?4ޓ Q\׃fׄ~&%XЦ|b'kawrY(Vt$ Y'[lV ZU.tnmXck\jiq6]Ta{ڼbb|xle Nx0Y/Ild8?II#;cSwGrLQ֭?{(he.d[ a=33LI/ fUR%ж$`Y0Bc,XdղhqH#J= 2eP/[Ku D+: h m.9iw` ܹjrԣ숾Vu~'v4@NW4wd:؛"ۜ >VURtEpROHuGWs &s&5@+9Y[f}HȲz^,rY(iPkr9xC(*kOn|e~QU[@+\|I醈[V\:> I?W{,Dhp$ "yf)6 bےEҗ) &'tNG2$]!tf?vY#)vXOR(}j;+ *+t"^Q|=mhކ@3:7tU]evzraOޟ=8AL?dͦ$JK]3>e*EO.c Xb9C`7mei\ ,7Ma`7ߢhԉ0]!FʷϟSЮ}CéEbq߱x(>UOVuݺ/]I:ȯ >~׎Mu #oNsUqn&vVwh(dԡuIkPU 0ݶfQ_7KHxډ׍v :S%.s,Vvʽ拀X: W(K=36XkpK ׄ6SBz8\:Xd HnHX$Ghpnb78>Β(8*2 =tH *+>Xm5`кlg+)]Ҷܬ5{r}zf} Cٙ9*g\$lŎ-28'8}*(nfUOnCʯ#$]C9rCWr4޶{f/֋SrC8q JtCjo1teEF2%ﮤ\k*~JXE 7qŻ7?AEbI\<'sPI[ʒxYS(]@k7+QZVL?') ֞ N6ԇgrTϭ.rl]ENt'PM] TP(.;]iP;Dln} ;C,V|trElɥpk g:!:\gOb)G][t.0\:XdJY&n f]_lF1GxF~@=Y(hVm#yVU8\Yŧg`]d2@B~AŤWBFliHtR@hqmD=h?.'ʠ({tk<I\oaL "CP ;~Wۊw2)|K7qL5? n{:O[xёgX &'K^Q:}R4 qPm^}G?n1'Tjlǹlho{8`1K3^،K2 *6RXHx.o//(8XB08L\7 .rpFH+Xckbl׀ۗBρtнkgG_݇Has^{0͠uo%COvl!B:X|`QbL[< LwJJd}t)Lϱ40VOP9J ܿ4{ʷ-D`CtlXRJTN$(lhSnYkY'GѱDt}wQQLa{G!A9;0^+6{m`q3l1\NS|I"WSpܱ/NX>\[+zofU݅D7 B(Xdt۽Szɹ aV 3B&@ V XQ5t Q\$)igJ|IhER:B[ . (HV<+): <5ݍ"+,Y$VϹ40VRH t{OOeI"7߾AX%1i ׎x;Щ: I"xHh%FpG,C_OfM[Tq QTTlF ,d; XdTqwQTWM8%PEvA .OûIA|׌|mHP9aYf0W{qNɪʪ$l>ip 0ʔ-sFtwyzM()f"K> yh E!!R_dQ@۹ (\%X9N&WU(⤈J"lQ[>; .P.)槳|S^` r{9mD Xd4Hq%^Kkl`PmmкBQ0G1iy$nщ8{]~݁ʧ xlΙkHC`4!S> O3,!pLuJZWOP{(oNX/DLY{ꗎIWK߾ne&709uFΝ86qf,%V酜iRXrvXRd!9xNiXG_"vzo2)6mϲ X81 $W8؄-XMeӤ-KϻBbZ 70-%)c@Bx9DOS/C ;nNEJB'wAp?/>@`[E,XhRSh,r(ȰXc~@ TN&egD#W1ZeQa<pic9/nepY i?8 A:eK+fE>dt<ܱa٪G.XҀ-~|Ͻu4޿~+K(7#60ɤh|-~FpbX'2eۥS oF+f#7`=}D{rf͒g=;DZG,dѲЅS}"9X*P`Qi,d^}/uIШpF^PLOˏ(Tu{sC]f ([A5m L\-45*qm i7\d;'اK" x j/62+fwmsEl ?qcؽsk[1e{$stjD}Mm'wٰM1ɣ6kCnmxvrf'K~wl&d{*V˜3A;$6LOl2B\/k>W/u׉6GP)NtBBwT+m4]X-qR@p" \/tĦM|9 Rk.~W KW dݚ?ӽ IDAT5`I=Z3}X@_; Ob{^\ɌZM ئϪ_t;s*k` pm1PPF,[300\8z޻~*,_qːKza+CHyoBM}( Z(5@>;6 ||.HUNZ%εƌʿܯx9&E,,_熜s|#PlOB( Z/QcdyǹW6]Dt!ܞ^XP8[ffN]sԇJ٬T8gWk&Hg;g8\FևB;! `iO_7!TS8Cgz7JgzE$vvzijh plLXtU"Ң@=1}tyZ6݄׬n,OW(c~ ê6&2$!N`0iBN.zmΠMpݤtWȈcJp:yWҹ7`yUw/{vBb<"C^۾ӹle:ܴXD |Or ڞetZcК#Ka1\ ,2:.2\6('ڏL>YZb04x#1 ]EMC~col[!!+Yj[rZyosʴ6?8!bR?SyrRqߎA\ ܹr/srxO(\~gI9"W p ,i6<{3#)kqv! [ bN "CEF7zfe3`QIUA?HșurI/P_5dR$(}k.R8pp0My *q*,dw0!6m1 6qVŤBxyޗ5V%qҔ.ktEVʯ7ȮBDÃ,@. ,2N܄\xitLYTM)bRW&JuG)\̴{]ˮ9fyBN$deaw`qx\fF(}.K ~P8R5)vBY) χrƴ-ZD+8ZYnN}m'n=-wk߭AQ)-nͪA[h&;qIrwG gj5{|88ǧs|몍yJ5:LSt *)9_}BsS'*'EӲkugNmAH  ޤBmY'O%a!C*_TU N;oQ2 Yvƺϰ)'X͚dAt´N,v)͢@kQ~]Rd%a'CO^Ô83Vx{?f}&dnɈc69`{þulb ,rU(hH9@@}0{rgN  u oZeFvIzNN䬻$I!8Fٌ=k[=2;Y4 z}xqP}dE>?-wS% U:IXu r̂#\|5JDκAiccwۯ`wrU(Ȩ!TV\{ wnHedɄDZipJnC %bgkek`s^k Ϥi`v?~ p|< $VwR|V)Gl]] T &Z =.[F'orVDCEpBhr_7"+ӏ1ܧ~uBi:|IGDp`b_^u5 ]ټ{[lv]τ}wPF䵶7rE\&QpO4s#`-+(X-]ê*ŀ!Aܰ> +}'oNQJzF\$7-@il܏*$Bc˚0/P&dX'PU^$"_?*Ż5w'`\b1>/>n;i?, 4<98s[(*'޿%692ݙ.$Clch~#RzEx ?kŦ56\½j׺R#"~ėx ):BaɌס82Hx({kj4"E ,2ķ0?U ڀh7[.B8eT(BN =cIoEst5 11L$.B@fG r!2w! ys' BU;Z\,^n[m"LO/B^VJP~ZWQI/VՐtR;\N}گB&9q#NxZڇ@ˢ·߄U6 p]E14 5X͗X̖Bwn&Ǔ:‡_B/ToFtoBX<ñB\(ߩ_58WoDf߸H߶chnGx6uŽUoVeQUSKo Jt^?'%Foܺq*+eb Ivfxǰ^X)WއZPnR w6 X"Z~a W,-+-b;-WAR!BXCАW2Wa?aF%JFÕ+GW;wךJR.\'C(_-jBQjwںFdbҊkޝ'Dh88g*ӵffU c5m]/mM O I¬3&?al0\:Xd._ HG~|7LB^Joa`1])\EPY]Wn֘/p)tpOGc9WMOa~HKW)sȼ wTm?x\4Sy zzar6w,|&$@ :G7`q2w "q©Go\x)`i&_-,Hl/q ǐ~7w};w-Z麚%m&,.*_Q |!p1Q8W1ބJk/ߟ:68\ ,2:\" 0z-.@څQmJCtZ*9kA$mc/Hj4m|$ A ",hb^Tw(>tIgB- ²7ǏK o_#ط!*:bRhtF BKzO Z/m3w./yQڑt"kw:?ARټ gPa5)|pcY8֦{BP:+f-Bce?1^]H("~wL[9+rtU"`~ 3!E8Y"*;n@!m ~))mt.B褦PB{w0A.E%3'sĕprYVJt6+ĪLJ  ^^+NX(BdŶ~Ih=q+_C*LlO(ast^;{`*Xdta.vN{DVEVrO0_Di6&cU%P8z=YE^+{_?6$X¶X (dLbez1,9#R\y\S<~ ~t!)~ZEQĖwg\z)7g {$>\\yh-/'o'mIu? כt C*9WUN)NR8ym!s?fǐ*{sRXPIc4V:T՝7qq%RH%j-KnvAtǝ#NG$H~Ht# nN,g[,-y 5"Hު:c {s/aMwqC{o:go%>E 1b\v")TkvGlhO*lV,,>v'zX_^Cl0V٠kY=z TF#p hM'WUƜ~ 9K^Zj%38tDssӍ$O-` EJe_v% ϙBg]̇G 1¾|20"c$2] ˞ҥ!%-;s@to?!OZy\lS6z`c{A32r ԾS\H!(|з 1+p`pp9%d.P̦/~>І (@)!q: V sݨu0nټ:vK=dOp\\%qݦKZҏ76hSMϛ.νW,KUOVy .{:P}Q6Z7{ ہ2v0't )!{{\d%rgagBaHv΂zh%hzW`ԓ\]Hl&kx/>D'rwr \kԯ;f ]@>4AM^[rzpOBX,Z!D,@NX YƐr0$.'A^m$1jW8 u,*#%B`{~;?ү[ڢG,Q Rˌ <jttCu[ ȃ|2XpJ`4q枎#X2g67SnB[ٺbڼ8wI'f%0X!y' pjvrʐȜ g1"'8>+{ {:ȴzC+ ]V& }zөrDZO)X>dd43jZ̙ 8=e,±6^pzph{ `MqͅoO7\6h$.H[4?ǀr3}fq a!oRCP k sޢlS5 88y _@ϋX3{!Lt.熌bLe!ys cO@:APSu_@c!O~뫚k :y]s/<@+!{*Jg&ZCZah-xE!#s^yA=akOʚKX1An|YkB5WFkރO}dia/WkDLIjTL"XXSW⚌* 3ѭz ڹǰvnYih9vZ8̧#\Ǻ? V(ʗ?0N1 UUĚ9ODگHU"juII; p)6o-BhpM#pW?m{e@^hXU*knh 7*oF6rXKFۇΏ,~02:n6 )/@M4Y,kdM Wڏцzn՗'Z;ðF/x:t+ *[bl@icٔq@e't[oyjOraф7s0Chf8q.rM@[X* Yy/ƙ 1-vmzr.RPL JE̕Z _0pU;>[ec}o[Eu-"cU.I]2EZCy=\ k`Mq%1)umMl@?oV~Fg^j7*^oz&_˦kCb&'T\uTeq lpE\b12~FWmEg$cD~e`6c'N+"fAN shgN 톙FSh~e/dSupPӟv@Aa<Μ7[PԲXA_/ a'Xfmı#-8 ~kzԛa,iҶt?bzZgqכnH:ɰ"u)\e=E{rWSL WPҲ|QLig)\AVӴx]9zPb&"r.-o\ ;q=V;T[jjRǤ+J\g86秱*UG瞮6l~VGuq!=O眎g2꘰ci^Xtmiq3 -Auw䱻0˚ѲuZa<10t0]ք4L/>1f2e=܉9& W⚏O\돵Tם4JeU` 7g/-#8Yߪen4dsLv>NZ:px/#g[a"_e8 nQ|sZh5gBu@p16o~q}RI WXt)WJ}dW^t`Mq%1)Ih\z 36^M-F&J,}>C(u|0"9d0@ F۩W#pUuYEt=y뼉g·$'cVb;n*ٿB4l6 ]m*"xϕq:s4Ħ&dcmi,K)ד0d1YМX&|B3 sx@:Ss9gƳO,DcGTtM'XBea0*2}hI{JK葜Cѓn].#ߺb`Mq%1)Gh>3|7BtD7\rHk4DNF/CN\nmiSMzeؗ>@U̕oxte.{WD:M˯ Hԏ@>;|dP5G-Cˈ{\>mU5ٙkV$F9R• ~|´F*>q7OEdy@(s,=_e XO`]L)\1Sҁ)G9fEשh s9oW<_b* `wڗ>m1Jϫ y&PW|OZ+|H.H `_4bv[ck46Nas~)o+}}gTΙmZy{(Ǭ+Ab`M3*pgq4oR݊LgF7|Ën o 6k9xt )_ثRA|isktn^9%T MY( ΃{d^qfc Sė>IHJlNSO(xĀ,;WF+ׯ3+PA?H:&97r=40T+^Qy<[9W tim933NnP6Wѻcy3^P;mcV>`ّ̇䔁 LqbJNqMrдmXETy$GN9r$l,>van㌫'ɧtht7]Z`vNʿJܗDti nXc̊|.IROO|3)Yqz g|̌G0l#Lj״և`"Z!$0X=|byc*y˔=4=i\5g-(0Q@S"ELNYR 4͢by?SKp$=sSx"ȟI28uXKPL#9[qsq5FI>5ŵ 2)%*M|/FDT˧o-VyІ Axf6M+ͦ7f18?i<th0 q<`ٌ/e>j=x(=OApU/\+= M_;l! ەm|&-mLɤ3uD2YhdH#v3te>yq_]BmZUg,j%R='lb4( ̢f6<]WNt6R[}.RƉӧß~_(qf.t΀ gIbo^O N1[lϿc%v6f6m\8 ?9j# noesN2䉨|6*s /23( &!Q*3tO΍eQ3Yן};83xgs& KakPքlf tjAX hEM-*c2l..a0UE/s#ZE7WemKR*#kKX;" (N}WaXcv֘\ܧҘDS\AL %1Xy:9& @2&BِKоlNrfR0TKAWP`QH>e8 Ss /\D.ж MهY F=->bGnñ#WbkX2n.yddTZT͗4REPs$dȠ!e0d地wyAUe" +)"qZɈqÚ߫ WT0{T(Ҹ Oc z-$Po^7yӒ^;qfQU n9Mf[ؘp?V[ޯ69e_?$)r,z:qс87Lbԟzkmi+eIsl-_sjJcXSxT_;݊Mǔh4-BhʍS7~7~er+?:]ҘEւ[*-bwd.~r.DZKXY4S ŌVppc(;hsWhW*31H%%e>$ S,$FæJ d-ssWt LEc"$%fyq5 4͆¤`m-ؘ+ %p` Xpepv#*˩-Ȋ4WdY[o~(][YtURjaɼw^=M}ĤJcXSȤl13)3J915;CB:[o~&S*ml.+L$FP*lVtA@$ ?IOl6Vgg~MyۦAZQ@ViE6X9zhsqbJ dA-կut#2 *k_BMatŕx,uz¹qpy\8w/\hb/;su}O܁"np>00 "->oDdxY5ŕ8tF*>XLy*=(efSV$law<IƷ5S:1bPK{Y//Uz.eRS0XV 3p-+|v/]Dlbnb6,v.$\:p\CߓC&?|O<3P<䓅}ٴxk1n+O#tulT*ڪHA_1l<~j}%~QXOUSCo:ds}>?)o(e N:Vk\R* jI5ŕ8toS l12fc,el\mPo7667\6i4".; 8<<8k< [H 9dÙfL~wEncӌauZ}i`JȈձRػt =./V ϨmM 9erXUfSOb󀄢c3z pI[mtN eq[t䟡Ni!# IDAT թaw7~a'h uAv<-5iX0YCl5/:z= @GiUH֙5'㾚'k-&5š?ժhlv|Rfl* &nA~FE.W1Jb{3v/d\ C\6oieq ;`ӓuE_=()#i2Ii>@tneaQ._nyN(P.4_;,Ԁ\4\?v \9sh k'OSW4եe4g(k%bz\mw>| C( ub[Q]{9WO'k-&)]!~hlڂ~Vl5eH;FBJzs.֣m76ܶfv8";^#XAaA<*]Sv,yXh{4co*dsV]4aοJUae nru^ɕϜ\`\<)%x`%ՙZ葃7Kv 3vnj &pUFb~d˲ae&9Ng =?]9;hڹВ k 5H}3OYi=Rigw%zOecDl|CNO2O155š??frf;zγ@ڰ\ѧl/oM94M2^;ac-*F)ޜ]a+8oS>^ao3$%]#-lMi~4Սa4EVW0Oi]-W2dMTcgy^ϡ 3=nɬ,шi9E0׻f`+yPoG2Ș!)d +: AC3ұ*Ik;֟S1A5CgHbmck&D+h9=8 ܧ,4KTe=+`#YI}TUY-7=Q~ զ@BIy6[.JTdݾzl\e a\UAsX/XTWEǬ42 \UwۍPv hi8M$6YVX6=-4p VMtI/cA|IK5pΤR/hb S٤kձV:籵Y;tݞ]+W@< jnYA K%dF{eӃEWPE5FAhj$e#-цGuRAmA&meB%j];lnlswkAqmnihX ,JΤr:brj5I&MVi`H uw@F/nX h,=fW}֙]њ5T?Cd*`#P6:%YoS32U+X0b8 ncF'9A#x/ɔ3X X_ߔ !J6֞h+-sv$2\߿*x)1)gʪ0pU-(arhvӣp)<)Y2$uo~UC4~eR)s;6A@?/U/u&UdQ 5Pc=/XkY̾?D-r,lǜrscoҳXҏI\HW~OScr ?q7_WլUq %6ϷwLXS&dcdE[6~MӔ J'Օv7:6&e ?^t.f7|ױ>%#xiLj0cPE j^=(e6mP R7ac[`XD75:-Oީ#1ՙ4qc&Zϟ҅)EC[c)Y X<&X j\c_-fmhgG~ס[CZ#!deJfoRsu͠9P$G=XiCZhT1{QMcrqTE8š?QI5~=[4lpGJ1z8.Gh8xD_Ӎ,&б7)3 +֍Zv@0g\]v޷_GUR''KƷw"~f0t=}8,rθ펇'>c(l g,!u@Jts*U|b7ReN9yu B~$F:lqs/C;@n`oCX&;2㓞&\,eNyx9 !R͙G0Rhp3O}K~|)-D8.,[a<ZR|Rsr> y䱼ܡ9z1 aT܊]H^?|bbx)11XS?Ezon5ǰr5O psƇKU1D V"8@7)K:K.T$*nvE$%9"-^0јUqzF ma/ޥ[ԽgWC%84ABi(.R >ƛY&ua{ޤhEE@߯{r0fZpѸ&(#asE#3:wh 4 [Y 4.nrkZuhfhB ޸7.~SS56QƬ} h{3=V.BASuN5OM[ZWn7Xe߱{Ky8I&C*bIw2XI )*-TD?z ȯ~C Rʸwb¥b-"H֚"sږ}/:=]nz@P&,ж[hg[Ͷ1k#Q(ӡN~|Nz=|dk1&5š a]&3ZdN]"0lmLҋ2)/Yʔg ܓq{ :r1,^\%7CGĭ>98z+K:?_?33iZ,6vDy[ ?r` ="v/GPǥؠ;躽WܱĤ*v4?}-hCW߉tI4fԢui`=)/YYs`vM, Z-2ؽ[]* 8 EZ ! ؜ߤﵫ!&kPě~o=-Q@eE1kE^qL@VLj?S^ P@]O`J.EeAͬ*R{ob.+/û8{n0तJajf4l}9\L5#WZcvZM1kG@1;]2Yб{3,nA%%V檜JL:4#3W.{+Dzw%-kΊ7U1Ŋlh#=Ŋ^ybU1L9b\cX?]0皪/-ȇ@Uwnz}WCL)^JLkC;l٨MYCT 2&7T}&8Z.VS0O4BdX\i&1.*)=T,R)cEPh5SNO؜{{{M5`RϨcU?pu Q#)B@GVw+ԅT [};~Fa[\RѦn/`@ivmy/Яst˙|Řo}1uP&IYT-=\VE>J޵A0|XR#|1 "b+pC9dzU TI_Zs >%z1(*&_,J_ኾ=LE\ W2REb6zr0eybp@5R0EQIj .|O!inh'w4 H1 c\ WTUPΊ-7 Jԫ/iQve4Vrp1 o:u?=Uj5WR ><#k[d4ͩOՌvM2тQ̻#!q# yh}G`Jԇ_=o>F#Fd cQ)RV+͆a\~ʤșWV_Opl(oNNS&$MXꡄ*lBb0`n[C+ E})%=0 W"{XRs)!TVfeE- KM5ՕDEUT)sŕd]g6eyߴD$~K`jR&ÀK 01@'I<l-Gtu'Yr\/ZI^5pGoEׯ<_/j:(g٫ͽT:FVVz2b|fyD"a r r_?=2jW5š '3e ECr1v96T"{N1X򥇛0fk22KDY{S3 #z=R,(`)6>AMId5mM@ƌ#0䃔t.EdRBҀ̘<\HCD XvcW+Nm'S^pX^څw\I6dRuNuV':? Me2($;W'-:$@Z~\dHXDpcr.Xф 3_< \=P@~@s!\)$E8ܧ)U1xZ 0Vk:?|ҰuX" I+># jfY+Զ MZ/>czã?ǭSP]${c@tS`e}{ ۣoo¢ׁD & @c\{-z-^ҴoP*F+VԶizu!2(B=(E}:JE?i.rsNkeZ\us5 kSK'k;~pwh %$ ٍJY,No2.=G53\A-DD΢*o)O>Phc$&zFlxpAE#N{%~>_RpP" M}ժ 毌N )آ9 k:z/z~@/++ZGkqj ,]?m10}L5߽x/^DqHo(i9WY((ɀ\ZҼoh]ߏhI5K `Mq(C@z9c9g.dS#p5,aXcmQW*lz.`i/CI1#Rf'~^/]͙FbcZ舎)ˡWK/9ѯ{5GTS!` '= ̝ޟn ]K˽_4.qǯR&?Ȉi@J29&f|>[V1év2ZU@%=Ǐk]|*cXrnfmt+`,/{YMZLz>sbIb|PW2p6bgW{f %8?]U]9'hSCan0p-w೟y1n{kGqe F2GYw]J:Q%/ 2 ݡ ;":)L^vcqs&-Fm7ffLa}4QXXl4}bv ^.zHּ9Z]OyEV *LZ yﰹYz"˺F%"~5 vMt|zfp8\:O`ٮmcaWEU1&})P`ขU_Y~L!SLq1)u9yi  QU~EV|  8Gmg_RXl *g8p:rZ0l^ ]z} {{9S&F@00`Ew[(l$[?*TdwamA9cm71k7aFA nv)1$MYEʱ RfG%؃~2VF wU3MSt!'Э(}1a A4hBK ۹]$}2uVPV0WEh @atFs3} ciFW8rxOƟ(dJ NĎ [C)1Rl%$r {?fA՛^_^ f-Ɠ dxJi{\A%1e~:1 4D4EPs V*=B:gG\k6plv|O <;A1=ѡAX`ӵc&Xc=Y@#@%9?KDh†_0$)Or]@`Ě9ydjafjWDù'ātvC$^"!urkK#I5K `Mqx#S20: ѻ䜱wifr؉e5\4I=x+beg9{ JSM+ #>e C˫'x8 p qJ zc+"*F}i;P"13 7o)k[ +0>I?FNTߋ_\K1C(Nk/^PN%) +2` .GXK,ND t=B"^@@`9>Pu29# M3/(8dIrG˜fyPDF)'xI =H.ue͵/56︙ l=cqu9vG]t9u/FWx IDATDT +Mc,\YH]C/1 Kt 9 5hy5FJTTY/l?$e,' W6ހ?c!TPoA0#֬7Үʼn߳-Uu̖eRL=cU@c?-3ݖ?!sʤ:<&IRfSIצ>TAm?rNxϻqߺ]s|# P-LuWkɟ͕XB [L1rO\TQZY{}Zh&k+FΈ=Q #SEPBN9$ۤfZ?aG6 d8m("a͊#҇01 +t.v8Sp>Js_(aUGHNb9Ф73REa `&1,ŏxs5*tN( $"U;ftg1+9% ]D#A he/6u6w{{$'Kf=H쎰k #K1^Yc,L5[Z SO~W~QK)FB~ppn`KlU)|T#4er|NI5ŕ`Mqh#g xêwI?V`JBXL1 ϴf4Oվk"{k]G Vs޷:6bL~e$2쌜Ju/@h,⨣0矀e CI||-eXPpUm1%w5&a`1u4d )¬Ĝ#(p?;^Pj9Ded,vH-X{ "pLٌI0C*T n(: {N)5T_RSy9{ U3/sz+9`Mqc,gm "e TFFdr@vN5*eJNeH(W!-bɒE iཇ}$R^S<ݜAu@D&){a\"8r)"8`UJ\1CBqڤMbHҌӦsUbȏ*掄1y@l,v"sf #3vO]l@F7B˷!4\IW 8rvBJ`Lj>' _ssR"wRw`fG>x#2K{Z0V\ZZ=\Mł{ͮ;,s&鮒`:W@s?ׯ{f vv݌BHh@^n>`"`Mq#a0|*y4GΪٻ|lX`13fTӭbJ|ݏ)p3a\ )Ucƫ^.e+lnvlHk5jϭ]6,Κ=.k㡌Ú)3%vPꐆA۶fƓ|ȌP@0B:+ۢ| 6r<hΠ:;xpPGTBw׼!<𶇡 =[(8-Xʷqkx 'F595)E-Moitez_\ؑimmҞV@FͬIlkt}"r_qrgӀO}Tl P 0(U``EOnޔ~#w2 GYa+Ieח̥E1<q 8M!T@=( :kǢԿXˤ'(*<7v.,xY5]VȲxpZx?CBhbp;_5UNRcJNq,0>#EGtE٫=fFA<$[=D? mwC2HE bd9P?QնH9{D^BhY(d)!d^]^@;[ifGҌ58ED{J}Y|sj=GL4PKLXfgi~ݓ/|&Gc)/D7~-zӈ_&1~TE8K `Mq`XUk{}5iL͓H p) %DGL>9U=?z !:x6@]ᣘWxdm~(?aTf.Ua+m%]IeGt⹋_F_m4VfzmaԷcܴHo@-cg֪Zd䌠)[1l@V =\ C@2T!-d" AAQ L!h `@&6hKAoֵK"*d0I Nv4N.zѫδU{o}NΰOgJծ]ުDL 91bw4v#7qzP3RߎOvP2wfn5 }(Kçame哽[>YT +ChE25*Hcl50½xJx ܐ+R2-24 Pz dgAA\ػ%<#7RY- _/@άFu|!Upv(= ci>q b~L|nPpeKZMZmkжq8|Er- WN BҚ&x´5h.bӎ4h1DL뀰cp'N垣dx=.L:|QLYePfn{QL1PCn#ZqcwN[X:皦F]aY]羴nh~u:3bz zEχs^!,>+xޢLR0y*#nU>PZ ±%;D瘗L2O]LEbL[mJK r _t\.Y!b}NB#I g?tx*%1;3 [ɅgThU679&{HNSmaB6LhZ L@%4xܻ""[ .]4 '_P +'1caC1 M/حo*)@҃z+!g ڔK&Yɐ6m?L jVH΋|mͣ_%q& Pt˂2GMs'ˈF^)H9+(p FDP'(vPޗU1 ^ѓO:KDCg;BΧ^ tn`mqka3e6zZ3E]3uhKiS̭,n!Y;p5ot_Yʒ !c x뜃[^cˆάTKrѼ2. :YBm43'gڻy)X0N@xCyKjs?2(ZP()R",pN08xePJp^9Eܩ'o,C1°(FqX%s:A_߽B8[I8+_K*}5o@{zԕ3WkJnz_dT@Z ٚ=Q\ RC9 '5TxL񠲞g *6,7zGry\(T+g l91 )%\C]WQ5iJ?PP);v15NCa|?X ;$ DdT U؜ga[FS^B(KTnJ/+}N E 4FZe 2qsRM(BgJ"݅^9EX3s>J{n ,J s7\?`/L(_{/wPx(<6 ame}!f^@:(ae:RS Bhw"9;RJ7`ϓs:* yIʫހ?_Is5-'HeᝆT|YL4Qtȼ.ᱱqL(F&HB ZZH&BHhM#h $WG9Rbms-?OmK^B3'Ln0B"y $G~{pIa6kᤁ?GYoNސ"j=@#+cj8UT d9|WQMI6ùhȭ֊l6J{n= iĊga54,YoքKA6dhcxc 2K8/ |r:,) 2`Njek&<]$/؁8fw5D+'RC:'+HyLe=pةuQrǦPs*tT01'Zc8BVI],|ՓF7Dg,_Ϡ_HԽ8[ZQ6_xS}|t 99A&%Jɼ 妋K,{i[8^g,M!= [|)<Yk]PJ{$p.)X/c8yȋ\ACʓ%'*9΂MM褢i0a8& 7'}6>ɷ$ؿ: !#!/1 `3PJX04JhΌ  s8ooLjn:'*I4rByZ +1a2\L]_\< yT" b?X0:'Ў'#"Gj[JVw:ʞz6 `ϗޯDdy/`ƣ#PDY(K+†F*IAc$R0! gr-ks;YtU߽/xI͒2>T6mLֵxK}ɳOW|u1J"!!d<ѦeښK[m&n5Q՚i'데bb6ڤDLPFs!ۅfZ *Y[?]BևɨM e(=:;3D[ȸKٽ&51MF8v@ZEW34G={V$dUǥ*J cZaD)iMi(]H)5 cqk=MmTI*JDnԠ4YU5ħ>~,I89bǒJRlrWE8sRZ䝌h m6_+Hyw!U6xbwyK DNB)YIDK(8Ie5 7ZWP>/FRQIWT TwȤD e2e7)"MbI9u XRy䝗EznpSx. Ji_W[T"ȅT0FCJB %t c̆35{>waY\y>O>du*5*lMߖұ;x-\f.p IDAT+!,SDjkOR(&U(:@H_6xX^?۵)Ua-m'+o/MQy:iwxST"Hɓi);bRYJ7``BNRHh[q;o{LǟmE%H"J4] )oL # 8Xa!cU; m02;8ʼnU\՘)PVkhtV<P\Br\T4bJg%i5{U mS{@-RH?BB*u`uagy\>OV $u~%-p:YX.X_A?9c8GW 0 Ny,7/±Ƙ*8U`I#Xvg ޫPijx ϸxn;XKUÛpBIRĜa\VfPb^$n_q7E9("}SZᙴ*/&X"P ; *Ny{Q ΅TPuπ2{]8gH"t(@pwRp|'o: "Qcsc~v:S=^oJ5:5]6&x3Ο3p:wJE*8{UJIzk?W|5764DNLB%KR|t۾_Kw9GyHZ@ ]PXЬx p)|;Q_o?gW>l٤EçŔbOwۑxo~'X"JblCNCɊ= \ UE*fKDXvY]c#g2mHNB@ GN#nJ!XVZޯXt7˖$4WĖGVsXnyW VhI%DIS] *2+ZLƛ!CVTz^5҃ezpYк!D\IR(XgB mYNcbr0$yKx!hxچL5$15??D6x~$; [J%˖ 'ʧ%-,[Ry^XJnY\)6"OXPf\%%L HM^,D Bb}89*GbF9wH!+\0X؈+p:{?V<>Q>I{Pn`=V򖫳SU`:yR,t7\<|5;+x!Jqc5+3N,MCA Ā̻cl̉6/ RkƆWJo SAm6Q71i6EZ*)bvb%8^fJImM|:u~|. {1fJ%m " pب|wRu%{Q2Nr}@>G\=bp/%`q|4<ڸ?/YV,bx7]༅a&O&<+x>Oy1Dv vӏ+\ BjKdr6f! X=f[8C ZPL|Mãe5*$d &R༩40Uc =g-Ц`, Lq;\xEeuNxHuu<:)Z[x.#?N!N×]$p[>NڠW gvm3o7'EKDY9# %\QV8B(7o/g c"Uΰ"bE )A"%i5W=E Z6ӧ-$e' I4^VߍxOQm* &ZNXQښJk( D X71RAZ:a/ͷ >{v\_Ƥr'Dk3BJ9Wa-=jdУi&.^}vsLąJ/c4wRW#eo5Nt?)Q=ib`Υ?STz6~9tnƮ%8-ѯ9WgJa=Рݝ:"rulۯ/ `} j+RC p䝲H+OW`GcC pSkᄁJq\ VBĭ~7?2BcQ2r= ="k{R* j8B- ԤbţzGN uM* /T!dY.ix6'Lr%"v=WRjHp\ǠZiXe$4grDh9 p) E&;)WIKݰ)hC[ĆjG;S B`y'k7W/V $/u4: lxvn vM;AN`c!DU;L+3pNkh Ӧ*MpB|z=^iK0OEQBȈ ֣fPU3U##uM 7cJQv3E/M3Azuկ!t>Մ5㋌19ijut?׼; 93uIU"]˽YɇUR v E*0AuFx٫{wȘ =;D*Mʈ'"F*e/y:gfhɸ,2BBRc12rq7)!|BއDyILR, %A GĪtUC誗E T; 9ȕ3*jXgdৎOSuYmj8J=K( ,_i!'  w*S${$"S!+4P@^3ȇ¥n)y!+Va}H\rg|,>E*=Uq.~Ld IpJAMJ)z5m?Pf@SB9s }h`LRyCy}a7 ,/|\s'Ix8/+4+TV$JM4'`SwSt=|.-VWacyr ?yBeAq6 'CȦp詂,.iL4D @k RˬF*ݢh椊J޵t*-aǹmwoTi CE,Rx޵_#u7n=8a!✼8e,Ѷ!AӶ]ڶ戈M3Prf4,3UQAP7)xV ~v',"tPḈ Qz.*L(r)Ϲo}{f+ EDZc0+r`Cu47EkZhRH?CR_`-o >umFQ ܏oR7")>A2FtJD<OB? t^de9\QSR]ygr:ת`ɽ`_wD<^D \ߚr^ i`f 6fvɗ=9L7&O,Y'me–RXǘM}Lo03`8/b8f lPUh=g `!l;D[p۫=3 028„Y$m|n61 oG^?qǖ͍ۯߪfrpi9[mkFWcȄWyיx v e)(' yM1AAགྷm9dS&fǐz~ZǏȅD3;6?VR'8HE gD(o1܄ A݊jUEHU5^5@U pqk ʜ+LHPSc0Miƨh L1͞<߷W2S 7CNHX<459-Ϝ$aQ ` /EzbS(YJC7e*WD:VM3Fl9/)rA:ނJ'g]o45'a  !J,BH=dÑ%s(2JkFǤF"ZȖ򶏓>[ǰ~! z0'(A@݄,uL]IYݿoJT!1+#Z;Iy;y\Dh["Y\,(8[ݦ`_:OO\47dq7_K0[Dt<Ap f"m7G;f bV̩P@J]w}"ɃbT. Uiizs9&mah-$+X;-hmʘC.4jgaaz+V EX?{[G÷O}:2pӗs>^zs^Ò v ]VNR+A-sp筀_R 0(%3;V0&E0[Hi&bJez1eqYrJ #xN!b"eDZ!n{\R4FxO6!VO\, B a*3)8W\} ;ߝ'Ud\pp)˅)JJ i(9 gy.t8 DA}u9z,&\M$>=~CEae *WԧjcH)`҂3q[z?>s?RS(F!0*V"ֆpTs's<ٜ}F8\ xʷt& *p<G"a5l%\gE * :ޤ !llV)8`b%ejgAt0oƹWuA!sQ؈IO$+JL9;~M3'~7XٚİSp%ς !R0Z/r»3@IU,"KD1˅6<.r([Ш"4'}89tQ2 v` `Upμ,VypN@$( V<.u4 VWj_cO N `+^[A)"WreV K('e=2i*)B l,C8-#ee"R"[6.bw` HcV W2'Y8kJoBx4@ַ">ѷ@Z,,$"'Q*M!!A]^T͜L"Rdc9>p9Yc! $crکQDi*0Ƒ N6uׅn7 #(YPm݃Pgwm<km k~? DtU Q6 ݌}px$NNBWu' p9Lh-B^A"h"W\BH!q~ko v/x_dc:]K]2H z>u<*M`_`<xrpSh8 w#$ߕ4ٌNILV_7kᔁbNSb+V2~h[U+!CԢ!N"7!8ݺ!2#:{ǽ^(k8Fթ, c(U xKo1%"H>~ĺ6i)(8U/F])(q]bE "Dнk ,RڶFEjuݠA6,)kZqcE+ ZnB #WD#pQbE㽈KFo[.VPXQwT, YY@:&DU( V1T)‚Ge`{@u=@Y8i`q[-. V`cǛGs⽃k,be[2 iX-UжJIN=ͬ͒ %JA8lRv dO)DeC_݇ØBpYL٧!=\ liuL)bVn}:^j!$pL *X-Zx8oarI+nD>Bv,aFG*9d2KAsiXI#'PZrF"eJh-!>p#SsA WFpIQC~>|e,4Lz7zz}Xעm\i8Jҿ0E73кj8K ZD|b˨ ,>JE*8waA(yDB,.GE].)+fpq'_Y'&OŘ7!e%+(}=hKjzJ_5x҅y*Q}*|.um9n1^o9n nvGtq(dBe;+xἅĵRC+4'[AApipNPiOBT 2OsV}">[YؙeM"Zc eOŝjm"%|*PwFz4:`:n$,عH/@?B JavXana@?8LsZ_o6Tq]w~~BʅDL ' $6X1Hc^t7o;T.3b2ad`b"i*Qrvƴ<9trgA",:MRrqLs8Y3)d&J)Mp6Ih#A3h-brDƐR^c\qy v DXж+S?(˫8qlқg]8ӟ5˸eP>ƍs+[ʅiN&<.yRgbGr`S3<RT'jYKeʦ:. RyG4 ucǿ?b0*V˒  Mm,%bxsuk݇:`.7p~Ӥh !Z6nq5KDCn(X6+ G=PZ`ai%R*'nץpn-}S RJ\k(iMxbA #yV .ۢE씉a4)X - yfŗsE. ʕPk?^T<亁 Ғu˃%pN{u9U6Tݲ"hz"WvXhI)\y|gKan z5X_kn?*樜8h8ʉk+Sm)'#w~퟿7׽3~[y>Ov 9QVs\FHR3PVu8c1pbpO;/;D}Ȧ /#QS%5JCݍ 8|TެQ~̏*ΊvB5M=,zҋ7]2 v`Ԡ?JfD{zy4qkcy2nG~B x͡-LKA([)z)eWޡ*2K9ֶx˟w0kvszFN,85"PNDR g^)Ed) 4Zi*:o e4[!bғV6Ph@ʖ,iUFj k&U`V9p^p=S)7w#"rV(7<+ x\܀>_mu]A!X  4z:z؟~l5RJ9 wܱ#3|948$YUxWl;N*l<84dJ1&2 !W|xu X,6Ӝ݈\${KYUiD2aۆTEX(Q@X`8[3/*'DVeP񳟦=X"-2p^Bx% (uՙXPBMi u %z!"SP0 KxxNɺCdZEe MLn#Z4 aQUx v`<r2S^VN9L'k_xT5 Le3wR,'K)!t:`QVA&_C),&7jlrbcx~k[8g} Y(kT(U"B5-Z(Sqe߾ "*e2Q 3 V[ԫ@1WЅIeyaQ v^?'QPPpz5>MM^_(]~iy\4"puoO! aDwǦ< tz3U97\uW=9PHh ׈ E]m)eLyƐreC۶J"V__G/ uMp>Fs=({i, WkL.x㶻߈+oc%C=gpzWUPɲ .R bqrT,gm'Z)ԳT" CR2ZD$GDOuֳ`=zz_c8G݉8zb &c|77C1 [HV;T:$5PRU`]l;V*%!1B0 2AN{K Qqy v`QXq"3V0h 3?aխM]6 P:2"lM\'z{ތOGPVf,Ԗy]SlC}%""^{`;KDCn}ff#`4C8" n'MY~p"W4ygqs:~HZO+'W{^BtXxzaU!XB )6֛Hz}խťz}TNXoRr>F Z;?{ɣp~/}^ݒa^* cy<.kJnF˥@!fGx K]JVyxソYZ :a~bANx_߱T@B0ĄyR ږCNVǀ`UPPkS߯bfb5B /AX_qku)'tz3>Y HaGIҺ4ҸM/|`A CD/|Tz c|VQ>k&{dťS-H%x\֗ߥAE*=UPPa}J_5(%xM(t,6-N9.[~OG#ڊƫ~:FQ  *((xL`g)\Kj+ aZS֨K9q_?q?R*(qwV@!X l[l[<*'88}3X<@umZM~k8 .IOY KyRC!XKr" s },, x`,r9q} [?rlKT", V=ڢ~xGN僳3qnXuX[ĵ֔Ms?-ڢ?PVh<( *''ukn@aiyK3Z+=宅#`16 *((xB'8q|+\a /B`։cӒܽp&]0#X˃%`QVAAB=8(U~~ _ҧ.&Q*'6Vk@̎*(-O, `iֱPi> 8| oX_O<` ,CG||*8_(`bugp-1U*\xı VUʉO b  N`B -Bփ_Y8ziy`mʉ)<]p ?6ӞgNE*8_(Rcm?*8LJbơ +po48vdk+5c|8l[ G4d|ms-|`ÑƱ4=:RORʉ5Vj G=,xd6X=+]UPPPpooxC9qf1`FX+5>|ؑM\|?)[B k+H>4_q!=vuǦ(a@?ЧT|sD=5xA &uk8G^ERqX[Cnu^ZY,WySZEX(`1hRbK3XX?8ppǮLr|[8&+*XMQ v`Gp$F;P9qbaq\ù.th)Ĵk+S,. N* V.GTNnX:0dkaiEpfTJ9axpC8vdsQШ)]F!X!VOҠ K<<.(eoaGp* ֣/I39(qX20µPAV]ʉ۱zb !ot|G;v"Q"]OdUPPP8E0Ȥ4ˇ 4bSCc5 !Ak\nDFQ{r+' B9 X>4K݉K GGc7{ؑM\xKmKW %^&W@!XOHx2zqPFsS)'86p!ݸ`OUPPP0^o0^o"X>4AݚX><\NP9ȃcq#F=h-;3Jᣏ^`Ifg|xL(' 1؋ĕS,-`GN/smrUPPP1L'xTNp!cqiiZSyp+Fʱ Ѕ Dhb+}&*UZK,`,x,r9q`Yz"Ûx3`iK{1?ثq 'C!X8}xoz8q'ǎ`tMTZk[˽+hjn40{1{1Ih¶A 9g-KYU7*'ߎ9Of~4Ҡ?Rֶ/\lO`N/OmUQdX,gKKYTb9/5q"'~V^a'>ttv3+X ES? C`tg8qc+>WJy#zA:##27n^WlϾf)puE`~lj=^5bVޝ|Z8qkH[k[`a,Gn?%>{XUlUjNYRstZ{zS󨫨73~6y E#E{J޻qbɳuwh8FV3gSW6޲\%a<(XkhJTlmnTlY锶oھ_Ty3Pۏ'YJ$%  j6j6qtE2ٿUXϨPh狢MeR'_-Q>$u:@/~>Ylml:siS\S}r^;}Ëצc¤% 𙘎dSJ׮ܜ~EMƃ c_^]t{lV$ ,In]OR+;ĕ) ,Mz-{u=}q#?gI[:'߻fُb^]A/>9 ,ph49Zjw-84IDAT*J%  sg$e,nՊz~.=aG@X` vw*zy쨇EE`^ӍԸp"Mjغ\eҖ]dejttNnV8\ #=y~()>u(z]Xѳ^C` zV\'#7 wlIDjZA˟EkH` 캜ZJ6=Wa$M6OW>71!Vl#?pd9ݪFgcACw/f"B鄅,+#s**\ z=xP ,%@Y.FB!.??CȲZ-U[V\(ƣG>,Q<@k<*gGC>ǻ !r` VP*CȲq"K; 5ʲ^[ree@JhgG˿;}g.AwvYW|zB!fA??RsְJg/z=+P+FcFUWyMhmonZ`˿Bʣ"B֗`i]^Tg5Cz%Dۘ3#sk;Px.}UlZ!T)^Z5u=B8?ja45}y@CBeY2ԁB!ݲDh'..feY?V3VaT3}xk#B?gr}ty Rzz[?6QyEG0h k;Ѕ5B!/]^}MSc<>x|;drCqE!(1Xm1L.Dt1hc4&s4MyEqZ^B![˭XJ\` Tu=NO_/Q+sBY" [A]PUcTu=šW/C! uz߭K%Ku=-B!QbBZ3gcB!S>jfB!" "B! ,B!seU3B!;`B!, ,B!CE!`(!B !BȂ"BY0XB! B!dP`B!, ,B!CE!`(!B !BȂ"BY0XB! B!dP`B!, ,B!CE!`(!B !BȂ"BY0XB! B!dP`B!, ,B!CE!`(!B !BȂ"BY0XB! B!dP`B!, ,B!CE!`(!B !BȂ"BY0XB! B!dP`B!, (3 % Z FCku!\;%TdBQTjj'c(!(H `Pr<ϐe=r%'qˠv/)!,'X1RV4ՕFUoy+\A)e@ǢNxH!{(c+f4MM]y!Su퓏C7‹BȵAE f뫙XkxI rp3r<95ƠhmPt3BY<XF4hy\!3+ f̐9+Z4g"B ,r.&wĦ~f3̑꥔BY*elh*FGW#!6(ȵ0k`<+˭ʋ E3ds~fMmB݌B$XQqj.1ЍAUi`خu3zkߖj6!\;N#D6g ɤft32V/fAeM㓥jTS !6X1ڄ,7 _QXty ]*Z|*nFBY%(H(#yj.ؠ.(2d.jQf!wWVMp1VUD!vq%w.1hq*Q:kʜƦT h^ !dɡ"׎16ciXvC O)܋e/Ce(zYp3=flƋ.0VO!K%D4cPMqxU6}DQn7Dڠ.Y(!z"׎)u3IP=`_, E Ƞ2‰/@f]u1X4"v`}LjL܌ZK!Q:˗]$r nFTtՆ‹Bvvyrf'XFL&M M!Qf{ъ.o_UT &Tf$+CE:ú5ƣ:_g5f2.c̰9jUM4 '2 ܃J)&f('݁RVmHn*\tJ9|&86%NqޠP`0PJ!"8Bpvlt]B ,B!K<-Rd F؊c333BLmN'9vl|P`NQBޏ7.p>Xd"B֚wq1>z#֌wƭGXP`\54傣`B>.'Xd" G)\EË g@qF!Y.(Hԓ @c!N\Vvx v'锦1AMHzsեr4no?Fyg(HKHËgP0,XSLY3AݻL@ ,)Mm䥢"dy_!`pF!Y(H(MHpS`"4ӤO0.+\\ȋ3 IP`Nij fr'd6íԊ!C:^@Sk J n !锺AE5Cfy/C+ ,)tB"40he w y{W7PGIgP`BY9^~gXt霦րE+!k"-Xpr^vqk)BE: E !kL`"~q@ -twr:5!ۯO1؝\/HEHYtg(HXN!gN ,9ur9 YWT`x  ; /YpD#(/!d=X.BϋoϡbtN]; Vۑqx66Chs]NȚe.MJZsh"Ycom}fv'G49! W1=>gNP! ,9uBY]Wao~wݙ|\(H\왐֛Wk=aFfi dȋN>"Xs",kB>:|u sE:'܃xP'\9,pu]>Bs`oNMH>XsJCA,9r=p~Z(3ܻ?:d"årYoE'z^pD#KDwB֏9w6uw&YE9eY`6(Zb"KA]ٙ,!\Ͽn‡?bPx7B键\08:A)L].<ߜǿ98JBEՋs_W}!:>"$|(usx OnMU"7 ,܇^}Bkg;w79(q{{X[ֽ8"dY6!|BE ,/ pXϿno[۽ wᘪcyysBgcm<*xхEXw[bYfػx.k!;=f +!]+NOR`w,U(>l8|3!}y֪Ν cϹ7o\Ë8:خc<?kC@ ,|D>륈so3n'^ɘ\,eAקx.>:AE`-E*<]=Z Jlx8U:XG8x}x.B>ev7_wq2;2X8pz( ;}cwow l<׽MS8|}N89f=!1˓ɽ~-xDnX̡4^qzg_}Ea. h m/*Ep3BYv |1^.+&8:\ąͲ:9/?!"KC];U,E_^hm`h6B<^"d9? ,r%(PU 66 e 뮫Axosv6k{Ū8=s-n$]ܼ;?p;}OY(i&urkƾAVl{0Ά w :`Wb'+2ˮ`E֓]E!KY jc/p_+qwoۻ}EAo^ q|8јX7?m {KZiY.PQĒ%C)c;Mw_O?ߡ"BEnq~>]纽ǝ ۤw?N$8x5c(H܄2ǃ[x8sNx9NG89b<!#|}{Xd.Xdi >#U^܃[OrF! P`B:粤J⹘,Ͼ<ƒ[x6 P`42CQdE&E]}ˁe͵`~% !0+)O7,` ts`X?w) ,dԵ``1+IQo`Xmyv/~~/sY*J\?Us1+2eïE!CEgs/͝,&ESD0k(`y>,!;ɒ¤#yWHaZ>~KP`b2>oMrs`RC)f,Xۿ??})p#K-XdU`Rgxt?b) ,0"Lj%Ͼ<“;xtkM"KE_dXɽMzw'OwK&Y(RQ0@ӂE֓s1)ٗG?أZC(R4 τ⹶w6iIQW-{BʆG[3(Rqii=kZƈSQܑ©ϵ1]˞u`)( ,Tԕ֬Rp) .M+90)QP`42CQdk sUWXP3Ej* ('r 0r]2u]f} >wC>2XdV<_s.h1SM}*UeD[SW(IƊ ""-f|BUM}y~ro,kI"KGIx?@ʤ{q[\L5{UbB_N?2iڢN",%Usuuxk߃[xNWFV ,tUVͤ.3$hp~g92Ίd(ejJcJĕqxkw$ETYpf̤⹆u-E}yQ`8Xde"D AN0!KVQ1Wq8OL_i/|$SV,r܊KR'Ow>vREgVnV^ZP`'Xx!I͊;OtG;mYs?܅1L]Y gQvUvgEY))")(V ,tI(TR}HtӌCi翚O=EѾUbS~zŷ"US}z~[RԽ4k ~?ŃP$W,qsaer.lx*'W7oE`ijfIaeUK^xo#ٖOJի =I5C|R1-Dиsiuǐψr"KIQ'w]_\yAEy"RÎjmVʔh02vLvDFwx. BEEU,XSDQb6PlX\S5DJWZZv2_9[*1ڬ6&Qb3c9VJL3)g^T?TI Y*& zej݄Q\(:2e$Iy{/;eDO"y>x>}+BuV5e|4;j ߒ]ݓ>(v2|gL2C>_l?֊AERe3Å4n'J|sx}cdYM IspPB%:'r!Z1JmⳌ0Jvg qeRFCx1~M^Mi?k,ryLfsy+JRo:?"mw,U M(lSWHsIKΙL) QJ1ȘrKFfS`J醔![^ź8Q/2 ˟ƺ: SљӮ:Yըq"Hn*swݒ[7ώ⹶w6l&V<׬n#Y2?س QpD)3x1!d4NFeiw!Tdr!>HmI1">HUʨoIЩTbظ4-S -0ջe/*NdN\ٚzgNROwM2֘, ,\NfCOa+d%zd(%.ig.X[!䪈)?&ɦ{ʡT̥#GFB$!)Yق!Dj 4Fgc ʨ(=,{sw'Gl4`,,.uwo|+HF{!Q'd6Vh093)(Lx 2K1iY?RX)IBIat-UsuebF\+3!Z"W2ˇ>Q!7 B,׬*j{pd;cŠ"K! tF,>~gD[p$W2ARxSmC 4h&dE d2 m}rTXJ7]B#x˖K[l@7z.B҅CTr󠋐, &1 J(seVt@eee΅愆r:F"2%1xߠwXb""2dZBѹ2'MRDCF3ĔrF3AI1DҾ+y[6N@6;^jx:l毋oq,لV2ߟi,B~/` Z[n.Y5Y)(RbEU+MXF^,a3'/`BV\e D4GsR[ª¤: 戽1U96Ɖh SXyc`pTQtuþvRж:_l@5<L!NwF׬)'A jB!Y*zd f^ Sc ,g)DL+:ê642Su uj\-SKv. kЍlnD..NC۪(m&VwOXl^Ӝ]fW˗rIJeȚ[uue]QPՂ,\ۺ+.ʮ7m8~#oF{3Jq Dvh&^A[|]6h[Ħ D!Q gau[6<.AS0kѻdMkӆ O݃'|7Ǫ6/ِǼ%YEEi*0r} Mv4!o߷Cx#-XdiV%咍Ĝe16 =G.֛`oy7ˈ[g'I#Lrha7WRmݤ52-8PYgr@LߔVYez)tm k^3ѿ'-\*ZB+ 8=<];g,.+^~C ZV ,HqQnBT@؞ 3LgR E^`sNVF##1~ntKg)̔Nmi5[WI!h9nqV_% nQe_!C{f0SQj+ 0y$LLJZu -9"`jP`Ι1N##G̵nEG*uD}ZFgT,+e- &4%B A|0\CpIZ]bLb֊|/bf8agi *E6͌ϷE!RIrNC[8bn߼@?+ E:>ȝ"˃s[M6!I!\h9\^x Q5śpݎÔ}!zHP)ܳAJYZuCE|%.[%6 0is.Q"Be ucӦf/8 O6oQp.3}qP n_++T|pL oq$bp~]Mgp5"X܀uzx!nѶph` 7R&X4n܏y^%I)/lVO2]Mj=tS4ώDyqpv#%S_30A'FlCM={/Txq#D_޴[q:HJ#ID[VvG;m{v5=<]͑o0dfk|;[U \>,ƻ2͸1/tqgfJY.fz`тJP`Lܒ1e'ea3[-Nq֭}{_t^X" $s\\T!/%Z?/3CL،I'}4ψVPHh}qkBX&qXNi1Sg+B1aB'dRMlN^ZϦ#~47Idq!Y(H'̴^!ng =ejomKRTOD. i)9[0nT1ⓩKزZŇJ -h+8G=rVmDeâE̿%B|ze$}(ފ*֞ 6Y=ܳbODo"lMls_tmr0^D aEki_de.PA1  r'"c*"y VvDR@ˉiNgS|ob]Y\vS۳Z(L;;p|ejzV3&6|>DY[s[V MԳY >eTbr~HrrĕkkNf9R4S~V ܣxYޣD=gCڪkߠR`㕻_Uz)ыDsWG|M_pB Y:n1Y终MJMX4\a ܿ[&MmFDXHň8 ȰPmMF?Bٷz-:ooݟjn5u]t2|wRW"MF6\* dԾ}~mZЇz/!=Kj#>x(PZ*܌OC VH2X#E=1޽Fctui7@ڲVL<`It):L QMm`/]4k*+X:,V+BvJcB !+Oh!Ԙ+/δp Hbf IEκL؇MJQdP߿n2/J+3# ,JJ d ֪AEōSTE 4&혗CYփB e)k)lߦjn֌\0?*rK"B)dXq0= ҈B@`ZdL=ϰ @]rooHPKX {ruKhE: YݑX0] 7t-,%E0tpT 6C1>&4.>"E :B \؂C&p_nܭ_D4#ij1I<4=%!t-2\١7o%\BJ׼"Q5 O{)2&6ZbIY ,X c!zhscւC85cb4Sz9; JMe$ *\'O Y͸M|]PYr(eQ}q|ۧ/T*M('W͸B)Xncrd*\[a"vIn`Q k:igVBj)[n4x2*,ZҲ5b)yo?-A=i5/C4xV!'mv8EĚXRF%fӹ`%4:.-D.|J anh}Јlw(yLwwcǴBىj5Tf3Y,+g%LSZkiS4=m8pMxZL_pgoFؾf=܄ -`5N3{ՅtR r 3 ܺgR|2"[zVu׸I2 h1BbKXAJQ% IDAT^! ~e_6{5Ż\u씀1Ѝ\7 FgM(45THDk貚&IB]EA{.mcs?+{Ob}(_Zڥv` h;VeO21@6/oN^T*uK ,W_x1N^{&. $E^^=IN;(ڴ^p7j򶳴hW8a0)r8V$c0ğ‚dLrn  Ld^pBkx! 9YNPeYi-7by>2PzC>7lx4nY*|FX_LoQPK~)A]Mz yo`#^q`BPMxMeZ}hD7^pxq49n[2!-Xά2/m2.T{2*G5$\ޚ]DKU[Ԙ1-`ldsȺF6(ySt`@}JC:Z08Q\I OҦsbR2SO?vJ M_uUA!oYeD@f/-LǢSQ-tv rݛu"U-~v38;tJhZ](H'hJ1iuQgA"ɁhgR.d3%, aZ.ͷ2 7_=K*q?B쓃6G=kR¢Kv%}tn UهCcκJb7Ouj$Wb D@!*B<+qY]Emۢ,RqDUviy[N>v}DufՃtC,eشG^8K thOny/Laޏ DdAoiD(>>=79 lM }6b  c ņodE{;=G>q /e09]{Q7-Qjɵr%@HY6{lwabB?A5M'@Xh2V"]‰(7o_svDk"D,&]=(HǤ+; r{'@TWG8 yϬW(@gPeq]<;,ΰ3 ru |Z.s DAaDL)qfz90p "Ӣ+NK9vjO'E,7\ֵa^SQ+WO5+ +/$JA DR&Y4Y' ! h1M76h2ORK_ ̩h={JpiǃR^~1 &1!㕺˶g>EAY,BCq0ʿ.k RĀg*4 ZӰku@nw܅$)8[,_ ;Bp,!/@vj?ճPJ)%Dkd*L UT#6;[ KI-^>@4پVHWr_x4v /N[K5GL٤*jw1: ~Ĩm{t1llL~=78DGnЬUwg *Y& +%s8<ѧ3F(rKU',?q)}Wg!jL@)]5YgYe[r1u$ <@o: Pq1i;~ UKo iA/o!DL=ג"M [4&1qz St 4BSg]Itz{!}+zZRǠw 0jårȵX?> UT˪`ŕрUBrAzd 3&Xq2QiwnZsQ6O@젿}N%zqѨ 3W:ΐeрp{^wYQ-bk檤c|[bl[]g,{Th(dNPvmΠ[jǸrԌs ^|-箤.$Rh }]i M4ʖ.FiRVPeEX*XZd&mhXhҼx ?TEXAUX=k*M8No fYf V\3|$"K˕Q|"؂`cϊBc&BViL2(P'Ƿl23ٶUZmbՔ8^ֱCKRFV亵6B6´d4Ik%yS[Lc{s<"KZL"+|_[m0<; d!κ\4nYEִj fZ fv߻$4ΒkqbۢPuy !]K7duԒծL +y6uLnۖi^Ǥû ζg' DPWVy>ЂP`NnYطba-^z1P}|e>@oZwnψ?R&k~n4g> h dJ-dJZ&s![)Obܗ=x'02ɠP@!ac_{ujo &x1y( 7^)d,H1 ֽ!ySmO'{.S,b$e-Q8<KZ0`t~;GY7fro/zCZZmhtx8ny$%` Y,w,vR6bQn/xz8>4l"F#2T!aK%`+1*7z׈{'SB#Մ#So $*ۛq^L%6۲4`g92؅m;cQeʠAav©ydx_7&1 1g6>%˞d"-RrX]L<W Zmm>1D3A?]`T>Pʐ-S6+Bh*O~3|f[*wWZ< /s.BZV ,-.[ ~@RbTvp]*>窀R9,K=x(3,UňYb!BxʼnFL"3|sW"$BٔUeF'']:Y<ǝ8||r+߿ߋe_9 PD1^+1[nC 0[gFžYg=-9;_f5ϴn8r 2A6VA+ O!)B!ĠB5#]` 1x5Uy!ˬb~P}ͻ*d:,O.?y} @StYz3DWJԯ)MKS5˂yR@94!To\[Ѥ>Yxn\pnY.FN-𻝢MN"H-odǖwKR T\-Ea^!Lu+-9eLF{eQ6oqXi.\m:5pW@ԃG:JoĈ6vwIQwmWu.*x]Vkq8>SE&qT }חzG:M@kkv3Õa@bs۹>[ꀻDZP.<c =Rmcg|@OvZLP RN۝Rs1nJ @(aP..b/_Ʊwpa sHhn<sM,M C3AMlE`p+]_F5ʽ1pLѧ~` ֬zҏ[lX}8saHg;CdLh ~E2Ӿdz[=~Z) O'oݪ+Z{oWm׼Uu}fP>zSo ź)uwWpe/^QoC6*U0:&k_.7r^ejYչ|Y#c ,K7I_-hs9CypiKXt4A֘F9b7|C9ɴQ6Q(M\9;G!%uĪx&6h-͖d&p)SF(3Mb{2?X1HKNʩ28p$aqDE1hYlw/k|qq"EU NT%0Jf3a:6.?HO6t^MǾ 0FLgjtq[~n;w{wn{uso{ ,ц(?w s@Deov~('7HV̟}3X^&Uܯ 4O<8q e \fh6&.fmfhg5;ilO%Jz 4<(k}H[O/Jц]ՊNb#{1W9]A(;d60XߗH2 P==Q&Ib}%2{٬Z`P9!,\{1oUɞD:6L7ϕ_Xp@u\fIc|mJ.s!_uX{=;(20;k+7zA4K_J,kS%(<"Ϸ,˻`r,0!n~ XִkZbqd" i2u*sl+ f-N.¾_q qؖʠn>qpU`TĄ->u*zL+&!XvՆJ %s6٩\ras[\}W}!3;$+vՁ,40c@<,bw_30aK),U# 3X@⸷{TT?~^922X_F5߹?sRgkXTqp6njv 6@8ykYI,Agdao5}ߛ]G@]9~$n~i~@9ǐ*y"SU )l]L)!Q- S`ꗿKHwiNJ#m$jf2|>yڶ-Nx~&NO>* /KB!mxc;BXnr:ȖObL&*Ig3 1݊=66 yr@K٩M DB@ Hɏrs}l]lr;xם|'ݜyP^Hw&P9Yﰣ=.T~<7 &-4W@?wcV t H}]/h䝷EBy|B$zTz*#u{oWdf\oь9Hy~bF5z9y1@˷TJ@pvDŽ,i`\t204wSOY mh5q FO'T#ny_Xz|k{y$b^qbRC)N UQAxcxor@M%A1vDv H Ę]-_ar BN`p"KX?`@W*R.FBVtǃڗH* ߏ ۍ ֫Mբ&!41H},FtN/"*#ɉ'qϰ^v.+,w t?AFbr"qY+(,ydz|+F&rbf,6P C>UC4Vηբ ]^#h<~ !|zu-=,n n1yCGPq E-5nS'tWJ:TWcUi 3뺷nQ\3jf%TGr_kiJ!%~&YVL` @zN*[ܮOQ'瑹uFM_$mgODy^-r`?NbJ)_7 fs0˄݃cᖑɇo0ÐWCWrٖLѢm2sEɉglV f o) iobyDrgⓏB43mgL1* uZG?C NO?~Hʨ tdC]a\q#1igfhP1xW%6*3ࢯČVvZrƢҏc{wna^ޜǤuva֋n,>n: wQGm>nHy1_GZrib~Gu@~`wrq`ro b7! uZ&u}R<ښ-RXes kv%K`Y#yCFOKѩ+Z0V1M dvó1?~k6&bHuEJsw[*Z֦gYn\Kpct5uKA M_ -n5 ?R?3_JlPDDTLYh13kZJ0 1m0snd6%vc;ranp-gcNp/ij|-.?/?Ȓc-#垉7^̒5,Нkwi\>Ц2s=uSѠ 2u,&֪2X>F)ikB8}[:+vUoJLVm;00%k1,?ZAߥg[> #t b/_XE+hD7[0 Я{է0VE#_ X -:ڻ}3 ܷxh/_NŽ:02KX,csqsX'BMs.+uY/A@cf !DG=1I eXTslD\ BHa ~f.D ͤչ:C{NKٲإ[h5٪k\2/ӨSX9qs睜=pMR@! UcD˽eo45YOudEs֋N*#`BܾM/`0rp0X*ldqG$;͝Cx]{Voa` Dtz "9@cSGĻםtu *_Yoh(%\|<ׯk<A;m}*H})o #4nA̽;q׫e.RY'->G~CrC) 5Xvk/ԖB=OvCw̘_.哣2Q87?y;dso}M>H9k=DvxoMBil$4unݛKPF/JΧݰ8 Ϸ 1sI@l1diRvnnQ1;ҹ}ޕk'&){J`m8&n~Ƭ87{{\ e $UӾ~ 5Ȳ`Q⯨b} 0حU[nMTc J!#މz X)tBwWWwt26bU;uH-#)R?A&Ue[rx09v@ۥ9z骹x(G"9^C%Ogl<kU~̵2au\ &Nj?.[ #@'}"wm7,=YU p*e)sUm^IARMĈn| Px0T׫erE ˏtfuMZ/&8B|u:e:2Q7߳[Oߵf;(nW#r+ !wr7|Sl`1ArӶcnm1&ILIpr#[,[1cL+HY ท/J8{!O 44]X-6\H_ q*AՙKj냲VmW`\ jQɘJ_~;M{V'| S[s@k\zlM89 O:;tn2sbȷC2aJZ2hz}AX‘:2Qܵʁ,TM\+]=3S!Xd`X,"BT=4r5Ĉ4n[~O2#@ë72+M[(Yϝ}ց,99=3WlVZ1>#ux-|^@!߿Jڃyb@!ko5xz+_|oRV*iZNC5csy.YfSON׎m2/e,"hI2F/t)&` (NZD)Vo:H%+嚔1Cg~f_0cB,vB%x_:X5P=)"8JY.3^CN^+AօG z-ʑfݿ .ށ)2,{rMdt :j79p$)LLcutu,y.nXd۬b]BvܝXW`y3YѶ V,u*.(,֦U3ի@&y9yt=HMpe҆ǟzC <;&lN~a 29tditE)Ly`=I{ݘZ9IOc̕~a5WՕʀ%nw[X]n(PJ&?+Vb ؚIBx榸1~eI 0irfTĀՆ1:~ ]hj.;H$Le_$c$~az©ҕp'e*dʱdDBvM9cW)wIT45-`pSo=K: [E } }YP}bc\e+UNSJZ1;RW-8:jx7]0}hb qS'R->.! ڒ@ DDϸ~by$V݃˘m* h# c^ ,xx_֎P`ךstA/<W/ EZ;TX8SzFrCm3lipzәo2#Bh%-eLptdXsQ@n~žDijeq@ o1-&j[)~'1kC 6C\S6) CR?$55 @+eV$_juz<:+nţ&EYJ}p!doT p fz[J DoSfEcLDf".JW|m-f))]b1[I5-?x(}`יh,Ha^c(H)j֪uqXrr]"v{7݆#S glC+/L?et+4Mfbh Wsr~fޞF˭WpdL2zt-FOqD5g.B"0EsɄ3h.bA]nC !kA>#Hj$8YN ݌_x7;0Y{zVvg *\1}MX'0l엾{0 :h׮>Kp  Sf^ګ?FT!ĜU`+_•hTEd|mo$3=pszp )jv?ѿk O.4A2!wS~nA7~U_ZS` @(\|N.52X_Fk#>X/"Djm3CNѶ9u.]3RrLbxw$ۚFldY¾Y* T&"v@n\0^Jo #}yKX% +3^!dcQgs@& F@/v*7W4XRa׮>7>)e}n9kNK&NBdܻEdwrC\$৹x9"wyEAM_.L 4C-<+:\>_{&h*0*s4b ȓ3YS>S鯽Яe9L\LVQ5e{deX0crc 6|M()| y bjI[< IDATp($ cxd&d66bv rJlrRA7 dd}PL/[JLY 9-i č2Ҙ('.7~8Ei-L,jRp˳mi=:@1Q<>x\9 ݻcT% ~qlbqVRJ1ZGGx qX@Hkct9 ;.V #p%}IsjWYˮX.Y<" +:>uKڋ|1k p@ȹD|ީ"/]Sأv:H!FP[40. NO'[L1ip|*\Uv1>V}Hg- A*Nj 87<> Pԩˮ&n> *P?Md]' s~*Hb.\^P{nб<ܽ66}\r9s ݂!@|Z(9,G.+;18F~Knl NyQqAGGFk*d[xr%\)lRt2|٫ea,\#,@J\0kuSnDf5FPr@4`oL & &=w {CArk%b6>&%`A x+@s] H-^Iq}2c0{:( \~ ocQHEs2ӕ=hܕudv8% .%ī;6Pz*U28CN!n,J|O]a/}2Մ%"vOQo Hl N<m20E]p,@rٹ{ͨ)3DO7f,[DC"e팽#{nR/BĵK/OafمϞc칊i5[}'Jj}NHqI\Σ#Kڙ+Oz|;6d^bf'3SwnZ:W2<`c#EwtMt,d;| y*fD129np::2QYD[X];%gb s<߶Я*b.@ _sek(U..黎ț!%‰S-p hpHj^~߆@ ]KZ Z`rG2>HV 4p*vWƹro:GJs;M #mN# mlr43L9&v m;ljcWqU߽㻗yg{WX"%Ť{PJ@|qUy݋~+ߣ-!7?J6.Y ##@J^Kre*O2F> ͚Y&6%@_1V XjdHyY;wqNPxe8nl]*bJ&X-7W9{']53\0Vxu2cxgHD $~JmscT U %=._y;wV?"f4;MNPBC mSq lrzh#zpcu=C߳,>boa P+@ TÏopdk'LW`Mooΰ=~%(gNӿޤ׹[K܁weuzEonUwwWﯜY_(n><˔88c-yo=;cW)fn8sQ9(X*cP +Pbf9_Bk엁;k;9+_'s w,ם3FϰZsOKK0\ l挊ɢXt\R7/{2yjٵ^ kE#>s a1}'DXewrO"* vw 9cr@n؂7 gU')" 7n@};hbl W+ B+_śPʙ6^Yեco }?>h9$m&ZBPtYĠoP ܾ1#3OМUwsiJ$qFX`$_Tdsy'U/';?cDX/ט[s ݹ2UhY`|5ni)@@/ ;Uk dsB!"4 xR'_,7^}HX_ %$ 7])rnwR@rq {V^;.Q*V̚=07Qv7;XB^<h!g hф0EJkbN9p_cKF19{Mfw%e,[[[dJWb"zLs-mO1linIhh e:е+/15(.Le%$pۘN`P% ,A+ 79._}/o' 㬂Rn@۶xɀ:X\Zi^+܄o+ܼ#uESx>|r,cRb]@%#5ʁi`x#b%k8dQO=(J!ce BfmU#%BM;s{f,SwX !(w8% {AA .+j{% %cS*=s}mb F }nxoA p[݄GHL+UY+i懜AY lqdVvw$z[FԠnmhډUww֫?m' B6 ECUB@ 9r>GRv.IKw7ʘh`r $ckeZh,&C'l|!zS*Sh$< syg.bV>&ۘL1Sĉcp z֟(H07=·7nʯEöp;+D}_k">J+dбh M((,L *gi1,lm& 3KAX!?YBC?ll- @-б ̸@}tCb!?_r~ ڸdm3A亞I}米u[ZX|uf]c-'WϯϦ(`']WHI$GKF5ʁx ޝ{j=qFg0eW.Kͯ #y|+| QBYpdPo,(M&!Οy]zy쿷pp.]+2aE xB|Cﮫ..wŴ  <%.R`$aMܝMG>3*퀄7y0O2ƮoP0l9b W!s^qѥqL8DvJ 8u!>ygOȋ~oÝIsrͻ{y^t7m:Z2G9pB!5Bb 1XB/nn"0WQ\!b@H: M@ng uqpcyR#Ġޑ]W.>0/gPN1K )N#Q%zŮ:oUس|D!awk?1J,~/AeD/D.4<ؚoy4(DN+}Ab߉ VBE76D3U"-?9@]eaQ/& O"WxB˔ˈ)s>@*"KV`b/o\:+WpͤU'5`P08/ǂ2.*=>| #էށJsJ۶ŵ"o Q`HD1"f;!x6 KM]!q 1L>u%gZ әѿ  dfjV:i#췫:> r[-05(`oYD ${tAm7'OF$o#Bпp 50g3<9od70z7ǟ͛6.{p':}JU0PDHp.vMƂ$s}yP`خv?,܆ϝp|x#sZȢ>l:,AnC`*`/&m\L.LhYC?1:uS0 Z@K *9@JK ?7cRy6w )bnƦrT#?)Q<*}$cђE88f0t.~[k&r4WA]F-\ݩ Kt/Aˮ̊V !_ήM,9ٿsMlsZϦI>CXR&hbvJ/>p X&̀J]7D?Tc7䞯d`c3jf f[N9&6\aq+o0QO u"6 y4CdR;[}us 8߃#@ąRZ{.,^\te4Ahi&hۭ±8s;u}Fq59:ʠ[g&\_̏VZGQ쵂+R !@v5 y^:l7hLckxi=8!<:2Q[-;'!<4/mUt0\dvyv{WK_NMT05jZ0Wo_d؂o1WC7!Hb\`a r3L w*Pe1H%,,ɠnOӶ1%3Ueo6\A*Y~op bq$ ci̠ cp a h @JHuU>}}>|Ï8>uLKV :O? ̐(#)πIX"Tg}gS f0LX`-UQtUv.[UqN}0^ti<-0 j"Q/aX"k(LуV=1fE_? v Q1k-rv*n%d7|xF#t:r c|F\Q:kr,V"#|> \YY1X&\-ch.]DtW f280 +Ue65JVŠEؿus=v2G9}>IcǧPFιJ !͏s.+mn0+fo]-kb3tpU|[@,+B\0: L`,l"Ox~|3C hr \ &'R..Ȑ"r_׾H.5EҁsD4n/˘d`r_HZΧ^<|~rrl͆T ~cd}b#k}^?̒ '1DI XtըAƯ?V:qgzHػs {wZ,r֎I;mL&;Nr~=Gݢ>;/Ũ+PvKa?<$ku* gOѕk418w]N\C׭}^c۪ձq}EӋx>tO T dQ7ƞ \V>eC(F &2#(a6D!g߻314E|vb4'W_n1v2*3~ Lu2U?@e=fkpaC_+@Zjp̪<~ {O+T; h AVZE]8?ڞMgO_LJ\b@]{* bRgaIDktR<CNpԐkޱ!k̚E~ѱvH9F!jIh v ZA"b츞'x΃S)SU\oGcI]GJ J] 1Z9y9P8L`=Qn!L"Y_C 𜖧0#-Bv/{> $Kz?jѼG)$x xJ/7/&8"ϗS%Ys`_cBNbM3SzRrC tg xgO]Gpqr>,vKPbr>({~֨`9fK]m;G|6vRZ`"e0g!O h0_1n%k[&b2F@:cXf^ÄpփFew6` {J8Y'#;b50"s1cmP½ر`yqY-V@Ć 6pEMh,nbmr+F(͓zsXyc 0[-h)gb KFcW?Gs@Ek{7cG܀Su XJ`|? )b\>"7F09?k nmV3s~(ek&|yQmz9Wk~|)`czԹs[`q8JXɸF9c2o17bRefclV1|,ΆYxwNO 2%F=\c"v/_`6t`D;s X^ hvMDxyx wL  +R7HTjS@Ϧp1-,߬siQڶzpyo Q2?L9JM? e3gH=Z$;%ae9u޻}gHg d=JcbOEAa`=`"yFFO,֬4W>w!$q H).3K( u&>ͯ'{7- XƐQz { w?/:@łK kQ[ 2[ Mg8sq01Avn*܂OJ\@&3~)ВH]rbiy$ ~{\JzJF_:!rJOJ2wzm)Ȋ.>ƈǯrEIp:o݋lu7uP"OmaDGFF5ʁj+y>VdְD54Sn$\cque0-OFe3Pcm\lw:1zP1sEI3J$JYQbe|׌`AUK7Y {hk$q5!ֿND \]h5r&ꑨs{be\X(8wgVC fKq=&mėwp885*bFܦ.IΟoZ[\ UCulqY,]GEF5ʁGr1^{6_ߧ/[6V$#MxB Vw(2Swk[ee6~;{*@FIY4X;[]Tn:$,7XX/V\sHyIm sl'>™|taNݦ@Z򬗬^Y&Nq?-4Yɰ H6OUS`t rEƒwX-Vh⤄n(2,RLƀ1 X̻8M\p\ϸ\ؘN@OB0+g-m4 MhS"܂耷]BN#ApQGR:fy֕8Bhy&g3MLC @7AT? Q@ro|{uWU'k}˗w ^!By$<$ZVWY%գtX]Zҡ[{.Q=VRTD"vii٭EZks||7wόs~7LrIs.Bf#SDroBty!{p:FYubf8m}f* yoۍhdb"ˮ U%>Tk5P*;kN=nF0\KuW+aD }?E0x+a:pK([bgԧ_UƐ^:T*S*b3.6nu ~&q/Qp-se>VV-N\b2a1xb7ܴ2*Vˬ}2jkzac.}k*{upq°_aob5XzcƐqFh`qG[{# i\4?):EeoHR& Fc<7Rm)q\bw|y2˂1$8WəZV~Z*`9H 8& R=ziꅥ;Is}wIXz "QYuhS @(dVZ2>B5^!}[+1S&˫ވr͜x琢ΑsX  3,Lj |S&Ű6ϕ=碲V1|y !D2E;;{*LZqt Suxnx=]Ü95UR!B\ڥ?{QHlLDV9Ơ #be)>Ū#| ũb9;?qBvIF.OXSQF 3Tu>BK3lGO>+>OD4eB r&lP`ʀQOڌd׵rUpd߳Kc5o0ՀWz5>]}lΝC8}fѣ3㴋ov#b#V5U',IW]S!?ƱN5Ca8M_l PZ5] vwvqu]q)Zb#Gio Ojٜ#5428[[O;@"./k6W/)+cX`Uy,U)Kco h=%E]+̐- ^Gih9f ƀq ؽZs{vX$ lr,-# ӘvϢbhho+ aTݳE_ܧ֭Mēk/׮ь9E8iuRP"&}N 8'"! 6՜ V'AtF=c*3k1XS"J2{$EUV~n PL$_ZZSR V Ls=.y P*-VW7gA;1WM!|<'"V$[3Grn ~kj@KfU;c'9p3'B̔Lm7܇ҿ9 i5"VˀKഃ%F27bUKo)f~ޫVh}+֑D\_4sRPրzNqXw.+FY67V >JNMFf e\}bja k•~(V,6EXX.;ߖc-qâY68!`s6v!%5|2sSU,Xf]l"__a4XoKs*&+3MJw$V65Y:ِ|k֪hP͓d#,8{㸸+Rfs:Ll6Yr8Fo6nE" ıGWbam"W'TW Bn&,ݴE}=UXX,a\7#P;'/@d«'̑]+Kjs#?klm q(dG2f5m)z1u[]_ rDcTp kQ0bW}<UǮuGʦUaWS&Z\jVau cSI5)o۪awwO*2JIV6T[Tyc& tFڸ_ Wn lIj" Ynh52`]\ k͘uԬ Q)?_l5PeT8*2C5Vwfe@KruR?4XLm2`l9^^k-h~*!5 4IU6g9 5;`3VB~k1YO2C\1e8x^;4&($R8*JY|eY@Y;?W.NPD+XOΐ6U)^"+}PN0Ɗw^q>pW,T?՞:qWAZIS\YH>e70ZT>юY~4cXsӄUd1I &V! q@b\ΐ\E( VVXN 's(eU,KXOL@fj@Qkq5cU&ylRci8]w!mU#SZ V{U/:;V[1U)^~+3 13yrQʃbU⃔{U Ͽ,W9濾+ާq V:&riL<"mƀ_ u9;y5pS%PL[`IZaw;ьY~4cXsQX髴(*(J*B2* €VI\EX]qUOېKUX ؖϛ` , ȩe^A3SP uiCӽU`F5HaBGBoﷱXb80Cq1,F'٬QTk8ʫ^`0@ PlLfiT?Qh6ɮ_Wwr5w[ m!vͼmvZ҄41{VÈb,?̴ઝPX}ryK)$87\v>13XG3f5iWq)2UaPp*(b|%A2ǕUZICǢ{<Ʊ0{ð_RWE (l. ԣ+6*Y,y N%/,VPT QTQRl{,ܼsŋeT$mXt'!16^ ,- e ZQ!?k*HBbPp~<}@֬:19N252Q,#R*elU0`a %!~c)f5i̶h˴}-,',bOSP[,PX]^U1VYXşeh:)hZgjz<-:iæ fM_ 4\TBURy\i`{eo' slSp3+$Hi|T` `e!r/U IDATU@Q~00^`c4?LXN,cj |DI Q`q(@`3]HGM ʓVVM(iq\5*.I!?acKuT1ELMݰ2T q`h$[$N_kJFc DԛjJk^ Ȳ1E Hk&UIz.WvƉsVFq7NMmDNJl1N` `iq_fxcjgIu36o+'"yP iu@^ .N`{8yboɘUl|gߌOMoMZ}n8vW/%E83XG)f5ǡ︮hk z*EEX! 0#ƀ?žkgl=[7-X532\wj*7l\8`oo5J`M؏<:TN %풓YyN\(T]ݗWTU9Gx )8aT+ezěWBIBfX)7N gxY횗}.I Ssi$ML܍RۿMWXa2\gaj0 bw0\nrKY?+{5믎^Ns'`잱\.dkg%"Gᢋ?{ԧvxV$۴sbI9sPki(#PPMmzUY pJnM{%O4㌖Ι&$29+6NyA78 Dt7']Ik-И4%DN^uHN抽\ Í)[#߄Ǫs6V-prqfjecV w]7(M@en[p5Co^%K5${gu8yI =rWׇVP+VF W Ib6N|>){5W9WE*R0}K]p1%?hZ5PU;ST1 zKq%֧m0YNO sh2+R[4dv$`y6=9%,GJ_H CzMye=]Kma[℗\X_9Ȁ Wx0#%A%cXy Kҕyޕ6/1FϿZUͪ+>r(1Q2G0"bkT/Oo k ZF2kKwng[V/'fm{*ˑWa_(>iAM֖U?9c-fkC9Eڏ_q%~7?!/LV=H`pRi>\KQqٵ?PVE1K!H\+l`Ut=ҫ?H3DNX3]HǤ:$n;Fd J`+sLfO7驗35犭Q=Rn/8,,栜=oGJ}u"Fba,I#߮Z~jE`::t'|Z%0MGe@ݪwJ EwĮF@QGQ5LgY'*[$ছ߈O*U@T4Ni5X~ 8v|=[tl$) ۋrBr{VpYgἁTXW11E35ǡ Ӥ JuHmtO~V>RUM噽'k+x3ɒY|a:,k#O3‰*I9EXE}5P517z;` 6>AfV bM{EVD4*iꠞb(%EE(fb?a% / 06%~.+HnQݪwt|lyyG]9e 4֪QMUah*6+clWB|:Xk$Uqj=[3rWuDb=;5?e3V{X-ٞr`y@X{(ڞ#*G!L~?~3PEDS_ R^< (b,W6,";{ocow;yX { G8s|@,r?18cϻr*'XD`A|G;"b,S}m|J/xk!|ޟk IP )hsn`˥6e\ <ãhb^H)>0E`3wET-MAU\rɁGɑ  𥴿R)ìn2-!:܀m5 o+d~\-gzEW3'u-߈e,"ާ*=q5?2@RŞ nb3{kC9mgײ0.c-UP_Z@$dxZ>303#gm(߳r XDžRMlsSs) {wVx>G*fэ`qhyiE&~Y(;i& )"Hu3IDL%_z\c᦯C 12\ SAsFOӰŘDV@GrśD s=,XN`軭v޸ޏ^daߪbDƑIP\R"89sHW|> '}Q+Yҫ Q1ZD-){}ndb*G91laXqbP}:Y/NoVUߦ l$GAOW"Զ1:xq)zLֆT"NX-G, *{M*)u.kvpaL1=;<yAV3EJ5NEsԋ@S]lX`g.90}Ť!Y%pMoEP"ns&NpZrkt=fTO^Lmk@+|*xjBqVN/1p-N\D@ɫ2$ݼPg offrEt+yqTTDvl7Y6q8b|7 "x?EryY^#!_R؁c\=Az)vG)+v8*t ltZ)dIOG̍uHpۭߊw#kL#s¸:eam.Z1ӃNLP[ :("3E :%Bs/GcT|vL%B36b O^G$if21HVᒂ+I|so(,%b0RWyJ>/N>v4c뷵NsY Fx4Jf0}fBU)*gu'Pl|ʌ!z4] c!Tm[/b'u>,V{]JjWRU]B*}Unw}[o@|{ y6~>)|?/WNƪuM2GyKMzm'Bf/l%}({27aX;#K{mZI 0hn@\_&c1f.(Fn&dεK T{iU(M(nຍ}Ľ~8)KbZ0o>^`-Y`VtVqU|%p\88lVV'>S"`iOks!WZ_yp0h%ܶ'q)a\3e NY6X0p9BGgL 0UzEn0D8F}dy΋лL{S18ySyu4]O1W7̵|83&L|&kj+S,K®1ZeiaBZ킙qxfь`q"FMW}Y.8VUhy" (1QJ\ɖW cP兰,~&N)/sȚ+՚ZA¸ƍ *05(4 'X-Ѕ) q(q7Mkp__lL69q 7Q!̎>^WOI5[\:ۓ$fETq>YHx/䮯E.D[9=S0R4i(U п_7zg;yf>hdWkJ P +ǎz`}f)9]٨X(W@(!pE#@ DA,^K.,.ՠb@`Mf}T1Eݷmը Ŕ\w6R -M t^p;~u=*(8iSd2ZRAGt.4ܥJS! Tt:; rpW saA>.Z Z6T]|ɿk﫬"m~Jcڌ*zR~ڹ"趶1D`䗓ݓ ыZsbrT6!ڃ,p2ƌa9J!*kNχ\j%#ߛ=b .lbV[p] UU=I OcBtV*yzF: 0?-c,ËxM+&4G)%1Z#BrJפu&`pdfR*@fCڰt0?0LO7m+OHŲ1 Eڼ"sM}Hك\clwR_9Vdr=>[3z9lMF K5VºeOu(sjw@b=vs^ͰjTܴ A6g\5(3ucXsHQϷD"t5.LрJ45fmXjW2` -ՓzU::qŕY[lխw3΄0TD0 9/|bY`Z6e҆)\b1?)aK^l`'yAT m;6 ">駀*Vjs$ 7 v ?وa q\뾱$Q1mR-kU +Ϛ&rm{7ڏA\bV% 1.a|Rbx`kg e3¾jVwPvJٶuʶIG&5b1Xb6=18tarC"| BS 8DyE$#8y=3q* 2J:%34Ul+YDD"\ע6/]}gY-"BB!2*F0TTyG~é :?:M N~|w # a`>r԰5Y3V5ŦzC+R"0hhV0Q7F}&W]hx2 6 Ȁ~ҊUiCٍ_/K= `s2yĺD6K SYb3kZR7FZ$8*];1¹ g5Zcr7<2:dh`q"|֕]S[4bfbeV%=hU% O*"¸RV{M/]69UWşڲ`\؅o{K w*}n*-Sy e)g/՘ICJpfRM|?.\ɽOKn[[#e3 H ,}*դŬEM1>:EȚιҠ9­SaHŠjRF_*z ְ^.VQgɀfd>Oă6v IDAT8=M "tay/~=7QWxN+2oN[8e81>(xWlmu`x\ .b/>|XTżSY,JQރḃ,V;䂲N{&.|u;?li䉇I.߲Sm Ò7v^[n& ҾS jj]˯|-~c*`FO='J&5?Ȅs38qpw8 3|_Z D  (>Pftbj-jL!H}sZʦ5bpbx(4`g>ReY=cSݝR}-Ű'`MD;wל\ǷB J\S:/~<%F'bػjZ1&,=Ҭ:19]'_Ajqj>֑h F +gn>/H 8[W5'QkvjƜLHbp nbc?9XXȹJOU X`&%e&HJu`U-槲%nj1{윬#Ҍɘpq2kuw!it/rWM" {=e&l&60唘Ս-ɚ横iB6|?sY]/eЛTR},Cobz꽼|_ P;xS&zT17XO5)KDŠ0fsQda5XG;f5ǡF07,sI7f˪<ܠUQz΃]uq>Ar ;ť\YhEE ' J0w2ΞC-Z3jUf(+?׶ ӪѴhRn㸯RBfE!ic:%QWX#J '1*YSݑzVUZAI%3lbgչTF/4mbZ_n2Ts^r~[\UO朇#mΣ}vw^0;5'阩y:j8a)'tx@L\Nl%!c*6ޛ!9RH g"=<_kCA֚[)&R"hEvYgRV5nkm 7&mI}FbR&VC@y?aySh&6Z+vf'seQ^0 }s.RF ,χ~ԗKmEʼAl2+WXkbvOZIgv8`Fd*))f[/_ߌ0֒gɬ. h1ZιJ;ZL`T n~ָ9)23>*KhCoKi29mjڤev|Śg8 QЅU>L c}{5#VM%}C>vmI^m,E5QI(xM)̨A1ZwED fӹMPN:!^|oh .cR朇>cwLtV67)9(%^ i$ %E]&TE^ dɵ+i l |QsI131%8eA@Gl9&$h9QcǼ!,]Gt isPEΆtod4~oy?Q^gI-ԟ:ᴯ,#(XQǨ: '9~Cz29Ex$cXsP9j%CLm>~.n=^pj/:|>X}BR Pݓ$x攫BRw <:aL@_>DE0 'qbM ["Ș_3`YQU pG @2SWz+YLLL^IQY;@F"w m|@';FKş#؄%&AyofqM_{WMZ[!Tc*(`aQ~N{&\,Uj)ʼ1dR2+p# 4L_Y' tܤw_rfT0T*UD·\較v3{e&V3:+ʒ%m;_~]ߋ_|?s2faD/'3"8B`I'a)]g1hK}HѩEC-lkC |mY9D'$M蛶<0@gK.?ƫn/cYu,t,r'с( Rc%j1KEA1n+qoc/gjSMҫ"<>H2EX"ثCVvL W? L os^fN-#w*wNe/6]U92̳9k ?]p+Q/g JIfkg,x׋3Cѻ5KcnaYrFG.Wws IGulܷ ^3utcXs G:)~@& (lBL䔽R&-<䔈D @afѩۧ0u0;ǀt^A_;d4huse њ N*1n :$O>JRuG <;q⯰sb4K#LsT=E{EI36.Cnѣ%.E. ̅vB"lm%TIM׽G?8ASa5z+%b0YLP}: 2GO|]rn u}࿏]/l2ztcXsHO{+ xd!0Y3DRF `#ˮyZsz|W~qVe5 )M#FT `, @?%ǐjX+X)=걔n=bɀTD؋|[Hum |K88,: ʪPNXb'lAnb2 /3:f%%R1u? ˕[ i5)i+^V-U2zUk⨞ӣ1V&XP`@m)Z(Zk [9uW|GcsUc эhtCB?\}Aj7uNtZL2y.]WŊ64p?ѩ0b <`>*>5P4 74֭9l:1w9쨟jAV{=v?,cR7UuI-VUXVf!vPq03Buec4훥)K*{ ˿v1zXBA&:M{x'uig#ĎT8ƨA:؛=j 2Rc`~U.^Ͻ8׼ ,] ત8RM:PTyiTOZ]WeaIM(-M#!Yb|jTVq&z#FԩW RU,-G1"QIS&+ $mDUG"'M[ŌE1LvX51𺘑 3OXD#Fxm9ě+:9ڔ17Wb+$~}(8V@e˓9,i,{%;[Q`q(#E:뾈"I;[0&90'+4$IKWҔ8=U҅qׅ變( )겒Lr9=hBw)@q4VW$^`R}FZ ǺWmw~\\H&Y#F*% Ljt`b30UsDW]pgT>RI{"^=dޢ)]Vf~a֑qC+Q˷ɩ4|"w.-N8aė>A>28kI ֩wX&:"rOō ]Z(bsr.zð?]l!txqBuƿE$'Wc~LS|zr`~uf_BlHmT}`Vp}%'}->BYuTcXsʰcs&  D㑜gAv*"52JX˖LpRvXA4V=f*̑H1蕯Wtd' p1V-2ylmoYMN 0jy?ỳ5Q͘f Şԋ́+8IJ<sKB҄@11.z%UM2-0_ NFfbn'uK^! ~f7:?M 0Ftv*MM *ڭ` z&|n%඾x`fѣ}CT?£׼($@lR Y> <1֯W*W1xX"%.zcAMa&&,cܶuE~UsklMڲh=@Du4uj TWKÀ8$," κ#qPJ dѽ kc(a"aB+@o#)GVS:Qo|>ikQt )reJdNﳝzڝlYN9+P&4D8̳?G Ŝ"cXsHhe ƲW[ C[Sp\V{xus9xxP`3p%l}bhoqkMkU,W" I1DpBb-.~' SM71kӈ@Ǔ8jEeUX+[׸0gp5xӞ씦<IU8Ř RUcQ߇X^G0( 6> g{;!<SSjjd `W*wg^z֣률cfn)9e(cѦьSUi&aS֞1;MRv˞~PXaR/.T>\RQ:qT$<:&s'roVGS}n UpARU~qG[p~/|:_rmQƚG0s\~GוF.<\y_rQJYtOQҕNZ$򒊍`Y~;/H|X b.j43ǎroroC[(㉚*`L6v u9e`h`q(# ׼憪U - j1+;QVTʾ^mW׽|>{{XHm) VC`AG1য}e޶vEE)/궅q@ \UHH@۝ }3P/Tt2VhU)h]V>q_X {~*e/n ?3.abZFRBa0/ se6 wſ[ MBa2)6B/΁`qXcU{ua4188ۮxh859D&0{x_Ze͋,05ڻnox: Fؒa)SBgߩ&vIڻ~闾G .79Z݈.qQ̝KOH1":.1%ݯ$rhIB"%$G.%1T%Wj*8A2P I*[j&-,ZJA#L`=*yӟ~\:,Ȝg,p3㐆n-2&Ze)&sƾꎗ>}_񡷾`n iJj`jptpj*VGVs- 3v<6@]TX@W2߇g@Q@V\6C@R^FO1¹ޚq< cXN08 ˕xF[ _c")4)ECLO Py%t,uZN&iUEʕ?K%c$޻ jӅR _)އ`:19eOslo^򪗟D5E0Q3ClffIRhU~v;w"XNWM,VmUSkS2ᵝ_s˛2̓Bs=I]1#xOڔ[k[pa"9ˑYM>eʱ"l+LZ?$F ȩ;ʜ#rΓ4GZnݓM˩R1˿wk@+iKƻs88w6߫#f 8֌S52!DW5ἶ1SIu7y;rYR%W}b% ϨSmu5 k>>s?߉l IDAT$:BY\SSr;I3:@RwOϨY$IR p'HAI^1[,26 6x3-c@RىkʖLxo. \A,]>*e,ZuD܄? 90WqH#E{2c%{͢yl@Nԃ+Upa\"Rx?xf1)| agѵa#|~?vvѷ4>vY8vlLa/-n%pOX@w<X2~eMߖ̱T7aXsգUGX$":LnSiQ}Lg1o.c2oDs҄]/Lٕ;vg]$%_^e^ Pnڻ灙֚M^?V^]ֲg='5U7s`^0Xjc{ėV'V[Pk a U1}Ak%Ű ys>f7^d`xҮg}MA6>q^v)[ZibNG/ՀªsZefm[(j0}}#}"Y3pmzj@U҃b:05Uvv;0`6HxXŸu7* 23 !{R-R"^ps񼛞 8fPjpŕiV $A cyk% oVi?֊ae AugЊj5*RFK>A@jua83JUs-0)uJz,*Ϛ^1V-V^@!G5` r0}s9$f5ǡ N09{q]7/ܤs.W~^x d@%%$m|B~"[3dWC MI䌩43EdpUeqH0YȬW͏(jA0Z@fB\ce`i@AUx5;"9g1uS&KZ/y˾J1M*7PcC'U HɁE] ^ѩ0P)lnw- k>[)@r5_x-w({gdIvy{zFfъ$ZGhG V$c ~^8x@6%B " r0V9@c-2gɼU=gޮʺu[}/5O U%)8MhS@ cP0BA‹+TCA0EĨ/6qŏ"Gž,W{,P\^* XkO,S0T8nQ`[8$5 6]C_OV+r.#r1XHSpQ/!Dy 8+ ^ygis`j(ȉ%TBe\Dh}9FH|xfi]U-ƕǂ{Db.Wg(sY^B26WʙSsUm D?(b6[*t(Fg{H.t>HTJ 4[;J1]>8v]ZgVC($3 hq宽'A 1LN,Fb[yAz Vf\؇_Ja֕"6[_JԺ@Q7^E0~u*c2tDDXչ:<:"FEHI)C9VN0<0ї-ȳ<.w[KH҆Oo6lц5 bߤ~Ʃ`.dc/c}IE3\L2aE/ykKswEN VnVhV2!))QvQc]s~_Q回[FV3tL@REN Tݲ \% X"fcT M`ӚOADy)[굧|Xz4-$+ !(!ecSHTElR%BcT @mpB‚W`v5:Xdݬ^w_JkV"XQ"nѰVR B2UrbȋpDp$(E_&C8l Kceop%±R]6M_2-,+'},j[~ ?qoav|V,i T\"*Lt[˿Q]` 9CFO=|e"']W;,f^Covwi@= .j!T3/r!ˋŔg9 2 M\i4XV[dXpl +[X|O,4;d~ejҝS *3>^/_>t'_WJ ,C}_y^UDaF$ ,rbeQ!PIULV”edc4P(Dqk1Zh!.,ϼ~=FܣiQcUu|2~ iQ)=ݤUK "[/-;,[^(u'*L2peAx-H\iR(pEpڤWFG EFuڡEN,ZE׾-QT],/4kJRrfvw<޺F^-esBBϕou.[=oΕ6sU:XElhwBٲRD|>\RuVSO8a7j| Sd/awnW^X5>ݯa}O6K|x+ZՔw]rwM ,rb O19N P,ˁV\n- 3y'CY0‹7\&@`CueLu7S+dM8%VЄ~u9'eRQSP5W+ܕ+߈WSz'rWU+ {+^W( E+@6[T*߯.RBJLpυ ̦3d*I e^Xh>IPY+OMXS0CX\[v_KX:֮'E~ҕuޯK]d| dY6s_y?ke}/ru2h*Uf49tQve0 d1t2QxiS@h !ܛ BȸPwStZ-|6~=:Q(c`֤|ZB4`OUZ>XT[Sd Po$5v/B`qҴMeUR&̧iRHRPIKzP2JRW|~pBN<y/\ {@ d℘P"i)Rgrp.{ёNB ,rɖ/_| .>q-T?hg gD$FyjtCXѵ/—7_^8QiՈgup%A~r.z$|n= _iTT26^TablZ&\m`w=' ε\,T cEH2ao@oGIR  K.hpp7u)vV;6Lc6c9#`Sk?>+^ PV*:n5ʗH_Ɨz>!E%<+8gN>H aԐjn|üZfv:3J"4  jR>lЯ (Dqej UGŰrlQxչ'4!RCj,mU9`PEwLTܿҧ?yF~?1BEZB*V;ESCWGZS Ep4r rm^"N0LBg#6 /C=?6|ЏYc Ha`jH`Jyِnd]SX8$@rbU˃4zNVnD_&B&/ak #ݭMƆ羵5OiˬrO03}i2qnWa}b;BENF[33\|l/:Zn vF#A|m4d }[P\ *)%xŻ_yCZI'r.-PTj8uK,12Z/a*UtT4GE( d^i-mtjjMXZWbxfEpM(.i4ǥ'PJ۫ݭծ!) j Fh&)4ʞ2A =Z0Oe{@EȱX \Qutz.wEAy{ G ~Y~ZVŔ.t)޹w]?TJ xXY~ᵐYY4iWʄ [{_KAkѾ sկ N- $5ѐZ(W4aŐw) YeHH#ؐ.WKU9; :Xd ,BnUw+))zj%vQ{ʇ k!g8\[>[ƏÕ AU0VCR%(`PGFWZX/\Ux2AT`|V]J)WVGGD-k{|KI!<f:6˷;ޭ^^e e ~G{;n݋yn~ /D, EY(2*\ w,ܣPյ=+ sJ'wBSKhEj'§w8Zzb,1+df%~|"BEt/t/ǽթuiMa`ӹ[ө[3-nk򆏼}ƏszՏ;MYLղzIDAT-V>K ELt`mr9U+L J^!Ɯ/QaZqUĵ=aJɘϥ(T!#ܫp9/,P`rǑgÝ9;wL4h&hw:wݭ GEwG]tFV%R:U[}2Dsp8=}S|*VhhWJԐesI4' 5dy[^+!Y;,_FA;56[yӽQX Ю$L[VH`J'LLwQߙSos 0FB5[#` !`+BveAv"ƭ1~eO D?%iPS\׿}v_!hX ,Wa2^"[jj I*ְv v X7tH_2!OڗM#J@φhJT\4m*+c/ 3{V_}! ܮ}_(7).D!)\u ! ҭ+x3Xf~}tȩ!'q (N B_G_FAL'9&c6˓!B鰦w0FCJ+u P J*\-n0r $#ƸD{cT]B TL[#&T`-I"XEG؋U)57Lu/1d@n7}]_uא&hP:F0.*5Πd TjA s#J a,L i!YC# 9XȀ} 0*4K~S>(K2W\|Ssᦃzt2WvL"Fxމz 򋖥JT ¹b/9 eX*4D4FHi}02sO116\V(dtj: !St/t/MΜm9nM'&%%-r$wsztalZRJ/H|ҹIZ@`! dҾKAYנ92$I\gLr5pS~wL0hMlhwkhwk8oYW!??%ri~:kqG\u=_`(a!^DQ@@:ou6.w Zk1!"`1/|GAtkQpj &6\|(QTg~R*<ѷ]S[~[?I}.BԨP>}^rٴ_c]y]JaĻXRj/+N \qP`BVb<,ݪF3A'54[O'9vwN2h$D*oZ[,XNsVHh䮹]%~1Uh&_fs2BJ̟# ,B5 QQ(Akfyr` VHlkSH\uE%6.' C?~Uw,P`Bn t*kAby،nt& U)5qamQ>!1kk h# `êRkzN<Xf|(%6j7hp-~- qX7VRJi)U^TVZ(I\7=}qP`B$$. z:zjusmlkc'%F%_S{/>3w**"L*`lBOK2wCϝ$li  ,BȱjҕRb[C[=u-"fyރObi5?YXBJe4`k|DoKfbP`Bn Y,(%0rVWج7y,7rTQ'{JЕ56,J!{=!䖣hnUpJ|8v:ɰ8/\G~=o'!J%(*|G:W dy\cҟ+9~(!n]8(juFFݭnLwk X.5WQp[gζׯ/`+ҟXEE!5?1un:ws5-]ݭ[ΜmaL ۻ汍{]̋kGI)XrY.5OpIcVۯۯCc'%F oߥװNýɹ5T˄'(!c2ZyHt{ulm7Q+϶pl+;D6˯~(|VK dK:Xʄw:Xr CVGkLk\lx&ǣ% W.bZ+`9i"BN1 ml6pzCac ,?昌riFwYE|.J$,X"\7mqvƗOJy"寅.*U9ك~mv})O ,BKX.4.>ݭnALn-;sv"ٹ4C֙Kke/~/OJE!w)Y[_Pč-'{z.ͼņm='AZv=xOxzPО @E!BbK]v7p :)z:zY~(0QWNol( 䪩!SYO×ˡ~@E!hK#Dׯckm$8{.0-0;eexesmk yR%ß}2.Da"S. ṿ[j :Bn> ,٩rimlmķ'+K XC> OK})kB ! "-78w,?1-pt@s0՝ OKR!kRu I8o7[Ý],?.Աĥ$ F^ /OcBȑY. W,B!X. BHFNd DIpK_}ܹ,ˑe9,(60 '#)B!7B_w>@R*Kn " Y( ('кN49YZMl'Nׯ{7(!d1 ¶Ie-0waUMٴDT[QtB!KzZjtV`('4s6ht `潕E&_w4!E!\|X&Ady */DP`pyyjA}hѷms^%B!do!W.o < P0l̹C ,MJt!ï?zm?cˣ2ȲD&ny&.Uot+n6!|\b6aͺW˽: !BGBxkƘPhOc0Ǹ8!!Bn= M" AO&Nq~ /jQ!B錅N6DuqqW8=}.)B!$TdW/B!Nh9ZB!BCB!B!d\;DxݺB!,B!CE!`(!B !BȂ"BY0XB! B!dP`B!, ,B!CE!`(!B !BȂ"BY0XB! B!dP`B!, ,B!CE!`(!B !BȂ"BY0XB! B!dP`B!, ,B!CE!`(!B !BȂ"BY0XB! B!dP`B!, ,B!CE!`(!B !BȂ"BY0XB! B!dP`B!, ,B!wzF@kҨ+tLbBH qv!nV_] tmP!k`ÌS l~Xv1!Մ8#ba_+t 3EÌIR?R5R©B ,rmBۆO*8.Rsf̓rY Kһ$]D0#!,XofQ&nە Q jwjڄcYAB}P``8pg3Fmiɸ"B , "7Eܩ0``KFxZ[˱]S !otJS`'[s3:5\]y\FQ^VOP`NkJwT ÌW.X5܊`vDtR*cBjAE:h@Q_ _!W/+%aŖR8+ bBtZۉEBE:Ak`6hm0U] 30fܸS4[?q2c LfLrp 4f9P*! , tȪfL+ky[sÌV+TeBAE:A9XdaF8?>8fVx \6ьoSmf$s(Hw`Js36ÌN`c 30{!f"`, cQB3f݄kkX_IsyVI]1Ì, , ROuE&ğJ C+k-FYjL 1Ì|Xs"$dhm0UH C5Q8Ìw6Hx_Uqs!otBLr>+]aẽ/ 6Q5U2HH ,^X Ct3Ì|zܯ<7 ܍75xlCq0#YY(Hgй"hm0,1,qr{_46߲,kL&5&#;vYrRlP`е_*lqicG20HŒ6t8^, X3jm Y&5K0X 'v3^wm4Q^^ƄR(HgxJe /WB4̘Rvz f(B(|-|+JH"r㔥FYNSp-_@Ċ0 m@83!ıQ̅mtB ,F"EEqh ݵC{CE!7<|[٥" ,YːhwuSy/س9X!BBTA;[EH"|N ǀttF]i")XcC~O _ !еpw.]P`nw#0}k쾳фvAE: @ "^;{<0U3.b[ 5 +![«w1LHnH" ,umbK4#ΐē[ ]k[=WBH9qv2(%P`"X_ܿs""4(!+O(Ѡ/ΧJ&F;CEEbȜ2 )mL{yO(H/"*s=G.}s{FE@E:Ekn~BV09X/.tH"R X͝{3_^w-2I\Q Yy=OrL5.ΧXx ,);BB7`y^paB_ثNYUros~6tRc0̰swc7wt!$_^B ],?(Hԕ vBJ.!B Vvb0>bywثN|9!+u=uqʻX> jSE^X|JEh 8\?DgS@8 ,)մ(̟ dՉ=_@dw/(HԵ&s4!!uis|4F]ll=M#䝡"(!!ϟCg.XS)Ye޵LCʫk,@z锺2Y!W8"쏵1($taBBȇg.ٝt锺.ɝ>!ø(qyY!GΡ"RWVr'd`m'n.U?!FxuY`Nf>P`Nj:X02ͫ~X;(H0DHlDoŏ&2~GGYmq1 £3(!,/~.}"AE:5b,ӓ & wMB ,9ues.E$wϳ?c;yأa !c`w6Y,Xs:X0J0 z^= BK`F:LJ9EwO>c;Yأa$wd\d !],rsP`α!B[͝B͏>`;9(HTvr$dU%0XFd·O<أ%&+DyOB Xs9X/GBŏ{X[˻nYأ)v@1ٝE)WaFSJsbi du!B{ +=P!+qgS9CE:4DEuBHG܄OY|\(HT왐뗗*ͭvdxG#UYi>~0;+霺\qBG'tGW"d,BV zJK@Ͽܹ}Ճ=޸!7|X 霪 !7g%B']7,!Xs8U!M=?<=|pFKVhAq'dJ`Nswo [7Y~(H?`BVqܰlQsXdP`^Pv$%K!7lӟldY(!tJW!B*!"G" D ] ,N?a,f!-zBVc G*8FU]CE 2``6Ͼ;&$BHt"ᄉa»{X[;kY(H/J9X}u릐%u!NJ ̆ ?g|8!tR`:X>cP`^PUEHȪ" -<&${3 }b m^>@]i縻us-C%H/2?/ sõRp1N'8;ZY/9Xo{}CȐwɸo5yp|/KN%N"~yϞg>!FeM" , R㗿/oQ`s{ lm3F$ c/BBȇR/'G}u-v/:^hqwvuvbŖ /N)9} pO>S`0}.ֳⲭm+vְ=k{g)Km{28e>!-Np~2?>ƳNneP`[]} [V`bËEuO*+ܭ1_]2!Bx j|P{'׆NTy3{k{os[޽uO`O~{u-+JW#c,/m`sm$O>6{G%NO'x2 !=6{XP`PyzmWƋ̗8d#IBkC+ژEH~rX7TXysvؿr޽ vbYj҅OOƷJl(7E2|63)-P`DqC# oP[Mb lיּ$z'@\>LJc;Y*l‚Ym/w]7 , .jc/qB(qwo ۻC\_h E%*uz2/_\\,eWؿ/~vQM"=.6z[]x'1k{g! /{+Zj۰//QRĒ!"0eR~xy#X7TU LCM*\>wְw`l``_.;G#Lpz<"r`< lˮDz  I  ?lU,5^W-+ [e#v( l5 IDAT8=ŏ8=\'/ӟQ`+"cNgxCkع;I貉cKsms''G<¿2 ,BVD.8ku\vz_^s1, q-Xe >v&BEzܻ؎>|$,b߅wn$2:= swGrn`Ä˯R`P`@(P]ݘEgtY;^,#o;B ,#&9FYj~yHĻ{?NW;E1 ""߽Ɵ] ,2 >Uβ1/ˇiv}QԝF>O#:19ʲ!u($)XasmON\>ȢUM~{/G_R`X7T1@Z&I>ˇ\_)zzbQT7<>x6 P`^Qy*8Zd5aQG\ ,cnm{w6,Y](!yEQ}E}(v ,X) ,39X,r=s(@\m|{D(HJ sg|HQ4I]IK6w1XWT{jdq\(|._"\GD`[y_~}7~0CEzEYjcuSȒEQ\1\2iH"ގ(&";EEQI_WX+~>B%}EQ?.ՅP͝I(Ȕ;),X_WX+ I yi"r9X?78*}$^ :XdY`Q<|}ǒ + %"6YQ)O<|CP`^Q:Y!V(2UroGlᣝIV ,+J3:Xd5y[><>~ BEz[4AJVy\ۻC[>mEQ{CɆ G[1(HxcI%yH /mcvݝCKGu©ϵ; 9]}/uڤ%(V ,+ReGK@ĉcn^9[Ph.hEEQ6Xy ?dɆhF>|}Ƙٷw"+Iȍ/~h\ Y!`?_Wxu AEzE nL{vJu.quy{i<&/oAn'*zyaJ(6 AEzOŚ/K };|o7ŕ7 0$1br]*0X(ş_/X9p5"*5B!ʲvKM-3cx9D50!gEnT7h{'(byx.֊@EzGUYr& yu{3Bt>L qI$S@nEEe.=.**~{/|?9#CEz'|N]*ގ$[`Wi-NT^\0 Q\3II]K &AE:fY.'wq&B-&XwđٕR.|&uˣ7̗c0WXSU}wʋ0|WvW*7Q`-L EQ|._zed9"*kyS@:89x# !%.(!?l/Y.(H1ƠÇfiݧK 7+jRHY^^⨱ar2mp眥(A(#I0,rSQElZ^(HHܭCjJsT#"P(,O$Q aC ÁƉ< ÉPNKŕiga,#GdUھWTj&gu}'z~[QԽf>W>}r_$׃Ď@4ϕJuu3I@IXzZ;JB&̛nL%.h$#/lCNJ{\*lӱu ES|+A<,5Y!ȇEQGx.~ol"4`JK[5Q夈J []hejh7S `*cu@3%@=Nictܗo@mJO[=v+r,˱U*QnTD"Vé3,]cK6<|eBd1P`1_hvddp{ JI)$Qە3]i@E?{Ve; erŘ.꼖Je-+_]ͭ4 Ss/ ar}Tfۺp:,(ꢒh lXR(HqZ4B$& ᬠ@v7餴nUvrkC~9B+}GzhI8hCڥ5 oL*q v\mpΠu< ,r۹ɢϟctYb}ƭ/JP`!va Dy1ь16ląFWAӈ16F\ޠ8ۥ bMD?9MˇO&NYX.o ϣ#Urj{fUJ)Ϋ66T)BEƄ:X}%.SEQ<>78OGdP`~a 2B4L,^|+N_$^@jVƇ`BP(Q͍mu>CEG)iCnM_•@r_RBk/D]A[HƼ|.B\)| \$X7) J`HiU8ViOc:WA8 1WN&يs;G(dE",3I,OP )/ʕ|0&T(20@Dى#&vj05ťgp!BB+JpsBՖ0PS.)l .95=w''3\;k}+k^QԾyݠ"Nܶfqsuf{#"+1QNFI  _ql{k2h_;S;`KA$0҉um19aao\7R;<=oS޾g* hxWu~t Qy-9;@7mBZjU`1k"C_4b^!=aRqp]*N2Cϟ i SR2s#TcHCp#dXcƅ$]M,Ḋɔ V iSGzgcZ!2c;L " TDڡ1W>n=qhk"|}c62f8M|lg'T֋)M)D7Qb8]doIo0ƠXB بAVءVHi&Yw']8)鬋lý)yg#>0w]mc'O.1ĎJ$l&6*"jƽٓD]jʿOUT|}* !fb< 8IFh9~p$sO67[/͝[i6) 1ِ\|&NB#>ݐ :X !DQY@]Se NYg'}&Q5C4;s ,9͐A1`2l NP wbI-dVE ^ :[ "K#̲$5(3P308;}QNХb#vqtm^h1͖ wqBl#|,>=n20&Dc4+Z{&ދ9 q{OYyv>__QtRd9r,)'^69 s…]Ry&(J\ud4; ԮΖsxOBL|,p@cs֖3ƎLt0((mg/&办n4Fpg}ad _"& &s'd3>R[D" mh-о},LruTM'T:vjHBO YGRJ!k(-j K&aEX{/`r2 &Mwuar9nE fw7tq-a}83ܵ5ԽN[84{I.wR'MnXg/pq4M*rs+T UmAU[G_hxbpEzE ;- bzZybEu"0Ү6֍hd79+k:@Ј<]7a"(uE!iS 44SIeĻƹ4pbԚi HCJkfL 5Ԝ:~hKy9ѲׁNC[l\ӰYN_'V_ r&$5蚝;_b[ !qYS4$ۨ+OޢWX2AE'=;D9Mm8, 4_ӸaIZF6fG{!З{PNKWcѾh:Y>ld@0`R|$F#vӟN\d غU>Х$%4W!wu'>ϣ͎`9ngh@hx)c{xկqS+\ D{m1?@@ ˆ+._C,n߆ Kޱ(B P`~'?eD^dTi$uHmy7^0;;p~*v0NXf /bic= |8]=3l6.:1f2ޫu|g:"ŜcBN f2f". 7+'8]]EuU9& yHesjA-M=r09=#n|9NersNENዝ&b&lk璼MK'q4ʼnx鉮G_Gs[\J2 wXT Q &G$82BE:ii;7;Ge !^=m FBJ{ EUkA0Yw!^}<'ߴ8 Xa%0SQ<@r *37BZ'G?Pr!F N_Y A-Dw52?bSn}\7~.b&k3ҘϰISacp41 " j n>G,d=mܾNUkh گ"(J9?Ap!*l%wTt43(7պ=$=:MA02ǽMKu~/&ؐ(>֑pqFˇPÜmhBU:`glfPiL:G$kLf2 YcG@j:f齶7 "237LdWCL @Q^oiȰ𰡃AtB3DhGگr+ڇL+'^Tfl k#6ܓWO:Ed8cq| VDRbkU:t PNȲQL5s;|xa u3wzlnӈöΗA5-aR9IG|L6 (T!W כHS2(@Î% ։Ղ(O IDATB]^0B8HqD+o muB!U:9XpT*QjAhi@T19Tfs6X0P%Ywbb\*(K!P|^ԥx Opt<ʚy'-Gw b(P>>55@+"h<7/-68+ Lg41>Ǖ)4 "^XƨֺNpz5Ke@hjlR cڻK\*! *OI>a{^+D(O[Ѿ^BE:Ckwpy~>sJ]d*WF$c6|-JGG.R#)"DT#l/ Pwi#v8L sN`l0sqhG"zQ𥝴Òu @[Ma^BG7N[چ%t-x>M  Ό̲8UM]/r Ju|<Ƈ>4WκQC_<֎fL!0R+vUý&]#Di-/EϳMW)uZ8=G^C\}.2R6Pnjw/ QvÓI5mtH2ޜNޮzZCA$h!'R}ompMkmdR ue1@{s~0O9pp:H:bI4z"䅁ƥ;>q:4(t]i 2 Ta< iQX jl8|NѤ6%6]-ob;ϭ>ceۯbe $f dx5ރkT,C%fb6ʺZPUV('B;r!25p*s;VAr.P/eI3Dxrx$ դrUOFMC݇a%F: k޹MY4,c$Z!FU{te:c7eKnEVQgza|gocPM+;ɵ@gTrdY =0u)}2xpKsL?ܧHX+M hͦnb5EzouB}b44rS*>pͅvG]NP~w%?B$#uʚ;;Wڗ$,&3kE:%v!9eb(rͱ$L 1Ï#㓾%ҡ.݅DčE]{ !Á|}\3 /ۤ PJ! ["Blx1$9Uk3qgÉQ,1Ɨh%˟gfdEL{Q~fϳRc<^A0A m# Yo;,61.Oqƒ$ dFAS/m:/p2*i&ǶAœBu.Nt| s_+&$C@O@E?ݵ6"+rç̱7>n4WF]X1/ -]ц25A.@;w[$.3 !K q_I Kk*Tܹ#IKݕ ,3PnxICHiO>:w{处q޿VQcTcsul H:9}d*\ՕTvQ.'HLKD4K 8'MCXpgpDg^fOԛNN;- fU\VT %BVgcLGx,Nw% $$RɈF;YɹmfL]xg>Rg\o溙=3b= |ڢDŽ@cszd*cL` HܙP`rl|dq4B'=;JWYYY"✋__U]\Vg#ɫ23 J) \&vz&RyҎ^;XF턆^67a3ݸc%yG[ -wv؂yŕw2| 6ĄKrf1cb,qJtS4Owq5j>gV7|8 ˭Ȕ\].WT* iίoUYv.V]SrKU5־9J\!%wSyA9CaTԳ.Sqr2 iį0\mKL(; #.v.mUo[5PFBP#&kt<̽"a;Ӎә$ʬv.FtݨAcNB'4kJ+h-Z`z~rI$E:3EU[e|-Dn^PSJ*VfM}]+x& tQn63% |Nhv_gIɍgpjJ&ԕI?i*lb8>/'%iX5OÝyx0̶0ȶn^:*q[qiQo@kW]Tʭۧz܆.N`%rCE:!v`oƯVo r4Ԑ[1fA ace% ueRv4c{gIL̬z===W{fz AwM]L$qML2RNJL$w$H 0 09xpY5ODOhUUfFF}۾<3BR囀Md4J¯5%/}ogDBw!g"Xz{@ j @~9 ~ l6\E[/b,-3 Gf $gp;'LX1MUUpM^o N]>! c \%K5圥`IehlH)bbNr~Z,s@ؤޛ͹w%g!U6i.Es kBL:o²C8pX=VpvoyreOrN*dfC1cKo񼓁,Ϋ+F+Eqz\n&4&p :ƷQ>N}ͦ=6u&27(.Y5AFIƷ9 l2lk'MPV:5V 1Kge2_o8.}ޖIWO [Pvlm u9gYvݦfQ- qxIUrIրQ2\ǹ;$a&:9`㦌"a6{ʰUx\eֳ9DU#@%$䳚I ,vTdloA#="H+L.cH5&4 h07C< ?. @솫̑cV&c3@z<;溹C_p. #cp9'`0o8bI s++` *LE12!iD,Em|碆<صЂa< ^z\bh!ɬ>o!_?F5[[I| :nlO8s(b0_>Ҳ1 @֛/KE{y:@!p8Z*K_v@ *sc97f+ C@3;\%;5?@a,|9)I³mɰ\7!,QveX~XVX?u  8K&îYXo> 3Y9FcL5ˋ;Xk8qd] Z F OT XU"`Đ?Uv;&wnIlBzo0Zj1by9h#':C{ kcISʵcU\ś N.FjUfɉlO]`F0|xp>nQ%•:cZM'/m,Gh‘TZKܲ ;^٣{5Q[%}Fg\Vˤgu&4ƌaty>^a!hȍF8p2Cmj[9!eDJ_+*_;9xX4Ex˞⁹FW4` a};r+SbШP@ wK;0 T]rwMO%{6R8g.(rot>f:0ږ<'gmKڈW"l\`nDʦp mHrOzA9 d0]F(P_4}%9&mc5=6XvmTA>U:0^%@.*F۰WP1Uo8=kYl;%,"e%K8w n.8&+iiKO~CNv[wUy^iJza-&eL2{M+Ջ`/ L*7m7@ۈw]H5sM~)qN3f";:ӗb pUmֹ- ֧*a tNmz$=:e;Wyڧ8q1hSp-,՞[<Ay"UΝeͮcOu:M8[^e~FceNXu^[P崍 f`[WMq^UʭmnC˽Y'g>(~!'QMxM'#ثC$h/\?~AI  ^Tjs$b4 a<~e#(Tq6V!T*=g*FiQӶII ^ \67 3C\ s;n8h e]\KLaYhG^Oʚ$v';wNh*NP|U= oGM+^e"tc,]}~4M&nd Jk ( ~2u-:Sœ+=ʱɥ'Q1XsNXuܤ p%_~ь{ssA߱X%YB0b`$ZQLw/[ <2S@0 fdMdĀg/Ic¸L؋67E<仔s$ N3>cI}5&,ڈLaI2ulJ<رs=iF$m uFrCI=طD~ff\I I:Z&q碾p=Z=’iQtqF?\d[kq8f~m_cI5*5e/)M\UY,g w{HwDOKp-"Ƚ&#.qY&"\ .V5} ]Uyzhxݼ䄜g L+7ݼyVI9rO>E<@D QQsdTmƬVFj4AƆX<~bnyy$ %OSu}4eS9ړ˱OX?V;?oЈ1# ٘Yd"/8daTa}Nz ZsfK~% .# ƀ{.<) ʹ\l!4˘p4,4Q+1h@^ܯ0cbMs'pIw`UY*WW9؜]Q* 8V30(`lKu`>W*cSmJxUCTy#U;QW05_HW04V{~5-:p|:J9!%匡O{.FXGgZik:n ~O^@X͌LZy!}2D%#7&0bdLiaVio'` xe&JcRh+ҽO~k榲_UJD%yIǔ=3@Az][UO~U3U&?/l2CMb'BH8,b@[rm:WH `pr _i^J Uk( l'a@@X *'_r "v<8˙Qo/!T@L@HFlDUP>&D\P+g*}@Z6–Io.~_d[EfAQȔd-T Os}ooGuwT vn\XOX:n W'],@-sNYpV0NH65%`yw?UK&XpfbIeu w_#RE -%J L%Y?;{ YY41L[ʞc͕ʔDĝ3d+秊 "Mz,{L|=x #qT.۽ݲsGF@;¶qxY[!ݍ+JnM&T0mF1DpKN<s]'aQV.~R@<$mZQ`!"F)UQG`m0V2KO2, [X#)jIː43j&9_7dUVX E>:vAHsx.$~+lT@ XMw7-Bh稶` R~&\0CsG?lRP$AHX,BNDTۤX;^2-R.fK~>0m4jyZ2(u|pXU3u|AׇT^@H0@ϔX?9%g sٕ\/DD5ڶ"Wn65'1%arf!;"$;>;[4CPypS{ꃵ2Xuk7e~ q7|F;0F+n]% IJ Ut*N& eFH}B &YaT5-)SRT j[,l$pO *ysCƦ!T-0 ojݜzm2JgUiR.ADJb"Is*xxRUM$1`3Ti5BL>tQ R_&i6FKcil'9k9ge1~dS*aD2m% Mg6O'~dmP[ ٶ1Ȍ.^_})d'9_hEX^D} e1ޱQ%\.cX븩c8aa1z0VB"RH %9+bj|Cx^)Ȣn,g!pS ]5x9k O>zW瀶%۫[Ѐes."…:2-3@"p 'C +9K; }4G|ȜT?g\`T2 2!$B C)`Hsf䘲w߳pyY%^_" PMRg381 fTT>X}%yq23\=8Xǭ:nu|{.̂yΎSq&B Mi]#. ҝ >rnԵLc`g,}~mAٯj HO FZzy,sGf1 #ڂgRF pe|;v=́}{ :nڨ_p ]ZlV)c*Al6U׾_e37z smriJƌa@:XmYJaf'Oc#|t-JJKOQ%89o)+Kh 簞sʞՙ0MR1 i̵/9u܁ԲY2fupU_QCoʾo7ȼnx͙+c@0ruLK%柲663KqB%-*v#.V,'ͱ fG#a$_`9+kk "PDg*nKQ|5RS4j1K"̋n7~,rNy>nrO[ƹ4\l%FK>KIs(礞c40}l҄iLF<9T(sj^ad`֖D#R k>sIʦzaknAq8qSr*#YFǼ&SO*E  ?mfJqk2qJ"뎶elڰQ|`kx.n]v\GGr/0Yt, \MFOX%u˗sw$';E nӠ4^>=11ZBpw(䱔5yzrOq/O"){ (*{Z5$[W@!W.sI^[$kE"@q}_#b=&`$r7``VS5N$NSt ~z~5j6I4B@Jblкsxzکc:g ƍ(i6\/Ȟ 5`~/?΀vYr(~eD3EF8*^m\Q9n!H'f ̀,eMfSNN*i1Vk7eXi\v19J GXj[vK: _ ]//l{n[51IE8f~I%k+b7 n|we0Hsel6v+nSs/fjE$3NrJ34rvI\ ӥKiU?cA+W| W|ͱ\yǛAJc2<4G*@'XuQ2re8U@(뷂)$Ydbx+> ,V 0aKh/`)Q0k[~rՋKoj[Yvgb&X:n(RKѐ!WϻE[Be@/\eSl}R|;g*a3afSƶ >p}b^_M \WX}|~׽(d8o/u~WyNTFdP$"͋ x衯Oռ:sE5z500FU*s֊R0Wg`9๮hd4u3526LpKɹ/ jfklUXE-md6u6MtVnׯ븕* N 'O8 "ide/~iu"HY'Ka{<@Cf}@`$2!s Bss@ q5|@rs"N%1߄H е̃b4އ˱Q UԽ`M,}WiP,nP33. ˏ` :Tz /~w g# m;+_^|o~o IY׬GZXV.0gsN!K/%(UDU2#bY;!X,ԡ|J˅a`N˧* &)#P2XX:nްީ9fIЮ\Rt)7TH,mI,_goD3;A b%]:M醂]<5-% AcSXuZ x@T/ #`j3ʤrL\NBrBԀkk4t9t\Y9'_,GeI>?K.kѪ&%Ӊj•:cXICEʘEvViz7ues9P=vx}$!Mγr|i@48{t76 5y[c m1NـY3i*aR8㾋(*Jt9g*eV,g4uԤ('-u"ﶚD:W,1\+WRNff䯦ai),mFɂ\C1VK-~͡k4{ Mz|ߔmO1y9jMaD|7" ]zAP,ZLt vIvZ8Xᇺ}I?g1Nidu?jenuܤi͟ z%>F5}8eδ> P+eݛ+0c-FqTb8wtrNx͉#`daflkE܃kGfL##]ŏ˘sP}@KIedXKR;Net l!JtYm A&]]0~|y񌧿mlpK.b9UvXb"* MA[,-ɼRsN89a8a IDAT G,/-&ꬤ%@<<`4)%LRrr> Y=V2*QsG9߉_X9knRRӤFsBҁXMa]B;xm';`~qrAYra{8f5;*O#EMDu..hQ+"VX4B?>x"T]&qeu@N$ixJGiuYr=LZ1g^5+#isV" 1结qX'yd3b rCמS*1xE3fUVNcB!%}.IIXS8ZFOX:nʸ%ԈC}l{qS,]ٮ {¤rw =K^0[̮$NAR߃R8D_,h17 v$e$ a8LxI|Ӌ`^` 4b˙3Wi[T%FAEhle dnw^yAc=7\UOEI3f.ͺǑfz[xo%ݲvfk~mZ^&tS9{*+ °ɼRx5MsyzrPUÃk ϶$ -u:suܪc"\*;͇,1rvpR `!ى10# /󜓀+S,/'<>@6[F9#t?go;H*83 M~ hp%hNd bZMF ЄG!i$B,UiU\OO$2#Q(2a.i mNd~ duo!~?[tQL@Hvd$t 첼}~!dέ4V?V6J9Գ ȡnkՂ0Y2SbHAoC| ?ilҠS Ej)\ڪlŬyO 舄!fyPS3"WQm&+sHPOLz6"pj!Hn=IoXKB?v&=f)9 ̠ U`i 綞ֶDĹU0NkĈs1?_@peye0sdNz= 3ϔq$טJv|i,eܼX?HBv+qrQ@ bEfFТ:'8 1&Lcm x6lMy9eQyp VLU;#̬[v&X:n e8 FUSvU2YOQOȘ 2 &&rKSܐWz{g:>cX@S ¤NƘB AlU a7FXh#M60W$OyMHY m;"(gKHT0D A&(&^\AXX#X O"TTQy*, ?߯ϝ f)~3fU2踾wJtcNJ(d8?D\W@UIx!\~oLSMzϙ1 o"2V?`5[$rc콦uoU]N$H$Lfp2#FFlTM~h[{k͒T. .T6q@[}s@?ۅ ]@t5q| Dc%\x7xgB-b4C}M0uk е[=Gۻj f_ U^>/H,Rn? 3WqbkT_W}"oOm-=O<ň7/lS6Kۊ/fT@xwf4I9R%gq?py:.X2iZ1"]Wxf Csk;s̒].Gl*ŦVQ4>.O# *J) z>b1cS@_/=5I,nKινb 9*e xʳxA֤239=  Z;eL{zQ(m`pFI~y][9YcP8[9'P00oU)1NQʗ?/Qt]>cyhƌ@lZql^9po&>cX\}q14cT9Xv0wy }?ڍw|dTEǠ)M۟iI]X*A<͢IjU;$kޥ`U,I澢g fǟBN8}k5Oe9`H~Rj~.~U"$Hj@ʳ//¹dv4 L,^R4JQg*A5] p%}"2k4},SBg^ef:( ִ.܅=*h4lPy7y!^Pa&3@-fʯ ]G1qrRiEAl^aQVY}\yVae`m*i!I>禧pc`>ֿXǩO}˛DqʽbR/_텈0;ҏQpH= q"aƺ"̚,sTY$$0D\3'G2OJRm#"qT:K )2v;ZQ_WAzRcќZ d{[3S8nMJ+u U,[]DcKD޵ZAK 񝒤l`GZR'';d ?2.k* |AvW <5ƫnr(JH.y85H,R-2D2X}k >xJ[+a"a7p-ۘ& 7Gիuff`%o. ˜-Y熲)o~maqi3E{;cR3A-#f<; Y7?QIYMS4Ia 3QpeF՚u{`s5O5a7a@2fbܕC 0F8&j"ȅ̒ײ+cCy.{#" i`VWy$tt-z.ٽ)2` l6l-!}V{w70W&3 $6H~ޠi]3" "mB[x忘{IGe9Lx2R'}c@ESȻuCOݷ_3@x4O#Ŗ8#(yv!kޢ憥DHd;8IJgr6e ck1"ℌD>o$@{N6Mq!(C**;%qqf)Pd "4*) .v.֪Gw`GiWr bj]e) HmmGGT aL#q=[/B&0EHŜImդN>B)H$B $`F2h3DD ӿqUAg 9@@Zioq|/nP5ʚU^=qy\0g\~~U99v;(JFkdn[F756:Z}d wl dF]62kWC殂3@3.eٍS,*g[4 C.kB;kkQrp ;gq6-A9gdrJYZP0 Hԝ:#'BFĆ10g?џjϷj8* YFn4[h?Ħ!;Dx](5dWyK?ZUL+.=ɣu7iܚFM}N`7#S)5N95, 2-a\i+1$pj4:<^`r杖+f6/sh4Kj e9!UY(Ω0A(fl 8VFm[*_ M Ć@>og%; }%_p5hnvQ@jqX:Gpfݟ!ZU99V^c"8<0cfRr&?:ch c7+`bAΒeEn,9Ej7`,ϣ1k#ᣋg˨+ ݤ{O~o !޻EfO~9caRLM;ڼ'ETcazBYCdhr7JZZC#9bd %:zN~4# s@hw"*ڶf{o쏰%Nts7Mv&F>zJA[h|ʩe n+/` .@ʺv>02 é26el(iD;>8̄oo/O9شqf{^AU8Fu W}<1W샱50IO#Rp|&]4V֓ WkkQ~_G-2'3&sB"^Xr6&)"~TT4flɴ/*sU|B`\1xW/w{8B~Ji9Gײ'XY4Ɩ0r@ TJwd\E9=4"8s2XX%u|cGd( Ք_0ZfNrC bwE՗}e ^N jv*K&K4@yBvO?5\9WdɃRFr֛xީ٭OlY/m,钨h!bReFo{(۲U-Bu3[GԹUg֪Z7/$M u{cskRQq :fdYw+
    g?_ 'Ut$MVBF/ˡЫW8:$BSm~`/jV<$RL67klPY=aD?x-qGHYWyp+4XལO>XD V|"*`Rz-ƘkުdZh:"\wm *dWj@+B^jM"Vm@V xGd@}LmW$s*;D8H U*&}@Ghi (*|bj_3nM-:=4l_oa?ofj~*^&޻Zkq,>0Ňчt&A|#s󇘚1)l[3+`X e1? k5*z2U5 */3~hb'$ /#2@$8ѣuѲ'àӤ:n@HqPxt6.h:|t9 ? D Z6q"-|p T3O'LPóbf XԙTgG*Ujmzϫ&U9heBL~j2l Ķ<Enp(>_jȰzZ ctry`h1ŘG9g}gLٕmu+ W3SVdؒRqPPz{j3;|.'kq؏zr 3g~ PPS XXNO6s05]Y7RFo' CuN>l2~t8Mе3OSIQц{Ʒcte>W!mNCH{WO+h;̡v{b( 僿eG7 [[Z/DzlJH4` ֙&F7ԖYv^vuW Tq\}'k8~<”UԠ%Hp?tez傜B9׽`>Ej1vPGqќZ=ދP^R|yg):ӝ|Yezgzgύc; m @%=1`jVO=feYby_ͱIh }K[ |*ŚEUKp7^ ۦqo{ccACOn7ZdJ*0݃n! F +[,p6B֔m׽ETk 5:8w9N3vm\oSsB] cUq/;ZdE a4cG | pZDk[hɘ֟.h*(a:ЂďrO#LLRj MŚAw7 tO#Z`%Հ*hB s礧oUyq"k WC4n$ =AݺZڻٻ:>U/COB-L|m*_$OC_ r5+ Eɜ3ZH[ ۅO~!MXf{JVQ̓)cIe ],f,hʘG)Kz RP~o=Z?4-ig'<5`9eAQVy_uvW /Kjb(cB> ";Gꕢx ky״yU7A25l[.tALMFOVSłxO1N2v/ɏԋw876 ((&6X5EAۭ&2 I丹6diIOVѻWBU,Z-k`PZ bJSS9NQP칌s,+ '(53\ { sZƆӦ"ʧ&jCV`tjersa|bM"H5L/[è,dsZM!$8_Y;w^اro.A0m7AK_ (.0$>;Վn>?)WVg$9\QU9g[/`voC37,\0a|\ |qZ͊S?uW<ȥtbIwg\L4.|IIQq +2YGP(,RWy|u#G5c0ǡ(0zףU*lp2KآYϖ'YV'U]kqkV@+0/y'/-#f.[\ɂ8߹-o*r|-12'wI*)Dhg"DVSo Z5@Yn4?|Vn܍ ̋ogŷ]s<~7a8~ee˶%tp0j Z$EG=`l`;]};~eSl1Jflhkv.+OQx1ɖNĉŁTn~hBlh5u(LJ<` %cjܩs?_ӆSThb?b̽;#վ/'Be<&Ipe9G'B-[z= DCpŷ~{ۿ>yWKki;zվ e1Fůs>j[HrOX2#QV0O>o3h{op8$Encs]1*VHX&8)Bx |4EqU%p;$? ]i\'=R,wCO$|mm7b?nr;knwz>]sGVmժ]cvKZ-ȲHZ(h|+jLT 5(=f6@ N8]fן5ݣq.+Rؽ IDAT+x7 u^0{t:@9%+s}zW ?+PU)Z.Xr C_%ORÕ#uudkYſdvXx F!Ă|?!\}0[gDx=o(`-ؐsE`Ut(@{,'qGYA\D=PdmuFN`kD]r{v՟gOB'Lt.Oۑmmůb#T~P\-Vġ5Qr A UUT!zmCO/}˻xc @1۵jF㪓LX +Xy~/$ jVdN^*x}-?Y&@+VKՒoEؾXK<`Pgg{/)idajj>S=Fk8UA8UR:..TZjmgV4F6Q 2avvYϺ:nSF?G{pgiL>mY,)70YAjPj*J$DwʃxFM6McgIUDE#K#`iل+srOH\zG>sݫo=/ݷ3(Gy[[DazzL,=ip::oYh%Jp t MFd%ʁ~etvʷ'?9F) {T+|\=jË~pijMST!`.S@:2j/z&tUFM߰-UK&­I<`-̇y<INgY8!;⎻?җ#*VtH@ZOۻm1u:V6F85˹7D~XV{m';_c/:.mmg K>)ð=J+\j @5Ɩڼaom CN|rcygfT\s}9S+YV&hH۴8%>-N':&5o*XZ=It!"TUu#;BuCD=_u~K3(wܱߒN1u/\~/29T堈qp;EVĂS dUU}ۙ?Qh[X*l0IZ+UJ,9ɃGsN'0(֕Wr0LJV{m:] 62si[GUpss}kXAO\Xrfs!6)((y>o|aVjpd09*6N^u^Q;fq"!`zلtoXOomBl-*6`*,$o-]`b9Tއ)d-({S K|l} OEFgm35z]љ]F+.͠6@jKq9U4G[2@D 6शdmf?fL悖]s09YܑQt2wXea,L6NPOd8yr6o{O9P Krܜh5"Z#iQHL~}4U,ncj@w1]c1%O3)O]b3dT-Հ e۹{7 V;+;^L]þ{U(0KD0$EHSJ#j )JP F C;s ZX@z3;]G9~^d5_9Ƈ} Ȋ1)Od{XL)xfl8hN02G, y;N%A4&wƒM,+5\؛[(=RO2 >/^]~jVeS\ݰy/\hņC%wJouhUfB-TƇA UTP֫xA=W\veWj/٥_t{,Urz\@wWWre#LG RؐAw/7~c{Nۍ^i>LT%8͂+70,J/΅сqmFTj"1_h__pUD%khJ)8U~{9xKXN`-/ ,`wzM9\ҧ_֙)5V6ZN'aos_/ů' +7[T5+cP&h|vpQe\1q>=|xKgGO{ӥ:hH_QRP+YJJ$` OjMh=]ݢzr>q@`ʕAVJF#A*^/}\vGm]f)er&@_!Nr2>I* am29ŔbPcY/WWS1łȂ1B̔13+fV>C3wVgen'rєRVp=Sὧ(^=8\-S+uàG:~濨κ)Z_E|xE]tS\q-k3 |kIkYj,o{>|tc7Մ}]r>vY~yCc{[u~hUQ(pzV&ZTZ*jMJbC=z=IlҫdUVb`ˎkmP`̘EL6% U9AJ0Yۏ,ѻ`oNb''#z`kXKlbgXfՠkcʬ<ìaC`HbQW,R6溯fj{_`|~')#Z/l+RLzw<1fܽk}O**WzZ ARԧ|J]뷍V  ݎ^>:fAi {lAJajU(kyiJiح}j׽w "\(I9qqNT`UU:* "^i ]IJ2>,R9qm>r^rk0?.WigQ|(N+_ƛ9TjU&e熓D|C133 Uie_~b;A}]pivq E:Be]Ji*]sTvQ3R5dI8aH(g/_bs2&m6ZadP8$}mN2Ep%qDj*L+ ~ fߝqb-aP*@4ɹ`9h^دtQVy$lqUpr ;_+?qw%LhUă~8ZٲѮю7Њ2~KK_ }Z+3_GF $RzeߟޕNjmt5wY5^ilG#d ssoCY0k]hvjJ?Atq<Нyf%V 9ei-U# K(翪Vju]|]E-7A2|M=D}ו'پL#d2N%&+ IWzv*^ #5YCs$ `^y!a CTC([=_MFn](k1FsM^xVK,l;$uq?`bsh5:ZJR=DJK\i*o:r;{Ƹ+Ķ\_e ҄,ܸpN..뺬|;ܟ+nJl)4aņ_QU> [ s>*6cf"QCIf}z?$sč%{nqc+ W֫.5+A\Uq^qfz۠Uڏ"hqk. 840,(pý?= G7c%#{,t~8Ɋr }Ta뙺j;hg^6. C!(n'Ӈoe&>0V/sk[ N`*X`Ǭr,k@U|l13{oMϙRRLƘ0AW5*nXG`7Wڐԩ D$ UIUF>7tw,3UW1nJ*{\E MyYI QA Ob07nz9v{&fݞݞ+n _qǩ#;yМCކarsasA א́$3iU &V3h)ט^ME]D |q1xع z2d{+zHO>r+h(K EA$KCPnA:%޻^ӇQZVD5hv6dS5}=nVk2*jȃUT ]$|ۻ}wɧ_|Y)LT,^j] 5~*&|NDa8 {CQA43_t Cs Rͧh4'Ɩ,8p9ʕWyE%GBTÌZWj^-fGeʛQk(+O= WV't$ | \5jdf HY"!WQPt: LQɒcf)҆s"y'h_ B{%Zj`Xm9\Kף*si_3±nώnl/z1L*V4 6*S4izPpR3jSլ jVjkXg-~-kYi\gID؛$`&y4)_> 69&T>9~^=J`$e1oTq1H.גV NiܾF%a[PVs\ @C$BFKT|G,5 }sM|*woVK7~Uz0Tuy"I7>|\59i0(as`yPF1sAڨͰ\l`d֡ZRؾր>;`ĿpeAXY(8DVfCY Y٫"* %L6}Z|1h$XV +3.# rŲ(wzNpHTsy"hEP姆X5?Mx6{V2{м^r;5@kyvC5S+wRX( LjiJ]ϑ2.0i> ld~翜kQzAK:&TXS` Ta]!-~/.b_o6}7:|#V1ZV҉\r>6[k&`uR9Ι jbk1i5JbWÊf4݆,{W |l k$7nm`Ҙ2BTfWD}0y;8.6惲sBVRrQ*2 eb>~B0qtbL6X{;7k>% ;5^ssD?:{G5i~Q9P3krO`zY!T^ 4tQ3a.rƤuO m\̗ ;!U۹dSUU\dO:`d3JJj+S04|=\Uz чa"b3ews]4CuYpk8vk=ƩưE-ajJ[Ūe"I@"ŋ0eޏ2:@+_As8Io-|`[KIU[JoN )1Шh)[T`JKV9pdB#R6rPn0)& +dm>ʬS!Ft,| Y=\ZQUS|8ᒾ_C3]v?纔λtV9vS]O߉BIkYh&yW,nQmbf%w߷"WL֖E_ujFQJ!';f 0&+=c[!ٰi-u]S;Ȣ5VۆZ0*؀%*.(ht4Q\dpWO6 )W_k8ukpI|UeS{!\e&F1t(a~p FEJj~9ef2%+˿\Ͳ:tj_-VrE.thĸbZ1|hoɵf92+ >Sg\8V@a>HzFIGۂF? >錅*%H]={/veBPlZʹGT.fTfrMQ#dJ͔+ШZ@l:ShE a\6zQFR*f(|k=1ȻZY]T+9QUX U?Dl8H2lr|- 9: ˯hmefγ\&]4T\ }b越U|+WU@Xk\;B2.޴[q.+ f' Ёb&N+s>v%#vl[MGF A#XitЩ*5|;}_{sR2毦Pͫ<~ȟ°0S+S@8xbI7r).reiPC`Q+WfjுXZe4;.5tLf7CE"5@%mv([4gek/W9|PqΗa4(H'do~cZFx⩞]hg<Z%/)X[.Z(03u{7iWZHfhePU_Cl,5ĭU&;NaHw@ +x^x&'v19٫Eљ:.{?"hlG!4(YR۽R^m`\m%$WIꍖ QO}ߖ\g9' H'Tb+4[ \`zȜ{7Hj0 "C#܃sG^6T\*㶈^)x,8 Tb0}7YI!&\J ֐kt3 QhHQ%7أU@H[3VS'>%4 |{DCL={.U,K pkEXI}e(X60 {T~mRQar*] TUUcUi'EtO?2M5Lp+sC3W29}9S3{Lmc8E"`{):F,G?vn־h^ [hcu+ic{ۺ\mRq*J=]y'I\oM_!َLJ?dt;y-h:5`Js%+Kh *kHX 8n-8*ί:_jNf*m(X5`jvNL7U-+Mj?<U+Wĵ &R%=b.Iު>ci|~8z->qiPvl3e`mMh,|S-9~d!DghpYZ AkLSz*`AJ \qDzK+pqKǨN=ܩ&vsîxm S ]{lh}91 NAk(X}y*(K\|K1-rMR1+P$X,SVQEj߫48_Qub?iW_m0GzBVR-)_^_+xܺnVDXA`D"⧲,Gm)Emn6y>\Uܡ}򻟡$*e!O\87ҿbDKB! |O:ט .ͧF0p\ZE ^Ldݒ|bU߮m 4̃yLppv f.t گ`؟cԓ,}œOR1X9%pճHY nt"NhY3649W ;Y 3ůs6ibL TDeKMsu UQ5Ӥ^#~b,8{Cj_Pʕm)YUd G#V$$ ![بD;p%!v\Q~INLN"" AyYZdqz&*9)[-LiQ Uey 0͒B k Ԫ*SO^aO9dzl&kвy/`mMhkh/`iR Y񷽉oڈ@ـ @LŊg5sX[E>7{_M8tn'-Mt{9W܊% ?=C;کӵ*]K=ܠ@\[hV @ 9fOhdj)d*Ba!ryP>[ l7[:U&j2MpcmNmLM#nL ,4\1vUdIs;/Z&V\7-(f樇lCym@s")6]QTScu֣^"!N+||`#B^}H=J(: BS6Z+j×EXk3 "ᬔqծ,9F[sΫV!Ts#t:aqT4`zf//y7cO>s,/E'&09`J]5Pڟ]Pn񌆙F ;ŏ_ 1%@`\"9+e! 6U$㰂kre0UDӳ[O<ę/r\~it'r,mh.3%{\@*(>Lm Ts>Fnl.G>&TI ADϮZ;ß} P-0cihۍBsP VY 'e"  u!X5h… |a j?.}Q@)[{e+s<[lM7 Jg2R|h ¤S]i5]_>\-T7,y:jo}mUK>WJ^v }k= ЕI7p?rW'hfW|nzk̄U{k3~wvQ䈑lc'hL[,Rȫ\i9|3Ϭ@.cѭLM+~>vWuҴ΅djS4 Z JfBiPr6M\RT˒)X{: )<`UhBT/SAkEP`P.4+!pZyWQAy@B0 5VVKN[.*2+%ji$|CGqfҨ>-|A<,eeGU~vjϒ!'%"+Y!8nH!Cnll2V&{C[⧶&4jJ֚ @k0yc*V c4Uo=%Ҹ/0d԰`C8^btH?7|B"ϭ vAbes.h+Wv_օ0R*u"l͂Gs:D5 m"$OҝUzAY8s${C?qeG µ3old*WjS{Xk勵|.4v[VAJ(9QkdnzT=΅veTS'3!.$8r͗*%RUJ\2hָ-Uyoc/Meg-$B#j{啲og*K*6I?m=]ݒ0.4ٛ2+TihP#XhԃVJW!W08Q "QLZ@^Agf/Bg0OL%aՑkzΧ]4 3,M. $㨂jmB%>޻OrUws3~wKHIICA@6mNlĎgD̄cv=덍/Ƴ`c B%ؘz-uWUsͬ߫j#eq3sMSTh Bn9mGJ=`l))?H(E 3NWMsL@s¶L$нC`˯|mz`bzM︾'heSAkDXZ1^ T V<y}û ksnUJaF hԕ^ŚTz{zY` vk|}j1Xu2J%'m,?Du/^fouۼEBhɌ`l"Xl]YlBm+WpJ檽;—_ Ǻg]^wAlambWH3K([p Y`x/AzJ!бb4 U@sݴ3;=.)<`dOi)~.Yj/nA"1hA ^REk!v)θ]:v|5Ve#w,)Y]]dzMSMӂ|_0. G'~8V];2PjUV@ޗeR"IHV'xe҅U } y:S12HH35!vmZ;0|#ZsqރmБ|{?).ص<4@NӱeHdgt܏Phb[HOFmZ6H'w֧jͻ ٶ `Pzm}CypnATP}/P8M!Hڀǃ}T P **ժpr)V$/9=c$̺.Me_R"M2j~2L} 3XƆxcDI Z UVL*CYU(LjbC%|r R]ZqEWNH= el~+G`E|!F1>}O_H+D̩Dakpd#ԭg =Xc+ BJ#B0e h;M*Gz92$LAQ~֧jͿƱ yٶ`G[={M݊ŝ@,0b9XepEHB~`~XG|or Va±`f7GQ+i%V襟Rɨd KH`ۍYvpJVj (u}s00X܄( U ypO=K?vU7eP Z;1XM ˘WɺV,xBP\K^Cwܾr<՚UUmXm\^3MUYQ䙴M1/fJFR M&,E$(JOcQA}W{.R?ˤc/Bd+<_0Ϳ`K :ϒ:jJs1P<>uRʰ rAz%mq`Fk ۠m;_HG.ֶw{Βf@]w _/.ў33^=(Q1J-q F*&M-*jt.ה,Hc#ڬ;}4u]˒Ζd_26|̌c0z/rL IDAT.-@b8;wڱΝ8<ӗULW[k` e *pU,CڂcFF3T:pӖ,Gul}뽗V֒xF{.UYU!T3s?PLAˠt G5?hJ)K:IZSyH\O7h]|:5Bā lԷu mI!_|l)X\XdL2wp_9$Tr7T7hNpK?apN9q 92PK܂6N90*VQ3A e-`J탺 Cp!ĉmN>RZ~p_wOg`yO ( RSj=ImaV|yǶ;7}G' ?rwş_*8lh޸ qa&?G*HvrC g 5ʁRr!3>po㣏gA:uQ+(5], H'Bv%Ȍ&l;<aQWZ[5 m0pHt~}{Y<L5Q)}ϋ PRIi:@UL;|߿9LW0o]yU m; KԶVYHTo1q?n(S6T3Vrtɢ'_YT.P Ty2HHcP* E *27NQyԫYMF@KZX}1X;ᖆqc8|aLJql)[y*n*1XTǶ|6crEV {krQ `cE\2JRZΚ# y V[Yf2i\TA,丂B*4`M{KT.Y C2r`A26 Gގ@^qQ 9 eezpc88$j+8Z$:vء|oN[ Zas;2K\4]~40gO0ƘJe V4 V,e`f85(T <Y׌W]+S.yhn9浂*L% Mf"SJ[<+Yg 4 @`8JelCor.>kXiXoeGAry| m; Y`m!k:(qR?t_Oh6-JpVzeC߬ ,X])uX@sTLN Q$Z X \$с mwaR?hg(6Ρ׊\--!{=;^Oͱ~yVė;=N)SWȡ|N2Wo]!J]ZuTA dn¦};ؿܲGʠ Vi|7K쓘r2JJd1.>}g0#P$!V1F;R VM1" Y%A`~{蟞nԭH\s`9aVh4ak -)E M٦AkS?Bv YOJƭWԻ.{b`}Gң&dӠe7C M{7k4rUPWf+57az28a7]Oqob\zZ؇ԙ|]f};W(4NIG &X~/;pҙ%|w}G2~a)#T4QsqkY*^KҔ6܌NRW[?ǟ7r>MԜU+B”eE-ҎI\q N*d2iA{!~V"X;{BV)-*9 w??9XFBjJ9`Y B\O^\ Sr*L1/]4h?>NP=uٶuY8y'Lϳe&D. =U!Mb!^ t'IJ릌rw)d .B XVXX{˔U)+|`7ƅ A8ek_ v< Nlvya@G*~FmMYyJ.j\S;k!p*1\i\^z h\P@:* V7okFX219$ _p-T&ƒ |#=gIV2UH] 3~% ILQYd_3d϶9 S6RUIFjێBR,tu[&ӕM.xeZ+=ց*&'n.\Q`Pb!%vXyUٛ<*8>#`4Fcd"IJeۉBm 3ڻnP=Sb%gZK<]s*+\͂52+.MdѼOL0IkEwc8Y94*uḾhl}#p߂Fs5uZS,ZrսO_s Ab]ʮTé6Hw? Z/ <;v4^]NKut`@=V=@a9&n-\[cNz"EEkadYL}dNDuGE,S/Y|ǭJY=Fv` KTQ Z%<Ӂ2mfͲJtWZ fٹ]'nhrrpĢh u:DZ}qqwʶ<w!WiQhDXp5KڈsV1Kصk ;K@;q?cpUsM-]*U8)XHa6;W֝sycV-Xs?wMTMl 5&﹕X@|"Zuʦxb- 4&\pTJS<}Yvm[Uil$u8b{֑\zEvUĪD:'E8WۖeU:nY8k*~z_LZVJ]𥟛v?ǫYf`Ej KпXjIZ>|_sY*ֆSHC>& XJ^Xu3I޴8U߾ ̙[>Uc:5@wU Vm vu▭9W;V*̛4.d"ƒ)Q9Ve/ FdM@wOvAJ *V#PF?vaD }&ힳB@x:@4}]Nk{.­m Xc5p%}4/|>,z]J(༏|8:vWYSewkIj -vIL/}q8py8x+9f ^rX80g#82M\/,Li)X-1P%^k>tGa#_6}]WYя@4/]ʠY.('hKowselVcu|J, ;cIb-iP F|36BvX0sv=DkѲH-8KM7EJ,݇߱:eу=ˊ/\O.p+l[b$mlU]\HC+Z3=*@aT`FuV 2вYTL[4r^wzj,#50B ˃y*]@^ aPxqlE? fevm@qaKvRJKp%w^w5sŌL>ևѪy`k;r4s>*}(\gưQ=>dpyםELN)vɳ KC=EsQɳ{ݢ[kڵm*X(X[byzE.y&sr.c&gJVVLM.&P!|[2Y5Up{gYO14H$ 9e71(-EaI* EA.6x:o}ß= 04uF`+K 湂L& Vnq_9Ge[. nv)>V6\}F/%(N>w:/D!~WW'bv"ׯi icY[ٶEu,#d`[ n\կ6*YT+oUl-Ŋ-e0+T_]̂ :0au(XMv|خPƁ(^,[N^S9'lGJ׶>Gv\:sn{WUj @h5 &<|M,j_,-/Qo=L&[ o`W6\MˡKetGM)T^`?=dz!n[9de`fYǁ`By 8'2)g7!ݗ]m}ǖupnmKZYkP¦ б@-< h吒W;#Ai T㗑~ s6VV-V>z8Kmp)*Y | WAܾ(v%p dH}XGH[=h.wY;j&[ L+W0g5q r 9pwޅdÇŅ8 FkN#zն2?@s?GL8>w*UR3MR8m8 4mm&/FnmKjjY`kAVDlH(pەWpW 6DB+9\"lK]**Wڰ! B{qhxa=vFɉ٩ZEeTf0kX{fùо217pW`τ+N (YM$["⛕QZ^ Pf4ƾs<yp؟jάvJEyg ĞA=\pbIVQ򿽖CZWʔ+ˮhWެߺB:ۖ5Z<¦mM,w n}5B ܔFN5A IŚ D~# 3ʕՊja@6mNgr2^|㆝qoއ۔߽/s(J(URo\&gFhfBJ; VV,=q*,&nMszuz罹ɷ"&me .K,qsxǶPV)ڵ,k}=^b,=5ŞQDp+Vv.Z@9 WzsY5$voߢ= -$mt:cϬi:Dq5oyV6jo%2.RP{_ T,Uc|  YDp0[sa6h~i0\㵟/We d];$H׾Cvr0˴()iT1tM]ÏI/XuUb˭ڹծ](wđ#yűs(4$O,a>p#a$Wgi x](cɠPe}R*X#9sS,`NWD qSv8mߜZi|5۶hppoS# {,?֕^FOo^*$<L= >Jk@eW5I~l ^wF\mr`?6Rs1?B̐+>aT7w.ShrŪHANBQD fNjlJϺ&;Q1pAXE'K[>@{ᶌ~Q/I`=K.>h|&g Ψg/Oӝrn@Vekdsp96d)6]۶"DX+4'2Y.ZXd2w`X@G%ַA3w`޳Ɖ Hw@vb*=/8 Nk$TŔw0(3q)Y589P VtdjV+r˃1e$J_w*V,FNMp8R,.'vن L,<ׯoM@ΧQz#t<  Ђ-I♗%o^40S r vX1a"{ t7So6<0ma}mkRcמGxi?6{d!YNEդI< yU,SbLBD1SY݇EVCW.; Sw*߶,vK6| ֲfiX.rn4 ])t2ET=%2*uT Pfj}܄smK+|j*Rk>*pl[P?,&gqꩧ⩧GQP{կ ##`<Z7AuT$=="FG3jo%/oJݷ\V(rwt"uQ6cqW m[k~m }Y8cO\~r7)[-I' KX)\j+XE$D m9e8).FOǧlaV:3 \Z{.W2*VVU,RDֿ>v)#8s7p"xpM'$]/\Їf ʥ%aiI^O&ؿ?z~S`C_%pE@GX,Mq7 l$w^ޮavg[.n*UApe D_PEmOgjnȅTlvbh3TnTZJ[X:!')t80j<W WYx*8LO.Q`dDQiWɎZKy Oe5E3r@Q%2ʁE \@+{oeh?S5 IDAT8mnz]V΁Y[DP{ÇOzyv;w`Yj ϛ ,Vj(RBOy9D`ے2(|psfqZ6{7Cn>?N LTfzEY_gU m+ebLPeHʳVpV[,4̙,4נ[9X܈y~ժL{vK#\} "JS,Y|B[Y٣t+F[~Ȋm5XTI}9쳼X܂69Ү,\{1 ns` 4pIrŖ oi =) -,YY- V0 h8MJR0wV_MaV=2ВN;Ͷ-`-ra=Y8*[y304d11J]W!@\By E5D5\>|(H܈`!0*MQ`b` ;@]/dL7i+ +Yfpo,qeerXL#(2W5+k<nz߷:p: PVOS>pzw黗CR>e)Us E!EREFik( 6! M=(CtQ՞T&RHF1<ܱ cFpSyx{ߴVyW7SFN݇c_`ֻ۶-} b &6!zЬǬJ| ?bb@$ P\Z+mBx"]]E[i5~ķ;=o`tb=E=Lj*tE Jy\BmEF(X1Zyg3w(Veʅ@47߇ >~C䊊O'ȅv^8jׁ-k;m9:8h:'Y9ːU<p=!wFz7 ͌,<cNJE]SQ˩Pb(Wքf7̡J 41mME=P!w)\'[bF ]r b%^fdV]yKfǝ_SbJ{Y=&*vN'T+0[0)sg7v֏FI٧ ݆(xϽb'{vg`@d$Jϒ}@NTJ,@x_ eU!TUҲUI XAQkp*˯ Rtam Xj(+t1}a'ަ!k푅_qT]%)"F^o9>k;3]r9fW\AJ/#g 4^ X.8p9[_&c+@ &uޣpԟ`=‹ho3`i :5K~-=؅jFZIcՇ濉FSjẑޥRXNY+~$|essdPJV aOm%+b抰s /ZwRzOpáN~Si=' tm}>{ԠW|~ƇY]2,-r5Kh9E0⁨YYiy6kh*L{N>VW'^Ib;KnlSqž/ (+ʣr~FIBUq|~$9ց@ \F|#sQ`Uxhkj|{e*hiǫjommkZGxX;}Ц+\ŚPjhWe`ܙգJ$( |JVWʂqPU XDH/@η Yc@ڳ*$kyS~2ZWLhU{0\SSrE<. U?H@?uVF* _ `4JA-r̲uKŕrS =' x7mm9闡}ֱuR s @yt$*A#A{G?f .YrXá(KgA@Wf3>/=T&1kZ[Y>B^Ķ5`-ra\65140UL(>p'i7MyF Iz Vd`Ur5P\A.Sl \1A`,_~5DM/ƄPh1qqh&"k-"rTrKԁ)JGf3N]A˖^\k` 6]̌k?s2۹瞋0`e4W3=@UJBU .[qY6ϭQ\7=|QǦ:Ϡrni73GB Vcc?X$N~o}PubO98' Li$./8N ZuNB@mmkHp[ 56YH^5h+CAz tU`99'64N `߳%x %?Obťh7&KptxV2Bq@TxYYr,U ĵRZ++oZ5 EVY@ÁO<;kТB3ysV%ar@Y ݪ.c(d|;|B4Lsה\E\/(QpPe؁t2xGS|oajI-YAF[:B)J:ge$Z%.lɣKϤZ֧uM Z@XpY4bljAWC&708-ʠmlĂHzHMM'(0N>>;1hG?c<O>~^,<=ShZ kU 3/U ZU^z9R{-Un<gw۞[N&;e'8fpQ U)W˂P)zMf/VP$cHNٔ-uG>dbӘ>LnD^@A&! S53K+>9f4P?o e^G0ܗV,+t%O\Ko-t@K~Iٶ&Hsa žo뇬vucUnתZq8 EAqi`2YbTs M.mcNBM2M|e঑>›^G><6g ~`%%'6Nj5^Z@{BQKh%فv8`}zeJXvA D-2*(p T6Hu>gFLRt 7Vxv Y҄ACTiB];i$!V*G-4<4hƳ>/>UR*,E5>^6j-jkm[VS0E: YqΨZST{N꫷[uh imGNsn5K2I+y Icf~Ehx\f7q烄 s0E}$VG)q [SjTZ2#^߷r/X3aI&`7%C/ŬN2[^^+ +`}?p0B.޵A~yUd@o|A)_ q+PFGt4wgx,Vw}z h9IY@ Ka10W M `/cm[h2J EE.Zm!!w"L& Hwnr*8q'^ +Bo,Tɴ1qԾ-A}dn *@}!3e+~l.K<]PzGH!k/lrLpKL)$ 8B' Ďó $e}HfbU@h$xgz JBӔ ޱ mMqb[ ޖ_ZyyɌgj& &zZ TkIKX{$-uZX HXvk:#y<5 0%zV^ G}835IpZNQGQ-UF^nBsz׆{+,k߽XdT`d>mĻoȺ>}1l4iWs{gHTc$t:='4zOu'L&~RZIb`ӿ D% 2ʉv߄rkAYi_FUJ%XVg3rP))N  4)AaΝ G~?ۦ폳2ito.ha` gu^j P{kiD.3|\u#55F'cG W'[thPYA$և)i[{lf)nzW[f۞:LZZ lZɒTQ뇬245`4YgTr*TEZ:FxU '`u[| ?C]O[kHU)&eӪAV뻶T~AUr+f, I`l_t߂xcŗuL5_x@[ e`:#]4칐׌؊BRjTrUJV,G@]fvTyI2L3 1>G^&a4Vj{4MFf,L&xߚ1W4 Q @qz' p͙2u7KWn߭MZؖضJ޿t!YRSm}կoYߏP[VlMmwY:A{A{pf&RUhcqHy0wȩ:3JgICX:b'rQicd=st3) l[ Q'\"XJV0j\_Ks+ b*?c`PU%3i0~@wz[>\L*&JVHkO5 OqG(:p0|HJUP. 1̄e.M jS`J{CBQS;ޏu[7 sk9z+ [yYM ZTIph6ho;i*_S[ mX`-xڐ?'i (2T )LM%dqBWi}QƞPzq=ĉ4z$EBkpcPF 8va>Hdiۜ:\jC먆#/H`@u.;`h)X1YrbU%9o,77\ͮǝoZi6k)Vo&.D'.:UYXWz'"}P,w-w?wE zvpм_|:",ٶd}XrkP8,["Xe o< F\+4r;3 _y=3fA+G]p5["zrx1 8k*7Y%deW}ƌc5R lbLӤʕsvT@wmw7l^Xn4ha$-@w7U`Y#i;@)Tm@mbqͬ I2AAdȂ4 =ED#5-͝oWy= `c&,2!Q?`A_?.k Q ,K.96ŊՊԟJN5 )88{,5k~,UJiC 4qTŢu/Z^u+"\`lUR,1J.-•[ 4Ğ7Sl ͅUhCv ${u}ڰ$~ h@(5 \EȤ[0/ TQl,=\\`+mо6p`+R%KF:h*U1Q,Updie̠0cFD["Y*CU`rJS`@IP[\JV4 8Xu]ˈ)#P,I =7S-MNu|P:$Wuh騂ʹWvSj*W(* {PF +6@+ևojUHW)N,{b^hz)Nĸ̏K7ht6vZP>W]ζ=`EMC:,C鲞jz+/b\JU1WF8..P  $}K7. A \H,Ƴޛ{L85"mW鷁50oQRilnB Y]M!¦ X;T]*]jđ q (CiUx;ߖMQ͚W7Xꀕ)Ryb`e29U,fH3QfUXIci1*X} (]MjKC;uk©|{T@ )U|]H`e L_{ @5F $/\QUkCklka[g۞:F FQ[IjmrbRYfڭ]D5d]JT,"o5ڊ M|oGx ,.'Cs8ʞ9桲`np87+>B[ѥ+9{o%t^KzZX@%|rDJF4bW(a!޿(8L~uG )pMTڸ#r:S^P<qf.h`YW9LgHOTTԿ;vj!rR mjOޡ' +cŔDʝ![O7ƈqH..| @Ř]x_*Y&QPG"p':]!stqkDKPUI{cb "&;6(qSOQmAQ!+ @KzWܞAI{ВaXIRkWodAdђ|le/ EYx{0y \\W]~^ ]Q]͠+*Ω{P VbQ/XU@/vP~HS{ױ]|uvvN]J2%LN WZ}7HS!0w!$.J~"Kd='pM_8]pڟOd\q<e?55`me  R[TYְ7Z벺EXp%@Ұi&$1⾯56,q#:v 5Pܩ9Er50L'9C zodIQ "ږUp.dKɢu7~/&WP, rQ"8WCp䞻t*_g8rTi%uԽ `  $ R(ŲHc9c&c;Rqgy{Yd*GhL@=w:g u~ݫ֭WnչUu~!ˏ,`҈ ft#8ENoX@ (}aVz/>][ϟ-Ȝ(2[szۭDO w#̕?l(=TR섟糞Ϊ-`YVjxAlo/?3=6+9\;- ʷcHI0WfĨ¤X#=.]4[l"ΰuJwU.#FV-,PsJ,i9*6`-[UT ʞS?^Hh< }} vثfrTʿ gFIݲX,I^I @K26_?;ſף(^ S-e+o•.#ʎb^GIW.K `Qb A\?CUyPU8s Zy]`nvvl)kߩ\nPCu)!y*K8w(_Fel|pu5+Nn@*\ z??7䍻Ic6V̠%`UW(-4J9*d5P(U$``I!X TQ?AiI8~ĶՃض \t NF8~6|u~f:LJm^V\AT'Kq5_`̓UF{ ` ^ 39GnsoEWN73#<{3.\ˬ'bR,\nUUn:pDW{Ш*{ *iFZw_9oNOI-0wR^z%Y Y/ݮpkƿb ݥs#I\HކM<|x paYn/4LjQ+9s575hkF5ѷX'}V+2nA"Jn2l4JmvBZFM GЌ&}xJ8Ǒ:錭Y9S4Ϙ+,d:<@0.6ТAn'߁u`9]N&nrœq^hHIE'?wXyGrd ι.[J.yqp :Z[6gKXm+Kzg'v+ ,-ð` X|۷`yǫW<&FGϻ`j瑗jUWo8{4pN,Z!S ^hR"HÚB&`v"k慗,hX2 `m!]ۅv} :^`t7],.4qU-.*<a%ϝz9B1a2'{Р5N++fU+BeqV=r"5x vM7b܃VogӖ8&>+ժ 2m o)%&W\ko +~.uaM>rHک 8+Tiق'zG͠A37 hy,ys?/Wt& 14_ͣo" ٭4ȆZiYbJ`9hۚT~6}xعg ŮF;"v^3k=&+x`U Z,t́Vh(Zn V`bp;PZҷ ֽ`@tXnnh.)W ?"DrVx k`Я\Z|{#/m-`3yrr-A]wm3b_YuϠ5zpŷx)YTwGǎ7J`LѲa W!KIw U`f8Widqoum.p^:++:`V N ^jKYh`+L 6͕ t꺎?Yځmwp쾴+[l0b~R X-P{ҨA* (@ zej⎒&-m I8; ndϯӵvP;z 21%DYu[0T5s\(wGŶ:u/MVOXgݖ8&2Xd1PIJ aku"Wq?@]NT듸|OT^YCjX"ype[-%Ty8e뿄h͙ўk_e;2; #s Dr\7Ԛ? 31ڑlnNf~C=`C|yY iW0&U8W*W\[܅,@U|($ nG(T%s-ڱPuE; 7O@#"?,r\>w5Iҋ܏W_SQֹ:] ZsdKX6OӰ$6uus]},"z9t-jz1T{;z;4 V= E<]x8c+EV*B)_FUuT*,:X+tu H?0-@4sTB3b~tӋ0^̅Sn܄V^2*W^W;n<.4_"CXH;Bl]%euʑQ6pTTǏ"F'ULy,KR=2k72O΃\8 ~/{yb"VzЖq}6WmT/rC`Q銡A7K{~ɟrTB\V>UZ<ܠ$=1fZVxPy}z_vNV>0]e7$Wel:F613$rN h1892 iHm?]|#OPVw6,JAY91+ wR`RQ]Q]EPbWZkFv]UT2\:dyd'Y_p*ξr*xE)⏁0 )Z:[*ޛEw9t܏$\[O-Z~_nv)V/#/يJ]Trydy4oQ~Tr^bbdղ6@3B_hm i)?<)x:ELԎ'm0h$&cڱN//mª2d\XNbOX<[{M.xTGh Fq~Ƣ=kh}1;A`} !FĠ@h`6J!C@l,oXe=;N&S4x}pr 5rksǺZT!nmn/[ 㰖ú՝NT2YD UEZpZeBGUZ)i UK]` ^ Y2 >p|Fm\b~VUPmlUm[\N[`} d'B[ ABV; |ɃX,RZTP@#-糗Z{ن N`:dz6 P`•IV]pB$̅<uW^;t⳩X(_;پ5UPEpS,b+& s>fRT\."V= (¹,TA+,*d"nogіF x9;9 e>1i#JO|[pbYy FzK_?895.A.f Yxܵݨ\v_PeWQ3N )GYN,f-pc( t,<3,Ma:S8X/HBbY2t8]YMtfIGǙKtZ(E V8mF "GfS8s Q-{ `' +|p̗G;B 5z[Ap=5 q']x92A903Y༤Y1vX'[3Iٱs] rꍷdz i2^ޔ7 vvXu܆fi[Hۣ4WgU<i4Qqep GkϋMMkRTj=ZɪY+xX2B1 3Dd0&%+M)b hֿҖ] 8UU·`hjS`6W93/fbi4x<~uj h ȵ*u'EaÇ ?)xdp˪f0TW?Xe,{FB!A{=zHrR)`9vanJu[k}mX68ɚlNP>:eMKu"|n]ltiAs8)P쥺sJ\5 0h=hDՙ~o)OjEiPq$8bU(Q^^UbZizh~;mƨ1Z~g"UU1%KNE 1EX*z_~;Y X63h¹*P)DXa%Ɏ@QWkK57pϔFPj CPۂbm:Xk3}M%%tѱx!.;8'QHMuE@`$#%$,|OpXma-G_['`+XV7B{o9?iYfWu 8߹dJɠJN)Vc)om6fbb^HX_*ϰ2ps i6rɖ_,S?9B6:+rTG֟~>e奃u#="`zfmf.RV͋#4UClI0wp`-9_M e @V -Y R%[/N}M9`Gv"#;*]e"#:JDYZDi0L/DcG ˰U1k$Sn>zG6۵msCk Zd,h:}âWfU^Vgƃo{;ng5 Ꭻ1WVoT`.1BL}qܷ%OߘeD5SZ%В}R`X?+)QG9G_8+|緤ã˨ZA[eHh..hAH642.F+*+i/M!+k`{+;hz􁿎f:mG#M.‡gno}o&/|Nܙ{ |9Ma\"UCM=r@s ,*0 Vy!=uT >,Nw-!՘N6۹ɸhhI{[N[94%Y`# \]ۜ밷seKXm1i_ܢWCV 9)w6ۥ:C \L< #㲌w?v6×oqjVjzUZ1m]%'?rц[G<WalXK2*@@Py:kSul9T)2 Z)/#H=[ V!`0NAm6;N1n6<|+_?"pHZY(8ϮHy X+=~'C9&VH!DvYנΤ0$׻ŎY]DGЯcVAÖ &۶058~lvwc{~*VJU^V>^sb9C)=c0Lh *aBHghNډ6o=x>qܼ%Z& $q%H=: ֱ+|_2lg%9hT UkYVCL.e-rQie] h] "wy^uY!p| ~j(+)+SчvYEk+ETUW4!CŁ'%D}bh eb bEX| ` O[YZ]S>Vo]B+u. |/?[v iuSwBUR9̏ W6Ŀ1%&Wm݅ȌGn4+V/QC08vr|uoyb3^fVآD D?J\E*.BQ Rɱ{#hI5gCb?fU"}ǓSѫXLͲkZXZYZ+&50 y5bAwrVAW%vnKXktmX5pA_Ud"++"^dmpՅ,sO`:+@t{<a:C;Uf5?a#-/K]Amepk&"*MM;ݷ}G'}5U `*S]U1X᪌u9Ҵl;EV(fF\nvDTaf5/*whCt$A.{4>𼚥i%P'(zZ%*ɥPfL5 *+vOΓةז4zmd 'Oh(#f)l^7h޾|_[&D5+)\u NOn㜃뀕͗uVEkТSX?Wl-h]8*N:&D a(I^%P9{$>ktTj7 `9l}y!|V9*1!*. p9]̟x2-Da lk2k4Zm6uu *`;u]Y, "m X:Zs2Kɘq:Cj]4ErlFC8ofr%~_od{N;[peTjC i8A{i|if(HiQ9Kz%*%9W'W VCf(+ )ΔBqCjyTmcw+28s le#reĥ]etVhE󍗗{?A6/[qeŠ?q8[*h{⑅,jzoNb|Kny[:bd8Rɮ a:E۶:X46i_o6l6C;W\x >h=ţhYGPUﱈ*y﫩i ZbYT=+wӾ6 Ձ*]ݳ4/T2Rm#,A`XAi;w!HG98(?ߨ,}O+;/ j TQ95p(\Y܃\ Nf7HŖX2F}=6?+5.tNzQC"̟XO-+XvnuoC0pJ;A05{@F\: XhiC |3}OV4; B?+-SX@K,φp\ O;YAK㗒eq%^dI 0aH]:ڑBHA`}w=unS,h!X*iRo(CIE @,[$َh1,krߛ}+Jcz;%,62yl'#k ! hӶL$io}Z:DVȊXk{K8zi4_Y3wZ`7(j𓹳YAL?{*Um$B*!& F'_9};~XGXTefMUҿ˄?l`!"o0~vW< l@C@nr+fjP~P(ϧG"uCr[:9̂Kpe9'Mv+(wvT:hHqXrl,M޺M5Ql>UCS|?_ U] FhltާmZn[cxKu9p8x(S+/K`ێ+ @M΋8Vx_];lcqV6-=4v%^2l _/*V XlVWmA@U+@`7j5"S}7SM@#X3vO& *M Yݴ"#U֣s\f1y\qp{*qMr&}K&͓7\d]|P(ܘIl.ksp( :?VX#Zđ)`yK""V܁9+ںDX}rX;4kғc/vbueX]풠p~DpaqkP'Q)ܤáY?kwG-ٷye]Dq֦,Om5 Wii@P,c}cYv2*VZ(A@*A^2&޷>}noq@xm_cx&2W-vNZ(U;ac#TQNtν-`M&A|_I Ccsj+U-oi+'P8*TRb» њbZ"^) v\vh48b|Yq?klrQ#V0II\A`fMČѱQ6`)XqӀ4pXuZ8ͤ6 ƊAZ%"XX)>$9h{NZZ2L] #T# >S: D$Q XF :q7G_[^WKOhͨ.eXz^RNO;[~t݅x}Tkm+0}VoŅ;vs{c^n6_l\W'/lSI!!bvy E4j]JI=:nDj`4{.&G㇞Ob}{aZ]т=x7U\>G} \ԫJW-g~/mɾ]aR+WBi\l9UR7%3/q2`d `7%Ҁh! R=KpkQi`DX=|Su^v'(a7 RҲl$znKXՐ5|j9iSbr7͔E;W) IU*v pD2@1F+btN~ xc/С8)xn4kև4$цgj]wd,jQ9"vRx0T\5f?}Zf,B@rλ] pV; !3`! ۩&L*a1d\n E#ޜK+G2PB^wN`U[=}/ %\0W4-`MRVd0S Y܀fu}/Gcq YrXb+YpUX', 쉽;Hit@ v\yG_4Ł/#AGp M nD&Ch^sV$@+_ltzTUrb&%]a6,QXh;]+nB "7W/4tkCP[(7u6/y_-v\]U0"0;4 p=_emK'5NVo%J 9H8eMbJy`(j%kH##a߶uݗ׷d>4 8,BR. L$B6-ײIXO_gLcm[1:x\յ 6&(XC@LNe5|3nڀpܫ+WVekWBi7mK`Y6C@TD:z7"{K*6Sv"rb@:ՙN$0] snO6:FeҨD1Scw/YPlm x8\Tut%(k!X\عZMgmbWV$%%=bqiC@fƬ.?4ZV./Ӊc=#?:9w"dwr "<0kdG;PV*W]"F{wqz@eiKGSG8vVX T?2kttW䎠t>T'CBZ'qe|y!F`2MJOD2 )0 :j,LiӰ<\_@8mn"4_K[WIGK6Z0. 'nKk9(Dud2uir5O ~ݢT.mup`f3mYepy$}S@u@Dr @|cftn N*sRնLzmeՊuTu X>L.sW-/ضr4ovP py3㾻0d#F KF,7z J.Rac먴Mh )0(X̀ .0"L2dTEիQ 4MSwvܹ5|X,m-J3d"m2E~b8*]mdqy"`|g[-TU @7hL 6 58QqnA+S !Tӫl^CvHU!M9j /w[:/V٩wO| D0WZV0)]ۆI٢Z'#o ] <0GIQ@!1y`t;]pB?9_F߃d/[kl.?TQ 6pFf_G/[z<ǧiH+P݁弼 GbKVOK?V*b8|,ƶPUʱ ʼn *3uXR%`E\-٧(6aoMn5Sh > R״:)+cH( R哝IM[I e"bcDP^1:EuW )'* }A# (K2l)k2 XmF#z;C jUZr[ou%xꉷjˤOƂ=OeG^˯DV^2h30Q9It^;Srҡ" x#?3Z W',(?"srT|Ѕ c_龳rlsV6CP61ʕfdq'0X7)B%.*A'oT,,|)Ģ2{xb!c͖|i5I.Ưg+= &_(xEr"K^n޶Vo|ֿJKrݷn}'ۉ;GI*r[Z+b7Ҽ]Rxr1X];X|0hTjyΊh\,K\<`ԏw>%)tV:`0\1j٬g_x͟cs6gp= "j 0f IDATvlZǒ?ƫW4 q,bdÎ5~: VE4rrz8t.~QYqO3 -!Pj8֮&`N#WVז]ЦdqN+„/z{Rd} oN ]}xd!lnT ͙zsV\P*ICյc ptcuD cA8#wOY2vQqȊs%+rg`UXZ+bJ؂}֠Lb!FfqJ]ugDz8l=ˉD{9|Z}OW{Om-+g"\_I*ـ˹AJUH%Gu~~l_ܓdʚ;v0-.U-.y,)ZQ,D.({+Ɩ@ΆM uGw=ƾ?8& Qe FV,ϭ:ɞ=uH>}}X0VV^(Đ_E!3\v%dzs^"y'y1\uG_ں(EV. @GŠ#Ad59BVâb6PUC'ʮvC:oC4NRA`((4 f8"$=Q*Xdgۺ*VpF^@2BN%\WF-;@씏1;}$%\;5 *vlSנQQЂF[!E,+g-; 匮}aXXi-wrl) ٴN>ϻ4 OUq44js SR;d y?Ķq|L 8CDK>#`!)S䚑.kBH}&USR^D\bM&x`k}|mUl `Ŏ0}Q~k*G,MU V\i^G/'u Dլse9ʔ* SV"$ 0f*$ywcX?v_NN N`s*-\s!hGAaJ<,+m*U\@ln5[>&zi 0keo[c^S@0a#@xͶ~s'ъB\Ĭ(]i)snK X۹2}C2v/DΌ#J ]*`i17*n|CU @Bx|Hv!oo$aiF+ 3yY7w"b#s8́f_ͼ^KC h ~G0▟<0%|o2>{]kJJpEx<\T(Y^.|7a ؂)X0)91۳ {#1rk! pD֦2d)U)rU|VtL$jGʖ D Vog,}Ki݇9'9> rZauw]W]>E!$/-YaثRyu' XyRJ^Ť3+4GIB)cDtN.@-z_nLc4.t` ~0@ C4v^} CɌ1_yI%0""\$LVHkeSLJTmBH[ e0Q0?x-SUwar/(^A%\r^JY}`+Ӗz휚.2HG1@w-5#.`Xu/j9<*+(?ä`V,5e 4)X'N.Lu[kknC['ׁ+MꂕFpU7f#"7 A'lj 4Ndp.At Z'xB.:P+7 , g: sR4JA뙯`~6$4aӾWFiU^$5 V߹+UvqgK Xqp1hٰ@Sdz3,d' $lDx1LQGTٖ,7@!HG@?ۡƃX,ݠ !⍿"S/hӳEDsǨ̌m{QûMp2 QNҜYK;{! |SvJߺv{cdw\*qP`0!)KЂ-|zcDkiyּlDdFKc/\S|_yUmXxA P,FlȈAQ"[chKKqXK[)HP.Wuغ4"C7ˍ|AEGl Vt\12T\2xMp )~GkH e. A%]V 0`N)|E rDU.`%o]$1"a""bCDEp""LbBm@Wngv 3MbԠ%Ehkpi4-mɹrk/ݟo5= _ yS6 -͟hKK}VojȚ( )}k<7H[b#KYC] S}:OoLYQ״-g.NWr佀E3 ЌXɏN7as)11X\ehM`j { S ka (p X{FiT=qA\LgN!-;O#1VˈV+V`jg-BzmuYWD"h[=EDhV34ɭ18peaERQ,%^0^MOJ6HR@ z;v"ڌjUGqvj*ĎȲzgn 3)<%3= i4BБ;M$E(EC 7hnpW_: T+-*"`2Sl&9: Yi(L{\ P)ܺDyѵ@=f D6rY@l[Y8 6&Y8 hgQXUIXo!GdTF=mk3\9*@KԬ.,'B%Zb~|L2rx.mZoVo|JW\ T8)duPz[RƐEwo*p*́ XE4Xx9A}?MD$Ap+ 7@[,Z TW3t"Ȫbx2i,JdfȚdJfDq^g{'C޵z/dہϞ_"JU bvq& VL`eȈ iQ*BɊ @hc6"X^Vx:G|%|,K*hy\aYliG7I|{i^sq|d-HՁ,-l38-2ń 7`v &aRrXf{+Z V:A*^}9_ZmX_9Qj2IJOTNTw}ۤ2oco(rd*A:BJ-< 'q(z*F5)QQЬ ly:gFQ#\9vE%xm>X QN+[fVT<&, xf]#҂pNG@l,tO2G8/1m0އ?!oƍ_Z_j`V(aԋӄ<@@2 j#;DIY&b$8'9'(0!2!T|)Aށ9{9C]}Z5zV1V G^:*[z'z[Z :1Xg+kΫTf\Jx,n ۾yPمHM:ލ TbQ:A֙d֋S7Mt0gQVJԫFJFj$ވfyKt3]r hCD %!TͰ ;¶p뿋= _Ã%.FUP7#]Q)`oe+NI]Bv ť8N9S:o!F`xb1*T,D>)M dIL&a&c\{wקv1^@V~%,@F{[oˬf")l^z);ԥgnR2`e{dsRZTUɊT M@t`nTR57bl.δ{3-nZ|mc'k޳f%h \@h@4̀:HNW4 0376gfM7XW'&"_~eGNEW6,T:Y8eDтr*pX/G@$1#fO mض: ygnO.()Db\+qbNTYnf>l>m+0|j9g;b>6JQVA{ИvH?qeԱͬ(5 xraIN3`*V1i-uϹ  H PHM GIVI-GNU$Yr9KUIJ,ylE*GYI") ;{Xk7w{}Nwݻη)Yq?sm@j"\Jx36bą`_Koj$\# $ $̃oP~NM&Uq.!%W =DS dr Vh$J$uZ@yn)y]_`&X)JUeE"G̖qYgm#"o2ҕyODeMG_‹r6RQauS`ņ^BK8 E!c%W8Q@D`'-71ad^ X+[S Po`\)Y.GR|i#F5Z# GUDrk jҵ6A35bL,fRRLK&w"JIYlbŐa"^M}>@#Bwm|ͯ18\H/V *B )D20~V~[VͬZKE#[ „w/~woosrQmcfa\7J "pNzVXn;G?q$Ѕ/`+#dG!=KFkkXZkFoZٸL(eJS(2UAB9 ,@ҁ]1d_;}/%;r02 VIIԑ%JomC_ǯjTɔXV'#dݟ,G,,1C@&T􀩙#Ka/d~\c$ZI;Se?\F874IV,e@!13LJPzA"U$e!¡!^:{` mTHaDXCkaB(ZL։5x?E_u:|GAnr -=%J p-VOH uSI߰p3z|&1 %i^T-$jATȂ.Bsaj_NyjU*ZL P݈}M޻1kqtvz8[H Cu1#!l*l R4*>,tD:}hHbU Voq[H*–y ښ?SY>{~%F-)+rOχ/V]B N*U.+H:B$(Lx7OW8h~|Y3 C?m^+.Hvxܘ ^*td.-$#`Y-$B`zYht_2yd*0, ]*Zby"2+0)HW,Sfz'[`LҞ TbE7d~0dFv:l)BG/:a{/~Asrm[/dig/sw*WCA"D$Y=<`r4Hhzup|3Bjm4]XqOD`ljX6߼Wd5)~4؛b1*HTą~՛&#)i&uQTEZ!&JB9Ql%E:RO3^GF]ኧf,~#ۆ5ք]UU q;O<+H$ |{>s}Rs[jj5?9$+xHhQL6scz80L9Th * "&Q~"%vX)z'x#WyDYbbGm{saMƂr?^?ΠPuD!@)<) 1)ds\9?|̇u d|55l&kh-(V>WΫ6I,=~:0S\&Wl CRA=Th *^R@YM)Gb1ERKwr2ѓp|HJ{km.mr+;F{ Y}jߋ,Re𩵿;?^`zu#Y=$Րψ(2_NMDYj:b"r`1T0zG FYhBlmLg0gP7isX<!8|S@8t h6Fbf zM`|֗\Pz"qA\Is~xFiO?;,V$I:.G*C  P7>ϱt=r&Y`Pmqoz߿ =*=X#\{c%%ss-Oڇ?{?a#\-"1k=xxf8 *IɘrZOSyAL ġA`4  RG6/ _?K x}'N[<[.3bbym ReeyRrE{c+FT+#Zd@uŏKlaY7$^tx( uKa %/b] q9g!e ̲1GD'H}uK}oWyT1G\ TŚL KxJ2V*R SWGPx]e8EQ1,mØ# #'T)WHU ;d*y]v ]ѯC+CjWzy+C7,AbmwLQsޭ(Dh*@G1vBLX44X3 "j=76pzky8'^/a@/ïZ R2"W+h8L7YvW`"؄^uѲfӒV z@$-wz˃e&k%XR,˷E^…}sb ʛU.݊yR9=c%Ydž8a竟+܍ZHLƑpPWru oByG Iyrh,;J,R%gC9 LE-H@6y댄XeH >p ۷߉~8HYl"]3,$^ rQ(Y:F18MM rLF? 1 ж:kZ6[M[ԽYl:P>ύU!R*IUܪHF+,.w?(h H/;y'*c Q+Vw:7W4'JxKOt5uiUI #88W%+{ɔ+bfTw/G0:6FmK39tZ!RjzN w6?dVa)J5(GU2#$vT pi8,6q\fw,sGF`)\bs.h$/5ay67t8[ ͼ|Pv%MHJ EERG)Īb ǚeH0db8igG$ayheu]?@x5OBWSOG^>4f{bE Ȃi4!yJ׸L2i\]J=Ѧq=`$Xh*p0AFrSa''?m$9+g8{ x)֜G#/6mJ5+R9+^ewIJp\Šoi#2E"t-+F7_UtKkԑf)a`Vz0"'g$r$[Ѱ>2P9CGk0{UuZT}+Iq-ϟ[؄;k0 VE2%ʇ*%.,@I `ѐ`\q&Y15HVʖ:hߠQyƉ_\ñ :ƒ|{1/Yq/%nFFRNLV nZ`f4_/ mZznamf #H c#@H*VD,,~\luRHFbG+!B.+ fAU)h8%fLh9S᭬ N1Njߤc5 zEwTф={T ב$+kZ!NOD"5sIV=d]fA=./pOm/[G‚ﳭS9T}mZirXzSAzq"Qjl|`$XkzYFO,,ƓOA$R $%f/=ZAժH \1wP9H'5I[HpQ2"B~z"@E1H"Q=r5T $&)-A8D*YOHPԪ 9 B1*:B Dq?L'Wϓ$+erd@] 8ؠ'f5GRzWvė^UMoԱNO EPyEu`&T\kZGdHF(G H%>eFJ̢M%Q`Q)g!Ÿ"bƘ`ӱ 8yb*)T+ƈTϔ-*!Z|ϖyA&S8,)Q`j5hj Ir"$Ep"ld>\אV"v!Z0Yrl_+F'%AnfYmz(&P 1f~azuM0cxL*zk.!X]t$ڬ nΈ=͑ sd=Y$@StIf /ZZ 0 9UԠ.m.84G&hAw(< IT'NBfM+-:xbCËS=,LKF~0r[6K! v\yPO@9eX枮]k83ϷGr5b;,D;_e DVShMLUȘ4 rET*P|=|"XcNEfE@ $lہMIArxr vFL"VbXuKP9ze(Vý6"PpWv &*N01?٩Op>ruK\ k*ر`APC}XZ2YԫrѠ֍ )}_l F37=jה$4' Yiu1R\ bkIC>;'uD\] TRyr$ZbAD%4՛óbxRB-MJ\(W;R D4`$RD\4KMk!.wb&Zr}dwF^(Lel~HI6҈v$W#.+Ζ\Dx鳟y[ 1=Vڅ .Z)SPEe6 r|[5wS'._L0NPM0NQOo^>_ \ ޢf)^[H1MA[Mڀt,08h>* bٖGqZ@ HM5'هD+p5@5Jhr M5, w_~ c}`GN*Erю#fwߟ8[&/m}o;IUԾl1"] -=[iWr5\會s>*oΔ,98P{djm ~6_[NwvnJZM8-J.N "%yY'k:ԞA ? ,bnрѺ"`f < n$ՀTɖYbb, ]k;&o1DX j^tld$W#`+,}MT{ϼd7Tf9ޣ?Qzi~eKꕨ=0# 4 i Q疒kQJb1y-۷ǔ9 U!] t걾_P[[#qpޡ=eg9yh¤fPsԮ 3^5PQxΑ+}$U$\+R&`2MU2uΈWc.U+SaBѲ9sJ^Eūc\4#x@רzi5 bX)gX2S %Y55]F^9FBW/fCxL˰pmH5W J6cюQF\5䑅3PC=TD𹷼 ? %`v}Pzl*#S?ٱw*+oŊ{H] RWz:I$02ݓ6e;OI L"GgatbyNb H@Hz6[yx~"ErTLl0jM,*y X HP"# ^af?77]n͈Q*8wZAڱՈ=jU.x>q<$ʐDVW1H v036TMuT5PWzԦbW"r`R/e`n'Aՙ2ێM!} 9'}>ZdBeUX4LnoDTb;s#i|"y8ïK+\M3C Vf۫'F6[̷Gy`veubRh) +>z{EL6 ՟4 ;W{xAj-UVFM2r%U +^(|_؏_@-," )$`2e_@9nӫ⑻KD `s=jԿ~m}84Ȃ {atM넍" $&@<9,8Aǖ&,u1gֵg`ˣ'Sv7G\FbM:Q4S߻Ɇ<+) 6ge%uSUre*ꉅxuI)j5S\ UW@UZĩK66 ڶE66)XQš+טl1CFUC4&}BxOmԵ!#W[6_C## (dE0D!pK# D֩:Y:FXeYI#)*n iU,) ;He>,rD.kuч \&Wq#.Y\EI-ito~'p'Ѕn[K:*6bb'¥ 5ccUyf֨.>f5dFG\-#0kc:o=$}EWtհ^JH9@c1$ 5D,~YKUR|V! tl*r逦`cJ>жڶUeH+Aw܀f̲̓$J3߃pnޫz?co= z+Rrqf2bΤj͉m5l\;=cwXNIɄ0dmS"[( `(k)HVL!~wZahF/MCC_'Z]AVpf@yuJڮE`VrX!XihqVչdelzP$Ep*X'4c1D8^aUÑcS"jĞ^^Vl+V7'ܤطL%oWt%h6,wn" vh s# : sqif2>i~}Q7tg6B@;knSPjԑO>*!e$ɗKeNH^c5al;v_c '=r"̩ŮeĈELp.keٓ>-x F\$T=b$0CBb|0_. ɎO\P 1{+B0f(TػNMixEc0Ӓ@)Vl3BPE++6n^PhGEEk)m?1*"p ͢\0#w$Y(k @> ƒ=oj %Un JT5P؄l4|^ZH"L=f!?oW֚[ 3ǰȕ2h~h0NJ+t:dAc$rbveliF` .! 3xOhOjĵ呅Pˆ `3\n3 *!hC q,υUj 2{AfW( "mW'<>s[ne@j4Tޓejg zkP $3 'gQUIJ 13@Xh#V b%_}RH$eVװYnb:<ݿc/þbQ,!i$[m:OW]byDtct@Cf(A 60M;ͱ"\w/m1f2bFQYj"$G8fU2N4>d}~Ef}Hv@2ȅ r_ɀX-{䪧`!+T.D0 U"ff4yӤvo_X^ V^d0e#n#PI"g Rj *ӿ Dpppo|򱿾2 P$m*i$9*0UDu-RB=U4M"KBw^.kʡmxL=b #ZX.y58d:Ɖ\.sahYRY YT<"gK:ǿ "BOqc qca` km&ܴdr՚._kgo`]bܰHU+ NmXXD8cgrٝ-^/*V2C/!].083H`@x_=ԑ:zSaoW1RB!71Z)OIS֐@Q%92*+#Zdm JX4) \buX ,ZuE>dP>!^o_/9>s9. ՟//%?ցr !hhAD 8&hņH$W.-!.D[-hl`~f80NՈ}# )*[q dň*] ֹpsX\@`%݌*Z|=bW.̨o"9ڦ↛qOSO# ð`$X[FK<pB="PpȮ8l>UnŴAv/ڬLgFc0hYP]Ga6 NFێjA&Y{Vd>/w>wo6&UtFSm";[Mf/VܻbHD*q9. YͣR IJH֧šLLn'9_/,4*YAo竊ī `/bXtEMHCQrES4g;z͈aasϕ] 59{æ^>HGb$X+G<ȱ5P7Gr5b_"oX,F aj 蛶"XZyABVA=Z; f,s8Ŋ*6jG!FBpUB$P_fڠb?&Jd*%9+CsdrE{xp 1 v>NqPC$X"hbTdBNHBGjlo6Ǥ#΂T xz,y9p4Fr5b_cv})YwUep2 #d;JDvmۢm;m.nZMmІ,` %e"iCIN H@h[PہDSD*9dY!Lm䞝~'EJԟwZ98qq5 zJ&C-3]@*stOt3,.2XƈsaTV \ D\#ta>RV3 Y "K,@G]`gxrRRXdUU6kIDi@DH2?oQ!33ټiQ+km1;o971@Yr f/p"`kY(5D@%`YA!쎂uDhlqnkVUu鿒]UǷ# 1}CQ[)B*YWQ)I;KlFL!KbѺGC]ErŢQ/"H(s^U+#hE2Db0|?-%˯R_"yb83!ܚŇ_zc_Eb~5pؕq"kHIhNRrzF!Fj` ۨ>/{a_zqI0bĵ€F$ܦ2Lwc(RaC$T&Ua ^Ѥ!d{#/[ m m~F'n͡ն頚3o5K$XnT3qA}_|oYށw| Ю<1;(ZcP6gEILzC1,،6g| @ ۯw< V%G 3w~i g)w'qLzK= T~H>Q9RLe1a4zWޮɌl 1K/52fFgT0imk 7zK#1RO-;DQK YQġK%u,D:l\,Hn%M7#0#fwxguLkF*';FDpp$pp_m;Q/AU\-x3_~35ʓa!Tk]-(Aq0eEXrVb}N;t04i)@G\p>'ݢ_8 ^Gl# <|CY,oã2V*d14h^57ޔFBŤ^P;'w0\9xSt6/GT"Qt̔ON,jS>'N}yd>K4j(ȣ %JO,đ٥.c JX _}p:fL=0p\Xn=qf$W#F\ }da0@SQ=9{Vi0`^C DpSǘk? x%W%PN ;#TI%!qb"IJUL a:Lw8v>y76BK Oz4y `IhjRbE۳8 ~xOjW cDb%a Z­`Uo=[[-^zqkZ8b΅bcKi^ K ‡gE07 nDϾ\@8Ձ$$杲\Tȯ9 ;&M V)6U7 dY$1(|KC !XΆp`^׉C t!oɡ=w\x:c`퀶U9vCpWFq91%*?VI>{ Y}is˓Q= 4"d%gc=K@}J, cFb`N};J-y<i#zRbzXs"_Fc+Wбrh+ Mqf44k_.Ur0wxa$W#F\5,'^}w5ŗVN*#Uq]_ #Gm}uS40#(+U(H*>%SM(UT S ^Inx;Aεvj27l8X:6z:V*+ZJڠV<<7#WO80F%F\:Fu$#8GCkv翹˭1baydLV0ػލ Z&JQҢeoP 9 kQ"o[Gaȑ\DO`^I T 1P^v3loc XB ݶd c [g?"ސ,?#7,$vݷ[w1̘糷>CDF֭Cd+3ĉQ2\[ +U?*4+\k0p)oS ¤RTC|3v7{WaE8羆7Kʞq;sD{LtL|OXW 1]xqt`pTQ3;ߩyi՜cG.㝃ʉ-0h⡌bg@&{RNXOa<H=V׊6}}ޗ%WC[' r'qOH(/p05Zݝn2"ݱW gBzxv%撧5:^": CF2&TjSBrkr\+Wog.q=U;gIek _CE0.!BV֋($J8YD`=Їj Tl=nT ,fXmj6‹Dџ|[7UX:FhmUpm@`ݭCXS;y5%TBx3~0ZZh @XsQ . &}]גFԫbيAѸq>VD}%) /GDz ]-U숱]8D`}{={ i 4RTƣXP,e'tؒ -Nd)ZU&w!]ַe} GDV؈r P$լĵ(✬h(ЎFKb) eص8JA*U2tTK;#=krwLeRYʒ/сT{c1{=Ri+ 4Bl6Enվ㉦ߋ[ >jt5]S"/?|7ZhѸ3%ݯjIQq}:Gߴ̸I<8u#NH)6Yʷ*( ڙC jD!Llߗ֠pJLƚ V!H/e&v[K ,Mj:?@je1|Q3[w 'LK؂n؂dQ*fS8eVn RhM|Zʵ {&=r"kY?xf!Y^-~oL)vtut;#5g}4rl.E`\AB5b8U 鋡A _?|U6U `,0y1tnZU*q1<6JS?l@egxSQk>{(L>XN E6Zw;RNX'p04xTխ\|j= ޘNkH7RAaPhT,<0)i+t U;,k|X& fr_Pd:[Կ~յ"JޮL sb<֌CZ k 3WT(sbߝ0KI[(!)txk׏?lQb9DE$BE-x>+'UFiC1JWseR2Ē2{8'5|0=K1i0A"4]{ u]A8MD`-N{Ζ5a iKַU(̭8Ӳzn ӱQV,P\%2EcWƸ] T4c2XaX*S߱r]E:F)㥬2(3.Nz ,]*V6gCi gd80L8Ev:}9S D`]IB3>bJ5G&O+P@ڭ!ֈvK-V3YxќnG4QmyQQޕ6 *Vjmh*Yz]ωSaؖTNto9U ?iyݞXVB)z,E募R+uơ5ʗ+YJ}E1nGCMŴ8 gbV"D@kt4)R .OL^0U0bJ;aG/E &Ξ@*y%59k%|_*+%n ilюKU[n/(?6}ۑb25Yh|RIciCl$2sȴ+0)U\rU,W12@;mCC'\KW WJŕ 68J&OQUk(c'd0[~'Qb<`1ׯvENXD` 'N9?Z|ri RPF5ՋQ^X}0 U˯Du+.6&Z3 V,mAh&=OJ&810y 5R\~а+ض~3ZF+~g߾}"KjvOⓇblX©w{zb)M&㳼V`epl5j5b΍\5Of,aQP`}WJ"K%X2JYU (tBEJ+Gy]0.}Eh-e&ap,\D ۷ӓPΌ 0qu gR͒T*{c:m1 g̙,8NH殕?U VDj^*\JVEm‰X6C#}ϥ0 g1ðQ{Mgx&7ז iF'RuD` Fhz&)m+Xΐ/lVhZ% l^ }dQ+s3 B8ùRʦkkRךh R6J)Em\>hrR͙ܵQi6xa(V`FWQjtc<&XqHbUdi(`pb+-@©3`,|9n~}ΣgڄrY jumՄ)2( ՃAJ 4d '@++\ՊHh);Ɉb@gEF+={?,4EVCt#mk|SBRfpFLlQ^8y7X%qγ,{JcK荷UH_ʕIFs-0Ag<5IDATm6oy8UxXa5QG)&L&3ʡH󥯾;bu,a {;(_P)Q~e ni  .<"ku? $>% 3nи*mDJ0\~eWx[x 瑲~ a[P{\G/S.eیU<1v08`XcU㢴ApCJek_d}99nކ~oL9_pX$*5%_+T>'j{"6はxFkIZig<QݱzvٳƆ;g'}wgzN57xH /B D` N.|&]+1OiQyhW4sj"2wMمڵq}I:R:*J&*W6fŗ&q;Y7I$ږ ƳbMy5׻G 2>pQvN4n>quU8M. a5'V&S_v9[g#,6=GI$MrNjY}|)m &56L>,kv0 ud5m6+KR^cbx0Qe"La˕"m#:fy=M;Lx XEdlVbyo/ܶr53FA~Ak"x="+B7=J zRVV׋7Vc@9q00C?H,ǿnQ*D"k6˨y.aPf FD=0lOa{1`*p,W ||g,V˕,zRe(?4mu+gf~|4 !:9" GL|O8 +pi r͠"U|w+[RzehSZEB.9h\kGg_}/[gQ)f[7w HA%S=w{\ɒ,Xv˩;ƀơ6fSOe LGc"KS'"TWހ ϳUUUdl7]_4ʶω+T8{FX-n ze 4%&M7oE&@ MyAg꾋(BD` 3wQ\P[Sv1kE֮VJ-1_ wW֏Y;5ǏVq' q$LF;ĕkjm+)?''0knp|-_J~SėϽ[6RNX)j$)e8rȲ,#t(pP;߳ Ȱ5]%KN&UrQO]YǍ0ƙoZ%w"iћD&SԲ+ÀAL7 QeP?ϭo`Ç9}hiSݝU~F`)/LlwJeJ_+RNl 8<L(0S{9@q{۷BkvΌRSmldVXi=e[m 갊-"0>NR78cbl\]z|r+%F04b/Vh奜3~;!{=1_go0p9f%vE^ MڀcyUdz3oov>…\ȲV-0>/~#qg%K^wSl֧Rdb(B}So$SUL5$9u(4*h40(_yvaOM1y?8<·LJ{|+pw犬% p0鱷KYf}V @A9}i,MJKsHl%{1 %:LN´\sx*"*0Z1QnMk >yWO[}!lk)ƽ{/kyS,eyWm=*"bJVwH7`ljӨrmA8xXpS%QY⧼ >Ɛi-"ˋ%o~mc7iOݮ/*fI=~_c<7~vlM*R)frU+6g՛pV+%B1jmћr3+Fd7#1.svyNq iL7揿щF,_]IIk"BJ1;}6ʟuK'UH"+Lq?[/[c{c/AiuC>ڴSlJZ9k7騝h Ɓ>F \Za&ͥ-rTK Z!=Z y; ,9 ϕCX[UߓXJjݾfs)6RmA^19iBs(AC;.="A8](2VbgywQ-FYo0 ?Gofmb8|Wds)Q$2#KE)-稯"&M1`wGp U >y9a6 `Wp%©2hv:lٕK+9*P_-:tF+l?*dwȾ^1G:͝W(ۛ"A8SA&ͥX^-Pr,;V &4h^7dwȾ|v"EܗW ,;-+*!Ksc8a'[Z^-˥]+~ݫcdYA_ ;2o"AX wRUJ,3Qu7t#![KoϽ=NdY 0;d_y댮iV#Ome ‚#Kd(Zl[rR9ˍQy8`wK瘠JdE-s7^5(\AD` L&NTY-VbQxgǠ9' φh9[w^WO:WC'"Ap44|a$jy k5ITj\7y"kwȾzUO!\^-ZxW% ,A.4[kr~שzOD` aoN96Jegoh[K,YO~,g |:|NkĖ%TB-R)*U2*nޮ0HlQ>oPg*,_ ¢#KL4[;l=vFz.[|j(mIu+9YxR"YZޭbQ[킐@ §q0q0w"U_fo[ݪ8賽٥q?9B`"\Y/R癌5+vAH"K'<}g_/geh7l(L6ʇ"k^̋)r~e]1 ,"AN.{]}{ϙo(U2Ty󄓅Eykj]Z'Vuˆ,AsAY|m9ڵ"zr%K`8pg{O*LCxfrHs !KaA'l>jzV׋W Qu2nZ|Rl=(ғ]we < X  v.KVϱ~Dbnonu+Y7Uͦko.J[c{(A,A @5&zոu%nw8IJJ(w{%ς,AKD?͓Q~yzTOܱ}X|7>rEqޗ֠ <3"A.1QoF%KF~ovFy?8a<AA"[Cڭ!>jJ{ԗ_/Q$_Hs*^2h(eHkPX WXeg Xʚ3Ҭoc*je9Gӡn3;;<1n3EQ V^@.i; SGa$,#p?w(ʡ`b ni0}GNwp]w1(1CbE-&`=iY0s:H,_PRe\cXs 3G03?L{/f9~]̐$kR㏾=.T+b:PX\,`qNJtq(NwA$-w`Y(Dk#MS$qҝ=; ssp S8~Nsިq}v1OKLĪ“瞢さX.`kyQ'ϡ>Oi5X҃EQ I\6Ӂ4y|ӽpNNlE׺ߨSecUyQ^h!M&d !>,; iX a0Z~(c)B)JE(!e zs2`o6vorU7b%#+ [eȮ*%`Ax@Nr(m zdEc ͛p\ ++7-/9f1ea>5*e}yY\sGn-#(Cq)\eK@|2o7vKvJFQv*X2I$ %LM!ٵkoFAf(;UCC? W$1 W{c  (Va,.CC$k\k~hJQ;>m( 1^2EB֭[x d(6"r! }' =FYĉGx;sEQKaU E'sQ ɲ E&e 5UC?cDGǶ &5)2mt+MhcXTeoٹF *=EQPEbzyNeY'!وظ2y C;2啂啂Ŝ[K+bYC_Kћ̾l6ϡ楼o~g:dH%Zۗ\}ԇ~)!h- Z!MCwo }O(eE9X_j|uLkRF_҃MOQ*n6:L݂NNv JԁsAWؚ`MI~>gLg_zev%E8~+؝yS!+`=װ^-[\f &95L,kJQFQ,v V^4F҇7 {(AcO"X[$+EQ˱ʺQC]RZaq%\VMTE6O^_ߔ0\)2)֓,K=X\n-p/*rxٱYMqNT)S.C5SE ҦAJQݤd'Zy1($ٵ>X(ʓ({ŞiPEQE9̨`)(LS}PEQE((ʄQREQE0*X((FKQEQe¨`)(L,EQEQ ((2aTEQEQ& ((ʄQREQE0*X((FKQEQeŒس([ZS]=EQe¨`)$ DքkLD/ -sEQ bAD( OQc Ɔ밽ៈԲUW)(㢂(;@X",$:EjВx&&`" DSRE/`)1ҖҀE3@~B-@ѸԲe]z:\xz u^ȗ({`)ʄpΒEM)xU)Fcpxԣ4B8.%(ʎ(v$IH ';+Sk5*T#DTFEQe`)6$U.ˊ:%J fxYkTg$ʖ|"_WRE,E"ijDBo%_^I)^ zuJ5D2Xt(J,E$@E YK!/&^'CUGB*^ܾ`)&HRK z+9yVJpkEJr. CdKKQ,EN7!m93ae%-NG\)^6W iƢϊ(,E k z9^)k8b.oWvtM20񊽻SuKQ ($tI\FXY4ʲIftq9!뼒B1NY\hW(EKQF`aj& 'y+XY^!j 0e#+D\ڈ|U4)zTRe?(C-LZuQ_^ɲͧW5Aݫ\RzUځqDC^x|ɋ(N( fZ[AȲ|'d!\ j[lx%IJ,4WHry /EQv,E\bmUݖoeP>z"$MjYԮ/v׏X/m/EQ rtßBy3q{[m=YU;J}%^:KBCH{ yweUEY,:l4urb̀x5(GĆĒ0 ՘X,-rO,TE `)%cv q)dW,e;YƄhWP\X\\0;IB]nK-^yf5WR,cfMjoz[7rD$LxRlbHKC FCHAEt E9`) i1;ƹБ֍޶{[)/x ׇ" Q2@;X"UO/EQ.*Xmtl y7"͓Bϗ"B/I W:\r WDL3zW)Gm(,PevM+3n^)#MjFNeĒ\!jwk2g3zQ( ,ҝJ ׯe!6UV#^Q]AJJS ݉ѿP({ r(_hәJ-\bb@aԒ.nLFMjC1DЊ“UeQRcH;_cyiRS&EkiWzt?}**o+}TCl6"e.ojXx 5^UL7/A*^ rqeHV\WnV{ׯnm]XSZQ kWٵ>IlL7kk NB3N"W{zT}l#ǻ 瞫YYER.l=LN[vUR00=[<^*^ʾ@K?9t KK.,.)C⵲sF}%^fl]-^eԸ;1Xڮފ7`)N7؉)"W.-"͊r&֚JrvcjqR/KWm/e'PRGu]hClpt(7 +vMJ[Y32/+_^x)DK7$Z- ܸem(Hn'aJ:nX^A&, f?9StaqՇ(v(ŋeE]rPөӍvCb}AXR}QRw0==-dWeW+VZSEQڝFīgW`ڮ :T`)cλ瘝op2^9LV20Af0yxt)?{~\-` |; |n$hj>V^]('8rl ^{z5P5FKِwr"xϹWo'lZyjKQe[hsYxuVsڝU:QR֤;pst7nr҆ϛI2nW@NTɈVa*ǘSRE6ݩ{_s7 F&:W4E8 2㧦Б+xkoHeP;'ZcRRE,G5Ⱦ˄T).̇2InVEc5$iDkkV\G>]KQQێGzο1֛-i`DrX\sqTӄ;$tk>d ziF.EQ|vy_lȽӅGuȸ#?W//(bb9~{KA*ڠ(/E]x#GNY\xcֺ`S1ڝDx?{Ќbl6jk-9}8kmR=syy񻗷4.>*Xwrҭ߿r` KveAUKFEjҥ(9}f^|2!Y_SP:Уǘ['nٝȾ[LJ퍳C&#Z[|zES16Uem:PXrֿ(*45](Ib2rCH&3l&jx8;#Zۧq$cz\KQv'ǎaop` 䁇r4"p2/peo3g j2J@KQvz4\lƨ` gZ ,x׻5A6'Zgl<\~jTj.E,>SdyXWCxв' >Ix/#XqϪǘ~`iQvl^ī3G*]λ@o]Od$ \}̱S!+dxv43uZi桶xֈg4ڥ6{-s⎼7Fk&c,B_߿{nj>xxKTZCa9So';?#9<-6#7v):±S 𭯟߱ƨ`1ON'<<\z|Wiµؔh5p[b=Y3i@oO H_gը0 IDATt1Ck 5F]~3gAxkYY̌Q$<Z`!8x;_!؁oc}?+3J`+XV//1[lX=06Z; ZM1񘊗̶x譡]/ֆB#Xk,[W_%fEE x X xc@|=c֏kAhؙ{y$ڕ^k^6Bkty8 Grwewka$VH8uX ـ)1O6"yQ)VdP|#JP `ƀsclG/o F+{-HV&%Z0J &ZÌ/.ey8m2]y2zgZҲ*Xgfy8gsxm$i"8 5X J kRC!efmBv`a@Ԫ!XBCEϘ kX58밉cjPk Pd9/1|g6p1mo3846E+ R^Vv)q}ko?{ajx QB!\s@Ay8wE._[ cyG<kµgrE-¹BXBxLm&?y֍hl|B~*ʕ?X(݌f8h`::skSC=y9x /1M}kL20ږhՃ9:lw*]'NM๯_]{ay)?k{qXG?A~ۗxkD+238U&\lL J\#74&FL 1 ^?'vnS?`|2430b+L3(WιJsb, w<~_4.Fz^iu0"3JDk.#Kp238߽ru z_-7z|;ۏd/xBTHmLX5M N(T,cAbP'}y/;3󾖫1eXXS r\%IR˕u$v kJ xdh-_mON$1&:>5Ǩ '-ZQ.H3tl;Na {&|}: " &< _{5Y_:3D Y&Ǩ"Q)YքܡQ-c)G>LfoO}3Aʙ]˟ǡM *a`rֆKtV &IƆx1%=mU"!UJVV(M8;3qזij2J8Q:*X3< 7/r_ V,RרX]vtVE| ڝ Bbx-! Q2C/1ӆ%._,(}AJ[mֆ UKp.9I\)ºb)<9]ųAQT7HϚ\/SsɊwM`/6V_< 벼.IJ_؍7Q6wѷbË?|՝-Y_T`CT]ڥrF]>P1jUjũII,&q`PoZ &MmH-ZG~ikVL}F2K#UoUޮjg!* &$` !Uh ``;w)fzvuq߈1ʋ _LMֲa1),p`mcV!Q(p⭣)*q~5jKL*uj[gBLjVᦲ8R㶙ow{߹̅7ww(ԂhэP$ݩ~C«/]B/}|5;E  E̪ȝ63ɀ ⌳HFr=1.n_ G" x5ѤR`s'O'"?x-J9zhVY^S=3rV3;uE'SY_:'M``'D Fnl~0|fBxֈyj>ձ&׈lxGZS`ܫ7xk{KEkuo}IX^g/rZx9k_ԧ!ICmUg1!d`rC1X G/ YѫY$'Գ"Ajݠ Y!(d .ȕ8GyȳF'k}7LoDIcY};cm*Z[Oūxw05e18 ժP'}ẁo^#'4+/k:EK)EU"&HE+$ m$`xD‡(&ɪ41&4/KjĆXCӍm2Ĭs+g9֑lz!a%jEWwRyaFܹzӽH>c||~φ_Khi./R X;qMPwo^\*^?yǻd፽ޝ$ ۚ 8z|ǟ=+|{doUQfPJ?+cL"HQ`b{a]"XxDVޟ_Qkl6$g?E!ew5i6'&o 4d0۔}=V7gӵuxvg'dFӃ㣂?~<W..g/B&!5X⿱II(UQi^*VUvX$-C@L 8iXCc†HWs+z[/#87>+Eה+jEj0bE( |Q@#Bqx *zUFuJ }Y}J ":kU3j~7GH-ak9Z8N*94 ?7&|\یj:lܵeT6p\tQ%C ^COg7y}og 5>*X#N|^~֥ޭ TUǭMN.ӂB(g)ӈ ,X$ʕ1)")(0𘱄hkƒ+BMX:O,FTRIْjbsX E  26K’9Ex>򿖓-q(.+q_ΈVk 3bG&)hmbÍ7jjykn杣3\ -Tot=r9Q|9 }\lSkl4Կ@g9E\[/|~CǴ;%ZCwoyz] 6O69JR~НNq׿ڇqq\z,؉)~;HS}#b CX6 GBUEzqkJiLI8gcwx8Bo(bmX@܀A$!I3, ~Lqi\&-ZܽwIxM.;OqYV},W7m/X?t|qvsGOU,mS()"*B1 5ƍ2uX5"B#Af*Bt+|_$Ks.^K 0yQ:ǥ+Q ʓ{)Չ͑% zEZȎ VWN|NMB p6^:E2UfQGKFc?"ZϏݜh>1 WuVĂS}ȕsjrΑa&Uw R$V~$kc DkͶ: ;:s`uR-.r{W{\ (WɃquOʎbdUOB+HLAo00q*dKrUD̘LZLRZZu:۴] F* xϫ}V}h=a1!6gJ-gaƨ1+>ZT,+),9[-~N'ZrUw|RUd`\vȐ:K Xæ-L$I` {/Hv/' VsLo1y]:(3&%Zo{dѮc'x❡_=.l-{>s{s.^67 "Z?\UPCVG5B kBQ{8$tO46&ma-LڂV+EZadk = x|/Owԫ(6ZgQM_hto"Z1J~[ n'hUQ ҅)b+ŊAgdld?Mak6!+Ek-[bn`!(q@J->V{ACl*r+[5:~cx l EGG֟~=fHyL͍qX#WIifi%WdZa袀…Zxbs:$E='Ҙ| {R>XռMڛ?*^`n͍k=s;j^q[} sgHSKU*Ɖn722%Q$zO2'^($K(ʴHH>ʑӃaLL(Y,<'FCiu ~8D3{2WokHE+>-XѨ~6/u ~ƺ-Q,gB$+I!`PXpQJ6& Cㄟކ (ԡ)y(ytdI=dra֠s%M\b]~ k1;nC6ݦtHZ sZz8o'ٙK®7qko:w54Ӝs,+\%I,j,`-gsʿy}-ɐ5>j[5{,+cl)dYmb͏T;F}j4_uu2ҔȰb͖"ҁEQP勱Jb?0+ivT[bŴ_½1XgV($H ¤]lꠕb) iaR< ?=OC{Z>>2E8x؋jdy]NL\%U奌rvӌgon:YDk}h^;I׾\I'8cm qhSgfg,/efҌ4  )E>H7ۍ1cCHyJ[5Pe'M9᯼bsV:EFYf#5UR>_=ᇆK)+ß>G$W5UhOSCP$ߐ,3a ayV"Imٜ)՘bLAU9_U3П{#ߦ汖آhܼsDʰzUWZf1X$9d嚕++o>y+lznáO}~L߹oeƭX&7ܾ6cw30c;mq=eǴ}<`i!Xn<5RZ`Ӂ> dE&D1dcp1mXP6 C L&XVq KB#M$HTĺd E a)׾+,bG5XEu^est?"@KIHZWDVTnmHP,Ӏac[c=11JsLɲ^ ~mȯ?Zߏ_vR ГToh{Δ#{&q0lk;"ӎ1%Bk/;|Sƫ9jAo4xaW{0(I^ڢa<`s'yJ 7êjO>J80TA2PS Ě,۔ h/B^ŞeAJs R|}?λ~!$Aax)Tk}L׳=ǡ\Im .qkϪL HpIHD-ĤWxJ<8aT@794[Vīz\@l32):M ϡ‡ rn!q¹ &||z&!Z[|X֏}cAW՘2)+?W?ξ[ Zn8x[jΧ$MXG B!uq84UvdБ_:o)嚃!d%d ׶ \\`]HX5hU2V8X'UӃbQiq><H\Sj@GxG:2eD|'F7n!{3'dk)T5p/L,Ċ4 vLb*M#yxMad1Z.PX+??k5v[:ٗU SWks3~.t2S}(/ zIȝEv50֞gho}ttQ_ rZDg5  ,;Ć;%Zkٜ1XcW4E9`-y?wvd: Elobg}`L9Ӆ⃄>xJ2*jUʕ F q\*`x(]G+y  8,ݿ|gt\'~;Suj#4+P⦂G)Cx$}`F|IS\JE6r&HS2 BrlcZ1@(K>bւ߁‡5!l|~O|ܔd +3" t.{\.G"ξUF%T"Fl!qG߻RPGlcidm@X'~=G:5hsU>7IgǁB~7x1|*iQl)Lqk,A:*=$\B$7r?O!cVE>e*V=9Zt燮W"|)hBovk'(Vzio>ck!v9e-܈;R%krmê(>n`bA"٤@ cS{:b6H+Bºؤ-diz#,O7u{;qfdC4׍M{<n-r%Ɔ(T#yZXT,/Y3_Oާcs'?Z}0My_oir\Yl3,Yeu/1|nǸˢ;%Zs_LzRXUhѱ8bzUQR o\(c-BQE E ~& .DzWbP45wC SMQ0}- ;7㷱P|LT!rg^[ޱQKu&yo%ԋbQњG_vneE$( $Ecį\=$q@b[Ϟo1s1jѯ_ TRF{Ș ID dyB"ǸIrLTѫw|4.:rPOY5gZa/)k0?{Jo͊Vߖ!W)#v&hTyp>M(|R/dyr YvmDk̍7/=3GQix8jgY7z^ ٷEL0i8eД'D.txr Q<Ȕ <3&27)U_ogZj_?K|~(S1w*Pt c}z'2S07׍ÛT*[V vgݨZI]Y#e%Pr"8@BXtQGj2 ) ˂mx 66-8^st^2pn4I( _hNpI,k XlG:"B:+$NH\lzo >z&MR ׇ[ձ4E r}4/%aYuI,T5ʗrcH~O^XkO}ό)YSFܻq&/Z wmE)8P5\/#ӆgìC-u]H𭅀vli(b=µ2P&RƘ1&ȅSE|\ȳ_EƓ(:30|6#Cr˒^m]C,|ok2(R߇ؖ(V`d(D>^&բz(cRkWq8C`?5~:Y?QR܍gyl)Cq1Ⱥ(rD\+" Z(LQ_t!I)pV}tD;*Dy ^B d/ebQOB\pcRIe(b/s\jY2+"` j72\h _xAIWb YYf6MbtEYZr|zɛ6~b_-ϖu[ `=<$ yn蒍\t?6gNq o"Wzn7kHcȢe$%\R\.n[~M!M*DN5qBcXh ,)V>YnwpeIF&_Cx#kS+eYRU3l], ,IE*@( W: _NT 3\i,*j@qAWZE}0L QȄڒ:x`*IJljCnU禔|\ZKf٘um*\ro}FIF͆[qKu2Cd杼I),@M`3HklNR1r=C^KOݧ9.dQQ@6tx|O~$dme?zF~1pd53׎/]9k\{Y7uM6 { ,l곰,k]G9rx׍)پgs͍SLH'z0Q& ŵ[k[~w^ X[ TMna!uׂ&3 AW7NВd+,3~IFcHk %E^R%eURwٯ|}X~ w^8GfȖfǢNCǤ^51VQ eYhY hiySԮδjjR̓2ZA6 @ 7$'۹mhŶX3囪TU+?Fa,QrLߧ&&ٖfA" ͌+%1 hw*kmV͜|T^ۆG @ ^dr̀,/`c],Ql:s̏}*SL=T:k/uꝽr]Op?YOr9k\{Y7K.l䷏䷏nF¦ l>gsP[Ͳe,n9|`#<| _VLRpJI&dq*"z iKrF XkWN8zpE f@X!{,qGg3B!b(i: g=\y uenz1XA]O+(G#ʪ`4<**w}YU]~> ׉2cHesxM(H`1U0/"5~iƋ_6s~bVYvB('COԈ-fB}q?(o2r#Q RV|Rp|J]›ykDW|^LMn#6ku=\uiLԙ3fćиV;'C<pmfv@U-S(a,#3 /r' 2`ZZj+,c{ȅOv2 \^ z6x,59܊Ank3:ȡ< 0ZsͲnEyG \쬠r:кbF_d:`;,#PьCAl#yQg~?KiMWkhyB',(u[sviWQ Wg`t VU<1YF^Hfw5[#b{eW9@Mx%ÉCk격AOU_ _ WbNrvrNnZxhL*!7zJFm DպD1Őn07뮽 3MXm8}Q.{w%XVF aBBd>y~\8 bp &x'xdZFyͷ*;Հ֛>;bTäV(t=l'8Wqd'*A}Y}A߁UUA^A Jg:TY3y_=G.\WNʠu`8˶y,&µuXa;͖}d+|C0%n>g-fyqfhAW:rhc })}o@S2R*KFڙiF$ 8E+ϕ~qK`5? KOb_\wθIێNS0>fTr7g9YznkLu@e\/kycC.xu%:Zpx΃3_m@g=UkeQյ&A/⃷.NIMy.jR%ց-bK$V=h?/ksD@|틚@x/v_{elAxU'X/Ҫ3 %`M2 2ZY&Rrc<%PцU~uw}x@VXA!m 4M|U"xBQ3s>_'k{;B)rq3m vre*BLh5¶g3o{?# MƄv""Vݭ't aԝnkLSȍ3y72 dEr'z\c-ZU\*yOמ|\,WX: HTC A2-+_u!Y 鈈Ybq3lMNp܃}gYxIŽ p%f1w1HT I$}ϭY֭ ]b1O>_YhUY `2!Rrb,DWYSoB1%v djKNxG~' _b}5 PWxGwf1c;1$мlFxȲhh9-b 8c𞻞kS^g˪ʺ53r tmI̋}{Sw2׫<ʔipR_,JUhF"7 RFo?MMTϠjI$_$<(^޴1@}Z^ҺF -K!L~]\j)ׯP5( Щf9vM:?O%߇$WB,q*]~XjifZwQV4%1|NLc@O 5 |B45O&#^"Z:~keoW-zP<,wN<%<`Wɥ M$IR}U%dV"'%ޣoƈ>̓;3(r ,Rg;Y }i3Jkq~]OD궧L1|!\}Y75.RDXL$dI:]b{?yPuL75eЀ9# & q: c;G^) &#ㅲp.7-.XVN*()zH~=4ϡUTEccYcl~ \Ų<F2! 1׍:}|'9ga+XQ$%*` Y;?)k3*`E`gfM>L tB30k(&t_wO~(*YMP&+U4t|\ֵ 6ϼ$zlLcxd*qer0WhQs>Nƈ彯}7i??ElԕL4f$MkgBۛ )acgTXB4,c5W=kVu J欀n*CB*X)-'gD_[+v*حHYh$\AJ@K)2e:+71Eᶷ?I!˕Kg7sGh9Ea^X/^N!Vr?w{{p7z>x+Stz?FM\dbe&1eI:v~9!﫮cko'c\(ܸ\ς•[{P~&?f3l,x%,`+*GY燵~Pd0s.LɶB6lsžs(80{SQuSOs;U0cȪ*76KDe jA Lfy[]ȱjdJ5"MK^tFࠤU(bi-[lTzyZT]*0JUY瓣4XvO,h[סdxӠzmśkns3 $+tcyggXCq{W]d|+ 7,0shNqBȆ͸>Leh{ _ $&N0VGA+/$,O-y=,̀YvgvOpn~;?s,me8#3!_56I:1,\O!eY\8 eg]F*,û3ȷ]ٺ .|#y[z3֛Y|mçe~@腄.^M | [9r(L-7Jg.+"wVwIfT :DJn=Pi׃0OV:W9熜wFUW{t+5<I`RDs_HbWUm1#ܩ1\1hX)oz~ gU&*5(, * glLpU#%$KTd2\L~XAJU(7EBmW72ͫXJ3y2s7T/- 6}}&eܞVVk]Lo[fYf"#R>joQlUSe| 3dn''2J^HNY-hԙ1Vu\ΚϬ+*{̼Ɨ&WFLk 5X>y+d{p~ a.SoR.\ȉ+a0z3S>G<`)xo(@ @,-z|Im*M َz{c)= Fқ4J;jkUaC7Nu3U .nn=z5,A+ =m2U4M4X9_`1v9U sߜև૮En:ޙԳ5."=6C{4(ڸq@WɊ0$s7k|/Qj+.x58+ p%4FF$Ѫjg_}=uqzc3iO u)]'X̢%".Z^UneZu\l/e4Ayz AU?,U:3+ Nh/7ȺhNNǐɧȇO3{䙐Qmb8%KW2*gTq+ ȓɷqeS˩eDC{1rJŃBe7^h v=:D`J˲1m%Q4EP,K`ѝoLKw!aHkXΩ[_?NQŪ}/%F+|W WC טq:lk-US?1_\ 8KA]`ij-5 [t+

    [q[b28uv]SLUÕµ&\CkʥRgwsUٿfDosS2^"UB+p'֌3Wb×4l=uX] kU7//ZLyMF aH>L < z/XZp~'Wqw #;X7ğs3 8D8kȸ9c i$»~ >O8׎:ϲ: #4FMFā7khrijۂ`dZv3S8g-+lW{  600.)WEW6G峗CnI\t!`} *V7k{L`+=imBy֌4c4 ec;h%.+gԲ+Lca ^֪T#Hdx40=ԓl?= 8ջ!pJ/cvFz'2XfFG3-2T9g^2 1dp<ŝtSܢTqb*uUqgCƸ95ϝY9xѶ{ESm4ۿA!FArvۙXO;nqUK\twGӎ*]&p=`cȲ̧U1cZUU>Vg8z5!'e0ڴ ű"\ "”z7AqWSiP%`RA4U֘4ڂ0}J"xKTE~w/OJʗhύfJ{!Ѵ+ vBI0%4Ox[{lR$'V{3'u"VM,~l ΖUuX]PR $%0NGtf4i X" YX?m+7[+K5ֱS:ɺ*?dyWպtE.zP1ֺ/eL]ny72]r΀&=K:l_Pv$TIÍ։V4I\o[y]S +3\3g ~ O^f:ݵhExfe]Vp*XZ٤Q7 D`DݰqlؼVmg܌" 8`bN b(G7Xr7̝oG?B]IǸ'BY3>#AJ3*s{b \``JɲR?c DgHO(盓|6"oMkD:D\4/_CUR K(!0^((MF9{xKG;7D%&T A _}^6\ b>:Xu !v"ụ^j W%haHj TƤ ZEXk4}ޫ?AU Pu8Ig CH">[WPBj/oy^h'.[3֫sv][Y%~xV`3EFQ3^ J+b蔥U8625 ~Ѭb PNj,=9JlCK, uǹbK.l~ N{S|zr14hZZ Ė78d!6"oVeezycD_(v4}Pѷ?~(X厏S:)79o"xO >|J씮jj{XY"wEA^H{3_Z溟,YO˃|yJ5ä_=?^b˱DɰY1K T1[iDwB0?7ږ8N;-=N+U05`Gwjv3u_chqz{t ̞{ \ϒ]%ʢr{`>)64oM $Lti+T1 O dJʧqx#*Xɱ 0 qCdjaMߵz#: \yE++c-e+ %KiW˒*f3].T.T@ s2.6K=xYQ)sDhck-[`CJ+{S<mJKOw!Klgӽ=h5d5VAhN= L̑>;G*dM/HF>= yP5a]l2잇?1;?|鿿]'kē@k+*ZY Kbb@oeZ'!0I&E%u߮Bmk4c$-;h[k_ߊj+ :6m]}G0'= Xv~\m^q!Ȯs[uCgbك}1t>tノ0^Bw߸`-_J͛39n30UC3 L'^m:0i:4*ɫV8Օ*WEQ8k+Q"XU3~X`D=u [Xk9ԀO™2b"40} %8[TC{6<[9VeB aaL4U*>W*㠥Ei?tcJu?W`wWH NcI.^O%eY1S8XKGCT7`nW _|rV7m%{S^>Ggk<8Nm$rq \Gjnt¥`HB[(pLJc=*bѲ1)5G< bܫ$L>  dzz"bn-2w]xf?ο0^gej N`ĪZ[-YPSnV eDp!_0YjWws[' +Yoylj"yMTV?(7Z%Uq{cNgJϕv4+7Q} KzD: jﳮo=_sM˵W{GStfL@ [^FՙuXί_ݡOn5Uk41YsۦAm}517e-v*\z•7gEf-mNM^+lm ! C%O)<#W|W"W bG]'GG~17sN썙#۝+"+]`2LzQR.S5KC+uAz|ϖQO<83[%geSk7 L\z.dK-┆jbV*f]o=_\Txvõ7w?#O%^Jz05;Zdy3{_LTAS,1  IDATU, ox+w=pSo]X!yZYz: Xk-V-!V(&i7h#XrFib"Drֿ$#8Bh S2WmSOVW4NZhwb;ԓ{A>7%{.W\l?W@܃=zh7< ٯ=*!_6w ڴWWĩgX|a;~ [w^[KIgv+帣 Yi:ƺNfl)cZ燕e. ٌq7V8K6TypU+{k5*Q[C%h4 -@!PYUeM:4hUO'ب?Jy&o U -%K})Xdy{ *ɝ!/ǩWKDZ,LAAO=1O3chР ZgMg^`ʋY+t9I {muV$΀2F SvVESFOD)0ZSB77}è_[gR#'a6O?>=nW1s/~-ŹWa6l R]5`=4ˏc-88oŹWf.r*WQ]fhql7#_c},!//T yXI!Yk̈8NDʑvIsQkRڢO+܎]J> )XY*U!*X0FģݱںtkZ*%" [ZY,9_ M3yپK2V(ÅjU Yq ,f${r7Sԅ=ښ ݆+ d5SRC=Gљ݃Tf@O3[7.pޅq`{ ;Z/jJɳezYwut9+<(0s Y!q un]xa׀f I+f8`L)y;4Verns($.âa4դFG>yfUE]ݼ ;r.ʍ8U'^6gfGz=X-5xC׸+}C2qiS@nt3 ;Lʉw*_k;~QO[ \A[*]q^u}^Z`*YX^@oA97tAyYt'Mݜ$ч-lUj=Uxjݿx*~8eǣb<7Z*m gґ".Ѷxj,=wFS7p{;O5W ꞻaB՗h\gMgP`圮L,YDS+Ԫ8 iF]Zk57hXh**ÍW"j P1R'F:B4bE*ޠ^%?t'Mv|7;2 9Wa7b72ZIoƛ8&N2{# dOW!+ ɗ0\ک2[OސQ1dT*VilO7uAT[V Mh%6_T Y-iGg\{@Pr44n jWXC2y`g*EPe4;ל\h ۷3͍> Yg *.Ӑ{(,ƯC7 51C&Vz gn=lP^j+g>L0䣵"˥ 2ze]ҩbS\Ayt_P! .'W{-Dh9։C{Iҵ"%ZGќQyOwFP#w2h(Wujq~QUUݼs@bHjCVVz>"^6k҄@ʓFql~# 7di j3-=1'Y= t?3M2mo*dD4[` [rΔVgIU֠nXl1-]SsVO1:TY1.%9 *4(/>lO$[&Py:e`ui#+g[be \ {}m }'&L1Z1Qr"YW/۟ ~) 3O m:] l4m"lSy,K'KaU)i?Sw\ESa]ph'^d27,Pf >w=XS^XJZS9n)\sfNҮy ZBp%ʾߤ6 ,,}^/0hou^7ߒg4K 9gf>[B̓1{C֤4Q "Ҟ>V?CP x|FW)^$! Bo`š;&2$Z?I;3꺦BOŎmH YX#6ժ`^A S(g)AHϒ\ʐK8ťW2,,IqFcǙ= 7pO;9z˿~;E6ld 7K}Zֺ̪d^Ec"X9ZzkPU7 t;τ 6%ƛ?#m8bL:dl cPz̫E†m-իiWۅg,z )•Z+vyrEOͺ`;ӊ3`ϣ;M]FfLuFb\MFTa }*dH,+vk,e;)ws _ |u^Odz ˺r{/L•!\ý0U3U264#fvNm>!N1ތ{0J*\R#hNX@ #vSpps fOFSPgQU|kj!,9-bOj[jVث;BWh-hƌyYÙ{,EK92d+#gIes9XEf[ 16dw1=Df$&ܟ5`۟'`5P,XYUQ?K5A$3lH;0/M-_+5΁Z}L)lڛŃ$DvڜLzl-YQdUNs'GO `$UIo4|K5Y^ eRAE5fЭ6C9ʌFf\ +(΢ڃ"jUdЉ}mrַ!?XmIMa*TyP7b\u+˲eY?7>EQPFe\l=fgh A*k"&%OI$@U4ibhswq !5UMH L%G_qм'^49Ò^ ]螝Axfe] 僕,L! l2>:JڀUrѶ3g83"QBnʥa #ä`1\QyJ>;EX- F36B}$_揼ይz[uv R;F5/HǣGk89A/2/Gl qF:`h^95|FϿfy_G[gZ&r0`Yf[ ]fF1Fb c5Z*,1Uc,ף, ʲdyKszK_s⹜L5z(pUyLs،&D*yt-8c4yu鿪8GLzRQd%Wq+x\[W.lUMd5 [W c* Ζe] 郕3 '[G#St7#DqGZUc L}z2Uw+̒ ǩM`ںmw77ߝYq:SF YZ)PE؊BZ$PeM6@U8fƖ |萑nbX]qb'BFsㇿ9azg7LK\z]ο D2nlpP%y QZrGWZ7'v`;dku>x>p*X߇hV2 EA>TU;_j$,9u$ġ|ϭJ+uqD*9ɀeϭ:vUyu>ɿ`kq6>MsEa'-+^hLK tg`Ckw`t_Mί4~Vƭƺ}DVBS w{B1Dpjj3 fqmqǧT9F[QU6ޔ6DŽ^tc3Vp  ζj})'SXfw#Ӆ_W|z~z>F#Pe)aS\˳6\b޳ہ׃ ]b`uL,6>Ag jLۋO)S½$ۅ VrǧLYO SR|䦩V&ΤIK Wy#Ykz,spX+Qiލ?0Ix9Z*5fwēT ?+1q;7J=KQ-($ G #K3ȉ)I29IrfN_GLB.WUi;l}8Rcl:wEHwlwܕ03&3l.?gd+l.;ZW"@.؊y.xN,bهu?wv>88W*A:ƒ7"8H)D$jUz/-CBl,86Ip rmϩM`/s{ڷ&1:{~?VV^no%Z,l3bÖMsרc_Ēת VMYQ`&i=͈,ѱ=4laF%>e_I36:g\:kgW^&DϯKNӇop#3 ٨0>Io:}JmXeޡoI LT`Ⱦ ?6QORNak1QzOdr8JQeݾx4ь NɨGkB8-5ڌdV#BU @wJk_)+- d+BO&w%A g1W@^wS.fǠKtփ:gTE+~dE7 Wa?\Hꀁ[Z,q$ xu =/n CV_&W"7XGk)TaLzK #:Zk>5ͽuUK$d%ۇul{%U[ZVaY-^[% 6/ c70eٝ kcvax1f`g?xY7ﭼy3#3#;'΁d",|Ӂ*ZJx\U.0gFȞ|9&Ty6\WYZ>Q3P1P%EklB[}#JKpݏ%͚Q'EJN`$aa\Ì-/x1xg9Jds]sXi^u 倫(7TOQj\ h*ӊ#0KM)U;e5}76Ll['D[#Qժ\JQ)vv/-OwKۃtdwlvm=~s_ax`)Od* WLt,Zoh^6[/lZk2{Y61}x`Pi>LɓYsTTUEYIJBVM&69c:fBz4 \qRIh|_|z ]PcycpQlts?[ޤ{`YL 8xYp h`B,߳*z:@Y.E|+\N2QYǞ>ȪtbBmӳ7`2 G=ARh>Ro$6!`nV^]Dn ?a0L(mjۑ.VGGqk6mmrYܢUVmi;<*Y6Ejeԑ+Sxԭ"U"&*LՌjDŪn+qA&1ƴ'o|dnp{S=jvlǼd7'?]s} xA[(XIpo_V;WY0ٺ?q9bl[:jnus߯/v-CBʖAѨqUMއ+5AڪVMTJ4QJcn8M"M@U\u[5ϡ!EK<)_XdpϗY.vPpaKs[{?8L5V=uasϹ`!\_9gkD͖_8|.=dzҪw:e6 IDAT["i: k{S%kLD;om`ŴO:v/pWh.Q 2PAӨ!ih\HL- ps7T͟Xu]MUӃ$Jff"N83DREJM8r*]ஊK)_^֧-9ˋ?xëv팿_;>U{~ޚg]t o3Q2>WrMdZ{#[OR9C`,`5$i Ou&ba*7]%6L*htM=~{LjgTPUH_0zF2-"aBuyM9k \s-fUWӤOHwZM|I09J*B63DUkpUx0^4٢JgmPU.cLPnE)[Xx,>J0Iu$;a\EDfVzU۱$F^ WJ*`UQŊ's'6פx*>ILXhxUڍ\35gA⤄*39*`5 cx/Q`4Ѱ0]r0aXw֓'gVs|I9+BZv]*S~珳N)Uxȶႉ9 Xg2֬r ɮcEUtSވI_Ug B:U}l'L@֙xڲH`F<|\ZJ `mYӫEtH}ydal.IŵHa0L,LqbPFj菰wefǏ~ZiY>҃3zvOpnNܕ/r`NشwqKR/1wlʼn{tF1ݴKQBYAUeWUX7$Q3a1+S@֛Vn*BʞvherBGx~.Q[FU,e iz+D

    G.n0>|yIﲄD*cceB88\}WM_3-UyڐӠOպ`"]@pPN(r3`s[]ԜXͿWϿn)[R}ի+z?(R|Etk/ލ\f-7v2޲w(c/pt?>W)qThM,L VSRS0_ x* ƃ%qZޝ=>}/BU`-ևJeIc;å_;zR=8{&NcE;H҆h0*k۶,Y)rp#iGut;`[vlx7q Wnr|K?,ʢCym L`;PScVrя ¶tb{:?ouhp\:>/iTERk"HYzՃrdFh n 7q_d۷u'8A֛^$Xjy[ʕ&0vDvV&{ֳU {AZw9gֳ`M/&iv2tܫ0JM|kzuTO VENE+NդDi 18- l\YBoq e%R77#xw ~*wtcLeEIHdpNNsJ @e Eg4 6•5m U,Hfz /S5MݰѡtyS?Oe#4J|w6'zu8s)0eií,]r3K[.ǙE/(/O0pX4hf jTJܲo{ߺb`nxpPuAG6.0@]#EѾpNXuG3k,3Ah9h>٧mh BVT~57"~IT)507bVV0~Ψt*r3aUTMLY*®Vm*쵕 {3mWbTZd@*[Wɬg_܃f4PU K\Y1u?iP9;1_uٿ#NdSm;{)MT28όLv7{3ۂĜzV}BQ!]$%)]s# )ˊS㏯~fYpnLJV]>}z&` 64w\+YD%s#r5c.f,sT^m|!X11y5 J'aކ !z!B;k{5o;G"`m.VD2#eYLn&bF~(Qi2j.Hm&+2bp1Ōǰ7L%& 0&DC7u7e4y!:IY&3nTii}&q;/m0Q/ǩ9J)U|.:N^Ag=^I9꺤NkNBwKBs܏t^+wAs>(@2װ"Wĵr2C坰|TSk}N!;#N79.ՔِuCIyWi^|cR֑SVJs<&N(h 2)D߫i;qgɛN'u@kvbT1iWtNBR4ږ4W`\~Xb/U?G !8FY1;q2M2d`C&%6p^3Yp.q [ j|ysm˲%%1M,, /pp/m̳ gXnz9=M5*X"WUY"U?Ej{m¶Ĕon J-4”j1x-Mo2ʖaf'•(VP$陊VYzٯ髿яG+RH,MZahH9M2-PG#%*V=wuAKg+hBsNę l,Yeu_3Pʩ)a%)9QQPS`ǿVLlLR$D4r翏UĦuoWN+63!<;fՒΙDD|B:K06avSZNbgH`fAcpM*V a?CHn36NTʴN +=8#FhA*O{>?OiAuYMA@c}?D*:dig$ Lh_D+Z &B=2d3HrRE>rC$lA_.vTyh9=Pef/JU9b%Ġd&l/LkY$|`-lO?V{+Xv3h'vMٞ5WW@܇<~SYN_ 3jMܧ5X VQdPSwU/yK\{Vi6udq'7`oEPf<,WU .XY6rQ}0'Aa߁3i0)c{,V=^ |mn̫U^woU;;c8Y-%@`>SW5I[JNr{},a3TOa(W5cypSgԢUt5DYQdE˫I,_7} 5hAQs+)g ZȂ= 8Cl9?1c7Wüd7fv `nI&=sr wW11UR;vs!j2ۚV}<z5frA3=G*pwdY&)pUʟ_㣔εtcMWPXi͂\;ꐡwR800㘿) .7L6bb:B9lr?nC,(Χc1%$~ЪV&5 T\s6OH,2y$[Wd ܙ.9y!DbOk>&a Td!N !)tm!u p.Pp %x ϡpl 4IL4i6 {.lLjnlp=j9qheQՏMPժ)䅴Ғ%'1EQJ2 q _C1XPU밈6uSJ4!=}6-`eE]KvKvÛ+|Aݺ끤xͺg^m*FCGQAZkA+CB,b&$kV{~!޻4OLVvgᐄxO:O!v0 rZjGr8[!jUev񧙙}5zӀ.٥`i9Ybc~N~߃6gֆG]{;FH?%P<:)`;Y'BUQE`V5޾Eb`umR{PU" T)^6N~!iT㟕PY e) v !"Ƿrr}A6_Xٺ3V16_|c#_YSU%0LpՂv4&ԝdV^lVGfoڨ UDEzʕ.AHɝU2di"XEi/=Nuv|?sܹ?Uk5ARkv̎pK#VWk Vx'( ۷ mRRlzOQ&R"*dN>և_{R}^얝}|E*Xѡ=Rc$@ bT1G( 6(v GEo}{|gW[k+]֑[XX:̃Ui:LY{`gh 0inU9ujhc-CU?*((24pϠr##?7%B{ IDAT2}++amO*m,iS6;HNǰ<ͥaHb ƹh0.ʂ()ʂq]ݏa_s=.imqVViErc@Q \&)t쇍P^ 0u Wi̓ zN\ 5Ջ<~ a}}췼(qMF~xɃ|*.c`:D] a& dlzǯ9dY5[AŇ$]kX%ʎtgton|Z+U*Ə}}pѶ|O+)tzTL=Ƃ-`&*DE YǫebN=4FV [&h~F+hl$r ~BYv+Y߃Sh֬jҏv󀵼P]-7L$t~`3 Kn747TM̿gK^%*LX SReZ ūOi\Z?by3NPe"ۿ`v ׁND\*!HE~Qv3 u|J+>Kb+5BM֋p38vtuCzk:WT25aˊ @^:>~n0*{" MYҕ֜t!+NFc]`^\^࢝,^w3 r}yzE`Y}U`eK"`5) quXp~Ϗ$mvWߌ~m %tի nu#pӿJ:v4q4ymRH-7߿f9],-Q/OU 0`~g>_Ӻc 1< _sa-{bDE;/qf`.M~Nol& RknXg5 &L}K]P: u7܅Li/{o$#RDa41ѯY4!RruZorƢ#볲e+;uCuL/}*+|L2&,t1a,|`TY9c5΀+T|M4•LN{zlt/_ >f7];\Hc:E=T~Xt13,: pe+0elop,ΚZ?@P;PEv(dT?Esh $+ݗ%**kxz }SWV΅bie` oxo{o뛕׸J3]_, 1N|">,Tôr̴=zIj+?J(t:MgGٰ2ᱣsz`•1aV6"г6xAM4=4jzTH}%OaC6ҔP`PT;+u4뀴BO+Y*,8{JU8[ec:\Ҙc>/ϖ!n5Q-8"V,$rm@¢Ac##LxW_s[ZoqY~ynNWfŔy3fN#8ң߸Gq=Z+[PU]2U**X6VPgg pν/^w3x9ݞJ2J3*΄gtv<.|Y^2IrѸ Sk*dEy,`=?9Zf[`^9Ci>U,w-xAl3#R`0yk3Z-d?jUf3(,kQU"ֆ|lK&5SϩnɮHiWyG`h#ǝuBiua+`EJKQODh\qګMj%*X ĝ_TZq`0T~XU^啭Z:3T!tD4E}Qأ_xʋv2y3߄d7\|溝4@r:?‰{(OТrFEE eLjXEZв6:A> P;8l.7CG)HIdŴ[U$ Z=ƍGz q ɿU\Uށ}lϯ)2n;#傉pc9XǏyy$S,,\vg}-OM݂j=*jsZi0/Ӕ\P**Xf8zϞwwwWU$SSR&]Kا0M 5 ^]O}VV[z;RWbzË́#t> f ~G;SmMHURRRQ`7 \1ZKI!VzfoU^iEt|gfrL7dgdq-rQG၏RD^r+_߶znꭻ9q/O≯xN ;wR1stXeڅ*UK(_'L[\K1±}穏7ͺM[ >tH"T}/EFTd\r/yܡ]SU;Vs8 MÞGO=Ju+wu$p(#Pp%S5:Wߗ8<QxxM O#K0^VVb' O 7"GJ +hn=lHN0iL2 &*-6"ܓSظM2FzUwH p~1ֲAΝ%ًOxͷ!087>O^`Po%beӍ,/܀+6sx1LJ/N?CEuyyA\|@"d)t%GXgEgj[vzQLɠHKZ33ZHq#4(=E++43sS)5b:Ȓ| OrD1, 6:pYM@XK2# Kկᕷ~*t8D8eݿBV|vGt\_W{ɶLuo:16޹mI/FtVbJ%\rхcSoU BHhk;6#~4.̀r.vRṘzuOBT1RT&U,M2uT(X b ĚfpLTTJˆW`aqz zŀ; )F^LY #/|+1V[fкPN;,M 9Y}m%9 ռ ZP9oZ5kmP5m*m+9\27c{\[OV}|k-zʡ;z 5<4 cRWкwH S Bj-dx~,<]PkG[5D^^M*`-ٲu21P) Щf|cxgnh~J ,z:QjjipP% IbVB>>M>oO|dXZ\\"|flkL d1uA"S4xdVSEgtn[1j,%9Vl9*zCɔ`"ClDJYsby0üji+EA 1'_S ] mJSyx>K3;)G l1wEXXfpt??=u *?>.lQx>VPE89F)x0Wv%Ƅ UbEئ(e3XV)3 ^]6tyX9>_AV>P')c峯~M,[4 *Sru8~ɋи`#*eWV bX"}.|ӊZ:$M )v%:LzšV>ՙ֛att퉙U4a~5m'٨V Mz}Hs"[HV`Lт,:NXCE }p!c~3cO,8*NZ}ʖgWXTi0X-(xZ/ 9l!89d[~kwˉs?Uk*hoGTfhgmʭgg9_ކ(sZ XCPb&n=736lh= +`-h kV93ӝjϾ5`,_#_\UT&̓*C`B&@#SHQ !'R]P|7Ǽ7Wx'+Ց}D^-XѴ>"uΎƫYZ[Ngp՟P`A?^×_y~oVI|$[љ/OI+Oy15׈b$M@t(IQt 1ǰ2|(R_bn0a N{S僖j̱ ~z I+Z0H9<[ kTҫ d2 )/% }&VX9XuChW]j*\:VvcS^Zo_)Q3.֏uY Zچ]NU!jyq:<|C+t`:tyn` ':[Ź=ꯇGZ ze!WE/ohsnƩ~W>cyNt?}K]QBUaC\w-SaTǯ1R?#k|63uT.0c tۣ.&AV8pj8 MϨ$0Ca~1,KX9r#Gv1gnpgb7}AˑG-'Y=^Й\j`Iq+_{i[J3O(TPp%eQd|幟{j>)NTL-0~˛vW&o{zC2CKG`?A/(X_ "Y>Q@U? Ԓ C~ôo1攐u2.fN%"炙.WR!A(k\L4+o`ee/V_SAլ.BƄ^#3 f=kUWh. U(bLsW_#9[]Z"ҚNrT"\cKpX&h&"fXYZ`H8v 6֝ +{N+TѮk>Xy)T+\I [ 7$ӮXuJ25dIpU8 s@E IDATW.;|3\י&% f8k0 ]|u#WJ0 )vHr#0IDC8Z&̅(_ j)kO ?|s=r`޸yX0W4!*u*8΋`*+XE᪉D o-sܳsjO_ݽt̫ݺIu4Z[UY,0ۚ~yme>P%Q 37͗t`žފK: ~]k?igQԡhDY4cO{ɻ6 {^钺C_^w%*7!ף1 B3bu/p<3WXibmoW}*{/᪎p!-`Bykm䖰gYfc~{V9MY~&eʵpeE$κ_|2!I-Qoϯb% VzL02Ly,UX{U V:3!ʕĊ0W'Y|5bwN[\kOOmOG=:n/8pv}UTr<W(|ӪVWQ/*g;}8#\.!$[g~t Ry%'cSILR߹:i}TbICHvS<Кmw1Y6P ƶ~j:4yaVZ`bf2ufaύ4~BehT1pUIrN_^C0umȹ^[YciRQAW9`E1uj3sl jπתUR{I dRgEZĆ{C7X$|.]u~ĭ?"dgjf<ӗrzv6$w0ZʕZ'+-lWֻ𮪕V5k6F{hHG `gUQK m"8>͟rgG器W]`(Ǵ?)ڒ1xuɩ׺=t=PlZ q!i ʞ?r5'N$ϴ9EάrO+pq`+ZЊ.&%UL|".>nk=| w@R*!AOk~[oիbn3_6U(.c>:>bEcp)p^bTh~7x),S`[}o^I>py$?*1Yf@mj:UVSa+SQ_̘0-c`*Na e4Vm*5hd5g,e%lS_C\ִB:uŶVÕJ&@Sx[Z$u@'`UpdAU snQUcGr.U,45kSTs\;j6|iMt҃,\5S0g vUHQE<>,^|9r߽,^To?aujxʨ3)3ZUgbr*˒0ssi,OqMd#L=+~)F Wٽ@%< >(WUz=qq>E4m"VU} p޿j gIa/Mp^!ˀqU0oׅ*mmI^&S2W\6޾  r !]q-Ꮟ_p\4;_.cdzٛraƖO41k&2:0󓲰n\H]1B`f͎iVu`gkAeF͓cʪ6 [o#_5v^ jglWrUUU2zO=-֩y>N+ I;1mև*W"ك]YNU3a꺝DMӞ˾yeEљz ~~3]]TD`1ѬjDi^s_xɖać$d`%s*$:CJٴI%}-QHȚ W&/+ L#RNP`SnL!_y G\T-r:VuƖ:(B4:KtZv[yi&j1LQb GmdhamBIO)RV!튨D0T36DK&DWQ%v1>=G~ipUUI+,cL9eXFu%1:[( k&MKD̅.`IYH7hD>~=K/> c@<-Z*U2W> 4TqS Zlk 6Ce 5!FYafUX*K U+S.JhS Z@ZkXe%q;;;:0 &R~"m; \\O`MqM8󰥦 ƔOzY >1t_j?Ӟ/٠QTŪxU[ W|&K=X#GfE'9llQ%`mH9ok/nsLY_շC}6*TJ*Rs\U!KN nA/fx)6_p [,` 1TICHxZr~yhY`"/`ND}է.V+Ut]ת0GQg̓9;ɬZb  $@ 6c 1nOLltسݞpGL{:tmclXlb0`h>ҷw2qʪ[}OWuV̪lfs{ee$J3< ^k6~V2p,*` p1֤,֒wKK)ޤ$ݕ)VhIyX{, {Q@*bf!Z(Y[ث|Zɥ2pap<6])WٽdBm@3!VuV"ǀ#nL8뿄zln.yۤ~-)yiyk>I@+k%m!}Ŧ1[t:+WF9rm]2P9.9~7n/* ,,ʞm<:j cFM<ſX;I,`v v%fRAdD܅G.l iwŚ;K-7I3rȮXuwM6,k{tfҘ `U4 B9t3`A*$= yg^ rCx^^g$n|ܘKܞ jCխyMij k+c4ɶm*j1>wmԉQaeo85$nV kՀ qg*cMT́83nWf41vvFt@`q _ (%xЖ@:-=ki}5h$1X/>ڏj{hR!|,VaRZ. dL6Is3|1xu`SX~~<>z|UI$;[R? l}0 ,cS|'f=/+m3a>"[uY7`TT +Dx|pm._C/>YTeĔ,VT+@W@p YF@ fD8Q5)M+KLZ-,jq>s`oEY+m(*7sپ[oVW?L%BMVXA g `P:NuIircI}`eRfT++!HR)-_ҜXEDŪS˾ S9bH]7i'F,Fs~Ic5+5kVv2 kLoYr7_,LtwO4fk'I \FS0.5a pN^+)f\)]u G[Z \ֈpAطcXz/ɞHIt1ݏ}vGf@_%$*V91ivh"ou8簼@R /k~kME Jʘ>DtJX5*X-Q?YlJ'#(ou`qVQb1bO}y>Ƈ{X8V΁']R|v)Ǒ!lQœm(1h@]9D#!iǎ3RsyFeW+5bqc7Fd yꦿx;|4Q֪OnsFɁ)X׀K:`_B('ze2ţGTи[^pb+ݳf_LZC@ut@U꤉a/Il$&uxn=]g]YFfkECnv:TW.}ŝB/̼/[lj,J[jAT #FTA0yOs ?D!(q2,8*G0.N9i\ri7`IF{6$EJbgѨ3 ʦ&Vn<C {x_~m^Ğj0Fxf' `c1t/JPb6 !?%n*uCbο*!J\Н55OP+ZP$ y8i]O;+g3 Ǐm3joOvGMiw\U=\nj(o߼s[jF$i"@#ƺhLHjX*z2;`MSʲL k'Sx2f&v!k5w{e`̕PfXc=&`d[wXNBWeY ׌V+O@ĮN"8m#Mؙ)3 FN"4N͎qZެVO.fy&5f9dL]K[>!h~'aW_zuAslo{{cdتl\As>/EBk)4 J~j`}Ig,qx⢋K.I'lTU%i4j`4F#jX%dn_ܶ"rqfqB.(עpQ^[9\u@)ʋ[GS+-8 ##Y,iBT2B!Ĭ0b`Y襥|dсž]K$>RAp( m\J-^;o>p-ڔ>I6g%NH!}Y f$ɖ12"B$W5j~>k/mhȵ/Ύ=i}|MCv.`$ḳjsSeޕiF/$EL;37cЁ^u+,p( /j=|*`̕cY c *2WQ/uC7ܾvlq%/KoV^&XIdEbMs'$4`t6eYWC34F7熵 72P{UOXG k XR\|େDh8φ&ij &E1ی_ya6kNZVA)HnvGe!^٬kۗ9*eKs+}®N7[n9:o~6pE@X*^fYO PO;[XF(x$#+I{8W BSU'1[7W&/qǡsGv{nT "}MO &Ԃbbx!;35ߪx bqe(Ժ3Z9?O|Fhrl)\!mfdU*'l Y?u^!GB{+O6SV;91;60d1^„0 N=96Ԏ$tcZQJTl7e߻ ߿k߿cf=`NvZY Vl,14'o 7ݜ,SU;V\eSXy]쒃C~e0(ʀUa<1k7MJjK?% ۦ1#vk+"P12٫,_nDYED8'~Uf!kvրETmT m92\E76% 3ei I,IS(;gC {eX/v)` -zuVƀ>{֯=fJl |_=;}S\0Ep`DgxQ:@ _,pKI)cl#ُ5T/daOt3԰X1@U&UbϋҒbƸ_huu5tpGR[=nZpnBj0 bY_ +-v:y SmUڛX5GxR,tLR("()qX8#tP2fgejEϻ+@]jҜDMFCR$1 08beq9i!U&Z f:ذ&YntՖuj0kf' `(L d8p[߆*"m V*pwɳ>fpb"+>AxB#,JVH]ϝx'PՀ+޾Gcdl~}K]@`+$9V @[5^u5,oM{ES!Y]( p(e0 ˥p3k'2laQB+ [>N{-G++$gBcl‚*:w"?ݧ?8#KOb=?~N 1WcE Z=#p&h ؇Wk=W:Qn-:{*(]:(b֒&7D/>QyMiyADȡ>xZJ1&B PS:¦p\0n)\5daDRřJKkge'+"h$yM'_ʙKK`X("|]%ϱ.O흳z*7r`2+ @ ࢀS=|; p穞"U|u;'3K1r?xߗ ER 2Z:}N<'5F| ?G9be֠^dͤ2B]5"SA}&ͨAAD5+ JHk[ݫs \*N6RO¹#+{|mo{Ff14SڍJM#x 12BW1O+>E>pwKf,bIf czAJ4s^dQWZ^ %a8ysǨ2XZ_ZBZX `xgT>7 RZXONmzv"[̧,!E. P < `j~I֜7D8~R\=@]#??<{Oœ!.%X0 !L]2UBDX=GQ oطt6/ ':!ΦpxcTZuEQj,HFY*8k*|~;Ϭ"nr[\wt:ݗTAb%NH9ɥIIE[IvP-z=v`@mb-AL{O;R,ASXRkVACWcW5" *iD[&V]*MZwW_2}tl s|5;ukv]v^K!'14"n~@O}RGlmGj䁃h/VRح/1peNhD 73IgD2veZ@H*nkwT`ҡ!0bx89zu܏ܟv۳p:-A, x-VZcez%p&V!daW @} AǖGg&&Ҁ+$!A^U*@f4։JkW]Bƫ]״= hɹ[.o'60OOX/{CPˊnt\1T,i93,>\77n<:VfzG z\^Wo[K_<,cUO`e/-=^ X1?G±#::SX=% %g89آLct1k2:Y'9>?z *-Xhl=vg-ʼn2 =+u#0,I=+UU%@2D؆bIY.4XW4D WF=?;٤*{/X< XQM"18fD (JYW!²?XXǘMa5ڢ֎ȮC!+'k0 i;*AVQn6w DٟL~>y%6Y=tPkj bdԡ,>L]))Q]ܱԃu9/APFjOu۰]YKU-pe}e}(.٧jǞ'?#Gɕ0'1ɖ¯:'ȁ`g /(=]Hrz0}Mo.+k0Y@RGs@6+1V&_,Ol?cu0ls REK!PɁ'@QK{3u GX섻2`WjnI`s~Mdcu1@Rm\zJ]`i`Tv `m]A֤ga3l.wl\ٿ ӆ_ExsTfޒ,gITd{4'ꌝi܁6e*AϷV/9wL6*Kw⁳.qξ++X9yGƱ'oEMc`O@0>]*9'!s>p--'9{+[wr$U |pNh%k&42c KGfYR#q*W~TůNPylRܲ6U/X"8PkB `|}ll&%9f5)$B"tEE:ۿ1 Q3Bv%dLT~ ]'m%zvHkԻ-윸[A| vye_ 텨yi:õs5KJaSԛ(K) Y5yߺiϔޚlȸ=BWkk ō,gp > g_v;~pb|È' X/g鍉R7+<13gUa;3oϦEV1 X,+gR{Q1)x"4~ fk ~%!ԃ<).XA i&کalJx)F#T\bϡWIgsT#4QWِ+u[sٞ:g`m_ 0Mnن_wͧӹP%ۈe@eėaNX;P27|MJToE!e0ʁ.@1!h*@EQm3 V}7z^)r 8K%?3{ruwa;Zž+XhsS6KiEτ2DwL{1 GSg}'SҖi"ޣe ~j`u VuU^YAhDn8Z $%{ rK-DK-JkhNo]P _^ٺ~v_G/\ʵSco:]J!M 3]`F08TFQ Yi:_ ~9}.*(ɧH9^:> @ (E 6{U+ҕEjpd\o_O!C+BP!ONB0V{J\; ŝ[6{xuicr*S K,XYbaĉctuv ܰn5;v>wMԜӂJ>JsF(Ҝ9u1 l|LJJ઀dV&k`6˖@,0pgtMӦtTo;A3} QL`Nl(%oˊUQA͒U%3hW`3mrKb7 F٭HkĺBeiF+ xeCeJ+mo/Gsѵw(wcM}oCy$JXe\Ih+Kr5F\y3i4,xΘI>7lфp Y&˚/4ld/:U0B@|q}gF]ۭ Ha-yr,$Kj,}@+W`X P%;?3}gnGW6C]g[7[5vNv%LhaqW6Y!F4akHg}j}^}@1( & Óy)FdJcoٶdjȺ(2\Tccm (.vz~dpi- q畟ž fysJ em5`l^ٗfHG񮧙K/++9*ʙV@u٫ppŞ=p1 "gw?|p?u#6+kԏ{%EOQN+?M)2kR@ bQC1%llCq<k{kgՏlm mѴ}3X8X9˖e{&xu[7ڶDcZLi{e*FD H|x*ȋ VqWC럞kĻJJ?|X SR\T66[4и:eZkUS9ר5F+@,XUfj'qf (SS`?홊kšWpE4W5a<d$|izpZ+ _mhMケT3W] F+5 ,,њe³!݈ga:X7-VE|jkOv(Vĺ$`հW>Pel̶3pTzCԌAf۱9^C:ۿpF{Rρ<ϣ,5-@P:W5S FA,YS&܀+RP圓*2;k>&N]Ky/{7R}e1@PPf ׫c{~']3VR?J*AZ!Z[Ss|5sٵd+ge }kЌÝeP$j+B$c(SJBS:bb?@4`E( jPrx<x2ewwD |_ KpWDZX4ly4 㲎4\Z?k+npm$g++\ P5ww&%2fW@9,`čC@Q(pA9rd{dm!ex ~Q*jWICy.q[5<#ʾ {eAuuD <|6ݸmL{d~5\f+`\jisT`&r5 EG~mV4t7G,*V`T 25588b/Ɍ:dxST#mTb`L5 L@҄οy7~ .PX8~NjKOlc41pe1di KA :^|acՠYk*"'3cK IV}kZc2?&BЛ*1߿ǎ{֫CHAU+Ry{^s$乢P+}&`E`P5&KvjSS 9 wY-<\wl4#YˮX|ό= $Ke­g!u lqBTI\, נ!K,x G5V";RU mV*Zy9{T 7ZUYt#%l0‡p٨yw:)Aj%аIi*dr+eņ粳lݻ&NWTf +6 F֍ƁʁzJh,e WwpD({xbE_~eaΎ#IVU9ތ@ p( U`\m+^voh6  9*q2I˳pC+C`ʇ{X TgdJ莖>P@782ҨT s@;!V@Mf\)2-cFʉ:=̖QmxꃇR $ڕp{ '[֥1~[k`LAW{ULUlP" \y,cXո/Ꮏ;)}ycĺt^YT \5 2*Zd,VTVP(i_bӤ" Ӱ|'T \sŅQ{(rH0^*;Y8;}2>(d=0ĵ9~qQ"z(S0ƭ/6뀾Nʺkom$C[w֜tlZ@lBFBXd5%J5/7>;ïvMPW. pQ,bD*9Nϑ3X/KteLڷ~5i䔥҈&5UQjsU}] 2/-1 !DkDQ5^'ߛ&߱5_Cf:qFՎȮXj(Jp}.^&A= .HHQSuDR{Z`>P%"NG# XAnzAR[_e#'#%NV]$}w/SD'0[O 5_3:>ZjA,s VzJ-HAl伧`m(_gu{#T{uc]#QfVGC]oT6$fz, S d,AxRl^uQHgʉi^v_\m=!¹ןG~NhN5)mhfqne粦jU 9zֈm* &Y'݁zX0\%Sx נ؉.4D)uhM±^sBJ[S24?)>8BD I$Aʒ~Afv@`%W 9h2uayInM!j/Ġ݊ Ȱ+z 5_rƧzqe;r/}+$8SXjC@\]E2+2pwaW/\z{d~kQ0a3VWYݥؙiSTubCQ3 AHZ%`x=IM0XʼnO`(Z$E>k}o`Uډsu4]ҋEϡTBH*-X@Hcx+\p!+SrQ Z]E* |) cwO_3S;ykf\WLM WFs,Q6"P 8<G,¤pX%GG,eщA:瞤-ư@Tb TȲV s_~}Mh+" E6)wDv5zvDbh`bՇu\[p2.֡G ([`F8ɣIQ{D^P"flƝ+ݨ3p|bx0<ܟrgcLg(D(WeXVWث*+֯] 58rr5eB2+Zʱ5;nKcr"5huXJdiH0W_cPݢp;$Y9[:r E 3ɮFZ9S- =a"5?wBk`hjp\)$%Sqv B 0 0GIjqjx ^YAc PQ GAD&<Gc-5M"&P)@rʁa}8F=h`,/*= %ٟ 9Q׵*""|~CBy;V0r1RHpXeć'Q?55{7 LLN }jcܐ[1i D:獅0bR֬d18s#4`0AQɐ ןq|dYmZhMaוZs|V]ɫ˗sgA43Iƪ6(pjB8lnDUPϥ6"!Y;Cg$z Uwi~PPW  C.`B`gqq:G/q}Í6r]Gس,mT]mD %wLp::*l]w$iOWidS)2#VuV/MfAsʈGfQCoW ħzJD8#Ęu1@\4GNG1u~_}=k\ -k0+Vk.ϼj0XGDD?Rۢm!hp0;r'{: -Ђ_ $b<8@(;l5qui)]#3J<$p3G`h syo^xY`y e~/;M )PR|kYXCU pP<%*+B3gw_X'Z,W|K L ..gز>HUNj(| oNv5j&Jzt!RY#PGJLܬgϙ*B%s} u$v #c*$fC@Wd QɄ ! Exs>+lӐH+񳐦s##3X?­TiXU~>F~ ,f¦aG5Eb^pA皁IgҦWP9B\SNhT(\QO<=̌ᑧq1N;{$Nx|@ swq~AZ,>, Zw/r+>d0+ 2pǻ_YXXF-շ_,% cTM+鿩&Jdn&AU{]y{Cpc_QjtYkbfԱþ]hl;c2P3;0C&^̢%E5a@=YӐiIdy9z6KKUfڱ{h~-u 7UF}2TUopc b=Aj?cm /P$x7@XZf̒N ,-]MxȌ~.^k0WmVҲQLec$XER>+ybhyeU7|U]]U=wgf[Cj l0GĖWa/x-L k H-4&PiԣsuM޻?go{~p;=.+nU:uh7~ũ}UTunðI$ߣLHUgϰkn{zUzʹBEh2T IDATvփ@>;kscaDRkI];#i,7V# |)VŒ6l2aA(pE:yO0Cě`뙏XVl9<,*[ {QȣOPϋ X DN̵PsuUS sZ0(Xr@hQ$ @X9lJ2ib9]M!轳.!3\.ԁ\IBߜH;>#38t LMBź.qiU3& g{o~XxgKJʤ`o%CJd8 (ujHب,!}vM UOI,<_HBZ/t'Kz~4ʳD5XHŨjB{_:¬X?0H$2sBCw.)h!$cP/jC"륽Ɍnvm dV l9,*_cb-y6Y OYgl *UJ몁,kM<әOE1!Φ>!(̓9j1][KL[ǔ6WW+Vl\mU :6z- c۫~;3-Oe^ʎAKF-jk](2[F|5, ?c5a>3e JօmXuLlf~+&3]`;j#akdv"છNث( ]'Y^< tx-.m kTgSyZѸOOrؕ^%{UUh=270DTJuasǒiڰ^_uș $Qo N$^PD4 R0t^"N85ӊL=h1yUKV*>9j`dfἍT{a*WURmR"UR `$ٵ`z\o-hhv~:krF>2t.IYu(zDy'{ m5K!ة4/نDmNvΣAh YS2Nh"[ ׸mڐnqe:ߖRǖ dɷa+yX`ۙd%Ϭ  գ ~,0. 2җ̳oN\J`"cآt#ڊ;4!;P!fB׉y ABA6q1kX5("`:OQh%EPZWp86U}pet39:s#(6:l,6&MMv>A+mV){% P%0XOIG=[, Rd{ Y:yco5H%2X/ېɧE22Om;ᗾcbBKpq\o8P Kq6#ͬ$(vm'nV [M&~E?#<8%^E+pK ]dga5c t*Fz]}]4#*X:+ euCbz6}@#:q`%64|?n]Z۽JΞ+y>dYb?_ֽbFA:gKJ"lH)Y` jG 7(ی8U)L~ _3fƻ܋%݁!;+tV$^ }1#UUjZE{|xb bI<keIƩ}Hru%OpFA|͟_\ u66bwy)vڧ`HvMil.[ hxYnk Ls |"nV%C.F(icju9Gx{^a\ b#tb"qoÓF# '1XF\IX.`mŶ'+'7f8 X Qk@ept# Fkk5GC?k;]J *VɾsxTǤV/d^ 0䆍ܰXCaLoPZ|xD #in\) fcxB@}I{#:2A )31]CI]]3atly,7]~|ꡭYE3XߩM-NEJ5;*Jv < 8XyYYh ٙ@VYdˤU2; @:NujLO.7FK>Lv>2@ENs)7lE AuOv3RkE5|Rg iU .SX+XUbH,U f &61D 6aE4á $^(2)YP`Yo6΃+ҌѺ4 2FA5BE0&e$}O pjByb҈7B!]t/oP1=>yr}PU\2@`fRT]iUםHmh-=m\|=9QdҁͶZJRҳ=%0Y:y`uAd{DsM B tpؘ9+" Fd>F2C6,[̨(}9;SoP008`̥\héǥ_9@IÈсxLԀgX:w:b}$6]aVPzuj%dC@9DOp@yx9X9JW uUN`ψ." p.}7н0$P2+uYFwO+BO3j_ je @,QB3aJpaze b #:!A#3@RUl@^}$yZ bgũyg K_|ѿ@:dOɤxܬ9 dhorg*v&BvҬ-kH:yP BΟzNbZ9Ru4(;L/\عt='WC!@0Ŗ C>j'}W!cAIV@! w씴 )cDW\,Xg0򰠾DEM U)Qv8UZ2y(.b2V7@'4&' SLT X98'YpŝoIς(aVWly?yG;R\ٺIȤ'Fq弭 TvrE[ٓ=B10Zk0ttqVr&$\sgtq}O;=N3$}6a@OM3*mlԚݥ~6 Fy喵H$UU(U*TKRvW0h'SdB pV1' o&Xa?_w=s03L=XTs 5ꁭy-2OyAF TcL 8gic]_ n<25I2+JiB;GnDH\Q@oL91"tM3@ljv}kYgZ*ܐ +w~O2llMɀFT,)i[BW6Xwq&{+c FA9PR98ᜃ/ldBUv$ r2R]JH@\lP1V ̍`U&qd(a!>/c(οhC<=zߧie"jpe۬K^+|),[,@kn(q&|+&gS7-*~zoe^Clg앩A ~ #;SL:GJ_ճЖ1ϗ'c<-3JΖ ı.jp`KR, ː{!\oP|3esꄨ9*Z@`8<sF'zVv4Fo bLV*؀y߈M|qܙ l)茩6WIXTAف^,GvT+MAtDG`UY>Mr-6A:~ =b0~ .}x@+o'8,ۭPU>d+kva02`tA%x_ {κx?e?z}&ph &U_6߁KB~ C  KDJ .B{.&ZglO:q]1Xl.,߳?Z_Qzr9YHځe;RY?&r+hjCalFX+=>q\Ie'c{P+whshFΡOChɗT=2\nvm ֑2 s8W6x/da 8nHqzǟtx矼 .о8Ҁy. 8pyO:xcxNHqLZ/6PTm`E_*^,LAU[@s1xj ! OGOy[ZK)b;pO4ඓLJ0BHg@ +ΐ`\}xk;yBUU>F{-k5:g%,*iE8+"~е~6uY˾vKLtQ4褪U|ZE+J8q98\)s5( {ХnƒQ!.fQs\Adʈ#& ' '8 ^ v]Jb2 pkqpľ dNꋁ=]b bqx*l)[4|SĐIFh. qU:9yV-I!\r'qo&'|i`O0!zs. [MڏQJCrEN,`iS0i[1H|.̵%2/m:'tGdJ?Wp)m^O6- K1 Քg>WV83Yi,"8' 9U :aoF#x,ow۝VH2uweZ622E 3g`o)q3^h2)c B@]#¥oxRbDb_=\/Y]%KIkPY cdSc1ybNd j,di@pSf0*%f\- hsZWWdV4cr(E1 ދm.^ŀYՉN"dMdfcNdQrd2cNa h`3c䕲#3Pbln˿n ο0'5 P9jSUՄ5Cx `A3FhfЬ;J.KSLw0BdtAm͋"#AP,]td]o;Yx2O<! * ibBB@r@2T5A~_#~OI ַ-j-S [A{9bT1Xn{BOV ?p*9KHfJ<79&vv&Q528DQhCg [x [>P8Mɡ} cc~%_v@ĥa$VreϠɤW{@A5?xѿ9:f 9b izdu IDAT du5X l}yX-ߺ|Q@׉M? L\MgmncC@l0!NB' +JMhv5߀hFf8k><ŷ.ޞU_z0RUɎ*(xH^2W33Q  3`6fS iۚRV,䂹Z`wF90 o44:A(xpw_+g7Fƪٮ̗/]NղmmȬ-3]Ѕm'̕-a:Cz0t1tb*_>Ujae*-b^"+8Zd:a0-,a ԃs$p2`5\Ɋwީg^2ռ8p-O"2Wޕ`ab+S=FU' &%L_p$q,7Jbqsry{v٨kG+ybbTs6&3[x?+61V;ʹ 1+Pʥ%Ht+1 5Ɗ@kdQm.o V4BR1/,L#cX ^](ڶ(cPT n*7GP4]OT+$KgxyH kňH bk2R8pV.JJ+`Pdv\Zm@;8 tW Qp ?xk*1>ۘi(:'d8$Q'qTS-8xaQ%;%"[O@ׄivY;Az)1֜3-d]lFz/d%Ϙ ᒬ閹 JRuKg k>iq e2UYR_J:m7m2dЪ=!bf}ͯw {{bk}H(N )uy+5`wE 421[``8| oOJ 7+ CYˏbU)iA!HT|̌[e'bc@MA"6D-@ #3zoS޼˃L% VHY@ Safh \;E4'XX JCmݼ hm- B@ |ŽkrUn;y'H30RGVzt7&H'N/cn^QxZKԃdǾ޶d@kk/{`M'ǥJ PB5d'<"\8^Ge ļb%6Φ#Mn[@ׁSM#LyM)?F~ŸIa$LZyR6@pc̈1b#;+Se@FYW $Osʤ]3F 扙X T/"h:@+c {v C)@T˵'2PaUA;8_߼)ݎ:tLfŷݢvaRo 2{ѝL rŦ85蓯]7}nbO@H+X+(k"q!unkTOu 57 @0,%CFx>XA41"-Is\T\ ұL z7K7$*4x#K>"BT`"$_׀j|bRLRtoǟ];[mbs}qZ,S9 D W^C(hE*}޾1' ~R-\ 6-S:j;Ptp7qvp @Lm̚d#֫ZFD ZDb7{W“`..ob|; FeB93y/(y Cdce EE*@Us PfnXeL.!CC 6*(nk%!+I  6nGb@W˞X]1ig0+yed#\xjAE%mu7XWmE!7HTT-d `߀6+ZɤC7|or{bUנ H)pmGpHUeu((yvRñd cvdmS a!2K0^RmzRCHW^11HfFK'ÏF|ix4 Y ~xkx]?9ɒ\W@oy?6ZWYKڴ(ڵ1*b`ԍ:J#2bH'_e*lvwgֳCN:?p.J-ֽ-JvJK*oޞ m%0U|/3? F]iPNc]3OlzHX،S\Zp)k+!]bWj4OmĐ6$ M&2ZjaFe!` pM\y|Wtr4S`_2UPp*גZUil% EfOU3X5|LUXR&PjOz{↱ Yޟ=VVҗyZv sz 悎{PY1"t]b8FN)Fp 6 0@RۊbD/ߌ ||GSԖ99Vp* X,KN[2%R12=IV ` Dqv6(2;!cxN4 ޣKjn3$#yeA@yWJS+֜nst gRuR,8vhc#v537K4Q ѺR?嗂Έ-J*JIYT0 ijS,Zt.K@elS6 PsF޾1FĨqrtjeh&Vp"L,qgUKY#/Dܓ1?mXR}+XLM G|Uyb9U1k^P^Q4 /WʺQ_IXl<FzT;o~J5(ː)"5XFr[}B.@GD!XxԨ5+-JN|ePa%-Sk:k4Smʜ{ĐeNg(H  C4 x﷠%@(Y+i: hCW$=u\RO75J.Rp?#~mUuYŘ٫EJ`n@9'oރgEڡm gVDxf`8ʳT-&G8;!M5T5b5;N*OnH5:#]:B&"𧟼jqA#{d Q 2!B%$^lm O4)IZR9Iwނ}W\=4-dg}MR(N1lE,4^.N+*@UWA$ Q,bNUA-h"W/6~0y/tP_C׶h|Kw~ x+qmKWjd\e5 6!8=FM*HN5*Bc ` \h8eel5$@ۀ\!D &.YARV|Zvߔ,w¼ , Ә& ԯjZUR\ga3tFU>•,d-잆bqb$7#"bT@ĘTi)d.Yٕar@S$qiKH % l%cb`bU-7e1%+[ LpS8LdW.x* AhE/y)xr{FAY+^@ fgoYYá+YD QΩqK,LQT<X"+cd, 8v~M,CHh;O&m. Zʐ;"p9̀ jB $7x,1X J{cbB(L}cx(oլdLث ͰOg9`5+-d_nIPǤ((< uOLw32]3#(JJ8Bq*\#70>SO}bzQ{N<_Cc ocJ1RyS}[\V=ByVvX+٦,N dnGnƑ}[dȲ.u3C!֪@+U'PD{'hE]}\R`cqCؘ<.lT88\m4p!ԃ:ZVUi@E$w2×~>% SiI|M?[1cvU9V 2AhgC0oV1 +&Boe$u؈m )A2!%;D7#*bb{WĪl x\| <݇t A~t& M n:CPd{+SB]B$ i,F`5_3rgK8_Y%(@UJ1-iJsg Xj0 @!j(#"&&FKeGX{?:Z!@=Rj$_i}|"=&ae/axhX}{KZ.D@֗{7ݒUbUY6 Hj6wvGe/b4/ . &Wܨ}y1q6ChK \!`]qN?up8 'r#]X>*EcʥXm+OL1UEDВb_Tn̦*٘+NUW\p_*eN#(B'03Q>aEZrF+0;ljT+=L>]߾_'R(D5+9تsR!EsoV6X+ٵ h^>r-\g PCPyVNĆJ Sp[HaG]'A#u )0gPOx \ t1y!^{3~~G/;vn2x3udYl$}*Y,SZrelQl{vKNz[ۺL[`cw"h?OsV`_-h9Wf>"$R5!C]hyHD^&* uQQ5g"}7\I{RC5.}ALObiwgT %U>•R,,faZ%ҊulR)J۳^zE.z˒jP^0 ca q:Mv8^.`(<u?u:p `c5jp}rT'K<a)"3 Ul@ivy*"g`j>keCfpѵ%_=^{b-j'\WA%Eox0[D]fr\Gڑ|\7Zp 6sTa"t׍St/mIE~iRq[s^u2;hdWUX,5#o%ٛ$Vu;LmJ[IR xkpL5'cеT³0U]+d8!NE-1t1"L%,U~8o<8<{p]r^1FD =V L VYg<-> ,"ح X?pSLv5K62pyEpg%X^lv[ Qfy׶#3ʬXH}׌>jɤ9ObޘqV=GLNCԘ*ܳV݄ C^ՠ٬wu!dR{ظD̠xQ1lA=q}c뾉/D=8;wv IgIFΘY69@ {mC@u(< 5ϱZQM`Oo>@Z}cXOLU (m c210Pa ^C7fI m 8'XF*٫kͷM ?pZ]1-S3%=~go<{/|Eh5YC-.bg5Y/2[085WmbseWfZS)[Xu` U7'?iP"ˁ/Tg KC{ Uo^~*}miIm]ϦV=`Ds?+YN[lB0>ȑqcQP,d4"Se;vb v"TJ?KBB|Q31ptՒ'`QZ_zQ*":1=:™[Wz٫*%m+Vq 6M IARr%`5 f !p׍=37d|fp}HX.G>Lm]N4Ss:*9u -MXWfA#bF|T1ws{p!(FftZdZGvɽ623t@1TofsI x'^+;l6(0?fbH r Hyg YNA25dl`:ĸ {_bIU:ūn[8eyL`8,TwJ22#EV+\= &b$9_Yz~m7pR6+kҲ V vP×+ \s<$F(n>?Z8Qyd%J){m|(ޑ*D%`6J)Hz:[*T^c|"ParҦ.32_@t>fٶW+"PU!$~(fU~<]wy 1_~Ej}ZU<2*&sY'^ \ "L@$7P`Fh/}?WX*AU|yI kN  1+si3^@TWcҹ${`ͦyp%gI|֌\>6alb ljP>/%&3g! 5* RA]wAgĀ@4x2"ptD9XA22n !{,WjD@+U։bG8ĽN˞XW Jβ/Yn)Շ&[5ru_H2A8xd<g]-o}νwo) "DJ*I|IVHd[ReW,G%;NRJ*qŕ˖%EQyqW9%Q% |")B E u={kw9w`^S=>쯿o} $@H| [wyEZ+@RS,ʈB\_Ȩ-|V@U&[.yW#GPS{z ƈC~5N=j*˿@k]>j\µ.d Ѯ{DYKPo$~O-|q4 udBsDAZN#eTofz?q\ [jr FtE_9M({_q:N]smϿ:'G ITzAý;p!Hu%QB ȬUh  X2Ww9w 5ӪX{e;f[ŌK5 uӫ㈳m\xU1ʟ?YP K<,uWt40ٙoueǙ!b9s+Ef/%`ISjr yl35/E,OvmGX3<@~ `|]G>Zu' ?BxI- 4@}p$ Bgg6N`V4wjЀBQ›g_,Ld@Uڛh]&Qa{9Pu]CEn8 @ZRf/ kdՈ:s*pC\N 8sdWzAjZ4R! MP~[_~<}J&Fs4l!+hbϠ,%M/8II5Ņo{ PM5ǟͻwdF,F2_{Ǡ=lx~frGÿs=ff1݀*P[mv4f́fhŌA]=KWgCuֲ=+gmDĦɩI Aί N*`׿zp wXbp6KIIsĐ.Af)%H׃&v>( B1g1Mpɛ:!5/ MpLD|V>#o `q8WwH:b6>]Ùٍ,tʚ>Ys)-j4*[٬!|);q$cA0 U-Oh[Hh6 1@ Rźr(:87dP>ڶ0 +JIͫAY}wˉؽP_d0j;O~„dE $MHFBeHFl 2v,lh)`FFI~ +O݊r௱f{2,ʟt h).8M/ISLq1dΝLݣh#&+/S"=\5S1@҇|G 1+(d`6bb-צ̕j74@7{&u7+x ^"{X~}=Ag!A8wjkZ&vjQ",?+CHIz1Xu~@fzH̕Jz(s0+5=܇ B @lTTȈTpl׵fifkfZ۾S\^q`> olXo04VA٥yт}tu0d (\9]>EʟhM-hf835Wnq-Pqɜ1qJNր,WM`HYpXX.LJYMkZq}6 ǬqUL|W]zcU lcH"ٔRTH,H T$}^U^ӄ=-bhFN2~:?؀2-dY7<2Q9[O\+5:1pEJXt1#bf@| ;rt޳MD?^sãӷCy]+Yp38 RXt\hUlš1b=i%EzvYd?*6WމR30{f,shOM\5X-irzVU ZkW;ݺ5W/ַ|Zˊ@S)x#+qkLH'Y'ĖwJ4$Հ*Spf}/4LԻmRpjiA%;>z }+p8SҶԀZcA% su` N0n \)u= X_Xl|~9.ζef+pS~`PW v.V 48rAp& ! aLNҾS,6_j˒D JA`S.|!;90 IDATlaL8+(0iQ,\e&2!5!>?w SRjȏFO \y=[{>8XrX>E uب]J/}))+flM [ʼUK`߁> eH25^W+:9KzWx%0;|ۘ< 8$-->7 Z@YW n/Xկy-iO4E&2'q˯`0 ecϬ,J c654gz u' V _LRbg{^qٖј,hHd|A zjHB≔9U#b@{y^MJ{. XoTGlbCHS).r䑅!yPY( gdu?~(`zATOȉH)O`uZPexk)DEPURz@$.2Vp5%`RX9G!kO0kl jL'絥\wm#(|: WXz-  v oSC taZ@w9K?pRYmAح'YbR 9r.rf`SX* R*-c@@ӅB$%K2xO@bG8}À/=sLq`e:i}&k'l4p@NԇmV> vCL,=TX1c58 8(o?؀{'ڤi;~*|^p_ho}2c3lHX5A2r@e)9"Vwth*_->CG Lv0  YnK'E}'8SQ= X5fV~(h*3T{D&$H|,>%%*%}&C2~B(ф ǁFi$5 MsY榧+drݳ}[5Ec( L`&L$fz NY+&@8غCy>K<ƌ*T(jƕy'D-68 o;q֩}eqX澞DԴLE腐 ,FV.H%rj0Y6,;(v4k?//K}i'5Vmygf*58|t%D5 0Eq4!w!1@+{e >JQphHd;>U^=rbeMSh,?zSJyhleZ{jó}+>Ylޫ(=S-hgssSl,û+ a 2d@LY'2ཏZ,KM4>ž0z gd:aXw 28٫U?,)`{HJ: 194ߛ6WV#sa!.:`i=BAlN,b^: Pʼ\/-Ỷ !R+,`b-zr)A@؀w*!+U~bZiGҩIeAxo9/\cyU{C&4UP@nɵZ%ЫQTݫe;%bFJ>~ @ŢX vN&Wv0c&$Q^YK)gBh%ִnbM4X̜|3i&C%Ay=YSz+Lq@RS5~\pUfn]gl޺e Z+e@v&Nt@ bQ'*YHe+-n,rHp <|n'4gM,re@xwe2FtՈ2ophƖs*R(0Ġڙ*Q~_~Jq <@hVE2VY+X) ' ND2DuL>@BoSѳdpROqq5XN <# PpN(UO(24ryʞ "dz!"Y? "&tWB ExA )̹27AppWw$7nG=?{6Y}Nᵩ@]ui*2+O*c@LJשdc_z_`Vc"~w{RSpA9YLԬDPKhND{2ReQ_|+1LUQiEb &).( 0ք%@mנ_Q& X_3=bZqDjW!0"wþ `t& Xq KY:7`_SXv߼[5`7Qm:*SeX?C`U1Vy'cUvp2Ź{&EᤓQDKS(kdƳ^4q;$JO[}JA/1gJFsmZXWt[}VRN!CDA|s 1ltK#rp¼bz6UWRY\x;SR6bpcc\wXAk>˺~A5gXDRm @l1{ p9 |Rh%ŃUa7A/}gf@VSa|T Qƃʢ: cZ i2:Ԓ~ Oy}`- [X `ESqc2SHG rCQ7i Kb0 &LE#A"iٟUԞ.̶Jl+4KNKRbf7l5uZwHo.>slf+ (=]"֩rQeS]TWNZ7Z>: 5]56YM!Dҫ,~ sSZ $ y L% δzC\ j;ZRT#un^_w^鸞u{hQjoR;s6.\zQ:/BE. 4u+y{,b)oc"*#uT%yP%)}Yb |"baXRYZքzV֪K09. ԶZ"Joc06 LjƁXE/$ȹ~9Sg1A7Q C NH"[k1ۜby  WzZկFeJ?UT뀈rK`փB@W&}Nʽ8MqNAxL'VGwYh5zƫO2;={ M8cޔEceWXZv::0$bd)lKP"bv ХaSDz>W xϾB^F$z\Jc@u:Ⱦᢆ&\`mXVkBӱK5f+|=&piDOWZ |VZ5G޹>2JY)Z ܕ}#[@ 4^7`$?X>}q+2;*<>*J{O# >B68M3^ha貼-!wi#*g.h P lyWGDD4 0|E1V6zثjjG*u3ROvVGI}b !>- 2hb5iA#w=F5xU:.K+6Wd*FaV,̔p6~LV St7\ؽkۦn*ʮ=ux l[a,&й}׎g k6|>zJmGp="uFZ# *Ta}W3X޻ UP<+g2QkGkeB*ዏ*\w,\I+Hv'Sm/_s4uOQrl|aఀ؋{{f\r1,}hۈvG&8%*S\*qG?{_j(4^ ' }(!~\P6zZ8-YJ@N@d %Y`:bĈw/H81'NE<Av_ Wm7/y$[=^ߴ@2"u/^2 )XхAO"AKIiZ &K fP埛:$V'?.v/7 ^P@*9Y 3YBo Lt6&\\˚i=/4r/ 27W^L @dlnM# =B$41W.( {ebf"u/;ZÆ.z`L J@ ҅\EJU@E-3P\bĨV%RׁwH))ku8yj6p7yr>+~W<,[ Z@R;YdUF 06&==9*sLV3.=dW,O/OHT,={J>t_7guBL$Ԁ7(0Ҿ#so92mW7ȄU`Ӵ=|ǙNtrmlƿě><[A=یɲ}fv? } %bZЯ ,vX&b5r"E^]1, `H`'puޅ!X,g6j&grPS՚3<]#x]GeݮHfaDswzZ,óFDZ 32+2V^A'DuÏE5 XuCWn 1{ /k7tKi;r~/Wwo J]I5a EG҅M6mWK7.joAws΢tߡӈxȎ#Qqy?2ùH;ufc1JI3I)[{b䩷}!)}3|F{%I.3%²',;²i"_,`+KƝҠENX< +5zC`U+QKĒSIɯI,w`>u6-u4J| OVЄ`~sÃtR3(;:jlpvAwƈefV /TTK<& Fts2s.X- ݣWu6O>̝-BlHMDJHa A(3 š̃w C c*|G"DjpŞss#Dd mm ^@䴦Uهy(bCJ-ݨ]ŷ'{/m2܏V4@ߡ@!8[z#xº)chMWSGM,Y5ǻúԠeabp}ߔ^< ^ZN[|tˤ 03s3}^uDU W4u壿=Vgm d4 b! ;D}R@dE(.nO,S/EX^!,R@m;$}SiΘJ7Tl cX*PS.?d f 2% PtYhhMuG UoT]W8[]îT+|W Doѕ@ ϶r'G$]wtY~g*-qoHagZUpA<%0O2!&rQA^dW(>ܜG#/3 ~Z\jAE^Pm T%2;2Ƽ4 @ĿP3 CJ}f"ņ$8<6#o=xh+|]Ӄ} X>U ZPHfI؀6x+`EE@:L<[j+CNV6ŽdGT">MxY;FXJ3˝e偠/WP,PaHK@/߈o?#DB4[ `YĈD"|cUZl~'vvrJgVWP3Z,⪳988S{r:2Qi0Y&Tz.lWPLX, +/ pϒX!4 ϟ(@}@N}-c@AVֱW 5XX$*VG+ŕ b_f,_ĵ?s k. pmxzf]~&[)U&l̬(2bzxp AVD &a qA;H;>,&hO2"+# 4?[_<ݯX1"yT@ 6Wy<Ŝ`#-iE{`4}LJԓH|eȌT@G_n!=cwCc=7P3%u2vZHhhR 6^X^,Q5rENUh #s?+O^™Slcp-zlJYvuo'aF1vP!,N<}nEF{t|,krN `8Z6?wIY߲n}!,!SӹձJ>+idXtQ @#p߻8K OZ5j [DZ8'1`hUǝ6)! dSE R bE}E/)\bPˌ#fpx?mד! ^wnʺ3</3SjJk@~2k2us7\bzཬbX˥޳Yĩ}0/A-('p5Bjdvd ʌ@W?P^3N ;[r1rf{sSfmD.EO("-%H|3hP-GQa9؈\FꕈiTب3,!Q +xf>5C #b DY 1'7k-ت/C!hp:4]lslpd*zKלcO?Hvw80YX3HAO0\겲Ă'H,]'Ag^X],:`g>񮒥QQ=WFZTSE_ s#-dBLQ8+UOVQ(mr_ _%ͪHZsLwutt^lx/d7x,LzejLWY#@G8 \o BrU5-QiƬ=?}qnOlS jxg$|AbL AA9C{k4~CVCv,ن UiMW *+Z*PVAK3P%vOZߩ*  KG[6 h)BE: s%*V(>˰j1~JL.WU_굽c/TI6&eX. 2*"6;8clަ kPđDyEE57+i[>v5AAblX-e޵>sp[]YtWω\Xo߄(d1mWU|D!$$L){UW'- Vi Lq-@K*Ϫ3nɯ2O\T4GGoZ" CC$I@CJXt+Ba>&FR"3_b%%Q 3Q[xJ'H l_D`1}SI8&eљrGբirWSS7vG6_DiP9Lv3H/4ܵhx?Os*^V4S73WRCDl+[< ۏ8>3g U2@U;fSF'9#_@[C%t5"+dN뗒Uzzp!H8%PYt@X.%o;꾣.}hLqN/V[Jԩ%2w⥉FCXMOs%+VAJKuSQ)niAO :},YyX괠^18 1&qPPMs]8`*_Ń}Aټ $rY+"A#REV X rVs"\L=&UELhg,fFRͭVSxQQ C;r(c /\~0&%82GaA; ׹FUI @ !>Dej@DeY5֮J5aQPK$+Ҝv6- 4W{!m:*A?a}Uouz-&Czsb4v2%jFZdx?6} ~\uaKڼo4hb*L-Tull6UpdX7y:fk%'y!w}JBjRq|1t\0J2Q嬕2'R1DyMb B@{v&>?5Ou 0T.H7G62pҁ`@V'X[ frsKbv/ƍ&ʑoPKP`e"gx 4K Tyh2slߙA `U-66m%Tpc#ROu u^VU3ooP(*C2]D)?g<ց+}[I, @A &*j`>X.3V\ѣ3,=jӁ P3WyBzsq pX )!>"hk<0]W2 L6otץEƥ8p`nÝ%Bz̳!gvHf8 kYT#17lC0 :aD_5 ZE@Yg9 ަX=-I'йhwS_>Kjaϕ+G `iڶ8]zϫ~%oM0k#:{Gt8c`skWS\ؼ ,!0 W1-~igig'rӃ)X\gdr=@m2`6Rb664mdpҠj.P\*ny`d7FEY052\!<%|wDO|n=uskO!k*bN33|jg gű4!JgEGI 1W)eeHk´WTَ!ਣeqiGwJ"@J`Gb eq ّD-! b){6AԩE>).tL VnkF1VS\ؼγ`yX6\; TZ|(T$dX7~˙JG QG 6>5i̾A M_4WK;P5dƟ=ȣnemU*iľJ Jcq򑃦SBWn("7kYW|+`҈CW(irl?1*<Ͷ_gCg Rpu)tD׀ g>3j[G[{K!@6)F98ow `LY~㑕4(by]]2@HH;;vw(J }R,fI8Wⷛc@Yކ10&.8F sNmlۗ#aylq9N?).zЃ2pZ` e0oe:߉k?ZkUj$ʩñ7V%tofPwA99Ř|b XU6c@ R Z4ulf5:P@զ2s t#,30 B~Uv+&(s:| a{q`cbFAVF\qDNS## 7a vd }HF SU`5_Ř`ӄ3cbGnGC]ÀNyd¾f{`],;:0^5W),RS-/$ dlf'e̺VH+s?Ы"DBJ<= (!igW^#bEY^5hǴW:~TT35w^aˤg~nX:V,-ub2sE$'ZLwp*~WC=V֪]ҩO,c9sr"bZ}gs0%_+|+4->涴/Ki7òkW4a-^m~rb%m{i+Rpu4 e}UL$#2{1[5Zzkث2 !`[M"j/dP%x XX:hR'` K6!~1PiTwA]ɐ$者 (Z% !e0UΪ5n BZ.'k%E4W]3X,B Cp4܍kJ0[JU_9Xt)B?qc"I S4 +w;O~Q qYр3x5ɱUHS T+8{;V^P@2oo)?91HԱ],I*KdE 7;At^D/ W_ E‰cv,SLq gb7Vd2Gٳ9i p V׶Y,3^Zud\g:G:-XBB s p%$W"l$#@SA҃RCy RIj?J)#u5*/vVpd7`F81Q$*)E#k6A\8>).ؼj-BoZ9 ء4Bvx[v @IZXBSdCJ i@PEA2zdUTu*\tsIUAҞYCTf +zXi+ :Lbc(k0132L)E "0XW] "ҋ=0f㙞\] @Zo.Z–IUrӉ(>PqJHH ᥋e]4 iz+#eG_ _p*Y*F(N9( m3.R{&rS;y{d_ ] Hu MAS !V, ٳT +F2[)58Fa, kDn )81Y8{uxɣ2 7#-r IDAT*߂>!M$!gT2dp%I'tܶP-bRil _X=Mt!x=Ϯ m{߀LЦ;clea KXdc-+I HV1=`"+fUf2JtKr!GR \cU1nWS\ +G}^7O!f t+q5b qz H̩M n#feiU{Dm]`Z.}Qu͟}|GNӊR|֊֍̫ xU0I^E+iAR Ȣ‬b@*  s|QMv>b`"8> ۧbXpAX2xk7Ѵ}8:1WS\N!X*eU@U捺( Bއ)H։(Ї fYFPP֪ǘ}DW{{Yފ@r5DA3(CgRrVЭ,P>KJ7W jKHG ziêO(+:qb }rPS싘(4\s&6 %v?).ؼε yz*+`jeWo<%TBD)%TP6-KS23#{O!ă8)Lթ`Uܐ+JגJI lSBWY& ;f \d)`ӃPvqcptKLX `1B5mb6H=賻ⲌUBF7'V.GQ{& {'I;=%#"ںz ia+9Ù!hb1I$#L#edylDq63>H6IfY  @轻kɬ#cw{pYUkEGGde|;{H^ڟ5cLj֚s~,W|Z9G+Y:'|l҂Pʾu{(waQE~%&E$}(+gLRZqe Q*im*g F#+z I؋Q Q('G3G)T h,#}doK1;c91h6&6{fqc(6Yܭ~4DLYq9}. k !I~ f87;n!>Qq|J+WDJ?g'ֿI ZkjA>i[V`&P8Ǻ~?@GIhx;_/{4%>-X+fkڨTʷ %R(-h||PFRVY8-<:Qq+!+vaD` $0$kQ06"W!Y_t|x+ȶ]*_IDY!7=9+Z!' (mS;P cgN88Uk U-$5wk]f5Pv~ [%󝦭Zahr\pe]:cWk| ?DbmW-1\c1V,_$ 39=a{GOV;cn D`$ y%\joE\ 4a_Y6R̸='|eVxا\*])寍V\%89QƊAWR$aŞ;֙sU\(V7rA 5S*ҽl(W uuSb8yAdw,T0% ]hΕ%KD`à9WJ@ĕp|uȚ%x[z_+B Wr]\C&ωktaw7G6Sk hm@WĴ>\|_y$q e L Dz,$QY]S'K\4e)Ij*f7Bz ? PP RM̷0b-J0ċ ȉJ'xɃ6\: Pfe҆(D`<4fzcX\!R03-x[*൯~#Nuw3O)X3mr`lgml|?@Q+βaN`2P,=7'$A$pYUaطs?ccMbrk1B@yț{?J[q\b? q:![!YLb*CHb/V D/vȰD` çx2 ^ʻ1oJAй |(ѹ' `@V]ڿѹƚ7K#Y eÉ ?dyf2&c ,cwI`$(n?(I)ȉ{r.vşq ܦ=V&V` FX:>dN:HcۋN/.*Ѱ۬*s&O=XPT!hOO'"M\m0M U7hv*1S+ 3jHZsQ|x>X 1 c›M$g}Ǿ5c2 BP|z2I$Ѽ!r ^߶nL/u8c<>~w=].qY{Ya"3$([Rğ 1 kY'^mm .X3pGXo1[C+HEV5)g>۲ޢi10>?uV̄w A~Sĸ+s#g㟀D@A 5 H͠H4,mۄB 0LE~;Qҟٴδb?\AvGb4$Wq|iB )Zql_ zTlhO _6Ekmb{"uT/6R~+ SQ5Kte-Cʖfl+wt[2i+m̡= 6qj<@ڪLdB0BIq"UZkhå,e/uLjKx;#LxU`xpOEL,2 W`g R."̆-l T.9na@d^Bi xIXzy!=q%r:|nJ`*'ۛXN۳ĕ{W2yZŐ_M=˯d}h7 z4B2sk03AXz.`s{ h_ʽq{o6nmC32ޏy̤&I8&|S=_aЏ0C88Rh؇uHJW!z+E6.MW8 mBʴ }p*!BgC?  i&;$Ow>Uv^P A5 TR@bhRnF"@¿ ͹- ߎ?F ce|ʉp)L]h dE:Vܵ!փt~ 6lr6RP*`gkt/mD`C4IP, |_U,,X'=ۖۢa ^Wm'ζB{څۃ"*oBfrV\MçUṫ"bض /+ (@10A! X(&@`Ȱ1/~ (|` ΙsPąR-G C닲=9 mW![ʽI=X> dY([\#%F!1 Q}GHS5c؈ڇ~3j)rnw,S`h/h;Ce8;q`f<7#|>A]̹W&}6[WrBTB@CU FHu HiE J)b_x/ʍz `8,459iRw 5twbARGwLWڲmqbhiuCDۅ'C<ͽ\ x&q%OKgX_/_g&2'ߢ;cJ/33o)\e 0I$q/[ܽ^pJAZ)J:TtN/( e+J_| 4h_|_'jЏ'3gW3J. ؇5rޫio˺+1\% $@Q?/* s%ᣟ 3 >$ͽX tzl7 i,~ k_BpdXa8vA{#wr+mWV9+K?LB'` V -wUɯ"t kaU*PgSKHC>8Vd; UC OTQKHĕ _Y>v|30̌ H=6&[SrBz"Α/d7q?D1P l*SrdۘD'E+V:`p'wMi(PC گ~ {%oC` AۋӘh.6=[r>(hU\=NubZ+\ect$A>hfxPab" 6'pp>%T0'~0*ܩiu@oXw ެ8Ft:ܩܺ'(0A<+)R :kg!҇ o `+Y,«GlP TQ'~H{{/>)-Zcw~&L@b6-qNWks/VA7%]x:D`CJ0{‚PsQW ¡Q ֬V*>} EZ\+r.F ,ܹݾ 4A@ڋ E:/HDɈe@6S u"m[l+ZF XXe?Y{B/}L/AJSS9-Yqu \ ! q†NN\+Pa2IctKփra4&Jr~_eZN֞Mes%H{0a×8L0SZ˩fR9ܞez"#h9x/}}>D*2?˶5yVIjZOn UkBXVU kҕ1?|‚pa^N mQYDx+s6NkWdyQ" |_\?͢+'sSgkk'q${ m_"`>*2-?u &x<f-CH}Z(,rt &c1 ORBaQa2ND\ ,0]IHV>ʅ3}s_/}CSJ|{jjwtٌI\JJ>YhߕH͏\%XDCd`==E31e/);">}JMW=څVPP}]W!!!DQTDq'}Zpo04EV*_y~w-('SL"h0lifݿ'Vp Ęm%Zcl85[* G[(y_,H!I0l4`Kz} `{0k Hpz·lrwWV)r="knm_ǿ-2`hr/t/v o |8Uz yUʭsrh_)uۙp¬V^@yPHŶ_K+J>__y!~q;5>_ncroF/@Cc@P SPؘZ ?UsDQ1J"<{]1 G:jjzaQV/Vq[RYΠMj%jgJ.mz;@-҃qSB˸d*ӌ2u9P^ds F2=W)U2-BKPTDW 4W$\<(7'FRh_ Ҝ+R-@'F"w#A" 6 ,*JE(Xc8H[ =\JwYѕۖ~x U+_4r[A'dTAYn,Z﮽޲*I0 ! X` b4`P8T( !imqf=C i G' 4vF9UNlE Obrb+zF~+ Ӣk}O \Sm[NpiZ\!H('ʈ*`JP]H׊ۂ*(T@PPTh){sNR`d[t³1& V49?Pa8#vhu{{6ŗTjE!*Urxc4۝`˸#\@'L Ah[!P2 gLcʊK~6py|_Kձz%"8x`{sWjVp+:`01DɳU~+ gzUpAvŋx?k_] -YߕK> _)U3E}RU5^PLr0`e !@_" `L! ):h(krXX9Ϭp:B6ѵ%JZZBA(ްFWH[g+ F}4Ϟx>ŋ_7!;rǶ xp V|*e>ʮ(mml4"/|ʉ*WrRUr*N79T Fttj~\:@ΪjRcT#F1(*M/C!(#v(/K.~&4/5# wy|v2X#dZ[Nx#t&! &/H)`s -hĜEo>/K#5|o|┱T&G Emnq+F[%4[lX5Lj")i A HT&Y+U=.9k7>=S2\R6} CٝjBʖMO7rOtR Bt⊯|1pnVZC5}|nu0G %"N zG\v/& A#m#*rXy\+$ƀ { Hk(u92c V|KVc 舯 @Ƥ-¤?K;:.\nGINX?(_o8s,̭0FwW%CIx6mhm.\Ϝ~kfUBʮ0 (U!/4DMVLhNXKi{A]V` -c+Wp TLq;Nٽ.\ $Vz'}:9E9dЏ0Gxj2ʕj I vcv%Oxvx4M,X3"*H;}H&uf [kVj3-CFKF[EQZ#mFB't"`ۅC9'$؞$b|YBɭ el@_3B'Fys{]7Xds[{ۇ^\9pd]v`cEҬi(BK+_"@ؖ2+NLP0 ]eĶ8kAfWQS:Eprv펱]okq(`|4I&ьaf0i2x{f,D #e^DȰ"MPdX䅕z&4KE lCJ-2pOԀxU.=1 EXhuRNX¾1FCZ/bUBޭ*H~o关_YH`qAjXiAf+3O@~tNz\6(m-_Vܜe/Ğ3&CUAb 5W oǭHTVXL($m&}_6*pD%ZzJlΕМ+lgŖ关@ػj]--tŞ{GS#;އ+ Xxkr' 1d@gĕaF' RFk+рic3;AZ 8}1 ',5zFzsj"+N`a6B;AwGʏeD3Ͱ7!/~)ݢ5lB(r}ƶ Ɋ(ξ҆Xz4ľD5E1X( H]|D̕+D1:-IFL" …K|~"ӂ,ᩉ& 7s<1WFڝ ڝ ߟ`gk) Y -'>:Af?3n/3{\P.2U,\CYAe/N+% 0,|PY@|vWq3s;dr:-_rvCN8=Θ}FZsij"j"d`wMbN_Y8m=w{-η2dӶT&]g,nF7$J _J`4+w!YZ7!hQ9`SkS϶A?#V/=_PAp8A@JTPP,_ba8vwXluGbNL5K6C d|*<ߤ#3dst44J3|[6ޟW8 %2"^Wؖ"KeWʶ=?kr?\̹}ROco<>"c#ILZhlP,hM vFQ^8~f,;ЭrM 6~bze ۅ}NBinVp.UlERZqL`Bm5Kwb-nۃiD[=ON՞R-`2IrOW"D}S/X +vQ,5XkQPrVht]uK %s 2OaS.T#ئe|1Z ABB"U.h{X#Krܚsж*g56dޓ-~OE._mYW,0$l F*y85v'Q^8r ̬)Vt02޹ʼn-i<.yxPB+AQC>˅[A0:LvL94@l^煳$X);AJzVJz3`2nxfgV|%*b-`U Bك , B_rɰX ,nW\B`фD5xߨX3^ΚD` gg_`"ڝ j 6/,װxawg1䔸p3ϴȚb*: dV^Qǰm@sHl|BV`,x3"K)W.[rN x!`c@'UV~8 %1Ġ 6ϵ(̵ʘkq0Ddp gWƭ8aE^JY8ag[ j2*e̵x[Cv(//Gjήd|ETe.#cXL+J`}\\beŘM"wMeҚ; a||҅ؾzrU4AxD` W(hTPoNc-n9q&of7~W rX쾿 X& a!=.Zc S+, ȂLJZb"hB-hr P'{/O,A0'X`cmXAYB`~y;ם=7&wv,lȐ!AWɚ(u1 U-x04H2WR\Ô"' it+w RB(~8gYTGWNt3ĕ97++'}*XpJ#+(4J,Tјc|V%6oŭI L(jpk!rx 5+e~!{m_ЇIpUjr?Jjks[8ܩ|{; KN%qX\ VlJXX92bsHZ*Vۭt.I_يN:ye6> /χ n gQ8*>~- щ,A8/R)@kVF_>(tԩa|5j|m›/}@&$ \jj= ܻq:4JhW+ hJG?}ywWXpasќ+TP.W1[Cl1 ,[t%/\xO.gyG\y7 ~X_l|;DT'o^w޾ I +,A8$[Ū _i}[ U\A/Bwg51ʟW~ ґ:%jL΅ *!+.簲Ýӝ&KQXcmuU.7JVbq 5@w{xiq~DKq?ѫϳ}{c(A@|#W>G"K ݝ%V*hWjlsbtwX-W{FOC؞xc{oK,h>~XﭞXpb]o_X17(^YnB'qjµ8blͫC;'}*F s,,Vј+VtB/ߛխ~org~o04tLበW( &X{hM|o~O%BA/6/TjȪՋՋx8cAbRr+ ĵR9ĵZ0W0,r W,ABk4[e,,Vlq+U̓7(6H4>Mrr'g9,ֵZ>ۣC9lҨԪF6,ALw{):lk/0c@~YG:&'+NUx{ OB~.㳙'K'bVkφQ~G_E-78j^\z脳8:"A8sl5ly՞`1ʿx%?Kd!J/qsNXX',A4Qvq7coWTE\c3ijXʯ,$c\dwx6[pD` L+ ycF5̵˨7hhu[+}vώQH!:h\ ۝`^OgX 7>T<-^|eUYC  9F|Kkhwh4Kh4K({8Qޭ,|Va8c+ t+&o@ba?D` F4-.Y+ \FzQW<ݷd < X >Vxk7KhwXTGYB{|@jX̬n9U~ZRK7D %puup(r͡o=0-X,QA8cđε[j1ʏzv(1X/[3,AsnwFXPW| 5T\}ϷCT*O}A 9$4` K(_-`B{vWAQnR-p+rp綴q% " x)P'}  "AAX  ,AACF  !#KA% pȈAA8dD`  2"AAX  ,AACJe֜IENDB`v_sim-3.8.0/tests/exports/planes-3.7.png000066400000000000000000004411021370110300500177720ustar00rootroot00000000000000PNG  IHDRXXfsBIT|d IDATxY,y;'3k}o/Ν; 0T"H~ppvлa MAY/ SVH \$JDH"$$@΂`0]޾ݷ{Urp2Qd[憎_7  -CuAA."AAZ,AA#KAňAAh1"AAZ,AA#KAňAAh1n|}$! pyKAňAAh1MA."S~"<9PYwSKƩy8 Wզqu@9POk?!V%Bk81U/RcDl RVz:^.h Vh8(ՠCPV_?SrU/hӗR(+Qج|x.(/9fP(qѐػc/!1^[ٝ &7rR8CP Iww7tuuV,f W+"br9(C[tA@]w݉p)hK %" ϓ蠽ޑFFGGD G +b"Аo#脎vxCP(|,A%+ǡA{g'v=={{!W*A@'֝O pH+p* !  h B. X Aa Ҫ{kiӽQ?};6_|/ˍOZDAPYq)0""rPꀝ.k![Nz4sxsbF6<!Pr|D)h}OQ|}zA#q  ?RGYXWޱ4 ^l~#0}{ .'fLUjLӾuagJ%tIkEV! "WЊa%$,!p J e0c^ű~ Ð(PJJx07P*S!l?l};e)!2 ?J`sSl`6 \hPHUwxH?5+ݗ:k8J.뢗p S(?}JSe ]'ET@ŷKUx.JkcuKPڄ#d3hʼnO!J)1lmma\.S!ETJ%ʕ DQ#(B?0ʕױ5F1r" `{ J)u~ȺPIz{ N\`% [[[ORPAP*PeQB'lzA7⃣#R;8&l6PQ`Vhl:hlVS[[[,tu͍ 2cd~BAIu*\1*;rN)U&|MYl1;D;@@`봒ܛ>KTj"$"+"0$ CbA}vV 2:HZO$wePN mҖOUlU_gQk(D׾G5pzx0b%B6]}}%]Ζ @@iЊ8LJ_hmb}Hm\~" MOaJ+$B!^ p8"Iĕ ǥv~TY%lk+ش>ˁTxLd$(pz` Qdďi"cs7J.c2jlEx Xp V. 4AcquZ !jxX|)e0Z(!G+Dx 4,A8"<Va 61!@Y+v֙'>_^ {#KR˻J3!s(B,]/L:qcS(4D(%E x9 [Qd 2+u_NFx 'R:g񲔔#K$wq=. J%ln!J_I½MxcIl)$(p%Eউr:~ubK+S+~QnAH}! Rpd*]@ՙ j+mŖd/'阄Ǥ~Wva$Ks,AhRPlp\ JDPh]֬rmcV8*D|QZ=_%uxCݍGAi?¡6pL /'󕭟PcWf #%%A85D` BbG.gR _yc?ᕄ}u|/U_b%K@ `iwx8zg˧RD@*9^xDxBZTB+[A K!K .6[muHWDPOmkRعN#C=%,Z+;rRgg[/;5+C8Q^.@:1- $ /AbD` W\Ρ+1AQD+N*IzhG:^ P/f Dx CpV|?`k×'o8 uj}ܮ(v"_ \VD` W/љK'iڬHm+T3e$<ϾI5J,JPlhAzeW cJɇr^x9ꄗ0maW"^p%\jGٝ Uak?n WW"\ωCi\4<5ەqP 3D` bѥ;LhX[+Km+a}TC5{*ZId.5,+zsp\yٺ^/0c`+a|V K4waߏX[)BR'G9v٭ /IIA (eÌT_ ; <" jzz xya{gc|pCA"$«,Yl/8cWQi~W KBpikatD, * /x9x%ˎ[}Aˆ 0~D WX…H[^ X]9. ¥ #R]bەeR Qnо" GW@ǹ#k;loIm+A8ixjry'MwQrQ'gWDD2WD.=:rB.gJ"بwR6޵^Z+Fx)/. pBzW9jsr=xjG&>lJ%R Dx g,\R( E K;lmVκ[ /'I9ǎn]/5ف\LU.vYpBEIK;+ cjENkTc"r97v\O$N:X&O"l-@plD`  wmem%¡9Hx&_p|#QAZU~x:"AGp.?@PXZusA8ܨs(ﹼvW%\ =."3ghȾ^DvANTxlfkp=M.R(XᕏI$«ëWِc("K83mC8pɶL,¹!L" \OW>/:CԄ;rdm$y^2QFp&4l,>ْAd+sҎb,}ADP*«$ K8U.Z(ڹ/}zEp{wx.ڬ^\yeoh~:;ϸǂ aIM«Pt~\qU,H.c׺(Wh~~w}F /c&kK-/oAwŎFg`/?A(MwR%̔EphzMtb2{Ns{ PV:L3t>Z+ ,>"=t[ή38;A t9lnV)dŠB,iG1>Mgw0<]anv#|drwuJ;PlKg&k1f fKK<]^by珿:=tC=v !]wT[R"3>مhٻk>McJ+K>R_R;ap}K,3lmAzg`vqAN6zYwhkPV="d` c`k£T}oL?<`YЪk/tiuv}|u6w`ڻˋ% zNtb Ǔ9+XG+N8DY׹7Z_wpAG[.A8fz;,-Tv#V#D` 58t]=VvxxP ?ō_qkV#F^n>};o.:d`t!ڻA3= ]h"څ,!nGwY{Z:ҾƯÇN4 UBnEG:흞 z&Yq7Sztaz+Aŵn::To?RU,k] ^G2-֞BI>A]XkrɌՅ"|:ʓ?ʓ;v eahA[r ZۻtIXWbt7v ͮd~ X[Y`G*UR:H38= \cOpvdŹG|֛l?esm!zohCQ+0>م~DLC#D`]aG;cypw_q'חkJ$yZ+ڶUMQq!&_J(u֞ 7XYa#^ik9ak{8N`I.D`]A׎鵉KK;<;~\fn~՚Z/PkC*ޑ1=] L2gB*ݽRzoxAΚ?VJF4##CnW>ٛal:sjlCB0StO}<]W4k,,'7fp|:{zxc[>w>\w[G## 6BbF/Cm` e|J/čgxX ZVq SHheQG)W ,>znyKc?,n eF/y >A(ƈ mx`S9vgO/n }n߼J<&248L0=/T(5YYgq.v?Q'x\tAV[WhhKXӶ|Ͻ۫lo.'&Y{ؔJh*GJ<m]0Y{ շi8zzg{,ƯݹT`9uV3 a=G^U]cϛl<]1M?2踸]p |?[>zX7'_p16κ[)=o&m,޾A) ,59x9FedrΞ^FǎYAΜ= A\Ls".L]ڬpU6+gݭ]\g(dν IDATC&o>$_֪X?~dܾzsGS?b&Ksl#צlql|xģ p 3: -S.Gڏs+"l j}n*FM׿P`e9CvL=s l{-Cx/0v?bu =a0 38:4ctb 'GwOVXzBZ)P q>\W!w_aeٛヷ[Y[Yfpl>F'gpl\.A8E g_@{48 9X#rVã+K~$74%kwFh+pRB+˶mNHtŹG,dc M0:5ظ]pBza,/ns"F#ǭ(Vxt*wGikB{GNR^J<ߙk^h`t/U׵U=bq!g||e&whq&r;slmTxݥcω%<7".]L`Z+2FY^x HhAF͜rv%=x[>KċLUd$\͓Gpze;ipl Ff3 aKvy/F,u)]yGgSU0{Lez7/[7KBuCmkVN Fo0nn=bmuGy?ov O065MW_?C&&0_t.#F9_AA]G?\fm#:|~ m>|o$7'4OU]5 Nz䡔x8݄l?܁gxїnO=dme׿2C׬蚚ah}v BP<]ca~0"=}n>?@ڿ:[fſ灾a.3 >`Ove+~r#>j58}g3>Y׿,t X5skt%\l>!\Od>Du焉.?k mlTKln\Dfxn#Sog0qM#OԎ}9N1fqWAۗl{wO2wOWxp%' vY.{y6Jycdsl]qP(za&s烕33<1{` 7!J<|}4ҷ~?kw;nBq- 6+qnwl.~<{7,aaig!p(TP+Tm?{R*F  6ꈖyݹ,>k_._G.?7GډoF/QhHF6D3ȭ)_gܫwp{ᅦ_!Y7(OsWP +(TT*1ER։4Ï`ZmAh;q~*]n2?Gw>cam'&6 F&&np<\OόƉ+Ȍ"q'`2צy9;Bi}̻o{xx#BL񑾔:=:g(cPnUV땎@)JDBi[ YkEd &hYDiͷ?i߂χ{W}Gƒ<]^ѝX}`ןIc\*|Ϗٕguyďb^+/|TD`Ţs/ _G?\>n8]<9p4e;.ʆ@+ 7m/yZ y$ǪF\Ţ zUkRVT)pPe Qƻ!R 6{s:.9گ, yx#g~z6LN3r!•㹗dg;zH|i&gzw7ieF)0v^Λ .qNOosc *G)퀣 J+*,ED؇ZuB˺VQ*AEkzqeEFk8hǩQ:W6@aИC%,20{sg=z6ɵ7g`Pܮ+L<^>ݔ1/""N_d욝jq~wX8.\"\X1,G+Jm_Jt?H3n iQ?+@LVl.{b)UYZkQu*v]wbQ~E1D!2$&ķ&dw~V+Çnn>`}fo?TlM\O H;/}j<[vv]fuByウS_yr^ p* :G)mX(Wɲvd]eFFQ_8yVX2S#Te%VRhG[8{"*R5(Lz W" VyY N4Zء~Îh1?Kt(ZberX-;P o?.W"_ 0JcE:DJJLR A8%8$uB sl?swGWS}hRhe錖y|.=V;84מ Sڏs$ώ;Pdei7xL7PkW0Q:X-b|+Ⱦ\:e?1Ern`huFϑ(KѳJ'^$KB4+gE= }~/?j es┪W~7cjI+ :Wul)MX`)Cy9+r9p]{(BG!& +%yi  & 1\÷O.媥՚dۚ#wej OL?7g>n,KOx|WI83N<񱗇,?;ipB78X-ό0<ҁ:E%nݻkݮ!Ff,3MψuL1lx'Ţ vxu xC<[O.{:Ȇdv7οr Z㸉+G1~CJr@@Q>(HٗWjF $g1|r]7 fy\ފg+σ| 0?RT*T*>-*~C T(BK7ٻ»ݻ#߻;NZu-z vgFxYxyE.hvJY\7l%m}ɥKdsxn&N+" XGa#<֔JCJeK%XNFy(0A) Dq>(qa="Z'Ik]eDxLvwՕvV*s&E Qa:(B. ChH0NS>n5qpXr*|xB':푾{~Ncݮ;ݻۯv 26}ɛa|溸];'^cU;kq68X'C}.qN1(eT""%[V;V|9b ,/*] ӗ"a*PTdHЪȂ7+nҚWYjܫ]mC}_ϴEVކwu+2D(Us?6>Z=%O'ھSJ ~{T#h+NHh}VGұ7{ ʭ e|>gݻ 4יz9ƦgnL+ֹz`{WϸGoC?"T7/~r0lV.g ?WcŔǓjp;NJMӵ#q4.V%8\@(<6B(Qj:D]3a(t\;ycj \WIyäwAMS2y:}qD!a|qm@h~(0eLTEVwh\jթ .jnu~ܑyg]";oկ0 zR56sbu>ˋ[,R}$zunӷ" U1ybEalŕgs\<jPܸ!`<^ي+Ft1 S~ڗmh/>X]fqLy˽jɺSJ97 M,Ê л֞Bns8Tt}PHDTQبlQ\FܭVZ''7`A:o yU\u}0}?o!+O}vl:cיcnKf`J%zA>5';o,ds`" U㑁v n2)Tzp\m+; U8F9rN ~BHd {{s/9o=$"7KIHֶlE)" F[y0rlFG7|xMa~' ݻȣYy f34~횹s/%_Yzv#&C^A]D}xAfnƉۗ"{=$1;`o DͱRTB+dփk+Eyn,\ .*AhPe],PJcV@(aB F9SQW=~5ȆF.*8Yv92&uL%Rϓmלd!M%&):qJ?W?L簮O~v{^cU\Yw$|_u֍L_ڗ#j'|ǽYmׁxA ]3z ݮL=ɯ| u[G%$u[i=^4Q})-hiUB>cU;"S/2Ju]ao~75nԳ74|nݮyZY^ax23n׷_<{b{ǹsq0ynyD`xO0<kNd2x Td:ZT緉V8`q~-]/QIH.emVBvmV0T ɢ2V,$tRnÂsmk𜈼C\е:NrݔIR*oc3Oc"?'B 8KUjL+&I88ݫ(#p+ F!8|k_w)l3%"r΄ցB]37>r6s 6X79 % $WGB"{=65T7ps}ikX\b{+RE׾tQkpB}Ѫұ6ju`Z~n~MLu31Ё IDAT ?$D ,٥rriRB\R.( x>ki` p};V,4tnp pFOLwb:A yXqȾ'ȮlD8LXD_*N98Y5BTɉ6!&ԶJ, ƵA!5|7qй*_#$؀^DpwtDUG 34Di4<OCH2vSXJEJ\[5=R7ˠk[4-oRFDeH= ?_JEVk#ZkGGXvVfȺ]5r~;__ _0 2>?;5FNxhtɊ%L*2h댱5b"Tv4"+BG6] $$a?lH8VED!D?.+$-[t3l }R]_Ѹ<3M^G*ʄX)25FVe 40O+T`Td8 eOM:#57?is[[ЀQFo7iUuzqU^%9-L |Dh\8q5|Yy HEU" CЎ0o2X?qXZ>lE>^p6FX6(!*#%8Al  $f6f_]uԩwΌϧn>uj9{<"VQ&s uBFIZadtQCg vöŬk21nx_ɜ(_G~B@K\Y5\Nfк"G8zٷsḩ,WoMmjPHL;L`V$y[o+Xq 8c"mkQ[9$8ԺVk=^h?zK31dVH6,"Cj} T+ZaPq+Ju?*[:>礍)ɰ[ǘZ xkZ};gVtYw&`#( G_%q' 榰M@Ƕ|EW)Lin+%3gˍ+qpxM,0:'8 6/OjTO<ժTn\Ŷ_byS!\`Q|XufvBȟ1L݇-#0۞8E}}MIi} c D>tuOu('w_}֝ѱ4/+7X*LuSG:.x8 =)Sb4S2rd<`s_5 M y9vгG--R~|m;T#u s)E;k:}p40%Õ)N-S 釔©VUJJ2AOvK09zE3KPS[)o6hUle Е[q SևfbT Z h*S S8pmoNxl&C;jzߛ$I 6]<+>"hͣnպ|4K֫EkkbϹňT~ &$($ Z4w+՞1ޢoCZ,7,wjD8TYT"?Epe{gq DXWR U#wK4\4܃B7B*PM=ZG_;w[}EqT%[ zJwMiB.։Zu ]*Ij@K \!o6 qIU Apj*yy' JVx+h_ "ۋ5͂y逺YBDZ_oyE>pjb=p˒1:ɽuNUVO?Ρ.Ueq3 /cPqʨBgT. ARLB%?֍^Qֶ;4ِ+?j6+u?j`X> Q5 eIۥWU W^n~YO!hͱܫ ZCi2یuٷ@K"` W`sޢTylJ?uҎᣭoiqij [C|/i()#[sWP]r9UUCVgU-[*;bC^7ʕS !̅}^ *PTЦ+2܌d\uP A2\|,aYu+&\{oo~h Vס`&1pSZe1.,QE*__h\\l 2fPؒ^\ h!pWC{8fc|TŲo%N4hk:q Ng&)\|,1~Fhc+o2TN ݞvm7SYcMTŒ=&3g+֭ .ǯ<3%&YÕX7,eLMسk}{[Rgsռ7άg`Z%3]g'l:wX)cé,굠'.V83\8Uba6ztUk1D1~A;9R[>3R7/WNS!_*BHn"S!&ΖDW~ȩ5| j3LAlh/:\@_߀D%=L ^FafSҋ1{0][Zu-›NQqg4ȼ*"k"gHGT؍SYR}IaB~k}JA?>FrĮMz?•o,V:lվmbʩX"/z]drG:Ͱm1'V0cpj9֬˙n^Pe! \; pE_$fx3bRF}^Oyc+RR9"$ƵB8XM>X&P?<+={lpY# ھxf^KYnZ;i#nVdl jq1}"6+>%DN^Mq&@ʶ+AkoWfHP4C9ʡZ+d`2=3nf^0./C3׏2mlQ?](`+C:1nq U9h F+}JnGY.O~۪i̟T#uxC^rn(2#UPn1L{S3|_Zs<*:ZW1p=cpjzgZ,J̓( {)|bb(NYĊ &V0b$BWW9?þS5`L?gN..USSLL Y 2H`@g&>}ER;3֐ XcPAF6:vaઽ!-֏U+B'zz=U,˾9E/C28v\bf&M*Ue߹[rDnN RI٫:jUUĿ 6~U*'N F+\.F)ZPg {̓⏉+&+[٤Qҝճ Y-Pb[zU,yEoZy 'ۭѬhx#pȭ{ʈOTOoJnx@>>gl2ruװ7sDN #l(̳Ql\Q~:啷_Fu*/Jך<딊\|:0~+&9mb{6Uy. &8_1{=˞]5ɃEaXvƢU7,.YAڳkuNmˌD3G#sìTFՂk_q?(;46Pq}h(YKlS W1j?\`eyQ n~,o0>R^de(tdDT29e8`VLʩa(t&4LgMЊ@V^>|Wj$ TJ5`)ƃUXTBz4PճVK$TA&p H?L>sUq!j6*W_M7pJ2 ?{)7ɀ&$%wQ^mu8AJ%W',fdāȈ(RPhY!y p@^IiYZ8VmX6_ pႾcCVykI[D &@ *ЄYdU>C/!ڹZYC[UOUnME"'&䪪(ZfOGA|A/g ~ꋇj)urbXQ*9LM5kbGYzQJAמ]ѼxNr&rbRG)!͂G+\t@JY%+ V$+K+szf[U<)ʋNe.KXG+tY7w6sՉy1uO¶<2?Y^t:g@b'>#k|SUbg=pB[µ?Tp2X]R#q&3G?:V«$UXE;^W7ajrJ]'x3HҒzsG<!@@"@ <ꛥR0V=\Hq-Tʠ68D,=:n U)dQJϪ3 s4gDy¿6 :~Tjڭ̃zBwWo|J"e AVJn*zm)< jALͩlPb  kk)rҪW>bUOz~;qhtZiiٹ9xˢpel>X'pJK?WtpNg~jFGBlI5Ƥ"ɟ<(::)`eSН9{9&RSܞ '^\(W*D][ZZA`=4kU P9Nո޼ԫ*YB'+9M`/Ow}v-e^5|&*N5L@ *v}JjnG$㡞?u1Jʿ&X;xۗqJϡ\BQE]2ECUU䶚~G+5 qO\|FpP>S%(XQ܇/ N s9ѯ;eI Nlz۝ކ:<d17&\тbe&1eI:ҶDSa-qh/% Kg@ټt-jl*)Ww-NN Xi!P;=#Y[cs*{`Wd.*:ֳ#[ĝx*ʞ 嬶\$ .6 HJ#pIDm?\S|{D[eYAϷu]T H8i0A X6Ҵq)什۱ Wyh2>z h@1ME:f~$mIzwsT PXZ7 fB H=n;^llU!O]6ŗ vpl[vjg,!oY0;ucI}6' K6>O4u[`U{}{F6\[x)H:~Y Xp[;_G훸dnW?ӇY;u H;jIZ&+ePnי3C/~**(ҭ*DmTfV8tWnPga2}x% q =<̄~H8{E:򉴣J0dM1W$K bՙ$q ChBb%Onx}yi0r6A*Ҝ$غ~ɋkd T<\QL=?]r /ºm m}թ rn [K9QKme`K Χ( ʙ.{ntRW/|c{vM_SKf34Xj A(ng|0G-x4 8 آz_ҍu$U>Ŋ*W_ {?}*{]:IB%ZKHˠe6Ku*UyZq$SB*6L4UܠY,,kvP#oy[02|9&1Kb6lh^ ]Ɂ=ad$W6MxFjJ{Zy'yk)|lɓWP)`}f̌\-罚71d-SKֲO`ʲ&mOs`ͱ6”f.qxoDrmn󠆔YoD'wO h &Xv<182uطk'iZ=ceQ,(w ?}Ob| .3]_ $7۵ n[Fv ffbtf3Aoy>go,9 Ʀc=UIwR%3Jb4w^EovBj'`:OtlO TJM!LjW c(9e+q)n]|O <ُ1AAxa,9Sp` bTQYL7Uj]y P_Y7waV&w|ճwf,:IJ'E Ū,TivԗfX5*/Q͒p4;^ZKU@~UaڋW+QL*)ٲSxleL-Yۃg;GqՀRQm^ҪBs5\>eI?s'Z]0ژ1Yם]:ڶr:ރ'%`-!<]k~^?'gf hGw3`v~lΏv4XjsoffeF75?7`{?=#m8ƒ=b'PL%fB=u5G] 8Tu9RڝB:0B_Dfzڍ/VWQ~T~ר9I{A:Avk4!بx>W$c閨}jrg"7:j71zCY[|>=}3B ܥT-)YEEX1Ym+YWRC|(a+ ^ N %8XβC *ˏҝm?tҙ>4~mY+UEE I *(вD-8CX3WdNL_7y8h5oj|I34W:C.Y毡EWYPum:L^V~7]n&^w3\;WpKi ÏO`|ק3!N<&W25~.)ExQy%K:rwrdRwDu(UTOjrXW|괣>)j6Eՙ6*p1slz~7z/Ond$ݿr|q'Xus0ځL/=#[8ҹe33ا/?TdTvD`=t؋S7gL9?*C`+斏AC+8Ѷ ^0o X9Zo0" #\p7"p6P ku?BI(m?ȓ3U*:mMՕ*|;By0+^,۽CkֺJJ0Zcf4(;{B꫺V0'*hϭA8J3ԚZAU3ȿnѰ70ؓ'?>fK3[F[`UU.BJ=\F$juUYEV!7ZJMqS+͛ _[9?WZ,mo1q֊5ؿ{P{bc+  _ޝOo_olg/^obd1&NaGey9@g#0͙MLs]]aaDu3f],㻌c=2Tsrϼe  \GieH_ozUUt `1NI"^zbh[Ƚ"ˠ7>9wE궍=xd֘ϛjиzRNC0;ST> ήw={nylA],iTڝuoǪ2g7WBKb P(+ LQæufZRL~ 8*5jFPRw%&w-^Rjrw%wj~ gƃn<.m@ UÖ g-j-Z_| )~AV-I޻|EW{@+1/lcj+׮;iC5,ֱX+G~%;{o6IF.`%ug}@ꌀ;X,GXc TL0sHʹgJP1a=zۗeD3*a s(>P 3cmaG} *ETվlLNijZ9u 9a$<%x_/֣|#>Y;;<&Q߃s_wUhǐF-*+^R7t;WaI**-we-n,d0g7j-׬ʉiS*?!%<_R< % x#I !"P +֢++Y B-MY>ھ\:a`&l%MҜFB?.ɗ$ω7Yؙȷ*ˮԂ^1T!I''{㧹>DbXS>]ؒfz~|ɋKeUZc=\x #m;8~"Kq^Hb uu#]]EUԋAd1O$%7~޽;Aw3KhvL7z` FAG`FEqD Q2#1NkHH\rx_.K:6]G5Th=+Tv~R+W?_va*,!r~hP}Uv/.fײ=ղi@(&QVPdT - jUK"y*3 q; BBm*ZDY:P ` V`z?xۛK|BFByTIpsy3Z8U%TqꦙwpI_M|A#ow\;e ׳ Z&3GyOhz&)g9FOsբ5+DsOP^w=[~:Xu%@{Ш^j W1k{=-'O"DKv>fvlnkZۀ.K_M8 W̃B+Ǜ:El^7JP/;h]Q~`Sޘ1QV`Ś5'%`9X̄EQ/}/F_`9F6 C8q(. <([?5)mdٟƃ"1P!c¡oPՠ|fdy UA^yz#_.h!&9qd_Α9~腟R*T]voɖ[uR2:W<p_AZp4X1PŲ W!)*k@ުվv !skPk҅Z`lQ|Wh|Fv_7I!+Q^!M/LoZ\|ozHheH+:G+$zM* ʞ(2"%KŷF~m7ψ_V0e4ޜ1֨ZPV6nRk_V,n8dFr{Ufe@ HB\Be&Xv,;$z;~;Cנ]|#9tBS?ӌBUpmV|5W30vG0/UaaۅwQ%u?ٟ1^`9(dt9BZEz_ IDATt௡qIu_cƺ2X6L|+uyͩHL-Z- ICZpv?K*,ZCV<,+ҟlnzu43|z@>M&Mݷߤϴop}hg*W&sM/jqV'wwjZk7l"[ķ],XGz/pæzz;w.Հ,tI N(mF'FGZipLn=ҙX:Um`jj)YyUg#KǑ6c.\>{?m}12AI<ߦP󽆬T Xq|.>Ylu5rۇX=5~CmxuF&x޼۩R4jt,VW&WpD`jա[b]%JF+,/YUmf\i" *zid GU0@~R NȢ:F1C:ʲko @kb*I40\Y lbTFU.*^p!Ǘk/8O~voP+VOjyʜjˬeVU>~/`an¿?* %Ba +#.( ?KtGѶF3FOQ peAC2sߋl+> s9睇< 5ȩk_\'{au?z}Aꕵ]wn&`GCW巙(Hm"z$mqTMmNk;#kv֎_yx3itLH-/jsH( ^u:5`%*Vwt0V AVZv=:ήG}Ri%=s'y /w+ڂ*v(̆{Ke46*UA!2z>?V}ԫ%.ZJOm HD~FͳTU}d0J_!$ن*T5DJ%eYG') ;MkS)A|>^->^|%Cօ8Yc`{Yp53FF^Byқ+://Um|517e#hTpaikσmm' 5#NHF<A+|Фl蓌x'Y֣COz &v/$-`Ib]r듡6C:ke}g /[{pcܬhMG+*(WEK(.YR 8!)edR!,@蝻Ȁ>VQ oD嬘0ر>X$ ij*(XN`\=qy?ϗ~EIJ=XA%+HU?1^Y7$lV,.UϜ ޫWYCO5+A1TJf+ w+>}9w?}.8JnkֲnV^3~"̓. UB t3%㶛5׽3ҸQv[UAhz0[Õ UI`l` W64>7/6Q еtԭGCw##5.̛ n_LTA^i˞P3TP(lcvahPN[Q̻Qkr`X EoYp5VYod슟SV7w/q͛†N_VZM!э 1!6aAi /(*H;CyP郫^_ûpzI=mgK.ނ.gdr8q5{1t65ɯzͪ6 [HLm!f#j+. i*S^v>Om;Ov<ͶR̿}o%Y.FtPվp\in4:XʘaeSii-{[WpC# hP!VhRh6~WBdE,z[lr4)\}uRr%-8i)Tմ ZRRw-5c`g%X&w V,NlץE3tס Si*R:7#lbZ|a7ʇoH^K?: o|$} XluV$΀2BRrVESFOD)06+SBvG"㫷::Q xx&|1;u c?QۂYv,; rUv߷oG~ n#;WWb:K~1_H Ã?-ox*i\R =QHs2ir x؎ziBq~Wb-⠲Zk὆*}i1EsIԐ)1X]^;cSZG) lµ%wκJU-!m6|%:-KxfyS KJV'~`piL;*]NUnzɕ\ُ6b+F8^ c+ǫj5O;{cʼn/>X^`1t>  [>1|C(y /xO kP<إS٢+,AJB蹩3DR;~ԣYCP$1P^wcC;cn)m!?BͰz r -^ɔWq`#؁36xKb L"O+yGȪGZB> KX%~"\sMmNRC_-Q\ S y҃UC2U2kaz:*e3OکRp/W7 ~V\{Zhn"\% %D]pq]opiF8Lwls^p2oX?c%!y_ckWr~KzX/ Jsrr~] mo%u'A#vQqH:M4k]$3%U=Υu{ʙM=&,1pu.c>71l2pL~6B{o|cњgVoAN ]\-Lof}f!Flgl>2c:X 5xCW3}C2qiS@ntMk\U sm4\bܽ RU33Y >J3nZm?W{PV.{<`x֐EAe驨6Nt/r*6oGoQ7Laǔ~ҹ;4 _+磥҄0`I Mh[@z)|]| ̬2<ƞMerpa(Q}1IL Ȧ{UgJ)+P?߿OEngQڦ@Umcj-U,C,'u?× -oy "—>׼_1V g`% U[pk?AVƒVj>BhL]4ԣ\?>xeD]9A/HF f72Y,L9~61yQvD^b|[:02Kf!{(G00c;ƲzmP% >Ve4ˠ׫X"M+تv)˲[:D(wLp5P ͎fx&&E&TV]%?9w:6VI2@qRLUbUw03+FCƒ7Xz}g8:h2l8,(Vh5[ WܪSmlP+\aI2LL}/}~S~@k5ػp W"`ͷ,H 9:-yum  \t|>տAJUAD gjUeoHjp0e+0>D]OXq*['_&|mF;`,*m8G 4RvUݎ^J f?Xΰ?zbfޛqwsUjI$Y^da lH$/!̐@DAdw $N0aē@2̼03H2/%61ɲ۽y揳ԩVFϧRT9{<ڨRY.eVҕIBB&81ʣGi-+ʂ'u`=G)*ôC3:;Yi:/VEȼ`RHQTUADxh-+ t; &ڛ+9?v.Ol+g!_paPYˁ%[(MmU3TEdECU5:{<嘛7jzS>y3`F;U]FjfL5JR0AJgE @^aUF@YVXgW2ܛ#73 Zkop)spXbU$VJu{ky3 {ͿobPY«_XSS5`.~)f 9>!n*A{3YJ*\R7DEo X)lEȂ*x,:։{RJUAsÓUvғU1u՞EߴZ]^0Ic[}#N1hbUIb/*NͅaM|Փ+s-lk:0)(XLx@z29#o/z-*lÊA}9֙\ȑ'_W(uDrV 7yluO;vV>|;."q^7`*.$DR+_"Gڴqr^:Ƙ:J{>r \ WU/d:`los[3w3ApW^d~*We-enLZ3܂ϛiAkS8F?BWL [;dIÞ4#ƶ1N)o;j@Y.\%bk:.YpI{nPT~# Sm J֐0`TV=w<;v`]tr9`q __U`!( `%XyQwĀ e,sG533ϘyF=-..Rj[RMv`V42u#zdZ26h}-ՠ3㜂rVj`%~ ]$|Ctx?ǾjM++m V,sx#o L\Pe?p~T$ \44 ӠpVw_p%Ikָd?a1{uSEx~ }kwtճZ~Z጖R#tOG 1QrrV֙PByݍo[78|CTtJJ蛣:SJpUQR@r3IfZ(?+1q;'Ju=5̇͡1ߟ4Xbt Yp*|iЖl? E/(PVyRzZeJcbz<}{VTZ1vᑂ#\Jxm|wÇfW0-m+Jiy=)4&:.Bq* N]ķdq a',t!貲ݗihk2v*C/su5hTM\w*-|1RO;L0L16@`WUt }-^p0r'*":_ϥmm[/[w=4EBfWc /U.:׉)YZImd)q2edZ/֜r&5b&4z{lTaGYV˝[P_y2]Xcy^u5 < b25SQc%`kUx-XJR?` )b xlbay3ϱ?X&pecCH|WV_ZqLLcGg,%ùx9kkca-VBCvu~7LAШ0#!U S>ʽT+d UW"`rTu 4j:Yĥ){tYr5ԗpiܝVY$0:J+U(MTYK̂ N=2[4{Sjٽ)VRN̋[\z-#^ ۙ<1{<9Gs[ ?$dXMUT+ץ_-J^2%a5=]BgFJg.E5֕әsgroژWc(8uA׮ϩޱUV|>we9)H-ꕈ5Uz{=ozyS:4͓$КXO/`i̞ErjFs?Uyɫ_ÉcGH]Y}&̦'@WCJ n,=VZ`A^BK',hFUU2e-R(KDȵdKdS d`n7+c 'c QO5]ĊApn#iiWUMI*k<~"La}| Zn+n`ߎnO7_K9ȑ)_lz*z &t6bUCtU,oao,}3U`A>W>URO)bY[3RNHLc6(+MJڨ`8 aape4Hiҭ%'MX1 hay72z-8[Q]^H\L]J#}95Iwaz=w|Cp;CK W&ۄr ~w:zC'$,3 *r ( tpʙPLX^Y/xJT,kco,{T5^N LGO?Vԫ!VTʰ1 *1Zk7z/ChNgxd`L4}$X:;* 3o ׼;}PgZ6իx[N6m# ]iE?rDxz3 k7ܽE7$ԠjfPciTn T h%5?%10VyӍ_+<+bM@^3b%*բ%•xTdQP:da c??Xs+W!ն6j`L*73Ȫ- 4`;O 56^๰Jd*&:\B`;yFv.V9>NJ b̌1AeA  OypѼ.\oW}u 3eyQ`sز(Uڂ:̀5u'0ʙ)-JP:\6FJ7Y29{(w;|ȡdVA»_ ?jYr_:lMLgQ6< uNT`5Ͽ=|0# ۝mV;уMQCnl &U'E+|e g;I[|Z+XSb;]LYb{^K*\kbc9+?m<H+gN9(GJ&eNatRszbk;7D(Su_5N'M `OG?1G>F@zvdvʋn3vۙ'MdY׫XS*+E,@V0uE cst[XeVBO_l}Ps11T^%fw!s`Ƕ[9|rOT}畞Cuτ' dHTs|,{*.hhPc(o y&)U59`%mcrx}z/^)Tu8aAxY`>0<:Λo~ 6eEkUh$I>|v:InKTJ+/F4WM~ZEPeyJ|$p^b;L) e䢒v3IT<\9CS;|`b#FKJIm]'&vc4J|@A"=\X:^B;EŽcfP(8,[cSS B`'SNws[ݘ|13L;M-pKV0t_! ^kx +ڊQLg/`h#շU{U{VG5X= 6Z2 uW7i)WbB)S:`NH:z5EL_f0K?*-hrg\)`6 TY^ !^u  pXN5NSjj0jaU x/Z8-}߯_I)dљ;kJY X̄EQ:SU^^[?؃eCV bTܖdAʏ+ k{~ S+36ϝsHQx>zdTq[g/jgVN%gT^ Kn>BT>\ћtVs⎪ 5Vy# ɋۥ( N<IJg\7&`%+.M_P,PwPh;w-Yh_\Yu%r1]ѕuL؆!foVf* S’>PC˽UE٦5*u uy }P)1 h>%xR"y^[0*e鞯NZ ;W~:/|c??+6URf0zRG(Rzs~JZ0TvkN\1.2ZC\FW jiYkI}*1!ڙ(/sTPRe=tFqt]!sp>^ mSe56SU}e^g:WԏKօ9LaM6Y șg r1\‚\ļ\A>7hКkt,+Ϟf]>‘3p)U;L8Sq3}٭}CWzVJĩAcXeԏ F#Q `]j/F"U{RBP(T7~BrɪbIkk\`R e;~ΦXfv(vezѓW) JUq(Qzo4땠nE*qP6!Vp>W(L-`yY¬teyy@,#[d\}aQwg`)aR%"B[{KDOs({팬UTC1]tN'%~ʉ3z®OjС^j+mu\ `u6pfcI5_*|rKGch8:U>5}|iiEg9^mY XWBg7[}^^U{,l{)\%gkסj_zUZ0eAʊPJQR$Gt)SU8瓴TxcWcOY%~JRD}fT#pc1P %֙b*89#TBTU'Yꝯ+pB^ ,eXM3t0td 're3Qfx; IDAT63ٳ9ڐ F;_b{)>_,- Vi2m^JL$*WxxiaGLi,⯥=UC@ZVxm]; \_ R45`˩Vϔo20d`Kk1$R%ahD-@UIv!]X˫?gP%2X'5碸Հ5g>u+.F[8OIH(S`ͿOTTM$+XT^_aJLV`JDʪ,9qO~Q9\r VO4M's#af7e;2jU6̠)`ݻ 9ZP5Hwz=vW@JM=!]w< rppUSD)Wξ@%V@q 􀌌11 6XŬ\, 0b8e0ϼp` =/:Sņ|&.".V_k+Z"T@/R^u݇av!բl;^]= h@m!$4sJa;i{o0c۝Z :U4(;uPR( <DmU4|u|rO>~^º a;:L?j^;[Z5V@E. +mE3aua(tYu!@w2晐/3!wnno= r9C/bxvZk7Z\xg 9pS1*Uc}jh\,*_M}ɿT v/a çVhFF7/SϦ?, W5NYB4R(EQg9&xÛ9JZMZ/ؼC-GNd `@X.-~YZdA^=@s__o}Ul_f; m[P۶k{), w)Q\hU\{ΩDTQ; 0kjdY۩0HK0 ^i;~c*s*+ȴTfN.IoBhg(\z!tOyV4CNik'yW(!0 +/g5`}`eu7o}__d +e|B}7nl٘ͺϔ%\p Fč᥷#jt&h/tA -}SQ;NC?W(GGWm>8o xN(֑[!< qc kIu ;c3srTbR_pTje% [ $05䟳Tkq++hsyuU S*kKɮSVԶ-kuŖ]ٶ-wOarJ|k{P V*"}`VéJd!U;Kə'/ʼͭ%Ɏ½*aOVX%TjnKAvN5Oވpы{ch="v6.!EN}L^*Њhdfՠ{Հ`}-rgՄTOVTiحTZ%_~Ţ~ri#AIn/Z븄fw">Si`^u K (^uO~O4׃VR%6@w^ ]lҳC~=|1adedeΤf~ѥ@~tJ!/oV5)}eE>b~*I`KPbl95JMAٶFԸn=klU-uݳWl5w;pة[?JŨ)V :hUCU|X7X,`&kR;~!VwCn41}ZUW;s$[^A_vu_A?AEJ͂DRR^r5>ŠGDLLΒze^L:?{RM }oP~6#DJ~蔘z_{NK:A%jjzնK$eD&Sg+7B%]Q/c"l%G:O? @O¿s&~WxUտ΁{^u B XcJw9~rm[)D5j+U019ɉ<9:rVTrG`'+g] nCCZq-~ '~Y} XF&\5+*uR|j˟.NU':lC4s#&P"YAXv:3Nl?h7\jc\,F<ȳ[=Уc:3LƱ=ty_՗)p 5R;*ל?ЩVe썥T%zUbBw[x3,K\Ֆ,l ]a[Qێsm F|w94ER>1'WFXKdHaz>\Dp04n4*BUeLTRnp$@6뛢KsVT^Z,o޼B"Q֬e)4F(1E;'PGsu J)\5U,]AUߨVIi3j&J?Ug8ǫ"DkiW"D'A UWR32C\x [/>7jӥ4A5KF&qmj˻#j#rvv?tk̹̏Uzy?ᑂchu_/=| T:SkN}Y{W+߯w O:$4R`XkhZXW LM+x<ƫv 3tvt{Һʑ(';:U Lw%ҋXy^ɵ+]+gM]VJ*lJZ ^Ƃ?!*CMϚg0wPy~~otWa_ *FiA]ue+l)\V++RcQ.J\ j{'A#3n Ac#!Dx J㭜?̣w1箘yhr \Sl5 5 .}9~CwS*)3Tu+h UUXUxK{Jz*fܾ~gxȊE;Z{xo JO+rFjJ.[o=ګ.,`Lt)˒tޏM\ríqb\G~6X^S֬/VZv9'+g=`'o=Grru/ȡȭM]ܰ$:D#J5TJ'Wtn,peqjh.̊^v<涪Nhbѧ+t*bY-߶^)ieYOezE3sCe5Gݑ/ڂJLxV#p+;[:?LUXaժWie󲠵v*0(n5 z#'{S{2nZ Z]nle!S'yNF$B儈́CD Э `e҅brO={QJMlzm_ ">'7/tc[_lv1 nt)7oXdB'E=1eǏECYD jhCr`%"XkrEj)/.&YW _i[Rz*:||0_339{32T dz?fcȼ_Zzv&zk[ͯ=%Lw|'`T]X1B*wJg[>H`J֞ԧxSY~ 1j0d;Cf<,}RzzS[NY (d(2h^߱VvvMWj -wTjth Ns&)g=`>XgKyΟ[?w'zɋoJ:qB T"h|~:)qn R O}ÖVSJjU`}TQT ʮ7 NQBg:ن3o0VPdBKJE V4+_9Xr%y(#d)N]c*sRa.9XY!׸{xJJSYU8r©xkWM$Sp($^|l]* \Uu:YL)J 5JL`^E9\?3̮y>!]ff=xj/^+ +YyEB,o3+@n]C%w _t`G"yRExgnL-.g(uzz+cS'bC)OBfƐZP]qZ睿)UVz:[|eMoC7wox`tfaU#`%H އHA6k0@J*uh* "cAq~]߲6*mN>БVT2C*e'Z:N" WYzNZX,tܺG4.>H}f@-hvtiT>:up"H ! \CJMQJ@+ 2G8VRJUڵIS=[yDLoHǗj1~s; TX&=5H$o4R^BEȊ ¬ĘJzEϼp5v^z~ӡ41YP& @'x.TڤO"2 *XRE,+j+–O"X#\@1&PUc #]:3XJ,lQ:}=րmr_ab^*]g0;Lf[W3/i!QFcr:°:H0[|IxczL^lx1n{lR|MPڔU^+ʝ jCԝbB2XVAk`NXPA2GmQ$- 7qeaE)۫se죒F9[,Qv6>x[w:1V V\nh$`)dvp5Jd x%* GZcd71?iAk J `0]{E0ڶU'iʲwUp%Ru".,x`Y)XeIi`Rö3)o*tk$SLrU#ZUPEezU`QOG4Gڄ5q8dTuŪb#T%@=N1q R6Ff3X`3󲑮LҕI q&ԃytħˆF@2vٵl`x73UT` D`߽2wq4{UZ. #.4KT04h\)S ķ IDAT J}%]󕁖O|B5+_zJKQ>l)!|$,bUby οBY_YK)JTF3a# Ubekr.Hl: 5v)wdzw/* 堩t4!>*+^A"bzԫt^XbKtghdH-9JKͤ{5/ ,p>]g8*W1ϰz60g4<m7܊6x^iB r=!Yxe,l`EznVR(V6$vmS%*XB0 Z*>pր(lmwH+tsח>)g%5:'񍕕s3W#yu.| p;x7ECumA;,ck48'+iLŔvjL{f jǚ;VX}9UI:S$D(SC]#)MܒS9!DR҄kiZ!#S|" ނߓoZ'o"a)Dk&7}O,~WR{>RU^XAeRkjuf,ԧaua5$- y,(2ɬl0̌lg,ah>Fg'~S_6*Ny0 GR>D^.Au{,K|+W>4 Z~QKTBckUcHRoO^&00:)f^GXexFF3.eǡ{HJM( dfxѝwT &hniU0E6TP%<KF2~vlß^'@yMR%Tyw^ |eP+o.|/6_쵧J!*?cDTwTLydpT֛hჸv!W+qAJiOS'sv, k&z 5b4ΩUy=NӡPP ?7? 1vh:]1ҙ>0)X>QJ,X[=sl5PNcC b\>*;.~Fh޲TxJU*+RgFWfVj@C=ySHT+@%'5ǁעѕtj[c 8*; ¶AJ0{*b`fUtlO*$Us0Aa[yv 8QN1aœ: X}.VMRi!kÕwfG .~&K%wٙe`:(D+E{Ė+`K@sXtzN>;_<ķ*,߇*,ɮ#,9P==&`c%k~72d;p*sr15Wm($2x?/ Vv̆Q;#nÿ<~Aʇ7=޴ m_ŕ,7 [9TY FsoEu$Fֻq'b1;8{|Qg|\[UcD OcHG?t4b`Ćɜhrxs0+7'+MR4:d4FZv Ny F%'} H!1μ|[{$Xն&T0KR٭\c0JSih 2&FgӢFѢw| @oT~.{G֙G{>,58h { s?KQ`Wl򞃵C Iœ98B+[08abe2)2›~'pYcY=ڰᄣQP 9P΄">5UoJ grXyHӺ-WRF0t`&'h,陟hIa $ap"/Us@ \9`J \eA%ȒIcβ411dAe-~N̊zgmI낪TecӾ`Tۧ\f|f|17#k&!o 'LI $ՖpUA?STτ7{,̷mpfZ[ݡ=˘0gkaa zdbjÀ*jtrqc+Aq8 vP~ NyPYW%7|[ϫsTM e'd0R۠\y'1,;۶ack9k3?.`rɧ{?>zݵ}ۺI#˫"}bh]/\QB M# bbk}bFWಌq4ULYJ<o^<˪OS\T5"LNј[ִ$UU-=9˨:IA&ʲl佘U{cvW+y:#ZWe<0mYr_*,fdOw {8tm[@+k16c阨ZSnPY\M`;,Zit}MOGEa\ধ&V5pxdJ \Pm% ױ4 ܡrŦCdO!5pSs"k%=(G `S诪5NZ|f.K4r@Xu4zaTNyxpo~}wŝbZ\ Gv1[ ?˘ScR7Q%+`ƨ*5r)Ҙ6̯UU{,?R1;?/&ں% , \y^[< Cݖ˓!X% c&$VK9xnlP[B]זp|FqSes~yT8HCdx{zYFgÖl`b߷W܈) z$4b',ƼS8wL9Õ$ܦ|&j2W:RUlsF_q\``ꑖ<\o6YS٩tRWU G'3gBV XS'+F\Vjm=ϭm0 uR9%;? 6>\;`kHʙ`;'-3I9JO3\C5F3 w-d^r W`U;fu(pX j~,lU|oU',#^M f3Q XCEd4Rwҟ- j+}v ˲ exq9B.E+k?֥,VVy0*fbUJH@5A7P)J,NQoj.p2L=jBZTt2(kzZC+N=&I`+j:sbaԦ *` KJ6 9bB&!u4Ocȅ]܃Oy\%{|1>1t\p`I(nokBcҏ0͜<|\1YMX,(`sû؏OFczW)jzg&Fձfɠ-E YY*5kGCHP.d6$Q%$HԤKOr-?^ ! +u8Kd U?8LZ9"Ҷ-NՇÌl+l0xW֊]d4~t PK X3^E88;mA~hʧҠH$%c L5`TzB%Bx|q:qm!z͛p7msD #˺XWES.g)r;߅^w-n[xɮ&{8Éu碋lu+ϖU*X`@G>J 9Uu\.>Yn-01rYX++[]7O`h,Ț[joմJ٫MMy[6*dkĈj\}k5+\E0q8>BW ;yXSOivE2C٫ \eZ}Ã:0@ ͮUPIHV8(/FX$`K[S &`*a_jBàJce1("Kf3,T[li 41ZSD8n:_'6 g 4[3;ϮK[XRRaM0vkC&'`UCgL(,E#Wgd]r]6W9GՆ57z!%).R`:O$spCA8 |8cfkȔ R Z5Y6A*sdEjÔ2XƹF!Y%by 'IrgK#!ZOl'Ė~{*n^9W̌Ǿ#h~,/M9̟|M Uddjr9ȩ]:Y'F+`ԥ~PA], @ByQ^2WPN0~|Y7& 4VҸ~lB{>U޻ U,IRFi,` '.'5_*טٴ>#Մ*W^^|wMIYd'تq^ι $ kaN) yh&j}Jʗ  a ѧa+*匟Goϝ[-|յk\UQAEhZ;9OAxً '$G$F*J+fA]5^;UՄetѻJg1}E>[mx;v+@UQi!5WV/)bQY;Pz`e,@[%AE%CL G=HpU&6Lɸ ``+ 䤇e`")5t˶ƾwՉȆzp2nV%j$l޻Hz^AG !N@Ek1WkQ`5HPK-kc'qF(edQ{S Vq{2&B- 8ɷsHݫ3CC*%Bԅ#59\R'@G 62R06|!!nhLnCx+XnšcaSwW]^w-574)e!t3tR@h$c10f4yƌJ` W@ܳ0=|>C1:ԞgV|ÖtO?#+^Q`R͞d(`˲lX@U姢Q܎oA||*7/l`eʔ ~AWzMUyH Rf˱iKJX+. [j?la]Gߺ9,UDֆMIC`*QJH)VMppư3vbہTg:3GbnoG܇&P@Yd"rÝbjõP.=eLQxW]NZ-( 2#7%v2!>s3QeŴCj@`o]<29_-J%QZZ)5x> ZJKÚ@$KG,.BP8`j P' 7U&,18E"aQ ,I 50Y7A1`n(H'cq( 8'+c0z񞐙VR2@L<% < >TZaZ]m%@˵w`aK(-%V R`Tipp9q_>RiWW t]1=t r:Xʃ}Y챘Qhfh[?#hJ`{<,o ŨbU` t߽2(M# CLV*TT23r&Rf$ 5 8 bqd8_w+2+1&g:ۃPr{O9wL - ѐeaMS,ʚV7f٩pĩb{1A؃z}Hw܋ IDAT}3d L/֐2ec<&\\rՃD~޴' K4 iXI5DϸZ!$|X9[^"/U? X ;`Ϟ=K]Y~]fimu&=R۲0 1D ;,`8sP ƫY$À+bgr4l-X9:jyPm-(̕Շ@uf_g LfB{Z=YTUFK&&Y141* b3., . löwb{` 'LYʺ9L?ϑ z< \QJVOX{IV]V R;,b2p_**D=}w]0`ͬ `+]o-oT4i{16)))ŨB\*UJafM,M`_yUZO(HB~ ,IJOm 7כ]d|yȋ҃|lU1Yg7o+WeUˑGwߍw8$nJ$ 0i/8a\~C.Nk6( B G ZIu"{Sث^pcp'lø&x^e+[!uoޙ.Й.ϒw)}57?{<`:mp%WOqӢ 21cg+er'YosKFZ4[@{+z.ǀV)\U1@h^QGSꥥkP5^U (Kp0pD5*m{oϊTQQgR[+-󞝚ɇxƗ.%dRPz2G#èE>+p.:lH%.TmX+e g҉T 7P&:g`a73nZT{5u}=hg5}$9H;{[gr<$ Gsw|\,o8H^(rsc~ۜgyBgfqp߾ekKVv4:YW8t:ޓti ?a+r_Z59u0+,/3+yݹl&+DRn;O*Zma' GzNv.mVy5GH$sJa%^[WGDia!;,ˏ|߳ݠDf rc?;_w|@n*ȋ~ Χnd]ܕgӓ)~:33-wX` iyƆaX)2'o9`]}}Rr?QjХ`j|β59Oz5R k??3("`8xEP_ pvl_QX?|>KX2D0>bƠq۾?%_fJ-&Qވ>q6lȈc^bwƄĺ{V͐>kj~_0%UKۜy],;Q|5+nȺB"6Xu9SZ\K7p8|,k}$iWl 29;i1:-f3E2eYh>57p[_?kMx8-*#`*l*ˑɎUt\x0 ӃquOe5v#)8jhSL=5ű9K7eilYP5?W4ڝs.C6'`J*'g3v cZo- L7a9qTp_*" GtO"SiTC2 0yS- hSB5p}Zo Ԋ ~psk͡;5J~NГPߥ d]B 0lFs_LNyxo~}wZ"hK.%? +;D90 [z;:l hu@@"$əgU d_v MSZ*h`̩v XϏ:|92X){Km()Se9 ;oFU[Oշ *W`)J\yne*HiU l$'ȧh `#sAF%F@S{!Pp8Gf0 jX{7qҭ/͏ 1sol~FXA Y<Mp&ϴgg`1a0v=x:gA3r %P_g]\@nૉɺXͽ`F9/=7\z(K^KnK&sl}3*{d iQqs J͏$=QяB5 Ә|bi+ e(X@U ,U ܈!33>s0C.ˢ‡DǁF*]W~w|beXǵJܵP +A ,189og?Xucżb 1=6V5 _obiKHl Lްǁ GJS`yr2%cc_eglɱVN@5UˉELC<%Q36#E^sbʃQj5xyր΋Փ =XuDKw ۏ::RZ;YWJ<*stCwɤp*5rbY)d 2&Ґ1yj/NB9dr%z p7rzczd0(~ܳ *V .@EAa񫯾/_(8ı u "lS6Xd)x r>e *K(+k=p | U`(c83=ބ&&`uhÓpq}5kGh0X_Ơy+HQh9 kՀM4QIFuu`CAZK:?qjh5ӏ #YQ`{;@¶iT4-;Soau{: Ԃj"%S>3MMypnMVHd&J'".m*YIxk`6!֚z" @iZΑdQxëPRVvJZݦǍh%) ˠ{,=5(xq+- S33OKeaMJR+7Ť33 ?:Ԉ@:dH@O }e~DXغ [ă#\sPE,R)UҔ(H(.-bPi>?е]7MM0Mp]$? S ~xן⮇oC<hj $ Q Yive<=cnyQHL,2+Wdmne:,a1\TiQQe[ [V o䎹|iv4S@oM{Y)m@<2 SXU{%FU sSPYKL:U,pՃ];(8XՔMXqe;P`-Eu4v_^|k[0uzoՀ1/?fe\ض}'1tqX*홢)0rl+U%s&$jħXƅ)Z#6*A0c6lۡsxrxr٩2u$f-mo.ݝxoQ NF1XͰ i,`X<+SS^W~ɗ]oQpR]p'hЍDdr !,LpJ9)k*ʖª9ՂI3hb*T~0S|/ ؅Ɠ8*Ƣd|c<&x3ؠ ٣a;@JFN "85=~h9W}i;juW5 poH C'=93nzk"/?3@LmCv?3\5<SZ/`꒲bWE [+uC̃>1갥$& u5cƂqoe gT=`C8xAطAb<31*e{[y!T?g<|5Xh89Jn*BL>K.T^ ĩJ!xK[KmDJ0W0l݋? Vk1}wzUC>r^ e^W`l&8y \#/ 5IYw(dkrK.Fw~ZuD|" o_4|r~{=RWЋb1AV ;bU$۩®>;._{b!3Sn\qފcv_y@1({0w;p?Oo[iN#sg@g|5@KmFE BՃyeܷ4>lO6RvaJCM@T+0V ՇӯѷKU ujjԩBP|Xl!P߳b@w-Wj<[ ,n4Vڗq*E8edbRJXy`RUN\lF *)םyٚʅ]܃Oy\dA'fcox|`/wH󲙯y֤ɪf"eȤ̩%Y@YX;ݗ?IUdՋ_w\8y]VZ>#q v񳧁 .Gpnf,`) gy̔kF1ltl}V=:{mL7oA.O}҄ bȂ1K1p|"+-Pu=@m5 fu Y>Wğ񊜤B`[HQdLҡ {/2q>mC5iFJ4.ڝ2jZYw(dZ,at[|<ї9kc]$S5wAl)jE8RY~?NM4/Z~eSi ndްy6U0Ӧ̞V n{Z@ڧup8!;?ᄅgb[ z IDATdW0Mc?C^I}.ag,x kG-%sj+]o593 {+{֤>Zj!xm!$Cb8KBUEՠ̛N\m?A糲mV޽rPf@\x^/xUV,YhrU37w{^8r.*W R{3$a==~wrh;U>'݆{?~t_>fꞅ5‹^#>d1Q$  YHNR'uTpjE[@V<\Zp." ^21aQw.<^t7ڮ@kaZ{w`1sn!?+pX8gu1Zcc6Ig$ݗ< :kjN}^7<%u'Qy *#*ri~a(D(4$S,H f# SsP!7xF|w |Jf{O}4vwr\Y2^T;Z]lm@Sw@n 1)SZݠ.۹U]fCF˕W7j̖,K{D/! , s[g_d[SU/&lT)s^yWq'W. ʦ2a.Z5Aa/&*K&pL^᠎-gf`zژa?@۳\=*ɨ_ǥI9L;s٪~%T-B:]&RDk4fUÌ2Yb *Fw8Ƌg_hg^8*(jdhxe~Q5KFkD|A9r#uuJV9} Vq/G=nAoaF75uBJYrV&ۏ:xqdb]~?\bxUS"yd٬=g],.F/EAsd0|*A t@@ Eɳ`2GDx) Cڏg*\:fpcN8q4z9z6eUi)U~4Us݃ʊQV\8o/!HPƁ`PC*ui VBƳ˔e ?ڿ(;ey0 W<XUG.Ba<@(h;zK>5m Iʺ4T.ȷ8T† q'W]^w-~C:,DN8z"؏H.E@4+ R( *?o֓T HZ0Z\@!*¼Z9@`Z@ \R;~U܅~F`?Q%epY ګW98'.`MRC3/`zk7Xb `FegXڅ$d2p$خJPJ+ɀ_Kpsn\9y4t?Tmӄѩp]ϡ{ @]ʪ TGTй|!91)B~ϗ&e&F"G; #5uIT5 yyxk_O\TE-֋.j`v-'g5SI?+EZJ&+10L2&Y7mE&Y*QFUv0w~2T:~!cp^Kw^߹4AM86Rim2W&W:%S;b_g}E(IW*+1PZ/D#&{jqFa&W;"VPxI*߭vJ``w<dpT`ss ,*W&鍚N2xgQ2lgS`NMpa.fƮ?y27iO;-50RPїZo)=bM+ E#ؾ߹^|{_1cp$WTi6Z8)iS!_y9NVJiGvW ;mzh~j0W^p-ϑwJ*Dp]4Eb BƟcrp*9 ly،e &kcQ\q vXu0XD֮/2^S vxO|` ]xpU@n02CuFQշvI{0ٺq ` [.߇;5K trɲ8MTE(j${ey1= @(W#DRPjپ֘n+<D=JY,JUWڤ/ٜJg5jQJJ`ZZݥ)mOMa~Ij KEvnc74r(g%Ȉ_"KQ F,N.1*\RcNTS]r -gi/RLbxS|%y֚gX[Z1jE0!j\&zUA`Ob?egM  *rRIUZ-ܴt*!8e|zs(, ŀQvk j 2*aũ핾 pV^\HW~RX2W1>GdW!]!m_cVj1ZSS 6׆LT%.3: ֚sCw~Z> w1t3@Oe r>E@+bdiuXK~ K9Ǿow;99@a\l=S r]W x$l<]_̔ykvpAIS5` t^N5#3XICJ'YwRV=PMʦ!x8\A>32@ւ#;?2_gcI?OLb1qX89* 4`6eN*2X $ʿ,yˆHYZQ³'틁e+K@S[PW>pWk#dCV$b<pxUoUT BB EλX+daL&H5s G% @ 5 gJb,5\Wfx+!ϿSYUԀdtUЍqFsA ]2Քb*~v$2D5Z*{9m OгFF$ϴ}Pv:<[ j>{UVWF^@XuCv>Z;tЙn#7VS[ǥoz%V9$lv: ,*+emFJ˲΢eg?{bED1Cy⪪?%|7#_S /V ʒՈVYB>l9T4ZUu!&7;aw&9||ot)mPvvG=<ۑqYJiqەB JFU 4t+ӝ>Tt[2Oc^֊ ¯,:-& 2(ڰ[U8wÓpmeU`c;l=[3x`ҥiXU505\9T.R)YN*H)x)A.{V@bǿ=rXa xJc~[=ޡz mdW * a1dzPC\&yU.Rkr|IkxӨD!{*mYϟ8P=$^K>2e_{ P>Pvv ZV~R&!/:=dPihB2GXW8րM #:1--m +X5u z O§Jv_u '&K5vc^Z}% CUg`*UMʱXqfaVU(#*Q~re,T:Y0(ac<#=h[Kmty/`lo %f`J*MQ1ObSu؈DC*TSSȦt؎<ϱ}O-R9+  Y+ɪ ?pm qx YePZWˮh DiOuН[rC&+}IҙY;"|Cӳw4P'dk` ф+QrDdazƊ8 $[k`kv'G 9)cx& ,tAl 7&8KCc{VvcD\I.ޞ;߫zD TW,z%1 '"Pԑ-U >IŮO߃;^{rbImgs.ӈz./8]ۢ(SAϬE>|Cc֭ؿB`QpSQ?U&L WE檬@ņ #l{ppz\ql=gMMs&lYAkM8w7hu 缅li.φl?hu>alJgM yb8{Y'TM]2J}T+5\ L$lȰ06=iA?0upUX@1^WG^OT9cXTpNqݹ~LCfsV oQXj'm\l`==rK.Fw~Z_1)JT9T%g(x Ld]6U± ց1bT)BR*πv#T`nՉ'߽^ riIb=f8݌^mbNFxl}8/i!LYA,LK@2YU?_< XQ@^ *A]o~sD@,e"aZD\H)gT#4lFg=sŹu㵃$(֊ K!PZN=h^ǀ+q㕯<_HJ*{="U}htgXزԂ>7ɖaL-(ˍhO\xx=MxlVF%fܳwpʾk/Pڲd\*j (0baY 3L/2W\gdYЖ6Ք60YPqޱErRJ]h5TǷ.&v:cp;[Bd'1D. d1)Xu TXSD7خ[yD(F)Rz}:Đl7N 8L'*,rf\򻍫Z6Sf q>&-w^ج]` bLh 4a/0 rJ?w~B.E{;^O[W^"64^q=X]Qxpxh/yhu#5^VRY[[C3U;`2U׹ ZCtc^mmhv^Lzo~3BۦD<*3`5k3/_JB̝M@ISD-y4>CM nZb`}Qb11uU;9+s]޽n}~v|:F&1XzKzaޥ= w:_oU8T+U!DUsT`jr7!2X+׉))(@+bSҷnBYIɍ/sxx YQAJPdTu|ͭlX4GzAAGjQR PHk4`_>3#]Y=HR IDATmp]TE1"NQ*X/kK|ʿxɧ^yLH6gwHO *U/1E 8hp:}F*{R*Wz?9(; a57bY G#xO5]VϚӨh G#mmu}*N;a |Qڥ=/1 WF:R@{aA:Ki .b:pU;N.X XSHv uvx H>/Qʗ,VgGK' u!;Q4iP4)W YUji *CbdO `kz}AG]ж઒qOu 2IU]{i%?UO3wO9_ӆ⯦&EJ@ebsw΢{:VLmb0*J]p陷t_HnGzߞ51]PEōcl'6`y.[;}C9F! ݱ˜X0̃渱8+\exPMp$n QT)-QnJ*ERXMAvd@`Oh Q|!YiH \LJEβ~|̪PB K(%Kj!eWU]dnނs+ WH|p{7v';aF^W x28S,t`2k jz/^Z4ײGü[7H2K9{!)W qdRdcZd r _kUb3p;~o5({sַWyVv<KKԫpaOesM7M,=|UV ]kXUTWBV-D"P`xfT(PO\KjoIŊyF{.ݛr2$#νUxO1*p[>S u^ħoNXq6.Sm_nс h` $5Zc1~[R:ʕ&tж^! Oh?WϿURyG]r_ٟ[W~Q.ҘEJ8="%X)!0 T J"RKEOkY^b˩ǠxGҔ4!b+ pÈKc|៚#i[ҳj C4ț;y`xavB_$|؅{{xg7``pI7aס6@N<ЃtV>dJUQkh\z?P)JzKTEFCg46WP9.Xub'=VKb,I WzeegVO;/V/D4 \ CM#d._1F6Fd !TcڝpN\ `cEow_E C5cꖟ%OAvB"3LHkc݄=SyjUwm[f޾,ׁfpзmǐ{kN،;쬳΂^ʹVD/҈0TaP9VH SGێj X`|9?Z=^|{|۟-v%U|WaS?U,?H\p &v@ 4Ơt#IQDלq>X?heZVYa=*`8D3`mF\X Mgƛ {=La¡ u- PL="i :C3oixc"k X՟42PM*C $Va'v yb`諸~S})b83[rf΅ch'->;=>L j~o Ԓa` Xk,*ZTݟp?{ vi #Vl_[e*U}[LAoT8k:z.b^W@m|{ xp}Mvò ;E89`uT+#ө+.ɑ~}SER4D<`HyNT~#m B &UI<)8QGFEoYnDaultGKKhV?;c"xifK۷]7ތ< o@NTyّ{Ys&T$6|Q!2|b^)td,9V1j=.oӦL++vs_/}G_.~T~Ruw]G$`3Pue=NʗM1/ p He>72[!a?t.cc;v쐞Z,) 8,.l-bJy5_;ekw+E'I,FHV8>⣭ӽ::^FT*z/UHvX7ﻥ\D2tBT;P8PUG<{R{a *]k[COh|y{僽 ve.DW{qT(WN!to[# fb}8t8T%V No53Z'w 2co/N=L[z넥OV$Y0u'7 cB]0|>{;Qi@Tއc"c}?|wOR-]5F2 cT?ؙ SnY*+ u8p?;'CmVQESHpRnJ:5n=FN(ڛ6e-١PֶiG` 7Hz5BҞwAwT#fMCm] vbƨMۅ+o.G23Ła| C.\tcX̝?|CkRUj\H em ?L0Q"ABۃPRˌv?xwHEYiݭp&r1 6" F*yMp53\qk'{߼d~i|U%K>a,~+R:[5<X+\6_]{<a|c?GX]Sb0|}Q{eˈYJ`QFznoڢiC^!1TCq2nHĨ n'Wyuzȭ[:[NxiTE3.u㣷~f7Ws fG:TFr-F[0ZO8sUV0hՙ/Ji42MBża*Mc9۹*v7{lJʬOՋ?;Sct"@Sv2?N k͢U8:fQo~q}\_tKt륻utB w2m tucЁC@!f8U@4hNkjJU6,ĺT_VU> ;v$\ vw`iv" fYl4lHzد[]RZr!1k=1>`ڀ,.YM#oM+BlԄncU{ta+7eUd. oT,pW%T6@aWm6Fdci\_Կ߯pg\)犡jPZ!0ؐŎ:O`o&岀1>N/3>T^)/`͟L\M&m1( 2J(ÕVCz|>t6 Z`4yAXNx1 3\w=>(>y]yFJ3x?P<;nC+yE#ˆ]x m<Q0|37 ´WTJhZIc1XbKԝ(Z7lF bUT\|jU`@ *T%,k1\VvB ݿwnCuq5͢?_t\{74edjQDZdUσ*d 2E?; t"VUH'(H,`8njU0+B/aiPJM@xsAV|!Ϟ%'Egz| =R b= ߰pgX%e| yUW~WG wV 7iL)B di@ޠv:Q̊2d'dQd*%ƀ" VX. ]53N?c:,hu`\ieS5b8Ws1YU Wc^ت*LM|p ?sN^F]} n_ٲG(V>SOXi*,75w4AJoz9ǚI esW=^7$Eo'[yݶmtaK۷cuy8A܀ҬHV6Vwq.@u 'ϰ&@ ] ΍-\lǂC$Tgdv)8cEC8L,}R;:kH9i}*3kG=HȲhm9rQrG>H#gtݒnT 8S 3o'[m{-h 8b}c_J77.|~XEQV3t (tv/Lcb\ EPIR c@ gވnC00 et(3W6@H`BHn]0gp d e[l%L:nY}LɄWV򔬫Ff~N+>o'e1XPO(uҸo k2^~Ph]^1BQҐ2.+VHu/MѦA#II$ >6;H ys/YO(u{0, ਟ:96>+[j gEz 逿 An5J0?p⦆<<GF%-aݏˮ'UW݊C>gZ̈RD&CS4ΑՠWHaW`e@" /q! ЉAKdb%D8/ƾo{uI+aJKL{G74 VUY+v532-jZ八0_\f1RP+IlC!\36xֶ}:М} rn@5NWu֯#DbuJ 2 911^sqq KN%P-+Zme'<`-g]?n5ox,@q=J ]*`n V4FwŽϿP}9?A֗, $Uś*VE&(JŰYD{e{RJ UIkl(hv"{z"b9hs`"0Ћ[lVyYb%OX6[T Yw-D:bSZT,- SP+d -iݟrhs@A Ƚ^YёCE g|'Rň,DWbY֋ѯV? vTMN2j`r~Z2t-~^hIFzXO1Y/`=w|λpBm\!1y/[ƬW9towĤ{yrS/<)|\;54"qe#DF433 Њ`qT$P–OxpRW\Q)>T]?D])1ţ!S"+?G(`=OtNՅ)5v-ÕO KgzTŔ++@L*܄@ASs|z"l+LwSż_A0@Ȥ wAꬸ#s 2s?tvN/@"R"*mV в o߹ֶu, k9Dٸg+ȍʱŚMA9h2Hh7-Gl%_QQKH%(]uʭh}&N v Ghh3AS6pumkW)7YBQ)X{WRSWMAꢌ:3 IDATG9A!8@ x6B۪UUe*84;RgD{}v j {şxF FgI>8Sx*VkUu.ݟN;,XYi1^Q\r.gf|}wvd!3{F5X}TH0Q2%/a"{TR!W3 NƶԻcqlH m?5N'7,JS(up 1B \Պ\$S%obHKw-Dh@dL2,//cP}m9C\_m\Y"QL6:Ȁ t`A{#"UzXCU\:A!D`VxtͻKqQ{E%{9=e Vq^WDғaן SSokT`t--Xږ2˂쳝g=׽‡~ < #pW<45fa:PU>{R>f`p]?R܃IPEeA?v'R\z}]V(0k R[){)YA)rb^sQFNA3"o MܨuW:)g][IH͖ĒD P˔B 2lPH>6.G¤r>rJZ_]Z\^gYzYoZD8Ƴ!Q#v\Y|GsStmS6 Zt/-Xv Nu˰ _kGZ}'p@Ρ TN<τ3 8k׃OyvQ–si>;ė/Ժ=W SiT%%X,AVBBv:U[!%89x{; 4`lCq[W=ͳ܃Ű~sЅl%Ҫ,UT4ɨAU 2BT"URؿo ? fÏϿk 4oGteK šO%0ې* 8^o{sHG--X}ѓİ _}1>(~Ο# dIzWk4&YU9quDMK9_ժԐ,.etI-ƪ Vҕ|U*>4-u4r;h%\YKZq'+8 hPE{X6)`Y!h׽+߃k}pI~:ęﮕ}m:o繊gUg: V̇ `RWZs+Hu, t,N*@`W ~ *ˊo7Q)1/>8qYޏsνfB[`ܭL)n@֤ S3&V*~85#/FA5V2ʮA&'ɇX1;$9 p4^d8`Ӑ536݇kbp zZlKt˻"M g{~/<҇srG p_K XMnYprCҁkM JEDϭ\h1*suٯU>! ibAɕd C3`E.YƛrV"8pq2&)?lKJ0= |G88t; qNs2p-u8hPo)NxrL^qgPty5`Ū**Y&˅e5Gb1f;A3h0xbi~}dM_ΔAlϠ>wv[h*\W: 8W>./ow5-*pUjp5 d~0`U%i mHcvM3}+CdF}, )?'2tޝzjuh\OJG,7tA8'팩ᯬx>H!W3t6h_KaڡCr$vl.Ffʂ渳wAAQ8L&'aCK`(DF4 Ro mU6V+]fpsm'dKb ^F;RP~~U{S !,z?]%cgwx3~}wx3sxxwa gܷ7 i9NjM#PLCZUyRBh= IowX]ne!BojTEYXQ:->KV}W^IB5؃,R"#P8o@AcmMż}^˨yLPp5ZJ1~L `rI9t$%+j dw  ~S¹iձM%LcRٖ cՖ8-i]BMAYh^ŦiKLKgj;vh\>A+Kg=ʞOP^Hxz6۷t۶TS)emOYsAá"#h{r 128HT嶵WԌtW&dcM0 L'#hN2qVeUC)fgNnzP՟Wֵk tmXin4He6L&5t[*MQ,_(cʲ9pZm%ӿn=p`1Vg %v7UA{j}̳{?pnve圸v/Uog[>@T]}6J( _y(` HFd[pV/@R  FX6S|BdBav=8SKDd L"LF `y:Z3Ntϔpp,$CVw'+%TԀZoMU 8>Թ0^:Ae^:+>XwL@o: ׎ du"CZ ^@ɀ2)=epU4-Sx5O1heqv {:ldqX']`ׅ/Go-zUf+)X.~<ȋeK\hþYNP kK+Wz5-ԫn4im%xkOƿ(z4w>tU,T F9bΗSg;G`e<)B,#Lөl{+s؉jzh⡳z3h545W-ZbmU@Uh) +B]'IՔ.BHv>pRT!t2Wrмa?O<\{ @#xV*.8R1&l",JOsnb=Me+)X8ޮ,mߎ>}{^p/\r)Xl$xQ@bnۇwU=dp7`ǹk늂R3 (+%TzjC&hj~y~ya2ME\!DCZitj v#,c̺.3@̝imVwW  Vt,yg<> {ELTf~wVv?:T"ĘY[Y]ͪ|DU|Usr$=^ up0p1UZ zld""ְ=]{TZ(We)YU(sp4Zd l'ɇ] [H2*kp5(k(X]Z]x U@\ֆN ZnWSu*hYʊi=U2T a=6]7U*,AV(`~C[ReJ d=9gr:/@0N~`Y]x}2в3-K{ÁU;USVI2*Ztz('Aԫ|| M[ȢbI!;@@$Uv˚Z9IpaOm :\"ֱwx3/n^]U T*,݇_D'^: ݂GZ>=|! AzG YugV9 Sb{̗CUR VY2oW`4H`նMRq2!yyz7WXP_V h`v ގ1+,ƤDubfW ' W Y~%mGڀ\!U]%]X9 J+ˌk0 O\$]OzQnZ'UR/de⮐ +F}O_"";Y3S5YSn[FYY ziۖ9-oK۷cuع 0[GD~'/ WӒ2eʁg7QPjp9p(ص>lz_850B*VDZ|t. dX/vDŘOmX"ܚv/Ļnx~K?X@Vcd*[?JbBK/9W}Sn?9uXA4+ Rq D&T%6~6^U䁚7o@Ah@fY|- 6LEZU{{dx`( p+]c)C=bv \)h@ -/l1"!X#N/FAM \9,Ͱ"P)To8ˌ* w0e) "4>QS쀯| TJdK!pK9QNZ:#Q yu=>mO /o[+ ?I~[E_-XE V] W9M7-/@ '#ՌS8F|+ # ێSCJbb`"27!N?_p|N;^t ,CU9MBhN<CVi#mpZUxas\; w?kc逽u ʄbGзs1BBG"xR*'U\|d^ip@oqF'p?;~ldV@p,Q:f"S&NfV 2%2R #&ROK8LwjCB'yIۡi\P <'ı5 v|mFPZ"ܒvUc>歲K`0s+ۄ#dP{f|+"\O81Nos@%'T!c[@3ޠκoDU,/p_O"$>1=68 䏩;M%c; j%Os]ebwJѩjU'2sWMb$#c--5 HOm7^0.U^9Ü|sҕ ֻS@6zUŭ Y2/i!EsNOX@nEs.nJ-axfǶ mL&2"ֵ;:{&}W\&&]sΩueW+^{/7nk="IfI6!ө䃚L3+?}޴1#&6ԇb+SƤatk5z1ň??@V4J Ȣ]1t: e˞:DH 2V`dQYs! 1vٖZX[\w=֣Ra>q7<}{du \6`55Հ{R2ȊMM}W AěێzK/N:V)B45C/ĕ@kz`Q*5,EN=s g[0g>-pȈGl=D#EuTe Wm+USXMc9\ZJ pHuO9WqɛW-*".JR v0: E i;&g t CU$ޭi Z$bԮչgm)Z$\ y͸= YyNͩU“U~#t4\R rUWdB L&XMu7ߴ[ v2[QELy9E/,>JrʹNrȢ TC8\:@Xw ӗhYq^KA^d f {ۖ" b'ž=󬳱㣷|NAV8p IDATYoUT*ʕAVsœ 0ȸ|)bLM&NJcwnSuVQ)W^"d/6e1$y裨3V2[䇤j 0PUI!MC8z,M{*H^+r WEWBQ:羬RZ!̪!'.{Sp{,scQP"1,M7t -m[WPVڮ _k|6سP-Fp]ɏEρ;0x`cw# 1 ޶L݂a:MʕB^+o^MKJO r Z6l^*-\9˼qmڇ4QҎ͎=_cߋPJ,*r 9,rr\ LvG˽730birNc-IkD=D~a'}`rNf uC `Je\+"/ٔo4\C&=sb p>~1߽-QQWb-Ҟo@\l$NRrXƁZ~|.c]:>߿g4ۀ*=Io]O{ D~î wd8ˋ&g!*ԫS)h`@=o iCsq+ru\:-.;f ZLV,M,W-ұOPAa<Ϩ,H՝ou<>u6&!XWFr}/(@Ja (tsjJhMppk:B`&S-Zd,K2R;X,=klKVYU ka.[؃? \#) c_u֓U ¸mkTG1&$%@MjF$ vg/-zL&upeU^ub@]O\povXVI~R?Y؀X^QgiX mLʨ/bYi]&'Z2(:GU8W>?T*+D'P^(Ĕ Tq s* @ܡ*VgOLuwr`.XBY؉`[ &y/bֳk|;U_Z>0uT*uU:2eJG*Tr%PB3Kej,à\q"<>w}2qWPUJ`9ol`bb;^e /e؜Dͅ+UXc@%pR}V{= 1Vc]D߹/)4D ""E9\}wqߨжcRi>Xx3W!;=Vy>Jg#s=BGد-C#=P>.<-vR/b6u~ ;N݉v_@V/ `Ta^oØ )V}J݅E%T4&<J\@+u <m# ţ_ČE+ۋ:}OVƫZho*]U5h$puk*XCⰠN9 HӋ0qO%)&U(Vs{SA.`7!\ v3Bv{Shqo,&I%t,Õ8WTQw2a ^,gm)XZؑ׽ >$`Xm3JV\߬a G}{?¯//wd,Q]);Vd\:@FC`e0`j8`8Y LK_kwVF[m|Sful^Y YVep{ W`j4BmLfM}W9VY,hwyuri1TeJ̩48n,G9qsQcР TWUYpu%x*F'#1;DXv)m$Id+xJ_8ރHcAH=NDV^塻žz.br x~K?܅] zG7vA MLι)G`1w{E&q1Yy'G 0clO: O}>m? f*qKϧ:LAE0G̃>\u k8 H19Q1\Beɂ^&Pj|l?c01V&{qoby69P%Ibda qj\Ҏ\I`*&Fucl3yYrgKVeZ uwm@e۴^dMptHqF9)y-q--G(\vWP"Tו**my )MXxY^8O(M(^ҩ_\Gփ|%]첞/\'m`$b-aaGpۧo z|tOY :VRXm;gT{uj2Mgb__6z3<Xam<ga? ¶\ уfq91#W["`ɝxhkGk5!_1W84αX6v vb=}YzU&Վ悖aȻDKXG^9!UըS$q`2uH~%_w<ެݒ nh$ 腄aBØUҖ E3,Ć<Gaf^9;6!  x1@R_UGf׭VyەUy3w?=sv3 ҜtC )_!*=)_F",f`8Zq~ږ>|øWt7̈H‹QõTK@cX~z~YYQ>&,a :KGZ ֮16!5&۰cSOxa gAu3ƶ]<\s=mV [\_ZW?Ap+'ނ?|ↃSBI%-Ȍ}JL0Dr uT fh{={U II)m]!Ab4<ÁHRbZ|:z|dijtwn~\7D[Q]ȇU`XYs~w5(/pĻMG>O\*3+q"owbf,wa\@S ©?vD3Vƛ0ւ)VaNZoq‰7 2WaAga0كwKWTgUKclƨUMF#E0N(B;y+)ȝvqKPraEJerղD=Su=55h.x`ȃF܅ JJءI 3! qw._->oT^-Vq !-{ۑh+2\XͯZ-7| ǂ^;EZ,!p7Dmu'Jrz|[R!B]'d L&DP1/viR@5OAxڷ­9fqNjFX߉g1y64~[κӅkZ.BI7>"C Vr/$ 1ꆱ8aF?\҇մ*U[h$ *Y6V\d08j@0MUPPq#ŏ;Aw Lg`MN{ԢepXz?nXp"M5aw\q%T$xo6KZ Q %&3xR'RMu-AhiVTփJw'O}XQ ^>Z.>+k\.իRŊnB-KX\S_dn jCUn͌uXkn^b]r86W+bQ^oL u9 2Z]V ɅOXwۖ<*bzW@:p5&,` ܗt;m8G8 {>ミm࡟.B EX+PlhJVL gkJazQB]KND_@,Pt{޺( z8h_56/V [{=fm + cs~U&)d2rcf jLpjv %rIknmEv E d%w׌4=Jt Ԓ{rUܥ-w u%U}2_G1eCoG8ǹp`v//ĭ,+Z|~ǕW]@l)5j_TVlهj>Fp |#%QB=A .{(ŝf8!D'o{?xW+X[cAlPx,}S(Xe__c6 V]jjխI % 2MثP>t_ jHzuJ1,&1p%G On>6ŠQ֧M:]g +b_siɝ܄}d+NEso`WmynfoK.hW^oT~m@m[׬޴ (̕ށK-0@h0 V-DZ9Ll/#~.'i)Ϻf9*n943b^/MU89-o=dz~ڂeY 3V(f0ӋHј_ma;$Z$kq2` d  SN?'QtšPhOQ/Z 9+Z}Ie琵dnyJUs/z;l4/ہ[,~of.ݵXp]l*_g~ӫ>xbj'7|1+Fe+^ VCb#ib"sol&Bt@te{xݞ+\ie *.͗UWAcbKԓ ?;c[iJ@#p -/.BԜX%uB^FMm^~mgUbTMM2OQ^o3@,PYJmQ ,(|Z e#V$`cjhd$Gևp)A\YqD;.-^*rǨfD@=.OsU zTU*XX0r1 #}]~XTZ1KjIFZ•a* s9y]1oWئUKr<=fxdQ_M~z:gRp%jqb cAO\ y?ųRr7L?Ooⷡs(q3Lg k.X>Fh'swvpl~*ƛ: ;& C3 `Fȋk;&L/^y8S'W" zO<ϟT25^hCW_L'6$R,0.t~.Zvtيtz;ضiٸq-7 b0__r\;$*B8A;uqp!aHh"3U .?k46siSt) lO XYlLg?yoOw86P-e1y`W{X# ܳ,pMcp*pHHs6X癪Ss>Pm EVT1DG("r5\6 -"8-oY";muhc^z;wO=0> Z0WA$Q=КVe. ŵj(kCRJ̪y4`-e/9I?q0'@`D Hܨ%~L1Faq  l~(H%.$, oA Yݷ&rsڊXhE~o/]s37t CSYrq;Adp`Zic6$]V볟% bLL#JTUjV q\$K5y%K2|!Aݱ`d*|,bWFd^Dc vَow֝y@,-[EHV9W]Y5 M f;T%" |rFUZJer"%cw7 4Dt;/]. ET8qGnY9n풢Cg}`A TJ<*P hvt5 #?$+t7}hS Kq"K<}mJDDanp~;dkhjoR]صgw00V1`:%1VPːPJ% $ňAffl:^xpF0S%|B '#2x!^&.PVۋV$`M&Zp"ųQ|#ucӚ@RLk(h\z۟%WX]0EJHn{uf&-{ub-d+C^0[HCR#ϣPEȮC2l.TjAUzuK6x"jeweUGJ>/b@*kamէoĮ~yl@V$j*Wi6T*hΩҞ/80g,7-QH3 Ol$flS{-|)waH4h23[o/;l'>_oc1^Z#}W3U1JB;V58䘒]6ҝZb< r*j 1UPϔCR,kQSkeVTJPU&T|Y#Hui`Ս/RѤD\1@UYT X8ЃܸS^ G{A5P&-F95 lO0u b8!iE T,*0'z f)U)`bG` , Q%=,9!;$kΧW2 i`AZ#8> ?,q̫QWu-O3۶\Fк&1aNǽXoۡ__[tX9xC/0(cA@&!CɇAIttx"yqjI 1S`-P  jN4X ŏ-Zκ6g=Fi4Mӊ W"{ϵ h4k&Pi[PYVFQpx(|@p3 ^[#mƃ^ރk'A`/E@$&T k( Է;Q`Y+ lpqc!J_+Kތ㯅n+.e]ɧooCV̄P<3^,A*i Zd=r_!fG%} OC w+1T9 FHAk4;S]UW~</G^I"~@Ё)f#N Ar:L/ @㤘vc5 $O`"&R{FR ظMT Ub)Sކ %E4Ji+\#T5]ߔE*K*WBr- m% @1N yd@0$ؗ4@u.;`5 \UC0PJr芳R%c1V%TE wg=!Ljd"PYկ2skg|H';UCp{H%\;Q2L<7Qjp@CpY*xJg=0d^5tQo c-n Jp|k@g zzinz;bk( hWz;t冏*+8NL" ByWɒ׿k7뿁\-E5 VRPmF,=+B\ p/UJj8*!RȲh-3K*ի%X*W%*?ER 0^V7I@>5yh_l{ (VQN,݁ hs!AVpQՊY{sop 7`Td+˰bMZu\B*VfJ NvHq$hTed}3U܃2 ̃A?'{sg VP}#1z'e 7#tyV@&BS[*]e}!E"C%P&]VڮܮYt VdJd sI-@`T];OMyLOY#O}ǮQ])u [L!<¶&IR%K,.Dۏ.(ԥA 'SAJ\[1(S!+%Hiݸۙog'ȴbV>Vo/Kԣ[:<я@!MU8_Bp1e g-c 8S*-@QyjBspN~XUi'T p. !hbWL;@U,PY`P s'aYܷ~D_?st7,l1ɮVE( VϹ`d[nll-(8w̄=QLKέHk"x>vA N;><5ztˌd{X$V+%Wojjp-7o|W]rQǥ CsJs^s7 /jVžw $fo'՗t#!B_*`q`et f"d@#c߽dA?'b VW9sr-;k93xUưan@(XY T`-`NJ4U`C@]riZJe [0!D-cR6tΗi`$(tF#k"|`DRQ'ɺN>:^c 9tW>xIh$j,%"dd4BIғ0NL}0X/ l[ـl%RY,s?ŹNMG!ѝXBw^_xշA,G~#ߗJuTUtV"3U1[C,7}}|5\d xUA *CUeLl.f#0v…bmG\{O>b!9Fnl<.Xr|{ufa~V\AcllԫFRJJ*kS :tv"a<`'W2Ç qߏQImH3I뭷}k6Qͽ1'A$eg.2΋.MX=>mp.11dheV՘ U-U+`DbiV@k=6jdj(?rl͉'JBQz8?9w@eY4hNr7%SFECW=kz ]r(rαǃqƚ R9bM$+94]_ lB pi~y%(e4P;#H`dXX<D@UMH$=(׬ _[рxlͽW–>ohNN3 ^׾s%7vqEGu,pbKWq V\. |C+.QC˶l> ZY߽wo= XpESܸ^c&i2Y}#>pM'> G:2y<^|тTuimu+_sTǁuZC+Vp5 sJ7~=N3~|cnlRCCғh]* ~N`4mv.\w=>v ȚUz6T!=w칵n=8 OWk>1`jt*a 5'?{E?G/xj`j @De cNk\G*zB`_Bn`sDjL_ 9{Qv<޵$͜Db+Mb]$!u!B]`Q]=A#5dV^goHb'L/Z{/T,TŻDz;JmEdz;ܷ__[oYVd[q Cw()Y2d{jW.R*cQZ5BgNOV(YIj }i>gE97/ª}1:aRK)V+?Ũd iطZZY*F4y=^!%-@ rġU=VTs`>ܼGXHbbݨ.? ~|"lV/۾ۊ>{o]}Xw wTilƷF<`,uw^*'˯f/? lm B V#[pUB”~wBn=)h~aaIM_i)V9'S uO@U26/Sk \:JQbŝI 0TuEbP%G.]Q xw8ݓ U2•.\sMS$]TU۠# z[ٶɢH6>ծz,ލ~{hVPrvON#N벬G"czBj'WZ ]UōCкF/V`{O\dY+|/ɻBV{V՗Hxn;'˸&^/T,BI 2KU2XYZ;Q[ I`{S 6(UZ$?w{DpCd$`™܇co?k͵UҍjVڢӋϘ} o8K+[t Yݪm[TRZµD'gw;J =) cS㮼7p}`z[v p!s2sC r"!W$W*VIf#\{؊' @g[w rGq-7㖁.Tq!IŴokSZ[v w0>,݈U|\t)j Wc(e*!F_cx̱{za 2+pW1z71h{6ی/&/oB%G2mJp59Z@ԭ5(0H\{wNriU f؂`wO5(VB´MqwpկP-㳊JG"z_Go/V<`՚tpMƖ>&3 O{-ڱVqҺ BY=Q9tk|Żۀ8X3+ZcƁ4x GHnI 00yD8Y WBD9WX*ZipYz{MmV=qAcxч5W^@-WQ C33#gg-~Tdʍ%HTD_$ilQ{5NbG@v3 \dp@5Ȉ9#{`@dpOww .BU<.\Ӓatee2H@#hY TURTily45BsZ=)&rKLۑ(1 VsD*Q -+j`i4hb.zG[~>7Y#Ȯz {h)7K9"ަ*=G+ u#Vzdu.9xGh5ǭùN &`݇Jg茪B L7C+S4xA\R0jQi,=de8K_k] ko5ύ:dYL̟C#\UW #Ew3+,'%2_h5V0([oV<` h4{0uǟx>?X<0dwޙ,Nq;*[0k,&]pEi`d& 8EԜW)=#'PcQ:L`g; Kdq~{+j1zgr**Xʀ*#=ї  x Ó1u`0UXa| h/"qJZ H`~(E(xR&'%'zw[czkyKq ag'[n>ミX!JB ʲTB)A`t]u B}c`P *Q|EJȲX-h`}*0z=ص@!&dNE#djseL42JV`jYBJqW V%l@Ͼզi X:03 5d4 f׼\sGT-#Ղ٪7!v_6[D9$Ro s/ݐ >lV=`b,Mo p'5}C4swPtꮵdaQ(+@ ZMw$h)R2PF+RJ*\U#0Ĺ4+o͠ax?F qTfFca8650wÄ?h]ZZcN5-.$ȼ]L`SU-U1hM~$`x wv3@Arb_VGz3x6X)$> Z[9o .#V.mT huKNzvXيҬ5IM,Ɠ2($vx%z7v>,n嚫 (-X0HS K>q`/I@2 H;P5zcj,"%%+<,:Wr0cS, Qi7' Ե(Z 1?,up>,xvj)c ݝ7ߗ<74UEME>NT%n6m 8XU^EȢ/eujYJ2; lvwDI¾JkED/t @o~E;&^Gy?d]0U+ʛD*e=`ATVc8{Cz]Hr3n7q%LB4  _3"\ԪBUzݐ(W[@.SxRu4&s!KqEI kQa߭{Uy,.?Y ݃۞[m0?eۆx?=8Uh?u00UA U y (XAI"\Eʍc= E2sIq+pF a[NY}I-ڧX? DX<9._([K)x +[I^3FU8 1b8eҍH~ H힯<Ko:8J%h¢aM(F@Ey> FAy" J2:j(,= YdƬQp{1+YgX'ScaN-4;u'cb!ZǩU>X"`g eV%puo ȇ0/bѺSұ/5cRKUV%E71,qX-B*r  Ar&ɿ 8V|Kńعk;vaǯ ®X38٧pOcnOQhn9BV%IՀNw,W%`[0XQUu'=D+ +9nOT}fnpʏQ8+2Y`y)\[ viBR!@AgG`)?4k`F$K ]fc<",z""Xn#_ [n>aݍ7dQf KP7,^C+j3 (bRC-I=KE9RL80*f->Bi_.سz-~xx54٧I*F|C;W,b#AjEKnBTZE$=Ӡ bˊ㭃yCgi{@IwqHJ\+Ԭk! \Ð<e2_b|*>Dy[Ƙ۴j_!]Fy7cH=R' T+;UJ5vo­|NVI$` 8FH3Ҁ]'es9AFd:hmqYx/%w/q'Ptn<p“knz"\9 R% 1xkzI ^!CU(㫊NN,).hAeb\C$`^z @)Z*=s2eWEDF 3G]sx'~o @UVZY}PBJBUS(V>\9GhP7Q~V~<_+45\hÕOjgᄀf] ?j@Q7Wde.d |e*Wu VAPثPKzJmȴ)FCQ Lp_soyu$Ἶ#Q*%%/Y!*\(V+!T=\0C{]UF'e,Y+\pes{Z1&9>Oyok~ 6O4RlL3CbK,ؘGbVq{%1H! FÂAbjg"bD!2Fz,`ٖorIsX͂<߇]3cG=8z/<$'ض*㫢l2;Nfy]88஧4%ҎfEq֡'FA,4H etpnNgԲ:q@-ӱa0Ĝ1f\\kLB,Brj+E(-~^%?_AαM/bQԼڣMD)?bVic F2[_Fi u u6txKurdb@0ٔO U]JH?!9•|L|XDR$1x [O@* @ca#4򇰀F a60;_ lufΉ=]o@}J`{CDPkXCP_C˺Ep<#GXE700-glŶ麄r1Ky`.˄ &%`Iœ՛zEۑo+Gً)paCwg?[n(>cAҠU+1.IP}.>ruY[ xq65iFw &u%/Q8#~aPXfI i9w^& }m Y`Dj9EvK!_ *]M&[vF9F ?a8b0a87s" j(hcu^] j_P40V]^5ZXnB"Ij \}Yj6k^fV'4g!_iMs_-H]( \Q\}Յ]`[ct24#e@ZfGA`8+MZ*H}nR% y\|Vl*?yje)M>_gF9_ ,YGr `*% Zw'$780ZQU-%Mf2c %ex#AǘԄ2E?Wfvm۲U'r-1Jb97Ucͽ >S3fR+5͐kmA_&leo7x&pr{pržFhxr%ƊcfH^(- " 0*TU%nBkaAxY@I c^Bs>R^Gst+ǾJʕI W|9a {YXjGsUr p[׮z,J߀Y7`#¡,JlW[&0AOpX5qcX[T{jE{vu*e-SV  mKe݁Xd{v昬vc܃E kxp퀺I `zGB`4*kUb4&Ȫ,"eQ:4 Z J ئR4hzv:kCuvTYXj\śSzi&q?X:8`߀ɂS&RZ h b|U㍴ B&* q";3} ,|ҩ ةTEB!e]"P1D  p~B'Ȁs^u eb]VƓِA\l\7WQRt^` V 55J_5leQi 2[ PYPEZF: ڕ2hNe|!U[0>lx~᥁@aF7G]4qVkL(E87j2=\_#ܿs zo[VTLg.E-T+KiwO,냨YK&X5XюR:jUa4RRXk1"3j<J+/'waxjV VӀ4)jm,江UK7^qw-op`Y{o_ @`9_REY\U!t|}lNW/a{]ݑ?ȕ+Y%Q Td\"MŰG,GzI+GMxb%J6ݎh+ԐLB'Ċ/u,3ef59^ %W^.8ԾQ";!IJ%Ecf%9 Gbl_EU=w+Dkb&Re{q"yQ'Փ5lHkiY,"8n]$o⺫$cuf5AaeMKlR+et;s)"BsNڴTȕccv,%Jz1T)$DN%bl4%II(: OD‰K̰Xm쉕-VT!W Q1e L [",Pf+W tQTZݧԅl=')צIfkѣjګ/ZBJ茜~/z$UƬHhͨHB҃yh4Sjb;ֱp㞻}=\7[6dAocf)7BcLԳ=D+W< jg@U0\BxJf ]YB$9%>z J#X? yCψIJ KI@ǡ~lȓŞgŧZnӁU'c 8sʫRD$eWOtFNm"orD{:LQoHv;Ɉ{nO [ e7]|-UYYzoi34Î%SoK,ٲv*yQ.R@)$$ʕ9%MHZH[2pS9BG.g( cRbp/clf]flFaSU1!wc>9t ,_Sv`BD v;M%B(!$KL-mZ&!+"Fk<Ǎ8mw߼'THTu{:$Bp'@%ӊzV(_jCDɂ|hf@BBjHZ'~ }H.Am@LAw3 eEac cn5@h$ Q\O(L~ .?:D#Mj5)w;J'!4krhhdH"NZؽsاTX13~x_+))V'ZDhTD7G<+> Q)gHU͒^Gh@PX-&f : V<ӒJg k r͒+kvA[g$xbK|#Ō'/6`R L@Tpe&}5@.Km`;ZW[f1ː,Gu(%bΣU<yx;"vy|m=W\Zð+6Gv1[?+mH($ ^BݧC`\~|Yd#) BKq!^RO ,H"V܂{I>l*[Vػ+Ó ʪ KKs*H6Rѽ }{$UKDŽ^cU#R\!fE>Щ"yv[ .tKI^9e<"4ώC\(A]DW#>ծd #CXD]2aZSvJXؽ<0UޅAu:&i-XP) W"Hrb^gn%Fh4@Ihm_> F5B5=փL-7#0U*G Krs6Aa <4,0W2Y9 B,b) Pa.,}4[)TB?`Dc *YVSILGdĪAkp|X*V/Xɛ -SK5_R/Z՝b+W%u%V%eDwmz ށs[e#Sv_c?VKUQ0r-K,gt3"M"ˆ*v1k#`.S4Xvq I"$̑ngs]e&T a`P|"V\A&IG ]lQMmwߊh_?UmTͲCgr&;CQrWe[~10ZYRcfpG^{9B}9b$AV] 嶔 ]y( E!+`+ XUȭHVn/۫QjCMxcY*ᗬ # ,*bu}'p+e@-xdek┺Tʗ*Ucb_x#}o3%TxryNGV sD{wG9z9 U ʋ**,G:] +Kd,3PQ+>COP gCHʂb瀱d˕Y}lr'V\g \TtDՃ,`0j5*!5H"V7v]z.!Y^,4(K},Roz"{>Oa3ipOzZp1Rsh]@v(`v[HK c&/p;ƻ{+9Ve,)ӕ6Zm*IUQ..=8d V>; JYEʒ'WP,z&īLr^BwEęHzsVIBku5g+2=ظ _7zT)TUUOyЄ$ɪ~N+\ aɗ !Pbܶ©Vdnt;@tl7nx3qۗ WE*U ܪZݜBl|lKin Z+K33,X:R@0]@w,՟mD2Wi ԠRBQQk V2͝02D\c.5>| ߰lZ\J%rzjPf ^&UY(W:m ˬjt;] ,xcoѰt% }u@4sFwl* f~2 VN D8ߍcwBv;+ɕ邸9( @W08TX\*B[`܉cZHNGr6n6n=;7I#0bF?9oʲ Iߖ_RtJũTlvZEIXHR:2(iZ.IjIβ7_[6=. h]W ݼʷN_ f\) ol1^(TG0!{a,NH{Vbn }x gy,YȰ2m[ˑt`p!uYGTzk%=IƛHBQ0f"X~͸?啬% ˫X/rϧz#O;,.^<m:kp\ȳ bI]<͸ZJn7&z*1 a09DHZ Z\JBZ~_y^9tjյ@w0)V" |O;N4) i37%7T`7`fsʮq0qv_Vѧ=;VrX1tG{&䩒ݟhq?{p(Z$WHʘVAٲ.QëW&2(J@񣷃8 Ulgsp3Mlv{g=?% %BZyOr$*E6G)XeM̀^.j@֓ףZ* ˢ=Hz`Nq !WZ3;?hiw܂/~+n—g+wZuI+'zʇlt V"vg<#wTx#3+)"\@0]ؙ},n^Dx{c#(Tʌ2b{>Y[Xw { 8%- )* vWpY<2Trv^E >#I*!ONֵPjf-;x &ǗnQĨ6r.-yWTsaˮ/!1.,EV^b28ңOlO>.$' {|V\O(r$IQ%GjlF=1ɶ7GDnxރ?|+cYݖ/` XQeʾ*i8nGz{zBzೳ`6 H>WH-jR泿n/cw;ތ^*$W Bo/%W*$]) oOH9RE0T!{\٩bxnȢ="ꃓ=plF#1H"]\__ )_/öq6~50w"Wz ;w1Hk?&r egG+ߟ;9GLo)ϭ+]qLnͰ3Xa?Pzr[ G(.p{x/b,X= U9KPvF(Psw݇Qz *37)``.W "샓5:@LMc3܂}{ďDmڻ˯r!*<.M hXU3!"Qt:(Ћmkd7`a <.c'SY!#. )Jփ{~ Wb5{3rbw>r':Dk@\*{np*?! hۨ?hj{, ]!Wۍ&281Y? $DT E#-r%R} ʵ&M;\,㖂[hqЫrI?5ڀ `5hW2!;Wã $i"7X Vd]Q`6D<37C݁{'GUOT&Sx(`il9pkPHmÌ\k:P,ђOT~@ d] ˼zž)ꖱjX/z,rʕz:O:┿0~@ .:3KV!vbqлh4& 2C; b bZ) Y*vڈ8 "7sP hCb< \Dę-;=B{f[ch9y%Y4|j uN@($~޲S ʗaF9k. |k<Ț S"/|]ΟLrX5 5D)%3L9[s6V20I@I"**eJ/X8^ѷeN+Ӓ~N Ug=$Ͱ:2q^,K*W}a=)9)LP$ "J`bkt "`zǀ`Pk Lu"kvA.[UQU K+KpO}2,զ#W7ɶdf s| bQܒ0wX,.r_V VY^7/ѷ*Tl-(xxØy;] ^ѽ@ qEb .˃sPh·S_k"I`1&G#u00Txd;8\;=4v]-JFTO\{z+KjثHYUpljŖD}*T#i`XVr10y&+-AcUT?K=؛gwaU:_,C>%K2u HEfj., * hr9Ʉ3{S$Ucl, FDk50TDrq ؽ|2PB,bY?VX9rrBbZ{\k7&.zU Pt:t7%Br%Bc4_W|?9_~lzf%3vo yEN}]*W(rʖU1}MԫWM|n'V""QZFcBk$W3Ƅ߈cAkp܂?mw`KbJC8AHjɃ%P IDAT ^,1  Zt)WUJ.˙v&)d"Z-f\"MLŢE@IGK-1x  "K `l¡ 4݄7UT$A20 gmȾm*V8.~zI `U1W%FAG~f'M139׏XۈkF )tUku0fH""^"8|[q %Qr._Zx\!i,"k[s@Vr4 ^r/: T"Y!+R~ԏct "t;#^2"ZgJ!ͽL-fNDqu_V|c}ff'b3"p)Zg NZQnAGs(rb9vj50j)0jAJȕKI(rX1|'jEP} W:,+lUO\9َvF P#b,jS "$Gڧ-~/9hVSȺ 1=8=X k#7)65"`a>T$W/. ;x N﷪?>=rUfb S\zՖ;E'  !_J5(1xuoyߗWo x+o/ 0Yߙ]Xvye Aے_8P2G ͼքvSJS؉8D %ͽ^OABĈkv7+_RR$/}$bva:KyEZA5<+ժ\e6JCcPhBkD ^Oqs\M*"D߀x}HV8lseW83O=L%1h KP'\ 0XrJacs|@=%RFb,"B`[eU, p* !Qdޒ2JY%KI]c~'1 9_^uMi/!_,A.`f%$F-,Ϻ*v!W54[)0'cE" 20Z<4UظeJ),.\ED$s  + S7\vJ,OʒaS _ K=AT8I]UA:B(TDYXK+Gwa~P &oЈ\ N3tKx[FMZd H`ݶI+  eԢ*Y6AHUJ0 {Js:28ogxb]ń,[>|WW^KtK/.ZG#VV 6;|ӯ[TD9$$)!*D9ee>Hׅʗ"_A9rec!AE2jqTIV Mkg*l(xNU^Bѕ#WZH!jř/`-K`5M[.phJ /"MؽfsjXBU5WzRz* +e9OVZUFMn'znyB(NWD+)Ya (.3(Z }W?kTӦxNE#̰*mum З YЄB#WF@C爗HotW6!)t:0£8sN ރa}WAiWh9$K=JU4;%*J^0c06y-ϽۥɩK*ZUCS*G92(!TĠ- T@ oV@4{ bX"eΓiٙ"dB!7 ]իHOp~A@ٳJIcJU"¯J--ze+q1Qd%/;J's;3F-~*9/9"¨Ald*U' \?R *5 0vYfcl!J q|[('$1 TL @ Sg[P X`~É8 phQLo!jM40+{nn&(P C4 r=LZ$YRrhKrjQӽ!׼:ԸKo<,;,A$`*TRL f0ҀZ`0uG;s#޺2YVNJF#x0'`02 4Po$7` 1?GU+"bp>߀G[9,1+($$K?y.?B@}:^j: Wei)S{zy^8{1n^D(( P)PS@RT T (-MI" @€5|`xy1u_ 1Ahl8ሳC)f(rشe/m#o8rˆoX~faO?>΃ČakTf, JP%$[NeKk,JS FblBcX"BEň=`'ǟ .xoބ)ϯ~o-1, -. dV-j:\7&Wə+Ae4P\!PQ@B$lg $ `lP:2fq(W'`Bs:OLQbc/ǦCFvF}`?CW]n![*= 3rSncX*siB";gx{n-Y-QҴY)iյԒĮjQ)(G~!$l8"K#\Bs|i1X 18Tp?|.ry#" L|SؒdKِПbyW_Z";/W_{O}84Ax{BolCDrǒ@yXR/K8fr0 l,"!SZY,Ozɘ[OA U[ rl8KԷ8;!W9fLw03-[5)%Q'u@t y%`ץ܅믻a 2yoڗt_z5{q}\SWe}BJJ$K3ؐT I; 81, E^Y J⠰j#WkeD`N(q@'x5qp^E:Dkaq! >6汸4)65 q֖hf50w}R1$<+A~5@ +2Ui*S@%Īg=WN2>X{ "(Vr3'ADW2M^7#8 FiLuS3xYLu5VO0:9;Fp17Q~gs3&? /;<gG%{d5lC dbqob%WW6 Ƹ`T!R\NĪW 09e~{wK*Y[ 9f ""O#fKd<C5 6j00XjVifgf|O`ֳsˆq23 m׼B8m1Pfa1 S%pa, t ic aaa$+A˚73( b bl/`ĩGTNSt;&x07+Sk[8w.|zl6h8>)| էh uKT`]svW ׫ Yc&$VoJʌHg0 lr)*[s2ٙ0, O$FQbuDOj *XgfLOu0=U准H02Ȉdnuf;X\i_J&6n7ބ/}?\14 ފwpgFn|$:UH "Y $S}TƀL!%M@_A22"r羯?GxV ^\]k`X\ȱf 02P Vfk !fs3]e|iwpwᆻ> <8B@qJI/:o0Xa)ɪ>օa %-CcM6GlPc'Ge 9c OVTD(#wSeF@;Kϗo7b IC$Xg8Lc:^i`hQ)M4160af y#.v]z: O}߱kG<" cg! a% 2'!4SJuT4J#J-@C+X·xZye HLby}୮"l<4Qϼ-""b% VDs]vsshR 06BbpHBfgͰ0gD=7߃?~+}#fpˇ% {MkT~=l551]TU@ʄ`YK=;beW&iEexe@l.c9ZmJ16իG4G,N6|l {z3]n?W܀sbd4#7CgRYV~JLEg/ߵ!y]x3;ے )`Ek10 vng@]: /qBC^IaKtÇ V1AkL֋GF602Z姧;XˢQ>bミ>._;PzBK|! d3P!&ҫĒnOʁʮ'J^K~.19Y3XsI~ B#aV$eff%Ub+@AJȵ<:&*5N,ؿ/#V`E4߼ct:)@`vْED677߈ Tg%)/PBL4fT0+w_]AkE_,g ʄb_"2bjYS*PB41ٛ0krd)JJȣQR4JAT 2 6ٗ{_6{fvGQ"N@]E$ Yp z~`iqK0uۖ00;s % c@ޟeݱ*W ,[d͠n. K(V^8ʕ"i5HVdmY $"/d< sR~DOetyЁŨꍯ)KG$X Z3fF:Gk^O02&6bnK9ڋ_bĩ[~8׾kO2K8Ty\OB*fh_?Gq{zTaa\ux/oF1:\G)>ڍ IDAT[A4AwOQ`"YƥVc@B@yw6x00yShmlwp ]h\Cr|Q@g@˺aml9OGB(}̫3\ V*Aidۘ:,F:&nѐg1?az Y7"N&|=xp96ҝOG_RF,U-ĶlH̒:L}ȖŖdꖘމH4P0#Y[d9R`Gg+_!`#}WUmvUk\`ERe5.>]q"[onU L,:6Llw}ODrYRwpw%Ab4ANV(, P, Yl0G)pիk\`EŇupD ZpF aLNw0;Tq|hu'o SO`{m|V 7'l**2X(+T#p͞ErNtU]XJNj +vċDf?6S+`m9G Q>ͱV V3LKsaiL=:D`t&.lpsY4G7l?xg7y7ZS/Vg™b'RD!UPh+ kKȫV(XB$؋ v$lOD!WL2 YaMσ5?o'6lc{WG4ƆAɽ@"XpC`f 5PKrVgK_tm?RI@YaVHxu u-uml 퉔)ed!7&U摔x&f2~$ [3/F͋5AC$X dCQ^V4^A2g3t0=Չ%cNxY/9~tI|S=}& uGd.`o@eĩ:$G?0iyݭV U!WD Ɉ(3r+ NwJ1!\g?C#u?#V?"8#^qwlzvn O$tPW]V!ODRbQȵNg>$I>wXX[+""@8|p.- H|hSX8eyO 7y7&spDB|d!YKBPZ%e@Vb[?^0;Q1yK)er F9k8ƣbycMB$XGls҆c`->)vDE$XLjŅ 90$QcbG$Q~!l,f&85)F̧][M?zzBT>i+\3Po.m˅r>|yRl=WB;1k5Qgmblhl86K~_48M*"8dO>:LJb XF&7ڌ^go^W_{߸ oYxWmf!dڈ7Ke[3]1^Zh EA PrdrشeCud]/\ZGh\~=$`o2TISݓ,r5;r%YU: S!Ҟ1 cll+'DJ!/ nkC_S]"LRs~r\3Sj c0"#j:CQ~!Q1ʯ860qn'vb dz;}ؑ}Ζ RmfѝC |*OLr\k"_dVU~j~ۧ'ۘƈH""N2fKH0&G~9g(6:Ke և>G[{wg}pz߽O-.HJABBN$MI;N44i@it: )d&\RRǔ8` IֽV{jW]$,:όб GŷәjpNT8,q8ϰkJrBynQ@Ud _epIȠ4}! Yb,"&Lf}Y?DL4 9*sJ _ omRYiAWf~0@EQ0 z}tC5YևQ(c`bsqSTʂ+wPr@i`_8/jsr%&Ǥ],_8TyDR#>B/XM8[NnB9,\O-+L~?*n-z{WBɰ+XwyqnMT*ڌA<{T[j!xj>RjG:1z*J1zvl.yoe_֚D&=̪<\LMp !܅D"ïNMr1ΜLn%`쿺m^~(Vp~׎oMj/䣏r/>٠S.X=^7Ol?s"^ӾVJ2GL6("[P!_b|dFNІӭ7CF!_OģYJݪknR8#zMra"[<چ @,!92YN'9I?=Wģ5hLkeC6~|'޸} jŒw*xᆞqDX/V>7(0t:YO8ࢳ6(MJB7T*H357cV.Ո/DD?w~$׃٫O3-=~<ӿ8` !m:PZxgᥫM>_b:':e:!?DǪٸOpӴkAV]m!RxCnAnq@.+q>fSm~'_%Wؘ eLbEJ23 gf͕F&3n݄@!_\\r=tC7tEǿ=v^q`6<ѩ?S9TTҖV8Z2XB5X 4pyXUwaDD,G,%ۺe2t@1,d?7|, w8zdMr9ИKsK,B,ɀץtpjV6 LX*K"#>]QWm[h  cU۳tq>_e[Q럻n~c%A(ػ&wU+ͭvcX9 <-kgppjJseR^V/^2XR"B4L>Wbt8谾T|A jĪin0(Hzq;׌oѷZR7OmnbHe 2^ҪńϩqXkZLrb$!ײ\`$%,!ĺdw Ra5Ƀ(LLIoFDd=?1zRhpa|{Xnv{ w/&S5}%G1!eŖ9~BlY\#Cz?Dj$f'Ԧ7'y&2$ p]w~oT8gS#g Wyܗg~+ \R"Bl*ѩ,'^̓ynZپUon犃mnbNnGeivjc\;}@n7bG&uP b+ʤ& NI+QUfKP>.AT,7j_u|N^zκTHj%?dIG;=6F"q?<4n7Lӯ1Q5#3M] ,!XD,ǩ10lSc$b9N };|7]jg|çR{|T-`hنǧR*9j$%u0(?1fT,ssڭDBK~n7ʗ^?ѯ}[_&| zvYi6mNr"ïN:p(..`QJsZfE&F\bUq-q|_k/*\X @"cLۅx ) !*I~u}z~<"TMs0nlbtvs-/C?k+>N n1) z$%kT,3v6UkTA@ U3 &%D4wQ٭]"ş~ }BqZ:VnXdI|6U-9"t,t^ ` !S*N1VM6CF;;3>}#xAzv]l Pa.?(0t:̴4 q!` !Gs|9UBm~gQ~.?~W妏W݋r5 P˂ϯ2[,KiPe,!DJ23r3'DRY/#̏SQR'ʷwP56AшdX&ڬ|BPPQSeLƗ!IDATNfG _Rx4gFsp!6 ) !13]`fiQ4]z=e,j@^yIJB\ b *LOk5B`ŮGVH` ! K'^}~4#Ӎ>XB!e B\kB!oH,!B:K!$B!3 B!L,!B:K!$B!3 B!L,!B:K!$B!`釾IENDB`v_sim-3.8.0/tests/exports/planes.ref.png000077700000000000000000000000001370110300500225262planes-3.7.pngustar00rootroot00000000000000v_sim-3.8.0/tests/exports/ref.res.xml000066400000000000000000000425661370110300500175760ustar00rootroot00000000000000 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 0.000000 0.000000 0.000000 never 0 0 3.000000 4.000000 0.200000 0.500000 0.300000 -1.000000 -0.300000 -0.900000 1 -1.000000 0 0.000 0.000 0.000 1.000 1 65535 0 0 0 1 0 0 5 [auto] 0 0 0 1 1 1 2 [auto] 1.250000 0 1 Wire pairs 1 0 0.500 0.000 1 0.823 0.984 0.849 2 65535 65280 0.000 0.000 0.000 0.333 1 0.823 0.884 0.849 1 65535 1.000 1.000 x y z 0.160 0.538 0.667 0.699 0.800 1 0 0.000 0.000 0.000 0.000 0.300 0.700 0.750 Sphere 1.230 Sphere 1.170 Sphere 1.000 Sphere 0.500 Point 0.250 Point 1.385 Sphere 1.243 Sphere 0.500 Sphere 1.250 Sphere 1.240 Sphere 1.250 Sphere 1.430 Sphere 1.375 Sphere 1.490 Sphere 0.600 Sphere 0.500 Sphere 1.225 Sphere 1.437 Sphere 1.430 Sphere 0.500 Sphere 1.175 Sphere 1.000 1.000 1.000 1.000 0.25 0.25 0.25 0.25 0.25 1.000 1.000 1.000 1.000 0.25 0.25 0.25 0.25 0.25 1.000 1.000 1.000 1.000 0.25 0.25 0.25 0.25 0.25 1.000 1.000 1.000 1.000 0.25 0.25 0.25 0.25 0.25 0.600 0.600 1.000 1.000 0.50 0.00 0.12 0.50 0.20 1.000 0.750 0.040 1.000 0.50 0.00 0.12 0.50 0.20 1.000 0.800 0.800 1.000 0.50 0.00 0.12 0.50 0.20 1.000 0.300 0.300 1.000 0.50 0.00 0.12 0.50 0.20 1.000 1.000 1.000 1.000 0.60 0.60 0.00 0.00 0.00 1.000 0.560 0.340 1.000 0.20 0.70 0.10 0.24 0.15 1.000 0.500 0.000 1.000 0.50 0.00 0.12 0.50 0.20 1.000 0.500 0.800 1.000 0.50 0.00 0.12 0.50 0.20 0.900 0.400 0.100 1.000 0.20 0.54 0.69 0.50 0.20 1.000 1.000 0.800 1.000 0.50 0.00 0.12 0.50 0.20 0.000 0.800 1.000 1.000 0.50 0.00 0.12 0.50 0.20 0.300 0.300 0.300 1.000 0.20 0.54 0.69 0.50 0.20 1.000 0.200 0.200 1.000 0.60 0.60 0.00 0.00 0.00 0.000 1.000 0.800 1.000 0.20 0.54 0.69 0.50 0.20 1.000 0.750 0.040 1.000 0.54 0.54 0.16 0.52 0.00 1.000 1.000 1.000 1.000 0.20 0.60 0.50 1.00 0.00 0.600 0.600 1.000 1.000 0.25 0.80 0.50 0.70 0.00 0.000 1.000 0.200 1.000 0.20 0.54 0.69 0.50 0.20 0 0.150000 0.100 0.100 0.100 0.100 2 57568 3 57568 10 1.000000 0.000000 0.000000 1 1.000 0.500 0.500 0.750 0.20 1.00 0.50 0.50 0.00 0 1 1.000 0.500 0.500 0.750 0.20 1.00 0.50 0.50 0.00 0 1 1.000 0.500 0.500 0.750 0.20 1.00 0.50 0.50 0.00 0 1 1.000 0.500 0.500 0.750 0.20 1.00 0.50 0.50 0.00 0 1 1.000 0.500 0.500 0.750 0.20 1.00 0.50 0.50 0.00 0 1 1.000 0.500 0.500 0.750 0.20 1.00 0.50 0.50 0.00 0 1 1.000 0.500 0.500 0.750 0.20 1.00 0.50 0.50 0.00 0 1 1.000 0.500 0.500 0.750 0.20 1.00 0.50 0.50 0.00 0 1 1.000 0.500 0.500 0.750 0.20 1.00 0.50 0.50 0.00 0 1 1.000 0.500 0.500 0.750 0.20 1.00 0.50 0.50 0.00 0 1 1.000 0.500 0.500 0.750 0.20 1.00 0.50 0.50 0.00 0 1 1.000 0.500 0.500 0.750 0.20 1.00 0.50 0.50 0.00 0 1 1.000 0.500 0.500 0.750 0.20 1.00 0.50 0.50 0.00 0 1 1.000 0.500 0.500 0.750 0.20 1.00 0.50 0.50 0.00 0 1 1.000 0.500 0.500 0.750 0.20 1.00 0.50 0.50 0.00 0 1 1.000 0.500 0.500 0.750 0.20 1.00 0.50 0.50 0.00 0 1 1.000 0.500 0.500 0.750 0.20 1.00 0.50 0.50 0.00 0 1 1.000 0.500 0.500 0.750 0.20 1.00 0.50 0.50 0.00 0 1 1.000 0.500 0.500 0.750 0.20 1.00 0.50 0.50 0.00 0 1 1.000 0.500 0.500 0.750 0.20 1.00 0.50 0.50 0.00 1 1 60.100 -65.600 0.000 0.500 0.500 1.000 5.000 Smooth 0 "Medium Spring Green" , 50 Purple, 300 Pale Goldenrod, 450 #fff v_sim-3.8.0/tests/exports/test_inter.ref.png000066400000000000000000001335111370110300500211400ustar00rootroot00000000000000PNG  IHDRXXfsBIT|d IDATxi$g~sDQWlpYrjY3+k, a0Bzcد]V~ 0¶VJj- G3(rgx7GUfD<ODfVuUwuUTWuC+̪o%7!`3@X=#`3@X=Q>_`гc Xp)Fw4x|~J5orc_娞=`i8\htJXc/J ꍧ1Vپ 赉B _F]2Fr.wbO_{T!Z@ץH^V* &_$c$3ꂕR1AO:wjJX)dt _ܺz`^IQ16 V֥KA[[A7:sу=Hjen2l[կܗ+?[~x$i$(%بi*P)ztRj}ICPjw~=3Szc^`3@X=#`3@X=#`3@X=#`3@X=#`3@X=#`3@X=#`3@X=#`3@X=#`3@X=#`3@X=#`3@X=#`3@X=#`3@X=#`3@X=#`3@X=#`3@X=#`3@X=#`3@X=#`3@X=#`3@X=#`3@X=#`3@X=#`3@X=#`3@X=#`3@X=#`3@X=#`38ǿvq?`?+Ҟ}}g' >iUwvy϶]~k>פo|䷺6>|v uҔ챺7$COJiuvXuiQ{챝.>auۅ+|~kZQ?zþcGk>5Lxk>F׾Cþ|vp_psU,c4Kg,^7ҫ~川onի<_bwvk`İ2#{I}ՏGRgG;V7v0KivFxͳr s}o|m̿rҵJ wO} ~{wZџ H׭i[~헙Hv[jop֝h^v\hLvU'pYm!(.>5]mSW51qČuBZ1c3abH6m]ݎi ZufN?ڹ7˻m,1%K;e4v;DJqCS\v;. 8n|O>ҥO]Nw6wc?;o]\~>6,l!?f^3݂Yw;6f)}lnBzM5Of\8 :^bp۱7 [;U;ta}wVg?l8Y XF5fqfC\a~cJFqr[nckJ mI;; Zםykw/ܶ3|k?޵̮|Csgc\}g׽naahp #ù3k;AoCl`vgw/=^w,0h~پ {1DjkWg￳򳢆]Vvx۞Kq8}.~29[>`nflm[;>12FtWU庅onldfVFo큯*]y: 22RS}z{gȒT.zP` <v쓻 n(܎iXzt 5npbAM׸~omֺ|:q[ܼovMvWV~|gT;4uw9~NcFwv޵27rHkHu{ ~Nm?_M=a9yy >D^aa.?^užwΞy]unϾD iUhc1`w{nӠ+YkXuִ8aG.΂,hv/y5o"7,w61h|d/sWW][n@@5?onsw`rvr#tߋ?w _|6Mz~{ M5,c,|_ǽ/=OI~,ۿn_;jii.vTn.;/om~!w9Umw{Lisۣz*ؗc4IU}͛k>]Wlx {=^qw 79U [>`fz%RYkxΞoׇ %'{`, XKFXг[>`;7){[# $Vj;kp,Ja>MdICKyhM;=#`BaOINX'  ,R94d)@,s**XKc)VL(BZ8-E:$8 ` -EJm@e!8 "`th"XBKXt( ,-EO4J!;:,!@ϖ"`ŘD@:H3` z+v,!X*tr kd)I+K'R,S^x-EN@:#% X1[n{'awiIVj MXpJIjj-]WnuKIRpܖ&`0G  Ѩ|X*FKܚ43{)Vb-Bp,EX`izFKy؎$4$li@Y:IRUc},-MJzm`Iz4+II2Kb%E,FshtciIAZJF`i#I 1?,MmRu$;g+` -UmێwFJRhڲT $ `@'#,ի@X`)t=D F}9*X=#`lV8M,U8 .`!4ɨdQ$XnO'i,л X v^,YIRJr6M,` X B1 XԹc/U8ٺQM`!RZb;ѨۉVJIT$-Y8 X=[Zܞy gKXۓs I'k) Xtr'R,p{*K'I*&XJ,p;iq?nD gKIǵKXN,-]Jt |o1pbI+v/`M]3ksm+P:EhE,F<笔h"<2L4 ,F&Iƨz/4!G$%%u)˘8ROɰtQ01ҵxߐ\J0&GYK#h%p0ݤ51XX)%uӾ懬jRB&#x?y|VLjX;گfϫ/ͯsENdo~T/2^O7'4V~g1ts+\n_oT2FFIIל]h6"M[k۰wWk9dvX"mNeLj4oq\C?_p*_ ]) ipmbVwlο(GmU W(6j'G`EE1R2B9s0&(499na1=@:ocRsJyXQ)\;lEU91*Қj3;CL~ bli}y#rxpL;LN|Rʟ\-K6h;7>Ԡ\QQnaNPJRIfYSڪJՆBq'x^kWV9XQYQہȨ( #Wmgei4?IZs覨_h!2ʭ͛1mhR F1Cc*/7;A9vc4{ϥ+)JB[QɍBYCu*L/AieQIY5<blT6tCUr \XUpߓu6/^F\ddiDm]Ek#ڻ\ಊb$*H[MېkIshKGFڶR jF)1I::o,]i 9O7sfEcb/l?8J1*M*K(rE(ܱ6'~Б:TQ22rS7UDBiCPRӴMe~5ٲmrBh̚%iRɺ$!ctp%IޕReMRYmu]fSlgkeb>ou ol!SnhVW$M6jVbjfgX^@z[B:5f1ƴm3(:I^upGf7 1I&&Y;{޽;{kVw6N@Yhl(F^Vxm.EyVLfmoにu䕍U]pIs@u4} ,xAn]bl>媊r,gK]T9}|3߆J7yM9W(f6{,*D)\kLI]'sǘWFMSk22&ir Bnm]*xb5AD$ՄFM4k74mh8X>^[Ue{m!$MB0,hLOޔ|N(u9TxUIr lUJi12MZ=RnҼ9&`4mjMוRfnn^SRJVӪVhìi&IIAd.O]WPJzA"㠦is 94S+?:X߃p{d+/)H]Fmjz4+kLtgW3(iTVV2T*oBm;wa%YG%cedz )![AsnꨦFڬޖQxAyrz: MLXۓ@vXu=R9B)D'5!DlIٹ<݀WޣzЅsШQ>dS7SG/(%/h8B#ì5JWgU<ާC4grzpѫF*/ysXQIu{\kZ9hUI!9Iʩkj8XcFE)[+IX&CS)Z׆ ʡR)*8MۊuA*|jmhW'.IFY`+i0\UYU#nũu BRh2VkCMJ658mSG!4\hd48;5Wйx'wARhC7jt%fMJz^5 9?m )Wu2h]3jrZᆬ-@էBP=:/Ma)DM&|c 1ɶj yg~p5W;bseh4}w:3PmSJ9-ۃ%P >Y&1lZfָ7G9WaҼ*dF_.hL,(Őnkfce`o32 iG%:"i0< 59\w~J(Peg3q_2ƠyʙY+5KzY]Vf*{Wy:SH.ѼcV^u^$|y9!8yPwUUJi-dUNrgSkG/F6&'sG{HoUu^Mbt )4VGF^ݹKb^QM :}g^Ԡ\*HΨyY{}YaN}x6F`pEYT@ 9BT>]-cPJ]YZ3D?oXjk%Iot>-|`K]?idm-|ps.ɹF!rikrI~M,$Eʊh$5T31 U{H9EunZ1TV&*iZ~dJIz7f3 xknOi8\.Ph*=b;bossBpjjpyɑ+\( WZRlIa2'[/MII!62Tr'9zTky韪VteʊUQ{/rsDEu#Z1ܯМ%uLlDbh+ZaV+uDptk5MWt-7ڦu]J;K|O2wqrv ΠL R4s%>ƧjmT;I:L_ѥdU7IrJ3F])4ϏFu#_Xmje匊b=,At+[5_A/Q̋Οci{hB!jWhBh\Fi&HU^kwUs^w}Syv|R jyBU#j)99_*%ޚu־n5ym'l>2NHxjI?n]S-5:w*PMSFD ʊxZQx)ΚtNg5X V=>-sJA}4 A)*8{GUӨ$hOk迩oWXxK K`!42ʣSTTYͭ ] sLR!LUU]tE4Nrr~ZRn.잜s^w?r57ᆴ;5VQܑ6RzRM&R*T1x9]k487_+ب(Lkma"c/B7|\`5$ Q)uizG/-3u#Jk{e3h婶&ѩirGn{_o|~6Tu}OVKo?|=IFgТ{H_|s:UrwgTUl,L:5XU,!px/_/%6 c&m4seTLh:rN*nޯ&TmRLN4$IPYaVL;Rvtwu!I{rz.\{PdQP9ӸWRU!]qz;OɓNi2B;5yՏ_AҠLr~J}wKZeTQeR$jk+#‹+~,WWWF7ge_ IayG9jGͿ`v<Ƞ8WR=v ?/F{QXʀNLmh<2:5DG9W͇^|OrHF!Ȼ+ɨܬԓY&Tj>|杘RUQE/lkKLBM)/=c$v?X4VrXޕyJdzAwz$4:ﳦQ[49WҥwuL~y~ʛmvuGx졛3[y$IYgh*9b5zF}οz*k}K!o<<أpIYp@5ȹBg8aԒ>Ջ/GlcoUW)@AJJ7LLUPe3ͮݣ0(uA/F& rVAߨC>X'#Tjl!kc5IUIIEW׏\zKu=v@ IVϵ+4ŶOR~74Sug}} 侇S* QkIyj*Dž&Kr~* m{/M=?7ΎD IEcS ?T٭2|\s`5s;z_O''5"1V14bRSOt4K4ϣ@0yq _]IsJBh}!ה+?[\YX鎗/_))WM1WІNz3Z[KkwPr/?S~¿ӀMN8s:Iu?O=x(z+Z]C{ ڡҴ2ΕXx8F'ƨ*2f+jj8- R>=OxOΟ J1ب,xxMWCP(lZn |9lr9fL?\TQtm̿}NkX?QY*οvZ|1̋IдIyc?v'[$Yʀ _$'V]ӣ_;\XyG_db4+};%ktghۃlQJ5M9|'ȿg~εsUl~Q!zCV j9PGՕY^ZrVF O7hR:}K7G4eU<{q+U# U^6~xqH=?9!g*W>W~1 S2 1DN&W˒.\i8L"ce?{MvS5Tmlh*zR|s}yUmn^R-#Bt*z޶39oR2JZч^z TFz9^yG}fDe`'I^io_J_>(n-MLX>P{􉷴vVVj4pL_'g#pz" y_uy-6Yr~12V.]o}iIQFV/& ~|f_Ikk~)y<豯>~mnvL]a'7Ct?+gt|r#]~#yAUh: {BRʿY?T>oLNrHvV_Bofv ʶFyhf(*mWzp7KBQx%je%jmhk+BH_|?nt_k'&>pMPU[mFҠlGEҟv {zVVj0XT5B̦.jei8r K4EjO^M|w?j;wW~?__z\ir%L>UU[ު4[xk2:volە#ݩdGeBST8go$UUlʢښtSQZM&ҿ󥿯|_}Xrvu(ź\*`4RrNzXʀ_'rܘϰP-9٪&f%gv,.Dұ3 IDAT$WZ[Kz:_#ʁɝo/>s/mv'_Ǫ'y~T(4 ?:u^p*4O'*|FnnuW]IK2Ϩ^sG. "N4Kq3g3=3[ya}8^c!KA!jyc>MUO~(ibgdFP<7pI(ˀZKQh`zG<^o+ yM9u _o^7zWcmNU>T+yRϏzJpiJݮ`jR09)tUBaC {JoA ة*>JK4adYAc[H)p>*-?J [s*d*s YMSaUWʷ]9 "# q.&2[LKA i$LL&"Z0!:MФYD >rdVtM6&k氹'^9#U4`U/apR%z+t4GS:22@zXć]x58m !L (y)E}d:*C+eC`k0&>8NTuw䌂a>(GoۙŇxs;MAU)zw JSUɣvL1Bȧ<9cT5_ɲ6MSRN`jJ0=%4M*=McRRKh53\h1B"i2&Y<Ia[؆Vf#$Vë9 KԪ m)A)1RJNvdY'zI=FCGw\1FTNF?f04%?A)~ C'^cŹTz&'%áe[%8a1dZ[|nS;n՚¹ Ev31͊ލؾyQ=瘞I=U<߻"ʵam1q:wUng2/ߍ38m0nH%! dii<) z7mcz'_M!4 uc1MBXd,i=7[uv]|.O=+׶K'&k䘘B-{*P-\d4ڟ!j2f_KJZFaE R:K!Bdx>$R)SQ4mqNnU.K]d,٘$^ [M+C P:Ck`jJ2=:U M%Dʣɘ5)Q +cmE h_hHn2:/ry/^r#0byA#"eBӴ4t:05%i?$S}N5%eb# St;sݫKllz#-D(JN-YS`]R (f}~kBp À:qMS: 1wt#Sg15c!Pd ~/|C )$.eGUK&zS,29ygvinO M]GBpT2u=@J9WM|ѐ88#D@U9rxt; RȲSY_E!gklvzp X!)0J!\6vt-Z@ RW#!¶zsc +-b;OdbDVԩb s,.66dCk6>^2@Is ꃄLUHJm)GC)+eFVa6U'u6:&a3Z([ "uzsFVkn^M!$K2n'P7̴`Lr&q:wxh!'$&I(V* 23? /f}hEVdr&'sTCJEƞ;X|zxN>8%ڒQdyN)ljm,_k~3ZE%Rh?`+ >ĎjaLܡ??x[m]-jM76BH\s:eј64yP*ڕrhlfeLd}ǾJZQV+u/s@F/кM]GfB>'םK|H~~ Lt&w]iaTows˟}.`(yʡb0T cd9׍Xb[4B uSzMj7u@ )@ EmFK^ؚn,bLyBg@֗D&᫔H]+od;VVu*O#F3G/)BlX(S%0549Vؘn(%p.YHԌDW Bb:4/b XkA!4qKK]-Gk ug5GDFN[00E}~+>wI?@9ͨ*-uXװ?MWH:T%# 18ݽvh'S+ \7akKKKxop_ȠƢ ~tRwm&OȈN`@$eۦ np %1-f,Ř,` <Ԣ9-x9Ѝ<^s>m7zB!w荿`P"ĐЧi":b($@TCU/4@oX[gb PU}C5g˜64 t!Եۂ4S{enOd'"qƹh7Q^OR~f\o%a2̓:Sm0b}XW.RQ\cW0Yh[!̕J"wW?},kwMqzL"@Yu83?ܡZ5d,g{Ny3q02s$>xuԡAR_ozPʱZ5 &FY"5]wxGQk?vǹ8zA1γmb!l# ׄP^i1 )8C{VYt=6u?_qmg-B*\/dY5F'Qm"Z&\vJ)_FQZAYULc+~;Y\ $5g>?Aʄi؊̔BzH֑?WRȤI,,SDFo:?.9'tΧ׼Q#y,k8&`N).25iC]5pRfV2T% 1`؋4[?NbU5Jx{~pfF@ H\/K5bL}iEC )bMBS{D9s!kh7|U=xlv iyDyP.9"yoQ|@A>)cQis4DéU El 0`:E8409먕Rg\xr|#ȉz!j `VӒ?N.n`m1kLK&&RE)P*R0BHGO_,SӒ,VY ?a>1= SK54`N 1ZAsd%7cl?U)l1|=MPÀH#P3y&㴞Y, YFD<7'_b˖DnM!)ħevTMjp.C\};07O}CƖpX&'p'D8S|}-LVx扷ss14-CK8Pˉ tZ`Le^W$w~[7"-GL|sZ*߹# t5I]ӔLlpd$J^#U3=A7乥(,M]X\oPuzϽ[g<,;rcLNGO|t+`je F%aҁ=DbȐ |5]՚+!PG[D!5J@-G>,xViHnZLbdƌ9K^&Gƕ(։DY @ 2#.Q2+Gg~_a pBJ0?CrKc[Ze|/>wiõa$AOn;gy;v- ~eϟi 4p\w5!x""$aXjzm RrI-&ǒY?xC# !IJEڟX1dqv& M}L@!)Bkm^_l~ +O^ Hfz%Cڝ4]l?DQ$R^=ԍEy%G =ZHO62S]q7.ĺg IEBY]ڿgx}K Rd<`]@J 0XLJJz z#\דe&N lCLOBX ڂT::Kd9o^$s0LfZ$c;8@ BAj]&T2G.gX ]kǭ$ {GcR/-mbvj|Nڏ8K5_]P4ӆAv̌dfFCJ=jc`İb{qR؀"ӇuP я11qEI g!Ԥ5ɻ(Nٌ<{f d9d&{Lg~-"$( x [9,k,﹊/s&1ïORzK@Ɩ=qD<y82DQd {'OKS'W4=䖲qN IV Boh:k< Ec;h6 E€^90YU=LQ]PV]J bC/O BRtuљAEeXX'MxFcL5!^k0&jj0 UԮIDڣ\ ,^{u֮| e%K!r !jIJͣMl_uVl il>N$.>@5AQ0k>J_yfgs[ Y!~|a@Y-aLty ǘLd&nk(?CJu RHN,/K&&<á$˺\{Xs|,i=9ir‡# w}i8ϣ{L> 8BuI\EHŷ>;ֽ̾wC-W, dي?4u`̙D#?an2n@@:a\h}<^PtXm#(Z.+Aj-j=1++Cd2#FkfϘг+G}b65\LJt)#xk8{obv G">z=O?4 E1A`q+BkDd "Ȩw2=u)BY:)Q}<{.Fdl \h]^>$xuoB)MAQS ,O===:X\\i8=,yd=Y8ѠijBhJzBHEW9paz\s{piFl\ ^/4:2Il/wΧ$iKK".")'y|avrݶc1f0h m eDU-vOFQuQf0ih:e\ܞ<1tÿyw _X MZOc-gtkZdR'vd*OW9KU-32Դ&k3-Ar݇֯Y x]Gϙ}so,lVGxnNfە Gc::;Q}`/y]Y}&}>6?l)қ 9#rN)2 CQqeZ-Ah#q6IIXDt=sC+L !s7ܟֶDPU5K Rit[9Z(T3\m'!MF IDATHGЉ6{xq[l 9Hٿ8J+ J,C.%H;B6+Ex,Ӟ^;xp~P2MkL#6jhkYi{ 8يtZX\~.%g1k_rgx㵆qO}z q92֊P7ޭzuh,^;vKnKX2Rl;Lyv._q,ܨG;^&#PSU! `?yדӌ4^$͕9s-?qk#" JW8{K{vc6B4*AM8mIۯw\3[H)nY'>م8ù<LL(j~< !ښ("to>C{gp`Ͼ~ᚱkv hVSBc*)jM]a6q7yF{<=z_w?$E1Aw1Y).Je BR )غ +|,O]58)SIL✌zP#*1@X=(y\!Va;qjJ,Io2A tz8|Ab2>4FDmQݻO}-xGcqkAyl콿xFU-SDUw_c(J(jF9a53=O=MI]j-[fW"\=:iS`tUyIzv7&Î^o#X_Geu NȀudؚemÎ78~ZԲ(4?%蚎d EhjM T'oݵ=19jˡj@q,غcV>q6eYy>!&R=t}AZDh7=Swܔ4+`/CHU`xv.n6Aph{1pV5x a9s UUPC4J$#hTFacY?9R/zYն;%@1n]dC(Hj1J69A;E_)q.y18z^mٵQ).aIQ"jhK$EkGl$Z+<ι$Rc`t,#(P^ٺ~pmwvԌ , ۂN'5  G.@8<` !xu?RnGۣ4uG-m?w=,l;k후ovgKQ5ղLNz&'SS,,,,-9Mmn~@(z\ o[ڣ۟әZdY/x'!8&$o X=,LmT yt?-]s Bll'C@%2swQd=~wxߜ_>YQ q7 J(S`i:{]F%il[Ҕzݍ-ҌB:zjw>k>3;+Qs.=H;fࣞ0"TUxxZlfϦ0WO NZ$Ek,kL)cUg=(!_@1tMg+u)&Ǿ"r]g<w1۹-%Մ`QʡO TU<?@֣OGzs3B5AwѦ 7/(4Vg,7 %utaCnڭ3҉9|uG9;FKp"*RX"WN +x]c(rfDKzs3qI*KFi !1~6 |^Z){ "DZfqq.0ba}FL@į~pCk꾯C=31'%_<c1;3zh,HEY~Mgw}.C(pyӁN'z(Z9I_^uiR9D xGЬ3 YjE:xqBK“HmJ9~?Isds Z;-V6 `bIuD<41&*sap趣 Pt\~ﲰblzjQ!j;g︆"|d7zw'BEnG`䜾W^+OG}y1sl]$bW5M§vLI$hf;ߵ5ts醮&T2kWw5M6}:MU5j7htݮFeܳ~'~m|w4*[Ι^FbO,.*TGr`gopxۏ̠ub!x i,B4 ;u^c r׆Åy時eD χ@Aw~#uWn՞J1O2sh%M-9wכyoCދR)ű< x6X(PiR#9iZ{44'A ]VAy;;i&i@p= :ɨ \C]G 2to|v\H565M+FeY2?Kxڂu]e9TKݽeV Z-ESScd^ K\w %GH5V`m`0{EQ@9H6:t0 Ū``_i̞ qH #mE]c LM<A-Z$Bbp8`{u])@YzuW޵7n?*>}&JLDp鞯݁Vo)5>4dt:(M3'Q)U2 ll;WRU ҡu[ӞI:x )B.\c,J׊54u&]_gnPJǝwt);ȲX nOP*!5"q(KBf=U#_T8KxlD}y^o?I-M`"g|XP62EbFxn6:({G -M^n}3M;TqhB: s>m5z()EL*sa5)vj(ꄐh㢍=Ѣ3KaOU "A{u yމڥj55)e ;/:v3jZAȨP3 x2uѹ'oekNwg$G_c8[ ՁeeOAivSPʬ֐;*j,6NO*xOH˂YE=E+CGY:r3κS_8U.gtfg(coPUmQ*~_&E1 \qR(qWj }4uOccDV1Ga<ЋV i2c!CcnGx ߑx'[)鞳KǻK}ZE>=gxo oR+"x!-Sp{w}S5{;k5 vskXu 7EK3G=Ewx|-,k*ocl^bܔu27+j1yA@QYk4n+ֆ,;N'01!*V+ZX]te1 !fm3X^7&U6ElY._E6pldPՎ)$(Bwӷhf5kRS v:uٍ~iY{v9Z_E*ƹAC FJmƠV [xZwk)Sa4M#6!8vUnt;[v碕]p7㉽DPl@8h#f6'~+Ma$VZڧ8vg֖#+(F cSYH#4{9]Mq:`CAv 8.rso|KZi3ƱDV;{ }SVg̚7vZEAtN($U-wcλM4-\ܜyP>(Q4BlŰeb^K۶_ŷ0_.4%z=8=y+^-j eQuƤ66e4ݮ]z/ŷ:"y s^1` n;}^m< R[=#9.e}WyN&dUEQX>-1^YORfס,_V0:Ac \p~3U0>X70 _7C텝 aU7|R^B`Pa< J`>_?g8 `7ʢ2n0:l6I~ Jp<+z9g𽇿) (U x/w^BK:~H|\tCKwp_\GF}EZ-= g߸ P)| t!`KW"BUI,~4DTwZnzQ?!݄oP{#d d hHs v|,6_+DQp"Lo4[K ϸT. m\S}.y( "?{iֲ`=-d$PjoLjc_P2.)CJ)5*|^a>n4?ԟc4y@ `:4󑤞[ڭ+Zxc|I ;$Z@G(ltUWlMf(@HcA` Uk׻!,OHCx۷c6K.4^ok߼ ngE2=BI*BhEUxK;η>*z((O($B@wy~t^a=l.Lvz:.d>;B$~~Us72+?fQ9t1]@[r//|gsO݂|bkk BT",Ph~k_n͌,Gs|y(V YeiQrC=2+C02B ) `Ѕ.[uZ`xUD7||+(eg, MK,mLWR ƤX,fX[SHSUW?UOR x^/}w᪢yp2T!O4/|S \S@K nwȰ` HY%d_ cU~*<൯oQկ;p}eͿcM<@M*ɜƃw}1Xy_6Z{԰2pYQᥐ*uGd_ûw?Q;ʽ\ mB>MaDYJ`?"um fPʸ%BB]*` cBB( Jb8cI"$vu6w?|QAi:GQx0Vtk_Wxtu=+T2M\<_*l3QWvx@fY&sۀ0AeY7q?p+qUQހ8ߍ/}kF@hA'=X kh @ȳh0 7b;E>k/4- [wR47=ʾ%^sG0z=/&d %C׽ "_67X! %Sܞ2=a?ar-F'!P=$o˺~7sK&&[?5Gv_u N&7hX>z=*pLcs?vmYrx"_`(0Y}vjf~Y"k~A_冑&+<\y~=_j䥅֑`X;,{gTGշ^w;O>*FWCHeȲ-|Jx3oR1T2,@]X=BQ@/)$YVe/z ߃BNUU!vbSL.t2x=AYZ22TƆ0&@8*Qɚ6DH|+zjss%cl})<q^N>Bh히`1 R/!BzJ^H3OXk9 *EB8zt _$Jk͍0| n/|[ Msk^Mxt |Oy0x?=0@Pe=e4!Hqu{/'dX?i ha4h_o~ V| ehK(UQ88ep3/<zgPbns>nqݾ,CTB j3Laރv[U0.v_lb> 9ҿD(1[7w3k' mwQb:C3T*HPuR?q, Y6w:m> aμͷ>X" >{ꝍnn3࿺iogn;}Sٱ6yt4+G p,V<+'c0td0pgzyXPA"X[B^yh׿~}wpx% C5JQUaQ)YϼJ3)#(*7++ڧ ;wS#>럎t'Ύc6~Wa8!>Ok_qu?Ue_'61 'N ٬tգxBki{J;EwٟsӝC B"/r\HJ&V$CJ՞f[\]UH k=T3|v¸{;\UB kH^(`6( *A1.RHP+#ˀ~?nC5gEa/KNE7eB)&0FaЯ`U fC߮G>pf]0&GN`V9v6x;uL [ҺbqN׮<_a{ O; V姑3|\hZxZZ9o`#Usx_b߯Dt{w!q9i6i{Vo$@!UE|<_@J[wpʀE~HU3Uq困VCRFP*ĉO~ڮX@a`qdū x<2XH@͙C*-`UpC3t 0@cLPVHe +YHUb6՘ J+qӝ{ѽa8} D M+8E*X,|AJ&& A0Ce=Z0ܳX@>yQR*dY}RFO'*Fx A^W=Gx?} d ^C̥ !Gvt-'ѣU^cECs#+C|3}wyibӟAZ(rn61\vϾu?p|f؝5R(t̯t{>tU Ty_b˓z߼x!&f)Ce|\≓!^T TʼnHS~þ[RvJޏ@)nKB@hj }3ȿX_Swܬ$Cw̿'(+P)"=߹I2Y>T z&0j˯ [x.7ՅyƇo }Lp˓糤Մ,sGq}_Y6q? v&w_|袏Bϱ k$°֖A*aMn_;k(E.Tt Z`]@oFH?Ynnᗼao+n}1lj pxW]{냸gbu)"rSJx |^jl)VC{̱2QPݥu6Ex 1_K A=+T)I{s{ӿ~b kt5] 1`-"vhYap81=>^FTU"׻ cT;Rk I閷_$q}}Zw~WZqflqle[zc"qSgCU@'͎:k5Ps<Ʈ-o7tTi B};ln}M6o~͞ 0l&ab.0 A ) 1PJ;!^/_/'h!M20A^ pK7zS1_(?;B{~ eee9tof0m&Rў?1݇19+z=k2Q_ŗos:uo2_yqrt+롳3Lza#a}HYN(`m,sGcʷ{6—PB*Z"Iƒ!f }޷?kzY6/\BMТ.k=yVʪDUZ܃. r\q0^0:1~8VȲ AVysE^25xڞO_ő#OﻧF ay߽sMpUJG,_z. ahq䈇++>T|sQr꘏ݲ|1f E`P{2AU̓;q~}iF:b k] 2:-uv{JEH1|_BJ6m|#>3&èeIzr{߂O jX!e'߰}=y/DQI\beÑUW*w:yDax{|h]Jz}k=-'>߯*3(BϺ؞=(U@edPL *R1n{=,d:GY%(0(u}kHӋ UeaK 1@Jx+XVg;p%t=v9zpߟ~=€EOe5QUdJF=}4"Ar[}?l>d`25"nO.~ ޞR P*9auU,0ưjtPP2č?sC'|D͸2?OU06*`6G1 0A1Ё-1ocA7Dmy="չ]wSMCxwupiv"~yo*|oٷݜ1WU|#qqW + z= acܷn4E=ca1N`sbsqMYݟKv:eY']/0C Fby_}XY4m#tnAREg.\ &~pd# 67  !_}'>;<σnOkSwX(-Jgw]ED/>x}wM~@Q}<'xIeuBʲ:]m:,Q{emWQsO|U*6I%:CRծy/b\PʒԭMqq:H\ڒΪQ[_4-9~'ʪ*!j9@DDhS K+m{n ;ϪBYu,KVPb:G;+HK ^s%絕%4<Ι>ShG0*N>A;" ..$A~'˲DY`!:6`,B;vV~qR#Ώt_ꥵ IDAT^ս m8Z.1$%*xlt_-K=# _R˶,a ^D͡ XZ[/ܣүRU.VʓfloAfH""oU嚔:cS‡/jޮvU05%]tQڀU >/<Pʍ׷.,?AVr5 ]?W{PƎ*5.|q]bA*RP/!}HWE cJ󍈈.WUUAiﻠ%_{dۓ뾆{7]X󹞺v\xЅEZ&갥7H<@ ܃Y[h](,*P\ h/=sstzW-\o `|ݺ4U,u\|x=p JGbi]*Zk"":8sf݃.ύ+9󪇈@j X/?+=>fTUXlˊB DKn s`:)U."C۵k`-mo%ƨ(׆"@PX9̨Es.% XtZVmT>X2Qgs8""r Y{nFWK$I^3@`TnfH4-E.؅p ^3`9kozDB1VVݩֺìBODD;ױ]R;7)DD+H;ݛU"[+՗Ԥz,5k+LrL]+@ (H?_`:ɑ.. ^̸!(q=͎ƤN0 ~ 3wݕ'9;,G GQ=q^V6U itRp*e} $!^!@xDBW?y-8h.?E-Dĉp"N$DL.x@:wˉYVq D=M;s5}L)Ϭ N4ur&+E$kJl\ߞa(>8pk,f)&9 4#ن$)IJT@MTKgT0[2eW"TSaǀEF;y3 -)Dn.W_IUf$d-/=/'A(uR9srm\0mOSv:xj+X:3k8+HGs ӂU.CN6a)q"EBm3-UhwoAM@jEff` UFc8G# @'YnjlDx"J36 G͜6,IBy%\.-݄&噫*߮dxvcZ<㏺\R D"8RUװac-|Z`sS"ꖔ>:”Ԏ(^9s_Z@RӾ.̎c`sŀEĘ[BS*Z+Wݩ#Q9yjai*aMR{A~y;2YfYf` ~`":؏\>F+A(*IL.cJln )Y.I%pTJVu7w?`L*-W*5`":OƔE{[`|$paA>2W&cg^2/(' |>]0'WEө2_: i)΋&(5]:МL& A0@`0 ?I L'fBnʑZZ~kF4,&s'dqe} es0`,5Ro|Gb 1b8Qqd5H#1ÑuSh]a[OuJnM)7P|Lsha.]hhHEfMlr{ѡǀEt 1r1+M'qI}7x[9֏/ao kVQ(Ԏ%05%Ku%f9B3,i1`][n8QB\q5xZ҅t+10ټxUr,#AةNnWW.1m5ihBKD ,C&]h N+ !K0Gp<kl8lU.|=SC ԻONud*EYo0] XD X\GFX=M 5qM0EP0;*NqOsX:YS5EY1Yl¤ 8] 6P-| ˊG nRh72͎.{#VZzߊpU=@YVm8sNn*N\#"ƀED51񃇷.]!"8t""""5,"""1`uc XDDDDc""""Q:ƀEDDD1,"""1`uc XDDDDc""""Q:ƀEDDD1,"""1`uc XDDDDc""""Q:ƀEDDD1,"""1`uc XDDDDc""""Q:&/ """:ۯioqc""" uuq&\] +K-\ XDDDt] `"""R W܉yV}K!p1`с*O. u&\"$"""Q:ƀEDDD1,"""1`uc XDDDDc""""Q:ƀEDDD1,"""1`uc XDDDDc""""Q:ƀEDDD1,"""nYgKQ肺mŪbꪺƀEDDDT*1`-99dƀEDDD{ 1?_ XDDDt<xV.]yB'//,"""`G_8ho_"ޣS\UMȒ#"""=}/pWO?6wupu#)|dg]{K.Y.~VIv*Ѱ!=:-+d,9$ICI~Mm,ڔ6kannϵ9srm0KN~>,""":P{YC1ږ~>.сr|s}7MDDDDc""""Q:ƀEDDD1,"""1`uc XDDDDc""""Q:ƀEDDD1,"""1`uc XDDDDc""""Q:ƀEDDD1,"""1`uc XDDDDc""""Q:ƀEDDD1,"""1`uc XDDDDc""""Q:ƀEDDD1,"""1`uc XDDDDc""""Q:ƀEDDD1,"""_u mIENDB`v_sim-3.8.0/tests/exports/test_inter.v_sim.py000066400000000000000000000035441370110300500213470ustar00rootroot00000000000000#!/usr/bin/python def dump(scene): scene.dump(v_sim.Dump.png_getStatic(), "out.win.png", 600, 600, None, None) v_sim.UiMainClass.getDefaultRendering().setCurrent(True) v_sim.UiMainClass.getCurrentPanel().quit(True) def clickAt(inter, view, x, y, button = 1, shiftMod = False, controlMod = False): ev = v_sim.SimplifiedEvents() ev.x = x ev.y = y ev.button = button ev.buttonType = v_sim.ButtonActionId.PRESS inter.handleEvent(view, ev) ev.button = button ev.shiftMod = shiftMod ev.controlMod = controlMod ev.buttonType = v_sim.ButtonActionId.RELEASE inter.handleEvent(view, ev) def _release(inter, view, ev): ev.buttonType = v_sim.ButtonActionId.RELEASE inter.handleEvent(view, ev) return FALSE def _move(inter, view, ev, disp): disp[5] += 1 x = float(disp[5]) / float(disp[4]) fx = (2*x)**3/2 if x < 0.5 else 1-(2-2*x)**3/2 ev.x = disp[0] + disp[2] * fx ev.y = disp[1] + disp[3] * fx ev.motion = True inter.handleEvent(view, ev) if (disp[4] == disp[5]): GLib.idle_add(_release, inter, view, ev) return False else: return True def move(inter, view, dx, dy, button = 1, shiftMod = False, controlMod = False, duration = 500, nSteps = 50): ev = v_sim.SimplifiedEvents() ev.x = 300 ev.y = 300 ev.button = button ev.buttonType = v_sim.ButtonActionId.PRESS inter.handleEvent(view, ev) iStep = 0 GLib.timeout_add(duration / nSteps, _move, inter, view, ev, [ev.x, ev.y, dx, dy, nSteps, iStep]) def test(scene): marks = scene.getMarks() view = scene.getGlView() inter = marks.get_property("interactive") inter.highlight(23) clickAt(inter, view, 342, 460, 3, shiftMod = True) clickAt(inter, view, 278, 377, 3) move(inter, view, 142, -75) GLib.timeout_add_seconds(1, dump, scene) from gi.repository import GLib scene = v_sim.UiMainClass.getDefaultRendering().getGlScene() GLib.idle_add(test, scene) v_sim-3.8.0/tests/exports/test_reload.ref.png000066400000000000000000001337051370110300500212720ustar00rootroot00000000000000PNG  IHDRXXfsBIT|d IDATxo$I'=$d*+Uz[{aMX`,tiaHhL?+Xdp73݃If̰3dD0_g?ցjDDDD]ÀEDDDT3,"""1`Ռf XDDDD5c""""Qj\DDDD7v/q`Ռfߘ&nh..܃uYoMk n`}}_=h巳 DDDD=``p&DDӺ~ IK(OBDDDԈZ*AJUvH{u"""ΩX!K)~XYqX_C I4C-Z_S(R`88g bag'Z 8'pNp>` o}B"""Z\UNW ks Y`42H7ox}?U^/F_9/|oq ? Œ `m< ͊c5S9d<͟/{m&s柟~EwK~7EȺ$""%p΅XY6Fa̤dup`W'ܿ?RI{;vΪU h:߹{!""Uۘc 6 NediV\*<83,}^9c|9N~j`9g7,U7ha4prRz|y;eӳNR"QԾDYk0VIeLU5r21v)W'3(Ygg-AJʯ*DtX7+?gE+""7v/q3P W"<K-.> oO7iL jK)]9 [i:,*WIEh^:n -?fc4zY^7+"""ZO9 c4_yWS.KYX"L`ſ_EwQ3P ZEDDD53?VኈѲa""""م{.:hٱEDDDT3,"""1`Ռf XDDDD5c""""QjƀEDDDT3,"""1`Ռf XDDDD5c""""QjƀEDDDT3,"""1`Ռf XDDDD5c""""QjƀEDDDT3,"""1`Ռf XDDDD5c""""QjƀEDDDT3,"""1`Ռf XDDDD5c""""QjƀEDDDT;@Ik p/.JDDh* "@L-EDDNĿA#Tb""6c!JTeAwQ)*8*ˌDD<,;J04U)k:Iح!e芁k*|y X4wT. IeR:Dˌ"()oF:X|ֹ#""_ CZjJjIkˊL]DDtu XԈ}6spLq+/*^1M}uDDt1 XԈY39%A8\bT.+_!p]@\,zE XԐ+4aHRUTb %(Cbeqh1`PjAM1 y]jJALkTGX:!jMUWÒbYRZ ޮx[rY`2#Q0`Q3ڳBX VӕXCP~2uh1`AC<:cZAWt|oWZ~qb_Pb""j3,;i{ /ĸ.FI]h<뙮YlbM FjoORF~BL+\" 2.3Q%BV.~1$z\b,v3^_XY (fw}HDWÀE!K&jKz^OJWUkU#GHLB,,&bFÞѼ90Tʰ|kPi#&chr/":?Z 3n4+IT㥔@)DjdG,ڕ_h0`Q#O?iYf_iWaNW/8^)A?(f'qA<& `Ee+ˌU~`FF^Oa0\I>>V&y_\f$Z| XT+SӞ].Tk%2d\~`FpM݅JS} Xڕ;̘L'eoWeFVbF䮸cGeJ’b>ˌ' Z9vq^Df XD&wy]G⠯$Ŵ0 nO8k|c<2#i XV#M=Xf' ҕ++#lXf4\fŀEDHjefF$B?,3&F?^_O+CLN|2MǀEqAiR[gyffw@?VIa u~?FToxc|b|+/`D5Q~T_L]|)-͘Y3<{|Zh X?=ODd8s *]4U0=wYڏ.,l}| ¸lHc16G9j0J1",2`ދ66M+cI DTug[ Y1X!|&G;æѕFa=XDk^/#-,jbrx|p-Vh0`Qc@nQK8/N nl:A%B"zc\Y۬bbafq*%y/n1`тaXcфOC"u21>ɡaȢ+5 " \'2!iF ˃NDQuar c-+)nkD€EK|EDo"6'E1AD$~MDgWgO[@ RjNX"כL ^QZ X(.Q1Ӟ=>p<ѕ0`QcZs^pI5#,j+XDTy=9*55Gp%]#4,j5 "zcV aڋW5j5$${`Eg&5+,2^R*4~dlpp0xGQ&.Pwv]"^ըQ6aOEe!C ^1 [1 Zs]hԸb;V v"9W4""n`meÀE0͝?j!y#hq&4weseN}/˄4_Qfу /Y&z,j\vEDp}2!hԸ<3,%&j]! X yhtONt\"o ^ X $$yDK(qo&_ٓc3 WRljFP`ElRp6 l1`Q$\=*&Yp%mPg0`Q+=X|JQ3\O=.ՌZKD˫&:Q"X{rdC]w-860X2!]f q(4e"j̣2J흕-;@Z+O^<aodY[hfDrZ-/wpbɐNF9ۧu{ }ƭkSCFx/O7nQ]Tw/ŗ;u{ ÕD Z! ~x +)7xUo p%}e/OI1s{Q2Gq~Iw9X [ۃbf?q'P\^d"j7Q8.ª?n^ÝJ.2ba];+غ9,\1t}sǿkFCt X\_RܹZsm`{g~CWU.65CT{{oG Xti X u2gOqqXj*W\^<5:6?{5.Z!K8~8fk{0D+\/OEs.LJnϷC Z!D,q/_Zbsx>'" K_&-ܺ4U~ c" N7Wnqsg8UiPT+roph= z,sLsUoVv-r(* ==ܺ?ɀEƀEei[]Osq(*մmYk~Z#,T#IukY3ٓq ]lZ:8叿^l``&?ac.:~r *iw̺?-lpd]E/ECQcŋ+D߃};w7pMW;r X:FJ*XjŬ<,z,jKaJbxw0`Qkt}8LğE]Um2`k1`Qku2PT \{'a1a{gӹ5iyYJ4?ŗ; Xt.^ɨ5X"z˝b ?, XDKCQmiLCevjdD-ĀE&fp(*5i9=ܹ?b31`Qk1 2r(*-=+P,jVګDUC8.M+mh^E&¡TB+zYf%u(*," Ҳ>>t w?d) XyX"dV5/jo ~[א?PZ#08"W <ysnϷ XD8EE{on XT`V24,.0 \P>7u{m9KˋYCQE]<9uvg?O>f" X2yfIy 9CQCW*Xp%[s'bV&? kMctZbՑ գ5Zi.:~8"\88E~{{-ܹ KZҼ\v(~\Wե%BE; 7/K ,"CQ?PTG6hk1`QpڄCQgKB kg>(\^ X*<ڎCQlVXw/wpM%ƀE2~OMZzE"~a*X/ŗ;ſRRW1jV+8u};w779aI1`Q+CQI9#SÝswkI1`Q&weCQݤ;+swcIˁZshٽCQJ@s IDAT=l/n2`-!,ji zY\}?ϵhCQ\wa1a{gі  ܉.&\CQDUG60`-,j{(J:|߽_5lX2 XDDUPfϵ ,Ȇmy]9aV!">r|~`EȆђPي_Xp90`QdAj5QC1ㅫ)ݏ6NYFj,{(jh`t%[E8]t9 XDDt%u E5]uLJnϷC3ƀEM,+~ֈccJWa>t nb 0`Qp;Q\u(j顨uվ[p烍b^u#$,{q8>zV?8K z=ܺ?ɀq X:`u& Esw~YEKYǭkSpXN֩:ux3Q֥gai(͝t?W }Vqm.Zg<>D%ӕ y E۷_nGvi~xaG6ܹI0 X:Yf$lr' XRPԺnl(,"";OXr{o;+&V1`Qp5eCQ=88p%Ri X:pHL~Eݽ/ǟd,jXjg;Qw4HUj?E%rimJÀEg`;QIHXM`itW7~~yu\0`Qkq|7~"PTQ cNٶe5Ցօ7u?` A KDDԀr,2~V1dZ)"ZiM4|ONzQ+&Q,.º$s) XJD}`uܩ\午7zřDHDˢ8oPi\"$ bxVD]g_p%ՋZɿg" sW/j'vuWp&ٳFW<+`qKy"+`%zQ+q!QqW/jX*O8sxLN)ÀEDDsI^!vROQ". .^r6u[ q(g`u^J{:KBrLX,jE(oP}l}%Vaw1`Q[jŽcȢr1Ȼ.=B{;)peɦjo_]Q@Djo7IȌ 0 VwE9WƅZL^t=2CMz KHP{=W.SѴE"CVU\.䵂j"Sw5 XZMs>d\ы/VzK;uaYK`u{Ϊ082te 8UZ[, _]\OuSᪿ {u"j9ȩ>̏y\3DC\:[nFE:] ףּ/a"g׮<Еb ,:QWdqM[VBЪL{{B\7 .)"+%g?"?|=ͺLt+S2\͙d;8/0[.*נ\]`̆M XZy~&|l oS-2P\|l`q9"TJV|);Wlg9=9 Y/#wv ί`t%c׃ot盿@:dNSJ)lJ0le>2 Q_ ,qh1`b#\hQ @u)d!, kC~0ӅwE8{ Q4|NC 2b5)H|Ħv++#}DAs'岙`0.>Eg fN,D0ޖjZP<PLc&'>0ʹquVp+ſncZ+s.B\O*?]6DBtY_:qzvF#h@$L VNfsRI+X2["mұ!ƏVy.+:rNVZMM9gZ353^YI=db|A©xم$+Z:#"f(7T+7~|Op~gXREd4|YX@}<a1`Qkes@] BqlrS_J+fEQ>;=WЕ4V`l:H>7 m<X4_2gה3֊jwܻZ"F[$w8,P2+;! (a Lq+X(Vޡ́kV1/)K"-7`E!bӱ+"h:OUvIgꍍ BKu)Ta:$T.ÿ@z~#irdB`4\2}?9 wCVD V1`]uUȍ9@@ axc%j`iJfW-lʠ*7XKueWFv[MeP.E\"V&64x!c`1y\d;wA oqz\4 G7A!$_p|l҅7@,jvE@T FfۦlNZ:,us|?\Y2@"}j3=gVֶb 5yX"alJwbi2tXR" Y Le5kC\%dc`K"p>?z3h t&/ĄLaK)O>t  lrw[+XǀEva6 yN`\s c? (%% |X$# UKR%{JR3:$fܐEZ Xjy4ihR,z IGS8~_۷<{U4ncV;oA5d,E|z+bg[CAD#߂0O/u{xoXc s@\hڹs"ta!`U<'ggL˂rs"U}0y_Lw:%HtJCc6qؾS$,(0iVs [C7|<++އ_ _~CGh~gYp&r4De}h!ITFݴ6Cc {9qEU0~ o3q'}Cuoi)MO`Li y>-yq/D”uA1 5me?saE #J߱!ك'E6Q|z$aS)C3PJ8@.Qի*)+Y fGp6A\"~BuP~M+ c]8/hKlRÏqٺ`Ϙ ^lpRoz͟@k&\ݴS!ƀEeI Ɣ3ٟ6% 9T.b8Ϗ,p0^jd%3T+1~έz ERR>l7hkxR PlH3XJT87&y(ŀ4] XzRXF~}J~+C'?Ft 3V;Ųu7t]6P ft/C֫_D^o6&1^s77<6W,ƭ~#ֺxnz֎ o3j>/B7:,@*X|~CxTqHw^p+' Mh^9'?!W҃)ޣK?Zio7\zI$/9u$+QM9?IhtgߏhBѨqӨ 5(I|` &k{=XˁݎzY!I8l8[xlyQ4lI6B`xrZi7=x|_}EA/qGe߼^~&rDx,q56~+;㠒sE`9hXQ uOKcL&#a׮]7^78RVEJ) {=VC V-ɏ+/1LŁ~^Wu>p+jBm~G19bv vJV!_B." l~y"JveX :">w ^c%:FBܽڿb_TBsRK6#D+@|U)*揾2d3~º:`h`z"(-|?r|*l~8,'gPHصxHcwD&+c3L&'媓@A9 cϬ?JQU0C0s~0XE+0\1?ɿɟ{Ae@A27:"*@YşɏH\u8Y&|mo"k+^15?GgcLYgI8[F!Rƙp:,jd}q$rL]q!un1c: ͠DC).u+8>8lKmsʇ%xseVkm8 d|e !.:N0Z(8H8U{O^ =$Iq32r_޸ڿݟ~}PO!>zh8ay0`Q-vFqP: aKY\ U"YX( XTl2ui҇NzaDb]?š 6Tx9:ʍ h R![8/~/8 F|S({^<F00Hְ {E ahx%.^ݟ~ 7aw%8dty0`QX`}'q &T0&+o߽q,XBr+w xs  b9}_TD:r;߽o EORM 3 QL*G!V&h(cka,Ñ@U%9kw(|0Lt7{Ͽ߿~i:q.*-Y꾎m.:k!+6f&#dɕU^|~|`wDtS+f2-U v6{\m+~WMe< yXJ G2%f?&Xk YxLFnq(HWos/wﯿƏRf}ꭒRE 9/?~RmfA9>Mu(&8 8Iw/|[/=;CȊ(gdr3ؼuwxXlȲ I!Z%{gs}&Gn2 C*$ɢ?ܗ-m|xPyofǘdN{ ٸ,8 :$Ai_R {QmwMfa\YEǨ Tg0e꧜@ _/7zDiCp>q1$Q Lwdz<h!V IVS "2k899~8w+|ORP(q j^~Xϕz'o姚[[zq8p ppwsU]e+c&LF8AO*O+U!R@^ku{_b"?LF)s3 0"9 WQ\ xu,k柯U$~HYҔrP*~tIU.u`B0~Mi'_q8?8P| yr??WŮrlrPDoYbs;8XCKʟNWr4C }xz7C_  K.{w1;?Ÿ ~0Ɏy&Pjr39% @|30F`?fy{pF5qq\"dh!d?oWV"gWh/|r,;G|֕>=(]epsf'RSz( ljG&âsRyճۘއ0@V%5ۯՑ$~\.fY~pV55l>lBo ?J^DH sڳ?qCMLo G/.p [ݯ7__̤XjN`m~T8_>ġ~F<6ӰN#9\9Cs9t"HSyCsu}r~ k~( iWLp~_ Y8])kmxCN! Vi(7W1Eq}W~8$1@ʡ.!ˇb0ks,`m'+??n< hX.B8%aا6^O#IB~_翄uIiXkI҃^{'K3w6DDF,& X!@,B*D֮ꮱ6`̟0YuM[WuuIU*-hA!b_* Hwq͇FȌFcv-$q=?<#~.ZiL& gUۿ~c,O:/FTRlJRu#8#@@e%1&#RJB -X[ :;}H)90u(Z\`{Q빲\GdtgaoPFfE}O`t !$!xST*+ 1W)MEdxHZ6ۇ!ϦȲ6dh)gޙ?{YtvNoih]dAR{iHM>oը- F7n4eY|D˷\d)w:Q"&\gPmz8c;DYjwB6Uesǵ aߡT7 ɝ\%Mpu. =Bui8LzE;ظhcbկ&/?+ffΠݞ%ϧȳ6~Z_FIS@/Fv+oNt DM?j YO1FTB5CwSķJ"dmDڒhwaG]Ch-cYLWQ5ĘEQ9*Y[g}\^$|t+LX9ȡ2SSvp`jCukGשm}4C #0oUU8W Ts?p Zq6_`3d+GOY%@ UChV5(JؔB=qu6ߨCWi+| \> z#LM՚ oy^dZ4IOh{B 겎ՠ jpIbՊ<˜ƴDLͭyWOQffHFR&T(%f >B<57¢h'u%+|V; 㩳IC" !8dy"X>D$1܃M lE ]*HY`}Ṽ$<c-?oGO1GU'%|)O|+?})ՙ#PHFu$h``#p9hZ M:,P?}w~54)ߐV>E˭M]!"ԞD>$c(ғϺ3?09ru<.cLa׾=x&!X)KUXkq~}صʒ'GV*):$8luUm1Ļ,{=RV||}zUՀa1`8`ps9tyC"tbyNIGkIHV-/Yz:P_IA$޷+tlrwv3d 8 f:~݂̋Q=R֪vN7Ҭ1\H#dF U\gQ$]UGlE1<@M*#?~⮇i  =B%XSKDsi2W^:BOjMaF(L~g^$Ϧhgҵ’B(oPƽ3򰪪֖HPJC~d}+hLB+c#J25IK>\Bԓ1,bd2:7X;ͿEr@~ ĸ(#tJ4W2ET 瓣O#శB!! B#F*Dϵ%JPX*mxQ:,H)ud}^~hf'I#c0TˋY ~̋d.CR,V\.j bpu[=B !: I-RJEDS+(Z\EQ jېP_s4w8ATv ˿'m" L7A}wQVbc!< "% 1tY瑮d )+:J;ø}]oxhB9C\t̪P)B@ʤ{EǴ9fH %x!D@ -Qfմ͘~BׇǹI(>wcw.qκ8)KIE5NhLFw`tV 'Cga2- I;BaUJ\ %FlɲJ'}&MlN؆Cp8W.jlG7}dݯZJقb "Aʂ{C7Lj)~hJ1Jʀ\#Z/+6+w7k.N)IQTU@2BmzfV,k&5UNJOY>eC=)y~=ő,t ;{py_yL&G@Syg g%6 6~Ҿx·RnLUP6Uo9xHcZ@$NNyZ{ wN|gHnHBS~'™^ !Ÿ=VCҨ`oշ^w>jP1&2j̢CZI$^:Xz@s>|GSS_{q%ڼwJ g&w[k!X ׸ yի<8& S2"YcbU 7H/FJ5(c< i/%FO%H-V)$/NtFDk#+.'Vbl|3iWjBH2#!"rGm2uk jCNUr:_/K=*Lc2|wѽ[?X*)$=YE>p9]KW_ |"vB8gJ ̺+8Z[ CClFKthwjuG!+BqϾx2fWݺH,!:fnLSJnۑ=De).Fa hM \.JcZcX[]qO@iyKcB  2OT;f" /< vkMIC1ޮ\dLĀ )-WG$>\*h y|AgRU`4w=LM[A2LqEBkcuOYtZe )!@q5 seV kzs  i[6yO+f&\+>xż4T2֭CkƤ( ½yk>zQ q@ $v/>@Nw7|e8~(2?N[Luo~VL!W`1&}>FCYYQk4s>{h# IDATgk@Du(2S^:N!Zg$TDIlU[Dd+&;K'Rbd0Hke(B2 bٖ_<"nZ](QH!f' ARN Ȳ @QrbT4!\p{~Affbb))|'+Z[41KŸBUOjE] 'k K/U`g8,P5-zV jmp*hl?OKN#FbtW0%+%ĈV +bH2i!Fw!\z1$ ptdY׎n_,4 փ߼!Tm,JnfS!䦎O+k  ;ޯSpfe!%Xux_tN f7`'#<t6-8Wd@d0,Z %؀,59&Jjk׌l1@>8$]0U% u{ YhVmoSSڂ#A@Sn2C72(!xSHY2}* v zR}-J}GY Wx_amTCJ io쮳QR'$nJkfB0?6?~&}6!Bs.Y6D2-U' GNFCBRvI$L`!l/ԶHU5#!FӔR)& hLFw&¿ k:kcI c23)pXY,.%~)/<\M&#/W|hjG瘚O3RsQ9 ౢ@J\z{Gu*M3d3.D<+YE(%@DՇf8]oTfhLFw&'t [ tQzwa0<#Je=kgT.Z~ʙû !"!M6J||bkD# 8_\u8̷3zuWkrkX7`8ȑw*d_'7]|hӉJYGht>Omz~i-0&EH)hZc-->u@(;ߌ/\|ͥDK.K{|G q섟&qZXI?}ޕ*,(y%ccZl^d[yEz `CTl+xPZ4xm?Z:7cZ!Щ.d=O *# t$BH1,2CnJO\y$cD s/;M;*(z(;vg#EȲ.dɢY8aObHY~uqCkR ./dO"6[h2ZUjyrϨ7|3fjX4H\_|~A=%Ӓe8\aH+wRL RHBH* e koDeDqqL4["qb$H*'3Lh_bk1'uY4)@H ;%cS}Lfp`8Zk|p`K .U~r/JaAlA<bc FF0&J[Ҩ3폲{05N{4d@8wL1$B4RRZמ=Bg]Ic͙4!bxWQ=b 㜣ʼnomB(κd{?"l*X; ?c7Ѡr13z*p3yS"Eƈcs=WHL9^BJ"Q3r\oY{Gu ɳvMF+4I>,Cka;v՚!ϧ.VNgN8Bf'}w9 ƯS=t-bM VyߡݞMC6Vt! *=~F-\D-ޕPqUTNK1mIba?yOVT^J27M_2X[t [;p7ǭ%]q)-*/Iwr ܕgM *[=JF ((0q˿gU.,d_.D{ױ0Цw%h; j\HpzuNN|ybK-jsyrW+!Rի P8;9 &kZ=ŋԾ|y<~^1BU%v۝(z{g(wĦr/\A.:;)` ZTv@ojo)?n Ňk lT * d9d9 4JmƢa!X FF[^9i"NS_#`O{|E#`0w ENy "OQf!)DեD=?I!:[ `~ 20,B>L" ;={h)$J)>q^6Uh¸>\Eg+*9@ U[ ?JUzEEuȲѝ`5VH""'펏~*C?uϣ8W$T׆>qhOU "G A 2kc}uɵ(ezK22.j/a:&T BՓ bcrqm7BE7* EQJ!D_z(m>C-5֍t`^ T7* [[Mk!X K.2%|9ݴ;ɛ u`}ȯ% c%n@t @eȡ"xZXx1FPcƤ֩lELMbacCc2M*krA+W RV*IY 9֥zsfgϪûȳ)?d OY }Em22jk!X 1F(33g25qn^ Yzv0h m_oDE0q(~HSÔ2h# )CTUr4˻='8xbffΠ;vk3=53yమB a(J%2ys7dOI: 2Aґ~,v)H%9tV'z}!yE't91=!:*UjccmRtl.>{9W017&oͅ7ş@rUڒP k,,ر;JYVe`p(e9;~\{kۄdNzn{,eٯ_=c,,›d857 nzh*X;MwxڌgM@ܜVJz&N)Ufw"xb)MĘ1={pgߑM>[%{GVky`i r0^ "MQ!p>!W~kZo%|Ȟ|$ZS{ ^ZZm#uE+PUqXֆ}5܇?4x!X FSI-B!4Jc1I'cVh=-m~o DL6u[*RsKmDUkdn$O~^C%4Y|/V03sSSѺm#~zUH6bVEGJAbV=0rG0:G*Z@ 2Θ|{D(c'*AkM hD; jm|)!^j"FK|uHC^z<>x %;Fȳ.Jx_N[QYpFOEN#t:{vgi:{wCr4DLuS:~2OnFKE%O11 n1=Nj~C^Zm*%e鶽A#r߹hVm ntc@RU:E7OB ` ֢VSix݄7cM*>SGY )mlp>Yg%q.,<%JX[Rs?o;B.p"z[F$S6%pET6dWa2b'WqQ: G{7y_6\}?Kݶ_ZҒs]AY.woU,7Qlr4ޅdS'~Fӝ6[SZgX["dtcx^]yw"S}r|+VEҭUՀcsGAZAqƜy] vs@]9?j rZ*9,ޗ JvqܿC}X@J |.O|?)mrL-qWV+r ଽes=*|M՚Fm`hVm#t{|duu(I'Rr붇z]ΤW @HB'Wz~$#V[YR&rUT $ƴ1yD"P%Rz=wCD(>xTՐ9A$:Ŀ?~ib^ 8[&\| **R9fϺYҚc3=)U}toSDCl;IˆTrn;O#YǎJi.u[oĐJkT )#ŕ,\=c'kFz,+B* (KJ\Wz:!FFj *r΁j{xmq#֏_o TUA%1P0 Ҕc]> {:F(?f%FN!8b5hX]G`uhVmU6?FxLRv IDAT$WJH>{ͺcL!Rl&y +1ĺ$vdP>{&e)x0Xe0R!DW͵_u/" H[lH]gjM!Nf2}>OA*2!ktz-%S[m9;~gUFAډhVm &4!ƴR# $XP*Gud? GMJisӿK7@91G.>C;Z|:2ff25,k82zOU4X蓭)9 ӝGg0=tmP k!áȑHQ@pd]:F<{1e-*b ƀ6Pރ[3pqp >4Xw4wf~'BI[ ŰD e=5WE ѲvHQHaeTfVӃsqmڭYJqC<{ӤR=*;Dʔax\.ϯtOZ=΋5r!2ùch[P)W!] 4A-L5oeּ*48ܷr!KYQn'BDHaK#)c8o)BS)ЕT\ wyc ~vRI(±{$ˇ$з@H+?{Ny)Ĥc [f1z\eac-/?[$֪>"_6J- f֕!0OuF`t !$a֯E4&; j0)E*a:N[ E H*|c7;1\źrҴXq: C:+`üph5J'bb/޸kw*US5{0,z93hD6,c*ZO0 1bmAU3hSpX-fpg!X  ip,H$oDH M^u}dY;|0<#_׽LBz("Gs0&;<|j齍(Kfd4tw2O8I,˂R%Y=X EK%Ғuk\!:hSڙhVmQN$X7}vxo evKcz 6\Bm "][= sx_bl YG6W_@{^@@+r_sCi<ݗbd$g^^\{Kwj?hfh }ak(ݢ(9rmP*'E!H/^aRW{9[yRCIR"-ZbPRV-cz a=v.`T6f&E$pbmYWzF\* *YͿ2>8+lY}?avYLMHZ RV>p0C xݜB_gSYyy羞sj6 d$fdd$K &0pLB̍4R@madY#-liA ݵ%w_̪^::u~(NՕ|O_[T˧|.ppIܢO.\rT!AQEs,ouOogje: Eg~GO}Ȗgf噀<%N] #4c X_{zV{ۗA?/brdEY+_&yQV 'Che["2 ö*iFл[9 IBXV*$ǀEV<`3x Y@Fxl?lC4dTT4s=KkU1,23u b=4-~͹)%Z8n ׭S6f1Ș7?"f9"c+,[eQ_ʹ~,0M(8  0s+8n4M~[ eS{AExC(ʉ46: V!ɖr 噑o~|hȨ(`ɩvVG5׾GJV<8Ʋl~^5'>O0Oaa[6e:X,1Lp]50 Ӽw‡̯y9YF.OH:Vac Xīe_JG˵&nqV+/pͩʇ#Exv)`ɩ`)`O_v!}Ϗ˽ pSV1y\9vjFAmjW/ðp*SY )H/B^œ,zb~^ ˲(<}zivp Sqjw`;_\l%`yAخZq_i4v׻dYBE[Ymuf)`ɩgX`ۚ4r^?zOlNʑad6q`6AE7΃Lq4g:&Aղ ƻ>A>k(oE9+&đ_V m7m=G>q΍K-4-wg<{[[G4]J}Kt:--fswmoQ:(`ɩeEȸ֙Q[]fbY)0qQ0 f1EaF902]<+ga/һ>A> 2 Lm7<|$"MOj.̂#`kk i:KyEV> @gԋ^㹨]Tq98 xK/LFdAYXCQXvc,46$bxةc/xݿ(,sDO\Tʾ3ߏ&9 Kr뺢U,\_äv2!KM%SQ~ja,yJΰ, 0&m vZE<#,O f`Sv ~!=j69m\5$ rl -3+pE>10a3P}׳Y$iLLNLy;5|7ٲU32Gww2l'Dь׮pU]F,c"'0$ hxibZ&X,20 xOyoK4]9$iaT*6[ h~yp< 0 ($ }\q![un{r8ptfo|pGHĪ7U:T35Eѿϓ$Y)mE ^7?:r~c7ZVbc.ꗕ2ʣe1M,K*5⸂i"/`>%V YCWXy+*XgWTZ 7|H8 ?:pue{WILY@,)bAŘ aG 'BhFN )Ő:\|kz/?HQyb2#O,̢kuiE3~忳5YVu%W'_Ϊ7}'e)Q8'3aO1.a8u,# 4ㅖ~}G>qƽpFXiYSÏ۹c 3in'o2dW%^V٦%Ҫe%g^A t2,3T2I=4v{ˠUhiA]Jq4i$/& |.%ThP6XUXeOR&!a0-$vÜWAnP<ϖOTضex08iDzJҜB{rgޱE*F?#`l>`2F{gDz/|[_O5[ח`.gaeYJEem6f9b84dT@KN<[njҨaow ֢Xn.LטLkDz?4L,1 ˴.^K?|Fss@2 vo:2]*}4Mqmχ*X XrZ-Dΰ;0 4]MZ2_OXe߰iYضm4}9`1I$r6ZD3 WiPb` KN$w(V?Ee%dޯ.O:iI gy&Q>hoan]9,Z]M$IeyXCXV=zʷ(:z䩂%n"拰pSg} LukXSNO73ٌb|6e2,'t#{6r BU 3^x65 (`)V,qEQg1W\XEt:&S{l[? '_ϡ*rqHY,btVXiqsz<tqE Y-B9,9AN^%$Ie-HIsYf6S=nam(/^抢9i񒿿ѻ>b\]g-Ͼ:j]?n*XgZE&mR30(0Zd@AaVpY: t,_r.ӹT&ۤ>x=~dY.(q) g,#-ҐQ;ZgK[r(CV9ٜFsfL&x~곿 l4MX\9ab6cq2 $" gOhp8$ #l;Ӊ5dTVZi04Ao0 !!U^},k(2eYLyJضAf8eЙXs rh9A0a08!Aeq4dTVԃ%V ryϽ_P"%I94,3<0 ,^ i &yfq [!qBܤ7@ {09#r y(p*[Ƕ]$²s\ a6]P6^9nQSDY,&ATp:A8WFH=_N,͡PYIӈ(^hJ͉!dBEKݸwY6‘)Icbe{xme `ɊZ W"KL?sW߿`pD?̹wuȢȢ0Ȳ 2\ge4:`XY,&'حyϿ0I?120^yVﭧeE=XrjAlly\~ |D 1 (IA4dyJV 1I/x>+?KSph}W4K*O4Z.ch4Z.PEl;9_d4 ,Ӵpl"t:iw.Ru$Ʉҟo垳IDS5`ݨ`Y-B9(p1oz9iL8E[ۼ;`^ދ' X EA^dDlqF'5\3aجeYZ;? Tc=F:U䞑gqdUlZZݡRjuuuk1K1YVE6] OR ޲l~yDZ㑏}k Y9Ekb6ӝQ |l4[Qy6 Xrϊ”,2 F+[E[ R_#w}'vGߠ(ʃ$"IBȧVEEa2D }Әjr)`lIYJeVGk= *?E,fj{{'2YYe1Y8zN8P,Q967W\עtiw+4.ժCsV^;.F,f1E64m,!$"|l;R1 87y+oU)`8ΈA9pi=Znuʟ]K-;y Uٖ/VNgDќ&S\Bz'eEK O8_Th.ÖY;ڝK? 'E 44˧ ^[CFDΈ,f>l]*{:{|3G[rE g>iRKJK zjuZs4[VbUxqs&FA7DZmosK=X X"n,F˥ׯ5{1>"a4M5 BN0侇ڴ{fYvtc)Q78=aȃ@_w %"w(ؿ:_Wmo=ܴRtwޭ(L5 N4 B[Záʭ(`ȩ2D&gWh+*^&/51(BF@-yF#ZMvGK,,900\p_S;wkˊDqCm0-װ \"+qaTߌnkȨ܊3f 0MZm$*6su㲺5,j?EBضI+JHURAKDIY3jUcSYVam4g:.5 , iw*T[Q3'WftU: NYT픣 'l9&À 5=1߫,,9nnVYݪPo.k*a9BzhضIzUjf X"rEaʵ'fESn%wOnEa(`4 oro 5Vn%"qbxtzWpɅM0kGFAva: X7`iPnPyQrp=].;{5ZzӥթTy.Q2Y;;vEN(k=X"DDnbmۤ=WթUl7;`2.B5˟i.nH['-~-_1)`ܡ4 fzåݩsFYI嵓QсdVFR>,v<5H=S)`lȪu)^*nnL!q7Yno9ۃzpV4T@KDdk>òRMz}-0`p3ۉObs_ =-\ȱÔOxYjw+t{z5*ղ[__;8 Q :s, ݺ@KDDLFe;SeW֨Tl.Ҳ5/Vֶ/8w:Wf`mi W%"r0%6g`ڝ ֓ e2  Q4TwmnnN3}jsi\ X""wUu Qnu: Mrx35odj_?uWF*oՈTg%"rKӜV5vi4]: ^e}dr`2(pAWׯ>kRK)2g1W+{{5zj9 j߫߫a`0ŌG!nݦϋ_gg>ujrg%"r |Q˧;U*KriۉG>c5?r{~9`ɓ)`# cuuӫ+GA?_5 3F3%DKD5g!~C*UNBw2p]~[kUZC uۭK)׃9ׯ*,ktz( e< QYLT6{>T,y ,3hU݂rDWao9R9K `< k?:pI_}=Q<9G7UsVNZ^䌇=? ;Lkβ]Ww[M~?i X""$QO|l9WSJf\su fӸ \̧^uk< h>^6 B,yVG ߩWi\-l&9a(`4f(۫{ε'f믫_:oyKx˫_MKDD0Hy;vYWeBnn힫{pgx3ZVNk *F4ȳP;6Tte=WRu6=0`4(O[u| 2*FKDD6" R=1[Wy*~fˣ/W׎C*Msh=eTt6,ي[cU9wAw,r g4M^_lyظԃu׸ۦߪy%""[&9u*ؠ~ruk,ʜ0+VSWk7\lwދ|;G>מ> N6H/OЅ.VG'ۢ%""gN'|[c1@xIoYڻ܅/}Q(]#nux˧+\:8AYO'РZsx> G>guԇE͚^ΣIvbDDDn WKX9 Se\NVBoFoFqGť鯯DsVKDDY\ݲs]h) ׏a/p2Evvc*"""rWr,VnNo՘."~2tmusӳ DDDTi=Z {:V98 S} Vpg*`ȩX&vNVBGĿF%w|xsVۉ:GLQYRKDDD9T=~FYߪQvb@\jz4Ny|"ϱt#enUDDDDNM+P8, S0, S0, S0, S0, S0, S0, S0, S0, S0, S0, S0, S0, S0, S0, S0, S0, S0, S0, Sٰ9S?cOmIENDB`v_sim-3.8.0/tests/exports/test_reload.v_sim.py000066400000000000000000000017711370110300500214740ustar00rootroot00000000000000#!/usr/bin/python def dump(scene): scene.dump(v_sim.Dump.png_getStatic(), "out.win.png", 600, 600, None, None) v_sim.UiMainClass.getDefaultRendering().setCurrent(True) v_sim.UiMainClass.getCurrentPanel().quit(True) def clickAt(inter, view, x, y, button = 1, shiftMod = False, controlMod = False): ev = v_sim.SimplifiedEvents() ev.x = x ev.y = y ev.button = button ev.buttonType = v_sim.ButtonActionId.PRESS inter.handleEvent(view, ev) ev.button = button ev.shiftMod = shiftMod ev.controlMod = controlMod ev.buttonType = v_sim.ButtonActionId.RELEASE inter.handleEvent(view, ev) def test(scene): marks = scene.getMarks() view = scene.getGlView() inter = marks.get_property("interactive") inter.highlight(23) clickAt(inter, view, 420, 429, 3, shiftMod = True) clickAt(inter, view, 351, 392, 3) scene.getData().reload(None) GLib.idle_add(dump, scene) from gi.repository import GLib scene = v_sim.UiMainClass.getDefaultRendering().getGlScene() GLib.idle_add(test, scene) v_sim-3.8.0/tests/exports/test_resources.v_sim.py000066400000000000000000000003321370110300500222300ustar00rootroot00000000000000#!/usr/bin/python (valid, nLines) = v_sim.ConfigFile.saveResourcesToXML("./tmp.res.xml", None) if not(valid): raise ValueError("Resources not written") print nLines v_sim.UiMainClass.getCurrentPanel().quit(True) v_sim-3.8.0/tests/exports/v_sim.res.xml000066400000000000000000000441671370110300500201360ustar00rootroot00000000000000 (0 "Medium Spring Green" , 50 Purple, 300 Pale Goldenrod, 450 #fff) 1.175 Sphere 0.5 Sphere 1.430 Sphere 1.437 Sphere 1.225 Sphere 0.5 Sphere 0.600 Sphere 1.490 Sphere 1.375 Sphere 1.430 Sphere 1.250 Sphere 1.240 Sphere 1.250 Sphere 0.500 Sphere 1.243 Sphere 1.385 Sphere 0.250 Point 0.500 Point 1.000 Sphere 1.170 Sphere 1.230 Sphere 0.750 Sphere 0.000000 0.000000 0.000000 never 0 0 1 1.000 0.500 0.500 0.750 0.20 1.00 0.50 0.50 0.00 0 1 1.000 0.500 0.500 0.750 0.20 1.00 0.50 0.50 0.00 0 1 1.000 0.500 0.500 0.750 0.20 1.00 0.50 0.50 0.00 0 1 1.000 0.500 0.500 0.750 0.20 1.00 0.50 0.50 0.00 0 1 1.000 0.500 0.500 0.750 0.20 1.00 0.50 0.50 0.00 0 1 1.000 0.500 0.500 0.750 0.20 1.00 0.50 0.50 0.00 0 1 1.000 0.500 0.500 0.750 0.20 1.00 0.50 0.50 0.00 0 1 1.000 0.500 0.500 0.750 0.20 1.00 0.50 0.50 0.00 0 1 1.000 0.500 0.500 0.750 0.20 1.00 0.50 0.50 0.00 0 1 1.000 0.500 0.500 0.750 0.20 1.00 0.50 0.50 0.00 0 1 1.000 0.500 0.500 0.750 0.20 1.00 0.50 0.50 0.00 0 1 1.000 0.500 0.500 0.750 0.20 1.00 0.50 0.50 0.00 0 1 1.000 0.500 0.500 0.750 0.20 1.00 0.50 0.50 0.00 0 1 1.000 0.500 0.500 0.750 0.20 1.00 0.50 0.50 0.00 0 1 1.000 0.500 0.500 0.750 0.20 1.00 0.50 0.50 0.00 0 1 1.000 0.500 0.500 0.750 0.20 1.00 0.50 0.50 0.00 0 1 1.000 0.500 0.500 0.750 0.20 1.00 0.50 0.50 0.00 0 1 1.000 0.500 0.500 0.750 0.20 1.00 0.50 0.50 0.00 0 1 1.000 0.500 0.500 0.750 0.20 1.00 0.50 0.50 0.00 0 1 1.000 0.500 0.500 0.750 0.20 1.00 0.50 0.50 0.00 1 1 1.000000 0.000000 0.000000 1 0.823 0.884 0.849 1 65535 1.000 1.000 1 0.823 0.984 0.849 2 65535 65280 0 0.500 0.000 1 2 57568 2 10 57568 3 0 0.150000 1 Wire pairs 1.000 0.600 0.200 1 0 Wire pairs 1.000 0.600 0.200 1 0 Wire pairs 0.000 1.000 0.800 1 1 Wire pairs 0.750 0.400 0.200 1 0 Cylinder pairs 0.750 0.400 0.200 1 0 Cylinder pairs 1.000 0.600 0.200 1 0 Wire pairs 0.750 0.400 0.200 1 0 Wire pairs 1.000 0.600 0.200 1 0 Wire pairs 1.000 0.600 0.200 1 0 Wire pairs 1.000 0.600 0.200 1 0 Wire pairs 1.000 0.600 0.200 1 0 Wire pairs 1.000 0.600 0.200 1 0 Wire pairs 1.000 0.600 0.200 1 0 Wire pairs 1.000 0.600 0.200 1 0 Wire pairs 1.000 0.600 0.200 1 0 Wire pairs 1.000 0.600 0.200 1 0 Wire pairs 0.000 0.600 1.000 1 1 Wire pairs 0.000 1.000 0.200 1 0 Wire pairs 1.000 0.600 0.200 1 0 Wire pairs 0 0.538 0.667 0.699 0.800 1 0 0.000 0.000 0.000 0.000 0.300 0.700 1.250000 0 0.000 0.000 0.000 1.000 1 65535 0 0 0 1 0 0 5 [auto] 0 0 0 1 1 1 2 [auto] 1 -1.000000 4.000000 0.200000 0.500000 0.300000 -1.000000 -0.300000 -0.900000 3.000000 60.100 -65.600 0.000 0.50 0.50 1. 5.000 0.000 1.000 0.200 1.000 0.20 0.54 0.69 0.50 0.20 0.600 0.600 1.000 1.000 0.25 0.80 0.50 0.70 0.00 1.000 1.000 1.000 1.000 0.20 0.60 0.50 1.00 0.00 1.000 0.750 0.040 1.000 0.54 0.54 0.16 0.52 0.00 0.000 1.000 0.800 1.000 0.20 0.54 0.69 0.50 0.20 1.000 0.200 0.200 1.000 0.60 0.60 0.00 0.00 0.00 0.300 0.300 0.300 1.000 0.20 0.54 0.69 0.50 0.20 0.000 0.800 1.000 1.000 0.50 0.00 0.12 0.50 0.20 1.000 1.000 0.800 1.000 0.50 0.00 0.12 0.50 0.20 0.900 0.400 0.100 1.000 0.20 0.54 0.69 0.50 0.20 1.000 0.500 0.800 1.000 0.50 0.00 0.12 0.50 0.20 1.000 0.500 0.000 1.000 0.50 0.00 0.12 0.50 0.20 1.000 0.560 0.340 1.000 0.20 0.70 0.10 0.24 0.15 1.000 1.000 1.000 1.000 0.60 0.60 0.00 0.00 0.00 1.000 0.300 0.300 1.000 0.50 0.00 0.12 0.50 0.20 1.000 0.800 0.800 1.000 0.50 0.00 0.12 0.50 0.20 1.000 0.750 0.040 1.000 0.50 0.00 0.12 0.50 0.20 0.600 0.600 1.000 1.000 0.50 0.00 0.12 0.50 0.20 1.000 1.000 1.000 1.000 0.25 0.25 0.25 0.25 0.25 1.000 1.000 1.000 1.000 0.25 0.25 0.25 0.25 0.25 1.000 1.000 1.000 1.000 0.25 0.25 0.25 0.25 0.25 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 v_sim-3.8.0/tests/exports/vibs-3.8.png000066400000000000000000002555321370110300500174660ustar00rootroot00000000000000PNG  IHDRXXfsBIT|d IDATxy$}̺ 0baAViDY4u2%=2ijڢ(Ei}OI%ZuI\ )s̠g2cȌȬ =_O}AĎ_,aqiS3y/Bmxk43 Af ufxk*֯643  ,  4&ֱ֮~u\]]!1l>T8{jcS! , < طsE/|cx.͎v\7}%Lpm{XA02ffPe(OPj hvĨ03[/eW{XA&zz]j 5@&c;Οĕj1HH`1dKn/ ʟ"ͭwC&c`}/]tC Xb~K(}]Y%>oLڠC $ OλGWσ b,+n*5e,+_a&ϐ5L`27`!cpwޅӿ8l΄iaBj_R3PbdطroQ>so>;< , fÎmS9\?vWl7"kkuϕ˛L&y.Z3,+ղQZhlX-BctSӮx<^ w=Hh _rB|\L{Fy'b?++s9 snwㅟ?2verڕzJYJYLBm-5wMz]& A7|twZoe^~Qy0c a4Mr9̴}qA|vUs8'adr`[`- ^y ΟKUl7`y"4 8ɩf(208I͍&67xW/Q-bw苃G|Uό*py WX6NO?ӾA윈ؚ g07= d^V 9 w~!)P!\΄Վw<9϶XM95жf 46^8|>Tq%P,ܬݤ빇<{9lzWde2?lnQ1YEF|G7zNŻN#]\1H^9ˣPn(˸˰wÅqsgD1i'^y r&n6}[>;4Y-`b2֠!N\ t" ps=o;+y;ˡ\.cii `u.g#j$z9p/>6hs +os~v8``̀qzd|#^>e}3'7|qoo p܏f#pt9nw-7,ؿ\LB;hjٸR5e:tBY6}Em۰mXeP( ɠX,0hثL1;_29<(h;m{>M\]_DQVA \Kpc'w*uʲ9S3,,M3y}Qo\Ĺ{%1YoOnò,m!ϣv< ܓKf\x1*$˙ ͮy+WX1XqZ hLa}s <,FB0>[) =4;G(2LB}=xh ="C7JD8;   vL&v 0nQհq`&,rVf#<mAtF,H]AB\qd=*0[ʰ9,[r1B6V%3lu*;'.> f3s:zBl9՘DF\u:,{E_=c۶nna6,B@Zŕ+WpuEGAu01n"pK`es4Z6jW76h;^;`n~p]H-]Q`{39`#3:OK… {E,,+R V,dYDMy2:{rcG(C2`R96`bm p q0"m]6ϨXk"_¼zl9֪ɕtvb^_9RȰ_,uDi0 íGl9Caf|b7b5 IO r< aInnkbom4q~N'LM燲} R ZxA}$Y;F -˂eYhZmjJ";K K*8.TRxlÁ4m7TزWh?/_5ɩ fɗ·..u?X$ ɩ^"ne¾ʓ] 9/4ťΝv#6NCSzgE8{37geBN$ek0/@-؜!kpđasӐ/d`̒B)i_Xť xLL0= r qRfݿpr"'k{O}2PAu" pɑ|k ߑz~ /Iwtd d P0M o2Mɐ51 ăs b RY9^8+0aC&JLh*5\'yWL `v5!,g_=__Y"4M_\w7 b$'"Ák?Ю;Iq\sp>vШjٸz+B.A*\[44˻rkڄŀ{Ȋc w; ,LF r&CpVpÈpo> %Ii"I\QR{S/w&lͳ~ֲlԫmln4PjVz gQu֧z.QP" ƆL̜߾2yWb Bh!&IzFML͚ΘOPcfK\s7 E;c:GAıKcsk_$qA#T/TaqР*l+pELRfl&/} kjU kW׬L,(cTHdv , {Q,eq4nu!p_.qՉyW@X%8Zĕ$Do'O ZuiTR<1+g㱯I夥a2n},r.2$G.XbsI :+}R{^\O2}4YKYQpVE6kv>or<׫hzd]ʓ$蚥2rO;qgCNDO9ZD5|1Qr`7ތ<#ّ<^lpإOKH`RGq+F8v/1.hXXK/$Movz0n.8APv!EDW9R A 1yWښVi4tHjg486ɗ=Xz2OXSa~˲qrs AOEK/ʢH.ЩLW=Nj'! TZxK`l6 ,־Zgf7F#.Ur {IA4b!EDWP+bLs9/]#;D%ÅNj%ZԪ?2Q )nu0V OFr sR{7|٬9 EA7~B^}ꠧagyW)J/+,+]ޕx5\e8ʠ , b$`E_lhXX)uB2V{?䅡 ː" F2᥿o7{gv|QL4.LŸ$H``i'_la'韀)Dv_ I " \T$ wI 1/by|?\w)]L4MR;4)}/A qu6ׇkb8=Q`*⸨ㄈ0p?Cqda `ʻOnp }6iڈbPHOr"I,p %j\+wAĘ񛞰21"A:SJ] ۓo$;rN>v,& h]$q5yWMͳƯR{'H`A)Wό$K@@7.|H٥J]Ln f8rt ͕ڀg"3V?0 Be7Gqu6ERD_y;8#!QCb8ގ;S>'T(&:0_ ;1>3A٬=dnS!kQ?q==0vavm߭k2 9JR{FBmqWqe. z:,#g%8DZ=LJ+FCU߽EVbv3̩mW]$)9$ƾKrv^u`ĘpYIǨZ^b?ְ&:1c;fut2SBLRBW1B9"1`j&[o_&'u2?#:/r; HP1ORӸ{IG% qΚƏouVLaI+" ,D2ɗpi%1##'/pIxpL$+m=; !áu依Ic[1J^+ IDAT_L4,vxq%UI\"$%KYl7sg^ĕZ)t-bHUGsLrD6wbZ7FVK 2}1Q( 1[Gj E#L)w5qJZW *Bt;W>G;\EV.RN(mI]n\{GB9Y.Ub ]:rt j8$b,|UֺTqkvLjeqkzWq"R^mT aʕT!*} J:W_ QX!Rw1ѻYF6kjAWJh^%hc ˯8T29]q`we ZǞ\ "ai7i}FWX[Q\X'KiK&B+.L]FߣQ廃rz1%⋉Ex,x,=X1d]¡fsҠuΔ? ė^D; ӆ  k+Ud%]aŕ0"@$^Z`֠C8q% Sx5W^Tt Z*p4WXp9y" `FX41KЗ <4!Ɵm?q'CUb9|,K,'Qqs咛t8Ā ?ȼ y=B8Y:2O:;LRP~GH!\Q%*=9Pw7Kw?%0BM!CH`35ǭ/p QB6,HCDT0SP-ZH$dPWXORU!04*,;ޥL..+fxz-7_}/,]2b\!A 1GYj{5ml;hW>K]u>%R&ԅÄ+aSyp0f+ fg4M镁if`7tZ WI  ="!eIKYl7ߘmRαP,ғCWh+>qA{ԥ ZnDΓχė:W/DkxHi!иRYoyǵl=$bHY9n=l[\)IwY*B 1"qlHh)VJG~X:dBw|!y[B6V+O_ e|]Ƹ#V },_ݓoM:д7iT}E1$9SlBq׷)':X>uim2zL9 B+&l0 L,Y(af20 KrfTgKg1aLx_,O-{r*XAD+ALOM}K&U/"L+1tc,:"? f`6'&W3_JB+,P! BQ)+S05p={ , ]J&mUX,'Ҏ \j[r_.oĈSQװ2 `r!A%Ŷ/ 3QFfb}=U(fC"+p ĕ"+b x?Dz<2.TA9X1v>l7qƠBAtVrP]v]):5jۤytεrcEo<Ȥ\OpWA\%Nead2`/4adL mp ޶`c[?p\|@rɹCH`ĀYZ. 3KU4ψ5t8+}HhCiK0M4+"Ԯi〟SҶ3YP0L,X6+g 4FTYpĶ݆ni4XE/[O/H`f 9xUWcHĕ.B\)H#El;)N1\iǪJxa7I3  0]ʯi 0B/ee0Dһ*ads`dÄ蓋2IznHx7XD  g1Xe8q⠧C~eqUsD_%'bچiYPr.x+jhÆ'LY\b4݄L,_p]VN 8`N;6s ۱r!wKE rUyb\  Lޯ7s%*Glzqp.|:έ:RAD2 +ч8p,3pLePy!L/)K\-٭ os  }RQ.֑KXvrWε! Hj?wz͌)}u[Ԡ[[q 9`Ɗ&vŒÑ\(,X GvL hb^XO:0٭rlpo96 ':[ fyr>VTT ݛ]0DqeNy},']ϭıK 1B'5vttJKr.:Nȑ R:+vHP67СMV8[;[JrtۆblVHRf%bI\rb@PRJ8LĤO5"Vq|T%vb%tY 9 q^_."9;0pΕbyY fg-+oQ`DrM;XR]A(M0AHEIbg;%DHL>V>tmjeq8xY+eV]Ž0!f2׭E(0 ?.nIGTp"%JO,S݁BA=K„}rQ9\&G;h_i .(,w|忤>q;Ndod3n>R;LX;II{O~f,{rc"%tJKT?&rLܱz[ ^PE;g;Pb{!AٽX)BYP+1"< s؂y3yoK6d&&s@j!E1rA]' vw.RX5HVrYQ!rBm{P\1u`fՋWnhzŲ,O<|=x͞IAan 9Aj'IH9x^X5u>F$'#nWJ dbӻ6[Ժ2Vo3`kgÈb,,B7HkZ\g\@ڇ A1.yK\e[$۩?RPkK41yP{yV ݆nݶ-oj}6춍ڶg[%ju8f(czT[GW{wKJTp?S}i[o_z@At/+7?\=1"٭ + jh/bILӖpŕ^-ۣ/)Ta!SEmBIޒ=l!CW|➄Sxf%|.o8>o~İAnc L&$Ļpc$*f_\R8l'Hm.-ID!8U&;`;bKr}R'IdmhD;|XX x{xZϹcc@$=V d-eJH\aܨNIiP!!0J*TƁf@9:`\S,C~għV? ϗ߹CL.\IuBkO~G( k E)T @視*$CC+N\;Ji|+s t E&Tpc%aͣ\*i }d&\"Z:?hb!E=qn_Xvy;χWȢB*Pi.-Rb'ЅSU c0U1}%SDCVwFJ. !B?zpEw>7hA[* YXWwbH4r$# @\'WǤu(P]P *EȊEg.r\*9(TJ/nU/wJeR6Ak EInxOsR+rQ#YO\RSu"nV$؁-T`T0rVإRoOvzÕ}RE(VGkv,#FXXqyrWD.Ul%RD .Opܦ_;O!vgX=^R#Q*LAʻ_+=B"3L% 8OtQI]cHl^}A;t"*.]uȽ"ƁTNF %GDC"0 > WId.V @lxq]vʍqł@; ZmUX$EiDVڤ 8mm,U ]w5vY!!wEEw R#cZҩȹVqE Ĩ闲0FRy;{D[y8G=V>яyjׄM/>eytsD|1t ,bHKUۓ^1tt>B"I/ȁ"⎕DDb"L#rBm " DVOl2+^^3~Đ@;R9WiUP ' !ߥ  "PnVpljOaܵ#stsƓNh`_dg҄U1YH$dee%ѹ+']:q%;V"mF0ANGD߇H24}j܇~s%ZERҖ$F Xr9p$ Àarы]H ;0 ~3$)}>|  qtnD?N<ƸYUkz?Tȵ P`THA;3/۪6+ {8rod&- cbKR6;>Ydsz~qߔ^B?CC~ɗD$BW3gtWµ,$E/`ҋ ъxCqGR8ʿ(]KVd~>UMoGPYPIH`cSR?Y^i[( z])9'"jRʄx(bBs|DŽo-H$Fd%ṃa7GF["Bl/G *4Jp IDAT꟦+]y'Oo.d21EjoS,eQavbu7\C[0AO8(BޱARi2[>6ݝ_]st}EQqe>+ȼhퟄoZ)_Z=4J"ŵ H4;8VQ-k[хeĹ^}UtMBSr+br*l8pg\ "&HXڥr8Bk H5wr)>;덶$Ӫ)o||0u- +GsH`XnnU&1a<*J-yt6'*⊃sU M;z͒K3>pAoRHWNJ'a-K駟NumiDc 7x610=SlF}ٯcsϥje^U}?nFxEcZ\ݭXR],Yu)z91Y)cCu&p⡿FX{0M[I\u?Ns `7΍^aɽ+&{?~ PPPXpu$vc9"!&DŔfyV'Q Oխ X8gMD $ŋ\ac Vl4yNjpjyZ '105BsEp{Պf֩ bLL_کRV1O#Cy"DBQާqr7s?KxY2 ~d^&$ŋ" *y4!A1Iq#t:9u"K\3LNp38 ٰQYl5j~) ?Ddĩ:wV(FnHT8lбA_c_FOCB {B(<8s Nj-u ѩO+[V|k_ӎmΕN\4b sE pǾ>5Zy.U͂ET;"QdEFS NUTAO'$ u#a: .+IO%4ᾉ,oCipz킷8_@g>YPq31Z#2g_3J'nXiP7s"+ɵ;7f XX,avt} QUrkSUZTJaH EtaHusmU8]}YWPġu4K)x#A֘9 ꔫvZv%y>šwxNܫbf -k-_)zm7B:TBAODܬLQ:U1"cyꓓu[ /PU>s312g_XuY{ ܨ49R m{x'  Bs E,+TOFj&ʧ2 م"կoҠsu&z\7@V],DM~{ZwD9je<k3%ݴENNSy{!-oy _zsPI15S_COjU [Mԫ]Jan`ƻiXPE-mYiB}Y S'/zNE7o}$4 L݅-Fe؅:Q,fPt\Zp> 'JӳFFە5/fw/ #[nf!5Bt\.N% KrD{$e׊1ZIfX|ס%QLF~c;\ch;Ȯ e%^fvPJ>?]ȄoW\ks nuzMWĒҸWHI׉n\Ls6qɊsz6(o2}1yms7ϢBey gzZBuL*_dZQk8*<at)tT"KxqW/IEԱ%`f8N 2.lXh6 R__]~ :խ67~2]SyV_@k$F\i뵐4^/.=% ,K4gF*3-`qӳn)*j:lbs1_pffl@ec-e+ ObB$J(bKN?EHNqנ[0 ?poG?$ƌNBV`t+'҆ uB!LauE*N謑S:,L~rNJ%?)L饞KS:)\ ~obr&W\JP^B_ 1eat~ vu_fLe[~j`۾=pkoPm&&BB1Q(!F#]l T6[EkD8,I% -1vn.q0A`^_1]H,BB=3UUGdD>UWUuZ.WEyCgwŘ<[4O ː#k}[ܮYL/]B:U!$窜`JOr+ +zܧ_>\=y_->S s`$\ǯ ESnc^*0gvUZlaQr+@rS%=d\W\%f,`mak?@Lн {x2yOUcjkoDCC /tZ-nsT Y=ϡ}dZ[1S8r}:X :9>\=wWlYYk&{25g=\./Թ[j}Hg<<_*V{5}tVt66e;3{ZгY l95=Sm*۔FsKW.O/%d'rZT)Ҁʰ{诔j"peK~c_ m8^4!@bR|P%鳐>xw ii%+ԏmmmXӬ%Oϡ#ʜmX5$W%B$5&@@Knt}mae:dZٝCϦ5x_GuU@,89ͺpR+@Iwi[ )+FlŹy|W߇\:OL9Qa~t@Y1pE]2ҫӇ]=`Ӗ698L080\.]1\ZGfR%˥ 镂- *s;l\usI繮 ]x f116Rp9I흍<&CK]ԢL XBNb–@ } ӓډ3"K-r*k@oyiu=AB8&q+6b˶vp؂kɖaj=/uyJV)в[qeJt1bKrネ+u?YZV[G#S(^7 _^gAB.>Y *$ 9Z*_KF,ɯc7=ZY94444l.Wj BĂ pjTNһRt T&l%V\Mhޏrۜ/o=g䜪l.pW0Z,prvLG|ۏFΩ+coIMВlW>#-wގ-۰E Wg040(n &p7E:BBW8ŕ0,Fs​7-L*\'}=K_+99ՖR)OFf$o|/Uv-#Q牆B(MfhO0Ό}/&[Rn-͉3ʅWB76l֎ R cbl44e_=hmkLc\9Z4TXVt_d$В(hU*b`%U9ߓuή8瘙cz!^vO<'an =7݌ßW2EY Xp˦_*lچͭhmkTy\!ZVuc}O3 y>9$crUCZ8R9JK%U J9YI`UU hy$m۠^=v;utfxZ8_ji{n}͸cS48F9UWGwnnjE0Y=?$O`dv IDAT[Zu{;g\%wP Ϳ*J&AXvYABvаmLw2Af%Ծ}/:"e.,451;13 ^h0D(G>߹T)ظz[Tpqp"\uvz/k^`R@8M)mr^/sk.Ե]Sl$>RC{w5ve'UYźYwk?@CkzO`@C=J@/WX"}^w`d24xͥq+68wf 'tVuminG賁-WTa'SdY78L@ޕ]ٯyQ[ PW_Ml|͘CWqbZT'H-pUHTn5غ=[ˉduQx8.^'t 4Nmrʴpa\Jd)>sAhŁ]JjI(WT➻_FOȩ!bРMkpBy>G߆_} B@\UzJ*>cυo[jGV3Sy ]ą[|Q7n@6<^<<k (@j!E6(I.,ɒ X, V Vqct?sj^- h̥qex._wd):Lj\'ƀ\:|Wå_0eTxN1nϷ[t.,}݃[Zݤ_>I\XIX yZ|989- B{%HU.,r*'XtIsle;& l)J&9UO i7AP?ndX"$2lj-[S/k݇uC'O(:*) Z4J[]Xwc6ll}nT ](?Y\mގͭO]@a/8ZeJ VI{9׳tJmt䗙U|uP chlSY׮WR3ox7r_[%c6(l Nj뒝8pqð<1$PVQSت }-Ԃt:G.B8,,zko}3XTiUҹą g#S"R2]udJ10>ZyWIyû_T{UQlk>ȇU&d+1Sp% `+W9WIzw`lj JP5MWjim6N塩ekULիZ5ʑmNGb6*_nҩjji@6_KZӦZZː%U뀢)YT%4l!Hpx;Pn[cӖ6d<&1pnK^7_]wE es*K7ቮ{Y\]s45 \k;Zs*URUJa %D YQ%`TNIPGWfg b7wWDž0gεws0]8Lz-$'%2ppV_Á߀M[Ez&&_ Y0\vº ]r qrFf-T)`=U*pKfql"$!K$ g!5wX[n|H-%dͽ`sɻ޵קnzM֡'@8GW&Y\utuc/]h^vqSνUJ D-u Z?p% J::j+> %xYL!<7O}u:r͸}|wNKi !r$ckl|1x:(Kzg0x~i'pD_ BRUI.M7rg)ggk+ ̆febeI`TYoy/U Zm7?_gq0U, adruMS8ylcY}4TKQ=ɹ*j|-zRPeV.a#LC1:RKyW \ AeI Z'ϱmq/Ԛƶ6xA<яF%2KT1sWx druMj_p`-k%UC%B +IGG :ԔFS5VCDP $dMl[HȰGYJ54`0ϟǗޟwE]_ ' }{4zS=%׬CG*1h}^ZɞKɄ,jK*o\rmޟ-n9I]=V듟T$I04~Oa|t5}p:Y va*XR/K,E{n-ay:L]^"'Xr~(f-ڰsO7'/Vh% |[I;m3mR[D E*a ^U *FoнƒdI~ӾiGV`! A oZNk5Y\Єs y"._qUCZiȲ- ΗW6]ƭ_yuڀ:+#34Ǿ\UU(اUS5pbݪSd2KoAcrstBغſ 3O X&#oܞuT%U jLZP[6#x镝c\9!`>Vܱ.tݶ,wL$sK1\lɢ+F-j|tc2sQb? 銉:qX }kKW:697}0w]>ṕEƵZ lU7ݸ#N_8W3Tѳ56YњfcOlk![,SK\b8}_dZ))e[־ZUGgs :KX5Zxpbj10e[ORʕX> E U)FlmN -|S[|? C~F,0 Jc`d3]qb[[瀅h;q=7M +@ R" (5S}-dH! d8jY6=Z0>:O|3+=ZNV/G\7r2igqs |%iE7% ]_8%Mn']k-4Tcf:mhk BzUAHqyJEL?a:P 7D7e2Ȯ(cT7yS~91ieၣmcwWތݻѹ{}yYy'N:Wۖv`[Kϴ"$ܐz^꺌aBfy SWL=d"&՗G鴇Wz iC{&pDj\׾EmIm˅.{/p>jSOp"XwE׻vB=}-hߵM&'0q8F6NaDهѧckR9ɢWmR =t$Hw br,R_;;,8:َN#$xC]¯(jb%%99榫Y.n=7angP8W"^Zw8^TQrTo%ZIpbq `` ા-ֆ>4~g`{{Ѻk:>e^d{6"۳]z Z'aTƿm̞cϞӒϝjWTZ0j`Iyx5) ~eOF;&Im1'%SQ< k`aB1 o1haD ey4DZ_S}=f_x=Z :8A;*{Ρc$#Ar"G:Yx[E:Uҗ.JcPp܃C~b_ׯVyDQdꪽ3k<­HլUNVR[5> WO|/q_UN+Sp$A*lS=(dx H7Ch;C{?y 0wE̿4~Q\Cs"z'M EJהLSpu]w{v^~R^d+MWnD:q>~CZr93U;,lׯs'/iCR3n]_M"rP0)qL9[ d{cF4_wrE=hܹzos/>>^@t~FsIGwEM!ٟ8ad)@Cx`f Jdz+@$u4bh`\p굦^l× =e:SKj1pE S}]4꿄I Ա2ܫPqݙBUM'K[Xf(иsrބаc6Fן@t6gP<} &%Lx22hE\-uй'bƜ2uX7vn|F2G>SձdԵ73ɉy~BlrUEZ*Zy]7eՅlGy0z+CwQ*U,!CJgLvEpm9/]@t t*&\Ok! ' 2TU=M}+~]mgrMV.Y6{7z6 ?y'ݔ:U-B\},۶-j% s_ 2 2Z@BI$+}@g2ૐ޶Т3}(>B#PF+N:?z~N`d*Lx_-prM[۰c'/`j>,WTXv5-ۘK-*Z+pLnhEƃuaC CGC|}=n IDATjq3}?~_U2*_.vyxBgՁmxqSZKVuo¾kE^.:V-@-fr횥P%/qR"ҽBeN#)t  J D+pwl<cCHmۋԞH]}Z/gx|@$EsO7*7F39#dYO- fGW0p~'pD\ՆREJfܶ+5S נ~#A@ܗ0Gi+\*kc:Zqhx[iću>oϵ``;y3xɓ4JAfo'ޏPo#8<.`+)Y]@ՄKVQy#4.LҊ*PAV9\,`U2@+IE48ۥcEC]Hm3`J:]X~LXT6+=X[ 욃`jmς=v%x/W^(Ȋ3CדCyN\$f ExxnUCGIJ$dաnڈ]ŋU{8+*XuTqWﯷJl[LB|9קfXp3S/D_D#-da?UuB(B[0AR+žL_GyL,Ԍ:jWY|zޱN|qҊBV" !+^օx,d<̒@LV߶C%ק8ScJ"cO YT9 $$Mnۦk{t„v WJ=26x^ 8w2}~>ƶDItA2-sx] 1<L3HNJjT=&.ձpknߺW[wߺhjolx`;w_}DԌOÉuJ+ ݠHv{=+_2.Hs2 <WR{xTA^dFb\{#]}%~عwwNIGK~X057gk,=zrMçtzճu`xƮV{HUsTʽ $?U[dDf?RUr86 W=ʾFMEDE瀩mR:'p/n#p?ą1d}!0|iOV{8U3%WbK0?Wnێk}w-r^,o 7>[ yW:W5#rԺ\ mu /t|+_ ) TA\)慡|`!h/TX ?4]삿c?l. Ma|tvEFSS/Z-`m%]swf151;XԄ`Ցʁ+MJwQJrsUbX$SE R k^Z»Y]KR2;.=ږ _(h$PFJ,kCʓ}R'VUjjIRX]\&Aܔe<\y'}(\}$53`4KWZ.Yi׾.lmA㹧1'pD.DX'2CQ𐿣)`&VLNLpHNB,ul**!Xב+-4ȡ MUxSyUzU\HP5ÒFrlzMmaBm`$LWJr]:dY@Hj*Hx)t^:T:sbA@n@3K$By?ܒƃ|9}/?toBgWm^߄\S*up~R\c2<%.$iK6􊟹c/\vpEdW&\1z[{;VpZuWa}Nz.).SBQT7+<.N5 x?4 \[.vaX* NR)R+9Ŵń,o QSe>ch`RsrMtoBgwmYu4/.I4+#3sdu'S]뚰mW苗16Z(+-"(\aTE i59|ą! Bqybs V #t F/.4BL^*T:T: / )}^:- H|\a, GÅESնX̃"R𙇯?;ݒN#)%r|dwkT- &1_8W"Xu =[+ϒewpe~'\`W\zrr ȒyWFd)|+=¢: %5_!1?0Di2*X5dJJJ JSj <|^\Y4"yXa>"Po~2mYiVV\>T%;YN{^4fӸ88GWK)" %U|Np$ YBJ'.W_Ε擹WPꯤ+bo4Rŵ um@ڴ0bL0MjaBzkyFf?@ Q2=OQXo~{RpЩ|P!Pa} _)הA[G#:r^ߤ.vdu'S{Cc6YW rU7`)dA/0l)"lsj0 FhMlGxH0t&b٠ HzLek#@) Q2>],`IWK +z",$U>V*!ZUP_`>_TKkeB,/s;a<N/P4(Tѻ"pLoЪrԂ959s%rU*nمt 8@ uRp9 \kLq_ce@{pykk ct* 8t Zb]-r*)`䎍vjeP8Yw:q!Q1\,v8<69#6Ȯ d2ݫJii$ $iAˠdqh+f*x4KB`EHy&NUd_9umˆE}Xhy,>L%%8c>S`p{%X!ks"p ߾U.gK@ClCEiu1kqqнPj2Y!*&JAUcРSu$k^vWnIఞG) f9cH/ ILjBRE׉%J J– IN"\Ts"ERIxΐ=o#?t?ǀJYNC㵏~ [6!הi<Ђ:nF.IʗsLM;١31aBhPEK~:m}}!?)m^3+siH&Az4[14ǂ%0q^k lЕ`U6_A1_V,+)*Jˏǒ"-!k9o Hj^߄|gX9V^- ñ9XuC?|{l*SSMH9*mf;@w8VQ/De)'Kgs,}tl8VaWR>}PX`NHR[!NV^6LT Hy 3{ \8nwN`tڹ ]r(|{~ QWSPE)}o6aB-<5r]9-T;$5Bc{VAÈc+zn@=-no*zS9aח*_(H$ %h\J5q ?']/ [ Ū %;%iVm{iM@93mڦ~< 0޵Q*j]9} nZLЇ##--O3 2.m'7fAǐ6|m-?t$lyZe"X!X/|!B'ŵ3*G.)I]rjı ,UG5e\:5=j{2k]+5LEHK#}DInLƠ26-OfoCQyZG 8Kq>'Kθp@̿Ҷi._+/GXAZp&x v`v854`'Gqip#o9tAQ1p.~un.T'"6s>ęPSYs)t' euX҅ p96m%ͻ2C<(c,lL@/ZiXҥ +NO<6Kav8\-p#9N{7Z13Ahiu3E>l57~qOx@Lb}[+22/NjIg ty(D^ip B=`V*/׃<Õh 15j,UЁbv$4GgqMrUcֈL ӰsR!ֲE )@X&6qPɉ" =7[ݢBF9Y~W$ϜP`R(`< -^σbxD.R@ XLw{ds\RSсu9@ߑaK&UP/r /-4Ʋ@TWqۆ r>k{l_!"n9֖e;| K_ȱ@-9/΢8=Le͟`5?>?/&Wb9N|qߣC3 *||򈞇ڝⴾ Zam҆=$ n !p3a@@CؑɕAplV* E;[$ 8WBPҜ*LY4hb2ރȞb>j\WNw  =-^ݙ%q@\* *o.)ͭꥩ/ WBjHA6v%֢ThP0&PX pConQ2\\X-#5*g{fS( )(OE-/lX10CLLB@a$NxPp}z]\R.QZDFN WJjD] :%(9ߙPNW3DK3Nc#9`!cEQ&fYMTU:Mc lqb0ՍOrD-4ȴ6 b/pLZ}w:M/'pé+Κ*kn5bvBkV Rifw=rK"i.Vԩ b:U6P5lfy[Q;PDaK8W2ɇ?Lf IDAT/`[EPesNy]1A VYm8{{]><_ݝhkol}.*rUEuvu[P՚ԹO*ƾ2@Q|ct\,\RG#TWm_h0O nT9\c]Je5br9v7Wß' :Zں]{cM\9ɒ \I24A:D#\HsL)h$^ cDŽ $$- ` wKJGUxa }! =ʰ:t H=?~ AmtZ{Zӌb/czMV-9dξuZ%.-0WPT],+O4AI@۱B:TKb< ܫ";@$ $l)7JUАXX|%5#s(~Q|yI\ވb %jgU[sRGtb }m2hD .sHÂdxP FY qBI:Z9о נK[6 0Eԅצi/`=r w?Y r’yW$H^lo ?R 栄[~):tòZl*'h r 2dA8^1eݯ/u=Hv K.9uÜքvFSsӓy7 H ɫ֒vFgW3}х?J?E.+loN7+c9*ǍXF9'>r<=N";݈` ųǐuZں=֔BavQ]9%+ƥJL,Zqi9StqYI ܉ݖ}w0)`3iS ԇ!b-A+יk6>h܂;~Px_Qx+Lxb9~ljEϦVp' kMVH@1\qov8r!K 曃Hifrw~ n4&Ól8f/aI3Ct/ѱa5o?؇P8s\]O.-g yU1]{.Nch`#rDP[nC38/РS% Bft"H%ֽ, M`7c"57 ؓKwe?q>?.\g0= S6=|17#H[pɃÊ.kUhnFGfpƽ1XwrDJ28U(Lt~$ەBuyUЗx!)ޙ(\*2.j%\,[`ͭꛘjRk>UL~ B>[qV:Ѯ}]bnCd촍?86{Ƚ金M?PL:Nڙ: ַmhB'`nX!9-PZ:r>{]9-J,pxaOS…u|szb Ϝs#set?Y*+h_k=s!/Fȟ\?f\+ B6)2:VGWv7Ϝ 7s]"%Cg\IE*BLAZA\U9tq!IA^5l!FTVȊC3SYoD~0b;FR{){%?USsF18ta/NWyDNE냒 #38J28-R"qNw0ҳ @J%ѝPbQ !IyUU9JII$ǿqC9]ONS➅[1G1L3ۂ:YνOv8̠y5ջ64܅H*<5B'!$a9dAow> qDqJΟdvE  K;O%I],.Uڹ )ϹH.}s:ppWit/Pe ƒ㒅m@2V,h T$pm<%N*:TEGqt9l݇cZhS$_ߌSk`<g8yo/TmىֶF]$d9X ОeIi  NKt Ä670BSP~so\`ꜰ/)\8wmdޢ,fBǏp"d,ŒР|PTpw/llA&cn&XjǞ.tte1;S\ISGg 7 0tmD>i~J,Or\eYݾ?xNf Y@7]R6b0w YWd.g@$J뛰6']q8B9@]Yl;򮜖NYx)O * m䧹D XT3I^f찴XQKnڏ!V4r-lknb>@.#<,M!T Ua+wǩVֈm;;ό7Wܟ<HόctdʣqZ-jjΠ1+?W:0YQYC_}H3q $YY`r\,.m(iEo#¯q^/^Fby;n96PCc ;ZW×1tMZ2u*0S}.iif2bp4L+-$Etb~#4iC AdQd9_p ݣRH sbpٟ8^ڃ #h?X8Uq[yTwi.2;ՠv &př2VԂuE" :-Vcf5exCT^ya`P b{:2BC/\AXH-x?Bh1(c j&Hj)δk0AVОqPM woփv 'p>P_rUB\Z\IE1FSs )pKyt Ǔy&AҶM;+Rϵ£j}(կV] <䥄0ݯ*Œm Yl@ PU|-xW2 9~4I}~VL| _1 D+\Մ+<uuo†-S}W0&p^r. {vyޕdp*Ol.\S.P/ ?MMLM̋"&nb!]I`slIVkeЄ͡o*+U}q9CwQ -|W!k/.zsiUdN|x r0ƒ5, <{rn"X:FdmkC[k+JÄ82lE/{o%ui7"ګ )"iˢ(e-힞33n-ϸ^miy?}ܤxbʔPs\Ώ}FdVʪ'7"nFfE<~_|7ºrۆ@R8Xn\(WF]NĆ)j97 `jYesI\ΟpHK0  L f2d:5d's$I064 9*uT*Pe\[ ` j҅1EP *yq]ieK#T\.%di|+Y`4qu_17kPDjffm@*GTnԣK@b|Õ{kș3ܣX+ X d2)-`d`!oGtXYlmRi(R2_CJe 9 _w 0ۥJrAK>7,&Ye^Ea8F4pzȝ;@RR-7 oaglJo}T:s%Cqr{kH}ǥ}66`u&* Ʉ<2d"+N *2#ZU$W*K&<$S>8*x07a1yCY@ X$GTd%fFCYB,+,<A^ʐ9Kr^fjHBo^zc8`UiB\*pC9Vkj]zMvwb6 `u&%T1`@"!>c"&p֖ݫ dG6D- 1 T"hrZuwa2s p\,T-XK\]{EhrvDHM7jaܙPb A8Jw g;hHڋ≣8#VRh W`m%|qhJ9Oя4G Q<8ֆԺ, U#@OhJ= ^x2'<$ԹtK .e~ TwWprl" rkgKp$d* q"d` 8Y-9ۀNU`,j́>T$Gt/} /8(g pJx獬uX]ajJG|Np˵Ayck2IQt08/G'_._þsGXN+U>Q1^4X10R) t*X+l.hy0Q>RZibK^Z,Rb BmB 6sTK'M 1ԳV1Rlpΐݲ{I۷pgcֳyw Z! W8!z^RiW8p\qQXk $:_10x V`@*l6^ NL$8SCj5`բ5`A@U*d[ a˖$YānEYU2yY }DG_xg 9Ahftߘ(?&3*gw<ꊫ'Hx"ؑBpf&zc$BuwOVhX?1o܄ Pq?BQ B "0Ԑ!Cp` IP Y̜֠aF=}z0FUOW.q8qӐ5ؽj%mс 1IJfKVe#K>', /1j-yC6D#TJTV`H WSa~$7S2!IRc\[}0?^pS8ThܪdY3Ӓ /VV8`4@`yj,5" }~I$Ȉ\~ՇS)LE1\yJa@αZ \J$\J3.<4EkK=LFA >_^dup@2 T: FBǢॖ4dogx!43/Bԡ# nކ})ڏ03$]]5g_P. \&xHVR#wONcn=ՊZ lX^-vQ&@=\T*UKV8`ID/D:fp\OB,NrECQ``'e\3Rad~(h-\9O!H})=|+=fr@开y@UR6ĮΎc5ԚTkyޏJd7~\J0ĦU*H#K?*5֍\9^qDb^D4瞜 a0Δ2 4- `LGr@vˆ晒q8.QtދcG׿߳=X"t,,'+S۔Pg>*ZE]2c5֚,mt 5+XQ5Hxȵ%ޙ0x4&9P8**˗X BeB>ꏠ*>0WmRY`@cg*fEeۙ@ܿθPԑn'|S^ԡr!)?Msc#rیCǩ^W IDATc{a†{E¢58歹tUbRqR{kakPS|*O`%)4sbZyyC.B{{ >q<(kkU[c|/gb_>1W Nr " \-D9St(&bC"fb4怖H@l" JrL1PI\"oh">s = Z #^q磊dzqy')T8qdbk hM?zc<`)D,#b-rmIttfΊ'"Zi JA_^AU<, E IQ-9m(7ʱ v(-bPXhPAݧzLݲH*?hN}"Du\MU2pY퉃Ug>H}AJ܆>1ZZ叞ӣcغe `E0ҽWLl~)p;kVRjry&4,XE&kPEMk1U(  Ur{nmyc݀:6I>øUYL <LqU;;:pXI2peNj c*,wKTGGg9YYԱꥢ.Υ)1ǁIzga0%Ipjf1Ms6PjnYImgbMfSvWwΣڽSǎLWS8RbYܤwf݂r YEw*:}xpα5 Xa1h-r r(љF[[ NPqUc[Qɤ'=d9!b 5Y1Ip.qp?uqA߃zYh*z ,~30E^W A˄ n \ p9.]9/{yW˿ߏ,_$;*bf3VTjǷ)lL [f.õ(.b {}Q$?afd $ 7r \fk4gn4_;i5 +?@,pqٱ&ΕVGփZ"/XV%!KΜѯEq:<;ȚS= YQ{'!a%1zW:3p9r/.̉&EH."c<xrVgN=NsR3uoEvMا8zO?*_ַ0|`. '@gS}1%ba_;TG"fZ P*T#\]VˮLO124=^Ҁ^9'RP:-}T.\ۙ.$%-*x_BUXC\|iCR"#%=VZ;7@"e ;$$T2c <*x A"URű$R ݖw ZR&( 95XW WG}|/uX:X 2a?UJ AuQV>x~w@GʘS:G.ni%]K \ԉNu,l! s ZzRVk&sˡ VL])0ġPEir 3>81ΝF(#3'8<iff:6l BekZCjr;n ։:B}QoقsG+N5{tÄTu{e Lk>1?_GaNN&= {0ҩ'*qsUeh1օiehˋ?:݉Բ ڒ=pɤDBI.hŹ 8q~1܆,S|kyԒeWX铜`nlJWEٕA{GZ'?t < Jj֗?IP;#C@u݁{/y%#e*ܥF D{6}N0LNL F$fЊ -].E|ƇGّшs=Џ>|4}B1 YNA`b%cH}y\~BX\W]=5PCe+-挵j9peBpŢA+ Ɓή ;ȵdcyE*J꺫A FyH0hoBCnyJ:榋/56 ,X 4'&pE]n%x Q$xkﺣWc4t5q!__oɸSK~*1`)׊=Kŋ\9m}i9YPu4MMA3]#qs`&Ǘc YPw0}[wS 4`ۍ) HpN9fŹLw~i7f8Brŀ$\?vYsT?x:!±RJH&==VuRBoR> <_¹xX˨,!q53MW!FuOl3 t|c(Y*VQ*U[fQu"@%A7@,\ip.Ns<Šg$W{-A6mZAJMl !2b{ }`FM 2Y[VE9 ⦨G[쑣x;vM.ikߥ=YP[$3_a ],3_;Tڇ{] Uf+(o+N8Z^ `i#_ZQ`eN֙{Lɢ=dDZw`HVWE@Kf@BJpj4Lqxԝ QXCcJ@\-CC=U~/e"9:9,8crl}<>;8X[}Bg7BM=>;%„NCy&(WYp2^*M]= ˿+x`e_LoDU' FoCgľVVP~zɔ}^6eY0;./ \JXb߭YUjUgP9Р3tvgޙA&8pj>)IE#@,IzkױBm@ B@3j5\^쑠_#V{D sD'2OO`h>1 ʘ786!†+n*gܚkYXz ͏TCpo|Wpfb#P!HmO9x&}\; d2 $RR2kPPbabڲ}P+BQĉGt WrΠ+Տ<(UP}s.r$ʁ'Nv"yWj-/79&j Wh]DMerz@yX<DP?6T=)\87^xX+Uu'eV8J]" \%S>zzhL#qp5E^duѧ<\+=L.Ø:7  cA$"Ear@L3RoHꇾ㐮)' NV=Z]ea“ah[X Cot?{7~s'~멃2G_&[j)9'I)VTU.0_bnܥKyER)1cVoM RL;VvzNM={5w)Z1P1 [F \w< Gf &Xg19ngǚAnC?Ș[JO<ϡy.PpVE}Td=gR4|?̂ݻ1|L"@%C6TźT RzC2#I xMD|ł)^HhkO^pxx,ʽ2. =Rrt;P!#j:{#3H=f=vDJ {@s7z/fSpa;9M )j 9]F"wpͷ /OiSi}vfgdǁB$_sJayv|GgZD9bVj^QZR[^M*ӗC{WxfLX]͔9Oԝ%h-hsFNo8` dy+e\Z,k^; 9Z' qʣ{P]N^$\9AC;;m_J՟31>;qnTu<8yjt/2J$'NHgL5\۔KUS<6=v(!K^T@*kZjnr-ݲp~*(J)m |QrbXZ+X TEK*yW]9dHV?]@XEqbq}UV=%s`q˼`Ik傕q(GWCGke3-=hh_tk: tL #%fq/@g wnꝩ} ZMW݃[ :5ڿ=Rkӗ^(8WBO_'8j--;` N,6JCq^|{J֫J<\+TfJ$*Xq!Z0^!_D;#JC(Xu\Ѡ].hUtNw@5Ib ,Ugv0p<3Tpebf§0s"8`<8 IDAT}Nee{/RI_ <Ο+]غ#cέrOc kYKu'\9*۟CGww_* sUfly)Mqc ;Vv̮r5,w]f/*3}e"`LU..q(v>+=Qr Ѓ( \7KrPVu~WX [A3 9Tujw'2jk۟CwoVϫT8?^"::3|;y|rd!B!]~~6L]ؔ#pz1~Zb\ͫj&П̸t )"`,DTцEEd!q KPi1R N)Z m*z{s[aý[Cvm3\mӷYI>=۟_"fD;: lr7֖ @QE sڗ!4(*LV׹)nO/  $ 4` r|*B4j ^ $ j1jVfѲ~JOO௏H9n&!}ǵYL%[dM [|UQK]^7yZs%?[ܩdELNVb-VXVh0mR.BLpqpٝCȄw^w"f]'џIfW,ٖi8R.qƁ(5FmP2tvq  B"d4W+|!k*4.ç⯏w]S6^%~qo62)e%vu5{~*(֥Coƭ*EMiVJg|ppNW0:!p% +5eʷt*p19{kz8rONP w&1mfB1Om-Xdchfe*,X nC7y\@rBH|#(o?݉uu5Ԇ,|ߓ_g V {nG&6t XkG"t9f2PJ]3 Ri_}g gT_H֚_G=N`)@%K7IL(Ը2},w* Yѡ?1mȽ؆[#G]APf~* bYڨ!BSQ Y4?݉w-7a@֫Ο+x + Leba]4`ygϠY :VLA-&:ׇmYtugJx71`~^$Tĥ՗M44UB;ʻNVSc4̳"y+fƩSdCuBVNGb:靸\ɲ/Yтvrz=Vl 34vADa˲^fm0!&c{MA:(Mp1ъ=s<&W#H&}?[?|/Nj_m]{ ߜGߦ^T8;:se+ЖOavllށM hxgG0%.D'՝d W֏X" +f=E%D3ZРPuyUX˫?ѡA{gـcEUP>G ͩf!YQGj%kXS 4XizՄ=?L<4d)p* <` \!f%r\}%u=b6LNc|ܪF*zCz逕lm(X7cZUͼk[ E`8H %-2p'HF.-gMeh "+0+](H2S c3H}nbeE_|rJjV`lhCߦ6YbA|/΍1>:x+2hрeբLȦ*LxP;W̴eD >]%ਕMEH"F2,#۔&ylgm%bWk`ɟxC t50xcpzmI?˺XwނMytfbY%bŊekQeBf`Wwiznb]xPG]\] F ulmŚG]? V͢Bq;K-wl]v1Rf=ٮu@-S֕jJ)cp7 v\?&bP Zazedޞq8C@QN._8}tվ}r63 58_f/}XbaG9pRQJ]8g|03=ELq'%`) 1~rOÇK+۩6d'ӃpM5f^ThYf&@/-@S,YTq̈|*V8y~ux@Bs9Y 6sCw[IG>xum7aӖ<7yG 8;V@FH|ԪA;VWp rZl,ӆ3"I3N|yM0y2fq<>)/\Wbnq\ &+s\-s)*4ߦ"/'f@aڽ1ή :2yEy3&ϕ05Y<C,*,|w<3rW.\;^m鵞 8Ԡ`CcL0Eb}_~$Nj斛yKmH$̏c̵8hiON80,U8XƵb|a*cfJFή4ˊp@e~;~Lp ]7^1\*N +*vu8a :nNϳl.iRmO 0 Uʹ3~%I lV><"ru*^:] O(7/1Px(T.օ_{#o7,U7s;6oɣϔX(U062UٝAcm,kqA4 e[1s1BL+a\ 83 eC-;q ?2&'ʘۯ쿨};+{K62O b_OqYgR4.M7p*[t=RVqD»0T. b'e91y, V浧r8* Xj3Se/bf#om_5X"Lf8[JN;/\Y8v3߳nvQgY녗EO( <T.߇LK&%`YvÄ#.VEPt@PF>Cpy>!Hp5?v'}H&`8<`8Ë& ]}ӍcW I/iIoTpǭؼ5MyO\alx㣭QbBޑF&ѹJX+.U+t+?:ɢ/DCO_N`߭bex_Hֽ ܐYN],o?hz)%I .tN-ס,eŢ<۱L+'/B7y)JZ59ϵdXb-] 0r|4 ΃j/f.wu$a\]t;݉p&kl\? _ U;ap+ȋ3YE{ə*]ٙhRʁQTEҽ$̵a0grpYNϘg^39^'-}'@4p1@8DS>!rPҏXmGg>X?'J;15-0=U9Lk)(Ө2)`jZP4µjB"zw'Jgϡ?]{{pm8[D}e{~rꀝsa!̣x+5ˡ-5T t ǮD!B@7K*h ]#~b#A`FPc"J#ƒBOԛ`>< “My<.pxP!oB98WK#?}m0{]ؖG( F̡%bŊuJ| ”b~D8Q3 qqO=93 lс;:pݍ?2&'J,㭗Z9יrNV8;k.):j,.s'Mj` 3! ޛK6l"5p6ke[ $>++7K [xa UdX=_>/xłt8:hgQȘ9zu¶/{"w۬J/<Wj[[۟(V0: f*H3T8SА,@BV{Ȼ8'`8jO|[gޤ`*;E& =ٰF7ߌM[ގL?tls\IQJglWG05>cX"y+#ͷL_\K2\E0WѶ~"ᡳ;,:{2d_u7odg xٗW!i8ЗeNaزnEsmwzICytlfWӝh^1-)vhN .Ct8SΉq=,`2\$o ̻ %h\@xD +mOƅ,Ls'>~ ]iUahFMw};.DoNrѡY̭kgҙCƊ"JyW°\jΟ-YNpbWo}9d2 dyKIUpn ˯r u]hlhH>z8"&ǚ IDAT:/G'k3e5 Ηu"zoa5 dPqSA|!f` V/y"oƵRόPhحwF2oQ}Z.pٶz;֋OYI;U>t/#nJ,LO1tjzݺUv\։dGqbNE3ɻb$JioQ.P@3܆|{J??!d8++Wbzƥ8Wd>]LsR96zsBv QSpmOBB;W^"hɂ(Uےn 5 j7c`̱yW\Șp,7w_ӒZt%r*fkw~n+}|χ0Z5FfQ@%n@:@Zjw'Vt @+yfW ''{ 5D0=YD/?v M;4ieY#t=$IY&G"`\$k@#3L(RL:_%9; }Io5"IU ԂH\ TqZ,X.Ä"?L x'^8)1 0P ` RK$LM P6㊵nv+xAw~nlށq'FR6;ďYαb$˅+08ִz ^pbV{peylޖ5> Ύ7 rjȹ _ ZPI8 0FS,Wn73T_bsURn}r9|UE]u8QnPD\0q@3S%†…H'pWŢRڞǔAC9s&_Y[w`V,̢01K,;R8 Ɗ@ lj4s %bE\\y y> 'nЧq~ELMWBxmy X@KӚ#۸!0`尓 Ot{g"z:6uN1;);]7(b2!Gcd2d;8Tza8RV>ZNtNq)qT9iϭ#g~!Uz.lށM9=on8@a\s3xXȾ타Tñ#,%84x`n3E8;v6'Ond犘(ŗW$!D_:_)r!ݡdEm#49 ez. YdG ;&F z&#$dv d:@Wx$c ρ,kxHu08U/~4}[EA-;wqNjIZ_8<+VҀ?h 4bԚ,z&@Wwݽ9t1 m:2Ύ a$7JNY~f:q7^9-i"$FK;R<`C:ew`LG d ds2]' *3t$JZ6x9oЉ# ݸ{ ~ ןy E{'v\ѥ@X FwXb-dNøV%yV' >ֵʥFKb X@z p_ց Ώ1q~)*bYLg2;ƝnYu;J{,݀0cwh ?ǝ ϗW/ܾ Pes1˩p%&Gi}9B=Ю\q 0vt^Vfw|z>//փuGړz9V2cŊu dܣe;r.:s81YIp)Nշ)l6Mm-(a#"]{ŭa׹\JC1'Dk|(Th߆!8Imd)? vP /D^Ynd 9A8H8OV D{ *DGr r7 sU;]`C~^6{? Zխ[wt``( TuadhR+VK'pȜ+sCi@mߡoQx?UQ"oSz"Sg0~8מ]8, EgWa72B_s]@2k\!=ypY󈳵f;SHc E;kJX:bpK%+GM|F|ʢG>E/!{ˇPoF/uσavtdgqn)2OOs/*K`t8X7}vGY `nXX)tte024Ι+ւbO<< cG d9رz]Y @pԃ:N $~=ش*tn]w+"ba:k[f+rKAv 5Y&la a 73 X򘁩|)WWuZ"j&vT=Hr=qXoY9<_LCx Ib9FDι]M7NG9ƹs.r^ usqݍc:t0CFΞ_ƕp¥`Nu<-rv ~)c9[>ֲ3MΒa(p D8:[YΗrCNx%С)+o1foxW~_;wc+ Y uߣaۻ10St\õ+\ d<J*ջ"}g(.=?Q5| 7GyÏc<:)n|k /s7Î]LVq 1H7AbP!F:AXDD QfjX- hV\ g/`yp$ q {?d.[{<(`E=k_s?y^) ۾2caם68$,"։~EGWuN,%WŴ^gX!~0w}cH (_D&3;Cؽ(Vq] k@`bhgY؏OoO7(f[ F;UX-g ^]+EJL12-xcն~(v;FΜõӧ1z^|MW pF YO;*1o A v,ȸNes"ĔK8S0B9c'qo` ~&p:X|1ڛW sӓe\\(XXKza~ryKaB[h5 MW2sTk5EeZNX`jK:(Ç=:bѳpObYveH[G $ ,XrD%B`#@4G b S' Kw) R'SB,?|_krjk{3͑}ymWU9\\<%]jrb-{E MOxaH)XaB; c(lIB#ga9\;{~$s9y~946'Nb xǧ;Dìpa.9z1K0ڏG=Z++fAUp+"o]9p  AWr3}C0g]P8W/WѐJdʬ)8v%8Wn\ +X;S/r|}s$T5NաAxx@[W?']WaGr:X͞bsp;߁<gbiL9?oP0+q<5t\lt(-\'Ϫ}pl(PqN:!~ݙyΕ z B++!Ía-ǰswɈy9DşM[EĦ%}?r{+DTSKzV-s‹\6`]ld176~`ǝw`#:<00{<=p^W; 2W%*EFyV NG P~qtߏݏ<;uo0%L;Ocp;N5:cGc+? \1'Ԫ0jkbX#TW pE|Ks:D9TJ> }]ؽ =}idW/blJ,\gRxiJj'u$DHq5sf,?j!r-]91K`ۓDEo(QPR S 3/bEx Hfs?<#Gw02C?1L=gē?܉̉ƑSC*J_`:]29W>w~P_wʡ2T.[7Gp<DZgwtnKU\8kWBcg2U#H\F.\9.J2ȑuY\~ m0xi _,,ΟϞXܸ}׏D:bМF t[B+"ӏ>o i|gNWEF,@\y!9{#vB+ڱy\8 ]nGbq;ww"YT*w"bM`ߺ1__J3\Šp w@`)q,9ޚ0FcVsAXz{2ExH4Y⪉j(BmD}=|=wA'Px4ϟ/i{p:<εUcl`ι9;}_uիK"JWЂh8 Q~+g&1T:r]!mEܪeZ&eXGgU) @$Z^e_0Rdzj+" 尒#{DQ/]o>w>;#50'cb Ϣi̟?XCyn m'9QSJM.1d_F.>/0||aYE Ȼq!d~D W.b6sWÕңlB댻n՝UVw^i}Ibaĝ"sK>mp3(; Hp:#?Ap륷0,} O>8CLLk.4%RhE1 ??>jzU"-X~侃qLF5}&N~ HFl1c1^掓֠;!RиZjYsQTr-ӴA@U0>LDNۏw#<4̾;}p=ⅳx8Z$ zteoC 0}MD}=!{؋ׯag0)X5v X&qszp8WVV_U@l4xTk a&-JՍĆb+1J.|ƾ#‰w #>88΃Lx,ΜFY<ꈭ ^Mr  Ο/X IDAT{qx8=}sC٧Qq=HnA@A+"#Ø/PEh'#vK%DzHe7)_Ӊ~f܃hAǝ|PSȍ݄P%m2}m @wߋū_PmxxQdG'I~S'P_XLC=pho:: ]`/^x0SFaIq%o Q,9 y@}Xb]=J ,P@5XYZhI`Bu]7vT9E_{0:DMY̝|WQƱAhHb>?' Tµ/񓓯gex?#kZ[:" O7^&s6'{8FеCWO}YU\kuwtP`@XaƑ(7nf;(Qq'A/raaFp 3(4Pa䥘ޙ׉ܡt"ʗ/bq0:@ztFǡaRsOx%^=_uߝ<.w{{_<~|UcEy!u ~ϠQ΍ב39Cs G#,8OA 2 >#"djD!ZcܑJpB5SZQq*QFMč+m"YB¼ۯg1 'Cl=|Σx%oR gz}\cދO~0IcCǐyAՏ믢ԏQ|Ke *w?z1/jQF'"=+AYr¢n\sBPUk:R g_5&TyW>tP0!V&NxPxĺ6!fYpB0ڄ=;qzʯC˘{yԫj_u2}?}itax:F٧0o:5;b[9Dvꈡ;FvvB աB"ŕ)_{#7,kíOMeWtu=QΑl`8Y &7m%bEّѬi֪ڮCr)Km|@#RHa 5: Q'.V7;*KO,h@Ha '! k[3ARSh"ޚ Kهa#h "pr%νlO"z2ص7L6B&..dU/P#`BQԺ"5:NQxΉ %~v_AxO?}c?\.3]WȽjwB)robJ6e \0/)bρ*?X.VȦc?jcw 8fCW+L.8AͶ6⣁3e]MƊA#a=Ceb;SBQm+gǵ‹aarZ1 q5_`jZƍɠ$!y0jc\5idEUzwFgjnQIWjȽbvd0gma|O0cvl78AͰsz gfJ'91ZluWI_}ۆP3sɹG7?s]|֢ʬu6AЂ| &g[s kLKl'[G;mcD3M<#eEmϜOН04נ껱s.- 'qNs~A;='!g|<!ESbqݱvnc5H\5*$F*8p'Ds[0EzS3><X9XjHWKWuBv=jU׽Rm}NDt2 \,naVf)‚>UZ\[izn_fT}<m ,ʙ M,s15Ȳa-_,!,jX:ڵ`У={p :DA +|r(B+h1r9ZS }SBd5̈nv+v"lEXnRcLՒּ"{n P/㇫V8$X/2DpÄ/LnwYc~C aL6!D c):'ʩя!у@pCXm"E 2wK)x݁+Htu;mGD=ŗntElwӟiu7XGҾ̓ p2E2dN0jjh5Y4QmM* ɜŞ꾏XWK4*݋B h(-etL7+*dhBC+ܗ?@:)2GEm3o0Jfw}?Ez`Sܟ}Psgc*2W5x?&[MLہLT2A5 dSlTϥP\+/.@l,O~,jBP3RBAnPŠe鞊, Շez:U~Νwl̂mzZcߏCP-,|9C; jeg(eG~ӽ@bᜣT"aj&p&B\9Vִ%FJ")8꾏Z*=|ɦ7EIZ1U-z1B@veڹSBKᣄ)Zs{:3)ӢH¡aKv,ᤅuaoIdΎ8 C!׊ b.Bus3 WUXb- ؃ Vz @;Ak'*dL8كܴYCC'K}Пȹ Mf:7sRy% d9cZԙ1PZ<1ݧpxW&&n.u^/,Tڹ!^W0LVw i#ZhT@4\UsYZ/b+ ]>'E},Ob;z@V0&+UԜhQw^X (> Z+îoeCU +B}7[L4b >3QUk"Me c~hZ@tmG0  mUU0;20V~РtM#^-Jzd}quEQhe)y'rBmw%CkfҺGco9WMDUGyf*|?SZv@ rW 0.kd4 =.r;wE"̻B(B-YhgBXu\VH3`rZ#7OG 8OjWvB Ze[hb zkH\L6 $8=QML LCv109pcj3T+Bb :yYQY-qGpW,ʐrYcÅ2WL b wpDBy Mt-u"9Jٮc[Rs*3߄r-~E63j,wcvz }ppL%mC#*]vόv\?9ۙ؋c %L]l/Y\Y6?Lyc}B AmFdj ^ ?XT 9GQ]m(1bDsTۣ̳ B~P@0j?UTPh!)v|9:/7mV7HMQ2PIW#QldF#.f X挡CZ^ rT8B\uT7{*y5k1̦Aװ‚K;tTrY0>:0fIeO(nHF}u Dm|Ds-FUTCZAlVVrmVY7)k{;@.IV|k-r]K*8`JDNdΕiT aEesBJߴ|α\+8}z^^3ʷjfs``-"R2Cd*\]{=agr"^S6DWĕ9]]Kv#ThX < ^  (0|Ggp{k~eJ, ƹbwZւX"HLR1OFǁ`×L&fgʱjv_鉛a5jt@T}.3t&a b}Go6bkk9 yWMwXZµ2q2~O|_$+a-%يZghwW~ ~ǘ0b*Vm<0?H%6}$1 EIJbq/IDATrv[1&r`\mqT \+f.8ʜ#7 DV T߃-4U3  OnoT5O9t6)jSbA+"΃{fVx ɋZͪao#JVJ\-k;l (*ZIAhڌr cȭbH$4 ubCV<-Yȭ '1e`PIS Vȼ#kZorIW7 suTD;ֲZ{ȂUک(AktUcḨ%۩ L|bR=QeXb̵n&qӗ{p롾59^ccd{"zjH$bV2qpc\CZ>m])3q>BCfs0PXb==ǹZ݈V.W0}kxu;ЙO\F6ϱXcRI!hYcĠd sTF'!Y 6'R\m h R8 cNU(_}JX;)W9Wтn]b[k&Z݅sE0ƐHzH$<$q(0_m?g bl6q8+cJWY-kn69pb`C +΁3Ey Xj$znVbZIqu{ډ97\* DBAl)6UspuJ [0WAx(ę[iB#grL)&JmXKJ(< lVqDf+ XŠrG˶seq\pJj1# U1QWQTd!J%JKzApV8&j!IaXEOƹO"Mo(`;UA'y$6-b:AeCx[IrXmT@#UF!CDDwRZ㋼IsCw&FzqŽ!ւL6,zHh A+/Ž؉\`;@s!7כN,IQ>MB#$"jWPKENY[݃'1_XٗZ&u$LzGXEq~y# 8'_E(HsU'Fx`Gb(pGo` jNY"ÁDptq`ƃ߅!QK4 V K:JU I%x,mVXs Z:1Z8n`Zp`o rܡ835=JX&Ypv ߝV g_BQn > X1cv Nͷ; !vdr-0fsJgL);-x vI*, 5L[b LjyLx{j7\+ L%C,)r|L$Ζ<YFڅ/L <* A[F [ݕ%Qm=rP=7F¡^>1R,`UɣDk&IՉ :) wD77G..9XmJw*f:rPvplF] =:46:ӜA pVweِj7TM.J)!eQ9"#]u4bkљO!ߕRzQY* ֎oA_>\juWV 6;(Ⱦ&n`G\]w:Nl;j * Ru} ֘]7ԍ^\ Ն ̨Md޳]sfP*RM@esd)A[l:yZ* 6GyAc g(+kMT;~VWuŽxэ?}ypp{e Pd22=#}*'EDK1\9ܛG>BXA@t%3njnCo#^y2rwm2 I9SzmO8:SH|GTEaBA%\ l93BeLJjA +`unXNC+͡#I\Xa`GN=/T0_XDjX5]N"桷+vikP|S'KjGj#> ;~|W T sxDm9.4 AjԼ5s_>|.}CݸjubEK K\ZȢ!2j5 CAK&@_>4YdR N 2( T riss&X/|.|Z"E[t&4R8:n\ku E[~U2 ơK51$RA ,tvݛ B}f)q "֝|Wn1xB s [% m ,b]Нquo:lYf+,Ԩ>ADൺ֥3Cwb eŶ>'qEF"֍>kRj̧ݝ`( vBĺpA3qyԾzI 2]),WAr E9nA@ gZݝMEzj3'JA<$e]-V4+Vw ؄(Bh+ b""jyAz@!Bb۟AOod @;JMA ,"Dg>BXb1zuqЅr SeWAĺAс[n9tsӼ>b @XXI' Z ,B!*s[CLL09Z6)1AAXRp?`ldc#[Rh]  !46܏T:ٙTl2D@A!:X$8a!ZoE;jkg'Zݝ%s^ou ¢"בD瘛]t$ߝPKc1Ltf`rD2"% ڇk~nt60[Aaz٭1SYKLC;; X eJ\' ڏkr])tđJ!בDa2[Koδ MdJ\M05Q&NJ hkEX]Ė籍AfPVw  dEeZT:T*FaDb͘* Al֥VOo}Y0Q3 (̐@Igbb % "JEH"בD3]{( 5=Inv'יPN[9s-AA ?gNVIENDB`v_sim-3.8.0/tests/exports/vibs.ref.png000077700000000000000000000000001370110300500216712vibs-3.8.pngustar00rootroot00000000000000v_sim-3.8.0/tests/exports/vibsxyz-3.8.png000066400000000000000000002562061370110300500202400ustar00rootroot00000000000000PNG  IHDRXXfsBIT|d IDATxyWy;TUw>FͲlYlK67|CLn `- MrC7@X{ $@b/1"ye[,k-wwUsZzz鞞OKU<=Cw~Y  h  4H`AA4XAA AAD!EA`H`AA4XAA AAD!EA`>/l8  ڞG}~AϣAAD!EA`"$bG?Vx$A ,XV ;@k$  ,`fVyR CwX3! hPAt(s+9sA)V8{V|A# EotBpQh ,HJ rGWW"b:159)O>S;QC݋BR)'?]-1Am.N؏Rbby*=5AIf+dg `stwwXF3#PRQ$M8xQ(M\c BZ8 .AhzDTBwwwM/yPJaWН_?mqN:E\xP(@5J v[5n\Po]C~r /i ,ֻ&smsu5-z T*64>  xa S>'N`bbb(r\^NYu0> @P@ɭP(48 Jg{Zo=f}?ZZ䞝Jݯ7bhhR e` 폦v}7!>#[n|/!Po _g_c,LBATc ==(X,B1V{b!?I_=~u&k:Uw?+~ttҵZ ]vq=#׶&>WK{ a+ LV<7oFWWcˋO#/V'*FME800;w&uD+zZC+{=z LGT  5t! A X#! V1(J~NOO'-'6 @3Q+E8*'&DcccIiXʪJ)e a۶mPJ7y=f\s SDeljl֩i`b *Cm,wuRֽEQ8QV1>>)LLL DGJ;Z-0 QTJ\GsӴ\6z>*pyLLLW;FUyכސ,q !8x uO"lcSBkZ:F8R˥]ziW]w5]2Wz}q 9(ٳgEQbP.B4QxRC(%dRc#hrkyRsĉ)cZDaH`v̙38{,cm%:ΆFSG'8ceB$iLOO2= )%(dEUZ5uVT* "$"'@ZMMfU*T*bbba" fX" ."ra""'RITZ<6ӧ0qΟE\A89"V=?k>tY0 QV2q g3)178s QTj^-'ܗqL4L-ZN$&Z_Y5c>Wv#ޠ&_JJ$e. j Yt >S HyQ[{ը/=†IP)$6-d V_]VVVQTP.o޾}-.!lԪZ.[\-fW5>j(ejTȤ+TUiVǑMEl1{unȪ{A3Z-t rӧOĉxgZ"r͊TC6zy8FJF[va҄bw 9EnIm9ktk1,$` ID(MkJ~V+Rq /w?|4ӈvՓdI)q̙j'c6Vi;0s r8ƥn#hZ#+5Z+MI'\xaå\| +r{g)<=c qc+SLת3Y{czĕd1@:F]NKYWz9 Y.zkWpt:\XA<Y)WD\" H[W9quKFFk"$4Bj/+ (nAmND38"qվ A,`"H\A,`DLEHTA4X !E2P  " h0 N.  bC,  C  " h0$   ,  C  " h0$   ,  C  " h0$   ,  C  " h0$   ,  C  " h0$   ,  C  "Y`1aA v10:}YZ'Ke H!EG"u#X*|X=f_5IyAiH`tڊ+'z<%,YD]2Aِ"41+R҉+ ehS{z%$ :XĚs!844R4b)̂f1Vg10&+ܶ4 /  ,b &l jʾ^lzuw餶Kk@)R]A ,bM!@,t J^eRn"&9˭GMѽրVR&EAXĚ0Jj8jNj9jDXۨWFxq{bK+MJ5A$$s?8VMK 6Rn_.s͐I1j(I‹ ":1RR#TGyTUs< օsWҺ/0rN&ͨ!N;4A8$E\*- xuE6^^j'8wA8%nƥRFA ,<`Ra($ `f.rΒ43V J)[e"$ ":ƀ!KU9 8Zkh"ԥS%`Y3 fTV9E‹ ,#ߴ2(J^AH`-9|5&'B*d':3De3 B ~%^ A vВJ# Y$!E8]>z̜,+V9& t /LKtHo`M׵ #0AXĊ9C@x[ic:1Vmp«Zɯwba^Fx^6ev8M7|H`+BoRBvX,O{E@$NtyX|3 $dl[&EtT1G+N $L}ϳim$ zE[a(MK//  ,i LU15IVR8UsxVpNxGQQ~$<"BOo"01v2ì Y,弼R%'WJ'u]a5Ad E4q +PLN: ZRVTjbp/a3p+ƺ$ϘPI /bAh=֕sgTN#L1tr ~!<^]ᔗֻ+VXJĊѱ"{LIR:UOx$9C'71 U"X"EapC ǡ5pl b W^J" WSXof3FBd^Z E,u%Q8Lj K*j$Gnx[`f;Ҋj%NjU"EO_7Qpnd2XTbL-<#({eߊ1' 턡B&lH` s Q f'ǫ8;2=ϫ ^«Pr"̳@@ZTbıDX%E4XļtXG''s Z^MP¤}ܺzeP4DDH`snC gNOч A.VxW!(xhu;j{ V> EԥP`DΝ9!U'|P4m4^Pe_ LJ1" u#h6Ak'&g /X/P^^ĨVVLʑS$6mE40>VȩV 84EQ(x //Dc5$:X7M=`|>5 rd' KUtF^BɃTx ֟zx%«"QDQ6 U ,Û{#;ɉOLR( bdjWh꺊%m^}H=ԨXrٸG$J qs|_ZIV!Ah(OG(Ô`8\J8E eviOGr ep} C:19GA|kG^x˙&ht;Rê1QAke~+S!;ADT4JxJ~"^.i %HRLGIFZCiK/ c:NA(2SΣ! fLWWw/ %xxU#DuH`nCo_X_5AaVm]WGщuu` J%F*#L^V`4p 'Gv BT ^^`CJlkz|`7`>5ċf  /nl /#mOf6U1=!%e^ Xe[ %syOĹ3-Apkb~?'ZV  ,B0@\pea̯g ;Xm1޴Pq($K GAww7B^r4vKJD ,  =S:k*c>|h |qgNS!;17/x+z{<σ|g2ǀ{P4 - P(x14ӕhc(u(OGxYWļa pnVZi6[^ys `^RQh̼ZE/[,3gQv7\ &ΌZDSX'HdcgGq[u'"$J,@Jʼnc4KzD\i+u, GPرs186ɉ\j U;WRb~.m*)L*  YA,ع395*@)Bbe+~ ϏgCv'ϥ>sfM*%U~aM+'jE~DA ]PQ)Gx1V\i@Ɲ'Xm}dzt=s#TN,]f0s*IRI(̽T!WU3AM=,t!6#(\xz#Ixt"VrJJH%!c Ő҃1IDB `ں70VOAXz zaCXMŔ@ܡYXm]A@kUHo$+[ȮI 8Fň/DsY.$kB  _:Is[: a[ <ÎMّi|+bI ,bi#Xq )c,wSRÎ,)MHl9 Ph*t }< E+ 44אD,"ı@q*s/7, wjdc(!`.я-=ǪxV;SEiuLVc`9]AuXAd0܍.@>u2/(E4n]%;GqdGEt2ZƢZ8 87i+'RXA}\ssϞFT3c$VM[{q~@Cg$FK 9iM`*/8yI;]ю993.w4މZ!qu\_ȩ)<!bR{YO!7$5K)V_k3{3A~oj*v^bX=3!dm(aǮuG+9|ϖ[=,b Harb3!8;Rf38i%myLCgef?=co^'Ylh}EıO]k:M@\k6uΝ)f-#Fpx*N4WnZQde"Y6%8Yl7$*hcjʬLYH/#^>=A4uJؼq IDATgItitl#8WDJC) 44RQ" #Q0 !xdiLqYlK}kaR]ڼ׿} lK'7/ݹ' eQ(z heW\zPuh@e[_<٧cj2l񨈵D͂{3 ͙iSdz !FoVpΠmJC( Lkhq"X:o>^>%A4Ki86P,"X Ppq'S$p:27 },cDa0 Q Caއf]ERvH֥*>|7)Gp=6<.rzzLMx3zm!(07`eLcg0P)A4+Y ) $\+$m}p+A(^7{"Ҷ uyUXDPy<RJR""@~"vd}X7dDzlq > sz o3!Z+4P˕k 񌈖Ry<2iTZ3>j%^6h \kW $A`X ' rd'Zήۺ^ŗ&%%o"J;V$HZHĖ{I r\UrZTaJVPZ#z ZMa!_ǹGPw֒Al;WOE8:ȋ+(" @A-ؤؤXell*Эw*I+7ta&YŢF,%Dq|e}XX{F4'Gv-y>iWݽT BJ|*3+1#fihI3QhjQ(ETh v]%тDg _v{"ش. Rg0z ى39ۙ=cO1MW%8`CV\eg_h43N+j&$e V7Z'vPJ{_׿M:]A,M[z0:8:c7Nm ZDZ ذ pI~b&Qns? OglBOeBy* kg$|@gb˭Kmi0f酙( aBapܔ+oD-Ϣmz~sFAGOo]Lg09|!!LI06v+6L'=3VG'Fh]_X3ŕTZ+[?/ݲK +iBn+ LSm5mJwxUFTJ[^5<+<>4sW $`~2z *e*d'Zσ5z WET}8 $+-8C`)9xͲֶ^<LKJ̬F:^KO~s{ߋA}ۈY>ݯ1"^Œse^l6=EH`ե7eW/4SpV ,P-F\--+}=8$ƊeKW_F8//療~fR ijTnny+Xy: w#töLFX3`G?v^ZkL8HC(|\{uxrcxNfaklgXI.iMOPnxqDX&V-3vK"X֞"$Nehv x 5"L|ߌ|qNj$C|_{u:^r5 ^Dܲ2CW>͚jVf|#J$4W~Q^ieEܱؔ3bc#@ʗ 1٧a\5za34܍{QpjbVx\wuk湞;l[!2k+y>N~)hd Kwf,8OKP]uu}.;V{iMjw懨&\cSxƗpn~Qٽw{sQWDrQ&xA[΀wS6cD_C:юٷ }LWç`*E:%;Rɇ8ql"99RgvSi"Rz`+`e'xl+(p4҇sYqD1ZqKEU*]Bw&:.d4h#A `p7CW{Lu#kR`mh._ `b'`baIJgdcew-xsXD#*4k蒎nÇiʥr=Zb)IX685㰒3Mxs ړ%\rz@l%,XCWm"Q<)D;p?| 8yk_3^#ι7ܟ2b,G '+4x6jge_ok>\e꾒qe1X[ LjB,zǜY bWsM/16 "X– pUC<ΟmKPn0__ 7OوKR%ϬJ#{ǀG+ ̱''R&꾢VPeURP'Q+X|j?[#Ss;QŒ(Y~73#DXHV,c1HV,M#yEFv3@i^^skD`]u&lh`$}dDt/ݹR R1WE3LIRXw/Sl}3mL15ˤv/fTl1U}kD8m';RAgfBiVX:);.<H=\jЉ/D̆(q!Cňc\ a"zD+ڈuJ(OE+,N7Y6te?t!78Mh(;<ۨ:Ϙƌoc8cx/Y~'2!· E>rV߸~~J*>Y3gZO,TU?2;ˈ3.t8FEQdYjy%c>lxtI+PV\܁X^޴Δq߿>G[=, HÍJkj'b[nX9ݟ=@""jU=Z):44~sȺ&5[I +jE v"tTdF*ss?I?zw5cCΉ҈(2b+Ҟ| :ì'=V(z x˷c%`z Q^"D糽Qy-Lm/?f2˦#fD<WIqwR{>"J]% 4}Yw1h~PHf#fXܦ Y\Y/MeTR ?s"\S^ER?,SeX%fJ9Xx>K ţxq_:kۅ}a[᱇OܙV0.p*[cs9;ёuwN㯹|͹߯rVƆ#'Ȋ:g R *"T+H4o~ =L.zDaTۂtVa++{F-j`kX;-rmΎG#nLz3VDcl a|;3iU=JBCs\y& oMs%6<0*_r_J kۭ%2~¦2sKEUZm g(K*jJRxȳ|v"hTܥ 6:<`p;3ӳ[<3(Z9! R [{}DsٕCҋ(x+ CJ=[zp_="{4T^vHڥ"+||zwWkIMU>Z+vJn cJ!ca!l+u/N[ܦ)Œ PTjspeZJigfB&3 HIhwJ]>a c#-+YKER` M(@kɃ#x|aCTiO;ehROdeՕy/ydJ[ ʈ$R"FihČA@űXgYP(rnp5U o{w2x/;7RSiD պt=@WIqjjc$ eyfEBJBƅH_}s ZǾ1䋓-\K6 N`]k G8IRAd&i"XYq`i^Y+FY%#zt*]RDhxwfi.nVdk8g阬bʍl{q+?#[ r"%{܌10o_"U+Btu8w[rN|z(@s3|3PIhmS \D/``F@U<-31EڇR~ pyLT+Vjch f@^h}D*2!<"B(O='r͍[gGۦf-E6ڽg7lJ]>G#$DJi[8$&ތ BK3Y_;ї]ʵ}-4 {O(KHaX1"¥%N&gIJ5WȖk,ܽJ|0:NZQ0Z\.c|bіztڠʱ,6X.7l[bvy"oLm^ijR4 cq8 er:;!`f{FmHTƹ}eU9鶐Yv3lN-bO墹; wtM4ܚ'u:s;y!2'JM=nX .SIZCQpۅػo#x`)>D{b~2mq9?PJLSef kR3Eif4?<^Hr[6yKOa@{ryzʈlnBP,"zc2.jS ے~5b;#SƮ ځB=z`0|&jVػocϏ~juC3 u*L\)=N4͘s5+歸S[o*VZ ɼ}<>.pRl\ᏏVhƷ1tB@"tV$县|4},+q=?֖e50p !@` qEj"RW$R|p C:n2(Sϝ&q X,+t^?enV`D8z8^ {:m< {X,JY9LK47κַ/W"An܂R#m`f(7l\o9*m$1.(y(V6rb9$в14"KVZՖHYt0vn{lveL8kkw㏾)~p̻pţWŏip 0(Yq [bJ #7RCkM82X axKOٮxyWqԅ5 WRV7P@XONa|JD뙑'ݛf|T10fZLOC8eYh2YL _3kLL 5b)I!#jW9^5>=NFſtLcqZmjܬ->tdݬd֏YN)׿ךy$$D[O kv:-XQ$7PpqSw" ($+]U?Wƹ鶚!At>/Tb\Pꚲ;=I*<#\YZkDq=[Fkt6mhEV>yDfn4sWHLM߅:,oQq2:8! nֱ)ؿD 'uWOiag|5RUO}" \Wº|_`Pu"EF8juKdx4 \ RIqe#XB_8sf#[#Ysf>:x7/~vFÃ+[pLԣ;h_M^A@+#D]fBAzVm~7q(p:u|Gohg4 /ۆC]>Ǻ. +%-g\<a|jRTE4mEaf10nf1cƒ+B@)GOxXII]#jcK9{؛qS0$O&}9dp%{,$]Ԥ[3d^_;WZVHg~s_FA4 Fn|3\x/AKYAJܸ}&U"%k~r1Hpxt=¾O@+ $NXYE ,uOyL>\=ne;dp%^l_=&IՋbyEDXr7o-a2\k0i|߷_Ava?.H IDATH''B@Oom#\o"~n=z.bYP65YnIkH.e!JhyqBx1)ؖI!7cM7.0zSoi(؊3bcG vGc@K+h]tX곬Q;׽s}ozɇrlD;~+W?*҃@#Xν}%Euͨ窥k|BEk@-IIXeLN`6UYJku#XVr;#Wǎ F nh&-8Dl-~ᗖX>"ۦBqS'#>jE6MW򛾯#8;2#0_WD?4ܝғ1R=!=Z~W| ČhLȓjbnm?d&y 8w9'vEObwX.h]w|,s&FHXkkn8;2p䬝Emԍ&5*]z\..?'\=z52uV#5u=q&,tҲ'PS1:+~ i֍bhαw㰿;'n.#bO{ZvN kiN].#pwX-[ `8Տ^#ZO`w)l,i1'=8]#ɿ܈k#V`G : W±/G̉nEksz.5>Zȩ)Zف C{6Ǐ;}d/33gf +(OBh2(\9vEO1l#ɿHSL ӔR+HIU#@ZD:-Ea3n sxGo~ߥĩS;M,*zU'.-'rʊ*\?*^ftFDp]_Ҿ83cϏj{ևhK>U*8\WJ"^Tl*\r%c=W"T͋9`Y HWoIѫz<_ˡ|P3Ә 9upϿk2rciֶ[HwSr>?Hhn܂Rj[7q^JR ֊BfҨz.2Em, 6lh6qIfq>E`[cӮT:7' g: ;X8i>'l|nyR =C҃(ؿ kV XIVSo?T<6<3Ӆ|ߕ%FAz&{>}􉆍w6kí;~Y001TݟIdNg ff6[ߌEl;>54cߠjB'jl-cx_5Y$22~dRZ.帹fZj=s$EΦiAeBqoH_~3=9byoe$dWwꎌv-gO>fyxѻ{MQuǠ8O9HU9wAvv]{/%~]cNA,R]=yp$WzZqѫdrrx$s5izzzfM=ywSO0S9s& g?q ,O '0Lem 'B=ۈ<C\ĥ Vh(_WwJfS :Leg,bqI9M0Uk-rjBpWLQsVqvdzMs1fOi2!|_ O=TR1dfz}M;o3uۮ)3 8_vݗĐ< ष/=NY|[XG x'#bk|/zg/%;xUBF\1{0y>RPJAJ b)&E{ ojG]98gŝ"X+"fz.'r=J]==(  q@/<\omi?%y>n޻nJ 5B,-l(y]ǎK f`I c3ZfG}:UȐ +#[i6 @P*u!}ϳJ\\.C(,\k0q|ࡓ-McY@;6ss_V7PHjj=&&'Q m?~7#2> _}m:t]v:\=2u<_35:wMaf/.7z*3Sˈ^dݣiauU-Fh]ǃ:܏->mQnb *3QLJg&f#VJ)pQ, r 4V+PJepuaӒj;3عS W+z.s|\u|tt}ǟJ*1<flDUaeF'Nń`d6k_emzJkDH9^-j @x߃+^wvDi#qw ̈+10 J 5p2Qs\sqs\)HVj^=z.-: CE\_w[OJǍjk;s{IƵIZĀʗ: شq;"m jĖ2-?O} !ف(VAdy^fg5=؃"0\ $$$HA1L[LebHfH :Cr6퐏C-^bw X\;WguwwgfU=]||_~{29)6qDl68l||3⠄ q2۟=wyAaeko.uu("Ex8[NLàD};까\D&|r$C=W.p(${WP)*l <7?S7ﻊ{v{Zˮ>˿ HJ pᚵ!(*Zߙp2>Xv-`LdX_T6^F2Ymb)܄=dqNz.s)ƫWE/-`,1Bpp\=\3T;\`DHbԁF+m3{D)<^˧]O?b̜`I (4Hd@F8h@׿L8Q It~3E^odY3;9=W^Ӈ5,s>4 u? +j^k s2QpD)ũg# \z@W\hJ`e*dNңe׹w6}4B_DC: dh ?1 "ƝI!xb΁$FwX\gPZ,fE 2$a! #()(29xfd<~~pcqݍe"#4=K6xYͰ0X 0sz0n48H\-tKb[x/nLգ? QC[ͦd d X 3M0w^:EոB~3? O0'sɟHTQ߉f$%F8;k;95*sp] Q0@C7|_d=0K2;,SDҌeMes?弗lz.SϥG*,{'?H 8a+HjA_"VˆW$1IyxⅽA~c٤ *@*/@F<, V \&9k1F(qL,ۈyv ]2{x{4&^Y8WpR3 {Ӻ鹆GS\vե8\h9?ԟ0 ar(`0"7}PcL@wUK4 ˊz$X΍Ygg 1eW (yMy ~,KOU01ݏv;zOejfOLus+ 1/ 7)"rkڡsb3 )6KĔ2"ky.C.'\vML\1V4d1H컮dZyTZrNj4ҔgR1$Ҁ+&?MYfݬX ڛK=]}ؖز3Kn\Fn@}#_C@!@F0l%ZIGd*J tTR3D(zsZY4Tg gݾ"R*RNx&-v1vƿapRLR",<^D/3SjavKGa;=,{fIG+T=*%Lub} R:/nH*/JV6#D&T/EBMuJOgL픹\cq$=G42zd^/ C`.ELsؾt9+Aƾ ?$R'Pʣ^kݕmԓ V1XGf*xlOIuRBi0R9/=~]*eK|QZv])f(<`2S(J+@(djx~,<]O h@׊c/nBQ~`@̶O BB8C8xVAB$>{^- `3haf^qWa2^ /ñv-qoJ < 6=WS1e,ͮY,~ cguKEflחFIוBj%VnB&ס\D WEbbğ00ju+s^e)]؋t8,kAmC58?hd+:jk˲٩nKR4 hKOUp^O&T }?ȞW05Ozڽ{r# a!AqwF鹢 <12&f013>^oeY](zCƍW_L@>K ?t__kKUs%W V_c-Cy٘SCdj8%4[KchZ$a&pl]ܾHk)cjۂ*e';=6\ ysKOy%`0z׿Up.Dt'1sv3禐/L~.zؤB:rDUFȶVyφy(Bs0QS+8,'Ҹ 9,_L 1M3:rB(r~׌@i[f1pД * >>N˝Naf9it9R0fSBlUyE/2x" |yaD, έNkIs^w^><Ǔ/`8+V@TOky:}IIVF r2ߓӇS FeJtXJNR"is 0Z)\=JC|Kecjc= P2rs tBi[2F+T4u%n-sos)\[&H@ID2o'RB>`H>aOW/+,xyꕅcLŝ @,=e"^Z,4)ɜy( ." F c;R,W ?;?ɟKsuq /,$JBbtKًQw.`SťQDAi0$s&3 1"? tk '.N* hvR _OU.D__d|N,?Z_{+6L4>q6C޶@L(_GNlm ܂ixߩ15=SRh1 _JsVJ/|LogNt%5vLډP:B$`v])@F0ƴ(t2T}^.o&~~K,}\SP}M 2nEi !į]Ӆ%:nL}q=⏾ \ܾr2{/Q,7qS]OWi,`wؙ|@v2à$A+N{YՍR,+Qvvc#6Kں鹚9|O%\O?ayyn|V6 ȲtT}Q x/ @0Y`ƀ"caJ!|=LgWUR1mu6rJ>'s 3/C !d)yf8~ѱM&Tv,sտ/Pёj}&qEO5,Y$YMLd2[1eZ؎&Gc=-b Y6^6ØyI10mN0s܇V%!xipwwۣWL^<8Ź9L'f0}f#a\Y\Yȧ]ǃw1{gΣUojy\McDPtXH܅L 8#(/Y5|ai-1I?zuUg\CEҷVueG'[+R&jO1*(zP>ce&m&,T'ɧy]j't"> NLW*񙳧 hIs#ʗ?/3˹;}w_`S NI\z 83b_Q.ekK똽3{7`⁃D] IDATUm/Ը11q'\Un⸩>h-!?M-O3B~|I):IwЋE˾bdW_τ)p0vXx"seB3=(\Bbc6{ TP wbN'$2JFSN;2zWEHg>1| b^@@>Z&1?7ktCnu7޺Qg82>38)Y8;+C^ݙܿ9X4_0F Kr݃8)XY2W`V#Z_@.Ç?|=3:-^YϹ =ܿ9KX?ɽ[,(IW6aQ.;&D[e-DZ {s.Q5Yrts(h Z @XWLW e*{"_-ܓ.~Ic(;r굞d8]ʏAZ]ܾY'xZOLN@]M *O;GGfEw;MKg8uqՑȾm\myVVV1Lxr^. l!-=V xD7K>B1as:dX}[K-\u~"FP(8PęvkX@uyS.8@J1P`1 B(#`D-pu+(ʣxӿp \;)7U(E#J9ۋ*7aC B$ە*eq]/i ]HML7t_X1 .=Uhz3ծLU\z `m\03*E ]f_O~XJ?Nb`ApV[\Bm` 7!']ew*^y`]۱jbD˽°]!ʂHngPk:Yv!k\9U7tS`˳WV7Q Oj婣&;CPO??@,C jE!(ueJ򎶶alywU|v V%Km6B[T`:.KğL{ kEb&\cXDLȘvYilj@{Q7pH-L5*u>?hi Gy.r|G1P/O:$ʜ;4d 25=h?PϣПة]Bs-ll@r"DW0jwrtaVG 5"PBv $0B)W4r[|xF=϶bnvz BW4uZJgKj!^eT2w6pN:Y\=j6ńՍ[8J%TNa 0Ocx؁\jJLg\3L:T''بN*BZ+(aZ!LIg㦀?,+|½PZ(Qpugl4ڈfÄF L ?҇>cܨ.^GmM7h%{{Ljal')bІTr E"nBck !@R_n4 >5ͼ**WS٪n_,H}#AhŘ-Xޢnzʞ<-ơ&^Y8G`qbyƫ/‡>]C++-%hL B)7@ AP7҇P0P@*1`@'T:BpL3`_uA \1u Q-`SGlwk}M;1\\iEy$MMd_A􍄀t{fb_'ze!Өg=s+K`i1*XԽ^WeOLʭZ'Աnz\;APy" $Y c=pw\ƍs BQ;쇍MY |."h2 P0H(nV<'ʘ[}g0snž"ԇޯVTJՍgV.1),6* Î}P³b9$A7BԿҜ(.W+%B3J7isB#^w nK]]{s)K&&d(|\[zMExhF7*\DQCcSxYJnr|]01 T=*#I0?ĊGߩvbl^{7_} ;X T-wBqP\+[.z%}n&ݐg`lr'ϟ{pΜs@uFۨ727܄ֵdQJČQ@i-Ni%z(ՌпܿEk %d5w`6WWbʆHh`MLh }P6B$wZ`aٌxpY#cW [}=}+cz59a1cϸsCKb ܸvH FDEyB 6bFݪ wx3 rR9z̠%tGg& F%5m^;7AVQL LDA?"vkm|"Ay(`}p(5j#TכX[&ݲ"D:ȂL 8@" ˃Ed1ߎE |t9 ٭{l2T=PIWr7d \N,plV(M\YmO??PZ;]Q 3 VrZg u򎣬[1mw Ҵ):A(QS" V,P}U7ES3pέ>|lGfp!X_pY,*܉,vj\2 Rş/}K}}O.Du֏VJzJAaRh<#i5C,̮ce+8YOau.]SNw{t6[-^v]Smg]T`"rPg܊WbҕT)=Tװ= %TNbUE^;Wo$KVM|;VRq6#yLZFv*ׇY!")7 Rף[T M%+בA, PzX) '"=Hsd8:.I)lo,,,XEڀEVjxm-s>&N 2UX?8yv 'ώj54-4Mw- #0G|= Ev|Mcs%?s Xv{'e R,wQ4kRܜ/qJ%KޏF+%-j2's8FQzm zshkRLYs5|vGHm"Z>3ƴF*~H SQ]€@АPIaj߻n!k`?BDU텟Y? %K8,)AX1FRoSSTb؅'_^,HՁ35O7[}hޭEܻ Q }E}ffF¦00 HWHM(@a:Y"vX^\Ef. R(z=6Ry]≰&w#? .y4o__Dd*:8므XZ L6y̓>* 2̊=xIܬ0Y\Nu ht-=CrPӌV0̘ 招)$bB gY KCQ#+K5\{sH^,0'~D&P,XYc{uy [+Mn<(#{k Rn jZLKAn>|(JDߔCL-0*1=V ﮘ*3'veR+am-qTQ62=s(<%ܿ~MW1zX{'w]/KB| OgA?Rё}z}}jyx3?Z3yX}Qoi^oa}y7ϣzs [-x^@ Й23</ƃ%,z_pSw7ըk:p9dX91 *M^f7nN)ڣKOU0}v;7vyV3B=֣ V@A.a=٥ab %r٢_=E9ǹvr@ș3r9DUsEHh`IXWv]9Ɋ"FNt^N9Qq  @>0:U.ť%p11>.@ ?O[{B ; H16'Rf\_*WσsLZr}yxED''D&&V1w+X_َ:q>犥ևՖp/s8kWz SV*swsΜً_C;^Xϲ? st VNF.klS98y2LZDN@u4MBX#vc/-rtfrC>i?6D< =8 Y䥻H'u- c5/..:gޯ[clpU+_ pqwHEJ%aP_G@C#%`|> 736WjXY\5ǹL:ZYSUR)e˲[{ <~~ԾTaj]XOv(# zf„fP(_D*3B2-2*ͬy>D=uWwzJ}`Mo9U 0W=1z,V ٷN-~Mar)keLpAZY]M(yIHfLl,7lf> alScxã}8DE4Wj +KXIemQ1@E, E~Dm "s T)Г@"b@&4Fk .<[A@eݾsX["R5Bx4p%@) W.b-@ &u$HR1&[1q"vo$}D=op%9=C.牁guu ##Tř,bc¹خ҂F1lÿ}8b Ȃa@b͂]\=t­SxYu&DU z8j́VH"D0`&9xeVE&aCZ_ Qy @Ռ%vv o[|cݚ9;2r3ØƓϊfk+[X[U-Vw*ӎۈY0'pi_'kf53a-(fк3W;,H @RY6[~)eD@q>"򯛀ReEߓ4бHK,SA?@h̩DJ |?@ v)uzaaWqOлW?=qG P@F)DHtMڛ>HLWRĬVX.Z+>-36o)?ZCD|`17E76߀, 0p ,E VpV;˘}6!*29# 2=@M b"] \DԭR ͍&j-D- [vxp?V c!rK"`am@DUFQ<<Q mRNyhPJ)ʕeMC@l SFך8g(VPez65,pX<6ʸm?9$brD'֖uWbr< +(FcL&o7Z5VV^:y.Qhl 1Y"]gx=* We9Z'e*EH{"3u琙I<] LvneN8su $g~v0d]J3T #S1EQ΁%T*]JVXnQAXo9bAXR\'G/m,88"LHaˣK~^;͊k(!J,"nI :o}t4#l>D]1j>5 t@"Ⱦg}BԱ\r= WP.T7C}f h5ZzMM!z`~@lnXW%f)j^gkAm*C]{Fh$[oy @>l*;߹ըNPO##\3FFdt)ZS D-UV  e<`xؖza4å\y.0ѩi͂c|d41릎yHNh jdD)6nJZ Zh׉* \}/ x_QB8\P1M1)eLM9D$gBŰ6_r /ґJ9P/yȕ(<@byFJa٨rfXZb1ȲAZf::uN% 7~_#T.h6;z{8LkEQ$@rKQ{)omC=QX^! ޞu1SKqHa/9Ĵb`H4JXUܗd);a]5pT} h`-DG:В۫yDXnRUh 9;7 JJH}Iq@)Gbc\˕(%Ay nn/a% ά,,~"V x;H/b_ h.Z?'L(ݍ 3Z+Otjiwov?NŹHnQo4tlG`c[zM lmܺuK%nuP,Nf z~5֛ P@܏|yq!{-(ez5";+ܴJ>zӔ)9Th `k/@+Ez5PuKw'c5Ө.r;{ YL9/}ưMU&qǙفG2xu&X۝]j`.ȧ\c!X%܀^BJu!\9EXe+J6LSωMlaZk v@`gp ,VnJ|oc D-@Fi:^*]Nt^2{o]XO#z]\bOH xm4AGd'=HD,}^W.d?7}[9z($ D Ds iD8 p eŭ6uu\^My Ly (1]VCC^qNzT_#6(H \꤇al!0DE" AGC"0!-}7c2?Xg\8Vؖ(0G1y^~筷8Xݖ2ܦ9{MC}ʆ5x<%K %,?7u x>p, I[%7C +Xk0l{INӓBA,}S[cX@]rXI!q'9Z 6*1Wk:*,un P9XR|P,} -\?U_*p[Z ,ɩP9zs DHKu_6\$l/ :|h7[EQJ{>ZahwtٚyV.T\8.B[ȶw݊!` .iAQD4jd ֡<ɳA hq5H9@`lQףM͸ҕwE(^1)]f,6J PF eI[NBj-P06)LԐJ-c)꾽o\7KܞLOAXNÌX*x[.x,[LmkҦ0g[Qqa#%qMeO̬ `i v݆%;`F0rfoݵG.Sa "@S\7,NrĀ@q{98줢6cc+w'qlj  VuBM6#84 X`%AH'ь,?!~@DDZ :7 v%n{KY]ۓM,mb+c R8u}|q]\L)Z ĬJb]10{>7^. )#%/(GL& N4g2.KB Ȋ5U6Qkz\@L~0.%ib5/ &Y(_R?;No^_<9eOGs4iE-|pX =v{iMb,q\YBzvBΓ/Ҝ~+^:TRn7p  \`N/tr22s9|9.`/z9 nc,&jhhPk->ZMt'gufבq&Lvi97,Qb}gSKUwE$d,8EG,0͠q3*," VFX 0WRFk;rk{ dhAl;C>rF@GFA9S8$Vikh[88.a,wa"0&+j]'B͕5qbyeY0Z,́0 uC)j.lHTvˁdK2X10 mnm"3 R O8g؏|_jYմ0uD*ʑsS٨"^D٬h )zYhXucD6+H9e QdX,Uri90?0b̒[ IDAT`r_{vʼn[OGq_KW5tn*pgJ_=s}{;,4ֶ)w̓Eȕіՙy;<&!T41 a 6M{znZnv#mj@Bb$[1 !TíYUusNf~?"vĎ<*3Nޱ gyfl޼g9vDƗ6 6J#bMIGڰJr4Dy*r59QZ;e 6ZRJi$ߪ{<"w4b:bfMYW +0TZAgwSE#/Y,biYb6Ζ%wr*0}Fa?N)ݴ@\.pnHT ˧ZxzG0M`@)&f*٢lVL^M =ƛ)i[ʧ‚gܷ6u-6 㧤N/͑U(/pKxc8g:8+1}>}vd%0X#EO -,8<_A*"UcQw%&Oԓ>]s=yͷkP+JN|L? 5o 9m tX\͢UFkQ.*LKVk|,D|WZaόSkjωF* U_j#^YqmG=D*p XQц MNL`vn?KE2֢@; KȳoSb6"t2(YJB0p1lZxv:CUetB`LaǞ+QbM֯>ɌY"(&.X( ,A _G2&./z՛wKwl4Jު^b ,!=.nU N< D7W| h3Fi4^y+m {RYFWea;vV:ݽ` ̔GI* nbX* L`O !o < ^~8)չ*]CIB  AQ@)v>n%/1 USa5N0s ` 'ot˱P2C:ų\l.-$ j<-f`v$/h ʍXkn\Z˘,!J~ꇞa!%׆yO`|3R\ \qe-Foz+~X-Zd[:xV +a8VVua>٧Ɛ !1u* Z'lU&>am}_v8ǁex' Kab|P ss!_<@ ~ ccczd* $nAfϜJ}ϟ9}=ᕘ430*GZ L9/bzyUCϝL 6'-fɁT&gF>W/Y<)/z5rr??9p53;_ rG n 7邖by,e{0] YdY8yE?$px̂_X Q,dzT>9GO4+ ,OSPM6@\*Iet-.8Ad4Q5폏O Me:5_?+gYӑJUq:s;clZMr8bJ^\ADeZ^"ɣƠwɩ}UR(:tv pQt׈?"F؞@;W^#p<_E3P)1(aPWR"1{oVa`fKRU쇵B`l|Lй`fB(a"p;M4‘fH}|b#Fż$  6gX b¿O= eyadfvt:G_ 2rr˪hU{%@#ktp0a2zYNJ?ӆ uEDvm":f!o9ZvwO3ޯ3XĚk$V#qGGic:Cwx!mQw '@BE`yvZg -mڝ[-y y!2ּvcJ%B׳YMB۷?|b_j&ӧtYο= lNDZm|j/ & *KQXtƜ({*- *f|hK\E_Vo ~+w޹Yy&hp>lfpN@‘}a׎ablDYvm9h6P yaDGfD U#ey%ĹjcJ+Vi(β\kR6Y((cBtvKXʂ0OYaRɔRvbUQ J9sc[5=|9 B|o?ݯ1YIꭢH\c+j&p# i$l! 2&D?wh'Ů y?*s|4Mmehr-[mDS?ط |vnι")lTӢ#ӓ1!`k*d\%LV/UY.l{6+v]n#n7^o~0/-hhUѺ݇K0-]&WQF4{u  s!dM;9w(at ~Ѥ}"/2t~Tw1m!\gA;&054&+e㇃ ^e:pN` <בR,T45]4Gr<>KƳh-T2m}ۛn _Z7QT"LTM꺏ڱt<O!\} \J݀/֬@Z6K#Fy<,tLY+)d-wS?bSTFyp@VYDB|^!e0 jKIu:2Xl^eUye # 7uJRU"$+RD,xLgY\ G(CehcܤƛF ,sgXfgp[!IxGi3LeڍBV&F Ei5 2Ȫ@,Bg`5=J\z SMC3;8lGUq^Xe kM9H+ՑK VI=_bĸau>I`iJp )lXKi<p:v )dq!܃VtdY+U3#kOtIp_5L-%uSa5Oh}0Q#" ( iX\3Y{=~ȼ-=lP~"ޡ @KASaG V"`(Y l0 1 @1409q0" BC#*p\hw vs,½7{%9"_#?݈4@5+0*jYŧ^WMsU| N*,d(,sAW x_B~cCl~?j ijDY 9ްC{|bV~[,rv*GH@<2+!DZTB+ϑ0 ȇ>,d utfBTEbAYW&49[?i<2LRGqVpe\l4 mjs?6IdXc9bQ#0Y5hYQQi Oz]~ Ƽ2gr߹y#+0>j"UPU,!0D:7Zn*zBuD3kO~E(,US4 s0)-e&T b YiP0$\o -}€uYPߘ^UBajj ;vgN:ccse/u8@|C_~1ѪZa@<93c݈Y}~|-<_͍߉{>m"9iYaa΀)0ut2hci ̇鈔,_g}i`%jZ|6c9fg1M\R/b077 ܼS7+s9(z[WmZE̠e):Š7)<83 PEp: l4t9uI#{5LMK~>_8~̤VCaPlPUz y+*cS$;ƦMqs iw@ Yg2l=Xxn4GT;D1c2V2=k7'9-1 Ojw2|։5wC80Ygk 06Cf, 4Hm@:'`5˪҂X#Kp%DVv5$!6HSam]f/{V4OMLR0 r(],/gJ1n3&&kW7a\r6C}?0qR<` fvD!-[ây˙ݒEn>w 1)+H>_ka=h?4ԒC%Mfǭ @Kƛ8ۛ/Ƹ0YYɋCFXtk~αV/N#9OQ]jI?$ɉ$f@Mͽsa(CDoK``zeYC#\ixCS8\kWǮKfI]BnkncaqG>xAWH^A0[I+i,oF ,'I\W÷^neS.qE8&,SxI oW?%' i+x[RKoDHi5[c$+$\FuY5t`u c ` eCuK6܅ JS( E(Qe`Px}ޘE)!imߖ< t͐fX* Aw(HTF39P].F4,c?`J@4ʑ\$Q V2$9=j]AbjVWt;&#yd&s`*&G *lHM7 &N`ll@ynR3aHе1a!~`$[j9WM)ZoJ# k%V8Ǧ6TBYṙ!CQVVS[+6Q2\ HAV-85L:13N0[!6LݛrFo助ŀU%J)Z-t:dyܔQ,1 :WStyХUz((e`¶tjF Q.Fdՠ͝FeTK-r I͸T6\y R^L{ o\&YmUހ@UUTՋRI=/ൄb3">2NO2@k(FL+vp Sׇf/K,Vh1hi`@ DT!-'9SM|GS-~BΠJNDf5MW!M2K76Ƨ?'JS!%r7`0@jA)tEw 5 IDATy'Fo2Z)cVסF,y(FPY5 p +5\IM an(vn)0610 ,_2p^ *M`تRe-(`@2OĂW]w-?|@dvk AǶY""tƜǚ g{Ox1y{{Ⱦe|d:'Q$Uz %&״QAe 5vfϞ(բp Y  wSp=W^|aHb7c(XZUiCh _7| hY?|s{U聖ê0WW^-̠E` %H'|k-HUP@#rYHɇ?_\!fku7g]՞^ulqY}5p!ov;@oL]Zc|l,JB OCdC <"pYU˔vs̍H5?ɦvL> MFɓf1 W|IqEsd`E/a.[{6H{$~Jp uJG^Q&CZNOb"ͺ#{X<ŌMQ RZ UrXh_Ÿ}\]ǟxm_ncpۆI!?'̈́h5`|U`={_"\r% tϳ R= Z:?>Ԑ|IpϻeU94ϣG2L捏TóˮJ5OWMdfv^ya'0xr~w IB%=ّfhvݰ{<. zHHj;}]3謀g;r>FƀJ(- V k3'I"Vd9g*+EY>B/l^+%xsz||)^?[,^9C-ʹVtQߌ'V/7YT8v89k-EY( eɠ43)^?Ry^NB"1lV kLf7[?pj(.^%U əցsϪh&RZ)lx j$'4i,\?4IԌ<`u&o>HθoPZLַcCݛc`9#Wp~iZ*If\9cЂR 2_RرcG2vU„y:b3C[)N}YG2t?=wlZy V vwpN@b@/0rK%q$BVp4]HyCl} 'Sƭ[fxQ4^){(TUrGF0˓AHct8l6Js.gB_j%7nu'aan%t SJ+ Z9,e;T0ȊHGEˣ - Sy7G!_q Y3}B$.p~x[*+U W?ˋnOXoO~yâ:>jD5p-D7SJo/$"PxB;0tQ6,sG02XʙR W8mƺAu6͇bGCxMÝ|s$L̃ͲJ`d ~=?nh]qibPu?u;_ X9Mn!\I4^w;0Ug<7uɓb /O4W{dY pDd5־:SPJ-{cWP9``6`p ۊەƁg\(rt[OpAMMߑDYUHT+ ]]'ny`45ØY=$CjdW)S ؾ >qiq2!7c$6v@CV5Qg#3!@4(`7e;W {xL0F+*c0F>~R`;!E>SD$236Je}םA_$ #*铀[~D 9yvbn-C,z׹W=Ul |`xiS ߛGwbv~#5J?[K. 95L͙?&#7#@+[wRps'+U[Tw#]S0^| @7>ww+G[)g:gɜlK5 (aBʠG8oǁj]vgSV[NFf/a|f=G_;'}9\%;vd .\$U=;}cUW &:~cl8:̄bS ʈ "rt9?ZRmEKcAK=LY赋Ͻ㘘@ W˯*p~/4ϝ9C6նp1>H|odʔ灔ErUw("m?3:s~,n|P}~Vͅ [bqp"k|9 ׂsTtR!Πϯ3W<ёtg>vB=eޞVs,nŶr*ǩl+]89 7wO?WصV7njSVXAO 3G+l{t}|EVʏJvȎCiؖrE|N,}O`W/:d5 *$`GΪKHVX\1+Vi !Z8' }&XZmZu&i3~쒍xӕƺc>Ҋ["ϔ¿_?b%kER$gRj&A kP*|HSP!UJ0=JВE<ʼn[Zg:/)Eऔ ~׹5* .UvUGp(!D,ρщD̵_gqO4Nz#I)aGyHzVT~)Nf[05?H)LW_{}aouqΞuȹih)FY_r-w}|Ӕ؁NгSbQd-(iSDt|w)`} "df$_;ox-> ?Q(9~Wcb$` fnBi#[Z1ZqhdS]*GN%h1n\.V >L`S7K~ DY8},ffy"9a dż8Olag S̺Hƪeɔ(`6yjwNgo>$Dj2!(GmS6'XY|5ScZkrd2%0$=fs[q)\;Wl3y5[W Wן6PyMۯ(ef1?3JBvj?==9/=,%ٱW {4*4VJ:aبBy.Z++/%Te@ s`lb%}$+$O J'x4l}IC5a#¤B%dUk:[wXk",ۏ~UnZJq~,K8ڈ,  F$2?n4t-|{ݐ{*IY7_Z=|pS",`RO[64*L X|)k`L1|$o(-JSs{yl6'Т95 ~cvG~mK@j|PO) ⷟S(a `3RX s~KQ`Ln{yI8+Jo"0V\0>qoJIϪK8W^'/\a _5ʪC)`ba]BlW=}Et:Ёpw-BӓhOB6Ͻ?` *RHP7ʿ IĬD aTCTP;u"\"+LɔnD$#eYt u=Jd㎳iF'Ecz ЯkWlsytvǐ9EY[YB0{_w?NsbcWyqZy5#N&Yq |mLj\@߻:oQU 6hFD7ӴR +;z!CU` W6{&w>+:BaƆ'Ǟx~1\ UR|TҨfꀀ+5k ;⒋šk1=7+2'1a0A='OR< =@.u&K'NrS3–MEM ǔN57.UXqx%=^ Ϩ AoAyZsd/cJH ʌWk <~3kĖu;xeCBA`nN1l6{ ?5aP{~U<iɓV˶c*߉yI]V>G 9'coItnnqq>|^z)ϞY{p&0Uu*+R255A @J x2Ar#r'uQ UU$Β;^-,43| Kxp!U -" +4n>Ѽ%<9}gzZ80agqZotw)W*>8L D_cJέg]|gSH|6ـޙRJŃde$5 d5LR&m>}^Gqn7-k|o=YWX}d}'c`6Sglk-(2(ml>w7yP|fd;ß@XoN7hn1q玁:Νp!`hjNZk7oRhz'Kp0 'XJ 4 QUV^bYYƬĚAX*˓{ N2Re%T%az+:f_?(mE"Z.%+M,2P`__dSw9|d<& KՊ=w~*I!J5ƃL7PڱX #lvOXM+oaVVl1ǰTkYhu{(9%k^rMǸ2tsvƟ X\Zٗ4yPVMJA£."YAVSR|QPdad<ԓx+D>V Ȯs_J*) \_{^bh6dώbW>A-^P7$1Zec`<^*JtG?_ [rTq;I!x[o-86j2kR (- sؖTJMƇ:Tpr,~Z1(əc-_XE1-`Zp^ ^Ndh&&LabcJXQNg63X5+S3ȴR,(ι+G`+ːʲĉ~FI%:V6Jc5,gWdٱޗ) HqY J-R@Г`uHUUhƀ+/E1@@֠,,Gߍ) q;6,SѾ4oz\;mM'c4)L0<6`2XD|/rHۘ&`|ޯqRn -7H9~cnىvvw#iUi"\X(cc7HV 5\gBEi '@F2nt=|S47YY^?Ov``7q4,.uF/D3<pz}+F p#h)9wTeJzJ'wݩ8c|ob1 ش|sK>˚K+Db,,44Y,c9g&u6E@;w ,E>D( w!s=Dx:[3,lqf@Cg>|Z\}=[9s75 T@V|ɩV8,K@4 tlT%ʗ J`"iݟk^t߃ ,0r뱉1DggTeyBjtJՀtOAW 7?4(y R[c#CʑYǾ`]Ģ* o|Ue_^AhTrҢl3SXg \{YIp~*lpR h ͍rffG\y!7+-[ct:aтUC[13B]Z56uK.Z-i1j#,C0>6nNN?Lh~WєH-t47x$e*щH d9,]l <|'UfR)}\M>}֊c.Cn93N}x0@bYK=ܠ>9jf_Q#JsF2\V)(hV84K1s2Y?wH}B5`E`OCAt;SCCi0c xDFkhc`{ic{M~G2a4xM_? 5<``kNh2|4%7^0Zں95YfƛȳXm7ď Y@1[0}ʈ!Oz=7@[7nı'P%fo,0fdsN s `F #-϶5o 7Ғ VY(≽ˡ&a_<54"_٠˸&l)gq=yNhbFRUP8{5G6m߉SGkbH#,$H74TM}qI!~ Gkb-uqBeWQTzSbfAi \d|N0L޷č7ؘO- \48DWZǵa,b5+Xa^q_#S2A(moq+o7^}Iu/RI:`߬K/?0[jfn6ǜ9iCω '54 #S11@V` }o㗒ӟ'^Qf^D#`OGrgwLK(gBP7Lk ,YH ܊0*K=?bdϛG F}M4ɉ@ 7=EYcR0/w\h5 "`q4N7GW3lA5]BUK0~M<; fX&/== i(, p•"7jܘkI)U+R"BYZ+j k5)Q %w\ܭ%R Ng\W[ -T`:)^)5LH;9@\!+N71`30rT=%ϰU ;ȍ`\yiiS ,_BB+T92uLB@d\~ H7,G.G(fX> ߓ,ydcMfBf%-S5NZ7cNr;}7#K{Y6!vY:Fq-lbB2?x^u]M Y̝~sgNcjl?My,Q ePY"U5Vl$ n([[ =_8:k.:&ۄb"s4]IϽ6?1ѩ( }u78@Yn١xk +|vP/{էpz-m8&}hJxXf> #|Y/0??y,,,H tߨA~t <~- nӻNe]אU.HdAS9fAí/}ʈ .$#eɪf@@j0M;vN> YZu]U#µ\{,.$e"El+&C-r<}| P*d?4o$u>A5&k1a% Μ ʡ6MA|$ՙ+n<;.gZhcP%< ҄Qω<3' +  kncoV-o~3g2Ry0S,bV UӠdsmN[ut!Z!nI7clM4tܖ+GZt2i@c6 #y.:FI՛A+YCP;.fRTN;S@j͟9G5۶QܐcB\> iHp,UW!نU(}T w2T8G#԰.x*W pe5[<2PuGmФmQ% ]$4%m)5oP.LC5~a4? B 6mYnJčhp(iSS` fB+&6Lf eb9T2شaN>\$<$ :Тw1mo9Vx{] 8mkس2ݺBg`ZCAq&vFdЙk}K2,\l{ҙZ,^j ]ba*;wtt IMsh <,ԑڶe_É rµZxgT9b+=UZC#&u 3M mbf$eբ~QY;R KWGEm;wτR/! g`|fȞ|@;if|coRK<|OW9&g2mgV A4?D y-aTZh:}`{+_Ǻ`S^b.D#ryeqD4Nr:}W||׿\nƚڡDZʈÑ_@ԅ9̸V/x B|m~Oڅ ~yM#)*up}S1|u>*|ytR&?_<22>=EP_U̠^^utb ?R}|oO(U,\]N;084fWX$Qs Z*8Ez+?}g_;\=Q) ,w6BK ʛ-09ЁQ4 xt£]A"kk[7Ll}xDg8hN}08GL1&GPUY.>#f!*:6RIwC%`czbzbpFxc׾ nGi<^; {!C,@^LP#u᰸Nr5a_ +,-\P#8`bH>a7)W0%_7``/8]|'Zj@VXc pGA!跗rPIFkeU}+_ J~e,..rF܋kY$Gf{;Rτ 9,\hrfkʏ /'ovRQb3JWBt%8UXP\yFË1Sw@^RX@Dr ťx؜o}79.7KɋkVY:$.{4n␸FeG6—" 9W#0JͳefqW1grik\˱b{ 3L-O xZ?yjIkAŀz s.c%?s@f֓<5Ow}k^or$4Uԡ:ܱfiCW`YUkUt66S,~ 56rgW:V\xВ#r@m)c-2uEBQ@ SOH@݁3< /U,` =KNq~ 1#ӣV$@cuq(q'<1p\k W"xu]0iE߮'1hAޒ 'q*}/;|ﮪ_gy?vAוVQlѿ15n ?]wgKOWY>>¸sYz >wayҾ0P1y )]-n! >ƌ% ,qLhqttMkuS>j 2ؿ<Ï-FraVtthG]3=o#j+fpm-Ñt N03 XY}Qh/-(,ٳa< IDATRr RonVw/pTϤR_bKE1<=xZpǜ8\?gq#I<Ə!~OF/vY1p/`-k' \GpY,KOծ'#H[]Z+ wj€29@w} 5ua%3#ڤk !xSId9̋ĕ\!θKVb0'";Wqwx[lc8bs˸ݽ ^䇱/=qϓwT7ƀ][k§egRw}MO|0$<7}k9JDZI,d`N {ww;~({=8yn5 n{5.ۖoUn^9$4di:*n/[4ѷƝ2MZ0cyԛffO*kK[` 'E'RzTaYh=qmx_2rqO eK -xgcúӇyTtaҏ3ssXYZ-kj= aȟׅ^|{.QON@;~Jw3Jbʓx2ɳqڹo; 6XI\/Ã>Q#7~Tu\hN qe|FPl_BA',w8IQu:ygp;K ܫO CԈ3^Br7Ź0&O^gkW)Rhyr zU~[ƽ܊M{{#,aUz.زܬ*.*,:X߸>ꎮ<=[`uE'"6'uE騻@Kd7IUNb7̸VrngY;}>E/@%dUyXBv'1x $0ƥ2m>֣O{` E-0W_.E\Gp/:x:RQ3?F IJ(WWUPYSEiܛ>ڦ{xfGΐ.c8ƕZcRV?fge4yV .[e<;hGdi{GvO#Yl}'ODmJn)[ Df0JSQRR(G`yM{}kf找c%"ŭbEV@*)"#o E?+(7O B.Oh ە=EZEZEQ@$fk롏x&>oB* y;eS;| RO.M|G ,εg^7.|P{6`ԅۈO|T:lMs3ψI\+bxw^d5*N-ʆN)ܓjKpw t:骖'LOL-#˸^]^-G>VDRWfJ}ƽDϼvY(FXDr<$Xpz~C;ϵ/Pz7wk%k}^Vx-#P!YV|g!!-{r`tPϲZAM)}f ZK"K\& CkBݨ TI&)J.ǝM:. ҂L\˾.w[T7>&w2 (W\XR}ε"0"? }3sBʽr@[z],L2D\lqG< x pc*d!?URVk^d9I]?8C~<NV™xUtq"oӇ0ÂÃx:V֪`B"BT_oE?chH)qM'ݫT S'w9\ f٥dGo{qy0'?sʡB ܯ02Sж}eVr tz@&vHф-n4_3h4!< lL~o[0B/t[r#c\҂IW,eH$W*.qLwTk^tYG\ٜ,9Y?z1pϳ7ד_:O,Bls ~_Ӻi]A{xqÌRnV?/DNs˜JA- of+Ysa|a<i<>[^f5]^8 z0ῂ2B+ː.2fx!s\tH *&C /xza`8񶂘҂jQZijO@:[~m8UZqo'~c}q,C$p]@}v$z<!BY6YhzQ#],um*`mU5~IhjO)Bnc68Dc/TTG:1”W@@>TڽŒg4E \Y97)45iB\Ndz".zϼ ~ҏ~ űg>g3\jpv~es(q41 `U9iÜs Yxv SqmyX]M| Y_{}~xc?B ^)*aR?T^` -0w0nB6p1ENEvM`yd{54c/*@l]\5k>8N. $s{+&~?oCYmbd ˝Q p@iq]##@e!wRw'Q8 )?f\Xtxq\ysȲ '>(,R1^^w˸{;YrhaOwF_,fQQm<Zg4e9^׈, d?L V;X"Fhmfj7mZEiHfPńV-3W%i*Oa8BBf`t;QyR&$h+ScVO1@\uyB0 s,Pb+8ȸ/YhD;~di&K/ËǟFiA/ ?>QX\}0sԴ2qsBNaD5W0;;̌q :Hc@uYuAwnR'%\EصWzE&Jk[+-Ҷ(Η"ؗ@Ub;2{ߕT9˟L\88й}+JbN1e-,Luۜhw;V<zUq~jwݫn 3EQ(E8?7RNqDvjRJ:!_m,qq M3d\Vy5UC,խOr/ &6g,߱_t}'nBIbq5R2+d,b>"G0f3B 'ox}/#Woa{3E[ZV+ׇ oy.,7S}wslqeRo{l]}\LM6Y^qUhO-:,CTVHaeyӛ(~]p+EkIϥ>TBqb ,[h%Fha%~Q(Jw5ݐp^lSh]S7&X siѽԾ1$`;C,I - }ħUyMAE}n铭H\#n$QPy% oMiq]A ,sÕ>gl=r@q+ a^*,'+v'J\͛w2'6q##fEW+MdYf&1~;XmUVC-mvВ#Yҙ?Љo0X5|&vCr/}{aA{]HdWN3v8@p( "Rvٿ^hzFf󘛛 Z0/oÕ/||oҐZv-@yAr3rmð.zmw* Ipq#Idi vKrDv6dGo?Z;ʅv3ċ#3q,p=5'߻b|;|Tp #Qe?]INRSIFZCa;_BVvp8}sCZ4u !C8vjX1aiA]G,"t:ga&ebX1hQs3q ߧ}oyKa{%0^N͟{oiһU^KpGN$I0㺸qq.HQi8hhehLaHP"Ӯ,S1N#v95}&F#;rTU5/A&Dh_.&,i l%9{F&~'n+[J94 TUT*T*~^Jx/DYeD=/|~-?nK7wvNn<.TU*ԏ*d58aToO7ﭬrGr{rSj"q5LR .:T͝ eҾPv"}]Cihpk_{D項.8||nXmr0 3A5r )' ! 0 q֔kJ*4gUoQbWʱӛf\>¤W+{wÃ6Xr!NyߍHs= q$1lZpe1$-`k\Ic"Veh!AIO$Ir -LJ≺;~;H\Y!B9 .98Uk IYH]~"K+<{Cm%ܻ)) W)ܮCBZXq2\(;zfALj,{_J:֡,"i4~GH$oMD(#T͝w-Diסm';ey=L].3_"=FoY.n?Wac 9R 't߽Oν?ʣSZ';wkCz!t?  GкR^ 1.,&KG{5S%z 7L` +F2f(ʚWrM΁;gאŪhmp&4# cQ=P 2g|ٻo߼܇PPYzd丄*ʿ:# f"V< F{Ĺv<,8N_A`(ۥzGP^* 15~0ӳ, 8Ρ I׽` K(m.v &GkیkbG5A袳A./kNvlw,X]]] IDATe,0l`x/yT2{.`"zQ9,^0Xt_B`Eo~yrY[\٣ "/i+_x Ϡ=k~'tpbqVؾAijT~,Mw .#L%Sb14(] rBwqWy'o B[goW=3I^7e9j97|1#VcoNo@|333VVpܹ{Vyߕ !Bk/g,GZ.<5gL5O !,c|.$yo9iW;xQ.r>annzZ an>O/x Zm%<u]~ݿ0ZF--2z}8+`",g՟(E'ab9XĭD,j;IŲK>qy, *eU͋;rC袛1a%Kme%3ɗp }6|"Ż}hZjF8T&| ^BM2-za@|^O/G[0jcvׯ^n);gE9q I$6,b#JE ݶs#U4p -Uʠa c*,c@a/\1ůJgN"k$a@|Ǐ.cA%VAUfʣJ{9LlW{z%Ĩ,>Fs*}+3YkWQYzH+˻@0VY:[$o!rx s8 r^Žo~C哟$oa vg/]ƽBX<}>)m^Z`i""#v?tӆnۢ809KWs'guEXXT"^n) tMubUڭO}Sxgg\(!m>k2qwh=DV(*ʃ:}x& ,]\u;ATf"š }W EBuvwQGdO1&vqE-v^FXsoK,-<3tܬZ)qٕhdAaEĤp82(0elhٲ)74.O-ΝC#WϺʝ7@㏎dY;)w6OBྛwCjH(DH#%Jt'.~2[ g s*^|r(^Co'w= FDr.3nJhRd-֕Fm"&YH%D ,`yYRнb-O;SMEUwè5gyQ(kcz98EѶ s"ƇR"n NTjA􅙚z"ҏŤ~FM$IvfL2yP1:qR܃YTKjMv$)*R#ϓ-rL >zi)ᦠ)cuN4F< %( L &R?kX $ BF; ٟug{E(RNnt0QJgo`S¡'kP)a+o.^{e'k.v-9B;0l)n,M!8͛71777eM2ʿĸ1QJD# h!1EB5XaId-吇u->J>HdqlN\,]МyYkc.c#[FQvh4(<]<EEFqcd)" )h!3C-I "q\jae?nNC~KdEbfМs0Nd1Z AYN*@+'RNriЉpG=E7K .=~\mk4Mqa# G;XG~Ws&1bir]2N#ˑ +ky1y%ƕS! RQb) a :0KpϱrA-xlk(2dٓ#"|J!]pnrFb}"!b7F*\J8lDX@% +Dw Sʡ'/`(YYiڿn8q8.Yv>|#cxbza.黟Ǿp?`Y= .Gs3ys~BCqeU"C'Nb)8 418C'Nb P:H_IÅnd' z^sO? 8~]2Bϒq-7d qe$T͝ Ol3Ga%!<>嶁G$Iz\ 9\5q]LslllgŒAŸ! @Iĸ2y$wG/εj.;A얹#Gt 26oZTvB-t02| ױ;G*X10 *<>?)=;g>ov:AjpPW&N`QLRKڝ. :݁?rKW.P>t~(ŘiB=1GiM,`.ʕK9rf<}FvY) bKe2}*Ü瑶g(ɝW&N`تAL%j#]V Ѵk\t9fDc=|/Wd鑅D~S7և^cgĥG„2!35}/CjqBo?n[<ucN;^_bPb\D%r(G2gO*Uq*JRd-f'KK.S .km+ͱ3w®%`%|ܱr.k>]1}ыdrBlb? W&2[ӌI&apu } b hVhw:r' B]]YFZAԍvQۛ Q%I"Ȭ7˝-#«0cO\p8n>`űlP{~+B jc >iôX"Kc4HQ!"T*Agr̝nAX'O4Ƕq4}K+VpWݍx&d^(}o^c"%vDr(m6`y_Id9*ϥA$URA-2Ϝ7RDU߰5鏲|cqjqpWݍO*_O,F%ԃ|LJ8 ߛ$a%r[h9KRdɜ#G%8E8稄t۫#ڊ"&۷vͬ'f=EO>Xcb9X`rT ``GLcK o~f ԡB8TBl,bS]WY7Q,:}eX 2 &]'X\.^bLhVz4ڀA"d!wKdA&둊R /L\pzdb1ġ7}<EEFGs@Qf"V;9zet""zGIAlG "+U{QTQ; \ݩ-i,Q%*0z{ɽs&R`ӓysE:Z9Kۙ' LȂow :{[p-&LAW >Z+t=+L<'$4%qE @!4bCf뿥G{,#*=a=Hz-oo0@"F<]5Lѫx&G5%qE U7<6{+cywŪ{|Z'ɒ9X*y =j^ uXebbk*iS=b'fš?nwogE4AňadIk/UUAd/,@0(D8:\U,q7 |\(r>aA0 )<{n^b[r|UDQ 9f![ U}#"\xqX %wpNo%`ȟ>J\1t= OW,%&L{ *3iY^]ݝjxNv*356@L/ bq]@N>0+˸<V<8YGE.mS!J`h0UNG\4+ބZgp{?fc\rv~@OuK,JEOأRĶ$.. ,s0J8JI\Cp_z-!2&bCS@;k1^81 'pT 0/նC%EeOս'=uK5'U%> /<#T3W#v"`Тl$˼ k_],ː),CG9i4H\@d}Liu=(Q(aՃR\"vFr1Rhj%Qpt7dWabXvU:h#jLb5'AaU8" 0KʞpZ͗rNJ ľ5=O /tGGp4CC9Qp$T0K& T_>\YI\ U17.> լevӞ@frd$Ibjq=qw)0KZ+‐Z##2ekb ك0㦖(G2Ӄ  :@D[SH*X<'Mvru~sEXt.Y)j:Gƀ/ .]v&5AN88LTjw!zbjuA BUw$(]dm* XsȲLIcD51T]/RΕZBā1~xC!ͩ|1]*sPx3٧v9F`‚k$1"3" c*2.VJrL|YzCՁeVgȻJ~X[I\cG&l:NY!SGb^՚ZBU<պƀL/t]VhFԭF$endrdÄVy b ?҄# X㼕IF !KA9TI+@$ƸsF~4RWE($-s+1+Jː"K38qsu)nFז1`B%ch+r.Gtb 1ai}5`p]ٻ+O1NP"A"N80 Mq؞ g%qE͆j_H_Tv6Ռ8L\ ,woVʊXI ƙN&PE V~BI9՚s:rƅOr]NBALL`Kj?C}Neސqb*nnF XY"D@AF3c@t3B`R ݛ3suA(s7DάSz 5j͙ժ0`A4!: i;aL҉(h)q`eAĨu 9ZL`ܫd*V侻mBɹI\AOV $ƘXrrnvu)A1zZ!!3֌1S!҄jaLA{4}՚޴W^bLv՜ Qo`H\A5\Ž9S>!I`jVɮb)R X^ꐸ"LkJCB{5LJUaÄv:蒸"%L՚ WH\MS#x&"lTPo7:vH\A{Gk&9H j3 L-f+h00ܼA V3mI Lդ0=KU6j4Y{+ }! e{(slHGdG`%];jUYA49XaC&k,.wymQ *t~IVh ovN b$w}Y]1L! 1;Wps5WAlYʱJ-q&qihBXA3 u %O$S`iB˃9>IDAT  0 !Yul$TaB*\+ Ť'+[1`&%O*S%*КwKI\A4d:X3U Ȥ`ct; չ"8[gժȽdJ`]zʂ-YP42lvS*FqH&0}v @"&Xp*juJCCys..A1JpN'ZS&XiʱaUu+}Tk>juÔ% u;[D&8(*jFz# jJ:Ufc]U7ARPoyCa~4vŔEGx*jnjjvL(S ,8GVW"8C Qz| ?Dc&wT I,Pk5|@@t@k:KbF#@wR ctt" ,{tCXCGpa5j>5nVT5)bc"V}fwdtd2L$vkVe|ꡪCpHqb!;AĦLRBa?ݫ}^VCkt: JwP7003WN- `-,ؠiֈ\ݭZGn@XWb- Ir|4ՠɽFH`1S|՚/[%|ʢ 8lh#t"g`ov'"IlX4hDh[~ Po*w+@tDYALa(/K|k̈́+>$Ík^M+$nzqaCXUR};zLh&!Dxh$X$X^ fz=@Z!Z2H`Md3T qOr?|c|߁?&۫2Q~\ ƑC` A2b43x&t.VXМ PIwVQ$Ͱc}-&w `\CfZ_! 5hw ؀24!ꪍO[֔j#@q$ţҽvu}W8 x&5Š֌V<4ZG@M`u9"+ C5>:|EM a 5Dהxr\raCX0PE lUr?x8X~bP+^9$ ,wjuپ VǛvSl'X]E GVov(ו(@kJXOuZGkZGR0 lX]##w Qm΄{E E 3VnVkV pNՕ.6t;n1:|5.#mzeR+H`=hw VjSz,X[*s vơ**5IazgW8"6%C@Vf+2U0;'@X[^qJa\J4.ÑcMW/Sh ,b[W#W#\FZ=lz#@ȱ8Z_~\Al͸=|0B=1XĎvRt;)ou[s|s󹻵[A+yYʥ^C Y&ȓlFPpv\]Ley `<=9.sPm")$=A[u9)b 500%"t AL1=D87_E WĖ",X]b[JlU>Z3!Z3!B`J[1m$#'``r߫B$[NjThh͆T}T>אekt"I' %)^Ǜp]k1,5$}%n.upS Y9"\̄ q: ,/u)A pqp 'ɽ"qX_/.sԛ5՚Cj'Xz;F̐AsPCGO4,ߠ;bxH`8 nYb+\fCf+`:\lu6*A#1ɽ5[Ak@{El XذގޖR`Ulhrw cuY&կ.ws LñM0\FyĶ E%qu\*Tf+r4lu0PB^䴽ae8:8wA9h֡#uFb51,$`u+ݪǁj7jG pdqa-G Aq]O6Pb;3H`Gg#wW 4|X!n%"rb9HIǔZY#H`Mq,wr5;_A l>qaE9atB%[O7;f.] $B[״ 07_E%ݭ#u,Vnv*E{OS-OXԒe+7X[s U4Tͭ f+FjՕ.V"IeajGp~1Ɛ"v:3WAk64՚GRvՕK]*rJM0/"v ,Cq,] @5S\AJwkSgzv*rJ;WWYԙY8SH`Xۻ4@fɀC:#jWeojӻ\TEGEEWvƘI|ővڕx~ؾy9S6YVy݊[80n$Ln-VZ٧>"W_MkQ ɚ4(%rM3*%JinY1bZ!4MUZAGȧL{m3^-je"D>S{!0 X^"pzlQjAiHgs_˧ۧ}_D&wFM M2iZ&uIg]ZZZ5Уr8Kᾖg͇ASk)`ܢzմU y1"<͝83ZղOk؆Gw=gO2Fj+P3~S8nL,nO$RL%jݒ{`KzP{5-\TSԫo^][;~=ΨW.-YLrڍ jg<+P [ebE:kLQ6wڵj@֥ݒ`Yv 9`q'So^(`̜EJe\SɔC2mn ~g@ѥ^S%fgW7>n%2Le^ -Lē6ɴ;"36z4]@7 Oop# Gi_|$V84ASDrѧ\YH$R"6$~OѥRɩ̸r_ -(`̱VG^͠pahaU)4=[2sF`6 J@MKdAJB[V-}:rar{jv)`,fGs8> XDDq`Z ;zrMZw_ X"@;a 3n|fݜX- #x }WrD'nto8,%lyJqa^w@ޣ\iu@ܞY""arGD9}>Jhx"tHf̓ٵٵv˄-/n?L -Ӭw3"MKDTr/ ]KXup-aZvKfeXwZKc;Ok7x,NNニv+O٭[ղOjnu˃ bCGOR+y´[DWIe\RL0kֻ+&pL$JW_??twMKDndnBˤ2.MjqݪUT>mr* ؾwrD OO̹n^&Ig\,;4n!E}Jޥ\d#쁵a١wsbU)`5f:"] HlHlgs.OUpOMzPh ޼}syp4(`ȭu[M&Ovt%5@tZڭ{dAM,nw&Go͌L:H;vkm=z0V }X$\"}d 8u[sa ')¡5-2>2j{ڗI X"2w:S:S/ڭZxvBln{lnMN+EZń-[i4uSj}'6>[RKDv 6%VI\29s\J7P. WU֬') Gm-mȾyE~iڗDd[[Ul8ι&dnvf)\>9`er戦A?'}i2Cd*LRDKD`pNMi$R6QrBd֓SOԂܵ٦a^~Q5lr;K(~:\jzUl'D"i]HĨnAz-xܡ^ nݲ4i7{|IҞw߿\K`Iߘ)ZD[29sOyJMݺKWol'NW/4ؾqv |+P^ WqJe)JKYv,;TBg}=zjO[㯛,}g"+`| 8xy |) cm3`6 [f.fvM2y.z٫EZQߜ/8/DD~Gء\4mU4J"[GOSt33(ܦV֌ګϫ[P?X^?,{ovnswDDlqްGHg2b}+ijU n}Bx8u'Ɖ-0bm^YƋd"Nߥ8 ]lFن X""\P.t2јE2m[,)fٱV1@*jFB -i^=u蟝Si5W^sm6_?4ƪ̀Z;LJ?5zDD&nx Z&vȭG֨zc U j&\ Jz^kvz4;q9eRq\"F4}jjÿ(dh,[0E~=J"myɴC2}n sH=kVԳK/Q{%럝S;9x|̲ݖk^4d)`܁vGiC#.ټznT}'W`۽?ѲcOcI{.ɘ/'庼4xy:?dK""rɴs0Kßk5{f9Mys%(OnP8j}c6<:K;BYT罈Es?9ԮEDPPs L;mDIbE̳~`?V 89jQ n]^YK29(-̹nA0V~'Lv-BvmxOÜW n<~&Lp43 X""3ln〕ι݊[`9(|'ݿrw0;JȜ>쿮[3ɴx%UJ'v,s~;Y`֢֢P{%sHKDdVt%q Z M8v!',/~*/0? X"" xҦx+,Ry=qxհ*'hvHD´=޼OrDnDKDd=ZMVBeRi(ɴqlnۭKa.ڭQK / 0ȼRGFOȎ"fdsO()}e_7ӯ2N3Ө܄=jh5.ɯG\rfvkQGIaP8>S8`7,LuplʸaQQyղAknb_콬M}^s)`GUfie7L*㰾#u^bQ~jE_-oyx G^S}[[1RZLJ-%ۭGp%AKDDmn〕ɻ3v+a))և޽3?.S-y%""%콬\[ivlj٧TP8j3xos%~Q{% DKDD&7Fl>B*_,7+/',5g{v+nV~3[лwi^)`ȝ))J/@DD'+Yd X""""%"""2a X""""%"""2a X""""%"""2a X""""%"""2a X""""%"""2a X""""%"""2a X""""%"""2a X""""%"""2a X""""%"""2a X""""%"""2a X""""%"""2aҵP@IENDB`v_sim-3.8.0/tests/exports/vibsxyz.ref.png000077700000000000000000000000001370110300500232172vibsxyz-3.8.pngustar00rootroot00000000000000v_sim-3.8.0/todo000066400000000000000000000243041370110300500135200ustar00rootroot00000000000000 Ajouter une possibilit de scripts internes. Permettre l'exportation dans d'autres formats que les images : des fichiers Povray, des fichiers SVG (en utilisant Cairo?). Rajouter les ombres dans le rendu OpenGL. Ajouter un motif pour le dessin des lignes. Ajouter un mode de rendu Wireframe + Smooth pour souligner les facettes. Permettre de faire varier le nombre de n~uds. Implmenter la duplication priodique de la bote. Divers actions sur les surfaces, dont la possibilit de simplifier (suppression de points) et de lisser (moyenner les points entre eux) les surfaces exitantes. Autre possibilit : pouvoir couper les surfaces avec les plans. Enfin, pouvoir exporter des surfaces. Utiliser un widget GtkRange la place d'un GtkSpin pour rgler la distance dans l'onglet plans. Permettre d'ajouter plusieurs lgendes et de pouvoir modifier leur forme et le texte. Modifier la mthode de rendu des spins pour crer une nouvelle mthode de rendu pour les champs de vecteur en gnral. Permettre la lecture des fichiers Nanoquanta (positions et densits). Utiliser OpenBabel pour permettre la lecture de nombreux formats d'entre. Mieux intgrer le chargement et l'affichage de champs scalaires grce aux iso-surfaces. Possibilit de rajouter / supprimer des iso-surfaces la vole. Ajout d'un plan de coupe color quand un champ scalaire est charg. Amliorer la mthode de rendu des spins en permettant le rendu des noeuds en mode atomique en plus du mode spin. Sparer visu_tools en plusieurs entit (couleurs, format de fichiers...) et mettre le tout dans un rpertoire part. Avoir un mode de rotation en conditions OpenGL dgrades. Permettre de dtacher les onglets et de les regrouper comme dans Gimp. Sauvegarder la position des onglets et leur contenu. Permettre l'exportation en PNG et JPEG, en utilisant les GdkPixbuf. Passer des paramtres de colorisation en ligne de commande. Passer des informations de plans en ligne de commande. Passer des translations en ligne de commande. Rajouter une configuration possible de la gestion des lumires. Passer le mode observe simple comme mode par dfaut. Transformer VisuData_struct en GObject et lui associer les signaux appropris pour le moment prsents dans l'object VisuObject. Ajouter une gestion du mode de rendu par OpenGlExtension. Ajouter une extension permettant de marquer les noeuds. Ajouter des fonctions permettant de dplacer les noeuds. Ajouter une gestion de chargement automatique de la colorisation quand un nouveau fichier rendu est charg. Ajouter une fonction de masquage des lments dans l'onglet de colorisation pour les lments dont les donnes sont infrieures un critre. Permettre de choisir le mode de masquage par des plans multiples : union, intersection... Unifier les boutons charger des ressources et enregistrer pour en faire un bouton gestion des ressources permettant de sauver ou de charger des ressources. Ajouter une confirmation pour quitter (optionnelle et configuarble). Raliser une interface pour le marquage des noeuds. Raliser une interface pour le dplacement des lments. Dans l'onglet des outils, il faudrait proposer des schmas de couleurs pr-enregistrs comme du bleu vers le rouge, un dgrad de gris... Modifier l'interface de colorisation pour rajouter une case cocher permettant le rechargement automatique. Correction du bug (rcurrent) des fentres de dialogue qui n'en sont pas. Support de multiples fichiers en entre (exemple : un fichier de position et un fichier d'orientation des spins). Affichage dans la fentre de slection des atomes des coordonnes du fichier d'entre et non des coordonnes utilises par V_Sim pour le rendu. Ajout d'une fonctionnalit de trac de plans. Les plans permettent de masquer les noeuds des zones de la bote. Transfert des paramtres qui ont une tte de ressources vers le fichier de ressources. Amliorer le systme de lecture et d'criture des fichiers de paramtres et de ressources. Les ressources des liaisons (couleurs, taille...) sont gres par type de liaisons et non plus de faon globale (avec tout de mme une valeur par dfaut). Passage une vue GtkTreeView pour la liste des liaisons (permet la slection multiple pour appliquer des changements plusieurs types de liaisons en mme temps, permet le tri...). Gestion de la couleur des liaisons au travers d'une liste droulante qui permet le stockage des couleurs dj rencontres. Support de la translation des noeuds l'intrieur de la bote pour les botes priodiques. Ajout d'une zone pour stocker des informations lies la mthode de rendu. Onglet lments , support des couleurs dj rencontres au travers d'une liste droulante. Onglet lments , passage une GtkComboBox pour la slection des lments et nettoyage du code en rapport avec la slection des lments par nom et non par pointeur. Onglet lments , ajout d'une ressources permettant de masquer ou non tous n~uds d'un mme lment. Onglet navigateur , ajout d'un filtre des fichiers affichs. Onglet coloration extrieure , affichage de la valeur min et de la valeur max associe au fichier charg. Onglet plans , cration d'un onglet pour grer la cration, la modification et les oprations sur les plans. Onglet configuration , ajout d'un facteur multiplicatif sur les GtkSpinButtons travaillant sur une grandeur physique. Cette version a pour objectif le support complet de la documentation pour l'API des fonctions basiques de V_Sim ; ainsi que la mise jour du site web. Documentation pour VisuObject. Documentation pour visu_tools. Documentation pour visu_commandLine. Documentation pour visu_basic. Documentation pour visu_elements. Documentation pour visu_data. Documentation pour opengl. Documentation pour visu_rendering. Documentation pour visu_configFile. Documentation pour visu_extension. Documentation pour visu_pairs. Documentation pour visu_dump. Documentation pour visu_pickMesure. Mise jour du site web avec les fonctionalits de la nouvelle version et corriger les manques prcdents. Les fichiers de spins sont reprsents par des flches dfinies par leur position et leur orientation. Lecture des fichiers d'entre au travers de l'interface GTK. Lecture des fichiers d'entre sur la ligne de commande. Rendu des spins par des flches (cylindriques ou cubiques). Modifications possibles de la gomtrie des flches. Coloration des spins en fonction de l'orientation. Enregistrement des ressources lies au spin.

    PY!j[,5\\>gr?}˥rɘgç _6gw% W /wK̺#n]iWZ)i#[0"u ڔN*rH475:6={BN:LU+gX, 9*,k>0`E .,c>wXdӈQXd4L@kۜ|RhJqk~\eܐyx F3?09v[e= \ثga$=!KfIJ%|ϵd2- V۰_ }_y&v l|kw@UZT?,u6TQgJ^X$_]Qa`5E 9x#-!'\UbcJnj]ԜJވ ]2K׼mxMA0c6[jA8>?Nn{@Sהfs[ ց qHBŽ_(2n+f^"2ǒ) ޯ1߆6,fW߆Z,L) KĈ}_9.B6= 2`|WGuߩM|V/Ttɍ'pz)x?9u.feh+:ZUh4"2baZh5X$#w;8W] 0M}t[-QIf|~*5M,4Fȩ0|{t]{a]*V(+7)Ti[K;&a`dݜ?gZKG*/eΈu6Xz5]]_D3٣P`$fwLsϸ%x/ֈ"<0X! !.dtZ! K2y@/0xf^RBD]y `sr$K )4euD@a2-jĘ[w`8hg1;V(-誺"@@ؕ>s|Gad M ̜_ (3>c6[Q0vvSD x#~-8"/5sg?fJeT=f=|vKjL՝HH7GJq%%+zXR4\W+v&7pUvfIXJm1u5au0k2ƔvҬFBWDM:!yp_-9!.\C\hr/X̯hyj9pO菬p$w,Ǹ{b@#bӈ[XnDKS.VGJ!Tf N7*=Zq}^jas JU XU1R{)O1(6\r6FU#S-bVRz^˦iA^PpViZgʶc@R.4cs*p1>&^:zp@̯%a"8oo˼?E?=8ODZ9Z(qUm]Ρz\lWwNԔDU3"ÿZEkJg5mn(7cF:iaCF/sSjFs3a6? n-e&Ӄe6}~|?&k͈+,3],`I?n$6rDoB$ zlaGp8lΥA4n&蜤 >2t ;UC6#=쫞pnL-5H /VY9JF&'T{NN "%(cpKwst]=p52{9B+ء1pu> yF^a^*0 +!WU¿ƓmVBUx߬Q2!-k2B#t{Gw`ʯyy\zzre͊P[1Bv; t2R{O~Dϥc;SNZ&eG C΄HY2Gڀ9_kt~tarhKם9Ϻ`S7{̖.%#ܤ2OW3FYAg8TVd7ڕ;/z#x y,\amʶeUk5WGWPѦ/G x4/1; 8=𴂧~_r<°=a5ވ'Q+)Vc1ڢZјƵs@]Ga]/:u`._!.l|ُg)+ٴl#a1gjcfpMy*a#L>$7>e+MKCXoC8w^jW;he ra!*LQ턮:haO[´3'ב3=\?}ǜkGX9~%nA9U\ [ecK iN,4ޚLQOKqv~IjF€_MrCG7-8:Ke\ҌT/L;J,#pN,f5M%=r~&1HnFRtʜUCi*Ñ|Fb1R#\ō`B(e+Ml)i!e0T+2 { Ț%5h}@sܓqg,RSc֖E)CZI6-1uXoG?#G{dM:cag:5 i dV jGX% CT'Uga |tsE\?s*hs2*6q"M4UD-HULTcn:..*DKe ҏpc:Z|vEY |lt1&%/ 'Hp6M[ 5s0zیV`(ƨNfaخd#' E7]òIJC7[ MjloS2~${te TR̖^l@1 ۊC.mVň1#&]쮿i u`.O|qqC7Q\{p P (0h?L{=lǚڍ@Ef @IZLP{͇ <~џT4tD%M*ln 9!Xqpl1Vɨ/o7:MV]pߓ-cRu4`eOƚO9V'Vt8OɐPnO@=2%`"vsMr݄}N@rޓQ: uN}7C5:Kk^#?"Oy IDATp]w<y7aIӱ`գS8@XZʍR2'F 8 Ƕ[a 鏘zȦ1fUuK-5f &6c亖+)=/>fh@O1T!hcT|rRaMĉV&+ȮΧi}lbm38U@zqMrex̵4F0%xzqx{iǚ4ZZ5U#RG;9m<ʲgq9Ҩ-ʹ@.Xy5oTzrI=cҪe^JJkUm._,E-y}GgETc5G+#J{PauAØըW\B:/K\xC( j8k-FDW!"Q Fz2Q-P5CyOM'Uag TqZV7/G2H+&{FQ*M W=KPLHI6RqMG u3mp̵Mm-=:sIی'l4E<2bͻ%C!ӂsR@QNz=IIê5S(847m/Vaی}t,?yl4=[JjPj $+d<أ՜58z>OiD˘08ں_t!.WRuڋY9c"2{v"ԅCz1 qtU 4,-`vmѯO8=q6q(b9crXYhkNN4M)7~;l8 F,mLtF drH6 }Ub씝"{ɵ ?D6r&4PVU&q1;`>X́ܩAu#?od0<_9:z6N5y p@Era0ܞ3}4 Sy v̥MMu3XQFn琳d(1d]zd؄V՝pm#WX֮0Y933 &`LҸX7~wcf2lM{%q@4U*݋uqI [k>[t{j)I J*8|p2QsFi`2}ߧa@5=nNeC ptHҮf>X9! 3)$l@p68Z B_4eMëlv眲Cs4m =/џmG@mkmW@pQŀcw#,B[adl& "°`>?Ƭ_:xU2pڷ2I6S&e=\W:HtR^Z6 Ɓk/@᳏IkY\j5nmll%7a͆4iH1յ[IrSN3(1vcD_I>{R]ؙFECC@UT, RM !"&ĀIY뚔Y|EN(Xﶩ2~]haB rXjZ{Ceex2bHXi?NNM9׾y,+(4"&l=[b,Z6USqm nUc1NtF1pi:Ŕ |YAwFv;tro ԛiu~+"R(bZ4LF[f):gn*1͜K^ZY5I Ȫ`jakWV 2b}$xkPnD kw=:_cc]0S5;m O/RLF/gC\8nxف{dΠ Cel-G{K@SW {/6nT/+ӱ&̕M{XU1u')U8 A9v'Ϗ0/TA_1#n&HQR3BO: om8"u'))#% g[kRK[x"޼|]rh,̒@A"Xj( nG'Y觕Tq~}irN HI棂S7aMcQ* HdD]կws=+Ԕe2S0=bf°uZkLd*W}Awڇ[Ͱ+9Qܶ HZ#E*Ϯl~uW~cTݛ0Tۯ4E˜{^T1\+{e9!>B3lʹzIc֨a8{pA\=8:!a%cܡA J9dnOǘUmlUl'0Kʼ(Y׹R2ZpN sFBƸߒG~kto]b c]AҌg\g:ŌfӲYTuzHŜ=gfrʄ7 K龜yr[-O#jr9H!%Aٛ隳od z6EgX.O{Z'`\l{lMw%qa 3|^ ̄q4˚0Mp$SiEA[&\E-s5'THyA@vTh 0G1 pc6[( )Ma_J;&l<ny="=bΩ9a`ŵ1m0G1A>#̡sYgb1x r$M7D?bNc>G|!,!Ex ahtM1ֈϘgm*l1$IDJ"/ SFJ#YvL_*4oT-4W'SX[WI7eڦiHư"njY{k ^uGi+ 9]X.M~ԛ BJ]V+*D!㡇9 F: '7T \_J~D߀/ߡzv:ÙW풑\ʸxM#@nS5j71ʸfج;wDsR[ ́UB*^W٬2Dp@A~9"< "Ou#o[cOeNLnjP?"MlLp= \@v;c uߗJAٝy=c1zyP6. :/aagF+kU[49 v򵀦u!ljfXJn_fL [ʍQ26 ^eYamkC5 k`f* ?.F5Ho{Qt-܏':0X3)C\LG g5}פn*Hy^ aw)>=?ΞL#7Բ߷hF{Tbb9 *il3>K?@aUtl46ȩw@HfR~o\Tfo/&U4<23t(ﺪ-rf)GNEw+r~Mx,shx_7Rb9+ {U5mC׵SRiq~O{}6^WL'Ʊ0_D?e}W7W#*/C¼i½GSc!)mIkv$'gBX1B) 3#I2Gi2o{>SiN8>27SVsO?u <`U5?@቟X]S,@+! q@Jx|WJKp٤ZUacz>IFeJbU B.Jy k#F2JeI%$N}et0nrܼq3Sfַ}:'qKҠd2^Sƣ[eF4 ږFv$Nƣ˗#Ɉq)SFMS5EhyW]$/xV-p ljlPurMnd?/H_c{mغFtao2ȅJ 6K,$@"DMu @6/v9h7j( cÀwz17c^u/ s\{Y:JN'Չ߄j)! =zNHV5'ZV@Q\zDV"^r\l SnNtfx_9M{fɤ\]c1q!bH!=Fŵjs$Uyڸ̖>$sa cFE݀JK՜3okV8XţkRZ0s+^51p|ERE$,2Mim#18 C  &71M)R\tYrSP+*YoPPv=ܴ5u6n&+hQS2`█}DTWB0g,,ƠH!嵤x U0f MHM5AAT}&L8it7Wmu_]"Zvoo V^1&H~uXM>Q(c3T3,y,s<뮗%nvP ȅrah8[Z<lDv cy fLH{>ߨ Zpjt5nb9Wԥ#55p|E*莏Ȫc/uk_ Μ9=AR`p-i@-u cc̺f"XΡpbZI7I.y`.iv JV{IJU/XRf+ЂEtLer8>*ؙ.o[Jd^L92泵vj%a,d㼮:{)~7ߋH567C(a۠K(g}J5Fv^ws'Uqm6EsSK 3 z HҮr>DL0Ђe$3)RG8"ihUUpJ>k|t$)ݖ_ fnCz[AXyLkd#SNp9"aEIQ6NͶ+)@r [Am dXR,E%,IѦH*5V D[^usD7Wk<B#Tűvze: -fu14^[5[Hww.kW>eZZu Xof/sdkxҲG!@DFU_8/o!nQHe-TsĜXyba|(ˆSs2|h&-?'?˅)lU?*,h@!6܁] ky͆|OAVV٩(B". sI7]n͜Έ6 aZ٘5 R6Îz Y/U{-)@e ϾEx쳟,,Ϡ3U- fYG)32eb9wN bѹ2tsgy-%C){I+~5 o$R of [jh{Vε#;)_TYu1A#q*l\@FJC2#;+#WiT1fc̤k` t^Y,FJAV+[6SNeL*g c°+#0扱ga}_ OW- ZIHr<-?# Zj\nlcKɅ |1n׃(7W|N2g`2zyqKENi}=1_.`v;Ҁ ;_@U[ORB.8j^p+H? S4MQT@TR=Q[ IDATg_=rEnNiRS74A*dU9F yv،Y"`vz$ix+~槾W2}ҫyjѦ;'d3BR_Gkb)+Ʃ'`e  ;!O,SŮsmpS7Xj̀g )ӱ3{R"!;IR*,I #kpt$<}M딣ĸt]#LyVh̀]*踊(Y[5nea`\96qXfmkq366cQ&mF+69{NP~Q<IZ8ʲ t#I{l)gY"2w(oHO 'TcΉvQJa(k fY}{= jZj |,vڪx7ò|-E(ߏ!$KGn} @,!:P/׽Z*u[* Cr1sF"0iO="ጧ!S |_!>|w~Q>6*c%z ܙuUx_ꅞC̙fHLںGb`8_AUf0Ј32Vgڢ"/|pZ!X0N@<6ah~)2`:nZ.,ߡWg. ]'^huy1Lc驽 fVJh ,RerJ`p ÎvH>cj& KZL5XNСe"?\עl ^ɪU=,ca\ !vѺ>N~O9sf {ӏ:-%Ei|H[n؆ieJ;Ίt$;e\/|ы]7o{jzt9@0ѓ\|k@˿SUwO$ O&mh $ OB2fPj(Cri5af0TQ bIQ@{t &#Ou|VkyqcS9 RA̘-p6 Vƙ%R5V(!T*n G iͤnIgىwר˜,+OvJ`o 8w=p:esȹ QyIw:!s$x $`ueH/$Z)|q:-&r_JM; 'nu#~~|(LBj%h\/]usiX6S aa8{W wntcW͎fmb>bgl LwbYN@kWcj9 S;#1\Xޯyt"ɬ,7#PFªꬍOrs|-|NilwhDG] 9To(Y+ecFܼ)mknD.)eS_>n^gYVXRIY^)c1g,z\BX-~Հ??[o.e9#O`6 ]@<u uǘuGop[s}~DM#`▊ԈA|?XYJ*J)7iF,/`((P?2@*{߀~]\+2IZ<:-f0GfrEYŲJ` ΪJt]LȌ6=A١4O5?](EybߖK2ٛ|P 1HlQ{,l0w텵YI Àgx7Iׄ雳aH &,s.>"ۈ GS110x o<8D=v;n;n6tV_2oz?\HT#r 2mDI명BN s'󷰞ct30jaBeHϫs)F1mcs=-]/@W*Iz]wWAN>ó,03n算gD7 !n8Ot?M4A-}Yq;| ~onQ&+ $}*S)`\ߗ_e{VFU`Ѫ=CJ6-lg{$.opx{"XUӴO\[9AoJʂdNFX7cÙsE'3[G:/* 2DzS*7f, hA1Rv QSL] #:JeVpa7cZ97E DL;\DJ]il`kr N2my \_O' ۍhUޑG3ceZbkVhր#X`▋>A ->_YpXS- ʩn @I EmOD0}܁!jyt/6fĩ6Ƙ,pNRL)b_g9!gI?pNN}n]Ly\jX۠rԧ)߉{b9`{{]I #u߆w_TD0rT4t|[Ɛ< x9/Үf<'ޢ$M7_ Hl9'lNob& \_f*2G^L;,Z=WrM=Μ]*"gYmKy”q[@L}㨚ΞvW_OeyR2 #?p{9Ny"<0X-\p=3/3;ߏB4*P e쨴i( x$ƊtS@rTVy}KڻT[{{/9RП9wV%x/L)us7?;~clKam) n/c.fĘEc(qv\g#B# AYfJwUMe%1@=V+o@ qm/S7?7}-sd"?9!1c8=zu pNGF˝jV@:peqiE9L97J)&kRCqLI1Rl.+6]9Pimv0o-GG۲珫*Fz=v?\i!:-)gtpzE$V^Yj=R@i$.ԘuZs T7Η ˠHޓM6;7A᜘f:/)֗+a;*`9/(2ȨJ1)$3 {4<ʖuϢ o|ӷ,f:NXYmKS+hX,Ήё=uč@ W8^='D$ƚ#H'z#Kk[;p"'ʸ7pW?T4K)uEG'UHl*Y~?ciQeL5( _+u#„m$$w|L7OmC}VFE r D^ CejN|b@0uĻcAM#ԪD{ȀSaƯes&rN^{i =x>T-l`,Ǖco L@ B {o#$a|ܘߪ\gvon,M*?kꮤXj0uRFu0s =ƱG,%ΈR)1ĸp$sm4ggZZ%a^[fSW GO,Їrơ\٨>PZIqR啬2{٣= zJatA{B%h2\՛s5O0n⦎CcfK݀O*r { TI\[8j]Ro|*q+c`架 ܂4_ Y,Yo=/#+2tv6qs4 uEVjQG;D]O9@Ev0U3^iQFpf5V*C=$,Ґ;WB,^h=]T7 ˸^WWWf"kYa2Ɓ:-u)  r9{iR(.`_eѲW&Zw\Xrm]]  *N?_lXb)>\+ IX2y;8E[L|&ݓ f57MAӶ]D WSRr#Ə1qtcf9#3`j>g,#:cfutV0Fo4eaT-f%4cnkFUaw\ H/#{#'Nʹ52Xӆ{kcNO9w !К.9`ݕ96Ee к/ڬ$8n"c>V+9L8~Vu[.rҍxecK!! Q6PXH 3f`]{h\NuO&D~~YRdNpJVn'IRcvy[ށ p}VP+ ˨g1@9#G98(j3ѕ:a1I)a |A|g, @GJ"w{\)sI1=  ]'sF@5xgx.B2=VwoHfqp)Ʉ$)I*[-Cm(!B)i(È2jmmwskkϽ}Ӈ/;[[)E1b"1bVߣ#r-fW5e&`ZUEpLx8YAZt |yyk~)ZY0`ٺEV<|ReAՖB?2 !SOX.%=f3.{bt:d5G sT}y("FXʆlol3鲏y8I͡bd&hrĈl )y3;Dqn5X=fs⤴{Sް02C.yUU-)ZZ.,LcR"L$EYrVql"Ot{*~Kp)]e_1 a BF^à) q-^xS\+F fޯmvԝ G M |F6qN"`鶦 0C-BB|)3k~ABF΁m躖';hVr5Sf3Y;Σ5]Ջu1w6xF?#nٖUU-Mҟ6_0ă,10Z$fٱvii+/F0kw]14JS 1sn~cTr9[wr ,V5MnغMX$ I|BtED˫N:tpttD|q0=۵kґ/ʕοSo%͇D(ժGjט͐csY FsrL9sd?@-;"zRoQ/UdF0",:88qw[C:SPX]}]jk-WLjaRKX͆XK07yYO^NyRuBT/T@Nyj85$4opc,2ڰvV5R'2÷Ko+b >aKWᄃ%[H T̙KL5hUGL;F#hwBBXuM3[chb7}.XIBb`W^oǁ\mc6륩Tik˨&WZwfIiqaڵC@'GG U4_V>ZzL9E"ONkgjD ˅ʪL V ceTf,ݓRҰ^:8O3OlG[\zj{ع)?qO;$+N2 d\\,|)XU VùC6^ +;n7hhMYD>◊aFq<)W_@+lZJS´OCL#ITgjgՔ<_M䫂Kz}ޛ֎Бo9.B P gbL6K&WOvcDZJv:$br72`LR˹ʊv:k4 EMxr|DYN(1(ƈHWUIR!E6k`ꮓdUID܊C纼>EDEi3cJjN02Z&$?@X)d+GGG̨d8w^C,BAh%Dp>aםu-p:R?u(eV~t᩷=>}:]-De:0rқWB,w2nJrdA9TtjHMDQ$#jd |ތwT2՛pJ#xW|8U~$n._.Yri" %, st ] {`0Fcwjވ~qaUDv[Hwp}7}!,`xm:_9gs$+S ՈT7ozPR%IytA?YiTra.N1WftH!бA1:l665*r"?CB.̳JܻJJ$?4rg2EF#QUb@pAtIt>#739D=MVùC)~>l]`ˍT|Ƒo<'dVS+7%V>@\Mڎ?Yw>8-ߕ_hIˤt`E#(kB/zɛ cv m+Nv }_CO8K|d$=NԮTyg~]7S;xhM$v\:뽩iSC#X rS}8/U5 o~Nj98+'OW_9-}]ˁbmbUyr,\o￳MًĜ&H=BěQ=@0K_ȇdD|'F,*r d( EyyUE Eu aWl-NC.*,yi;]q4("Rx1䃍訦)ۢ@HĀ,X4JF$~a9 ?u0_0 `P:3ZҎMĒDBz;8=7c0XigCJq#54${G^ +3}!_%zu44Kd2Ç`er-Bu8gcc]#1"15-o?{[ꕒ>ރMMGeLG`>89^MD RFf(gFX1`ur/#Pj +Uల/y8tq}?lp'O;} klX+p.)0$X?'H!=z//&OV* G۟YUʄflTsuvsW}izs: ]-800HOe!ϟi9'b@?BT&1&%HmpUl1;D^@6e!NM%߮_Sw!Y13sٮsn=w^r=C&GRvGS=/'+n'b]IC\0F%8 ]{z 'G>Q&A/n_-Я%օ&) :QfW38רsŻ+/lDQ/*HΌSCCoǥTYf]f.+8}&<_E.sp.̘/8Z>vV&&P$SVNџRPB|2B(u"gnl.W@d׹:Jབ59N\C8X:Uϒb0kf`$(g4'"sOTѼUwH#!$Xs 1Ƀu5<È0![_[{m5X&fxw `΃=@"9p%^#$r7h))U>QZ4T %[{|++H%Yuj4PsM:!k 0CC)/>0ߍ+fcۡ>:3;#M b][zL9J ,2eF# N9#Y!tV6VRq2Pa l=19$chm3FFW}=2h&7-Ad!7J;bJ N)p|> ;9iD&w9bzJ6oI*|Ro:KҲ]Xdr-M\VRZ&Wy<0xGN#,f OΗ 1ڿg>Md9 Dͥa" [U̺ZF%>򙲸UjStkಞ08:r%(b$z^q'ʁ b`dy9\$/8<.]"\\],t64E#X 1i1 H0!YFD0EVF1 axO7N:'9"h*QIUkDJ#n}I XIVh4!/,Zg=.`\"+Dʹ^պ-Oʺ/s"jǼo;D5d2UGֈEf4쐫FI1n0kĸ0k Lj՚?]Pc$Fk\G&SjrRaDG0GGGW"ZD#.zu)Yue ,6 Qdk(T~L+^6?u-RK$'&"$#DWa+BBzub| Ơ ,OC&,Fl|[Vz{q+5wxIÖ. d Cztآǰ'~6RcDB(i깣UI4$VIi6 q0b-Q>8Z0`>2s|luZl.ҠRJ~b 03 Rzl0^:j/\yҼMj8ȲC pY͚ ά;gQiϯ#yE޼vU jpY.{4ٌ\播ҥvڕOm?E9?qVowؚVdA5oJɇXy߁q@'?)Ejﺄ=A_;~8 6}OW& |MwVu^ZJ ULtQq~+F"BJ,G Ð0H8Y1:3oĊpr{z T濺VùDt‡[鋫tfRYY5=8f2W+هDh|KK@+퐩T?SD9pp-?ɀ B1K;n+04ҵ ɀIG!F C0D''5c7f!Zb|[apNipq]/Ty)ՒLNrC) Juyx6:jR|yym_Z:a0ZIUYYQpx%ɾ|NNPԱw뿚$P?IG}q\ao_wst =fw)v~ :_D \?zv9~p݉J6vFQ;+9M"<RA'e< ˥GJ9{l6zz0zMqmLuF0`7; 2%(g.::-O|c? ͖&52sNlc>s;kS-+Cgqbs])uXՁ|Pu cֹX@>Ho] h"%F5oENv{>2E)jI!;7@AL, "5oaV#-Pԫ&h@9bρaoOa!tuwC%,5fCx?}Ll;i.V!Y@W(`ޯ:;+oE( ιa1r'_j\v:gaLH6 Co^6XuM?kd~;q}:1Bl<u?8zk/ܣ?p˫^Mc`,%e_!  ) i0,3wXwyGMz3ʄ-%̵vaSbu=JT@ZRޣ ʃde< 'sO;YrSr8Ekh4U~%J{VKj%X#6k= %ϻ0B q!1`wٰe1 0TqmyʷlJZOA3$؆hTWJSn!=#F_tv7̓͟e]B\y9Z;>גJD9c+H݂ ,,Uz0~吒 ;l0LO*ے i4~}d| 'D@N" }ޮtԴ/_[us0$ͱJ X:t҄ i?Yլ)tz,bCDb&U:ZVj8|۩ҧ&Zt!ŵsSG Tæpt#kT0)0lH솢9Q,1ya8Ei.dZ?wKv*IvԜF1|S^+bqɲf ^tkBd<["#d9J j9ٸ 9T90y'9#~|>_aBt ,/}vru]s _k V5) $Ƭ$ :WȪ0']d,`9 HAasNQVtlD%ƩԎFpb%X!Hx "j׻~h~)7x/[\Vr/Jiʹ^/G>s)*&f %%XzB̝d4r%)EXyp6c,gLtG) ̱ 58a6;Gd"پS)u2rpk&[ v&d̮crIԚHI`#! ^c׆8E4El!1>'T:X4|(~~A- 0nt^$֣-5˔dy 3rlўX(:1tsF8n !1'xKaPUb@VlpuMs<P74gd>52/U~tYY ҕttJ dZgf@ -uptxE-&%_>i8tFq ,JIf#c&+n=ts3I\)Yv/Dv WVAYSDH c'lj1uOBPu(mߊ&YBßsu+w3@Fw4pnRn oJ2]sIzvb 掶JDs  0NJh "Pp"+SU8%p~heqƁ8)btX,68Z,<{XJv=L2)#᧺jbxw,Ͽ_MNJ֖@F M6-HQ;$Uu=s 0 6hHٛb3_h"+Xn{Ýw}t'*!Izyi'"`k 3!#V ",2Rv %{* 6"Ţ+1+rufvOq4SBk@ gpg`6)X;j8Ȟ?^64_p2y14`0vvզڍjBwT>!SUج<5$<ǹJbաijA&xnaTa01cМbbtIVuYR2=pxH88-}/X~"8E+e3X8h5C1D"BXᛞ-X,:Ek ІBKmaYc}ih04pnƯ,I>Ú|% v 3Op>AD4`O0id+v d3ɘf9"!0u #`qYl̈F#r~5siߪ30"X,3 C=:zwu탍6S$` 1MO}☰Λ9<6 3ɉ-G#X 1EAJCm~ 2bŪ^YT0Oغ 3+'^ă\F0OQg J|ėWD9p"$fv^3i)(ݨΕ*'A̦֛6XyTI |AP&jUV 9dK,hE8"gx;-a@dd@v^.M2j{{10ûJޞP\C2K`!lzzrw4pn!"V1/HVˀ+CS Īhǧ8Rқ<![vys㫞+۠rx(>'MPOs;@V.??I$KKD+Kjwjg6JjpZ.CldBW+|Vpp3{K=.]^VˀɈk($'$ (de!3Q-n3)_wWn7 IϺ*A5U\q' G ya""kc?q "o҈Jr`SuuF"G3KAaEG8#W@JکxtF@9 Ty_@lOݟ?-'>e&V"lhaN+np^.^c|aAG?aLpn>;n{A ul稊ҽGe>"oW_*@@8""-k ! .@h)HdKR"&rG'ay}&a$[S|N;ёv uO @|juVSB]^ AoaZfrUb6cí7~ `5R3^y\y\aD;` 6;pu;dd:N4*r!T52@owI;nzW]PCr&IR3@dJPXHϖpj"ˆ)[UAu%KO1"sTyN\1y06 UҘc$&~`ʺ5+DHwBOk4Y&7Nfpo׽ "ZN\Skca6:.?b^@#  '~ÓɟLaj|AfA)қ|V|~g]Ÿ@Uk(/͙RrU3~yx{RGBJ!ϟڊze GX(gM? 1L+wz5w;MJuN FM~|?n×~% |*lݍA!\ǿ\cAFb`yV#rcޞaP2&x;)Dq3h~>vpmr y\F:؞TyGr:b"o7rlʠ`5ш# g{,:,: /9۪nⓕ8A(SrJpXH)bǓ= y0G8Me`&z"Ηmf+ ,\~l <#\.BB d0;t0D.qm)}lCls@G,FV8湔Ǿ4p aL2&\G=.5upq eѽn5\[LLe]$*| RrgV$x!sځ/!G3ɂ=5AG8#mqvѕHGX:+4}A?7$p`g&0T5Sc@kTD:M~oVC#X ejɿ\{…s\a`~qyqqr+6K<(=&D=ݴXQr6 J<;Ԍ10BfMg& 1A`iR!'-yd}ZK*knyrbFVitnl54p{6ԭŢ h)1GA0fFJAy/،Pb#l:|7$f$F3i)S_ɴ:񱀭3;^W"۶7ņasyRŒ s|X,bZ]gqFocPb:lW `54<(l6<xO?ְbMQHj"147h}Ëtj^マ$ B`N) 98r6@VRBOU*1`eLۀj@$b&[LQTH39%OR!!܁\9c1Tfp2air|ܛ`54oHh~l/NׁͧU<@ @1:wj!ut!ؘj$vGxm(w6'Sq6=  &ܣq j)X h󄩺<z\AV;<q|eɱi 7|6M~ԗ(FI*s[_.G0rŒ Ii890ܤˏdO&X^g!Bγ3$fV?H R$!@`rH)y#WdʹE0 0:#a,U>!Eټ=&l[gKro11/\RK \(]r׹ _//?(,Ja:!Jne‚ @QDdCw b&Gk EA4 MjhxbOqϧ,p8pn]2ukp|<`yԭ'+Caլ,5a*};0[^{Wzj$9F甔ypD̟q~̃s>{u!+!l! h:dd_1f3 J{fz>}G[ɣ>o &ZdQ SPRN$y? =/kQ 2D,yPrmஒ5}AhMX⺙Nbpp~ 3\q_|㘶WCgC&Z}{m\Ff_rֵe^0$`+:wiPdWsph9Y^,>B#&'8 ̈iG|]w @S*jhhfcqaVl1{nxFAWDAW- lĈP֮v>wQ$buT&EIE;,tɚDDh/}'bFa @Á`شE#X [HIptoU{s9 {ri;cypgX(Hq*V!Y*!OdiʓsHQ1rP$w/;HQEIn=31 eA8@ w 8Y |a0< OOJ)R:tUuw Tob4gB1d2`? *Ioj ·fY~>[fUq%]N-u!k/ +vv:+!ZZ[筢uq2bR/W`ӭtYo;neF@y2ey f:}T>)\,'U\E;K+Vks,*cV?iT4=X,#ApiӣD$-GH2A򕆬u6:^o^4-){ i*Ċ#,o=>V(Y/4_rټ0Z?0Xr3/4/Q״*NMݝZvxj8P—s].%OFkmߛfӭz"ϷLL<>Z b44ljY-Iz[[ 7*E8  VAU8ߠ7[+թk3k|lxIWQݫCO0xd} pdL;/~7|_p RWQS͖;]W+h5QqgKJV[~v` JqҰdӪ[Vëk:dެky2`1Uw`u*o8"YXtyR2O&6<;[eTAL\[]WN5;,Zq  t|U--bW[+˭eA?hj< J:ukeYV񍦘NՔ2q,w"4\4D]X45HUD垘nI6b44O&!U_,;(`e;X, YDjWlD۱TJgӥP3[o SiNvpak$n5Sӭ05g՚l,qRv,yӉ \4NC,n-'*0yXpA`=% ^ӑ[/ke04J nlTd;s[,&X8wh&GCYNMKvJީeF@Zݩ `XpJy6rkeyΖV(Y?x1U3uwkt]=2>R( WYh'`NH @'=L/O'Kgr>P΂;.B\t+ Xi˪}MV-ˏD 7VT;|GSn]ۻuIph 4^?؛:&XWh4 GW"`n(Zw0˦UzEM֎hNVAgYzݐ;oρ}E+{BJi#3j9jMȲvյsLㅆ@{WADJBFEZ3*|Ro^:Y5*5*S4K!j,сuv> HO#IRTA9It]}mAL8q?zm_f+8%5[Nוt=`{:; pmm5}#-d Xg=3KtwwTe6-駿zy\  nJEuݪasn_=:PXu[%,`4|=oMsX:K*ʫ95y5[hj4 " ]yON˼Dnfsm5$7?p4^e2J"`lnk\G^Ύz٥/$v WMN9=N|w|mGQhcY),Weu#22#Uyٵk~?ι?RA!BVYw!B6 ,B!CE!b(!BV !BȊ"BY1XB!+B!dP`B!/OB!篾|v"BY1XB!+!O|;ۻF{]T3U6B!ڹ?p}E(aj{{x?{]ES!B [ܺ (*( +cf bP1WxB!`bP)ot3?WB!1(ֆ]YEnPdB!泲1EQNX5bKbg۷4U`>xGÅB|? F*W$+'Oc`<TZ7'?W7zB~V&eTՋ6:Xm[ifh]Z8>8>nqx1|%`zA"cy}%]o '?]xB!7 Um(vqb>58>xcj|նs4=!\VD-{}xB!f`\W\ͼ{5C젮)ffQ ĉ+Ub]'?ByV,V;ޭ[][y:-yh[U6R^]$.{@cB,V("@]O}=ZA`M1B""+ Q`syk("*It!cŋ= Du=A]O4S\MQLg8==^o16fm, !dV mLf~gs߹GCB"+RUC}q%?_K(va߹!KyVBNd"b>_X"Ƌ* kZ]5ydeX˶P"!Y\AtBM3"+,QTն51x|7;dWA(!Fٿϟ.}_l4nX &4@Uag6F%=Szƒ?:%WB᯾|v׭xaBZXm۠ifNiM&_˫j֥WBfp\P,wmѽ|$B!W̵:XBnPxt[oqvgg)!rYY"]8(^NOӗ'B!`KdIhp| _ʦB!iE,%-Yu!BJ\"B4L!BȶBE!b."lB!m!BȊ"BY1XB!+B!dP`B! ,B!CE!b(!BV !BȊ"BY1XB!+B!dP`B! ,B!CE!b(!BV !BȊ"BY1XB!+B!dP`B! ,B!CE!b(!BV !BȊ"BY1XB!+B!dP`B! ,B!CE!b(!BV !BȊ"BY1XB!+B!dP`B! ,B!CE!b(!BV !BȊ)*ݩ'Bn6X1&"!]nT]BnXq #<:‹BȐ"׎QRaAX$/dwj5^ 3BY?XQd1q,F%Q|uEDW\uGF!8(ȵ#@zޢd;%З[(\nY18\ܢ[ 3BVY V]Y.`6m:χcXeF;"vKw"aFBȇAEChj]b'Fs}Q+!1YS[.M ,b.CuV1qV: $F#Esvzk_"h>s!ƶ"8(ZV]#+2 ֢t*KsڿU!\6ֹ]'lXd-oc;_KȺko|\B1;f*W~>o}/eX(Zp9X,̘ (KH?n`4ۯ:n|֠i0#!7 ,6D ܙ:IWwE2hh $s'E9P`!6B.dIA`9h3/!!k6M] Ì  ,'"$[ٴ i^)Fvv`n1|jt5|0#!  YNӸ$ٴqz>s5qnhr~6y& 7B ,uY`2d 3q ;F;%ݽ{eJӸ]A5 !k`%wB> k5ȓr@.Xb 3:յ_ia a+ZtҸG|p:rɎ٢.%ϼ" ,\I\7!k|Vwݝ2V+fÌ"k!!M=͞aƝ%*t~raMm}l0H ,6 2h0c6eeÌeU`NjNF)*|lڠ(6|(P0-!7hj۩;++a NQbg᝔Tob6k0‹MVFEAE&0ZX~uΗ){ڌd\7c~. Yol$*&S r}U>2|(!\;umQs;gw!DÆ2dmXaR ޭ 'nkn !YjCXGQ}3u7Xc k@;(̈́ Z!|&ݎ^O <[w 8a}9X@<J>"!7 ,>"$0&,ś@"7 ,6bM! ) Bpf p?'͂  !ѶEXfAE ĸa~„(  ZWheHq#uk:i06(J"7 ldmB (YQ_˯\d%wBH E8>{n4B ,6BP!)D\(h[,9ܽ z9vFqEI r1yS,kqr2G@"k !B~ %dLVߝ"xU7Y+>DKm( E NfZGF֋_Bޗo>Lv'!/EBXh!B7n}û-uZi}sQ!6xq.Zi[ s!ƋOkn !]8r!" Ok "x\,2 (Zk h v>D`ߟBcl Áqӱ"$H!P\>+4ŭ^MyO85# !CD"À;XEH1c}C3@˒ dpT#km-D(!!K?H`5co" B>ώ=f~(Zi,²,BBHqvR qF!Y3XdaUR$d }S%kY?\|WhZnV,B> ,VB * fV`Nd ~EȇBEJӸK jV)~L=~-#Y;i nBU;XMmoO |.(AVr'd{^|v#"G4v<,&bBNgFEr(ij @`ň:X{5;X/GB )|" G4v1 ]=_=;Lv'WY;u"*"$d[QuWǷY\ډ!^l# Ե7?=}#!r] 9Ͼ| x=&$WY;i-B^1PU=>XwsvV\왐+.2b=%"VRzWvpwwwd"V;= " aq4!UݟY)!^W!ɸƫc(YXd4>ѽd;![:C_0!Y-Xds?2Wxrɸ~Œ dep4# `"d0@fdY5XB֊4لcoZ_C@EA%IY.斐M ;=l c"VD幯Y` Y#" ^B,:X}0!X8A05gլLY/:E]ۯCn0@EU]xr7'8~;)zS!WT@1dHBEtl-& 3!<C|t+s=x \b"+!AWg_O~O?KE ,2VU-^q\[,Z ~>d\) !x_3Xd4>Dxk. 5n=$?yzg!hf.2W ,~Zws  u]kN5?;Z:f.޼1+!&\ ,B<$<=ʒYD Qx'.(9N>WD?Ȣ|He<-=>t\ ,2EUC~>a 2k 9 ,2ڢ U1X)S.lv_%(e"[R ^EQs"1Taaˬώ=ƒ,@. ~yߢ(jpDxOb! 5DX`7_(Ȼ"a(EQ 0MXv3 EP`!EQ&#",œg_Ńx] ,r!Xd0j=mEQɦ "{_ƒ sxr.Xd0f `g¢\Ͼ|/~} ,r.`ZX 2R_a¿ ,BE%C&iԵl߼\w"IEQ: K,ٗo|{Xd)Xd02 RkȜW5DeQT턿_P(Ȁ5\$@^5,¢@f`ᗯ1~~,@Eo,JV uƐ:g ,B`QTm<1>=<.@ECC,VU"+|{xUeŀD(`LlXD_` ԛ{($ ,BaQTry[(j$kBmK6/_9R IDATdP`Aj*lQe\DV@7}<_%]- GH-J9]P6)D x7~o$F(!EQȢK(X[ !Wx &j>(^(Ƞd(0@ag_?~ߥb(Ƞ/Mrs`QDM"  ~oŏUD8AAl ,<v'O_gɆ- `MEQ!U:<-<'OP`m)XdP$wBm/I0}BE4Ȳ|û;}uӊ X}G2(Ƞ`;!#~>ݝ5" %( ,2(`1DH)ˋ>x? ݔuoŏl2(!dCYEQo>|mpƒ O?_u7\XdP`r5(@,C -BEZBuݢ T5!k:nqٗo=R`m Xdp4EU(ꢨ>jÃώO>&%!bUEQn9g?_+ znjaMX6ŦE]Ͼ|~x0b " ,>(jϵ }zed3"Ե7Sg-^q(|ɸv/|G)6 ,28`ߧ(ꓧw򹮺(3+͂BZw,3$/@P` |޵Uýn>>vQlM sAElvvxy8ue?uE]57_#t!ê^dÓwT ,28꺅*PLr'dSYu)VUuUIa6䃇,ٰP`BvNaYwQg_Ńx]  ",SL5+-C|G)6 ,28$wB6~ћIJ|B\)7GHrT~P`-$wB6 k9Xd2B>]Wϵ(r-P`!!Vd޷(obJ(k; BG"DֆX漢w;߻kn Y!~ԵE]wObeP`ART!dK*oZ[BV G/2HA>x!MEjɆlXds ( !̈́Idhv#l.U cfA{  !Ύ:ff-! X͝!t :X Cd ~;)g9EScۯ0kӠ"} kgYi@~I. N t# u7 ,2LRԖ ,莾9KN‘]Fi,S7~h\xVe RSnp_o&"L( d9ht3>2 h /y^ =w4HA).>=pUVԺ[M%kU.]b\ؑ`1DIP`A#(+ 4I#^zqK?^' RQ1:OhsY] f PH羯8k\T&1B2.E %+_R8^J H %mOb#C;O.<#?ڳz+gqҟhauݤsC `YE` w>kmʃseW4L3W":XBXP*εEC^[㴭B:\kssjYJNb~-1[@P@a1"LN"| ̓@UgXj:"(,y`i% /[@Aqs鎠  Lde¶61n Xp- +/9wۍP1&%AnW0vz~ Vrw/\pI2"ڭEX/ Jq>59:v'Y{ջi-5埇q? j~LB0 cu*ByD{#6_g .]kp!/ is6)ĕ8Q/>M37A,Irz/KǠ%Bhf#:8MLoܤzV5eOd]7u]<˷| E_g$"\N2SN>RtDp@Yjݽxa&WLvJA|j6-+ R5)7-X}@<܃]8Px'i=,D/l ?KS7IeG]|1Pu B."^4s |1b[ɐ"å;=f ib>{6 RnJOd3ƕH}*>[G{Uɚ٠8DaFtw_},6zB ƷJ'jAduo:2"0e6ϽCoPR߫[VKQD償Ψg r+ܮKˎb#<9f9w}.z?ۙp^NԳڝpݐB{y Yt6 ,2Xڢ lSc>m9/yyq0}nLdgF˧;v0e,88`.J˺|:Ka# ]QYtqⱊd&fR. VԌvNJ6‰65fuY whNg,tKn_9H>MR.VOe b=ݒ/bw`ͬst/=/2` Jӿr*&Ùi-Lъ*Zn0 Pl(2՟՗9'˓g UR-K,~7"|CizJ/tX^.!8FF c2I6]H_/0=wt]8Y5lػ2uyP`A29'?À韌߬b+X0 7vKBPͼF3W p 0R@ߖXti\{Yo'܊<رV \-)@m߼!DV(>:wP\\g$LOde1$۠{_G<YX6t$YwΧg,/86+_g]k Jzp!sAP'*@8*6 ܞ]&t7sȢJF7 ,2XwTUr"qʿpAcҠ'Z>c4[;g9iT>Hݲc*M!ިҩ_L<7kUrEB#U }^زwx%bcP?fܓ "4&X"/ |31kK[چL/8[\?t*[I,fC |^ښ; 0:]~ċva[-! !T3iը@;\2eZ]sG|EBuH[IeLw1µ2:Ǜ,|띭؋ʲk1X#b]mǿo)k/ ~.{6'3j3"jT$''Z.c QimGjVŁnqMw<,qM#r!Rth2eK(rrf#YmI'5- u4]28qM޹K-5m($k:2颰̙M/=70NG\nXZ̒%@8qn(ր6m19RA6iW.S , Bb-%, `tZCv4A Jg(i kи(B4t|$Y26,S#@eb \fd|G&ߺ Bؿ i:%}&ۏ1k9j!;hGB;m~ɄĽ;vӂ.=^͆<4ZE '-AeiR4œ }X9}`[x!z2;ڤ  +[ug& }XQh* 69hk U4R9I.@ӑX`i:pzO{X=! R|eh uǷS_p( I:ըv))yk"ԑ/Ӏnvt>FB>,ƭx9EM 'sjA:~\/eV'QQSO׹)_t:\\9$+Mж-Ԉt;l2NQYv2'':ZPv`WW;a= +~7k<6.uעȯÅމf[{t2]|~MљakFÄ&6ziۮN$7 ,28B%:XU,;d:ߪ !L~DS.{}~q-S.N x!Yv/L(LHOS]KakBNRh`)-Oh ; Bbq61^?" ,}oyC.e }+>k-4@#qLE-\CkwlhCca? sQҽAnXEczu5O㹉St4O.e?7_|h4_F`UUξK\3Uwdn%>7I, ,Pwkєʬ6fq&v7yMױQ lՅ.s qe A=|]3^PqsO`a^0FmሔebAr8rMSA㋾v2;+)(&*"Ae3P>xosP/c^5_ iQf敃I ,y{" \/ސ4@i'F#py44,!ޚ \.UZ !K6(#"vru&ɝ@|E~lTI )QGĻ.p;c}߹ãzkĕOŒ~)\)^HcPoLXIIM(ж9"˫{xNC.bf<$08gYyI " DcTWwrajUwp[89}?{yv|)Sƭem ;쵱q^:X &4MwaE./FmQvII-΢B&&$nq>rp[ĕnhu ֺ-*Ǔh& Ջ+,d9c>#6 3Ӿ̆8jiE1%DJ0jw>ri& D:yH8d$rЇ%[ՙ]ѽUMU!pr9jlGlJ!B:Xgᡈ"c>sqld$Jx+=)`Ny74[a>e_l};!KY7kmMh0,8sI`$:/r,+JDCz:R08ne$>o? "MO@&<<&H(;?SHU_.cqz'*;qq֨di#T{2^7~:b6[Pe>M8+(;#N^bgZc`kmmĕ]h\"۽}BEׁˮQcF#z{da[*,2Hv09c>kP F>'+O%RI.T]L7 ېG)Z0+?W !!܉MQ֬lhC^LXJ~ƒ,xFHkG\;mOR@IL VpsDq.`CXu坰(^CR#5JYA&B;3T"1]:U$u;['w|ҁZE ZUrs*㓳 Y~M ݱPVL!;5޽5\dP䳹gkQI%bKܺY< "}*L:K_Ȏ[w@9iٶB nBϵ69 Ε{N܈n6Z v48g{^`6*`P;aևNFideM&$.ܶuUۄك^t(5 aN|vuʖ8(}I1~q!x wNbTc!IkS}2kJWdXw@:%J@]ƠB¯YV "+ՖXLp|(ֺT; "(K*W (}ۋ-7/fz~OtÉAl `A"kRl[kH͗MPdEC$sORIuΘ۞AUHc:'m =sg:n#;E(Z4\tJ&$B |}$BIC9tqc}!]% ZhZ;ALN~[;%pzYE~FbAdu{|`͇!B2(Bӫ}Q|,6Ԋ(KŨr"Xh8-"->n Ύc%1d |0VS|6sA)R]- "*+/BkMa&eSERн~-0Hb(mk|.ըJ/dS_g.q6,}B_ş% TMCYm{vo6&, >/U1LE^Pg 'KǕ\2W[o^ʅtM L:\>.o|zŒPO/iLH!?\Ϲ۷?U[Ȥu-W[W 4m埇_]e{Mv9PXdt"#+y!3ܤgU.ɶ@ :i5dOƴ#7S%" fP>y@`mڞ""+-=? nYkF`m@Z}xo)奔PiXwo$H_ NY ^@kafߞk[(RݱKa ,|ԟp51 i!t\b2>7e q6ǐJh ^W룲R[/!]z|VyQz %L '~"VƀYv˻n @Nvs,Tf2O #>|۠P`ABC}>ˊFA2 LYrPuH=[F]y y,).@(iƘ(AU1x"裃RlJJ4Gɱq`Uq"E }xy& t.:BЪcnEs gRHbWh%pktlkE$ADЏn1B3+,xIuprgG'|~L&k5DX*]#@h$I}VP*mäkāB<<}1O4¶%m )\ '9Xs`PUeڗiJ/,Ik%1mJ)%~qIAK3e XB{-B'Lӵs|,k-Ƣum4.9p%h ͂H/ Ekp'3+?+͐ .0~K q> -NFy(pH5btk%wl;;ߘ͚wT(``Wd8DG>>H! ,qIY -Ά8 6tGl js5Vg+вum}20!M!;[pҀY_ ܜ%pbf#;kfm_{o*]&ܾw Fpzt/5X|50f#2$}Q&:-qvTtCW=YW71xO'Oˎ [-ԶY.rյEvAk"3+01t/?B"̨s>MKaկōj0>A8얅0^0b"g cp-'sL{sτqt6.scsC_Fd,b+sE&$1JDܣs:BYfS Q3یӷY b8΢Cs*fԅ,:X'_Ƨ.?;w)==鲔4xmʟ[~no;«4Onw]\EëAkD/@i%U.Hr![u?EXLKX\W5sb *W&i$p'OF6HLM 0ܾ Tm\.5}b/! y%cU|Mk BXvZ_j >?*%%X1Q*<rķ'wwΛ)R*9Ǯp9FP5!7)Kֺ,;W~gid/[3G(9B^9׈Kj 4[FIT'?oyq!,Œ;ϱi&XX"|reUIy $O@ow$Cb-R*ǝ Q+ϿB'TiY%I5 -y6ni/Ya8~:3$raf=L{6EWHnOϪ'd]+i]F#RpyE\qX&i&Nb8, Y"P흧C}ޞ Y/s&2m $:kw޽0I.3qOH!Pc/)kA}ɿgd'ß)q}`T`aQZff,L&"֯:Ž0DP`A09#j\V"^ouȍX/ >E~im@g$VU F0yG .Χ8}CM$f3_9 \/"3 D EUs0 Ε"zN6+:+銀("+xkyWΝB,4'w4MK:Y.79FV\?~WuyXPFrv| ]W&:U)i'K,x\FCock1,P**N_ۘb,[kfo`T(ڙMrcT^{4?C`^\y:I7E]1Œ{_J"t5R1B/YЦ:[FƉ2DD ow2QU?/|%o]uBȝ,`ŐX\~nEPBx8~D:_*{fْ:lxͿh 1PmJtT%\ $ؔ~令ScvFW_-afVE(Q`R8ЁB@KaZb(Ady-e'3ULՊȨ2*O6%(''C=&mkc2y{=76?t^.pr.nU `>w!Jz$B#QBw#9P o*3PJ@R2 #Tٕ\0ʔZQg ta}f9\⁺{5MM$eRRZl3qW"#u1*xo+av圞={(%Eu죉u9^JzUXb\1RV5AhzBMα!qf`(7)רh 16hU),FnI@,lYspt*NR,V3H j)Ȳ_T@8Ξ>|#ΌUU5Xy3!P\eR +-+q=q2l#6 S@ $VN!$u j`!t`½?~i}_Aj*뎮 :u_: $C߶b_?R4ݾ4+iB=sJ.@9<5F ƀI,6T":&`yt$̥dŽvZ&SWIxrJw}]|l^LLM^غTPԄ*GL)sXt _QxW5^0֠[Y, k)(8zFĶk$sIe7Pگ/YR%6uA!™qع,2[^H9R 0ιR[]d6hșGDR1"{4cS)l \ڟyإItlAy`A{Ey6NͰ:v`O+f5R_MP ]ɍ#ڳ^4@ tt?3 Vlun2=ʒdd~+2N܌ cu|LFj5ߏ=a>sf-.çfVA3cvww}<<^`LLcؗ,^\?b0] JW,5f(lak {o c$]ʠIRq&nP gs6ws )h Kk[a{_nޗQ yc;ߏ&DGJxTK>LiVmr1&U^jYUem])ǁbLx/s&:\̹/e\^9c l3Jv b")M;ѻ#vkKL*"%U|U dRG8:H3d6j}͚@.bY|C{oRjp=[diƎU $Y+]ܺs{(C-V>.ᱰAhxB6L 7K|Z4F͍:\.ēk3!2 3;65O>b!N)\8qCrdpol5cBg?uot;MqB'd1-9gWM6 đs`SC/PB?eWP:F? р-0w.3;bv U."ѵC_,]2{l-C]!f3¬Q3"<:;icmJҹqi|G·Vm`7 _4ܴ̕*qڠ OenZepmvI.Zɨ`,$yWv].>,:=7._CnV#pV׶%zp9aZ$yk W`xo5ˇ1#<$E0^(cw'm5t`x Ę IDATsԊ؅昋kZapġZDϛ'oB^W2S!n+O^Iz0<*V%2!QN{듥4 ;'yD܀;2XB1}`Q8lfn6`U1'aJƵ}ͨ O> =(A'ɝ佰e`]t}~?G=7d M穥Gs,BX$KOwLc]|lay5-CEQX,fՒ{]M'9cr/9׆O=e:KPu oR@#R/AGr\`ݠ S)EW4H"ԉ4^+n|q"L(,ưIƛ̎1qnk EYK  E~6BSjX%0[%[bФ,Ie+Xoh\+ҙ<6X[,y)!mLbQ@)(%8eV}gQ>E/2#D%+lZD.̙GsLXowLrI%˜^^+lF0]?ep4Y4<Q ?$'ٔ^^30v^_F8ât _y=>)hXմMstSڇp`ɱXx*Y*w.Do j i#ճ&|dW8hatA"Q VrO--`VeU"cf; {a͛x42p1-{4O^c^X$+P8B<5R]-&2".bB}zOH@JW#]9y.[pf8ȌarR]gRcT37]Ut}/pgd|l45+eVjJ$qh.,ʝ @ٱXXb~7uW'Gky^iK僔,q,,jcr&˺54 p| RJcl=+F"B iޚ-ڢj^R|I߲|ͯ&c?.\|tѲdm1,ʼNO<hXգbD2/8r)Pny⚪6P׀K& V)|xC4O-!d\V" cX)2pU{]c'c am@بDϒ/ɭX_$A ƆJo]Y1gJ1 *(Qqh/Ba`0pjc)ݦ+4}u`c OL$zh|?O :Q#"OΌ$``Ze|J+nٙdbEzR dST(q? ?fl-XGtaÐ\"#]zrymFՃkikH*VV(qpGOrqA2+ (fHrXUFUϜYVP8d0?UfڪݮP< >ws-rd7AY.aIΠu^ZGmHjƆjF뀹وO+֋ӹ*,mQ@sPeacNfIs\E0&H**]|l1_`ytF];@ "ʋ%GP@0vnW lVQy/}~MI-RjHKezmE ~_^7ř5.[j{̆*! >چ"(-^$-ؔx ^Q߄TSP;` FP0*0d1AI%/Sꠉ@} ٪R ka)ޞhso0=͸ASr1àGDw_|rƓQ ji+>gQNXEH8>f o[N? پHI!NCb,!f67w㿝cg2z`c kC.b$zE\߂,[ G n֌-őJA% ټ~dcO>SB f!l-!QButPafPosO ?*c׾j^P(" LS5ʇSH !chE_vRd.N`U w^wʾֹj6 `Kola[ l+kJYWTAԎ|bZhi5j=@]ta Qa0<=-k:]p.Iw@z_-"b@s:vx#ΊE;5 O$3ZR9> +."!z("RDBY )ק|;Y yH˘.N.VPIlApshf iqܙ%붔( A|+mCA>ub _' ))|xՊ~1qL䒡#X(*7cO2Ye突6{.VRR QJƓ^W`NU3W^%X"pf|S:vv>en˓4GfsΐFc^.߽d'+g`صx \#.22x2se|KnΑ0[KV۟ `AsF2d (ԯr”ʼnɢ* k@WQأ `f\;~ PpBT U7Kab]Gj X"2Y>wO!4dұTx7*kՖ ^6S&" }ćW^М<}׮P BaUg+0PeirT T*ģ rEޞgkN$8Ir?p@ࠏQ6ǀZUg"~=ZJA%9N\9b`rocdzXz-$RO{s]Rgū_ٮ'8SP-ڤ^C|6_>nԁ(K\6A0 CZnO#"5 KY5K}3c2.#$k[&%S'x ԋ94#RQ|Ƈ}>J:7@E [ |XŹDŽ}#.@RpY-2 P˓m:0^zetn͘'YE|PV@2ܰ切6ul̔ט,q߲0.m#aaZ;Ih?- [ؚZ~9L[;/Ş̹Z〦;$'vk^Xd@ج,E<]>׬VٷX@'`PҰVmRZϚ&)_dMfǨ 0l\cegA]m߶23F!idݸb# HMd {{dl1?y_#膛CL[g¨E] "*߭יqpnK͗_-rY ẅʤv B=6RY_Pec9 ҃/CP$!/Cg d~D)#Hdo5tz ͫ12baˍ,p3<>&?9;&xZ-\rn#nߤR WcŻ?~i MlhEdf lD asgGz8`|?ao3EHS0WM|Kb8V뀾q J;NŭH3aY/q| ;lz9KO t>kx TvYßD B`(Q[d!՟i)Pg4h[) ux,bO҆.8阤ng('sP?*d |L ; !C#Aα?_σr#54]3k?IַQI͕M*S@ 3<+jTǞΠ1FEH =>y>VΊ?fڶ,=,a irvJc32jQD(唏0El)YURƱ=_L){˿;bvqKŷy&9T6+AA]w,QiZ ~"-f&b\)5,. r'?Ҭe#v~ZyJdpqo |6iLe#"zd< D!F(d!d|u{qtstFisJN*{2f IDATaه5iHU,= KgbyS$[f[9SS>3 x **c]en3^}s?Ϳ+ݒV erasV9B 2K99G?|-ytFBؙ04o 3a촊(Y$ܾ!kt:vծ-FP0AX/,j;1,AA}鷦N(#az)O*o#f1dx0&C \0!sB/IQǘCH+&X>Kf5IĘ䱴Sq&D"k{UQ[-y7 Ej |o})͑*4b*@rɠD@}87Wa`TM@NOad0 )ۼ1*]CL oUc@e^_N ѷ `1SG]:mC qVnB(* {sPZ)`(f~[D*d^^p!,]@צE>x8ʱKpbvqk#_$YKF-A=I"a RH1l͆Q]|`L!$&t]<%RFuSo) "O?{ (0fҤ8j%W|0aNɣ=cw\(Q86rV6H躽&qU0}m_jN }?zu5ܹ-pհV.2cW7%,ed#Y<|0Uzi4Wp [,N]d?5%^=\"rt)Α\;(E rNW +\ŋm:F[ 8d2rв`m1`#M^X{kfhbvq?se2"Wj7 Q]MP*FxA]@Bm2-@텘6sPB3ʍWvhrxJhHB= f{4#kxʷⰈe5&| }h-je#:9ғ}UsD r"g{/#%iVcsem+kEmgA7GJ&IҷV0bɘ"+a78*+rOnNo\J\ߋ; p|B`??_~wɺ&j$ggBi5ڀ$ gQWV(vȆMrΚ`%(]"Ph81$*i^\ +v&wW.nPiL`0CYy6m@4b#Jl@SAX1#vQ`eMb㾋@^~} ׶=cXDQ+$IPFYg*a t0lK~^W*>e "zP5 'POO%i4J)CcG |+?zeh.Aq@جFЁBAXt(Q(\!j.Pܛ CP uHK~ hAT5ƫ h.]W62>Zg}WA*#H!fs5+_\(R8uhج2Rc"!D1aF*RdP*OetXWh){Ae r.ͫ-M,@#vUzBhk'<1rV+4GU@%`>v|0J^4aďZ60ɇ#A(`Zׂ\sh*yGd3Ps]Ǻ;:@P| z%a?OBɷ\G<508"N}rq|"?7keZEX_V:qIh;ZQ bQN%þpsrH>M`ʪ& Q[yGc*X ͆XIsßQm^>SK6՞hG88gn;BYS%qz|:hR6n&ELH3hHsV㷫JK BHx@p+X0W`̬g R8fVE) iR!M~.ivq"f}׷ό>xZ2RKKFE~;`X2͈K\F3W;f2oy.]b 34F%Kp/M - ,ZD >9&Ra2ZŨ2m }GGi{9l#G1NTI"gTWA]8c0fCV!ۈjN(COC6ˣmn1&"䆉2fV*(m?c ͘9kۀe}ڎgпڞG~ZQ(1XwG$]raAmX0Y[xUQ]9;z:zC/ lrY}{{Rͷ^q??WM"9^L.G^ 4CL3Ï:`4jΫ}Q0 redZ*N涊FR\Th\ !2 զs[C&ڇP@ VU;Y@(jlʃ) p"OWBt͢QE6j/R(iX]45'[n ~z.| {j]v]ėk/}1//,}y2-ŝ;[,/JfAQMBUSCWr|iJCA+s.fp0$B`k,E $急J~?g uJ6k%a/o7lE4`U]?x ,u t]GJ%I>| lcg0PQe~3wKmPeW&2 #C檿X^ZRbe7fxr9^sP?~*{ 8>8"?o-BpR XEޮApYm.S#Y aP:+ZƔWI%1II醍. >_ g’1Xyx_B oureOCc::ծcQY/pۧ3Q_#r;.^$+n9;8YUV?Qpgcrt`,U# KXO9O|&-p1e DTseoeK)%i:wOO dv},1EJ3Tb9GhYY,I.B:I(k>$뭲X l_sQ&2KkyZsiSqw/m+]r'Aƅ"!A>SsXW rW 5 r^{ !\Cg;5ETu7(c~ r&ˈt&Z*ѧw1cc_bv~r^o ,7EvEٛ yZ\-F='e+R"771Bxqф4oeb*^ h ]pfq/\%Ybh`VOnZzc0f $VūR[.mo@3l%W9ؗ_6^Z ם(3$gbYq\_xY0Yo(2ѩ=ail\dhl 6ڲ8>@tߚC<)N5m&${2hbܧ1$Xl] vnQuwפ[=0pxiNa{>EA2ep58F٫ r)lfS0 :"ҽN_|fl gړO@<`▍~ xᏥ<^}3l]UDy_鲃-YRH);皕+(aÚZX*&'׫*mV?64 l$fv5( TMu` %o'-O" #c-T33rR DS²B Zxb,te E^>nNe$pAs ] X& FMw~X,=^.ޕDY 7INH3b_J,4XuZ{ .dMO,hp R#Bx׎d{/~)flZ2JȠ2Xb0N0 UD.b @R}7^Tfm[jҲgǵؓ$JzkBA7VZAc1X_T> 38XO=%Y}/JiKO6I%17V8Q {sr3sl^/=SM^fFoٳXk-~n\)qKwX/&?cy՞ `g B^m }B`qaK:ժCo-~py%sMݬ360 6'Ac$~5.l9U-CN==Xsm~&VLF]qtD8]:=AB"XIE+_Nآ>2a[f?j+v췣aIR_?,٩9)싖(DXȪ!}⪞Ne!vLX]\o JiQ͇KU%,p\:+ߜ \lAgѲh j2ΜI|St*U:V*GX:so{\UP^W-̺`>RyO~z47R05 +snvap|, ý#oYhU_o~m Xumܜ9 3a^c_zLF]#Xz)nקKFփo+c*` _YϘֿ8~}y78$,4IrT-~n^א8fqʾhB+ T41NZQM)4x~:20W?D:dmXH~x! Dԣ" κSi *QHSbX>]'G{xџmN)9Ú$ek6_&# X,dޞ9l)%=[ӵҺT6k1êhuZQq5 8S9dϝyb* 0LurQB IDAT`Lff39_BXCTY'<:KBK]*@{b $́,nʩkc@E)/+:Zi?@Qc1*͐ D'U|~rI$yrLvvk$.ur89)nu{Ǭv5$\>_@UNȫ9O&gfR?އO&y. ҂OnO7Z$ 8dЙ@F\8vy_-fxCc$礔LT{pPh/Di`c]Wo9ӿ!+sy@e=D::2,G,G&Y+gs[%K~7Y A*Qs(僂NP4ON/tV[7v ;[6H>jYLfjviEpVxWP`M+ٙZZ:edJcFj(SBEι|uے"suD*|Ѳa3ऩ #Hf#T&z& ^yAeVf>Ꞷ05>>BJ <ȗhhO='yZt:fΑaV6!CB b 7w-O=*Y6! F$* 3`u8{Vn]/`@W򛕭pR0 sk'$R챷%,{5pPUXݯob*ۖLSA#B͉K)=Z56] 7T1_6>>flv2z#Vj^Z-jI6.Pɜ $9jIbIE#SG$=^|[JAc"HRN\ g^̭0ٮzk5E.g,zq$o-/ R"t 89ھ(bWEx`▌-wtQ !#;請zST#S `Jpx(Tב'yY7pS<Lc_'&-I|:}Cʸn(gKDfޖ^I󨕷a8 GvVd=b|v ;]ܒV J( j/\pɚ@9HV%Wy2>Ý^ @en!#! T*@BTIc:``ptt&zb0yAA2FHDfv{ {VXke&*{~gU:w30hS&,N҃L턽1yyuh!*"rsLK;PȇWK_oԗ&ؐEdmaq1Th1bbFv0ۢqT,0ϝ+k30`!"wcEڂ`(sXXľg { &Km]7u=ke5N_B.gT֦d&Mq5{Ioj_Ryaf$nZ#\t.:vMM ^Pa'QRB>҅<-Ssh .VT/,QaG:`p/r)u`5£?H?DY#eAX>D햰27X9msZNفCRGN{P& 8w= Gx/9k$`0Wܜph6UoR6/4%CB(ڎ7 =ncqHEV9?x^^HdAɜ9FpfǑsbnXTO. ^Qe! X<p|(.n7f|{ǫGQ$&N" Ud?k:tTHJ,.UrAE.peQG ׯ>aC9w*Ǽywb%VMVmXYbGMsV (UXGX8w ]yyl*>͙=)Ox91>$l@qJ?j&4!3%r@f#Y4U6(vstZt(p蚉@ k=I;9#<剟?w,Č9ai{rB|9`,/q1ØtJo ǒm06oiKkX7@h-'bv tx Ǫ԰8umKBNܱ0=$N1-[ф K,opj\XD"Tز:8sջ ?'Hn/L[9tSME7[v<+kr6vᩞBóG{S G,&g!nhd@EeA'y2$U;{1pSRW6:$SMQsbהK,ʹPir*2baUK6¼B mCUѻfZB0L+}b. nmT' < %Lc!3hnY腨rUK( ۳\ʈe_8&`%F*+ e\^/X ] IX.Oུ 2PԷ^0lCe5$V RBŜmW49ICJ %aѓ~9qY6G$6pfJvMKvQEr)[e!Ex2y@ {Xb5RR*l\V1ObtI+e Q4_q1lTMEͼUK5RaH1 a>{f̖E &iv5XGk8ڏx}_{i~*RVS( 18!X*,N8?O~.)qS iHI&4%{0miFs66MYa[+gz݌ G_PM?^), ڇ\qLX,DwDLE^G^d}cpz4RӈԊ,N[#2Ҷ&l,>]1N%;MRm3vیVҹ]Lc.l#h2?)73fmbieѴtn$^8o8CܼA~`.[m=ʆS,kR}KܒZ.N &8r(?j5J>Ʊ1 a~ԝ:b St9\AJRըXHEHۅ)nsfΕ),@68Qu=͆on8EYǁsluF-TMeayA#v;5>Y2zLȮbY'y欖@8\"Y:LS >՗%Xm+˺{~MaWPE%][Z#W&Տ/쉈qB=PW%^dg. ݢ~1`;W1cT- `PE18m^ܮWnfR''274En2uߞqH jd$^XgwcHR+G.T ,ر7'DھcKMHRY5ѕhur~3 H$i` !Vzy_љmØ+B0ߴllbRX3NO=NO)h9 ^Ok.͑ho"(Fq'PI=^uĄ1;b/ Rjd*.|+oɲ6fDrjgWm[՚qrBX.4Io@(xz2qa3 QVK$G.m`6%";t`b "xY{%挤&5g8-A;M ;Y f8023(9Q-RP*TNٷƧ^un\r'1DLjw; 8.8o8Cܴԛ`( jԴ&8X3y%,1f8!y 4Kv]m2 _Qo#Nג+V!t2u8%Q:O;~g$&望_#+W)jX3^AU/T7,A )ͱ4kiG#,kt }_ ?Njy*0sxrHi!۫23ÙIǕ]+s༘VGۭhX5p@)5[Ű!gF߭Dᕰj%Yn\GmXai,%m#. ˪#wXX?@i^yNI:;[˓Ix]멬a a gz]u3yVuztYsR}'Wl}W97=`⦎<\`-=fU_.A ]ĹeSG眘m:/F҈|aEaf̀a% BJTj kJJzyW&\en \"U MAz:=_tڪF$d#̰~|TR#ׯa:j4DRK3tau]Bă,Ҙo2eT%Y"~esĖ:7i*K!Nb`I3 ,ly* ;E r$,GφYRಖdmv$ d%%+M mw2,&b<#? lG(k IDAT#S|ko ZJ.%n  7;!wujL1N.jI*/)A#a_a#`ÏfSz#H=j)LHm;O 6;𸧡r뎔k8#}TG:MAk!s2M!H̒@qØ%r툴T"զUTav< 9I-);;d~an-憳e3uL qdu2]BE[c!=;4t ¥H@IشRYgLi5V3 2p| CޟzT@ z"t ;)q^Uj#X٨ Ul*4+ HH@q@/~DʸgcM X9^lrnQ=&[Q23M&h xc?=`\VZiaXui(_-^\ދsp&SV͘y,?A 6K VJ 9ݚ+դ˥T0$}\xO0T 8VR\`!w4P#(t P~~^sjfC3"ksW[,zirn{@dLSQ QT=#7T$z;Na^;OvM Is|Jgijh&JFdVI;KgctLqlW`*!;?!F!$0:@08ݨ01NppyلAVm֘Kerk1X_3x Co@8)4GIמXM<W"ҳE0)[\eRcdk*%?Ӕ1^<+#,2׮eTS ,yHGկ} ]zӪW4 ?ڙ񩎑x5z wk3eicWD}{lwlH@d@e&o!nHQJؽw#`wID7)rs?~l! ?ß?*""@) dԔ+iD:ʋ 'x#'')LrQ0 ~}y L$VQ%H\-5I Lx4NI`{3; %W$)<̷ˆY[՟amKeptYHB!:&^z@>DN+\@)Gg\mw`FF)\\7TR68$ {#\X`cp]}'`nk^FyqH\MɕT2+1I ~eD!N^KKlD>~#~5_ZE_KhȢDzYa"41cS-ꅁ4&ao}qKYxOOx~QX O/ cĮ0&:,{ `iEuv9l4S)WȺ9=ݻ$G$recq_3?V4hۨ:R, 1 =y{V Ƥ81R-~̀cknTFBEK2#,,pθrE5F^3#!q+O~<ŝ|> -3V$%/1c aLQ+DLbdZxO= .WAo"D'2wR*5\6G`Ia1!&B뵴 6T<[{X%cxp| l.h>ߌ/!ULGI*kE $2j _@ξ\8ȸ2BuqY$uuHAu`a 6Y@Hf;&,sOjz* &m]?_r.z,8gTJ9  L*jrWThy/WRUpeW `-XqWo!KD FMCZY6 & {Yiڜn A~`&%\ah+D`Η*9b9ɣxz,ǥO-}pl|ɘW_LhǂIqN`gE IYۄݻ푞T%K&1ңݟou*iX]9XNOgl !">ߌx͗ԋ( @,: c-]iʘ&mځʺ12<\6;Cu[*Rz񮷾r%պflts dBl[&ș!j-TtD G܋_w~_4ds ^ #y (iAVȿ|oxH*>e"pAzfWW@e$ĥѲS{moz !4HL[!a8bB`yL{-jd7}*)is'cq|t7n j-||cOP;N\f*cA]=(cH:[hڕg}IS!ea:a.gàUs=Rƒ7\ $ǔu*h5t%.)*B[ =x>pʫsS4\8;{ >' :197s#?*u[*6uMt8dm'0.^#dZ ()28YLN=>h8 Aēk [{Paf [ᝨT&*1:U{1PMP͈qPT1h(:"GRqՏ+!s(MSw>a"66agt^4XӔX[%_;2F.1Ѽ~ /P!)j U4E~vsכG-{uD?HMlwkre!kͼM|4LAۀk"_v="'"iì^orwX'`hUvKh掏;$@{ZVw?.Q%҄Wߍvipr|7n[WѯGctKȁ4jtrL8[bbĘX8c~I}K99"9N qvjuŻb?խUl6KA ${2O@$ pڴiʔ΢qvTעKU9F^Bݜ%Mf=,h^~Wbl=]0m0WejQkea6E3SmSzXRMruwa:Q&csQi-La ͮYY)e9KeeP0 6]&c"Aa/R@ 0j. 0o:l&jަlsnjt:R4EКAÔt۽9W*R*qpZkP.b* x~E3cf [V{h)6uM3^}ߨ'}%^fYsk_û=sVI f*Fc;_;b5%yeDoCܲ=7҅wkeQ*/DU@3Oߗ!<(zKg?}Ûe*C$+w<^/@x h0FYȚRg7ה1""\˓R@p} (w>63G9Z5?N̪JɼT })xsGampwScqxaw66M9_E mf]2Dcl!@6_#DH &X^ @}1cb nF:=BF3X=Ԙ QQr. V~UHW,z͉7vabji2ZTdX.OJr,_~qjDwz-G:0X[!nH} -,ymb*Z~k6Xk9ydrPc#sC@f)U`b>Rs\&_nof1u;k47U|¨ ;y82@1<~٤-pEz:`9%my"NIJJ-iYtb1/OʧGt*qζ 2=^.-+舰Zwo/}mQ+7N+z,G%~%:~i3чy籛ޭns,;+˸)PjPxK#g= gqO1`atușba^O]mZsF1IB=lsh5 wտ83[qEY*:b_~3.=n̤b޺~ r@&IڭΩ Ӎo.A` hL\]RUY(mF\_LO{xW\՛-qzR A ccN)C@ړ/IY#aJz\OVʵF ;G ` LPk*|*~Or>Gkpr ,'QR.{翇W~'~ؘVN@ۨ;cs*NN] /ɵdqIFqfFSQtu# :xt~|bHQ)f,W>0J[!Rz|vW}?fBDm%ܩO]F_c] q8u[.Rb+? sRD"qO0aEWPXTn.8J)#+Td_+3> ~EFw5 2e@iM7gSvLtZG!qӳGe^Ze@Iq䀉}}<;Y[xjF*@iit㾗~o gDmX9WϧzYl2.cƕ3YIzZLc8Xo8!&󘆀 E [*a3݉p;R'1ßo@5sA"ȑClٻ$s\., .6{nz1>b2$;d~Kӧ el$ׄ9o;w&įQb7Wkw!{o ,Pfav̩-*kQBL\9w`ctލ0)IIFטNm Y JڪƋMM8;%th6ݍkVk:!=PEx[.̪*-$QV}fdU`[կ$}NN1’# )5knr{>S쩦B 0  "12Mq \z^i 8m؏;3)IZt_1XeE}/<'J: ՐI|B )-@P]>"d73QK5 X]'~O{19[=/ϯ2#/"`n9i߀`ѬflW1{}?;/R0ѰCr, !:'(Z SJk"^ ^|L15kUZq8״xNַede^NN]wwIG@xKcpvۃl+k߄LUtCM<y0(X&}E= I-iA礹3T?Ϟ^@V=j7X,{<ŀ{}5ס4mX 7sTMZu;x/2CkA{,\!ecR#\UӍ :Z iVﳞ2Aÿ|ͷq(I[iInfm\ 9WY3a-#( gگPWWu-rfu#5b IDATVT^h%I]K˾h :B. @>y$D#|ȘBF<ί 9zu^;QR"!N.UE@9(s)NgQ:̫1>A4G=kKkf /yW ? eFJbYszV@ps(oeo7Pp-c>{9Q.2sΚ33؀賈<\HZؿO规 ,7g*)^̱po26)޻f}C%^7loC (&׌JKRBY2KlG]ၓ_;)CrQ[R8mJH^vAvM/I;өU1l~4)Ma`U]619c-TRjՈ̈́~*W4EM-ʺoAT!ߪhMަɳXr \VYGƢ{Œ\]??q0` y5JU`&TL BIgX< q.IK-SjPLCa`r1L ( & `X,=8wxO|E"B,.V(1:EkE)i}2&XHdiTZpH ~ 4QNiKX {R'La{{0)9HX$6 ^(p}}-&eހ9\r[Cg }l*A7^h[9֓|$IC LX'xe XʅCiI]֊WJz!в OLDb Hb!z9f`c}䡌Rq#!:-)~E<%ů(ɵ&}'́l))9ܤ<NzٹA- w'Rk5Ohˤ0'"t ס2Q/"6v@_/眀Ac6*l]cF4X-kGrGLA'MC 㮴Ii| fMIR\t3;* SO1 q$l6@1&D1`}BʚR lPW}?*#kZec[X \ +s8;8;c,،##A+;s@me 5d @n\.莰u+xmKtR{^iw(zD$_@H+GJr0Yқ1f㑒j%ats?u`n8Cܺrzj<ڲ/N2)'@+۹NRj648 Ozc2 T،>bN(P`Ft=y19e΀`n2ƛ/rX\$7 oiϾw_|cR,ssB $u%0a lc1:`~O @\Cu[.R$<e^Pe*aRSRFĺ^^6|CDZN],x3wDi6fx/-kW؀Cp+¤gO"xוJ.磺'xV#J@Y>} hLA@^@ҧA+Jb~wM%ހHe5Fj,^yiBr jG0M }ߡW0@ cn!㒲>klRԶ4V=A%h p"g827Gk/]j!&lV!i=Zwu xieWe_.֋QI48WxQzL *(ǹydt:H~zHF *CraZVWA6iT Hql~"{La{\x+^Uie균A@{ќ\+j]ݫ!jl*鴂r\iV+nU풖k^xKjKÀQ8MB!L;Ӹvj~'7՛O2.lF5S[5n'0:Κ2OIR1LaDa0MiB|0Հݎ1Lk?P `4z[Ɓ:-"rCȇ+{o[MS&KR:0#d4/AbU#)Ie0;drzlT1'xñZ^hR´KfQѩ+bu_/Ͽa{rIn6lX8+H+;?`00'A۔cDQzJF@(A\;e*ȹ/=Es9|p)y}QCc " 7IN 4\=R̈1avX,W& XoďP1l&.%yl!*ئ[Uf)ZZ_?m  LLՉiꐼGfM!׮ -ZTsT4>B`Rc!nQ2 h~vvdf??ρ6[؆l>QZ=fdEw Hjy݉A( < r~{6/ÿz7I?D 8'Dտ 胜)0I~n)@o0/2RJs&ܴa7Ƽ2Jʎ ѯ־I+h0$Q /׶Kސ<8GGv됲C; jn9R? ČaGκ"\ KhS,#$[?c6G}JoW,"R-GXDWG̀X4\TQh\q<\(9Rg乳Aᙟxk碄\ۿ9K` '8؉t6 ju!;lz`?,I 9)a+ئnY=yDeI-O.k|uX-ܚ K \VHrZX9R# "1g#XEAΡVpawyVBFJ vI8BJLOWSLi7P`?{L5MKG- jҏXA(!͝KX%@LcK P&Q֛H {`޿5=x_ݾqX"%3l|x4Xx2[Eƾ` Z"&3# {h0O/o5mTܧVvvnrZGGggWGGV`Q2UaI5YnbgR`K(W$)0N_?{o-[Vy~q7@ " *-d Zt B C&I` UU.籥k6eP`UҲzYU]]Z˩Hrxӝb:{2ߐg7q#Nč|ƿ^}H0WEd%=7/,C~燍O+_z9zh@o[Aը*P#tEE(HKb9~qjŧOYg+VXM U wCt ;-(ՒBD&+WZFe4<_ڛ%0V sa)r'чf:(BJ+r֯)ڐ{" Z$jesƽPPk:_%oE2H 5kin){0n 孿_;sQWjAgОShs F#=P!;x?_nH'q\3zkF,Hȃ6$ZafѹOZp(9XK*10^ @_쬅ѷ"ZgwԨ&c-o+BjT@J'堜S%}D-hvOQe>:ZC _ rc,J63.\EՆx OeSZ# ǎA Ec-;c|-,]6cR˜Z'1 REaA0iJ%p;X)Ʃ8AlSTտlVpO]`8؈4Gs*_} kOs Z::>5M;HSJ;H6jJT`|- /VU8dajźkŋ_?|5*3D:zUTPּ(7\KOtжODV]YVDQ,hh/ 1ʅSBH?h4Ұ.\l:g>z…Pҽ=h0&"LNo%5!e (FA/^L8Xk {mh V,Buv1%el:Kj\T>멄E]k‹Ɛ3j3:VBU˘ }b. PjQPyK9su*91Fk9,+;,>[W$VC糂֚r|ӞC ;y,H5sVU3вU+pZ 64%nQU6THvjfViIlZ-wj0B`0K!省u,Pb$7-ws՞bs:o/B4^x?fS5BzRN x3\@zV7L aϯLFeJXe2_jk F`zxEc&j6Dnʙ^hD5B=)Tl%PJQLt*tU߃k=>Ŧ"NJ.V6*~Y}쟯S6a*@.l5:Ÿar]2&l(W15C;.C> ZhM,32b>("~n{Y05&.b`ml34 n+h#vp`;97ExMuhҼ򭵆:j N=xTrOWh,7g9=XJ#UU -£ZXW2x064a 5U:qZva42:sM||[&E,9,`Z${TE@1OZOQ5"Jۢxm^rJiװ}Y.M7/,C1{~| +JAh <.e,EH+5 ?fL;\_أ5>0!ԯ 1B "I,a8Z$,hSԓhqbSGxg:\'Z-H2Vmتm[>s!B"XGPQj";/xMAOmȘ_ۧWQXZ R~c:c,|\@x\lX%\ 4 vk{XIS0?6w= ss0wO탉z^)k-v= mUP UCWb;\+'+)2S IDATlԺ3th]Ӎ4W@W%YXc20Wh'KX?`7HP(9l~9Y^wV/f0%I J)AP x~&|=;ªT Gp9ΡAӅs*sE>K(*RG9MdU(K: [[+rq"Uk埗zEJC^|.bWx>u|0kk:v:U{{~wb%ZSKFu=Tu 9DEu@(咢 23^|| "c]]T]%B^To ?WG!˦c{W{ptN¡`x ]hI*[^LI_Y1K*-Tj)gHЮ#152jȋ1oE1Yϼ@Ԭ^^Db48t#J,Ke(]ckx\5~nw8m `oVCP1E ItU66Hh)eulEV" C57ZڅZ[ WG 4Z8uE kp!"JX'yBfK+D"H?Jxz$4js^9ka\Ab2R-)QfT( ,J,ӲapjV--fq1tY뼠]6朁ꪈ= ͖eϵXyQ*`@C{tb6SR)-kIl.FWjGVs( ZRE8j`;b)v"JP(F^|X! 0`}z VIa(E) (H@/#{f¹8Kr>5< }/'ٚ3NC~(>B&G\)jCa_;ju5E _U,y^Pnؐ*ˋy /CU4JG>d#K/UCD#f¼tjP-4'(c3>"9N펯1Ξ"fY"+PdcM.e^w_PDjD_,e(GveIE>ƻ$r5&+{U=5>4eZO6y<0kdb0XK{B1b|p(p9XrmXaW>;:oX!7JhxeirZHx?4*:3*YRkPʆabe~ ~a4HR}1( _ >9\|?88F'n+'JH>ZiIFt-Hd&~JVhFXɒhN"$х>nb,?B>!u> ?@"R|"q*sONqX`1fLsRi%P m*Jw9$AAD#ada%5x].z>݉9X+!X-ȀE$T0Iza6x*Q*I2-{kvV&m$4@JJ@ ,RA$RIsYdj9R_%4~OJ`QU/tbXRCd)+N"+-:]^˳Ym yX#|+6,QW{Rab)a%ps~/h&ȶT/vцN-⺫|u@/ VH}]:DlR@b\@hѢ`SQW:NǢPR`>hE?bkHIi0tV6H~Rz*>T|ނxIH* ŠC#[nJ_gXUM%g(9b,(o5Sb>Әϫ 6Kn|Kp1U40_._'Ư']e^\مs9X_a4=to4vG7PW_ܛ0΢ C ^;zPZzXctmDq& HS P +[` ?O:lgm\>-A\*Ѹ<%'aK;V]YfQTW><רeUbg╞}U}|XB ^߳[a>/p&v,63CL0&DYFeo}p!/"+dEyA a VpΠo_l: 8XSx~&4հL6L e)E!00ZQhfk \0x |6{ov͊^8k-4b)~".dzjφHu=!U>ARdP%ZA&(w Qۆ,.cJ^Cf3P*'>Q,>Ae63 ,0?ExcHhΠBhdH&HpIX+\c4h=M-Ґ^Xd5OeW(Z>?c$ Y ol,>Pʋ?Q^dd\^$m]~jx&][~N-ք% Q:;_zTe*(Jcm@]˭ϺujBȆ`{s'̇]TpxlrgX̡Y,k{BY 1"  ce L>SW$)r46Q]_#xMћEӍgKj,Ėuۦ!p l.~_"aw@4me>XVĕsЯK鼬j9b.m fzVHRnrfshU Vl|mNօ8Zj $PRShU-0}YH& vJ s,& % E0+_ .k}(U5A' 0+#`4)V*0?Og >u9AQ@-DLaQU9^u֑iA$@:YL,.7)a#+>iX2/y̡*I wdҩ[\aZ$0E8>Aêr(OYLR h)!&JAZ%c.\ĕ|@5$(^L4zFlPz8tá[-H~9T~>ѾeQ$ia뮣* Z=Z=$IiFd %( ?sG_b) +!ԒB~{j\rXe9GTU'9aZupp<ƶVhu5pGGQ׳1?pherh}OX,%Xzn#MHI 9gy% H(HAJJ`1+u/\Y/<{3.sY{_,3w^0Mg`qD,b- ;4 J(tIT *,l.7\ъ!k]"j@pRHKIFêFi#Y>زT2e>^>cѬ6b1WЂ'yCJJ./EAei(nIZӔͦe3DX$>ky^ÃТ}L3tqbXԬ,R|}hL[UOd!x߄ɤ6ecG/e\b-!GpLs ՗# Ç{,rPp>,Tpu-Gl1n1DZe%"%\`2Ih'6Htf\e*|5=a2DžxFJ- ݟ/{ _t0B0/犼V >: ׾y+yh/!LshцD)\u^K"l-!?-A3B:Ds_R&Z $uR,J sj-QU.%gsۃQm"Y28[gG!6E=U_4ȺoĖZ+RW#+c-X^ p(`Z A\b<}ϛۿQFp0RX!BYLAPլb9e@>&`.)`˅fYVh( 8 kd**Y.P5= N-5 -c ^кX5ATJxFlL1PtV8(E-̇fdFT@E( $1NcsFp坠l2ύN V ) ? 紿mv]HRW $} k璤g=%hhHӎ:m#M;>BOJT㘒) ,Вgqᨍ[K̦%泊dAdQK˷Ȃ\1 h 27WPRFh[% @Ns1 ZR91@l.ZcĶHpZkD^صOlQTD#C\. yN"r.|Ѯi5%4:5t+hhQ8Ty]a8\k^/=41,CsЕ`B* F- FL ݂ce-U}X֡)bX琨 J$]0+H@Mpo~} _;CV#!4 "K i?fr X9@%Jr^@: 3 Dz"b{p?aUzJ)QB$HS44n[of>9>AHӶ_ΫR?j&T }v~b5eap pFBw"m)V:/٤dR*?+VL^19 VoJQ5_p}߆O{! *c ^Dہ.xP_PRP:p 'MϪ(},1J Z\#M$1Qt\94Uhno7b#|F-NgER@pldW (ՆG]uR{Exaaw'NhwVSt: z~'5TJs0>+En)jjVLw`,(i P*,e97~ˁ\Q\фQ#B@7ju|+Sԡ=n7L_}&Y 9Y> K酎^hҷseSA5eb1x ! uS\5 -PCe::кDjVB\DrE`) P&P~v]0;Wb*s|eA5BExj%pKy/mΞIۃd@ ^IDATo} sqډIcj !T?hau}~W/E=XDs6scJW_TqraEEaLX->L~-B#M@ Q$s(iWޛU)u&m8$qV$uwvi|: ɟ|EφdfoAIHټ\ G0ץ^Yj36$˅F/_CY|w.%`p))r":6}n Gm W*L'fS635xSXceX@)$^ݯ; D]ajHؓFW3^)i M`B_CTWԖ}F2faQK囩ZJdHoե,oԖ>k{&ʻ H1++dN pJ2MX`1 ɸd\ҖBbAoM&X?ҍםKfHSl]i^7?AE>/v8ߎS0;2,N&L)EX(l q*m`j.PsX k]M%D*AYa_#P4[5*eᶖU=xik{8tCvkUKOCF&,f4) v `pSݪJNٴ2̓"ATY^›ɀD~`d6Nj(3tg޽V|'?YѮ>*kqE\I @|.T2l.xgzT(CF\ٴlZRQQ  ]In-w=-޽ra9 }_;^PP*J*(UA* 'uN9/?8ј!\$ }OCt j3Xe鼰"|Of{qTA -E)UX)>"YW C ?)Y:YJVhrbrժ=-?b'(cXuJ;UPQEn& :]>^hBi8HɝY\!qY>Tu;]w6qul^~0؄ƮB! .!TSI )RTbEp{ފ0Yͪ?UXW&t)G[c]Ah >jI[ͪU0Rn41i VQ8hjzLlrgbU46n-Z 6F1 R' 噋-mOch0T vBS .>A$VW?OH߉V\}Yʰ)6^zmNjTJۯzBOK"V4om+E3Y^fj h 9%;ra0׌fuR[XY`0hM8rGݡ؈٤Dfy!\U8Ӏx;^{I%C BH?f|jA4VX-jGeoo1Y~}2ЪPU%¢P( JZ 67 ,W&,:PfM :Z1ZmSuk.&%P[.(,U}x~e ?@>C((@݆{ۈui1 4„ue9^k K ի J%uPi'Q`9WA^&3`1b)M~t[.RhmtctRb2.0.)B,І TQ{B>+ХL2FCJiwIKeԵyla[:4$K /,cZDUY] !ɰbխNr^ QInݝ"0O~;џ/2D<A'D#nZS6-ʨ"dzdyz).HZ6-D EHĢբl,\U 梷ҺE,<3ӏN(a k}[ټVD6C&Ռ U$„aUyTEUꩍl*SߥR29dy'~Ty[*OB@Wb,axx^E40b:)IrHIIU,ť>U*l.w~}\9gSƯriS\1eij%ŠrXZ9$zLbyl^2v0bVXY`e;Yyo|'>Јߓ\L"'D7(HiaL k+fXId $^g_qE)f)F ,E!}, ]\BP)K"-e;z$2xsloe3 $Zm4UZX?ʼnSt 0q)o|>:zaz0R!lnCss[__?7+ñWp3 As/r>tRчǗ170\b0*2l'`hU:XY( ݝ1W#xY"V=Pu|$-$6%PZ_i̭JʽM|(4cCF=btR/Mj+\+m Fm NqD;.1ޥe]釿:UZM!!x,-p zk"RC:y2 ,VCF=bVbmሌP:*%ˣQJ;5 %Mxolrga0eMwh6֎t1S?9n1-,\2/.DPz@ ֛SH}{&c; ,a0eaynssph.U;Xnoeosu\|ŸzuϢ E,&{_=r( ,a1GSukrV){@nPpuy\\dPx:ׂr a,[ZfX \`gX;ȷ#qz `c v|arDVy$U>b)y>-EE,`05a>0UxJ$60n+py~n K} X[ .ӆ2+R$IA }k37,mcg~ۉÕ`_ l0-`4WsjV]>cTs%\Rd;ӄ0םP Ak]jֻXNv lsu _"SA@B2%O25,yʱa{mՍ.VךխOY~{3)r~cgYl9X c't ,aǦ5\ipNGam#*rMk;x i-xB`~Be0nn/}ah6hwe !w l̸9zl=!,f?X`1 sh)rs ^?F+)F+|z5 -\ bkG}?!~b憁vJG,Ipq7ޡd7lfI"_ݦҢ*)Sa-7X RV:qYu8Xf( Nڹl,f?X`1 sS0VO+~tXbuUnbEA̦%;1k N q\ϲX ܔ4[A`QuS [3lQoL;z;$2`!ӄ07=E#XR+qhwOu5g2scӳK"[ ,a%;$ڝ+moCufq"qy!Sa:-9hj+]5n\|u>3%k/ڃ-B0e0$6cA؉vwhvfCiv|yŝ_a [,=&ցqeks T O^A ,a+Dn=~uYN=llRbw'ǹ3T"=_l]o'PX`1 \5ͱuXN N6ynMj'ln̦eLuZ2zm8l `0 sMsǾ4c_Zkӥ֑xssloflpk ,Fqb.nS N'!:6-ܙU2n]mΝQ/"fsVqbFg@[+ Ff<αaGA\ vs@KHuj鲹0.X 0O1Bu (cuN7A;SVtf+vNiz86Z\Ylz(*}(Aby yV |} -wމq [d8wf7X\b0!b:)1xama}KQz8փtRbg;ǹSn]&gxs6pX&w X`1 b6αyGAiĵ#]u10pFЕv9v,Q(սU9=\ba0 sg><խ6z8r ,[ιS 8vbps, X`1 ܠl.:k\>m[==W;[9@{`0 sg)N?6ş:EA4yc޼QI ]Yt ־>,a&$TX]O/te Vv6,'obu{^Y0Mժ`>~r[]w麕V3gn(g8yO vz;:~Y`1 0 (GHf#8B"MpxG!0$b:[;[`7=w d0 sAΟDq.ncʰu>fvØw3wqD?2_gS+ ίׯ5,aK&4nlwqdkT:ẕunm_ :}|.֏tG400 ʢxtm9zN7mw;V IV:wzg=(l:20 sE3*zG{X`8jcmڊۛ6qηhm11lo Sf0|~=`0 \խ$X[ּYCu[1r)6=XOn=Q_ާa0 \uteq,V6;8~jbu+O?:VhTpEqxڝ7"xG?}xW `0 \q/}a7V6Ew,?qunMte&ژ s|V]sbQ)|OSX 0ue&8z=pۿlij״u namɸ`ufoϹxFzG34a0 <2?? 6wk^/ű};s(ysgf8vQW3Mqm#85ßߩM%ܯ5v>Vz }[XX`1 0Oi7(k]l؉>?}?}5^ͯln{30\m#I%Җx5&Uw>VqfkzO@X`1 0l^!WxKgm#޻5\ic}uoD73?;W& b{3FN $ p昆k sNoMȹ݋_:a94[I*ʼn[dRm`|ͳslmf>1GX^c3W/|έs\X 0 ,Ξjp.N`J׏(:α9dS|؉U{$~<ş͙}* ,ad2.0֑c}-p#x\`|\+nJWϾ(D#T.X 0 ruch6F+m<*s?;ǙFA~l* +mge'װ1s}* ,a#WJeu_:vr'x!W8szgf:a|#*]ӎsraap~Kq3Vq3VlK__>ȰƱ>>2aad >\ч) bHG~JGzX?҃ '{Jn92G aa.@OpyWv:ݍ_<|xǐ(ƳbOrfU;Od4W8ayJ*Q}mlz 9zu\MADwbaP11upl%o3lO3lq!+7dw) AF0hԅ ( Fq1MZs2niv?N|yEџG ,'^/wmkƊ[.7Xڦ}WgZ]f?N7[.;X#<۫$洶Y)G.WU N` ,0&@Xa L` ,0&@Xa L` ,0&@Xa L` ,0&@Xa L` ,0&@R$4fpK\IENDB`v_sim-3.8.0/tests/exports/aluminium.ref.png000077700000000000000000000000001370110300500237622aluminium-3.7.pngustar00rootroot00000000000000v_sim-3.8.0/tests/exports/cinchonidine.flat.png000066400000000000000000001423611370110300500215670ustar00rootroot00000000000000PNG  IHDRXXfsBIT|d IDATxy$GyDDf}-͌4:%B\qXg@lkkmck|  cavm! 4}ьf{*ꪮ"s2|7WW͂B!t B!,7(!B !BH"B2XB!]B!P`B!t ,B!.CE!exqG/8!B<{rN1E!e(!B !BH"B2s.r'BV 20DBaBȊ;~J"RCXJ ,2|Wy˖?~2kQ.Q.!!D˭J)NZ@yC'KN~2~|=~ҷT*T*! @?t9+>瑒yK({(dqwmU`o& CH)aR&B֪-[`͚5(^rjz?: ;/!M>@)!zk?ظ,}V۱Tš @9 peH k=|7z?c`eQJaxxRJ;e6 \q\ğ~\V\{7֮]#8###\EVNt(;U/~qǢZ@ޟNq2 X m-@".9}d-Ũ1&O&I$IV^1Jin3ҡ'>X^\%Ik-4גXQ<ݻZ jv֬Yj k->8y[zxqdNI`9 7K1GHi"MSDQFk-JR^nHϿʥ'︍Fq;m?jxElW2>s? )S\v܉x?8*RkaWdaliP`-tᾱ8($I1$A^$&&&ӟF#_w1"Yo+\Pj5jD;Ieb]_YM{ݻca߾}y`.} ͢V5cP36VZ_Rx|,uz?=E12PVsw\j=җ7нR<)DLŮ/ߺc]ىEZL1C |/ -Bhi~ǔzyXsq<W`ŪyrRiyKZ:Mr.H/6!]ʫZXLXk ` R~_UL>Z^W>E4m1;b5< =5m4-NA@kOǎZjQY{r/ k `E@3L21f*dGԅnaГ"wZ &&&|vVILin+ 3_"UfqIdQǵt4{j`bBkLh)Qlb 9tN>_3ۏ/~)>-ݵ,l,>5X<j)~PHZ8[=iZԭŨHC_> 0>U|p|N=rEAO"StZ6ja?O}@x"`WGS'~3 d"@(4ڗtśtvR*QA.\u :>7K:N`bk}!rKDVqSW^qq0~{-=fX@SdsBl*f]%O%*5?FO"DBh̋D/(!ƋpNQ,4y wT,TBZX;FFYL(QUY%s`aINBl,RցB !Kp8稔S8ÌQ *w ,B/:sJM01pe%+?"fRK0T Y`EVBBEH)Z!Vl `!>! !KTצFV Iʅ0N`zTj)[!2_Vy(3!)X8Զ1>:œW:aj>{ p0Й^%f!>!]HIhmc|JQqI[1:2ᑑ\\ ! DxZBgBz6 IȡAE=bmFZql|nm@@ hW} a!,%r(ȲP[υ\y-Xz5FGGQTra|Z։ce C iPJA)!Y{Y=c.,UWrk ذ(᯺6&Oum+: JR r)K|yQa{n 04]'R҉*kl8%K$1Hæ܄XdIS 15*]Uа;wgoZ )$pQ5֐JBIG\E CqH)! c JI4VȣY{p>SD/(ji="ԧR ,$BU.zSVL mikh4P*`-`aȌlNd>5fZZ$R)-i/버L.#*PX?"? M.Sb熟=NYF9աc%ZS2FWUP eG1#A牣!$FRE(1I@ P*AJV/g}yGZCgѽ$Ik!ELBy]Ӆ+9YQ y1`Az Ue{RAfu`ZI/R`d"FJs1U[Ͷ &#LGؿh]} a6.MRABIRsodoچutH ISX K_Cm_Z|[7.8`$x΅A&BT Pd" pu@uz=Em2WYX+P ju#c%܉=Q%8p >;0/ZGAZ)c40 IR.wk% uX,y-;:Pq ,q'LS&#8V**q5ly}M}%'b4j+h4)Ҕt̋ +卌GJTQs41ݬ} q`bp :Dn2&g;-~odizET>4'5HRPRB!d,c;g8B 0 pUTF\ \i J5@niuB+1hS4)jS14LV&XdFG]UF`d .Ւ.?9^OՁE P(X\Yr0Xkqn T AB봥^Mѡ~z%vU TTN@R )H7ƠQK5\>HS48IZ"(WH J-R 2JSWTnY k2L)5t!$Zi͞˃2LkiX1QԌH)HZHBHYX1J<.R 04\B $*rQwjB-&&[F &X+%0E4Ŕh)7)j I'Vj/x`0f΅AϞ8a%Ri̵ 5T9m 1HZH) Ai| f,W(XP);10Ƕ)`݅mHѨk(J5sdAL)K+#ͨܛ pxkS1&]yTO152Rh ݁Z + m&EXZ5&͊2q-s @TRJ Mͬ .E\ ry6Rаm ZwAEEꉻ=G($p<4RjR`SwrFLfd/p0@8NcRBB* !eZ @8v'k\$+ C*˞iԿEY!A:xa LtUJcYꁱBX3(҈ Σ_q]LP` 5sͅafѬ9uʫqwEB(Wcs +qO>IHDH%rRXNWgѨ I4] !DsjTFAƸij` wʕlj.QKqNESmn!>O?owkgpAjmr TgYH%Tҥ<T :y$J͕WX}-f ) E3)T̢e c*׉ylv%aDK_7+&Ov7W/hs?"y4sB~~ /`YYTٱTf"*m;%}/ZڸȓFe(B(EԘK!I2Q͒tfM4!kZ^CvB:5^?L^[+3?_׉+[ XCd+v՗[oڄ%)*=r y^L+<|7Y)6&/` eV&c32Ղ9!&Z <lQ* ubł1lGbLa2E9g בwZlϓ +w3D?|u"c{m*XB->MdP`lA E\T @>:ArRZ]MęOquxn OP[a,$yB*_B)HlHɓ;R.$ DkWwUL)i=XP`ya-`uV7vuE&\ ΀,EUl3TqA})I`k- O5VZ+ Kv5[XMP1\="i9u]r> gX3?~BE l#ә J1dipϷ>ޅuʏ}E>Ywb9 f@vA@k=?FMUt"ϽfrB ҇, Z g?p9}OsQ7g?!,*e D/tެ#K IDATYF@6ӇfKha3B8璟֑ehUOhP9MTb >XdఅTW=3<ڷo6ELf(1y1. hIfzajG# (ܡ"˞' oS%h4Maɬ;bهBY3׈4!M @@[r3L6KdM\&HI Nbĉ5Y ~o"! 4`2@>fhd5|>j՜i 5+պ%u !;/0LKB5LвqMSX^i@"d3/hw+ 2V@^b6x@V.>m!,(PD3iBknEز00tb 8,h%YN! %*DB^+ c5 %`B^2 j'ʶ[k[-_BȂaᲛy_ )]?B! (7r ?5rҸBH&BȲ,B8aO~Y}| |qFֺm֠#X~T,BY0E$Tn-S h.埃VIY{M_‰,HHi Z?`%ƲmZ/s.UH"WO>`K%JWW=(rPm`D\hSZl! XEfgZ>ez+k-RhTj &B c<Ss0::r˿xD2(B8Kcx ߎ/5NB u蓀\ lD_ӑOފARD-^~(!K Y\|58$(%18|QډFXRi—mnA f~t -BYP`2EV.O"0"21lRGE$ ŭ[UfgcWhU1*1$ֺ,BR)BBw}֭[Ꭿ'UËDVtQۍF<,I1;#qJ|6iޞnBVX.|+TjOz.b !KFYp1x9g`ll CCCl<_r0;#GDj ZT 4`Pzϩ,ic%i RBg9͊K `$"\pfeaJrPq_ x/v 2~0lLEjkqxc^߷a)%ֹx+B(":bd ]JGd4U4,$ s@W_쀅OQz`\2ic%-&C:2(!d),Bه!L~Bൿ􁮌>jU-]SjfB7`@|=Qq\mQ8̕٢XBXc2, kmEEi*Nqt} 5qϗ8UEFQ3 }p6E!K ,BHQ0g- _)vJ Wql}E"/=V +UL-t!d)!!]G|$X-B._J@pMuwoɋgjߎuiGa<\3vEI F֥R%Z_q,',U("^,xGr)%0lYg6W"3 sa!D9 a%,ZSRV}O\.C{8v~ ȋK2Y% !]GN@kDH)0 ̾N\?5(${{: NKu?߶$Ip}N¥M{}ڄcXTMy횧(+Jǂz>z P*Zy! ,B)jmvkg<y \V[&IP *9}J=Bu[hؐ) 'c;&I"L};7|{Ʃ7`xxJaiyKOBXt"ar@k}Јo©Nŏ&!WƮzT\TV xdŗ_LŘE'}[6‰-swb埗K)swъ8}wΕ7FT&}SzB ,BDӟіbګhH*^Ey8,݉uf7v߇#0ֱ<|e :vxtMEHZ~5dŨ3#TD !dDQ8(_Q&A "\u} N ֌kn~Da7t,BH!OKEX\.⪽`X< k FB/X㨑[blJb*-$9:֏6ΏG ̾3W8Z ڳq djwLG|ԫ^\ &T],R!m;EpiaH"#Gu0 Pl"  g8qm6[5g}LvA?&j6SEQ8).xic,]1T48-ZaBV6Xd9PJ"Ȋ1EyNB⭯z@EfYEN xRDs '렡fkI\;Eg,\YLA5h]$YRٜ !+"$ʋV'hYj,&rj[^xa$ Y>=X0>> ߿WyyY??o5Ѽ)wN'v՞l_gC.WI IS$I"YԙO!Xd8n(@yEk E;Q3]"ƛhNMMajj q;g .}'o9M؉ o9 "~`]E3Bf[DE/9?AY20EH v+iB # duE:T!0{-L!$,`a&\",tQg{zmL>bBDISp:9GJ$>l"±CnR~6VJePd]uVad9NtVel ~)"~N93M@Q\#[v/4`=Ǫ&BB [_[?  K,3'}OH䜐A, $QZ@MUTUm/Ybُ4nÐu5¿ܜ _xn}eNYa //,Wߝ&g9aќ%vGcmhc),=¤@w;+>1)A6Bwk}S{mS_UVaxx8o]K.SlAe \@OI gW$0vBE`G' SqEx*8&j.Y( q[I,gqt}zdDZ q#A} m&^/ȇ\*Z(-uexUp̟)\[ XdB䳱4E:c-NmͅgW+L_݊S -Q\|r\hSϘ񳋅߾Sq_(Z ^x8q7hYKdL\ic` B1iV/K∬3VW#׷X"Y4WI*ΎFOXe5ؘ> r]>pTzZTnE~|[5 MicY-/FFzS`E8 ea`a`B+&eR´(O3AE `EW` GIo:ΡKƉ=qwVnZo7?pQ_'7N͟XeƁtp4(DsڞAw~ ejc`LH hIJ%!~o[ E@X  NX)MB^蜾ZR5ZIgN2=_r1k@E/SI|tk(I ͅ!ڌ'-ouVtkz,|/rȟu|0'4O{M%}tvy|Kq@<4J#[^ǘXwEPI)%ޱ[){;1 QV~fC k`!]$K}/pAc:mSA /uTð-!  5.e(A)$y@,n(%xGl^y<܊]fݎz(ZpW,Zh"Q]<1jԬь0B{$a-TXmsuR*/뢰"d9AEk) %\V^e IFߗ!'YJpڀg)%P:QCJlI)]ؘt~R: [a1ɣxQr?`ڄgM[z"x)T%HADB5WZHcgRNKznwrh*{uYiB2(P`R˼4p٘ %f<"X9m-$2T4 l.7_lCfq؁H)5ӄd9d$=5 ZkZtӏ܎1Ql+[ާY'YQ& 6.=wp8ϫ}[;k߁&V{T:4\ LGE&BF,%4yd.+ @~$0)Aa8Gf'B:Xd$IiBHw M/ؠwUE|z6gބ6i񝅔 p>{S> PA/gpOiiRopyB 6&o` 84UτDfP֠NT$=C>X)a_dD&=ߖ//8Iic3UFMp" w0d-aލԯǦHD w_ĕf'L¶yBѷyH;)ޞ'㗿r@@ (_ܞ-~FEd[>/]w(.>U4X 2`xY0|]z'-]&>6]x]훸 <9rK ΅'czߕY:&S:}sARF#iDyy+ު?=Bd$֢E)A(*B@+{]58/tZf꯽=~T*b􅃉ح5C?3bs ^> _{op+{J`n/GO.wS:G[UB:60-2 Z>XoUC|&䪮oOu6DzeXT(_ X)!|{QXl$A^o˪T*(ϮƢnCED lMvlMzn5zgE"1Qҙ7K[<]jS.Nf O&xnWZ!/wO/z!On/~\j5[^Vӱ(s>eE րG-dsa;4ԅ\?=VW`-0 3iU#،. <¸\ӗ<3ۡGm*ŸZݗ^JI<^ӌ#8֛1ؒ>)7]u%0ˬܝR<8w&pVNT>?LWEB}בݭ"͸\o gD?8#!=q}-_ BBHyofi! iq m` `. .uDIZ ff*{7+6k*r%pLڼ@̮AHH`Algcֶy*MS(og"d0#X6gǖI<6 i_S? +!2&DsO<7%zj|QWpp\ͻLvSOZ<|&i7]=2{]ඝeYv|$:O (i3bk Z?XfbӁiWnqŃ,4, N=(v[V2OCo~Cv կSF:Ʒf_5{÷Z>aӸGmc [fQNuNckNcك^~XDMOPZo! H!q מϔ`(Y-wtQOBAeV&l*ǽ"G>TxE/jNjbBU4GQ4m}B jU¸T{d~+Vhڧ IDATW: {z߁MO_{ * !lvnVx%f!o8QsUWNb "g,kLs{:!(tvQt¥(LBuB bC%@y>]dV VN;hl~ oZwmrNىX<`MDje" ^d9yQ1-X[g6 B̟Gd 2Rrd?'tZ[8%3O,5 tdYvA,Nj]K.-M(JnFi<&.~B_R'Y "S٣$$p1[z>~bhC'ݚ4mįLߝca\Hf:qRg|deB5(4aKSŝLO+jM&t56wN$W 4Nu~r-rQ/Luq.e Kk NevsP `cFiiSdj\4Ԗ3iWHH_\$к3Lu c+p"𩭕.`sFAng!^{aԋ"*g}d^ϛwn(Kٌڳ8D&B05 +bK }5=] '{+9\a#'_6;hyИd^Kmqr1o6E%vڬO_kt>ˋ/vfK3ߞw>yԠp5:Bik$k I: CV4)V)l׻f:ʟgGN~+,Ρ76 ڹf3_~lʒxS~pr&g!"kϝw>w>rXkbSX5kT;k) &\)M1`ʹК"\I \_hFBZsj "0V SXX a+g!}{{+?Yjd\)uʇPҁӖZCyw.*G"DϠX-8cL+di.lh?{|Q>tȔ4D&հVX+p-Z>K]˜ŕ5yM3E&MkZ=:Ep@ۜ" A'm$:IR$IҌpf4 g>x|[qڿ k}ĹocS2UlmM뱌1{N)g.8ine,(IQh걒4gHx]ɍB͆@[L7kut,pr -Dӭ}_@bZ--}܊M7b 4'uvٺhZ->)L&wt,c]}/tB(&@*u>k&;}#}ݎ" tU0pV8;SNpykM8o,+}ۥk_@Kvo_WF4]tq[$rcYf3QPr6V5{d1akhrz*-I3SI#cDQSQ1+zO!B#Y@srU0Q+[:~{whl)sS\RR\23Wq˗C}`߻|/g?F$i8IIn2Z,|dV^S>q Fc v"lTNiH:h#Yl =@HFBHڵey.&,ǫRJ<,`/nWuUEZy<][Mj?Eg1Y^;:^\}n p[ڼ4KYT+AŠłky>6X:2+.;n]/v͈DgQ@Fx68=_,(] &!-$ ,A~]}ڊaj/Rv (PJ!6wY3aۗ\*!xj;m^Z|/[ܛy_F5ѕϜ˺\jТ1vi2 PRk{`Ek@){"Z@aK$֘(1[q.%.|/Zd>y4E5^u Og }ٿR A@I %%d~٢dS` )qΦ5ѸQFan3:hr_=HOƵ9Fd{Mxiye6{xɪ M44H74"c$Fh>}%7dRMyW "@DfdfnfjzᜪZc {:UϡpMͧU]Y'R[kR !OK@pyTk&RUFcϕDA QSku)Bo2>vgƄ|gՌO41oNtH\.{Νq96kR6Y3 8OzvԷ_qg"Xæb~uB$ZVZbx!lv{L985R?/Ч0]K QNm? wzgp`Ό'p'zST@L\΋wV\8~y% Xe<]ML~U鈒-PYC]g85hVBB&HSD.MSH5a )JBe^f))΋B%0SM-h6K׋]AZEjq67Zr^& ]y^ΰ0]'6^3ax6YPqSqxs^xq{cB׀== a\v\Ĝ%f1MmEY'Hh R'R Z 2PGF1U߹)LhƪfRhfɍ6b]{u Ωޙ\^l9q^&IbG8j]z7K甖w6YGϑ7BTZvY]1OlpjiLgI{)U Q~tgG z 5;]?¨Bb[=P]m< )ﯘߖR"2YiΥ}M$Z^nJqﭔBFeH"fgpPiFqFJ׏#XL/Ǭ++YqبA]Ԫ؇½B߯}VAѷ C/oƆh>6+ kꅕ{ Pl PGyk縝eE\tcʻ N6Y;➢)lybF塵Q@-]ݕ1 -_ax_)~` O+Xq!K D{ݾZ*=XB o&+& ~rM^se.(%o7@f{ h)PV`5X0Ӕ5oUn`pF{  cb}ģ1}4[Z?Vu{.̳GM4"?ޗVh(*cij+fԤ [irI)q cq}(y8 Z+$t o~Q_zZ25Z>Ib{˯z%bFDXXw`u(Q{f̘ *JJ2_9,(~}k ( 9M q !"4} Zj f =' K.W/ H)L7j Rd@ WOY7Z}wn0=Ex] ic߸p'Wq aX`1 yn Y GaӃ?9a˓z=Y=kJrًfww6Rq ^Fx # 2!X{f/cMݸilׅ(:>M(Z +J`|GO1YZ_wE+fUpćߩ1u﬘aa=~Ε0%;bXLCk@" MjϺ (NS#lHs_ŕiԤ*l(ǰ{ֿ$75m?w7^!p?5]Bq/N$5rW ,b+GHvq}B@Vh;=v 8ͬC\_ },[`Wsc49o,xfVz+' W=QB.^&yգxM>{ `w?i7_1ӹWzxMQWE_,@d?|zYHWZiڋ,k>x^K6oD1mP@wK"?0#`,fx_}PkV-ᾟx<;uÅUph*Z꬚=\O$￞+Vkj.…$^?.ӃL7i 5(SP*-j$@Ǧ Z9a5B0q1[=g~նJ?A] )1y"iTS3*?,Z(|2\,AGm#>2|fZuG`5nSOP& r뫺0:B+|]kcr 7T.YR I6ml㥆ѴKg`|??o=O'a>{ۚ.l\V/DBqU,˰:iȕ'Dr܊V)+5*"k#"]󳖌U蒋ԅ)@SET*A¯8|S).!69LiȢ%x3\-P2UV4Hej$AVj Nw:pd^af, }#"2ۅ{Q%o2+&m{]҃.B:DB@&BD6%i3 $* - Dw "u}>݂Kf"dXLsE3 SAHnB]=ua*MS$I02ta7G<{(BLjD ]=?Q >LX5lV)W\o" R B}nJhT v/H[')J+]Q.mxo'#\tl4B[wy(9O٥B YhsЯ)"J@ެUz>\DUٯywjR "PZCZm=U*!EQd򶖨?r] 袁F3qQFk]xZɭ=JCYK + "-"k'(eJ!\ZH+?y]rƑAA)!44!Q } ;&t_Sp Mbðm+_#|&>\xAO5 !ʲ{bxͰ6I 6$}x: >lJsXKBD[V6ltER}~g ,Hk3Z6'u~J/yRЂێ eѷm3X՘ۯ0]mlNBah]_נع.:'̲ RII}s4%bX̨,Z4}.; Bݷ#)q G 5~n?̭$X4m;S̭$k[N86٢AU-_~"mAN;7t)RDXBS,,zCYR͞fh2/6d,( 8a%H.š: 0޿ ~ z*_+GZ!{ TY&gE BT=ֶS4U5(|. )X`1;ĉ,FpMtW.gKfga)ɲ Ȳ̧8FRɒR38ٳ}azͫg`s+ vaN9sJ v.tW{&JEړ=AAT[K*em#vEo 7a􊈐)ޣc&Dzʥ҂ZG&n06"mS؀P3 Äi 1')o5qt.RW]"d J!!H TXJuν\C" š1SX̘Xd)[(T#z9臉vt~,{,PV}#MSJ%T*#+Zk\?k`!'弇 V{mnj(#"GL8A"4 $D")Hh@Ћ VOvro9dANO-] PD bAuRDlΝW^fŔ7F|uVK$!'3S X̘a5Bp]␈Cьf-g`Oql.M J]k۶Ԗ/An=k x}Kj"NnlADP F, `jH!LK Q@ֵ4 .⢈y &t>S~v_KR6hǟ1cdjլ)hCQ+ # U2&̥Fn;piMG&7O) ,f8V>P 9!#ӄ&ZVT*yp*Y?bf)Wnn%j:RוK)"'2-W0YB$W']sb}3d{-q~ _Ͽ u)AK:$]!Yt4@ i(lZ0ӹ>8Irc*Wy*a ]ѻP6}(4HL>bkBP?ҦÀ>Ωzُp-?m+|ꎛOl@71]it6k&v5}Y5cL̟WܒV+ˆ0~my36`COXn뽁Vt6^x͟m8eV)l_C 鏣au;{P̎@#s]| _Fށ1ʶ0RJ{1]Q^"78Oo";ࢋ/ܥEQ S4ߵVJkt鰆LY\ӿg$,2R~DBnDdjG"6k [<T*~m[ظq#xrAd uWA)t@G2bJJsWOQ# R  eҲbr%\B>3^*xszm닂+J00 ˠ1va,WO ЅE3ѰbFeZ3A -A4BNEB[[#f aZ5XKN8<:G|];7>w/"—6|PVsqɩͧϟjl/{Eak#rBSk>Ml BY@b!hi`!tP4V:_ijBfb`Fu!Mp]zһ; }}Ke__/}l IHvWsU*@DȲ BH)}Jb|;j8s՘6kpK1עYX0vw"Jy w]鼏c }B BS"X`1c,qU Lp6fKPJR;VLd>p2WW:Β!VIVq$* X>++}j㴡dwǒ?$Dx\XG'>Gh|+AM aYL"w!R{?,VZi'F2)yhhTAE|=FF\iHLH}wWz136E] 祖eߊᜱ0Ű{q((KkbU~{7> ۭ ̾q>X@®6O:ltӼi\.)͂YX24mD#_ `1Mzıߵ"Jۙ,⪞9e|Ⱦ` )/~',ޏX1Y4 B N)|ZZVV5rbV]'A8z޻>_kVTၾcq.u޽ݵ̱e `"XZ}Cm;C'aE㴍ȅVC,Qi$~`ޕDId'y{?\ #V!hM8'VIPȲ *4a6gK';ZePmQջx/\?aTZ蟳I&)k4mwE 5CX"knz~RZeEO ; ,f K!VYRIlK3 e9>@E׉H}a)d/o[=)e!BÈf[+y7 |i<|cKx7}]=H#p6X~E_W>GX4W''pyC1~=eVdy4iVm3y@S'8\ŌgoD^/;F{sx!l+p[V ad*L/iaH)Z\F__ 5ur{pu'}p@s=?(2Q$wVjW{:h U/'2}CnxCv?f 8z?; 40q]J[D@(8IaA*c|i&aLY"rAE M4lksfI0 V6Ck4MQVʲ +y\b\>t-v^ۯčg ]?( tێ]<5?aه}Kj $T##j~.,ܾ?q_3kc܀wwȚS. &YLB 9c@X1b5;K_I\12*t+YK}DxtYjr?%iKVaxxxD0jKW!t\;x.6F0Gnk߮?#R|صYyTp-8v^aWr<\9 u#wweЧ9}W Dݎ^M$ VVm۰uVlݺ? Mg~V}x|B*FJ#_sҙjNKjx8H:z.j]mVTmFo.8,f\ɞV2Ȳi"2d2+|r4OMu6h6xz0-Ita4$-[yfg2/)ܼtbXqw~RnaЇ] &*@BewBvHHl栤S,="t Z'rbLi[wN2N1QpH!Rqz(g^[׉w5{8=X luzH-Q0to.<]\o{/wڴo!h9 Z#lϝpݞfEH,|KkbEl3> t`#ݝ6LzU"BLj㑑D3bqP24U"+p[Vwj2 i  ϽJN:h  ```"GC/GX5~::V zNQ դˆٓV"!FAeei ŠʲWc'7 5{^ 8M!41>R[!ôSU]YORTkU W,,Kı B$8FE>nx >vDRRe\L-6uۮ:D|5CMVv++K. Nи҅O};~'c|V߾x45m)gH%5W]GEHA[ #Tpk lJ'X9pD9J(+}\txN8zE-/45匶Ck@f&U[Ί^:_U9 <&=G+7d=vd8 x_yo5쓽.x ssݠ RaxE$z0g=LSZ[Z(ŕ]+^PyweȂǎ眉fMHVWy6wW6-]2) $E(KѮue7}(BTrBSŌ(`WJDJ!!z6&W3Ioh @V.B!2HlBuLAнZU>M<4+3'fz߷Ұ*(1_x>^I_'i!s!KRR AަFh};3^.+'2FҶYf<~vNCuPsݢ  /M AW[*O f[\ҦUQ3ׂ|x?.8bzX S3 ("i芔[ b5:ĀV0y;̊+%%ҐJeū+|'kZLkRy-3-ܴA6K++>zW`=q){]n. Alc47/{UCzg{'´ X p2dP`MUW ,.-Ybk\֦H7KSIԊٱD85 Q܂DKRGs ӁnOׂ ,-5Hrv$4(eκ(BG"%MmIeDfV I !̈xH) K;u~)2G_H񥴂 nBF+5p1ރ4x9 Ͱb˻M] ԠTiae#[ /b٥jRJdRB*4K!̧ ݦ>J0 }(^qFWZ)>4Qm˄`-rT2,d&)IHT*ك| P4N^5Ŝѓa\4F]F fp@,Z y68pp5-"(%ATSoFz;qNڭ\d)(&@RYhoflpaB\f6z$ E6Ms"> H)jIZ IPԒT^I4rŻ|߰8(h9@6,hi I Z-Nħ:2DN]Vm]WڜR.hADPZ_Iŕ1VONp%_AtߑYV3}֒YBj,csV??h"a,nӃҦÂx)29y"5,O t3ې8qƚ S b=8#=S"a 2K!/ -1 eƪ!piw(w`R"%e"R\)am_=vn27+[S_e7F .+OA*B[59 P DB+-LٿcS&b@)$ jI Z $I}_JSYϦŸaqPؽV[RX\/;9I9"H,j` ݊B&jRur27YoP#X ")@6DB@@ǐ%S۵*#p ͂e(̊B{_LDẇWvj Ss?Z1҄p2Bji m;s>Ŷw"#W (MC( +4ٲ>.:e+Ch IDAT '7,&`Zz@5'JA/R!M(C,c&2gLs|)%jZķ1YVn{zj5GՇ.ED^Mz1ԯQK'a? 6-dI ,<=ŻK/kn@%5hE̊cTKdzȲAS$My;"H)1<\EZ6tnS0*uͿLj4FD MH "q "ئaRa+IrBaYV*PTHfF]qm{/CWxRVt}r_̖Nfx}{Yq/}PP %lJ㖷uL{a0.NTeYRlVVLR$Wj崒b[qGHH{` ,i@z,L\Lija۶XaK0RDӮ5yJ[0:S;4b&"Y@ֽYD4)l5[ 3p)„*IXv#Y9w_^OuZt6aQxv{g%wbj>+S%Rcq0S#O? $FGn8UӫSЙ6,Nd1 c(ksR/rox`H\fjaa!Gvft)"dai1,aaZ ,aaaSѢa ,aaaSݢa ,aaaaŰbaE ȝS X 0 0-0 3.*Φbfbai1,aqQ6 )2LSX`1 0 ôX 0 0-0 3.^\0`0 0 bX`1 0#X cX`1 0 ôX 0 0-0 3.`:<^X`1 0 ôX 0̸"w1,aB9BuzLwz 0Lo7W ϛd;"A sI$@@xu(p6ańHߑX*C[EBD "do&H`z?७=.X`1 0 ߾8!+c @xW}v≷n2JD ;sրq1 iL',af۷ADZCk 5`cЂ  6oVFyk+{)™Ӱ`[\LvX`1 02 ,)JZ _i yIFB  tjGVX`1 0k-yʪR^HV}ˊ XqUAk7 3?roU^\-{=b ,apwZR! >Uj }Z <_+ؙh΅CUNuqeVFn@9wRL`0 pY@ ]4Ćb~s[xA L!TE]*n@.ŴADJJq(\5Io>0 *?XhPh |تVDQW bP|ԥE]UAxZ"ldEQ(~ߘ\*utaɱRuQ:a2P'J4/v\ +!\} M^dEV`EVdWlLa 8t @R a CQA$iG}W{Քz QWVP"AB J1'2 0 #O YZC)!ZAJ 6RJHV^XJk\j0I!t  a8W[F0H}iTĕuʲ I"MY4K>62)Jz+ )3H!$,Ce[ Ga,KgcڴiUi &Ndr4P`e'sPi9kE`X9u5WΐT)*6J򈠶?,X`1 8| 4)w`L ^3/YLA: 6FJ:ql4ZeΎuݾ}}[[(:Tqpa)ϒei4MP'kFXSp'g䆚(V]P`XAS^wLDdX9`҃2HJs8uXi|v qM/-r\!6G#^i0jc&,,Q]A[U/ƚ"(ֲ}XVGRZAXRnsMCy4F*D4NE݇e:5q p`e錍фvWyk ,aK R'cqp8;O8s eZDThpQ-#>?h\{5Ya0 V&I2bӇþ Kw!+*C崅nRYx7b:fM8c왽މSS͂MaF׳1\Q
    1<[:oF]6kqqx5޻c+j7 PX~75z/w*6kGt,a,SE(˾=2fM_^,-mwl,,0AU {fX]:++UD !g,=mVqsd.̕o^LX`1 3y|K¨Eee^xR_CD]ٓ1Q|;#2wHڣX>]fy}ҝW^HD "_g 5t=",^z BDk g,a]Z )}}}]:zIsZCo{O:miF0 LoI>ej144!TU(|0(0|K;=& Gwuʱ>GV{koǰe¦qSp7;nnTGaFE\Kƣ.ED}wn8 oFvlg ]=W7 |hDDHޏཱུp@TZkQIJ¬3p%Sw܌xJL1X`1 àXVZEVR(<}}ߊ |bHHٿ|\c? 86i( BŹ'k8s՘+ף*ˁs17})Vލb&ދM2pg7Hbeg4 h ]H#0rAtD]fAk`Z0=wF <즞n&[%q>ǥ?VVCZŵV3%b*bt5{ O8y/AyQ/ZV=}:-8gV1 61$"t#p3Ymw-S>/y`K/`޾ ;:9KomFMcV,fLHhiZbhhߴey{cl-f8$y)z4O/ dZԐN\7!/z k=Wp0zGY|x`mj/TG+ )0AB!ֽݿ!0LC\{}ЙVXY7|W{ ߆w'O`}Pu__G hQY[kd#8Z?2M_(폛57$ѥ+| 5|Ј,aZi^L<,aFa,BjG2^,Sn<>dʋmҒ JL.*B,O;n] YN7iWc6uW~_^ 7KФlt',axcq÷'{pnplR9;[ka|򆙓B\M~)m\4/W.hoRO`^O7s:0Lejxu²"hm*T:6]PEٰK+{'påLM~pVW}fWjRV*H4,axv\T ?޻hURV.w="Ql&A_s=R>oDHWY 3Qbi3?b_uKis2>z<9! DfuiAD]Gjrq&r"S6|hʐ&)4AȲif""waV 3^Pv\@EQ(QI!|IP&u !H 0UPJ@@C +/~) ,a6]O(ѫ`\}h+K+$2Mrf hAPZA R4_yiIH=2DaKp͋lbn" )aSațe)L&IVER|>(-L &R(% v;9f 5X 0m_خ.F^iRUR Z)i:4AAVon!tgADm-Wjހ#X 0m+ }Ҿl<#"(y+RHeLȷفO-:nȟgVR~ׂc 2a6r_+XEy$K)eh&2<D(Z@T9{3og`h]eeg0S`1 tȤb(o"EaaJCA٨L$qQ,_&:4ȝ-fWaAAh9# 30Li*F6W?dX>Zc#Z*vday0uXYX`'Zhô X 0m,8Kg\48cM50_WJA%$F,@q_}9y+c3`0 fLV.K Zצ\ h=n% }'񎍝p 0L )^엉hmjȗFl !@ {9YY~[/1l7D޺p[0`0 .%L0kaaZ ,aaaQ 00 0La0 0 bX`1 t1 U]H,aaZ ,aaaq9E0 ,aaaaŰbai1,ai`'w%X`1 0 ôX 0 0-0 0La0 0 bX`1 0 ôX 0]3Laaoރ$9k `ABK`z!-1$ۡb㪔JvR䏐J82. ! #dZH),$yt}s9==왞~;CƀEDDD4d XDDDDCƀEDɱ;a""""2,"""!FDDtpa6 ϯ=)^sԛC̝7}*|BBv RG4h, B@I X@B@5B,`qMshӻդk- kn=k{?dp XDD\Z,3mx,,5(+USwm)%kH XDDi W+mm9-I9XDDM?B)$V*(A/B@J7Qo3F] )|nºUYJXV0?+Tsκhhw&&ُ J)Drg Sy  B \殫=7^WV, PJXpK႖V j,aцb""nΝ!q~Q[wW.zohGGBʔ/Eo5K\ؒBBC_87fhbpш]g i !.q[wK`~"wh]p毋@\Mt2噅R RB,ŀED4b*&e!,W gй!\ %FgzSq BG"{z`""#cLh4PT_Z. Hm.rW_₨Eymy!syξXF?(ըnRo?3 RH_smn Q^ ~XE -k 1E05<%ϑXŢIDD#Sp?TgpƜAl\5r+]5!Zeph( _;]Q'Ch7hӏ[7}!`/Wd뀢_R R֙JXhcZT`#5Zܐ,zb""rՓ5ʵZR*H VUnmk{iZjqS.uvCD4BoaB3t3˖ˡr(QX;Gq^O33TU1L( |Kpj_ˋ v%GƅXh6MCE 툢W %e[ Q.B}ɮWY56,"B7jQLhšϽCZ=7|Y3mN~so뻰k!(Qt9XaP.|U=ƒý x1߹>)u}\1R-"h$o=Zx-e;J˖?yg9߭?, z/=A.[Cxɕw^H|m\E9m*@Q g(%5zΝ\ʳ,"n~ V$`CcQXH*ZXR*nMB&[qYS;FcG5ݻqr$,ԁ g-jBU9Kr51= i<3{iEW_нήiiY~OIǀED4"~c01u|w,A7G !n [Zb /,6/ʨv\ع;3n^g =GiPxA!}Xײ-@?S]gxa&"[kΩ7g5,Ô{#/'ZKrX!p^zf̘ō߹_ d[o~W?nⷔPR*mҵ/x[e?{/ŷ S]XMp|7w#RK׌4<_5!&::; -So<)8{NK;e5 @TyNsz.I!/}g=]wa_?Ќ\Hܾ+z$*q`a٦a1`o8155Zm\>\ ]K{S˒W[ox]=pOUլk1[WJEo x՛LcK'Uh, [5XN;g 4pqc~~q#w@oк&j^[ >B/SE5)wq2|y1O~R@bMpm$ MR-`_O໷|W~7Eա_<}UU8F,ʙ4x󘙙AäJͰ~H ބvmve9Zo7qz0NO_{(W~-F 4PVX)$ug8&}W_eϨGVU4ƨT5 *E8¿F{|}hcMQs5IE=okB`׵4M_z;2KuFk+Wq[Pig~cv=uC/%K3i,s$MQW㖩Kf@T9Df{rۮ%.dI9^o7BVx `}@Eaf?nʲ Y!3cp3#H` > gݹ&?JZ#MӞaj/j+q6?tʐ\Xc`lXOh?Th01Wrh&ё )MӞ߄(a{x|ܚi.[vEY2FB)?T+4F% xm,""/Dwk-,+_9HRJqSPm7~ARReHH@2hM,">աR0Ƭ: P٪ʳnm?fBR@`?eC*{ͤ[e ~gI5DDGtcs1HNǯ=.Z!qh]{0 kNXahc嚒ƅW^~NɰEDtBBj0!X`N,ͱl1ʘ{rI!niDko<QŠ*PY:w]\8W@8)_ۀ[ttGoO 1wht5ThA$XZZ\߿?80-~}Uʯ}#CcumtaUJ>BVX92$IRi{7}A|{`k[?~?YnE1]L9W/ e a""ZiO " v:,,,ǟt\ggQ]FH@bco6mNDtk˚›?_`u;Vhab3&7fS|aHEm"L"$"""2,"""!c""""2,"""!c""""2,"""!c"":fo ÀEDDD4dl4J[i8]c[D4Dh21` k~7C{DDJ-wjߪeǀE[(/< @@@h_$?^A܃<]-?xU)j|V%a k܂1ƀEFHic(sXs/T[ OD9TV =ǁ{~ yk,?X#%,:"EHr>)RՁTQ|R-? aD4zQB;R ~pP0_ AZ c|3DqE*j鈷 _J@I$?6K%En΄RB)v1:sm :(R@R~ORB}+W*CW,**A9`!x+G:g @ChrCwU?A< csk,Wrc}h)DD>,X )DQ"+f|e3I O| ǟ0_4 @)1xXn@)Qo0¤gEq]X"$9apSAkd|e؆acEh,/b!dQRJV\;c$9D#M5f"-է,ZZ8R\ - [&]EjP zU쮕jQMz X^Yj_Yݼ3:f XXkvcBьz 4[1ZSLPsdH9ݜD4~h4JJQCBX)|nB[ \QP~)ȍj ͖{~Y*_i.zl`:Li~ɖR   q03`4$Gw%CY`"Mۦ <~f׸X;IH !|G Ճ"ݼV\S7{{"vP\K11vN]шPk(4PVlkcYh3d63g89>}=KiśV6%WM*VM X\W.)%#y95\q]ɰ;0`#~jPJt5V坝ocdv4+):|U#"ZogLpQ\ei¾.ܐŀAh/gh/gxNx\Sh6#jh"4Zhb4[5l? ĕc +): ij׋)`m\'+`aW(Wr!C_F$J6sSGF@>I`̏Y/(v)%|QoaT~gkIµ"j;1yT\VJ[K 䮹2|JJYLp/VEҌPGuxjZ1Iם1&I7/&sZ` XK)zS5Z1ZST$њњq b9W2RWUÖDDC)%#RVBʁX.9։$uRPh4UW_Ve H|pJ9!HQa#@e WhNŘU$fꘙDJ4ɱbe9C{9e."ZgZZ#ZkRbZ !DM:] :Z.8E7(FV/VCD#fHdkim^qժ},OZS5LS1c?˝S$+(MQIҹF- DvrOjTkum$T:9F%SFF[Th$I wzoM!ƙ:Z1gj"曨4E7^ʰt ʲdh2i#ܫVϸQ$ݼ'3ي]+B*7l5dE*2@mV X&/VBfjqծF#BK6XYrRw#WmvKPR -YwWaV! ]D՗pMA[Yq׃Z`xqx||jfh4ًQ$1ओ#pX^Lx bZ|"“YAIJ(z/'F3Bn4"41*$lYTܠvN'GǯBmM X+)yzx,$g]k`zV~zkFqT\[t:,Ņ.Ӟh豣%(!<7[c XDDDt:XXz3睱!9&ƭ=!%X""" b""""2,"""!c""""2,"""!c""""2,"""!c""""2,"""!c""""2,"""!c""""2,"""!c""""2,"""!c""""2,"""!c""""2,"""!c""""2,"""!c""""2,"""!c""""2,"""!c""""2,"""!c""""2,"""!c""""2,"""!c""""2,"""!c""""2,"""!c""""2,"""!c""""2,"""!c""""2,"""!c""""2,"""!c""""oyIENDB`v_sim-3.8.0/tests/exports/cinchonidine.ref.png000066400000000000000000002365501370110300500214210ustar00rootroot00000000000000PNG  IHDRXXfsBIT|d pHYs  tEXtSoftwarewww.inkscape.org< IDATxw`eƟ鳻) ] w*ʉaDl~zz]O z'Ԑdn \H~ݝY&3k6J\4z μ"p{@4I3q2Y܉AMxoX`>֮Z Ae{0d(ξة)A͍[6'-L~1@Qj (۶QVV^ n0%:6MLV^U˖bŲ%>W(n~>h~M)*rrr@ A`*++{n#\}8q&Yg`:Øq5  BUUȲ <8=ǁeY0 >(zxi$Z1.VX)'`֭4x0 }iDLY];ПcÚ(*,,E '<4QQQVsPжp~l: ޱzrL6lߺe:xO{dr8ض 9K8~;v,Uh6Lӄax1pa7FXmcKS1;qe! Ķg^p1.jL.0׬2aQT\?Un%]I~8t19kc6`gc]h߱v2 ۵KYo5PU:wqOA~A`ӆ磓puB2ޯkukѡCAAHOymC4D",^E:_j6c(3V-CuQ'6m]9_?ӧg^Hi:|ѐ#Ƕ1OrR蓆Ǔip18۶10kګ82D,CT@ /څ3G^0vmUe%+.$<(3_x*Bmۖ-dֻŗ!Ͽ8%}cL5B!(sKȪ ]סiN6 0 g]xq&_w#;oǶOE8fu~ֶr88`63X !8c/@5\tPL&"C֌bѼ+D^^E/@UU3ŒbKSܼ<Ak`[o6hW, #/'EqYZ_z^|>*\wsO-?e'-W]i? CSsFhWxu ֮\<{;IWs>7i?p:e['ޏ=OgDZI-JTS}IܳbSQic&_VY/mvs_pr=C9 {n3AޥѧO?6_WoadSY&k VY @(B^^ ЩS'mP{‹͛2fUe%n*r1kc8i8i`ؾuk֬X~Yrn= Nw_~!}5nA\ph|_ЭWoLq}z8s ڶӠL0/^;,[9,_gu/YwgLOYu_VXK.p!bHN)FOf˲2?"{dM`m+/[q秽C ApW`ǶmV-O}Sw\|:\U۷ÏS?}k9JZwPN}͜% 槸z8lۆa0Mò,<QѦM,Y0?mf:uv)UEzK/%19 SGԙՕe%%kX%I`Iz/>h?Z;"I,EHd=r`l%UB!\ݶ-vlڠysѵg/-*^@u?9ֳv`܉c qݨau0`@<ߚ>tPl\.瞏Wy [lx߻׎ש3Ͽ{_[ E4J DeE m#kkղ0plaAX);wYL 0Юoήs1}iQ۵m[#V"J,D'iMFD}=??kWh[lFAaëwnVoD]tUHj#K:tmȪeK1@ <xM8`Yce k{O0XQ2>ض[_GqhӶ ߸&˷\S%;aΝ1OdeԹ `B]Vqp=.s;;P2hzW^wC=o=sK֊eKp2 㠃{e5˲Nj$bNwkV;z%LJk=A[D-7)ƽ?Ub1_`b1Xq|^a@4(Jf_HCًqιR-ooӧ>zj(]Q `S/vB\UW3Qu+y3{uqpgZ} E R]=0P]UƵ CplUwgFV-ÀkyMJ7/m,3h@Pw_{~;|6;TݻvAQzÚOW=۽kWF#Ke$7/@m۟RT\j?]/qn ~+nZGt~jMlǡG{qeNjmy>i,+QPPX] EJAB<qZS.=XpCJqv2M0Mx&b1 t!`9yyJ/bWcq[QZOC:fǮ{֮ZGjI9'kg>`_ cAn.^}QM׎Əy#/bk0p 7aA׹X$6oӡs_(uX4+MӠit]aܬL+إ6oРNAj_spEq3WRqh8 h 3p0(*,ǁipUsLYn PQAVqhWRzOH6 ^aeYb^{5+)iA^k[U5y{|2(߼ Ǐ}/^icCu_wƛJg[Z5hx7Mi"U8XՈbx%mgxS˖F~s?֮I)OȄӄ!MĊKq0:4YQйk7,Yֵ>jOK4,Xv7λN"{F${׎Ԯ;q7s~kVܯ>֥thWd5kq 裏F׮]0뚛eY4 WC&ၧx; ԿOA$ƚ1pw{W)}TVTG&->qc1z(d_apE-l۲ ͭLۻ3c.8䨣3޷]yX,MnUD,]6ycϽO>g'?G'YQt5uќr9ilNՕU6$7\n={;Babb0wWPTUwcc|o:Nds80s( NYU!6lD0<\'FL~%'p5W!-sP8.=td8t|E~M7rއ۷7~z7:hxNdN7o=P-P2^>VM]./]G&_&r~H(IyDru< ΘV(0k-g_|.|6Yphxbt y^/f0#pkz'~ f9>lVGGG'a K*y ڥ fai~UM0S5;ڴI/?&=| x`{y98K[d|7~XJ@bL,/4M"dAeq[V:r]2onUe%DQD0xN>6%cuO7É_USi#ns%zcj^b(++^S_,[TWUbܕpa2ZG4Bx3fu_cN> _5~@Ǯ]e͂_z>۸sң:yDzJ ܯ`P%m%ar.b(//G=pw @ K4@ r8C(7Zc1(Zottq^{Yy%i<~߽{x~{U[=9yydN}g}vZ*qw]L<G45cs/GϿh]{:3_yzU7DڥdXb9L[b8vׅXx1ڕ`h=Tډ<WB~^?dRlڸvCh}^-H4H`AD蚆˰l6NҾin咩`AќPo7~h(  "d`ejAAv" 2$  ,  ,C  "ː" 2$  ,  ,C  "ː" 2$  ,  ,C  "ː" 2$  ,  ,C  "ː" 2$  ,  ,C  "ː" 2$  ,  ,C  "ː" 2$  ,  ,C  "ː" 2$  ,  ,C  "ː" 2$  ,  ,#6 y"wȁ(F,j0ZA , 29*W 7OE^% ql@a!1E D&b51w bC Z|<9 rsp~R0l"{ P"DI@^|';r&2iq`A4oH`D+xcTN>sdI4TA$lRCu8*5Ģ*/B[U`PD $#$DGNŕ\ضxD,# /O-I&ADӀAA))L6 IDAT'#'OE($$1Şj UU*㨮a[vF&ʊK@PB0 A JD+$H`HB0(!8 # ,cBLm`A4$!_yt^jB|䷪EA q xx 1N,P A ɑ#rd9'"a%fW+E\ ӆQC8&0kO*!=j:Ze@sEe#ƂAYʑ9/{tHΜj sBLjGǢo[b,ɠR`9`yTE) 8} r/W # $…9sdB/B9,#8QkvN`X5Kݝ}abs5 AQE"1WA(jYx 9̔0-nA膂 ꂛ4]-^ >lʑʑ!Δc; D̕*]?X$o?xWaM(nW~"l":v펞ᧁZђ{ؼv>z?ߎN:AeȲ `ia_cqTL+B(WN&y!qtp{-fA"L3Ӷ ,ŠD&B9 rrd$I֭[1/6}:lہ3.E;탽nxks0md\{pgAUU Sdw϶mX2g'{a# !J_J@  J|zf;iwÏẐQ%$r!E4;C0 #b*!ncضhR0s"a=g~VaĿ(P%ppmצo?CN:}ioLEMsU nbs1+&9V&Ad`MXX/dZu)M k DJe+DgгsG<>5#''O`]~8\GzFvP{~pȲ EQ|1U!I 1 ;$'h: sj Q 1V)Ay(+ fb',~M7iҠD,I R!;Òyvc|Q1ו Dsxx啗V\s;n:uY[\ӺC *i j<ՇeYu:ۣq DcdU<*WA*)bOLV\3}eԊh,"+ `H IPd֘1-f"EtDU>bx @0,E1#q0wFEtr E*4MQdI{oO8 I`plq{ttTEz"L2*d I$ jN,Ny Z5 NyX>C"!jHF0("s\jC)rXmE&a:s.B(*Y<%<_У4`HSta_0Mch]"+J$"c>RQsQz mزv z󛄕w-))A(-[D{ \j>Yr'Soh.W}Y\\ȯѷ&i0#:" ė$$4$Q2nR{NԨEKI JLHDAgT)0 Z@,#efbfC۲n WZ2O|}k[*Ĵ'l[U|ޫ)5MeeѶC}eوEl"y݄{Uf +dE,e#~n%/ŗdSE% VIDT (Ab"Q'|wʄi4W!XUUb KSWZF07ue, K۶|o,:=q d2p)}!6JtǹC Lp `ѝ9rڶ}iHuuxԊiBB|j%t!-XD,C4.P|E≂TMg&ym0 ˖Cޯ/۱$~#)]MJ4Y \u Adq\g榊 }il{ozN`t ӝ ÀaxѦ=J>A4cLӆiڈ֑/lH"YfaGE aHI!BbL4H ?/C7aS $p+N\! *Q.F WHzmْv%8Ю]F^Ww }xHEO??{;p ?z _6$,J{su]Ǐ??9 Zl VoLHY]Ɯ/Y!DY$ $odf^^GV XZJ"yfrp 1z@LRν`aGɏa҃ a9S5I~?YE!PU$&"aUcع#m[V]155MSLޥݷ!6yݛ v1v+c888<-~Ie$pF?("<•Q~=nX6 cgtEaI{A d?wUJ23x!akm;~wyݰ`/t݄eY6" |J+`6tM6]vujظj>{ul߼;wAR-xoIM Xiq`֭<A܆x !5k|nXvBlY r r`Y$Z:n; >E/cN}j|836]?ò!\U IQ lӄkUŀCC~NQ9/,gW Z;׺s$(@E{-L}2L Ӱ6s Xbl݁=[ρ˻Lxޣxye0PYY uԭ'r9FDQ=|o͎6!E4:k[سy`)SByb Y,E9n5c#K~8)kSz*JXԞ&o?-ۆR, xw$=9ՂxګY'_l eQseChV6O&A0Wp<β,^:,m0 p겥,w VJr{ůLS=.M&V`6ˇmEDKbDKvürs8緶pok\3v`;'3cwnGT]ae6,omp˲` Hq E @~aQFߋhp Ķwcq!.A :TaMw9W^(q<''eY}n'={㓏 Yi:'B^ [Po EMiYp^ӔT& &OTVǹ̍Jv\s\Qe&,ۆi(hWI>X?2,g /M'<(Ʋ5_0[KD@ m idYf!@OXqEU7;N|-/L +7]4X6EW.&縛 vBQ=O@790qjTbxbHIxh"fB yؾqrrrRZ/x}N D/t`-YaJI̖[r}]ueErŖ㋲Gq] |:!=3M'<7u}>f H`DqlXQK~'Ì4M K A{muF[8x4]ajqyKB / JL}x!HK/ 6`m }GH,D% (hѐ"&ڥkl$cEX`> ڴe0ksٮ[UGVJb+t]iؽP =xqCWg5]$$>0]H`D&\/ŨPTXQp-bD2^~U0m3V䥈+˲uDQTVV@ϩb>j 0$sR[tww8blC%O+VKБ"" 5G"6s,ڶ-d; rrs1λP ؽuύ{gv UP8ϵuA4躎p)#PԱS35O4mX˴`n{ +ߎ )ˇKQ1g.yyX) }5M{1ݩz/mb^z!^WV,T=]mu˼eyګYgE={s.^_io}+n)-0aqR>1{6ؒYH=q܈\L1D܃6ԬY]"m \MRxiL>˅Ȳ(\}ɡCrxV䣤e `98L` JJ6o~41L#cPG7E/R 0t tip b#*e5A܄{6KOEE~\. 2( . iF>z_Ğo4XƘvꪎqp(HiLVFf^9f-}oAn"9%ъTiCpcK.#ݸmh`ފ&1\Ne5QKl4ղw٧fƌn<Oj%BP޶m$Isk֬[n!):D0t~Eიٳ?}gpZ\.%׽o~ʕ+1}.+^]Spjԩ+#՛?W @9qXe?8\.nw\\ I^ .~}kо#F^է>Qߠ$O$I `6---|_Eu %%*+`l|c#>l222vR xm.>8 A"E╲̆1^3FUU\.WbR$$IBeo׾Ħug0|>5((WYvv6Yv-~Q_p_r ^ǯ:e[kܐ+ hHaL*CoNjz>No 𧤒+b%1[by I$J:6m,Ļb՘\q(g^Zc=㉋CJ#"~;N}O<ͳZpj^A$^/9S,)9$l^qxn\RS\dgecYVW+9?/X-?H@?^͢ :_bl…쩮vÄX#*vlxuc~?~lfϚIq=#^/00 o4+&b$l`Yex/.|>ɔoXȊBvA HJV[%ni~ d008ad^E  PWu,\}M5+IIIg)Ev=&Zb"KeTULZZYYYdff3^lY}=u!?H$IT wi{%l08_FJf?3'(--% ю? 7J ߲uqq+Uʕhem~1 Wlp\qqcS xsZRӆbu5'3N#gZ^nN,cOвau ڳ3b&̈́A2g?X#Tő~ sLX*RXDӈA ܊'WE~~~J5\ؖ_LHJJ" iFrR-w~~GĝRsh8)sR*r}p8,Vlkx6 a]ؚsBkc'V쨯GE2sHɣlBQ̲tpp4p/ɓ rm% +DQc̶m t ޟ~V|hæ+V;O\ߏdC˲Ș+1;+]oQ6b2O} TSX4HHŜT y3K!'||VuNڶM(" d?uڈ?S49}+'k0u͵.@kK 5'kغu+}w,Ysٹ#~oKG`98)eLCJ*|!gg,kP <|SRC-b˺y{ocҥR(" Mlu̞='$vÜeWhr7p`I[pZ6O ùbJu0{%t.{222e HqIߤ&"K RP;'Y!H KWiǨz܊e6?GL$"u#Zy+VrtN>tϽ|}3f30?q 0 <2o`ϦYx1K, Jh'ቯ=ARҲFŐX`oStd哞G"f̚4+@W_}o9'?gm65|-j ۿK82п{,*!S5(r ^b%Q&IXe6lv7hLeTO?ƶG>1|>Cz8&?fSO_>x/ˮi㨭 >ҟq]j{!ɇ#. ՇbṆ;(.)rMUeUUڽ#s-;c)$Igo|e˖OZҜ-`;& /솛-* ӈW4'@ sQyFPU{JW ąT,)& bVsƎ5mp71}"^|Iֽ2׬^ܹs //A߿ oH۶x%r&U?菈1Wmۨ<xlG`9)@/^YG}󔗕~}%7'+Vp}ڵ<3w*f.Z:Yg2 Ί%N,]wB==,zju/?SOEJb{b'Mزe |{)x*u\Acr{XCT=X dg-^O<55=v1MmML,.@ @R =LIO0fܰ9|U"b("}D$2EE)erM;uA[bbt O8F~* `퉉p8itfnHʦ)/Zm%dg  `#084FbmYIrZŜƐ4ְ{ARG;WZw"B`Ogl❷,qUr5qԌL J?eknDq+DXNk}=%%ňbtىkȊ:CA 3/̼|_꼏O:X~ݍC}~_LČTyUUIlC\ 2'tDi8)Xxtgˉ}%HXX CڰI 'N =#s\[X϶?q2EAe$BA6-۽|'Or͍OKJqtuOHOk3{/>#%%I0MG{n^Ys'dQX,Q%*Ĩ DodWP@kC9Eg9aQ\}m!u IR?.be9Y]EGG}cԆf1bhWWݽ|OJ-iYټUp8_˘ .l!c^`,4]1ʲ<l_*xI(uT n*(*DWz_|?HNKqx-]w/|$\.Wb|ҥ,Y]|}:`9\8ANKiK?!gn}pz:!QYme Ѷ亖^/%[>AOOo_v_o tuu{%nx/fֶv>/]0egQ\.J h6DSes!Zm#[[x7)38Ybx RR*n^/}Cr2@fCa!/࿲yز#oc󺵼y?⟿ IDATUnh,UUq\yڱ &ru,D#ul;W䛾oyemEnn$G:V;_CWO] "s\ Ύ 躎$,Z^ 3[GGm-M=tea?~#!RuLĎK__y Hy4c mWQpjj^ODlA~L+sa"(*9#$;^ucj:UǛ|_/+xHITȀ쬈k,HOCJKn7WteY=FII .kPɡNE1nz?f˺.81Xc@Jv.'jjh%–ll;B<@`يKtNqmC$Gu;7NP%sPuDQdʴrL+"7`O7iD^g~Co0KQz#B_i`0HX,:nnTO#vBy nA.">šmn2)hU~}764#1D̲܃Puֱ{^VvǸVν*I(Q bߒh D^//bjŸvu=ki˺dr}ޜثUXR/~ڷxDXNV^iYH)"Dޱ*Ad/qZi:u ׋vƀ4%;^tTvP/]E߀U˯EeM޼cG#-dⵛ iY,:_|i{ȴXNT>uAa,6Y@ zD?;\˙?_7,Zn_Ff"eq ~22CU,EY#JXAMk @5E/xL^{=d?_:vD1w#<~O֐W2p1pèOkk 55"Z"! {"B! $kušWד_2m\4L31GۏEvH(ʒkgɵףkMtف#9-,~~vȨalkB2lG 4JyUaa~42rٳuo // 446PWWǩA毼;!C\i T1l t k0X&tuE ,VUN^xtv2k֬~1Wd܅/#&Ҩ(<3Y)O:7"6/*S.(#\LC| m/F-P Hg=~0Myc )3`ڻx+Z8D{SmM k@Ԭ,RrY6gIiz,8]],1~K|!meEVQq%`  s@,#&-qrD3f(ʠ&fAAXp!ڸ鼎wp0&ΞKyiZN -X)F,0Lt]_'<~m2;l$,LiVK[tAeir7;]˨3&jô4@Ai^;;$Y]^u1RQ]nr &|5˲hhD[?ae`ZU894#1X ab6EBөXU̟7wH`BCkHb/08aX[ODZz\{MZP-[h0X ~_R լlsI]eQhi3Z>c\Z70S?HQxeh{JS`82&w:CC'#(L](DJ'VQiFU]qL3"BH\cXu 9%4W\8:xi8]{anK# {>v ++Ӵ+}l4ٹco)3yU1̲[dYͬλJR)XNYSsH>Cɂ!P'(^VߤF.R.p.VᘪW1K?4K9q-A/}SK9|l0- 3f2L1of_{\` B(kutҲKMZN.O_NLfJŲ5!VBjr/_0Q2 nAn{o|\s5QR\/))DvIm]︛E471[?e6kŘfKxS]vVdIJ#7JyPP/_VdJj&݅i`H!dQt !߬*Sf%{>햅tB1>!}bʈfƞ3k0PaKיR0mA4ve]\ ŶXh@KXei{졠lDkp1pØ#˯`Z9:NqINI4^̼| [64I9,M ?õSDlbScqh2ء^APƔje']vaDJ~u>]4vn|ոTEZJ*DjOYZ[écU﹍̼cXNՁ!HS OX%t2'dDD=4ed]17AXtI94e
    ԴTRSRx܈@[cQu`/EE!5koSb2RQʠ 'bI*%(YdXdNq \x:EQdI#Q*.5bݒYq vjIGb{ɤ.?Z͚[67dmfiۘ i&!$d hO"W񧤜΄(L)+oz+^Y{4#bMCg)X+G4&#5(l& `#Dn: rJ.WL"j jЪUX]u`4 )) χrr=|>IJNBkؾ ˶ȞR[xUMX7VP#ORw l BQʥE&j%Ei )qq͉ XAژRU˅r1lx:B|Rϳ(楄(I[T-%NBT`eU4 U#;>O;:IIiC!~OX`ii sba-]#GS9I#5":[[h;AJ4ם`o/I|"1?EdZ-X1Qh2 z>ԴSqM[d%zRȍ^VdTEz>Jxff)-Ut#?Y9#(zynkD)JRT("JR]lfDW8e٘у)5YQ/',3}22J{eZta oEfZTtlo wͭ4a-] 747o^?W+o}5;9\N8"t#llZYe ISs {Mg!sNz$^w򧖒=s6.Ѷt [?>{/saڴi(J;CaF^߰>3.q987~ѹ/$ SӰ,c=~t6S}hŅE,]ˍ,K455Q^fV]䛧YmEüQCT%R""6ih4ړ5,xxM;\hyurKJ!ۿ۷q5(jk05(r܍lL$  imiŘfV dJ<Ci?MjF&nqcm޴ ${z5(2$/ew͛[؞^zbsZThPQq%rT)($KؖM G4jQD:I̾l.4uU( kUV\ ͘#.¡0,BWw7f֒e8G8r*ނ)`` RMЍ~̀DY"H34eFKV3¡7ƩcddSTX9xN:Eͻ+nKHVDlp) i=w{4[D~,A 55R]y/ǝBUAAB€K} ݈"F^$z:Xe[2lUQXl2ڜضm,F~hmc&fB3s/p#vt $t z/Zȣ^74Moo~[ ˧Sbea0>8avx n[Cc4JPibeŖix+|(6CJ1t&m'=DgS=_9{V@Z1VKLjj*}j;J=Ʊ`Mp]N\ |[ jT&@ 3=ގ\cXf"A.ךÎ++CBecKB$콼c}ΗN9gum,+Jl" Q0Qėi5 ˳_e j%~m 2B 4\UC밞|;("_,6y;< ;<{Q1`x635c,QOh~O}S|HEcI,Ny]۷{)`DqpG`Mpz{HfB% /Izo=En1l;~uXlHv4ܸ-%sYB),NՁ*˲- +ivq9iE݋V  _\2&œJ3x,(["Hԛ ʭL:kgY%<1opvR,%lJP9`Ml\ $!<ΕU+)..\_ľ0aD EQ'?ɿ}MqEp\?N,6 ^8hq=˦ wx|>hs/,;b-b2 =޲C#n(ӴDwc\Ʊ>Bzvn@0niMqU/*J0dE=qcXԠ]R yRӕ&C[%,܂yWN! kMFTiNik4RdK4҆|s6nƈ P*V\(L)Uڿp&5$%ֆm[Ͳ9 ,Vߣ#ˤ_1n0 X[tQdm7v217rӴn[X-es\uQk| 3Gث؊>İatvvRyu=YPD:݂pV|e\(lSNP}g#bpݶ]t]B)-b9r7s'\-9Rׁ4$ IDATLM O)`l'%%rv2G`MpT"v{$j] Rdfo^ g.%E]G\LQhsEE'b2#et#b5 Xpym AછoC3 1(-&IѸqKk{;3.%ώ=u_>=415 rwGgv`D/gC #[^d:_ḙ]Z!\"F|N} % YErBY^N4CpeeCKZ/ J+1%VwͲ-H̼198 kKDȴ9ٹ{;>ܼm1%-2u;w ԚIg{KyWa>/Z0\p%Qx1,ţjswS,Yff +oe7*z{UYղnd [׿L(ƥTWw7rLQMAp8LH S2} V^$_ޗ2أ+Wݷ5Lnz $ZK( j"bs>Z9CbZ}(9JD{3%3Z/\ЯdJy"66- YF$Ix:\<.$—ʴfJY`! V{>V,ݲlZZf\"JqȲEշW~kYAE$ll[X®h|Iɥ蠬RI".@*f݊ƦNMM 96>D5HbޕWsAL/Nzz: @Ww7m457qsͣQhԒgF3Hfފ{ >Ǎmۈ%Zq%t">lwN ]]=NN9c&^'$A~Brssx"7vٿ?esYs=]6>Ew[WZMVf _v LYA:|Z2P\EDfwjziyxUIMIߍX9EQB k;n޳{7i93KG`M2dYt|:[[hhn ;q\h$$MJaޕP>+K&LՏa:ǕRQI6Qt99l Z? ɒ av\T6IwO75SZ1uDwx~Ԓ"~RQQ( ؒ(E5 @jZ%S+x駟:pYIp0ѽL;?p1գAfbZxsfvl|^ 3׾xIή=ǃ=h ,INt& 7 MػgUUt߃4KG`MRR22IɈfڶMYQPRKL:R$*rt'b[TwֿB]u^ۅ(JB_{-6+@iɋ= iY.4YSs_⫬^EQ"*-([ض?)G?(sysOLT˶ٿu 3Xl)`#b aDõ\CٴiZ$I!5 T.i׼L[A+ݻvhQ$7Yc% =ix˸:\Hu=(exmho p APT9BFՍf#$ Fd$-;immg:|=}fԭjݖ8q;TH!p!dҶ]6ewC @؄@q7}i3g4r%,͌wѼy=J;RwLS W\7\ $O'3f@44M|(]Sp$̵KeʤIc ?w6M.EE4NϴmTˉ@wEsGU$3AlA"ђ(/cYgˉUF,rh#"ռo_VPT8~iOLI *Lld<>hzZ;{j]{%Ge{{,PIAk'e> ųu~g |ߏ(:<24‘@ANy1{5g=޾n8{|,@S := SkNlYszLKXRmhPZ59^},7ߌȘݰ^ˮ2M=w_?jQǥ'.cLAb: f'M^ tH~E V7&r%!)d?A fE%}L?YԌ*&$$I²}fϙ͏x{)iYw,j`6j6t, @0RZ^ȩ{n'C'DjLFxqDӦSQWǚ^fy]466 iʊY~Wx3MFq ̱8('Jyz EDM$^{4M2`pL)5;l^1VM8H&yW_{'IdD%+_җ=LӤ jdlUԜ誔- ~ƏoXӵٯ(-8! wgF}y:Zin,KC~4kۺhm=N([!4&O`ypL!-h2i*8=‘ݻEEQ% YՉa`YĪi:Q{+,'](ҹzt6q^G' "rVX)r”- ,ض}=Wy_sC81RRRR0aNV*+ӥ13B[U0~ /U&͚äYsmھ Tm.++/IK O`ydH }Ĭ.]g҄JgFA@Xmt]Mos eLG`u(ʱyl]*o>,7p=&M2eDݭm~q n8K_O<Cs!)]Jeel9q\lsMӕS)x#:TG{H1ߖ/FإLEG!d3%Cl^F:E8AӴ\ *)+/' kZnߊmEG>x:$:2lʭێ|>?GZIq%eT =IJsFNN~ T.Es,s}.6v6s/aE~e+cl3?{ INu:MnVY8TU.C X dJa4MDƩ/<AZQ )a~y**6*VIcy׆u̙3yr~ŕ|kƃ> 6o[7 ш#Xi,A)_OOSvX@C`^`rGA@7Qƻ= ;IZa nMi: R:[RV=PM?t[6:$#el`Yzm%eUEM`؎`Z{niU:*taSb(iivGcڶ(D/ ANu#%{0}[;N="v1\ru4מ+( ,ٷm; <|:?50˲Hɚ ٻq]:bau*=ݿqt'Qĸ MOLlcө$[V`?H$&5ɦۆ#2+ߢis#)#͎ömvm\u؈;nNI0 8BH4Jooad˲u^j9`%*`([@dl–LUVI2!=ʣ;(#ˠ;XE줧`8g&B S^CDAĴLt=;vO$8k'w|Oi8ˊJ&صqGޮNY%Z^N=npfrR*)r"X'<GFlPewt( "8{'?7x_|A~~t59<_SO}ڦL=7+dɱ(ѵZvn45#t"+Y|˝(J*Xmױ, l_ H$V+3V"_n**[MGDT?Z)۶6L`UQ^%^^?]6%pUIAۆ ]|qf[Ȓ;9cv9{'`EPTEQM=ٵE~P@ fF{c\9&1 S70M#d7XuI84$I~$Qǿ[nb^3Mzs͵R4@ D$ LLB*!1 d2$qYA"` ` -kdoƲgiGⴱ)KCEB8SI)th'0yk_ʊJNo':VU9ͩUuw(f)--Mݺ>?^Hk{?' 0~|!+1)"eqp Mu|cdE;ȶxc>D-Ҋ ,iD$E/=Ϣy;ށe[ =q]A`ĉ|׹-ATUE2 eYhʛ/~?>/+TE.`@0ȸjfNNdu־~ѓ)b(2 I0qkG   QRlDضfY\bY|ۄ~Ji>gcI *۬[FU4Uç9s . RVVSୗ~;SUXXwE3a qžاMNIؖž-,Y;t?~< to쌏\:ݝ^GY( (#]iZva3 ^8fIuv揯i8%A`ʬ9沂r(v>]qe:a_G>bVVђdY)H :'z( f#N|~?h`%i>jf@,{9}Jch4B~Wh)#-R^VN4F(ʊ ~e7jȶW1v0|57CVh݄e-VEs~؈m ˲0 aŋ`y!<1 APTm\!9Н( H,IJټmOƯ6p/伎C6xdKIΦݹaBՑW^YE'<(JIi).* :]qNaYґ'">f͢B&i7EcJ\!$9 (Kܺ׻>?H+^ѫL0SY#E,*Wmmm?;9޻ MS26ר:#Fl:c1M 0u=&NcFFp9 ~? zYli=rn"c :Cdv fv,+[ /PY^~7ZSUFioXE4˴ XńSyRtvuM;BB eAmȝ,I$"&`]n4MC4gVp; 764 dSH-3pݽҋ/q ҡ'J?wxqowh^qg5VGDE|ܸlNRii]72qvEJ(t?-VBSDQ'Ȉ-휠4L#{nS/dIfBjh]m:Vo91 ^H {0t IDATdan'7,# kj#$?7a`FV\-[_zO7z{dfӲ HV:tYfbLP d ` "ҿsz4U˙ Uƶ,LD4#W(NnKǾm[(@3,+rxWLjU|@mg(Ncf4wd#*T,5T?*b5LojPT(Iʔ8)E<@7l b b c  aڙ[A$L$,AZtn0#a"c{\H( ]rk\d4MLD0(?=Dr| [/=R%JJ|}HF:)kByx u(J98J29?F}T:!YGL<6 ,@עzu0)HBoyX ?yя|dk%eĕ[t(]F)Ɩc|?=Hs2`@ 6X`4iha ٴS4 ,˭Yu\1&ȶH"D-D,d4RVrpXI`Z- C4_뺞vE`Mm®k@U5QBm²ډS}5ƨǥ'o!?OcfŕCSҏb:Dg}IVek' D҂tc霳iǫhT%WhI(jlrbςr;sHSV06(@Lß;sa D>90ذa_Ypl̡(#,'fm!Butn,,K@!eۅae ML"mZ|s]\}̘plD;oB3ȶs+ٖB&;ƌX333g5BUneNDN4EDA̼V[&eg(cM z\Mfsk\F&ϾbtqY ,"+26od;#|_bjha6DI~q}W;-v6 92Ӵ%#$ +AqK):+[N~*5bA)Ș[y*c&E6sU2mXBa3/˜,'}-8?Evo\φeSQQ1| d;'0PRe`--,~c7ǥ'5U%Q0@d(?1%v.T*R4hYy}hg m WMge"6=ɵ a"/wí1- #s{2Niݵ}U套^|T7ǾFyu9k}*vR{sb65lzvĕ('W9D" JT֟H=&rضi;EܭabZ6љy⏿ǎC<ߺe( PcǎOύwzx O`y z:I2 #+23JMB=*DKB\T:e\M_g҂TdoD|;lش7Z(2 ɶm T,j(XFD2;5=0 !SD+* 9AodkYoyn%^Cmm-XNV۶m^gٲeklޏ})8EIaT:FQLJLNvWvV\ٶ9l\a,p%t]`ɳ禙ؾj9ᛦd"5D4fĤe[Z3rix+fZ4NisnDDZ9}AUiA, XV|ȟ!e']]'%Jq(eÄƍ#@M]t·W~cnp 9?6:Phk.>7%gľm rAwW{=k_`Y"&dDۆLZXč~A=S?OIY9`BQU>.헾LW{;TXi)dJJKk`ʕ? y[z}<ͯD,d.OruWӃeeLGuIS,d.'blZ,k &$bF(OYXdMg9 VY} LLEMW,Ev6gUöW?O,szIEJ}D?V^+JN'Nsŵםq>(/1gRv_K_ok`Y"h!Ib6N@(t#/wV{g&3m4ԉJO? ?>]=DȲ^S>tA.efJA|c=mj%L"2ӦMcM7ٰ~-` #1b,4 ^uwqө4iwNH%tSVV_p 3\ [p^3pS:/ETûwz ,atHAs55W"9y@UU5v-t>̥~ Ci4Wϓ׻/c0tP3N]'Ns9Ӻ$8}˼_mj `Xb e180@@?s/emw"Uo~@β,y@I4JM atvvLoZΛ8= nZc4t *">cg'<vjf! U#۹K_ee1 N{M::;) |_RPhIvtu'DQŊ(0xBe4͗M= $i k>觨kg.]'3g>7s}+VPS[aZ&qzz<&d S ^g/I/Q0h[`[NF3L,@]<.?OSS[G ν1^1VE[/0)m3AmnCCR-eܟ9nƮ$a|n( L8|Z<]4UE$t U# 0[<_?8흝T@ mqiඇf+˶I!) >BOAE&O] =L%6hXoMG䋨{& |_&Cbƍ?dyzl5<|w >Oq7EUU7&{8"*clzUeCq6xˣt*M P\ V6 )r';H @O'/ RZY#eZ}$ɨn$S:X)s@06=Lh`$ByM:V=BEt=SOO=GUUTU-4\\=/;̚S \:r Qigx!x7epFuU*<u4wDhqq ,MahQ-d'~e$ "UCa#"͋y5{;9B~fjc~Jv(3H6{7g3fP<"L$ikoS3a"5&4/*bV'x.xc&MjŐ$ 8]L;@x HX³ys;4 M=_S<#%faFr;4 ܏ sa<:mCrp(L('< |~Zʍ;*s*$ N6M7 39w(FemBm-4ς7зZLMlWk{io!H(#ahֶ̫V&ͺmGg'I *S)?d^@LQ3{ƌy 7.x..n@q{Kc @Ylm_;D܈(eW?rsgJtطRi>ˈ];IDKcOQTp{(@d$I&Hd{NjPdA.j|fe?iwsq>ɼ$[YLKm""&sԆE1X`6 w_fzzObhT1V$i[V%[CSVޑ/ t=M:388i̿ўbQl۩ĭB$AUlNQt>9"KD%dY"XWǾ-G{=(UUoL62ܯD,41-t:;}{)W{5QgKNrA-Zf'NDՋ./u"2W/; ܽoEE T#+|ײʷXW&ל~;?pujdSg_V^MFUajh tZ'J1շ=fw?Yʹ=%ÛX.* mtTGFy&7qEc̞ݻHRwtb'ؾsPw?Ŝ=)?a<}=##m{ދP`U7gΝE#U#)۾};U5y׮ J'ޤrtԚGH *Y]v7-qxcrE#LPFJ wf%Z+EkC1bt\e[n۷N&. <\<1"5 )l޼\L0)Ty8lB -_J8d7Ң55) I _>Dd@ ߾qMشeKA[%4,ss.F롃L6LD], TVV2yDZ>C!jxqB@`(e[ t2;#~7:uVCa#nO9O.@]$xai+Ir%7ZeYVEW:f 4~e"/ _d m0a bmݺCJ&PU@8LZ&6ϡvDD'{ZNJX<>uGX8o7`M2 b=6嘋`&Kzuu$+(1{X\*m1qqX{{9yb6 oqp#\uu߼ xj'N"L$ y0(5j4d S#9@8QGV7BU,eS. Gt a_Ĭnz`?^ZZZhll̊+QQeXq{eHWdD"kCvVc;"|^-A?Kun-uE"=طm3F:[`KNi ڃO<OkUءx9"(N[.Q3VAU̻ŰZ[JJn槖ʷ0"˶mz)//?%UYYAw9ǩ ,SBD%YWu:XV0WFMP(*c}o=#ĵhFy$g ,.G9k::Rʽ,T*E  IDAT"'@T5'O9K&xwƟ8=B. ?-F Ȳ)vjëڰ Xȣd}S1H kOis}#8c;4tTM#)aܫ8ȰjmRoY|+][ #߻}O,2,DOlA'<w=yO, Y Mid2Ν;ǿˇ3J7:1{Ǧ/ǧiTWCTEEQ(tlKym~?hG[odYz CxjIfCjQ0q s>a2k*61Hhli|~ M¶9 0\biO`8 b {3+DKmGDebl)eY$ 81jx8v=€pFDI⾏~__aiC=+M3J$|泟CYU9}1Ǧiq("8 ]@ns2i{Gl+0طwҋ|_J1d$pfT74wfŊ_4TT*E2WG<'H$ؿ?? S/Yq(E/Udŕ$IqR4G0$ Q_[Ϻ?ƤOsEj-& 뜊3$h  S+ZS)>mn΋P"UBHIE:=NO`yx.BE0+l"+)_7cݺuO>3IOGQ3q;?_gx #_d% ~qRu/)>o WT,;}ueMSA"0XG4:m?oo`wOLdj Q$ R Yc.)VF}y" `DZx;G /Eqd[Mغr9;wdiL PRMtv9o F.7AC7طu--t8` Th~G ;u4lF9Mcͱƴ+8=]wÝ#fFؾ};[l\{^pZJ`Ar9}/l>R^Ɏ;h Qҽ6h[#iBBto&T;vP76Zx4pk9l\Ɔ\J y/eY5k'?QX!|j3kﺍ'PG䲩˯x%wϸG{g? om[X'9g>n&41nD,.f/,!)AdDQ s}~xRqE4 ]QZ/_EKƬߛ+VSf3?6^uk֬,Xͧ!Z"`>5X]]],{s2u0 5[7#b5QUUU p s{?w4NnAVQ1aL&LoW'dyfߋ$Ih/CYmeRN+ٷm _йȚϕՔ,H`"k#9wA&U )W{J+d 0؆7 DM mb Lرc޽K;W/ ,|j҉_O8c%ڵ{ɓ'SVVFYYl륫68@ôT֍DF۶y=Iy4??QVVi(d" 8"ʲ,z{/+?1w|^R%{zTY6 -9gtnYndHg5cZ`#֩ 2r':;YM`9v`*ђH־Av)5#ԘGi4"b+c]\{m55ضMZVN`ݝsp!zk9g#w:bX'4t^IGڎd+#xY~Y)ey>[9r}==ipI$¬k.vB5PEI%+Z-۶b|/O[^Ac{Xh=|EQp"TR6k 8]۶W`1 #[$"~-b:g%SsEz5fS+X-@gu=6ε( .]⚯?PU@ "*iwPb;;f[ɓЪD&Hxc ̛7UUEk؇ ۶I&|{%ǎg+5xxc:/ʫi l~~n;Ͷm[ٴy[5w 1S8,{$fկ>M L\ _R7y =K`pi>;aoi:_[;M3פZUt˲߱%lsEj-q\Ɗ5h@ qʽn_;7 io=+D+*(:DFvSsr9K-<̯GyYeeaz{{줳J1g ,!X~W9K^i aAA`fi 3g`ǎ<_eߖ\߃Z`5y׽PSS)$Iz;9|NvXlGAeYadlZDzad5c |9ut$WђHQT(JeٲYv:7_MIfzmi.eY$Wb; c9qLAH @L+~?WN3 <+ P#Z]zG0F(4W. y@ Ek#=87:=kS,nTbooh!+sOcQ~['B=T (dY}tvȱfj*?^\q2˫?׿Bjp5 P=za[*a͙3jH-5k#.wJml²|Ny*Xű^Jl :`U|0YntwMdWpK/ O VWJŭAЏ8.L*Գ>{n!r`?FF0l4 :u!K s>n¿> s$EQ4իW:}' ׶J}=E#TMO4Ij[av,;2 Te[omVe++Գ} |#5Z`Űꗍ'b{z%pֶ]mgS:xɒEtgvس%& XB݇;Y>۝l#.\ıN XZfpSvF WߨJXcq ;t.4+ V0,8# ˷ʕeO|$ 748pƁ#ޖ~.JU*B%K 3tҿ#+FVdK֌dHHgd],5ړke6;wEF:K+F JQJ,¾l6K.__5!3WzIUU;_"gN̶!+My7?y<ܼ*)L?>wyDc#ޟ,!ػw)KuH$r5󖯤yfk/CyFV­l6g.OgDUjc>d+}9b(Bp A?~:Omf[M,Z}x\~͝_݃(H,Fʋ>a-Eo3sRrL,楟aōw+5!U5J_9:H$5\L!`+/UqE㣮1ajt cSF` 7o m̿߹ >9^hOw %_[WkE1(5پ-/>OO7ZZ>}Gؑ#$khhCmcc/[G'腱j= OG Vvmp;|p0Gݜ<_%D+oXt)k֬- WYJ 8p7_0#\ʤo[$-YEi|h4?J8ʅʻkx?Ct̒mi<[#Nj8CzpYh.'\$` Q"3;/P]]]W18P8>s憛1OltCy,g kh<⏬a盯V-a\gٚ+1N$` 1|W~w/}U."2qϽ.l~kd K\T?_M @8,n&FV^j?CChɚn KQ(y7&ϣuV+'N{^::Lղ5lu̎FEr5he+hƛ> xPz\L&C,Xu1*S,!셋p1s('w`T-bDJL=*SJ&֏{;۾M0 M a+ O)M5n&UPHgASU[f2җ"Ą+XSk$EQX".^ʉ#ٷ>2,bf$96d}T XB!DTgUJI카̞[KBB,!c tpJ3!cR迒o!B|u! XIB1&-B XB,!cg$_B!D g$K!ĘhJ؃%B8B1&?!b$` !P3%bL%F8-B1&j؃KKӑ%bL»AB|u!p4 qzBLr$` !9Y3!c4'K!ĘM4 qZ!bL&wG*XB,!c"=XB|u!9*G3%bL䨜ѹC.J_J_Bwm,ן,u8y(]{8!P $Dnz ͳڨJ*}bIBqZqń3<UAC4^EŴXI˜y]ղrYoB=477pBZj>t.vÖWT-_ŴֶJ/A XB!Fu~߰2L HPJyV.=oUcg?9s}ƾm[Yd1_җF4TU-<EAQ8,Xƍݻ'|;e먩y&K!Dxygs$5OniGRm].4:6[_ބ:|sN}}=}.%W~Ζ,Y<ԯXzZ[gWfAb\\BǏ +3Lfib:*$ (XZo{;񳟧q.CrYxqZ[ZpkUZ|Bj]{ӧA.]^,Bqֲ7uhlj$DD"aiFFĢ1xd2$1>0s,logM7Õ^xn %/CEӂ̙3{#vqxJ/S'B?uj5I41#P 00 h4J*AUUXh4ƌjy?>oL:W^V^*V| JVCCݼwwWn⼑%}۶rdFJ7–`X C'ǩJTJ#JňD#jmQvj7f=Ǐ{8S@[AC|kk+7nw_ل?.IBLq١a鏨I*TUmvT[hH4B,#LۇOoa<[7ꪫF#^+* {&\­EMX"qsW$*ABLqo<F M@QPoo6A0(nwF!]׈F"VJ%I$C\';:ɯ+& XB1?4+Jyo(=Ea<sq]qm۲ql`Ab_RT(v6,!EǞ۾qx^҃x3̹h=tE/C%)K|+SP\_Qp )$`0xxA |\#1 ©R5cz!X~nF ŏt'aX ,=a X XBQ"nOʕ+iooG4:;;ټy3o=^k/UT/J&WŠSx**>_l}<7< }ߧ*9iAulwԇ! >nu^ ]m9] XBgf~or_:"iL.]%Kpwg|Ϳ~+֭Ƭ~z e p=Q-@<*7caxr]'-)mmNd٘WBGFTa[z>:Vl___8o$` !4ٷDD" ާ>FM0Mo rLV\|G6u=]N U nP*<*YX0l6\eT 9yd]EۇiU7nڽƙ3{<%Ҟ~76OP4XNGUUt]o皫8Ë\O3N~ouv!,ٶeE|uu-++eXV.6zJ/5͜]/b*JV+VYPĊ>{4so'K1^+8;Â%˿d+/N*Vy O/δr۱+ Y\0ս-Q:6{xf/-dʂWR:]vЂ]P|뭷HKTUz%zO4MZ[[ }V4d UUihh`=8ylP/NI USiYmV!T'qX{sVxgaZl^~U- Y ǍgU|+cu]2a^yeW}k,!Ĕչw7/>4cʪ+89GYnmU4^,mc<e[?9WW ]]](+l7"kqјgǨ'DyW}v>\hzм5[0 X˧zT'k+bqIBLYGeҥJ{?jJwN|2}~<{bH^]_:^ U+˲UΖ+l p%>uMܫF;O6VIy8(^3#Q]CB* Y~4ªVȜpo:Gp%^8$` !hoo/{ȻJw:wO{{;;k^ۆ~Fs!>GW]q5(1$3! Bp tuuWXSn jy<~3zo.ɽ7M 3fҺh <;(KWx q^/c ]e۶mʫ\t5hɟbJ64rJ Ypj{tvvR8+`jn~*/MV#[H6X#Gf@ߌFITW32W:]p6/E`ĪܛQvRQ`nӧa/>_-λ _x;vr&K1e̙ǻ۶y^aR;U0dYŖ[i=ws69G8K"~ctyߟBCK k6>lBe_#N}֘~bDb9KIr?e\f-h$?=;1ߍҀuQ}Yr˚ Ō:"K1e͜7~pIM)+4ۥ̲,6oʢ׎:\{/?~}.O%nD^'b7sief8\}]bމ?嘙"ܷ};haھyKrnw6ϜE[ٳm韾L&Q0`zyW1}j/> XB)i,N8F5k(\V(=O.͒fٹc}KXi-ryy`cWqRL6EbX` S=N24G4ijhЍ`}rEWAɴ9\vFWF4`eЮT'QS]MUU5twwil͕~)DS,x o'8S |3}}V.#O.ZJu-gMVZގLKV,b;6VСC8qkJѡxb#}!|zL33M]7J•V6V#G d,'/ ־xdώ ٕ&w!A7L{Nsn\aeYo/يӱ 61#?}@"QE49%\^ Z]qtMml(4.>7=rp?iATUEQ c©A4CE)l|'"UP%)`~ !8kjfe芫i1tm|lF&u~[3X0-iieJu C L3B<TmzRxx,FSs35 )s pu:aϜ%}r6㔜3iQDgx,GLQP!&K1y2z}liwmU+{]7 "I4%S]]M]mMjkƢĢQZpH'lzKPJ9XV'ƶ-lqT4Uco\#& XB14w /ރ -lS_A2t=_5n9$0kLHOBSۓ_2E?ZN,@nM)IB7{h4_rOcxW% V]AWųK'+ A5t]'Jx՗*s/, Tիpkz)q]ssh#K!ю7^#l{C S')hjX+s"-q= T+ Y@XvWn?/LxNVz&K!`_/!X[=5P@:W6#a[ Y( ɚ$'tb[8ܪq_:] Za †qe\#K!@o/f,l.\[>~YUq\,²rXVl.+?F4#{Č97"\U@4+u,ifUz&sbzQMFUqF wuNm t }]Z9l Pbh*^ml6Vikp&RS;,!'(]#%|[:NuzxWg9sn_H>?D7J-m\͡mV.*-]慽~19HB h_+/bﻛM&Du\x:"`ͻr EW\y\3#QL%  <\CBTȭ_M^|TWUQ]]jjp 4R). H%*W|vtwP]]iJx\yl8TӲ-H66RA!.d[fy鱇Dca躎xVlYخG.?7Tr!& XB1ʕ~6~;epnLDĨi}!K/YEKty bN!@ d,F<9C?Coħ*|uB%sbOjpB!d K!&0 W" XB1yv5Dbr%T$` !`i` 1HB  XBL&b`PePDBL`&w]DBL`^JKIEBL`&w4*Ĥ"K!&0`)T$` !)eL,!<_"b2%X%KIEBL`> >J2ABBLpaT<$` !'KGBLpI(Ĥ#K!&8%#K!&8W 1HB 8lT#b%\]41YHB W4` 1iHB p\"=X#8؎]H!xnK1 t;ʁ;8{'!$>4x,^FۂVr%K!&8Ѓ5s,<G"bT4ֲG>'f1ɰw;l{W\˯DմJ_b$` !"M&bLkl0 t]GuTUSI$@QF JJч㟪 ŅNBL=~Ӧ1L]Hk:il]ui^{Q}%>[K}ӴJ/ygHTW()+ `0 88a0}o6.^ZE ,!w6=?x--a`e IDAT&F4rC_H$С+o8kn8Ygfk*Ta{g]Fia)6,q^IB zP@uUf4#D"&:Z!h)阴ϛGm*+=L|_>bf]A 8yyU"OU2YE ,!#3O0yx3bD1M]t]ʃ*b;6 \E:ӱwoUeuB  1EQuH$C|x-KL1rBTc U$bF>"\n8UդRI'HH&hi{Uz`OVp8mcYmcv e)NBT3?1cQA7 0tT%RmAMC5 pc1U4SW_G4%2c}߫?Lf Gۄ*^* Wa CVi/kG8$` !8:rT2GL%/-li^XU *[xTA* V *) A_.e,qPrAu]RNH,ƺnb'ښ(g_á~*t ?7[l4|lfX/ϟnc.y {%mhTc#-s1O,!GU5I,+WC{cO`4`I > Xm7KבkJlG;:MϓJ%i0sL(lÇΝqhv_~m( $` !82Ld1M?4=/__ *]j>` a0sqp=˶HIԐqQurKTqpVޫl6K-3YrZv* G̽C?KxXhxˮw=lx#+W@7iEEQ Jղt26ܸ69˖3grf XB1ޖYkO<T4p5QBPo i,*;9ldr Mu$)LD‘ET<4UCuw5揉sKwY/b"Q=J_u=_u&XhUxm >ʈOɩ8 wnXV\6G#\z^[U껬mbW9`-X"aFc"ˑ,rE&a(3L&~z +֮Wc9%BֆyԹ=HTDjP߫(q0I$y駘5:5uq Sk۞g>BTGmg _0ll j3 ߤ;hl`{OO7ӫro9z0<1UЦ2J/_8 9"DԘ(!D/g3T姹:$ /MZu\2PT nQ0q?ʘ>o uuF$` !8Yn13JW,|n5ILD\ XB1N~>1y I~4=j=-s_?MRHOTiZzň1.C4Ci?yH)~{.Wfc'2}ؖ 7IWc+Ƈͅ`埦q߯+n XS,! L?H˶t`ݿƒK}b8*J0RUMixy[2,}\y~^_CF{уٳL:'u)**.}*)44`mv.,^ߣjƋn,0yLYwyd2Y ,!8Z:"~wS"~y|O't=[x! h_d꬯!U&Z;Y}9> 5=q_=<4tb S膎rwd߶-hOe\{^Eg5eolhݝwp+Q>լ`5Zy}|?ؾucG1HB3p]cйw7G%GslfkgԞz]hBeGb*g~UU,? 3qXUta`fJ,|u^~xUjkI:aU<۶6K׬c 7jwYavs[UxeNu2@?m.Va>wa,`ˉ' HT*XS,!8n{Zfd%l|-l߾w^zQT︋K_{O>oLz&]|i_&ne5ٗY` gqX#|)|?>,8k{q VҳTgB((/V%8jzŀfn3 !:tGV9a?wx{񅫮¥^4 x۶a6lʕ+qŮ;q\ m%/7/=7>'!';,}+'BKJuyzOmۆe[pl×yp]rD^GOI,:u>YO?Z{bz+UO, \$1Buݸf*=Wc7NC@Vǁ8&|xjG?ַpw$fA);7 ]q4>w$QqVR`pUh6ŢE0<< >Y ?4ngЇz@'}..|z+9 ,vcǎعc'8Ig֟8M`CUU^Yz5`݋_Oz1&blnN>dgԛ%ё%B"V[?P+ Je^4}݇cV+h xQw,T7C6)}i13MSSJPάΩ#>Z {Ǯ]GmEp]HeTUɡirȊ{/YXl8g2`YZTLA Y&[ !t*1g_aQbΉ+XD4y,Y[a [[0]w߃kOKvlQhS渒trUnjU+ct:8Kpf'7|sO (:Mt89dU/Agm݊Ush 'oB@ iVjxԷetJ{KTOL#8XOM Wa"v~ nNn>(>!5/ڈN$)$I0U(4jpV0#:b*.zn]qoߎ(` (*UNt]\s5x%oyotNWrYSU8ŕW¨'>sHAŀEDQik k,=q#.kzU5`۷=}/pq_^71F=A辴81i '0F=KNv=ĥc8i~,"tV&w奄;H.u={‹qgp^SN>/޸ .Ė-[p;q[.ӟBZ2p.?=O~FFi66aW*'OLL ވS~Jo XD4kI;Pr[PtU_ JT(1W[[_Xf-Y{zΫf[}Vo؈_޽ku\X O!,\z߇0h񀏀hph$4JdT^)USK~\ =ɟH]c06GFa/}_}`*9[d)G=Ûc>8Rèc݆XXډ0 2ٶ 嘀"*T5,M M*FS*d?Js Z% deO߂Ue#eV*'z,@eyrT4 *WffɓlP(XyВ=RN`R2x Y}3z\d,fbNWLRJ'^Uj?klY2M]dnX -!`S E]2Ҭ7Ǯ%y&c"AR'E)Hӣcn !+׫OQS*s2dt4CPf~ I׿SwIʗ4, J&Hy>mTšWx!=:xI emI3~ª4ޯXz4o˘::1`姤}!UVTNΞzpyIDATgJgQ版M&cI2Bؖ-R1)T? a2+?$CR a `41`ь҂tɲDQ?u>nLzOYeR]YU~*:ͬߘP])8Q@2<./7f[-a[,[DZmWLJuMKt5e⏢@RH>ѓPMS4dHM)?]<_#Aw YN=˂eI؎mIHI) ] (G P+IuWfH}h&1`wf@eJyCkzf\>>UQsu4/+*OD4u +;Ynmi 8Niٺ_xZaz)$I4o85ŀu~azm{t+3 "75=FE aꎄm[m ]-}g&OOTW ^YX`+K[eUbζLGOR2dz&uDD0g),߲%%S6EW'E qa|>W[[|en)>[fgf.I򔔡Hh.JI6НF !*0fmf|9n,E3_9J/7F)8a,MIG$TQurk|efH8Jz>SN)O.!ӏ?~}'۵ ]#k5ᙱKWҕp9J)$nS / 5/ǂYp̙ g;'Uq"L,JEF3kjï;Bu*O$\ I!A(Hf)d?AI]t!6^r1֯_F1z]nފ>iwq 'Iy@L:lׂ1Wp] k$8JEE)8E X|xj'$6<߆Y|o(q\nҥ0AK$H93栧 ?uX:4/Z u8Tի`ժոu_`źp u}G0EL~)DLr=}s-HK|Ĥ&,SHQW\ `Q4a`0`KU-6<φ[uh!M3Q# d]D4K}n7>y}AJYl.R8|J_~]<'S Q DN\ c&Y(*@`i+M )0` I!iEh>!r_N\,[11_ @Qa7ea"RJ߼2yypcòlH 3@ ˲q' ߂[m\=BG@BCQ= ׵MM򮫛L:gfY2Ccl9O0` B5^_ZzI|߁_+GFfzu1w'ԶqI'a,e q`BaԼ^22!,8v(LEI{G',:J BZ1oucv=DQ cn0L'LD4OCp‘Esł%K9g dsyQn[r'8L)Bs`C\>1L0 QUs  BxA#vt1GHQO=u, fPRǮd: #u;ҷ]]He@F$ 3Dq3kKSN;F;bnï;k\|sW#B IAeM9?+Itڶmp<|;\߂%c}Q)ȗ0ǀE3&SV]u^b7x氇p9K@Oowӊp`*ь/|7@_eY,KBIg),K$ 8Aŧ>792zB9.5_Mc 4+*TH+J3(P}xnwye7]zbWpQkd@݉mEh#t[1VFJW_z9UXx1N?y=M-H)}WY$Ij/~v /=}C3tJ&]Ia75 Oal,$XLF߷ujFӅ۽.a]aN+DӉnEz7x˂%K=|/nWeK:AϼJyf|~ǭ?=hLf7Kz+=T㼁 RR Ul#J|o=ԛth8vB@ގvv+d>{O[M[\r9$Q=l~\rX~=V^ w,@7 0ޝ@+hAW wL Ef #0gݲg\ 9i01`b<߫h4\<4z`jtJDa1QQRcNT 5߂Wk>nqHCM_'u,AK>)aw0MA7ULv2.i .MW^ft= W:TjW3+^QȊ .GfCZ7^S]Da$f#aW.ӼŀEG,Uhh={ƐWEKPV8CJW;Bg"D́4 !zz_՜_s顪R=(M MyIo3"ί#',~_Б!w55_ϖX19@7HLosM>a8b"b"2R*w+ծf^ʫ^ K@(&tՎОvѡRKu,y{6z>U(E$1n<t}a@4s SDa{&Uj ͦ搫ؐ ׵1g۠ nEhWh6,TSA(׳|Li3ӜP>E+xD0dB{"D{"3;B991k ˁ쐦tBLJWk"bU(^z^rP[} ۉy-Ro6;<4 XDIvnq0g2zvuk؇Y1A7FkBwMLhj=hׂ_QrZl[ɓNjv bEZXzZC<8t+р$qw.1Z]o44j mG=aCͰ51ӊX8!ju|ju5_<4C!$+QAs~QsëwlxKX^.DT`Sm[7x5Sm^OzUJy[`b<[(q\TϗvUWFLܧA Ony6\fI=;34[n$Q^vƀ1`yy%-搋a#>GVh Hj%FCúl(M=Y9St Jjv'A2@эJ) T~Ϸ|<;Zvba@D aG a*sc*€EDDDg XDDDD}ƀEDDDg XDDDD}ƀEDDDg XDDDD}ƀEDDDg XDDDD}ƀEDDDg XDDDD}ƀEDDDg XDDDD}ƀEDDDg XDDDD}ƀEDDDg XDDDD}ƀEDDDg-wt38.no8(n94,^u ~ز;R>ӱc?Ajya ^`!Ysix`ڵh,X+V`Nda~ Taxs/VKVb"""C2b9^62' iY8a7rA?i9Moz#uخ ^¶q{}^ XDDDtȼFm/@aͦM~XTªSOÿ*?z #˖0`aYx?,lv{pڋ9ݱ1<ǟ~z_5]lo A?xj,\z;6ci1`!SY_|8 q~A;A?W[`hbf_>_&ԆcP©=y'A?fөj5ocK_9XDDDt`?ԶGQk60f,[w};y>|a @03_-;}^ XDDDtЖ<rGzU߾G'T߾\aLN9eFJ0`A۱{|/ccvǝxF>*|x\9#߇~ 5/݄:ƾ""">c""""3,""">c""""3,""">c""""3,""">c""""3,""">c""""3,""">c""""3,""">c""""3,""">c""""3,""">c""""3,""">c""""3,""">c""""3,""">c""""3,""">c""""3,""">c""""3,""">c""""3,""">c""""3,""">c""""3,""">c""""3,""">c""""3,""">c""""3,""">c""""3,""">;}1IENDB`v_sim-3.8.0/tests/exports/color-3.7.png000066400000000000000000005461521370110300500176410ustar00rootroot00000000000000PNG  IHDRXXfsBIT|d IDATxguˬ3` VD'R$FO&$'bC2b7ާ݈/Xi_l-[Hr7K5Β O~60H[B}* "ő˟^9OF`VUFVp К#w.wSAX,:_ ^P*wL[8|Ͽ8_/vAXVaAaZoAՈoArn kE:w)o(@)Z>{$A(?hBZpֿw Z`m,fO=)6M: 4up포{º" 2oؼЊT`T# VhA+?<-S } |E*sr^dYP5GjqӍa\ Uwv.G~㳡׵ok=wʎr>sߴ)cXT_CIp u>4Wcߧw\AX,޿qڷԑ15WcG#`^[:sYtfۖ~[ º&k*2 i,Ce8 $yͰ _ha/} lׂe"+RTaTkU:fxtQ=B=m؛o :pf o.P ǘqd V -(gkeݾܟBD Y`9ʻcE ):ne،0lF ƶi%"?][f[tu_G,(VI JDb5 n:8\UX~k8hX\lqu[h[^KXۥElBvD,c0|?>⩞[1VX0YITz홋%vweQ,XG>Xw,FESeQ> i 88 oZ[lzZ0 [lnҺyιfJ0_ÞM/FPq zfkZtUShVqwzXA"K|o/K(A+N`r?ۅ(Z}g X  erAAXAAX`D`  ,0"AAY/3۠.AAXAAX   ,AAF  #KAa% AAX`D`  ,0"AAX   ,AAfk 0;G % WŮY BsA"aq\S`)Zk KR Bl9^ X@{XES)_jˋ.^ X@h #k,Zt`mkLVS,Bl)oj^QTSt ˏ,AX`P' iRO'`{q/\).|z e[^NAX@@ ^ό%M\֠9H*Ii/J)Tҫt1Zp։Qa% @i@sXRɲܿ8tخנR ARxAE=A}D` m"4ZWqčێTIymr //U,UqڅW!ܬ.G/Dx X0OHE 0OSK'+Te': LAUXrVelW+J'K?"a(jXެ1LN4}|)=,:ʭ[Z"Ae9q\pZ#K,Aa*A= zY@x*\=Z˖ +Pԡ,&rY qD` ,BRC8UӲ"MXsf9L?W>j cnGA,A(j dOb$UigJLūIҕ[BMxEi$clnAXMiTfF#1UϳGP.N5Biڏ/hEcL_X"AX=)('j`0"58H؍r0YGfY*]Z)@R 쮧q8^ ,3"u9 ś8ϰF=erl|f 2%lnb5K~ HWM$ K,a㜟X@8M{ ,1R*a(%a:UP7F en\|a1%KNh&4~*g-4z_h3Ck"Jl1h^q+]Aش|)C!I%E e"A=D` W@ Ko`:1ޠe^Yfێ / sJ5(^x0/AG.Q@EWn>fP(mje&hǴ+V Pn^!@9X2d,3XDx #KXlמ,뎞y{vȫD)vUdC4a0*‹l ,"a!KXw TRg1T;z_ܩDCysdio^la]B)M*TGp=v4YfR^V%JH\yr"37P 5PR5m^췐sXfqΑR[f5zHD.3QBxI./AXC~A4L%ܺ~m;ڸĹauq7g'zKUB"'^x/Z% טb%M/AXe4AP%PL6{k-tz0y%3 r>> _1҄hբ.K傲Ԉ,a202qܺsʵ0XM )D܀

    )4ZױUx}AXšdtCڀzǍ7ZJdX؝]h7TΉ~ ]Q-Zl2x%%K,aMQnho6| PO/ %u=J{U-~Z$lW,]RlQVoZ{pa!LH[Dx B KX3 W&[7ܼzk&trXWjYYXJUڎX^>DSx($n$w7&y G Bƍ5>nGZI(^IҒVBJ% PiZs01L=Nn<{>W. JfE)NjlQE«R^Ze2K0KV0"p[!M-7չtB~S*u (5Mj -g1Va,} (WA@TPT6W-54,o+\q_؈V" E>r@ 3[f+w܁qvL]m"adyP^Iy<,-^A9* 4qgObCgd"e@" l6Hh;yv fn岮*,(AXz H'튪QkH|]qCV 0/ܨg\27.^f곔Dt>]C߬  F#-֮0+TA9Y<>K򹼌/%H}0Qէ_sSLGG^ F_w^?4W4 u4YW:Bx_Rm J.u}QJ7ckHAD"e Ybzeϕ!4fjE8"ld{ѷ7  01ތ*WVCȋ- /h>I8vH⌴El5аd9ܐ4@9iKu3g j^u]xXQ@5O'Qᨭ.f,w9Zmۇ"/M^ԫ襐f%^ .h7~iu<ǥ}ySֱ֕XcVCaP J[]q> d5,aYزm\>r$ϜkKu0}Uę)(T\՚+Nm3]:CAڅxUxU@y1VyZ4[\ICZADfa\2ʼnN$e_S&켴B&Wi^T^ժw7F_1TixbXתCdn}09r$gNYsI0yD)`ݘ+ֲs GAX<|7o Bi^r7oEdž +ZH! ãնE|WL F@c0CyL9ڽt6}>NatP"q.{5aEzaUӀ9P :+Lѓ-]=keV#4@Hv KK+1!KDM * @h}Lӯ_]{FЁ.]K'EU{oZLnn2k1Vcȩrn4D 2ǐ܆콵g%̓G~WS9 VC 8?)pULJʯ("k^( ks|Yċz=- ,U5DD E&@Qh~a7V]gێ!6m4ON$\0Sw4T{j6g4 Uus9vuQRL /Uɣ-.TTyL9G*L:jG{CEȈyǷVk!Aǫ{E"61POf:TJ"k%_ <۵xr]SpŽ$GX;4ٯ\sog>rՍ̀~"P+g٫ $L/wySi32 rƂ&`pcj9;HXԒIP"k` *GQ@TKmi^yFǫ,䕿zV?_=}q$u(P~jp{:z.\I?,{V ˊu Q:3h4hU0`P1 -wy!.ƱYmf 2 {k N9˿b-U^ޠ^o^\68 cv}F{B, )gq[EGc۶ CnZ|':?KӸ̺ϬJKw3Ud/>`̥Xy5.m{曬#gBC޼ػ n +Wdv]f '?JMx]k^[J q$q勓ԧ% +Xǒ^LYgah,%@cټ%bkL[Ɉ$:Ο6n i8&WLU/sbYh\>CR8nYҩu]?!XΔ/: WibHµ.(^ϏQ6lѨg}uT Ʈ+,yoirp-Alisƀᐛ74;V>j^ oU{92׹6p7WJaD\X2 9o rZ1LuVX0揎{GK~L!&S U&p=mBX|]SQOפ𒡅e\QnpGuܔ,&&.^bl"%I2>˻,{~W-f02j Hi&Us_iyu 4WnA3݋ZS l ~Vh EVVZ\l0gs)" Aط  ll0 7{w޽{m]f/)bZWϗZ-8JaF, 2nŌYKɒ+g֡TlY}h*EY7^9K К:"V:_(0PB s+pL,tNl>]šc DɉgNs5q @Dm Z D$ڜm*k{sb `P*njpY"]! aE~F{`Tyg:yI4^7&\?hE>SPKMfdqW+՜p3['xa_,R\X*aZq -_šbϾQF*$[(Ԭ11909\x#KQ(Wd0XVʰNc1d6EeHk ,Xk}AJV5V4SM֣~ڪfZuiʮ-S0(fDV0^< .lq\SfgOCPJ)\n" ,PG.Xغ}M[Sz b؉| 2λ w _s4IMLjR8G5$C-œyüN^Nʺp7.Ao%ұ6W tms  C (xfX9{۵BLTO(J*q8Tl.'эUv雼ʫh"Ǐ6S 2>BiKq CD, qhUhQJcH{$Wfwt۳/jš\ռ9@/B(g j)yɶk-*>Ur !(QPSL>MVݜYE>'V>8_.'72YԷ*b`0λ7osG IDATǯ0 8}\8M\qZﴪVjB, O:4Ur4 EF>WspZpӲ; X8VPsG "5v)ţHv7O:WhM %}ţeu_ٵ*c`hG4Cz`JXe͟m]?msZlټgI+  ]X@sQ _m_(:ǐ:}ͽURp8g R )ƥdk됔ğwqǝfZpn98"6ݹW4DZ90{ {z樧:B]ro۞dr ǫ ؆\+,.H01<2"B,XB>U{vI(/ UZ,Z|1?S{ 8f&_:Ň^ZѝğVX,H$xͶ>Ra$ND` ޵aQNaWYMW` ǧ?Է~+?F 4VS?*g_!^dB:ED9S0>_q vV8soG~̅8t/R"&rrej{?zZ_>wm+μこ{~i >l9Ėm>y_}t QÊo ``0⎻600gx=$(*˓/ @5X+3_0T6!F\/V`DJ+dj Jq5}~=s:jEA_:+Wh+g5s"3˓cR)Aw/d7o,Un R *w \\Yd:K︟:w?W{>ro '8ڟUٸƞ;FqN^.k2XٽOL~ӧa:©PD+ZT/UYy^f3sn;t y_Ӧ!w?h?F1\J/ȶ3ZB\i0Ρց*nxyP]#rE"rP*W*Z~V2xkּS@X5ų=J+V&?nx/>|3\ŀ~f1'Z uHj>=wڕ){q;t3Wys`KIi)1) W_0=o{Rj} UI9,܇uz]r.r]g vءٵF 7Wk y?&9h]fX/ee`̗on$%6}>}`3 y#v"EZ\y!ظo-5Lfyu~'}?8[ -xO?F3 UJBwmi/sٗ.P3_U\)U~:?42K=sơڕD,sj}_5g172nPWVj03rA e,.3m[>,id8s4Ċ*9*[m+O|E Xls?IWJ3C+V?OY>WȈ~wĆfd4uZKX?V rq8̮~qR[ hG|VkDW^3 prss|v,.\)q#qO|!/R0b'-wEۚAhjٔiZ93Cbcy7S ŧ6{61,_Voh {7&"pO~>%AaA#16wT՝ojHVKW/L `wK]85S>2_`hp7Nijz v׬9 D:Ohs(;ޞy=r@O񙂭1'#̷x\A`)T>)ڄS-u5)3ߒm[$O|$đX6V*5}`$@Oq Nr^u?IVwqY/}eaD7xS%6`)^O/*hU+} BmPt2)v/ p4.$tjGi,mScUuXpe2Wέ9,Dy>6޽Qoy?^|!Y,KشSP)\Yg9FW"zi\b Q1` ~]94`D\k 6ݵ\4?]^~y_ly:H}S..z -eI;/$](E}=RI^(]vM#,ۡʵ Veʘ8OѺ^\- 6'(嗶XO_>t)F?;me+<疩OimN'=.t d'mݲܭ<ؽ~aq#] v~Y򀾟»ntUQ+Obz"5Ȧ-u`A27ϴ':EbI݅mK?bFp}re#~o=OҼ8 #Ő:r_.0bT[v Uz='ܺ frq9Fݶ$+蓼IOFF OPZucP |RROkGfI[2+֟Y{z,8[(:C8pz4>xK&Xklb!n\ډx.s/]{L/ÚixVUskB$/RHwR'fTλ@|YZ*._J.0oP#*TUԥZ{x.&OWi3Cl4qɱ';&yjp&vS90A)[Gw[eNr1@-?>DP ! Q_S9rS *kWWq=_χIiah›߱m;8sq̨!Z\z-?Vgگէ)=S8*Zd6}.{p츋T _ KV.TRh|Q7$_J{%N{;n2ė܁({~mz{ԋ_%h{/hិ]*݅*ޖ|oH qWoN/'"6?@"zx *?k6݄SfBv3+$#D,Xk]{G8 _ŧQD?Lzi"{lxZ<[@&څVtT>S츧-دӴy1v tSUӌ( KV, v ^ g*Bjxۗ!_x?:c[T,&6;soyg/Rx o|B:h_|Y@|6$Y/9s-oZFn~忡V;6ѻ sR޲իC-4chTfD*& 5q3XXzw{ۮ.BN銿yg ..ٵv[fjb[BqXQ~`1/[Z873JstL'zqe}><+\`G$P)2Kt]޺ӯG}^**Ek_*/yO T.\333^?Z?e>Nn}S=u$s|؏ 6(S&~2ث,,XF,X=Jټm{n& 5ifxu'*\ˉw3zqX4s1}|~x4Aشh}DլKכ e2-z>Pѽ]~Ѹ$)44O=|/x$hӿ{sU _z7 奇WޢϭV O-U+oٹ02s'`/ ._ےe[>Zz V6B]֍Ⱥ?t9e3?@)7~O|yq4j*/;:ٖcZsfvׯLqu=\/ 7z0u^$Ǟoŝ5f|t-wN:mKʩ2˭PPX?+Ge*/Lک?lEcz& ̩^H+Vr)oy{Lk),qt|biU.C  .` Zs5[Rݎ *]bO'Z"k7Q0q UP(~/f_2r? ׯLqF i{ɋ]-9fD*bh}oVl='4沙-ZyJ >c?S(;J+d՞{[~e݂{fזX/(܅yV9}3W9g*~~bol%).|2$]BJ}3g$3ʚ roxoxid}eki~o*-U Zrw%nfOm.Rr)W>:l~6Iz~طR^Jl8VF*L'|sA)9ޟ0SB=8+g(o~.j瞾UN?UK4$7t Cܯ65ForgJqGci>jqA.2U 'y/0g,:SKvacTE5PdwQJx!Ēd>XE+}V1DUl4=*t֟yJKqtaf%Z<~܃e<6',@3tqj>U~CC6f>ʬ)"H-po$"ymUmIMM9 60qYa\6}<:6y"ݑ|@ȡ7mώ7o};<^@,X+k8@^}*?8s[znv6fS\?Gu {]ǤiM040@Fԓe@&7_3G)i%l/R0؎Tގ\^e5\^Qk^ϡ7m'4W/M/|O&:ΰsxÕkX+wr'*?~|9 ^h=GOu_һ$w^u)ŅkW\Mju1Sdg$5$8s!ܚ˃MLX,+/tv(S*z*UiRoR^d&u1Sh[bc"} SEzRay Hy D޷UAս1 7>7@s$*EWQk0Y.K0`QA6{|l9J h/* bG32R^~k q;hwAs`E 6rlgɝ;=Ƒ'%=ZYfcj´v +_6X݁Mjm?7%*U*jQDf-qKb믏y|ׯ!}VWawć/}Yy.pSBA:y^=^?3+&EO{x_H"M5 No&>qfx#y{Jna^}VјlBFw>ZخK %8Q6ą2;+:~m3p gcQ^$|{nfA^xb'`zH!'[w o޽M[R\?|=T?KHUsqXVekW#=83gY]ޘIqL&:)Z[rw+? [?`:`ouWoGRWQJ?UF'F]i$?6@S fU#%xL$,ZAU) jM^>Ej" u{ֆժ|"rʗ-]wlYd>+3e84Lc$eƇF}/;Tbe׫=#ݿ?sT[MbwłkVa@!ekK{*/=ªc1;iOKL{@Og?~c Wz[UVk-㓓'"ެ2^P-vRE<τc>D=+} 0dg.NUL">)N5_ {V*g JO -v=S7L}㨆Ʊq֞*M8+,!Qx( toM>(jeAW1МВϪT IDATWalC[qNz'\c٦z߄jiXM[x{k^yyO,Nquޯ}ȇ;GDl龰`9,h'1ibk괘֢B|HpKLl,>0CPCU@['vRh5ȲSS&-Cǻ]@7-0+Tĕ[>&_;|Y$VL>V12ZQxqg)V"zz=~V2}&D`-rC[|ǗcP=wSDo5,& S5s=yS=]szv5fiiSEڼW_\R(n?zHGTeԳ^kV{7JyR 疻I=Sq䫼0pJ~ƇM8֢Yx۹Գ3Gx`}?M쁽~1*e WO=(L%]"uy2~0LМ8ӒWi J0?R9S6ŰAqFv&//={ߊR8X`KTخ+iUN]}gr _2VtZd=Fq|jJu˱G{F5C/cHL~=\[)U.tW5kiGy`qXl }+WI$?z$Ʊ酯Q .:VXB;4)X 4<DBPp&/A6-rZ*n^ڞpRcX:H6n|SM$|/7~S \Km4-~p]]Mq9;M7{w؉PG@eؙ3cCB@WTwEoxb\ٛ ijɆ ( ITQ0ݶ2Y=?˛rT_ E;s.EQmxAW:Nqǟ4sXȦɩ'l6`݋xGog{mr-GʒWCMaeϸ†e\C"Cyٻ-N. %Pv5;nk#pJ J#λ>]11-xj m(HvoV*܃xXLJ;8sp;7ݿf~9R3[B0BS (% ǂ0 \0z8_γō 5Jc Pֈ<>}|iѧg~c28|adBŗ^`=ʔUƠ8u$MLxq/5w>B _Ġ#` M}Opq@%#ɜn7 vf0];7JتP!W [V % T.ZĮ$_CV.yVu>wm$:nYc ȴ3ρRHϣ.S;&pky|}&ϵw6ZU'#L 6ϱmXҜrY)S+(Rp@RQVЪ7wƯߕ}BsI{D 7\фkC5FXsE(b륀[5|)r$̞˫6ٵ2ƀ,z. iCnGx=Fv*()hݕx9e D=[RKHQ3yj'60NV-_IMXp-Y9V;{/1xd\IS'%i#y1vi8{wgye.{Ԓ+qZ` j*g۫e0Qs̲n,;~eIO'/ot3if00*l7؉0d<ɸՋ)*Т@+r"EO#Ϝ[{b ߱|>ٕbK=vM%y9ϙ▗(+RgSNj/(4mnDzGi9NU^~49f0\.j&io<]험/tMvP(!H$RFzpUB~꟠ZO 'zH˨`i{q>6K>K.TdCE]/+I@>wG 1.@\Bzs!Аv%ݫyv[_'WC{MsOyr'9sT9n`XI$,[5Ǜ}bQqsE!Ԥwnkk:k6cV9 pKbn貢P '"sx忉zdSxqdXy8@f/ '3.@<D걖:{D\E?]g|yD@a_PԆ᳛gk皖mx/(^'eƬ.}bWEhm'WE˪RU<#(hdaijb>'Z՞wgVfU 1/O:Vl{e׭v,-yBI"I^>974w Jock$hWC+G)Wқ h6D ɎG&+ l!^Iŏ`Ŷ;-𵇫]*?#orX{;Zdi={C8)`b _ ?Q< I_C/y'3hhe7;"WrH@YO!J25dN tLv?U6&Kfw7o? upXjO>p*zNzl4ZEY F  :wc$Kg<.|V 6<gO): RF~!%x:^'I{['PK0χ D7=o&˦vR4X%AВΧ(ÂٕwvmhsLpNۿ~ZY2^KҚ@ z+Wyۡ)4xxC{i;, 8HG;A BLpBOnƯ$ A JdgJ(CЄ @o7lw$Yvͤ] \)؛;R~}}92{h{u> !{jI\:S,R]{0jc_Ȇ\Q^[H(7c{}2=Iړd\V bx@L`\11q7V NjTy䥸-SYd-s9ߕv `Ey3Na2kk*P0C}X. (4r4;n+]*7zA|z=X=}#;* ?HNkr P)Wr0<g3JfbK渄F4|1m%`MOi㬳jN3ƆQY=VtTÊW,Ah$r4m G>V2Sʘ04w%-G+<$c?U}KYBms-;,HP"/֑j!Aߑ E?_#Z]@#+*r":X}ᾓ݋O/U!ԉ~ mOeH.)\o]4tcwG%檊/*WUGc`CU'LÚR7Lv `ag;ϳpFVn[҈htC5S5p@hsJ͓)Nnd5KI)C]ɜ .Z%¶ҺkVV O@#[,{smCDzJKm+ ]m`J0u?x\l8i0G.VH4Y`vUy~R㓗rm+) IDATE.Ro4eߓs^g˲ :z!`+ ?BhW]Bao۾i>'w}9j23_\CJfHv!3 @㓐2~b PY#+i X?Gs\z=zӈnN0 cf`%W-afOҊKw.QnHr79UIgHv=VLuQԚ(t s6ںv3ǣL̓* W\/ Cށ_pym|ņDĎ(UϷVe9~ %aWCDFgС-@Z Bӽ;$=[dS>XGQ E߸Vw:x_F^\B7aPkş:d!V̿chɻ(Daô+p.e{#!_rW|AR_f7M$΋RPYnJ Lfƫy_6?HIVf dKpSauS[h+k Nֺ[;s// 0VfC#/H}wV;翿~ @HySBa( Aauɣ%Iy.ͤ\I-x \LsbـG&q _'0m)`'QRq@P؇ŴdOz%!--GDm56 HS{w"8B LΌ'8RT|fOCc#0ADt$2L~xd۹7:|Whԝ3ǒ 4P1n!@:!.j?u B'gZp6'(߼xɗZ+R/s$V}s <mZhQ y*hc9ye8rsҼW㠴1\xm"15ZfΘeWϦ;E.FWɶ䦣=#mdWNeq+; U0 >@A1/2(z7=Tޣ5gbͦ2[+p;GR 0͟ti0`8na67(w4 zWC , ˆ.?d/VWRFu/l8&gWz,%? I]ߍ|D!v CBP^11cOU!5lW! 6ͤ=As/d_1/( ![䊆|ؚ+R& \YLҥD Nǥ U/Q%-!E4A/d%C>*can=f~fD~`a:%r64\ZOo[PjY~Vy`_A \zs-8Q PE?BMDJYGG\$Zͻ{N-k`2Srw=#N;r|s2[1+ZܗŇ.= <*E߼q2UK"}2{ \2!҄SeJ$Dm\ Iô)LlȀ ~<L?#:*=ޚ Jh,#@x JXD5v'v3Iw uwIS-V6Bk Ʈ[N[ aIW4k_T q[Wn ,<#QرCAIfnxߕl>:nA;h14pё)X/+%߆iM 06#-C u\B|fs8RiX?֏#ץRZ(ϕe``vI mq˰U^9=# ۖ+O(e39/Wޝ\d6<-6v ا㕀J38ɛI틪e&|+dC%/Wz a_kclis%/mӦ &w!nkws 1h)%x1D΃5q˸ .c%^ xB*%`?$D|[5Vŭ:N>j;gNښοjHZ`U fzOe\x M-Ki>39໒k ߏ:l9ƣT0RzXLX)ʱЊʩL󧓕yIikoҶW1~#d{o]^aHJ epփ{O-~pԵc'oBgC$ߕXTMȵZn-k j\ux%u~/ME)y!s2iO{3b*x1WmjH(s 6zBH$qP8HLH 4 Ah1"d:'q5ZyTIL ,!_c] ) hMwMB,b_a[#Q6h6f Ү$9]IpW&V78FEGQ%@-yg裂RfrMp?#rK{0]W[`O6 sktr[u3Y):SLomG ?}& :rD zopy|a6ջI)(sR".>($jG 1]^vs Lx`9"d\˾v@Qe7N% 4ebA9l`GsC;3oz ݙFէ6!*&,X%C &e(‰Z_%mo$`ߺo+v[@lXY4#^yIQjT[y zG)gw EWݏJ~0sHaI)ɲ/؏Y9}iP[EĔ!Cp դSmxǜ߶%_l†`ę?Th61iUWzRXIK@&bfxd =lw=߱aOg˶WDf#ڑ<e;u!({m&DF Q&o0p.OQtBϊ zQUL}Sٔ7U4Xak`("{*5r61٭k*֫٭ٸ +hBs.igc5T^}?7T<>(E$3|GaJ3ưtm[C((\y@!|m<@_<@h|`h@R ޝb(, c^6IV$.e ZkHG> A{{&웯a·N3?_\f^m͖[{빴R2Chn+<;?[(b@Q$(ܳ9PXKy} %^se'2^AXqQ%Z\B$n2Hp/,q׹XЊxDՒn^ګ{&,1g&}{#^c.XKd_{r"o^V( T#ʵjv̽GcM+.KY׽47qPNAJB`AP#d\ĕ qǏޅL9lr55 VILaar@HWCQ`[Tgn@/TPY}e1~H*6뭨*(<3<3o1%Vz*L-@2R88xȯ@Rpg/WcY"P  B{[@`߱[ JSo@Xe(0qJ'D ?"+"0nT/E7w cerFiG5%Y[q@>F[٫0u d$MωhV[}J&F S wCiqfIvd@;J+DJd (\RC 1GF!ZiL(Бw eҚ+fT 3;`!˿S8*ӽ=1*ə(S0𕟧?B OjWmYumگ rfRԖ5yR QH[Rf2IcGw_S/{a9LJ@$v,xۂ,(!E1ǕB"θ ܋|,*E!Ծ-J67%Y&Zh\ ^"q,PdM-u <^ \ Ij ұ_#luQ $u h<]V`tt~DBGH2\ dC|ȠY4h8HZe}=#,*[Ms!"1M,)B;VgV&A"yXD@ XhWPG@I‘jg%SƖ0\<"#tLܒl5oBm,IvVOB9+Sj#C&?s[pAr[HEY+n/l|XRq"P^7hBv́-ݫ@^6, # 3CPƑGӪi@3\;H_pgR 5sXƦ ["DHC]^qNhtLZOA͢Ԡ:<`Mו \QߕcyZ#f>qJ;.2~b& KL{e6^9N ~~}nݯ==M{={O _[tZ *kBkXàB h[ :L;T><4^"   Q~WЈa{KUWEhgŪ'-Z˒KpQ6pċFV"g'.*"2p1d;vq~Ckw+nK,)O5/ R)I[RHᢃsa`6I%@PzI-Y*˼G*!B|;:p0wmQFa &.L0N9F2))BWQ4DSmlƿJEXJ1~bˉl@_޽9v5Vٟ_+;c9 .[ڳm| Oy.pgv/TskF$ 6Lר4hOlLU\׷w 1Оi!$*NGmPfVV0Ck⾉`a 2Y:h"UBj/Z <őXSOx17}ϾNYwYsW(+)\|@!N=GdƼI}s.Q~ĖKنeV?Op֕N~4ZJW{Z^jG Mώ!zv 3F<+q]ɌY]̘ev/+0Пga -pPF?ٍGJ)-|;SKh'=A4g]J{5V/;--±))'|/}z<2P|ъ=F!T#~y݇$whC #(1m?zØwc"HT`Y"\ F ͅ!h&'z:4,t)SСB0Q*A$~66{B/8[((qʼnёx2 SBphk`kMF! a^CWϦo;'v?S–OAB*WTqd`^{\BA⻂ڸd·q1>pz-7hT<{[H ҄`᧶Q j}èUzSZ~콅81+rـm[ٶEƤ);Egw 8΂(>?[$'C[xWF:c]Õ13M~X &_c'5YВ7ц|#]L$3Pۢ-&!k 6miIBep=WԩTP웢"Pz1(1ȋmHe ?w0: 2 J^c=W P:|5uu&;dBMs/I{W~=w&<a\5)d"6θ`J0}l~NbHqQC6Pc?_ED2%1ʌ7B4N_51;e8PG? #0YCzc1,Q[.$]x~Zl IDATQ{]{s;*U'倸kX~fɺ3ٟkx#PXFu 5є2 DEEpϪ=IG` <ʣ͎hUiή6YY\Lgw)ƎK3nbsb>l,gҫg{sʏZF@MM>%lo٤1ڠZhq.FGHkln f?$ oߍ=*BhUfJu-09LCox NT\䀤)@޳>֝pMŷׂ+v!Ie YbXOU%X|u7n#+yjҡ&9 6.:tXҮ a$daf ݻ͹˿ɪ(L^}"ױ@-hS=Gq(i^y`)ؗmhBB!rE+X+d1dr:|Pϼgv3_">%DY hFQ3o|_#[<|bgn2\XWpM )" EnSGvm۷gN{fKގyZ`e<:κbM0v\:nyiW̊\{}+]`hm_1"<ڵ,_h >=e6NL1P`2eGpҪmku{UT>)H+P "T*+ >I㲾_O[qM:hlEf* +xk= <W¿oITUxD^_hmX(BD.XAQET;>!ն!&P=5JkD\Ħ_Yyh+% -#2æ=Y&J:#qO^ĸMڜ2d]ٶۿ^JF`5 yuQ'P'ٓϤ1պ5P1m@׹,r%衚ջ'@'x MDD`vm":F#HuH6B1oA H[WhX/ ʠJCۧ>XInL&N\*frwݩ=q 2bBGn{v?t;iO[ՅV 4F[- m6y _Aw}9gٝo O;󿣅 잶ZaIjbQ)CE2fg&ҤpDڎlBlmKM_ ZiC<)p̹TzQVM!Q궗U}B! ,hLTb,UZ>M@XC2G!uRhB0͗΃ERfVj{ Ji=iъoY 8Bw[=Hi%f@szr]#B8Z45i1Pd.\9֘d:3v1b^6^k3q/\Q-p#m2VJ 0VKO ʓHkO2eeÂ!!Z#Ha* _Odm'QXP>Z:} 韓 4cR;O8pov-=YTN赋݄jG"'!V!(XaD<V'~[p"9@}zd{wIhFH* RFP]ĩ)4ZjSEHZi{=xz3 1%`Y-ǖ#S E<e ҺE k*F@TCAWiZ[@YVYA {k諌;# sxe9;ewj.].-۸QcCBǡHB $/  !%fL 6& cq7Ie[]j-8);;Z^z^̝{-s9<|[b9iڲ KZQ>[Y3kX=M"HbЏPW=jg˒kRĎ#%ZKй|x͈-^m ؈ & SX$ I`vǓ9б_ˍac B!MvdVڼ' :J0G>Mɻ:rӸ-D}Gٯ?dzI>7!7j ʵD|LŽy;jVBkoC=Jɬ̋V2#cb>p*O=0RE\º#"6؎HH!" QRY(]P=uMhEyj[1 S2V !!〔'eŸz,5xJ/iOKކMaٰL^, vCf'ʕB~ç^yWCA9@92)ɺ+ɺʞS^ۏ~L25i .d^7c5$` ZK(H* ;gaj(?j݈^iѱ,CHTH<\F⇠EVT +5$\IIpiLԴ?ESzV|9*gv9+wYWs@_?ȪF-Hk䢪Bc`]ν#VkYCU\KW$j0ӏ,tr+S" uhWU  6Nn ' Th65%t`tOU B R@EC$_iWJJwrͫ4  we +EG,p11Zk(!8۟ř'/3_*G]wY2C}7_|$)aʓ7uZ,gnLA[&t|ڎLaV³aBbm;#4Qo8T.6zh?`!/K ַzPք&1Lt=bΕ^iE30nj+8zf>EkFs,窧27sg-H%3Y ku%LBVvT/k,^Ѿ{އ 8'ѿ=ξ=\`@cS @LKvcEÎtmctVAm86t.DQ Z2ak/=x DUԫdV񰔂(Rh>:dC"Hr`@NmAd¸Hh_ƿN)frbɯSammrqMAWތl`-WGDA4HeIF2'͙J=Wȩ6\'?mʆ-_ӆ u4ڨ%E-qq~䑘tW3g03P!_H3w"ZN7RrD'(57DZU4Z5mDp (S%:jގ*5TRP26hZIw(eg.DOV!wt.{A:7~B1]q!3P|j;UK븿Ě7Ɗ|LXMȱ^+C2e2?]»BΓT'ȦUm mN"ؽ?X66]EF7*28Sm.SŲ0Hqze~أ5x{/m H4ތ,[&Ӱ7AmK Ō̾/Q 8C0Vg䦳J]&E2$!;RP jz|+OǴE2Y,-J'`ޅo)EkǕ)**Ǚ_.J@RdaQ cQ9^-mt};)GvVhB>9 wc3}v{7nsLEQ'udڙ}F+3ZYt۾tma9-BjA%,P8gjpP%'5KO'ƈd%!S[dٗxru|CBh=sk9 B@Xm˕v?M3BϿ;7<[V`3*{_.C -%x\Ŭ@Ul[n6\B /7MAձSwJ8hHD2 "$"d6^Af{ĞR}|ތ$A7q]%{Dϊ؞ ޹O=!JGx 7hUVSBf[YZ1,=`Z3{꺞:ɻ/yw|di~A.xQs \k) AϐC&(<3U{0"%~$#p#1k1& vCR@b20楑)،*ЭggW]3fm)tMZ fT4 ՒkIVފܲmָ nbwWf}!sSLd`ȇ DH>w;} ? y?"9 w?rN%[+u.>Kdhhm¢aߧ5LAOZBld %G2hrӓ?=&1+`hWg<ĕ_Yu;B9Cfqg 'h&)!cd a"FGDFCP2C8KMsؓ%xe]lT?AgɣA_:@œd1:)DPjt%^gWoh| nꑿ-nbJp/+ |VABE|My"!p' 597b]_!(T!S€`\eӑ1BZZw_g^@(ر)̂E= voe <*d`=mfB|]!:ZV`տ z[]}J͸dD+:Qv •Y@MӶx@ cRnޕ/Lzf3Β"c0لQ\9ǓzgFd=W ZW1=Rax4[{q_zOֺ5RUL4hS=p$Ð@x"#l%GY2<)(ffәA?8HY DUg8*`%S Sm蝐;1KfNkYGu%~6:OW7v`=l\5lW d\W1#ˌY8ϙǼE}b'62{*گ9k&Dz,UB n֌oD3{5.UW~ixeS]9VݝLCc E>l,̤NJl CCpUWZֽߢZ {Dpy!I{N, dbՈTjULb ү͟!A+oLJ3"I7cUr-!ߤlPi!O`?HoH_yƸ{0oc7Q 4I7ZYUiIsޟzvڲX+ϚΨD:L0%\e+|mW] Xo0BP߭D\W4u51JC8gbU_efWe &˻)}ۦU# 9cd/Vy+_?(BOGXB % :8Jr_LAʍ8lR)R8KɊOޛdr䑁k?Fx9.,G+0ESeTjt.<?0Xt?ЖqXʫ2jd=uʡW­kRUj-ٰ`KGs/:{lzI+ 7>L5A4>&^q(NP֋eQ$DyA QH@?̭[2S7Q5p MV C8fQ aeG+o佩~1%,OġBQJw+DP @s;:p$3Q'"WVaS[kgDg赸>S/ &WzOKk- L9Z\ȻPq=$(6^öڪDetX&2-ߺYq/GM`=h[I HtBa'!//-?C?{Rup$')ĪGk)FP #yxw۔7tx3䬾\}IƖ9޷Yg^HGaC[o@)b񭟡-+G( ~XϬH[VnV4 ?4-n|z]zJ\y 4bh~vL: F ޾>1J!t,k x5*y'*wFuZvʶv0~ª6]buR`WzD߅cM(qZ|X{e?w?~d:֑Æcxwanf9.rM̧ńDPK[VBX(GMx|*[Yՠ1ϏʌU#d dI+ 6 ޻=F ݕ(6̬1aQփcOVo_=hWxDJ Y\QeT&}WO ޏ4Ɏ:U3 'փUqSsۆj(vvm-&np%3*}ER5 ZI6a&70|yy|=Q-X7'/c|';}: ^U^"bwW(o`r=z58ߟ'XAqoJ֑hF4džb r|6!f 7[!գЬ*Pq'޻K8L}U)eOp;bkKHKs 4Ȇ _-{B@h~#]EkU,E~uz Ъg:~ 01:^. ~؛/9,sfO|Wrl&}.+lYJ0&^<Gu8%o&iO#w; -߼5auc0aE6+=b d38d hvWᯪ+W GGibQE֞a{}^ڪ@VTwwk X .9M+O.fX}OgMcqdAΕlϝP]W<!ku^xmf3az;)L9ܑ^Qz'`띿aΈvҫ'd&udu|sNfO.yo7H!-5g}E O>!oM=lm@Ch 0ws䉜_:4[|2+G8 66j"4D2bYoPy";ۑmaQq+%ucsރ60o{&,EGKV&sţoTiH0JvW[&`Ud~qB-xջ(_lD[e0WWӖux2+d()cev(gĂ͎'\q%ot_WG|ٓ/ \a$eq-%jcWG!DZ--@a\+>*-W?lX+;yq2^L;q{UIpgw)l ?Lc*طmE:rY-.xRgQ.=Lz/AM6a.Y7 Ym#$V8Y/2!N4iC/y3Ɵb/v{6cS:(jB15E[F)!*p`{u`r"3) $&4k(IAQ'>vG;2iĺr#/=+z>b%$s `BY|2ILRҕd X|!YX|x) 2J@t,d ceޫO/g҂ѕ->'`ʫ߅${1͏#Z3_h.~Y'8 r';as5֌̏#)s{*SiRԌs`a3R#tt"HYc`=a6:J]c/VӔ:&b:x|t_{WZWs1~Y{{^(E K[6`܊bGHJl9\rxzЄUO~vn+NocR{SLjϦޮjQT ubR@~Hgbe9VԔq!86 J^ 8+4H_h^YC 4>^#%emZ׳`koqޅt>- لj5r1OeŽS ~O\w3;N9 ϴZn[V*͔W){Z"0b嶛o켇VZ[rd(~-]?E.)H2pNfn=RjuMFPkBM RJrWS}#4 "\ߧG&!yESUcUD- dr)gϠX±Q8Dxz~ұATv!U*C?Q AoMY Њ gAdX{yj*Ԕ"Õp[y cmPn>+G) OgZ\I0 ^a+tw 5s[N0yn%J%J>q%¨E[*c;05)2pX^q^mD\ WCB D8Ih܏r[uҎ`!eO.؟`Juhd AJq# w*ɞEqP &2+X':X"kY'SHLkg6牐 SؼH\S_n?C 4Tx_Kzhk͓k%^AJqxi>>g[/?y3#٦G}2Q@ #6%(]XJB UR$v`kJ!8Oc2{6P.cݎ:_.gěS,̭Z`?<_>Ö'7wIA>.9CGW Ҭ=U- *:6=CdӉ"]qX%) ~c~K:9u=>UF֬٤PxJI0j>yff6û>A]PbVL3B :mV9ldЂyakqI硍wbaD)Äk=׉Gi8h~>G[A-Yh5 [Vt_HC*q]_5Ŷ J[[) tgi7yR8J}3])8i{jgSϜ،{n: Q@! JtZsVrV| %Ҭj0U]Kbz]_!A;@_Q=Zi@k2zFnY?Xh`~Z:'OeΌٜ$8yӎgzNaSm aw~z"r']}CĒh@`yYD 0JᩋF9җ%G)AƑ\9ܶ2+D,C 2.5[oS,3*ZOA ndpAD)h5x Sf :=}WXmfIglg+hoP b IDAT'S>־mˠq;aVˆ0e^fH$ x9=vuՄg ֳg+a]e8nz?ӫ Qplv+*dM0a0-ϞWY63 H`4l]1+!&`չ+>6:Fj#kuؔ=[)O#k%~KxMC1邑ب`|ERp% s'3`Γ)߽ edK+byzcj+ b08|ydSdΌ?xM) ¼k5~2oɡ jq{Pbd矞mc֤ ugB֫pC7q$HCg\X>o,K|+<g`Ҁ)g BBi " b񭟡S~v|U 箽G0UʖqNUeoL̪4 XqK97ztmO*Mg3HCkdbM 7"\)ՊMe6~vZ9 <lp:`' o'Rn_C 0b"/_@ؐaL5&xRF*WjUu>䭴&CXݽ F!Fčc_aڳ*&Ļx&EοIȑ-|f";PBJtA_Ϯ|'̿(VزTއHSڷ1cMdE>Wi$ 0@oȎC@6S0 wN\Hzٟqa{s,+Pk"mwI]‚2a5Qq7哆aDNH8Ek@7QKD`|Bd VZRpj O55ḧ́w(!`鶵 ɇKδudvmP^EE{YWoϕ X>mUFgJаx͈ѿܼP@poҞ,O+ Hrڣ#Іؔ?Tw1*h=W6sG #KX&H!Nq[l_PlFH×ց8F^ɂNĆTװwv*I53(c,;=W?⡷Q BD@ I@h&RT,5IQ^2y6XBzHD=yB*eU?Й,dN`7MӦNz-r[祩9c사#I);uu׵qR/|r^WTճh~ _˒pP<#)qCǦqkHCq "8DV1jٚ}ٿXGmQ5V{3Yx8 .wn#,r2aj!I&nx,}o,ʳ't%GچՌ 6f1B*R4_y{-L =$# !R4%D&BHA`'Ȓ5_ȼ9q:8g0#K-OJ EQ_(dv1 ɯ/XњI$)vio1}|yB'?(eO^i\-G5yTa8p󝏦!O)SuXp-8'4ffKr-zSEq6F[.(\?@9֋U* %ȂDGB$Z12c FXhdNZ 4q$W?NdN +'W~*jǤx\%cQ uS6j4hxFoWÈ-ezO%C;>KM_"7ЋqO; {#gMa0uzJRPW!8DC$d*MP\~]s%:͇ t~ ;mGw(Bh 4y9κjxҸо\%88ŵeoD@ڏR)8u\-#tRh;C3m֘tIO}uS>VR) Q!D!*P8%RRJ(EqGەJ2u׌\JڪO GW@x(lxz\ESwR9T-YuƠѺ*Uqp,pvT`tU{ k8hb񶍝\ÁP^Qs> GoyFGD:њɓ[XtM'S_QFJ31euẅ@ÒA_NT_&|Mx o0I 2[@E`I(4@D҂Ni5dPS X\iC{HfIJ%TFުЗ)&,(.x+tNєMq{n7:r(YWZ8 ВoyG ]ɪ]--l \e1W|a2^Y- !6q.ad VyO%1&" a8 W(%CDjbimDcÇc$cpa|'Ԅ=Q`nw| @!c l?lʫW{ '+Y^m2X6tQOձ`M4}FZ8q}1bH ~q(K/:gYrd=ӏ#!ӿ[T"4 5esID{>>xmCn9dęXlyD,S{He7pUBV^U?gVȘ(*eQITV>BP:Uh:ZS2{^׷>BRU1?qsgEw`UKƑ?3)kVUŲ?Kx<Zk~GVi\G*ɤ-a21I}7c.5QZ:vpdM&ʏ4w>ע3%uk8biP &} ]2ٽ7|& Sh )ެ%~N +=@\o%Wubr]vG 8lH٣OGY5ߋ+?Ԥ?V'g\vB@.r嗌#Kd=6b]0B }#{~*:ށ:CEoq_D:CWmˆз}̾/X J)Ra`ACkj7iޫլ={f80IqfN" JM=y _WEQq9J7}bQ #ũF*Y}bI(1rM\ޭs [Pi[RU!82QZ=B(;Nkm sܦMeCx к2ZM!LM)1F`~R];kÙ7g r`E{(;y"ffXsN=Y @R8"J% +* D:BI415\Ȟ-c08_x z}:zε@kcDds$9 ygǫ톷/딛*zK):ceG- |M.?6֑ 8ldfZmt54jş0s_+Bt;c㟎>d Jdl6I?(k0g˓s"*t ܧ*3!C`~r8 ?i_ſsß4q/DesO6HeEø1[A~L3/2t`X67atWTy3q6אלDJh]=$ZeyN -CJ y7C" y[ٱu8Y֑=͜y-oVF݌nޡqZd R/1Rl,0/]v,86sOqlW ]r)CBn;NY>LZ5ySGx8R)k-Κ56 z3pR#ps<|XHvT2X b. fcQmR( ZS} @0*ˀ)\WrY=: utl\ldzKz!({АHd=FP> l]`]M7Fh><"/;dցjaW6p6nR?>6ܓ5wmCyCs7Ԭۻ~kVhU#!::0pK.pW@D.kpj;ɹ469ֿW޳-ï̓T/ѐ ytpEPmc 1+"O"C8@遟9N C'n_{,TI3Et(iӌDߨˬ2ƶupFJpb`(;hԂ] 0/ؐaYK?~tLKHmF ٩.lx}x쓙Hw=b4:*JAkT5d8z^aK-}5' agbXØF&T%eJ0d{۔}UU~;RX~䲙e[Y*ܺ OJ,yT`4k,q8pX/tLLxo.&ʼPj&UُÄ:j+j~LhBdyWA@ -h4U/\KŊ&b &7>m36S[O0kI;)$h e 9|[5"p\&PB!>Pz <,_3ŕ0Aj}hiy<:,uي$={O3p֧Xm$"NGM P=v5??Rf/AKޡ?gJ}Eٟ$?^~h+t)Ð]=Seϕe#, Q@0ZB2\ΣNFFJiw_h|0%{[DI#&A iO30x\:>R $X5YK1B#&$JIԶ(-zU65a͝Cf,ʛzoLK`tWT(TX%w~$׍kOӑ [Wr;*-GUy" pla GՏeʓX?橏6W\Kͱoͣ<2jX60C``LsO2=_?rh4 5اw}Yp[K-x#؈ȗ`g ʠ[8 l6V5f/9yh7L4O1py7yXߕ!V2L تT@ډ<䷭u ̝JO,~=3wP(?e:V܌ɴ!(q?P^$bYIHGvoh6 \CZ1f[rDvYzf=nx@m{f.:}Gl*G,qfn,zQ:8L>)j *rR B1t?:8ϱš{(\ QQ `=WiWZK)q3!-fc 4Pogl bkRkV.R8J0j\ kM{@6f(GHq|:h_ww^!R,̼.a;=Xe~h>ǂ3Z5,R38t- p2*}_T_׉(fMWM!6>{tma3M\Yj%P{#3BZ2-r,E%MZ\žb.;tQc |r{g_j?89'rB W09ʡ %RtO)v8cE NI[KŽb@a$Xu"`_!E,tf„ R{OtuGZ<d n/$e{^j -6E2_-2Tq=r< B*!S4M֋‹z*s&? 1LFƠ-}c3)i)'& DS)lxΎ t7hs0 %^4L!J+gE?fmXOxⲊo1LcS#e[<ǂe] ~@) 5BcL؏MG 0v[٬ c%2{%.ZzqΗل­d[_5MV!%?GŃ_B} ؼ/M*TxtOIv89-2ؚAR 5+9IVy}oۦr@W7󌿪Y3ɺ%cXJT衱p7Žo_U>8yJX1MpXֳ}{3;KB4n"sئC6DpԱ(%)Zٽu[vaUU_7P`UcJ%Ul[L0n#;nS U\\K1U`oBxM~5ux{"5> 4k1Oݮ&0kɸBзZ<"*8'o)#%ٵwzN '[M#x~Ү=ǻ| z^)h/PZL [j6Ck:72ul-dz2Rªi6{#G *ڤͿ}\y@J~j0>Z7m#lZ7m# (ȵzti,Y9C&b0mqj„=8i' ݬƘ~6~t-nU܋=w7}>~hx~X~rc]U\yB" !}Ty;iWq$9v)碟ۆED'2y Z)}}pǤL-W:8> IqVlbQ;չ3k>6x %L(FE1k‚I?2^H\WRˍmr;d=Xq]?ZXbgQNڮmlOEGyzҮ$Яbɺi:&֟tڰy;j ȓ5I+&z7}IMaE&UC\L|m}C#M2s lgWh9GKq8 jbs|/IꅚεRȎbrڈBOF5+{s%I欫-ȏ7cQj%zv}=ɗ 6 b:nAr^M'v#&"|%%Bf6n滛nd[:Z%SP؈h+HNZk|sOZ;Zg<>wi' zW9`Q|<ˡc,}VGOaz>{;wf?\ta.@:7~ᠤ6+|䷴\\$jҀ-:G!eK5=$/YTMsA`|dߢ~! ̃5$,LbfMU6n=rh};+jC~WzֳK)\KJ8 Q{&Zsl9֣m[ޚ1rU $iG?O˔7`=Ď]C<6TcY̟FݳsYZOZ '$F 1z'.sAR" Wy ZJdĬ{Lh @|;g"˓t Z]%Z@]E/nq_SrRd>g@5#THnB o!B0S+-` Zp%_pem")=;G{J>U'ڌBIv􌧢mPN48g1e5B@s!R:;Vd@ c O3/QeADj|S?56`ճt/NzgOW@S,Qx0kLr A9vlZ4sMp#"@+a@HPJ\(?";N1V7O6GkiUe`F*_ּ7_0@D!A80pp֛N{*uw!ԼSjOh, JvȔ,XmK;R}RkVrgٍW~Gفs S&@ ɬiBBFc/jĵHd\AHWkUev|{{=,%xw?uvB-U7T^dt4쿉ˮ=}s85ƏajVu]$A2dNpmE6UkU nͲjTKTSg˪pf$9X:hLIUGZطyH-Ŏlǿ,kiK9$[:%˧!i~C[n ;K ^.#(?ДCý #@IP#4||HTH3d%%*` %mQn0K9,j'gѷjJ) % *zaB)W~fWTt2Hj5sYYʲc} ^,G!\9hϴӶq-rrH^oqqBpM^L`4~Z=fdhx؋vH,@__m76U ZXiR f ZV `Վ?f;96?2wշlLzsݥў=MO3rRÎ@}E5td=W8 )%A)\X0d94tr ih]Z"|90Z/p FK+-V!%-P~M֕R+8vCʋΓ9}EWVsdc8$V斳"}4 z+[qׯfՒM):Sӣ1]hSSl}cq[y!bk_ěՖrA[kkv[WJ:AIiyX.D" "mڪ$5k=H%%];{zBD.xzE j0;JUU2 Sg34P8!pK$k6uLz >V@ӷ,{C+ZXg04/QrKv5y ?w%{R$o]ZOhxbwA)7 D}H#2"ZUΫ(dRtظcZPVpg?BJțFY%1K*F# _oi9h=Re*2] vo eP /"}hqΫ>h:dJ+.'8빟#/I1!z7Vq$^C pz)USEJcCXbU-;t⡊:ipi%yW&V~! ,T{6f:W>v8ٮj@MT{uݱfҮ"HJڰk&u5F#)(k1*i,A;rpT=kn$0='' ODT11W0"Y!I9tĹ+D>㝮mz;vN[)v쨍ڋM""_R :m z<ƳDN(4 VMGѽXrǝH&ɺ {32\D_oJA-|վ"?\YJh)d_AJJ).#dMkSJ&u sɺb9`[ .,0RFF##`! ҹGPCve_xcd?2F0Sٻy]4JL C*f1fjuL΁! fR.^0z%f(0sbi4IOU ;m d{B' [߿ՅH1м.cB}W<rJ;zHh8ؤlhv'9Zk7B& -Hv=pjp'_،ZXI21w -P?XV ['N2% J0ˢj\ wo_oG5mh^Jڋ3XEbE\ga]*^Nziz)ӞbD[G9ZQFkd_"CED2@+[oL:MKS|"Uƕ+sy_<%&S X<qv{w~#m"pbI|ٖyZ$c$X0bV8֘Ȼe2^Fɥ$ٻ DkRUs"D+l k. uVm~&޶zFövH,Usxh=ٝ}rDLkOV 4V5ӷq(+n00xbp6M_/SdU ]@A$ZVƑolZN -_b%"-A ޽]X7I~9p%JH<09l,жeo^j{\ɀts%7_C/7IOeܲZC{Zx[j؇/yvބ%%P=F]Jƕ݂u9_&U*+4e6I 8۾}oJS%,je_(ÃhyqNAͷގ8H!0si]{ P\ʂǼ!uWGW\KEwG*)=D9i='*m_ZhV2^888Z_bċ/B y#UhA3pBzF񂚾<0Wo^=rnEAvvxۡp3fοj G&~i3jXӷ&6G ||GŹ[2cwQ}NJ%_3+><|-j$Ɔa48J?ו~ m \ }i?'ZUH! #$.W<+_{*f-iDڅSGB`TX\C+_H;K[G*)tɺtos~;`C2DN_|m}[_0 g\IqFf_ޛ?O(&(2đ#RSmoF-%Dbypr9D"@N} 5v!U'/ٝ""0XV fum<Z5Ƀ|DT]S͈2ÅyG^-0d3YZZZ(e֓ #@ӕ3Rj2H WjMf0!A6$ˆL ɚ|߃؟L2Z Fhf8e%q}]$zSHr >W{!J/ѹj< aM`fmE&I^{[B&-o :5܇hxJ*Vͺk.X]~u7z#^xQrV_O``=WCNB qSS1tƐq$z \I}}qxbiMYC& R|ӻ-߿eD'zJBbp6G9t,]sY⹊#5Dvd$T'YiKt!ə"1=X0B6]H9ߪ йΦ G"{*_FPbËH}y"h|{䵲xYSXA<ѡ&elG#뺤RlgN }r;v׷j#f昮:.mGƳN&*s+3|;'a2>R@ĒM cVGH4LsrdOH}Mئ6QajAvX< [+ê:ɳe07%0ʃp08JZIhzhOsyU7x;:;(kX~"\״M[m53tNe3P5#umV!չ#8F(p@!_M1 bp&klsי]MܾۭUf(ju}òdʏ+^jj>%)<*Z` ,T v;[ d8W0MUy A`m,fe  Bw|%RI9OO{)ʥljBrUگ[~+޿obpUlfenF=@cMg86hL4$%rqlj(@ezt!@FL2 y[k\1~μp5$`_~\] DjPp(yQچBP-HʩxƏG`?oF Y VI) JOsIϡd#k3|3~h(yќ -W?gxoJx몏;^iԠoɍM{:O}h eʑ=\P8~vff9ZcWYG$;zBt4غa,P B.|\s'{t?dӈ4xjBq" .8bXO17iHo[R d5-rucb|=hJ\!#֛ϫjuSB|w^w)NVѰ뺱ר[wTJN;3mU?^&ުi\\xqs#rQF1I[J)%T͎ońe41l**{*~_? VAV؞7]Z+*1(-, D˺ ;ll}2J9܏3|w-p94/VMӝ҄q$-uƢgC"zwc\p(P$ƅP:d&FałoGTe[6KM5u%mi$ޭHǫJ[&ָV URKB CM(C)q0 D}2'FKa|MBJB]& ocM`KN) )RTc=R*=-=Srrך Yꪳ[b_!~F',Q]?'GC5&dvR6$k3Hۮ b)B 8$l[]! 0x"!bV񡈺4rklme3mu?Dhv,}K;=] lÊS"ڲiTgT^Q1;/<`گR-2 p*O|#EiWB 4"дfMwvp'xyבxϑ\/"ݟp(Vm嶄o%D)8]٥U!!2b ]A`Å.* j"AJM? "r|9}=>Bcp 8K\Sub&F$ga| [Ϫ5&.OeB*ay\Z>۽R%`ju6",7枱`!cϧ $ݷ Te_c4Ol\n:Vz={a99wdw>'ܴ5{LлNcʆtgN^=WM"P!ڃYJ!msŠ+`Cf5G087Ќ[LWYÃ/X~YBWYjIdqm$OX7Bm=aN}6w-ƿzNa}џm֏ߣ-4NӞ`F(EPF%-aq[Ah`Zsi!cRgjmA$rP!0ʤ?JP(AMTHYWc{#ɑcٜ=f5IIwJ ƺyQ߽ )Da D2 Q!R= n"&& V-cOĒsI@֐ XMgtabbMf}W~"pPB0|-tmEv<n;G I5+d1 :=xa=>x( Oe)к^S䣭CC1mȏdjAM3ڰed}<Z $0 pt@9,S|vm߇cVY l&鄹&U ;"7ɟc,Z1`N1&ch)й WBާ#ja5 ֘6n0HG|B`~웨B~S`mU+zX<{8&5+]2&Üt'sRMw!=^AU,xG/D2^IrmA?Z[@mF`QqƥHIwTun00`p QA57DѸ$&*$f& DSYK+ʦ, ݗtl}νwdy9nwշZU,'H:Tٻ3Ɔӣ5E\f6K %=hHA5Wj7wR.kܫ;0~9 h\փ,hXH͋=g=Lb_^A)'t˼i`)9?;O@`DG¶{"@ɂeXtR^Fyh{0&QB#?~a)Ou$?'ŇCY#sfj{ij]83l²fB$FE҆H];F L6cW=-5}̢ތvQfzezI =Z%HM V[@8wĩ! A  +X]+ªkf:uUNSSY/IZc?p}~u>^:ni¢~ jz|HMiOTha,’" 7@XuXgI` ֝ɡ>g/:-ֺI/M=̈́ѦIAbu! R`%b.J…CP CD`BHS{Zzq)+ߓb5GZBvn hl&E365zԓ 5go7Iu3W3D[ύMX%B5'Q C8TR.`ڗ}쥌|!W|y*gkqEI|>>$j<~_n7$c)Ţ`}gaƷ?!k/9-%evo@ wahe>X61JH"Bژ j9E!g ,qV9,/Evx 9k,Us;{X:$dz wI x'ߺ٭`:|ڇ+G;6zi.>CuZYKa3nI*C9 `(ţkbc1 e@-cy} JZTO7E(a̧?a3*ŘZEjP![-rI G<k1坉CqqzdkfS2ptpj*гaj}42dWjsܽ@ l=i" 5U[W- T DK_>PkT"x_0ZƌVA/P=2v͹mx#4'!]iҊXiքEЭLU9hvzZkAjc.*BV1ǧܷ]L՞Q6d.=68!MǓv9t(PFm6nS&FD:UDejF6RXcb.LN`r1[vnV" sfde5ԏN<0U @[0]r+15ib6UIm!~?ņSߓAp%֜?m|YE8z֢- ?cP]# G>򴱈YD _r 1ҿbuMu/ܼ n*"Lγ}@U1lCqpx#_F̻9('gYܻy9I; iDع/y1[F䧣1bB@.?)ǜ*<5 [ْiڜҜs/?<_݉e]tad|DH!AXg4THi$R;gP(B'9GN9pt &h-1;7LT*K ",P+~~.FLtZ>k޹w? (Iرg_fڪ雗ikl>d#Д%B-JaTαKW:Q7]GR"U-r鱋O}Kh F) 5LX kH-u #\?A)f_|.KNh_\9/gR b:&M M04 IDATE 6ܼ8q'|fI>pjoqS%5fCdypϏy9`uub@]~be9g=Cs>ӵXtl\^$|`3;9W™r{{\)@y)-ցW!e=бLj t Oz>.9WԆ_Sٱ 8%jUH;pD(0- FZ4Hޙ2TS)j9iwr!jf̉wA8QY4tL#j:̬7N^gz?U(>uz}|4m"@{ D=Y*;d8f"߅, yd!49^%Vi֙+Q0GJlqb[9K~$C9cc(ƆCn$~o"aIl:ŴڸHCD`]ι$ 5@,簱jO8gPNiD\)'M5mx2 n՞p^E8!_䭆y)?wEżb@h-Ж |*Wۅ<|^{>$67|r~K\4a!p3" :-r=*S)c-ЕWy PݽPLބ]됕@`&% S߃$ia9zT!ʼNvaZ0RDXᴹ?}&Lke_sLgqGoH_]fS[OX<(i='ΰp qU A%'12FJRa #@ Jε7jN2{%R$zZ4勹(/Nӓ \x_,aLôņ&-eg¹GCcr (&?ՃJ [;BS>lkkS>m;x1 z}2`bo5XYbcYl{&j05Ў^4*~8wWf]KfDCڿfoc f:vJ=yvUvsHϡFQ dO".dv~#amE(`nj+CcGpl@TxRVM!Z9Hٱ4eߴXwJ!vJi$a eVggDJ8K=zZf\Lo'GtUy HOr=gU~>1J9A-212f1TXr$/l)գB}ȩxI耭 %&k?*!xs\%ۥ&#zx&uCVuY peTtMQ F%$rl8|ag6,8[)sw"C?e2BXA};, a p&o}go\OvxgS=7&tE/9 J+4X1䏚9mn+[{t3BvLT5'47H nM(cn!guqx9]@M)b5KmAŦ]K&@KiL\x\(&fdX̄\~_ЦC *NӮ֧hI2vo30H͂E{O0\9֑ ҶrIdYo.6mQn@@s%I ^7P4)4E>~ƎEFm tLHqW7:VgOV(D0ԓ:i/ݤ&e8ApN3n/RszE藕 Kvpҵ `F( IxӗV Ɛ[ĚmwJ!zd=Y6L@i8<\M\UO^ ( W-^&+/fҹcReϫqH2K)w?D"rcL3Jf#zJbSQD. C~ļJ6;;^n=}7|eC9.r#X[B4 Ճuc5!y>E>vL܅Ϣj-cogM @kwRuNkaKϧ*S̝g eH}1"!m\ vߧ6!t`*7JA>p^i/ :o<9d@"IX {ؘҧ9[1¼U+@VfF0Җ&st_dəoVy#M=t -Zu&53]E_gnk=mDTH)Pe~۱yGkYa;xY*!{ N(\(Aw)0W&R |E~qs[%M2/$QpΩ["v|[TlҴ9yoGpw}!H \L o[5^PYgv7f%`q(Fi|@[IX}Y&6;IC+DB ]#2u^o0U4DKwO?o8{57,J=~՝ x3~o+3yi]kẙsv/\D>UÏde \Zcc<3b9 =ԝ/ƣ_x+c E -XڦJ͂H_sR[/_LONj2sk _Ms?%,ڱdž/<}^d(͑7_FO.ྒྷހ6i ?͝RƷWi ^KpJ&^r^p+Gޜ剐m7mܸ&҆&L2Oe-iT7~\ vߧ k^1);pN#BTM_hwlULe ^_7w]*EgoBjk,}7_ꅒ-GLT41Ct J[Vj1WgkBǑfClZcޟ㜵co%euWN[kMcu #KF1RUae9u۔K#lͰepv2Zqל.xrN2~م'sVVy [o|0]\$eԨ*K>p@3WXŸч:˰ca,;Y7= 󊚋ugnqq` ~, Z0G'Rvl7k%͡ښgu-Hn,g+7^U(&wwp+Q@J Gv8N+Y3ӞwK閤kpnZׁQӮ-i_7tSN&9`U1 jv ^Vΐn%yfun3zsV7ݪޓQ@V~4OP6OJB:pK4zR\, >澫y!~6lhBc Iv>b@wV.M6CzsbN2Sڗy)ߓbEʦis ʿ&kB9Gs;;}Th6He@g  Zc^YliF剔##4H=ǩl$K6=kXbM5T‏7 xY T,/1`"Du9XaJo=pK+\ͥoZCp9ܾ3`+(Rw!~285cp@ʥui=ɭ-*QU [S7/Y#mW>U#y 5y~fr#΍A@(-&)_GDm!AΌ?:<RUڧ1qf8 WlA\*@OQ>{"HVc h`4hJX6-XaD,,+TxE4v~<4 ѳq{6Rzdl޽ pBV.0i"j,>m9NU55ż?&9yc1}rӗ8G78y3tqkWʳEؕ߇r.5,%hvorBI!zyLZ*gJOiz@ nqy!0L ųWNDGKHZfkԒuj~ӁVuV^iK0Ή7\x6bLL G~J [g_[ӡ3lGNPPoo{ `MkTUڶ%DH0iCj1"R,{?|b)22D z!G~whvKF PKC=&3`^I`w'B\Y/yך@or@!͇|/| HJȟ-(h 0GNSSLFUF'|T0 W7Vc9sfoRSUM[}1li3EISrsĮĚr)G{ym'Cࢣ0T[MjVRMsF@H r`Jh NFeSF? sl62*.q)ou=&ă?ch#TӀ_؊Rk{jN|A0g\l&cxhD J^F V4j{ td.{M 2Ph.僟Yl.e;,=^rs&k _z>g&Dq]~(S6Wظ*j\) Q ru$ɝ#Ň,?eI@-NpX$$Fҿ^B)9-'$ Bq[D &kšvp5ġ=9HE?m*]R=9^-+I5"P`RxvG z-ByYW$||(E y,H y\uf6A9tV-EֱOliTCA q7Se7eM2ߏ東WM~X3-:qi,.*mߒ %y)B0xm*. yК%BypW{ B;>򂷶wbz}2!R16I*֜n0S-SX aOjY9ٌ|bNщ?])VHMdg=S_y%]wZ6yjQh'-O!r!An۵yUaifޔ]c5;oG9pU[wfF2ihpv'H[(@o2H VֵWcb[ N'.O0I#3{vL$;'.OMP0ZQx^]QrajƠ@CxDX*w@+%j9=סG@Qbh%:ly͈33+j4VD|:9Di*ddeO=U3^}ھ2R }5=|vƋ4s'ə;a\t nfbgsބla&G`\Gt~% k17yZ۲ec2`Xe0Wc01|:'Q5Ue* ݤ,oM^;v+8쾂dHWځk6i<︮ͦDlBk*m쾣VŔPV)T&JuW>Mo>P*_O!i[m]9zRZ i gOx!SfjklAHlU1Gv\[ef v-DHW0{a[=>+3>C5RE2C.pySa3\1nk횮 \Mб' + zDN"mF}"o4X+K%Ix8k,vRgZ9n&d\_ۏ6.N鬝 %9 L,?>[M \t9iww~_ ]~r/}}Zk?|-/}/y+_5Bs(Z6ц7lBK q:vFNKPJGgω+>r2R00e IDATSCSUgHGX5M)D VA4 ;8c\(r0g΃+t 'k");j&Q yhBPqZ2B)9&cL~mu܄C]?Kydɯu*HFɒEJ[ B2OU_9~QS6`cIf &p;ٯL?l-o۶{:2)]C@V0-AU vGߣ `2ҔW/Ql_V|dpMUBz޼dٷ?k?˻ "eh=:GQ@#!BH,vHrE[تqCwW.[ˇLEu%'YT°/vODX5~uίʃp hMt~Xa)l GZ̃&ZZ͈wfOɚFn s_PE1^X @0a}g-8a܋8pe@@C/=dy,a|5` ڬjWp5su2'_i& ۟$K+t2 gnb*Qdkֺ"X&ʘ 3oFkuW\*3o/ `Pj> ˇDڐYkҋJ+H2*c'@Я"ḍ|Lפ(6K^NcЗ)==SYyEM+VX 5GKi6a?LT?.jL9#Z\߰ $'N+W=Q$Iڛo=o\ChU̗Y|#Õhڒ!P{ߒ$e»+7uK@hAt=x;l&$ e8xï|I.xͳI|ӕCc|+Ic!ӆ+cPZdk<'YN&V>uʧ FɆۮυ`K%ˀPD,aeJl֛7rZ|ve9/45% |`͝W+qL-aVX̐`uq/f?aumlx:z%ǴߴK7w *7 ~tXrIqZP5D_O(ˋ=u2Eom |ꞁ4y} Gd~[?n6qת *iuبW"+uMr!1>k+|P Dܱȥ12Zmvv3&Zyu}YcAѼ!9@0il# 7s k*AkL."m9/V3 .D{*2L-?~FLT] oGV.]0x_ WI3ƲeӲH7[c^2\K`$_]=BGoK{RJlfڛTt\ Kf X.P(7D|w؜sө|7X *4/(ٴȱ,f:pЭW /DJir9r%='t򭜷o(_9 ˵üT#'hMFG 9'7Mf\Xq'34<_KH> Nk% dkUZ~e  @i{V"MY,3ૹJ<+usa'޾2gҔ!nn@LhfXgw"K#WY1 ֤,7gbj9h<\wg84bYtLJ@lؖ # ,} \U p Rҧ~2&ՀT Jcj1")\RNėJ[rLa-(XY.jHnG : NHDFh' !Gki~R·+[GlDi !Ky? Ʒ9 ?Xk]%\.71X8@"LN)W*o:sZV\I)$SΛ\YĜ+fB VUӱp> ?#ݟ(Dkk%"vw8q* U"@u[ҢٯFLb.չD} `AL>w溩j~m&kFtz.`{3{,1 J݋ \z[ii?00Rkrc2RcH:}3{ݧ9;-X ( `anV ޼dDn\ɰ#UUê"#+4" JvSjVĖr96E1`}d;3K"֝I之8 ;⿼[GFlx -yymq쯯<ilrf_g&` Fi&' ghk ZŮL+>㟻9b),)ͮgv /iN" Q1mmG Nc ]BjLVdq#*r*ǘ۫L?MAբj~)E˜9s@¹`HQJL33WQVMWxf:!=PoeeϢMږUg8::tXKFν^7leXU^j*_Y+ˊ <5愧XVTNo/lEZx@%bV&F,MnM^׽Onf0ڃ <"E io/L5W=s,eHcUj_ mȂo 4iEjp||kpGxUeTD`T_!stx4˘'IKοm,wv6<V6+D*WUUp-:ͺk-Ο^ŭīnҠV8'Hi!hBI&g~}KD IٽX,U"ᒕkwߒ{JEGn[Xv)Ju3WյXZQ>wbRؚ޹|B4RpIiC Ao|}E.MURFijimuuheI)p- ~^e! ;J:=YiTPSaMw%~l}`È0i7(ʱa|*oiK2 6s|yץ8%[ؼE-QH)y=X)5ߦa!3T10JW?jt1 J'Ձ%h,\G+$W3 9R8?WTR3\Bbj͓lH!'U,9WI5^Մo鞞f:I<ŋW W W XbjON|3[O{ orJ$]G/ ,JAkr,k.8\,*f"CHA@"0sl̒XwIJ!ƠϢVY]uEKN%LrW$ sE6\ ]k[ִF֏&ehP;U.+,fɰley,|*ނnm8a^ǗN}LDFp5S"ѶTye M%g_i<7I\=j'씻L+ ƐR"_8+zĹW?:D&y|wb_oչ})߃Dgl50F"*=qC j 9?qfKJ9V3x%fxexdFV%/iPZ>~5Y07{S:;X0PtYG(0򴗳w Yr*󚙀U-T4rf gjh!Sem(  \6ɾF;r4+%M溾.MQ犆'7Ãs+R3%ղ6 R6M0[ Z"pV8Uf2j oҭDP?ۆnВ88Eu7DuP6nQcVmj&|Ϊ 6oݵCݫ^vQ=d}Ƃwt<`\'|q%,K(9#̞GF00y+yJQ=+'H҈Y%R9v:k2g$Mi]("y$UyTU/w;1î".`IQw- `4PcbQ1*Q0 ,".1 l0̝9?Ωϼ龵Z<>>jت]Z/+'րI NZ >=<\:`bH\V@ 'źF?Tƾ;&qW ̗Yt~5eDݹ#P\6Ag6 VkP5cۓ 7ʞ8`-W1W@|lm?$hKK~1|1FG**BzA'lU|ƾ+ l#fC?!$[yUkmE/%Q| Wuǽ^lHCkςLm]>bSgC@p&*kYPT*W ^Nn;=< IDATw܆/ .} *o^͌IWQf{O{HI%߂@uRQؼק|+( $FVlnKE1Y9:.Ƞ06s$ُ9̞ TX X\<^[ÝMU~u}/m!ݩc32q7qIoex4?³ c;BP PK>Fkyrd0vohD$aP}I vwl_B{E;@eFT!0~qkt$joN{Ľ0O@`#!“r}>YoKa XE 従bB hm %R7.`h-&\ºsX* f/;-#!};N6\Isf.f>؀/Qzj'?D"Kġx2j9V=ln2<Ӝ|w\­i0zC[K0R-˽ύݿi0#t̻ބ[*$a(uCLQAɕ)H[Rwc9u[a͕$yjB@hJ#<Ӭt͛muBF/ذbDQids+y:7-DX]m٥G3q*й8mR^ X4=>q^CA=qzX%" }5֍Mp5\Q+"\v%!6eVpa?@ a 7]i{ٮ4_ZxPG!#Be()G&C؂Cdi;@[މ&vpe]gfΔ޶O ߟ B"\z@8 ":Z4C$yg)(p݅\7`PՑQk6,-.eD_Ai8b'9ɂg%\-ho\e| ˴`mh__w 1YH驎.:OY٭g'"gYXf?šR'V)\gk+uqlNRp\ WLUJZtuO8oZDZۖMp%p3 FؠRe_|1%Os{zla%4$ |0kyBd=;ֆXlm kLfLZ;E}]랄K\ƓWcNd@.e+5x%b84(\H.\LW{ { 4g Z/?$00}R |~zg4ԉz8ڐؓ&BjpoT릳N>rZ'V%?L3*ж Ɔ7 ^1%]2)ڂ{b-դ;i @]&`Ƞ AJf@j;L$%HV X@Bp9F=I>M;i^zĿ8Xo&j)Њ r*V;: pU0Wcr2'j q!PUL#:@hYpgkrvؚ>q.(41Zx%halaǿKom(^f)R cnE!pUm,j6a5Ҭ:oPwǡ.=-iA)+k V+܎ OxO>yKl[LY` %#܀'֧޼6|A)p_Jg6~O2ólUVfָXee~5Ŷ"`{GGu^h$lMůOEGS7ldf'$݉z"+ޡJpY}3f-K}W^[vWqeqA yevDM)jqwx1Nz 0~HD`&YHJ,񝙂cY. 4SΫF^U  #Hog50"YGz9艟2c>GE231ٱƺ*(]h< U +^Wiէo ܤ.1sM80= q%\z>%.8pC P Q[6j!Rz4y@M`@  OjUb- 7bܘ'@$Tdb [2kb,(k\s`7,ZVΏi2&{vFlݭpزYwf}-njq<3Q;GҦsdtwA hG,!-c$B7!m3T)yw]Ix44Vem- s PºxdٛIF˜Ϙiʹ𢶅oh)cKJ|"eؙNNJzhj|PXJ)BH!ġ >Z$rJ 5;/~]LmK٥568hºH`Kke,1ҹQfZԢwD`J7Ìvd-P SSB}CEt:LaR YM='4{=nӟ)1,Xˈ`[)P <|4> ]xr_@>+ M5bux'%W~qUڡ}jDIlDzMo\a eq NnAKX3xKXނO4k/$R ЪǚzlŚGx[H/@Y-B)$H3HLdP6NHٽaH3V3{7[0o`60My mFhFiWHh4ttCCuEoFlIbm_ȲXH@B_ >FD USq2ք?F"^w7xč1fJU%jwUhx;m0ǷM[x H/!Ţ.+p!=@3?݊jc~*']Q0ka5-e&uͮusƆy.9lUUj6xۉFuaҙSs3]6c/]OBᘎT-iD jεU5F8?>sj cxXヲ؅Cu b'F̱⭊.~w \%u6{3ȱl j~nhR=f){%9 8 TޢGocu2j:OX+ɺobHv@&#c{&$Tu" "D MmRa%P(xxR0ٵӸ@Zݠ]X#|a}Q@|DvϬܪ}I52enj{1@lX[~ikT`z'Ru)dIfSЫP*h#l90flϖQĄ6y3@ځ,V<wV/ު݌CıtPhPS-jUBa'y>wԛ^irC3н;VKYa1܈A0LK(mhSx[H)8RW^V,Xu Ze~x[F+|vl2ZO nC3$+H18y˾V2dٶZnWi.}Φ_o&#,,8C+ajZu&B$kza<SQ\"ٸN+VƂ,-yl[w{9kCH)&gURᥔImD+l uR)ٌ8ag8gGZGy|ܻT-,!֚9a 1{RZ[56O\%ulb˚ ִ-$<}5t:(|((AXd oG)Vcq̖+-9(m R&[8z't_9s GC\ +0YpuE4+q *:+h#CDc~?)Uȍ}ahPϽoz Bn3LB`l=+j {CRڽp%3H!;D<|;+X 5wfK$Aڿ{Y8ARxMVO{^=L7֮Ɣ<~ }7쪳~YW6 OxRb!F(d$J{Ek]SgK=gvۃyL[4'jHagI ;vRz|I)Tyuٝ9;[`#Ewb᛾A{bIq,ݱu/|Oxsi_S~3m(gbjSaK|~ %x:be5N@I8g'wf{gkhlTa`2}l^A8k\LtPӥ AP('"T&e,beN<{nk6PL nL\Ws Uld WGwaي+M1D9-O`Wc6tGI0{THy~5.Vts=* E e Ǽ^KI*bWQ=+KV"O޽`l |K{`|1 &Uv@KLjqһdx-s_'ox6d q1Ldze}/,9^M8hѲxd/O5Kzb&j a#Pl4eZ*'c+f\7G%7e4iqTU*o31&A֭e J6uݻs힛I|)mKZcZ6-&ʎ!2BY%:\YxczF+jP,H0T*5ul>2?e6&mIEuݦoSad!8,2yOc`a\tiJ $arKl%hn^Ȅ,# i@αǺ ^+4c^F_'P=c tWv'+nj"1#ٿE.ޤiIȯs,sn^-8|g5pENT_}>s35u6DJ~9=[i+^w+^w_[y1LIG&'9O_f5Z0sS~i'zO\m&6 jYt]ZH7ZDGcDD95S~fXDŽ*$R85y 3hj]{o1gnnk\G% O Ji#Oڙ<&(X"[(e_:yqLElڰweTb޶zZW~ۋ2X՘bIeMdm=q:~fӯne4p 9wq7QDֶZŌ>) l7)ke r'` F'q=<+?@V@Q-/d(Gl8^P@H+V&Jem[\n?5dլG8)Ϻ;ݸk+WڎQ Lľ :TWc- IDAT pi`VsNKuJ?q- QOB#ggs]+ ^wH;ꏿFO\m q{jUP]rټ(@WR g9㺵` hl \8V+Ј5⥓fVGi;^z`=e\fY ò==t7Chr\FBk B!D ׾Fz>x6Qфlc g1lXZF}<1K`k\p($H &&ɑ@KlHkԘk vH"eX~Aab: rZ*+\_[R 4bS;U[->#V(h`߶T4^ЯΨd,H=ʜs.\#Sd5 ;gk7^ ³%in\,L7I?珪3kcLlmdP@*16 fIر}u=R ' :.<; c=c~iعW ~6s$:3~vR7a=jj]y5wERx%xfLغ&s6 `fc&OJ<5hj`B F"cAހԥCmY;lXc<%jlݲˆ93aE6)̨+L_[?;B|>JbcXS'p+$EuG]t}4*0IXV9)eIk1?y8~f2 kUw|w(cntrns,-0OC:Pvћ7n,\s? f ^t8/뒟|*D+ a('N1WXW^APF$6v*.v?P4|K6> $7ᡯtSaaeB&Wɤel+ ڰ`)%}Lak#}Ƃx-@**05dE|![zզ[56J4ov.wUQUd:FcuQݡ I1 ӊp7xy?)C n¼-+;1h-M7^NOAR զI_޶?Gş펭,\Fb֥@x;_L3+Үо&Dϱ(9Mo'xKLԲDoYo\ 6eMNby4h2ZBYf2 ,2bW= 1(;t_m\eO2y,3 !# fw >u)2dYE$6 XyfmTd2/[303EE~O^&&iyw6wWݾfW-~z2hچrDqȖKgw9@[1$ X{kp`c"2ӶmY;& g,JclDn̵]Lb66nB;qj &D$CЂσw_ǴǴO9y( =S2 8xýĺ1crw_DˀТ?R`|)y{cjbeͷ2GHRO$"X=v$*2P76>6.{i^$=P=7~, fOR+Se/4Dp <<Y. p]?F- 21; +sP!!DH MX힛D<Be/8i*nٲ9 Y}#Iq&aƆ("1^ͩh+J$h+!Ѯo֪2@oڶhCi%00Z!^}6R ?hr~k]r6^Fֽ Ygs%"Tr l/9%w?/p<4]gb}4ꂆPu7j"3iIIM/HuxN0hЂ|xsx;8ꭶw$uUjόhN$Y /nsWK9 [* V-Yޱv֮hVcW9WA"(ޙ94S޻ f!G# L]u5mqMZoZ^{ (z4x)({3\..x^}W=bL`3)Dl\{e- [dd.2(}. "e^uymsDvh*In7svQfOPs\A1韒TGF XPV t+urJ22 )4jhC(,솓{xP{"pT۾ rYqlln5w3&#kOdٗYՈ!Ԝxguzlyi<]!#s+]?eF8;@s,ٲO?i %zv=eWpkUhEIkDzinkָ˺[n'T c?ÖsY$s#$|Atتg%Sݲz~MvyS]d- 5" O&@ptWjXd?^~;ϺjR٧ 93]W܏o6к Ϝ)޼`ϴ{(m8壟^Ɩ}x=DڂVĮQ6ocJhw gfbW\@-V\~nW X)OMT ,0X\Yd*,$`aްB >rS ' Y e15s׉>tpU;Q`8_A2f }nFy匥ŚKdK%ǸbW9J7 t".OsqG{$L|`3 t]잀פi_sJkCg3ݺ=iEMh?cKR Bb&r !ct?Lm˿l8ƺ;LtDMvgC'mzYV(auܲBȼpjv]{1Zt2T(q9-KG!0|X rma.z~'F*4iz]bNܰ7poOKg/dݎMV ( !- ZY-c- Qs\lv D'<;M>EN<7lX-ZXm6a$,1& 頮j\x&y5%jX;=Ӌ<0]G?\R IyL ƺ=0Bsϱ>&Z"oرi|;gr;~'j 7bw=잰L\qm, D,'*mgg}9ILэ~rAk{KF e,؊-pncEy-@ciMb"ca)_w- [͕>45'3ątU2]:mTeM=! 6nŒ/Fn4|9X@i'<)0cfaq Z 9aso6>2)Xf=[7Kcb:T-BΦ>bx\Af/%6CK[e,Jσ9)P[%Hd!$~+OFhZpS7.+$٪u]m|T;*xXqwmNCI_EvA|78mzԟC4L0SvFܳ}`XsnB5c RBK[׳ܪ$uO3n<)\|Toa,9aίK_ ,g/*vVLLj32ߌbĞb)*^ȏD!.F^ U  'B*2tAH%@dg(ON!L_b\ !e-c x$:YKd.qsce%4B̬>p 66\ۧ,?kJF݉vP9;2e,`%2 cf\2,c69n@d"$:bDn*eaKޔ7}R Jd#N~g]Bw\ res"Z(xuZúWUlRp=/C-AR{Ny < }~È҄&TK/:%A3z6ݞkZΕ- ҩ_I$#Uj'|c?G栐<_%o?qcCJ% 1(8ZS'ڋ)ӸjgV[6ck0RXwtB˴^1 L` H '`0nv&lKְ_Fǚp]Mn)F?ox* Įl\>gvlHҲqSBϙu.$u( '<;m۬%v7!\Jbf'+F@~MҞF^Z-$07[׵1pp& !U%E$(^s-JÖ)}S&, 03=D%i9aDIl ^&$cG5_YOͿh[Dٯhi;8 [=vYq( Ba Y{3> keAݪw—oDYg'cG#&B81Ra3kU^I]+kthb3>SM% 8UQdAb\2Isƍk}jLԿٽ&c.fm&%Ik*@SU :iV+|{+4^"-#U 0#E`A]e'F?| I2w,B x!X6ga 5Km޼ ms |nw>-; 0!2hNnĘD}@/,ݜwFmo> bW*MCʝt.ݸ}IGjʌUo߷nX#;矴{t,1+6ުXj4T8$4(R}+[D8l0{j&:|*DE-.;yz1U`{W)n<öޡTDs5y i俐^L^PS!_|/ZeWY`*& IDATbf6#^'Xg௠[M-fޤ}Ꭱ$:,XvU$.gX 2ðwJ$dǐe64/#7?wY cvmdPt2"H DʼvەdW""ò-mz ۧcBLVua@7dukx嬹=5*0fTӳ3nWjDMLlG/,<1VuӼUm j)'ш⪳hDATceYpe`Jչ~KPŘ(„.* 1a #BL#FizwvT#G#v,/Siz/ ^fSWv:+\ʁOٗZx3j[~F?QwUf_}Ӿ"B)U7Jh5:ZD aцǓ6ު _ޛ1Z( dOe0{ eh(gzB, q4kzHGQeʲDA^T yۧ4㰎8zʇ_>sc&8+}!Ʉ[^ƺ] 64Em+A f0zTW}MnLߌ̞3f kOOGyqAeRWƱOj%'RK\=N'$; Wشxm\`r ]$LVc B[DTTXFZ#8S/d1X12XY|9M("(" esI#ӌSʂ Hڰ@Mګ+=GO`/{1=cOqִԐT)j&iPPUou؀voΑJx 0MT {yiu^o1WzJm2Yjgܥ@kyVHܚ(P^ YV鹦nk>LB)'0hŒX+rW]fZv];+JZl #>5wIܹLUcjvcXr|.YX6;bөVZT |%YYgӶVn`[^֌/{'ylPm̀&pgMӘ!3۝C#$ƽ_6#h;WԑjFaʹZߴd9/D`F_Ev|%C&Wo%l~yR nVG\goe 6 &${Q9$Ҕ4@dYRpB~n͵+5tc>t'ƙ!Ĉf?} p\6o8g~}Ĝ7/ٔZQ(g=XQlMJDFx4~p;bn_k5(wa-m5+@9g)|zո4Ljӟs}sc>_qh]?"U S߱I„ nE\x)x:j+x!"qA8.)ZEuW)-{# "xͶ[#7w2A`)4 c@ߑ[yO|]9#>k]`ZvoiN狸˻xY6f$ oЎ7rKIp{gy;};g6o4 =X}+P *!4(`gj}O\~>0^jJ5. ~P(.5jo=Wϡtty?.#s @o9,;q!.y>q=++(8zDm˷Z  Lxrg6-h-NMwB,ZGnMxn/[8Ȃ<~TX;HAޕ `VٝOIZ³{B 閐ٳ݋!wM5m*Rqá" " jJ4@U (lns a\%,BOf;kzZn#k\K^^7ZgD;Ru[}z9D&<;0 IS'ۖqK(éDd^^ّ;mlXiVeS7hYכ-tAvFT"c󬭲z("̍ƀJo2+d6U#?~KX4h3ekn+/[LΕxDJd,Ku #!<pG*ߨ\{5f>Ymp_״\1*4cq#H)`f]护p~VW BXuQW-WƲ <$[n_1ڡU \˜Z38y3d5μ #JRTsRg8N!["EIOj9=4D *)Sl[koaxpYkZ:Nzm&ݦ1d8Kl7ح_R&F*4iPjڟ aݒ̰`%ڂ;5i՘ &nlm=!V9"|leiZm+ {:B~3p Wi: H3!B7[Kr%,đD]N-Oks̖\m}_!c WCs4_~@s> Xq3tT_g(uеˆ:A0jZ8fe*\P~6 @HqãN/<OUiylgVI_^B5>\YaLpke#IͥEMXI]썀n+J /,957̉|w3kMV7D.BMX5Jͣ/^wƱSW^D%@Ȼ.i7ߪ,4 yYUgXxdgrsM2@ P*Suyh*,`կ\jL[&`NvvvUjZͽBv3.n>ng]7{^\I6vtHLtV2kV}En7r?|)JLKQZPgb]) mCf*_%>'.x \i}qs&Ɂ*`oˉ ɱ]\I5Tv&Ǡ* Ӕ0@N'yhjƏ: 5/- s$>?*fR5(_[g55ܦMWV/|_zڷ-ʳmeZ!W8[L*]`a}Z3\̝ko5WM! 8rBlKts_^wcrgy|f a7?BN&W^FU 1WAUȚjb21&wO(|(ϙ+*Zk(ɼMY5:naLs]7h+.hGo*FViڮ [ Hl&Z!k}洵"hV;ֶ`Y+#x털6+^][}ʑ~lpթ^qc3GQU)thJtᄄg$rS^-G])Q_Ċ' c)t9ݒLA3)T c=Cy}I _ ԚgvzgP ?8o1}Sٖ%a4 }X*T"@BleUZNs75G4 uyΟ&w % Js&ȋD\v#8Xva jw.2JMFdDmQo6d)C_ ]D^H(/T BkRd*S}@JɌs0<S{ rh]XO:3}ImƕW:{koќQ8u& (h׷ve'jjՀi9Wt oUf]Ӻ})Wv=*[vte\Ycѣ:ozUyڍ 0 )XthI!C.W8=5<bp%툘&g/B{< \\Fn!/hmTd/==3hG#@.9g]q( lSe Ƌ U| fSeۯ5O( H6aZ4~qg]s96}ٍDwE)U|+{WRdvGxfc,"+2RRDHT(x;t#QDI*X4+O|JC!Cia%Y'k4nF0:t!͵GmWlFj.IItNfCB*LG]{m]ۑZzIݑ&SPfpكQ}n)#8:SII^h99q73EQU)t\5Ƒ.tszh5OMڣ/E6 E qyGw| 뵇d_]'5Y@zǼ j(jaļ'~s_7]X6T }oN4PէnŦY{yxb@US^5_ULXtL+^,rW[4Z.DJo-{1GuP+EfoFh7=Hڼy+ah6@WT, ^h^ھ{M^SS7Ikl]?p]d!^RU~)=*ٮi>Q`7!0 pJM>$c{ 6o`T#QuTu?,}.yyWBBʅ_ؗ0'Y^^Ǯw|@2z%,kX2W} t92)3Z;m۝qXZ[f7P_ǨСDxdIc Uf s6KD8mRjLs9Y>{#,>r FWb9DJ2°?1Ȋˉ4 n\ɗikLfoa͵c|@htE=A2o;m+S2mEg`6Q;i|xAr`dݛNގ1 !^ G<|yYMZm"lH޵ҸR2{ Bxc6+cK`vc&sv/¦ *my[?+&OabįWQF@u6:-vRI݈ ,^Oz̰גwM,HjǜM$o5(^}I?N֔x9Zس nyɥ2/\q!}l\Rf=HNyQJ>m/R5P\tg f(&kLfl\g֔N{=%)(hJ;n$zYk;~J-qXx"dvhuMKW{bԡZӞ1ѲCN6lS ߇0:\@ '@rwܿkHȼ1'e,˞ή:Υ:_~xXplzUJ!RH|X_ VfVJr6:\+\. :o `I6}2dvoPXi^3^t -0j;+ ek<tI%j@Ms($+ ƽ")и]N4Ûb}>eREA^0[i 㷂N=vUV)w@/ HWد =xqM ?`#/rXiLWDG CK%yjJBP<(t$HmB԰ku!+T·2;'^":FEڎ)>L5uoeH#f;h;K=WI[Vpt2Юjk͖Z鑂~=^!TgpU÷FbX K,Je5hɛϙ19[j҄hB#lY7#(W֣ec S@+Rx6s[$ ,`,6Ж&\{ZY3uLN{l!Brʓ-kM{3ZiXZw|aQP& |i3I0ߙlg6E?)2xܟ˓Ox[IADZoja E/2fDh~B^LJŏ5-eW-dPT Q +>,u1_:ab $Nm9h&t[x=.ivVfn `p!]M)z=u-Z] kF156Bde :! R&unty4!Gdq5CCqOxFk>7w )Cv( "TeR"Y/,cݜڎ? aGV:Th@VuOVڄkwe_Im&L= p,O`D@1ff4c 061M9Ì'ns$cT %B7qݻ G}4u髿Y`tr`a_= _h, Ȁ)[*0cJЊ{] Lu+m=|u:g5P ' (EȦP p"|vQ.`DtxmA+j `ۮ%,#X_ x[zo`KtF1&Oa'6-mr\%z>Fq @SGxs%^mg{ayx̞<[`Lfo GC B pX*9yV:%0{qX0mBðG "nOΪ_Aw[ysaYa8dU)գ`.5ۅU9<7^g @am]W 3i ƅLwg&H9y-ρ!<\r'6*'tqJIG_n({\ i9ʴ$Fۥ_;m{ `"$%}#}hdoNK<4 GAg>HI(2u^xJ߳{!H׺m8fiqٜx7BVx:a0D)-!VBo1g75+#M+)%B[JA-ؽ.ZJ2f'n!7r#WoP}GkrswYޖtj޶`7N4~QFy,x ,/Դg7~]osգ6>qaܧIK#/}?~9%!xM?+{&hXerύ>+rPd9p| + \pP:SVNNʲCvڰGhZ#W,27A!)ߴ(R׆LM.s p5L`鹯s)zJSsR8S9Y-/@>j`34o޶{]ۡVRr/ b~Q- 1(B*QnxŃo;&cg>iCvLUxaiX]ZiC.- hAGqbV$RHfpJBPo'+׫x`K_A|. e&NFi(NɄh@ChHBhz7V\ 5 ]/k綟Ts|jF-RH 4$i/Ӎmkc2Ek#aM`뀫3rB \g.sď~`@UYT6GFǴg_F!%%8CRS P 3PDQqb2{eVliP5z IDAT4c{vaT_@.f4w˪{ʂƽ( }&cbaW fKB =ӎSi xviyߝ&MĚWd~wIZNۦCZX= frZ.ݝLJ>8 ٗr!9ȠF("jQ _ GuPHw%/Mp:Y|rއ3=?T|z}_E#99iD\_j|Esat!'a1҈CaZ 0>gtmoV3iˤkb5*(%W)W|v 'P 05>Z\MޱaP5::(׮<@q_w# W>4a@lzoz/gJ_C<^3A` \P zup+Hkr`[[ضJ CSX9nG#-%&r"[ǚ=Nz&"K@JS/S l#Fe8߻w=6M2jK FE lwl$ AdDPsW*s﯈l8L?{o3=慄^tG6k=޴e&m:TZ4 H. j\{$PQ "j-qus~ޡmIt.\ .ld'pU:cϚTٛ68UʑQNw$9#Ws'™a{0M]CAE@W6p #27صpi-\;BtW[biTT"p K+ZRi@à;S%n&_єn9E_9ժ~CYއ\}yW^ibl_"Ň-I. 7{D|4W;F_ۡVf\؅B}F+CD[σ`Ziƃqmm8)J%@HL.nMfzIkW\ؗQEx,B'$UIK¾k 6c]|oqݽ! ||1AL814LGGZYeB^uӅ` > hMeҏtU\I=I o?s{.@c0sT[N5T}:rCϱ,MRdQyt6qbۍצT Rh1SA8q"~nϠ:Zc XUM{N2tB7-B'a2L PcMI(,\ bv88!RJ+[yʍWIQ+/t;hW| ]O<+7@%#C{NؖOʁ9$+!3XM+Wn;pu W5„Q̿PS)$L) R,>53Ar/wB2ci9%ROOa9W-f8^@m{g2ZIFfOgWAй:[b2Af"[u"Oz҅ǵPHB)\rDO,UDZ1Wiʑ$+lBEZ+\a f'h:.BD45LLu[Yw8cMtkύ6$;WۅP+ hc.ݮլ $كD>%4}EZae̯ *- оU7T×͹)ay@$PVf׺$ 9LQRDET 9G "&wIH79/,ѷҊr5m#(Zk@VV"j!W:PBe 9O:<{]J?N2 Bob쒜kzDn jc4a˗ѽ75: kڪ{yrws. /8&y.X27Q -a{ ({ )%R Jû%} #ɭ&.2' \Kp'Q8;O*.X(K ,([OUU8rё)ׯ "`S9#=6sqʝD4OemC,0 u%z(yd'4lJgcv f*raȔ  Z{qs̖[tmEnHWq@b0_z H fB78/ -$\pa[d˖ޮt떙993;;wOzZ33{<'Dus0'3BDxF*$3 34o:%b)r.cb/V3 J0ɲ9#7rmj^!2!:rl3ﯠ=xH:Q٧"^|U'"1D96zW?oR fP(H\F!Ԯ s| B[Pھ4k^dނ-}St\|=)g;=gi6a Z@! D&F C6dDL/W JD ωV{V9wfLH$r_`jȘBjԴc':mz6'AD亍1N Nn3[Nmijxeɡ{8KI&RQ2$Vt4`Q1Qi "4|oޕ ]kb!:-&t,Dduk="[iWP+{#^ ):iQu2>q o;~AA)|eٜ5GMgeӺuD|7TP ߪ^VKIA4`ٶp(35'N5[/hNd=κ6@qhR*ݷ3}co%صjGBׇBDAi7q#706OaJW#= &&E ix2 *'i6 yvem>gLji'>?oYD7EvmF i$}Z32)DA3nHQu#Qo е% 2P*3Gø7ƈE4ehXc JǍ+pل}+%˯\}#_dƣW;P)X9"JL x˥Ti*A Wx8L02,ԶmޖoDP( ̍k[ Uzs%%G3` K$8Vt+WT?OLVtTS3O@PZ3u&oD {jz{v&vBK3eXX'=IH ޲F SJ#*axQ+FsgjrIi$Pz L *H󯦆s+8Xm;PCcՄ>![gk -x>3JxÜu362`r҂+3#[S$ȑ }sSkK-CiQKF2$z!$R(Zh`/(t.tلܼC6P$IRH7&uLU`} ʞ[y紻DTC%fZE=ӗ |)۲71X# h`WPn=Z yDoZ˱Åm>j Y97h˽6͛@.|FX&lc?m[[dY # 33 #:0gb=W7DSB:)VEVOxnЩMn k]pZz~AH Fd'vC%6~|%(`J+ل@SI lS><~^rkJ Q1xhh(fj*]?lvSFX ,OBG9x?R嗨MCAUP@ ad|×^г[kR>ߞ̾mBXOdEwպ Ֆ\MA ^:k1H_,n&? AڰXJ',cƧ)(%$zp~lM=yN<"ܰf,y?65lXaS=K;Kn;qR@=O60'9z:0dλ(@*Gd1,2,|qL.D an,=WRjP[Cswfͩ ҄& //;nUlmc !.VN=,*Y, IDATҍ5eMDvg!$FVlP$A h\"rh.IgNZ%"}96;Vᄳ qa8p2f/<g\ncX!-=IWCJ/dlSn%/`0."0[KP%%?B5z{laWa] FېaCooY$J@54j3V 4:H~OW"KU*> N+yF0p5-<2?N Rp~pmp/%PrVda#7ylBU(#t Yk$K?Hɇ({n4hMxiNQöhµj^~Ա}`A\Αʇ 8΄yö:U;$BmZzMSC/``AcC§ }B"& nX09[RT]q=sDU hr*d9NK4=Ad1s;fnHs:nl^-Iy Nfբ47֙M{ˬTC:P档%C􅽜C)ɶyǷ#@K=&<m+&k*{+|%&QsxĻM~p1.DWOXϧ_#\pz٣갰g|$ӴƸbZk ̭ WjdVuԏi˃'-Iw?N4:Wk1D0}l}O\L`h^F-VMHpo7ʺ'|~so{IUFx}2E.ߠӺG| b%I:w$ +fs|o>|ií+?6oDr&8XXr|:ן፣WfR_ҭKY$oXϜwuRr^U~>!-'jo`*ۖRC!F~1nB (ЫBIquX{ *^B`40kj> j#b֛h' 4G , #KS0%D6. xZT M=i!vטLzb@'mbx쇢 Y$ny ]h=mz0/)|,oф8m4ݚ웁7X{ª AD5 +Թ/bɦ.02d{yԩv=(mPRiM(%^]L d xcBȅMXtf9J {kvń)x #DbB9LºfK,94ƪ lrMWCD6(O{ϗ|vjWjy&ص@ r,ҽr:z1%"2\}h:xǟE$ZV8\=(D@RHTo>I Nu'V*k)3ީ.‚]MTjM芽NUVR XmE@Z(ũVA$G糺O͇>6m'[iÈqPԴ$,Wg_kK[]*(J"4znBm;sǀ5W$RT{3 ء՗e3!U/8mW:(8 Ү/)Z\ךZ߲%#Loe5jd˓,IfokBXz2?@80';0]4Uw fQ{s_'fEewc!eLP*_佀{GDj&ybq{G1q>3ڏ"mrklXjUsfiƍ5[s=TGi70w6 a+#a`Rr2rBDڣ6^|'? Q8;XiGҺE$OL|]XU"V;=gyF,A6ǯeߣ'%b ۩s, _ <) Au `*'wIa*VAIIy()>YZZWlIep3'yH)w)zJlB%'mʊB]fTT\O4@֞')=ŷjet`N*Er:0Q 3F 5W"#;cW 4(u?DM*s&ۂ!ߌr6[dMM'VԤƛ]e7 U!y޹$-8t pV[0"pH\HƂ)O%KaGlRKw?5va翛%\A_AW M¿G0vF{zP%%zE@cbar8 `_OQ #^xeɅ 󬞔|BgI9&}腗312+a$w0X0QS,ҲNMk(gdGp "aO2WڨN&5m=61ڻ{4&x %pnsx<6Ig`bC ݋ƕBjAUH  ~* (ETYk^WSIUٌV*g0DQK)57<-O`gv؇@Lͩ;\ļث-.s1 ٴ N 6|x dDݗ=hM㿤^xմ^L!>z_Zp,8%Sq!]Gf% Cnբ)%dɇ'̾"WAdPSk ՐBQuCPsvX+Bcfg6˲I{esEhSn[opͼWU3^1 k ,F0-cr,'},;WP};999jk7P/2۾m=sj}î?XlXbZ|y()}W.${\s PFγ ȢI7#ƶm^Q`_f+\&l >kVu&lpvƶV`(*0{^aG) +tDu<3g?%+6HBih=>pk*Iy &|d}e>UmXz9ͺLGjrI/ sAL[ZUdW, laJ^v7URTg})ߥܗ@r/F@kEy6*Mi jMа6C2HVs,8eҝ0f?\mxfA1Ez)R*H-(mZIŁP{'Sp}'5Y߇NY_ٗVVTL+*|%Xmpuh};p mDzǎXn(*44NpB.Chcqmc4LM@Err=@men԰}`U+,L:rڎ(w7ױQ'|np=Ė|K[,[[͸=jZNk1M8BjI#!0ڹ﬿j٥ZP7K{;L=%٬w|}jr_3SdP76Vf/X`=qzVAlaFh($"xR0u;}n;bC?,=^]ɓv_7|0f9E2 -_n "tu8^zq ;Mf/*I%,|a<% sU1+c [P|Zh$*xRR޲%%cΣ՘hXf 6, 6N|65lXGT+bȽwhI.-[7%M.%z- OI4}o9)Lpwdy^[{%H?v3J)|)XRNX \0` v--V <)"҆o:i0&1(Ƚl)$MYX0K)e%)W=?Z ,bzI1XTFQ "b 9 7|@Kޛ짵AKL+}wTӲ<&I羫evW=l 'g-d6d?["E33~HAe- SX\%}DZm,"Li3-z#~K> U;(JZX)3Q< F6<,ѼmsS̆isѣ07ʦmgc::J%^a 5c}/g~tIɬba/p0ނ1Sd| 2[iv\Suw;kߺނLV*![>h"Hiwѣ2ofcߙ{NqzOZ>EM'$Tr JPǟ;%%MkƠ3'PR`tqF`t#dhډ/ϿzF> H3e͟[;qw!zXݶϺ6tL _r-'MPPfZ',Fc\%4=2LV6jM-L&[nƳ*BJNppB PG:㷳2j][gX6oQxz[\̣Ɩ,){N JPQ7?~vaY2 }O[g "0P/f믾ƴIѺ;xiנ_PNTrZ໧w\m=WB\M RItЭ ُ-*gvȸRB!4{ϖUh<سiWDfGUh=T}VVmRs0,ͺIvUc^h ?GӆOoE'PV:e+ZIŔO\;\8cfV&=XGѱ mt򙿤z'D"5h`<5]63^̹/w겻WB@2p`E;_~i?腗qgj IDATX` #{Yrf3WN&k_f J~vf#8=_Od5wg( ^y Oon$R(zʒ=IA}&KjCVþ|a32CKZÂi!)t|EvE` dV{=T-G!yGx(r`; \E߶Z E<&7o.ݮ}MU۷=Xz[BeMk x]C0a>jLG`1qKS=]usޫڱ'݆<40;(ꛞL OZ@3s1Û1z+[+m.i0J)AZ%g=Z @mYC)mk-Mll#&,[OoQ1/aj\oq z=ʃ6XC?,eߣ Jbp}ٻ+%\"4=+`W+xnyca\2&0V %xvqvzy睝gOgO=b, Zke%xՅ3^11 B0NP Nw4FG8XP\e}4W3t{_Ȼ&}`Uxr٣t㪚M0&w$A}9ˆzƁDF2ͥr{!Jw9XJ=S%%3V݉'mDa #`0`JV,T{nl>qqGm_g s_3>aW}J핐jH5lKQc|U <[?~.Tͥ߾O^|:]t -,1h"i]5F.X6Aa ݈QWA/2qpzYdv1e`1+ J) # qrv@!@CI}znT\ TH0cm('qKSɞ>tu iQ//H'mm$m20׳}_k5v|7`h4lYJ)"5jԨc\qtF0=䲕(.9i_8Y3KMm^]U('we= ݩwծ\dei]sXU(QRW 2itه{dNPALl 4@ERr`O=rVR\&a.=%hhhYb-3m }`kN yV֙GNSJVS̞o1φ|QWu u"C(!TvW%\2{5ݥIMdY-xTIYc،BIRodK21ƸFJkX!'g4 v` ̬ ᛺9|R.<ydhk8ijh:5%=;npdGOZs[tƶzv)8pCxZA)!M`b0$_W jc !zO[0o٦/Q_1{<d>o\ѭ $"ETr?0HvXvҘN5L6j$|ɸO F#%H!zŬ#OV\*k8ߦ}&^ ;]7[&U%v=?rSYTƖ\Gp(xfbazY79 Xw&1,򧁺(8WieHe,ɸM ;wqE}ޢϗ|#jEgbKuCuꑦ e_22f:Y;c5{IkOK9w_gĎhn}יҟh-d2kzzy쇓 j"U3yW絫BS Fx$,CWmV" iFaQ(lBNqތfC<9 _vd,**M_g?9YO{9XYRDZnnUݿvzL5Gu‹m4*Kb}+`{%甗cY-2IК8B8: I=S D)+afkD uhئM6rW=+Iaj!?ʬ =m__J _)zm?5aBcnÄ 29:d<J J н@{B`YqرzD=2D_)f/OI槸|'wanܾKO~X<]ٛ,rWf\?p8c=$B ʹ|fOk {g+rR9 Tw(6WNl~sčgɅ? xċ'sfmHI㫎`_ jǞMbX+Aj^z~w9 _&g_6<Ⱉ8[QWlPcu4;z#;N6烔 t& ڑg IJl}%p+y|΄ 5]eC%FxT$7l+)z6/{1 4!=% NpԂ,t+%W_)|: (z:L4fO?R-nЙ̞|ќZitGɖU\dd H*$c|~4N?D-[z 6H?_ 1a{HAIz6x!۬oZnyX4RS]VOW{V=V!'ÄX 빊&j$f,V:DfEn8ѵ(7|~Rm2c+]t)4+VYx ERWGwB >v\JمA{|ILypUW%tv> !D` 3$Lx Iڑ蹯d2V}gc[Gz^s Njp&"^ja'&jX$~hr˿r@iimಝQ;}[x~{F>F#]GyyA{;p/=2n O 2p*ư3m9CЃ\Zoz)6DYU;ur ynx,;X6n~82]xrDQ@ zXx;Pd^+p6[|+ S^O }rAkCw_ І0~bץ{ob썢SoPWvBe֟wٺ5$)B?,_YY+nbsFK~ȣew\٭TIAtw1b6(^#"z=U&gV(+Fl *K۷^4C9gĠ`}h8>q3ΚK Z',ߒ} P㝸$z9U+ 7dnk%H1(lJ]'7dX`?G$o%pj6M8?%G(C_ `5BaVA}858 U$ `@!( (s U{U9unO95]oVNlŖ{t{)5@T_{7M"0)B)'[ ymVc'we? s N7rv[Wr#t6(8yS]A9T_?bF[j&gzϕt+kQ/xk9ض=dWa:?F꽚GqS:ȁٓk> j.L4~퉬 yWK1\q@hk)]zqG[iٜĤdv7RD"~Ys.441m\uCM=l 450P<6l#Sg;Y!tJSE( ;w{u1s>.owjeӊm+#HP ;]:7M L>t@y(0v癍\˚z\\U*`+#iC \Pp@+(B}*kfzX޺7n1>, W#"cI D gՖ+l_*2Wfw6yf/G‚Y,%O #I\x~H 0H7- ,~qRl?ܧrdvD:{BkC']+ 0| 0I u48>,WFg  a@Ī5U&cP iQ'I2{1uq#"FCqұdǹ럤/R GOشcNnkWr!@vWV9,.]-- "?nPp֓\ͱ\^owzA>T2`k@ѝ?% 3CxYJZaA%:Q+:;ϝ$ pUf>tW'.;q+&jx:4 0ZF Wuٕ@Pd] Q殽 Wb>}V618*O n>,?pN׾7˯g>_T۝@h ̻Q LbikEe1E[˺1|8W?4eq~+6[6}Py"Ogʼ8C{֟X6~Yy%nzEwv@EJoA_zٛ \-}*=yn ָhcBS?~g u@0\ φy ~gwt5~M?P4b~+h kSZ;z76_bV@]]s?G< ꍁWS qAcw(MW'ޢ nG^[GUڢxzb<^sWW͟H)(8qӏl甧<;+y|~~ݻL??B P_ZS)czNLqL?8d3f+ [A[ IDATUlH}loP O⧞5Ƴ4y&o% Zߍ[׿\J#1S#o-m F.M샫΢CHE}pwf!] {U < [޶fdzd;\[B7vԧ<(J?zuGpٻ#3JSt";{Ә+2J"$`W6#u&Z Jbg7C]0WoLKESWcv S6?Gޕg&~l&Ԑp>=xN (? <P-)w^%7[|WmXhX([^4ﲶ3c\5>y y*.ANPhkY.vݗ/Rh,`HjdfR#Fȗk„' m!È1DآB=qScv죋pL@Z'‘;۵ԮJ_kT}7dۿle/[sA3nVQIfRIA#:(GO}ZQݷ\qJJ0y^·V Oe[`K  CJmS=i8|EDP ڐlm ߷;k\`{QK#+ 'l/1X (\VͶIs?r}%Ŏ7~pVf\ \A=s^+j" a=.UYF―Aaի;`', Yj7lvA@)[Vx96yrw:Dγ.0oWޮRea Yo6Sŗ_9vfֵ,L4VZpHe / "[تFN %I`ہUc€ 0( # fg׺ئw=Ԙ >Li&v6f >PX4 Qh'FG+}%E 4'HJ3gJ-H:^"*7Awd}+DqE @l(qܼDY>}R͔0B} &LÄdRa53Π~;nơx!v<3OZІc'++=nyXHL'jg9r޵ӫx)y$76}4{\,*} Ac1y@ak\^,xy'hj?"r l4^}\|OO/H?x6rSIEN qn4˹J'gN" 45$kyOYPX`Wu\,j9ufS9}rdv  '4' 6kJmR Tk{JI@xRD-ú(TDA2IB=\F$%%O\ً:UԳv6C+ 1t z9/E0abhpE%/4lj}Qm72rN3l&6Mʡ617Y ͮ~gs.d 7- iV)`\3nؕ (1J,c(S-> :Ix7{=l1q|hw+F+ʝH7/lxq]{yڿ݇qIAkRbW ($\eV܏TAz\ծ PD7lp5RȘA&,2fQ[c.9u$}-cFX#a0^pfC-)`mYV̮isZX my_GO~ݴÐ8>*PRCVxC#ȏ_:L}ʀ{u6&{#6zg(JPO}l#x0H)BC)1Dbmy,cW%q'.e/W)י3ڄy/x>\ڍۖkI\vF#i[d´:L]ޥ yM^cV*}zt[]=tOObY"(v喵b3F+jxOJ ]v%9U 'eև/[EԔ*(hW0o=<F\GPC1'\G(`-dY΃+izo.IQD J?} vDM6 n,`Co>?} ~zW/iOaVvw t2T=TBE9JAmWz1иDZ%ewziCgŪY (Df^p9vXq}pNlZ8a9'{faN"En}R`! IͰ#\ұ,=M\_EQ@w+ۯ8X3UsFkWD|E]t>65[ w=㬩#hIژB2 \։yU7Uց\y\*pElz#(ՒaӀ+oG 4] P@ $P\<`Xa#9o_폲v{qU|[}.5EW//9vjE|RkگmXRVUæzFl} .WD!*0fNdŴ -:kjA֧'e,'՗ȳ# gF\]aI n!:}gv+Oܺ?>|XW,Zp]֨F} {`):p5iVH4㍄( Xs۷|nL\ NAo]/1k`} g .93M]s30oaOF?S&ZL7Wa(*%h)r'WƣPEr?(?:NZ$GnTL-N[L3VaZpn aCVK fd!@1.>Ut҆]SMAA^݅?CQ J4.7rlIm#sfX3aO.a.л.q=#O]>!?qCe2>>t˦ weI`q)˺~@"*G(K+`Όĭ^_g4i8kazgQvB+eY'lP 'kC$hY'Ih"1iغX$%Dza;.kW~JSI il,lP8<:MF6b-%WBE% 1{z^24bf n9n:p/@V Rs@oQ GW#SpZ-jNrc7j^͚Νr6aދ5U _v㍄fohƛ k︔w^gۍ~R r]wꃖu cj؝Pd##qu_y#_~ga;u/Q$0% fتhXa/=yS(i\(0:}ߝnBĕ#KVWxz3^ǼWjǝբFB1in yumQ]^hSl]|Ӆ8V"ux [wn\Zz?@Ư& y>j3pEb3֫u0LEGA'M^9/P E vm;nk#G?D3k_Xn#l7kj?ni*&cC3Rnq7m ]h 00TYic25_kRM LMAشu]`4[.Q?UV-Yi MjiVwG0n7y%Y˃;*paA(C{{N=,8+BIă.1sA/ܽcOc"F~׬] مq&V[#+:)n=ފљ v{{>),@= N=ąHzÕ/NWCm$".OAԶ߶]Xy/VZl}zp736" $Vʡp׵re|4^y O܋!Ȣu% ,w?G%r@90/ie=kmVCk~3 JQġ?[8hjָ,O}(V;%%ih 5{w䰑 EcoiVکU釈?VUCF#ՐR&c|0s^])Ծpy>E"=g 9UK!gXIWZ*\ӹp&ܼ M#B;ׯeM3`A,=l"qc|w^C'2Va q@Eh@Ľl@ef BE9=>)oIDhB. G޴. ֙*P*  8q}MfЬ.eՃPQ5~ӿ̹o0{/ت#$cEGJ!{-YleY@Q{k|:MD9i4'O PQ XW\]k9s[鋼* x^+Ԁ.|+#ՐUޫ6;C; hMz2AO[P3^y u` 1\̜v({Hdف+g)N^/o)4A7LdX4 Gw\ mosK\+zӿ`ܽ}{'\OLZb_b/wM |z܇SULL' Ķ1ܗsi EQ,P'~֗ByOF }WlmE[#og hvJ+:w-z6X  %BѻoV@͍o5+? mH [s;ڃa& *lRnM pt%"1IMygBlAwPd‫ZaϹw¹XqF m#/ga IDATĹV\i N%`Sʗ@58պr`y`%ɨiEXP Z:ii33q!K1kɒ+ X3q*^<}X)Ja &A*Ru61ãuoRK4F^[6Ħe+OpsU=`ҲH%TDh + ILh8i/;9On.䈪i }دi'tV/x R@j XM݆7/|$>}&e CE%=.}tz2u&AlVƅr w}-U_)`Dâÿ_sp q٫<<`o= P7M;[KrS<ҖUCMl6!rɹxvQy*hIkWLɴW,œP yKkSNϪWƑ-ߪƏp& +nxk\, `~FGbLA)OXx{5I5Im%8q|˕>dw3NgյWQO 1ς@ЂN(?}F=^AokCsX{-Of\s[ N p-^vz>hn%~NU !WӴUX'klb(Bm>'ȸ>#?U Hy5 CxsggqGCjs-e+J9K{e fꨚb%{v8ϕ8M Oegă?pZ?ۄ?2(9O.-zuƇo~pJ̓)1օ6ǧlǣDyһWo8U0Ȥ[^12\xqgg3к)h$Y=\wzkW`٧>=Gv25HN(?cV^a^֌ko=*@8oNFĶ@ԕoۈ9<ã &vۧ)^=/?I=Y6uVSK&:qnTZIag۫f8wߨT @\z2˺+ڊ{҄b5^×m GG3زW~dJz/8Xz @΋j $3zVq^-Q27΃96%7.W05C)@r/G Vx_ 21R-`$( uw);ⰶme7=}nX$8r@`qsZG/,%@ԆyM[F2eV?{$X[J:ⴅ:՞#-eJ苂E[ k24qa^~C]Xb-6\{tyX,F:NypFV!* |{CgEiy:c'abMl=KFQFb6h{ȯsEGҢ# F倡UC4 f+c+OfTp|J?)v,{qI@y_ z0\9`e-ؑc\^U6 뀖j muաY?-ʑB LzN7yoFiXt̹m9\wAO%3`9`gi#hh+hkGB u ;zN'ˑ]80Uf?~yc*e^}\|{BqbdLߟ|hs*sąE_Xc" 20a:Lige>kL2$F3QaA'/W1%zP5'ﻂ;xaˊ.Ts@À '&\y'l~c} 灇Vls>MyZ$cJ=aE'*RǷOEuwe-P* ^ ڊ+gVj6#G l>B_w>!cFB6M#Fہ!A%,CpZKqaX@B7>L5 |\ɘxSNa>vCe*kH }  g+9}>rcuG\ω{jW~r(C0&LBy7~~N_I>T˔^j|Cglg?LSӫ+0\I%sj FkؽR`'i۪WkK\F7~&{+ơjrQD!=y$%4~t^Ȩ-@Dw%Ř=f6|+r ־;kh9R9@DШOQM|h[`u5->$\R-gWQE,&2la%L;%{Afb_%="$R l:dªF5ڗraj5٤CܳW46~y8?[( zm/!C}eZr!!D!|HxGl^Y]XQ oi84q bN-.9k\ɩT=`UK4x^tvĔGŽi3tر們] * ô6AНIZp`RF~ x6Ş(qk$d]QyfG-Kfdv0ϖ|,J5RΊMAVK!N_)ܾ>Ĩ3/!%4/ؑIWv"P9ɳ ZޝwUD2x/);br}0@q[έe {=R;^1A9#޳J੏@ Wxᥓ N@`4 QЉzy;3-iO BUuY:3b672teEnMSN2Xes7jIQ Q@si MԮmKsJ8+ 38UN'e78ydim6L?l`1X_^L6h1ņΓ{W9jڋzG լ`:-WpŃYЫ_>Gztĺ5b&,g}Ua;jgk@BZ3&Q5ތ s: 6]9oF\Lv[ԡՀi!Ł~J%b5&bXv7_>LL%[ EƉ4&ͤIbt윆ates̢&[%ZFv9l1~Bk-14=M\OO}z)pRֹ|**=b:kʉw?E}VC),K㍄=,S0/pЅ0g綿{8WsC{mBà H妺u ~p͖wh6zøᨍlvU,{R)@B!I ڊjVގ=VmY>‚"і-_pşJ&0)i uaqZJ'35',}Mos5}kԀc3B M hy@eZڴ@֔FX_]ھ4Q*`OsG?ƹw=vf_뾿 =4n|Aφl0rN)r u*}^ :hKFU {P=QS vZ\XqcbټI֚"aP͋hyH65/ dD4'̉ >x]h%M{ɔTKSw`5nJ>uc 1.1( ҴHN*Zxl81{"PVEāViekBlփ*׆a$dui56cMeͤA3iB>l}Td}m ÃVCuh/?Y;p(?tZ _@v*oY-#R GbL&cm}jq?F@Aj+k,K׸LiaѬ]-[=4q9l;Ȳe콺!IJ6~J4);utd^pD;GYo})˟̞mP \fmः@YY8I'I,-&4© 3b󔆍:_hjYk?oYx?f`zV᪨2kJ#)0 P BXRdJfF}0ك̾"XAlz#*LZJVU.1I-&V{x X}Q-U(Z)Enz&VB+m+3ڠTБI8Wpu8#GYŽ?J,0V?`[#e\ZVO+#N yɢ3B/gJ}亻a}C8 zߟ#5 Yo^KMr5Q ! MCmsWȲrڿ dӁd9⬥\U[e̅]ӣ5V+D+ʅ *%B 4u222%k^ ),edv_͠ʔd"<=#F2J1? p=ECpwR ڇG%561IcNN[D,F'R^[N`iWV W&a!Vul5 ,YhG:6<8.}ʏ,P̮]XET ϯ r&i oēŶ%[k<@sb^N:.'nzќ'wr1S;m ڔkHTNU tDQj$ U&jBK I $$l!$ЈS%{&j%m$'\8`Eb!µ"'xUbZ@+Q8!n6yh$!H` &IZ{oe$F/&/Xl3A€>~#T"$ 9;H嗥 OϽ ΓecE4PAM!%ѤޫL#F)>{56hWl:l`|>i'ӾvNׯ:=7*tsbɭ*knI]h_Ђ@B E  <gAج6Ƃ bH!$KbKumYvDdfUeUWueUVUWO*3##"Odge~62d2W,붖Diω쓟0^+:mGoY&ծCdPqF 2h 8G}-ǯ}~ jNKH0RaEZ&Dwiȕc8L89'!<FLViB7[3o0`fݹ&^zv㲉syh 'fh.)[oNB8qԆ#B' b"kؽ4[-=GGz-Ӄ2 =*ȄϗxDֱPtѬA~e/I_5bw3Xp(ħ\ @AcZS3lζBS;)K(ўݥ,˔EA9@A=eZäXqw.%o(}_?Cd߿ߑ@+عZu?UXZMa۴Ocv_ 8,YkRjRCcұ4-GRmTpRIB;I~wЊ\]A3D˱%Y-p u@*M&l}@b wZ:I#]vz>d[D:EQv<"kf )ZU72q})]: lƘs.Zp+J}*aԁnDIloiq%H]⾎1Ds#wEu<=GQ*%-F dtHVJJYԃ,%Eъ"D' &b!I3̾Y ^܅v׊lޒ >}(anSu0n]̵fp*m XAaf2 (=N:$굈0&?>~.S מ}`UןC.W-AU'B* @}@1?J]Bo4gzē]"~*&Ԅjg|'[+GGk'a{ R+s,В"WdDJ@vDZrܠ''fh٠̊Vz]?vSHVH @ FhxO.2)o7h96=XXeZi{1׻X` 'y{LEC")h ,FNjAVɂ$O/9P=+|D" kȭA{9mqu-؇Hi]MO[ĕI~,8Qfw_g-[u # KSфl:N):U@Xe '>o7O92D)6yOrOCK{[-o YKV%Kpik*VD "JAHa"RFīv;+C,]N>d*65hY[.EUHf>ՈZNHz=-GY+YYf?ٶJ.zk[o[oj8Yp߷+-g҅Y8i0FE *JLcK{QU0`N!L&Sx+xt޽/M hˋ+|X Q\H?%ܸ`&"j҂?V!T@CS!ctYggD LtY]k*%=}Jǵ -ׁx 8''SKsBb3 B+,fy^{?]%M8v-?Jif9\ öXToXɞ_sy\y1w+h-W0A39!ձhc,"̉.҈H@&lj@D ")đ'/I 䂁G=pO_нiߺ)Ŕ_V0AQ߽Z"!hTmjhhDCACAC_e.;L00*DFT5LU먹y_)Ag=ivi![' ^=)O.B,ylKsyw/ xAk.Va\q3N2k햵RUXK<`'_V&]k}:L(F 5xyD a (ihi>6'[׵vq/P%Ew$Jk8~JЌOXU'sA+%2Ѫ4je&rLD!Ԉ4^=y]2U#/sҿ>rې 55y{50P,Nu:ףS'-ium#(<ƪbddgܳ+ձfky>]W2BKd)„v1RG#hlN}U7@9=#ip^/9ؿy!. %3HUV*ȋj9J|+ĊK$_o=wOfUM[JFБwkDֻN`(c8h4sw ?=`Pޥs<Ӽ9RILD;wwd~>O#mTMۘM9+Ē[,D2-gW,Q\с{>|HZV)ͤrpi02a"W6lVas՟PFX)Sᖡշqqx02ߡ94/|1yV6ciNosVOjl~Ƈwl5k_h wef-[JJu n7K#R '\fxdZ-sA8encptR Kab` JZqs]%ŮE:^\bp_aZqם2KN[ck&ӞTF Ċef~ɻB6͟hgLu=/'frcΓ&ytp !]jķ/$D_OGة͟Eֵ/܏ .hP*Fi&v(|h^ڤl9i8$ "щqE*Qb)ki4aneX蒈RWX.ZX)U0Pq٧3}numfn6IzrG$X a?x?#tNPS5 7f W.ƅ/p5$([=)(>~[q븍\က}Zx[SWcSG>l/tR1*R1}j3ڌ1A̟G0Q(6K[dR:Ii<Oz $aQ Zo-btjqvP,^xCtq=* H)o';" Ȏ"M %Պ\-9'?ZJ hQ.)Js{K ']d.㌻fZ7N6? f$ I%7S*$I$B$D&'VP0[hM!OUwbpleY`ciK,-VSKFmfn6Z, 6c+kr,֟"LDn&zt:۪k|X#&rrΊ-ۇNzBvF6N Bi) Qy+ҫ}+Ex>q N@$HrE[ /y^y᫯dʺZ'$qUm/}T'N PQ kYWmxu'5W;%?ςr3;J`햞c#Xˠ5414Z 4sqI.˛/FBvE'EX!Fhyx\o`701ipyzAmߝ |G<D5-/}S \ᧅzU7x/[7_{+Kξ44(0ڹBϹ(9z-"L;Ϲ9w\o$" fb{XmCZ"+W´A1~~sC 0vҸNs$9Wиw,7ݪ[jLlC@G1"o?XPI!4u1wS-YHD-^~>gG4~eq$\;$0LlM^tƳ_6377b/DX? 墭S_4f+ItX[^fZC}+w/𿲧#ǰ"bZd>%Q%ϖ1/',l 1#h#mMCуJ'ZL$Aū3GF:wݹIJ>g6:wa"1qcE!i*1FtKZA&4aѲE3>3)蹒b2i|4fܟ4z^zK\f%#>,8sjJX,h FL.#MI0fJ-K bE zQ7 ryUqN%_4_pt"2A3&[ϲd} Vu$:`3p=%4evl;аZU\;J\|.OdvcXևX[8Rđ^-ڡX4QhX^Ǿ\}wK~Cj43]H,24cE#2<fTKBSnQ%YFx-j~c{3^- -V,H%h[K.mNG zL`PSu}D^ص~ t9̾AzN?%4{ҲfdQ 8>ZmQxAκV]wlV,.LڢMĖifijp8&}/R 9 I2PEeɻ_9,#\Fޕx4bKih{ƽwV#hlqqшMpӄǛ"\snE5dlby8s.9g͜-`mcDѨVE|DryǕ ШTfjmcY9!62M|[x3 yWJTrQ _5"癪WAdU3R+KE] Fٹh굈Jx*cM(ֺf.Z. yeU P8f6^%S 8U,|DSTfK4afroq-g .\G\pŅ<gl ШeDat`M:q#cF fYt+! g3wD*DoqKS! "[geOƩ$J 1 cEc[笊e -HI 9˖-='K%>1ʗ}G AҠ1ʇaBe֘k(k*MViH5bhɛ%Aa$ָh©op[Vf_/&6jX(_-'o̅W^Ű-`=X %3OHҠ)8"06Q~T;]I%oa߃:NiB/5V7UJ[U ʋ9zn;W^sn_Mڱ˲id~ljO[sCy<2zJ%6(ڕr.Q.uB?497HnpSZ f.Dsr.Qpf,R HL=儤6R9t`wLtk4OQ(ԙ0 my[Ok7lmQz7w?01?[V7Va-ZW8`tEW]S?=QZ+,! ©3S(?Ҡneͩ! !a`S`*9IhWa3Bœf̭T.4Fhf_+?"]WmZQ;  >VfӛݐVMZlZNaؾS.w\$/6oe`Y5Y*yX(oRIiR FzK\[=$Kw{KC4.P!r.wo?} fA;/lRJFƊ\re3=e+1V.DR˱"X7_uYxhCu,% GFy#r9qӜZ 5ingޏJ $H"pcw_x1:'Ѿ yqA n5{cR> XP`tt,07JͶ1w 츄j8ʶ]nkYDzt3ʏiV}e avIeI9FNCC\p]pB ~q%۴wGk[vrlMʑW#)'ʟ"ÄzU:_[ZlilPKGdUXɶXI+VA+EֲeXb/D?kO]'F&ـfύyCOo'O`'qs%͗Ś-qЎo6 BBR]s~o=:6:W+.XZ`4]ѱ>8J{7ߛ`̾3Z}ChR$‰J5B}Kh RW^9U** K;Dp\% { `UrYoq-[,˹*<% Sa6dvzmLtAt#=dυ4ZJ+~=3;2ehhlM9D2G,5JYn+ך OѮH)(rٵӫ{e "X;-әz<^ߘe:Su(?8d@MSAzfb#ReT\ 0'@s6WiAƊ+FH +H"Iŕ&"}^vؕ;8%ŭx=E^`UnLJX r;Љmhz<^1_ y9a$Ph`9)\|nN9`9dJ+NOc:=1jQ# ']&1i.>ģluFI$ĕױB'IzJ$=.NN$o7cΰ>fLK Gi^VŲr)BeҨE4jVqX!c}O@&G|d:Kk62Jidpݔ2"qV* h_zde EJ|RAE@촄b3.g<"6XkQ;vˑխD V\|굈OUxI~/y'WJUى$Ő+eGaƝQƝQ\0U DNDk>vƁekёv6Q%܈T1טg ioB*0*`l/~2{Z,dQ,j^[k::k@Z  H{Z\섨ȂF' "qC<n|TJ4e¤'ˋ!&u&(Tf(D9N"86/)\[dWš .}cln0?X$J`Y,ۚXLR \ DG Mq\0˔!5ʘ5[bi³h!$&I<5U>RҩPHL8LC'Wi/uj\V6{X60[ )),;$HtSi2fH|PB؜}ItE52'AxI:iHD7щCF "!(T^_MBUj= p}УR|:HEZw|W+g~:G`?+9A,eC1I%Bk#HCd>TB:(ozi])-IDD81n#B|/\?$֠忬qLݟ" >"# >srWp1Wä́Zceb\oeloBi:L!JԐhcF$nf,'L蹻9F }<:K?,}A$Rz DĵAA3f Q qJ IFG?G@}XfDDpR'9;Q;¼9|2?'e9=:%+zhŲN"IS: (Fq= ifz^"~afJv.Ǹ{N$_Y;w܋.]H#B7ChUgǣ TB& Jƾ+[)`Qޥ-DG3j  XN$Ex|4 ٦-eK> e3>MqBhmI4ޣs\edHpu;!fLe.`jNev*J{^w0K L]0N ٦@<׬ (A(l$P7~= <}>$X _d\w7ip4yDgv(Oc%S+|zB O%fq?,e|XBhtڄPt *ӏJiJj/h:0ϡ8i9 5EgO]mA&;O niٞrWY*[XeXel0]:>ߛM*DH/$kΛ(Iv C/$VL5jP(28g`ctxjHeDjpӎ~wȻp5o?Y LMZ$-JxWA[m451%ߡI$KT쥑5B;i(HF :# ^jDk?ǟe;9k.cO֝ a4X,@[di#2Q{p"Jx}Ոs+/0بö鏼w3oR;ʨM8m¡$qd; ꟡S$EsM-ͣT.}4aNp3,wf|+yBI5NZXNhTMW?ŲId" 0D (PN;& |ˏX1y<E&kO]iliJ [f?N Jw-k *Saf;x?YdԿu;9|)efJFDiJ"mD1+8GRܹg7Y-;/K䱧'=cbŲvZBetטa1]^*M*Mry#yg 4cfַI1[5%oe}fOi{QR8Ke&8ts4E%L+~eUXeLhsp<㺒p]vt$]'֙j2}Nl_+5;=IuW ;I:! RSLM%S%#2#2nJ\Zd -'26J=U~e Z,ۚ8VLm{J>M*q` x"g7J27ak(Zf4%Xp%}W69 ϙjO(xM:NLEIrQ##.ԂRCUk̓F+P` ZeGQ-互"#cyFNj-ɧcEe#u&ثe5,5K*?s{_ǔgEvVD%$itcIKFHcT39 Il$)Z_C{o=bY8V9T!3zh8"C#yy"cfLjӴF5c&jw7S`lh"Kv4d٩&S(_'ɥjf_RѓMК1h\ijP=:},d1":860w^Oŕ؅H*Zr{jxb SƋǧ) L)24436Qd|9Q7F5j[) L}: \oՍ\Μ&]kwZ~)ɭVґ4ms Xk+uD8T"bCs$RgR2jz#e+gk]WoC+,KϩUCj?j&(203P94ci2yLnM$'|GlIq+[ƔiX9'm@'h!P"2D Ӯ.% J"bDbR_*ryN+sə+ f *VSdeJoV=*7겾51Z,;8V>X(?gbw n2Fٙ&3S &4;(?wmi3IU.(;&XeJ.B8M#jS!}D(mڱ lqYZ@xdtȮ')rtL\}FLdoh[bl*s3͖=X#cGۙl;(orKٗ{%w5z8ɁC:Q B4n*Rl44zFe%͟˥c"3w'J-0izQ,zu"6{X,}و9tOcv\vl3Mq4W[ٷ}qnViQ/9j=V.⿿>e{Q"V.ӓDQ'_ Gh٩dQ'Py 9Q 9N4f+ՙcX,[(W IDATǦcR>#yFF <·4bh-5XX,bvt?1XcG }ˣ}17hHtڼXA" ;6c-zeIӛ=)Br}JC$@'h30ЈZ?3?$#cyv<>.02nS7k:PrvSdfn,iX,UpU{x45Rˆs߳JOz]K*1DqڙÜv0qjpy} -MY(xL*w_óX4~U遇6t?kYg=cX,ۋ_G>oE}F {qE吻o!-L斘퇅d:+q?#͖%:pI@ H-W͕v?\a-GBBx}2KKKmf+*9n?Jۛʮ`]` tz!k?'9fvrv>*VaQw3;"|Y}QT_̦KIEf6jh~m*SV6Oz𪜣 un]親zʮ%IDПn%B2-Ce(55!I*V(`%aݸjF67vؑEm* )|=bFTu=7vTtoq_ċ5!%&4:PX7TA@ @?WEdHvR9ݚ|^ӗVUnvT"l Ńq{Nڽ Q=ߦ[F9xWW6SV6O"h,xb(R,$_jc_>}!=wsZy n+9U/92-ÿx1mQ**5כF@jePxLWף%m_N8`̟`PT]OOdHcF@/M if5?lW5jHJMMhj-.{|5x^8IO=w\]0򹊖򚿳{?ђrs愈mqhvnF^i0Й3~}/xԵӯ{Oѽ.<^|MjJe+Z{C8zZxZksI6wT,hGy`Hr>2x*xpU]Oٝfr:XS)?{?~)+2iɴ4seL3W.v-=e}r0 8^oh3[f"INZOeD`XpU,LP!`;wC;0!`t X]F2@?6e *6IENDB`v_sim-3.8.0/tests/exports/color.ref.png000077700000000000000000000000001370110300500222162color-3.7.pngustar00rootroot00000000000000v_sim-3.8.0/tests/exports/dump.v_sim.py000066400000000000000000000003161370110300500201260ustar00rootroot00000000000000#/usr/bin/env python scene = v_sim.UiMainClass.getDefaultRendering().getGlScene() scene.dump(v_sim.Dump.png_getStatic(), "out.win.png", 600, 600, None, None) v_sim.UiMainClass.getCurrentPanel().quit(True) v_sim-3.8.0/tests/exports/field-3.3.png000066400000000000000000002015151370110300500175710ustar00rootroot00000000000000PNG  IHDRXX1sBITO IDATxYs$irEdb)Bj ER4QIr H+.$ə !\ @'DeJ̠j2Ap^!h<t`B'$ ˧(fOj(cg‰31ь(IP"CwR/[cg <z⛛ dk 9ESpEQT51I0A-z(I U̠11'p! 552܎u%1.HIRG.]sA!HȻ.:BKJru, UV,ja B8$O^$|gT˰|(faJJ$$ufS̚&7M.)u/ZQ69&LD|i=Z)$YRUR/eLOu7FVanZC p1#"5Y30ĪNu-.zZBF3ќC!h7z>rnUFaJJ^JUBffնPs֦Q; -AB8ј~ps%6M$U-^Qu-u-3ش :ΡB8ѨBx 9/)LuxN5 S? m ir xkN4 )a9mLUk=TeR')I]'֘F+Fa75&p13FDA!A2kTSݓN"Sf$\4 sApBB'h8346b,7u/zŞ*IU.Uk[ fp+B I|bpwԽTW."OUfP➝fS#@a`f/2ige-!zKTt%3E,:p!c0N:fFCTmp0ePRUIԽ^5{ܠmmr 7CS !0 .3 to^SUd] .)t1-IǍI؜.dS]SRV|bjmca BB8膉؟Ju?{85]}ip$!N y#NNUIzKUO/Ỹ"Z'~*GDSƍF+apL2 l$TUU]Bƙ 6 m3g#8}B'60x hԩWU-"}/#]JS pqLFwD ʗ>"߯SU*⪖.d4-ԃv!c !tT`h^P`ܳXׯS)L ~=oVm:!!"qHtW/uoBo38hO+0>X$N:YdBF!;u-jjkoܚty:0x%7h6)'3K i$̓[ NXDaLZy6@,,@aS7Cpď>ṁ'&}TA2\v@riHpf! g&6YmzƗ` ! )kGD`PK'"}r6DEp܈h P5a :"4 g;oww B ׾m:y{k}@bJar Ƹt+8 ĵ/@nDUGHCWƔeU> x}핏F<}Gb)ʄ ! a洏!Ž5{MUK,) Ga*Lexᘧ\6>'8Cą/+ cvpf>#yb׏ B1\&8>q%Yą/͑ 6ldeą/J.aDB6U%0>q o%'v@,_08Nat5ˆ {Yq~*3G _M${gg={ 2%0**w{ą/l#$칮QgoiJb1Sp@퐼z{9l(#5<%18`D\Shp9Yyhĵ@Y * RV\BB`dhpvy wwu-KWf1gHiNhqڍ  0lsxp¥驰!Dжd[s},WEEGȎ@a0"R2~ppV,-ef҉^Pȍ08Sfģ{oܺn*83U/ "" ()v@,^DW5h&'{ .Gvt ! >em(3kyn-.8K^Dw[n~4)8;DB ( TyotL /8 8h16yjZ4.-0(xjW?;7a{> xw#qfJaPhJD:QQ?aQ ] NnqXf&0duW#ҥ`6w.> x&"bpNOWKa8"" M 7-/o7I:nu'I$" 6J_~A9U.<8$C~ilUǂ!"` ѬkEGʇ/ħݿW|`B~>Y%pvM!U*bd||oOCŽo6L" F{u4Y?Fi^v,Ǵr$Q7X[?kgfKמef0z'Kutg9,?.~y+B໻ nGP8aDDɍxh-F8>Y 1-6_pM֏23QcV"%'2~.;r󧋟} HB#I@Hz">ۊFW^~G|6-8cIXm_[_|gytvGfnͤEh4&R0] IWO_X:k7.|iBi <{Z ~׈,~xū_vd̀EU˧4bBEL@ &b"){{LtefiN>! 2:_>ˋpA-f]P`$0Q 0*L@H#DBX6P4$M4T%2"Sݯ7W>d!pB! ƴy1Z`^z _ %Iu lKٌLN/))SBHR=j$i]PI&?xj"8[qʌXy?r慺&,3@a0{cҩawi.=xG8^6+!fJf!( )!fЌTLϚ(F%#!şmۋ|5kOx/Rx ! Ɣݼ=!a)"\zu%I3v 5fzg01Ov*jVB* Bh +gt3PR,oodt,ҕ;.N!ւC{9ċ䃒sY޲p]}r>f3%UEh"o坉xMd Z^ B(H(b 2Iu͟oCgcҘpO>[z#,3`L#=}NK_'rD7x\]+  W4`V2(11(!(h4T0r$ "❉b _n3 ޯT9W^./9!Jnvg %GǽR#qm Jȁ)ISJGJ 0Aiz|,MR)eV@C*f/w7I߅kqŅŅ?~BiOz (:ċˇg-:|z4#QMsTC'(-(n3*>|>z6jme NO„PmXV$tQdB_nZM͝|'FǕ>]B!庖f}y`}c=cƽ8Ht7 > (,gF§wL'~׹iauϲ1|0!#&JC;!,ޛ0fJkeZM)Syhʌ8Ї?[fnݙ!<ǤOߺTZ\?5^^vmja6EX~~ʝ Ϸ|'Mbs.'×=3^k_''e)Df =Gz ѣwr4fŝ4].#<~Oл[+vn^>]o4+OqixCIyTީt$:I%ωzd2uP-a<\ƌ TA1MT@TQ P1Q_89|$ݤF 0x9M߻_V צŅzv6}:;3SxP􅕰'H fv$)I(Xz#k잰JH+(?$uj1j& nuy @'yn3Ф;ˌۄ(}{7Sګ_̜oB#BQ =Z\_ZY\|:\yj,0 C3L{EAQi tE &O1Q ye $UfwG8bmMպi7tr=\fȶ*B%|hZHg4XRS~+oN|jOH΀eh*%`秧b 9&08`Ў>|91<^\LW//=j?Pqu..~L56C]Hj1d.<<xcإݻHc2B]IO0J]EQ7 %E TdeY:aK"RDHpTD/.j+lEfa7BȞ BY%LH5I0x0b4R/&f)Nx?QeBfW2gveg2*..̤ŅB}a6]MoNp`g7ofn7AN ]ͫb ̽.dK=;R*RQ</{'~۵k{3\ ĥѺ5ߕۖT;*|x4i**sW%F/x4Ft|H IT*@NRvz9<8(V> Ef}0(U%(2rA*iQ5BDZCl}UEiL/<~f Ud4#ީ. @Xf)!Fl9IuȺ$_/B}uy0.^ʵO]xpouڅL4+3J4#)Зג^a/cYIĚIIbW^W(j*$9`d5 ڊ$62VR3d`y_4_hUօz0)4s@(IԲU)P"J]#Isj'Q\8{QBXf%!FfO<ͥ/`}c_"-ޕ[nK7n,{Wp.m<\|e֣-#f>7v `zqO%L6SofPA O3@KNѐhG=LDJT55 a)knC pDkG ml#*}:hj4Vh@XbX5 s1*=G8הfZw/e hZ΋yjNXf!syv! w.jѽ/V|Å7\K7fgfgnu77Xf`}Dh- J›E`eheYD=zF3M(cOKQm5t!P$R%H3 %-,mhwJmeibeFS%yKd6e2sۃBO*ԧwCC_8R^* ~ٛ:/}Qߜ2s! ~/529aE|τL)lV} n=ys{vҭ+--pyvqfy~pkoA>1xOzE4%=>fǑsbg^Kw GUu.Q<9ڥaP]QKKb~nR[KBY4j*&R(4R)eF èX|ຸ1\\eB)f5*ܛiFS-횽ݽՒ'˯=wW/YZ1?8'Kw YzmoAB³,f"^/,f& J*d%Ai&Y dCAK}G[!7xgt%a&ϘP4梮B KǪQR3m X6oźXZ8W^Թհ̜BWb.3Xٮ`fL% |W|ţ_<to߻6cz^˿՟`cl ^րAD)į4sOg7*:ώo/$܊P} MMj^yT (S{8`^* $B2j[UQRi2W > ̩i ~ٟ9k-/{w7OeBϱKKˌnG1e4Hbn>I I=!eyMV@^xh/ΣͯVVvY*Mm-幢8C_e?BZZ$ dK- a4aY!$SR1[! 4I'M_Ryү~WF1h-6l x# F`07|"DPI yM@ؽd_~H~z}%||{Υj8wgOnwU\%]_3Tqk@(nPjX)&F) >QW=ǣPwxa1W-fc %>UD˦P{kǭA3}ifWm`S3bXf!8 ={n,hdXo;5kUݕ7ϒF}# q&R gnr R=>{I~EVO<{ܝ4U4ْnywoH}ka׎>aňGN Z3KQ$kucOj1pԑ)j4t(,kMK45$)5C5ehbTC2rTl8p"[fnܞ !<M*8|+rxN"_ae) f3]6JP,$.IRJr#Q!㵸?iI˛#_ʯm;zqn.M/_ze?ݽvO!鏊2ۇ|{.]/Dhoff􏾤(`0k]Z[1K D`?hRɆDt-qO&AUdE1T)/u-3KWf2s ! SzG.eCoqȖktU jN6B mQTL,4Ez(sH/ lF$f}{fWWGwm̵ s,N-_/˳:ȃ{{{n`@3!$E{BFIٛT<+;&le`7Kc֊WQQ[f TBz%jOE,A[ Y6?eUͬl?9)/1nqƓws\ 08ݮJrh{iFuS?}\P 4B9L'RA M?(jթT咊- h>{>ղ@T=sByvW7o-Upt׫Ov9'"ITE$Zƈ:Sp8VeS+cH CDjF"fDdgiEn&m5'ꇒ =!'bo~Bx ! ^Nޕڼr)A;ƍ覟yﳅ`.if&Lex$EgMcD)~3R FKcȓ>۟#PIxWw]ns !zũs+37^=כd~pxwÝǻOv]хF4JLXҀ!zJ_]װ5 =7(꽊Bo03(BFD*P<2ѣ6[j! "ĺ 1#Vơo8L~r+kZ( r~h&7]3K"Z0iYOS5) qXz2<m05|$"UA/}ziWoM-_Z]qqw[Vv!QǮ,VUbȣ_}.uW0KY.bnQ˞N TU!]&jιbD.׬-rBZr2tof^GuV8_mO;.]Bgmbzi.?7+Q ☡ۂ*}Z5wA(^6A zV|4J³oGD̐F_v&P(jE],݌ƯV\^>7<ۻ؟^^Axg˵흇[?L^t xZӲ5COzxlr0νzB9(J@5 DɞhhF&2[0 DΉ,':,]>u! 3u.ƽQktnX鼳ClcY CG$D*"H&g[78y~ݙj;\L)5ry,o+N=8x;x @j2_0< -\h6wVXju))2 ݒENTY} aBi*afy`hl=I="-Dz:DB᥼-9?;f㾀6Aӣ4s졡oYP@3hD؀Ij^LTpB3m;.HQTs֠l}>ho?j$vE3U{۫~3W/ K?Zpsݵ/l$+/toJN)6ِS&zz1@T,Z Owa a9^j /Vau:xͫ#C6u!)dH_` ko0YKLeR`6g([U=3hRt!w0[  ->OG~ۻ毪5Y[ƕN2 7[_f5U/L/_qq /^>?gOmDw k’ǃe%̪zaRl$?_#,3g8Vx=9X_!:¾э G_RTcOG̠ϗ1(YC+hT ZB턮@tN2sTwX*TMdwgKH*n޵C7—Y<0LTǻ{jϒLVBqPҥޡj2iU#PUji[#E"/| ph1SY$0x6_IUn._>迣pp4FwэXwf M_ bh 3*L@1F3XJ͒&)7gDdKXb>3JMJOؤtoo ѷkh_KLwT`pVt-XX9ߛ]lgʼnz޿>Xz@7rDaTZ25yjwQ=E&b"[ )lÅ b4e&,3g8PBFmőeCNp7,%HnkvX a`F2 b&@<'*4)f$\Fh$S.D$_z$QM 8͈"P*D><Iw˥ɡ"&,BYAՓ_03,N/Xn--][zO{Oyw+{Y "ݙ99J皨z7!UH6M">L2SZheTR瓰̜]B<'5L쵢C@D=}i@ R'ulk^[SaI#BZY&$+h) Ha|a8:<۝0:䨟Г}Tݾ+n=Dl0zx I0D_y#Usä{D- CIn#u-tT)DK$DJcdjTz}rZyFh @)' D%E E,+p[K7?tsqnigWV+{zwuӯWiIQQ1jޚ߽PS*D."Dҡ_?̝Ka|8½^r>R%<|\nQz=t[w%W3r䩨/`h7J22 V"FhpA! f"Z;d|ZYV44Mu)!qGpZ6O^dcMbd#5B$B&v^2v4<|? ɍ[K7{3t[m>|[;+;>~/:("JV^UVc6S$ݓO>8A3Jappj'>SkKGrx4Xz?uTjϚOZ-Fnni#2V)%=+f(zh=/t'EnI*]/D eq0Pb4y;ɫwFIfpl͒eNJ}3F;hO76>|+)4{pś 3333mΣ߭ 6]U U1gVHRmNع$,3g8MѫUJʇ|oXi?Fa#E^O0ֿѽE*JӬiiB (:l&jR!uB @ 23q &E䊲O/j Nd. S!`Hc]5JiHUː! ԼO,)KVzud,*n=SŰ?ݯ"\tkq\Yxog4흕WvUBs[Q]On:e,B^Gq+S|Y:JID|8TS1Y}ZvK˔z:Ԍ& Eh-E*JDE4U Ŏ 1̀HH ZDRdVDH h_Ӈѷ[UwRψ)9B11a2(Qfnum0! m>ظ} .XXhqKT}K/~wv۶5I&Y+-_2s ! ^!^\j?- UT3SCtWs3wxmI5l+F2`djl2LͲ!SRNVUfj'%P.BIK=PFNWvҊrŗ ;~WJ d,x& IDAT[M0d[E>e|+#L0K(7z\q_NUcUD*\]j5I ӽ˟.-Zxmnjҥϖ1[wiJα/ bWYh3R@FPN{}6hF3f("~hav{DF J G?ǎ}חo.{_>&?.b,@ā^je]N5a{\1Sg>;rAXyT]fWM"L1aW$).Snb 5JTe$PuQ,oq .%,~C}#G#đ%jfN'[RKتZps0\o??|ed1;{pr;gONw7뻛[x矟[~/?w?^,3?XpqaemNqK+{Gg̗^>=L^ pp`@EhU9mpGM2yfnEB5YJ7bWHhV9et{0fo1QiH"~CF(YHrSJCo1d98*۞f9}pkNzPObf}x?8xugytytt_Ư~~7?b Kdr? p9D[!O:}fggĮ[qb)'"Y&! G %S@ PY>+;K-, Yp ChXѼ% !\3 Ovco㍃=!PM Y,Iw_7zS=>:|dѓ կ_>˯&E#[ⳗlTb%nR NdD*)rsrkblGI.!Acb%DLbZ }/똷SU11nՃӎfuHBxCؽ 00μAQ Fŋ" (H %70 6@OJ+W~U3" )YP n/,JJf!v1ݍ]h&R'uW /VWVy}ISMgܭӢz85x ڲrpÛ c)S%KdBb#0>Jpqm&i銡(-@QZ޴LvpVlӦ_i CtG<SGPzr&5(.vvQtaoq5ѓuQ#?zc%e㓧_n .q04% [4(R7;pukcjv=,&oS- 8)A%ۀߎ#PU@)' zxr ^'ڑd=KX>C>taaխ)B{@Tb9Kpz9a 2vVQvᦂ"_5b+5<\x\u(M=ef .q |!7w2}2kϯNNxZ^=^F{уkRSb6!ZFTȚ]%zXB e bŬg;ƪa('5+N g-=,f"ys|b(Ɵ]n[G)OE"2HS}1ɏd֎O [fU^F+?=w(Ű|ާi[ .q ƭCa qCD|3?Ͼi‡߳qڟZ6Z0!jSUNj*B zk^ޡݫ nN)R,G[TJ>2.gRn=kp6DtwG/(EӒIb^}uG #㪵{C\eBbhŨAeU>ٚ)qR%p.!&$bֹ ^+4|d|`r󯲜oxG^Xfn,@ĵ+-P3{t[}sewMlC=̩ھgE} MJ4oS9K@! 妝`@ V91h?b!󣏝Րb&m"n+M4 lD"}ducDk@C)rA($} }?Rd5_|EW^<^<[Xfn,@ādF0›Ta%orW6o_29RǚOzb!+9E`vl\`]EIA*2)1VBv,x]@Z4/N~dbCSd|! }iS5u/!fyš1w2v >|sL.~&*4OV;-}_~݋g/[ .q ,3? ;lϒ'g7]27]:|KtukBAI3CXIj4C \zWA.萊T2p0Ě!y\JOg 1W$?&}Da.I&g6 I@6qrl#Jy#)}{GEט7wo>=m|}W;fXpkb ]a#Y7h= JǶwݝ>z0YzʢH &Dlǘ gD1/he[1+(z6}-@+FTc }" 3W |ݧ.==yP<, 8lu?gغFP͏l0,jH|p(n YD>>^ʣ'n_ge6KL֏ELK͗FpH!G u4q>7go|U+ztܓ@ȥ0 J--2Ւۏ5Ԝ*dk(C6%%z׊0s0UcMMQ7ΪC9bvi{ݧOO?9O);LtW\^~gP]i9MTYV>ӯ^=Z'M\ʇ?;"MrKc%L.!.g=tR!X-69uwjwmzPlܥqK)'cS{wC$1kᢩ{ cWJ.j { *檀HV;$G<6I×V?׋5r8mS06\}F~SRmRx@xV"%N|tzG|}6S,@hK|~᫯$4Quf򓪿@oG9h1^"Р7K9=L%K% H iƤu,jIEq[h:0 -H <]Kw5 # ݅ Є/J>q :cZ={fˢfkWb~,M|c|?8%8=x__{TK\.r=ᛘ{ð0i̡=t_}1?ͅs؜ߙ=H%A[:^xF ,٫_ƳQ_hB$1=7?s/JDuafTHEBZvjKŎu~:\:#€{/?}~OK !P֛#RRhf SeD+=xW8|K/؇x{exY!В1{5f\ <VZ-%m,gorLY|GkgRd ڌfD 9$Z}tXquuukuw;jA{W+q{uKݽf{o"<.NDʲ[,oOt6Gs[vN}Wi=eZMյ;N-FF$"m.q8ƭZٸ(D>vڹBUtY\P3ù:fM0Ph#y]"w(q;UYKlH1>PMꕈA )D[?Ҍ.H(#WHT8Z%?`va?B4yjc^u2y;<UA˾/qb%xYq:9z@$qqYn ~jZ[y}QIG?@YBW(xZ D}btTo %YI^cLQL'ie hj7R5FT p iT R6™T`ٴsw0:jmSǴs%?|p6oc,@ěCmO Y҇j=&jOrN^ vfuKfMJ.iGj+.5k UBUGTVhH!I1R~(+arSvЧ7ЛͿ~͉P8X%D1Oǧg7e]7sdTr-3pZ,m8#NժqqƗϰK[!yJFZ&}!͔Նx+R'lh?cNflUfr èT#@%C4Dcm901hsq)V~.*tH,{vdc&+ Ϟl#΅zvWڻj1Px^~qw&8%L5,\Yfñ:a0JklԧmFo´)"v-$aщsJv5s?2딏 `{wܴ͕Vӆ3/[vIAUpWx^\ .8k:V8qֱ=fS]U YdjlryD% |pL]-ekiz^}g_,`X`'iD$OX]7b,6xSDQ kn/ }% uu%`uu32j!":"`Ԑ,7-z̎4[R絅aMMjϙ-a&:UP*Y f3V*e5E QDkn4A,Gw`m`[~ &OMʌn?zoN{l8'DނsKu=ǒ#ͱns Ssѡx'8DgWov~.[eGw~Lm)qLR*vam33#xv&MjZI=9;S1vt\5d g ǩ͆ZY}Vf !f"̨;ZFڑvDڛra8> }gnч~ifzh3|$vt@/d7g!p~p ..MHKG47b61'ӽb)zbK4~;u<1u{ o@Ӟޱ)]MEՆko!f"YY8ncսֱjT]kuU ˡpbcW{Nx½g'U#sf6֧g$ l5rH>:ݣW6}X|Cz{9Z֗!FxcaKUj3F) kl/bb떝\v.Jr{l2>1o,:KLсEsS%$f/V~hI鈾&շ0B0 fI~G:Ac!`; +D렎$+EeϗV])otbLQYw}qn(XS;)O.9 .hzXk{U#oDp]+AE/U8ts@fx`-xϟJ< rX}kԦD zHTU`tV vB&t\L557iQnG,wQ>_}}q}`1tZfw߻Kސ>pqX%Ǹu]t&b1fzoK.])oOE[tRʺm~ wWax\)N+~]kKֽ>t[5[UrVwwTrG4feL8H4e % :9 KEǭ6eϳj?Ѷx< bOE ]M,0 #\pYfX`ݞ4n -eҼٚrc8 e3sCNaͩ¹_Fu22gA{R$bF7nnsxꪪp#]lrC %VGslx Qq/L^T!gݸ~a K*L IDAT ײetIn=Z߁c cSC ڕz\%7e!펅.q811XAF"Bhޒ{ NwOK5'fָ^z Ν!{ZKzp&QBYOK_LΒ2," 0O.ȗD#oY ?gs\ ~nM]mxKLh?]C {;l_[-sV]%d< $9|(8Cɿ^| @j% RGiJZ(+PlO\=FO4SJ',tUbo1Ac0ݸ d+/5AdOCyv. Ѽ&mN Fz յ>:QyrI>P* +G'|*DB(f,f Ͳ+䇯cfwÛmpcFxc%nM, ֳR\[0kʓ!>^|9BjyM7Jw$Xz2g#gIC5S)1[/0zԀJ JEc=y4Lո0C!Jc~ѕ;n.ҚFj$?2/BK~pXpÑ9uo 6v8KJ|-{O꿚 (nA:p9L%# SyZ03ww5NG92wpPGGkrw1q./yD܅Z'Y8VJ(wC0Sykq_a K@ T ˯ضoL?'CK5]4ݑI H$_jFNR5m*;&hbcJ$`̒wwU<ʯ+ vadtw%!LSUsFWWXFd}|<Oii mo!I{&$#5#QbdI`p}G8|O{Jbi+sc%ʚH Hbz?/ _xH3Fh,slHIƁuXgw9j(ߋ57CԞ"hKu"._N5"z`aFq;)6:8Qz !rB6GAXcָq ,1XȤȿiP˯ 9Am #% wAc0 r|L@9ebuVZw3Ќmkh pbzFUbU+ D0Gh)9vҴ<5mF¢Pa.Bc22&N@DwqƛTJQ `] 50ԄDZM|Uܽ!~l8\r< \ h.;Pw]q}l Dh@B8V GIWn ?>5Nj{1W`}v93ڶZ*5[g|>]}ӟmgyuWT-5 *YPwO .o ʼnjٙt婵 Py>>SJYlXzS,iroӿK`VM{pFxc%QҽJtǵ&R( ðZ U*r)? ['sV߾%Y* S#[ZJ/Kt}\} ێe]zh1[9Qۃkd!Q}BL1 BT4YD%ĸVnS8:k̫BdŒf,ZJ)PWYR)Y 7ÛJ o},@[CuF)b#g jH;񃇍 bW j;"k(4-9Ĝ׭O:Nf2Sh֛$yv<;6HĆO@\6 tRWȫ6MC@4NM۳b kZ\E`,뵭׶^ժߴba!`.Kɇ٨͔ՆXߤGX:=Yΰ /o!NؓЀng{oDZB)<5PrWShZxK r+Ih͵+RSimRdS)wJ@2BRle,`Vk[%)0|jf319w筠%H N?8\-6ZQ{~񯭬 #,jβ$BX.3a'Gϭ?{Sl ".k M aaËyP=,l8k;fyXƄ&N'eYEZJ8M[M2 x "b`F47̛̿%QDٹH VbCRժVe5WЊ;o[3|S_\zoߴw%Gxc%Q}rl"DZT`!v֤{{O ?((A<_~܊zV,1\DX90]ތhMg{j/^iʢ9J F6A7(^BM~5:WU ņ!e5jUk%Qr0~2~25ꪀP<@tP`pFxc%>)eʞ2\`97BlV툜?m0-i_CX8_ [pu|>9-sf7+c=Y)_oǩ.\+Az%#74k'#dN6>  l2jf,eX˰klʰ*d< I5|w>e' ne-6..+ͺ ޓ|fH ꍹλvyIaPX rn ϟZ&6 Љr^3ϮO -v7b\e-̵:BݏLbD oGШn+;??.eS1J/L$'ܑ!vGn;Y~Xך5J) l(Z}UO Wf}XH^~9^q+҇K܆XpwLE@rS 3W=NB#Y<ӫܴ>_~|Xii!4KNm@OtWtHx}|X;|3diIC3pkE:ŠV^^'( M zuI n'9Kzdك7!#i62 ZIzU67X " o~~tvc^FG?A #4~/=1f)E FJ`s՟vVuD$iɡ$ٯMyt{J2*Sh#i˦B};^)6bʔClؘ0tO~ZO룋 v)5S{G!K Irm{x"'#R>uȂRbfe VC'lG(qfp~cFxc%q[%aGr0Մ >d^g%E3HŰԻMrr)bN;ds7N xu|2DvSh:$pfg61NLېYAEDi`yIlȔ.B Q^UѺʨSC6%M\k8-LBCn-萫 &,6ajUetBI> Y?pKpon# !}U,HJDX?y'BAD3;+nao|?9}*>D "☢A偢ABosr t(#^A-}0EU1[ ҘP ')Y 33GтPG6t@6wcRGXb"p]J"V k/߷Jq՚f[+O7@pU?7yLyLje폅.q}hgjޓϿ܍2L4DN2|g;Z;Vll|u{ @?,Y@Ҽ.ji4VH"yU%9ccz`v'EuGA` lD/0W̏ƒNh7XӍ hM(pH*F;8ݼ aamv_M}ð l{fVo}҇7c!FS.qm1LA>/=n4Pŵ]; SU?tRtUGIa[l`)`6.E/n .0E) 3J ''ǧggYGHB8|25EO tems*ZGiTkuշVmWKAdZyD{Z;3ef+k w ja@~N8/Ͼz% ;Mߏ޼=ƒ#7vGNxqNrc1&S`CT:W $6Y^g3\#-|5pB3RŽ7t:/ REk- a{`ֳVJ4:wY=?&.zES c0VGpVxe8  W+ox*XSu> (.G˘8stk{/KY{oco}i ]I+5N?hX̄Z"Ij mV''69M"1=?/jV^,aܵUpzvvvvzcm[c KRbSbj>*xasSu-~)wսrJ6eSTIQU+*XGGf͚f__͡3p@j+?ߋco,@A}ϾxфDV 0a+w<3ᴁ.AMɤ4t4ɤ )v[%M =w86/"s&i¸AOvΝ?Cdǿ8)]A堚R&/꾕W*WVĐ{v3q-V.a{ZY+=xaeu<:fmGGѲj'Lqa{ݷc^nkq/߽oKK\$cjFkhsܙ (Vu4ZR#b Ɩn%9, gx8\dahI @+n\vg|Nt矜ݧ)(wfkXX#'Wkw I4]cE(#7O \]}㸽4`K,o,@ě"2@?(D%FpGҕ`2B"dß5n7Zi@?􁺫z^6mvM$Y{B[)Jw;"㻆INOSmJZg6G矱&TbHY_4erՆ~ϊ7U"`;$K^Vy;kͯ56ko>>>Qn8^ֺNjbFxc)XB_XjVVNO`DS55:ar(PZhL2Xo֒Vv\+߭{7TgZ8vL%S{rk|MiKM\;l9!hB)pN t:jqTbI\n(!rw3k1BYSqyrA\`ڢwu YPGk~uKdcaK)}Zg/^Z/^]fVZ OH+hQ{M)N9 IDAT"3imzaut>90bŐY+ً DYUD>S"D <;9kuۯM]:9kv9F<4fi.xZ2(GƘVf1J,֞/&PEFFr]n6j ۬fowC> )z!w8ُ \baK)!$їaJ8k_}|W=J KQQ}o?T^YL6XhFEU #>We1ckQ%3K^– ~<iD%ceh?#ح5{U{{p./  <~ S)0*N52ѳNb-B#mXop}CÏ>O}ܫ&&F[.oټъ&?oޥ?S'~Q\BdGAYNjMj0IQF&2rkք[WosyY_A vbl1񦛶hXE;lǀy5IND z;!< ? WjKj UN.s8E2M/.+61 ff^ ~has;p$bFxxˏC2./_%ךHuD> *p2 eЦaFM $N,$h4+elVǫchb37gj!TlQhZ{?"ziAuLjA k^fфqCIDCvfua%kޝUUkCZ6Cm'u³~tH] m/u%NJn ZopA1ž:zsJ޸s' .O~q@><ՖS\1 o J7T8cƬLY.Zu<'foRV++au|bXc[-0 ,/wȊ<%kvʁ5s }m{`o434;]J[UÌFq&6k~ZqgK]lj&3!}?ވp/81AO$it7w߾іe?vwʝ&Ro5bSTf!&IݴhM[[>^\C_l, ggÜMpB >IkÇ3>_@T 'v&Or`:_e"Ң;lt8Zj&7gv@-nBۭ.^c](Wm^';k{qy$h #I6{r{Y! "F LW1ow}4Y`lh0V7R4 Ԇ Ŭ GGx8:0`G4ӄ&3ohjpd*SXg6h jG/j[-G~kϞ/r9%GlÛrSEի<QX;f^*9LESuy[~ \\o6Z I¸ &nқ#O"FěBY%F-`,G*iW/>+Hg\0G¿Dzrz\ fѥʜM1jc@G+:DqXo2@= ZLST+}kgfU2ÖJ.+{ub^|$Fd|$pA\[%< UwYݽ02&9^EUF^j :h83ekais,o<ؘCGz?^L&^k(iCIS\yxi86f'>6{ .BibE\jhc摊)p|ֻ%A.YH:/S:Tw=D,Erth4=[mNO\5OR/4 0qЌQj ßm4%HWF)E|4TG5J]5mw]FrLCbױ.^؎܎Yh3i,u%Ͻ9V՛ R$Q'ZЫW{٫=|mYdZ"E6E$APA @ 7TU1{{oDdUzˎǪ̬ȈD8_/dA:B{AϿruhu/ᓥ. Dc?+)DTg¼8 #>~L\\wmRN;eLhtjp&"CdMf&6B_&8zیsXdvjmsEҊYI=Ʉ4ߔ cH ;:H i7]jS]E}E$iSlq3 AW*&@8_$aXԇңz*uU$;e8a *gzW@TH9|f :ܣ|.W D (ɌfoY60φ#w-v^Ҳ  Ѥe\'kͷaj;a79yGl%$ hF! Ld1R!t$4uEMzH@4iZau4Lӵrnsncm4zu0ƂSia)sj"DX>iJ,͇ efuu'H1+vEo p %0+i@.p;Wy##{\ckyYnX˴Nca6}~3{1~_-"mªv2wKyka)K!N240%66XcDjfa<mdĴ@@D:SLA:@s[(e02 Q FLHOUġJA,*)(d(A d a5K&=6HYDfQY9811¾Sm*6"^QԮ>`$E(@O=`<喈\Su`у;:)dsp^~gS\"c9WR16hB<ޣ)J5Fi3/bROv2}a ^oʿH}ib( U 6RbPJԥ6b/KžS+ 'sՏ´b$hw;S9BwpxhPV;L!)ÄĝxDUa_{_;WSG?H'^U'<'Ua6 M&t/=n/łkm >T{_y_z_UuvUx4DI6l1;94DJ^3J&Ēaoʈɍ;َ S1AfbJHMPV)j0*_%54$8 ,0m2`qE_,i!.IV[{f+e$3p5 ۳Nn gXij8s+ WUUûwY E?H';)\p͌"\9_Ve\T*(#I?H\iٽa'@֘Tfʪ*ji`yRX; $f v2D>eB;Z&e,pc467nIC…=h:1j0>PO%C߄*aPSpb5A$*&= ;*+xG=ʲTa׼σ]]:_:W8Wtjp艰aqwHعlUY-nw&Ëx︮y{x/"PYz޻v˺^uQbq3e(16IFdL41NACݑ4%.KJOW$3yz\iOiV/5܈3@lh 0P<8ϥ'Gm?©!H)Tٳ8 6#a]:$"»ҹһJ OpsoQ z"qmB@UE<(ʲZV TE{qjC./i]+1kR #0ep&klkXcT rS@ lu@\GDpce_MK+i!y TFRZ,_ Rћ;tNd6]v00jgBύ=uyscx:RPe֯X*]@?wq:0;Ufvdџ}f3lT$ט+.'6DWnJc% -+/oϙ ui]Md2U0@DX`cbHXT3RQa%,B/Ued.P%_(6tai};/ѡG@"@II`%;l@Iw!䫫 H0%Q%F',H &2Ll$)$@A 0d1ح !*5D=`Cd D1乓iKc[K𨠏{YWCk(`% pVDqW]ƕN~X R b㼡(!qa44#VUA$jmI~P'R(-|ujEŶپ*؇ZkӰXb') ) eq`a4Q2D{M E #Wug/섃w&d؉pP0G K?rdJ;1R55A_#<*艰NȲw>ZɌz_:"Ҙ ;EAjJalfL| k,f09`B I 6͈0X^@&gNb݌RgБǓƍ;m8Y,ܶ!` U DJ&Nz-x ЧgγJ¬19ʇkFi^5aG}jQ# ƙ0z}ae2n9=1iCvDy]"ɤ/x&! [׉[opHI DFEAPo@6LȌ"<*#~ra˜̐5& #)U\Eٹb,rQV+"r7"R]z$MYsw:wPEI y25h)~y~{NhCtE`i䝩!^`n&n܅ ;%h$TѸ &a(4a1$B5(3;򢡳=w!AN`Qxi>W kG=8=_Myxoo C=(p#.j^UUռ*gHaU[:wwd{+%9#1ȲIJyԒ.&^괹hz0X[K5ȕ-7V;/ڼMzN+N@bdFr!1Y,=GJSe"I3ŚFf{/΅4)-yh-Qzl4:Y߼~VW``YF X(rI\"<:艰^TaEg/N''νq@*='ysO75mY~+TBsA,.xEJjbSpHRD*JZBS1`єVؒ: )LX!T B17TJclhK!.VÌ 'c/DI޲qXCDP KcDɇQ H1AmEzdK(Hq)[KF`u@} g,z_3; ~'kZ}'Wzy:=Ad2ucx̎dWW v.ĆƧ ;$d,"QZh_Y0*PDk~ӻrrbGN!ĝF;Wnb(fbQF 31άЧF{% CqH%JX,9W;W&l@g^Gd=KxkV'I=ǣf<]쇗{볉 IDAT^Ue5Z>mb 2'M.{(^<1!_#]QM/EM5%v_WBŲDm0ig/j=Y„ % `ɰ11B,DSB`BV!1%#*왭x~"!nS Bճ8xa0@>0#{ 4bc2Ue^+c*g"^{5pk^k0& 4z4vųpp'_>u?@Th4 {p/KfL]W_ȼ`VY "`t*.Q4m/~Zkk &zޤm舸 jkdӻjYT%LW $ԐahbRaTU5,Ҧ$DBXflĐ(>ny(p_}Yv.9B艰]ہWDY[;_Tظ&1ZLeXÅثP~o>0;GF*{g1XV}䆓goL6qʭ`"9ia D'U(H!iXt+rh%H֝SVv1Ƴ?=ξBnWd( E< %"RaT!Véw#DR5JӻؗEvC(J5O8VsN??"Cw;>wϽ9]|mm }UE Wfgq*C焝seUbVe] ׇzN Oxmz*φY6WEdԽ{cHjZlUbs0v5L,[hˏKtWl>B*Xcj\Ҟ EH8)vRqNѼ[],* d^ gܕ ]@_#wM%֔gxa*5B/&7IuI Oc7n}'6R«Mkz̸_P4h 3Kޮpfe*Ô$ɬfE;ŕ6\iinq R*)vUP j&ɛ~5d)FZH<5+ߨ!@W5Q3 S1|jTMr*/BD[bUiOoXى!$lT  YRQqTUiQZ}Δv=F_#ʱU8B'x*.|GОQ[EY[r\w^/*̫0]`-\t%5&B V %?F;bm7jiR)ˀ6*T%4W ODs2ͼJ!ME=K}C=WeYEYUE]/CnW$.}#!ٵtVLZajwuQٹz18ZK^ƫ7_;{-a^{*kf&ѡc=o%̝`gQYnFZVtp!ckrYm@ОowR) PєՉH@D$z:JpE!1Ҹ j ibR¾ˠ%5cxC*ks(( +Du[5Vd?{S@g||]}-;j4B,aG =8$jm6ȳHė]W9O>'?:^f2~ѐ~}MC!gTyQ׋I xa_8 u?D!'Ɏxzx˜d]`Mډڨ1 sh@`!3 ka]jqEӉOM$ƻY}'4)XLJ(+{a/PVL!SuUXb^^~Fs0e5_,b\nD_#}ϭZ7]~ ۩?;pbK5BDFUkWnYVlVfu]ΕkkȬL4]<._[LF:⍩uPc HS0w tPPCC':[YQ?%H"ԘYmt{V4ާ\vW\̲a?OgvΕ"sO<2hoq0dG'_QUϾ ?|Iǣ+|O_|0w}yxWnhȺje̔*'-pu]$X26c揄LOJ0 o)t4ʒDWcO"]e>'-TV-s 08d(\ʷvҤ%ދ; 9脪 "lf< pH_L~4fl鄽F (,?GDB8ⲣPUj^fU.z`2Lmzφ?R30rUy)6΁ƕy 3׵+rӳ䆝EJUlnlgi๯=dH {"?F}ˎSg9{iT= O]r~?kQ,6.lxP68 ) ZN`}oXNA)VGx﫺^Vլ[8W>V+bVbqeYD}lFU? \_۸1Am{=+xn'. UhYVQXUjH!du(fgZCTų̞CKЍ(GDһ*)JNi^YHO8.sy  9 RA@DAJՐ( 0@{{{UƖvzUY6a6 ^˟a="艰ǡ,aD_9ck"Kd@C@m60ƪsEYڲ`/~}mtzr0 z..."<艰ǡ 6!.\(jfg̾K|~aZO7 w Uekx4)s9.eMve|"jqח.rǣx_c0-zYv]zW3_m;`"%0cct8)41ZhcVxh'L͎glN&Nִih?ǖTUcCw=W[!@ZW|窪e9+YQ̊%iA?O8 0kenr0B8 xyEd:{ԗKYXx IDAThkreow}\Fp\=mOgDyѐ$KƳ0bT'86"QqΕA8)<` dxgE f)36ή_wϘl:qx@y*w"D(O2dĮn0 U5[[F[Q* i8rMԦXQ7&҇W33(8(tTA}%c2@7nyvo_=ghr"{|aG}D0WN+؃ 0EUe]ۓ+}S^V(ΟOqīg;U*e]"܆_ï4Y 4dˈH m참CRٹ(YQnvQnR?kfG&.`*/MiTEJyѤ8h) ݋.Ddd:NYKm(nL0.C?α}X0]ԗ>x~lГ.ϼhaG}DP1SِTf0)_R}3{CUXYU뢮9r[y]Wݼk /FyNiI"]AgI񓵹'^<'OM1 [T]UHbZPI})L%`%4ΤO4S qmTLW5NXJc-PYU|}:U+b Im~>yuh#_Z[; A3b?::A2z jv/?t x_l^rk-SAgsd@/u6d2NڙPI@*. 8{ɳIQԬz|c 14s5X iT NT2l }sX&neQ'S4|2 KW,[q lhmnݺB!Aoyg+g,* nâJ\h70뺨"Hpd_hm"kG =8" ]IfLiL 8)^G5 }]󬤢d|dTlWPHK0P੆ -{M~xOe n5yy&v iR(Őڡ|<=EYjf }$C<7:&(az&ј&XIJFuY(Dv0!WU>AS*+SzIՀ_Kcm|A7kVȡ'*;E]slvz4ZϲLOv6/=b/fu!:lC>(`ňQU"u^Xؐ hA`hNGrIa0́!Rja-,9Kv]XCpF#+?o aa_#lf'f|ʞ9qU?٫ k^5zaCYoWF1xW;_) 5{U "Vo <,Vj+:pt`L&ΟŇ˓6o>&kw>~?#!!Aޓ1&~#k&ia9U" cDÈB]NOH-W^PVӏgqtrr|aR#X0 ܌'y~xW9B`k[#TyfspnQU͢}U]O5\ﺓbXn:nWnU5dkWsg[[31⟾|gs8S{ܴD޽_u2!i<>(r!Ej2@M4ud,̞<{.aMF>D$kY zkklg|0[y/>+#{ ׼F"ZT[rs(k|™Us~$(,eUQl֥Kޚ3|᷿""i}/}74"21< ;$8m7EɽP=\H}4`!11 Iio'24T5Ǐ;r{8aG=8k0ȗU^fbk4y眝߫?Z7VYjJwpX\YlfQl쭷o[',ҳ~r[mZhA$A X% 2 ;7Mw{b.:v􌙞fՍXl!1bv`YP\>ɥN9̓Bʪ|˪TݞLǾEQn% ɕR0A@7bYaMk5<Cʓj؋wsnK'w._gRҲmlozfnN<` dYSEyX^V#$n-ln!n*  dleل$g1c`ixS8S_0<[6f֯gQ$;C#ړ:k7FJ8Y G& SB \7`Mk{M&EeYҌҸ9k5XmS+yN`R; ],X4LeӉ^YZ(%˓5kd}'v_\Ĭn 9F歇;0L{6 0,$cY?DJ<<'`eL ;槷wKxRf(v`A4pNc[R9A`JJlݿV DǾoیSghCW#=>եW6굦q l$|S}0,+=ER%hCJ l8\$FoLA(۶- @ 0+qt,m 1׼wO^iXIS(5(Ydv?vYxvm^cz|@LX9C|׭OIPR2ȥR !LpVaЗk%0hiU +6Ζm=z*: \К,FkZè7ND'O7va{w|?-t"r)}9z9ڲB [Ye˪I-4 D#Q{4!LB2J ສ'eڶeZ5 7@ ʙr-D]*%)MaEV}r\P!B fEzkpoMP$ cxyp}Sf) ”WK dڰ}0֎IXjB׼wy~)x.8!iڦ锧gҗ2$`8jہT°zO< |2Fk%5!4ʶ4 D#QfypWРdi)yYsӍ>ݥkk+?Yt'vn;_R,N3wݺF`IA(]a^nx?|%R:i@9#,ٔl h0 H{u/|食yo6nG'"s3 ժOFFh$@)=r{w=ӴRIđ_P>|KS.MDkkw.6& e.i0L˲\ôy68q+{ソ|3%VzXFa5Q/^![sZVa,<Lèj A9i:pqV<0XկWM6 20l9ǹ`cTJZȠbŨ|[jmZiWlqD،pJaQI#;o-yz%R^m۪ܛa_r rdi*e/1H  횦cDJ.e)0fHi2ƽ>' R2!mSñ?>YqDkTJk-nzs7URV>xuyd[enUoOS(a3)AF33YxܛTYEH^ hE'Ĩ:^C)XNiYڱm[J#]OkǸG@Q$Ec@lYFڿp0VlF'*yB PZ*- &K3dYxwb DljZ1veGg]_opl2XZQQDkϳ?c IQYwI?nw?߫:8aXO޼q7 iQ$E(i"̮!ځaY4qun Pn"nrZqA">ig a&!D+"&on7t3a ZQr~/ 6g=){h'aKUnhTuХ)u'a/G br-myBpΩaj-Vw3@۶KED 3MeYn:^DN) BJ 8#rv{Oѣ7*Vߎ?fŏ|4pN)(88˔eDZw>o>"%gҚҌEXY&TaRݎ&{;1 DQDy>A (Z]I^ow>>Y>y{OLˮxwb()H(.Y-Mf 󂱌Ҍ $R@$gRB*!/o ?+Z]V睗=73BJj{W`x}b\dq2 ֶ홖M 3:hu%`}yޏ(^N$Y4nO!Շ/`[T'osXD8pFvvA8qD6H7+Mc@()K ômE( DZ2ńLya+`܊i Rk0 8pŲ2 V0hsW$x w})9JCsN<]E;]]YпZwҘb3Avw54盭cJS¾GbԸqN3\E;zK$xkڗ_՘_ p279λPٳ?H o$Qt&ӴCi<7?~?aڦae^uB㌙KaaT>޳?-J#g5+\?wzrkܓk4~rP)껯zG!Z+RR)2 ]+g!-RqbTåQA_V = B;P*D4y2kcKsg"%DQ6$/M|!U4m Ӏʩ7'n$W9ݵlF80ѸSC$ahRsMԛ^@,IL7Csօ C4- '?~Qд(R%f8ӄ7Z~xdtaQR#׳Š]Ah{Vk,QHS."Xyxl9DJ v+ı]0ҔfBXE>E.# Ah&g/N5-ܣ 4ӤPy&bm%R.,4 1+u57[cT \!d/BL>?ܞy-ow\7,LF@ ̢0WV~} t31Ηb9^ў+NW΀ij kN:c6`Pd /r H7./Yw@Y"`( ? ^;֪fӰbכn9;N5 BґR{EW[AhWnX=JY“ õ sx ֫rðu~?^3֊L))%}yh>f8bG! /Fcu+^}#jh(rQP+vvZݭ]L)h~gC~6ȃ~?^0Lӱ,_Y1gR0e;W>+ZGr$X8cgS  ~7ws|ŠVXqŠCiʒE'@Y}{4퀳\*RAK{S PE.<$aũԜ8kGOT\1^;vR4!Op^yIQ$&amWNj2Ջ!:рF cUtÊs  #)#6",ܩcIQ$J`rNl{NKQpai˜d)8՚Vm߷êVcU)UԧqDxVJmday ebpE7MuVNV/G8B=V$fNY+4Mzӛ_ u,8D !6 o<7aC ʲF^XEax䒃i?aG))dM=)uԧQxU3El?Hbik(Hw9yaZ+]Y{fS *ĵ ªS8fT.0&ӘZ8Lֳ4"E#z'CB0DJX.de% lF807Jnjݭ]RE]ˣejD \ J% _ʭ\/0:gL˨zӫ]3m7t+NCx+P Ar!، D`Byպ1S C{ht+zf2\ ;I=?twje'm%C)#u^' k j 7a^:V^'wh@/vZf!.n+s~]$!A+'y1wqĆQiW\:ft;h  BO>}فihyz=T4a,49 ݆*KyXqj /o_$ B)rZ慕S/8aŁzb?\;-r|Qٺ`b3C,Mx'ch_korŏbЧk+Y@jvD5?o3CY]˝B׳ [sY KR`).v:҄ \r=kۓGGx`"4sh!VΈ{bXqZ N>~EBL۔5S'_kZxjta"4҄?2j \К 7( zR X]ZsAm! D^;z NXuWEw5+v[mEh4m_;#4 DbLr&zk2M!f4Я ҘU=ml@c3©AAo(jYF-gYAuJVF;?׻Ov䎛>7_'!Bh$,L g͍:tV![; BBu}"89m.(+؜yikχg|E!FQOQy²^Ry:1koYF{>hz<;ZYmF1E)L"OO%P:KaUn5ZbLNlKF3])}ĬYhy͹<ߚ[HcNӵW[Ja D'!JVα_ :4#ݢZsTA:\>>YKG+WNZs>z̋I2;s*9qE5٭ǟǃs!4C$`Ff}k~1,:Eg5iQ)YX_mL6We D"ک[Ͷxl՚[]Y^dis޽B C!4\'S'c(wi⺶jLYͺS‘ m o%R B墨eͶtjm=Q;zJV}]0Bh[3Blպ[mA}Ωs|S 0B}>왿_率&ʵ=_ޡ !v\;36l< v-x+>s:C;뢀AB# B?(=|O!^]kǧ:QV 0B!4n_X[&y&B=tu't~ D!Wnx?|@ D!'^B~?%`"k/,@] BBvf<~`"O?{WsbRw00BML5pl9IDATgNr9jܸMD BBئAȓaĕW{Rɿ!Ќsmv-L#j?RQMf"!VA!4mЛoW ox(+Vi1'[N !B Rulc.X Zknne^) D!F)-٦Ѫ hV rA6rR8F!^:\nQZpb+TQJWiNgA!t ݮͪ׮kk4J .9'E'xp!Ёqܦ2~G/c^%? 1B4PBha"i!f!BABha"i!f!BABha"i!f!BABha"i!f!BABha"i!f!BABha"i!f!BABha"i!f!BABha"i!f!BABha"i!f!BABha"i!f!BABha"i!f!BABha"i!f!BABha"i!f!B c|'7IENDB`v_sim-3.8.0/tests/exports/field-3.4.png000066400000000000000000002007101370110300500175660ustar00rootroot00000000000000PNG  IHDRXXfsBIT|d IDATx$uwsܪ֮ n !p6CJ#A3Z_BđD`Lb@u*koGgfxegoᑕ~ B!a!BV ,B!"B ,B!"B ,B!"B ,B!"B ,B!"B ,B!"B ,B!"B ,B!"B ,B!"B ,B!"B ,B!"B ,B!"B ,B!"B ,B!"B ,B!"B ,B!"B ,B!"B ,B!"B ,B!"B ,B!"B ,B!"B ,B!"B ,B!"B ,B!"B ,B!"B ,B!"B ,B!"B ,B!"B ,B!"B ,B!"B ,B!"B ,B!"B ,B!"B ,B!"B ,B!"B ,B!"B ,B!"B ,B!"B ,B!"B ,B!"B ,B!"B ,B!"B ,B!"B ,B!"B ,B!"B ,B!"B ,B!"B ,B!"B ,B!"BOy( Py!2 ,AQ@2UT^B ,$$QP(9.B!gYzDjkS/Dwdˊ"^ջ]NNvB9e(H/UDPpȄF@qX.#BN ^$B&k,腖w (`n*.B! CE%cn kXE WQH 7@\^|9]B&BEzLk(D^lL!hx冄U! ,:}񢪰u[th AaL]2(Eht!M,=JKESDՔfʏ98KE! YzI"2.SPf4^ cj,/ZXf$,?Od>H2+.Rԗt!WP`GU!mz*`k]EaEvy!V`HַZuBAEzj2a=vez1/. .[{!|"`Tv@ 0sUJ[$_@j*lW]+lMB ,x3FS77՝.jyG1ʳ]hʌ:6滼^OB9M(HOhzOQ4*Z8UetLZv}X]r-[HBI"@Xꚉs wdQAYAῗ"@0`Yy.[y.B , ՁHu2?vc]eC }1dvEeCa!䍇3)o``Z`?Ut*]7 , T54}3r80.5W.! q$aa 9s=1 " 0c$/D+4^=qtH>BEz̺'vbk}÷XnWYۅ^e./BeGHV 4zY^&*Ak&[V#Ã:MM9(HoHYaەdZ2eLᝮvIbYNeF]-X7sާBșst蝪W/Ҳ|"k_ܮ톩~Ya^Ӂ ˒!PW.+ ĸῗc۵~KXbQ\qާCș@Ez1EEH}zp*y3"B]I]B)}pa~Y w)+e"o>=>BN ,+R &AttX:]H*CEz%BNCHo0@zp:],.Ez~j .GU kEHH_H%B7N`[ְ58"] [{"dx@ٝXWQ,T!s1%Bxؗ 3EV ,?$|BcC8A`U߫P \8#"վ;sX,?mZ;!OY{]OX{+콮PWxCak("d~ ;tH"#f`(tj=G^OSw(;7][h#Bis=@7v'=`j< ;u6 #Q^ak>ޡHV|%dٙMC㇯ ":-BNޡHﰵK*_C|uaw[x"h$:X,?#9XEzw倣 Yv|J+7oS`~BEzG DHkA^:WG 9mx"D!d9N=޾C ,KjV cZX= k`؝ ޝH/U!L];<~s>Bw'KتDŽ=Fy0ӗaޝH/ap !`j7v'w'KlJtYZNpyx%;^9xw"$ #EҙzWm`cawxw"$fثէvf ,Krv7sygD+ |.x_ZI/9:*+B"bC8ݧ8<,q&v6Yn`^2onů't->ys'Y~(H/P",2\zBEȩe>pE &KBI/k`P%73OE!'kUOAxstrCEzIdB+gDtPt'2:O~aw0Nzl`iYI>ǯpsd7%dֺlg567K\g;G:XTZ%†b9lh'#_KODtBr)A\$5V֤EANxpq (& z!dEzk)+ "dpюO]9l?z s~BP`˄͋Gs?')zq0NIoڠÚElF}qˍjE2qZ,x[[\{{OO :XDclVCs.[#_X=b}.YB`b+?] tsJYxh Y\Ɖ,:]dP_ŧ?}qEAvB *Mᴚο¤Uf˰N9gN+G x=Xd"Zc|BGNZE<B+"䬐 |s}@E Io+ =)~/k~|/Wfoye\qȺ")O`olag?d9Ezᡟ.gcc(!Wt?J⏻{:]40J{=DqY:X`6g(Nhe95اhͱ.rRN3+|+7ps14v'/5۞B/9V:ÓyZ]LCϪD4e[w.9?HzK`Ƚ GN.W9^ZCY"İ+te/vD`^SU ձ:Z8]BDv',klg>ʁCx~_!>]\djњo7U.u~ ugU]|KW7t'"=/S?<ʁI%w֪^tbk=\]|ҧK+p/|s9IlA_˸ٟy"~66?teWmڍM [◮x_}=O>S^9Qs(/]ǽ~c p X t1}µm-ln 5;g;x?} b1n\pwnkVkg{КҪ<냕ð;9O(J^ߪ% -`q%ȏ犥Rk3;5t)<\E3,V]pIXz `؝XCK7jo紷l޹p^HyV\v̝LV}FZpr-A"&/Z'p&mٮgi{7EWp|/vZgFϻ9eA%$ -);9(Hi2_yo?} q*bV+21՗֩Wѵ,%Bawr>P`7nּmsZE\75-ϵϊ;)VawrP`^7nVoXA?Sq<l:ls79]B, ;9{(HK|ۣChK{,CC7u$ϕZELs=z99.U; 8Oѵl 䬡"f\}o㞜ÂdH{ܼpKW6RkVx?Zd8V+pYsVk2XYBEVogݮb\wǯÏ?}XZs+5شZjo?e2ˇͲO_0N ,kP":^lmԙ.*x[7+sņ\OWZjVQtfiBEzMB49=nn~')~~]iy)@}#l]"2#ԡ"o$h=?Аuq|֝s}hx ƱVZnƉw.%W9~o1NN ,2%b!O3vm[߄Sˆ`(FNȈƠFQ4{"84)`ĥ+yBj1-x|FNZ tƣ-܀uWZ9}2T",Wjv| y"Aly{wwv' =u0(rX'q0Mzv)r>?ixqU&G%cp 1@T`; SڍV/~i|GGBkJlHkb؝Xd9Yiop?&DsYƯAh A!&+cį 3pb1  ,l #q0b??ŵ![\;{xs\f̜VP]v~+|- ,r*P`S9lnfG;ez"۝\h; %tR—TpIi89@ BEP@0bP PUF{eAj(n_A`Ob~el+e&ϵb 6DW q "'.KP YY֧?}/^W_.@ WgrcPX녖̐2Z׽Ba'*D.~k-ߟ IpA\8h* P#(@A(AgVz߿"kqwbqy*}ls>֔C%8+ݿp ?[ ,-XdlOVz~iv35v[<|*j^ %deF[< x%p˜( 2gPmʌP5P(xh- !||/\y] L+B`u,ѕoݹG^vp9wլO$b|'GG>F$%+@.C,`eU@ ƌX -5% g|N|H^|៤:Gwָ~c Wo^)?A./\Jv o9/&|^6y8Z,Gt/3p%{yY(H9<:*fn;i}4T>$C٫EjB񱌥.$[LV!%!gzfw6 EQ9/Μ}blʏy( 'la|/5*r>zdѣMiqZ+2zh?(s.KٝY,Xa.GFqݩլil 8_{k5U8EhU!pAw58t 5EI ©N\p ο[gpF@ /M|~Ғb~iK>ϥ!ujsl#E UawrP`3D87B9=G?~̽iJZaWjbP(PKAc(4i\h0J{oP_uO<|p˥&`g{/9]/vКA`؝X e~G+_{m\Gq܅& Mx<@)s6.MPDc`0([^XrJTQ:"qp!e\r01:gE~(vgg^|?×#J"\4& -I~cgwIWP`LLff`i4%oHYFkNpT}qkߞ: )s@-qދ`4KލB p 5` ?j1rAx$*.|}C|ό|Ә}dp7x-YYy_x& >6v']@EzOl4s*-N(4s1i214s>:;T1O{S8hrdV .Ġ0(VWpΡ6!Q Π0 c5ᚩS|}0b>1τZg/ISZ#ǟy+@|`؝t =J%nʃj6'FHQ=I (<{bEo0HWԋ/k`K4<"xq!ƑQ\im)DD}q0ΏJgwS.?Of.3xjYv犮Ǭ<=cT: aT} 3L8`\){م[՚h6݇x\\_$kZ~ Z#?=aw%Xd LôW ա"8|$ќ"JNaE`TƻW"1~ARAiLRRE[Aofz5Jc ~$_Bȋ J4"e =B>TD" âB8֤4Lsݺs1yOs8tָ v']AEzOJVvIFN-\+\r;;|3tAlٸh6DjJsN:7764Uq^(jx:vM iVJ;b(zCQ_9?xw j >ΐ7aNkNWyr^*~\Ute7o_H"?#eye)K/+(H*@1;pM,F~5}Ly? RM=&s,}R+.4"u=J0!:(9X88\a3*ڼՃsAP jʎjBT{j!F Lh eHC 7/4S} %ݶ3\UD.999 ."EК]ZY:v^lݍut1wyGeu38(0ҤN +5 „6eL_"V\e#,o]qp? pH$!&*ShҢH  \C"xPahdj. "`=w4v0UsHє]7peY՚њ䗧˃xw_x S?!Si1vuy'+7v'džUeQ A bWEFkŴl#'ܳcwp&;K:^j:M+M`eg/1P!ݲ g44cp&Y(L9`4;- @i P:,UDeX#qa4ՅʷRB+OС<τ<yN#%c~_;96Xd%*MAO"Z󕍎oDϸ&+9Gtu\fW뎈{o8g!kr P4 Ԇ:1PpDU;WeP(\>Z%aPC-JƟQS 5+am>7ji.bBktW75\]ϽuKWEsVϞcg{"0<*G^֝ cAEL& Y7B?ffKsFK?1"ndf |sOwЦAA RXJE=1] {l]( J?Hb/-ӰY֙eWjhlN**'qӗ%|ox55ϼy.깅vu"XP`U=tV{nK|5n7;\]V cY'D::9]r:? k2=PBPEE/xE*<´: 6$ eH_@NKd-KGk^t5y.<}#幆[E̓fa!$<"@EVȗt9 NqaF0/[]BɄE}{5ͻƋ/~(BoU3Mc{_~ğgP*p~.r0 H$e©bZM `S$݁=<ĿݺӺ^m3_ y'uFWY={O*b4Z^=GylLK7q Z;͚#I1U@v#@F !I\#>WQ|@ Jy=* rmޟ;nYǖ8.wlu8Q|N,&"fDl?|uNњR0E\es͓a؝ ,U]Մ b%&) _kwg3]y: ;9X>2b9h#TIt^5WEAm)U˅"q.#D|O.@%7 cx.>e4B "WO~ Uk(Y>y Xd%Bk0#/$cPۅ ',`yrZ%r=|[3\8Ek[a?BEG^`mĆov ds}SzrbLeƻXA(/hkEI1!e˥Y훞\hr(PkF`T`CV[?_|̼ng&4~/N2Up hZE\Fs=뼴efL(JPU htg%5D>5a֍5bh%F^}K6vzw*sQ8kऀ3q}͊uZ۔*"I` 8B[qgG"6uKl#wL]{,lW<>8w࿸}T_KA:yun]UD֟?tMs=ONaawX䍣-%YPh!wf秆_G3dr3B gE,/ʯ9CP.͡]e2+Kke UJٵ>G%%L8}` L('qfz?˪eQ%guxe)v*bF֝^.t\"P`0Mc7ƒ[*_Bya6w:i]]C2fǎ^lg2M5:U8cP)Shk+?g",VRDС}Õn[2쒃+O9ińLWk0}Кazn?6IJeZ Up h\2Nur_P *kkDc ;mel ԟaIHEqi4ui8_r,E (²r}sRdJik.kė0BH 7jXåTI Ow ]֏)[6sdM˷ݭy*"svɼP`!cpfp5~zSoӷNp3|&&i0 (TӱD~Ԋ+ϭH1/ɢ՘䨩106˲E^2aT33c?oLC #Gηy ֎HdKl,\׮o}87JN ,2h7tHm1F7J[h;Mv?uQ#^6öd5q7ƌɪc6sAq94s-ZPA ~ `n,j8T+~ ً0S .%iV. {^[y7Iv%HȱWbET"0݋|79|K|#ⵌ#NWAzU߫ZҕuosgF\ۡstr#ZOfӬooSZIF`[c3q\6dFu?X3p)*kQY:^QZX`k W[AU,jgaָylhxjUa9\U;Zfa'  $u,Dp]Guy+UƟppb7~>P`:#.\BM, Gh}Sw$~h1:qٸSH&4UPQe*PCU^`qEW ,am:/hrNaԡlKd9XͲݩU/lY:r6e(h6>?c\oRhM^e\&9'pqJ$d,,ℶ\GJ de8aבmf]跌l$SU6<;/R "Ej|h@__# ,J  n⻵ds"6g'P5n2׸Y IDAT5uϢV)r%!3ǕZ3|ڿBA؃Y4 tZ8SrmҞ2:;Y>o #S3m:-%ZN }_o\ٌNdT1\*k:""Ԩ;аR櫊~/`%Z/S z KR1$QD䷍4/Φ|NCj0K^YK%MD)j8f}p 7{rB!'UY wGΡ>g厎`Cت;:D)[ԇՇ][9&B6˥bY04U}9M1oجq49qy{rZsX!܎vq\Nq+%B2 ,2Đ0*,׸ Yo>O`/qDS`d*Seol|7̡S S4rdLx1tuuuUjuu[UQ>(ŕ_?a(6=жi&cѕ uD%QP^޷q<TN":Ɗϥk5t.V[l-qUZ>|x8__9fBEVnF¹V#/bЍ~B|^ᝑgX$rYp*&+9c2f`#}G^L뒈KT"(*gQr`e(ltEV{؃KȪUa9-uM.+ 7>yH. xqeDPNGD2zcw -Oy!."W,2Xde8gsQd9rehk2XX[v~Z8.$(_rAlEv.ڽX-vJQ]'.L( Vt2bP5wҞPhn{<5Gh8%5O"$@EV^DwRt|]եL/6%i" hֱFs?j˭:z17~U|ayXomO#czm3r[bk"a:"5uN[Y0Ak |8-N[kUQPesBh8^Ӭ\VܥM i0~DT"4 ?sZMnxy,2l4JV*59 11AL9*J5iNsI`^Q?G4N-T|8OْHс@y_ʖ4]4G iܩ{wmv 0 ȋtA6UU|?,#lRSTj%(^Lh (`@At&4NMP#ј!SB!01(T?kSBatx/C$IVαUg;pW3Xd>`!7vؾgTc8T'bKh_hmGew뷚[ ݛT6Y([3,u͗{Eo}dp@>6BipXoFK!U<C/Zaɹj9iM0] 母DXA 8[HY-_N4-'@sÅ9?q`ˣ,uMS"E&CEVLH`8]ou垃IBj&{}&,2& {m%b٩ul ԯZK7߾3rlx(XO7]՛X^H5*RM٫bwaت!fb k ǎe_KeAIIndbUWU=\az!_Rӏl:jo{X`'!,2 ,2ɞMILj.[`R.le[D qŴe3j,ǹ95ID[7n Zר5GqJIFf([o+B?rժ^dYN5 z.,R+z.ly-;ZNƽ3:T^dy7 (5bPUAi|s|u5|2:.u0eZL ѮcQ B*o< sZa}2]|PZÏHtK.I8?T؁01vvIgCFHQ|X*lDV.nh$BiҖˈ.6x|m˄ 1.ķR%˄,Aa ehLZ kk0s,hqjVCs蝹W>U(2NfAEV%<{ƈfd!ԡp52<7B<ёOsݻPkW#Vx$:֍IS&r,?z_8f ܏_odqr5]e%A'+^4rEC^e>H Urܖ81N[B |> Vf>uvR b}u`(&~(h}Z.Kt)Cy-,(j(;eS:l ]Dr(@8#)? iH%iJʷmݤw[(TuXCo}dN^f4wy2}τWlPۦ<\tq&s^,oP|ԟsWQZs-B3$/ 7m庲>'Pӛ$x H`S-w[< R(#-d3 bxSUݛy>d[U@:7;yQZMPb=WgLtY_9d/>vyiWލk`uٚ\7^_Q #'i|CpyC]nT{wN2ބL)%4h|O!2Bl9g)ʝNN  ȩyJSs=Xs]f5׍2)YX# ŭ$8f.Y(eHQqFZk*0ZQKo}.5 s4(MYƗyT VGF Z L@JcggkѬtqy 7w=M%]D+x_nJœUDeRYxCc̸z+Ć>S9ZJ0ѧ湊d#C1dT((b ģK+t]<[g>Zvh Q5L#P5UXfZr uJ7A1*?!v>R !L|YTd" @?H]VG'.hcڑ sn+gpF]e"la\dWpռwv4w7X3q,D!0AK&+N-}ʃ XEŀ-:aD4oxrUj}_35kXsܚj$j$ű'K̓a.7^kzƲ-i{mMBkoc,D7ʞM'G'1]'<>1$eFN;36B=LQdfH>0JvM"L"H8(f k""y;̂;YC#U檆\b(Ue>rX.Ka@\ ]/yܘكZg{=. djZ9<>)@f MhLjYfzf4e{lP1% XU_OǐR氫\Km#ULua(0e# A! D Ar '=ٶ1N(g.:.^=g5jE8ekXsݨj*;zvW#D,˗a<g-.<"/ AQ-S @z#]#تqWlGGe_Z6lt`ec`Jh΃&Ue|kY G YZ :e0 m#tKvbU{baDsaU_F:~.ݼ ՊX)Fe`X߳؝y9o ^zzс`uٚ\7Zzv@U .YxQ(T?@ku} (FGbgP?apRgRjvd5psgYq sJsJdyae`-C(#KOUiG*4{` el7nQ6H@㍢у UWGi-DL@biň#Bd-\ŢʆcΤGNH ky8q[/}B+``u\7ZrIA>o5FeQ2 dDvVa t|GB4TR3n.Y1 /JDDnhն/`!FLn-^b {e@J1C}S9HIom!OmyFN_@˥CT(]"( \y?9^Qkp\ ,Ŏc04;5^eD83Xs=f5׍Q B㹺6$Z63 'j((7#½o$CzYXQ.jև歟$#obqxg@ }4 ' 1" 0uw f7f6ЕY#Y~ uXƒ,5rU9L$I;A ]Du\.NWYpFOp2';^|sN<}yiЪ`\7\-ccȃ 0=F2Y'^Gn$T) cȢCP٨f䠭s M'f~[fqxXc]o ʲmMc8mg!9O}], /o8b&6,ɇX>AXB"r슜&^0?ތ1{SHPj.Mn6r}c^+ޡK`X,Ux_y^+f 2⬧@K5mgzjXs"~o"2vC#]O H}XX1o4R @[7p{YydH"BPG䖾w6Pц(@dC#l34zLxjf+01>jilGXۣ?@IUv *5}Ccjvg \M`Wі8]D:LV\hT-S0m`{Βr *}BTjsͥ^ cg\`ujDhnXh%}r "7Wm\сBj0L`p#{= q{{S=`cDMgkl A9#Qtz0Wme*w2[\C46KYu :5>>_SeX`HN˫Þ+sI3yph25nT!CD_ޑ4׳iS ^.s37 eF}| >yڂD].z[ypcM*a&T# t,GlT@[fz{wpU6P*ͳݩ8lKaLγaA-#d1C8AA9X(؀S,"340ju!!Nd>, :`B_@]>:l)C˃_jy\W5Nd  P_$@oeAӹ7;iB1A 0$,hx @JN#B1hQ) DHcw^C, 2XVI 8X+``HS7CAʂhw$/aO?;H5ve\3eSPHUC}7| }w4=o: IDATȂDc "z],B"ٮQ@bAD R@\]Nn0C"Kiu9g}TyTZ JjįqU`R z5+xN2WB!m9נHD{ѵK?g>A0unTVθhDAU ՃC`$kcO)l. fk]X/%B30T@#0۷And(B8#H/r${}7Qimyiܬ?Ot%qvK԰`eIBK= Ϳ%ƄPSc5{DKRYQ]]b,"u4-Rr}>F fx>VB%YfR3Ɣ }G/Yo ȌEVdܾu`Xm-A Ou:/5*De5:ڰYFZƖ 2Z_Y7ЬeD#-*:/'ܵkP[rM:$vePU9O^$3)2ɰY%ݤD;S{Ĩ7z@cHY} -@X,,!qY<N/3E>*kRg\\k9arџbz/Ԉ9CZ6+0F7\t@AK2N$/a X$f\`W;M\"JY 6c]K#ȷ+Tvf`ח~Ꙗ";-:0gl*{ /Hkun[?z< NNPjhdZNcRwQA;f_˚DgQٱ1s䴉(4 >{ |~TFra]++k%I_D@ c@GC9eASLX$ӵKB5{JkSSoXӞ{%i e dr8 3( G! @ ]F!4I}?W Վ+[dRcd1aɃpxr[ pT:xQI A͛ʢVY UêZddOIT 5YIo%K9CRVОULuE!\|ܙ׫HvK, 1Rhh`kE8UjXsݨjH >x G|vڞ wG˯zgj񘡚 ~}O'kc2Mc6[aaqxh>*ujx7FL[ԈOV3}UqyQπwt| ''ur49/4Yw8!L3`ˣ^,V-AdR6֣J}̤#fm C&Xe!A,Jk`y@O6I/.`$cݒʚvz5"Km^\/КRkSޒ%la{q䞠"C>+9sW&:CHK_<|ܫ+tv2OH)p0#v}"{1 )Ĉz@ `/oue"ic_7N d!ReFdo0Y2]aE|$sPVLmlUlWT.@(Xf{&Q dX}kft$jrM}R!ˈ:=h=do N0 2rH)uc@UO`m^s.?y0{Z \7C6fm&Tw@TfBL3pד%œn_EDvc# ' y(ժ ]D[ ԑ%2L[X* Sf5:mnB nqkPʘJBMܞ["!Ђj-V68nmcLK72ZM` rOx{$ է A:m' (QDE,8طrlՋu95/VzXvإrnr eNȜҀ4 9e}ryrLE~zlVgk qU,Wo~/`dNm3]pYE: ̵wcj_T?vۖnSo k4cԐPYjKBeq-bhMjD Cl-z<`<$HC'Sc*'Z'u/UQns{ is T枿> 5\/jkW; &s9 C߫~]&GǒMY867}eZlX=B.B %b`NVdȇUYy:lʤ;UQ!< 2cIsl4D`-b2){9Q*}$EDd ,^e$5 9{1NcQK]*sGA+yeMDeóǐa .gntv1uÜ0kr{~L0yp6uٚMsݸʃx`Π!I5w[6?JBf5, ;%1 դB DUgsh12&gR9ZA%F*KPȦ>%uʦa)) U2]onl6dA D>J$ o6M}q'H>AVl*Y}0PY}@w_{IS.$.Qՙ<8G4uٚ\7Jń% ¬j*\?p,dco|d ]sMlagd!D,t˥6q)wI0,#FM_si>!X.8% gMb] Ȓ(M7Kf5̒='y_}<6*Wd{cT9$M&]h2HwX/A >V**}!eDLJ*׌v lGʮ[t1{~=ye zLa/ՇE^}g,{U5 5KsxfNHp?CߟT+ X*ܑG*#7Q=Y2a b[XG9zF%GCD\,C]^%@_7D"b$T0vY*+TQҍFqŠY: ͥG:΍F~؂:M>R6P4I(# Z[b}w~VG:2jvBkqud-,W]/]C A3*JJ:m M&D8@VOA@d L2B1B`q^AP64Bd~+n3BK8g|"Ã"]l{nRE;΢-V֣2^nzgO;R2f]{oDVbe#:RȈ 01ɉ=ޜin pAA, o!l72jDZ}Xgku師G:kfj \7NGBQv D9,V{Y"%z4~m ]t$`Uq82Z`4"&Yh@]lV;8u5 QiFMs jDQ/Ýp()YHU,Kvռ*a7nwͣ(4|GKB٨{O@n}fczff ~@6z_#jhUx|%Qk`uêzƥ_ocZABrf⑅̛kS )Z!!r1B 'H:5mA~ K@ fdf !ʃNڪ7g]Gp@7M<]Z^yYɬKqdz IX)d $`9lA!38E 2@U>$H(h6[b Y,X.APGcאЉTJ9qѺrzQJomzΜsͥ5n\ fr62K|+`W:4B JtBwtÓVUz+[s)NVӶ,tEbl#>&`qpX3qE"j>kJX10<}\1&+I et>z葐z%euuX-* ]zZu!@~r$}a )Ldr3v* HO,Q LLx q-Xv:zX.tbv[+;k0m1`z˧X-\"v /D|.i5Ksݘ:}0H9Yzx *Fr`^vAp6ԏƱ0 i2/@kDZ!z^<:␂7FS7RXDBhQ=@Qu;X֝*\.)~9 |ohG165xN ShSY@M(I"jp`R!Ȗ1){$5xԤAew|Lm])7v l*4$%hф~VN I "1g.,Wm@6=Xs]f5׍OKdž5Y[بƏmTPՂ%8S(}Ӑ'@=.5h}[A `u.5S͊(2"Ёw+BYwDI n,ږN.֙ !F7v3ZiyIh;hNiRkG}SMT@ެ8vI ^<(\Ҙ-d6`H@:p.j4Z/ʒu }C XL}igHNHI5=^X'@;6cfu]uc@ v_F ou#E&LReBQ Ǒ dUTu IDATkU.y2)6e`1;}˯H*ZmGߟ9=M̭GTkOf\7ȒXaС*mDl6X]~Dk4*fNV_G,@ , fb6&$ ¤Ќŭװy#hYYrb92 0BF Κ0Mj*n W"Gä֪ՂY8@ |bE2s;*Ybh ix` pSE,x֙cS2m5Z1 q @:%5s bD@lh r () :ZOi lۯzB']Ƀ}`u#kHdu+A%6s|sKKg@jVNHi@|uzJ=Xl1pX0&+-)6'n .\3H|ivY/ƀм,eBGL7| õ!Tϕ-siuխ# /"Z#* d킁Tla\!bhϜRyFNccpo&٘Bc >=8ŢŷϬϿZ1=R4^K_O:爆R35ͬv? `%Xz0XtI-k':eGBCq\@,`>癍K aa^m*~ x "*ATOJ+g7hGb ̑ܰl9U3Tz)6rlh@cJga")oxˆ6R`^нjhwض̶r@Uʘenq&bFB/!a&§OH 枅>`ͽ0}'܃_x& v'?c{/J#N \7 ˒S?~upu3w FYpwdsC愈a)ww^{MF*ID }oO]2hwfd g+QsaT >a4B6W:>)idfsA\̍\ALYfˬu4 ,߳$-H[c{,ڼWCBJ 9);I[bsJI@'G3X=yAWs\שFVJT"7mwW?s3wG.cFg,,= 'Ug,ȟ aF6X=w;G? 0XA2VB ~ #E'X#?^fo`F# 2uzT 塦6O_XЩcLV ܗ&J1B`r+bh2VmhS,A L` mFhQV3vm85mE=[AYPˈœCB ":;~S..5u\7H¦h}Ղb$yNȇxQ1YØ`kOK`~3nMĠM+&Ucn[; #h}ݯѵ<}[4T@jgcD$Cn_Y֦fpL:(ᨣFRdFM~{zV$gpj!7g%?뀟g. Eك5ujXsJ4-X:jq4lz7`iuկУz Pr_|!vGU TGneb# )06oDUȍLYO@XXrQdUu4R4zwFOϾ ,=iƷѪ ˈ@_lyY͖!D`"q046F&l$z䤀 iЈ[Csb6.Oh +XTn/ kikY;az ȧϟZ%wkf6j s*ۓnwcz o| |NU`4`!vktN0i"gJ@"P[Dy_ޙKu&Z1_ɧ euvUnLSvBdenYF8fq`"w,)I&"yN<)iE$6Is)w.zqjfNObq:tq8(`޻:Κ5 h0F'antg1BH5gy\=Yn_,ND?O:R/=2|"jR ?+'FXY@bq~xZ@XZi1X LreP- @4x\Z_:>Eq{:Gcf0]P.(#%u=c4P"}VCY'P,(dP ",u9w)#D!ZG"p1NJda!w0C?1O?1?Xpjf\שF4Yo 0al`})'8?j #RkC_T/=x!DkC%L43 %dg&nQ ,Ge&>Pri^r0zy|l0 jӖ#=>i4thS޳¤CA9ekm2_6  2U6IPyHڧ2%cY2ˆ !!`[99#׷q%~W)jp5":5nd\.s"TQҾK,Hi CC36SydQchi˅^|z nw& @i\Xm r*V_v=bz5@HjΌ_QKu5L4Z`gUҵH&f79. œީŲg&K_B2R&5jCAAGHN;)3r6ѣɿzGenƒS3FVJ  ݯw?cٔ-F\k?G_WNxͷ7j@cYP5i2\tUv'hZMz۸W4c)bт^ˈ‚[d5l oǫ>(8u6 ,nOLէvhyA *#%*q/UY 1Z )gpΖ܎u DJCi6OE;䔴NN3rҞoTXm CMwO~oz-Pu(ňlS3TI:T`iW09h~}owN[?xg$Vz [yj]dV@1 BҞ]o2S'.{@˅c&jX 5)`C~K{eK3($%`;O|AUb`2.NHDG@Al:rJש`- 2j-#àZS7>IJ=?8ao~Vgk 溑σW?Md@.|smR[}zDd ǣ[pwdZq#ݽ41-@(n.'Ht53YlC& #Tsآ*بrq|3jμs/K}DƏArU"H+ϳrDڰ<3u{CR:hZ#{ 56L8!)mҞ~ o0 0H9彋.Ugk 溑F9X\1TҎ@ M ik7-[WO>ē_!Oo!l|ODZ}R: %__ry1VXo\j>jP΋#]ղfM@jTC1pzPG?jT?uoI\-[(3Z2z+.X?ʶH2;gP$J10[._摓sӐJaE~08x2o0 .qr4-p~ؠߞ|YO>u5nho_د턜zl 2/1Yl#@qճh@+ nNqzvS>={L>UkF[e, dtС#萒-%k)謀'oGJg8m m} ۞Vfΐ"q<ۤ W?9/R=/,QsH,6mORru'߃:4o`qpfudT*[ p-4T:܅[Լ`i:- J^݆#)!DYy=R)R@ ,Y02Z4/K"23"Ȍ9GXvΘFO[rS#~0{. 3yph5nd=:QMƙt`~k%̐mt'zS$޺ijCs RŲ 1L</d+|J@'(+KװWH*kdrP?@\_?f!f08 KD0 jvXK_}urW/"ڭy\׭Y"FVܿ񏾥Mso1Ξ)NO?Dw~~ Ro8qB~vH{57{@2y}7?#ҢT !"vGUq#L @37R@qXc5flSz{{O4%{gA :[˥jjzoG*Pذvda\F݌Yf0Ewc?k"Fū53Xsܺ/>"Jl}|0i}z5lzVc~U}aFZȜ1 G@ZPLG}/>?]l>l΋bHZizRJjyxS8LǪ]TlN>vhs՘Ū7Жc0lV Ă2ԣ=9Lb= 5ad@N6] pX^z~˩},@<5{n \7\? N/?( 6[mƽ_ꫀ7珴8=}^, %[1_ٷA!$QEdoX$*aMn5LŒ#BjebudI;hTY[z Kl/,֩v/j,41WhEpʐu+,ox,f.]eOV+!szqkXs͵R}o}tq oňŢWO4+oq p{߳p~k'3'ܹ(bbpj(k_ L D]$?_={-R Ȣ:, llux\֌,]8l59X-YF22IF e*3h88g3! 85-rJ`.GbV35uk纱.OW ncvk_ٷ\P wS<|,k @1ggk4@A6bt^!-aŘsi2 W p^¹faT95@4Mv|ԟASK|IPd4 (q &Q6m}x9Q mf}QstTXK@0e`JLHA@,xj^7`801A@ p`D<s@~12?,`5{n \7< +~ Eup_>7f<<@=A[\;= LV z!s7X˻x[dm5ԟaϰϭ7]Ɛ|C2LW9%fI;`F쎰XruK^ Yk骝y7qw\dN %ݥCiLNImخx7cdAkߐ=rYcD@VgS"

    s5StCͭք^37 S@EX6~NjE >Xg5;Yݽf6ܭ YaKz дgNyXۜ,J$ ZA0[v>Ֆ8q;:h]O>p)7OЭ޵ѝ [OhEߟ!?~3g2ncj0,b5b !R%w|]"3KdD- Edf{ׂATJS8Z?CuUvu#/O a|wK<09X{\Q ӥw'n*?\t寽x*,עpLºC>prDy9簰eڥ,JK6b#ѱb_2~^, wMe ` D*IrZ**񥇖(W!gZፕgY:&I$Iy=ݟڶId=qVn~>~ɏ-2P^DŽ8Y[h$9TPx]1^{( ݕenDq|ZYF7U@qw?ZӘUU-PꯄK!2{r< Z.j{6(yզ 0h|rLn?Zal<_G^Ñ{T_ ]{784; {k+}p;ki'F$ɀ8Y?irUƻnƻ_W, s,C`l}|#ۛt9Mx(dSM)F&Z~,,MHgKx<P%*8rejlĕ$.ص#+t[5Q{cFlѬ&˔BU6=IXTpS J-=[r=OSƣ$sժBu<\ \}ŖgV7?SΎD+;&qmgF+p;'`5ر(E槿& ;;]!lIsr󦶧ﺅ[6Nhm 4'vqوUKGǤ,:y^'fU֞=;o|AE)J(+XAa]ڼP*,2'c.*MU]D 6<^Zx^ oSZٓqd2V.]8L=q0F0ŎB'`畏)cvJ/,,Zc\{[YMʴ*Ge}͏=L6`Ǣ" QYv+.yK}WmDe5_*{#Ah<gh+BOUkgYR$3 F2dJZNךG~n/.N.sscU"$>+ST XT\#e3 {sAGiV߮WpeV{UsClxDkszVyZQK .u\IiU @U TkG+ܾ4"c-!mn5X `5رʾ9 ?(D;5U`aa~;3W35rXK)Ooٺb2%FAhCaPTgy(5ZӓNٹ}RLQ0A |(UUP;;w).&'m&W)T_6RzƊ'&E))M*WT\[Be,BDxVڶ}M!/u=-rQJjie6<HNNACX2*genߔs7&/g7QoDL%OI8Ȳl[oDG (Ze<^c43_`ɲ_[?hiYqa[ c_z3 :w^qe G(*A'<)2ɲL)J dي@ ^P-BQFKL jnWwRieԫj O 7wSVq\U*tV\ݭ{QUǖ%Yw\D˦H!H1hp0`1q栩`5`B/=UiY|NS{;Sd_`&5"%YJ|B)$"#xLaIa3 ' hJá% 3[ XZyLEG8W=3v桩`5;kyQِ2#Hjhm[_pu]V~jXp݅e!=Zk.{3צ^ ZTG .MJ gFUR!ZyL[{׶m0:~eESV>u ; EqvCB3V^WR* .#yAsdPxsիRu}EO:v9tիD\A!J^i Hk:ÀLt!h!@q_k_g+XŚ? C7h!okY]ƺSo ^~GW9x_F`;h*X v,|[Q*%׭{t%qD\o7Eǃ/|3Nk1ʶeH|z얯ZuLLnOnl]}rWjlL H!q<"n.?&'ϳ4i:FHug_9~8Y߅>7VQPE|+Z{fRU9Uo0@-BU0)g1UE ZZ2-qa!jkM* ISjN٥`ر ;ڏ];samx(484;Zo7^~tF.S3Bb,a0|{m!]3b:Cia3}XU[kSW\eH$RL${kVlF.3*OWY<9Qjv^ga_M^&j?$e%ɚ c2C]6Q?M0Njcm`yUXT-A{H&N nʾf %-{m!X v6o[ooҙ A_ȸ1Ǣޞ1MS8>yN:RUNVլmK2a' 3rpe_և!2q )Sdpg03[[}v|~$Zanq뺻68U#J0TBrTw e+gFjh־lOޑge(xQCg@IKF`WM#jPO)ne1yb(% {} VѲ</3 i68 4;Ji|=ԋTX)e+KJ(!D!4!> gIӈ m4$}G<B!]5K `7B(ቜʣ>9š{kLН$ɐxq8Ze0x~9.qC{јRAɔ.5/m:->. HSpjjZ|h*GiEZֈLXY3eV9Jf$ID4hUB3w6j6'`5..珼)~?>R0/˅4ZE]IG@~TEMrFkg=\u2E6Ub/dI׶v'CkÜXCyZgۿږ敖tdۼZm̾*U ]<MWYXG=OғO)8UF`{h*X v. (i,/RM#M8Euַ~ Hnj+]qo=h妺Hʤ? <;V̪O<Oxũ+o7g'%*pکBܭly̿&z6ᦗdJ 입ݛ=Wq ٢/\psdF'X9cm։]7A!@k:{r.?y)Z.G@{,o3A3A`h*X v46;x#y y LF1p[|R? zϽS` c?h!YhMD3drY\m%C71<|L!hÆ*VU<$ݲjU,V :S#\+CZ(c|;5Yr%S^Z۸AO?[yaǵ%m }ve-;(&48Y4;`R^t"?5rU* hʬ^IfN/EV/6>pV: ՙ_UΪ&0-E0cc/;x\\Ƽ/{RL9IGlNgjUi번,1&{~Ūx= !̻=( AzzjRS@QULVޗ]K͟ll0U}ߵ-!^X>n- k!fHfEQ蘀Ͼe Z箕&cutqo&$ V Y3lG"Wo8N35|뱯b6*Cc RYR/S ܶ°KwڻkxN`Eg3 {i]VUAW~W?VWVyi$]g?[eWEhS*U=&'+{`om|?|1X{K]Ɛ)B 1F+I_E%J]vDYqz+ArY*J?³y%#PO AEbg}mh<0Hc g@ZGΧȗ~i/=8bP9Zn&hcjpztoAYan|$ S>=#noN>@་gˎ2+ػpLZe1dM]{QkŸM& (jyAnhBx 7`*ctȷ,/O LΧ#_<;k/Z}R9Y[4Rd5~<X4,mvo2JT~K@eω;{6IkCʪmJ׽ K 1~e ZUuaSym;' kMբjɶZ-^o4_`r"bokYa ,.w8܈npv̬6h0%j7>-i.R~)$IkI<NW9=֓/GdYb A !'r _?s؇vb>z #_~1Vˑ'^&ZƔ>[JAHFG1(U kWjabW-h#qƀֺCǒkUkI3a<>htg93WL6.a މLnƉ{D`BY/%,e=)F7+q<}ۗ^EhrРɲ$ IjGz߲Ѧct;a.+ C3;;q_Z c{8ki 7 gNU`c:Սkղ]exWp-#(j,Z-4F#&?d jRU0]f[K"c ge笮>J\ '@I1N'6N>KhƔU@l(MA%rk誔sݴ{bD}>wfxH H!q(Z.| m |?tU(@.5`/]k,/ghhחx>1J9q?#*V棞mq$KADꅘx*k/T BPL:z-\hKǩ+UZ+jP]]Ty x<@RߏZwOq3ILe]"15+EC!X v6Ak |+mvlJ"UJEa4 iC:Rdr}iYVdUJ?Bu÷Wo/gHQ"ϝnk?³(@+ [-"wdesh®@UQ)ɾWntj  b#Yxq/eei6T ) fW)*RdY0ΘN't:Ѹ7a)XT`9yV,"G (ք}lNNUxx̵,"1VW0b'K3sՔJd" x{YG__ ].opMYt³Q(|KruZh]3,α-bULn,D{ۮux4mUXZt+p>XFi:gmQ9H#!$g`vZaټpQ9,+K3-'YB\R @;=Oؘ'Z/:~2I2$S78PsD8 4eYLq,4. `568/ Dp˃iZbD8Rj+sALg}Wkpbzae`Ll~qu^{l[5~RN(I1u]PdV$v\pfzEvJLhmA:%$Wf!:/q|=mŽ4;K8Ey{|ßqy)4r ''>s;)`hjąm0FwCxs[i`*×yC°K"[€ Zu\N7%\[rNG_̾z쾈tKtKgsY6hDCsû:ٚ5>ʹDʜ4ȳGx[;fvkʔtP-Uy}H$6`}-p[|*Kϫ}ho?3gqrL6);4 7_xBR\Λ*MH·o1Yxtœ jԟ]3`{\m..]v[xG&Je 1(3`6 6;,/hʈ>Jmrol0tZ|9~քxQE ?Y^>:yZKxr$xYp64Ǯ쵬rZg1˄41Z N <crvA&M[I8`yOL@"l*X N ja5?x *.'r Aʄ$ʻHQMmmbG⹀@ke0i^K3=w%3v$#$ ZӯIT9LI %3Tkg[o?9kEya cZUJ?=Vc 4U`58y48 vQj <ɲcr 3{Xy` g08dsd婙+5Cht:^uuv(O><-xGCH L +>X ͭfC?ޏ 7irmE |Vbp"]I2"c@^୿.V[tht~Yv\K% B!=~|e2T"/Ov{0]&8r5ي7"h E`C;QucpѾԉ@ ãCNl'$in'i~t8'u)3<'- i2(:މ;w7xc:W9Ji Y:EkO<ִV қYkykESj1cO'Wmh ժ ƣVVT i2*/I2"$iBS׮2Q:`Ч?Xg}}ת0_hj%ɲ1Yc|&zqYˆ@"$Jh. Wc|֯ l0-4;ik*Xg -2Yn.OsU1VC <\p^*q8G,/ {\:9Z9]_HtH .QMoMOS8 ?+mj-"5tBm<5-Tx,3 Kkبsr!eFW?~x罥R8x|h~d]ϿqZ v%lVo/I2$qF V9rY6 d~-4nT&B`Zh*X vX :P7ЮrU3YGD7#cmIA:K"࢛f7}v;3k4cW{?k:jTNPI_ '1<,%FQu QaL@{OXhɲ48}Lh*X `50`( TfQ4t#ĆM;Vܝ))PNv6:sɶz!~@}kCJҒޛ@kr)!WXR'dYDI1JQZZfkI0T"u?>}4BSj㡵' D>Y1ȵ#{ۧVeczd`BF}FVJwOI8PD)%2A)ka$AifL6ǭK6MH+MIݿ!  3&}Ml`hǒsw"`Ӏ'>mv]--b|fիY:ǫ\H3FnucU:FxG.5aVZMм4xI8/i}F rebcs}wT IDAT{JkbdH X__g}mՕÚNeww,mQN,k?熷]:5^ k6 F%L?ON,ڗ\"^k("s?x?AFkIebѺ@-$̶qJ |MF<1HRa 왢{Qɺ]Gx.zvեf4T$`5>Xg7J }C*<4ӽhcmoӘ8#d@1:'fk)0k;v3_`0| >ÞәĒ)|cO,17w+i~5YDh<L j,*X :ɔg8-`d]Ԛb}d@Y]]!IgC>N%\Nu𻏸@)I3U\u\25ڭy@`A]4Zk0³Z2w6)Ib hHG}y>=TLMKRZME!y(\&!TAa<<gzSnhOY7փFӧtoӄ$c<Ӛ(q'Gk:k6DC$ s_gDA SF߲cHC ڧ{ۃTri FJM땃L6&v_ ^Vu7`fh_re;YOLj=ۜ |@rth[g8$#,!nv.=`y<ݛhT`B.n \i@kjBv/l !ipMÿZ+@-C4bߍo~?%;O' |~Wu }{GfFr ~5\+e-9zsb),5O ' op q<ڤ!YY}#G>cy?Z^vM{x׋9@oY`5x KOd'ơgGv'`9].x+Å/.az) Yq:3 b$Kzhz'~@)m5%wOu4hmh ]{7 V\_W~*[hћ tzs!͡a4HsqjgJ®J _{6PUN<Z!M3J4?ZںAҮ -VS;nM6 `5x#e5ss!s-`iW]]XsFô|L3K$}6˳\=Cx{g V2f\^Cy@-$rww_hτ`5 `5hPV c8N|BVn=pEzxgMkEHU6nVY$#O&ZJ)Mo{s!/^Mn<L jE&4'ޜ%[ -–oۉVx+3x3dA3־GͥLT%ygoT`2||Eizq(j{ĭ47͇ZS7ָ76 Ny2VbVbLa0 BN7`qsXXl…6O7^ܾx?vZ7*\}KF1ڑ6 Y$9IOu}?/8r,Xd񹻧A#+J1E p` = _@ro8| ,||E@`Үj43ȧC=HP${Z"~.F5IP?ju[wJu|RlNT74uay6V.h'KgÉHaD;qK:i3.k(iӹ򅜪u[W?yF(<Ț]ޑpr_2R&@}D㵅(ҟXl6UGd2r9FK iLz_NRݲlC%TerJ92JډQZ3.S?h_RF?mW6tivqf #i^s9E-HډCIR.YJBVv?h0#<}C)Nk2ǡfdi&3Q>ם\N"m,`˦ӹ~:U( E+/ΫW$*bX\oi>Ϯf3Bu|\n=CEPa8{JJ B|Ϧk&k $)TvM9l;)tpt&&խWO.B֎Ux3ͥ in0= L7)#Eժ`!m, Uk0)'˭岪5l`?h4hh'' %):z l?#TQ42e9Pߗi f32Gfs"t2Gɰ|pdyvp 4Dŋ/LF$$d(| 2LU{rhRB:X[:?KrAkʭ*r* *A(j44m˓.?&Ul0)9WG X4R&QEm*n9pFHGO2rJR*r*4Ex^'p|EZ\ = wnհHse4N4u#M≯?߻Aܑ&pCM՝dI;bL;1yvᢺ5D[f1Є~GJRA>Fg,ڃh@X-'$ٖUJ fNJՒ,FKodfd!ŏUYUoXpK *<ܪUY*9͋vp녷/U KNjRa]bր@Q8U'9vbaZNЋ4_>YHz6[ܱ,Y%)˪VL]3i',Ujفox7B)ǿQz/4Ng IQ:t:SMV;̜ʮZVɽ;pVTBBmj 3XX+©gcϒ[IuR-vJB-Wx^7X\UZ,u0"e$o&4[a)@^rY݂j2,3jjR&(gyΙϵ: 7DxevGW?A @4X}ٗ]/rTɫwsk;N׿Q>mB5[Ef, ,O[Kku{5UvM):*x\^/PsZ?SXxIk#O\Vzܴ\I6j%UGuխT%)9Y+͕U *ܦe /:y匬Ղ, VLKE'TjIU8˫|x@~͇Co*W,]SՖ2u `ƣƣɪSvM՛UKSnZO6ˇT~X/7̷H{Ij+;nkiN$̩\1UYmfN^QE;q%խM!+|`_zm_ߩѺ!, éӱO/ډfqu2\1U$Xә~r:Wy#4)z ép*ʩn&խrŔiTkت5ճ~2孩BlϠʴk>M~di#`ixnWw1wcZI; upX2ym 6w/CVg2y?뜏/ʭX^/` +6% Ovblw+jbÊxn_U޶^?2KXmW' sFVnTT #}G{EգD~?M,ޱZVadϳ BpkLn;i'ܪTR^N)eIRI[Wi'.C:rnZVnVb;օZ:~2%յ-2. Ga, 9=K}~MZSº`z}WȪH*!nՔij:(IFH^0zrpLDN)d^Kf.,xiK B7UuĴ U$dC{Nw[궃W0RdZLxf.,xKa8XPs/n9dRM[q< tv2 o*[hUohrFV9>l4V*ʭ5lULPYTY\=u;;,ڰ^V E5:jCN/R rݽJRrO'Pl ū|n(5ϭf`!e,ؠ8PTYխUت,UjWU>[__4Dr5ZE/|.Y4:W RF-w/ZUfWTf0ڿS[^nv8;)T[/ X<M/?M߬+XpM,+V0 ڳĊdjډwe25}΋bF(D*t2\Sa_'CڕZRȲ 5ZE5Zɰ|ViYk0rATonZJ"`XyOUULN',Y!밤Ò2Hg'#ۻ{}6aI՚\29mJ"`NN:9JrauQufT.T.wuDm_%=yty], n hBDUT}Yݲ 5j-ډ~N<;wÇgc)#܂ #{$؁ ͻ+7ҳmRTojeن,{N̨ m' nb; T٪-^̧Yi=v•D/cP'Ovb\PQf\6UY֓d^7PؽkmJ,"ܤ$:ATFVպZꢝ+h'z@Ekuվ՝!ͺ^Xt~:^Uv,PfuPRw 0ʧ 9Oߕa,P\X˂`Ek>|к/ [7E~cE;ZKkJnZ;OpikNVvHݦZM$`^%ITk$$gN<9NoX>g"]SZ4Jk>-`NFY,6Tkjj-淞m'&[cuہ^V_ TvM)Ie/ElU:zg?.%%`EgU'TlPkYQ PvډC/4ɲ !9]iJ,5OfډXRa*vO:;O^Nrp:;czh'.gjvba'3>KYC)IS߬\B{P"`vXZF>ZaY-#}WPݎl_ SX"tvoURE[;I3oN*kAზ #ӋD  l̻wjjE~"`ת~?{X Xrԇ'5nnV=lb U!ݦ+p6i\̟1_W7[rKF.+o77 /mn_gVX`&wV$/?;lnwK:.Q(otQѫwX`c&әRuLEKw~][|u?_զ5$`FQ.'˪^)juU;;hP~YMHd:Igxg1pzg{w_t&o&mq*צWC`f^ ZR-6vb2@h2&N{vx~Yz܅EHFRFH e,RFH e&IDAT,RFH e,RFH e,RFH e,RFH e,RFH e,RFH e,RFH e,RFH e,RFH e,RFH e,RFH e,$_=,IENDB`v_sim-3.8.0/tests/exports/field-3.5.png000066400000000000000000002036551370110300500176020ustar00rootroot00000000000000PNG  IHDRXXfsBIT|d IDATx[p$YzNftҍFcgzw;^\S(9Ma.'=:F+l=Pv#hr"i ɔwi%Bβ{zFq*p*TUM`*dJ+|G~GA!B*Ì!B.,B!`B!T B!b(XB!C"B !BHP!B*E!R1i~a!B󽇏{ڎ,B!`B!TL)A?o^>Zm_<ų}!BD~33bJjᜅs,n2H4:j}xk߯!BB%eL>LB4kk)`ϯ^IjU!Bp7~7$5-rUȖ EpNުΝI$9EOT/+}=}_ig^'Bs1 D `L@d \IPeykf&pZ\)Di*=?J/+|sYmnmΓB!Ņ"X $3xr(Y33^4D5q|q3$s=UwWx)B!rsY1윃M4s$5[kH:ħLg3Dz"B.?1PɣV֞ ˎaL/UV+-}(`su$s\cEeRe΁B!㥲F.HU#e,cR$IBlVa s kړNrʵUe\B!{ʄXyzP5EE*d%I-B<[:̨X*B!EkɣX刕15ͦy[7jcjSFsB!WKUl6\%yʘZKDJbeq^;I0+B!jQ`~fa,p/˕m(aW^4$%3G!IB?oovNJ >#oXZ6}y"6?G!RF~G{+w|` If033ksC?"MH'`btB^qO]x-/ٙ߷6CFc/|.prr-\B! `899,uyo] Z6abZ^B!W GXRZ9y,2x2FA^6sȬ6-lH92H!j(XdOUs w#]IbO9X ޖf f3īU!~`!U-EX]ӌc-AR"ӌes֧˿v.B!C"#GC `u;nTd(?1M ҚAM"Ih?_?Q,sL3BiEF GW]qgMǂf>(D,m]׈f)z1B!W 9.D{LEuXfIٌ6jI.!BPQU6 Ly6cx$Ę"͘%`eA_3H!  V g-Mےf,vR$I4#Wi5f$iEFO}88'z-f򦩵5s?Mkκ!kZ !d¡`iau("tfO9LX"(Am&\c0 !d"`#|9 PU4O,'G>6Z⟫y^^U43ĢR/B-,2r)5Ŭ34./\umF̥S}Um:]B"c)'uvf j3o%ӌswh6mӌ+|b̟k2fޔf,Et5O,ӌK u 214C]Vy61F6kZҌ%lhzҰyze!S U` `ߜL.O8(]I;f$y+ E4# y++f$L,2&*b3' gLݧk3 A~%4cxo3E$ !d`PD(X$4c!^iJ0_/6+z1H,2bE…KiFc$뚙IR. !ÆE*S434[OR/\3AҴ4m ͓$!TUd,R6s8-hW"M%w4cŶYHU6cG!_(Xd,fL3N31͘>5;ba#u4#!(Xd$)"ض6ciJSٰ֡h4,ŋPȘV١LYhxڞf u\G$k ~;A؉5}=!jA"cAB!bۇ2+}-4LԃxΥijPPċPXpNzBGYK.c]L=Ϳq6cTjgF ~(Xdl;4??S4ֵ/:-*!dz`#XIXjX" VgS?q6ro5'SɃEƂs 1LKL3I|Z3y1WZ bjMS!Q28iFB#G !5ڌi45M.i2lƆ_ċ2(Xd,00,BBz&fLÂس f)Қ1ssyhXdM_h0H0`B,Rw"Re[|aIxB·EBQ.@]m 9Vm$@ Km>jv|#^M iEƇOL2nbq=8gJ4| K7c8c\Y(Xdl#WL4)8:lbgx>VYjs\+7Mf/8 l7\\~(Xdl80@YETӌ'8?iy>v 2B{Ҍj:$^\(XdlXHR$5K%*b>Ǝf_5mef蠉~1!S  Re/WB.%4cZ/ӌ^j5Z 1}eTB& ""l:4'-K@}6Ż/ƴ!V6.L װS7o͏l `Bi*:`O`B_[\Zd鄂EƆu IkHie{ܸO \r9@N,ff_!"$ĚLg[ǀ7V" 9iT!1Qv!,,Q.(Xdl.͜EH鄍Q,0E /LBJ0%./e2(XdlXD(YE{lD||q!I7)Ydz`B6 7}ˆvv'ld/rO !,BJ]aY{; 8 Υv}f\FH_Pذ5X+Bƣ7n؝L,26\JƯ!E*R ēEF`%ar&݆QȖ d `1C"x:_yqڵQ!A"cZE)Z48'8:j"I <5BE!drЦ̛G[l@& +"rɻw(rlmA8tTFHPX6?Y !W|.5X+" g3 !W !Dp%27BD`L\s{b,B& +1EȿB !y3j"^VVYN&Xqηj`gfBH|ɽ4O, n !+_~6A"cYe;!@)B O( f0O],5X)+OEk67Q,2qFƊu|f !d^:}E& +.L#"&wO B2YPXiX@Or){oen1E& +*ruv2kjXX /B>}@շ"fM!6 e^ل7gQg2FƊb,B:ΛcշW|f|Я!ų=_~ `b3Wd!"EX8:h"M % +"KyrpӄdF K!!uVڸO\a(Xdd-EI Cx_B(/,2Vl5N&*SU^W׮ 摱NեJjg<-|,2~a]mB=29xt"[wYNFhd`BHl< X\ŵ3>rŠ`Siju21!dT"l<(1,2vb<:VryU.[,v'EJ!aEv[tlB΂EƎ ȝE9!yEFG: \\<=KV Kb#XQ޲a,v~@#Xd2DҘ[M LJF^>Gٲ ;6sagB&oᛒlQܼz:Y&o`srӂ33ů(E 0Fea>{bC"I͜Z9VՃht2|Z^>؝ I)BYDҪ0TW:IM2` 3Xs=h2 "c' @Zqh>Z`v{_ΞXd0ENȽ*hAo"7٦!l氰0f2$" o*F/}j0arP e,YîӪovR+tpW-%r`,sj3QVѭ!8"X≏b}gq%W (kVχ VJT%X/l図03cL<.Ze(\d X:bw!"x]FHPD`3\6Ü7 kV|@oa\5?P@ՃMd*Vâ *C"*`#XGI!l~<*ҎIBk )ȳv2E*E& Eáj| S:!'navrq(Xd",F1A'Djx'XyLr95Sy4+BpыV:rbȹv!} aL⥪;$+Par yN?`y O:I֭YO;"M8Sn<-BE&r{{ES5rt<ܤVy'J36 e>ō9 ,24,[07|oSo-BQMhARUb;QȠl 5X&o`PDHʚo6}vxsXPRRG̪j CP&I`?k/QPDp|lӏ[װXGZ35ܾs-谉~um)Z%Ӻhc.3Ş;.>ܾs s5v_#nPD5-{ϰXXy,,ֱT| 5~ũ/wL ~UzR&Rܱ|"]Etxyo]ýG>%2PDl:("N?}o`auX| K^.7=w#aVy8Lhuۍ5\&-E>,2,22lScx"ykK7f4"]xߴMG6_`w̓@9-2EPDЩ{բUKWFٽU`q[籰T| At53_ϵΛcl>lhu#MWVUJ1~k'S|>בL^EyP3L*7-}Fk\nW< IDAT|K=>Wѿy}7>s"]S5<zDJ$qt}YwlȔ@"SèD+yP8kMܚY_L4Z`uz. 4zZ|1%Fx{iu?0v>Չ(]cܞb"ȓGX& L Y!ܘϰuWZ*x^㢞eSkZktv:^TП˟Z<㠝V Ex!5-%jtrC61M))E&fvF/2{ju9mMvܽU`isX5kE=׽vo^bw^tM{٢Uޢc cъVqGKFWO_]û(X'(XdbȚK[]bUt;y,| 7o8ͦ166hzYDc?^ZymgkR.5ܚRl@΁E&扃jIhcuZ}dhg\<C=ʭyz!>?Wq-Zh 㤈VqKYnBgyx[ĻÿX E&\`dъz. ovwwksЧϕ.֠gI2$DGo~[½K,r.,21dYeF=vb찒}kn{=kwczy\IZQhǎCQdܑI a:>3 Iw(Xdb(7T{Ë b;.rywX\ڵ\nԱtKWi#8.C/!!ZNR*B&{;=ƭxs,r&,21Vf=)3}6lxZⲏnݸ9sceu/]o6(WQD?ְ{iw*W=|Ge<67VL Pmhu6,(_yܸ9:ݽMQw>sǯ?}8n˖^|p~}&tE&V;㞱&i3βrߺRt"|=16qI'LѪz2Q5l7bwRHW_}N!W E>$< :BD[v+$"^QTo"S*SԌAշ 60/mҋޤkwLogU~tgl@eJ۸w pE:B"Cya޻h>}M #i( P0.9r  XP0te,Aqb-s0"0"c`/2k1sEMQqx~=%Ǩ~&Z0 gH;#=>|(XdbhvCZ6]nsza{kIH\%^DPUkqeuk=Wyܽ~DEǨ~y(iE{tǛ߹)X,21dM @Qu(rWK_W8UsHG y $ 1* \xTŋ c0Ch/P1AB4( $];_]>ҽ)j>6EǨ>}Ȃ^X:1lZfb1 L=!Mh QaֱBݔ:E&"QEzP yKEa+)FB4`LI u j8u~; @PDG?y߿X\3pwjsY"TӚQQt=tp,SH ,215X]4";nuLڨvb?Q}CFBaU|d l'DP#S.ʔB@ħ!v 1 1"d ~_1|_^5ONjӧOh>F;M{4VHxpkwV3h6_L',21}]*\?}(Z/>7+- ٻB#IWh.KE0^JB#D+ȘiN["Xp)DZ&D WC‹Dxu0Wxv<:4E]Ǩ~I-;C^^tX/pF!ɡ`/jxrѫ.wz+ 5Xq6  =iB Q)"2Ug4!|/gۙ ]0 i$J]"#-g?S|Z^ to6ywpEF+ZiX&]ncu{oEr(XdȚi`ib縸Q=!/uqӀE VK<_蟳* Qx:<^VLpb/%,:  @.g#|w* %hh6 _|CDϷ3|mZt]N}VtaWx0lX{}Zd`bZD0?vN7aAԡ\iD!ˋ }?JV7±x.kpu˄ԡU10ջoz/: vOtb<:ZhV p3*ޓ?~gϼ݈E?}ha{jZ9Y&RqԢuY={Ҳ])1C"EY@ZKd}ςon>W҃]m Yu)GQ7i;Έ_? h([0-Cwer[o"XE_,^VM]˖$KX<|BJ䡪·]/Ao%x|x馨\Q67{.Z/gEG?)*6_?`ˆ+L-HY3U8ƤM̤8K18_Y&ƻL!>J4lQ(f摰8J5P_vmk*~i#wxzPsֽ)j{=WQuJuQ>SZ#qqt[6{o >)1B"PNck9j?f N1:U 6)zQ _W]y0eDp<꫐7X[c+~…9h\0>G_DWCIo꟮ ~g֮MQ?9)t]MhcŖ ,S8,2Qd| *ԶytNϏ^ TU8ռɩfmR;{ٲ "(0{#o(nxQCX"H:ܪ$T%΅dwx9#1=^3( (_>XSOO5E^Ͽ¼ /՜8a3« Laoh8wn"b{۾ \)(!r0\( 5OӅd/!$Dg",4mDA|0}X|a J5můn} T.ZKWQzA>Jڎ4֘D+n3f,cm|*?X`]a(Xdh"̀MF{`hk{TyeNc"?@tr*9:+[bBqA(8@|2a;C6ZAJ9"Y1:į("'^{uOӧhyV=*z~zUnVqϣOG9S"cE&']ZNSoJ4vNc,_>' )`G6*ѫDg 2/5|1~|^}d^%s. cD?[_KEp)1սHVAJE)zU/g;U:8ۢO%|ÛlpE`S}wJFsyG:c /WZjTh>N_闺 "H.&;n1^^aq$1ةF3EPKu[h^[$ d#Sק9o :uw#NEU擧ihŁ W2FJ$jmܻ{(XW (3z~lQ՟sN_ p#W*b'QD'/Qߋ*F c!.sDR V^ D|!p``9;[Lݪ{eU.:Jr,[KIhf*N}dK `xoW0ъ"O)j?5ֹI.y8i%<}3S"#E&Ag;}l]56ׁ$- Y ÷|iA"*МHYfe*I|}  1@hhL;)I\XﰈPE[:>ԼV3yD ! @BEoDTVXUn~O~<}8nceu& B"E^ղTNoeWE$mh;?~}b-wxZb$o` ݧHA*(E:~-DpM츚,A Q iR}V0GL!YyWE} 1D|6߰frŢzJ빴5K\4ET5jъ;tp:Q_E֟-VV籹qrA"Ej)rRt6k XhwK66KY=؜aiG 'X aH/kK Š"U$~Q(?^BK``ɜ`[k9P>FKK(B-2a?qF}PUnbM,kRhŋ.#(c=덼)j)Ojc tb}VW:k:D,-(XW (Z#X wXgE9B߃<۾Ӳꎺ.xN W[7P/d8kLK Qj?ZpԨ,50F`ќ`5(=PVk%MXzYQpgzpRDKD]|>%ZVJiW1c[-MQWV{j~w0|*^gˆ+L,gK#_Y]A⹞^ժڎ:$gIhBPAn7X3,,PzB[ 13w Ta >峋^8.Hh'ƪN{xI/.T S/Zoܯ{7zE<9눉ɞS#Z#ͦ[6Q4@"E{7GuqyGE^h@;mZB΄q=#(:YA q~ U3@~,U Iݲ$>%4j>(6q^%(EZ?0&ɗBP_ _ v!ex9Eu=J-~ `)ꛍC8?y/lX]οN#Zlxou`ɥC}Kv=ye' I?μ%=)Db#u$Ө> W@ss`DhBt?JzmQīd9ck >HVx}2rGRRķVJGtp +L",2q43:bwC5m=tzS誗\˴)WSQ#A^I_Gy9 4ꞷQ@"N뮐fY cƗ$+D봴*:4.oWR(Yl 3hϣumzjb{4xX{Ayj(Xd{azEmBԱ=~6A)zL蔕O8YR HiXb'|~W^~"wdh/8VNEX1c$%]h1:/w/6vNMQ\ 1MGM?}uȤC"ǠhPf՟ z!dmr)'D[JebJ9Gp*nZBMV8 E},1I t8~"m7^$D$ Q%]֧U v2/:6H/YXBM9$~NJxDUK  0#PM:?Ars/e5-alE)\k:)jt/ZLF>`ˆ L͆_ק*Y}jMRuy ЈTdiC2APeAXlxNK8 1>UPu2 IlgJ(jK c$+D$,#g[d20c8oG[=]i5a)CNOxpga4tGlne@ 85X9EbA7uZV[Uvt~a$JtfAhiYwE }DClH `}R"T ?Fk6▯/l|%,JmL[~vU?>ޗėCZ_U9.;=yo,𰐮o`wf?g֑8reu-.),2h *-_+8ӷzu t |.MB"HQ(qJbhL8X"gOKP?|R,Ab;օ *.g~Abmg^ yU>z=8U|e]F0D×xzp+`u `Æ7fZ!N$~8m eL;e˳̓=s?ι'[Kmc-O_dz`V@PorgqW@4=k_f WnuPd)B]\HؘT5, EHi|_DH A%ƪŤ-4t5T圁݅$a ^b\+Q`P-._-Bc|ڝEFj_;|7< z]}q{u!ħ| цm4䀓6)l"FcerI*-c ذN,rm!FyJb,w-F4O b?dRo JWca3_&Pz馨O?VE} (XdhnYE69vʷ½Ψ3W%ʷJQ7׏Pc9?[PQ!]cHVO>m`BhhHNj_:>V ЕM I5tkg(:m류r *C6~=f谉wNrK}[=WׂL,2h^[`KѬ% h*G6oww_[J]}Wq3.K+Zi, 7 $m?$,#6l1RDTX:T DPZgrb4Bd,RK u>_?sǹl}B݉e-":5E#_ dȡ`# "gFp!$+T'Z'OY+~&, ԙC+8|8Y(VC$TA1AiG*bl KU`E;ׂI]QdA]tKo9;dP'2(DL~)4h<㲵\"$40g]35*=U)M׷4P}؆Ybsx_U,.b,yo ?ρ lr! og+/]hEOun.i|tjK P˕FP|V , "Htj}*IԅŞKI>ˇԡ]Դ~hh@+<1V~A@+ >ίKݏM⋿pƕΨ7N/S~K_:{l:4?󳷸d%Ü !'F̅_8YK\{g I q^{9J={~goS-{EUNh59Xga3Y 9p9k-S89uY,!u η ts~UX~ qpPSmگrSS?n[~mAPͿ^Y0nc}z(67%S#Xd"ɚij^X?@Q}8>V)=xD+# _w!Śki i֑qK#Xd"IUT TSdKZWjO\ T G@]kN?N;E:c~YՔN`{ \r:_]TkTQ~`rB"ό6`n'N;qY6Z+-_ZuRj_ǾSgc*gP8mO4\*YpȬ^2 c3/`Ά_-u5 KyZP\Yu(mNT%zzɂ•fEtuK,?V/[.P},nՇڌ7OL0EH&lt'8A=l )-[S~K9b閈U[%Ӆ:{3 KPXBc$+O\B_x;4.Ԙ1U9"Ư۬apH4E A/-uh*j HԘTf!-.SۯK#hZީQH|.Y{?vZ:]OVhdc< R5,24 4rɒI h[7Y7/6oCR@}B|zfr0"nmX\4qOL?2]7 ulv҆PT\\~po F?(N`Π 3J/7dPզڬ( 8 X} NS8hU1XQ\{Rz9S vgJIbai߇ \DAzRg`J zͅ]f@֛́_PPܗu-.v|pX^qbVu^uHD͗sQu浬pW'O`yoj#eQs}@^=K$&&E8"08ujBNwuD!J< )'H9h0 u9zC<{ot4o@ |%Lm_F|au_u=[\wk\d'7ھ1`m̸udJ`k[<~-6KOR7$tU=hrqXRΗ㱒.ha-6kz:09ăvީ(:QwtUwFvpfb675@ȶ)eM¢X%LBqze*9cf: R!s |6gdEljUZ)K/ʷH8 oA֫WhՊ\h= {bk5xUit:CV!n Zŏt9KD:z@8x*VΈ}YkkϗM8C_bD,b-1X\`¨W\fwMsq Fu+s#FFq)+9irW^KLsoEnTwRuK?;7bkԢW~{vWhhU "@+V݃:wZl'~l6L^UeVVI%k>|(_4pj > lX]sZ 3||K{C} =K↳xRrAYPʯHop PbyN7gNP ro-QU&+XNR5D{Ѓ 쮤xMeݵIr`\Xc ]C"@_᷿7z&Ĩ,9GoW B lh94c| #.{Ql>&,澫㪆`T!++^(kz+L?@˲Kw CrU`e&gxc~{]-kH~JdE5K2{b;iu -]VA!dM(c*$t&!YʨGT9c\l]iHg!V2+gKvXnۖ<܅.`(c,)AVN Jm!^Ա Ea 3%nF *`nD m Mޖ]-k_JpE2pkb;iA6aʈ]+-߁}WZߓ *VEQԜ\Pqxm!4]!k@N,-/O1*)t;ѻ-n .SВ*^5X]sfVv%(x2 : %+@2`*WA"3u /ݵ}(NY[qUrY̚l7 .(Y;:úPG{˫[~BV&`ƽ.leyPf"CPT>",.pY@qi-ψ:k8,qT6p hYr,*EĪ cf)fuUʥ0lhVD?JК~ТMڣrۓUKJ.vln͸Z,1dh ]g/ R7!!1vR&'go|9.m*TQk/.>3XM(U9IgЊ-K rb .S{2נ)`\+r X%(E~ߕ1~YLpݏUͲY%*yY&4(Tp&'ѭƅKdvJ۬j- ݵYpǕZ5{Ghyw!2s*u@O|?BpBc:TI,,1S.iYM] U-b]|L@0_YaҀt.% 5WAتk3;*Y0}Y"\esP2vn/DYˇ] XeKS;4ATuӨ{hUt dM› \DFZb-ZI8Lp[p+lPAh4pb/x]ͳaPT"0-CbQ)3d*!\c~Y\SYժV XLREJ+4bfq"-qr;Ɵ;0\Y+<4wYQu+۶+"+zV"BD7gn VF)XKѻg `-cF h`i*ŠQ~tƿC7}5˃FVXzV?P 5%+M*RC.\#G> D]4͹KLY6Ȩg”-m72OW筀[] }CA!6谖dҠ- Gc\XMNQ\L blP-OOO'GG`ft'/r[u3R!+q\G:+5fpCWho:.7ݲ:H$d1R& % Xch3R,~eb?fI,;*AAC2X*~l,v+?GM h6] x6lWޮa _``cR1.+MѰ_I[v֦vnA ⪜ *܏.gļ2%[(`lgS}G@:;)*Y8 [+QP%?!]1\Dn1ͨYeH UK>gj!嵲8W~qa,nۦ^%8SǸ(l*[nN'XmNsXT/ eBn -BۢY5M ju?QV)ZR.c\fM[ky q8N$c|s7\ \4oKfJGAcbCGc`eb1Qlk N@bK s\UէmEdaVB pb<@*Ϟ9*lp݄yV(lZ4mV-jF*^rvYuD~E%ْdnXjFH YV,d,US]~{J1ChgOPWT\'єZ2h@@rLC+LyXy No`6re:yh{٩Xe?:hsB F% DM=o SY,B"H {h]!-Hzx7Tn檻p/=,)-Z>tN*M ?R%oEGBN"|7p#SF`Um ThdQ\L`{\o䏙$En@*ʶܮ 3e@. |u9|өAΟj4!ejB#IF#Ti[4+SVΕ/=)@nx_ڒdnXKѐ.[ :>Ch!P]Wf|\.JѺgEɂllmh4=4 Sڕj;wV]BmE۶b;k}/?mKh*dM0.[ +e2S?ô yU}TA\+Ul_];< 84ۃ?b#MqG7qH<`Al3 IhLQ9LBtcƚVP(+Y]S*S?`KA1EAX"lB,Q4eCh_=hM lExmv֪Q@C+Q U~U("dw,EGF*=R{ >VCT)sH(.$=kD)[_c˸.+yb*3W/}'MuЀ12Hl6 sp~)5V6fPӀHUU Z \U 87I{Q@ }m[kz2d veB}5,CXb|c}y,'{$Vҵcx>dN~`/WY@wj6E AhW*V#yj+`fWg|n(-s*dZumv VmYs<*qZC*LjՅ$/@?4^fȕa@gOKv +X2SMYR$Cf k_`UthheM_:Y3]]ٜ(e]epgd0O=4 (p1zR:L=e.o~}_خ){ IIC(aԴ_kZ dWh}WumYp[m{ɟq K&lٲ-:X2"G#M g9ibV, lp|[89D!Xgg.|\&[[1lOѝu܀Qd2D@p9~ e E8* Nxa"EL}ma7pdi %ɐ!Df'2 IB!Թ5|&0*,3|bFcq9Xbb!u PFPۂV@,J\]&._ـ`E[kmʕ\WetxhDSe )!Ľ&U]b eS9U*6?}5!?ƉiM04:2VВ{L[t{:y4T@jrgjI`V %$DRB{I,-},Łj$; gd.0.` g熴 :-;~Xn4QgRm ZyoZ I7u8wap bE(Xwb;m&\%=/ec* Zq.*"ou:;]>cҧ; 7qi r xOU̖*tAˎj@`˸1U hSUi}-q* ~4 SBbG]"Gwе%T plq%!.O |,c<0.\9_ݘL<2PY@"+j$НB-4/l['Ƚl#Kzho_/o2u[b;ma]:=8Wpt>25!Sut]M[gl;W]b,½w PP-RB:Cʆ+:b_hiKU1>π= @QȒ d1sB> py)kQfar\Zl9b gjz=LZ$*NmjD"x9hr|S{ˬU[ثEN['%NaE`X_e 0򎨢sJ!DzAHBqBB峺(b}|hџȠnRIO|U!p7DXrX\RujН_}aU 0i<1d!\ϔSE!6(HL7$/&N@AO=){ {6,!]Ѐzk8٭c`z+͘N$*4yK4X(p1X_Mv 3^n_-wkR5L:J7YXV*(N:Ŧ;Aם޷#mRw"ё @X!4k*T%+WQQ.SM j_݆hZs]6sx*0J= }LYޭ3h.@fFϢnѳ.mz9)s!fb2f%[vex.Co) T") Z&lj Eˇ`e%((-)- bm;s9u뙅2 d_<{{o=#H 4+0b *Â&EYVsUH`]ƢPI3E sAU•Sf{2 zV)Uu^`h@;b9=je18xɘIR4 -%@AAԢP? )C` g JS Z_U+ޭ KSV(FQpm#jv'pIEkֹW AM3߅+`I2:XY6Ger@OV{ӿs5+4yg;Bi BӶhֈMj3:T(U%3] srg3uL?3:OOPHݐ  2"\Ybg~AI`CG$.EquI=ƐEڧM %P< > Ia!HzJ |5pgKZ]:˰8/` hPu7fumq.Ӗ]=` \7 `1=Ur)ETe0 Hlv]~ם#4-sYqnn3l}_b/וd2Tp;8 GWӋ˷kځr伥ٖAv`vـ|F>ƾ<왳kюz K3r)I{9nnĪx4tF(I\ 5`5  s/߾/:f-b"zr':UҶ`}[k%f*2[ Lna rUw4A@堢:lS6V&`7t a%3 ٩IY#TY>w YUY;3C̀Xzpptc,#7nr%,3ً5,ʠ(>|Lzna~u I أd~s`5j*Vg7F *XŤ%] f% nۥVK|7 Z`{{@:?,lv6z}Gu504PFO5O VH]<B;~$bS'@РG &]t}QIT5flB}$ବ̂p8{erMaTȩSy<9X\}T NOYP+ZI-*65L+2I`>3잗q`g +62"%D*Xb)ZQ MZԖ@$mW Zv$ XZl"ojvf!"0Olah,NB7}]Xrd J&[h@( 8 4M  ,N'UMp3=?eq|~ǩM~cy-ϔˮAsљ!+Z;le@-nCQlJˋ%JƔ$?$̰WJjTzژJ8w@5Syp^kZ㾳/.ehrKKk `-v{l›)Chͻ/VcP&u"˔A}V`X엢!Yr)VY2l r}NѪ KK;b @ Yv^%+*quZ>OH <4\yYv$Ȣd! c.$@$eB!Kx3u- d.̒aT0_EH^,SIݰZ5ޓt[';݉װ[RB%X.;~Ir^Eȝ,#Rx _@ΝLA, Bykn Yvj@Va>\-Yli|]  YTnσYքܶ 񻸐3p/\brx+g{O]S`s W˚~iq5שW.|hup䣔OX\{k`o- oª׮ܫu(v=,.Zl-F?VլW0Ȃ HH}'!>Nˀ\{;=u%&VW!֦b]eo:)0{Akk `-vrКm,TzPBYBh\[K* $q|1U](csjy,=j ~j,LY4;ʮwYFH8KZTo*I(!S0iBQS<>V7.SPY$W;NL8؜D܄]'5^~zU4Lsz/fINHE2UE!k'RVjZL,e1E p U*c*)4MVATcT+dU+;ID}E:""͠N]*p Y_vI_3l6@S7oG2uYS9X4fk^ l)ZӢHĢQf44\bR]l:fl6z3n@ѺuQ/%J[vb/3Q.i_bW:[Qd&S+YsV9zS{QUT# 1,Rť]f3t!RBhYc7% 4@\7R74!cu| SΩWBDTW Y|棼B9Ka% DGNr*kE)UI[BE 6"A@#:5 (pľ%F)!5 1 Zz%hڐ=â>ïLw5-l+yG] h \QR7O{ RT`n(,8B dUB.I H盬fW@+DRW$̭Յ2H :Yݻ/ͳ'(jL8 \3w*l앴r#8peSu9וU$Bt" -\"hHA\ܨ֖r|K kD&U* SB RJAݘu(ʕ+'1yB#3 I:4$aQ޴M{+`z]lq.΅5mqp>t\r=|t @AMJ!:C yA5{q OD&B@zeȁr@V0s~x25 !NVv8՟]4`f8嫬 AnO`,oUϒr_u %8n)(˰ZbY {hufb=]u%w%Ì:ƛoG8zд lؒ9 B{.} הgkR &"p!I!Gهg"aPWdʝ<-7vm ߯2P(,s8zr D.α,&lN+܃9r*З8/#Qsd֠&:@kXǫ]Ez=lvb/?M{3?W{E"Ԩ1l賻s,: 0uYP/X1&IaX-){uq;voG݃pp$9K ݶyQ]>[W@reԚS.';4QBL=bt8,'Afz5d&9sBRJrS˗V7*Ȳwhp_F7jp'nl-d<A*!F fŠ-Š H7AZT\)5iX8bH[lTA_uB3kI4zmv6ُF. +xB}̶ C Go$ԎoIHT'STnYg&t v(}WG/ 5hUn f\3T%V5$bgZp5|/n; r rVRN`HcJ8 kiI5L?slbT+,~ޮCμ\5[k7Ip .17Ȫۇ5Z>xwqo_ ܃tyqG1?p߁U$i dǣ. {u-nݹw96 @Uz@%~?`35kIţJ,a-4.\6s4wx$אTvL{B28UY9`-2~B*L1@wSXIiv60TNa.Jܗo `-vkb.If@k2jY,AVL 8zCH{n8EL9̲4hF m9RA{t bAܜ˫Wπ@ hBΐs%!ۤ"Tp΃sןX9Aҁr廘&9]MbEpt؄2 ͠-@x;]0}z9( vG%]Cc+ 7clCoov9U2XYmSY8P42ΨanJ ]wz< L,deІ͈ PH]REQJr=UgX29-^gn7nayYc|>L[Ҍ A\VV2xN]AJXVpF,Uh M $ )go٥`t к֒dy5Ƚ}.‹BQդ[*?y!9αټfsg8=^U޺T`H +u)XS|Ҕ Y)2U ecy é2gV=vP\2ȚGrK"A(篪 +cʳbT-/enBV8qVvz~vЕc,.¨[1Nc"׵+&&V\-A*~KlIXlћ41(cB5>%b18,%U(¿z7EuK" ]v9 dE;#bXev/< b70]d+p87d@UZ)%cJ2PLɹ'EVK琏~C4TxaNQwHȨ597nCS JeU%KmvlR:5F"h&dwbbMY#.7%6 ^݅QMK`.O޺*u]v$g -b/a{7>g,XB>[~2!0 YJ ,dWU!a'͘UĪdxD8\vΉ5Il8UA/pa+ۏ]+=8A D"$ ( F}.Ƚe=DÊ}g"@x)ؼ*h RLյU}#к]>b;o"wc3 /486B>$YY2Asz7`^`fR(yS+eyTD?q4 C-V ǃlbe&daJ1| ^:l[On`TWі1S0ZGd?\Pbs+(,& T,yr00U`x݃:nX-vlonfVn,LJo}ʔ"rPd#S.g<E%mCe݆TFfm/fX_n!V\4dӛ4=lO\1dya}++>plv` ۰U7%nCLD` 8^5J  H >j{g+URzE6:$+-blQ^jŜ] twfZʭGDH!4Xa/S}d>~7yDh fflU8 \V5d͍Cx.  úJ 3X-vöw b.YxIe[#x(e)A50Y`z}_6 A( Z  [6 Aã[\ˣQ<Ϲ $u %=;Y>UΑcJd.”\<I/&P(f98T+1E{q0_OT~᭏ڎ[e7`ŶOX5hV8?LLTBW6b<] 4 ʺ?%]ԙ v(Te)翂}=8 ˠ5Qd Yi'A5~q~[;yu &NYTMܟʌ4bT3AOH,^>NH)qIrkIujbb $$m $ l=BHDA@ M*T=.7oCC>V=|Vuխ-V\umQw`(}S~/\L]VnG+E?|CU *&2T%%lh3[0tZOpdžY]8G}#I`N\08׌Mm.2vC-_V xO(EbULq5{TI㨸 Kv Ø|0[mu,F r|ro$Bvo.=~npz{| @ ʙq U/'gC3Ȓ>/iFP\~΅^ eV{\P R:UT¨jȪN y]9MNߋ뜭kt<~+1ÕۢnA W2/F. QTIE- AKݐ4 YC/{';`~(t8E)gE_ZUOblm!B zGܙrE4w>%iUzbz- VDC:[6醐e0Ądj*;rQLj1P T edXԀ DGF4%!ģI$%cIU1Np% >G 1vI9E*Bm޿Y;%WKekZl[h{1v5U/7pNɺp_,`={ F0rsYfuyHJUy|sC Ѫ\1V뺦ʹo|[okv|LEK|waE*ɝ}pzY:' U*jpjeV20 #gxs!e&䧗ʃ.X}Aߝ! Hw[R4^bhyno0/ӚZ?yoLUo|mQo -nAS 5 %h,D`%ۖBi*{<%%lfbVPR6dŝ+d/2܅T_;'u F9 ]w_1n/ڪjK˖Y 7 myQwl0Cr,̟g8<|Ãh5vj+>584)Y霏DXS4 H f0oJrP8 @H@$'`&Bv\.f ua4Yg? ؎E&3M]+`Bm&apZ,@T6%&u& P` FXD> !`wb[U]H3EBHME o(\b t+e9( R>vhst ]oqroh=, fح2ߒYUuՅv/Nw"BCđ&R]أ@ 7?+,?Sy;9rfpc;۝U[eLK[#9K,YyK"hy$p8'-6P\YUJQ%+) N^nCRS;)NNOpr"y[mzlQp4Fh{/ө+YpO)!cۅc`P-֯3OD~ U J\"XJcje.WʩYf%3Q$Ctg'WRP~r1e~y0\bQLbULJzJB"g1"h]"B|9ᄔ$U`R!eAIY"[_q_5@Vߟ˽\=\2FUۓwܒž[k[e`]u-3Wav |+<+W`nAlf9&DI&ٳo27>dۿK]G :W@|[euQ/k2"YGsDnJ$K 辂c=]#'!t\$bQ IDAT@|A\HF ]:,+@oY0!@L K܆t )@3 ЙQwvݙY Y]w}k Mvx$(XrbYb㙅΍݈ 6>qD7,,}}4wd,AcN^ĕA/BWa 450N24W΃r,bw2W馯p~2ӲB*n|Uθ-r."~aLI-ԥpR+u濊(6+g'kaʕ KR^Qw~W+kJ)ϟ-T;EW@ r?=]^z(X 룸$Bs]LʊY|Ll)լt4h ;{ڢTG5cL޻W~9Rd0ڜ#B* #l]/Bꥶ?@wzZj\?'M&BirL8]G,E9f'q ȳ5 ,FVB}(l)3!+D2yȜ;dERfnzX $p7~h7<_5X!+T?1נ(~ggw˰_{P{@ph?[߻/)#$?xgOy24*C@}!SY t;S+(e\Yk !fEs펱Ɩ%&{,u!@ D-s}D@jdgrj J 14hw\hr j6x-_YɃ(X-9`;kya3,.0N e{*3㏾k3?3}'OŧxվԩޫQc]w~ +ж ڦ'!h 4s5̬n\\!PƇFX=`Wx]K+Œڡ$-8WqTegMǠegkFM2>$bc$ pq?4h??# ø9#7/;uWw. ` `-vֵ"9NN3x)~W P2Gh>[sH֏?؜=r]ɡUoo8H3 [(_e ZoJ[q'ߵ Y29 ]F}R.p=%B(=R"š$pe^f2&&WeÖZ.[gJbm `-vN,V>kI޷S˨RgJ5rr5 'Op O`DNs7U80ЅTL/SHsSج,ewR!9 }zFZtBDl1h4eyvdc~{Ak%5ozXfyU~0S?~u|{LEuu"R%'W`U]x s!Vt5וʕ U,pݐpkhUos YE4WpTկH[~GL$D9ТAMJ4Ј;Zvآ`-vƸOZVS:5h^9%]W,۳Aߟ''/s<'8xMH!t]1yWp%p=qՉʻ cw.uVa4hˢ}c;Ђlj8O ^yo9?)T(fN-IF_?[nI.,[1 !EI+N Cʁ]GFTcrr=xw|5,S$[BƫU9.7VmjufMcaSG/ύmhn;7-Yd};wɥ @ D$ A$ "EQCR'F#l;b"f#9,O(!qDqDpIQ\vwUr׳᜻eeή!ys3~qJUUvAMA:ի,P*iJvã\UxJhBcPZR 6*~*3Xl9 0\ uXhi1cQw"TW?IgWƿ_F_ xE˒gcU*1ʲMlLL0=y>l/ۯ_Vٻ-Fӵn!).}ˮ) !kxw"]J*lS[M~%â H6V+QUݥ6<\*1EJO t/yG? zA!lcEq-y"pCʄ%Y6!MיN0E/?57hZ0|5|TXy6M'$)E^!--mT8cb˗f{G=:J«[a*cjUL8P~͒Uf_MQw @hm=',F~ȴP( 0%tmD!ӡ 섍 ۷i}Fk0 1FZk!B0v+]^XTR#:3j1[n^Fuu.Յ0 O[^?|oin2dj̖[VS*c4E5;7Um#\DE-*,W*l>oVLΌjeJ+>)[j n~d/ +]9 `nYr랷P)cJKj(0=\T9X^?ؿW*CD_| /ж)ER))e]}<3?\gv^YMwM>yolƗ [iWɖMD VRas*| D" A@1$Sƫ~ƕ Mcn+C#Z92.AkP+[钣&hLsK.Ax0Rcd_[hXݫ1ˑȲdJQH*V-Ou'Od8z%%zIًwny*"YT-&ug&Lƨ/C4͡Ibzz"(d#kyy AoԪֹdQgj~5*TBFt[?6wX*XsO}ΕZZi- eѺ$ mՂƃKJ04g suZpp$L'Lc&Sp.BS v( 'ʹcJ5jWCH`dEaq%C^^uDKf3Cf);g73yX%Kp즊ih4pU;v]U9Q] ,-3Mji_yOx屐ʢ;5_]An&XM&c&u;E1aUTNؑ'KKpsYXnηMjat6É5Ji9PE~~m4bm%Y][V:Fuѳ?f?ldu+5q9L9V 5r Ul$t/)^ HY^ʌHtt2!Mdi- bWO<փe<,7iA3a}sMmp7%ZUÚ50 A~9{_|s'#_<#ƩשvP4FTmjF0Xq%L!ʞ-ᐭYUE;6͐VyfKsMUmeǏZQʼ9E)RʎG’+3S~C F*Z$Kz&WTq"W6M 5CzLͪ]l)9Ԅ*U̫nz'Ztxqc^^2Or\՝glo "39(ήg%*w*@)St,L9pjY}pQCF'eca(X;,ɢ1l糪.sWhWJ\2'34!M4!&SyymFa4M|\G+{^y[Xg^U$dV^~/`: 5QT &Vyq}%m jBMQZOul}`2y `Jø I,ʁmd/zE_|㇮1"5a(8(_YodYR)3n%^p P/.WÿɛcDg ZY^pz~_Y.QZR)+6@Iҿ|֡_g cJ.1%s2E軜m>hA~'0€vU ԛJ`yu9@)K!tˑ)Y{n[->xܮjUGݷEe"jƮGF8 BdxEr![hhaV$-~oEΘo4ƕc23k~Q@:Hjݟ B[3/z}kRM+Icts,Adn[bsrۆt ).>gS;u f3jbe@.Qny\%Α.!L-݀geI1v݃4GRT@Yh]vƠPҒ0>{[qA*l ,<'rϟ:N~=USuüU0Nux#,E ?KL]&x2&v_c@%&֧󍿇,YۉT':t=U3ڦ5pFP_k4Us-㫪9V-Z4N?L߼ޫ#]Z+KBiR* -F]{1F BTeE!eADuYZ,a?":orߟz2x\JUmw'tԬ: gn-^ux}lL dyƓ9q4 m XETh|ͥluRAMSA$l;FL_{\ҙN|U3XwjZ-ޮtn-kfi51 Ql#Rҫ1*`Ԟg ()?z= {wK<eJ Y:%Mdzs.9兆`OBR*wЍop{0Mrzn7˧XY>qVVBfO8RڝAa';R;ZǀRw Im`Qyڜ˴ʅϣ*Y}xY"WvrS~U@H7踇nn~ůcMg%FK9|ܣ+ibA t^AS" ~'X <Q Euf/Mf}Z ts>ߧQ_wsuAQ $ ԥ 5y}/A=PED`U/!0Fq]C@4$yYPe2@ n5$!CG܋jp%7ߚ󨴳O~lݶ:0b U@+ BJ ]+[6v=n IDATta4DW,;۶=Y*zq@|fe++GJFS" ~/z,j{.[: /&SB~;l~q=Y6HuVo*~+MyբWGUQ_+S_/m )9aLZ*C4 &ªt]S]suJf=ix0$ kR٦>mVw*Lk6.̉33p.n}]z N޵=ZW nĒ-A@ VWsW*b^yJy,RaB 7!P[ۼ~H1Kgct ܺko{;iDelwJi ZKwފ;{AAЖ *鵴jVC4.>Ѳ[fgG2dMT5Er%^KHgB&Z>zO.A*TaX6crtel󯾗8m{^wovv$’8h{Eλ+ S|'X ֥|i1SömYqほxw {)%\9[j@Hк4}FO͖619fnÁS]U2>q< bdB#k/ '@+!lB0N,(E1EQ^s3ĴyLT SOѠɥYfֻ&(! "`S@0X=N"US$4,\a@ + &Ƙ0h 6fIVkê˜Ҍ}@=BAx_1 ^X((Efim5MSs!`Aa {WXS.ڌ~I4 D!p FFB\sv&C4h\FUuگ%ت#UBFj1L}}lU]KK'Oɋ 0s+]!2P>aGѿfkM4"Ljp|ؔ/?n{;k+)"2nj#y<%Y?jIVU2+:[Y-1.SiRmaez`ês4δ^eP ԧ)'S%#;òR i6a:l; JW/C[KfL5JRjI|&lvT!M}`uͼ?Ҋ,9=ϖnV۱:EӔLۀ/Ax)9M_ʝ?DɂLͯ0̯=X`y,,\hg5Ǔ.U(0HB6YO_$xԍ{v9InUNl2a;^߷V<_Ҧ Dy,4cK'; ,re󭤋a.^2 }冥iT;Oª=%n&+X `y,lҶmlY2G&ks U%R.(!ϓh鄲,)˭>(!?UZ7@@/ۑǹ(OU䂱u+fEGZ^=L[C[6q]i tŜ[QMG8aث@ֈ/>vI2e:eٹK@)_diJ^ocPFM\moT%,P2YMB$C[9i6`PRQJ &`sxj8VʆO*@iLFM@?8`Y4]GcoڕBM4F'}ͼ/7ʒ,Eզmئ[ѴQ}n0!*m+ϜQ LgXcm~_ L'`°OF7w7'c᠕ޠ&rU,s_0@)3|4Y'%F3Fr3'r8|Qvvw8A"}vWՔ.iDl1oQ? +̜ߌR5xe`!"b6-zd5Sb9v2Ȳ亗KJO֊Tú-(`ؙn`2 O<UTC_߽B7RVJTrdiEMN2M2e4zͧn}roi:rUfٔ,Mw`^ڌ^ҫU6[ |eW9(<,&bq nF"Z.* X8Tq_-vҘx:3$KTs"'&Ymo:2oy=MWKw*V dg?:gcÔa(8y֣QZRS©CBTEã:uV`+>+:0 " $ "K'XZ[u6b "7A+~ך:٘Vʲ)ɘhD/ ?w;%%`gbZ+敩5W#F4K@QZ2!eNLV%<ݼNwc` D}6`Bʜ0P@ʂ44E!1&`^*)KbFELc1a D2P `<2]ݨ581VJ7- M6NיLNsyy]ְ.qSr‡oxcPW. lg]0Y"˹ PJVU&_}0RESoz+VK}ycGGC {4K'YWW7Q'cEL"ˋ/;Ue*6FpX^9B“[Jkdo? >͐eJQ&ŔAM `yt'ӵo^EF? A)mPxA'EkD]3ZA٤xgcFy%5Ƅ ^e-}C!O0"- N=ox_8__a29ñwY]=VЋĽwvX m'a^D*YDR^RR4/%CKWz7܉b8`h3/uS_c~ZK))itzƎls;^^ZNV7.T&,s{BW_%MMTw/ XI_G׫`|O$3o2l~x|p?,'YW j,BnwVgE2ge2=Ses4'^c6Kr^nxЄ!D d٘^sݮ;@ƠMY~08 m޲#{a"{R ɘxh4bssu;r\'X * O(\`hkoNmI21?-}=|>ZrJQ)Eu({s^NFØ*"BEZ֣Q4A;v*7gY:bꆅFlx!]y/c᠔qK\]蟼懺taSYf!};z܇?Nc>? x?{hG{>dt,Wl\P|CyhWeiC َeMԥ2ōVmMQ'=' RQLYf4@+^(1޸7> __[/,8~Vm$MT`tHkRɇ𫟏v;!D豐0t`] pbDQߑ+7&FknJaTcX2 cSG?x}<3a:=ma2y͍8%(&8ѵ|^|MW̮_kS+AC^M drKA\Y{O<J[?Oy¹ }ßvF5Fa;w\RSuEB'e(J)QJD~Z2#I6\llͧwΏ?J 0N="(֛d>mSzK53\ BeWV,vaQ7[{^aNX,̩H{xVT SeQ䒏#;ߺ])]xRC !4qpޱ3zT] ;ߵ8"2*k{<Fۋu. Y8ǃŧht-!EDGz{!>ϸuAVZ[s6! z䟿sg8vݍ ?gˢa$B׏-YNȕYnЄaay7gzC=X`y,$*/.,<`hY Dh”(Sb,AC  t%AQ?4yQbbwS,z -/#ߘT)yg88SbcKϖ(&$`MFǧxzj`tIO:g4z>kG>|HqUe2E!wXZKdY UQWYfIVONlll)#<dԦ#} e"_lVOV IDAT@ E|p?×=# }L– vQ7#ڨ u~m4Y6Bʌ8P. eq{rƭ]scޓc$q<hyT}yT^1K!AҚlB e)1&"ڃ  ,s0Yj/mB/c{+X`y,$\~b`Uhe22p_wZ]|~[wFXK{+U]ܾ H@Ey.xg!Y]\BJMKE~{{SLAlm2 ƘhOyL>ht,-_"\lԝ Z[uo|vV{Ei,s"% 佘~} :!M7QK)eg/HM^:й!ar`LVP0#V .Pwz=Xˣ{0.i0i/oUeJ! I2%MSVAᆀGe?|xqCWfx13Kx{#76"/=Y_c숚heAmڎhVJJS64&ل, UYw,E5*Gՠ>/bW_OxK{rJɺ?~(\*egj%Q.UZE 8_swR!yEcx@d1q@!7<caQiA Ո`hhLﭨ(?fm֮!C zK䇿uk0ZR]N)3|*3`@w%3$!q4s Y3 2AĄGws1\H=duW|caQPѫ3cx?잯o/GF BD`@P{|M{h׽(ˌL݌B%UN%晝)[[ߗ.ޖ Sl,g`c q/`y,0cXUjՉf%Dر>F Qpx힯k/`ri%s+ĪIٔhDY?ٱm*e$ǧmjr ϲ;!_"Xdj[C_RF+6c}HadyL/ɺA"˂H>Ijv`LƂLP z!;vF 7?pXXB9: iu=~Ӭ]Cӣ˔GaP!} `y,,+X8Z~fO֦tM R8RB2)^G)Yӳ'|jW@+o҇qABu `y,,0 2z/H-ڲREIML67$K]_ozcnDrxţ;Ҥ/Q ƒj10ݵ5D=^x!w PD(a}H2' R)2@/9yB/OXZ>;F9Ԭˁ?^oXVTy.Ža19 BD,4 ص~|`Gդ$^En=O?́`m0O-- lcpF9UeV IEF 4Ł2y,,T$w`ZOZ.6f2MgIFϰ+nx*Te2p"AWIkVM/ i]j7gA( ¢#UÅ7C^[} ;YT{1Z8YjOֳЪD*%>zƻ6٧{T%BE5`yl0@ĻT*d]|>J0h2G =#PDa˶݃̑ 1eQSO(ƄǯL>+X J ovfrqUH2liv6bY(UdAQf$cx:`sߏ@y~4y,,}.n0t5j62|0eOMrQZQ Itzdz :ϲvhW) ¢R<<*XCc({.v`p$YT ޕ]&c677(K r/yY'ێ ӳLgLN+^?6k,EKgi9+,Uf: ˫Th3 ̑t%BK&M667\5IXU|r;rKorXXdbE'mdT0$cn|rhd5G>81eN*wmL*C?/QZr䆽]O>K?'84gٻᒽ,O<ΜN(buo[zLKƛ9qnn| /~r򹧈_uHZK8Oږ0ܳ|bm\kVm`/1ǣ)]%BF+N?O٧&LFJ٬NQ^t {^wKضp\x=n? 3Fϲ=%WρM3BOq/UAaıip U `a];gi9?XZYZ9vbV2)NK.-Tjvfa[>+k\4R}ou|K7٠T3E w-k2*X9cuzKGO!{ 1a %K|og Y& [zO<< ƣvÈ0%mtl[eῩ.f5 'Y;c0HAIYfdٔ(}GńaRF7sØ]'Xg'X[PB՞ [J쳺sVյ~tZ2ȼ pa /d!ADYf8BhO{_wK,H%ɴg k}W{,-[ueO%qxTxu FM`nga/O責jA9h` rÕlbWk:L! ADM,Ql䤉ÿu(0un=0hm/&QBW{>:a@j3cnz:&\Ye]5U71d4Hhm珽rw Io2Fg(Ϭ w8O,sЀ瞙X`yxd${Ʀ`iڡ~G:TEAMWJRq%vz ,]BJTrtgerEALJ&c;c`hGO<<L'%IɳOOceզǽ<2tڑ?ܫ[;d͙YI"~6Yv1eBOY#Kc!(O<<8blY #c0X^Vju"\;`hC"e!AR y>!z}<&FHi[+XD'XW{TW*V-"yႭu Fː.M eMtQ3׿V2f3W8t-۪J_Vm=R.vJ .' ۗ*>p]fSq86cEQn6k:Pҟ[,lH9ǃX"`k,]J\o b86,S8hЛ$/fX|KXah60LB&qFNUyB1gR,9nxUS).ʲ:\ " zc?Y/p=-CV.x)55DPbGot'{jcӹa[eljeא$-WrLDHDiObtp4Ug0w!#`8W `o O㗫 dp^i4,ud!!ktڡlǐ_3^743C,rJr.)Pn?BA/yߠW5?/0+;9,%zUK[|+6 \䋡ǯ.V}[pl|~CShx<, ,z''3Ijl.-u#u;ڶ[mGm&u{p GSZIe;E5kyX*W =ީhMrr}F5RmӖ_;g'܊pl +z 3iiKDf~o|fᦝ\@>ңjI`qXnt:S.۪Ѫxa~0VY#򪖼l[/~Oox'7`v+=E26V7V9SO-߮,\ޡǻu^Zg,wNNڭiD?nA'TM^TaCW?d#=QN^ՖԹgp4\ݷJ"`TeUrN[hN;TMW^Vw׸ GWsÕDfUo^2̼*nY>ݽGUXA7T} ond;EUk5֜XWp_ÕDTk|ljVeIJkz8KЧǏ7) Yb"TUK/޽gp%#﭂p rXn97Iv*yuɋūmu7dgCW =5Ύ NQ7Jk$3zcFe ؓӺP{4Xw_<  [{WAxk0Űp0Q7V9hpv+ YW܌vszQn/G.!Igli,5kE hĢQ"` `^0 )U۴/+8gZ]Z,HnKju[罦{3r<(`,iU\pģ,j #LV!34' Vke}ѦŪoZXpODTnn'u[UPnh0V9Z.y0S6Tk8X4X~}sn] XpOHA7˿weZף=~ZY^ntB[̸MqKbG+:J,x0~kw r=KrQgL)\t#uZ{p0Qd9墆*Hs͢|GC`+RnIdgj2VARrm'YtSC}n.sv+7;/v]`"`H IDAT7gdžrQgpv7$o9,7| C5K7{;k†梽/xw^wW}+"`''@Qkɓ'凃NP{ndT~;W; bշ9\WA$˯Zr}SrQrQwUAgN{s{Hoik`Yp=x?[,Eaw{v-w1U۴U<\:%[p}-C%z"`d>BaC˫Uʍ!`,Dc4*M$dVAw*zX8JY:ǟiS4XWꮣy[Q,@&0x$Ozh-yUkymupWA$[˯!m V4\N۾W pC`!7UZ'n=*hQiym*DǫS U*r,`]T17/4f{Z,3۪ 2,!OڭdX>@A'&=ív(IDsܹ*F1[~SCM"`nݠ?֠?W= V͖wrX>\t"Wn VRР?^kFd6rmP0(D6ߤ4dn Rv+ XzjʆJeCw*8u0viQIoi+xp EXds[Ki)م5 C-BW-Wңېoc~k4.-mn;|SUsvu_v*eq,X۾vU-U{?h4{p*TU,Ty3sϕGA!B*Ì!B.,B!`B!T B!b(XB!C"B !BHP!B*E!R1q;ҽB!#XB!C"BSg#/!g3s*B!RZYB6E/ZaLf.(PU" E"'׺9M-B!r2Ş;XGCp ۭ~?'WFqisD1eH!\>F"Xi$+,~C;,1QSkT6ل.B!bq&g$,-UYʋ=˜(+c"C_W9jtֆm eB܌$8JTRS֦^_d:Y[1=WBym-hl-l6qpMwޝ^֙楄B.F*NӖoɐAݬltDS{ՍQBTb3Q, R6oZDH&7$B!QYxPKk"Mh4vptӅh4vuUC!26*M*,tQ, B biGTeB!`u-k3.(NK!2M}!!BEgrB!\(XB!w:!B. `B!T B!b(XB!C"B !BHP!B*E!R1,B!`B!T B!b(XB!C"B !BHP!B*E!R1,B!`B!T B!b(XB!C"B !BHP!B*E!R1,B!`B!T B!b(XB!C"B !BHP!B*E!R1,B!`B!T B!b(XB!C"B !BHP!B*E!R1,B!`B!TL< f07CVa3E*ZB!gEΝl `@b=n,UdE)T)^B 9wDA( Zq:J E!d2`s'8ZEZ$IQd^"A D(Qi,E9J}ċiFB!ㆂEU2,2m`\b#k."]ifa3xB97(X ~EWct#{cL ,H3Ed|ʑiFB!UC"珸_X-jGA Ld.(#`1zG[Z/^"G! ;SuRU3K1">("k.X>b{1E!t(XQ_eF(XΛ&xf1ƱA\3}q3Qrf1<ꕦiFB!mPȹ#)X GPP إE 1ӌ.Y/F!@"SQ֨R @}6cCjZ6(2j S !\l(XQU6 Ly6cQl7 2H3iF j إLf$d+f eH-X&2^iF$ɐ&L3BȴB"玪Kw8ehEɛf"4La3[I4#!L8,rm&k]]']R5P0Wz\1Hn2P#x9 PU$ I+aݥ#f\]W\ܶO5Ij2$>H"E Vb)E W-n_s1BTxU%VG! 9w1JN QoD+բ+0Gҥ/B 9wBK@XV+kk33EzIg㶔m(OZ/gBEKZ4i\aVcAv$I+ !EB+a1Ҍe Vٌq-B͋L=L=d&?ˬtjB(Xd,XeV}ٌ߮ay Am&v$BqδIѮЭ2H$PX')!I=XzSZTTҕ2 !  j0#dTcI|]Vy61F6jҌ%2x "L1,2T"1@vdʰ>jfAbי6af&ʣ_//#\i)4#!d`1v,RpPzv]Z6WH3YhҼB&  EExO3ѮH\.%R05K^`L3B`^X~mRffb`.><@(o<4#!dP!Sf#EѾ=pxƎ%U$EBEƂk2,8J-!ULjc].XpjoSI! `" iiƙ2"Efb,,c]AZL3BNEJSS;fU=.]ql0745H E",2&L١Loxڙfu\GD+ n?AXKW`O\PXP0EHLJ_ Sku/^soZ~/ohx kO'dV8Jzw.fq}ٌABHYL32P`wr iFG3>Swا.Z-*!dz`"XXrX"Vgc7q6r&IˢH&Yj$L,2Ua\^BZfTcĮڛBh4#!cEƇƣGXIX=q^e"X&t b7xB  "8 iεc lzf``n.\m^5w5L32 (Xd,Xġԝ!,BTe-#םpgcZ8f$h6R)  9 ,2v"$zU8l#Q3ڮzfr5}xBNEBQ.@9;#1skH:f3&.j8riFBڠ`! SfL3κbٹG<87_J7RK16)ӌB"cC"dVqt0V=VYjk\)7MInb )L$P`2U4c >Wڣf#%"@"c#(6"_\MNѻ+na a&r]WfH/6lcB D_\Hi2[ȥtjA:cp<|ǨL>,26DXEe%I,նDgc'aLi  !v]1_ !C"cC- "0,B'[ Vf}9 B Fpb2%L',262kv͍R ~ˁ[.BPi+L+S"d`"ZPi3V`eQ,2}PR q_ !dB0&VbO邂EFYnd!FA")BBH '島_bel S,sEq$,B=4"nh"5J(XdlXߦM!$Vơkٰdz'##a,B[XN6fb\:3K#d (Xdld-jWGW؝L,26"Ư!E*R ēEF`Ear"I+n(d2PȘYBʼ8@p,BEF)D86,BHѢڮpt yi BХMC/ٲL6,2VDrɻw)rlmA8.`e>'J = X? X]c-\(Xd 7rQ8p"A&fB =w/rZZd2PX )BJ4Pxtbw2Sk]vf&n;k!ieFXZ20,B!Sɋ ɃEƊ͔E> 3G4Bjd)X\z-rd!0E&~Yu >2/ܸE"{&8@OaQH& +I+DPa!bVvx~MF@"c%W TN'[ ʕ룸4BE s0<{ Xd2`Yl@MC~6YٲLT#c%KC,B.;æ+W+2BEƋJW3+vلdPXR[b!,EX$cC"cE k!҃e?ܸ4!/T#ㅥW yYf1+q_PXIۊ ! ,o“xFx`A\jB.3U3}<2vB T)XF#ײ1A"V !ıuvyE$T&+sI PرE,Ӌ' r'ثR=gq̸/\2(Xdalf՚BΛSgn2E ;!EXND|#\\¿CU<~ B"S˨"XF ; MIP2 UN"Ƴ'nJ"G< \==KVzBF|qlXZaLHXs9^!drU0k<ʖ 传`/l PH=;-}Y-J!O!V1; =,2vZ-)~SPh4Z&M-֟^(=,2̱hU*[}VJ!Б>!a"t; YZUVF6d]c!=!~ { .歫yDQ;ijZ#h #] Ϩbw"#,2vEPyD ?hH!16 e67 3X^6[6(ykWA0ExYRNF #XdS)KeuVcwJXe\&Fjg;x"Vo#M옐*a⨲1G]եlRB͎! #|.$  Fd+Ӗ>{B@ڥʈz@"T",/AK1q> 8"X.|_[`ʡ`BPEku;.tC}r?U[ת$Q00P"',\ʪZ+Ph5 gO/_Y\]^\O.6,2P:]ǽWtMp}*`]HT( 0"PXNTǻHm@#p_6ïo?]Xk3M,=gGvKxE|~~rq` Kq\Z}YfPCu9MCkT)2|%m&* |pbf+>=~FXdB`ED TF\J[} b!V`w^@MQ&'`>%[6ʠ`dZf8 UfRk_@Pj0H󅴠&/P5@ Geu s*Uh6\ܜY)G/U"n16K+0l"kM Ƹbqb֝jUFZ-"ru2淹_K)~{%?g2 |~+sxE  bv;frrz<9 tu^5!N7"['Vpc|BxAk,D]1 ˒f\+gx^ܠ.ʕbj?ᤰs1n^/\(Xd"pu5NQVy]ҋ'IW4`hk_ qWgsXhr1%/F>-1 T/Q!jf|d?h :@ĶE$|{o *|uiBb"/cHۯ/RH%PDfmR(ZÞK{VF.ʋ}g+\ҟ<]P R)RR$˗R{;X4+G!^f4Bj]`?ryE˥ul)BO:ٹtlB.,2;ql\yx1Eh8΋7۶G^dFS X]K;)K}+l!0y,[u2.ZB cq35EquU^W#Υ, >í; xXL?,2|ULXT~;*YUw~UuR^G!WVX6W] f"Q*S> JGЙ<Ҋ ݍ \5u3 ;^? O`Z@Ea^sGk   ޱ)-7hrQ=,K?' L/N/(]F̷d2RCK_}JCݲ)*>](&fu[1H$4cw<nYG{c2PDP`u"/ӇSQG,nRE|Ѓ.G?*a?BaT|k"j-sYX IDATZ03Q+L!%hQZoFC[5_ 9f/~Kqi(.VVp 9,2<|k ^( Ef4UJ9Y{T};ǥT#>".W6~WK7v zk`q5O>%P5ڸ`:}w)$kRX?@*kXYdd@ XoF4xyvm_B'lhnUhŏo٠BvUhB *9Ժ 3`-x*5}K|ᾓosW&)}w*]``/q+XX#x nܺst`M^:3ր~7O˔P;TN&u} u]nlIħ|h?5Ş.*nܺq_B(Xd"H _+xqsI8XXcakJ!]!SxҦJHվz_߹ ja_+PGcR W@*e}RW %KEx!,^hɚ$bnrw.⣿%)E&$qP侾#XIb]WW Ku,Ա:|~ Nӥ_6³)3ꙇFy:Lh:'oc5 :O:şŨ +1_e ]b/sҥ>=ɚ!|nr_`` EǛ l648zuUpVf4&]޴摮ib6uNs*{Ĭzj+2?ہ/Xw# quY`䑬"toHv؃\ {=cai__ēw}Idʠ`!CKu,,ֱz  ]õsx2WR'u8:.fruZa;{G}#'q"yD|Bɿu"E.&-:X|ud&I^>ŗ6.QPD&ڵ <0?7,X6:]wŹnܺ t|qvwxG#-7(VD֐"ZGʱY%+=߄Q[ڇ' _eiA"A"Ŧn}`}'&\KZcѿz vwiC4{sQ:.hW7zlom/v,m^BGAXZB71i3;y.{?~6!SL:W-Zet5hY~c Kuװ+HWzݝ&v^6Ⱝ5:4]uZUVY+ǶWƥPk:͒e[&'&S~7ZWL^EiP3J Mc']W\Vfqmm oE/_bK-4ڤkfVsTPR7H?owwAjɚd?[ >dkܗD K5lX#[X`<ͺbYj7o][ŇaRnÍ)-70SK9FqPQnvc*wZS7p?[ x (Xo(XdbHf2bfUC(IW<(^Y.xJ[=|-ombw#lni5Ń8 nP| u1pcpq_eQIC4O}Id `!I`NU>Z=NlvlKKu,]9])]{MlYkNUchuyxɔ`^˿|[``!M2`.F\0nuiVG&&'^Ӌs5\>k$Nv\C4E(u|NZ/<35 )Bx`_X>ť:vٲL IB5$̆\< FbqX\ vzˍC|G⚧[z?fI2.",.-㽟rȄC"[.g8 Lh\=W<9~>B=ʵY,,ױ67Eyۭ?-88tƩEv8U<+l#Xɇ/q%ܹD"B"CV_g.B=W(W-VԢxp{tn7g^uDՋV82*1UL6kx|1gPPn6*z3ςIȵ5`qyk7µRJ=$ɰ#8.B/)G!ZAR*B&{'7[,r",21VgzRfJpoh9Z`qEVjkX]ǛX^y*Gu/u|7uayXJ״֟ȷlX]`H_KVq;o԰q"+ cX\VpUܼuwR; i_ \x+kx(X',21tF:hu}t%gIֲr7^Vt:\=N[ lnvTS>l:DL,jI}ZwNg?>_Y'&D.,2uR>Dg3*` "00{"Fj=ї~ `qi+Fxz.8vIĈV*RHWXXQl_ {:rR%/OˋX9qRUT*D`ĺL(2B `b^ &\Ml\f{y.Z{qay-=&Ot=;w;+, ʳwE a3ja 6B} NJ ~/[]t P D `jŋ`lL`#4_J۬P+P4E=\Lz.h $HW"C"Cҭkj۽u*omT1US#Xn (|,B\ v(.U8Ang Ѐ WYk=BF"U~桸!g]y{,r $պ_@ê r>d*ZDp&"SCċ>Je|JQ.q; N !-ZDj`qW~3|/n/g.ڻ)j>4E:>K! h3 V7F-]O$ QHPt&w>z߃2SXk]TyTHEA|JЧXuV<: Lc`\ ]-;Y!kp0I5`P)O>+1k_{C4f.z,5ғD:ΫNk 'C΋gxܽL"mPĐ`hp Eq`;zcZ(N$O +j-ӅN$+"X!~ 5/|y>Qz/~/ϛGM+~ȶ.Z灜yX9gO>ě %tB"CkХra{yFrW괨WĪ+Mx,H]QT+W'[T B/cC)X`XV&0L ܔ0?wFfpuZSԿ.MQejE9?hR Og ;xf$X/rF!ɡ`e jyrR_gӤY}ˈ0fu3O娕 L ]Aȼtl=/k9+x?׿nNR=l-Zv3'ѰKWqE ɡ`"M,lFA9?僣􏩢쥏<_e*ǿAUw.lI(Tf f0^r{_?biyH6U1O߇}=_'lxts *:2a-Iy1w}ˆb/L,2ULh=in"a^ԡ\~X*]}-)%su[&/L}2@MH/ l}f6 1.UXvY/hCZ jujk}>x.z.']ojzA y}ڦdyp_MU @"FV\3@~.ZRyZ|餱ھ/ }w^9s1#"2庿Pke3׀ԋ/ (Et t"8),`M;вaw-0\ָ~`G0"z?~|k.-Zxy֟ݯfvsܗD LIˢ>f;TրWǷאl;AojGmVť*]3MG}JO}yBvKtb8Z Z`V _G;@ko {BǏ\+Y_MQ\;k"Ek[. 7fZ6}IdPD Eҁd>:W҃=m Y(G1vΌ |{UDJLnk#`}$O6t$εd)_7RXK@D{=V'[)+WoYks㰯zޢU~OgE| )*6|gw.me%E&,} T&Z ػ: v޶UgLni`":H{^uY&Ļ|q,#[y)ƥTܮȝ *0̡K{(!WhRV@QMQ;빊\WjMhSV50[6yc ~5K"cE.$ !Z>j!^uW[ VѺU#[@ R(:wU'V0.7؇H "#ث#t G<`}"WkٱՋV}6SUwIF\$ LaoP];Sn~] 9 `Y(|DK|8) D.#ح!_.Ƿ^ȼDAKB۶ ȧ0v 5!YZg~gnItIIWQza>ڊ:4֘D+ 16[`]b(Xdh\{}f&}025U҃r,zUJv^ x[aAh̞} =".FPSJ#Z H(b7Xh!6l2d)jI"aBEX t3#Y._C'Z w}u3hyVhmrVhO?»_YGɸ/ (N*rt*wRu۱Ӟ{Vݱ 87K!dAJPߢR4K.(A$L%|_!ZIN\/"YWDdI: E\Y r#C&+~=G ~kQ5^.*ѿsgU=T]갚~`w.we%E&jN 41a]1\iQ!f>/ochR7n=AWja0ɋЬ΂ cQY(3EPKVh^$ d#%K|(Ԫ'.5kAO*2=:^5LSOQ͐-c|c!4Lhu6]KK Li>[TG%Z7t?.*W}0Ȗ_J $ zQS^a DA|Z12:z3|͖X'Phˆ˹2-:.Y%T o D\j{s7g1 ") u^QS 3]m?p$+O[]ǝKx`gܗD (E8w5W\4dWީD⚏4+{Ɗ6*(|pۨҎA\RպX.Y~"Bgj_<"y VPfsTVPUnfkN~>}8ocumo{u `"j[*7q"eUpitP>a_JGm]2b`5$Xbf*bc`Ejaa ,iC/B ZcckN4 T~V$/YxH}d)>4#R,~/,emԸQd0DEl"XUQ(?{YvВQlk 8XozVy|iuZ'B#Q]Pa!Q~3 ^_D+uwu롞Kf5tGC]ՕN:r 傂E&V7{UAcP"Bulx}C qmEN Ítb-2c`2DPfY ʭ=F]ƵX4-l M:Umi67qX\+EXzEC{Mev.w+ +ruumk(~ +Z>_YWٲA"Ɂ҇h=tUg`wVҁ>E<< ɾS#ZIb w-6*8;(XdL8VYrd,"0x:=+ni63~aص]7z @ ApGjU4&aLi",-fBV]mT7 vKB}Ma薬)M&^H} +-:DK ;SnZ+OIghZ'E\P|׺o rWK6:G E=0MQs 3uxym|7q2@"G:kJ v9? =#qbj1xZBL}~U.Yʇ5mo/Xb#kNJLS,K'+}*FZZF'oRU͜<@,\La_|n,ψD+hu8q\z.\6E|aG7kІ[Uу빜n7O?L5,2}t|H'Z>|xTNH>qK"KNہ3 }wʷDLť܌q$뾳J.CK }-َ~'Y^Śu ʒdYmyv2&\+JUvj3R^:E}(o)R<|Q}7Y_\ş'L& 8ԢЪMIw_-EFynυLۉrUl  J :*um\ByW"qh^w6+f8BqtbYdȕ@,`C;5Udjo&y8 [Vts/)Et>]7Ўz{7PMQ.FzpoV3HSTC"G և`& ^TtC7qPtJ+gwE2XĥYR H_b26sth IE&a#06j0էI%ZqJ R.X&o Y[*8/&؁ %&*珤XۥJLon?,{ )Z{g^_FCp(x6qKSzus㰨zfNYuUn@Pđ&P5A?LxtݯuY"L/QOwI rѶgf<6DBѻƤTYW JQʨpFiŲdQ@A%LQe3d&l5"kaP=X-"n(Ed ~Ȃ}$YS_ދKk5ZJ =vU"/V4E6^uBSv:]Θ %~)wlSY7dˆ럿?+}KkTSXpk/]xpka< jӏ;+{o? SL,W>E^e&]z) (J/|tZbVh""'0Łؐ@"smK6P A `ԧ"kh]+P+0a~,YR`J^%@,m V< $xͯN{AHD+D5;F\ӽ:)>xXzpMQtU/[eÝKxglp`#I-85L_HRTa勐\(/K p• ꃞa*BSOS Uن:O)5-]H\+ Bxˆqe$+oX4;31Zc"X2=s|}a(!fQjcyZt!W.gK#~qx/h?hÉ sa=z2^fB2hST&A+a6<[6\P(XdQ_sSU$ 8? k鷆ֱN~e0H9:%=>Ԇn_F۾kT,uEQ7P”Dߘ4 qJTElH u|P b$Q$ɬpB1BqVGA')V!v|/_Q x _i0|~GG!Ze?3 uԃX]{ LjMB)^1U_/E`svߩsfK] _׶]vEKZX!A2QГ`1jbA}fNZA޿ JK`7B%_B'JTwTwD;@|B w~oKKV1ވZj3\g3րÞdOGBT뤦f >wxu`M/vEa]<(4H4j"Z~oO1'm=N /ܺkYX,tI !.5窵3/kQXEw²9EQZ e~)P.0)f=f!WPIX' u) OZ?Ug_[?{,Ir\Ȭ<03=x vmL2=Mf)_dZ}Z$rIKoTIoάȈ{'oev]-kFdHJ >娨>Cjnj@K|_Z Kw4MЂӮpKD`r]tH0`U&Ȁ3 x@ !_] ܥ PH X0 Uy]TLR*+f `AF A@Ɵ X1Ze/]U[O o]Z_ _cwCUs͉Kbg ZloM,# HpGi hijmRM OQJ[Lppq5%VHC6,!I#a -бAB $*L#QK\A"*14@HZj.ϭACq/+X,w&5d? 쿹P6-?~sW=0:y | \"bN/ib_-k3w"T+ }bdУ뙷Z?G^+m)R L0Fޙƅ{1Kz-"`Q5vdF42FNHcH<"1CR3RY"`fI,@k)~k="HЭ^G!%N`eKaS{ ,&`/{G%F^oE.YbEv=2 .Z`-6 \ 9"ήBd_p7 !jĽ="FY1٪x ێɸjdWtӊ ժȈ,]aXD90ZQc 14@jBDH$Q S/V Y,TqABE(%O :*5#%eFQ&Gg0Y}AJBJzL(L0[tNz-y2RQ D ^W,AOw~o1>s#j7nerױV6) +H."M _߿7g%>B|Z(Y23\҂Rjk%Vew>%rj}Je ]icL ))ŀOq2ן-a8d݂b*g@6* s!jL]7 Ϗ.ziח[7fv9w^doz +`&[\ lp`P s9}Tb QBןz*E醱P݅ӋMXܠX-UEƝ2YU8\Q\0] =![ΆeFC%L w @EdC\GӔ Ī3AlW^ 0{%LJ`DymS㲳{JWVӤJG~w~G`~וl1koo]{2r@z [MKkFZaAY9A0I^85H`AMQ='̈ x Q{q ~_E5\^9fŝy `7FAJẠijX%"R"%!tB$'@7ASdv9jli[(No!KWP+pig- l/v"\l/G\ɺYIH&6JnW1ZNtS]bfSqݾ?O)-Y3ASMʕIY84u\cZMnGzoڳ s ֮BXк Fs&q8q@i؀l |݂$к Y3$n܍"ZD,+VP\yJ@ij^fΟB 2:+'f.Y]7C/ulXM/PYPI]{]E"0XP$ ]^Øm`Kuۓz.hNrSFS/Oo ͌bda/J H#0H-]Ee<+wh97@+ S.(,Ar 1LA\9S}kS9l57KL |,Y);߿{qe3 _RPܗ<b{obXcS&uZ 4֞v]zޠHC^'Cwe-*qe\2E !gcJUqéyUgs Dz7R>c dw}Ivk]{,}ʻNպXk2 @7`(mbUBT5nB`?c<_ic_ë hM J KNV,&+?<=SVr<E'kpO4-94f.Ȫ,p.lR Is2U5P*I^$` \J*TJ؃[qQbi{i*gנ[ OƲZ^\;[vUN,@ vҺ Elՠ8㯐cݘѪU"c/K R@@҄$u V1VM!jߙoU]`+ТMÃr;8Є*xI^7[bpM̔ d9Y(1Z[N{tG{Uv g L v(,C4şA [`B6՜RP&> f.zjUvYm)>p&3j__Yi@I 4pI Kcj" `M^]u{(h@VvS$"s :[UVX,84ckoʶPɗt#Zbn-kp*p[p=6( raJ_ IXS'Ҙ' =>`䋙0(*PywX|<;L) ~ Ф*o59""\SHsƑ scJ|%_T!D|D]Q@!Ϟ!Ox0 dB0h_5$e&K&Z/WFBiSHDY&d}<CZ& ̠ ݹskޗ<]8UP,Y9Y+{lU]`e x^qz_ܜz_:_E0Xkq$͚Ь1*3YV^dRms`5leLf0R,VqB>! {"BERM+ݗDkxyw~r{:^:'㴭&^fLCVcl8c@)T1 0UgF]5q";Vdq~ ǟ!=oekwV}qWm( @4;r:(1Y+?axlkh(ϱ`>[be0-@Uavy w,nۙ!N`I`KLIho W:xqZ~j 9ƳM[4 36h㺨Tt-d b6 *TS05W$ViuWԞ݃cqgq]YZJğHl-@qڧ.`nBOM_%sɰfO'rk}-vjK;X U2h}|TuM ]@7}\@ކ4Bϟ`!mo} mՖ_I*Z9㹊Ybd8x}.FK%ŀj! Բ6VcOXQ@~h:Ȃ#nu*d+ "Qʲ pA}gK?WʫH.=h-vlZloF~*TܱѤYrxxєM;g_X"e1ݔ#h1QWMMi%oXRH Dg-Cz@+Т(iĹ|MLVqOwu ~C$ lXrf X/=0! .P0Jv C@X]vF@%N[!@܃ _I8e!,Y H@ >[@ 3($\F9{ rb2djBJEOfY] p%f<5t ;H 1L?+1bztqǟ|[!v+!Oo\d3MŁm߄qDmZloiX'|xLם-Q`3w? p؛z:")I)snaV}7 k!y<=T QoTO#`V_\R|.ѐ.O8RЬ4d . *R r7 Vw.B:F"jzI5*B"B]onWЙ}k{2r QA|5U׍o^W0XZ.,ȚP[ e JɵVj$$s0權4=[]RϪmj7od Ll]9IVyUð*ܾ<p*wePQ簰lΎ}cڍ5h܃(NY+"BR"{Jo?DzQ$!&'pC~e%\;G>]撒Hu-D AV 0dSVj7YTMv yP1X\˃ݕŪ$wYG˕h  JjY,/ja[~":"AA٫#BbUẄ_}dD3b"4 q99kfnҮ+` r^3P/Z6j P5 3,/ $? })qO#5Xa3\@W~BЉ3K2B,Gi;<2P V>^CV1?Jf& QyUtH~n, }_p@zar ^Bd((eWXT?_݋]Vr13Y`i@:2 +sÉ~>4b Àq|oƵUeb{k"W:*;~T/,ٲKJYa@mF F=?ഊ)`'J$^k0BD@_TM RXgjFk֍$; BEk*t! &Jwd.t Cn@Yv]ΐrJgVHc$D )F)Eik ! @x*vR K< > 08t+oʖ m Z*[u[fbfZ?*:i?@'"vy9\r f#gb}f]Q2ԔG5lݏvU2#3wN{3FՐ=i dy $Q[f2{%* JjSv#ȟ +:x+N<,SXuWzYsov[uy*!{0`lVQuB]ȒD|˷xTJt?CW-CvWZm ZloQr1Yeu⴦ +KaĨ3ۖa-ʁ{޻pB#w丹rl(z`TrsO٬xpPϙv@KvoBjvjIuRW)+FE7d =ٓ24m2QMH"{H lR.|~k%2) F3gA9\ʡ#(e?| , Vqid\ 媮q^U_K mEkmbO@=θf|e]*w r@ְ<-½o?YƖemv|NoR.*j$BwxqrTW;M[}Gy#8Ț:n*7T{^گK٭p!@¸se0(.RPw-9dTHF1%DKgH(nKqH > 4~E 0zZ ! D HH1Y)F] d ]@,6@;~?̰ۘpmlo`F[b{mWeo@ z$+'0@Ҡ.aYCdIںK\@AyVPf&VV' 3Y CH @Yv?0` t, tJMuPZPbx1̹ jr0d7& 7-z Ȕ]UY (v*4iG:}a^j:vP~Y{mRF`Cc.4 b4 i <9 &ˀOϜƍcx-UG P`w>-c KMBE R/MAN ʯAea 45i} 2q@YqSe=\9+;R61`4Œ0&s*T P)* +}"HZd㶲pTIs |?FK%JQ uE}QY,PW妮35ثWܒ^-k6g&E+9e땅do(/[}0 #{o/Yg҈q`E~mo~:9BwhiDa0rτɪd57M?UʶSn#aF2@ ŏ)JqeFRc-FjA,mgR~N`z"d9x2[5f GWrO0X`ӗX 1 ͋ Vr3%kۜ믻 N7,$=Pk,l@7~N) s Ùλ7C%\qr/fЁrV SP, +0jE K)oв? 2f9 LSHY-hȀ)HRd1&SbCFD8KAdOo̞ۮ"Y?旴mچMuT3̩zAŒ O^a7xgJ5j< %fj9QD 'ƟIS˗wB  +̬CU|xAG'8:>ifrw,)&PgNgs^uXK\{WJH/`x#lCd~sխdyf]* GVYY-uGdva͛2,#'%B(^wrZ:zhi,lq.׶>/A̬})Vctb\HVC ?iaWjCPWsg]zq[H 8bo.>uAHcʱX櫳]Ƅ?f%$ߪ ~%)ɇń[,)5oܔ0}|rٳz/*UV.JNW2v"צ45YHs>.M-"tv:7ʬ^B Ҡs"CȀk/-(& #=~/ @׃Fk?@W~+?TfM;-c%ka~zqΊg/?Gѕؽ=` ^[Lu}/~_k4Mu=*&k^evb\hϹ,13Y;wA'bccy1Z 1j8KKS0T,'jT\]5gUL@Yz*eSxpbBۉu4jE^GZ\vPeN({"@: U?Fd-&=R$DbTB+,>w!"NNH e  hRu`.Vrd$dDJl aM۱Ebhl Zl%| |_0 Y8P@V#P)l5xA9Ds Z c0 ! z%ÖXZye2ȚXkN%n51 3he̕7d +땑^jRpPc ++Yh` ӌ9NX)HACq Z(\|ZvGT48tsjeMC?|Na  5k1n$_!)U %ksѣCaI6)0.J"eYU%9UxAUʂP٣ 朔nWGGXiL}o)GY~jU k+*ׁ\O)R3L*Ci~\@V! d5`B3UWUVٶ(QU-&h.^` {uI j[-̚5 n6ͦ r?9+ E4j ;Gs2PW 8`<`fm ' `-ז,r'}/t, ">N;>b_k8L,;e:XuR[L`tRW_-HmBdb@2C$YA[CxZ><@l0<{  JH4ǁ M%no{,׷=ݭ(ccĮNOɒ~hTrӱLPYw 0"ѐDXr&fmk€4kn+$B4 ,6ELi d!&0%0" #pq>Uט1ZhY @xDd! G0 my{?+:X u[maks+vEjgg8;;|+-eWWײQ7`w时F0\Yf5Qa"%BD\ПZ<̐$3yk&+[.Җdy9HV_T܀TNJmc3}?+ TQV[6Ljx!%~JJڛ$+:{PK03Y6fXy# vK{QVa!R]GdJ&I,eM@]ߩ+B:\]s$ qR*kr[˪X&olt*Vvۋ rkLJp)\J/eavWG"LR~X%8ᵮ|2 q E Ku+P !opڿV6u?2;Zd<^[u]·tǘ1`5 gX?7o,̓N"GhdI}m+LVm!5w #NVň47dV1`5UDr>&U XtsU35nVPS9̈́]ךh/,ς=. R:̊wgxeX{Ӳ<5cs(mp*cI׸YEA,FPU!TTcqqhֲvkcO?y?D"!vd_ ޵%ͮVV3XCijLOzp|Of~)?bDBEa bŁO 8B(ie#@[r" ,\J\Ȯa }uKx?w`+U%)B+r {'Ŋԗj wRBT4F"E$ R& _pHig2o~#zڎ~}.$2CD&8( kTܫn¾Ω/+tf?+m Zlm]ЯzBDLËj 2m+;gdU疲:^?/ Q 1޻FUCf.u s9Qn  :a;J¤?:@0>MբP +;lG9pDr8le޺yze,I&L ս2cĨ.y)32Ev:M [4,ПIAegp QA[y QW>d4@sD .@D`Z`b0ثW?Fՙ82o^WkޛO*( @!f١O1/ɶ;;٬skeڞ'fSPaEJQg!Y)Ͷ*YNe9]G! CY+V 8=q m$H\HW /Tn xWy /`TMp Dmi ~4~n⮏*ֳJ_g^7ɑQm\#+FdX "爤 #t/V|P%`UسDU^]yPڱ.'!;#R%OoC%e Ie=dmk=  !Y\4_۞&ގy}uM}t:H@a<:UNWdmWܒ^- b{ofq43sBX!DJ6|_ۿW>棟 iyxb$oC*ȢPWT]SDqYbFQC5&?0!98ϥ蛊igI}[>Fz-[5 13ej:[5U3۟^DyJ2itО$fu"-rv! % #D#d yc-$\\ 悃,aa{ *CYگQ]V@Y3g{uEKsG:Dw|z5\v%a Zl]#655_0Z b{-Ys7s$O(L׃ӧeb5 Q"KS@D!3EZ ]׺fAV@Zo;]7Wאr $VGBXݹٍac=rV'^n Te㱕qT|TJau Dp0ʢ@ ^ZB,g"9P\SJ3SBP,6jA 4&Z6OWQݻ=MAV%VwZ#:7E=כ}-.D0nK(tߌ4ZbYe/:twV: pYNE<}Kӏj96Bx~.Eup< umXo&愔6ܞqO`17=[uч˖IudUwYMVh>xx @N4N C= ct!O24@!PPEA]r>床FV0f}X*W@Z'@ |ՃboWwVN\w{0Uú=x5["0* |2ⲬM;K=VV͠ʷbA@Y0YV+OhBp3iDJܬͬŒ##o&>PC㮺Y7$@xrƒuw td}^L~U@  @Fmt);TAd%6',2 R`Yduw@J(96MDTHu!$4& ,aA,.K{`FK&v>R2j, ˨g\08eƦ#vgO݃pt9K `-"xG?y;@ AW{;~^he.&cz͇!99؊o~/ T69ȢUj&+ZD5@-jEXͭ6heu_Y~*@MfC5&< *jw_%W.?Tԩid fq RKΔT k4Qo`/`]֛sH1 - "4zmXm,[~*Qk.7FJ#B$8Ð찋̙NX os">l57lS5UT^&0`IsP|,)Rd/ Y ՘̾?:=SZUSgCa2 rجd PbjDhUu G ZעdJH:)`urͳ ]8ן;@֮ϝdI \ VLAI5ZDŽނW0KPTG ELUДI@6 !fwcFaV:. .b3:cDPpBJ!Qn:l"\lmLEq[K…4nkla9f o=:⯉- _[Ҩ+vۿdX\)DP ӭa썲:LG~d T(S2n})s"B IDATV}@!tXuG [H'BJp^@Xg,妜 Ay n!,Vg_dפ_3)x:rF?93JKf)AkL=ǩCgTρT1 @T *2Fh9{l0aǑpDd= "H$R@NFeEGXE#*:la,ev F)~~%~}la{X??`$}ٯS? .о[uH]cƆ bаSޏUV>x5 ,hw$}{8Ympܝ〞ƨ/L+"`W/lQ z7a$.Ga Yu'F@|RSkk _yvORP Q(:VPߏ0f iErr(¢PcpV/ z]O ĐHI3fHx$%j;7<Rw>|/jt-隌>_. `-6&??R x6s{/uo>iDJio~ a}rj`bT#D@o#Hg쮓kB0F烪|y9HAb(q5@s2S0p/ '4$I|k5"8Mr@&HY'B^};p47(gfID(p:܊p޻=[R]~9guZ*@G D uK{q?8ov#qnun B7Z$n{Kf΋Ɯ3Z{׮(5E+s̙*o|#/,κhbj] BUH U&lRW׾[ hSc8;:E}=,!ՈexgsbzBZS.'Ji 0^D Fo!Ϡ, LTq$B,}; *x]J$-)M'i[9ڭ QSK@(PnlL뛲qiIi2ݧU%Ku2]K; [T xnG.`GSN{TLBktS2JC;pk}\٭d _KSa+GxgZ~pb 4X)N]EPPJ|LR/]BVfqҢojDgR\>^sL"#"—d! 5*aE2̺).FAdݵ hЂhBЖ Fx7ZEYr 7c>d9Y8f]ZxX;<'~JHZ@pZGCcpxQ8P^)x>WCV@j3q %Y UkbGy/}*][JQh-ڹؚo^{n=T&{o|g:Eu\AhmC_?=7QS,,4JE]/kO݇./75&{*SzLMTv)U)4FaR종#oj Zq8V%Fuv>Րex-DHsɶdwnJBi:} tmu|VkW dX(z+OumsS?DU&FUVjBW[09x#lxk5ZǾX*{h 1if8W1M`~:DL-x VKu +prýuU Pip 4)b5F!Z) LiZe`.ᬌCYQN],=O荷B1{lG:ҲeL:6m~NoX94 YJY%ܮO=;~w'x7 4nw:;U^"vSojCX+ ~e [GPcoj.)$@fir@ٓ:FgylR 3P V9A)|Р]^ GdJȢ!j Z)F b}"+N˶vz/DjaNhGq{)~TNMy?,V# VjDmJ+ ׁ_Yiy{w0ޞ%}kwu+ .0(F +p NFc)9@钕0^ф-@}p}t?PW s* PG6 Hj0L | }mjMM3x[˩€6c.?yT+7|4aWGhAVhde nHSț?wFm Ղ$/^c:@K;Z bYm#"yq"YW ֻ=k"$S+s?Ah͗=3OKnu-ºQUAS}7r#q]^~gA >}P )3KxE,B+y%&%rˆ2 YZ0lhId-y+郩>J23Y9#a:?.NnX&:@:GmVĒ5R68KZ웅a2[+ZlU6,l#{P\͵bLϵC%>e9=:{ CrxYaZ $buTAK(>d>V ˊ-w6:{+ͯnȢ91?ַ?@T C׻;1qC'U_k}n"7^r{u1%!x h0F8WUndƪPBLioq˽70c1VA[bluVD;s)$6+Gd@N]AV߼ty(ƇwNuWDQ|wsDZVܑs+@-؁d'WYsE˅ZžS1iIkmkH*M<|js;OvnQP׻w_wAZWX`c_D",VE67o`qSc6c?~ka45UE6#1Y;ST?YA@&i! *5M> |{bzXeZ8DCiFXco¼>3M أ.2(R2cڱXZ^zsi?9Otvxzmά8JI:ñtsM`'Vo cDSIǥ{0ކ.ڈYq8^ָM'k1+NWJ(ĹZɕš}Z VuxOMIJh;?s5lt:+Ua[߮bx)bh5A_YeNL֮|gv+G:IXy'*ҝ]GmF.='95XzR)Z7,{,Kf,:0=mڱQ X/n;Qbbi=ՠGk8jN4o~I]I-V:EX|U*DPһP+]}*<54vNj-؇z) b$Z_*&om= &CY[O)ZQl؂5oaRFsEJLR KSYDz'ȑߧ:8RpaRE܊c +U |d6z,Dz@'=w{|%Flh]8 NCCmsvΡŮH)aduVL\xtBXe &+)u싰^t,c JIgDѻ h)ނ_~ CbO:v' 'd%zi@x_y= ŀhN0 ,cy3Z $A𥳐 A{V^J.9t<7b-wBj`,@JҏypzdoΕibf6eR;B\-^xߵ#BtHf^i (ڵbwJ0 ߑ!!h>`!ýSlWTҡф9j!hS#Vo[Dg9я6 Z6=Y2$V)Ξa:{dFڥKWR)vYi* %Hk|Lz1 ci%3P;2f"xouSoZk 5}.K愇s !x̫)lc!FۺSR08yו*>H| 8q9WyS )Ez` ` 6a~*>#-Aݹo=}'B9}gyN)O9LFWݻW~ͶwHA[.X KǴQ ^!wϦ1L2YoYwAU*xp-K,{"(i8׿Ewi=XuHFNC<AVΥb0+4w[LC$<64T2)[)E2H;ke 6+,HE1eJ_l G?|CDwTLz̧g{zXC9,Dn@JO-2lYhL3ujy$ I^z1Z V&沈?fSwLuYDvK!mf*߂ `=!U@ZK{oSۡmhBayjg]HoQvTZ~b ֱ/YII|)[o]ߪ>8kmG,JkFqdӦ}PgΜ9sϿ;!O̴\O$Y S.jlCZXL8#胬I|m S Q烊kAVL!h/ɐ|(#.*cDA{6Ȉ90>T[ S2 j]jIݶ`k}mYa0Yx3?~6:˄Fkͱ[Ra,+F\#P-~EVg1uZkLy<(cro~Û7uR&^a07;^fSWD++QV=v*ֲXR k).y! Z'Es@g 㥭 ߪʋK]Yd"Gib!vBb `30rLYm}mC v[_ hulKk:_A|oWK{Ǹ9s-6si]mSS__:C86sfLg[u7JQhLZKő>\7'PhX^eiēKÙks)`EE=-ZZF'"3rD1F3C$N!CZ@ udk(uׁRߵk]:e:]\?^z;w }pUƔ^0J&g-fN̸{WܳS*AR>Xފu=؉,+x}UM9gRUu@kŽԳg:2HiMU.A߮{s탛o`-t-T-D}1xB߽LEٙBha6͡hhA qmCsJ}2:MHU6l/#;Cc4:V&1 QafϯxNʷ)̠emwH?DMYB{0?.]Y-?>}c57w5ncȀ[a(Є`)1rc'VfSwڥYg{to;Xl*gRW#Ux9:tvk`chMQbL<|L]wM<u~"BEQ43&--x^)=gvQ6̦Eş//B"vѓ9+lz?/x/ B8 6 !mϱPqL5Vbcx΋G :N!r?Vߕ>C S^+A9qPj]4+x^1*znIxLil`Z4_hr>zUXXu/ԏpoᝥ" 4Mt:,}v0$Q{ uKZS (l/z ]áGy$%bk0c:r\b8x3⍗} *2v h(P'::dvljdx~}fN]O8iNǝoGAԠ'BSAP[h/JkCJ!*Ziƣ8|vh9o=S]vSXi%{NG .J`y| Br;;0ǸC` Ń0/p Z+?'~htYOKNq]}]:M$,q9z>^xYkwњtH"4ͬ5 Nz&1FRdVγTYX'8ʁb0,P]kÀ÷{?]ea+`/N=o 7 AC=`S) XD@&f-*HB =`tld5VW Ӿ -K޸a1kRA E8} 4Cäv8E=cqހ4A B6Ȓ41F{?t |k} >ZD6 c473J=e`]Exc`cDj)^h^}}{p'̫T>\9J<‡>0CXP p ]*#c6;/mp_옘hR_ %pDZ3X' :M)UD]CNDvhd{k2}a{i@kSE JC>f0zR }ׯͱ͌"+(h^q!rG}K8ї3ҸK酶DNؚ `L PJi/Qib[ Rq^^+&O_MuۉhOX=n6o $JhєA;i|dA8<4ZV?]Cڡ@K1bXI;# `Ho(K(/uԾ["b8[X3X7am[Z_}$Ai0F\*Zuݲ WgB̦ۜp45u5Yd2OzWMa-X-N]Wag?/*i&".Hz Gغw L+#9 RZ,eLnY!^kG! #~z,q`O_d0@Pho E;V\g5FA;2X+ uyﰮ j;Nlo4 \4XkZfֱogӰ@aIZG` !(0x,| ϧq13p}YgHvWjjS[_`Ia-ze>cr? 5Z]? %6xZ0%cZNFH b PʁUCC:(6F,]jyc\Z.i2TK|@ckьT,%Rz 9/oN):$ޣ\C'O$ }_bwӌFlO.b\t4&>_`ƚZǾTY(!Smu=g6_+T6͌ih9!\|zy`[NVT|[#fLٮV r|gy FKyQ4[;UgH_δ*#K\>[lWXye|.Y ˱.jy+lTck|1MhjkӐXFA|O=֧HE+BWe4X!\ ,여땆xULS 6E3XMN2k}4[ ΰvdV5io\N[޻hvD{)u#6oҊYZ \&L2])_YZ)EE?VJÅw߳x_~"_P|#;m_:U{O*TQ)BBXICPAs6p_:W YOΜV_! Ԉ9 :' =6+2;%P1X.h [q?.ч;|=ktz*(bzp]Axb"\Ǿd4Li%l6@QPWhURs\^!*/4Zͳ@j }{^|{Vi_g_ľ¹j =R7 ª}' YZ(M2p | /jBzBCU6u(WaQs41v6>Y.sX \Zzz7kAŵc0ߖ3z$0ڗ ȽAIi%]kҁJϡ]HmR!= ŷQ73R$ΩDpxߧ&3 :MZh%)B\CSu%V^ͧk2{y17=ĭ7~돜./)7, C}NmW9R[Q7Nlo]dk"u]G [h* cT2kv{>w]螎EJ̽ iAe+4_c[ٷ]ߗRA5oxPp<Ҝs8ڲA@QwR? /[_h][ϫz'Tm8Ќ%@ROiT*B7"9ewZ @[o~)%H3_K0 K6$2 % m[2 TG: |- ={>ghХ\ҌGG8o?TO- kd`:E}e1˥$-⽥JGਜ਼Tiѐ1M1p:ڞb5)Ѯ>G?8z$QzVv>&֊(:O)H~]tA)cbqzz.[~:R?w>l6f67(k|ʔ.+]}>쒽6nt7s5C3h|Bi\q=h=+` -)?>IY:mU|4wV*p9u0p~r1&3 :e,[E,;g{f8L1@gdq6IҁѨ`PBQ:4U;Rg]Ȗ,Ǻk+h!feMWķ>51osYZjm O0*6V?T͛#ZvK?婸No)6F0ܼp՘]`6ztN-VF*8AbO0c`. kc VJ)vEI+Ꜥa#鱢 T Y;ߏd8.c{~gkk}ͽ(yoASO[8(cΒS0ҶpA8`L`P*FS9~,`aŶ^ 1~~[BXWG`u!s{V?w:oc5ؔq;mjN5^{O~+)ӜBRul Kg߿$SK`I  H[`|NKUfύP3QvxhGM y}[Jj/h.0GqٽK . xKS 2 uٚzߠG֞xQڷk欀'cݏ`:E}IA~3x cYwcP6Rb)t&@|>9q/ (ʷR"(-/}#, }RHMdT>-U U*aZ?W4kF CACJZOa3Lc1- { bJDo1vZOF)lx&2*:f(4־;Z~0c ֱ¹@ ]R QCBSP(婪uz3O3 ͶQ >{\&q661l2n{_VjɽC=trզ~6E7?{[uBp LV1U;GkXw0R\۴~o:m6"N$]V:vP(ĭ6+vC9f+?2 ׋~Wjx'ZL)hųR" vxUZ8V8!lq-"T54slO SSP>淍 "k})EhVw>A 4C7ĺ96IS٢ƶ5o"ͅC쩶 XV3q#{z#GnDkV_Ci&]f0u#,4n/E ,oj/SXNR{Xh%A8#fvTҋ'ՄFٲ[j"~Zu0c`c_EbSx'j۠6)1 {=;'M=ktZsh9Bq, oɷ^С;8vg KO1=gBV[آ룿 VNDՏwkh9."615 h0(%| k&ЉME3na:tS/ٹ&Tx*h:&- c`xX'\!KGb޲Q}8,å \l JaNY'&$h BbRr3wL^%{+fFkgn\9ggTW5ѥ A /o$ֱ#C%iKz]89;x|e9;>WFkŠx}oƝ/`zz=eu3$nny&븖Nc_E`]+Xgjyf7^F?c^x67z'fL&[L&LSihk ?[yo><ҳcxu'Ȟz)ĝ7*Sjlz{X,u=yHX%8x? j9(ͱ8omz+5>(1[ !Gӏ&@l%rN{Թi e!GO4lӢ(}]Axb`cE\Q9k̈́?|UWW7]@qVRMEUMi 8CUvX`P1{֞@3(nZfv0])pw\؃r S7S;g>{P ޢ1&[Ph,.wDT[NΕQd}VIRH~W[x-X]^xom1ӟgcwmuxTpdd5l`l}K{K t|!)uLW(,RSn&k5}'rDy|]'>_RDAᜥaqm5JiKJ)'X3&Xm|+w1W=#O+67gc811!&?Z,V+_wxoweBDvy5X UPckfj1=ʄiE3)X-;Cs:N+ڠUwߡc7T-y,4g&vڴf  Zu%}¸T,p%hiSX``URl`[k{cmppc ֱ9iB$l 7hQ7*%y֚lst<4OQW_CC q cⴖJȣf!W٭7kQF'xtyu]L)jTˡbFxizB'`ʽ]N#*Ρ5L[@A5wli_6V 5upc ֱB,Xs툗!ˎ2sïs~x,|û/UoQ}4Z_bga=owm_fR>E!&m^:-2"-Wu$|?(J RwrnjZ "%:V նѤL<8p:rj mEAIMْX8T2ZJ|t d?<8&~[yp^;s$]+ZQZKgW~cPdwˎ})ǡP6GPLϾsHnBhI=u=i>{ h~CYЪUX:>Yp wF=1Fø럿: s?4Tk!\Rm F#:f*Y ् QZXzEw>M2  G f),)BANP%]hc` J2?PZ3BW}5A stCSc)GY1[Um:u@%:s8bCe<BE*ecFa4M[,V5͜<[[TY8xt 1ޖ5MuMTA/'wcJ.1f=|M_J /ۯ3Wdoٶb!ȆXy(d?/|mcfyiYc}j[p%ׁ+q(T;mK{ez-ժjp^Ƿ^XF+Qn/>NW籮6;0]d{r8zZ!X3X/k*RPMkM  eE!lwky_u=a^m3_d2=9ý,: d p<ٔ]D=[/+t<*j k~>ͣ)i.Ŵc^xB@Ctq|-\H"ٴygk:U5Һ0Rr(K`hQkb'}=;n^* \R'NM`:3o7Ѱ =@}sᗈGtLV5AXH>T;ISJP]X@N?NҲv6"(peG b~5^U!˜e1jeSj۹*x) W,6"k}8C(dﰱuwM3c:٦i,`1>m9Ȋ 9v5Ξ;EÃnS6к: R1(F#CXfr0u^|72nJxSz~ӟ " Q䮨(G)TơL'X4[i-((g_īK^eXhL`KWx , ơlLgl(kxQ,|3!a{f>ڥ`c߆v9o6?iFL&[Ҷ `0Wv𶻩_zQ~ȟYQ܉gyih}Ɇjk螼}Ecl^B9|F67Gňs8<c{7}ܗb_Gr<Ӵ PAq KY<$$e>xQz WaVXҟJ4[q͔Kn]GQh޸Z8b|Wu áZ3X-k.5j5*kk ק{MYq!pߙMGp0Q]s HjClo_M5x(Q;O?`"`,9WH.Wd}ar=: 4lIH%0f[3&+w4.,Au5>0e]9;ȬO;d=4H֫s̬JWXF` $Kj6iC&:<71/̛̼ w݌cp7vYl/0MhK->9g^'3*DݺyyTq5j)r4~uΟz9^[| I*Vaٜ?Y" IkD }U:ҍ(1Y6"MGdYL[ K%a3[/Y5nvg0(`ثIӘ$&U7JT㠉H{wslq#]Jlf'==S<_{kF7m}Ozz^'̛q/lA4}i1Eu6`NK8x[{ I2?3oƘ '}vW57`iTgÖ]ǝ"2\\[-ڝs4kx~EA ?9aT\ Oagqifꪊ cPF88egR(ܜ^](Uz\84p` =/լi'FM*!(UReCFij.C~՗#QADclkWf?~Ujoj\r_6A>@Q`r09Zg$i`#rń+3vTŤ1tW/T%Lҙj}'/HqdžFe4T"%I*kEN67qFr0:(R'I2|652dd%R 0x89؞l @Q$F}rh44Z ۪:n9eiS}lCAʂYRmo]gv6sghǏ2 YJm_DkUMkۿJ9{/T-iujw+l=>R8hGS5sf4X}:Qտ]~_gOe+Eclz#\ק ̫1&F2i6ffAlҙ۽Tjxē]tro5;UA+SYgr-|o#|#_0ưuݴ;ZCEɆ(/YR푀%*'K|#̘jks?)^*oݻ,h}6dU[ױGRP8%ϭl~{??Iжf6^tvW635us5J+(w7zTA,v}iV2"0uX`mMX:ei<9XwɆ*؞ET6ޅ__nu<߈)Q,{{v*g{"7Y"v h8fЄac\|+^ޝw>ItYNWLܝJמޫ Ο}VkFso1JUG[}d| uxuoa*?Xɿ} eFQf8"!y>iGv"O6 Xb锥/QXIͫ%!PZ';:Oaج'(ګai[Yj߰=Mv?@M9xYjÕR_wt>O{a`LUurkVD9DA'gK!rҸwpG{T}  pJQBDs^ՠQ`LGQS4G#zӡ^_ .Zc0U2Ncw\oװP{,#JysϽW780 u!6_G4:3mpN7VW\8Qݨu1`^=p?وx`WO 񠪾͉. vR$ɐѨe67qxLH!j;=XDxIKMBɲ1eP)q2p8 ϋu5{fU=[w|LtTDMF5)q`p`_?o<)UNQdx^1rC;s6IG6\c*ULG8!leu/dMqimO0ЪU٨:r@Qg3 qV&%BuxXZY=~GA o&OΒaU1}v_^gmOy7_g/ncO>ghVE% q\{0tv:?X^]/sO) .Q0onVds{(푦4Ux^R,zG9Ι=t9 "2a,/Ӑ@rt:c\2{x= KXJZ\]\"ցpcTx>EEaPq4pԵ7To>}ן9VVNuN"q4-~Z2H ฆV0,=_CgdYd~ È (`૎)iw|ܐg ׋}{i>$ ˇ IDATR\y|/4'A(CFO: XbIyo<,Kl< Vzz+w]! 0̮4~zyN_ˠWwLo`N/ "ih! 0=ڳ ;K\G#P[`I-h:Lryܮy-ـkrD>I ;$;I%K,%-kMC- DZ}@$cl@ڷ80mPwcxǴfCސh?~hU}]svT:i۵.Iy>f0fc2W6.s$zgYLHeg1aMyeZ K',TVz2ai0Y8;#kvV PJeêupׁ<7;~2Lօ_?C QDOؾ( kuy^1I2k͆,1kF _eo;w׹om}ql?Xr }T^9 YHKjRvw`p'.K[ }I Hiz lz)˼^ Imx7|szӯ>N6Zj&Zpp]S[Y@Mf` ,jPzpv~M:b(.-~TaB8tweYfdоei22;p,к$\GEl%L*Xb)Mcꃡ˭9,oLb֊̪Ҁ$铦m˴OFon-Ggz/ZW"*)0:'V,\J XbIi5Kq{>!oWa'$d9dy; .1^ko0[vЩ2)A:ztGX5% ap* {Vvo,hl"3HBAдkgۤ c(7OV vB`xMlʷ?x j7_V(2xF_!b[KŘl\&K34?2Lq =XbIMq;AX8`؏eCɡE%aEPPyL`&F*ڠ!MJEPՌ6]GX+O%`dRKTset͝\Ϸc1(+vA2\'xRSȲ,+)彿!1H1qbFq2 !q#|& {uvMqHK,-cv*XxKg'lb{78NutG18:Zk;|Mq)H8)aP9^xnFTNP/99^],ČM~gR?nf>w|A>`ǛL0Z{TU 8*sҪ*Mlo书T֠"=Ǚ d';y.?9P,eVsAMWoogd|qU,pJUTa{ 7AAyί0FFkEcxp#Iɀ$MfRRE9De|+9',&6Dx2o:; Yƥ hu0 ۃBS2 )ʒ_{;)ʌ,'6`ɐhco}7; Oo3n__F%@3ڀލ, v.JT>QS)E3P P{Anc(UN6htxՅ]Ws6|㏿ˏce4)ZDvTN4 Xbi骄Ǭ$ iڏ5ӋUb&,7.Z!Ď=&hk=vIA4AYBcsk⋿dk/E<.y ,S_Gޡ98NxC54~uٮ}e#,KA#]! v7_kWCwMQGC m<°AY~D(c~`]r AJha8ȿ2|A(*ғs'C/39xYU&q]*(Kp!ݻ}C7{9*zg~MۓuH %E1a؀hiAsUz#ɑN~KK|D+/.^wW3 i6$Msq % /~s3ߡraР{ba hR9%aa`EJex PX$*4d `hs5s0C Ơ"njƛ  /G xnN]v0ji<ֳ_Z} Zvi>Flp0e9J-&MvR:$`599b( C/;~=8CQ&$i$3o1^5O|WTAS .Ѫj5<~ ymeY$9:G Kkr߰cŕ N_؝L*Yi,˂) DC̼ؕ(qj$TA =Pʥ( "J?/ y4ˈ!,&,WOk Xp?֡2:P C;4rcT)*(l.;O6rQ䃁,N^R(KfB'dL)UP i:"GyL C,'Mþչ{7 (2'ˆ$Iz3܃_m)K`tҚTjgސ5/.mj/ 1Qln^&2t4s㩝yh+U#G vLC.뤓%.F38;GɮPUcTh K,!I$ɘ81l'}x&,U8f4d45h 讲]'4&a?p_ g<ʉDž ;{';w F8kkE8R0(q9u7@/>LgƕKc7na_Veþ !nW+1繄Gk%duN|6e:k:W^snlÿ{$qɪ`Ec.~ymI 'KbbȐ?&^1(eNƅ:p_:Ax5wY.<.v2y6f 2iInZ!RH g8BF3ݵ[O~Q=6c<[E.?.jЙfT)%d͏1v<.Rn-ِe]`hq]5Ơʂ$oSeP=xL ^rqW5RTHqA<.|°a'˻~5ة0uC|~[ߟ,s8ƣҋ#[jVt ׫#L[s6 Y,ǡ(R\=bL 6 YDMX~aU0!$` q۲[O[R4[6x5nMSZC%`Lׄa`1ih4 ǧT2Pо+L+XD(%đgGlUNuku>}lo;ens 򠘒%ؼT VB]iR0jik,ggx%E0 [%.VU5 %vHnGs%lEz3; 0'f}]`hY*\>=m3F1EY$}\>,$` qL"L޴v)1ݍvWAo'p {q"Ep'ٻsOg`ɈQqǟ+8a&խvDs%]? ^&խ!þ-q}iv7g@]VxNsC+sbIKhouViꍀ:w yvkv|CnO$d- ݵGU+`K4)FAtW4W#\^q ; b'g5w3}oj?lB7!Ob NViUˉvHa\`{+a<,PxBb- iRPoVBFs;|~'Kq]QQ]?ѵt9q/ZG~; %d-vJ]{\&wCV&ݵ:֩Ma߆<;>,e<,F<;|BzDEm,%vVkG[ӭfjWZv{Ο1/97) xK}@=$` !f4 s^|~Hy6pu":]Nmrlsa?K%!k3N,%%Xf٦^xޏv=/qցm}@>$` !m_5X?V/e8X(cJ:ҒT7=G,!ı,_om֤cKp0(]; őNY?`}Sݨ IDAT%#Kq"L[/t#Va]ѭqhךּ5 Ys?$3w:wKg8XDظtad_FL*XnQ#K!0UjljRZ?ݸJ͠0g׭܈}r XR"K!tD^QX]^>vؼ" nfK:;{:Av=$` !LXQcuNgF3 +[)~Fʒ iw"),q-RF\[jgz泺^gneif2 \j VƍT3OT \^+n^5cKqЩz#ŵHB KK%W.VS hw"ڝA?uGAゲDuF+ ]V`%&K!NIu vD'+݈ssl>gGA !8J8}ISs KBpԻv醭nu#L7.'b敘gnp}T&4x XB!vG:53qo|<.R6ČaukгSݥJ\,!׵{ XnDl`GA z9A4nک:W. Gg{*Vu,!7-KK.>?V]ۻծzNY;3 bk#[0ol\iwktW,2*CB6eeFtWmȊj>/pB5 ZJ/Yukk#gd'%GBҒ+iV}&K!njm~/qGAة9Lqʈ#jL8y0HBҠt4ˉg9ל>v{+eü}m\iBNiXH(pz7~poeJBSfkcZeA4vVl|1^v$dݙ^o,wGgZS|[^{U XB!x3wmZfy>vظZuk<ʧSݛ(`%';n ~.dš܏,!Sݚu[jBVPˉ)[V6ΜkrjCnF<m(^MHBqdiɋ y(6t#jS N5gҒ͍fJ 6/Ŝ=/<7CTy/9wa XB!fX]vATB.R6.ӹf+] X$\F};$K!ҒG\h_X;nJHgu(ޖ5^Jg醌i8$vێo,y9Zcu&CC)}a IBq,fJVUjlEUխl^UfC敘vӍ=|Vn,!d ? 5j{[aNr R34W׾aM%؛T&XUj4WBMYjۻi{+cmDf`-KϯnooHBqi ?OtVQUukt x:iZy%f{3m RZ ;w˗\ $` !SN7|sV󖏽Fęn/Y |AVB1#MKG\zq߳AgzNFkOX0T$Yqطs[$` !1[}w|e%?Axg7]W 23 UZ9οf7&B1/n8mnF 8r]ni XB!X*fDQLZ a{9?߉IpBeLIQ݌ˉۣ~|[@zB 5ud9]^ҳJ3gvY1NoX B! ԣvՕ(.'tZ,!B۰_ :Ֆ]B!>Y1ܹ|!B%7pB!NB!ĜIB!3 XB!s&K!b$` !B̙,!B9%B1gB!LB!ĜIB!3 XB!s&K!b$` !B̙,!B9%B1gB!LB!ĜIB!3 XB!s&K!b$` !B̙,!B9%B1gB!LB!ĜIB!3 XB!s&K!b$` !B̙,!B9%B1gB!LB!ĜIB!3 XB!s&K!b$` !B̙,!B9w dIENDB`v_sim-3.8.0/tests/exports/field-3.7.png000066400000000000000000002227331370110300500176020ustar00rootroot00000000000000PNG  IHDRXXfsBIT|d IDATxmp\yν@/ 1 33FGxr\Ru%MUJUvފk+&V*_!Jj^ynYֶd{$Kf(kf8|'1 @7ssvohv }_N ȯ}-!BHPyB!A"B2,B!.C"B2,B!.C"B2,B!.C"B2,B!./8!Bzo-#XB!]E!eZN?`xx q<8H^ø~ć BӵK *Xku$)ATBkmd҄kk;)X1` uՊ[u {l^c}쏿T:'!Bz6u"$A\Euu5w͛xm&"@) k-=S/ӭHPUopL;kt !BENEdP.B$qfb``/@ĠT\$6a B!VT;:I%+ dmmb{J]VR岆1~nmW*c F!EWP*F0f$HTx00F`A)Z&1+GY4B!ǏZvruW:}{{Fvv$)^^ ~ !ҿt}-Bw$ۈ"R*RJM*Wn-Y$R"BH/r =Tax4 _a1C?:PJ*;>d B>"X$dN2]@u" JEiOæ}b;/SBb_~_V$̒$;QPe{\w Tgh]6BV#;EB9ȯ}[& '000b}wmÈ/Vʯc~9̈WBH𭹅w_ܵ-ȕ[bgg 5Jkk 66%ll :-k,aa=!֠`\8hK ¢b]RNT|yr=LVG!DEXD6REx C "T$1_vY !C"_)RbH T$Ed] hGm/B9PH.7ҢzcYFRDT$šPd\F[cf$#CdZg]HW(T^f4006FӺ!`C'4UGHX +L}W+WU8K xQ!`CZ @z lm"đr/ EJ/xyҚiFB(X$XX @(g*.I7FP*ٌ@'GؿB 9|,Bu|XmQ/ 8cf@*: ef$Ek+HmaF9 rѮHřȗqRI.B&,r,e^Z I &ڥ|A}\nTE( TG'͊L4ZI0H!C" =5A"`".4hNl*p!H!d7, ^ZHU'XWGP% 2Te If.BqEr¦ܙz-Hֵ*Ufbc"@a` p򬵁N Arl`\ץr3Xz7GU.R>.VbBw׋BQErZس(%٩AӕB!BGbkmhYZvB Ʌ]7ң@i]EH)ӌ+@1r]pW˲!`\pK0ExH{wÖQ +LzSɎF91BHPH.XXת8L;%Pg3FN x2W#)khw4/BH>PH.TSH}\AVmo%v@uEK1(}?`KWiFB!@"IXcQ(hleh+ n(riGqڌ!U1He !]ErX"dt fLPNc: (F" E|.W$iFBHgPH.0EH.Q "ߣ^m$\ 9KʆbBB"{viBk,vJ~3:ՉVE.cA;%b ŋ`\0ƺvG+ChmPp*RJ["hDlBXٸhWB, _T} ɛr*WO׀С^)Aq0Fq0 u> 2AY(X$\ @"ɤ DnXa(V.T];I_L3PHnT F* K'FxIfq_Er)Br)]1jӌq?BB=WiRە0HHOB"`},Br1Ƣ`c"^O) D(Fi}Jӌ?t%NiFBEr)BB$`m=s(hrٌ׈h$t#!p`\0U)BBZegG;[i8Va#T$18WuCI׷+\X](X$;/ilQ}Xȥc ӌκb{;N)a}B"!"Lr@cOJ&EqMS3b.WX_EiKȝ&wmn`1`v'GzwJL3R Wizf[f,Q/=4:GR6>ͨQNf$  B44cf2#BѧBbb1ƉJQ[m'\2&G  k,T$PJǖ>")$eSջ !5{ "A1Q,cQ*%(mkEQErC[ %(`r(4J%JQ}ڕzw]KE[e,=PHnnJȑrU.k0S z ¹'qg%`B9teryk;Uۋ̎CIӆ_amƯGU!3t5߷pΣ!s(X$7OR!(RXYކ`l|01,S!$gFYdErh#τu_OoA{Dtl$7Oqb>"!}S ex SbEr#)kB!{(A"+!x prNEr)BBH#^N3E  !"nK/xɥ '(XϠ`0ڸF1?RXh'X[ J X(YA6 eK؝Avr'OJ`hy `)B_B 4'$}"8kBHU`iqӭO81H_O) ?Q!1;;OV((X$W"$B=fAXңMS'sXt "$nP6qC!A"!$_{ <(m(X$_(XO"+vN `hpXC#m(X$WgB`=Dp,Xw]$$ gY$S+BR4JO(Q(X$WtH_{Z <`A]IOHq'I=)a1X0qGI3!ˣ뀀'`\Gȏ"!ǝh )Bx[pt|GGH{FrE!`5iЉ{79"j$W6>}2R j$w\!hoa`s'%&YEz ɕr@D00 9t"X:Dl@z LB$X^xFfp j$g"!!ZӌbހEr%,"$(g!,>859Al =j$W6`BB H&YFH "$; Sl@Er%㘳 9 2g`\ )BEB3h5slw 3a#?nt>KX])at<Er'? ڡZtݟyx0U E"V00_̥q :,[ ُhet~" Z- j:.L?ǏRHp0ay6XZa8ˇ>r4` ) BNe~tNCENEܛIANF),=ڄ \6{8O`2@ IDATH05=/vfkՕ=mzT\#Z@_j E%J!19u7rBAG~Y>?ϖ #(X'˯Lu|/pv`t3gO`tlźǭdKXZJ Ek/Zq@:|& C"3/2XƛC(X'8=9y,-n?Y?fϜF1qz0mX0(ﯨd%<G6rI">7C8}sGmX.qr6qjE 0:^xHJX|Օm<h>~hF/ݻe-g'qf/nml`zfٲt#X'Z\])>j?'w)ɩMB띻-Bp6.'Xx@8>hj7e*-#(X've;ncV97n\j`KEl`u{+5Ѱ#.yxP*D0x܃=^ l m,}sB!߼۸Z/tE \EgΞUu~f̏Rϵx 7]=WZ_yjVj8%~^=X fL`jzJV A,m[he)&N  'qzr)-h$ͤ+,8be3_=fcjz/arC"}(7*>܄7 XаwlΜ̬PD?5=ڦ>l/wD%H TKק&]'zˤXp/V05=ϟ`a B1;Xڬuz5֗qQSԻ{},_^ZM7_:t1FNj(."p=uZ8pq )j-5Du\w7EhN8qXx;u>ˇ*]C1FN`{+Ρ]'l -,3TwsOZ8AĻBTkRH𨺞^SPD6E]ZĻΩ-wlڮj;|K.Mg-+]۟9t'8?3Kxq"=~g/uMN04\z[} svΣ! a XYhe)--yQ)]$X@o^_BIhx:cqh{ê [wKJ܂lGMQח!4|MvO@dtg?[^JןS|E<]-IAp-NOc84Ez>ܧo7hVP%mWh;5qSzE" qɽֱYp'ԃހ)B3^kyIKNa:H\kOoZKmSCJ/^"{E\+8uvQMK{XkӨ(R!RX"%Ѯzɛ`P6@AEPp7$6ſcbt|0mjSԹPłx!!]anYhnXEz">/^7zio:_N2(,5Z(D J"kJXEIV IRJd~VHJ"yIxWY'm:P +BD3sYy ܝy55=_J _BK,3.[eg Ѫwȝ/Ӏ&+G`քyA,ALP-Z nr+qQ(DDAGUK#{|'~\?N:Aw#?uB~[6*"$!U{Soa6-^LU|!ŸMKBZh01.%Ҭ@ XDJ`]rF{SnWo%"P6θgKQ*KϽ`0;e:jzB0S'UmJg͟ו^jw] \`*(XgH|{+EcWO@KѫU,몧XDf U4D `V~Q,QBma! %LA0e!F(rr|-_>m乑RGMQߺyx_$H|Iͷ0{eS#(ʾIO?7s:l:=Np~׉+E&z3rBC.%'pi>=:Tf*5VJjjFtiN"j4]j"$M-`VKիW^u>7R)3}?N Z`}){sk/az:790Ezhlk3~ҍGd**L+lR0TxGN\ g#Q֋X-JE, F4] ` X  J\%D*)MQzHVO/}9_/tL$ Gz.<$tyܼ:~*u+O?qĤנ`\("ilFd%Zxc-_|08 \JsemA\ɦJy2>Uh$"Os=|B)r/2Ze9 `E-㇮%f .*Wx.G'>|{95= `|(Z!}',f>3 ]GxSӛxxo=Q^EqDᱝ^^FPդ3hVl~ېB| $%6IYeىnwQ/RF5\dʈEd20kY b+3 Pƥ Y΃CW Zxx`g$j)꽵׼_ҵ0_³ϟ`,c$eB!B\± h< lEwVڵg8f‰Ȋ?Ưo"Yu;Su*Y=+(Z3k|O^j7=,3,Sd#l&X< Z4تW6ݦ̖K\@['0] r+#eRG|{~VۺqB)KRq| I" A`BD P{ҐO.|Q_jZ7}352}a*u\A7z\={ol6x?X[ Ûo,e1EzzUQi)}x^Uݵ==?^!=^%>iDM/-.rÀER((Bsb̉h5S*}K9)2!ey boW+뿇Hu̳mf4xzzgnZ[Uݚz."G${bk15=0c9`@"L-~Y98[cU/RQu.J/#'a19PP``DyP@몸$oy!qPk \SSgܡS )L|Z/wVuM~ћ̙-.7"ۍ^;69Zԋ;3퉵0\`s(XNV8PJ햭vw˟G`8g6mPrݥUfqz Um1h $ De2: mx>mT !r%ڋWTU}\ X200S})|r>}J`[Ľ5KJV0}rnSԩ鑴{);v7N=E}ºyu\{ߗ7YN8B"=Eyǥ\n:0uZj`iH6hZA:$l@A>z00H"ő," )ײF*4n3 3o+෩lY-{7S[&;5'I6l.*ws)ǥJou\-̭I\`c(X(@-K'QyX֫g; ݫr|SYYJ=zhW4au(/6'Ek JAy3@hhDvJat{<<@U҈nQȾZlZ.8#ap╪.Xc`OW9O϶&-]o=. 0` guGMQte&5+7ٟ6cWMf9ё<`~?Dkv !U+=XO+Vޫ r2TLmшih K D,D LJg*mo@A)HC\%Qa]e*JR2Ve~5zOͤi5,f }PPgQST&<ԙ]Yx3cx)l8PHOR(Dujjk؏hy\U%Yu+t5Z{vfm%!+it;ַp_{Ų(-ErfE!KXRXi(a}TQ[ #Y5V4qÈ;XY Ժ,3 ߣ]oGVv~62\ӾݦGߖʩqKu[[1`S(XEycuqdwm/\~̶{Uen jk 7,0EY[X{^,^ZGbw1Qx -ʛPq\wY5rI֊5 Fw+pO"~"|j>>=xn۷uogZ= ߹]\6EKJSiXȏdBӓ8?3; Oyt$o(XޯnЧӉhSoMQ0ܿg/cĉ=yxo=mpzrK8B7,S4kӰ:PZ]F|ds{60~- GLR6D|~o {Ik\z!: ѮQZZ@Aq轥>mpB9n- NF|=j`2o"ӛCLX.iY'ƴ`Qw^:}EN)ZYyFNjiMW7E>NpڋM˶l`/(XH|+.!XD+cû&ZNNsJ k.W@WE*X6]džܡ hAZ2tXk\핉hc+ "ɕQVl#RX(k1fEDnZc(dX!hAd}יdY R<" F\-㮃ʲ;庒^_];5ݻ4TwZ~']p{]?0N/`Vax1Ovil=㴈զlX=WF8{ R.e̥qy}FHz )44 sGk<D)"irÐ՞v[Nمw={[n,8Pnih())q5#$<泡$bB'WquL,hXt+p34/,cGWd*)DWf6ZdBI7dUGvhS^F,4E:kxqs\}Ҩ=C=Җ G)X iھtia[74_? a&B=!Q5+P-]vah_n*}9WĞY"0U.Q&?&B*R,1UWWqYlI6F " hfU~J?ir ?-{I+gSԽݿD;F+D*u^ L:E`J6Zd H벬F-_dD$A @>U O,cT݃ 3 J*tGF *3@ jAY9J#Jm佖$?*uS?VࠚYylml`zR[Yx/>JFHz [:NzԚhuDՎD֘t[X70gw\]dUsf4a Ay-/%iR_eSH!wIKEd-Q2 >ݲ:>#YƧ-LV"ZDJR*rDŽe]{0IE׸N(ZY7MQ]U *fLO_呑^Ezp腥߈V}ʞW }]kkTɆ{HT IDATpUKUحUjJ 񱴢'X8($+6Z)H!WU5^\x)]D,;0c0,ۂY:4)ͬqk|16q(>j$Ѱj~nm䅖_-]Cզ7_:>؅^ N!G 9I&Ә5wc c{ǑBn=IL;ίw0Eg-B3R1>hh{Ie:D=:UZJX 0XngEZTU 3[X 24Rb]͈O}JT?tVkΙЎ6 !KcoiSl=WMQ7]Gnm:Gpo,wyt`j=BNk7죝w$aIUU2Cu;tfaAYʧ|%C[*Mq[ NČAd*BAv3#*.g!Vpʖl ϕ$Rn9,_gEd5`#ՓUS".jӢx 'Z-E%r o* >07VmZ[.-nur:NhK˶kS;"ZR̽K- ֚f2hk]z-L\4dFt J С ~f!ďZg@`y*&Jeadbe* "ʼzP~fR77 Eʬ\4y_ޥ_DKŻ0)ʁ4E]{m-ӌ˘2Kxv^;PHQj.WD+(4Cƫ15kfV.klJ]wbWjXJ@l+n) h(r%$~ \}Ha;($Ӆ5A0=kSR_o^}S-ZvCtͦDVpzr3)XG 9j`eTjrwig'Zٳޙ/C5g5̌|)Jt+Õԣ;^C 1ĭuU,\tM 6~E"@&aI_e!i=D,X]| t箍-*m+&U%Zk2΄!|_Ch|VAzn5E]ZlzֱYp'[:,sw4BDZݭӪ (vnFj^uIz0~[{U S{VUjV DH1$ޡ$u`+Zkj ]w<VYOBAA "X? Dp5\P-\Y.(]Z5̘,7_ۓص1-}ěԓ'wwmO{~G j5j nZo ^OQ,sP{a@e] 6>:LS!YZre[7t k+M+E0"OLe"0+갟B\iD)(3>[Q*UR(=Q*rPU}:;-ZoF7=X8L5ok; OpgImtѱA׉^STcz A"=Kht4=nmv \Ax'hc-ԭA*.{ QJFֻ{$,C$IHY.ze@ɓ"H*@t~VZi E|Yq7b f4bËuItݙ\ !|G3 {D+Bi?߈֟k^s_Bt|G: 9eSmL76)V5??M}bhh@f{&UV) =5Ňv #55 K;^G%lDU.mjm%5DQP_gݟ%:d}WT%Ul=i[=tf ml3;bz ~?z#gzxиz d#Ye˒RUe{{>yoݪʺu'X6v[U#1')zOXzt88;YӲ ƛU?O}kc.5w,< ~ϡ˗pKxqhs| o[}g?yhrCܠ`$mᬮH"@˝V}2w.R&o{,_ТvO&~Tq 4cޣ >4!Wes`=#F~z<Dfx{<3sp>x$ժv-\~?'`b~{K|hO~?1jӇysd*<шXPzqBj\hu^gd&yђa{ _`qտdjufV- p>`7hGxF l 8s4hBRA@LQЊ&,w!Uޞpx}vXo%A!>-^ԟ<q3ǐ"b%{F.,^'[LӢ{LiaBh6mjU%߉˯$VEi{XKvlCi}h?CI@`4 pr @DGRZvmkbiñS+8sQ|W/ m$McL L%vqvr9w}#ys[Ucϯ~4fyurSO>1<֯њ.HŠ` 1Ej4rx$ #O+}Z෿?LI<KiT`S!(GB[o޻t,% >*X! 捏jtoLzǴ]Jh8`<%*7Fe-X~=BւB]PO^Hf[#r#v>/)Zz=]OSx5?Ϡ`k ;ߨqh2\ ۡuU>;xKQau*{M=;TwAKw^EM'L+d L5ML '+HKwŵ.hYn\xorA:1Xɰ Yfv*\\{3F2R׺h'5lDW-?,iҩBGV#4UċkB@=|s4|?o ~>1(3\*䙂R)fJɆ4SZPW~[̠`VZOV'r 1>w)-c㚥hqv{-jĮ[\Ok}c``kF>3u`l  BMC£Cp ߊY:9rz.aT")äZ Ù(UH:sP zcPxeTxIɲF"SFՒ)aC;uΑs SљGeꇧhu4UnOx8=|cxw^:XC(XCdh?2^+SuRC+Ã~/9Q[su3p@l<۩({TnLwΖ~Ͷ#x@lv]N 0Ȋ9sYߵ͎im+Y t9dY- __XY|hуbSkGJ<s'F] ,x>%-^AWJu(XCdf@+i|jΘZ۾ ZX1xIiNV>ָSV_8u:/UZC^[{JidQy \^*}iw-E_!K {w֙ф]*6jL,1!˵hR CGV"U DUIrFҴVP vϱG\S’Urr-Aqa}sa[%b%CzT锳"=hg"0&gZIC}a^@|bӄd!'.(KZNf*fd7٠u]&tR~=E2Xc[eg%5 ȳ9"d4ms{G L%5J!+ @WȊe荱]Sδ6.s ee*T.s=-E@ڍZO^8#I3^ 5GR`Y(beoEh硥ȵ(+:]:sI8;ە9OϹw(ÁPg6R  Nl=stT!R+ Z%`#jUK|,)59I+vo=#gh-j^x !%b%1&,g`lFq@ ρ$)ie F~9Fo!Z/Hmh*/LBVq-7g۟ӂz2x !pJ14$UR|A* 0 ]l҈Ԍ>=W1+FdQz!ZU*YoὟO};8p2[{m@z=+u+ j`k`!*Wfn^#v7b/EBF+J㢖e/(h1 Q: jH^$dz#̱aM]e( ҹJ,jAK;k:/V3,ԋTf|wl[J *>IJE׉zU28GXk(WtU _+Zˏѯ~A 13&Pe*ŕ8:1̒ԩVff:7.<.a#rSE}*V6*mqt y4JKl+NXQu1/L: SH*Ojd@ gV:&⣍DzUi?)&xU۵vPV*Z:g2Sd|愨JVr PŚY0QU%% FUYByZ?%OSx-osÎA:1+Zltծ3 Mchcq<\Vpu+/.-_ rU2$h6@Xh]aTVJlӅz{핊JK=sVb`ٝ:L:QP)@!UR/OT@~[%0L,(Uri0b̄ɬ@"圓j#yeTUXފo{=G?hnN >'߱XClhё1/\3 peֱ .]PJ,hhYʼp- 󙐬]{|"I 8'd+( PHBk8[M F(IJ6i䯲qە vSVYR"eh=@וʫ+~.)rIi`tk 9m`e>֘s *jLQ.?ŐhQzMw=Nm,z-wZDC8(XG-beCԵQ7c{}/D}!_Հ ,$Չ)O_n+'VKYJ dcQZr8d=vپHH\N YZY7W)5͡uVa`;'J^ɞ2K`QVU.i+FeҁTxR:Y ZeIWz?_~k>x^ 5M r9azR^=[z ZԚlj yv|\`/SkFakU! LOglTpeʃ >]4Jهv/ 7\B PRlqY[kҊ^(oVùiUVIقyR&kz(rVNiN_;l vi0Pxt@rt/C==mO}%pCыX٘b~eԮT%;lc\ʕ˻@ӚG@ ae2,Ԟ< VnJ{(Y TL=,ߴB])eٲ} * JAYEYY P!>zX`(0K9>>x)4LG;6*` đj[)jQs!RYJ;[w984ݷts5 hk<ؾ 6eEy3x౷,}-C L 5F[ͽ4 C `ȚNV{BLzDQ,714EHTa[i>|ҘH-K&00V\>\ޯ}QnяKDy={rM  gU*>V Q2`g`%GC^U_D1-MV,ms(Wtw*zt1^h1r}YKqԾ@XCl4Mކ6tu >Q!k-%=}\ R2I'(\Uavl'dA*)}gB)0cMz<"!˵.FG{,DCBd^yk+2h6z/hAB4@ xI){_9}A, ɋeMDd%K봥ފ%YoO2:M/}$UNۥVcD񼮮F#ThRh='@}Z>NлO}o[oy+jI3f 5U:JzT`ڨt:ͲE ,4d!6|1@ G(F0f݌"dFֶYn%,AL!lp7DɓZ f?LuB9^U--Lj#^W*W[݂"u,pӔ%h`8y")))]I{ {khtسP!+(t1Zમ5Jh;,ߏ+_ h-u]6xO7&=8=Q b?~mWf-X~+ֿ `8PEa:a<:PC|}80xqcp 2y?~>QToHN3)Y$$l]<K,% dIwX)ݤYe\͢HD*aurOa2^mW T. Zp<8ACsU8G~|vyr"qj?o:Yw(.;PUB*U18'H[xͅ.Q\[kwܳtKXjp{?93 G;kf7|?y5gʲ,y:y1̯dJ&3CF1p͏ApT~|fRCgyuv[5OJ.ѣ(m+Muaωٔ`0uJ՘ \vbzXo,{!;s]+~ȎE[Yq01yZY'<=f"^օ!cp1sm_6ZARO5זv}-e'd.`>|Y\(T?#TgYog r ^ QR4 2dvg9-ȵIƁ֙K7skɽJʡ8săUE?Qw~9ujR;L̟)XCl]?ƿW'30\dݸ"4M4[A:@izU.rQʃ#Kt{=i"]6t^*3Pv ɶy: hΙs[vծ6Dқr!Yҹ|ZZxֻR?V4} gF5Y*x {6 v VU UU9T*UcThx5% (?^Z_ Tf7v1+Uѯ{'=5~Wy ˮ33 u,Ñ#4n;wK`Pt?|nab RT!7 8)hZ]GqU&uHId@26{fU|ǡېl+Jl MYyց<0 @cIL~7H.* TKHطЗ)U!^xWPU5EUU,PU Q 7Ahp>k hruM1JЦ |W_)0aƄFc!AW2m"dyik&K TIG *UU XwGqV'p^CXCl@]Wiw~?YWdX1tWEIkǽ5.~8TƦ(Rh1/e;: y)(ϥdziCJ M66xe=YT,{mE,=szt9e.-ec~R@T* /brTʁu ̠zLQFvG#}_¡jr\l * ;FPg9}MZ<ع˃x-_{3^ &` Q5$^sgП\Uݙ `q]E@MG0zDp$ @V JozWο +Ö10Dn(Wmn:N/?CV7LvyW}ZmvʬR!H[e 9 3xTz\@3&o1.y?`R[ lԘO>B*&_Td]`UmpUhj} e@?ժZ1ݓ<t81(XG;bezCޔo`{cRV~/C뺊|.HCDp:~2Xp2z!$UXE@F$PeGN胟ՂxYolX35iŀYGQ{,YJXKC'*T$fѧ,pv`lq[. ݱRVc0B3O ݑ)R{&eȦ,`f%g6 6>,U,7M@]LJW Z`KNxs/%N?&8:17e?y ~W^l?F=]*rb_ݵ3<۵S|]* jt&㘴a<_NlY-WVol+euf@ƿX>Z,ǀTahBmhfK86};/b ZCN`WI  .yJ!,Ɇ|UL W9I"'iBQPz P؉.x7A7=r^`k6NO7KZx z!$m#h|ib?;%iBٛ% Re=Kq[2ḍY9660܂5UTZ^,l(4)&M@U&αU(@k4q`PJ!*T!CVjS i+57#!XD*g:Ш)ºFu're h-y/>xˍil#(XCtgqj4 ݙmZn&u42}q1<`P6=RÉavQuDe)94Y8#{&&Hu6t¡,NBJ#``uBTY~-p>(FZ¡ 1b8 5$o~D0Kϣ,`M'+^pJC E,PЕU@X E/{#!Gׯ0[U|K7=|hwX8Z1|Ct$.η~;>~w?v gfa14B2#W>5GμCfY6ɉFxlHtxBagg6ڐ_16ol$++Q1u= |EA-?>RsTޣ GhjĤf"N'd_!Uy0e=O<&E3MZШXYيDznX T+mUhd|X<{@|ͥ?9knZԫ˗7JV1+qv Xno-u>PUYՆAg^7~&ESe*(Jb6ʍ' M]%\=ɕ4@P4#h}X;kӆΦ(Ut=&^Ђ3gjWSY1=^yY0A+4`A3@1)RxA.)akk0n4PT!K0VE w\ J.WU1=X4\Þۻg,KچU߯g>`p?1+[Js~PjAU~Achbܜ {Hs8szryD(p.BpU TҦ>\{,}粐bk,Ū^H[omIqʊEkGCm.n z)[=R@dfiP5!bV&&@7f,K#I (`9](a̦^vVu^յxj6zmAky_|)7<C` qS^ xWpfah ݁v֑8k;X^=035`҃C\U"WePeeU+Lu.̋:m;c4,70vTL㺄2BFx_M 94*|5I c)p4'ϖ(a9('RW.T oR:0T_PȒk%ġjOiu"Mj,IڊE:~W:0^m7"G?bc|66$~_VnzZXV噅&6orTΐ-;V$j4x}U rJewѲɨ]$ YMKP67amWO.nQ,tQzKX:%6MUwN䬎%U0pu{Xre@S}Vr•Dg x{p /\LSK0XXƁ*,ˣ4OMo}wbP~ 5JnF|ï7t ]Z۵7pj]t:za<)\! (*_xpU<&t 1RQ5uH!P(+]*oM\ժY]f_eRҬBݗQB̾3$I=Y @Voe-h`ҙylRSR2lpEω\U@U8|ǎ翰˝XtX*Т=yj ` `T-(Ӱ(}x/lO5Cj mṞ;.'$Ӆ%LLX[.a51+KZ. ,d`Z#|=Bh3hlA[[Ύ=P1Y{cӭiSq͗8OUB4I [j œ>z=uB* 8 LR3 9&C PIjh$wl}ZC6}_}<c2iG#bc:dɽooƣUoh?ZA4fpk%nȣ#՘RJLYQ(6lnInٷg3)lOǞתfQn\-^қ`S"*󱻀|73*Y>>zc}AI^.]ТP/=4yp5+X`k#Os/SCբaQcNӄ6662裞Eh}=8#d/DK*Ϸ+dzW2 KP]:#)\.},!uGkl+Um:P6CfBgT!X|W}Z Y\Ujم^`Ech 0F,߯<[UQԪYRS+qSi5x67b&4C{.~s; ZiPՂnԧ>5яXHj~''Ot'}AХ墤&Qd!l E #&c\U'rj dٙ |/d>z,ŧd2{y@vE5+ v{)=~Q4rK ӾT^;CeF|&rEv$).ʕ/^癅T^癊I Aέp0h7N 1)s+5 fx ȃ0_5h Qr?aA \lA:1+Ƀu O~ ?+Nu}UFY'OԚU aY\^$ k (y\nTR#IEZ03Ljec!vd0ІC$bdvs3f/Q*CdY,@0'U*`ӲCBUn33ټfVUNfxļؼt1Ƣ}XIy#h.뿣ZAxӟę7Nz)A:1+4{O}1 ?u`5Z!55~+QN "G@U57PUuX¤/P8]4t[U4׊$09e%$]ʠT>Tx:sKDqJX VB!a5=#l`}jlC>B׶;TlD*q!DRD!3/x>MT Ǣ10gK߿@V_~Y}9o?[XuXW*+Z8ʾ,Up$\S}NR;ʡjTkk761Zۈ*h:끅З@*bG dYq9-T#s~91V+?.L'fԝԢj٨YbitynEu,7t/)AUJz3֧q&9I 1h2(K@k]K/b>w*e~c!V:3Eh]n>)!ml}?,n7cL@ CgCȹdGpF뛨'kJ"ՕQrIg6h`C0TdW}_EڙY9*۫fU1﫵7tYgrՈ+YHy/BU8WOj R -)@>ehEπ<&Ȋ7HUh4a_hC\_~YܵbU-юXh˗}ӋS~PK6*]W7O!@E:H%RKRԓŊjԣYڶ')ZOiD-X+ &ВBցJ%ҐCH'r:6.L&e8^xz9.aUˇT!.^+"I){p\\zp?ҡюXcZXkޟi|^JrUDC]B,H6n=VdĤX2D Ȣ%BSUƨ 뵵\ҡh ,"Ut_>/9JEl{}rs)a~/VC"C{ӎ`R8PoWR!'窼y`eٗmq,@ J N>$PTȌ FK=]cQ-0Yj%&c`<@7i Z&}x#0^[x!"F 5-O{_9>\j?5N_}?,Jջ5&;ǣC Q))DO'Re%Jn4Gpu҄zh@ jctq%êmVi#%0fؒa9FcŔVIC: :sRZu-keϐ~QP(P7ʙ^j*1]F=2D˕uda|0)0YlBOb3Z(u>x=b(2zkXC|v8cx~W[a*`!ϟ2BfxDT$ݗ)50Id". %U\U*`t(QUy.ZfJBI%iI#1PgDATHsU~NS(S d$gP8kmUszf_~ Fʽ N)fM|41ɉ`Ä,W0PW&%FVOpɃco^Ljt7s 5a+ooug&Pā19L^ā*Uq R;+Mʐ%chٙ DFpmDF,dj~]͸&F[mma re#(zY–@OY|Lg,(7Y$Ld6a\6M2eR{/~?s+1(XF7bhn&a;[ e|#|? 3sÁ'Nqt48cPF9 WWMH9ZYG%c!qq֝#Fxz:P#1@-z@zm=FBw% 5 &b mv|.UDcsZ;ڕi܅h>NGNmGE跀=taآ8BԸ&8b |(AѴB`cB@[:|.TnUMϮg50i U5({s]]ܺ.3IR]yopS5bPXh Fu S6?KRܭ{[*fխ tcpؘ "f\rjPc VtOJX,wNSO?1+@_\:d&;la(4t/\dfn8ԈMQW(Joڔ M{޳>4^,1TN :ƹ`%>09J*YTfSt \5h$)wZ(Z߷'}(x̊}(XC S?>d|Cg;[4 #dEpڔQ4r맰v55;d4c҅YdS귪JúsIt:%[9><ҵ9ls @f1@Q%`; $F 2=(LOsCA=ɽ#v8 ژZZKX>8p:> 41MYi]-m]jA+_"N߷zA`Pnkj{o;,ZWCZ1+7*E7~w/E-t9EQ,+jI윾;7w|>l6t6tzE*M.c UIBr;r*=ݲ+ -G@"؁>o ZDVZ#2suoaSN v-]K:DcnZ{:TUKIcV&M(*ټMgbQd%nh}3O{;Qm>~ 5Mײ^z7~?kwN;C;d fg3[YU@3 e{A AȈ(Ҧ)^#= X9TpO7 G y.Ͷ t>=]/=u>~1huƏXC G,ªZw' ,vYxgp#gfOA᫊*II?#.ipuWW EyQڂr:Ѫ^Iu5kIb 9'Za(Vv[$3^&*B2+X5t`QK 7+Uً2zb64 ?CHЃ|#KN\3:_N}>Pd։bס~ɓޟioMZ800vgVn q#gpcgak6E8N Ԭ3XmZYN+ɫ9G8oȤ{BskRȚ*T #@}ct ƬR~OV.yZHbAҺ ԙgB!@ 44sЧT|ߞsK+ĩ;0OyU/66GVbXƝݏ|"[ =C޻]."dR [LDwRJYF2*d!44IJQၨVjO3,t]>"A>m<^'2XYӿv:)VթeK4#Ňv1]hy&bhIA[4 ZXsaɻBU@RUJW0Ĕ |%C\Xk!vЊ#߁ԟSbe*+WmV[ރƱ9.ٖ5)Q)C"(WPL$YzS0Mj%3~< 2͖V~L{NeGbb<\ Yr]N:ehVT2r:ϣj|B,-0M}_l|X^f'63o"d> vn|}c0:z#Coh|#2={]w+C/;w 7%_Kڳo dJ2R^ls 72@@e+ n&5%;*'$QުV.tӉV!:NyniJ72*p:M*@5i ?7D䢚HvIj&4h?R.h=qՆ+`0J17E /=<>L|ChX2`՞YԯŃ]gEerbJ/M9GrE0 F g q#_yLiIYRiͪ2=eD%JzP/d{|Ú,6!W;[yoֳ T6U2L'/ z5.vUM9N+NݛxyR.4P8& IDAT^?}AA`PnXj!ZS W:JVWj+Y}frY;k8qY"hilBX* 9Tu\J*f`6P)EҔEOAa`Չũt᪍m:VП!e٦gT&3KFR?$BFJ1&ȲELI Q >|ZՕW96y9E8(XG=/~j, o˸|jShӁ/3:#N'>=Y-K! Rn@Tz#5.4$e+'U&Yid_v> z9R3촮5R=>]Bj햗Yk K:&LXkXv;b%OI0s1 > pF҄iY\B>@}WzyDZ}Cs_yo )A:Q bebRltx_+/{} vgFќ!  Bd{j9ap2K/=?9BAW9$oW(gBagaXHv!C SNPL$)%E™aĕIz !(mBy0K{ֶIlt=^y@k\9D"倾EU"h GЉ .0EeûkBCΈPC?X- >}d ' ^} s_~<=oL࿺5bG!TsiW<(~CBoTt7C+U=\UY)U&kנ1Gû4zV_lZP+<u|U/ Yc4!c>z^֤9:qπcy+XTI#z*h<+0 I*S,hgJUAuqn,&)>ɂ0Q.s; 1Q}5 UE}xqwsW [#nj[>n{; 76 9bMﻘ{Rq54_= \᫷NwD@l֎> r hR6of'>Q |٤$P#A8}w`gӓm+:O qc*T^-V# i87.f>!{2C[d?&5{約Dsf1]oh).]ҥK3`dswWzPd֊o▌4MnG~ /6n9*;0g?,yTUUùac6fo: IbVVoebKrV!(ؓNSG-j,zRZ춅euѮ.nsh]0Ź$i$sa* SA|]!0ڿ!} e4X$Phs@\%\:.\8 ^l:^H{^~'Nݱuk7Z qKfroǝݏ2.? =؅Eޭ'?LLѥ0:Z6o^Nw: =|~ 8*8WrdRJц93 5+5Iӑ6E(Hi˘C iu(}gz9AK)hYSլkEwmp.K/FmW.=Tash.$o[n j Z x m,&o0_l~) 毽pӤu9Z q͜"8ȣ//3-dumt5-4GU u @/?Nqi@U!8~8x1[@S|+W9= \VROd6Ӕ@V){pɮ޻ԉ݊ne!!@$L0\ƞ>sxD2fa 6bd0 A'UyuXkVwKgzJΧ{+5`)cTJ0_43IV -7VE=< R֪5T$x`Jfi=+CQ7Tj}WtflQSjcveB^F)]t޿73*~,JHi!I2"6'֭tua޽SlDk$?Β- ݻU- ?ylϽ/S U-{s6}(|OAO$diBDe{f>λFҷ1 I=:K3?Q#!ԼM^-L/ 1)..N)7UƶL8UucXTPokO%jMb֠dPI+1{`U0`%ܖ!J4HֱsnKnѕbߵ h|]Y侵Ўi1x&xw7;=(HpsHֶ>#IBy>rdPԔo>0V6)(y2IHSS{-GBi7Eb2Fs4eG}64G뺍Td|qݱ £e€DNerhJkmG/IaGHgr”$Jb2\N GҔB*#%Ug4vUs 'M׭qLܡ5o5~*VMaD(0lwTJ2cYmN^*Q2*SG 6̴fiF$w]6Ư@u']^< 5|roO7V xܭZ< x`0湪ʙ,}هȲ8E+6 <$wͭ - !G7æ: E9jިJZ֫}Zejb^},冦ې(H)eh4_1mgDX/!V5RU 5UWaQn,uIE[F 0-Lʀ0 KgKyOhp ͟ga`mz*UN.˖6}V{QޙtU[*G*Mz{5ð>2Gjq~\pDiaApU TVWD߸& ϓHO \"1lc#l9_-`da=S: m;w?蘤Yh =l8|s0t5zTv^fr!0& o=C&Q֊fo;znaĘEY+L\U,STZDj^&\V8_c՗6 !iZki4D[oJZsxB+R܋(mD͟eJVvD(~*U-^L w۵SJ-f[N<`U`s~?/ҷ3IV5UR$eiO4 u:hp>%/}E5Z"Dd4(I-KY~bj%"I)E8 Y;.,'YS@"XLiu*Up HgjJ 5ze uSnDK]:Be.ˉ.B:s1GYH۟8-/ǣ|S L ,`cWVڊ:w3<7gjL=_'>w a@e!} unsei{7W܂Ȳ$q /\v.}+B:JRzU}uw)$U, mlO Zſ J7P5TBc*LlB. thtY̝JكE~Vf!)Ekѐei$#dz|铟-I>rvWL] vBڊZw-fwH~+SXUЎ4(:A)PStSz׿f{M\r8\zǝ6ٽmhl@4f.KFAI^ P̈́켸ɵORi+V2׽W5ξ25…^۴u%hIQ`I*5=)@gS%Gu/9=p1{<=/>5'>e J-Gl'%{UK~@;wퟍhZbfP*_*+uۜ;'AE$ITUYv, g︫[7ҙ5FJur GS@hH&Lշ=E oVrM*\sJɪ-c \r`QPܫ.Bm*@/w$ ȵ'ͿҶINUzlSrw唲U14'BN؎S\e>tA 2Oxx#Y6.iBHCfTDU3jrǞ/5oOJ/~$R$&DQ8Txd 2 ׾u{4'DJqH}@eF^l' L9 sej38L)GR7D IDATrOWYRV5S-s`X^e#>·USj E\SZ5UF`ll' ib'@6-.y E[NբŌbs+#+X$}x@ pilojtC<oI'b?\WQ:FfV10u>RRFh`t4(ϥ6`qYmj?Yc#ysƼW^&:dQ[Ԯ^/Q6}[ŒeQ*HƐiMYA)X,Dyaxr;0Fp4`42n#V}f{*hZh VA.G!J΍>FFC y{K߷7 i"%?vyo6Yj;/׿#u\FhxZyk/fֈ(n4eЦ6'(:nf4UnI cVn_x(_8|XMm,%Ut f17r J,U]*gxn栨={,T>*e!I<,Um,,.]y ZhT-f*A[>1ӻ{ RUC7ב&+c o#Vր}E!aV˜02L13d_v݋L)TV)K`f߃[X4PƐzA97Pme*|V5{MXfnA*Wc!>r};ѹ]J\̣UJ V W/_$_]s;![-j13hKG?|?η AƅڣTF&iLqHFVqbX9<;JyR)7|.i\±qW7 Dprdn:zAhgzCKq5t[ro &ŋ*#jۭ[W5{Z)ctj 076WSUKVą9^d#@$RggJy(ZD{j1S(U\|×QIո'k, m!KFwC'}$h!v\J{*!Wq1ȳ_)\ --v Umd}A %UJf~y/9ZADyuN>jH8UjUƽZEpxOj^,+\p ʭ¦5FȪkft-,TJ=cG)6GrC`mM7ŖByiqBxO$զ:5Fe*^>u*Cw:yVx_;cY2 1& ׹B!ibKL&&Yvā=9%5Qc阌)?nZj"UOI}:ꄫV4Uּ0ն7#&JĞ͸ZMr-Nۺ/ )M,.7^z'FMLg bP#l'^m¾ QVjvˇ3]y`t8&N1F6vbSn059Ws䡘_J#ي;U;ayp˫;AѭT5_Rd`1 <H}/9\%URݨXIzJztD`v VdyJ!FPzqLee\^>mJ\y xg?I@I̳rp6#pUzhR-f 08q\s u|7~uɝI5Y8<8VB>yvU/jpmFD&'w^\#*")R)5ە1m%Yo=MEוIO\u|G?c^/~UATJNKnx6t1׽H,?sh#lCkpߺhg)乍6mI㾷/}[B(gQ14e7o#,3Rcyi277G=EU/ֻUOy ithU]*yqtmZ *`j.C{AZ..cЫ0t2(9O'y.ңOjqH顔bqWvmďKЭU=˽%h}7a lZ),##y$W~ tzH#Sa }ȳ!J Dڕ#|ueKNo1E@EU$Ҡ0{%:%[FZvSR:`WɕBPiTӅ_@E RV_þM5$$€v~"{KiǽB<*\BB$'FyRZ&RR"d, IEt:t:ehCF.a5IO<]bz/BDc}gK6g3+Cѹ P*4Mh(r*@^)SRjڲ͡ԂѰ2]I罂7F+vwë'7}AMrjtq>ZRG)C(|?`72Kt;¨'fyLQ#Gq!666H8+h.bĞ'+-$oϲYؑg]$8'ݮ5SxϷ?;bHuWs}^eBLmFSD!?Zqq0CŢh c_nr>!gS iR  ZzU4J IuPgTL_5SFfiZk~!=eN1AqftFM9lh6t։$qlLCKZr&V:e,ɚIXu GXg8evvRY\qXdfiͨ_}a];s,^ȶыȹMrdXbm?H0L<5HV%eɱ+\U6m3y˦2VETK뤰NDyyә퍰݂Ik <)YN A-W6=Q']llF1ggM}?ō#}Ix`{3r/}ӫ;Q*sc\In127P, %`2 ´򗀩>;X:Rȳoe%_Rڈh6kbS(`w#\:&}}[6é%YU|141 ߺL0Ga;ybK)]փJXw>(/C奚ڹs,H#WQ<]g}!*O:G)[ :Л \Ƒ@z]9 CvS !2uv )-c~XyQoAa=V&y&jj5UDlU(I#LY¾&M3 BJAy$VEpwN/d<7UopݫNaI 5o]1 -f-:-;e9;훥oǶٶ k<)#,wre=9Cb t; x^@76=]0H(-c|a,,l]>G>sW.$Zfbx v(%~n;R只>5e)dY3_>l.kӬLF;Y # ^Ew,-f27.y wOw$I7hM[bfy-:yÏ0D,ܹa^RdYVZGdY`g}}8NHi?YWKD涳_sJ^E;5U_9ʌnG]8+Q:]̖B7]&_ &jP9}\vؘqK xw .;v<%2!iS ZeT9X0[J^_Žo|C;u޹){&C#Ȳ8$7ɲ:ȑ ۖ 'XOcU B0l<)Xɮ=%}=sk(Җ  ȕB8]T5m^r4qsW[XJ"WPclVW<#,L`Dar[1cԏ8D,c 滭Sh x]ג$$$O5gPD*X[ mr;g+yP7hy};. \gss5V!aNII[NӮ{N)v}Kx)gA)Cπnf\}  wv,4BKaB9c9FH\ANR1Ag?MveS%Bx(!tB Rqj -IcMЊ gf^Ut"թY┱]~nRU$'@Q ˃U/Hۡl`@lM%3t:@iult}~/Y\n7yaNOgkpߚhP-f [iǍsοO>cv5AW*KlwhN3 ?>~:^7P#n(:] ΠUO2PpPc?4R5Φ.z{͍Me\^Ղ]}p4e#5>QHĄcyҔA'eBxj|x*X[m̢t ?~4 ++\s%KuWO)h0;^b"Fy! ./zQ;ŎI/-+<"g?{{X\I3\H{{C':RU%yߪBgNf X\ɵّ5f_eLa2dʳ)T& K ;l&KU;V yD 8Dә#rS{c A&(w OUa`mEA-YOࢥU($EU`gY-yࡣTX0#Q,cR ,yfǎ 9|m1X_7b?mŻ '0.LUeVV2C*SAv3+SB4W Eq1rU2X d*H|[mc/jʡZ+4" 7.ARN(ƈʪW:A,C0L9y+kCF6aC~}$l|;y&ˁM1: k9CGDs9MƐ,H$ MF5U9}>pdЖwKz}6 *9ioj<`4)|hWeZX$r@+jeÂ̱; .ma|c7)G)ayn2?^rRAl|g)=Ϸ$GJ.̿0*Gk0aӦ5eUDX~yhʱ'BZO߱A mPۧ+Wb#-J!Yy>p]u?Qrm||;.dm]3יc-S*.t$|$-A<g^s|?(ʃJe4+W9?UU>Ԡ%FZCw?4iuHy={0<%b z=c4QD#{漿?궮/heK9R%jY2*$4j.!]}h-*U+qB+B($IFn,RS෿tBձ xg?qZkk%X-fmӆn9};o{ kv(U,SГ |9Б0a9T=SyӫG' )}7Y)"D"%MCcX3A\}ZGa.E"ihjVͶh^n)1yn2!-խ#~'u}l>YVw&a6#,&Pz>.H!g!i=X[-j1sȝ%eKN?5zo77K$jt֔+ 3H-.F&#N5Vip>qISE`ŧ<6~_YBZ ޒ,G0˜ U #j{sY^.ÀlÇp]0Bc EG~Te1i#DNG@Ŷ,CE3bTNK~wO={k0A; 09ٓSB86&!lA@2G'xj|{_NBuA<W}tA-:A?M h IRͧtg >~)}#eZ'!I N{[ļ m`9Þ[uv?…KsT*S#UZo(YFK9'g}~hTyLmTBt2)s}}@CߟcNiKe<<_&}tvg08ľk{X>s-3[B|O龌qߙsz9a\uì_+tOA[mV5+zxڱso8ж|"I.T6sQdiHm0k&66wZA[pfs;0mcsO~$0a8<|FC$?W2F#@ mlKN`ě.,Ou6<8=O<`8$ &vVDޢZ4Dkt?+pyp[牗wRE9p1}(hVǒe!*ec{\p˙i]1xcFptFk:^~lmҧ2۽`t,<ԑ,c4Jل( F>_K@|ߏNҧo?9֋[fnn)5ߝ~hegFYf0t;h#a7 C\tNAo#{h%~Ld I2|y >}]y ܺh V%Y'PL{_˃k<m70YHAY螃GW;w\:9 {J}Ϗ }m+"o= OH撛Y~I1!lU |U"E)|oq[ɡǾ×}̕6PIʓ3 ݳ#ß7X\IЙY`Y<ߟmt<@{tRWI$I89a?gvls!,$рUVWz8(}ov_Yjg%6dE`qQ g/o=WD6Gr`]Ų ǿMU]l#=Jt Oc}uedyNG؁iOȻ_MhFTB BtF-%] V0ƪ1=q>{v`ew_t:sA?= {slgyі.?[$J%Xg-<\{Ќ ^-+TR {V9rt£9G~` GC$dB7tY$Cthll<7Ny!~]A@sWE>o$`E:K^?/G"a}c3DX[-j1&`~>Q7|~xyהB]+ N!`}HùUP.c2!Nj`4Id@ɐ }4%NkaE&66ˣ~Ԟ1y/ S)Z乗A;<}e8\]^w.۶ӶEk DI?GB["l1Pʖ`!-oz},Np01N[ Bx^d isvtI2BH`1qY젴"3X>]=6?BH}?~;~sl_Vᧁ7#@J W|K*!m;fa0F)=v$i;5h VDQ"4o7''{|EmF!Lkh0t Hͣ3tt:J c9}뢽;I(eonmlិUwk&wS8BAifhmMyh(ECFz/{,I, }hnw )}Fң a\}\J.Q?<`MGTTi4XatЍӟ ߼F_0۴ k{p N:'%T<ѨFaPg97zeM,1V2Xd[n|RGws爠8=ܨ8i4u:N hbm"\ - zNw\D]Y޻@e"A2z+ G}@!2_D{M H S#[o;>xg\yCjm`jP{{{۶!E k~{qh8ڡ0kxo'l&C"iCiBZ4 Sݽ%Z7n_O٥љCgENw|ݽ!ڸa6эQG7;U.X˃|gGП} g˿yb"s߷!iDG4 S"N놖Lr57]u" 'XS0nf !&k/Yư>Q#WQ65U5Ѵ a.h',KZ`&;!,`q+GTfs>C3:_}+_~icMލ(Jn^/\5x^ؾasUMFFz zƶ[t:uPV0 0֮"FjH S+%Z,J}Ws>4puMd.eh 3Y?׵p] 1i*сS}ly.DJeVuxA<w?P*/ w!bR;V`%! |,EQq'P$s.z61P塬h?ǘlvtHlCէt IDATJ5 A}9c[XNi `hd=5${=E-B1<7RH _?<}#uƒ|Yc ~ᇆ?~Eqttޭ,l\<뮶3<߳}wFXhDZ > ?;ajuT6=CY4+K-J g|{_>I`]v)_Ə<=__a<8aS6l@EvD/&lLKYnۆx<3;顼JQB^Ѩ7píw}ᙬ9G >gvv>\bI4hDZD}VӰFwj"׳1]6>5Z4@°Ͳd@N,1<ׇ`=PKwpן1f]?{臣^Pew1&¶:XfF}zFĴ, ]R~ ǵ0ne[QG5Ù(,B,1V2XH|%7lܶN^vż^)IJ;ZUxjiz X OaU~h b-l{kqhח,B,1VJ;Enя bv}=mO{xit6nNED[m6Gء_:2W^[NQ%Lãݲ46lit;6zבwg~vOϰkJIjJ~G~Y'E!6EtQ* vEi03ѯ/$X^Rkvݕ7{KD{/Q/BSe[AkDTZL6N$WQ?g^sw2}'xpZ C_LOw> #Zb|@KU=ހmw6%fޗ~Hg_g@s!4JCf 1f5e2sOU1lf[ˋ]^|sOWY<СӲXsy'3-xv^y1%MyQX,A,$,BӺ$%ĀXft- P#Dc*lDdd:A ٭H'}[ >R-yHi3Yjb:ۯaE*S3iW3t dqimKMNJ 1$b.p *⤳qFW,oݶCmzws_)>0WC>m;R͟mK~oy.kygy6׼*~8uӣi4-F{!qд i6;F4>,XBnfaxT4gy2Q/WEQp ObQli6VseѴS"B,!8Gf(RL6F2#ƙb>ݶMilȱӑ+y>;Qڛ?╊S,iF p]qpW8E(,!8㹮OmSTttAU¾[Xd*F`z.Cڞ|LP;p_N4;YyF3?&>u'QQ(xYD&'uʹ;J8 ԇĸ cZ VO2#'qX\煁Yjix\'˯׿ڣNn,Q_^895eS{XVN' LSGUk̜}G{+yc#VH%3tCw,vd{V\/$v;6EG_ћw{k\{ P ro) pm] \EEUUvpSYҩ LEĵXt<:3!F ^C' lغL.?et˧> XV׵QT{N뾥ɨ8su,¡aw0~uN˦4iMl>rުU\1EEQP{!_I:g[|1ޗI k<]6;<@S7",yҨ,-ti5,|?@Ubq-B6194VtG5%SLoĝ_<;4,ܴa/Gijz'!Q7)OJS]6, &hMby_|28r_,_LQJ:ԫֻ۶sM/}߀Žwv笈1Шl<'O}fq,{"M2XBAe4javٰ-EQkꉩSiRű{s֩ }_Gvź y|Q/Q Zxn6My28{^lH+HK*V[K a+B1AiĵbB)ctpOâݲF졸k--Ѿ\žgfFDq5T&Ni"E{;]IQ7b']GbL1g3lY+8w{T)v;]{Lx ?-W4.:- sv ┅6"Q7G1ld?oޅ0φ;|zGlܶcī'q|fDb*ͺyW"3ub @,!ٖGiХZ1 p`u$)Oې%Fpo,n~dbQ@a~z}K^8Dt:ezt;MmgHD幧>-B!PؖGuIgj<zlŃnx0ذ9Ǯfu \ W*s/ )|=^8ABi2uuhPW"$,!ĚpvoBn݊#1JI6(|_7@y۷1`[ssyھ sOU<1byOf<1y?:Jm,jVsϬkۮiժ|x*p'_~zyU4jRb)q BcR.V-B!]Y`??]cYJdy%.| .bLDӴHekqb?X [tZ) J1$%+ޗ<?}xoPh(3Y5o&Ϯiv]f_DŽ{wÚ][j%*iB`c blyn ۢQ3UU#h(b^v+( 1Z-b?ˎ7^ͮ-SO1aЮ)NLfQ; Ty*TqʅbSBuC:&$UCy -e2er: @aѨ&ݎ3uLs/~p7;EQ'[(:b0D*L $4-|),)rH%X<ק^5ۇL\>V(y\קհ.wi6 b뮋ij{Wow~i߯z`j&M8+iϬ"b$BqX!I B*M$)M'ɺVâˮwo~/{@L83d KXBJf3qҙ8sAflXXm_"̟lQ 4Fخ!'L>X2Y&EBtZ6%{Z[6(gÞ[Z \C߹yv] l,ﰼct TD*ٜt [ X_vkŗoߍLͯ#'"Q(@uOnY&Qy*i3l !+L.f9&R l\!Adb?0WMj_d?ag;{EhS.V1zBya8D,!8 ݎ/|FUr0+$Qf2Ldh6ͺIc>x+[enQ>qvlҙ8b"S(FW8gx%'O,!8ES*a|:'_H01" _JͺIyJ_x^4!SYd,XXE #\g" b@V[(M( +RLQLqޅ7m\|kOAbPXQ7(LΤ9ygx;x;|I%ℙ˾b)lb9nMNNoS[֩2Ah`b)Ii"yx%-+K!)׌~HF)@dr:M"c<QWíqn-/t9If2 B ,/v٪LNXJ0=!?vBgM[K]6([X.q <>Z0uk$BqF1 =/6bDWUNJŘI35fEbʒޯ7昙˰ơ"w[9"&IDATZRqxT[u`B,!gzOTb9Iy2Ld*Ʀs l:пv^5@lA#S 9k,QbSarK,!c pOdWkIJBtCwW *K:K iQIf2D6 kYuط|XB!V4R*'φT9PV1.Ԫ/P*'N,r t,z)J,!,-t٪lN4df.C~^HaP|CeIVOP}iL15!#r9\G"Buݲh,^~nML)N٭M97h,ۯrv"^7M+|C B1bR>T!M. ۉAR;qã%B!ĺ8YHKiOkۊY.` !BKQ&(R$X;1,7Y.B!8*?Pi17OSB!ŢX;Rr/B!cnPH%B1p` !B XB!&B!ĀI%B1`` !B XB!&B!ĀI%B1`` !B XB!&B!ĀI%B1`` !B XB!&B!ĀI%B1`` !B XB!&B!ĀI%B1`` !B XB!&B!ĀI%B1`` !B XB!&B!ĀI%B1`` !B XB!&B!ĀI%B1`` !B XB!&B!ĀI%B1`` !B XB!Qx$"IENDB`v_sim-3.8.0/tests/exports/field.ref.png000077700000000000000000000000001370110300500221302field-3.7.pngustar00rootroot00000000000000v_sim-3.8.0/tests/exports/generate.sh000066400000000000000000000011651370110300500176240ustar00rootroot00000000000000#!/bin/bash DIR=../tmp/src EXE=v_sim-dev VER=3.8 $DIR/$EXE ../examples/aluminium.d3 -r alu.xml -e aluminium-$VER.png > aluminium.log 2>&1 $DIR/$EXE ../examples/aluminium.d3 -p ../examples/planes.xml -f ../examples/density-sih4.dat -v 0.01:0.05 -e field-$VER.png > field.log 2>&1 $DIR/$EXE ../examples/test_isosurfaces.ascii -i ../examples/test_isosurfaces.surf -e iso-$VER.png > iso.log 2>&1 $DIR/$EXE ../examples/demo.ascii -p ../examples/planes.xml -e planes-$VER.png > planes.log 2>&1 $DIR/$EXE ../examples/aluminium.d3 -p ../examples/planes.xml -f ../examples/density-sih4.dat -b 1 -n 10 -e map-$VER.png > map.log 2>&1 v_sim-3.8.0/tests/exports/imgdiff.py000077500000000000000000000007771370110300500174700ustar00rootroot00000000000000#!/usr/bin/env python import sys import numpy from scipy import misc rad = sys.argv[1] ref = misc.imread(sys.argv[2]).astype(numpy.float32)[:,:,0:3] for i in range(3, len(sys.argv)): img = misc.imread(sys.argv[i]).astype(numpy.float32)[:,:,0:3] ssd = numpy.sqrt((ref - img) ** 2) print "%15g %15g" % (ssd.ptp(), ssd.sum() / ssd.shape[0] / ssd.shape[1]), ssd *= 10. ssd.clip(0.,255.) misc.imsave(rad + ".diff%d.png" % (i - 3), ssd.astype(numpy.uint8)) print "# %s peak-to-peak average" % rad v_sim-3.8.0/tests/exports/iso-3.3.png000066400000000000000000002372201370110300500173020ustar00rootroot00000000000000PNG  IHDRXX1sBITO IDATxyeU}{{_YYU5*k00 $$h qnVY`a ݃h`fPITR9++爌xýg{ߋ̚22<*ō^b=d2L&s"W2L&d!d25ML&\d!d25ML&\d!d25ML&\d!d25ML&\d!d25ML&\d!d25ML&\d!d25ML&\d!d25ML&\d!d25ML&\d!d25ML&\d!d25ML&\d!d25ML&\d!d25ML&\d!d25ML&\d!d25ML&\d!d25ML&\ӄ}`ٺѠ}.L/ Y37-/Gz<Õj^Ԣԙi(KßwgqRW㸼}=JoFL?^(g*\bjej4>Ld!lYamP88U^@kb4thJ[-$E5-ٲXRnl|sEӹMeQ5ȦͽM{>)ܸ\ r5գaf2 Y354XnSF@4顢V(LM{GSPڞ.T'R)!(K߹3pcL+fE0nl+hX//G<ҘfB82k,MU,PaBJDN7GUc}.wWU.&ڂdc=?#QT\t~S7spm?*7F8=O5Yd!l0Y)'$1mH'݌IJ4w3ww7hl=UH退BZ]6/Xp꩕Ez:;_17z3um)x4/T9ܘĞa FI(5 Tq;Tdt{E g]E\Nj{7'0yLm8؛ sEo&o*g犙 Yz;w5uma,zx4a‘d!l 4+o}+`P1FztAUH hEýFS 08HFҕbԭ&9G${n4/RLhj7;Wf4 2PEO=;=#@d!l 8)bUPMHѕnPQ!FMfYl4N sEo&lTf|+hק>vΎ$ afcvBar2eFIU7"Ȋw7E&9nJ7puF&ֶxnN^EΗ熗i&NB0tV"RDܜXCa7@Z *ݣ{zs3P@IiQH% %4L.`h~So> afc0q+KCNq7{p1At#]k3Qw#&#]ݍ q:c*J/aA$n9vdjN&B04l ݔСm+̨Nw1+H 7!b"]SPɡ Rf&n2Y/1+Kcs >L慰63qP T Q "Jy jDHJQE"B֋fDӓfJb\Agf֙Gl B!v_!>PlE`f&bnEFHZiFuc&b4^< {F?=}Z/ /lTsYaf0qX;]D` 16cin"4N0g$ 2#wP9TX[m?Ͻzs\»ʋNW/[,l>.YCf6 kU:¸Pڪ9T]A2F<"SQ51&{MwiN%Mi긝λQg~WRjӘZ`ZѼ}VGxշ+{$Y^ܲ}1ɼxd!l$YF( t̍H@("H8 IHs%7at 07]3X}ϻU`m!ȋ^L~](it$~w~ϕËqqaiL`Ӧ/xd!l5g3^PFCB]$.t1;L%kfn"htWs!EI4K7^tn}/** B ias;vƤ$J`@lP#}ϻ{w~opXRHd!lk -BN M#L"] ӝ$fBJ%h t .~=TU4;;z$2YuIi濥GڱXawz8Z 8IwϼZhaJ-/B/ afc'25Z;b7QJ! u-MeE[GA*oU$QD2 Q%%U\)m"Z\S8AM%DeJ;TYk.SⱣiE>_›9͙pL% aZ9!hqtxe^^Wqe%F#&E$U&l5R G  6-çDC[ Wx35c/,Igs%ȿAҬӿ??qI?U]#(!(47A1 (if =)-/-Ts-<ݷޑؐ(Twx4p_.SxʐI  ;~yhBoӃ5Y0y B8d#L_O5.G{s$>IL/t'@*4RQ5Mh&+zLT}{$0S7qwϜ9]oٚR@/=۝kPk67t Oۻ; zʚ9{!@];3zY3, /qMÔ'_Ep.VDw7I$,4ɶbSUڸxnFl6'dL%% af@ª#S=7Nv|cڏ^7ԧN<gpLh*\ml~q9:mI嶴5:GbOg@VUUan89^YC-4[Dv~]+mkj&⒅01(J9\^y';90[v߄KYMSq6%q &*S7qBsG yv׮.cer?lN$h@ tYywwi,M\^e_Ra Z ZPjE?Pa"̄0B/jOT HXUhP-#U*M"N> {_|ӧVH,lyae2/="l B==kpM~rn dS밺]د%.\ͺϒNӓ Hogv~db!m7ş^꺔R Cb(f W 3UYmhunu(gwym,No*B`Z53,ɘ>E[殜0uN.OBpj#;pك__ٸ9r /mq@I ~MWpzީSO&_A5D2uzGM厦e'=nV7'PRnLN.c* Zy2PRjyxk!#E$ZdlmD= |1FS(※Hk;,J՟-uɬgEYGwӏ+7Ä B̺`Bz);'`BȔ[)I S' $ڛ|Laf`[ 'IiM  LJ/y$K17¬':Su؝pSh$M$Ygf6zLj##T#\="u]jFULHlQR1Mf>{?5ƶamI&OR R "AH @!2!ФL^l8ަ4ݞl=Rjr1*GxWD EB {"PiBE诞×S-RoE$E4_;~D0+᐀LH1= i(r̺' albzYDh9N3A"A4RTD鲒!+69Szm_nT0.M*xMT{p.BR7IU"ML-!AKppכNZtfUQ Bmδ2/8<#L"F! a*58wht37oƐʐL]EE%:!T"vF40!co~ D\rV"ürTdR^+`Ͼ IDAT‹}Y!!AwΥDPTMXP!Dݣ1+hl:L&vZ(" 7m@idgvyLuOէx؄cRAws3kFI*Y4162"LR v"n xQc-*<@$ iBt's}3_u! !4FSC2O>RSSwӹN} TC͛c?獃x,lm]"̬wf㥷uMܣ>B3 C(c$P$H3BP \/8omBvTg׸ɃF@6&*pH> 2B) Mg&i7+@$9я;ys8-+*m֭ر;vG'IE ,P/#0X*g`&0>h[kS IRj(۴RJi< T;Kd5X%$}{[)UA'XH% ".ij MFm  !@H܂t?'ios̺x5ftmjӔzuBcdfkXM̆ ajgi K=)9Ɠ9˞BDwTG۔.qTEL<C?SctYMiQ P+9sJlŪTLww@yb,Djڬ6-`2DX((1hN0[ޟ/~%muqsٟWLvf9Y3W.?iŤ"$$iڃ;Ȧ{c9'9iC˼t7"EP'GYFc~MY]6\YVcl{X :pHJQH'عԯg>҄->yzuz&3W_}䛶tjg)kTdF+ZjA4l HVYyW_PBRA5IӬq]Wu=Jc=k]jTUp<UA#Ybg)tcO v3<& a*3!mi;R+Z4?@ɲU2_)/ү!\KDOOrGH}`V8q'xOWxTUu4jq1.-ct3'~|?_tٞ1}![g!̬_k4`jUtKa?!k8L*b g7/ERsF z7abl>_={.Ec:?\NRK5f1"jc jn$KK!F1kʊxLHw Pw(`fN.#2MUFD& 8پ탿C8۾P#0E^nf")@ګĴCGDϥ2q-RЪ[7mVQ7cѬq}{\Ջc#}e$WV|4r;B)CH3/wOkw@Ϭgk4sxG1it(ꮘT)K.k_-5U֓)R85Sjۚ_M>vknoF"8SxTUx2>w:w:{ c-]8/> L~asRBjlJǟFaf}-')R;g|ϟFʸ;`rdHK-i&IKPxr*A*\v` WM= }vg1Fj[R$Ĩk+F8xl"6\uQ iJs<8^3EŜHY^Q!iGwtS^w-4"Yod!̬ H#9/%#RNSY} 1&ר{=aѴt%zϯޥ7T|v\b/w Yݍ$ЛGUeaig@n}C~(f0CjᲗEQh{QQ9<(ʢϼM_u[ ]ɬY3W;{?P }߫$0 ܀m?uǣN*;MD0wԬ/@tJ~\ rj"g֤%@"ZUmr8LT I33N|>^sE1fL164G>nw(B7sg{́O?q4 =?~OvnJ{g˶?ufq?~ҁyYFEƀoR=.dױmhjS.rtNvY]͝7.h\D H>`#e97'hO5=pM/WJLmHE +O-E!UuU2K0.?鍇еP ܭ~ O~]csع%2{FOWݶe& 3,uܽ @$8ߏrp˸cܱGoڥ7]'s3[ozÖ7&-50q]/}V{oݶn{iӝ7p23ss]|OH#LMܚm,HKH9QL ٻj,$];7K}{bSf 0)*ZČˑG>ɷwn-υ>ɼDd!\}7{>=NwY\B{w3wt@:3<~+3v-skwskal9{+CVN SZGR?>ϖrY:i\L>ӽ~0Ť*EQۯ!Z$biK=tCZc2SE+hfn!pn\GE`f?3)uF:*.p#\.MM@4UMecZ@\ ?g: -ٹb–^H]7̧\Xy#<?ڣ\Q/)U6Y7T>=Ks"fu=O>,vcv O[ 8j4Eh{!r$5c_C2u^{ָpՋlfY3p:ֺ&-07ö\ t mn{,:ArR%whW彰yfӟw_isO~rߑ?O>_]b50n-?oThZSMe1>MEZmf<B Mo "t磺VB Rx]ouvPɬ/odf>AyAOO|:캣!u8Ym-Brss#~΁\;our{\==Wu/9#?qG<XNxnx߱}gcɷw^|ϴ}LjcV5lsI}bJin*fbWtaFSLӐ_EQUBwq5EN>$-YoH&0h\OG@jelVMI۱ 9J]{\}_ V>=n߳[nض[ska~Ͻ?48sđGxⳏ}x'_?};h*)kX3KkGBl}K鮩֨0FM+EĺTIY\CPH7O~FɬfInu[4N|v7-QH](}4z; p⍗2Q7ٖ/O?GM{m==޺۷޵};o:ѧ<شG\sCi;fNFeO?oc̢fE>4SKWUtԉurdY(Z!LZd?3aTGRprx3ǹ"BYtN|D*"I2zW;pSkoT#3:mgN=q}T={-' ^}쓧;]lsy=xa݇m-؎$1_tzG_ndiwwDUa!b(x@P$(uw` Y3,3&ѥNxE˃dAH*?1![} όD,m]#AOFV?XZ>#@ڒLu}^[۞/W~ȖVF{;X<>~~.1i]bBj@#ꬪXUYƋ>K+032Nq2h 1~eQZD J,2sz|g2/=Y34!f%P,>i$ ٳ$!DJ1.YPI TDOHlOY;8>FCoU,;Lo5ۯcwxӽmnwoѽ/4?v蝟ϝu+m.b܊'4]~vܺ<@DTU"Fs'#<$d!̬#f>_x?c)S$M;hswsf tLK?g8}ERK9;2adάҟhtv,;%Ǐm[y}w)\#\3\sɼd!̬޶;i>Qf!M*M!n$Ru'J:4О$ITضl*$>^YyoýrGyͽ;oMsܳ{v[ɣgN;sѣ{8pѣ"tXU;{7'56)ik^QQE" "B(-.daoǟ׍d^Df ވ )Y$ n3YSZ7I]xTYݬԤPT6.E(w*p§sm߾?~xG" e~wM3w=%Eܹ{^%w{*3:z'Wjyuv8i4DQ+Rs̪x˼TDAUɠJɡ8֧WD̺! af]W'N& !"&ivpSݽdMԀI.c;XflOS) rg:P3oUoKhSܖ<:̣7|򶝻r;_u-wyö]d2N:zN;̇c*5bCJQĬjBIz33h !bA cuDzw<$KG̺͋IE.H R@$+4_kg~3I`sg0?B KK _vI 8o5`N\gqrG}_M^v/eoض}^oWy%l4Alk4Wz?k{B4O WU" j"I-Z:jE9d^lfg}cpKda>U# (i=*p1 p725.w蠊6112Ȥw7SHC;被 OyGH75E~]aJM|vƧ:uC@`nm6am.QU1Y4^_cEHΓMneQFGtO%AtV%TP5jjD#J1'/0NBY/|-1d$= EPPzI6ɻ^wIw4 ;u`OC.v 5kkmU$@W1VYͣ[4sGSԑ Ka~Ӆ3Kؽ/yeX+ ݾsvt_C}؁SgZ+Xy\MC_7_M7~1HhH5WUI*429nġO{0c ;W>濼N7+ ҚvZx'>u+|?hŗ<.y'?(o\]Z|{:$.TՔ4eQ˚,#S {р"PP-lb_YnWO N'z|7#~Q#YlT~u e""Ur(8?q;pJ8iEP Bfs9b47d86iw7|=SOx|էڸ ?py\v%>Э,v+ůLn;&]-uy!Ĵ>i_Z]G'w* p1O+K?nuTIٽ T%ԎS;@S*Ől].<#Svd܀ce<欵& cR͚R…w/P 0Fb]P /; bY@+$`ڬs"InOM}&+ nX[q/ؓ/sq_ߘͷM[_nCGipdqٽga ;7>NG2ܙ/ߕ7={}$D(A5u)i4F1@!>W}'9Osvm3|sbLMns&Ys+NS0 zЏl:Yﲵ:3Xt6֙g3s٬Ipx[E59RGv˞voyOlZg?)vˣ=p=nmz#k6‡xñح'pg~< Iٽ=!d lY?KeѨY=rhk)esaFHQiؗHΙG% Y4ٵ-HDC\H<% ,`Vu1.f(z<Ϲ- WW[3Zcqԗ ON vw+yF!0ٸGwe o1 &h)H)>1 \{iH:YK4_x[ (lDzG"jL ;@NsRd p2ʵrlsAeD2Et]7@s`~hISw"} s[ 3A8?'W("cU%{vvRDƪ/NExJû@8p1[JBPJ:E@Ґ8IN(@H2n`kbi/|·f6\u|W< UJ7q;9{T4 =Ԑ:KO>2vTRE$P( zTz4_x[H:*PP(QJI4 l`"ru)UG*#QұH5 6j峂nuTR#/xW? dS)q_g7)fq p!-9 Rx7?/2.<JRtԤ r$ڤԤhpO<`}"pΠm3Q QjKXRKQb? FQ҈{F]I?D?TvfNfm-bYU+Q;Ā8sD x}:1(fxÇ?xSw!:=~{C_?,^uW޶b&. 8HfD،@;r D8C|~KGWSQu q^>HcUY ̡bsTfn[۱[q/3#h=H=1k'F) QhTjjft{w>*,Qȶ !h1PعZtHiE6K5bϒf4\XR |}r[ :,vlRgI2$haK2<r]yѼ\.(GXҷCА7.s(.O{yރ7tT) %E(r"2M3{( uB!ZM?7-f:1M?|ߛ+*&CxZ̈0Q$RܖRJMZHiڈDGI6#l:fe-NJRXZzgPΘR9J"&g㎏n w 8{5S#zu D8C|k_ݷ+XC?];߆4XFQJU RBJYliT f\(V\paIj!gzK15#Rxs+%)`) $QU ]0Rygnʁgn 0sa)RȠmW|ogĬ`)a$ّl!E)8ŦY5M4KM*SZLBJcM#M#n2<~Ӎ'Sf_)٬- {wZHqy'xws] .SS#:"p!oܫʨ~6O>Qdօ(B%Id \mo8*Hu1R0-EŤ IQ[E!ѱzLJSe90%Y4 Su?gJwf喔4,?3  b7^>:&ca؊P8/B´V5J̥"hcY] j|(Z;hέwpDB;^(StaTF,% 9ÿ_wơ<.l B*jAC2B~#Z-GE$WtfJ E孽5M˹ ?j4>f xHM^ X%uobR*F,Yn,SnAT=0{Z= ܓ p` ;|.#AG\Й[X=bԲy,HLo a"ޢ4$%I] y,s76\m_4TD7iZ] 7GS"4@8aFwO]WdfDԚBf"nqq7x\fyYAO{G~7?׿/CO=AD!2:Ylxh!Qy˖(1"bj P^gda /9$ /$ACxH„~u ^Ep铟7hoD(|UL4. 8+Zv .y[K2m?y bT?"0D4Mm*h*Aß|ַ?1&>eGШPEp1Ť MX[IS6"IHkMFEUX]Bēݶ붃3? &dIQ noLHtj|:4݉M :; CE8`Gw5VbAd8t+l+Gf猳P4T7<l< ;_$f}Xgw,SU,.J'gQs,$8H*Er@}O=3-=[XdPeĝݶwt`y?%ٹ'J &$L.pB'RZlb*j#2RGw,eYe.3fhݳ{;YgKWW/;y2dX+t9#E}&BqqJ{E Fڡ|krk"pq;}d^h#y`Fu97RVG3%vfĝEc7@Ye{%5 S*IJ퀴uS&pW+QGWXG~0^88,b?ZȲ,}8'OUKֶ_hb/zWo ߻ZTH0R3FhtbG̀g8`ɑyfMiO_\%םT͠٬ց(!>{ߛ2hBT47pTRsgZ݋B:|s78k2ͽe7tg\rʫ )0z=/HRct%> ywW՚XcM${vkN2FwtX#0ဝ"bB$G,-YXؽ8-Li(ѱs.^ZH8k!͕ oC .,'iF2GIDJSo[6cVFSzmvE[RzI R)<7MSwDu11~18 r6AZ]G>fM F8q7!ɜG&{Hq )pYE|[4,.YXXNi!YD~fi)fTBǓopLIJ8EKsDSC2ݷe֬Kw)7R^AuV]T9 ܣkڽ/iF?WobhBRw, LD,κ#0 R۸ٯv|^,ɉfj3KY(/5Ѧi_xrHz={*yɳ#z֋j믻)͙4Da,i49>_Jz{FYvFrӰaVndpN2'`]cu ,^`oMB&rQZLnf> Mw_1`YP8}WӉ)5!uE-!AFgkEm*3iU@@ؤ޾ w_v$j3%vfUikylg<]u,<"vA `u'y*o*BFG)}Il#T*]F5;8ۨ+:z}y-~п~i IS#>߰'_O{U#Al*_( Gv ^z^ ?͹QiͲY{ͻpi*b]a- vפ'o.+"^Jp99Iѯ}vS>NEh*3e! e*1KP80ဝ4 Yơ9R4`ekk8q"=#?]._YƊUá)9< xuivGvl[oomgzёzAldk9^Vb}#bp6& N#+ BJW4lTal(#J"ɤaw7 D8W?zHX*?3s9e}9%={|ލEFX]E8?)zG~lS#Ka-G?!64/Fh;큗v1>zMxzE/^`^q}7g5\uw>^"EDQY0jb=[ |g>QZ;$h fr$Em&BvpYƫR ) y!?r}ͲY;Vgdlܷ++XZh#~w! w)O7\2k9_ˍi!۽.1yXu7DRk3SDODlR4)cijIj !2cI~Vg.B0%./ۮ]l睇0)/q"h,轃iLʱbJ,4NB2'J*k`5}PR$K$+ ]Nuk׺vԈ =s^q>IU$ @ SyveL3f 8"X)&"1 çʀs ?gni`z'xqƎ]7miN׻Uj̪#] MP%ulY(}nƦfpp}WD37?ʻ)wu;c0fe)xP "%ez.v"p6U3"Z잣kZ&k뎔 7Fympm kkFJH%!B AJRuf6)C-$t2.!޿p!{<՟Bg]  wỏgɈ춠B3 $ 70BA'`B%TG () N鷾^Հ"p6[Rݡ{[OC4D4g]!ƚF#;yOD qN&sP`&'?Xril>mD.[M0!gn;UVtDѧg{w9m:!pI%3s6srِGoZÄ|%Ry< D8#*^YDk])PDNzBkATOLc3;nRM(a"L6dN317.`tsY$n)3-Gڮ7KK,xO"tg !.57Jb4$!wh(;Fl؀` ;.fycuc:5[_GFB"En.c"8+G2,K^! IT\ : njBScb%ZjFnFIe ݺfyk 7n,fBH\p)1±~Yz" 󉏬_q05:``O QsP Nciڜ]7iNnҶӮm'ӣGvmm:Le9O.$r嘵]- bJ IGF0@D!`#TjjB;!LIQTis6TIտt?]ݻ7=!68E[Q3 <9{6qf0;0 CE8`G*gnu|~_oRnJiV5J:$Lb#LRFIMW!4-y`Cw6,3 4gs ȑBDHtk/ ۡe!>q3 ǰ򒇌 2HbHu$$(J.5(z"IRbDD )8͌ܙEߝ!w'h EJ8<+ުpyKcA>j[?4J.h3NU;wqKNC_&3,BMn{gfx.Bws܈h[_OLBqS#99 alX\CXli % x ޳ N- 0a9w"j֙f(-RJ;lD|آxI¹=W1hmMRXPgL(DXQ`0Ig}!0}!ƆxQ_!HG)xA?5Zpv1F5npW6y9ʾ{FnbaM&'ӵt%CǚV|2afI]PFSѦ$IUSv]uDbZΟV]3JI:ߎ;ЇgKNX.p<۩xI30\(yUm 0:s/!9OZfTj˴^e$%Ax&䊌T:bźH-(E=kTho7ZFq[yQp#!\.'fAL)4j7x_{2_o|`C:b ; U9J,w]kmϵWMf],htOɽd *F%gϵ(LՃheF+ͦUuƅ!Oa\ډ 8.q qPAf,5#Yi7ˣѮAw}}j/Y; D8?SQ59ɜeKfSD&~P˹}sh+v r\e=]@JIEӼ/2AZ1A"lJzMX:`r|˃^F[I'>J |׉y ?|EKK{$)^z;STUD_}QM7耳;q[Nצz[Nv=Dns۶G֎<[h/| BTTX+x)&,F$>B*BBc5hogZ x_N/#Ȏ dGdsd^u4 ͼx_oC9Lj$1/\{pp@pH#̠WCQg<]7m׿`ցuٹM)Sw <'157˦pUqݝ).^;VZ&4qx\D̄T JzXp2on,/z"zƮd]*-j8VkWX=RK&/it0TvQ)ۜVy:mlNkɣGo|w<7m7xN>e.)IBE\}*0bF ̺Z!@Y~F_' I>~L]3XSQvg,X ;E迩laS/n=${`48I\ھ謝$ ဝ;. *C]5yۮ|+=fi.bV┩E+3݇HuQ0B1 ),)9wc-VW1.-pNĩaZ -nl>߾yŌ,! UUxydST^һƠh)PFMIRD TA6i)HWǟ.=GQVّ̤s@8VW3`!49"bqŞ=ؿce%zxt ܷ*;=މ"4/oeq} l0`E3E).J^c0Ά\Lvn#0$ىZ>xidוӟ{SSU=^X]CK"}?XˏU{<:"h%[Zž=ZmpGC]8@v:^SCQ ^rwŧDtB׌ɭ7O-.VVu`p`K.Xڳ`4nK6Y=! Ia{mR"evu((D?H21[ErFs\ Ā]h2RE?Vw^9|*ox(.ڟ:Pzqa$6;w}5M㋋d4y4HW*RE֚#5^R&"&<5+PJC&0S3g$7Y5B%(Lq$Հ⢈5Mv3|u>O[`)J$'_yo5/_G|]7\Stk}'U$ڜH\8kN76D&8eqQA3(q3F\v.[ hwt$A6yr nH˓I,yu{67Jчem yE(57Pc;n2~5xܿ8go.wg1́f7=)\Elm;d2dDVWSu58yl!"p.k3Ԝ?A/GT8\tq2 p30q73s~?(Fsa,]4*r`׮i6 ?DM&.Ȗ'gtx||Rʂ?sp `V\jkC!'O;seiIS__uD.pa $t'^N"b 'MQJ Q&! %)HbHzjdݛ r):)#M |9z ݗ\zw# oo{k=n7߼&iԂQ"!ecCEOX_u:Ʌq{00L87ћT|׻X1~B$L"aHD#t!w/Y3q! >ۿq/zrwx~[ceb: WEŶm;miMvmliyرv}#xs5j5Ms&?~U/TBQ)1RyQ** @RPJo^S3/ܽ8׈*yŏg~s_|'U18Sy`ߦqڮL`t;=ڭvy/0F8M=@Tz•W d݋D38(̈́f8t8a+a5T5IDx{y=߽cr-/aLnc~.!&sׯY5g~4%b4өs;N2'Nj|%c _G/BjtrBDgF͡NA "&-:.E5AE%+ Lͯޚms|U=q-=g\7^W=[W;u7.)OϫiR}Ib:o8t*U¸;+j?0sns-H~}p*`"%"K]HYP3}KKG(J;L4{Z_[x ٨~oꗮw0/=IL_Ͼp+9w3a~,pJ|;""n4Fxj%:`@|僚 +0qC p<#yߕ(TXZ$<C9,O_Kg ݱaơ[,쿰x~cg+^͘ͺ#)utʸ=լr\%tݽJ%a6"LequɈ |?PE?B)~T1jjf* >uϞ WVH_s`o O?zHimwT$Y7ߺek37ϼwt`p,dnv''+#{9{u  sgıwN)ݫsғ$"dLȇK #I|x>!_ؼH(kUGMMFpNk)`nAtJq~^~'腇>P/"^Q>*6@@ A4B:7՟Zk1cε>UJU9eg>Ykuַ17F-ٸn:094^Ds.Ij$Twm;{u\8}H '`; "w@G/(8(2 $&T0\S?z |Yؠ U -AZQԪj @ C~teODED C4hMyv>=`:MzuU.kl<uGȨi;3o=ק~J`4kMIO˙,(X 65N_X!{yu}N2 l!)dJ--OH ڕq *INZxw-iMZPoўŽB!‚M*4nWQo5"nB{YD T؞]HT#Q'=?.](B*] #8bG B Fޛ/sSsY<(>ն]Z^YˑaR i]&QP>Cֱ.E8k ]^no<9S<BUqzO^Wkjv0 @Z6i ZtMᯞ} IDATS\ҡ+}R_T՜ֲ۠nܳ, uйFޏ,:yp}<>{iChm]s<uB0[S̳7nۙݚfڶvYPtmE @EX)qӕroOf}ū7B"Da7 a鬱&(D-(rU01H`ɼjf*QD4rhzfGA!GޯF+RU=Fvln|H_o؊DoHmOS N# l2V CU% N#~U0sߺF@b1QBO-9L&4"H3fiuE-\cw qD2k`mmmRUۆÿmxv{kc)jcKi 1 "Evz>vSPptdn-ȃ4n[]87Ţ 3D#WÕѨۂӤD,@jH ]t}Ha6жBBc4Ç,*(‚M(a*ZTksiّIGȦ`KnM An=3@ G$qdrDsK"SIn%$rWs̕s1Ft:] F/WDe7ϧ\{ޗ}s.?ze9BH^By3N4 lZ v.z߼qsz |ץTVi\/o9ŝꧮ1E(@1TAM2{bypobsc4QTSa-CwpsdVU%xe89߾ڈ|.9ąDF='=G>OWܑmBS{N4 l2mT`0y&S "\7tI_z+6ʓ{4.-ٵL 7*{=߶r3XP S"'>'>;^G=^ґmb4g13sRGA}avJi vmb)\Jܧ?"(‚MFPQjU5 N3_뮱_2oc4F!䙽tDOƟaHl-@[n;fA{媫.ޱ̥]zR}ӈYpۃ^J'|ȿĂ  6t6Fզ$Yb]Ț΀JJ: dst #7SU")B.xym`=s{C?D͗]:~ljEX90]pB"34GW/ yuL`by-LoЗRJxO ҈`⨉XO&+ѓ+_ч.Qgqޖ-lr/9*h2b`a&]ھU%EŪEEߞ /O z&v TB }U.ƺxs|K3 ;)p|iIߵ 3o-[]^>g˖sݻi0o~8\.:ZPP`3k)3ua=U6(d!-ͤ9KLΥa Y vD眮qaUan+yg'?[:~x<959'B m*dbp%U?FlpLn|C@E=tD4.Lӌ4rT['s袋hi8޿j`Ffn@zZ(P>>j84oa[~Νs2sZ} ,",̠GDy.3MBf@QUrnVpjTܴEQӄ\x֭s馅v?A9+\[PqP`.˻[I6! e3@U7(JU :.h0`TjD{ q[ G_z8Nuw0 6(J`"Ⱥrfܼ-=A/Q ^JBKFs@ vb.rpC-e9c m",X(`XRpY]Jy#Bql T™_T:EH=O*'c&3GтGՈx02UNL`ca&Mwyh*%US:T|Ac{~zNuVBK|{s4C:[˾@=?gee2xvDut8rR5ZPBD0A2fHd&ϙg#XdwQ>"UnD${BG`i0;n"x(`!hUQY'6,2_IcW^P 7  GEr[#z'u|ySl,EXYadd'W$]?oöqyDBfTt=ctKaOk ĞL4&:NѤ!۷il--;9._ U.؄P@DDd '"(}$ .0Ys3 G"2+ֹ&h\UzdQaD!‚ 9b|'G:mkh{ɦ ;:u,l{隱cʹqUM^_hq@!‚ bm󂉢pXׁ{K,HI@g=겤[V J%z:dKDD#'Oa/wGX1Qrm+Uţxvx*y\BԏF>M7.AiLyc6[0נuh:!DQ5Uiג4mN-ۚÄy1nJE9QTk=*[ )?v.aˁoxœs!F'G.o\&MUH)4(DXq_}n8\j3{CW̕sfLO|!F_+w^s g?ꑿ>̂t~O~lSОt@"nW]tZ`TUp.5oә)z(7)kˣג#,ؘ(2}䝟n< U2239"9h4|ᘈS0^;U;dn?wY +r`i9kA ~LV!wسFQmDEZUY j&h0X7|߈eU=i?N9)(xPa{xكDlHD ]o?z3WT(\b}ҸW*f01;bG϶x9zuE7$q5uݽi &/iSLl6TyTBJWO^vA .]'"y!Ou}E]ϛ%94UT?Oje2H-RHiTWEǫ_-8FA\W+F!c0m\"J`caIGSU5Sct/3 cfDtlۆ۱};CT9> [<)R;2kO^FC8%'O R,۔c:Kz % } X7iz(wW_c쭿 s]'Vnw_P Pr ,%rF+D|2%L0жm4X; PEhɆsj$)(e*}c  *sRWa F %ˇT/}AQ ixovY F?Ǧ<3s]J1E!"`E@z{ |-FUDPTFl,HL`.-h4眫<05iA=]LfY>JWEw_ Lt@y5? Fi_<~n{ҥ|ʅ+A< ( @9U\T~XӯYFUH?79 }9(40 Z eF2@Gꋡ`caF2'#bd"b1ȁe"4UB6X]xSU!FѺQtGOl)4Y#Q PIc %$s({7~ `Ig/wàARtn $UV%&Reirl.4]`"4C)~oS41BDDV6)6 D?x _|BC!‚y;Z$(1 1b !6ܺYM|8CbmMS1>w\qRl?eoUnH#5{A*`%d~V%Y=y>^*?$)Hpx_GADqA9b!IHTLjc&8*CAF[~,d(2  lɫG$b|1F8HiE1!4DL٬jjZ;T9"(kYJ JZju ˀAdIJ(b RI-' 5] %UZIIR3))@d>z# Ofhrc۞bTޕ ;&" (Zf7 VD`3R+SIPA#cȊDBA%29@MkS@U39Z`Qpgԫk ;1F1~)`I.U!74G !f򲟙wIDI 9%U@ r@hm6J҈4V h񨉁01Pxav:bGB@Df4'@v#,X(DX ,!0r.*N,!1ķmAǮC HQUNe6U"&H;W[UDL@Pֳ.;ַm-I5 DD֧r[LHw|Ͻ_IrV`ks "/B$v@S=⴦ o}sN'|ù8)uHE< WDҨDfEd`׾} bk&}!b yY(ĠJ**?cy߆ʞ٧{ myrAAF!‚) Uv=Gissх UA*+k PD"cs wn#ow;Iiij#^eB=L@5Yi}??_Iݭ1W)Rj)DB M?*1d24'{?\ c \舘ZL")*W'v((DX`cj&o'c DeDDb>Z\#M`ś0sVqbF }<<ۗ};:Vr!u'"[osq-I6ca6m_)e#\ۿI =S KP͑W #6E_Q,T@$Qw>;O∬6gy4Q"G,^YR1"FfOLVW+ؐ( lgNFccBbc# mCݶu֡m݆m¡fmm&:&Vb#1BSk`M7[H?h!?&Θ'R;6*w\\/G+2`CF tx_GF dꤝkQ:ۻ*9Q'"HC(aan½!]"&b ɒm^ݏƟ[ UsL: DtS39m%Rk^ܿ%a6&.ƕ 3G޳tƙ'+!x((+LQD9WzfQ'Pk SPQAw,5N͐MbPe&석$cAcI]rH[ZomCA1w];ݴ=(-;I׋1P`# F" GL$kNk0.=_<_ow?~3O;kg^umU(t@tD*"0;f'bTgMAQ4-ذ(DXcgm0cm ۨ%q5-ta$TrPR:8uAARIgj_o{cƈvG/&szp:V[X =t03VvOa3mpv:L&XLU1KO&umӒ W /b|̪ /Ʃ:VRUV/9[ E=sw/F \lPߩV2Bۆ&::&-VӶuumf! ufm;k:YXJ6O}_imZFxLtgB}>L0]ڨڙ_;0ݿY6a.,L:U(^oe") ROR62}I2gfJ>*#DξyǮB31sP5ZlP",xǣk|J16J+1E[Ab۶uڶi̋a:mךfi .r?d'c22zۡid<&'f9CEq3{R ״`Âع)Txl!Zh A{JYk9^-C=fG4jE'H%DUTd =u3rFŞ`BvU1f@ ufo3)VϺU AsbPɀ\{ŢDA&8s y&('=$/|艒#,p(9‚,^R{iUA|HJDcK$OW"Dы ^!r.ˤi.GF1B%*;.xU m$€t6-J֦icvXוsCahZ} YO3Fc>ڭ&;uمY591 %b&)S@$GV*^ԢA1{Pl_~oWsVPpQaH&O٤6:&1抰]k۵aڴku}iOgVλx6mmEbvsGRU8+!Z=8U)&Qbb"1Fa2[arc JPV`i#,ؐ(DXQ`\{"AFU mYNviM;kiLv4ktm?}_++9[]띑h֍ ,NzgU"0ɸVۉΙ:Ue:L dDl#-T2"0؜48p`oDȁUXR0W ;oD57^WTPaQ*zeBvJEb۶km;mi۬ʹmm;mi;pĎ@9얷m̞? X U<ܾa˒&4M22U_ cv,q>{7L8Y-vU+hT95HPg*Uvz~L`vӄ<ᅶ2*fy"2+B&#'J`_?O5M罈lEebXi'eD*CU/ vv=T" snyUUEBb/aV7 }de8Oι){ V4x @$ƎHP k!nZcjPm$iu.#hSy4FvY!:T t:&p|K@<40 ԚZp bdi#S6H2A埼g4:/9WYQQgLZqUUݳ: N 64/𞷾c>(=s1Oy֣-vJbm̬VEnBEpɍAAT"hxz>[V+4<uv͐su_S?LaYФ1vfD4Awd MG}72C`r/-0#{?(hvYؼc:AW"8W=λw"k+(8(DX /&U+_o'HJ]|ť Ω^Y|UU w-hTDUPLp=\"*b7c7MĖ-^w/_h[7vUQ@(‚4'ܾs+w}8s#CW2Bu^ d'Ny眻UGswg^1ʧb @k|YBmSnλ տ>\mo"O,.6k`ʝe+H8:N`.~ov +f)CzЕPx.fF Ƃ؞TD f :򲮬`N܉D8g_kA)a P׻:јhbԗ 7d! v6\9w{\8^^=D䳟eUJfX!'aJ˻wς+տ>\sƃhu%鬇^~L39y4P.i<4$TH׫&UI@.r%5g]4,=]t>jP&?uD)?Ȋy:v/C"%CLϟ5bdQQ`d&a<Hvm-ԵtD8`8,DXUB!‚ IW9{tAQ x聹`E>uB_Vq'~}ĀS X( B2#i,m3|d:??((OsͥjG=fIҗWjQ{Ϩ*W\{EBmMMoEZKc;Y[l֮hD80R5ZAHfQ((*J'iISkhM5v7}[HV:cd e0H6 $S&,A0+:) 瞫D:j^&a{b9DO9<޶DN.uϿ?a`^qjb[5?r EZ#j"kkhuBXnNi4[fȂBQjǂO0rх&sWVC$Ȏ GT~_#{oF( gOeZ\fV"sN^ !T]w"I7R@%!?)\&K 48>{+c!o@$ة@Ӆmm[7MӶlfquULFfNe:[<(`#ǖ-SbРY\k?GʱD=y̞̚yWϒTek#p"LPee#DHNxaй/k}aU.5==OAMpvɾ#ar"rN%HĔٵrKŪҁ"qQ 1C 뾨<9" MQtөHJTG!‚^vM5<)[ɤ0^G#)J=jE֑K~h}y<BEIH[EUTLG4ORQBC2C /^y?"DUq+̨̩cI_&X0/þq&x>HQ|^jvmVO*"^&ֵfJөNUhw.",|.:'u*ќKc ˶E _ڰoa 챵KA6 @%+8B4 (9; @d`$7ݝ@9;_{ĝ]0Vzy)C!.TBU*$K8ebE}9H_:H1w0.4u0IC紪iF1ŨDBAlTJܪ2SuE`b%!H~@)G3̯hoNMhT >bQ Zq$r鴆9gj. - OV DBI&1*u=g OU%FKGއPPm4u6MS8khc1!؃x]EX>),35'ƘR#R \e#WοeGNiJD% O,4KDJ;옞l拷ȯG&zhIbUNf9L$f=6f(HY Ih#M#1VY98f|4",ظ#qŠexQK-:Zm\x7dJnmDa'S|3BPk^B bF.s_bLZ6V A.&;b8֘[ ltW}ڙ_?sOkV2c=hڶiۺmnfuݿ=|&:&&66B /(8qEXQМ $`ƞ3Y1tAbO݇f+浀7B5)j t2ѥ $)Sm2T}i h8Q L$cj"R[Dm[i{@}W\JlV =^PaZ]8)><$@.[`*%s()̹tu'vCpuF6]7QryN*;l[ڐwvT H+:S3 \Oe09J{i_^7Hb=P"PDD.@uoo`NH Bk\.ѕ }9 y0Ri:#Mf )G`o ӆ"tN+8}ȆR'L̐ga^g]@"Ps'L`ni%"e0 (o/"ҪB;|=uF"'3GaBhc>Z1,Uq 0,JLeb O !`>,>&{IE#h={BZflw00mڵqDiGu/緔r#)TE;crÅ{]|}Bl  60 b?ǦJrp@ 13Sjfj)ȓ+>xeJ "C$IːXQ\ v D)\}8(~%D?} A $R(D9MJ>q$ZolC _#-_ 6.?K_i!  vILKY>EE-sN:[W;>+ ~Җ+pDPe|2wz&b=}8=﫷7bwUV~99vgzb8|0n~sϗDr൫aLm1*s1'cd"#|ʹ֧(DX+SRK~&6z^[c"! I #:Ra=8-jzSԝ2V"(9pHI ڦN͎CO響rݕTը :w\9W9W13}37۾xN}61 ޛ[v]}h8)R")"iI5`YRҔȩrCR*ǩ|NUbUqŎHN>X,))1@n IDATQ' A Fhʇu7#Ùyw-=G`ޭ2l^7]+p#&>xϨKNYeټO f;9.Tfk-%GTτ[8N I)~ٝnSԠ4X4YʝKXhbHB摄ˆȐ%Ճv|!#/GM zG 5) F\xdWx7n< RFW(ww\F33Kƣ|s LGN7kmpn] îTP_w6zEFGz@Q-vTd׶@]y&wOwɝ fPu@o֛<5V5Y=sp\ 0;q;߹}z(HKOhb0zikiF]z^pp '|ϯ{VMZ;bĸvNovmvmO&^SU+7*}]=V2 &e_c0;x} eCpI`K`4tfYt@uhˆ3k?Q=ЊEo0z?z)ڦ90Λ;EАB$OŶ aTBDJ꺭pksiTsd8<>MC^/f.,,sf{ 쨡ZILRʊŲ]yNQAu (U(!dV-dg_,0~?FYMܬU;K"p|/ϝ2r-MU$Q U0e/"MmMJ}MwƯSoؼ>v@5Cr- >$%F|ob--2@8aXH1UHoP"=@bG sg>O&oPG35蠈f3َmj^@ Ȟe :)?/v]Jԗy$K`ӌBhSꁭ]*F+ͻ1<2JHJQJlBez/b>3B~oșdd ZPuve3 DD?ha[}k.{H3s5זZ|[?+xe`mㅒ%otG#k#̀peBJU>/pq'Nq2oo*XԈغ#Bw5L$Dvc3 E`FIM(ug%4n5(t"5+jR!Uad$hfvyY?k^ wb0u/B{l)meдdbzwݧo &%6k (U~yCJ۝#Z)uH+cU*{Eʾ`|^0B$>M(g7}Cʡ 󁕌d$42P#K'fEJ/[Y48"y.nhd c[\2|B``F~0%ÆIh:B*hTKPoD藳7E3%Ѫ* H >Oox4[zM" :s)#P⎶y;w aʰH<= T @6 ڶ4 h[ٮ0`mB,L&@51`RS>?R?{T*JF MRgGM>)]$d7P"Drfc`iB7plܥ`Td:u$B` }4Ut4u'y"O1Uan` [҇-?oo[OzzJS/Q4{ BĭH׉"Mx-o?0P7#wu榨'WR7.ljM3}@2!YDUIIeƱ:w]cqk+)inrtþ6kPJѬGߗGS>XajJ 档_tT*ʕMh 4OhU(@!Ebjŧ63MjC>q漪FW_QSR;1 'a4N:]y^U#A)[T j9:L)R$;v=';bFX Ll213*w䡎2w[VL*DfTI4!jpAմ ր_T!TߤP$LHE`1'?cTEE?7GӨk....>#b?wx*?]OIMTJP 2p0ԃR^/]'RR %&Ɋ-t|`np(3m0Q=a40Eߊ/z? O/T* ,t; 4w i@!5dLEAs9Ow&%mbҨ9yU$˕uz fpXSJoLv`"hZLt'˕2T* )R=&`80Nض@߿`JfQ_&4XP FDBo(TBO0lZ6AtB*RC|(g[ W *D%h#%DQcD&H:PD'Au5qwxGBvE! c/t DĕʜR_QFB#JqbAH#wz8 ¨ Te݆f!5BfHū3LDFOLUdP3->yIIzRƜizu}cr? s(r,PN1PN܆#wu2T!WސB \ @!HLKd  S<>pfXδ*ȾDpяZET%%@4$@JIZ;3W !&`.:,fnmŬ{GT^V*xSH.kBSJ[zRz;Pp ]lI("`) $xŒ0 Kː/-+;|`%ˍYf0tUjJ1>>+UcS)1)jԤ)u)u͉}+W]ǐwC65)NwCV\\Z3U+8Q(@nn"%"-`h!}2CQI0Lǽѐk%7L_" S5I{ME T(jL)4Kx?,Vv +A(Ďr~)D3*F+m f|+(rd.%nbm(BUo M(3d S?#H0"3O̮Lͨ)|*,zGIDh2)}f&"e撶3;X=|¹ӖB+'JT,WNgpy7m(JDpd [9 (qR򢥁3IQ SʉSzLj1"qgs LM͢CS5uI9LOڥثI{Oԥ8w0ͧOL ~RbL\2!R.,LZ4 SԈ_Im/YF/ ̕a԰!5#C2J2t<2fU^{KDӫ׆d ?$u!/eta]X_JeBXy#R&*aȡҟ_6[1]5SU3Tڬ.qpbYzϼgZ 3ק/ O՛Gc{ELIcܹϛ *Z8`.Q É9[x`jKVP*sLMV+{5׃r+a6U35X;31W5ϑFJayыI=OԱ $zUURޟ ̚26 X`,5Y=ܺl@OZg8)ڡ0(+V/R`jDXٷ쑵v&Z_d,QTba0 C9D)hNN:wW0&5KC4$Ɲ4q$Ilo?w[o}˲rpuQL(s`-pYlڀ:2T!Wb4uOšc+ؕN"Źp baBȴgM;*Ga6/:pTX- z^٢Sbrb I;[z;z"":3 4r!;FM۬Z_U+ EE=dg<9(.ATv5xȥΟ<~vqwjc'd Lzվwv&rh!" "ADfӒ-'q25J>sV&zDe<4!Cd15NhJCgYmZ/Vw'b7_3S>! &l 1?>uI1Կ%T_ʾFJJ ߰յSJQ/ӎ|+J`p-%lj0< ~=%C:Vu;jIԫ> fi,~xG[sjDXٷUbն$.B@=J0O3h`>_04'Fh"ҕs]iXyc>]ge$`ow5|yyUp:̣T%U+OFx|~ۿu,y+bjU;H7{AnJA|/a㋘sIjth^^Ѿg~}۞=VWy1if=hqfe|m?t(;'Tfi@ m*>C eF ɔjÒ!]!gOkR=?Dq %A)f}g3')raD~%E45zg>im?r4={3.  /l-b)9^U.'ukS 'y?BN%}-]Rn=3+A CX>zwpUGXsjL Ѕ.9yJBH J4I1Dv:`vǻ~m㙧]x!(r)NkoczV˷4UgużD{T!WRRЇECݬ/>{B4}X~ێp`ۧad\*n)eK]bגGsO O?"XoV*8|Hy'<$!d6%P$#myՖWOGVw^=t ϝNbbx}yaiX38o$}>bŅ j}2T!WbT͞6;LVy;hݲp ڶiCU.%e6@39_M8|84,Yr $6a4^j͖羕4eS#B'tz2^>URSA{&H_8m+Z,SWjDX\̡GbZY)JoGwѨmۦ[$6o{թu4MWE.F_ȇsjIhE6NʳA?1j㷮z~w~umW^ 0j]WjDX\CǏ^~ koŅLԦ䷤T]@_A,g9n>qƙS (:~ŇH?)+U+~,9|Q@)89kjIM5+ jq5fE 8"Ïcͳg<aƩgâ.ZYVos_T !1ڴbu2T!cnjGs'=w!\keLKtW,Y Mn/}EϜѻRk[1Y?o=c~9JAJE8|٩I3T3rh=p5qacEp Њx=^Eӧh 5.8 Dn8Rrh8̈*g ҫ ae?s ?rQ]sO9x[]K8|ir.TQP|Dl8] z .agN]>v~ Q M+sMTCǏ =svj3H@ !LH^͊[K>ц,\]R P͟!/wm5ݮ7U+54x̍G_-Q$zUq*+|ϝ92-'0ܓq^9v~EZ):`eBX}E @}wcZf5L DL%8d+Cף?ꊷp@e㙓+LLU*vT!G)xc@}G_oPr Ј>FB2+y>fCA跷PťX& )sR;ɽ2'}y>xsTQM"b935}syDA5@5Z\ʯBHNXǏIK5?5"'O?s'նm:a0n&,‰[wm?{1bUlN g'5R8mҲ dA7 ڄEXRs f6N:Yc$?ndG+9Fß|mf܄Q04."A؈Zخ}/OE~+VEʦ!TD&;ϝ洿vɦ22҇b.3WB `h2Ԉ2 aey adKoo'- M4~կq-ZZ8_g E#KHsιsRB@ ]g0n˸&> 9zQ}Gag{Cgl6ò!Y^Z]}7 mHw8z(՟y $,/-(V ))| ?ٞWuܮ3U+sʃic(Q,o6 녾`{Ta`IHvTwDSʿrWEG2wE6KumO<?{6P{fqQ:ڊg,-re(E)sUAzfpI4(M5@pecIY)!,%quQSy+M\b^ "$TKg=3{\^2VV2I߼ e1u1n=w4O&(IRSJ)o%]'2fx~DRd?\JQ2w|rM UBۋeQim5uPdP+ `!iJO9FKVuMH#'Wc,mml!,,I3S"v޳4; Jۃ*g0`Rr<:0_ȶ‚e-C mfs/CPqZ;tD<E+Ƙ6ʔja)XiDr-@fmى%(|_\ dV*y?|_)rLL5QRJi{[ m`eaBs\bs}=^"ִUGr OߚN+4#!W*9~gTKQ5j)%UUI55$@UcL}.Mvt{[c2ϋ Rbզ{+]^ua4YJ#0C+w猇L̏]\n9}r]f4 ƺFX_V括WU?dTS^&Ԥ111ƾO]u{GL]IN]\ٳ} 2B"FS͝y=/6͸maq9=bvoW13$Kdu"s [P2G48,& RhISVǤ)o]>*}N:{UuyiPsNyw=Mz࠸ phe3yХx5! w)CvT/e¶1L aezu9L)db}NNcH&3)TSG1'n}Ba&pmiw-...ԓH*qğ=ԓũT:2` >P !X!D݈f ЩMyҀ;^1zLɋh>rjY;n;;03'(z0T.l|5S2WY|B}:Tj"SJg)2HJbԸBP$-'B,>4hܥ*sO>e:zᱣN>-+ K[Bjeya!%MI-i4rYK.M3#EVnƝvrc[+Wd`w}*a)"'ntl*,,.,:SE: Waw?9|/ ;JS#\Sb>SU )O ɫdfؚ<,=yohڋG62^)'(D tBWW)__`K˘ k'nρ\!תS2_,2¤F%) "B*`M&D:3TLʚLd" o~CXd2"wvO?B1@͒YLD,/j ,2&5hތ c+9F+! (@Oj31RԋES582KǸHX{7dݳ6xY\_q;r\(BJ5M4p2{I+1ZVoā7µՈ2ov<(QrCTEU ػUX d֘%fQ-%fؔٯ#x,=)!T'!ic&E**X7^&旄o{|NRaW^6F(>tr[XRcLf&j1U I$4%+&ܜc߹?YK}JI1"D@ hc43 h63t1ˁ*^y!0_e2/В!)5c$5 RJa~fK%Lyߟd- 0r0Ӄ`gNJn6g@RҴ+|7*Basǿz `hv׿`^*DDD$PEDb2z\\iy>(}~\ E.9ZӤM'jR RUkSG?_T*7*k_w_Z:[DG.U5RE$2ŻFЕ(794J~g/;ЩiLDJmTc%I-͈~Ն6_BXO؏sǟBx2#4iTMG &Qzn[m+Bp5Yg\x-I*IܒբD[&|y%|ū~MSטo|wڋTnU+󈑄W<7,` R-h2P4M4wd)Y߆urؿ 8ƷۿW4$mQFɓvb?7U>Mi֕{vQySn> aepk C?z^%i~ WB n6R \v_RN#I,)ϙsGw>T;ZjŶ]N M~t7nW*P2L,ŝfFw~WXYMп4͸iF(!iv;nr37*/kV}=_`6ɵ$iҏA2V|0Uצy"?<}k\NÏ|`UP@_f4 !d߿> @š哔4rۇkrӨBX7ׯ=al>d44˯W #6!PkWCS5cQ,? `IΤeᅭ_UD i)I:_zlx}flE@夬.mxFX aeqMFŒԀ40k$ȝw_L.|2T΄+O|K #!H=SiՇ(41C>;38K{#-5OZlB/z0o+K/|KFʾdP0hQp+aO>&4 +Gy Eg+OiX;qgN$w}e.f ?3rIuHgoL e[Y.8ЩOoV^ oFm;ǣiB!W86"4aRCP("_'rܠ, >w# ij%JVՔT*Xn X[偃 ¼ dJ+!uSM~3x.,,. 0:RSylr#J%󹇌dcҟ"bA8$ % !Pzd9p].'-,{o< @B.M&g@|k&5 j2K3?52 \\E]\,.i0a4Bh|=7f}EF rq}s !K]Ϝ Qq@di Ќ L 2x G 3~XYq^{DSts-¿UF $ŘMш(f7+/OV*hF($)rӧH-L6փPJ# :R x8qFM۸T 1h#>o>PBVAwW}s hTcJ1>^WM)%^5!#}hۤ&~277S֖5;Z5' k| !xu̳'c85.^a-ٚIhISb˅vlf E|2Ȇ9[|}h0fG;HLi>4F>ic7]Ǯ֖$ièEa{rWFUʍF;+_}elIHN_J)P..N!M2HpHd$V$rw܉b;6ą|h‘Aak˗EpPđ4jRRL)FըS )žXpg L}g"6Ɏ&5S2XԈK<pL+ 6Z\6EbD6` 0dO=R $ F+IQ87ysO>a0dg{]l-׹]HYļk[ R)j_mc_&QɎK{M)1%t]1*(U*7*MJjf\,sF D[ @nҌOt%,-{4;~6ǸrN\ӌChD;s%Y;m)P)9fjJl1TbJ). lmZ;;w&#]**56! v=Q %U[,h0[2L?UzMbsO>q{ 3o!^%ӏlqV0 ^J23pYʁ`n8P3FDp-ԧ2t"d6A{SnoC0n٭T^rV7 k?CR`J6AԨD -eJui0#0j7=`l>B"%dۓ^d_ziF!˴?M8R($("ar€~|E?0:K1}WC)ƞdJ6 ֵ*uYɺHXo^1H BAByƬa0ZJj#o:hX RӼz4hmۈO>q;AdOx _kl@hPOrWr6"2n+]\KHԃE_ԧiS)FI$']?ncp?>?76}>WRCV=VZeNA$ABT Y}Լܦ/@Y* -|?g4ˆoRyx _e7Y{ vk!}N< !qZ[n5g2xh^SY]]>Nbž~kxBKKOQ5iwW~SIkJJ1Gaas "Ϝa-;^Ȼ B,tHdpކ' WMg cv-feiX1oC 8#1kaU]OI}R;1\qV*OB4zi3)tE-,n*!\lz'w%ٔ-_B@)O34ȿhV"_"iz*q;#_@6`k$dY+h ~xpsfP0$XA^9\;ؗRcǮDNIm﻾^yV*WA>vUQj+7g$Hs1YNBC"tLCCPXQTpf`_@߀I4QXT)CL^wbbdc{繫3V*E˚w!v,YP˄3Qlh;|_twkK`W8xOv ?יs{olFXDŦDPP[vY=h`̇`13|o403@XFm-Ɇ,ɒ,RM\U˽{|8{odVXKVU.@VddDdc$I0,mD TS\vֶbk:OqB`'d1/Q`f./h^ ana@ %e r!$jZkA/䌨(z. IU5E2#0B;j  _xeE SJ!~7o(TK m)|ߣ..mfn CD/BAfgv a"gSQf-tI <\/?hRI5EZC.hxצѦQI F`ĸTNnj~%#_ p!t:/}7- 'ZSHE&}Xa@eǏYϪ4T "*)'!E:94^Ŋ JӪia`j6M.PG?L'-ALljBUJ-)E̚f683E|gn8{ sQ}^>sJ&4)_Mv,_4CPKط+)XU](/DstS[OI"146 i[)5V-"\3_-e-cgU}Eysf݇X1IlyNf֘y1.~;9'df \ntUpD5,o-MK*渭`e HdFK_M1j;ONjx.J1Bl]FV#K9:/C,*`7xLTo=݆j*)Q[A IF?_}6gGxD8si^drH#-ѡJˌdQ{pSMf{r)Qe/3ז%j.ŜX\ QEaV7 R G>fσD 3O=ÿ>:DYOi!Ƹh슫9A̎!MaJiMLR# KEZ9SnT%OA#jZC=n^U yʔĜTI$jZM `,ݢ,ehyg3 xsΟ'`@{U/Ai""s_ڃߙ.΁GDDLw\%-iF]T23"$NglɊ=ر Rf|!Q*o@bjI$6!mY4gV,-1KBAxC}SaB (ģVo^5 Y}~jC*+\#*b}ۦ@@`7^`!"g_Z7w+Vmfcئ@יe|3Y:tg+Ĩv {0L׬Vi7 E6FJ;\D(}y L h` Fhcj\?¿ܓߖ^#t˿;/JLjTM@T庖!=K:-M[s=u%io6/efK2ʎ(04w2u!-@D+@gB8=jOךRB@)[ytA*3Bؼ=#3AMDaW8@|}s_o{iyF_UU#$Nx DI"jBLj ^zHൣ t/}Tˀ(*,$A w~o~7sԨsͻGӏ[]2IL?ܠ]siRmKS'+Dϑ cx.Ks = 5g>SLvE]]ʚ)5˯zL ؙCSzkƱ1`b&66O?|ǹxD8;PP{)s $"Zr@PI sAuUe@8$Jŕ_xs]K-TUD@dc* Rwby&Ѵv&xelvDD6ks>m +aq "3U6g)hܹ8#B`sc ,ުo _@?mP,JMV$UFl<)ʠ@4heĢ,-8Y^lEB15[(l)uR*5%N@縴DD?ypalV @۾p<"t/պTa0J"@"&&L"K_ |2qTs)~B@ bfUmxJ B*ң2'6HO`P V8Uz0χQD6y*B͋HR"zfE7X2o8 ?=W**暩" %D \=\Q^mEP(bK0j +7|(b+GTd@z+G>_`'sEflQYϔˁ>*MҦS_˗,IRAC90ӏ~!/P~'-jdcmgx񈪶nX.Mu(zT4'?{.U%(BDrTJ!f>yMKhvY8(W9mhHGX~X(ȒŐ j}:[z~sS 6g+T8EL!p! o]aKś$* lϊ B}hX%R92By*Q &sbkP:P{9ٿfN} s݃a EC@x}7ov:*y )i)!PPMDZewZi@p;Bg_Tʴ@,#>E9HBж6Bm %@$SN^w'2ma*eƑR|v?zXYѧWjh׀:i5ﮐ"22h*ܹsk>x:S du'Ե:`4B] UZxt -݅ !q'[ E}ȯwI m"\>vƮ2VþZ:Ka- .\]['8w ?ʂV^9Tĥ"]noQZ]cPk]#f !my"0"p "]@WPʓ oJnF92)AA t*Q"ZeVE=}qTP#BgBG%ѥN[˗ +\/jGwQc ұ'KYlЮHXZ]@Ys&gTJD5Bgξ~^!$I"b$(2K(b #HMK$JX .w\fYp)&B DN7MzcEL.ڍK{D޹HiL!~ b'|H<t .3Үv2*r R&FXDD@^J۪4Lsί)iJ֤J2-d@*<4H(ϻPj׶']="kW3-2X^h{ys': M*`yTTDIUD9%7 RT?m ^ѧKeA;ӡU 1ynjsp!t-LBET#,D~~mh[YCYK޼h+;= T :R`F7j7e6am PWwSgI̋רsPp!t/$W(H*ӎQAL,D *331w\z=xPCl sC+&"H=r]L?(A#hTRE]Y}9aZhPw5Aj-V:BG.})XRTwFee(J-Ui>591T(>)5/7ǠtZ 2%r?Bgy֠BBp򶄊ey rHIQ$D$&_ &$(Dc")(%E6ILMxXKq^ 11b3h3[?M+1/IZs e?bs#b9 xDSvw٨|iwB ,j64+gn6Ra4l=B i wf H1e`,!tFl @'7P@C`b9:"*rhL"E%)XiB*3*3t!bݙ9;ʴ,Ӧed;,TBa.jZ;{m,=.ś*Qgr/3wK%StyE,&QIIZ˅&ˠ6ԦĸxfUUMF;:S Ay9,eLȁrwY쓼2SfMd}/>")R:BgGsEn\,,]R`bSӶith[ w`GKw@B*X0;}s ~sp!t5O|) v gQ^r#L SRMMҴcqWNQia"b;  Y{0IUS.'"aF;9L9lJ>k-֜ y#OYΝx[QيRSSSMy? 2i*9R NvZ"j.MZ%vrV0M+o2p.E@ER*S+-b'w% Gʁ:GDj(Q^UdY2A4ȢҲh99Ndռ)U d(``$Ϳ ݖw~aQC]39:~]y?-%~.gsC3Ѝu[$ RlQZf 'o__^s[^Y՟9|O{?>\~¼29Nf3"cBB6 ЮoT>U(*)Yf++~px+"U0DW  {`/J. 36rP+ Fw6 TJk[,.f@ʃy{8{g/T / Fˣds<tr* ƈ`V7^#B eIE5Va5V!:yM4Gɢ AP%F+LKВwl?GBZUam-':}h|'c,ʶ\|k~vE~*@fRf4Joo}C>r"&~XL^"fLPf>֝?s:*SS*ː>A@2X]bmS5Ɠ9߹K@=փagAPAv J)D<dUFe%=?Fa8g!@E7Ku=jۚld"z7٬T:^5$05M xn&6|CNPIi柪A` EUlXo]{:s8/>KkD^z"'V@*տMiTΌ5BUbzh=>֎^Us.!h-7ղ áF:`ekTTJEW/L ެT+I`U`P3*l2%?yj8،@EǮkz@UU$j*H̘0`áֵUVFm%PpGa %+5* 0xyaHcbiU}mklTpj8zs1oPHJ82DHV,@se-RDB"DULfl0G 3 jat`U DTөxaw?v$.!p}B1Hc/Tp?p!t5v_$.^ƠVlٴ,_% |w76ڕ+&7 =;:kfU HT:+PJ*I9$˔b9G4MX,LEjhY,̳\՛eB2!_0tH2A?pTD~Tc⧍MeD6grvf4B.F{lv(ͮ/ڒUMo#P؏ &$EjIIbmĶMfX64Nit} sq!trJL9}Juےb f_V(2PR |V0-I 'ɫDڭvR@"y~oix"c&6b6mcVڊMQąPqPA:ä@ ρш| ̰ =>666LO_o[rUAUR44.k]o*l^~I-_k>3\w&ĘLۦi] I)SqT^#t"zbB,O[ 7ͥ4ΐ* l Ti#/+.wrj0@٭Ho'SjcHN@WJ1JӚ5,T "UM \ KB*%2FUo%ɐZ[jPM:]W Ԅ뗞Į⵫ɟIE$MfEb;ehc[YLHAH[ĵ:@ɳP Y(DDҭ\ x/Ww!}ymk {Կ|yy`!o&8~Kb%E1@SC9pJĔS"A35S*D$DE5Aw=]ߥ9@C[-J֧I,BdZ(%,K˯m]o߱Yة._6%=q\)6Zjva3%<퓧֠*)eb2( e֊Uh"V !~㗯^gqkx[˦ZצAX^Tfocngfƒ'g._!A"RbR)RhwԊ4I$mmJMLMپKo 9 KI].vn"0):X& hTڻϜZ 8vK'ym0씱Tˎ.K "1'@Dk P=T\L%RHJw~;=Å9$aTHUtu&$;H{49 7"L lg4:{7ZuRe,IX9mJاFsPT"IML 8ru"!b~@bNb)(ERnrO-t2( ~/W?c'FI$&$Th[Ԧؤ$K&&mf]6Ǟ_._Kjnլk=+bMf*3mi/ ':S^óչtJ)yEI\ LmLMmJ]4CO{CYB8?yu&kQ"AT;T Y8]Ls*1.3˯g>_ln.GlUaJ) m\8q޶6~pr/Mgs]!$/]ʭ'YuD?]Ѣ~KTC]"(IzwҴ R/vYS(ҦĔHL]Ǹ8ws9,V%N(9iaVG,vD/Y'L+-@r^_K²IEHqvQ`;Oiⱏ6 z']g羴LhC g!/& d ]'15N\n1ôxs3-evU m15IE3/6,#z]\Cx\s8\ӄEX(HQ5)h\)T-]>*DT% b> 1k|"G$8/쵽6>/1R1v_|_|e0n'+dm&5 l E@T9߁lؐ3.S@@6Vbł׉ԅ9$̦mJ20pa @lRH)ko%P6YEye(%&"R?DKf47 M(JuU_A~[]ۡq =/ B0,RHq*:%mX9`a?o޲ dQTMfm'0RU| !v2jWiM^JJ@"x~Win=ౕ\x~HCH2WޚlʢY$U FjcGqN5Q9,*kVJ񝉪Fիi ]'7G>~JDa3O>S?eD&Ì0*B=:Rfyxa49]w6w+8J"-KoԚ;Yu܉teҙᲹ͐@!9BSNO>t~٢[C^.!F[D40 U4bEZ,Ғ~h3SիN6FdjgVT0p#;dcAM 0UbB`IQ˃zpK'" 8ԟ,2|}g/mn/o \#gq>0 FU4UQV&1*!@>ΎSYaR642ُT2Ӑ`h-, nRPC (hws7g< \ܜ-$4\#MۤIڄ@ `'+*&gixar~g>(jV&|YP0dTeu`zn27&EQfN_s}~7_{kq?.)ia"0WA[H@|6Ma~mEPZb|׻m1Ր"K.-%@:ڧVG|ā3{7omƕ}"o iR$!pj0uu= E\b~ ӭ3UDPSjSQ!XfTC(&AScb}18mmN?/mBy[RL[KCwƅqnd%ӭpTFa8B$tabxWD(/,EBV*Z~lmVP4sQ"z$8Ag\|ǿ'rS:<Ma0%Y,-($S[ 1>R Khw +URKv(u&pxczvU&.McOI m+mlo54jd'+9LM"7i! j!IU IfD&Ux̹;<8FQ,kV_{XV=Dt!tDG]xRF0HQi:0Y;}A ( @"L"b&-; *q޼cLxԁ_w&j{EFwBҿ/م.iNZӉffde1LD)u{"nÓm>QrQ:*jd"Q bPb=QA񤖤1ʥ{?|ԱA/_<s'#:]GDۭa`x\Gz4Mji:mouݺ"B aSReѠ0_Qį?tv_BBnh KԁWF[y+ϼbs:uqWtOp!t{byy*xRGycu} yMbVL^X,"D$DY (ƃgu(Dkf&~;96i,2\>com.m.nNwp wäԅq)4J ɤ%m mt.淰"c09TQ >*nSޥ T qas{0:ɃVΞ\__nn/.nN/m޺2 e.(cViFj8A:,Φ7S29\=.N3_FDC ΍hVg2<>ycO?z:&^~y{s:nxvVx^q(i!6?q0gVAؼ<vүɲ?k7m]{8B8O$yn{v|`2WZq!tBgBB9H"'r|[boxhm}8'[+/mǓqksMٴtq6ᨚփAѨ,fqǂܶeB8ۆqusLQZGUUq6X]t]HUz9@:FD-L0j=W=q4atOz(Ibw.sxhԼ0dJ]U1ni;noiZ&z+^&90:!DD6[W\c8Y'+4i>[8B96KgUţq:ؾgfv]bPUs`p!tB&"V5 VV&m]m$sp!tH4y2Lj O XD[lnoڢP:B9V6/7/LVɤlgv{;k[ۈ:Bq2ӭv x\WO:qj[lc1&G)`B8nEj9zR&Nf6kwm+e9@:s#צaOյ`&z2(['mNzD \ǹ)rxiLI]ռq|q|`6m6y4G9("lo5ð>Ma"spp!tY,)fZ]LV7%qBqݼؼ'8/q# 8sq!tq4.8Αƅq9Ҹ:8GBqHB8i\q# 8sq!tq4.8Αƅq9Ҹ:8GBqHB8i\q# 8sq!tq4.8Αƅq9Ҹ:8GBqHB8i\q# 8sq!tq4.8Αƅq9Ҹ:8GBqHB8i\q# 8sq!tq4.8ΑWLIENDB`v_sim-3.8.0/tests/exports/iso-3.4.png000066400000000000000000002545471370110300500173160ustar00rootroot00000000000000PNG  IHDRXXfsBIT|d IDATxyeU[{so ]jYe3gíVWʰ~~|Ϲv뾽ֻ%?G1 0 0 Taa_5L`aal1& 0 0Xaa[ ,0 0-aac0 0 c1eaŘ2 0 bL`aal1& 0 0Xaa[ ,0 0-aac0 0 c1eaŘ2 0 bL`aal1& 0 0Xaa[ ,0 0-aac0 0 c1eaŘ2 0 bL`aal1& 0 0Xaa[ ,0 0-aac0 0 c1eaŘ2 0 b Ød*2Xp 0' ,A\s<{ Q`2f4 !S{aY1e;]=D!Eᘞ.^--aTj R+xO`a ,QCKMy15]LM=/b`jz_80XXYS" /0K ,IM{f< G Se陞-)KtDY3tp< 1Qvac0v"@10cSө53SRU.)1n\Y1/0 a(|S:vPk(Uό&T߁8˾kS-1C GZ+A0 ,A"bM<{ Uӷ E֯ȫ=3=T ]sv?!ߵSWujq2D]-Bs8P@%;*D.߽\u* @nmu2go}=~ϸ+9y|y|?9w}=3iucnW\9k|^++c Q2%9"1!,!Fv5E*fC!mD)0\X`f\Z"#BHU(F%hȣK8=S˹]Ʈ5y!T+cVeƥa j峠.6@DEx*ZA8~Q cBT*iD4+H" O/0.X8X|6],*(x hE(<> fe;iX"1tΣYp]'!8F8ћJ ffKbϋ*[qaPY0c0vP)d9@5!MAjT"DPRŘo+E4j wdW.fz޶bU_FC.GV7Lf\~hn17gnd+T0~ӛJkjU/f{ gVaua$$4ǘ:ra18 ZU}FT !FTuÖ Qe(QB;E 2}aX70g}k}^Rj-!6RҨ0 .& cq)EC T8HfC5U\L\lVO~ɓf_ qh+Z<"ڸv*,- Y? ֮UП ӓbc?V7.0 `0vlׄn)AmTCTU"pX]5ql,TM:+5 vn3#ܶϾ*Z؟*5Kmǩp6Hbz-X]VpP]ʏdE`0vHm*Dq'X𩊔|J55#U*xr|4(F*D40W^!9k+:׼gz\.ɧP\Jff{c-Fɘ2d1m4+E!Nј*Xs(QVL+ C$I*!J6{rdC~'a\rL`BQ8΃>UGS:9*թP3>QH s2}tB6jT@yo=[D)'ٌhG1ɔRQHy,a 7 Br)^su)֓rC |6<|[)ǻ|vN‘CiW= RXÚY}wP| J <*l3Km߯a"4D%7Sv95|,BՆNĖ'+%7(JZS:O\j:i#pgɡ}MıtKGx0G7ϓ;~u StU./vua<9L`!"d[}+a&6p,%%}W*9q a\+9w7EZ(k&>oQ>A#߳‘9:"H9։-H}Pi,>4!TfUs*"{ ,؉2f(Œsy_uE8S!VV++ĕ&TEGlyRV- X~dVB8K3NAW.tY AJCpazSzڇUX Uv)/zYSஷ~ckȋӀo_aڟj! SE+fNZ^V*qu]]EC ;rBڪWtCӖ8 x@x+n[w=_4B.&%B2q0dBQ8J_rةѹ41o$UO{'oBdB6Ai")e_a\fr7B[%2\UpUp}?MKU*@ 8uD2}:I syTpHTR/O2Ezpљ<z%~ suFCsu->Y9>a#N`هK \r4a} V]2= "kϲ4{|M?-N gٻoS'Vu_a\& ck*]j$BoePEQ^9Y^1Zi'N4UR&UR%iL . UC2*B#E T<iu [7zV$z*}K#vO177e; X#׵uu&}>L -AدRŖf$;)*giܦXSuGޞq)4~C$6 g'N^q?ϳ¦{'1%*ȠSeIP}#뼮,N%FFgks ;i)'+}U,ru{<3 0e;ECM{uv뤽m |hVYWI$ !mmZL9x9t0uk$@]//𽟥g?i~ǛՑBP"P1~*0 ju@5!BL~4gax>xs*:JmT^Ixft7 ,!9YGUa!RHs#%}Qد"O~ȧFbkΫysSe*]VH|uA㯒~% {سpٹ<_ QRKrLQȃ4f^ 7(u&R罇a.WB@G%`씫$x5C~'4VW P BGSh#' ~[+1a:6‹P(bDA8 sshTM(Qz(p[c}Nm)`z<[KR:u|eO32 ,Iݥ ZzmDHtу=?}Va.o˾_u Ҵ%-+U+~D$z;jJKRf/UqK7^ϣ{hLsS(x`ii*A#wn> 'H՚lb-3*|z1R̤tV~}YX0e;6wC:xjjA1%<쳶 7.dŕ{"N@IC]`Է%./7//^>*wq6xQLEi(GJb1 r#be{SOM!`|^JBmޗwVgy>)]ejbSa cGaA X+ ES환'xu%D{+̄3M8{":!h/7b-j|2[@x%:eyU_g=7 /yG(|Y/*K˂d(.J~Q0Ug*yOߧ§;a4"iO!9uj}-ia Rb."k{Ԫ31 ° a$j"'OQH26OheE㽪k+W_éGҚLAfn}ԯmEF.䱢ДmeɇqjdpJm< TdG8*ReUQQ*u. KYOZQ|%1D8X aR"cTO5Ǒ^阞)0XCsk+fqp1߽;pI9M#}=WҊŮ[QRU"5ySkF>nV]>\BmpP] BҒ #hLoX8OYDU H"UL%ʕ+%c^EVdT!}tw=p=0-Vr*W^+#gka\& )g}z8˫?/ !ä3< 'g3.tۅmFR%i;16:;"+8nX횤W)K#T9*BHA4W(TBW,ꕸf%sFS+Y0a Yp(P`-0|XS0a\bL:]:?El;+19>c͉_Zш?.ܚiR'L2Ru N\sj25kΝgPژd>[Q˦~Q+|cPyO%s|~9IPfwqQHnNxµ|o:XNKl%ae>ةTs< nG9zĈ+ 96V!tȡ?G^\w [uT+PukU.WKBdC]VQZVg3'B%]8KL TU^PsJB^'B}iuf|]NUR*R/0(%ZUcg62fzd~Oha0.>0<=>M)5{TaЦMWGxx}Y)' 'UNq[<'yňwN㖐?9G1fdwU݅TsJaTT*JtPUiH54AՐ+g]M:1vs IDATŕ:pIi1al3~2'HͭjdߐO>oeފVիd05׏5eŤZ"*M$ɏUjV󯸋"uh];`קWmhS0wK*X<ҹw>2ϵ>¹J s~?>'c,. aN*X`n Nϔc<޶06 ,&D45Sz? ȝUS{bx؎Mk9+wuka@X93,ڶsuHq{ mdEꛦ*s8HA'JO&w ]ZWMPxT]S E$ qȷ Wn߃ ןZT_,2feaO "4mL4Fu^1'wyEgu%ع^:Xvpt+_wԱ(x!mEn5vjvۂJT5uK>կY, -OH2t+\>OE^Q:4[rMrdYVdOx/ys{+;,ivaW6l9X5`;XM4&x/6+UZAI8us|+2jUxaB`%ju:hê9ץ<ub+D!{ZU~|c=EQPeNI0]>= 9G+yz,>PNۤhrK-ip>ҬlZؗ~2: ͞癆al7& cKuUwfYh%%>r/S5ofMۑ׾>s%:ibɍ Z|U=aCE:3cSg#@cu*Vm6FZuE +aqn7xe,6It a<2mO|v`j6Cݖ*wL:N+EͪzuoVƃ$u8L+Yotr_.,ppCST cϽ=}ͪ§aScj^{~Z\SZ{nsҴ ogiڃaǵQ g}Yϕ r ǁLϔ/0.X4uCⅫ\+5E\\r9_\Z?0^]iW5u5_ۈ,uiK≳lnBlE +'!"L8kpc|}6AY[Z+wnBugs*Z{ [U cg`0ܞW dr14h1 AESU;׈bUV+ih8{P;~?syr_zޡ͝cIW-/-Xֹ>gR#GWTӈe=REIu\QT*^<(isIDИĕw"Ym=ݾ7:t3Pz)llPx&Xk@΍q.E2@zUo:^ zͬ.H|˛ywa<՘2-2i9ȧtFl_ ,H"*UTm*X)A<LJ$scs@Q&FԿ9;~&qidOp'N0ݻk֊+\b\!q.CH[jl"U~-]U?{˛ӕb?U陒=}lO2-?w䘃+fa5&w%˫ׄ+^aQ }z) )[v]##^x"yN W5oL*VUUDm6[i:ӝKN;XwOm~ 8?& ch ֆs\xɁ{A})D{ٹ,Uԡ٫5Ӵxgt)hV0G@{JIiֵ^6d[Qu~N+\;Sk#!$ -=?~/4yփx,2 k%TR5F=A|#>}6yףw*EU+wqkU4V5p޶2u$8I!49k"VꖠHxSU=ZeX !=?F툫̅ma8ze 1k4,. 3SU cKGyj/(բIٷB3⥛}UW˺X䘆eX4,i*D|9L.r5:'yUE;U*WުjЈo-WZ/BV׎H 5XMUH&ÿWũP<^ǃsxhFsꦗ&tŢ6c;.Mٽ nq937]MjξcF!l,^Yeو2+ͪR'=`q c-B&X·xҿn`ԐTSB;EĘ: 0Ur05x8Վ؛LêW#we\y8|UkUi|Q@S DŽm :\1 *Ĩ-X|8E9Mfn4}_QUnbċ4~€=}9ql墎0 al7~c&JGf.SX:’+_UkԄR%t2sqXN ?3A&r%9'[g~ 'K&*/ִR* iU\/})"!8Ȅ҇y]E1MxW2\ >XO+4%N l9ug0 al#7y?[$K4mKPD]`n/ 9v9d4Ծ"R@@G`o{}sTNbΐyA@ ?9ȫ69랦dH]ꊬլ%ME0߈iW|8WS$WPrӳ(uhtLSzeSQxj/a|<,WIQS+s?+oVGf> c'z)ݳΥ9.T9EJ9=͸ZPIJ%>#Ogݧ^tED- V늭jv`UشS.Vp3Gw\Q'yLZ1*>xO98'ux!ڲ,Ry#VgJ1o0sc0ow ʄ (BJx_KQ|Us/n0!>0S>>G9FYpͫr (gz`gfT*3M7:U;D|9DVO J~ sƌǓҜBlW" oJ`?9Bqك'"8bO!+친8¾32a\bL`v.iHJҨL},!^pg s3 nMëc'(?ALaz= }>Ɍ Sn/UB'VWcE7s6!n.84b#oyzFYx  $jHmNZ59p}Xm0s?|}۬ibJP9#CQUy$|*aS ,NmI]B6a2GbEX9\Gp}[dtnF'4g]`pu1Z]sX,:!+ xwH'ڍ8w*?6u;}6kDrDC ajª C4ilVJ+,w N|DضӱԂnWjT4Ux'(¨87~ gv=y1 c1eیh^%Sg.sk85CYӏs ^x'(8'8%Fw~O?X#cUe<+1ZW3{=}ҳo 6Ǻ2]9StƲǣ mZ'ā)\ܜ[Fm*ƐIcYek#w"sþ`QSE$/p}qT.C\]9 űT#)WM}1GY2 1eیv$K1,.Tş9fPުb#wKH"ȓ NfF!?>3%{/f~O陲ٞvu+ !/|rĀŅoJU6Zuw}/li krEk: kI׳ Y1UTQIЉU] zU-$7*S /^*K={λa ,N6z_cr57L۹ rf~ػorp i^nuծ1/?,9Ծkη9U֨Zc F]X+2)=7Z\'!xᆪ}֊ hL['/:~E14ST%J+IE(pbdX{ yE.oƓalnF*i`bv䍀5˄lrQn:1׾C/ _~'{Rk|ծ[o w\-o.o=FMWjbqcaU߷Q{KE4bG52X,߼CGt#Hx 1W$K~Y1B>YtYRHQie!8Vb=10K ,njcnueڢTHhcz*oQp”/X !'26G_o1t-Lϴ-ƺU_o]Օ1+˓w}w?5m,`6[jQBh՗ Ts*/`U U&^%c$ӐV6/xDaL􎙢$h(gшS(C7}?7Maۏ ,.L1Wi ^nOmХ$vPKfFa LwA8~RI#y'VUR.(;{yO }$tk~'j׮^c]]SkڕZ>s?Υm|.\dV%XUXUN}/pc`<ܳ{MioGuZ!ej)O|LeTɰ *USr,g=ѱwA0 al#0ff^A-rd~au;un-["^VVPq2~a}^Xݖ$j@}_5o-ƙٲxu]"$zVVWskDOPT&sT**xjUE*E"EX!=$ LTnaT ,<ٽ[0.& cI9M9J@֔]WLzLR"{˂9k[|Sny>(,f/z1%tI^X?rDpyIU: U߽n71=[6sEHzϯ3?xz?OEGx>YZuUjVIU ?}ڨN@YI\'HHU) ˂ٲZΣ"˂qD",x:rs& R`0.BL?[H :zdӟiV/9|8_^#ן9ө$(*nK,RQ&s& Aux| ]W6!q>F?dtX uBDak4Z~%X+IJQ%54+{whWd,TU*|QSAcDe90 c0 u y<>*r%`?{ ﺫVڋ{\h/n^?8ikt|i8!6aƻ ~1Wb< a[毾#jZo6(_\_y]|zA kFe^^^' #F9t.*ȿ B'*>F˂k.hD!iз9l4:±4hj*Xq)0egxКUSS ™֛mVEUH6BQuɟ&DA IIےxu׊@eoVe(Z:[- EV#&DO{+ {d7ҿz.j?UK>?s$ ZXa<㘯sϱm[-t Tt*\Q0+<1x*1 1SEA1R{=ƣB"s}0' ,ø$tXYEI ݕ#s* xMZEJqG WY:+"B%(8@ѐޡf+<~a}3"||~ĕ/?SiATz7]Gy~/7пz,O5<9pYؑ0}ծ[#! [~_o-T%!Y\yF'LYR8;@13Qǜ8"+ص[al;& c̿op# d~`p]T)r+1 8qZuQ(I"#t27wݪcDZȷ-͊ZBZ߷|}F.B]d!F??<횡 n8ysa5xx|-|0=ƒ>yspfxsNw17=>]ٹ-o@`ixĜ*3sݕWޥ^ҥ9j#G0eێ ,ødtyM5Km cr{MM1G8xImEIPUlq|kߜ`pS'a:2al֞lG6gVT<"뿁+w M 1Q%.X^Vﺷy`Y7]W˚j-cs IDAT빌Ռȡkz| yt.Bbxn_J?wL|s<ش{EAPM["0=^H+=ks{x$P8GcOUs<3妅aOX|4%:=/ŧYq)e~B^S'WD57K .%FL{^}לX !&lFҏ:+UMU5b'+I&&tf{q.+Mï~L"UL O燿Y{DBkgv#$:ծ3K#sh^&{ +qsxk3ާsާM^"E(TCvC:nX2Kg~?L,&VduTՅUѤ'oVHDpPP~/tS"vCEw}AI*M,LGu.PM!Oq!*/fpU z 4~5!3KxCwDO|ue3N[#y8r8-rꉥUBRJqL̺=sxUUjC@4{/#g.c]1eIUWZ@6yvaAj#O$~pc]*O>Y Mf;mv6a>{(T162 >o.]LB[шOˑ8r88<yobTƦEXvsixy8W Bӳ0a\B>ΣYFB;+IP:GGs%xNA9σR6rYXHD'WԔuh5&TEdb2;A#'p6aՕ++8wLERw=]sPQb]NJ TKi\#YNmDx9qlVxSͱȧq3=%w[ȁ:ģa_Ɍsi%Wu%Ϲ̬T*H412X F -܍ ش'7_{MOm{ayī1yb0´L@f@I$4\Ӌ|?ι7n̬,UJnV*v>jSsUPy u֞1n`-c(((X[UPoR5 g'KBϬC6ZgP!_>qٰlVVjf)\w|,ͽrƭ7`08Ù9>Hwي6j?ԝ)%G>̨o t3"4M= 1^CZ2Hsd-q;N?Suv~lݱ [wlZܾwcu^ػ;ʹ1,x x< M0?פ2_cB!X͇e^ gf79Ȕ-RHԔ>K7=v4KɳBh=d&x8j܄t6~& PjJhBq#rxZݓt|}""1nNz&ˋu;nݱ y qN~:Sծ]gnǮ3 Yסqyw~{ހ~`mUP׿_N?' VǾwAva)g|M3,]`&8b%5D| 8̐)=sGjRc=mEMS^=|zޣA=y&/dDbpt{+Wཇ[\@ZKB=uަ6)wځ(xI|,kL-h ;+zg>/z [qoq#Oř眆]g]gn_;bVW!q ;n?/|枣cAA(Xn|o㱯jA8 m9<{=[KU,ռЎCό= U-jiH *C0xPMH|\Kѩ~v06ZёDD 1yt$F]6<] UE*QoؔbV{NOy3q{% 7dRXD0< p fc>]؎;6agglشeM[K"$neD7""\ Eb|y,S|NvjJ>SjVrX}s5$ <8xF B+W*j0RzT–; sl.$LjUb!:ϖݣ-pEVhl¼i'QF"Og^73v$ $Uk["49mF{'/y@g=:5S#:,((X% *(807 w "+7~$$~hDlH%D=F9O~^rؾ}p$0\7bv #¾oV "O1XXXp;wlڷhѩWq|P@5) :&cի?O #ķ_c*S_,\kE@ВIM  JQkOŁLJ<A}=Wc:գ=G(ab88~GKxj0Mpʲ]߳WC0*!"D<$1t@Gq~b&1ЍYe0K ;N݉5'`uU)xV)xIRCĜ.ݵ/0Sz OZc}qOѹznApp>ْ=HgB˿9<$1 *(8I2a%@#ZD %F2%,0}x?ν`v"vP90/¬aF@VU+e"Ѣe4-ivjVR%_zje_AjeUXҖ"$ffb0f1)d܉x׽, jՐmTca<ߊC`>M6 cFees20؉ev>/gǁ DŽ)Oʾ/*iY_KQ0taBm#]aX9 n55/`"g V֌XlJJybdPׅ!/m\xn'񬎌xo F#Y,fs`&]ofa`kJ7W $E~3]-JlFӉFtb˄߽ JFvS5J<,!` bVPjg`} ф/H8;0sG5q1ES;C}ٕ]Č)IXb"l lf)'^#Q @ӀS`pa]Q  $BۨP՜T%aaT$+EQvߐ]Kq\ *d!S}cTVVUe*YCRYT26ad&l>L!*[ S2!rL1 Jvf 8! lbXBdTV2 y4"Zv>tH4bgi%\UaԈeV!Q]<k"MQ[#`:홌k~Xf3⡃l\:!?Qߪz "HTk`r'u;D6&=HYj>Op^>$LӔ\ UnkL5 #eU:%MbE#*nӎBS=yAAQQPG2!::` 6le;xpu7lNbwhr/E!X' c˖lY~ {L3u*0θ}$g?\~e?&v&>b'3,1%߆^R#Y^|*A*(xp·?uk90M3ZPKj@312R_O bObtUۧS1;ksU1b̕9W_A))iDHy,k̺1C1%"6gR۰r ] gMѹ=NX\\ypIq  *(Xg<KH"65EӪ\D`>}vU~g%c6$Q =Nը,\u#sHVfFm)uÜP;f<\R>ؑN"uD#$!x^ާ%`FD;+ *8=ȧ2r4Z?r8۶4-;UrvˤZX\l B \#VI`@5=%rŦ69"T̉4]'˃ɨ=k޴Ͼc aR5慰iꓫ MX;g[Wq^ ?#phHVfH?HN o۾븾x g^e)j:u blCַh9 #Q5<¹~^ ,o> f1 1CIasDo#b۷2ⳈrN%!^`] 'jdg#B<֋A,j'["pbx `]`<@ͳaic7Y Q# ȸF!>˶/{`}PVA:W~@/쥜X0㽨`iI )`5BFVn8U|×PzZ,efuxh4fXP &"A%}=֌!Tw }ufzi?WWpG!ht8c&`֮]voFxdLIc,c u0vO .xի\aX9SICW&Im=Ġ5W_U(;!VxcdnLVcyZJAвL]cvu꿣` *(XC~:bd* 4wI =0&4 9zls[=-x17)_kyE**T(YTGUC<Č,"o:SiLCxT=;Rʾ۶xOy/`Ǯ]DTat=)*cmqޣ yVUu%@"xRbI'>XY냢`!$)W1#ԕ/$fOd!lYA,@ɺz*]xƋ."_cun t28yцS9DGqnkD c3GfPi|W!+q^TIb&T+Aph%m;$ξ"Ny[QaE$\h[geW?5' UPF8wJ>WY,x[#y橁]@UEa ݦx)8,zG`<֫3^|iQR7k^vU,"l[nk1]Uk j,k* c4L,fYwf#F=u/ j[Q5 Rg-.SqgO_B @5c0uʡ" CMmdJX+meQ$hKW}x%JDI9{G|AKU9 0-Ghǝ)D|Ch+sLОGH{u7 IDATݺ~XHY->”+jTix* F02\F%`}PVA#/. *KFDJ, Nkmq፿O;m33!^";z㦯 An@#g>B2uaG=zFޔ\-r)!+=bzG( #2[$V^S(k%|I9Й,c r`G:m &Lr kq `N}yU 3b/\DK̇4"|G9S.zq:l\9ƌvNF\q/:HVJpV V]RJfN?m)?*ڳfڎxdԕ M_x=zqX|n"- @);2,S4"bȕ)US~cGG[]a`% *(X3tUBU*Srbm*'[9b&p^ 7B<׮##35MU] cZG 7Dg>>vJ|h vZ;<3nM4^vԶvLOzqCzgǟ*nFOg` Bcm|X<4uleC4qB- *(X H$U58XMr. 0/<ϽѨ;U׼u(H:*^)k|nP^~gi$hC<и枻aOQ M:&9qw3q5EJ/촒o_+0l T}R٨=6:g1xjf Xs*0j^.‚E!Xk2?_|iU5R !W&wlREgEv߀|5 ihԟˮ22T,v ܒvz') ¦0 `z/΁$,,L~CH:+Xy1X_<E_S !L\icq*XM -(XSUP=rf9ZX-W2UߩX"W.#$=_)C,n!U) Qr+=g;@*5{pk~.zXvlHlF23/V$[E|H@ɕdj56GT4£!#5cE`K p>r.n'J` pg^dJBhG"6,K}R'WR0#|Io\=8 _rbN;ܺ y0f~ܜ6s.*MBf3\?U}^+ZR&,CrZQs~.)O[1>/>&Db 3*d I N>2 N07c)P$$+vT%B B4I>1#0rU01da^/nrR•?Bk@buVRj~%—:>`H`V+5la$`tvukB N0^ߜ Vԫ6[x"DV0r듫yFc{@  HPsB#bH}ʦ˄S}v@&f5s}1UUǝ5I;>vUJvY >0HzD,HH}_U@Ra1"n_SPP< *(8AJRj [fD*Nj8rdžC˓Ϻcr5 ¨Qv>>'SRÓʤ!%[i3O*(*p:7$0*LG-gSܠ&w8=byϨ卑6迼o/Ѝ)]k*(X,UQ 1j~$Vv۶x}Gv"f!W}s{_c hyѬDժ\U VP#R%vD8Z'Γg- V4h͵bS⨞GO+e8NlLŢ4Q3h"|OࡄB N VR~ga݁VEb$kl-NM_T<.vt 쬈6__ԧ4 Dmͪ`뭪smh[$s\2SN ? B9*8W'?0ZzdW8j#0Nj`3]WђAR8&%QTh8=xiecA XX  @K 5PUM2Mtx om`p,A `oaJ!8#,!U/wmBZPPpbQuF̷Ԫ*>Wkad8O??)*zuS.=bGT1Z3ekiI0*dQ.Bvbu/$SREbFm bglƨ0X]J% X{|f`1UPpz؜QZ`UPꕾ;BǹuPP(T20&v DA=b!CF\D*DԅRG 2!ٹn.PO L!B@ 8,"~fcXқA *(X+fen@/YU˄[n"eC_ .,TM QuQU6y6}z.EAUPXB}ةW~-O#`fYL `YUJ|< 1x!O;5316(04!F:xf^A%fW<в{Un0Wfp0ǵ [X7/""Oۆ-pvqNKhQZvLdY6/UP86%XI d ^hv  15sY:^X+R%v15eD`n+ST5딱=W@9Em40;XnާlCoݛ0 *T}R4$rmuY,MA *(X';V!fss{OJ߰}yRgۋs r5!YJJĺRaI=9s91#1 1 6o~ kyBV8G%YV..J1{$_̽gT9H*|F(K;?=`ȉVb4 ݋ݸ/AnڱxH8aPc*W \bKWŤ)sdOJQyR[_ʥ:(?+n?{t, Ցʷh2N-$`(uĤoV.`aax%% [NrOeH0^Y̐18}Q^:%,F:XRDYC; 0j'c+E3jyEůc^'>4RUp!󲠖 (yfN{ p{~] MPVA܋+|-^AX[Nv_H f`88rU+/H ^1#@ AD|F>s13BhEC<oUˌ_٭9ć`>U ^}X@j+aU_޻ :걿 6^-W&\rM. gn pרcA!X ܾ䱟w>h1 VA2-#`0 ldb9Uz.$LmqvU& hۈ4%Af1>j,MC꧿C`- #Z1=3YE ȒqܒQLV.`dIVvTaA!YGC`dmT/){!٨dR;FERtfv\z+D>5u_Uh|g4?UPF!X'9~'+pGn b| CBE]9%]sζ,u:UqRAȺAmSөIg9&3p0UsX Į:뿘㸟+Jȥ# D8,5xj:-`eOV\wYAz N24cփ*TC:خi00.,{T33 AK ~2b> sF38kkgp{<z+>?~uU%pOk x|@Kd'>eAnJ7h={s T|c K!` r4N;?y7;gg  s .jx؁*ŃO1ss;8oPvS5ځyʃBEG> {oP K} XHU:)X{@[QRr%G Wm"W-Wa~($Cۨ׮=?u7g#r: 6Bl0 Hl01ztꛚVSD`·$Dˆ]LC20ЬgʯZ,#vqe?;O p˻@ ˣ)~$!deϫ+F+V5YYedQh9*cVAAJ($Iѻ-.M )Y!؁B@`FAk!h!$ 'u`QUk 8Upf۠uZi,u}N?~V%ퟻ s_*\gI2JV_ZJT =*/ ի̜KD:fOB)^P j2' LuKnϻ9!Ts:CI%w S]G4;˥щXqh*vrؙXTE:T13bDŽzի{lATts.s| Dn)^Z~UNFU4hdR&,(8 dEx-._ykqtjEG&Y YNC*MՒ ]~,1=v>vcV'ULmƍcʘ GWYq^M9{o%%H2`]Xܿ6+|Ǽp_ #˻ OcmѓR'23N¶@PʄǀB NbDclHDcsW]_|u Ȍd~8{,iX֥#{g~? w8p[DRidi&_ SK*?C#o`tNdxLUZ"LhXT&t(݀Fo(Rܓj `4AE /u9h^ ~+@ͬs1pNl||U\}v }`v 7Sn|q$M+v;"=~Cߏ{`~`AQMNޠ,IW] ,|kA"pοip!* A@ V1Al4׉PƧv0s'ƿlقsG.7)W[qE\E{({>G^*{L͒n`,؝>oc`cTؕ ]"T~bl6{V\*HyAPVAkdN =tUW%$এ5~S!Lp hVJ;@eqO>\m?8cLKp09fp{w* =ͣG tʺ9=X@G3e딅sF%KVGV UX")lH.W+'Tm,am\ ($DԵCTS=ZNiz+[. KA*"?o X'{gFC/@X3aE==a86ooZ413tjdl_4!;u`9Wm_#XJU:w TNt.xǻ a59U/(xh)k(Z@Uq,Ŭ+v *" HG C@Ki\gOԫ>Y}8<ޞى xZz-b!лS¡6*i+;:bg!3e~^\fJ涬+U'.󘎭ࡊRD/(8ɱV1 9+ޥgb--n0`,F``bz\0k|n {vRy0 E劙_(i_U4yPV禦S>pv R5jgJ@0|ʪ/XĪmhEn~~gxW"fM3}>UPpLM1^G W~ח - F0V+|@-A_Z . 2b,,AHE矕n۷rJ̜"5^ggA8&{@Uß㾭:oީsz]`ZG+SЍQU+UL((xh隞S#\dŬ8h-%*A5Z"Ɏ-"xKrM\Ekd{,PZ#Ll0tN˃HgnroEǐ[G#9q ҿ~4=`] [aq^@V&>Tx /r&W=48VqDMUPpiT(X eIVzIPDof8.JNDB1#C?SKD`ߵE$$ +SE<c-FUFsedG#ܰs37˧ꑬ&ңkmf>}sdY]U\%r%0?@!XGC`<&JdEDodd*"E0AY"ɛe?ω_6 P xl6Z4j YSkۅ9 w>sTaTUsên+f [p vnj,'Npv$`ͫZ zm!c<^x|41[/ufzǡC8v8#]J 1!|J V$"8]hrTnSϸ?Pu*܃mskzg>._WPPD!X'!뚑억]o_{woXI)JWm?*X A@46dQ` 1 eFhj0$+}Zn6a,F5vΆ:{!`~~3Fׯ~5|[qgtʚ}odH1LjtSw1{UcfR.pT]UPpАֱ,$ʺ]6fy;⍸R"TP87l\cO#fو?UʂJp:pPX E˂Ań  kvnۦ97PMMapSS!Czj|1\=؏nAwoÓt|;UҲ,hW <ǯQPPVAIbڙ`G#3"X _xW5!~/QBgֆ\猬0bz,1;U duFgu{I݂SuN5a8Nlpζm2b`e )`Ǩt^ӛf-1pw?/Wbz} !݋9! UPAʋW/S2̱m2aD Q1쿧8^Ib(;, 0JČ45^1 q@!ƁqC@65`ͣm:|D X ߏ`瀶E:k:_=Cˏ$~﯏qդND~x1~FAޛIrWnDfVUojukmH4xeπ03~f ƀaa ߌ؞o2bц"n!!VU~wnuW{ EdddčHuwnPVA*G0~Yޓ%>=!̯rlH8 ?ʺڠiϰh'Xٻ9ji@0c'o>p_R(3TWlf5s|/nLUaѯ* 1*f|kN0S437nZ!M[˹Ӷ`}._w;OS"]\??,`B ΎGaRjz^ Yn4Ǟu4q7~rfbPx"c@z3E?A?N\3R>}ɸanN ,3PlMg` zxUWDx-XUغg߿T֓G@^`fkWLG!XO2/#jH' L =N)6$o~zv"J@q f V@PM!K˯~[gp}4;9lj͛qΝ>框XtJ[S{{f7߀ɉ ,ɽ`"EXC.T WΗ gq7b/VXoWQ z ʎ3zaf?!mF{\(ul.IW1_>T,-txx8D^s' 7Oߎiflۆsss fqr-q_e?ֿCEAAEQ V;"U"LeD! bϡD$1ߗAˇ5V`}O2#ށD9ӔA"<;|S6m9,\ {/"Xu V/￁ t aRE˩R4{m`RŬ>k}ob\TBlas|Z ; ;pQpfv-N]YS֬9]jqj(465OAAUsvMWPgu\» &D3:y] $T)Ch>Z*XM?0?7oƕ眃w~8œS׮Ňn4^&G^&,((X(`"TD C''2сðqg* "a ~3H )⼂Y7~zbEDK$Sx!眃׬t{U 33U֘$T)~хB V!\&wلLDד[K*\bPo`(t]ėS?yh']wń= W eHN4U%I٫YszL9a3=`AAʣU+v Y&ᖏ v3S0ed)*V@qXs'Hph8ՃoLqu~f1S>u`QRt?1:>_?v;-:_Jy j/)uD0f^>@¥8ʎȦM8uz87ܻ݁l<}KV!^ٯӡ>2)U&3s' z&`GØu}}]7[2;WhhKDCAUqg)۽zӱ\uhqJt!yjLUъGtJ}RANphI X Ͼ~CzUPGIr/(x@)6itNqb"b0&kZ`C$u^()W~%֔?Y7 w@&C6q>%QQQ V E*(X*4sTU_ TL˿ HPim 'Yݟ7TVvV:lOnތ^kNxtD5< *(X^Umґώ-,JMLe .zُu|-J88XI9JSB^t9B VnLM!\}zcCD3fZB:TirJaAJU8_5*[@4o)̑ `1w BC0bE%&[K)[SYrfsjèU|zUPB!X%kUhrs*!e&(Bp5q@ %ʿp%XLNRe|Jת\1*6LE ^>'UEXPr(&UL&5f/_&^ߑt B h Ztwn|.(Pj_3R0nIRFVO0[sv\9`38sK!}T_ N]Lj0H~mWlG>bㅏC| .a\ek L$P͚:sg؁UߤR]5f oyďx V`r0„K<|;%cf%2`,1Oww'Rvle8ɚZ)ZL{D5fOQ?R*{:aA*9;'SLI9 D !q Yb0ޟqIVI[_S*\O- ̨Wv`(9X+`R4xO; b:+;;";^RaZMS,֗ ')̨aQ3c0[UZk\G"+((x4(X}jQY&@$&QMD6}XU>'1p]>;yJ1 X `;/Ҏ6-ʟ_lPU "f֢2W_`t~OUM')_q+(X(`˟9l@q.sbo7!3e !K$Z@qʄozN{z\vEx_6,U+*V  SBʃ<8AU51XrWw x\1&UPp qzYzk03ؠ77yk7f*0W0y?a.zDڹ'W6O#灑'@*:`R b^'al-Xߥh|OƬJCk @ANn{SJټ"`Q⃞.&+FGyZk1[ט0WטkzzStկ6i ?#GE*(8̇DU " "d݀y|,,%[&@|Dn# cjS2}00fB53h#>^LD[ǂK.»?5hD5Lx2RA|묳0W׸y/:Xn/JUanDɦUP(`qş D`|cr5O +bf“>|Kuδ1Gf~><\/\ɀ)QkV 7AP13{m wv1~1xԓw+_*`Ӡ IDAT~kugşnXU}R*ݰ`U VoIPKK:D1ٹ吩Wym_w,6`XSマ 7Ǔ%чB@0P\zFZiYeŹRs`1}kȇ/[A T̨٠ 5T!32aAʣ¿? Q qT10FvĂ9--~}hڽG4_ۚ^%\\ԶJtјIҮ| U!B"W9Q+wgD0.=?}i Cs΅ûemut8Vфv;޳KA#}`GF#4:Al4b_/y*(Xy(!4}9'pBBu' dKVa{X+iS< ?~WA}ı񼬹i8>ޫWHΓ+ɼY/{yuIs+VL ۍ[^Yn5> &F)xg j&AYQUՃ`E|* "y( qp"-NɖsW:L"= _So>AHJ0Pc w?~۞y5Y&Yĉ/"Ddh\_4CvUHÐDŏ},5`4h`a @XRPPpQVAQD S"-8p$X,kįZ{֔P9f`90~ͷi|J*m\앳ʄcOzWm/8v_,@GD/ޟdg"ح[a^ YM$Ͼw}c 3ҦhɢnZ4FV$s&2|R V -(XyUPpՄ-*pd9 k-0XW iP3ҝu`yAYJp_ɺ"d0Su ߺ sbx9qU n ߥ2&=uA| o ~k硑H(Qŗtu#kA]T 3$Ā 9v1cOp~_PPpQVAQ$#i7;! ZX`a kh`[5TB*-f^,fHRr.ve/ߚ}^~GT<Ԟ—p1 !!sh-fpUZwEBs!TST< V `%u- zb uY8Ċ2ڴeTҲ JԣB!Eb.AIX J:VgCaBooʈ6)p}牮#") ,oe @ZzO haw-/y)#FyC#W?~ =aUvʄֶZdjGin5 gclt9^,Zn6 = pآ++]ApG+dYO<e*2LA  CԭW3x.EN}xWeq> kf@͞"h4A΁p$ GxG_;-Fa1u1Z9tbs3XA06brNXNcTb`p>Lu)x V `| yV"5eA l[Xn=2@Ѷn-EZ.%'N g'`g )vm6%])b]S:0h矡W|7]JpĖ$+= %^JnHԬ?N7<Ԍ8x6]O`c`| ( q0]-^aT"hkSPPVAтg  x3Aܘߊ Uɲ{,\1MGjZpR/>8;ef?Qp3e ȓOj?@xPsF,:zQn'?^/mKU$۞LAd,/щe_,䷽?6JO<{ ݙ|%{6 h|4I uM5aa00cPUhl +ZbY0*Th# >+((8b(SPpUȸw߹4ma]gذx5E6hfhQ3u'YΩλ8x9=OSW)de_;nCUc'l q}hVz}򃿟[O}<"Hc '@+@ ܹ%BNwIƞA?0: SoڗOի zF< \D0D1ўrjI tj[h i3A.@9=XԂ{2Uj[5'J*- BbPlV"<%/}o?t\,Υ_whzci"3%"}8()+}x)C*ɺg|&?}Y!iA"@`[O= h[- <'N!aCcN+abfT~|F0 ,T`P3 X ,,hA^%;ֹI8iJYvk4M`Ԍ0 1016Yg;0ԶWYժP(A@ltdվN2|H& ^?@5NʅPKC"l{ EUx`h% JE(Lb,s ƌV|!Wxn FUbb+]7V^JU U-åDXPP`&k `&"vDQKރeTjGPU^aA΄twDd۷ w+o9340u6E<`݉jbRXs7j<fwfyՎ "3D>C(dz<"OȗqiXkZ0FOx zfa4D;F J*VJh8BEMXf'Dʕl:G;AXP((? vz#cvɐ8S\]BY0``JeB#ס@IS P;{-x \ y79d$Žwʉ.4\*Z̬CFgVQ,#*#l{SM[nVdJZn /DcZ`ӀbnIP1:Fd&GpDЩ b'@JjLQ3 `"U,%G&T, AHBls9r:; ԵZ e9JCmņ3Μ4u>h ~ߠ냞9Sw1cfF_Zķk&+⋪G3 Jy%>ڀW|胸oԷ3'~>Չq_%>Ρ u ufY@S%z;C#98 uiC yK s9Xe‚cB VTrΪIWAWUZR0 VÙ"hXbܣ ٮuޓۿMBz?o򖯨ӹp7x<1laGEsHBlaÐUބcXvZ"4hٱQ䂂Wk&U/v6mmhE4͢oh[n`ra cLC3i4 X\ܫ+/*vsV$ϩ\48YmF:ixv~fhs>T#oaka'EHBsA cVx<U/W}~sW?tiF0TCrm:U+`53+XP?,1jьTjF X\؍R`bTAve #'h&sPMcN nG# J]VxmQ']6cO)NEډ'D5ʈ.U;T9*]k<^" 9B))4T"˛gQZ*]+`:*=C@ĂHKƴ``Bs-IU0yUcY+=$Z8>[; 3)!AIjsiElw3p" +W Џ'R5µ S`]ɂSʅ!6L]gD+.+c%KP" H%BΞu,"ML~4qX 2>“=cuw_4 & kBe 3/[7~uOOܰ xL.PPPptPVA @Xd+[>݉ڝkkݶ'Ӈ;,'v ޣ ODl*Tc\AWUz=T5u^  ۶en s9?/` XjNTʁs/%ӟ(I/s$UĹXOLT0 @w_Di@eR\Õspڗb0X~ 5kUj^9Xhn{44iv}lJ"+^?oȞYwCjr eCC(vw$@)>h &}{?_w~Ϙ-aJ_C|iƖѵnzî8"VPPPcWu^SȻl><',Nz#Lpm 7p Vm 1@*~O fz4'`mc'bն#kwLm@8 5QmyKD*[9~67J?GwPґbbx7[?YYMf39M n>ܜdu~\yꘑ@hSv3y\uDχ|?]UPoذm+@}/HƠQiYd+(]^@5F Tȶ؊>G:K<~=z  CZo( ƫYpyZhQKG&A"#"H#`$<01}$ &);bu!*Z:M7@$8b%S+A)Z- %c?{-(nB!Xaq_^;#Z&d OL'+#5Qn{0jıf`Ul[ACTp8TpDae;5U1}iT`|'^Dx7RKJCU?W`66#\9i3v;u·]/b76n Z;o^\Dn-Aov>Kc8wLI O@JiA a۟,*zBcy3(A `b8nr~bf8q{ޝ)WJnluUԽcy#ǂV{A*ZOOFz&sl|9X!<3,ҧWacFT 51L]tp_*z*U5 ك-.1e2#i3~}f@Agg`37x l PMƓٴF/Vx> gpm0k$.%,kJWh~`"un{P 4cd.>! C IDAT>*((H(c4r+5)=2dg9$?+tVU ScpgCʠWlF $^"(ky=% < ZsSOjTT ^$S|Y6d+ZyGabiPjxO݆ *(8UPp 1Փ+_F#K0)T9OA'+#IR^{E~Ba%VUe` 5 g[$4ݓї׾'(X?;񛧜iߜ~~ ֭&3'}nxeNE2׉_WxH(0UyUB⎫R5.SBSWߓ%E:I拈sv UҒVsPG~e( jI*̀'`@bcMTvXͲ S$R!LE"69.CT,S, =c0s͵`/~Q=VX5.P" k"ƍyBӽ0XLf&#v톔NSNtCGWu8-N K/.#Yi[M*WZ"trocmtw[meAd Yfe!0a1j]:- k)2Lx;,^uU'FHkD᭣ kɺ%Syhr87沒'೿:;^SGP s 3eyW,tS(+|fƩq.ed:}N\uu&AxDΕIrՎ-6 WNƗ\ru}`3Pd"LşP"WWe^!$T h1a&⿦c}&$*lxſ&s:{IB$$-qA/*Nϑ."9昵<N>'vCtհCT,=#}k6Ss aU5Eٗ$ќ/\3 jV]4BUX¹&n["]g;'VDUPP|UPp,H$8Vihƚ_%:J_C8>+ι3jS)sxT8S$7'S6Ptt{tC#˳B$ Wy ;}xu|Y$d֚,5F`l0.@Wó몫=;*0O/Q Īm>,ˆyy9k]!XUPpL;Dj&O!IDʽMa`_:`|8M˱foF:J`WWU"Ϗ{@% <ͱ"8G6m+[ؐs?"/pHVIE>h{A;Oֽway @`4Aw_yN8-]rzrՂsXveѵ[+pbaIM|wcm[c r5^?L'@Zv_Կp@\"98P&4UTZzV.C~>DF N r%[M*BQѻ1+dDgK@RY\T;e%? u02_ CMS&`ԫ D_Lē<?&9]$˃ )ɗ "ɴ@;|H7%{Ejq "iID( *vkFNR",(X>UPpr3:\oi:3e,a)D/'|> Ƙt~I"m'p~%1Ɨ+;)YWAR MCįtRW0)P^' uũ\)e1N5f3:\!b⼺|e<ٚdip0e_XuE*(X6UPp eAyA(1yÿI5"2r 3Ҥ/W}[D \%O!Q\\u,TH~ յ0!IjIYGU+=,ܒpXc*H4%+7窖a]5k\ehp07UP\UPp ̳vדl?Ώ̌kA}E>=/N~~v 0N{~_@`Oxe=ŭo%bR(u[JR0_ʃC ɢs|TEAB VT.rvRltZ f=ٹ2u'1q,]H=X ISX'v۹s>^.,O`2dj)_c?^E|`&j@ԠmSiјJ%pN$4 8Z^AB 5BӁ03U)EЃ+A1z k*SM".h| bߌ0ĸ/ƹ9{N9O,\cj0+ʝp-Dm'18܋8 _A `C2Wr"ĘPσȇ0u v+C,Ac)8 }D.p^iז2sq,JZRaB%Mwc˳-ϑ)f{.綡>z0\`qO?gssʽt`AY콷,/fwۃ_۳ )">%RU:`eA-9I_8`}ğAAB 1Lq9Sꐪ)ª2êRcN?>y/ijSI$zJ_ϑ3{P"d'+yVA3LPY#FzB[+nAUP>꺏r512=Xڀw]s}eY[ w}7h w%LϞM=o*R(X\hm cZXxOyُ Q Vun_0\ܫu?Ryc<9Xd"^__5!W?ć4baؘF" ҈`(yb!77ooO}_WD ehWf0Rؿ{卒)xg8*m?e_9]D,M3Db^0h4籰O~Y}(``YdI4$- NQ23 \3'zб0 B}3 B'D CȔsJH$_?߈ .`_(=p"@ AE0ERK"@kdb{DQHrնø+%S|˓_|IUP̳$0pErR)x6 |GeРb;U A Dj@J**ZwqK+̟yA1mbMݕ,#yB0 ph$k﮽B8i=TqN 8EZ%i?v!_ U3΂Necc`.GcoT~J9D7-{ A9 QŚ>ժ:E9ZsnT8 Ar`a>p'kjd̫]/ᘠd˓uOYܻsw*}"#ręzT, 3 ^O_5am)W]jvAA#C1ḂktI2 pU[HrF,odWg?ϸfTiE`j*^uqz-Ce84X"XR%E50z˧%@\QHH ^?W]̾caח˞uyo-81aHfք>̟w hnVH\L{( VA*F۪#g9 N>EխP.dEvP 6`f4N@n!+`e>!:O<ˉ_<9\u$ }YqTjeYBcSe1h~殣,kvՠ?8((1H%Ht ,$!fVϗS+L\;$,.&g rRsl<}A gTz2&OCI06ۈk$;DR1 #*}DYrp.kzp>k~)=oջƈطA?s *(( g_B"Wol7\s2#I"\lYZ*-%%WPW\KSPPp$PVA*mje'ug533:jH Íx6.ycg A7 ?=qS,aT?OY4Ku΅]61c]sp܂%LtJloSGJs-1{0E(kxqlCk8-K2zۛ!"urziJ^+((8( #?`qHӿpᒮ5ņdq0D*{N?dUU"*#UlWx pus!vKas[j>,'kb\hr̾L rJĠMY c()k-ފ۷WPPpdPVA*F: 4+`1Df%[pCL-2AOX'\x{JY_C;<4z/MYw0Ek?e2UzB)htQ `[0pᄕh\AyVi9tl-"<iGvh Aw  %LiO*DjI],G@EDA}F5 p )"/Bj[_0e8[~8~G`$ڵ`PDG+D}6Vi8LB QDHI X_M=JLnSa%*`Rap>v9LYTD@2Q""yE(&ݗaLʗ<,AU)+o`EGQ?_@Qq9=3 c1e9m4 pn۰dAS\CxHZj?Q(dNa&L] vl9XӘ2 V  פvMQ) ;M S8c8P^nd N}0"3|Jg$$a\D9Ց|m1 4 c0e=|̝"<ՂND!: Q(i!䎵TG* tzh#,!&ySoB"Z$~|B$@tHtQ+h Obro(X\|B}Ul[t.=5JQq3+4E]Eh9XذgøIaf;)Lڪc5иn90nO#t1DqHqi8. )" )4A]!1a)$>0ޖ}2z꾺hIF/$ #HÃ]עZt]mѶwqmѵ.]i7w"}UkDG}Oאk R|܃ܴ c1eFVT-jT_uBˢL],G Qh1EqLb;=0 # ꩯ|yöI"JTM޽жQX%AbZ:}GXti IDAT>swEK mτy^O0a\tV9wp妸d煀h<GJ9UZ{s0a.*O..wC0~2Z Kv MX@V]1٭Rn[]18NN{7Wۮ BjQUDp^4e;`ƛϝO?fnT3"͛RTk ]-!w&n&ZL1 @ Lc MˊK_3aKn7%s<]SpACu^+%\|B{E#GJS "~d,@K "hTMFS$0 Xqymй]9XCڱG8!X5 S57\cc+T[gP+Mt(ỒН4-|h00;S$Vi+XMp- hƣ*@qsU^0qe "479|+Z\ZPtT|a1yLs~Pz<,@)\XGRo6UByRies}q~Cei] ]߭#Fp,7a\6@P17U@d}Wq}a0JjIRȏ)[u,J pI*s3G @Lzg c;P)z>SՁcx?Rԍq{UXuutm7Bۭcm¦ =9g^(*q5k79X0Q bc :Ƿۦa rT0]RPbwE1%L`)Mс#X8ҾY1 !c\$)vC'MWhQ@obӔEJHP!v0Sbޘ(49F_=_8W.ƶHLx"rHAА^Kv1ou}a;9X&'JLhbvK0ˡẺ`^Et_rbIG0n[yI?LJ:6*sm kյct]X1:vuEs[4K׸CrUo1}WoCA0Xq;oX RSUU~DWOȠkDK-:\\_kg>NNU^V _pf%&9t~?OZnU!̀VvٮR_.VEhU<`‹˓d3nJ H$hc \ #9 !pV18WB(ہv*+F3ms(`a\猣1v}xsfaXVEh ,A-??^9 h%< E@G(uVҨ(t[LE*;p:.TP#^^Cs]wCĶZfa ,0>0a+9J~jMpa0s.UkpjVݝs2-0vXq; lW'I8}J?mJ55hB^P +*(R\ݛJ\Mؖ?΂م];%0Xal 8HaJ FK*QDEpQvF$Cg9C%[CX{3Wo3`X,-,0sN+sKk_vE2t68JPk$:PSԙJyWJ̛ʹWbU(q1TrL Wyccpʼ3 c;0e{Հ_kKK  ])IXΪ cW$w0Hh p 1c!ș>VYLJsٱ7u[>[rODxCY2.UmUcN`< ! tc\:}jK0 ,ø>"zEL$ug,-e➸J5aF7;?;1'~mɵ9+H!Huʸj/:o}C?/zqKyU,DhƦBC —. CeMr&bnUC|$" "_߆XxW >U0GڵJM({?K.z Gs ] k`9XquAPL%*Mxhy/<=`0s&L?}4M/HLp󋠅[ %tlĕ2Ba<[V$$&W2ұO|KKvœp008`)R;*C'#x8|jpჀAcL);Fm^yWCrmT<1&wGP2s77Z4oݿ^\ 8칵aφ+e{IC\,ʝsNh  jna3i1?S8ݍ37AD|h1x]IJR::JW\xyq$hȡML"$U$R_ G!} Xfa^,ømv{уxyņĐ{- @ Ǡ&"j#fCښi䢿Gb,)2gN @ͯ"Ap(.9ٟga(Mi0],0^7ME%#% H}yMBwŒ/b+ NZ{+3Uv]>wϝʹ3,D-'.=gV U:W6`#7${S/k++`25ɝw:ɽb7 ("81V-Kn" ZX9{ΜB!%SA*2_Rz2= , \'_Idf%$ `".nyM\١.v8USBNr_⪯27SÌJdĪ;b5h-0vKr7 uЁ g_ܫ OBkm>(hHr>_21NJ!K82 U0 (Ґ 31fSP/-xCG?Sh/\'0ޤ2 wxsE^f. c0AD XiQfWeFLB|oD!2Z%!vP[! *B2B~I:ww|pGy8>D!; \ 異t&\:9g ڕ\K_Ub]Xf>ƞ,c;~碵̼wuNn][hb8*&=LZtFB+EΧ &~-Bvt c/bdW $a.& cfⓠ=c4JΟx =7bCqɯ fX(ҍxlhR5U뫺o`fer?TXϋtn>*Wf0:0ͽ=@&Sppc8|p #&CL@=zmJ;ZTvWD}][CEXx1Hu"e1ܲ9똃e{#ifyy7 klDABm+/CV"Iv}-V vmdI & 09I#D*D#GwƠ<.U2=%]5*Bđ4oU :!7N'+Kh4fǐ"tŊ sJ U4|X7 %*C}]%^F;\lAes c0e{ A'99Z9a+8FYFt%AXE/繊Euԡ?@NJVFĄsgD{)V"Z40vXq/]ӄ6AkD։Cd]NoكD  ,B2JJ]^Fxy40>SJm92됧}}% iV`aXZDZQlSN7V{2I8 a}9BePU{>U9I?qhvaa&nO|h)4 f fM3"ͩii  &fvcGCف1~ƊCR ||fR3 ,`"_x̌ exu9n}2@*7+ h^d! uUƮca\oc_;&J( G6w>˜]vy0mxJy$b"r&!ݧ5DUwhahِO9'#k5q*Y‘Wu ye ,e~ŵ*UBHK?'3j9}t-6|;aI3ko45]U6s+/ ":JTTjWQq)e+D܇XGɢ}{H9Xa0vp^6ѧ\ֳ;Qs q ߎVeI=8OGq43ʣ͒ڱRdq?/ ^, W" (.y[%a0vP*)A֎^/0.rL-v"+=\+q[*TESʮq;.aFʿ% Gjqym0aJJd5iHؾ>U%4a}ۺǕDQܩ B(ګ5E(s 8~g달un8]9DBn,~`A9|;;w}"t];FU%'bq_un}iѨa:& c*qZXP`_\)uo9YhR7kwrf[7eX ǕW/EgYryrqyOR5B ƽhBl*l}1 0vX| +wLTG%qU: AR*PBOI=oowJ'«YXJCQl4 }@Ŋm3ʥXV`u$ӳst:ɺ]Pl4hճa]L`sBMqI9XcdULy0*iz'};;Ǽ+*b2QGiMܤ0 QdTigtt~eO3os^8z|oa ,!:c] |2Thkj &b?M..q;λp"I{8?*!hPѳx NMM]*x|O(c>Yd1kH9t9G`DC_~ hr c0e;Ds*+$G>v"GL 6lVp0 7;+}/0!Bw}UsQ;riy^(MyVC淫3_pr dala($AT@I\ĕBPR K.GKSJga9?ꥋٽ*-\(YBL>)BLߖ]^RVΞGFuM4 "VEh ,Az_]\\x !{"Tjf4U:U`e(o%Qdw!Wx+ux FaBB *UETIS}qzY7ĨD&yʵMIi^|`" A!`ai_=kZ XBJclM)-ѭV<,l ,4]I 5|+ÂU}P+ d* &sV!&[|,%ngzJ,baz^lS@SYfO>Ta7 & c7ȉUSQ$q5\(<|ס|=P+%lGknX-n8p&LR`m*КJPWm"""!4w=l0vXHηJBj `z'ouic;s еK02kn&E֡z GQnz3) 48nk6=n\\{o,y.X5 c0e;BiYӂ:=6ZbΣ:tmwh]srP* 7=x~xtvvgܮr3> 􌾩 3r<$6tuh33s(J~V r c]al1} uD}EuM!FFסaN}|Dv?in7v }Z "8!uf(}H`ְ.3AKmzvucl2nƍ9X<ͣZh$* ?m"*ⱡMCs[cp<$VVξ Coonˎ72ێMY9}sX92d*.V'a\w"iנ)z=@5e9XQ  CvydbN. {8Uzt1V7pVΛ1+ O =N4GA476x BD`ps sssHc,ebDRhoa; ,)꾓HB+vW!IqD]IwIT闹KME%Y7Ȍ IDATR~ښz۷>é&Nόj%q9!1?7! /I[BBLh2xxvJh_^s ,5,Dh;^Rp],V]NՃ\1;4dvq%]8W>QnM80njq$yˍ^MbB# Oz,pL_\cFA݅E4 X:z 0j+aИ2wCO !| H[68 - R(.A ±j'!DVT7Yd9FSUQnN%o?H\sgD@L;r4GKksF0vX\XzWY<`qnr @-VM2o/Eêk*=}n ,G vfitA04GCL}RIݫ_lɹqϧ~iKec0vM;KOX~(mN uQ\:ybnV"K*KޤU{?]ࣸ {ڽ9Ƥ{uo_:_ʽ6iEa\2Fk8<A" 8FE4 " +"6$Z[AJ3GF8xvo.~WWDsPqIХɾvHk:'!og5\q L`aE^ЦY%M8KKm@+pp| =VenL>7G}t1 ] `wmJmӱ<ձ7.aL-,lBZ4 , 4=?dջuM&i.?;bM\ϣZ8\!SNl_zw' U{7!!"$ۿLX:0 X ,N,=cn"mE*:A]ڴ7QBAn_@:&b^`inxk߷a[`>.[KCAa4,UL`.1)DS%"r5 s˺3>zHIROYT m9 A"w_yn0ηj#_~4ey@Ю/huy7N02]dS_@p3x/][RD֤jZܥ V5'XԵ:0A3$G^:?y9 3h4f3nLfzb 5psݹ(xa0vYA2ŃbZh[8@ /PL`H N+ oc/|_̖͎?b;wY SIBP\^4)44\3FXgM2; sh\s`{1wB M ,øX~p$qq[E%h)۸РkL-;Gϕ.%J9A)![׶|n~ 7@x/fye7`ĽB"K/x<ih[s1#a~XY2e.a{]"L%רP_,B;0hRq؃FP-S,iNƨ!@|=}xe絗9Oпi4hE浍G=Gwc&3e.|al=`u8f9 j!0N>tNԽhnm/9@/ =#cVΜReC*Gs>&~}u/$`"`)tQ<=* ">g;UREhr2h9}oW0nTL`uȥ닏=PTUNi~VoĎak>g*`ࡼC(*>‘tbTH}Yl Bx_k>'O8PWsDh ʤCa{q\4 O1K7 ގ, ;@Ӑi$(<-W/|4a2ØPvk I(, GaԠ+/)(9胟s+}d"01\tZv"M-=eGqGw ,؃L 05kVp[߀``zBLׁhdQvt{ C-= [ YLG좸b_{eWU"ʣF\+Trt~NWb Ŝvƍ cҁMӔ\NUZiH%pX>[pr>?bxlH"F pS B  /~E ξ ١ +a4*/TX҉ 8<naܘ2=!Jke+ oTAA;3.ļq;T=ܪJ ! _,l"BO\@^h/.D0$^|7n ?.gr>K~B *\z$jqӧtxIu!R[ #]g( cnv4F~TW%g-@"Bg%z)ioU\Q5Z$uDU+SU|rP12=Bש4[-`^:} F#Bs !~1йh7>@,`CEiL]׽hX5m{dk`Ϊ !8 JC;9xusQY:zBA\,øF279O>|'犉83ж妢Mv8N-Dh4 4"ưq5OQIչYؐÍb 8]:FFqwlbO^0V!@BW=D:!۸Cu*9h1Ev x2BPޫаBl^O$<0VfX,@Sa{>6йy'Ǿ[nKUd-v`іHJE16?-;u%rPrޕ QpSwL!H^vƍ cch9,%ajCc4S.7i堺0XjoFhpkB+ AhT [e07`np S@L:}c/Η[5AA!QP|6$0<;P` ةrgN<@:I$ ! 0& M_~ catu48PB^FJ8FGRS,"| KpZB I[~96\xBT~>8n , ]Qpd5` [W%Pa [90;S Iŕgx*]XP@ׂ-muƛ XG6 yF0ѽ@;<(a"}cz}" 1`=xQh} $,2>!(||;"&UId17(1wƚ~Dv +0)WΕ?U N!ݙT̤?b0kR;s+98fpж|4s.a`9Xq-Xa!DuqMn2 9\Zs&.sރ$Ƥt݂~`$ai04gzMAԔt4XusLeWܣ? ,a{InZT!  S}urϭB̿jKUCJ9Zc1vvܢm[cq VEhׂ ,x"٥* Ӱ![$/ M`׃I% $w1=ff{g0dH"\xy,uBTFg5x" \?L-j_-ޔ>V2jr^XA|LBbQANIDǔީj(Fcm;xuԤ07 ,#"t["LD&|"c"|OTŠz3%RjfT<LL; sjćt*ocvRy%뉬k6'W.Wgg ,xCqG(B |ETێUdEjUZUAX'ܫ",Εc<΍Dj8!/7Oܒg~fY\C6g4 7+qyECɧBJJdw Zhfn]G׍uv=XIHiHvqx _|}eMaI]ۙ)|^:RJlTHb0Y  2o0xn åӧfbC@$ۊEZx9wTxa6܊U~ڪ~^c"?^(ʸYmC|u|A'L>O&5ıٿ Z?EG!Bulsba_wDUECH)&E׮RNt\ZsR zgpԋ)6q6 [M:uL]O a[x媈?!;[HR -VvVm7UZ_Gۮmv2x镧 x5L`ƛS(OJUvjU=z}C~dׁx+nc۞щlIQ97VPE$(u LUE9F^WT=HD9X!&i__\&{W^B_3!8S7}3amِDW7* u^UEU׍47ˏѶkW1_Ƹ]ø];ZWbUb09J$*: U%)æWt#7͆ţ3ckתXZЪ{J{:4 3^*I*m'OX`EwMDT +nO2!B$ڡJ=҇LV)JJGEEH@X*G Mr q{~>ϼ8O-0(,"X/#j;E֬:t?\ zL`‡f]"d.]' ѡj[h%AbGʢ*m@M 1G xJdU^E)0Fݫڵ"J%Sr0䝬΋A O* ϼ <b>V% Pu4wމ?EA p_eLV?/02 #s>+ ,R/ȏ١ar*333@2av_hWUowoORV(RUzXe}2=={8i`MGz!jw>PZNSOfW60{+EAA:࿹c3h!^o0 s Q&ɊyXѪN9 KF'3WJg'X>~ċҏ0,Cq@+SiKZO.^|4k S1)mh mx >21+u"kb ^ :s.CnRGHdCc6ŕW#,OTbaI/XW]&_3DX{ m= ]2sO-㥟^ƅ{]n~n 3h_ۖϽEE xTU)#jAC75U#BÌ3( Pmbr<^&+,+yW} ءm^^X u mC{3uV]ɳ5qw̽YlYi!L^EWWq AoY{˷W&Dg|ӯɋ3CQwYYa ,øxsh qX܏b~ۖ OhfNV ^"buRf Y;G@C*2dFGh&4he#\,@, jUDNHTr PWW%D{tKV!r\e ,øNxO?_ )E  W1qƻ/ѵŕK\.|!d%*Z\suDx䶷' (.h8AH"I{,U90aNh/08rMW}hV'34wH.' x*BuL`utLzKkjڙD"c8Q Ǽ~BEl&!wIaFaɻsw ǚg5L 3.;9:d$%q; /Tλb(ª0bYf0{u!WQZg)^Za".ļ+3 ª cyO V:(iE@1\?uNW@}{X&?ܜo~\Qdr݅Th R-?mD_}3Q-~\IrH׻5433D{_md.wf_\Uz9wT[$hh%,eOGn7` bmXkʼS9gYR 73of}?w)U~쭡ǘWP6O"JB ,B_0MRi,J#atamr}\ 3pV p^{<4O&qhO0K }bװx~O~_m{>;~]iSc[5 TsqئOfRUacDx4vM4 @4OD E >zmZv1ӈ?Ј4ԉN$4jV@[qI K^]*R ]F\#Ogމs]Ht켢LP$w. 5+ŧs)Z&PFoTJωrgP`rLꇿBtDZ-8WI0*kj TK?1`hZpkIJ7FB!%U1E`'}bYRȲՄR.Mnm[SYa"w$Tӌ敥2EȺ;!K/,NT*\i^4J~OC~Y_.&c8i%0,(ڷ};Q yނBٴ$j{T^@P Q.U F^E(9n(9!oE!}{f^WluWǯBݷ?s y_E!+D:/?=/T9´> 3a%4j:LW.6uPItYx.O "/X3B7"{(|vjF3dYdIvr I=w?84/ȁxc%[v:$^h]oB;"F/f۽J,PVGhrBEȱ@Rz@}v4o[hxB˿mǝ\*V-!.@[T٥Һ$4 v/"LYwyz8jJq$Vxcm:"KB)T`mN+ !GC1/g1l\H duxO#:8Y)jg `/V-mV&(_}Zgϥ1p=d:uW!]TϹx}$ &jN2T6pt9v`rĤߵA~Mg*޼ObdGkD>uB^2Ţ٧ ѥB۹JCY]lE9@.5J:wH[;m* ;P̕~ BJC9KVA>{F5! ye`#r/W.PJrYK%|.\1HG\V)xj筒ʯwݒdtk+l#[/l)P:u0*4h$]h Nabme4dGޘPpJ& *A~K$I f"F\z7{`=,Qnny[̋tA[I(! !GSx酟H!wuA*5httɹʃ"jUU@\&# H1P$M.]0D\@̗?92V@E6@}:z<J¢-V ?] Y (96Bn+4ߴP2ApC,7+,udz>?Y؍Y 5y%AѶu5H+xTч@E1O'^V$*:pwv^@rEg-м _0:c&\EHBWq=]R EC;"%kئyouym6߹}쵇 p͊fU.Z+ vGV@?VÌ H^";Wb:Z;[Lc `QB^zв%N;GI"d-+*(Tkݛ|3Am yt\,1уO3QG;3w;-(E:@u1+{V C[c b0j{Ig.9AQ=1CLeB ٴ,FDO pBd˗z6*fjbR d2I{t9iP`r.t/:{ ds T D ba$< DY8RQ|5GpYJ,=/ *- Idi6 0A9PB4WصK'XL `=#d`c>5IIR UKb90m7*s 87s xW m: :eTk{>fk"8[{ F+&quac5o[2.c!HbO[w@ ؖa14w0D Bw8 ""EȚYl-V4s q$3#vLo&ob+9`ؼ=&%d!k3Մ=œ[rᵆwɹZV{e,+FG hi.c:!|ִ\%wppjoM=[`R„4(Yyùl4L%5d 38SLj!i)J( hQ@ W"i^IRq־`)}Y "Bֈ^ཏMBT"ª<gIXrIOzWl ( AggƦ I);D']Hw|٤;fmͯ ?wkV8(Y3ۿa&Z 6Ќ}ߑe[B]j3ߏZB̗IQX<>ҚfH Źrnq [|z(ǐxoY@!Bn ,B֘gpK/4oړQVCgFG ɡ@B{M][>=${nIכW|itn6SJ4rb"Ňư'X[q.VD ţ)u_JCXd!BEϭ^ߡPK%d粶I,C[}!CrQFS͘8)8>or#Ѵ+W+#6Dah) ڸms~_WWvO5!'0 .%UYIybSK}۾4MQP'kBۚjFd,<m4<;['sZ{s~ǛA\AYQ=I##lwrM{(9 \iN-姲Bvfb]S G Μ|o~ۺE._in>USѼ^EVok2/W(`lcJٔ֔:6~ջ>BAEIcMkAW*#Ώ, 0eB-d|G\!0l7QUU6Ia[_P0S(b,m s"+?ʚFJX[J k{({݅Ea`Lc,-`=c,m.r'P`rHP^.Kz<&QYӤ\{bs랏ic2ÂT]1nFޮsk 䆪˅MX2Z(P* ۇevn ~cXŕlý`:!Ρ"䄱V+EE=BPmGB+9E] N>uo|,Ӕ mpy7[z{ @X@ز׌ llI|w$QĚc;!IkPֈ3`<FY&X0|`Ǖs! kTZ^t0 mE;⠉+oŕˀ7_ϣ%-[u^/~<($hvwA\5jڎeQW~3( G;"8DBN>Z!n F"1Y4=DKo|XuXTP[RY *ҾCݱ{ _n*<Dgc[. nhCwqU !! W?vۋXFS(F0ܮ! Q(Dv-}hR PR U uƵҶˇV #(%;X0XŬSb`\ *B<z9Ϋ5|]uYPEr.;\+#[#v;1mI,yX)&H"+} *&3XS,^ ,*Fc@Wf6- Xpy6Ţt ˘"LQC=_b9/X+~!b[ [JF=P@KTU(R6b0wGX!!'M0? xIRx10c~ LYEp|9@5Pԋ E!Qzim`{tDR -%V+=DrK( ι?UU!"2F07Mj 0N\U\,`E`ܨqQP(A>MnXW9)'I>9.<{PYx5+ SL-sKcB:0EIOlsTQ\)V 6]|V}R/@W|h8;@ #AīzF| ,UUmDT;~@H];AhywqAytS"YQ(m  !!' /B#t{X 9pŽ lh5GU GK$[oz#Ҕ|T>GC>ox'UlY+dY$kVs{xQ2YፁUH({翋'CH x}/>X@B縏b\Kwׯ$*/9S\|&TkoAH^ŗf><,RPpE^wbb3>8ܫQhyx;eCk7 ^Z@by.9dQ$N2X0{ x10^a@]zWby,:Yi_LM1$ |~<΃rfHKdY睃bŽc^Adyu0ZΕ58o`J4%21Hj_U!v?Bޑ^`r"iǕI3T;+A'w%]JRO /J>1woW` LQ» 9Xtf&~iŠ ="wz/0FBJ 9x!bsJ %Acཉ,V1ׅ}Qr "} t1" wpƬT{ bcP4BL7© ۵;I?&zaI4NޠYW3>XAXByqWz'I4Ar$/ ""1(Xn!h%'KS =H b&9X /;;zxse0w.vDs\]khjxuQd]TN:.ix 9wc. y ,rxv V(tCqTgU`-%]Q}%ж>/M_vw!P\Å 7cْ"}\{i[>[cATil%6q9C`P.t^L^ F"5X P#d|:[բ" ~={ٽjؗ[oKݬ;əPJ&wg Pg{zVQyM (pa<ǥ^ڊ/&%Cqo& B˫¨=j-q0G#c/ѷV!zqƑUSëg/t\o\LUA/izZ/~{;?Bj݀FGlTxm?H\h&͖ CSO4shV CW+us_u_PWsT^.=!d ,BNC kK"8mJv4??^$l9#v}K\~ayCPaUj稫jU#jTqf)FﹱB !&oc;eA$WX e:<RQ+sCSc !p X#y4M:=o@QMNKcHܽzH* PBX5jJHC ,BN \钋Qhy, ovOKV皷U>S bSĐ{jz;߽ϥ,tH\EܪRn竰ݾu4nWr 9JݹJP`rhOɫ"K+ 0tRl=JO4,[T.,@Rc҈{܅ * Ѫjݪ*z܅w-[˄ aV }Ue -+ )IA^ׇ1AD) Vx9kv \.t[ *pO=vOיVeu/XJViۋjJBkvkI`D1(Ν_j Q v\Ow=O}y`tjW9^s,ST< +.-!GM* 6 hE hgB+K%A(b$B{Zjf|FcwxSypO~3o!+\7:NZcN.!!"2٫0mwrX,sw܇w[R1sXV &>i5O* nlsBwִߵ{m<>{g꣪v0Zg;B։|suʃ!'餂sEoao jP-<>t~5F]+I Q\Ǿ|,^8 ^1kJ=(q7xqs8'`L?W>>sW'd9IAbݪ@QEohvϢ׳opNQ-sjq[[4v_S Sr2 },Q9DU0 @5H]㿤q{_.΅&:t6>y.j߄=p˯5 r k3\4s, ka3gg0EMG[p3WQ$)P#SspX`f_q^BE9"Ur7, ʲ^1ט8ǰ3 ,BȻbWaR?XJ-5!(? VטO9*/6fvRJoyCFpRWg5҄o|l#ڌig&8;fhʚ`Ǟzu_u܇r(P`BeUͷͭPZ,|F֋9C9T(!+e>1ei0'[[gpc>wGn%+ RSVP T5BLQZG(*ve(:sPʄABn8'Ʒ~rt*zX^O<})!FUyT{ #-B [IՇ$eD[梈9+@i܊;+ZMð~P9E ]:b;>.nׯ|}!H( lBٴΫGxjfh `!j!ཁB ¥+^ F!+YJaq!Yszţ/_9Jcu+Gko- !NJ1a uP`0l f*3&O{Bq9,bۆk{`hы+ ~ѕ2qsLj.΢Z8k-`g2ǥ{ٛw:&m(";/臐pT8MN٭U ~exrNFC*@Cr7%~{>!%g dݙW5~Bl ko oGu.AÄv,΍9laAS,6ztnqPx(jcP໏!ŇWqڷM]{2eBwy\ٙtq[={pugkS\ٙ8N9깆Xgw?(0 ,lmrZ-& kw zWj BCUP^pq%y' VGHiEN:;{s;319q?Nq䮂:!䄑@`PdwL/UImM'w^nϿ*~sݟ ^amIȐ;9eT㭫[>oă>yCYq2{G+!wB)"8[iQfArB}m @ٳع>CnbWߜa~[#~ˉ!@?Cb%!!TR$wkX?(;91՘Vw# G%n.Cc ,r'_gy@!u"r_0 C~ky,>16Mk=?s܇E0E/N*L']׳ 6Jz%`8|ZcW妨HHAw!Xap31x#( bf`[n9Z5q%B ,B}-,F%` jE&nl԰(!k !X,WC-cq"?( 3}lCL0U+nf)Ok ,B%+vo.{sUq>@>?ـ ^>6YW(!6I_( Eo݇ٴš NԵG( !!u[Ilen iRwU+X pX׷82IiS@h"d"SW;عf%7k0,Q[}lltZcWaoo3T-<B^Xiͫ"=0D]yLn.0{v! >XXr,`Qb8.1( 6>6$@wCNjrtP`B1[ao&-]`8* ԕ^nuՔɝBքnݸ61fQn9;saf:v'B5[[ll1BqTKô;!k!s 0gh\bc+'F(rtP`B {sܼ1[}01}B! ,B!CE!b(!BV !BȊ"BY1XB!+B!dP`B! ,B!CE!b(!BV !BȊ"BY1XB!+B!dP`B! ,B!CE!b(!BV !BȊ"BY1XB!+B!dP`B! ,B!CE!b(!BV !BȊ"BY1XB!+B!dP`B! ,B!CE!b(!BVE>zIENDB`v_sim-3.8.0/tests/exports/iso-3.5.png000066400000000000000000003141501370110300500173020ustar00rootroot00000000000000PNG  IHDRXXfsBIT|d IDATxy%U='2o-]ͦѠ<$ F/ ?fy6f0¯BP( ]C BP(mU( BU( BU( BU( BU( BU(\DjP( {HuP(<8|tn<xLՆLɸ#, •RVdq0?_1?Fޘ=өg0z&LUqP(.m WrsFS*'#sJ=Rt{i<5@ӄzP(<^` W dz)W) uTUBU;T9W!@x7}{÷E| ~SV҉Kۀoa:@3Y]kvEUQFs.eu36FSÖ( S3?,,fa0Kbnu=s5+MSu9U9s)PW Pw#`Q|55^϶*#U*ըrUADG~jP(< u=oXZC.u!daYp泟DWWzRZQTzCKvhQ**<D0ϖV|q^P(<PT!x9O]UY+"D$ǮBgf !׼dW]+HqQUBU)U7Xm Ӊҏگ" @k3ŭY"cf*"P(\)W,QQKDV\ƁnXXqL" No0j;g?E6#VE05@c:Ok i[rJ9yocFzf֧4czE//_/Ћ+Z.Kn("R= ?r( ]`:Bx?VY`yߤ%!ϋ_\QU5U8}&hR]htyk_>rǶ߿:o}f>sBjTp0yYIY4x;ꅅ 2 '=YKԵR~cCIim`z7{Xu*E*3E\<_jv\]T(<}#S"NT_ZF#ϡCǍ뮫8}t mmc~61~7+?pKN@b}?i{P] MBT*f:]EW[I"OcD1 ޿TG:Jl_zE/mI˅4`'Ae$ ~f"i'oVߠBm9= mxAtڰ0>L,,:_q\#V)1%3ABEQT%gY>wEuT@TdDQlk:7zwԧ 0zwrԘ'N^#+xz) X0$Debh8CK"mi4K !0]]exW'cBmm }.kjF%;7 kl{S~ /*L*fBUE\Ep \2{Ƴ6m+oK`%E\-%91͵3:F$!,KR1VX/H x@DU?ď]:@`yfiiңAȂ-um8ھqU(^}7/|OS~7O=0s~53M&9GQ" g. c/Bsm[4}@[:u5Xe_>3,;Db_P$#$3Q״5X!hwAFkp~YD@QbanWe\FI )3$X߉ak S)JQF)UTUl%*U)߼s?mh naSQlR:qնST7z{6V-rj7tYJ(U.R(Dq%AňAWex2x0׋vŮUzZ3t`U9E̫B`i'<t{ZYJ-rzq:Rk.H?gh+Q3=`ef5~ŽYjB{E]}#];*3 MK*j n_')%DFY^Dpx93B:3K&s{w-ֱ[uXi! 3ѫ,FITua->r;$(-,T|t^mLZ&F՟_~ {*vj/4TU^@N*Jd܅yP.iʦs* o!5| "8IN100UyzF UZ@LnE 2 `Ya<>x|fyqMam-JCp/+\TS{R$b+E5ͩ{j|t4IIn8C8}]%6]}s*ތU3VC2 5Yk[~jKԶ M8']82\ qO~p_'P ͑_?^Gnłu=ht8WSUsTMe Pxfqq;;rr2MۂV7؇/ m0# 0BUN)5No6x"cB3,^/tɋܺH-VKN_DWeA$:PO_EJE*lV7BޮzHVN 6͘9VWϲ$g>VUYhL`R)i&*SXϐmTI,N;:݆fUi}&SyelMk5. SmW#bI W]MR\LdBws50\`2>{7R(<=ἹGe $ada tF(IJTbLTaW8I2-Ҍu,5(q9ԧI_Dd`fZ'w~ܫ:am5Z/U(\mv}(.6 e:mUU(<ؕzmpC3h,Tk>z3d;:m \ 8Bj38m5yf! b]WXE@Ʋ|찆""iCҖmWz G+ =eOgU(̢. j/ U&3LҌB>d$*/<v{FPAWQls^DguBasBa%+CHI`):˅<% yV>qwAPN AKVFQu h ]j!Zj&pZW \ MzXX*"E` J6{l4:144E+ԐwH6(p!, )Ә։M{%я4c+ݐͫ';FՏWѝ jY]m8xxŊsgh .X۝X(.^˒yg9- `#GDv sB >Y.-M6 !:${a1y=mz&Xn9to0瑁/m'~!͂ s'2HGn+[Y_yqȱyc|SO#ϣ;{Px.S"XUS`MXe9}tVJJb(-^3J!;",aφ?FX;(Sl!rw /y\!'~^޾ݍw`ZVp5(POr;D`)!hOfQi% 0SEC@THJ*I߷/ +Rڢb!ӵqDD0QT,F˴fr \E,fk:'w%֌0L+'Ew{oW#N8v"ɕ2BNX>RU BwA8^.1p1e(0%) (f*;[K(uH"R:$f&ɹ7a |)&:k8Ǣ-ۉpx IEf'7i,?~>L_ 0^zgte8i ,O9v"x ݧBa`ys.h'8Bjx z2^. =TĘTf)2u )K=sv4jd sk/߆ Tb*40#Νx UrJ,OG0X1 $' F$ ͫ0?c - WENѭ]cE[G(U&Nu &گ"TThjGOT}ȢZ6k0l}߿jT/q i_Qs{o\4ϔnL|D ziKSUmV 0Pu +j3d z@JBkgp(%,00*ba Km9wDr*I\I7A*1ו,bJ6u3E/ΖÕm Kۆ (Vp()BaIwO0^z+;>;'b͕9b]Fh`r]fss3EASdq#ĨU]BEk1WEk҃hl۝\7i9*:W$I ?ӵ5aP90^mf-Ym6L{|-6 38|lszru_](*>Ad] m?7Fo: p+;}*Eg,}LBB;ha`W7dB01Ӻg* =}.|Ĺ^?ETDSXwG|";|38#^¡B}/#sX+֌Wg&"+[n{\:-uXեBa?I ]j}Fʲpn-g1W\kt7LW ;ԬI]N'$ѕi`Hcrb̵m2!` 6h6yiKղ(F<5vto~m|"8wKK ls;H-ؤP:!8Y]!I<Ey39}L;{f':,BaS*'bFRDl fwm/]LlEQ yvܺZWPHB˒J!,IvJ$Z@%E:[I >BB:lSV>p?f-/\D sJ F"bVΝRף~|6Ì酕6؍a/RMG׹Iٽåba}߅冃K#P(RV4CDF|n|`]Ʃ[qC#_uG1*;)m5E)72! $`9iRy|6䤺*ns4֡@\\ g?F<7V8u \cm`>fnf iӢgc/|Qiه$9f++S-8xhTVU(#}v0哏ujn"DHuM_PaxΏGn7e VʷuBBLb1r!Eq.]*| D(, ӀzxӟqlptO+K~_(8T3֋Nݦt#y)yV!z/ZWBdd z?yj= ǮY :ŦP*E?|QO<h+m`Q3?q7I=tѧ< a#=|$GN)Nu 9+W Tlb8*uQ9G)#ssc9s]!{&t.E U(#%EX(#"/.=:txY=f߿=>=,{9IsJDr#Bd /y4  ^k* ?^;E0 IDATS\ ҄:* ]|U3źUꪢrnv'mKh4ϫRi|Ҕr:qoñW5D5 :BNX>{}~xυgr kl?ƽNiCx_D=l'l66f-XWn|yf[z$E̮^9(:Q;e1WUUccU1*FQd\mpJ%}Zz%A}=*9>t=] <̩5@8T  "Dp.Fm6{ΝCT<8 0Zc/eqч7fa!&cT$UgJSEXne>Rj1-.P;EP0Gv,HRxux@ͨ2mh'@)Ehf& ߏbQ/M!"f1~ 9H^}wǷ8ǹ(};Z|XX_mݞP(\9E` W*݄M;ꑂLWV,B6rfC4KU,Eᶨ\9c9W%%HIjuP!jІ@JmQ< ӝ!-aJsqO(dԣup2,p*" }⍺* r7y!x9$wJCpOt{< D%"3|Y>EU޵ 75ݐzV]jUD]Sj>W* TC5.(N^AoCreKKjhQ!g?}aoX;V9vǯ[/ BOX>gpxOVHOTE> RT%>L)~:?ݽƲ$O2?HY9e_|CEo9scmG:RrQ\ (B618K0eL?5CDpA9(@XŚ(TzMFNIH^oFepD84wGQ(<(PCN~q:jjUa> [=*r3DU]ԶEn43t~F-:uE#hYL ݰ&+*Eq}Zpd.E}5oQ!Tf*MZ9i.IB_Y_oBQ {;E$vyKe/ ,.P/*zW\e4@i9,S|o@1NS?Rz0&IgL(INGׁ=ӃٚtVTY -U܇g(r{|T GiAԭR)\.F IfxAqQXY1:,3NOeAb|KU(twn R!wnLc s_ЉiM)XϓTO*8pxL卼˶>5i3yh:,`O6YNAuB˥9tM6&37olQD5r)ћKU,&DR5;h^*8Azz$j\7dz 'fBW3XYL3꿡7mqV&^( %EX(\!]jsto5NUjTt`%5Y4hXg%QW 7> S:={n&`~mYvt7O)ġ |"FǛ׉$>ŗSwME]E'v+Gt`]9*W:{3sĹ YfsH^\ӄZϼ/ _տ  I &S҇J{VptA䪓fu54t09A$5T{[@ *,TL Y,`v A(Qum@RͅH >G4ů!lC_T.& MC`9>LE1R:SjI1`n.F kf+E\,nWŹ_>s_~z,뤚ۥX[Sk,5 , zJP]ro !zťJ}bvaˠɰkER-QnEV;. d(l(g n^О#V-Zc80 i:`jo[^i#tTO\WσuG{8W4 Ov}]D* oK*}uJEgD?JPk*vHL q[zϒUH7XV-15XPz:bsNqDV[ ;xERl%>ifo*Qd&"k(bcOѬNL`^Zh,mҶ6W:ӂQU}^j'D\'uSwݱҥEd{},MI:/=]jkfrFAOgrqr<~MIX(5E` ;$ܬQ,IlN\9 @\P9B+^'/}֥'n4-a=֧ev-R/ (O` Ƣj,ȗekf!*rUl:+>BA]պ4n'ЊCMBk(4Y6ҫ$n+o#"Lk&BՆ #ea޿ A*v Uw7lPi!GͺqBP1B^+xIiqDwVbiP&EL0#`1S-ht.m8,:ߪNHEq:rzEVͮ'?|guUC/(FaS¡ꅖHյ0? p Fivs f+Uq3rU8~mI {IXŽnS9Eh)r֭K1oʈ%Leȹ8-vԠD"]7["Fj6hg[Xw5jU1>_ djjuTU4$uΑ@aF@|_QT~Q,.z": -U;]l>e9밎:BaO)P]0c(V zST\례ڒ҄N,V?T<@NQ3yʟ80ʜx"Tu"kFWmk x( 沮*tꬤmK}]f6:I*AXE< Rq8v,,ꗺ/-8*ǯ-uX^RVptWH ]4+_z8Y9ݧ] pXҬNTw0㻤=;c惿[cMf}0?^wt3EaS꾷˾զ뒞Wi HB6tbYuЪ^X--y CyF 3i~d\\en/O%`Ioé'W9~"KG9"ZBaw)P!Bl`SQq33KY!b5~KqmKF!67ցQ\ 4M\Db`:nW~Q+sȹT7kzϻ>.r*" a3ݻiFZ  `~F^fq|?$dbPUr}SI1Æ6 ]?6[?:ˡHzNrzA*R(HbG!>8x$b}t`|EB\ڶXC񳦁KYQ+|K~='^ra {HX7DV_F $Ap> Ebjj#ÉT@l4,mr'4vt /RPjW Lϟ*fSzphSQH)¡ޥ8yj }G#3gYnʘ͋5%g*V*iH_s( * ʓd|Z#78%\_Y} C>uX!ӆg:5̙)S&$?%XWkrm74rTU1E}0r%"}~㻿Ե+ =D 䥯}y澾k>|;5D+̰9(483|j ߔpB"aъ Gnu57<ՐO4˾[`%FT&:H63aJDe\XqOF{1̘kSf1GV/l./IbkN޷ [WWfFUP!b2Dbk@}ߣ{/4, ÑEA4S-HI)e~vB|N;ە DT\e5\u'6Q`E1 ޫM\w;=OST qi5C?bl4,U(Æ7K~GF=\N[9=>q3y ~ދgz -7qK_M+k?}A'>@+D8J M75zv"?kY(f)P!/}˸]ߟb*V@@GUO؈=xL_9LoZ`0[/m{ N88w{wd "l4M ֌hr؉cv#lڅƜ951km ,r{ݮĖƸ`e) ;a6Gd0[j0ƙV@ե3Q.h#EPY@,` } ! ,gP`JK߶<;w|%?p/BBa)P)]*p5Gqj#tN1#`RGbg%+FA 4iih?f4!p~:s< 5KGkG}ıtdn>܍i|rM8szՆ=G..zw/|/&uXݖe`,tW 6hiy!>5WfUieftVEh, UJf…ʁ#.r˾Ba#E` ;w@C1tʛ ̍UZHTq{h-ФIz :ŤdE ke1-NOf*)/iKBa)P  T0IS wl?Lڡ/b{44C 8 l=spmamRj27}؋χ-i}Px쑙mv$~Gx7μΣjQdcP#AdhҶYm,Mo95EK,h v?RiݾaH~j2UOS )jF픅‡H4u"48⪚sONнP5*vaj0ۢKuq$$фz>=WьQUф\oW!Y*ЏDuwY8PoMo ][Y]أأϤ spYQ j (rSrNX !P`nɩ,?=jOBu*q+Dni8UEk?2wX:2 SVpEHVY xRw^ցYWnHT4:$ 18R(ކn',AQDgO>`W?w~]FTKzOv^3hYϫ,{#"18L HOB+-aMK" su2ChUq&8U=\"_w]5, PV#9}JDhbQAS1 zRd&HSj9l:Emԑ1]ęh|h]Mah??|]ݴ?#ԵnwxdQL9ZgV>fQڨ0Q`m&zQX庈¬LwyW1X3m{@mRy>l6P(" w`|oz@YX_Zv-$!=} 89Tyd5`o99UHւ:5: "hYtoMw2Fd}gƣD(T]qʵNCEj``|Wbg_':(B}*0G9,0gA*h.$TH'<|]GX(E` ;`C*j䙄 >/~aTR1w6DRDl7F07!eD^JI4LF6Y밆_L}yT]_&2#L?0OGs)&ylzDѐj>:WRjjե~3Q&` Xf|I`EH^B1&YTiUcd TFQ}gW| 2E` ng] /-4 uw/= K-K7;=NZ>phq/B_S?G~?t|F>|QNRn{0IVsw _o䷼:zl+׃,,ۮ9ygjO>u=Qwd0OQhח/> E*jgW57]i=mq&x#q`MEMƺdW3{h۲Ls}νދ N1ZM$LQTJDtT ͪMjLlRLӡ"(7H D߽{Y?\k}6Eog܈7ͮKQlor]`鎫?-{o%^|w~^ wλ`xwm%cxb/]SpbqW_w| ;53;Ao_x_4>jWcw @p`sZ&M"r΁9݄CX\ز[~+ a_,Ddv&zl25*W1yI"V6&Ҋ8WD]!1[|'Rȯ0edUc=l鶻t8/J"iԻwbx.þ+by۰i4p%x•3v{;;n{qö9>"Shx_yEX~l4@$s.rs`"L uǬcs1 ЎFS'8~Pozk^ (`#H NdgZ 'Onu?t&Aeiwb[\MX {M8پv_\MRr$kZpO.M+텓F,3Mu^\}y6%_{amx•?[HW$`=fƵuww;'T Z(3xh*+a"LW?w;|$S]qXU>@C "C LgB 6}'YуEs3qm{Y)}R2!銈?eMǑʃweBX w[퐜@&W8-=dE_ux 8hQV;s 7-k_ HܻO.Hνp ]?,k@%hiId5;xv+LI S#wAIAGό;y;aM` *(0dt7z|F!=Db!Q0g*WC`۔ԑ^3` }+^8SOVTe!`Ǎ۝?kx~6 {_h߈yv^j~We]49٨LV"4D R!I+J'f]MMMoKKzZ&,ƒw{)((X *((qSiԯ @MFf,-*ŴvVҞϬm^^& Ts,9D<ҙoh\Ŋ:Zq&$+*\dۃ?{$SO)4M.vW/$OWl<DS4𑷿7m⫯^s~õO5I>xC8|v&.Gs1: /yk!5`B-{΅,.ueFCKJF 炂3D!X׽qcX`YSq}3q9BHᣱX! %>Ȗ(/1YFC}V4f~bxި{Zʄ;;1Ep> &,SYW"|i߫d7S]]5Ocŗ~_#O;wđ'p$~]ZB]Y,0M @f_9`^>4Z,7i炂32w@oI۔J <%Ջ!t囐UZӋF ?\,C"X"\h9XLw߅e& }ʞ!An5<8&3z _X O2^@N$Ts5 ;t*Y:0Cq;"qٺm'a۱u\Z{tߝ:z$ZHQC՟I0lj[bNCttD^޷)HЁy9ؾs 3ox#.$!ﺻ}v';p 1,Zf jfйA8dZDu[p>j#XI9XsV#dSo"rͳ^މc)Ag^6H6[Hz?@מ8PoSbExDsEz]o0N7~ +svp;vق= cz]]O6聓xcea`Ag,g@ F=*"Иjۦ{䰠`( qވ˯-,u+w+NPL<7PC:"=l]XS>V#Y? SDG#sjPu,Z P+[(2 ̬%ųʄ7Ҡ"P-,-d1f{+/Bai]6+Ŷ'N廏?UHVĕ/_OBDp]pߝ2λhžv`9Lo+WOR@ ġS8vh_?_\WcPU\Dk"Klz ^*((PVAYlt/N}l!*T `%]YY,2A jY{ys*IN w߹s\xnl1=n97pe;p" }Xĩc-^y 8(PcaAxԵ.((X *(8KHOE22aIPr] Ubq`HMNŪD?!`0p<X5;6hCA$4f/L܀)k ZsU~+Kh.#V%M!B`2Ŋ!9f瑭xۓ'6ͦ,"OUTgj| MS#2Guoa9,'8;uvlmSؼm {lOqEo;,mXf} /JAA~];_zV\׃6ΗɊ ;YsuX/qd!K.øVTM"Xǔ\`F S߇Q"Nh|L]c1cj=Z46/vE%t xp8kB}/-mP|W^W/BDi*(fxGϣ3~2(j@*'!4{> vեÒFq!MmNw.܊fsf,L4sKDpT KV y/ GF)-$$( YL8Lox؏l@"!VL D;]kuJ'jMt\|4=y"uI0I&eI ,PV !Hbkxbn o=J7c!v]{%n9rD!X@!XnN SM Z- 's33tsZ3c'$Z" uHTBiͬj̃;t sηAr:5ǜ=1 F6 @@EHYB0BzZPpS-EQq%c;kIP`E=hfDG0CH4LDۜ Hl(ٹ‹޾KTPB "7-kE9_;TUvr8xkR;5*((8;(VHR9Ԫ~yxGcIDq]_n±{dJ%K>IVg2c@!Qy~Z#+Ȗ""H4b %I${?u32)0CB$i ܛbf?%#Ʈ=8tpA LG1) M*Srbx DXPBolM:)FWzw{b67/;-KbUuK݄êTJDێS$V*<Qܙ/H%yp4A6#at~lFʄak- YJY;#IcAAYE!X#=Xܩ+;(yX˞[y'yg_ SR)Bב7/#Y@hwZUa\Jt唄UU"`CQ\OS>0t^ H=7Ӻ}okQ.V IDAT%dj^GGcA<ovm *Z#Y'P5Ќ`#(c0uM̈r5/mrM,({QJu#w4D⑔4Ra'@Mt)XUUDRrF 1OJJ$ Jd*xd^NVN(*z@".~_bF9NHN_$[֫D,lj4Ô{A:wYPPqaDT:4q,x335VdmIpGnL/~d&,aԙ? |W2Wqn;r9j S1UטrC+ M_.!¦M9dRz\tԩ(vj e8T$6>x^r)Pbnȿqq%Y!%R)*+W@`)UP Hi&t31!*` H*V&ژ܂Q 0%V"cT1M{Ux;ZFuTNTn=|AxXM0/ 7R%F؛?'B}( AR,؞E!%J!BԊAکdȪy==ӟ7Tx݉dX &PPpF( VA#ލk>*pW淽f =|VGvrԔ7vTXq3 Uz=ÞnTTl?`yNo @X\DXZJ&D#9ʖdrg=^uzydEg# f_g'~U pN ~GSPPQa|Ø"`黀'=4=H%(@  *W@=4T()!w w:f dʢ" נ0ҠRHH#PD;$GCDE7ERXi`fªc )lFRj;3(UF#h"hHn*#O}ך)bI)̪Uh؁l#g v:g\A3UzDL3Y~n';~>X&\\F *(xpG" a3DaDo.QCnm$tp+vdb}7\8߀uȔ*K>5r!d+ F5RswUFȓn3tв`lJ^)WUUcAu@@ DoXIc臓/g@E&ԳִٝcJg}($3rSw; s}],G)<#D%j&X7@ܡ7T"C,9uQ#?QIVjfu~ॸϷNTclc X=S|߻HGŌl`~0Oyi((83UPp7%d@oxzΒfk%">5J`ECG;2E)ˈ$E+vO燸vj.A: X2PA[ ECGmFcŨ9Ʀv]Q=|⣸Rat$a IPKBqcGI! U@sT9fl9uHg.kߗM"K1 fFͻWȆ`(,,%<҂x4.tA*WQu7@ڡ6@ddxT?@NWp+OGmQ0eʄTn'Gi9Z3s*,DDAdB mپ1A J-}sX:`{˝w^2ÔD6Kllk6BٚIgXCn+-bvڃȚKuVAFPVAbχ k3Έݖ)UUQ{n uHDHsƑT,#CX«>zŌ4M!US\UrhNbnW"XUT΄c7ve7-[O{oHgo$_"Y)Q݇ ]sw S6NzG:C2N0ie$|g^U`*B$뜥#sN;p6MC!XgexE*Y)` b&UN@k,JpAZbFBRf] wEĮH"HKddX'L70K3ȶc(@\xJ,'678;mWNDIH{pV Goñ-uy^yX)@[>Q%f.t5@m `UUc!Tlv]ŃUPUPpXe-щ)CQK7phYD]1@ { 8=BRMg//L^||N"K34λ8ًu.ճhC@vq۩XJHK.2bD+'RNVFzIv" * v9Ի7o@VF}"Cp"V*§pT+̴)X,CUauO *( vFC@PqFA#}?RsF-Drس^g\vC ^(2P' G3WU'\1(4'QaB6ZA:Q "-i І##[AlIc{*v;FBLx "ܱid喡*]3a˩8< N{6\0Sq[Y0V  SPH rUx":$LMa8CUOamµMss 8U 5n:k,S&kvA枱\\8&, P79:|fyM~iR#z\AL4"xTs >)fqE93+˓D0d*U)^`ߩS˷m$9X~VpyYc]*Y4#if&IfZ' BUPԫ4D?%,z !j Upk8WczjK_9轼W`f0L4d#YBxO8Wf1jt @˂6U6A*M)WL)yV>fAwV9Lja'WQm^k bG#լX&̶;oſ:9Wݣxҿc2Ǽ*sf6j~#zP z.(8 *((Ƿ; CTn* dJQ ;"é9%ZDW%EtU@8߷cIVKȉU`UYqLМr\A0?uNgO+Sˤbiq} !˽X98/#Qid1>w&#q@ܮU :>8s@ ]X *(c0F rŀ[ȂGDT1֍)oA_2+i"| >e#Zv=?{iCHӀ7ܿ];@ʳr~V 8Lכ Vfjġ7_9Aڏ1C;bfw^~K8y̱`商s7cm`19gB  ҄:NT>.-<̧DLIL#.f-W.M{uSUaKy[S[?*A;jfК ?$*jT0p6x5^3Yۙ%<<h}J*V"!\EbNݰm" |ecFӶVPPubG>ˇ\EC4DBFdyؼH2 b+/Mq^#^f vSオ6zUUmbBVݳ{_ \{ymh: %=3{Kc^Zo_ױr=\dŘHR07gKRɐH\k~_Ҩ$"%Ϻ8 2 ?j .fȱcڏ.d 6B M 'U9 s@]UKKOwDċ&tct,'b_sITx,D7meɾhڞ]G!m{BɈV|My[,GXFȈR2maab.<1B 0M K_ۺJA7x 67;1"K$J9a ! |"]UUylmu+i0=lLO/3 S~ۗuףVӔhHh\]?>5Psk?eeuU= 7u33- Ѵo8{OY'y  c"TI,l8i͛=6o8mm933ɚЛj]w Z}b3Gq h_KheayIJKzgd :yDg^ӟCFsOl=eZ>{;SGK>+-;\Dj[%*~jqŃUPp(`x[hBIpr/'UDpys9'@g ;Gp(7ũCD:vV.a>ddjIGrʊJ&q5}5ʚ+XY9j,{lUoD~_}5^1[-!G]+p֎d1**/(xP+(X#rV2bL-BhѶmvYp6`%VMK$TY-UH C€DM5={b$EN%a ^1bJcVu!;0;8vY)s%S7|˳w΁i9 $+;`~0V$YKܫ\"MW 4|9yކ/#.n\R!〈_\O|A#UP 񖷧W]<+ɔsn4-o XZ"Fш བжMx/\d!sǶܸsEI;)PnA\ _I (o! [C"᝶)6>rmGnuNIp'>7g"\F۶ĪƢ9#ً.7x 5O`9 *(X˃k%T̓J\5`vFdEu4>)$Ks#WKOYR_$Saa5J־=-[f-!JxA@w꽅u;$nAi -9Έ}DzxP+廚Km_/<#P<|M/F~+U˫e@A#{7B` /{i49 *(X w} \d}5irWUUD! fU$,W4[)vgrJ(f'"hGke 1N1*ܐm{8E6IitӚ|moU?@e;?qP:We^e{,*Vpxl2R*F؞f"PT=T5/F}3 XۿWL%?WAw2 *(X Y9l8ܭ[x*r `,Fl`cʂu ^- 9b0Fdyy<0`Ccfa:^e& ]eAKjVTJ 3Bҽ6YJFHo!D%Hʅw98b  |5YZ ;ʼnI˄,zoxofwG]$@LpFiL."B)JVAYE!Xk*)b)iaRrE6'neJ@] + @Z`IR NޫĪdankC%D AD`At ٷd+o k$؆zj:[zpf?boȄp `03!^/~ M9{-oB7ŃUPpPzx VS7x?Jm3a&|dж,-5i4MBa X`n, 3ÉQb8a{"2)ueBR`&P # 2_URX@,,ZвᱭC^TМ:73jJ y#׿XwK+[i!3@Q ր~v ӸԩSJ+W>ߋXzmU,5})uT9LV{H))ε^U8S\εTma@d|('{?/g~AM.kCYiTS}_k4 B $120flE(((FQ ViWX_S1k\7[`UT4* !)LA 3j@j jFF1Bj,c=o-Q"`~!S|`QuEj  !u#F|kQOMu$? 1b1=xD%A F:O^I=; {l5l{0勠&x*(0UP Ԕ.ICXz+]6^Kh%4"}4jU!>18QYb1+ԩXqBGf1uX*g XMm1)! 1^%Ǯf(df^yP.떫Y1$G&L(((XUP&,j8WEլN5&9 ?UrF<_zr |K)}t`зVc! %Mn52Oޟq^OJ] MRP1A2 lc05H’OQc0.{S *(X at F7cUdz:3;;q9f\0I2?!K;" c*f'ۻNBU3Zbm Y@ra؁'L A F@-XY\D5=}ϒlşh̍vܰdaAD SCH,LAB:[ֈU+?>/ȏెR",(Xqz; !xxfϛ2R_$heYD.`53`g,$c|X9-8XwP2M%BI#^t6`Q ?)v&Ӯy׮^\pi)GrD۩T˅$t(((XUPVP )ʅ:PbρD[mo::+ pΧh( h"(q:3.5; &Fł HU1++dtGDsb[%U $W/&At?dPi;` @. f@˄D) #Y.3i;n3ӏ ӹTC)W&?Y} ާ>vc,ftt޶rՃ,b&Gi,т`xo ]PNUPFͯ;퐰V%j؀>VRqS\$h7Y+`$QI2y4U]iJ|fbL& [DdLy 3^z0"J0o'{yV%buU145blA]w$)'TydH,QOޯ!t]ǩ'f6ODA%`x͛_1F2hbWXE4BJdv hf>-KK'x O'#)A] @ydSd4[0~l6aW31^13\JCEuv`$T /D{S:4D@ B[JVy*ZrH@Bƻz@3?8 aZq"TFz AIV$Z=T穠сB "yاUWN^^ XX$!iBdED}C\H !EFu:47x2r5T'Ď#Tl6lڤ䍹#X%帧.*Vw& *(xxk^A{S;iw|~3zVv^봿-y:ò`~ kr\ (A4HR~Yu1'Тm5>S,X0 ֒$R,IB&FtCg->Fq㟎OIUǹa}RHG\6"i9]6oV2--H,OUB "wyR +|KKMNrdH]}إ17@b?ܜ*RT 68 5Q>*VdKEhɎ9c}""5ɷڏQo|+ʝ"'S?Y$z`L@W< /KKOOP/wU2ߡ(1v__vZ fXuu0Y"V,Jl0zp?+pq`vȘ(Ϊ"d2"4 OoV"Hu.-a*A+*}ߴo|+Fc+3O0X1b{c$[{i!bjSoK_@}~k Uhʷqqx)Uaݹ0Rb#G28W42h9M((X`lڃB58Uw_H^X$L ^)$ 9X+xdeg {:$`khv4㻮Ik jR. $y.zҝңOhH:u|5C)ſsotGMfYўՑ@\HX%%bi#GjP׆DLHr%` *(B ΀q_=)mƄD0s5 Өbw0 ^ Ǡx` 8DbxĠbibV͓"#$a>wmnyM:Lߝyrl#X;)Y, N,O+,@1T2* VbDE4Ѱ8!|h3wooPq$T\Z'8 A,zL(".=ʄ)SZSǣGk xܩWi}2qa؟ꉓ‚:UPp uݟ@ƑQZŎA*&4z AExC d:@5ZClRGsBנ.ɟ9M7a6/t"/);o VMu'-*s<"}b%]w__f^Dn4`{<|ڝS*)XA k]|AC`lBLRU[Y%1! *jE2qG6ĀQš QD2H=bRvm[@$/^z&vY?/^㡻,ŁM%QϧkSOo 8bGa|`ofW5X[7⤮3 nc0<|q.t.t.,c|ٰ~x+ࡃR",(xkkEm~&Ćb2z\OcxLޒyݦc|XPj4\U1?p< Op}Q }m=Q 1 ]XCe J ņmM;xh.O)efȍ/l54MMLo3iz]O>_PPAQ qh¿iدPƠb< yp5kͷ'=9ǙP"4s\ aSUJk"$`|G  @icTWSd෾*c{UF[mU񞘛ߒ5j*lWjǪR,R:gYn) shQVmg2 qA` 89 U\o({NK_zғz ,|TjAEєmpw#}0=%YWcG{kP}!q{oۜ.2W31&|%*!,pli|Xp.&m^Vc1zg,ܺ{i cGʕdNQ{$TpΕ5}bEh%$VT t IDATh%:!N"zD++UA(ː$Cj&8=[B ht#N>fF@%Es$>tY_YMwD/^gW G:(I(PWqFPI#18dI mc&pװթ6*WCXRb=H{B,chv\90& `?&lѸ],**g2rO-w$yYBS*^!p XB JWS7T&WFMq i)NJfcw~;v39/pi%N`3a* 4 !=D M3ڹʺR4x%ٚfD!XQK$+蓬~PgUcG(+t &9>#g&j'Ay(cI5G^Fh9SFjSEaH ZHKr91 , ,Tư^ OJH0uZƽX{ˤSW7eW'WTV֒w$G'}ntUPbΰBEl9+(Z;w_JS@E ܞ߿ἵa6$ ĥ LiMd߁J=ꕈp\sgKH`usFXU.$y4l~*6}5+'V0ayr{ U%Za4N/5wM{4SjB#n U"b@)8,VoICrΖ`Uxx2i шw]=?r, xԬ,|l+穓,Źp!%X>=WXȕ1~y_,(y QPE!X[XLkhLW U$Z-Wz?(.khcVoOsK:K]Ǘ3 2TGZ_AfM]Bv2^eaU1gmK*c82PU1aO~{}L ybo?kwp-Zմ+E/D:<=z?l (%‚fUfn[SyxKȩ_nCpE݋H1'!Tᾗ<`nvtD#1xExR >'#Tֲ{V;vicDKFkv8tGՖև%α0옛#ʥ;vBx+{wg|kBH7ʓLOofhRh2'BE-_S8^A `l1{ma99$+!Nx^s-(Z$^;N_/bMHwԪʀ58K4F 4B #x :2jUI pAxp;?h۶&?NZk0a]VWo+?/}S2S>+_o_z )(xA^NiAA:x/୯{3C[/u\ ԕ4q~=w͆S'R^Ks> 5/㴞?|ƹ̌:=Mٞ_Yan;-{jӰ4,oDc{B"[Ϲb Z+#9ʘǠZz⦆×!:|C$};82\7 l`u1|P?} ՔoN8j^gnXwAE*(b$+@L%:JJgK=0(EYf(~i?//~ł+ѯd *`sɮ{T[UiV"Ck12?2`-m0@! 윟gh-G&843Vpa!r8ZM $r%[pmi2gAAZUPpLFCzՔZSD+}EҲڡgwXԾ`"+:; qUhqQID,E 4?( Rw00?pt0`%~^UUepVqx-qaTaSwmJGk}//DM}昊ki}z r47Ge-=ʾQ6^PP(ଁR_n; .K|# DlK߽nx,lkEy ZXHˆ:T;_Gz~;Zo5ǝ!U ",SE!X[mUߑKΆ 'B=arooZRh[<8U"tjMg!:KmI |2MH|3(((8KPVAYD 3耠bM*Vp!! [2ӥA%Vʩ69Y.̷ɟz={^k{Yg/ *("r*~3S&t&21CrYw%Vʅw*ޯonKjU^e1K'Úz||T>?K%MNp*E!XgUAQϝ@{YF\$w3#(4 hoȯ3os[+X u܈c VDNl *(8 οi!äδC}Nz (f)3iS"Vh&{OIzUXMO}.,p5zUPpv-dZ*r~[~NcM{pBD0t1 k782a*&*rRVq2q*'ڤkvSmS: 67)((8H>N)h_,{% *(B$+ /N䪿 %^+n{2Hf´gci؊u"^k=sZ_AŃUP(`0`Um^j4ZߤxYރ _u>` `E%|K~4YFDxӯ꽽$k=bU Z33`6Z=ۿ*櫊 ,Uኼs` ܊z5"c,nP¸Y[B)  /qWfHb\Lñࡍh.}w>7`f_؜T"4bDCe-K/Dk>{Wr 6`\o1-2nc8XF3 xTs;!x3߀Csg~#N@WQ|*!! * @i->J[C7֟G8sS5-΀epT%+b^MqU0/=~}Ig6]|Cl\Ppӈ|@ Tv#T[qx[HXkSaMx4F| |t+1NDpu}/v+I=7^G^+ygnAC8~=D^NV`MaObD+SVWC{kq.`0h k @4E2P" k*Xg.y> m*tzՎ 쵽x#_u$+@^3x79c$"4$sK,m@ԦHҺEP||ҫ̵$+DG@Ww?y=ϾM ;Y{K?cx 6`l>2-abLvJ#DSYO]ޕ$[)C1_tf?M-{Gl1`ȗHZ7%XX~8]z|S츔Ȇ4G!-U\L},"WIu't>wϸV!Kyi"gk}'AAAɣM>yHdj*JD+lJX6 7[T X;q$Mr I J{v|12ݱy'HPn0_%߭X7'L^wۧO7+X떾zYHn؟jt_ͨ|=O(qp8u>XM&=%CT~bИ4L<oP9!DkG,y%>O4QRe ]vWZK68f̣x_:O+å`3K=c#M*qLg={nloX`PPPe>ϳ>ѽP+w+Ɔmd)U=>*cUq==_UUVgԫ#x/1! e ZH]rwh,‚A)>UOڊU?[%.=$ PU`mxL*4NN}}ȧW -_#? څGk_wb?jDE;Hʷ[o‚ٱCX\F0?`4A Di?_Nـu˗ҒiWQKɈcT4 9?+*[*#.KO|{41B##{%qP~|AS;j˄Zj=ޟ0Zʁ"T6<LEe,k.RaPbp0Q|'`l\sXsNre!ןоykqaԃXA+ ;TF8z| Z=^ii((\UPJ!(*9:}zJ6lY X*-jK97IJٗPYE쩉)Πr+c0cZ|?u:fOVSϼ?Z4?տvsܿ;\/#'r$Txz $k$V>}וT;pbɔh:xBPTp 4n׺HdӡHi@=E?g.¼'~?\?tIX "A-4-cTV !mN&x1S~ϧPL'< `s4 od4 khǑ#55L&,uEqΑg'jq1@=i(@P͈T|+q}KQt$[]VL wM665;<(iCxW c͜ I1Xs%g Qe"ؘeLh/`%t.vAs-.*( $1tw`bOU[*tA;7ArX9Wp`z!8_ᝡquTD+x9^+]>xߕ! 6Uw, 0n4R@j^lj2 <ՄƂӏe 6nsjgn ADU]s5pȄ&8Psj ˑ#5Ix\S5ȷDv(w 'u5}%+wlk{UWuJλJλ><{Lė},|y;=Nn|Zt/)TB:aӸW*#xZK1_Ld$xl ༪b@q1j%` baIq/(<d/hssAqb@,F8g1b ۸ ,;*xYΆ415Nq|45*|#]u]+v'_`5e7&+盳nR%&b31U^W:V",5 v'`>etdrok\.d5S'AOjɸa2L&u\q^}ب[nZzrox~](n DJNE$eiʗۑ:HGr{v4o5esIvJ֧G\"864lM]2Koq/VbEu P;ohU.8;O/bӐ8' ωT[ +)WI$W0~լiT z.(<UPp8 hFv=>]\}]5MSS&u( I [uS:ۅH`@嘦*bx5pMA@+NC\L5|};Y]Y]}˓?-|wq&o #YԾ%A !kQ{.GX<)X>I2T aֶ3M$W&RIP1e%=FZAAiG!X'%ScZujUk&8?Ix, qnBmD&u`97g_s sǸu<}Хss,JUΨOvǖ(p#тzuzueTg֕OCxS<>WQԬV2a^-:U adun.xӾIl{Sq~+< ÚmT !ˤu# 1*YIn%" Ul>`膰:e6bh NZB94PU!Xi1cIƄa)^ F\Ǝ4Eo_Ԩ07^]a07'UU~Ğ6߿Q.TjH.>\q9P)v'g-.|Qɨ5><}I"T@@TWW#9Ի3_/L.[~,rM7sb>tjWw~¶7?eH!\L7n5#obba{O%g<1T^ VAAD&И3+,?ҁkeK:V"+>t`R[E{Anґn"LdD(hT 붫E[h|׷uŚ dhUvj4~>@/J ]fEpQj0Gx1 ݠR",(,VAI"NAG&_V[5ɧ&}VM|=~.l3Wq<`x fcϭ%Z2.vLq7/.x.ar>P]O/,:3TOLQ>w`X8Z._K DJNwrc'!lT8Hw %i@uH)]b{^俊 N? *(8:Ҷð3{7q`ZrUwnscfBSi1uJݬ{tV^}`=cpI10_90g^\FG c4EN==uO<_\ (h|Z<{DebI65hRBeB|7TdJ|]ppwxOKLCA(XFGFL?c^ ϠM0[WGSUhGG:up:o# ͣ ֘W5~&[WV[5%ذAk5&, zoLU0Я z΃E1Q)a^5XM&h}'/zıP}D /?az_pHbEEҋ@6@e7*_S:( VA_xq4uW:kavCKVRdho:mSOux|ݑ 2&\_!k6S95\10 f%uDLPRb`gO!b#B_$*0R(> 't/He*}}O+&rdq-.q=t ^mPiadUbb6s7Fyl `^e"vMI=_f5{>qRPˌGXfg$R QK;v?Fx9}PUݜxdy@M4'WOp7&c"W 3JyzH 83xߖ$[{oI$#^mYۙY!uf9ݞ*Z2V:C<$_[, >Xacz+((8iUPpx+^~{$NP*5c'4jWuuʤ^WLqSAr'cfw,ubبt]iXSvvMo&zB b b lf0h w U%K)äX13&+RCܵ|Nѱ:t(G%Xw[CaK s|pJPPPСx 6/|K[&k%Hx>E] *Z`LQ?5<m0i0beWWQ<^ZE:aqTzAUJ0ٹXh ;82p;V3f'ZZSWi쒊5zV:"Eڛ." rV2nD'*,7Nɐ2?pB}նm"ѧʁXlCjL{*5OF T <{y\|rs91殾4^lAE*($$%X$4 r¤^a2YWXY9k+ӥʩErQ XcU YV kP^a88w`AU1̢~h.\\a²kna{߂R|+d3ՠStwk@}OuvUmgL[k7 GreRc&*S փ[y,07p`kFX[1Z`pssx*M *(D$OV6͊->QU\(fB]Kˎ:+WLzK9;r52h8`xQ$V2#_Mm0[gu1'5b՚g6$b@ra Yků*G4#_I*њa%,=bHLfnLT(9?k 0q==Gc6@5)5bL1]TÚ!F* ߷1%*[9ٶY﹧ l(%‚M _mɅr4 Iq#b\,{ …(K;'m J %@kPo!C©X6~cq8kxҨ\Po-b%Bhh1ؖj:{)K12o#4[0`$Š/תs7K^ǃaAO Gb* G$FŶ F,V]s"5Ze0PjDU>cZgmX? PU _gAC`_ |YDOf^bpu4eeİ'_]SSrҠ`Ʒ%B-Xҥb,^'WQװ80v>kUp4^HjCO&ʔN+Q4HD䖕RaPiUn.Ynw4"rP'(p@x"cы\&LzjU;U0bwGRahrܑhx_N$nBfA7FTyԓ؆W0Ye<*h@*'UyE浗β[#{M *(8 hå\oP'̫@U*TZc`N)1kV:CRGKc`gbix5BVcl G=o;g{/{psSc#jՖre2^)3+>j˴s%B=fDJKѣ|w4 htH>k [a{V++ۨ0kvj ^8R^/ч6>ǹ58#{`ˮ<[;{=` F$8JDɑJ)㨤ĤT\UQUʮT~8?$%Jl$%a[I$@LF 17s^{ssϰϹ>o\|QQWQYl IDAT$,Ux1Jt+ǡA)u!B`pdR?eN·H`n`{j{yu^+mD4'$ϕ-z1VOf|r}XNh$G:FȄ6ߖ{[:)+YxD1yzhܠeaA.÷"`|i1ԡ#:E E"O7LZJKuR ل&^UcP9 K ?[`Ee8WUj~m;C!k|_]WVA`i0ě0Tr(͖Yt"걛g]%WݲjgLz )[uƙ/ }Q=qĶDRï?|BUҴru~DϠ0A~N>|e_Pp]FWEH+V}*&˗z Q"TdYq0Db?*4T1aXI<ñ0jTfK!^OO;o$'r{a||u'67ǎ{CbKK|>kg}bZBwN6u@(O&udʧt0ʑv tt$#U@,3`D9!V10ss‚*DUB `6Ҡ=Ww\*+UqRt2U,:I+ ٘lDCWi`Jˮ*YgPFmma_Ĩ𺧟B7| ~; 0ݍHٵڴ@ছ*gM)tfMOYCܗrDHw[Sc }n="BeDвk~\%0U\?YUZ?x,- 25 ZX@=\WPp]D۴S~瞉ʄ fa[rhP@"N")TٞңvxjIVF UpB9,a'Q1cO_j UoHמ~xC,ha!]) S)0ܖzMɾfrvjӹ}/O?hlDJD]tVjvU"YD2i57?ӭb`!<,hV*dU!0O,ÂsXt#Bz􇶝P$YC,}~76:~ 39A/7@#GJ6w.a+vN /[[8Z؞yMIzg|t =<#ISci_S(VV !`4XZ X\ XZXZX^F\d-.JYFu((QVAb;h4)3p+,?k/5g̼WV"m "6lf֪mg*U,#\"oEJhigyD9?OnVI`%25{iBXXJB`DczEUPۈ䂺8#:>,P$S.#%;+_HɖyIA3kW"T\@+YI0TKןKsSz%CB1ۆ#a0nǒ4\)9}54Yxh됬3ӥbjfD~<,DTv}WK3.m[m2aR2նx/&\Śo`>C i`F`aPX-H?ޜ~e+@`![x?|=*B]k:TJar_Jݲ`4,'U (9r˭A ^y q^p:,`:;Od ɼX8^:Υc^ yG# {F4J1{FX-4i*QF nY"5SgJ6GQ9%'DK2'%Y͟ :rXC3F$ oCH$'/aA#Qu -G]f0FQ2s/#2*g4@f?&DdA9 \ʌ>~w֙ṢXXf K!ԙj¹Jbʖɤř3Tm[wHVN( VA *(}a3ԫTbJäp:#ҟ28;/71zaUXKa-ptQ9BIbUquIJ[`xG1!W2J(QC;Az̢2_齲=iƗ6̱tLvvQMvc ?tlG@$WGo^7?E=U*sիD&BU1J Zd&HȂ`"AvҤSm7B(*WBd:rAH_iy*1|.‘/MUil;4q5P9Yٍu4ހr)+dYQ6Jz)+xr5dWtY=$BBWJ8td~X(elL@C*x8';^w{&@yͷN+=Zzd"⤂7@R2pi@Njh r !A' iaLD(UUln:<)d0+ !)XbFC!X{H #V~A/֝AEg#XbBB՗t@`>SQ*<k08? J*UŊHOuT/03:Wޓ^Pd b當ɪ`ܷ$c‹ąʃ@,J9} &\5$*W:S$X\P`AQf6aW3:NmowV9rS\}e+$Zյ#)#"v.>/ 9dt+XAg?Lv4 }n+@:Ȯr|^bj+YIV|i &Q&ۓ4^y߂yוߔ(UPGxfUR2ToLqZ*&3!(#g<\V&r7]U[h$ *%z Q:(=r$զ/С-RSW`C| ^]J? ̏- WV/]Rnt9$Bnv✃N *{/ QsId;QPZEQ 0M^c+S O2UYi7\"L Z24U-TuS1 oֿi[|l~N7ϖlFcsuffۊJ)BD1jT9ON-"\0TQ5С˾w>cTLSɎJVNv\F^m-(QD?c@Znlq y)8f?425lkȿ8|/]gk,tx+y w/`**tA9ɵb#*yHX~h;A:aAp`T0uU3WO}7?~Kwc {5[J :怪ΫsKom%vA`8z&uߤYJVx"PκŒ~;i'XUotWfuf!2кG+Yvʁ]09I #+wI1d`\Usc17[W7/{")U@53*XU,S4[؞֭((xM(X{soDzf%<=Fuh 8j뿊+`Vx$c %,B!WN;UTEˆcLբK.hvnv;`g{ܑo1\YQ?x֖\\Md3g^ꡬ4̚Ub TQUB}`%IKo{򮹠:A!X{>~vTgƚAQ mXw\]tv1ha_ZȐ]_ҵsF@ (J/8̫QG׎/h^ ԞT%su,523T ' *(K#N*h: x~0;h% 1Aϟa5  ?ʘ=hX@< :]gFrޛw:*AʓvߖΝ/9 } 1z W(WaxKę&6|?w<۫[G/pᾄh}^M+X`Epԫ BdJoEAk`!νMX_d*HIj}MiJUy96>ִQexι̳;6 ¬ 3O2GS@HVTǀ#3% j#;PHl]f2H߽f`8Ơc0G*WFj*Ws] i$?;ybAJ+I0Yh|1b%BBhqJ{AA!X{soK~2hzJV(1&߁ϑ`lC؄廧CEsl=MWg&ځdi,\U[s:PXQ*Lt ז~"*7 A*T41\-poa{}ޝpA&Vf8ϾGxc 񋃋VXTEUQ_T;s8 &uRp xyF>#@'qi4;9d)s`1^[oG?xYwf3t_w?KYQ͒Kk#Auـa&2*:AAUPpp7 sb7!#RYMieg<Ԫ2! =wۅg@%2TZ"tZҁ"Xb"},yШ'4]_MNp7Ֆ_}>ɽG`IJV>ddSլpp sb4_U扒 #z{9"7?w]_BZͳBn뫼o4ob{{ k8}c((QVAUĹ{ވso#ZSvr$[$ak[: o.z\D9v<\&#"U.#V(&0206d jC@ Sgfl3ӧ/nn^ySQvǍAZ{ARV9,]fx/Er\ecc0.NNNUUoeJB#Q[%\5&&ML&ޖe}o^DZA B νMQpA3Qo|e%U87DGo)%PHr<'*pF Wa$Yh1eR6{"}{M>DxJ54wy2!(N:+\Eش{}Jx)X9Q*P;\2ൿ.B&H}"Wk8{yد[Ppx i?矕jd[%H;09t&K{'.DU"0wBn,%'@p#`0ôGx GV=Y'9[%}WfՇEJߋofE^,l r,JNԭ-x?dVUAPkj]QTe2H(ƇN25_83@H r:/|"1BVd1u?GcmPI͆*>i`8q2\k<X+QBeKbT3n}0>[ 0,H~ ֈsΌ!`G M-?2CFoDTU~UPp{j$$ˑ%ʯN_J$ P/xMdqbdRXg.i'煩1ݮ?WYYOv2_J)`\ RB!]ss〹9Yc/)'@(*P[+ٺK z?*_hٔX, >^+^yo{_o$;ɖ߽&W WPPPVA5oTVi+JN0QyhJWf9$+!e_1*bs&0ʡ`8̸ƬA,{0WB( 8S\11Dc,,p DZw]O5R?י ގ BM`,fmL4&>~!RǿO{{-Rd]UAe9OlV z4K c/Iblc%ZFKE[8%l۞-/ÁPo M+8>d *TPEB@ (`~^T2ܴMB4q9gjؚupbIUɦp+AKh5L.V.$?, Ã߽{\PPpq(&2.*W)>{ϑ5d/bȷp&#cԋM FMxQ1x1ѣ80׺ IDATF)reG_xWV<ũ5;IAf\')"-9**i[;@=jVe;S X aTDM>9=SS}$Xz%$u @olAAeF<[N3(z0k 2C_f3y >0wbҶh}I0 -B` >:Agmro&C]`Z:Pe`%E9BǶxﱽYo Mƀo+i+U|3W2ճb|Ĵȩ(KCXTD?Vd^6BX^L1vN:wAA}3Z4rh᭳,A#( #@A!`>ASYg$j`¸hC>?iDq,"" "jVacEMCh[B=%uPJٲlP;ɛϨ oѩ|%mqX5X4,T%ZOBH+(G- VAxhRVE$cw2%Aiسտ%:%в">O5m,a'NQsR.$ >K(7,Y*- vbbo).3wp*y;HVX+˹3,8[h!whɪd p6h%ĂKA!Xݞ.{: r$hrp,N)r H VpCb!bH@,Aq'cMz' PݐQDC7Dt;niޛBԂrh!Z!TUb Yl2u5za6l#eJ& |MJ@z2-0f2~*((]UP* r ba;D ެ3?x(y^BH{ }!0'}*tu!~JFX!UR=E3assB`C0)(XᅱoMފ:owʃ퍺 V~?,--`QVA N*MڦR_B|&eI CZG0AJ#8x:mB%pi8eϤmFy@) HͼW}RES@6kp!/d&fT嘆HLJ+YSnY1XRAAޢ}0w /E1;BHR@MN@p,A)5rT ' C ~#!2& zWCj\T4+eT*!HKHxX1RJ8Jp)b-R&C",dqdF"muH#ȕrWc(
    Н MdX.*'~+ٝ90g+1edyRiH__omFQf磌Py/J^ !ȫ|cA5yκFd9E6P^|pz/Xt] ej{ZPP(`Ew:F)NcgRl n _X2~y@e?13)ASJIW`ƐD p΃,AϤA=..wʌ˅]U}ܥ!UQX٘ h.:|dv߁dӜ+@cv`l֠"Yi,ѩ% `t ]H=br/(}^7rz1hFbֲڂ:E PӠ죺=S?<}d}a:#qY q)gWz߇|-BE"C  xo vs:=53ۀ{ ^&<-K`Q}w߃5  2B*,:% ZMRtNɖX N|W+ȬB[ޕ2RU.nSaY3Ola*f+0; >3r.z7՛^3˱\)F3wqbdM"["42Q|㙫7"UPp %$դZ!^.Q㵨SQRFvt'5gf!YUbȕo[QZ/ vz=|Qxr秷91UbB"b=o*(;`iĂlKv4D )SR.sKJ[qwCSًia_8l9~t̊^Hx߇< ^fj 3Dը>*U7hmv M:n{œdH2#D3b1K"¶E4(i^y7-_\-UPpfIȧh{7 uɲ@uf:Ylq[4|sqD͒M"A?yStwN 6&*ɵR l.T`W!*;=Džp֣񽥾#=g%pABH]UapUPw( VA>WqW&wJS;ڙĦ*. [OC!3_|gYpHeWa9,7cQ2C?PK  VШ]VKUlrl\1Gq֣AP]nPCUW rX;z *(/`C5MyDsݙ#hyIP TV*;TN=?]@Feiڶ~[ʃF1~ @Nr\Ե Z G]`QVA>+X@Gt#'IF(%SdLVEjX]L%T,;5f7uh%}'ԬެO_A-n:_X.__DpJrU(&C!X7,=@"[D,D)2*+DzHpr jnόО:`ǃΩ]( 99SA5굆Y xj^ `ܨP Hl\,{[!_qD,4/qFrds@vJnTrݠTWF t 7< *(Z&2E$T@.kkchNUO b-Zv*b" JL 3C(((PG)nVYjWjDo{mCC wS]+(Pi6!bDE?0 - 8b`~;[H#lS0'?Wd\SH V1UPOF{eZxz8t7{0{p~kPbզ<Se2ץܽ⾺m`GZ)Ɠ|FE\ɽ൅`엘!wLJ0 MngƟ DɁ*$Z s]+EIVT4dLɓWW;drňWWq$䃸CޕkRтEQ pb ;PQ8x,C">FHX)꒐|31>f<5Rl:S'+![nz!r9̯9[=O2.|y)ra!Z! , !]xWVwuܔE&ßsspHN˂.g.OťO遉h|Cre*d-""Rna8v` *('4| 7yK*fD+UDӺP;:'W!%qd QK?3K@g}4ieƇK\- %h`OQLŃ5 O VL&؞o1yApS,r!M;$XCvԙ36Nn"HE NN=4V" ^K[&}\Q9v8zM{:. r&B]U3|W.ϜNq1!_2Yi(|Yy0r6--YNe{EXP( VAA%7_!D,=q'9 .'f4,!WDw 8 wԋt0B'3B/1B A/= F3s|}[+sHf$YXDz=g{'/3xO5՟neQ󫫉de@[^4kʄҋ`oQJRJfTYxaf03^7v{ͱpUX_dF~5UVt1!|`*Yp-%!B /*V/YAAGQ zaej|U\^,mWsC5_&i@ O @8wRB =Rno(5b?"Pkb_k* E*(W`ξ pcZj/ϔ+y_/>:˽2>AzEInoO;M0lU'>'8qnܫZf9{Aޠ}%aPWjN3%BNnux\,l@g&wكs82IW7f 1+bժh$;n_u _p) PVA>gQ%_L8znq% @LAޫ 鑖9 ہ2% ډ(VFzf,}qqdes0nӎ1 ^P'(`?9̳Bb]( 8o|]C4+|43 +hmN%0dNYX9"Bq[]+q*I8gq]yUP+VHT`uV>Pwq6 DpuZtaXNDFBI)˖Ηle$Dz6:i4*1x eaA5‰/Fz WI#bWx?$Kg|'ǒY7co>gL<!<$ɬ IDAT~2'l`h޳a3q"LS';f&H)@$fk X󰒑߳0ɇĽwu?T"1J}lIo{eKL&[R91c cR{1f8u2eve5g*A*r ^S(`{_ׅPQ*si6>O4"&m9T,{ktQg|C4Sw3˃[g_M(h!WeMۻ"ZvfНg`wwٶ*(+UPxb8rJ,@DĞy@w!8r A7 "$ CpбSNYˌByJ[26d ͺfLrt}nznώUPGx졇QW#U*m4Pfr#D@fb.؃=FC]Wx? ?ND+feuIubQ"3(J%X.uz^ 3ժ{tVR1KftY `*@{B veRA̪JoB$Z!*00E5gB"> ME9\xn<lRlh<}.'[Ȑo[:%E7 |9e*VnvY/eBay9,vvq!Wt,`PVA. |xJXg#Z$-#x0?0?XX` hDdȃ~)tB|RsX:,H͍d2Ҕ{ηdD+_Dvv"/3~uy&$ Fκhq KkQC!X{SXVBXO! p@`#_`8.͉zU1IωCz[fxd+ uW&|2Ν:sOPeJUNrcLerd||_-#PRjhxXdsʗ>_ ɪjm-((<UP x졇gD q]}<|=!UD qǠf̍ƌ1Gr̍ !L.bHk6i6a6>W&I-UX^MUo{;@m7r5{>/ؘDw$נK,. *(≠n+X%VXH+Vs{0u|ₔZ/o)r' sKO\_*ˇKR{KQi4Bn~Ya;me&iJ8{#рiҞVǶYQb `ruH q^bD b#3۫+%WVVr`RAMbA"EF\GX3%t!Tb-Y(t\[FfӨժ [[Vmwv$yC `OPVAna`B$|2W~J X_oq\!$e :Wʺ~1[GrDXX\ʔ(<8/9Z5%?[:URj΋aMGTdOp+v` *(D_щ@!]AԪL>{/j{ܹ<έX[o1i>>g(fZ:жoqF9%˔,:ŀa;wBhxw^F rs4fC̤qțw-Fw&ưQGb<@X>xHnkE1G=>Ͳq/*I;_llvC^'7tɕΞLLŃUP(YSPpaCfrU# *y9Y\!8-ash[BдG +xs,K 0B$vж3DyT^ŧ ƴ .g77U)Tx0^dJ﫜?W w]an-r-fIiZ 5 E*(upY*vZ_luMbsS+S[LM4-ƣm(*Vk~O(:$X4 ,pJTy>Rf G*J^㞽Zbmj/Z%1V"F~HS}TX˽UZ= *(B\HtY0)i⽚EFMۢmW]F.3LJlV̜qr+Fc,$*>Fl'ǔv0HKf}wb'%Ȣ)9,kB v&/HIϴB%īT6nC -y#U^O뱕dc~,$$]n%GXa0+CRy΁,\5b0a+,9>ÆQ8g%*n6/f*({UPO3իVS#D*x}(Z^WZE۶h}5q^ ,yb{Sd%Ji]</趦^!)Vl^n}kSq}0^qϲx~.((&W/VV>=r1ψ:S1;Q3b=Q}Ѐ<`Z\9fT,u_fk|"W `54"Lh shb7XɊHe@[&OWkH)4IVjz9V.|32{>"ykO>v%+#AHP&ƛJ }*+$¤^A^wǦ%krR:|_U9PcW Fv7_c4rzRR5=@D!(,X>-ʀ9(%Xd'Z@{u8j KԕDH 3Kg>\@U}~ U(XЛF@W.U?D1O{/rr w>) U|5+ň\]Ib*D@L.S V㓷( d!J{9nz~ެO{5*B1(ag•XlqERqʉNռ"|qU2>19)X Fb%WXW^o'ZT-6-iYPcc( Ju":i7?_w~]収K= l%e˒f 1B~'24n:O_UuVu% FY8_Ԭ|mU9IQ&Wt((Vձ|>M`Yذ8ؿ~ ((E͐ Tn12!l"t=t EkаhaF$ >|'_~m֙ET0?sc:J PK/^{A_:[ ^* {w><V}Zted|X(>?)hF*UjP%0),& n>1> OA]FIp:>| oo|o[aGG)Xˏ)ھ{Qix?$FfwQa~mߝd[lz]Ck3f0(Nwp'@d3TBvmڬ(Vlńӻp00M|w0{{NJ<5m-x#Nc0ASi)mlbbODo= 3jhcqd%>6OUNT'W[)Hf0({b=?Jm]>*ۑрx Uf#Z<+Iu0CglvnpQ3A̘?Ü@)}[ } ţ:A#X w>}; jaAzdbVqrI0L@v:':\F] yR5:-KjeUJ\]1#(m/ӵ\ˤʞm_< %#+?RJ}+ 2>F滚,UWJy&VME<< ̀U`u0~}xB p1rmIR=+XJm@8 .jVWWG8s\a$U)ZP_+xP>8 6 L[[I#6cZJRlf18@V:::`2 b4%EuKF644d4 #/ͥ(cO0"|8>E6zL AL@ O f‘OdUI2<%U_mmyVMUJ~I*U*#\T(b '!ѣC 0S.+Mjh `540Daqr؈ ,'RVj]]/'2a6d_?ٍ7"ao)':fLy50U~wV$Y!?/'DX+[FUO-jB8A _⊕)`КOGoYpeŔ*׼BGCmF-%RV. VJVB=IDXL9L^?o yJi`Ú IDAT3&1Lb#Z~e4៼.)W "W 6!X"U)Ug%}2jm%buՔC5'YGE*3#Cm?k̓p7Z[``5"iP#i{Jb ḡ8cvAdR]Y!w#5{삕I`1G$A"X*}2;yCd]S<QL76ݏE%aa?#9G%*`'N?w#bBF!H0v]xQ#0 v>f-XpKnaJUFLh[dB&>.!Z zqx(`,e6CS)!BtoW;eF#BĈ,@G8s/6cZy|B+:\ $ l(Yb.J6j5NO  7N3ZH_O`3' YYZd V=aq`#XØ`:aF$ 01xa!R[J7G_|=YC"Y/wREg8|j>ԿzL%:W2y U1d0׈J@8zIenT.42xx}ry(+ .(X^B }@9Bdre""( @1DSaּٳs{!T,Mjh$jh&@HzGy㓻\u4pv9 ʪ̢qG[1 %'<\s*VLБ"X*ttSfLkQСG9@]*ERT;M$^w5S/ 3ta ժDV'| d0r)|Ohē߭55Op=)X  Rʱ<ʱ9)10T[Oj`El!ꪠ5_.gJzZ/r{&OH 0yp0/ 'Nܫl%GO;s?N​2m7GCL6o~+Yđ{<af \ }YI2'bD$y6$B70wlN(dj L!kX`p2SB7"A^9 PSԕe yr%<7H.zʙT?c"DܮŻ\ѥo@M%2h6jݝ0 F`FeB'OC"QH PD39sC`540gP(ipGkQê^i`^O>rԖK,KU޴̐V#QWxqmة<\'`8 "9~[<&ɢ߄=K#u_|qdǟxAB`54`hׁl@y'\jOnF.V" ]8QWvgE(1]LR #+q;evwe4T+ϒjK @?Bzytzl-0/J= 6{*g;(2jAlg,:B,PtL:@b.D@4o^ 74|@a*B(ZTy暑}[B8s=HNV"^SBPRtØlH)W jh8$K]ϯ2Y$mUUaիaT 0Vaެ- zаjh8kUFTzWN +X`+6*/R@\|R'kt[G@8KX2^Z^atݚ*WZ,Nөb6f3`eŦ &FlJdWRxP'*-3;6ZcpYL\( uɯ"Rq! հD?l⦇6F>hအi0,r _i\@ҋEKR|UG"W=MP/s]n47dC(j}?cFW|XX'WrP661 &Sl LU4MtN"4ξR(9RNh8Φw^$b \hCMUG6ŚP߲iKcC`54\kX[bɻsy\T +!Zժ HXrxi,oQՊ÷;:kX"]tb:UVfȑT"1ϟ*ʄ;%nwaO| vQ[= YjXC9$bUl aðFG ^%+lX1N..LB23K*TnCKnoe.',b-%n8dm5oqxer稉YRW$*HV"`D}X!:&Wiv1w\P֞N=)VIu{*YcʂbK%2? OhU87АVCÁ"i.a].WNܕP&*EɤJզ4@.d"f?Ka[ g_in2a)5)V"Z2V$2%l혜?;Xy6?%[h?}Ѣ~wѢf$MMUN61Xma>Z54|VCDc8̗G\%K_UP>,8&YF&0F=..e$+KQdPpL^jâ^yR>J066F67"67#[Rȕh2k~ՠ>L!`tE*?&! D j0G##A Q!B`Zr F@"CA%Hb1jU%A#[,ރ[/UMtX(@$38[ColаMjh8f߮yDyڏkWJ6ARbQpU ˖Xy#ڔC7ߌ~cM.t<^9EJ%BѲVR!܌1Ĉ]%KHP$D tÀq·mɩ/#Eɚt[_o䪡*VCDo1 &"FgJ 0RU|X9tT&[QcrѶwW,GM"`-r4e1*76#|LJSpokm,7 .e>.o&EK)JB3?{OL-,&߷ y`?lsc544;jhKJXɪ()%'k!fp|:%G`F4l#.wYS"cJrW"c638a)FϛQ B[c57sWfѪ[[<بBew KQWT8_s"5)5! P-c0_#(F/ "$n}_uRfS e>9Q9ĢcP^- ZSA`54|б^!2C{L/yh,] YL@FNRW"U#89tIFEU'^@h+.VvA&T`ԖÈb W%&-JKL:CAgc]c$tO{wщ]a1PAdxe#+}A/OL@^~&]D#X  WPJ:Z8&QD "j U lT_ JMLPzě/?1殊_X}.{@W΀2G s=BSD$Nϟi2 wTtkI|1ZTDn |y|}N*JyethJ/$"Rk. [Ӳb嫩"Ty!;M| /5$P62$U ~so-;sCC.8)DF*CJ!VފJEJ|$b* K% h`D5Ha.?&y)+.#Y>0>+v~S!y#W dʊK"_(< x 7[ȑ|ٳ@luM&1o|s٭mа{h%†8^?@Fj9%NpN?S:|." 0")7J- ")|yV&\\Mi!:Rʐ#e(1y^{ X;>,vFYT^Nva߼Vѣ=rQ?I@ACCޢ__a6s?CVp \)= Q22+Dk֗-e`Z]GdryB|rHidi!XFLb\ɐ:wų^JkB\7j}1lE4ё֮ȚCs}̔4644&Z}ƫϾ&y꺢t*[@)\]eI*ťrbcJZLcHi C-=]}^:l#7@s#kX̔.V/SJp%IYkXk0+"jLy7޽ٮ|Jx i"KCٳlaD r])`54>?W~'6Q80w S0EpIЅvzN! R*$5yQ9^*$S=A-8u@Q/WU _NF|zʵNe`U^+Y%ܼrI(QeY1ɕ?l#JG]-{Hiux?U4&4inh/4аx;'Oȕ*+밍]S#`3p0V1ݼgw.L_eU mJ@&OhE|e؄bK-l#;f#W̖t3s q2Ixy!i?NbUuI0NTi[CGpIxtyl;m5-)ܥM*URWנn|_X!BaC^}~/-)+?xgYʣ}8c&̶d|}`~ Nh%Ï_gU"R{z50UMO?S&Y1aBq mt)?kQIPHV-3ǑVD+ʀ!9w= [{@խI)X۞rvjwVm%†G#X i0wRǚD=r ZL+,`uͻnp6//zP.LV&[GKד*0Ū0'#Z[P'W$a4_^֏^v: `L*gnRnRP&sQE ":z`"-1O#?G$VAmy{ ^ IDAT]`54!yG%Z}_WR(kJֆa]kV͒S񽋟\=oi%o>,#.hUXLLcKxU *dSU.yDo9@6"="}K$X̙P" MJ 'Q/GfT"ߞ2аhaUZD`Bl4[Fe+TerfVnJ!S} 1| DJgԧ!"b a [?H<=J;jK*I!(\Ee+}sE N*,)V#Q#(a6{{?ҢɽaVC!T zR2_& EGD47cfV?/zK Nwe8TNao}cSaxCRȢuHrJep=ul/8qk~ ť:09|xT.turY1QyMu7a?VC'B"W>+R*!ѫ}+A;HTD;\~yʇV/flT (NvH%+vL`|l"t FGr%*=(RЃe ;RމV8W\R)) xX]ٗа7ha0NIIydyk2ec$ˈQ(06lQt'ۂDBdU(DQBU*fe;cƢxDhV <*{삺S\(}2khX аxyXV"S8!JDMәbuX]VV &F72e]7nb~5|ʜŌϵA%o狩.!v~pq1]uZ x)#wU(͢uv.y {`54:CPRFioGLS'WF0ω &,x.YA1i1K(F_y+ ^\vA(ŴTʑT,ԕxC|۳PTd "K*5zMjh4aT+TH|=ķm])fS`efUo>%RhW{/t>|4בc!cI)RIbNN5a)T#H߃|Mxhre\ݪHظEh0-- ɕAXɻ؉d-R0YZ36A8B3Ekp]GevS{0"T2&W"m X"y1 qe  ZʑJwL s[[O0P/ p*&Ƥd ekLVH|FnWS)NfN]`1ɺ 4{T,:MWz1{-Ry`*k#Y=aLg L9$ghVCþ=@A MQuf3KF_͌y<#??GWN&ME6;G 뤑%ʣ jAIY9!Q \x#LpK@Zֱs;칡aЂFv>vk!()"kY}uG%Cҝu9sж&adhݢĬqoMdUl岏T- RSDX|YbP&:^^M wd*֏aLjh_4аxчTay4neczW`N3TzĞ] '{o@񽼮#*#Rxsjt{\+S=R`bJ zFj-IWhh%†E#X }PԬ퍡Փ՛?Yb#AHu}gҵZK4q+ݽq+(m u6hE &٧NO8s䔉SΒVWzscso`Ht LgJr8/L OES 'ſEf{Z`"mh߬/x%{F+.yifIt0N̳FuEф8BrdF&`W:/}P H+`9l/O[$#Zá pqrmxme}9c J<ҽ[I#La:-D@1Wl(qm;`18A+ǰ|j2 Xd+=Z D`k!0`jU!~ILȇj0Mې*`unu!V(4Fh00Ե6dS`i&YD+uBI֥Tǿ K]~<ϭpUdQM5b03B(fpC{44\ vmx-=4VC5Ʊ @~1r oAId nmau6=:$뛛@H;"S;2 jHҨ 5Cri06ZRZ "ʔ)Ê*Tt!G>ヌ_Z W@S0Rk: &6 3aU*eFS͟ߌk]o&p npb6b #:cueCU}H(+YX}TU*I*UF6E|eL&eDF/a/cZ!ThB<#21e{Sg^"Z*@< f36 Ӕ X㓢EX,Vb4 ? bmU"Xө)!8So~8 WrDhulS^TגVC6UAV,^ʹĸcatNXHNtO=>Rk.&r Mq,,y +kU@omRCI(*SRd\MgUMkCCV6dV1FM h:m/>G ȹsFjˠ*s+)~}e*U+`D2!#KO$ID9ٶxP/ IFrđ"Y꺢` ;ÜѢm kP-"lh81 u\KVV"q"8$;ja_*Q: #8+fxckkt]*H)gX+WD$)aEl$L41VB ,X V0bO#*k<41ˆVl%>"~YJVwr:-YC[㋇xHn+]4"K͍YmKb!,~bPL(^(dE1b\Ťd%,j[y ޹ȕ]{Snn 1G#Hpɯ| ja v>HլeJA#(MtW^7EiXam|T Q\yƠuHK|nƖ ln{BTIDAT_3'll?o D` GW/BURq Y\ -UHhpk ۱`CrQp9ta6fTue̴Zngʃi'Xi\IJy1UU+,GqA)r6B\b*Bq賏+z6a8'Kz>}>|vUF Qȧ5i_7eqC-F!+, YA ކ"(JQ+p;ґ(C5a.zRC)bŪn r(~)ٝX(W&`&QXkE(ly8{{})E uOB4W6Moc]jVۓ@5J0>kg"wA%3Rl_/W*u"(o8BI`${!T }wSUFB <7Ɍ%gԑu ]AQMAEj 5}+MUG;|(> @*\ 6]]] F.nO#-R[hpJ}V>U\1>OEai]0/c(<ߺ~ k=WwORiPBC\$b67C8R8-no S4nx5[o>4`qf v<KQ {Klz vWû lz}+;}޻( ~ϧ})džT} 魇FԲC+>2>򸍔TG {t\AkO˶b8ږ/׮^`wק})NJTAxhVmШXG>}֬j:|I,ikkV}9\+o/5O=ZȪs< c)V,.Uru˹ 竕JO֟}c݂W'OAx\+Wvtڗrawp9GVZa탰-Vt0Hs ׾fR膐2&|RiيjK-c5R4喠6 Q5q]`݂bkAXgwⓟNNnQC?u؇G"V]9s/#Y.Tɂ5 z#|&Y-b)FY{mպzŪޤ>̳SʻeU˻e˹Gd-p s4U֐98;G ej+#|^Š0n~dQ\e3BcR@>Ss[]y4OnQj\ޫr DDY[{>GTaj{û}r"gvIK2$1=Ax:g_AozM"7)zh's=?$'޺Q0%'e(ƴ xZ",@ @ WRRQdšI@YQ'uwAG'(*ϊTB*h7u)pqC}Md^Y~˘VͰNo|s'3~Dצ\YXw[OJW(WS'y^`4g#t4JQ0JaB:}IUĔR{RI",-V*XN)~P!`s΅/WLh`='#rթْ\Oxh)PR4FhS`LVJyʾҚv h4䅍z%-BA$eYURr0\GHqE_T5\Tk_? WZ賞pػwNϾ=Y󇣼zQd+uOH2kFiϼA8*p2yo;+;|kWγ?Ƕd*WWVq,i fRZ+ bf8WՄ@>)4P`BV_kHq #琞W iY$k.{}|U47yRИ :?+JA] E];qaG]hQ9"2'!%gG\좵2[!8e!ެ'r5 VKjP!DzsB_kh"zkծljϵb~x~:] b+nݎbnq x!8x,ÿB t^<aё -%V[PL\%`>L'Ql/3XRɊ~8G'1()* Vz!=ٔRpkU[Ҩ:)<|^b~Bޒ*eK[HK3|fb5Su\Uٴb1wn%Njˊ`BQk~縫ț<0|C2*,k"8G,.yr%.=W7?+O#K!cpǑ*-h e)hγ;Sb/WZ'tX9看 VDW?ݹ 4v\vJe)xg|їg҈W/_p.bW: Ϗ,A88N0Tu+6*tk2>`OQpȄO*:P -MZd~umrԚ<6E]kɉ Qv.^OaV+XƨsANXc4nASZnq3;tܘ7V2GFVNGWJE0ZQjM I]fne\7r6R,Ap3-t^Im0WhzhMk6窕xōAL.0[.hX T=xwq׭Ɩ֔& Ա )4Y̰Gg=ИB/[&,j,A1FPqb=[Jܹ1XsGuNs E[z7 -ױ>}p4tukPeᙣQޛsPM*7A^X \jsЧNÛ7oT 8P:e)&PJ&ZYJm-7|g,,NUpq38gnJ엩e>LUN}uQJi&` zZc hgPn6r CIsQ+ V()J_P$%KNteVZ! 2k9M" 4(JŨ:5c(]Q~rKiɦJ #Kn/nT dR1|֝zɳAjVqlNHWm!ܜ Ћњ޵/,FK*BA8D` p={QcJڝenw3&Z*%~Ʊ5YӠ5:hpW1t{W9{ll%‰g2LFt:Tꗚ V*q:xō\ŊIeQZk yɈ%f&Қ1?fqqSX&%*BA8QD` pԭć(tRDn%^R=q̭;-)x!^'oFұCB5wFi8(8ٞ՛!K3Cp-{6WW֩9skkN[ѷ}^/Cnk"JXrThJ9Yqb~ź{FE& %™2)o-@L֫Vm :C+,cMǪRܽ|UU*[K(%¹`*JN/N̏L'ct0Z|@Ol~_j,Az̭ VB5l5l5L/gs?~@Obf+ӦhF5EF ̭VDs|QhnQ~2M-W4jgwq(%,A^+ Eiww-h a2̦?gSx##VK"%k{`|Yh%Zk[-[-P0Z&({> ,"Axc@ޠE:̭hb̭ZOYjZXUpdp,hK:~6چv܊bk6=/B6 ',Ax܇:ܴ׏F^?έ$Vlu6[U@d|\BAx%lg >z0V7n[Y! *cd% "A9{s 廽ޠ(5UgnMId8ժ< U*BA8yD` (چE}[u+R1VN(oQ` i!K%YGLQ~b0hKN"U63i**;^1Ax%c+-ltS+qf0l2>X0Q>ұe%p d)*T([Y^IVƓ 1mN]u"`Ab}p'o1p =(fBB"#\AP e]7]&B*?)5ފ1܌'16`rT KU{ƅ/y$+ "?=bN+1&(yϞzw9xO==*!P7Uzu "8"ʉ*D@@{$+##c )@DX2Jh)Ş=s߻|ט$G3ooи}BDGH,  G~7!S+巤r9t6[T1Ob1^F^I _H`D˵7nHM('fddd!ʏr,q7,H*B @sK"V8zcEwչW^ҫqͷcddlL"=9#VH9r}C} mBsuDQ8 T Ŋf#%C`8)MէnD*n\Jρj;U[æE* ! #*QUCEQE;#_}!.}ku/&z0cq[_F vPofPx&PJ(3Hň*fz=[`\Gj=V Jd&"k02W DxK^í\H:QrU%*,"r|Ub齥"1$$Py($T2R2r6^۔@ v$B!W#L-o+F  "pDqr*8fUpYǘj{gg/}ƬnZ} T=S+WOll:RPH\s^݄}u}އz 㗱N ,BB2[9IJ,E ej"p9FSYC15AZ$ Y @#  WKyxo$B(a itR@ׄL22ؒ ,HvN2xE%B~sNnobFm1}D@ 3\Y= V(nw`HW|D@B ќ,j!m*F"ɊU2`%CJ VR }yf7 u<4N%:+-fyǝ=w{"o}]wb8+Tߚ1MU DЏfHs~w˹.ilmElG،P6j5Xl 'T?0ߑRk>V"aVP$QɃ9W@wovVjshm&([J8b i8z)|M~7V=Xn"~?̏c !nLt^|W>y#}o/y;Du]MM\t̠۝A3z) T ?b3E0z;5@(st>q  F)rU3bCd D b}gI# KFp:N0#BtRD|܇[嬆]"dM9>86׽j|˷+6t fYZ3T`0PW>y&#cq׵Y+XwILjsì~X/e &k;YY2\e<@gr'XѝbҨQE BPX"A"4)xiVR+*@T᧦^?&ɪ4k >.A7X7|+^/߉۪WQzMxp8urǗW(##c[e%"H`: ! {𾋔xffd$6{0S `뤦֤Xw1]c7RF`N*\Zjb$fhoŐn96pULY"D̿Xwb_Dvbd)?wnXF!ai$NǓXX8'GRFFFl|dQ LlJU)9fxrȶ# lvB̀g#UEG[T+DH5'ͺ,y6'`I qѪ}Mc8 1+##aSKdMdY>Ĩ R>FFԞ7v+Y%w4Ԭ@1 0&`e(Yb$P =!ydDEf@Uvpg_HOV"Z4RKqv{M+#\bKKc[0`ͨXWP-1AռYN6Ķ:s*RCH`՚Q$j gVވ@Yb MO?~3`@t{Dqe&L22V~+8Msg:]c;sT]E7&y6Jb~w35 +2W}dƗdӟ9 ڧǖ"vHX֞iլJHy88b5& Kl$ձX6FU,m/K++]|KH63#t VF9D&XۊHl[jrBѧ^خG婭^XA1P]645 pb$ [&"e/Mhb`8*^mU9pWyg}gYI^|7olP[;vu1=qĹMFS&XM.Xq>f]w>t'LہW,ߊ$A 8e+b,TuM/!%,8Ͳl)Ä/ b-s,װBMZ֣,W,2EE$<rm;5ԦYbCv^HVzFzX':;8ǀ,iC7##c VF6nEFt `r   b"ج0{AH$`R0}<U~mWK_8|ƭ΋E|zG.Avm322 [n6##\dr>l>%G01|૪n{ql= SGM[wljsc{d[FPoh}7}j*FLC<;x#?K:z|yrcoLA?A.nw?7]yU )_^22@D[\"LP3chw *03ʥe+5Em#_E"c%b6vtBh"1IϩC1ErEȘm)&ZZʳN"Zh8jX]%m6s' PV22r0#c7t^/z6|vg"-\qlS..b2H8ѹN>9.=QpH%2;(A! &z.O߷Dx1*I&gU+>)g n+D Y2Tݳ&KgHZ89-YU6t-V w'/cfwuqҶ;###mEQpj*Y]/zJ#,2=~,3 ͙kJx`AՌZf,#Y&Aj)ZtBsy8rgT\,=>Y/G8qnTYOVCbf/#+KiJ{u}og _aihaed[dOUJ]Hib\5h\oۮ(Wyvfpp_tO!6}1!3a`{f^TnU5 *UQT,lT,R;|TёGG˯e?[EL*bK@ ?u 3RwKLL0kMK HsO{.< t9RVb}0ړfddLD&Xۈ_aRtY Zǻw֫ȖjڦtC%KM pDŨkcjgB@Qiө3 v >TW\?b1V3I X8u ק"pq槧1 ڏ[&.E3{߷8_blpxKϟ1L22s{DR0ވxŭ78!y^?\e*2?ja`V4e$2eWc 'HhҶVr5D&|10mB=t߽AQJeϾ z;I̲2o2A"9$>ݤ&"rcĬg^IO+ C`N&Xی<0#cfcFTC$`|YH%t=_gvv`dT{dbͳUzx?N=D#\lN]{7TdqN@/o8њ;F^mfC6zw;ģwU$_"[#'®C5JfՍϽ: qd[sΡ`:w'praވ1эd`9!a$V"Yl\W|h߳;L*&jltnaF6"<#U gq]\`$KO:ye|%opp[F'Ɓ.NJc`P##7@A _'5k!#Y.8iƂ΢ 1 6nz鷽bWpxT߮Č.CQ`~aAL:;=cU"6dx83Ň`3 FfԇTLT(:'J2gK rzoUй`ۅzS;wu3FaF6O~+rKIV!S,Gۤ65_׫'g*6,@)GmON(d9KKx~ C /5|X \m׬z;LXCLs=_zEN IDATEQo_/(wvǼ[ Uj8yfx&w%+àpl#1 Ǐ-{Զ%#㩎L22 '?ͷ!` [NBZ@M48OP)ckJ^gxyxIU|\*C{tG;Gytx%Jf"^zEBƍIj<]5?fıeه%ŒB*/9!Xl@U,:bFgǎxJ.^܇ϼbpчW8=-耚0 XBlmf޳u BjmXg$lmL*3Pi.plGW -vq| +9) "SeL(Y$hLoIX$"T11EwDj4RwcgQ_*ԴGoʣ|LgL22|\uRpa;`n*ZvD UFȕKIyOVTccs$51G?Ȫ39 d V@}Yj "#WE`# B] ڔD9ҬB+k' mvD3ԟzj&w8~t {ϛ¾ q-CFFFL22GǮ=;ZKҔaLMe;*QWlC,A!>|뿫ץ`E=t6cZSTH ˫Ц=MYW0rIud 81EAfP`%heYǪ`!)qD"V50!JQcA>Q]"m? ]m7ND9=xj!-ġ{û"6#͠"M4HX(rX*]jy[‘tG1,ŕ-yҁ)QmT,F|H#A&r15ҼӑJ ur$AS;M);QlcdI'WpuyP:H  |>>'_?[ @fwe]+#c A{`W_(KB"Ĭ#-|byP)5*I*G5@>^\B |y:cC4ՊgXk)M!tMO~lEa2fTpmd$v}(!bB `jVmvO>,UU8 b3EbSQk;݆׶P ع=ŒD&Xo: ⑛-Ha4`whfy ZBĈL(EXĤ;HQ{Uʼ^'E:ZhMX H,1zw:oƝ8+ x33A `)ޚw|cÊ1̝@ؗ329=#,qLmH54՞{kmZ3_|-ll{jpwՄ)N|TEܩ`WĈ:J |UߵuD1ubKn.ǣ;x&k1;x:ƍ'ϖ/]8*I9 s{|uo{Ӎfo-[w(BU K작 VFYޛʓC 0*PQ){ s`r&*+0c5ԚSN\E D(E\%2Rj䌡U"1EkM;l?o俪M@ihfqT$*^)tΊSDʇjMc(+iR˽r${;vnw D.&kBefve}+7}{,ib/6i PLuc8gwO 6 VFY a$.)<-hX׺->(s fj56⢗(5N$kcZ8x'VZme*5h jjUqaNUPH}5}k4cvp~3eٱmiڶÌ߽sNg&UXzGQPp$Z3P^#"[:>N 'OX֮L+#cKw7dUHVw)I+rKdAτ" ApIV$[ ;Y"2ָTSrdF%YA5(jb@֪iVJ\~c,o,7kEDu5Mu˱J]CEVf[$ 2]9[^2JR8~ʕΛ>sfddL226^YgvիhEDʁ5'ZD;]$Q;bEkъ>V ftF*j2bD90}-LDK$^IrT1sUή_i7 !3񅃑XIi?+[~*`j&Xݮ=g^7~@DkRt}'x " ޛM) ݴLTDµᝢb˂c<)׃M4NZjl}"X%r62*nk5>w*8Ƽqv+yEUD GI{B1=q!LMa* e7O)dgqs0#c+ VF"㪞inj)VbF's6-v밃'ԥARڏT u_D>wX{uQjYVƎ1l)TRȖw|:7T,=X;xЉAHҬbMX=;p5bNjsn&Yݮ=v: r.}2`MY'kwaedl)2=+/F0$OT=JE,B°ijQC"qT\rQG{T7M\>wN,5 Fk` YzB `gt;xk<:\- 3 _ ̮_W sRnjjj 5J䪽0f %Ǐ,}X[L226CD(3X@pHR mvq`Mᝓhr` Iƪ^~uo0R5f%DZKS&ل%,"~_ei>ξd"[)yɿj=gwaISXU#?[UoԫXb}?qW0n51pEo[qK_[2D%+$%iJA1pq=˰Ntbj='cw!ez*Fqצ"4,y`Ga$\c~`8<\*X,(%]7 $0D6Wya8™L22`ed!Z 3E0њEzjL~&E:A^^ jvLjw&}xO>kM>7Sη SNXw1$`jnLBRǍ뫓ކyl?{Oaedl!2(jQ'"ң&pMq!66o(NSj#GPR8"3XGQhjd+9 \Z<㏺٤LрoQyT1QΝY^,!Z`++#:`*8@8R/!*BU5E7GZ }z!y{;񲏿sOŒBv8fd H#YN=.6)8VǮ}eۥ)p}"#yXM`~fOc`"ad@+Z)l7rNMbUǪ~qrUA5 K,/W8uj8,/ VD"λ_C>#\BkS0PΝ,L22YѱD\xx<3JʂDK3Uk_y*Y> a=)~ PԠ~̮2H Ɠ&{iQk0m/Jeܦy ևP<Ǐ3**qC`v1e?S~W`3M:r%0w];&[L226:./݀g061Ik+&dkH1 B e=Gn|ڦxI;,@$-R%#.Z^v,=:mVJTM&WO.{SVN02>K/ۅ/_?+#c 5*S1 S@vDC:L*4WO &Q$@Qj, BUG<.'~|ǟ( ,/MN28C\aRC~$Io~aTbC FM +=(" T V:MڸoTPy~5@/G~jc2(lUCJ1( EqQ0%)(K& rCx ucIXme ) (;? /ށ}O6m\`ed5ɺo0C!߂?9Lԗ"4*XI%S $P !f̉*{SIBu$HW⺏޲bJ5V<`)#jsk^똚eyfC&XFR\9}1Pm^_Wa~^s1@x3P>rTK ;1q W\zY}W-,@pGNyUE(b),'OpݣYKYR,_ UChL"#s-bmVbQfJ=[n̷(|Fh7Dܖ>.ށq ˞Nac8A 5~{4;+q:dA\HLch98.cɗ}"t"%"tGR8C1}N!@\u٥**%TΟƞS`edl"2 zowX"HvXbBKJbH "KQ [C82ށJC|gϡRTP^~ \̝`yĉ˘;9>nڱ~l=:'){|, V&W)c+Rb1}xsV%{\w1=ddR_uVn+#cPmhǠqJ©-Y:vLZLv5sH"@"?\!v?utbvw^nY,/V;ljc}̝cy\Jd*(mMMb"&oREXUڱ>V%WV.$UŏdY:c$QJ"PNA}EE;B X@RR}sx٭L226 GIVU*S7 IDAT:5H0KoG&A;ܩAz#1pDp,p! ?bkvw7MB&X@[JcBC] M7 T# n@LlZ焸/1ACC$sRyr J|} ]ؑ7ФpMسw .]f|3T ׿xى_zWx%>u\jmr6ilMbn3;1'km:8b˜P-{neK}e{M׊-w@ ZXtGQuSE B1 }RxԲ9#c VFF)&!WWd~cSK9B":OQ4&:&T"6oR?õTby-:𪷽S JjWzƫ6;>!\_<dl_Ms% )6R܍4t+Hsh*^/~|/P<$`CC1g++Cd)DlDA(+ |N=#c VFFP1Qֻͪ Y`dDI[bɧu$F۱ G`IpYi#W^scB;?T5S,!@Rk3 BP9 <1C3าJrJ_ FwF1[,82Ƅf},Mw SVʈ@[d7"Hָ圫/E<2kȑnqxqwщgD?(K0â36Zr Yq Uʿb5jzT(>QRY(rRk˖DB -+AYDαW`Q9Tl,fƩ\^a_r3+#c#pOefNCwWgf6'*Ű-J[=a2Xwqz@nQp,)bJmuVjrH/|6T}Nw}}^}nLmb:l\GmJ *=2e|uߴ 5OTKSLk`b;00Jsy^,-^ 3c(ˁNx:.]FFƚ+#c#B'\H!N hWwNq*D֌lh)ibk;3>&?38.ga0&XK᪑XEҥ>N<3w NOgrm$YQ0;H5lU!TsU5?zF3~+B'R' q.6rvPm#fp* L,e8q!;Ϯ r?Œ@&XA>&+0%%Kh/U7Bi v3^uxp݋?:4ꈂE0s4ȤԟֵFH$$VO9Ԍˌj5da o<}(dѦEJ \/Y , vyi,jT D"BwsTƒL9 f,+!;K%gdd`edlc VM+JQ ڤJ{lۨX88={꛼HL$}eNmV?ZJ`ZCm%z&20mDwWO zH~WgkמSwLcWbW;q?~Qc8u_`D8*M fs`UN.F53q@`q9q5c&_<3c 8ƃ ]ٶEGW9  K3سc/]A%XB>ʫ _dӪvkt$hs~N+WyueX4."w_Gr`ɥ±h{ko?|?|%HK+ݵCI{1.{Ÿqqe?}Ɨ_[s{ a GH1g~(.ZN,BU$,8ҨIbwШ_04{H>6 a&?ua붙:bb#TV,̣WμWHj1[S%M0ŋHPIS<}.B'.`%}.2V3X\G[ҌDND6ǴgnY¿ӷiofҵA^.L^#"CKe0zjZ˱dG}t *Gց͐p)nRE| {9f0]c_[$}g=k]׎ぎs0?t<5O]!60=B2qĞCБ@w D%XDTRp/! i`0VHA\ H pю@ VaA0#HN4-3I? T 'Lrw?y"C_3F" #>'ēb礌Q@7ߜ:gmyj~Wc.]8r s}p8rA>1¬Tdf8`ff-+[ XZ+*6J**6GI?ۦ mG׻k{֕RS2<Azn>O W`Y$ JN ,3W>lFb}cmS3"|cko  DfW,)p?%^B6>Çq;"q9,OKw Okwq_"^_āb%؊ #"̲Y̌98D0t Xt;;vUUQATUQ :(HV,AQ~& cBV,F谕|$7 A/](/W>EgV"Qi[074# 4m>cj=Vt#?#|yEW :R+/bct;qݺ`?wǰ{/-8ƁOW`%;gܳ /{.݁!.w.wǥm,/pS8ͣWjD:"yΩ"`p^}=rXQQ~TUQI$;4hNK?C,ȼUCSj,%X+eJH֎WӻQt,ZYLsoCC/~- #g'LxF(u Dhdcf22#(Hu'NYX 'HV{:{/mL }`έ-< ±Ëc8|~s \@#eE"BB~$j]U_$kdW6e`JiH_g3hl4Jw>s$-WƑ<Bl1ݗnǶضcܙ6/{N]'q8ul8<)w`t |Gۺ:b׽!U LfU&X%]Po<ꊸ >)XQ ܍k0RIqpqPu1# c3ye8Ź v\xP[Ѽ=\^d#+Ғ!0b8G&Mѭ TwBڟ"1\zi/|>ޛ{!EהS8~?ݖ 8h.l'.b]]{sغ}[Q߹'=8|2ۿGќߦ-aE رs߼؆OE#`UTC77YKM7]݇-syٓ%v` I%AX(vew\j6G}w=XfAYĨQSb40Akl&:IU&۞FG5yN,?m8`WĪvVS꺓'zξTN_Q,[y Vʏ߆߻ B_MXA1;=';/=wo΋`E 6رg;ޞ#w?/~3{EEjTUQqqoR!(#>%9"1Y[TC!~w>h7,E|ŕ?ާJKDp4 K% y/ A#B^N`jZopf3}獿GA6 1JA.uq vN`AsdiD#Ȋ'RFJQŲ둬X { CpJ䑮 qVn;?py8o,v+v;RցO Fx8\݅K( 'U-b ITbbZ8kDw'NT(Zf%W}G[7rՅIx@`7H@N)qk:ӂá3QJצ0%$'$)9?9b HY ?}ͦA&Ig\ GawWE &p69F]_pfn#17Q [x?؇]G *xpk_F&ȎJBuvTCKu>? eN@2^ !Vh=t 3CtS.Meh{uly~0(8񜈴˰;L+GeŽ)J:sgTBjx:ݱnkُ'YP_LZ@7ֿ ǘeܰ}4JIhlqpD8yv0caL&/SZqjeC0tKˌkսNS^J?X=)B}v 8p'ޮpRѴhVEEŹAU**$|Oܹ CXZ$G]Ý$SuIV@*VۘSEX߉ǔ`%s4r $S*L }BDF Pt/C$~ BhlM"EhyS0JQd(:.X?#rt7ԬX:?/'n^F8B@۶ho ̳I7UUTT`UT<+=H>Nb`!ЛdHimWcS`$m1ATxJ{td14'*wLXi/|V*uJz|J|1c33 sh]ơ`5^n|+* VEC譊7s,v@J\4ix(kSˎ ͭb?xD8l({lc|3 &jcH*iQ5`˹$a31 E?!񔲩"cZnH3X@EA"Ʉ1fHO`1 Y_!Q\@Жl fk߷_$?q6Hc\Ɖ MXMsz**6Z"xH7yf-K`婨ĔQ&<{+6ӹǎ@&!j{嵢('N¡s6 fʥm0pM*%vl",VpDQY.Nb =RБ\ TJp=:ybMⲑ2ᙰuc- [ȳvFXQQ IDAT, pc2칢EEYI^Df_xO%m1$OxBm`4:`ei08 %_ - "a0 ':P #B BGL!ҟuϩScňXmPƁy- :g5 8ѴTJHtvxJfhhq6rK'J,0Hx ʣywp/W8u"MמV8UQ "Q{8{{L5Y}RlCAHmO7L,[.cQvy*XmٶŌsZp4I\.!i$?u uڤ㈄|846)ITb4m 5ȫ*&W+7)nݦ$+UDtM]\{bs VECQ(L AHJ X<U6& e=iTyYe 4bpI dWu)쫂`E8Hޤ~@At!`}Z!h¼`OoIs"Ǐ"++p!1Xii\q8<&.c"4L*q+-Z|9+z/6`TxC6E<*Y<ɽ4TTl Uxqn#YB.5\Ye7d)V:M=<-hO;^y?Drسs)!. g*-`f0@Öx_/lh/kz_cGo @X^FXYEKrI&w)~MqMQ0(frjsz3WM. [vZC?*X0`@Տ-SHH̫DiPwN[*sz$8Xe57ߖ p #8uIH#PLyIzR+3c )lFxbh- ԋ5T@&OF'OxJ,IQCK%O uf|T[֓Cax7lى-@5 ר-Q9C%X<452hME5*;F8Ka&`Lnc9-q1Xฑ,- Rsw5FtAoe0/ - F̦&wXE-3ACJY -ێLBޮܺ`s-okD0u=r5.|]1c,F J[!" pjyeR%"8E=WAP {e`f| z!i;,#3KYͱONf~~#8g%"7 zx0y-C5HG~qTOׂ>ay5jSgqD'FĠ{eXvWP5 Dh"pv7}W]b}I&Υ5g!?wm7+**6J**6I* 0%Tf$* *[`qQrQ+#iT~|?Ȋehf"#l%f889 7'* >FH"mhЅȎ z^mKv;Ag{F"f:%)>mJ':[Й.86Q; P {-;ߔ$wVVEFP VEf!hxBKPޭJ!N0!(ŠQ&#cg8hm60BPb( 8Ԁ?4Vەrn8ALʶO{Mנ|D>DCT@=`qׅ*7F|)4PV"O1yX1ikܟͨW͇gpp<^U@@ދ WTT<bP*hG`Q=RLBe}o( #j$Ė2}.THUO};D)U"f|H3!ybQ̻e?G^NWBwQ A'.k=a|&p26gf1( G+qP&MN(E 1}G;|y)?*˒? e=.ZS7G@, le X:5k_%* P~ɘ.`0؂u pyA R;ߜKE*Y2 Hb#V2q_@IU%v% !@GlBGbD0:l=)[J\AG Uꕝ >=TRHVO+>id/ͷ6߹?'|o,ְC`K ,a[ l\_ə#Z 犊 #x#^ٮp0ȯ;qLsw>t~سa$BD{1E% CO*ރ?x04\hN&LÜۙ˜۶/$rV^x˧TO 2ZN*WɿTtJ$^E1oƕ1<>-4WA"C@xi\OT*** TUQѯ}yÙ8n@J'"gde6 i0@n*D9l#Zv=?'x> x jZd Ha/L!: Nh"|mO'5.XWMUJ$h1*hl"$AəerчU:˳/}g#Q2-d*͆jY>VSQyTUQ!/`0&Ol7H ({n4f8 Gm#xcsny/Ӹiq ,3 ,իO/n軲lݸ+֞YS~vֽ8PIT\|qw:=Hu_r̴jfW4HDHc&1 (*8 oMq #,$4&Jcf !0?UI\M'Y_~cƐHP5)ҥi\*YDKV~ n02Esz.khzG&\LM>&2)#Aa?;|WLaGB{\=&BCp8͌驨}č?̣ޏOKI&U\G,'rU$[џb~;@Sõ%tK_w+/MD J5sE^M' [J V$P(H$Ǩ^E.~oG>@|VE,r!A|n*~7vl6^=XG%X너c#x?F׍z*/a"HfM}"Q<4L+U_H>3;ަ^; F0p:yt03Fc`M=%Lc L `^"U|Sg#:F]LF'dox)+_9!Yu-,i fÚ$WUc )I*1"|kz#"1RgYU봦fQ=+iН駧`UTl`UT< Dح^M.%Xi"] =\T꺢&߸  Dw:UWC h1f[ײKpKg(' |-]KKpMY9&LIg}]c$ k)Qt quqAuNnۿSTy֙\93r, `UT=1q7RWqr,MԥG"+ z4Ʊc#,.D4TIzqNr,FfAfBLLJ.v^-"Υ-z * YEPO:\V5BPtM` ɢ -{U1%?csU(~覐cob]smTEū5nNJBDr #7}ڿ^ͻB}* 11gBjLUlWTf9R  :e[e;xsՇD'HB)"$D<\ߎ9KGe-G{"Lpzqxѻʝwڟ<*XhH.Iޫ5Ly:9BKK++9)@!M/to82? v>V +yh56nb$Y6FLLR"D%fFuKhffH~ AKh'g?~ÀDsG+S=Jnd \ sM`;'AGP]HR+U˫e@:o|QCI-|ܟPQyTUQqDbj;A ṙDkia4B"Wఴ P_j`^oVz4[)vYS5g%>{tF:f,IHխI#ePȶǹfIHeȃҚiXOqOnC/"Y;?n>+M"-\ŲH;0ֈ.f"P1>Qeh`GI"̾ޥDE?WE#`UT ;?ﻤ^Eu{UD'O2sD N8%h"2F,:p`]OaPA9( IDATcgNǖ8שּׂ A3A!+eU3G:;bJ[YŚl4}:Ώ~IJP)RxYN9{.y4^|Z $ 1FZ AϱW˼q 3D$KPHUB^w/|ioꨜͣ !!vraWLb8zhۀ hA H\DE,(<l*s!`#Lct6[yP+PRT$Hx -P67 yDw8xWN-NBȚXiɵU$RPzEDXQJ,E,SQ)rEvC,fK^c[ttR^ivҰq`w, 'bDȢ`OyџrZt0c{ehG >L=e3e(vD~:fnΔ,#b>܈hɏ,lU=F"y2PQ T(2BjUT&nŖieRǸDFϥn:v8"_kGIj1pNb]K\.L%Hvf IVgH5Drs>vLkI5yН:U<=3Z"@R˲&ʆ粥⑋`UTNB˂ yr=֫UDTϣ/<FK hЙJ54 HiRgIh93%X^/L!lÕ} )%ZBFfHKhgfMs }G4;a=YL4lZU>18QY2#{CYŊu:70lj80kً/=nʼnOW9>f)٢4_qKqj#*B} +ƈċ?xӃu;TUQqMV50IR&RepZ)p5r_xeUJ_U$?Ρe-^g5E.ӧg&v ϸ\i4֕,=#]jUH< pW?YF䣷 ] t#1k;[VI(ǖ#,,#Cf yE DXQ"Ƽ+WY;=Bp` ֑9!tQQ/1F>aжs'*JAHWȃmX b|UZ. ;PF1(s1!l*Xe4x^|}5aq\PSf%^CX0,|3iw7nzU**UX&)L8VybFIժXi kYPիEċWʔv&,@y:‡3R"c8)X̸"ZJ +!s)K8e*H!3[?!Yy:&K"3,]YIqPE@ jR>k9bbJDk,U|Mt NReYK2Ɲn㑒O1PvXB.=g$)fTŬ8nE/iGZGdumcǠo+&OvM3/V >`HI*G#l `≮&˂eX`,؊DXQNxMiS$zއ_%3ǜK 9pڃHDyFdAA2*cD;"h0IAAZ5%SUl֕Kh0g$XH^gs껂uQ4@"#&0a7B'!EDKZ!hkZi b܀_Wߪ?Dآ}p?I&q"4jC׊t DH 䟂`y̴C4 D4٘2TT|;+j?U_jB dJ U&ZA T!f%1 S&UI$A}9>,L^re\Ӻ(Hb˄HX+ zgd$K$`i($싎$mw{Y4ImMD@Iif)L@Pu -tFvA.[*I%@R533k\ ?}K#8bEU 6/~ '<SӺ=0#@Ͼ9VΞpjS?0gsCl?t2x}**QMg*c-2+2hHI5D}U#1/a<^ht 'N{p[%+L,|Zo]j1faFK@؜~h_fvD?0W Ӟibxx*W|c#YX>/a/#rK43&F΢ifYd*\4Db%p;OITUQ\WY'tU.A .YxIUG8q ⫴4t1@D<ʦZپ9 L]YZ{JE4pW31U0밢Ltk@٭=7Oj;mn<gdߺl7d#`'.`x^sGH]Dz3ʏOvNS%2fft$+YE+dU=D:x?¶[ q&@}ʽJ$H 甼Ή[fqTKl:gčWl=䓇quc&\c;c8Teb'Rl0jv033\ JڶdUOV#57 p?|_/n 崆sI#]'k`u"BZP"|D:s)&`BVYWuX6ltKb|8q?M1'JEg(a~򼼡Gry6 f`*h|>h1 H$k0Ȟ}]WTU^~>37K#$\p/y[R2,:ڨ8gG tADl, YEElu@  X0$NKǤNʤT+;\(&ˊ81YEVW% ɕ$նXEDU "ŗ{6zZ**mQ VEݗ_ @լgvϼǟ~3F+F16?p祻ֿҘNvx8[8b 9!Bˀ~NfEh-mő#қvjxn6W>wOXьW̝el4GܭRJkDH\~gf*sxD 0v_~%CJ0is/4 FRr9$gGwchh.tX9~\Sc֕%t.سS7a 9b3"(b)ʔ1F̀0۶9cu?}̷/"E O4>r:W T݄խib\WCfS{]E/V|/tTbU؍ZSPD,ʃq썔>,~VStzPԄrǶi໱BϨب w[?>SK̄k&4arUfG,/"si15NSDxsE8ybBDpȹ-׀0>pP%A95 SA9JHEF"pș) iAgm[e?YL LmmWl)i 0~_Sg_J!^h-=?4+v^g]B}ZѶZ)J@D&G *xzu.ݗw}yEV.agM-+rҀЄ@p3Mawx2W宮*] fhɀe,!4Kyxވsv8q}/3_(qƍ^e\{ 5hqQWAP 3KWU)IUnT!KP p_,72AG4qۂHsԜv$yOn@5>ۮE?zA>gGg#T0lQRl̜Ip;R48`q1`qC1$7Q肂 *(8hP'l a #]A *(UEs""HWLjp$8f<&R.T]: 1#v |`yĕ~!9XFLA1'!l*UJ9PBϝ_Wܮ&x #lطɟOKJ@.(vg)z緿*hiO{i8|Q]OAU{*B 1IVZE/=}/pQs,"=JU{Z4M={0pcch-)W6beqB NDSr,HM+V w $6AҠm.! D(`GJTJ^ Zz$#{ž=#;cL&NMuJ A1 4@tlP_O}s ̐3q`$хzo`fM@? :m6:Gp¸?s"ol_{%/)M;swjۘcJ!l"ܖ=",xNfy+'i3@l@,|&h[JIuM|)VRT* si UPp 1 :hWnvK(Xe{ X9*C򠦻weA?gȓ)fAIy-#:+n^F};9D!A[8y:5{X;ePoC9sN 7n2%x7?ۙ?XUbkCF9ϭc]R_ ^.T S-(8PJg$+@ʤ%B1UZLeEO7/++`A̩L9WU*<:7U'ߤ~]O7m'T̨Q9kǨb89}vMl;|t 7n`oz|ʢb/>jfLd1mꁨen_m;9裂{E*(8Ջ2E},GJ_~;]g* "5;{_F4Sl!~:%UPp ZVl=VȢX$~&T YlĠ dp$EWڍ/n؀-JJWk%Vc,pG,C0MMLqOT7 MwN1 T1c|*"lG{6uԬF=62/m8 YS0=ofOM1aYޣ QSR=4O /$AWF ESDSw3mLe"/  /A#"8f3ƾgg%DUڦEŪ^1.5tbN} (""piya53vy [0ٻK-yx|^%7LV0Z_jիؗPKA<^p3]_X+DL3gOLӣɲ21٨A%1t 5ٗD_!`uAp}h/ fwz7#T5 FF ]e{1 Jyo{8f5 X;bƮ;LP%+d$k#}6,XhQ#"Η3f`*gAB N,`Rz(T"Yqdʀmz5Q!1XDAӏ8z}{NBmFPZ&DH 41$|ӦD()Xz>l a8LĊG#jđd'm݁] ]ҽ䤪3R#Z,:4"s QVA+# C\:#*C|FFζƏ ?9˻8σ!FpW/G`ʉ@&/`xQ $Xl[57Z Kپbi$68f C36R{4̋vw-FK}VDdq!!0j W;XLǚ%L@43QA޳+[BHp߾}lӦD*q6?$~8n/R, @f-.uWtN(Ljx5dIRvZlKSAx %YO~s|",(8 A_p>?~w-nr$QAOD&FhqD0p+ W @NjhHDlb\ys*H>, DɻE7{xږ-͘ޒ0ܸ=;k>_Fj1ĩ ˔G@QVA)FT()Z'dE_M˗K ;ڄ8ISD=XqtIDmt5|F =8fQVU gyzd형DPBF?8 s=  n8Ķ5ktx6?N}y`n9 um ~sOih)i%@ģm[kS ?:<AoNnrAA^ xo &/u\ X;$+ǶfI 56*C9FmxBm_E}6M"w6v{q jZ[;w<?F%7dCM淜F'FBT?+yezw@KFk;}Ti޿0y89[lB]cq8N0_תs.!"4?kуE7`>tC ЌQ#ZL|}I֑Y(((X`rbՎuX5 n,0_`JV-EYڳfI9ͷ|e:)pS@!/#T mztT?<30 B}Q\U1 s8f<5u C-x#g s>uN5gދ睏}=[MW!TdžB N&O_$#[.q[<=HVdžQaHG  x͏966L`ǽwWuNaEcgo{}XSטxƹ9x @##>zmxj{ؾlUo8 M{Cˢx NHVev2A;u_w&oNȑ#MB_ό|!kۢAߠm`Vu̓pп #{- ʊ8[?n[!>}*fï~l܈lǦyܵ{76/%asraS?;o=MPj+G!X)lyIY I+$*-˙έp&r͕casxWEn=pT55w9߽ ,= <OT =0L‰xڃhGEtxg?=Ymk`6c˚5+j%E8\p~6%ϪxQVAiuHb![Iڑ (Il,g2i+6+f<[S{NH-l۞i[W؁6l_:]׬IDd2Dzn5h+ NUPpLD][ԑdId.']]Ă%m}CXjR-@!s̸,!VH"=u eS[g]nv|) *(80ElfRs\Jmh xD fo둫Hrϕj9/4zڵz~e&tHL|\Q1rԙ\W ]6,J 與UёUT>Dv-Is?VbzP;m߾x_+ "aAB NRa tNGg$3T,K~|X7o17O,?M\MX-gv8SxtKoqmk:_68AmaIq/(XUPp 'j4  #9dփ>rNsM"ZYһy鸆잛#^qke"֡r|/<5BuM N&c?V`"zrB @?rձ,@W('f ?Bg5*V8a2s$bqNf.1`ۺسx3>y{UGxۖB NDQ2{zDVD"`W> @8U";#SQ"gY W06IRb_1*fT]ЩWT|'/txlzU3R™c͘RJFf݇ׯGŌɺl={9̹ WX]h1 *(8EiRNU5S"KM # gp'Gj&R@yjta+j|aW0W՘*<nZAAICі N!⃙A)A%'Rx45gH@@`;B/Ӷ:ي+%NHVZ u9{K3݇&76p3 _Áy=VAj(X V\Ř^re ʃQ my!T^]DrUzzj%S#X.b*;•ozz5悂E*(8 fk({ɕT;}+D& 'AJb QRE,UshpexSw G98P.dg|zx VE*(8EXtKrश0j[ga~So}} \7.T }kZ)XS3 3|]c1_U*l{}tԟ)((8>$C=Ǡ'Qs Ď{CedŹ,ZuؙA0^ew$WӔ ])}K,\9PuLʕsX U%lחG}%`uQVAIyõ9T  nČ]~yd:xs.pI'2@tX<=[* +%?_vEGk%Ȋ?ÞKO4;7?>bRgNr&:]fС'!vU?w1aU@q`|6d_vХ#|?sz!$}K#"H4/s{WSPPp|(%‚U'0URkTUf:A4I*rQB,XcUzK]\u!F 21_;9R^@|v,w]Mko%W2mc\MJoߛ)_ev1@6'*![^*9XB xڤ/Yw]3P:9 `@*} \s+ `^)`A`MxLuʩp\apU ve~y[w.GKb$JT# Vޛ06bՈ`G<~?L#&8:G IDATo-fs1*0glo](o9GFIf2+'$^k^c:RVXeo[>0C@@!@ը'ex Y=(PP(ޫH2ul1{SHANL p %}C@l|~yo~pL$)[]$Re. Dq+G|z"|~_a׼|'mO5LG]̈,P֓ QJ"|ޭt=(GI"x I ~t@0rxɩ# ۷ *(8tfumB@+|"OJ|R("j!2"|k-(;U0|Xw~#QvHAHiByDWwqQ[PLꓩHS(Gq*A^JByo<Ja+In[zޭ|r$kZـ?TV?+5U"@0öEc,Fr5BGŃUP*((wTX*UޭZ\PG],)bF#o |լG4yӭiY5IIP)VB*ŧxf+_ Z\MБvcjOD}$/!!zy/< zE06~_K^'ڪT15Z TkpMLB7:>YAAQLǂ#]i-,- #ZLj޷1Di􀓉Ǿ}F+!P,%#jq}#o7ٿ)K8:|tM )$t7-."<8VV%%+ "PG\VCґyW, (>9&rU}1vf8"͹" k$&ưrpDpŬa1,FYFVAj(XGkC%L])X-jy߶b(`qѣḭ-%%3%GGq=Y= #Vw~Ov,id6SG6x%<-V1I_x᚟E)b@Rcq4EW Cim^΋'|*xk5L|l⁗85=fFZ EG)8 [Єv#[D:AZf0czO `pzAX Xh N$ *(8J[Hlma4=C [09@ީZl{[;0 =F#m-d( 9VRm &"sMU^rS.eQ78OdH^^hzDp{ _ARCW]n*$ҥxE 4\f<(T9۾e3ԯG^K!aĢ{~$Hٽ Y{8b&e€,&xT"p ` EA@!X}w zB jB7"D LD+8Cw}ءifX\ -zqjJ5-tbllGd_Jb;a~R/#$l#,zTƒVgq /}HV[{"rq4EKHsD蠕(yb<ŲM@LB|,HrA&Wa=45 a+6ZQ}qQ NJ185ZΛk 1x5i}o[Тi3c3ƾ#80,.4 ڶAxB o}uTby;7}s^sNk!w|M!$=a+!yJʎѯf, EA=؎-f8XЎ>8Wy3;ntaF+v/gX#gZZݺtj} K9<~_Ǧ>YKm{S&Gq=}NG5t , V`+2P|Pδ ̉ #]M3A6Q VU-A[Uk-!3Ljh(E騽%DD)Ss@oj|I!`Lhv4.aD-Ez+41JND+iD5(Rb %%`s+ ks %IʈPQg9b@+y%D,!/^$]'`+գoں%5SVcDI筟  vUk$U} ߶~b;1rT?R<dY%kq%n0 IkFhFA{ۥ D꾧f$ LDT$gJv!B dM@'b9>;g&-U;mLb/2{*XXIWE9XF/g1"(} VŃUPp\<*[wF =ЉI8{-5uD!K>+xqеQW#;tٲ36 ,l# yx~C5vs|p?Ҙ4eoJwdxY3ZD=70%<*w%}On]j>zr%KU`)Pc\r ZCcVlX€B Fe툂#X ,K(A[f| .()*ZBFɽ`PVA`JA$+BB@@ss ^U 3ߖ7%058#WޖCG8dIU% b]zF.b܍]> Џp%6uvoy.(p:ҩI; MĞ``Fx%h$+ϿR;۱wx o-}Y䋴u'k!(b; -Y E_8 厱ٮѰ\  F|`xfTA3G!X}S}$Iզ<&OjedFD i N8W! p 8>Y~۱+f\>MTZTܴ10?$e|nYɸ>޷'?t ~ґnK%FuKŴv(˯@)|F/yRjWjЕMW1ڂE|KP0XoN;ah ʚU f0Ψ43k\JB VI^CI+H"UFsAH] ZJU"^nU=c,QIB@0Ƹ 7c ̮/R?)1^%),'LŊGSvGJ Ot,]LYz%33p}{oC`yϸ+}׷} X"Ȕ,63|L|*B*:8+-j;%ठ /WZ+#6uؼIvoy?÷cĦ1ƓeOqSAC8x.i@OfO-Z7haR L4kCMsC,8jIJMMA@뛤Vތ3,D)VVS U\Oa[q/!~׬ " :o?5gبCf|݉,'K]UhwŃUP( VA c}QGɰ}̡xB̈a A`v`RaM Mp:ǫ?=A0 Ay @#D0*PTlg !}$x#-jS]\m*ɔ̛l0/&1\C{VBn*-hMWe1 eͮ=c ֒H'jJDD /a!!DRfIGīed0U2^k?~n7׹,EQ ?W$PdDwJUYMRm;ҹiGhv ܙ. 4D_6hR)W NǸfUyKEOCT t ^AwRP7N U FUlSˑy-]p,zŜTt9SئJUŲxVE$9%(cC!XǁX*&Y9 Soլ.- QFF5M3dsfg5U#SH \qع83Ue=(MoJ8O&1@U_5̈V, 1bvGO_r[&J rR $->SbQy4KC } :VA*߼'?Vu:TSZxpzP-&DQPM-λhV[Eh[pqfjn^paؿ. ֣b%uU!4 *"HUi>|clÁ{Ǩm;s}nf> guwQ]d#"'" L ˘N7'$Ϭ2WL`={tt&^1K}ZZ A'K:"1K\|{nHV"={ߌݚ[ ti'[@1suU!ӮH?;U^(QbE`DΡ A&V5 xں+ASj/6&ɜn$b7$r%#OચI]]7MڞfY-)F6J2s D!E3zoG̩L"0@!'Sp f1oss\<|c9G ^k?~FA6 *(8Ah' ~?KiBTT("³})ZmF,}=+eX%Tm+rA07uVD ܅+֭kCA KoB0mwYJ|~2q? vjTNdgWF!t/<Ҳ,#lH*i_ ,k9f;F⫯V—LX8Bϛ**x *(8Eb| I)cv8w2<ʹK@zXvO5>" Qnk@1DD2}>+݇#! ^,'^?>Ό: gjJy7o}z9 忛Ȉ/\%J?<8C=Zɒ6J'nH˙ cf@z Qs9E٧`Tժ\, X\$roWd)߭$bb1Ϥ?EW{]^p n1Lc[iz݄ޜDpc M03 w?4 g/:sU|B$Α8vP_K#3{7@zWO\JץP|Zzv =qbJW-+˞ƧGRP^e4[ ڽ?g@aiDX\T l[6ܱkRQzC%Xۍ9%gTiW\Dth/&D+(Q)y~B'M)WcA&]#`Q3YgXp뒧1PR(g4Eff2 zG 97Dfrg,r 4ʁmQ٠yXPMKɕ>ؚ݇0d2ٳcln@" bd#!]`UTl38*9|N5 ̀\"}0h֔j̴Bŝx{~x&hHO(A7q-\AF5v (^fw"D,smD$u<\_b^-ws3Ӟ7?{4*AӠ)̀K0Wy]S5]'"86*G-q\FcL&s&JɘѫH%)P VEv~P$j*fEEήxyI%l47%yY.\f:Bu**Wa֐Q#em_ S^މK "&gΫܙYpn ˇ pi@^O E R 9z ۆڋ(.5ӡpIX芕?)h!& `DNWT̨b@1;D[ MiZ#Ids%{}#yD{Kl5;?6d^Å)ZW^ FĆDiSbdf“/jGZIliE0õ[ipj_-GsWT3\+u2U>j,%WϏ4b*ic"mdbܹYTUQhm& nBY~@gW̻S GHQ >x @\\L'5ց(N/>/?:1n+f,)&'()ʮ> z<_71h4xp`k~3J־/%7S.%*qRtfjzJU_M&N`UT&!fխoxiRH6ޱ*3B)nRޟ5n{}o!O[PIA$fr''\yXu:LZO{;3I/hqFC.$fxmaO*D F^ 0]mpJNFeE#skM`Suc8ƼBfE͂J**v ODIVFB1b$qi&(oEb}?{|L)"Ww7: {"S`;#݈H<kJUEݞ_~橢Ky݇H\ܻ_{!(?Kv-?r8qLi~v'Ti݆-Fucx z **^רbp7bc)T,%Gb o6 %d* K+*҉IA0&+0Ҩ=UĢ<<0IOX'<k:̏ hJrijRW#pesk\?uL-~ } o< Ϋ6Oys*[@Ӹknkh6*%X sgbjVEE%X;aJ*D6E+iYk榎CL3nN~L<PѭʉOφzIIݏډ6^.(ٟʝ/BWu^Vpp K>zm;D #7 Zpӂ޲̹ς&Ƀ twoxy᪷_P'UZk-Ρ1\ `y!LqRq A5d7cxa!][.\~FtWxUTHn 5h Lv Fg6TOhQR y@~nGIeX Y m@U8lwż ϯ_|2E`nA–_l5`Y~ŷA$bW߭pSj/Rf<swt{ixťBp.N)QmAdf~8Ccs**n6TUQo޿65aQ9< :߲?3#ˋc1bUD``ˑ+`R5 R|N Y݄Ѽ+hl{y ?v2%#la: ` ڍ#=h( 삞wz1B}ߧd#_ku~>DbrwjՀhfht6x`UTF`{2"obZYRy0vY10 λ/{l/){C6 1R-PQ #&3&",n1SJ<"{oD[>=ϠARsJn_<^!9A0 w:cw%1):l=xqI{Zɇ!ENf~Ё>ɚ'ay\͊(BxeBWoF|<}c8O"Id56U-ޖ$XW.4p4:Kڔ9^S}gSy0X-64h}UeM#xH<'K2Y{mz72ɽ::˅KB%i JpݗeoyUDˉf_4WpۭP VEuFש 6ÝdpWHH@ߏw|˖j0]ϝKH gD*kRy,M#W 5[>(FLAmmXX pPDrAQ`IayeKC"$QSX2+Jʉ߁ѺRׁb%uD6hh?W`UTD )FR)b)"<ί~9S#I)93Ov(OSibee0wܙ?'w IDATD*M4D p`CD `S"s"Aۨ5h áv)G1+v1ʵ-}mAv%[Ko*d$0Xb `\,[w"Oчf<Xh^c"Yٞ cJ1 6ZuG~_QKkVJ+I:2 BҨ( J}AU{%ɬW!u>"Cbp@:F\HXI@1mƈ7H9X"\C[)'?3G$v:Jϝ|+&zuaݛ&c4Hɮf9*LE.uZ""6rVgޭ "67#6GqVcd>Wo=қ?\m"U"cʡs`{b "hHg=B]IS5={QCTiXޜ{<׎J**v hZ ;-~n5%X4-ZyĄc&0BTEK"_} =wc bk*~T6)cNz|~ebZ !X>/!\8Q,@ˉH&W._KH"PN#K a5Xe2e2h)tUvTUQqw/MV ,cT iPj2aqR}$Kz¤9Q"?"B AXǻϚ I^.ʍ(b TB ɤh`2B014>H˖}ҧ[Vj-L v5Gs̜ \R\\`ŭVTUQ78-dJSB JkUgbPu#C(*1"cc(kjEHك4áՅ7Ө|L2T61LQtHs1%:$Żf~kSyؼWe`&RYh9rD-\ӭ]ۏJ**vBFFG;[!B t؍ZhDFs sjYP„AW#@Aт16oYw]4%rv\tf$@M@F.r"^0 fz>\)Q&fG 695-pt<#ȿ51 ]%Xێ5(ib7IrTcis sz0 ﯙJ{d/ض` 3L43bPvϻ|>6ǨP#E]B ę31 "m@l I2!, aH%: {׾oKc*iM2 U&Unk xvQ!aPuEŎ]Й:eKgNQ34S l? <Aځ @" FCƱ2LfX'](yS$804Ejx P򒉕4Dk*T^K(a B]8A}z(N?dƇF)56 `T@j|Q \Nۋc**nRr$pO;< , =y~BOq9h}J`PtJ:{zOy>y)N?zVܫe*VZ ~ V2cPRucn;^=t?:/G***vUfmk4@ MŵIVbX:vd+Y`r*/ AXXӼ@ϻRʎAf<^ÕЭMW0,&vmkp,A=XGpU+jMh-E@ ȾN`b)$ҡiXXPh;W+*nFTUQq%ޝ&ޞH%ѡt{aK$($X`dMl(sP$EHTb4G|憫de*BD fvYP15T-R E`۠Zkf 7eU}M J`c׎T8Lw-F؋hϽq[B0C:+**U/ls_7]8 3ьɻN?J`yZ&l(CEY~K'߻hS%0}4=?4߉SXd48Ie? :d;cqɕceg F^D;Iږ)f1뚴NI س:?u;=`&D%X70dcAZ9#T%_=2J#<}YbZoS+S؉ Wq/Z_nJǛi\.GD72z!øG|:}p }mG3 ٹYk9"Ȟ+:E-VTDxٗu<+F^F+˃6FȆ/HQY<]hjQ8GHȶ~}H2l-kѥV&$Rf?ҡ`wB$FD R-,B #Z]v{9tWa$ :q,F~\e9X;`UTL&W% [l4Ӑ,-q_r'V/\qI%=,b0sܽ;9|TL/{ ~:Yg~dFJ]XhTPyY#tcKp/KctH껺z?÷oD%DF0sKЭ'W;`UT:8\22"\q*Iϒ%Iv5멊=Xp6'dցGɎO=>~xZ ^F #] 뺍@j[W"ҐgUcԳ/i((2Ț\czm [ơx_5bP]`&fLDIBMBuaJEJ'5dR7fWÜ;F$;{RŸ0t= {Lմj }vsKo}ZL !tLFY2jҭ_3ێmG-0M۠ipXk[WEEA%X"*۹f^ɯ,T, L*PX28g*.S*i\8W_~G>-1UBԓ0D׍/c0x7}=kmTL«A۪jUbQ VE.+X@O) oMrr#J6E7JO[;%u U$*ЛaGjg!'5k2sXnb:;ndocyxty"7j9^Qs`iyw##C= Or@ ?VriRoWCFjXշ03a><ྟ[Wu}G'KVڇRB$&zD`fUõ#qߩtLwHU̚ZQ{P VE.@`1w9&3'ߕH),,F*FMD ʑ"/I-S%DHY"2Zs_-"Z@lLNn?p׆:t>s옖BĆ]۫I vTUQ ZN+݆I4:cob9LХD@̟e&=X%uA"4" |h9N< IkvGW**v *Ehרas?x\gg%;-itJP̺XN 1J:&<ˑ:]tuw.u 6m誶k^Q&]kj:Bi}YU"urcS_EG099ٶM(lzz<#e<4.`UT܌H?' w '*ȿUA ӄ,dOn{JkHх``2HEMJ**v^+{b }KUG X𸎥R+)"εmdr->ՃUQq @ <f>󯀘A1jՠQ;hsPVSĽX@`쇐nPˊ"1@!Y8ۅ'zgl{w.KxͨE%Xӻkfrw~>7C9QI2-f/RŒD3$+hF X0 A5,8I#DpU'WR2~ǎgEE `UT({f? xZxO'PwreS '.-ȕ^,1]2Ńl$ΫAID'?<0CwqGl=< 8w nsG5v)X A%XɃr'Ku)|# ƀ3O R `o'!"TDg?=RUFD8= UH,:|>Bbę'ߖsn{EE΢]r`NIm*L_1 W f"U%2 Jt+K+nVˆwm;g]-3y&f%/3d+u <;{"ޯk6KX5bgQ VE.-Qdp--c,Z⁃   d~\={A+{w`y&ĩcoEm=sSO='>OS܉*_9׫Pl;{T؝ZEōEXQQ@UO>b iG>D6\]b ƈ(.F(1 h}A"aq8Ӈ@%`^|>w pJj+S?9Ov`/H)D"·?a™'CwNJrs;jr Tb [w<>["+#gFڶŰm1hmAۂ5&ߍ݇'߃XŸ}2~+MO<餠@1a\yǠCב~B*jD?axjrx}*X%s<(Yi`"5f7oIg@Yܶc9(QER`o4>gH?U\?}ܖWW{dY ˫~4чzpZPF+*vU%M=vb$d  1B$s "s HTJLwE"(֝g?2RD,y3~tVHɖ70 /c*D"qハ kSQQb +=Y׭ B1A@#WQBm=n*"D|ӟ]leAW2g2MmDJN$LCyc*b , 4ht<@%X!\[@Xn&0p!s.SJĀ(bxϞL옛AKsJʁg`ܙB* b huZɴrh,$bP VEEŖ8vqxRKk= u`.F Xm33?p-3ڒ\%D@HasJ#tQ;Db@ؾRpkiJsqeQQQqeb`:ho}>9x"F~-o{͏oE 0| A!$"+N^M9r_L}ELZ?}Zd@X:x߱lwsWPgVT,jbU51YBV֊RqSh[^] `E `UTBh8g9Fc|D׋Qtc`Vz]Ň5,H֔M^C14TVEŎvVT\'v]-Zm7B%X;/gAhneiؾ a;PڤvVT*|c1ӳ9XyP4ӒBK1/@"[MmFqޡ6En0뙥Dhxվ2h IB^NRU)81Y3>Gm⺣AV7ڂ:qV?e,fm~_G& ɂx*+bmϿRxf!,wUbץmSwnT)a)8?Yo0$l0CpH $\5m&\}n!K1o~5 r+.g$1F!1|ϷVlk3 \KR\{ނ0N;@l7A"@Jqs+*v `UTlIuYHn"QB%w%)T CBV%W^&lRTD9xfq9{U*%Z,).e21ވ^ 0y  L&n""\*k3ҿCx44q>b 抯4TTT*6AdUQ 5$f#{,IIDÂp CSBP\%OVA.X@N|*?HpR#wݓ;pgmg"mSNJԥh`IPMX{:%17$bQlQvHU*X;J** LB 1"$fe"%W*Xx՛նٓ^sՑQn2᳋˸pLA5KNgr-h2l2{J]+#PVۤKs>jvg`y$iAׅˮ[QQP VE6@c cCPU"S璞KSL7"F V3%%XNI&,Z  Dp 7 hwb*=P=O %j@% ~_N)G[OXWQQmLw$rca`yz,a+}lXbTjͥ7oX*+&$F([4/7l RV"v 9x"Ct "J35pIUc**v`UTl:.KSz<E\X%BGW]!,E3MJeFŻd]0J% QGmk%H]QUekY[7ӿǖ9ʿd1nFU***J~36ޕPŤ`9 DZdam}(b<IɒFz wsܯbyv r\ٳWWH}&e*Uv_(_yHLX9aN\dۚ-gHpGՃUQSbǠl (.^"!- xK&X[밾a4Ǻ@)S+JDXJ*VHFMU,*U*ۧK, ƝVgqqwI5ۚlnz1<+.1}݅׎J** 1+%O]%^wJb@:\8ƅ r0GƒT,pLU8쯸̗Ankwޭ$գI PBb3--m٧c",,XL LtޛU+ \űU¹X=X;k**}LbDd#ӧ~ Z:`{k<`2#QQDA3 @~&Q.д_iI]`߃%o+Y =H,.Ƭ*E /Vƍ4'i,Uí!3R꿿m޺UvޖS*G/-:TTT6 VE @"%؆)ժ}- Np/q F 1tz^ՍG3ar8e`10C6N~/̿ZqIct-  h4F7j\u""XY=UTauTNEΣ*X"WMzD+F(KZ[SMNZh.a05BSS\Wǫ{}=a 03X„[S/XYXas2NPCh "DXQXFM8`* `(a֞Gu Ɍ=":h,ߘb@I Z gGEH$0D ƀ͍LC,& XFnDN[uwEx}8 `!DS"ϖ.0Lػ4&ɡII,"Z+ Yo8?U#G˗}IܑfŨ.[n@`UTrʻ[RN(6䙙AԃC,C^U}<iTrU$"{!Zwr?[qAFE@X5w^{lrΩe@%$a=X苊i J=++E/f2XC^`y]z** `UTl!R_^Y&Ժ?l){#WmUܐX1;QR.|lJ̢G> W`wObs?V 2/!}D/y[KGF 8X d݅f/KszCX$B&O޿C>Q"Z" oNJF.;&@%X[e2_NY'Ҽ**L5vU.eJ'`]9 ի+? Xyd5baYTUQ8 (Y:'`XbK7m]9$gs| >޾ Q5#WFK?\O|'4 BA&09ad]'6oi`s\)U; ))׾-5޻?5UQb V*֙\+˅õzGfHX@:!>}C;#24VϡdE,\A BO 'w`;>? dMDV c_{D̳|7_W/+*v`UTl1.>8YW.^G#D|¢{AYKnMD6{Oqm~qH?/?*W^=\"\uAɖ+UTj8-2z֬LB[^t pſ髂UQ3b ΃B+Gu5q{+A єv{Fpd zO3J8m?;g>3,z9N Diz"dAr0S_Xd%%}8 QmKA***v`UTl.=ys1FW/;6DnE2e$\:, &#ǔnOF#06,?1zZ}Afz{t)uHVA%OzrJ$/I.xoo\=WTl/*&Ra$@ W/DsS˴Q&J{oonV:^x3-{i=N.aU͸ؓlY$k7׎@}""0K@x>uϺb*F\d7R᫇lj\=+_DϒA~ [`=kSb4tcjCUT&\ӂ`CbgǤ9sm]xM3 L >ty0ܱS;s**>b1 YƔ0QiKGM[ ;QɊAKF}2*)]H˅.sa0{SVG0}qbԮ#x»5ppp'9o7pÑ{ 3{W⣋J**vd%B3"` a'mbASr5mnɋ7 Rtq>?}юG]([ =\}_XRmX 6Gx N%iJ}?ɁƂi8rh/**!\B|W3Rdjyrs$Q7KMn/6+(7`?JK$јjM]Q7<)yleh7^BF7-,W+>~.QJn J|{SU|KquΥw _d:>SQq[G,J\߁A C߶:~1V+"ZbZ"8G',tbBNj3>{hED{tJ}F;{qXPm`9LB/J#gAsI\m<*ps# +=gVGX7H7OYT]culj|lWΟ+%!3kR7`J%[PM zD=3ݒQEM;M*Ndbiif틸-=͊**_z@侴V&Acج2A7]N9L._ܭJJ%-+ ބ{•s~$C'07,G^} zB#%;{7H*qYna6Ꟑ1e$CpP @688.~m^QQA ǩEG!7XڷVp[3}4#\{}+w֓O'.+D ;t{?v8\a7r}&xet"kMakWU, F⤙X,>ؿ#8 iQ]zptkFXC,. J(tPn*=;$n;^2'(G;|]1X8ƏrmƑ'F ?%SO"IS$lRm"ZD4FgN!v_»mU**`UT65}M >VJ IDAT7QlsF1 WyW;m)*U6@Xl0ey8+ZUJo|9G˄@JdJ J*kMDŽ`$ h[}4s9U|CF UQ1pu(IS.? +<(_@#Ea]}ɦ?zϞ0-/~?.gYG:"N1{dDj 3]ssp5 %(=B 8   _5\ժݨ VEnF:~$W63H|D樄h p@7؛4gaߑcsUFpwuP[o^ZWjQW!MJD\k}f  6 ֈ0QVf]b1*er~3ht.,  ?[|*&#{czw0k9xwk9'{89l{ ;D+:@2knycFCs={+!VHCFjmQj6 XQ*d#|EEbyTTbs7KHY4X(Ye/;%ֱs?=<ϳe^shCx|~KXٝFkhr9%ZɝEcaУ;%2%!+VljU&\m#iDʗ`6Eʥ'?VQQ=XQIJqe +IT*0@nΟK:G)ڕ=m[Y&wl}GaiN&~2<5Tz pU\9 ~(?E  Sמfq;p3=z^j-#,0Xc:jPK%UQPNr uCr0g*8kGepWVs ;{}8}@[] aGikSxIJE,{XjruK'xKX<+3DM}EEUebTNlՏ7R}enDP @OpWlrgh.u5JV C'8gm t7 ^tdҙӸq\~;(|Pک^BR0y[i92l,5Nd&_9Tv `1<Lff` Vfkkmx/1꼕#ǘ,8-EG U(, ]N WÃ4k9+:{Gq'Rzԏl e̼:tFBNT96EaR^}0cD2Gdӓe[x,Ax]9hSʃHLa7?Sʑ8) ˂E{ՁCޔ)U:a>tiNVzvua`MwEG`UTv$: ˇy}"Wano]%MV>KF$%JLz'7R峧gqr N䥼H,KD14{co89ufH\xBQ ,+@&kZ[B#V!>6BߣJ}0VU'u7|w*e`ˠJyST Qxf51>'۷ߖH=Wdfkh̃Hq5P"I\/`hkڣ%1L(хK2a$I&`yuyr4dĊTY*IryE_:='WqO}z[O"iU`ީTuTL~UITմPln]󭨸P=X4 #s@( :޹D>m;+2r0tsH{x|Fdbiˈၵm{(żOk|493fN=b:/H,N;-r eU+~4]T$X9WÏa7Lu4ݬl1fJZ5>aq w㵊%Rodp9<]'/IWT VE.C+>kQ9=4$Q _8wlh0G-P qd%hQQ )XeKl|eeHZ>y;4̝?H/{*Dҡ1F V*YA|'ApσLkO -H<#c櫚G?R`0U,nQ VEnGY#,GvMkuH Pu|=Rre@H( u jk3IVQBu?ڷ"*Xw\]99hGBŃ2OtrZ ,8ڙz%g]@=XEgZiLFE*, O!Щ Z|aSw8XͿ*e(c7P.K%rd+,J1k fEґKiI2ҕnIBA Te/>h0Z>,TJc%VQReM"' I ^^GYJv˟\z2^U3=%Yqcs eF׬ JO;3F>+W9ߪPB\S^ڙ5TUQqa`)%Ry0%T&Eի\.Y^|T,fLC$]iaцC m9$#+%S|X|eƑt1A(,d*Ym/0 ӯ3!s&Sf:I1S*( r'q]ĮDJ]*1AMtY7trWTb!Xw srQ1F)6Q&7hOTߋv%;CWY*$mNŊDk̨H;mW7v]U*AэFt ~wkKBeި8j RSlȴ;M'˕kd3V6kUVr4-~S<񅥅VQQQ VEŮ,6K챏<,*|, & U f'56YgmfS+~, k?Y$."PH(ʃTw̘ dgL6ztSN̓vR#Wxce;!4ODZ6J/@{ fr4CT~cPTj躵׺bJ**v8(pnsFU'E8Hi8dX̴ /`ctuT%EeB_4%PO"Z{\0H1B }s$+4rƕ\ W}, F, v躉*%VWNΊŨbz&-no=L6^E{x_V,; C\A؆2-]I|p_TII)]KT^0ʼW݅˰h H[W豾c0t}HQ%W.'J9J@I=b,wr W?@F?V  X94R:t:5o\#_~`џSEEԠъ]9vG B,ETNuɥ*(" ,=׺zҶ y`r:41RiK{Dfi){ޝ;lUǀ @+f #ēHw K&܋a\$+N4TⅅGV ^}'z0;c8;OzrnD癄r5a:WTT\Ue`r,AF,m_9Тg*sy0fdeOd Cchg| VFout rZץ su =0T8*UAgarcmdң}iޟ*`!+eA1wlʣ#-6G;CĢwR+3G >: g; 5Ȟ:{>UU䷚L.WrUQq VEŝ12(r#|J.ұ9J**U⾢" 䊀w!%~} ҒvΝ e}U `b8 `!!5L;ûFtW\| e΍|:}!u_sY%{{'o N<]B:c???fF 8 D>@wߟF%X 9agf@$bW*%JTb"KZ;tokr+t:gChU%2bHOq q&cVXpk콖T9YPOՙ2$v+( >S6T#B&_.k'ǂ3qy6S2ty_:׵bNƌz:ͫrFP&T,&R)z`t"%E'<'*'hHM}ԍ̦zF~Ɉp3VRàL gH:09d-вc>K{bU+B|!} ?K* 8a8>0ǏcY%Yͱ3,*eј[AwQPQU(Q^`$!VK = jRRH 4ic1©Wp6gpZ"8SDrAd;QG>-Q.Hh2?E>w-I<\ Egy!ޝL)8(R+? L5ZEE͢;3DaIUj€Q("ѰLWa%H.LBa%Ur"8qΕ_`n -1\#,S.g2"D fA P?Mg Lg)sED`ReM@>~J**UQ(>lAP &*d]!{b7at@SZKsy#3WBzZ"-S.<T$U>ñY9z|D/HE bxB`yvL]WZϩ85*4(RRIv>%@49_QQǙ#,BxT]?gA~q"D!椪 ,p9#S!S',mE*ƒīϾh+5IVnZHHȯAd#|HTNĽG_gxpXHr&} 94RkDwFX$QMqw<-E-VT2F./Ӧv|=ަL [9E _PQͅ t"mH(z1^B H&?1;Ef8Yd`t\" ebJʳ%^K[7.gOcҥ9@*9f%bU|/.#s ߜ9 :CuZM[J**>d}<ΟZ{ol/v%}1F ƣ!>tp[zv[ /LJU)aeP̃ @$8 # ~`'1sc';E/$k$Y>bnLhld,?*+mJyxK),&eg"~!%`=UbPK~i?w k|^Bz=kiȁN"hI욗F 6!5a $KD`|IfoT"G)TCrڌ6+9GMR!b^yv"0;6+}A _T UEeQD:x:.R_! glk%+bPƩg_ś?%o#W|~@;b~M=Fh[r\`K\&,, ("tt" :"{6Ρq;9`; eO(KJR) R^ϙBuU:F\#!¡噋a<`] XbڇZ(@ IDATn;SQCx~iF:>GE$vtxᜳtLb;~TTƓB@r Bk_M{U@eg~AC =D%_)=w0< 9-MG+k@ʃH:C싅( ID3ep)djpkcu$޽4'0 㵊aM`˯%0Pg./oSKێ`UTD|yg*YPQ* G7hkqKioW~7 Ń+Np7+)^zfMB)u/=RԫZВꞽ D""5\xzRIoTU ЁCol\$)J+W-#(=dߟF̭UITb3?G {AG'UT.Dj)os,$TOh4¼ |sH%'Z ‚?a(A_YBʆD}EЈ7OS- *9լ۪<2># O="$%= 21DehYT<9\L qMRjDЕe!9˪VX;J**/=BԠ27Mv]-+zӟ[7GU d/:X{! JldcHrO$:<'$8ݴD}I^?tfh/ S<+œ+W0ڻox>FH=U9o8حB%Xۈ~^M빦 +#6[Ɋ la4fHVT >.SC[]{a@X\"T1^۴Eyۃky>p})24n:F=1\`J^,*}{AJקaȂRӱ'HଃuSQQqMTUQMx)|YŖX?~+9d||=g]ɈP:rt:%_[A%XbZ RJe$%*,3f4-igrŬJORIlolxA^#4Y<۟}D<itbJMA 8>Pgͺ$9frrלtaa˗1ڿ_O<*)Q$<{VXȴ*X;J**Q]h3UAYSi%4   ݐPC(lR^#XiDh@u`YCbY5*&2P"!.G)g5ɔ/Y(g>bK}9ϑL5 0t0{ '+囮Tk t#UNvʻƦIGjλgc:HLSBsfK~wtlQ*WY.O[4\˙I`g'g ¨Z8̴YfSLC VEN*X[TUΙY+83GKX!@TN|9:8{ fNݟˇP2WVWm+>[_ OEy)6w֏*`ec)VH⚊0ctx-?k-F&7EffKC%2X0p Irti&" R:#M'Y0a繺u3H<q>iM4$֏Hm;f*Kt`y:UMd}p=zQ\櫨-LK\,}% JQX fHrR'3*FFt`@>@iTOf$AP"q~,ʊU\1Wx`ʊH~HX;[d/-BDun4P#TQQ1J**v渁iYKJʃ ճVct]0bj:et̔2R53tN%SV\A UF9[=>,8#_E4 V|ku4"wzUb$%.J9\O =Q҆`UTɽb0kD fJDN& `8XXIjt:A9*'$JnDzl9*rz,Myu:PgR̾@VJ+}eXRG C G~,xͤ Y@%?Qq}J*!_ep?u6O+**n`UTlJ"٦ Cֈ株0H LJX,=DtʦXyibleӈw-! +l1j^B=="\XTQ;-ۛh*$,VqL""VշiT2ˢ,Zae[["p؉<TUQ 7dgr@vcd{uz". B)OHeG-C-j(c&u UDƢYY59Y2ԉXFXruɌj΁sq77s0d2[]q|G\(^BvIb]SQ#bˑ 5 Q4[*UĤF3{x'pζd\,|C,h '6rٍYg i{!CQ"J~|`Bl`"hXoH^:%Mv<Ǧs}A+d8B)*ɫr@V Ru 1a)TUQPFA*X =a9]+Fp KCn98fp$=9ib ?oUHa,ըcvmN?`E)zrђ2eͤĻbe㱕 2X TrwSE%X %W扊eCmhE%lˮ* @SYywb27L-&bq &edV5D< 4B IW&ZlS%I{뾁K} }J:D˜K48 :.?UªQTUQ *cs74MN)]DW%i|TJ;9o;17e*p&O-/#yH. B<'udPR4kxr!ATsEm3R ݞx׷7ȝ@Zk޹B`4:칢bgPs**~\fۍ\ 0`!p@^ :!ta͝sZ\|(˜3E,J;1VsE(빨b6'΁u#+^?q͝.»@4L{A:݉`UTlGv]w~W 1@ 8ݐ;0sxCkk%EK©{1i@.TRlҡ7*zĘ{#vHDNmX.,ŲhRa}a;`UTlfU,*,_' b*GKz0wtu}ntr((P,`==;*Xӱ:.\ٙJJԻ4'̻2--"vVR$ ZPXtUTTNTbIFT(Z(+@6tt^I׊,HflL5KtoK8pːu H#PhUI(݁(0E]\A}^J.yJ`w}{{55$Ubl.:칢bGP VE6O}/>ʀ>Hlw瓷F"A }4C`kz%ɨmmĄxI}$Q tpR.#^B`?%n Sd%h~,dqFEE6+*'+3F\Щy=tЙϪO>j|blK =}_/ ,FϘl DpXd6#ێJ ՃUQbqn0$lQW!!쁧J_?ݎ J閉SbA4S|RFmk:x:vFo4zgvK{W6oP**vDXQ# Q*ynr+DT($0y& /ͥzS([^AF}"5@,zbGzq'Z ;NX>q߶n`m ȴEU**v'H.%*G4H̸L+5``SV]?Ŵm%<Rݎpf hiV[^V%na: ^A qmF9cCFJݩX99z|Gf<ۿ#D@**v3*~^2,~w$kbΈ"--ZI)"X4b5E&ЙL,1K8|t[wvip,"w&dUmTTT\ `UT|8G_zy"ca|q<ݎqjQ@)LiPFa:#RE\w¡#vnw"}T&]Ȗο٦#v꿪yTUQZGE8\|W$z,7f3 9.g fj:Tm9S6R@Z? *F؀˷x6s|;EXQ[wt;GZ5ȵJLW;trr"e^L؁x{k{DJIG_+-H QI#kR#**vUp!wδc&i!sЈ.*HIRMcXVl+c?\\[6 +Z 9wi Էz˔f>{D,m4cxbx˻|cYl***bY?δcn$Cg=uxeub,{6@ЇY#¡@a~5#b$ [f)XP~/mж+FF-K#@?9gO4[:!*e-$ 9*,YboTJ)aX?i!_1t-n4T)Ɉo-,1RG~>b8ᝇrih9yn***2bfsFGK8=ZB䛒⹴8dDJkw?{y)̊a=.Z~:EMO&' d"L; OP$y_xފ/C4~ 5 j oRa3.ڣI|npoϢ> EU**v9n3dL~TVW:ǴOO{03Fw߃:7i\ʹwRTDt̔ン\MA -+{m3M;B3ÏhFƊ EU**v)$noCӝr`Lw1ˈD@-Q[%?Zul+;|*VJ&UJۊt*Z:\TyqWئ"*X[qgu@A!޸p&]tFNUϱ$zRE IVa:oG6 GR}@ÖXcY 򕑃_)iёQ+n;|nƏ^#qTUQK{F h19&oyzFEv!W@`UTbݺ᧠={lC, <ZXj~V#[7>Hph<Ʊ V#( J~4*YbҤybi0%-99(RfgՃJDш0j)M{?|$&gVTln'rTb"]v| 9aܠxpߙhDFD 3#@*6!ڱT:4ퟟLS8%=jِ0[*,Ӣ,R&+Eu Q̀Ȥ j@kHOr kas%>n)n VEŮE4WZucѭQ*u ~ $d Z${8i09UJA@ʊX,^ǰ0%9EYT;uO}oҢ *v 0``:+@b9X)jbPIV\4oƫ' @LPXQP] &/LžKpٺ4$gHjJe:{mqfCg2 .q"0G9+n\ q8ŃB[9U,qJ\z/pN _k.lqbIb{Ư}wvU VEEG^{WGu `J""dr!xNDu-"+UڥC~?V0=ZKM{\vWٝC OXcNp_u5; '{gkIDATa;Y¯ڇdZ|DsxY}/G}m`U}Y.=Ÿw`AxoAvDa=5r*O> RuKiW?#~8N|.u~ŏ:|mUT7mEwPnkE-(3|ۋ[|-lfGG;,޳, X̦eE{~ ^-`zZ;bIh-{*.cD[.h<ݕTD7&1,+@bw} M0UBBa:XaLS yiA.mF1τJ JKQM5j}bFb/7XA[=[YN}V?;V4?qD"a) \8oU\iX*= atfX.}l/RL'#K4EH)qbǵJVv_JE7m41B;~eOs-H {*1\v!I/I-ZK~ܾ~ExlHҌʹ&F7W4~c,IdRĕcY:ҳ,4M(K1 #g+׸UWs[ILQԑ qs8tnT>E'SLt "t0咼*փRu!`r_QR8eCUiTTRIx˲2Trhcbp8,J9ϨEbg <` ¶#իg㗿8VYrV-ړ"jVVFpEx2Ї܏~++yNΛf tX}ma:?Y}zeZʴ|X7Xk)ɒdѤd2Y2UK1g+ M^ #“%[s>sJ(++wZ-FBZEqYEW_ʇJՇrAk8KMPŪR^/Vh,]ZzC+鐷ՊhP.Fib2|@kSI阩m+`cJNئ(B ` –V(%]g$A&U\k)}Vvv`Z{<\v=>zxRou.V:V#|RֆKhmT2c7y+M2  %?M3W+Mv&w+Y섻cB]oG v_#j#ɧ'A{x5Fw\*mxZO5߭".CiC**^;JW4-Źc)͵s އw0QYWUpB-7*UƶfoozuI9AY~q"BeWIXi0`̇BQ\9[Zc͒0x B%C'T +B0> Rv=ʶj,(hTw!Ga{ ܩ盿=v.m3_;WZuhH Ah=dYmwZ\ Ɣ\)nnjaxAxhl}4jמd*;.^دkRS^CZiŽD;1R ݪeYևﳒj"t'vʚ0-WU*=voΟ gɍ˻|[ol0V%«RuhT1 Q _WɇTK%&N2broш6UX0R-ڿxn}>>*V_zMK6BU4IXl.K %Rĕ\8❷.qT D` v~|Bx^<꘰r⊖~jH[Vc 6{nլOVGT %MVk]d k!JfU\ k}vM\$qeO?ݛ/?c^Vɻzb}L\Ī*BGG_V"zuS^e|qzPM5G'}ևQc}WɿUav8Zy^y|W8me ʼnKo~a] ~8vxR;?c窕 UvF[v&z*%O,7)AX)Cܿs[u*GkR{E6l&4&IYRU%ZPUs+aw }?8[yO>qq"aI %SW@=9ĕ!-!=`4"; }h 6a{1ŧȞXx_yݪQ=[mF{Y1%j1sjҳ~Rd[߾/?ǝG>"l O IFHu>VjA>]ËēOoJk2-텮`<'*/O__+[``LgU!W??9)#ލ<A8k#>{Cy""aqgB>aQ 6:)*TJCqHk]юb:!CZ):ETbx(Xyz=[TTՂrAeB&w8,y78-w7}(_ayx>Z+:n'cg :ʅ\KJ(ެuiZvbV8i`θx[DŽ?.bo{=i}Oγ^ ,ݧT]K>0B 2V-=1Yݛ1󿽳Cy*D` * ~?ddf0 a+\Y "?}:QX4l&է$dboG^%RhZ+`eݍ(MN\zteX- BwO7[lA8 y2y/><5"\E@t2n/p;v*b^,-zך~p hӴEMKiU)AyO& V\.ZbNʵ+kzhɬ09I ς/?9֑M:o'Ƶ Cy&D` 9d,aXf9nFQh ײe>aS<=,ٽTo=q.yL߻\]^UӃ_ȢG+F\/xpO؅ō˻|?W K=:3|Vԕn/'4?Ķ !|{/;Vz .ʡTHZ:i_b!f_ aW}w_\q( eBx5t7')9J b4ĒHխ"tVeYZo%=/NYjЛdVOFwTaS{rl%`Q:/"D)5Ί7O8?t7/?g^V>B Tӣ Us"(2y2- o=?b|=?c"+y5xU+q Nm_r2V֔zKN|Bv)!iMY.OkoLs8+h<~'&?!K^gUJtZl&<^a17_AdfBpmg!JҖGէj`tQ|hLgfxֆcrҲLՏ y ? $=. ֛Ð5-9-2Ӭr}m1 @ow dr:տqe>εQ$m|ZUOc V"6׮׉P,~|h*;7O/ڍlR[cv]>ayj%d<278 <8hYEHyHKQ~zdz :݌, &sk1ܜVNYQ-wXXZyn[p9s{{un5vSѢ6wy:[.X]bXrMe+ZPp8-9"\peo1an'><`FW KX̃(0V/.BgT$Qd(Rs!^{S 7czGn=ht[* 4d>[r)o}TZO^@+i*7Ar*hexeRu)BdPxHUC݂ ;=~͋EN E]jY"Axjq̌c6M[Anj%JS. yE[e[ZV:Q%20뱽VByp7fQPO A7OLeȀ3z3/+>{Vl{\4>&Gd C:xViZ|fXlFdF{B\2r]}k~e&F-*XʔbeLK9/kg孨,`# u?>t7>Ra#T:,̭ nef40̭rSk(Qi}VhkS>76ưP+W>ޗjs]i`Г)M?ςzIdbP(,AṊn/D@AlEZZf3nv9& |Y+ʿO1&i̴qu^4a2E(A /Q42n/dv2v̭ٴ:VamM> }0+NcqKo~s^R%U]!K31; խְ G5ziۃNU, 8: YV9|a XAhP]Que{*a#5y1ơZL%F[Q~0,Jߧ{f3nw9=$y"9Y= JB!tК;oy$yXlhzS^7D` 5TKr@hsE*2vݘ|[|2!zMDi*UփXܭ.oO}u=;|"G._=}^$AX ;qLK&e5Vkv]v] zwNX_ys:-Q "9b Y#KszV1s|kÂK(?;X 4icy!,A$"AxX.-G书ޭ^?\pfӊtb=s!2"Ӫ`ID ="Axe1a&K`OBk0,Z30适0; bsMz g,A^BŪ9z0.ʐ5=Z,O7s,0QN'TdPX ,rxaAoP0tnx7enon9E(#K 0Smg+, Q("AXćGV\c*R2$M!K 8<(9<(` ЌN5VfFFr(T6*SpAxQ]t3~mխKb^q49{FŃ%B s,-rC(?0u (9h[I**N ʈA8Vb3VhEa:Y2{̭r,{G gzT1^ dn GB3 GdbVQ>QT/^^%D` l0ܛ~`ӡZ88}QZ:*G6,A-TIU2F`0խnܚςؚNN2&L D` l)xΔn77(;t\:, 谬[UE(ApA8,-Q~a0 ޭn7ٽ[ђm xD` 3LJ&q}O" Ќwc+@KZ 9"A9!C+TB3uB 9,X UxpJiAx± ++A"AANX  ,AASF  )#KA% pʈAA8eD`  2"AANLj<IENDB`v_sim-3.8.0/tests/exports/iso-3.7.png000066400000000000000000003145261370110300500173130ustar00rootroot00000000000000PNG  IHDRXXfsBIT|d IDATx{dgY}w}k: !" ¨ 8G8Q02 *:8pT=3xs0J ( 0IH $!Nサ{_>}ZU{ݻSVZ*]=#`ˠW k(`QVAAAAAAA-F!X[B `\ȕ>mDugɻXYǞ1Q`<,/7W .`0ll=Ém7VFc1gXAAAA&X8 7fT~))*ΥM c<4M`<; ǸCڮ(X;l2`t57>8G4]܃*gLVX,_zUUR}*n[~eFDW3$SEu9\fb_Tyx57<u׏1?{\CUS*$so]GK|x+Q aucwq3>J4'UUʽO^SƞxR{4_nUꪢL1E^} ?=ނ&`}GzAJAY-F,ت?"}|V!YqH"Y \ԅ`eŷ{yƹ|eKP'ի[q{c4xu9EэCP"8yf̵nzen_܉-((x cKk_CRI'_EU%ZZ*z.W?&T3{m(ތn6\EڥP՚LC݌MM۠z}!"8r=bmĖ,AD$ɊD \4i*}l4T"1ܹ$`d?vםC̸1\U% { gsс8f&Qh?]%if_DDkI4]XPPPpl:WP* f%X!Bhh17cʊbm\wB,S?gPN|죄`|f$Z\ &*?YZl-KIL 9|6ze񾪕꟣r,74=" u*pU^~ ;bߚ&D/Ud5x?JjLӌG%` !p h{>xsyc1r9?6kbogz I j<T3VL8~󳳨 H7ttYZlle"ҮXuя~$ F*^jףZB4DxBӌPaxX-U_?2=\}RB)x|ծv e!)AEq8UHUS9u EP)Q ++ >EH|O"j>c$S?ȝwpw*p9Cx9rS'8lU23Sk׀s_OϙLfL3Dk~l]KF^oMA[x?m`#YqYf$i*%XY1B"0ʏI+Q!l=_A2e$"e *QgO0 èVRl`^_Z83bG#*V-l꤄* VRUv2fʚ#3dDo،O`l`.ADVhe+=sUUpnecyΜkʊ/F|_. ;lr4P|ƹ9l@WeU.L\;$Zɢ%@>m!X!3!!z}.M/%Q]6=G4dZJV7ocIBpm6V0C3Z Gh8[1WuՁY7(((x\bS1-M!̋\sQȵg MrRp3D"E '*X)S5zblAoi`df`>Z"iKLHXGﺓ'C,JVrF%&9>qѵ]HZ~b`"H hf11c%Ue`?`,%¤Uc]O*~OIo{#Y~ >5 o?/g=52133̥xRC _Oďu_{pYΜZf4.[S'c!˄n7%=!Xj3 #"dtՙ{T2[o cTJrC-PUfosj Hu"m~7.8.Iv4,E?Y@)(Nvߡ mw 6B T͵r.F<|ݫ.z( eN_"#%W!D`P5)<I)4 <$hd_DZ&* FIYT1/OEK67m7`3$K:*-.{[/6FD}$\A%TՊ~Yxƞ?K;pOl`m[0CD rVq=$ϻ6gC=YĤK; I @Z!v hFKÊP#`& >srU 3x6w M3biiOx*ݞܹc>}oy͋ رy3%.ݻrN-NS:*M JӼBT^SD4yV!Jڦ#.߿Bu>·99=,xC`x.pG>3sAAEe.HV)F:'8}! >7owШ`h&9*i=$U ~N$K#9j RRGJ\-}ӠgMC5AxYeeDOU?!ҲǛ{ ce s+}({l9dɊX!E5X]Gد|VFAmNX4&9yxbZJh V)P40BYyjaVw8'%c%x]ss>,HL,]Y"[c3{ߣNs W g~'5  6k+{S۬%3 r$)SPX;0t [Z+{HɔK~KԽ@k~\%=ӂ+m+TP)mPv01+74eԚ%]!Py&Li\Nc@Ɠ@$w)jRjc)}_ėXÍfle8XYW (NȂcUR4F%d54?9&)KfH KAtY881Vy؅;عhhthу_^۲AϗxߪǮϿG9tiqL=27_UPpQVAn}hƲ*B;o0+S.Ds9+hn7Iҟ*&{WiMs"̳%yN:8f?~&)c~~e{ 5ԉ勿`[a` k73G?̞CmӜ )3O?x3Ԓb;!nx3#Pd`r0UB&@K|0hgJn˱ڽ=)x/̷oa"&UE۟o vફgWs>=zB.(( VANBa4Dq'c&ʌsNhH$L3Ŝb MjU4Fε)s8LHfvEBD 5nߊSKVX,oPscɉqlC̺㈛M߲@=Pff++v,gUPeΪ`8O+0 ?ʡĮ0kG;TGs30QE@5& 4g"vul<ַb r>&[;:$%՛6֑lᖷ G$[S'8]?0'<{EB vuMVcfwsh0LkD; I N!GX0\"JD,nBDĨQ|x 245 f}߇9m4Z57f U<VkVd3GL_ץ?63 _n?rUMp.) P~ !3!? x4 }XAԩ,MS*is,nFO-o+c|\NdW<'|1hOh= _,xSOXde-N-)((0'l/=mSJKAXjDi|4:'1;1:yÉq:dLB*#t4qD˥q:1/++Aj/W}:{juTp鱨fer%:@mmGl=Fd3mCH͍qӨ4 + \MU+/`QQEjpm049hiU۹NzD)7]ZRIKLCT^(([vBɇf#*S*Q*q14i`u^GKp酴A-$#YyC8~Z25r ܗA8'@E*((%‚DD;Gslz0Ĉ~?ˀ44&X LB?h!u(fihXhOX]4w'襫>"-D7T,?G8X@s-ouCF$RYe6)>+V*Y^5ч *(ITS5w ^ښox*>y1axDTm}r] Kj[Y>DU""i3ȵ$D G_Ta,?0L_rz˙:}p/S' f!mg,f{Qc}&,K8/b=%V~n{T  1Eu4 :0esADVcLSF{aj"5x+_u}{0ϋF~}xX7YbzW\K1\֍Q`4XxJjWeFu4!-ИXHdy>HzrSK8Qz{g>J\B ET h HAi!p v?gOFqΡv[.? 2*x f<9EsЩT0ݐ&Zsظ2(-qu`y ]('iSzFK;1Ӑqva={g9N_ܶ}F!X;AKb |w W7ow"Ahֱ=%r=FD4v3|""qL Lu:I9)|⠦>tjW1Ihw=8iv+ V]3S:ӧ.bl"\U)AW{eFMRW$nEKKHΦ&Oغr8y|mgAA(%‚D43. ْRbƩSzBiGt;ڛ]g/aEwj Muo=\:v5{jSSphs/)Cж3N 1j]pf >ġyݻ.H8Nv=qHB@g]%~i#{PyM0|?g0" h333msyy51~:-߾l;`J$X{g *(AaA},.A4<4 IDAT~t%=֔K㥥©wx[޿ &n@O3ko$"%LJ8q3Ο|J,3b1/H$pD=o S.QkX2*f+lU1[񶮙i01*jUTiF#hx4Vi*G4&H5k^Dh;ҕ/2kJ`'QVAN3~ s'NrIΞ:ΝT)Cyj}Y S}]~U<=tdВR ɇ'V-HG"-dR[,y.|׾/9q; d!Q V"R`MP*ɓhǂ%I.`aiƳH"YW,xBԕcCB fv W8pp=` *(!TjfH 4yhKO\'HW_-NjИTXy!:!C*ZӺLbp!˘HmcB >a_Ĺ!y϶Y9L>z#9pp'\3#Gm1t(`psݿ¤_): sUA8zTr^o ~4Z^c?_b"IHfhRtkt?U%Ao?Ra]NJk\:-VS, 8 xx H2M?wb:E`!%u46"Ҫ~Ӿa흹{/(x|m{N:T&VH\]w$eɺtgr߰[o*DYeJ.ɏ3jRꓫ)ϣJ &փ5P%b9GӀ8[ya!C$L K&ZEYe0+S>FuJ1L&T:3]o|/TN/j 9 v`l!j*0F5^ .$4q@!X[{o*U5ȃnN\ =%)@$OlJoU/.yhu> kI?9[MK_}{ʬG܌.C %|j.,K-&szahճAӺwL ֖+34/MßJff0S3Tհ px+ #FbbW&Gq+4Z]g"{ɤ=y:~Y?'\.LQ[0faLܑD0RhVJ` ѫ]j:B3z<$$L~,x  SU3֭֨ι~U xs%[Kfk=LiS.N/pܖ쯠(I{n;;' eʺ!ЎZiǮʋH{TTR@m2uM_Ыᐛ$^ȏĎ\l 9 =e†m&{3Ա`iI}'`0Fۗ|ϯPW)=-UJt8ǠU$%wK۶VLnET窘M&j\ϱùo{^FwIcsg3K[6ǡ**VA(X{o+)Fczx*:CueڈUA$ *j89,X EE$RU[*L~b9 IU~i|^,١5z5Ry  f?Pł0p1zRJ GEpfصjYD\"MЖPA&DϻDbp}a_t u%~uN[r\\P( VAeB,Y/M)VVzKZ+WYr9՘$ڪ$Yic(i{!Mwq?_*RHV6ȃc IfV"44ĀNo֪[86#y.z,89+Y9Wy089j+ s-ꏶf)BCZv}uhE~Y5_Fޭ}%څpD,jv(`Ӹ疻 !X=JKy}THK:=.D$VS%YHtiǐF%3j.X$rK8 u\֩!i0;3KU5mx]=b-]cGVnې8L'PU0sqy٫OB:Bݿ38 {𪃅`l7 *($,t>Sc\"\u& TnP/ȥcShU-wEZ5N^MzA[efF|^ Ƀ56cQ #i2/}Eqr՞:5LUIFVm~Dbw382y[B|T`vV h pU_~{oA vAAAQVA&W`J tu $*˥-*Xoz\&Rrx.Jn|?G'Sy5ٴrᘤbI$Wc`˾bCǧ"ruWU*T;s{R@~X\ӪU& wD9IkcnN"βd5m_sk/fcg7?lEz!}<n‚F!XX;ɉ`r0xij:TH$r'adiVZV_^5z+ӎ(Η{щR|f,J* [aD, _IU|VKZMtU*k#V@\Mwav攙%Ya :\`*dНé`?Pl' *(~|;ahMu֪"]L= )*G5\&-b!SAde5ȖU$։c88Ǟ}3e.aA6K0qQ^%jIBf?sX"<0@|6TK-@{5+ 0Eڵ`娇S>y%`!וdH4zdŹxξo:eypnX'ɕxEV7N&ժUPL1Vۿש;B$+ 2m\_\y_!,h"V&+UXY )2*~rCv}oyS׀{<~.>C!Xn\pӉŒDB!tC-i*K&DX8̞}2`PVA%BZ9h.{ۙa1pqò2JK*84F&C2O]~m-NimP'[T RsDt\y?}[M%h|Qq<`Ȟ-%WYogOI*!L|zG>u7OmUP9LWSv[Z6{г:UH2vಅ@PNU*lGk!l*ƣ `\"XՆ|Ϳ@ pWH{ V.d9޳}_'dC*>T:o@MPɵbxۮsy0B\I6UHmPU{ʥah4) VYR`P)!p#XٶAU!K*ECwKm9+ *(D|F{Q "/v*?,M!fݱ%~p<U,-i%64?T)a),@XڽZgŇ$nAy:`!i%[#T#,-9c@UʨkHZ#yT Dʼ5xez= Ʀ/ [E uScK<]88ǃlqUPpYo7oT0pi=)8Z6\&z.. w҄;-ܔWbh^)<#{?SČwy&Yv&ήQӃ0j!%W f8}zPC< RS;xӟOX6@!X?&.kB5TcPVe _{>>N9c|0w3xJBkpwISivTL?80s+ze¨( -`uP *[ﻸ& ]TLm&x.UEG̸>7ͼ̥T+G5j{+%oh?70,`c(`HP9VXSyIdw95?ub1zSXz_~~pÍR @^p;=Mo`kY~ xqy7qy7*` f{|~=ȿ+'}r#{ uuCe]]Z> rVUh`9(c1nhLis cU`l!W?3&+K9=XӐS-}9?v'=w0|u-,?FO:|*O5ڥ3ǜ:N/oyoyӖ՛xل{BWN_~/T31ːOB"mh#8G=w= uNhH& nmV\P(`0IX$B$V9L`-Du`{za M]KD~*oѭgw3qWX|SX~9سoȞ}Cxc3˜:™eΏ7D2yJ[݇'k#[Dh`e]CVO"$s؇5* %fߢ\ -"Z)_C2 AU!޷*OJj#XHAM{oп{^P(`;P"G5Ur{,6d4" @cs4Giujy'Og 0;Wgߐv{ ƽь>\+:☛g(֘eV&WRhL!D ,\Oӌz F;thu#3:5;NUnO"'U!@@JYvV s;J%hD}8qlq3'` `l+TƓyl`. j7Pj^Bkf"DXN?߇U?8u7Þ}CvgLK9~^qKw/L$2Wc3m[ )>Z?:VT1  IDAT&֣sn2tTE?s]r|Gӕ$z@'ht_-sH:~P0L]QeH5Ӏ̰23{ *("UP OPLj,Z +Ό++\B#~Z3&pg*3~qc.Y᚛,{ ۥ_f9]g9wv񃯹9suBx[m'O ZK&~΅H{!=+XV?O#s|Kz,;^ū3213K%B8{z$*x(J?T:Oꊑ *`\?l! *( zix 6++3""`r-HgЋ,-ЯrҤ"5\Gڕx>Z8k6C=|oط dbOa7q?&DW&,u UJ5B4c`e*.M={29}9ʃ|B^MM݅PERWל~${A֡M@\&$1tĪAvӭ\URƧb뿬.O{CՉ3Y*;oɼdvް/]$\J~)q^aOC.<ޯobJMTrm$X!ybiP~3^{{|18TP%7 SJ T"2CDR14&o|2eYXPPyUP hGKv:G8?H2S3[W5UME>qNq8u DQuy86E}>̂MMaB OjTd${ ^ W-&WL }u ~y9@|p 'DzݐyJ"0`XMBaU?s={g2#^xΞgC?N1FDge$ɲa&V!4i"X\ǁ^]waBĥQi#wғ6Uʆ) p3UŌ+c<"T46EUY< H\z A!X.鐉C$x[ܫH^nߪkr[X!DW=G:̹`a! {q5OܿqiT0J ÁNs'}{ *(LUPP$)XD;ЇE>%^×8gta뮾uZ>ܖ\IV2O+XY9ФLxɈ*^~HkVV$Y{nUCzo7iS= 3~gHuv{izz#xg.~JRLx>XŴ,,J_/{ H%4H`Bf}$[⅘K*9 TuA°ru-V^C!BxPwMI#^Pp9(`3 /, Luv>DXf1%?k& r)+-e0նyQ BPJc2{xۮLc7;0  &AlD=)֫zR{U" (ҟB .:'0xb?y{}wί݋;~˜yx? F4 CGO%f;DF,AOhU?Q*)dH%$:0_y` ޹"3iy8:*x W!8 av`2`(`-6%Jr[! (@'S1I ! 0g@:YB掇T+&ͤ^ NrN -k_IDJJTO_%<ݿ^WyQ[㫟O8kkt=#];ڊK^~.ߵ'{%BȋuAG !"xB:뀛TRdEKp g}]cK0'[z}hۇ{ `ˏ?DT.w:\;:p=>?bK g>UB`94‚^WfTΡo8t-)D = esA:QVAq˛ߎ@>Xdhp>dc,vl@P916,0y00˃`Fr7.`ɏ@AU,6-㓛2]߶1#?|%\$5Wnٌ5 `be^ E} 7uAyϻ uw1AvL /=q7}w݇fB ~2 ΁)(Hڹ&o\P6UPhK; S_h6:MDPS A$a#B R¶rUGDǰHdoߍ;x" }ʞkiMU@ 22XEV]'0WQs?tGϐ-#ZƳtrDl$0Mw÷?m˖#:3ݎ-;6`ˎزc#rIfoǁG0^ߢbF]תbY*<02\U9'sD^0 Ѣ=s8Mضc5~D\6bT $IW Ԥ 5ifQ BE@EYc0Ԥ~gxK^vѿ8G|hCH{&RT0g[ A..dh]+X ~!!^Ɇg掦zAl&iް!%akyϻlE}"3ݎ3ێgnmhf1tݽ܃>c4Ƹiд-6W5kѴ-8:n Mh^VcY|n+瞉v?kEQPPGQ ։hxG@GRAIFbmP,4ԓI@`0-xPD /csT!̩CE/1ާ^<&[(Fh셓t2ݻi%  ^GIed"I@yá='+aT;@CWDb}w?]w)cSμ`l߀.:g[vlhf= I.8;/~77 ײ"h!@`۞(Iںct/((X`+S!$ Xt_a]%Z\B`8!R(iDcG)ب '294Am05*MI pр LlV&T?C;Rex&;`&$tݚ"0W@{0DԬB#HV=7 f  v؉gqy۰y,6oOؙ>cϮx#wl?A%] )5hvesAQVAI—DSz\qªL=F"B`,@@ldt\6S" sUNH vlA+#) l yt18m;w(!1󹞳DoEJPȔ+Bfm$|zD a ɎdLz+^O'{j]hW0?7_e ,bwY-;6s`Ӷil:ƭ#$ DT5 kR|jjV)8͈YXۘIV~lgqJU rY<όdmh $CXZ z@*N盙=܂hWX 0D;PU.XL]e9|H K/>#80'Y][w5׼pD5 #LWVå7ȷ{l#t3hFIn/<ozعQk˟-Ucs@ʒUbM By6uM㗼WPPpbUP0w8t`}})ͽ TT>@bt2aT 0s8"-ntj8"o'`nƈ\i-=d݅ІGmcGv< xoO :ęP :?+3 y(֥( `GB%;srJٱSVf%M V9ѦA !%r`<(VBD5 ̜HOW"TΙҕT"#L:2`owX&i+޳?y'؇|Cǩ% uZǨ+Ja-Q 1p ,c ;n6>|W*qgnZL%GDx퍷R!r fTSCi}]Jˆj*ms  ( VAg*D2dgn!BʷT&9_!T;ތ1>JX;և8` 1κK)ߣZDN 0AKQ1=1bڷ d;V:$ (((xHPVA)ĤK=?a=7ub ^,`~:2}`ded` ^B+uUaXU:)WaT2UUUNIm3UU s IT`/K_@ 1OLw9䌭_*J]a;ж{$ sx㐬zی`-(aD$'1SJD#bI蔪cD˄t%#y~ Y9$&¨1;kTUkZ_;#bৌh]Z|8'(FyZ" Ғ^'YeBvzg)A#9,Rqu8Tb{ౄbr/(x+ :h3hS:Xbf܎UCGdsz"rr`4=IL ۷ah6Ôeb504P?CKs 3mӝQIi Y%Maco$ ,yӆ vZ#jw@"I~G kAm$:e6'z؁|79W/[B.((X?UPp Հ,5'N H&{:dX7N}H>Ol:E \DT0rߝpr`Z.rC+ MeʊfgsF\lP+= }ESz̲""88h _U/#DsKJ }_൸zSl,J[`E*(xd*IDKWvlTwIcl`crB2=4[O G@/1ZGo?B0 c҄f-*ᗏ>P7vp`v>9SKw$ 4Y?d%'!3}~_m/֣E@)#S)_U='%gÞR:Y ] L6y6`.3'w?Sb3k#̈ױ$x JaAI9;SĺNGlf`i0ކګ$*$demP 'RG袗lbo.{?I;;b:0BRPk<|X,xѦY-L+%**j,gN~/|瞃Wq;&}.PfZ* .fx!"ińi>iUv_^LBL /O~KLCAPVAIQ2 DM?* 9R*[r,tqPU$v2mi -:NZ?2~rCW ЩgD:"Ҳ']_Yis[GC@kbђzi}͎?n}wܑkz-g9PF-J߭1 zTjZp dmU*"8юMsGo4m{⳿X+?xĨY)!"8?3^okG!X{m``%$REƔ$MGՃEC+-]Ť sG QXs* ,AHl<ԩ $&&HV>>LmsVZ#Ux_ůB`6qu*BߔU {13BXc=?5sCj4bȌ^H L3ZAJ36,Aw 48"!s]QYRr`*X\,5gNp53XXmSSayI@Jg<ǽǂ~=h=C5aVL Ⱥд)+'`)9%@,> SS0n@]Oa5ӌw٩߇|'EyeVuMR䄇A>#MU B (IpˑVW^IWM otݽ[1b8E]OùMuU5DU \ UU3cҍe3S3)fo9.{ƿ!*^vtù/dLDFAK6ZTil[hBʃfB4Vh #`MU$@="IXKEKDU*WRTl4Sy0#VqAug ``jtM8#HZP z.(X; *(XHKp;0= Ljr HF儋Ә8禀gBh~?w"DS@u:_USTD涛, UJۿ @]+%,4P@=m 4eDԫESU߭{J~Q;6(ERa|]%B{. .jf5B ^7@VSbUZ“[!X`(`-ԫ6 ̕~$,4 *m,~ 2&K|h7z&iϿb͇iԝgfӅƋzkqW>u].A%4A07O,^-9K@$HZ:_YG@,)wcPods9`XXs!eRKXrD6g0*X)" "JpΡiۤ(zUPF *NBtd*6ju0JWާCOmzoşE|x~ff%Ͽ|U_k"Uڦz$PKW6#; nۓijQJ]=To[+_aiY1VN~z;D EUNwԭ5/3|%Hg;VAטHƬWe69Mх{AZQVA*޷aSr+Q4\tE#FPD归zo7'_oK>tOIUWOi=?&]RU]߸}9̓Nx9gu߽x%)"5'ԩ|N!`Lhl 7AI~. |kI&0C=TQA֌u53VAÅDd&HJNBG}ш0=͘f{%֥ >܈+tu])6$pC5t!unҒI2*>t{څ?Zỷ<ǘY}WzuKJy7CN-: Nh~ZĮ1j#KD]TC[0p.Svw5?ݠ*(X+ *(X?D,M/DR<Cpt*'Y\-GLeU$#j@M|WBPerjJ;%;H }jm]k:3&Wvql$a=r5 1, _R#S7;*G"5t1¡S1rtH ֏o_A ]@A>-9$Wq%VJ'rUUN?+yVQ"7hIIct81##3KwPC0=|sVn'^c$KN!R.-!R9"ZPI**[-QO%[%^8#W)*&f֑\q|5r(UBD}mq#W]/$ `BO$* 0'WmXt,#eFU°er9[!7otu Cy3?fщHd k!Y\Y0'RLeU|kKϹtM[$"Ցm._1`Qȭ$* VAÆo_AAZJTRe[|z[~&%RիH3G{$YPߗvƍ\sÔ0r8ǰ0oJ M?&> :i>Rߏ֡F:5MC7$"Ec)H y11AKY$X!,oHвV3?z4}ZdÊॗaǧn|f7fYEG?'݆dۧ4Ѐp:+$IH`*]/hB颸]: pD{Nxw#g{&~n73=lA!AHǥQ36]L?$ֹi]:Gb#VY0jQI<O(jESMUTwPKQpc~X9@T{&-D̕)dXTr%{>{=VTkjKfDoMuUPrIqIj˃*p'5x]'C%E \'Sv|n_3 F?<ĸp巾nv( +X1{1[eBb9Hvf&<@~~Uoʨ5D7D5hradRa68p뀪 *AU H\ j(XÁ0+S\+aJABWnBlT_Je.B 0A7U<X?U,ŹW߀]'*9ɥA`h)7'DRAoThYb)b @]w@c]5U|C?A Ť` *yE \-EϏ8xN/J4AE/&5@3rLUaU]Guc]*K5Ĉ+1.yN3%FHr$; D-ޯSpe>\{ޅJ N=GC$z`+k <^) 5t@` UPjP6['`%eIV4G2Q\׶It24#hr9lw Ep ݃P1.[)'T.HQ@)N "Rwz;!\|h..({v+a 1I : kBG%Vl+A[e;"aA!`uJV)uUYcI2YiEM.{?]Ie*![q30-J~Z#J)Q@7FF&JeC27|4SSHSZ͡yO>|AD5a1#5zHV݃f~c,XH bEd(h0#`Xb ց`ՕUR5PhE[+ 8=%Wm;F,^"&;ҌA0U;lc : PY6V2 sd*8+)Fr,y:1gdhV=qJN|P29rD}*F]!9vJFKGVPP~$!I]Y=/\Pc-b=={$y 5Tը@ !+j$3mxMABP>{B'T+MT3 q;93sU*VyXS!6JBiDRU@>85~%jYYAm`E*(8%ФSTnUD#_)5vAfڔ()l G)TqhU*0 =gʗs*z(K };³po=zUIB,!8ҧ9zTKG[I5dpԮHAl#[xA `Wu~9 VG:"+.%W;fM)ԠGfS9lX dx`*u]j.3݃o$,GVΊ`ogHcgid'D7$XO9`zV!s 2TpPrIήR"x+O ((x(X'jfn_>ZEb* 6"9,.n_Q2E6CFWLYˬ[.! 3G\Vr}eߜdpbD!X+jʄ:,$R喅LQKsDG5 Uԑ5eD+#a]1m}y^߶HG1h3g@#}Hr2zX9NdcB^EL5c8k]h(D?`m(%‚ZŚU%<ײ_.XIx- V#M0:G3wT :cT&ǩ)\h$bwt]!H#NHBHƝ%ђr}XL ,(ѩ{s4,0 !$u00M07).k%]oc F80~՘] )*= 3D RƘ~g1pC87sR4wxùA6t\mj*cE)==$UPp)H:* )|JկGC<T̷Oa$=*>qэ%hШ,"R(uVh3.XMO({6գ p1FQ"w;.-Y>Ϩ@gvg!@{`jj#FM<޸<?q='sCl=rmԟ(&UbX:BBm!48>x|ޏ賓%QOKT,YoXκu H̄ 1 )t4qˎ9Yw>JO[OcC%_%ܢ)-?U5efΖNS7X8S_O((x5`$kyl|Z$Kţ8t\zwbJQ/S\mMZ"4&tvt Np2;+'Y}Gd偢|ѵԷ+O鈕 Jzpz2`Nrj%lҕeu9PU `ϙ *((`M[K.*XZTUێŸxI( h18}EcιNU>=)V*γK^"Kgl؛Yh$z5ilّ_UG0 uݘpERA+O%r 2R=FB?ٽ?WhDSSsD,fB ($a-jYJUx/ɗndyLo-D2]m,!̽R !&wàk#e]V3Q7 ˩Tb{&d9_FICX01D @`XČ5'J!+ ` Z9X^%L/z[{^ sX,N|w:m_ xdr͚\1 H$k0ӾFV{ Ygwt`dbMf3/GIJ#qj?#Whםٽa58W1Y&h[a4z.❳;6ϛ((xxS>9}&p|`*M(= x hh%DO,AAVBhQU ޫF5 \6dܶm0t,6ҍױ.DJZ1>>X] 4:WBQV# `HQW ` PQ Q1`1}W&2y` ` _]Ub `spwH1 ? l;*ڪ !8y ~y5=*N Ux4#Vc ƸȌ)l{J}ܡ}UPp p2M܇?S OGĠ1Vt6Gݣ^G3JOT D4A1\1\_uRmڶؑ᎝L%%3or ?dž{yD$K& jb8.X\Jd%?p{}4^AG-Y!d}O@=1=N"ioD(^G ?`8Dm&Wεy}P:\NAɪU7kuUEg9Of]/5\YRSrHA#`<sTe>HJ2P\\3ݸX x*1"""8'fLDxv $]UY}p/ezU Ļ0Z4غŪZSTJ0ж|'{ ]YM=2H[z3eHO֨V}=`$UPp:$nx_%DFS*Kex.Q 1k1" ٽdUq vO*MΥ%jcػ%>od)0| }";%ld%oD)[^6 JHuwg^c![ѧ>$4)cJUeBGH7C"iͤ?߹3*Gv`:e`-"zw=, xfhL"}݅pJV"I`;9 6s(i g _z<\_(]APxϻI?^9ibr7LWaj##`)2-c`LȿRΏ=0ҧ_y-`vf%`aϡ!xIIaê cڦf`M7 #52dsB۱޺uХzI픦4cQ~4#fTUA`уU|,<,h&Z'l7֢1i~Qxvī% !a"1/'d7Lo;ㄜ6aa%ǫY]"r\]UbqX~gT =U锥b;觠}ۺɗ2a80+76%O宻01ZA]~=MϫAA#NCm,+VH}yVQĈ#;s>,qUe;u>Rݻ|׮Am5LJbM3Cp_}8f8nPqe\*(((CyBB?S8$+L~#tVeE'~ bguόv3ǂZ~| ,cTM5 Aa1Pr/d #e"@T ͝^c3>r2Lhzy _#@ĞgıS߆{)6ZmG$ NWSPp{Դ/<fx3~h^gxKN.ckch(}rxl'X-e|Bm񳟦q.(Dz5<xp<@SW5 c2n[mKBw]; x%e.y]Ū3Π2=o2Ujk=۶qucd]cSVۖ zUJ_~ btxwAŃUPpHHJ`'ruB>*."N82tc%+c6v90ѳfYk5#RםXAnڻ!YZ^C7~`2a=w:1g Uza [=rtrEsMSdN7GAA(#]P 7Jx +VU1Ί>$U}ʎlVBG)&wwU%fe9s+ֆtubyᕾYu}ͼ颋,^Mر󞡵Oo\t3v0K|&κ-?O; .:^m=_`AAx Nh$|X n<1 M'047S*TbEn-1B d^%zeRN`WW z!$s<ꭟ-@DYCҺ7twU  aΰ7_YMwwKT:{l0| zIɇEp3z0?y9'u_=@_r Їxyq2,/si9{Ț6.#bOBYPPp(4@ۜ $sс\{욏Y1ѩ6/my`kQ N h N7:6dL5\\tb׼'vs 2b? " QaK2rSoȮh\9ՠzlq^B 连{8[n'=}y]m- 1Oku: xξ LԤ;UPp0,3ctWݐ0_C_'lO@ #aohtkqSo1"lr0S;IҲ>ȣ[t |KXg.-kesVVVy_E[PPp3?7)]ȿ0?ŋ. H*1``5E]ʃ 9Z7}-Y~AX*7hS?m8w6jcABpvxQVA)B0CI⽀~\#AJSe:zȭ[ً[gիZժFV$oF{.¹۶q ۆC*kA6GLMk`";,ґRj C&Y*HVx5/{Jre%8:(jUiTsY0UWu F%u֝YKK [8 7%WǪ^Ax `"=X$Q`ť]& {P?~xXRس'kL(!WT=WltJW"_kXj]++<}qvzWܙZPPp2[컘n9W/=\g݃e݉Bsϔˇtjך4p$wB7QvF*((8}PVA)B0+U {Ϧ{fwq%Y?{NeDREY$-3޷On˾}dybu8j^y76'W5^ `*̉MS&y.Vuy:ܾ!"H4&BJ$Vz#miYj ϜHXsϙ`]3^%Ž`kPVAi?]X* J6motG7W3LJ`D|e8Xf0X伋pFӈe {HyJ 2099 ƣHLuɑz̤W2L>>62r)WMZ\(XG}%`kQVAI? ,.lgP/R X; ZTU?w1ƀ>W5W^aP֓v%.Pj_p9oxCw y.fOʯ< ,✣%{7=׏/b}l *(8A?Y  v1b*X 1RUTf1cx'޷x5? @z嚇=Ä}8 O~OMWc$z D}l,DBGazd\ R\E;&Z edk]s;JLDgVv k `2i7'G*(8aa**k*Ę@$ BXa$$f=W?xRw>TGT/!o MzLIMլ6ay=]ӸX^b]F{f'V[g[>G͇ߥXPPpRP-;Y\8,I0kIR2fAx|˃'FCXScl1FL<+s ao'>_ׇu6nEr^40uz NDB^gs^ps/ f8 q&盠x `lIe@Z7yHK??cCi'q^o'q5ֈX 0\xI=*==[~^LjSAyCzF$ѺDtW(z`'nS+CPژ{ʕ{%5T"l{cyDŽ7:=6pfc{_>c1jkABA,T)Ƶ9Qދ Z*[ Caa!,KKX\U(5y JVP·5}uTdޛH(uZY ր5ɐ.ǭdύ"f* ]ZAn7]48sXҶQ'ժlMcYH=ȢT&W&kk+Cm,KQ[fF% \Z,((89( VA"D9HjFu.+W.{CXҒ!eKJpanN64, H[ΤF%sYUU /)MYo<|lC 7zQቒBСݽVߊԵ~) XCSC?d,ycLv4ŨŇ(4Gw4l- *(8wҙW4Ëƴb6eBW5*bXkgqTW^^ᛟ,FΨG2ɏ֒=J Jo<<떣E:S`9[x6>q#9:+((86UPp,JNTJ4 U%T%OZpaLwoZs8mE1h/ҠR0>, !&de[9S:CvWE.%.`M? &z5Ao\h;t FoPO(J["N/ʣ+;J5GS}U,~:ꟼMBFIL4de*(UPpx߯^uLQR` k›@Dڗ|/ۮ䏏\U^E .l56D1lS6BUQG5k @0Syx E*(8J6)#!!؜M|q"42ʕH"W-"AB=M:VW=TQQ *dBY4w lT̽) Kj@f%/{C'\UXBSWL_t^>=wE-8 W$f]]3Wv=8oq9Ƥ+O,m\9UbPcZט_̌ltQDԻϑ-emZX{iL*+܃pٻ)*4_bs?)jJm }Q Du*qT0TiQ<POJ (*{*̠{O]+\lz)M0vhձpfr$!-1Vv<#Z49$/u.A2HV,qk0Fx/ŋSfVqwϝoe|mR`bB7ɊެH\Tҹt&-Dv>p? "%g0@Cc퇽ጪ>81lZ&) g x*#Tjp 1 `2EP>jbVO %gZ8 UX:b\áCqX03(M# .$[EA}RB+)X^uh_ +u#rbptRRwb$ιyLzޛo\.xwNJ$̕y}SڠEk$6 Uՙw]$c;1ܾ}w8-Fx~$v#U ޳mʂ1FQ5!2BeC!~=%Ž`PVAq ?`r'mCۆAIrSzUCcXg!X #\|cθ`DO=fmDժ,?XX";mfw)B8b1L8thtк)m<5yI6Uwnr!]YO %#4+ ^dU*ByuhV?T5VتW4֮u]WʺWAMzM UJ(4@ ۷KQϹ܍a͟6x Զ&~7@kLXmXG{ QAX=l *(8+I|e_R󩛰a40Nh)M#yRU3mU#Ymh]\2BW&I‡dXҤ`$/ ^!z?^0NULUa*ʛՎh{㓸;'w^I$'ckܳm?w1tD'^ӎ/^ǞzQ Q@LQ1VTa팴 D}6}ZwQ|ySbr/(*UPpu(f.PK}2=[i1ZɹKKhmØ*j`L樓\]_Ir**C|4ǥm'yq3kևשpfBӎi1#'u#?ɗ0s9H3*ky\Nimh =8dD=LXq ,.V%T1yb14n&{3w G=EPHTw?D*mJ|ې yӶIaATU6{eј gQ-w8̹mɐK0z[]IF紪|AFގ7ν`-UPpxɫ^3\&8 Cc hI^פ{VPP( VAq⥯~yx;SИܛVjqxt8:nL(WiU*%O6z=BHk}匕^E%~2b+؊Ӊh)n:MH~õ֘Ρхѕ#mdk[TZo^Uj*VIX;7Yb0[WCxDZ\SOw _m2&/h BhR {8o͐*1|fnX\<`1!U5d[5u``Du?cp׷2Ϸ Y( VA⥯yydEy&tGB}:b d%9]}/5D+;nP:zʰq q1UPġZ;`ePs޳:m4 >1Ӷ8Uµ|D*m7+5k=**܀LY$g KOBԧNC݄nkǎ@wO8X> Bs`?v۶5|EKx7\daa{$U5VqRRC߳NKLܮ0rxp蜏ljO9ݝW-5XZ@0`be(J|FL-bIb\z]|.'a /xE숴`2DŽ7H\K@cꑬ-$S1]Z3pjv<2$D%X{G6 1Ô0t b"yT ]Z ^L}n!S:8r E2w-D/€/9|zmkkVO*zihzfcGBf> p/ř-7ZW3d%Zc+~J1tO6+|@`??ʂ1MiTUu. M,,<4dy_IVE,.Š=#u(ho}b9GyN?7nλ)u牛-3Iute-3öI:nu0r_^} rlm2U&˸X I/_NyCŃq6)/A RiF!ub8W̼k4+]wHNA#ZM||}Hz2G8< E0"XжJ,Q'޾[WyJ**< 2x_z}`xsE$ZJ@J`:!_iLÁbTk0u1pxsK$.C`#q?Ν=QH%;n o _\Nˁ$v%ZlH!zDJpRNeJb˻J1 Q qs)v1 dǒ\Lt`*$U|l[%X7lTUQTUQ1w,r%YEH4`ꔑ. *h ̽ϖdIRݙ-1kMrX=`'z lDHBDDls?iDN܈j%9F2*LQ8/`0R"RWYiտ%?k>3:"?%lctL.zUvʔ>+RE*LJ49bi#LT.K#ba"e0$ECf,zc7X s5M ~ "B\5MF[%*nA[\vEH~qm ?y2_ FXf6)x'n-75#ɻ &cIҤ+"15seוŮ_.Mt'ֈ?B' <0\3D_&MUܦ铬RaEEE%XGq3H0VzÎ7PYΕ`KDXp#` DQU܊/dIphLƁt]Ց, #mTb Hʙʁ̙X:̡f{]$EjbTL)I[9 :pvX13"!4^i.)HRD8#BBZ*j#!u`Ѣ V""ꓵx ү3N.?{ED5R" ڙh_{-2LB7n907=+*_!x p!r7UH#~ȏ&A`h!#FӢ@n߹}->򒗣e1ktk,}{Q~m%¨yXcDm  5)(W~1ID8z[;^d|ob!y0#UsT_.M4E}V]GLD, QR_ +*P_]9Ko6`8,UXJ*iI=Xr,ԥ`[bpf[ب,cÑ7T2KQrbod3w=ֿ=u VeAߺ|n}(f'Up'Bc :ڨ`<&'?X"534C-;07ރ=1 2UК,0lnzln4%K?pc߮]*btIDRDp& QrH~L #/Vj,=R*¦#}DJ]ĒΔΙǐL/?\9.KPzJ䮱:MҘ""˟bxQ"`yrP6?6)Uswf'LDxt齬Z5 r W^1鱱غK NXq}y: *z$d6KI!)U4soXQ= Gq 4M6 dDH-\"L)WѸSlBP#.PdJi&ջI]z̋Ĉ+v0g!kD_XOZ.+%~un;af\/AT"hgJChL݇xb2੧]MC_mEŵJ**Qzk/PH=LIG\wHI0AAIltx -kEDs`[xbBq lD%dkĥh scRnᴃ ,t9} U.8ojP|Θ%K;=_ \yQK} Bhh`^)cvZRKb77G8zmT%¨`)Z[91bxLQCA+^P VE<qRcxhB}$yO*U,J*XSBja{'ɕ+: zˎ%.DB Y{ lO49AȊZ($ZUYk)Aq:^~K"),vV(v,^aQ""O#Gf=v]6bj pQ(<\r,VT\i%sCAt$r^T]^G|/7*T/fKl;>ƻ%RTC<^9XA8 %JqJUKJ8ټb݅LH{>`T$7Q\*Oځًwq,rPWyNL?~a4c<;]Iz}X]7kSQ|CU**(='Onie=Veb%PĦa~2VO4s͌Xtӗ@Oy\,?dP~x>ԭYH~-)I}A4<]J^="c;q\y˫q[{sQ9}{c: SΉu)WE`UT[%JTɂ}J<˃qAJ\c<~tMU+IbA,?ZI6b_bBɤqh0LS Y:JG!jjhvӟL*۴u)(r+IU\z۸70V[V ~o2*UTTUQ1'DWԎξx'z#r( +h Y:G.w(. h]Y7uMRS(+ TVD  0. >΁)M4{m}:&@իT"DE@.=&}2u#2q*U-q 2[~ 1~~!DVD.#b+˳DWhIAWr0fzYLj̍u:,, 6\'*2ay Q`A)|N=Pdd$ʄ{EX=c.dwBMv7;q"W!2byEAO )wzK݁WTxk zW\?NL[JdJ-9Y$#I,ܙu5yJ\4fi\'&;e+Sl) 8q%?gciyb*- v켝%ФVW1M zfx,EX־kh!f 4%ͩG/ۈ!zI~Q;׋gs[Ǯ%7JK}943+%AΞ;5~ͧPo/;**戭x4\% YPiGll? 41k}JfȌlj0̈́S6$zCzų'Gb>Eq2ίg#= %ϯ_~h!f 9fῸߺ7!>zX B!}+^]+N "eiե**W<0NjTo-sɛàPt^|]bDlRGǓe%౵VJjzՁ_H~ -Âm}=-!RC6#Gj}J̌fVT\9X{͛^`mRd$C7\AtRR'p M$aKM@J_o%eV't]P&^hFĶ| -/y*s}N5DjC |͏%S}-QGڄtr $oׄ`n1hXKa66\0"icP޾W^/f6W.{n]dG0ob2:\UTDTUQغX)Q ֎L@kRE)F"x=3{"_\J݇#G/k] H#+XkuŔIA&Lebe*bUgE0B NjOl%]>yB*NL/>#T+Ĭt"sWFv66 $:^T9|߸ߋvYv޶m#V0(_Z%P VEcb Tu$Se8e 6W!4/ߟÄ`EozЇi%+ݻB*UYqNLt"A`"X\mG% HOB 8y= OR\(7ʌꉒ,fk"N\e5-reԿ,@#.уU&T8 cv.V[F61ok: `UT\l `0w`A` z'g @UŞE3D=jyt^'U*fa*a%B#^#@77`Tvi?]?{s=wة^O qq߸]>qUDŽ[dR$kDk ׉s_ֿ J{h7tYdHɥDtP}$8& t!_zBLF )b6*Wcph%3@q-#1~eb7gKJ8rctz2 ߄W bnmT ْ 1ȝ, iI4H.yz`h̃3E w˾'tr{*UA+<]M д05I1$@!:: LuΊ ֹѺ:Q%>9U~߅/h&"6"ctw>ߨ>P VEUF鍫i['o',A{ie&ED?o+?~l~)Yd(M)n"0E=I Y$03+իHMꛖBȔ(2+4-0Cs+D*6fٍ=ԱRU7cQ Bh$ă)jZJ@VJ,zw-=wJH@uM=?Wt܊`UT\AJH VbyNPWV*˱h4xx9[I "$ [TATlc9F̈Q@rȈ׺U|NydI5H`h7i,v^\GSdyv_/x]+**`UT\pM˂tAb@ SȿX@)T9v;|8l'. &W.dI/IT},fHSjO*W\f8Qv"!nÏˌ-{OݦHDl%eVmakx+z䪌 TUQuMhN{8YKZ\{^: !g<W ]p|H$菒q>K03:b8f HnLA%, ED Rr_fZ@j\[$?Di6MC(gM3^'LT^kZ][7ٻ**TUQq/=`ma Fp1 Kтԉw:9 x_q7d1c#UW53z1VF;%I@R(-2B"XB`xJ$-]c1 bYs֬dqqe kv*%G YE;4V:>-ucB)"FE.TEb~b<\Cp{`@gwb~B A Cu4cbxuKkiXz{#"~ai Ϗf m.r +** *Nd 8C)ʈ3o7)Z1?!1=RV}"STfR2gx7X C*M"{ *Yی(+vϭ &gJɕH2PRrFj`%ʮiÌD-1 !^Jr,N,t"}TUQuChh~ 7'w3w*s:CLٌAC&&<4,NcR!J P3x`*:ll4MsH;g݉A 8D$GsRo!E3:q0Y]1*W13Ě$ 3Ō4PM]QQqU0hy.ƌ-8~RTX.ii YL]nO0ifٯaW⁏^~1⩻6;Q %fx쵾utJ>LwҾoy5ӗ1^fC"u bciUl*ۈtLNiWKZ]k1 DXQ:D}Ffcfa4iFB&fvڌ8B"Ul 1Z߂ ac {:Zhq'0#KJ`HVD(Db CXh)8oYFӑ6t. F50-1{G%YH ص`2o\~_IsD%Xްf7[= dscl)Po1mL1&ћ=1s #Ujwu; G ڳ.aŷcY1,Jշ#)E++SF^G*&% DɒN$Z& :0AK:}&T*TD, vk6$: Mr$o%GE~0_PQ1?TVEun="|"TZ,͞4"Ȗ9GP/UQH8oR8r%@M7ɭl:6E+ěe~X9j1t^j ._X;IVfnQ4@R#I3b^ ` 8JЁDZ a31:" s>L0l;D|AOM0 (<;=jƮM柬DXQ4sV^TM%2]SVu(үw Jfx|7ME+.&c, 3?xGҮm93BoG:_,R` _wct~>c8*bqeW1v2IGI0]?RD.",ՃUQ1?TUQO0#iױ}>)i, R:7q "ȒCVJeʈ8E6?eϩOwؾgWTH, IϨN/~YK!K%;@I|*ƒ&x'oyǛm4"(TktxСƘLFtۘt#LnIDkJU AIqR3\㰰|"*˘{bUZE?OŒU+.xOp  qSAl^$w(+jtz1o${%!{'I꺑y1ltKciuKMqu8\l)H`UT]RLfBBV"e@VHXY2oTT(_'+r $BRғu7gzKRx=HJU>Md2hx$+U]7Bu7UoW fc)2!(^&b~b`b">sx"T JH2 WddB"Dnɀn͏ecT' u,=qD DDMm<!n܋jt&u||͕-Y :4Xp p+X5b~]{*`AɄ@@J3ْ`E&lUaD=I @bh;D#!1,:"*n{\;U;`q,R | -˥"wwxEkxrc]8 @dl؊}J**҃s#&H Q"ı+bClI,FĘc4by#tq @07ae:Aը$Zr<'H'9o7><?_^WmnFg }6lr%ŠF%X1TRE Uqu׿҆Vq9<|E&mT{E>@ׅ=`E;4s^n{0ueziHw୭[=3Æmh2C@`y(0,Xg)y %C$(PTTwg-l=unu)^.]g2ZQ1TUQysDCc[ <M :85Kb T#/Ȗz,jB;{+׀S4*M4< @'f3TJ Յδ\ɫxPmm9+F@~AA)Ƚ#qB"bP[.6& |}]SpQfHa!'v+d:x9!/*@|ÍF d̮GJt~bjӁŌ@ⲩ[C++E|pk_kg7:d/2TB're)&9cϭ8wUTT\o8'QI>t~ 3iRXeGbE0//!yak_|ͮsI+ܡ9_3aHW-y Qպ}I]v9ŽvVTՃUQ_poīGᙳO+ZtxmiZ`3T ^@+[Z!Լ+x/G?To5tߑշfan*|Yy>"<Y)bx?al<8߰\=aEp޹V 'OGp_p4TTU'&Jq}TOClw Vb l_z94Zg?p8u;ZW4{uGp#P~,w:j0 b _yWTT;\WTT;^MyP@LX.oZ \d x,.Iu Ÿ0;8qg NAgPܫSaϵsGz {+%2VO½ՏUQqb"գpءl>@.(MR V`ʮ,+#ie\{!V;34JdTP=SBE'&p?o/Q=XE%X]g]U^G``>M,<- `"]Ł#sY`{+ܵ$%F3(KEYĈ1ߊ`$ˮ31I@yaͮŠF"Zj"qD4 4aB GXK@/b#UɈS>VV@)2$Oi!X;0VOl1Y/"ec:b%Š}'G{B/>xyNƥC*51X k s,]f`%f+Ҵtp3lFwG O슊k U'9GZ:JX 'B%{}&D%*$ IDAThX˃=<(x<Ꝋc qGaQHF!с07'NhE8q`UTU/(ޕbhH$HS?xJ+z :Nu'dv!eCTF}Ueds &ƛseb7q<\@ìE2j]eŘ&[lmk(Vʰ32%sZX2?偓f$VEEP VE>go2Gmh.]9E dWFD'犯L0܊GN*XVb\aYEvt#[*1.WTT.*'ނF޼UBQDjWgl_x/\SSPXWtsFl ;e0.@)ʾ30M,+QKY#W2aYuTUQ#;ae颂xEI rl\R8WBE #$DEUIF|Wft_;sL8e-i'jaEUƒy4M3@MX]~5`v`bxꙏZΒݽE; %v;@K,x/護]ӜR @v:)8v!J\AfdQ<*e; F D+** AcR6[q߻_KGժcTUQ'p`*r-hinN'xьpM-B0C\4ywYu$D$Q%̔&gAvU*|Jq*C`E|QK{?/~2e rPD>>6n`/ও=X۩+/Z,|&D^gWD'R%Tn0mtjbWڙG瑞&VzTU**TUQ1gx%UFb8qg)S&_qC_qI#ef`VHY"T 8vct9Dqh'Y*^;>)G++]Y)/snM_UT`UT 4p܂A"N9@y gt|v8q`/~2?; [ U$f]GEBt}2ES{<%JcGV٩Ȍglj[@aʄbbN? vt.*)*lS%.moDT'Yלqy?y +ONIĩ_9FHҊR1͠^0ֶQ3**J**{>qMQ +e>t=1W$ jGs@Ӡ9qHߏYBڭvXa"1u3ZXx\ d@\J TP)\U/*$TO$PyكV`8h\)M/>+RrP Ap$} "N>XΝMZ-dSxnnsNBs޶GpVHU뷥HB5ARzx=ld! )KJ&]6Ϻ:~Ѝ#j(+ ciF^bnbeϬG4<'0o"w!?;pH Wg[&Yzd BT]m`al X[_&zHgA!N9T|ˆd~XJnz**J**v Ǔ %bJw)n!B18"7*T!a8d-)WM$1EoR"pk4TT(#YOK0E @G8 z>i⨀籃d1_:hm>=WTT`UTby/="7i,1 p,h[U" LUښlfB(+j^^͗""#Uǎf21^_O R<{ѬTM-V,l}<%Ϳ+d\y]B.WOPE$'W"\:o! 0hY0Þ޽}-[TO]ce§]qs. TiS0Q&a[9~q%;u4rIɛv@4w^Q17TUQ sv0[c|?^5bbիb/dJɔaP!xH0K"Yih, FK0M;Rޖ>>/ɵ3 zŷ*Ce@>Cd*=H.ˢ Yx[EÌxP@ EUɤnQɊd*E1)j,f0輪W/!Hf6>ںݐQЙ݇* KmɹI8 e,W6g^|AEGTQE%Xe$ $e$  x@Dz'llL0 ƣ []\ȥ$?UaT9̗Y@TX"f0V_UT`UTraFT)TQaIVW1]k#ccC.XV fbyGpkmQ#Y[n+=#ǎ WV.x<",-)J%*i4i-FQGv66*J ^@EŵUn"RC l @'Dk]P+|UXZ3S HyZ"%>xlFkU¹&.Ҳ/m:yE~CU**v TjJ1(&}C*k86kGXߘ`{;`<O,B,k,=bt i7xhBJ_4y >DX 1hi4)A5XZ/|=ZBakǯM7 C mh54a'ލn{\Ly;$7J}W]rhz.Y\ xw"Vx،):FSvu^37' , @ݯSgUnLlP%33[ LE&Pr[ :s( XL[b2ǎg-d*]_GTE/K`)0)ĸPw:tWʹZJ]Mjh54а0BUky$cQD*d Bt%=V3* K b+A\ J~[o.ɾ} y0+wX@TtZ-2#;w2Ҽzp5{(Μ?W౿kkk^ե&Bu|R.Ԙ׻r-aJ ;_ʳrRJ1?- m$ w *xXwk20!F VQ.RW.R:C_Wv&+ }ihh-4аC`fHrM$KAI3 %X"2%K Qz։q:Fp'7c<^*#Yb hdt1D,~32$b1h JdGs'XǢA~+Wp]vO'T2:`zĸȯc.Xֻa8,s/`xL.$FTq#/^ BGF f#G L m\ȌlYg ;|8:sWzaPč ݣ/; H(d_VlKD6Î$E鱎Gdsp#wL`L0ԣ 㑣PDUtgOSNBG1zUGfVgаhao_\*4>yg&I쨇HۺxX_K{̜:}^q#7ё &P*ћT1EP_@ QA]weEQ 轣ڟիA#W o4а;F$o lY쥪UR8t*PD&u-o[;lFx0lؐp食oT*@؍, ©IrqoXz7j]G#X ;=V ]EQ{_<_\zvmLNCޠ]_:rTJ(Jo+gԌULj *x׭=yc]jE7`Y4~]ԊSTEA$Š}3G89 H.Z6/A%E1U<CCCaq؏A KOb>,%8SUL!.@11%rl / PpYJCCwc.[ /}> b ,BHm)?bFU| 㖲cj2аha!D|+`peZISC5(XFh0ۭcA/ƩN)ect礭]Ѕk[W&S +m[PtugN܇4ӃL`e&  lv7Cs>ޟXC[`542=n#YdcrJ/YqaÞ1骺9JfxrBh-PE:03fO)66],=]fT(=|?٭Vu3 '`@l%B"-:0? }۾B#X {sʅ`W Pf.iTI)0 %r̼=Tf#~:B 9Rry+7V?~ RP `ec]3/LkXMJ0eʂiD,@7mQs,09q\IG!@!8|/6ywKpݡ=?,C5R(PTq21B]dwm;~̏?X%%zr3 lxoG;~o0)(D&)XUD?[JK3lYDMjhZ4&$bRTDY9MjYa@Xتc̣x}޽ VMERq?Q>l@!Fd̓žgA0rgT{1*H%PHt?ӫؕmhx7h%VZ f3`j:cU(✵Qcq y=,[&SeVl"Ggd!024 yV% S3SpGwj1iixxQf\و'd[˳Eihΰf׍Ulm ]!p#o(@޶o~q ܊՛oudORKJ/1:Cwi/UbMZYL7~"tx#&%Xgn,}'ObJ\N޷@"Yu;B L'#0#Ͼ^khhXFS$].«]TJaPWS* u=CRBx [˳o@{10ē]h̉_XͪUYd"dP)0' BQ!B`n[|/Mp%4/A0QI~l| XEU;8yy;țuqZq.Z$]ۊO䤹ȈL&VwvU)Od%=*"Eb%*?ɖb2VV++ dM'L&@DϾWa)X 78=m(XٲA=Kl C&aKM= N̳OcHG*YN=;{s SBnu1dsw!'PG0ۺXDٌ`1fh/ duQ IDATG.|g־\}`543vP)y+jφfo$\ze#JIg'*G`F`B EnjߖM*(YGWlj@!P;%m&{ͪ,XD%. &tYZYf3W:_&aZn! C_GC>CdawHÿ:1b]j蜓؉qpছ#PN::29q.z V&dC2^o  )u8 q0 ƈ㒊ʕL'KTML&ЙTMF" cy44ܠPx<árE6pS#SRqRҺyR:&LC .`/3%Yx'erW+`"_y:/hc{ĸ(dJl>+WN&`2ULgd:qb+ ."fOyayn@ts"'XU$})$sL"at2Hs4Or +E4)&ĦLE@H(T(!/)[_@ B!J E~d~$e)c0 ˆq0U6Ή0?\EӉeD$*QH,C]jh>} T9#n{w^Npr2][/WV2+Paa`uĘƴ)5f]g #O1Gî\s X׍eB'P,HX%25d2@ 2,_(hM"K͇а-p!'WDg_zX`Ml,"t0|(1c" De0)1J.CFɲGݿ{PI!JKLYT=|ȱ"#$"$ <%g+`żL&W/ @eG0=Z jhgLGYU1{BJ9"ޢ "t RG 31x9FLĈVy6%I:rnytTy ;bWЁ9B6A<U_ܱ^Fpr (LcyM5BUAv @+*@bpDȀ;D,/]炋c^T; b䬚Y9Xv44\hϼl|g dH1=p 0& tOd9!R33o:@d4%T3<#oIU X/<"B.Pz>\Z"B{;|g`W댫1lBsDxDVSUW:D8@sVpK,Dp&6*2DԞ-ha!VrvG<#=!;9b#5bX|0#I+M()@3~I_:"x\ɍw%B$/O {g\8Jd$s_0oʋ8Aσa3R ̜5&,QVK{S8sbp =J`qBƦz%Nݍa54lNlhQP%'C;{09`ULEЩ O)U*+cZ TC' >7@l!`@c2A;S8rm΁ _\ө?O] Jʎ>^']"YOe1]܉y{yQTӯnΝ[`cC#Qc叾VCSb *X^j J18sA50 UA+nbՑ}3!oщ*z#)p8SS,O=$***ETa/v 7fQl`Q)Vi+X5Jec?G D `%cլ;Hpb, 0O{ -@ɛ&|!1l544h VC zDRT>+`0>+`ɻ*)20%*fX&>os٧**=QaZah\iIar%|UTb)*2%%KLrFq &^yu38~Ec{W8 b\)v-`543{vvT+[سvDqߋ/'UE'bF]J^8Fd~.1GD8S8 Ho\Y5yGO(*Fjee_}$~x */HAT7{?UM"AB$@%@#8@4@b/1SL<7s`Ĝ;*캤L-obh VC J m |#V`X"l0Rju>?<"CbHNO #>^$"XSKi$չSi1a? Ƕ=\0{vE@Nf7U*Rht1QC!=ܰ@ W6_y74VC O$*5ĩ zFX&Mz.)P Ԡt=kD|$bL O=dqWn3}3B`]_Rށ:HbmQ"WeZ{U*F7ef{-#Ns>7cˆ1X,6n4аx)fgMk:fuXF.VX琱BL'/8+Y L%UEe+R5 Kd4.֪V޷rbU3dUk!Y];~ҕ@?Ի? ?ʑc 9vRU!. aOkIsbtpyny̐Dg6SUW~R49-틋ޭ{/MY|-szdj }s]6bO0UQ8M((("NN`0ٵ:[ȇ FDS(kϷvDMy6 {5IUia} *$!溦B!6GUBk", L-DEoN_64Hh VC>͆}GW TQ^*Jj|Eu+He, |M1dR8P6/YQFT\eUu.}^j+VХ+ZER+#X=_$Ή+!tRbYSމsIU"QC\*Ki0+d qc6Xl`ckgCÍFn d;d}N]Cw)MDĈ$RU{FRo[MrWI+m)ՠa(c,"Yv>v)6+*n%WF=A=`U!jUo8wSUð~a71ǽ>z߼G#X 1{='40rMjB@&Zœś-i9e#z]*ܮ߿LfkǬ;o\8D>|q dbWʇF+@bCtŖ -_oScyZNd$(ZՏU=ZmA&aI~شq%,_95444p]'ܘ]|?5efQ^FPn/uT틜Mn!Qi뷍G<ȓat D>d nQJw"`E/{2At%8s%W*nR)ҰT/چ4/JNMdXʈFr%RF0(y|.[\lmyJ?|9T,S4h%?%n!),AnVe1=4O+.Zm_{>|y544lA#X I<%<{q#X| WuEU(Z#ƌTRⶪv WVjoUz]waįN`Id]Uy0 J1+Yf1l!WiyPP}< M/UC*”,7Si"Y2<c~`? ,1_Dڸt[mVC daFHV+#|1ɒp Z2_=LlP#wC/F `.[ٗDʢte3DCK&8,A|7%{/E6$r%^u2/.!VJK͹g+R^ӎ(~wUke@F2FRjscƆ<bD*ZjWE"P1_D铏 d7>@5ðeRq>id4ob@o K‚O79Ά@"lhg1ł@z8\ v"T o Q+ZCɩJ9X1/)3U*ʼA_b~Cf%^i1V6t96ugTVɋJszξ[FԺ{=~c˵rxƃG{N9qPRfhPb\Az?k䪡a7L@RUyŖ?n (Yn (TrQUzZ(*wRcT",B/m'dMq#;(`8{4Љb,z6Z1TKZ[g*Ѯř6 ȣ(ˇʒc3Ñ6aVC ~wp2,^U@H1(D^>dIVHL8)_Ȟ9uK>diީ>pv?|`uFb>#ws#Tu=ij 2۶LTѩ.GuXF`*r"v>n'цvʡCvXbCw^GCC΢<9K[^w>.DʃFe?#I=R"'~ӏXQ}_ nwxk%N;}TRso1E-ۨ $〾 X,ISJ0T&ǤpMV\;~544:jhx?+?Oqو;$ESL&0B=w3y:ˆd0){(P6JG1J{~Ta@Q*60 :xpBqB| _xxv\f"W$)X V"lhx܏Of<Sf_C#t]gN\:`&1)@|WcLÞCgC/r+(b#_#wU:-ޫsafBzy >Hy&\yM'.{])L6: p)& W+f*vmEzژĩ'ihh=4a|<w+d+e"fYg38 0cy c;vlg~q) .,Y0J}Cx]_-y*~'@j1upYRK/wQ)͔RM?:sI0YP2(}VDHmf?. ʄi!ΊDҵKf~bSvMjh#<)0V2b<`cZmҺgxq1p#:||SUgaJHjUތx@J0VZ]|%ڌ@Q;t ݋eV} ROVʮ~SyY) K1w{We0 t)򤄳AR ]Lk4BGm%†=DS*|" WY<5ޥV+Z]7Aq^5V7.8Yլ'ZҕTL|0j?:qwXuLp~re){弬Uw/F2[>էR SK>-(b4*JC_320oC ^-1Zj' {`54T*Stz\UE>HA00PqA8_Bq_.e8ؚE7U*y{5_(ӘrC~L IDAT#2U,nK2=JS?z)$Il%S"/¢@]z'kSXU.Kɏɏ>=A#X YU:g U!2r<1ۙp0ލKk>Αj0~LRRT@9X DNheBxq}alY)Kq嗰vVuiDRǸޫw]0f$2ZVhdkg%BIѫE#X {8"JZ`p}D zPZd7CX+RC$Pn7q/aiF.=Nfx03Aq+,_KAxh[HV,"ۑh%doc}j+kFZJqsaeBQ3VWTz"eIT/G]444jh%r\-ng` 5F%H}0qe>0FU/-Q7 @ѻ{85;~)TA! tƤj0,+4ۭvQUQF[)(sqg0&R/_ Leφ=C#X '=?߮=SYp#trC6r&)~&n+ lNd-6jƆ+F]fSH&Rd*{JYܗ2wa<./i]ѱlb2:#f+tSda3y5Ϲhxb=M-aoVC.L`I0dv5}&#X̅`-JQ[ʥksh0REʭ>?xȅ4{P> 2YP Y)ă3[ 6Tz:',]m~5䙗 3e*>"kv= _Z0$jDђz}I"t;8!$*]۶1C{{Iwe$*SuvDM e.|"&5Qscә}*wN&DJ˿)J_9k_ZVC㉿qVp.DjLd:|W]KBp%'0ELǯ7z#˄e;Q<$2JX>ێ^+{յR|tbyJרP&0V-OJQz{а;haQ{ Ï"N*R%U'anU+ A"3sG_1T!vU9|$c_\h_2`h֥c+}U絯oH՟DL\*dVjh 4аWq=UEF3 P P.-S+㕕~Ӯ?U^}'rT3FM|Ay?} {2k=+1d4\ %zG_к`),?_YihhjhaXwo= L9@jbYR'9VVQ1_XT)cKk!Wx|X-l%TnV Y)ouնG;g kFRaUh>B==߲zlQ kcS`540J. V$+WPS$+A@P0j`1G PA,mb ^>T:\nhbrgU+:݃[M)]tĭq՟a}W JU;0WT9Kc .†]LR;F0<P* VdќPa0`PĨ`n6W}e:9UEJ"L>ż=5,W+:"w!o3\&:pG@:']J :zQJ~z: Dn|J3"XU*b寙1_]˻ ] mhK4аH&u+YBj7Em`=C'Z݄ UF bLĒt?\r(o{" f\JYVt=3)VS{FJVJ0J:W"!^%4ސF*!_*X)\q]^64\haKN,*Kl Ui"D)V12.m NB~PMRy蝂N_/J&kTjWb~ A&Zۚщn*wй3",O}>Px]Tƨ;FVxs%p+Y9A8а_VC.`LʬAUJ`N4Tsl%Be\8}jQ@ %62@ԢD5 "QeSԫHV&vĕ)5=#*#3?N)S C>* bK Ss+ T]UEU}O8<G#X WDu&cϺ2`E+! %QI7uTQDk&XvԋRDJJVF*]seImQ>t=H("եw}ERJ3]:s'Y}EW%ʢtrʢ[F_ ̓аwha1*'V`$CRGXx$RF>aU.$J4)00t"M@ev;V7u!I!.'0EHBL!φLs=#bc:7?zibr-<$+]BVG/jh x:_GRֳꪎИKL 2'_\rL%31.^)Mp@̀faR׷()۰^ىx&ÿVTjoBN*0>:H@LW]іа'hrv}ݙ80ˉ@ňDu^l}*1X)Ő<T L[p ||2pDа]YR,yhz演hXJ & L,a۠"$TRRkp XyCpCSbee:ZrDVP*V(#=SP2̻Vނl'4RV $Z{Cޢ]½xN~a^, (¢2 @,6Pji癬TFGO1rKRә_c{]*%Uufڐi[Wԉ3e3WRgGoޑsoX&ߙpّ:DаߓC1cmU7/ %D/V@)B+1{=1Jpٖ2a]ҳ%A0^`[z-]BJ :z"ju{+|p[_7K$3CE8UަG ĸѻwFJ8QNZ"L(d+?VlJeΟrW`ɟd=1" mhhطh%†=@.f0k7C;!ċ%AWX B(m@&wܷb"f3bhTŞZu* L@UVLEŒVMݽsާA:!@MDS{@L`v)bGsʷɊ=qk&tJәF݃KzZgt!Ye[:!XeRWyX'Gnڵs~Mjh#wE1;K"?鵨@%½Ʀ}OYU8ջڦ3 ϫj6Jdv꺼MLʕ8]̠FWõ]E#X {~=%%F 8߷W38ct:؅E.7qyfu\ZVη4X1>'j9,={>=9`54IHD뱇_˗}YV*Fk^"Yi8% NH^-JVSj灉f)0 >.z_»N}K::=nd7hLN~z @ˋd)s䌦ĒķUԀ ׊x_ru@Y1!;{>t׆craVC>C"Sޱ/p1H D`/d!s2;I,kDI}Z>ОfCr>O|ci2*oW7 =/3nhhh] g 7(W4Y9QY@haI4FU1z78DS٬?H*I^p_k6oQd픒u%r7Iw n]7)8.=};̎#0F#X Ùp\U$0y!,,Jam}G7!F($h_+_.Dœ\Is)O:~Ur+W &0E&`8MCCoDO@]Y4. W1]wX,Er-Rb&#B#TOzTLհ@)d?ZhYE@[_|F` +1q%o$jy`2F A|=\ojVCES)TЕ N83g@H Mu.leWÀM`v->\pSe$$au)Lf3tjI#EL(]J=-fexJ Rխ(QVqFVf+Xk:`54w\jC>^jUK/[sz , don3$ި8_UPITu`R9+Tkɢjz1L8W} `54S9|+X"}]l,p&UP) Z\3[f+HB4u%jżw·ZKbzrZR]GL0\~!h+_]8𪎯)X #ᚱCw䨧ȋ.aJGzM:M?)MgMir"se5U軾P-[+feK[fpYjW3 ̩ ohCGv_}=>kG#X "v3F^U  S |~eSS"ʾ|^l[$507ؠDg f5ϧQb].[5'G˕[7JGC ̊.p*?3oZX&R#\`54{$u U bU#WU3Ut -znUDUD476pzH?ed :$VpVo:FR]aEwl@J (;k"P(kyN0өW̄㍢ 2%byh`g~kD"W׃z4VCC[^c0k"bTA5/ƈ!_,궕ܺ;W ЩSBp7[18c Qv%J!fcYi)8CcWT"X*(_ QVL0&S`2/*޵7аoE_Kh ̉rN"xYUL#H0O]""KW˛agfݴs^!WɌU`JT`X2R5jĤ13f3B@tA{S^|.#а4kG\5˝> RAp*{g$u̬9BH*(db0 )$?9& RDB & C1]][f{?{3uOosDMUeU5yG2-B^roҼB\pi0DAX_M`ЉbzYYj0 ` QD>=V$>sj*T>iTr yNvE"9RhGiWU Ҍqd GkEJ~Mۯ+ա_ֺob;JmK!ysj/ -ek>!fog?z9KK!9p`0(%?V{ώQd" "FTucHźd9[uaAp2-,.E+5?:b$i+G.>d[q| b$,QI}iG@%7yB]MlĖp2ķ.IóK")s,b p8]'{bb@L T5b*p0 #?B0e'x#"+`="a0c 7_B*)~ͭ]!63ʻ$*]x\nԝC՗jvOj?76 !{6K*V `iH Ihե Th;0Xqұ#턌uj{mZOBA WF5!OBWd%UB U L3j tuKVgpbP+X^+ez X׌U\ ̪t"0Kǿ޸X8F1HcrSS|ziV [6Epm8GH,kv8kE۪X7=3Ѓ=e y,rc2!1 X,`!kfc18rdmag/_ť8պ5$ i=UM)$մqُ(T]ȋB]kĂAu"ҜP38Ӌ c)}IDATC b@a@Yըk9#bɴuJD!Pl0 8[TK'HcN~7gu[vW>A?Lp9DWvT$z{;+uZ~L4xc)о}OX.jL&%&*ޗMk%B{fm1#c`e'3?ԌY([+MҹJlv_B^XxgoCp WbP|!J'i &az@! ~KB\ 2p _"MeZY#,4miDK~?4xXqYRDĎNJ8"dr+:?X6a"|M?Ldys.bo[W?\ҡİSֶ?Eā\7*S{< B LoMa-UDrpAH@fzf~ x"4J4jǦYk`zmB^ir_=piz]_X5+ӵ߿ɽb! X8ݷ3uG`ۅZbWÇ !<kj׼/{G. (IUT:YV2~?BD Nr{UbL$ Si`ST|}= sX{NXTZ(W[{)@pt$Ƀ҉_HZAW):(5;qڒXzⱿx0e'79fN}[)`%H7Њhwal9r8w߻pVGSپ^Itn/蹦V HzBF7ɆDeYY `qlsIJ`ߊaOhp$hXWŐ>+m spDp Ͽ6J~Ym2Y=cn#_S\G|VQq(Q8R__q & 8S'GU@Qǒ7J>VVq]1K/1H#L$.^oYʍlYUlS2(kpToU^_O{W!T*W5|wv\+a l&@4j+VRkgјFBѥl sϿ؜R㻊"ku5-R#UqX*V]Ai`\mx_WWm<.lWw?ĢIagUR/He^}G0E8G^=*\+vwYJQ]ތì-`-Qq3YmASc 0 !J~ya->^uOb2+h긽W Xq1skf$R.;6+Q> =j5kҧc]%WL-?am\Ο{mmv㱤1,VU4G;mJ^֣q ^u?j?_L`Ɖ&+k>V]!R PB+8Y1مլkI'a%^zY<ƴNhO_}QG}cRWTwX jBڗj@U/.=`O"sx+wɽqb0IWv=ٽJôڰ#[Yu*XVj3W ۟?<ƏnTǍjۂm:{2"GCڷUK7^xa<=^ý)>tO偘2m`7^nx#TVa@Yh#B(RJdª+j_\`uW9zy xk GqVv [sXrvUvtq̗xOT% fgzpp j ~8o`fG1 m3BA) <@=@i=" Bs7oV]?Xa" + 1;uqT|k{:fa2 `]HV!/# 9C#\URŖQn&otaG\ 9pGU?1GO081f{wN 5p,pDkkyN G;ƿ~kÛ:7O?]vf! C| D6/\B;O<2&  V /z ^QTe[~x[5FWdB1At% $QXHcmAѡ#!o)(zovfj}'Xеr[a G}\u8}xXqƨ E7ȚEx J\/?8-) MUIZ?5Wi{d0«^{;B]=TVrHRF2d Hr2@W#Ov~)Md7^;urM*WҦi w?~2a2/g3LffQ;O2~kSg E/Cޭ/(**ҟǫY(wT@VVKe\śQ"(aRXȉ._息p²⵺7l>a5E1>.l0̗EaWIg2 YFs1AB˥oV1F^"+sCq QrD mEsכ9;9~V@u7qHtj Kv~2k]qQ`ML`gq.oq~c7Yty3 $a@, 0XaQyyΑV9E(2{`8SoFWf; a]cDXY_RdC#W~_wK݅D$^֡B`sn qԘ2 TXɋU8 GpF ~u0NI-F X1eƙTSd *0 sٙїtQ8zL`qf 12S DdԷh?nB`C 5 h1e3b^k=m%">تc>J<9!om[0Xa&E73 h1e}Hsm3ʅ+Q0`И 8zL`a<;;լXcgE>֪Q:'*B8zL`a<Q^Z0G-Ѹ@Uݪ|&5A À ,0'{*(zr }8Sa6O|Gb(Ya!,TT0x0G˅lVa!iOa%& 0=~@Wa~57խ4{(baG ,0LUTedsխX*64sS' ~Zq2 8B+yQ񸇼piVULw*,cACFChG ,0c$] /kg׌ŢlZa1x+ڪUQ8rL`a|͘%1skV`4*0^zf{v*̦վDO E8K2 8̧5wngs G9.^*sN2:Q,h0Xad߾sZqZ3rlĹ6(0Xa f5'zaMm%2#a)g1=/k=[<)0a׌˦xC Y aOWq|2 0 8dL`aa2& 0 0Xaa ,0 0Caa!c0 0 1eaqȘ2 0 8d?)*[]IENDB`v_sim-3.8.0/tests/exports/iso.ref.png000077700000000000000000000000001370110300500213462iso-3.7.pngustar00rootroot00000000000000v_sim-3.8.0/tests/exports/link.ascii000066400000000000000000000007111370110300500174410ustar00rootroot00000000000000# Test for links 30 0 2 0 0 30 #keyword: angstroem 0.5 1 1 Au 4.0 1 1 Au 0.5 1 5 Au 5.0 1 5 Au 0.5 1 9 Au 6.0 1 9 Au 0.5 1 13 Au 7.0 1 13 Au 15.5 1 1 Au 19.0 1 1 Ni 15.5 1 5 Au 20.0 1 5 Ni 15.5 1 9 Au 21.0 1 9 Ni 15.5 1 13 Au 22.0 1 13 Ni 0.5 1 16 Ni 4.0 1 16 Ni 0.5 1 20 Ni 5.0 1 20 Ni 0.5 1 24 Ni 6.0 1 24 Ni 0.5 1 28 Ni 7.0 1 28 Ni 15.5 1 16 Au 19.0 1 16 Mo 15.5 1 20 Au 20.0 1 20 Mo 15.5 1 24 Au 21.0 1 24 Mo 15.5 1 28 Au 22.0 1 28 Mo v_sim-3.8.0/tests/exports/links.ref.png000066400000000000000000001351751370110300500201100ustar00rootroot00000000000000PNG  IHDRXXfsBIT|d IDATx$}wfUϡelQ)R0MlE,}&E ,AHg-ċ;Q&t$Z`$)D ؝̼gvffȭꞞڞO++̍]5 X""""s%"""2g X""""s%"""2g X""""s%"""2g X""""s%"""2gQܷY{җ8UDDDDLKDDDdΎ|FpyàS':_-""" X[yV@k  |b""""K7omC><3d2k @ǀ `Oyo=O-qKDDd^ofEC`-!3 [̃q|_,t2`Z G!G\fm f*YL\6l ᦛadYFߧ=0f0v^֊,73\25|P7Mdc C[|c E Ao&,A( :nno_ .n&Ν;+яhE狿<_,˚masYf,\i0P<ۜjkrkl { w@q7 n6di!민7qm~Z!7NM;u׾o^6,=F0xK Xy9YqKh+v竞r'Xob ƕ+B0Ê`2V0W zېxzӖ~ 7St}6[^wйvnN.^@eYϯYϷ=yߠs`o>X.am Y=AKm9UB YCt0*=A#ՊPBw9} 0o"{9R!BYQަeńx~;f{޹stC:\>ۏ^*c0v曹[p^9㨦?XqUՉV^A W^U JϨTr K*[>wa"'\f9,eY1.^ۋm8,^ףs=ڟayMCs`ZUU80P%ш^ŋxx&MYMx}TAJ֨ KO^hDo-cݘ+WjQtzq>{~?JQ;8bv@QK/\oDL?ۍyy9s9hp8( \Bic{'>US>nz=znu,L zUVQ{CGɱe.~5-cr[X?F1 XZ^02sCu*;ιUo SW&\UUEedY.yS/Bhh'>P#z+2׀8'k\dee3_ef=:0,b+`t v^C kbr1(Ӻ1իJ= WUT5'}rY7)\1WیM|O5w&'5K8 d\NwFd墨Ξ!ɡcaYq!?e,c0׮Q61_~2}?eTeY6]61UqV س6*!g`ŏ,ndJ,`'rk.;t&TJo:C1+•CEܦ4>M<_̛ϜL܈Ex{>=~!a`o1ܭ{djhQ 8ɦ"ތ6SzI!kooph4b45g[yQzo鐕 Fn篼gz"gz-Gq1L}at+Ƴ;l1/&sLkx'UJVM}֠9|jћ{,=zf! fOsc9Ȳ9~ʺ3?Hfߞ kk u P[p>;wdNDtζcOҪ\:`y/7j:der2zwllD6g#=3t0FWFa=(3 ˽+<;v0JU5 Wܸ~ǻݗC!U?ܖ8q+9U,!vb5SW:y\T|cwBdnR7DeV5ßK`kD,8@05%"" =uo>8^DDDZd;PDDD99S#"3$2חf 5G((z=ɧVE}]|q-+AʤeS `BRkpe1vn xAV5vᅯaרq[ !_^d4kfVRjZ>NE6b{`@yz[[}z>EQS/[k0ܮsf%&Oםm lmmv!^y +>Nl};ݗu;9_ z@QpJ:_o{9o0g֒9m:P:U356`e6շ (.\s`1߹RmqWZLaղu.\s" ?|#F !+N5|{|};PN-=k`Z!Nh{/6CCUtj:`y_~+"kCf՝XYoukn"ϩb4ۣnbڊea>!2*c(סKͺ1q+ײ&@ ji|`o0!#ta XaH| I8%˞6>tkU;l!i{{1w~. f_>c nE̠IJNT!EO4>(g~rwwit֌'pZ&` 6VB݄=p8v+ =&z>Լ})eiXi{snY"M|Ϗ4N m),9U5^o- 494o_CRU,g봴ij=zݮƾ-HzÁp47}/^TH Z1`Z᪩`Őu{?=1M(JAjVҼ}Iz#s~g"˷yzS!LN=ooSx89 g\b;[K\l7ۘ$PD4B{U+xX塬oMP iLIM\Pc=X;3\1Y,ijDV\=@jp1Xj"t :X` 7A\Ҁo [Y"Fkht߾{PF :0jse7}[i}pgVӵCh_O5XTp V^wUu5+_MU:]}"nW'~i pǴtΑS93CU:hW^ԥtdc(`-J{ (L4xk UUU^U:UYN>:Akpgj˨,KzZO - S!΃Z\5䎳jjAYB6q=bRx6PK f\ZduZ>0ReYl>>vr7ZdT:܈bly$a:%T*@YzFULwq ,_ϗ.Y*xTŚ5kUӕ+#''Hkf`]It#RWhaW)azYև K(+խbkWVS]JsNjz,KoxEOVUERjCh5U&l(:x :|J) V׺"KKNU:a@PSƏZU0Ble`Xyg%dNO콟\Kj5~7M&a|]vK _kMWFuekT6,ᥗux_ t\EmSe+\Dg˱Ϻ>n4L98?{TCհ Xzs{pT^n)5G~3֛ri/qDwxo濂a;dQ`o], Z=_kΞ~~LJOsef]>g3y8Kgr3r>CU_Wn5O8!KD"Uu~_<CtXqZ ýl•,*X aPEosjz9j% ! zBU(t])\(`-?(2FC7{G8s _y2_\-^|?|xk$R:jjj>DDMKΜp+_DdYL܈ {[W52oAi:pul;*Y9,9S/}Z2 #/xDD4M1iՋxKDDd)`əW""+Y Xrfh ,934JDDօ%""BKu%g_:Q3ADDd(`əW""N+Y7 Xri,94JDD֍z%""FKN5uzDNB6~:t >.&GgW"T毾s[@ceجck22.*lr(`-كO>ֺc<#+۞brEO?_m{! 1C:uˬ(x?fPZ IDATx}1O=zpPbvo~;c^K2t;ufJm#;͌eCnbs{>QQZ~I3yg1Xc0]!LA{>ZF½NG)ӄvV:9tq~G_,O"Yt{;1֒ey-O-'Ͳ/\1k~+(xG?rpP_"0VMTځjt{[[֣s.袈lU'ߑ*/vrtt:bUK=9]vdf֡ҾN^ !C*⡟0r:!s߻7P%fV  Y6[>nyd%!ƊzZzD9U1j\ϬmUӡ( )4TUsz9 U(}tȲl"`L7nr|RSS5ث8LǠ=ul`!Pފϯ߫>^W^YV^ Xs2 WV;\5:`+X{vw B8aazVLUڡ V Z{{{ogۡUb*SͬU+3[nS};0#p+aユ_{n§ 6}[/Ml"V6PV퀕e|'?D:D8g* WwT}t&CUjY6&*]< b8.7+awybj^oZ")b4%v Ǽ/TM)xԂKCxX0 /yеB}(=tsS96NV"*X'pXE|`eۍ՗nnNs&+[u%{=^sX3ǫBU{iW^obePkߊ~cXkΚ4K{}hеUk7r*dU-,Vt YM ]JcDDhֻ.^9YDFkPPGz!+~Cf-YЪFa#_sEYBYY՟e}̥Z: ܸr5`u VdТC UrAڭ}BI%s~F!ET:=0VYc֍Km@H!LT꘮~ƹز\IhRP>\sVsಀc9U<&P/bl}h0 !)ͭkמfwל[O 4}(`ݠCGBw+kzیckzVS.dC&ǔz6DEhb21CslCS:PyLȊ2_)_s`3+zj"Xycy7WTP@:Zeo&l&'mdiΔyf +V!bKyN&*XaN}6u 0n3|4LVTL XY]xd媭9ׄɳM KfX# MSjZaaLS,冏fVf٫J"ף T9b%"X3w&p}>4qo>ScBzS7δZ}g0u2\o%p=]_5JDSAO?ȁv~ Fb5}A!; *\ i;hJ\@zbu# SCV`li? Oӳgx)`-A{ Cۇ}QwLg9龛zJY9,Y2),SG0LU+c5B Xz^O10nl{EN }qiWt}v6•k8WV a!@a|1hYBUJkld8C@fUp%r$ X'pj\99( s8w@YRՊY +V),0c" &''= _hm;]l6X6 XK7踇 a~Nj*Raufyh,[5!iـ }&a{f_Om,:cW ^Ua+(Y?cCs e\`TѴtYpCg9GYep8[۷zEN9Xv9 j}8 mՕ(SHT;LU_UQYYnlJͥp5WxkENS,e,U,_êPUhoO0q{XƶڇqeYRUшݳM9dog1$hq xnкQ+H ˺jUp+ߵ.:v/Fwv[(r)`"rH~8X,Z'eUB}>,X6F7_ޗuˏ7,9{Gxץ2_\֭s/>˟<߸<YV|Ze xW^߭p%"%kkpk\=犷DVFYs V"< X273@3HYG [:3QDdd- ^*Wߵ-u4~şx347킈̓%k܋p+SW""r)`+9dhv Xv4JDDN;,Y;%""@K֊_Y%kEDD,PW""r(`+9+dmh X64JDD ,Y%""g$__-z6rx8 GsD` X4J]/.:^:9!d@n ˯۱Fo?Uol,Y %y7ˠ̐g` cfn@5խ}ϼ+l)`-?{~emR=c}̟_Ʉ?G2t;Y֐1uÕaGKD>{O1™Z^:;/^b7T%YÔi/M UE `C\-Y E@TjKXcȲ<ɳ,<'s<]ȑ>j?S9%CLiCɫ:ض-"_x;'"Ak|11k-y-,ա#s:eA'ۿ7n>j:"+_">Õ Zvrtn=ڊ7!qM7dwx]V]ݲX&HM 4ZKӡ`GZ !9h4;q?St:{;Æ]<(2bjx `X >f1`k=Ȼ`Kn{`F` }<[p-WIӡ(惉k-Y=7dY1UoR…iVz VEOH*vvv塧k`N;稪 k-;׮-R~[Ǝ|*b¤AZv`c`+p%c V7ZMoi;oS_{a.tp:Y Mjַ6 lo͹sz{=zZCfo•ni}>܎%x`])P`E+LV78nmyȷتiu(?p׾TR&Ve48zփ>̾siASsu'WfFhF5ףۺUcyvc1^;S)DW7,_2H |F7cDz T Tӭ( k'/>&aի?2L6ff{&tLܹqv{=lvTv:>t*{rմ~m\m X;Z`MrBu`Tˁn p&}wĔRJի־RjnK%sҽY(~1,o^,Q{e UZcC&\X{/B},1!뿜MVWb*ԕP`B6U~*d`ɥu+F1fbYj:XV:KyzQDd!e}v qn܈ڿg-/\5f0xci r$iVg5q\W<8bҲ?PFR:f]&VLjN{?cuOEtrڪxr9q7W @؀B *%dž!xFРA?9m l]YZ;\MJU+y7 Y)\vJ1"2IkxO\Y6. KTe\ !7_/ ޅFt•e!gf&wpPL][&\A(&xB9"pu*cU9BtZ@e ƴ7bEi 7Ve^^UXm]ՇK]}mizvJWDY,%K/t)(ti6=U=n"흧Ԧf9Aɩ?Нz޾;[t,qT0l*V!7",CU<h WㄷP S>Z)"su~#Ot9+X$ȵoOAv&abur5 mlԀkV%>7u#.+ :`:`5ϸ~chO&HAkv'KDGk:XSykN c{v¥Ll53@l@S]_9^OwBV~ɚf͋52JF ^")OsL>MWqӦ/q/ׄ+b*6LW.e2PVQae R*{0Yƙ.al߼•")`a!_kY+N9Gp\Ӎ[R PUV1XgX2]vk1=<,dM4F6+p,G"GkN#9X,#.|hWbJMU1P0nUdQϗUO޺i2:>+TUUEYMj7]S:*;n]'lfY:`USP#J5_O_+wPkKʲZD,9U.e&Lb 8&R SDj}R6,6 l;Jj*r"PMW9e [-"5~_Y|9d-Vɠ5J㲦\20,Qkϯgz!jo&\|6QDfPeorKgq Wnᬠ5XanUw+7c IDAT@Gd&Lj4q.a+EMk9`lre>ZŚ5{*4١5ae`wF_p{дôVuyPD4=#u3ws \02k,2SE Pk.Ï1=m};J%kbFVsU*a/!XOא[ c4+9TZ_{S*:=Xu.'wJVc lS7aT*\(`-?(2>>>,~[O_9q"muܠ[l ^c /"r,7~ /}a⊷jW+9mSZn?KDdd273++Q`t܊B,९p]+9+fvRu% ugzQ^㉋?M4M,Xu+Q+T X0%""JKFDDdS)`hl*,YM% W""d!4JDD6,_&S+t X2w%""NKNDDd)`il:,+Q9+Wrh,C:2.`,cGnl$,+Ey߃^:CZYF|EL\!6bϮ"9V[>?͹!>XÏh,ğ{@f ̂5`1;2L<{ Y"x XK1<v@ֶr:/3tg`S@u22)VfnXzgV;9聟~1UBXyH90TA}hSEy]bg44 ZWCn y?ο\bDd,(Pc֒eyMӉPd\~? `كO>=1ygc6.x1%Vf[C~@?scx>L^,9}wB hT?eɡ;2+Ẁϣ^M%t:yNQ>wvWm"r2`a$È5N`0l[[lmmv1Ƭƿdvԏ,U͒%q(b\3_^vAh](εv6!^~׋:m99Upeոn4(7頻 c {ʲ\d#nY5۟2Kh8$=8-rZz{Uv| eJ`vF lC Sfw X8ׂ1Tu:Mj7`bTw݂sƋKV9UR;\eYFc줶SmΝ;GףȲ~`\Moc04zkSqg/aG|Q|! Za=`\lm yE1!kgt˲n;})"󡀵`/c,' -b{`4cBBAY]۱u+%ҖSbV*~+T4[!?ָ[)"[3=WBhZnOWڇ S8SY X'ti AbafiŹsS;GՇZJDm[0ȷ)R뀵jw?sw՜5h M`L Z&6 6C!d|BN! =L/6[YG Vj:deY6m9s`5g۵I;g.USyOGrCWhzRK]Pt:TRUEGRB6V{ +[O=8O .k,u?辯!)!>wǐW2׆!Cv -Cq/+h X`ޕ)Q^^},{-,˙EHG8sʈ8'"#GUף8Y'#2yD_ !@3ǵrET *iH0%"ļƓE ^EHd AbYh-ׯFGNId-h8\X\Rp吡j4e( ׆$]V>D ]Q(F{Ӗ+CDU#+:Cߵ?ȹT!xﳨ !,O*-ݐ,M*J e2a+RYB̀s'~O~B4aB!_!f}Y0:E9ä] @^*Fd8pJ, bD\q!PS-feH\4 zǪ(990aH{f{i\{}rWVM*!΁TyĕaCg*.3Y޷ѫh{/FbV]ƥNP)rhӚZK07XrR>VjyὟ/?o}r,`V-II'DrX wF.Y\rkEUF"Wi& 1  9.f{uZk<4nvyN"&7}^@~cfT^eіdiT!NJAbm+JFVVF\\gO~?~&ɝeS6~s .I»Q\90 b"H> ,|ۏߟdA9R^YL޻,~OjY=*J L`@yIaPaRQ+_$\@~%UɔSVJD\NWePk)HʻQ1R^2]`ztF| Ab>89/GyS30=:*Th+ob^ v(>cл8A1߀طHJyɆri",ȕl6* fd<)4ǾFG/ϟ{>'|'E.Xf6C+LnQv)Y~+s {;pE<  q!U^ʈU!Gls4z( K;6lLL gίC9bYNb=vrBǯ#+O|f.mӫDʳ Nak& s@E(QhUX)U>'N UܲvYdʋd_`O`| "Y²g{=sm$K$*ŕg4q@~x!#n*YYvAܝK)#JaU~-}Шl&*<{2 kY~&\^H LN[會[HT6GѮy à}f& +d`"bl{1l3n+,c7UnKqUF40NrE*g IWk^"GYG*.͠,D\N냲X\yΫ/4ѸY#6Kx/ ûŏ\j9zC}>9)5ܖv||ڃUܨ' E6oYQ)eP+O|.Ͻ/DX99F〙c̚&1m8( A;eAX$Y)jN(kA*vIX0 P.JVGDhaB+KA,E\eFR"kMӨR G9YmYV94zb5:Cbq89V[1UZL=0k?X%e;ޣi(E abG*ꞆBC":ݟ4dƘ49J+.l [Wv,XK2*׮C>N%SsD֏VƬ) c:cL啖?3EL$fpYq*T`- ?]4"+ÁYDKBk 51]piD&|[V|d,XKDKne96-q_Ɓт3XMĈՌqEYhw*ŕ@ C9F$+o>R+@œ&*6u/*]e8!%tMP55 Wmg>^q(k}M{{iVX7k_BӄxCQѤ\6fOb"Rj.WXl4gfNRV|t{EQ.Xl@:mTKE(B([G_8?O[?)tT(-((ʒ%0TUA?]f"G?F`P+.{ * ZFmTq5L_Vo?RlK&W߸znET`-} ;N).Ht3H"+4nK)ІėGV.Q;k(żw|#`vi%HKX{~QY8"úVZt1U;1;|Ow  < 4Ў_x\cPI#=gQjlQnj۟׈Ǻx0h-ڎ)⊨{oWҦ?tWڞNT*-g?0R,¥U]u7Fn<,d;* )߁_eTE$)?ui10}ͶCʥ/`<|n#݇#,Z[`8F9X+15k3~rVQ6X䱗0̜sduEDIY F#`4VA_6q;"ї0*ڡE't"Y;pk绂Оc欠-0Z>#sl/t͓|*) *k *kVU ?siǮ( 英#M1G-HD|N~8tu뺵ʴ6&>qD#/<6CEnV!/uwȺ {w/bEg$aUh |EZʺiFX]Zѫ[ P5!?qPQ*.)2?=|` mLBhd݀m-`@un!P dhC:]J7#11#ХUiF߷zO->Me@ c@ y0.0S;,sb(l8\P|wE&E_Ұz}`F()& cyN*clwk8MD`0tZDD.(W-?pํ^IL ."V'"YGsK@&ڗ1PIvUQ{v?po4}FٶªtG!nE}n=q,08|{997)~eQupn./rB` NB+0ek'-ĸ i@B<;TX@F9S=0Zd~JY)s{ X:ԮXjc6l 9j=WND4Ìǭm֢q{r\ 3CxoEb_-l VQ4 , 1}U }n}aUWq{7Үx~s Yh-:䆆b9nWwʿ1kbi([Jf0q} 0(r%PuNHJu:wt:$LHT%wu%E2vWn_X𞴥r!vZLE~.:Kpª4XkuQeC; vHVPyh@@6C}mc:bi[k<5wm5K+c}n<Uwwkl<Є [A!v>LQ@@<T`( wϯlk`ׁ0h&5 ϳIi}>X;JO`M6nMQ,`Z SUY qc#@3 0ˆI` 0x|:ݦ*W4U|evBH9*vV  IDAT"(2m9[BuaqQ`bqVҏdV!`6X`L{␣0*IH #pɷQ+a'}qU,BW`φa;>O~7Càt6* K&qqnӹfpZ >$ 0WD&yۊs="%"SK3c"JQ*DJxOy"B<`/΀DQi$2W2u{`0zWi;C=!&?{o@Qi캢] ("G >/N/+O|f.=?DŽ40~cW4&c9לͷ h,&xυNg (ef4M94`)WX eR.I3 mU\Q,p`y 2+r pוy{筯F(0SWŢvE9_cՓVXJB0{vuO_n4\Bxs.%XkѧDkK xɹ@pBE,eK'@y3r|{~$0Oytϫ(~.?+.sH8M^H2@tբsܟܰDη1yveǦ( 3p!Dy8q*^EM10J>4rSqS"AGfxN*uL7;h'g 79$ ]2:::ζ+ %^4'fa q>>Kŝv`D]2!p"F"P|$-9,ܴ$yvsZLUa8:ŕݓ~,R4B+-+jk@`dpofXIԊ5(tΞɳE 㬲#?tpS4^0pT~_Ս"bP- O1cZe#$a8f_ݽWb9 AE\5v[^CHD Ŏަx3YO$[/ϟ%ߴB0*Es||IP;<\.Rʒ?g ks\CؕoYPi\T`utE^{В cF:,+3kWG\* m~N\yg}] [tup ve(MDN37q򂵭jжywR:DxNxOvqh||l^~߬aL}xOdzht|: %{oh|ovp">j{fP9] '9xHrJ 'u ŒOw(i1j"&Sƽ 7W38M[E`te_,hlNo~]w<9Gnj{E*+媢k ܯS(;2$lr4%OIC*vT,n>si ۩D MTI 1r%2YZ::;ϲѪl $k ˓4.vVW;h  k"YjMF9GeKEzz~OFgMWQ(XK$y딟/; F&OeJur3~/_z\} :s' @`|^ ϨRyT``O5;@:@[|܏tI&ńi@ɜq:6\{e|ϚFQX+E4MX9,6LFNSժӜ_{S{1co[(vx?k/i⪈?'_?{~[k>a<?s??v;¢4Sv_fvQBgyϺax}rU\>ڞϵ;_5l*-͗_߾#Q̿RlRvGW_[(Wr~T`);Ð'^}FQͿRKNʿRh\ XΠW<4JQ. ,eg+EY(Ch,ͿRK 4JQ_)Q(CRvͿRWrqT`)[_)+EY*Geyh,X֣W<4JQ ,e+EY(AuV+EY(ˣZ\OU쏀h *&PU{GAQRW>ݻa-~ ~ G^Y*_ Q0gʺmOgAeyZ!?}:Fch j`PPWU,I` Ok UA-~5by]-:x)\{YpK;F@e{mJUnQ+EY*V@x ArG`w]@(0nw OaoUm uX XƤj۟}]է0za PY5>*u'z!<{g5JQ %/-#Pt3 A.4 >/z b>&FIRT D⧴5 8|i?~u썀P[9҆(}>bݐ6u/\zHP3+6"uS9#tQ jE!# Q0*'MmTuRx=X\jcO~rTQvXK?ސr(7[uL<@L ppWvCd bǘDRVS* (,MEK"0X8J?[YXh_PKwWd&j.NDk sKQ*.~9]'Q﨑"1)#0uB(HI]E8\XB·J@ߒ@~@E֦V!*Vc95Ea c}ĆMߵ["QWYXcmVYrFT`]G_<3MD]Sk' $ƣkUQ1Eֶ P,Pd1JF@:F)rUWDS<,"i8]֏^ $w:pS c`0 :6101Ud)PuN~!F`( +O}@>I` [U@u3T4QEUwXL!ڀ^,3J{ nEEQ k`d>SVGu$ 0+6v~kV\EJK^WUx=co]kC*T:'V<&S\tDDS@77M}#P݈"*7ƄǷK,Q3w}Gw_Jh0 %qԁ&]߮ȋm YrnpY? k{cX*n7BLAZۉPcE%joa<c4RSmkrD5;ln0c(>+12kqKڗeBG8&'IX-03n}G?;~3;B"8|Gqt=M iT)2 jT2SqӒUt}bN IVv4n-pÂi37Z`lpAߝ}(4uaxap/)b"/Oz?F]J3b!(Lb٪rn 0 y췢-QLT~4Efớm^k1Z* lkk smR&ޓ#X)YI<3Ҍ 0{{󶿏ܸ͛mo4;:#p iEe )H L` 5< %U;Rv*担E~ O)w9itb;PcnwWEQKݐzr=ՏPFp ԋ!!8ҏdeO4/X{{{{Q\]pQg&]$O$~ dppv+ DAa,Kc'Y+K7&~l}س;#|'wYd0|a&vRy/0Hh ll֍RxWWvùyP,ޔXFNWf?GiKQNF9ɳV|] fEŠb8@U/KqEј~'|#r SVw;,21l]خzR֋UQXD!UksÎ;F/ 4dR`p3Eak1FUUvRf$?苃^D^Jq`[QR\JÅ[rKSCOXBm.UveK:͎BъG7W^E 9~>r\?:uEFmsjrYT#Eѫ%{84M.0(&+o .",8dF^MRn<ҭ @]3z4H>*։Zw!aB 9n6ڐ/ې:z[ad  8@ɖEK"X,f˲w6 ?]:59XUȯL5 K^[~w?( oߦDžo Wwka^OH}+JMFAy],f[mWp0R?`H`=^knڭAƆsك݈V `碨2&Τl=R\k ) iDPjB0!u" pS @J"+܋w޷їƷj[":PAfuĨgƄ"#&1L5e/~%Q+'ԅVj6rz9NIxi gvX r~Lƫ+^'ԍm\Y!B'H8u !=JQ9T`*r@!\y^mHxaua V9 StěO)bj"*ъh 㧰!D_eqU u;R`T#X Fm۲ v5 F8];xpejbm^YdC3g ޣL kL0wn6cW-A9IV&D;0.dQcd9.lFa*b!Q+Vb?-/}B8p>s)?.3èaW2Iǔ,磱ۅPnܶ+KuuAC~$ǝ^mC 2j:&p;mjmNV37 1 9ahf3L݃Nw)2 sR.K oo0,MjY?Aqrx r ͤ3h$Հ8`zEbT3xa&ͱ&ِq`?-B1y&nvM]}HEuosJ*Jh0/wq 0SL}lW,^Q vc`aqNᝃ5F~"Xdk.Rt:N qja]D )IXmp:ܬgg5}_&,ppe}URja >+~6U6^y3syXbnDx^ꆈ$;klGg c8Y$q 5Mgi8wwqw '9SyYHs俙c44o{IcxӜ7eːUnGmUmW6]/}a"\tt(`4s JwݲR$%͈>6?/1 cM)K$Ml$b !XNˈ+wA4 3ˌ,]f2Yfr UXq1uJۊl [4 j7?iWEj,֋njf$٥ "WrvT`-u \lUQdzLE Lf"&;rUYI}7wyw|v8U>ւQhW1W$&ͻ]7!T\)eDM7/È#4M@^Qښvu$~o~)>-( +ۮsP7 McbJusW^$?yvQZ2<딟Gi2`Fk ԙvH* 񕏾 U,+ R7ʅIhO'q՗}/޲QG v)W-bDi Z!aoWgW ֍qn~ۚDQ*Vh};٤z'D y赏W^WoW/_ZEdthjxO}k_Bgqk*Ϳ̭5*ok?Q6pW#~S6kw8k>E:,Be#yK%뷯Heo=#Q ,e#y}( ,e7ë?o^(vWT`)Gʿz(Aqh,ͿRK84JQ_)zPl(Ce}R6 ͿRW>T`)_)+EY*BeyhXƠW<4JQ֋ ,ec+EY(E1h,ͿRK4JQ_)zQl(CeT>::h 8?ddkCsuJ{x huE+X`^{Tc݇l{)~XL{|w==ͿRk< T* PA ,pG}S> ?y 7!a8F`_Ud owuxH *UlS(c+W>iX+y1aE],hIh@Gvu S6!Gȕk=C)*\nQO('EUeт:n'ͿRkɼPpj*+Ca`e80aQUeuM8|Bh+ :uz*AOX?4nX*e]< P!H̘v$m*T @ i~iӓ|9~dWFT`-(⍴+#yV& +H >!Bmf$Be+2vm,?-*?@ilT./Ĩԧʴ7)"-B_7/4nn3"N#@g(do#uU5[7&`oC}PA+a:G'H+2$Pݒa[~[ȟQN/ g.>K_L]U6v8G$R`0x<ޜc$rQuN 7ݥڨC.ȀH.'SX k߾1ZuJ$aw@8|勌G^8gtBpN")7*v4jΈu'MHFzVc9=e/Weo}AX?qU'B]F]qY>9Y2T`G^F5KQVoٶ_8h#7)b3u"6,,bDF]fEed0G>n `,,e~>0!NĊRd+2]5q #b ?3^ZX@r"huVy*EB^]pmnٺhWEb]ZmMGP9*ZpS$6eTU9lP% P.售qeQxWy!!@C 3MLIW'Cܞx( Ξy[/eITk@CmnSF^,WWR{mR{0)Øema Vǿ+b=H\(hVV4c=-~1`,[SAIC^nczC>3 Q,lu q"(2]7"B33VZV+w\(HD^g4 K0i $ U5jL|܊Kf P=#$QV(V` 6X quG":h[y "Wq 9*1y.s/! 87MQvX$_adS|Pmqa(.dVǰ@r*:2ݕoCc(eO3.i;ASIz4v^[^+*{ '*[Mvj: M Q04Rں[qxΡIm"R\1cr|{ܻw򐣢(F93d"̧4>8? >;؄j^\ເk /qx˸\|z _C/p[~6i,}P X6 w0Oc*2HG蹵ꊮ\I#v%u>FB :܌C߃ M=oZR*Yںd©jS.P=L^g**PuNRȞE@Y8XAЖD [! _]IM̀f(M˷ 0 \[iỷ+cbٍ!T~ KCQ`f3;At17Ũw~Jm gꓡvGҦRںe\#ѪiWMܢH]9La)I$V6 LK> cz| &UQvXLwN1g8O b/1X ƻ8pM"Dqk $ۢ-?78fm!(E\O8@97<񙅉vVY\,4g8b*T:(UlW,I_z';$+k[+bGNq8 dq;z?.l'̔eCcL{Phq$y%hmz7X8MJz^&6Ӿb5J!ftyX'! A?虂Ipqo<{(QdJLi;)nL 2t:;@~ G.q&xsRŘ\[4%W~>" q%q6&|Wi" W{cqsR"K^^֡)Ҕh'q@H b`H0`'@ 1@@^yJ`H,+X(F [1L;R%Q$ĽΜ]C]̜9gsvvvS_WWWy0rUyps+hB0`AFq| 5L@SJvwϛJ\~{\#8; Ň+`;/PCҩoNgHGwǖF9 ++%C;~QlU-ւi&ؚm{*؞~Ǐ_NѸo0#tx~w HG1G̏heRvM>$Bb1`-H Wƴ!_I؀I O6\R*ꄭ ;so\pIaVjW*Cؚ ~{*Zta"Z<#حC'@:2~%hM%͵->uv9żQv;ߡ;Ǧf* Y7~߼viWӺ!0UeUӮ[--g{O,$1\#ڭCx\Rb{T'bLu3{{";[?s:~߭?: nOb;뿱%KV?o/Ȭ nخQx򷧾ѢI=^;h V6eHlxD{?O85}Vy'g:<1WnWTuT;:-j^x~mbtȖu=63\-9cSum5}nO^|hwm3ul Àu^~k u|wf.W_|/}4wt^~ߏlW.>yһPg_ p''D4i[='#D@yOxOh,Zl{6ο"Z- X0wT{;Bt pja5V - _V -_V-_V-_V-_VWDzWD+ĀE+pjbqQ8h51`Q8?Eށz˨T;]:Ņ3 J?Wt-1~͓ޥpb:$F#=C`XWQJ+l8 |Ons kC`8u( ,mkc+OvTz!0cipQa2xCX W-ƃʟ/O[|Su7px'.rъb/( h h+? `S,cx+Fy&Zf;6W^\΍/c8Te}k_{B{TjIB:prsv U9=x_pw=|'cDEؓ{_XǙx׌LJ %Z5&:x0ZǏ@a8#>\wܱvjHd5ʇE=\/K @'+jo156w=}YqVb#+vI%p=ĨpDń^\_~IRֱu4#Wy E~( 6޶ؠHu?jY!#FЄMZ7(xS{1i֚AhE0`=/c4h_?֙ʂ`h!P!47: Ĵjc#)6cv1 [،FogȢKWӥiW b{f  cj'`entxo #ZDaI>?F%8?DpV=:L4 !k{>p(%Y~kƲ5 00tha+b"u''8b"UkX+W%PB841&7bB{2!LLt؊DQxׯ~p!MDGǀu_l*N01&{0lo)\e,KlRG#u(Ռ(Z|ޛYPtF B Š]CQu?CԤb l*n1d C{Lq3=*pކ(0 0110qa4hG"<_6>NbO#XO- JԽ;0f)30z39{`p勇+/s4ORmuzFX m@6{'@m#w#=wK6*Ky@1m1o 6`,pvxw*ߔ1eYb0(4?#MSsw=Ż Gp-.~TA(JA "`ސmw99p;05P~QC` dG .txP u0&KWӥ)b $m P=cL,)!,4R5okka<a4c<Ak~-` WJ$|;:U u6>rll}럣#F09x ФE߉ DT MWag°t#dA ZJ{"ԈmLOE+' Y0V)h Q ՅpCϗ-e[Km *lh( RM2)S+TSީX :R pNparzC_%|G6 5MMe|UJcɡ٤ija|{Lm1N\⊺p/q RJ,w/Á1'T(G#تZѾ0`@+P ~+_j}K6Q>X)P>DI %3j!pDeW`%c%i! ZJ| jVRk/_&[=`'B4*Hv79)(I[7RPZC 1Ԍ-LQ5Dˆ!i?mgsvlY'G|ؐJҙv7ъ#ڤOk) 77m0EUS`:?tsͨH+Xc ݐO67DK)CAu'[ J ٰSIeaQ4$䭺S}&k3E T'5# X1mt,I4ˇH\/a#I6iC]5D?Y6,`9 =>{/հKj{FZA sX kLOeuDCjC NP=8%RY(5dD3c+`k$ .#s{QiTv(tڮ#D_GTG68Қ[ c+;iQc*+Lkh[C )qu Xv{LgoHVZÅ_+f/B5cg"R4>VPT|jB %R;)L5LKaUSV++qͿvcZ!z`eB2R:8jKaׯsfG Kh?X '0Zhk V{S9fuXyYDt њq*Wo)H At~^?u Vdz;vC@Q ~ACYGT8|h!N *{ijQ:PbjL Kv|I.Ǖx-˄{h]s.ͽZ:^+%€ճ47)8i'0~u-v UPBAYUʆ!P"?<Õsu_s_\{>Y:@;k~}uHw)/t -6ǕQ+WSP-RZ5A((Du`B\-!| gٸ .;:#V+%!$= Q?栙Zt>;&6_;uƖ8?җ׾/|3Iv m b@B&\GuQ,vGmgcra-H=כd^k¨!_AM~_snPD;$ƫN|-tBb:LҺah&+[|A[~$<&0ښ#;d$%CuYgT#WDˋ3FzD@dgJ+H~-3 du+ZuZ\aXG\)>(9zuz'?;`ORqq%aǷ(BbwW}?hOm3{?4ìP=`(Imkl~#=? $Y'8PR+@8G/TMeGѽulę*lUG^uTCtwGVHnZW*Dzs\-'^|[< pb;TYjq_Ƶ ],NzNt;{9|3}1h4FR.T#wokx 8vƞu4،:R M` t:9QA-ԯ?/=ϢWQjTóIΩÀՓՅy]λ~o{_(4 PEQDPQEi4*(JQ!TEQ (hTEQFB(4BEQѨ*(FPQEi4*(JQ!TEQ (hTEQFB(4BEQѨ*(FPQEi4*(JQ!TEQ (hTEQFB(4BEQѨ*(FPQEi4*(JQ!TEQ (hTEQFB(4BEQѨ*(FPQEi4*(JQ!TEQ (hTEQFB(4BEQѨ*(FPQEi4*(JQ!TEQ (hTEQFB(4BEQѨ*(FPQEi4*(JQ!TEQ (hTEQFB(4BEQѨ*(FPQEi4*(JQ!TEQ (hTEQFB(4BEQѨ*(FPQEi4*(JQ!TEQ (hTEQFB(4BEQѨ*(FPQEi4*(JQ!TEQ (hTEQFB(4BEQѨ*(FPQEi4*(JQ!TEQ (hTEQFB(4BEQѨ*(FPQEi4*(JQ!TEQ (hTEQFB(4BEQѨ*(FPQEi4*(J{rE[0rEQeyP!l.Ql̰̬Ҩ(JsP!l.@e Ȑql3[(D0"[زB"(33ZfVMFEQV *F A\7!2Ȁ!TRܩVQQ aq6/ %"c@"Cd(PTZv?%0*"P!l0,o\@D b)FI"ֲVQQ'¦sOA0aDd HP+c&*,?*ES#f.JC&E"DyWj)Xɨ(2B\AͅD XUPM$PTK⒭TaTeQ!l. &"Zxh5"21"D@:񣖥Uo(K aaaem7 &2(2&v1'&̶E<6*ͅ 0ef-}E&( "CQ%)2=X+Q!l4"|R%ےEDp4dLTk "ej9(@<28fEt(bLCHG"*X\j2*ҋ asa\ \Zs+Eb!؂󦖥-J 4ڲPQQ aq}F (2LıXF~bQإ,,lۢԚ Ei*-uZ6+z&MQDqDQl(I(I ErۢEeBhX*oz( [vGؘđ1ű@dE, . [vٖ(BllIe%̸gıIp$J}\61WQQV6*er/ɢ,lYάı'Ƶ2Q,"WQQV*edē^L0sy^QD1(MDd(I>?Ti<"/<ɨ6[ \0H!ʼnc&#Eq7-2/l(ʓ aa&kqa<+󬜙vDI$F [5Q:dYY,UeP!l4',,*h(ojliEGHӨ͠ [eٲyny(ʓ aa^,+]n* L4d4$wH!c^tqzʙFݤ&M4DM_Ef. e6:ɨ4¦D*k3[2H(MFIj4"2i۠(lEa;e4Ui* eoe2i86"IbYvK1~[RV%*MGG#CrD&c*rjG"ƐU1EYVf"ɨT[&Ҍ&[(iE4c>eeњ eEBtݨr/e)dtıI[Qڊ4S껈"vf ',+WBvZJ,1Cb*ijk4b1 @HnR;EgVMFeP!l:,Qep&UZZqڑ+3MFΛ:[tdT¦c-(Rר`-3U͆bQdL_šu-٠m)fgls6EGXPPY>d JԴV+{1Iҁ4tfN5@ Zg;3qbZQZՎMF>UؚZ<,*MGrLQ mgS.1ULFijEv$&M]-c7M,VEY*MLD B&cx&ILbxdƧTBoMǖLH'Kɻ`T M^P!TP&T-TVEPUVn?єOAYZ"ı1(+nشyާ2:IYH-+1qmRT@DZ \ gg BOAY2q2e{iQA*(K hQee\GgY'˳,e%>eD5 Uȭ3i>*5Jq-Bёl5 DؤaBި*$afנ(1g81:P* ’ V\SO|QVzSw[YcXkt4]J[WAP$qT(צAجF2zSUV6O]"[Ty\FYQ T>=DZ!\ƧRJ#TV/׮LeJ/* cj*+2ye]j`& )疈TsꔕʼF{4hʌҍ ea uHy$i2)PZ>l YT>5DZLJ)D*LdQ@o| QRרve65eF O5 u*+$_mj*))N4kTY!^kK P!T,QerLMfSYMxM@o|C'*+&R\ B @ll_aƾ(*J,J#( { G,ZGzC+(1@0pe.zG@P kTYj*qQ16EY:.7Am;*"҅eEQQjҝ4H&*bH6d.v@jG#QB79DwN?F捙颿?T)lU*‚j~DALFCa2\,ҕnc"n0ȀW{VAŊ~/,lf+l4"޻xϩY*en y$f+bJ~#[Pb:# |p!`~ C"g .\e*?NahX4 u*ya b qcW?&6$a@&"݆û@HEkVT2SD`g__Ykbu}-|*BbYEn^:8c݅ci @P(E KJ R[HpUOS1/jbla/d\m֝yDtúg݊jGg'CSkAͪ 2[wÃ;FU RQ%P?}K)]X=lD-t%/#*Tr&bfم̮v~%/~2V,T0~^T]T7ONɦ7M/rB)3(30UWL%0̶s% *ɥΦd+OeBuq-m| r].x.s;vW!l*JE["J`c;A]ܮrV݋?~5ƙ疭vYvBuqű(2&>mIbQ!T*|0M%ԥcj{Mrƛa'3bP}X;+=d@ܶ [ N6`Cݵo7^Ŧ13߼>isȮuOkpCkP6m\_^g_@boYF^9t>T0H:]3>kb/%Pݓ^Da3_ܪpLDudgd)^}^9ˎ144Mi*JEl^W>ᚠ\ji2{H+9"Q+@ 2'!\-|(4n ;`ZwzKPj1|ik)g9@|\L NOYzTW c&v۰sTSfV?*J/a6Soġ}MR\ZCLS0;!;s^Y9^7!! UriXq٘V=J(/_u]TQ\" =\)g’@ j,.d;8L7iL#d?|ᷞmמ>< ʐkBZM,Ze'mTF ꧃*&,dc$wV[LwO㍇y^.>2i+T)o^_dL|k6U黐۵ͪ s'u7Η\m$~4@d`"ya& $TC#o `0tdEBh8gC ƟYQ,8LϽ|\WYO,VѹH[~pAP"?$&x`JwJQmf٥4^ yA"vEhL~u&x\! bYɡ,&K;dVT핖aTٸ&}MG[Ģ~L%' v_(KF.>7G$u;u;te_ArgaCyv91Ƿ}jIAYP8 [{k;? <1;ל/S}9{dg~>UO֭oLwnw?c|_Z+O*Jv;&¹גgI4 >vXKYROjAJ} |wWZxw?P8_8Ur/c["όX r]nm'uK9֮a!B dd~wbǾdw޸:vyBt!/X>}jSes+v\8:_8; kr=Eν2=)6‰nUkkUչSlz9a6^)Y:\rs*g.ysc@xȌiB)3-P(r Ik I؉={]峇Cv=\vv;:?_8._Pi)áYg*}qUKF\r8"0EA/2]`h-gmƉְ/=t*| Ϳ/7ýIU3j6Hvsk!O~ؑO׮o';3sw0v;o\]S(ˈ Fv{[.L$Z̈esws~#rP׷Ip.:6~xrJ/#3 j]s]#gق};fSm^kNW0e` Jɩl*%gCČl>[ ʡn*ŵZ}ĝ%BMYݨ*]7߷9ynK_g0OTk%xrh)80 {p6>y<  Hu!`γ*AG.?邻v&VcʹUFݵHk"[_p!sh@] V;}k3[,Y4ef1Be ͹fwnxgχ/?S-=_l[}"ϟϟNOΟΝNBtKa2|5ǨF5jkȆ㛝gd.@(M+Km .134AjNdha흇Y IDATn}e%6G]sx;G׫>T.:;|7U]B -L$zߎACb3ŮrB~~G]񱷓ǓgF̮H*cZS;v{)uk2bMV4LDw߬靸dɅ/mHa8*Q`2n6!U5J_ IEnD"W4"bO3gCa$'<2Qרu_:a׻ _vU}k|OKܘ~HƮ Ů=Ŗ9g7^KϟϞM/1Zͮ yg}jΟ?،lu}srX֊7Snds˰TvB)}p>9qS_7f%)3B )o_!{== |%7Z@[q¬y6A޵5Z~#bNp1:w6>y'Udf\{߼ηF?]bbts4=w.>q<9w&r5@H6"auSH4xA ] `v8Ϊcb߹K ƥ 6;<]S.D>8Ea4'6$fq:ص<|80- uUONٓɛo%_IȮS?gB[]\u(6h-<-~ll)o$ ֻJЇ6;LG -Ps!p>/40`Ghgbbp 셏 s_ox=yfQYgiZ Md'23gԹ6^!fIC%z#Xw!{E<#"Hwruᏺ2ThꃎNƋk/~0 m9^SfV j*]H:T/_趖jw3$Os{[QAqn9FUolPoR.ȟ{. .=;{-=v>r5r.4'WKpY g݊s‡pUVa8Cnۻҋvt@u90Gt7\[=.n~z+@SfV*JIb~f3g^ RSWep(CBDP rhvÓݭژQpN֏)ǘob]ٝ_> mmzhz\rDԔApu?ٝc]l䐽4XWj'tijgk$(vΡ7ꙇj ,>k׷4efՠQ%0GG`KB9BNכ@a{x^+dn8{-> E-;ofpϾNlLv*FwC[Ϟ9Q''w's璷PG脝]I!k3>F!Cl4,zTU5`|vnhfey$&C 0^ q?4s8)3^O=@ۆ"rHHF4f [3\,ؚ8 (fB뵌Mj xϮ#.FGZW^k9=Ch_M#&ذ2+hf|]54v 嵫]>LŜ;kYuf7t8޻w=3 :T %H^BIkl4T~H`8chY.;g$WFò;cמ4u;`r$=$.fWpkőާ{s?rq?EӢ]fV*J/?MS_s/EzRݝߢxcuw6_5G\=&2=u7X̲: I8 5kݕ*ٗ=\opqrx]l>NN\֢5{4!Zyy:j6bvAx-DM?ss.IC)3 Btt` /MMK{*6[% LqLpZXy8}Aa#SM9>ZgJJcopJ+.kԽAGwȞ?8Q''﴾ͷ^w_j]%#ΕCDn6M]X<- ^w(EEMY5*~˗ Ѫ"v{U*Uw^wbʠEcpz vk-Y[euj 6>\gzy!` e_8r5~3Ieu u5^9mwriO͡+{$>HB #>,2a0(o\7PB"sϯܾ2**]ޭ7үfv넘]_A Lʡ\,^xr_e,sG]C)O *J/stW`ԅ\+[sͳr[pÍ@]I0z[%I~_h$>e,ȞdϩK $S]POY[-[Cd{dzדvTztzSS-@`P} c ݟ> !I ]әE(7^tGyBP!Tz_y$o}u<2_!UwUjy Bm~*:sUrPث.$fKՓSN$KD2e2"Si[%?'p;/~΂Ie«C/t}&ۻ'߻7NJz}1X]#] xNri/4]ce~-\j`%#  Kd3v9ie`]{S΅%ԕ4e0lld!ڧ%q$,#-^A'T8}bқW_j?ÝC:{Oo-5gN|ԉtr"rgRvPg 6 B0q{ء"8]0Ѐc Ͼ]g>ris_23ݛ-"Tzٽo6>=qWbG52089B6UM{K̵+'nf{p; <rl`J C2>*Fu'nWaNjbsOQ޳{.V/|~P#푝Οu⻚2"Q!Tz W3ܘ'ۺTW /uBHJp ;!و*%~JLF~K|Z0-I/Z/l". "_EyVG%J3^u 5No@>bСCݷdzdz+}HqHP6f@6tk=XV+wk_/uByA&ݢb]9< fg>_lՔF^kկ @`2`&f&_bVL0dWpΈ iM^@Lu;M1ֹ W|}uFBpܰ fhsZe2rby/)13 Kn 1ђق,e.2d%@H0X23 nu&ȵW+o|zfݗۗ:ٻ/wo#jw^mֺ8 {oPWr -ݴdf*'v2?D]S%/5ڏߎ۝۝[CÃ2Q!Tz:$1!h^piWl 0c" A'+=>U DΒ?]9a;7z9,hu0l`#?Ȁ,(Yj 1$A%`-$b &uUco gf@D同Jp]R0woJ tLzt/H>}ه?2̾CŋGf_<2 w'铭oԉԉ]aQA|P>..tu7Ռ-<f, u37=ۅL*+Be~f'H ZY I li B* |<;]ꐨ̾of?N &3r&z'S~N.aE6Y!` G,E*-%bl#D)%[,,dž`A[W/nR19&LtoLMě$+@J(1g&g$% g?}'f֬/yȌ\o}ԉ/Kɡq<{Nom#c=ih3NK);_Ҕ K4il11'i@Z,tMRIN0%KBӹJ 0a;gUy u1 i#2×f|D fa5Luci#* \riV2ha YJ9MwE&B%\8 B.vh!Z[`f̽\&bC:sr6o~\[˽C~#f[[/~xԉk]K@Hw {\9&~$ϗy#<4H0_qF])3+Bq`\Ƀ$ N[nP?0$b\1)!EGp5mk%PmG0L%dDlӎ0{9a Ll$ְ%Dְ sX䐤0QðCo1Ji 08_X~2ೖ* \]W_۟;:ymg:OܕwNh}+}R@.r !t+7XG{01l֣'j7z#;׍ZBЬQS?Mϖ<|򪏸seb6~˰wL3d֠*0T q#y6 (;Fk>1e0HA&  ("F)s䣃[1[Ó}K\טԷ-> ӵ1Loݙ0͡~?$Z{:O83> yZ tf }:[o'no|t{x~#i-ºXŞDO{(2 P!Tz Bnjt])]Q|x-+}TӹpNvBHrB)nvݽe]A|ۙhfL@3o YK0i[Ė#春$Lncƒ !v\o:Whci]ݏ-ӂb%~Ƿ{Pb(V&3sʱ9|fv֬ʇt19q??Vۭ0 ^ _􃹟-BXF |oλMOR̴BQרK׈GϩK_$vݙ ,Q"rsDD^lHj0|gS%h-Rqm0%`7BWWwgOSk 9dD4c و`a1 ,ְa vr#_TFy.ElMG`$%,5Id=fPB7˂A&n=saXA 0 b.W․w] &oږЭ{d ̇w?:+[o񕁓G[w@#Y>ft1?i~Wh E-Be?F{2杏zfZN(k޿ܩҪW̬,"T !dOv%g1p-9vbe0J \2-`2: "-W$]?qdhEQNj3ؗҌ+aCY0"&DQ9I8.fJ"rL%kʘ"uy4ڐJvL\b(A:KH72%QCJ-p~Fr C[ %dڒބQ\Q@k;Nm<﬑Ocf?ȧ|j?[N^׾kE(|:̬DT{r.ʰ89ksXzϛv`L%8&Mj3Xo7Su'.#KIwSٞ?ګ7e)@dA֐Zq10[$)-9SJRg)bXpH6 1sI@Pb,w.f apj㔲H#X9շFlJ i8߬!_* եqı.dcA(7^uf触_#^~G&?#Ήzi,yn<>qR(JZKMGPyjFy'I̟{o|s/sHoXO r:/'Ֆu)_J}1 IDAT(`R/! n מ8| M`2`Zdx:M d-0%bFl9H%GʥA 5x65|#BTPPDۚg=F~:Xʯ!< 4$}Sȗqe|n7+N^˦3Srj~Wjێ|:?;sık?F߉cKcIϫ7 s/车J^MYAEC81Ibw_$̧Vۜ&b똃?.:CMMG(PaflI㔪J֨3m"+y}_ iQQEuZ" Ya"Iqx96,QicFlMls<Ŝ0$*,qIdMlBIDXH )pm-cXo |o _- m@%UjSڸ]̭ېYNRMM_YSfV*-h=cMR:smHL̈ 52'^h)4Orp 2  Ny7 #8wuZ_xOMxv]yG>>MƒGhhUZ%G^ td|P^r%<@wݫ: kH2p$ 2C`\ "0QPCm>#M7}FiAjd`Y2CaDRe71'@d9"F\c1!䚔VmL\߈PֆJ6MYg@r\]YahS>%4?F/$j EefU;э*4 VnZ9/3 |?9L<4;<]x+:V믾4p7wowMDzX% y/sר)3+y<C''{:.3IN0WIN>u m6-yߩ@>XO7j ,J( K SfsFDMN-0 FdlQ2A^{H1P23$jqG* F D‡G[3ODAŜie Vt|jWxQk;nX*ƑӮ}"/_f=xhvn(?}ZaBrjoBЅ(bظ`!;>P)3+ BedSJ ul)Hp$"&u=?yӎ`$+Fh ܇ :IݘXri,_.1eYZ}nIdv2ATF1Vw&- &H FH-ZBB-Th* VUs=g1{{="2ӣd%ޖg3{wﵳZ{_/{?Xٿo:c_?|-!~_ |+[ <m!6`ۃ~VdJay tǠ䇱uDuTuўgh̤P?[o$7eZO3U A1bCKVO-AH尖:) p2.)GiHDV֩80P؋$TS#yH9J+'\jH+TcݰwYO_sYgߋ~@׻Ah CD@;i@o#E8֟ZQH qqo !qroŇ,ߜ\GQ$[|Ͽ>Ε-غF_<@-u_% i.$HL&5P"&(Z5fC cP--OH6yziEA` 8u/h&^y Q 䈴'E RA~,&TLe)K 8,Z3kVb$EmzeL {;fъt@DE4N1μbۅVf \ d)w:VK .xoCoO&w[~~_9Vb\э?}+ZU6al6P,0 1 :c5LY^i?Je_D+(GDFys곘d)NJR5",:I6_ fGK(->z!ILDG2Sb2~P$M2?52u |lՉZdS(GPU5ӧiޙR A"JdU"1 ΰZͧ\S OL X6~KS {&lُ~}VᇧO #_SD}c4o]f ml6n ?ng#|bGyuv! A.)50f.2&(XFGQexo5w!Tr"uvc;q*6vwgR,hDZJ(%LZ m%TGSe!U I[:ìg<zͧjɔoW Fq>ya!eLan9g6<'Wwzo{Wsr}#5_{z2ÿ'?[F?~X<D ]D죞L?)%k̏1â6J!DT^@$ meWǗҍ#y# XW˥eB ,]Qm: 7`u*zW$R̅r` "'TmEuVzYSpY L_<)kڼ0#LUu٬DA@w` \6KH8Zޙs;D;7,53 W݂koouJ.%T_X=}ck9m!,)dܸU@n5!6JhgtnGcaR++ UeJ~;TXm7H u@JV٪HUhW:f2H ֽqKdRv׹@1YJPT%d37ZKd#Bz;CdGR}f0ܤYJ<&X=kA1G1J0>F{zڨ5J|,aͥQ:{Pڏ^}$yr\`G׮v׮{N=_X= 緖s[  ꉎ\j}E5ӲG[ Ҿpb IL^)=tuncPaVGСɮ0l*fN'sG@Ph)HdMʐW@O2*t( 3| $ UdR<!dJRn"Pd*؛FLϫLRYG9aq˸* 9јi%ɢwD! (9Y>g0,,k$@#P3Xɠ 'K r~n.]|@SG8lُp_\tysҕ/by==}褹c.}Zfalpo B7`eO(boPOQ^YG3hWOv eN *V@HV應d!g@>Wɫ"PGqj4$1cDcBdr:1UEBɲxix3%_ܒRI*$EԒL[5i2%(A$P *X+ 1UJ>AQn@UbԱhxQs t;ˋOb#Aq58^[RݲT3T;ܣ)t o١Y7]k@6-f4Aݧޥ+˫v}~w`۸ `GϞ=_o-39@7uYLΈ[|2r1HB! _@}[+E"H+XbW]AS#L2mWC UriPJ>/ek* LPQѴQzNz=t 5*=P: /Eh]U%_`MޅۇlF*|uMOW \\fLb|)ey]ptq{->V|f@ 0>@wˡqL,|=F%#lXQ?"f,Z#;D]{CH|jOs|cēG'O t`]}ow')nO?@7I%584>Dm7e䴏zߝTy?2D\Qރ-o}9QʲA}e@4zb1"0) Iغ,@Hdv1"@i4{j]ӬΆ.dʟwfj&x!+L]:&tn(ZrͥL1VJ5G2U aP Qgs-/X4g XMLKTk1S}b/f ___V,.pzxkKW{Ϟ.m6͝y֞|13pXF)ʉ;QcIuۅn^@nZd2uƚe&@r0ǀCy - L* .`"Hֈ56538*Hk^ ỎDޯEkUqK b!p 8p[\j}53 J[U iq#`ƂVfNBgä9>v U cnP>mdhjz:C߲09 `Кu'E/pz24\te~?ѓxm-lGe5Zfpj"UI>>D :@;S0IQ ,K@u^A%ԑUBfz1 Qz|Ӫ$PKN;&7  AUփͥrPiԇ^'C"W0>G"`GoZndz= cRLYFμ<|tM3'j~?O[ ƛcܔgWΔLc#}đʝJh}I}-fv"V["vZЙDT[5bk:PaXfKtB1I@M(~ؾW óZWo `֙ ?cG$\]> O3dJ}ڊB:P'rQ;gfǷ$2 \(6/fi]R ,{ZpF}ߛZV79Cs)B5ifl OYa},[ ƛcjO:Z9Y̊lE4^e"XϏh1F[ؒ'LzIc-(;w +nS*VW/gUK$•TFݙȚeA[mqd~ѢD**X yL,usj&`»T@fbxr&v7 y$6fޞ%ud:! ^L`\moƷnۮR+P8]iH'X~G~?3"[ ƛc{]i- _Іi'=g&6<"N(eHSgvq_O̥{U#P@8=l/ UBʚ6V5>b 7؂ P$`g(U1)#ƢWt2TcCJ%$; IDAT/+Ϩfe GqQ gҕSױ8 ) '촸`cNb.-B3zLC,*T;-'Z~>Cl>Gw=  y-nCy.JiI@uúR]1a5n nwĢQNk / hCt$z,AKoD$US Ё>@@mKqupKV`(F, qmKgT!KZrcR40S:ZUI!UH^]+6*讱?š6;@)o % EݖLIyaff;\~I3 c.>տ0oJ5@7z>y5gv`KHa]+ e.}vk|=$*g09#hVҐu<.ƀ28Lr8UV^'6O##;!fWZf{E;%FŃV.B;!V_;Ͷ=^1Ay-n1 B%JyܻH뙵!8;u0%yu]i`]E^PeL ɉ9 k`')dkp5Bj^4dR.|L9bY+!W_e "?cEd, $Xp+d~l;7g@"T@}]_z%>*iı!QGC{þ[(]} Vn!aq5ܷ}H6ͮL$ ݶ=ZmgٲED Zi\f.>}Lo <eǷ{'n:24d eP ge ux(fpX=(8Efˇ2ɢ~"5"=&&OH[V1]جC} 7"NI@;k.c||p+K@GޕN>hT崯4Op A_7]K3#Nլ@lp8o{9LyPpVPwaӃZ 6X~d`<艭(oP4,~PP+Ѣחg[40 >1ɏ"_Bt^ڃnͧyzsa)M2iVkv, Wr 뢍ۉ3ɩ\i88!0TP·Z6 JV0I$ +kXIC^n՝ ;zh*!uzrQ6 'UH!ɢ[OIv6 DC0 31_CK¶OX.;M|?clpo:Ϸo~\miX 1pgDzG3>`W\猷nNU\*Qz ҕ4‰X G;P;Qßx.<2'Lۇz$ q:( G1-ᆾb+i{R StP!q|nKV/1D_A> ;* :z-ncml>Gh9|oFL)ESQn$.?wAr oPG!|X~5H۷n?C LsD K?7yh,CyumjXH:;j4M8G@x|YeJܝF;%f"/a_ڠINע`QP8 ~4i== 6d eyDh$‰O*h0>CBEZtg%( tK&P E1*u=!O!ЌJdu4W =Ao[ Zw @-NF3Q:w}#c }29[ W7tz񃃀4OL]$'_1?(L n4CBb*R(zسi--]V|z.(^7,Z*iRty'55\P|NrtmBpj(: aȆ*Z~ j6Kpط2clZb!zVe_ ГB)QHS}Wr$-BU5svhq 4>67ܒ ?1n` };pN; }@\i\w$6J}Fձp~K8ܺFslpoq(>5]sǟ<ѺDF-3??|4F/6J5[`.H maiè_/`q 4h$V/kbYW@}+NZ,!a}[{.yVGU /2:GoeNLl -CCzeh#Yg+10$,nM  =Pm c|{2` 2ۊ߇j+ }n>9W@2[ ƛ2]cFx;zGڦU.[j3Ǹ&f?pgrMU[X^A |V#q,ٛI~i\3Qu.mU=-?=sitclpoѥ)GLƒ'=N li٢|M3ܒ\|M5!0]޾)%*_s;$x!5Ѵi2rј@9咫\tNhN"ԴpĦq8JY-MágP?瘚C,' 壌^Ps@jHJ{WinkMruOapE #UB0T @~ڒLBmpSlhlpopsфEa!V"jT9YLiɺ1DYFKNbSaTc,ΘVƦ.2'ye(@$r]p4MRznLJ_CS5OQG /+J>Z\ం_&ZɤjUPdh{" }4 63nxn?z(j-z.z512e:RNLmRz7 $ᦉ~?/v9տ_0V PsBgݵ;OR*H1!)מs$Jbr䳵(/d8DJI)Քb*d%+QI%I&+XB JbFjugH hQKfM)U$,%@H#(J88(4Wu-QAXo jl fٰqGN;;:H6ŐHY ^?t6UeaP%-4>u-A#bvxLxb8LTG_zMaܘ| !RQGvu U{9 wf+7,c=X(EEhtX xSEHyݕETb͵,9"tZP֨ jJjյD Xroz$|@J4gu) q)%tHu)lc 8bͻ;+T clw D1CieS "k|zm*HyygڦכeX;/ N=؝<ݦNZFylpo.rA7Hܾӫ F^'23[$lrJy uRtN@ @jǙ˔҆uPj`{ZVPOi r?g ,G&1.ެ49 iQ "Pޗ5T{ Sp6ÎS;*7'|KLv6Ɋ iN$;rB9 !qxJ X: ` bnR}v*huR1Zae݊ọm9-n+cJi^\&Ry+ܾW,Tu¦ju<5yF-ҐW^C_ŗ%wOO Q"!hh>R&k Lk)1D,eWC񁏂@ph 1-XK&Nc%htح8;oɏMH9Vt&$ȧu :l D'`p 1vhSwS)?3ۇwa<@0ԝ]. \VLD+/?ˍ`Kzm cG(MH.Lr"_h@iiU5țک82ٱȴXwXPLBLHw4'LЏJwl6$?O|[њ*Mf^<~y):[0UDO|6|tUyJC%ܒ(It7 ezgDCU@|3`u\7Vf`VD(DO(bV[W0vi 0}t0qqigFӓ _nP@TK&]fT6 *vDwt"??׍-#<m5hzt÷MGO_^j!2=( t8#q*{']$N3LEn$|O[R/ ."^Ži$0+k]2 H@\Ɯ*UIX Ef=5  ov5 ƽ&ƛ]>m \tjA+6Bq(ZHnx9;X B,UɅ(U* %C||GI`[t|fj{oP;Mb#<m|YLtxM.7ţủafΖr;@k'|[w7Agg᰸Ֆ&BF 6xKGFh>&Ae{[ I5ŰRYB$ xy N9^p%4aPA?hנ41 FxKEfa̵z#4ϋR]uG{Z\ 㖬ęA fKPf->!̒j5&dIK{~K >7/ϤP-F .~| )$,܀nJL^-TF*ޫc0UB Afl_ 'mJc-* _S,OhBThg`xXp)(=v?*4&gYO󇲍?ô .!|k$]@<%JW_LWw9}ݡ҄NL%a") LDMDM;I(/dNPFɪY5dIA 5d1,N(IchJjgUwVFLKq)-Jn .@1I^\! N6x!&$@*Or|nEWUmTV/W5(hIטU -EuDqq㧁 Py"!'Z5>VʢMH1I!Ak]K?޶7 #5nZRKSv)lzLC:-HH˧Z_X_PH)&)Q*T9k-Xe%RA6h] ;M6 i=7^Tk$!vU`"(ܽ8j֤!=~Er 1=[zmǔ[D!,1<!7bwa4Tw{369+8lpoq(r7-x/B̊4Gwr)lvv&g+[hԨ'RriCf+RUIn0? j*K%F-j}( f-x-5@]6ǭA,j&P%k3y68w{Fy)|3/9Es5WZLMl#-nB5le~7n-?@πItxCG/)o ӥW*ZkR-XJS5Ko.YCIq5H!6;O2 -cApVLGQT?A2DJ;t jBZE0PgTqN X#ϰC 2V-OE!09HP/4:p8m4 `vRIKБoIZ>jtsԾi|P G쮺&_T"H,njxM9f--pǶ6G,Z6ȘX$ډJp2:XK)ZkzrN Dgi0~^0"}USsd}7Î%JV=n'/;::! ЉY)YnNf)"+U$*e*\HLc4#]mЋ?;^az0Y)W{[))H* k> lLm}Bb_;,M8] X ʐ(oUәH y҇5>i#Ax~1۶2ba7lm>i&df(ś9&"0ݡ)eb*w_R"^!`뎌NpQ΃)1*ox)6[jpduqLɊ kW!hTr3@vk{Q'8XIp>aBSbWhG@ګ(X]cB&ݸԔȌߞnۡUO1GF8$bڀy7zڵF-Y7[Fxc xkDф`d O}EW/ ^I'{_WCԯ͖hy9*zv쮛/OPv;&mS7qT$@Jk|~:/33ɆgU_v`Ŵ\PYiVi"QRȺc. e:sY9[[@F9A3HU\„MA]TTa0ąU{ I ULa"f:`C_m{6fh[}JxkCIN悊MzMF" gYU_L3#kn۷\myߍOɜ3S]f;"Mu;N\\t;NJia9EH VQBU5T% Xv5!TXjlbZ&UQK<_㊫JZuk FBfd(2Us'Nu&fYԚN!qƩTSWO8; REWgh3kSwthO O.Υ] H0=XU QIM<7 ĖY-#[cyfqt VM4h/+!f٧Ҙ_Pf؄SJv],URXql!\bS l6RcxT0'pYT/&%*ɈDgtˑaL?/;qTJYZƅ@^# ""k| 8"Z(F *Κa]GK/ S6x ~sdl]?6:rƱ2qSN)]R"KA1t׼n3Uý6{fi^&783)B5Q4:$U"` XNPEl./çwr)Dh%n@j]6 M9n\fiK$,8 /9V;Q3B%3PeIG5ƾWIU:l:20w^k4U/2^US@D%ʯ=a+ggCjb@wLɘ ~Xe?@/ C+>9#gOӐ)k˧kB3n[ΘHgf䋜}؜i bAop8]XbbU%: Pm*. ı`2YPȽdsese+9#{9fx׽Y[̅9nteYsi-(hB(K.u,AVL+!(W'f2C^LXT rDz;oMv$IvqȼB4 tlLϣwrHܵ(KJf2~Mi2WDLHE.r5;Ϟ~ UyT2}Vȋ8q܏{vmmzݏG+C hzP2҃|aۯPE}á+Y˅Cy1¿6FG{u]VJQ!Ͷ_>*7Ejp銷AEk  s<4x\,- D%L2ԟo Ň4D՘5gYC B-ڃ,sW,]"4"iFA[&KJ|ʼ*H5>٬[L.9"Խ~4?Ja9wԝ m /%2H52:KϾ(ݿS،/@8La%TSΔs^{PWAkaP$v-HUb}[h{ Tt4wǣ#$f*rQT EDPM vP YFj]SH Ի$(&uqD{x7"(a\ )*bKTƔ硏y O(XS=@)8_C<-ѽr#el#= P "(K>R0fM/ v&lўeGnX-T+wU9>X@q2BS&:dbC|$ [pyMlϝ!BB@F5:Au-P+(g'(c,71Gt.ciad^Ç{KXPlS2e4`mDJutO? τ@8ڳho^#dUe&'~|ϱBܜEޞ/ 6tDT_JkaAE&8̀>G`u-` ֨mQB2 - 򈏀F&DPX@ .h萙3 o@jx'CrO ـf2C 7UeJ\d!Qyd!IT.=UF2*,:/~4=ejGFn"Xm.BA%DvOuP+Egw6JFτ@8)BH<@spiٺhwwHICMli^Y[&ig1\Mh\(L AJJ`WP@r^yС\`E$BLdSH"Լfy+ j:[=^BC*D4pgT͞t,Y.<{u 9^P)x LTTDDyL_x}<*{D遂4kuzVahH?IjcᙰG{Yra"-feg8""՚ ~DDyx*"h*)Si_7CLU豈I=Ć*<䬷;­,kr6cl4g,~D "{7!=YFW(`9HPKS>jU]J~1V+gviЧZ*ܪacn.{@%K}%]OIz-@G{uNyCik:+]=JhP)gpO묪kh FQs>jJ\:TdmLX_u$YS*}}= js Z揀M-\YHrM$/jՎ23€Z3ɤwvBjwR8OAH }SmjPͶDEU~ۥS2mdgF 閺4ptO:z?]DH< .<yRV`~(xijʚ_u6_Q1NL.I j}"ׂD:{i,7W>3BYj *Cz Zow 5qEZ8WOs2ث,T Idf`VB+H ÿ?D*De."=V\ }6τ@83_8Ե̜sn/O%␈tx8ޯ  `1eQJ= IUUxalShI%u٧VjZܝ=@r[{J=|%kzQCUO jbgbE>|d1þDBE# !- Y4hI/fgF )egrs)ԓ Jq,ְQ#;pAEU/2nGJE̘n&PC) EZ28my}T:(1qPbQ WfHP1Y}ixv?6rhR?odvV5H/t8,:*yUMc&V͞pizHa̪ ֚*(hЇHh.CР{@LxB7 pg'ԗR29so-V;Dk0ҐT2PB;׺1!Mn@ZcT@DtOC oPwϹ -Qt:AmAqcTmO KzGӬ\a>Z'94V]n#*Uw< j: 4Mx*|>L[NuOeLͶB\0~~6τEG;",&UUj >5ky_*U5#ހ2s4o\h T%}r]> QZӱd UgI! EK[Eդle46~J]lŶctHR sJ Άxo^U6QJ<7;lJl;tXcl%PKo!%oX]Υ}`Sf/IQ&;J+g|mT hϲ" "Fabc|W79{' 91sUDZsRbEDJ?X (Rzm>{l˹ 1]-u(Ta@l,%žrY)JwJ}|@BEEKNl#x Jl̅3΃ DFX-4RV(NMRCAQ1B%@C; IDATةkBE&TQ&‚F7-}BsD'R*yE123b#t KlMSwpk~[Zbd行k>>8Lٞ]Jl̒UUDɳ mo-F&zhcyTlĝyRN )']T a qT |5@ ʪp%GnnHEj=$?L&o可3 S3\-$Rdzf .!<ϲL}l \>|!6Z&E@@~ҾcgFhϲ P7*"*`^E\f˭W< 4׾r=xVr_ HI)- U͒Í I9vu2% -5(̽TUT\Hkih.PeKPPmU~NU?h5.#\?&R(wj:6B!J0pɬEil.S{_$٧윅3ۯcWRrBwb8(_/&P86#<6h'0b ,P‡$ޅ^ o_u~#,k}2:9Kb(\t]S~,DĚK*bmT ,-g-[`}q. )Eo|e}7.Y`O -qrvmr8!d )J ̡sBDU 3{?xDTH^\S"k6T!p )ׁ¡e**a={ vh+28mlFx&lўeG03~"]- cX*TEU+<9[ ,:")A&rPs2+KWN5 X2c]9F6vh8ob3:ڢ*"Ddȓ q$H9zg" @E}6 S5f&S.EaYIC;S2 !3CEY5;ۉLVٵ"\cS2DQ%RaB&vb0J"7),sJj'^r s5GW|he=a~->o(ئWY5TvMM9q*}W'd 2fgF 8 Aʬ̻ܜdGU@@M(T$G -LL6#vaVM 4aj1;A*5 \兰  *3.&PQ@n!Z 8=^Z(\SaYgt@HDC?y*G=5BPMy8yo}c7&ۨ R!!0YE`U%X݋ٽuRpI}6JFϊю^eMo* &QI(j֗%ʨszO~ў]7QY!܆?q0ՓJAȊn=;W[;`\kw+9甓V#!x$AMht}DМLs:1w"pȅ`'^~zT$"ҥ}ɩjpia<1'Ϙ9pُ߽1$ՉUgQKփ" E~U+Ȗ~("9KJ)TݗB<ʨC2br]&ET碔OvŽŭMQY$u%%c~TCE yD͟%٠LO[,C8qr?L>ACk;ɿ:9m,+sVltv" Gg(Xl]NPMO )qBl)9w<̙7gt?EPiq)w@_-Qr#j2N *J u}~)b)*T}κQQ8:3[~U&adɫ]'N6KנY<\}&c+fRhwde;W(m##<+6hXJs>_SQQYgGrzD @\dLCjU8N,ys=uTV8ua? 3cXUX] y_|U ~OJv9 %hZCvTB P_W\8,#2<%C@Iؖ%7If/7ޯk\6ϊ@81:"Qb@\"8"r:O\D='<,9,"],iȻ9 ~<@ϱݮC"UA]a(H,+.HtT IA`5A/$.Bh QW}A Ԧ% {}^8|O`f,t3TeGDIǼ2T> :dVy>KYG;Ǝ?ͦRflu漘ϛKWP hUicR>6iB`|qlY8uv O0ť%…< _x dHV,H&^P.WC7DTVܳ1^Iq)c*U@3pPs^J!e:&J)>y;VWjqUW F딼0`X_;[ldgF %XL9SB)' SqIw* )@ y9fpOQ}q |Hj~( X[5@8$ҤJ%V{;!quTď]wB!fVPT80ЮY,ԐGݷ~FV(:dɁC^_ͯ>U{Dz&Go<_'!j!m5߁ecc'?|iǞ_7d"1(3j#w>)jY [xB܈ޚ6;|=\.1*=Ƴ/803" ><$󡷮" YIo>O?[w0[?QWsA+Bd!RUѠAb v ( wH7LBӿ.<>^ÿIKQ5zVlL[.3=xU'@^hOR@蚈_; 2Qkl'J/=B_dV%w$xćcy֟Y_9Kr k[1䳮 }^XT#Om0_1͕e+) $%d2Oj4V&\%Ky^;:33VQ?9PٱG;RUU9.R: 57._P^[#9T7@_N-T[)C?Y>x8d #{\u)nx/బu~`Wb)u~;`!,z$ nlߴMFq"1~ad8<2˴?ᤦ'_\+cPG{m_RO@ԴMo!}dVm]ڦжB1y!GN)KLNQZD:HxB%6:m54ԦAj%oH@D]JF!cu,3Yʇj9)m! f[Wn'jIz5>3Tu j=œZ Q: 4{M @"OU&kF,m'D%C@!@"= ،G;y~v2lmJ)u]RrVG_& ɺյc:=W>#圳'KM\)!-'| P.gW+?Rz+v#'27u]D밽rSw&uMVTG?3+SeAԠ6Y2sQUP& q";L|66#<+62ю(yslˎխۏvTUH\}Ro}c!r`fY]5YͳZ5CfM뮢X,)K ªgG;L,g_{M), RJUm))ĒCF5բT!s׿G*t{i@^Im.KǤ'9H S39^YN3lÎ/YYUoM-\BYįmLqiE 2`gRL k۶MC?)%á A7>b =b_04y2|Hp!C %T?R/njI|K1F81Q] 4gbX.w:in&E1XU+U~Dr*RΫk-[%uzCc0zהViBGԲH"4lP}cƥ,rGNr޾ 6Zʧ%{|wiF(-#@JkS`i\9pIR[@ 1g~>ß}0۱Yѿ>JFG;FF81$W$DrFؔۋ>PDZ|xCsu)gUM)=wUY\L3?XX]߭@UwRZ옏SL%?Z)D= JU4U)@tw*]οʽ P#ϦED ү!a&fX ??` 6fu.8klR_s/\?.JPDga}1 6va%Ϋ^Znja]LD"*j%6x* )s`H%Hr->+ۃء]-s.Ȏ^3xr< fjW1"@)Rի V%2nRԿ|'l6P Pr<Y뀖!]\qh*3z{E ZaZ_eeΐ@81.K2sʹK !AT!b!01r(4Ͳ  H!pm]&S\ ﭭkvKsqmO)98B<*McL7 C% j]ցF,\!!8$@P3,~B1쀊9ꌢ|}rUG/ᙲG;޺$1rl찚!˵4k۶bP՛5PEkhBi˶9fcb׶6o=}n,lPze.mu]7TpH^<P]Cjx1jEW{ k͘> q(=[jp n&!"95_4J /ۦaVo{Q+#Sk%˰G{v./cc0= 7-[1W߿yKL?yDcRo0 d21,9ɴi-iP>rBw(,"Y$(4phfXv]J)@X. (A=2-˯DDU*& yQ'T KpϐoGÄOi7碠m.jv.!W^'玢ٳr{dҴNRJVxP=ɩrWSfHUr4I3"Ч , *QZHs0J5V@owo#JT \eލ~&@9_5bpW+j"Ʋ/VS@EOknO a yZ/1:ϔpR Cxz)6"jbs}3|.Cw *21Mv6;xscçE{BB@z1рEAr^.pGVDJD%(9nYU^ d&>{*%-&U^4BΜ'cD|D?Az{J݋*>+Ou/ aMeAY}/$HȢ 0d2;??\lTo9,'"",ꖅ`gӀLv?'UgF xK)C3!*Qc1rnrT9TӲT6rign $ $9wR+RDj@<=%=@)ez@+[1DsV ]) :fAK=Qmo˟PPJ5A`~RrwjBP%,2QXnɚgJJ5UyXFhf+Nֆ߽~BLX#TU1>G#X h)4ǜl؏+"UoX,afaRp T #k3BY;JdہPR4@7.ȧK7jfFBճբZ-SUƍ{7$ި"נ uT(Y<) -r>8 1 ©J9CLWI+wTm!p- FHTUӠ IDATב<PH &|ADhyyc3D mۦiXur /NrJxtjd[V4G8]?;h#b\Kn)l@5}*uTmCϯ*UkeP*CphPM-:-J]+P`6cbRl\{[* 8glhvT-vkj-}p86#sk2L&cK?T$H.6 u}Ep8sVyXjmZЃp#~76fQ & [ozV% ׽p@֍?;|۶MB飮F 6mю kD󛺿P*D9~~xWU3D)2n>]߈1_[盏ǞiUc4W?{_ēH _k .vۦ%Yjݫ9۩)£p]sڞC[2- E0vN 5S!W6 1u"y3d~UxZ=Ʌaa|F6 ym=b߻:9g^llFxlюe bOM~wk^p!cpGwڥ4MNlgͭ Qmu͞X;`*:.V(Uׁ^9D/tP/\dS՜o@5R`1` FRWjVDRz/n|>Lڶ1ȟ2B0Q1PCfi~-ß*> ,ҕ<,a YdV'H }BΗYl-+ˌvNxGI=Pei޸!7HM4Q`VkND46M]APk(ul6?O]78(R*NMb 1Onl}t2W2 \UT5uZɃdɱ)bͶo{uޞ[LίKk绋dBsWR S}S$F`ieڎZ`X(@2i*Y(VhD[v˒8e$³e##xKYM꫙#nbeCrQuי]ˊ UMфRJrÁ;TAq3__~Υ4Lڦi?6 R1f1ږ#ɧXͱnm'K>s6+Ϛ`H%"^zeX2JwjM.)ULbJms#'~|62³e#v!{*gs7A_2]ߢGJ@0_HE5fJ/]j1nqs&T|gkc@mp}\;^ʵP|#nEY 8|_ 7&AALԥΚv)BxmR]S5#9_Ճw߾ShT5VrٲG;,g˿MRwp&Txz'Ht0Ŧ=TA&O#(]ge/p|ɤvReyҶyuO>"S _b&jzN} [58^n>_U;Z˚G+-'EΗr2 u+np5p=zn奚izۄSp֨D[2c3³e#veQ=M`)b\R1Uc9?=7N&mcbgEti`MZZ#S [sLK%rYl 1aK?Rb*!r 41Z5Ə=eAriNXb=Q2K2xA_eH[^)<&Xۗ?LM᯽8dj0oSVJ /\mdgF x#md=D>c@msL*0M7^[ϮN^hMoZ+ElCQy9MכG1' rj}ܑ`ijf^h.6Q%e׉HQB1N,#Oa@GD}`qoߚN'ɤis(⍭B5J8~?MMoP;_z7{1³ech[uJ־5u]ٜi 1oO|r7g߽Y*@tq2|k26/M^Rl&S#KYڔRJo b"bTUɲX,fqmxSFo<,5yphLLԶۇ5O4Ӥ[.reu)<}ʵ5GƥRN_-WWO>$!MĚ*I7-´ov* Eˍ jtbx+E}Mkr*s[`-0Ǧy@W+fb隨| eZk_;je[8J$/.˯_SN]RǏ??C!oRCo?,5E B>=S/9gõ*"*?ƥݝ_$.( ,*}4qmTWpT!hijD Esix%pL8+6FG;=iX(νto}O4˞p-ZYMctgi3sNTXD&Ҳ ZH)3}!沸´1)gihT,PkOӪ%̟4b ڀ7]9_EM@3 -kEyaT03 ˰#]gF D!p~;4DK'[&@uvuǙUuu~[[0KHӪrWͪTTJDq,,#"K"CE䶮{zQK|aO+uP/OٸZ%UP,Ye2ܪRgmk6 SAAHa1 d|@_}srpr3(9+6h'2}*'fDy\2s[0zfz Ngi8_==t s۞ Ais{)L\~nf"DQ v P/\P-B^ 4WԂNUEAQ3Exn,]u]9bpYwsڞ@UhT"moh W^;!ٰG;I"Ӯerʉuܥ';8QXfHX=mj`n+߻7BvL*JD$<͖[431iy%_=^-"h]5v4Te\\؞ع:]#8ݕU(LīZg@C!h{Vlю7rƄOOMZk{N pf׉Őr1HTŽTDjA:1t#x`2N/]y`t/ rW iL216KgIۆT0M|?^"b fQ /ۦm661i™r5{|!DK 40Wp_} rm%3dv2ifLc33gjtZo^ᩋ^؆9gҥԥt= dR)%Rx1R&J4Ƀ[[ꫯV;_SD5Ba}:ΒxԥNvބsJmx߂9w),%PwMwx߹(]k].bXXvr\2PÅمw{e׽zߙ-1ono|֋s،G;L.0?V&B<_3wSU6W06p9K;"|YTƧ}/{cHa$dsYRDp\bE{sn[cui ht>]?j 8͛>=EUf"A$6Fw.a>71&⵵_O>]dt3d#v">P2[sV"5^qE+_;y~aP[C= b }w'"=#mNuPKI gz4֌F KR/l,<;QA|붳wo./^]>$PV€( w?T2-5=(c֥>x/%[)+3JFώ@8Мh'|a/i~>+ך!,2Qc2E< Nضm4![wIГ sDJ\ܺ9|ϲs;w׮lmnլv5q϶@IpXgB=EZcgF QJѿ&Ji$J p߫9PrXo~чҎr3rB?}ba)_[> 03YIlv;|7 fJ).L/ImXڧ\ٌ߳#>oʜ9pQi-BE΋s+s@Dbk޽u˅*J"#3qGw[&%pNyb\w>UOH0ϻb&}Y76MӦƩ16W^;^]! Z >HJq>- a>_|ɅcY3g#vS͝p/.m&6ӂG'2* ~t[:|S#Yc !D&Z⟈ i2f3hWm~B7j%Ɯ%6Q^B{B|c9cN2Zt:].!`^A۶mZ9Of#p I|>.6M gV`<̚13diMYxGA`Siy*">W]-b\,rL)}}UA-E&$*5zY\{Yɤ}\9Qo,9ui,]J)pp--(hY."u]J]y|QDetX+7|j;e/!ؕ >M5?Sk!Lɷ^֛Zdv]Wۼlɂ)XfRZ,&%KŐ[1pBhܸ򗮽+ /ju&;k/gPC`+9.]UQh{ڀp7Pcau=v]N~ NQ5zltv"'RKKk-@DoliNkCOfG0iP"RC kЌ;Uh!ᒧ9+űl+'iO~u)[3/W+mm ?Vrr1_XTk^w>gj绣z3g#v"Y}Q~x".z O2rt>s!5)$-n:o^Z񑜶mڶm%"f !|}{SU{p %#/Kc 1>GgF'I6eM98 ٣\;Ć-4UgFh'2+c PsJ)+@maZmXt]ץngwܡ~WQQDk -[t1b M1ŗQUkaސk7\}RZ.-ۯ/mq?m'w'=eWbdf3#"#d2,U3U%- NZTDHZ6+FBC LIlJULɬȘ<|w5pwsy=Az?{aϽC)s~,yYA>CE&>o VBUcy"R 00n>¤p4h-Et4P`dY& Á*I^B(%tJ) r!tZѦҕPq<o !L?P1gZ쓗6ixoUAkL/NFX84L|LR*F8cSS,Z=$q#Ia7N?SzI}=iP"oM2J8<k 4@WʴYRJJj!LRB, k줮<@$R !%mGkY09uRdٶ핏0@"z<[5749Zk) cJqWK Wt=>Ẅ/{Ӥpf:zӔBpMzƟ^k))J9KnYeJ :.24M)BJ!%iJ#w'N@_Y1Ne;3; GH J8@pi-D ~jn4!,KRLdEA=`V˲2xs]onILdi9$ifOJtRR0tGRD&0AA 7`ՠt@+5QJRʕ6;tƋNmϣ2J)c~y["ZnNӇQeYY.?-/L)y Дىb-f2Adhm"Ym +"}M[\\p]5w&O&i3PLoEn9wx`=%1wv>3-.ȲLHa ==6qcB, SZJYd y;\̰*Vɠwö2E!ZbņPZqo" PBȳVN0ە{~'T^f0E \EJ_=U*)J+Zi\/L-¸S\&c"ee}QMwJ+%ĬW4}nja&@H IDATRyRιeY6npt6ĸsGvR eYaq<LrΘټmv>s&)5 koQB )J 3o+ӗPQߒ?Wa2~J ܐ^Y&TB`cqD$ZpZO/fh!JR7׼jAZRJBΘcI\v[L'Rm2ó|M8,tg@ ZK%@GeA:wДRJ)!6$52t<[rKeߘ$),s^J~?:Bbn>=SJ \kZu'veG/(#,;b7h PJR&:da>z;lsH=RJ iD$BTy@5)OJJ!ʲ3 J)ƙz[u!DH!4 17PgX5Z,4'nFnj}J P6wv:oAù"R řpW}TdY5/lu]۶8~di6|BJ%e&(Ye,46PJql{4`JQ))!njxsX½- !Zifٞ“KRI38JɄI,4%2gh9 :XpxIǡcFs~{? ^2FQZgB@jۣш1F)]U {< J5] hBT4My'pP0E4{֚*)bciMa#0IF2t]q˲,eg.-/mOxsKeBp|A$ܲ2UF321,8M ޻`:>^.h4a` DZ~EwLVfS`&)ǹݰڮ O +3~8qɢ+p-EKnz)Rl1DZ?jU??\r1 L[k% DmU*K9 ,>KJ1F(MFp,bFX$Ѣj(qOYR '㮡ZkJmۖkBz-&cLNsh,4Jcf%]"ʜq1vU~3θZ~pVR:O%Bq:s~8 -J sje͝ NzRD 3F#H)QJaCT[Jp8\0ȽfYfzWK_=9;qwD| I"@Z#r8ckeu/ 3B(-ndƉ{ J)=Ϣᬅs,dYF)U Og{/6+EVhιe[;9X+-Nygvg: YkM)(] ( 4馽gzB>{~<}M˜3 +X8tz2AI$qqyKSKР&DK=esɘTJ)22F:ekceeY[Bvph=^%βl4QJ,I=3‚Œ-*E;d қuĪֳAONY"HN-?[0piU.B .TJ ۲ȇүz _O.4U㣊ʲnڪУR)2i @ 1-+GXPѢˬlNkU@ w@*w fԟJ8I`(hhE&DQJeTVBpl *Q(9ymtz癩8pj-J)}Pj"RjM^kMs E!D8o{@ҙȔVR |J:IQsh4| 3‚Z"#|/m߻}81K2O~z=LәMʟ-[f?}sVxL{'(e[DzMʽ{*-ۿ'֪b+]zFŒ"n ʇ8,4M4 ~7 tpaa->n"_tz@+ {: T8qnoS~vls18a Q.LrlziR(V.5Na$qǹרy3PwfprRi @0ޘVo,dOǟMC!m};_hm40Fx"ʲ,˲( jGwiNbXe_|J{T^)۳Gxyyޅ5X5z1 eyjR %-3Opgr{w!P($eYʇ_jRj)ccg[릆xMI]`Ukٸ8}'cx!a2B y#+71CĖӫ!Z)!PX4;//TZjEh$+]a_9mno_'ϏV,)^m/u&bG+}Mt"7:(^oT{D_}4" nq7q }d>O@᯿s)R+Z[K3@Ƥy-< !CXhrs]׏ZJu9'_t<+Jm[g9L#bDIΥ\Bvz2XႸGX\FQJC~+uKHs+^=%R!PƄRָ8v{@]4pr?}+o/OֿxŨVR*%o )u(b$aŵuM\AT`$.H !y->R!4= 靌9Ҝs۶\^%7ZSJ |}eYCJH$]3Z>#]B?~xO B 4N /BI{Yl ! fM )!.`DҜSp84Y쯃S:#,.D4@ǼEvyxj gx3ELu0҄ شCr] BHms-)Wު=BL tF4)"uaUnZSJcR%R, (7-h-PZIBs vI !Z9PbqW(3OJB+6E o1FYC!I,XKU8m٬["Ay'BWDꅃtkBy=+J)!D)%DF4 8a&_Jη")4 ڙӣ`T_}߶lVY@~?GYa+}c!h B 4" ,[_ek_j g@aa Do׍{\L/[Rx?I;$RJ˲-%:0;{P*w}u]/%qа6q$hvꗭj˖ejͩRiMJza?*n֮RJJ̌O֠t*KHejg}^*ٶm[Rӣpa-9YGy׷Yt` ,e\m٬x( `ԅ]oq,c/T Tg[]/i?: PBW^3B[.J(l6ddu^'㵆m~6RA:^DZ@7}SH>xoZg9/9R*3AJkS뺮^* m@(' ȋnZ8c/m{vG"f^;O)"-&ׄ= E! PJ)~~ؿ"X5Zhq#A?f~Ů5lzV{(A/IXͅE WVJ !R1N 1#,4 HTQԔؕW,ϳW)ՠ I0+ݦ7}S3!B,40 r#,\(VR(+vTc-0 Fh|t8SDjr~cR}:jAV5)GW10B۔IdK^>mdy%kka0kHqtY&-4,˲: !Uē]:Նc۬\TtOd Aq)Z|>}R ̾R)e>m0Lѭ `z9dTn۶L(zx4LŘ0ݹB~7U J J%J}!IWRsʓSR鰟í ߇Q .b/9K叢ìc\5Ruln' v:{߸;*)Ue^*W~1#,:ԳM?V'>3jqg.oFEwߍϏ7^Aw>ﶶw}ЉJ L#_`щBw\4'ÂpgFk >&8/ N?af&8<=\5R=*WJվNU ƃ^2ܰq^H+\p28V>yu./V }ίp5/>aގ 5!cRupRkA6$M,AHv[QPfEa#)˩XUMPTnϞUպ[9%*2I4$7x~7T>ts^Y N8Sbstihz*URu@H׭׹nEJ^.5"ǪѢۈ4~O5yO@h5A2$/ [m;]jm I4$b G.EouR-ƩW7nS0| e]R seDh)RiMɷ*Up*U[oZ wa?ItڕcFRs+U׹d=Fd~q Pt ,UNUzӫ7=H9''%6ӮCTjnk[$0¢ۈ@x>W9m2k8Rsj ۥv ׋kY;5<0)w=|T[#, o-i(nJ(4KjLiTjHs "U 2*pI"D:.+E7bs3iL7~-@7+ 0Zuj Rs5Zrٰ`ᤈ4qK{=iO\jͫ!t}PNDฬRs[{e dOݸ{%L Sӆ 9 vJ՚ pY agyݸ$I`DUkNlWkN<|&F&M\vt ; .^`ORCX2z lz D~b J՚*Ujt{񁰂IDAT@0ʆش<]&^][4jf3/o {uO#(Vne/[+=zxO\;5H/ƍWoBl+s t;wس՘/`7ZiMA/uKFc,s=~l_6 3[cBA/y8mzӭ[nQzzzI0:_BAj.n{f6Rکml9Kzܘ7%~n4BFx !BY0ʂQmux$^rrH/pz=4ӯ{>3[!BwE$2;kumq.`sN` ;.o 9I,vZw]BA/>> Xڭ.ڥ2Nƪb۔1LRqNujuqy]jK fp{#7al-@8S|+3- n͵SS]b*qwxnE4ń@^x3"[:ޡo$Gn隈Xk{u!qh[v* _[[%3fy(a\ n+B/rNk ]5\νν~/Я{>NO|o۟ɂV5Ehә,Dl3tǡi~Nݘs1|:L̻0.ne![ 0?s/*Sb|f嶶|孭Rkq,̠)TCSb%^DMNaй۸V`N紵UjZu]w`4L~7 |<8+l xpBDA@ʋm:nb+yBwiTiW_>{}3!B(0 RӤomZ%#A %6!(WmPv23 %#.{˜ظ5fkm\Y;%n= {M_;uFë7ݓƧeQhv+˧=.y#G+֮_kSo "Sn||0u6xb4j4F)VB7b4LM97FToۥv aĝӰٔӓL,9oK{$:9 Mzpvˍ[*:q$<9 o&D m2Hc c}gk "BЦ#qGPovpUtM[iLӨwQQu^y4`ȯ?yսXB&ub(jN [t~ރ iDNs>|hz"g0ut܅e0".6vZ*՛^jNkprxk&6OQXƌ0#D)ytj{x{o@i9kào^ 9V BDNo:j{zރY;ңWn' <9vf3P_ {sHM BP ^^\M5^jWMvI=a ֎24*K1"n  `koFz|{kFKlPaZ:gcF=}!c0"rv|B㍖*mkS&Aԕ{Ruvq!B薋# vMפtͶ"SNtrDw֚[`̪9'1" Aܢ.5Zl I4>=/Y; )r쯶&Mx]0""کF+7Z^T;kħGaٙ/v]pV.Dbbf76ZDFatvz?ھWИl6N8 !^FfQ[v*͖- ~D'GyÌpM7. "ЅDLv.5Z^T;ߪ9ǟ`]p!0$AILD5㛾"iN_<347>i}0gqU|OXBwY;WܢѠyZOdmEa9s8N# K~lZ_N#"y"SW?| x}| 4eX"&8-]uE!ϱ>?rtO! l|nRy|ᣗzBc|N;onB"8!-:V bz> lkk7#&ǓcßK̮_bQB{Bo Q,34X[[-ǽ]y)GB-lqN7<:~_![^U-}7}# ٌ@2!t[<ت=ک9GAsb44{s >@!J;E&snG~&x q=%&,̼߱'>GB]ɶ%_<6Q˝u,^7?UɅv>,'!ų'>[?|`v s|FAXzP$W?kib."o'(B+%0%,FU߻A  ddqvo^ z!NxF[$tN;V}Zr﷪ ꎢAx"C)BBk$ 1],FvkU3AE~`}I sd!ۓIuMpW}U-=ک! Hz /Li`{z/\!c'9VZjToozeN{ 3fkdM 1#D!${qܟNmj|ެ1b D!qΔE%p!BBw5\XdCBBiBiBit! g2g_.s߈B- 3BBw"0"0"p B; 3BBwBBwBBwBBwaB!taFBN@BN@BNæ!4ÄBNÌ!НV=O?~ҋ>V/ x\f^c (B[\-.t&1LAdKfoʋK]J]0DͷdF|:Zpp;A!i67JQd^vVe/Bhlt <K\~H0Dͷp/5L)'c:BE2yXl(\ty!TpKdYWZsy??k?{rr| raf{-|\E"_Kt`o8i./ YtZw^RgeB:-M~\ BoYBa D!ta D!t]G!n7BiBiBiBiBiBiBiBiBi?BRiʁIENDB`v_sim-3.8.0/tests/exports/map-3.4.png000066400000000000000000002556141370110300500172750ustar00rootroot00000000000000PNG  IHDRXXfsBIT|d IDATxw\W}>wf[V\Tf[r 5@IHBH~u/@B P)8`lp-E͖e[dIVYi̽9sgge˞7E;wn;>|W!BL !BL5$B!ڌB!DB!h3XB!mFK!H` !B ,!B6#%Bf$B!ڌB!DB!h3XB!mFK!H` !B ,!B6#%Bf$B!ڌB!DB!h3XB!mFK!H` !B ,!B6#%Bf$B!ڌB!DB!h3XB!mFK!H` !B ,!B6#%Bf$B!ڌB!DB!h3XB!mFK!H` !B ,!B6#%Bf$B!ڌB!DB!h3XB!mFK!H` !B ,!B6#%Bf$B!ڌB!DB!h3XB!mFK!H` !B ,!B6#%Bf$B!ڌB!DB!h3XB!mFK!H` !B ,!B6#%Bf$B!ڌB!DB!h3XB!mFK!H` !B ,!B6#%Bf$B!ڌB!DB!h3XB!mFK!H` !B ,!B6#%Bf$B!ڌB!DB!h3XB!mFK!H` !B ,!B6#%Bf$B!ڌB!DB!h3XB!mFK!H` !B ,!B6#%Bf$B!ڌB!DN dT Xk'tBc"%&=jBb0~'kBI$ 'cObHr尙bR'LK!ĉGKLz,1d42&hYmos2,.!kljɈ`0wc0_BpY(3:!&B<]$DGD9J>\tB˹[9^Ap*M2[VnBFKL~l( >ͭ%M )pU*& \N|erB:(D %m:FRqb+1TL^jLS/ƉIxIu !W/^WNL*J˹] "CQbLJv !ɆX_"L&pށ d0b1UP ಌ,BXw&N6|WD WRM|1qPj5򎩡ʌB1q5'ER=rЪ$J%!NsR̺bMv !DG!%&=Z Bb-g ++ď^tnbj]`]iBi]!CKt:W^MaT\R\Đ$/DfJ=S.!X$Dg0X F `8rU5 򖩦j4,iCnBH$ĤǙ16~3.ەR˜r]e4h!z !x"%:@FBFhr jp|U)#Mըg4RBlfB'$,HJ}RMV Z[M0Pjzu>ϕ֝hdrI"%:ou`̨.ɓ62ٮjՅꫵW/.]Al>hd͇B ,09D#,##^p ]1VKJZBVLvv !Nn$DG`FOs2e8gZMUK*Jn F=u.]B ,OLZz=-]ApU|iZ`CB 0WM9UgXNB)XF,1>UMu%T߭PTz#1r t9*vZ#)byb*|ZM0gW@:ݏ2cJx !&?X#0NP8Ԓr+1B߻U@WWi|}pG3C!& X#YO,hFODWWW%wzuCϮz#Ι.!!%:̏":HS'2WVq._n$JwZ5ьQ1H`f~B'=642*gU뮸߻AOo巯{,Bv!%:k(B9Xb,5]/'Vu;ǫV$n׷k_r52HGR]BLmS^@=_:׺*tu#dzz@}v H^Bq,$D!q%Cqd8hVWw5`Ib>j}`~}$Ϩ2!%:k-IZ5l#ƃзkhv%#}UNWBo5]Z/\qOq!%:Ò', vsU'j] 5߷+P2mznj42ҼBLm$DanbRPtvuu&[K1Gpbѥ?H`!$$. p#,IL^r6ígno:`dXnI4dnWsu6VEwyG.'BBɌ4Jd{v=R,VߣJeQbkxO-x$DǐG^Xb ܮx$#VWjJ* nvW(+ 52.!N,Xcp%BC$}*BpFSu$_OSyozaۇk:셗b|C#u>WrhԳ$8/%ƞo$_p(17%D;CD(ıݮŲ0bwwչ]= ?"f0<(ʌC v q\H`!,CE%B!, 6,PI|z3fu6#nFP(̕` >_[ۗZiӻJR5<dGKt YFXB+Yf38PЁbyF-v8+_rBvn>F=͝35L'Xcۤ ՏpH11]K}wk%Q#{J H`!mXBLb+[GVhrj8iНJt Y"T!&=zƑ=65lfR'X0`D%1>41٧LqBEDLJ9X@Kt6 # SH*bϯ8K"K.%:,seJ"KNCcsJD(V 1$ifs H`" %BM#Dǐ$ XC̙+KLmtErԪAA Ɂ(2lT!w!:$1XHC q# %Fw)Q4%Z*!Cy0yXbꢻ(̂1P }5ŔEw)Q W 1ы<>y}'d81.%:ɽNBtECU2H`c1C SݥDGc@= tt}hB1Ef"SKY+rX3fvW;%x(҆s5YXBL:)((BCZSB< €E`cL8W9,1Ő?BIO7kp@j-a|vBXrXBL~,-`.6#ĉBw(qYh KNLeczbf즫[15GfnBL)b)PRզ!fc7_KL tG ]OBƱ:GT sxTLtGڰ S8BK,!@M8sV7=>5!ݡDQf]]m$dXsbc` v8RZWch4%:FCm;?(:G)>Gt0C#MP_!&;OMCc`ai봄wtG0F%B!*{w5Gawѱ%:FÍF%xCv O%:ݡD,CQBLv\+uaB ,љH`#D(VK;%x;HBLnJ=.\$KtX#ij Dg-,\O, >EH|j Tx| Ϙ1g#񡻓HԪAOS(v E硻HT"CxBbhA0wsIt$iݗ` 1iy:ݏc0,:cf;NKN3` 1yisN顧Waw$:R!>F`T E %:M#]pY8$:c *1Y1㟇bx(SzpvB/X#iզw< <+!xXb?EGҨმwZ2"]}ĝ%BGU0ot}9X#i421sIb1>?x <[!NN-} ` v\,1%:˵֕`W-C zF6"O q4`C`g,j뾅h'rDGS~IZɪJ,Ij9}-և򚄘j$I+?P*s*.&/rDGRod` ZXu#f&eŮI֖ˆe~ D֟ w9]g^Ƕy_wQ/gd{!ڀX\腕D -掖.rWXo~xN3KZU*4?~n.5XBݍ4֛Qa5Y)-g\9-wBglpދpn Y1b hWS{y|Xbr!%:z#{! 'f= B+J·pkA^mXxQ1~;[P>ċ4sxx!V{*g.%%&XcInZI`Y5eݫ| Mya |_"smIVYlY/E, /.a  qFaVw* MZK]L*KE~G^W=hLh<ģ m\3y4<uyߧ}o9+?{_' >j3E)*FZ'lrY_ yP,S,#䴚3Za\hAQ+C / ^vc_,q՘;{&T".gg>( d2_b]h^4D^Ҟ8AyʂXMB0:Q2shWF8 ݯ{ ~KZ^?{Kyi !F$vJ1tGAX\pO 5 땏 )rkrcɍڳ"+8?6**]9*&Ya28_nT8X'.h8)*D~Ԋ".gz7.Y׼,_}<]'xc:5Xxtj$ ^DXDXUJ7%nVpJqJțQ[p`{8 B0T :p@>uҴ︹jgrD38P}4ƣb Kt,aHv?1y3  BC`. 0bޫ+ޗ6yL~!NhT Ai o ỎAg^$AKt,g!mzCe"7+,TS5 Bsm0NG3] VTFF!шck TIh XZ_Ƕiz]M矿|HhME+rj#i>D`t.~"w ь,155M M,J9ʼ0F5g 9f*;N!"\&l9MYBF+v㑇9%E zxwR?z2 :.rkrb>+ݕ?Ҕݺ׊2DXgqGB}nfz|!XSnC悥%TX ?z-βr90wpm"GDpe a781clQ3pz 7(qЗ2d4bC(K#$Zn% ?"@k1fVq bKBK<q}=}:$E)@Ѥ s^rŬxW,8#px6u8dު)0j_ $y4ojnιOmuqؽ\5K! '~jy較 g9g7ٔF*f'zXMGġ h{<Ϥ6깣Tؾ7ؾ}jw"cqX(nVlMa9yZ2UvgU~kt&QdqDXט1#u29ظn8t/h—+פ{qi3Fە 7VپݷJBJȌɷlm( cD%, eV­ЏGvCc[6*l}Ӿkj!ȀůIBәhhM.g m?r j k ,]rmʒ)]`2.zv%}{-wWy`S*C"[O/lOS=pBH`l IDATnq *e*c͆\:"d ?cMb mUt-!"c.=*Sֱk?%P (b⑃%:]|U-KhE'˼%+S.|f%+RJ[U\eNWmiA&…qArVNm[Cϵ*׵Zoד;NU*F'r*vЊ >f ԟxq`y,]1GvR]p`4ayP4 #{w>Z)KWf\:KV_lUʲU)8oؾys7U9 ,j{AhRPE˽e~B$)Z0WB⊖ y1.fqtj9\9Y])\-Dp>GF=~V61K˚KMs*b+s,p,՜*2j-h߉Baw1H`&ٳn|ͽI sPM٥\p6|ەMm3meKV\:KW6"ϵgWToc x`k> {|wQˣVt}2 K9X # mt]k2հulJ؊Ur@u,К;JŰi:޾?@ybx! ,ѴXE.nV|p B+KջHD# b`Œ%+SVi:glK]wtJg*y|ܪ@>$lvĮh*Q*9YM&8źq@Ky7Tx#_"k2 ,P]xM(=Tki5] ?pl9 KyRga>$ys;*~3g-'6؞$Y:/]2\ktEW?/umX[ڶƞG}gOV<TL>ٵ鬭Eü)iI(2 YܷyK޶"X΅FI Ъ!m5lUJdVYO>Vx ",{D#Kt43gw/5ASW4j2H h{pLy?FōG8X ^` NH5nm[lZ葦s Zr")rJNQQ.e` (.|n͊cT\ع U9󹈌]1?&-4;֩0ac>0_8ZMP];X ي:7|w;_cѲy(O4}ҽfeTg7|$)#^{~y4+\z0V4XvyV嶟tmkm[[JRZ xV=lW(,"RgY\R✛C̉Zm_Њ]aN`rV(.N$X_=pݍh`9=wU(tC9`ׯ<0c'ʘ#Oy^.FktuCwoi)n:_P\۶ָ[u]])rSACFQʉ5VLV5 QanVa'Vl׷ =Bk2 xbQKt4 ?UNLqV,Q?7{,^LgL<ѱ-bm}yd6!3Y K[435la {U- ˖58:W7,LYu^ڭm׸즿?vy*S)ďNeXLFZ={de:Z@43єAn̽%IjxWސ,wUM^<Øj#ٮVOc;8|p93RK+rDW_W~ 9#Pr_L(;gJ7S,ŮUZSuI}nEWyaLY(]s#,[s,[`y# wq=]ܿ]wvKiOy\'w)yZ8]- xUr…ϦģLLIOs<ߠmt1Sa3˾m:z56h7rĔ"h7\I@.cwFvISo`- 5sBY0߽GBTa~ceMt~M\1Pλ26|M]ۉ>u.d68{Y3!bƭvukm[2-*p3{d 9Qce >"Q:;׬j_|w ⶵYtxk".^ōlpDn?&I#;. ,10&-R)/m@V^=6Q=^%Q1*. +.E4$Ahb-Z?gMzMxB"Fb`6lv+S^ҋZ~v S.LKk۶۶ոm{WʼnTk *bȗr.D[^ -' %EW?Ė[4N˓^( ƝrBU\+I#;qY,^6[aw1nD(:0on^ϸ_sOr_x/󥵼c;-։b2\8*aHBy|  KBniכ#bU6_rs~"_H?òu/ip:mx-lE\P]N erc\JMyF!"mzb6F,5b2ZuG]c3վu-|䫅ЪVfQ816v' ,̋Wngp7 Q=,lN< ?hЂ\pq?62s%?:#˜8+/k`~[_ŞtX. 7c|vϵCwe"[rmm,/Y3ś޳sa4 |1Z -ډ߾8 j]f>hg?13gw7$D,sKy+`*]p{$LR[J!Pf1EYhN叽WbAlB80[l&Gi?-Xb!zlmoC`w2wO^v?Ʌ ֌p:˗չ֙ݏVX{7ves[7עhWM$(;ZB+rʿ@h>7M}?SIh9MpS ,D?ze#ۣ Chq٨}x>_oEY/U0rcP 2aσL +)֋]V vz!5݄={d ;' 5,r:_:X^omR;z{C[7u*e+r`Mn1%蝯QByf4UOShMo|YW'D. ,I\}7j/܉j);TB<B*vB?78BWcM {cN)lb\îbP<%fE٦[z:: HBhRS{>4ù^Pڎ@?{iZht8}Z{X<[z,q!%:2lptL(;ZѾк{IhE*,L8?N$r(4XenoS geKJ([pU 4 Y)eڄc7t.|jwLX<C,_^gƌyGwUٺ=뻹n/C!5Њ\;pǠeN+oSJh-ҎDOx vSr q"%: jdLesnJa(gU.mp˒ˇ?.rUbmWB8wz.l'*h%ȢeϻAlRnk~~o8;tf6(5ϻ炐Gwžc~] RfP{&8Rs]x7Š#\tI͖z_w~(s4B*[%bљ?9Zhj\\znrJ &? bu寎nTXe{vyZ'Dxn[a7lTȱFT5X*ﱫ9Zq(\`aMb΅39ܪ ؊)Y8lxޛc{gcf-> z#0~xa9/>6wotbNi^@0غ_SË0 ص0.[_`AENMɅ\(.ࢋZ9Šխ\[[zظ-vCH V#Kono*"+G DO,x!%:kt6ݽ|x hp, X1`%Nѣ M(8suÚsyfU(ܨ @l쿿a inČg,"E 8RG$B4zMN`uj8gdFi 0Y_} tвQ+Ws%Cw+V9ѓ\Nzo7{|w*m%тq`>,*bA_xa U*363QSn0jax$O ,,]1k}>sJϵj:sD7xy"q08T-Ap!7 $*/&6xd}Y g[E`k@?_`ݰx-MW$¾\ᮞb2RY W}k\h ~mݹ{c ܕ~S/S$;F`z;7 " Gj^f ӧgZU秞3ĊsF1E*[bqS/[*zi W+ybZ%WY='$4 ,x %:X`gBD8 47ge0Z Ou b$D28u{+aU؛1{cH0)Z*w^gn!z'*8VA8]N]u| ٭`ϻs9؊&8 t$V^V[Exq|+ GXy+k--t6ofC\TF7t>Oͽ<43'ݠR] ,,X4=]N`bʗ X3JP ʔBj]ee'Ta[^LΕ!ܩu}{`r9W|{wk.Mԡa#b Xs``;0^}'~;n/ѩ:㦹Mo~ [._^ }7ތVT˅Wa/]ʦN/.Whư<8Q+U8^+b%ìF^=5.qF,f犲 nQl56#c#<<Ϲ\3fszʖt]7vy}104-N;BH`g>.%uõF5K.dY(V+7+=I% +4 y_=u5h5'u៰队}%Nl=>: oVPKKb%X!}]son~ X<̳~NC5=a wlW~=p)؏} ;Rb`nO܀{j&9ǣmj0 [J̀}b7ɝ%|jV#Z@\J[ZMBh\j8+a%C\!V#ϵx[ˮkE&}P2uˊV"F-OsZ ,E;O>8M:;.ZeY!0r1rx Shy#TJ!^rW־[iXvl]pԱ}*uV8s60ի?}K`d{|t5f1 *l>q`ӍnsK_G`r+|k "k'] cZ`a7 .p͢9BrB0hZzQ/ka.y ]Z^6of=^JP+fӂ]-e2H`OR\vpL>Z9\;yWxSô7z_o^Vv#NlQep`#+>; }p` 6ͯ`uao_^a}W`/? k:7`Lc~UnL=nKN~w|ЋQ`G_~C{0a?|]q#7xe F]pĸbDVZ7aw_ <ˉ,' IDAT@*< "+]QYS.y +׌pì\;Rt>pǍlM}}5MSZDӸ3ED]H`'XgN`*' ]KY-r.LT:lZY:枭&q8[F UUCݞ˘a{ < NXnp+^/< 6A|^ 䏱 {d.iCOWgC'n8n?sؽo2Ѓރk7ǰ}߾{ag.6W܀;p˗w}ľfWV a4[Y4?^rgB"hrF69 ZaٌYUkyj3cv<׎6tsn犅V>ͥf=!O˻]H`VKٗ-gp>ND7XLb'k܃e( ]te(bB] V}c0kUn`ЋX=z#Ο~_ *\yo>G`, ^s5|2:UTh0껱a$;GH =gxp%z5Cp!y?\x/ \X 8loy? ul7߂OG 6aMxNT ㄖfيJ>{^x} .V40v,F ij1Na~\BvfUky Xyo=lZ͏;ٹVjZt;NhXbJZ3[ -&~͢ *7(e-h;#xU5<}vou߁^o[-gNLs{_  mT.:еJu];׌*Ga䁔ƂG-|v1 {`|װ{R_ w=JL~~߁WQ?C}0`zj/~fs4 .V9UonS8pV!^YQ\MnZvW`4WB+lUkFXu0k/ h 8}wg+:nqKaw$Ĕ w~}*M\&]5rX%;Z$n~ V^wxA*U =-۷WO9Gsz90|+78?܀m>8v I>>i~{c a18|kp׽ֻF曱 >q '7H4/a;e*W)Yh5ÛlsV-\-FN$8</0Ei~i}^vfm[|8hՉ>!3_ ?n ŝEy/[L_ 1Ne3seZ0ƸyaRe\f^%I8-2y+ڇĬ|f&k`3icޱka~x$@}jߔq'ϷTk5i[R``;o4p}2?)bvp9>/湧cd/aJGc_˘k S&{afL/b>zbݜu̒Km_T[L>OW 3_s)ǿd]!j is &lTB4\| -ck.r]hs!e,!@Yx37r|3,>o 1Ī9;g_~}y`[oc-=w|afn,xJH`)A}$VK);1d),(arTVB̓uLbC7e~ $fN !|Ndloa>wZ7󏱟x&k`kUL}m܃ 0/Z~Ѓf3{-wͽχwuW!2om]x1@7* ~/fϝ}Z~#֯C} ;cm;bLX_'>HY/D- TşCxAfB/ _;9P>}qU`ìpӗyknn4qc:D49XlxJH`)AR%Tk0;3 {WyE31ј|`c{I+w"1Vjq:W IR#b`\Y,BvpkWe>wJ۰=͜H'2qV1& =&e,/lзe|eXl8Ku:e g_F"zQ7# ?c9a_e֫0{1/}|CwWW`Ÿ W?J }+|Ṙ^|RdLŹZar7#`˛a!v!yYpr'wL#zwڢhXzFZ̸Vǯ}}9v.vsG_;/\}0.9/> :aιhy;*l\a'I yc>zj FKL ^܈g`^& f` C(^Qtg pS{Y]`kE0X/|y2tT0nbM3 @#T7YzR,^=`;ےqs^a/-?}p s_a\_}~7Μ}|}w V->0; [$;.ľ7anו$|żFlb]O"mZ6L=k\0ԏR̥{ʕ RHe9eI,veBCЋaYL%*&¨Ӣh,NXˠ3h#!y$;Mٴe&Œ\4E/f朔˟?5xpa{ilÛB^س Mg FKLIL⍅.\FDXR^^ @z^ߐrUY3s999'  \{^^WEDP+("EN($@!U+ yerfZk<<<@VdĤ5GLB j ޓ%̀d0A?s'Z`AUHd5CVdP5ƟTRB]2"( 'tN}SlXsZPO׌f2 \4ꭰ~17GρC?Un3;q5Ap;e8KсauHtg@1bZTYWKOeȜֲ#axZ'{PDy7Z8¹UuxNV$4r%J-Ћ 涝 @cu\だ0@.fʹY=wL,}yZШ;\cyQ#T9o 䴭m0sZ zןྻ~E\EpBgd>D ocG 90KrPԒ(A&8Rʇ7Q^Y,@)i?W' ݝ}(_o?ޏvUnA%<nF"?+Lg?ڙGo.Ϧu򀏓V&.A^]5 B#iw= 軛~5"![|_.eaUHOz^:m8)EB?G+0.YLC԰tQ kW?U^+8*+%sĉ8ȿ*C5PŦtv+<*cvtEa=.s߯iݾUI^li?EŇuC@' d@ F9mH]x9d2}9j<"c _Y2 ˆBN Q uǬ_xfذ2Th+~00jS6}&OI^`ȞCwiӐ'daBGS!AMA>8rOѣO `X2VvQd Vð[2pH#ޏ?6%c1"SpU%|E%XM[^HRFWT4,S\n UsϟeA}s#.Pk :N)ɟm#:8Huޖ7}y$Gk>G0hH=U֮jzUU*" H}c Vų7F?e S\d 9Vr\9ye˚] )j`ࡥJٹ|M]32pj/! `Z̬Y@4cC}9}:voĜԌ)y^ꅳ@S|0  S*tnox"B]rQȰyw Sw|ާ}OOlL]oPѠx c͛U4"S JT.$\sZ|괮ȥK<+{:nِa٢n\?d!i;TP+-AF V-,c;> mEa-dF8j/ش5 ^.Bf~3 g{7Ԏt◆ EV]3¡ܥ"zU2!;̞y9HzZLmFI# C/yɇ {LAC /c@Pكkȱ:AjG!kNB;=)[ :Y11; T |~yy@HbJHfz-40-zI+ k/?=ڕ9z?hᦫ_F<@Ss„i}xD'~O}k eP ;|]' Ji@5 Uhڿ") "Ls&䞿y| 7Ex+N=Ƹs))*,%.GwkE?Äo.e |,mϠ csUBvd$8j}n[@r\t:f5'5_H;C$"$0{9T}XY0m8|ƿEESXDٶRp t}r6Vr$47m cKF|lzx9K A YCMBkZQ'mۂ^yر=D<-IA?ރ~$iEk [evfd̞kU%dp΅8Z+XXڗ*SU;qbޘ·sʞd<b>ѻťO u:Gݕ_zzUQ*"8){bm\3av ~Xq>0n/SRǂlۆ#<'΀.b =8ܹPM}9Ӌ.xn~p2zѧנ\<,5鸪Ȏ`9V0$euK(}ʺYЅҁ J폲 3#OCWNDG$ts' v: =tP̢}YXlX[H y oËw4;R8q4_sċ青:r'NS޵XFla 91/K]Bt 4K{\N_. N/,m3Њeڬ^z>ɷsk=Kռ\3@'?lz])aEv inuHmzX(S(Tĩɥ?_בo-ƀO {Ǯ$A &E7`flG[ÐY[W#8zgO!.^ [=a9g ټG c"0X\N"m Gc%YdH06F @xrTdXs a@#Kg9g !W"WqJP~C![w #{8+? Vxڋ۰ܭߪĥ͟ xN9mӟNR7}r?BEqcVh/r9D6õ;m#k+ǝf\ |ēݳYú;^׺+{J`Ud* gU0^)Gntg`TҍCSZ7ʳ&XS\9K@Ob_ŒSEEy-:jp5!Ztr8`OdPdPGB_' =?㚄_ѴBgXQwWQB C0#Bn)5.hwL#,CG"=zāPC6)"?9xwhkG֭@&URd }y"@#b"jF .dWQ~21σI|(9ωнH9VqM*mEV)-{YJ">->Zpgs\ǡxM|;?uYX+$"" }a]O-\džS^M+P!LP--L" }4NmA772<K qxX9A@_~V> 0TCK-W?Ѝ^q/<.[Pnv URDSnUOHRٻj%Ʀamʸ3lM9ZTQ=eJ l4wǣu$W,D6vAEoo= z<,֔'5!u%Y<,*Tн]I}f/1\ބ܄;s4uZ>`Q,8Zs"x0.M`˭M=39Zl>GaNRv޴Y1fa]=h3|pμ g6 ^׺+I`UdAsHnkya\Xx{)Y18HxD%|=qC>Jq l +h_I:?EiJѵm7`SuytϠ{7CKF7w=SzRjD{PH!Ө<&|cP3:agAJc*HogDAk^F~xW. ܊^U,ȪA^~| IDAT롘>}݀^z6Y%,d[D>G `*/)ὀW <,}{AdynYO`+p$_h.V_W ʹQa4>? ?2|Zl +S@_Y%r5;.\ٶ^z!*dR}|Qї(xƿ~VrbCH l!R[\cde@˃NX0z7 yO|ѻnGuL<8opɨt? A0^؀J(=ݍ^/%4DygRئ7Aj ʰZ쑗k@R7/+uW( Y $pWs-ڕם`༏bԠ/A)Z4B! yc 9J}_S x- ZʬYKZk֜RUjE 6@|E֫$X~E/ڎlpJV1K8|وW֬`Mߢ~[I硝-X>N#@Z@Tz'^eXN8.^4TD, qJ_ѱWZ;=[L*k} VOӀϣK zeLk0^G^y#^D*$Lh&IU/m`H8&ۓM%Dp D}1wrῑ@JIf-+}- gFNWG {˗!sm7݋\w?m6(x|5`J[ȁH`"E *BQR*S jV( ]?V̻20 dP2$#-TZ{Af3G>ӽCcBO8}!DsZd8OV d6󟿀sjt E EZ+ρH =ޓtq~Ds+Z-HTWs+K$j3Dv NuF|[:M|~D-;2gظ+|6`^}ErUr 5Yk>q2nR3TM&k)+dRX-$0f|3|7Vy}C HH(HIZҺKۏ3# S+Ph6V?i^^3 FdIr fY~\rxڀ"Cl fz3C_UwA':A1jB(b( EH0Jf~, bz-x׌ f` 0HsTUWG<c?[AF~91iPrdtd1_œhiX4^=XՈ zR; ܌ bWWqth\[~^:a畳/zvhơ򕄽=Eڷq]'+W|mfG{/łR]cAW]} Ȅ)-LZj검+V"WU"n!ٜᰣ&ۣ\vQ5#TeQ!B W+ %r?F$˿GG $BǓE3  YҀ92|Fxi1|JÍ7g|E[X~x ډ~|*Juz˰98H/Fl='a,Up#Wx1h8XNXz%pM) {-Ї~V&Qϵ*տ}pnA)hy~;_L%y=*r إWNx~+/a/^Y|$DǮPOݏeInK^J\2-45W\M.sGؗ%0`niN` _^=n凍C> }bP(a~s2Pd|̝ C.]mR"͂^n#[!9̸2'*3<9@dq9g"d>A9 $C^-kWƯʭȗ~mXƏEV ٜ39Qapp@w<}j?IaEYz4<y*͹ZKiz.-\hh|yL?XtMjFܞ;+zngMK7|Y5V(;ؼym]- Td2twiֳxeysI`Ud SZxLQ2F(wϤQ8{6@.R^az{8ԵNL)t[%Qr9`$X"2k" D-M ΄QOÆ>d dd<gᚭv-(T2h.2КaU\T!JrW6G#b!Uw8!dQJ57Q!k2|8|SI'AQd|t{Ҿ3dlýi#ihT{^`9t/#~#Na܈V`냆Fslb@RRxy*reYyt/!q;(dsǭz= ;vso8/,w"sI*RbƔ~JO"k k¶Ř1cDeD괫D|NIDv@xFei,*L`L]HȱR]|D1ۂh 2b(泇 APh2c(i[mrFQz[F 'K0Z66w#]h^#ᓨcBA2 9)O!/Aܾ*߫4`<{"46=g`y;RX+붫v_@9Y<S*bIFmb1@SWt~[p% tǀNs۾=6v@w$>>Qu݅ "r{x$JkG"m#|,Q{!COVq_S1wXOO%iwH+n߳ b TlgOMN]n]_"@מ^ttxzЕՐA3hӄs)8Trb>7tt|l. k%w16z*zݰj#AvT>y88h@Q`,]yn zgʇhFC$'VRĝבH\ swaq7nVhż,G/I --1KK"lQ8ZQRטr uuy7,A#;z{?v|; o"oNDzfV"o)rR#KxM@fUKl$}W{܁']i^q~Ku!ԽkWI۸'7y*Pq 4VG [IK-EvRۈN g__bO@k6ghcax3<n}^9jQRB-ڌ~og2{|PE 'FdQaȡdQ _ q.G:4*B 5upE$2w7= rq7ރsCE&F ۼ I\|f`˨%g, awaۓs98$ "Qz8h0;XÎ#n>ke7\$r&!ps 6 5怖OY I2h6 ݂.7k9̾ߎ!NE G8 kY*dR˔$h&X˧x+ع@Kvh>A ;sѯ$*>3=@ Koe1ճ+낖Kv2WXyu+ȼhP#aZ3:+Y-V}xzɑķq4D>oeQZ_q FpqVJ޹ H^~.xZ{F8(=__\7݈|I26:0|D$A]> }y7F~բ59=f:r4@m5@U>s7:u,@QE-WUYaϻ (Uy9zmQ(BHC4t/ Ggߗ4,H &N\.xwW"!J|I4uouRK ܈: Z6n׽V,p˦.}`^EޜR`Ud|چ9j!wL$q-9a_p.4Ոb8˔x^fꐦY|J/2)kK@uqL=]S Ͻ6(hq<7 o3h1srwr9jYvtpuU6BmR{YILku rCF _:9WZBҽ:Ms]%FgEw Lǣ]2"^Μ LHH1cc᧑=}͓Z, ,nxvWml.^\ aYȘahu>u俑+Ё[сaXx3uUyoq@pŹ4qJۏ'y*:v*|dߤ(QǗRat=B1p_A !s3j< C_ skG>fȭ8Qv^;KXV婂{懏vo{0[AR r/BtNДHq3N @ϝ-⠥sb >^vZq;'HET\mdƜa VśXdAa:Ŋ'r}%t]^cq9mLlKD(n4HXI\B/ɳ̓Ź5C ^׎.8uH0 Ƀ×?6[bSJUPS/AӠ Ga@#:z8huBM*#F+8 ` FluHVESa5O=Οݾ }v pJbjխ6"~ϑ KSnqQ%-qz7넗μ7MVJ6,[uXNzG$qhMwܗxC ʷ}uiEk,{<-\,Z 6tfd8 E<9Z#X~=lZA@4Wu`X䠡Zюh(BM=Zvtf.#r1rЫrw$WVwd%V;oTJ~ >gaoʇ[v>^ =/fA> /oY3﵀dTV-d_ <  !Q}Ӈ %E$8ZR֟+&Ç1,- \} o̘3Qc yyVE޼RXmdf&MoeSݬ~i\mSRED$%@+#y߾!*SP;m\^AjBu)Z0kq$ {<ʺQ9dz@3-)܃*@$ec> Nu0d8`[E'߰u*pwI:GM# +2ٯt)+07+G  /R׫]T-h=7;ng^Z|h:tyAͰvZa =j{]05jb[4},%}!=#>K!PgɋC <+lx/UFI|qā(b]'нf|gX~ֻ,4 A%n^뷠cV [;ޛԢk}u:N$Nef@ʇxy䝰j)|"ԮL4 lو>p;|z ,U#:; Տ"'9`yOUlբ`ЙwG Tna "U dUVlq*Li'MK9ZE .=?=l[2w(Zkزk_7Tpk IDAT8Xm/*٬<1I}G`B8jT\Op\9[2`|o=$se\[BOay[yeswp _AkB?c`K0i\ɥ UoQ($_["CGqI,2j/τ!sCFA"Ș h]g#.U~89fog2uu} y,\}U rO튽,hVYYucw! ߼ܺMC=J$7 >u*mC:3-В<[el &lxy'r.^ Cxl&)@r@˾p7I-S5,scer䮔4hłUW'~NT">k{ (||@†N:;EHZF$^Rw]TnTA' 3S܍Ȁ6ɳ p\9-2 *OGjKy#0y<2yg""\t# Chݢ{dlYYy觰c2c-XCHHA`#5{ALnOj,+aMȀeh^7pwa1x2~Old=$+ +8d?u2h99\sKVyR?LU:KQZ}eF7XRΉbk=@=5/}P7%*ySZ(^LPiYz vLs0=y]7TVEv2Dzja?9N:FSX&  0M)|9 0<ʂ#xK䯿ABG ,DW!S'@sGUؖd~ctp<,YXb"Uf}apE9iy4l\2%͚0ja'd3ҸO\R`]g%4zFt4%Z=CʗhMzQ4۵sMv9Ț<˶v+?HE\\)I,#QM'|Coӏ7@4f\ƞg"wqgdꐁL)g50WangIy5>/Ja08("G4<▸v̶)`XnTĥ@@` d&!M'!Bdŷ-O }%yŴz69\0t ]Վy4>Pر5`r 9f̉ >~/SeːSd 3kߍdɪgddm;n(fov1c識?W S4&K|4H)h0F} lIι+ORXm$_|lr<3G?U aET,X٭d,_e}Z zW9 \~[h+@} ҷk o"/I0vd<٭C`P ("wo&"S!;!rOT=1d/ K9iОr"#ơ @f {oeuw5WP(fpg`Y,25Y-Rct:$+3ie{%mu+lGhQI %j(/~{=Ջ *֬ɜǺ'[D9t< K-O& %u¾Ğp*(}߄*ŀ럆]7Ī d _< !7#N{I}I!84ǎw4~dLj[ge@  WG6LBw,d puH N7>lޝ8d9 @$uL(`s;G`F_6:Jy!ߍ.}w ( fga H^Ep.ahibٹ ֑@cz_>As]U7 2x+ȦtYO=xix% "M8FM=@^ [6>G52!ނ3Y DԵ~ ;/yS-ڰZ=I.ݮ˙#0dͪ.նn|s\3p/pyG/^XbA/LGGpY,MaX^lPF* e$ьy8ui!xȞgǟ˶!++#;#}u4gtçv9d&2!5+ށCZ>s,i,|{yfiZ&6lB=#p*n:K`D>9 S_Cq'w䡿F?kw!>܎4c# "&Z%70x2q3Rsu?  zc5 NJLXddx H8 ۮ^KXRgCН5UY@6UMvn=]Y2xLT*5Jc?LJiI.W95>I"6'Zn:fvz鼍^\PrVƑsOXJ]Vjn'wt6:Km<0" pqXqhU ^xv^RQؗ'Bٯ#N F`w>g_{|6 Y >)׉L^g HvR&5꤂I8GI9;j{UN/_V/.HVsN~ Ti=R?YP 5UXsrz`&LmxC<2(d}Ò&PU(U@FO,n<}{Õ4< f0c%*yYD _9fcD-BzX7BU!E XּŐ EbAΠ' q D1|}/r*uu'D~ti_/=~ꏑ=G ׿?؀ko@$,2cErEp`z}~߳,3ᚫ~NU̓ݵc+PhM9!u¼#=_0F(Jf/v%0'é%.P4\6p/uI⁖Q/")M쒀#_*ݗB+'$@LpGRc]eZetzuzzq*Pt ٺ(~7*{dA2̱6]'L9$WwaݸI"n=[0{lb2/n]0 =ǑYS_ՀGZWC 4w CB u̚eXp`KKe{  WC?|Q6z`B IDATL'cqr܌EO ۶ >_~ٿ.nXAnǨO7V|fȷ.}{F`z/N!u8nj-,N_ Q5y+^,x&-ycM# 7@SU|6?O3Υ*\+/1I2]ua8VX[@pBT1ŲͽQ1XX"0X㽸.P8xyЂ5pt]Ԥ`$f wF<)[r Q /u[&'iX|`jx.w(;Ss8f,P_ X7 (YogrbRG?{ GCv.9A䓘_LaDx'r w[~ jZF94+;c`r?`'[UNZ 'k߀|Sy d&z$T!L"7+v9 c*r!?;T!n(.ְ^C0Vܥ~.Z:@.Xj b¶-_A˄XuKT%g&N cAG{ V/wLoX%[p*/&s,$2!Y_dQj˜,0a!2mffO np}2{VUr pу舛@O/ vR3'JkSiYYBeз]hѻ,:Ga8п0Wh >< LMȷ:CR6g>54,\[nf &E>-ڋӳp W(r Y/"ãz+zh /sw#~>{ kB.wC<wHn HqrBTݣ9l"t`JYK |sGkqjy@Q ~V_Y~6| e#|輪}x-Qjث0U$U/SfV.vzrE^}+z V/.0jKXzaHX,3ZGFxV%&RO1=78&CUݹ "Փ_t1qBy }KX)?v]1AZu8]R<_xс#  CPŪq, 'l5ca XPVXx TKNbr>+oC?qrl~t+#_~3<|/$[ٰ]ٱWg,] pTh\ɴƳ60/?^~9߇r@C?[yo1,>'H{9N‹x?;h0gmZ0N*C=8CM |vɃh>YCv$ a 6V⡦zz/|U·=0={/^JV/.HM΀hbYz{(Mj|*0H/-k'NhfznAZט,ڪЌ{,|@x";`޺ 6Jn#3ftxu!(Z&_-{gP2=+8ªa-a`\:ʁ/Xvf6*e/;<'h=s C/yepNCw"п[̶mp4 }Z9ۦ"MqA}kF?nUQK.NtJ7W^Ya"PNk O{ɭlhoɃcDiMpWD|.߄џtR30ߓ 5.5?Fa€NUöTwce|vj{sjE^ȽG~M{Ĺ\hI)Q!G!?Q~Ȯ))t? zy? 0+GcyWуnoubB&KNs3I䖟G&ߊȃ'( \UK|x .%T3(AV /r+ȃާe=-_Öjv8pLs H\_[%DxĢO_F(p٤C>F=LZO_Kgҿ Ź?񇘅θ_SLphh{cUk1w~)`LL`btN{L"B)ाo"7ٯ}A~yȉ%׌S>k"5X& eB]ܓX6!~G**N10F+,ڔ]`s/Zj_b%d9ӽX81X*,>wf)goଙbL%?Ūu͖Ӑэ7GcO]|sm>ёQ@C؄6cϵՆ1SSii0MweTV^o MDITu^³(y20|(AJVd5C :LdE`m?4f*h%A>x܉ٶ&VDny#j SSz1E tn33GIMjzt_ V11<`l %35@^Iht? \K_J"t?&x[آ`X}\ڽm11>0{^ҋW~$^\Ppy%Fs.y/ʁA$PuCci }:j!J5*j7L .B1ggy9r4=G0j7O#q?}yЃ7ˊg#O9QgM|+߄؅lىe"˕DNdWM{㞻KɄ' yal[TLվ}->98yPk$dbYћa;X8Iҡl%zY/3ˤC- 'Ib`Bٛ!Y.ҵ=V/%zL*ŒK!3iwM~qEɊ@xl\J|ZehjLPɇӈW0y F=SMC 7)Fo~^ 1Fva3eȚPڌքᅇ ~S(4PCG3:T܏ApCrh0XZ<) l5. 9x'7yb@h ȑw#뇑>fzf@Ny_xNr|':Ѕ~*&$ `x2Dx ~NW|G~ 4ZB7+C̭1J{́!s# vd$)%XU9 cĽoVq)-׿SݬWVe>0;h4b{ыNxH%yMbga?Љ+/-W[>˪ʮh VuS %{6A aȺ:g,Z[Rڂ CYZMm3 ,<`i9F.%a¦'(ɫ(QJ Ai:2(գ"G%GN\5E^(pGZKH5^ſ'IW4@^,IN/9 [F< 7h kw8T|C]8σ+=.1YR*xzO [qyPR:Xay>*~Qv"nS_JJk^}0CPKˣu`\zqAE$B7 T +)C唳!u˷,,ҹ{MjHm9 (;̟a|=)Ts_J-;X1Ƹ>'׾\ւ},=YP,Rڊ$X? Ik "' ʜ!DZElL4nL46o0ڜc#.ev윺5AK4H[i^ fD6Z,˘_3;O` }j![VÊAQ1p緐6kϱnOruI_Rb,O|CȍoF-TjHmnnswoMl \fwzT6 (rP@#k^ j\.dF<[wß'Ȫ_˞IA$ osG;C+|Z%L_IA!9,D\-iC{ՋsBudDXi$G%jX{!(3̎dWY'kwCUݱW>tDl,Ԡm9ԁtR 䦵:pj/:%ƔnLa̶)tQ84&:PM-a]rw+Ia,K+P4ap`? Zȵ@$t0oA}0ȉ98pفp%LϞ'+aF6 JxPc`d00J4"^ Vɞ.yXߚb]Z@w*字T?Yt3',t=_>-̪~x747>Dux6Iַ 7Wm*Iݰ 9ъAS%ii*BX! 9@YvS2GσՋs"B(jBf(N3Ha"3c,ۂ+VHEM_+Y1zHkY4% $(]@;ǑJ T 3|z{|{PTK C6E@fmkC;cp$cѵ9 %,Z<ǍB̟ϊ)S>3qȶqnc]=#,;> &y+ #+*#Nע /s_ g˖raGzPp JMzI~߻=Sht(ieų=do!4zA l<_:$\{:8-oҭ za){0XGMK}KK?&*`G`₋.!{beii}Fb[x{]@JT1U%:u҇@YKAB5t0ݮ#Z,̠#_:L/"[S3o.Vש_B."sn̡g e}T}oMXE O ;6ꕸVƱ9>w7p#<$zkSU8sp_:jeb-2]QU(|n8i/bXAG)s']Sǁ)7vȚаcWWTx&L+ IYZu JΉ!A:\V#KG*|K8 p&C2w5/ xXXP]zNXw#]u%2jCdTr/59V$rK`Q>x"AOTɈ""D?2t 2|G,ꀖ疒}R ݠ3TCZAh4UثW=h $Tb{Ae wZn U(p*+Gy^^kV/.^@ȣ bmae>7 >gm mZZBU2)8%B)ZW>T1mi" D2 9ԇ"ySw*qǗGY N#t֝LF(Ow鉇(k7̜D> i~7F2>~  592=(9n!Ыze-09Ze  hU[Leh4OjE i&dńy0K*(0pJybv[J*DE wP K c~TC"h:Y0'e^)*aŹF`₊StFI!UD[2GwfRVcî³K TD=Ѯ?c)(O 5juhVj;0sCQ^RwP YpyZ|7&kN@`q%L );/{ք~ b$kBsmMUhy)X*'UR[NDTI1Q!E/-OCY{ 2 WanUW`/H{!#Y'aX[:t0V]_~+֕ҟ3X-I_8[O_%B a1z^kV/.łn[v@thcY]/d~fX,[ c%wY/RZrF&*+GS(ZΞr); ]cfPG`iփI QCA'i+Y.;r}n* ]#a=<$%OUnA8҆rA(Nd0z2pPQ0=સ=<,zǙzIglbՀv.KJ"I9+P՗aX> kN`eՏFMyI/~XzqEgkKjK1fKQa+7NT/e)dYdyd-hg5"h"i~0aq 1 T ~ۃ7E`.)mA|+*';E*'3s8-Pc@S(-o@k)ł'oUUG3==Ջ &fÒ*X8@8ڇ i|C*.4YpvO4,.zʳV!KVpd>6Q5hI?"(&C>K`vOx1̃0WՊQ-Z} ixARʼ\c1^YM;#S&u|%0?bF"Ix1fQ#ZkkPͳ?xL2xS%a=: (L .:)Ha3"d2~q+SAuCsR3|5 |[T +oI(oJ=Ջ &=5Cȶsa$5 d:4MOkesy:,<1t,`{k07eB,fP?cCP{˲.&Jld|E<%$'^=iK|H[yS:EBYwJf"&l2L夞xeɦpCtI;w-'bfvgz*UU{Ap?#*[MV|LUJ$E!Ϩ;!Z予㙧lم?^ j7` Dx{:8QI=/-z\V9Ш:FĪ(;d"YSt2ܱd}݋^G`EIOV`u:"P5YXo\ވHS-m`A ")D#ʑ#j_d?̳fID#zt@6mmʤ s~&".4jIvUefčDũ7M+ wc,l=XS]˅ъʌ1IKn={70PK Y՗oi((6]xk'RrdelJgqqP}L4T.k%ShEU&X~@4Yλv" J$E{oш+xZ72Ojr_VQW6+z4PHՠK?MzLemps1 ɩٓ72_l -6mI-Z T`q*֙ZX", y>&'L&&=>_2D@iRɑ Ɠgx29c_a)rY-pQ֠TAQȋE1`97籩`BXXf_aI ћ#D]"AJ.6fMy,IHiF5J}53[Ki;GS55!l?!kfNA  *UTIYU鉽kƹkN]x=۱qJ1}\O֑')jkIv6x/לk!񸙐`b#hoUUѤicj*UbLEw WM0Fc + JIo>EYs #t ̗BH[ϝKrw[ɢV4ZE>B {V<.iI" +&~H`-E8FtYМ:CA] gJ^xaw,rK<ܙHh_ck/HJzB\ t5v^C(_՟ {_>gFAb3h V] i*IRRKO/uݕ$I;nxriɗj(Sex?2Yh{ v`h ibKxH)=b`l:ܿSe){GP'7>32A8#͛mV͠%X-v%2tq%}w8#B~_\Zbb>)BHf9F6UU$gx#)VLi j!2BɇrRx]%x[SlA_xbɕ c ik*$7fQ+MQj9] V~^87A J%ًԄ!&h] qih>ty%*HBD%eJ D&/J2U/: s  MeәTҽ/I",3cM]7XԊETlC}ƍ/d(oxbapf|b)1 A"5FQޑp?k AANkǑR$ZMUA$"Uywک/!,3[ѥ{TXVHlh|t$Z:-Z͊%@L?~͊VjŮRکTèm(*HǮ>J}kC`m!X}f J`UWn܂$ P6TXjyXM_2Q8S~)21X *JX"RTzv-˯-D5BETl D%>7_V@n:T1(V+AfvM5[% ! I{W*lq[=o{ħZј!ʬʞ_CU c,9}6}7%ZV͠"l+*wHa]dUUT'BZcbUUIUUB@TW8kbwLNeꅀ +*Q,sgҙ~ìYq]LuNgx\ U5!RAn/;Y]7kAUt  }gk:לowFwa8pͱS7l_>;niE>0UZJ\6z].tfIJ2;]!11w %}>FܜSr yӸ2 Y6CvIʔ$I)+Ϳ&Jk-sG#]*GGkE (Y^Z)99"jMnѬԭDR.há {ko{Ԍy:ñDxO!ԺY!PB&9IQU DR5WXN7H `tƶZ^3mƹgD` ZբpdYNg)R$#!˛ڦ:UF+j_m &UnN|: e#'X .z4ěw(H)DM#m"4J>sEJ IDATJUw!¢FڈfkP3pln'Rg *˕-N3KuId˯9D|H\So#ȓ?k"}[RcTO?_&Hъc,IPBC3U[su 4I4]"S̚ #z!#|\ǡ'YoIҡ9Ci_)}0rT05@4{l5ՑJ0@D}s%9Ҵàp)S3͚A͍Z28"Oe=E B$)w.xἍSx~[Nf\߯N~ 5QyrS(jTWJ '_}JEF`f:>zE>,5 9t6 ߼ VEb3h=X-v%$Z;ӌqMe}?ʕ*ȋ2O;s/9yTsU\뚞_ن;u#I?&k嶍AJ|(d_x.IV5Dtemҷ3~Dv2%M:\rd̔*l7+~xy |vn|M֐*O禿4z. ?ߜZʙ|4kf/4͢.E8N7^GHD0ί#XyB'Brd\}nH֘ӧ[M&> OSL0{BI |f;|Lǰ5վ)9n[21mJ޹hN6^#S0}k,]8к&I"~ cxj+\fЖ[o33{.)YrO?u)uV!B~=}wn{PᤶFϦC7RjVhYQ)tc^Ȯ}_`c{| bJ)jD<ﱂwΓ$j?ڑLG BH╡S}"Sp S84 Qg%EIJ ~4uRiz~Y6m!;,P4_epD,$1὾lҳz2m]ftdS:aBF0< b> vo6%Vjqhy34o .4:)w-)[mF=s`ZZ[:lUӪ֕W g)/ݰn(TUPUE<y~@өҡXufKQ9Y+ԤZa %*͵mz*R$vP+9 eS3)UQ*f/*a *b͚šה0ZėY!sY(MEV0}=y 5*AʩJaLҊ=_sju.^͈D*X-nbWB)z*; b;1^Hq7b.I9!XK}D|_X#$ ќJTՄ2Ȋ!I҉s>>h~+)fS)Y"dUR(G&I*]۶[di%$2AJ{n},^oe}_t$INNR/kQIt6|M f ?NDU/R?L˘.#a@JBr]PLC 2^`VN֪Mii%I4Zq@c ¬E-4 Q Xؿz9-uIe6Jk&[F9֟Kx-+CčMmZيZ«XCޤD˃Fެ$kC?sҴCUe E)w4[NܶuHr DYz;: iuu&tD1$IbZƸ.:!z˖.0HNa>,tH/}r?K^4k!y^GfSsS<@M6d123T+n+{aF"MGb˸3@RHw|{۷Ce] wB&u^֒R~+IDcgCZB0ҡ/$l|sҡW 'g80VQ| ^@utGAbhM-v%ݏ TTIxx<`42- %f$RpJцޙY7!^ |#j.xL:WU' .*+(ЈLi܍ޛ?hWƔdvn\Q'F1731$$ݻR@z'V%,}oa4ƑD N:G!CѫcZaL+A#&P&{>i _GS6e&QV,75 4~`h3Zl/R9Jd@ +j6yp!!%(@qŋFRװv勉p*UeD|Hٌq o.͓]KZ.Pv.f0b;a JLN+9|"/Artc}pJ]K< P+V8L#eGo?S/^k|j%D3Dk1)l4fi37KИtX+[-PM.5O4M}oAMqoYŮ^g~sPUk7%RHx];OFWӌVTU೉R,{g9u Z3ٳGx S<:@kU=Iw//TNRq%"cL7Htr?E iSAE.AMȜr4rdAԦZjAГ+#Nk2U)nFvs]+ebZ#"rU"emRfs#e,w 5>a Y8_V-)=p?IY۵HjYhݼhEKZ^\ч?S<=}\hґ2L{Kw HVYƠ2W~4FSc\phێ7?}[;@7bYcX#X)Sf1FIV^ԝk Q=iM)d7CAoCu o yo_>v JՄ$bs#N4r܁; W5"̔*( 4^A ;Z UNSp|0o9~EY~shO@0FF3~,÷cȩ{ϧtẟf2$IeT_//0dEvHRQkx{c ^jXkC;{g}ӛ vimn["%3c{6-$>E7َ$dm ׁ )AisHnL .qQ dѸS"!i&v҅4ˑ\*G< m9!O*46<πP 10IL덗\Q=!~Q=D@.`ƦZOL!==6ёpPUA^ #F!UlM?mr"|cDt2173#^۝!˹ۺw瞩cZ;PI$LȅN,K ! 6Qc& *yxht!3ODDcd9͍LNm5=]cYU>q>1-J<5)ӟLð5mkx}zZl-jkd~ׯ!DB2Ħķn4.pawSم֘,S .}IDl1U9('~6RO>u።I .pǔWShNy>ZB͵sIRZPdC <Ȥ)Yžs& JpNLf %ZU\rBUO e|@wū\@nR8r{"8xS9[nԀf9Q 69̴Jc;UPW $ uؔWYܣRwouaвQ>%OH)~*X-6bW^n,/~7dLIRoO+LNH.UR)R .s; `hYa4~Yߺ;D0e ZRI9ګ"LVIE/_ Mpm3 QR"q0mw_q2 IU4Y^)}ه6K+A#JAHy/,B/.FW#`hnUv)mJ<7 B,E}6FHȲL*DC(7 2a0h\֚ gٟg^ߖh=X-6`صP`ܭ+JJISk3WN67D&JI 2.1wcn7w, tgL[8Fe?X4ooc1:ESe5Go-s\,r,ѧϛ kSq uG]&yćpѠL ʿwyÅZXeQ@Mz"QIaѓA"Jmaa$[R$ey!x/CA5FXc0(Th1ŗ%̓Rq8<̂;#Kbch V]Jo䷹RVd*e$^C JW$r˵6T60C۩;,,ba3st;H>CG&lHkAo7 !bjyUhS4r%W@}i7qR%UR%<̯˞38'qB]I.]`<ʗϫxiW! J%$Iey+FC? kϛυFZz3}N ZJL&i 6OEi~k& pϙ44c0Wڰ". V%X-ZJ$\&U=T DRrd}RQ驪 69zg&׵pY)R&|iRJT7}⇎TؠQ. y$/~nmqD:sbn IdLKm,;=if#h !8R)\ۇ rLKD91"ʓҠ_PPךV R7 c!O#߆”A(R]zwNtDʌ~na~;z-v3/z-ZwnwKo]! \%#XJM\|M1SJ<|~D-df:]CwՒ$\iOudn6+/?ygu(ERwcq9NjՋ+(R|Y֥ә%tȲjuf:?$n >-GbpO,RUZWP~2Ճϋi7zɘMl/^wå~=mT%Ez{~[^/Y 54KV ҤC;CIY֡p5}yl`'ew4/A/Ň bעNvޫ_aa<~,'c*4蝇)mXfq` )Df޼Nڠ9;x TU`t C&>-=#Bc*Jxgd3>yByN>)M2͜:!)Xk(OU;egZ +bp ,sf{]d~.#ͺi/^Eˑۿߌ2 bnGb4(bq*)}y3)*rV.8r"Io: T/6X6i?i%nd&ۏ7bba/
    ŠufcX6G:h IDATZ: JUUVWW W1$^FKOwYoIŒ:ggzLc*yF#ZFˉps4< DKߗ5|¯^$tpUnHɼ9@kz'YX8L7yWm)]'R)3#WmwAѺ5! 7J&IL+@y1Gns*iU<`:#Caݱ_T*]tvy1B@Clyi V%X-v-փ $iPNXT0Ǒl]=H|vN;uh%!ۿޙ)^5͸'O ^|*E9Fʄ'-XjwfkT-ҏLK RjO(GY\8Bt:3fc~? c,n:퉫e1urJeQ^D(J͢>JzKz# ZTTIF\X鈑T~Q5àX5=[!w6 X'"} 񣧴HЎmCj%^L֠*?*{d2d0JQ;BX2}PC|@>2n Ȓ/a gNzĭQl.>B9әrGyW̸.\h V] mA.BA]NUW V /iuꎮ\IY\8ʭ?#˩xh≍Ưsk?`ztAY^) ث*' #lw;?-ă:KTɋ\0|=x{aSkW$d3|ځҁI"c4*1'#U[kKw!tUXrOX=,q]~0t  3 #iJV̵vr=$M(KS/tg?1?̆^pt{#M:t;=^4c\h=X-Vjk~U>'{u.L\ cy-VW c=#;9-kύQ1&tYLO=-jbpͿʖ`9hbE9"WɐxW_fݷɊt%S#.Rx3_D۶p=rǓ:Iu~*MZWEtpύ M hUNUTYBā].N/-ZbWCk#$. !DH_? 8? E1&MdYȘLO$UUԿW~y Ȳzu_ 3 1nړ6 +QI?gG|4i6f2Y=5avcXۉ9e=fF}B4(;)JtkĒcq+;t9\l̘"DJ 舑5eB U$i 2޸ZD3AXas_9akro{u#H#V2&~ -mnC%.^QtVV]W١SH^oH )])#,K){gM{n/|xL_//! GWx[\{d/g)*(5 Ju?[ґjBOFzn6X2\ DEQ .9?xh4DUUu0l̛h'Ucƣ ;!/`O\Ʌ'C.)&}/-]~oWo}"d95 8B?:hN?t!57ک&LUkr]+y;փbhK-v-܍ڒ; +ZR$Ғp#]6Iͯ??1 e9әMErҼ񅒦q67S5;3[3mdq{̓3eط/׀*2 ޭ5hrmU!5~,Onf^u!1z?uxcvGI,,k(J7(?؎ox\I.ocMTMbH%&=[X48n۳> }QbSNs൯`Rp'/B;G-YZl b‚VNeI7jnE>`2Ye2Ye<^e4ZfiybzUMr7LϝchU4)AhORY?!e)U:u_1?kTx_G> ~4c=G(:RIfߥ{#~px { oRq{wx8pdđ;>BDudd[8Uf7t:}: <ݥ2?zpKǵH[D`HνS< ucNdr۲~ S_ʙR$(YRVCZeUJRHL&޼w:n ?~k: 1T^Jj,-!bi+UT$Ư'V}h4M8h~KgT#O3m۷v,~ 7LG!IGbtٗbsԄfwChC[jgMcN,o/ts} %-~6}|;Aآf:xeyg?ӏ>aXT庱NYC,MvS:˔um Qbm![7E[3{-a#RwNuu6uh%BIn&iAܮʩ1egf$Iȋ  Dka|E`U\7I$] ͕ +2IW?m?Dyb>s7:U1ڮEbh V]s=Qňx2v݊!ջ( >bhdʻj7-c Nridm$͖O?掔1YYk_HnZ+tc8_}g0XpI>~-ߜp1qL'` ˬPݬMqoE%֢+GBGO ?H;C3_}Oįc)8s *U Q(*gz?x9%+Xk9y[[oWq]$IXٌohV6V8;<pC!Xk޵"M3:4`^I,]] HSbui|/(&cd+oqC{lc݂\w%jc2wK׊ibG EKRB'K;=?hvov_#w;g?3]SxŰ$oD^ (+CƓeBNb[ﻅ$m\.bgUmg$_f0htor辛v*a] 27EUXoF9EM"-uzG7xu_=}箉kPc< n`m&w- u\&dq,8X}K٣;v~yS{W~O,V MT Uڡ,Nㆉk)Άp4aveJUrd(*>w?XܘQTOZ.[MkE#XWLECb*( i:"R2%HQ}Z vw0`C:Us,;&ݍ3x]*'/dyHwIY򼤻z/e~1;yu,S?cؿnw@4aA5Z81F3,9re<s'0{-27qji$]>"!$Y&?"lEٕ*ѺR&MG Mۖn>טEn98`0x~ַ{>B銼 .=2eY]s~~'B"h M% Gw}̄1UL!~$ mKh3F+  fi5t-Wq+yuy:); l~UAԥDzZlOz rփ^80`ƓVww۷H]a[広/|w3χ.siy嫘}7q™7X;SrrR!b0W_~%~M%|x?'(7P4~p0`>.j]oD*X-6DbWCi0ߟ%|ܒ>c\p>-,,_כ38Ldf~m>KsAuUaf0t=СrGQ14EֲX?c ZUnTA"Ek;~8Z(*($iL)$ΟߢM~!dk5:AsS1VfR$_Anәכ;e?ہ`$ZŮVaS,|˟%O.֎ǿo.^1FR }ۺ05Ng:=?,2F+  q;,-{&k&>BS#bC*Sznc(h(р`dzo~rj ndʬP;TƮJw#>h1f@!)c*X-v99|ٕ _\܀%w?3oVVck%l/b|:S]:Ht$[XKQ(U5!Wtf8ҦE%Iʊiڥ(3:yP,U7{{?OJ$B"w>fmr7WX+m)Sɀ4vL:θP;ͣt:3XkQrq&MV&}o΃dͻ䞕MOBb6 `Yͦa 1L ;f=LĄ#n=mm6I'kڒ$&%4_MhhT64xvppl׽4>_.~OzU^40 !10|7S_YxmL]"qy]("z8RpٯQ*֩TO˙V^#z6{qD8zntiQ9ı}*Ofڂ-@A (to)s B &!oIB'F.6̓8F?0xmc(b*'1 IDATn$=YI}WAaOz5Zy N&FqXfӲVd=!<`iڜփW>evUUI:"X^B˜,9amNtz8t'$ZtdȂ\Bq, %v;8gj_omXipBի5^?`o4kt:WYpO?VlFPDƩգ`P׾ _l}>DhZYWrix~JwVS Tic{=]\^BVzK LoLqYK̷$!TlV/Zb:u;mڝ3n-9Yfi%I?tit{}`9/[9':MJTNW+L܍݈w{7ww/y~1=FY+.A''' }Z]UKdvicZŴg.I{b &CxSS}w)' 9YX'`AWWBZڳEaǾEvZeWkиn5>CC-zr{2{fש86C>h|5llO1Au{#O?&'*ȍtb:˴t΄?㱙qNiZ<*m,6M{vb^\6\" =N$0L-ͤ#7gJitMq^#S{Ӳ,c%l[ۉ;a]rra;y5+g nȂd\K1 ]gK~8 T'<NnV]e{S{B>i^۹J{ne'Ox7j&D tLu!_+i&TS*]Щ7?2a6vVAN|O|II|s/I YKPMqG!OW9w:N@kM} 45zݫ4Y_*e;N0JlZ&5~0< ?ܩ<˗} -#"ĘRﳱJItګ44 ק}1 rPLBJb%u9G8;7D5c{0PIq]B^g6-N6N:!Ui 3YGyXYV;GPUv FB9 ?ppm\ǢTRG}ey{$IkGDh $Ѓ{OGIi>0tɠυ> *Gd@,1H}adk&y⣟W CDO$T;1!5ޓy{$:QM2~a5'>"9 ƶJ%薾z辉t"k8&i7DZ .;ϳ(,tF|g{!9*t{ppL` H%^X!VfQ8m82]$ |r9^Z:A]ﳰpZ|.b9_I QNGhZO}8"rIx^^BC c@kNg9 z( @=ax`L\ =t_7L7 %B`ÓK=.VVY,ҕ. 0\5^zz`ɦRbRè$W?_VOqvFa5~GOIzM 1 S]\dQ@znWe#( M9wt3X~)ʷP_babiku8&I,Bvw"i6|x4%B`Ó8bÆii={낫$>s[_O{^ygqC?O'"-CVM1,jӕ.a:Bt~!ApoŷUzj7-Oc|m2 7N$΋oV* y!'YXXX{t3]dDJbiSi8zsӦ@; ' uU7IZ}\/O`9] |zg' a9@XLzQLJ[a_xdGx%ÇۣAڦY\>aE1I!iʗg{?"oWxtZGh$rP~ &%,1f~E~JɶlնßYs{8]\%̟5ܫ=a3iwZZMZlW0?,QA'zY\jdth闢8 €8x4p4tVWN B`iZ%u\l,a1.' !=qhfXM#I #I d ptp0,UF8f3/M_ca&?}|ep_8$ iim%f{|"M7[OHhZa؄lJv2KdE2Xb {4 wX9u1=oTZ8 }{t :&NVKߘ{G(55zugi.M_/oZa1hiPw_1_ˎV: e8NQu ɝw3X?qDži>8G, ijQHR ~Fq˝;}G  2o'^rLϐ+17) HPLBLd% V}$I'/ O#$13ĆH+.ǶM$Ӊb;`HP̽$cm@0 ㋟M,0@gh؏5+ItAAE 9_y]4M' C8$",ϹWY}J[hB1 >hAD<҃%"%B1bir?6o2axսw $79(ĉj@0puDDq~ CN %:˴ۗh6/ >>0Q.aMh~ 6 yMl8PXbqBc2xd!zmƗUo{Q?|w?DatVWY^~5?iHGK^|f~ߒ'hh˙9ðL2s0$,C/>=aYVϳnEN7(G.V.{[ؗ;4|^]ų$qBizN?m1{,Tsԯ%I0^sa:F$xnײ (A,8DzAzNӺڢ_PY($ tWXi>>=,CX#x匷qj&znxs@?w\7X:1)~8NPǝjz.N0ٴP'laԧ}}aXYXa1qx6{m6{ bidwpQKjVah.rPdiY?r +^|מ 8v`m{ > f,r9uBn1p{:3ka Mؾ8otHV;y(ѯ)+z'At($|3dIin_>/friyPF4,H{ƤxDt*~iFr67@C'I0" #3>d:_m8ۏQ˦]"Ksگ?jF9q|đU9'h|ö6JW,q M}p~'|# Nr:Nn5t{Xo<򋽩uB%C_>|Ri՗Qmg7"bHf`,M6km׌ELtm~^G]#+f$:@}#5ٰy|C2 :Yh16qLN0S{§$Izop=jjw}>>|UmbHtDDDN2Ybf)"K`szpk ve[av r4NCoɊ7NkW  p$gЦnl6h4i4VrYChyT+i~qFub8B#l;HKdi.{ bf_?ub0V}.:Jµ+g2M}I]]ns=_7XZzf% |^};6B@*B|@;ߍ9N⚕+=X"KsՃ%nXʑ P' 7h~08Y8! #An*k4]aQ?%q aY:kvIH\]I2sfqtxo>]oaa& Js}__rzm%%&',qtKQZ)y!~@3G",/j1$'T8 4MM=oTChhI2Zx`Zs-!q`Y9L+7fZw '"ڭvwťEdK&ŒʙQxO$ed 528! Gx/}8/=E!ct]:.[쾽GRh9eDȊX7(LJer&ghy*:zRN:M8 >yd BGģ6Gд2bdڣ,,(WXrPdmM !JƸF,1Eqt;>\a JerE|`qyiQ{z0Nғb!!Z1,DZ),H<(ewnG*Lr9-lY { G1K*تT-LKr˪6#^}1BRaK3gNnpCsrƲ8Nh8g6&Œ1.&0,'^FjSZJ*Zr,*'.^GbtpH5;x_|p#03}a6FCd{^ףT6,`I%!EQBjf|eJ崜X,z]~ON'72h|Fuc'"4=Wf 9}ޔo~Irs'RzDdٳq('&Յ5lSK5ah I]%\z~j!IDATQ(ԸGFP`p DV̺W(#Z VCeZ=Ol/*P~_\+ľu틡žz;F?~?Ϗ- *SFQfqqah`M`>8XFLHN\NKn TNř*DQLVWV^qQGa@ Jvc8hJ=X(X5Bh=T4JpUlr9Rz^ǣוrv[ _>ֹӉ|W9<㴱k}8>؞|8,!nTQiU|2pY&iUNu}Z ~חr>v^ HuiaL5@#"LӥzˍdD6$Z*ժMncY9rE5~Dm{[Q>ubBq\<+*GCϯE!ai5G'sw}.?%Ө.Tv˲rXKѢjgj>`)ľ6t1X7zԏ&R q07>? N_z34,I%ĜfBTĚMyS9Q]K[͋%:>w_5A/>x3hYi~gr1/ġ9gz@bX\<:#z]sC6o^ MqP/PۣU!'4HKT돂'΍[ wCw:Y?ێPPS_*L` ,1Xnk?_v_% - ߋhx5ʉY>Nˉu^'' %u:>Q`dLv~<.^_hcXwqa?O~۵^'q2,'r:EfSڪXSGv;>~/' A#{X{ԏ%Po֡IKLC&˞ͳyޓ<{=oh' K=?^'qE1KF;XvJզX\h?u%խ;7OJu|4 %R`)8].[ةI ˙w{}k?fs`3q < 6s8i|/b}u[y*UBIe*Un19Q5:Y(nG m[})b|dfi?e6g j !^er9JբsJ"hZ3ܟx$ unx cAd~C2Xb&N!TƪtTBLG}@}0V[)7,Gj~̴<( "k3mr?=W`Jei{L>BEaLLn*'npJ&gΕAVss= 9/}kVNxeD\f tfڿ.ύkWU9RSS5bY-lnF4םQvkrp1YG@( 'Ŵe%Cݶ7:i3t52 SK:U{ݶ;ڟxæwq4ZKV^f`iKqÈҌUs]%B^elJeRMn8 [h*]R_.+)bZjٳBp֕g%v,{!GXΒYGp ,.ƺ^2XbZ&`morߩI];{zC1-Gq69CgqIeB 6v`ʙ2Nˣ帏*(Jed{`i B cVGeRys91OlQ*[(V٭CQN,o=iy,V_=OlIB .?3,'Y^)R]  熴[ktғR*n\kydĴH%i숝7-,, :cpLI]D~' c켁7< =XbZ$B ynȵ+!׮ ˉ˧TvTQ@ ØNeN%*P\diȥg:^3tDNtj Kq{(Se:RB;o\dq8ri5\ͽVX\.3e|"5qkgd䯀$ Øƚ3ʉyO-)U,Jn5> 7U>7NE`QdD&䯿BO{\VS_̏Z=O-1뫃QvKʉ Ø~קTXZ)::5h4!,,\&2> ( NgTZ=a>[ٍ[Ks]ʉX6TXX`df޻v?M'kTɃO !0c5 Jek#U\NjpYnh}E%ev N  鞌qMp !5lդ]/YZ),YZQugl͍f80tJ~w,^ap5o+$eg uIR!a90 :Xϓϕ9}>W.;{k}use,̑ 3<W BHasrU|bU/+5ti ˉ΍SNl;9Wftg/n ,1M` !w}]D,Yf K,Jˉ*'^ӚfhPZ$7+Ȥkք,7Agqҩ"A0,'j.u5bˉK^`a1ڵ4!=v#W0S;5~^B!\'uz\ʉʙzJfgaQ VeJVc>foVΔ,(HK!n8?Tbr|rZNw}Z F:֮ ԷMu&ٚq ,!aڵ(/,)S_LoU|Z ƚ4˻N 5 .z`Ml睂yjI%buB8=ążZ\S yC uX׮ 8*ΖuѢg`7/Q?H%bW;* ˉΪRs2gWu|Z 5V9ǾNcmͷ֨/F?gj 5IkXBq鞿" a9QY[G]N5FN" ` !8a3W ,-X>]RK,.i\wh9^]|ʙb)B1E` !DUVY>]bi@}@`p|eTNv|]l8:XwX9Sbq0 1v]?/B̅a̕g\y \}JbJբR]T ͆Ccm@s}z+}.ܱ1]JnAq@,!3:>?x iI/Δ8uF>r=5ˇaLSԗ A:YN<7ռjb~H%'+_0/XZ)om.'ޭunǛ辭Kjsl`KF8 ` !8Rr.mΜ+ex0i6<}rͷX\Q' g։J*BcN2LZR]_*P(.`rb1!krNaI)XB!0 i92MjsmjV~m> = upBL,{Bqb8NLKi9qػU_('֗ KA̵+=W:a0uRSg@"`{$! &IBy\wFAԩ/8sR9wss7EݶGI`'<B1' fJ+8h-[Me.7 8:RB}Q?ʡIBxt;jSgJ&7~Rlwz,?\ܰLxRʃ0w\_cA^;<Bl ˉ:c]Xy ?|9iAi`cks03 duA$s^'b ꘩l|y_?P$e`k8=XCÀ0٢q_uB!č`yyKw:+N٢?I{^׍~B!P̜]/<7/qk'-k\XB!8Y|\ixf}ԏ) & MB!t.߼89O^E<X[U],rn%qB!n$/}90we*f qQ,X^Yaye;? [o~٪ݮB!n߲a'z~N^.|l+BvR~:y1B!ίxW1O$N{2\ ݭȄüv1!B̳J[yD[S5Z`:/6 dvuk~,B!ei~ʖ84 vhem+!mw~^>|V|O19uB!<{W]q ϏzfaL*I{"uAoAv ! Bˀ^-YY(JjVߣ3p{Sr}otdVhB!Df(f3زsZܴTGn+84{˟j; %B!đ=:}o.,֊Z(qnJd{w4{P,ִOXB!8f(jesdT- m NSeŁgk+ȢAHB!n(,Sljz%oZ`rjODubIK!' \jpAXB!8vjG2Hv` !☓K!"cmr߫y@ BqIK!"c` !BdL,!BeB!M;5kx^CB!3%,!BIB!D$B!ȘXB!$q5],!BsB!ȘXB!K!"c` !BdlM{5ؾ5` !☓ B!D$B!ȘXB!eB!<}&uB! B!D;.?9u{=ƽal久B1s`d/IT9!Bdcq;C{,wqa4 = vB!Nr^ |mk7g$B!'}W3XY{|`eUF+EVM!DxLOe}ƽ0VjRB!dc($8ft^ !Go 1uPd}gGWB!њ .YפB!l][q~c$^ !Go,Jz85 k%{%Bs>#a?>LQ(!d8t+}ej6y{|ݮ?X[]w6O^߾氯Bqi?ؖ=rY>O`6F;zf$jt;!ʕT-%B!r ֙s7s'~qB!NK!bZ$B!ȘXB!KB!#,!BI%B1 B!2&B!D$B!ȘXB!K!"c` !BdL,!BS_`IENDB`v_sim-3.8.0/tests/exports/map-3.5.png000066400000000000000000003010611370110300500172620ustar00rootroot00000000000000PNG  IHDRXXfsBIT|d IDATxw%Y4|rewh4!YЂV{ 8v+B $EHF#и̴73]fV._ff|DFfU}ߣSi""ܮ|}߈}3B!fX!BB!P!Bj B!P!Bj B!P!Bj B!P!Bj,8!B.8F!Bj B!,:Ex7xMMWs;\y})'B K"XOa.\~5ö-X+@J;rn)A!Rj*X㿎N47wB@@ Bp&8N3,ˆeYdYp]A`cWj9B!P/bp{fFK ێ%Fk p!BFM"XTj+-TRA!|-8v@J^{a?z"B 5,r/+XwQ*. %X+m[B!ԏ{N~? vaY6KEbRru}45qǁm- ?pg<˹yloN_BYs˲la=X @öEJ%@[\IX#ݿ<=jTt|Q>'!BV~BaЃ %TRr8 ѶH %"c 8& R.E!d٠`eGG  S/ReYlYvJjx_)G ! Y~JՂ *5olm #`G#`T17 BJ!r'PȲ#T]QR 'L9 !*hz_W .B! C"ˎ k%~xY8ׂ[@ɶQ*hDQ/ f$E0E~UHxv]PlGEI>AՈaQbB(Xd hU:ٌnJ\׆ډ6p) ?L5S !PȲ#,Ș-`[VftiFN`@"uAhY!4mdtKv\Tof4CtU>ӌ  2%XTº,s6e2nIz%Ҍ~jyޏV B EꂔB NVAf,t2[Q*Q4# gf$(XNp9 {@yǴ]eԤҊnɆe!~4^$^T`O!ԅ8E"ZiX8e nVC|O-{Z`L3B`"@"8c-KDu]?.ȱd e?v1HYj(XEHyKn%\PǘݘzDPHTqa}99B,RT2EjTuɁ㈰KzaR1?G/BS(X.,fʦK%dN3:|58kvi*3HY +C"OfL=1t9Ԣ~ʼyp /!`:+4 lsH`ֽZ%e{W ;^8P0EK-#X0qksYR6 (X~!ZXRayLNOBdq=B}$¦XӋ=}hjn!+1u-:W7rD (Xk/at`}w/a~BWj"\<=mmǩWoԴmBA"u%.Q\<"WR^'qHOs=Jz(]GjŅsӆm,PHݱ,UD联o ou 7_ũc/б^tbCO/QY,Uk~ĭ9tiFϦ\:?Y )E h d8P+RD7x[ .\6J!4/Na՚QA"uǫGdJl M@D`%LzcGutEH",U#Xpldê5͸}s}E؀dE HFd]hAEXo'bEL|"CۇAlÆ>J!bR00ݽ,,PHHd 8Q-*-BG^oO޺[b!_'йFIW 6aC&J!W.Mapd5mhEs9C"9,Rwe5kh( *ZlDCJN7 H B=>y&oIp"L/nB 6aXh_BWO;7% 4hmSEF!f2D+#$b=3^"L/Ѿ1qyJ~kbCOzEȽ&%K SmGWO,9,RwTN&kuZF+n)LCү(|G͋ Ǝ>ȧ \{tm݄[(]4SeLOVQBWO;/M{H>E`[L V*j< 2QRh&jX \' 2djKoXH&o^čb!@`HW6oي}jr߱EgocCнE ;Q{{\JР^K`1>/7uP!r`xI>opL|'p\IWtm޲EvWg{::JX8,,PDTf{"]n.D qUr!\}Zɂy_t I]$RAou7aAp\^ۄo3%d;ѳE ;:EOa-$Z.uN(TQT˔0-?HKџ4ߍ,pGnMXv5zz/x/ =q&nC Xv],](]>giW ΝN DZ Bj /,roo7MVeB(ZQ}UATФD2[ߥ:2"TɨVܾS)▗V̦*̺v@_G޾uo|1ZnCP(]Jy_<O!ФPHc. L?"]1i g:DFO:u_}@W7 pչvnG6Sc .]VtSȒ@"uǫ|k{aɄedӁ2-S=¢jG$T"l/4TTKV"U(Ң+蕙:4-8NH;یqw _8@(VS;0Mq[705YFGG 7ڕzgPHLH hIzd\Do4I,ߛaΛyʌDbkTTeԽznbܮq }QW.ÕGq ՏޡgB.S Q IDATׁWnpR3(XAE%J io#՗~Fbɷh#ZPIG U{(-wajR=BFKKD(%$uE_$[.@Kp /OSշ}#.rOX,Gf=ܺ1k[г^1 i|?@Ih0;mtHkrR)zY0SyvO_"0"LFK/ˠ,VئYx\10U(g"w٨~Q4 JErš_8Mڬ"]ݛеE^5XNƚu-`A" _::cDiHJ"HC6dԀ1'DP!%)JPRQ- PPҢmsZfVAtLGSԩ:a]εYV.KIp?p.-JiTnޘܬpu|C",jYHx+N0[MGLAK7j8uLFZ,,k*QDM\TeH C3E+|Xw !򅣸|>4'74~J׃e:5^u`@" KX@Ϛ$#[2(L82BBsqTD8/ɨ #HYFXTD'})CN?f(DtCu5Z!Z(:fΒLFvb7|(t=p]hmڂ;zz"uK[vu-hnq07m,E=s'`>|C);itdOx^zAЪQsy Q|ISo9;QHGaIBTeu"2ae+_>5vQb38KtuoGl kL .DϦ #W:` ~\̑-2"eR{ #Lf(o&^w:U_тQ61KIMŃ7ff4\5>|uF2T݆.rǔEڱH.UR!]>=Ͼg?]+Lu^!k܁,rPHcJ2 Ȅ8hř>#20P%#3 N (JHZ:}Xf$R9c!h/#cF`W2Ǟh^[4pF*R5ъK&-K "J"'ڔ k'}nHh`3WkDl0(]+ =i)BX:pd]CV6,$"X-8آ1Eꔬl%RF-k\?&lsNo!UFЌ:%%ZS% +tO+F+?J?.(jI$E+އĹf:VnqEyb=}_;ϼ -]^JWSeLΟu-زE i>>%fE,I8f)#23JLI(a:#2#e25]ʈ0 GF*eOތJuFF*R%Ra/JU dN_ZUъP -|Ktp3|0?"_COv摭.ixDk5ZplDV(O~2k7ЁRL rqZxm̴*1?:'OrKˌL)l{EҲaM/HC";r 4h2,{mq77gD `<9g@sۍ܆ 8 ϯg`waӖtՅv؎7jVcury_\ 4;q~ #Ussc6IgGD7䅄)<>*O+ ǘ ~i.hאCV|g3&=Ķjwr.ϩ"@(]_C^] kҵle \:?iBǵo<0;SJEmxnZ w4=l ?@6^1v]V;S'!K0ODyF+u^_H2ۋDKoǧ#]r02ߣhe*!@BKUtkcf $I# <б]i|(X!0tkF0roRyKD#z?B|+zYΟ̙x 9(ZN+ Sw> WȉR.Px&ޟۡt28kt ++e l@H\jez;ፘ=\CV,8xq}6㆛0B҇F|lc#̓US88yQuY'ZeR &iiiȈH~/y\Te/-vy"\P_T~4{WjUh-Ft sDž5JxlKI?@Qwp[xjtw3c7=B`A O-yIߨ D+!u2 v]{=lc`DҥzQ8F."98&ӉK TZ;8[cd4a%`݆Vy~ueV<5}T|=B`_?ǵ3ߊi&T%“'RB5Zqx^A .[| n_1G:.9)3  )a:Mā)I0M&hEm/2VScHdUEozebPw.ZyV/or? ):58ށAoێ5t5Xsָܸ{Ł^ƫ#4 oz{?ZZMږ/*&2D)§fVyt`D֖>v'ngz^]oF+O{[&S .HBk Q)ѰDZ3.іDQL4<'1}xy\ΘmFׯK/PiFDhjnqBZ6 tb#]qm_}BCV,0<>tt6L3Ν֏)H-~I0E5N9eoV!(ȶ5Ǯ>08cC^@sEGU5eRO L5QSt^H0%fd*)RYZ(-$vrF Ժ `b>3cf|V3t ֗ӐxށA c^e66cf[7断߻߲O .@EGu-4QfIhv$nbr) 'DgȔD1kmc`#U04S%+Όx帋#]7TPޖw 5,] #] _$[)nYH*yZ]9W$[L0s\:?_ #E_EӤq9cNKq 2x*Ba4-tuй ӓ冗=ta`'Οip(XaЂ'Q~ 1ȹ ?fEfF]@UJVb G6 +makƢFW-9 cLDL)D|:2NOrlIDSfcRא! zo Z \HEiɬ Ej >w̜s Ӑ9kpwh-5UMh(a<'Rm0_hHC" ÞuaCW7J8O@nfu" qOB1Sbq_Ʈ5ch$(*Ϝv.N92nDGoaL>WS<¤]GU sE+z-Ӣen3/dZz4Fb)w1iJ0&ZƱ~ξ*U<3< r,]Cףwpk% } }l@8u6^9!HQMd~S7˔7dEcIIΫyrSuUD+JY̓ȔJoX/zazU^o!@> `?%]û``N -,]4s(t'z1;S_8]E-;a*|.FkBjQd8ed+} ʻ|J'd+oُٞ9u&$.18chǶ֖}qq⸃ӧTzqzJ$*IEҒf3dMZhKT(-N98&X3%rF2WEW}Xwԏ tu~VȞrkͺ48y}sVoZZ]] i6–9'Ld ȗ}ԅZ~!3[8j@S)J]<6ORc}egu mm{v{ضА!?W[8Su¶F0#> :i*H2 ;sUKJ$T;^/P801쿃bӇ D1wNNCrHWujt=p }|C iz6u`Ǟ eO~MF 颪m&f @fIE}F2,eѫx_Zﵙ\ƪm`hǣT08cx(?bpꔃSlzšC.-C6ZDV$I0L04^爝&ȑHUcMQ(ZF[w40>EtSXhVy3҅Xn,whu-|7o<Әi&Y~(Xa0ͯ1(L$,>-z$&گzVh_:}h\+axs?ܛxl3daht=E=|XENwpze+)? HsǑ$,:@҂k͌70uOh)qllA[ƝWr"Vt=h6 7qz4 ,0ljGp% [.25*:;kAF*G'9>HJH hU؀e7X@rS9BGQ&} `6Ã^tMM >K8=`lTs}r?%"6ALHVR $-\J+%17/ ZϊDZN/s5Z /VrLcLvcWݥsuK6,,0Yۂ`츅?"LB/K#Z:e ~W,eRαG5P oچXM/C 05 K_V_ \ßY |lS\6p cli2ǢM";F[<-S""a"MQDEX2~эٿ|;/='J)OymYiђ*jwA~?0wh mɂxKwK/"?%RKc1W!qˀT,C~HmlVАupjK/0vE;K$Z(/y'ZG>.WB!TBm u0DseӢ"V׍-na%H i3%+s5/h|Ej)Hf}ަ oOK%TRq`EǀU∖>'=⚫1$c^@ :yK@z/@9m} ze ʮD?5%pjT-qC/05a$E-fybAҸ-2~ctɛ!G ,$c>kUK/[}V9'ӇyI9[eKtyxѭسC[`^~bKV0,08|fgDM86=V/{-N2ePn:P˛ T]?$S>-VHJ<}@S0!֬WOs[rI *%EQ*Zh3Ot-rI@[_Q;Hs̶>ȐZkǎ zCLM :P‰#.^up%5A]2*E3P\h?_EeOY\oGVQG{Ge%uNzmEP}2s@h%ɓXFN\(*YE{?\72Cy1B6IaXҿͨ yÈVBtB'DQu8W~Qs/وV(Yk;튤i+ -$Q$S IDAT(>G᱓מn~EpI 5\z{WkUcG#x5~I/>W+.^qubf WZ`n&#U܏@ ƔF/O EZ'GZT9I)N%50,,}L:LۮV-jT"Kז=whm $4Z>#*EX(M!|hD"9ܧF[=ҨʤDJtVZ,r/m;?G-PwXGtTK7Y{_HZ3750V`~ Ku~gXW}= IhiYkQ1-[(>zf*!iz ~| {xe o0UU<␃/0~ގ>hEĩJhGTLEBH+ɕN? ؝@kPLJNYE,Yg՛-(eEMOִ2LJt PΟ}809<`䛔>.ǥ )A}(d0Pj5R}k(t0U^!N)ip:|ۣo^2 ; ^\8yp Pq hnПFWèJ8p\U}gc)Dx3QQQGs"Zh%뷌nJccdUّ_5z 0zq7JZ~e(ezTkyR3OeT`U*`-z*Qd9˒-~C[8rtL i(>֍k['i+)AƓ?ˈN ?s6'%fỎj:*u?? $dv(r ђ}~CoJqLNjP8} }%U`f rM_LEƸleG~4NjǛðfND+:ԙ@LP)c| .+c]\>o'$SzGw(Z@PZ.$ZSSsyji;ȤbD?᛾&Eud`bލXՆcS7)sysJEtPm3(xX3E+ h(ZBG:H(-[ZP l\>+ ?O= 9x;{WB(_^gۀO5.`@MR =v f_D P? 5- H/%Zg:D*:LHZ^VQD ^ 3'G{Qcov}9\V?7QSzDF~^)2|‚HEh<秣Z> ^R? o^^wh8Zđ8}RtFV,PhzR78njTi3Vhi2q`՛ {;jyn rVBUd J>C_n~1_ l釬33'Vȓ .g/>S~Z?@`+pHH7^z?|OˇBCޏKl^νl٩+O.1vž/7aܸÚB2OGtL)oh7"ђ9r:Hbyh[HV\so1.';?~(w 8,Pl[MO[xdQpރе@X]5e @ ͈V"%5XL w  F\?yo*"뭴\2N| nIZJi+|bfșy`C;> r8y EzOm() 4@.7? F=UR*ᗎh*OߩD+%KGf.C^p{bl)JdW$Z |OtQv#;(3*]іkc\:}_9 4WadZ<?M `Q!2!hQ*3eHUh4_.Z=үCo`U/Li8~x@$`> o{r׀.Qn~oyjkC+|HV._oQ\ȿ>  Wa gOg'ҷyC>/s|or2E?/OGhMB]`3U33T4 |~6byן8}dg[vzصỌ{SW/0zLǟEGɘwq-\Ѫ6.߼ss#m1ui-Tn#ZX+߻ Ncv&_ 4}ؾg]KrNNz'$@H-/]EVPTUD@騐EP";I@_7ruۿf:|I|*41Şbo`+zs`JL,5aK[a0@u+H'7F cV=w7>l@ TpO[4YѨtݰ Q \7 Aq ѷZ`];4@: $PI=€pSppƱ]{ǁnжWp[\!lzXKK|&K=wxWuGэfŊC"@+ -y86M>ҌÈq邠a; ^[UK\4=[1={x.eH9 / ҽcxc*7/S*3o5/d.l?,EUJ~Zi ;XgxۗVt\+~__1Xg^(hqiUT٘a]jܻ=ת% R\G<: hLD7&j hCu@G=Uyr;ӎ3/R^HUMG ߯[EK`e>e4Їe &ֽû`jɏwOu@?/bٿ-5PBbK~3=>cT ^&Sє×.`P-*@'\r;\!, =?|/e篁{swBuLKAԍ.p+K7cAd:ܒv8i8|t*lϡ\ ^b߷<O y p3ҽ&<xvXQa":-('{[_XqJa꥕K>Zޫѹ{#qBuߋp_5DWSѸ}pvٗh.< (Y]_Ƣ7q"*~%5Jt`_֭њeo;_ Mݕ#_=Q -3qAXt5ue&J=ka0m;0ϢM'wC.ǀNCO,Љ~a%`V NCizٷ[YhkyO$u7fςu]=o}YX.\sQv O<CWi/e\;Pb|6,x,ln,;b|UaDuXP}&A|?@"Fc8?nJ#ӌZS,~ݨly.1~-zoi|o@++P}Z-W9un_ԃ]6{G)JQ$z>.)UDŒׂK0{jV9q յܩ{f7a V^\'}^M#K]@&^FxQHw.? ˖@M KC.l-p'!щ,Zm8~ R'=q.©R$WZT( hNݮU/ϸjiU$xtA_G6|H7㧦CAYFMH3jB7Zߎ'KX8Ak2Qw䳾6#>WQIvo'LuZ*-[1nm_x\o2`Ƚ+mHSZw}vt5nQ>xRd_IIiҴn쓶ϣBo 踗QF+"е&t@_"aZFep:7Ów{`1FN7mhg2 +GAȈ qҔl+NoH1#[:ס;H~\f9G'HU*(}ѵ;!A)IH;ha_WQJ׵"uc&wހygO_Fι~{9|8<gyȠ>psE}8b;nLrɦm?6YG}/2t>]sT@0,b(y=}&RXSuGjn=#iP(>WɅz1UP^cʡ݌jlMeufwrNoecUT +%Y8i>\q"`|ߎ6fm&0%l0{#3`+jY@>)^fNeˆCRXEoE0`O&&gZQT~`n/*SAMY/J@ďESB"j E*K5;PmGW4H]7x:rOӹ5G )UZR6·1Ja e"5(;L-T:}qc[j_+kaG~m=A_Ҍ&#&\{I: R͐5,[=!EUJ2ԝ8vXa'ʀs'g/#hoc rA\ڪEJ{jag]/px$tfL^d%-8ȑ#C-Q>[−ca-` B5BN{B cT:v:l tHh)m}ۨ]cy}`.9 ,Y@+\+ :otT4̎}6^غ1֍1{č'faʡa4&9v77v\_Ks)Z"-e|LٌNle IDATCYh=ň x~MT3phU`"*+ޤЊ\/$OtG: r'(ॵU{"iqXf]Fݝ[WP) %/Ôa9@w_ u!`y+"7 vPvv8Y@B߅isRAz@{&Hՙg?'`A +;(9-M鹥ĎEW!OoG/y9 4\@>>^^~ ށ+HO@r1jwANBކ>}w*yow1t$"P5[@͆ P0ЏBPGm(8mU=vN -n.L*0QVgܯC9 0eb.\+`V.N%\dŢ$W>J=hjT0E\&ckSy{ZQ=w<nKx1SJKS7-MTդ|EQRYT}b[ QGCa܉b4`v"ִms\`P?"dHަ\08(Bp 0,YEDb1.$COƑ7b0pz8/~FJK )$l %eN.?zaB mh!޿'ى GWyZ|H8 p(`d!эĻ㑫oUg")D!BN!{^$vG|^\g ] %<Ml_$@G?q՗XqDCZS}y}+ W}KPPL{LH$_8ryZ#sJxfSgv˛}w\}NξQ{ <=?W7qCbZ1U ¼p Be[m)4O/p~MC]+E(d29 2@C#}BvTm=Oj-Ahˋ&S_lfgY }ɖ,EƎGh s?<H}ɑ@- USвFxZp-̾Dr+ec`0h%~ s`wh9-b.!{|>GDHIpAy9\IՉ~Sȝw,8q$@:: uWa*z8vCmG/;wU(o@J> td#3 "gkzEb8}瞍V]qKk{CگoT92xhݍ$Kʆadc5T̀e;~p2.^,c+W+/ xp|6?,x05;lXgJy Y5ohewC YFOa 6>uQ3Nd eJO>W/+iǰz/L^@9E3=$SۻT*ΖMw{I`e>+Hb>X~F&0Г,tR(,bߞĽ4WlJ֗#Eۭ∿feGN3N7cwJˑE"Cƺn ^ᄩHM aX <Zti7 Dr$n.ԟ#')-bˊ`ȁ߁9&F0dAU8Cۂ|aI.{N eIp=pEB/C:5hǾiȂw0xҶ |7sཅF?Cw.[``ƺW(,boDZ]ϠoYCKACq"O@{kGx)]]syR]!R*sn2aZ7GYm϶2.F4ffn+`h=w }0?3R?` :$W!NT[)wRPNIiɞ0%P5XP -]T%2k]b%еfkCrZxqwoCuruGBm%m+2ya[ȑDvW뭴_Fbv0E sqM|hp+p (O!ME3>4 !ވpLV5p_"ǜ T6 -ȋsaPIBaHTO" y{@p*+`XؖVZm@O#=Ci P[eK^OCe,U3%Y 9 0aZ7sn_nijۙ<>J-AߴPO!j +|6>?Nlj'd9STT&ҴΣ(>RXEw}e V/;# %  x#ŏ.^|vqB݉l}d/@8:>,+GL;-rHU n8 d|_xk=2c0 )uprI72' e߇9BJ< r 0$!>9Seвtmʄ-O)5MMBYRq.'<`d2Հ,9as'@,\}rHpġKyw#gn. Bn =+'aLoDu؃ڟ!GV<u ?7P kj`@O=7+ِ 5yS~[ O f i> 4X' }N6񒓡k=M)Im (WCNjZ~7<Db1dαa+FS[da0|9uJnDvj@O56m C&y7$^us k/٬0#RE{++>\ww*~_l(C~]VhW~5^DHV%xo%i$? HE@u ߐ?0{hG| %y$h yt|;t~W5Ag'@W ߋ#tg|. kLv/Td:<[?RрJXKxtts RdH~2wJ`}md2R2tMM< w$qز}OcpٽaH"09@? /Y@VYy>p#ΊXt/0.HO1 )h+\#pp"Gx>x:,e\x<{nl4?,N~B@+ vxqrOŨ=Lԙ]T8a/>^ʊI-LX3'$:_w2<ˆUE濫"AmRvmW6рʏ|CD!|WmD]Vx[}fuHbPibqX(ԍ TO2, rtO]-yr!H<G=v6!w-A됣zQs38'$UFykU,W]޷UPwh,-<#$N/!d2<@}2Jdz_F@.ݨ E q)rڇ 7rӷc  GW 8V};9) >r5HHk~Ġ۷l})p|YEԾgp{Q#y}B/Vh^YyEeˆ8K^KăjW.iCOPY&G!>i_1\Sa@n1\g }1y3$w]۷wI*~'}W0j\Kׇs᝴vDIBc2VD¼BpwPIt] W]hW0݄v{إy9|H Wx ph<#6Ì@'z3x+\3v77oCئ.2ws4F JCJzpbR{TIWe`-J7 Rzs$Ȓ$L=Jt]_ ?ܻ/]եk^mܟUaځ_ lK cHY aje1jy@6tݍH0az05Z٪CR*}YD,U;.BĠo"*n0kf`\Duy/ C>X1Zj?+_\u1uVc&}Z8C]jeoX0>ev>`WJy0U[Q`eTi2Z`\|&!h;u+>ٍ[1 ;aW6@:R33̘ 4Rh߂hAGVLe; ÀHy ]18f 2ilݍ['Dk#kJ%aG3$NH4@tÆa*2X= a7&Oo)>.K W}RS OnQP2u8ҫ5m]S1 'յ9qp3Bg!Rxd҇Ìݟ,l ˑ#! v>v6)+#¢! cY,lֵW߯JKظ;/lXqLKgwskx220IUWJYy*E(SƸ^ ߼Ƨpsߏ0Z`o찼0{#5 =RZR(P& V=g`[WBW3ڄ H7z}1v]]p3r'T:~[+i89bdqv+O@J]6pXKC ~0X=@7JVV;P G, r wNu>c ~6~2*)sG`O\5a)/!@&ZBt7r|cԞv=* l[>3^gcao`جwB 0{N߸ang.c0Bljq}4NSF]}d@kF(dOFk,tO"VX0/^(h\5!Au2qz7'vH}:pޱj_ԃّ鋲K`e&Lmuʃwg-5G'<aݻlDwVVm'Wѻ25q2øBBPdk-_gt3΢/=_bYm7p@*]5{WGndS'z)GO'K%[l5J& J% }!9 J.aIZNwG%9f6#_` .: i$=5n- ph6Q/< 3)Q%A)2Ch@5h* _yl:,Oeh-^Շ`T5hw hy!4 h^ 4GZv}*r7fycOMUMD"FT:;Ҵ4ugw'-Mёy0Jܻ;MQ=",~'Ctw;oKDl}^KlU[H;<Np[mH;Vl-&@%XZ|2,qI†CtүlZ<Gȸ!0p{߁ 6JDƭp\or8N4CcRp 9V(&eSu|@͚!8(9az%fdJ%:xx=r-#N 60L9> }r)V 2p(  ^C!  ᱋2B}<~6H&ЉTN S ~N l]gA CeC/,olDG޴Ыk/.#ψ!#KdYp3k?d/~X r ԝ*뷶͖}꽽qa~ݷu񋉎 ?jB e6Z~dŏEzP{F.feZL1sΤ0S= -ZMZhm!ݓTID"FUM *<7! IDATQzЯ^%Ҵ{QV`ӆ}WQ)2pH5 R fZ{q ! v *^8qߟceоo_{yk7!C  0vm@FˈĐdA9~"!c!}Ja\9ܽ ǁ1Bz~9>Nu5e.Bo67eQqt }ilFk҃lUitY]ۼ]_Ϻ6b\Z!6#''Bu+8侹5'ߊ$P] R(It(;oh[?%w<1MӃ[pֽwxu?l:;a \G=|ȉh 6LV(<2/l eG8]pO s.a5XqW"eFiK&+H2jR*W}iȞk&.O)(RdI. Vkg0ܭvBd޽TvECC8^e.dH~ٲu=y;2df,xdx#;%H}=46"?1r&R] 7=GM1L[wGgP*d1*CA 88BmL'6#Af@HY d\lr8B4A6wzs!D0oW"wEǺ{ȇ@FMD%5dcJ*) } <6/}l͆t ~zQƵP?bB}0ߚV;jPߎ <@~EDíqoʅI#f4~gHgG]lʚ{Xz;wCA[O)(RXE/X? /X?f/X<'3scMھzϮ8.`ቖkFZ# |P2X*2Ԩ&N;FAI &q H2 p4LJw߄SgPbhy@`Xơ!䈑sAV HE7B< ID0kE#$`[ jZRW$\ d ]&EX2dtwÍQ#.m#๹jĒHt: /xVнHhP_@k,Xpv{QeYx*' |)x| ŷ'RZQiUirJ"0ez:3l\/+(RXE/*GXzl6R'MkB&D0h{`G8%Wݯ mz\,|ocZ1x ¬Yx =CMWŒ!zp0S$ i?2_ 9\*1r8>S廡$rVx9H*RW|q&>E,Z!<ѷ2AJȉs`Dd]O<n f}(-rdHd>L8O4"d(*dmHsx^H]D, v CPDe nKcҮϾVt,f 9NzFs<}ƔÎ_)) %H(JQ I&#w()zz @0Wf&vq) UwVq1//}sdz0I߳ &g'`]2 tjkQ짗Cʻa q}y<2j:]hl .5plf.|P9~TWw$.ptxc-r Y(iD]G+] Nc0^ise|6hSeprh҄DQ#382s0;սl@Kc|8P  .ScdWF䢹Öum6̔BQ0(xsQc_:j~gݼ u3^3`˃d|X^'2z,j'L `I`et&G H»MUh ]kv1rDFe<0A^nL#"\ k!+/FLhSfy}ȱg3tl?)|BS{W΃+>/LF*F 9H K }r(9X-*($%Q#(5EVLX ``5Y0/+nf&8p0cZLv>e#X}pQ^|0 1pmKLQc~ QRTu(#4$y99ӑ%GЏ\y}?sǂc{i7mNpXL6hv]x&ob<"c/|R {?j环A|P^wFo6x _-{:'(RXEٯEƌZckqU;в&Yu,NwbuAU@] V}K¦A_DE‹ ԍ%ä3_*MF.y,9Y,Oѣ>S4m0e%_3&1")b&_5 kL=Y;Ks?5kP|>0s)yFEb $a2L&?9}^/.`*o'p<6gajέKN0 0˹lx@of(`-GoD< \ޗ66C&kPbr?@[A0k%4&Sd>HRXE/SR 2frl*B3> \6̑po,ECn_0 1 B'BP+Тju|VKC݇8:X\=RN'E)\5j wإ ZϵR hjQ3>Waɪ{Fraͯ)P{&$M Ԏ^4v0^Ӡ/,M84ָmlu^[Jʶ7!>(sx ":/Oo Yxll|~~^fC"Ѣ2r9R{ȵ/΋r!^ڋEC\) ; X\;[([_Ϲ̄AԑЁ8]3 ;#[4i\Z_Cx2JF~zsws5Y[k#ºWUeH>)%k"voLvs,_93`plpzmdV+72E/s"/dzVf=shж${kB0Z_  ֤]x(|?Ok7fOA~SPr '$8 GpۑnBN>> P`ihb˸ 6z@wr;-gE y &7oF8:b}П}^xRS"gv0]9 O^>s9{{&@"-bɤ%HA l{ {=[tb|<Fy#f5cs^|[:- w1k%o|\YOPӕ[V_YCkۮ 8Y+UeH>)Cٹ *>Wu0rN|ܜsJ=/ –=r1HG!( q f#0X ~ h=}'rlrrjBhMjN")u= ۶`jњtuvq堣Fо^O:"ލ~){/̓0Z:=21,3뙏?8u؍QVP߇[.;п$^ie6 { YWfV3Z5) l]}1`%HY-bv+ zoB ͩiwZMx>zU Xy'`bVuc(˗KZ|{fxeSo(ۛ^H VUI) SkVfL+gf+%qw, dfLKEpg-z* ⯛e: i\CbxA:!%1Y@wJQՅ0ܘ R~\e 4\K^S!^o$*ϙ[L{ {KBjI*J)R 4҄ kd9+V0/V'v/~ 3K3tS;em sID\0SKH1Z`LF[T!5kr ӗUL슢@UR8ȱ'<GZJj|J0Ƨ rހS*ڵ݋{(,R7DUtw?9]0؎ad12uh!ٚ8b. avŝȌEэ>?si^$d֋`45 gzp׵ha-;lb`0o#W=秦,k^Q<-HSF4g"O )tw%#Y1q1ܰ 5iBiA?Ztae b9'8]ghU+ǥ+/Pi Tʷ0e濱$:OR5Veήf0+ˬz0̅ \{8&3fV*evȥD&BywuCqBD̂sNp8%8K8vwӡF>o% < ~2r` g\%nlt'ZhmCaɱ&1A?;t=hG= : ChMKY MAs 4`!x1|mgA iJȚ6=j`_gD] /0`̙'0zuM WZ :V`:͉]T|U9MǾRyV~j?P p(/uZ>CO f9lp2K>)ɽhzi jxKNOcJ_%XZ3J[Y pEJ9qOyl ióU,i/R"ᙫѹoA$>BZ_E,۱ MF{:F02) "K`SE E$ɡ5 7  O5 M &vs {dW2,I;`ʉVS?7#Z[O9)yyY8~6l\^a ޒ$#)3U8fz)]ȷ f,4eA9œc?s~b̉^|},I+0z*Hb;ᨀiE9a#wҧDˌŽ2oO$˄Ok: B _-?{JehzFKQ?ƞ$!1SVpԛ:0R(%!>/glyR\mPQ~c &+bK7Ӑ|ά,Gz2Iqxߡ:"`ZKCOdjtѡX41`,#ބ|h!q|ņ=aԇ SNC u\=4='gWhľNM0 Mw"<?Ey;|soU2f1o-c[)pѰhk@v$ [8(r`P73csZ1pXSa*2>{r#;E$x?B&hl;45'{:A=d" !,vJ݇ܣegx¤\2*˥Ѹ>ٲgq{KAF_Rq` & FW֢`Dfw V S E3 k!@2x>X+uz0r\ar۹w_Cs |2ӆ^P䲟pR[U`:,E`r䡇}FH`M?FGì * ~-C.#>KX M&'ۙrEzd[a蚛/9㫆y*Y)PGN1xyt4DeXp'04Tval Y jU,3<1d~@X9ez1\⍞{1峻j4[̓ kIJT*P /%s9WHl=qG"%آ`bpJRyD2e; CH bdVc38w!'Ȫ3),bcde)rDF= pSUk#'#{^Z4BC'28d#݊  C ҂HUE1iKI:a!}rºA~^‹AˉHI\H/$udk6쟏$ F=145.I5pluLBtO|}Gh=;!ޖ>uk>5#㫡a%s8?>Fezj4*!PElzՋ~:fݕk*@y<%)q~#ޒzzزi_ݱʭ/ɛ]Te" N"ji}Gx;>ᕞɼTwf5 ѭ /k{^#ь H $i>]#pmے`B*wm ;EfM' KR%PD(!ZeÁWwꕔ !W}d<hzd4#y@5JIMr$R{.Ht~D#}_d6Xwgx"2R)k wZv%W?IVϯךO-nH>ZS _|/+B'Ȭc\QDq'-Ô5sSEs3=il2G ~d`;@u+QYq҈=Kx(QY`xIǃL _P*>H*Sϼ3d,:I4NkmDL)n@ip{*l<)WB4{怖Io]=Xt<47{Xo#sg!GjJ8}@h"ɲ`hqJWRoCUne&+!~txXु 7fǤHnx:Ys`xL^hR@l"hjf+HTIԀ-γIj_aot } YyE ܆Exx>)WN`.2eu2y0ΉQ\ &(MRc &1s7Yp4b˒hɋCh_קw;|򗩭BDo7LjkXi[7^*ت6dz7 $ȂȬ8V!AY*:'ܳBA:1VNs#SF,q~u/#/c{ A*s ʑ΀Ƀ_7_,hIHaB.uDgђZ qSlLՄMHΏ ;Wz0gdÇdٟkE&,| #]l2f9F_’e7>e&,cS$y!7]hT޾<ȒH[=؋csOPu$nR9H3IqLW،ˊ[TEbv-S$Lzd V˃-bh_AoTW>XUgw$~dmfVJ?R9{h–,٬}a(=q_]N$A%U_uHò>$ YS&B;E6lKn'{~ X" ӑggH jD rozt1Iy2˱Y..#S'fORpct>foK؇`oReJWO#59^\Q$7 &xcV=m[:H&2VٙgYeSH5$ZŊLߌz?2wY)an1}:28*n|Zr mm)Ǚ6\PF\oYL놣f" mQ"y z> >ܪÑa/W!G-650 ;v!w]|*s`KȊaʑ HjڎxdY* a=tw<׆l.Ҳ<O8<~)2 3%MͰw0 ȰQT%r pYP?{_O#:u&Q}_)4"E:W%ĊvCXܞ·ߜful Ge0{f2$sѹ)s+ yyUvjQŴ<DUAl,;h@Byf؋H Y/ӑEE+_ N99%Ub}~r<oBN9iK NInu24=ȜAqdFdHɽAN8r_R \c6zu+o6 K@j{bY h;:^fLv&M}!k/A:@uFN4+qZ+M(0򷟁\5D$ 7% ;vO  }b3bjaosβ*k"7|'&εw1ITɌ8T\Y`EleP^|`!Yv ?Ѹ[Yf כHwc`:`\mXTMUg|w0 w&ɫ*AjJcEe 1ȊEάe_Cҝ$i`VX9P +,a'"s|% %w#:8 @s88[11cd7r݇|a `LB9d_X8,( $/;{K΀XW V 2_l rP.#AtQ5Ž*"PځNY5k%╦ twhZI_\wrq(eq~t3GzeACʩuȂNtVcKaw jsa !9K}[ sE0<_~0e2}ٱξ)Wagyo{е"/} Y(6%Lq%~cl#l|*i_ "i0Ѩ{jӫiKY ۶נcNbnp{"9i;#pwLp5t asQ55 S# e)#_RǙݵ[ 6JƜ-_ ݜwf|} C=G\qltxw TOJ[GM523Zf*D2ِe+[egKp|"(`maf Ē@|܃$A^ SȼH_'[XV!7Ìd)gUB.y} û9H{FVv׊LmB2\$2TW߇Cz:#p# sæ" cW#L5"`㯑LZڞq0,6f4-۶=+sa\_2&Z PH6bmW单*>+-m4Բq}]v9ڭdU":V{J2<`|HyT3_Bڎ / + DvoF4a\dԽȴ0y1䪫"]mYpuHC r`$=jU=2kGB)@⢶ՆBiCZrA\O +ǠtZ$U}ѫ8z.vʬZe_7V*44hctkWDsY1BAhm1 +R z!)cXQjdƉHm]vW#LI|9xb$,_,A[TD~8قLkFFf'n{u ~݆< \ yd(<<40)AH kNy-P(UCkw̃9pppHKl 7݌,; 6Y{(2eoA&/4S߉t,aȌg\:F˵㖛wBCg=Њt/44߮Տ#w?15yVOC8:X5qY xJm&x.d`?VR@ǐΌT!y!Bp _;xddNb`x@-0봞Z`5WIW9)lE٬|%'FCs {[ Mmc׎kVmW单VU8DhuC;''v":/@:;HHa[܎`bV:u⡄709h:\u'Z!5eq6dA;H ;ZF~Կ#AzsȑHgijE [ʤr)\6ՁJ̯9{7 _=]݅|\Cx s6rcU_rȱtm1d&fgэ?Hq+ 5Y AAK`轖2FNl!M롷+\ryfE"/;;](vJ{=|ޟ83׶}.߀tY&UuߚF`ĵ#h1Ow4E"ZO38'P.cαn1h>WqYDh۩[ä qb5<(UU}V{ '=8DWQ,L> k&bwOXة"H6 #|ma/=PSC"eZPKps:xT}Z :`{2Z&ZWp\#Io5 sށ`䔴3E:MN!-֢/蝛yup(z~/r| /o@FOAFmB~Ys[O>X 蚌>=ص)Nτr ݺ\; -вFA " 41[ķ[[/ ܞ~9A=j0s|:u~㨍D׳}ǡW?y2w_3#-%uxa_._"{{ Ăȱݍ05\u ܚ?@ 3i3y"gԃd} a+p֧aBضP. mEV4AHz]Vp߫-9:r|1=Cp2kvl}q#?WE7'K0#OU-@9 IDATz[̊9h]hU-P- - m(gD"cHɂ=\x92t)3!2Tyӡfl%ꆦd3}~@xfISs ۫{RXUgř 5h@#VZYJ)~C{^bͺAjȀ73OIHaľrJХ߁= j)z|vt1aj'4Ase6Q.j$'͝wbA; q 8cX"E@AI;r'Slqe.(8ER Tꠄ&÷_A> Ƿ&O"E0Њ^~Ɇ3W†ȇχiG_} 9SoUOO3[r!Z&T ZcͲG;f-CC>~lߌ^m:,Rߟ "tn̷`>cy, c{ˢK:&fσJ s`˲Fj},j\>1aXou%賔6ǭubk_CHr,_$TPh&ڣ VlX#àeX*:؂9lCZs}/L-1uH"Qʤ+jK ;akQ^ʔo[%¦{BYlH 0"P29dqtao6!KLsMGy rkD.8 :}t9|[Gw_ k_B4]3 Ó!]m~{w!bLXac:t~W fD8-N5f<i ȦͰ{wP;L8p9QpuT`s5]ݣV )]>DBL$3$u&0[ɲZQ]b!z7SGx3j"ܿ J3XI`zDVwͻ YNՅdȱ=/bs!nSIKfgΧ\1ME %$-[wӡwvܴm1!2mаPmk 50?>R}A4e|%%W/4 @|kgFRrSf 7@iMJ2.^+HΨG?޿D:jN[ G v·'  7+_D?|+y0`dd!Zk(v0voufskr9;+rx'hI ʻ Hټ [ :y?gf<1hDTmluP!D %)\LBF(B1r}+Se@b:9?a_02:^3̔L_QKqy<[QwQ+@Z.=hh>sx3K`Ueo",ƼAzt5Bp؜tS(9/ox/^Z"AՓz{oLe31L̪36nEk5H9v`'qc B"'/Nr(,jZޣW;P#zTn(P7#BSd lz t)ɸR|EISv z`Ikapa0Jg!-W. n9c02{ 7a| 9P- c^;$4@d(z6lb֫+oE:{|P L 'we`"nc0 ][ C< dd;fs5M<)mEf~=ZaĬ&DfԸ!@XW,9zg hOC;b2=hU_Λ)Uk*>+ʇenƭv?:!h@+~y{^ +$I2ij>N& ִKy6t AytGSGNJ0g^^,NiA^gqrBC JcBB%_LSW@}sQp0Xq{0Jt[SB{m NA:a/SjQh.96!;v@C#1 ߿>x*6M"ݴMGG>}~1nߊls>mLXBm 8bQ%,I@w@96 IxKrKC=45CCpιeT @ ޅQo\?!Gz^Q7N;ѕ 3exbeH C<ӕf#!jp8+_Pc4 unRWޏͷcL맦7S>XTVU8D*Ch螠)f&_{^?(K; lGQ4ELerr#HB2Qb<Ɣ Rۆ,a6c;bMz[oGN:Ƅ 弶сRPhN'C, &C  BP,8]ٲNYyl['ZE$ G'lW/SOBUn5д,kRg(eIYyo8ȒI/3MІrޡpŝaH:E_![GY#0}:ezng -UO.U ~<|3s> q1$z41_.N9z{}(aRu/E8HdFh.{v9+wg-sq9[ΓBJL<ɖB5SvMAؕzԖ._ey3`ډ,tOQyU~iLUk*>-cx6Wjt,#Q&(RHF4IIӄ\,9$G9P*xHBj&oF<6B$J-) M 2-8#Ag-4Sb0h3Vߥ /.V:/ xRʚaBYb@ZYIykr B:sx`/ji9yl(z"`Ahs䬥0yۍUG3qF7m?f@,WRHA[ࠥ4,䴯AI'&Eu;`ˆL:䉂@&&aLp=>!rmR <\47T=s)7 qwO08Hl &*?J`UeR)%O(@hs^U0Ɲ1JEgYYHfWO+nAj4-Q.'H\\NA^\{ZJ)IUi}Nvwzxv:,\\B9tR=\=iNy]s$Bm_بPS4J^uưiBH);wJS^nZM4bOJ)ɢ@"yz\`SP S`n=8k!x }!o\tG EnBn8y[[AS`hU%2q٪%5@{,]fIbeBԲ[ gwu6|VSڽ h>PQWF[,h7GK_o} v ,X<׍Q 2lmnyNb/ck[pe.t Û)BNT?jRvP*Bl`g|v<f^h"n%^9!*I2eٹS}]ӏJ=!܅5eֆ[Xz42ԏ(SK).)wPBIȱ7e΀*ͦ"˗1!Tٛ@ÚUk][YRBk!(h"F:pV8mEjr?<*X*TBu-|Lu4ygW\lx >1܎Ϟ<L6m<6۶nt(sv@{74{[`VG@˛V)# Cy6 pASp[a!!j1:ęW!] ,bxR =2`m]_m:o>',xR`gԞ7߫ґ@o ծ7&Uy OwtK5qUv67o[+fc>mt=̴YӔRiRibMq|v u:H x7f IA:'w e @w--}$$N Kn<%jB2)!(* u e55HʚPEa bD> PL|n?TMM(^ȸq#C#[S/yÞ@ă?gA] "j>P:3a`-S$%q@rjEm tvC2ah41s畽}6cI}x/J EEJ궆ǰ)?A^[Adbs Wٖ*:y{{WwX'✘Kz@#It6`J8C'`^HlLm}{i͖/UU}Zυ@K U <8TLf_ U\.ZpN] CoGjaV) 7vu*\>dHIIfAF+zyc&JpPZ;qM(P`(41|!!Ufs.BRsI†kab(ޠHc$Z76fyAD`eZ2k^\2'E\u"nɠy .AzEC G@ + ~jOE( d^8PU;gHm =bGT, g0\tgG.Qp Oh<|E8Bب@NIExs_̵3lE%H0,y+:JX*oeW+9j:lzB= N'2]8* $8įeG~c_0$K*qsNm+Sfaf?L}Y`RXU٧ř$L#U2qh] \"f%~ʽ] z:ֲnswWdu;߽ivUw03!삢 =hWzу6bXi}I!B)քVK". AccL̼7g Tuj潟7|Wyd,?DV/n"*3߅c.@o28oec{JAQkm1'P}cB9&a϶&?iVޒr0oŴ ʛ%WVjTf6pSfo./zxנg_Z)P _8w-7 wig]ֺU<\3(<>q[~W_-+䁯;`iR\w k M!>p|Mħ ՘K?/c? mfn ZRq_7mveC$nd/%T:VP!Go`5muݢ /KF0xgHeN|@຅,e҇;+?Mr=[?f47 m8FB*[ڶ[_m-(>楖@wST)H`2Fyw oSw6Hߠ-}e@y=>D>(-DI 6w5axqY-M?m} "yQ[/Bh{vUyМSm0 BL%۲sRoCǰqX>w+2)EQ?5~RY3{Oo `TC޸Co>ѲJ`෿e7KK+&vAſ^У,J%BSV~-pf ÿpM652'[`}qQ)ruXHc>hK?G;譄\Y1/1ˏedi`xøD.~.y/t[4+5% _L\ ^|Bz'  C񭃘 CQܷWyuߺ^!|o{JaW":Ujn hc;u>s'Lh$&ؠXU̯# ҃7w&d NjɽUQ eބ|Xu `]> 7Pؤ!F˃Zf}W1Y`!;ZGDJqX *Lס1ZiBRw\ *aI^nH@|[X`]6:jq3.>}[Cީ`IaI-lO {WCB}vP##&<`idf >͉(^,4MS[**)tGL*7 m|u}|b.}`HܢWZ m kVAa¤\/O\I7ΠU|8>`|:/# ҨZ9 "㯢ϝc$+g"{#G-ᶏ<$쪂ῂj=Hohlx,ғT&$h\5#\97'%a$;h+1>LLҿ Gk(pۦ. HPPŲxm Lջ 7ZЏW4^,= ̡ ;.5mM44<W|< _zrʍ0I 䢎K{,dS:M!\ +L^-ukGai?{«ᅪt4\xyiO¹ނh53#gn'6S5sYI\pj˧h4@1U 䞻qĮ o~ ymt} y6Xlqݧ\RMr_M}_B/BX'd3u\U[V:qQ|u),@{, +GfϏS+S "TyGE?ncg_[anx[$w/qf~$㰒vڐ(3gV>I`5mU rr=H+ ˧8wq?þKHziam3U+gc)da3S߅F4 O?W.r}rۨߍ^/\+#dn)B֯_Dii:6[شI=} z  ;_C="( x}G^!tI'ؤ\'t`ŃzU<&yPdzw _"< -0X!'~sj}۞“6q]ٹ-YQMK)ăK{zO;+{_+3zIޟy\{F>h7, jsێMead7Q˰c7[tnzH>I)G[6Qc1͎mu(jkHNށ+}a7md$dv3߁c2@ oF]z} 993Sg+WB.mç+[&Z[I%ΓmH45T6텱)"~twfc` Z `瞇_DVWѶ@tTX_G^j.!K v)L4I"[P8ri@{!t(R Fϡp)$&+!>ٿy‰e>AΗ{-w,K<3󄥪W, BJ,@ Ϣ+X:%$U8t~6>hV k<;xOf(L)i9d]X;K۾WJyeycj)8sAU~dc}YL;Cr`ytS0\g^+m\,/ݤ:[+\0FV1K@`a=XZF=q+}{?x9x1~iY;< yH?G.hd8:zz+H9#pahkZx2N,,qcwM+]}'OxG OQiW`2hp'8>w[e*_fo)Oc]6^)RFL۹u`)symsێ",MX L8o²XY_*clX2&ss7D5/SDbÉu3O"Kw2} \!=tr -I<#)Zmkt2zn"W7c3?TXb BЌ)"j~b uG?Zsf=: _?O=O7!E/|% ie0reկۑ_UVOda_L7Ġj )%jYT4E'cIlU]EjHxu` mŘS%͏܇ދKOZHr@spX*>'IV:|5mMݢ@Qe|ljeCz_S&ztvs6B8Ř(F 'kȖroh Hkh _I# Emۛp}zn_CTrŲES6 xזc8w \OUVl[|b͊cdЯUtuI!MCToD[T;3r\p0UyRb =J >*zծ*@_k< 1}D@K]{Y9:|9I,qiv-.X׷knƄF th(2S:@ ߲}]iEɯ”ƞsXU0!m[(4`.ނ+!n, ˧Е0>tV ѽ5:ބU'ai7;B+h@]3&_x!ik.} nrr*?!?8{fGs` pz-d֑ßD!bv6MC0qZ +D +RUZ!tEގ0\I}~h sֈD Ƨ AbaO *[%ߏaoW5z!u]Xmrd~+QQ05Z)x$\#6/Z$.PQv^ߐ[6}Ǿ_GzǠX }JMLϊJԞtLù$]UQh':WWAhMS螵-Dnp["̪jAo0`'V=86uh*$R¨h r'0u)0/rڎ*08 xT,K5NZ>u܍yLOn`2Ch*Zt`׺3ro%m}E` 9x?t^( DBM%LW,HCxZiUi[{|H1/ [ϣm,ߙ#DtU(WYN aLko=cQL= 8<<]=mn,EnSSMЪR wڌ_M W7kBv")j}1}Mz<\N\Ϣk[Z"qc[ׄ/SDwM3&t `ၨ22l$ѫdXB*zpJYf:Oa?%ƀ%}jI_R %gnr£+kiYY1ZY,de㖮Boj[vgى6Wn v5,.̶ꎢ'|Z> ^Uw$k ˻R4}ks{7_ZKIDi46 -ƉZ' iƘ((닶]jiۚ)(}ebLD|ڍc~S\ a,9TWa |,=0 JR3 כ:9?3?kKI^o RĒZo&7)6c+k?lvԑÙ U;مf;ٸK<`' (ާ)@uU*TS_cPX X}r%Z8- +_NҾ|h}K厢^K=n"8R"qh{4𞰥~P.N p_]61XfSkċ$9̆,{aZssȊq[KﴴWM[9j1T6R,U:vh0AuPbdݎ'B;!,&$JJސX(zeێS>7Ul uFSBFhk;i@;J!B:MmjCgm-<K|]e3Aik0Z^Pj/VRts$BKu?N e42-ז}yWKWV؉V:|o=I`ns)r0-X #l(ϾwM90vurhC۶T՘d+2]aR.F5VO u=FT6&ew&1 ד=zn,OVhK8AWԖiS$ui !%>~Ar^ aV-6mE*c z5)7C([xLuF5*(SRV0=VqZi{CYҹƕcʊߛL[qx_͓06x]{t~w0Ƃ& Q['r;3jy)Ǵ-u5f2dhteM&qB:֨H@p]8 ,2ICNdDXafP=BcE>],Q@M~LmBdO"#ZmsOU Mӄ H!??=ϠýOʈ)_!)+'޷Ijso^Յ3_$uzԎ/ɣ)ǽ;H KOg=a`]6xn6ﺰ|'J6,tG#֖.cMH Y&IJg`4?P5BJhc2i0bShAZm*)0K5v3h%H!Y@CB#jr?U5ߤ &WS"n&w Kax>dVzA7{hƔG5c?݁r$:[ެO:j{1_4m0ϸ%s۶pns1,u";1w!1}5܇ˋvh1I\''ݩYD\ u6*CաtnۆV=m[SWɄI5a2SUq 5<%gkMc|=ecv cIuvgJlVRU#LW0]Ouv]xn_=>N[}DԪ鳒+;鹙5m2ew{ ϩE ~>c2g'<Ʊ9`mEx- `:h E h^Y8vmY^t eft,NxɄtL'd]*u[LlR=&#Μf`')xrf8N:iCk^٪m64z])e!i/?aI}EiQm\2(~+XI|HǠ eY a=~LY(#yF3~:-7whg+X .¹a[tmL^>q_M\@rn|!@%q?*K\Z9PH}ڡ; '5O%][Wө˶S'iж}"?[kC _~nsş'g%K,6Ms^l Y<jБ+zNB<ܵG-ڶi+.'w}9s۹iٙ/A=_|!MqW"ٙsܸ/ n6rqlHsNTyeVĭM~Mο5KK--nZE-]ad.(,۬N8t݉ԝ0>Iq,߭6ԍ 5o9>TIK+\;׬hP!)UOQF:g!~Gtԙ޸{ax(֝>^;ac𺮬bXYհaec۶3⟓gVQqJowæcydIuL99Nu\ۮn) ,Yf䭌_{q7N^/W,X\֒W}9 W20 ,S}z=֤Jw$7׈ޝ@%PWwc~$kWZ>С]Bѿ#F,ND+4NJ7N3Bǵ٫8JIXdbi&՘QU@1%M(-J$^ !&p=,.4P6+J{O%";1X7kns6YL0>tearMY9mq*[KxQ,~Se e? h]ȾU:9s߄Y5),Q2)g.B?&eĕLҡϩ+a̯D˜kegO$ɍWd[De c`0X(z O8Cܛp;rjI\,,/- nsۮn .`14 Y"KOKwϣE1")5%x&Flpl*oFc 8p :ęBɏy&[^ߠ_쥽Y̓2s<:4 SKƔe{j0G9eʜwI ,{y%\H5r1Y5}׳2B ?&gŴxN ,.1,RCzE]t ?^񝛽="+X׻m5?r&mp궠ZoH_CKWt쐐e+ / VҐYz&eUNWEJcb;KhOOf|S<$~!=tbDYYA觇RI>qdI I*зY[Ą^[.WUxddrh<+_IƉ06֍sǎ#q Uo˿lLuVe1Z <s<ư1[7N r N|4:l ЦV6aNtK.=X5M~fĠM~MCL %wh;IV~EsTbRb$pMC$LA+JXI$D4߆1Նt_EI1ƒBz)K);OВ'-#O4asaM&vKlo_&UU.x^8@Ȫ"I6ufS1`y v:w (3~ ,.S}ʲO7H>4 De4+D nR(=;Qd]uvT-lա}1QZˏ mh&c PC۶4* RZ}F4m!@mИئ>A]vn\BVT2uivo':*g 銼PEeBϫZm<+~}i/xWk(15%"DI,Qbٱav5]aKV^#oH47<(°wzȲ1!ǿq6Οy۷e.?+8DY 2qShX0IV@-Mڶ5КDhۦ9Q:z]v Bѓ7aLUn?m[μ?oWxHÓt]pX$2ewmR=ʲƸ=3>Bt>mkZțnT=lUhZNG ٽuwb7ځmuc+I\{7m.=we叹*agޡ O(7U5h]HqRƌOq0Ɨ U=cm>u!9|YA14E6(v5Tsm/NH7W@v!WȂϖ41waU#韯*? "ͿoȪ7{l]P|.h)Oqpw;;t;涫*X BWB6w*H&'%"-MDlSq`B4.x)Sw)& 86*fr#_\J'LCZڦfҶEM[ mEh]P=p@U |/*~#i&\ٺ;/3<pS#(zz=sv eu񯀾]3Rh1S(^)" [bOڥ‡nn jK>OU͑.t{dR+X7kn|ŦW/$ģʳϞA(,QrU1.+Kr&%CK빿ܲ7+q"KaB:w)z%(*\9OD%lc{h⣨(JK]dn/ՌU-&߮t$@ÃMKG>H5دl h7FȮִ;n6<󒝄ckKoj`i"l&ԹJ>4:p>F /wF@ =g qW>>:4ODjI=5~Deg[U޵ Y]X &jYWؔU˽LxG &at{̢r~HKZGuJms7¹+H~%i :eM6rlXsL~o0>6MS!E -͹4PHӅEPfD4NjԡL2ןc:sx\>܀qoP"bFX$nAeK w{&!,Qlۦ<-<csvc}?x*Uu3%bJ겠 &"(%M;Ր!փUrll,8ؒDR:hVWط`~+ϩ0'2J2< i*6ںmC2DʧZA)?cٕuMS7(@gY_`զ:~˻+C;V%΃sa|0IR+Q#lu]ZSPcڝB)nTrV-F-Q8n_ڣinKD)4m"mA֘fBUٍ[UЂ'^`4,BɱZе9kq$͕X/>jZU M`5]aaa1|]v'ap<-%BxIL( xڲ(+zZ ?c0n{g KK 1eAY/dsq[cc|We;ZC2bxsED%cZ:$)SSKT7Qmj `:U22t 8:ڦm)kKTy$>leK Ktfo٭w 70橢\T yB}Wdg=;JCxkS@Y~$+ dȧWU,H 㚪4-Ƹ|+Uen[hxHMV, 1msRW䥓ă« {,ҷ3e/^` l] $<~`ݠgGO`+S @Q8oW_{THPi*zdW`OPY+T4 b2"13R1o\ڠ~5݋ՎMp]7E=PM1UfnT _5TY1Z3*7dt<֍bsۮ1[`I'YY$LSѢXOY~[Aۓqi|NhaV1'UUԕuavɁz;/jNY{$CJXDPƫ+JXw޲/^F_A$aC;3B:FwwǮ/UP5:hi;U'7;-c m[ZiB”uAmZuكB28|fq\QlXsuv]"adA2 4u5 i.ŏfa~߱9Dh~=/q]d ꪢ&ΥxĵNx orJa '絳gdZCWĠ IQ$?wm^ V~%'ǵ}sY]&s%mHCSf2)\.>RM5avńڔTu[P}&`0tvЎ˛1v͓x6~7EfCVr|(en.I05?k "6 |ߤ=) IDATS6'מS Gd!1pM'Kތ ji]|0c T V0k2M1){TUb>ߊ[$$_c(_54MHAU(&}GYTQa(>u]`bW@Xjf2VN;݃UGz-hM@ϳNynjnB6HVZ/\҄s0r E>|*εmV/Oz6n5eFKFW޾y\~orXp Y\YgGU&6mrpe%r|Xe(\yWMZP^62 u54MCZ㕺Iԏo]aK.*>ui"f⧬[w2fk{\I]M &_ mjdd|xxMzf5@Li//+խd^;oࡿGn3tܦl`mטOXŇy}Βz,.S>"0ʒ^/YS0kᇙwuVNmrcUFZ>EIazT=>1,ƅ*t;,ј^+3A&5*Jʺ@bƔE~ϱ8b g.#fhK!F˞ָ kjXh)ںLb[Ob/Z;'^]\=M UeWUn>bvFK {_@3A9rsw_ fqa/KK>z%>@^o7s%-^cu)6lXs5l3 dPKi3zAs ?CYyV\YBDi8}ITVܜyizE| PU[L!pxMۜ"2ЊP<(ԹǠ> v7fɞ,ޗ%"_sZӫ"hF.7 ,=Ysʪ[u# KBhABBY `kvLḞ0_f"DLD=1 !$$hBf @RU]{ɬ2:ޟ"Y'3;ϓ+- b G걛,#ej=TN"/]RaDXy|#ϗy,AI?iuk>q}xYu>13RH|jDU걮,HJGu! ڝLzGuZuf{F ozSe>F}sij 0×XqAˀ4$Yf,aG dU:/o]"R< |? yP$l%2v,EE!敚U{Ex欮-G hS*|㾻FMe>X.{p,0Z"\-]Mldp|^=%dAHQ@HxyD:6|$c~z}(1V(X@1[03JmI j+I?&kDqi!2d2;2R\Ӳ÷>7(u+:;Wl\$kDaWOjR_õ݌Jƫ|teWQv,JR ?w7dMDҿ X( L}>_h0US@j_򤈪/Z2OY7+~18] 3;"efF1U9lGYH_|T6C+4V˿^_Q c"BxNP75゙e#Yާ1o}Fgx^PY([wt%X#$0ӲW#0?Fc/aT# kXs_Vq Y،ZƳf82 OO&5L5~^Pt<1I1,+WPZexKvH{ 5VzT$"x{m(YiVh!0a#5Y}6'ʈHX# yFf{: *qCB , H(ttX"b&\x2!IF3vȠ4uD%:_ghAZeJ9clye Sc;18s9 a[a[NLFw'.r Jfp: I<*c{'m<1K엾M5* `1prAVŲ2M['2Oi߶i)>~!Y @7*H|)GՍi >9YGKF+|1#Z"Vdj޿h,R/sZʠ {?\(Y+2{" a?"?Eڠh~=tN1H(R9Ay>}já߻~ɉAJZA<[Ii(/9͠He߬RexG}MZ{f nXbm\G$}EgHy(Ne 8^}[~eK:GiI.S+q7MI />QhT!.Q2:#euFm@J~<أX,,"j=[]ZÿVrZR~v%<$TsԆJy#ZIB mJU`4M;`d^I"Mxް˱X44&zQ{bJZy0!hU4IYKwU_̪8 6_8݉ 3p1ƞ Ҭ{0Z".˨dM)&6ALQRX?zj4{!!Av g6zt#cvJ+ܘ-|_Ҵ)JlBXFV <;I$diB PvZunO|ꋷURu'_&  l@+/ㅟbh0R~YXQh9pe=)YU^U؞j_H/1SnA޺g#>z9RP.߬sʱ8r5R(1'iAҦ;CGu7"P^L2OȲ>YjӴOץK<2BB4=t#`Vm{zNL+UiNJ߇s^̼QJ$]%ݓt'xOl9pC'Y+/VcjC4Y7,y_lk(uǭ*ؾ72|(#USUy/HH؝U98e3V.:uׄZu6+L<j Azxǹ#/>RB|?Ay~'9w =>\coʡ~-"[Օ i r4.5LS Ǚ~O67)y4dJXt ˁQd1JiId 'W\‹Q<7Cװth~a=!AQcֺ:Zl^edt ) 'I:nF lʐ*#:>(mG??'f"dfM0<r0[ F}$~И_p $`Vbt~" 3W6.G 3;JH@[0X6kt*{POy2+tS4[o8X,D)#'užaȓZY,c I)2$uJ!y\vRX).eE`@RjS#nT4.3r?O@K Tyeu\>ZbdMȲ < ISߏs"(~Wb1ib*mzrO_#VDO .;qc(?]kG\kP}j/#}s 1 e^\2k\wݬ1h#Q+JM)y!2H2 8rΞJ%sҴ_/5/1#WX|Hcdϭ!)-eYDFky)o@eASsN}(:QeY eo$t/]EV >uQiv+.re\u>o(X^Q ^?5`-l͘w}KiPbM ?qNj\s;zIybF 2kx^ž']NhC A63nH, u2x"x VbhZYXw쨵hT)*[*ʞa4g,Ǹ K.pcP~ |`7ƬTYKunZ clhKVZq77AY. 'xk`OR<<؇<3Dqy̨#<擛ux!0Zg}PaaR:~rq-mYƒί'<<V>ޝ ,WNp,L cx)Ά=9~1=p-wEE1H=doT=ȋ7Z>& ЕD8/fTwBPd\X٢qVоb=Պ;H-n{ؼwquzLcJM ,LPӶ&AJMs-Ik{nJMe/RB+JNL}xB6Bh}P,:+ÕV9 A[͛F]mpIaխAO'p߽1SBDcŏuՄfs/>E0& kAH/zqr%k?ig$5y£W3*|AV;Z#\X0ZÔj|Oz55[Om[O}19?eRE%ph ZPbL@x ZIz ~iLm(D i'cf+yΉ`^\)lX(ױ=e7]vDZc B `_.Nbн^r%<vز4YS+K. y*h?H6{.~ Da0^֛M&J:2#i0T [j#k -EwXXcr_qݡJ.U(+Rê^gz?fӯ]u_)eSt{t3 Gֽ>EPN1mE~ i^3'_ Oҥ'<|'<:N[DxCTY2GLۡii9vc[w `pǮ3N±"2Yu{NZPf/&h-ʿ5°ADQ8|֩]uPo=vO[Heu)e=ҴOQ* R?^U^8ѽgm|6W?cH=ޒ g;㱬9-M;evD)pngj y@ߏкhoZuCq./Gkp =L7ݦwz Z.Ϸcq5g6ae1i0J*m}Qd \׋˚ u,y/o{~V/Sʐ*%z\w^gڔ"Al,L1:Yg=͙%ߎUQ!2@C+ԗ! sJ%хǓ6u G}~4h6Ra ߏ4 O|CN eR9Y6#`<@yx^PʪB>I*!Ϻw<( o{=Y`p"݋ 3Nƃ,E!NqRnKkiie'j{& IDATFgO@։:fkx~WcsutfrRfx^Y֯֐ҐepXXU?D(n zi!Pr|ݟuZ 1Qd$.9i3LȕW3 ]=I{5"Re "`8, `k}O&~O띡>ՃF6tX  td 9`6\1shm k"8Z3p8JÇb8Z(GlAj4`{ B|N%"D]5pfV~=xk¬TkIiW XPƲBke˲R&HV=Lގ}ZmE,Fkgk]ˉW}mB([(t>e%Bm1shUe|$;\H?Id%imVf,g2TUlch;+tuKư*fN&i4!e 2ϹW`*rmSG6ۊP/<݉ 3Gi;-V..3S_wAVI^t!>M}7䦕{W*|L4;M`0tRJڡ˃.^^Gס]>For╜Ok}`Ca`˂y10K{I4푤=t &e-XK6XB ?أ9ѽlR~8\1sq.`h(bRXGeXiqoG/b0EvRT @z/~ 2OҀ(mԀgh"&eXsB$*UÄ&\ >Ofs?Q$Eu|?G ej%x>y> "0"Iu2b+CZuvP7![bR2C!Jfg[Z#Brg֎/~Z&[/6ɳ_&q>u <դ?C/;J?tR,Q7[UhAE!&Ɲ3R 0kG`sW_0+Ce5&M _b_;C{=WnxO!<+- |y0, a3sqGt&\^Xd ZYۄj4Zg%yʛ>,/~f(F(%mf>{ˠ9m6/Wng2q,Q}׾arȝҺwzHk+XvgZYAyǖ+(FҒ̽X|EMv%J`;L 97wdgiv7.9S,\aP0fbTU\TT/v=eee=kGI>i#I\" /+A+/ V2vt:~o4n*UVM6S( 0]w7.rRjB :`ukD+J}adn3WRe|*}2n|D}~j 47's:1op]YO.]8g jmÀ!i!I:S o {0`"'Zj,s9ɳ-vڴmQ0uq,̡GJX mrQ۩h%>5AXj4XC){BnI|(g]Vd (#Z>w-` =O޻~ї;lEu`{[ޓ1IyIa!YREզҪK yE$#_O?TFw8̖_g|s%qgC:6hZ '>ݿ!dGf0tfW]5K9 W22ڈ~8nQ;x3?x }|?!ˬ }:@ C_`lJb6ͬADDq@k}e2*+Y'r@vweqRe\kr}pGk٘/@kn[W˿ .8}78XϳN `;x3WmV> $_cްXdt={Slbhs>L:f8aL9X:ё+7YSA\WVhm~|ߣlLJ.9Go~᱑~Yf<(X2_*:+Qm̗ AqigՓ *E /|{蛯E pZjꝝ,|$cz\Tօz٪t]ͣ wN#@|J;:gtBNaկW:lyGʔr.灜hrRy5/9tY-g>fGB ߹-uH" kD!r?*z-Lt&iv-۳iI4+)1#@juWh{<™!>Wg:5:-X1v ˜, Ҁ( ؛ Z[V"Jɲ>@k+n'ܦ%6x?OZV,tp,~n>%zSt{䃍y|?CX.Jgan x= zVNKoOeO/|ejdӃq j[wTׅ 'vt 7w q(?Ǿp,p3.uq`9.a]lDG޾`r6! ޱ-E#4:ݓoL-C߶#(^" xɾ] \v6ev2EC<y`99; .0yӼnuExۧ'1Ql ]FCc8Jei(pÆ3NFnu:fW"] 8Gg!# ONThh'2)U  !~Q&?8G^Y6;CLӦnG| 0\8tc_s#\.a6 )vfi!I'>iq-FnN 5iڳ#|)hPZ$.{WC~}rd ?S'i1xu?qlxev5odeD),?pB%z_%l7gT8 . $ij}OI>^`@6M)1biڣ;MwN$˯O4HS?_?4Bx">,>r,ZӪI ˖S A# C3zR@!ɔ$`0HKK襓\ڷ4{t2ge7DQ2=-?BSTͱ19NqcfQ, n: od"{S;f0h$eY}}a[il QnⳊ3 JhA0D1;/nس@urwNV fm0]@Buwrm3\{:iUT%sriG/IңLlsqwl+tL,.()>;,YV]xpBBY;#aXà%s= IDAT"=s ;a%S'dH'dY }@e c|Y48`I``yN9Ivǥо$,5f OZ(_2+fr;?t"4d.l+lrl.F38.$VtZ,'UX0Ti18/J6{i//ĸ]1&Iʌ,뒦WA1KJwdYa92׊xQ-mg^v1ёu/ ?11IhfR4Giɾ˦X c NɥbV\+rYN.osy;/~agX*0F1Hh-q<@)3w.Nm/>,,\BGiAoa2#k:픅=5Z T,Eh< M*NsX4"͐0YXYXNf;=eEk; /|c<34edj>,sGo~'Zf0= _Pv htc"zt 8we vFqnњh4CjXxJ\v"a(zx0c|hZ\lSJ:Yt)/Zq:FpcW&4uќV̷"X>HdN,?ì,4#A.,NBbrv ˆZ-^:iy I"ILF]ti),d3:m[#F3h[z@omJc[N,?[,#٬aYc $ IRƤiDR|:)zHk6\isWW:Ozaue̗{+loս8K)3Ui6l)1f٭V\ݶi/%.5#T d x^@'i0 H[~4=|+_u&FIaK.1d2 =u΋6zۮ>t|،MZcʿs/{9̷b G^Ni;+ s7$<B9h`R_.FhL5I"QZ- `K19S+| h3lfow5 ʿO*sL KgVZU %Ve('8}Cq]~엄\U~>y0%y>`0(%fM(I>o=^:=5sa`7YX8LbV䞦˕"+@LPs Թns\$$yӺьhWdVrQJL bYck; ?8?bsҬGG+&Rž=5kUZi.!h6~Q$ c:';FipiuV˱Pit_EњiΕb^ev PeBW*>'L@'?o*{(uX Q4W\kJ a M BipXf.ROp >?dSޅe==fnA2$铥D\+YYAbyQXAts;1=>\mJ\+]T[gy4`v/ǣoieL}뻼&{ `slVWud4F>fHkOm$h/Ug1i( B>{y? ˕\y˭|Sg\"wrG)2UsZc|Z nR[\ <|َͱ=frƧ YGBIlZ vtʱYzݜ^7]ݚa䳸zq[;򧽜֘u: ]5:ˢOI BjZ-Bʭ,rrpXdv[%K,ڭZ=`aFs>VhХsUv c;`hQ:rH!dY45(&IC) rMU˕\dVhp^zf=8+ 9ڭavkzuۥ3 n ȹCoFxɑܝc+|O>siAҴKDt:>Z(C+j*rH+*6q;ir> @/Xf IS%dZJ吃/O).%$ 9&H'R%Kh)rfu73b6y~U,7Ґx~r?Eep*טf`)4<fժ4ǻnʐ UUU! b`]=菂H 9n YFVnuQuy흅q̪;*4CJJ83AEJHSY\.*6Cc~DhIzFjmlu!k*629:o,4wb; v_ݒn%Rii8w%pm 1629zFB9׹8c\6Q .Riz\CFAdQw,,V6GU-+ b[,-WKB&ǎRMy]ԪVX *ZiM,m*e Y7 YìZ !iz5ֵg.Jo΀tk\ 74KD [6fHPaKc7@ERjUuwn&fo,INZkQkEP#-{KVPխnDUZ ͪ?zޝ![x?؁f3#j۪W9P8oխTZ0XrlՊo'CfTwU[p0`ц FAxfBcHd`A{QfZY(+hUJmJFF#`8kHzd"ThT#+ Y3S*m^ۏ䇬Ǭbmz?T醄gM}M9)ED7+ T6g%ټ_ݪZ2dvPy,1TwAwVV)nBX"-y+@ZVZ? znJz YHkV+HOugkrz0"!n<"ҪAA7$fVFAF9_u+YcǯŨY9{NvbPuAk*[ XDt# .! P (){)@lgJ%%L=] XmSn<V.D=#+#\0I!KB~4jقgƉI$vF’'OjԽ XDXuAt(Mx1խߙX)V; *\GfX>]v뱂EWED4(%$H"ҚQ5jy(U-[:g%ɏ {N0`MռdrgCvOAvQ7m+uY[h5;apf hь\ 0`f\ -%`Dz͉͆+jvy=1( mBjV=6VZߙgd~c}F.ZJBnOAZ ŋgXmBb""ZzFfI oVf[n-EB~OA6EcZIrGhl EDr~B? "[J2揂 **/{kUC%@, oDC 7zaDDk'n@, UPUY^WWµ~S7m5FVB'96+Xr6ẋ5>I79;Ź6vQ)Q)ժ+T< f\lì#+/4Z F,VgB+XDD$ 2()#+#õfFQӪ,{dezLw8wF8aOO^\l""hR; ͐j pݮ߻U`lFTUa^s7'+XϤ>/e. XDD[¶|p?yhOzl눈fl5T(_ \GiõBխK̪hд8=:jR_lh7i{c<qď+4<|3ﱗ:"E-&|egh6*piծu8TbI=V% 1>JM?-Nr_UO>*Lzl눈)n5&"WERy)~_[GA5 foLRn#I#`.Ev`ت5*|I$HMh<{Y^I%jyT.BEZ,_|ٺ JId ΞׯZ<XYBm՗ X6l puDD脁3ffB Y{Wj~s e맅U_J6/`>\gWA&[5ժuI T]D2@2? ¬:V0,_PuY3:G4'oނvU_B,}T8d%L.L.A\v7[ t&-g_' gMؖx|?=ďz;t˞Kݸ!{N+DUD?~%"WU;F8T]nQiGAkV*xM X`ޡ/Rj`rQ8sm4U.m% Pu !kkUrb{=? fX0㼆:>b0a5i\ӤN?>+"̪W㻯(l))$z7xGyL 졊/L=%+XI+"޾g_-ٰD)eE=N jܱ]>:"m]m|Eۡaj3"@E7dw|oɂaFب4͆fI߻fr~vfFU\o0=l89X=7lUyZD|w=c0[6 &̦}er"5~X3B]E8kLrխ+XFVKH$S̪JBZ\A.pEk,NդGIVӆٲrjۂ\,?`y{c֗m8=tr 4]$%) lEBdo>_y )81ك5El]\I"({ݚeJi-zljM""Bf 84])8nujU ŗ-*V L w"d6mM;|\N"`OOVVJr5u|Pڌ-U,""l˳^t zVKHh(jٟZՂfHiXyqjRDVUpw_{z]MVlY#\AUMEktDDDO\*ՐSD)SڊJBb,_zقnH02+XKT?d1HKx(YLۉ~׽.,"" EB_JV~Oy] -TkҐT*3iv'ڕmŋ <0|$âX XDDQ/ !A!Kn5jU 1 \fA2-?0y؃5 M)XXG&dZ@2-{J~`*l!js ǀEDD7exċg&@3 խl^A6,B R¬`u>y'[ÀEDD$)o'f%IHRGUVõ88NiͱEDDteN8?m Mh'[n}h.⫣uŀEDD4!_"e3LDDD` 6kRߙ DDDX""""{"ƀEDDD1,"""-wFMsg"""5 Q"ƀEDDD1,"""-}T:Ol+XDDDDc""""Qg"""_lr֤39ߝ\DDDD+ Q؃EDDDX>ᣉ]g,k5n"""ZXG MDDDkn'5j -4_Vn""l ָGDm€y*LB$1i w,EDDD1Zûek[|DDD7/ jQ5 Bư5֢0, pXdYF厈ƛopDYy|\虵G!_XIDAT:^V,@嬪i^c1m XʴjӼƤkGݝ8hknDQU>Km^Vk Vq+ShZ }j#j 2B_{VAr0&{<?L4*kw Hkx`G~T:&ߣOV} DDDaE7dnd"1`E(bE"""ɰEDDD1,"""1`E(b XDDDDc""""Q"ƀEDDD?!\h\rIENDB`v_sim-3.8.0/tests/exports/map-3.6.png000066400000000000000000002747651370110300500173070ustar00rootroot00000000000000PNG  IHDRXXfsBIT|d IDATxyx$Y;kվKvUWwm f?~l`.g0y \. sٯscm0nnkߺJt".)dr')*LU^?2#Ns"Kx}_/HB!a{B!,B!C"B1,B!C"B1,B!C"B1,B!C"B1r>46 Bixv`B! !BHYvnO^DKXV,+~ꭳk1;WB]~R-Rr(P*bqq_aZX @xss7i5x)!B~$*z%\HE ndv=x&c.oFElF>xv ]verOB"uAz0z!ۯf4 [F"W^4/Z..DYPH]RB0wdirhisyFL^O3"p9ZiFBzEsqK.j.J+& ~]GTv{Bi$(X.D,  ī2ELТS]'Z iFBH`y(X$ ϓg3kiFa]W>oF 4[ e7v1HYm(XuIMK Wޗ/nL<"$rTX_EBj)"`Z: vl{*,XT-jJvQZt!  "ki|^--KE-wD}kvUf,RWLE֞(͘x6/ZJ,-ES]vExB +Bi8d1qF2 ^v`ec{BI0EH:9\Df_45v\~Aċ]ܻPH]< ìI,.8f +||w3DJNxW#ӌ(Xnpwr/p{҉b,flkχm==jH/BEꂊ`I"5,&KdzwlvvT#!`y! ҌP-ۭrع\|T@˞4#!uEꇟ#B-`z !!$[ 6w6{*BA@J)M8ƃEEH j2=WE@0E,R7\ǃe !A0@9+<-" NBB}W!yk3L> 4($F"rEq @I!ԕ EȿB !2 Uj^)t؝4&yjL ~䞤8[]vQh2aSjOC".~Uob;i<(Xxd;!R|Bw/95BV j8(X,=u=ܸ6bW5RW\O>r\:E +|3!DaO¼L4,RW \D{^ٓOB`k7Xq`#$fIr"lCa~BUj" 69VtK7k7!ՠ`Ba$R ΝY@/ vv fn'xMgh}O"dZҢۋԄށv\8[ ɂEhi TK6H#)_=F/7Bfg`vZ.ѱi/]׏NJ!5ذ,vPHql*BE%Z@ނ_fH J;4B"D#XpBdÆMMX1IB"uǰL%RB0XIXhRZ*(Fe\ff.cf%=~~@>7nFg_?zGۏ~J!bR߈6 Y(X-XpTK,<•R@>L-@" R)kv2fH| RD&%]#Gg{W߈--hj{JENjC")jrEKJ΄D|S fg.cf&SNkvj,48ۆ6?s{U!$E=IR$Zm+-uL$Z7(R.7m˘} Ǟбy3:{;<~J!wXZ&/׆v Yu(XRLRo*D+ޏ>Hv'}a_3/c/]xR?ؼ]}J:0EH#1W,cnF[{ݽmR= vH]+nGh"BQ%|"rE+PE)f/a8s0= Q nێwY"N SȪB"u',roUVZ}V@joLc?3ӗ0sk?N=yBIWt nA"L΍kpylԄۼ,X N1G&E ˸0!Sǫ*Z F?7Z2bfn?3GN0{)]"S@@;,RwaK_chSVCRI߲E+X~@R3<'1s8= /6lIn*+?܁-]-,C"PHq"6_@*ְ2DjD++}2|rъ#v!U8퓘}/qlؼwoxԗuZ_8Wq4Mj4j@\Ċ+W0خLdV`js .Suh L=[0}'zG=H"돵,ri[[F"V6BXXmRܮL_Am-[h2csi/.c7w6cѣqė.Æ-J=0J!:o.8[F{{[Zp|D1(X8Z`]IKZd J۾g.KrYGYf$Ak vCw7u<8=0A􏎢{`EzD+3h߳},Rs(XȊ@ "Z~hUiå@$Db@vd)%`킴vC4+T8Ǒs,nQHݨ`M^.bǞظ mygk:>`"Yp~%,R۲WWåWV8J]k  mN  L=#Qt{`}#DYM/Xr .^uԱk>>w`]Z[%D}w(Z-W}wă?鴵D0 %>/ !ZӀؐh#!cQ-ðn pNWgc8|`t {`}ckB.nrR3(XAЄHdJE+8VVkraf xk)ŠK2KjuZjҢ^M;!Z ]*҅4Uz1:"`O}EV )]0 Avݵ`-.8}s77w^9{ i\C^h0o5Gb%tX(Zf۷%j,3K d4kky}P@A  (8{SGk IDATJ="]=tW VgiK3:(XfPHC8kKyBBI>դb +F+h*` ;b9Z)TyJ=^P5Ym'B;GEL9E4;0u(x4*n.`qASV\=4AÃ&hQĖO@"dGMUh`ؿ~梚D&SKji*$0<3;eJ O%.ZZM&~ =a0y(1G~0VR^-`@" % d\]Fm$ϖD+/)X݇Ae%@ 4S\x)Vhsoȗ/]=avHד*6 ܍[[P'ܶk 6oiFSns!,wtq2#ZZ/gmA?LD✂>eDpKsSy3uua~c]4cfyk'd1 kpNS0uiz{?5a r/S?+g;ЎM8yZ]B?,ic%A-Õ,D}>$Ss SҰ]$26fVZ1! :6=}%|y:61/3>HkDs4c<48\@0z?>P P^WH 7N"w 4O ahWyXMKVL$M]vIÓcPyV,ʈ%"Zᜐ&K+ }k}zH[^ *ԡq`~ze gpC0k!ä)B(Δp6miF@;._|E0e? M:ң;5hS1Ø0!gQmbゼ`ZVN ԔEƣkrF@th!Zc-uߛr|ôdP͊J)k/`텁mfɃGq@ k|{fiK3m`ErƟums.:]D|-!!T` ZAcCzUaFK(}+R6G⼳D1oʕ?=rԝ%Rۄ'E*"mHbx^3ɧ1y<08ER65ǑhiaӖfܺP)u~2?܎|>/ cYGE}SmܖWſv.vG=Q5<``vRBO_L"xTFl߽W'pzOS(X!304F yhiP' 2a~ ΘxyL"U^+(^ʊH61QFeO6ؖ-o8mVMDehm럝Lg&?Nu{pe~=C#tPVށv &rQ7z vgD#,tW3ךง9045qĉC_Q#Et"ZA0-CHK9Ihńb<9_ (ZJVJBuiҏǬ8u%/])0kz1mz)] =ڃV\8{Oܨt:EM[kp갉ͩqcv;݉Tȅ3&Np昉 &OE@&;Bʵ:-hm6V|EHVjKF|[- +M;"*Nq)ǘCeVEXNaHIȮ;,u ֲ맴 ~s6C<{иs!rk^>cqΘ8qJ 9zNOr(^K1eDsFQjV=}XsњOi\!ZX1*>-89 ){-}vJWhI\ie:g_fKx_t:Ef }nLVI@>+Ƀ~1p14aÎ~HȵI'X8sBI3UPya KI31+(SF+gsϕVV(Z>/!2Sj̴ԡ&Y15-8oKz?FpډWYMoC.g fKYGPHC` G0_֤HSjx!qGԶ]v06bN3J=Å & hi}GJI[SUK~Ι™v\g8P{ B4.TW/!Z J nŘh/[lghCwwx.20yXTね߈W8K6C" [s eϊ fUmиxT= Y8~gGbo\cu^ꩴRʊ0%W2Dt*/h}II LIvU7w"vӐA;Q޳ҕ˛n]vqmjө%oÀ۳S'Y ioEڂ-R]eiibxm]~Ak~j7W8qΝ1q>QDDV2 V5%'uj+g.٦rʜ* /h*$d%݉VylHF7#UHy0tbhu/].X=mKǮĭzO(Xa߽55  .))1KLT vmv R\4paār8GEM(DK'.5,7 IEvEe't("LuZ-O;>&:Ŀ]VM4dM+A_@72;1g/ZZ(4YقҢ>lڂǾ᩿t:E7|p *uKH,ޏFT-1< ٖ( U ZzŌO;_2u^BYj-$b})s% C}T-*YhѬ;.Z%[wYъӀ<_E52 ؉=6t55yk3lܼ޸{÷%_ԕƫ#4 }-O6UQ=v1Q(R,R} FD~}q#*gc-q 'L\ 赹$MhUDD2R5"6ԲE_bЊ>)]IfRh*"\bNizVqEFNH+wHzGF1cWCHWS Ђ50܁=wy^B̪ecRbqb*V]VP#Sۀ5Ht wd ;yck*]-9l܄9o.ٸw۾w;o|ep,02bt#12梫 2!sEg-;kI GPPGVJV5wEҔ:TDIk#R'U,{"X]2y'XV8PT ݃ ۳;vtiڰ -9LZٮQkë^Ӈy_ʹzO40MYG]m[RP᥿CHm'ۅ8A]hԱRDIH?@%Bm+} \,6 8 9GՂ9^xM<< բ.FG]`^(l-QMtJ;׌@Wa J E=Mr)!@vqq&.'uD߲#vؙ,!]ޓ]wX< ۿ  i6mnCb℁?\_2!Z)1TFo]$pDJ{h$h4'ǒ<.lY :I0|ɰw(_9Ȕ+7q uL6K8x*8:-kjٳ&N&N b0&\1ъ-@jMl%L"Yv"=u./#b54tXpE,0ukq|,!P霴v^z%2>l'b>ģZ) "]侣F4[!s]@^j@H Ză~^7!9x|{ X|Y}f;3"M&"NUϵk{lsMM8|0S'-LZ@hcr#}iB3$U!PHDЫIHTh6ضjQ;$tz ^\u l]O]YހEf Aܺ.g R~ 2d*V)T%VA1DX=%"QP%$$`m: h 4wBCG4N ~g j$1`0w= iv ЗC"eDJ{عب)]g݊/@%Gh?g!!42L韥LahD+F+e E jъMh1\s_%H ibژ{/Py ^E&+Ab[x]M-#HELocDѫPJ:U,2--mnYE&ZDHz. oT1rQ.O[66xUe\X8{N yE(Z1IV(EZzꝇD$,8&&bB$kKۦ!=բFw"Z3>r"ZV"ZS e;[3!]{-]{;1}.ⳗk9#Zhi&+$B)5]$MnE+-ygR|GCE i(^aX93.ieₓ,mE65U!MhDBE/}(;dSgzdhd]0b?4mlj6@6(J@OCڋ0}ޭ V?'3\ɗ̂ %Z.^)h k_i?1ҷG4ׄ9`6[HE IDAT=b c┅ɋ*L ~Vb ާE.ix_N?Cة2c9t}^|2.8!(PHC 8e?  Ū",jO6Rߖ&A݂xǀ`G ͜/ST_BhՏ@6(m#v hjIDDj1|3 އ$i9[WǀK{h O<9le0sr Sj}_ K&SA/JJWq) SΜanVTiU#%)Zf|w*Z)rѪwJZ#ֿz/c\PHC-oDS WzN]] ?SAMUxN$ BiE(U"Z@"o EJRBE>,?>(m lc2g"E6wIe2 N `8p:_D+/rJ?EFҎh"*1cR;lWlb⤅8|gNDϿrѪ*Z|NRQ?sXô\^?\O]R&A i(~u{j+Q%W 6xl''DMb@],Q .SZKj)X{x'/eIePE II %W9|oҢZ{i}tL7n\ҶY j%|)aEˏJ"5y?byxTmruM~r򯀅s ܩ T-?u1m{\gNB:sĉ\\,'}X!ZEܷKWڈV8 Zww7pB" Ş#jEJD_XL_!Wy.@vJТ^ZPd”J hx}'*CE,#} AZ0/c0%شy?7 't%yJ\8 yp(p,`_ %Q6"r?yKρ|cѬhQ1?WU(,jHtѣ\ Jъ~6wc+a|z#n=M8}Bqw%"ZϰV(m{TToܓK<7(k􍎅K6T-V*|QyaJ%+cSqKQT*ئ-(FZ("<yW!~> VAO,X]oZSiȹY^: '\ W3? 9[6m6 ުU5˂].]5{%x&Kc@>4o?EٲA2p3@}_T2h9)ܩBE.}*&Zᝇɂxx1+=u?tPd"L.mv?dh먌Jg z.c8gEQD+=S%aڈߪ.s|ܬyX܄_[:[`a׾rF4;lEO;) ,_ƙVZD+ D"&*VYS> lnyh Sa{XCe26U %Yy@ho{Jrٟ}+G%gOH<\\. } qW> ,C޿ptEu3}5&ShGiBM}8w |O7dg/p 𫟋/E_DzP/C^PT-X>.R$+ U&D? P)Z=.vxK`z999| 檋VWPdDؙ|Ke"X wFo®qm}vL;,P lxI{B2E+"d[ #b9D{Et`x/Y } V^9p!? ǁ(dh$ܷ((A޸|f`h<tBzo!2}0/7 OMSJ>s _&瀍?><+ >:Cˆ.e_ Z .v9xaEQ>"\"EQWR_=݈zY>;|׾r Mm(Xo=[q_/.Yѧ-H" LA&܅FK0T>&(f -@~cc;j{'xsWCG&y0]ȏ~> b"~ q}PVS~꫐eueZ $"EwkeV#Wֲ%^q ]Pʢ V7Ls#hB|`|U#o,hkL<^{xj4hQpAEQ !aPVxgrF_:wIr"v$J)JBPl"`w#Eǵ[ Sv?%@lB}EgI Tq\) i9BM'i8g1"Ju=Q [W(Z8iMeܲ hձBQe;M$1-l+-0T7I*2`hХY8Křz9x-2No^$ 1]F7sǫKXB6N}(:VzA H?LMVa5_XfXy٧$UXoá$oPPa& %>S?S{ty%zHLh |BByD"T I.۾ upT+nˬQdHEI!6P9K(e|7!VH0FHsOڼPhhJx5J́k?!:Q{pypW`v8pMz3 6uىp4`2@ޙ̚? QX0iPjnCt fK@ ] t}ݖ>Piaz wAF|ճ[Nhu Z\{qQ @iyQ]khUdtD;hȆuQ-K,]g¸&@  Av;vZ^X560!)L{hzF@e'7Yj'PףXeÿV^Y'romOZQ{a`$a vz~0X +sʈo mip)@J G[ydQo5/A)P6 P*x,;*fŪc]ۡ g`wZ!C1w!w_5g'| /G:v%p}G?BQ ֛KNK;"QK ~h@XBTAH(Ԋ`0a0SeX#CRzP"XqZLz'6Ẍ́[= KcîfW/狼niv2nrơ46%^{}*.da)bF?в^(h{m6%.gF+zLg܉ v{d2ú;SA,^eiŐ<>%Țpm v Iҟws_t7Oب2ݨ:*x B JaO|0BwuzuEHFm.X߁J(5CPCC?ň!8Ĉ[K8mmK *62|paS&ܴNR A}H!3/[/D]$C0y r6lZbZnWqW#y dĉy`˨S#-f0 9+c׽-3ϚSf8 TEظWT=_$C;:tOؔ)1z9{Cq-WyZӔv,7rs_g}0A@ν~Fieoy`I`eߕW#W>'h3Z&O(-u`hi_ =v*R ck)~\]p빨n JӋQ_D]W!?ABV j+D}Wj@(q5srbJGBH,yZ;B:Cf]A=%T!X Gw#;xP r)̺ 0m<)~=_djRcv ȗԺLw_) k³`ij,Flԇ0!@y.1V^TR =;Oh)o[ Ô{,PoQ.lw74 d^^bL|{bN'|b N}gZ=-]LU9 Vw$hޑ H+/:3DcED.́rb&*[%>Bt ϊ0Q3U߲H~cP>>A ՈjP?g_Q/Rm< ;@A](F 4aXex8ܦXa-P<]HgdX V]o9Iy\w \ \6uyHg u g~&rQ{}~upͨ~O|N|$|d1Zdf؇Ǐyo <;-`ymƮkEHն;ӞootJ34M2vzF>Ҳam|nyk%JP+?%l b-7}"W`:sJiUT wq`-В)gڟxJ|'|`f9,u7{h- IDAT2p60ջi"X1FSRR0b$\}sC/*~@Tp@w Js%lOi $:/ہm4O!3÷tz5E0n9t̙Dȣr]7| P¯૿w_p{rḰP1 ,Xp42]X]igo*ZgT4Y2hvᝇWO{@k:u<,͞n1͎]ox^ah1 FOL0Rtb% ,]g8KY wp@ܲ;Oo9ZMQ'ۏ"Vdj+ (,yG3˿D+ҳw9јûC. CEH0Iqon҈3GcT,[*Kmp˼[SHC<4rzn^F4!ނi}h m#2 GR$=JEBB!,#_8,a4h/7APZ#-X3]7@k`cHhо :n=%3v yt )*+BN= 'GPȤ БF9Hĉ@EdѰx[Sv di~c N ;"Xv.t?=8k @I85L2kXӢO|D態_5|$t|`fy_)YKPGcYU6a4Nřg/EqSصzZn=@;$$o`GRUDAA [>skI`e ",zOѶ˚X3eMe-\H[WBq`PDˑ"z<>(+,C6 8[q)+C.BFOi D "rd:db=üpP9dC'CQ ۅ7C D &Dc BeTz  "fGӖeHӱȺ;o8ֲ!HȲ w@ 3Ngh@#bgU6 V< r? JV ?f+{avuK "~TW_(bݪmEYE4&86N9Slg2IN :k}V]NcIcYg]I6t,d_V+/ԕPXeعd(r@C-b޵B`#IPd',Aj1JJa0B_GwBH44r($_EeaZ  @4Xy(lKO Mǘ d =hlxa|X?S9 B.~Es"ǔBc "'Zdp/8gr{۰AH*V8p45m /<vb 9P̹YGz\H*: v-E6>ԝn>`8?t ^Bc.4F=/x7"7sEY@ޕm[",_,fe̞Q;*нWacur+g|NneԄ(}\zs&~nVw׈|VI%3WPZ3͎m{OYsRUSLqIaۖL6#Ys%Y+Z,}ZEP.S\ =)Eݍ9B=EZRZWg)l؆\ '@J2[V3VH^ zX^kj %u€PC=Kr1,*@TX=}IB'l@Qw.B!Yq'qe0 RTWš2>V}^Hz!mѥ %X9dwt†ț7##z,àuq,<ݍ)ҙ x- #U X~V8z;W:†uQ+'Jxr}gˆ( {e6$7Nn[0jgco{y.]g3ٙgr*bϝO^}sҥҲ8k+lt a)>Z L+IV$ ,VxB\E9`e}$Y&HaҶ <ܣ'd2~D[%10-2/.ͭ}2I&luӄ@q7AP |{x BQWaџH!^ AJ1]hlxztz [#ːr \fʐY0mnq\ =ҽmat/>ALF"E𗫑'y^t4ҟ¦{}E0 nDN5cJ!s(aM] UH[jӔUd8IS94Q "Q Z,Y푳Mҏ3vaH>%^JqI-{OI}NVӭG)?a<x[*k6V m/yďo`C#} }pE,G^qPqPV/:gQo|8 ce -{Z.ȋd m1FGEC]((tE(޽]@(>yF (7NG3|lYN)F}F]?ȭEA^Xf΄NC'?=O?W<J> zۨwAJ*& *-ޮM7uHg: ڻ%p\i '6+;wOawʾkezyM jiltнW*+/w_+d8S;Ҳ33Gb:)ڔO+}*>[xuW^yw%IƮ.?exu2Vԑ O=$|#S>V{{6 /XER">F;1\%Ϩ_]zd2[ %0k\7E;Țvs-RT*B!)2֧0Fh ˀ-HD avEEu@kӅHڐs@1\ވ1(OR( /nhrs4oK\ԇJ d)˳uXZ  в6h[ uʍr-k?*t/l H^g$ xNz{gV Gј4dc蠬JN% b,C>PހV{%WhVޟG:a : *ya^9)-ѥW(vVj`<@}} ui@;%p}r;;5y>Afn )+;h_cn\g a)U=_T](ib( u<}Mu_s,F|<4QHvYGQYZķJ 6|>bxמ*UF`-c.4=JKF˳d zQYpwBkL! ٞTy@wR~܍Ў?u2hX't0pX'688u6ޖʸꩪ)f-\QE<}NKbԕXHY_~ vkYfa&,vJ=bd٬IKnDTuBzdB~\#GdȰMÐA&Lj:${ J!~9/ +CIޭȗ4m)*P% aaXepw!`%rĵL*ڟLj(+F,ViTC#B둋.Hn0x r/#}_YtFLAV@sےgIeBc*œ3>+e"XS=k_hC,FKE1zuݧN 3Xy$sֳD,+/_n,,\}/lf"D dpN0Wo 'u2WQҶ oa:)+B&M'D4VÖ0opx_O1T ܼVE3%LxR!*RjEP0D(*!O h6@fVTRR0eE4v;>@5BwC/"GՌ 9f*D -6W~-CN1.Ȑᓕ7 #N I#US&X #ذV} 3/ Z+=;'#Ôn4B%:eё&,յk+y}NУW9|ZCf@u1kAf*^@ ZJ6 ~ziE0V/@&iz##Stcʵ{0 Z@f,!݋*ྍx3LФ^SPtޞA5#Wj =%l!ƛ?K7ñ{Շ]Li@pqB$\86"5 ఓr}&@Qp)2섬,!"Ń`itKzX?<׸ BiNǟ>Q^O F]w-edj>O8),.7-|kYx+4ISۍF"WR׽*iRE]R*""dҊ?+%1֯i&v1MRߧ濙 .tքl/LYzeŒ %rya h[c={]t鏬{L>j'E"[dD?M@ؼy C-C X$;aƇ8Gdl%RG$E`!8$AX]@ef˄ 88_vu@Sj @";+0-Jer{pX]q5pG1)Ue 8o!c+f!'Ɓ?s,z3}2쾵NJS*E9dP;$E848]Z@wE7[D|n݁0 < f y]L>'g|HeL~{T2C7vN-捻ع= "!PPemB]ٺMbvҩ]sICbP 31 s ӣH(U"<9 B~ٿ;tv)C1n_w=iZ襬FO gC>1i8)nO# W޸pP2Ys!8o|9o[c9ǚMlZ}< ^^Xw=W=2O0dTGJ#Mַj-4'H"OMyX_s(z4 O{N@7(|&~r%G|r,+GZ߇  Xd9@EXW})@F?'t2e X nx &mX[,Y V!82Hma]] A@(2, #D 9dE&EU""@䬏jw~=pDiC{!/ 9|26~̜yRMEcȸCab!'}!0=\TAա-W"gA)1\`<@eضצ-l#h IDATNbzV0AF+syJg-Nȕ,/Z㠣GQݽޖdǶ6oaŒ^O6Ѻ @Xy'w_O׽Uf\a/&Y_W>VXhr,^Rd@bltpQƪD#бs e]a_p RVDxp&LAVQ d]ٮ%ȸ^}q%r`oX #K`x c;rxW@R Ё(G<*٪_VK?A _Eђב/GTt4"Hi)wpeƌ`ʁύɈfo~AۄW+S*,:*,2 vZvb {L[C! }tӁ# PBak+/S:<>gy]=S-'u'|$Q5U;ae+ޣ%/|Ivh#*9@Yޣ.ӿzdi>u:O'T C" (zIDQQCn|W; rYݤf[%[l~Z\`@fw{sav^P||9Oktӗd.üJyK.I%3DB2,)e&Z=jIS$q#l,{Վ(j_X~>2fQ򭶴kȺ[Y~Ƙ{*+|w  42 Q_nC\FIA#ơ..?ͭVor;@~nҨ;m aMrڕL!TRAY*5g=ĬJf*  gϟ%]/r:4CmwD0B!~ ?U qCZ{ `J)'C(B. W"ۖ JHSI-D Qш_K& Q)R> 1X( h;5ܰʥy1RQ]#Gu?PCWOևAٷF#ܤJP?KȓgB N~w8ְC7?]Ka˟Qπ.I 2HK:5 YҌ5.C^G,1Q9@>,pp0>2Jor+4hƝ?Z S+/|tpMȚhűݯ{3Ug |)O6 ө%"SD؋2_^]@W]bcvU*=ʸDԈ1p2AφDu{&{"\G \4үkHODQ)"]ᰁȈPUI.h>߿5e4ra"n\e\< .C557}Oc0f"wKa686O]$) xޗ!@fӐS՞Sd \KDPCjw>: pbWu2c PP.pAdO Ͳc1:\;6O1O|  p GZ~`uw@ Ղ:Iv/V^I1` KS L ZS|-[h*kLԒ@+YM^JjMײ0D P%5ՊER!#ס68T= HJ)89;ɗ+K-IE;GZ:`[;H!4\s8xiU[Hj**D']k$g1TGj+*AUW!8Qqv,m w@;=>OͧvV}t8oàCQ/\ȱk+R),ٌ LPwj/u) a۔vyưYf`ǀG77]ejs |L(<*}, h ރP}E5zǫ RH)#y}RRIQ lX’e5 _,3*oa |;E0=ƶ'gTP!"TgT>)&_a- ]Pm۠Ƹ*BQ@e- 1`K@zG([P|x} O' UKtA)&,V.LriE\c¼дgXy'Eiś-6,a @N 7Ch5thySfl!$>Gx*I.Cp0 {_xz]96p v{FoQ0k|=r)@Q(D*"uh$|6tPd5F)G jwOrm\tp՜/խ;uC*+G4iSJ AN=kèN+Nӈg_fx#zN-JUN }:K13RJ!B@MCjV NwANH)]fƐ^nɂQ^ߙcg/@<_w׫yBS73gHQq `}$O], rocVZMbbdcMe2ӱS6*Esu>1blbcjz\Bm#8'~qAеN={]C3܆LchKfv,kpQEPHMU}*k~4Be(@KPӦ#롲*Hq3Kb(,eTiaXGHvp;\1P2Z`1H(ԋεp}Xg;\;-Ϩݨ"Z#}%B`5hy@J<3fuY qȡEkSnKVteL"sOvt QON)P0$9]pexB_L} 흈](.uL#G3%͔s WUslj2!0v2t6%Ao~G7uiQjs. hs7CZsulh5I*Ȱ0B̕}\Y3IYMd8(sRIP4wן4ai)SŠ X= }$aMI~P|½ s="$.-4 7l5]矔ZH@+q:K(KټSw$VŶK+c%_oGɓ^4JAqbX 0'UҠ.sH%kБt)H6 Ԥ݁)D@Sv>ue|烛Ce!_tE!g! 6*lٓ1P[ Ͱ|d\w KݧS}3` GA!W T7+ڂlZnZ}k_F  maf C*b$)?PPC.O@r"A,,{~y sJzQmо/4}xucK\ǂwjWL)>U"6x(rF~w49F=^7tM%y* ֎dvi.+_D$Lz^lS$M!{EZ0i:Ep3X* ٍ`d CνDˑLn˛3Fr%k:^]Obb2t_;G nӋ8: Jb(|j>@5! h M-11TC_u&*蔜D;@s+^.C>[]haD1|Fkn0k7_G _2j(OH0wXs ~S#C e$˟H`~`hf[dMс.Uѱcs2e*LE2&{fTe_Ui h};2z TM [>TK iVh y':ظ՘x93$֩f!W~V-A?{O~Xw?SarN*H|'O㝲uVFxVmЗIҰċLN5.f F57l>6ᨃ.lr1!)Ұe?wyxJ)&%!djF_z)8"E/S![U$S&w#kBKNr8Wa=;>qhjM"0dsDA/:RE`AcUmt;i;m!h !IN[V"?D$-D_r' M(P Ws \ȴpmwτcȎ ϸIs/Go<ںm=( ntbC- tME0̸ʗ'igeJvEφ̋*r_$hye{2gviWIz@ 05>8C +:'ʐۆ@S`T Ml_]LT=91رhKJw:f;_^+VW^[ (E{ma,< $WV"AL}ݹQoJbx@n<4֤X$zȖpع)씌Lm袯#VgĿ;+ S@Ə ]9V,A`nCwO z}7:'iL <0JQAXqD, xb $Cw̌ZhQx|)R1hLI) qX.q B6adxed|ؖS4E;v}p;ejh?|XTyG|{+;FeiS hFg=68so|(QlBfit<{΅‘(ںZ RO7j:?#3J__R4riFH*) GݺN.xb;$h%֎gvi>+/O n e:Sto+w5 'a('PfĜ"r?BgTE/Yl:IG6_xIjU* H*8g\#IGE_zyNt螃 aJ;%CA]WUJwQ#H h u8H5Ad#ۡ(>W>@!M; c&`!p7 LD+vd$\o-6F}/2}g/upօ)uȡ_D.!8 ~ `+0ĬVTHb\uσ*V ^yz%IᠶlG7~_b䡋4tz?=3w❴da%kG `Ul(r *-Tz_&KvA+$K4eG GݶղN17(QNҧHMMh) h9_pehtqjUb#_hC-hѻ Z0a򉼓VqVmV*I6I72_}tߨ){amQC~[nDVm hۆg*]bO{#=g䎏5 r=P"$/jraٔEI\L|[ q-3>gbqȾg"]n{]=( 3ṓS\ qMݵ8e-IEO^z;Vh1(8.O=[^Lun=3fN[%kǵ `Ul574P8 kPz&(}5& b$I$ q?!muBF%pZ9D iDX"Q a;;E A'EWȑ&@ 2nEwBn~(27zG#߽ Yt0 ":ȷ/H4BdcoU+Dy5w#K5n &e;Qæ0WԸ#D$"@^g^WfW}~˨H&!0ݣ(2֕+N 8WO<\-S&=3 DV2P LHgOC)Zqj\yH'RIPv[[>"hI(g;m<kG `Ul5lSl?.ۊLxuTE#4PIax*^[>2L軈Sp8U L= zu ^@%Qї 00Wvmŷí!F9eݐ#w"G?~t#܆,awCK.F= t"ןo >xnAKZ!{ K.3UK:8*U3ɷ'>Pӎ4 %(2.ܸu(F^|Y@b 4hqw?A)0Z@z˜-"|E Zd$ˁVj [%hkvg*Zt\"9^0i cTKnLSQv\VŶ[+cP z"d[@Q;]=A#4$e|LLwf8E H{:FtϠ{>䢤q=oyfd>D-->;wSp/cC&O(VAe!Wف?rӌG Q w"܂D :0 H5ȸ.d.@ :Q3=d@KlRK WbPE R  2tT?(Za[OA-goѕȧ?x<|,da-s4q1Zr)0oFyעsz,2frGp pl5!/}* beZZniY%q:Qz_n&hgĸ-s)aˮY;-Wbv<VŶ4H  fckJVwm<< yh"hƔ;% ;P ?s ͝fyB!]vU0bhIhܯ8) 1otO{ Q*Fw<|ObZjƒeuRz-_Bg45)?F:A}maSfskWgr5F #/+7)Zwb^[=r^,5'o$?m c$[;Bثi! 0}1{/wE`C FEm=1 l77\g@DP^' kB۫HG5`krl.9}ҞA@{#G>;f}p'`$aس>y|XYS>B}0u;2gK2s|bd:?udn U+f>Zǣ~9뼔s}sm=4!;W190JZF`X<ӑ8&#ɼ0@X.,zԟD.fze:$f?uW4щp3%$]D+eyH[ʖiN󒔻ɥ?ΧgJՎivkL;[2r5Bon߮xmDR<3x,(m@NN1ɯ}혋TU4 ;%K;aI %fgRB(79dߩH{ATKU4C jH%F)&pe:A&4{7ף|l2wHw#pa#>9w'w݉Mx?> YEsȨ+.D`0sYI{@HxHש2Ԍ@) 1FGr~%T7pxAܔ[O~ܯƨD XxrreLa˃LGCCILpgq4/9Á|*9]f-,k݃;Ubۭ PZ I 3Q&&K,S:^7%TBv \Q-zRbW H*d`0i {|F ߄tu a[OEPC ž0aSb[VArF_Om"S6]Pfq,KѫO{ћo7V!g|qq=30}zX& ,@ LU(&J m>]|t~L]\T7G޹IP8y9g3W!^eQ#6Cߗ+Ԛ(LS[vMo}9B!(UsؙXP :b;j6V}ܝ H@̕mDzg0 O@0(^9*^çI><h%Gi*sal $ݱX0 Aj#'-iнۚ:/`PvGsHhPB 7}ykW X{q9h], 1ra4tzhOZ3*.2PkF"da;LfQW#EE󘎷-')C_Bu%-1ڎfX= X=29qa /}>u}2.#> O?>~ lD >ft A'`kkP\]HFz} eo'^Jy\"V܄.,=I??ئLF:@Ɵ>aq9{ "St9=-Nreſ8/0{~sމ-HS^B۸UR4VmV1Xھ].P$\FT>iJ[ǿoLM&]cLA ["+GsvHSf@mb 7ފ1&ƌ+M]0ŨV "> j PB~IY( |DbS Ybɣİ*Fo^4>9ق udf;=O:- EX~*2cOxQadِ^FW_C†Dbh)_ehߏSjEOrȘPUeWI@6{HF.ɩi~: hKK]#!E[alw0B]{ _cG%Oй4YCbKKN&W\I\Xe*"y#S.x ~˕+ZAvC}IVVI2c[*ݚ˃edtMRhybkc)qc  #|OvNh9(t>ew^`2tߣ\j㣸]V:ԁrPmhg:@o^cdl$0.¢ˍHb7I>:)(h!nQz\NkCg搙7kЫ":zKo"|XxU俾$̘w_ BE<ʃ'!-$P0V^AX q44EK,hUdp eV B@׮C֮Kw8%DZ!H&k 灸e'Y U([THBӄ4#ZˁEYj}LN%97}Ut#w Z2u8haa{h~Ml+(X;UbۭQ儍zt @,e[3-w!N:KVLLFca}!xoTH`:'(Zw.#QdJiE֭E6q!%س g+ !"%-A ]#yA,ĢD Jv4TM KxRZe㱶@6.B(ɣCpP[ Ȕyo_Eh8jdS?z*v ggga˰J%RRڅE>'>)P6Sv2d?pūp?(s*NS H듫+~U+$K U? .<~'WlOKX3I Q\ A'!f3bσ D@uDq߂!;) ªUOA{a,!?Q WG1\:d C7L!d Q#{N n\Q^#P\@h6dfCHeUkCm{g-Eyhg#\+3Kˑ( r94 ^C 7dMVIhYCw.Z=NJ\R#/-I r[- h><0P] (A 8*B jWq 暒d$#akخsjUkTե>zƢAΘN}'F'G"ñǢ<]lcς.2K_D־I+Z ja&rUc7n4>1f5x]pLL~_f`b!Pv֮E[ڒ`tsu67# H H}4%uR %@8(_bx @K{FVBAυ )IJ]߂V~:{&-"ܱXnG @ڕǓ#AYA#u+=[a9f)VuN eH"$gy{Rjj1uf(|FQr)":.{D pHgeP7{e)^~WȢd7n7O&кBT3ja`#OXqA8JjBtb,JrMCȞ%Js2*"\>>yw31zyj} zO=&7i=  @Nx ry)!FlW*A;Ubۭya.N\ޕ͆;ʼn7y-["qAv^Ʋ70n:~$PU"!16u^xA":(X*12hW@>N{m.^Yu1bzhWj![#Ԟ\#TxAiPD[ R^JIOdZ? X~*^3p*8u :@V{ s'7=ӎD>t(菮wC&OCo2;'"c'ٰ֭0C4[d FI/?~K&EBu IDATXY.ϝHʗů9N9[M6PHlBSYp>NG{9; H.>h0߻Ƀ@r,?%a~k9)'Oہ >AGlK(X;Ubۭ% VRMCr54a6IIn(8?ˀsϩ/b-0qmq?&1j6U?]*+WhOmi*U 3}l㩦MջR [?ۗ|x"77jRK1Q!EH#y]uY! 87KChhJq7Iu)ltqT"Яdk{42 O*AZfv䅚QPU )/6$v;׉C ueZMA\[~ƁJDSFA5O !!LD bXlCC޻<:,r2`$ddX&aH>m@TۙY# ]!~>'@c$^[G^ۄ BGr0m45'Kc1.dךQrdrmF9ÖU6, mr.M * )b3g#Hփ)rM4^\ jc[]5D>ƎK8&U BI;!Q~bf"rl-61f$d mh'&Qb`oZ†ߣ.NMlyRN >` 0疔v{@VJU{ +i"Zď4᳢StNkX Ӗ+ ֎hvmbL6C$)6Ρ FYXY$ O߰ ,bp)V$C,RAl~Xnt2RM[' C3T"dlz!І* BZg:ƈ1LÄ9oY3\,9'#MlϬi\ZQpu2qsnPdi T! zЧցƈ%K=e09^YgH_z)h1#w f'`B~n50]&;xW\Wl(VZ ZUk 4j$Qo)6*Lr7V8$Pe `amݥVS6*\BMxM& 깪"Ųdh̵urВ|+J$ ~3Kr7ߴUb۵`"O;9*쯛C''I &-k!BUQ4k(.!ȏE7>4.)! 4vߡ0[j@vw݃k_hoA>'\<-6AJp᥇a烕(v`FO2f&VB 4dkD(m[P :&<h4"UpşГw1e*1t4BW;,N~7*%s{; 勐"Dq[`}%Amش[¸.d}*QIρ%"TB7ɕe:E}qdf,ViF7Lq7NmtUd'UA :L<H@+BR/i9\ -럮PR{r@IZ ӰQ}q6=@֪W[ L*ײ BWl6螯2D!J.P; mn&'a; "q\T*R,Q( R( 0Tb.$'q5uoiXe<LJL'ЄGtH|3QC܅#dyH[DBUnC-S#bY!4BqK) E PN O]/H)IYX/ą$g0! #z0ZW4lRd3N涛sh;GC `2@886*J$qRma|2d\dCÎCL\W_3JTTj1J4 A f;}.;鞅1~̱x7="S?7z檵IgM/oJ}< :f,ʵ9;8ɍM~+I#ê{rwɳ@+yf5@˫jQ[oh Uolz東J*1Xۮ͹]M/eGI]{@[-&Vһ Mv }($+ ~ǖЍyh0*I:.c&#<Ybg < Q!"&ԇrGC2TX+^UCLNSYG8(1C]_ G#M q>J޻禞Y vKj0_/@%(I^%u($h!.MG>g> ?ElVQv|VŶks.l.H^O53\,}6 !m$iK并}-|iYʵcuWIG 5hhsU00<A:O=;JET!B.g⚢H2os;`8 jdK%Fv&fP1UO$^I'סF Gƽu;Bou SցK'lPs߈5B[r 0vVRj@(]:6u9xKxMU'Q v> ꟆH.їm{eDBw2ۃUbv|VŶk+cT!k+]O*cqQ;S)۰0J,V UuAZ76͏EuOB\@wǵQ,HLtӰA{!o@&Ά?>`86nU1U&CFD{'~l؀bX~q Jdի :15ePe(&~uB 0p#HdC]X3 !ȼ&Q쮒AyEg3j&^sR[/VjEvf~r,DJ)p Z)-mz $`]c3T~ B6lڀf>jFE+-ZJmdU]@; `QCNUR>ij!NR? .R.TSݎ$pZgG95=Fe_gHS{oSm?̸d{*fˊZ*]ې}@F*pFlܙ Oۇ-ŦD첦KH5X:4Z7ֻ&TQovF_@6>vMN%. ҲY䵇kѮ9y A ?`kXp H`v < ;U1t:XC~L)?{ocI}.gFZY{Uҵtnٜfz7E$4 Helfl}-"nGY^"2"^faclp^;`n._V?Oz(>eOÊA 4m >}OC6FּUzpo]3ZxU8Uc_:ʯ>W6\`3O0XF@2uץ=ف Wbиu;RQߞb!*j#R-1'cć1Kc5_ѕ_@Q]ELԻ"z!wؠ~3p-!&G n9Sq-}mE(-bCɥdzs'|?¹H!+|֤|ۼ{\%Ce.tr78^~yѳG+xU=@c M3E _}5xs@/ >5 W-0pIGZ+nY_:q![f~i6<:ȑpj7 n::U}hMΜK$[+F~P _ s Brp~ oi4IOd(f}$փ_n"~$*V-( 堕z+X'S)r\3` @%s翋>=P7h鞊Vt)ڑygofpynd[r=PI!+R<ŜjU5.Uo˻w! *VAdx; \yYy0M:&[Q3@^>0.p_Uili&vW]ʽo~ w.pɷ+Kє5\cߡˠ;ialB.Ej)Pi½Wyޗ?AN &-)mX" o%Np;1od: _r)m's@ohGַ ݼ)iH SB䟳gV?Т,>. Cpc^搒Oz]P)N${Ђ.i:ېVtt/rmX V %#A K-El|ޅېqV Z]O%ZElO0 n]#X}8;,BWN_H}nq+fϝ7<_6]p%wGN{cȶBi\>?,Z7.@Сo[`mMa(¸ *,/A_)|y,˴Nag _zn: jc1 wк[oC Yq_SZm+?]6N r5H/-4 2gŇ[&'*Fa_"_B?6V;P[%E qZr1B*Utd\Q*0~-<{Tw nWrsA}<5❻H/s).}mM"-aZ@hmdS.>rj¾ch7ȕ o /?>^@~8l×ᅨ>re)x]KNL_=vяtvq5EspIE^.ED_e8ZS轷#+*5o~ ?C&`Xx,WYAl oIpRH3`w[\(dQC1X>dv(>.AQ'$ V6#l#X~ȹ%={ X[ҋ㢡ן+Z$1,0|?ޠjgǯ:8q ˰}%| ;?yپ!2L3ilm'Tڵy|rx8IQX)x"-U ;l>no9t IDATuhFo ם#0>Z;/MwU@ʝ"m|..0#5B̺n?|EVW;0\MqsSRyP[H=qy6N?lJ`)N£X`a*9T}'UغN;dQtD\Dm͗m< *qkQG}fz% H!3A7|j;T͋Ӓ9$πV~q+QpXRVy"ƶ`-l_[r*Z$%HH:[HHyЄ^:̅Z/n.UU5Dd,.*M X #T~!Tȱ7~Gӷ}/"T%|ܽaWiVG }V}^o  Owvbt.lE6Dy[3@@lBK$+?OYDAs'+{pm Zؾv+̈K]E h2lW0iRk6*׌֣5Ku ˵%@VtͥY#9@a^;s?#fA'aF,`vțB=siX?N.#?yx]/;46l_B|ޝ_0#)n;ktji)1ې Xۈ{I! D)Pԙzс uK8(yY9 aLCY -"xiNjP7$U+ gn_uq߻uXGcSO>> 턴mKAhDZԦTRns5U/~1/QNr+ɖ] cm;- lGSJ9 4e l7QӼ1cuPc Mc1>u?o]y0Ad+ot۫ZFU8~ l;x׹C/e4K8{?` 8m!vSq1Ѳd&tv,B!pX D!c Ug`"x Twk2 J)TZZ1X$nXwu$*뿁6N@iL0Vε T3[.BІ6gaK"}@ƴA\ywg8{~pdƶ`-l[][PV3‘lZ/p,Wֽ\}qF m:W͍fbnb5Mlc8ҿo"O=[USۂ1 ރ6jJπ unG\exhQ"F RO3G@/?A&# ]h.9}7|-ZmV"<[ԨA9@N<ch[QR3yMj uUfsiЬٵŲ{#YdawB998pIkhS^jVOԭJ?R$3̀*X~WXZ+Y6}`$cg[z75;z!M^iOߪYAJ6f UWrl\mub7c;F,c@*t^?&5&dx1>@zW*'ps|oٶb&28B,TP)+ ĜTḓ~)*RB,ХHڞPLu@@6 epn=: u)nn_N2E߂VJ|ކ,V- #e ,:պÔŝ!'T56kZK65:ig8qf_"a`-l[ Y#h0J.-=~7x>҃;D<>\y](idtr ziF`7~g?+iNM).ڸ sL\DLwc x1h6n|$KEm/Zu$*&sH }ueB,CI`V,})@k ӌk29BwsVyJw#yj:ޘZ@J9 ~pZ/.ismEK]߬wSx\[-ka(tHs epi-uy)PAju,XV,xivՂ{MUq bTHvG쎫vAbV VdJPQ^~)e`J@z _;8q{Oݦšf!FPS!2ݺ)T T*@C bx˞0-5}X,ͶWM.M)a틈 p9d L/12-ۆ8Z1k?(-v~N^?fp14J1O+~* 抚JG{&'eYKHqʣNl?ډ-ui /RbpqpIq>D/[hFPv v'# NQdi t8MbS90)w &H-ףw϶ԥy.G2f=/fU "k_D)XsUop }^nQNt:XjT֟0364-j<؆t,SҍȮ+ġ=cu%R2_l}}*E `-l[Xmۚ3E˗ VB*=^˛!Kե@Pm1TN"(~{I p *|tq:W"RT;OCsS*F\@}ۗ.\:t\7; f⁠2A}iF-\1N*HAϬh7~vF-E*5/.MNҸBa {sλُ!\(X7-karZv=ƺYk"p^3WKq:I@6igd9-67ų/#Xmj%9*ݧ` J: Ӡ//ƨ*jO Y܋팗H ڰj-5&#NU̗wP1@ e(2'~)j&]괥YsCK *O8FcpTpNL`+w SpG u'wk>t Fҵ4UX^inNh pﭩݟˢMjaiyZ$irξ I) p<3ĒQAfTpD>spƌrajD n(i1%WyvAAy )!+8njcݚj&d+F)P Z==@K?cPEpU*܂HZk=muSu>;\ft#-HԟQŢCK8~Bӿ3%H0+fJ2 u(VQzٽYM cԂ8@cY HS>߾4* U5|G[ҍY7,YE(U]Nu˫fog^iڤAKM \yi^qZP ~`-ض{LzqZf9IK0WS-=7ͮ'0ͦoeclKSQed2 ZCa*$MJ(?bmJUV]fm/v^f:mPx nکnW)1|j` Q3@wYB ^c᭓*6h{ecQ47Q5%]Ǖ=R!:"EKʟ|TOvuf2vwadA' C;𕫔3s KN%HjV['y{֦rZOr,laH[4 Lg!aiPtZ)f\~qy7IMj7^b#Ax\]drdškKLQǎ%'BIMcYQ-P[`Mh 2rUv)jnGd?!aX`cjHYxҩddw>@a]o)}qoeP8{(ZfZ^$>6XPBY"|sʟ|76mCڷ$1*^H̠)ʆeڻז5$-_z@+=JvLDr?b?ZW7-ka>n ֵ?·ye>dۊE+]83B)nk}};\U7Q[f ]J[c٦iM['M)UF lS0>^%$L*>Oo!F )8g^"@eogeo봫2qo`Bl,uSu<)᪄1`idiuhw.V{ A?+samO Mi|6 '3UfNay[¹k+UU;EC?Dc)F z1ڿ!.g;JќI=SI[UQP4>"}YWS l@]6F 6d4ʌ3pF8n_8-2 W 0N5EsPSzZ:+1KtPA>{EZGZ 3(Zy%م'֞)clW$~:>-ghr/J.½L$1?aŒ(oru+A'"cʏ{oiŎYPc+W Nqm+#c|_\AwU4Faę asPhrmc>g&j(9i^|1AL= /x<߸?1qfԝ?qLfTi=bZR77ƣ\fC]ؗZ521 YfYX6{Lx^LqX8Ft9Vw,o<'?^ O-R4[(X v=F&qsoZ噻_ 4Vf\0Axs0M%:t[﹅kchSvV]&)h]vP5=b ߊ*0Eu \vL/)O]WRЗ: Bu ;#A M ';qelSS3fwwE ]7\h)Byֽf=Wzx^j%Y_ڛ:t*Zyf{2}[a"`-l/@0ɹ*@V:f"q(I@V̮, V/ܱD gՂ=Mnߏt'8qw%ր @'Fc ?hg-DD Kވu-0K+cJG"O[bmdGL1_Ӊߧ;d0X)";K>s WP5A.H6{"Ǩz=--WB: {7=m^qL'[YvA֕q݉,dv›'4o 1Mpy AO&#B(eQ&B QG}"M޴ =$xLG[ Fߴ@ pWѺ:haڃUʢ_`ϿzW@\ G p[,;1%_*o|3kA+ԟ eu & xЧ:ulv\[-ba)řnV<'לcsP9__YLi182 mV2ݾw<+4SMI}?c\\xLi1u='$qMakv,9VZbd3pvSeBeF\h%;?wCxdݳc-n!qoFۊlw3=ec[1iC_B]s8w%tl c ka~.½,wnɫ7_YH:);?Sҹ+lxekZoW;f\8&(/ʁ;-O\ԝP. JD37wͦ1wiӷ+vcЍ JL1JJ՜`:K7Pk1Lc >J حO|sR4>Yhi*CYS$lOE+ރ4^B^ܕb(^Udx͓_g?"蝻ɫg0q3(-_Y5%Y-QQiuP>s$FxK6q-]Z݇LJԔ#Ss'Ap@ݛDhhsa mȯZV_-#nߗkKP=)"\RJ]ONkʲSZopj*e456[ʄm6esw~hYm#!^ mNyg2S>ZXV@|w5ӟ.Fď4]@E&曊pqȮ~5E+5obr-c Z؁~[ѭdIZh%'_m}> Yu+֐-/]agw5堕܂v?z` [JzKC 3UHH ,v-HսXX(wyդ.E`M- =SWE%؆~|Њ]ӂ$k:B]4tj!EYbڀCey}gnc Z~ KI.$iLR- ]ΎI+Mb!*WC.4j!OEa6x q4w+rI13Oy}QIywEg vBZ9_j @u5δ3AOI7<쐮 s*܍ن▾*O;]midRؒG7)N\1ޛ#z]++wK.…uv -~AQ?LImu*<锬hTD*/E1{aihiK0`FQ.S=LQqǹ>dj`z1l]hU@+L4P[it3Zk$]W+U^Z_; SkY?1h箽gusWHHw,?nrc9@hJ]Ov锺vb"q" t`~? 岶[ZV]? (eV1pmT' Iy}rp]njiP^p2mokLkVcpN l{˽5_f4ht˗?3خ;۴'ajK''k?֨wS ei(KҚ3^a ^Z <Pv ,,`'YY\R'G9s%]F``2)Pz=,"L]\}Yg ͩw~TR}W,OǷ\662te݂;;-wWJ~!EP bNSzv${ܗ06.?,+O[YrP7@WF:Y*xKR(Z[5:i(5E)Tn\4ȝk~ bȀڿ[.[3Yd-j@V EYPcvv4P=|WSyNAEe Z؁z₅7h1}257^xYYbix$E`#G[5 #A` Ҧamm1nsre u 3S]䪖dCƃtZ[Js ZE kiVf̀(a*f "[PWJZ]h !Ӎr`+yۛzKAulX ;V*=M#}Cvl <ī ; (+S\l)y=dEQy6)' ; '*MG8S^-Cct*(.zw "`”XM<ϥ5&'ڢbܪ<X ҼI!v]:'R3.]We}; +fT|桚(}nŔɖ[r=G3bPW$.}:*V8؎PHlulX ;d.MY|{=SWK dmCcRBg|zwFzIҎ0 X<m Z.hMw ΁'= -I"qVr3f[5 5ujRa+Sc :.{]']GD8X4Ԉ1 ,}U׬b8ܠ_ Ε6=: z1|_}O[L66na؟V6*+1 u1#D⽉@+?nOu}7x; ;l.n,|'D[/u)(>F 깲4Z?)*UBYb+tS%l3'_|I[} aGk=)C*GzMXP aNIOʊ[o .&70?+V_g6&.emUmrmJ>s*Ii(FD|c}&l/˜ci\ک1"gC~RtzCBۦLݽht'̹?/{#Ǐ-۟\ BZ؁Fٕ=T|"|NzD eYP7cƣm.ahIC  *ml?a7- qZoGZT ۗ\j&h YlPشC.ij4)]Iԗ&%ŧqTK4s9ZCϜoQ>}:?|bp*ʘƥLPNmV&sPe5M'#ع:=v# erBRPd2-eR?r -͔Z0*L#%EQbUjm<s9R@oSBJ/y`~lX ;Uvf35΃O3o9RK]ST3fLfpvԗT6y9r,'7`0X[Ba,( Xc{彎:f>AB V']A2 f 3-KIuvAd^N#T,Kf6C3 Z!݈t5ekX*)ml.hfyl>N.|156~d)B: -Gnxd_6o+p&*u= -mcALUxfIY]9)p z%Ud?V󺒖4TTvܗv Fz\?]Zp2!3\̥°E%ө28(],tz =mԫl4f6آD)D+WU6fAO!KZN>AʠVՀ|"5pϥQ KKK$K.…ulX ;x:7 aKߵ4u$17߱Nk4B~mSUe)Ǹ02jOOV4f"U.wM`:yl[]G,nm޵v)&>"UhS$gC|;)" "[I1 c lbye`e n0tS< AN A+_t/5\Њw¿xs܇:[+jag7{,Vp)}-h7m\8+)C)+>mWUekT>pg>h]mEPW[X+ZԪn{ -F>\M ) oYu=F8%u1cD6ӵk̵abDET;NL3%[\tK]2C7)ˣ~Z ELE2#v7p5siA{\Z3f`w.-kaƜa(JA]{ea^ڽS~R@@S[vPSJQw ZA.֖c /45t '˹jmz ^qHW Z90ah qoȪk;:oeS҉)IkԧІ~ɵMGh{@Y6MCQ Rpvp1S2N.>S-*i^e9`i E7Mƞ-_j;~mm4#^ O];uPшˉ%ߢщ)>ƚr 0EKYc*PF1EhvaSO]4eI=McqvJ|Pw[igU^eMsmiB:,8!WαdA !îL5R~S224 MSm}Lx黯;cT\tJ=x̍)[4q `18W0|ra "&%SD,e0i,w߲s*zoeHs?f{ |6X[U65M36N F*wdeR-=NGz>Ϗ>l)u]äCߧ dBS71ĸ(Wd2Z㙮ZuH:#j'hY([QQM1H,?y~ִ\T>+wUB,K%0}eNR(`AFuԥNXm(lE4 Gs\sA˗ZX^]f?"`-X^ lea.YOVV|`~o S(U&M2 ΁! c =H2bڈO W׀^s0Ԁ%y.-In`1 >Ohꉯ4=-j%W jV`TC/I|\ъ=Aխ<w1RZPV|\kX^:`^o&o_-VwaojXZ_[bL Nיɥ+Yw(ωkmomXݧq'PYKTW;re5_c`[4*u3)Jz6B{i V3ޠuOulX ;049D VVDY")Tm#ׇ_}Uݕ>i2F|}4iJOOfAAG@‹>qa(Jάނ1«_.7I.N}fQBVzȎV4MHѢT).<ބt@wd&v˃_g_;@TwO|M\9 Wbcyy`*)Lŗ^?9 kG~~O1Xc)ᴙd׍mjnXA1*hn?{~ R {j4ڭ-ls 8qn3nQxlh^.x>duiã >UEg^:n/SRr(*F3Y̕ A#Ֆ"c^.=IgUf ( uW>^?,1b-ma0Z;c:}8n:~5e e FƓ n"¼ꦖWV4G ~([9v ߤS4NrĻN|6̷ rp_a4x|Ӎֹt'K &K:.&I1Em#c(ܽƒWH-uDă6eFKOffnb qaj#(NOL(K) +YK6GL >.Ue|[nۚP9.suzl{5*ԓy_\׊J `8v3)U?ɔqIj'0|1]$=4o*X$qIvwe<.u[& /|p(%߆{뱻?{}I;Q#vw/ɤ(z8$V1mಗxd,`-\c4 Yj+ Dv[& ({ fbx!BaK*pr~>~ZKUU\T2*Ře̚CQz,l3FL'cтvW=j.6>6́z37h$P(E6~?HE2OOWHv<6o^.E?!鹢NLlzo\پDcĢjQ(,S)kaOj2ko 1o} MգVJ/'2HqK͝(}|4lxN'Ř4nU_uOt*0GLc1gSfe֡-%d9 B Mll7qLLD\NL =mlsA 6 $uwU?\?2(\keV)o}t:Q,Pt5gbc~^^RCBh)*XrhcW\U"?"t6V=R6@*9 ߸8_==Yc$|#&oAnuOu.S 4IRAHxؖK5byeWPBk|cAhUuMpc *9l:AwH =D92X^ܕlryb}¥: ouirg!gSi4ଠBjr8v}_"Iۓ H4u9'b IAT[t{8^We!iRJ tdYt0;ׂJѤu^X4S]s$Z5a'dS !A(m{2dIZZ75Tڧ>L~SQ>_ ~s!W*XⲌǍ p'B7*"AEcV(On߸3cp6gj|Fl3{z^~Huw]^ !ViVI%Ҵܾ4<1nZ&q-2l?>:\m_r#WnºΑRQVЂ1KkXjvut8IE2s [jVxkݟ~=g>وMߵ-#+'nĐJX#Ť`ՎdJ'>}V4G24![jWxg9RnɵQ:A.*#IZpt)Q]+7n t }=/o|={ͷxN皐!5y~h131}#O4AqcY& ƤTUR6(,qW}`{r^|С'e D‘#, υ9V)Zd2ߒ!)_#"(I9t/E3skyMLD󬎅L8Oa ċ,ECF'Q`E$s.|mƞCoLMYr;A5ʂcMCK/!Ғ&0)D3Z4sH)&{6{O>wA#NV$ lRFdZM]%RjT ':+#VWg,ng2u O`:|[ڊ}]w?IֈP%SJ!/ 'ۺ!Z棓OAp<5}7!Yc:9wP:^=dYxCIdD9RXQJ*`Vs~FO? }i u)y+v> o =eiIZ3X~o}iZe\s6&:p igY(a%H wX R]|'£'B+Tmv[J&0cКEN1Q9ݱxz?u’$f!/ QSB+7i\< 4u-kȲZW$Chorj֞~GQ"v:qM_  [_~=w6{˜%ϾMI)%X-f nN3MαBH}xGsN$Ig JnRjy5Rݟwn uO=BTTv77ɇ!тxzOY[N6 DLfTkߝc=c8VH1`E֞p/ l}_y|=7 vLD8`3V8?B|^ɸR2&bx7x}wxokI+y%x9^ '9I؃V+~zָߤk^qKYшb8G|YaxqkǛD) R[s>|ȺBEN % ȑ"T #>fl9l%hkg7+^x!I\@7i2dy FygpNcmMY¬Ť d9XgU!M=`GJIY Y.+!ki, %ص|Nv|oOΉ, r,!$h[THax8@N™MdDVsY{F}67uMUW[7ۏ3t*A%Jb%{!=tP ^d08hxz^6 O]0G*FuFuM랞~o.7)R5H%X_3w3mMU U5 xxEVo+fX.X:~D9RE`͜ J;,mnA(˂cyW<ϟC0O&˥ Vň~7 x꒲R}^/ڏ9ώOq/p!<pnΝac,eYQ9E1s^ux/?8˘ ),I"C@mL֙Y|u3|]k3YkMh(eG"fF5{.,!kLkSF[ޫ|5c [$4JkO:\cW_cyz:Sh$ZgdW#`ξᛁ뒢!e $Øo{Ǿr ֆ̰t [DDʾ}'?;qwڽ3ZeD% ȑ%·K^[}sׄB!`96?$Rj5XW&4Z6yE/~s5Vɲ.R_gw /ɧ@)oCsBJe*_hǠT\j4KkXjQrzZЉ@_+i+h{V"㸜1o ; 9q\ꩶC5.-p69aGvy,/_G{ 4RjJȲXcڻa.ug t{\E{UƷ4T(\(޻L@!%'Xchde4IFRJtNl{Halׯ*K)Ly+XǍ9YX`©no0\}yQwY)> ;ws2 ʒr̝>7H[a`~" JacH5M&oTc{O]F/a}'|bB7_?xDSTeNY3CYXѯl qFrU|0O:xuAucV$N.:BȚ #KR}{.)PxBT@%ynJn,:=vDY^#ku.:N#Q`Eֆq=2?vYjۈ-B Rِq$ %fԲb嶟wcI/p{'k_2,M.א 3I(=0-J|372dqY[QS`)_oWa: V1~ragahMwNيҸw'}:$)5RHN;zDCU(9xX <,_w):'HNp:g1;,uruq;y|㱧vCG ZW:%+9^L~i֔`c,U)KGY84Ø$iܓR h :$DCUX J&s HX#FI"kʋl =G?F FHrtn=NS ZjߑO}ވ-nUFFJW{/X޻fXtHWB:7k2iLe9UJ"g~z5Uq낼al-꺢3vTӽ+j,5y^ukR)҈!Ǜ("Gk-m>ְqUE Xx+Ʈ"+dD <kj*u,eAV!%7޾?k7iSK@)R=DVV) Hwko^5Ԁ%M%I %|r<9 Tt2N尦jb"x.-^J "4̷x/b& ȑc\nWu(5aܩE]>`rnPH-? o" l5JCQ 9xC3k<ԓ%j@}%g U5Ę_:Ƕw}|/{Ϲgm&VVOT)ZګdYW8krhFǕ7\kGc̎p0$pt]˛{SyU(>E߷$mAƖ$ړS9Jxs`|:"d[S5%ѐ|4 3!U͇mP/Nz_]\MY$x)V_ʛU+XǛXMfm# ]ֱybjzZٽ:KFH!PA<>â9\ E5n$uljP8jaGB{8ܺl8p.T0Ml+S )&GWуu+r0&|9XϤ" *!&ޫK/%f#0飼Q(uH%!"7yo۽ '(bA]{j-ֲopL}$itwSR!,IJSi(?Ob& ȑޔW"S)M'BnFc*67161 IDAT+ 1դ/g>-VWoD'IDN4O?aDFhm*/k=<ǟF - +Mѹ Y*w&h4V'W؟c$ri E,`]1lou.:j"]SP 2F:7=7L~ 2nB47~(%y}mZjpkNG7霤9ELŹs[ȃQxoZe9`wk+L^7_gW4z,lu/2}DLJ`+=^YldɍwT˽Ԧ(z`!kwAIyR MmQ9RJno+EVGEP!BIfy?ǡ [J^R"wdeؚ$Y:ܝ`#H}oD Yg㨆`4Z{^ynxbգ)<; c+D1iSR0 WއWkIxD6afk3{k'E9 7)y>^3[79(0rpSGB pW`1C1YUd7ϡV~?ʫ֔HRux\ 3R-ҠE)s5Qw$7%5Ԙ{C@*R8CE 4!Ք V58[QR\A59KX#yի+,aY"EQ ”<[9ǿit)"X6=֔ Q]b9Ѩl:,G-tFCh :csXSaT1%{*GJ+9׳@' cq@w-fכ 2bXGt;.z, -UXW:Ad}Gl*o HSEao _MTN!I6Z hT⽘{ﰶr y,(pq7]j`Y]<.V󏿀V)R"ԕ%IYKSo=<2:,װu97&Xu\RRuеfy(Q7v ||iYTji2HbU頻QØ%jD1H6}y?0k)>u#F*MolEx?I+[&Noh\ ᧂW^:5:!%fUeX=ޅ7ku:ߧ% 8HdR5fdxaڛs |3+@術mS5.?bbBbL.J9,ER=֨+˟/ Uk—5G)t"7o׏уu\gn}G.obK 9CY* (Q,Қy6oùssm[(bo>]Nx)I^Fph.$i4 zc&ԡu09),͚@ c*$,HeQYh_t&4[:;EV`͇8Сr%GsL3ysn!e9> O~q5uȆRAPqkFʰ)5VEL1uIz TՐ~,u aAu^0F!:ɐJ+4 E14w[sq% _VYEu`{ZoOj |!#e{Ty1sv*TKxv{B%mD%Šɞ;ˣ͐fP)’ez*a ^$8)CiUE#I"I2dṶyEYZ’eQ cسX/5T>>ΛU5}~XZE`i<᷄ɸd^ 2=o{ /}R#H|྅>>B=($l_##I I@)hT4U_n&b{; F k iڢ2]`!H)CY1NVkbrAǗ5 SN>V4k;Q`e&ϕ:Ј5i~X[Q8 cr+q$EIUti߁cH0>'˃ZCYj3y\cRVpӧOdtS <О^ѱ0U(En;{ˌ˾Cwk]V8s$IBY_O*KHc쁍"K?YI~l%715tFQeu׾_^ȞIbVT`E~ew)bj`znVB$XVeD'$Ck3T N y V|w v{! Ԝ߁u-f`E 4Gуu1 kpe!1aB5]cJʲ T1de+j# 9d֖!p8g2IpTb:QMV`gforn/}X0XQ_]U쯳0pD?G `cJsL3Z"%o\^ȞwYY9t:hWh)f?3'ISԦĻ$V#sWlq V10k/s/c6қ_dx@a3pz6!S3o{xtOAaat*$cu,@Jj~7'{f4mK=Z;$̊\X,K~݈XGH d[|\͚ h 'O *YƔ8gHҊ7- #$I k xo i&t>5Ǟ=YRF/I"^$ l)+rD [sǰ|qsƕC i*Ȳ&ZpvU~ uEnH.I6Y35]VUDu+rd;TQ`]Y8M|qe ?be:Y:ABW~H*DJiҒSr$zvOP%y1D6R"%k9 I$]XRX) Z1r%$Jx\xU\쥳psy1t:8vB*e k=xK_]AAXQs:g4`8,H6~( xe1:juwb _hr@`E0N$UKW+YSV6p#shH@WB(U&4΁u؃fd, !J)ޙ80"\W$1+XW=ͷ^|Yh,b[cmHu֞V[$ӿ{Z;w8gphg8m=Gf#]h&X[.ll^ʼn+kq1'V"GxDx['r%sY, } {4]˜ 3Lbk|a e)d[ ,8g'0@<_2t 4D9 ^vToF) rvӼ7xsn9AJrss_|xkJSAs`Mפ pޱ2^gURҌɉNX#u#X:\0.TS͋?G_{\ooཥrTk* !RKe|7zH.iDkn}HG$Y!1B`HH|:XQj>sX#G9ځIɶ㨆 6/|n{y׬wRVCóz뿰q~ %]x\s4щdֹ k )^ ʲqcρ+X<3NKwG8*k{ˋo =O_XW!fy`kOh58gp֠Ւ @ XK{[s:sgZ GX`E$cVd._9ɜ au<1Ktd IB#@UMجE1Y$0D <226LjHX#˸%سyItFQ*i :0 9E^eYw mqS\BLa61,,Vbm#«kk*G BPW#jHoUi4];#Py|YL~b@]H㽯:!sÕj_%"ޥIq'+m n: 9v>DC`qP9y>$χFzMQ<fƻ!B~D9T#z'gW]MY^\/f~8pK]*#@Y^lh,u:ݔJF*VSډP* Cd8c~Uv^m" =IB\Kښ4VKMDSpX >G98*6T)KVK:[En]%l/=:2<&MBbL >UmI9̬!N]XqF+r,) CYuy% b+I+)˫,_&U4a.,S"+u8gFu=d0 FH᝞K詳0ռ V("~/x'b[֜<\dޭh?Zl,Sլ*eY{OUp"lnZA[S糇fI֚ z)D.,x6QbJT2WuÚF[GIge cXSC671F`El di.FJ/~:pR8^ }$2kFÚѰ_R啌rR')hX3{1 J @%9CUMaC8a~H6Js ZRVKS̱E'aLN>"Wiwme|g|_;sgbgc`nZ(qq [խab4,e[|CsY\E~yw?#0klu){ $kt綗~dDnBQ*OvOm/dY0ep h7t~"WEa(~1Bukr"V:1 Qb(0r "+̂t8RCjS"B x^5}6 NhGY[ RкE6WN4G9pȥ3k7v/{ً ^o3D|{%?q~u^ai5eW%T|;?,  G~ښ@^5wq[>e#HHkw{(1!8HG5h qq En8wf]IL h 5~VYяupg-VX[\s5)!%Ia`EXpr9Ny\7 IW$ItVNt Qr"Y~\`{RamM]SQU9JyL!;\=# ֕X0]J@Bd@1$ I^CGq9?#(IDAT/qKq~ ~n?oFw2GzzZ5hUښ.pb\\1ٽxTxqnFF8gH ;ǃ WUk劗ݮw~"28& b9%fyͰ_a,Iv,:H"Vxw.(x׈-)%x^UElqU H2]JSEg9eDFj'{aՑ%Q4ìׇ8&5]"HӤ[@|^I{;h(mR(66v:ԉԱ9.%Q%>Er ^}b,ݳQUUGBF] ׿~w7%~VNf`7|AԲTZD*-XizEN<X)TCX6Y2Ӥ"A؊ 8XZRR-YԊn=f Xb,~h,"dJɨng#,5B~77>Et9_&t\y6T:<:"lp' XDZzuHF!?ث[-rIZ1'!ktrt ,"Z+(TD1Yޜ{! Qj jECQ7+I39V3,"Z[-iS2>1)t6 9ť+2Zzժ1&E-/Nj |UGA;VZ! 9a"`VNFAIY@TAIPzj B|-3d -FD6'!YNNh+GA(i"")G!#Q^LEmp8qQdHSŘ11`k]խʅy(QČΜ(P-̐B_!dD 7" VAtfɓD䟪BUmQ) !]L`oPݪƙbsbu<0z WZ6VJ.`BA`y`a!QxIY@2%(JYC< ju(Y,6,")4m4g (2;gQ!쮄1 PKơP<nFmib|Ϗ?h{2=,"u=g*9;n{dCUmo~O?fZA|RBxdbeky)\`-EUJg&fcV J&h/(EU*jٕL VĸLNPH,""_T+:+-AaRªnU+ѻR v%dw$.+Bh6:Kڻ `""w4?1FA$SA 2FA˚ J̪ ;!\G×pلVYP8Y F'agO-z,#Ί:і Y5ܝSomnRRѨVlNzVtM}l+Vܸ 'c_f܏mߺߺe8O_c|atP8t6Ͻ뻸l R<2v&C! ]ɆVo;wX.V/ [_?}SȩQ.'ޭ㻷d:o3 ߷ TDrJ:lNVh,-kWf\<@͛_>t6"O~Re_pwۦ+䛐Qdr 0` J}Պn#+p1b.'͛_' sAbZ@ 9NrQ<-Ns'"f?Lh=Bupupz\`T?C<o߷ߺ([ۛը 4jO)a =m#+Xoz}r /3j97Q_p٨׉&mqqƽ[dTuuΩ|wx _?zz̋ײ֟}MYb8L`,=nfou& 9Nf}:f_ܮi}ns-i\kXӳסu{F<{x Eai89 G իU4ݏiFͻ+ժƎY^!ܼƟI`5Zn{hGᴁ ϺRFOZr4f=^-N?x.М^Nj0ـl_Cp)En"XZP*jP:굖O{9$>䨎x {Y^~&OJϥcɑuk*XӞ> zZhZšP̟Uj]ɪ ɊQ2uOPJ3&L)gyEf4󯫽L/?w}~+ S=ls>~i2Du^k^kAp"@Đ7eղq÷VֲQk>r:nx MNX׿7vg-c"mձÙUx"x"It;}pbAC1XjuXhbB)EDBhpa=Xn^}nU2md""k<9Ɂ19]VDIH)D1̎̎^@:((4T< pޅv$Dt6""akňFB#ޝ0`Tq㶳28pu+Zu}޻<.¡ Ԇrj]jrF]p2`LTqlr#pEvNǃ-O师 ,dr3S\DCga;i?R9`#Zv8WdI嬌WjZa]yV!kpwj+էn{{?X8<6"bDBAdRv8dIÉZJcFY m~1#Lnڹ?qYY=w9' UU,,"""xM N+de yv,!S 'G/5$w8͝=so3g{"$נ?P`?v4Njm-9DDnyh8'ՌZvZ>g4`FDv" q[E_&&I,b"Z+>\蚈܉h]rsk"n XDQ}V^Qs" ND4-,"o`ȃYZۑ ӎW`"Y1`&/:# {&ĈhMNM)7h)4UrQuFafUU?" XD43""g XDDDDc""""r'4Y`wݴiz~Jx6۞i_.y3}D65fǽi{-Lc i.y3}DDנ²G/b[ntײȍeY*W.<}DD`fv = F {{nhl\ZD^< ^Ѣ9\ȋ {}g""/mTZ4.ƽ<&mQ p,IWԗoD+"Zuy8OnY'ؿ0t?p,g|/gLM3AI^FmG?c6j7|geb2S1ÀQnϲuMaTxr_ev3ba8i#" ܾs_]Њ߻@sױߕ&gV+MD, XDDDDc""""\EL1rEDDD1,""""1`yc XDDDDc""""<ƀEDDDF`IENDB`v_sim-3.8.0/tests/exports/map-3.7.png000066400000000000000000002777771370110300500173160ustar00rootroot00000000000000PNG  IHDRXXfsBIT|d IDATxyumV,`H\Eʒɑ#/"NJb;$y*r=۲8,KqtՔ(nb H,$6 H 0Vݪƞ٣驮u9sO-B!cݞB!ՆK!HB!:K!HB!:K!HB!:K!HB!:LRwuLC!ҡKO,!B#B!0,!B#B!0] ݜB!DǹUo`hhCCϼyKϋOT(ˌܹk6#B1x'1`L}1@P0 !Gw2B!qfT>ӿ rP(DP*YNd !bn3c)__RO ZidI뮫1o^>5Xk8rNEv.zݶsB!}fD~'~ KMfzhy չ"JP]\8Fec/}ݶ|כom.B͌ K6קh4jd?&g6mrpHEN;n^hv%\Ds91B!*0ll6h64UjIT(V iR,6TCK^D#BaF#XFf5'үjʫNqds窜?_*UX3t+?:BǝEB`5uI2aH~v51q0 aMCPC/:/GpIBk$Fzȕ:,癘q|ZA֘uv5XZ%(B\t^](??dB!~:"ğvQQ8yjqkrr4:hvQ:-l.m}GD!bV"X@6!`3iAj4qd˥fkz$/\WYC$B\ۘ/­kG.k`˿Ua_0}}TTb [/tٌ()z%BvtU~Z2Wz3LNS={ss~SɕBqu1c,GvU "B_!B4]`9E6n8}akCjI&'G%WB!*"w'Y.fB!]aV-B!&f3XkMK39iT+#^nl*BqiHDWij%J bI+M1A$\|Lf^B!C%a~'Rr~&0H%FҌBq ##X=~&'H_43L"b]1a>"lK!z$X+jՇ2)4L"bEWUJ(Wشa4B\EHDw aGlѮ|; 2DiƐBذ4Ð)BK:hp t-4۝` P ڮRzq\]W34ax !D/#z ҃zl3B@ ~ő/WTIx5xl*(Kt,E f# Խ /?xB@P*ŢjՌ͐fҌ]%K>* `]]@"]B$"I$֍l8 fBD%fkUw ٤m+]CEC.hK!:K:Q sMCc-4!F.\10rvf#VE64Q+ ґ``o,f(Eؤ^nwU(fLn, T IZKas)G!HDWP7h6HO$XQB@ ŒX }TeҨcB\HDI7wz k-ZwU */`( ˮD$fHRwB\3HDWʹ CKXC5"[Qj1vŏ+}֦)fҬ֋ !ՀKtk=l_ WTGb76vE-BKt=0}^mXkכPT=( A@i@R G/6B9KtV9J^k$ٰewJRR18X:C|8ب57–&Bm$X+XlԪZ㳸(ͦlRF7 x5c!Rx]K%3c4M!kMfS%,n,ў >VMM6&H_,KQz'_B1J1}!^R4b`{=+ņzIdEb)Gc)T{3WҨ7+( ,B"J36N52]1YXnTĽHfB\,"E.>\.D{@,_~D-5n- ,=Gi!fZjը~kV*[rKWҌoTF)fC%`6jw$=DҜJtAR n40X½CW#VhW#.`+EaK|*:WҗLZ3N3Ʒ mj``JUB/5L-P,Fr!_c1?P]jF#~)(G%1 q5#ScRw IW7M-W 92IVEs Jk ׻ V*R.ӌ?B\=Wu*j((DO"]EVk0TTxb\WH WfǑFJVUQn#]C)B!hDEթcIWE+"^hZnB,0r J qjM5Ȧ *(WA_hD}{4 !:Kt0NB!&zw;(X\ɦ#$GjCiF! ,51J 1Cej5M=[MhWFJ6S1QTQmWTX_Kqq$X+D)B 1۸v^(n}E/2 !6:{z,Z qEMt0NKp0U.# 1ǐ`"G89= ^Q,1`Ѩ71@TT=),Q 3S`x~RY'B%RB lX -RK-$X(M((R3MSQpK1$Xk0j4ZP,H&TF%d]ٴ EiB|N? U.d#N"t;[.wkjB\,5\ȯa"ݟP$Xk4c Ţ_ !GNND'\ا?9ޥk4BQ!,!ą՚xT $X(E(pzL0ϩ&0i qEHDh6CP((E(hmѐg|Db}<;!. *` !|l5NNxX`"B\2ٚKti B\` K)%z}6-$B\:'O V[g;St8E(BAܯVm26V׫Q$X4]P RjǏ1,^>4Ч*a#Sz+ qS(,E"XcgԪM*.RQ{SMtBqv| *v=Kt~z+ q4!E'J_qg'O5UqP%Hj.Ҧl~|tbBj4!` !Xvpg"D}!V:&댝bajD!]^1P.B\\`861lZ6A%J-VPa ˥`9N>I28Tfނ>D1c"B#KtF*B!D!uSSMtf3 `+F# LQ,SMJ ! KWe>,U*bQy%Xq~NT+ E`RފB\\i<Ǐaj<*>D CX4!C ;2-! *zP*)E(ĵL"XIyox,! *Ft/¢RB\tRW iz牮{ !:)XS N {HBt `9zV̀B\&,u jQkNFFOOQj_d)O4un⚥ӂQԲA>D]/gѱ,u\pa ?Wٿc7yx~חYv*nXe7ljIW A`mV8̊%XbV`QQBh܈57bw;Ξyӻ6Qpҵjk׳lKL`AԲ̩I.g՚rp 1,u`ah~1hv`=rFϼS`;,~q$]6ljK99~#$Xb֐`S7uu7Xk -c>9V kWdW==۟,~1Wf ,[55.!z/py&'nQ?OMv$B`S,nM:;26-XY5hYkN(en*W=yF*]#YnGVK"3"tynZ%XbV`SG84/Nزca$Rh-HAJx']=?`e%,[o`o@M yn^ĒCw{J*G%Nm1EKDhYk06nYO0q*'Z m #Q+Cy}'?ywD5U7ld5ko2Ek`5!G_㆑yܸz>}F#C%OCCQ+ʋTNx`\$Bf(ŘUP}atO<6M.^5ڰ#k$]BALm)xYn IČ#]QI(-s:HYyOȊV$g6#ZQ8UӇ=矾& /Nk5yk'/ 2vع*qêyy\$b$X4!ipDF^YYӇJC.S,q% fL͖HN=߂ \װj&޼܅bcgZ@%f :85<&AV)VZM.$Z3W4VO<>QzfkÏG/3zAY$5qkߴub.15Xi4B-N{A%q_+>a=!-wIV >hE{F|c?)xn߃L$]Kb6v'+֬tk+βzBV/3Ktz 08!rNF-l/-LG%eg}{gXx +Vewru.qUcgϯxqiVo+)NP@wSq#]'I&5XRe"Zk!ъǾr'Ic6+ZnN?mX{~(9ǙSpgP og%r #7sÚuX#sJ:׎t6-MŌ =[ȗoښuhE)?nW^dD?OF}hDOOa1Dtp4eyǡio%K%]bN3[>^e!V'3KtF|/A}m(4K VE+;=~dLCK /V974E+? 6LO$s;]$]B\NNpnʼnOI\eHDqCnav8Nx./u9J\Nk^Zї56#Z-ӝ9l=Ƴ`JCvg5=h.'Z.k#"tziw,ed 8,S}`yH괜7")j߰t:+=7Nu^ZDG-(WZ mP=Oȹg8"=H">tw,e-pn:W5,S$XFM.r9Nkq/:-G0|G-,J .ѣvgXa!#kkY?z`VmPr\r$K-caq2m2 S g9E*c^T#Ov5k'Z>.# fC/fBVgﮓj :Kx:ˍhY )KӺbo.TZZ—8&%\6/ux)\Lj̓.1.g_&':9\=ՉKzH BΏȧhV4BD\h%\т8!czE2J&}H*ZHޟ;=c0 s&:45 K L40vKt P1ANpORjWu1jV,N.Q8x2-kEQ+q{5i]hHDǰ?<LN(e,^X lz+'ZN4:$ZttB`vlprh"V-V+{%%C,&?cwfQ|.$]~_t Ͱ{O^ej :KQ0'saʤ.!NJĈTR} IDAT s4MDVoW lk{X7sҵn-\d LF"&n;m|8-YxMF\HDOЈW LkVxD\1W64CӾF+wL Xt#Y:lo \ph^zbj҇VXj҆\4X:v-=-_L*9|m5.'ZVǺkNgŌ]Zf=t BIum"wǡFY92#%X #=1`VEd=l{hYk0mjR)6L!9{[TrѪ 9 ~nBx/-lp^A<{ֽ5V_tmͬXV50.e:7ZM[6]HDOPE)a۾+9Q"&uUn:nM͸H#/I['x~-f'1&\c؅93huNrh']sg"{o]sEQEX: xCHDOP64?"!rauIôU1֣ک$2"@nz Db2/Z'Z-? IZnF vO^2-(%8r~~z Tmƛ$]-'S7(hNNt{Jbb~s?eEGRṧU^[XlA6:IqY?7f ?Zemq9If}ak2{5n5v/rQ!|Ǣ`ђ SMlvV5k6,dŜ8:'v{:b"=ʑyVoNVol28|hyK{_HE&&/L|@{ѲR"Z,az񰹂qK~>&-o=hM3N=lD++g ~ԟ%+4ҵn-ܰfkXtN8:,R)^TqEHDOtweO=TX?YVolr[dͦf+pp_} zkG\t`C_Jr?L1Z)'ga"s6+HS*Wm8ys_lN?>âJb縐dE+3kYdSzFx 3}s -o^sۋ|ZJ#d&oS /+{[};kGKhDiB$?I. Znv)\; d/{>C>-+s]LǗ#Yy$]3ʒev|g2oAcz}_|s ؇.}IR]F6lƭ llc&J)+e^[dFگJ/Z;2KD9y64xv7"Zcħy|:-YyHWIVY+LzQ-k (K`@]ɇ/ZnA˚M!k66mulj_uhE(Ҿ";*gc$ہHTɉ_v`EkqomRӌuy^,ow)ẗ́dt]6&0\dZ^V;rnʣtC%z5< ?6>%6M!k66ٴMM}ꉣ,wWZ|qbEoL* 65ZP5E`י0MwUrlv+Ov3^̄XgRH%]1,X|:J>psnOG!$X'pvΏ>Y1shqKD"v-Y$vs^[")Ҿ"'hY_|["<&qyA󶵦 qh#~nv".w:b?M#J( -ٴS,f͆j . =;ۈMJIOKK_`ͦ&k75m5ljM=}QZq;zEՉmsMPܴ5ׄHTԕmEk*='sJWpQ?zșSݞN .p_^~.17` ]&2w"E M ll[3Ԧk|̰k[=;K {Kq'sm} 2;W _|W˪BM."(ts9/Y:!V^Z#$jmDi8 G-[荒yK5h+]'xq_myq_ysD YtpM1H%=𒚍ȑ_CTzZN y\Co@A˒kݖ[L/R}kMFLu{:mqmdԲA\,3b3jA|]*.y;ޗDbD"k?םovcuW}%,c[G ďaiuʡl3xTKF>XOT7wHo6{=iprܣkHWRdނ jȿ]k(8:~5K /}׏iW]0bEz2Dʗ _1~$mGdlڍQtk:Ygwl+"{vya_Gtyq簹m\L-Z&V |ik{%id.WPu-JV9"]Xj=.Xeé6ʏ6ljrvc[ykumk|,}Ez K/]ٹi4 /U5j)Dw6\$ɿ&5˧!ޜ2WFЏhEѦs_w1:|5IV; ^7tmͬXnVpcY;ԲA\ ,3+Yx2{vx !LX<~XshyZj.s unlXp ǁ%$ZDȊw} NȗOTz Xcjajܵ,Yyͮ;#]sI Z6!=  EG=LN2Bܼ͛2$7 ?`C֯onmT[k De] F>9Ǐh9a~ D`h] uy ='ɺ<.SU(W R_mkO>rS=x{HDϰfB6oY}<%a6e6-h=>"kc(/F6_}jZTL2uT !VMk[WgF[:~ex_ʦ}#Z0-E{63~zm"S-Q6> ='zct KUj .K c|\ hKyh}d)_gh[8ҖVH ;d}sessY|ZT,]d:wUe:ַy9pāe+;VL%I fW@A$5Z6GnEZ 3.o{XYp)Q.XHuˬ{ttD%zW<B*R6:k;ZoAݞJʞ#ygɐ t̊B?W?9_N覉hb9`dZ[[|S kkmkl,Rq`}ʌ1smʧ hme h/EOʒ}/$kvKWx?-Yu隷1ehK w7Z#XmkU"C9o|͒ۖF߳DE<sd>MO zD;y8-- ‚x. 㰆mqha}Cp׳YV:ٰ[b:nSuXKUa}WΊVH6h9Gr. ɝ%?du.w]Op={HDEA'~1]eC/ӦgeVFK)U2GdMy>ZT–;*K`x 8 šT둼^^ vL`yl5 /EUw<'?6 ˗6XΛnqSs;Vd>v*oo{Eop/Z~~0hԏ]nTKdϸt*>pc㊫ \So\!YUhsj llM{\%Ձ6|FU~z0HD;ޅ[쇱nPy\gm#v~ǒGcspvgݩh5Ɉ˗xu6nh߉~2Gٷ̱WIDˏ' VˮtSm$-x~,MfAuJl-HD ֿ @% ??O[V?^A?R-'R<;{3fb.'gmҔur({AvLRi?/ze_`O}1(/` I ֓xۆu56'ٰ$W2;3~.txmEXl|-Sr>K#TI%H׺-\p߉l N\5$XgpK'ïdZ}.=.'ۡ徂Zd,xZ*rQ-oc`JHe̤$yqru/k+?2Xʊf|̹=uB6m!ٰƖ-5nc67;>vcߞ2O?7\ҋ^/~ w],*4jvCIIW`,[6[D%z~FFDˤ~I{ȿR3:sex3bv\1{rs]?!X^XEdIT^ܹ{' :5/ Za,MXjcp /nl,t%s0 q[ذ1AuH{<{'UDVK[uE&7%K."]Š5k>j |$XpkV*c/L8ljE\ۅ9B";.T|YzGa{aE^=.ix/IAPVǡ40/N&X~kQti(`hWL*QǾHxk"y㩴ו'ZLQeM6nMod7\WLmsRF'X=MOJI˶HKNAmΞ%z )\~ &'rQ S6%2=)ȭ*̊V*X&SCՒ>e+L1IϏf[~xBH 6'kv}`Fҍl3_vr0q[c#/C' 2EH-XRqn?=7P;ߟFƦ-onXܰ!-T)gsev>Ǿ]2sO| 0rQMw."ikX#+l('w{V` ֿX\¯>^Ufg`N5ZTb]eL!*?<@voAGT!('U8jU#TE࿿۷;,.lprBN4ח8cp~Wž' a,Lftk_&pמD2OMqՎ։;者aSM+V)? ?e0vݎ Oi%BKA|NQe**~_j $XpwZN(h;"WM.*UF %ޱωL] {U1/ T"hUX `my+,^7},XI8~dͥ^|I"P8yN8NmP'I%>6}xɢׅ9 ap0d5lƦ oSj}+ǶGٻyђd];LxRh3]F%z !R!HSh/R~:*Z5M+d8BoD&<bW'2"TL*ZP[?ƮvxFU$/'a_Zcgf}h)4F BMEmxA.N'ʐ;^y{(mѢtuO~ۋhyI i W4xsW&ٴ}=]X*Ya߮=ʾ2'ZŶW ܰ/}5rYvm?Y.#=߼EOX^m˦BO``JU_|Kejڈ:,sb?$Be\0s!{"*(U"\P.cG6`GcV+n.^ ˖Es?JAh93Ç1pNçIŨain}cp(Lղ ēx0~{>ѿO]iym mD+0in[qc7u-wLM56miqػ¶GTvV8JhT>GuR(#gx˷k B%z 3dtR~_ޮ \MVV3hߖ!iǐ싟;sywEbئo>wwC(ZUZE`o\ }ob-Z(Xl@D:י^@6B۰"cwlmC"qh5KFoKD+XaKiDE^ZjD#^~ = TeӖo{TcŪ ط¾ {cl4Hߟ.z'w~k&>g=3щA IDATE$XHCnۊTv|ٚNI4 t- iʏV9 /ikD#"W?}ӻ?ɕ20~O>lB)Ė,Bao\ 7`ֆ0oWEKESS`z]HlO=ǢUHj&1x Imq+'Z.}a_TV<饕Yd̦ϻՈn{K' B6nM5nywmym΍l{dOwW'HE QbkUa(L-w?y iD=xՌK[Xʑ!O=|rME3\ay@XTݤѫ~ wi"QOy?}p 7G~ ;[jB1R)r nλ*(/gc+oED*EcP؇w+'/WE;El=U W1X@5hbzm a?VO| Bc4Zu蚖괒HWRG_4Yт^npȝo;شʦ-U-h#JYᑯ {v2Ws _ck\V>=8<$vJW>WPh"ɊW|駰oob V~?|?D$X?<HXS8vl c֕P s-Nq +g97SuXpl ^8o8=zegSB-N<Ѫ؟A\KЯrTk SV-=D+SEBL\+mvvQrm+VټV|Kz=;*'xZB5ǩ$?L6ٰ[sO>rD%z 鑯|寢@ʥ#brbN| m M4fG C@J!^ թ^ ~߃V X4F_ao}|#qD@9Q[PŞ<?Iv ĺАikl|-p쳯a; ;ѳp~ {}p=W_sK _"?ޏȖ=7 v'Jk\AR1/ZMBnH,kt0i/H\tUmݞUn7Oq׷LrHk=wGgg>s*-YJhW7,S;!|:Mm[/kjNUeEaݻMx2~gv[2i~n| ,ی]ys$^}>p۰?3Ѷr-4᣿ݼ>Ln^܀DScU&vY 2L6ףkq?JXJ+ )U#k_z V~+pp_>S`'1x~[u/wrUj`]^d;'MVdRI=Q[ fHjޞ>~u[)6Rm+]F Ygg{clвAV~)W .Z8,zA03%L)gOч1 Ժm&yؚqMOT I :_HHL Ln}lt;ï9L1,b~ow0?sßǮ|p0fE5 ͸.˂ I0g'_ǜzEx;8bG+ f08gmMìv` G8Zh$Rk6EhatĿS/-04inm}b2}D0lF?XCBnuo 6-hrNpN$#Jǎ'xA u[niԡFY92#%X(,SQA`SIrd4t)'[Ӊ~F薃Q,7 )Lx7DLtM5{0XLZڋ01y`#QYwZ`b\a>y @C |3z ?^Z̘cMb{招f sӯ/M{^ _|? /» G}G$P۾{£O#<Eh&Il$Z7|OEDZhD O [{8 l,Wi ؄6-}OKýԢ)D x;$]ݠ|[>unʩ,Zp߃ؿ~޾ooY Y LE"v]5 9^C@Nh>b4Xw% ^1cWɶLDm$я82fGqKKSQxCGBc0cxj8v~OHP?LQo`~7/?}mK{;L *QJ lrϘd1lQ`r "I(WgGUu̮0x>5]sO{VwN)!J*Rd6B+UG$ydW_Cg}z?~/?bXyG/A=OA&^u L.x HJ\aC`^=' 7cߴ5hchI-E]˟w%Ș9jʘ{i„)RTdEѷo( AjH!2nYF˳ul9/dM|,Y;aMݮ4=R n>s.gJzowګf/7P8AŬYUٲyY`MYټpK jE\BRօ|΋Z`d-DȏRhSBӖDdIx =EjM3=#"Ph 6:#>Hhs-$1V5>8C0bC Ms|6́ƳiA)x,N83q8>o~~}gö`?^2zrp&CU/i+$^u;{/c޴Jѵ[n(m?qgs- @R?LQCP!r}-K6r !7-:.0:0;NP=5DtZN/Ayt<<;dz /e>F42hX#\V59]5ۤۿa;3d,pz@ޕy?fy6e" T)B)eaB7ĒиA!-ƛh<^Yf<=Azt]"SK`0q}H,u!ҋ诶mRGv!zҘG'T7l?!6fl98^;+y3ܸUЊ<"C,hZ RQ6P|uJH*@g-G˂ʅ'\ s")rM׃?>Cˢϒ֣+U}&,֦̭>_XB~"VDsfh* $-)g#iwgI|LX0:tǃ?MENL3OB0[Np46 []3rTkaq4/?SvP $TIDx`eYJKPV,VYx|P鸻204I ë 1!h=}(7 >;/A{5r!0cēvc\0\E0<{:to 7c0n ѫ1h)hyeȰYm@M* a0" &~%`eVڜRBC}ͽUF 2Rn;;V"pN.{J}";}qlYZQ%:P-aE8}F#/c/Ȁhcp8&`ئ< 1(# q%a&mz\'&*q 휃v *(ч U^2pa[ҡ³}R{(x$Azx)v ]ndOxR{һ;G!iӠG콐6Ba(`8N3;"?{6tY"F+mi`a$F8_>Y K0S?pr րZ`9xȱ(2zsqv"mwcа"zgIQ;ot:++om)D"FQ(QXv!70|=p=0`z" KB璈7:wHl$S фj*x qi5#s?Y xZkBDRhE#b?^\qU^,eCve Km /My{z%W흦a)u0c:c2 N :t`Xg_:})DOC=d 稰E pkvew6,Γq`0t\߲~F´;f'cхl(W A)6̺Iih ,8DL^~4b|40^GYt&xIu}QJKk3'/pjSow<d~q-zY,bә 7Vbkя~4,D? K0Nr4cLJۗ8z+\9V0cf\V-^1Z<撢ZTf6V3k2W٨q]R}ˍ[[<[KP$f(#iBhThVBB-w}!qs=Avi>B 4Q {h9qB2>> 죮 IDATZ#;hOd}X)`Ñw@ #,V"l9 9Qcm̾FˋZYVqވj,H^EX*f%f]k0PF2"br,kъWY{nGX ֟:hfNuUGw&nїmCpUrZS.\ō-fOxLr~:u:&];$mp!g@ժQAӍ[ޢ־BKrYFq .(89D9喸:zֶJ>wruo#[g9DWxa}RT <"< ~-2vdd=vC>7ҹ. v w#^EȊMp:t2.>Hأ|A*_-tCȈPY9 :}0进=|8t%TIgDݓWkkny=a`%@~t(G sOFSF@u 6S:do, Ċ  &%\&H(HdH_d7Hؗ-7qx옎5\|N*9rۓDڟSeMO x^ԞG`֫Em2֡SJAÛ~Mwz;s VǐэJSGw]^?|]EC}Υ$D]m%ˇlYV"EC#HVD FYuINyj$ O : hs&TAheBh\wx6$ Fσw$ХK4ƒF/?.ϡS yf#)(g-> s`e$P@beGJze*ЮR:)klG6V>ޭݛ->D<0(AY>n (FWi#pa¹WG34&φf1!&<++ºpK݄ V3O5aO!èݥopx H$H >K/YeOv()K$/aȨލܐypuA|4tq%+t{5N61g%mͺ`֬͗ە6iy6gn O5+Y hA TC!Ԧ *DsXjE hz ~R]Sòk@kͰQXă&9Cu^\tJ#:f8yO- J=L4WV"3kg:Fi*kP넭Q8q 2(Ln,K jWV}] ZIWˎWJJLf9&AnX\ J1H= (B)2ޞ 3f) >G 5f ڴ }7ʹ/fi`Θm| _>ѳXU\* ZZVDcUe-%+M7Zc?Lh˺ڒEݮU=׷AG6|ʆCyksVVQ@%YatKd~p]DbY!rײN$QFʛ];RG#ÂAY#",F >{vYްCd03r:dߋl=R `ROdB߀D34\"P#AaUa0/FHcmZ $bdDX||9?Ww5@{*ljExUCv~~xj}$D42$d9}dËg=RS4 ~L8r[G0\S+-Hpe#XhX<j9׏{"ȩˍO*Ӗ3}ʖ.LE<`7Of5ռ| in*}+3tbuZD6g5]J9 x dj(/{HmFwМIss,fB.Mh*ˮnǙ< 7ؙeeut0l4.X$ Mxo^{ 2\pЀ '@=9zsGtmtki*/BQtAcW!.a>" n6|qJ|hP[8i'1pLԥ>&STE蟟 MY  O< _5ٰћ.BmPj͘߆#M0HH3isOχ5m^ #5'tB. ?z!d!Ln>^/IyHϕ‡w'&u75&iy+omJ˒tZƺ5>}L;f}mFsE6"=Bd"c."H/GֿT 늴?k!HE7X3:&B@-m9ymdt)d(Vh.s/ZOah dU[) BxBXx,OX8,~ Ch?E1X С/B}J'b}(2C Ġgdp~[I0dK>{"gvaOAv:0>3$+G3ᱜҢM=l8s/3KJzQ{YƢy b*>:1a0tg*z} Pt*o1POne&Y0ow <6g:3fn,Y缑GѲL FmܱXY`_b[`svơc] ,{Dj%@@\v1LB$Oп̀iF X ~7Ј,yA+5@3)̌&W{5>ZYiZ uߨ$J@he0449 1|%pk_T 1_=Ǩm(@_YDLާm7섣M7OW?=e+B ~:s]l"R-',sgwAj:PnYl;!#o쎶,t.ga͌i6b-w~ F+*| ;;$-@4ԧظukظ5[|y>'og,ޫFY#aZyvoҁ&,-rkuFXV HqD"P|Z `*ʐuܽIpPVv;DSо";DGV";^P-e+ۙ(S;o8>M ~*iBBp "j' T4c`X,! {ChmBg/< 54{ 1/2|ċO)g3N_U >u6*/K[W1'4.EjYb5ZdL}Ooq=Zb"LTg#R&`Ȣ߳1ZYs#tKmdR\ QZ}nQNA֣845(оc Eq.y,̋ySI& jjZYAQњ+mygV ȹvFېArms~|x/cF=EssvE7 ;X5j|y=nl ɽ.E]%ܰ g#\i>4T*MW( ޮne3ЗPnR%t)`xxH$f9jDb` moEv)1oL_ϐF>s99p?bD3jKvf:'CsXoR'dt(= Yz 3[ԓX1}_hE.g+VVցVm*#z:=?R6QW,]?^EL9q啅t.e^ԎΥTV""ez$E,oy6ggxL+?n;,e;,0F( A|eԏˡStx˰zWۘ}QN:,#O?l=Pdp/sd Sn2 f5 CQ|RwCSBs ;J ^6ƦӅ?@v~fB$BDbpZdJ{<.F.|ٵFeTNk&FGб|r> Э2tL?y:dJhEur#='#/_>,F::;G؋AA^t:ʜN@9h}|G#;JN]mw;+S>74rYlװr&6kXLH$b),s2zwj֬gŗXL:~(`Y"n}k4 ngmEÂ-0JDY95ZkK!-tF$n#^&˻d qBdٛaO4)69vr4X^wrv_#:g!l8wЄJ,ހ>675&?+?7mfm4fE -CERS"O_^+MQ?BE*+|}$;(Tp#O]3PMz hm:,d<'vfDg&o-h* ~hX,1-﷢رhIK BfDƶFG` Pه93o}9+eύ;~:3f*- 9gj:#&}@,\+Z\ |I~=dR3H_y 2{z 0rݝx}pFV)>gi8=XRhe" ]6]x57ß)"`)=+Ńc=ZzݹywZ]mΚvg'cȸ IGye!ՅtY?;N޾ˇ&vz>[B&ќZn# ;f-CEDU  xIh J87 E>K,k^& oUeHA" W>fS]톬Ǿ@&nxH2Y 08H°SER8T$d%bi6"uAƷ' &_/Ñ^qw.q݅dxud]oɰv5z>!Ḉs@b16P=+2zjxKͼ/ Y~#t;:;$+D'ږHݑ>‡iK 妡4r gѺ4gYN֕>~sy+`riY$#v.koa˼۷z "jEy>Ǽ"F#', ^q:i-׀БIAGhl9Q}Vdmwn6>_-ӡȈa%HF?2majD H]ID ̿}F# ^E(Ux&U_6 Y ['G(AKAKYK 5~R\4<-I!{#$H #}}2; PS S<1$M=79cwH*ЬT,Cw]H'26$+IE,&I충^G t5+fXRb }S%fXd<g;. )1NYW̺ Z6 3j Aګw~&LZ2}Kyҩ GQaTS ʾIyS5NIl@q N[[Pc;7H9$>9nEd'dٍhףiv]n mFLHA*`R@w]@>ګXv{C{"?BE0Y Y+# LKK35?:̤ϐe ug,&-STBAjU 2%@SV[8+ :,t^O4ՃBA )2 Q̢ /y2X]%ڠ [n +̖f0Gଓ88zڵ&?>߾lG%\A&}:#ڔAZSzFdԗtD -)¨-fED~ =jă@&L@t @ bPb׉;!$zTfxj@Z; k4h'yL}̦m(8h$-p>A*C#_>ΞkaoA/^wc'pѱW1Kl9ŀ&~sR v\ @SupZ2{gs@+| /O5 #[.%O-yFN_&`0-&- 4MNryW<IV[ˊ\nuc.\h&b9"nK-?^ ^"9@/n놅pD(.vq5!#?ǻrQ'@s 9g? %#п~4<>VG%.MUPf̗ѺfVڷ @FtFJ!.N18 dV`; ? C*YgO'!_y~zlYv1iAZ`J@ˁ AOtGp7dF.!B$d-fqg␈/!Y8-@SU"y;¿2y๶[H.׀hzgѥ״RaRydy6ii&,RJNKY `_c& TXT'U Wa6= IDATegbCvMݖΝ"r%@f(ĒhQsN4X>e=ӑO2`'C{bPo/LgLAjXW +k%a]4f\ii/{WC1)%c lvDBԆёzp_ h*s;hv6[+zώB9hHiť6wgj~s9zo>hNi TbgqZUZɰAzn;z IzС 7C3Msaȣv% fe<ÒbC&LhOnHfx9 =f1ٌKO##=E[fVЂj hw3dwTyWԔ^+omҜ=PM>xk|EgDFBV#\ }KZَ#<ՈqjX1 Rq0r,ZEPJcwFg5Z;d@ E/*ZP ^(r(&úVš \ۇu裋@w@2c9)q!1d1*aNȡ?227Mhil_Ba!44F!?92~0n?sBfnqV$_^dذc,2 O  MG-"rĄӶ A P"tថaX!OKDت`ڱΓŽ8[P4^l$Q^)򼹧4<"\F_-sIm\]V-3'}˕nyiy6iNYP(jN|E'ueE.rʺs" 5\Q8f!lIur |73C ҉HQ:^wL0Xp`:{O:fX ]iW~ G@-{_A} g3U%"F5LnTڄ/k:m _i t")pnX)(%ӡ,:D1Nvm[7c"hUo'd7D RHy1`v@oX$2f(TBMW|ϴMbs/ L?Ƭ)) ]CUGjg14.ͩm8|`$Iƣq-bù.'ao}8a䠇ḦmzxI@x ρv;ϝ !# rT,J[p_>jCZ' !FV C ta恖hEuZh5ZpZA'G^'% r@LC=k|}s"r}?Xykf.jƗV8` ٗ,0k bo^B>C~q0*ȇVSDC<[f+,,Sۃ+Xʼa!"lVSֳXH" L8a &lOhp^M`5=45{=B4.- m %g3E8#0l(:j $@ sx%M3ѪvSkS`Z}rɉPTujי^P=l\xڰ 61i JY) e2~G#ch5755f ^%fU>۠3SOuw}n|eEv-h7e238rYna|dy6i˜e,>Fm@WɊ!L*~n\ c;ٺD"$B+"`JB+ #@TX'tSpH-s! LB-ېf0tb(Vu֩6yCq1TV[ݐ]Ttp ђvHI%W!,$Qdc`mj@jWVC*k:Shn@~w2QT<ٝsI{=`_5 ,@[^gi=cMM2!`"vvxkJ0Be3c 8qMV[&6TIN!{&{Ӱm<4AH.|""`՞N ڜN+ VA _,̃g~HXyk~hI1ȍwRBPj:`JZI·0ZG~h͠"ui^~7T"eʅeW"ev+r-Y4E(~}a"2[6ǀ'lP&ו"pյ5[{_?2bD:kFJZRZac>4Mv6qLO73JCa:ŤZ:Up.Tjb#o&֨q0b<Ad kԈF@ЗoD;;hD4K*%`ޟ݉0Pse'2˺n  M apTgs4DbPH9/,NGk3qJ00%ZvZHK^}(*)i`-&Qq4<\a'=:v\U@b=) Rӳ!րV"`Gx"CrdY :|-hPHY@\:=BHSRvDh0"A(}&t:ҩڭ;ҧ Ѵ@#Fcn=P  Z$5!BM<;  &X3qZB4YL8Bq1r! 2)>z \Xݭ&]LÀH? 0=װb Ù̘ &W;3}xk磇<>MAr>{ $kY/ƻ/<8bV?;'Q{,غ:N].{0K*s.ukߺ}_nEPT@gYqygW TF]Eّ]nzߪތKƭnPg73#FFf|{Nȯ[PV*I)h.#CXw Zq{1p߳`5l6k34Ի? 2o7`^Ǩ[KbM­ߎ7zD`O 0q8MT PS@zC,8= MpUƬY-![":=xA%$,琹ߎvxOUkE[;%G w 3:v:Dƒ0mmSGB]b;Rhc u9adzȦG@ 艟s)E!C3p͸UІߠ@%ˑEb6 7|vnF?>N E_#㧢_x/ltz㾓dLvy=qt1Sc}/lx 9yS8k>, z1~.C`$m;o,oS-hmż_ەD8QWg YeD<(?ѐ5O900 ?o{)h㛊S8m?&<%{*C{ѿ~m%/Zi.-^|Jk]kVb S!.0>M# +=ٲm\VW4JOKBnCfTO*vh T*_у* O\CzG 1Zua\?,]}nE#v: ^8P3euºk-Wi'XF<h]d,ߙΟ0GV| R9atZݦ 5QF f '~g' Uc^d$x\DB.59\ <|'Pm~^ jы3t@ˉ |}}Gݘ DO^(Bn, : ĂPU.$pgZK cۗy;e&nHWAD7S<اii̤SZSG|r;f 4a/jpYuHgwJO禘AL ݲ'A64M?C_jw"eZtq_f8b3w\bTpȥ"u%#`B7B3ZCP lhկseI!瑢".H3H-GhO"- %SՑ:x"<"T0'"S> #b||T3ٯF8wS*ds@>Nw}H 6;|;HBK _ `>a\)ΥVTSOdIC.3RRLѕ!E5"qwȼC2bOYڋۇ4*76 NH.ie eI~O{3e='9pver|9g}e 72k?E`)(AMSY,,"x9uJsp*,< yYla;vic`倖^* \:%SVSJ 8w >Aȩ7Ê} +`r1 E [{79߁b!ۂ5R5hgw>|:(7Rpz }G^9A:;'?Tg\  yLh9\P7'.no)>p[hYj:m.oZƺ\h @x90~3eP41ANnќ?q\<֌$|cw_y[ y4oېw}ufܐ IDAT̚guwcbxS8-CҘ?K]P 1 !{.b@|yƕy=`pziPC~}Ui(X56:ZC VN%J 1X6wuo7H][&W^Õd1]ޢs)?Z'oD h0 ނ,\tt$ʅW`z3dn?rː":Bt:W!2Up-E! Ȃ+V"_2x:蟊g&E"S5Ϡc!S>)\-iv+]_QH@ϗNRLr |+XV1m Op}Qa]+#mH!v3u[kJ͓o{^+˘xIr)I~֟w,_깼m'l^x9~xֈj^k+楦1{B^"OB Z jV] ml,bR,D~u]&O<{#>VuSB7?NXmY*T| 7AOZבȑ "3d/iWt0 ) e\c|5hONXCr5c͇]K;3߆̘;m /C߀}Uq?z6]mYLۜ29|e Mma2eN~1WBnpS>Eɕg.~b|Shun #9h 9P+d`#g?]iȺb]*;P)0"wjĹA i-7 ~??WB}@Ho_*ǯ.SjĄj$Nfi߰ozdccϥ^]v ZZ:b$c?@j]_/};c';MވyGrW/|oɧ>Ad13)\:ɳȢX[7ߊ,jx/Z2ӡv+w 28@y hpX׉  &v+D NN_Axӟaf9zppᤓћoF<ݰPzgͽWt }j0q hI'I=hQ'?3łS$01+e,Wn"($_㶏?ԟ{\.zȧ? dɹ`L{ݷ?XRZ yѫ"nL*S'L$L u1H=@{PPqBRa,z2;$%Ъ/Zu~h \]@^e'݃5a{ g(D]68e'l RzGQ:Zc#Ԑ(<|6~TxgjUPlN7r:RjAYJźVd8tL\VvntT2DdpT׍NkF$CPFTA.X GջYъ`NWۑK@߸y,XVd W W_ۈy6:ozw[w#fr94PY>=0|W5MITYc)!tԕ_(ca͝h@o҉u3QrA5kj-_5ލ>-9H>~&\ _+,L?횞K%0& FshΏIx3STpn *7$%?8\pwS%V鉑VCþ1@ogƂSH2o[Wۧw!#CC,5AiglH+^=| ;1؞CDB2սQ jn֍`jĠ_ze> !Sg&W?SihmA[ ⓈrݓP2䠋QT3[ A3HH3HA- jm-96iz?Ev"g$ L= &7 'ÿ@@<Jeu &3wz$RPPxSs0tw_4PSx!K` *],hAq!L`&N =/~/>6_CokdQeIO$aT N}XzS)M޾Ŵ F%*MpIRC~mT,[HIn:E2~z|>sbSi~i˓c 5a{ժ3,+]o}3:OsRjnbhk}ziVQ\m;j =Bj}CHwAHp^#+BG3V ;qm[v2w&:rۃ~)V`r$C:m.iJ!b¯!#+[Y ,zVdԇ3}lHüqOÅW!g92{#[éïEzY跠D8\(v@P?ёMHm[~ =qn@rQLD} )V\[SݺnJ'8)%wi Uӡ_A]f>bs82x>ĩ]: M۫:irm3 bxnFьv@`Wr̿ W}k!F)ԺW|}}hqZmX=e$5a{U|[7Ƿ? 5:@!ݣbE lS05q2P>RJ:q7v` :2ϒǾ($7 WQ`/`l@Z)ӐfqW˺>窄Qi+ SKP=IPRC-@*^zoMA!ـMFoق~Ai]路Ggk_ 梷މ.t ې|sʳ{Sj#sluq8 Lpqlq:n7'HCņш럆a LGiӴi3l9"JWEH`UM:M홻 CCϋ g\Lylj~2Vw! ; > =?4nWFx*ɡE`e- l#NAJߖ}߯{&KO=h6LD׊ClY 0ZN;ߦ2`KkpX @AfIE(Lk-RRtlQ0Pr+Զ*uJvmNE4C[yylQn,u ۱=;j"G rUpֱ0mݝ) 3' AѡUTm>8ﳾ+?-2w•;Fx&<Ć(X.%du' $*TjRR^6EN\Zn Kl!j'ƔDl4 ˡV;O!;"|v dp .[w@_3&c-M3B`n+ץDM=6AWr5>$}Uĸ]K;G =weFPP(aL1T-$~+qH"|qqVEoE<7 [.!6PމvZ]5hT3!dY :}mT4Ch*>CeӍ`0he EȆVU--a* VRՊO) xEȨi} A޼&/qY1W"3[o}| rkG;w";G`Ϻz|y9h)!H m`zr7_S!7'jWN{,xЏ$,UZ!.eVa&gy?=ЀwŬj9D@{t{u-q#vQ]0QAù>!Ϋe6e80{j|9 .Ep,KYcWЊXx Q]si2^ˌ{. .}հ֪ U( r6}?Cw *K,oѻK߀Uv2<=mBGC)0g6=TAb%7Pl e, v,ȽCT,F3(NBAʦ[ReRlǠcJ.}Wmm0:RF @"ԁWU) +xx[6Õcs|\$*Xy*V\Z]ȃ*#w!Eq񌑐9 ;ɗ1+:Rm!)<~*T-8RWFc}{.?,[ǡ$Mח]@+@ PY\4ukVZF9~3q"gNs |t ,̕^-MJZifxSۄ{kMD! l} U.)+ߐܲ,݆  4Y;6ARCS)ePޅBK^٨@zl ڪlOZ j r([W*;VjW@%Zk6!"+~'#p2X6Ndq4x)Gp2 f΄_?߉d ma*[cA>.K >)gA܏r UX>2J4\m ɵŋtj=x(P]\T\uԝ(0WosU4V+i^ aĠĶW%Brz@<hm@]m̲f7'``9~tl!<4 cndSR*C:UÌT+^U<݃Z)1Fl!D^QjAGE׈*RiAzqOH–ati7fNtXeh\PuвL|\vKd{Ka7Ի* ٨÷0hۻ@Ts)f„!|ep(N+`¥ }RDf-ፋWCڀ~:-GÒi0}"zv=r֙p1.^'׾ӍJ㐞qNr #>CO"*,>YLƨϢ~^Ac^WN"$AG;*9Ȋ]IH\;0󗣛^@;#9CuIu_"u¯A)n?A83iz6Q"?_pA5-$O5[(u[.&|]d0mMIk`q}q|/BoRU\\EKByRl-a"CK 5z-f(Sq hjREرAyWWܣ'3S蚩lVSc8s{%2J zN%;g=fp<2 G=}9CN{9gS6ngpt_8вI}&sL, NqY .v3PHp 4PANx /L '_tuGU2d+whi瑶 ^v?!b[UpFAkܽ)?Ơs4yNXZݹj1&hu-*\񇆃C Hi|Uc{}.{͙ϞEPEkVZ|y\ vIX!@XkhsYhqYRa`'XU52VX4%9uH ?vNvT(gGAa^:R \/(.\̲UYjM1KtG-C>al]i+>Ve艻ǮzS-(QOʧjyaNJ TlX˷{)X?|N裧^u/B =W!6™oq^䈣(x+`>;P[H#]KOȟO@n0@QE]pTܰ˼vT;XǔIz 훊^.+zX[ܟ ZPlHM IDATA~AZK+1t0@t298Ek-M!P6^Dj(d-@dӖ ־h j^mQKd(MJm cFM@sbB4S,k3\`P9 A`NVRDν Cu@{;hCzNJmeX;k1EPh]=v SyQ w]'"XuG.8E˨KBZ(̈́EJ+E@9&tN/>6xt10 `fgԓVx ?BSi ,̝nGGoY|g 'Kԯ*+GMMDFUuQujVHA`YH&+X\]VSxȀ ?v!<-m&F:B,sP"R,sU2;9V_ ИM\>;f!n׀x >Yv+Z.C-Շ6I+&a5a{jJ,pn+ݧoed~2T AYˆNPU!R"*P>c:Jc OBm w㿁936d6XB٥/ aM )aSJͰQa~Z29hκLa~VÌ"U M!*pS)B"i3[`I Q ?'-E&t { 'd.Ddu7wvZLÁjC_AFGMіvdp;эxOB!>ڸ ;sʔQt+a>LPW |aLs q^i`{aМD !IR].x "n4y:4qiѼ%4K-PZ=+huAKԹ VΡ> ͍۫v)RinW{W@ ?? ں5s>τď{5J/:E~Ќ:ԎgUZY*R OaL4!q?1 .F: s/P5l`:ѐB;'^7b0dBS'%:=`f,0=Da0Zp* ǁIz׀T3DiWᶓp6%vKedTdȢ0}"f+0Sf)ldԩx[RSU)T:j^j _ZN粋P&%V>{ Fr8W m*z QKC   !O^.&>6/7| D}z$% Z&͌fsŌY^8>z V}$[W[?KI.9}{|f \WR =6#T aYVŦ\*"wR܉ aJ(5du "߬*w'aJj7bPhJ͆gvTj25gUx:& t zG`)- ?dNEZMV\xikv$hŬZ\rc"E.R2BfwI;ulSb2K2Q98)"_|?|cȲW`8@* `q@\dŠ7\w{}{ }5,Zh ay҉z?aO~>q1E>WuY \=lj_ j ~a{Pn5Qc@PS?2jضV(6C7:0P6!lAfVQH-\fJ'`/=Q3]g뀠X!BD9@UG+OlVQe`忯&TZn"_O!^>dQQ E+Z*r!#Nsoo1 %@4MDvC, ad .QH`;H ehOqL~|Sv)hkl}dt߷F Vj}>tOߐ\őc_(q8ٟ,m "- ),W.֚dK qB8R>ї+͝b~}×?Tm _a)uC ^$}Z`jdZ\ "WK\b|dU0L[Z(B[l\ &:L-jkkժ-Ľ+v+\> +]]>0f-$;-ww3;X dLR`^ @>V,o+J|:Iݎ 0~o*)h0X#k߷`5lZ)F^b%C\O3Ϭ{w p6 l6jbGBrKS@;#$=דfY}e0jPS@ft vl`C`3Ev.Z{ φAy5 5+ʦ; -dJ6f(XB faLj񊖟aa^/:σm!܍6ÖCw[_U \}tp Få9@kU$ȅ08~X mБ!(ݠB  "RjBۺJ rk݈Il tTsԆJuQdA4;vpaKc}Oǡ RhvCC(;drcP(ݨ@piJr|#I{ V ΅A\ 73yu##=|& cYWȨϛʿ=}-l\˯ X/WQshNjGJ8WΝxP([H6ڢ"tbhBi%Y!b37_J+SN1oFFA Jq>EgC"pе6ܥPtt-ʚIU( U\B myXD8?MptlAԠ^w2}p+˻ 5}xUh8d\"0檎 FHS=`:J !j. #CHs;^ ?T_OG}PS|Shq5}հ;.Ԏ>T.Ws!SaUcck$gngᶳ1w^ ]$N/)6 6nBJ 2mul~,WmT[1i㱛!F6l"V%BJπZ4Y\ڃ.\tnl9:J(`fC, ~r/Z*@_rRhoˁL=PyGWCW'Z&&S$p@w2 rw J_?.t; E ^P L^ ?ЬL>&deIfc3@ѶH)~0bKժe^5,lPz I-&֘2D|]y9j? +ɷ P!V!}k(Vg(p%hGAWj'UH]9?VlK!)E XFǡGir[й)&e沲{};#93:[-VC#N;RpEy8DB`8- 1dz?eڼ[[W[^=cy_7q &\{,|щѕ_ ^ ct)P>S݉f쨣g ZDvni\?*膵P!܎lF&CڭnفlqOo*lbF@GqjU KI!%A:Z7r10~TG{hKyUJ.ȘlCe7c0t7ӘiƘndžs2ޭŶ,YKYkIUz޻G,֪R{wΕnn*ec$|~ tqm[ln@(d/ ӳv,T!^*umq"]Z|O!N {Z>M+[ YϾF1{{ā&hۻ+镰:#*.?=+2lc" (@3 ~bɀV>`kfX"Xi+ 1挃ܛ֟?/_%+f V(}V:-5oKX _QKgtɖF۶˶QlbvLc>( صCed^`㫈30Wla'd֗dJB]HfRVhID(VJnX4u,X<{wAow !uG q^&0BaH;6!6_R]5p  vsBc*[ 竈0 #^ Uyw*L(c]Cv+L͛:\8\ePZǏ/P =x[02E11:H{NSfGeXF9.T[SːgIEr̡%"Ҏ-RbQI/rRY `#Fl丟X lS3!NZInmڭL*cM6댖{>WpNmtf0B~|g 2 1k u5tv#<з̞1P+?~`q%E`͂ڽд(>#p-woof1ZU竾5=}W`-Y"lZښ"9b0)Rg%4[t栿 ZWgkXxLVpŌw?sB{g0rLhߟ+jɀ l6#Tk /9fBU kyOy蠥=S _OkOkVkΞoۼ"+ fqQfa`5wE 1Z)KHI Bι<Fف<8?oKR< aۏۭhGEnw-0yxFL^X1HsQrZ-.0 qÁh.,0;wYP՛ bA &}%,lCt\kMV*b||V|16?A}(-@3  .t7Y s &bADUQ!'s_K/<ېl?]Uhg#F*@dTf!rNb"`ek&qF]sk0Og]mm-jmM۹t&>?UTI^spۓ,{EY(&s'`KsTC˻oL:(Lj,޼a ±#Ӛu0!;ls^V(KoMbMbeCyx{@IGG~#&}!b&ab6+̍_ŠE5PaEj;^ִt|Z 8nϬgoq=A_]vdfCg-Y+21Xmx[ܺ7;o:?BI C@jd:gA,Jj.7rw VL 88JbZ@>"[*ܺ)`z]d]Dofdp)>;~?'2)IHbJG݃G?eل->oB``1oIN~p3&-ۗZ {eӤ{9 0_!^]쪘7۾:p}O]s<D?w !1%10@ҳM<,ca|7.?fXk֊n kVkk1Xs`y^/Ο#|C5>aW0dFq|ml$~aqŐ-(6 !: tWYF@tߺђj ma A gIT1bz)ғ_HD:-T,驻'L'ruL0(:9e]{r=L 1RH! r[xL/bwh3c<(\1VbK@K@Vk*CW!X os*MDTw#Qs]s=kz=NgYy3[[ּr9^>_-?$\A:!׮qšZeki)X %B& S$I)Si,ZMgwQ_<8(c,s)ݗ3{ "">&Zai]l8-{btPj/`Ͷ)0z`%uQb 4BN:laQ #r@DOUO>v**0\C ]!.fU5xDט)q V ߪ*wa-jm[Y( ^/·^'pxf£5Tܢ\nvH/&<iဋډ1,= V@+,p@S[{5DΥ˄ArوM@R~cLg|#p1rj`;q t \@>\4"\1!8>f6C/{I}7P8.Mvun5A ń*|6VAoGQ^? 3*T7^rQkXD7'b3 7hU–X6?_fع%,VftyP+w& ]*]dUf:a"h1#-H@Mk! 6H`}Ty"y금3L[U'Z%H&s3<5VgQ$ S1HqӼO-ʏ9Cm]y8ΪTFx0D k"'(!T*ɵ޸m,xԦbɍ0:PDQ7Vg_$At"Bo;г5E7 .5;jȋǓ4gP -q~<ߟC0RHn黠Ơ5l h;̺r@cQ; \'Y|VgwD ڇij.O3cj@Ů5Ʋ`Bx8v0g5>AmCU" / ( M iR< +Xvp}qcICh;.֨b ,K3()GHᆰ`av.5?Q_#I5PSYI{A;pj&I\vo;375}cBDzQsL0FMHS4[/8eo⾅{׎jS&Tw qbD.HMBFmF;] Qo_n[H??/]23?Rl3/~kVkkBWpǝ4@@W#P&jȪT F+QeN,ʋ!E>8LX)meW.QDI-Zh"-*FȂ3>ؿ:y!`7dT p^r0@4AYt} &>3KI MX."A("'2TB8Pe vJM`G`|ƏE`)=ϕiQ=?jNB &싀Z&[5Um E]η"Zښ " ?Nw/w>H&#ucV56L.g{\#!R9y> ~̘V4ݩn5hd"lУCsƏct91A+b{ E}RkLgVy~muSgse1Xdِ*ѐRĻpKcxZA]-QK(]& M Nhy`Z5~\Ldj _a׾}gwp>h8vWZ;,$Y?N_pq_cVٞ~SʭPeltYgzn35;  = hշeXhz[V/Rk38& Mʼngh]R9 |,,, YE[ԶS~_gت~˸mܘ jЊɻOS-Nhm%gp>8My`Ŷu"w#ns,N|=.P,XXahUaho{_q܎/_J3q1FߍFf64Z)'fo"GDn]w!")=6=>3LW o&?4ƃoǎHV_"b8.)i9*>-¤WsSEX2CN7G7CӟrSa,:P]?I9ݴ~}x3iԊhOyx>mVmzƲ-uXZk$\v코7;pa{W~c+cu-@MRV@2"/˂),]xiZŠا 5dZ}lYtw>f<5d0 EFn}f|لgd R5y2&sϽz%XwIJ+!%|+D5/9'@koZ8'<<5;]Qh7.ּEK_ݬ./o8;kjY cM,_ Z#&|@ {5Vf:G INhă-!$ s05Q&We$f탠v@ߘ/vQ넬+Wʍ~tmK)Y_!Q9@*\?=GlŻւ[֠Uie=TA_:IVF{F5=Cvs.YFe*5]"r44"--{l1ֲAފZk̑Aknyp?~<,Byl<ԙǎL/lAAUQ+J(u1R&b#bGHD-[t,ՊYV)_J^F!^Fη0/aP(0P+rue6GU?f{4"d%4$*FerUnm>ghk|#sig r8օe |áG· MQ]Ӹ2"`, q[-)Sp 58` hEn fBm]X-cbbXVkHAIu}ݍ)X ϶xV-cD5_HPE<$ Fk6*'χ,3 (Uoxqpz056ֆV(MrNxwB`m$k] +KMJT? ߿,nACps7, \2 B֡w#&gʪ05 ΞyiҴ R$$iQPϜQ[5w4E WqH=Kjry&|ߧZ䍯p%#:P[ 1ιm&wI+kQ!ͷeݽhmUJBI$i6<_;Tew\{ҏwU ןj'Wb~r"m x{nm ƱI:4owgw8TXM_=0f1w᳷y/8 [H ]ڭ1NMu4v^ Mƨp45ɘ$ v}>ȶGؽc ,L s:#3x)v9VpjHAREFQ ' wYϷg&ji $虇#F42 *ӳgO\-u[`.LQ7/g]ocO7~{,@\bŅMU4O,s Q2,3fUب1V(<Ut@Ry1N2GyvsSg_r~ޥajj}ͳkF`x{r n-jm]XQzkEldv/d4X܁{9bG5Qf!.Hk+7b>KuC%(ز5.,AE *PsEn@+Z۝#E)S;HϬV8gQsm5]U!KGw@{LU.Mwt: W\.y!ոVTwqtBF݈H( 71Ъ&вWZ!U)+㟽gG G=+3H=l 3"Ty} m+d@K{Xq~WjZk85wvn;p520+ ]&l W1h̋IU9yS%J$ΕGnzzT'rQ-= [:? UwwWDWh`HTl܎ GD.x&V!nAX=cE3 =u{P6ڸ amޏѤ MwʄL菿?ٲc9}? K{fn [Ukz$ ?4ϝ4W,0X *˜,ȲE\28-d܂YkKӻ7ĺ5!43"CDPc5=0&0?6I(Юd 0Eu&đy98BB)_eJer2o(89jǡcPʂxcJTH'R֟{'eVqbO2i}NsimƲEZkϡc?opÏr=+'63 kB}|^ ͳSZkQP h ~~U$6ca"D݁+ uY\^j85|sb\\׎"T$G$1+i]o)|ܕO#V)vE Aune"I(*-WWV^XUs0ΓݜMwaÕ7QN5Wd=hqYRxwIA,GK,/gyy:joir ƲZ!m7mKy~2\VU5כD[R< ƚ$߶;+ IDATuuP*(F4f6hʭic|=o *Âτv0q --Y,ߖXurTi?eYPO0IW6g};o~ } P,'0Wչ&,Z$MHS\7tvKw-leq)=Vtf>6C,s)(K[fR{.@bj~CgyiiIhԎo`t.z!;;Rm֤ Y_bƜInVtBcM!3#VyJYpD-}Ilزs{ z6*'˞֖ժ ii*N}n~W=mSgPZ 4!E:,sÑ_gKyޝMy%a6͒(WS^sI̽ Hxq GWQ2pԢW/l8ug" JLr6d{`j Y`eY!(0@ҵ3䝬s$`j{dρQ1635 K Kz_oƳ<-QX +Ks։`q˶H}tU8st,m^F*#r|yUʲ,Ke] [>T=A/ϝw^v ^TkܚE1,GS`1h֨KGtg.7{90~dRHUMT@ S~<k_Dڏ\{yH\% Ml&Re5.&1A9C͝xʸ^}( #ׁQyptp<S/we h錘]X8se>}8(.pOZ;f.L9Z/s?;曮2 ęNAkD9h,DT1C,A㔥_ҤK(.;>=!z9zKtH!;Ox&Ï;ؾII6MeЙOvBFgƥ#3Tm a?ORD+ںPZ`(߹Q]ZRd(e:'N!0.3Q!TAYtԯoH$1u[|mݿ]ġ:K$$/2 4$NU xIiH<|)1.qUހ; }boumFgjv1\Y?5͛_p 1h\yMFLvZג*eed*y6 ˆFˈǂ٨{ǽڀMװe:6^\whf6Ji?bs8q| r;uVqZ! > f%>Ȼ(2C#Uݢ()"!kmc cjZ)@Zk5džYwMp60n91;,8Xܲ9}εU:X-eZ[.B `qV_~7x,ݵt?LmYk} N* ʸ̚5'8)<'N1" vgsHi(sU8t/r,՘fRXxWschbtb4t!)$ey%( yn$rz`wAGgT xqXi4$Q"D!s?*ؼJk~;O;K7M'vzy:(]wNKW‰(>H:fs_!F 8iW])Iq Ml-RUsB)<΍\&" f֑7/2:Xm56.֍$\Tw˖8}x&r A¹w ó :w3J^e 4"MJ)G R{MR>ҴK\doL GNF p߃Pqsy9Wc*|UV`Vq0#8x(aǕ7{x ,7dxܖճ rN4 B[nW$(#]&p$&MS2g48 WW!ߵw!۽zQXUNfUa`mkVkA{~?|o~1M.@ŀ˸-M)]g tX"r[p;ERҴORŐ헝dd ?[ )m܋tqGb/ALZՆ->(|@ &.B l,ږm=ps[TK˓NpI;].=Y ,4Ơ,Ghuh!ANGpYzze 7ei21Ԕel":O1l7l S/~͵bƳEgEmaV^_8֝]'/ =9Q,4^9`cŵVňQB>*1<\n%q1A)TnڸnԸ3Rm n3,C̹ͼ-Xq&bx=#"smyf(*e9b4ZeiKKXYY( |H}*͂@3R]Vd8"(k0r{bqK%s;<,d靑{PZ#:흝P1`drhdʞi.&lREQə$0Wq<P* &hա,3UҎB+,2F|;zݪp< N] gdhY\mgc+d9bL12iAvT\[:ض}$E( BTxߊ?-uƙƕ%;:*[g,+/pOZ;_ ݉Z;[X33lnٹ 5k`D,]? 33vggnO7tg?#0`5"Dd|O>XpY}'deN^ {DĞyuyiƐ$ BH  h bfY+Cٽ,=}$ !jO,:S+dߦ;~Qw!/m5?> i!M+1R ,`|I.Aǣ9X4+[tY -$r:v05]{_ģ+_.twZ;1. +Ks4ȾŎ=я}ӓ3 E ݔ4jASFt3e軾-΅Wۮ暗_}n ,UAF§&h\v1NDRޅTA)-eS1d*z͚[t냌\io); n:ǼbQd"p&1r}Iy[a,m[|Cv80hցo?q]_;r A~_`zv4RHW@JKԈgU/;'={MW^ؠY6fKkڤ4gF7ڿcԸdYJkN)UtZwug, τyQ{ײU~gtt1"ąydуYDJ^~̀͢n?fnH#Ƚbvt: "dYgZh=X* ~X(Ur"R*0 ԖgLΑe7\!1;+d*i`PuV\: <}s:IEJT$-[tM0. |MD`F GǙq]udnV̤ٶ"- /*--W*sJU%t׋lfvq< a^e6 VkTcl6&??ַon*]#}(++Kh-Gt:S#+ !Uw, zZ 9[зӃ/Ohϻu@)Ctcǘ]Ӆ2` 7Hhk-jmYYӋ\hde+oz~_{U<mq˭f08HL3i+,-cPBbvP=_>&S V[vHI)CNbdi]bn*G @B$IctgkXp%-_] )Idvi]O]b0Xe8}:1`fguj]Zں޴{.w$_=_lrl'M#pXEuoD" H)$8!0 ij:.ǖRe$鑦gkvVF?t(UcJ:$EXm6uc^}3X޾Ws'~?;C%<"ϭVLR6sh]ĩ[7u5م(JR]8:aۯmlןߛe80CA$dȕuQ(=d #I>ReF"5Ib?E1vx2g,)] R 0&)Zk@y_T4T`. %T?,+d%fỲ-)t>EaJ13>FRl37+UkTi7r{^| 2 1ݛzعk:/.ca @Qʖ> RQ'5º$epVLHҔыX^K_ phEQ'V X]=,ȳUFrHQ s3?D乕٨eCoV(]+Q)ߔCbHQd5sLE GϫaUjA뒼gNGk8+HQ 2f/MNcLI13m$@ee4T$-IM2ݶ4NSﺛ8;F6vVXOʄr+8Xzۘ^$IRVz&0lCS'癞dDF%Sy=z81ǿab,!ټ#of|א"Zں|Iki~g~_ؙz@U/ m-UrAɕ.?ʞ@Q\Z;H4"Ee8<1et)pL~aw15@7c39yk^~/1=X"ҕ+d%|oSݎW7FQѲӰ*Iy>$IR6%Ot,q&N֊BR]컼>~`~a'ssIi:55bwB(z_4FFBz蓤iHu%[O0\r?%LsW|X+21Z[z lǞKy;~-ldǔ;RpД*,32(4X8v/MR:箋b8N?-+g%(J9?nK4ܒU؈H;'z=Sde9=i|Z`L$iBnz!KG~7ڝd6 IDATBLt,]qBJHR](Hgx4B$(U2$ KǞ, ۝!tDAYL} w{h1h/ V Sٕ {gc\A9$162n> Roԗ>[M(!eB.W^?~.=9(ZcL?d^vxPPf>Q%3h,J+WswŃHJd$"D)52Hi(PiV3pLK%gop6}cZ Z[W!I{Vh/լ,\MTi9ɕvc#1/$R"MJ/lْ,3&-;>iMErUbtI'VKsTC&\V%J"#r+{0˪xNt74݀Ҡ( ʠL(8\q&1y߫1Q810AM"*8LwuMg^k?>ΩZ穧Nu~7|K^VPV8-a9.˶:/nT˄xIh $,d\YB Qc^ If'GJϴ-K eB a] \ZՖ;!I ˊ)}VG~|t$YRB)IBkyNbň>]vw*.[ r2bL_kͥI~jR[0Eh*X+ k_/uþ24j-3/ sȆ |㳷p…a 4X*_+:m.IiϦuGʎ'.m)dGIA.Syju ^߇ÉgXPv:_BjߨG~iJ Z}Gԡ395ӜxV:' r\_v$3y{8)Tztnr8~Y.5~S0,+:~_sr5|?niR,ta9vj5mV|4krJ;:QQ k~_;ﴕΥLy$)mT±љS9u]I"Iq'ʆ{g>wk;!! .۶-D-]Ήsр/44zO@_ q=Қtl[!h4R'(Vebg ۟F/6mۜqBA**UjJIWXqaǓe,'CRkmFI'JU^&&2/ :aT' ݧ䛟Z/ )% DZq |%YVH(FI.j q\*>^?ؤRieyL5V`bb;j$qBDa7 ~^/;B UNVj4yLh6wl1=TcUC)r~p"%?WZ+B1q`[lVW=S.?oj'Q]Z3zgmB8-6:KH)ɲ%#ȲfAƀ6Kr48H脋mTxVe~lJ#\fh{-Bc/<( Ĝ$iQ$rce3ʪ^.Զ7>op\Xh>m9HpjwϗRk-kFTVfŰ쐲x60dYB׉:YhL3>>fXˏM~pFƲ+-pvrϿ'Zm{*(*\O:g7_UJ]@Q%,)4cLN>^87>v[ٶԝ? 4]M;לL4I8}EEz + Y^ˉ#v;>w^F+ISjSLMMEr;E, <$ǮI=~PP!eBa,KtWqɍ[Q*'I0Svɜ^(L \&yS|ߢR{~DagXb%A :Ic1KMjlc42,;Ըs=9GZ*GBCI$ ,aOjMh &w\A_$iDa@8i'?yސ HxzxhW$L&q$aVkM{?Ww?8vTk`tjN(U><&SS1ELnwTh(CheYT$7Q$&A8512axhjeÍYg^vjT2#NZIZa;e[VSVxZ\dL1/'eTyV9ir!C5eH%JP*!"°E$M3Ta#2Y V7ؗ27 ͌`ox;_|M%k6 gC_{DR!YfIu`V0y?BUٲl qpimIVa$QT/kl>}Iw,cLxNLk[x^pa/:.,Uln4 f%VSAa]om !ExD폵x:#H҈x^aDFW6+&Sgţ'cMַ/}䃥|ÌBM9fгnd`8UO/E%CfI@LjMS~~ Ba>OɳׁQ$-3/;3/;_q/L^tV}(*U.R\PPT bM(,2E9N,v?]m핳Rؓ4CFᎏ g{~OcIbW"+&gf'Y/};CI/kv Ncy}ŖŤi@7&/8wZk<ԶJɲZupM6gN9@m!ʙukܾ4nU~ a҅ADŽQ)ܬe/]Oc˿~s8NѣVjgQ`6#rֻE腍š'W{MZ!*AGYZ)QV+qq\m(eGlz/v+2B+e"ܟ-|>$UKC19@Wãkx{n3/ySӀakv¥KBHһdAQ)$KC rdޏelAz1[4C^yX:ؖsO{C̒dfa)0S=w_G[@ɶTJIjg՟eً\~5 pL#pT,<r`ۂ " 'hJ IDAT R,[`ۂB]))Kل(jSa hP5ʲi mBXH3p@SOMO}׼j+3(*;+VtGYlX:dmbqGnEiEv-9n.+Sq>8w:lkIA1T)׻_4E% [*G1W5?O>,RuJeRD!ЅiQR"͆ :>iA{(mpy4[-s\Gຂ0 su/W|C//jr'&Қ$ia']X\S$XeMd>d+-W}l9Y3WsRU$\sg4zO>ƣ_5W⾲L hXeˢŴCk$I؎M6QIBK<},U*>Yj8Iq J]}nxP$Y@'QL\e_ڽú5,òDvͤU7 O>]ZɳPu>?֭69ѹ|3?yT#7`E¿*R $%+6k09KYI&IqhLsW5°;;m_, adjjq&'lj8V~ހK(> +0"S2,sTÁk}3_W e{,dmp癬m?F w˷[` vllzzoZRس1KHR9BXVL&BXHg؉e( Y7z,k8mu,}5ZyՎR BvdZi}t^)+$@Xf6q%!$ϳy|4a˲=Ww^[K9s&-<?u>X4޳XT>/l(h-;?7e:9)=0C`%erijajl;_[\yųawr ;C HGH)ƶ omI\kEFiBF8q5<}\'_pq?z Ŗd%dYLrJ1w [#^zv 5NJg]W*'ض8ĉ$%?8yWaṠr JI*mv*Xe58abt(20a W]y}e1SnqFR6~e14yB%r<*QD{o}͐ %ROnFktyqo>9O>3k]wrz֜F#Kcc2*,%DQ(jE-tOe7\V#,I,8{{n.?e9ؖeXK(#Kt&˒Rb8$-SLMO'1Q>T-h&+G %SZQeK7d*X3nXHYnڦܸƷнѱ]w,[^qzGSkIE?5TI4dyJi4vPoj=ᛟ*Px3HEղ &v$ Ű}X'ILپo{m۷E1AP#]8ohHQ dY@զA^#I8y,{`L˰,sUe_ro[~2noP3qܠNme7\F"eBEI(ŗ5y>dyygs#h.U Ü4i DQF}VkVF(] ̈&4;0 Q쁙`T aYr_άݰk?T=m'̉2v$׽lQ_u*Zk<ŲfNm[!a[ Uߩ 2,)3JiZj=GZoXXF+֒{voc dYL6i4jӴZ ¨N54tnu<.̖A8A+رhUx%Omg1eE-8m; /cME T m?xuqtU ԳCk6?(ox楽EDbIvZ),&GTV.}nF!Ӑ1y^ +QX>)"0 0,2%Um򫃆+6~͎]+YCC׬"l.bsɍ[ġYD a4Mh&71r|_C>9=9q\BZdYTAj8 lȨLeX(YA_rͻ7Wf76!xy엏,m,*ܸ e0Qm^#^XVQe,4B`[6tL˲~|B+ql%3,Kq@']>#8Ug2FFJ(̗A5 .eXٲ/2&wl[߽_z.B`рhK9̪b#S=|:V%l, ۶\JY J+8గ<̓r7@,m,Ko:ǵH3Lz0rkJN8`W Cd)o3V[=~QpUR DZp]VG}`CX 9aXcb#pԯZV,QZv%R(Bi{%zA3n0 `XVx˅LNA z~G=KœThAR2#Ie˪1ړ(v0v߿ Dk)Х|y Iүʙ8_ D4_Fm?C2 . ̋*Zy\G繛g~:ɏzϕ!D$IsӄA5AZiFOzl۸և9 ׭x [mKm{x@Ǖ'r|<|_!qtQt6+#2j03Xe, m"\\oϟxffa;Y߸=HJSQJ'-jRoc]?c{XV !,luKsԡh֦Yw5[q,Kd4Z;[->)B!ݱ+eJ4 *x~?QɲOIb RW:]k.M%̰\a'/;>ծ:m_<å'yBDa4i&-Imz)j:qRu^S¡tN'q $ - jO3zJ'1 M*X瓜I ]W Y[w:X>VzRC͋N:'~K8Ks'bB$hL6Q$g/+r/IW>B\ Z eN5H˲9ړ{v2YV3X6oھ1}|1̏>_}Y6pOw?#?ŀB뙙X`qتa :X2 R KHQH6*U%ϋ$7e)R#IV4v²l,撷g-BC'X_5;)-j__[OI!ÏH Z)aW++V>s¦ mIUQzG~Q'@BYEX$Rdy' DKpy_ cӓѢW |e!0󹒥=]g>_3;yVo'{E"lWUx0GzNp*WbG.n 4ɃDR7 Je5JKI9SLO?qh|o.B8EO-¶mְ6M. 2P8W:3eZ+.jۺ&EPRST TVаHtܓ3fA3ic<|IJj϶&y5ƷAJa7=E"I&$XÂm-~)~8O?QQORխ*9 N8CT\86,G_m{XqL-u˚"Q*U&MmLM=clhqkŀȪ ;Yj\JW02}т1C,p #QOhSny xT TDJR? 3fjw|\~Efm }y{EmY`1׽&n}-HE5mXݺ(17Wo|\J!8kD5 2IDAT+1C٘`qG9!CV q43̈́iW-];> ~ǜڋv5V~>!mXP5׽殮?@ʜ:z'MGjg|{o| ){4wk4tr2#M#,!IBGQX Y]|^7,lL`XTNFLOF@1|;834խcfJm:6խqoV]kWlh/==N:%Kaa?e9<5Z-,qu}3eMOu þRVgxMOxՎil$4R#jkn;S7(VCySgd!Ka!Ȳ$qBi$LN󆈢W9iS28V*Bgk`Х2010qAT4Szf3CG0]?y5]H CRO66a(H%Y0"4,CX|pV9J&r?S(P۶cn[QQi5SЈ/>}w|nSh=YxgC?S^đZ dYL4*{Xy /.rtm 0 8NcXC5) ;I9CHSqH2ZSb|ae36{pp':!RhGm2(9d2㗑H\l@7*B=jK Hbym--G`RA:UD&]D.ï; ?{ʟ P}ŸOX:zk$AP<-_4Թdqhen,,95rYᐬX  r-dEEl)?|/b!4W>ǯgÙ_22fێn5 mlU`Q;NQXpHx}bXKHed3MpGg?6F#*^yXfX}XhE,vKé6vPn)B"ڡR","T63[Cf7f(WnWzo8q(E>xP`G+/|zI4T%k;Cac_:hw Fv+p{Hn+-G[ot/d3{/}ׇ>Dd}C Vy 2!FD6^MEnܣ+aY/LiJ`)YpJfv+4PMNM+{X#٧^S'77 AAXVm2 P0\|,rvCX象&j>VŽԈfɖRA!3X U| | ̙pJjj5hDoNdq< 0DZ~=<<.R W@,2XWws}zԊ,"Fvkzpy`jS?}blZANzhtO} `prMFikh$2.7p \F6=Zpඕ "nŋ@!~Q˯G>W_|ac%YTo?hN"(l^5[NT-XF2.#,63=o|)\X ā;:|efH.@6N"M+z9ogo)$2*^t8un=s٭|SXZ?۵i0:5p5!3XԉUvJf~1]ÅnbZZ%8p؅a 1OkT$? 9˪6tYaL&Bv@& ,"."ӷX>3=go $n!}%ULFfժ~* iH,C %"S\E2.7Yuf0P.WIm!#ҧD:??,zs⣿[CF# r }X`Q'EDB!WB!WƵ, p/["綐I 򹭁yׇ~lϿ"i\|5zI]+ ; ذwYEp!K٭Ff,,;[2)JixoGppdRjɈrYLѦ*BjUD)2ײx|x|kf08r?j?j!?HŢX~G4hHg{cpZt`M&UD&U{)X\n+^u *00&E$brC|i΄7Uߩ1>#"LODd#`q1""A)(7?p A$v[-Qbfs('׿~s8rXѶ$b2b_?,N6XDD}続&ۊ@-* ; ;锺u:YD>oo|?ۓ|*Ԧ\"ۂa# ,NzH<1"V6ؒu djBX0T5ȅr+Pe޽pGO1SXSRj A @[5XNDE ,bJN`s=lZA\haAhށÏm_*&J9 W^#>XDD#n!Uf# lv3`w?i  - W} s[ͮve>hl2:\#*ggP RTTsV` KK4K#;?hzܩ`3YZfI];C,RhW?J ?Jyq{w{~1tyTk\R" 4k:a u3uivkCm*R1D)Y}>7N Y\ƆFKڕ ^D#jᅻv:,M:{nRhiXUfڌ/7fZ꽆-'#snTzemZq+ X^ޚ_;TBF<&tq>/="/9= XEmFO?= aq}T5/S*U""ۭ Z"^ 67Heͭ &c~ɉP؁:O5Xo=Z׫.Jy:hޭIte{VSge=;p\:Ȏ+A|?~awߙTB9]jWVz;WR''WN5#B͚#N1tҕID/{j:-YkL<ֿ;ݮEfhƹNyW >o;~/! fuaax"޺ZyD&K{[xo=f&eGsh*YX5{wnj|tDdbI_r~D7H~_S\BnՌS.w#)xlҁUV`h߻DZDDD$r3xmfx|"|a;Dqy5\w.t[a2aԸᘙx%\\a3&dB rW3얿^tY B ɸXȆ> q^`ieiSǗa- >մDh흥uݶu=.-ODxѩmf,,KHd#$2>6l-=35./!S(jtC3XD4ڷi4+պ`/^:rFrJVx" 8꿽~5(4G6rm%`M̑n:r6'=M`fiY+'Q(r)nvxjvk QX*ȦH.ufLF)ކ X_ \VH.+uT"+ )`sV׳jw!=>Ɇo& Hw R:sL :_;Ȁl6Ʌ\JʥSNx٭yN!J#G"&#awh Cn=?[4MAFk4LE5C63uQ7^Na7Fi"(Ufo*SMX?ȅpmUmEH.^ ^ 5aݣ,9,%5lN2"붢OCT^}=_Z[&y2y36Mo`2pP9#2TrCvujgwF;#{2J4Ɲ.i~GT.Uqm5nh(2^gڹ] 8hW{ad EDAY~p[|-bh_Ep27MgDERE wV;'229LZ2<4VN_1+ѹKF&M"}ll$9H 7X` ʹRDnϒ dw\"WiBq,W#{5hL^A&$@l8ܴh57b3:5ZXDDDJ k4֢i^$2X'5A"$"""Ffνqñ"$=I B"u}o_ƽG)u;q3lx#"jڗ[ݴSSDYj9Kc%1)š{܉f]N?m)A@0N[ qn3=;i,"4qz," zeXNDaED}ۭ}mXZ=}h ve~#"Ҋ Q1gȝb,"˸3Aiw'w"Y33}3=V~0Z`LL"k3̶6TW4 L͍5kf"i2,bq:Ǚ&"LX@uqQ #j7$D4Kj5C0vo04ޠ~{P5&MLj\} ,^;׼>$q>5se,Y2Z{V?칦yXíRyo>ʑ ܥ+M  ߛD{ߞ"$"""4XDDDD:cEDDD3XDDDD:ӼED_"bHg tHg tHg tHg tHg'PRpIENDB`v_sim-3.8.0/tests/exports/map.ref.png000077700000000000000000000000001370110300500213142map-3.7.pngustar00rootroot00000000000000v_sim-3.8.0/tests/exports/planes-3.3.png000066400000000000000000004547061370110300500200040ustar00rootroot00000000000000PNG  IHDRXX1sBITO IDATx]y<4ą$IƒǗ$ˎI͇|TMU7i>LRId˞q26%kxl4)KD $@B4r^Z{ S}\p=BP(f B!, LSP( 3MBP(4E B0!, LSP( 3MBP(4E B0!, LSP( 3MBP(4E B0!, LSP( 3MBP(4E B0!, LSP( 3MBP(4E B0!, LSP( 3MBP(4E B0!, LSP( 3MBP(4E B0!, LSP( 3MBP(4E B0!, LSP( 3MBP(4E B0!, LSP( 3MBP(4E B0!, LSP( 3MBP(4E B0!, LSP( 3MBP(4E B0!, LSP( 3MBP(4E B0!, LSP( 3MBP(4E B0!, LSP( 3MBP(4E B0!, LSP( 3MBP(4E B0!, LSP( 3MBP(4E B0!, LSP( 3MBP(4E B0TB@LfP(>=E [ۂ$$UG+X(>E [uDUM ~c0T0 [S*j1M&5d !la[tTqj$u0Ĩ-i0 ["Men!6UPpb[\C`k*Ant981UP(7s` 6xHHmJJB8T(=Х1F-¦Ppb١+q}C@z_%T$'֝,MHcp(BXO u,O1pIv9 CpD(!ԃޣS&jhlJ+BSp?_ rݡƈ *z1T^98{TM8i,>5E PBv^4;,-4V0-4Zhl4"Qp`Mז')3w}pDj' u*OOe]5M\擟Ba&(BXW,n GxmyyH0fb ZJHuΛspێBaKRp*ٶ}(0,_=١M&o*Ag:JA&;hX&z,SpUۖ[2+G٤1N& * AZ1tiMI Qp7Y1*eOthq@ʈ0VUhq8'N&L4.q"CUhʼnblƽkPI]CURı$$fI64Z&5 8^VLO4]_nj+ TuEf'd;i,<!,|Zv;t]t0H+D^7ƪX2~X=X>E 0l9 B.]\+ЇSkԚF ZBz UB`s )AUD'4:~vkE(BX,l,ma/_\Ci0zJE;TEa0 8*o38F46";F ,\'Ѝ|Pzwij]0TE`$bcIlGOC( E wpT='ŵ cB04\4 O-d{x=^[Nxnjd0ۀ$:N&iPť#k󫛞 B/!0QZQ!6v-*iMFo*dnn5Ǧ8NZ.E w +WƗ/!mJBB 9Tz*!i |`GMn \VyT PփPKDZ:M,+<!,ܚu^8١GMHu+pY;a5pid"[8N]Y*T 4_I'Ei,&E `ǮѶ!ٕM\zo TgkMA'@?-%\xԵƕ,n#V a0U-" `CTS|w2 pcnJUɮ=sù KQm2\}[Y*z aLCdˌ"fB聅O-|pPfhsp\Ou \`q[(xxi1E 7c~޵w^Ȧέޯ3\}[*SFxν2uO)M9%0aU3ţfrZq>Z{`?4*l7x8n6"s!k&62\}؞yպ8`<"  4~&QT jX8VܕZU2Ua*\"3BU-{. VSM4eϥM)趠!ՍB^KAB@̛2f0*ݿΙkOm!M[w?.Q&ܨjYXDqm7nAn "zEXϝP;Dm>7-/7Cl zEb @B`PfT?Ι?.+׺T7Gj0JA9k!,$߶43˷~8EAZV@hfM2ʜ8*bUԟJ A!ժ}~?)q0 0pS3Lt}Y_MkM"T;a_8z&;i63It0jn d0;!S(*7^YaSX|8spIR7sc}i&֌ךD4ne:Kۇ{-hz-P^kjf3n^ SV a /-h S I2 Wߩ$@ʗ mcW-"BU\5MpT8f}kVp4{/,mp 8-4@򖦚As0x0]E>43v6FD>7y[@#Sp3m,#_|o^4M[k+b(KTԉ6ךD8M2U_pwmzvFL4e)C+r)*h[Z.4Lmd !k!-Ê))p==+!V hm8IKMf2g3V-_K-&2Y]鵈pFe8ZZT尙ĵq3>!Ev X4Z V÷R`O P3!gIlsev@S?spCct@Sam_Lt2 8UuFsUu=@ҸL&H㽣̱Ҏ!+ַHvuX %1j2f EUhwMVnY4]?ȥ嗅&bBl%f'8l 3Jn8g;Όo^*rՙLt2ok\UB_%Z3LUJb8>}xzʥ- Vh$Qve'oȬ/]3Du=n:FLdD^ˤ]dY45uUTHx3*&=7/-|pi\کh+o:U:zڌZh,wLYaѾWS_yѷh)VzHqIjT *@bW&.^yTBG2GA;M 1Bf1MN^?z@w?Phlך5lѨn8QJ6fucۡLpҶm.}xjkC;}Ie]iT%\Jh0l`*L@tuU7.*Dd;&N  =XNI>FS5<䭋_[/l:kM?T=_uB`hTmߕR|meL&1iChzz vĕWƷ~1Xy* b |oLSn4@ɰlN;G/l҇tFU=sGCB=Pc(=JcHV̮=sXam934yG^PP=.̶, 4@K@R>d%7gB$ka#b/<%G0-WrhT( D K `,D%ph+&6iݧjn밾l9ڶ48vuSW(Bp<'˟97~: ~c$x¨0tP@A Qi (01eYam)RI|jOWi <;ufS(z~ !XCf4Ra=YWtfVMVM]{_pmyrEB޻r:0jeykb~RwveG*M, 5Bfחo;h 1wUz8skwݙY@K31 $$TEWޱ~lPacyvu|ꃫhٸoEl4Vh Ҧ0*En} IzrE*3b<}zWV$>űY ?&֬((7NJAɶX?#<$7֩D(L3 j%BAmU+lW03;G||N!|xm_>ٕ~v肬]QK:g2:cdE6t ]D&%hz$g5IN M/3S@K{GF9.JVmed2: eS}溒Vj )a3O7"\+ iLҟ`߿n:VBwx~GǸ%.E ==4QOC8Uv3h{;dQ;gX[30P.  g-9lsYi%Z#E*ۿ+Wy)9 |R>ߋp?ﮞ4!KTDLhuiM25)~𹟻0wn1h"ɅzS41櫄qBn*Rs-ZJ)T -RZ4o/R5u-7z%$}qK1\,rysxP -Q&9Ԏm59yftS7|#\v.ITXM3 #?<+Eɂr~i0҄IӞ!h3[aNPHvjlTx>싷>W:IKJs;dkQt=K'"TmnR?$SO!=^aiC<I+qI(G^z^ۼw%r][&PfcB\aSE -TeЂA xR"I{f.nB5fS{WkK# !Sjw(l[" EEsO,Yco &M*iۢ=TZ0Uʷ@=eJa=ĵGE("}fG|kDg"~Lڠ'HC{-: %5 Ő¾%aݿ`\Z[M.Ƿydcn'}Ctr)T:X;Q/!(D@IzvDZ!5[9%/L(ygTE-%aiUPD$H Uܪ&!1i񓓟]~ƴu˶drɛK =. PA%# `aԤ8<X1T*]p?s gS4>RC@""A ue!xeG餉Fb2i;kn&.ukwbs[LS3s©􅬂&~|fdc+6K_+:CΆku"&02&24B#(w!)ؓ|m6MCRUt9A^"f$0VUmBASIfz৯M7a5ƠaY@9g3LVm fPC:F@ThBIY==]{|cCڦ9XtRȔ7 f! |06ThzH?'YU/oOLSAࡥG-|qĻ?GyAVttu4ؠ/GhBeasD2evi0B 9\41)r/<ޏ>aہZ~[A]!*XB@UDLmVmş_!篝,yۅ&.aUi,¼pYTpHI3d{[ ݉i4Mr,ܭɽNGAf/t*kIǮhMBN(A _ P1DA|E o̓윛؛kfS`0 O>s~6ԉ+4ЩηɴH *PtY z>*(cIx-Tr,Lff5;4y0l1BkAmI?G4܈i!$dh@I,*yRi(@Օx`〮ϔl72+iP_l[DE;uTHSh6"zls_ISNl+M巷5BX{Is'E!?UlCK;v x; IDATF*(%SF!|رk3 5'޽)G)9`Wn>[W(<"Uw{09rEiK 2+*LC~)-jĽhӤK *[-h,`tKQ R>:{KP ]⹖E P@*Ŕd%` m=NF_IfmTP=`W S/J }k8Pɥ '_UhJinEٹg< >Z9~gKMkER05H176ʜ"M(&d# q0A!)UARẸgSmJFo{=;}sӐvpSA166M$("4Էdoj?g PHԌPQ o@`{0;ۖiqDC+0է^;_}&6x/RO 4-;SH‚gۘ[)4-!A߯1 "ЄiפtZ/d܍q1#~W ӿ)v5{i58}f"[?ݷ/]wn:̑.3(`KG,A"fhќb 6y  vzjB>z歓omc} o`:, V?L9 Aۨ>y¯y QVJSqRK?ڳOC 7ms0\ZIkQ؞)KmIfϾhvc吖;r~Lfo˹KfZæ}6u*i&-/r~^;x+,6c IfGNO? 7/ݺvoH­“ܻo>ڻ9I.~x:'b[_p@p1O-n#L]oBSAڝ3gLz?mACgMzQ7v!DRM-佊*@mFJ!`C#~3o)_~ SQP0fL@r<+sFkg >0 xPN!M0;w}4k>9mL/2ٵȾdBw1a+\4Iӽ@C5|) a<0f}Ridm.|uTM:\1|0ŏARFoHga~3 o_CoƜ- fcRBryTYPɇ~lčN0CĴg[BQA왃6 `Z!;Q4VZ^TV )@hP!gfO'"ux`42P +}L^~PﬦYR=6w&"K ٳ|Դl(i)=! VA5Y]5xOCJq ͠'&ߟg>7$i 2VjKf%{O%0AU@PH_>\g^ n&1HZNS,ٵg gϬbf:HuK.|Eܖ,pjr]&>bEԒ-IS׿(-"(́өo<|+vK?T k_J77<?#)6asSk?wtrM2s Ԅ ?YEWο6뾻+Uu kֵԕ^5j M4 c|}:Gk[@۷nYvyx &AEHe!6 oNԔ|U1;ODROPw ܔ?`ٶUJdxQd A 5*ˇ ?jOo '2zb"v?=w,c뫖Sf:&O ;LRZXWMzZAT>4 NT0E0B"ў3brI?=GBT/x=@%eo=9uXlB!g H?:@{-oDZE_V. __^G3s$ $5ABHU;@SD!fp<Ǧ?!L o{&NYs5f4^*a`wW"1ULi>;N}%%y\J[) t߿B VdT5* ـ͗귎T S;,/׶Rklu!Zj. S\LHҦÃG;.;lvoA:A5\TTx֏lWܶnb)M4X;l)?zn;mIg75/z}IqY*S xUPլ*H65(AcFS(luVb:!  :{0Z}n.  bmh3 Ҟ]U+? 23̬{(kϗ> xP sQ4%a|W K_ӟӭC@R}svp+Ǐ]Q8( r-]'[KiL$GSj~{_eg{dW4FZ'5M/E5[G SU 웒9KE#.ru 41/-iu' w{`tH߮g=pWA!Hh8B*jjAvw0K{Z (Kӭw_H{=]}@JVJu!>mj`f@$!d 4j6_K̙nCJ-2QSUgv;éޟb;b5ܸN{&T{zB⹃BV.Fi@in<2P3׶O&EX@3SIyӶ>m3n.ȫb4Smm]qBLbX€GFwt*\{ٳ}fk[Ht{ft+҃ߓԍنw2~bFS5{ЈX@<үE#t+;ݴxL9jޕS5{!jr\ClTf5?nA@S2wiO9A)dK,l9n3<˷6ʟS & }Žc?%Sf!9zŽU%MGzR lοmn)9du9{p_kN{Zg>ʯ7>ܣ.CfإG*/iI^_ueܛzLMU%O+BKxmUQB 5yL@,m~>̹׏f-ytt@RrNL}m+`Uj1]m-T&vI17pt(on i&_zT*yjֿ"큦>C#SSͯG/ ͓Q=o;5 LMM#r3@3SfE'h*fAgv9Z[m~ٛԵW+B"'m.]Xkg k6 {"C 0Sͩ)p~0 jrzX3^DNHOFv o+#R ى nX]ӛC,:U 9 SwOgɕ$KB( `Kq9 Kma*MJ̔c@;2ܶ&.xz k$M=xM"bcA,626ToL;7ړS$CG[YI ti:qH%ٳ[H3!`EG9ԜY~<+s bަ3d޶`ZeY0ZHo"iɍ&8E U%#;v`wn9ws#o`.Pf}Kҿr T:a?|F̹=П,ۋ8Dσi`@x[J d޵=Df-ZB60,B1 gμFlɶm7;T>^;o! !@`k; 䈂)CykL ׿֞4IҰ["U\tO@4@'-LYCڋ>V CϑA^mlHSoDv*35RI>ˬJ|ԈH1S`ELBl7 񓏖qDB"w=?=U%.]X}BڍJGʆHa,Rv 8[)ݷAIʕ?L4]&@Fm=|_߼s>\k]>EN^ |C%˻uU9L4^1@y{@3xRE&*$99ݷwqZ0i4hcrz6Ke5h=v \m߭vY&PU+ZP3f&$"܈yY|G_ ?P)yMTg)iƥkܞ¢਻[͍4J*XJB@!Эͺf^7^߾ڐOZ)nګ=mOA{͛a'4JC+Ov4ygoۥoF»̑gw=s網;g5^Z[`n\k~*?"myDڝ7lO8sѳVi q C噝>P㿎zM`q~bdBx|?&,Ccsh4{Rd{,7`KVDFK00S;ӣC̖v!l52ˡ,`$ gGQӮ @*|RZrLm='7x=4rR7½K#wJGE "},I>:F՛"^kTɄo#Mz}?qAćBAcG'zFfmڍ_$7}^&hk@Xqx[5|XQ1{aώ]sy0_[W>S! MܿAUjkFz9r`71 ol<_HJ>)!!PM Mfէ;O}>GfRM@A|O]ɉ?ZJk}RgC YrN:H]jhRADk/=q EM!AcE]/e#19Y.BC"-8 IDATpbp~L~>C0RώJGgC-4 "!֗kP>/#`-UV RCړ$*T !IfUUWՄu~[xSҙ?6*N w)=MOQʨhl@/'mL$I$ַ0>^_4+u7aナ~36oK6wڿUA\A|A>@ᬑLn~L@(Ar9Srк;J KS0CԳ_*1^UF$3!?tF酣Xn2ygU~ˇUxfVI  @;1k^#~j#:v;YCwTT&!_鬯]&s>iBz;aU9..ezK5E "j(A#$^>Z"R<'H*xv4)enB»v?~ݡ|} C?o<:h Q."x/||̬;f0çzގ| AmtDGt?O B*O׫8&M`2(z' VM$pJ KaGs]ok )|:wWlumN̘MC '!< F*T B+hd :w>mV0{ tu{ּg:HPN[~/S ~)O ֥Sr)F7gvG.V*Tb=`Uφq(mf_[X,^k뺩ZA Dj < ef(mh7 z4@B%0\3|ҟYU#}2(0Xq^OOh/۶44co^x; vOy0X x A4+ b,Y0ooo9Wң,9Q$ݑT0rAw ?K$W@(&hjVM>dOrik5'QOJVM>L-T s6$8< &i42ye=mFb5w h݆d;{'5FhOj_*Vz{gw$)i aT<|~Q,z{"e.aTbNRs|աi3_! ֨99h"bp+ԕK[6kq k_}z$39Cgz~ғQ3kLDg͂캮+9 HER$5В-ْ-tUyl%[RGG#+ֈ /$= Ol%):?* Aw':K=NEl!Tzj&t\omwol>\3[MYIQ2?Fq'i5퐈$9RSNMΈNAE-Ty;m]W..dMRI)!|'~e`!Uͳ? `rP[2/1V+ٸe:>s쾻ӉnlY,PC+ ]8I9xq3M)olO ig{t0RM~7[`:dTAs_VAl6Ӣsx|.L]c %X+3Ec)4h QCW ': ,!Wҷg3cd_ϰ,LAܦ2=*X^`U-$#D"Hq$JG+,Ea7^݋Bnĺ;Ϣ:\ h䓓1pw?/r ZA >b?ᢉO Hk4L yiYJjR)zr V~lzp)GωfR#N S=yؠYɳ]@ ?_}˸SY-"Unrz{{_Uvo%sVQFcfjAs>ʌ)Ld2 ¤0:ha锰b4|{|˶ SsCɗ 3lzژ*bP'@+zB!!]JELԊ^}_t d-{Eh"n"6A:`~G6uЖڹ:˚>R0CICbT9 Y, uDK;z{Eč㊇쏱dj]:Z8j[`kX5 e`T fp*+{5O21{tYBiCK7!k= % NMtf[߇u{?t9Uj5EE@=ugLugL`x^8go; T"s̥a=9=짐 djTHHKD0SDzOg堵M907(sp Y 3涰㟷\i4B& AR@5ۨ*vc#tὌ(VxD/Z  I" TYU*Ja)^'dJ%hMTt69/j)CXD?qhӢ#Q=bHܠL_aYE_&Ngyd۬Zpp܊6f8Wɂ,e I]S3#m&Ϥ 5_T3o +̴BZ1 >з+&]djtˉ\SJwI{DZs$œMf|2'[!E z1IǙ 7u +mot8D5J;@ZWh rG S;T0蛳 q:"{".O @xڱu8o~!p=C}l[^`O_# t:TIL22A0PBLPDղEqB MOjXl0 DCkFd` o 1{$c@3[H!j9Y$D]ArDq)k͋l#jXcw[E6|ͼ+&x'7'ꖉʇ+~5/f@xu\ɀ#{FPUq"?a@DNIf$ǿɄ216Lb79靁A"4727<੮f%BKji[gVLQ2R*J,b{KK!hX~BBD|W/6"I)jVኝ#o0Ԙnml0s* zQ[hFVO ^ C4y].ӰTѡlB i@ !D%㩈Σn` bEEת{j3o9(R_5 Wfex R-]_/}$Gʇ޻[M 00fdI#a GHyd\UIRG"E-+hFsլї@xq;tZ=robc @ġ5:2 QLQK")3!tkH5@z<s=&L 3IOxδ58O~ ]g)$LLuc)G7VȂQ%ɯ;"T?;A\'Ivbi9r+[!Ej36~ђ#V jC}zv;^|D ~F~] [:^H Ycq%g]qFG-u016c qE(ݭ q~& А,ٚ^$g*NBtf 2%DS_AKZOK0IȂ&7I! R{2ҔjD=($9b3-/"{՝gG(83aDrJB񂏜][ 4lx3٬mr] {aMNV׸}qF+ʓ j\9*T;n`/^[dISd.R WooKFᴕ!E҃8qTz:jG[~toW:4H3 7j+HQЕ;8Zo .Z`6QM4qqqȣ;Z;V8sI`CcxNOm=J ^xTw,wAv`2vA\f/LH3Zjh<{#NPH3~KFEa>g5 I$o7ȇNX(Pb}MOmVdV :c 8Ww}Sj `ߖ.%}!aବPʋXBlظp -޹Sod:61P"Kݳp ZrZ3kU$U~&dS.^]dZOBNjW|֧ٗt8sg'6]'CH}bTd" C?ҟrA3U׋JeK}sFp]+aSʹɩi8d"SfRZR3$lť;9EY:f2[JflξiO)^@h+|$HZz]d1Ԏs,n.;&F0+=Q@飝ҳfA}?v󶽽 n ʬ<HQu^sgΖdZӲطEyxU069D(#f |)j#?}A,H0L97 y鏞q77E"MMk7̞[PT*M_7AAEզ_Ӎ^ l-6.굃0rˣXPRj–UT<;H;EhzEĊB&"S?w]I'Gש'w|q" g&Dc驮q)1 h5Ywɤt{}=¶~-p c_7Qu>5fEÝWܡP&05d4t(]9|/&e:dN"UY0=̭+\/=s@",X 9=vH]aP:h!Z"G޲g;*i\*ǐd*"g3Hga[F3цK24X[pS ) s>7kO.M̄x12?,s[`J/d$j?Ra,n5S7l\&Сˇ:O, %.&hun(Ns}t=`Gi-A- PAdafˢTM B1c$嵌< %zf)F{R䤚/ |^+p:hRDDDigZp>a7i+ gG#0Yz+ |p }@ssnr4PMct-Rr.'QӍw>}b~V-\TU(]c)d5,JAF6 -Bh%Xڱ~cA[t-E6p{Jz,<މ|v=!NXM!>u#ɒ@@2Rc!wͦւ:)y6֩I c7]^|}UW*P0i#^q헞wTO5c!F3(ҋ̌*K_:?GXX,/B:?࠹&V2 Rɮ2Ov'1A=6MD}ߒҧݏ:VЕD$Bt )_2f- w~'w9矨BWM{9}Ϋ&Ŀ>`^QD sSbmBꜹT-ΣZQ*kôl2s0Bjw3Z {#y B٠ҙe+}aϮE͠ZI~==4tG/whGm w(`DS%?;nF1CuHe4LSP )ŨL G!tюciߣ0 QTUIW=Ve^zp}}+<'Uc e$»` (E#2^E!@A˰L$lYi3KS~Q~5YdFF0ުv_ TJ苘k2LƄ LVE,3ȁoܷxt_on-+ikC}+N4/;U ШK9SҜS;dݏmi+v`,JOlt{dz?ثB[):r B *2~Dž;nk8w" A?}~h=(zk%8!3dJa@ V\@P0woofUX>}?U\ tf- T͛;AkJt=!M[^s&C3986*B7~T5eF='cguyϓ؏; )4CS5 %63| P.jsy w7ED<-aQ@Uj,-R^&2&@I( 4VZtc1%6o|q+iR3|NϥD3CHrnκ b;²$R4F8g ?V*Pj}*l !Ҳf YU!B*; F U3lyYSmDoQ (zn֩nR3OGԵYu00[HM dHɖ2q,Y"vd;6h>xzԊMjpnI تGx=ڏIɁs[G4BE|W@V:5Jp/46(gH)`A)` ”-S?w×?-֑%2/} G #e՚Ё@e\ X*aYa_V;V>e@(SWb3o%I c3F!z3:af8}|HWg!9~91gD x7 2ʖ=%.{[*zzУ}LZ)|>RPj- Q*'bjh.ahFfv䃗n' /عKX YaِLd"2ZZh}VB*t +uD_'1Lsy, o=⑿TCC!RcH-xjX-x&M[p'޹]6V/cF# Ha=4J,TQ5ud?^&[~ # +Y9w'}hO_CTd_h1>K ~d4ESQ(Ԣy$şy qi.x8L Ԏ(c{UT/=NX{:@wIHC/4=H%1 !( : })fτl)A2R$%2eB&aCY>MU0c](R4utˏab F$ -G,&H)rRT ڹ̡'cëڎT|lLY b+zu"/g >q.|}!j.8%5^0X{̒ùR 8}VTLкs<Q:V\1y Mvf}h*8{w"+λ _¡CE0M)}P_qCH*v9p~-ϜMB'h<6̇F# %o3;>).l6!}6pNIU0Ozt2g {'W~J׭=[q5cR/fЛdFXά!^UFHDSQ,]r\d2gI%"x`'$P#h.m 9KΖ3svcnΘdO %~Lg?=pwRoxxx5ZW5?6`6LGCI"Ir.ҎD7]߹⷗uKC-ANTFʂ^@KM.5#Ky\:}0MG=+4qUljE V'^n pLySG-3zmǐx0Z0grQk ,tV:]A/s6QNfzN yjq6:r;JW3~[%k7,icRSPg+.jKB7!U/f! YxX]mqpE"OT?_|KYp\jru^`5:VJf˖LKja-')9M$ɖrbN6"ޖs|+;0!Gl; 3-[%D&0$7MJiɴ͖ږoqSwNs(5E+Hv)`(%֮R+9%^a<{@I/U{䅹=t7uioJC nDoxU=EO9VQeǛ a ]6Vm=9PKGCBG5 $ѡ?8UpLL9A*rwX 4'˿Mx&v}-:j=LQF.Kq/X`8! ѝfhMb% LX@\kOu*6ycVW+]dM5.B_|S&,'6ɲ 0Dh#"!W74먦>%Ъɭ * h@u`x{:ZI$I)5I)7g H5Lli6mbwiMH6쯍}P BĪO[~uH ś*(HO d׾u %+^'Ɂ8Վz *xSeW?ؑCKM#o2G̜ٚhRd{#QS>ͳ yT=ih8 hx?lFnpj C9QR})`J+tݝǏHismw"Yʓ5Łͳ!mq Pf:rl Z5'(\8AM~M"S!h&ϠPk=>4n }tWJq/3i$HbI(}#h{?>1H\TtdcǏʧ?i%Hpԩ.hEBľ\@+UB$%I9} tb1/+*f6kf'N,b Eyǣ4a ]P x8g;4L$n^^\A-`ud&g/M/3QL]oHQc}~ˎ7 HE@q6: Ezde_DZbݣȰXY.OZ1!E|lݾCX_bOڞ^Mbg̝anƅfgN=G-{"Q̯f&!' ԾnWd fZS_`TM1:zmGsR]>C"RdTS})禱"T&< ,-#O_sǗbsXd9q4y`#༟ɘ<DDMI}l^pJGS"SCAo,k߉̵b b $fZ|ϯɳ*5#XJ*kg $U`Gbm| kT@j Ш{o ץ EE&'̹)'M97ϔZt)͓ڧوg{u dll2jt4k٩PQo @-XF鬴@$`W{MzD*}ݑnfTnXm+m4C6ڑCKG-=nYgϻ$v=rhɃG-z\~GN*(BT5V,O. , ߔ]#>1Nb#X(`.Pc<|g1.69gܼ&DՃ=bۖ)_bg`{Ķ__<'CO͋G_;3&xoUqQ-BmCAFQCW Fi! BHyCma0E)QuM6E.Is-_%U"џl6JH)p-EȄQ;Sί~=CYgն>Ks̳,ᄎ[r4)2dʹ9L4Nuh3J$|dkr.KKǎcG2QG$4Xc{TFC %ěUFFZ@ x_wn pN Fcp4z9 IDAToCӲ o* ts~9x/8Zn3"?@\H3v1h#yў颐M&4禘NMjRfVI.-.tZ?]Y2+kv~gHj  d`!-cAY==f”L֒ +4A34S4jTQZנ Gcyt4тi i;B=~%9w "*7VN%啥`͂4(-v,teIФg @[D2#)s~iz(37}>~c5j qeaCS#7M4I<9bnJcסmUd-&Y^Z*k8 瞫;A,CJ*6<Ӹi/5M4H`玠K-B$5%ž9zĬ-5W 铠d~x1FeۣvTtۋ90aQf^2Ӯ>ٵ ZVLd8ZiOm,D"i$Lv3gMFw|{(ˮLyR*S֜$Ke`b2m,KTwѫM*S,t* H 1 ƶ$YT*%+{ٻsνEdd$<+勈|g{OG:PWx!59A>aPz*MA%:z ? :^.ܟyQ 暠:n^ c󘭑_+5,L*%DtX;%Ho$5kDl6m|%Ogh5XZʦ@- OӪz@oh\R+CT/|F EPkzSw sYMAȘ: lE`(9u^ED9k@"B/aTT$k_kPհ)\";\R'/"\=s g(!zZFֶN$)O* jYbr(Hh3&kiX8,O]||'![KL2? X߀qQYº Dˌu_9 g;Pxo|]Fau:+`(=Й? sчMlƀ x6r)BtJH /==55IWܷ%؏tj~1b'*.*>ٛ&(tBa pv.J!rHV!kH\mUU C=&՚ Cqx=5Ǘz!&"hju b<lu,B<6sV;"MTG- @EBVk˲f|:,cP,l>Ӵf{Ug=!ֺ6)Q h$FTldvw~lݠ8s-Cij6.hG\$8lW6aBɁr$E5pM50Fj8yeׅ釦:D^wT{""u]45Q^La]E*`tXmn7~aSQ su3AKALFjgkVu4<+U~18VU6;AQk;OHKwx+^o_<ˎ TU( 7iۚ#XxcRl(泥ppir{XsmZ)W:V{q>ܫ>{=0eSVD\d|t[ڊf3ش4[&TwDSufqYT6Bx˪@Ketނj>Ђ! ^ ,E0WĮ1 yf[pDN\:~~if#Vp,ʸ(iʳ0w)pz֜ ' Z(=ԣ@-=vʐZ_@U 1VUET,(#V#@ #88q r7I)N L+a1fD= NX(x.5["[8 D tהM,_A/U? /`II-O{ !p$7Nxl\Ld\h@Xҟ@y~hRJe4YF0Ų;:9}b~ws(t\7_]ڶm'5LѾ&iiBNO fJ N\Kɤߵj(^JEsTXTEUEA,;(*R׼C1sj!҄vgi(7;ԂYkd&ߓcA_fٮOGl0s¬"k:is#uZnWªg)9a'w|ߋӤҐ)PCH Y=z~10қuH($D_Zxb:-jj'k]?p |lM4'BL9( #ʅ7_# k8boNI<1'S*ANQ|ODž . #.[XMjޏX^|׆/໳1GpI;I{{k}db*ؑ#y%M2FV28 0.uN(PW_[ϋ>:PTxxƄZR;&!ůohvmh7cMcjoh22%6FA=E;uUUW2#U-0^y;G&R6_S `VK΋Q` RVCZO[_4 kW';;r*5ழ]Z@*i'GF*0z<@]ƹmUAw4DjJWW6YS@Ln7>0( EP%6{U5wQvκfz1"\~\h@Xw녅cR93 h,#2EӔCqktn?7쵝Hvݫv)bpдtخTB!6C@!h]Zw\2z؞nnc,KN5g|DTֵ˟6 f $l4D;&-ê,C !L9|.X݂/N)i->tuXwb)Y,GJ #YV4[Q%T}6pn/6DF#/NW-",&{ƂRZYRhպ&$8ѩgXwY3d4$plY_ЇSX)\E HMJHĄV+0 (l䜊^Ň:gU([2.8 ,T22$% E-D"& ݬf}IrvGiSSt RL9bATMg7 L_ OM'Zc'a7=MoB# R(f?TÈj\X SpHH0B._hs3i0/,h @D^[y9EMAr8{]S$kIZij#D[YkaO鶖ppCr9Dĩ,n ggJ,>-X֦FEN9M^eƿh}(;ti: ysts[ ړozӘ?ٹ;˭.hEUZM*DDjQ'Tg8oP FgQ wI(wh3yK͇I17ceNb;^5 Glw.:e6 X5tEQ % _yw T4/q'\7]`4 P\$R!21`_yKPHE\VTŏ35)g%J #B&JIaUNk7Vx4,K| Qޞ+0+J*ۻ;E;7O35Q~g[)?>J}Vr|M&q\"RUU=s^B+^,YɸЀp15j#c~44\O\?J+zPv-dq9_7>㩵OQרYaWu^3(-%v\jo^:;/<-O>+ϼqݳOydنMmO']l8&@ H 8UmR͌mOTN%xh5G(})If,Ч78՚ÉUtj2mNŢ Jl E;Ul 6Fmn.(" 1 -Lx5 iJ0KA2JDOYMj-[ %XSo }7m^wswR0]Ē*eOY7̬0Jp IJ]Q-A:1AI.RFPt\IPj,Yx$tJ )-+ʞy\kP W+z?$+‡H!1s]g^xTw~z=oZ.v=_N[ֻ-ؾ{z; [;tO補SIII+Ȓ:0dE4ĿS9{ym*Ϡ[mNYE^{=AL3t$Y}Щ[gNvfNtx5"'62ͅX#hBDJA*` BDBJc IDATa$ \tjXtS[뒑KS}uSN#Z3ˀm,m^ DŠ!j{> @+$@mo?O}0I'B5PI[ -_zt"ZfVr1.4 <tjm?3xcG\'*l=9c=FgE8ZF 䭨$hRC -jlWb髕T zx8x4|a CrZڲށ.}yb/}Z!y#9C_i΢\U97iīf)KPuLY=kWo~Ě簆k\/uQƿ\&CuRCE~?`]ZuSw(K}!jN©b;D :٩GUJ( Ƃ0L% _yML<^8 /t `>|S^hoRE|qo2Fuf FwuY!E p]g{:U+7`ϟFAN! m$WZUf)Dֱ:ɮkWE;%ňpqa]5m,tC׬ /}GD-^+VƢ@K0ǂ6ȂU՞\X0(Aja&"> _5<>E|-_N[6-;qNyyx #O9Gbi"jQ`xng(U]w}n[Kz fhRD%bpЍ={Oރ9-/ǂDR׾(۶;|I!m+V_θ+"ɍ/:Bh D;ù B  E\qS'.x#)2I@JHT[,<[ލ?;|LMlF$Q]ap):{Cc -l>|;O!uPw-|r d8JR:(A6&a0{\b*!Ƅkpg ,Ɋ8ZOr$ ҊYH[_UlRESt4hsQU?T22%f(vJTyNS#_E&v.|oԹh;i(;5q'"CL,w '@,(doW̕z֕T5JB-"ATYoɇ|˽j>.Vʬp\@F!}ӱ#}M2/긄o{ A?H=eq vGFaf"[AY%#bv^%@D}߾Kvͽ-;sp=[,)`PYR'+zjl䠰N yT6;?SиTHqode}m[Ԏh[m`]u  Mu)?4d΅ lHx,8N (* U@2;m9fq峏HDyNr7{=ZVM@cl@bWvpPМ7zp+R% ƔӆΛa[߾p#?]`&AeSeu,ADu Uk` AnRU wX|˦DcoY\ᜥA.9sU,Cְk6LJfMFqh#B 4%)iH-`QJȡZ`$cM*!HDvHTVl|d~[e_)g;xG;^mj_믫VY{8w:ә:G2#uKy1)Ab M(!L ]]jIq'P&uJG$ʼn?ɞk͝,i+T_Ĕ.1Db\HVt@`"I[„`-4ȘTE3> F#L7VS5ܾ[?{/gU&q|Oնc@E4H $Hn$#Ā7m#G_y,F(+squPĞw4Yh^epQ@ }#@#w*(0o|$"+Pp(ANc8X ( 1~@ q۴8e7Y1"sX٥wջ칸n&ẏ;vc~_ C;wku]U\GRiχGJuTOUMrjw?EZc=M_XZZ@FeqE =SvAtmY0Ղ 'iwU}}7OBNucbQe演PD >}%g f2 ASa{qiE2 }=0v\5.@ <[OcpƲgab^+-ۿhAa[+`%.ӢINdRTRD(bՙ4^Dի 5itF&疩V%\jr~w~4yߛa˛ÚkkmsާSUNW_8]+adK)DO?pX ݁j;-/0+T5v1"B9Ҁ~РMGp[ ;*@ 7f4LYDȪ~۩1E?A U;?rbr QOUíG|mGIѦh' 2kZFQaV#GeEB1uG?q?t+ k f?N^J+ i=#"!ZU+rˎDk-Cn\ǎ OJ1 6&7B[О i)2Zͯ ;!(&^˺!ky{B"ɪl_D!\Jho)*PW2Qg:[PąH Z/Qjf. Ռ?@ăw/\7ppaR[mB';3in.Y   8PT,&[W?ғNfs4e52P uD:{dv"Ea@aĪz,D%YZ|z8 gBcARQAںMDHa1dqP A5=xF2t;:t|l&Xi{ԇ)uN_5e)Uה+n(yo_IzaFEm- Pz-ө:.<cgfXתʀAz͇Zת6 eYeH?iLsϏ)~ ZIaZ PҖ4k* Svj<wN™>Q]2"l}#mAH)9fJ0 t"@0J,ݟ-^ ?c}a?Ͷ bQT /a4d) jACAX9@z['y|L3DžUYT֖PZ}ά޴HH#PPmZB`(KM5 0ǂ>CROU(*g0hKMA9ґ]8^lSbܭ_[ם8p͹zIzv}'ä*p*JLP^)ED"Q N$ ٵ6`F87JJ:,aWeafPY\9:d%l(8O M>QL b.]."[0RcG] NJ`lj~?mh_>:QlEPA \vH b+0U, y195h"!q/ EjB+]a=BN>sx"`1 mO(Fs|H>Q  G5 ^@T>r^{j.ErF:‘47o%{DJѻRc{Lɞ)ڷ7x]2 t݂nWW+;|WƗzx/OA-.Իv&nnϘ7$ .Zlq꽅w(<5|U$ 0}G1gϊiViMC!FT6Yg~+92Ȫbs,t:eYVe)tg^UuO"D /D Ų̘SL!`fJ[3Z"ĈRvaC&'H~A\6n,?jXP TYbĬB RH0*MDTR'`y_=|mK=V8.@ | ðgF gX /*)5bm`] sZ;乸nVbCItހ0~t5v);?;P=U$3\zw"a2p3lNCYbDrڔ"^n_w]n3c(8<mteYe5UsI_W۲/-Be M"ɍ )kHf sRֹqAw<sGȩ 6d9ȵqTUcIDb/%LP+q %WɤU+ ZDxԨ%*Pܰpѷ/sVJMM]bAlZKDRLNhj"S@N "(葝dbaڨK[?P,f+Tyv+ 8(̞Sj yUlK# U5SԵ2upxflWэ%mY,kN>Z8 C0b8B*>~:+Ic!NRO=9.l wCq׭@;CRPLږt> 1- 4`t}6"v"P-:,ރAckupN~9|ֻOc\B=IlL`k7 T7l7E Ds3 G~|x @\Cߑq?*/9\PѪڞo6q>X (v'+8sXf—9l#zZ|y"ZrMQR"n52NB 6M6%#Jl z z >]}=–^Sj4=_TV8Z V7dmC7Wi%Ԡ$Z3T0e03/'}gJp1DžKyGt|X0ScȭmR'EV-C_0 |9ߝdn[il -`ƨxS]4WZdD5vTsހ)}W,w \<ƣDr"B;f# 3F [opTr "&+-Sw~9֋ ƅ +]f,PI)Ft縰"BZa@@h>3R-ƅBL$ظ3/Vxs*\17AÙ*ܡ~YSݳg`@"z?+F*E qIZQ`;S8SoĤ E 3q m7'vT=w!elxcNh}k )jnȧ+~tADI AJ!#<0pa.ָdQwXp&RAj( mjyLmO[ $UCI%NڪYLT*Wg~ =zՇ9G=g.]u;OakFd"-מ1FiKOd Ljyx@?gjZah֒{$  QF>Rjd`tHgy4j6a`br!?=B?'|Nz]%]Fҙy}d<,}Ak!pcq<~`"%4?#62i$1;Sikj0>kx^cI:/( #۩/!R-,TއT$'?Jq~jJ1b06FB"Y -IU/p?O %^!fa"mmX; IDATщ͹xO"qHn-@ DGH|uA#crg\X0p~01R GY_qfǯ-(\f@(iTEA 85B8VkuSa# ԃ\ʲ(t%5@'1렢":u9ܚW]^V/}όuyI%c Q?lm 6;6{ 8 TXTmȎ U2RҐ3űo oS C7S|zÍtK.._yjsG‰E0n*1`(Pp@v#͸E\ WvN 7Kp,:IBh\m#=UKOmd[lV)S5&5nػ.7tZ.Ur>y !dc0\TRm5jZmE# z?:H`8I@ԱsΡ~8qbBZjl2TJ΋bD4 zjk1Wt6.֍t~Í^WV6umk>w_Staog%&JȹG lDlKJ ;{;濔 FjL,a&bNhYZE ٌ!njgFQ(dzL  41]}up0@BkHfQNcJPEr(͑chT,-Pĺ̃#P}Yj.Dž SJEKrU8v k5U=X[aR{j+)/H[+ 80ugq[oCn=_e6Ň5H*GD ~ .<ģb %e)%d{^#ba۸V˽mF`` 9_#L5 =| 22(09OYG±WuW=9NKHv(KDx,!-1cL[YYj;_A{l|~9x<۱nݩ`[[rP t瞞Rzv"kjYmE@YYtf=sp0zٕmԂc^{[-EQnS[V2|H@Կ]` DjJkjʈ$CN8#bDqaK68B4,*CͧM!|?9~BB`ҚG,t*VUkE':0 0,CYU!RLMhh)3꼨0,iVU%򞠭"xy΋hi„Q[UBx"RWeacuyUZ)Hq/\\2ڨD^j݀kFpPUBfQ1Ί/?֋+! AZQ q.Ҳ%5ߛ85je A`8咑=i~"@ȯT#*̝7V*$ 6+'F5Gvcs0b\`\@J֕*A4i eD@@ޮ&rTE AUP!"TTC9 Á uCj &sBBXļDĚj֤!/0ecYAY: j - @@—UVr:63*q1~ R³gs U zWu^= 41Wc pNҾIzG|"ATqpGBWM^W/#, c~O RUa0eYu6>QiRi.T^L1=Ȕ ~UgW?TT.DbzL/$ .cÔeDNzh_7X9@AA\]`ǁa+|!{qk\@0_'Da+8ƊHg߫^xy`( qNp M#i) and/hU^6"PZ_ 2P0!u+څ\ ,,4΅>W72)8"+dX u0 Pv}RS`8 Śa@%{F>:tD= ]w{ףּ+}y>'+dԈX98׶`GJ]M]Vofg\`hݷD܀ՔA!IbsH?)|Jbbf'e`r*Yy5wJ*K6J" 5ں͖t>%vHYPI,J $ШY1fS10s+,V'Ptx%,7Ɠ煅JùT_lcI͚to  "C1c !+<ꃤP= +hPȵ_ +[.dqh;3de̕Bé(vQ''YE\YyW̹ŲٝA %G,Fq:)P Sw'%o`6u Ե%֞(z= p R1yЫj]׺h8BBxpտFQa\t$Als<O!bUWRtQ:CܕgV- 28?Qn6fR ed JUTj:JVBgb@ H?2y|m)6F/ `/0C#Bf :h؂ e./iضpdsq,3.\ :b,zὴ,T F N[v я>Ű4;tݺB0Hb" ~HAJn_XRB-Q2-$r&JN4ĈP"вvEwYPKTyWU'<;{֐JUeNHB*HPRQF!(Y]t/Ws^ZJ~ݽL n *1 D#$JPjJwx眽?9y޺CU%]};g:kXn.)l͖ڀڑdkYG[TMSteN3sztY]vZt`jxw{=̜v5)" ǴE` e_N%&K8Eƨ9VO j3Pη;G )5/Qh>Iҋ7!,<1+-RbcB B+uv(x_/ '`E!&JPb"dD%cn[0e UiO@SWY[,< m g/ͩ4,'UpsSg4]ꁕF:d2)_OktqQC$>8x0ѝpS1u[ں 0\'qBBt額<s@f[/m@蟠W=5sǸUZvr,?B'w^{% r#Xjh(MEbj(2R\c^`odovRw) *|_qb>3 kMU' @{_Y_!¡+4.xF+ƫ"i?ՔTDa؉^jpvbg5v1>ig%yWcklEm7ѱFc ❽$SC5Prk-c{/}O 7?͎WKBi1-FCt#4*8Rgwc&lU O:s(֣{yݹ}fW7P2S{aX¥3˫*יƒK8Y Re^v 9#!|N䗲!0Ν]u ?1m|'5N3V/=a~w-3pSW  bg4*+ʢTC~NΠK?Z:|/^scLZ9df~=rj%qéO_L,vKXAEhX*L#.4"NHAh=kn@| a*n230q/3pi ӓ^#Ehg:kh8RB椈>g:moT'1s뺲;s if?<h9gAJ'k&$,9ԋz\(C WPBk$ 8=տ 6\pVܡl8bie>V#gKg=%TvDO?''yxzQZwF|0ƓLmcʌjYEY(^׿ )CdTh['Q,؆enn&mg*'WX)A_jw2; \Y |(ƞܳiH5-H3}uD %bw=׏5>|RRJj4'ShftZDbzҜ"DRp#hFz*{m|B1`8 ?9Pg]K7\6\`f ~l(10TU/Ǧ EU }o 9^s^*c&&W/'Qox6H'E2b!2 P`OH^[I#Ӻ ?HnUlϔ:K(D *@""@eQC[ս/m_z Rd9)L 61Ab@ Ec`<ېZ^ؚ3%IzQً~Sx|gu_X vϫjIGJ#؜r33;( B/ _|gJM>s9)B#,b%e/c 5AQJ y zs(KTYG(`s՛bSonn釻dabLl/, s=Y/)wH$%R"r ٽ{!(Xq[>΄$3\'\nǺ1Eݖ\Ľ 7twMـFd>s34,h9C.+֧ "j>IFP,C+~ߡÿ7,cÀrgr IGIq&kABUpw_^]/CZ&E?NSt6vau!Hyn?DH*ZscO,VUP}f2M[)ſ к?N˳!zEZb/x^ьԘ6,ɱ:uOfi6 ̳Od,Q:JbXa.0+¹ΦKzǾ;??ʼn^nFlʈ}jT QvAZD W3!BcxdbiEn&?=.w~ =Nx߹(hy}B"Uy4VKQp 5( >!1gVIBE}w돢B rHxe-HIUT`(hW*&JJ yu Rvl(F 1WjXh4FШpqQŲ\mao P,k`a$bVc!f0 SE<E^l-wN*-aY2+mŀh< fSK+OЫ=tUCm0ϭOZ8WZc~\lCTwxNʋc%YT+PBtك(%OeHIs*jjʨ"N.nیmM@xM۫1|u?OZ (h72؈Y xD婑ESb'Of}?;5U+`wͳe֌ۅo葪U~0a!78 +گ|yx/IOPQpTK+@( zޖnxֲY *3YG-B}D.$ZȿoBZ_~fg;'Nd/pq^L_3}Q <fl(g1Cs1t֎jsf\_U^y!t(Ά~t3'N-AΉ6nL) SPΡ#h"f Fnv(J8K꾧uӖ\$"68|ms缫;]@'Cpiߝ0ŅB y TUTT5HVR;7-WoxCY54 ԝ땜FL ~eO˂\!!Pz0GPQ5!oNBR uT4CGJOh"v؈^S;ĵ%p,P,@ٱ[: IDAT1J"b8~+i鞽?}qqSZzΐ #cJ|oh(mt\e@p'O)ILj," a?5 ~ӼTFP}{$(QBA F oj_XdƜ-M(¡ (12tTX/H2 Rd!DQqk+t㓏g>>8}Kc݋^8qɵܙn_^'.G93A`"#d0õ%ȁ (1R T) ;h4/:IZ6{>d\TI ųje'!*à0ć`X]WHD-;"BkG3 N!Fcڙ`"ظER4-Fl-BYrQgt +';{JD*YFa̿E"N"# ˆeIu:jQ"-SG8D-%-%C*&XFp1MY3ң((IADx-q <@ kx%H:*&DUED#ٲ:xe$Z=_ s's(ӝ^nvjOqFl'h[y)؁ pCEDmeP14.w"] { gy$HIsvE#)HzՁ]l1hID5)@s=JNp#\e ,y&F(XɁxz%ՃԔc@/lV33CFX4ff dC|SvcՑ?jW!x1)wk:s==џղOײSYHTS&ouzlHӹzrb_(KL"kr3@R$VS;X @X3眜6!PUk9ⴥ;ÓwCrvwtN^PM^P,ubw{ɣ_l} (rAMj MULgN@{/u/?nbw:!W-BZ|7H}@{ V$ "T*@Mq.r+e1BFjIYMYxb p|bu7_Mow'a(@qAX1uo玂\דи$I?aErV@n߷Y&!q.PUc.4:fCcZ,+p iG:z!.xܳ k"QmCEk>.PFԴBP"I$L}Vcd-z0f`p'6iMIĈEy2?IfțMWk׆ ۇg33ރ7&?9ׇ+mP܂K0Eŧ}G>pu~3iU(8\#n֌*wS S\J\@( fd*SY.ׂŶ |kAq}؂e E.k'%Hy՘i#. VZ`IFN?b3c(\QpY9zt~DFm_Tŀ0GwR7/eKE.w p(`CU僷041@2gE("4֋iP|\lBܨ# MFRĔoNNVB6{M:U#{pT8-;Í6Xu}~dv7)w.ע B>TpIs_^OsvၴNj#IK|X_VTUlLއW'x@U !@ lmp헙ʧ.5qђ~.r08(^ɩƂȜS g8ڴH-AJhEM(ےRcZϽM yzcg2LW#(PwY[8 _\ş5cd6 AbG6} At-+cϘ1ʷ  솴㻈(8 Y4x8b GD/c"C#H8$òd;v*fn㪩MAMf9QwuO9nno?A~9Nv@$ݴpXdB=-V;o*?y[<"Z/3#Cՠ/)7aqT:+ qV54le fHbQL .[&:a [#<1C̈ƥNgZ¹!ɩ7q H 42 PGAG|$_3%)Rc ґw{j0)to^?JIod q )( "Zco-0"'5aU?@6Uu2.{TP.kͫjM4[!7X5Fӄ|zEj Ͽޓ'5eSb\;xQgX8ox5[NefT `DRY$ʀcqQ64"wP t''D[.OnKN">e;DgPт{ 2d [Չi:\E.st.꺞n֣x^Ip G6+[)&DCꆬ!EwSFX\ t]f {sH|TALV-M Hå0 }!_#l 4V+H^k318b[@X em [D *,G𺌅 b~KGsB_p#s`6^ ^-]s_h=~8Hd[o$Qlki.pБ=PHMvFbqĎDI)8jNNĺXjP%m$o]#-:9+eum"!UU3vfPD@e#F2f@Wvuv#=7n92tgYimˏ融7goScE;:vٗ "f6O79**>x;uci-vj)9A@Hx]3d. xf3s䚿H?+ [~n/b OB"%%dz ϒGHp8{RxL#nu⁓~Md^P [shbX"`aX Mth8o4ls<+e7ey5 8S¿0/zuu/Õ05EGhf TsuN.ゞ^hDbǾӛYbʹ(MՈ皽Mle'^0;VjlrQA>A)3S$-A]BgpG9EdGhaw?'s -W،L-+D?O!HEWt3ԢЪ"c2OHF6fDr.eנxX"^7 \"4d:N1BĔۊ ȒT(SFobAn[O/cbeUHﲵ HjZiavO7} f5ܻr-)ҘнW!m08XwQ$$g_Tv,0SrXYW^ةC2خZzuR`@O˜ֵlk}l7-bHaK nx=O_ _ OH=/SXj(XUZZlTU_7/.صfl((zrR*.5fg"`Y1kK7P 5 Ui\sI$7HFRRoZ M>MXݝfЃ2(B):U.,B< mX8KYe PUR\.k'% *@hBHT/_{Û/n^ [Masym9,"s,bUx}_U^/-)[h0/R2v`aAH6_\ps+LwK'(:N4qID4S |t:1܌8:[^źΦkmaݶZw?Ls 5 "E4oF57,.Jds^`$$5Y .Aw}9z\WPʼ!*;dD%䷟=BA &H._ݧn%5~ Po2U(A%3l-K-8yAᢦYra,:T"|uo?eBs߶CHEBUś*|A7ʨz/e>T_xv)Fdw/kbUb|(Aup mHkr0}m'xCglC@L1* (hĄ1E)!I<* @zh0 ~8$Sʺ!O G\?-% rtK(Ԥ"TAAT.q^Νut_RmS{E73v!\P \ۗ׍܀ے ;_]*bc'6+ݩ&.\maoN݉ˆ3"DAŀm Z4ڕ[cÙPMUl,,5mC^o !Οŗy H;^j1p.*' pQ4 /F#_"zHhp5&2HIX`J Inj,! 0h[IxrS:IjlK4+; (EDb1-b! *%!ԤC-JP|$f3>}5wju L7+ kƤGN CƺZ8`7"Q Hk_21<Җg-j϶*JlAAEd$hSǖ8!xbHhpJCH<0zS*Tz/Uࡗoٴ+2 Fr q5\ۖFAY.s n| BY(+FA@$6(|D*Ԡc~4C`D4EίͨU;j~+%,D gc2{Y*Pb$)wE)1C },#r&p@@ͻL^`"QЩQ&_O(xٌ! AET4x` rcpgvYq 賩Sr{A)d!@XwGL+'?Yf B!$BAC;hb#t]v(EsEfoUP9Spinz4&ZZd=HrFCXz=)^bD=Wc>y LӓRCyѪ2$Jk!FE 8(K'GM tG_2u](Z)]uF (=gAQ:#H1j u xG%NFrBu+5CfwYk鉶 iMG .܈X͖Pb|CWȪj)sSهQrCӛ2>a#Xk fl;,µZnQf۪I+i ԩcﱖASM@^ƈ s=*"BjZTUy/}qG~ R*W+s-e(Դ%#REqQE (TyqH80AB%{$'#V46$nUnGn 8)h!ItN lP0E_.'T5vH jl($Pg>Xz֖5RUOD[m- Fw(r cOZT$0-Ɗ.&8-J4D}{e :(K.R[-uĬBVPlBkp^MnɬfŢ(Lm]-KˌrXGrjI#`$["\Ps81=0Xk&D@xlVzǔA> a0\Z=7uo6/^vBX0GeMd,Cþqh5"rǠ *%BTj ~I#DkI (e{XFAU ?Zh(IA#hf'z 3g2`kM;}?jQ)8cr-?kiJ2}lϽyD`5gs?[ƚ6B0@U@4A#Tg?nVW( o{"(.Gx>IvV^n_5Gq}̀5 13rji$<.z?"/jQCc$m* Ġ2Lmۉ&=1ҚE)qT j>!!H RIJXt%^XD5pZ''yX)Ȧ% Gi !B QrJ{XCSU TGNZ>V|塿UhgB#~s={oˉ+XK ww}1))p?Xup5f`- CDf66iG`v<\OO ef , XMm1S'P W. qYR]2!t\.M#ZXB2 jEZg#A 3&u#nTsǵ7P ~? !i/Geا4Kgs$4ivk"( Hd4eTY *j1aH**dPņ Uiq\,4Q@lX2 1 IBY K^47"+ ҙe*0fRh8?K[@+\NKy+s(* O<"WR|A).WK]l4HDPdTżxHGG.[뺓]nm63% IDATa~.UQJ% /[-*Kr.~v8~j{/`Lŧ(*0`cÍ9B~_[-sC|*0!-\Ҏ肉XLhDu<W&+M#r" iQd9a%@`s;?'"uh@͜8 qs|ο;.BcA)D,RDz[[жwrXI>k+5nM ^{ )8&lp [/OPᐵu;ʺS\u P(h{b;7ۛZg 3X;~vL! ]9LX{0)d *QƸRQGLЭ>pJpv6Gx Ɓ@Ug(0 P\f,R35'4L"w?տȁĢd}w 3E3$0YTO3QHˮ L6npٵ!gG=٧{M'Kr};Q_Qm2 #X"0FbwbFV#A *v}| &pG{nt,(q4L:F1D(dٙܦy8yݡSC?#HB =K/Qq_uE]PM?h[PP97w~_GԦ_o>όCUA&Gl Ԙ-z_}O @=jǶ OZ"$P kH`-/4%ZeSq̎đe$wPumQs ;} Й9џxO˓nLy;}' 7L$3GMTY)`"EATeY8Lcp.\]pF:[M[@X=|{~ Qm##P|O bz7~p&tbɅ1SyJx^JBon! (^c?v7ajkTS@Bb+EH9GHcKUYF,M轹o7}phd_" -뚇 իïXr6=DĢ >5[ H#CUIU#v HT0P n -4[3ѳ*xJHK2VR{19աSj @0DAMޝ[,+u2KՓ3yQY\} |6k<3g ofe[$#"d!;wG|ߢbBb}g{8/3 @2)l$WVq)F@#BH5 v1xjYIV%*6gatԞyBZUYs D,EAXӲOLʇ反P-"5R)(BKn{ մ,%޴##_a!@]9ZǏ<Ͻ}7ft4q(DxH$[ETbF‚R*ŝ¦is+B gCVJԓzS QCFQMI/)1b+/[&vÁ lnq /coL^C/*8R1/Jk+-0U"rnM:q쨫xX~9 .r  H 1s#Zr0M?^v$c̤؞l5I< bsmApm/S$ 7Es/%6@]Vi6[#X7TR"㡎]BʦSϓ"#$ bg uڝNA&áՇJb =/?`]73=ύo"M(݈[<uKȅKi虊©:vY;d;>W贱p-gǞQV $\ju_i5j%s+v~L_Y t7Sf)Q~Ic[Uu* 1#%! o]]Y;W#1+`NmV 5o044^vW:ҍ߬@\! Py *`PaP?etl`P07)vYM-ƕ5ODC jI͐ ܴ~#y'D^ R{*|]@Nlfs),ѠB Q<%k:M W"^4B2!QD *g1;b"ylgLD4Y[}D=? H6՝ǥ~Iǐ=DΩ+:W9rt׭?@ ,A"g*43,x=ʩcu*|Es4}-RH ErWЅwӫ3X86:(rDTB`^-/C~KcqB"&•]Du1&n[ S~5w诖Z$φG Ҭ1K&=p V~pJBJelgJL4v@!&:WUkTEb~տ*m2%6wmƽeF{3ǗU)mz䓥(1<BP[/G91M $φ>7T^)WJע/pT HUᐞ[<>99ό} ^ݧV[S -?"li/ _YJjidֹŸ}ۿSUxWNmF,1: |IPЄ,!(SO\ N/ AHTD@8^0t) s/%zk_2(f-+u$iq} R!B`R"Ub, zb2AŔDY8vsޥ8M[΢HyY[xOVsFp Ug<x%ƤyqO܉nm7|Ҋ=I%g)8%B˂l*&U2څ &AZ?O R3Of,EH [VAX િ1}%w]Svj2Mm #ҋ(-/8"yuƟN`xo+`Na h8uJ*bGQrOL) AaPy6 A_w}LY?U*(VhҊ0Jպ" (Gd f #gtyLmvWuV`:[DZgYȭ)]q|g#?̚|wɫO$)m?so|Y?@S3q14#`q!xsݲ! }鶤0UjYPYhP84*1Ew*kZeG4, -f(N @-4:ڴ,$*i>eﲥ>=s^ccknjQ ,AU̬+50`~Ck=9­{nn-Q"V4* Hjh^odž#qZx@DGGCo̖o:H"ZstsSoFQ|Q$R wu[b-%kQ8 2uSƙT^ klX պ#J:`Ms2;Qy`'q"қ{e(hq& va!87+ՂQHjx띔7'vѬ%Ԕ#ք 5`MmazCmm'7hTK^pjwal䕨@ de=%ec;=*wx߮=8u˥;oGOM$3TglV׀f'Iԋ 'd%-:;eY$!EĶ lj}eyJZ95{B` gaC(Ԝj, q"eYCa΀p+o|minѪ6|"hjYf k4M" ?:Ԉd ׈U: <@ՉAgz [IF .wEHm_3 (j`c1TL*vOʐ:YiUhUIUY]GFXe1`VQlxW~ZUوJ0~R­{L5XiD*H? U2mPbU:RG$y#[^S4Id]ߖhTmhUon+o922\D/ϻ;5itOKl] *+V7?ALLX_v-[Q)ym6L1tLFhwཛb|PJ2}?tsurΞf3xtcmK<0g6<"e:EH[0GOxOr,Xڇg/q>۞jbx/n]65HxUw|C,7FL@%e*&P  \UJ k_o UWQi\B NWG9ig>u+Huv(ymPD&HXY#u9K{Οr.`{ov? 4Jr#ya ^QDT(w&PMAخDVx,_ ͡pkމՃ?#w~p^t;uyϘ*q}m gmEC/H &B`ޠS>vy?ki{7%ClW)&J:N(?>'!c:(E@_(Cf8$IE ZKB  D F Օ8扝p?;@G? tA04LR^QZ% dKE{H@d,|_O~-g̱H\b_ߴFna9'C7ɕr/ ,()"a3<$@DO'[ڱ`,Ds[LLH$Ɋ(Gܽ)  Ɩ ?ף΀??_#)$`6MsL1#Cc<I=m@9˂=/r|Xf'+yHAѶF6PR[n1"H)>}!Ev26-T|ev7F6 IDAT?qG~ zZk!,9:WI'uq0 :)lX,uW=0*V P6C"0G9|6ߑՉ?UH "Mfk"J0jh;#aBPTBz&6x%% ~<=QH-T\ė- ٨3鬲ig΀Zh!:*1'ҥQ hu=?@0&Y1ʤm}fH!K Rw<+>"y'IK(Ak_9 !" 9 7m&(|_nnϻmsI|{np콝dFE{rޮڹ=p𡝷}nd3iGJ;Rw.h/'CǻDGAUQz"-^󏴿vQ-ӟ HeTE]OHrą7-}\_q>]i:X*'&;@Q`.$PH{gQWpR QFkv}?F6YJ]/Iԋˤ$pq5&G.w"0Ͳ(!@BP:X5!&O1Zbd`n9{;[}Jާzщ N t:i'mfg]" Xe<-;~%70V 3؀,Rl@e}Pj{NSU4;C4'ޤImRQPE]}=]]R3 rwܿrth Z{ڥǾ[qѓ[9^fS/!oϏrLH }D"Es?qm-Ï)4f`3T4Sx ?pw=QΗI豣Tfwr=82YJcdR4.Hvӑ? RM \"yCY o8M;xxXdvLjSqd/E@קust6`ء~u>}SUP f:N&t:$]"c,܄eY)a]SpԐNel3´*U4;$2q݂GXNcSߥ>ƾ)X~{+$Is(L_}ugms(F:v=T0|^/" [q&[BYeuskN"#.?R:K38R`u RE be0Eh РT%QWb017%%".PºQI"n!!~%~Ђmw4o&1=J&3_1>QAgb@J gS:CX9P H"=pu˩GPql˿㕩zuH6m#) >e[EI H\v;7NGXyJ˯4x/="2cco7\DZ[[ YiL!|(4%N1y.MJ46 uiԟrGR 2!#exh칛we=(Hzsf1QtJ7\? ї9di̤;3?xvF0B}g'.suRhfi"c-))Q4nu}z5ju?ş~Pof0m{ދ^#=+)ĨGk!\%0t6a9\4:NU* +lM{N%2 <|W[S=6678#E0K]V|/]o}6me13B[,9>a)ZJZ5%{qR[ׄcVAp_Of)qvpQ7 |Ê d̀ ڈJP@4S^J$6&{7I%|8"׏A)x*}N$G3154z)ݻ$__U[PSNXˍo*Zwvҏ;H~U;Rr ,?Fھ^d$9 D @_*"igGv֚]9 '\BM)5dsh3$ Ztq\v)@xe\ Q2\IJ;KUw/|Q$B.EFA0w\?sU"Gx巄3=?;U3"7F?RU8QZaM'Yr(eTBB!#RTۮ .`bʗJsc:]-M@+䨻ۢ,P,)RHnNwYOjJ:\KuoGWɱC4TG&!tvM[-$",$XPFؖגfjXkQhl<֗61[T9Ճq<]ѷ,a8v;,svͩ/!{)E;̼SiP 2WnT` >8`ȤA q*b.$r,[tRVun}~Hl((u/H:oi)?fǎ`Lt>o[Y~RtZrC۾߁ h6AA01.$%o_bR/G rWK5 -("d(N jwS)!׃IL'-³HxvZ`uiKi%g'y&Gd׺^!bH>W&&7=1**&)R@;Sºm8r.oWoz{e֮Ww=sЍC ir]]YKK wB~"T,,j~$F F :wѺ[8;q5%WL[4M^ l術D5^~;B_Be^x\)GMCQvg,iLMĺڝ;$F|3`s{/IϿv=ᮛ/s+-+ZѾ!-B1XH*R" $K|袕8EQmLq@AU=MS)@ EҮp`RQ\T2{xO Ӓ>e,{  >,Ja" v .z^PAAMs2"U9G,( ~9w(3uFz'ڕ/v<#֟; 7Pw<:[?w%*zH=$Ų.Jܓ }]&h-uQCIR4X{k@/S4Qn+I!*y9s$icTn/! ] UCg&x K|Bvf~VzNڥw|;Vء~k@ Z  $!iqjJ:%XloB3y[}e0'{nv7v+<;v)mg3Ow'&>#O^ /QjM(UP9J0]g)Σ|bvbOqeu.;n̼/e)I0-bC)#O3j@ZhDD7O/wgڋh1w~UB7J L<餰@LR7$BQPEqQUUְ3—]2ra"b"_L$Dn_5S9> ,_h9BF؀ A\G?d^6Wp/=#<5,pp`xf"kpcAAϳwn}`{_<6ODnI1ٙPUf+Ep_0beFUp\3^52 +V*1WWpd")9rw<`kjX_pw=Y^ʳxEWGCH@ M^)JFecs% GNѶ u^iiRJvNiD.cO &BP xr9?8(LLgx>g64ܑkW&SV}5Z I|]熝zp2ς2(0zBvaִzzʍf;p^'F)A.!aBB3*Ԇ*$UP +M)deו/ݚ^6|=!$g_nO|;_ww-P1d:=IuX`j-e&΢6Ϣ \ei[M t4MLi8% mY^ Vȯ~_aʠbVX{BL6sFM%Od)Wy_hVn#Zfd&%'.|c&N{M].2niqQ@doҶLR웋q7Nsǡ0To_ R" fHqSzC'2# EB0C@aھO6]#`MX@`߻>צ@j41'd*nyᢨ9CVIsm|$Bٰ50) ̯1F8dZ `}gwĢE\ W Y-*.wCR*,N3Osql. ry.pC! s#BQ(+yBWe>=" d.|}r3P8 񵫾#z `S$w>1~XXJA i(LJr2$.H]AAG4 l&+3!m24h(Ps[~Q~b 1,u+_U=1B1"hiX=J2) iMk uc;RD-5)ɸ}T۶~d{mN@d?|c悴!5E(2  fbA!,\Ьyd:H2 .[EGU|RMK>7sfS2q( ^3#rQbA@ցX]=[Oj. t)1SJLsW =QDU%R! 4LbϚB`9?p]~W>Ԏ<w K<ܔJ1QYpTCb3,T_}&ffeEhU5/$D%p:w4үƻnn0[MU[k3chX@m+$7_{ ncǿjCP3=MS woAeo nAvf;?H/A 0FDĒw9B@-0WqH_322탥i,{H!umanY&-A̅7uC뱌|"/9UNGE3%O!#t;p/y'PЖu=h@4ELH& }Boj&0"Ĩ}BtdR]_7}ߔ(+/ |Y moK_j@9kRL1b_S#9? .u}b{C"#DoHM1b2i&tzaсT`<xy@XCIj yc W;z-ڕxEu\_wHZ;{x@@'7~7~+o𣯼@7V!Jp;`1ƄWIFdoHLIbadB!m M4v+s$ta] D u?6lcA0F#Npl. 3Z8O|l%Œ#$BbD]BjDukrN6)_񱿸{޺)T(m/{U]W@<*f4AciO@,b)kA,APBHPEQ#m`Ltia: JV >0\JJ,,~ƭC?rlz:mBE504 tm!a44]Ծk?-uvQ]qA%4^M:4o|ϗ;W|Ѯeo 7!KH( Nuof!rK?DRDKM>bd(CQ*FW5Yx]mosyhpر,Ba7Ru̓e'o;kOA@\.S`-oxy X<7H"%k)à$JbsPI6>Z\`YW~/YTlno MF1~w2FQfѥQ_iDT||Ε?gv^L&" @B8ypT8'~򤕗J94hۛV)DKE/u}7sm?OgDۚˡL4_]ʤE(>v1w=ϽTIMF]<"g9k"H$+➶ͬZdzbI@cl݁PiwqKnʝ1nqy]U2`.\Q>g8.g §&jt[;p/_gTDH.,ʶ;-y޼z(tJ %{kPD@x\ n'> 2ugG}Y j ye$1B2yĩ7Dԉ{r>ŴC Z/`4yl֧>g3Op(K9]V^_ Fq_rR~t Oo.1bṇMf^+L'Xiz&mISe_fH7ot7q(D| 9HcBh!_jOfS! ɩ8m<~oY]yWo9XZ122 w% k9ZU!BS6r%c4 ew:?%^|.cY;;Ы|V0 `ܲy!  Cyw(0=xPhCK 3+lo-D:ip씓%v]]|xʈ! R}oR  VaXG@qy<kX_[ʃ*ݵ/Нw?x= SQPK sAт,k@6n~S*]AlCd y]o)n$f-STb>yP+O;(SsiH'9Q6@KMHɡJE`+ +jXt:8tIȮ=O{݊u>w_3yk R"/W;ia1)D]REh[07ޝ U|f B4p̾:wct:~ vy=?Xk"r֚c,Dc:8(X+ܩBxW\goH72>Kɗ%ݷc(Atu7h%j9zxV|jQTzN {a 桇wxdcz3JZ4{ mDPEK)!yR(bd@„BXNzHe>v`%dEUB 1՟c=kTN&@ᰦ=!m0銍B!򶪊HP M]u&QUns(bťw.KrKrO Z1¡2ˡwE*Xbù}KhLf]s/'戕$KW 4^J#bh@cy#$Ety1cab@JÍ﷾d77'O7tc_yJ9P  0X?~Q{:􉃉B jGXyC.@_P#kJ Ǣ6ԒR[)cn[\ol8@~*|gBZ_DQpmze /=5vt6Fк.LNSfLY*hP*ziX(@`pH6Myd)v_0v՝O3Q Ыń8!%IbB}X>I <~q>9}^뻴Xb]J I1j0zey#-?o1 ,1>>GiabD@?G`8_~2V՟~l傖 Cz9Fē 4-&3LVд @krVL&$zhhқF%&(?66FذE1;f-ЊVBB[GziϻZh7}hphEk+Aȑ 6ga$ۀBGx$+o| n P:☸,\9EJ5Mhڶr 2tzٵC,fqxd,1ġBGgC2K^Y<uXŢH4VS }кE>eFh&z1moo`񢶉R54m}4Jߣ2 i(] dqCO<"';}5XerY7mBkHЀ5@fa0 fvbfV)*w$d#-B)%%B炣hrB#r-$r;.!^J49W׆#(bڙH` d2aײoj{p)ZrՂN @!jPUWGEĻU@v*6+|@Rx k 4*H~IY8hcm.dX`4(L>) yۀeg֣slp1b }""k̢C me$i1`aaATվ,k=F&O~;ʵtK#4U8d%JaFKEB7A}rԁpt @"zr!F@HPJ )jA-oSUUa`1Ř&Zq_@%X؃SSu7XK|+eQ,24>/FdSe1=a/ ^&_y[/CLeGމˌFFF}D7 .jǾ&T] ;}Y輰v.CciW:Ym@qxaoDПQL$)Ak$R%1sՋ IdFHl=յH_أ^6tVd!j%bIT ;9)`% tjK־qM>񺿫TI+éȐ9D.W}tRJވ1̠-4Fh E+#G黕̛3X€ U+H^aioLz?DAdQ4?R)%) $hBGk?~V t-Zx]RVvb:I0YR|׿ n )tkpi $:cPÌ%Ty>Dm01§aeAAr<.cO&"0C;b"b"0 i?[nȡC͡>"Gg#[Nu=}#Pt!(RCbhdهT#拒 PK{[VVWC!<_  ԒbU+M_a1Bр܂1@[lj˞20LT)xF^$T)$\GDE } ͗Z?EQ+| ZW ܢ^Vwp;ͶXʣ}Y{R;p>?XN&&\2gJ-gduPI53eUEJYыB]x߱pgszQ0Ƞ6ܛp,tg@٩c$sK8|=ZF#zPS=P}~'5G;cj~@9d16FAElPcTB$)t 3ZgWea!d Oƶ5 PClzBGA FaՀFP2/i+yU)$[b[߽~-;"880] h0FWdqAZ1z? 4O ^s|[(Y; mcKG;k'dpfZ/-| o43L&!-%Õ\HEj Fµ>㾟#s,o#.&c$CmKx @uFhg'If @^J Ht@c6 ODAd$fJ A*PӺTL Cy9&J Sh$D`"2_ze֎@ƶDwJ,nB⏮bR:)@m&H))>h,Ni~^ |%"'n0ӾVޗ1:x]'`Pf `fJ;}:G@F{6ol~ۑ^;F,q@Fg w ;>Lpean"# {G %t_PP!6e롕H{%y[ @˄!V2 >$տy(*v9̟lFaIϿT/ 2G|ˡAI$0 [O ikAbA aTn bAd<ұw{W~ap{W![D!P? AG0EDSQvH Ԓnco::lKx !A|5QR`ه-OŁ1A$tuOBҺq&ÇrwOru@] /s5L?@ɟMf]e)#E\r,%c NH6 C@J7oS]~YKf)B Ec!@sWph6n?M/Y-2EAdWM;"u:TB!5A,0d@0s#颋&q\ |:i2D pdkCt뛰.oG-̼Pa 'n&'M1S/jm"hrXʽ9\P#R{@`aß~Ź|3;zOuQ4V~Sy㗞=q8L sdYiL&͑{K6筽g2F6AZL0\-DKՈ{9O76YqHaR3]BCP i#BC?۷-:Dx[uv7ֽ^z% w $A/%=|C"XKPw)B^KfvHk@;H 2x/AkPě YEΑ)b~ +HM{,!--]f_aVC J"̑JV C$ `ϗtR2bd꟦I󅶑Y%RE/3(7'7s㉎S4;wG=i6#6AFTBp zbC9wj5P >1#C?(i44LbcB Ѿ'R8~;p<Ԋ zWu0A|ƼI5SB0:zgچJ}Ϛi-9ˠtVpGsA*ulFnC 4 2?,tQT {uV ;C:r=ڌe'.ܖBˆiTQ g~'ȷ %|8Ȥ |T6)Ly^-k5YX GG703>/,WC)z REPiA[]v a~l''O%.]ޱs s0}G3k`ZlA(PUT -Se\1/Z݅R^%SJ9L3,%7$s.d6f4O_+7c p4ɨe_.js^B d6E> PmtIm۠P~]??8i`X.a5:s)cߋych⹢"[aa ": vKQ.tӣfh;9/^40;.k؃av%SV&!uKo)d]I bIaY%ޮ#(ݮDm(&Иy}$F$C4 $I\Pb_ŐLJCӄs)gN.%lqkmF܈Cݩ*"5=hIS1f<4 cuobsICNE$QvM޶ ov.uToz~ä|7=O!r~|lfg> M4M4MPa87҆UFP Ko5Xm9LBB!5kivA?]q"cBJfMپۿpі-x+[ν @A=r{vR G$4HHwWBպvڟ,I`-Qx#F.@n[ZR2}l)J8$J.B P@p h b01P!FXV<` >ݏ NɏڀF5{,iqm_2)Y2%C`lpܹʏ).Ɣ^;>}/!~u>#Ȏ{߶>> f{1Ǐ`h3ܐ@1}rf:B4MڶiBcmG?| ]x`~0Uf/p94GN^gA$摣&! ;7:r4<l]#;0ⶋӶ́Mvp@ R[-V[B!<_U.TJhu$@h' X$v&% y#+u= %vaʑ@#!bsf"IhIێX?݈ ba8f b=]'s$= (.;"P5ͽL@Q _JXd,!qtTDIQ@賅;w/{_]H+֎9sd; #cw-;0o<+˸xLeO|PrDYW~A F۴:B`N3*h~ 0*ޕ""]Z[CHJ-4*n`Wly?{dŖw{_t,"%@u^E,&r= 4 M5w4~ VO>W]muuu3u)2CwrtY|4%CQ\U!RY!BfS{8p6#^p߻BdJ 4"yWE x OSEKx=Y_.""|&Ҝ )s_jAܾu+"Ҋ {ƹ5WcG@V*$9KTUmF&,m_;"2<7LvRܔB1QZp(<+1wL 9K2%tR"ÿ;;~j[;\.Ål_} Rj%k-uP !]Ј0$XJL2RJt ]- ?Ă?1u6dO}^d8izwl,Sx8X$8QPPJ:(3j,ƘRrmؗ_aAG?5^㈷/o~uUE#9{-ŎY0YO2(U3eڶmmۦmu,?ldiǥ,}y5@ yH ,=24NО~ʓzrX4eM۴m۶2c2X&i[onm[O 57lS%^kLOK#m6MM|SzhM a WN͏LWb@&eOArD$ܷ/! t d&cH%jyݵ×^RXߡEXxь,f TwwgNɩi0K)Z!%4 IspS9F N . fGp0:<>ٞ0A};JcSV7Jg.xarj4Ѧi۶mڦiFM1F#hxdhxy# oQ6gSA8e?-pس@#cÓ|R;7ɮKiRXV92:Y=xR:x@ \5%ՅPy"A!,tl S;oq2w~߮?R^ <^|r@)0@ L:=w yqXXΑ)8&A5Pb* N4m䘟bp{gn@Ɏ0Pa"Tvv]gŲ2;+`س{t ȢʷȄP)hΑA-[[A_4 RT5Oؕш1I%_:PҨr }/^zue}6UIW bf=tmlPICbӯ]xd;n>v>:/µPR-@k5Vl4,,cШl?ve%ѳ<# BT1?T/s/vEf4  CѤ%`gT$Bq`s8e Ɠr _h쒃y^Q/@=S>4 h`PaL "x꺱'u,,j\]+o0KST?eTV,\>%CCI"<`5q+a#>w^C vt[7^^ě@R]+O!ngUQdue{nOjj,J%8 0D>JVGUr߅OXOŶIkg¦3WD;WOVh h wk,TTQbGѯd"saЈf_RZ"M !%XBJE1LQ۠<_xz(no'R#/=!˵]+P5TJ.V>+i0;4c0K7ta=SS8F ˜ݠw&_,K % .Nr:)ls94y.(k+r7p$ҿŎKsύGqŞc֦armdL[tԖpRfA} mD)aH-+y74ǟ%5QJ0Ɉu]1S6 A8g]l,d*ˢE=b,.0BcHK1ʨt_T:*EmtX eM9D_G a}akﺾxx񡬭BxN]eȖxJgRX$ҳIգ?D?ժ|3s$cP14Iusg#~js[)4K5%i²$2 J  mFБ@1Qo-Z 9k@{nH*~,l DыWXheguQXd7{g e?78.F-+9LPOkzu@MK>3՜+QhJHANw+$.#:MfD:×9NX=$f#OaJ2!4ilSV*1; d >F(Y;M : 2lc3T@}yÜtl ;l{ :9+:_0%d  0Y^US-Sc{a/tز",[ZDidFݭ K}ʧDV($dS10U ׍фO.,EB*F#u߿ޟfב5A& wuY}dr`h?vw Չt?.m LK~Eݰp *ՠpg"C@d&f ](RJiZ[O.~b(lTY_gE/4L}pr_,>v NlrmN:,R>7ڝՒQ"4iT5@eZw/0%&@Q<ȎOϲ4k6&) xkjn./ooHS )u BYRe[P+,d3 kFO^ߞ4D ?;<#lHOdh,0u=3mF)珊,ƽ8;a@ CÞK3}1Oj!&|@Q򬝧*W'_`Vƃ]dzE6%Ǝm˦ahDRJYr2/K%_]xBwj`n@ ۧ{.PCLyG>/ጵ3B4T*(PY ɄM~v("" IDATfTJ CeiAe h|ܑHdcӶM6MhI1+]!ީ@p4H$&a ˙H@*@ Y=A$Иqy"_ ZUZ^Ty"C8\\nOj@Ӄ @Us}CrUV x{Ni9qF}/((븠\| |4-i<|$oD Eh]('Z 9( K)4p "ٶ6A$Ml.-k)~E~|f}:u0;t>lNu2\5P/!:uF(qA`Y≰kEԠ;Ǣ<*(;tp>ǸmFmQĦdŜ^u>q̥~,)C.腻#s;Q73(=@+k5piH9Ū_;q驟sɏ1F3N K g_IAE(%%^ 8 +  Y H ~IWy޳;;3dÛ?Ga04iCyУ‹hRJ1{xqk&؋wnIDLDjL$2C$üէA  v]:͸f)g3󿯮ƕ4,M`W&W}U';<#.2w9sq}9'MӌFmh_z~&ACh= <1-)1%dLƘIK%+a`%2GaD߃ѐmxT$(I|ߗOJ!.ŨnabDDJJSY˞FhLb.Zɉ틒-Zxqag/tЇMյ|1?swxig~x r WA_ TP7a`)`zU,e)~𚏏5jRe~0߿~ GgQF=X/r[gو1F&ʊMi6``b43Ͻ_. aa֡&ծAPh4?L&=6y$1!Rb!$0&=o4G LΑ׆}o݉& 44[&UR`"yLNSciL%I FvR&`IZGh.S?#ƙg4 F$xS=ĀLJDEj-dyj$A̻3"ҫ~;V%^%ξrak P)) ],*BsSdW]۟|jKڪPONs֨`3+A)-:ktp I 0r>w h}t0#a5J=7PON@6p_]_&I`!P!)̚>P&YDp]DI(" 9DݳlQPh^hË'fs.Y^d 0’Da|گb-\xyxA=O$a+w8xt"5x"s)g)gq)泳R1z*c|xa΍$YMy`JѽKIwKKJGDJ:t_ډ6?E?qjC Qn4m˶e !qtPYĬla&֌- |}QP_'ͰD:Ab!=HR 00 b׿G>O<2J#~my3j[+|JXQ<փt[ϺP~@E}n|ϰ(7>OB $WO0k5bKD")T8`$_V3dj)IoCY|@B3ۺm=qG9h[Jϓe}Hb!շw!d+@"5:qʎשuH2R2 f:.vsO$oQiZeOn>_/{C> 2O2wq4Xg^hԺ;Uѣ`ӄXs ` XXz_~Q UEFnc 5pvt6疁Łl杧[ 6y @Bct*I(|+|/1 ID6Χ%#+ Tčԝ~*ΘYe˲ э|_BɯZjmun< ,FKKgf,V"20 ;&?%FpNæY}`Hb!H. 9/9@;/l3՝fZ桫jQLAb5NTŒ13FQi AB]XۜR`x\7fne[YMki:K]g))=4h}+WW6?NSE =|>8 KZSՒgRTՌ Edv˞ɤt{VsgǏwTisBj_R'=֡7mEMu D_$Y^%ǦD0w'v p݉{?C:wB2fuy $;BDZd$:iLi'\BVewUf$@`=EBpݮ"b(٧%Rre6zn|z8#2@L)*Y-IVf)骤$~^F#H,D')ME K|fu 4*&XO/X3_P'K("Py?m{)r׾ڈ@MԨK%m:.X7x] @ERJƚ0(Ɍ"WL ;v]߷rpL11e6ҵZ7$=nrA/n2>\+XZzrȐBm nVßX Ё-mtmS);蠙@N@ɦAp[ Aa"~e|3WqQO%,y`Wp%YA^T"79,G0?sg)h C8@TU R*T1M G)ɨ@QT+(n5hLhKS <_g ՟u+eT%{P]9n}+c~7$b ޲"VbOOl`DE<$Q@=3Sme 7V1RUI @}[{|M|kZ<d<^-V#7:mLcGch#-b*D~w[xzU6jFo SB!8lM/#*',SW!8 2F6M!_39];OHp<1d9]V#;kuy_"=GEhBUL&"H kkFV LJ/Ab:cgQdV׺ Kou$Lm,bdNfL&Jtyeׅ]d@FLCp봺^Ubw* eP;\Uʮqç8cv%7tB ȠX[9&RFf1e7+foG7F~`&h[4-M5Dw$xq,*2"8IpN!=ЅDCB0, &v SPý';SA{1 s%/~I:::fN1q:~$Ry[-ivqwy7CZlm[RBªX(XI!uُOYn8|uwE:Ln J\]MCI3nA E&"7`AӹY0y#ԪZCfzý \`\8K =.~87q2B124jH̐t|= D{My¤I,(ܗ,fh@ rbgW߄Ջ.-㼕~,g~*'2E Ei~t!t?uIqK}}2)U[̦/'"Ь6T}qQպĺ\0"4#-8<ŘR>^д-1^lOY)JQՌNQko?uZp-3drm Y\~WszSJ$yt1܏l DΣ$ t^GnKct_XWQ A^5)zZFpƳ|gg%:S 7O?JFgh)Z)d1q>g3FKMREH&c$S{3y7q"te)<ٟ^oxHEUd}Eq>[U}ѣl%Ƃޔ Y`hq0Fq+m{d L10! 7iaQ/O q1뢅:+JG~u1#g3N9a6|f4l3Bօ~au4@ _ѻ^zӶ;O w zcץkkrd"浟;m?ƄMOIEt|9vc42vٜL4 ВȝX\P P~,nz9=c{Ҙ*ICT\[*w4Zs§͌*(}~G/|-\"inXMo 8IY $x#1`+ +;rݚ@bSIa TU Yi31 SƏ.$Y7@3w0&Syq>(e5kÌ[+3j[SCJi>?r4B.5o3iH((_wX+~`Hdw"k=Ů6ƟM# b|/OkNT/oXpG^abZBH#Ydz% ]0w%UKI̍@m}SEoq&Cc݉ذ(.2Ͷ\bYՅ9,| i1)*aGaRHn~Yv?Xkk>M @v#sE3c\!XN*_pG>yʱ`7nkoΛ;+Vy":fd)bOW0B \rϾg^s~d!}W{ӵ]t!ϳEfT&Dp%c"|8!"\'#XЪGp MJ V2AJʏoyۧZ4Oqےb!Pٶ4$S RVVVş8M8'/|=$6(p^I*@ (g#$RPe Xt?iǷ?2d^-C/R_| uN_IE,+sa40^ qf"4{.M)T 6jeܰUkA$(e#ji[D@͹CWT'FF3a]yl4JXyΧ_c+?[5 B"q3CvkK#芙= sAb05rx# .<b_Tgo,* z8|? _ IDATntÏSq,gD@ ~O\a d\Rr^jnd#TDC7#DY 8OVGyn4^YO/M Ͻ`AAH(4B!fiHu p6ӛo[p"70 Mc3Ov}U?zP6N=rG9^E.hu=nA zy\&J?YP4 0Y7lF$WOf3 )v#vЀ` `!6,D3Y.Ky/U;p}@]X.l`rhcR]fuf)ԝE gOv&)3AySϗYM%g8 )IVꅽh6WQ|jp ,2;@HdD3זNol=Ir+]\64"FHB\UDL PvĠ oqEy/Id)= ^p*K햘j=}b˨S"O<0]y*D"ycy}ҪIsO>W e6xuMQ)Y^Aڟ'qʀg~%'[*6!T@LЈv †K#HC#Α:D/M%}+/TmC\_-(1{lRzނYدst;c3W@RHF]tPc.%r 7'bV䠠e87G,uHBfrf -FfJWvMe nqK*(aI37? T0I 7sۇ(ܵ4\M]?(}L(78ۗLDT=GMF*ꂬ.U'26I ϱT1s4vݐLfyY~hH鏏<ύ;,eQB u5a08G#a4٣V=,}e/fZdmNk42?S o#=MwPT^>| E!lQcM-*}$˒lM- 6X2xbrc0 (]4A7+*" TQAw )0ۀ1`-Y0,?_S}JSXPrLtBqK:xA"9*V; 0" P}Q413:tHx׿U2y|N&/Lg1?k恳ⵚYw]EX5Ll4pvU'3%c"pRNa@䀂!9x0> Q }O3k7ړǎ٧ gq}揬};wNy/w*ޜL(Rd؊]p`6EsϿ`oZ&'NFۓy9hj*1^ju!_`-8®Li4@Xki(_ُ}g= lFh]=4823p G $£1iTP(kZW$yRgqqSceWnBnn0sh 9B#e0i/p:;~/ͫW *~s4i\?+m0NTέ:px6&㮗A[t[d;񞍥CK vL49RK_gL0b@4) ūCR*ai>K݁+w[839C%H.L2E㢨eRA9X,'#gK,?[$xۑKZOV鿢"m$V9Ҫakˡ1)T|.33,C7Rщzb,|V0jY( NXL ui굼`qƂbx0BunԿ4.UHp?\\ ta%N9[g?7iZPqG~YBVre^9G-gzJHF.?J5neOhXL )@00rxQDRHFOBA+%/Fxxijp@ؓLsV5gq,t]u}^v;\r-^ؿ]*tPTxne+.(Hoh p8U l0oO$:|y8(޺]h$.њJ*n=Vh ,!tfzފXIhAؕ 5ĐѡKs#\70ʗhwֲ\#ֳnv<3@u=ڣ"/*/APhX+"O]dJn-} S2$vjR*wO^8c8rɻ9+!V钕 ye%U6T>$Т-򂂑nU@$87(1b.H}Q}(ۉڶAOwͻ&@awl^wљO+?j!ℷ;DM52y8LFhH gnK ցNsNS]F̶xjoDh(裫:OiS'jxg{:%6Wk{rDjͪ|LN 濄&V.S/-SdR]?o{5@KqqAUakS[rW,bq}qwfhl>MԌ>8XY Gӑ--3>sYȩ1XYa~H>@/-FH4SPVDN lU0_UK)\<0妖7B|j鼚OϠr|f/06'A? ިQq+"Uz#`4g@7۸\]Ė>j"C%EۅvFHŢB`D=YYWPQyвz+_mdSC,G]%{)ћ%3[Zna~G?ʮ\G4Vaco%3KY2{jɨ.mھk_xZ)9l=ӻ;>%w8GS/US@T-6E!kŴgv8pYv >/\4~\gGӝ;唇Mie]yu'1T{^*ĨJHB8 UaɞvK鳖Xn"&-_ ,{g@6=uf]U41"["X 0ڞETCN 6:l v{ ۃx 7"(XQ":tSsm&%J.L@OdfJXp9V߽C9+.{frQ~D,E}Q*"(Hc'yR-L2 F'հ]%G-5=ĥ"khq?sW#hj4"µ' sD"QzR mnb.l5]o.+5ǬSYMAZ:&i@cS$RdoBm2Pt! .:T Zɲj_oٟ,dP| ? m/*@||Ϟmn\\RԍzCPS9wG)W :䧡@A 8Xu KDKHK5lND ~G޸]!5)@ g_"̬8RlVe(%i7s9ۼ}-@e:zA0_e^@'@RP2R(m0&.Xx+T}-}3Hpty~+euW4(d{˶ˈ>M3K{ǑK~CB%$DzWhO0N$搱EpYq54ik0?~M#Z'/q- &os`Djoh+A%<5  *G"R#E K`#S%I|~z*"e6B36eǏ|DL2X-e\wKt$BKQ T-=PdH!M i3akHJ$ 8P|=@ N/'X3Q̒;f3uI93hF*:1Q9-TS|[papeEBH)arcJXRX1@BNN?[| O/ ;'`ήn lj4;%u]&d҄, JXw-[Wot1;sa%e2s٧_5xH̏c9iYuCKuK֥tٝ"8Ph.У&=Rrɽ\P=r~%RPKYR)o{黃ìk}wo?NHi4IۊcnQ/SYPcm7$#ayQC"?SM½:{7ߔ=/챹-ϭ-,^JY,9B֯>!7=7?d +Lf}~:y>QjvR]5GP,e^ʮϢ⌴XPͥ Rɪg6߻` YSb2X&{㍓[ⳅ5,|<#(\;êG/9ni5Nd0Q.uwRxbر15𸔭B-A, ϒ-\״ Ć U%Z$*WIQ@Ab*N#aB]sB.W|ϋ/ "ʓM۱,nu@t{q{(1jGcI!YwyuSKNҊ~2F @ B6i3 (n*@y;R/ON)q6S_*E^.KCp?wUnK>zwՀlrq>@fk'-,!ꡬH( L#R-kpo+N׆u}L;[It߂RδWG.sΡ_ᐄ9dx.HϾ} 'MhfDJ)%3KO44߲bUzWJ%9@fXwi)5B&#U*KLW$tZa!*އek[ʽ 6ҩ;2Ϲpl+- >`T@xSF~%F<)z%p9vb#eB #c5 Zl2;gW %x)omϞaa߉ pK^sӅ~TSR w#ȹԤm J͓)!:D:2VG[ՠ#TWr7{I⥖WU)wBM@(kdzNx3,@G.yW9пWȦxc`z@ OxZ~쑱b…r7̘̌d,.DB+y0{W[1;:VBQӬPmSVH}{ *"BԇN^(^nкW%<~x~ȬfU1[ "@ bcABȊ@P/V< %r.d0G>v ox뾐v_# ېs0^%w.!Xkkߟ0O+ݕuUK@  U RE3 fY-} 7L}@ |=$صo,FWw˭K-t \.|-L=q䒟k7hCz0/Fqe?P#Ǣ@pDAmq1pL)a6S8aD WB*ZU(Ay%ȃVHүrA ~e򻷿kD:p~,Wx79wcksps6:ޝ8: FP!b_ZaJDip\gتj`By$  e)K -H|efm0KH~ ].0Y8z[nT94{y|/cP'Ȥ:8(1ą dM!'g}_GsNŹs,d =g3;@XcR2SrXH=/jA l Ȁ螯?'LC ]3&¬5UT'H%Ie=|_W,W8z_nmub"m\GD؎D0( Xiwl`)xWLOuh-'75OgxpYZa57^QpP'CՎ eə wb}0Ŗu,}^ u@G'D9Bjr;.yO3z~%ia Ud8C[ v)YJ6q>lε5]8:{ho|[8R4ya=:ɣfR188D&]K5G  IDAT͕;=h$_/gz+^|ލvNEH^)W(GblMA"44xg-08C7eD\;_ess)(U\F.aj)Oa@A/!+NCCğ?_{pB'v'R|P6] FlsK-$EvxF?­ A+U )vfawS8pG)3sb>կZv\w*jGYVd٭Ejz0O^- s2ؼ;×K_,dxP˯:#5EO# @/<3g'<#­,am~2gFNկ|>kH75KMl8Lg"'uK]ץd󙺎a " .iZZH ՇBT"YMհpB"—flYjQm+5A9:Jy+_mW`e͔ r8euPD* b~tAE2f-`PQԜ+]Z_54gqՄ/`@ 'I7}Pn3,/:q \ݟ州Qډ^Pd(ǃ[R<:.Q *E'%(BuW$Z҄3-=%㱎݈Ё3ޒִ>x7\s+^]}/H{ݖl*\u;̂C`bh7c>E\cPiZn F7#)ʎRr;Gqgv|eLRObr'M־C[PQL\gD3eA{e 7 X.\`l]X4_E֯icobht-f+mJ8$JqfHCJԡcn”Cw.V7>U52E>֊Ebˌ@nxP5'XAppk;BQcja}~A/:OϹOtX. ͘ LxTڡ_ `gK`(65K7MouD)K6Gݩ N#If3T2$<: M!rL9 @_[o|TKo|Sw,F&1E_}B8,M,JX[Ofgᡠ 6ZpݷZ.j$t+>rvzhj0^-,CUJ)czKο{o ⤋Qp3l ID3 ]J/\f8q1 b"m<4rwߎL(v:}%]`çh+L0m>ضw)\w>.XOZ Z<2rc3Gw8iMjNGp ?VPb)7#i.ODR:}>aoc]ޛZ"R']*9#9͸fZIH 3/8fBbRPYV #.p.3uGo-1|1ۜ:Ȁ+a|tm"JՁlMVo@hRCXxg(}ztz t:R  һ7_vP'NrŷVK$pKpK(GMcƲ;xaq fOk7`>x4 >]m|\W'̘w("!JQ؎Ntnߏį!L8cqL+%x j! (V(בRž~!4y[m+ auD[n]c⊑&lY2:BX.j (ikg\P2IjD^P^+tDp|6'Dn-jkc|xGW^4hdV.XA1\l2!%a :XXP@x߹wFTx!,ԢOz&X{n~8M\MqB[P["(xn`Q{^ 9EC?/|K7eL-6&'W|l^b^B5DІԄ[*UhjjD@߰(P0"Eߝ?WnuD$vNi滞N%#$PZ;3¨j.#wkw X.ƞS[Jxgg`D |bV&jh j#-WkUF+@ZzD 2%!%u_.},˥sRߛ쏆wy"mIp'kQDM&@{?zx+FyJhغxwS ?ʡP;ޫCZeUUЖky]!Z7ɇ {E@g)$va/6(4%kt 4 r;:3TFThQ51U, 4 ᪚q >6W?t7Yi$׃.cN-@Z\*C\5"T[/R37wY'kS,=ot.3$Sx@vFyD gB~ _G8^4Y3,RJdII3]wh8D@2rɡo)ݗ~&M 6ijvZj뜺΋>/ SiYef+g<;"+7yBd<`5D JdLbR+XqpszRggDte 2c|7?Xd#i0ɛkAK# 4-^%0"B_R4sx{9Ͼч>|gN5EL~V=U&(8ڜƛQk+$Eo릉5U{ԌaK7v <5.kz,e3wSգ1k֧ ʒNU0ӏ&R%HCGɽ yW (<}Y,KoƍzЫjp;~#EHE> xbkǏQ>)9ċ?AD{7}SWy;Jj6&S^4ؓtPB 'SR;PR;p8K{6yjtx`7r&zÞ p6 guM "R%am[|l1;%!HvX i׮qVa(ht{8e" ,T{ Zv0NΌ2i}2."gsM3v1Ya `abs &DT Vyps/ sTHRa&9ܣ[)%nay]ڃFowJ(eo^#dF,8N5r@IN-/?׿~O[>!i4`4S4W1}Fm1tAzR^B}#E|f㛝{WyZcfl}{n;|__ k`h#@b5χH.NPXA03b:".\ %x*v@{'Nnwv+N#`miוKr[}pWpU ;3.>5 (>4YTkI^ce3$XѨ>v6GJaQIHO }ݪJt/@.&4[q}f^[2`C\T_~cFZ9 s23W|S}]!\Py[8'cd^}(5}6Nρwܮd*)Z:Zf/33Ouc^{Q'͎~^;ÏRߧ1ߤwT捶p45)+jMvfgp9EmG5JLNI8K6؛(brpf[jyH\VCIƛp޼fdXOB h6"³+ hmW×jGF]"PЄJ5 7e9Ï/^뎇..aGPWI##sWkEQ{&Kw1td6L J)CKɊX7, bKk)̾pS%SB3;Ȟ}>{?NJ} /?#ݱó̏=4 I 4 &=i!Pâo Ԋm? t t3ƳG Ueq *򫷬~C\N*Ee5lp} .. >c̓-6J *2`a@⺌nEf _kԨp e&4W]۸g;ɯwt3#P\j!0=q#kT6/{ 1 :0f`"z h'v+\5>r7j\6חTmKfniqei~Ie!«BMj6` И#H3Arsv-|g9mx80U'OT;Kaoyw2rt @LyҸ{ u{k'|.t.pJ'=:Y5RvډM&OCz_j $XIFKf&Ȯ\dg.q-9}av,}f3G>ù\ͲY6桄 c[rE|3kW#J*;S_M)lS q@O>͌Ɨ}o~-06`Ɲ7+頢WHa=\d}Bٺ4u+:ٷ-CwǓ9v#B J dg=Aga. aib`v=nfy%kdt9ۏ@լ!u> fR^i0LIW0RuϒSTSMlK-m"v1T[88١mp_{KΑ 5@-2XVeE E#Gzm3{+gYIcRrFDsg"CX{E+s"PJrֈpC:]3d zkF<;x5Lȋsx0__bOtO,OvZYk{֬䑶bi;خ8BAJ*B5k!com;o7|j.=! esC9HƷDM R5:-E78 j@#'QAJF=C4Rt;K 1[LIf=1G?s//h{ݳgݼnʶ-Q`ԩCuՒ2̶0sBꚕQ{;($1 Єd5C ;O53l~df1AΒчu֩٩KOܹ~g1W5 XXk@2p``zaaG*s__ Ǥ 8J R+/]XEXZ j `=fOP'Y,DB^_ /E:{8k/~8N QwGhz%3 ޳ÃEqa0>dalwEXAآBnbaV/ċU;:VN&K6,gW`Cl%㓃TvM~ratxA>PDF@U}x]`zD|e MθpQ;_пJcj֬o=7=~Yv%2OAHg~DpT-ðWQK[TRѯ€?4ʶ8"73<U5P j50 H @f1jY zK²l-YmIvrSZ-4E11U՛{?">f櫉|EUqu͛w8gߝΊr{K2lGK5!b}9'*"zaM}p$M҆eaM,BqFlƬGgX-X=Ugk\UQY"9a2djӉM&755,$ҟE, x׊gSttB [gvRV%5mIƴϮ/^U);~Tɴ5: ,S O_s J!CKaazћޚdNG:M'.t٦&,Y?fa\^Sa*5ɚrV>6H)a&s!2_mvY V;QR3OKxG)b_B/3wn?Z&\:0\DIzDD]I`p'FIG t A//QC+亣;XJ#)" %pBʉR&Iq.^O6=. #J5`t=(K0& XIR8krw0bds\B/ 6j)ZSY!R1 86ˤn!GȆn꾠BR 5)(,5ߺ_)ϽO_3!W  \B)X3V{D΃O!t/GhO#F E)w ~qB^^ᰰrj4׈(tTqQ5xd]`jJ>!*P{nZZL?uBu ~K7uSKY,ᶰ@h'2oı9>fUVaa`+@PBoT rHa @Aľw"L"= T:*3'۷%At৖ꈌ+1RiHAD ԗ6F:stwpmjMO룲R L2h #mFi픢 @徟my֘oLALP(q{25 1#zAǚ+&VAV,!fN}_C/7x,JCʦ0q42{>z^|rMAsn=B'R9G es l)e0h}E7WU  (!iivwGޡ{LTҩb~ye>p;G9 Н LDo F{9$p g3_P_UEm*yѨh &Yw~zs*A•-JjwVӼ$~I X=54$yZv{Dk<ȋ۾mDE3)݌΃D_yf( %NJ#nMD)Ḍf)&"RkĪKA!C<,ZX:KAc3֚|myH<5NM)edjB*D>?u`l׽L`.I268)Xmq;ɗDK##g}ޟ"2]w «8ퟰx|Z}@y~8:61'fN)%o|&7~Z"i[)((|*rEJ*-[b̈L po'XiX4 f #X&U'@DM >?sCy!x5VSj Rc9F ˆ`V)3@BZDK-N=̾Ļ%#2hfH;+ ~yS2c5>:p+-UOO9xg'ӨxuũRL.M{wP[SAkifE=2&" U3wt9{o~@]7 N7b/}w``+ϟ룠VrfP,.aAK695MRF$M@щ!l{Cxd2|2u,!TԿ[26 *(osh[/\I׊꣚c!S2T*7)׹T6YZپ$5",.5L&y^89WPJzq> ;35M`&bZ(DL226MF h,~-2ăBZ ͪĩP^}ó>;ק 8\Ĩ]#D`&5zKK8DfK9ers-FB xO1#" =IٸQ~T+Y\$> V/4gLH 8ODv 3@cK~k:kmqiDg6°F*7zn-|P#(5"ƈ7ű7KeޥrD f0*D 4ASJ[:׈#{caLd-ك)G Zp`iIFVQ%"viA>*,D{D[ LTsY,6?wאDj_w[,nݿoq/}=X> uXU:֢`qQ-QbFM1-,`<2N cyi8,\]p{9,xfIQO`TAy+ηȿPծiC՚~ = DdMor`c֕Y iU&@FÆqk,.yy2=>߾ٶss超3g3YpX>6V`ي(e5MjR4i4jhchqU.J?ݙ)_D`^S5sֳH@Ͼ %L&2J.Zm;; R2a*Ω072$&sd6°˦V6aJO_d0B [04&3~Nv:qRdd}s_pw*YqԸj`-#`. f>;CF[ 3R@#pc@b!d~tO郌V¤k1>d .!ؿM}~w;bi^xɅc ™;Z╆w/$tD݈}i׍I.&.7I)5Q:,i<x<|Ӿy۱w?(ԷeJD1EYd@;H  }bq/= "NpB-c!tH8 ) )`1jiiS`e㊲v9laIevK.cv,@^b!RpU;@3b0YQ>M(C3R/8OZ[ \DT̨XӃ_&147x9L5!Z( ?m +DEE H ]-p/~fصvѡY e--툧 oәս]9ә:X:F#Wvf4jh4&QrXd(#),=g_b]-B8up-1@2%a)3⽔Na IWAG??nz_@U^OboJ 'i/E[١;_= :v~;>{W,WgLA+h4R,yAJ k̕#rR)UkVeH 򆂜g Gy=( RdF47>wmOw!T[*0ؽ/x3 ųϢvqn]U]ɱUq-Fֿ,f0H uD!nD, a ̖ʜ&C҂5Pcb%9D\WbLI(@L$G~Q]cd:> lHLȈo룣e2܂$ qQA6cRPL#D|jQ" +SzZ:+ӻ=ES;3Fyݿ!űDN@jWEc.G5q<2A.G+-b@wDmK^qW]#= J|^l7fo)|@{J/oZSN:`/EWRj}*BDLuKzϬ?:6x(/+1zP 1j7-- ˦)R΢A1oވi dJlreP@cޯ3Fx}\?xn@؛l4d{6 7E ?ØjbHpaR9jTk96x\_O=|Ifywh,SN=h+{ا>KdJ0g.+(7c0Buտ S(H(ux!*ĵD/21@6}˯aבp @QI>QkzV$U&G!:}ƍ<#ڟpmH"x#Oջ%B?G{ali(%겮92OB*OVQ~N`;BHHbhCIb _,J$1_ζ*DMD ]hhBK+ )A8vrpSn%ا0)84r",P@bD섔!]Y9K+;zN]QuٞWˋ}DJlP$d) 4XUk j];i;:򊭬`D\Q̃ID :A:1o;äigg.`OTUC[5H]"R?qW~HNa` A!? aJy9 >lI\pcmEC/#F%35] ėHbP%+Oe_&]rp!;JcAlq_o}QA/{,WT @;uZ|5ł fJm]i!Z3ĥ$ӣPNӝDDUE$#ֆua!,J~̛@FDZ FH3з:K)BD%\Y6{NttN&S[d&+5v9O'2H%ׯt^ , #CclΦMZ[nkT8@lJA6M-t ¦xgx/1m D4\\es FX[\vD5̏`,kbyr>7? _ .TAshQssysB&D!9C)GP1;s)Rp@k(HzوVvnWUݘaMlc~So}#]E@3YAY~n;%9Ks&+`eb+LVt"^6t r>?|N~gޭOآ0diƴC26kJ*#,F2 l PAn-wȝ#0@EysG/E/2]I_X1%%]7ت-z2|(ju~]'Y봝bB+6H;]۵]Nd:<]̮tOL;L-|{Xdh[ bTS¦IR:;S<dR?.1m:pB;/|{:5`4ڰ1ٺ}aqpD/SEikf=JJJ޳/j}\5R)!4ޞd]W5jH_=`qQjRtlY!&e1X"!#)A:Bʟ<~iW,^Sf5U.xR^d̔d> F6˔^g&Zk?qU532-I<+mqALPTG3Y?:EÐf%%;_!յ/( EslA" Q6 !b>Zryl>L{9x.0u|#RX@DY^_tvz+?=(,'368 i Fi;=-ݣ)]>m )qyē@8cRJ(m2ڼedӓuQڹo{Ȥi)Qm{J9V DXTݱ;=eKn]j 4R6WiM&*XG 2ꏩ5RHchԌ,)i=}i )yH)ǒ̈jC)9<pҹ\'D`X hB{_y{U"mwnz鯃²*@9!?+"fv^u,w?ڃŭ GQyX#\^\r .fzx=so,N*y/Kh4%޼u 禗؜,3c*ff8yxEgOMICs[Yհj,j?[e1vNuN)+:V$7aIB*bPf?UDETE$du*- rYvXV5-tA֥E r E=#hɠObO})Ssމ3XSBZ/"-/ -\v<s]u6i[f~**]e^rfrKDIfť#$Nk7s_n@Q/9Gxx5 u:ICoƸ|qC%1suf~ F ԣ9OJA7-@eUWIJŮtlww?~mmzfWh5,XꓮWR%`'EFqʹ#.siE4 %EuupV?c![0C{YE('WIסZtjm |5:Z,4^?|At "Xyaj$"c>='{ZzGT3!6FbYMMYɃfdJo~ilێŔʜ#9Yf<ПM)hמ%Ξ~Jo[e.5 bTQܾ>Z LR``dZÕ Q71T4 E(Hf ØX, uԡq;z6> ɴtdȟ>a@"ɧԌtY.@u̼^^J<DM]/6*fޔŊ̏O*GKOJbiyP)as 1#n@޻d 绍wrȺ>gyɴX:p"K^~e)(%-5J,έQ3 r"nt+~?}ͷ|Ƭ*1 #-G3@8? m@ڬ"#Y/vL[dIhK@:mdڊ"*9-Fht]/tǶG[FF@dǿV`eTU :;j1wp\;BE#P@n71]D8{z"y^8T9Xש#%,,6{mp|{~cK+# KBb%!6BrߊX&STt@6L抣 6|>9Go3uH{^rޏ}H҅ A)-?S7^ #%MkA97%Et{JBZ3p~D-%.-{*("NFMohj 6>Biwk0/>{vW%'ɲ3aeAS+c'K%nm߱Z0~gL]e4eC'1N!U<>Zo(P zճ*Ho:@A2>D}etG#=rl#qis™dUD?9={衑LSh2'r}ͷea}D?@59.rW %AYC!0$gJ]Ok[NUdM/QV]N FC _~r!&3Qޱ1u+`}4]l5 {ǵpD x޼qڻ?P~SNz#z IueG9Xš|*g){A4N)_%"=YG.0pwVhQxV,lũ\LOc?r}GQ"u,|ͷǫ~WP#u`6Q0xՀ!ܹ1*ZZH$9+2Ro8}{ƍ.4aJEAf"톂13rPDq O߲cxv OIMOX>T\ -DK͇l;w/ #)ۓ@8c%GPi޻33,߄(XF9 zӨ)]R IDAT/l H"2V F=2\d>gh|&GGȱHvκD`\𨢠U/P jW\̛_[¡*[\wS1?*oP}|H֍H8&2T` QwmƖF6J$$ƈ5l &E_y-D|Bf8{ؗ/W9ڼ @wlP O&"zw~ṬW~><*ۼeԈߴOMjy}ix)o?#&3!^0`cpI{ cuH9A%jG0EpM,OEe暯5؋DD .UB);h+m6Tb51R=šQl2J@݀>CTbݺKQ4f:p0j}(Oqc{F%-1Fb$&wHX,0c|G]L[v gs*;}M#2. '1@k=Fn><1ӎ](Գyjz5̴$<NzkQk3^Q(2xSH7tJ"]XQL!Y(+eN}ɨ@`iFXUS]HDž܁ jgm4bͯ"Wp{2Q__rɕRRUqZ{KLZ wݻ//9={Ǯ}!k6L4:?Ry%'"cb%Vb#6JJIWsw| glFt9^ 2PZX+f\qU$F*ȥt!rF1y3a}۱k&h3ķ9 f܌x2Ǐ^Fͪ \+ 3.jP̀W[w Pt6BY8ǂ<&Aڞ{./aX!E% rq1C)̕<-y1cv|mk})j_Y8'?nRs{s"mؚ$M@ -F#F*M@(Ԉ(7ʍQ2MlVų( 8[!`5~h* Fťf1NOAjھ[kenmD%$φkWI`XWjNsW7ᯄP:;&qN3 Nfblb8f¢T*4n2raO3n;`sŘCx/|R]YRRJ&JFPO5"M۵kd%5^)2)R!mڻD_pI8)4-ޑkuMd(Kh :FY(oLm6/l`k&95́p ffd2^Hm+`oͼy؃"6X/0{1υ$Y", u_;8kÌuYŽʺ\\^:COr#e&X(ˆ'C% Ri*|}ye(߽4jʹ󒉧́puS1 p[z 2hPw@,3D bBÔFbM1"P+x @zMyEЛxWgV ZNhڀiڽ sde^8966#͛Ǫ湁KCҀ1Q`aމ~KLqrttl3O2~,%pH= ]XY:Nbx^9V`r;!@H;AX3wȏjJ/p:"YwqnB!X vz'cdfN)#U8a$eb&I4hy(yMGϱ[+W_&^0:; uYSVw[ػնl[XԘ⛜%yj˝L{mڴej!ws|;}m;{(5pBG6CdboJ6Q7L=kxV"ȪKf&`S5%S^88SXg4Òڨ4AmDJDc?~ Ea#^_> ǜ*d/Q/hx{}{ET)8~C~JM;QDdJMLlnyWkE/vG@'nO]q 3޳93)ns \mx 8zy4Ӈ߾ȯE*:СKa02/RB jDLDL@"{|THvtX(E8R5NAE\sqSIk`"F#:wä%2cտ~oT%8fo}~U栋szF4I^V({Y1 ExN,ڄ'dČBY0_}Ws=>7BN ڻĉVySՖ;519 >J;}mFcTDcD@Jqߒu:!?]sdrD׳>?+w ^eQ5AkB geDE4fլ ƗU$Rws%@^J/ F.Ea)(1xˋj/H3׈YT*& UDEd܅g4K,!-P3BQ@117DɈuiNQRWoy|Ppih'=u.?[ ]8߮t#Ӈ`w|?V/ z!up{j3K]D  P2DI$5(LԒRFd0zg\ 27wOnd=ZX^0ڒTע*P%2fpBZ n@ -Z3`l.9l:yby`spN왉KF{lW]cMK6Tk݈ q~6`̐%EfmiwYQkP :ZHxGA" Ңf"&Ys"Y6g,h'VN;Y,nw(HF|6&E<4<¸wҨzvtgg}zPFiiNSuRJ`3R xi 5ԌьhԌ)(i()%ӴwԌy^#}O83|t*Dhv^ZE7d6MO,-?dw.1eY>D'ޑ{onƔ@Fb@vKHbjl&([m[gq^ >YYu_7WWёٙ'"uk+Vt꾀l7| koHI[pEc\n{ĤWѕ?v&S)=>|^^*K^|σT_wO9f<{;}+DVs4MWAƋR%,_*AS<3Fbx<,Qg"s?r|'XB`A\ )WyLPŎ7i 1xJfJ&!p{܈R;k̥6~'h {?Y{1R39g4l("WQXyT"ߣZ%/LॿΛx ]esg~^6Au:c>/(EB&q!\ r~w2Lũ\4EEdW,pj̆gh0Q (<4+f2EsQP`fnIgi&?O+ޟĻc6qۏ)mw,[VOc<4>_ٞ [v#>GGFeA* X ;kb"J +ez__b9Y"W 6u08r~6B&_NM;qpWw>S~D"/zXZ L:y&h&r:7w5π(ɣ 7 <쮷uOOح%`睏m2}UAee=}Ҿ#l[=K(t51cf'eC/?:Djlgx3zk7^ג{ג{}<ҝF kI ͡L 6 KBFbJAyGYTeHPx LH3`j˩ xg@a}=|v&dW"3rFx:0c<ҽq0{O/d(_Y϶.bT~.nI,1g2KO>RT|$e!=m-F:"Ov~Dm: %ӁY-4Ͻ,´>ڼ>Kɣrh,Ճdij{.=HAyJ|OSGd[ce@ XoHC _P__.?=3>\7bOv nGxXx7A lgCR &Xli>CiR4k0P -VC*iT VdX)M6 H3查熳4+D#,&y]t@:3Tj0y ìuiJiێ44Fv:ѪWf,-bc;`w g+2iki l|1/f6Ai# ~uA:ao;eY95Ce%IhNR=M LbbE@13A{6m1NTQj8;D."vGQadx>y7^rMB.Fǹ6y0)cyN]knAK'p8(]K91O \J\8XaiċSCr%de4#mx&_w|EnffTiCV+sĕd1+(#01{*?`}3& 潢ȿDA8CZAmbnݳ G<ӣ0XOtavP)7 FҤl%S0D>乴 /fsb)}F0*o${6j7c ;d20 #G(8llAxt#G+81/ds h&:ng+}}8-;`^p3YlVHH<d@mTbԏ*_M־ښh 9t P%NC1fCv1Gl )L[ 8s`$47%`9S 1iOllب|_Yl])7UG1q0P(fLA+Wr%ߛAo:i)NO,~yi3vRSnI1EvA64zw6~y-yQt,N/z]{UX*8p6>Pm-׀I3)@|hʞe>07:P`:*d ^GӴ3gc+d G팭 #?B6.q>n{Nl>IHp-:vǙnanm`"C6vtQy|tqtv bvFO=;da&bV m{711e #`% tdD1ƐmX6g5F~# Bz0&ݶP b)H<򝗾0Dj3 lfeH6PږL "4D3N#j1{ UAr @kcP.ՎgܷRE|&QLHDFvIDATXx?<|1S(AƫTJͭv&x"6ٿpz,Ú+mڽB[]LN=UCJ YK-0p66a<9PZAh5bD:abvM @6&d0!cԙzm_+xP9"?Z:XNnnNZ͑aӭ旅 s ea"Ea4/\ *NH^3V+fm0dfl6 c`Cl'' 3/v(X֬y4x|bmAlb 2R@p؝M|&3E\] 5ĨW_@ż=Z(#3 G Ұ141S αC.y +f0{"21a kgąLe-cE#(s_Dq!rA\ą Dvs$ۺLWo>c.T Tk"o+7kv=:_HDi2,YUl90%ƥg3Y &E#y=2̆a}MXE\/yҕ_c  aQ\XQ6u'gsp.j,T&R&E0}Mp=]Ml")9j@55YQI;# a~e -#fд նYn>./"n#\ B&l4GXl+RVG _88%,\6n <7UL&1E`!ц&=bM$S&k1;epP8BdFd米rX,eM\ۈ6b"[n{N&c#MLݪh ݩam  4NYHAU,3%2l<%# XиZ B@Ɉ @knCQ.(W¸A!XDq+8Nh"eo};#7{G.HNۉaR6z@SC6Q GP cQFL04 @D⭨EBFk~,_x !^`:Lx*URT3Y7bvs,X2GSgajʮ%3&-w){+ylؕdsfgMCEVP: L'P~zt&GwQ |ǟ<'"ˠe R9,Wk70L{I%6q|9GpC st40Pn\ lbn>c(w`w1S ۜJ*}g\Q$B9jFg‰ӼuB!B(*Ī]& b)[Q.rA}#uvs$6Ipu0̂/ ZH@v&x!NՓ<&rBŊFA< VD:3J@ԖUl!B("n6XΖQ&*a^YΤy8U|XB0qb>:k]]\2 s0ڎ0EFxl1 `&LgouFtkY\ pFXa7lk7cxNP*EL< Y(Ҭ_ Ntoӂ {00#0b"n'T3)'g̊S ׋7LwgkpLƺ14L+Ұ?u'gk"u[ߎ&A:~I]3a"͜aP0  DHSbY%A)2dXµe!Γ^gLWƛeZVC{"DB"팻1L֫Tb9[(ƨu;M|aR{woIFr,fk;{hVeEPXրa 5~gz@K>m.*^ BB3ݧݧ=jX*R6sk9uc&6`LL<qt),mFwix)0fhGL_e"zt- !B(\Z W6TJa-.J/'r{W~=P0C`qA ){$b2qT083ko¬OM 61*UJ5}l"m[Q1|%Hk ]wzg8M&O4Sk2 1><_\p!.7ư8(rڍxmԮ1%13zW~n~OiBrsi1HLOB(p; e~S#B(& AX̖*afC/6rģ`{w˾HO )WYxKo{b/_eu :1ưKmbXKk7QiN{싽K&~qtO·.~ϳՍ}!N 3Glb)[[ 0зq9jǣW2%t5^v+w=W?#V@p(o!Vٿ8(Z.w6xtA61uƲExIrHE61zX|Xx4ƨz=cOj"=KF߸Udpr(Dk&Vעr%Ea4h [a e 7b9Lssz9O}!sDwR lTעZ`E5gzp_rd.8WɣNH DT6l藜(|&.dtVctl MJ,ɍ7 ʾD~'BA8MƣdoP*ZX粡_jܛVI5ڿ<6:iƛ0ɓ\rnc*""pV[vj˕pm=Wqanm]p&S珮E0n*=2޿=ڿ1x"pGlp)U0i5_X.I> VG  'W;я/BBA8WQ9~mJ0_ +&6G hۥ@ũ Pxi|&w[zd.?v]<BAXQ2Zxn׭MXEu/ T m.}_^?>|Ώ}_}G˾g#B(g&ZTNm"$1{p6q!q_<034W}JἸUs/! h<~y<΃NwiH nFNkz/D9s^zcNYbi҈ MZ=WE18l'-rjު{9堐ˮ`Ozqls)N" Eg4L?<~P[Uk<ƨy8h5&Wv5ľv ym G)) #?J-ںZr" ghd0/Q.r8L<8x\ k\WW`6_@I]FekC?6e-T[/۵b1vΠ6ڃ쯱 kHk?&Jr5*W7M>oDZlwJ/P MWO?{k+SmvYw1֊76߼hZ`tY<"s&֢͸\߼RؼRj vKYS߈6b_\ Y bRߺRhbBBAXvV\LUj0i/nm H3`2:|J/>m 2OgԴݦZ+8)zZ(B(H;uM܊+(pN"jὋG8y 9#8b&J5T#F`?h>&&4f|1{fŅ^#~ u&͸U0(]Qklb5{BA$G]bvs;_b7ba2/;=XB ٵ$?" |vg T}#s7S7'i6K_ȳQ?P8(, BAd:ZT*M|ng<Y.=Z wg$DAxaC["RjF\(f [e;b|AW`fO APg8LOlb}3rA}3^ߌf7Ýǽn焠('C |J-WjQ-oi4{&nknkٗ/." 2t8>yPEkFfOջqp&࠰LDA8CM&^WS'VM!6a#a03ݞGUI${S3mC*h(᥂ً**J]+Z2eVL`c9BὈJ lX{Dx*.(R}=|H+4a1eUMswq5^փw .X> /Ϋ!AM`Z]1eӋ ,3 뀕a ZJbwEQ B,o0 xL`Ƙp01YW"Wj vDAL`.>Θ>s+O@"Ez5Mc0'X1:X^oŵ3 A< / ;PUUN@,cZ˵jY1eTݮC2/-$jEW w$";^y=QhE41esN%`eVm Z]+W-?#! ̄aXz\<+$ «`UzԽX7uԖ0a< S3]ž~\6ߓ h^嫘85zꀺa4F /0& cap .- rY# W[Z%3Mx(25Л0= f E+c}!SI '«( tz.FaXqfuћRxQWU|=8TS݌9>d2 (1ewmyʲ|`f N2S| e iu?KjO1& chvZ)l|A,{Nǥ<^|%TʟoF]7Dka< 2!fw%r+6nB7 ]*<]v1 D{= iq56V.0(L`Rup֊5#.!=^UbtXKA`HP `PKl0& tG\~[7͚`8qe8tT|UNǃslR4˄al^L`O=;vN$w%83 ܅O Kb1lrAxŁ{)cxj h5EtՃ(-u#c29i_]2ETi "`!(Ty>eZ@`0LB`Kϯ[2 «׭+K+B$qbq&r܎&'XɎ6 .kW7MT!BE 8*H^$F+ PGӸh,cmDXh٪*nϣەY]y==B銁~{cXEU9=ޤ$y}yC>,'5p]דUPvR!1 EU5k.,X|pXYJF[&&eV)\K׊ /caxb`)8"uW6,{[:GY\ j#*-49"Q ~o4% 39/>5:B`,/Xr@nW(&&+`X ZrHcVeXܮIxaa%X]:)%RQXbW@ @q,B݂lI0;\X05ozW,l`F\`N+W:ezi#}JS ^F7!\eOIqRkDᵸО]J,],f4~oRKJ+6x<2$N,A|q_dt?qPi/SRچ rc$j'N!@1gN¼YK8Jxu{]nO\NcKL++5V$rmx$L`[wL@^[7NHw$] Y {t7ѽ.ʏ)I٩Ej^Rc1 f -Iјű{ IMlXYQk &L`[=+%j~ w)HD9<+0N TH1g$]; v Z^necQ2>ţy1*4=r ̬Q=Nwnz"&&+- &eB˸;A`F DNG\tDtsZ^14&0L`g0o\ْGS\-#+ UPQ^]߈"W+&1 ׊5}mt|2K>UZh~-WHW)KT,bIw/Ͻ<>Uc#«jyG-\:]Jxl/"XZV|0el*z< 3҅yܾu]%S{U QsFm2YmԒ-X6K` 4thEnKK]oq.!(K+ĎB*XΥ~@Jjjউ,шkN[|E51U׫RD03v5X^_kr،͊ ,cӰ}n{HЕyثc 9=T1e+r)ꝝ+J !ƜBSsoč~O+5V1RxMhp Sz{aq/.XZ17&6 &MCئf7q$5CiZjLZOWҢU'UzK PAvI$rSQaFqvBM}?dO?STh#LUƞA9Ubia1(oe"ڳ: ދ ۾3>4HEX^8Ƅ׺aP&&+|nq۸s{u ' \ հO4KWW/ {0 %ndjo,[?9),KxZK'Vʪ(= IqlGiI*75YJ#֍yĄ'=aj07%sn5L`ݓxf Rsgoc ~rJC!JEd-nb8SEXգ{|[8q܅!4,e-]&:t, ZBDZ3d'Bʗ5 `_`Hk?mAz4UMވ/ocٓP>'W= &#Xb0r j8m1ffo6枹}7E0eLY w8%e5Ut.LT%{l O2\=.0#80PL< 0ܐpaYE8޾As|Dċ=Ou۽L+8Z40N3tp_Zms\C+߃" $IO*3ײɥJ޾n#/́qm u-)IƲů&.&']K0=UItu>gíngj-/xUY!NJ ֪rirRW6W<^Ox׿;s}uM}1VՖ8sLߎ+X<vI(`,"DcXfq.S88]T.sFGG 3"qeY ?4+V s|ݓ` Xcc); ?-`Ճ\&F.0x+Tx-"I|@̈́\-_+̡eUisL,Z=ʃ/0_U)FXb9 n-p~s}pk71(rWEYbq?+bc%oB1\ E-JBA<-E=1MqE_:Hn/YN)Nt$Т˻`uO7n'5sop_9 &áw`f[p".sT&,ZAh EB_ERT)_4hY},#%+Ɍd$A/IS5@}FYEkTL*AKZb`4Mg>}`,,RUUE>RJ Nmuj i<[x8a<@M"ݷb\E(jZeRy>x=W}p[ɇƶKU!cb+wL#ޡ>2E+ Q1^?C1npp80q ΑƲX.Xe#)bT{ ~yvYcVqy y+ZT AD:KW!KEQ;WyVT,d9XCw@&䭷ncڎr6e˂lj 3]EE-X1Vah.T(YVR:o֨mJ)NX.usvTckAƗ_uSc== &rFx p}0emgHm3o>p0L5BݹP"ע+iHuu;uI(MJnv ^XޛT/\C[+Ų\>yf~ `gjK=TXqG84ªh_~~ѬYMq ]Yy v#FXe6&Gb+5~|k<.AUobǝÑdvF`EV,Q: IDAT\,*Ų8…bH-l_xCppKp8Q4We>@!Uaʫ*-GA,UbEROܠ{Py-F {Ph58<;hi5U裋*Lzk¶b"er[pO RX }=-=t}mW^$6? @kd?6r1l4G3n!R2&5 s*;̭qzM4 ,9phNpju)k6x3Ǒb<苻EbdFGW E;ʾ 2>vrY6b?()%w( )GNIXۈ|"zR$D>85L/m8\Ѹl⸭ Vd*V2RFcڥM3'd\Z<$Բx]/7א3; DJKeZTn@=(-il` F[Fp91kwr "\L`Lq9LMKOnGs >H%w0{o\]wYQ_%@w"ȕѶ-H: {"N=]ϭM DJmTؙ:&͸ev^a‘-v1Eː]5`r]Ë#H?HeXZmC9q=T;>BO At!,5m8vB!y25Ff~/ 9!mg\ۗ)P;j˝.&hWR&[˜X"T/FqB_{w)9`y\dRѮ#8L:<Țdc+ 2(@RHwf#*Fn+jšF=f E<4A|Qل(eG}$Xbմ9jj ~g,Wzk8=W`\/L`k;ke|x}>H_Er4M=Aq'5kyPb)LC]ܪՊ JYۣ}EՂx,lKF X}Z*v@^g)Y>@.BXBWŢBҎ>OvV(: R09ݧ=MeAl;_ǎn^_¹3#&rvzygNX6N];q1'E\3bY$A*%%ydPu!C>t+Wf$ $_x2N}L{t$eFtؕjn;zQQ0e+V9PSk?g7t[5)C;=fAUgX(6-6aYDU,fBOeDM+jON>k@W—PO`s:Z_hQ>Պb:}*ݽX+Dp 3oF-| I\IR[3U oP;15O=L#`5n2V1509-֣O w>,=ɱҌ("d|nDD 4\Zȋ%(5.LF]R 2,,;yک|Jpo* 1^SڔJz^ GfOʆx~,ĚyYB%Ot\ }.H*I3J{YA o"%s'}+܄m *YE`/)؟/ZEK,i@`Z`f_՞/o«j bJVX 瀼"߰5`vѥczv58g wᮠƃchg4 >>:uc\Xra(n vy4i5B)zz`ka? n={ufwROp nCĕ3^z">t_4{HSdcmJ!Zq dko<v t< (hbRsb@qOV6!4o|tlaa/q]2EU5 օӘ,UӘ#J;P_dy'Kݽ"^ux͟ W6 3s{CDv#ˆX:( j%B,jU) \)+_HBȁUj %\t񫪍v srQl=gbʎ,EV~Y!Y5?  fi; pu,?Xf`?&g4K }3`1KHSܣsN4tip0]Z&T+v}ٟޤµ|Vj"qHoLH rU{4! ]M-WT24y] 'T>0w%$+pҔB_ OOSw-E9Hfѹ-qoM,,UC8"8_iFW)gX!PsMIcod͊imq%-E d}x *Jn Q4- T΁$ͮA7N33]!ISVEtz\n}珼;z8Gn^"\L`B'GnDjƭ75Q{ <4#GfrHdWN"3h|X"HDsI] ~>!b4@eJQ_RRGQ*-佇Dh&f ! 8CPŷ~d\PؐnA'{@z8? RYYJ*@ @}>fGeѦؓtޠ;/} y˲/L8䵭D+~\^)7\=Bo"4?܆ yukU90 r_7L`=7_ 0?\f N]mIfچ˚q"UTƯY8$- 쟸-Pmh;+.,GtKX GYDŽnogQE,*z]+@gsN#;̧k%n>*3᫯~shc'.bUW b*R\=0ԲfXx1=PD O_\ K1WekYjhmraBrm%`~\P9". /{Ľ&V*j @#>^<$j~-A5%%>Jvec⯼%^,=$/&Ybª;B@5 aw;1KŠDZݠ^)wS{:u7 !" qr瑺Ljj%PǎgASN.ŏ;ΓV+9_S<]29?m)T M׏~t}3#_k2XO UpNZƙ77UdUc8|/m SP"P*t-bE7 `ԗ*.,J(b<3@i|is#S(O]hU)8+dpH I hF D ڨ$ nAp!7TOSsw *?3Pl )t\eqbF4#|i +T\C/ⴖי|ަ4lj?F!C&j$ 8䉃ä(i A:Cv}4^_9k{5((Sit0M']\^h!ua 6~tfڵg G8Xwze s8NLKw&%f1#ְA1 %,ge9(pa~l(EbhDhCP1ʳF !Kd݈wKh1:֤8Jg4S3ȑ*q%[= p@{c/ŵ_§KS;}_t;C}X}dחcZFVÕXꤾ`=4BtpUC@nDF5u2mׁ 1%$afXyVFzabJFVтpXvjhI._vv Flj)sD`P ODYTS5u ,\>{9IJ

    эU_V*'II!׌b%KajhbOJq.# 7e7-?\ ZK{~Pؒ؞ByyfMlp꒼I#7Hp^;8r87BXsj'):_33éz͟ 0QS]{Zt@B5XAc&4 IDAT ![^Ǭ~b#Y?]m4; hӂ$}[zW RHhKĤbe7a ' p͎`|׏zd`KAsrE{(5kKoXtR(H+)R!H|寧fr[zU~e1y5{t>f >}^s怘"V,݅ TŸ́1nJV@Un#kB=z˘3G6͂z^nT`w.n3tq* H1t ׇ $_t%~h"H48q{P+,Dx坟Dxs_EmĬ*&E7 vh{ST%A.af!Ŗj r#qϐAk3fT TPH4H\U%@ЂZȁ|<Ms/ +Ү*/eu 3cNq*t>[|űE*$ s7> BxUxoLi4g:{ `6ŕ%AbbC\ial|*)F:=נ_x5"}x8)x+ZHQEAŹn\)pŔ bKR+} {oG{nGb6X[c/óW8(&}妺@juWK1AB+w5dSD,AъC/MN;jb}6FH fj ng!ƉhN)Sf0YUH&ҼDL"V]GҀ!ĈvrM(KM:\ *א9懳m,WYZo^œx_r AD&T@x=DR\ WaEׅ[0BdF?'_fby}V煽7Yg E 0it"VlbK*.s«:*P1Ԓ@UH) Պ1*Y]"kxL[%qp@$:x8"`0ՙ;REX:1=|X~` {Vz8j?3o.Z!ve ȖE,C jg%(K3T qEiKLOE߱ƬiXTpUK]>c4TO Fsml{NA۱vv Fmũ>grF`i 5@+jGVii,trk>lyX[={o?f`yƉw]K~|qD'Sn^4Qyۉ ,B7׎#_7frw!ME%Tr  |W()Jb,<=N]+qPA-]|+ W5' nKrVQ3N3l+ NuuSj/AĖG[XţGw9FF];cَwv8TQ[M ,:#K?sZ4T1B>h ƩţxqG{oQX}b8 aG:,*>-Kb5>MJ yfcUyWU4z΄ AWSkXp3C{.sg7&7,Wx$k-X}_l*QXm_Cշѽ"XI~Ww}xDerL`m1߅DNzkp?S1FUJAD4렃c):NO /|1oLpȀu0bWZG;K= EJt譻  #sһl\$ǐ$7 H:DPEsIQr=rܘel% ?Ra?㯝Ahl2gg Ęm`gs혫*g6sRz|arCŲ;44*%ýʊAi,S nwh;&Fre3]ϟP+>1..REU#\Ic͘gP^jVM \ -d}a/8}:~|kPxBt*LUp4cԵ">W!>Sq@ |+տy{xF+.kkJj~2J\e. FrAVgW-8 1 }g_9~ `E\YtvܺkWIԇj*X˫T-.׌`d'txwpfa/bn$Z. *.bةgRR^SԘ˻yzsy1{;I"\+!x+,eHS/$FM)GG1yjXf-/n;?ڧOuSۂq3;diXW¶]^-}]H9pZ7ohY\cxr 2OW8SV_].AwZ 9IrԵFA{]#j$w`Po[A=_v +Nܝ򁵭", L'u蝽 hr%>INTT5 HA.^iPĀmc_8s<%<ТB Q(h|F\{]t]Ъ@GnPI8ϮBl%A/ŃQ9)M,B B; -_:-e yΜKĢ̾#cnbsH\},%lw\ѪU*Qn^?KFUyw!tޛu_{H p'Mmc[8ĒlXSIjj2Sej*Ieb'UIUf25b%ckqD,Ӳ6Z"%A F}g8{d$(F}{{LSMz~<_?3ҔXM:)s"́Q;; .V6 ɩќ=0\yA|ۺk nbvġ}oܣ?z/66eVpJR:v? T4}L "t]Mo@tʀ^aρT1y\/U۠2$d$wh݄Tў-'g|E 3۾za;֢UMӔjAQMmZIMy-nJÌSDN2ژEL}٣躞ɌLbJ=gsR%tA$f|~Tar&LmzY:tjGL}KMnyiWxQ>biG`cQe4{Uذ e CsXO+܌@cqX!f4NI (_R}^37Y~~8?H8h!B7CJhZwc!1:LK4qǯe, RڔyJa\Q\_k)o, f$̮wwP;~mIgdGzRW5ޯz:z]Wla߭p̔o,OM%& 08э֍CKgTKg$;qBw͔ITgۿqa7"]i4>NmkwΜ"YMDL:t}Y:2򻅓[*+A}ΆOQLQu ! k)*qmn>¡;|)aqѐ8V0re5 A! sēGW~CφYØEg6KUAmJ)%*5yyHj)7IxGK@e4>[ 9i{cըݿ5rTd9wJf.&v\KTki'rr'òx/VYBX+5'H :KTp41! O`6YYyںuk7v1؂G<?_vDJ$~*)@ ?E1a7f9,`K +]pS7)>LRUQJ\TJDžm$mY1B΀U!]h]z4>ӷMגVRr\ua^qf֍7nTH6n9!Ed2~K43RRl~T8tbg9R8RUi %xxUArIL``/1^[4PIfnAܠ%UͰ L]0t7=ܷsɰ淁.u=2~Ѫ\Lܥ~c"!XNmifඦy:/{zNQ7toHJŁUz 2J0[JM#`6z{YVF+LĆR\7m`A t%l:#80BvtVJ8S4}w2?]g>Hl(&{?U@/6`+g)LT)7iKVk+kNdIduŁ؄AFm]-}LNi!کZՔpn22m+LJGP喌 Ae֛s|dlz'O_iх:۳7= Wx %sV4a _uecbMwpW"xHE#̧"yFќ̋i4F^!@{H+Qxram~y3<0Y h D]}Tu^)-@a\Q}Ƙ$kO,?Ag. O?9mu׿7@|nz%=ubS'?MьrGf(50 *<fx-bX] nhdYQ3Hf~h?}Ot/(=)R7ljP T|A+`5wq m̜gV?6L`u]ΦYI:cMLΜFF ּv?JfÉ23u){& mvJYX2H/$ O-s((=PAKux7&fT!ci ߜ0=~Wl=8M$Kڔk&cT"hA؂;;'l@+eH3DW@w wsGv|ga 0^. @eɉkh e&BQ=\jy$R}nֲIpvt ǃ4Tdgɂjt5/ppJU@fϧjM& 3Xw[XKصy$y]|d{ M ).\;q`{.@KZTd9Њ{*Р}4+(Sh櫢@J\{{ Z}0f*@U bIik,Wn2ċ*A!Ѥ?hVksp>ITgvE>DbX;g8:Z#a1C-=Ux;_dYs3!*}z>/ʁ*Z''Y}_Dy~-9"ZlA5%)fbO oo}3zE*7Ag䣧/z,wz{]::Omnel؂ƒ=O~]| ثAM+SCFFT̂xI*`+ *-DBV-)2KH|#p GeC)AE@QR2^>i1 r7fqG$y"RU6<";ZcVJD!LlhW|YM6'^;Ϳ?duܬ ھ C03^!iO*Mn< uD,Tx5Unkm`{nOOX澯?37zq0G )44pZ T| |$Lf \! hh:P&ޓNY,+2d(ژz;{8O!It 6Q7JҘ3l8Kl_qk^2Z*J"䜹/s=W}kiCYTj+;KNũhq i:>tb`3,_WxRO IDAT40X*ឤ0< ѽ;5<#O|)2&ME0߾QR h {iM84[fAZ]Y(V(dƔ Ib߻pϽhrbgUU~ hDQf Y/)䬎*H?f67vi~C5,Us+v:bُm:CPI+J` PzYfx>&cB|_0E;W{%uZAzA V-~ܭ W-i.U%Nsr]Ҩ) ( 6X&AߘEh} VdžVOִRcR x8Ty|,v3W%H3V^ݼQ? XW(fƇ~ 2'3{??{M{Oc= 7$e+gX#FaT[j*(?Gou:o/agx[Z3`\!<a rב7)! 2X5LدP&J"M@CއL-ƩhwT _3tiɢqKVo,tʤILtxRA ӉmyFWIokDRPgw 3fVNhp7p:J@ "Ņ{B)V[攜JJLgSn|~s ,mhOu*`ڄxȘ{]ssJ3֫rpz'H]cgdxBK¿GI [>vQ~23웵k״ E6bq*[Hҳf&z1ؠJșH8Yg,7|X'9\|!/^KXb=XPk o|=!ᑼ);3: ~j3лouhW^oġ'/?0 ;`&L!>^rUtFqh7[ҁߨ|`ZdvJ["THroDuX ~ [{kSmH=# mBSRb.Fϐ"=oIzz~<`_j#r]vrYH!V$CKl vc/ӈдͤsi-j R&~f3=y?\O#pG6 ԊCbsmR!9@kn䱗q/I.O A%riْG+, ՈYs+|$JpZjϡ_bxɓREAYG/C'o=hJܼ}w]@='Bӏ9aWz6p_c~}L2H 6俓} =w uKzǥܵ Uxⱗx߿Cvej~`; l*U-gkTd nJQl ^381bY7@2$ɼWqS*Jͅ|葐_t*]+Uqx^PBؒońrDԻGU]W΍#̄lB;IVƿ\Td~2U%02DzMM m7:֘Qr.LgX>/<z5ԂEb,VslѤ;t$\4I> A$cZ|nyڀ֩=@XT!kC{:"ƣ1O%*uMUF$OuZ9YJ;L~+nӵ(ֵёõ(]w$ObU@V 0225(7Z!0 Z-2\:%3}&/ӊ9{7 'Ou;]Z\8U@Ta0!RaΞ=?`!{7NR&UJ1{M 't']RRZSbGkY52Gg?^ߐo>C|s{)f 0}>/2™zHʚr4TSd6%ڔHmc | j;Xap} }pAF6Lz.3Ù =]y+cD F-}Er34Tb' f Q;s RyLS sW*%CW-\+#y3c'0fB1w^ODW !*^Un7ů,S+ٽ1o?͆ˮ'])RAóͮ;Ќ0} 3w6[wp?m`Jmy/x`݆H#zTPE*9Kq.&7l}!*~Pcf2`F1X!M2cV]~̅w*}[b\J/%@`$(])Dz,X=ŸO%rgI'ϴ|ˇS>cY>Djt2 +YѶE,B튱YG&zGq66! QȽTjm^% XCtO.5E̫s+da< ^G:0U6A5rs{G'5Z~C*H M刳AEjR RRFH2@RBD=G_U\ UVN`fޣJ7g(Y%&_} D@u^:zڍ\Um$ͻ0X@@ăJ#ȪLP( l {3b@EKf) oŬ*a/@`0SP :tMs SAU̥)壟7L ZmW&tlU~ǐЄ\Jo)xS|M iK<48Hu8?k1_AkPնh!Iv`YlJtV19Ap~D.>'X Vm7Eq` lOoZȌ V6(k/qnEJDJ!}=ɼl>{Cj*Lm=:~C|:*j aό{Z.F*|?j1Ǯد6OV "F5殰}bQ.N r嬐uoHw=]_ MRٳ}]{(WDVSe8&|qdduкؽ"K[XĶs&ncg1 ~g8'E{n9'6z他@kټkrw{qaZѯc ^p.s*VւkSRB!LGW1i&sCdy̤pɻwgO1>g$`A*`5h tX9gbTQkҮCڦiS+9`'4vBL2z6q $ʞd$[ϑ|cf2"SR2Ec? ?N}QQNUr0_onUQ+^`=ſaL40@Q>U MouI-jj.@jΒsG_%q{M[-bBRM1,Z9[_/ZZgO[XV=r='$X~FAHW;KDap`q'5U7aOӐ5M7"g<0XboN/l{`d*at3HXr'ryϣCϨ'RL[#nl Mj, - bA~?z2Ӏy'$XiGy~6>C 7,.݇DihȒK SQ,nʄ3ԸvN%t)@h s,;}yt!Ldh\w0o7 jdLS HcƄgpp ȈSO^ˬ1kfefx+N%bT"qc$gʊ:cK#?۰$ 9ͻYZ ŽU_WT}5*~GR² D"?dsKYr~PŲSSIQGr}d%n[A[gt'Ƣ#rp#R_4>WxU8gdkUG2P]ÁپrmV+E*As7WڂL 78 HSm`?3'HAue?Ht%jQ&M}< jX}D$a`5QiB&лI='C$8XbdLɿYfOJԎ o"`Aq>_޼/pvbl$j.nZMěa+&ZLndY'JO@T'E&?! 5tjXԘ m_7ЧLLY s>?ČQ%"B쐍g^iߥqr-kq/us`@,C-bLTj4Ylsg qu߷sKl:"R7bWMC$3ݺ6JhO-6^sri_M߰}^Jeog-6k4|g%P% 3czQ+mWسhS=d,cenfTUaЖ\3W[X6lrnocQ1:琢(QV:&`)܇E&"77-*Y߲`/̑x $\OѦƴS΋*SYds)E _dm*DL(**zlBW:1Ͻz61țH~W~sꋀqGe M lu+:^|"fvȷ8ڍx9ϔkZ fۗɝt GI4gja#>D`txNTɲ"軭 IDAT=ɪץ:5m^&HZBEty4wY&6Wg|mO5+{{deLi7O,ʤIll4R* ?5~ݏڐg_ dQZM1pdv3VjuX0G`*i,miyjaRde-O7rO'&_R}Qe՛_ʪ- QezKWfv3' "VmyNxMT5 mln+po,G/l<?0?N宯]^Xr-L sf}ó;՟hޱ{&WjQ¢ܡ g=ξ aUvC'& XV&dgsz1=y_巽Ydž_vg4G Z;%WCBih:Gn*5AdnN! D!M2AtޅTBR&5"gs! iDFĥ 8=]ݾ7*go',t:kk&K^KiVJ Gli&3~sc;èG Jsx+oԀ4thэy(Cz:ͅ4hږvaBӶiJX:3FZK +SǸo6IH3S{R6Huʄ1AC0czsJC37m9NcM&Zc HQEшh:qͬig6 p ̏i\] (:t0UFuZHN^ikr㓣 Kxi l??\ZaT1R-V5ҥ~::m`͵cϟ.bK:03~^N-T)(\{#̀3R%Js4j4I\B%!_VI0MKb)+/Q>O]=+a=+#LX`T|f">llsC$`gW9gh;YeDkz3*^X9X>۲rA9+\x4b) b'a x5Y2)%]x 9-*wl?/y(ȼOqׯpuLBN/V U_3VMh8om`͵[]=Ȗ v_-.acdž;wm*Ǟ<Ktlcϟy/e6.(6JD$]7X9* > "=w9 IΉ~KbSi}b~W~}n(a7mi G$ ʊE:q]ahNc{d!xw0KA8W}D~0qh:Thz׽M1=f/;4wK+ȕ25;0.T&Wnkh9[IԢgٺaƤQdXZ*ۺZ$ jf@)Y度5+s>>{55P sk800nXXice jHvMjjj/MSU&BYV mBҒkٰgf+/TNsc]hi0?4 eg'T=̨ cd4+}gZ+Kܴ >ƞ5ݻk3ϵ`Ǐ45T]ӢyuKH%5}Z_=Om 3X篭6]˿{g.op-[ٶ}od޻pk1`'/ҋgy3ŴgN, ?'DͽhR>i%w}'|.*Sj"NA He2 5*E Fəviva,XYTҦYѲ7>z YSg$s޴XTVOˠsZ&R"?;f<K]=/bk:Y' Ld|~^{4s*]6/4b,FU?V؆0T9i49Õf?$yO^ƾJ0zͲw%WkcE5 IreWv0Cf e-6'v 6XPީ5Ϙ`%c+e+'@wӄ`S+(E#^z]td+y5i9Kh fz#xhY[Xsm:5H5O_e:4 Ul+;y|s<Y&vCT{x$^'C T tV4HB՟܏f~J@fi2/% 6oU+?095v7mK׶"?Y%-TӦSgo.gٸ0Ev=ݲt:qOƜSVu"@Ur@)V.H,R,<| FEgΚIjPw.EшBGJ/\[v2_Y{Y6thV)53Ι3@wѣe %iz~KC/'|CQP \Bj\@̢Z\HIHB&XX,HTьLjZlJn;>g-/{>n׹V1^ͱTJdcDF>PJK3}\HD(cq X:Mo /(;Uc9L8mYܕܯ\ 3߆w9تcϟ [.\vşC?KiUQUERR^˪@KyzI48G?qU w[-u߾rmʄRKI0Ӟ1VMe*1s`"x&hb*PrBӚӷ,1h43e7og˅lgسaӌ9Rm I@h`d[Y欀.lJ#LJIa~[#7%Uь)4B#J`1n8>XkfѬ;tR-tC Kb#]3~m4f9 6)eOw"f4skqw|Uްjt׮FxA ud:%) Ԍ`Mhȳ~a~q.9s{y;FK9R$1oYgٶ>f240kL5̲RD\gþ ,X>:Cȃ5~jɣM篭6]rߝ)RqsH*1*ı7W<)I ~O jA.U=WsVߦd9*`UجdLII5*X插ۖsS~8Qc).B%Xkeٖ%s+BM;OwJ0֊l~[KbłfT(gՐ=Wmd<ӸK5whU;"" ٝ9jU=ޜdj"WyFiY,]su`xpeZ殞:)(Qk\u;>3mKEyeJ*no2Z>ϕy<jm+Pt%g)4[svON/DHijk$r/}Se- zD{#(֐ \[^uw9{kgL9{fs]ZgU|N0' @*pMk#])Ϲ7>$=ɿ=sQk5(c/㛣YK`Djhtf&L`q#ϗiڴfRi[3!.OȚ55ޯs eN8}Ǜz`\=2.VAY=>3H2%Ƶ_ L&|>-MjD Yj?gSZ%>|Co?u8"EWvi\4;^:e [a>V;^3`4QLX@nVh|a Y S3жya~@ߞ[f9s{6?¥bG;tlQAdiJŠP`k{B+ʟEHi{ŭ? p3fa>_=WoN翭vec}^js]p'o?ʲ]EJ}FhjHbpZ@?i_'o%[/aK~17DX\0UiL lljZ=QHnbŒ_`< I4f2:%3՞-/vxI@+UI*|H$Xi38-ɛRFȃНC=B;Ϊ([]ZLIGo{'e'HuB1{pm2S-)8@jnkVb li5啀V(ef:%x~)m].9`9]§A?-(d4)zN: $ E>fŅsܪk־+R1Y=RIV 1+)RD@tf*9RgG8}\zҞ=¾KW V<+Lz,ǹ7j[wr?m`͵Dm7qڟ_?4Kp+S\{ws,V F@M$d ?{Oytp2Y0tڮ^uwB0Z5] "yrpU,*m?ȓuɄLfNM^H{OXKQVi|Ri̓Y}Vc3Hl5%-=Gؒu5rdT j[LK$[teU$GJM8?zV]AV2Z4v<DA&Zy #x!r-R\GIlמأk 3z}.E]Y\g79Vi5$nz<0Tv_Y|{_q?CW,# ">Ie"4S6إxa_`dz†߲@mz^|KZg1F.^<&t:om`͵`6^ݝ_v.NK6_q\V.Gr5?6|t~Fā $N 5I[XV!N~ycNY S x"kRKp5Z j7A'% #]ShlD7' ɲM=.=q?WԌǠ:D .TqLSΞ/,g2o"$KD$ScHe#\1pe|W=zS-Zۿ0ChV)a^h?af˞;HZF=̿u픾J8cTX{2zY9Z5Tث>)Zke tրVJn&/r-gJJgɏN3{}l-QpA<Uw0pXTm/[6_t}<'uZFc=Vgr?m`͵ixm8=Kx ]#lu#;1u!/^{t'e}lL|0@W״rFWڋiMSUfGi:k\k.͇JD5jŁQx-ŝ]c@[Mo X<~7n>6;z[oku5‘>t/nc\@ϲoa߄j̬ YW[ɼ{uE:`)aI1{?իv>C@w P`>'乐wg`6;MaÙ=|[;~38fa&(#&`F>#Hf:axsD: mD$D[L;@dѻ-KL͍T͊þ*?kuJ<8o{Sr uԑOA/tzppwZ.|! )\,áY8i NRI\]m|z-FYǶ]}&wk1Y5V{GpoBx 48ԋhl.t^E}]q mЖK%d\Bumr|*Z2[MŨkUQp sg6IhMt63qpL%VBX,|si#n.z3!_ IDATɱK@SZY>)<>Z fe喿`H;t. ƃdެK ʞ[02#7Yuc.TCX!eƔbhi2VmD\1Osl+UF O>LGY+CwR`g <mB-2e0%і3naG!h%~QGԀQ!.p̱?I#R/iTŏ:1ղUg%~$@K8YT1b܌>oi|-o 5&~W}jViF_J/d"B8VfPT#b+gt]Dx(n^;`!-`km)f`s%ıX_BXU >PM*V\Zj Ȇсd%VA{Ƞ5*O+3T$#.e{&LPi[-T6v ڹyyT$e:h1{No赬p|| =H?Nɒ(冐7 `ꉏKX_Xv~Q)OT y ++W5h_]eƔ21邍u%L;*#>WF:q=t(|(WOaNgd-Coz/-,uoeu3GOvc'g>tSr)yL{T&BJ Z>|?Wf&ӝ99GQ3־H^7{l.gC2v֭߆ >]D"5|N<頼ĜlL&|FArNR՟$jp@ɲ*,K6?V,K[\1+#A "Vbz:'`HCEܽ]!,d^-#?xOZc}@{wC5P)ueY֔H?kypyr1ՖT@z-"Lt[|&@Xu(M?(N=i).ʻ\?95h%oWdN}acN>3|CO/Yg--jT(pje30uX/W֘[XT!&\F:zS\@X9„=Ŧ#@esl'KzleXX8啮>S"Sy<DŽ>C}YUXQ hc!JP+q}$0%Na,CT90V^am5fFǃ~?C6%QƝcx]zb=UQ}-Gl\pg`|blefG`@QnwT^2[rpiB .;^VW@5y>X#X!WPQ9dDIW$l}[tK?5 /^ h&RPi)ˢ%Lvę U}MuRkr߇__O!kV*`UV.Jgɍ3 ,_,C-%8# `ːlh*ʗ<72ceƔp\ת8߫zj#cztILTi$ SL)yd@'鳙%%1 g\]p?S'X|MI:\߄O4y?_ ԵSI:K@[#LřHXV \:̏ ~(Eο dʍR՛|6;'qӭ#θ2Qטw:䭖$ivTH-LLa0 "Xk{wmӛPVzh,*yQeۭ<-3>U[vk쵊Ѡ^އ,c p~Qu׿PF_OJR5 %_$ܥ1`u(~nJ|=[{&fL Bpg9?Zt_#;W_gƐFS̸Z(H!Gr,-2c\Sr6Jr3n4 @L%+-3.}y..h}:2OFK+t(}p~(fmdU +?_L|JDbƘբy|ܤ*`ᐲtk}r(,3,χ(%h@h<{\K-TE>VLT҅]08'ACj{вGgRӹxΜ *-R E5o}ڙTj~hSf ꕩ*¨w<_BXye+XԷ}wH),3{' jUz?~gt*E:57ϝUUnzxm<ϫu'֘0tf!5H;F;Fξ{U5"~=l6]fB:lIR~^캝]]\>,A 8dTb"Q`;~vReRZ|<.BUNb(lЫF,*/zD7K'N!+2ZyMrߩ y$p}Wə\3dnt~&\D ii"?x5+*WCw$`!,/N2@qc+99;ѧZ.kq)5"URR bZT텈W|tO}rCۦ&Tfפ;-@?~H<9s\όSD0qYК3@fw3QkL '&WOZC8 U(>t.NXPHtZ u4R=j'_lC'!LaxaZ ׇ7|#2=INa>4zE+mgOe7GMebܞ%4HpJVH-Cd `~xC@W3b1~?߶T+fMUXyy ^65n;S7s3>nN)C6nYaj`rHpy$i,%d3yg_S7SµHy|u8ycBȁ-U׵w=ԯAuJڗtIa+]$\.fVA4t@f - #瓟V|A:7wM _zĩTI"pUfEL5I g(z\+y=c0"կU|T\-5|2u 45fR RcWa#uw.Q{CΥ +dv0xolDvNny fsd}W{z0簏GjQLX%f&VJRBS :hI:BRl#y4d0;WAWWMVI6nSW>VPwEвˆ8m g,LϢ 42\+1qpP*3Ia,c>@MFG8kT,!GMa;-IUL+2T%05I3ȓY% Z&> iOL<&xu>lf#Pg2?c0!m9H*,Ua:_E$925WI,s}z+[kL| &nk_]v>5_o?VPC4TQCJ#R&Eҙhh՚i+c)dGY~O0ϸs; ˧(hCvz#=9ͻ]v>]O?}l?+L`G|]7 E02!Gde6ԁ:oO ș/+TucQq1l8>X*³=tY5usWoUeAT3^ܾf}^xwu-5ϧ4! Uz<ĭͤ[P$܈zUjm&bKEәTe a,ی_OA+UJu6(ko1)?DDR<8L_`޲{7"^2w텻ᄊ}|?'gd=)_dG\ w X5_ǚD گBb*E4ܴ3(ʎ,/0KŰ]wyƺIoZn;_Z.]FÖ (;N+lZ]#R9?8B`sTWI]a??vwPC +NTܹe]\W1w9'*9" T%{1J%eEk=W>,OI\rws8 9,B*+GH $J WZ՗&Z(J|Oo:V]eV)!ae+es1gЩԫj_&Jݟ]1Ms` VV!mUY{KsЊnWy>~3;ӓwapLb}ۨ՗(N<%x88 NdAG!+ fLH/-i@9Y ȥWNQ RB 7 .=V'2cvU "`e%_U85Yd쥄gZU5Vߺ)*7A Ad1 9RueNJ̄+,Oyc_BjpF6 pw}~%˜d<t77p8X@Vvg5]*V wmFf XϪ-2oѺ ŒVih1dEQ|LNƯٻj U;jg2<=ro9Lh'lnNt^t:[pgS,0טXzɕLҒSw6Y@kL|AsULOlf$uVu9B5fCFIO.bt`gML8stzCc* 7`ɌjQ0g}q79t՛ kJ(TʶV 'w]*1cƫ'SA+]o;MB`+Ud]BVBhڏ q}Vvs$/xuσm]|+eԝ5g&:,+[1-[Tn8S'PqXy?A7]WxYUʹUV,eЪ˜SݛMdT ~D)2\iQJ:fTL7m+ɦs+8lz~=_Y蒚0'"?y&K=R3,]^yoF{xyf%߁!olNE XvTZ0l +tV([?w~GνWgWR*Kw@:āVﯕnځ0=faX"2KQHxop5m|=owi)LNyh:(KVvstGT\ifBV2,[Ӫ4`ZgPq&lj) c?8s5r֟_,\Su0烅Vo?@- ʢ ;@ V,A^|Eju:`RBqϧ,')_V ҨZąкk(@`\[6Fn 0BV9R[ߩ[ŖBu 7g sEXKrW+)Y}-oC9ʤ~WIW*# _e,XX?wAF7WmmUAr,JQ~N;t;CUF&4:=TxUkѺ&NyI2d-`Խ zf=vqFq=;0-/ЕcLa d'J8 a ݧ_3id?r6d1`LC5(uJ4D~n'+P GJ`+}e6peG*ՊI@+xҝ@Pldݥ_iVOXE!_WbhJ`~a' L._w8H+9*eߚuH*X9c=R[.Ӡet S32j JuZZrΧY B kțE>*Cj3&ȫY1*xU?5qf ZKd>n7=UUJ[CzWʁwhTߎuF#0zв)ab&16<yZwϯg)`XY9;3%/2eL>2탶;GD;c Bnz4j5~e[:p>$ZgrhBtcYp&S\н}!%(NRlR}C 8wj`WbLL-k`0@V܌˅](RJ٪ @yQ~9wbz&aAK۸M@Zjgr7cpH-׌~EO^PZJT-zAR_"tWMi!ր)P !bk'ORJWܬ[kf^V,`?e^wlv$R7}BWV#ZguUTui%'&\GOeQA҇au.qfx\$=|tT Uɫ%R)tqi9< tn˼a=shg-n4}h~x-f.4V*"|5<-r0jA;N榍gϢ'ƦtY0:{5{_XAF^ٰn+/]\&\Ֆ<餀Pafp8,KftX}ѵJXB륺𷊦@!*4յT$K W-aL Vi;dO~~ԽYE1ՀS K^C 43=X Dqr_{ƕ:i@ o^(cq^Xa"\idy -!dC 1W?FnTgҊomŃVSRqB(5hTC 1Z)-s{o3Oc|gF?iO?y*λ0ƌGGTu)C5{C&i9Ŵ\v鳙yB dA6|v5ųt}.@UgN*j*Xa=ĬjŃuv :-UeʲzR՟[-",+V Y*,8S0VV[/l0KYa|.[Pz`0Xk}Q|Ggr!}ii4,`j3B(XsrOC$i|Li\'oE1%f//I~76/ ]z { 7J;F{CLD ~0R5$^ԅQLexk4ܓ|YUJP.DZ3 CC?4ݷsM'~DmҙA  h3 ~2-rUyVʕ },h2 5ۋd=7?:X 7O<AUfW2ImOPPMm.zjԎk7-@Њ܃SoJ\$MK[^)fi`2={ }׳dng o />JA6)>X\;dz`gt%snOtZD*ῤ3`|:T5KX~k-_*|;//\cj[>}bE-1EQ¿?oxdX:p:gloD5z^Dw*U*W>^ر*Ǒ@% M{"^W"iW59'g{mƯz> ImWeϱsʼOYϒK7Y֝ܯXcY~:/Z Ŗ8b7Ij*^ jPq;$w%G!y lR5d"*3brff1w>vc= ڶG+1biyrJ22Z3I?7-]ObANp MvPYy#K= k.f }lsC. h>-HLWYG[tZ>#L(W^X \G#.\h%SmR}mTOkUP$yw:_XLvާ bee%ٜ)Kgjl?uA_ϫFg"ۙUQ%7IAY J&_gg\3H- ~]*{8jYRkiͽQqiEṽMeܾ -3Ds“,s!+_krϧPa4 u`bQ?-uj\LAf`$K%.dgJi2Ygs3K[ؖ|񜥳fƦIfߊюD-iMzW8jH"D8hw=G>ܰd3ƻk߁ٽ[|7{*!=z =xCCtEW2oy-I`5:T\:HTQ[pW9|=$lҙ 3揟8ze :i[bQqVYUGsȘ%n?\/9>ٝv!wa&]n1s}I!PH}B(PgOyUt?FժVF—ñ㜷VuMa"F B2ZDGT+>&perpey..R$'&8 ])WybW^LOW1%b?l^K4>>bUb3%8Ȳ/?24}U ԟY{$ӟ *U0o 8MZxϿ6Qkr)UFfSK]wW>a\;`˒gEm0$$PEP൵/F*e<` ZXK&%Y&f#OŁE**v"^JiF7Ƭ WY9UrKM(Yx"ϱE)ONsVU)V*b"2ĈEVMS| 77j>^(rgr1)AU+UPX?60 5 R6--py卋eB{WWEY5#h~fZ8B+T2 WWY5I89uyf4a&` *}M:Jc|pquP[e%Th>Za/b&}SP + nv ;XF6;gl J*I|՚I`*֊3c4R6MF %1Zy~m>ܼ v}}%SϠ6UŨX#`XM)ZW3e`֣jX%K}73VΊI[5B7L׍0bw`xGھ[Z$ C$Bժ#v?<@Vhu;oBUm *ZY\.1zob-q+xSTyԊȗ`媞߲GO"gA5LB>:_n\wfi\JY VN &B5RC| v:LXe :w;8.lp@+ڪbyUWR$d9Mq)12@r(ߤ)fcnn)g g9nz긠Q0r,tZTixcUp[eZֈ!b\ѲXklVVY$Yw5 -L׷򋛮_+G>JBvWU)qLu=pLW-B%)E(1Rb5At8HԿ$u1p!Mi )hHp  j^-[2ځU/Sc'r1䵷2N&vC:-–[a_-=_$p`EUHr/+XTh3#%?odb<ןP^բсlumɭq=(Y)hjfz;EnsJ Tв@.{Y7^]e(!k僕3 U/yjEb {BDVNF"~ƠS3!+UOxƏI`|K 0JN sW׉UBc! p 9$V2f֔ٶLى /V3ϿΣk'QGߎ'ֽvImЙECJp98gg1Wcute>Dv!\ٝ{n73{(;X`qӷM [l8]s E5c31[ gbs?{l03h]BU=lK)•0<ϣZW QMk8K*[\!hq05G$! &Dvcp_u( ԃkkxen~""lxwK N뷳&@:*V5֙HDM?O+"֤`U\LԲzE^{cBqʢٶ8VpXUc^IHe[Y+@kevgbN}MJ~;ҵǘ#Lsd/tXݨy{~ULm͖Ƕ_r}źIjcj@ժ@ypnT:Sl'.4bk Y!$~HVs'nl<wO3;NXx>Lc0bCCXlJhOԟ=Zw VUԹ "m ϖQJV8˭CY::`Pd 7~K2 Y/5)6o&SGzEY}rC3L|^l^"wI m:)uUס^[>Bf/cQmC&A  (=AμB0R9FNG^$n5VI $ IDAT\,>x%u'ꇣTMA) /sy h-`bqr׫牉P!B VPŢe,Q{gj§!?g| l/K65F!G*Zn@e6?m;5IOdm#-GnUN+_geDS\{i~MpU֞!w]bU8ĺ*)u[21bbף6Ǻ(,ꔦ=q]eTƿ:}8tppVXC;$;8 Os"|YÂ@ VSYγ T*#(4$v4FF_oj:f\i[BdЫSȲО'w]C/^t]^x"R 'R,,vՁx{0]\Oեlo׺vf=FIy˼֖W1fr :hCߡ +GZkp]]4Fхm%deG_&I:Bh gnkǔ`L)+aL*kL2l:gI#UI=O [}(6*}jO(. IFjTt{̇*KhƔw{\dYs21 wy]7YA9$(\BQaNU k BA[[$qV5k>9}K顥,q-[\}xZaϿoR<{5B&R$&vrw(&U"L$Z*m4,MVR s(X$꽃sB &+K) t>s u =@70`qrG&Lw=E6MT%pMATUshB+ 7UκUI,9^>򪲛&U*^ ̨7JoJ5jXZ1lwRWBTq~鉧c-:ڭT X79 U$~%~5'd5;LWBbZ@mF;}Z9)BRlN>ZWXU~kë+m̅jlha9iˀ6/3+/:Mu3K%ɍ9p0=*>fo}_ްP07I$tAuƃen13&h."9(<['e埏4)a `QfN 9MC27 䅇+uOL \lN,iek^:3ifQ?+f֞k}T--b .{Ř*N"x_(گƸrI]UQ%'&_t9ck YiqJ ުlϖXoIÈPXC/BH" %j]CpTRz#Mbl.CcӅS?ЙihU&CIK;HNMTT&c9zk 0۽<"nl"[)μY39#h@չTDEzТ/ʄcBIP.]fQw,M,7S Yl?:? s._Cx8~UL`*ϝJ-Rl,DJUPPO[z<TU"GyO?ǜx2D2Ũpܥ_Ԃwp_v:LXyƉ s6v盶/'oS̱Ir@!\nޠeb\*iD❸pe/y0w5*uB5گ}ѵʸ%-_d >O;ҋ bU-B.覯yB<08r5P7&-PL =Nc.^BE_@̔Z'*]Ո:`ԬsL"N%t.IGbBG"|%XI̠%Zhu^`b6naqGgJzV/FL~s8 [_U @ zki k%(=Bv^eYwZL-SC/4&G_RߩJ &~UWR+bq{y,l"{<پ16eVߎj'ßp݁ҵ "BfVp̈́ò[)w VðUo@Ix|&%(s8#JX-z&߫l>W{]^.Ys# KDi3f5R*% =LV5j, Rg^u$ y3!]NRJ4)@{ PwuвfI59U(}*ȊL-`șT=pËFd 2lq.1I±{M`R|Ub[8r, P~S@K|s %p/5%0`&k};1>ɵܼ 10A>$zz9*t3^#XeY\+wS]UcN Z6ܙK4XnsJHk{kU 8˪=~P"Y:#\ :͝uj4a$Yf;!e*~BUɛ+`La_MNH'^Zʵq0&󹼃u\yj3ϷBK \sg5*+\*Vj|BUרm)W=H%p]mjU _Ժz##?T K@˅ (%aGwK=e'Kg#`a\՝܈x/U%U! m n0r7ƃlO7f<<ma{a6 @jT*mUYދ{o**KJ䑢"2^,ވwg8tǦӒsasO8ܹvY£S'pO?pvwrQ]:0|gȌٛ@y۫Zǘ:1G?M@װ=ףOw{G//bH%#ࡍ/6*jMHߎS`e,B@YвYIWs·{.7#F' v ;Z{`iZf&7)C=ipu"$+~2sB[H|A$ ˮDF2$|J iE59N "\m ֈg!0g@̹(ĎeYVbW L-p- `UX9pG~p_,bci$`e-oŸ蠒!1Dך#^17 ,ZG !%($h ৞?0w+,-cm_8[Aq=:5;$QzWqr%VarD͏.ڱtim{[[A_[{vwnma/풼X -ẏ9r <" YWb.}\AJa4`ڏo4d3yy!ڱ9Ja@>Xh (\]\j<>HU?"9q4T5 R{D1_5=;qڏk:Ԫ"|`Nyf;[  0ZZ{[9F C \-'X)*TU.N'YV@9&f'uPab6ejh# ~@Ջޓd S蜃#ºu9tf%R c 0p%vVT)AeZ*N|QO"bGj ABϘ+ZV|KnO>Ѳr==sA۷brq>BawBo ޛ?;9[FAIJWEQEc&}<"yUkẻryfnx?~%z."0L}TK-߂8`ӂ50DdK!cPCA|cy2]_+8RY۾aS F"(b_)SEjd `-Aڣ Tkx"sٺwd/r~x%cjC߸ uޙM8Ifk6/\Z(t],rEhnAU 1PŢz*hř:Gs"Y24EH@f\uEPXpiy8\A-lP䡶a *N*&jTc\+&ElYV8$:8JAb5bg^ab&6s%πw ~q="eb(+, +[!MT;| [_+>? T }Ԃ,cV={r^d6[g! B#h37^c5]n^˜}ަAc(evЄ7Q'ּW%HS{TCY`{dJg}eϻqdظ, $(hRt0y/\V+enbB:1f9/t? ,Ѳɦ:{JƼq@Q@FsgVp Sy"cBIm2 G7?kўYwe|h00 -[7mŀB-Xpőm[QI}7( Й܀1u(ryW_`00wљݍН"Ku/hU ,89rG+ibp/TuzA/ |Qn܉nc,a-p[-h k7%K^dm=80YylD߂>7\~ 8>wqTj)an2{,mƷfWxtp"UOp70^UN><dA!3@Y GmhOsvߤpL<{`]]cNg‚ Xlk.hiaZ,ذɩ 3G>a5X!(ѹQ)GOy.6nGQ]F!1Yz&fB1,ڕVa@QUtNTDZ\5{\@+uSf7Af 6Sׁ%]e$nnOp@Q 3 xfI6)&6pVA@ި} %hΉsA\&>LXqeg l J0=,Xd嬕n "`0X~#CJy~Ѓ_noa4.ډzy7_(,&dnLt/(h%@]PXKPhEFG/}6_(6e|^uynivi Ʋ'09G(U!D`h5}Y^ *;Y3P  84oo8gSjH}PMqmv7]/zѽz//cn݅[w!,|a|&wi@dP6oWOp|=*,.PT O2jqϢ)9>[i 2XM]y00 @ `  ^v bػl2'iSefɉ,g,D:쩎jpMV%HS̨\2.1tQq/+Ahb̑>wg7_jA^S2ܹU{bq p-G]4>(| <|`M 9"+qA)(bV^sɭ]JRSeY~ bg}xbleK-E{d `-A1n4 j\ԃ 4} 6/m@Ȟ<^-,*Mjoef\meu0t@hh** .ZԉX"yNKrk8 l= ,?Ż*HjKOZ, `YwD$ ˢflU"eDNAQ# /3Wdƚ6F:Ӡ,cJb/"1k~GJ3d*$3Xe3ވMoUL^4,S0f x3fXIzTA=(Ǵ=Ҵ4p;sx⛟[\mMo*^XUnۯ'Ѹ8E& "P]HÌR0 hbR ozT,ؙ' O!X!zMaYXKz jWr k9āìD+NlK*dobKz&fw? 4lBB;\fB'afAF'f'޲2 Ck-{I2p1+9aU irFkJ櫓W w7'{Q1)Y' W# YN :6r&P^q*p2T x#x;x;=L1AccB= 1( 8tx ˫%-J l~ k8+1p"xY&c0 9+%4' T HڛPh/Yu\ƭtL?LXy5Y= u-qa&'WO8)p4fd9গ]KoExMd?vYXWq8pՕ@|ͭ:.ܵ/߻x=ImdV6";@0Ne ޡ(snkNIH +ٍk@Ja|Gayu駇$AkAFW%¼wV,]R ؝S`eү{)@5~i՘E,uOdh#g  TN,:zQlŭjx8v,)38T]S9|7v "Tgʬ+R&W~[`qE ,xs8fQ LtP_[pvW>/DY-;x&̯80!v\DYe ugvc1@EWo|_ s0%nX1X4@̞s@7708tb9u= Zر-o)={W;r=xpYeA6=\M3U,rxבbŤҩ*)(s%!XcŇ!{e07M9LNŋʑ,>R`)qOdK5D#X+V2ZN@0YFƗ@<9 4z5oiM,G̛pB¥3QZ*ޫm$m A %R:TP `eBsftP !L_?Z7iER5ib>g,ճPc"" bt*Jrb0B%xz:l2 \]7%#pGDϼ:h{ĴR'0Z  7Ze V`#YZb,ޭ7W,8֠1E]% cf\AeCz%ݫ0d9BǓ oy%n\_0PðZFTcr*ȃ,0V1`mAV ,Ag?&z8<,=b<&Pt{ߞWr8Ht-G1W?%ͶA]R 25l 496+_:6y2sտpݟg嬛@AWn_bD{D8#/PZQ27HkߣD.rYA%=bܵ(KVUX= 9)K0nz+@G>}NcFYq yL@Tp{%Mdq8n_t땸/- 3nicV2x-K٪l0BVH=V9 l@32Z"C@K7}}|;}W Yx˒a!x;yu;$"*+f QdWJAK Xb 㔉lI85DY19UbrFF9lbh8EX}ln8~ꨣ˥lv8ef-X ;<4h 6O ^&=]xtugDY߸,5".ԮD1F7pK*W,ldY||#C14f?Ypa+&0LLO7Ds&Ac}Bi9u]82$90%`jKր=޷n{)V )s\25KưXVy^GR3D9{.1X{"J9ue4@]E:FaHiHN _2 8&˥k6RWա 2xЄ`>B 5Dza_MS r\ Wdrfr2Š9Dx(z  X`4 hYj Ͼ2+pϥ|TuYLξrڈfXNtpXLcs( U-\;;ڪkȥg 48SOgF+dƪW9%%%!"cޝ>4SߙXvμ/3oj'4RFak5aF,`w {;Tkl" #XidADDa]\!?9№I؞*]#!8V@T 2q"DU_6ViHSԂ}X<o?!5~?_; 4PO.uO> fIaۮ(P/8n3  &9?|8-e?/GdibFK}Bq\jBKmA@( @B,'bD[3&5K&-E/gۆ2 ; MbN'o0R1z?m T&b٬ m)P. eafU[U\ߦv2`cr'ܞLǛ9(>!>OO^ LreUv?O<=Vr1yOkqV%ʡC0=rKBCCp.2z n.}, 8 !M΀r!32TXMuX+Cdە;s,?߽ ߠ*hoa\!^$7u٠BhR j@]AVY(;$VX*W$ W."̕qd-NO!i`8VK9CXFy)KX#JԄ-j”,Wfeɽz W4\eb2TI/5r )`oS@1AD|z Zd2~4lbe*B#SW~lA¿趩 (Qk D}'kklg.zj)`3|䀌6}+~?U@ŚOq?{w"e6z7 T0" ,΋Hj?j6v ,8t$`8̳)C)q{_2?Tp\@*KݮTT&Mޒ1NLlU\6j3Z 3W+{q^9 @68#3Я^X6 dV !`r[@wcjG;pnt5(I D2#0QpJ.2Vig~tyza@%lOH,\ܶŘ+fF$c)&ar|G d i=h gx]<6VCGܶՂoW1f)&T8s"3PSb-igy|D P<- ֩UP8F(H_1|wȉ@YHldAYL<ܗSZ7u/ Gu02#am@3Pa]w'\5!*Ijd2_U¦fS`L_`b*2FipQNj \i ^ҡ-$ i0qlĦ" r4@kNUO L@N;Eҗ;P Ȳwe\wi_ب+8Lu_;]|jJ#,m+6DJu<\QHCuV8TsV%J r3؅NXI< s 䩿p[.>w׮+%Ha $lXV AZ) ljzvZ S6Xn'&[PMlQb_HٛTqC74՞q\˥a+ |jyB-mh Yc6K)jB*Xlyel"5b#u2KsO)s` %\eI&Y^o;>sѱZ+'֬k'kkb'Vv( ((@J'U%tŗ~ͷ˅X5}ӟK"޲7=,G,M` -Y 帉=)<u&'brt:[Pv;alxD-%K &:N1~ +.$Y,V!:UqՙwG]HyEpD`Zʀ]#Չ[lNUe  a*BCxxbrNGm|n]t!sm>fէ11~j[f**D՛f`c@ζeCK-.X`E1)!<&Q 8U٬@T%@sn),Q'zuk0Y-c\c5>|]Uܮ:ey[qLb K в Z_O jՃ f)f`(~AC/fX ީ evs0NJO*2/o6 1LM̕Hl(7rjBRe0YΑ0˔#5+kkRk՘p WUI,#|JJ'Wy?|g($]LJ劀$-r  zcN7e% *QuO'a7}fš'Aofgwl,W%|nP|WK3 XY*, Qv:-`eȆy13ռ !&d`<P00Y;aϹ_TEl,޻Ӈ'}@O:"mcBz[@{#ަ $`b +GI TJ-jyP XLyބu] ? 'ChuY"K>;`e5Y]!.&*3GtkS`>vQ9Ʃt# \#2piX{*@Rٙpo}?,/`{;wp{);'Y8=߷bJރ}^u@lSY$ ҀUP48'"beh`58o_,K A`gϞ#fm6^q,oKR@!@&K )GTRH\.ξe"bq&f`r+K_ S31ae ܥ"=ѽG`%(ӤKmy`vy%A1^ZHqo+peY+%걲R`0]\>8XWN2du ⮞I=fb^\IiwF;z}Y S;lŢ+"WkXdXHm4~O&ڭFA:Q{B:N DuV>" \vlzmW1mQBic &hAWd dIY]a<=ː]oXCbل6" N:4K"N]\iAPdJ>{AzҺ1Ϫ֯R&&bjOx Z̔X%mGQ3wp V|hU`&Ƭ 1 iD Il8ԋhU=\ՁE]]m,0Uxuo^A,f<$ q3Wwfc9TñX>x2u Rhi-ū}#rgWܺ dV%%b3NE .]v"Uk*̌TQ&@2%̕+=Ԉ)#CY\QpJCA]YXB+O/6 YTB"t:`&pc'>ٛĆ Xaf݁˙c9sa*mb8OP8PsT;;cLX0)*Q,IuB=:4s\6+k6@@u,QUʲ ߳IY5_pK j}"C:7IC n[zkH * U(Qhy\j0k j5 ka4Vy SC~爪KAGua]pCWYk@7 >عV*)SvLf IT[9*VŅ p1Çr,=yy*׶osi~T,VPe d^MU~}x8zcBU j`n8/_49WMtۖQӎ$ĉ}^O7|dɚp0_ LN>*BQ *į+iyY!+a$HręGp Yp~O^ijkW?,8og+*<*i1W3laUEPN}l ==NH9_Dwh}b8 +_r`Q9n *ɔ^S~\b#' x݁%Yv'1k((@E3#xα͉"T(.&|庋k[6l2$@f/@pPHG7If/d:VpS&Q@vMfϪ{ tq}ط%=-kkܟq/€Fc@m#-W)ɥ9h`v`eAt^W_DToÝ?u{:n%ޗ!m&-uLl@uj1~GU݂QIdtK(60o[t$  !^@4DԵ&`=do7;,hܯ]gƷ󙣪Ǒ5`H1sU%((C7Kgx(F 6``G}gIPptҕv$wev(9C4w >|~gGZEeAh/}Q4[&t$k1whT=Cg bٵ[8H'4u͟w8> k1VedfOׇ Evqdd2 jʡHgKg ~!\S Lo@ O'b\'"D>(c?{BI 3=D&$tK*( BYhlHG*Bt )sx | l=Ǩ߅FUL6`(FxjRv;f3n+Rsvae9wjl췢(P8Pu2_Y !vO(2g(MωZohwW]1pw0\}NMb%7{ƒ7|hd@>fH\)N O!R$K@t1#QSsqiysXP kS2ļgKq X[Ҏdn}S$f(}LYq 5173O2]3pkΈrwmEsm'& ϽS0Q2:P K*FG(BbCp(\fpT/!AW}ΦdFQZ+gnةo 119 dgz z:v _H@j%p @4b/)(N',"Z)`XdZaCiu\)0`H;$fsoM64@],+{t@@VB 4˾{d Ih,4@F6PBH &cF4ΘW6dV]FV 'M=}y?c*5)kk̿ƣA3ͲS*e`KTxb&3'Wwk,fJqq@OC\WLmhF1wa˸tV0شn\1xc]cbT%rYl%v`>`> ;-1,Ҽ.Htqc Xz"%I*0Gܶ*Y" "p[̡C`;6y&d)iS矻ǭ=RX+V9ZeA*~c*MTEFC^H \ Z. k4ҩl۹, Ua4Nl3Ԍm^ӓz{e.ȃY\@R$I 59GIC9hk?8}R$o@j `~EOߏGΰq$zuMQ2eaTɩ*2ZOՃk,aS'G5r\n{%qF,0&k= W_2 8ogmX6kފI\*06ԃ!˻/{l,αTqٚQPʟGvm,%Eg2q>>`4x?iXJ?p8lxFfʝIQzCP^2 Y-tvI ip2LIm0z \hy$iDv T1FHHP@쮠nԌ'_w:Ԉ@Q[ >קI}, B!X E d $&Lu6`u19(&SioΘ,-YkVZikg4ό{Fl{P"' p E*g5fm a{(;[0kO)͹n`aڪ< %1b sƍq/3aaoIc.(k%vU1lўfNw H5zt>GdY ݛu_Ӡ 0kԃF] lq/D19rr ISS(ס^<縇8,BY 25aQw:01!uB957Oo:D*g󛑹OC[Z7o=ǰG 2)NZ73`u%:UP,@% ozpbAYSX K+LE*i9wB]H o]RB)X6ĩTZӵ49T2M>d*X)>@fii[g T;1_ 2 ]W?*DYgGŞ8g?{"B4Rqm܌ކ ~@BJ7D6YՌ;Q&`+z"* P(+,>>\ј_}̱\ \ ,d95nٺR~ߺ3}1<(QNNZպuشn'1WHޖyQZ,UZ dܔ˷+Xi[*(`2Pxbe@Z];C8ԎCP+2MߗINԩ@T@p|+7EZ]S PeՓ,چvSlwZYuYk+" ͈&X΅\T؅feMELYXhdtaf`D& N:["RVcXggZ]Yz)/NJNl>|n?xvH7ZX2^c(Uf*F?BUNRgD^TfԐ-5k'k_jQxH` fWɉ ɾ͞>3a>u,Vz@ mzOau;15yMĶ4?o }X!9'!jENs N~|+RF0`M ZZ0rz#dӸڌC >ԵU/@W4>'ϾqY @gߟ"dam,w?0$oI;V}(R'q$(%ԋy7%fDK"+Ve3`r?FV[j6u)o0ա@bScmUF ]v7٣ >_I]>d8{զqէhvìSh1bv25*x_FP=hڔ9«umE%GTT8\M8hr,3v7UEr-pe,Cp1ۂj咣&~@G'x 石XnBsm{xXj尦#\)^f}ntL"䀋u+ KB*8*(irY:)"PEWo5<-̬I?»7L)?>j0wF+Hܦ-d58oQ_Aj?F6܂zl0d# \EU:;nq\ֳ_arp6Ru  Ǝ3.qpa CX仏yP(~Pp]m=dAYٹ\u:@@>ZCǧ-spbYCv@ d)[f2p;e|o ?x |)!" ,fxU=7,Cd݄l> ꁘ:JWzsL'Ak"˘+"&Ļ̶ ^#e'^נ$;T6i:Jeb;yW5MK!3jRa`ҹ6}N :xbT%XU Ja"+⡜+!1ޕ X|vy{ _ 9oyx Vb_@5 ضF~R+G]-{<YM] Ǿ7n*2Xi >%8xF?;A6U(`P .=VޛG[rw/"޷Ԧ%F*Il1ލ^ 3}9cxz<>=xfi66-(d m$$jޛ}_Dd{^W˓~y߷cJ" 0yfh<U$;"[r#="\2X({?mʶYdr20{"D̘EFhr@C!5b!#%~_| qB^Xp3Я+H,w>FO>1e[㯸  F,*M>.TΦ. '~vU.TpeR 5o#=p3j9Ez2r5ӱC8q`F`bLG"(>"ʎФm+4pe[U-0 IDAT]-@"2bT5@Ts|nڌ[(JcztmV .e  j4O!ȠZ&(:tX<6<8'=_ë.1֌і :R& F#`iI U-X.,ǻwk. b3` 68oM:F 1]OSkoyn7r=@y5hkK IoHfB`B` РcN:FY$5%FvL wg"su8nr#d2X(Kbz`"]lpLpEDV,UմFA20á|@3/-:'ߣ1Z-W3Qzz/T9xz*/*Aָ<{sm`%{e KT T9'߻BYT Fn^T%NO\ [^^ A!dz%r֔ieSO~=4P TW?fS[]KȨZq-ן ǗsIjr-J@՘zY<@Nօ8y0t@3^ųqq.VpH㼰]{. O_E\3ӵܲCoϏc-(Ճ]oI Ă*`%bαxwWnzC}l `¿} mW/:hBG=X{C5CgOD 3E Ubޠ)&EMO:YZgSSd{&\IٲM*Db9yPaޯ͞_UhQUM։]W6~S̳%ɩiN XL,QbXF5^VSxM:!*mǿ߭cw]>^MMLV4#0|TK[ڥ䂖NjF nʙ9""#|¥c]bTjB@usM'`W:kP}J| p@FDLXyXA|Xۗ9ǡmY  -J#deLa^+[ގhWb6*]ft>Q34AX&68&F =f8q эEOF^0\b9U`\ {HN ~'lyj{nMcš$tRԛ l# |JN ok5M^] A3Y*iP'`<yܓi#?SAdVv4!: '_[)[=gTE< >^ MC0>dT8ɝ1k" ÒQ `E6en)*t1%'-AVX!ɲxrZQ=M0 c OpRe碱X4( ?\+œ]U` 3gI~i1oϗNP0WCtAh}p4j*Ƈ/]+|MuX\yr-l/YK&@bL̓R ;Ocpqbu^rpbM[csa1 tq2K0nw`UȩMܕsƪ($0&Wܱ|I&1HJ@%/S-,C->nЭ?Qe{ހqN ϏϏ'˳Y!aeO.j O=ɫ?')w&t*OɚbY=$Ue}8R-qc'G܊BL,z#@/߱jWzЫR*F8pNQ9HJ7 ʁ<')}RI6XVWo84݌]e dM`z_z_:jR^c@ rO\ %@@sOlvvKĺs)A[,G1:M 6m'~ť׿*Tu;hʌ>71%q&y@pT'Pa4,{C$RJ3ef ?v9nFDy j*|5ط#kKR*Yd p =h+UeN2:Rm,DkG$ B XU9=s% `F I}߷ ; [] lcŒ+2VS(,Ha!: ~ǬB<& T%8#,l%9bkD r4eS e> ;{C#`5Hn6om綍+ 1AJ~&Ofk2E0`Ԍ<%kduLU'*ΞʥHB c9׶MliW}ݟ54 Ysqp#ݷDEڇŅ}Fެz;[Y0i]Heo f:|, V²a&*W֯}wm>=)[ H<젖W㓄) X&0jB1޹6% Bp koI<Y,]q򭘓pQHAt1`3M@z/:>ʐ,R"6`a^>T D^5()"9Tᆢm*$u9=v׿*T`%5!cgKNP|e P`<%vs)NY#U DWXE _ɧfwжcyD$/qӣw;_9mpQ ϧɸJ:3 @ X(]OI98QnaAۇh V?SX{Kp5 `<8$(جP!e6/IR2WLlvP0l Iڏ}E4oɵX˽Lgd=Xi͟*y۱LӫFf2.Ɍ*f< ɞ !Hʉh)6"gRu;?z!FhQ 4$7Z,cB B1̞`.r1cuv{r: Tu[ 2hc<W*,M_ =cXsri}9kP݊*UaW5`O^²xz#an>iZs:4uWk4c컥9Jן/./,޸զM83'` $,<_0?͒ ,Ze`8hy Q8rp&bW>^7Y Ü{{9uM:"y0>KE^a`1X`aDkV7&`(Ūji`HUd, MSy&S(X'X S Udg ?#ŀ^tG1J u›{VIL@ qq½p_¬ޞ <&wx,] ,h,O LG.]u'Elæ1DMhbN;wd1g5B! G}ĥ%viַ_9h ܗO n"YAdV0,aY+x Zן,vXe`5IjV{/3KŜ\.3b\{rɺZ#,eC6LVMVi3H36X&bVKNR8 $˦DɟՓ,&eMR鸆+Sp<~B)R3Y2Xф'=a]W|g?~a!mƥ2zA2;A 9R{qgcfTEBNJ'l!u>HZH.D澻 VT~ ^ Ɨ/;᤺O I [3@sW"8U(y \3bJ@Dʼj۟F\W(,9z4/}Z3&ç-[2U>vH!ܝJ@XW1,v|Y UOwy5d p(H|UknGEPhRD@iȬO$ڲA+M1I!HLt<8uEF%A&8y-E$0 0"lymq٘DRfreV)K +WX^ZE$]XJ1oim0!b8dw,$TyxAl"Ic j]>z(4p@10aF8_z^ˉ`x 1J;d]8cEdvf0 ,,,Ba!t"0M/°H^׭ L$yWsp)ژC4L?UO\0X$qFwRvqDGcd$^۔*ӻ08i=6- u^L,V,dfօcҽ9 vta+zA `RNU4ITf.)⼣,Lfy:6f,FV5#{:2*D*1b,q!~h땉;:U0wc2TCV  X@M%T]ZF1wj'E 4* FcɀxcSsbLq4Ț8pܞ3ԋS&,rnUhH؍z lp5-7J_Aq%RB\1P;sWDO|bHI=2{ ixaD8e"hɺl}d14!2xM#sihhНȢ4ms`IT6Q%kP(嗕, CfkW(*Ղ@'{FG)DQXy@# rrlDC;oB K{F>+@Vr`o?:'_nu;`:|.Ы0@b&3T&dql$./6|9^IYUw;z⓬OZo}t}wKK0ƬbɣCp[K?w;|Qϛ,9kd H {^UFkT1qi}u= {%|ɖ<2)Y@/ rf%>A×ѣVoL֭*i41:*E@B5Ƥ[֢$cwc&ӟX,a~ca}Qrߗ{.|ߖ@(mۯ7|+rTt+S$3Ĉ] ` iO+YŒ%=.tYj(#Y>vY5$vԟCV۰XUԽ^}7Vn[( }|Ǥ"# GϘ\@¤&^ p u!0^'_Mxri&dǢmBjrQ0 ,d+㵿ل@c&?Zk]Wf/h/u:{dzH3\EAޒ7ao,O:K?\ 0cVm@p?߅[_m:ݜʹ$HF;.Ȳ>Bϝ/Z^NY/oX- C3I ~9'Z\r饈\A'`tLDz8Wn87p;9O?dy( :xԤhʓGdL5,*o/&vY uw,K2$/Q'"6)y`_ǃ;%i*Y2Z݅tsi'[0^\i׷?tE8M$14Il֤7]n!nՊH]3p !θL1.޿/ٛPY̽\!S]ZƶoPT d%<%E@MUgt[;)hF_[V$/}T`j#[qsssΨ)ͣ֩1QӲ{D`]WMlbpT.hu&{.BdsUbW}2U=Ju0^=ߙU P99;v|'Z,rt.yBTԌ4)&8,?7 C< ҹWa|Q`HgV +xc_P_. qo/GW;+3JiFb37dRh7匳 T3ypY1x@,L[ֹ (+*zlO Ni$}S9[>sݵ{){%<CƂ+"\bّsPJP92{_PK=-(',@8@=&]'q~,nzM@$\yA{C{+sYcGl.35i.<ʥq(Xg& e*9T?;nڻ{3@ﭽ3 0UОXUot"BN7[>g)["{{1iNOXeejf${& @v &HI=K$sD2GʈyW xGKM`ft[T=#TتzH8uVUGxhQ~g~e}u,`Pd6Mᴟ1un&"!Z?*;(pփo]cCߋJ, R0HqϽ'x걽h`=ߊzJjz0ؾ 2b0kLEe.Y,{I〪cD]4#.ԣGQ3p4!<{ow8czElZ`joQ=O8Edbi@6"qcI7 Rbǫn|Z)KUy lLH |<9[>^ GǘazA]+ gWfĞɌ4Μc a ,|Cl:正t=ֿPeCwkv.rx-4TaD'c^BVGX@`pJ T˯$Ι\l%@]dUH gN&mu2߽*ϹCF3-nHW|@WZm2 ` !15ՖCP aPPONϡ+W(SKZ(z=wi*ynAE2XZA^Y_nw4u%2o&/x5R {pɋsq%h{h+;If Q;wvνn3wǚ# j\b,}B$'^fx, ی=.`/Y~6naqe鳳''*ڴEY0 hm! WT%BH, ʵ| 0U,0i΀o `W$&Z'-o2ΉЀ1[F 0s};Y :ɩZ5t_o ѓγVlP-u~W$pbow{T޻w?>eL ;{eԓ` J5ޟYXtҬ]5RWڪ_攜 ,Ng dC:0a0"Foي1YEFjnb`ߞ)X'a9u*YA);r אE֠ @@,Vi )1,ìE'=ǔa="zbce״{]BKy|HdDdAΉ|dmV\I><'yZ|`B4L)U/ [PdIi %0xlR` 3hYV}f)y{AԀCk]{K}ʡ`&]ݺ]'h dw5zudH=UA@dw'΁Kg *G{TbY 9F$q$v!cYlT8rcTD d2I(aT "W/d)TDnmW^V&SY,k3[. - #0 jb,-P%). n kW\J)ý{6r~@*HDPH7@%*K37D hnAtĀn)?,k44Kp,Ԃ`Qk; z*[ᐢ3l'@bH^+, F8Xqu ps0geDil]-P6f箚p|)WӊzZ^N 3z/X<I}/;)TyTBu]?+sfmkKYJ.edmIBm4#%Ҥ`@e[#@l,C`0 6$VJJ ԃl6ة ج)K@\|_|1f8R4F lwgg+o$ f;E;:m,Hv? |5Pd{@z}]=5VUā&h36Q@P%]o"zsmރQ aK#¡GFP-a0e8D3!$G\ r5@5Ӆejx;q4v*o/áL; B^I o|n~6-Xַ CLZi).GHwN+rާ}a=OLL5K-T+][K;ֺ/-Y5i2Y^fk $uE"DM!jޡ k<1MZ&JDM@z=pkP]_o8 l1:;c[! e`!KʘN6,LZ 0̦F.AR8KD^u$Р!TѶҋy BI̱b\rI-=UqMZ*6:R)БVJf,)xie1.z ",sߗb={ff<;ڎ姬SmZG!dUuZN<*.Ȋ@(5$@H|95$bw@cd:1rNʼU>4E8f%9Lc! & H `XԀ4u_}芢s 0XMꀖDcf3YF'XF܏ xɈ=bD=Y~c eUAW]>W8"9F^A~ae·#vֿmfoVجd3gch A9G$\ (e'JtwUׄp葝/r{A vN=`*.r̕6:ovJa( `šӳ=I>vLB)" h^T,N })@@:`Ǽλn(OUZ&& IDAT։:jb d:M!c}nÇY, F=OU6;9 9Ih~>E(DO*iXǷ1h +t1bӠ(rnN2~(?cV!{l%{g3*,`*@ ТG We\q<uUakiw{Zd{V2ޱP'X,_0WłJU~N BH`}UFn-lm'IL_ @$KG]HEeԃ3JLVJJg{?pK~#ܐ^*V΂\'3F,56^Gͽ -N- !j>IrPuSdpHl(e`f񡧞L#Y" [#kGA"5$Cɍ2623aWjNFh"=%v$zRoU:Z͔,U%< -YvJ- \+.[ɠL]\#Ӫ;`x$ ˑT"tiVS)Ć5 [T*֥G)h `iu{u{jhϰx1L۔~z5teuX߱D[XTbdK#Ct|_z/hOZ3Y2XkF弘 ݷbs[M9<Ӏ'-)XT2C* )~3C;14cgW 劲:N52ǹ䔇4df"r. 0 g~-`qL*+.g2(c7s<$(ނA4RlnjZUz'L9Z+{9/Ct|}.BCU׈6o  l5PTxE1'-v2$3#vXpUĞqJG8MMdR >cT𗀂\ؾ2[i 0@NA(3lUR@\E0RfAFKdKr4pmER>E+; ;Vc/LNeyfS] ߶aTPJcF Q{ld1ݍ U5Y3(c'J pe |kÇ\pދJoEuK[/1=^Fao緤,BH"fq@ 3JH 8udz1VD.$g9.ID'$շf۬t+P❨x'7ùlǁjK>id԰}"[Tt vjX5QܨWbq})-ϻU&?cݶfmXc0Hpop 5YQ3LOC^^5 *ya8R>R]L]cTx,V>,,cB`Ht; @M#(>]d7F|/U.]M*錢+pTc`5 [b{#U5'xO׶"_f3TP>@dF{8{{i|Sm@.{%2`"3 HAvDnjBw{MbMpg=)w*WW:eFFe(˚. g>UO*Ub%av=V8e(3Z$rfcΐ+}4 72*([bDPX,\@k`+FK$[YAG y .=TT箱|ɃY"[Lοu8;t01rY%C plɋ˶*Z.PUUK:%!2FKlP7`jbt˜\ٺ ,d*d=7sh+/9tCy=,.or!t8keZdU3s6U!+!X+[:@9IQ9_߄a/ ,N;RB#RZ#:`"SPP[4i݄(1'h9>(\tɔb[u[  {a Sy/Aj#''I"}-R}49)M*:mçCpL]h^ؗHzbd~I|aWxd.9ﴇ+ cKp}o-QnY-gyԍچln5|(ږޣjT|@@Uc{7g~tJAR}@y\+k4g\1S {=N' oNGX q3=s6g߹f肪 @\71٘ރeGhXK@{F~^"NS{ e Gщ- P4\w, 6" KQ&:G\dlQc@lkSz! `QKX *cEվEYT"`4EA;QOԁ~7`Dޏ1X\Ua2WMh#|C_$Bnb+#n7GY0qK8xE<͹|(JLNJUNe}n߾lsŝT( tmMPU|^OLI&{$jb u(@i4|aX,<)8 Ub:3aO?  [6&ێO3(8b0B4VU- S+VaI)*-hRxCp7g옑M^Oj0$ݏ?, CFź,@ R3x }_xq*t8sdUq4iyγm3Y2XkrW}$2`%7]UrivĊLle220)wsT,3y%Gu';WJBv mdc۬6 6nlϸglўi0^qC4flvŴ,$VPUT{f99'"2RIzPUVޛ/ofDddΉsOg3r3_2GCh<}eJxR2+Uþ{Y9xPm?Hհ L;mhBDӶ"tDl.?.Q*xV jPES{~5#@ܗK0l8Q;h'@kZ_ L~>@%Vu@;F/Kdp6*xH?{~Ӧ7*e \9ʓ8CB$&2U;$9- bmjRZb` z76 O+Y_cD=D?z<@kx`"4gv BM /yKuFf -A?D2XU7pp#e`ȕ)rL`UX#vU4謚҂!KX*ݤ.@N !D'j<؝fiˠZRp)OYMӕ!v=x` *l75}",Fۀ+QA6tPs@G l р7DV@_#D!8{zUf|̧݅١Wçcd31 m,dURaBͼua%*BXY1FmԶ4x˝">_;30Q\>Xb@-{XÖI lK!5u2ۃL,$~6G:pJ,q=}ٽwa;0?/oMy >4瞁9G75e+v=ib`K{7m6[5/K2@JƬsxmR-~) pYԘV:Xc2q|_? θ6}.>J*Cy;g0F)׎5Yza@Ř,FR5,Kbta* XیtBH 3F Cwc6|PםVǾZмmW*{C{7dٯ , VZO]‹^ōozRͱʮqhAb ą{h5JDY+ʠʻbpջY 5  X C]Yw|4{`uy`Zrsç߽Z?I|eUX_]"k4=ŦA4k-V%}=հ]4VMdկLT KDBJY4b =&;c2s6"UDfEO@,&br.x;)97=813Y̌M̅rU^ݪ5 jh b wفRpXPWpe2Rޱcg櫏ʝ,rW֫d6ҟ*gaMUѡ`+$.T^o}T5gPNU6Lv/Kvh)( BHX7fjjnx@YJ%y(hl'"FIb)dj@Y+qRd@L'sx@ˎs|0/w~@( @qUcHœ_&aٷb"!$>sHL#Ae_Wj>D˱UKcT :cxtb8"R|F&X)~W,z4`X4H zV|x~]Tsq-ܴ{o{"tڶ^r`rv@RVҺ9섲W\e_,kDw\Zu(cXݖSmw[ a6 /FLgrt fl9rƢ;K(Y)G+ҤXrps~vS G+ c9|\U[5l /'|QW''.ɀkjAV<*di@hLavXD+6"`y+ߣ (0WY5I ?<˗J0ByfvIa&b,N^m _ius*r93ؒL:H(ĉ;g+T4.e32KF?w{8l:tǼ;zl\la+/Y 8 Vcp RHɶ>~t3`>}7m^-Y0 g*ݶM4xb՗lng6|.j& _s6), K0V i2, !%*iV:+-n :Q G8y)Y2X }FX=`Xni0s'^ xboY_W凞g>K"A omfhDf:bcl)AK3Y5 =ѪDXgYMחiNːyhvgܤ3RLvۤ-{j00|}B~oW^EU븍DŦ!>\)A(hʘW&Տ-x(t܂4`+\}Ttpx;:Y+xh #/hW:]f,5#.e>_~MڂǽzP)g6`5=gPv:u?!|삷!x7sQ.A dV~zЯ (]NٽZ<܇`ŝkP>XBDYQVS3u`_MDֺRLho!'tQD;"?|ۛ_(ݯ=cF]\h}DigH6iMix*4)ݛN*J/䩒XɄHh-(K ҟd'w5hD l`3bi&̄ hMdD$qk/-~5=r'I%P 6|@SJ5_z9`Np:KLU9=syT//a@؀VgCo<Yؘ|/3,wzG4L[_%ˆ*'z%RC,`i=pǟ9{a j̼x6b 7KTp 嬕F5B\YUW̕>0=4d4mKf&1"vs< 脀g8;k7 |8o,&"f"W L>ؚ`7eL<8x΂@-  i!21&&i2y=21ʨ|! VJ2 j꬞}v3Dࢵ}yoJ/ + _S g~m2ؤXW[։}gmJh0Vc9,7"xUJ:7 !J%Â!zWgaz|󙜨kp\}ժ9|~* 1ZH|3Vn,3]75>+Т& +w YXK3@ E{bӠ1= nW?;| ς\e=T95X ZlaaUX|wWк=W8sEB/>0}Qh\<FzKGRvKyr&Ie Id{lY t s@6C ُX y?!3jz4X5B~P05|5;4uM%Wpy މ&miǼj/>M4A##FF.l1FhAxP -я33O ޺̀5`}]ݫ[_G~}~~m ,axRpɧvr/q %K+ ;> ~iZwl9y[UTkdaICӕLWWuN?{so"xWp+t'A]s4'HpbM zIB127-4 ,mz'(n!&ĕ~=:S{ Sx;P^!XJABτ>扐>{Sޤ_;k\UF@3B&9w]S &I߱% 9.ַBv8`$K5iMc#Tx F5d}A/%O ~t@f-0FgTvg ` }+M(`CNo\l$FAќLϿx/*eBg~?d ICZ# c^rl48dDg'1Eۄ"[4tlNB}p1>6]cT'~酑ܠ|zi[1޳MZj3+}Y%Nd{g#C$xu9B:_A/絀tf@c@4N 11[eX+7 :SJam=eA;^e`O*Πږ`&nK6%${.ǝ޿2H<*l*TpQs\kd1_) [Ѭ+ Z nW;wƲ0pબ;jY;fx'0mL` ^7͟ `Ldو%HH}@@t\LJ1b:Y~@8gst]7`j ++o@|ЯgYK.Ӈjv\e0Ҙ`Ŧ,|2 B*<<%)˜`a.N;^66@) P f20+xo{>x%H bbh, V@}6Ă'&79ؖnhUվP"-cKkS`Ȝu.X%$zl== tPqDhڭ JULsb8Vj%vLWpEl[Z Ys62f[ԡnȗYRksv,0۾#w\ili;Ĉ$az^<,i`Nlj鶚W\IZE0)V*L ,1p!>3cP]?sl| e>ϬtX͖+"2&&"6 dh֏~gγl /PG;P+B:8>K~je'%@je;o[Cw+)´ϻS{^LGSeqф :h^#P̺8hʂ<"@{v6ոK΁rp)>X$';<"h" ; CAUN-b 6;("/'FfF`׫Ş_?%U\T o1*#X;T#g^H;/4VD^Ʉ`i6X ~{ބ?Ql~??_| j,]ע\dj}b̈́-t!Д7S4RGvTأ)PMJ `4m Ĉao;g~TS;tX1Zhc&g+[5M{3i[Ķ50-%&B>.iPL amOLy*+&cf=:j+!N_H {3XgތwªϨG\io1J,W2z.JVgQ֫tg!֗&hKy`mVWOVh_Z=R.lVbA5- X1@Gs0ܿ{l"F"#mcKaB;/&WiԔ$5⡳Sް:74&XRˏuoTW;ȪE4r5 [aȖ/o tqŊ( sGn V>Aϱ+q(ſMg46h9kj9k[ (*Dx[W Q>;W1(('/F%ޯfm`+K~BD5fG:A *܍w ۤ9NS<ȰHNw_ebf!3t>:)6BPm2x%Z`mϣ96:Q$El"d[,>{I ')hnj>;m]$'-^"dE[g)/ר}c[ XUf׻."*fMeq#0sOz/Jpu ^#j.7Rǀj#͹h&6s )cD 38FTqv)3[5%2e8pύ7b3Ŗbias6[4 m!m^A A ʾ9e_=P߫҄z1kއ$'&ef8Z+>}kH9r3AB`stJsʚ @:iq~-Wכ?3X4V;hIh`bt r.<&C[[jR-Jw ɯ3] sEuL-4WXprYgCNKΔ%${50 }'laͭbP<4!@%X匕94<x+ٟK*{F.O>Ekrh:@&ju BF/+UQbM3/&^Pu TZ IJg0"W`1NFhbK}DȌ ∘W̅ؒu7"[ЯpH ơ_8ֳ2= QV:!: p"GYK==U-c0W1F]=8m Lp's;{˫AWwO\ŭZQ kccD,gPUD9_fDx · o;ui?[ޏ^]v+KQn7 {ĔRô|Y)jD !T*Lq31ㇸx|g`mt9ӓӤŬRf::Wa!iA)D&tsFTGֵ,"4A1u@ শփ|W% l $rz "lT3ݢ6; %*DʤB/|ȕw3ۍކp@\fVaf_mlsԫX,5 d2 'f&S7t]/A"O YaJJ!sQ,),&AJGn60W_0ﲒr4ڷ $JEO|&kY 5 †O"Lhcq{?BȀUfv.|xTrKPL4wڀ2F0B3~#%΀u]Q:z[[^iVOI>'3BЂ"D9Oٍ|a䆱"6XK@h, VxJ _;{ PWVXtYw,&I+*[J~o z&ka dK1'F!e@!׌,  P jI\A4r.'BL-@DHcMգ_̈́3 ?/Un9>kܴ١\P@) y׏#u\OJJ:ôuBwYV9wd㸖 :q;ƖkPʛ0!){9f+vv ~m GCfi:Ͻ8 B @AHI\5sҙ*E++:yAсҀ *JL֯l`"uP7[d@4D:ϡ(>a#%'@  ch_w{Өcj/;U *%e\p)KYNj:]=,X7<" `+Ͽ@K`PZd %[!AV6 #D>.4 < czڣ| h,[r~C!~ !*P A`˟mue8~p57/>6i.'c-H%)S_ڞg?~o"~ 1]& (*A;>>T::9X󹦖p_<~Jy-b exΓ/s񍽫 `ƉcxNn9e{JCEP|qʲ$YMg4M@Y|7ೡ (Sc>V*Uiy ϶B˹102Uu%4e% Pb,ab FAD W%%ͩ9D]3/&mhѝ3(@( S@5^o72v-3V@0k>Uݽ3A3KLDtƓf Xޮڸ3{mm+7~!9 iێߘCƦP/l;ǼbAl5W͒xӆD?P~͢؋`dM@QY!muM7AazHZc^1'ڶkARީAdU]1Y@ES+kl-e)Kio"CKixlW,lŪNK<8,ҕLel>s`,!] OҡyfhNہ fd .+"˧"dtp`UW<|Owz6&7\V'<сdrg@m".c ,T j{IR@sq~ӶZ|LhqvB[x wUu@9Wx3X\$Vcnw*INϫi &wga~;8j0:>^|&@wSJ@~P(E± c*{G>3 6 _dY%Ò IDATi@2]wߦ2- PI50'yj xW,c>0%͉=Cl g[r:Vsݷ;yLu:JR}4hTw"}1`DrVjE(TB0?,o+|k.hVZo*s=1$>#~D",Qx@uH(K dfeNd[?Cܜ6wmB'ōO,YXV;.ŬuX_t&I8?uie.TOeOw[ח}Nk3?C+|>[uyaDJic Ї-PIʼnxMK?m(=/>]8- Vx [Z[w,M.gy=0*õŠ [MT!4DʔPR-3H #vv h0d, Adm4kb+MD[pWB^qEݻ=q6m@u%AX2!@И`+?j6 9\]o[ DRI~]e0J"c-q۰(dЕ/A&@'4̐dqf-+?BSZ H?Pduo,+Z3Y5٫e&&zDsxiEg2ke+9G r"=pƻ=(%ޣ!vUɋ˓L`vgI: )3p04LޯX7/4`\kH },:>7S%qM E.K2_Wg4ɛ.>Fo<)]HC1F! g'"!": W x9' ;-/7hh0ĄFu=kGO{;`+ZULWƃ0 AY6rpWx*6tk5Z7?_yᗔ|2]lYÛ>y઺!+R?N N"zޟ@m 4Xzտ`6+Ax.1@X"z5W2Y:Lw6_Zwn ̏ǯ|σ*ѼJPh`M t\sd2.vPUI ΃= f Diy}@s dfKxW0/T -VY[, C87?JNZCd)X(N5I{i)x1#ӑ+6+x@Nz-D 4Q֖Zlק IП0el}k" %t(0.xֱ 3l[a>$ 4Pl@#QjS/kGb[" ^{'R^\{o.eo>_y->"gA=|||Ik*ABvLFjAX/vEW_UfԻnǁsCaEV`C(+ &Lx]LP'Vmw\:K&GIeޛƖ1:*W>%ޛdlAIzM+I Ihqs]~n} :uf tpͫ+й8`uK\ǮKidE-X2*ICq9^Ȭsel981b+^>&qkwx.{fC~nc׾T ޣ?pza">g!%F v?^7f 4=Ș46 V;Fc[u =¤Gh{?Nu8&223fZ[SeWb! \}W~؏>isa5,g牸O?tdX_@/x[?X+HaaUBߤpɁqs bJS Kb|Ps'X{$N%ľdsX/p6w-Rd6Qf3O X,LVM| 7%1H6FW7-T+eL>XxBя y $DҮ+coyS8a5? y4FBU\<lP̈́(ˍYx/1ԫ*Mi"Ɓs4;Ya&:>9[6?rN[TK60(Gf>-Sv*ɘP%D9Y ,&@S῱8qPa$%€&@“<_6QfbAAy"eD@I@Jt@KENbVq:&R;3DDV M`F` @`WwWL'T?+ MMGb?h TeѠʜY+(#0q>)kqꄱ ":E.!ڗ9uY֧7D 1rx{ 82A~6Cl*_}۔)pPG_'+2¾c1X\e=k_+͠ >82ޙ@3ZG<|zWs )h)\8tw dETSpMT35e¥,֦X*bA!N̯ǎcuj wpVETv,1SQv+<¶pH<t`Z!VbJDc: ʕ&> MHSHa-ڧbV!͍Kx{5[r}|](\sאqoSe!eW(7/CS| s4AH5953`+Lw~7Cj"\ϛYE @Vg*qe*z@ ~ z`'6+{j@&4ԝ̞_@1h>s=vy,8xTpΏ|W%<3Y~.H]"RKY`mf trr^bƩdA'":P= A}%%Ө`&5 BO1  2WksB[WلS*ePM}_l]reVd (p*fADfW\WtC'^{1yVo亽3ROP쥶l|~꩙ LA]Af e0/ #BDXCfJV,5u`U,vo*<}U:5++@%X{F*tnUTǓ1:{@<NA0 fB( ?P;wjL{36Mz\{@ygg!goA>EAòԩ8c̫A0ex,&7GϾ9lVL#2 t(OP<\ZtA@τy =J.yW,qQgy ?)]YVjd6`wu2 U! 5T2WH6{c]s;^}ݹm6p_p?i"wICa`\;o ;v0JN- O8 Ya_I x4*MM4c'MVAsPUaq VNs+23vۂx#$Nx3]_Il`"Uq{׫!ެН]QlV#%u 6F3];~3W#mX/T^W526S+ _Q/$}+|Y/)u)Ea%LE>Q+5hC`3(lV53r1m1kG\:YMP2C3aG IH7 n+8$~X&Q=ekV.j* V1y W~ݬ|Y8GI' Mt+^5ud[/u=xOO[f \a"򿟭ɳXEZC^EHX۱h,mm`b u4Ì,^Dm h#i&Z6MWV2WEc" ƈ,f YCDDhb<`Ep@-\9(} 5  ka`h xpJ}vpMW`1` N%k/}%DD";sfZr٤V !BaS5k~m5vX^-`mf [ '`n*jfuum볍R]$SfiQ #deEͦT{je{o!ƢQ(7hy`fF@3#38$fD5Wq͕^&d1'If2]-7#N}Wo f ⟧cz7b)j2bP "bt|6Z`L{eˍ'Sp !$ף}3Am.D<ʕm<Y5yeg)* җ0duxmoKYMtz dYZ>PѰJԇ L䄡A83WQYb)vXgP6HD$;N; s-! M8Yjwe bϵs;,n j>3Q@s%H"YZk QN0^D4|G2a񏟂_ գmG"͌ތr!W~>i #Ne0dGdp `!3"v7371X1%pe5pWG:X M k{/I14m n"V ݥ܀o U)/ )):aSA<Zs `Ius_/ 6GMnun0Gܶc%4L\tJ{!6R.Kɒ:}NN, dA@0ɬQ:P Oc {@TP,ujw{lZAwwiŬ<Drx a&)b pPVLJmEeIp&BQp8SM>e5 23= |s wxshN:өLYpc{o~)Oe&ʿ;hs2+j.bnJY3h@!B͂miZ +,ﳛ $r}df(3Y6``Pp4LW,o鶟 (#,u` W p;d>ֿ = 6s<`(}FƀUlH)A$jn&LS@ Yb]g܄w_ Ʀl>eWdAtJ0mKzML}+>OB- }@m7O"3-D}s@DŽyOX?<~!ܷ߅;@y YX^NHQeu:F+\}e ' %zF g>c~\R۵?IfO ٫7]D qW=qXZfr mmMБ.%9賫Cc"YD FP;aWk~:EỮCuѽpFx<>z,"V3T{X%lB2Ň,Jz.?wK߽3C:FwHc ZgU 'KpcC|IoѴ{,  hU~?AVr^R.r0 > ]o*]y|~{#RS%gx6Y:e E n < 1 \9xp:+6}!g@7õ?Dk6Eg@ iJ],L"TW?W|\sDABa%jPϲA՗GWfDPۀ&-0 (a+}$ףT^?^s1cpQK4Ŏ,VG/2M|%y2nvu?rJYb~^)xy.z[ ,1$ٵČC~ɘ5}V]ii+[ 1$\|M2Y @5֠[qDM9-rlyho#qk:}X_JWHD!Ef-Oabze'BtI{J=d H .A} ޕMދ#:VY7ks{J5HUdɒI$ԁ!cӌa|鯿:u7@ &'xl˒y,JRի޽{_i^i]ҭ{}瞳>ۿ5kB ĞX,LfQ62% ^~!-+8)M@\Ly\-CDT-<ʑ}? سW G.:#:Mp0 IDATǝ |kCo@S&N`j6S*~r* 91%so}̻O5GD#4"2:G I ) :P'V.!洯,I`B]#[KN\?_}{͸Y)i~Ə cÄgOmh~PgIT֍~/On:SvgdϻίN!%q\pߡZgfrEYFB,d( ZzDJgpցYO ~?i[0Ou(+WgL!Lj欕d;310VeVH37A- H3 %Ĉ" 0d֗s"x>﫡 o~ ~t_ {{?c&=X6۷!jODPsG\y +7{&3PY5NA$N0v!hUDFu 50OSB6WCƆѣb)V@' >Y(`ьZ v4tݷq^:< KM e[8ˤk8aUPWs +CYcZP`﹙+ ]}ʪNY!bfpn)3Ky},iN!3XM@d@ق1[DN4%$@kJn%dfOκ9x`e7[ߊ5cCII,xU/ߎ#D RY\^ ;3[T L?-ʥbf))8 KA:Q#<>  :A҈( XK)5h>o`B{K:lvV6 ֎78ycf} deVT%dĞ"x&PR1Z%xh`j}}INuFen7mI6(M @ nK a%G=o??Qs5%o>tESA$_؈>#t^bc]Ǽ*6@&(W^K HM:]MyDXtf!uqT/k[J PPssD {;Vb>),|`m.`r^)u8;8TW/@1=p8}C̓bf4nG 3cTJExE:LQ1RE y"$`S>"be&h{!ƈN`'sX耯Oy]̆Di6 5\O+%J<'ij T_02Vkd,E+幹^= QsCc&7}}(a-` dJ?204@5M͑s j~=pѼv fyұY q[7ښ;'YbaA:XsEUD!K%%MMOFW.{'9XBN,HQ-M<2B#_ ƿΌNlLU%l;vőz3pUːhbDy4-7MdTdQmN P# vC[B*^ev @AI(ɮOx8 rdN /|ǎoÑ-7p'xpv]DY%Dh~VF=oKNy1Q*D /Kg$inNawgm#r?g*fQ+n;ΑnWc^$\svKXSxT<+ʔP%)2% @R)DŽ8",!&5ڴdjVƀB88]T9RYtQ/H/& ZB\k d[5JͥmZikID/qyƅ~Q+mצ s'YI#$T'K#/8)ЭqFBt&n)۵[_2!?aMX J`9Pbx@X鼇52#0-?Pҩ-s@$<7ܲ8L%;V2q QH͈?5?].`I`KDD\(u)`[LY7Oڹ@K2U廾{᫹ YӒ&x%s/g.SjZX7X鎒Zל*="=Q]_A+6ӠWiJђ&X%Oꫳ\@:9* e)iVΒ/vY.K}\V(BK%[' L7G+*9곚`c*t٥+ V4ȓL2{ Oj'h) @Eץ@\↾(m!/^O=H;wePmX f?*h8,k5 ,L3NV线ǟPN>w1GE-w-go&1)! ]a:M;q2 |NEU i@~e~m,) AXZ~i׼CW6{=0\[D̠W4{iQ ZpOVU\1`e%(.ߎ܇e|OD%"b%:Zqc[Ri**y:+@Dp>s { ّŲ{](V6Tc# 3 P5U0!%o-'@VS4 A%x탫Tޭfgny/ZSLJ /`LKx/d@r.1i%UX{orYF#рx`5Yv/G<L٧I?+sC*{l/@w2ea]ot)k$Ứɠj/vA Cq 8Ur*W>R(6fjV5Z%sz ^Xgb^1 Pu pտ3P?))j}Xq2/2z ̮:qNyLO:.?$&a|۴Tb, V {Qm/^<hM^U=) WW{&tP@NԠK]DoHqJ|V+*hQ_Ŷ#yscXov3\M4͹g.3~^ދ_ KQlz~dU{RaT1Y{$K`7-l}NHD\iP3(?9:)oZR"u+V[k2HK9’ޖ;QF.o^u! :Y-Dm \γf"SGx:^?o {5W2Uث*;\W^jǙb *ԩ>/~ʙIFF6k5KB#-a5T&"]É16ibIAGDΩcۖmBa|eosw&wnr8\U|"Q(4OX2siH~ (u`QWL^s%VMKSCtӉ -߈n2AmrݛTSyj^sgi<+YߑRE(wC!/i.8^Cȕѣd4e,r`#dU-wC?{:|% g,6RNL\Kw\J_hԠC+,w Sh ɭYwp?n03BX[ 1&c.^z>Xweb+؁xMxZ58oFO-lR*Mk`:l?$]l" JXLύ2S\A@^w 8BWVw[@:s,A3"B#q>s+ Qy̙٢J[ VZ<N+g2SgN%KDaJ@gftϠJHfRXlA&44,rmay n n6W dI8ͨV>r7Z';3hgyz;;!Rƃ 'g0=dI7&3sBR!['ϩb٫D<(Zf%י <"1/zD^j#-of2(<1CDyTX ]b&chpvݎgz:%~ݘA6@f˥K@@EcĚ[!V]bM9$p*U[nqUȅ+s Aku_OgDKHD(1iQ3%aLaO+>ڨ'Ǖ&@ׁt&ثY^"`]);ޭ@ּ4"(,-V|oj6MJ4 '׿5kW_%WϼcwR* ao2e>:Fń23V#ֿ:*[P^kFS8 y `mN X^!4,dG !9+glg&Ob:J'EY r٤bJA*pu[= ;Nb&TAfiYLwNzf΂/2{%쭷ݎO]}F>}5xM7)#a OįfXbQ, {Ց?Xu>$6@ `ՠ;uF|m+pJUTE}&gFC?굁Z><\)罇FӒqRX`5;6Lɣsz %`tfܳuނ/$(BF{ŕU+9[iܮ-BRpB^rX[$IʶE k?r1j2UV`l`.̮MmU,)Eazgb5jAFX4ᰞ dILSJ M-PCĽ/ Q0@ʖX gkSPTNp,VIsߛ7Rit|(AVٷ>}m㓯z60y馛sT< N瘸n% Ll,=oq`E 8 ykr,Tp(J ,W"Fh4cEwXǞ]3UlMzq#jJ+&k˷)c DP@  s~z3*=p=]9eZZEu(@"U{(z={r2k5<NJ" )>ʫއWVܶOQ Z:gG%1e!RDL~,j{1JĐHZ$YŰS4q4x˸ty7LX]_Ygb-+UIw@gT EP:3X\,X4*A4A1%]Tmq*^'6UoG:_!ib=SMʨ_6RnhSc 5v)R{UŒ׾U= 56?`>xCd8V[! zyؕW GZscpkD5g΍EBBrA*Vbapb`Ewi.X} &ORڏ6 zKYV)DM̩!te\KNk$vET?D`c 48cυD_il*̎Z>Oh&ͤ+e<@D{r-$)b7ռeY0v.;pW~|UpS;7#?^҉Y;?-p֑@ݥqK/;]{ipIT>vtךɢt$ N d (aTq3ٔ9irKQơ `^u d?FFq,k''W[у#>dfO)ODJUg^.dgR[X f1Rk,5L;&-x<*7g}d NXm,{w<]7'Zg*e!p6Ş޽ eY#.j4B^X[$Ӊ&kG/,k9gV0T KxWPl C? r9d=9U ܻ%>):Ao+=.}\遀)x8|C!?\ڙM:o+b$uF&,+~R*MW=V ŤJU$UZE4j`s@;n}o.4.g]﷩6Y~jc|C`5 ^>$ wL&p616/Éa3݇sw'oؾs3vNq%kVhqn{cԖ|U2{77> ^VEha%-1X,' n %m3ƂsD#_/:fsrqb%' xҙԯWsr@Gy3=g\)Y-X;~|́VKE("aH h9 T̙I9!ճC>X"̒-ה;k*%nd,I@ZJHK )F`i׹h0ڦ@PK8TŕoscGU3WP㠍89 k# ||[@`A7GQaC'Ti}s/Qkմ$Mg:Qgӎ`2NoOܐhIu7bu|ݷL*VN]p)7>%e`XiadสjvbzfB0ܟRVQD+@yB,=o;bhbc=NzQT%X^vu^?t&zDC8K :pL:JqB^ҲX[$b"y"r&U>1I<{%|80$0,)0(pNDc~&՟{|+g!6G,_p~Nٹ>! _п70V)2r :%B@U];AXR}=ߐ>{PbP>!RfSVǶ,H,̐5Ipvfv:F|@2FDĮ3@g.r< t0r8pg<rgfR ,-XE%? M_2ϑq;.#Wx۩ 9=9@[bIxq~\&4`#c^af,`u#7yӺwυ4qW_X[(!eCvCDYudVv]5Xt :t8G;^ `v#Wտ:o/;Zh o;(bYpB~Qf&o Է&B&Y-\˔gXK 1S^*5I0X0x_ A4@ň8"N':^௤'O♈LAvlcTfB)h5s7Vq :`Ѡ.\KB27pRuޝVFg}1%C3Ip~'KjvxL'En#&z;X(/061 |o4H))iU2aNkH,SHǠg6mh}DX{%Y5SvU@wr`c 8h3:d#`͏B goG_~ץ2fVˮ|8v?RT վw)9olvxf7eݳ}S콐,t1'>n -7d}jӔIP~n$H*]Q8b @;2Iv1ANw۫$<r吮3)TJޱ&_q$Da Rut 4m@] P[!s{{I>l@BҶ@=\=p?K&܎e3>nfg݇ZLLJ6X)BccNLĨw:E$ӲI<*O0y@K< Ug+LbEsUW`N16 'm{mo$貪9SؿW}>>tYLJkrQ%'Ts?m:=vT7 j>SB^ҲX[(1 =ص<dS@K_N[)RދQ`D@9?PJ03PQl.D^0M~pWe]E%p0%)}Raa=Q"DNh u@v_z`jsp3dk҄Wv!mXxwO?WƑ@UFVlvGY*Pg?#8h~V0=X$R3!5.ËsI$/|:ZgKi9Ĝ#}e88x76 :P,zdkY\9BӜ;jלŒdf X;^@Q;´dw{bH"|#50_澨VG 27Tq1dЙ+^2VYs*D4" k\k RxZP%YfR*XA3J74BfTf -OSncsT!T5 |ӠhX?1g#P3I $HL8xX9qWfߪ %gYkkrU"h[p;@,TqnHn}n!,U cLRj q,"PHULHh&FFuMiA&1 dyxu`H 3"|A,_pڳv`ȑzfc`QqR@ҋldיY,Qk [~, 댤q&˙+G>>:1aDpF~/-]ibJ8[#~.s\\,29mXje4U0 3e5CF5ncV X,׺,X'9kb^q& 5Vzŏu !efZ%E8OzSTpOVh-h^riXzZEKo"V瞧LM4e!-{8J)A5 :4U|:ڎYb,ͬ S+8OaA3PW9Ie*(&7n@x/. F B oDT$a9(Q{ p`ewƠlt+UV&=Zuatr nvU#l[OGj 90'URYWiU gf܉b%)*MUl6lO F^ƞ;GuWsw\mL8A x|Z{ϠZ{2d6ԘҤm *P$$GdnciؾJIQ?_VV(F[ٌˤ*R7 YY'ۮ4=`e@3LKq,85`~YFTfET# Iۿ ZbQT,AO3< 4AAR+nžBny"\/c?w/3Y{1Qa*W1}i/ˮ]o+^߸.ԣqI gnD *"e9'(x'IULI5if6"(rr`ߎ;ˇVRI0>tPٞ=@ՕvBÓ}s( Ava0?@Uy_F0m2*e T+85b(^Ͷ _T D享$k덍pޡ 48+aF{TٟĨI,W '9 , 6DÊQ5[HSAϐ):Ө{ͤIbxϾ"G}k 9ݏ!()&l :'s{l&iN@J"O q3X$y2^vaMā}tn"uI&}FU2ESȡ)X~?1Xi ۷mL"HBJQ9$$\r+bY6lu9|SؘyCƄGwEDtO9# ƜMPMZ:NL dyΨ: QsK$hY,A]ISՇV2g ʺYP0}fWLeRO9ڈ6*qp J!u{|ʵ @I3h[{ Rvw|+~+$#x6:{^v.w`_d9fl7i3TW$TJ^ЙV ۝`> $I2pU>:UxMϯG*)=VJʈw*-"c%D`(P `&BXLN<^+EH"hF-M9mޟ:Ԓw"u~s b J>QvnW8؞pQfB%t ,J R)3SJ]TVY^y(o'H A`LE2&8c|(y80+PU'?~#l-$!3W]o^1S‘T@˂Z+YX$`JꦖlLL[?sq(3.,b2QW)$iXw?ع z=8.D:˫ fMo H]I*72S7l)˟[? }F6'z0"w.N&MTuz@OدŒ0ixQp-ߜg?G*p5`zs \tlps]*fT]Ḯa8b2jY;5k+!}y0"%0V` hi[РI 8+ߨvD1\-"3Y,OXK=_)A*O\Uޡg&KK `u\BL,g&< az-v\e9̼Q02;Uȱh QWŔ}4vo9?)4;Nk(`&'T&a v݌HG)PIO<ޮUȒ> }/IP$%tdfÒ-ܬ>t IDAT\I\p5_BJW}vX{[ǿyf0󳛍qhwiG)±}!3X[,S]k}#gkC*ϒDY+w2I 4SEG\'LQ^Q->d`*j85 ,14+8ypXk]l0Y#g0Kd燩 W`c{NB^ZX[,^j 8HUiɀ Љ'Δ W`,`]Ƞ,Yf*9HrJn{\7ߘ{1M=&ۯɗ8{1eHu*S $hA> )m +3%|,ã{&4$5tƤQPIJadF8L'udaf l{)>*)!1f4mf4R69['|dۯ9)~X0GD}  el(" JlE:3HWR^6%]KFKÝlO__8s؋($uQ@aC s3k5_NBTCY^iAt]ʑ Yé2]YyzW4RH DJALTHtJYEOuqͭ t9X>\,/Gqr5{VV&Пk߉3މ!\1#}5\Q[!LeUl.`8,VR*12WL-(;Mπ#&5tlJ:L ^Iۿf'g#Mù24S`m8uL|/v|tωZe-U/ĎB> AG#\-W^2 )ٻh>;2y>Yb &{J T7w Aaq@-U"^&7J_W{mBt\I[GL$-{*遬lGϽI1W$Yd5FVdjgiP2{K L=;{SJK-ˡ2|#R`NZ( =e*B5tmwW_vt%|i xcb|1t57aCؽM|G!{`#`*ZaS>ϙ{Rݺc>Xd*W`2Qh-- Z'cx y:Bd[ yUkRk;EX"gg@ƖCM1FLv rA5I`8 Lb 1cB,W.胬>rYBaF'15P>DzfqD}t>"a&lSu~,E/ T#z&sr.(fA  l{#,Ivx. ȸwO%+%U!= j".8gE< \ n1\9Z}JJlFޫW4T[4l~ǛPC{Y\МwkNl!;.VS2ڟ߾m>vjJar.||7݊i<q@4d@E<2Mq8^[f&3Qf5ʒ*9qo2*ݭ֣ KƀĒ@^z5kFfy5`--!YW>>ͬGUefuǷVdč7nĉ{>ߦkiz~Ozaݭ<[2b]3Y\;?|/"8#Z7"a`]*i{+\E71 GG#qI@_o~ . T`j`1lvpfVa#X!ȯw_3lO.^&R;*;.}6JN(YNѩ]S¸TK4u`0;j@M`4Tۏ30.h(o* + .*,WkB9?3%p i]I&s"\`4«fۃVX/,$irϹZ£gK= 4|8!GQA>pa'Wh6 ##bڑ*@>hXgm`=\E.Xٱ[ v+4\SkmCT ,u!O84`pe2$"Mr`4e|~mx11QcCEGX9It\Uh-3(Y6׶&M㐊ѻ"a۸^v[渰T8c7q0p0)K8ۏ A?Sd/|@RؔNM#އr2=U"Yjn7?xо>xh,V]3*:FO>gV0="=4ȔCD,:R5oX4ѨeBDBV}V]+,OI)ʀ(#ӳb˰Vo:tx,tkPz}^o 5Y9jWowIł7bO},QyfD;fyĽ%_y bF연xSX0ɛ8<n?ga'M@[jys'o1Ϯ1u~ZT!?e C})·M|j"V\tN7M"WznL[nEH*W #^ӛ6T8N5K|&{ Oȥw`.LFlնʕKȉ(sΦ 9F3RO"$,jTg7}hYJ_X!/E62\#J?'Jb]grh0rVldɓ T_(Ho Q_v.bf";ϫO A„;'0{Qt8LRRJ#G$ %7䇜߱$m kVԕJ !, 6zm4S~ QBa ~3m%@5}A`s5aKy峁=`"}? %Xl9lLOx0 -z+6r"FKu ժhSpb:'6k,>vjPY΍+fYϔSyZ)+hI}XIH}WdhVu-#M91Xc"݈SUZl!Z_M~7myLLJ6p##X;^a0ؙ~X%(2=sJ᳒.2J4L@bt:< ".:7Xqx25V'1rm.b!ZٖY 0X^IVRz,#Jog࡟?O0,mݐVzm[V**?KbE.w:kyܷwsߍˍ,oetDF;?(۷B-e:i.;7r)ZIR 1HacEdrj]ỷNZUpm%+}q8n!AYdڀ0WKk "RJG՝b>,OArVQKH2mՈao[F f*- *QWZu|^W@FA|@ dQ#WӺ^Sr@`D/zXh²?ey-΋:h#N/MHvsQ _# p=i d{i1<<"muuɑ~ۤwJ[B%`qN/ovR2-h8#^z:7sKp?v3pY(Z@HW/}@-ۙJcA8DEB-*GW>_tX7߯Fdy(ebE|Jhϟl>=hЛԗV0LYEʏiwWSiLqR)'Mfa/؝ʡGb9[&hǙUvhI0*W,UnX:`u j*sy_&J<M \ڼgMapcȄ*QAUd+Y-գh([SEY)7A!9.l?[IDJ,YҺ=F Qc1#l |D1^l;BfҹYcTpN}W |kK"OD[޻, hyLn`` ` h85!#r_zmO踮|ф<25:FF26a 414ΒܞhS6[a~ Ɋb8!CJZ {ffű}c#W<:b5v ?-E规,)-۞32bEeb$a^[`!P!*ގ\Q(8|kM_kG XiY*Uy*:h*LıEgI F}(jɢQ(EzDeBF<:Ѿm =r8sa W1*09 Ώ*QɹJ\,w9X(sa߫U& =΋r-Sdp=R95hpzacQ^%[JP. ՜ը_Hm̈kBBDAB1$ۆ¢pϏ) N?EO0sB"Եdp~a{RE^X;o%X, u5J !?)EqؖT}hRA4/ql9k$,9W1Jp<$!h+XdhH'Srx& qx]RwdqRf6}槟1%, 3y o&|Dl\A^>~uÒӣƹ4ׇ$<Ɏ4o H~Mƽ2ۯȽBnKM@s M~G u%H! hbT~w*X+z`\4:븄$h6 cភK;K#Xli-3=~+d+ma,׵M#(B@vSz]b{C`&HT LLV`f\8 6*/, ESH|*BbIIݷ>'aR*ԫ #:P7+,[g+/Hv/E ]1L#9qW?)ʓ)L V 9Q;6U! IDATc8ZnBH#ɔ(%xR pKJ!Tf|s?BH.z"[=Z[l 㦢6BhB4Rf067M*Wba0D3D3 SJWϾBT"q/р>dW3+v_k}`(k#UMAt [|bvrz0 vB;۹KM`j0¹-5V Uh,d0!r]4SlwVfdʕHG)N3;BcL"X9D"ŕ$TGF$ST<31.׀LnQMp M@ j"<6)YЃoޑ tm8I5Ivmm,]l9Zmx*3ϴmԚ`.0~ QhB:^h4װ(#0kxogtZ ǿvs MbAՆRB]=mDC%5Dh!;|܏^}{< =0K]hõAGvF^Dx~psǒTz4MeR(JS#R?:M|QTT/> ~Ӟ:T1j?p}h,f *XJ2%a;"ŨD *9F\Be%bU؀8k(R֑ g^#z']*Z$mԐ:h"?-tv7|#ʏ+ 2ɲ&߹I-*H'aC"YY,gBAYlV[f͞=~6$k8PQjhKV՟m)Y[+ߧ9Klg!Yy1(%Mh -k>'hj%(saqxwAS05SWi u+lY!'|/ Fkfjˌ%žɖJÅzgp.[ f3V;!W,# Cls&f\:?p3ńZNPZ,eR)|RlN'K4ܓ$XGכ\!C5YA6{KdHIYVXv\5e(u"Cp!6BA)Ȗ%G3+M-wу"4^r)8[0lC+ga9,h v#;V`.b\1mG/ %4`spэ"!tFN0O.]bUore@&& 8&*ti$av\!w$8gU* װeq!"]y] [k54fTey7Am! XRKd"J&4hF5A=njFCY7Q7 YBrC"XHg0 )rX-@蝌,Oj;hld4 P+&Bu˩r7AFI6 & y: 6Q"C2jPb,ӘabR/]ء"V!^C/陞$D]uٞkxB}ʃvEΑV`넎`^mɩ*+ظJrUbr& #VJ^H77\}"p@c<1 "}BZn ^'+kz?P[l)CMA ,hاlU"w$uY2 BVLAnTb8222YN>ϕ c 1`TR2!5d5I6äb%UyĪ)!׊o_7{ e[_u4ևf_K8r1;!YF}T&H2Sb`)t]bu{IxO Cạ!X|_TN`\8nVgui5?ĀVʡk1(GmZ5DNWH_-!j$ĭ >Dr뎉"LR1m,ܨ5p/3%KgsKwp!/Ui!{e*|x3[&RxdRr}ї"?Iuy=(mMG%&<4.֭:,[cmAC/y x0`HLzBh^jކ{_>#-q<*.11Y!ɑX_a=uޝߵa+؎lu4ad$L c#:H`/!G%Judtϝfd9OUGq:7b7pSS8b_}"po}>>Ds~.HXV?LN!..9k. x<+/lvf}moD[I*eJ.k KƢ7)16*-A;m%0L:pb NZI_[Z;3o[+T\C2ߗ0%:r"=e8Pq?QV"\} C= X9w!ZVXqiՍ 78?~lO,&<#+UFe B(Z_HHwQ,-S}9 T2IGjA8{N8*:}"8oa/}CLd)r(DzhH)IX$f(hp/=鹙cxۗy>Cw2qV.NIҢDP`0lsz6zUچQ/vkLs0 /ilⱷ`ᑻS3N*r0+_^f˲l*Z8nBZ8qnH?jAljrK!UK3p~ %b\(Wt\&1{qF2j]+= Wz]KXK8$uk$x33[t6և HʶX`V&%6ŵ}&Y?8IPHip/߁?toʥc\,UK*]sˤ@+vqv!!'B8dz19ow,_7'%J>۳Vރ-Ex"qϹ I,{o#X?Gv S "g`O!Ƿ}U9,s͍QG$1Hl;mQF^ Qs,:ZQ P!F§Fw=s1yopfEL!69!B8#k$I9'd ,wJ!\ud~Ť "yӺ8NCF,H7*:$ǚcݣȚ840'o nÃm%8Onȸέ6^f)ǂ{,ע%}jUԲCVOoAe%NUBT%Z7Ǒk Bɂ$,:BIT"*:*/Y*8V=EIYsJꗑ/wVzd o.Ud׎Rp/ړX&U&/T|t`I]BP7 N;xd T>r2y .Ł#FE$&xz \&^wk^0³gA`,85h8',D8ZEJҽ/#l? u l4{k^5O9`\)sOA4&W#:2'<hur&Y&DtxHtq6e[:LS{)렚Hhaspa^"W.&[.F<3OS!dd2]4;@9)sDJ$Be8jr&bU+p!'n<|wA T2ᴰu(j*Q"U é*XPAU@5]u5,V=41KE-:r~HLzJt9:×v\MNUܩWvA_~_ꈯ_e  4E{ Sf1 Ծoye32XF a8|eʃ25/MDx~"hy^Ec4 8s#W;Ez Y#X1/D*f\iI4tuPa /cL(%UźD*z@@Hbe5@3yw]^z3#d%HP;j*h򀟪xHmR|75VRdjӃC@`JUFȠݹv@F *zreJ?F.MękWLpm!$ˠEhQ"ZtkJdB4P(sVh viGeӨrɝ.-ðуFBf?` UUj8Tj,jǰt?wyQ3nٳg%dh]AѲe_^";ͅE 呆~=\ҹ*V3 H-!)i9iےM$'kN %Yԋxw>R9psEJB+ޞ-JaP;K Rfa% kLNUhӏvj7pDzډI3e9+i% FQX;oe _~b O\w(9$XY9wP\,b U@zWbt-Ա[ish9"ZB.GLS*"6-𝟅B+֙GeqRH!RA=|G@muPwA#Q$EKU=sF%iAXVr4B8}rؿN IDATE0y"j9G։ZX D"MNVj'#.2F8c0!B 7&lX ,FpB=fHQ3DH*RE @EEXK08sDYp};}G%*ٺ]_;Ee.+lsh)_ -IV|= jdVM)~("!7-,*Kk25zlḒ\A|ls##6ZV ln<; f'09]!FawUtk`Ql12N?nwbn/@ ŕN+(rH28X6Iฬ&:8{+.C<@k *$5:Gq%[R7jx0HzBdP}'X##(?W_~VE+cWJ}s0cim9l,.nmcF MIR  |s%l-2O ҨdNGJZewRmt(pĩ<48|oZpsF}2FD;wdgÁ%#8(j.#X; z8*Fpv\8.!Ň#.p&gBFd(gE)psI0K+DΝ9te]fY";'.112b@rj@ 0<Z0 ̸}&{Ǐ}ׯ p!;0GU###p!`u9ձ9Z-䝟UZ86ynr{ 4WuUJp wn$G ?YTh;@ԫ F xÅG gU+LR彅܀MP!ށ…cw±'WS=OtUG`0N\#͍k#ln]pwH\^Pi,H i8] VpXlo~R<`:E8"SJU瘕Ua NE*Ď@Ш30pk;Pi>#/5@ڟmc_| iJ"95zm8_15¥}!0SKibjھH>'GTTDNGj.};5ՈBH~\<#oߡC3 -ot:k1\8HtK7pm 84.eÅL^CwytU[uiR1c}~+=k]^[ 6 YP3eG0YͲuMu@5jQPd q646}oFB̜k;/^8H喁^N 5"#0J26BfoPZN"j?Uz}PR ?r *!YaՁiT} >|͍tq0&*O`)LMW 4`0" }36}3&Wl\^N Y3 ϽhwN̅Oj˹e9)mTpoʪyOlI[l1ʨM~9(ɠ_<\|SssC=BN(=$*6)*Jk>cPjdT#E\=qȑ"8<@=JB} W rB!^d\'ldʾ.QLLx:2 pz^u3u=ĄOC''pP#l]=Ň psZ ҉QTD]Ma/9EJ`T^J$\~-<U=i !6" eID~T_At%f?rt78>D"Btd9H~/+~x"W&1*OEQ=Ynw2Un9ir@=/VՔ4^fY84@!8a-/ַuћ05ʥaWbÞB0 շ9\3=9,IQcsae6*\$=3d_ݍP#uHb@^ Vly/C#KR3B-6)=E fH}Wq8b8a50Ghub|H T[9vrpl8Z1s.-yW5C%Q, dBFr&v`Z PT& o /L`j#W:G#c0Кaz f3n ֩[<.,$,]&xόhA8?3WP@ܰc,ٻ%mf^ӯft I{6݁[h0p8$hN#˞+9z֧d _{Ėh y'1j7,{ M "۳qNť!X.̀pnN[<9Gcz٤nMaa쭯6(w\puZgr4ℜ(L}9"hi<+Q4Ym|o}# 1G fpGqK5yk7ncbybI@z[TbUi`6Eb _#,A\s= Aɥtis"B[)|jnҡ"u:5tDC\l3sfx>  66j^a8jru2Hs, z< -%+ӯ" cjr5s`%4g=99WxDsQ2L{ ??}Xp~O"ykD8n,ZpϨM$f*fJ~RgYRbC SFL,lxvq$1JHѾ&VI")ꃨԗ60WR{` n0LO98y^uأSn-@05̬I ).B 2q}manu؂~K' Tː,jK,.0ʔȐ,FcEuN , & >_kʽf;t]8s hMQk(s7RBNĉ<52ʜ"rTBp#I/E>(߾"D`y\t:^ےkWqJ,rP;Yt) ukzf&91;å^cҰS:$%5!ZֽAA|_ޱr:%BA{џ=8DM$A28gTɁ6&| E$ V.GH(]G;tLGida: &Iu9jߑC9J844EPLͧe 4MoZ@.1!}7 SWfp z=}8:\zcczn*UaAK inUT [vpm$WFqm]-űA '1j":+/a_Uzoqӳ=qΖGG:QQHugz7ukcn>f#ĵNzb"BBAɄXy$ ܙǪXNPpxhEUPp!Ht立=;(/U([s㖊uyuyIh%EK,"T-ONQFMT"h oV{E%D zUHG#5{‘cb'qѕ]>:a[[s}13T)cuee|F 3*̣"LsPd^T$uğa!HN! vjOީI-ӻ¶J .KxuYEFIrXE)||`i`q7!.TɶU22X"cDSۃuOnߛՕ!VW:ϫ7:1Q/oIhb.3lrQ#T@IXIy6,IJYͲsT+0YBA5A`s9C8#W_<Oąh!ʠ!#WzbUb*,,Ix;BʇMc$k{w}{AܫhJ^5<,j:kKu\7yl!iUL P,3:k\2Z<0>x=$:aW`ֹ8|s&{,__aueՋC:ukO O;+ նADkXRe`v*9sh3Zl[0cmo؊r{΅%J#05^GFhbXJXE8A<:cBa$ NH@ cDr=͒TwÍ`uuX4\2-Nণsnp Soϊ҉wC:u@D2wMTlĞB,PpkZm$-G__A"9Hq%l#8TJ91CRA]FYj2 cV`[Z8SKrKС `usNڷ 3=n2ZuFXDeۮRXh7lW0B~6{m{U+S wBV2bMt!@o9X\1P9 &j.r`V1?$03חb ~ v{-u 2haq 3s=LM]~u邌N찻(V'^\ h7l3ɻp濗QZ{{EidSAE E+} EKÅ+4ꘁAա8B\Ŵ&z 0Bפ 28jGG:Pl68)Ofpnp|n5,_x%${F2+3;ɯRa jSXDQHLUDཛྷ[x dQ(Xn .Y96 ͍g6v :tV!0V.rPOaVխٹ>fra 1 Ck XL$n{19ǪX9JFqRLɫժJ %bkUI!H@dWzX!`W򯦦{8xx#U:)fSduk~a&u pla+RaUc61P6)3%5+Xа!(#1 ^m(F{)Y ?C7 QsUDb5u4 WVh'#@_:V$B`\8 tjI1=þI[ah 7PNt*D~g(i+j5,@ZJM[g199'9D=K&h\!D<:i͍þ I'<`<ٺtau]ŖБAx:0]+Vu%Yh}3!QR"HRd.gE<Ή)ŨD+_G%FC_'PO;uuWO|Ϸ<GG:<Bl2>SӢn-,Ng1[[abn=. ĀԲ UE7<&|arq+6v⯐ALdƣ.R^{ͪ\^HJ#l )]sy_7мY¸µ=4{.ضv],r:L൵Yv٫u2}'y%^?O ѐw_bl>Fś8jo1cl׌dpm̸)pR}Tflޜu8[{ X"c{TzV&% ciШS-wˏr B;<%ñޯlzUeafӹ?n?2#a}!NG2me^߿DܩX]aYf&ڷWOIDATyW%A~UkqRAĽڭvs`v[Yt8t.qDk,\ ^˱F{7>z˄!Ul dk˲Le+k0˛5;/fXf^lf "%Lզk 2 df֠*ĸv#KenUvn7Ók#\wg6Ca#^ZO &P!?.\ˌS۸] ޾+2-{ЄY7l6p??eyo@K54}Ug!"ۭdDrn5Tw;4j΁c' qX2_Is⌬.HOrÕ9)l\\Bf -,vC]/ږ W͡(=O PiӬEt(`bwHyMygnqҙ( i,:zvKּ?YhY GO .D6 V q]׻,!ژ kN!m-g،5Z},˥+k2B(dQ}yu]p X"[Z4+[iTm{jI' Ce526kDws*\r*vq޶-;T- fsc:g @$b#Nc{(dsf=u(`Lv+RXi 1r3U>n͋_z^CsM&m^]9+_޲ x˂`w Ɨr`AܥV̫jiykDQѨ !8,ݪUF}þڭ*v'tðr3Y2d10tyˌ6ۖYz .'2,۲[x G)IorG - ^To]u֏15 X"3;d]wM|#bZ\J2x:FF7E;/X=Im FF( bcaY@ ǁCیf~e,Z`?xյef^Ʌ%r*2&ЕFvڥZsbh3j#sl~3rz,NC/PwX{]ע5WedK؃uzX4Du0E%rFod1=l^ZKҡUC0+wzoY xGgLJ\?t8c0`٬V'5!|94$ X"sVPtXfqQraE=,'VjfF`DW`ѯL:=H8pr?8Z׎Y8ͻ۳[um- n-~vD X"s::`mP&1S1X .ݚNDq7ywV pq^ #[ܑZۧeyU4jz)-g^T{%u(`̽þCҡZr*$2(lk7r}{=*;m{Y?fN`4 H+5|+by|6k_xL3$X2OKK9nes10XҲ ףV5Kn-Eo`rzO^ޏݼ;yUڃu<rGra)`c}g\"!Q\LH ۭյ,i;m5[9:/y//W/5JN?%U@vkMcn-cV慭ڭS8v1z#kV&1aF{{#a (`\XڭT [1\LvUj>z/]7'i6LDv7ldrݺt5ͥi^-%8'o0{fL-pjO+3~9O6W< X"rV2XJHbdrn^o~mKK|?d8+JY rM4٢+ <-|VHUX),ƉG-RbÞڭ 7o];:$\~WrzWKYrI)`'9;llə{2(E vnX ܼ[?V[.n / (`)kۭ Y{,,*m.6d#F],Ɯ,/(Tv5JNIۗu:R-wl=ncf)1>{.[mZ?,4-Y*"=XXv9L2WV DdvkYh,Lv$S $ \wW*];z1yv+ Wo'FU-z{yl| X"2n&ۛMbb)A4XJP,yVô[;:b޼7G[9b0>o_g82"!ݿlUc?7o(,Zv+ L[R^{.-sCS YGhW3G.klV9_W+)`}5z[#a+6nlv+vg 2緯@W|3G 9{.{Us21 lW*@*ݪvjvkMBg 8d|"/ Wݎf^ɧK',|kkvFMcKN7ulvPڭ)VvVR-UV5~gaސя~vX"L?z|H+87Vk%"ByMkRrBlPiS=?˩~*\ݩ6v _-=vj-Iմ(`llkc,#,;akVKc!;b_~0/ܼc߬T'wOfr{&KrJjl{k-IK%" POڭBs7v*ݙ[Ð5++WR 1>ϟhbС\o5WdL"ƕb7Tz˟?մ5T1h6zq)an]IrŴ[{.[[ތ sN6w,.+\d[=ຜHȦMKr!gm]*,Av++[޵U:y!+mr$_.fY؋&V9vs&Ip}9ǃꭞYVlw?rM,v*Y^I+Ľv+ʕ4Jr'vkx1䔖,.'xJzaG#3 _\)Fˉf}CiX?ۿOjPȅJ/|)E'1,\ӧZE5v,bYEny]^>yX<̳G^ qE&ntvԤO iL3h.%{֥i.]5VⅭS[' ?Q4 W2WN<Pڃ%"2g}ݭ[-Ra,/EgwEyMibw|3FޘML9\i? )`LXO>lJ+I qs2ZkkYvacڭӄllGW"%"2Eû ޽n5ZlM3QJIJn?G4\&y}?SfӺ9^ؔK JAzcnբ?,k.p•H@DDΈx/)ֽ%rwnfW;[-v}c"r: X""gT, aLDIg٢|-fsz=RZ1>T{%,9nHUZIOD($YZIrA^j&[,aΌ.9DDn=L<!_r9E'Κ Jcn[ @4Q6ߎȹ%"2::޾ZK+IW'ݪ;6("GKD;n/yrGdDD.JCOgDDDD,)`LKDDD$` X""""S HDDDD%"""0,)`LKDDD$` X""""S HDDDD%"""0,)`LKDDD$` X""""S HDDDD%"""0,)`LKDDD$` X""""S HDDDD%"""0,)`LKDDD$` X""""S HDDDDf` IENDB`v_sim-3.8.0/tests/exports/planes-3.5.png000066400000000000000000004150761370110300500200030ustar00rootroot00000000000000PNG  IHDRXXfsBIT|d IDATxY$yKRU{7  Em"15%eA[5,Rh1Z2]]6c ߉5RP>ˠۅNmV}'x@DQBI)U VE1<)~ \fq+8O)Ja:]T6}-pП}/]'KcZv9z(ǎSfϜБ#Z-qAW>N rWQd3dxm5 9Sa.v2  ܫNCݦj=}SȺ>fOСCc{c;[QWkkz? *$jqU4*.iAv3B(L@w Zj]?ɿQ׍ծ9/A&"\yR1{1k-ՂCǎmн9:BOcx7QvAZin'gA<TVYBYzRQ)1FvXjQ`>4؟nckJ}I5Gv- zޣZaz}XH4vQ33L=JݮD٤Ewi !AᠨUZP) x S@e@u 󚱚k R =EQP7oyY33aEu)};[QZ}as),Cy E^R,K9e&kCA^&Y)`m7zMZm_iVb,z}y7op: ~9@k- lBA :Zb)X*{%e> *.ҭZ`w\Q)[Zy\ bK+{𢡄_Y^c{=ի8kqҟHQ4gQ/A8(vuRnS،(nAY@ò \?a˥ZW3m.C?k76IPvXkLUx@+ܬ^Oe~BA6R4{Nsn/ \b:hPcl%bSt"agٖQDVYeIQ}u~ҕ2 $JGr ܳw,%K>e+Q{RSے{|YVyeQ46ٜ.Jb$wA^ԟ.(8P8(\XIɜëo4ah|o隐 "(A؛_OjUBpu$;<V0YVX kAhӂNLюP-Fqgg7/V\#_kq j+A*@ y*X2 yL(HpAX`Uqy[MR&5)KXb><{0-Ϸmr&}Mk  &6R}3Av 1JAfBRd!u_ݞ 7D8QL"Ak9YއJRϳ_-xq%dزpvDT U4WA#b)L }"A ے.Jd6,T:o E(͈a'ضJ  X  fAA:`  LX  F  „% 0aD`  LX  F  „% 0aD`  LX  F  „% 0aƞY=xGw{ „%[mD jxqK} %[ҊjVx)KGYzV(J)a{_$²G$ ,AL=xs4@/V*) ωB̠PVb/A݂,A JA2U,E›klT&^v@ [DjKA>D` „0F JAKr&%)« 1*I+V@r!&KaK%6XBe喆RpE 96P9_A#K6֊vV!\S/AX9ԪF-m }I«axU hl /v,/Vs^ lXN?"wֶZ7r.rz}%F5RJe 2hcm/OQ]ys"AXXE̡Yfsw4«A*a]VePd «11,- GX! K8چCmSܼџL"gI$G5*.kuH'̶6_-*0(/A83t:!/5ߖ^&އ< /m՘,+IjTtQ .^ }, 1&Td5tm+pr}H.Wpb)r1ͫ)U5AػSӇZ}͹4O _rĀ2.װjTaFG*(ETao K9tM+޼snpHSx54Me^n-ь~l{݄,aҝ8<ҏܸDRhTXw"j%V^Y!Ӵ;WSx"$A/=Ҧ3[,q'ž)&LݘՅT«j aࠕ#Fh G;X ;aR1'k2]h B;xw1,땞 yD` C-϶-]Ŭ$ 9^U L7/A\/AG1VshVWnV5C4\$ VT덭+WQx$@ B8r \זo$͓@l,aJb+ V)ۻ2 wߡ l="=c]f8`ˋ;%AE^V`m=1-͹S;IxEEx Xžݱ=֩Bׯ-pkw$ ~^ouQj% cWp2WGG;:Bȕˋ2Ivp,;^YV;E^>fnW!KأjXs}n\[nmSZv + TZÍQkEctIDU^$v?"]̡GOtCQ8]^diI&iJz'ZvTX^(>T蜧 m{E|,Ex X®ĩi3sNwI-" sJxC6JSdPcszK"A+t-ONa{zyQ&iJSx5ZUb˦эhi3Ix·r.^IWTEx [,aqxCG/\02 9bDSxe$4m Ax)%UO"M"K5Ls 㙻m%XKxLn[Z0uP%:fY[^IW"= #K:ĩ)]A6C^,-ꔃZx::ܘַ 309voky ,a9u 3x5דDvAZxj$k*Wp&\" Uv--Q"(";q46xy'ž`5H0ePn[L]N„z.k KVLsL"K {" 0yz^o «64uPɲӍrWdiC=/^{ X¶qHSgfޓKo̳ 4 YMxٖөjxUb}%k"KrQm&$7oƭ ΓP!v;täMeRPc[%K EZ9D` [tmBp[]DvAHkxvǒeN7N.^ƒRC~._\ [H;?Bx ݬz^ ǻUE :^)KX?"2{Ù3%ba^Av<NQ^SNJt6Pǫ,= 0 Q׸"`8tsoDvAȀjDV.( 2F15ՠ,=^E X¦ɸY _wο:͹{ _c9!Vw* ky7鰴X8Z X¦8} Nt­^ZZd"AIx :]q5,aCtp[\HYn5?C"A<(k\\,͑c]Ξ;o-2f_+y3o|_ ܛfZ[}ft갢P!Kcg8̡6ׯ,rd}nO46QKD i {8\0"8<읇C"|+TdW>*BJQ{qAv'NMq7QRa9"59s!N{sDZ05] #m~<  ڝY:%Hwrt7 orš؜[E2Lj2BɰJm%iS;>oVV; t/IpXHNCE^Ⱦ&:5KD (6h0"ќ{S(=\k̭kJW5Ilc^ #ۆsem4 !Q*ft8)Kk/q҆S!H*5] kC-11Lx5,nO{u+/\7:XџqK?{xCNBuNey,nx^&.Oi3ÄZjo`;[9PBa1{wڊ9k3/ XSg9{ar^}Ɩφ>٢}ک"ACtj_ƵSEZH2xri|cK>b Ya1Ivne ζDt ;0b%.rDCGq%EFG#qX;>1pҍUlcZdzf;Fׁ6%Nriu, knktA$<8 X9Sx\Z[?ps,M5(%K{ppp|٫knRqF!05q=GœQο:Džom&\TadcB] l5'NMq/>?ޗ"̥DHD`sNܝ!}~>0b+J<ԨIaams׽G{^~:7ƻhHnA>X}cf6܄/_Eⶋ;@Z=5V{2'5Zs/AFn| MGve_NYo6Zß>v$/Zkt] K =xvR0Zj`}t}ݱ=| /}.VbQ+0dvVέwWqasf9zbp+jCYX3λgnݫ{&=-:/+\7J< t{V]8yz3Boic!>/!Q>n~՗"v1)[FnF2+7Z=µ #?Lw1wc_LtJqF"krD?x >w'w!!µKc>3K {.} 7I I嵴^`;Z/Et N_ _oO$]=tNU.Lc5Qs#wݵTc Vc0Zt/a'ɬʥ^ނ&zʈE~at_(wkw Uθrny(%vёq&nxѓ:bqg.mgHpmD`:]}HLd9^3VpGû~ᵪ7J ZKث}Q- ĩ)~OQ8K\vp.Up%%;܆XM˟ox֊(p IDATֻO av3gpYr{|aon7ѹ_cǚ &,Fa^kJAYDIZx4+\!Σ Mq50st\#Jڕ +=ZcEcLpE/]x$/J">,JlykDH7̤.FZu#N6Wu8yzG~|"/ogOϴ8} 9}^C-.>rN7T}[yȵ'hXY ZlРAth_ *h_-@9B'z>pxch5wyg#*T TͶv' m`fAd% xw!=9ZE<ʻ?kcı2h"5V|i6h֕^wdDxOfyNwl:KF-྇sǛfn׷Np=Z )$aEjQn tG)WK}B:^g sE%j +_)h)QDudkֆPRx*b2EԜAEBCykt&xnO6wcBV#Œ"66<(w|c%Dz;v-o}mY^{w O`u~љ2ʡC:&CT>#EP^G:,KЮ6%z|MQj1ĕs- U+_|Ҋ{BFi6DQa5[d6Awژvjc]tKn,YfZW򹑇6ކ4v&ЩIWhvD-_5omk9{|/a[Oӝ\w5ଅIRkugGOqkW7{xGjQ 4JjFu)OV`5hVNjv \ ZO訑co[+UM.UpҺvJCje492 }P8yW>˟ %ﬣkr6ߧf;yW]5'h^w':yѓ=eq-g-lR_ 'L\07ڹ_kO1|pTZx@W={IuS 1!>,HیxZy|Ӟ#|򹍗xhcM!SZG/:WX-đ̢lm\,= JS 4'?N֐!&.6Zmk\x%kg#~aT0T^X*W ,=yJ|V<>Rb]jqau8Ч6T(ݐ 6,>uQKy_2180E ΃G,q4Τl:Bky[w6#Nu:3\oGcAu5G|lWP3 VK Lv֠t(0j *ea-TfQyXBJg3`Mp BϿ#U֗<Lĕo'qVԅCӹރs\-:W\-hU :cej䡱Y특\x7L"9{s*_G-SM&Ï̤kknzi;rf4(89^}Nw Ḉn0o~)Ld8R.թyUQH5u**f*8ޘn#L]+A) ZC?GԷIoT=MJg{7Mq[97CQBY 0Z6^kJq#mu6[޷>`Q0(\_[R 5_G+42Йs϶0|XmZd}=YXc︍W./ܙY5"wm3s|/gEv/}E(ܘBT"* 5 a2xtHҎСxeR$Ea@RybS~O=;8p{Um1tc\M]NbYc T BxTQX1D&W },:\f@_ĐtC~g{(K~ 5wom&$bgvlou_/-M G;ű]Nwf!%NLc!ˋ|DyUGn 𝪦 !8Z4( ~5SY{q4s6> 1JR=1+O3bꀷOh{?Cap VL|LA]/)dE {-|3q^G=Yt(_q8t6ڮ^EZ\5q~ѥ«JL /*KTE-QE׎0 N T}68QƫrE8pa+l6YXF1(¦q&:ɩiUoƓSjqmZ!tXavThBkAF.m3 :짼x__W8A%<$@OCTcTxNPUґr֔@xG.^[Bfe=-b?JV4CQ]~Xl5g5-:P}`Up jG<4\x(/~/ߝqmmёIl lmڍn[y޸s߼ý8X#+eӜ>ٿ-Prh ,U⢙|d>⒄ ^vwr(P> {ZK J_.j;w&QsFתO*㐪Ƨ>J:3E:l] c%m [)\ eh{iW~m Lh5W^{>a7E]5N (Bײ'݆8uJlZvYhxBk}}]Qk'E9s{|OwOR0&N\Dk" 8~rxmdY/+;}9M '(?$ꑄuףnv +s\pa t+,?*:as*<EVp1|PDŽ̡(Ɣ<׎_t2OPT06a`Qip@o [2M/D¯!9W=UX͛#ˇc4 V+L9d,18Idiq@E,_iHdaBk՛l~֘O"Gk Nsy^],@F/+'xW.-.\aN+_ U97PyjR>#pk\cP}E]UIU=}rr|YT!dCi d覲bRxUl:X)%+C) JoYOxL' E S .VtI"œJ9=A<=ѵ9Z-L#6UNj>5iY2a2mk _>]Y?v}I~~Ǵ^&":sʛ=o[vksw?}}$D8>V`u2Yio^pvZ\+US`nnJ¬):܀sROA-'>WAp #yJc";taT+UR0й8a}x2+$Z&VqzdFUMR>LB+,!<裫Dru.#ė=k{R2;JߥnyYs iN4eh=Vλp#EsE?ZAd &V3[(B[sZ{ZM&v?9ţo 9xW.aD`ρExY~}wsHŅ?T5r0WO!^GG54BnnɵrȤb(9L'Cߏ RGU)-\=tI7-GY{\YR:Gt<K¢=Zw)AqUѵ "7%K.H*2)Q&d9>_\~.F'\֤I\WՏ RX*յjk v;NXTXmZY15c)x&T< A=j zv&ꛭ|675wngIPőQcTFb-Ti ϗƙe 95ӚljvƏ|)FאָV 3jY?P[<g-U:~rwJ\=^\A"*ŸM}(NB>-_UW?i_M*9[. %pXPQdb1 &?;|[i FXK|,%'* FCz[3DU0Lm3l L$ۆpA[ >؇0IfܫjYmX~t!DbޕŔib)kY'yhP6ۭܬ`Mc1.a ]J튧`ɥa[\uʛGk?#>fzz~>Q !$㩃>/P E#,^+Uk; Q/h^N?:W.%ǍyUtИ&l أȫ"[RRd~Ow9Q''ἌoEH:Q^jj}9BxV~768X6q0xwޕ|F[?H|_v,+#Xj"jDc:Cf1:DJϕAd3hW[~7=Jgb#\Igu~VtV:ZӜ>;C{N\Y%Vb_ G<3U"DGRiHWE < O8pA ռ IXdl1H-(@T}q5Tpӈ"V&a!F`2 IuUU|6LNmBV!Y1b89I%(+3ΌktA9W q$Q0UnG E2T4L) \f·6tgNZt}}zۃYek_}Wf/Z/Ra<:wl5:cq!3#4s妞ޥVO'@5\,sA$e ˅P*JvʪQ.TyWeb*hꔺ7 wU嗗M#V gXTgr;F>ܨoS[QT*DC-PÇ!>y+tT:xlU?GWr~ݔ #6T),8W֢,\CEVj>.˰;ão;+D wd4o0x ·r \FI;((Y|F="{ХF~Vl- IDATQ50&dEYVT#KϜ]? 8QO8љB .iqQ*=oU(1xe PzR(vi!>EnU6du|lvM'?XQ=_H ֺJB˻8hkEޮK S%Ziр >xB?k^W/S _U~3λ6|Ј}hl֚\q~o{,Yfpj7FzB&z}#$} ~xG\(tFs^^;p.r<^{BpOYvU>V, Tb=<W%9X>TxWۜ'W5pjYm0,Æ#դI,Vtd9HÙJIWJP) jlup|*}@M<ʄGzx b郏"{zb*l~нj:vjj.Xɽr,uc!D„. P{ԿTFϦ7Iv6{B'>8O"Cjb) ^5P]MlZdž[%Vj9bwXmV$D>DTq,c|rTd6)K1,X8MC=6*H. 72&+V=P~!ӼaM^6^)+ᮘ,)a6J5n F0pYP]exj]ϭ!v0|j"kC(J& \23UPר򪅢Dף N/<3OpO/; $%5sVwNH$8[,2וcU. R/Ssu!8=Gj#xoǭZh"OVՇ4Eo*9i }S)/1~kQ0BkTG f+7:."=-ٟyvW{lKRaMtb(0PdB)D!AU(4%eThxܭ //-zQ7_F~Q} }׊Ն=F(X{Z^5u]"&^1|UZުn1Uj)_yKg[Q# 5gPF\}izݣ,N7uQ+V ]vR[Qpy5T &1!JUeϢ/XG_켚Jh3MU?FCiMs>*hN^9S\3"%gW74fBUIvvEzVYj/ea.~`iz_upPP5ZU4:sx]tAgZ(+L-P*+ݬ0,22y!p~g}QZ>N<*Qc| El#zF0dU=yp?uēYOf֑\8Jq;U%'^PGmM+֧?@Ր")jNEcl8j/~OCIh?>18TABV3=KId(˅P]K8nΫX2UY" Csoup1e_O뼥PGF'q{EEiQςRطJДǎc\\ɛPPPvJ}RLڪNOp\[ErcUwTnVZQxŤpp14xT>*7 -]Ae(c>Ci xBؒ~ڋט;Ogū#~}F]|Wj̢x^\ȵIIiʥ A;s"<] XFab=VkLy e0|i/}qO_vhkCNq"i4;ަIREO˜"kqk76^}Յ֝C#|S.nB&z^{J` 'ɥ&PB_ JdE}H-tT*@P!| E=lL7%)|N UF񧿆8CwV߃8(frP[N R$#*iݠ mrkEURq!s˂ Y*ɧT A am/.$*Ro(Ǟ0}Ou~# S1z;UU(ľ3K2Oz68V}X¦s7 ћ}}_1ۿwuٖ꣰g3%X9w,ޛcߘgzo_gxy:aCH#̀xW:OU)韩?Bt)55{uQUA@1\.\˸C\~xffoUX0 !Nח% qPdZfP50v>^U(0RcA-ʧ*+remONtU}X*"e(fRgͣ8OUw{@,@\M(ɒ8x,KPcd<>ɑb[HLl'd[Hے,ȖF-Z(w7+xݭ7} 7A4n~_]M>j&ޅRcCNI+т1Д<~ٽ cW Bȴ):=Li+|>E@byWf՛߃ͯ=xt,@k1J{iU\YYɃ9P)M3"VQ LPƴ!OGx۟~ +U(&iS?~tE}1g)3/_:o\~Z5ukw_~ul:6ɂm׷t {<1ωsƔw0:]Xڽ[-3ȜI(/^y'blܥ|v.%6?k5Ђ SH/A!ޙݸNһ])Ⴗa*So$UJٵr7Τ,swX7ļWaͷEGkN]tKf';d=Ļe[A"&,8F[v4ƘR W.x]4oMc ,)ǝAkJVbnGF#g*(:?x'P HXIH)̔&Z QE:F saLWny/@Gdo%C\,X4B<Ȝڛ 3L;ө[g6(1b :(P-)â;KCU4aDFb揬H~;QƓw{Gu߬zabI[HLjt u fB:Q+Oժ{f8%K%N-Sჯy/N}֡=_蘗ؙ&| f}d+kUeVʴۏDzcQ+1nFAni̾c)~|ϯDfZuVf ~(-+R!QNѿr#Z+87trat`ol%`=AF{,T8_L+[)rt waT\g *L+ˡz YgZGGҶ=^.wǜha:ڝd+<yӪ^oE>i3 ޔ7Obg@:y̩K]7>ڹ!dI9Zj,XOU,U#nPU Go݃GR:@%@V:P  W*y3BܙwYGݬ&˲Ub %.zhzf';YcXf.*f_,==UiQP\8ֱc凰nTƈ[QȜFL"syժ,Au kNR͖x {oÒB?ݜfu =VoPmsI%UZR]QG{~+g>h%ރˬ8oh(4mr/k,4 l"l"ʕ% pL"X%jVeQJ9#j7!ˑ^awCd#D25d0>_<"e:zItBS/ be*`yn$82nF˄+9mZE-{~mJ:IobfT3Vy/c+_|V9uR(T"U4BJ ?\~M#|uC߬CVXZowdRǧ}UU/ChX%PV´Z^dvK~jJ>_?f >@{kj__ɮCh!ϧUX3yrޟ ,tmL̋}{]ESDR @|ZU;!(-g)ˋinF`V6=5?;uhnjGL̀,^yXR hub9:,EVșYJLKCG8x`iMtJ&hu4yeW.7u~T w q6%JߺVC",)_'eI`%:(}wO!Ani eM5ԫY0f)tZ[X|{כ +y9cOPdM1* իDɪG@2m@UjߖpH>lQ[6t`{?{W܁V0V*XiL1:ʦjJg r$g.N*a3{"\KT"^`ed+5ίHe ̄~jU0Vˎ"P:Ea+0) !% K@kz=w3NoyLk^QkÆ'%*(1Q[BSJCBu.'[މ4#ߗ=GL؈ǓKUW% X&%Wh=wEGWMP%ʗ htI9%'ci $'}sPJV ;o~ZG]7ˤ^^U K+[s6ЩXSS"Ȱ~N2;,)󌁍*S8hU% GWzj]7l,\=}D/"FApu,˜UV ` vfƹT*N{VDo ʣ#;c0~t=|ß5N5ig2ɐ롅L|O/eFq4׬<fP 3TT14Ź_uopΕL'שׂ<1Z?jn˪W [c%h;SJ|˅ r6f*`ҷLMYBT|r26l~XځWYzhe QD)TL&>WQa%CۀB\Y2B{F)k9vxUwnQ_V~2U~;WR?߳<25Jvb9JuAm=/KIc?' m+ _IԪRɒC!q2`T0_vJ^vr0@%Zg=?Z3.s]q/G)x[;ZzZ5J S;sw_xsl7慇}~I.N-tf סIrg%8 & wy>Y–$\vO _וPpvT _#T28挖VB޼2w3N"o#\10|7'EW&R9 h.TщiJ/)6vF끅wYO;77C{""L0, M'}eFT"Tn[/{>+ƪW1[2+QRoimZs4(~&~ܔPYVue-IKכE\Y3(Q hUW;h?9ЊekU|b/&CXK IDAT-x|.&• πrxRl4D[b#X7 ]FKMk- 4~_N~[ͦBe!?h2M+ &bbki]t٦]k e] 5!?t}'8Si쥩HA+θi]b>^l !?GUJT SnbeIӆ3k&4%g .'n95\@Zf:n&W-tYu+q(ۏm$(eP,`tX01%^POE\o_@;hms׺0lmߧQ+`ᱦ 55H1z2-iS>Yڄ%$Ge-DLZ}=\=MwjS,K+i#VW*o+p ٽT+^us˖1Vzn;Є˥VdC+NKf >aIZu<k},sݭ/g {)靆CGBOo (7p.E '.bvs?t~&9: xLpZC%dp<rMU6Qt8g< ˈS_w w=|YF 4%.aʍs̕] =X,Bۡ- [v֚BJi_n,ˑ|d-TT}B6#Z/H?ʩޖSO{^뭔8 %voM-!ƙr%1c%HP"\*ٿe6>ܷ?| GifhuO4 9i6]_3B'뚈q>;r۠9Lf*5ܤh9c/#h]W1̑g/9_ ΛWV`9_iw<ִkny3Ȼ8dEFVhdvн۹~~瘐L)y:E&ТE lRRh6!ӝ?}rtfazu%v^iilXp4*jTr^!IM{BXY#o0n`SZȬ|DTX ǎq<(t!e'|rױl9K[Cn @Uy_E-ED8"B,3Uc5 ΐޖ.m:֪9K*v1.AVRD́V+W^hNq?nyPTR]w?#jp盒cj{7C\u+'`X;Tp륪O+ODBe-oR-.P*3\_ޤ:f!*:c K-Gek>fk^;LţL:YrmAkjf;1۾~y})\I~hz u) 'nnU/40tvP;߱}.&5 -u)\~X׋j~E ٫W ׾SZUn|A\{AQ:^r"lQ(e-PܐRnfX~҅ -|STV5A8ԅ[mu֩(ּ_-3鋡'AD^U,TD%+() YY;+ 0)N!.WſכTڂq&&jԶ,]zxǭPU >lʫT̜.5Td*CU+ȅ&xc5jɝkкpM2c; \\>- SOKO 4+ iЧ*GǾa > Sg »Zz#>/UGTI$MTT7+w\kBަ̧BNte3󲅒 eB>[$L'POfpyLiȬo{?6CPS(;1 zzt/84|VdQ:? JĶ'<^g|AGqѪXӉtҎ*QU*gS:k>fn-:_u}ʲd G00sVYeު W"dK,zCm@}WUO:deR*V ZҵP/>]Y uiqJ'jʕXF?)B2W7^=M7FZg!p tJ>6;K{_͓ %| =^:방 Րv ~OKK r9l{Ȃ/^Uws6Hg'b@4-2裬Q/e-]61+[&%@_m`&Ѻ`ВL gj0'wԸ92C*栱i+K+ & gxhۯ.R; K_+2{>[|_؂~/U+iJ JXWwrJ5=TyJ[,k: 2R0% G8q4.J ?9Iv&*=%q/TzJ a&+3JGT@/VHzum*C҅ϰGe!\8,[ll:1)\[;ɶU@*xDK-G^vߟ.|2 Zf 9Ӫ=O./&E,•UX`BB* BqM@;Ctttr-եųL=7̚e;]ƼJx 'K `boreZ4 Z "RnF짤?zMX$MgCn8./oCg*$4+jD…v`0F7&&]߱(z J`01\g׷$MG !:pWQPwVɮq-nW& Uo4Sk63Z>)F%HΨF^-G|_QRP^i& r&_NT*`Uu\ȩV ׽Jf?!k<|R#]^Z 'IUX`̈́EQqFY~7Cׅ-1iq v>]}DLIZ <.ye ]3owۘ/ao5= p\xQ FbwT1ZIG:%CőwWF)PyHi|'vʻ?qfW#2 ovg6&XjE+&1a!`{Wwyٓ93s3y2/g W7: Ti>6؅ŀĨX5*0n+b4YY[RVoov{& 0zGRUZdXP鳴r0XDŲW]*I=y.0_[U a\ą1|uo\@͊?;շ\vp63{N3tsZz.ϯCk80EF^dc!{Ҹҡ}tmm*TWRoT)ϊXótl|9ow2[k(Z;o93yj?G0OGC,zYCWGO/-Xy5J|xGFJ`wTS !7ed)Խ+U V㶼"/ ?•[(G9S!ph;?>j&LN|q@/ u-U* )ol|꘯gŎ}DkI4Tg@CUuw3ZLAߓN*y*7=+9-=rB1OJY;U>i ++I=VaUl%rem#ox;"Piy:r _B`-x'/sFVYZu57k#Zz/5 ƈFI#5n?*S8NgZ VITS8yJcXkb43_|r)k.f즫nAr8fcOaf,USwn<EbKg6W4F 4UF֪G{?x׻f NuO lU?RΩ=nBeOZuJ9Mr$a~S޻ vnbrzȺM=&Kڝ2@Y침ÕA9*UtjtJq?f\Rp-_<\MۅCfy5˃{XdQ^?/pCV-O!)J?m}F TL}~P*X2?(*OB>w}j2- _ʉciNV7h)u>ҪS쬆)U|z) ky*T˔ѣT'#dA7¦SqЎ([?ԎiTZjr}3q®/oBo@vvt5z%ɶn71O`y9da2g&ݯ2nXsU<ؤ#V&^JHzw*&[ h0ZOW %u%n*w/{j!KJV!gΐeu|{n L2}AŻ*\ZZ)duiP!cKqÖv9ɾj*/h?S1 as*oe_b VULRҶrZY\oz9y;xWY8coDYlþguy'UXsn&T'?鑀; 0e$LZ%bpM:V͆oH/,%<3`ڑ㔇R~{vjuFW]{j;P[7&e>dA>>F|dEx_h*?/ShP]p6&4$D]= ]q&9+&85V`K|g $AT JV⇥=XRv$%5eIΤhaნzfQ̝.zWpj4 ր#Lʨ`"Z#dATjs#R&`EfW*OIn\U<.#]I9uWo:9~ځVXVb*SUʌòțKW]3!Fiei%ua+(TyZyZuYv{iYokon9LN!ŎJ:tt>S #UD <T(XPUEFj,+[-ʙ1OW6>/GZy9rNWvq[u%TMvځufΚǞ|o7OתJޘ+8 %D * `vMI]?Y $ox w~؎՗v`ǟzƷjf:eKeUXIQZ-hWD"\ ղkC&~[bckXF812neMx2h@ `Zd>^QS9~cuqy\{+7; ֈ UUB)qSV-_הM"Z@T7~ߔXsU^aHU/'hRRX<`-;:Zd9 ~~zi!.17A\oĔ-S3ʛ4AQ S_j(]"SA[ _/PӺ<}~ojj%D| 7_X׫3t}1wc?:%ٖ2g,tlS寮fIҳtwK6liW6/b j[ǥs$ZjUԫZITpnk`Uja<ANn=+ؖX_ Lqr! [dv{OM\3Iv.W0ut"fW]3ss|7}u>8D0iBgN[~ |rV)paU +d ?㇘m<9{N yAW鍘 hU(@V4W u WM#W$X:k:Z}E{Ӛ9ћDWI~ulNg۵t.%Ql==.e98'f ;;\)TSr=v|!6\O>tʟqSfI7&\j:M`]~(A+ˢn1&H+YEҮs_=‘z W힅DZ, .qh&aAVzK+D `YKo IDAT5%Ntwt$e@wq>#w- M YuX"ʱWa˷ufTU0T]Œ ()J0pVJȬ>L~M^f_2f D5zWĜ_yi_ i  ARL\s9o'|C}{eT)15tDXRC飼zndՀM >X>idŋXʌ=jRj"O 'MU7: bX}. %z#z.k ZJ~u)?01sO WjlETb5CsZVzLwz}OAQ)?ezB8jܾ_+Ī)X#A460rl~ 3# Wbw_ï:ͅ 3]hrkcNOӪŖY,59]sȪ1B' ׾lN#XE4V$QʝM#ʄvЪd*`sF_$iE~~?F7yэk MM6[mnP}1vN=7Bm |3f5 bnLab~kg`/BWTN /TrEaMJ%wy?6iYr?pg-5~VjW``#Lt(5fg24s2 !/]ClqF<F)[V"<3Xk̩ߟ ZID ݋ a~) wo4rVpa! P9b&I˧?ײ)mkhQKSz@+r҉N:nrV%` J̈́>szw|bW朗2&6FQ8|DWh  Ωt`MԚ+JXcM -7L̅[)̛oERS=_[Vҝ˕}PPh3ǚ#:dfNwjf:m]|v}> QPb?SiZdD}C\ {MP [hir X_,J%to[P pի|ƩXCȤFIij^ƵrUwnHjBlJ37.<W*{S :ѝC3ʨu3DM4:Y!a+:5±X1b*$HVU*fBqz&|Xh듵oÔz-s__赟kJB0 N$E=3ȪWN/X%a+A^Jʙ5;6vZv{k)@U VajCXDx6a#sΧ2*%κU/GRC!F;tMY yմ(ڐo]A7rf>뙗m6NWLSjz-ٟ46gȀo}UѴmZ6ظj2[\߷e^t=/nɈ0ߥȡaȯ sxqb4ꂙЃVg ;BZ,/3b|V-{nwMtlLE$ u S_ZP++*5 \90o's%ɫT̈́=X- 2 Zs_f> .=K_F省VRՄ*8`-?J{$\WP^ aIaMU5gsx}pEnU mdRȪ z-Q-| `c!2fyF|W,EbㅻJ` 4oSJ~bȒ%'GSlO@1/[KmtL_1/[g+Ǹ,1af&dr YPцy'~+T͂ (4"imCq9pg*ۛ5LChŏ px_/_^b=^E35+Aq?޲&}VV%`9`K#bt(dҥ{_#5_ӇQ5$>#*=Ei%%tn[*XUTOU XIu7L m0Ea8r+)|½?wͅ&Ej#::hI|^/DR'\Q3t#l@(i3/K-t8Lv Dz6!&=L bk-u}R WM V_` P)~.8߽CP̭񜀕N^=\Jlx-{>SÑ'w\N*_ -Va*+:7ǦkJ)>dՁv-je#5`UM2Vb \>v45u '~+;?H~;7tw^ +]A*\`i)d;J tԸQ_"5rm0rxkL'=p@W@1Ĕ0ZKN53+ .u-'v?H~۟.0QɪwBE 07!XĉV-WBƀ5jkl =f,ӕ8ۘ) n6}kOgXfh,h)1Hq7p⑇8Z?bRIVǍGMqx%Dm]MR`PilW'hqiMyҗt}]E'/ⒷP{o>y)ȡc?PKHu5W"X(7*RJ'17j{% VpǻsPpϽCK9Fg(d鏟\Տ+v}] TuO6cUU9 (˒#}܋9/>3B~eY2v"BDvc"%l5^Ҁ.,w 9}}S6 ?Æ_03.]o^wu.ac|ZrZu}4nah }}gW7 )RV13f־3rJ'ck}"5f%z~mKApH 2lujl% -+"h5u Q׏:F@%.(T~ !iQZ~{c#̫+-nHy;[l r-o E`؍ه<wߊkA X߻3 (*_fTE9PM0 VYD%K߅;ޛsǗYnϿFH䬤Q\,8*(Z>Vvpe ղu)87yK2`zM U["?V2&YD &뽢J5 ?d5Q[V*g.x* 6̡Wfe;V%`T O,9JUJ+y#œ@8'fSZaEs 40V`< џvK9rf5>C0Qgp=[4>IM !7KMu f Wvu<g5R@afSޮ.rYQ%)@tO> _w# f. u;P6o슅rzw򭇑=0{ J+ᾛ>Ǻ)븞~B 7AVLzПw =[v mKq1xr°%-2-1Ȃڂ{쥌*:(3 _ҪGZ<|{;ιq5"~hA+^.OVs-cs 9hheMCV sC]KZ8M PpӴi/2m'%&̞(jISE+U/b*155U8BB`MFC!DH\HYܢz;IJ>/~$_jzX;9]rU}BG@nW߻KP#TM@5M dAURxz -br \{ h^-%!F[qRT.j0+A-x62itlFo6āO|bTJͅ|K}U4(ݭU\很-[k\> ߤˬos6t˜ }VV-` Lt&h4PJ$ VuxȒWVOB) !ƫW+ش 2XR`R-~ 6]H7ɋ=C?Ha&Z[h¸~7yj WjzQKE,l47N& 4lUy:Q[x_qfnx`w[_ƪ^ז΃Vܢ;\Z5?7`z}d #\q/8Ȉ9#`Gc#վfUĮ*DTUoJ  K-h"QapG5RE);#OC I8 QnLh_PeHч,@ӧiڛ.JdW:d~G֩VfȲ μ ۥJZ>!lAK;ں)~ |gnd>^ BA໖1)˫@UϬ|lՇx͆Do\eLjZnj\a$*5Z\J Pv´ZoLg|\!%˙:VA (k~Uq$Lol|M:`"o7wl\=ꀭ =]ZRƅo],?צ(T BfTګUFy I޻.O(>WQ6j8ѽb##̙7]zށ<~2@6*U26YQ̈́E{11ߨV\g${Y,]J)-P;/A߰+&L^ӛ<ᾯݨCVR.>Wm@+ӣpL?c?$~}Y%NPבeВ@۵ <m Vv+5qz㷜}4XSؑN̂TPJTj*,BTV}TyڷSI  p5 ,R3X-5 eWVz>?pei%{[ZT!˭zާ!i8AQ9 {D*cfgCT1Q?QUr1#48L@B_ueVAA>0P5F*ݚ(5@>WMդ`)9?dŋZwU.*CQ#ɵLm;D{.Z[v'!r؍9 afwTj|,܁VAO*(h.Dg[Y۹g KZ;CO) 돕E;ذeJ2Z\ CP&>Td:L͂u_,.Ҟ$캪*`+TV=T3uq߁ AUSg[ Fad7$;'Z^^[FHVVӀ@$ҌG#4HV䑄X‡OeөYTYH JPĺplETpo{k@ Cz+>Z5A \ `Z~H\fZM j*- {ٚ|HU?/H*z-c |)YHgKD-Ah܋S}ՎTW1ܶ,}3E5CL<3)ܠd#Sܔc.M~}LQqt"%EͷҭWt&|5`,߯h>KyMrdLˀ^u~D. DTTB U4un:'?yU eLNw$7}wO4kx&ea>|!Yxb XˋQyana5%r=lxY{R M r栞ڔ1k\/4öUU !t ٿHfybA꣒#F U ?m9h6e`,WbL-RQY•WDؽEo(VK9\fZ/'ӝ;ԑߣ8dr~~;^p`y+:X}&)3嗘ч#LQ Ee$ *HSEiA٥=>T }Vz ;[qj(Y`K/"ė233oyޛMT$EW>@VhScVZKU _Gq|ɜl⬜u\j%Z/TJ%k0` Tze"c5{-,MW.N0%;zeI U01!>(P5_ MTG)7*M4 rɂf+ [+ʜm*dB SՀC !pX }~g\HV~LN̗[O9T6ixUq<ٺr2ygSX8WПԍ,O@f\jq&'4JJ2rݐש!ǿp5$N &3L fvhB]J ]Y!.4YuC~:,,$%3 8ㄷ k2qWqɬTr?ΰw%Sqc?Għr'8gaU*lzu ?;hExKֆ X̄nAp˴P8YDcȂ &kcvMl,#fB%•ϕcpQ4z05*cS:vwዊ"V~ϋ bEU+󄨪 _a^T6FLa,XO;yְq U|k`&˶U<ͩ")W krr2(JUVޫX:M哥U JIA j|5p)B6;"=Wӟ~Yv0`7͜,eRfh.c%W4/|=7ztIziqgțX QrsDeXCHS|v>g}6fe+M%KU^\XRQC:PѨrWY9x_"1}+k@P'yӇ~5 w_٠% WO4`CO[/`i Nn nL7L+iOElԊ`˦ɱ#.f+ūK5}ߣ*݀HEY2Z( &ª,C—URm$774M. Z @i9#W%*Th`,5NS|[`G +ovuEHDs6Oi8@;Tj rZh/.]1{{vہN!t 1P EBؗX=Lt7ZR+rU;Wy=LRٷe.:+hPJSSDq 3a}vpOL_!H*UU*Qo4 Z!˶~Wx6.h*j鞻XX%<}7 z ;VdYLDBcա,xrU٩B%XV婂3E0yϓ/7,cHqg_Cw=u>V#H5n3[ca,Qh7b$.mSɪU !!TY^Q(&'4B=)sv{yVU+Y0h61{{$s_NS%ESXYf/3,Xpqw(t_2<0g/4jyHpeS,h0ʟۑXu\|Rצdu\dpv>^PBYkBd3~j~oyf|bYs}K&8-XO=tggQa^_t;A30*OqǍ-e /Eqxk)$9VKrQ:Bc6 z N"Cj+ 5蘽[ ޅn̓`fxK_#)%V+DJw{bN-8#&d8i)Y*'Uc& m߳#S}dz]')ۨʩ.667kIJ>XM3*.r 6V>*Zb銂>8<<,Y:\˲J1{-svx;apq3O):!iTLՎz}DX@eeי mtǿ `E;`~h5*jde*܅#I6 p{wx7cimQl0LN^?1_PyOX`&h[K,H)Rp1hke%Tm4!+u~˟ Y,KVj6J$T̕:*u򛨤9UK10ƒJ3+R*7`@{9(M'A+ K1+U*O˓I&v~ @/w2_4'NPvVZ]IcTyi2`z q/lkQ7A VZ/+ (Xb%Za/3y%,۹}pKv6WF;=f8 W a=uHf?q!s

    X!7X>6 *>ҳ->Fo(8>y>vYSH>s>vۜ|>bK>G!~>$>T:Y>+>ۭl>">>w>Z[>z>vB6>szǙ>1 խ9>x}i>p5>4p?(JI۪?\6=?#I!db?0qPOR?;,!cnD?F#ew?R?^q9?g"?q#xY?xU??C &?=-Z??E?#ZV?>'^X?ZM?Gm?6fZ?Zm?ߘ7?j {?ˢdJ?>J?,9?v?/~TϘ?j< ?,??1$C?,0?B3 ;W?" x?z?BV??W??8HN?3 C?7F ?t?Q>!TQZQ@> X>֮UQ>1`>ϿEP`>5uY>%>7S>>@cX>pZ>`QhQ>g)sh>T> y?>IW'>2^q>Ё>egF6>(僅>Kn6t>WOd>Ц!:C>B?&>f>ڎ?]˱GE?y2"?!he,?-il?8C3<?Cc+l?Pi cw?Z 2=^?cmy?b}?N+t?|^݆?w&?Eu?՛9(?z?|"%7?w>D2?vãT?xCIt?~Z ?o$~+X?:Ty?$F=?W3?}H?45h?4 ?so^S[?d:?V%?FnP?6|q0?'qz#?JKP?%[>j>0 ->l%){(>kt>|>BVF>R<Ǿ>ƣ|> $>8H> #ɢ>@$&>r&RY>Vesd>Jr>)M<>QD>tV3>4>>_0>1!>r0->H~%>Tu$j>lN? @&?SA?#H/?)qW"?4¿?@SH ?K 8?U-F8 ?_t H?f` s?o+?uA͓?|MSW?h2)?Ǭ?Gg?Sv\?Mf7?TW?¹?-Er?ESy???t?'C?'."{?،f(?WU?p{?3r?aL[?ȶ"2?|n:G?}^:Z?zba?{9I\E?\"Ik?V2 ?G9}?Zg?Ʌ`9"?y?W)?~CB?"?5?=P)?Bs$?ˈ#?uX/6?ҡ\A?nX?Zw?D?|רo?u _?rVz?rRwX?uAl9?|-?Uӕ]?f3?<$?s??3@oG?X?âd?I8a?2`_,?S?0:%??ݒ?踠O?zu+?l67?]4 *?MR ?=r8H?.J`p ?&ա? ךV>C>ވtg9>/>4;x>˿ɚf@>E>,Q>>]yJ>0YP0>d7n>YSm>-ܦ>þGPK>#N>*b q>MX*0>i#R>b>{>\E>Y6FN>_k.>r >q>g&? 5??\kr?% O`?12;&Gl>(>{\Ac>~$>Zz\>er>ڲ>pv>}1bDs>?q>W)N>s >Ďp>zG> 5Rʹ>W)@{>ag$>wøk>#ؕ,>|*h>gh{>qR>v>f >PR>ʚc>L\?oB?>x? >C?+ Ω ?60SC?APC~?J%?ScK?]cd?eEJ?ms[?sE`?y-. ?1 0?$(?cU?*n/?4ť?Z&,P?n?Itt?r+?X#p?""? A??b[?-.?[?BpK[?߫A%?(鲟??{rZ?tN@?qt ?r?wl7?^9?Kh?O?qä!6?qYp?tFL?zoR۹?UVm?x"?i9[_?u^{b_?#;?ĺ6b?Ȧ?-;>z?dϲF?i6e.? T?x[<?[?RڡL?/^ꬶ?t.?e&V?TA?D?5&f?&;V?!w$?]`>0%6R>uQx>Wb->]0 >ǧ18 >9(>|i>@r>QCr}9 >~'oy>1>R`[>_Z>ӭf>r֮gp>Nn>C/>#ǩ=F{>44]͐>$6j>ݍ >At`>šAt>\ː>ꔪ[]>YvH ? g? q\OX?=M?%F?1>1?<,?EJ0?P¾#?Ye.?cd!~?lH ׃?ta}X#?{[oJ? p?zl-??XL?K?tE:?&?n}?I1?!k?jN?9޹{?}P2?w{X2?vԎN?w=1?{$ u!?l<?,j?u?|"69?Œ%?V.sN?IF}m @?0%*U?N ?=8?>[a~?5 ?vq"? ?k?[L z?vj?gA?VٚGWm?F״Hx?8MEXI?*`rP?]ֲKl? ;ly{>>ܞX>1Fc>( 5">|2>~BL>^R><>Y]{>VRC >Z->aM>pGڍ>T>P*`>!&>R'( >aHu>oο\E>v!>w>I]>,<>װ§>xKX>B77>>[(?G< %?f? ̟t?,S"JU`?7;?B ś0?Ma<ۨ?X 4?c{")?n?wo?]¦?,O?GfXZ?ʐl?)cY?;j'?ИΑ? ^?7??HT?Ob?1rg?}?kV"9?|DYZ?U.Ex?XV5?Ƶ7_N??|@! ?wt?wH/w=?z42?^%?mҳ>?V??IXj?讹L?"c? ?wz>f?J*?O[Bf?~2ZR?Afq? ?=ܢP??8Z?z,?En?} a?|V;?}/]m?1l?o=oX?4j[B?!?YO?? "??۩p/?e!?qmt?zA:??@`?$?0,4 ?|b8?}*ɳ?;zi)?u%b?gh%EB?Wp:z?Hj$?:p•?-Mz?+j ?\w?xUT>#;>Ɯk>ޚ(r*>i貆>%$q>1> s>n;>:ю>W<\>2~>JQam>ء~>Cg>*K6>}rEa>rtJ9?>+>I[>EO>>.Lv>;_>&>ߍϭ>ec>?^[Dx?04?JE=?'?Y?3'̢?@z?K6.\t?Wv=ׄ?d;H ?qp?|G"E?F?Zr~/?彆ȧ?4??Kx(ɛ??Pφ?$?4? AMwF*?_?\Hw?l-r?^}?3r?9iM?Zd?_Tk?nq6?< ?܍{0?|^u/?|'@W?G\:kf?פy?9%c?O7/?oꊳ?[?ael?H??߻W~E?C׫r-P?Bi?D^K?Kʿx?(?מt?3?e<~f?<]PY ?}9?rR<?dme?VP(?Hu F?6,>b>g>.Sz\(>.pm>OoQ>H>BH > Y>+L>4 >1v0l>R>1u>4 >+Myr> F>BJ>I>Oڜ>.pm><:>.SzB>NK>b׾N>6?-N?P) ?!@l?0c*?r?o77o?NX?qF6?bH?ƪ%hUWF>񼝇>ޚ7r>ќ`> y>m>͟I>qު>Qt?>X>H2^>1>i"o>_&D>=/>=>k5Yʊ>7cp>]l>Xn*>W|t>@0+(>ЦHT׺>>lRv>X:?Ím'C?_ͼD?F?-;'?92Z8?GSpe?V?f)0*?tNѧl??d6?$~Zd?PH?#$TI?}#?e*??NGXH?Sfi?:̔8z?=?KPz'?Fշ?+t?mի'?Qx?pKdPY?{Lo4?y:µ?zS=?+ Q?;z_?T?J&!?cc?gU:?а?f4 0$?,X;?]1?@?)?ᴒ?-5?TR~?][!?u`CH9?u]?yE0C?8?pxܻ?C1F?@L??|#?_z?i-x?x2H?}b?L?tώ?<2]?LЯ?tIB5?eJ&?^N?Gsk??.j?A ?~]`Өx?u/A2~?kf?a[Z?UcXx:f?J(?AnA?65. :?* ak?nS?b0?.YE>ln.>I;%>Mz>Nf" >b{f>¦M>0Rq>O.+7>[)1>->>Aub!&>|> 8E>_]B˗>>$kǴ>Z:y>s'FJ>53`>KH>-Va~>mv^:>hԽΛ>s"X>fע>3&8? 4}],??)z?7m[?F9#?U.`t[?N>H? ?b,~?gaZ?h\~+M?[Rm?G`?c9R?A{Uk?eP?)?}p#?yo ?q?"x@?xAH?rí?q(>?sNn?x$Kh?OU?HĖ?,/?1ա?̎z?J} 6>^Fj>݅>йϜ> ;>x ">@r36F>ny/>`TP>H'7>5+$+>@>zb&,>,2#F>e5>N>eO>zð>M'zW>chQ >pB:>nnÌ>*^}ѽ`>+B>쏌!>]u (`?bf?l?&N?5zplC?DG ?TJa?dxE?t?g ^?Eo?&)?ށ>??CJe?;_?`?CR+?s%I??ӷ?Z??lǽQ??z?s]6g?pc ?p9|Y?s-L?z?{jf?c ??ˈ?qKeH?d|s?m?7!?UǕ??,4?H]ݓ?-?@R?b6?5I^??w?Y ??q&F?pF7?r鳚?yoZ?xb>2?*?'<^>?~?e6B_r?2i~?mN?#&ld?eud?ۑ?R?f,J%?F̓T?J/@??jJu?)3?C?|)Y?vL?qdY\?iTx{?am^?Y>L?Q"?GVV??>?4զSp?* ,&Zx>=>nF[>ԗb> >Q>1>)QD, >&n*0> > T!3>IlEs>rvK8n>1ROBY>E燝>>儱>O>>{f>U{j>J^>ŗ0>{8>ͅW}80>ڿH 0>^&<>P? K%?S[8?#HG?2^?AP?Q> ?aLcA?qriP|? ̪?z7,?!6?GiO?<[weA?(17?׊?K ?Rk|?y?GT ?Ki)?tk?Xۑ?X'$?xbmm?q۾#?m>e r?mR?rI)83?zv-sa?@ ?~8bO?*/p(?_1H?IT?4?[?y'w?W>%?x&(?T؜ ?7p?ӬY ?$UB?>?% ?|Z|[?u( %:?r۶O?tGJ?ygSq??? Y?!+7j?xQ?:j?d]d?6=u*?:K?<e.>~[UT> >]RD>9>2>_he>z0(>t>윗@>ȓ>t6d>>[VG>umt]\>8Beo>d[>?9>B9PD> >2> T0>Ӎ4>̲> [Ġ>!$=@>_.£>}8>z? %&?_Q0?._^{#P?=Ml?M= ?lB?zwIX?b J?haB?I ?c ?)]0?-~?,ks?G#j?>EZ/?3`@?(6G?,4A??G[>_ > 9ͦ=^>~r>̮c>>q[{C>^j>xp>TIX>uBq.>N5+>5G4>se1X>e>rk>{TF>o>zv)0d>y_,Q>G<>A>>ӀJk>X4lW> p0>W;0?~?BL?'es?6/?F0r?Ve ?e3WHr?sP!IK?ؾ?Lie?%%? ?=wd?8ގ?{ yu?/? !2=?*bj_~? 41?@?,0r?10x~?R]?}'>>?w~8$?tvRލ?tH[(?y*Ԏ?ب?M >?xq{?ll?_=`>?o!;T?B2c?r? T=?ߓ(?#x{?ff/?,p( ?[$?h:?a{8Y[?Vi;b?L}?Aұ>>?6z%kJ?,/ۍYu?? ̈f?é{ ?1B@> gj>쥎ԓ>j>ϋ'F>[q>o%> i>s;f5X>* >vR>R|{>x">\ >فt>$>Ί )>CE>גj>vKe >'bU >LxR>GP`>ы>p&X> `>~?.?z`?!Jw?0\l?@r-?P-?^4F,?kL!l ?xP?RHaҜj?R4r"?R7,?qN]?F?>?G?Xt?.x7)?N4d?|ѼJ?uQ~?% P?ņߚ?^W]?΍?{ _?w[?xYoS+?|3G?n?|LA?L8a?F?E?7~Y?-O?, M?zOb?A9?f?{?l['??b=?'>+?)t#,?'N?`)D? /?|}XK?~Ch?؟W?+ ?zh?ZZ?X,?0?i~Zd?XYz?YjQL?Th?-_q?!_?r%ae?P$Sȋ?ʺݧ?MJ?Ö?#?{h?/gM?uԀ5X?na?dRQj ?ZX<f?P>ǭ?D6 @K?9+S?/88LN?"UQy?|?Cf >Jĥ>[|->q;>jM>Ms&8> F*>&U>Q=R>4$@Y>n"4m>Kg_W>4CZ)> 1G>? XlF>ʯ)d>d3JW>T>#iNt>IZ>>1>Ɓ>>@>>s'>TD?N`?38?("?(Q=?6Eo?EߩH?T:l?b6Rٟ?o}`\7?{o~*v?‘+~?yt?u*?Wø? ␢?^7 :?ik?gF2K?=Z"?|הD?xD9T=J?xP=Q?{6x>?3VS?l>&?֩2?9 K|?Ug? b? N?M׷(, >Aڛt>> >뗱ς>9 2>2>NJ4n>ߧ>eNm>!P}{>;M_>>+>ݪB3>{> H_>"(>35>5? >Øh>rz# > +Ō>yr>9Cx>}|nv?~x? 5Ia@?X>?#Pm?l*C6?IW?7?@7f?:[<*?lV)?{;c5?uT ?sM z ?uNa?{A?<$fJ?`|??)? d? ?cXB}?8<"?ZLh ?CIY?,$?y]l?˅?nJ?d9?j6?1`?:*rKM?zk>?qջ?g]D?]o3k?R+5?EsҐ?:Id ?0M;%;?# t>Y? f?B1"z>p%#>8uټ>uM>(,>D!Z:>zVS>POj͸>0UN >+2@>#C{(>QE> h>)&1o>&1e>i~U>&>֠>Xr> i8>PH>e؝K>ӵW\_> > >?<>es)(?ރ?\P?M7\H?"S6{?-BqWh?7ԁH?C#yB(j?PAM?\'f?h n?t.?&(?[?m>f?FLP&?2I?imx3?3Z[?E?ն?&V?W=?mg?RP?̳}1C?̻?]7?qh?y %?s0C?p\/O?pk?t/Q2?{H\n?cslc?7P?hT?D~2P?8-; ?.s?!N?UO*?lQ>b=`Y>R>P\;(u>wDf>w R>'G->+t>u">8ɾ>E*i>?>1O ɿ>i>?eg>c>r>~E>\X>c>M> p>HZnH>/7<>MD>LQYB?3? Z;UZ?2㨿?*(?'!6&4?0vvP?7ۑc]j?A!A%?Lr # ?W<c/?dF66݄?q˭j ?}kP7?D!͘e?)qkն?F'T?٦I?1|%?Ѳ ?ڣ8?. =?n?ia/ ?C?HP?v#?> }k >,>{Av>κl>KfA4u>pEH>&Su>DZ> ؊>&4>t݂{>DU0>}>Zu$ >tYO>Dc>2 >}t>>r6z>ˮvo>רUp>ݩU>;),8>}X?>~0y? +e? z?Sp?&?0Fqvd?68O?>L?F0@0f?Pв[t?Z'?ڰ2?f?Q9?֛n_?2 ?+C?Cf&?ʅ?5 Je?yX"?8KȰ?|_?ݐE?4JY??zV ?qY.렪A?fmT?\0?RPD@^?G\ՋC'?=|Q?2m7?'?? 8w>;!>NC>tgZo>f)>}ȼ`>:lJ>^w>#L>R>f>uD ><pm>ބ,>;t>x$>r hL>c d>ڞ܄jL>EXd>Ƈp >׽"iI>࢏R >hcė">8>kxT? oK~?켎?>?''KF?1g?8\Y7i?@O}?F ?Pӄ?YHŘ?c2-X ?n[%t?xʡi? W)?eS?2O\B?aY? ?كѨ?e`?+_Kp? 7gN?`9?)@?}/?ܓF2]?7+O?rFh:? M-?yX gL?to?rWޢ?s'f?xFYV?`? W?ɞl??f ?i?~kS?M).?i=?+n;m?f@?-?ZH?z ?NU!?{?̉ ?~?xv?vՄ(k?wk?|B J ^?kF?{2/??I[?S8?dع?iZ]??)?p2V?` ?;~? R ^?Gr:?i? '?D曒z?{Ő?r_S*?h=oZ)?_cw?Td]?Je?AǛk|`?7Rac?-z=K?" HL?n?ՈJ>>a9>y I>옲>Fb() >ȷ&>>/16>8q>>L&O̐>yRa>1>gu>5>;ZJe>cr>^l>]>ݜ#>2G>٫Mn>D o}>i}\>O&M?&} ?1I?f$?'Ӹ$?2&2?: \J?Bw?Iy.oF?RXҚB?\ w<`?da~?ob^K?xcd?Sn9?]4?o?ȓMr?jBQ?G:ε?a? Zq!?Du?*g?ȱ? ?! T?<2?) ;?Y`?~0r%?xk?v~?xAbC'?}2?M h7?n_~x)?Qij9?k?Z4?оwH?E?Xc?Py.h?oWc?0X?Ϛ?XB?$ K? 1h} ?44?^ Ӂ?zeOX?xoȻY?z#[?d&?'FM7U?{v^DC?*??eQiB?Bn ?6PF@?VQ ?@?γz?_Pw?Wf?mB?y|D??|-?WKF?z͋Sg?q|Ys{?g`=]?^Mk?TRrK?Kx 7N+?B2+?9$]?1);2T?%-? ?Ɯs?>*m ">޿3>K7>яԁ> *>.,i >Ç/>>W->>Q^>[ېI>Q^ޞ>>W>(>Ç/+>.,i> *4N>яԁ>Kϻd>޿3x>*m "|?~?Ɯs?Z?%-Q?1);2T?9$]?B2+?Kx 7N, ?TRro?^Mk?g`=]?q|Ys{?z͋S\?WKF?|0??y|F?mB?Wf?_Pw?γx?@?VQ?6PF??Bn?eQi?<2?! T? ?ȳ?*g?Du? Zq!?a?G:β?jBQ?ȓMr?k?]4?Sn9?xc]?ob^L ?da~?\ w<`?RXҚH?Iy.o?BM?: \J?2&~?'ӸJ?f$?1?&}!J>O&>i>D z>٫Mn>2G>ݜ>k#>^l>cpv>;ZI>5ݦ>gv>1S>yRaU>L&PT>^>8qdQ>/1>JJ>ȷ;E>Fb(>옲>y >V:?ՈJ>L?3?" HM?-z=Kp?7Ray?AǛk|X?Je?Td|?_cw?h=oZ)?r_S*?{Ő?D曒z? '?i?Gr;? R _?;~?` ?p2V?)??iZ]?dع?S7??IS?{2-?kF?|B J ^?wk?vՄ(k?xv?~ξ?̉?{?NU!?z ?ZI?-?f@?+n;m?i=?LXl-?~kS?i??f ?ɞh? W?`?xFYV?s'f?rWޞ?ty?yX gM? M-?rFh:?7+O?ܓF2a?}1?)@?`8? 7gN?+_Kp?e`?كѨ? ?aY?2O\B?eS? W)?xʡi?n[%?c2-X0?YHŘ?Pl?F 8?@O}?8\Y7i?1g?''K??켍? oKn>k{B>8>hcė9c>࢏RJ>׽"i>Ƈp>EX8Y>ڞ܄ >c c`3>r g>xy>;>ބ?F><q7>ul>f >Sc>R&>^wN>:m>}ȼr>f)>>tgT>N>;!? 8q??'ޘ?2mb?=|Q?G\ՋC2?RPD@^?\09?fm`?qY.렪B?zV ??4JW?ݐE?|_?8Kȳ?yX"?5 Jb?ʅ?Cf%?+C?2 ?֛n_?Q9?f?ڰ'?H>'?xɬwq?t?E?rP'?tS2.?y1/?E o?!8)?, ?Ǫ^o?|?@rîc?Fi-X7?O+?5`C?H)`Y9?~ƩW?sΔY?K"?1E?rG*?:&H?xJ/c0?qʦ2?neoa?nEMܠ?r&`?z&:?a?r??߂?h?'?֮N?B^??x?2?H}]?N09P?Xΰj?Q$#?B%D?YY?r6(?fw?ZLt?68O?0Fqvd?&?SpB? ? +?>~0y>}D>;)=>ݩ>רUpb>ˮY>r6>}t>9>2ؼ>DchZ>tYO >Zt߲>}ی>DWA>t݃ >&4> >V2>&S{>pEhJ>KfA5&*>κl>{->,>}k?5H?ry?^?+g`Jr?6+6wV0V?A"i?MXUd?WU2dL?bx ?l1?vS;2b?? YPZ? kbv?vA?a˕?I ?N6B??Sڛ?n.?'h?a2<9?}$bD?HI??_VL0?|95-?{C?s\?pl?p2*.?sMW?zoB?@;d? 5?1?R?|?aF? X?*\?@?hZY?5Jz?mG?Uςu?`?A`8?Dq?.N9?v?pcxG?l~`?m ?rl^?z%?)jl ?> LQYN>MDZ>/7L">HZ~> >~>c@>\=>}>>N>?e>i/>1O C>@>E)|>8ɽO>u>+u>'G>w >wE>P\;!Y>R~>b=a?lQ?UO*?!?.sw?8-;"?D~2K?PY>hT?[dt?eD1?pj6A ?ywz?{8@?Qy?c;?R)o@?YX!^?\?4Eu?T'?}!q?^T?}Pb?x^pʲ,?64.?wɢO? ?p/N?|[[O?ti$?po?pwm?sB9?{-RI?vXF9?5iQ?,O@?^T?@A'?Ô? -q?{|?n6 ?pJ ?Uo ?sk&?\Sr?e?&(?[?t"?h n?\'f?PAM?C#yB($?7ԁl?-BqV?"S6z?M7\H?\N?ނ >es)>?4> > |>ӵW\jH>e؝Z>PH]> ip>X>֠>&F>i~>&1 n>)&1> XL>Qp>#C{f>*>0UNힳ>POj#|>zV*>D!Zz@>(@>u>8uټy>p'?B1? f?# t>Y?0M;%;l?:Id7?Esқ?R+4?]o3k?g]D?qջ?zk>?:*rKL?1`?j6?d9?nJ?˅?y]n?,$?CIY?ZLh ?8< ?cXB|? ? e?)?`|>?<$fI?{A?uNa?sM z)?uT ?{;c/?lV)?:[<'?@7f?7?IV?l*C5?f>?z;?G6? ?'dA1?j}N%?gK'Ҏ? m ?)?5?Nm?~i暺?w3y??t: ?ug?x- ?hOa}??:VO?v? ?<? 5Ia?~>}|nu>9C>yr> +>rz<>Øh>5> >35h>"> GR>{J>ݪ@'S>+$V>28>;M>!P ->eNl>R>NJ%>2R>9 >뗱> >>Aڛi>>׷(-Z?' x??P4y?׿[?A9?M<`? M? b?Ug?9 K?֩6?l>&?3VS ?{6x??xP=Y?xD9T=R?|הD?=Z?gF2F?ik?^7 :? ␢?Wø?u*?yt?‘+~?r>v?F+?,?!D4'?QQ?% ?ɔ G ?{o~*TD>s.>8> >Ɓ>>1>|>>#h>T>d3>ʯ7H>? W> 15>4CΖ>Kg0>n"u >4$@RJ>QWv>&Vc(> >Ms'<>jM$>q6>[|>Jĥ?Cb?|S?"UQy?/88K?9+S?D6 @K?P>ǜ?ZX<f?dRQj ?na?uԀ5X?/gM?{h??Ö?MJ?ʺݧ?P$Sȋ?r%ad?!_?-_p?Tf?YjQL?XYz?i~Zb?0?X,?ZZ?zh?+ ?؟Z?~Ch?|}X+?b=??l['?}?f?#x{?zO`?, K?-O?7~X?H?N?L8d?|LA?n?|3Y?xYoS+!?w[ ?{ _?Ή?^W]"?ņߚ?% P?uQ~?|ѼJ?N4d?.x7)?Xv?G?>?F?qN]?R7,?R4r"?RHaҜj?xP?kL!l$?^4F?P-?@r-?0\lx?!Jw?z`4?.p>~h>  >p&o>ы(>GPҸ>LxRT>'b>vK>גY>CE >Έk>c>ف;t>\8>x>R|<>vֻ)>*G>s;f> >o&X>[,F>ϋ'>jў>쥎ԓ> gi?1B&?é{>? ̈e?,/ۍYt?6z%k?Aұ>i?L}?Vi;b?a{8Yl?hK?q:?xs ?]\W?d"?:gB?Bf? O?ҷ?t6?`>?R]?10x~?,0p?@? 41?*bj_? !2=?/?{ ys?8ގ?=wd? ?%%?Lif??sP!IY?e3WHr?Ve ?F0r?6/?'es?BL?~>W;> p͘>X4le>ӀJ>0>A>G>y_,>zv)>n^>{Rš>r>e>sec>5K>N5=>uBpb>TI>x>^]5>q\6>>̮c%.>~b(> 9ͦ=h>_?G ? ?,4?(6G?3`@?>EZ0 ?G#j?R>,ks?[xV?cRV?k<~?rڱ?y6R2r? ?I}?MEIG?0"Ԋ?w?c9?ql?ckh?R-'L?LS?+F?Mk?ԳV?TCe?dʫ?H#I?=Q_?$;? ?Cխ?zM%?wq«j?yU= ?Mz>}>_.±>!$=u> [H>̲>Ӎk> T0>2`> e>B9P)>?vT>dK>8Bep>umt>>[VG:>to>ɜ>윗Ī>t>z0%>_he4>>9>]RDҌ> >~[UQ? >e+v?o?#晤n?0#sq,?9%th?C|[?M)?Ut5DJ?^^I?em/:?mtq"?ss?y0 ?+%O0?25?/c?m!Cz`?F R?e@?~ſ?V?ȅ?hy?<?$U@?ӬY ?7p?H]ݒ?x&&?W>?y'w?X?4?IT?_1H?*/p(?~8bO?@ ?zv-se?rI)86?mR?m>e {?q۾#?xbmm?X'$?Xی?to?Ki)?GT ?}?Rk|?K ?׊?(17?<[weA?GiO?!7?z7,? ̮?qriP|?aLcA?Q> ?AP?2^?#HG?S[(? K$ >P>^&G>ڿH 30>ͅW}i>{n>ŗ>JR>U{d>{">Mo>儰&>>E;>1RP>rvKR >Il> T![> >&n*&>)QD-\>Q> l>ԗb>nF`>=>,&UT?Dxcy?"a"M?BE4?* &?GVV?Q?Y>L?am^ ?iTx{?qdY\?vL?|)X?C?)6?jJu??J/B?F̓T?f,J?R?ۑ?eua?#&ld?mN?2i~?e6B_p?~?'<^B?,?xb>5?yoV?r鳠?pF7?q&F?w?Y ?v??5I^?b8?@R?-?eP?,4??UǗ?7?m?d|s?qKeH??ˈ?c ?{jf?z?s-L?p9|P?pc ?s]6g?z??lǽQ??Z??ӷ?s%I?CR.?`?;_?CJe??ށ>?&)?Eo?g b?t?dxE?TJa?DG ?5zplC?&@?J?bf>]u (\>쏌!\>+>*^}>nnÀH>pC >chQ:>M'z;>y>e܅>M >e0>,2#1>zb-R>?>5+"">H'7>`TY>n>@r3Ճ>x `?> '>йϐ>݅ >^F]Y> ?`A? MUdj?<?$t-xR`?0P)~?:Z|>?C?MV 1?VP U ?`,L*W?h7?qF1?x+$?͔~p?6g??$Q+?X]Z?=\?$m-?g ?M UہH?1`?I:?v8?;c2U?J};?̎z?1ՠ?,/?HĖ?OS?x$K^?sNr?q(>?rí?xA5?"x:?q?yo ?}p#?)?@?A{Uj?c9Q?G`?[Rl?h\~+L?gaX?b,~?N>H? ?n>Y?<$7?z_i'?uLw?s ?uYu?z#5? bA?oi_?qn?$|?$ʻ?A??K),?nӚ ?hB? d?c}(?a?k?OeeC? ?uD?fc??U.`t3#>f>s9&>hԽξ>mvh>-Vb>Kߢ>5>s'>Z:>$kDz̐>9f>_]Bm> 8WK>|@>Au`V>>.>[*X>O.+->0Rqю>¦;n>b{>Nf>Mzq<>I;O>l`?.Y?b0?nSD?* aQ?65. ?AnA?J(?UcXx:f?a[Z?kf?u/A2|?~]`Өl?A??.l?Gsk?^N?eJ&?tIB5?LЯ?<2\?tϏ?L?}b?x2K?i-z?_z ??|?@L?C1F?pxܻ?8?yE0;?u]?u`CHX:N>lmN>D>ЦHT>@0+ڠ>W|>Xn=I>]k8$>7y>k5W>=:>=X>_&>i">>H2^V>X>Qtj>qܳM>#>7F> ya>ќB>ޚ7rf>񼝇>UW%?b'؉? LJ?:l\?%{?2bGI??FV?IJ?U?c ?pJ ??z-V.?'q?{Mf?,8{?-zn?=-?CM ?Ա%?y A?,CrD?M; ?=;p?0X8{?085?1gJY׳?g<?~?bH?uд?Hv?R;?WK8?Z?%H? 70?XMA?t+h?w ȮL?$?X4D?JG",?=+r\~?1- 5^ ?"fc~?x^??T>=紈>ߠ><> c}>#l0>°2`Z>(DB>oU>QϿV`>?]L>ǣU>h~>G >F>Gs>hۧ>ǣ(:>?]N8>QϿW*O>oV >(Dr>°2`>#l0tt> c><>ߖ>=??x^??"fc?1- 5]?=+r\z?JG",?X4D?fmh~T?t)h?z! ?7JSW?J4"`?5yW?n)i?ؼ? ?^~?%o_?"DĂ6?R;? N?-]V?*B?R`??./$ݣ;?45W?&(J ?MD0?ic֊?$>ec>ߍ>&!E>;_=j>.LW>EO@>M>+ >rtH >}q>*L>Ce>ؠ_>JQa>3>Ȳ><#h>n> s,T>11>%$R>i貆Z>ޚ(r>Ɯk*>#,?xUT?[?+jb?-M ?:p•?Hj?Wp:z?gh%EO?u%b?;zi)?}*ɯ?|b8?0,4 ?$?@`??zA:?qmt?e!?۩p/? "f?(sR?"c?讹L?IXj?V??mҳ7?^%?z40?wH/w=?wt?|@! %??Ƶ7_J?XV8?U.Ey?|DYZ?kV"9?}?1rg?Ob?HT??8? ^?ИΑ?;j'?)cU?ʐl?GfX`?,T?]«?wo?n?c{"(?X 4?Ma<?B śZ?7;܎?,S"JV? ̟?fF?G<(p>[(>B77>xP>װ¨$>,<+>I]I>a>v N>oν+G>aHt<>R'>!4>P*>T>pG,>ay0>Zzt>VRD^>Y]z`>^ Z>~(>|2@>( />1Fc>ܞ> H? ;ly{?]ֲKmf?*`r?8MEXI?F״Hx?VٚGW?gA?vd?[L {?f? ?vq"?5 ?>[a~?=8?N ?0%*T?IF}m ;?V.sO?Œ%?|"69?u?,X?l<?{$ u!?w=0?vԎN?w{X,?}P6?9޹}?jM?!k?I1?n}?tE:?'?K?>?H߮?NCf?[= ?k??%6(U??ӂ?x,Z7?sbq?rC ?u?{BN?*?7 ?:Tq?9F.G?m%?K=$?$Ԧ? -eɡ?+:?Φ(?ەQL?*3?l?81 ?%F?=N? q\XL? gd>YvH:>ꔪ[]>\˾$>šAE>Atʼn>ݍ >$>44\B>#ǩ<>C/'>Pk>r֮f>ӭ>_>RaX>3t>~'oV>QCr|U>@r1>|i>9(>ǧ18 D>]0 >Wb->uQg>0%6U8?]_|?!wd?&:~?5&?Dp?TA?e&V?t.?/^ꬷ?RڡL?[?x[<? Q?i6e.?dϲA?-;>v?Ȧ?ĺ6b?#;?u^{b]?i9[\?x"?UVm?zoRۼ?tFL?qYp?qä!3?uq U7?}Ib*?A?V M?M^&+?Ӕ?=v?_g"?A?k_ ?zn??v- ? ~ta?ȑ?OC?>xt?oHN>L`>ʚc2>PhD>fܯ,>qRL>gg>|*>#ؕLV>w÷>agn>W)AR> 5RI >zF>Ďj>s>W+X>?q7>}1bD >p0|>צ>e>ZzR>~h>{\AY>8>&G ?"x?0]?#BgX=0?2 L?Aڱ?Qy?wӏ?K揜sS?._?fZMU?!HW?|]SF?vH:?t?v]VM?|Pg*>q>r >_k>Y6G >\>{D>b/>i#ڄ>MX*A>c>* >þG|I>-ݑ>YSω>d>0YC\>]y>ܠ>, >E>˿ɚU>4;p>/(>ވtgA>C? ךV?&ա@?.J`pp?=r8?MR ?]4 *?l67?zu-?踠Ov?ݒ??0:#?S?2`_-?I8a?âg?X?3@oG?s>?<#?f3?Uӕ\?|-?uAl8?rRwXԽ?rVz?u _?|רj???Zw?nX?ҡ\C?uX/6?ˈ!?Bs$?=P,?9?&?dx?W)?z?Ʌ`9!?Zk?G9}?V2 ?\"Io?{9I\=?zba?}^:S?|n:G?ȶ"2?aL[?3q?p{?WU?،f)?'."~?'B?t???ESy?-Es?¹?TW?Mf7?Sv`?Gg?Ǭ?h2&?|MSW?uA͓?o+?f` V?_t ?U-F81?K 8?@SH ?4¿?)qW?#H4!?SA? BJ>lN>Tu$>H~T>r0>1!w>_3>0k>4>t㲹>Q9>)MW>JrG>Ve}>r&S>@쵙v> #>8H> $>ƣ1>R< >BVFȠ(>|>kM>l%)o>0 B>j?%[h?JKX?'qz#3?]:?Ը{ 1?Mm?}ub`??3I?#U&l?WD$?|"%7?z?՛9(?Eu?w&?|^݆?N+p?b}?Ea>y?%d?3Yk?/?8?-k?ct?_6?,?zI?&M ?J\?nUC?S\u?z|k?3?!J7? NR?lwj?;ZM?\_?EUU?QYv??Jk7i?N):+.?B7* ?O?zOJ;z?x U?IwmG?d84?h ?6Ԭ?ɜ ?{TP?sՔl?l(}ھ?cm?!he,?y2?]˱I>ڎ>fɶ>B4>Ц!:?z>WOd>Knm]>(傈>egg>ЁBa>3U:>IW)> x.>T>g)s8>`Qhl>pZ>@cAm>7Sy*>%>5t>ϿE>1>֮U$> Xv>!TQZd>Q??KxF0?}p?!Ԋհ?0F\?@+JX?Oo4 O?]lf?jVZ?w+^?ce?f)E?ˢdJ?j {?ߘ6?Zm~?6fX?Gk?ZM?>'^X?#ZV??I?=-\?C '??xT?q#xY?g"?^q9?R?F#eǔ?;,!cnx?0qPO1?#I!dd?\6=0?(JI>6>p5>x}z>1 ՝>szT>vB5V>z W>Zc>w2&>#>"-r>۬>+ >T;ʲ>i>G>aE>vۜ}>sQ6>vY $>yj>Fo2(>ҳ->6 *>X!BP>/=H?CdLH?ȝ";?E_?(0?6+&?EsQ ?S0 ?a{?ngZ?z<1?7$#?u ?{?t?5J+d?%H?)7?c'?\4}N?> z*?L* ?%??Zy?yC~?Zo?ɍiUd?YJ?{jљ?{M ;?~" ?9c?v؍?% 1}?/O#d/? p:?sY?S4c?R$M?28??_LW?%Ib?vT?l?i:1b?5w?wW?~zm?c\?~=o*?{x+?|Z\u?D;?Ajm?JU`=?ۃ?js?HJ?-}*Vx?ӕ?0&???s?^W:?%;V'?0r#?0~?-5-E%?/!L?1?|+?[?sT?ix> {?Ob|?!=">kx\>Au%!!{> @>һ">{Wq>Ul>ÄIe@>zf!;G>ڀl>S$9|>f >(_>Ԩ.u>w "0>6ӞK>32>[Z)>Okj~>0Uf.H>vp>)xd>C1` >fI >klZh>DG>h?1&Ĝ? c9?93H?#{g՜?0qX?=p"r:(?JZe(?WbO`4p>?D}>*a>`>|>j>OnXN6>S @>ÜJ>n>k C>up d>@A6U>4h^@>n>D:>]\>?4'> 3">#2>%>XW(>ʐ!_&>Գ!p>߫.W\>Q>hgm>"\?kT?}?v ?#[>ŨD?-B):P?76b?CC̠?PW0?[]wR?g/2?s?Lj!?~L]K?[z?7XYK?Ѻ,v?Ȼv?ee?N2?? g8?H)7?z.dJ?aUC? ?TP'H?앥?|6 ".?u]?r|P}?r{D|(y?u"{l?{_]? ?!j'?n?5 ?h'??d;*?97?ჿ?]??7?=Uy?xH5?Ke?L`M??Al?#C?~5[{E?u*e?r?q?t"[#L?{7n N?#:WN?*9?Ɋ/?sK?ʑ?N]]K? /K? ?p"?ү)?BXn?}Y?:B's??.$C?vU?|<w?s$ ?h\?_h@(_E?S\lE?FwY!?;o?0,U?"&l82?3?VB4>{Ѿ8> >yLj>m[> hG(>r=>R.و>D>m >}x>k>o_>&>}>[8>P F><.~>j?s>*7 ڪ>Ł >ѷܽ H>*0>`>_0dJ?5? -Ӌ?D" e? F+>?'Գl?06 ?8<P֯p?BEh?L1FL?W[1?cR?p!F?|T/?RHN?:?WE'\?J23?# ?P1 ! ?hKg?|˳?UH؇?k??S]?.;~?0$?n|?}AyS> εR> a >ϻ?">f%p>Z>v>7>w3>w>a$E>7">W.%3>S{>BG> >uy>R6saL>˥{s>)ߊ>xU>؋8ֲ><>7*c>Q=(?M|s? 9?^IrD? ۓ?'_m?0 j+?7 QЄ??̯??Fg$?Q ?Zsw_?e_`R?rr*?~ s?;aO?TT?.(?鰓?S[!Qc?$&9?|j?#jLK?+բ}?֒ 60?nrJ ?xaYh?耽?E?,Q1_?%Qg? h?3.X!?dSb?L&v?fĢx?4?;'hd?F?|?rED?0=.?6-?| ?F,?vևM+n?t=$X?upb?yW?J?HM??%?'a/?0[?Qh|?-rDP?zq>?|R_?:?|**?RPol?|0f?aB?fC?>ܼ?|Gy1?s)瘊N?i+1?`M?TB?J_};h?@16;?3%S.J?(%^}r?*@????YJW> 19v>r-O">V4.\>ci>93D>U>F>xN>멕>rx>*6>"~>2$v_g>!G@>M@T>4EA>"| >?d>lr>fހ~>ᆽM!^><|>]'?qs|? BF?{%4? ?)#?2P_c?9mF?A?H;]r?QMw?ZG\$4?c?n2_?xPFRǞ?'_?TMP?޸zT?coZ?F6?ĺlh?[v6X?|"/E?"?QЌM?jZκ?k?AD?y?,^?(ڵ? >k?|{=T?v\?t#?uH̲?yZs`?s+\? ؠ=cb?,?\0~?z ?+:#ȕ?\?zzE?f ?E?;ė?15V ?,^? QK?d2h?UK|?~?謊)?|<?ysK?zOt)sJ?~Rٷq?EF+Pt?D5H?ةÿ?\$?xu!?_,?wMq?0'H`g?0O?T?j\?uz?5?j^0?6}8?j6DT |->Ki0>v8>בNx>d>2f>`=k>,6F>zV;>!ab>b7]>^@ l^>tL;> { >t;>pkJ2>ZM.g)>#>|i>̓Q֏>ږUK>1\>rDsl>v ?"˫?$lv? i ?)2El?3,q?<B?C ?L1 h?TI?^O ~?f&2?p6>SB?x`)_& ?NB?d?p>?xjM?:>i? &?M`tQQ?VRyI?}Ț?!M?$th?jn?x?vO?uqg`?ئ?ip-?{Ҡs5)?y*p5?zR嵾?/ n?Ƚ?~<ɶ?lE@A?E4?!\d2H?y"x/?gtCF?*ũ?T>?T<?/&P?.{U?bn@?DC3Bu[?u!/?|?oϡ?}?{o>u?}DHE?Qw'b?qeK?Q\ʫ?H?]8` "?[?/Q?SDs?T?LVD?E"? O? ?o,?ҷH2?N?{: ?{]~?r%?ic x?a:LR?V2M&?NξL?EZ8]?< K?2,?&i@S?.8.?:t!?qbn> >Z۬>Aw >XE>b>w>Pk>nla>W#>Oѫg>ڈrN>b >ڈ>Oѫx>W#>nmh>P>w=>>Xk>Aw >Zt> :?qb?:t?.9N?&i@S?2,?< ?EZ8O?Nξ?V2Mk?a:Lb?ic p?r%?{]~?{: ?N?ҷH2?o,? ? O?E"?LVD?T?SDr?/Q?[?]8` "?H?Q\ʫ?qeK?Qw'f?}DHE?{o>j?}?oϡ?|?u!/?DC3Bu\?bnD?.{U?/&Q?T<?T>?\?gtCF?y"x+?!\d2F?E7?lE@i?xjM?p>?f?NB?x`)_& ?p6>SJ?f&2?^O ~?TH?L1 h?C ?<B ?3,qQ?)2Em? i ?$l?"˵>vn>rDn>1Z>ږe>̓Q֏*>|i~>E>ZM.>pkH]*>̹U> ᗳ>tL=ic>^@ (>b7p>!ab>zWR>,6f>`H>2Ҁr>d<>בN6>v8ѿ>Kk>>DT |0?f{'P?.' ?#Ƞ?/S@?8&?C[4#?NF*?W7dxQ?al?j!͛-?sTy?} '?j6<\?6}8?j^0?5?u{?j\?T?0M?0'H`f?wMq?_,?xu!?\${?ةÿ?D5H?EF+Pp?~Rٷk?zOt)sT?ysK?|<?~?謊'?UK|?d2h? QM?,^?15V"?;ė?F?f ?zzE?3.X!?+:#Ȓ?z ?\0~?,? ؠ=cY?s+\?yZs`?uH̲?t#?vg?|{=T? >k?(ڹ?y?,^?AD?k?jZκ?QЌM?"?|"/D?[v6W?ĺlh?F6?co\?޸zR?TMP?'_?xPFRǞ?n2?c?ZG\$>?QMr?H;];?A?9mEK?2P_c?)#? ?{%? BG?qs>]4c><|Z>ᆽM*>fޔO>l>?/">"|>4E>M@(a>!G>2$v_>"@>*6zu>rx;>멕%>x#|>G,>!#>93/>c>V4@ >r-O> 1:"??YK??V?*@ ?(%^} ?3%S.z?@16@?J_};a?TB?`M?i+1?s)瘊N?|Gy1?>ܼ?f@?aB?|0f?RPol?|**?:?|R_?zqJ?p?qBSyA?uC*?}4p?e!?HJ&?% oZ?x8?nr>?֒ 60?+բ}?#jLK?|j?$&9?S[!Qa?鰓?.(?TS?;aO?~ s?rr(?e_`l?Zsw_?Q ?Fg$|??̯?t?7 Q^?0 j?'_m? ۓv?^Ir? 9?M|7>QTg>7*b>؋8>x*>)ck>˥{q>R6sapn>uj> \=>BG*>S6w>W0ՠ>7DZ>a$D>MM>wV>w?>ZQ>fE>ϻ?> a> ε>AyR?R/J?BW=? S?,?7717?C-T?P$?Z&o7o?dB@A?pDU?x=?@F?fvgm?ڏe$? ;?F%qE?e!?hY*,?T?HoL?;|"?sOz?U_'n ?sqg??2"??5Uk?zG ?te솪?qDHx?qх_?uj2?}K8?2lyt?4$%?{B?2A 8?`ל?vBf?GpBxR??|(?j*&?Ƕ,??d;)?4o?3;X?@ ??9^?vs%v?q_s[̻?o$ ?pU?tP6A?}_0d>` >*0>ܽ %>ѷŁ 0>*7 @>jP><.>P >[EA>}>'>o>kB>|>m |F>D>R.[>r[> hGG>m>yR> >{Ѿ5?VB5?3?"&l8?0,V?;o?FwY ?S\lE?_h@(_E?h\?s$ ?|<x?vP?.$C??:B's?}Y?BXl?ү)?p"? ? /K?N]]K?ʑ?sK?Ɋ/?*7?#:WN?{7n P?t"[#G?q?r?u*h?~5[{A?#C?Al??L`M?Ke?xH5?=Ux??7?ჿ?]?98?c\|?h'?5 ?n?!j'? ?{_]?u"{d?r{D|(m?r|Py?u]?|6 ")?앥?TP'H??aUB?z.dJ?H)6? g8??N4?ee?Ȼw?Ѻ,v?7XYK?[z?~L]Z?Lj1?s?g/Y?[]wR?PW0?CCl?76at?-B)98?#[>ť?v ?~"Z>hgpt>Q;x>߫.W>Գ!W>ʐ!P>XW>:>#(> >?4'G>]\q>n=,>4hC>@A8->up)>k BD>+>Üc~>S >OnX'>j>`>%\>*>?D}>`0? [l?Ti/?$L?1.J??<?H'6?TQ@D?`*Z@?jEfGp! ?t(U&?~nqJ?b?u~WY?0#/E?m4.?|?- ?^?$N?.b?7i??\? ?fb?ӯT?3-H?cp?{9@Bј?va0c?uuD?wȿi?~WØ?~F}?j*q?(?i?I:?zn#?bP?IU ?i??28?S?qԫ)8?VM:?2t? 1T?m)=?LSֶ{?ys^?wHIKU?w aw?{?Hi-I?tPbB?LaK?oe?xޛ?K鈡#?rr8?-F?N~Z?Hm?(I>DG>klyX>fI&>C1Eh>)x<>v>0Uf-J>Ok1>[ZB>3{>6ӜbJ>w o>Ԩt>(_ H>f 5>S$_>ڀyi>zf!>ÄJe>U >{Wp>һ"k> ~>Au%!>kxVS?!=# ?Ob}?$>> Y?1E? z*?\4}N?c'?)8?%H?5J+d?v?{?u ?7$#?z/;>X!;h>6 *">ҳ-@>Fo#h>y\>vY<>s>vۜ|҄>a<>G><>T:D5>+>۬P>"O>>w>Z>z>>vB5 >sz2 >1 լW>x}>p5>.?(JI݀?\6=?#I!dc`?0qPO?;,!cnk?F#eǻ?R?^q9?g"?q#xY?x\??C %?=-X????#ZU?>'^X?ZM?Gl?6fZ?Zm~?ߘ7?j {?ˢdJ?>J?,:?v?/~TϘ?j<?,??1$C?,0?B3 ;U?" u?z?BT??W??8HN?3 C?7F?u??ce?w+n?jVZ?]lh?Oo4 Od?@+JX ?0F ?!Ԋ՜?}Đ??KxB>Q`>!TQZT> Xp>֮UP(>1>ϿEW>5u*,>%->7SD>@c#>pZ>`Qh>g)s>T> x3?>IWӼ>2g>Ё>eg>(僈>KnZ>WOdh>Ц!:O>BI=>f>ڎ?]˱I?y2&?!he,ޔ?-i?8C3?3?z|f?S\u?nUC?J\?&M ?zI?)?_6?cu?-m?8?dx?3Yj?%d?Ea>y?b}?N+s?|^݆?w&?Eu?՛9(?z?|"%7?w>D)?vãR?xCIt?~Z?o$~+Y?:T?$F=?W3?}H?45g?4?so^S[?d:?V%?FnP?6|p?'qz#,?JKH?%[`>j>0 .>l%)>kt>|(>BVFм>R<dž8>ƣ|> $6>8H> #ݬ;>@쳽 >r&R>Ve>Jrl>)M->Qc>t4^> >_p>1!~>r0->H~=>Tu$ >lN8? C?SA?#H1!?)qW ?4¿?@SH ?K 8?U-F86?_t N?f` v?o+?uA͓?|MSW?h2&?Ǭ?Gg?SvX?Mf7?TU?¹?-Es?ESy???t?'A?'."|?،f)?WU?p{?3t?aL`?ȶ"2?|n:G?}^:T?zba?{9I\M?\"Il?V2 ?G9}?Zh?Ʌ`9 ?{?W)?~C>?"?5?=P)?Bs$?ˈ#?uX/6?ҡ\C?nX?Zx?K?|רt?u _?rVz?rRwX?uAl??|-?Uӕd?f3?<%?s??3@oG?X?âd?I8a?2`_,?S?0:$??ݒ?踠O?zu)?l67?]4 ?MR ?=r8?.J`pl?&բ`? ךVX>CP>ވtg8h>/H>4;$>˿ɚ?>E>,! >z>]x>0YE >d@5>YSP>->þGp>">*a]>MX)D>i#>b>{D>\>>Y6G2>_kG]>r >q>g1P? 5>`?\kr?% O_?12;?;j7AGyT?E3z?P)?Xx@?aХ8U?h =?p05g?v2B#?|̇??E7 ?|z?P4:?2v?HDZ~ز? qKY?NsWM?:M?'?4I7%?@,|?4(}?\#4?'+?u͍?[~?@l?%?|P?0]?"xp>&G<>>{\Amp>~>Zz[>eMl>6>pv*>}1bC>?qH>W)vF>sN>Ďwv>zG^> 5R<>W)?U>ag혨>wø>#ؕ^>|*P0>gg>qRV>f>P[>ʚc>Li~?oB?>xJ? >C?+ Ω!w?60SD5?APC?J%?ScK?]cd?eEP?ms[?sEZ?y-. ?1 0?$,?cU?*n(?4Ŧ?Z&,P?p?Itt?r,?X#p?""? A??b[?-.?[?BpK[?߫A%?(鲠??{rZ?tN@?qt?r?wl7?^9?Kh?Ow?dϲA?i6e.? T?x[<?[?RڡL?/^ꬶ?t.?e&V?TA?D?5&?&; ?!w0%6P>uQ>Wb->]0 ~>ǧ18 >9(>|i60>@q>QCr|E>~'o>1>R`>_>ӭ5>r֮f}>M_>C.>#ǩ= >44]b>$>ݍ >At>šA~>\˥>ꔪ[]>YvH? gH? q\N?=N?%F^?1>1;?<,?EJ1?P¾#?Ye.?cd!?lH ׃?ta}X ?{[oN? p?zl-??XL8?5YK.?<{?8[a~?5 ?vq"? ?i?[L z?vf?gA?VٚGWv?F״Hw?8MEXI?*`r?]ֲKl? ;ly{\>p>ܞt>1Fc>( h>|2>~.">^><2>Y]z>VRCZ>Z{>a닙P>pG>T੠>P*,>!3>R&F>aHu>oξb'>v >Q>I]iU>,װ¨ >xH>B7<>[(:?G<?f? ̟I?,S"JV?7;,?B śY?Maf?J*?O[Be?~2ZQ?Afq? ?=ܢP??8X?z(?En?} f?|V7?}/]l?1p?o=oZ?4j[B?!?YO?? ">?۩p/?e!?qmt?zA:??@`?$?0,4 ?|b9?}*ɲ?;zi)?u%b?gh%E;?Wp:z?Hi?:p•?-M ?+jl?[?xUT>#=B>Ɯkv>ޚ(r^>i貆>%$\,>1\> s>n>;Wf>WI>2T>JQa>ؠ+>Ce~>*K%>}q{#>rtIݹ>+(>M>EOD>.LcB>;_=>&>ߍX>ec>?^[Duu?04)?JE??'?Y0?3'̢?@z ?K6.\?Wv=ׄ?d;H ?qq?|G"B?F?Zr~/?彆Ȩ?4??Kx(ɚ??Pυ?$?4? AMwF)?_?\Hu?l-r?^~?3%?%/i?qO;,-?k-?[t?-?CB?[|?KN?UZ?Li?1Q6?q EI?EyL?y# ͝?@?<*]`?sE5p?h0P?=+&?Z?h?CV?>d?Df?̥?f%?0egB5?w.F?jiS?]O?Oԧ?Akv?3u0?%.T?.`t? B`>@T>$=hr>̓>G~̀N>FҐ>ñH'>tKܞ>'M>᪜6>5>]I#8>pQ>M5{A> >M5H>pQ>]I$r>JY>᪜\B>'>tK>ñH*>F>G~n(>̓f>$=h>@? B`h?.`rv?%.TΆ?3u?Ak{?Oԧ?]O?jiS?w.F?0egB8?f&?̥?Dg?>g?CV?h?Z?=+&?h0P?sE5p?<*]`?@?y# ͘?EyL?q EE?1Q6?Ld?UZ?KK?[|?CB?-?[t?k3?qO;,-?%/i?W>%?ZJ?M?'m\?bR~?;|uv?"΁l?CY?{Ν@?$Ub?vt?m˶??<ֽ? _gA?3>6*?^z(?JDe?1 v??s$?Mۚ#?%!?b?Ⳁ?{P?2:t@? $}?l4?1?'/x?*? {?%Xk?a?cB"?v^G?ji퀞?^KlM^,?QW}a?C ")?77G?+046?Y?he?H{>*J>)?8>e>+|o>yS > )>.z찜>w[8>ۿ>\2>}>9H>ԝZ5G>Q7>b2[>]>2k>=P>oj>V,U>3t->,иF>RȲ0> y [>"?(>dp#-v?u\w*r?/$?! w?0ys!?>V@ ?Lؒ$-?[xP?je_(?x\?X?T? YQ?( ?AqR?Qu?Ci?$J?=繀?ќ5R~?se ?UF?]i???Oc?j|?yz?ǫb??|r?^ȕ?I}y?u8֞?hYa?X%?x?k^?_?5a?RI?t?}?@?B?'-'?{$?oLM?}x?}I'?NJ?K7ڃ?Qg'2? - ?e9q*?pY&R? KS?l1QU?[J[ 8?oD?_s:?NV? ;Cp?ө?S?5+d?AN ?b?XD;?K#!"?e׭V?=)46x?sں?t3&7}x?j MH?`wW?ST|=5U?Fx/؊?;hb?0j]u?$r%X?mX?p)? f>w>qt\>hV8M> U TT>3ԋϱ>p3V>#uR,>?u>xv&>H)E>>>M>4'> YzH>){RO>]7ͱ>|bE>G?#>4Nm>ʊK>>->̈́g>LGЯ>D3)>>7l?-G?G?q427?+՘?:<xF?Ij,H!?Y+?iK@(+?x e?{fr?#Rr?x~b?M!?Y~X?є?#t?5"oe_u?gnaV?\q?<^w%?2?<Mz?LD G?F ^?C>I?|~??7? M?v?Z ?Rs?ԹY5?n 図?Ea D? (|?A4?#O?Sn?L@??|J[V?t P ?kc֐?a=?V1?KiNR?A 8 Ԑ'?5C=s1?*09`d3>lG/Q`>> >і(a>ű e%>:> Y"+>vT>,@@> :?>S6>u5><#gR>#̥>"+xG>l>޲M>2 >u`> >!m> Af>Ӕz}T>@] >0U_>AR? ?|8Kl?'2P4?6a.>J?E^?VRlݴ?f d?u~^?32c?c?6F ?X`p?A:A?"YC??~z?O_?byq.?:ˁz?hҧ?^Ȅ?BV?f?؄}?zt(?v P;?u81J?we,?}W0?h2?~5g?gm?@4?]?JE?zѻ3?xO1?Ơ$?FXB? S?INmڊ?z!F?Ej?;5 ?r/?V樔?x%`=?u|w ?v%4Д?{W?/g ?䩽IxY?,ǡ;?}Ja?T?9?4|?H&h]?,b}?Q2?%kۻ=?o@x?]$?ȉ.?>P^?Xa?Dj??U?>5W|?gҏ?0Mk?|.rx?ut)D?n|?e Ѳ`?[Fm`?QAKB?EH ?:.?0zǨ?#I?tۋ ? ,|>Jۇ"> >プ5m8>Kb?>,TI>,me>0i>>O*x>Q7>U!y3>~+>S> ?">z! >Q4>Y >֘*>|qi>gzs>It> ޽> ,>ĝ>>ETqp >M >"h>P C?$*$?^¨?#5?2|F?B%*e?Rs|[ p?bkE?r4 ?Jɞd? ̦?b?{;?*~?V?N1?L ?uW? ??]%?kV?V U&?E~?lFl?x9ܺ?t'6?s}=?vS?|=d^?Zo gwA?Pc?+k^?Hݿ?̡?Lp@?o'L%?AF?ID?$`+?|`?ȳ?5 TQ*?Rv? )W?%Fc?4ɛT?}JQ?y=}u?yS]?}8?M#^c?ӱ%F?Rv?Z ?iýX?]ŏ?b(1?P;_>s?DO?$w",?c??\g s?=hQ?dj?S (?m~x?4F8??,_S0J?[|?=P?\ 81?x(?kIzڟD >7 >s?>5]~>ׇٙH>r>@qA>o#H>b}Z>) L^>ݪ=>?|g>x4A>.>o%J>a >>D>B0>;y>Czh>2:w>>A3h>|,?o?. Jh?.Hwnx?=(?L?] ̀j$?lsf?z? ?y\p@?|scZ?$̘.?IZ??P\|?'܂?EX?,ap?7??##B?ŧQj3?9?ʛ?|K?wT+$?v 5}?xd΁]?}aܘ? y%?8?n?I?GJe?'?6~?Jm?~OT?r9^?.!?,?3w/?l &?jy?=غNX?e7YZ?ڹy?#BlD?rS;vw?U?&̏?O}?3?KYlk?bT{?ՙ;=]r>j6>܉>2+V>Pg!آ>uwý>\> _]>No^J> ͺ>>y>Dy>#%i#>d)D>1>>d7>U~UT>rBx>@ֻ>V‰h>,' >j|F{x>NCyX>~.5@>u,?7d?Z{?'_?6; ć?E6?UCtI?dBP?rH?Ed`h?/1?P?DR ?}brڊ?{I?GA?;tM? o?ߚYیU?q~?WoY?Rb?^?$?פ?x1=?~ 9?}X{?/Kצ?c@?aE1t?Ej??{ "ʟl?yw?Vڀq?1AO?*?BQy}?\E??9 y?/_?B%k??B\G?a}R?2?^?J-I?fm ?Q?Pˏ?g y?؄0?>8?;#Q?a?I86?bj?;YU?I3? z?}֒>?͔],?FE\S? ?th3? I?S2?ElbJ?cbC?<{FE?c%0?vx?nX?|I?sF&-6?k?aJ"\ ?VvԪ?J?@?=ۘl?1> Wbp?$ d|?AU/o?z/aa>~g>d<9>)эV>ҤE>([n>rCna> >{vW>2JX >c|> g> ߐ>fo>wi>?ET>.o+>/Q>v[E>Q>mc>>6l4N8>y>]HX> >T1?gYp@?D=Ũ?" u?0ME?>ϼa?MT4u?[Į?h++?uf?p|?bV.5?jO?O)?D0J?,c?2 *?A:?d4J?xn{?7ģj8?ș?Xx{Xu?z?6@?ʸ˘9?f"Z?Wџ$?SA?_?loF?nw?ȟB?]? \VU?QSiS?uO%?<`?澜 0?"ըw???,e}?މͷW?O?k{?'??+{=?L%*z'?:N`?jl7?Ms?Dy?{2?*Y1?1?(??ͳ?譓S(?dߞO?^ 7 ?chvk?YI?f 8?nR?:Lrt?u?fq ?Dغ?h?hqo@?"P?x oQ?p (w?e￐?Z-ޯ?NDT?@KL?3,ĵb?&%,6?6 ? %K>ju>jhe>3M!!>.1Ƞ>-R>YT>ru0>*-߄>>I>g>ڊ>Ȋq>-̲̥'>4>]>vM~(>.->ϗv>j rEZ>a>۸$>Evv`>Җ>ĭ#7>:>UZX?/z?4?q)@?(v*h?6@?DZSKU?RtGD?`\#m ?k2Yl?w,sFӺ?TDK }?r?:z?""F?T[~?a"q? ?oY?SN?F/{]^?Y+zF?=P~i?B ?n?;H-?B?jw?ǵ?@%1 ?K(?ǭ@Ó?{ ? [W?VnL?EY0d?M? ? Q?,yk ?OFC?wv ?ύd?xDn?Ȼg?jr2-?aԳЛ?}tf?Nhq=??)? `u>?&o?V ? ?{?D:?jϹ?n^?[4E?B $??9AN?JfE?8I?& ?h?+%?/?niXi?.*@Ua?1X?2?n0?{-r?qzr?g$+{$?\z|?P]t9=L?B`?44q|?':,=?ft`? ϑŌ>e">ͩF>≔&n>Gc>{o5o>Q>;iڪ>fe>WI>&a>N)?l> *N >w>}$>Hy>#>߇>PQ2>;FHU>g. _> Y$>I9 >ة[p>Jj/(>1Xh>NOVS?j%??@?$}*HH?0]P?=l?I{~ ?U vT?a1?mOޒ?xI ?O?87p!?Ԕ4n?mo?17?`@-y?2?e>?:bH[?o^'?8gR? [?lE:?C ?ƙ|?rO? _?b}(G?~f{ ?J@͠=?ua0?ke]?.&jMm?3[YP?}iY?|r?#TA?X?֓?t QU?kݿ? Hs?ĐN~?܃>h?p? k?7h? km67?[tj?0ԥ?{TQڪ?zy⟲Y?},R?j0?9ǣ?̨?$T?z̈́v?W?cH>?iy7??Iӣ?~,y.? 8J*?U?C:?JԻl ?d8T?IR?Ux?|[?r]n#h6?gk@ѿ?\@?PpG??B 8Zy?4*?B?'?e? 思>EUlk>ߓ4v>)i9> ݃V>-b> @>mv7>Qsp>C _N>w)>ONU>c{>>w>GGSr>:٢>jrU*>őҾ>'И>9/=iR>j3HY>$>d\o4>K-v>C5~>nXut>O?`p?FO?1DP?$q?/*:=8?81$?C33-X?O Oz?YC)-)X?dޓQ,?qR8vNE?|# { ?:1:?::: d?5y?Gb?=V>s>ƥ$>ႜ>Wܜ{>_>(ː>Zӽ>VM>~|>Ob> >I>%?>qKM&>>'q,>.ך$>>΂ dz>_sI>ݦ.F >RXp>r>B?g[b?}zMb?PHf?!XF?)fCX?29"?9#sr?B~?K7?U6WV2?as7>X?m0?xф3?0&V?pcWt?L/9^?Z?eˬBY?V\9+?}?q'TCe?C*{?B0.^?1#|? Ł?(X;?yK+? w4?ae@T_?|.(h74?v;Z?sQW?sio?w_k?~?, [6?r?[MI"?~?Mi?=c"H?'X?5<2F?lp9?)m?t/?tz??_3u>?_?6E^?TG@?{_c?}l8h?wKO?uxNݚ?vr:I?zy?? dbs?!$2g?4) h?џS#? e?V?^?Ή?9(~? L˟?8?W?ˍQ?ZLV?B S?Y\?D ?v5zsB?lۘT?b}$?V{U?J>V?=%{d?0q?#oZ*?P&UB?x<">K.gj>%cA>˿h>df#<>ð>]?A>W> I d>)>:pr>qIs}>Tl>t>d 8_>,>@K4>š֜?>8>mS>y^>w0Y> xͻw>?#⏻?}2?56?"b[y?*iX?2ݣ?:?$Ձ?AH f?H׌I?Qg ?Z;BSΰ?d_2Ջt?phJV]?zp/|?g+Ѥ?QQ?_Ʒ?Sxڜ?C^W2?~Vw2 ?x?%g$AŻ?f)J?(g%?J?=[?}?bއ?xN?K])%=?}&*?wAZ%?t?uLL6?xÕ?x- i7? E?lx8?OlmKd?Dzt?1M1U??R=-?XQAx?7L?C@d? b?F?̉:6&?{\z?kzf??Y'??.n?>q+?{D%J%?z!?|ھgG?1;?}^q? L?9#W?RoZ{v?uUM?%?5?Ț6v?&;*^?\^nG^?*؇ ?5?~Z?;S?lY?Nҕ?y0a/?pv?fF?\>܈?QIZlo?D?7e?+a? bMٓ? ^5?B!O>/Y(T>*%G>d\A>Kwq6X>®*B>V!E&>J3>5~1&>>-ax> ~ >QX>&#>L?>> 1H>Y>̪`>M3>=>qFt>R\>!_w?RZ?ѩI?hۥ,?#O 犼|?,3cj6?5Pz0>'?>$37W?EM{?M7?TÕ?]-nn?dO@?mhj&?vk?oު[X?z7??tSb? DE|?h_J2?8?ҌIW?|?MlO?*?y}?b̤yd??/?lu?%~?ڪ??&Os?{X誨h&?zOkQ?|5NI?V&Oy?l?Fۣ?s&?|uw ? ?mx6?:iO"?v*V?s?WӺ?0q%/?%acQ ?<)?$?dF=u\?,?_NO?Q7?!G4?^&xE?I;BT?|IMS?oJ?)V?uu骗?xpyĺ?qCCq?g?_e?TPet?IKw|?>v,?2J7?%|&?ϕ? ّ>c>n>zξ\>hƩ >8Ay^>n5>S>oTSR2>J<{>S5>)z+>>uX:m>>4>A:>5߷>4!QUG>^O=p>py]>)xA>s>cRnx>lFT? 6M9?^B+?"g~?-"?62n?AN95S0L?Ie[m^?R/GeQ?YB%gM?bU9B?iuE?q?xmg?e?W =1?$|F?ct??$dǍ?0?H&?cՇ&?Q?t?ȁؘ~?QlU?/šr?#â\?ɡy?F2?I[(?l A?ee>D? yd2b?s[3?Y6?@o?(?X;Xڿ?.h$? |8;I?1_8?1/Vx?䃭[!?!H?mH?k:ab?=?,4C+?ޯ?#?ِ\? Y#??m?lp?ke?3? Kc?fL:]?H}o? C:?+U?aJA?n ?g?xht?ҍ?{Yo?k? &泺?ˑ"j?~= P?uC>?o &~?eXbg?^=];r?T?KqDJ?At2z?5{CG-?*w~? b?qfFӆ?Bح>aW>0_>XB;>ԌC>B#>h>kإ>z>|SX>B1U>tvZ> 3N>tv>B11>|S˖t>z>kK>h;>B#梹>ԌC >XBՐ>0_>aP?B?qfFE? bT?*w~?5{CGs?At2?KqD=?T?^=];?eXbg?o &~?uC>}?~= J?ˑ"h? &泼?k?{Yt?ҍ?xht?g?n ?aJ@?+U? C: ?H}j?fL:V? Kc?3?ke?lp??m? Y#?ِ]?#?޲?,4C/?=?k:ab?mH?!H?䃭[#?1/Vx?mx6? |8;E?.h$?X;Xڻ?(?@o?Y6?s[3? yd2`?ee>>?l A?I[)?F6?ɡy?#â\?/šz?QlU?ȁؘ?t?S?cՇ&?H&?0?$dǏ??ct?$|A?W =-?e?xm`?q?iuE?bU9B?YB%g$?R/Ge?Ie[mlF[O>cRn,>sI>)x9D>pyI>^O= >4!QU >5İ>>4 >>uXÞ>K>)zL >S5a>JoTS>T>n[>8AC>hƒ.>zξ>n>]? ّ ?ϔ?%|?2J7:?>v-,?IKw?TPet?_e?g?qCCz?xpyĺ~?uu骗?)V?oK?>S?Y?q͙?w:?|4L?:.X?\ ? h?Jd?R?+`2?$37'?5Pz0>!`>R>qF҇>=>M >̪1>Y~> 0Y>xk>L?y>&G>QYC8> }%>-ax~>g>5~1i[>JQ>V!E>®*n>Kwq6X>d\Q>*%:>/Y+^?B!Lp? ]? bMٓ?+ab?7e?D8?QIZlo-?\>܈?fF?pv?y0a/?Nҕ?lY?;S?~\?5?*؇ ?\^nG`?&;*Z?Ț6u?5?%?uUM?RoZ{v?9#S? L?}^q?18?|ھg5?z?{D%J% ?>q+??.n?Y'?kzfA?{\|?̉:6(?F? b?C@d?7L?XQAy??R=.?=c"H?Dzt?OlmKd?lx8? E?x- i5?xÕ?uLL6?t?wAZ%?}&*?K])%=?xR?bއ?}?=[?J?(g%?f)J?%g$AŻ?x?~Vw2 ?C^W0?Sxڜ?_ƴ?QQ?g+ў?zp/?phJVS?d_2Ջn?Z;BSά?Qg ?H׌I?AH :?:?$ՁH?2ݣ|?*ix?"b[0?5?}4?# >y> x˲>w0cQ>y\>mSȦ>8>š֜ľ>@KM >+Y>d 8>ѹ>Tl>qI7><d>:p,>)}> I?>W>]?M>ð>de>˿UT>%c>K.g1?x9?P&U>?#oZ?0q?=%{?J>V?V{U?b}$?lۘT?v5zsH?D ?YV?B P?ZLT?ˍQ?8?V? Lˠ?9(~?ΉȾ?[?S? c?џS#?4) g?!$2e? dbl??zy?vr:I?uxNݚj?wKU?}l8h?{_c?TG@?6E^?_?_3u??tz??t/?)l?lp8?5<2H?'X?P_ă?Mi?ˀ?[MI$?r?~?, [1?w_k?sio?sQW?v;Z?|.(h7.?ae@T_? w4?yK+?(X;? ń?1#|?B0.^?C*{?q'TCf?}?V\9,?eˬBY?Z?L/9`?pcWu?0&V?xфG?m0?as7>B?U6WV2?K74?B~?9#sr?29!?)fB?!XT?PHf?}zM?g[>DD>rv>RX>ݦ.R>_s$>΂ d>6>.ך>'q-&F>G>qK>%e>k> >O6>~.>VMk>Zӽ;>(v>_ >Wܜd!>ႜp>ƥP>s>=W? Lr­?;Y?%a0?2v«?@πPH?N~?Zqc?eb ?qL?zLkw?Z!V?<;?D$?zAg?`x?nYuxt0?p?t{?FB?A?x?Ve??bD`_?T'?.?Hp?,?)Q?;Hj ?{<?vn?uu*`]?w}[J?}֠{s?o7"?PgQ?Bv? o?,?+?d:z[?: 3t?e"c(?F_?4-?X?*{p?`W?%~%?k-霡?kh?|Gaܐg?w™6s?w c?x}?}p:c?FZ:?ZJ?y:?Vy?Jx#?̷?딌?8ګy?dx?Y&L?z͗0?OH>nXw>C5 >K?>d\v>>j3H(>9/= >>'Йr>őK>jrSm>:>GGSL>>>c>O9R>w)I>C `4O>Qsl>mvՓ>âF>-G> ݃(>)U>ߓ.>EUl? 思?e?'B?4*?X?B 8Zyj?PpGI?\@?gk@ѿ?r]n#h6?|`?Uw?IR?d8T?JԻl ?C:?U? 8J)?~,y0?Iӣ??iy7?cH>?W?z̈́v?$T?̨?9ǣ?j.?},R?zy⟲K?{TQڪ?0Ԡ?[te? km6*?7h? k?p?܃>d?ĐN~? Hs?kݿ?t QU?֓?,yk ?#T@?|v?}iY?3[YP?.&jMv?ke]#?ua4?J@͠6?~f{?b}(G? _?rO ?ƙ|?C ?lE:? [?8gP?o^'?:bHX?e@?2?`@-|?1;?mq?Ԕ4t?87p!?O?xI ?mOި?a1?U vT?I{~ x?=l?0]?$}*H?@?P?j%>NOV\H>1[8>Jj@@>ة[@>I9$> Z'>g. p>;FH >P>߇># >Hyh>}$T>wX> *N#>N)A>&c\3>WI>fe\Q>;io>QҒ>{or>G.>≔&E>ͩ>e#v? ϑ?ftR?':,j?44q|?B`L?P]t9=b?\z|?g$+{&?qzx?{-|?n0?2?1R?.*@Ua?niXi?/?+%?h?& ?8H?JfA?9AQ? ?B $?[4J?n^?jϹ?D:?x? ?V ?&o? `u:???Nhq:?}tf?aԳЙ?jr2+?Ȼg?xDn?ύd?wv ?OFC?"ըw? Q? ?M?EY0d?VnR? [W?{?ǭ@Ñ?K)?@%1#?ǵ?jw?B?;H*?n?B ?=P~h?Y+zC?F/{]Z?SN?oY? ?a"s?T[?""F?:~?r?TDK }?w,sFӾ?k2Y?`\#m6?RtG8?DZSKT?6@h?(v(?q)`?38?/t>UZ>:}p>ĭ#F>Җ0>Evv>۸ >ax>j rE>ϗʋR>.-3g>vLb>]3>4D>-̲ͬ->ȉ>ڍ>(c>><>*-ڍ)>ru0̸>YTި>-Rx>.1M>3M>jh>ju? %KD?6F?&%,5?3,ĵb?@KL?ND?Z-ޯ?e￐?p (w?x oQ?"Q?hqo@?h?Dذ?fq z?u?:Lrp?nR?f 6?YH?chvk?^ 7 ?dߞO?譓S(?ͳ??(?1?*Y1?{2?Dy?Ms?jl5?:NX?L%*z'?+{=??'?k{?O?މͷV?,e~???/_?澜 ,?<`?uO%?QSiU? \VY?]?ȟB?nw?loF?_?SA?Wџ(?f"Z?ʸ˘>?6B?z?Xx{Xr?ș?7ģj4?xn{?d4J?A:?2 ,?,c?D0J?O)?jT?bV.=?p|?u~?h++?[Įȼ?MT4u?>ϼa?0MEP?" u?D=?gYk>T6> >]H>>6l4R>/>mcfX>Q%>v[>/Q!>.o*&>?E'>wi#>fp> ߎ0> ] >A>2JVv?>{v>A>rC >([>ҤEv>)т>d<>~gT?z/aN?AU/l?$ cZ?1> WbT?=ۘ ?J?@`?VvԪ?aJ"\ ?k?sF&-D?|I?nX?vs?c%*?<{FE?cbC?ElbD?S1? I?th0? ?FE\R?͔],?}֒>? z?I6?;YU?bk?I87?a?;#T?>8?؄0?g x?Q?Pˎ?fm ?J-L?^?,?a}R?B\G??B%m?,?9 y?\E??BQy?*?1AR?Vڀs?yw?{ "ʟl?Ej??aE1?c@?/Kצ?}X{?~ 9?x1=?$?ת?^?Rb?WoS?q~?ߚYیS? l?;tM?GA?{I?}brڋ?DR?R?/1?Ed`u?rR?dBP?UCtI?E5?6; ć?'_?Zy?7``>u00>~.+>NCy>j|F~>,'>VŽ>@ֻT>rBH>U~W@>dk0>1=m>d)6>#%i>D>x]>T> ͺ>No\3> ^t>آ>ux>Pg!؊>2>܄\>j>=T ?pS?S5?!@Z?ڹm?e7YO?=غNX?ju?l "?3w/?ȳ?.?r9[?~OT?Jm?6~?'?GJe?I?n?8? y*?}aܟ?xd΁_?v 5?wT+%?|K?ʛ?9?ŧQj1?##B??7?,ap?EX?'܂??P\|?I\?$̘-?|scZ?y\pK?z? ?lsf?] ̀j$?L?=?.Hwnp?. G?o >|,Ƞ>A3x>>2:wh>C>;iH>Bt>>P>a`s>o%I!>~>x4>?{\>y>) 2+>bꯒ >o!~>@q>0>ׇm>5]>s'>7 >ڟ9?gF?f6Z?_3E5?(x \?4?A*‘?LSk]M?VsŹH?aYTb]?ii&q{?qi?x(?kIzH?\ 81?=P?[{?,_S0J?4F8.?m~x?S (?dd?=hQ?\g q??`?$w"*?DN?P;_>r?b(1?]Ő?iýZ?Z ?Rv?ӱ%I?M#^c?}8?yS]?y=}w?}J??4ɛP?%Fa? )W?Rv ?5 TQ,?INmڊ?|`|?$`,?ID?AF?o'L%?LpA?̡?Hݿ?+k`?Pl?Zo gwD?|=d^?vS?s}=?t'6?x9ܺ?lFl?E~?V U%?kV?]%? ??uY?L ?N1?V?*~?{;?b? ̦?Jɞk?r4?bk??Rs|[ F?B%*eH?2|F?#4?^?$*>P C~>" >MH>ETq} >ĝ>h> ޽>T>I>gzϏ>|q,>֗>Y$>Q5>z_> ?~>S >~[>U!wp>Q7Y >>O*r>0>,mI>,Tߠ>KbIi>プ5i> [>Jۇ? ,2?tۋ ?#I?0zǨ?:/?EH,?QAKB?[Fmz?e Ѳ|?n|?ut)L?|.rx?0Mk?gҏ?>5W|?U?Dj??Xa?>PZ?ȉ+?]$?o@w?%kۻ=?Q1?,b}?H&h]?4|?9?T?}Ja?,ǡ;?䩽IxZ?/g?{W?v%4Д?u|w ?x%`=?V樔?r+?;5 ?Ef?z!F?-)Gz? S?FXB?Ơ$?xO1?zѻ3?JE?]?@4?gm?~5j?h2?}W0?we,?u81f?v P;?zt(?؄}?f?BV?^Ȅ?hҧ?:ˁz?byq.?O_??~z?"YC?A:@?X`p?6F ?c?32c?u~^?f d?VRl݊?E^T?6a.>J?'2P?|8K? D>AR>0U\>@X>Ӕz> Af>!mJ> &>ua!>2 /A>{>l>"+y%P>#̥_><#i>u5q*>S;> 96>,@@7>vr> Y>:>ű >і(mp>> yV>lG/QH1>`d3?uG9S?LP??*09;D?5C=s20?A 8 Ԑ@?KiNR?V1?a=?kc֦?t P ?|J[V??LD?Sx?#P?A4? (|?Ea E?n 図?ԹY5?Rs?Z ?v? M?7??|~?C>G?F ^?LD E?R>Mz?7b5?|>7D>D3+ >LGЯ>̈́g>-ø>| >ʊz/>4D>E>|b>]8 >){j> Y>^>>~@>ʶ>Hq>xv>D>#uR>p>3ԋP> U P>hV!>qm>o? f@?mX?p)H?$r%"?0j]u?;hb?Fx/،?ST|=5l?`ws?j Md?t3&7}|?sں?=)46z?e׭^?K#!$?XD;?b?AN?5+c?S?ө? ;Co?NU?_s:?oD?[J[ 7?l1QU? KS?pY&Q?e9q*? -?Qg'.?K7ڃ?NN?}I(?}x?oLM?{+?'-%?B?A?}?bR~?RH?5a?_?k]?x?X#?hYa?u8֝?I}r?^Ȕ?|q??ǫb?yz#?j?Oc???]i?UI?se!?ќ5R|?=繀?$J?Ci?Qu?AqQ?( ? YP?T?X?x\?je_(d?[xPی?Lؒ$?>V@ ?0ys!@?! 2?/&?u\w*r>dp#/>"?> y >RȲ2>,и+>3t-0>V,U>oX>=PP>2kߚ>])>b>Q>ԝZ+$>d>}>]>ۿxn>w[>.z> )>yS&<>+|m>>)/>*J?H?he.?YM?+046C?77G?C "0?QW}{?^KlM^i?ji퀾?v^G?cB$?a?%Xo? |?*?'/}?1?l4? $}?2:t>?{P??b?%!?Mۚ#?s!??1 v?JDb?^z"?3>6*? _gA?<ֽ??m˶?vt?$Ub?{ΝB?CY?"΁l?;|uv?? ?}? ?^$??3zX?az?=Pr6/?}@E?c?uvF?4?rX6>!> >Qj!.>F9 z>A88>#">1d[>7U >B>9%>#b>>#bY>9%v>Bw>7V >1d\W ># h>A:>F9 >Qj> >!$>rX6#%V>sm>h9>W@`> K;`>ILL >%:">LW8 +>p}:>NB>* 4An>|> =>mcL>p/m>Ko,>Brƒz><*B,u>T0 >Ш>u .>yG`>Հ;pk>\T>-3>0 =?|{Sh2?_:ٰ?$z "M?3+?BX&?Q?| ?ay?pD?}9?a?UMH.?<_%v ?@2>? m#?S?-EY?AqU?}>ђ?Z?qrL?|7?-Z9??u?wǩ(?f?,?dp?F?S?=#p?? }ԟ?P?pڧ?v!?CLA?+?;nO?uf?N507[?dD?_?cep?D0?sΡ?SSJ?ϏO?kV?!L?r?|vNX ?n5?Qt(6?w;F?}e/???n?9?0&?a (W?\9?R9?-?co?':?YD?@b=??, O?BO?1N?8px?~v?r2R?g]o@?[ ?N>?AFk٘?5?N?){%?|^?Gta3?"ަD>AZ>a^J>Tmc>3>*T>->J4C>z>f>U5Й6>\>{Z;>c'+>m`q{r>f\% >Ðb>/S>^ > >_q9>*->ZK-@>ETs߸>$?E` ?F^? Ev4?.l?=ziL?Mqe?]>8^n?m z?{2i-?@d ?_??]$\?U(m?dYR. N?*F̭r??,eD?u?FWb?cx?zu~?AP?Ʌ?#'[i?$M?&E;Vt??+#t4?شx?`o?l?g&ؿ$?0h ?+1a?[ l?b8?!8R?_^}?Z6k?%ظb? ¿?:^?ܶ?tt?oXW?~w7?{xDY?|pX-?f$ M6?Yvli?{ݥ[?~>8&Y>3>*m}> 'L>͍0L >.>Tk`>ސ >@wk!>">xap&>Vp*>L5vm>FCC>7\>XDQ<>Ke>s\ǽ >?[]L>D$>~&4>Հn@>L_eNh>@M<>zx? q,?[hB?)O ?8*~ d?G-_5t?X4#پ?h$u?w["?(QK@!?b׷@?,w?*xEy?S1t?]?|v?RNk0?p?EI?C)֠?: ٶ?%?? oB?rM?zl(wR?y?{Gt?[ >]?w]T?o?d{=?X>6.?Mq<*?AITq?4:?(%8?Z? m9|N?K8̾k>|%>佞&>ΧQ4> K>+N3>j:>K6l>S"i~>.h>df>Xg/J}>C'>rJ>&W>|Sz>nn-/>[ݺ>Kw>48>~,>Ĺ) X>&7h>ܕ^A`>oy>(`?}O?]-K?$ڛ8?3_&Ց?B%t?SE ?cn?rV_?|A?WDڤ?zYݶ?%Ǟ?B?Ǔ ?)l?16? ?2Q?xyz?+~4?>(mj@?wAi?}W7m(?xl?w5('?zANs ?djR?&}?9@FP3?Ys-?f?\}?S-I?`E!?f)7X?vyqz?RQu?]9B?S&0?{_R?7f?>?`?L?! ?DFC?AȮF?R)&?B?A2?VG\?~y?P:g?.tE?$6?ᯤc?8VL??z3?)( M?ޖI?Ax.?4s*?[? ? h!2?O?J[vV?C?1Q3?'K?q ?R 6?{ŒI;?saa?i^Z?`Xd?S&f?G47(?:7ŝ?-)bqwh?!2 ?JI->觀Z%ߩ> x>ul>ēZ>K>C(r>X23>o[A>zޛ'V>BFn_>kl>>BFA>;^>Ա>4'S>,iG>F>IţP><kth>lғ'>W&A>XIČp>(>涋?ޒx|? ? ^;?.{?=2.k(?L֨?]wq@?k2$?yC =r?VC ?JEȺ?ID?/W7d?O;?m5F[?dL@?ѐb_?%*GT?h#?,*=?=F?}a?i}w?}4?|=eV?~J1a3?Xm?>x?.!?6? ?+?@RH?p??w,?A:h?υdG?w?S}'?uI+U?Vw?D9?gqNȝ?*0?4|?G_??:IÂ?Gde+2?ie?XI6?]s|?uLa?v#?'?uhٛ?*?~>D?u?/;6?h?jWv.?W,?E%?a))??>U,? ?8ٓ?7F?0w/.?pOo?L:?bЅ?x]gO?pM?e#>f?Y"?MK?@_KR?26μ4?$*?:?]pԼ>hFm>)٪>FI>,r>;ܲ*>'H>]n7>.IOӏ>">;Ն;>-(=V@>]κ>wV>2Ԃ>~s >g0N<> 9@>oI>=4>@l>T@T>Լm%>TRC|0>d> ,@? `YtPP?\5?'e:0?5N?D?THC8IXX?cP y( ?qb?~5)oP?J?}i?۷\Q?gض??>?~)?]e_?x6?1:҅?Oe?eZt?0%{?Bx?x?90?YQ? ~B?a?(%?U.?GVv ?֫7=?}jy3?m6?I?D*J??Sϖ0?+jH؇?<p?-1?0G(c??l07?kQ[06?W>n?ħ%?H7*?&e,'? Ӹx?J??PA\?z;cm?j\?hb`M?4 ?Lc'q?,rj1?]C^?©fH?g!F?`O? LD?yiw?9dOkl?3dl?Qh?*2?V-mj^?6g'??L`?Dn?t :?jSMu?`zF?R[vEu?C裢+Z?5mO7$?(,Iч?mC? GJJh>&\>>F g>h_z>Ȉc,>lX>oU>6>;+>da9>tK>mϨ>>K >>$>zt0>?x>^F>ybuC>B_7>c,.>*M>p8>%N >]klp?|E? ; ?"<3$ ?08h/à?=[SۊG?K~{1p?YYy?f]wL?s/2&>?=?t̉?#Jx?E0?r#+? ?mx?A8_‚>?0?F*/?8\%?*ݷE#D?;S?0bQ>#8)r>lC>GuG>>|#H>ȷ%<>rU>' >xBۣ>DD;9>66۴>&0>KQ`D>[Px;>N>"W>3>G>A~B>]s>SAP>< T>n猳>գ(jŐ> #'>%6@>Jj?ɵ2x?CL ?" `@?(d2?5`H~?B>x?P"?]9Gx?h ?s^Lcp?~L?>?z--?~̇?2콦?ݠ?{?!s? r¢?eW۽?5GHui?_s~?d| j?fj?D0O?֧?` ?M~?;>??%ތ?b$(?iI/?/ ?xW@?~\?Xr?NiR?THف?-~1U ?щ ?%S`J?lXR? {K9?=5G?k?]O?S3,?dmP?C)R'?j&o?'j?=* _9?IAj]?*5qm?1w3?*;?2h_?׊L9?W?k?ebD?UWDx?Gnw?3?=?A>(j?rz=?#P?1?{;#P?N{?5t?|#7 p8?q=G?d&DK.?W'@֪?H\q ?9?,&Y6o,?tdx?e`M?9^[I7>k71>67>֧i*>Ȁ@>HN">)9F> 3>`>އ> p>c>ؽ>}j7>oC{2>N{> >!>Jb>Wrl>.g7>с8>!H>E.Th>@>B?nR~v?.7_8?3ra?%i^*?1R?<J6k0?G#eP?Sl0`?_e?h l?sȊ?~d?e9?`(?Oe?r?=4?oID?'?ƚ?t4j? )?RU*?հu?qȊ1?_$^?y_?>:?mC0?3%?I?1?'t=h?C?a? ?I"?9\Z#?x??kHb?=r?J??*?n7?ڨa?Q2h?nU?ެ[?91?_h5>yɫ>֪y> X\ ?>hޡr>%Ӥ>-A>CW>5>7>1>!Qv>SңI">>ٸ#>i"YHZ>{UD ?>>æD>/H>כ%>kq 8>-Ս߬>{+E?xP?1C]?d*A?o6U?Zm/?V^]A? ]f?Mułp>%.x>FN">~7>hg>cGĝF>a`1>hyZ>H&ys>w,~->p>N\3>sf>˯TZ>H >$">zDO>fB>_& 4>Ȉa>Լ >߹JF>6eW~>L•>Õ@? jP̴?2S?Nt?$.ݰ?-3+vp?4x$'sD?<(B@?CwmP?rF?C@i ?$ ?AKw?b]kL?>r?An?.Aa ?|Rl7?z&x+?z.p?!?-wK?5 ?9Q??͹{&?.$7?ӌ?g?CH?~6?-y? N?@qZ?'5)>흽dLk>*Q>~K{>|PK>1I>bȖx>eŊ>>0K>}7>4d#ew>ag k>cn[>Us > f)L>DN>8>Ъ'>Uy>Uhu>pEC>D? Y:?YuSo?u?& ?/O?.?6ֿt??zw-?EZp?Ld?S&%X?ZNbP4?bQ]?lk#?uô?A gg?DK??(?9-9Y?6^?*z!?M4??PBO?HW?ݵ?, 1?|s?j?VRΩ?)I?8"?|]v?yJBo/?yٮId#?~9tL?r+0{?1G?h[nȺ?8G?;гf?v?с L?YJv?L(zGd?>]ܖT?1 aZX?#?J?6گIk>K|>JT > !o>|^WN>Č[Qk>UÛ>D1x>C$K>Lc;>Vi>1KuU>q _>T>o>lŸG,>D.e=>y<>|da4>-Ġn>Qwb >␏;>E+>?UD]yt\?h}Y?`=?'y8S(?1Ĥ?:w,r?C!1?K(Ip?R?m?YX1p?`߭t?fR,?m-?t~T?}@ϡ?LTq?_ɂ?H Z?c,?I?!xl?l~E ?.\?.If??8)W{?-U|?dS`?-ob?U]?o?ԫGh9E?a?搵?S|?:/v?;}ٹ?d?`b)zJ?Hz-?sؓ ?8Pd?{DN?_Z?v#?Wh]Z?O-?uH??IL?>P*?ͼ?{Ļ?j(?w?P %?UkH?k !?.I?X6:A?lS??;?yR K?!.i?kFU?u]eO?mU0?j2? ,?x @ #?p:/A?fp+?]Ph?Q˩>2?D:?6k~?*Q[?Пu?pJU?F(ra>7+=H?>7oa|>Tv>DŽ>*Ϻ>>w >ZFz>8><@>`sp>gϭM>҉>}@=>2n>T>]V%>]_1r>>󎴭<> m>LME?W #`?0?2?ns_?&j?2 Uƒ?='K?G|= ?QVx[?XŁ<$?a?g /M?nT"?s]?yYK ?-?"?;? ؋F?zR愧?BmT?[{?\c?Iw/v?Z)]@?t?a=9A? ?& 页?{治?򹟾?5v??3'? Ml?ĭ,2 ?cc1?\,?}T? w@w?YC?5W4?X=?M ?),2d?mI$?b?5#{?{ )>?z3ԁ? i!-?{D>?q?o3?*???b z?Vf?)h>Wj?bj?k9?& G]?s,?Z;?@?b?9ngH?]X?zqm3A?w?~9?wW1?-ؔ?JlP8 ??zIџ#?tR6?ml:\?dAa0D?]Մ\$?S B4?G[~&?;rN&?0GMJ?#M9?s? oi+>Q_>-(>+9C>&+i>i5>lgw>񉔳2>Jk6J]>;p>NQ>֝ o>l"?h>֝ o1>N>:>Jk6KT>񉔴H>lgwh>i5o>&+i)>+9>-I>Q_j? oi+?q?#M9?0GMJ?;rM?G[~?S B6?]Մ\0?dAa0R?ml:\?tR6?zIџ#??JlP8$?-ؔ?wW1?~=?w ?zqm3C?]X?9ngH?@?`?Z;?s,?& GS?k/?bj?)h>Wd?Vf ?b z???*?o3?q?{D>? i!-?z3ԁ?{ )>?5#{?d?mI&?),2f?;}ٹ?XLMFH> >󎴭>Nn>]_#>]V$>T>2x>~-> >gϭ>_A><>8}>ZF>w .>>*>DŽp.>Tv0>7o]Z>7+=D?F(nm?pJ ?П@?*Q?6k~?D:?Q˩>2?]Pc?fp+?p:/C?x @ .? ,?j2?mU+?u]eO?kFV?!.i?yR N??>?lS?X6:B?.I?k ?UkG?P %?w?j(?{Ļ?Ͱ?>P"?IL??uJ?O-?Wh]Z?v#!?_Z?{DQ?8Pd?sؓ ?Hz2?`b)zM?d?r+0{?of>v?HD?+e?#(+?߆e?Ļh E?:/L>E+>␏;>Qwb>-Ġn>|d`>y>D.d>lŸh>oq>1>q>1K˲N>Vh>L>C$v>D1u>V >Č[Qk>|^~z> !o>JT>K{ ?6گE??#?1 aZX?>]ܖ\?L(zGd?Yj>H?dj7b?p8#?x#@??r9?&Py`?l?D?6W?ϝA,?"$|?¥?ȡ S?᩾?p?=F?vt?4S?}?O?u~?L? 7ƥX?dn?l?~9tD >pEL>Uhh>UyJ>Ъ'1>8ݎ >DE> f(`>Us2>cn\l >ag"P>4d#e>}>/>>də>bȖ>1>|PK>~K{,>*Q$>흽dLh>)È? Tc??` ?'я£?46?C=҄?R%%?`:%?j?zE%?s?b]kJ?AKw?$ ?C@i ?rH?,3>?Lb?5?ݗf? ?uO?K2{k?lb?U?!w?|47P/?x =ڡ?w&[?zf/1~J?Aݙ?2%?j04?c*?eIi?m5ż?ꂐ?f;?/'T ?G#O?( Py?yc?nǃ?~={O?q.F?T$?s=]?/p&E?s֗P?h?_)??T*fÕl>L• >6eWF>߹J9>Լ>Ȉ>_& 4o>f>zDF>$>:r>˯V1>0>N]1>p`>w,~>H&|>hy>a`1>cG_>h/>~V>FN>%.>MułD?!B?v)y?*\\?7bVa?F6?Ur ?c0C ?ppi+?z9%=6?9C?/jE!?[W?{)K?5xX)? x?IpTl?Ǘ3?;?85"6?)L.t? e?R ? 2??x??\L?MDk?9Ű{+N@>-Ս4>kq$>כ%>/L>æD<>">{UC>i"Y<>ٸ:>=>SҤ+>!Q>>82g>>CW>->%Ӥ>hԶ> X\D>֪ >y˗>h6:?Br?Lv?Ed(y?,??9ug]J$?HY>?W;?dy#Y,?qpE:h?|^?Yݎ?"(=#?5/ݜ]?x&N?[<?rX?9ԃ]?Gi?+DC?Bb|?+7z5?]|y?)@V?P\Z?qR G?|GnA?1;$?)q߹?G`R?֢??79?/~}?_:?y_?_$Y?qȊ1?հp?RU(? )?t4e?ƚ ?'?oID?=4?r?Oe?`(?e9?~d4?sȄ?h l8?_e?Sl0?G#d?<J6k?1R?%i^*`?3ra?.7_?nR~y@>Bh>>E.v>IP>с̬>.gY>WrR>I>!m>>N{I>oC|>}k0>q>e >އCR>`#|> 3Ut>)9>HN#^>Ȁs>֧i8>6;>k73k?9^[I7K?e`K?tc?,&Y6m?9L?H\q ~?W'@֪?d&DK"?q=G?|#7 pA?5t?N{?{;#O?1?#P?rz=?A>(l?=?3?Gnv?UWDw?ebE?k?W?׊L;?2hh?*;?1w3?*5qm?IAjg?=* _8?'j?j&n?C)R%?dmJ?S3,?]N?k?=5E? {K5?lXR?%S`I?щ ?-~1U ?;K(?NiR?Xr?~\?xW@?/ ?iI8?b$.?%ތ??;G?M~?` ?֧?D0K?fj?d| f?_s~ ?5GHuc?eWۺ? r ?!s?{?ݠ?2콩?~̇ ?z--?>?~L?s^Lcx?h@?]9G?P"?B>h?5`H~`?(d1p?" ``?CL?ɵ2y>JjP>%6@נ> #'>գ(j >n猳`>< >S>]s T>A.>- >>"X>NX>[Q!>KQ`>&0#>66ᴙ>DD;8>xB,>' `>rWh>ȷ%b>|#P>GuO>lGH>#8'1?0bQ?;?*ݷE!|?8\%u?F*/ƺ?UZHH?bS?o<ZF?xlMͶ?#]j?URZ?rN9??rh?W?S$? ?C"t?::7?M?8?q8^8?o? 0ni?U ?A$P?1Ӽg?[I? *n?b_?^Z^}?p?~Np?ñ? Y=? '?5!??38?8)?OB::?7 ߶?{~?<p?pNUh?,h&?WRw?'|?^/)?HȊN?*]kp>%S>q>*M>c,.>B_7ƌ>ybt`>^F,>>O>z]R>$>>Kt>0>me2>s>daw>;>5>oT>l>Ȉc>h_$>F r>.>&Y? GJG?mB?(,IчT?5mO6?C裢+3?R[vEu?`z6?jSMr?t I?Dn?L`??6g"?V-mjR?*2?Qe?3dl?9dOkh?yiv? LD?`O?g!E?©fI?]C^?,rj1?Lc'w?4 ?hb`Q?j_?z;cq?PA\??J? Ӹx?&e,%?H7*?ħ%?W>e?kQ[03?l05??0G(c?-1?Vw?+jH؇?Sϖ0?D*J@?I?m6?}jy7?֫7= ?GVv ?U.?(%?a? ~B?YM?90?x?Bx?0%t?eZk?Oe?1:҅?x6?]e`?~*?>??gض?۷\Q?}l?J?~5)ol?qb?cP y( ?THC8IXP?D?5N8?'e: ?\50? `YtM> ,0>dP>TRCx>Լm>T@W>@ 4>=,>oIN> Cd>g0.>~r>2Mf>wo>]κ>-(<>;> \>.IO >]mh>'Hn>;ܲЪ>,v>FW>)>hFi?]pԸ?:^?$*?26μ3{?@_KR?MK?Y"?e#>e?pM"?x]gO?bЄ?L:?pOh?0w/&?7@?8ٔ??>U,??a)*?E%?W,?jWv.?h?/;8?u?~>D?*?uhٛ?'?v#?uLb?]s|?XI2?ie?Gde+3?:Iz??G_?4|?*0?gqNȚ?D9?{_R?uI+T?S}&?w?υdG?A:h?w,?p??@RI? ?+?6?.!?>x?Xj?~J1a3?|=eV?}4?i}}?}a?=B?,*=?h#?%*GV?ѐb`?dLA?m5F_?O;?/W7g?ID?JEȺ?VC ?yC =r?k2$?]wq0?L֠?=2.j`?.{p? ^;? ?ޒx{>涋8>/>XIČ(>W&A>lғT><kx>Iţ>F|>,i8>4'X>GK>;_D>B{>kl?[>BFŚ>zޛ%>o[@/>X/\>C(>>ēZs>u> y >>觀Z%>I(?`Z5r8?J}?!2 ?-)bqv9?:7Ŝ?G46?S&?7f??S&-?]9@?RQu?vyq{?f)7X?`E!?S-I?\}?f?Ys-?9@FP3?&}?djU?zANs?w5('?xl?}W7m.?wAi?>(mjE?+~2?xyz?2Q?!?16?)l!?Ǔ?B?%Ǣ?zYݶ?WDڶ?|A?rV_?cn?SE ?B%,?3_&Ց?$ڛ?]-K?}O>(>o~>ܕ^Ao>&7h>Ĺ) G>~N>4T>K|>[Z>nn,s>|a>&>rK)>C({>Xg.F>dd>,>S"i>K6l?>j:a>+N> Kf>ΧQV>佞>|~?K8̾f? m9wL?Z?(%8?4:&?AIT:?Mq;?X>6.?d{=?o?w]T?[ >^?>Gt? !v?N?^ir?[&w?`?ŏ3zx?f?07?W_;?5Je^k? <\A ?dm? ?\.A?I"'?$?&ý?׎n\?3j??-?q䛢?m?z3X?y@p?}%??x/6?$^)?y%I?HR[B? ¿?A;?*?2Ө?u?$?VY5Β??L?2ñ'? ˺?;3?TD?r1?{z >@M@<>L_eE>Հn@Ǭ>~&h>DF>?[>s\ǼY>K]>XDP>7B>FCD P>L5vns>WvQ>xas>"ہ>@w>ސ k>Ti>.>͍0 > 'a>*m>3>8&>~???#z?0OC{?:N?Fg?S6qv?`tg熤?j351?tHhX?~f};\? S!:?arҬ?q?am]?nA:??0 0+?";0?ka?؁?%A1?d?d<8?b8?ʇi?_?黖a?gI@?dk1?Koө?8^?Mqe?=zid?.l? EvN?F^r?E`>>ETsl>ZK68>*-4>_q^L>>^ N>/S.>Ðb=>f\ H>m`qj >c($>{[>]0>U5И>f'>y">J4Bl>>*T>3>Tn>a^7>Aȴ?"ަ@A?Gta?|?){%?5?M?AFk8?N>?[ ?g]oL?r2R$?~v?8py?1N?BP?, T??@b=?YF?':?co?-?R9?\8?a (S?0&?9?k???}e/?w;F?Qt(4?n5?|vNX?r?!T?kV?ϏJ?SSJ?sΤ?D1?cep?e%t?dC?N507X?ua?;nN?&?CLђ?AqU?-EY?S? m#?@2>?<_%v?UMH0?}9?^?pD?ay?Q?|?BX&?3+q?$z "?_:?|{Sg>0 =,>-3>\\>Հ;pl>ym">u | >Ш >TM><*BΓE>Br5p>LR>pt >mcLM> u>{B>* 4>NM>p}p#>LW8a>%;&>ILb> K;w>W7>h>s]>#%N?3UuU?qn(?#{5OM?0Z]?<3K?Iu5D?WC{@?d\|?qD`n?~?8XI?΍E?@32?]?'A? ^$N?Ry$?< Z?1,?qN:?e55?i-F%?D5?e?cXKX?'bI?mj2?yBgx?"g,?Q%y?!@6Q?g:?ȱ8?t*?u;?u^P-?hqP?K?4 9LJ?o?LczCI?Nh8 H?V??^ ֬?Q-]?8 ?6=A?d%*v?]?{?[?m?c_?~o]? /?. 44?MOת?>??Dp?5h?N>?)ir? Y\?p?3rM+ ?P521e>˱>O">`-K>Rm3x>τ>MZ>/ D>]#4T>:Ԛ>ӀC>!/M>GC>!.ff>ӀD>:N>]#4(>/ DEz>M>τۖ>Rm3F>`>O>˱>521T?i.? ?!3I?/T.h?=?5d?Dp?>??MOס?. 40? /?~o]?c_?m ?{?a?]?d%*v?6=G?8 ?Q-]?^ ֬?V? ?ᅺ?y|8? kq?z7h?)? AT?l$Zj?4?۞a?v<3?g] ?t?]PEZ?ԭ)Eh?p&?iE?x[KM?k׮n?_<>囌?P「{?B#e?4?'19 ?8;rb? NNH6>RO> /E>4>iZ9Q>ʉmY4> ?y>5 ">$C!>_L>-3->e>:/>5%g>nxkp> L >lL[>Jq=߹>"xZ>P>|> >p>ح>^flR>qs}> J? 7hF?&`e?(5?60m?FS?U^tՃ?d7$)?oCY?֠?!??4?4L?BJ?RO?o?R\[a?#?B7?TK3? /C?Ά?}7M? }p?&?7/)?tܣ}Q?I ;W)?VY}b?N5??ȻFaX?׎? 4>?@?{nT2?֪R?UgJQ?yIG3_?{V?pi&ä"?cɁ?TTN:?F6?:]M]?/_BJ=?!2ڐ?͸?<>2k>aF>nb}>[~@>Qf$*>o9a>q (y>o9&X1>RalG>1>QZ2>p> מ">K>Z|/>s>t9JԿB>v_>VK>Ū^6>ѩWώ>||>@E@>y2?qw(\?(b/?"C偋?1(u?A N?Q}?a$Bb+?pH̑?[W?="V?jd?6[?5R? ?WF-;?L?Ry Zj?TB?4?|?ޜ߅+?:NО?sV{? ?q:`?`:?k屶?z~{?h?T_k?~w?Vj.?}(?~Dt?G2)?Xr?Ԡ1\p?ҹ?E =h9?JY?-?L+ ?Qܞ?Zw?ki?dш?$;Z?ZGM'?P?JrI?yn@fT?`yWڔ?=k,OJ">M> f0E>ճM>C%f<>PO>z.:rq>L>TiM<>S׿~>[>pd>L L>]~,>p8k^>ɼ1)а>StU8>f2g>I:f>gcx>>ʳn1X>p>Ǽ>3mFe?R,?{?2{-?+@#J?::T?Joͨ?[d1?j +?y Im?d"x?c8r9?eJ-?Jde?è ?P ?0d?- ?0?pZ?&S?Ԩ?4 ? ?|8WO?{Wտd?~hcDf?N1?%Û?$? ?#|23u?]̠L ?L ?W$?tЮ?e?P?BH}#?̼eR?*#+@/?oC!e?Abq?ğ7? fٔ?6{?fjFA?~88?{^}zcm?|wX~?i̱7+?򸐎ʯ?S?vWi&?ُ>mV>?>ڤmN >SX>q8>옎w>~>n<l>  V>zbG>(ȳ CE>8> T>^ŭ>3>9SM>sj>.>.+z>ۊŬ> VuGo>Ѧ`!>W7>ʹ`>߆B?hY8?ƹx?%y?4?K)?D$ᬦ=@?TLB?d*wM?r˸?$(u$?S*?,=~?*?s?)ڣ?Gkp? /;? 5?h!^?Y(s#(?]xX? M?zOu"?zho?yMp?|£C?(yg?>6=?[9??cƴv?d ?ǿ?*?joH?n8[? Ⅶ?3R_m?f il?cĂ?ۨ?SN6`?G'gdlZ? ?{9?ѷf? ݠ?FaSa?aA?i]u?>U3?;zlE?@!%?SH ?BJ@?e?g?jdi6?{i?U|? w]?h:|r?Ǐ??"AZk?/?v?TX" ?CQ?Pf;E?YT?l/?;s ?VB?}\)'4>?riG|?g9[a?[i8'(1?NHn?@Mz ?2]0?$ZFÜ?F?nk?ہ.b>d> o^>U$o>ͩDl>ćc|>âB>N>°>8MQZ>bͳt)> H1C> >fO>B2>KJO>濧>7;>٭bqc>}c>ԯ >ۄ>KVp>ץU@>=Ɖ>]\Jh?."?i9Z? Lj ?/eǼ0?=$P?L8Gtp?\U?k)b* 5?ƒ\a?ޑ?8`? 1? ?,v?,h?'jd,ƶ?d?@M-,?Er#L1???hM? 68?W*?+  c?s>?Ļ:?Ntcd?@??q&?{ ?Vi?,.i?x`J?n!X?bW;j?TEAF?E5z%A?6< >}?)*T˶?GU%? =^i>{>"M>'>{Ƙq>ǁ z>ŹJ>cT6J>?sRL>l,>8x˳>ar~>>S$.>Mnop>^xN>5>>=laZl>a4>D>IT>b=`>˂DR>7 >>`>Z/S6>'9? "2??'(Y?5@?DÀTK?SJ0?b'"bR?o1Cx?zs?5z;?p?z6?(1?&?V~?l?>i^n?ҟ$?v`dT?[g?[.:4?U1?&HT`!?tW5?E͈"?ٚ6?]i1]?`\E?.jk?3 2?E(?4<%?$4zJ?fԗ?5 ?˞A"?\Y?C?xw?f3m?Vo?phop?zMDB?o E? ?d˜?S?r ?ٴ@?E$y?|]L?PpB?sPS?f7z?YH)J?Jj?;,"?-Zi[V? KMM?C1?kqzz>I>ٽz@ݡ>m >}ճ.CR>W>, >`$I3>>Wi.>_8>C>>jr\>+Z0>p8<>y_^>1GJ>`xF>|& >JAt$>:s|]7>i>Bg6 >Փ0 >"G8>tB>C?:'e?e0?"0}w/?/ש?;ط*?IX!t?W/9-X?d>r,X?p5?yJ?Lʱb ?g\? } K?łӪ_$?0~0ʒZ?D?n?]tHt?wYY?Ԧ?٧sn?;CF%?8>?7i?Pl#?¼ԡ?&GQs?]F?R3"T??#]?q4!?4?P? ?9yP?N??uO?qnV'O?b@?C?+&?C?&$[?Xˆ?Fuy%?-D?J!?)Nc-?! "?;Gv?.?sE?4R?0ۺ?urd?UY'38?Ihp_??Ojz?( i\?edVz?XO*s3?-&b?c)V f?8MX?pnJ?e??A|g?mÇ :?A='?56?wB ?jR ?]6刌?Nd ?>楎S>?0_i?" o`H?N?р>,KV>D>=Wŝ>65P;>*hSzk> 4#>Rl>q7l>0j.̥>NM>ǝ /I>/ J>J+ի>><)D>E'\L>ϳ'>۹H8>pD>T1%$>̜8xЭ>LM>b+>Dd >?L$t?dto?dj?(4?4_;?A^ ?I=?NtEK ?Yx-\`?dxr?ol?wm*P?k?)VkA?aJ$?gTc>ǖ >ّJ M>Rg>OgN>ğ E:>yۧU>D}>~Y>Ct>"n>JT>^P?s>$$>Nl>3I>z>5-f>&Z>Ǒ(p>52>,H>M`>qJ> g@?˂)Q%? h?֨+?&)5(?1";hsP?:R?EVD3 ?Q[y^EH?Zﮟ`?d-=d?nM?vS*,?e?9*;e?TJN?8?fF*? v?/? ;E?}i?i ?0v>U?=D?|Yp?ԫd?ʍH? ?y?)F?zf3?T?+@W@?cԋy?;>?+?g_e??b? , a? W|?u(T?7jA?.a?7 F?j ??.J kZ?Ac*?B ?aYX?;cO?n ?$3s?+t?{g>C?rx?ui2O?&a?Qٲ?c,?(xy?)?je?/5%? ?47n ?"kf?e]%?O?y?_?å?vuҰ?(?z _a?mi|0!w@?`A4 ?P~uا?@x/?19Ck?"ϢD?xP o?*fy>6Jb$>ύ>ْO\>b>(e>2 X >#>I^G5>WYrk>?>u>{n>{nYH>*kn,S>KF*>~ȗ>X>YvJ>~>u\ɳ>&&ä>-<>윩Q>|È?5H? hX?cƆb? $[s?(NÝ?1~n-T?9#5oP?B B?Jj^#0?Sh&l?]O/?f ")?ppO?xGr? "?c ? u"?-B?@$?s]&2\?l??t?/J?⫙o?}W?_طXL%?e]"?q*̒?d:Βĺ?k&&?Sp8Čf?}B1?g푑?0a}g?$?"7?7Էt?K䥺?Z}?YGF?cƐ?kv-?E]@?`~i? ?IN9?ݬ?c&?{-?SQ?//>?+?Kg_?M+>?Ki?g0n'l?7^?w \t?kkI?]d!R?Nc?>-p?0*L?!%n?-4ǟ?gTS>$>{fp>p\w>ɮHy>~`3=>>>ޭpu>3f@!>rq~MN >Q|_:->M^>Ï>{>Q'&8>979>snh> l#>ʲlL>א ,a>&_>m">ܳC?:F2?C)?= '?dex?;"ڮ??f/OS.?svZ.*?fTtt?X>8?IrԔ5?:k=y?,W?~>Me?DY>֋>?#>N%!>֛P/5>I%j>u%<>Fty>O:R>:p>-R>*6d*u>>$->ZP>uK>ʱu͗>̬>C)>>Jy >ݜ`9>1auY8>[U>?}? Z 8?,0?"A\&?*L&?3.@̠?? \>v>ma>gwh>FH>]fJA>J{>.>sM>H>""4Z>F"" >["\>K> >z`=>S kk>>F>K"H>ٹV>zF6>b:RR>uD? m"y?>?"?,-'=?6H)њ N?AOI?IG'>/?R=Xz%?X8 ?^ `?cQƀ?gi H?m##qnx?rYB?w޳/???k, ?ճ-s?O9?.m6B?en#?4N?Zl?i? q?/օ?l,?2@Z?5GF?އ?'D?2Z?|POo?}W8?rc?LcD?qDVn?} k?:,?KRm?!zU!?2t$?޳tf? :t?oe?-?tR?򙒔?CG?V9{?S'u?p+9?=LJsQ?pe?#Rb??S{?u?V K?b@,_?tCVi?+Y?+x8? ?&^?(Ν?r?):u?w-Q?oFo)?dOj ?X^f?KB?=D,*?0^8!?" ,?<까? jc/x>讦/v>2} >vJXI>ƒД0>,{>7A>v~; >Լ->1,>0jO>٘>С >5vUW>xWJ>\(>ޅc]>A|i>>7]>dO`>|Y H> r?2zv??!,U?+&?6j~?B;Y?N I7?WqH1?`P ?f>˘?lŘI( ?q k?u*n ?yG\?~cT?Wh ?Ii8?Clg?a?h ?5?S-$?Dek?E|W}?贈\?N\9? l۴?ʝ q?fs5~W2?%=e??hqAc?p^*?~L?!ն?f?}G5?{r?(#ke?$?z>d>5v>r:l>ؿ&>iu>@>P;Ξ>B>:"q>e>^7'>>_W>^7&8>e4>:">B2>P< >@>iv5>ؿ¦o>r:T>5v>d*??$_?(#ke?4k-> ?Ao?Op#?ZU@?cQ?l̞=?s(?zJcV?b8?BX?KCB?-B?.,?w:l?yt?uD?fn?YH?o+?-ʚͤ?C?|%T ?Lx~?b?*1?EL?0z?}?L? 6?u~,P)?? ?OxZ?sJ?')?g1?Hel?s?rc?UD?Ct?);?,B?{r˘?`P?WqH0?N I7?B;?6j~c?+&?!,ݬ?#?2zv> u>|Yl>dOd>>7>A|>ޅc]Z>\>xWc >5vTP >С{A>ٙŞ>0~>>Լ->v~G&>7Aߒ>,>ƒЌ>vJXk>2} >讦/6>c/̩? j=(?<깇?" ,n?0^8"?=D,ܯ?K?X^b?dOj ?oFo.?w-Z?):u?r?(Ν?&^? ?+xGF ?Ns+?&~|j?0]Bl?d?1[[?:Q?5?w޳/?rYB?m##qnP?gi G?cQƀ?^ ,?X8 ¦?R=Xz?IG'>0?AOI?6H)њ ?,-'=?"?>? m"{ >uD,>b:Y>zF6#8>ٹVc>K"$>>Ff>S kJ>z`gU>W>KTo>[!>F"#Y>""32>H>r>>J&>]fJQ>F>g>ma>ʞ>? ? J?tȺ{x?'٪ɐ?5]3H?DB26D?S)a٤?a]Ը*?mD"j?wu՘?2?Bv:?rt?d? ڴwP?"pj?~U? 4? p*?؋*,?\[?br ?+s?ԮfI?z6$U?]-Y.?;? 6o?JL?ES J=?WZ?Dm?}OM??QGfe?a?Z&? v-6?#? e.?y ?`?=?B?Z/Ԇ6?sp:8?0?͖=?簐uz?7вH&?=#?{ڟl!?{`?#?|[ ?*??\?u?a ?kzՎ??yJv?M?u+mf?b;(\?$8rb?&D9?a ?q2ĉ?79J ~?V=?r;?x?e/p?q #k#,?g#;,8?a{Sl?Ze?Uy=| ?P/դ?J"}CO\?CY?e>[U(>1au>ݜe>Jy>C)>->E>ʱǘ>uKx>Z>$->y>*6b>->:>O:>F̴>u%>>I%SY>֛P/K9>N%>?#>֋?DYe?~>H?,W?:k=yP?Irԓ?X>8?fTtt?svZ.)?f/OS0??;"گ?dex?= '?*U~Թ>?VX)a?i$?ka?8R?MCk?o^?_17?Ԥ#e?Դ,=C?CK*?r+?D2e,q?|bK1?{sE ?R??/r^?ԏA? A?}RR5?RW; ?NYi?̜З`?1Fh?2~ݸ?_t$?ە?2U?p;-I?CD$?Z}?ȵA^?47O?SĉIC?}b&X?y9!.?y肜?}N?"ʍ?qVK?/H ?vPl?y?m̀8t?_6h7?7+?:O?v*J?'hS?$y%? 8(n?,w?wĪi?h}4?d?5,?v|΢?nq?cy2^?Zة?R8?Kuː?D5y??x6E?7eu?0RK?'{d? bd8?*&ceV?C- ?:F6>ܳCʄ>m#L>A>א ]>ʲlL> l5>sn>9W>Q'->{>>M^J8>Q|_Q>rq~K>3fAN>ޭs> F>>~`3U>ɮ&P>p\̇a>{fV>!?gTS?-4ǟ|?!%lC?0*Lw?>-?Nc?]d!R?kkI?w \s?7^?g0n'l?Ki ?M+>?Kg_?+?//>?SP?>-?De?b-?R~F?W)$|p>윩Q(>->&&>u\>~>Yu,>Wx>~x>Kt8>*kmu>{nYI`>|>u>?>WYrl>I^Fk>#y>2 u>('>>ْO>x>6J`?*eg?xP n?"ϢD?19Ck ?@x/?P~uا?`A4 ?mi|0!wD?z _a?,?vuҰ?å?_?y?O?e]%?"kf?47n ? ?/5&?je?*?(xy?c0?Qٶ?&a?ui2[?rx?{g>C?+t?$3s ?n?;cP?aYX?B ?Ac*?.J kZ??j?7 F?.a?7jA?u(U? W}?,Gׅ'??b?g_e?+?;??cԋ~?+@W>?T ?zf3?)H?y??ʍH?ԫc?|Yp?=@?0v>U?i ?}i? ;D?/? v?fF+?8?TJN?9*;n?e?vS*>?nM?d-=d?Zﮟ0?Q[y^E?EVD2?:R0?1";hs?&)5'?֨*? hP?˂)Q&p> l>qR>M`x>,H/x>52ΰ>Ǒ(oX>&[>5-f>K>3Iw>Nz>$>^P>JŁ->">Ct9>~E>D|tF>yUj>ğ F,>OgNۛ~>R3G>ّJ >ǖ>gT`?Np L?!D?"]g?1JDqsQ?@z?P~D?` 5`?m<w?y@&?p2]?0Z?CB-?W 7?eL?9lђ?UwF?}6?z8?̂B?+ea"Q?.?2%t?Q̥F?P =?c㘠?1jٻ?[HH? 8}}?T?\u?|Wx ?BFH?;a5?d9E?Fe/?7?3?.b?RaF?#L? 1V?-?X8?=?uO?b?BR}?3?ɒ:? 02?R?\i ? 9ڣ?*Nى?P?4?ah?e< s7E?9b"W?)sF?fS=4?oC&r?$3{ި? ~PՅ?zj?L[O?OB\?}lBh? >Dd >b+>Lc>̜8x>T1%>q>۹>ϳ'>E'B>>J+,>/ OT>ǝ 0>NM(>0j.>q7g>(> >*hS >65P>=WŖ>Dʹ>,G,?·??" o_?0_i?>楎S*?Nd l?]6列?jR?wB ?5?;CF%?٧sn?Ԧ?wYY?]tHr?l?D?0~0ʒY?łӪ_*? } P?g\?Lʱb?yJ?p5?d>r,X?W/9-X?IX!tP?;ط*?/ש`?"0}w/?e?:'c>CÀ>tB0>"A>Փ0#`>Bg6>j#>:s|]+H>JAtS>|&>`xF>1G.>yv>p8<>+Z>jr[>C>>@>Wd>:>`$J?>W>+>}ճ.s>m|>ٽz@j>-?kqv?Cһ? KMd?-Zi[Vx?;,"?Jjn?YH)J?f7z?sPS?PpL?|]H?E$y?ٴC?r?S?dš?> ?C?w?nƈ?(/?b|?*?f\"kD1?o;Z?|$%m?(ؤ ?Au?? 7/?Y(?p?\B?c4}?m4 ?C4¸?]f?".'[8?i^l?l?V~?&?(7?z6?p?5z;?zs?o1Cx?b'"bR?SJ?DÀTK?5?P?'(Z?? "2>'9@>Z/S1`>8>7 >˂DdP>b=4@>IT>D>a->=la(>6 >^c>Mno5<>S$ъ>s->ar>8x>l(>?s7>cT65I>ŸҶ>ǁ zIN>{Ƙh>'>"B>{D? =TP?GU#p?)*T>?6< >}?+  `?W*? 68?hN???>L/?Er# 5?U ?|CNh?1 ?*w\?,5?m/,?@?ۨ?QCV~?-;?r|ȼ?WHC?dX*?!ƙ?-U??ev??=r?Vd?]ڙa?Z AP?4Ă>?@ND?k?Gdu79?nO?)?zkM_?)?,{}?ojt?P|?W?!1i?7\?τb?0={?/C6?w턊]?k)b*]\J>=ƅ>ץU°>KF>ۜ>ԯ X>}x>٭bp>7;>)>KJO}|>B2|>fҋ>p> H1>bͳt}>8Ki>°ʅ$>y>á>ćc>ͩDm0>U$> n|>?ہ.X?F?nP?$ZF?2]0?@Mz z?NHn?[i8'(1?g9[a?riG|?}\)'46?VF?;s ?l/?YR?Pf;H?CQ?TX" ?v?/?"AZk??ǎ?h:|r? w]?U|?{h?jdi6?g?e?BJA?SH ?@!&?;zlD?>U3?i]u?aA?FaSS? ݠ?ѷf?{7? ?G'gdlR?SN6_?ğ7?cĂ?f il?3R_m? Ⅶ?n8[?joH?*?ǿ?d ?cƴw??[7?>6B?(yg?|£\?yMr?zho?zOu"? M?]xX?Y(s#%?h!_? 5? /߆;>ʹ>WR>Ѧ`!> VuG>ۊ >.+y>묦>s>9SM2>>^V>pA>8'>(ȳ h>zb_> r>n<w>>?>q>SwT>ڤmN>?>mV?ن?vWi? cP?-+z[?:3 :]-?GmH?TJc #?aD^W?m#"?wH^?-?͹B ?Hp֘?~U?H?ta?~ݣĆ?9l? =n`?t y?!ȖL?8?Фvc?K|?4ԀV? ?#`?cv? }?B%? eX?k7 E?]+O? r?S=?򸐎ʬ?i̱7'?|wX~?{^}zct?~84?fjFA?6{? fٓ?d?Abq?oC!e?*#+@.?̼eP?BH}!?e?N?tЮ?W"?L ?]̠L ?#|23u?$? ?%Ý?NC?~hcDf?{Wտd?|8W\??4 ?ԩ?&Q?pZ?0?- ?0e?P ?è?Jde?eJ/?c8r9?d"x?y Im?j +?[d1?Jox?::T?+@#Jp?2{+?{?R,޸>3mFf>H>p>ʳnh>">gc>I:f>f2@>StV>ɼ1)8>p8jw>]~->L M8>p`>>S׿3>Ti>L>z.:V>">C%f>ճM> f0 >(>J? Μn?|:?'a 4?4G?A5{q5?N ` ?Z@_?gI~?sJe?~?%?=k,OB?H>ڑ?NߧF?Vj???nb?_u ?`yW=?yn@fT?JrI?P?ZGM'?$;Z?dш?ki?Zw?Qܞ?L+ ?-?JY?E =h8?ҹ?Ԡ1\s?Xv?G2 ?~Dt?}(?$>j2?6Y?J3B?t?2_W?g*A4.?F,5F??B8?yR?n͖&?ogm\?'s?Vy54>@EbH>||>ѩW>Ū_#>Vm>v>9JԿ]B>ts>Z|ٯ|>Kd> >eF>QZM>1P>Ral>o9&Rg>q J>o9Y>Qf|>[~>nb}}>aF>2k??׎?ȻFaY?N5??VY}b?I ;W)?tܣ}Q?7/(?&? }p?}7M?Ά? /C?TK3?B4?#?R\[^?o?RO?BJ?4L?4??!?֠?oCY?>7$+?ᅺ?k?x}?O#g#?laa??S16?h?28?jd6?⠗F}?3x-?zt:6?miQ ?"Ғ?Fqf? Iv?δ8r?ğx?1YQ?~?J?%U Mh>qs֏>^fe>حؚ>p1> Ҧ>{>O>"x2>Jq=&>lK> Ll>nxl>5>:.>ef>-3>_z>$ь>5 > >ʉmY7P>iZ9] >4 > +.>R ? NNHN?8;ra囏?k׮n?x[KM?iE?p#?ԭ)Ec?]PE\?t?g] ?v<3?۞e?6?l$Zk? AT?,?B>h??u20?,&ʷr)?]o?gZ E?\7Xd??~1?O?nH4?'Ky?~qx?ˤj?LMdQ?N? 6l?z7=? kr?y|;?θb?*}?FSKE(?\k>?VWZ?? I?^P?\.?GZ? tQJ?l?he1?~ ?A,?U`?w(!?b?Ma|H?~W? E?z?)?l$2?˩td6?_)?l}(j? fJ?|Ţ?n#Dl?`GZ]O?Q)D ?A+?2˿ L?$(AM?G?J?HM>P >9G>IM>/]4F>#$>m;;>+>;>bT\>^c%K>>7;*>z>JZ>7;)>>^c%Kw8>bTh>;a>+x>m;>#$ >/]4F>IS>9G>P ?HI?G?J?$(AMl?2˿ b?A+?Q)D ?`GZ]O%?n#D\?|Ţ? fE?l}(h?_)?˩td6?l$2?)?z? E?~V?Ma|H?h>b?+c?"_?mJZ`+??=??FSKE*?*}?!?1en?,ۆ?h,i?}W-h?e ]C?US?M?Y7?P+/??k"H?ļc%?8۾Wf?k0?좨 ?ZǷ}?k??T`i|?nMP(?ex?}d?r_˺k?d.U?Ua8P?Fza$g,?8;9?,?*?_hxP>J>}hN >̵>.ޒVv>!_ϓ>j>Ep>&O@>6kQ>ͤ>k_7>j3>0>Z> m1 >0 \>|6Xn>^>2S>ݬ>1>&+(>c,؊7?P{}Z|?"G S?*gEQ?+X?; a*x?K )?Z3q J ?hH7X?wb]~p?A:?Ӯu?8 ? &?e?x+??[?nW?V/?b?Ŀ?!h+H?@ti&?R~:? P?kll?IJH?nj`f?=?[̇?צ?M)?ߑVΕ ?f ?^Ǝt?k@?Z,^?w xq?|Kw?WL?J?ᳺO=?!,ж?r?+*S?R(}<?F;? V?1? *Gѧ?6hr.?f?P@P{?? +u?#}?y4?eN?4 2nt? #Im?$Ae?16uP?Dz: u?9R?C@Y?+Z4:?sFo?3?Ƭ?$-?&h?NbS?^9? o-l??v`~1?ijuh2?[T}?M$ֱ?@?2Yy?%4%W?(a3:?z;R>P8XH)>S0>᧫z`q>"4 >ĵ>aA>':>6'>Q7U>8?>z?>v:>]>fL>h>ή>zCA>KEN>W_>ӰŰ>X>'>'2x>f=>1۸?1r_h?'z(?$yԆH?4̢^ ?DvkoP?T^s6#U^?cy ?r{mW+? |?E?)?֯?`X'?gJh?NYm?*n0?R4?6'bH??uh&?8ck?&V?F3? @? f?XfXxb^?1?3}?(?Y?pF ?/b;[~?Nl#?҅?*R|?L).ҟ?j y?$I`u?<.?}(?zq^?|)q/Q?Vj?sh?]{?,?"2?'e?xB? 7$?qo?_kI?eH?nÈQ?|2?H?)9? ?ӟuY7?D*r?Q1?j:>9?y?#ŹT ?yШ{?Q?%G^?|J,?. L?ku=VB?E ui?{h?px?bS?SF,?EsT?8|[?+1-|?ANyp?o\#GT?0pb>5@>]koV5>؋|>&G>/>8 >Mwn>p >R'C>++b>atK>>ق o>DZ>A>N蛍>@PY>}-\ >AE"L>CO>Cgd>SlS>E><9,F??!?lkhXKh>W&>++G>ne18>Vբ2>VLbQ>s2O>q1>d1>Ƈ~>b>lT!+>L,Lw>գp>A_a>>w\J>R\&>9d>+>o D>7\i>ҪK>f8a >z<0>=\i? ?֝p?&adFy1?5Ā?E'2?UP,?d|?rU*N?ǖ?ʑ}Z?9?u0?򴫙R?)^mc?W<@?6 h?~Ap*?֤i䮎?*15k?X/G? 5to? j?h:N?88?YJ?Xwx?Zn`?xY4{?䖫:2>m >þ>St>. w؅>$UWƑ&>M*~>UJV>لW>l]'>S>$ #>ER%&>׻>c7kMO>u>#灂>[0t>BD>]"Qg><](>ϣ5>->pܯP@>:.?}?EzEf?!.}?0u`?>]?M]5?\50?i/`?vcSyx?U?W9Z?cq#g?Ɇ\?ጷg1?dk[{4?؅ .?[V?+?'x?Z;_? ?}-u\?}ɑ,?/c?%ˣv?BC~?V^?ezF?46v?^)?bψ?Ty?N? ?yj?.g? 6^?)n?mgD?yH?bC? q?]?I7?Kv4?P/p?Rҁ?}?o W??k2?i^ ?יq?.?r=:)?8gWJ?Gv?3r?\wJ?Uka\?G?/'??;_?s;Q?b_vs$?)l\K?ĝQ:4?"%'R^?Xb{*?o U?O_x?n@??Rda?4fk?x>x?hp ?t$~?gE'?Zc?Kx@rt?<k_@?-lr3߳? F?xƪ!Z?y1M>_I\>Π%$>ֲ9E>w%x>+5>1G>bm^6?>DeH:>t>RF>T>">D;>{:>F̋~*>K9I9}>Ų .rH>%k( >J >«8>t)m>DJ>ZJ@>œ&>/O? nK`?c?'? ?5SB@?C==RP?R^!S?`ӭH?l`H?v?x~?FS? 3pQ?)gt?Ő^?kȀ+R?K]~?nI_?;Jt?xm??izb?F-j?-?;N?I? w(xX?0 Ʃm?U[0?LUt?uXB?~I0?]3"-?=z܋?0`?)E?6~$??|S#X ?Bjz#?!1\w?yp_ T?iM|?o it?z#H\\a?n6?`1xe?Q(NS?@~Y?1{c?"y?.l?,T>ᾧ)b>wdEb}>y+/>G]ѡ>'3?7>_i_>LJ>u~QL>' >5+I>PV!>,>6!f_2>^>Қ>c!Qt>]r,>c_)C >E>4>BT>)܄ݡ>phCP>G >ՙ*wx?p?tN?|3ה?v -?@eZ?+:&A?ې?l̕e? ?`]j ?N=v?o?yo퀒?$JE ?a=w?[G7?LG4?\g*|? /?xf?}c? N? ?+=|d9)`>Tu>"I~rZ>R>W,>:l>3_> ⮀>by>fm*>ɪB|>/WIU>&P>./&>6؊:>8->iM>*Q>۝gm>•A>z.zp>kL>cAP>{ID>8??k?/oS?(g:`?3B?@.'I?J%t`?U `?aX?i*2X?qd?w -d?~Z??4+?r UЪ?V8?!-?xH?(+?&r?͖o?a>>!<6>kK > ;/Ḏ>͟aR K(>N5> B6]>K>5+͗>-t>%:3E>S>D`,h>ǒ>x]>"Ҁ>>7zA>It>>p0|>S>v)jS>k&@a8>$3>G4(>#-g?a9K/`?S7??& 2?0;?F?9c<9?C@8u?M[>Do?UࢧK ?`8?fuvP?o?uŠr?|QAT ?RI@? Fؘ?a#X7?[vI?\bhB?(U ?h8?4?_zկX?u?j[P?/4 `?z?G@f?R?~gI?0#?,?A ?1V ?RՍ?Xw?R?GL?iߑ?T{oݣ?g]?Dt+?~&ms\?~&Y@?=R?y9?x,( LL>|`\h.>eM >AĿ>yl>>!f+U>y :>jtAr>f>J]h>O_>T">7 >S^>s_>lmZd>>EJd>ĔGp>f4">s۲">V3X4>ܪ ]x>xtf?@?3=?[P?"6?*?2Q#uِ?9sK@?A?HCgP?Pa?Wf}p?`.Y?hY?p?wƧ?i ?963_v?4`\?&?66?wo{?PT?[h?T\N?lէ?s;'?Vה^ƒ?O+=ˑ?sR?M+?%2Y6?__F?ڴ?7Nؕ?}?}PwK?aK>?y?GRm?B;?t2?T\e5?N!z?5[ ߂?HԬI?t֭&e?b8?hߛ?Qʃ(?"*Z ??4pBI?ڨ,O?vMel?3wp?{9?xj?x㟤sL?|$? O?Kc ?@j?Qf?*wI?o?wu?G ?? ? ?|15f?ڜ1?̗O?? g.X? j0?r"A"- "?cd@ $QV>椣_t>Ʋ6>jʞK3>Q0>Km0">nu@>i T>[s?>.>h>mۓz>]P%>)Y>^5>k1>kLVt>j>u>&=3>فM>FR1*>{]20>4?3?k5r?t?#9&8}?+Zp?3;7?:xT`?AyX?FapP?Li _= ?Q Fd ?V2x?_;e?e׍?o%>F8?vnfű?B&n?Ц>A?^?rg 1?An8?k??Z+W?~-=?71Z?ZZZK? ˹?#"?q+?!iW? ,?% d?1a?+ ?|Z?xR7?xGGɈ?{2x?[ѐ?FR33?p4?yP?^m?`Z?y,6 ?7%Lo?ڿu?Nj='?bA?I?}=!?Wz?Iڴw?fXu? h}?@?0?j?`?&(?s(K!? q(?z~g?n 9@?`C7X{T?P&YMN?@z,tX?1y;?"D W?%ư?nD>/[*><ؘ>ؚ>|,I>pp><.p`>skJT>n >r1_>Â>u0&>{{|><>6r'>'>4dvَ>2>8'>8k\>- ^7>ꢀڨ>R?22K? {Ŋ?I ?%GU9ϖ?/ I3?7tC?A3!?G;g?Od0?Syր:X?WSn;?[w!@?`S! ?d,-p]?j,+&Z< ?qz?'? ?y.?<v?~/j)?z$Go?yv^'?},?K(?,Ȱ?ԵZف?T?&{? 䮕?+>v ?񾣆?.?Z?gT?p ?? V߾?g?ߠ*?'y2.?9 0?"?CJl?s v?s?rU?%*{'?tҸ?'<o?Ǣj?X,N?$3?:=?<}Q?Q%n[B?w)[\?m@]?HS-5?>?a}?>}?h?s;K?fR[?XP7?IAP?:J?,<=?/06?M>-lw>A)Oc>>8>wmM>Dp>:}׆>Ubm)>hF> I#wN>Bz>* Q>in=8V>R6>[>?Pk;>!Z@>;e^ >l$>=!o>܋B8>>?ӧ?p?>Q?%y?1>#?;z&`?E ?P`y?V f?]o0?bv4k?e_ 0?i;0b?l]1?pf6L?sT ?wp*.?}7*,?`ۻw?"/=?')s'?ⰌN?6#氣?l$T?#i? tR=E?)a:?kZ?6~9?Qߪ?m0X?%]ă?EB`/?J=?@&?LD\?&l??\kQ?E)t5?{Q?ͮ|d6?ړh?p??qTc?{Ev?R?3锯?n(?@N?EeeA?i7|?uTxΈ?jsB?_U?Qx ?Bl */?3)H?&(ѵGJ?!.?:i>6Օ>lp>4>O>IC6>|P>Fidy`>:)Ř> `y>py_>^f>-Vl>}4΂0>F%>K;>\>_N b>>q> uiU? ,,N|?T4?$g?0wx?<=(?HI?SŽh`?^YO?e2G b?lsn?qO,?uLqe]P?x sD?zd ?|u^C?<?b^.??Ev?=x]?V((?o;{?Bm?8|{?-;1T?<*m?m?Lɷ?{86?M'3#?o%?DefK\?LOt?3@!?XrXp~?4J?,h?N0s?Rz9?}R?bub|?ie3?ק?P?"F:?)y? `6J?] ?Ӷ ?״?gXL? ?@#?_]*>?qh?! |?s#VcE?_?yl`>m|>Px$> ]>ə` >S׉j>R>" Eq>I6r>1%>*wXN>>*w>ʅ>I6r\>" E)>R6>SU>ə`> ;>PxR>m?yld?D? >c|?,_L?9*4Or?F«ބ?TD۲?`ޫ >?i.?rژ?z cE ?" ?ArA?s#VG?! ?qh?_]*>?@#? ?gXL?״?Ӷ ?]? `6J ?)y?"F5?P?ק?ie,?buby?}Q?Rz:?N0s?,h?4N?XrXp}?3@"?LOz?DefKc?o%?M'3(?{88?Lɷ?:¦?<*m?-;1U?8|q?Bl?>;m?Q?,sp?4?z#?ZpՋ?nd;7?֢Y?p ?@?'?|ޣk ?\c ]?ǩ/ ?6\zh?saj?o ud>q>>_N >\>KN>F%S><å>}4΢>->&>^ek>pyA> `z>:)>Fidi#>|+x>IC6>>4>lp>6Օ?:i"g?!.?&(ѵGE?3)H?Bl */?Qx ?_U?jsB?uTxΈ?i7~?EeeH?@N?n(?3锵?R?{Ev?qTc??p?ړh?ͮ|d6?{Q?i>*?Gߝ|@?Jh?vL6?O?6?c{O&?O;^?5Nv?aXS?1*&ze?qM ?_??RT ?@ ?,6?·O}?}\#Q??n;K?ԵZـ? ?s~{?E)t$ ?%y]?@ ?ǜ?ӧl>C>>܋B>=!px>l$>>;e^1>!Z>?O>[ >d>in=9Q>* >Bz > I#U>hF>Ub8>:}>Dp_>wm.R>>8>A)R>-lt_?Mz?/.?,<=?:J?IAP?XP7?fR[?s;K?h?>}?a}?>?HS-6?m@_?w)[\?Q%n[D?<}V?:=?$3?X,N?Ǣl?'<o?tҸ?%*{'?rH?s?s v?CJl?"?9 0|?'y2*?ߠ*?g?? V߿?p ?gT?Z?0?񾣆?+>v ? 䮕?&{?U?p4?,Ȱ?K(?},?yv^?z$Go?~/j ?<l?y.? |?r>#?c1o?uGO,p?p_`?ybHA?ܣSM?蝎$P?5C?u?f?~3?<Ųd?Nbm?c?l*|Q?wDB?qz?R >ꢀن>- ^>8k[>8'X>2/>4dwL>'>>6֛>{{U>u0( >^>r1_8>nۢY>skJD><.p[>pp >|,,>ؚ><嶾>/[?nB ?%~?"D V9?1ym?@z,tX?P&YMJ?`C7X{W?n 9@?z~g? q(?s(K!?&(?`?j?2?@? h~?fXy?Iڴy?Wz?}=!?I?Y>b@?P\?dޡo?}x?y/?yLQ?}tޜ?ܜw?̜1?aTsע?T?ϛ?h Ay?1?A?B&r?vnfű?o%>F9?e׍?_;e@?V2x ?Q Fc?Li _4>{]2 >FR1/>فM@>&=>{^>ji>kLV@>j>^5$>)Y u>]P>m۔N>.>>[t>h]>nu*>Kl>퇭>jʞK>ƲɆ>椣_\p> $T ?Qk? Tޡ?$'s?3k03?C;%?p?S2jd?cd@B?r"A"- "? j.? g.X??̗O?ڜ1?|15f? ? !??G ?wu?o?*wI?Qf?@j?Kc? N?|?x㟤sN?xj|?{9?3wp?vMek?ڨ,N?4pBM??"*Z ?Qʃ(?hߛ?b8?t֭&f?HԬJ?5[ ߄?N!{?T\e6?t2?/4 `?GRq?y?aK>?}PwK?}?7Nؕ?ڴ?__A?%2Y3?M+?sQ?O+=ˏ?Vה^ƒ?s;'?lէ?T\N?[h?PT?wo{?66?&?4`]?963_x?i ?wƧ?p?hY8?`.Y`?Wf}p?Pa`?HCg ?A?9sKp?2Q#uـ?*0?"6?[?3=? >xtf>ܪ ]>V3p>s۲0>f4*>ĔGx>>E(>lmZ R>sOu>S>7o@>T#!>Oa\T>J>f>jtB)>y >!f >bG>>Aľ>eM L>|`\U>,( N?rnuC4?n?%(Mz?4[;?D]`D?Uk<֚?e \?s<҉?Ѝ ?y^R?#nfx?qW???]Q?Blތ? :L?fn?|;? M?@?`O?=t?K?!2???[]|?8?;G?Ȓ?%ğO?m?RIDo?C@8u?9c<8?0;?F?& 2@??S7?a9K-0>#-i>G45>$3p>k&@H>v)jS>Sʬ>p]>It>@>7z\>G>"ҀZ$>xMV>Ǔ6>D`.q>>%:->->5+͖>K֠> B6>N5>͟aR > ;/}}>kK}T>>!(*?D'?UlHi?e&?s2)?Z8Ѐ>{IY>cA0>kL@>z. >•%>۝f >*Q>i0>8.>6Q>.0h^>&Je>/WL,>ɪ>fmӄ[>b 5> ~K>3_U>:lj>W'>R>"I~r\>T>d9)B?h?Fa?% 5?3 ?C]k?ȘN?cf=?qut?gVA?Rl?:@X?Cd?=Z)?Sy=M?fəR?o?wӰ?V xZ?:X-q\?mp?`˿z?bH>?ΒD~f?.u8y?%d? 2?Wʰ?w d?WJO??= ?gƄl? ?BX?M)b?bG? e?0?ψ(?P?ƈ]M?W_fH?32Gt?-?͒E@?7?VJeI?RX?Yj?T_w?y_?+=|=? ? P?}c?xf? /?\g*{?LG.?[G7?a=u?$JE?yo퀐?o?N=v?`]j? ?l̕g?ۘ?+:&J?@ep?v -?|3׈?tN?l>p?aJF ?T3bP?GV N ?:^7?.^=`?!LK?)?ՙ*ww>G>phQ0>)܄>BT>4g>E:`>c_)@>]U>c!#P>Қ.>^>6!f_>,*>PV]a>5s>ꀋ>u~Q>Lm>_Ȩ>'3>G]n>y+.>>wdEb>ᾧ)j?,|?.l?"yo?1{c~B?@~YU?Q(N;?`1xe?n5?z#H\\b?o ix?iMx?yp_ R?!1\w?Bjz"?|S#X ?6~$?ξM?+ !?flә?󛔕Y?bC?[[ט?s?Cz#?鯈c?Wl$?;a}?R+v?T;?lFy\?Bl?9?v?l`P?`ӭ`?R^!S?C==R@?5SA`?'??c? nC>/M>œ&>ZJF`>DJ8>t)m>«(>J>%k1>Ų /<>K9I:>F̊>{<>DA>%>T#>RE>tO>DeE>bm]>1F:>+>w%F>ֲ9>Π%p>_I\`?y1L?xƪ!? F?-lr3?<k_?Kx@r.?Zc?gE'?t$~?hp#?x>r?4fk?Rda??n??O_x?o U?Xb{,?"%'R]?ĝQ:8?)l\J?b_vs%?s;Q??;_?/'?K?Uka\?\wQ?3r?Gz?8gWM?r=:+?יq?/?i^ ?k2??o W?}?R~?P/p?Kv4?I7?]? q?>򴫙R?yH?mgD?)n? 6^?.g? ?yj?N?Ty?bχ?^)?46v?ezE?V^?BCy?%ˣv?/c?}ɑ,?}-u`? ?Z;_?'x?+?[Y?؅ .?dk[{:?ጷg??Ɇ_?cq#e?W9Z?U*?vcSyp?i/`?\50?M]4?>] ?0u`?!.}?EzEb`?} >:.p>pܯPp>-@>ϣ5><">]"P>BW>[1>#>u>c7kNA>p>ERp(>$\2>S>l>ف>UJ r>M*i>$UWl>. wpz>Sty&>þ>m>䖫:1|? LZ? k?(3?6ss?E?j?S,yL?b˞E[0?o^gy?zN2{?:nDB?A ?~Q {?:? L!(=g?Q˔??Rx??YpOY?c3? ?l??wp4?B?`ˢ ?3#!?=\fP>z<>f8u@>ҪKh>7\izx>n>=>9d0>R\f>w[<>A`;>գÇ>L,L>lT>b1>Ɔ/>d1A>q1>s2L>VLb~>VBF>ne>+|>W&>XK?򎲺? l?#H/?1KA?@ A‚2?MKKZ?ZX?grRU?tf@ ?C%?kъ?V?Js&?dz*?1fP?LҀ?U?]f?2]6?+c?m~b:?kHZ?S4fh??3"'?]l,?YTڧ? ?|?(H?j] ?Za R?k?[?0 P^?~7<.?M`?L2?zm@!?y$O*?{ ^T?W ?H"??j y?4?X}r-N?O!?bΉC?e? W ?)\ ?)?:Y?SvYw?8t1?FV?Fy4K4? ?Jo1 m?|N?y~_?z]*?Xj?_?Sl?z ?n?8k?v@T?Vsġ?H%?|h%\?p? /??rIى;*?z@ ?l?ڋ+t?]J΀(?N4@?=8?-y1X?@z~?lkg0??!P><9,I`>S>Sl7>Cgd>CO>AE" >}-\ @>@P>N(>A쾏>D>فd>V>at>++`{|>R'b>pQ>Mq>8;>/V`>&Q>؋#>]koR>54?0pb?o\#GU?ANy?+1-?8|ZD?Es"?SF,|?bS?pz?{h?E uj?ku=VD?. L?|J,?%G\?R?yШ{?#ŹT?y?j:>8?Q1?D*s?ӟuY7? ?H?)9?|2?nÈQ?eH?_kI?qo? 7$?xB?'e?"2?,?]y?sp?Vj?|)q/Q?zq^?}(?<.?$I`u?ᳺO=?L).Ҡ?*Rz?҃?Nl"?/b;[z?pF ?Y?(?3}?1?XfXxb^? f ? B?F3?&\?8ck?uh&??6'bH?R4?*n0?NYm?gJi?`X'?֯?)?E? ~?'>W,?{*ˢ?VV@? @dy?r{m1>fO>'2 >'x>f4>Ӱ<>W޴4>KEN>zCL7>ή[>htj>fu>>v:M>z>X>8@>Q6>7*1>':>aɶ>ĵO>"4>᧫zU>S1>P8XM?z;JE?(a0?%4%W?2YyD?@^?M$ֱq?[T|?ijuh2?v`~$?? o-l?^9?NbS?&g?$.?Ƭ?3?sFo?+Z4:?C@Y?9R?Dz: q?16uO?$Ae? #Ik?4 2nt?eN?y3?#}? +u??P@Pz?f?6hr.? *Gѧ?1? V?F;?R(}<?+*X?r?!,д?!?J?WL?|Kw ?w xp?Z,^?k:?^Ǝt?f ?ߑVΕ?M)?צ?[̆?@?nj`f?IJL?klj? P?R~:?@ti5?!h+L??b?V/?nW?[??x-?e? &?8 ?Ӯu?A:?wb]~v?hH7e?Z3q J?K )?; a*|?+ܒ?*gEQ?"G S?P{}^>c,؊B>&+d>1ל>ݬ6>2G>MM>|6E>0 > m10>Tv>D]>j4Si>k_Ć>Ё>6@>&O@{>EqA>jUU>!_>.ޒVF>̵P>}hM>J>xP+?Ǹ'?+7=H?_h:?,???8;9?Fza$g?Ua8P?d.U?r_˺f?>d?|?$⸲?VO;f?,!y?PO<_?-q_?A$#zh?jc ?T$HA?c+?}>?ex?nMP(?T`iw??k?ZǷ}?좨 ?k0 ?8۾We?ļc%?k"F??P+3?Y:?M?UY?e ]S?}W-g?h,s?,ۆ?1em?.Ώ?l3C? e?H]?`ڊ?ݣ]ؾn?_@D?DVv?x`?p -h?B?)3?(s?؄h?ZT\?Q{;e?t?Yog?BJ) ?Q ?V΋l6??Y9WZ?a/??kϲ?Q?2/`?Gn?MMg*?o >|of>J`>ռX.> >f7z>ߌ>>`H@H>0Uu>p>Jm>ʀꌊ>JĞ>p~>0U>`H?>Ֆ>ߌމ>f7y> T>ռXIN>J|>|o˽G> f? r(?CL?'9N?5}[`?D+$*?T2] ?cFs 7FL>?5>݈m$̰>%>ftP>W#1*>Ii%>d6&Է>m.q>zgM>ۢƭf>Ӕ">TY >Nuۂ>Sq>/Ւ(>`H<>d[>p)v>V$,>αW>r\b>C/ל?>N?fZԢ? Hٵ? 8Mr?/4?>n8?O3>?^,*6?lsߥ?|4?`? = ?MĶ?8?Z ?R?!?,?s??ե?5ևGY?Hה?/?oŅ?J?yYd?%s ?C?oB7E?~ }{?I[(?I??~?4?a[o?2Z܊?t*?"1o?V%?j?)?[%8?JǚՄ?j?|>p?{}N?~O܆))?;k'M?gP̕?8^;(?=&q??37 ?2y?z~?j?BG?ix9D@?N?rf5?3g>?* ?ZU?M??It?N? ؠqyU?LN?ܰB? ]?yt?B(9?k~y?Skі?HNO_?C#vh\?|n.?ov6O2?a t?Q(?B>7?5N$_?(--?P? oyy>w{*>E]^6>%q>k{Kx>ŵ_%Y>CW^>23n>$Y<^>QU+b>O5d>{l> %̋>B>*>>U(2C > ESz>|>ϑ"R>3V`>\ > X>~Wxx>O50>)B>dJW? nؓ|?3?&x0ј?6\` ?G1o?V0?eGr.?t|j?b?z?In? kH?N^?O;?ޭ(?AX$@?se?9="2?G+?p6V?E0T?,93?5?}$1'?{h;(?kghL?Fy#}?B?{c_R?Ϫi"?JQH÷?6d_?Ol?1IQL?+N*{?D? ?0xh?o?|di_??(ܦ?Ȳoz?` ?xJ5?uӍj@?v߿N?{æy?1:hx7?Tt?kY?ݓ;??h?w_"Ai? A?a?L)8?,!G?lAe? f?m?|WA?%J??^?zY?y?DU> ??"~:\?8j,?4?+sD?syN?LJ?uyCog?D}?XjBJ?tJ{&?f.C?XEr?IxL(?)d>S7tu>ڣ$7`>˘ E>r1>jq9>z>Y>leY>߉8>@1y]>ď9O>`V> >:'>1>,ƝZ><ξ_$>?gD>Af1UP>xMw@>)qٿ`>+pX>H?X?O? K8?/\lp?@]{?Pr?_&V?mڢ?|FP `|?iq?Yw ??DE@? f?U>S.~?ՐEDt?3XK?l? J3?XC?}`b?wdFS5?u{R?wC?~~0B?6(iwH?'b?r?ݸ?R?ʈ/u? i%?驓%`?3?{\.?Qrh?N?[_?jue?&?#r?~5?wo-+7?t*jL?u{[]\T?z@IYm?#,^_?n ?Cԕ8j?p0 2?.J?N#B?~H?a?Gs7f?e}F?5"? v?G?ָܥ]?N?rb?#?QNj?j̒\? w]8?pvo?Y?t ?̤?ta ?ts~?Q?qLx?tW:?yP?mۦ?`~*?Q_?Bֵ?4?&\o X?ٮZ? jW,l>N >L(>_,0>$|q>']Ξ_>уFJ>ݿ9>u[>p;n>4^>o|>^/1>>">Cau>F=1j>:VG>]>Nji 4>z[!>D_ >ȕ2>XjOKX>u >Gm@>j+q? mW?Z^?'J_ ?6٭T0v ?F[?VB Z?dБZX?rm& ? ~?H<?vσ?}tz? >?;& ?*rAE?ϲf)?9ȭw??qd?Iih ?ı%?رdh@?gֿ|?(l?c`^,?1?W=;? ;?_V$C?o?z Q"zOF?x/yl?y,g?[6j?{*Oy?Tfɗ?=?z"?@?sY`? ҟ[?i?d!D?:}@d?i1|q?Z:?pD?8S ?+Q?ݞ!;?r`?ѯ?)ǵ0%?9X_?>%?̆?+<|? `?4Տ>\Gpu>9 >[:>PM)V->g<>js>2>-âNB>\O>>9>q.>ZwFN> $rM> =>ιS>c+ >ϴ>aƮ>J[>ʌ>K!;8>Ы?V>7+5X@>K!T@>UI?? M``?!18@?0&7wv??)w?Mr{?[E?hw]cH?tV}?xm?{Ѻ?7)?<^5N ? p?-?iJ?D!>y?s?0`$?{?yM>%蒣 >׎{>$Ձ5aj>@>9"L>]>yD>|>t>>>e.T4>է"C&>,>5>0.>7oG>gS>ݲt_>MM>is>e#>;l]@>o7z`>J@? ރ`?"῀?''ĺ?5._?Cq?Q*SY?_ X ?iƺFjP?t3P{?|d?L?ݤ ۚ?~?"?OV?נ? dw?ML{?7R?Gy$rA?}I0~?0|?j0 ?Nz7?Cu1%T??3͔?j"s?HV}?xz?P]ý?ɋ2?[h?Aa?vGU?ѐPi?}?yJ?[_DL?Q @?KM?,?>&i?KX?C[:b?핂WX?#h&q?GF?rGʹi?U ?:eE6?/f2?b?dC?З?U??rstj?dC$S0?TuwX?D .?4L^?%J9?Y>K:>q|V>W\>OՄ+>ް5C>`ean>R />SΟ%>=>~śx>P>.c,>F>evo>z?\>!>%B>'.>LVX>X>N`>^>n >{%@?D?dRԩ ?!1`(?.㄀?9N?F=ڼZ* ?R?_'M@?h[~J ?qn*@?v^@$?{F@? ?z2W?T;C?A~?n ?'?&%?F?׏w1?udjX? F?IO~>胍0>p S>H>A>t&j>a}>yOi>Qb>P_)/>dRB> NT4>K&G>~6><">Opܭ >Iu>5%x0>8XX(>H2(>g@>+`>1W4>s%z>J=@?u??Xʝ?'i?3yf?>9?Guv?RԟD ?\z ~?dAM?k<%H?q5|?tí8?xxom?{+]\?`&?ok ڛ?00?n0@}?y]?{ue??"4g_?41?(q_$?]@D?UÃ?e5;?O?FЋs?vy?//v?o|o&Q?Ju?6*?#q?\9$?Še?d?s?])_ ?}H?kU?w?`~A?Q.E?)>E?׹Y?8T3?܋R?g?F*SBw?J~S|?z1?K\=??8?l?8Ǚ!=? m?v?:{A)??CAg?s.>&?hŵF?= ?rl:?Z[Ζ?TC+?x\:?8E?iT?#?ۖ|hp??А?I0?y!a?i9&?Z @?HQ?8o?(C?|f?\>qL >x{U¸>ݡc\>΋>RK>U>tg>P>i>>Y># .> X >oj 8w>Q%lσ>P >wbQO>BB> d)>>q(h>)0>;ў+W> )p>Ѯ1>>+0|`?"?'hP?ԯϠ?&ٷ?0c?8l|u`?A.?IA%?RYjcg?Y|bo?a:=p?f̂hx?mBH?rpT%?wQ]Rҁ?}'>? 4'?¢Z?.T!y?Ȧq?LZH?UΤF?wd#+?Wt?Kr&??^X?2pT?rg(T?F$?1B??i1?Zl?H?88?(UZX?'`? ^_->Q*;>ey\>݊oj>Π~>6 >p20>꫼2v>:` >ǎd>sX>R,>a>U Sw>O|>CɈ$>B[2\>FO>՟3>x6j>n>.Wl+T>g4`>Qc&@>w?S"h?>B?q@͠?#&žp?+ԏ@?3Y?9L?AB". ?Fƣ҈?M}?SQ`?YH@?a3;?gDU?o$U?t2(wwj?}X9?/ز?)JdB?N`C?x?^Nc?0zp?r/Ċ?}ܬx?~ $N?&y C?RvV?0pwU?b4 ?n!?U ߼?0ŶE?ִ ?|r?xO>v?xMuJi?z,?IO?1\?yN”@?6?u ji?wNi?R;J\ ?~ H"?*Cp?Sy_?-lں??r#y?J?RF@.?Ԉ?`g?g?/56Bu?^>얚?D~?v??gȅ?W>c?F5?6b& S?'t? ?? > fL>p{r܌>ۻ|>̺>\>`;>j_p7b>nƊ >ŗG>} YFS> 0iQ:>HF>?%I>D6˃>J>(6>mؔ~>ë>bp>ڗܢ >y)@>#?j>BNQ?_UtHH??{l"4?% Ύ}P?.4yp?5r۔?=T`?CT]⍀?HQjdp?MrՅ ?Qeݥ4ހ?Tn  ?Ydą?`.Xm?e++]?m;N*?tDqۂ?}pGl?Ee?r?ةNl?[[?!Z?*,ޱ?4q?`?W$?}?On?g -? [.-?GS?C^Br?c@^?_m}?~T??wmUI?tK0gy?t_X?wnҠ/?~1??1)`Cb?9Gp?MD53?oO?ݤ? m8-?.D?w?.Q]?@^?c)G?@s)?ޤ< ? ? 0j?L?LM?x.?u"-- ?uMډ1?x/)Q?~Bs?s}!O?r3#,??q%6?}?)0?@y?I8y?W7 Zh?#?~h?sc?^rk?K%}?G|z?r>{0?c߯P?T& ?CT5?3@m ?$kHv?$>Gp?? >b[b>|CY,>$H>8>$z>cH&>j,> a>&`< >Pyz>:G]>fꏹ>xKPv>ޖ>!>pzD>)>h>%b>^f=->f>4h?UyX,?W?ϳ1?'V?21@HVX?;W *?D\5?Ku7?R ?VDh?YZƠ?\jyq?_3?am5?df-,?i\ u?0 />}?!mzr?b'`?Gv>S<>,׊>!t=P>YDq3>Di>`[>sQ>>OҢ>Y>2u">,{IQt>.{o>6>[u> N>/C>G>G>gI>=?F?5vzf?(.?(5?3,?@5=M3?=`ӕ^?lk%?B"?9?<?=en^T?y?) ?k3~?l*i1?z$r?⾻/?Eu??}(p>?{0=̘?|yl?J?ho?Ab?W`@ͤ?7e%U?iV?#r@?S?0#?`&?P^ ?(?qwB?#e?"6\?8? X?.kn?rt(\?N`?jt?{5?wP%D? P8?7MFNE?2\&? F X?¨?8=Ɏ?-?`?sl?@^G?K?Ff:?h u?{86R?pw*?cE*E?U5Cy@?F3T!V?7 D?("8?Sי? *P/>7%0>b3a>Cp*>һ+>dO>>>>to> >LL>zQg>[#>c(:O>`` >?&K>>4M;>L>ȾZ>l8>a_M>A?0e>Li{j? Y??&pp?3MR 5?@7bs?Lzׯy?Wb?b"Ӱ?iꜜ?p[?tۇ,?x#+_?z1 4HP?zτf\?z,0l?z} ^?z?{r s?}lZ ? ?@ ֕?VQ("?\"?J?a!?)D?]?OY?7i~?i?_ga51b?Rs?tOzz?fm×?2c?5I?/4?nٴ?QYhm? U@-Vw?X6X?WI??Fm~?ZPzm?]p?^EΙY?Tۣ?.*@!L?#B?Wn?il??A2"[?♤G??Lv_?T??SWC?AT?pB4?{`?yg)~? %w^5?`y?EBv?~x%Sn?9Z?>Zi?ޓ(?_Fr?,5 ?<2?]j4 ?Ѽ?뎼u?'g?'@?b?w ?o塶ֶ?dvkg?X\sb?Ki~?=D~ɮp>%ﲙM>ܙ״>"1=>LCL>+F>*eP>ߍ C>L-q>H?j}>l>H?j~>L- >ߍ%>*eF>+F`>LCz>"y>ܙ״ܤ>%ﲅ>ɩ?(r78??X?"#?0n; ?=D~?Ki?X\sbw?dvkg?o塶ֶ?w ?b?'@?'g?뎼v ?Ѽ?]j4?<2"?,5&?_Fx?ޓ(?>Zj?9Z?~x%Sk?EBy?`y? %w^,?yg)v?{`?pB3?AT?SWB?T??Lvb??♤G??A2"[?il?Wn?#D?.*@!M?Tۣ?^EΙ]?]s?ho?Fm|?WI? ?X6W? U@-Vw?QYhm?n٬?/4?5J?2c?fmÖ?tOzw?Rs?_ga51b?i?7i~?O[?b?)N?J?a(?\"?VQ($?@ ֕? ?}lZ ?{r s?z?z} ^?z,0X?zτfD?z1 4HD?x#+_?tۇ,?pM?iꜜ?b"Ӧ?Wb?Lzׯ?@7bW?3MR 5?&pq&?? Y>Li{l>A?7>a_\>l>ȾZb>MJx>4M!>>?&>``T2>c(>[郸>zQފ>Ld> @g>s^>>>dO>>һ+͛&>Cg,>b3>7? *P1=?Sי?("n?7 \?F3T!2?U5Cy8?cE*;?pw*?{86b?h {?Ff:?K?@^J?sl?`?/?8=ɔ?©? F `?2\$?7MFNF? P8?wP%A?{8?jb?N`?rt(\|?.kn? U?8?"6Y?#e?qwB?'?P^ ?`&?0%?S?#r@?iV?7e%Y?W`@ͨ?Ab"?s 8?J?|yl?{0=̛?}(p>??Eu?⾻(?z$s?l*i-?k3~?) ?y?=en^S?<?9?B$?lk%?=`ӕb?Oi̵F?ʿ?_']?.{V?/pJ?xC(s `?t-G1?qST $?oa}d(?m'?l$Ӆ?j/6?hN=4?eH8D?aO:?[I:E?SID>g.->PV>GI>0K> E>[]>7>.|\>,{I>2uz >`>O_>#>s>=>Db>YDc>!t<6>,9>Sl?Gsp?b'?!my?0 />?> u?O71V?^VC0?k9G?xĒ?^è?bPI4h(>f>^f=-">%RH>a>)>pzD*>!V>X>xKT>fD*>:>Py+>&` >jĆg>cGZ>$zĪ>8a>#>|CY">b[???$>G?$kH?3@m{*?G|z?K%?^rk?sc?~h?#?W7 Zi?I8z?@y?)0?}?q%6??r3#,?s}!O?~Bs?x/)Q?uMډ?u"-- ?x.?LM?L? 0j? ?ޤ< ?@s,?c)G?@]?.Q]?.D?w? m8.?ݤ?oO?MD54?9Gp?1)`Cd?1\?~1?wnҠ:?t_\?tK0g|?wmUI?~T-?_m}?c@^?C^Br?GR? [.*?g -?On?}?W$?`?4p?*,ޱ?!Z?[W?ةNl?Ee?v?}pGn?tDqێ?m;N*?e++]?`.Xn?Ydą`?Tn ?Qeݥ4`?MrՅ?HQjd?CT]?=T0?5r۔@?.4y?% Ύ}?{l"ބ? ?_UtL>BNZ>#I">y)ަ>ڗܢ6x>b8>ë>mؕ>(> H>D6U6>?%>H<> 0iQ>} Y>ŗ~K>nƊ_>j_p|z>`<>>̺\>ۻ|;;>p{r܀> fm? ??'t>Y?6b& Ș?F5}?W>B?gȅ?v??D~?^>얝?/56Bu?`g?g?Ԉ?RF@,?J?r#y??-lں?Syd?*Cp?~ H ?R;J\ ?wNm?u jg?w@l>?teFA?s(J?vh%&ȷ?} r?;J?)?۰^?j{$|5?Zş?DؽZ?g W?֢B?f\3?Nr.?Pj?D? g4?6v?|r?ִ?0ŶE?U ߽?n ?b4"?0pwT?RvW?&y C?~ $L?}ܬu?r/Ċ?0zn?^Nb?x?N`C?)JdB?/ز?}X9 ?t2(wwn?o$U?gDU?a3; ?YH@?SQ?M}`?Fƣ҈€?AB".ˠ?9L鸀?3X?+ԏ?#&žP?q@P?>B?S">w>Qc,>g4n>.Wlgh>n\>x>՟>FPC>B[1>CɈu >O!>U T*>a-u>Rw>sY>ǎd>9S>꫼X$>p1>6>Π>݊oJ>ey\J>Q*;,? ^_)?'L?(UZ?88?H?Zlt?i1?y@:?(7@?D?I-Z2 ?@ ?۰pt?X}R?N=??NBm>+0„ >Ѯ<> )@>;ў+^>)p>q(ha@>0> cH>BB>wbQ>P !>>Q%n%>oj > Xm$># ́>>i?MS>/>tgC>TGK>R">΋>ݡbr>x{U¢j>qL ?\?|f?(Co?8o"?HQn?Z @?i90?y!a?I0??А?ۖ|hp?#?iU?8E?x\&??CAe?:{A.?v? m?8Ǚ!4?l??8?K\=?z8?J~S}?F*SBw?g?܋R?8T3?׹Y?)>F?Q.B?`~A?w?kU?}H?])_ ?s?E9V?Še?\9$?#q?6-?Ju?o|o&P?//w?vz?FЋs?O?e5:?UÂ?]@B?(q_"?41 ?"4g]??{uc?y]?n0@{?00?ok ژ?`&?{+]h?xxom?tíD?q5|?k<%x?dAM?\z ~P?RԟDP?Guv?>9?3yf@?'i@?Xʞ??q@>JC`>s%>1W4@>+>gK>H2(>8XXX>5%x>IvE>Opܮ1f><">x:>K'W> NC>dRQ >P_)!\>Q2>yOh9>aM>t&3f>Aٺk>Hs>p $J>胍>~H?I$?pֆy0?'3m%P?6|?G&I?X Fw!?gq-.n?vEuO?tb?n}&?_{5ۅL?1j?*a?B0?r@"B?_c1?v?U u?' g?tD?_쪬?Il ?k3t??ы ?cm?ضJ=?jv?fw|E?:T?!=N?,U?P؅?t+6F?g =>{+>n >[>N0>r>LV`>'/6P>%C`>!>z?>ev>G[>.>@&>~Ś>=>SΟ0a>R >`dI>ްU>ON>W\ܶt>q|N>K:U>9?Vv?*n&?y?%J[??8A$&i?,?KM?YW?[_DL?yK?}?ѐPi?vGV?Aa?[h?ɋ2?P]ý?xz?HV{?j"r?3͔??Cu1%M?Nz7?j0 ?0|?}I0?Gy$r@?7R?ML{? d?נ?OV?~?"?ݤ ۢ?L?|t?t3P{?iƺFj?_ X0?Q*SY?Cq?5._`?''ĺ?" ? ރ`>Q>o7>;l]0>e#ؾ>is >MMӐ>ݲt8>gT>7q4>0.ؠ>5>,>է"x.>e.T>E>r>|G>yDu>]e>9">?~d>$Ձ5>׎{~>%蒇>M~?B?9r^?"?]3?04?@}Ԏ?Po "?`&F꿌?mzm(?zFɡ?VO?砀w ?M?$?NO]?a61?v<*?ܸ?ϫ2?|?Yy ?SGP?n?\?9AkL?Ɓ?<DŽe?H]x=c?4Jc??R!?!)?͒5x?hZN?m̽?R?x#?+2?( uN?S!3?U[?:7 A?sBQ?HA?_|?ZӒJ?_V$C?+q? _?qI?m?( =[x2?əi?9x? V5?x3eD}?iQ?-? v?<^5N?7)?{Ѻ?xm?tV}?hw]cH?[D?Mr{`??)v?0&7wv?!18`? M`?P>UI>K!S>7+5Lp>Ы?C>K!;>ʍdp>JËh>aưa$>w>c*>ιT^> $r>Zw^>o>ծ>>[>-âN=0>2,>g<>?>PM)U>>[9>9 q>\Gp?4^? ?+<f?:;\>?IVХs^?XG&DI?fUC_[?s5U6? 4|sa?iJֿU?H??cV(??v?Ph?_6<+?%?9Xa?)ǵ0%?Ѳ?rh?ݞ!=?+Q?8S ?pE?Z>?i1|q?:}@f?d!F?i? ҟZ?sYa?>?z"?=?Tfɓ?{*O}?[6j?y,^?x/yg?z Q"zOB?o¡?#r? ;?W=9?1?c`^-?(k?gֿ|?رdh@?ı%?Iih ??qd?9ȭu?ϲf)?*rAE?;& ? :?}tz?vσ?t)F?uoeD)?{y?]qIj+q0>GmР>u >XjOK >ȕ2P>D_X>z[!>Nji >Z>:VÊ>F=1kA@>C`xL>>"м>^>ozuE>4EL>p;Y>uEf>ݿ9m>уE>']·>$|q>_,>L(>N? jW6?ٮr?&\o V?4 ?Bֵj?Q_?`~*?mۦ?yP?tW:~?qLs?Q?ts|?ta ?̤?t ?Y?pvo? w]:?j̒\?QNj?&?rb?N?ָܥ_?G? v?5$?e}G?Gs7g?_?~H?N#B?.I?p0 2?Cԕ8h?n ?#,^_?z@IYp?u{[]\O?t*jL?wo-+7?~5?Ȳox?&?jub?[_?N?Qrh?{\+?3?驓%`? i&?ʈ/x?Q?ݸ?r?'g?6(iwH?~~0E?wQ?u{R?wdFS5?}`b?XF? J3?l?3XL?ՐEDv?U>S.? i?DE@??Yw #?iq?|FP `?mڢ?_&V?Pr?@]{?/\l? K8`?Op?(>H>+l>)qٻ@>xMɒh>Af1yx>?g@><οr>,Ɲ>1fg>:'}> ݐ>!>ď9̋>@1 >߉6>leXo>Y̦>zM'>jqL>q2>˘ >ڣ$7ˤ>S7tq>)d2?;|bO9? #?!@=ֈ?/KPx"? ?y?zY?^??%J?|WA?m? f?lAe?,!G?L)9? A?a?w_"Al??h?ݓ:?kY?Ty?1:hx@?{æy?v߿R?uӍj@?xJ0?` ?JǚՃ?(ܦ??|diY?o?0xf??D?+N*|?1IQO?Ol?6d_?JQH÷?Ϫi$?{c_R?C?Fy#|?kghL?{h;(!?}$1'?5?,93?E0S?p6W?G-?9="6?se ?AX$A?ޭ+?N^?O>? kL?In?z?t|j?\?eGr6?V0?G1o?6\` ?&x0ј?3? nؗ<>dJW>)BX>O54~>~Wx> XQ>\ ň>3VV>ϑܪ>|j> Ez>U(12>*?L>A> $>{k]>O4e>QTN>$Y;#>23n>CW(>ŵ_$K>k{K_T>%qg>E]OU>w{ʸ? oyu?PZ?(--q?5N$?B>7?Q(?a t?ov6O3?|n.|?C#vhZ?HNO]?Skі?k~v?B(:?yr? ]?ܰB?LN? ؠqyV?N?It??M?ZU?* ?3g>?rf5?N?ix9D>?BG?j?z~?2y??37 ?=&p?8^;-?gP̟?;k'L?~O܆)*?{}N?|>p?j?}= ?[%3?)?j?V%?"1l?t%?2Z܊?a[o?4??~?I?I[(?~ }~?oB7M?C?%s ?yYo?J ?oŅ?/?Hו?5ևGX?ե??s?,?!?Z ?T?8?MĶ? =?`?|4?ls߹?^,*8?O3L?>n8?/4? 8M? HٸT?fZ>N>C/לH>rq>α>V$[>p)m>d[=>`H/Ւ>S>Nuۃt>TY>Ӕ"eE>ۢƬj>zgM >m.q>d6&$>Ii>W#1>ftٖ>%Y>݈m$>?4O> 7F>x?<[ ?.?(V_?! W?0 iއ.F?<_v{w.?JiK?YsP?h2?w^D7?M`?NI&-L?^S?#w?Tb$?~?RD?*l ?/g?kX2?h??Mߪ?u a?RI?fL?y-?Llcν'?kr?*?~P?9&?hc?Q ?Zڨ4?;DD?C?_!f?//S?ίr?]#? *sv?Ko`َ?}[N_?L}Q(?ve'?M 8A?x׌SV?!?G ?Ip?S?1^Q=?j(? a?Ff?7jO?)]UHK~>Kta>Xja2>[>]~$Ô>H>F >E+H>Xؕ9>z>]n}Q>˥>]n{>>Xw>E>FC >>]~$>[>XjVv>Kt>HK? f"?XFתd?)]U?e ?t4? ^ژ?q=?i?HP^I?݇_ ?a >#>ވj%>J4\>Τy>\q>lF>zIB>vēt>8k5>"I:Y>5R>hxo>{RzX>M>￷^>h\ٯ">xr"->cу>*1%>Ubф>nFؚ>. P>oP?{~?dw@?"(l&W?1 @ff?@d.`?Q;Ȭ?`l2`?oj'?P?rt?h;?Kbs?%k?`Q(8V?pz?8ߋQ?Wg*?C:?:"r?c%2f??i50@8? W?EE4?|E?|44@?0B;?OYJJ?{޸a??NG駮?2N@?d?E?!q?%COo?35o?-?'+M?7$?~`C?~Oe?x.ޏ6n?u8?v{+?{~RTQ?Q? *u?Ac?$WW?W ?9?FQ :m?4;OL?@>?tL?T?[V? 48 ?g?##ζ?}N{?zp4?`?ߔ7?_?Y$/F?=ܱ^ ?s@Ģ?9?1\|J?DQP?0: ?`@Kcd?Ԏl%?>#?r6bOc>->X>ԳZ!<>/Jzdg>CA>`o>c>p/}>M{e>?}>dIp>ɋ}s>oadV> [y>sĴx>f >w>-Id:k>,FZ>́O'>հZL>\ >ya B(>d!@? a??'4?7 4?HI?Xu ?gvn8?vgUL?K, ?Gf%?Jt^?'mZ?eF?lEl?7Kp}?B?3=L?&C X?ݘ`?lXe-j?{(|?wq#%h?x-,I?~fg?-PQ{?H?e3~?2nGzo?aX ?;6?w5?Ct܋?nlit?m? lE?G מ ??F?{?F&\? %?Q[#E?v-Fe?,?rNH(?q-b ?tT@)?|(j?_1M?P_?eF?~ o?+0?8?RvN?/3?AdӶ8?:츌W?L0?}|?SP??-J?W+6 M?M??3*'?-L?>0''M?ȃ?di8?H:?DP ?"͇h?*?[X?V ?wnvD?jcs>?[U4E?Lj]o?>srH?1O)c?"-HI?>+8c?0]/E>+$ ,>b> >̟dBS 9>Zw>i<>Y"L>cav>?>mR>|˙>L'hG>`>vDӝ$>ln >hG>6\>{ P>M8I|>>񱓙(>4X>܃x>HG?8?V3?,(? ij?0 ?AQ>+pm@?QtI?`_ }l?o.T1?}bR0?[͘ l?oyM?{&t? [.=??z%U?YN;H?>I?71z?dI?@d?wfA?rʭu?r^?vdB)?bI?dbV?:V@?t'l{?$U?[ ?|,4?7+j?|B?^y?R@?Amy?R?TB ?&E?g!I?WTI?vc)?q ل?pSvx ?sp1 A3?zȅ:iM?΍"?E=+?_?_~?N?O?R6?p)'?(?Ǝ߇?>h?Mjc?mUO|?X.0?v?qQDE?7Dr?h{?mq2?if ??[.?4?1p?m#nA?x\b?pY\~?ټ?BՍRi?b@0k?~#Pp|4?qC [?bҷ?S#T??D2R&?6v1Jd?(1G?[? zG[>0f, h>%.>_]M>b=>äoT>{(¸>vz>}*N>3 >=nu>{ >āLE>֍G#>WP`>Pd> Ÿ[>Kp>8_)>L.2p>uޞ>X%>Բp> gH> U >1l@? q?1?'R®?7?GhICP?W&[P?dfl ?r \?YY?.?*>?fe4?2/x?œc@-?<^۸?\,GV?cJ?0E|ɨ?{Wi`z?t'ܰ)?q?qx}?v6]?[n']?˕?dVXp?.v?/{?8!'O)?P^1?R^q&?(?7L[@?D'?]eol?I9?k5?^ k? ?=n?!?h.r?u= ?Q?{?I&w?U%j=%?h(S~T?$[V?g?BJ?ET`? h?L?([!c?C*?!ɳ%?Q^X?vma?i|.,8?[qO ?LSux?<4.k?.>I? ?b'?3Q>_O>W2`>՘.>ƮM(@>#>/L*>T>t^h >y>X>yN[>`).>L0>W^*ه`>>sKf7>c!K>m>7>٤(>IJp>лYC> ]Ő>iw#>Yr?$?L?! RR ?0#F٠??-?Nn?[vUw0?g c?sj?*_x?~?),?=N?i???KY.f??J?uw?y RO4?uIA{A?t9=?vIS#?{D>BL?@N?Hm?ê?⭺=X? ?-rl?S&<}?)t?[~Y?P?$?R8uѵ?4?w??/Wi?~xd?y5:?x}j?zi ]?0h?gx9?W?kfM?&+S8?㥣+&.?Ta?J:~:"?6@-Y+?\?Z?K;?>#T?:??tX??ss?u&[?]%JO??HUœ?2J+6??0$?Խy@?r=G?+?N??V[/>?U׬?b[+?`~V?~BM?p.6-S?bA8?RDX[g?BM,?2};iid?#[2Iz?.[6?t9>󎬦l>5>{x#>I=>Ve<>}>DD3> !>K/:|>G2h'>۳->I.!h>#2@py>BE>]>,Zޓ>ߥ{>kܿj>+@>Ȭ&(>baLF@>5ǖ>ۈ!>KN[?3R'`? )6?=c@?&?5#?C[X?QV\?]YW@] ?gA`?qe5#J?yL?4"g?^5*?ݛc?nV7?? Ƶ?{V ?y2 ZT?y{ ?{CpسH?^_?5 h?k?/?FU?͉?~?N(p?U 'e?z2Z?R ;e]?K?w`2?8YMT?%xG?XHq;?1UI>d?Fv?^?$?u^W?;hB?Dr?6+?z~,?cG?uͅᆮ?gҲT?W[ncF?Fjk?5]f?&ᤰ} ?a ?͞c>W>>n[A:>l(>Iv>PL>-H8>pC=>>DĒ>)>/f>->ʦv>ֶP>O<>Sx>9S p>y>oN28>S3@>uF9>P(;~`>Z ?:|4? ui? `?-aV?9 T[?E&c ?Q?\qp`?eg98?m_h]0?rvَ?va*lX?xhU?yir?yH}$?yB?y??{0?(.c? Ȅ[ ?l?}M?bIQ??J?;N7?w?Lid?:L?=v8~d?O?cp?4FU?G$?Qz]B?c?=C$,?DM?A`5?}LB?ͽx?_1?U-ϝ?P? 0?k+?n1f'?*QQ?j?T,FF?- ?-~?¾Ī?Y8P?E7T?&c\?mB?7:r??Y$?~r.n2R?A?Oh6v1?t2?Z0?jm??Y:?ή?DsB ?mˀ?=;?%m?]Vp?@,$?8n@?U9?zMD?k+"WL?[Qvʋ?I]?8Ze?)kD?7 :?L>كG>>>A =j>=N>ʸO >0>$`H>Bsy>%Y:>@>'>757> ʢ>vCNo~>H’G>x>\>*mx>eP>; H>ڪQv>u P>50>#Q ?<?+pE?W_ @?'mvI?2 ?=]E@?Fo]&<@?Py4!P?X_Sp?a ~{?f"O?k X?o}|`?q2@?s?v4*.+?zhg?~&$k?;WS?2p/?ב鍭?b+?IjMl?#q'?rq? ?6##?(Sl?rʜ(?ʤ!0?__*?hu?TH? Ln?m?wYZ?rÄ,?}P 2?~Q-J?4~?7| ? f?2?6ߟc{,?Ey?N?ɢ?Fhȶ?. ???rh@l?g3 ك?)n?;e?y>q i>򯺡[ >g;>Mf>#>!>+3>8rqcb>E0xV,>͙X >) =TG>SiC>=e>Ǝ鼤>ܣM>jz z>Aޗ>m-o8>d[>~[:P>vw;>UD`>4\q > ? ?:o?E(V`?`c@?' {v3@?0I`?8c?@ޱ i?Gw8`k?PFȪ?Uj5?[?aqV?eۍר?jMA5f?pbܳP?u gP?|WK?C?u#?O3?rGDH? " ??9?JKwdV?73?ydp?$?o}?Z7?P֥?me=-?hcWZ?!?3 ?;}?{(~?x,?yRg] =?at? H?ּ6?R.?!'Mgm?̡ ???N?\ ?W>F?Ji҆i?55? Gj?&?H;VT?> e4 ?s?ٝ&?yUӼc?tu?rE΀?s+ñ?y om?o4?O'+E?iC?fGۉF?75?GG|(?4??n3?->X- ?,?ASj? t?Nf?Qox?<?}y6?mU`x?]HR?Keh?:QgX\?*Wuc?V}? .K >غ|n>U(>x0->e|>@>$N1># 9>h}U&>)^>f 2>4x0>K}>bnG|>2>sT@>=%c>GhM>\(y">Oݱ*>r8”R> >;9>e@Gx?>viP?x!HH>?O(g?$Fe?,%U[@?3˞8?:8Ŏ ?A5 ?FO%d ?Km8?Q5?U p?Zxy$>0?aa'?f8?mx?td=)?~uoR?M4?Ǯ7:?R}?h? ;?ё?I^?B`?Dh?v&\?*cL?ٽzN?m9:4f?Haj?FP?/~#*?|Pq?v4E{?ssKU?s}?wOhan? {@F?zG?IBC?w1f8?1X?^ ?+4?17#Xs?98=?y{#g???H?Uކ?2@?0|jie?~bޜ ?uU_0A?p?o ?qd,:{?w$D]?}?=m ?-LR?bM?s򆹔?hX}j?KZ?-(M??_PV?cBa2?kC\? pb?ɐG)}?2>?0?z9R?kT&?[ ы+>&/Sl>n$pݲ>}ų>VoY> I>Z6h >h,W(>޼TL>T+ >wVn>n݃>D4K>S >>Î*x>/[Z>~> 3(>WB*>ڮg>wf>+=H>+[?ۚ4?E?4ox?'Sa8?0KQR8?7 p??eQ,?D:,L ?Iظ$?NmT)?Qv[ޠ?S<?U#`?Yns>ǩ>ض9QHu>MPN>B`3>:24>3>t4L>K2 C+>YHQ4> )>~Jc>~4P&>[ϧ>&>o0>v>ɣ />!6)>✎y>u>3?{C91?Ꭹ~? zQ8@?)ڷ7x?3! R ?Fi?Ng-8?S8"Ax?XBwX?[;~Dנ?]^W?^hP@?_ϙ@~?aQP`?cVtXy?gmH?no|P?uY.?{r-?]E?1g?@)C?\&ڞ?W#[]?tX?&|j=?4; ?OY?g׼֑8?QCغ? R?C;D?6[*;?| ?M^?x+}?sII=%?qcO2Tk?r[q?vIJI?2n k?g.?> t?DrmX ?;?M.rN?y!W?J-?yU(|?ۚW?yK?> S?Si?b B?u?oO~?_:Z^?.z?y6#?uʬӺD?u4$sZ?wR$z?| ?]\ ?TG?קHY?WI>䕸(>,p^>Ǎ*DL>%Ǻ>P_J>.>=X>^+O>2iS>2Ț>!3>b@>],>hk>̦ʶ>s6MÍ>T=c>*>=2k9>H8?R8 ?n4TV? FM?*IS?5b?Bk:z?Lao>?U?^jSC?c?gs-D?j*/d?k?kփrԊ?kٲM>?kWdp?l vP8?n2y@ P?qm/T0?v J-?~tIr?qiǪ?J,g?\ ?q? V_Z?6f:?bM?MK?plM?ARr!?9»9?/i5-H>-$RgQ>+(>;ŧ[>Ď"XP_<>4,>Ǜ>{O>y~>1V:Hm&>Rʳ>4̓>Ms>5N^>2l'>HҸ><>iOO>ּ^>o> >@? ?ݤEGr?(`{&"?5,]R?Bã ?P4?Zcvz?d]56R?l0?s!Ր!|?wt?zNv?{ÊL,?{7m8?y#x6?w~vٙ?v1)?udm?u ?:?["[z?^vo?u, ̓?|L<.?|_?r[i?Y_E?2ew?B?EJL?^T>%?8?2 ?{ݕ ?Gh1?~!i?zםO(?zJ)?| x*?_:Uh? ?/J?UH?%i??fD4?:F˳?y|??<\>?{?RL?r0ufH+?g`R#?[N?N 8?@@Js?1=?#̗x?D}N"?c(>='>ʡ>Ow0>+B+>&F>rљX>9`L>U $>R[C>.}]X}>L|>.}]X8l>R[>U >9A>rљ j>&͓>+BT\>Ow0 >ʓ>=$?do?D}N"z?#̗v?1=?@@JW?N 8ʸ?[Nz?g`R#?r0ufH'?{?RL?<\D?y|A?:F˸?fD???%i?/J?UR? ?_:Uh?| x*?zJ)?zםO(?~!i?Gh1?{ݕ?8?2 ?^T>%?EJG?B?2ew?Y_C?r[i?|_?|L</?u, ͅ?^vo?["[z?:?%PPA??^X?/_֢±??~C/??{w낁?|{?x?< vx?ze? 0?_?(x?U}=V> y>o>ּ^>iOP>=0>H>2>5N>Ms77>4̓>R|>1V:G>y~x>wp>Ǥ>4,(>Ď"XO>;>i>+8>-$RZ>5-? 1%Ҷ?"?*؍E2?9crO?Hc!,?WqW(?eɳg^?rӅPǭ??z^,?Eo9?WP?N -?%Z?f\? $H? SN?0,t?0پ8??~oSHV?z07*۾?y=ǽR?{3$ݸ?ƭ$?m?c?~?7]H?ßD?X"c? n{??#`~?#А?@?`hk? {?B?iU?5Y}Q?GEp$~?F?n%?FYd'?2n e?xsW?u 3?v6皭?zG1?\R?`R?; ?\s,:?5?/i8?9»7?ARr!?plL?MH?bN?6f:? V_Z?q?\ ?J,c?qiǪ?~tI|?v J-?qm/T0?n2y@ P?l vPH?kWdt?kٲM>?kփrԊ?k?j*/d?gs-D?c?^jSC?U?Lao>?Bk:?5b?*I? FD?n4Y?R8#C>Hd>=2kMo>MJ>T=bJ>s6Ne>̦˯>hk >]j'>e>!3l>2ੑ>2i>^*>=>.>P_>%>Ǎ*C2>,p^->䕸(>M?[S?D?"HSpQ?1gGC?A6QK,R?QA(i?a*g`?o1Ury?} -% S?< ?=RI?s}H??.?<0?'P??FN,?WI S?yJ?ۚW?yU(x?J-?y!W?M.rQ?;?DrmX ?> x?g.?f!d?vIJI?r[q?qcO2Tl?sII=&?x+}?MT?| ?6[*;?C;E? P?QCغ?g׼֑6?OY?4; ?&|j=?tX?W#[]?\&ڞ?@)C?1g?]A?{r7?uY.?no|H?gmH?cVtXy?aQPX?_ϙ@~P?^hP ?]^W?[;~D׀?XBv?S8"Ax?Ng,?Fi?>! R @?3<?)ڷ7x? zQ8?Ꭻ?{CC >e>>✎y1/>!7>ɣ  >z>o>'$>[4$>~4U@>~WU> )Gv>YHQ>K2 B>t4.>3>:25>B;:>MP>ض9QH>>nsV?rG?tΩ}P?% ?5Q#NNz?EFy?V|_!?f!skz?uk9v?\m?EsV?Cq?Mk?۶\Fnm?V@s?Z?.K?Y?}]? n1?2d??3W ?~w''y?vYꔭ?r"2o?pމ)֒?rU͏?wgG%W?X4?7D\? ?3~o?X?WO{?6o5nh?z7p?v 1|?n?oT(?g4?]ۇ?^mj~?YC?@?8̰I? {@G?va pwu?qIo?pW?qkbu?w"X@: ?|yr?'?c!h?s&?`* ?peh|C?<^A?Ո߁Bj?2,v[?ȷw%?Cu?a?n᷈x?E?mO}d?fEݜ^?@}?ufbq?l?e'·?`008$p?Y+[\>+=H >wL>ڮg >W> p>~(>/[">Î*x>S >D4(>n݄Q>wVo>T+>޼S>h,V%>Z6h > ڏ>Voj>}Z>n$pj>&/N>ы ?V^??ɐG)|? pb?kCX?cBa2??_PV?-(M?K\?hX}l?s򆹖?bL?-LR?=m?}?w$D]?qd,:?o?p?uU_0E?~bޜ"?0|ji_?2@?Uނ?H???y{#h?98;?17#Xv?+4?^ ?1Z?w1f:?IBG?zL?at?wOhaj?sr?ssKR?v4E{?|Pq?/~#*?FP?Hai?m9:4e?ٽzN?*cK?v&\?Dk?Ba?I^?ё? 9?h?R}?Ǯ7:?M4?~uo[?td=)?mx?f8?aa'?Zxy$>0?U p`?Q5ɠ?Km8?FO%c?A5?:8Ŏ?3˞8 ?,%U[ ?$Fe ?O(i0?x!HH?(?>vl@>e@G>;9*> H>r8”Zl>OH>\(yS>GhM>=%eW><>sT@>3i>bnG >K}>4x1;>f>)]>h}U~># u>$NJ>@_X>e|5>x/>U>غ|c? .K?VP?*Wuc?:QgX\X?Kep?]H??mU`h?}y6?<?Qox?Nf? t?ASh?,?->X- ?n3?4??GG|(?78?fGۉG?iC?O'+H?o4?y ox?s+ú?rE΀?tu?yUӼl?ٝ&?r?> e4?H;VR?& ? Gj?55?Ji҆j?W>F?\ ??N?̡ ??!'Mgo?R2?ּ6? H?~Q-J?yRg] >4\qp>UX`>vw;>~[G>dp>m->A>jzh>ܣ,>ƎW(>=>SiCl">) =TP>͙X~>E0w>8rqc#>+pp>&>#U|>Mf>gT>򯺠>q T>? (7 uv?G y?*os?:roɜ?K,?]?m0+x?}VZMԅ?迄b?8,'?kK?@9jQ?@?v.?àm??/{b?q8h?34ץ?{!?R#њ5?ɛR?ThkbS?{a?x1d?xBWT?|R?0C}?y#V`>5>u @>ڪQvp>; >e>*m@>x> >H”%$>CNp^&>v to>756>'d>Q>%YQ>Bru>$`>0>ʸO_>=N$>A =>>ڪ>ك=?Ld?7 :U?)k?8Zew?I]?[Qvʋ?k+"WL?zMD?U9?8n@?@,!?]Vp?%m?=;?m˂?DsB ?ή?Y:??jm?Z0?t7?Oh6v3?A?~r.n2V??Y$?7:q?mB?&c_?E7R?Y8P?¾ĩ?-~?- ?T,FF?k?*QQ?n1f'?k+? -?P?U-Ϟ?_1?ͽx?}d\n?A`3?DM ?=C$'?c?Qz]B?G$?4FR?cp?N?=v8~d?:L?Lid?x?;N7??J?bIQ?}K?l? Ȅ[ ?(.c?{*?y??yB?yH}"?yir?xhV?va*lT?rvَ?m_h]H?eg9X?\qp`?Q?E&c?9 TZ?-aV? `? ui?:|3>>ZP(; >uF9:>S3>oN2(>y>9SC>Uj>O>ֶr>ʦv>->xh>>Dđ|>ja>pC=>-HX!>O{u>Iut>l(>nZ >>W?͞?^?&ᤰ{?5]f:?FjkZ?W[nc@?gҲT?uͅᆮ?cG?z~,?6+?Dp?;hC?u^X?$?^?Fv?1UI>f?XHq;?%xG?8YMT?w`6?K?R ;ea?z2Z?U 'e?N(p?~?r`>͋?ݲ? w? qv? ?IΆ?~m?BY D?b |??U?:?U;r?.D?& ?Q2?}\4#r?~x`?[ |?vK?H?N?e— ?j?~{?Ë?r{`?ޚ]Nw? `m?Fv?KN[ `>ۈ!@>5DZ >baLgP>Ȭ& >>8>kܿj4>ߥ~>,Z>]V>B>#2@>I.Q>۳>G2h%>K/ט > !>DC֤>}H>Ve:>I@>{w >5>󎬦r?t?.[3?#[2G?2};ii?BM?RDX[^?bA/?p.6-T?~BM?`~V?b[+?U׬?V[/>??N?+?r=H?ԽyB?0$??2J+6?HU¢??]%JO?u&Y?ss??:??tX?>#U?K;?Z?\?6@-Y*?J:~:!?T`?㥣+&/?&+S8?kfM?W?gx5?0h?zi \?x}j?y5;?=BM?vIS,?t9>?uIA{A?y RO/?u|?J??KY.i? ?i??=J?)8?~?sj?*_v?g c?[vUw?Nn??,?0#F٠p?! RR?L0?$@>Yr>iwP> ]Ր>лYC0>>٤+>a>mx>c!L>sK>>W^*>LD>`)>[l:>yN; >X~>t^h >/L*>#˜>ƮM'>՘f>W2\>_?3LQ?b'? f?.>I?<4.kT?LSu^?[qO?i|.,8 ?vmb?Q^X}?!ɳ%?C*?([!d?L? f?ETa?BJ?g?$[V?h(S~T?U%j=$?I&w?Q?{?u=?h.r?!?>o? ?/wBs?(J?dfLL|?`R?~+ "?W0?STw?U"?Ú6?nPiY?v7?,?w1l> ͆> m >Բ>Xhh>u>L.L>8_n>Kq> Ź->Pds>WP`>֍q>āL>zu>=m >3А>})G>>{({>>ä#>b>_]C>%.>0f, vp? zG[F?[?(1G?6v1I?D2R?S#T??bҷ?qC [?~#Pp|/?b@0k?BՍRj?ټ?pY\~?x\`?m#nA?1p?4?[.?if >?mq0?h{?7Dv?qQDF?v?X./?mUO}?Mjc?>h?Ǝ߇?%?p)'?R8?L?N?_~?_~?E=/?΍ ?zȅ:iO?sp1 A0?pSvx?q ه?vc*?Q[#H?g!K?&D?TB ?R?Amy?R@?^y?|F?7+j?|,4?[ ?$U?t'l{?:VF?dbV?bM?vdB:?r^?rʭu?wfE?@d?dI?71z?>I?YN;I?z%U?? [.=?{&u?oyR?[͘ l?}bR8?o.T2?`_ }?QtI?AQ>+pm8?0 ? ijH?,(?V40>HGZH>܋(>4X>񱓙X> >M8h>{ Q">6\7>hG>lmA>vDp>`>L'h{>|˘>mU>?s>c`>Y">i;>(>̟dBRco> >>aT>+$?0]/B ?>+4?"-HH(?1O)c?>srG?Lj]l?[U4E?jcsB?wnvD?V z?[X?*?"͇h?DP?H9?di7?Ȃ?>0''L?-J?3*'??M?W+6 O?-K??SP?}|?L0?:츌W?AdӶ9?/3?RvN?8?+2?~ n?eD?P_?_1M?|(j?tT@)?q-b?rNH(?v-Fe?.?~Oe? %?F&\?{??F?G מ? lE?m?nliv?Ct܏?w5?;6?aX ?2nGzq?e3?H?-PQ{?~fp?x-,a?wq#%}?{(|?lXe-l?ݘ^?&C [?3=L?B?7Kp}?lEm?eF?'mZ?Jtc?Gf(?K, ?vgUP?gvnD?Xu?HI?7  ?'4?? ct>d!>ya BX>\`>հZLj>́O?>,Fkh>-Id;>wt>fN>sĴ!> f>oad>ɋ}>dI>?} >MT>p.6>cPk>`o1?>C3Z>/Jzcc>ԳZ!>X> V>O^0? 9'_m?{k?*5ca?7 \Ȋ?Dw?S[h?czPN,?r6b#?Ԏl%?`@Kcd?0:?DQL?1\|H?9?s@ğ?=ܱ^?Y$/D?^?ߔ7?`?zp4?}N{?##ε?g? 48 ?[V?T ?tL?@??4;OM?FQ :m?:?W?$WV?Af? *~?Q?{~RTQ?v{.?u8?x.ޏ6o?}qL"?~`C?7$?'+M?-?35l?%COk?!q?E?d?2N@?NG駮??{޸c?OYJM?0B@?|44C?|E?EE?? ^?i50@:??c%2e?:"v?C;?Wg.?8ߋO?p|?`Q(8T?%k?Kbs?h;?rt?P?oj'?`l2X?Q;Ȭ?@d.`?1 @fh?"(l&W?dw@?{,>oY>. PZ>nFh>Ubj>*1L>cI>xr">h\ٺ>￷>M5>{Rz>hxo*>5Rc>"I>8kp>vo>zI>l>`>\oe>Τy>J4\X>ވj>#>a ?jַ _?k߆ ?#3s?1][S%l?? U3.?M?]DS?kPD2f?z?cx-2?ibǞ?׮o`&? >??WA4?<,!?CSJ?≓e?\@?ug?%[?{j??Fc?:cA? l? ?LGP?S(z?{lAd?{?v_sim-3.8.0/lib/plug-ins/nanoquanta-netcdf/silane.nc000066400000000000000000010770001370110300500223410ustar00rootroot00000000000000CDF character_string_lengthPmax_number_of_angular_momentamax_number_of_coefficientsmax_number_of_projectorsmax_number_of_statesnumber_of_atomsnumber_of_atom_speciesnumber_of_cartesian_directionsnumber_of_componentsnumber_of_grid_points_vector1number_of_grid_points_vector2number_of_grid_points_vector3number_of_kpointsnumber_of_reduced_dimensionsnumber_of_spinor_componentsnumber_of_spinsnumber_of_symmetry_operationsnumber_of_vectorsreal_or_complex_density symbol_lengthnpsp codvsnlen rhoijdim1 psptitlen  file_formatETSF Nanoquantafile_format_version?ff Conventionshttp://www.etsf.eu/fileformats/titleSilane molecule - ABINIT 5.3.3historyABINIT generated file : space_groupprimitive_vectorsHreduced_symmetry_matrices  symmorphicyes$`reduced_symmetry_translations  atom_speciesreduced_atom_positions xvalence_charges(atomic_numbers8atom_species_namesHchemical_symbolspseudopotential_typesnumber_of_electronsexchange_functionalPcorrelation_functionalP fermi_energy units atomic unitsscale_to_atomic_units?0smearing_schemeP8smearing_width units atomic unitsscale_to_atomic_units?number_of_states  eigenvalues  units atomic unitsscale_to_atomic_units? occupations `kpoint_grid_shift  kpoint_grid_vectors H8monkhorst_pack_folding reduced_coordinates_of_kpoints `kpoint_weights   basis_setP kinetic_energy_cutoff units atomic unitsscale_to_atomic_units?\number_of_coefficients  k_dependentyesd"reduced_coordinates_of_plane_waves   k_dependentyestdate/codvsn/ecut_eff/ecutsm/etot/headform/fform/intxc/ixc/occopt/pertcase/residm/stmbias/tphysel/tsmear/ecutdg/usepaw/pspcod/pspdat/pspso/pspxc0qptn 0 so_typat0$symafm0,title00znuclpsp18lmn_size1Hrhoij1Pdensity  units atomic unitsscale_to_atomic_units?K2@@$@$@$?????|hs??|hs??|hs?Ձ$/?Ձ$/??|hs??|hs?Ձ$/?Ձ$/?Ձ$/??|hs?Ձ$/@?@,?Si HSi HGoedecker-Teter-Hutter Fri May 31 17:22:04 EDT 1996Goedecker-Teter-Hutter Wed May 8 14:27:44 EDT 1996j3]Fermi-Dirac?6C-GGGGGGGGGGGGGGGGGGGGGGGG@@??@@??y@@@?y@@@?GGGGGGGGGGGG????????????plane_waves@$ۀ2"5.3@$|i,4>MBM.K?6C-@$Goedecker-Teter-Hutter Fri May 31 17:22:04 EDT 1996 Goedecker-Teter-Hutter Wed May 8 14:27:44 EDT 1996 @,?GGGGGGGGGGGGGGGGGGGGGGGGGGGGGG>I4>1G>i>2>hJ4>nX?fBG/?wRiz? H?#\f?,?#R?Kq?Aʘ?ir"=?SX?i?Ab?%%Q?ˮ~ ?mS?eԅiO>A.#>ff >cv c>+e>1>q>0#>e/h>?1>ub>(Śh?iv?^@_?ҙ$ޢ? ^o?(U?% o?0?K5)i=?qg?^il?WE?_&?q,?KS?1E2?%Ƽ?ҌUP? z<>ф?22zܛ?@?oÉK>&^5>>I /2_>>'ƻG>d7Sz>C>>DT,>+fMH>B1H>ANkZ?K? >? \nR?0Z3s? R^u?ڍk#?{Uc<2?Ď Ǽ?=#? ۆ?0?0_?"?Q#T?{/?ڊa? ys?/g? [&!?#?Iis>>v">g[>*c->=쩀>ӽ">mW>ܦ'>?׈Ai4?0ڳk? "X0??Ul]?kAA_?WCo?/OO?9{?nkfo?hs͗?Wӳxu?hRf=?n*@?Pn>Ԭ\>3>cB>̋K>>4?^?&_ ?|!?F8?[-D=?ˤD/? n1/R?"̵?$&[_L?$T%?$CJ?$+`?$?$xȆ,?${I?$՟?$%Y ?" K? m;?sk?Kډ=^n)> sw>Dw9??4ӡ?x(?/s1?jb?VT^?8Lһ?̯?#pS?'|oQ1?*hL ?,d u0?-ݯJ?->߲r?,@IO?,N}g?,Չ4B?-(??-vq'?,c3T.?*9J?'{V?#BX?}t?7cٚ}?Ir"??.K?P3??b!]?'!L?q+? ،Y?gt_?7rm? z?%s8t?*^}?/8?1.Wf?2O F?3]ckN?3^M$?37K?3"ʶ'7?37_up?3^qK4?f? eǬ?e}? f?]}ES?m? X9>M?}`}?]?$?%r_?+F?15?4N?68?8o/m~?8%?8&?8¿?8Ճ6?8?8pZI!?8 J?8A?6G w?4M=?15+[?+ ?%rKV?h?u?E=?}̴? X|r?/u? F@e@? ?*%?R@_?m\?#L?*Bi9?15/]n?5C[x?8$Oh?;$KG?>`qkh?>` ?>Zunf?>`dᐺ_?>`37a?>#}?=[> ?;A?8;FT?5C`~?15(?*@;kW?#r|?39c?R?+>? S_? Ak?V]?De?g=? l?)ۓ?'zwĩ9?/KY?4MdV/?8)'?@`w?;d?6^?1.P@?*,u4?"?։?T g?'1-b?Fb=?{j?F>[?E֓{3)?E,F~?D:\C9?Br~9?AOh?=Z7Q?8>%?2H?,a'AKG?$$,efn?ݱ?wr,K?,n?Ko?FeS"?|8 ?R?$Fk?-Ų?3[z g?8?>"?AT'2?Cȍ?E,1Uԛ?FCAv?Fe{?GI}~4?Gc {4?GI+?FQ?FC/ ?E,&d?C.?A' ]_?>"I?8Goz?3\.?-;?q?$ kU? 6 ?14x?F_d?;ȪME?kѾ#?tt?hz2j?$xkz?-]M-?3\ ?8cA3?>^v*y?A[@?D$e?ECcA?F+T?G}U ?GVRg?GǵJF"?GP\?Gv^7f?F*;n?EKe?D%LC?Awr Y?>_={?8j'f?3]_]?-h?$؝ټM?i?#0?l#i?cZ?Y? d?b{w?$d}?,J8fL?35s?8٠^?>^&?B4?DyHWμ?F>"wm_?GIcM?G'NSF?G] ?G׵ux+?G[d?G'd?GIjA?F>1Oc?Dy^`??BQ|8L9?>_08?886)?36?,K ?$ =?cZ-? b?Yg,mnO?NLlY?h\t4?*?R Ķ4?$l9 (?,r?3!?8蜮?>Xd7/@?Bs ?D[?Fa}2?Gbn}x?Ge8Z?Gב/?G+4?Gב74?Gh:Y?Gby2?Fa $-?D.ݳa?BY+k?8so5?3!Pc?, ,?$ ϓ?R@U?+Z^UX?B1?Dy6jG?F>ɳ?GI4?G??G#X?Gv?G!9H6C?G{␄?GI=?F> FV?DyB]?B_8'?8#D4?364r?,9?$PQ?c^qf&?? |W?Y~?<!UI/?lJ8M?O?iaoQ?$؆b3D?-OT|?3]Q3D?8U#F?>_?AV7?D${?E E?F]Y?Gvt?GA>?GCo:D?G}%?GV?FՒ?E\~?D$ٞc?AX΁?>_[Ë?8O?3]OB?-Z/%?$؜#w?iіi??6U?lZE"?y?G:-?tR?Tϛ[?$qRB?-eqQ?3\5G?8XV?>",8?AS?C}D?E+ۀ֓?FBɆ?Fi=?GI/Za\L?Gb{vZ?GI6yOSS?FQ?FB?|6?E+U9Z?Clj`?AW?>">b?8>gdo;o?Fa]<;#?F>ĉ?E+e6O?E,e?D:5#?Bdk.i?AP~%?=ZAq!?8cٿ?2?,Yy?,a,?$$`M?c?wӖ?- `D?*;$,?"F-p?wX,?Tj(?"ͼ5?*T%?1aw?6^Y?;S.?@2mN?AO?Akr?A92??Ab?B|$ ?B8?Bv?Aǟ('?A~窏?A4W?@#Qvy?=#Zk,?8T(sA?4N1$?/>(ؘ?'{? mM U?iG0~?X5?ӊZ? tv+? ?.P_i?T9=,?>?A?#X?*|^V?15׸3I?5Djp?8G@R?;7?=[G+_f?>#d4=?>_.H?>_©9?>ZeZC?>`m?>`MF!* ?>$?=\?[T?; +?8,i?5D?15t}?*\`?#?D(o?Sc?-o? 4VS?"?]h'? [;D?q?a?b?37?3_=!!?3]A?26?1"!?/x3?*)qz?%t]D? *4K?9a? ? S? ?>f>[?E7?ʥ?2Bcg? ڕwz?7dd?:*ka?q??#C ?'||1V?*SM?,cʜ ?-#)'?-?Զ`>f*O>-{E>B{A?Y?r >A_I >" >n>9Aw>x]>B^?yCAwK?3I1? %? D?U U?kt?WX3#A?%ED ?E?mf0K?hTz#?X??iqZ`?p qq?r:?*8;@?Z:?m?Wg۔?~Wa? Ц?3z?r?ϖ>Ϙ[>Ut>QĘ8>>? N>-l$>i>Cփ*W?T^?+f? ]d?1_ow? ߝ?ڄؕ?{1Zd?d[?Ț.??0+s?R|?OCu?j+?}rM-y?ܳ\? !@&?443? _Q?D?(fݢj>B>D:*e>,z-?>?\P>2 ,.>fWM>@e/>Z04>kz$?z?&(?G?O? ӄv?_ ?%ۆ?0~A?K;QSs?q%?^V?/- ]?_~.?rG*?L?20&.B?&? S? 뽪?Ji?'Z?.S>>>?9 %>e=>1_W>fy?;a>@PiU>mo/>шJR?%@?q?†c? 8)?ub?$fx?/ه5?J ?oc;?]V;%?Ɯf?]?pxS$?K n5?0w?%-bVP?J:d? (E -?D@a?e%6?2l\>,JC>p>>_s>dH>d;)>L$sD>r>i 8>z>50'??\ 3? uPn?߸00?~?ײRp?\?qUW?S?80V?{?+?Wz?б?i[?Ƨ?1? Etz?#b?"!>)zRr>7f,>aPt>Jr>>>%CV>i cZ>wW?>#1U?a?ܹ*?*? a%?b[E?jMY??W /?pt?NJ?DKMB`?8,x? Np?™?Nm>X?*980?H)&]?yF3?zzt? :!?Bϳ0S? >4>gjR> 9d>%\.>ud>gdϺ>vD>KDmu>`r?k]Z?F qL8? ,$? ΏH`?f]?)}E?5Osl ?g?/=K?s̝#? 4?"C ?#R?!~a >?4P&?#ZN?g~ɋ?8*?3q?+>Eom>6ºͣ3>̕!C>ww2AI> x>? ⋉w? nL? ĐҸ?׈<?3T1W?W$)?l5ܤ?k? &?"W%Z?$0?'ǹ~?+3F?-wf'?//4c +?/:V^?-~4N?+0X?'wʂUߐ?#?FQr?,GE=?&շ?Qr?V? z;>u+?bcf>0?_&?RH?? C0/L?}D=o?xo?U`?u'u_?"Nf ?$]t \?&]q!?) nR?,bJA ?0ݡ?3ɱn?4q3^?5`?5#?4%(?3*jF?0`ߦ?+cx%?%t\y?o4 ?&?$-V?A.?4 J?QY?Kխe? ?C܅? E䯇?TL?.`Of? 1Q?!)0?$u'ڢ?(r+?**?-Z?0ʸ?3UB?6=Tܗj?9E֎?;0k??`?!Z?&ng{B&?+f??/ ?1Zer_?3gC ZX?5ٮ?9{eJ? Ѕ?B];?DeI?FӲw?Hdr?I^M@ 5?IoA9Jz?Hb?F4L3b?C- w??Be?9,ܵ)i?3*ezr?+/`c?!ЦF?Fhr?1?'?!;??Z?'A?|Cx?"MW_?(+~ ?/ .?3lt9%?7#(R?:d`拹?=zWm=?@p?C5ki?E; >?GEh?I(C?KpIRN?LS.`~J?L3U(?J@Q?HbjJ ?D ?AE!261?;tP?4?-ݑ?#?') ?[M8ړ?,o ?Ԡe?}{?2m4?L4?$[|?*<+HK?1YK?5>no?9`f?=,s?@ͷB?B y6*?E/(;?GK?JZ:f?L2eW#?M(?N9dQ?M] {?L3Bβ?Io"0?EԠ<ɾ?An1?< ?5׀?/9o[[?${S?KuvZ)?#O?Ft"(?Y"K?T P?d\1_? oa?&[?-K?3f@JȾ?8pdځ=?=@*P?@ n?Buǡ?DR?G#~}-$?Ic! ?Kou?M0w ?NwNTq?NLdE?N9KP.?LSL?I^J?E$e?Ak)?)??LQx.?L}?L!?LGHF"?KoKB?Jrh?GC?DA?Ah??6|?GAQx?E.[:,?B-hD?@?=XH?9TF?5iēM?1Z>54|?*2?$\"a`{??3tJ?~DCJ?ZP~?!P98?tK?(9+j?#h_"?-,3( ?4?;uCQ?AEWiE ?Dr[?Hb?JfLJ?L3?LRżo?Koyќ?IڈU?G5Q?E[\#?C4-:?@r<,?=ƚ K?:d,p\?7#8QM?3l. >?/ S ?(0?"Mǐ`^?">?'|3?S*?,j?5̽w?ؘ?F=?!J{j?+0L?3+q?9-@W??aY(?C-Z/?F4yQ?Hbg ?Iop?I]%ߘ?Hd)?F$F?DLg?B#?@Z?=As?9oT?7#fEsX?4F'2lE>62 >4? rWV$?}E?kzz?:?0+.?#AE?'yQե?+1ڨq ?-7'po?/:E?//$~?-=S?+3?'ɾ?$k!?"I`? SÕ?< &?u?Z{j?5Lo?fN? z?oq/(L? .s(X>Ʀ>"9Մ>yr>u>:OR>Do"?U@8?G??jN6?+?erO;?!H/;?#Y?$}k?$_^o?#)5?"&|H0? V}?t ?0VSm?i2?7!?+ ͔[?P^ۑ? Ц00? 1v ?Gy&?D.>}c>L͔>wsc>hHH>?sB.>܆> i>d!? n?FF? k?|dY>"?Pq?Ig?*i?NLQ?`]?Ϡ8z?8u[?E7 [?OJQ?r;=?Y!#6vN>wׯ>ምG>E!>f,s >->XL[>; Σ>V@Q?%T?e퓸? }#?Pa?NsG?,?&'?WGm?*?WLDU?8e47XQ >yg/MX7>hp5a>렬4%>0>%l&>@\>-"&QI>1E(Z>D\̌?;?1? ]َ?0N(5? vzK?Vjz?y^_?9[?7p3? 5\?-YN? 0&9?䱘=E??z+6T?٨?T[?/6N? [<S?S ?0&>?G V>T L>+>>o@>>{QG>>H>y_>%ء%?b-?ݟ'h?BL? aڴ׌f?$?u|L? }?Vvs֦?oAu#?M:HՒ?Cs⨼^?7hwDe?s^?W%?MiJ` ?)Ҡ?G,?e 9?z1k? ?Bޥʅ? voz>6OR> %>U9>+@V>lW`>D*>[>!n>}&c?)ո[.e?Z? Y?]b? ?6*?&?VqT?>4?SBZ%? 96 &n?"Pytve?#789?$oh?$,.?$9?"~C!? g@YSw?T?Lra?j@&? P -y~??rn=> %! >ZQM>v'W>բGh>-3?>@? \y?wHI?;]-T? jҺ?PAH@?wTa?CͩQ$?@? YӅ?#E?'?6J?+vنU?.VKz?0*K ?0t`u?/_Ų ?-T&?)MM?$8gb? D[?*{r3?=? ]?QgX>c>>N?v>!)`>Go>mr?XXr?Ƽ.N?O[qT? _?%?%0ΐ.??-?"-9 hT?& f?+ng[59$?0k.yl`Z? ]St?&cZE?b{ k?@650?@tJ?@.:?>f.?:Ak?6/??1(}?*@u`N?"LzI?*[?u?5ҋgD?-G?"}Xc?F7\(?C?6"ʿ?Ӷ?uт?Nw? 7ٚP?$^?*H?0y?4ƍx?9cAߖ??u?CQo?Ho\@?MFH]5?Qs ?SK~?VL^̤?X5"* 8?Xחe?WO>?UqC] ?QVE[1?LZ$?Eþu?@.qP?7tS?/?$)ʑ?'˥?w~h?}юa?=*?Bx_?pB%7?#4UC?(,t(?0tZ)?5,UN&?:/3!??u ?C ?/&_?5QO?;.j$%?@Ҋ?C\Y?G;q-?KPM?OE~?Q[?SP?V'?X :?Yf@?YFA?X5_ ?U{3Ձ?QNf?L.LZ?E ?@6fmD?774ʥM?0*_ -?$>?XJ?0?m=ί9?nU? ȟV4)?& x?-}J ?4TC?;P?A:c]Vu*?D?Hnd?K#}?Opߍ5?Q"GP?Sx7(?TU`s?V=Q@?Wa칾E?X xs?W .I?VL7x?S?Pg>A{?J ??D8nZ?>{G2?6@al?.U :&Q?#X$?F-,*? ⏲?J?QU!r m? 7IC?@7;n? ?4h80?"GT?+$81?3$|Қ?;iho?B ۪t?G*=?LB%?Q_OT?S!G?UK8?VMc?V=l?Vm%?U)oQ ?T`Y?Sx *?Q|$k*?PZSF7?MF ?Id_`w?EyTk?@cdn?9$?3 }l:?+mm֒?#g?Q~wD4?Jo?ɪV?&S?#dip?.T-?6@sA-d?>z+r?DcPy?J n{?Pg il?Sf?VK0T?WÐ?X >֧?Wa?V S?V=` ?T?Sxmh?Qq?O`*y?K\?HnXQH?D3SH?A:*?;CV?4T7H`?-6?& 6RP? ?Kԛ?m1 Y3?]?'}8?$i|,?0*2QM?7(Ƙ?@6?Q?Eۧ?L.{7+?Qw7Cs?Uzu8?X4B?{e?Y:挜?Yfp?X :p?V|f?S'?Qd"f?O~#ɱ?KPoJ=?G;((?C2]t?@ 9?;.7U?5(U?/;J?' D?",v?mѐ?Th%?T@w ?wMj@{?K2awb?$dx!-?0s{?8#8?@H S?FuF?M՜e?RxU8?V);TC?XM-fB?Zi?Y ?Wεd?UK$V\?RX?PZP){?KA?G; ƀ?C ÿ??uGX?:R?5,e@c?0tAL1?(H?#4|>]?mM?BR:?NP)?}ٯ?3 c?'-?$=?/l?73{?@.?E?LZL?QF ?Uq"|?WNOB?XSWN!y?X4zD?VKA?Srq?Q 9?ME?Hn;?CuM??u<ɡ?9b?4Ӯ3 ?0~?*a\ ?$v? 8NHF? y3?vK+?* ?Oѡ? ^?Fq?"}W?- R?5V?_?>{?Dj~?J5la?PXՊ?S^?Uq*?V)HY?U{6?SfHn?Q_L} ?M4`5?Id;J?D`?@n,a?:3?4ӴuѮ?1 &1o?+.}?&%X?!S=?o)\?$#&?OI'? N ?d#/M?,6Y5?? Zڔ?)/I}?3##%U?:R31?A'w?FZw?K Nc?PX@:?QVh?RxgBX?Q6?PgY?L5?H;(?E<^?A:_͗v?;.(&?5,uN*?0jg;r?+!,&X?&=[?"`:{v?7?q8FŽ?وd6[? izO? VmdM? ^V? Z?z܃KѦ?^p ?$?/!?60JPG?=Ge?Bk&?F}?J\^;?LZڔC?M[I?L.hAG?J z<9?G*kAk?D%k?@AQr+?;;L?5Cxav?0uSf&6?* A??&&N*ޔ?"`w??W%?:GQ7?(GK? *lj~?9o J?X4P?)"?Mv? .Vʬ?נR? F衈F?(ܒp?1U?7M2|?=GX ?Aшz?D ?E<?F1C?E?Dԇ?B ??p?9\n?4UQ?/>O?(a|u?$C۝1?!Th ??ʹP_?tLK? fuj? tL?uc6?'Bc1?P?Ov?DM'? ph%?-_Zd?"M'#?*B0?1c- ?60mg?:˧"W?>R?@/?@O?@6+ە+?>{0<"?;j3Ed?7ps/?3 Ϋ&?-5%)?'oK?#5wjK>z?` >ANm;? ,X5? `ֶ?y?Hca?"N4h?(z y?/IhH?3#K?5Ӗ &?7@Z?8$[ T?7As:?6Av:w?3 X ?0B j"L?+ni}a3 ?&c37?"-q=?l?c?&ǽ?=AQ? 2.?p6/?VDE?X}"M>;>yۦ:>"!ą>Av>n?0? #u?o?. ? FٍҜ?$%4?)?- ?/q?0t|=ϟ?0*D>?.U&?+?'?r$?#Kk? H;`*?@ ?EXߓ?y/?R9NU*d? l?&B>->jܸg>w}Z;Go>,`>|?ul?d? $T}?7xA?C ]?oR? ב?"~/?$Hp)?$`^e?$ju?#-?"!5Ac? 99bl?Tj*7? ޫW=?Wj.q?c? k? t.? Y?Zxo?)Z$>{뭨?2>戦cb>b>C!Cn>r6>?w>5̵>\w+>? ~}+?G%? T ~?|e?aê?H z?*qֳG?Mo?f >8?m2|$K?7?CC֩?M`(C?pgU/?WAy???hQs? aVټ??V e?`3;L>!2>vj@>ul> >m*S>9%P>~ӳ~1>%xz?ڡi . ?4 3ݒt? ;Pu?ߗ=?UTa?j ?UCl?c?Y?j>s?dn?Sɟ?deؓ#?jcI4?U? ei?U?iY=4?SӁ%?~Q? ?/`j'?֦Hɾ>ϓz>V$>%̬q>'>iے~>yt\=>O~pB>sZi*Y?[<d?H.+? /ULd? >z 8>8l>JG>x o)>Uy>/y#0>ԭ? >?x)[PU?<15p? k>S;+?Pܚq?w'\ԡ?C׹U?=" ? 0 h?#s?'>49?+P\?.U-!?0*@?0t:-y?/3?-F'2?)G_?$;8? DkN?*qݮ?? NC?UQ%E><ӳ >oN>LoK>.>hA>uؒv?9 Y?ڞ`? C3?|{J?E?3\ :?`Yk?";?&$*?+ M1*?1 N?4(]?6'3?8S~?8 ?8{q?6RQs?39?0|̃ ?)TuD?#1GaJ??b&J? m?? J;`>K,>~a>sZ>'?+Z7?ˢ(? uK?N?_/}R ?0 ?"(m-D?'A?.IRV?3?8rM?<+}?@/O?Am2` ?B5!?A^?@Z?=!P?8N`?3B??,Wh +?$*uW?E?;k7?һz?/Ȝԑ,?P#? t(?IL?׾?S ? #Q!a?v2??T/o?!p?'>b?/$`?5dT?;Å,a?A4a?Dt2d3?FƱT?H?I&Ը?I&̥?GD?DBP?A=! ?;^i?4Xw?,bt9?#Cfuq?*[^?GM7~ ? 7ڶ?D$5?ui?n?}? `4?B^?]?jN?"s*?'nE??/7?5 .Y?=HN?B+?G1?KaS/?PqO?Q6h?RڧA?RfM?Q,H?M1SQ?G#?B#8yt?;c^)?3C?)cjk? D=/?gCs?~H? M?9?  ? l(?vNͫ?M1RRD?Du?=!ף+?3$h?) 0(?n g?h?űI?O!Qq?@lХ?^Q?Tq^?"o;?(3Ӝ?dZ??e4f?eh2;?c0z?_ҿ~?W%?Qﶼs\?G9W?@Kܝ^?64?-frDz?! +?T*ïf?'d?v-03g?ɣi?+?5?<6Dz2?A|fy?FOQ=,?L gm?Qv؊?U1#?YT _b?^q/c?bg3E5?e&?huHM?i͐?h4J?e#p#?a殉P#?Z#?RqHA?I5?B^5?8k]?0s8 h?${$ T"?g6`?d}I [?;F?"2?'@;F?/} {?54F?=?CHQv2?G߲wPz?L/?Qv }?T礏)?Xw?\ ?sި?`/L> ?bs?eG?g:=?hu:ż?gs2a?dm?`~?YW)>>?QME?H/SCp?FƊJ?@.~BF?6P ?.TT/?#f*?bB?o:T!?#V0+?+&]@?3yv,?;߱2 ?B(M?HuI?OYL?S=dk?Vel?YSۊU?\ Z?^zr?`j$3L?aBWl?avh'ˁ?b?bۿ?bg=?a)%p?^h`w?X@u?p?R2%??Kn?DQ!?<تz?4(WҪ?+X/p?"&\'?Q+? ǺbC?'={28?1mY?8;a?AM?G04F?N%?So?Xn6?[1?^qMrb?`/+4?`@ ?aB`:t?aeea?aBz?`x?`/+(Z?^qD7E?[C+ƪ?X&DJ?Sùk}w?NӂZ?G1d:ꞌ?A?8mʇ?1s?'>rƴ? ԭ?bl`L?"-.R?+˗s?4'V?< K?D]?K~{M?Rˤu7:)?XZ'n?^ ?a)[*?bf ?bBf?bj2?aj^?aBzU?`j)1y?^}GY?\ A?YSa?Vebf6?S=cu8?OcP-?H=Ƈ'?B@W?;cH=5?3+)?+w?#%2ȴ?o)p&?h~H?#@?.T-*TI?6;صV?@.l?F O?P>O?V[g>uL?] ?b,(?d;?eǀ?e03?d<~?b㧂k ?`*?^tr\?[c??Xw9Dׂ?U1|nj?R)S?N"?I/9c.?C?=v?5dB?.Fjf?&$2T&? ȏ ?+ :?"$'M?$@g?0)Zu7?8S P?AmnR/?H]z2?QƬBv?YVx?`}7L:?dS?gr?hur"?g C?e?b͛L?`/!E?\ 0IK?Xw-tQ?T]Z?QvXI?Lb8+?Gߥ,2?CH`ө?=L3rx?5Rs-?/ ?'@b?"B???d*?s߆?${nئ ?0sr;?8I?Bٱś?Ij?R!V?ZR 8?ai[U?e?hcOb]?i_R?hu i?eǎMm?bf'?^q-?YS3;?U1j|)?QvL*?L J1Y?FOENw?A\ 4E?<6A?5':q?/=B?'> .?"(A4?_M*[?Ä́u?212?SX]?#{@r;?/1YeO?8z 3?A{@?I\?R;'E?ZcU?az?eh4[;?gT]|?hqhx?gsa ?d̘"?a)hKM?[]?Vd?R)0|C?L4F?FO1A?AF; Ƽ?:J:ν?4|'P?/P좫?'ntN?!ש?Pz ?\/3 ?uxЛ?'q?h=*v?!ТJ;#?-Q*?6X)?@T$s?G ?Q#c?WozD?_q Q^?c0p ?ehB<?e_J?d֣?b,Y?^'Xc?XE?S=P ?NQѥ?Ggg?A;ڛ?:J:?3;?/A0?(3at'?"/u?Tt/?^b`?[HBH?Oq.?Q?S X,?ܔA?)\3?3y3-?="N1Z?D} I?M1?Tc?Z&ʬ/?_?a+&i ?aIu?`ޝ^&?]c?X4e?St ?O=x?I/|T?CH"?<6{Z`?4|X?/?( 66?#7\̩?jrm?3\?J?cy? hUL +? j?~};?z?$B@?0#.?8Oj}!?A|?G~|޷?O|Ӊ?Tz8[?W%Ϯ"E?Zc1M?ZݓH?(3taC?#N]o$?2馺 ?]Q?vv⤼? o ? ĶH@?9X.8x? ? '?h\v^? EwSҾ?)]?3D$0%ڜ?; RQa?B#xF?GD U?M1);?Q(I?RXQo@?R`JX?Q/?P*]?K={?G1/C?BQa?=?d=m?5C?/?'nq?"㸙?ky> ?3d?? V;?ʟp֑?Ղ?ul?D3f?0?ķ3?,٥*?# a?,Оs?4YJeP?;D?A _[?Dm{Y?G^?IT~?I?Hbp?FVFD?DB?A߽?;?5dbk2?/,?'>cg?!MOU?U ?IӄG?w? L ?Sfg?I ץ?T? u9?v?E{? ?mQ7?6ˋI?$,eZ?,@]?3D)8?8P!t #?=#8z!?@t?Aܷ^?B"rҽNi?> ->ATqV>1g>q*?!M? #|+?e?`=?# ?)v?0?3i_H,?6{?8{QE?8/U?8S-?6neU?4(n?1=Ar?+?&$?"r ?a--T?+-?%?-(? }'a?? R">Q>Ϧ>-yc)>L?>co>=b?? $^;?q?.z}? GJ|?#7,5? Ɋ*?%q?CUM.?w̐[T?Quۿ? j@P?:s ?v@g"&? ?$T>5W>,w>l@9e>w]@>H>;>]>']R?TV?i?2?j^s?cR?x*:>KS؍>v)K)>hO>h>k>EN? c?"?#?U? ?p7?_? m_*_?"_3?$$oZlp?$@N>S>sZ'>5}?>{1;>&>3ћ!>]Q ?/y?V`I ? ?s>??4EL?WO?[?RH? !M] ?"ľe?$pg?'m\?+1s?-ģSТ?/-[4}?/9GR?-֫*g?+0Rqt?'wXu ?#? ?,s?w7?J?? R){P? @1'>I>ApKX>$ GP>~U>9T??Z(M?:j\?:hR? tgv>?g%.b>z,>>t@(z?Y4?̺'? O=#?;]O?_?M ?"( ?'@z0%?.{?3ɍϜq?8/r?<؀q?@.A5?Amb?BZYb?A1?@Us?=!ݧ$?8NcM?3C ,i\d?,xe ?$*5?/-?gmO??詌>? Ƽs?Y>F>L:?1 #?PP?Tf?MWF ?yX?!(?'0?0 FN?5 k?<?Am?D8?GDB?JD9t?KG1,?KF3'?I=+y?E! R$?B&Bg?羺I?5co?,бw?"L>B?/Lr?ϲ^5?aou?a.g?_ mi?Y%h?Sv~?LM '?Dj} ?O%?'ʡWc?/H %?5"??LP?Ff?MY iK?S"T?Yo9?`dZ%?dC!͕;?gn Qs?ie+&?iU2c;6?fƎ?b>Qc?\B'/?Sx5?J[P?BT1?8N?z?/q+?#? *?S7?2%?dq?9=?MMX?%R8?!оHI?'ʱϙ=?/?2̲?4U?=?I?D$Di?Lt8?Rǭ R?X.?`F~?fe,:?kM` ?p2?q[?q s?nP2Ʀ?i fX?bͺ2?Y_ ?P<1\?E,EJ?=!2o?3"`Tg?'wlQ? l)?VZ.`?$j>~?^H?_"U ?!=r?'i?/HY?4!*?;Iګ?CD='?ř?Jӑ@?Qg?W.|?^ k^?dQ"D?kg] vl?q2ר?sr}.?uQ"?t,&?roW?nj_?fƄ1?_ `ǃ?S?I=,M\?@WyA?5Ұ?)?+0F&?"K0_?n?7?TK?!?݇?&[[?/6?57?=?ð?CD=:?Ix?PZ~?U?[Gf?b,S'e?h>m?oMS?s6?vl?w1b?w[o 棛?tž~?q V?iU L?a.c?U’?KF?AU}?7WTy?-ݪCw?$$ j?YJTZ?}PL?"(A?'1!0+?/]" _?6"s??6 ?D+'.?JÕ0"?P+?U fl?ZyK?` "H=?dζR?jW?pB ?tE?w r?xg⣨?w9?uQ 56?q[TL?ie?an'*P?V +fX?K/?BW'=?8#B?/9R,?$͎;2? G1?",%?'@K?0 Vj?6Hv?@C%`?F S?Lt L?Q3?UZd?Ze?`AA6?cVi)?g! @V?l)DG?q.#ch?tPl/?v*p?w R?vۣL?sT5I?p2Ɠ΂?gF$p"?`>A?Ts3?JD?Am?7R2?/-nz&N?$#5?":2?& 35Ȼ?.^Y(C?52?tPI,?t-Mb6?s#3?q1qyZ?kY ?d~7]?\ ?R??GհS?@.a?6@>P?-NS?$V*fz?$޵]G ?+l<?3H>?<\$Al?D\Υ?LVIY?S"'?X}6?^O?b,d6?dΌ?g F[?i7&?jnP?l降?oT.8?pEk?q.A$?pq`?oF?kg?f;-%?`c'}?V]We?N%H:F?D|(TD?Sd?j鸔H?h~ĔN?d&㩄?`.vD?Y0U%?RRz*?IS%? {?At?82NjK?0߉?_j?'If]?$2?+0\3?3ѕN?<ץI$?DB0?NNHw?VP6%?`c]e?fw$?kghw?o ?pm_?q.ϣ*?p1G?o$vӿW?lnե?jb& T?i'?g 䤔8?dΉ@Q?b,, \?^]1i?Xӄ{?S"$?LW ?D];y?<3?3ɚ?+l7?$ު$]u?$ןE?-rP[g?6?"?@.X?G&([?R?3oH?\ (xԈ?dGD?kя?q1|Z?sŔ?t he?tP'?rpjϱ?p{H?l$15?i[?f_G?cV֛Y?`?[ &ߓ?W.U_?Rǟ/Q?MYd6?Em(vS??zu~?5Ixl?."3^?& ^?"Y5h?$ࢌ?/,g?7Pb0-?Am0n?JCt?TY0?`>x/˪E?gVNQ?p1X?s.)?vFzs?wM?vRA?tPq?q.!8?l)>?g 5J@?cVBz?`AgF?Z97?U댰ʣ?Q2dj?LtD?FкQ?@Cb?6&H?0 p[I?'@3?"+U. z? ╧v?$#Om?/8Kee?8#?BnbD?Kc9?V ij?an~/ߑ?"'SV?Ր?XkAB[?"ٞ?-n?7 ?AC^n?KFVid?UXq?a.,},?iUy'8?q Lw?t݄~?w[לR? Gh ?Vۃ ?:V#b? ܰ}? ?ն:ܗ?]?.(U?(͑r?3D #?P:?\ F?Vښw8?Rʂ[?LV1"?E[?@CYʉ?6ɺU?/[ҜY8?'̡?!а^Ƣ? av,?d? jkxdH?\?8?6C:? ۫㭈?*?kK?"Mrk?,,X?5eD[ ?>?Dko(?Jяă?P׃M?S+Ah?U'W(?V &?Tƀ5A?R?W8?NrKw]?IR?D\ӊv??y`t?6#2m?/(?&Y’?!=! _?%]LZ?Vϖ? jkJ?lr?ᒽ?h= g?0XE?d?iq?It?dAS?$,?.ew?5ev?UV>l6?XBf.? bk?A?y]?(OyԒ?%27ZV?$-Z c?,ܞI?3D?8Pd(?=#jG?@$U"i?A&?B B?Am%"[?@. u-?<-{Y?8ۗ?3{.P#$?.w?'@aM?"(W$?6! ?_2I?߫V ? v?ʠJ?>;Xjp>*\I> yo>4z>CTǣ? i? I)?(\?r?"O6ԱC?(C A=?/y4%?3#R?5ӭg?7.i)?8$a?74/?",ys?P?.Ë?$-A?yQ? W.Y?Jc??ڇ ?Wj>yI>(O>#~RP>b˨_y>'3?{`d?jqo?!? G?1?#Ak?'y~R ?+1 ?-޶Dt?/9?/-~?-zz?+1@x?'O7w?$#gl?"X;? V. ? ?buw?VG?2r>?H? R?}? n!'y>M՟>" 7>z1e@>|An?-Y8?d)?5(?$QL?d?;a1?m?#b%q?'|5 ?*o?,ac^?-:r?-f L?,ץ?,d?,I?-k2?-uϜ?,a19'?*Їw?'zu3.?#|ɒ8?C0>?7o:,+?Ma ?TB?0H?LY$4{??$?Wi>7?cdn^6&? (?5? ?%?7W?cn?u^UU?"MZ?$[ݲ?&[Ӻb?) p?,\?0>)?3$?4˛0?5Na8?5=8?4o?3*c`~?0Z?+c'x?%tsH ? \?'T?f? hͩt?1??qɳ??o t-? 7ݮ?#3~$-?'e[Y?-㦕?3 G?7o,?;iY!?>zt&?@6-?@3W?@.,?>row?: i?6/$^?1Kr!=O?*@ߢ˔?"LokG]?+H26?9F,?D6`?1|]۷?'Y7K? !(d?@ ?Ҙ?Uʷ_? ,"E3?wC_w0~D?H?I?I0)?Gu?D3O?AIZ`/?;n?4XWD?,¡@?#U?+B8?D?pF?,T?Ih??x?Q|:U? l\`|?Wß&?%O?!=k8?&YP?/Vۨ?6ޥT??yRAfu?5chz?,@?"L1{?0?? ],X?c9?Tq?a<ɫ?]?/MZ`?4[? ϶?&Vd0p?/cn!?7+wF?@܏S?Fx_?e?MiѲ?S,F9?X͗?^q¬e?a,Rha?cR.?bѭi/ڰ?4Xң >?*ALG?7D?8p? a? f1/? r? kw!?8L*?[|n? [q?&)?/"_v?6V?@%U%?G?OV$(g?UQ{Kٙ?\"Ģ?cI/ZU?h}0o?lڎȏP?o l?n?ktN?f;0?`fT?W"D?O8:3%?Dj8?;5J?1zH?%u?6n:\?I`=?H8U?vɴ?W/?v@ ? ؜L?'-kMa?/]?5g??vXo;?F4?Oǎy?UuJ?]N??dGrk?loM1?r%1r?uS#PP?vM?vJsZ?tL6r?pjǙ?h6'?`Q 8N?U߇T?J- ?Aor?6/so?+d??#H_0?ĭ`>?pڀ?$LX?%vI? ?&xER?/]]Q?5L% ?=p~?E6G?N!L?T@3?\.ۭd?c*?lSMTZ?sZ1w4?x {?|֤ܱ][?m %L?~RQ?{kØ?vV=F?p?f4# ??\?PGعi?D4?:w?0cUr?'{f6?tF|?ng?T|H?!=?&V d?/"4o?5?=f ?DOw?Ld%"?aG?iT"s,?qy{ ?xYo7?~D?b(d?\RӾ? &<?Sjm?{k~w3?tLמ>?kt8}M?`yb?3*}M?*?"MYy_3? 7IpK?!q&?& .?/d\&K?6[>\??w#ؙĢ?E6Թ-?LdJ[?SB?Yr&BE?`#O?f8FLҵ?n: ?u]J@3?|mgHe?jV ?A?9?Yy? <?~c?vX7?nz%?bљPP?UՎ?IBT?@.?4PZN?,ai&*н?$[r ?#4:Ә?'=3"?/)ʒ2?7,w!q?@,ۜ?F"/?NL{?S/JG?YrP^?`d?d5?j?qSzZ?4˴Cڏ?,M<?,h #?3 )l?;T<92?D\p{t?M&?UQWX^?]Cl4?cl@1?iSP*?n `?q?0Wq?7of .?A]c?IR;W.?S+XN?\?dٽR?lRO:?q%>O?u]O-?w ;?y(U.#?yT j?xF~ю?xH?x0.0?yST!?y(y);:?Fv[b?R>r?^p_y?h|?r$xO0%?xMqcn?~DRQ?(z??(Q??xh#J?~j?yT0|]F?u2(?rM?oW ?jZ](&?f8,kT?ahU ~?\.@?U8!?OU2?FW2Z??z"A?5d 삍?-ل?) ?-1 ?5Ş6Y4{?@5o?Hr?TA>M?as{?lͷ[?uRD?|ռlH??rŷ$?e ?bZ?jٝ ?h?mLm(?y(5$n?s3'?oX 3X?ieH`~B?dmH?``?ZJ?T#} Y?OcwA?GOyt?@Wa?6<#?/:eh?'~?&["_I?,`X^U?5֐{?@V|?I-?V +bY?c&Q-?o L4?vІR?N?[p?c ?F?~^?rL6K?~糇 ?wht?qjZa?jn?dU?`dEJe?YrJ]A?S,?NQ?F8!,?@=?7,H?/ tj?'=W?#3ʼn%?$ZI/?* P?4鏻1?@.8}n?IDh(?U [Z?bol?n2"?v3a!?~(GY$? _?*t?I?%.B?fć?|mv .?u]]L@o?n!?f8H6?`sWQ?Yr )w?SO?LdŴ?E6>3??w~z?6Mn?/d.?&[Vy?!?]? 7yW?"L>?'z] =k?3*^?>5?Gp6L8?SEg?` y0*?kstkuJ?tL ?{jMw?? ɝD>?[d?·?~9?xY$?qx$?iT!OY?a?ZIr|I?S)2?LdlkMX?DO{?=b+?5 v"?/"n:?&VeF?!=xFs?ST?m镎?s( {?#wX5?0Xu8?:R?Dx]%?P??\MUnM?f?pL?vU2)?{jpJ?~zZ?=T ?|Ey1?xε?sZ(K?lS.j#?cF`"Rs?Eƾz?O9 S$?UmyJ?\"l?`r ?bzp?crLSu?aA?^q}?X3q?S,>d?M.p?F3?@ R_?7,n?/c+?&Vc(A? Ϗ??Pe?pg# ? NY?#~Nz?R?b+? oz? '?m?"N"1?,Ӳp?5eʼn ?>5R5L?Dk7Sp?J>?Pכ7?SQ$?U 9?V 8t?T;:?R?q?NIEn7}?IRnr/?D\ ;??yn?6g)$?/4*?&$bV?!=e2,ޢ?$m?VC9? j}?Н?9-?Tվ?خN?ãa?3B?ǖ#?.2 ?# 9v(5?,I1 ?4Z| ?; ?Adv=?DIxY?GwX?I^Y\?Ij& ?H?F\h?Df!\?AyPD?;g)+3?5c|3?/4?'=Di˘?!Jg?SAz?23?u6? 1o?R_?:@?뗭? \\? `D?PW?G?li?/"?"OhH?*D{y?1Nq?61A ?:LwO?>Ţ>Y?@/H_X?@h:H?@69~4?>zd"HJ?;iBۃr?7oO?3 A+?-!>?'"?#30w? 7}?n *?p;+L?|B? d6K6 ?b'?? }+L>| ?azF9? d?t4Q|?H%U?EF?[ ?#p?%w' E?+g.?0,}?3+v?i?4&N?5מZ.?5qf =?4˟ϻ?3x_'?0EO?,}'O ?) Xp?&[IX?$[eC?"MOy?sDW?+xA?gԢ?=6? fFl??]r %?`Zn>5^W?g@eab?yFs?L'? o6~?(bȸ??zF;o%?dsKA?B v ?D t`?EHf]T?F; |?E8?DYK/?AH?=FYƱc?7L?1mzdM?(̥/K? Eyf9?sa? S[? f?G4^Q?xB?d?L=ϰ? L?ێ?$?j6P?"g*?'m]} ib?/τ["?5\Z]?=0?B3&?G04e*?KF]?P 7?Qk4?RN}S?RR?`>?an%?a.\^?_ k K?Yy?S݄ũ?LmcںR?Djw?4;N?FUϧ?Pԅ3+?Vh ?_{[H?gPO?p?w#^v?}jR?up? #?w?B?{*.?t lHA?kD' @?`:'?Sݗe*#?Gq?=FP?21hXD%?EV~?MLR[+ԕ?T@&?\$l?cF\?lRx?tz~?~5S?vV?4;y?g*1?e%?5fɐ?1vsr?ʷV"?G?vS(!`?kt5?_ ds ,?Qֳh?DK?9,9o ?1|?(Hl$c?$)O?'n/b`6?/[W}2?65Ѯ>?@"}?FVED|?NEv?TLGx?\=ה)d?c /u?ib '?qTN(?yx?? ?R"C ?oN?ɩ1!'?Q?A\?洢?z?/V5?xH?noj)W?a..[?R/7?E?;tT?2-GJ?*"z?(~$.?/v$?6ɭ¦?@ '?GF\?PG%r?Uhpť?\*0?c -*nQ?hj?pE7?a?uٰ?~5[@?jm?Na}q??1? {?#?^N.?$?⇻qo?yAin(?o 9#??an K&?RQ ?Fcg??QpP ?Ep…H>?? PU T?S#B??kV?>A?4p$?bvq7?}q-?sÂ?h}?\ ň?Ppk?D90?;.b?35>j?3S# c%?9,'r?B5'1?LUդ?UQ 6(?_ֆB?g߱}?o!?tzB? ,*?@|)?MU?]L?Mlց?t?ά?PР???~5^K?wSVC?p?fyI ?\ۜ9.'?R ʇ?G0ԯ???6;9~?34\ѡ?9M?t?NͲ3??? >m?ZBk??~5IvD?yW3|?t'?oM]$?gQV?_B?UQ`?LV*?Bl?9(?3S—Ov?3\3~?;-~?DwS*X?PtD"?\ )l?h|䥬?s, ?}%w?b w?43?/?ϫ?S򃺝? ^?%Fe?oL?݄"|ql?}> J?y#Ev)?uٷ]?q U] ?lRJ?e{?F֘?_)ت?Vi=#?O׋?E1?=a0@?4T ݾb?0?3Zc??lk&s?wcIT?t1"?uW^!?4?eorY?B$?m?T 3?KOt?>}?{?C ?Kj|?J~?ɣ^ڛ]?I|{?RcĉG?? ?yzλs?qMp?iMe?c O+?\=?T]~?NE[S?FV Y5?@"%(?6Sb?/~*?'m!Mc?$YVS?(pޒ?/m\_(?9, a?DE?Qw+EA?_ YA?ks=?vRЙ'?+?I?OE?`G??54q)?/""S|?'FJ?"b ?!R"1?$1@v?*>&?5?Ao?M1>*?Y\#q ?fI?r@nLk ?{)%z?cH?ܣ?ql?$i?uS/*?bU?W7?wSt9?oO??e{anJ?]fI?Uh?NEI^?EBM}?=Rl?5H-cq?/gsU?&uQ?!=T?i'?*d?!(zR?%srC?21t?=FXw?Gr?Sm?`R:?kC&C?t5X?{)R;P?a7)?ٖ>? *?ulK9?}.p4?w#$.?p by?gir?_ϓ)X?Vi ?PPi?FUм*?>F<5?5'ݬ?/޷ -?&(? 2畤? ?u/? n?3q? >\\r#?/gV# ?&Ҋe)? BI~G?2Tt?cXG?ؐ:?$d?.^y'?9ݱU?%v%n&-?1\]_?;b?DkwUq?O9,sQ ?Wy;'?`V1?fW?ksS5?n$Z s?\ c@ ?VkkC?RM4?LV0\?EW?@CFz,E?6)!?/~Zj+?'q{]?!^u? NN?cc ? i`k$?:F ?Wc?ߔ͌? Vt ? K ?k_HD? G?Ed?D?B F{-??&^?9/Q?4SIڹ?/c?(ǸS?$>r?!R/U?Q ?|"9?J)s? dQغ\?rV?+?vjے;?)[Ԅ?i?%Z,?H1|? G5?l*݈?3M ?%xA]?,@?22M?5z?9-2P?;u`?0 E?-E?*r)i:?(?$DƠG?!(F ?o?-} ?%9? q?Eji?܆v ?iB.I? /p?39xd? aV?Sp?W??F-?%u)S?+\?16G9?4NXS?6"`?8ǵ_?8RD?8+?8Dz>?8?8s?8 ?8mb?86&w?6Gزg?4L4?14P ?+?%r<?̡Eb?OG?=u? \vP?U?4?^2?.p? yL?L(?t? V֔m?!1q8?&oKR@?+pd?/ N(?1Yc?3eU6=6?5N?9 y?<`dI??N2?A7R\?Aظy|?A`v?AD򰘥??SC?;Bs\|?6r)?21MT ?+ddìv?#@ X?ll?{כT[? ++? ]]?n?]tev??zi? ?V)? + ?X8q?"`{:?&%X?*|a?0so?5 |?;?@FZ?C2u?G)1χ?J A?L.s}?MyU~?LZWY?J%?H#U? ?=ai? S:#?_?xa&2^?k?3 >?#e%?(2=%??/N淣C?5* B?=9&?Cr`~?H L?N##?Ra0?V[SOL*?YVn?Z݇"y?ZcuM?W?Td<2?O|k)%?GW$%>?AzS{Y?8O?0P?$Bd?c?]4?مa#? O?pp?w?W`=?n?">?''ı?/G')?5ջM??'i?FZM]O?MX0m^?S" G?Yy7B?`c,M4?dp?g4m?i9?iUֽ?fƒ Γ?bZ?\Bo?SݗZH?J?B*Q?8O:?/5?#@n?.? v?5?wK?W?ح|O? /?'-no?/\5\)_?5EZe??uW"?FU?Ou?U# ?]?dw?lnD?r$ZZ?uSjt?vۅ?v6w?tL]?pՄ?hI6c1?` .nC?U2y ?J+?At>?6/}z(?+eJ?%swb?)?Xic?ߒIǮ?hz? ?L?&Z#2?/+p?5w|'?>6?FU@??PU+?VhNL?_-t?g̕5?p՚K?w#?}%,?u? `?c?GB?{*"Q؃?t)a ?kD4鳚\?`:C?SݩTe?Gkh?=G Кe?218?+`9?!r ?Vpfp?2?"?V ?'-F6?/zX|?5B[?>qn?EQQ}jt?Nζ)?VPM''?_T,(?f,E:6?q`w?y/v?0W?O蓡?v;^Uj?쉰F??o]?2R[R?~?t"}?hC z&?\B붥?O|f?Bv;E?6d3ת?15Vs?&nR R5?"_ˡk.?#Ε?'ʕЍ]?/] yC?5Xav?>8o?Dv?M# ?UfO?^\j?eݓ95?pD&&m ?x(Fab?F&}?ڛ>_?rK?Үv?& F?7hkb?P,j?NȀh?m%?{*qW?p?b(x?Tu?F#F?;䭏ԥ?4M{? ?+8ck?&%P4N?(2?/H>v)=?5$R?>o:oE?EQ o?MFP&?U q!V?]*z?d{=1F?m'{+?v 6?r1?S^?r,h?ZK?t/?|]oЧ?L) KK?s,?Po??ZF?ϿXw?tL<?fM?W.??J"h5??6m?6l9T?/ d6ob7?*ӵ&?/P'i?5֞xU??v>??FUӕ?N}\?UfFWbl?]sS;?dZ H ?lIf)~?sV]?|UGpO?$}n?@o_?ga?*E?( ۱?/`?PfZ媨?L"-G???Z[X ?n;?v?iUxSM~f?Zc?Ј ?LZN?AE~}?8ʒ?1YE0?0tP?5zH??H?Fܿ0?P)I?V >1?^\7n?d݂<?lI {?rô?xhak??L?B˜ʛ?w>?]9?8L??p?IG?2N?RTW?6 R?յ[r?IA?v^?i¹@9^:?Z݀?Mh ?Ad9墮?8&?3e͑Q?5Aw?`%e;?{9E?@xs? q$5?*za,?ZB?qz-?f?}VDo ?r$s3?d l?V[dI?J ?#?A]@?8*?9 %C?@n?H+͸?S!|@r?])?g?q`YV?xʴɞ*N?;? ة?BWh?$A?fX?rȰE:?{ra.?Ĭ?`Y?co?1)1? (x?q1/P?A.a ?qy?w#_kY?lnѢA?`c?Rˉy?G**w5'??Xo?8{?<`yܪ?CDj?NѺ׺x?YM(T$?dO ?6?pLr9?y*tI?,o?⢫?@0/?p?6>N?僅?{S?MJS?{}?ľ?b5R?vBs?@:?V?$?WZ ?yLs?pX?d]8?YqJ?Nҟ H?C4?<`?89??V?G)ie,?RܞNT?`ct?lm҈۪?w" 8?0?Ә?q7bY?K?)o?cw U?a2*m ? ?{R?s`Έc?p~?o?8ۢ~?A;?J <z&?VZx_[?do?r$' ?}PaO?/?q{U?Zb?*y_?LWR?Ͷn>Bx?pD6і?f]?_;D?UI?MY`v,J?C7Jh?;dGR)?5?8ȓ>@?ATр\?L- d?YUFB?gZ?uRpC@U?t-'?tj?C? ?'lѦ?HJp?u~&?bF?d4M?̓?~})?D00?je6P?xk,?sd-m?mk+ ?eӨ?_T4ٿi?Vi5j ?Om@$?FJW?=:A,?57Nq?3e`&5?8 ?A?MrlI?ZLo?iB+.?v]j\? 7N?w?9?{?Ie?GBz?mev7?p3+?K?lc?CpT??n)0?xJj܂?ri}?lIzy?dv(4?^]-?V | =?P_>?FdLW??MD?5R\`?0t =?1Y4rW)?6?ADx 8?LYx|'ݷ?Zb׺z*?iT]g?vJ]?Nz?)?"U-?KA?P/D?a6ˋ?5`:?/GpM?(2f9?&$?+Aiy?15xH?;1?F2`w?TRf_?bS?pZx??{(M-?>׭.?MUg?OhoT?z= #?h?+?r \?ڼ&0?}T?x˖MIB?pD|_90*?eR\'?^]BQ?Ug_G?MmZ{?D+?>R?5-e?/]6@T^?'V"?#yy?"_NA3?&md?+I?6꫑o?B{N?O|'[?\BaF=H?h̢98?t^̥?~!2?4?x<?o$v?DU?uġ`?9?1?yP(:?q`0?f)A?_T̺T6?V ly߹w?N?EQY?5$R- ?/u,?'-5ր:?">wMM?14P?V4{?!$?%sL?225n?=G?GɃ?Sݺ3?`|f?kCI24?tN?{)S_?[ё?ٌ?X?u__Y?}kFx~?w#[Dq?pB۔?gX,P?_*<]?5ҕ?/}?&7C? y? ͮV?\s?p?A?Ȱ ?+fmK/?61‡?Al-?Jp ?U?`4?h7ߊ?p,?tL@!?v|5K?v(2,u?uS9?r$eEy?ln\Sy?d\^?]E?U+ [?O ?Fܒx<5??v&U?5/b?/\?',n? J?c wz?Vi*?v!1?Bޠ?;NuS?c~N?#B>AŃ?/`c?8Q"$j?BX;8I?JF d8?S"WW?\C @?b%`?f_#UG?iUJ9U?iŽp +?g])?dj?`c?YM?S"G'2?MXcs?F'T??_;?5rq?/G ]3?'|xl9?">? BΏ9?V{J?oy? r`? ]? ??ۭ?$Hב?0GΘK?8Qy?AOP?Gϴ?O}Dž?TtTT?W[TM ?Zc ?ZtB2R?YV:,;?V[H?Rk?N]@/?H趓?C,Lq;?=Ƿe?5dm?/N>Qy?(1ӣf?#ˮ?0kW?J#?u'*? \c_? OXz?4?"^G?U:?ȓ]c?v? 8?;8;l?Z ? r?$?f? ϠR&?&D?]?#CuR7?+hOK ?;HB??8i?AE]V?A}٠?AC?A]L??rT?<`tӈ?9 }"|?5Q?3eFZ?1Y 6"?/Ev?+ Xc?&mDlz`?!T?~Kj?j<{?֯N? c:g?6r?]FiN? "ȳ-8]? kb$l}?66g??XIqD?4v"?#NC?* $?16O?5Du?82w?;O/?=Zd?>!Q?>][?>]-a?>W,0?>]\1?>]KA&?>!8\?=YV>??;C'Ȉ?8@g65?5C+ ?14 ?*]&,U?#Wl?ʻ1?Tr~?0t&? :? [9?  #? fg1? Ǔ?7,?:?!+rW?&oP?,W wo?0[A?3k͛E?5A?8n*#?;K:[??XW?ArI?CMLc?Dh?E/P62?EL^&?Dc?C,3t?@?;kw_?51_L?0[-?'xZ ?R+~?N`? F\?2Wx? dx? \? oاo?h۰?t ](?V?"`?&9aA?+?\0?0?5*>^?;,e/A?A9-`nzu?EM?H_?L"Itt?Pf:?QފO?RxB?QP?PXT?Kk?Fh-?AAh9?:=?3# !H=?)@%M$? D`?Ϻ4?U g8? Bs? n9MO0?e?N#?$9?l'%f?#1KA?(E(?/g4t?4z>?<4ԩ?CF,>?I.HK;?O*?SĚH?Xb[?]'_?`ށO?a?a9Âp?_?Z&c?Txk?M1N \?DA?="`K4?3])n?)[%z?0{]?11?4$?kL.X?T?NϲZ ?&ʄ?! ??'D ?/>=X&D?4Ӷ?==/d ?Dň'?LrQ?RƎ畩?XȷD?`hq?f˭^?kU|?p1?q[%?q S?n)Z ?i ~9#?b'?Y?!)c,?ĸ?k~\s?!fK?&\&DX?/gdt?5=v?= JT?Eu?NDSlO ?Ug\?]Q?ez;?om=?wS sq?,b?DԘym?M2?Ufg !>?^\4؞D?ekq??pCH@b?x{F?5e d?ړԒ?r?$?7ڗ?J$?P=?N"?Ox|?{*ڜU?pu?bSDg?T5(?F h~?;?5C,k?,V2?&#?(P?/??5Kű+?=Ξm?DcSj?MUn?U8?^N6?e6?o,>?wVjQZ? ??7{s?`R ?ٿY?g3?DYI?.T?<,6?l$-?N?s>?vV:-~?i o?Ƴs?Z'mT?Kw??@i?8:]?0$d?+$'?/ddZ?4ߙXP?=V?E.m??M??UƨxQ?^;kvWk?etnDq-?nZ";?uF?C$?m{'?6D?Bco?"ٴ?M?b\?Jq?nWK?;?P0?ʩDth_?{kq?n;{:?_Y0?PXw'.?C-`S`?;ƆK?3l?0-?4{AN?=>T^?E6JB$?NE?Uf5gp}?^Nyf?etҘ@;?m eym?tu" ?| ?zbJ?ˑSE??R?V+?YF[7?4-$&?G>yy?{_?JKV?(϶?=1?Q?~͌]U?q 5f?a/ѱ?Q6 ?Dn2p?=Z?5¢d?5+{=?<5\15O?DFw?N҃M?Uhl?^\g?e?nX?tuc-Q?{5 j?R?Xǘ(??2߮8m?'-n?]P2? 8?wi6?<)"?G!?p&?D]?o?$~?Rݭ?q[1?awK?Rx4$Գ?E=^W?>!?8o)Q?;,mk?CGΡ?Lshǚ?T;??]~n?e?o,C.u?uA?|Qׇ?Xѽ?U\Y:l?.CS?qpo?Xu?2":E?[?%%?wV6?4>?LS?O?p]~*?uaS?|!Zp?p1"(?`xޓ?QެTG?E?>]%Њ?;i`?A9#ؓ?I.{?Rƾ,?\-eA?ez!?pCUW?w]6u?CFh?g\m?4J?@r?GG'?dM{`?h,Z?餹? *?Ka?i$?XG?ԇ?>He?q7=?bS+?xտ?kˍ?].%?Pf\?D]u?>];[??YMn0?E2k?OyAw?XȆܣpE?c2f?o,ͩ+h?xoS{? 0wԚO?l~o?dK?2}s?q F#?dAj?)S,-?ucb?Q?W1?'=[?]|,f?Qyy?Bv;?`-(?+_O?ou?sZV,M?fRy?X*?L?CN6N?>W5?AhH?HwL@?S}=G?`?lQđ?wRƿT?bY?6_YЋ?!?ձF?'P1a.?Nl ?'^?uz׻?S87|?u|ύ?Bn?څ?'Y?z{i? {P?7/6/?ks|?wSr֤?lRg?`?S_i?H?A4b&?>]@k?CMHz,?L ?Xe}?f7Va?sY!?v?ىXs?`A]I;?Dűr ?Pf!C~?]]~]lx?kgO?x-?aIt?qNZ˥?ؿN?hM?Yi?U?΄?rR? rZ?8e'5?e*(^?G~ ?!i?밠i?m,?Di'?wv?pD!Hr?e{?\._o?R!z+?I.f9y?A9Bu?;s?>!I?X?EŎa?QO5?`ݵm ?p1Jt?|N&?t ?B8?ަbE"?LAu?3 =?w}m?kN"?[*Q?lFL?x:?r'>|?"B@?U?Y&.?| 2?u0?o-02fA?e ^Yj?]ܩj?T?Lt]7 ?CG&"?;,#ٕ?8o%;?=Y<)?EpQ?Rwiy?aQo?qZ%?ح?#OS?ѣ?CZi3?yi?F'C?C|"K?wd/?+]?^'$q?(h &?3Ej^?{@?Y`M6e?{6]?tugn?n*x,",?etm;?^\ !?Uhh =Q?N(=?Dh&!?<5If?5+_8?54P E1?;N6s?DecԆ?Qq^?ag1?qwJ\?~N#a?Np&(? ?td?JxQY?H.n?Gh]k?4>D?YN g?Sי?Xf?̱X?4{gtlF?0Ŕh?3k;?8L?C,?PXJ~c?_yUTt?njg?{j$?{Av]?O &*?a?m-ʄ?J=4\.?UGb?LXn.?D?B#c?#?mɄ?Dib?ux2?n|d?euJ6a?^; 0q?U(?MCz[?EFn?=N"2?4uEp[?/Z?+ؿ '?0r?5Cޑ_?@?K5r?Z&C=$?i x ?vUH{L?LD?M r?>n=5?%c?o0?C],?-`?ٸdlf?a1?7H ? {U?wu(?o-[0HY?e0ZX?^O Z҇?UlN?MVT=а?D?=Π?5Kf?/>B?(I {?&k(?,V(&?15?;P]?FLߓ?TYRLW?b=?ptՕ?{)V?fB?MD~ VV?OV곉?a?!?zvm3?q?{?ک*?r[?xˇ{l?pDqi3:?e?}N?^]о ?Uf?Al?M)|%,?DĜ?>+X?5Kl/?/]t(?' [d?#Uh?"_%?&nq|!?*6X ?5uc?A՘ `?M2+_C?Y c?f񨗰?r@6?{)7?0)S?j?I6?$?DY?=>M?4?/=(v?'ɇ`] ?!@?$K'Rj?MT|?Zn ??5US+?WVf?⣍.?)xf_(?3o=)?=%:3 ?DͲ;?M3 Ew8T?T ;"G?Z'Ee0U?_Ƅn ?a)O?al6a?`p'?]?X _?S )|?OrS?I.V?CGh(?<5+3{%?4z;?/;?(wU?# ?i? Ú$ ?I?/? lǬ8s? ВM?4}*?m l?  %?)z|?3%=#?:7F?A?Fgy?K?PYC$8?Q\˩?RxA5+?Qި+\?PfN?Lڦ+?HU?ERV?A9{&?;,xpg?5*8)?0SZ֗?+K!z?&Бa?"^?qh?-?p*(?Bp? kix-? Z/? diEi? "#?/:違?=Ȭ?)sp?'|0|4?0MM?5y'?;c?@CT?C-(q?DrC\?EV"1?Ef?D5CI?CM,>?A.>??Y ?;(M8?8nD*N?5c?3k]?ҪK?0rÌsD?,UaSl?&mjfZF?!(z$]?U~?3>? ?K3!? bs? a[?%A,4?ܳ9? -?oÌF? pi?' ?/8`ߟe?4O%m?8E?=# =?@J~?AKM?AMb;?AefAP?BcS?B=?BSM?AB\?A]c?A&Oo?@E(?=!Z(?8?4M) ce?/Cp:us?'{ykUK? mǻ?j?@@/?Bjs?DakY?FLc?Hc@;K?I\%?In+J"2@qV?'hў?/GMj\?4݊ ?;α#9?CBX/?J?QPKJ?W,r޳?^_?dzfU?kg82#?q1s?sBy^?uQM?tn%[?re?n<?fƮs?_ ]`?S"޼?I=nNX?@0)?5ӣ@o?+10i?'|h:?vTkA?pm l?U3!^?!>< ?&VM ?/!+?5~|Ӣ?=Tc?DNP$>?Lbwݎ?S@?ZH%G?a/?iS8w.?q SJY?xY:1?~M@?Pp%*?n?{k5R?tLI`$?ktsXg?`0v?S4?G|OX?>!?3+c0#~?/lh?$ٛ!?!S6?"{?'Hک?/"W?5a/?>wF?E^lt?MJ9?T>_gw?\#x?cR?lQ%1 ?tYzv?~5@ ]e?v|?4,kU?fUN?mC?W?p $?M?gL_?vSǶ?kto9(?_ s"?Q<7&K?D6?9-n>!?4MKw$?+{i?&%{?(3H@?/Hr ?5>}f?>lo?EQ ?MQk?Uh[?]I&?d8K8?mw@?v oȑ?F-?it?r*ƎS?[x7??ޯQr?LJBg?s!)o?P; ?k^ b?l?tL;?fƨrm`?We?l?Jr[{??}?8^?0D?+IZE?/jfE?4߂?=v{?E۞?M5?UrEܙ?^:6?etv-x?n5B9?u?Cs}?l΄?2-?BmjB?1A?M9?f?JɌ&?o$L?cb:?P#w=?ʾdf?{k6?nBE?_cEw?PX?C-?I?="X0?4E5?_?1 Ai ?3qz ]?;ƽ?DN'7.?MKŭ?U =?^;?e4M?n^CP?uo?~$kH?{1?>+?0l?JŞf?GRW.?{?Lբ!?Ğ &d?+/{?n"?svq?\-0?A̽ ?rգ?c0V?S^x ?F4='~[?@nL3?7"f|?4 ?:IfLz?CCka?Lc\?T/ ?]ajdl?et-Z?n^{?tX?|sj"? ܤB ?IL?_d)j?W?Ҩt??1ʨ?ڢ0?ãY>? :w?J5{?LW\?T3-? 9Z?tݸG``?ehGC?Uq ?HbuL?AR(-?9T(l?:.1g-?Aԝ ?J~ ?Sp<?\1X0?d ?nM+?uJ?|qO?D?# ?2S747?o?HpyM?b??HLZ|?jQu}?B7?B1?[>B+?uPvR?e?V)z$3?In\3?Aus :?=?~@?@c?G}y_?QC?ZHd ?c ?ms6?up#p >?~$P﫱v? "?#a??R8??ڗ?T-P?!7?آIj?X^?A°?1wSb?f:5?L(?XIk?,H5?{N?s 4?dѐ?Uzk}O?I]LB?Aߟ`[b?@LE?D?Nk, m?W-┥,?a0?lPb?v (#A?C״?z'i?HL>?2V$n!?0?$YD(?yS ]?\??bq`?4tO?n6?H}?`+ix?FҎ_?ˈ*?Z^j?44-;?~LG?q1_?b,,?S8_?Hc?B]8X]?B̲?Ib4M?S?\*9?a zd??)?# \?0+w{?? [?~5v?q?d=K?XXE|?MOl?D'?B1?FѴ=?Q^Eg?^] s?kfE?xX_?u-QĨ?qlEV?AM?9g'?|O;?3w?!Z?r?MDU?kQZ?D>C8?ys?? xG?_k(Q?5kP?l%?>YO?th ]l?iS|1>?^kپ?S<٪Ҷ?Ic@i?BEΠ?ANWI?Hb:?Sxm+y?b+ɽ?q0ަq?~b\"?34h#?YҏsH?mVD?F?qu0?H??$?b?1Ω?I<8`{?\p?zvz7?+j?Zw?2?Ihq?{^?C,;?v ɡ>H?lQl`?aQX:?W-?N ?D6?@c?A)?I\vO}+?UyZS?d?s?e?tT?MR?K?E?׉?1jĺ&?';H?{?ncV ?"E-?- ? \?=?WCq5?XM7?~? g`f?~$!?u( S?mG ?c1?ZIxZF?Q !|?5*[sPg?/G_!O?(3 ?&%?e?+J?/$ ?9.SXY0?D1S*E?Q^ޚw?_ k&y3?ks`{k?vS?0S2?̳V1? ?1WqHP? 6P?ӚM?4yPCy?v ???~5L?t?b?lRX?c=1q?\jF:?TjU?MK.?E\?>z3?5 ?/!Tٲ0?'n?"ܶ?!Tf5?$6c?'}Ż4c?3,?>+F=?G[m?Sd²5 ?`ѹE?ks0P?tL4F0?{jR?Ή%? מ ?[Σ?L7]?~xkѠe?xYF7ώ?qG?iS Q?a{?ZI]?S?Lc?DNˬ"B?=D?5ݶv?/!{ax?&V\e)H?!=K>D?Uq?p|0?w'? oB?+4Tꚢ?5m %/?@#.?I>ƫ&G?S}?_ ?fƅ̋?n_5?rFl?tx?uPx?s?P?q1 )c?kg\$0?dGI?^4lw?W-l=?Qld?Jċ?CC@~۠?;Bi ?4=D|)?/GXt'?'u-?!=hD?>{?`^x?&籎?YM?m݀L[?!ԑ-m?-:V?6u?@* ?G'?QN?-׬[?5I?>ڤ?D?JzI?PYL&6?S^Nf?Uq,_?V)!?Uzc*8?S5{tN?Q^o?M."?Ic?DIt?@)H'?:QZ?49?1 t?+!Mj?&$yk?!R^]?n\?%PI֌?Q@&? .Z?Y??]?MCF?!!T|?+5^񡄀?3-W7?9/nC??#%?C-zd?F4Ø?Hb@)?In '?I]D]?HcBG~O?F?D_?B̠$ ?@`Ncj?=>^?9𙍯:?7!(YF?4E ?0!?+Bȏ/?$؎5?t 5?Wve?Ǩr?&? R?.V?'kZ?݅Uok?:c.xI?=;?@KWh?CIz3?E=ك?GՉ6?I?Kn_KJ?LQN?L2Uy?Jp00?Hb`*/?D\ ?AE ?;u)TB?4.~[?-'-]?#ï?+sL ?ʌ?H?#?Ht?N`?zK2b?2Q? 9 F?$?*x"?0-?4Ҵl5?9aEǃ??r?CT-?Hlk4?MC?53?Q&?Sn?VK;r?X49a?Xb?Wl?Uq?QMsѝ?LZ??Ee?@/eT /?7pO[v?/)KE?$1"?+ Xc?WŲl?+s?yU?2Q=?2s?!)~?'n͊9?/P$;l?4{*=?:HBu ?@;I?FM b?L+?R'L0?VcRt?[pN?a(RW=?d}h0?gr˦PB?hmv?g|X^?ehw)?a^Bq_?ZdGQP?R&UW?I-]?A8Lh?8|^VG?/XF?#.?"F-?/I?_-IɈ? ]DC?!ӹY?&8?/4?5>?==7?CBJI?IK~%/?PkI?U1?[Kbu?b+GE h?h^?og*xK#?shՆ>?voR?w|Bt?w[{"?t0Cb?q ëps?iUY?a.ˬ?U9D9?KGWOr?AI7?7kk?-߷T{?*U?"Ng? 8뛋r?!MO?&T?/cɦu?6S`j??ub,rx?E5q0?Lb?Sf?Ypbyx ?`?f7~̎;?n?u\?|ls?O,-?Df:?3`?%? Fmn$?~A^g?vP\?n&?bi ?U@??ItZI~?E5g?NDf6c?Uf4{C?^N+Z?etBz?mP[0?tu,5?|tʀ?=zig?g14?@?Rc_??Yt0!?4U("?Gty?C?JǰL??'-?*Cޯ?lx?~u?q x?aY˝?Qk(l.?DU< ?@U݇?7";?4픪J?:IN?CCHU?LcP#;w?Tx$?]R{K?etV0?n^kfq2W?tg?|*H8? ?Hӳ!?_\ M?aEn?ҽZnK?_]?1.ŷ?ڻ?ã/y\+?ѠF?J5[?LG?p? JI?tk!F?ehbl?Uq)[|?Hb4?A̛W?:c%ߵ?9a&?@\.?Ih'7?S 9 P?\6?l?7J{3G?>p?Z?vW7?Baeol?*?I?X?\?XK?*Od/?]4??s(?d{?VKps&C?Knc:?Dx7c,?EME!?MD-=!?VcξZ?b+ $?n8?yE=?E&C?ʫieY[??*B*?:$?L?.?#kz?* F?(??go? i??3 ? U?ɶjd?#hTԁ?H??+pW??]??J' ?u\{?h7}l?[ߴ?Qz?G 7$<,?Dx:?IZ0?S`1-=?a(HwM?o&Ӧ?|kI]^?PS/?(!?Q+.?,D-?ܾ ?B ?^uM?ndS?@/??1?Z Tl?8*o\?[YԶ?N/A"?J~B?_XgG?ROe?do[m?yaW?n?b+?Vd@J;?MD::S?ELSr?D#?Knrc?VJ7Ʉ?dpSV?sp*K?9',?1P[?)me?Xn?2F? ?ܑ~?C/ h"?3??~0?80#?aS9?3kmq??e$ !?I?ʂ ?j?|UVT?qw?f7?[(PA?R(Uuu?Hm0ܖ?C?Cs?LQ0o?X3b˘9?gq:q(?v[?Dcd?ȀKX?'oOWu?36?1 N?poU[]?Lh?Z?Cvu?bq)E?tu?I ?Ā?s;{(?QV?|9? A a?|.#O?s&?i/M#M?`5?Uڬ\?LWp[.?C ^w?@?Bqu;e?L1?X}a?h?w = ?p5?)?$#?F]a?F?Ȍ_?BѬՕ%?۔O6?@?C0?%T?NZh?c?$d? G.e?Oro?|$e?tuH?lHE:&?cY ?YqX]h?P(?FNsu??t?f?=z?Aj$h?Jc%;W?W߄8?g?O?wYY?yY?rz<`?O61?gZ?âU{?gr?Ȍ?pa7?9h?"ؼ?2ݹ=?7'?fmI?-+?O>h[a?| ۇ?t:K%?m/KM??d#0?\= Q ?SPi&'?I&?@Nk?9bߎ?:c%鐋?@.?HbbI?Up~?eg_?tƺ? ?=P?KmO?Ik7V?lj?âGS?g[?17?.?rn ?Oɂį?6?`V$"m?Jn? ?|}q:?t7L?n_]c?etMʒ}?]ؒ76?T.:?Lc8dt?CCw !d_?:IN?4&?7"뤈?;?DB?Q!f?a*1}?q?~rl?~??PЪ?I'j.?ig?FKƇ&?4s0s?Yy=*$?RX(?IHB?̜E?5vP3?|DL?tu ?moc^?4{wI?0\N?3l\-?6Nfh?AE[s?L[+T?ZczHI?iT?v /?p?4ynj?tJ?K[?O`Sy?p\\"?'ڂnȄ?*Ъ?ekl?@ .?)?|V:lb?s.?lIAE+1?dF yy?]؜0|?Uf?N'nL?FUNץ??vs5?5pB?/PRy?*Y?/ B?1­s?;vc?E敠~?R[??a.}U?n$?xLXH?:s@H?,q??딡\:?q?\yN?J_~?RdVh???y<>R\?qy?iFŌ?cc(!?\=?TX?NDiU ?FU6(]?@!+C?6G ?/)eg7?'nx?$6-D?(Xt7?*?4?@02??I?UȆTl9?bѺ߳B?n(?v\_|\?~? OF?X, ?'Q?ׇ6?&%9?|mj?u]ݷ?n8?f7s1?`11?Yqbvh?S;(c?Lc`O"?E5չi??u<=?6{'?/cm?&nnv?!vv6`? 9vq*k?"Od?"ݾE2?-zNzc?70t?A{/:W?KHSH?Uȯ &?5t?/~wja?&^*?!5{Üj?9 u?S/%?Hhw?Zb5?#i>i?0:Ѓv?8~Ǻ!-?A?I }?R?Zdt?a]?ehL7?g:}I?h2?gr1y?d%?a)eUr?[Hx?VdVu/Ƃ6?'mv\?! ,?_a? KΫ ?yҋ?,>p? -?/,D?$ wu?0`[f4?7?@0@}?E[?L\^$p?Q KU9?2e!t?8߿%?=[SB?Ar-s?BD]?D94v?E+̪d?EYtJ?F?* ?1Z?5Ù5?9b.?=hu?@}Z?B??E--i4?G_`?JlWN?Kſt?M m?N7>?Mۋ?L2f  ?Inq?Ej!?As?<f?5Bzg?/;Km?$}my?Oޓ?8l?{T\?k?P?FE?I @?#6 ?/}?5f ˡ?<5;h"?A+Jb?FM6?L PP?Qu#Ƭ?U/Cx?YR8bԵ5?^pֶH?bfY|5?eg?htmT?iYhHp?hPs'?e(4[`?/]H?7+/?@q-?FGx)?NG?SY:u?YpJAR?`c;mw?dy^v)?jȓ+'?qʛjeH[?wڠL?~lX#?Hi?6?N?B:?\> ?ZW?v?o î?c#?V 8F?IU0?@?5ؑ?25U1?*Bg]?(&?/ ]?6W1i?@?G17?P5T?UgVgI?\a?cf?h\>%?pDnvr?u1N ?~4?%=?8$MHf?h?E8'?\L36?Q> ??%f? ,&?yA<'/?o b?ao5_1?Re0?FwO?<6?8?1Z?0tah?5`G2w??F?F*i?PE(K?VS73?^[{)a?d܎rQV?lGؙH?rU;?xGӖ?>ym?Bmh??u:/1?ܩ ?oxv?%_?T?/!{?6Gt?:;?q? 6u?vJ/?i%B5f2?Z A˭j?Mj?<5{ʋ?Dndc?NhW?п ?1-?UB-u?3-[?x?t?G? RN?Wt(?0 +?y^U ?KnHX?-o8C?H{ ,-?W'?=UX?_:e?ڦoD?t7?e @0?Wx ?M==J?F?BCj?D-X?]h ?pg?`?~{?pI?bfwx??UK&G?L:5x?F`P_&m ?JŲ?RXu?^olX6?jst?w٥`xN?=d9?v/Z?&Sv*?:?#˭?a!o?FH5[}? [,?Qlr"?%?P? xu?F)ñk?rXh?#DRs?,G?'P?E1??wڒ?jc@?^p?R@`h?JE?F<ôc?K!>?UJn0?be u?p?~l/I?'U?JE?\R?}n-?BCͩ?d2d?B+Q?X6lS?!|p`?is_?i? qE?it?1J?NNl?  ?2 W?Bgs&!?~4h?q?dۈ]t~?YR]Y?PYM[?G4bM?E9_n?M7q?W ?eM?tF C?`o(?Y}lK?Gb? y?H>%O?3)TU&?K?!?493?؃?Xb(LfG? ?W?u]?Za9?4ǘ?@O?2i)a???xN?u)#?j_02?`fH?U0( ?K\(?E-t?E*Վ?N7Y`?Y٭R?hs~6n?wi%/? 1p?^I?Pw?v!e?$o[?jh?D_U? %?p?סs3?F ?ji??HP8?˽[?/L?jljCm?XÄ-?xg\;`?pD ?d7?ZC)LZ?Qu3ֈ$?G:!#?BLȩ?D9I$2_?Mмބ?Zu5?i2~?xsR?Q.b?퇣?)g%1?j9?oP"*?Bh?ȯ06?EV?Lq??~ť??5Z&?)]yq?$y ?ŃW?$u?{5Уbg?r;'0?hqF?`dK\?U-}?L  ?C "Ql4?@۟p?Bc4 ?L22gN?XY?hHRB?w]~?9~?]/?EW?F?Q?tY?Ȍ?l?BYU?"? "J?CI@?% ?N[Ya?q)?);6?$V?O /?|3R?tuЦ?lH k?cWB?Yq# G?P [6?FNutYF??t>mO}?=h?A`?In?V(F|M?e+0nN?uOu?Z߰]?O?`( !?Hm?K8*"?*աx?oJ#?%A?IiNc?. ? pS?ᙈ?3(?2u?#{?|?ub‡?ny-?dRZg?\-?Sj ?Jh=?AÒa>p?:n>:B?9n_"?=[KZ;n?E[e?RxP9f?a2@?q[-Ȩ?2?#7@?S%?Cl?G1?Ft ?ş2?wi#?3B?^S?(G?3?4Gi?YLp ?{6T¬T?tu=?n0?e-W?^\-a67?Ug$?N|?D/*܌?<5c.?5,5H?5Üg?8wlR?A`M?M cGy?Zݦ6`?iRlɔ?v?>? ;?겁?•j?q2?-`3?O?FI?ZC?d1|?N'P?CJ0y??#XD?x n?r$ ?lHp?d/lx?^\-V:nG?VCuk?Pxg-?FSϳ.???sLv?5&t?0utЛ?1ZO?2;>?<抑v?FϻX??Rm!?an1?o ?y@vέ ?44?#p} ?.t?Udo?R?P?O?[.e?O*?~5=.?uٹV?pEZ'ɞ?hXݿ?cT?\+!?Ugû?Pli?GG߻?#60u??$^~rzK?$'S?/>MРE?8'2.?B͵A?K0L?V {<{?ao- ?ij>?q[pa?uPvta?w ?xR+?wʮ?ts]/?pzE?j_<#D?d$uB?`O?Z]E`C?U;}?PL?JA$b?Ddž??zRL?6)&xO?/QU.?'1[?").H?(c? ? ?$c?0wKs?8z?B ?Izq?RH(?ZGA?a6le?eRu?hD?i)?htV۸"?e+Kɯn?bf?^pՃ?YSj?U0;ޡ?Qu*a?L [=?FN(?AQ%U?<5dt_?5*7O?/fG=?'=Vy?") f~Q?b0?F ռ?8A4|?}̢iw?SwCu8?$~ٽ?0w@ ?8'le?@0ųg?FC:?M_-Q?Rxj%4?V)֋?XP9\h?Zr?Yv#2/?A=WjZ?CL?E+bB3?FB[ ?F;W?GHd?Ga5 ?GG\?F'?FAwL?E*?C?AZR#?>"bo?8-&F?3\Q1?-p?$|=? ?ĭ?L2 ?LM#?^O7[#?Z9X?jnl/? #s?&^7p?-15?3g.\U?8p| i?=@Woo?@ j?BKT >?DۿM-?G!?IaB?KmM0,z?M.eb?Nuux+L?NğS?N8!bO?LR;(;?I]w?EX̀?Aن,?L^@P?@6֚?7q_?T^v?JEyL ?An彸?7~9L?/0]E?-C?&]5S !?'-^K?/r>?6ʭF?@ ?G^?O>?T6?ZH@<?`?da UM?iD ?oVd1?sӏ:?y'w?lܧO)d?ż?A&$?c։X?k?qs8wyX=?@C-ݴ/?G ?PW5BR(?Vg]?]"n?cD?iz]?pDR\(?t?1{L?y O??b?J&}Fo?S;5?_?W?E, ?/j?]va?vh?uM?wd8j?l-}i?`?:@?Q_y(?EXX`??e*?m+?sm6?x ?hnAlf?C \?Z?c8?Ͳ&?Dž?Ч?(I?? ?vSI?uŒ-?uS—#?g7YU?YWoW?L/1?A٫?>"L?s?8o锇`4?;,M3{?CGN?Ls -?T(?]4 ?eAg\?o+arY?u=?|k`?X1h!9p?TW?>I?qGbbӕ?2$?_}?2&?mi?wT3r?4^?M)u?l5E?y?v;r.?|֧~?p2!,n?`+8k?Q%?E+h?Ar?=?9݇c?@՝!?G0?Qg:j?ZHbS 5?c'Ry?m?uhR?~#kv7? o-&a?щ ?='A?:W*\?t-Oa?fq?!}ȭ?g?z>?`?1wi??M3?C?P Y?F;?sZn E?d* ?U{!Q?I]$?CL?@2%p?CU??LX^?Uu?`\3?i-,?s]y2$H?|A? `*,?@&m?϶?W9V?*Z ?K?ɬd0?"O=?B5ʭE?S56?T?ps&?1Ǘe?4,˼?'=0o?ɑ?ydZ?vj0?grȕW?X4S2?LRhzHg?E++^+?B9 ?G9.?Qu3П:?Znun?d^r2*r?pD:?xw 2?XBo=8?U?G?ݵ{aa?٫R?_ڳ?ig?Fr?4?"?Xө?D?/?͇Q"]?whAIb?0NR?r:?KD#?wǣp?ht0k?Y_t%N?N8R@i?FAm?D۾?KNG#fn?T8?`@IF_S?ia?t>ot?g~U?T\7y?!?' ?m@>?hc~?`UR?BEd?`x|?4/?t5m?!j!f?63?+()?c5? {Pk?FDl?G!m?Oj?Xu|?cUt!|iz?oU43?yk9¬?C:M'?卑Η?Y??1'?dä?>84?~#ra ?*?M?TW?\?u&??B0e?hL?AF?V?SB%?}I?tP27hn?eP?X@4?NuEb?GG,?I`9?Q.??\(OXS?g2Џ?s?im0?}Ƣ?hK>?pRG?W?-Ee?hJJ?dD?~S?O$?㵣t?@8!??km?nz+?(t?! ?|?c]?Ja]7?la?q-?b:)V:?V o?M.N?Ga.:?Km+A4?S[}?`-\?l'+?y&>v?y{?1?ʽ]ه?;?F4d*?F{?P`׻?ЇO?o`?wGh?gj?T? 7)?F%l/Z?ɢ|-?E7?i?W?h$?y'Lk?l(?`.?S;Za?Km?GGT?M.!^Y\?V vAl?bh(^Q?q,3?kE~?I0]{>l?b&?? P??ֺ8?͓?!?.o&?A6gg/?LC?XPm?~V?;P#?ie5z?4?:a?qJ ?caO5?! 2?sFG?g ,w?\!d&?Q?Ia]?F^Ê?NuĹ ?XG?e?i_4R?t? ?idN|?`@v?T愓Vr?KON?Db?E+%7?N7;@N?Y(~?hs`M?wvhx?M?E?O#b ?Ey.J?Q~?``/*Z?p1jTz?| d?t3[/?w$b|?V"8?Ka?3Ҏ$?w* J?b?$Ѵ?k?n?r ,e>?ª?U^?YВ*?|>o?uZ?o,mɁU?eX ?]۸ˆ?T\ ?Ls?CG6F?;-P?8p).?8ε\?AEw?L/I ?YW!l?gՏ?uRS?t9{?t*?ƪ$?l3?'i8N??#s?́ ?c@w?l5?T'?D?iΆSN?xP?sL!r?m ?e\?_SEN?Vh="?OupϘ?F ?=Ȫ@?5UK?3g[\_?3]Ls??X_?`'?Sc5?JS?~R?Rwv?y^?ht?g?e+ } ?bi%i?`.TwA?\` ]?XvWRN?T ?Qus4?L0h?GAA?CGF?=)W?5.ɠ?/ ?'A܃39?"r1?R?j4Հ4? EG?޴,?$:t?0-1?7Q?@88gN?Ej /?L0Ld?Q{e?U{Qا?X4k*)?Y[?Yf "K?XS?V )2M?S_ac?Q ?O*%`(r?AS/;?D$ȼ?Eկ> ?F9^y?GAWg?G遄?G16?|?Gs?G \u?Fâ?EIup?D$G#?Ay?>^l?8p?3]5i?-چ9?$iV ?mW?"O2?q#Nr?qY?s*?sA#?1^kt?"ԅ?) Al?0d"a?53\?; g7?@2:wh?C2&?E-%1n?G! Q?IJ>?JA?LE%CA?M&E?N_1RC?Nu ?M3'?KoeW[?Hd\?D9e?A?C?;0('=.~?40V?-?#e݆A?i"?,/] _?L?rEP?"`R? 2oK?&Jr?-Gm?4U=A?;",?A9{t?Dۚ(?HmiU?KC?OX5?QoPb?SwJ?T f'?VI#?>|s?6B4iI?.Wt`?#e{? V?mr 29?/`3vZ? xJ+m?&%=?.Ͱ?5d^K?=ͮ}?CiY?I.{6?NJ?R(!?U0-?Xum&?[pS?^Ëdj?`7PPJ?b>k?d?G\gi?@/5D?6B;$?-!?-j"?) W?-g?5c??yO?F (?O؜O ?UFP7?\-[5v?a萌Xw?f6ɽ?jR7I?oV?w?rc-?u1+?ySYD@?~Ď??N*5V?EkL?-z?W?~FTSp?xQw?r%\I?h~WD~?^r)?R@e+?Fzd+?>| ϓ?4:M.N ?3]ʖ9?0ܧt_?4TRJH݆?=X)P?EHQ?Oؐ)?Vm?_媯?ey?lPa?qi?uؒZ&?yޞڑ?}z#?pkk?̷̋9?%BA0? !?TPm?ۧ?f?5 ?bߞ?}+2?sX ?h~OmK?\ M?P"m=?DFM K?;079i?8yFh?5,Y'?;i ?CűD?MW:|Bv?U;?_$=?fX?pCZfd?v Žq\?|Tai_?>;?CzJ@ ?3\b?Ϛ?Ğ㳋?`Bl"??͈?,K?+-)?[0U L?rA)bn?,b)?}z?r%LG?d׃;?V\^L?; *d?A9 Q?I.@УQ?RZx?\- :?ey{.?pCR,?wUm!`h?CT?Օ?&oH?_ϒ?G);?dJa?izpy?3P??[\?[sF? {b!?Y6 4?N?Ȍs?r/k?b-&?x(?k)?]=Yv?Pg[ ?D=?A T?@x6X?Di*M?N ?W,j?az?lP;/?v ?栱?CH%c?zg= "?H.?1^-? ?g|9?yo0(-?\òƑ?ި|??/D2s?H^`>?H Ų!?d␀U?Eos?[0?秺?7kl?zꗇ?w?G}?BT?ܥ ?Z֥,?[(?YYXM?*ɣE?v?W# ?sD?dFi&?VKVȆ?KolmI?EAc?E-j\?K8d?U/!E?`?jX?u??>V'4}?pA7?1~?F?3{? ?t!"?fϱՁ? SGQ?WvN?p??K7J'?܃v?HP*w?ӯF?5u?SU?BH?tr9?eaP-?WL7,?Mp?F\?G!,{s?OL\)?Xu`?cU\;H?oUS?yJ?C}?*?7u?J M?n?m?.\|?>2I?}Α?Rx??\,?!jN|?$7~?B=?rEq?g?D?SD[?.%'?tPYWa?e5nѭ?XcG/?Nu-?Gp?Iq?Q@?[Ȫ?f 6?rDK?}م?m M?Fe m?Is?Io]?tp?=m?P>? ??z|? G?\M(?WP ?’xl?MKs9?L?s.l? w[`??5?re\[?d$/*?q ?Dm0of?۾?Or?L#2?Rn?] S=?[?{N?<u?x?Q{SS?>C?uO+?)y?({?Gb%?l ?}ڽ^ ?rd[?fl5*?[tv?QÈM?I"?FR?Nujd?X1X?e"J?tO3*?V?RȒ"?<?p:0m ?i:s3?BaH_??܂>-\?]|6?4?Ѧs?|"??I?F;?V|'?v*?D?+7?C<?y:*@Y?oVɯ?cUs\7?Xv ?O%bK?G"++?Ed?MJ+'C?W„atr?eQf;pw?tx?ټ1w?k7t?S?z*_?H ?q?Kk? }(? xV?Xmm|? '}H[]?!?u? [?5] ?%OK?2vģ^?uZU?>w?uһS?j`?`1On?U0?Kw?E-ٍ?D$?edg?I;R%2Y?FDD ?|T;?q^?f7&&?[4y#?R(vڞ1?Hm鬠?C,?Av~'i?Hd~zc?Sy ?b,{?J?z?2?Ib ?{4]?C?v -$?lPlCd?a<&?W-+*J?NO#?Dk]~e?@M?>`?DǒPJ?PgT]D?]ϨU?ky?xAH?a?q6?>M?AKzJ"?X&?5Q{?f9?3)?)? ?)8 ij?e! RE?GWw?p85?= i?r&q?C@?wa?pCO?ezIcZ?\-yLh?RƸ!D?I.P?A:3|P?a^6?;?͑?bfI?D;bp??1d/?|U8 ?v EY?pCL`?fvUPK?_`݂?Uʚ?MXmcu?CWgp?;A)1?5\?3_Yo?;1rg?D$?P =ph?\ M|?h}H?sxՊ?}6h ?aЇӝ?3PU?tY?AE4Z?Sz`? 7M?%[QM?)es?KS|?}i:iA7?yp9 ?u3^?qtf?lPj,?ezL~I?_ZxV?Vg?O4?ED?=S ?4Uv!v#T?0/ʆ?-{c?4F?>~H?Fn`Lz}?R@ee?^r{ ?h}JX?r$ʟE?xAZ+?~ߞ?f3?ڒ9`?_А??&"y?~9v ?ySI?u1D _?r㡈?oW>s?jȹP?f7?Pڸ&?a?\-fd?Uud?O9lI?FIdyo??y@{ ?5duhp?-}̔?) a t?$0?-q(V?6DFy?@0<[?Gc?R@Hr?\ n?d3ǎ/?kc?q1)/?sm?tɍص?tPE',?rw:&?pq ?lƀFV?i#;~?f:B\?cV" M?`BJ?[ ?W- +k?RƎ[?MXbb?Es.f??yƓ?5sMY?.yr?&RM?"Eh1?q1R8?#J?.[fë{?6 O8O(?@0?FȈE?P5E[?V\o3?]uC9?b-.1~?d ?eUJ?eB%@?d?[{ ?Xv-ʼ?U0s V?R(Q-?N$*\N?I.p`?C.H?=L?5d7Ʊ?.6p?&&7aZW? fޅ9?2Tl?(rb}?~vbJ?DFM?J =w0-?Pgf?S" ?VL(?WÂ2?X ?WaP'?V`Rs?B?DyQV?F=b?GHӤ ?G\~'?Gff?G֥x?GDu:?G1Ct?GHy>?F=k+̄?Dxw?BEDI?>^[.?8bkV?36?,Ԏ-?$w?g+ ?Qʸ?_}hp?^Ѵ ??PVB?u㍐?$R?,׸?3U\?9 9K??[Nb?B͎E?E?GP*(?Ia?J{r?K۴e?L^N?MP)9?MU>?M/WF2?LI?Ijq3?F0?CO{ы??|gm?9|?3ڰ%?+4^?"?9K?⠿*e?f%j?OPGSR?U#5 ?#Vg\?+n0]?3 0W~?9["u?@?E_?IcQ?Y?MDc?PYԂ)j?Q\k?SwĹ9G?T[?UHqs/?V2U?V<ޞ?V:6c?UK $?S`?Q_0Y23?Lugy?G+s?B y{]?;kEr_^?3j$?+!z5x?"Cd?9?gC?sx?#ը'6?+??3^ߚ?;Yf-?Bo$?HHF?Oib?S{H?MA%? D?%~^?K/Rd7?1rV?R]?vui? W?w$1^?o5`\!?cI¯Щ?V۵rw?K:t?B mp?9'l?8(k?9 P?@{ ?HqNY?S!D?]re?gֵ4?q_\ ?xzF?8aDv?{G?A?NK[??r,讵?{Pg?L4?a"W^??Ys?E# 4 ?O|y=?XEp@?cb2ٴ?or/af?xJVD? [?k[R?yFj)?2Xl?pX8?d"sSB?C?uKG?1I>?blY?:ȇ?]yg?R/?B5}?aN?Z?ã2?sZ z?f^:?XTѪ?L\]?CNͮI?B{?B5?Ibe?S<ЯԚ?^fͯ?iRC%s?tr?\?k:?R?^5?Dҡ? _G?yULB?C2?kj?ğV?}d"?!CӤ?՟C}?;$t0?V>~*?B?{{7??Rp b?06`z?R;|?|mp k?o;?a)\l?S* ?I@'A,?F= AU-?Gk?PY\~J?YQ˜?dO?qe>?~3Xy(?Aez?288?n?Ma?l-g?hx1?B>h?%?sE?B"?WV m?,?.x?B, ?Jr?]c??S36?~jx'e?pV3?bfwT?UK/?L?GHF?I`V?Q P?\!΀?g}?s|?ati?9 {?pub?r?=?h8Ʉ!?彧{N?}7?n?`O?@_ C4X??˩?}3?60 ?!xb?OL?c?Jε?m ?q-P,?bĎ/?V$2??M/ z]?GI?JF1%?Sw*X?^I4?i8X?u0:S5???ca.ڲ?xᅣ5W?7 ? gQ?}?{VaL?:^W?7&?gE?zZ ?ʽ"e?WHr??ގV??`^?%!UC?~»hPF?pli &?b|.?V<Пg/?Mt9m?G­?K?T:aw,?`hK4?jR#?vEs?=I(?pg:%?Åh7~?C#LD?XR?H:q?KI?:ǚ?ŅO?a?B ?q?@F?jv?Պym=?t^i?F? 4J?4{?{&W9?oC;CIu?ab?V}?MOu?G6Y?L*?UvW ?aA=?lu,;*?x9p?LWW?zWy?s'?jT?>,n?P?ajA%/?7H??p3D??y0?8 C?j'?1??~@o?kiY?u.(n?{5iR?Mp;9?xz?lޮgY?aAG ^?UGÉ?L!Z.?Gi?MOY$?V~I?a\?ox_?{1?xE8?1#?| R?ß?Ԯ8]?W^X?@.ѝ̏?Ca?B!f(?Gi?**K?;ȡ?$8c?Vڬ?Yz;?C)??!?r1@?>`^?vq?jP}¾?`i_t?TؒF?Kq?G)Q"?Mk?V<n ?b?p|s?~?#H>N?_/]?/?ݨ&;?xB?W| ?(to?zX?+B^?9 oS2i?`5?CO~ƕf?LC#?X"Tei?fmW?sY|X?轥?FѕT?_?AJc?QIM?]Un2-?/2?@pq?r` w?ulWD?NӇ@?dqP?q?2jv?au?l9^] ? /?x:g?o?c?Xȇ|?OT*?Em%0(??[M?8?W??. ?G,5(S?RmF?`c?ln:R?w"wڭ*?우?ym$?q~?%-,N? +?Mϑ;??݉1?h?==?~4fI?y9Yv?t?o?g>_s(?_ʪ?UPҏ0Ij?LUL?B7Ǵ?9& ?3U>U˾?,Xv!?3|?;m'|?D=?N?Xxv(?cIN?ln0R?sZJg?xXW?|lGYz?~sH?lcRl?~Ɉ?{eQ D?x3}?v>FW?u1i߼?s (?qʝ`?nh?iR?c?]˜?UPƪ6?MRv?D\Sj?;ykP?3^И?,ۀ?$/X?+7?3C?<ܡ e\?Dۨ,:?NK?V۸)?`d6ͧO?f8:?b? ?a[Q?aB [J?`iԁ?^[OW?\y?YR?Vci#$?S?+${.nk?3Kf]6?;mx %?B ZJ?G,B ?Lk?Q_Ӑok?SY?UKA?VyK?V=+?VGU<?UX?T+?SwRe?Q+ +?PY4?MD*aN?Ic(?Ek/M?@Jh?9xP?3 H?+nuvS?#^BC?V>?Qh?`'H ?G?<?"D?+7!3?3U+?9I8 ??DH?CO鉓V?FӿdCQ?I!+?Ll?M/?M%'?MPO?Lo?KM?Jy+qQ?Iat?Gsg?E~7?B_̬??ZD?9 L?3T ?,֏9?$N?tnoI(?P LQ?C? ?:?1y)?Y +?$&%N\?,h$_?3"G?8,#t?>ZN$+?B4 N ?DfWOG?Faq?Gbwk?G ?G'?GR?GW?Gnb?Gb (?Fa,@?D >?B6Z ?>Y&T[?8j?3!M?,ž_?$׷?WeL?0.rC?ᴉ??9c|?Ft? ʜj?'B?01?6=%ؽ?_?LP?LFº?KnHF?J@??G>ag?D 3c?A&eo]??NԸf_?G2/4,?A2)#?8nl?1 &n?'An*? \5?$Eij?'G4f?0?8X8?Aq/?IRhs?Rt?YK`?`3y?d NX?h[q7?j_$H?l("{ ?l?l%}?lǙ?li ?l I?l) ?j&@ݏ?hS?dhT ?`{쾰?YY?R6nSV?ITi;?A:T?8`$?0Q?'?,?0!˕?7oT5?Ab4_?IQbq(]?S+mY3?\Q:C4?d 3CD?lQk8?qi>?u\;{?w2o_?y'_o?yS.l?xs?xh;?x64?yT2?y(c?w۔13?u]I6?q6 -?lT,?d @?\.G?S-o?IT%?A# Γ?7qK:?01?3! L?6;geM??1 ?G0?R@v?\/'?f Z,0?p a,.?wR=?~4-EJ?>98?n?4G}?ɔ,?MyIC??MN)m?I5h?/ixA?p?@cM?~6_=?wTQ?p·g?f$3B?\%?R+8dsa?G2uOk??f~?6=3Q?8,8Q?Xq ?A,?HauE?SEHe?`z?lQX?wRk@)?O+?6E$m?{?8O^?'00?`;?G?u*DzI?S(?u !?(W?{̀}?(t?}??8#gx?3?wTj%Ei?lS"?`h ?S7z+?Hrqg?AΜI?B;vu X?Da2?MNK?XBZJ?dw?q-?~3k?ź]?hX?/H(?qCu!?Z;?a?[l;h?kW?[v?kI?\x9?m?0Y?;?0?ѳy?# ?~6-9$?qŧ+H?dC?XFL?MH?D(,?DYܠ?Gժ]k?QBq?[?hԅ?u[U-?>?=)?>ߓz]???rr?D]4?#l)?Pk~?[h?>!?v@??J1??E:?$x^?D?5&?Vi/?@壓o??p?u];'?h1?[?Q2ed]?Gڹ?F`5?JD?R|r?^o2?j q?wuM?qwV?}-?&.U?g?#@a?e?t?E ۖ'? ;^tu?i ?e8Yt? E? -7b?FuE??$bQ"c'?a*?(3H `?"T?/?wVe%?j?^qE?R?J?GaQD7Ob?KmD?SdGI*?`-'?l't?y&jC}?oRL?Ö?)'?D:?[?Ern!?ܢ'?m؟??w ? $?бe?Oi?FmJ?!F6F?|?+i?:!3_?V?y(E^X?l)?`/ j?S" V?Kn.x?G?LE?TcT?`؊ J>?lģI ?yR?ȜU҅?í5?Ngd#?[L(?W?f?ωڕ?[P &?7o?ӕ?8F%?!9ف?иI? l?C:t?\MŐ?,?9m?8?ySj?lƫTG89?`ٱ?T??LF'\E?G~&e?Li\†?Ukft?aA'?la, R?x/~4?LTa?zVx>?s\z?jf)?>pb?ǸcCA?)+?7Qg)k?Ao?p3+{"}?}:?8m{&?/b~?F<\??I?kw?ua;?{Yl-H?Mg?xX?l*?aBx?Uw?LIo?GYsh??Lœ?U;?adM?lⶳ-?xA;˲?YQ!?L?Qw?Z?Ф]?KzN?vJe?iZߪ?p27)?h@_?p3w8?=?wmD!?0?^P? c?[on%?Rv|?Mv?aF?xR\8?l_p|?ae֮G?U R?Lނ>P?G'x?L9?>8?ȧ^?î?H?[_m+?΅O? 8BN?/?$?8 2?zGw1?8ݺ ?|m?? Ǥr?.?\F"?_,Ĭ?x^:c?ɉH#?yS P ?l?`.i&SX?T ?LEɚע?Ga̕?Km,?S;?`.2?l(f.?y&?~2?*?Kc?0H?)?Fk?xb-?н?w$?wtPc?Ok?J#?ʙL?FDA?8;9??wؼ?eA?38n?y'?I?l(vG*?`.Mș?S &x?KmCf?F`!?J2?R`?^p12. ?jKȲ?wٿLM-?/H* ?i?&M\;?My?#nt?ΗR;?FDu? 9}3?i3f?g?ɡݮ? ?F?\^X?$SG?f¢?'?).?yw?wM?j_䐄?^oh?R5ұ?JT _?D8JE?GL?Qi?[Ɨ?hpZҗ?u\?>LY?> ?4k?Bo?u\ )|?h,Ei?[O(?Q`B?Gyo?BF]m?D*B?M]?Xl F?dPA,v?q2?~4!d7?4n?mV?/ٓK? ? W?fV ?\T#?k=6?\.řm?k䁌O ?\%l?aa2?P?b8?0&Fj3?˖?0EJM?~4-*?qn\#F?da8 ?Xق?MP0/?D|ګ?>Z)ω?AW?Hx ^?S輦?`?lRs6?wR?+.?6pf?W#?]K?'r|=?%@?([?u/-k}?SR)y?uiO:?.?s>?'/??% i?6F?v`?wRT6M?lQ+-?`'4?SêN?HUjcA1?A?8@?^^?? E?G3Ka?R&.?\t?f>;W?p͵'?wSIO?~4ֿQ#??@>T? t?Xu??M,?#j?MLV??Փ?oO?2yX??]?~4O<?wRu1{?p>?f k?\hpF?R^D?G0ЧJt??B&R?6=L?,QgY?0{,?7s΀v?Ahl m?IU56?S-eAx ?\ܔ'c?dZ?lSz?q)=:?u\⢺~j?wئl7?y'{?yS/u?xFr?xՐ *?x謩"L?ySVv ?y' ?wJP?u\Du ?qH?lQCv?dBe+?\a?1{!?S+eE)?IRo;e?AY?7qX$ N3?0w^X?$8v?RBR,F6?YKP.?`"f?d6k+?hpH_?jbԪ?l)O~K?lƹ1S?l^Ty?lǭ1?l ޼8?lj?l( ?ji1?hNM?d o?`(?Y7Ȟb?Rui?IRN?Aͥ?8 ?0Qa?'IXNP?Z$d ? ̷,N.?R+"c[?QW7?MO?H;/?C_^Ҵ??E?7pJ?0zwl?'@vF? :sQ":?G4?FE?;C]w?Hw7? U/X?'*{?0Q0?6>eC?`UZ ?B֬%?Dy>f'X?F>>{?GIX?G>v?GSZ?G׏u?GִOs?G ?GIb2?F=Μ.|?Dy,w?B=n7?>_91?8A/@?36Nq?,Ը@s?$S?g*?yac?^kWi?^@"?7h"4?9Uj]?"O?+4#l2?3ne?9s??xjD?CN??F<`W~?Iڝ?Lj U?M//Ex?M7!V?MQ3="?Ldu?K1?J?Ib-1?GPl?Eo?B899??\̕?9a!?3U?,h=?$#J?u^?Or?ୃ? ڄ??8kޗu?"<=i?+#2?3L[?;j)R6?B )M?G*u(?LX#g?Q_gA ?SO'dd?UK?V2E?V=?Vvy@)o?U xu?TR0?SxדOz?Qp1'?PZHt?MF?Ie5rg?EW$5?@AW?92?3)?+pu04?#)БBY?Vzo}?OC5?fx6?"ƣ?+`7?4(8?Br?O)'kD?H_J?BSշ9?;ş,?3˻i#?+K?#N+?tT?$(p k?+2Ӹj?3CoR??3}]ls?;i(doa?Dd|?Ng0?X ?cH1?lmӅq?sYΌ0?xXx2K?|lAjE?~x?loB]?~4?{Lq56?xM`?vDrZ?u2L%?s~JO?q˻ ?n?iU M?c⭦?]LB?US'B?Ml?D^ߠ?;qI?3`KT?,Y>?36h!?9B?B =?K?VّD]?cH%.?o C?w"H?R}?u>ӍA?QA -.2?$?JEϚ?$w?᭖#?Ms t??7@?݊5f?T_?~605?yx$5?tpb?o=?g?_5J-?USC ?LX)$/?B.Jڤ?9VEJ?3U`n?8γ??&!?G)mxz?Rʺ&m?`bpVX?lm5M?w"eH?0?r%?qe?z?Atl?cJDXK?`'Nc?m?{y3?s48E?\?߁B ?CtKv?g`\?+CT?x:8.?qa?g?]⸭?S#E]?H)j0?@"?9 J?>^4Y?CM;љ?LI?XvhKS?f.??u?k|K?e 3?rg~?3~:w~?̭q?m.z? H#g?x.*?o=?coL?Xt?`?Oų?Eդ??[>:έ?Bsn?F?Q^$/)?^紶?keds?xW˱?tH?qTpT;?AM ?l?,?T2?!ҕU?jb?ćh?k; ?D: d?y@?76w?о ?`*f׿?\:?mr1?Ok?tzHᡅ?iT_?^eɂM?S>t?IdŻxO?BͳO9I?DxaϘ?Ih2n?S,=h?a(o9?o?|km(C*?Pt?whq?P4?SV?eX?B&???՗ʉD??SD?Zq?8e ??uC?N˔'?.w?`q ?̅ 9f?D3?yx?n ?b,B?Ve?MFQ')?E0D{?F{?\tRX?KN?B?Hj?Sܥ?Wr? ?BE?f5?eEf?i27??NC/?ʨE?3[Na?COsL?~5H?qˏ ?_?d?YTdU?PZt:?Gn4n?GG?M-C?V )*?b5`*?q,?k bz!?vWN?j`?`iBb?TA./?K۴Pco?Gf?LV]Z?U]E?aA$-).?lyI?x@f?L`?za8S?t}1?jz ?><7g?"?s]?77?O.]@?p3Zw?JҸQ?9v??i\H??w?k'?ux!_?{Yf4?M+G'?xKr?lR]4?aA^?UZOW?L3<,?G&?K*?Tw9?`h29R?jN1xx?vb)?=uc?po~?נ?C:6 ?Xl;Q?*iE?;?;X`_?É;3J?GI ?Cn2Z?<?Ar>?$)?%:"?g?}`?/z?ܥRY?{@\?ovݔ?aZŃA?V ?MOG?GLk?J7K?Sw6h?^G+?io?u0l=?[`??cyϤe?x2H?7O h?bJ}]?~K:?$K?;m?8?5dA?{9?S{?XLǙW?r:Y?_?[?`Op?$Ŗ?~F?pS?bԬ4?V?.E?M??>_??\p P?Ea)?Oi?XQ澁?c⊐ߩ?o׀?xʌSh? 2O?lqr?ŭ?2 ?qfm?d;/?4?u\^`?B&?n?R:?]Ps?Q?A] ?`-+A?o l?{?sY 3?ftR?X(?Ll?CNjA?8Ɠc?925?@IQ?Hjk?S#|:?]ܿ?gY_uz?q`V8!x?xe?#¡?ZqS?BAA?ޥ"(?c@U?rB/a?M[?Βdi?$Y?JGw?u?Q9l?u/ZS?;y?w"jm"?o i?cH#v=?Vߛ^?K.?B ?9Юe?,B h?,ڜ#̻?3{*M?;2h?D_I?Mށ?URї*?]N?c?iTta?n# ?q.\?si4&\?u19E?v]}?xm ??{ ?~_%0i?lByn?~GTTU?|l \IJ?xXGy ?sYN9?lmH?cH#8?Xz?N`_?D׌?;j7?344o?$k8?$JB?+s R?3?HEC?:R?VeKX?YTM x?\ }-?^nNa?`ie?aB4ކ?a?bKVd?bw?bf4q?a(W1?^ێ?Xu0?R-HK'?K>ϖH?D\G??V ?UKJ?S~L?Q^ɰJ?L^>&?G* ?B Y`@w?;jVg?3 x;?+ }?"t#?:Ք?_?r?Qy?wʉb?$t>x?, //?3Vߎ=?99??]!a?BE?EG;^ ?GN?IcD5?Jh}?K 4Zk?Lu~?MPN ?M2?M/^о$?L ?I0?Fґ_?CNbY??#?9ԒI?37@?+3˿,?"W?9?ЙM?A Xz?qSޗ?2eD|S?nîr?$Pt?-/?3^͆?8˪~v?>`3?A&X(jv?D%?E5V ?Fh ?GnJ?G4v1?G({?G|A?G ?F-K9?EGT?D%d>?A)?>_5Y6?8Eא ?3^2%|?-4?$ڡ?m?8?q̛?pW?+U*?E!Ϯ?#{R?-ƙւ?4(?;0 ??AN>i?DQFT?Hdw?Kp7V?MԠw7?Nwyd?Nawc?MG?LGa`?JKAȲ?IN?G#9Ly?E/O4B?CM]?@?;2->?5I4+?0K=+w?) ?;=?"t)#?0]U?q`4Q?r0?Q)?l(?#E?.V\?6A ?>{t?DxE9?J r=J?Pf[?S?VKq?WÐQ&?X T?WaB5?V=Xڞ?T~?Sy+i?Qxyz?O2?Kz\?Hp Z h?D- ?A;av;?;Y?4VMq?-"r!A?& n8'? fP?"\G =?qnd?l<: W?#?.UW6?6FK?@.t?F-y?PA?V[#C?]eA?b,iA?do?e>GG?eWrZ֪?d0U?Nq '?I1?CW?ى#?=2?5fOp?.Q?&'Q\>? ,AG?/mk ?$ّl?-?D?6@_ΪX?@.us?G,sp?R??\ ?d[x?keT?q1j՞?sp~.?t7?tPM^rX?rĖA?p/p?l1Hp?i$?fJJ?cWz7mi?`"Y^\?[v{?W/hv?Rt?M[ؒZ?EC FW??}{~?5A?.|'/D?&0?"Rܢv?-{ m?4˿3?>yˉy?Ft1]?R>S?^pt~%?h|_$:?r$@N?x*/?~R?8E?ړΒ?hI&??0On?~6?yT=?u2+NW?rdπ?oXPbX?jbCZ?f9J}_?a[б?\0D&y?U*f?OC[?F??}\\-3?5fq ?-p ?) C?3].bE?;.Q k?DE%8?Pdab?\ Nq?h|+U?sCʇ?}_WI?aK{zK?3V n?L?K '?Sڤ? *\#?%XlT?COa?ݐF?}LjP?yܝs?uڒ̾["?qO?lSv9?e|Y\@?_.?V ?O+ ?E6?=Su?4V)B?0o?8޶?A"5 ?J 6ў?VZYǕ?d-#:?r$>Q?}3f? ?qbhOu?Z!`Q?* &|?%?>O>?Q?`?NH?H?=?D1iM?@ aN(?|WD!?v 8?pE7_?fk?_a?U*1'?M[z?C 7#]?;AGY.?5h3h?>^?D+-?Pf RQ?]0Mڿ?kE?xjf?a?qKO?U?ئb.9D?7Ht?XuZ?Fb}?LVp?E#?l ?^ ?eE?Hl3?g?U#?J?HuW(?'?C?X cG?\0?z37?lMp?ot?33aT/?JB?|p=?DV/?v Z?lSz0?a#O$?W/s?N?.?D ?@V?D#U?Km ?VJ]`t?dj,?sqNu?G?4k?)t?X~h?&;=?Ȅz?-?B@|?»^#?HQX?>)}(?8M?S?ÒL?ֆP?fd&>?J,k?v=f?|VGZf?q˃?f9퓚?[uv?R)~?Ho??Ca=9z|?E5Y?M2$?W^?ec?tD I??ą~+? T?/B/?H>&?su?K"?ܠ?vY˹?W? ׬c??uؿ?ȗB?5?ȹ?3ܹ????G*?u\#0?jʯ]?`jNsV?U1 ~?K?E.0?F)?Nt /-?XL\}?eCun?tO,֣?1?RTtu?0*?$B??Bbm ?}?!?]LWX?6BC1?#n-?"?K9?r?JИc?05T?\P \?rHFy?{ C{?=?(?Q\??iA'?uM?x/j?+9?GTH!?>K&?}-hU?rQA]?f`8A?[/?QH?IfЭ?G ?MnOG2?V;[h?bZPc?pjy?~ .9֢?#ƥm?_h]@??]%Z?Q7?W{v?).'?z5^0?8 ?9S@;?<0>?(P?y(>#?{?8?y f?d}v3?I?Hjq?u1h2k?iko?^v?Sx8!X?J?G7X?LEMO?T7ԓ?`ث!(?lkZ?yR) ?ȽM$%?˿I ?Q ?[?5т? Hp?Jުa?VOJ?8r?(?9P:?V?ѭY4_? 7-j?xMu?\E$?ura?ľ ?Ql?ySJ?lXN?`~Z(?Teڢ"?LEd:?G\ˡ?J8(r?Swu^?^X&|1?iqY ?u0iA=T?'\?堂l?cm/,d?yyh?7h"?}^ `\?~gԈ?2r?<3?9D?W?{Ԏ?A^?Xsg(? D`4?Ugr?#?`ʗ?$;Z?~\F?p%u?b)!m?Vgm?Q3v'?zFA?Oxv?{ rP?Cį?]?OD?/P)?ߍn? 3P?er?Ć?>g"T?ru?d;})"?W`\?N_;[?F ?G"L[?Ozte?Xv-WT?cU4Jo?oV=%?yD?C9҇e???!?! 2?e[?>β ? +2?dD!K?Jw?]#r>?H>v?CĂ?CE/ ?R?dyH?g?S\Z?eg$e?tOw?eu`_b?X>&?Nu3?EՃh+?E.L_?Km'=?U0'?`c7.?jV+?uطY?>Nv|?SE?1lN?ezo?4.c#? ?uVcУ?YG? >?Xg?NZ?u?Luڡu?؋?Hf[?`G?? IF?"Hp:?t^I/?eg8A?WpZ?M)n?D$Qh?Cb`?Hnf?R)723?[?f7EĂ?qv ?|Tg?ڣ?H'|?eB@?JZ?Sr?Z?8CSݏ?R?k9*!?3+,"?CM!?yQ?Dh?t[?Xδ?)b5? %Sr?rȘ?s0?d^?VK>?Kn! ?At#?@L>?D;?N4BKI?W.e ;8?aeT?lQC?v cK?Cq|e?z+g?H w?2N*8u?c?S f?yǠ?\p??F-?uɜ4?)Pp6?Hv5?ym?F,^?D?YpD ?3ZP?~#ن5?q0TД?b,$@?S?Hc2:?>_8x>?;x ]?A;|˲?G?w8N?t͑?X*@?H?أuܑ?qA?a?x听?kky ?]?Pf D?DVw?8 ?53?;Aq?C]f?M[M9Ɵ?U`g6?_|?f?pDBo?v ˗?|U:??D+?D)4?g0y?j֋D4?į:!3?`ΖIO?zo?[tK?5?)O;d?Z*?qG>0?g?}+?r#?d ?VZ=\?J Lغ ?A4hh?3_Fb?0 C?4W,lP?=W?EX>J?Oq<_?VE?_?e{KH]?lRA%ǒ4?qd|y?;Kyg?J ?X3w?~S;??x~26?r$Q?h|y;6?^prӈ?R?b?F;?>{(,?4͍?$=V?"Lql?&+@!?. W?5?~??~a5M?Ey/v?M[ ?RȠ6?W/I?$[?[ZZ?`Yi$?cWH! ?fߢ?iT!?lƥ㵩?pXh}?r6n'?tO{ oΰ?6AW\E"?.W.3?#b?ës?qͷ:\?tdiŃ?s!]?2~?"qE@?)8L?0j6?5+?;%,?@ Z?C`x$?E//wJ?G$O+?IM?JF?LGo|?MŻ?N``+?Nva=?Mx?KoV1/0?Hd[U?DƲ Yd?Acfj?;/t ?4̵>p@?-ƅj?#J?Ie?,\??KSk@vK?IJj?!y?$R_?-ڍ?3]hw?8^?>$-K?A PA?C?E-(>x?FD4np?FM9?GJ5~?Gcnq?GJY8?FcB?FC?E,s>?C;j?Ajx?>#s?8a?3\٤F?-"%?$Z.?< ,?bНk?K)Ŭ?J?W~I?ټ/?$K?//`-=?5ǁY?? Ƒw-?JCz3?T:Yl_?`>]Z"?gZv?p1 ?s-8a?v"?wOn?v:?tPIԋK?q.G?l*vnJ?g!3L?cW?`BGň?Zi?U)'w6?Q?LwK0?FYK?@ECS?6G?0s?'C@_?".>? H5?-b1c?5/"dW?@5*Q?H!??T ?a\?l͕`U{?uRy?|Ւչ?R1?հV?-uu?GIG?u@r?m.R?y( ?s)>?oY)f?i(t[?dK)?`?%C?ZL' P?TR?O猿,?GPh/?@BpI?6 $#?/xQf?'F?&]w2?3[ŷFj?!8?lZ";u?wcA5B?tW?uCf9!?a ?8X9u?Mj?(?Sl ?K;j?<^F ?p?yOӠ?tA"NG?pF' ?i! ?c٧v?]ߌ'K?VkQy"?P]?G+x1?@Ey?5t<?/Q?-Fjf?8yrH?An̰?L,n(?YU~7{?guE?uRuɭ?tWtX!RO?E h?Q\=E?`ݡb ?p1?|3[?t?a?޻L?|?LAU?$?3mջ?wJҁN-?n?{?Ig??r$z??Vn?YM?|#N?unη}?o/]?e ?]l  ?TnX?Lv"a?CI*?;/BN?8plF?A5m??I\E h?Uy5?dM?s?H]?ϼ?_"?L"v?/`{?1V̭/?5?jg?޿?!ϥ?,/V?Qv8/?G;b ?BQV:?FA\bA?Nht/?Yd{|?gHl4Q?v=Ҳ?v?D(?Ƭh3?F:*{?$G?%?d+B?!OT?ܰX?ˮ&?te ?f=?)?iߨ?~0?j7?^!?V^{?j?t@Cl?i3?`AlQ?TY2?KPx2?D]'$?F?Ntc3{?X[Ÿi?eޔ+?tO-=?l)@@?`.~?SgL?Kmٲ?GH S?Ia:B?QZJ??\b@Ǭ?g\.?s^}?Z?ݕ5l|?p- ;?*?=C_?iPPNu? ?Y:?A}?\٨?B7܎?;wu?D?u ??!?j^?cuaGE?JwZ<'?l{wA?q-&M?bZE?V W?M.(V.?F~?G" P\=?O_P?Xu?cU}w?oV+ ?yu?CJr3*D?-`f?B.?ARM1?Q??k|?>gM?C:h#?Ѱ??^),F?~(?͸A?Ch?7?vA?' &?SyOu?6!?tOCU?eҗe?X5iN?NuМ3?FB.Y?DR_ ?KOL$,A?T槥.?`@1@?i'/"?t?A#?h[t{?T,?Bgҹ??S5?h冣F?!,??dos?P?ǔÅ?p ?"o ?G(??ׇ?B?o?]b}?&Q?v-?gy_#?YeHA?N?E+XYc?B)?G:7K?Qv?Z镦?d A?pD}T?x a?Xd/d??O<)#?EyT?Z?J#{?ig:?FK?P??DO?E ? ]^P?7#?w:Ρ?6]R?ۗ+S?~,D?w:<(?hsxB5?YXQV?N7и,6?C B?@|d]?C-E?L읜#xu?U{?`3no?i?s zʻ?|ӘI? \ ?􆂱?{<vo?36\?qHG?8?giӍ?喏;-?CZ\S? v6? q?p+p?1fb^?3p?'j"Q?[h#?"V?vH9t?gq֥/?X3-ML?LQXu?AЙ?=Aι?@dT`?Gr}?Qҝo?ZJJO:?cU=?m4_?u6x?~$?  ?[ ?J?6? 9 ?R?!06+?//?iF??1i#?-?L <??cx\?ιa]?s4?d9?Uz*ξ ?I]\O#Ě?8qڪtcu?;0|V^?CIM?Lv?m @?sasK?x-ҿ?iŬ1?D@alU2?dP? ̚{?c8"S?!K4?I? ?'w5j?Fn?C?t~-?t(E?uRS{4?gr?YUF1?L.鈴G?Aو`?3]Ჽ?-KA?/7 \?5?@E.?E?Gu?PqWR?Vjv ?]7+Zc%?c\P?i-?pEqd?t@T4?y ?tsb??JyQO:^?Sѷ?*6C?/E?^?l?tC8?t_8?wb\*%?l/O?`>&$?Qc ?Eq?+CJ ?T6m;H?JD?Amo5?76Dy?/0O?-?_E"?kpK?hMm?"/}eF?'E?KR1/8?OC?Q:o ?Snxye?V?X -!?Yf'j#K?Y2d?X4=t?UzxP?Q}{-?L.O?El?@6n[?7ד~?0+X A?$1?NJȧ?Km?^3k? b?&_ 1 ?-8?3h 0L?8r36?=CLc?@o?B)=^?Dma?G$|En.?Ic?Kp '?M0w?Nw`?N&ZE?N8lz?LR[?I]Ó)?Er#?A_9?*?{Tgxr?0?/X?f?N]M뻣?$}rC+?/: ?5V ?<|mt?A3$O?E[F\?IpXP?L4kFN?Mӻbk?N:l?MqoHt?L?J| ?G n!?E0tz?Bu?@?= 3 E?9(g?5!(?1[ >?*C{ݏ?$^KO?ۀ?7<;W?נSp?d,T?z(J?M7?$oQG0?0t:og?8$%?@h͵q?F?M^(?{D?F}?%ﺧ?>2|?h?$|-a?0s:F?8xw?Brqn?I\%D?Rs?Z_/?aDo\?e! ?hc ?iħ?huܞ+O?e=D?bgrr?^s7ȿ?YUq Y?U3NVi?Qw>?Ly PR?FQt+)?Ah%n?<:&Q?5?/)?'A*Y?"+.?dGWk?E"?5?$$O?/9CH?8#>%)?Bhn2?|Pp? }?|?u3?n !?d~p?\?Sg?JR ?A֊?:mކ?9ʞn?B8?L1TA{1?X՘$y?Lc/?E}?Xti?Ac?6(ccj?߳BO?%?ƿ5?@?{7P?rF13?h%Ej?`e ?UY?L Cc?C % a?@O02k?E*֊?iՃH|? ]\?Ip ?6yaJ??Xֻod??v/?B?S?]ȣ5??,?~>)?p8]J?bfd-aD?UK?LOKQ'?E2^?E-_?Kdm?U0z3l?`$*`?jȖf?uض`?>#V? lv?2%q:?;vL?4 ?Sfo?u3?5/_? 7%3?X?P=G?ؙ?Lu? h?H덞?1?J?B7h6u?eCW?tb1 ?eƭ(e=?Wžܷٮ?Mc?E+,lo?B V?G:~]Y ?Qu0<#?ZOUN3?ds?pDk?x7?XscA6?^,?kLIo?oD?Lf?qDT?j! aw?FXr?:px?U3?bO9?E;ӗ4?$ۘ?X?wPU?ᇠ?r ?X6?wbe?hs\?Yx?N7S=?D945?@R0?C R"?B略?Ȍ1?W{S$?FW??-? ?wG>?hGյ?X=|t?L2$i"?A[_?9 }?:K,7?A=\x?JA?S/Va?\:z?dj?nOy}/?u)?| ?Ɉ?ҝ!]?2Kp?RPE?R0?iG?H>?K~?o$??W(?K|? ?\?8vX?Z;?uO4c?e?V(d(?Innb?=[O1?5ā1ຌ?5.?<9Q?Dc"do?NaL?Ui?^^7r?e?wLIQ? j?Fz 3?U?CD,y?oG)?#G~7?֦x}?qZK]?an1D?Rw$?EZ ?8J#?1[x?0vY6/?5 ??M#?F0:;+?PD?V!3u?^^Z?djme?lJID?rˋ?x(I??v@?B֊^E?}?Џ?ߛqn?w?9x?) ݇?/NA?.i?~?B?v@P'jJ?i=*?6͈Z?? C]?D2/j:?Jô?P[$?U׸?Zx?`|yˈ?d ?jΞ/a?p7W?t]?wZ 1w?x{Z?ws?uPÉ?q[2-?ib9?an6v1?V }?K)?B?9?8$)Og?/<|~\??935H?IbjD?g;H?",B?'BCQ?/?5;}?<:Md(T?A_L+?FQ(?L (a@K?Qw д ?U2U'?YT] ?^rY(?bg Aх?e^6D,?htEHz?igN?hM?eIa_?aޚ?Z@?R܏ ?%L?$a4??*G!?#]}"T?-H?4}s`?;ub[?AE6?D{b/?Hd42Ц?JCZ?L59?LUE?Kry\v}Y?IU=?G-?E53?C:P?@GO:?=F`?:fG?7%3U?3nQV4?/ kj?( /?"O?Gs?++?Pn'?@Cz?| a?)?$dba>?/AZ^?7ǥ ?@.s?E:gu?L[M?Q4z&2?Uqѿ:?WP?Xؗb棭?X6Pba?VM$?S\xr?QǙ?MI#O)&?Hq{ͫ?C\#??ynѪ?9fQ3?4tj?0?*𢈒@?$b%.? :^>l?B|D?zG ?_F?\%?Uc<?#xGd^?/ǡ3?8zV?Ap2b\!?I ?R^d?Zc.?aP N?eh?g(?h5_?gs;G?d+C?a*z(?[?Vg ܗ?R++`?Lo6?FR*3Yu?A&?:Nd?4R?/Un= ?'r@?!ﷅP?`{#?/?yTdZ?)1X?"K?-Y?7K!?A%d?KF-hu?UNv ?a.8$s?iU.qJ?q urw^?tt]?w[p+?wP?vZ(?sHRy?orP?h.Jd?b-H?[A]_?U˅ ?P\?Io{?CFD?=Dj?5ڌq?/ӵ?&Ԛ?!N?Lҝ?A?LS?*?4~?@._?IeB-_?UW?b?n-?v]lMs?~mM? /~? z ?嘿?gQ?h?|n/qaP?u^'ԯ?n2b6?f9!2?`WiB?Yt"?S"0N?Lh^LZ?E9L??|u?/*?'q7WRx?$-?(y?6 -q?AD4?LXY#?Zb[?iT\]?v󆅉?Jݾ?RW ?M\?Kΐԡ?P.K6?s?(L#8?+W?/?Av2??|W̔?si?lKm?dvn?]ܲb=?UiG?On?FY5C??{p^jU?5ٿ?/S6%?*6N8X?/ q?; d$?DDC?Q&TX?aAp ?qƟ?~Y?\?^\a?s?Jd{y??G.?4=n?Y:m?S£@?CF?!?I?|y(B?twH??mFpi?ewe ?^RA?UiRg?NI%%?E9b^8A?=B3?4}D?0$m?3l1?@/9?Ha+?Uo:?eg5f?tÕ=U? @u4|?Eb?K(?JS?Pĵ?âj>K?ڡ=11r?1J?|E?JS0?r ?`3'?K? co?|-?th+?nbJ˂?ewFWr?]W؏6h?TRA9?Lg$r S?CE?P:Z۰?|{?tw0[cC?lK4O?c x D?Ys ?Vdޯ?MEVJW?E4?D@?Gյ{?Q" ?[`LI?h]Ӗ?u\ ?>Q??@ ?3Z?3Q?32`?$lڍH?ʒcZ?c?@^?A5?@[?G)?7E?%„?`?6E/~?Mxh?@u䭤??$'?u\R+Y?h js?[;l߸?QB8?GH+ؖ?DxZ-?EA#?MD[_?Vc/I>?b+%ؼ?n1ZYu?yp?ZA? #>k?_Ov"?w!?Nl):?u?8`x?Z٩?@s.?3"?&s?YB?C$鰣???Rprd?pYR?Q,?|lBSi?o7Br?a(?Sp?IٚwDr?D$X.,(?CoC?Hmɳ?R(}y?[Œ?f7; ?qe k?|T?0 8?I GjU?e}?*6@e?X63n?}Z?8m+?㡾3?X?å ?C!6?=b?6?/H?Y-w?*Vd?c?,˚?s@;JР?d(i?VK/@5?Kn0?C%N?@ꗢWs?Ce7?Lų?UZf?`!?i?sZI ?||7? Ϣ%?= ?ٮ?Kn ?vG?^*s?64?߿?C? ?"m?'?pɰ- ?1&?3Zk?' ?.?`іY?vZ˸?grIa"?X39N?LQF?BC?=k??u5'հ?FOB*?PQ?Yqu.?c  ?lI?tu*?|RSf?Opݦ2?hƮ?~/?c|io?N#?$n?BTA"?!ɍ1?7?CzL?Ȍ3v?lF?F?8pyi?1%?I%K?wg?haG+?XEE[?L2 ?A̵*?:d1V?9cF?A˘r~?I#b?S 0C!?\>ཨC?d7q?mڪ *;?t3L?|?O?ޚc`?e~}d?SHj?LX?յP?Vi?pgpD?ȌQ=?ga"?âԋè?k?O ?G3Z5?1?wZ(jNC?gOO/?W?J₴ ?@_ma?7#?4Լ}W?:L=U)?CE)p?LeoX:p?T Bw?]'PZ ?eue?n`_?tj`@g?|_kd? 5?ITu?_L ]? CH?_r?w!?1;!?hg-?âBus?G?I+q?KI6?? j@h?tܼg3"?egZ@p?UpV\?HbJa?;薵V?3mx!?0v|]?4~*4+~?=BBo?E8u?NGtp^?Uh\?^P&?eu?mQE ?tv>b ?|LT^?nxu ?eS? /?R5j?YQ>?308?F?o3?JkDž? wP?9 z??~G yy?qP?ax%W l?QK`|7?Df`?6B?/ }|?*r̸?/UBP?5Ȱ`??zT3?FXGېd?Ov`?UhR?]0 ?dgn4?lJ5NO?saI?|V"1kV?^}?@`^?.vx?*MV~?'?Au8?OKr ?KS$_>?@iQ?5E?4F?vj?iTUv{?Zcϛ?]?LZ 7nn?AEL?%?1x^yA?( ~ά?$,o?'rq%?/ڻ?6hm׀?@$_?FXfm?NH%K?T<1 ?\?w m?c e?i:pm?qdo:+?y;{??U?QEr?x*^5?=m?SC?!]Kp?&-"ܩ?/˰U?5ڀ4?=CAF.?CFzbU?I9A?P#7a?UZqv?[T"c?b,6!?h8U ?o?s?vz\B?w̪?wZ?t 8h?q3;?iTg?a-Z?UD Ԗ?KFBϮ?AAR?7r?- ?Xu[?,t ?{ q?=~ ?6?!WQ?'s)=9?/VP;wz?4aI?:Nl|pm?IwaH?KqcL.4?LTʝ?L4•2y?J :?HcU4?D`t?AE?;uG+P?40:@?-ߜN0?#'A]X?+yrt?'t?#? ;?4NĨ?/Ή!?'}/N? n?k]*[3? ?^gN?:'[?3?Hn|ZP?!oL?+1ƿ?3+o?9-G???۠?C.Qע?F5*?Hdv?Iqۡ?I`Ȥ9?Hg?F5?D[KM?Jhx?PYa+7h?S_?Ur`}*?V*v?U||?SrŪ?QaM}*?MT9?Ig d?D +?@Km(?:!A#eA?4 ?1!mT!?+.: H?&)27M?!VY9Uz?suO ?(8gxW ?RJ?WU[ҶV?_'g՗?c1W?eiǢ} ?ewgO?dNza?b.Fe?^ ǥZ?Xr=g?S?W?Nڡ{?GT?A. yHy?:O*㎠?3o?/y?(7yp?" !A?Z#>)/?c=u? ?R1%#P?W&]? l?+/J10?5&9?@2g?IqV?G y4?S^8?` +4?ksa`/?tLGzA?{k;J#?; [? 'ݜ?\AGB 6?+W-?~ʢ{>?xZ ?qw#P?iU=$?ao~ؔ1?ZM)?S.?Lh?DR#o?=?5}?/(kXT?&[3fk?!@OX?X_+s?qXg=?u M?/R0?9+'K)c?D??Q+Tu?_ ' ?ksRIE0?vST?i?U2 NE?SOM?\=?VwV?H(j?5>i?vd?~7r?t#Ww?lTg3?cV卣?\u%?T N?MPHh?E8?>+?5Wƒy?/(ݤ?' o!?"Q?!TI??$9Қ?4L8",??\?J ?W/y?fŅ6?tK4?C]f?p3u?O'?s!5??Ls?ol9#??[EqB?ru.??oC1?v 7?m/?dVX?]=0?U }m?ME?EUK?>6?52{u'#?/L"x}?U 0tkz?MPd?DQ`C?;?3 *?1 s6?4E?@Ov?Ha?Uo3|?eg ?tO%"? On;,Z?*-f?K4S?Jm)~ٮ?}"_?ãse?]e>?2#I? 2?}?ڟrϮ?`\y?K@_E? G?|;I?tJ?nb4)O?ew)=?]?TU0'?Lg&Op?CEf?:L3?4zTU?7"Bx?A?Im*>0D?k@v?3y46?J־k?|t?D?v ƒxh?lRQ?a(2?W.` ?N?Dӿ%?@?BB?Fѝ ?Q^.?^V?kf5p?xXQU?uO+1?qcѧ?BM ?=7G?zr? ^i?"B$?ߞD1?Ť%?lֺ?D !?zk?V ?Ihz?`c*D?X?m1?ƛ?tv&?iT1wyO?^_?S=]A?Ic?B}?BC?D`?M{h?X(L?dK@?q+5?~4p.;?l:?U X?0fr?MWp??E?\=F?lpp?\AD1?ls ?]@b t?l?"А[;?t磤?1Yl?wZ?'3T?~5wQ#?q:?^Gq?iRP?t]m? l?l-?F )?_D&|?ʅ~ ?YY?z;5 ?Dmf?lrb2g?Ŧ&?#9v?"o ? u(?@h?X֪?Bk?r ?u?xX2n s?kgx?^s3?Q^U?FJ?A߬*/X?@|D?D!?NSmg?W-\d?a ~?lQ- ?v j|?C?{WT?IB$V?2L?,!?CDi?z@2kF?]?߭\?‹kŗ??I4 ?2 ?GN'^2?=?Zw05?3^/?~R!?q1]Q?b,h l?Sڤ?Hc<?Azy?=?":X?@KkB?GLڛ?Q?ZIrW ?c#?m}?u7B?~$C[? Z?–)T?y9;?: 4?R>?(Ǫ?"]zxP?y?a9T?F֟?1'b?}1a?Lr{ ?a?1\?G?s?,?dBz?Uz5Fv?I]{>|?AW?9蔲m?:6?AaT%?Jm?S#:?\:?dݱtE^?n!*?ځ7۠?âL? x*?Jo?K_St?~? &e?tҩ?egh"e?UpS2?Hb$Ix?="#?4FU?1 e?3c_bb?;*?DPcM?MN6H?U ]qB?^=0SR?eI?n`R+ޯ?up?~%?{?+YMc?0w?Z_b?G,<ĝxG ?ET.?~?MYQ?U G&?] .?dީu?mb?v _?҃??r ?Z{ղb? Ev?T?Kl" ?r*?O _&?ܻk?i?tK::?fŃ4?W^s?JNc??u ?/mb?$O+2?!VC /?"Ah?' f?/( =?5؛?>_?E{?MOi9j?Tl4N?\% $?c@u?lRy ?toi?~5 ?uV?4,QY?q?׿t_?ʙv?,^Y?ɐe?Y{?vR24?ks%+?_ J#L3?QH?DGba?9-qwp"?'}N" ?y53ŝ?t7l?[C3?!A?&[ \~?/(@?5fN?=Њ?DR'B:?LgAB{?SI?ZKdKG?aE?iTvu?qH8>?xYgd?~l<`O?hg?[xf? k+~?e@?{jWF?tK%?ks ?`#,?STGֆ?GߤW?>@[?3+^? nv{I?ZĻŕ?)l?d\Ń?>]ޤ?!Aր9?' h?/N5c?4l7Q?;k=?CFǡ?Jt?Q?v`?W/?^iI?de1 ?kh?q1d%?s?uPO\?tMgy?rMv^?n-H?f˨qP=?_ M?Sgr?I<?@>|z{?5Ӛ̋?+2TlD?ls<[?ɨX;?T='[??d&A?[fA ?"Lj?(8xz?/тT?3}' ?:NE?A׹e46?G=iϝ?NYc?S>sF۳?XH@}?^Jy2;?b-b>?d C?e ^L?eh+?c0M4Ϧ\?_/#?Wо/?QR+?GQQ'?@?6&?-ve 0?!ˀ7yI? ؔ0?ou J? z?TT]g ?)L?t|F?!VեM?&)h?+ޗc ?1)W?4 -).?:! ?@z?D~?If/\&0?Mشp?Q`))?S?U{˪d?V)Ϊ?UqyTv?S^ϙԨ?PX}u?JVV?DO^?>spe?5ӞmEq?-g~?"STG?I ?N=?k?/C?'?Z[uw?y.\?$@?+'?0I'D?4Ii#?7&qO?96 ?=E=8?@]c?B>7?D:)/?FlHh?HfR?I_?Ipv?Hc^ĭ?F5-?C-A^k??]`W?9-2v):?3+pL?+2.&P?!Ҝ>e?Id?5}? NI? @?'|?0v?U{l1cq?̨S\@?#~V?**ܨe??16Lz?5F%.?80RK?;:qJ?=_7w[?>'p"4?>d~.Rx?>dk<`?>^`n?>d-}?>c\?>'ߵ7?=^Z9?;tVM7?8%ö{?5Edo?16Q?*K+?#'+?[B?UBi ?1p1%2? [@? C? 19v/??sL5?'x:@?0]u%?5z#?;}lb?@X9?C.ĸ?Dӕ?E;nOx?E CG?D(?CQUI+?A??`ss?;L?8t#?5v?3okF&?0ҞO?,Z;<7?&qV3?!+Q&?Q?51? Am? bw 5? i{?/ .?pKE? δ?)؜?3#r?:j9q?AޣP?FXͪ?Ks?PYIT$?Qfn?Rz j3?Q؝K?Pi!j?Lwm?HqM(?E4Ŀ^?A=}o?;3?'Ndp?50uٔ?0ɿ[?+ܲz?&r/UL?"c(!?Ca ?tؐL|?x^m"? mb_? Z0~? aC?S3 ?HT{?)8?3,7^?=!t?D(#?M1?T ?Z''N?_-+?av?af?`S?]?XѮ?S \k?OO?I3?CK1?<;z#?4C?/_{_?(Hqm`?#7 ?p(?F?6y ?NH? la^? F?ɿSx?'w@12?3"@*n?=!X?ECw?PQ?Y S?b넷Y?i B]?n|?q ת?q\#?p2k)8?k)DM?f\?`?X̨&?R]?Lx?f=?p?vV-7?{kdΗa?~a-?K'/?|k,u?x,t?s[??lUV3E?c1?\2ی?Ts$X?N2P?E:dչ?=}?5PgJ4?/dd?&1p&o? WNn?){ ?‚q?rgkVV?>?*Ew?5$U?AYЊm?M0.a'?Yl?f1?r@V?{)`?E՘?ʨXw? ?%"?Uke?NJgq?E 8?=:?5( ?/n0:?&Ч'x?!ӀL?n [w?4*?!(ȑ ?D3v؃?>@?5iy?/c'??'u8?#Uuc?"`xg?&m~!]?5Bp?@!?K~?Z%V?i MR?vUm \?mwj?M$",?3?比Xo?\L?DT?߉d?=?a}g?8ڻΕ? [Vu?wv2*_?o0;=?e`&XF?^S6c?U40?M[2?D؎&xj?=6#L]?5OHX?/C]h>q?(F??&, ~?,V'7?8"q;?C+k?PWӣ+?_0F?njym?{j ^=? :a?O]K?AR?n=i?Jyjn?0t?MR[J?v۱?CHӱ?J?nq?ENJ!2?uc_?nA1?ewk?^?|l":?U"Ä?MwD!?E*aK?=.{V?4;m?/?#?+(a?0Q?;pU?DU?QV/?a@(m?q8?~Г(?;O6??>ʟy?J?a?G|?4x}?YO?Sm ?s ?̈́G?6?|d ?twA@?m&!zP?ew3o'?^Ri+c?UiZF?NH.?E8\-3?=Bm?4}F8j?0㨇Om?3k ڂ`?=XcL?E2?Rwc?avF?q[>?dy?$5*?a4I?DY1??Gg?<?wh?†|*G0?^ng?)6a?4 ??z3(@?Z:֠?{8ŝ?twX;7?nfC?eb?^_Qe?UjC(?NX Q?D[E?<7Y?5,i*8xc?5sX?> _%ǿ?EqKʼ?Qݳ(Q?`ݫ>B_?p12qJ?|Rd)?u\=d?M?#gU?L*+?4Z%Vx?w?֠?j{d?#"?nP ?r!?A%?W$?ZW?|0]?uNFV?o/^?e^x?]ޓnʽ?T͛ ?Luس?CHu?;. O?8o[?>]]Jv@?CMu1?L0vY?X?fQ&?sYtb4?5^?P~?`eY[?Bgn*?RuQ?^b?Rf8?Z1?9?v؉?pwȀ?e8gq?rE?3v ?n?maKS1? ڤ1t?x˭?o֞3;?c0!?Xܡ?Oj&U?Ey??YؘK?>W ?Ag|$?H`67lx?SuHz?` {1.?lQ,2k?wS CR?Nt?7;)I?>en?>F"?(xg ?8? ?v= 8?T[+7?v<?ښG.?'n?(}"?螠 D??7 x?UdhEi?wS2?lRo7-?` ?SNWߧ%?HV+Ni9?A~|?>]ή??Y[i(?E8?O#?XȜ.Q"w?c>?ou׶?xʹm? r/?mǓ?G]QO?3Q?rce?ef}u?Ef?v/&?k4?\0?E]%f?;ıwJ?A9L?I.?R hb?\-?ez>3?pD_?whz?D _?j?6r^/"?ջ*+?H%$?eb# ?t?J؝?Pۍ:?5?2#?Y.J?\?X Ó?qC-?bgy?x1N?kz?].K.!?Pfӛ?D;~?>!RŠ?8o?;-wӔ?CGJ0u?Lt%A_g?TM׏n?]ܝng?e?o-88?utr?|^?Y4Z?Uf? ?r#xh?_[?q~?&z[?S)?wn?4,~?LzU%B?p+?j]?uE^T?|nr@B?p1f}?`-u?QQ90?EM_/+?=Z &?59j?5,D?<6ǖɠ?D&?N{?Uh~?^]kԕ?e>|?R,m?Yk(7?4#?GϒK?KZq'b?J,{G?A#m? b\?ŐI ?~+t?q8`K?a>?Qօ?D T?81NW?0Um?+1_?/4?4̽`?=b^?Eʸr?M\?UI/?^=R$?eu񺾯?nt?uCJ?Du?mykts?hG?Bs\?>.*?L z .?Dםuc?Md<?UhVp ?^_? l?e"Q?pDz:VF?x˭F\$?aN_?o=G?qVd4?9v?CIP?,;?O2[ku?Mf?˦?{('K8?p6mT?b,R?T=@?FBᖔ?;nM_o?*BKij?!*Co?y)_|M?p)A?!w?&гH?/mi=p?5Ȉ*?=w "?EW?NH⊴?UjX =~?]9\?e|7KW?oG?wTu?9Q?beZ?u@{?$G$?$_}?E?e?{(2o?r@>_v?fcp.?Y:o?M14?AV?50@?#ca?: ?uv>?駒q?+`31? ӳ&i?&$J?/c"y$?5Oq(Q?= !6?E9ruI?Nz ?Tb?\0+D?cU*?lS݁?sZqw?xאh?| ??~'xD?{j'G?vUuF?p`B?fw?\ N?P ?D8?:tcNG?0AW?4\ ">?5/Q?(14?9U?RrP?+ r?!Խoі?'Ϣü?/E.L?4?=DK]L?DɓpqD?LwS_2?R*m?X_J?`.H'?fӨ;?k?p2 jCQ?q[O?q c9bv?nz@ZL?i 55?bX!?YLJD$?P(#?E`N'?="?3#?'yE?VA&I? ? oH5E?~?YO?18y?qҺ?#7?(?/0?4|?<;'?CJQ?I2,?O?SL?X}~7?]II?`h?aߝW?a^=?_dF?Z&/ g?TpLY?M1>-?D4?="۸U?32HK?)%L6?}?2'&? dw? \3s? odM`S?-&s?u{?Ԧ҆?"cg?&+ vR?+!g1?07>?50=k3?;2Jz?A<&?E w?H(Or?LyS ?PhYHǬ?Q?Ry>.G ?Q 5?PYIDޝ?KPaR?F!?AE)U?:ס ?3#M?) 6f? Fd?[V? #]O? _J0N? cr{? e-9;?5ʏ?ȐA?!+b ?&qQ*?,[Sv?0 ֣?3oޏ_E?5@?8t3?;yĽ??`/$?A^!?CQMa?DXE?E*^?EelN?Db|?C.V?@1.Y42?Um?ӹ=?%u/ Ô?+]sO?17tn:?4PyԵ_=?6)u@?8?8=?8@?8.1?8f?8Dn8?8lzQ?8KpD?8G$?6, D?4P'?17J F?+SZΉ?%uY1?Q8?+֯?2? ]j?{WR?JZ?? 'ҙ]?{|?~?#@zE#?+fԏ?22n- ?6)"?;DϧO???AG`h8?A;nj?AIb(?A?S??2t];$??/ڡ?+?&r YB?!uѽv?!: 3?:y??ڍI? 7?jp?[sB[? [|+]?{,5R?Ev)s?$ޑ?/z?60L?=G?B=?F[ @[?J,,?L]`ZcRC?M1?L2Ly?JBx?WhC?ZeX;X?Zׁ?YYdѡ?V^R?UB W-?`r%ެ?h6',`?p%R?tL|?vq,?vR'?uTK-L?r&)?lqP1-v?d/}?]úB3]?Uméw?O̕\ 7?F $??} ^F ?5Ag?/d\~?'2ކ?z? H?Nm<_?Z6fE?xƯ4v?ub?/:?%qV_9?20CJ?=E0d$G?G\bC??Sw??`.bd?kCW "?t]?{)ʸ?H?;^\? ke?v. BM?}Ͼ.?w%{Ӆ?p7r5?g?_I?Vl6 ?P0O3v?FY4K?>vQ |?5B8?/+k+)?&r]x? L?J?p$a?VA*?[a?+:F2?6:(?B:[T?O{a?\AF?h́?tv O?~8fߏ??N[?o3?qX?vEb!?F&?u>|?y`IQ?qb;ނ?fǖ#?_X8_}?V#1?O=?EUvF?>ʁ?5ݥk}?/#?'1_?"A[?5S?W?PS?!`A?14(҂?;*?F[&?Tbnm,?bN⍎?pkS?{)bk?yx?N@!+?Pߎ?7Ed?Q`?'?rY?۟?Jwԧ~?x5?pEz?ed?^`f?Ui A?Ml[?Dؓ\C?>FuP ?5 _?/b]s?'{?#ys3?"`?&mh~9L?4L3??ؚ ?J egc?Wg9?fŇ?tKP?]Dq?׼_F?O讙&?suyE\?L7rm?/?c!?[>Ώ?r;(?Rh/"?|W ?v ׾?msl?d.{k?]ܐI%1?U <]?Mv)?ETc?>շ?5x7?/KB?u z'?u?H2?.@?(FcZ??ػ'?Η5f?dɖ$? ?o&?E{a?kn?xeNWW?sTڊK?m%W?eg_?_VC&?VjiF?OAg<:?FB?=ɷ?0?5mzl?3eS?8,*?Am?JG&?VZZR!?+(:گ?u^h?i%x?rb?ay?Ųӹ?8?8K]!?ERqK?@9ʤH?|WPyP?v N۝?pD?fM???_裴?Uq?MZVU|?C㹗?;z=?5|h5e?8_þ??ęD?G),?RH>:?`c%s?lnm ?w"C,?RǤ3?Z˱?r3 p ?(?[\?dw?ad?}?|P#?tL3?'?$?C(?n@v?g;E?x ?qa"r= ?gX?]?S"fu?HW?@?9 p?8£"?<`K-m?C6f?Nѓ?YM?dlz*?pxco?y? }w?/ɲ?@Ӝ9?VF?h?oyP?|0tO?NW8?|:YT?ŃO??]&N?A*G4?oL8?nR?y4B?p*8?d0X?YF3?N"~iq?C V??P?|&?|?w#R ?ln7&L?`cji?Rs?G*J??"} ?8_؉?5D?;YB|?A/?EN?vF?i+?ZܶY?Mx~?A%'?6h;1?/ F8/:?*?/Q㜰pT?5ڦOй??x\$?FV ?N =?Ug?]-9ox?d*?lJ?sjK?|Vdъ??@詙2?47D?*?'Z?؞?Ow_?K'6;N?8!?DLL?.?vQ&?iT;Y?Zc?LY|?ADד?4M6v?+?&&FX?(4y7LS?/J-T?5r?>`1?ESXx?Mn?U ˃/?]ڒ^[?dzG?mR ~O?D:7?M3?UhA?^^?e׺n?pDS8?xC㩑?xVB?ڕN?q{?[l?i@?P`?OO?M<&a?OnZp?{(1b?pEo?b5>?T?F*x%b?;vm?+3 b;?!Ц?Y P?6?"A"?'1e~?/rP ?5ܠ@?> #&+\?ET/0?Oc?V"(?_V,b]?fyO?qaR?yab'?4i>I?l#;?u?X|?󚮋?R̒}?ᯪ?~j6kfD?tQL?hV0׊?\A J?O|M/?B??6/?%t4\?DR?ƹ?FXV?Pgς?Vjf?_XKw?g]cQ?p^lÕ?w#^?}N.?ul(?/X?/LK?H?{)#AQ?to(?kCHM͗?`#޲?S8 0?GG9?=Gd+?21|X?V?i[?љxu{R?z'(1?[Wak?D? KF[c?'2-0?/c<0?5or??{D?FK:?O(/?UItE?]#Z@?d7?loL?r%:{A,?uS?v]E?v?tL8?pי?h̬OT?`CU ?UZN:0?JE?A`^?60aG?+e1`b?e1y?Pi? c~?[0? ?[ *?q?"B ?'ϳ8?/NoQ|?5׶???S&?Fʆ?M\?S$n?Y 60KH?`dk4I?dɢma?gʾ?i(3%O?iU`?fw)n?b3I?\B!S?S݋?J?B[0s?8O;< ?/lc?#ACx?h? v ?>Qgo? hP?l?zƃs? ?9rC?#e!HQx?(8*vE?/WL)?5WK?=A:?C‡?HW?Nn9?RoA?V]*NO?YX?O?ZޮK?ZdȤE?WXE7?T; ?O}<$?Gɢ?AX?8Oώ)?0}a}?$+pǽ?G)? ^(?.Q?\ݖ?>'z? 3{?1w?8"?\w?"c?&*r ?*⦯?0x`6?5I{2?;XIMQw?@y2?Dkd?G-%g?J z?L1!C?Mh@H?L\w}?J'?F@!D?B.}7?=H?60M*?/ ?$h?T6]r?|-@b?L?\'?1? ?Bv?x?!AK?!sv?&r5+A?+F|8?//}L?1] #J?3jfD?5W]6?9~mK??1plo,?/L}?*U?%u? TD?;m?H? #un??PS?~p?O}? Wa?i6&w?/_?%v\\??,_v?22A%?5Hm?9/ઐ?;x؜J?6(p?5vo?/σ?&? T?iP?j?ɶ} ?NCR?*"Ծ?5Ś ?A'?M/BS?Y4.?f/F9?r@;?{)}1?d> ? ?ZH)?%]8?v ?crp1?䱦T?wUN/f?o燙?e}W1T*?]G#V8?UkBC?NI&^L?E>?=UO?5)!?/l|7?&ϥb?!ҥuTv?l0]?(?!(L ?/1ɭ?9*Kg>?D?Q J?_ 4~?kscy?vS,:/??5B{a?/&Y7e?' 2#?"u?!Snu$;?$]4?1?;rUvG?EQ?RY ?a-Θ'l?nI?x(?ٷ$?VN?T6??{<[?.?룾FE ?S9(Sc?@@#?yݣ?qa#)?iz= ?c ۋN?\@U}Ռ?TVJH?NH?FXW 4?@$/T?6io?/(?'oqA?$(¼?74?Nc'Jt?a !u? J@?~7( H?u]k?pFWO?hi?c !?5 ?\I꿡?Uj?Y1?PNhK?G?@N'}i?6/?/qn?(?*X Ov?3Z}) ??QA?`>E?lͯF?wcmC?uWF?uAVL?sx:?k ??B)}?To?L&VS?8 Hq?u?yX2oL?tA\^?pF*|?inY?crg?]ޡ5?Vjj?P?y?GH*9(?@DX9?5/u?/F?-9~"?3\#>?;-EGg?D4?PHEͩ?\ v x?h|܃5կ?st?6?}4K=?b0L?4xF-?Z ?ՏAs?TdǢ? ?&6?01y?5h?}  ?yFĒv?uڰ"r?qZ>?lS&Ii?e|Ng6?Qz?E??/:?6Fָ|?@xH?G=?Pgo?Ui Yu ?\6?c ?hANM=?pE2o?u(Ә9?~5Iu?˒4Pr?S?ʫl?fh?nN?Tw?!hV?$!f?g=w?y@6?o TXk?an\4?ROJ\?F|P?< -?1%?(0 ?$?'oJD?/Z?6X' b?@#Kٰ?FW%JL!?NF 8?T\)9?\>(}Id?c Gu/?is ?q~)?y9??ߊ?RXD9 ?U3;?ɒǑ?.?li?F^ۆ?,zE?Sd@?x3"?nqh??a-\{?R^~A?EYr?;t?/r?$nB?!TH H?"K4?'8?/%%}?5!?>4?E'.p?MN35?Tf7#?\eժ?cݕ33?lR\?t@y>?~60&?v8Y?4t^??I1?)?R?D6t?t?/[?vRؑWvI?ksIߔ?_ p9?Ql:?D"c?9,-u_?*< S?!)'?;ϖ,?m7 ?!Ҹb?&Q?/k>?5O?=7qY?EC4P?NG?Ui Rg?]އa?e|'9 ?o_W)?wT;JP?(9?bҷ?u(ÞA?$W(֒g?` I? ?Ҍf?{) )?r@cZ9^?fL?YIO9?M1Eo?A&%!L?5j&t?%sU,?#?]_n4?.?h&|? ?U?&:,?/JǸ?5m=?>V`$?FXPƏ?Ps%w?Vjɼ?_H?g[A=3?pg9?w#M'N?}k?us4;?jQ?ٙV?^Y?{)Dd?t4?kCat?`/@?S;|?G:,Y?=F%?21`? _?0S ?_-?1Go?gvq?k;3? FҔ"?&!n?/m"?5 Mx?@$B?GwS?P䒁?V[ð?_Ca ?f/,U?o1{Wb?sB[?wd^A?yApy?x=6?vSKŗ?r@8̰?kCH?bOa{?W``?Lk(?B#%?7LŐBȴ?,1x?:,9eN?jOa? i? . ? q=Y?x?V? -;I?&];?/(aX?6uԲ&?@;HLK?G ͂?Ox?USer?\ݭ7]'?cJ FZ?h~ܧe?lKY?o p'?n1?kt1-?fl:1?`:?W*K?O8w~!!?Dk *j?;xɻY?13j"?%v"F?zT@? 30??ύy9?kĈل? r|K?h&??!Ի9?' ;?/Q>P?6 ni?@FFkVc]?E/ 8?LZ 76?RJ?Vܓh?\z­q?`?y ?ao W+?a/;w?_ +?Ya?S'v?Liy?Dk: C?S?%š?7?+H9?y `?.Z? jX ??Ά"/?_?!WbA?$l"q?(R[dC?/_?4Y2w?9LoP?? >?B w?DTצ?EP+&=?FL8L?E/t_?D*?A(?=H&Ƅ?7M /?1U?(Ύ-E? Fy?{QC? ӒFx?? ?lX?H#b? ŸF?t":?2_у?!&8?!,O&}?$\?v?( eJ?*Ey?- ?0Li?3YJD?6AH4?9n?;4E:N?N??~*f>?2Rmo?!FetWb??;I!b? ?#!-3?'i#]?*?,hn4τA?Kw?CGN ?A=?+Dl?"MBU?*BdD?1 ?61 :?:J ?> i?@0^u?@t(?@91?>Hi?;o|?7uƠk?3X?-OA?'ma?#:W2? <(Lt?vS}?vR?Ҧu)I? jFZ?fԮ ?*f? LÚ>}@+j[?`‹E?0u?žը?+'h4?#1#?,Zq4?4YZjt?;@j?AYj?DS๹?G4?I3?I$YY?HJ=?F7Y?DіL?AbeP?;?M?5i{œ?/-?'D[?!Uq?\~30?R'U?z ? ??Wz ?΁*?~!r? &?\?H?Uѳ?"L,E?,А ?5cNmr?>>Yh?Dk%b75?JvS]?P:Uz?Sbo~?Uw7v?V 1u?T$& ?RA>}?NK;X?IW0'q?D`с4??<0?6fVuQ?0?&nk ?!B(O?+ԾG ?[x Rę? qH?̬:?t?sr?? |?p?B?*@+;?4XH!]?>/?Ec?O8"f?US쨯?\@g?`1?bҖH?c?a Ed?^th6?X?G6?S.Th?M! ?F"2?@X ?71%D?/k!,T?&[宼j? ӧt?C?zOH? YMQ?MZ?Tԧ"f?b68? Bi?6y,sqY?%s@?1z?;@d!~?Dj-FO?O7߆F~?WVN?`U?fM?kt??n{U?oR?leb ?he>?cJ H?\2[?UTgA|Z?OޢDmp?G?@=^?6g\k?/(">?&{|? ͦdY?`?? n=N!? k@ ? e=Z?h ?,I?+b?6.(2?A U?JC?U'h+NY?`hR?h27O?pY(?tLۙ?vzt?vY?uT?r& &K?lq15=7F?du?]]a ?U {?O2z?Fc[iٓ??{!Ρ?5Y-Ӕ?/c,;=?'15m? Jau?$^?Xsw.?wPmn?bbm-?;$O?#c"ݫ?0΄?:.z_?D6 ?P֣\w;K?\?fHDd?p?vVJE??{kF(?~ m?)k?|טAF?x:?s[дA?lUAH?ct2$'?\1Qm ?T8aܪ?NN^@3?E9!?=Vf??5O;x?/bo8?&ϕk{? lZ^?'.@Z?ܲ?p? ?'y`?3)2?>g,?G?S72?`E?ksM?tLn^ ?{k?tGȀ? mS?\\E?la?~)3yi?xZF@?MJG? ?޹?x;?|nT)?u^p6Ya?nʸH?f9|?`fEy?Yt.,?S!d?Lg?E8B??y@??6[?/fL8?&)?3?!N? 7Ϊڸ?"LYZ?,_W?5+?@+U?IrT?V 7?c|?o !H?vCgD@?E?\,pr?cng?gN?0|!K?_?~؅?wqX?qN8?j˙׭~w?dX?`e:??YsȚ?S, ?N;?FްT M?@Hd?7-|~?/ޅE6?'>he?#4A?$Z4?-cnoK?5 ?@53;[?HDB5H4?T;j?a?l 5F0?uS?!?|c{!?9v{?w?7S ?ť?I;?nQx?y)2!>?sS?oYa`3?ij ?d0?`r@?ZK[a(?Tˊ?O?%?GF@?@:?6NF?/5y;?'?&[!F:?-Yw ?4ʏ}?>x%?F ,s?R>8?^pC[Y?wۖ#?y(?yT64*?xzw?xؼV?xڶ1?yTΖy?y(?w۩_?u]g=v?q"j?lSR7B?dA[?\x?S,SG-?IRHF?A *R?7o mT?0:^4?,іL4?,ˉ?3 V[b?; ?D\mqc?MCA?UQ^/?]<ކ?ch`˹?iT?n??q˂܇?s`?u2`?v54?xҲ?{gC?~pj?mIt?~=?|m}ņX?xY}nz?sZM?lnh?cHDpL?Xǯ8?N`Z?DR?;iGC+?38F?-Kۦ-?) K ?-wbx?5cj6??y:(?F8E?O6?Udtxl?\.+y?aSQ?f8_O:?j@?oXwq?r?u2YKy?yT?[?~??Q}?s^?$A?]-I?~|I?x ʾ?r$?h}O?^q@F?R?QF\?F=7?>z4+6I?4˂~?-qdw?&[%B{?')~4?/_TJ?6<+?@Mut?GCUD?O5>?TCW?ZJK?M?`Gc?dp ?ix]?oX>5.?sIj?y(ĤrO?m>;?¦8D?(1]{?-yI?&?d?|<{1?uSۮ?l Ow?ai`?Tl-v&?H5dsA?@5&?52\?,aUT?$[?#4y`&?'>l?/n&?7,l?@Q]?FݠoV?NFH?Sz?Yr w?`dPl0S?d'?jwsA?q˛?wۗ??~i?. K?$}?ǯD? ߖ?[ B?Y?v}%E?o ?cIi?V %9#?Il1?@v?5/~ߺ?*0h륨?"M hL? 8w?!^tͧ?&b׃?/eօ9?6[??xtx#?E7]?Le5cy?S U?YrLk?`p ?f8b`?nmrU?u]i;?|m>3?xtA?2O?9!?*? h6?~AD?vJ}ᄱ?nB$(?bű?US?I:ſ?@.?4Ai9?'{f#D{?u/1?p s?Vi/.?!?9'D?&X.t ?/%_q?5b/?={58?DPAg?LfC,@i?S~`?ZK c]?aXyN`?iT8=}?qt!?xYr?~ n!?AM?[㮤? ʾ?X[?{j:?tL z8?ksF/?`m`?Sa$e^?G{?>Iu?3*/Q?#^Ws?Ғ%?rmXUY?潾b?("$Ͻ? ~O?&VF?/aJd3?5NH}A?=8?E8t^LX?Nb ?TO?\0;lm?c~r?lS7O?s[P?x&hi?|֋YA:?r ;?~ۅS?{k x?vUq7N?pQ?f8k?\N?PvJ?DsC?:e?x?0K?V?&2gg?<T?xv?Y?X? f:?'1]?/bk?5i[??zl}?F>A5?6t@b?@3:]?GE?O"|B?USj zp?\ݘjz?cJ"?h~ Dsu?l`Hq?o `?nwl?ktLmM?f2?`\3&?WN@}?O8ũ?DjD?;[ӽ#?1 A`?%uN&?# P ? tR?e{?V$a?2 t? mdQ?x>n?s?? ^%?&[F9?/i#?700v?@)Q?FvO?M3?S.K?Xe?^sc_o?a _?cJE;R?b?`pV?\TȝQE?Uȟ|?O8V?ES?>*Vi?4Y)?*BhP$P?H-?!S?)[?=h~?h͘2??k w4? q͐U?[5h?+0[?!AA活?&p?0l|?6zC??>PF?D_q?IV, ?N ?Tt?V 6D?U g)?S=h?P4qN?J 暉?Dk ?>}?5e ?,қu-E?"Mܟ?sk?2v?՞? RV?_]?.Q?XUk?? Kdӹ?zhg?j?[]?![7}?'C皢?/X?5ha"?;95Y?AǬv?D([S?FnRe?H;?IKV9?In1i?G!,?Dwma?A@?;;p?4Z8}9*?,#0H?# -?-\9?K´??b0Ζ+>~5!V? |.?mK?g="? k ͩ?ҏ~?vF ?u*? <\'Tl?#9a?'ˣx?-l?3?7uLH7?;o2@??>@Nԙ?@8w?@. ܽ?@0?>3f?:z8?61_k?1/I&b?*CX ?"N^:3?-Ḝa? ?F6!?eQ>68tg}z8>E>Bx^?Ό?ꬊ1?!ZS?Z?"vNJ? r? p_舲]?"(SD?$)T?$5Ǯ?$*@=j?$ot?$?$>-?$fY??$FnU?$*H ?"]=p ? p^?+ ?QؘR?4O?#"3y?c?ُY>C.>Ѝ 2>sY]/p>Sb? ?6.? ?9~?0;b?#B- ?'{9?+4G ?-Hya?/@Yk?/5#?-̞0?+9Kl)?'Pr#?$w{?";#j? FI?qp^?Ba?] f?7Mu?ݴhg? Gv?)z? D>q">#D">z1_Z?L>@R)f? 3? ȽIz?/o?d^4?"M4z?(T(Ԥ?/.G:?3$S?5r]?7(?8'+r&.?7Ia+?6E~u?3(#?0JfB?+uWCu?&AQ(?"2U0?퍤e??*ƞGH?+́? y5R?E?p2k?Z+>Rkh >d;>"n\?Rc?K?k ??$+O$Y?,݀Rp?3D7b?8P[ 1?=$_dj>?@I?AE?BmJ?)?Ap-?@1`E?0 >7^>ʃ>(=H?;S?rv?A?$*G?.b{ q?5dVoA?q?KIk[>?Kup?JGI?G!ۻ?D?AAO?<n?6kx?011?'6쵺?!)?m35??R##2P?` ? ?69A>^>4?X,m? T)?g@m?d28L?"K-9?,8ӣ?5c:=a?>CZ?Dj?JѦb7B?PHC?Sp!?UJ@O'?V {Hh?T,?RAæ]?Nյ{?IV@&?D`bF?sM?vX?3X?q:?+,m?(_7Ԟo?3B' ?t9Q?/߷?8MW?Bt6?Jm:L?Sn;<)?\B5?b*&1ޔ?fb3#?iVvƂ??i̫?gGz?d^S?`eP ,a?Y ,ί ?S$v:?M\ѬZ?Fy??5 E?5A?V P?an?i¤<?q[v&K?uQ8ȿ?w&9?xmB?wG]?tϺU?p?j3&t?dϽ۱?`5Sz?Z'Za?U{eD?P$??J1]?DV??a?6/Jg?/?'2Mt?"(}yN5?>???$Wӷ.?/+ZR?7?Al5,?JCJ?T4?`>?gXU?p1,?swW?vG A^?wy$?vu?tQ_8 d?q.?l+!Ufq?g"(?cWn?`B/MA?Z|{ݿH?U?QBEn?LuZA?FJ%W?@D]ڈ?6Mz?0 뜬?'@?",n&? s`G?$%1&@?-ˆ+c?6?&E,:?@-N,?Gԇ}?R? v?\ & ?dA'?k;n?q25?s9F4n#?t?tQ.jk?ra}?pP5+~?l$̨ ?i\?fi?cWQ?`?[{VG8?W.?R/=?MZ1'JF?Eサ??z4#?5 ?.c?& Qn?"4P"0?$H?+0!y?3?< ??D؃c(?NĐf?VHiG|&?`ce ?f?kg}?ok]?p??q.wdP?p*E?oX?lֱ}.?j-ls?iz>,?g!^i?d MR?b,iE?^4Bj?Xj/?S"?LW'(>~?D]D<*H?<#q?3ɜ0"?+l`$3?${zD?$P?'jQ?0it7?8؋?A3꿔C?IRCj?R(2?Y!oGL??`9Up]?d*mv?h8??j(?l*\ ?lǪU-?l{Ү?ll o?lց9)??ldz]9?l*gY??j6F!?h6ժ?dKD<?`Y@~?Yq"?R8$?IR ?AϤi?8M?0kK?' ҏ?$l$?$Cyj?+k 0?375?< ?D\/?LVdx?S"ٸ3?Xɝo?^X$?b,Ira?d1?g!; om?i)&?j;#?l`>K?oȺ?p6;I?q.O1?pν-?o;?kgzl?f ?`cĪ!?Vڟ?NˁJ?D5hFV?<-&?3qL?+1.ʖb?$R?"ZOB.?& Kݒ?. ?5y??ywV?EPK?MYY )?RLJ\pi?W.]Zo?[8>wY?`%M?cWB?f%9?i%a?lljx ?pڲ?r?8?tP 2?tH?sW?q1۽n??k.`?d׫t|?\ f?R?hEI?GH O?@.??6@+&?Tٲ.?JDl`?AmvJrB?7^$?/-&h8>?$$Ş?~&?*O?"(rAJ?'1?/?6qA+$??i?DRۍ ?J./?P H]2?U`\`?Zʏ?`OKj>?d^*?jA(u?pg:?td?w%Ժk?xWZV?wn&'K?uPY:(?q[G&?ioa,?an}1?V Jْ?KU?B7ݫ?8#"?/9'z,?"mdž?co?|Df?^?!)@UD?&* ?/?5ጬ9?=@룄?CD?Iydg?P>f?U09'?[ʂ?b,3?hXk?oDS?s/; .?vV~?w*KE?w[;?tݟ-V~d?q ` ZJ?iU `?a.B'1?U|9?KFV?Aa?7k,p?-ݯ<$a? m.&f?We#x?%qu?`Q? ?!?.#?'ER?/JD\?4h[?;aG?CE*{?Jhê!?QI ;*;?W/4/?^b:l?dX?kh\f?q24v?s?uQ<?tŕ?rĥ?n?f3P6?_ V0n?SN?IRՂ?bJ?Y"?P<5O?EI݃3?="A:?3"c\?'x6EB?fG{O1?rm? U-u? 7E??YTϫ? C?"AHuU?'͟IO?/LHPG?5Q??>?F!6B?M[c͓?S$v8 ?Y~?`dDO?d٦?g'P?ifSAE?iU?fƵR/?bI?\B*?SݫNH?J.R,?BGj+J?8OKi?/X?#@j\ƴ?ܴ1? "^?;?]?|GI? o?g}C=?'q?!Ӆ?' _Š?/D?6?@E0?Eם?LY9ݵu?R?Vj[z)?\lD`?`?Po?ao (?a/?_ .ǯ?Yȃ`9?SB?L(?Dk=C~J?b?5e h?,l_|?"M:?H4+?H? ?Z6'}>׵pu>!t?h5 ?od?C?R/1IO?*)< ?!Ӧv?'6K?0 K}>\> Z>~_?.'n?קF3?Lm?a^?e?8BB?"-?'FN"V?<ݿ?@1ŗ;,?Apff?Br&p?Aņ?@G~?=%#4?8Q8?3E6?,ӆZ ?$,T?aL?y/?轼'>CL!'>$-m>y>y 2?Zwa?ۊĜ?l-RB? O"#?{?*N_1?Q?娗_?"1r\?&~~?+tU?0?n?3{?6E_ڭ?7J3?8( m?7g^b?5zi?3%cA?/e?(ϖ ?"NE ??3? 9`%? ̇2>޾u3>{D}S>$;>6ic? eu?'\? i[?ə|?7@4?\^p?him?<#%[? mb?")tSr?$#J8R>a}>!mj>iv>",Z??2#? hS6?Z?W9?m֦?ZW_?#:?v ?s{Cx?n-x?]M[Z?n?t|h?k!?VU?\Vz?oTr?Xfg?Sxm2? U?4O?&>4%[>P>;)ݰ>dZ>9/|Iy>^; v?X?9c?Ŋ m?jF?@^?u6*?!Yp?#4`Ӯ?$s -j?$i?#~չd?"tA? L:?{Ⱦk?6_R?n@fHv?;]?.Ž}?Tpy? ǀmw]? ϫ?IDl&?b*>%k>MyY>x:ܸ>hH>']]>;,?|i8? j?w?,6? F}^iq?$if ?)1k?-?/;C?0v ˬ?0-{?.\2VwΆ?+%3?'Eg5W?#? Zg?=ηE?J`>C?} R?U@? plZd?? N?ybZ? $֭>S>.7"m>ك0>w L>e?W\? 7?c]_o?TA+?O]?L{Q? O?u?>9 > H>,5.>KGs?)6?PY?&KLx?cӜI?((6?6҉_E?͍? Q>6O;V>O>}>35?.zmX+?GJ4?*/B3?#%CR?,Т@?4XǤ?;B%&h?A`?D߿Dx?Gsi?IJ:&?IjP?H?FFlV?D;|?A39?;ǹ^?5h4F?/a&?'BQ%$?! w?Y}_?R?xh? 9 ?Tx? eh?͎?(1?1 ? $i?f;? DWQ?)n]?3B~?;f?B#GF?G5Lr?M2nWM?Q*?R>?R[?Q0?PݒNO?K"+?G4A?BmOL3J?=ۋN?5 ?/G\+I?'qmp?"I?n]^a? 3?ι? c$?ˇ$??t?CXӯ?} =q?4c?$!R89?0]MN?8N~?A%3$?GDq4?O|O(?TiB?W:%)?Ze7&{?Z2Bl?YX.r?V]5?R͘oG?Nf?Hie?Cυ$?=̝,X?5gB?/T$+e?(5?#<ͧ?5',?ԧ7?wifQr? 覹? #?8oj? /?Qdx?BVt ?)}L0?3K'?= =Pb?Diѳ3?M1-M?TwH?Z'Bw?_{2.?aA; ?anq?`ߠVA?]?X{?SC\rL?Odxo?I27@?CJ.ƙ?<9۩N[?4~*n?/O&?(js?#DM?lu?z"?Cu7?Ƹ*? gn|V? 3T?fKW8?!~ *?-}R?6±@?@4e?GN8k?Qx?W!KR?_#?c0S;?eid]?eޕ?dY8r?b. Ӝ?^ .> ?X\h?S>V?N'?Gu:?A"?:LO ?3W?/P@Mo?(4\N7?"63?U?_-t?Y ?O]Lc?ķlƈ2?RPqr?#EX/?/x߅?8yET?AY?II?Rk?Zclo?aW)V?eh?g `?hW?gtR?d8??a*b#?[x ?Vfzi/?R*t?L]X?FP0R?Ay_x?:LN1T?4}S?!?/R{N?'oMnX?!ʕP?q$?Ө]?uz M?&)4?x;?$znּ?0rbk?8FZr ?Bt?IW?RVk?Zrd#?a槪u?eJɄ?h '?i/2w?hu1s?e{Av?bgtL?^s+ ?YU+b?U2IWD?QwRI?L ?P5?FPnH3?A0/?<7vE?5p?/$շ?'>?"(3+?_57?A>:N?2FX`%? 7?$Yf?0)?4~?8R"t-q?AlM?HrN?Q 4?YV-?`ޭEZ?d +?gsxYG?hu?g@;?eU ?bŎ?`/僶b?\!ty8?XxI~-?TGQe\?Qw >a?Ll5<@?G_hw?CH ?=cͱ?5`?9?/A;A?'A2 q?"*(?2&?cH?gŌl?#$erE?.RZ?6?@."z?Fţ}a?Pᬈ|?V[l t?]=?b-#d fE?d6cn?e ?e*?d=/?bzqm6?`ڋ A?^~/Dzu?[?V?Xw[?U2,\?R)rP?N9) ?I0/Uݘ?C ?=!?5dg /?.&H?&$AP? Ȁ@+?*s?acg?"*?+⻎2?4'FM??'=w82? ǚ ^?b&e?n j?#1O4?+!?3,K{?;’o?B蝠P ?H[擾?OW_^?S=pc?Ve?YSl1@?\ ?^o?`jGݤ?aB]?a?b ?b*m?bg'?a)%?^G_U?X 8?RpC?K:?DAr?(?"1?'@"2?/E'?52 ?=??CHjL?G[?L쪁O?QvE?T|?Xw~a~`?\ `?`/^璾?bd ?ep)N?gGu?hu3?gs.[?d6DV?`ގ{?YVQ!C?Q吔?H{?Amga?8SKRL?0*-$?$Td?) ?3V2;?B?`u?"(#?'>s%x?/0t!3?5rCT?<71w?Aձ?FO\?L E"y(?Qvb V?U1CK8#?YTB!?^r#??bgP1?e+?huUVf?i`?hr?e󤖝?a}\(m?Zk6M?R3C$?Ik?B_Z?837?0sf?${#Tx?T?Zcޫ,I?Rn?I c?A~6?8{>`?/H1?#7?iJ^lMn?q?PȾdH?eJ?`{d~sU?VV?"?(4X?/d?3%B]?:K X?A/s7H?Ga?Nްk/ ?X?^18?b-^?/oqn?4}7x?<8?CI{k"?I1.Fڬ?O>??SĖp;?X3T6]?]>,3?`7J?a2?ac ?_-7%?Z'8FV?T.?M1g}?D+[?="}g"?3PT?)kj?o1^?Ih^0? Ns?;uA? ب? og?xZ?pz)W?50`s?#,?(5=?/Sy?5[?=˫?CSs?H%?Nr?R?V\~G?YX72xȚ?Z$-?Zd S?WX'?Tk?O}k5A?G9?A?8OW?0&HtSd?$Ci2?bv2? c?F))5?wA&?[G~?`Q8 ? қ'R??u,"?nDА;?"*B?'q?/h?5pe}y?=ˉ?B1?G3ug,?K'?Pm?Q]};?RꠎG?R^;?Q+[?M2?Gp?B$Aiml?;P?3D)@?)s\? FK5?ir?1J3?? Ue?#i?!D?Vn(r7>I>!e">ׯE?[J?g@?: ?7?cw?@d ?",0?'E7?./U?3c{?8A?<;gJ|?@1Z7J?Ap=?BV"h?ALU?@;S\?=%8?8Q,T~H?3E ?,gƑ?$,3gC>N/m,>/v{F>gd>O6?ׇL)? =G? 7?! ?Ģ?b?gY0?"`?&)?+?7?1 _?4,~?6ã:?8X'?8X?3R ?0Wp%?)ϫ0Iw?# "\`?r^ܳ6?e=Ǩ? "Bz%?C>6y(>>/ݢK>krp? |jb?ym??/׹? pS?T?|yi_?IT?j? G?#UA?'E>am?+%hB?.\%?0.#z?0w}:D?0~?- J+-?)?$? GYϗ?.s?\`? #KTQ?o>$>>>iퟗ-M>y v7>ND/>Kw?.*.?H3? @uh? KР-?ʈ?-?:ˑb?mͧ?5ml?{5]? !?"r?#?$J0?$>mC?#3.$?!%2AW?k@?=J?kj? *?V|?d>JnYp>:,*> >?Wg>,}>?>B ???1? ^+r3?22g? 65?܁^ ?}ťw?q{?'??4Vﭏ?_g3?;)c?ȜZ`? [O?*L-? ~{?55p? `#yU?PV?*|>Cy>:pJ>,6'>? >>2@>Ȧ*> AX\>`? /?EU)V? }H^?|=7?ݫ?K x?-d(?Rfu??X?? S#?=>/?J6O$?T>]?v7f?\Y>q?/Ƹ?+.?©s? e}?s?wVCL?b \>$ e9 >x jK>Tz>4>+ &> ^b?s{ԘX?]d ? ~Hp?uk?ZL?R8e?  ҳ?"C>?$ 1?$bx1?$]N-?#+j?" wB? <{<2?Z w?&~6?\cj?2?X? 7{,? \<юQ?\)Ӯ?*v5ٛ>}m>\pN>F;>B[>%lX>hM&>j6?g|? WU?.>?Hg]?{UhL?So)b? mݠ+g?<QKK>,囖O>tĈH>uP>=c? C_#? klS?d)L?fof?"L+?(kT5R?/arO?3$?5ԑӲQ?7&!?8&)!K?7t-?6D"xP?3g ?0ϝ?+rӽ9jL?&+?"0@I?]U?>?'?ۑ E? _`S?x>?ƻ>C?WUi>b[G>ԓy>[!?Ec?Aư?A?*|?"LWL?*A58!?1?60"Gjo?:X?>T?@0y؁V?@-va?@8*SK?>~άD?;mIr4?7s޴?3a?-U*`?'C)4&?#7SzL? :f.<?rܳ?rb(!?ϲ.? fAP~?cEl=?҂?8tg}>xo?^.h? *- ? ?W3? D[?(V?1]o e?7Lh ??=G:,?A"?DD'r?E.(7?F>ܵ?ED1?D1?B vA??n?9b0?4Wj{?/ B?(4Q"?$yWnV?!U`?z?ʪ.?ˎQ1ff? ei!?T̯?uw}?&Bs?ْ? W0X?yMs?Q&?$cU99?/ߙ>|?6/DK?=F?ByO|X%?F9hF?Jϡ?L\*?MV|0?L0l?J y?G,#?D'?-?@A5?;70..?5$ւG?0vU~l?*R ?&'z?"`h&C?W֚??4K?βX ?  _?9&)?W!!P?@1Z?*k9Wl?x? H@?)ĭ?3"[?:1~uK ?A$83?Fp?K ?PYC+?Qc=?RyS n?Q Z#I?PhA,x?Ls&?H?EB?A;שj?;0Kf,?5-CNS?0M*?+/QD?&0WC?"`pi?]?q#-?]DΝ.? hmS? Ur< ? ]2؋?;g?D?"|@|?-}:(?5ԨP?>8`?DDw?J @?PX}?S_ yM?Uq8i?V*5G?U|2 ?SԾL?Q`vk?M`St?Ie ҙ?Dn?@y?:&F?4Ûd?1 ?+ڸ%?&&Db?!Sw?oH.S1?$:?OW? ~T?g?(W6a?%e??$Rp?/JC?70?@.=|?Ec呶?LZVƞ?QeZMU?UqK?W%?X1,K?X5M$e?VM. Og?SL%?Q1?0"?*˹?$,? 8t1?0D"u?v@pT?ݜ({?[mz x?vV?I~?$, %g?0rڔ?8"?@Jjd?F hL?M ?Rxm苼?V)H-B)?Xv?Zww?Y?WĎJ ?UL`?R;ɸ?P[ac-?K7 ~?G<.6?C m ??vo'?:eR?5,K??0u- ?(Mn?#4?17|?BV0Mb?a?}XOm? N?Ԍ?$S%V?0)ttu?7р@?@5??U?E- ?L.M`?Qh)M?U{6 d?X54˨?YV?Yg1ZR?X A|?VYa??S,{?Q"A4Q?OIJʨ?KQrǭe?G;7?Cg=&?@ P?;.a?5\#?/r?'E?",?3> ?T+I?S>??ʪY?#R?.SdDM?6?xUI?>yP%?Da?J dݻEB?Pg@?S$?VLG?W]n?X r?T4:?Sy== ?Qfe?O^w@?Kxg`9?Ho>N ?DDzr"?A:T?;0z?4T ,?-2=?& 4c ? &?n[N?l ??3e=?"࿎E?+4U?3E$i'?;i-2k?Q__z?SL?UL!K@?VR?V=?V6?UD$?T:ؤ?Sy *?Qfw?PZ:U?MFJgC?IdiCe?Eiz?@HG݂?9K?3 YU$?+mF;?#N_]#?Q9f޴^?JCy_\?*w ,??S1? 7>0?i_?'=Y?0:Ja?7o0¨??6" ?C?H(?MMgc$?Q+#5q?RX?S;m;?T[?Ui%t?U&^?UiTb?T[ƶ7?S%zC? 7ƥ?@eG5? Ug?J/Ž?Pio?#[?+lL`?3 =p?Hn!f1?KϪ#I?O1?Q %?SxP6?TG=s?V= ?Wa[?X n{?Wõ?VLlRON?Sh?Pg&{?J #Ƞ?Dac?>z.A?6@?.Tęj?#u4?h?.CM?TzY?T}?bD?",^?'lp?/6ƅ?5)F?;.Db!?@5]6?C?%{?G;NNi?KP|?O -t?Qt?4zl?:w?@O0?D!?Ie(?MtiXKa?Q_.~{?S\FE|?U{? ?V)78|?Uq|X?S_\?PY R?J~)R?D?>k>3?5u?-5?"}*[?F6]?-U2? _y[? X,? ke?ڿ?rÚU?8~ ?"aϱw?&N?+bG~?0zȓ?5-2G?;/FTJ?A;X$?Ev ?H>AmtF?LNڏ?Pg> ?QdB`?Ry''?Q?PYYIb?Km$h?FU. X?A@M,?:8F(v?3#9&K?)ǭ ? Dƛ?O3b? [~ґ?-j?YΧ?;#o6? K?CP ?˱ ?Y:skF?"aj?&'y4&?*a`&?0v)l?5r?;e ?@3 x?D?U?G,o߲?J ]U?L04S?Mg ?L\J)?Jy\?Fȶ ?B"#$?=Gbb ?60J{?/:?$01?5}O5Y? m^?ȯ1?eg? i%7?ʑ?t9\?r ? :{?#7~?'ȣS?-L?3Y?7sm3?;m*0?>~f3?@8g/A?@R8?@0?>o7?:nN?61lN?1?*C4<:?"MB\\?-?-T? w?Dk>BM>#/>ºcл>mfS?Z>(?i U?F1Mد? #r?nr?(b&?dHa?XZq?"03W`=?&?+r}}6?0V2R?30?6D3_?7a?8';v?7m0?5տ z?3%4?/`=?(V$Iʪ?"N{+?I,?Tj\"? <]? =>~*g>xx>7r>/X|> kjK? 4/@f?yD|N?>RR? n^?S5\?{FD?Hp?p}yf? _?#Q(J;?'C.?+$1`?.[б?0-R%??0w>X?0f w?-}qO?)y%x?$c? G?.mʅ?S;ѳ? "pb?-7>^4>-XF>A>F7>a >ɪE>rDT?+Ot?\i\? \at8 *? wv?G+ʻ?dB?[|?& ^?Z!? =X?" Z?#0?$ah?${9?$ ?"^c? F???Cl57?i*? ЊnI??tj>}=>?@E>Z>ždB>y `>$Z?b<?`ve?[L ? d?]aי? ?< ?[} _?uyw?Szyh?J](]?>2?{HQ?zM?TA`U ?/u?M 4PX?f͢?~x? V ?G@;? Pl;>b>0e2>ɵ c>1ˎL>>f=?>?3B>KCq>Ъ"/j?V?N?fd? a}N?vJN4?%u34?1Em?Ld!?rL}?`8l?ΰ?`q5,?s /?M٩cm?24Fp"?'38f?۶y5? QfF?t,?rz?d&&K>Td~)>ح=SN>?E)ha>e1F>dg<->a(>y>9">VW?Zk ?}X? Xtױ?ˮ$?c?5?¡BO=?YgQ?-EwW?䀏ID^?;C?gG?upg,?_绠x?ڬjU%?8~? ? p> ?]j?ʤ>4>">yZQ>hs_>f9?>㑑b>> N>= > ?>ڜc˂? }i_?Dܢ¥4? g?|WU3?&vY?Ji.?,w[5?QDq?ܥ2!x?*%?;Srks?H0Z(?QY4?tQ?Zs~9@?`p?W}?%r=? bFLk?E+?ܑ[?`:"y>!*>vz5>ߋ֩|>"%>q!>7;rj>g{5? 壺 ?J4??iN`?Y?ߎ /?!p*?#̤"?$<`$?$rȋ?#u)?"P6(`? kq?wR%C?2/f?jh?8xY?+X-?S G? XO:R? ?E)?aK>{;?>J{$>uX>fRѓ>'C^>SY[? y!j?#z0O??W|8?.u[?#@.w?'yR"?+2azw(>z .j>vo~? ?,?B )?'??pM?%u:G?+e@;?0_R?3+h?4M`?5ًڰ?5?4΋ɤP?3W?0Y'U?,ـ}?)q?&^?$^ Qg^?"O޵?vKgm?ŔI?h?DE/G? g ;?Aǡ$?5t[?^=>/;}?z\?Cig? `a?3V͋+?0˅?-B ?*¨*?(7M?$>?!)XC?Ȇ?.RjK? ? -C?C8ᬉ?ٷ֓?J:q?ͥg? 6͂?yNu?ĕ?#?_ #?!'?Ș?Dq9?:St? t2&?<'?WFg? V:'?ͫۮ?z??'v- ?0p QY?5A?;FN?@+?C-Ȫ?DbV?E՝2?EFD'f?DK?CP ?A??]_~7?;i?8qQ?5+q?3mS?08\?,W6E,?&nP/?!(o?@^:?2A$? Ev? ]p+? kv_??iɆ;?D'B?!nv?+/37?3*?9,[i??B.?C-Gi?F4"?Hcm?IoD#X?I_?He"3k?Fhmj2?D=2?B?@Cs?=B<.?9+|9?7#KI?4Fn:#?0~]?+Fa|h?$+?t0#a?V.?4bI?;td0N?AE V9?DV?Hc%)|?J}2?L3;?LS؛u?Kppy'?I@K?GD >?E[7$?CrAA[?@UV?IتD ?G#q!?E.?C(jj?@~X?;~[1?5KL?0Y?) u?"?+;?mFٟN?n ?X[?ώ?3?"vd?+1>8?3#=?9/ &z??\E?CN^pA??F ,?Iڡ8Uy?L+?M0G3?M%?MQ.g?LP ?K1?Jq'?Ib?G3rqm?E|[??BЙi??[ S=(i?9 mjw?3T4?,Տ"!%Q?$^J?pF%a?JL?l n?u?3Ej*?@8g? Ǣ% ?'E'?0?6;_:?J??ZS?Bͯރ?ET+]?G&W?Ib&D?J啽?Kh?L!?MQH6-$?MO?M0dJ?LtHl?Iڑ 1?F?CN$"8??I?9$?3?+146?"Zlk?4M?j֤?l2X߅a?nLf?mM*?+B5?"*M ?) 0?0a^Q5?5qZo?;ǥS?@iEe?C죧?NvF?MZĄ?Ko9?HdqE?D?o?AO?;/&!2?4;E?-Ģ>;?#㫁B?T]?'J?G Seg?Yj?T1O?ejԽ? pi;?&\y$?-&?3f?8pM+?=@?@l؋^?B:?D50.l?G#\,?Ib,b[?Kob}?M0!j`?Nw :?N]?N9_?LR#wTG?I]W5?EG?ASb4?ԧ?BG¯?Dh 6?Fي k:?HeGV?I^J?Io}?HcP?F4Q;?C-f??X?9-Wd?3+?+0?!A;?FLՁ?A? (qV? )z|? `}e? Dt ?3渑?2 aU?!)J"^?&oi}c!?,X2>%?0 d7?3m;7,?5y(?8qh%`?; C??\`W_ ?A TY?CO5s&?DB?Ef4i?9.M?;2[t?4,?a&Qsw?ר?(/? p>k?8œ?\?S9?wy"K?"Osz?$^2t?&^H?) ˵?,Xl;?0?38Y3?4L7h?5ɡ+g?5oC?4^|Nk?3,R?0?+g^ $ܭ?%w Gzt?o.?2?8z# ?DZ}?+J>Ϡ;>z=J">#+Q>|w>? ?ak4;? N=?u]v?591?Yv?}`?<+џ? vx?"3H?$ c3i?';X?+6x ?-q?/3Q?/> Z?-RW2l?+4?'{SyOc?#BZLt?1j%<;??nݥ?9? # L>'W>R>iG>xӶ;Z>Ns> e@?v,?H? .Y? >o??+s)\?7f6?jW*b?1zPz?w[Bzl? *v=?"[?#^LѺ?$kM?$ȞC?#~c?!ԣN/??tK2?kGB{?Z)?g?7MW>~Yנ>9ڨ>? >“&>9 A>y.:`>$r1k?b:VX{?. 0?㢳B? cS'#?qi?v???ZɊP?s ?Qt?Ht?<容N?ԯ@o?ޭ03?Sk?/]?Lഖ?l f?~<0? o"5"?F r>? (> @> J>ɀ>fl>e>0uc>j_Z>{vQ>6xD??cZ?]3y+3? x$?񘫧?/ר?h?_)?tW?'ܤ?;x?;ʭ?/%oh?[Ho?+?̠iM??%M? @?GA?>T*F>:d<(>{ c:>nKv_sim-3.8.0/lib/plug-ins/python-gi/000077500000000000000000000000001370110300500170475ustar00rootroot00000000000000v_sim-3.8.0/lib/plug-ins/python-gi/Makefile.am000066400000000000000000000025041370110300500211040ustar00rootroot00000000000000## Process this file with automake to produce Makefile.in vpath %.h $(top_srcdir)/src if PLATFORM_WIN32 cflagWin = -mms-bitfields -mno-cygwin endif libpythongi_la_SOURCES = pythongi.c libpythongi_la_LIBADD = $(top_builddir)/src/libv_sim-3.la \ @GLIB_LIBS@ @GTKS_LIBS@ @PYTHON_LIBS@ libpythongi_la_LDFLAGS = -module @EXTRA_LDFLAGS@ -version-info $(lib_v_sim_version) if WITH_GOBJECT_INTROSPECTION PYTHONGI_LIB = libpythongi.la PYTHONGI_EXAMPLE = pygi_collisions.v_sim.py \ pygi_isolate.v_sim.py \ pygi_rotate.v_sim.py \ pygi_load.v_sim.py \ pygi_plot.v_sim.py \ pygi_rightMenu.v_sim.py \ collisions.ascii \ cnt.Benzen_on_Ag111 PYTHONGI_PIX = pythongi.png stock-pythongi_20.png PYTHONGI_OVERRIDES = v_sim.py endif v_simplugins_LTLIBRARIES = \ $(PYTHONGI_LIB) AM_CPPFLAGS = \ -I$(top_srcdir)/src \ @GLIB_CFLAGS@ @GTKS_CFLAGS@ @PYTHON_INCLUDES@ AM_CFLAGS = $(cflagWin) -D'VISU_TYPELIBS_DIR="$(libdir)/girepository-1.0"' -Wno-long-long -Wno-strict-prototypes v_simexamples_DATA = $(PYTHONGI_EXAMPLE) v_simpixmaps_DATA = $(PYTHONGI_PIX) v_simoverrides_PYTHON = $(PYTHONGI_OVERRIDES) EXTRA_DIST = pygi_collisions.v_sim.py \ pygi_isolate.v_sim.py \ pygi_rotate.v_sim.py \ pygi_load.v_sim.py \ pygi_plot.v_sim.py \ pygi_rightMenu.v_sim.py \ collisions.ascii \ cnt.Benzen_on_Ag111 \ pythongi.png stock-pythongi_20.png \ v_sim.py v_sim-3.8.0/lib/plug-ins/python-gi/cnt.Benzen_on_Ag111000066400000000000000000000042121370110300500223230ustar00rootroot00000000000000Benzen_on_Ag111 1 9.8127213 0 0 0 8.4980659 0 0 0 12 Ag C H 24 6 18 Selective dynamics Cartesian 0.818765 1.416323 -2.3767 F F F # Ag 1st layer 0.818719 4.249027 -2.3767 F F F 0.818765 7.081749 -2.3767 F F F 3.271871 0.000032 -2.3767 F F F 3.271898 2.832684 -2.3767 F F F 3.271906 5.665349 -2.3767 F F F 5.725076 1.416305 -2.3767 F F F 5.725084 4.249081 -2.3767 F F F 5.725122 7.081713 -2.3767 F F F 8.178330 0.000002 -2.3767 F F F 8.178376 2.832719 -2.3767 F F F 8.178314 5.665341 -2.3767 F F F 1.628523 0.000044 0.0 T T T 1.628518 2.832675 0.0 T T T 1.628489 5.665345 0.0 T T T 4.081670 1.416352 0.0 T T T 4.081697 4.249009 0.0 T T T 4.081730 7.081736 0.0 T T T 6.534899 8.498026 0.0 T T T 6.534904 2.832714 0.0 T T T 6.534934 5.665387 0.0 T T T 8.988114 1.416357 0.0 T T T 8.988087 4.249050 0.0 T T T 8.988054 7.081688 0.0 T T T 3.6918001 3.52319 2.9 T T T # C benzen 2.3081999 3.52319 2.9 T T T 3.6918001 1.12681 2.9 T T T 2.3081999 1.12681 2.9 T T T 4.3833499 2.325 2.9 T T T 1.6166496 2.325 2.9 T T T 4.2393398 4.47208 2.9 T T T # H benzen 1.7606611 4.47208 2.9 T T T 4.2393398 0.17792 2.9 T T T 1.7606611 0.17792 2.9 T T T 5.4791799 2.325 2.9 T T T 0.5208197 2.325 2.9 T T T 0.005895 0.0 -3.2322 F F F # H saturation 0.005893 2.832689 -3.2322 F F F 0.005899 5.665379 -3.2322 F F F 2.459063 1.416337 -3.2322 F F F 2.459072 4.249038 -3.2322 F F F 2.459060 7.081724 -3.2322 F F F 4.912269 0.000005 -3.2322 F F F 4.912273 2.832685 -3.2322 F F F 4.912270 5.665372 -3.2322 F F F 7.365461 1.416340 -3.2322 F F F 7.365462 4.249034 -3.2322 F F F 7.365454 7.081721 -3.2322 F F F v_sim-3.8.0/lib/plug-ins/python-gi/collisions.ascii000066400000000000000000000247271370110300500222530ustar00rootroot00000000000000# V_Sim export to ascii from 'toto.ascii' 16.08 0 16.08 0 0 16.08 #keyword: angstroem # Statistics are valid for all nodes (hidden or not). # Hidden nodes are printed, but commented. # Box contains 2 element(s). # Box contains 178 nodes. # | 110 nodes for element 'Ni'. # | 68 nodes for element 'Au'. 4.02 4.02 2.01 Ni 4.02 4.02 6.0300002 Ni 4.02 4.02 10.05 Ni 4.02 4.02 14.07 Ni 4.02 8.04 2.01 Ni 4.02 8.04 6.0300002 Ni 4.02 8.04 10.05 Ni 4.02 8.04 14.07 Ni 4.02 12.06 2.01 Ni 4.02 12.06 6.0300002 Ni 4.02 12.06 10.05 Ni 4.02 12.06 14.07 Ni 8.04 4.02 2.01 Ni 8.04 4.02 6.0300002 Ni 8.04 4.02 10.05 Ni 8.04 4.02 14.07 Ni 8.04 8.04 2.01 Ni 8.04 8.04 6.0300002 Ni 8.04 8.04 10.05 Ni 8.04 8.04 14.07 Ni 8.04 12.06 2.01 Ni 8.04 12.06 6.0300002 Ni 8.04 12.06 10.05 Ni 8.04 12.06 14.07 Ni 12.06 4.02 2.01 Ni 12.06 4.02 6.0300002 Ni 12.06 4.02 10.05 Ni 12.06 4.02 14.07 Ni 12.06 8.04 2.01 Ni 12.06 8.04 6.0300002 Ni 12.06 8.04 10.05 Ni 12.06 8.04 14.07 Ni 12.06 12.06 2.01 Ni 12.06 12.06 6.0300002 Ni 12.06 12.06 10.05 Ni 12.06 12.06 14.07 Ni 2.01 4.02 4.02 Ni 2.01 4.02 8.04 Ni 2.01 4.02 12.06 Ni 2.01 8.04 4.02 Ni 2.01 8.04 8.04 Ni 2.01 8.04 12.06 Ni 2.01 12.06 4.02 Ni 2.01 12.06 8.04 Ni 2.01 12.06 12.06 Ni 6.0300002 4.02 4.02 Ni 6.0300002 4.02 8.04 Ni 6.0300002 4.02 12.06 Ni 6.0300002 8.04 4.02 Ni 6.0300002 8.04 8.04 Ni 6.0300002 8.04 12.06 Ni 6.0300002 12.06 4.02 Ni 6.0300002 12.06 8.04 Ni 6.0300002 12.06 12.06 Ni 10.05 4.02 4.02 Ni 10.05 4.02 8.04 Ni 10.05 4.02 12.06 Ni 10.05 8.04 4.02 Ni 10.05 8.04 8.04 Ni 10.05 8.04 12.06 Ni 10.05 12.06 4.02 Ni 10.05 12.06 8.04 Ni 10.05 12.06 12.06 Ni 14.07 4.02 4.02 Ni 14.07 4.02 8.04 Ni 14.07 4.02 12.06 Ni 14.07 8.04 4.02 Ni 14.07 8.04 8.04 Ni 14.400295 7.2272959 11.310699 Ni 14.07 12.06 4.02 Ni 14.07 12.06 8.04 Ni 14.07 12.06 12.06 Ni 4.02 2.01 4.02 Ni 4.02 2.01 8.04 Ni 4.02 2.01 12.06 Ni 4.02 6.0300002 4.02 Ni 4.02 6.0300002 8.04 Ni 4.02 6.0300002 12.06 Ni 4.02 10.05 4.02 Ni 4.02 10.05 8.04 Ni 4.02 10.05 12.06 Ni 4.02 14.07 4.02 Ni 4.02 14.07 8.04 Ni 4.02 14.07 12.06 Ni 8.04 2.01 4.02 Ni 8.04 2.01 8.04 Ni 8.04 2.01 12.06 Ni 8.04 6.0300002 4.02 Ni 8.04 6.0300002 8.04 Ni 8.04 6.0300002 12.06 Ni 8.04 10.05 4.02 Ni 8.04 10.05 8.04 Ni 8.04 10.05 12.06 Ni 8.04 14.07 4.02 Ni 8.04 14.07 8.04 Ni 8.04 14.07 12.06 Ni 12.06 2.01 4.02 Ni 12.06 2.01 8.04 Ni 12.06 2.01 12.06 Ni 12.06 6.0300002 4.02 Ni 12.06 6.0300002 8.04 Ni 12.06 6.0300002 12.06 Ni 12.06 10.05 4.02 Ni 12.06 10.05 8.04 Ni 12.06 10.05 12.06 Ni 12.06 14.07 4.02 Ni 12.390296 13.257296 7.2906981 Ni 12.06 14.07 12.06 Ni 2.01 2.01 2.01 Au 2.01 2.01 6.0300002 Au 2.01 2.01 10.05 Au 2.01 2.01 14.07 Au 2.01 6.0300002 2.01 Au 2.01 6.0300002 6.0300002 Au 2.01 6.0300002 10.05 Au 2.01 6.0300002 14.07 Au 2.01 10.05 2.01 Au 2.01 10.05 6.0300002 Au 2.01 10.05 10.05 Au 2.01 10.05 14.07 Au 2.01 14.07 2.01 Au 2.01 14.07 6.0300002 Au 2.01 14.07 10.05 Au 2.01 14.07 14.07 Au 6.0300002 2.01 2.01 Au 6.0300002 2.01 6.0300002 Au 6.0300002 2.01 10.05 Au 6.0300002 2.01 14.07 Au 6.0300002 6.0300002 2.01 Au 6.0300002 6.0300002 6.0300002 Au 6.0300002 6.0300002 10.05 Au 6.0300002 6.0300002 14.07 Au 6.0300002 10.05 2.01 Au 6.0300002 10.05 6.0300002 Au 6.0300002 10.05 10.05 Au 6.0300002 10.05 14.07 Au 6.0300002 14.07 2.01 Au 6.0300002 14.07 6.0300002 Au 6.0300002 14.07 10.05 Au 6.0300002 14.07 14.07 Au 10.05 2.01 2.01 Au 10.05 2.01 6.0300002 Au 10.05 2.01 10.05 Au 10.05 2.01 14.07 Au 10.05 6.0300002 2.01 Au 10.05 6.0300002 6.0300002 Au 10.05 6.0300002 10.05 Au 10.05 6.0300002 14.07 Au 10.05 10.05 2.01 Au 10.05 10.05 6.0300002 Au 10.05 10.05 10.05 Au 10.05 10.05 14.07 Au 10.05 14.07 2.01 Au 10.05 14.07 6.0300002 Au 10.05 14.07 10.05 Au 10.05 14.07 14.07 Au 14.257972 0.88464224 2.5351298 Au 14.07 2.01 6.0300002 Au 14.07 2.01 10.05 Au 14.07 2.01 14.07 Au 14.07 6.0300002 2.01 Au 14.07 6.0300002 6.0300002 Au 14.400295 5.2172961 9.3006983 Au 14.400295 5.2172961 13.320698 Au 14.07 10.05 2.01 Au 14.07 10.05 6.0300002 Au 14.07 10.05 10.05 Au 14.07 10.05 14.07 Au 14.07 14.07 2.01 Au 14.400295 13.257296 5.2806983 Au 14.07 14.07 10.05 Au 14.07 14.07 14.07 Au 14.07 2.01 2.01 Au 12.06 14.07 8.04 Ni 14.07 14.07 6.0300002 Au 14.07 6.0300002 10.05 Au 14.07 8.04 12.06 Ni 14.07 6.0300002 14.07 Au v_sim-3.8.0/lib/plug-ins/python-gi/pygi_collisions.py000066400000000000000000000036701370110300500226350ustar00rootroot00000000000000#!/usr/bin/env python from gi.repository import v_sim # Load the file to test. data = v_sim.Data.new() data.addFile("collisions.ascii",0,None) v_sim.visuBasicLoad_dataFromFile(data,None,0) # Parse the configuration files. v_sim.visuBasicParse_configFiles() # Or read only the given file. #v_sim.visuConfigFileLoad(v_sim.CONFIGFILE_RESOURCE, "v_sim.res", data) # Example of loop to create a dictionnary associating element name and radius. rad = {} dataIter = data.iterNew() data.iterStart(dataIter) while (dataIter.element != None): rad[dataIter.element.name] = v_sim.renderingAtomicGet_radius(dataIter.element) data.iterNextElement(dataIter) # Example with integrated iterators (still an issue with the # stop criterion) try: for it in data.__iterElements__(): rad[it.element.name] = v_sim.renderingAtomicGet_radius(it.element) except RuntimeError: pass print "Radii: ", rad def hit(c1, r1, c2, r2): return ( (c1.x-c2.x)**2 + (c1.y-c2.y)**2 + (c1.z-c2.z)**2 < (r1 + r2) ** 2 ) # With Python iterators. ##collision = [] ##try: ## for it1 in data: ## try: ## for it2 in data: ## if it1.node.number > it2.node.number and \ ## hit(data.getNodeCoordinates(it1.node), rad[it1.element.name], \ ## data.getNodeCoordinates(it2.node), rad[it2.element.name]): ## collision.append((int(it1.node.number), int(it2.node.number))) ## except RuntimeError: ## pass ##except RuntimeError: ## pass ##print collision # With V_Sim iterators print "Collision detection..." collision = [] it1 = data.iterNew() it2 = data.iterNew() data.iterStart(it1) while (it1.node is not None): data.iterStart(it2) while (it2.node is not None): if it1.node.number > it2.node.number and \ hit(data.getNodeCoordinates(it1.node), rad[it1.element.name], \ data.getNodeCoordinates(it2.node), rad[it2.element.name]): collision.append((int(it1.node.number), int(it2.node.number))) data.iterNext(it2) data.iterNext(it1) print collision v_sim-3.8.0/lib/plug-ins/python-gi/pygi_collisions.v_sim.py000077500000000000000000000033471370110300500237550ustar00rootroot00000000000000#!/usr/bin/env python # -*- coding: utf-8 -*- from gi.repository import v_sim import cProfile render = v_sim.UiMainClass.getDefaultRendering() data = render.getVisuData() # Example with integrated iterators (still an issue with the # stop criterion) rad = {} for it in data.__iterElements__(): rad[it.element.getName()] = v_sim.RenderingAtomic.getRadius(it.element) #print "Radii: ", rad def hit((x1,y1,z1), r1, (x2,y2,z2), r2): return ( (x1-x2)**2 + (y1-y2)**2 + (z1-z2)**2 < (r1 + r2)**2 ) # With Python iterators. collision = set() def byPairs(data, collision): for (it1, it2) in data.__iterByPairs__(): if hit(data.getNodeCoordinates(it1.node), rad[it1.element.getName()], \ data.getNodeCoordinates(it2.node), rad[it2.element.getName()]): collision.add(int(it1.node.number)) collision.add(int(it2.node.number)) def doubleLoop(data, collision): for it1 in data: for it2 in data: if it1.node.number > it2.node.number and \ hit(data.getNodeCoordinates(it1.node), rad[it1.element.getName()], \ data.getNodeCoordinates(it2.node), rad[it2.element.getName()]): collision.add(int(it1.node.number)) collision.add(int(it2.node.number)) def byCopy(data, collision): nodes = data.getAllNodePositions() for (c1, i1, e1) in nodes: for (c2, i2, e2) in nodes: if i1 > i2 and hit(c1, rad[e1], c2, rad[e2]): collision.add(int(i1)) collision.add(int(i2)) cProfile.run('doubleLoop(data, collision)') cProfile.run('byPairs(data, collision)') cProfile.run('byCopy(data, collision)') marks = render.getMarks() if marks.setHighlightedList(tuple(collision), v_sim.MarksStatus.SET): v_sim.Object.redraw("My script") #v_sim.UiMainClass.getCurrentPanel().quit(True) v_sim-3.8.0/lib/plug-ins/python-gi/pygi_isolate.py000066400000000000000000000042761370110300500221220ustar00rootroot00000000000000#!/usr/bin/env python from gi.repository import v_sim # Load the file to test. data=v_sim.Data.new() data.addFile("diff.ascii",0,None) v_sim.visuBasicLoad_dataFromFile(data,None,0) # Parse the configuration files. v_sim.visuBasicParse_configFiles() def prox(data, c1, c2, rad): r1 = data.convertXYZToReduced(c1) r2 = data.convertXYZToReduced(c2) for dx in range(-1, 2): for dy in range(-1, 2): for dz in range(-1, 2): r2_trans = v_sim.Coord.__new__(v_sim.Coord) r2_trans.x = r2.x + dx r2_trans.y = r2.y + dy r2_trans.z = r2.z + dz c2_trans = data.convertReducedToXYZ(r2_trans) dist2 = (c1.x-c2_trans.x)**2 + (c1.y-c2_trans.y)**2 + (c1.z-c2_trans.z)**2 if dist2 <= (rad) ** 2: return True return False ##RAD = input('Choose a radius: ') ##NODE = input('Choose a node id: ') RAD = 5. NODE = 216 print "All nodes further than ",RAD," from node ",NODE," will be hidden." coord0 = data.getNodeCoordinates(data.getNodeFromNumber(NODE)) dataIter = data.iterNew() data.iterStart(dataIter) while (dataIter.node is not None): if prox(data, coord0, data.getNodeCoordinates(dataIter.node), RAD): print "Node ",dataIter.node.number," is visible" dataIter.node.setVisibility(True) else: print "Node ",dataIter.node.number," is hidden" dataIter.node.setVisibility(False) data.iterNext(dataIter) #----------------------DUMP----------------------# print '\n\t---DUMP dans du resultat dans diffOut.ascii---\n' outFilename = "diffOut.png" ##outFilename = "diffOut.ascii" dumps = v_sim.visuDumpGet_allModules() for dump in dumps: if dump.fileType.match(outFilename): if dump.bitmap: ctx = v_sim.PixmapContext.new(450, 450) v_sim.openGLInit_context(); view = data.getOpenGLView() view.camera.length0 = data.getBoxLengths()[0]; v_sim.openGLModelize(view.camera); data.setSizeOfView(450, 450) v_sim.openGLProject(view.window, view.camera, data.getBoxLengths()[1]) v_sim.visuExtensions_rebuildAllLists(data) v_sim.openGL_reDraw(None, data) image = v_sim.visuOpenGLGet_pixmapData(450, 450, True) else: image = None # The exportation routine. dump.callWriteFunc(outFilename, 450, 450, data, image, None, None) if dump.bitmap: ctx.free() break v_sim-3.8.0/lib/plug-ins/python-gi/pygi_isolate.v_sim.py000066400000000000000000000030161370110300500232250ustar00rootroot00000000000000#!/usr/bin/env python from gi.repository import v_sim import cProfile render = v_sim.uiMainClass_getDefaultRendering() data = render.getVisuData() def prox(data, (x0, y0, z0), c, rad): (u, v, w) = data.convertXYZToReduced(c) for dx in range(-1, 2): for dy in range(-1, 2): for dz in range(-1, 2): (x, y, z) = data.convertReducedToXYZ((u + dx, v + dy, w + dz)) dist2 = (x - x0)**2 + (y - y0)**2 + (z - z0)**2 if dist2 <= (rad) ** 2: return True return False def isolate(RAD, NODE): coord0 = data.getNodeCoordinates(data.getNodeFromNumber(NODE)) dataIter = data.iterNew() data.iterStart(dataIter) while (dataIter.node is not None): if prox(data, coord0, data.getNodeCoordinates(dataIter.node), RAD): print "Node ",dataIter.node.number," is visible" dataIter.node.setVisibility(True) else: print "Node ",dataIter.node.number," is hidden" dataIter.node.setVisibility(False) data.iterNext(dataIter) data.createAllNodes() ##RAD = input('Choose a radius: ') ##NODE = input('Choose a node id: ') RAD = 5. NODE = 21 print "All nodes further than ",RAD," from node ",NODE," will be hidden." cProfile.run('isolate(RAD, NODE)') v_sim.object_redraw(None) #----------------------DUMP----------------------# outFilename = "diffOut.png" print '\n\t---DUMP dans du resultat dans %s---\n' % outFilename ##outFilename = "diffOut.ascii" dumps = v_sim.dump_getAllModules() for dump in dumps: if dump.fileType.match(outFilename): render.dump(dump, outFilename, 450, 450, None, None) v_sim-3.8.0/lib/plug-ins/python-gi/pygi_load.v_sim.py000066400000000000000000000035451370110300500225130ustar00rootroot00000000000000#!/usr/bin/env python from gi.repository import v_sim import traceback def parseCNT(format, filename, data, iset, cancel): print "test file: %s for VisuData: %s(%d)" % (filename, data, iset) valid = False try: # Read the given file. f = open(filename, "r") desc = f.readline() f.readline() box = map(float, f.readline().split()) + \ map(float, f.readline().split()) + \ map(float, f.readline().split()) if len(box) != 9: raise ValueError elements = f.readline().split() nElements = map(int, f.readline().split()) # From here, we consider that this file is indeed a VASP file. valid = True f.readline() f.readline() coords = [] for line in f.xreadlines(): coords.append(map(float, line.split()[:3])) f.close() allElements = [] for (ele, n) in zip(elements, nElements): allElements += [ele, ] * n # Pass the variables to V_Sim. # Declare one set of data for this file. data.setNSubset(1) # Setup the box geomtry. box = v_sim.Box.new_full(box, v_sim.BoxBoundaries.PERIODIC) # Setting up the box geometry here make available to use the # converting routines to go from reduced coordinates to cartesian. data.setBox(box) # Allocate the internal arrays for these elemnts and number of nodes. data.allocateByNames(nElements, elements) for (coord, ele) in zip(coords, allElements): # For each node, add it with its coordinates data.addNodeFromElementName(ele, coord, False); # Set a commentry for this subset of data. data.setDescription(desc.strip(), 0) return True except Exception as error: traceback.print_exc() return valid return False # Declare this new fileformat to V_Sim. fmt = v_sim.DataLoader.new("VASP CNT files", ("*.cnt", "cnt.*"), False, parseCNT, 95) v_sim.DataAtomicClass.addLoader(fmt) v_sim-3.8.0/lib/plug-ins/python-gi/pygi_plot.v_sim.py000066400000000000000000000207251370110300500225510ustar00rootroot00000000000000#!/usr/bin/env python # -*- coding: utf-8 -*- # vim: set fileencoding=utf-8 ## EXTRAITS DE LA LICENCE ## Copyright CEA, contributeurs : Damien CALISTE, laboratoire L_Sim, (2012-2012) ## Adresse mèl : ## CALISTE, damien P caliste AT cea P fr. ## Ce logiciel est un programme informatique servant à visualiser des ## structures atomiques dans un rendu pseudo-3D. ## Ce logiciel est régi par la licence CeCILL soumise au droit français et ## respectant les principes de diffusion des logiciels libres. Vous pouvez ## utiliser, modifier et/ou redistribuer ce programme sous les conditions ## de la licence CeCILL telle que diffusée par le CEA, le CNRS et l'INRIA ## sur le site "http://www.cecill.info". ## Le fait que vous puissiez accéder à cet en-tête signifie que vous avez ## pris connaissance de la licence CeCILL, et que vous en avez accepté les ## termes (cf. le fichier Documentation/licence.fr.txt fourni avec ce logiciel). ## LICENCE SUM UP ## Copyright CEA, contributors: Damien CALISTE, L_Sim laboratory, (2012-2012) ## E-mail address: ## CALISTE, damien P caliste AT cea P fr. ## This software is a computer program whose purpose is to visualize atomic ## configurations in 3D. ## This software is governed by the CeCILL license under French law and ## abiding by the rules of distribution of free software. You can use, ## modify and/ or redistribute the software under the terms of the CeCILL ## license as circulated by CEA, CNRS and INRIA at the following URL ## "http://www.cecill.info". ## The fact that you are presently reading this means that you have had ## knowledge of the CeCILL license and that you accept its terms. You can ## find a copy of this licence shipped with this software at ## Documentation/licence.en.txt. from gi.repository import v_sim from gi.repository import Gtk import numpy from matplotlib.figure import Figure from matplotlib.backends.backend_cairo import FigureCanvasCairo as FigureCanvas from matplotlib.backends.backend_cairo import RendererCairo as Renderer dpi = 100 fig_width = 3 fig_height = 2 def mplCurveDraw(widget, cr, f, renderer): renderer.gc.ctx = cr w = widget.get_allocated_width() h = widget.get_allocated_height() cr.translate(max(0, (w - fig_width * dpi) * 0.5), -max(0, (h - fig_height * dpi) * 0.5)) renderer.set_width_height(w, h) f.draw(renderer) def onTogglePick(widget, interPick, panel, wdx, wdy, wdz, wdx_ref, wdy_ref, wdz_ref): render = v_sim.UiMainClass.getDefaultRendering() if (widget.get_active()): handle = interPick.connect("node-selection", onNodeSelected, panel, widget, wdx, wdy, wdz, wdx_ref, wdy_ref, wdz_ref) interPick.set_data("pick", handle) render.pushInteractive(interPick) render.pushMessage("Pick a node with the mouse") else: interPick.disconnect(interPick.get_data("pick")) render.popInteractive(interPick) render.popMessage() def onNodeSelected(inter, kind, node0, node1, node2, panel, toggle, entryX, entryY, entryZ, entryX_ref, entryY_ref, entryZ_ref): if not(kind == v_sim.InteractivePick.SELECTED): return data = panel.getData() (x, y, z) = data.getNodeCoordinates(node0) if entryX_ref is not None: entryX.setValue(x - entryX_ref.getValue()) else: entryX.setValue(x) if entryY_ref is not None: entryY.setValue(y - entryY_ref.getValue()) else: entryY.setValue(y) if entryZ_ref is not None: entryZ.setValue(z - entryZ_ref.getValue()) else: entryZ.setValue(z) toggle.set_active(False) def onDraw(widget, area, mplFig, panel, combo, (ox, oy, oz), (dx, dy, dz)): # We get the scalar field. it = combo.get_active_iter() if it is None: return model = combo.get_model() (field,) = model.get(it, v_sim.UiSurfacesFieldId.POINTER) data = panel.getData() # We setup the data to iterate over. orig = numpy.array(data.convertXYZToReduced((ox.getValue(), oy.getValue(), oz.getValue()))) vect = numpy.array(data.convertXYZToReduced((dx.getValue(), dy.getValue(), dz.getValue()))) norm = 1. / numpy.sqrt(vect[0] * vect[0] + vect[1] * vect[1] + vect[2] * vect[2]) vect *= norm l0 = max(-orig[0] / max(vect[0], 1e-6), -orig[1] / max(vect[1], 1e-6), -orig[2] / max(vect[2], 1e-6)) l1 = min((1. - orig[0]) / max(vect[0], 1e-6), (1. - orig[1]) / max(vect[1], 1e-6), (1. - orig[2]) / max(vect[2], 1e-6)) orig0 = numpy.array(data.convertReducedToXYZ(tuple(orig + l0 * vect))) vect0 = numpy.array(data.convertReducedToXYZ(tuple(orig + l1 * vect))) - orig0 norm = numpy.sqrt(vect0[0] * vect0[0] + vect0[1] * vect0[1] + vect0[2] * vect0[2]) # We setup the data to be plotted. a = mplFig.add_subplot(111) x = numpy.arange(0.0, 1.0, 0.01) y = numpy.arange(0.0, 1.0, 0.01) for i in range(100): point = orig0 + x[i] * vect0 (valid, val) = field.getValue(tuple(point), (0,0,0)) if valid: y[i] = val x *= norm a.plot(x,y) # We ask for redraw of the widget. area.queue_draw() def panelCreateSelection(panel, vbox, interPick, label, wdx_ref = None, wdy_ref = None, wdz_ref = None): # The line to choose the origin/orientation. hbox = Gtk.Box.new(Gtk.Orientation.HORIZONTAL, 5) vbox.pack_start(hbox, False, False, 0) lbl = Gtk.Label.new(label) hbox.pack_start(lbl, False, False, 0) wdx = v_sim.UiNumericalEntry.new(0.) wdx.set_width_chars(6) hbox.pack_start(wdx, True, True, 0) wdy = v_sim.UiNumericalEntry.new(0.) wdy.set_width_chars(6) hbox.pack_start(wdy, True, True, 0) wdz = v_sim.UiNumericalEntry.new(0.) wdz.set_width_chars(6) hbox.pack_start(wdz, True, True, 0) wd = Gtk.ToggleButton.new() wd.add(Gtk.Image.new_from_stock(Gtk.STOCK_FIND, Gtk.IconSize.MENU)) wd.connect("toggled", onTogglePick, interPick, panel, wdx, wdy, wdz, wdx_ref, wdy_ref, wdz_ref) hbox.pack_start(wd, False, False, 0) return (wdx, wdy, wdz) def panelCreateWidgets(): panel = v_sim.UiPanel.new("mytools", "Customized tools", "My tools") panel.setDockable(True) panel.attach(v_sim.UiPanelClass.getCommandPanel()); vbox = Gtk.Box.new(Gtk.Orientation.VERTICAL, 0) panel.add(vbox) lbl = Gtk.Label.new("Interpolate data along lines") lbl.set_alignment(0., 0.5) lbl.set_use_markup(True) vbox.pack_start(lbl, False, False, 0) # The line to choose a data field. hbox = Gtk.Box.new(Gtk.Orientation.HORIZONTAL, 5) vbox.pack_start(hbox, False, False, 0) lbl = Gtk.Label.new("Choose a data field:") hbox.pack_start(lbl, False, False, 0) combo = Gtk.ComboBox.new() combo.set_model(v_sim.UiPanel.surfaces_getFields()) hbox.pack_start(combo, True, True, 0) renderer = Gtk.CellRendererText.new() combo.pack_start(renderer, False) renderer.set_property("xalign", 1.0) combo.add_attribute(renderer, "markup", v_sim.UiSurfacesFieldId.LABEL) interPick = v_sim.Interactive.new(v_sim.InteractiveId.PICK) # The line to choose the origin. (origx, origy, origz) = panelCreateSelection(panel, vbox, interPick, "Choose the origin:") # The line to choose the direction. (dirx, diry, dirz) = panelCreateSelection(panel, vbox, interPick, "Choose the direction:", wdx_ref = origx, wdy_ref = origy, wdz_ref = origz) dirx.setValue(1.) diry.setValue(1.) dirz.setValue(1.) # The drawing area for the curve. hbox = Gtk.Box.new(Gtk.Orientation.HORIZONTAL, 0) vbox.pack_start(hbox, True, True, 0) scrolled = Gtk.ScrolledWindow.new(None, None) scrolled.set_policy(Gtk.PolicyType.AUTOMATIC, Gtk.PolicyType.AUTOMATIC) hbox.pack_start(scrolled, True, True, 0) f = Figure(figsize=(fig_width,fig_height), dpi = dpi) canvas = FigureCanvas(f) f.set_canvas(canvas) renderer = Renderer(dpi = dpi) area = Gtk.DrawingArea.new() area.set_size_request(fig_width * dpi, fig_height * dpi) area.connect("draw", mplCurveDraw, f, renderer) scrolled.add_with_viewport(area) # The toolbar for action on the curve. wd = Gtk.Toolbar.new() wd.set_orientation(Gtk.Orientation.VERTICAL) wd.set_style(Gtk.ToolbarStyle.ICONS) wd.set_icon_size(Gtk.IconSize.SMALL_TOOLBAR) hbox.pack_start(wd, False, False, 0) item = Gtk.ToolButton.new_from_stock(Gtk.STOCK_REFRESH) item.connect("clicked", onDraw, area, f, panel, combo, (origx, origy, origz), (dirx, diry, dirz)) wd.insert(item, -1) return (f, panel, interPick) # We create the widgets and plot the stuff. (mplFig, panel, i) = panelCreateWidgets() panel.show_all() v_sim-3.8.0/lib/plug-ins/python-gi/pygi_rightMenu.v_sim.py000066400000000000000000000077571370110300500235470ustar00rootroot00000000000000#!/usr/bin/env python # -*- coding: utf-8 -*- # vim: set fileencoding=utf-8 ## EXTRAITS DE LA LICENCE ## Copyright CEA, contributeurs : Damien CALISTE, laboratoire L_Sim, (2012-2012) ## Adresse mèl : ## CALISTE, damien P caliste AT cea P fr. ## Ce logiciel est un programme informatique servant à visualiser des ## structures atomiques dans un rendu pseudo-3D. ## Ce logiciel est régi par la licence CeCILL soumise au droit français et ## respectant les principes de diffusion des logiciels libres. Vous pouvez ## utiliser, modifier et/ou redistribuer ce programme sous les conditions ## de la licence CeCILL telle que diffusée par le CEA, le CNRS et l'INRIA ## sur le site "http://www.cecill.info". ## Le fait que vous puissiez accéder à cet en-tête signifie que vous avez ## pris connaissance de la licence CeCILL, et que vous en avez accepté les ## termes (cf. le fichier Documentation/licence.fr.txt fourni avec ce logiciel). ## LICENCE SUM UP ## Copyright CEA, contributors: Damien CALISTE, L_Sim laboratory, (2012-2012) ## E-mail address: ## CALISTE, damien P caliste AT cea P fr. ## This software is a computer program whose purpose is to visualize atomic ## configurations in 3D. ## This software is governed by the CeCILL license under French law and ## abiding by the rules of distribution of free software. You can use, ## modify and/ or redistribute the software under the terms of the CeCILL ## license as circulated by CEA, CNRS and INRIA at the following URL ## "http://www.cecill.info". ## The fact that you are presently reading this means that you have had ## knowledge of the CeCILL license and that you accept its terms. You can ## find a copy of this licence shipped with this software at ## Documentation/licence.en.txt. from gi.repository import v_sim from gi.repository import Gtk, GLib def onMeasure(item, marks, nodeId): if marks.setInfos(nodeId, True): v_sim.Object.redrawForce("rightMenu script") def onClean(item, marks, nodeId): if marks.setInfos(nodeId, False): v_sim.Object.redrawForce("rightMenu script") def buildMenu(inter, node): menu = Gtk.Menu.new() marks = v_sim.UiMainClass.getDefaultRendering().getMarks() # The default contents (single node case). if node is not None: item = Gtk.MenuItem.new_with_label("Measure node neighbourhood") item.connect("activate", onMeasure, marks, node.number) menu.append(item) item = Gtk.MenuItem.new_with_label("Remove measures from node") item.connect("activate", onClean, marks, node.number) item.set_sensitive(marks.getActive(node.number)) menu.append(item) # The user added items. for (lblNone, lblSingle, lblSelection, callback, kwargs) in inter.actionList.values(): if node is None: item = Gtk.MenuItem.new_with_label(lblNone) item.connect("activate", callback, None, kwargs) else: item = Gtk.MenuItem.new_with_label(lblSingle) item.connect("activate", callback, node.number, kwargs) menu.append(item) return menu def menuPosition(menu, (x, y)): return (x, y, True) def onActionMenu(inter, x, y, node): print node menu = buildMenu(inter, node) menu.show_all() menu.popup(None, None, menuPosition, (x, y), 0, Gtk.get_current_event_time()) # Define a right clic menu on rendering window. inter = v_sim.UiRenderingWindowClass.getInteractive() if 'actionMenuId' in globals(): inter.disconnect(actionMenuId) actionMenuId = inter.connect("menu", onActionMenu) # Add new methods to the interactive object of the rendering window. def addNodeAction(self, id, labelNone, labelSingle, labelSelection, callback, kwargs = {}): self.actionList[id] = (labelNone, labelSingle, labelSelection, callback, kwargs) def removeNodeAction(self, id): self.actionList.pop(id, None) # Add a list of custom action to inter. if not(hasattr(v_sim.Interactive, "actionList")): setattr(v_sim.Interactive, "actionList", {}) # Add methods to review this list. v_sim.Interactive.addNodeAction = addNodeAction v_sim.Interactive.removeNodeAction = removeNodeAction v_sim-3.8.0/lib/plug-ins/python-gi/pygi_rotate.v_sim.py000066400000000000000000000012161370110300500230630ustar00rootroot00000000000000#!/usr/bin/env python from gi.repository import v_sim import math, time render = v_sim.uiMainClass_getDefaultRendering() data = render.getVisuData() camera = data.getOpenGLView().camera (theta0, gross0) = (camera.theta, camera.gross) dumps = v_sim.dump_getAllModules() for dump in dumps: if dump.fileType.match("a.png"): format = dump NB = 100. for i in range(0, int(NB) + 1): data.setAngleOfView(theta0 + 360. * i / NB, 0, 0, v_sim.CAMERA_THETA) data.setZoomOfView(gross0 + 0.5 * math.sin(i * math.pi * 2. / NB)) v_sim.object_redraw("My script") #time.sleep(0.01) #render.dump(format, "rotation%03d.png" % i, 450, 450, None, None) v_sim-3.8.0/lib/plug-ins/python-gi/pythongi.c000066400000000000000000000631751370110300500210700ustar00rootroot00000000000000/* EXTRAITS DE LA LICENCE Copyright CEA, contributeurs : Damien CALISTE, Tristan BERTHELOT, laboratoire L_Sim, (2001-2010) Adresse ml : CALISTE, damien P caliste AT cea P fr. BERTHELOT, tristan P berthelot AT isen P fr. Ce logiciel est un programme informatique servant visualiser des structures atomiques dans un rendu pseudo-3D. Ce logiciel est rgi par la licence CeCILL soumise au droit franais et respectant les principes de diffusion des logiciels libres. Vous pouvez utiliser, modifier et/ou redistribuer ce programme sous les conditions de la licence CeCILL telle que diffuse par le CEA, le CNRS et l'INRIA sur le site "http://www.cecill.info". Le fait que vous puissiez accder cet en-tte signifie que vous avez pris connaissance de la licence CeCILL, et que vous en avez accept les termes (cf. le fichier Documentation/licence.fr.txt fourni avec ce logiciel). */ /* LICENCE SUM UP Copyright CEA, contributors: Damien CALISTE, Tristan BERTHELOT, L_Sim laboratory, (2001-2010) E-mail address: CALISTE, damien P caliste AT cea P fr. BERTHELOT, tristan P berthelot AT isen P fr. This software is a computer program whose purpose is to visualize atomic configurations in 3D. This software is governed by the CeCILL license under French law and abiding by the rules of distribution of free software. You can use, modify and/ or redistribute the software under the terms of the CeCILL license as circulated by CEA, CNRS and INRIA at the following URL "http://www.cecill.info". The fact that you are presently reading this means that you have had knowledge of the CeCILL license and that you accept its terms. You can find a copy of this licence shipped with this software at Documentation/licence.en.txt. */ #include #include #include #include #include #include #include #include #include #include #include #include #define PYTHONGI_DESCRIPTION _("" \ "This plug-in allows to execute\n" \ "Python scripts using GObject\n" \ "introspection.") #define PYTHONGI_AUTHORS "Caliste Damien &\nTristan Berthelot" #define FLAG_PARAMETER_INIT_SCRIPTS "init_scripts" #define DESC_PARAMETER_INIT_SCRIPTS "Scripts loaded on startup ; paths separated by ':'" enum { SCRIPT_LABEL, SCRIPT_PATH, N_SCRIPTS }; /* Local variables. */ static gchar *iconPath; static GtkWidget *panelPython, *pyFileChooser, *pyExecute, *pyTextView; static gboolean isPanelInitialised = FALSE, isPythonInitialised = FALSE; static GtkListStore *initScripts; static GtkTextBuffer *pyTextBuffer; static GtkTextTag *monoTag, *errorTag, *boldTag; static GList *history, *curHist; /* Local methods. */ static void initialisePython(); static void initialisePanel(VisuUiPanel *panel); static gboolean loadScript(gpointer file); static void addInitScript(const gchar *file, gboolean immediate, GtkWindow *parent); static void exportParameters(GString *data, VisuData *dataObj); static gboolean readInitScripts(VisuConfigFileEntry *entry, gchar **lines, int nbLines, int position, GError **error); static void _bufSetText(const gchar *text, GtkTextTag *tag, gboolean error); /* Callbacks. */ static void onPanelEnter(VisuUiPanel *panel, gpointer data); static void onScriptChosen(GtkFileChooserButton *widget, gpointer user_data); static void onScriptExecute(GtkButton *widget, gpointer user_data); static void onInitScriptAdded(GtkToolButton *bt, gpointer data); static void onInitScriptRemoved(GtkToolButton *bt, gpointer data); static void onInitScriptReload(GtkToolButton *bt, gpointer data); static gboolean onPyIO(GIOChannel *source, GIOCondition condition, gpointer data); static void onOutputCleared(GtkToolButton *bt, gpointer data); static void onOutputCancel(GtkToolButton *bt, gpointer data); static void onOutputGetData(GtkToolButton *bt, gpointer data); #if GTK_MAJOR_VERSION >= 3 static void onVScroll(GtkAdjustment *adj, gpointer data); #endif static void onInteractiveEntry(GtkEntry *entry, gpointer data); static gboolean onKeyPressed(GtkWidget *widget, GdkEventKey *event, gpointer data); gboolean pythongiInit(void) { GHashTable *options; ToolOption *opt; const gchar *file; VisuConfigFileEntry *entry; DBG_fprintf(stderr, "Plugin PythonGI: initialisation.\n"); iconPath = g_build_filename(V_SIM_PIXMAPS_DIR, "pythongi.png", NULL); initScripts = gtk_list_store_new(N_SCRIPTS, G_TYPE_STRING, G_TYPE_STRING); pyTextBuffer = gtk_text_buffer_new((GtkTextTagTable*)0); monoTag = gtk_text_buffer_create_tag(pyTextBuffer, "typewriter", "family", "monospace", NULL); errorTag = gtk_text_buffer_create_tag(pyTextBuffer, "error", "foreground", "Tomato", NULL); boldTag = gtk_text_buffer_create_tag(pyTextBuffer, "bold", "weight", PANGO_WEIGHT_BOLD, NULL); history = curHist = (GList*)0; isPythonInitialised = FALSE; options = commandLineGet_options(); if (options && (opt = (ToolOption*)g_hash_table_lookup(options, "pyScriptInit"))) { DBG_fprintf(stderr, "Plugin PythonGI: will run init script.\n"); initialisePython(); file = g_value_get_string(tool_option_getValue(opt)); addInitScript(file, TRUE, (GtkWindow*)0); } if (options && (opt = (ToolOption*)g_hash_table_lookup(options, "pyScript"))) { DBG_fprintf(stderr, "Plugin PythonGI: will run py script.\n"); initialisePython(); file = g_value_get_string(tool_option_getValue(opt)); g_idle_add_full(G_PRIORITY_LOW, loadScript, (gpointer)file, NULL); } visu_config_file_addKnownTag("python"); entry = visu_config_file_addEntry(VISU_CONFIG_FILE_PARAMETER, FLAG_PARAMETER_INIT_SCRIPTS, DESC_PARAMETER_INIT_SCRIPTS, 1, readInitScripts); visu_config_file_entry_setVersion(entry, 3.7f); visu_config_file_addExportFunction(VISU_CONFIG_FILE_PARAMETER, exportParameters); return TRUE; } gboolean pythongiInitGtk(void) { /* Long description */ gchar *cl = _("Python scripting"); /* Short description */ gchar *tl = _("Python"); GHashTable *options; ToolOption *opt; const gchar *file; isPanelInitialised = FALSE; panelPython = visu_ui_panel_newWithIconFromPath("Panel_python", cl, tl, "stock-pythongi_20.png"); visu_ui_panel_setDockable(VISU_UI_PANEL(panelPython), TRUE); visu_ui_panel_attach(VISU_UI_PANEL(panelPython), visu_ui_panel_class_getCommandPanel()); g_signal_connect(G_OBJECT(panelPython), "page-entered", G_CALLBACK(onPanelEnter), (gpointer)0); options = commandLineGet_options(); if (options && (opt = (ToolOption*)g_hash_table_lookup(options, "pyScript"))) { initialisePanel(VISU_UI_PANEL(panelPython)); file = g_value_get_string(tool_option_getValue(opt)); gtk_file_chooser_select_filename(GTK_FILE_CHOOSER(pyFileChooser), file); gtk_widget_set_sensitive(pyExecute, TRUE); } return TRUE; } const char* pythongiGet_description(void) { return PYTHONGI_DESCRIPTION; } const char* pythongiGet_authors(void) { return PYTHONGI_AUTHORS; } const char* pythongiGet_icon(void) { return iconPath; } void pythongiFree(void) { DBG_fprintf(stderr, "Panel PythonGI: finalise.\n"); g_free(iconPath); g_object_unref(initScripts); if (!isPythonInitialised) return; Py_Finalize(); } static void onPanelEnter(VisuUiPanel *panel, gpointer data _U_) { DBG_fprintf(stderr, "Panel PythonGI: caught the 'page-entered' signal %d.\n", isPanelInitialised); if (!isPythonInitialised) initialisePython(); if (!isPanelInitialised) initialisePanel(panel); } static void initialisePython() { if (isPythonInitialised) return; DBG_fprintf(stderr, "Panel PythonGI: initialise Python.\n"); Py_SetProgramName((char*)commandLineGet_programName()); Py_Initialize(); DBG_fprintf(stderr, "Panel PythonGI: import sys.\n" "import os;\n" "os.putenv(\"GI_TYPELIB_PATH\", \"" VISU_TYPELIBS_DIR "\")\n"); PyRun_SimpleString("import os;" "os.putenv(\"GI_TYPELIB_PATH\", \"" VISU_TYPELIBS_DIR "\");" "import sys;" "sys.argv = ['']\n" "from gi.repository import v_sim"); DBG_fprintf(stderr, " | done.\n"); isPythonInitialised = TRUE; } static void addFilters(GtkWidget *wd) { GtkFileFilter *flt; flt = gtk_file_filter_new(); gtk_file_filter_set_name(flt, _("Python scripts for V_Sim")); gtk_file_filter_add_mime_type(flt, "text/x-script.python"); gtk_file_filter_add_mime_type(flt, "text/x-python"); gtk_file_filter_add_mime_type(flt, "application/x-python"); gtk_file_chooser_add_filter(GTK_FILE_CHOOSER(wd), flt); flt = gtk_file_filter_new(); gtk_file_filter_set_name(flt, _("All")); gtk_file_filter_add_pattern(flt, "*"); gtk_file_chooser_add_filter(GTK_FILE_CHOOSER(wd), flt); } static void initialisePanel(VisuUiPanel *panel) { int fd[2]; gchar *string; GIOChannel *pyIO; GtkWidget *vbox, *hbox, *wd, *scrolled; GtkTreeViewColumn *column; GtkCellRenderer *renderer; GtkToolItem *item; GtkTreeSelection *selection; g_return_if_fail(!isPanelInitialised); /* Redirect stdout. */ if (pipe(fd)) g_warning("Cannot create pipes for Python process."); else { string = g_strdup_printf("sys.stdout = os.fdopen(%d, 'w', 0)", fd[1]); DBG_fprintf(stderr, "Panel PythonGI: run '%s'.\n", string); PyRun_SimpleString(string); g_free(string); pyIO = g_io_channel_unix_new(fd[0]); g_io_channel_set_flags(pyIO, G_IO_FLAG_NONBLOCK, NULL); g_io_add_watch(pyIO, G_IO_IN | G_IO_PRI, onPyIO, GINT_TO_POINTER(FALSE)); } /* Redirect stderr. */ if (pipe(fd)) g_warning("Cannot create pipes for Python process."); else { string = g_strdup_printf("sys.stderr = os.fdopen(%d, 'w', 0)", fd[1]); DBG_fprintf(stderr, "Panel PythonGI: run '%s'.\n", string); PyRun_SimpleString(string); g_free(string); pyIO = g_io_channel_unix_new(fd[0]); g_io_channel_set_flags(pyIO, G_IO_FLAG_NONBLOCK, NULL); g_io_add_watch(pyIO, G_IO_IN | G_IO_PRI, onPyIO, GINT_TO_POINTER(TRUE)); } vbox = gtk_vbox_new(FALSE, 0); gtk_container_set_border_width(GTK_CONTAINER(panel), 5); gtk_container_add(GTK_CONTAINER(panel), vbox); wd = gtk_label_new(_("Scripts loaded on startup")); gtk_label_set_use_markup(GTK_LABEL(wd), TRUE); gtk_label_set_xalign(GTK_LABEL(wd), 0.); gtk_widget_set_name(wd, "label_head"); gtk_box_pack_start(GTK_BOX(vbox), wd, FALSE, FALSE, 0); hbox = gtk_hbox_new(FALSE, 0); gtk_box_pack_start(GTK_BOX(vbox), hbox, FALSE, FALSE, 3); scrolled = gtk_scrolled_window_new(NULL, NULL); gtk_widget_set_size_request(scrolled, -1, 100); gtk_scrolled_window_set_policy(GTK_SCROLLED_WINDOW(scrolled), GTK_POLICY_AUTOMATIC, GTK_POLICY_AUTOMATIC); gtk_scrolled_window_set_shadow_type(GTK_SCROLLED_WINDOW(scrolled), GTK_SHADOW_ETCHED_IN); gtk_box_pack_start(GTK_BOX(hbox), scrolled, TRUE, TRUE, 0); wd = gtk_tree_view_new_with_model(GTK_TREE_MODEL(initScripts)); gtk_tree_view_set_headers_visible(GTK_TREE_VIEW(wd), FALSE); gtk_widget_set_tooltip_text(wd, _("This list is saved with the parameter file.")); gtk_container_add(GTK_CONTAINER(scrolled), wd); renderer = gtk_cell_renderer_text_new(); column = gtk_tree_view_column_new_with_attributes("", renderer, "text", SCRIPT_LABEL, NULL); gtk_tree_view_append_column(GTK_TREE_VIEW(wd), column); renderer = gtk_cell_renderer_text_new(); g_object_set(G_OBJECT(renderer), "scale", 0.75, NULL); column = gtk_tree_view_column_new_with_attributes("", renderer, "text", SCRIPT_PATH, NULL); gtk_tree_view_append_column(GTK_TREE_VIEW(wd), column); selection = gtk_tree_view_get_selection(GTK_TREE_VIEW(wd)); wd = gtk_toolbar_new(); gtk_orientable_set_orientation(GTK_ORIENTABLE(wd), GTK_ORIENTATION_VERTICAL); gtk_toolbar_set_style(GTK_TOOLBAR(wd), GTK_TOOLBAR_ICONS); gtk_toolbar_set_icon_size(GTK_TOOLBAR(wd), GTK_ICON_SIZE_SMALL_TOOLBAR); gtk_box_pack_start(GTK_BOX(hbox), wd, FALSE, FALSE, 0); item = gtk_tool_button_new(NULL, NULL); gtk_tool_button_set_icon_name(GTK_TOOL_BUTTON(item), "list-add"); g_signal_connect(G_OBJECT(item), "clicked", G_CALLBACK(onInitScriptAdded), (gpointer)0); gtk_toolbar_insert(GTK_TOOLBAR(wd), item, -1); item = gtk_tool_button_new(NULL, NULL); gtk_tool_button_set_icon_name(GTK_TOOL_BUTTON(item), "list-remove"); g_signal_connect(G_OBJECT(item), "clicked", G_CALLBACK(onInitScriptRemoved), (gpointer)selection); gtk_toolbar_insert(GTK_TOOLBAR(wd), item, -1); item = gtk_tool_button_new(NULL, NULL); gtk_tool_button_set_icon_name(GTK_TOOL_BUTTON(item), "view-refresh"); g_signal_connect(G_OBJECT(item), "clicked", G_CALLBACK(onInitScriptReload), (gpointer)selection); gtk_toolbar_insert(GTK_TOOLBAR(wd), item, -1); wd = gtk_label_new(_("Interactive scripting")); gtk_label_set_use_markup(GTK_LABEL(wd), TRUE); gtk_label_set_xalign(GTK_LABEL(wd), 0.); gtk_widget_set_name(wd, "label_head"); gtk_box_pack_start(GTK_BOX(vbox), wd, FALSE, FALSE, 0); hbox = gtk_hbox_new(FALSE, 3); gtk_box_pack_start(GTK_BOX(vbox), hbox, FALSE, FALSE, 3); wd = gtk_label_new(_("Load:")); gtk_widget_set_margin_start(wd, 5); gtk_box_pack_start(GTK_BOX(hbox), wd, FALSE, FALSE, 0); pyFileChooser = gtk_file_chooser_button_new(_("Choose a Python script"), GTK_FILE_CHOOSER_ACTION_OPEN); addFilters(pyFileChooser); gtk_box_pack_start(GTK_BOX(hbox), pyFileChooser, TRUE, TRUE, 0); pyExecute = gtk_button_new_from_icon_name("system-run", GTK_ICON_SIZE_SMALL_TOOLBAR); gtk_widget_set_margin_end(pyExecute, 5); gtk_widget_set_sensitive(pyExecute, FALSE); gtk_box_pack_start(GTK_BOX(hbox), pyExecute, FALSE, FALSE, 0); g_signal_connect(G_OBJECT(pyFileChooser), "file-set", G_CALLBACK(onScriptChosen), (gpointer)pyExecute); g_signal_connect(G_OBJECT(pyExecute), "clicked", G_CALLBACK(onScriptExecute), (gpointer)pyFileChooser); hbox = gtk_hbox_new(FALSE, 0); gtk_box_pack_start(GTK_BOX(vbox), hbox, TRUE, TRUE, 3); scrolled = gtk_scrolled_window_new(NULL, NULL); gtk_scrolled_window_set_policy(GTK_SCROLLED_WINDOW(scrolled), GTK_POLICY_AUTOMATIC, GTK_POLICY_ALWAYS); gtk_scrolled_window_set_shadow_type(GTK_SCROLLED_WINDOW(scrolled), GTK_SHADOW_ETCHED_IN); gtk_box_pack_start(GTK_BOX(hbox), scrolled, TRUE, TRUE, 0); pyTextView = gtk_text_view_new_with_buffer(pyTextBuffer); g_object_unref(pyTextBuffer); gtk_text_view_set_editable(GTK_TEXT_VIEW(pyTextView), FALSE); gtk_text_view_set_cursor_visible(GTK_TEXT_VIEW(pyTextView), FALSE); gtk_container_add(GTK_CONTAINER(scrolled), pyTextView); #if GTK_MAJOR_VERSION >= 3 g_signal_connect(G_OBJECT(gtk_scrollable_get_vadjustment(GTK_SCROLLABLE(pyTextView))), "changed", G_CALLBACK(onVScroll), (gpointer)0); #endif wd = gtk_toolbar_new(); gtk_orientable_set_orientation(GTK_ORIENTABLE(wd), GTK_ORIENTATION_VERTICAL); gtk_toolbar_set_style(GTK_TOOLBAR(wd), GTK_TOOLBAR_ICONS); gtk_toolbar_set_icon_size(GTK_TOOLBAR(wd), GTK_ICON_SIZE_SMALL_TOOLBAR); gtk_box_pack_start(GTK_BOX(hbox), wd, FALSE, FALSE, 0); item = gtk_tool_button_new(NULL, NULL); gtk_tool_button_set_icon_name(GTK_TOOL_BUTTON(item), "edit-clear"); g_signal_connect(G_OBJECT(item), "clicked", G_CALLBACK(onOutputCleared), (gpointer)0); gtk_toolbar_insert(GTK_TOOLBAR(wd), item, -1); gtk_widget_set_tooltip_text(GTK_WIDGET(item), _("Clear Python output.")); item = gtk_tool_button_new(NULL, NULL); gtk_tool_button_set_icon_name(GTK_TOOL_BUTTON(item), "process-stop"); gtk_widget_set_sensitive(GTK_WIDGET(item), FALSE); g_signal_connect(G_OBJECT(item), "clicked", G_CALLBACK(onOutputCancel), (gpointer)0); gtk_toolbar_insert(GTK_TOOLBAR(wd), item, -1); item = gtk_tool_button_new(NULL, NULL); gtk_tool_button_set_icon_name(GTK_TOOL_BUTTON(item), "edit-find"); gtk_toolbar_insert(GTK_TOOLBAR(wd), item, -1); gtk_widget_set_tooltip_text(GTK_WIDGET(item), _("Get the current VisuData object as 'data'" " variable and the current VisuGlView as 'view'.")); wd = gtk_entry_new(); #if GTK_MAJOR_VERSION > 3 || (GTK_MAJOR_VERSION == 3 && GTK_MINOR_VERSION > 1) gtk_entry_set_placeholder_text(GTK_ENTRY(wd), _("Python interactive command line")); #endif g_signal_connect(G_OBJECT(wd), "activate", G_CALLBACK(onInteractiveEntry), (gpointer)0); g_signal_connect(G_OBJECT(wd), "key-press-event", G_CALLBACK(onKeyPressed), (gpointer)0); g_signal_connect(G_OBJECT(item), "clicked", G_CALLBACK(onOutputGetData), (gpointer)wd); gtk_box_pack_end(GTK_BOX(vbox), wd, FALSE, FALSE, 0); gtk_widget_show_all(vbox); isPanelInitialised = TRUE; } static void onScriptChosen(GtkFileChooserButton *widget, gpointer user_data) { gchar *file; file = gtk_file_chooser_get_filename(GTK_FILE_CHOOSER(widget)); gtk_widget_set_sensitive(GTK_WIDGET(user_data), (file != (gchar*)0)); if (file) g_free(file); } static void onScriptExecute(GtkButton *widget _U_, gpointer user_data) { gchar *file; file = gtk_file_chooser_get_filename(GTK_FILE_CHOOSER(user_data)); g_return_if_fail(file); g_idle_add_full(G_PRIORITY_DEFAULT_IDLE, loadScript, (gpointer)file, g_free); } static gboolean loadScript(gpointer file) { gchar *script, *label, *name; GError *error; DBG_fprintf(stderr, "Panel PythonGI: load script '%s'.\n", (gchar*)file); g_return_val_if_fail(isPythonInitialised, FALSE); error = (GError*)0; if (!g_file_get_contents((gchar*)file, &script, (gsize*)0, &error)) { if (error) { visu_ui_raiseWarning(_("Load a Python script"), error->message, visu_ui_panel_getContainerWindow (VISU_UI_PANEL(panelPython))); g_error_free(error); } return FALSE; } name = g_path_get_basename((const gchar*)file); label = g_strdup_printf(_("Load script \"%s\"\n"), name); g_free(name); _bufSetText(label, boldTag, FALSE); g_free(label); PyRun_SimpleString(script); g_free(script); return FALSE; } static void addInitScript(const gchar *file, gboolean immediate, GtkWindow *parent) { GtkTreeIter iter; gchar *path, *name; if (!g_file_test(file, G_FILE_TEST_IS_REGULAR)) { if (parent) visu_ui_raiseWarning(_("Choose a Python script"), _("Not a regular file."), parent); return; } path = tool_path_normalize(file); name = g_path_get_basename(file); gtk_list_store_append(initScripts, &iter); gtk_list_store_set(initScripts, &iter, SCRIPT_PATH, path, SCRIPT_LABEL, name, -1); g_free(name); if (immediate) { loadScript((gpointer)path); g_free(path); } else g_idle_add_full(G_PRIORITY_LOW, loadScript, (gpointer)path, g_free); } static void onInitScriptAdded(GtkToolButton *bt _U_, gpointer data _U_) { GtkWidget *dialog; gchar *filename; GtkWindow *parent; parent = visu_ui_panel_getContainerWindow(VISU_UI_PANEL(panelPython)); dialog = gtk_file_chooser_dialog_new(_("Choose a Python script"), parent, GTK_FILE_CHOOSER_ACTION_OPEN, TOOL_ICON_CANCEL, GTK_RESPONSE_CANCEL, TOOL_ICON_OPEN, GTK_RESPONSE_ACCEPT, NULL); addFilters(dialog); if (gtk_dialog_run(GTK_DIALOG(dialog)) == GTK_RESPONSE_ACCEPT) { filename = gtk_file_chooser_get_filename(GTK_FILE_CHOOSER(dialog)); addInitScript(filename, FALSE, parent); g_free(filename); } gtk_widget_destroy(dialog); } static void onInitScriptRemoved(GtkToolButton *bt _U_, gpointer data) { gboolean valid; GtkTreeModel *model; GtkTreeIter iter; valid = gtk_tree_selection_get_selected(GTK_TREE_SELECTION(data), &model, &iter); if (!valid) return; gtk_list_store_remove(GTK_LIST_STORE(model), &iter); } static void onInitScriptReload(GtkToolButton *bt _U_, gpointer data) { gboolean valid; GtkTreeModel *model; GtkTreeIter iter; gchar *path; valid = gtk_tree_selection_get_selected(GTK_TREE_SELECTION(data), &model, &iter); if (!valid) return; gtk_tree_model_get(model, &iter, SCRIPT_PATH, &path, -1); loadScript((gpointer)path); g_free(path); } static gboolean onPyIO(GIOChannel *source, GIOCondition condition _U_, gpointer data) { #define size 256 gchar string[size]; gsize lg; GError *error; error = (GError*)0; /* DBG_fprintf(stderr, "Panel PythonGI: receive buffer data.\n"); */ if (g_io_channel_read_chars(source, string, size, &lg, &error) != G_IO_STATUS_NORMAL) { g_warning("%s", error->message); g_error_free(error); return TRUE; } string[lg] = '\0'; /* DBG_fprintf(stderr, "Panel PythonGI: got\n%s\n", string); */ _bufSetText(string, monoTag, GPOINTER_TO_INT(data)); /* Flush Gtk events. */ visu_ui_wait(); return TRUE; } static void _bufSetText(const gchar *text, GtkTextTag *tag, gboolean error) { GtkTextIter iter; gtk_text_buffer_get_end_iter(pyTextBuffer, &iter); if (!error) gtk_text_buffer_insert_with_tags(pyTextBuffer, &iter, text, -1, tag, NULL); else gtk_text_buffer_insert_with_tags(pyTextBuffer, &iter, text, -1, tag, errorTag, NULL); } static void onOutputCleared(GtkToolButton *bt _U_, gpointer data _U_) { GtkTextIter start, end; gtk_text_buffer_get_bounds(pyTextBuffer, &start, &end); gtk_text_buffer_delete(pyTextBuffer, &start, &end); } static void onOutputCancel(GtkToolButton *bt _U_, gpointer data _U_) { DBG_fprintf(stderr, "Panel PythonGI: try to interrupt.\n"); PyErr_SetString(PyExc_TypeError, "script interrupted."); } static void onOutputGetData(GtkToolButton *bt _U_, gpointer data) { DBG_fprintf(stderr, "Panel PythonGI: get current data.\n"); gtk_entry_set_text(GTK_ENTRY(data), "scene = v_sim.UiMainClass.getDefaultRendering().getGlScene()"); g_signal_emit_by_name(G_OBJECT(data), "activate"); gtk_entry_set_text(GTK_ENTRY(data), "data = scene.getData()"); g_signal_emit_by_name(G_OBJECT(data), "activate"); gtk_entry_set_text(GTK_ENTRY(data), "view = scene.getGlView()"); g_signal_emit_by_name(G_OBJECT(data), "activate"); gtk_entry_set_text(GTK_ENTRY(data), "selection = v_sim.ui_interactive_pick_getSelection()"); g_signal_emit_by_name(G_OBJECT(data), "activate"); } #if GTK_MAJOR_VERSION >= 3 static void onVScroll(GtkAdjustment *adj, gpointer data _U_) { guint oldUpper; oldUpper = GPOINTER_TO_INT(g_object_get_data(G_OBJECT(adj), "old-upper")); if (gtk_adjustment_get_value(adj) + gtk_adjustment_get_page_size(adj) == oldUpper) /* Scroll to the end. */ gtk_adjustment_set_value(adj, gtk_adjustment_get_upper(adj) - gtk_adjustment_get_page_size(adj)); g_object_set_data(G_OBJECT(adj), "old-upper", GINT_TO_POINTER(gtk_adjustment_get_upper(adj))); } #endif static void onInteractiveEntry(GtkEntry *entry, gpointer data _U_) { _bufSetText("> ", NULL, FALSE); _bufSetText(gtk_entry_get_text(entry), monoTag, FALSE); _bufSetText("\n", NULL, FALSE); PyRun_SimpleString(gtk_entry_get_text(entry)); history = g_list_prepend(history, g_strdup(gtk_entry_get_text(entry))); curHist = (GList*)0; gtk_entry_set_text(entry, ""); } static gboolean onKeyPressed(GtkWidget *widget, GdkEventKey *event, gpointer data _U_) { if (event->keyval != GDK_KEY_Up && event->keyval != GDK_KEY_Down) return FALSE; if (event->keyval == GDK_KEY_Up) curHist = (curHist)?((curHist->next)?curHist->next:curHist):history; else if (event->keyval == GDK_KEY_Down && curHist) curHist = curHist->prev; gtk_entry_set_text(GTK_ENTRY(widget), (curHist)?(const gchar*)curHist->data:""); gtk_editable_set_position(GTK_EDITABLE(widget), -1); return TRUE; } /**************/ /* Parameters */ /**************/ static gboolean readInitScripts(VisuConfigFileEntry *entry _U_, gchar **lines, int nbLines, int position _U_, GError **error _U_) { gchar **paths; guint i; g_return_val_if_fail(nbLines == 1, FALSE); DBG_fprintf(stderr, "Plugin PythonGI: initialisation scripts.\n"); initialisePython(); paths = g_strsplit_set(lines[0], ":\n", 100); for (i = 0; paths[i]; i++) { g_strstrip(paths[i]); DBG_fprintf(stderr, "Panel PythonGI: test file '%s'.\n", paths[i]); addInitScript(paths[i], TRUE, (GtkWindow*)0); } g_strfreev(paths); return TRUE; } static void exportParameters(GString *data, VisuData *dataObj _U_) { gboolean valid; GtkTreeIter iter; gchar *file; g_string_append_printf(data, "# %s\n", DESC_PARAMETER_INIT_SCRIPTS); g_string_append_printf(data, "%s[python]: ", FLAG_PARAMETER_INIT_SCRIPTS); for (valid = gtk_tree_model_get_iter_first(GTK_TREE_MODEL(initScripts), &iter); valid; valid = gtk_tree_model_iter_next(GTK_TREE_MODEL(initScripts), &iter)) { gtk_tree_model_get(GTK_TREE_MODEL(initScripts), &iter, SCRIPT_PATH, &file, -1); g_string_append_printf(data, "%s:", file); g_free(file); } g_string_append_printf(data, "\n\n"); } v_sim-3.8.0/lib/plug-ins/python-gi/pythongi.png000066400000000000000000000037301370110300500214210ustar00rootroot00000000000000PNG  IHDR szzsBIT|d pHYs B(xtEXtSoftwarewww.inkscape.org<UIDATXŗ]]UsfgKK˔R;BT7J4hH AB0*B`5}>H|QJM(H@aJ0mq:y{{-rK[Zēsg_+{o13WypŎDfXկ2T {tɳe?z\sU`?now#W^@o '=j7FGƼa_!uX?؍Wy9yƁ*U^GFD--5ắ>pMcp3B0\s.A A˷21R%8oq~;w}'W]a/ݽ6gT`䋥|͵ VJ>8uNI:d,qq^IgIwҷse%`rg.`wJjĩ'՚gMύ( ̌L Q93 ײl'78-@2߸hܡ 3Z#e6A)uUjip`~ JKcONDʦM@tyGљ:fU#Rzbl_| z17o`'1?qrKAY{W)tG8wlW=)BH)O15Q{mzsc{6b`Xa6rԹ-f&jq"μ,&zxGK/"6cF` Ј@2SRp5N"ΗaF#;Wwd&o2u%t__`!9,ZA8j"OPk[ʵZmi.j yO;{.X(Ec f)htso0Uσ1إ`߶i-ltrzRj-exG`1SXQ/ja6F+%tQ/O;O꼓#z;s-Gi\Mbt xvq 0c!gzߵ$gXI!Le~3e.yC ̃H8)bε2<3U#h}>!LfB \v5Q7%) f %s~y,>#]S8?v믙BEEdMHEx\;-0Gر!]|~ )",y|&Ão(]$)HAD2@ݯSR3"9L6rp60Oy싘(V$mc"" B |1rsW]Sg k.nK9>~W-"`+٤z@NH-Bk z18vXʓY4MiT*LkT?f[veC@О}@n}\3cuXQI[֫Dq‘v@q"&-+@mׯ,ih}kF$fvQKL 8ϴbnX>يzt,"S[y?OayIENDB`v_sim-3.8.0/lib/plug-ins/python-gi/stock-pythongi_20.png000066400000000000000000000015131370110300500230400ustar00rootroot00000000000000PNG  IHDR sRGBbKGDC pHYs  tIME  ""ptEXtCommentCreated with GIMPWIDAT8ݔOUu?;or,Gg,3(Ibh$vRPleL0BA"ADS,W5{h{-Z9;<\1(qpC|b箕41>"L=9si@AvZgon^B/xi-kSز+l]yF9zA&(tcr W;mF}&5erb΅_^|$6h ?i6B<|S22>&6850_CgMAî| >m>7BӋayS\1P뿇=vPEpo+0W+UPv0WsgRᗗ~BD}V;4;4>b #QQ)[Nc7eЂjI B |Db=襹[:=BѐPcL[[ @MϑjEטpȮtw65sSOTPo;k b~>B@()*P@(PART@ ("P( ((@P  (( (P@@ PBP (*%) m1PC,6֘ ыAX46 " {[[l6[j`Mɑ--VE֩mmTֶJ@¹@G Z *ZGZe:i@QtEբkUH*[fkVUV4͢SL*iBP24ĭ Z 58jke4fjmҶeCf`h۔LJV  *k23ْCZS-F@iPuͅXm0Z r VpmZKk b1L ؖFյX-T4weQHe(KE mlܺkN⠐ 2dfm6T.#͓km]4mf*U6j̲ՃEUУYs6+Z+!lQ-[m3bzsbSDeH1]DI&Z6fЛ3Pq'm^* ئYYG[S bBMWlڂ͘eE"է]l3WSʚ͊fZ4֎v(nxTM II [fVfF"2[dnuǯA+J{0tQY6m3[bZ1 "mtd햙%3mV͚T>Nr40Fm hfIVڙ`m65 YjliXFٶm6ڶf6 1mֆR heRVSMQ+#Ƭڪ mJmB-QJҖX [+6ի6m *lŲ$[Z3[c 4h)i[m+*Bث[ZmZ²V6͍Rjl +mk+LDmZk56eSZRK*-e[SmdaڶRjbj2-YJfѶCKYMSCQh-*fF)Jc$VMcl6M&ͲeYle- [UHY-HZhYQ- 6ƪj**mjVچT X-1!UUkBZ6ւ3LcmF[%VզUlڦͤU"#EV0mVֵZ5SeUT~L$&0?I0d=@j)J ! =Rި4zBI$H`ne-@ (7˾gjRQb)Q__7yahHɩ $#E ^~m4J14cbH(̍ʻ>+4[k>^UDQh}mZQX$ٔwA,Tl4chϝ5$@QDhh_/obQ"A21oo~WFRm*M|dd"lFǟ}{s=Z-EcQ&m-ѴE&MDHZ/ƢTTXf*6V(߷Z(-|h$DFf+=MlXFIHE)!&k&7jѨh-{zE`l,Xk=_+X5AEZ+oIZIQ%^>y|jJ E6LV*4^3#!ƒ򼍾6Kk#b 66{|c(mŴjjWƋDQ#hHhFϟ7Ɋlj{ﷺj(hbA5߿~kZ+Eh"26J1+Ծ3ZE`|!6TdňϛR$2[*_6`+󶷋k"+uWIXՂAUߵ_VBd ( =6IH j@PwVHbţ{_Fhڋ}nj+b<-mF(4j6Q[1mF#5`Hn5[ƶ" ) 6@ dw)EiEt זBerRQRAV8I1 ;|nh׵tR$%%_].NS7W,[Wk]\c"D@6w"vnWuuD]wK+\dH0닮97;KsvNGw7$w;.]ˢؒҎd9E.ruwHm~b !eQ_b2H`DX.@pZTږV1JT J6j%j -mKLNi9r1UhmZRBmR]%hW9%$ݗnG.n[Im[IKV,m%_<72E1;h"$d6 ((0ӻwwwsn\9vrtnttLu;W# gw.뻗qr㝝YU[J ҶVRwvnnrܻ-@m)Jim*Uhp.mӻ{~<.=2vr.y9vJ\]ʿ5JfKE!\'.gupFn뻺"9#Εwv.sr㒅\M"9.s]q.\'v.r9BV-edB ԵҠڕZ+LחhwrUȯ6HTXΜw]݂ͺcEΛ$wp;9lN]Ћ9PR]݉*Em*-jJpwW.w\IN%w\Guws9LN]˺;MQp%~GbڊcH %Dc\s;twur]5·SQIћ#$JeeZR)lkJ`u\ N˘Ƨ.r\Lpw[Pp6uԚ9˻ 4mh|f?U0_C*[:#'%\ŦRE"4iCdN\;3ܷNeݝub5s+.EEܝ]껻]tt ӎQrvQwsr,,JZPieA-Y*(jEFPi@dUmm}֟Ilw6[ɷkl,D`RŞv`[Q+ZR :똫WtbZRijTV m@oXM9ۻ \tλۜ#DG ֎\w;9Qt\+r]]NY۹ќsK|Č5>0QAn 9kmXjVT[h)YRmm VQ-k*`\ݻ˲nQuq\.+Xd)K RZQnҙږږڊ4mHRjڴhmBVU`OgP[ $Kߓ Y^Nmq*wAP]s]uq)ӠܮE˻5s:Z;wdNw8qvNQ˔˺ܱwrw[w)빮GݻU䑨6ɸsrU]ι**W-Q Ys~cbMY5HjwlW+ swupRQJim*NƇ;r;ܝ˹']tEr ]1Χ]v'3&H5i΁&Ze2m_ݞ7iw\,]lJ")*0En\.ݮйpn+[].\ҒՕjU-U[V%))mk[j˺ݙt]r˻ȱndvwEr 6|}P[-TZm&ƤlLHӺ;S[' 07;:%\ۄCw]D]-3N#sX5N[dn[A7w.sG.7nAber*ss%A(iʶ:_{y7r5Lf5`U<6 nmw;s7wHn.rttr\uƹF wu \]ܨݤn9pgu9;n㛜ƹ3ks\:ar)wfAnS;wnwv軷7Bi42(?J;W9W[-&U&ƤlFFhpb볝tefWuu;\tD)n.Mup+#rF.HY(cr".t#vnwLr5vW8Ww`+J+sq$kŋw---6Z6 @2j#IT橔Ewvtt;;v],nG(F7L5Ӕj哀lG5rȫ5йE'9ѮZ]q%s͎h.܍\ 5˥5(wth.nnUsq/l ej(k4 FkˮW79WwD˻;Is\ ҈.\ܮanDl묑sTcn'Nm\ܔN5.\wr7J8bw;.\w۔\EŐM4\N1pW\r):8FV«(*~2._lu,ػ\hbѲ ,TTVyv]ݨMwhwF Βwr9NK.u90F2sΨ$]5㩗 κw7.;p;X]t65W#F~߈M|r;o[%E!FeQsr, w]ˮE"Qvn]\IA$.[")%5`Dk]sPut1wP7+ƮW t&#]vwvnQIwvtFM۟|<.)mmYR,"iRmwKvwthbwt.\,WwXnsssۻDAC"srB̉] Q+vst6KuEp4\%su: q˺웥rC5XKsş|,-IA2LYKcoŠm&,EG:]Q,ڒTDU&JsIW($M7McnQQhmp5i rt!\,mr!C 9] s pw].sgآܹ8Ea~>>~3/S½ߊQX6`IkxmF52-,wuĉΛѫܹEw]6 79Erir4뻻tɹnZ:]UAE.q".rs\1hӻMwqZwW4Zv6v븊wtH5|h>aY.v7Z# ƍXŒots5®Z41\M&7JQWK#F,d䑧v;]s75Ȅn5;-kkttQ\&rrcW1.Pm73#duumcRt<<3D*}z( sa;HhܹcX9b.bF\skܫїun'].Zwk775q4\wD&+\wW.V;GuVAnFa)-w\幺V79˕5XmH| y[-w+b ej55Z1Wݷ,tFIk sw;+Iۗ(ܹɔܻ6MMrF!J"bstgunhu.@iط"g;`srqHj'w#fAAbU{m2(4)񜝣Mo,TUiMFѴ^Cwuιs sw:ܵuQg9M –"n˦4d swwwk˷9kI\1k]&:D-Xq`خ,\.79r6Si+o%k[(Ѩ4Z 7fKu]6ۤt4m8Q7B:q6wnF'75E\%th\ᨌjKQݮXu5 \%j~~ɂw8.]ݮ6EhVB7 Ni(wqrwF\.7+hs˥spḐh\wTFa1`nfWfѹQ[9WwF:N䣦j9LbwX9q9\_&mDhbѣ%XnG rѢ;vhaݮnt\X'uÛrY.n\ܹwu;lQs3bI7Nʊt2]cds]v-tݮ9b5;k%$[]ye:'@Ymx h4Nk,Q#Qq.crwW"lVj6FttUԍ w$wr.PQQh65sw]tuMrXӻvr%ەE~߼JSrWm~VJXhּ[rMwQ\ۥQ\;D%WMr(N,1ۜd(wRErܺU.(L2Aˆww;ErpWwwuܹ\nӺ(DV._/ûno0̺kbѢŬQ 75t܈4Usb) ˗(ţ#b*2(Ҹnsc\r5w\W E۔ Tݹ6wcDQ#W-͢cb1&@Hߣ$ѿe ]WcXXlj(Սy%YhZL`uervnww,c2\"5tԆMkc!5p*+&w]۷P(s8gv,ݚˮuw;\wkRW7 XlXh~yEz&9k6DkEMO;RIs$[1j mI"*-\ڍQcEP9ܮV4mΚ*  H5rH5hPM;rF7wQPmp$A_~*J\nUmcx ̚ԋ61ܹcT2\@J[\9Mrܮ&lw1N%;sp\"b1wwwQsmͮ\wV\L5XG~f#u^.6EQlZ;@sA(Ecrۄ]6չ#g84VTcs̷tE'9F9qήQdDps\&FscƎs9(FݤS1j{wB}4ZIjTj1*- 6m$*EE&94*DljI),&.kpb23"N\EG.E2Ei01+mJU֋m)"hd(b)1i($E jă4Ib-wonkUE)5cb(#N\bTZ55ȱIe#QhalQbb%Di=׫{}W'V%6"AFMAMHAdS"V6M@Eb)7]+'4@C|mC(TmQD IQ&hJ\ELJI4b )DʋFߋ~Zڼ`"]#&sR[S"rqcW-sEW61I1cY1nruT*O6|'>db@mŹ LQ4b hbrM FXr*LAbʼn6\#կ&Eci0QlQس QkҍIh("b=MܶRFQm!\-A&4 skd565eQ?w߫w'_`C.[C- 6%AhbhL Ɖ,Fэcb(~OzkoͶlQPIdƍRhtɢm#+`vZ6Ѳ3M&&Z'@@bzKEF\j(1 KܢIiS)Ŋ1F0`0[_~~5{rU) *#FƤrLEW9bhm)D!EQҚ^?]PT%Z6F(j#Q\ܬXܹkKr!Ec_~{WU$i*4VHF#F1X cEIQXd2 DV &i~hTP~a*QlFEI-b,Fb(XQLcF6ݼb^޶Zۅ!c1-FYTl4h`(`rɒNѳ^׭õ}\T hERjf-EXb1Q\pu=9ZMؤ5!ѢTkmksfBF$Z 5_aּXЋPQd,I*,Xr1Iđ5d}wk~C,W( FЕIb*L1ƒF}YmtѯU֒Ѡ$hHڊCE ͵m09\,bmxr*15RfT`#"2i#S#%1*({^U: \I4`EDܺQPj"6-F,dW~ֱ 0%XZ2XV5c$h${^{Ob ^ߛjF4V5ζ#&&chLQcRRY1F!(5~|zm^(5h&"LEFm)1Y+s~~v1si4-h51cPElbDd9$IETA L41F4j"4", =$` P,2 EdFŨ0QȋEPhؿr{A4 !&d&F5KQH$lo=1WJ&5%FXm%v5XE"]A_⟌[hɭ&M"L~vb*(r뭫**2E5IRcP-4E~^}^bEE*"J5b,-cb$M^-|W#QQcA1m*4aQRNuq$*,KzMEQ$`Hɨ1TP__}bnjfchh4%h1E; ~e޺w6Rj66"@0j 5D&^Z(K_JmJdbĐDIY#&Ō&ƍb_k|϶ ѣEhmֈLb#D_{\jnkkdh-ٕ% +$2A#A {ͽv1#lF،cS(d@XƢ+}ןb5OZ"4Z(mdlVaj6׷kԵ")#QB_Dm{s^|m%MRQ(q'LHh APlQlj)=~ֿWQAhF4T&&Ǿ{"\Eb,h+ccL5Bmܯ[E$X-LF1bcn7{+} E,IF4F}߻{rIknhLPQQ@h#`c}־$؍b%wWƿwlb- m_oփHF6lhѤѡ`mᢪH"5Qhh6%_-O1i(ض7 *(,XF#i=CwָMi*폵;*)* ( o}׷WݬX,hc"Z4T3{WmWLFœQEF V1ϻwطݫ4RFcF"E3}{65hōQo{OKU,llh2DY#F6}'}s6P2 fsݹ[Dc$Ϻs͟-dImFAP%b$IV,$W۾b6(#2%߾QƠƟ>WOϚ&Qj5h!V5F`6M_}M{mIXԑQF4c_j$bƌDb5$i7ωl"E}o~nE"1h_wϸ_kdɤňJ-{^nXQF u{}ouPhj)ﷷuF65DU$Z{oumz6)"4U^TZ(fPŏt:c'H P^Y(Qw'},XѶ$ NX[{w/uXo~={{p1bJX#>[|ƈ(X5}S)DKI2"%|;-DU&顄 dAd'ۙ}ѱb(ooQ-4X1}{ݷb6|^QWJ* y}> *q:K,h"Q{owtXbJ okp6H#_/n^ o{׊{_jfbƈ/}mF*}}t$,RinwOY(*1:$EF}(kx62P b}}G&` DCǻ{^u0Jf]h 'mF !PXP)3GH((1Q;PqQdE{&0 #b5ouōϹ}ʂ c$F/oQ}sbbCq!P "vaD(=1Ѣ{"^yJ-g )Zx“6- {Wb(Wpk q݇4h(}G"23:o+Y8IDFM}^/A'T^!D",qМ0L{FUa7q& bEUL(H"M%, 4:Qb Ӹ"Q ^;TbqOAE]aE*$٤E7zV( Md5"3T6IXӍzq1vPG2hbE)41 /wf׎Qv1ghbhi&$xV ;php2H*ȱNN!Qb'N:Ƞ'pppq99gLbpt\N[hDf45U 0 1cM1H:LQit۠T*$N:+Ct4#""i $F&ɛDQCno݉3vl@P{b׺L"NM`;TJu`l`:Tw *28.H:c:vpwq$f+I&LM P]w`#6 TY8^@ ܲcXv,{y1UQ!y4Wd*4䉑* ٪ /^ScEJS!E iɡ͚La5vCwf*(; *mGf6ёdp 'MAEo 4Уf6;SӧsP8LئM㻺Eݛ!P8Ҋ1^M噁Lbͫ (h8(8,ˊ &+'N3:V 5 &nx`fc#a7cӂ)7C4QDUɆ 2n+@M3WM7j i!^s^绞Iίw4vn$5/(q `̙Ī6#:hLfu& 3t 0lR{8* 7XOBؠWcv C;*v;4R/q3n6r(s &CqxMcvCQJš tN1B7kҚbit SMSj𮋱Jf3%vhsv5!cgpb;㗅!N8_7Hq8>M3M -'fIcta+;!XegWꊏvty袨wnaL\fΜk;Iba CM Eמ H\ɂ/wNN3qy9&J\@Le@_t a(*ES{4S7Ɠwq7fYN;gxP(wO{=9X%w@ĚiIƙ5Y}aKDOx0̞7f$wӘ|q!{ִS(VsuツaW]NgWN8mxTo$<+ Tw`rwfΏc״`ٷuj>: &|q+};{k=sG}0|^t^r,49 _{a0ޛ]AB%D{ǵ^4.0|n;=xp¨^jLJ^zXMM^1"_ӊ5lw{| T>40 qb,Y&"$w}: <%v&esM5VGoGaP,zPtɨ(7J<<1[a;G;";&puQ7c4q[K௽'^twtXsťDlPO{{*&')6кi&5qԳg$X6-îmk;&'`>ƂitꓑV֎4\(=x- (z}:NE{875@^=QEնxS5\.aRr(Ư }r*>xFk8}=b°]7XU/N)Q3]178|7Tx] rBZ}k>(rz[){Ȩ6  ښf 'T ZZ}sX-2O]T5(}==RyiܵduLڏ١hK>hdk%L2qr1n5-N렪Ghn3.qTT^;MJ4Jlۅ] Å'Q~ > NQWKW V0b ]zWR]FMDg1mo T1K[Fq[NjΈ٩P+Km6AxvVfeNNWiY.6F{VU>LMԪwMpJ;mhonQb!*6Cث1vs=^ҷAhaSTnIU7N٣J%[ `cPT{[:Т]mli1XѷMbBvԨp#m{3RgiQxU,cw1y-`c|oDӔGL+ ֨3ÞdB1.u緾<s넣9\tjLS%п{G*yD~x|ZV[4bo;ȦlLMEtLf%YWSBFS㶍 Ds)+KgWQKJVҕ'k0DU YjB"[iE[JQ1sk>|K}!#J655eAJhTEƶmTcmn`3Kkh6VF"Yc[j**")'up۝zH0-Bqu6*X*+[dA%T[%eXs)maQr;tKV´Sc8UaaKhre Vdk{nnV/}>Lm6m_~F><Qn<-BF1*VLYh]+/!5ZVxȭEA{[BP.h`v%m` mam;ؔKwsyypbK[hWoPᅶ%J#kSF"Ѩlaw\Y4nR<.;4Q1me@ǧQjUJ"ʊ 9qklQڍ26+1- *'{0ڶ-4ͼBJ/7/8u\r>S@.uw]ӕQQ,xaEHul9UmX֗>锵`UV++QKfQQQV+9chU "겊ZP-mId91Š[eī~gV 1V[AmKǷ)ȡb DؗqS7r[[2ĪįsTEmk 4{DIV Ts6B_uDE*jo}} 4[JQeb>{xb b 2w}v.6<;t)7@[9w:|EV*HuIXm)DibE)oMHUj9mbF[eihTFQ bmb)iYXnRhElF9ܦ[ k ,Uzg%X*qΐD6R5JTХ*"o#?fkIsyk BsoB}>1ohZ5clF}k` U"*( Ewn<v$R`Mح5uw炉 5umy'^{Hg)>q :L}tp,.WI 0H??~##~'kVώLj%Li(|çnj J@FES鿽[xU}jjܶ5o[z" $R̅&Kη,U/@_f*3[}tve'5`c ! j@ʬ:,moQ$$ <)O:e3׀s w_7ۈW}dŶ) >GswgFm6-) ,Wo~MXѭ^5sm֠kz۔F&i(4 HD#HͰX1.kʹx׍]X\LFu7vʸĮ"3Lf AB~d%EEQ55łĒHM4tx?ֹ9ML hʃ?<""aPn4 Pr1 ~> LePXO>[smڍ5mUET%(59;fH"IlnYε^O ~;j>j-7rDz}Njq0 kDY1]ۊ%*4?<# ! ؑ }bkLOe]n!D>01> r{n=ط?!!c[Նw۷_~O8y$0$Y}gC&$XAI""h,ebI7+cE1ԑvUst>O֎RWi@v5TY2elT! c$dfP 1Z=3I$$ٶ|`o{E-ͫ\+cFŷ-}k\AI J$H K mx\:[uC,/*zx&8Q$>؃m5j6x.5*&fZ ٹ+d$01#s bbDƓo;5ZQknZkEQk+!IbL͸#Ѩܫx6 b1lԹ|ƿ~v壨fHV@[D.W#ckr ^?<F(Bĩљĸ]#sSu3ȱrye0@<~pk b-oUpcF5_}fVI"GhNHbj`,&0 D?76HJm$T C Q-m\1{ذҏV PQms&&'rM<їG,~izKsI [Lxvr/o r HK):&}zϲN}o@LqW!gI<<0-e@Y݊rXWDGJLK 8s](W w%nVpN}@~@w ˸>GN׃6`@X'Ŝ6ydO{q,Kn.cTn;صhߵxD >j՘vƵJʄdOU3wOQm" xP[Up0ْ y#dQإ*N**=˳n:}#ۨ}v0t4MIpV oBǺv1b^g=] 8檫!XGؠ/|o ǬecsϽ_9^cu^M9xI!^/s+n* V?t]և9 ";/W4w"S ƻވdh%[MLLcx-z [T> 8Fjl'MG NF*z='UgHϖ:svڳr`ǂ"/zajAi8VgrA=BڲAH,P(r+Pf+S1FPY-/A9#BUkA9 stF.V7+[F!E=5ܫ>¤w8lÞ'AR~*Ђf#>(cu@/Xt%;ۼ ĞmsnOmvh̐i<;Z29`%{t^=D{XXZ><IXAC|ɗK(~G tdR{׌A9p: '& Տjҁ0lm&8<4gf f'`)x#&q3ǛUQ8n:Ú=bdn1p5FGn%'rxc^k57Ûgu+ӬCysGOAGCWu̥VIs/N}P:Gs7\s޵bhnɼص}j܏a4MP]0h\!e=jRsUy+ɸ ޞ6x\ݗEVWsrMenη}FrD#-gi6VautbRScӆy!aјې]q Z_^y2{brAL\gԦO`ɾ:3] 7aО.}qv} 3i <:8װ(¬b0Cs=r z,;MNe|PiL9,uo43r a5P+zPzL.o(\̮p;Re՛&S.lރڪ 3ݫWmŴn?K{yv91Pӳeɍhf9uus:3IT;e4-w2FS\:YGvzutW[,XU{ւ"r,9S:ģؕ)IX{"G5WCY -LNb-C=Xy+P/(z3z1g;=*TXhFou ﵯ5bڲYdKIIY%%JJVkkZ|$$ !$OMo*f [)\ɨT;>}$D1@~yVljFՋm#Do] M;0JR"0P`TX5\Mlug+:)gO{)ohZy($rJi7QaI C Hh'!!, $M) >wlFƋvnmQ`PggI0am ̅CL<&$̚ '05,ؤLDƃ& 6%5EollF|xtBN|.XLH}\uēXs$V ,FQ ! N?$  HH"B 0 Δ,_޾gYm?ۿ;ޢs/V|Nxڽ{!@Y! [^Fjnm[ضŵV6,Ȩž9F#1?u32HFLAd5cRX~b(;OeG~o]3feߩ57hJ)RbBV5jT><H a$ #%BI!$H\;)5VQxw1ե/ki'[o.$$PI޴7|g!1@k[EX,mbFە"Q1S-vK͸r7 ⫃S8T8ldzqg_֯^6(|Bч H $$0d`I|$$$ SgݨakgPݰ3on1d$(sh^mEƋiUҍыa5&?/:X B5652:JF2I"̀rh6JTԲHH@aIa! '  q?߷kfW;Y壙vS,O&nbZmož\(&ˠ}'H0Y6Z[\Qh[mddߚ"#Q|opϽo5n\?9D;1ˊ >LS\Ͼuh $@.e²Y]Fي (HI?BI$(DI8H$@?d4OpAW`usl?Z?}edѵK `aj,XXnC&$'X@r@'̐֊ѶJ"EoDLFi)جljc1F, {sژz\+g$5y#W%B.sV HJR&! $$4YQuL}o J.S=g3c!<|=>@$PUCdjXV*clt&Ě ^QFj#\kWg9c d H,?PrÕpaX*HBq?HBIIN ٘T.?s?kmGC 11~bu^=䜀~da"jHjZŶ--W-FmUc,i1h2fbWͣIz$"P,ET7nƿrb$P.9j`((f1ĶHI!?d &@$!$>Cm9i?]Yt>dďPԵo>ϻ߿m&]/~> L`@d?5VEhJ1bA@.YVVVAF T+ɺ$lئk^ (J++$@C&Ѷ,JD~m?~̳sӋ.%1<jT, eI:j/]'FAhkeOfTez}mҚ4Hً,Mu82YEyK爳&aͣ 6ҵL<>ET\8Sa[Z+W`n< KM4>RX.r9{~ T%yF2(f{P 봙.Xpy᳕bQ͸fFl7OEz.`sK3Aޗ4I ŏ `<Q ذ,.skIu vAq7!"POAP{Q#N}u>Z{*mo8ANfs)FV0Ȱa۾̜^oA8厬y>ėv=.M0q^>nS? l%- -8!|xN}n[)Z}B}V}cu:Y7HaP?ffc[ȅ@=_\{Y x )9S)#$cUѭPNP X-qv ï5=H4q6G u<=Q{6b.)Tq j>mU75A8 3^_D/ΈlˍI}A S w_ÌQ=FE e9,|o \Ѷ #@a<.i!&ַdjw#YwvY{BC:LTͷ$jdPz03K,"_,s*&)!\}녵 K;nF]X|}1sJ EN'.Н+(1nqv+8Mt!B 8=DEΦbea\@%|-8k&=.{ٚW~mxj¦G) x!.Î:^81p^^¨4@usX'h0ך+}iޏuPLk`5lC+0\W9ŏ6.w4ǙeLS9ی[N=_ } wӼL> J O>\dL>׫rP^tFeZAUvu 2 δvteI$-BL\-( nџOoRa)j&Q4g,<$vx A/={9 ަװaŚ lZ3O[.<$BQ"QhcfՋ>\Z4s՜-U4fSr}鳁axWl5LiZ˔Ջp{ Xjgvјd9I%_-*rn^9/k" &M>[Bw6{ٞۤUgF~*؞|`Ż@?1폞/=H]| 7螺^jy7cX}6zW+y(^]97n >wz>t cHhxW=IsyP.a칧\K`¯rۑOShO^T@kyzT;xOgC#:5F-GSEH3`.7@ƅg+O˧&ϞQ=xQYRFC}ޫ9'a׷*qaTX kNGϼcIj.oU{"7³HRc_}u\b@!I3{m`uLQS$UE&Udgg<3x!sw,^S4qd>g<^HnMݽ L+W-{˾5. uT's;ΔzXYGmuMZZ^M2[ Tg^Gskɝ9M1M HJOsՔF^N S9q/;P38MRK '}#8D{jKq7\{4->u#1',Y}Ş}}1Q׻EׯmE{w$mj0}a{FDŃ"oq}}k]dgvID`iKc(xS]:Bwj}ݹc03YC/C|/;$vP{ I2l6þpEUe.Ӳ{I$?r.t .'5X]^WR׵; V%0fh9KF7Q`dsG!l&>>Qyt֗XRz}`9l :[^QewsL6Oɏj +"2HE-mr8( MPپϮu\( +;bIG(_D *#^T#n'q/EJr hӸ#(z1z e۽㭠rlMڠ՗m-M:^>+#JmLǁ9o⢋8p"8t\::I j8IO=}ha|3jY==uS7#|ӡ\ȝKW #{ 8of .XXߦl< ﶹzKHмZ|}7=}4gf-3oG(;qcA w[@W{}ZǃwH3}<$,Zp&hECVgk&mi@":>,[ųG|,I  $pI@'2SxEUq}O%= _w.UIh3h*ckf/wJ  @m1LdT5EZ\TjZbk&sr c19cRU˕ok4k$u5mE@Ko4im@!8SL?BHAC %,@BԿq18fЍ#|8bck/`",8+ᄨCq&LbJEnmQlj( u!i߷@>@'I! \1V+4m5~&LƃX2Xܱ\܈S桀sQ |Nȵ˜Rc*@̴ ycbQ^#^Kh iHCdiB@ 9Kqt&r>f5|.WHǚI<Ć  B,"0 I'0jmQZ6Ţ\T( ; H I7.% .nUۿw`1#n1 W-kDBf%UN)H@|i <  $qIфQ }߆h͂ '~kEkWms,gPXn8,5QƈWmh_U^Umh+Bwh/Βb&ɤȘXWM9wݣ5*=*TXŪErbqֵ[A1Jq$ ,'!"i`HA0hen7o؟~Ɍ_fw(V1Z\u8=`|BA@#PYC1)+}ʿU=a@  I%I(,XE4IeL31Q} il e" Gn8(b!WW_~G0ek?HH 4 d DaFL>@Ya$9mQ[m_ͪh(Z &\,!5tq5rdPQPPrmʇߩ݆w%(lӂ]v̼o6rF|wx͙.Z{sš8<[H@'.D7\Z쑳 #zi|=19UnHь' i7rv X־DrW  ?nfݚ4Nr0e"\B\8b0r:ո7 ܦ)vKI57  du0_=UX]8szUɽ۬ei|9@,cQeU0"|֟I>J[݉Bٺ}D1/|hq]I&qIn0i>;eV7^>ǜNHؘe O>§sn+y;ڗwwusxk|z g?Fq*Q+ hj ;ܛ7} v}*K;i؋ݐ(>@;#QEċIH&مn@v!b TM˳Ha 8.3F[R"!U 5Gd38K h2.M /0'|/e&9q#;7ٍ3=n#q NŔ;-yli(~Y%Rߐ3=ӵ}g_[YLӣ8M˕H̺ͮ}4Ժ7#%0T|%}wy[՛go;ݦ{Q`^Ō6CLvwoB vݤ4~l˹ ưfH#쁅A'锐xLA^@KW$=W{Ge!nd#u;\3׽ڻTsvd/`G[5c;!g޴ "ƌI]u]>U}Zz|w }{8CjK O 2D`w\P I;R'vCb.ojcn>3 :Ѽ}*᫋b!(S ph7U~^V)tmbS mSYcM4P?m+x%#N ؓ] Y شC1RS°B3a2 EO4p/DŽq1ב׊&`tz4\s1\/Ho#xIqAĉh$&YD!qJM(itƋװNFqSw%p@`2c\=΂P<#<@٘%'`E2(.bn؎C]/kܾz,N@-k'=ERdLE5Xu&4Pq"S/5bkXPI'w#:0z6SPäR-x[2'PrcBө kL]=}s:NQ{;7 ,2^n 5 }XI=leW\Z-;lkYIPqLcdOAڜHWf^2z\y}Ȇ^"hVMa8,@da֮fOiQMq҇AI!&.xQv8h僚hc;xa]\ji6"|NԱ!5o`<+GOgoW9ĩViE~Ao]#;[xlqe =7 |}C 7OxX!8Lr,vDL_yFa =]`$b1l7 ?h워 څY۩WZ"[oQ5jK5&4߷띞g3mF9'͵tvOB.j=.1۾!$\ላ3OԀ4٤.JQ5v[{G(;O$iz#wrpVQcyy3YoMܳ$Q]t;&ϳУ>`^G 1:25F;N$D]T[GՍZokF!f^ys'jVܷK{^`w#܃cKo{f'{sl=0U/};,{LG>2%YKJ9^x7zY3;KZ5窩j_{ q6~0vws1{zٗGkYسց؜ն<@ըPs%>`4LxYv=*7dܒ}LyX vUXo!>d˟vQiΗUV; !<HOIIL7}6ۮhPh1٧s4@%_ؾ<2 $9ԁPVN->I!nnZ65Dj~rѢU# n %+* T TS7ٙJ{߇ + әReeVJXJI>4 |0$O~qn_櫨[=tSHG:L?xSw7i\}{?!B B(X~HBs !շ-oZ͢b5~\EF0a#!?Vbe ȥR(K0? EjVu<+6HyIA$ $$IN3RE_A8<64|ƮӆgQYmͫx#[̅d a1!'̒mUVRZ6$_TnTE"Li'#t}v (FVm,Bao:%WMa)>~D}ي(c*1"-11rg ? ?BQa$%YSE˙w8vOx6~_c, m7SH~-O>VI'B#EVڏk!B,QUmF5ZHȢz([jKiRU^pmg4_p%g PQNZֈ,F+̡kl'p L FFM?(i;gwgu~Ù>d}T.2H bHCy@0 @_UF(jb 4&FYvXɭ;-*dp~۪LήH&c 8  ί\f%X#)C-ىc >,  &mWWj.aᄈ|B )}uMBVa1)~=sٻ*ƯVEj4m^MEh RE AA,;)Xar⌿GY~A1߻mu^sCQZ-ѠR`ђd&F|?Ӄ "Ԋ-te<}u~aLjbw>wjFojk-[b(,E AR"rWOYyQ y!\F# ȌuHgjITE&JM&RJ"B~2 L!ҿnoՓC)٩"-xy~B~I8W$j(O$@ *IW ^h1F<1μLsr0Ь**?~Qq3~yhfŌO2iJ4|IA{>iGF$2rg} LN5l)8&o'=i6$->hb`nr@P(4տgn#MHHv_!Cd2+./IXFyEF̕\K0/B޸AA3F ] LW B Iԛ"tHF 0| ` }U¢a&rZXSqJ{3eL0MApũu ҮuuG6lzwlEm2Ҽ̓n!/LCzye[HX@krXY`|C5[殬?Y`hl7× †zM7&seYXV}7i>`ft2 `s:ֲ[j>bVq^czWosaoF:p{6/Jx{h=Ĵ˿:|tu;N[^((ytȻf`F[& -S3 *}@ϙSXqq@<-~&]U5syh#QFhdNص kR`eEYHSdO`PyՆd\ %) Ea-0Sb} BMё[Mt&eی?,'lנ0wB ƈsu?_NLkm}_o:yBgTTla԰xa4 L8S8ʳ~ś%2kȢNwS0VV-7ځ`af'қ& h9Fcަ9$dbkBcAd/Sj)zޝ\-gl 2&Õ|KxlڻbOےj8nЗ;~@@r 5)w}2*ĹG- LM'nwN0)lmF? ^9o[F\ZFb3S+;@Bئ y]_>c3rؕ*.jKq`+`eA_ɠMjj~$m)l5z?׹`>;MVgnR=Ĥr=oyz$7~{ܼ)s xrju fOCy3 躎qd pQ~."|˫6/yJ;f랄5?&7=׾_#EPQ]n;+i陏c猶8W|gvDk +cP>@NQ]ݸ-2XQ-L .lDmVwe&\ Sw ϐ=Mm;P_'f)8k@opY Gb~þdr?J?i^vmc(3RҨq{Ȫ9^O%Gw:&nѫFx!ƻ|ǧ*Gyx-#)q@ƌ!yKp355G9 .uoq>7;+dp1׺Ƿp\J mm[JQ_UNT]0tno _׋>^j\N,֙}{}bfmt6Uc8|U-f{.$.xYZk7CdhlEfټf:žLl뼼=e3TJՓ!}_ 2K o-KA/2ZSctUOgrǚX&쓑BA`>{'J{-ۡ y÷ ZGB9`c86 diwҜ -ϡRܔ(Ja?zh(2k%8ЇyR!0@UP!="ݒ_>ɓ%ߺ ;:s_3q߰TYGKÊ;Dq4tʐ'hL>x4I$M ӍE;>FDaH(qq {30t.}vTt+yG3b&`s?;;TW.X}׮P E\S[h.&&(ҿ]pWm?8V#'vؾ~ ?|KE_׌m8HDHi? P pw?w=؞^6Rj"tÒ@ "(*V+KVZ-r+)"6+۳AJ2;kc1 G&a8lb \3&aeXBKk HB' ?RN}hER ~>1FÝ~ LمPC~ޛ.! 9$0,X4_߳v_}cխ}V[nm-V_nF1HlXւ)Xʇٸ[S34sưsaB<˙51̡@ӋihƔ? P/K;T^fH֘EArE zp ߳ 1!m}??_}Q}V*mF5i(hd1;Sn[٢A0%s\0sxBGlm$"jShii\Ų, qI?%>0HaJ?YRaԜ"J;4~DR;mfu'>O$Sɮ7 HNE 2dSώ|>!b5UXX+rh.Eђh;^Kr6 /R}-=br~~7CO0MaQf6ԥX,0sԢ"f&C0 O$ !8ws ԴnCjs)t!SRm~٬gB1mMHY ضmsmF&*#"( &n{;8 %[cXXBKt\xgp ;'$?$ x,",@/ V¹>{h3}?0T5D~;/#UU}LLv-`O$ j?-kbRmxZƬZF"K 4 ,s`g͢?r@d@%-¹|*V3rwi-ElRѵJ6OЀ|0 a88d=:g7$ֆBkE46+?1U@b:0"¯VV-0kch(117ܬT`)S`[M-hEk/y`,] Ef>˦( Ä\2Ln ݅C{~;\ -GCdub󏀾3K5ow{ etm'ĭXzދ4rH8aYAgd$.=[t.X^$ @$d#1ϒaJJ2eNȏlnG X#Q(4jRҾJH`"X2Gُ[3B$k2BO"&P $(4mZF.IBF3őI R¶f1k?"HC$@$ xi ١q7G!U0y$\xf*kBi XC#4PimwNw_9Љؖ˨PF"%Շ2c&"Aə& "׃&9'=-R;^xva:]!4/1dDԏpop'ۇm=@\>*:SAx$˃ű ͯ~TfaAplZ,g3C4Ԧ76W}nnLqZ.A` (WFA1WL%J06q!L- tEf|j٤h w /XRXg*xp73yᄃL)ׂ@$n/{gM0rܘkn^((OATa^^ d)5>DSŐHsΧ|F!&^]%2!U- 29$ ʯ_;QyXŖ﬒Ƀ=D騉j^B&ܱNygJ&[!/Vk!{Ȗ NMtZVsmz{vFn%W+?8++O ۄAJvDy3 BNgc,w>"/%Zܳ^Zpɏ5醚sVO =&w%W{$?pqfBȖM3l^'vY;<*# :my,7Q_9~Eh$P+j6F^ DB5YQ#sTO~\"+Ԍ tܽil>s3{p =)7*^oO/6 pv&>o\"7̝.NK׵ym8ZLS+;]ޣ:[Cc -z/ۺy6< Qwzﭝs` +yfz!/HdoN;b}YIƵEb=yr{=udKoq?=LvQF<#iyxhPя{G+I?{W/^˔ÞHpt/N_.3DccA)~9޲aYO .C;x"-Q9oT泻%﷥oP/j%>AO05+VTՃxQ/;*_\޲9{X}q0«;JO7t;ðsAŶKw$h>rSFQ,ob9sY/6oh~ݠϢppeWwKb>{7=^q>TnFN[+ܱ,Ռ[^Rx= ȦN@5;D5y޼yw<|k=Bz2y퉹}R Oy{pRos)BKV"o4kΦ"_ѫC;'~\̮ƐcrcMi=?*%%[-<A|wPKYثh`;3/iqp_n>kqD*&vIÛp< ,8Za=+ˎ50y1U&93{~]^-đn$Aa&tj6K0Np,\1գ`^`W5Vim1[g| Chxg$h8{mg)˫+nx,R}MDWysq-s}:]& $ҋy$ߣMoapn z<^dsɷ6/}2 6R>"z`tSZXnoiPlgۊGRstioY:a7 /;wgbGYty#\yOc]ϩ^ĠAV>R)O d`ҽo݃qzX/%/` Vhhw?4Yy&co{<ؘ棺X鞍 {}}}`'C4$FI$utS <|qNj!>) x4J_ɓ ݻ~4}Yfg_~Ǿ|,Pgc?4E$$5`E5[+^MFI% <8EJT*opkK¢\E)V[Ci~$?Bh$4Ɩh:k62~Is~C9(AGA{ݏ65W+cQͫsm.F6DdU"Zqss):{O~˸c3,U4AZPmq)X@?!~?"73bԈuHt5]Y=ɽI`XҢq%dXkJ+lkoۖbkFI w0btjm_X6gϿ}߷k1*iU5 *1ahB"I0 2CKq?$|~(~(?HOgE!!11Ku\YzFp:q" @q ߰$2Uj6cVc $L#tb.Q kP3?&\fSkg͡@wm6FQ!YU#FZ(Y'$?$4I4B0g$BC9P.ӈk8VtN~`,~:̆0 kF[xMI`_ǍʻHtkfF('̀`0QwEJD¹]^.QtxHhd"Sь+b8η% ">g"kRo&bgHD w}^(~HÌ}$$,$ ͬZpI7vF/.Ƌk9Z4d 10(u?S</Ro"R[`s-F@,C2Piph3?Ð]^O_m~{FcD^rmZ-V׫6X#wt;vd)s~A9ՁupS9yCyˆn&&"0$HC I/ z}l;ݎC&^?B|+Ƣ|3ﱌ g}aNVۖضoܶF*5QPW(AаDRfIPj`2:( H"Ɣ Hޘkb¦ mcIŭE*JR RыB>JZFr֊[~j+ʮ`Dda*6$v=(KF-k:m*"s+nWhT_aaBZY($!A p\ùr m{ "9t%&ܖ0Xh+<ڳ_U:kj3w%ٷthE@Ѿ3zlcDZ. !j0GQ΃ ,@T ]N]YAGNlw w6 |_wAL]#Iisފ_fv*n#ѮvL;kuJ+-| ,# !Ք3s/Twit9uOPad|=0F}F"q]/׋Io7-Hvj&%En#A@RixR%">ub88G/eH {v+ n(^\z a%CA .bHwf*S1bkr :!%ƽ06 ]$^0\{L;$N'TKsFCӨCX栵t.ךLe 6Y1Ȋ׾3F7 roE㏼ɡ= uzK{OTwM֘/;3xmGiwvZ%̹zØ{Iι}ixlFzD^{ܬTf;b{;KYPi꒽ü||U?[&Ͱ6n\_tayy(l4_ľ1Bb(EnHպƷn#eX7G\jAuA )Ɨ PD/ Äl 9`dGoH  $a{뱷XNfRAq [?20y5 *҄E$ aOuJHɄJj $[t]a K3b|"1zlЏ"N tdK}nTiPQkV'ϫL#e473>XQL ߕ{.y Bs͡q~O+\YUxYk! =q!y2$OC`~8/vGӨ񙃂I6#%U# hf3O!-ƚP*i7P^QPwU`%|CyMFk QTE9Z/9}b9&iZ4ĊG͌Y('PƫK Qqj"iqfhVqd:3h`U)(nZkf[dmC2Lok>/mrh/~݌=i1Hz޴*q5z׏7 J{]!4-v ,w98TRQCk[9ro5up@HHdS=xū4auiVA j`z(q1m}n}hQ\m,"[i))[VAEAR{J/XMlO5\ Amaߊ/p{ ב٣ة\nu2>+h tsզːlg`uV{w6_q؂$7Uw!]?oU]1K;){ծ/|a7ۺ% #݅|NJp{SehhQg޾Q(̣`>{fF)aTIDŽG'VvkT(k-?>?JrۼV_|,DvuKuLz !!$sU/jGϾ/< Yl^ oQA`sצUlsU8 Bq壷)l_iJ~,L(ATqaɌl{᷸mljY*DGp_ʡ{epZ`D U+GZ8_WA8/^rnvuE sUxr wLB.4[aXɻb Iԧ/&ϯVΌ+kfo]Mf26Qwt lq"3jC0 ReSȹFHG՞ Dw%PZXF<)If{a_z760=\Jo } T"6|x3:*ޡk rzwɴY +{Z6+tccCH\ӆa~5D!'Pzi{WlhpH7FqeFƧl7sWc >p{ߟlB0̎)owcᛝc c`X'}-+/jtn tv1˯$V.2[ 5+j.xͅgr ,UD+u a8+O$I;熪Z i ؼpɄD2UC'0SfG0vXHA9`yuI'剬m1|ԏFMbu*QC d~fI .4L&7g_Oo"8cR Ax},w(: zg(Jhփg]=y@'/]Yl˘'8,`7[?q\t5C|OBx`^Ps= Բn}" m(B pX6F,ncۯ76Nqa|VM3ʊ!te#7e8,38,DQy6dCUQp)ڄN>ڸ` 9}t/UeM6ɂbss]n+xI I'!!d 8!HC~MCfA)?VO&Aԛvo\_{J?>߾m׍Zƭ*,"L e S"փ7Yɿ =e[hͥm-14Zi4!,$"?󟯜^kLC(>ӄ$ͬ^_+H ~b[q۽BIY1VōV*\#Zd'YV"SdʑE IqH!D;Jh" T`f mE%?dH)CJ_} G?cG^`ʜ%vC7߳VAYg߽6z֍kUlkEh4wHAVPjXsfn^u>n ꭴ]l DUkQH"RŶ\f5@Cxג+( wM9 8~p)}{.=$B 0Ra!<|@MX[W2[er13S) l(Vn50k/Z Z"E[*Ї >(0!d`aIs-##F``i2Ba2A5*T|Ϝ`?5~H~OH 5!B +|TIr\c3q}xba]$aײ߻ncpb&Ze-hVHڥ p Ƣ0II 2@(? k ߿KR쩚h#a8Ig 4$H3XJ-,3`F6[!* ]!?8 u- `Z֠YRڴ?O !%ORI@Dwr"-?4>=ye|e0EbPs ɉ(1 U-h-W湢Z,QQe1`?Q \Na@AҘ̮$A+]L£RkJJ(0$<2,n?]ko93aoKKUeA梾{nBLEaZŎ!̓ s$%aY c_bbE#SV YiEZ3:Sك3XS')i04@`D屺NBwN띯m_f`? $~647V xCĕݛaƏ8?~{́+\|~qoտ*IcTm|75!Ș(uuS˟~{Vb&4D$˹λ]t;!$N埳h2pQdSw!pgn|_r[ӹN.hһy=^C[k{ñ=˽9jng ɋY;V"^;pwfT.륈>IAQ8OYu|QD/&.q˥X/!m>#0k ^-?vk{~,ьJ2vLފ2[YT^*7p>۝f+7)WI[5_bLY!3yYލmdOagA02@&9X$TB2/Ih)b%T-ȅX eеf}>W&arsb1W  IScZ Pzbx,xaxflPQkl 1#lӓpF)ݘ?l􏆔Ioͬ@N$,sXn{HhdxEͿ2/eFvtC_t7Jر@ѴcQB곟P<"fV/xɰٲs2v8c4߭<;{ŀ{"藣-%v=5`C츣MD ]k{̧E&]*>[|/ȅ^z( #J{->WuU} TH=S%C%x`>)wIyhZ!іd !g1Ԫnϓ>Ov`~Nu3 4.YN“,PPt1%g " 3dfyA0;(18F|dd wy_n̬,ЛArdK)o!Ne[2K,U6#S( ©CRX˴Еɽ9ףB>B`2`<޷`|>,Ekm>v$ՋY)ܖQ?c+ln:2"ccrLl62Kq\z3npZ_[aW4+deL5dtw>rWPD8˖r\qc8 w1dt_q&ޚ zDĎA9"B62n\t? 8}zMpv(36O!:*[Rf($OL0~bboryF mh"}xa2!MF1k:w2,V=廎*Oϋ?ه>Dʈ۽湅L= y=*eXJKu 9u}{csvL/{cP\IgI]r@ҏqL3otywP7rj(8֊>GvQi,U.綁+۬]qQ-HDhYIY"0CǼ1ê`׏6B_YU  b$g1x$qD=᎜(.T;HێZC$,}uV:& 9Ihc7Kњᷪ.IsŔb&Ƨi87 n./_Eƛ>.׻</JR55VYJ]͋žq{:D)5`] 잊+",A!mx^JW;[uϽ`<Ր"}t n9^}`pQ93ky:<=.t)7ѽΌ^p\DĊs^_7k»J-Fgƃ1xJuۗB\CED]u]hqԬDh;ݯ<8M$޼~EN޳JYJ하8*^S| SW|obceTʱ9>52_f Y' 1F-2A/f3;xcXM";g Uxv 3D}$~ۛǫц&qY0r ~sQ్3]^=l_*;/!^ɫܺY'tW'S:zӅGkm VS17Q·ҏ_ [ 'mN<Kݺ$rwz_Rg'2S^=ݗ!Ɂ ,MYp_:ՑRwk#epL],:V?qךԖ[0_^ƔDw^c(#w>*:Z~/K f-H/?cHщ#ǟ=ZӲ^O"e{}xKNܾnoNNr{T8vpoXLkav2DLdp-{ Nx$i2w ~2%q4@<ƶϷSHΤ$}bx$=NMy1^uYzELx ?'=f|\s^c\mY:w1}gK8E_(w[#mG4X]Kwza|W^?X^wh=9-Tc3pr| }s@#}{N%ޓԁWN`ĈΓaxwK:S),f8"ۘ -RՔsw[սxד`~S׻{Eޠ 30ضYf=[JNҏM^`)ϒ ,=?O|̐Lu*nVMW".V[%J*a[ߴͯ4\nWsg?:* *mMAR#QlbcOCƖ0ҁ .xLﺷ={y2ӑ˖5߳0.YqC(3?2I~mk⍭|moj֏W7JT\)c٩}Jyh1%)bƥj?Fd0'_qo?_{d*ffe`|a/ǻRCƠrȡI'2@M@lEQT[Fkt' j9WyD FHEqA* qfۓ 1QV fSne[$&!!`DAO6qi?모kwgdN/7j2#8q` <$W30+$![WW4j(,(q2--Zdpci{yڔEAZȉZm\[RC?RI ?D=(fp~Cd'g-? BjF/{O @5?$~Ckm19n\UZ-fTDe]}ц|"(5ۆV FE [h +0Pd8d!,{?\?`ܵH|+ #9s",^s,E6ok_\-n\{("CǏ wq'V`P XlqM"Z\}3)EmjPPMj#Ac"J ? H9FV{@{ka&&c 7+Hr1Y R{RÄPۚ~[^6k&6b0JbUꢪ)tOno7U1XSlZPUFF\؋ 0$BQ$ ? ?>1>~ߪ,i74p(ݳL,Roa! SmnUF֢*2@~sV UQcKZOέzeP/q"2Ҋ*# b?@N?I? >(I)dDr>/˴ֺ}kFڊ}[ |4HȜBc QmZ}[Տ[cc&"w -EJƍ>3BU{LnzICK#KRG޻oä4Ll-jF!k&vq=Op[lJfyz\ڔ҆} T}qgzBC{*f۪2عO*go]2.xi(1ʿ-XM]f[ apw85(#Pz3mtWek< Fyo(ݬ4v T獝2Tj쾔z".^nQ>YΆ*ܐK9:+ N ^c434:D$EEI8a+NI݅bGA/+lK221%Y҅_#(&?,lqՁ/>2dj 6mǑ my".k *@Fl{X$z:zN10Ṱ+" WK-@JBԵ95qarqJhA2݃XDcЙ; TO,oܱݑaB7\r{:<<=<-/gsWz'ci횞ɑ7-i>P{|1xE Ӕ{/Fpry=!ewIIЫLbv(hPy;r>0,Tضw^c5-[#^o.\I߮nnɴ;?$Y҈(0븡SΝ*+4EG$zy+4?J7yLM=ry'1#%SHyG5##}e[ k>L Lw22#А &[!/7H*%AfcmdȈ PP0s  a2ǤY!%#ILR[`# n&'A9Uej% (rqù~I ;r`:ҷnIAx|DAC |znjϳk>y2PK9F'ٖrw؀dyΝm?ó}Wsw7]<ϬA_PrLù{*TM/|.Sh^s#8m4StHG2mY44kH.% e[+DHDNɋH@Z->/C9_Is{q^R>P|Fqf ͫk =$6 q<($>ֳjU#+tc: N= zt㹡Cv>AM32`'sZEa (ܯ,',rT:2&A3%,Da?gQEҊɺ)C3 4Z7 ;(ķ&W'(Ky֒u}ʁS'cw]uiU8SfO0vv#-ax<-[g)GiRj%Ϙ Щqe` ng/C]>Ou'; _Q^lp2+JEیb0c֖w=eij!}NiΫ9n4ݐKr|!dDzpˌ+wyk `lYWpުȟ3iI|% \2X4D4QωCO9!E-u0=a o o,4o>b+/y޶Rz#1Ml8Z`-?{|#1LnM P"TԡoOsnp:s7EOp5ANWMz9`.F٤oj^Ue*UYWH+5x)!)neI#sleEMޙ<4zץ*!-Ϧu./ch3w&ع&hfsMLC;pHmtXwxۇ^gdP>X#zNm;ѿS [ k/)+^~oMA +6nG6-΅E@׎F_! fq{I7 B\~#y?f$au5s1} ;=Ϩ۹1Fޮ8UD6}p^Ո{>i8l879˵we>49@\Fn]ܷː7Y]~m' _,ΐ}Y'=tz8ޫIئ'>_:jNsgsY-rhcYVgK jĔRHE#^r9xnnAQ< \H%NJA{L򼢇 /&= Ǿp[{ Xf߷B{G ry`_]7^t!;};pmUADžt=L=eWS{!=;< D,yYG#imx%{= ~,wLu Ӌzn*ւ/b8iC>vXcߙ6B#V/ve7K1_}M+%/> *o}ޑ ]םe-C[<}EsasxDc|(%ӷ cXޛnKVBzéʛ͢{Q}:hsK3|ɸ,8ORJ9^rMx6Ocz>U;+Oh ?xܞ})LwWwއD˄{_:d&uxrb޽DonVs{}#;h{F\J7^xYѸ3\v6k7vm?+Zvf^0P"uB~=g\ 'ݶru"a?;fDdF@13aB_Ct"($QN^fIN ~ٷ` Yu`!ߣ YQh(=ZUB-0$ B}jmj$"J!(2f߶^|OvǛc8)hGQjPv޾Be峨ŝ|֏I@wIs}N R\^ q6:=.%rzӾšޝa\6r~Yefݶaw^S˚C^Mb{H$kn%틸k[- ` D{vҐ]o> *SIʔ5koYʏCc5Ƿ&Bsѩ̸Yrwx]!,%OvIPأwrYti /5= 0}o_(sLc |J8W žaO`̛5g9x|?p@ᐘ$a'$' ? 24d3Ak'=]!9U >"$7ֹ hԖƣcGwcbsX4Xo{Qeե}k7)ews;.p(Թl$O$N lo{mˏcg"8RyC(rvOu:bg_hF(nIkr$ D-.Du,l E}N Qł*e.fe?I'h<H#$0  4 5ؔ> u~|{/?x9'2AdQ /-!Xc$<H"F+܂rF+"xy׾&-9 aOܔIhuXKɱ0e"-?!?B$R~?Ns)+޸81*FEn~5w %v sAYߌ u[h[@" g2ҵ̬L(I$ #%3Ơ$2]<'a˂wYxPYm_>?!@?$ a Vq0 gr {n i 1Q~S) 22@!X%`j6j*0FF" Fc+P+y4Vh]x cG#H+-#-26-qR@)BŀCJB~knqn͂6hLnh_eY; ]ŐC!HU-1򹴠s R/~0gW۵F63-QUU ª%Bĝb5c~\sc~ax$aݝU0> $Y kmsTh[XŠiPb1Ug럶?>ffF_<ү*ؕBѰUImfV1?N0  $>'&O~~Q oksV{}??!ǤH(A`TZ;#Cb?7ƹXx ! &H'!&)U,ne/["8֕ZcH9qRq/$D ?p`~.0FSfi@1J}Y5bj, ϭ)XC?}};vnC~mDlmAEaXcQD?$'>|;Ǿ1 "}dpc.Za}g|)ir}{@!6Tk%UFKdqD-LhVa/+H 79ю&Ҩ1Al@DhC){S8=5V/&_<8}4% {r; &໇k1oUX˷2{gf-Jҗ zⶹМ+nwi3wחƻ4ӄ뎊=+Vzv<(A cioy"xYN!'U Ce׃lT/<4hi3PADN11{nFL<5e4k/5lhO] s@QLny2Nv7L/]f=r0w󍥝u񁳾r]dȅ\QO,Uh)k_G*%*I~(,W8F6!7Dlꁆu 0C-VxL k/2}h03x]rX9y:[#m ⤊Zռ[c>DL t\V)#BQXR~U [؃ QCjrK75#DA(SakbE zŌa8G$ Ө,$U޹{(S("L ǁ)eZ q69KП[.& !!a7 ١pBfRYxXDDf-nw0ewJ9-90XUE3>pbA0E UOB1 b @;HӃ7VXA5$pq%HM ֔';LP^: :϶K<øV~xu<`$>= [5r|{8ք/Xi8n :pQ=737|jSӴJ#i qFBpˁ]Ĉ: :)0۲*C%TqTY]Vc'c7v(M# BMܱeh3kAْ?bER+.2S;3"sd6AE& g5bBCB֢6,ZbXޗ\6B#a nADh@fݙ_sIap2|3x2)rbQb&Es,ӎ֩<g6Т |pVP@GM!͓#L8ޮ'f F6#xL ӡCkD3sKVv2GBq2mט ޕc\idBRVL>1\OGJtfkrͅV01R\1pU5Г2cAnTӁw7fV'԰TGa=DjybWe:ofr&0D4BY_F\4[3y.hDT~f"S]lB'`/8vCX/ĿH',Tϧ\ mms wAAq4R#,"̐:( okڃ[3j~^dPuKɮ9ƞhYyy8JYAafDmUtVNk-v-=D2R.a=W{!1!(ci߱ROݱXյ` cIt,sJ%I/ؒˋ1<^,ywܡ۴v6F# Q"f`o^O$sy(yp@]]T{fxwA'qUokH׍vF5r wUOj`N^>S֧{pՇ{!ЕOh]N2Уk5ww;u^ BzAu|yY#:ZN޸oiߕDk=X>`#vhz1rP*J,b nǑEU}SliݖNS2nv/|v FXɾ['d'I`8g;_ hAoW6r .p5,nj]Nʔj[ľz`7Y/BQsA<^B`~gDt͗;Zklo`}rEا"yycW8f7eh/RoT1@~(+D#8rb# <֖P<(L9MplnʕݹծT3 u`gx`kW :^kwx?qJnd"wU@NX<$4aR[3ny[4j8n7|8fNn!h!DΎ5dgu4?\P3w˅{; >IMo';i}@,gSΦeoz<_>_ZbƍEhbbR+dD#q6F`[/gV[,lV"2VWme?@$(I>f}sv( Ώko~Vca"Kiσ vP7MTlL˝x[TXc|S<)͈{zxJ[O1F(u2hcBH0@'o x'hQ)Hb\Qxi3OVZV1DXȌ,J=9˟Uy 1(o< #\y*fS <04HCIBQL>$\?uE=Wc5LWHzhO}U6׍k(V7db\ha]prn5[oΛ&oTTz:-R/R(Ken iOM8?d$4(BN)I!|~gy=?dOv$BIcn_g!!UA;}}0/<%HQdQEѕ%VgbZ\ ;p ϹHږ,]pLSk@mFعhϒI Hxa $'HON`Ct1i93.CHְ㛱;7珘̊VobUxڹlZMb#@cty|0GLwd-59/ekR+mv¦PY*n" G.EI$80 ,$lH#ܘI)a>Aaj@!/J9CvK;TȲEoߙ{!I )X߻v&dW.]"oG,؈B w.]8sIӑww\;uן$ ㏌ ) C,vAѐҁ#pVc ," W}Ċ&hUi4j1aFSQB;>r~➦oB>uڑnTlT,KmTA~׎8%ԁoX<xhB6/?vK~h^\WEDv9U[i}RƥmI_l&0~[4#[:=zBwʻ;>kL{(YGﯦ.]2saqxv2[Ћ 1u#ƺ'dw&AwK\O'A˴@nw?'XJu!͙KTpc^rPv/bAY=pxp Mo9 Ì>dQ(|k)mϞ'x5GWЎ|E8ߎ| tzv UӼߺ˶`N[!mK)]i1kgh"^+hf`ޫf"[P{iEp]aBFA&U5^;{CVMWZDS"a1JV`LnF431% hvX:sP%_3[ PFF?d؏ /-HxmSS *q0s,>MXYovECk/*_b-4.Ӱkg͹Ww|W^-(Fd9"O{&Ռ?/c+-t@\/FHЋ~" 'xr⧚ƼL%BTSwck2z׌gV"Olc5a;g]kޘBɶlo=-3/su-r(` ǞܒxFCcE'.<#3pPwZo<. ⾙0ώӭ5pbҞUBN+&nBեB z9XJ%ڟЦk)Ao=9maJNn ܴچ[ XCoHeQF.45b&mXOE] Hyad@uZp^LB'Ej%CB`9X i".Fm7h'$z5ML+/2}[-hi칡M#)5~`X(rePeas 7& wV!X܈+!s@*@츷ix[~wѬZRڴ8 Cռ315g64r}a,XY54^ %׍mOmnVM! Y5ʻKk $P>464e%zobx!{5C ְF _mi#sf]g >Sr>$3SDz^9ܯ. w@ep~Ñ$c4aRΕ "g0  5좉d0` _N{jLKHnR/vч57*_35ЀdM⫃hY׷Oj2c&>غ ?Q]YJ'-]ΏӵiR3Y&XOΗW{5wZ600~{ϸt.Jy㡙ώPMfHzX\DR[i}[{ÎK}Q\}w ',Eׇllv{ɩѕ}fvtL'$:Z({'5nTi.~lnQ3ty7}c`4u۝OAb/U0 ζۊj½91h&^]~3`rڰ*Z{{]yt!e~Zt7 _HVxou{uuF3\C!k.i~u^[gۅ>,Ƶo6~hmbȯޣ GC ='3oggzڣOw[ʵzka;7=b| fS OI=PNu\Ժ>2-9wU;lʱۄ{ S~7RFgKzUhsq獈УOEys'Ϧ1Ed η^WT9\l>2Lt3bg_I}# qvy̦Ğ>ګmʐv:h=pW4Քgs r $/oP{"=/j9bV#R"xL4wf螹:z,й6B ?V6S n=品خiqVo{v1'u;@a̺:l6{%9&AvY' i,M|_D5m KIS9P1Kdg,jh}k}5q N8ܨ0H%"_*QB"4hk Eóg GI| )7e3^iX+qf[6F7tE /L-yxz^v&<hF\t˹bi9hY2MMLn ow^}s4;,UJI(K  'FZ H[`0~Ҧsr-/o?oX^]b8xAG8x,XnldZ͝bz;9(h3OrXY;HD~1YN^سǓ c\-5_-Z#r{4q,{R<3E-v2Nt<}^zιh6l5 l`@G cG<8A 0Qˆ4<0 1!xQiN?i㏎44ҟ ~? Pa<  Xm G 'er&*3fp)]kBʜC˖_vK5v% HU2_1ݘFUGu?j~L& -il+{cf3Hī~.zl^zQbNnE+ͻMX<ޞpwSй! lwJT CkJk{xv8! 2*dwM7Jri2 .[ԧks?ycVzd:XOP,L]hswY:+Sxlt:B'J$دd=\pC72pRW@U{& J|Wex4iz"c8{!IλuO$[=j1}YF1 EدEpFD}:ƩH6ƓlƝs&a|;f x"S \ң/s{g|51|oK Β7xoI{EK7< zkUZ-CF3PމafVƱO,y7lx+4[Sbh%Ѿvͼ7er71wzvn-y=s uu$mh}0ш =pV˳@RY!xE4jdax:G }z2< {u5x?,mQݢRpWf\ }!n?Q1ΜX`q%by؜HwX> ;)lJ?v;2 A'3v:J Oŵy9}0_ _8pP9h[:z='x]P` uuj !+zS}<gG;\[ڠaKM1|yko< P p4.3X#1Y^^X;R;JjEBȯyG7Է/ogTvzc"mӖԟmX(OoBpڇ6ixG< xdazCDžт[%9Yom>ME>EqYOyf{oQ}8ӯ` }cp?vkn6/zMCo={2[=2~={fsxM,O-jf\e}[y~;6 ކ:xTۈ?_E7eo_m=Tefr`ʞ{-5p0 |N!7n+h[=.lץ`+ \T%jmg3O>S4mǶN{1h=p/TOȘ_W5ro^@d]5̬8p]}j0WCW/8eG[e>RpϷR˚m?`Zz_l{[FYG!,_j)wl dza>N(O cK7; \TkI6~3m#rMۤN9j9nj< !'igzGT:~#-H^ny 𖈘1O8$/3zlRIM=r6ه`Lc4HT^ ׃@.}}μT{>"VIVŨFj ~O-V2 Gf@[O/b'$S*Xo@ԺA=c TeobHnmxoK}竎{o~eK=Fx iZIJ #4GiRn odCE}; DS͉gc9^Q984-y,=3r|fzqm}Q^'da>؃[ak^ 5a;B<#AGUh'z@ɒ!x1xz{|f!+v?ys}Xm,{.#f hd+uuȽˠ ]ЁBήX|CM<79=W}.Oq#b~O"wZ:7ZZ,nAG -ՠa' tח;{BƧl{pbzr!=_CN0:ˎ/? 3xl|ո8wDzFwHbqU(' 35mrRK du7$R,pCk[s@n>s:j]>4wq<+Q]%1jkAm]Uܧ}.{ T{_ !JPCޓe885 ܄3=>tޙNl7wx.vӵ9}YoSfWyl u<<8Ml [E 0=qWl&W±aWʹ݌5gou~g Z;m)'+/b]=JLRÈ) {=&O؏Y:j|z3&WR\7[d(fo[Vt=b0Q{ﰌ[smNI;#;k# PGǚP'aLafM ˋPWL?W⺽3KCa&A%3ԎncnNiygycL=_lx9bvO 0=N_{ hZeu޾7Wo1[߸H 2;ʞɤI#Ǧ^;v5x,l=u\Tozr^zߟaGXiymv߄raIXSJqW}?^)s+yDFx%NPg^vņtӾw ݺ'7ǔ:kxwgwȑs80^p ym]Swa"oE 5 z}I$LoNL&#kڤ44bGRB z=ѝvDd=5bz{tnόp]:c9}m/"9$CG^ڈ˓p[g%vK;Ӽm|A<Dٓ5R7|`k?ywwt5,6y_y>=UNjDA]20Oz.<ۂ|,۷5Yzz3 s\:I3˛sA6fD?frgfQ+F d,ս#zmb-wC+o/w u'8dG)\;m@G35é=qk..yHKd],!{fIK٩y<,~ٝDaRoZWyZ9$H׋} S}5GN(x~tJx3oK7H \N<#ܦ;ӧmnGio$&BSr6#(8z>{ްBl) D j` p,d3?pܚ 'k {ǽ|qe|Jc,7<2'M|=IROxֶ܏Yo*9x=lf3V5}-L{6u ]gGpyEY[%CɃT a3Lh8Cёֺ$|+{Z<~Zn~ܻwKO+^Б,MQz X ~1w5%`m#A잰!cIUNyxQ Q}gVW-hh{bc;48nێBњm؍'$_n=~ZÁovG?hqz"\⡾Þ2׉!g>2{̺3(}X.F}z {-1 >{yJ7XcG}S%l  @JS[qC=V֍Cw,xxu[}YQbP?Dr2>^6Gz >/o 1yjW½SՓrqg d\??^g&tڝ=51,]5a>[*YGWRv[_{1^;)M",]!*r&*FmMT7/4znP /y 7<_AWX" x:7zx2XߞKEbU|4j etO?{cǎJ1s({3]6D_[e/gL:^>25}Me[0xlGЊҊgr\u}.K/7+?FyP MN;{ ъuljw][uk*,]0~~ vuJ;۽Tl xT 3W;po[KzumS£&3}¯^!x452!;WKXrjt ;Qp>{WN+=_;>C:WZNh(AEdza :4,r z_o2z+wI U{t|v%pn>ﳤdwZԒU&\ξ/pcY `7I'x˝I1^Aݳ(V^s-Ȳ B|O7V/{kjͤIs7ݒ3@!-KLP=m{$s=W1lh5^.-JaLr[kDHd I<}3ݯӮ-A~j!䵦VMNL⻖-wC.&xSA{ x%"&Kzu{_5]5VGIi?z_v{wz-X wg c۾e y;{1`8: ~,E Y]{>3ʗc:<$vox蒽=U<1Iw{Z ~*&{]x.9m s۽XZѾ6~);~ S{M6'ev횘.Pf~4.'xGxo sZV=?W_ x[s'z좜ޘL5i*Y{ܛXq]{Ǣ2 @6왾-;޽!5窍}d{17m{\)O_W`c9/Z|'#{7!{{w#/wΚoHG%i>'HrM>۝Ӊﻲ)o^q=WJsz]_QNN纼{y^`C+lUDIz8+|E^S FṪ==efrK:eAE|N$ CJfgzGx8 ϰFJDrgm]=9}4xy23޾\LW!sbs[Y35zZe=1¶NFys ~:U*erIkױ-Gt x=Axf,;0+=wm.f"lvx[ٝnj嚉?mH sb򇯎{ZaϭgNc1f Ug?HP#VEvoy4zbuHw .'LqFc<}'xaUcTk&{ݧu/ݫf8S/L刜C[ncc\(tGd{z_ טey)kr{Gv<ܚҘgjH =]wC2MJ:ӇRܻ<'Q|_ӛط|0{[znD̶a)y}7(0Ggw=L|Le8?n2Qquwٯf*'ǬuXy{D޹y{4ї{/A^Bgwc=~{ɭy[HX=^,#&soM8%o/=YW=rўL\P=(T(g{rDw~+]1h<\@yW]#w}{٭ =;[}oeUo5=0Jo(sA;I79p9jsCv.,7 _x Nh}, <3W}|p#}k>|k]vٺ yIMf,{jǪbi1/y*/b *QZ+h?%GN>w%Y::o]pu6/{Q mW;4lKA~9܏ۅ;:ľ51>%/ Gtm%.f{VXj͑@Κ6.PIa)*Ӧ!ݍ-_rxFDV$n6eyT_ĵ8esݡ\|œR=\\1P6 sԶbcV"W<;F*IԞmEi}උhS}Zؙ5aOes^GhՆMcy .Cٺt6r`Ń4Eݺ'z݂xkH9ox(_,ys,a`pcz@[5Tμ͜=z HÞ<]Q }'M3nnp|`=U|.4|-#Wiݖu/js{<`ڕ/6]o}i}vEЏjF8b^ׂA=d< sH9j^xrᷟ[TM{Y/ m|YOc7`]|7O9?{I{ ۖ9uٷZKGیz jT޹v_x\C su{ٜ.lhզN?^ҳ32Mz#8)zbqSL\G`5:u:UPܚ9b7H|;;{>P}v7=]S87Ҋ&>qrz1{&y1su-Mz۳xvM[5y'rr[=V7Ayÿ3[.c+9[:>%go]YH=sڻ[ykݹoc{}NuHԂtP9=16f^bz/2h=%zPw'dzZoO8ov"Rq\ wȥmL}3z nwnv&QKu]td^-sVl"y1^hyi5_K"]`D6DuSptvz{ţ0m5\xvǘ 1{ogUf Lvʽ{b*0V#ׄqكы]{EېN9Q+K&Y縃ZX{ |:ocb`l\9O rsFQ{|7 4Q~'6RpvP> 2qz,û0YRY1+#ɞOR$Y=YSZ|炏η^L_=/ W=-|%8˳+]iOdiH^7ziGI嵮&PSibnS sZ~^}op$O6pKS{/loWNV",?9܇gnSol@x^''/f^>Os9~xv^gik̘٣/nnvw?D;fÜ>Gֵ|:ϫ;nќy 1 ] oS,lpR4gCV/[i7%mjk([ho$1##;Rf;Z7`OP)Uq˜&k|& 4kԽU]5Gc+X_oE^6pHhyw|3PPd~)}_'K8]\jVw.Kެjĝo> qynܗr>X2үձ|C!ǽhPA\Nc/W>e=9m>2I/ݛ㽝\~J9U◐{wW"p\m}\>'>[s]Es݅s0o'ʓ*׏C\b:u;]3v#gB$fMz]W;RG{^**yFǞѾiٚo`NWk3}M>VpE'7< u^A\{\[2w3Z2.X8,1;T8ǗݔW5x_1`CK#\WY^{W,Qww0Q\yI%3a(ђWη8y]mr8O:Woo+/F~Ouv@cu|7TtySqNsyfHRdՃ{i['YjebFm~iI>>oO ^Y;,lvk^y sy, k} *ԭ  h{߻ݣ~hBַAOX DyRYlAW¾&{ڰxz}VAU`{Bo9H-SuF`72vE'RS5bЯb"TW&ޖKE7dx)szMSd #]zS+|>=DMu_wvopz%H9'v ŞU( V>G $bA.QȒIgÐ>U6i|oA" ? J-퇹b+^|RA2v{ŴSBo_ehl{uqCs'%C/ ]v]ry ^Mp3ACDۇ]EߐyHWL6TuO6[hw5f$öS6ӗf3r8@<8=N5-UO=k?gO<$]@uNp/t%$ǥ>OI;nXOZś3Tڞ%h0J^6yǺjpxݼ:t7wrewHP:>c<4%f-{-8ɹs)).(9;}sVJ\[iu}. h iJRM/yE'~=v|ef+2+Cm c=Q{Z3þIOr9َ+.e=A2*hɑ5!ڽd[FW:6xh$xf0N LzV'ZmG#{'ۺ/kaF9z=ѪV業 "9q\{ +vۛTޤOgY"2 r>{mC [WȟƁ۵nvI:b\xBa:OW֦vN O*UQM5d^,Psuom/>ûr9]e{r6yn~w9ۄ.&6nۂY-[ǎӆu ݬ5zx}_G(w:̦OwV}1ozM5s2_y{mfу3o)eܾ ZQVUFn obTpp7;SxW5,Zl]mU0&գ󽂶Zy Mx\  f.یs3}٣kC> z-=AG4mPj Nw7jͼBa8 {<0 ]83E^ ;+e69i/ӯo6ƸDѥ<.qS{qx~fNZ.nFYݻTۃ2I>a\1Q_{n8Abx<'MEɝ &Zgpmܗ~d9)xlq$G4 Pw-$(8}Wmn߳ʧN|&-W|B3(v{Td@RӃVS༹nu$Fvkŭy ߟ;D~qj^r|T|c!3R\wʹ /$/? z׷w]zJ=yk7t^qpp}З$tzSȽp/q}Z}k%VK;쑁;Ԯ>grAuHs& g`obuMK #:7\3YbgXq֮D<P=z?]4[qt[}yT[rُH`#`kwrc1l'5xMkR\OCMO}\ ʻ!^G/|эC -h{2־wl}<ͣc_sEe=[]V~OzYy5-v91$F8wܜA9^y2_> YӨSgN8{"p*fܗy(kE=hbW-==]o[G.W1Mrux޻ ˃j78՞,~ϝ]2Nԇ^* "3WܶDn LYy2(6c+Cy1YԵ|.i3lpnM}Ǹ1.) uMU>3j{>^}zfrHhǯ}N`$ӯO1o}7 kw@z4Nl'&7VZHSbK[뛞hdD&SqygZA_wz7=JWwTDyU~2Ag?u(=vмӳa.v2׻C>2.漞vؕc40@9 WqNJT_p,ڽ޻잾=yw+Ɏg`̪hC3pu<i\{\#53Zrnכ9n4Lrϣ=Y+u-O&ʊ'9uY8?)۝r[vD'̌z,CL`lx/iPŨ^{Or/ާ_J`y=OAȃx+*{fۥb֐۬7OhV4v-pFxt: qll1M?׶O94ol)3z/Lz"O3Ţka0lEk'Oe]u@Wa~ڷQˎXgu-3Z#="q|\5Di{_w<#+[s竝5cyx>9V{mȧw[{ S2\go| WE jlfOg9U٫$W_w s X2ػ^Z}G,N=ý/T<=7粟f)H;+ a|]66:,yE8g3AsII^Kw|uWwoV]TW;6zLFUW*Uw;6nQk/Ng/e]0fԴ"q{LLw˛y J9u$!^#sՂ0P_\N~ &O.u7ۢd׹]Z qS^giTp(+\tN[N6jdS>rw4_j%71WZL6_7w jrj_opP} $[O7Yxmķ| M1;KEz Rݞ?V0kCns!팑pЏJ !> jF'-=qNGjoҼd7BN1ޒ 7ckٞ*RlxɢL[J|N#-^e##P}Y6e83 G=k:, 1X}n*=G q^e^wGIq{qe_$@Ht:u3z/8/t.ew eyv(QGTgb&4I w{~0a5'!#s j3>: R3bbn؟6p՟f<7ZzB[{JϺx7tIc=CUn:\QЬUt8O7WJ$d,ybj휕/h~7A͹ශ9}BeOy흃}mٍ\)zmM_5N>><֑;[g?^IT5=7D3\kPtWb:5\W6FzkrrO1>j..ާɀ {'\~wz4*=>~{'n<ԝ\lijf"U,g'CHߖR5c]ڻVmOn_!oiS<4(m. LTxtb˚=!cp=O#7ףɛ_{C[h93ۍSHD[Ӧ{sV+^hp{GnJrNrm2pֽ\o j=3Ot^8SgƏd%.W灬s??d#an6t]jgge}㼔bnZ珒#wF'|{)@Ⱥ>=Kozv'x+!۾o\N3~t+뛠% ~I{rƯGieԪNXܞI9cwsùS lw]1IP%:3w%*g 5ޞT|wSz,8Yw#ُMd]GHѩ,VL -Ond{<]_ss'ŸͤѴ5\7yQ#Ȣ-~AМ ,> ;6qW|t]h'O#~}.'V'xy}pi4:'tuu 5h^}p5˻*Yv{;M3'O{wX㷽 X/.b14ʧWj}hV!u| !<-*'z6hHG,֯LWlScjݹц琒.qG{>ܚ߰V7ax Y/`iyzUwW;wwM:G^=r1I(ƍ: ]/"o$@qϗzߴ _LKgmzPQNE/qݹTqCa8;^ъ9"а7x}Z2Vyop дp:=\=02kv;=eMe;͝;k,?yp92ڛ㖈z>]CtjnKMwwVoל3]1 xS*` UWם(nF s3 ɂۤ:=[RŠfv$m5*>uްw5l|'7W=ntG.tSo~++&it]Es]=L h`ՍrEnL#|sL>D,Sњ2} :޴='fZv;iw, n4e>sasˇ,CnSVݥ/w_x&T?Iz- K`vq]M4p?[`_|gw}c=atnW|>foe1z'M=d7^=.M9\7˻*_Vsts.ܼǣl<6H^{h}Iu4oywL(lS94h^xt\4ItC4>p~ce;˓A9̓m9V&s$];1t;.zH᲍OqI_9+ &h^mq~{IT;kceoKSDd0ٞnz{|I'{.A8, j_z.-r}:)lcNyWNS {^ ,췽p2&Ӆ& h[2s+Xv{I]/uNDYԁv׏ KgAIrq=wyI0١ܜNF;f~Yh1ǘszGUM]F$ NA҃뜲oO:6a#n[1u#w5V&phGpwgp\{whg#ϐKo)>bZ9G]͹gwr+FSb_X?BW}pmmiN ER2yg7 !g*Z[# EBvHܓeѦYLW ;ٮ ۇ}Zx2?cu^eZOVqkf1w,ۻ'*˦v~Nޮ޳1/}GvmŢM]N!sw{ڊ==Ej~Na~mߛVEy{imߪStze'ٝ~yc}Mǔಅ҇pf1vw7F镁Pa}֬yrY3"+Id>ot]O{qֱsV2,u:^BfNTNn=={hQ{w7< \AoglDL뙳F s&1{pԡw a7\/ ~=ET6:w2Y;99זNit4)mE=ޕ,q)5`zj=(cA0/&:̦Ζ{sH !+'إO{Cŝ|,lfs S7u/lHu=xĻw%sg#di׽^B v0"n Grr^-ǭ}CMgt]}kHqr>75Ū$5Ncɜx\O9-3BK}[,X4^\&o?15_*mM>ea-3cKoW=ݦv>؃OF׹=Z{7϶=w% )d_iwLjxf痪>7붜#_Ɏ/S}}OwmlMKUn/+^@P=T:VSԭq\8|Gri쫰gQù8&7fwwM,wkÂy7)=z]Sz\a(o1;e<1p=+Κ_fV9w'D/SԼ.=,.zi!lli7^0,S=߽Yt(?vΰDdoE$7qmAǍz:lKM"+zm]_Iy*g|kuq^zU^ 9"+/gkGH,G_77>ђ* @d/gV9ا[)Y"oh=vvurݐ{vcYV`|TtqyƩq<뱃9:ѕG'HH<=x%϶e5qj2i}z|2).z}{ƻ\'2ۉ`|X@/3sԽOs1Y^-&״b:9fjs5r2|; 'v ZDc\VL.@ùHڂ:5$7+<znSU7Eq 蘓~gA"r{: ,6b6sHrn) Ec-:n=f|6/5>M +XD{bھ!r-K>!ŭz\z}\kUx_zLG_p=.+hIYhHt9{xX;,m;$2r27>k<U`))?K4ׂrOg^AB;eƌIYTaɫ܃3{='T t1P:#=M1_&HIG =sq =?ֹÄ='wz]^Ajwȑ`>7{¾懙%RĨL-MO.]zPϟ޽o-=*bj#Mݶ{O; s]c[Q:aΦ0-x˖nX{)0Cӹ8z?3'rS=Leu1ۻז/9[nES;5t(bt5%qxo?h؆h#ő=e*DvFWu{-t `9.ݯ+bWE2޶ 㔋 |P;شev>/J0+vo]^RO73M0ma =rZ%cؼ7B6ϟp2xx5؄]{{=fqؙ3QhOn0vwPU %fyo Y/k'_iVbU ޘ/oh/G_yʎdNIGgxA^:;q'A2ȇXb{EzU\I9wotuZ[rWB!C'UWb-w킈ٯ/U;{$ҧS2v`lJvEյaãouܣٰ2J/쾣 s#:lգW s~zl^~Fv.C8 C]!x _vzf)Y;<9/wrB,.Gzy^))^ڜ}w{oզGJ C=e6П.r^)0W}ٜ6-}LQWFנ6m2H͚4q!JS9H8Zug>oW솙zg{ッwz2O<þ E/OgKa}影{{sf+&Ar'BgbkqQT]W9ds9Nj[O<iid#qVfpsn q;7 u~vhxe[Au0(8N˴lܸkvyNΎv;M!.^wؚ~Y0iC; r=}YQUv\=Sяl~}IXJw)eSm!lfE:{z=><|ϲGmKYO43}(yvɒެ{ BϽ$oD4p40-"ΝǨ+oB mÛ^ bGm.^dcl%.X14+g5=wV!ayr lqSR($mSXE,sVOL5c8ٯ)X=Rm32ZgW;A !~!Ζ +#8)Q#0s[÷ƣXMeM#np:׽t(S2Tn(t+ܔظo{9շyh|׋l[:E,^ǰ{C<#JhFaM7'mz.Gsnm@ŦiݘoS_%.ߘ8ɼߩnM,ڢ.NJ3-n,󏇘z XjG%Ty;t2\ )l}Np _rt^6\J?=|qeܷyT]@6N{d,3?{ĝ B .ۖ-~k^C`9*-c(x}SBMU51W:񹛒ujεs_!q͕mCYkvo7i7Dpg|fAbEl*8GEh דmrsA#C"!¨bN,Bg.{?2U\T$0ݮҷU_Th52畚LV]Nrw{qJ9 nHR foY!Ѝ5暬n=9GmX>̱l^;,<9w,xR{ BhGqkn=CJG/=2]Sjpjрx&J,qgWQ\ƍZok{9%8 l~-k[&=nV:p~g\@\KhiZ\Nyޯ&]\-zB50/5?-tyGI^ w;ӑ;'A)-н&m@,-'+.Ns?d3;NZ+.+_cN"ny^!; gӣM%nijm4+ޞ}N ǻzW<8*>O;Sb^b&>&Kvy-p;^oC3-ì1(:n.7cwhbOmii˴y7, o6bg9ʨ m~Y>p|c~Ʈ״Sl4Slݥְ{F|6v=d/|53 5osf`bwb ȌSOzD߹A|。NM5Ox`?r_M_\=os@ﴢHHT6瀋0?Q018D,w|GEbz=BKBOoΕ8\6c)dޥ dP3~ޯ2 ߏ!#.=:=5čZ‰(VuW#)gz.#˷/洱<:+A$[]0\}h,rm&+}f Pq.=#y`)iy kt&d(_,zN#uu\t<1ESs_GmJ"ھ*z$ݧe]Lq.gvABB= y]ZuGBؽzp_nO2b>fyNtł;Kc`%ktHU}+TN a+7Eun 6dP>DilR ]^*vQF{ݥ{IfW];DyRx2yzu\./{rdǎ87R~=A2g]˧`m㴳[=7_<gT|xvt-= OG/ 2 6=pX)l-L{:&gpd7N?tsW<D/x{n̞ɔrR.;52yq݅¢ю& tGAyQ^g+쩤Saۺq9ŽWz+KƬU98c#?;uYtz*~b8AO%mgGe8=n<,_e rI ?kXĶ/|P{ 7,=ͯNlYp8YZ ;پgOٞ.pXJ{mX=v-Ɩ|kW^ w[6xt/p:ڹUjGhD]([Ûx^K^".>o;ISώu9hsۻ97 0䋱mUҜY6uT@K8,#|U)g#==A<^{*r5F~=Gu7]$sksEÉ?h\6߷TKsϚ*7l_Fı> =okGXkٵ_޾MtDyw*2[KwF\/\þz/,%e1~y$#gx^7HҺi:ZI]{Itl{ۜZqN=]nl+׺|g]9E}><ЖgvidbtvɾUx\9/.QlB窍gObNIs:hˣ]t6AY`yr:Cn{%3Abd~v=j3x(/Vn!{X'K_jگ"[=f=/T Y˼`=p$Ƿa,/͡sӚ+욋B8Nԟ Y.>'qtbl+\Ji؞ W(%}^!\TUƑ.]. J74@P_>+]f:p#w>:Ғ,kqrxVWly偨L'd%Odܻ` E-Ǜ.һ|'-}x.>W=y|dzE*U{N^ 1K=@Žw:3! xMA YbsoHm޾v :n9+{ۛu=JR}ZZk)߬{ Tԍ;y {}aBx&ΛϡzKN=:OhB9Nh}<݀=(f27vޘ}ps sD&mǁ2.X:_¼tg 9M]cGx1 IY>EO;_K="Z+٢Xߖ,u{ R /dSb^L[3髼ǝ[NoRP:tїRV랇ϖgf{=ڑ֔лۣ^DY<'8Ef<dFX_;ҁ^fy=u&v &[ƯhtYL`lk=>R.ADV8>giFs3LfYn,9}I%^.pn&M|f0;ݏ̲*{1`I:{]Hp OvYlX~.7VЭGG N~0*pQlzj·s=G}WLV7xRsyz!L⶜p9{=fchU9>6hdШ1i!YQЉJ]>Ztw5վy,4 xų{ͫw;L6z{B28rqdA>_P*v5o.|w),nzg  X["[ rAw}?jV\ :8z&6Sc@gӾ9/A}y)a߮sS\e8i8L( A6X^szi 7=)2<_snF_z0t7=cIux b5q<_F wv0^}r|YCGΰ݄׶$f:6KLPt/<"]DWmLS>S?.4)>?q.&K/*rui{b1:9-֌AY9*PtEŗyأ;=%(7ܦLOZF&hۼMV Dm}IZe8C,}=E])-D{"aF̽mC .R}J: 9vʜc~On9ccyryoO'R:_3?Q R!I3vA$y]^}}E=;RBub/ {eu&+gssꠉ΂sڰtIO;xQ~NwY)ORڞﭾ2Nm0z}2)`QV`[p{Pqcu%xhM#5h= ͧvUJdz݊j85֖ Ძ*ǹ#ޘlC+*orGx1M&HFd%4N{. o򚻷ϼsfw=!KmsN9Kҷi={rrYyBr4Btη+׽ڣ^z{ޒaQiy꣟[n@}'%w)y/0m6 iGov vq{xY'<@{e=Y#6wk,g Z /Z'#<\yERTK=ku2+KG Ӟwdi<16Ҍܣw/((j ,v"ϯpxoc;g0jr{yi7X@x ^ԩCSk1.ν$yv_ 5gN!!ȷ2ۓo\8=#œv=;(wҰqDrN 1Cd8F{n5姩[Ȇez KȡƱ뱑q/1/4"~mٹP_|W_ONchg)a+r#F8B_>YbD빹op,{o`g@9ēwY LVR.==.\^Sxf&=tZ j'{J[>G\6n/)/VD8|{( Uy >zE sql<;#Q=z%^8oZw?}_ :Mʷ?5oJ+4ohUawOZэ^y={)Ǎ=ΏAc3i<{kGo!ϊںB sO9ώz: ~gUrӻWZY]R5W4CW,r>\C3ql$sW$ >` c}eJlc{ظY0]Q4?r.8-'yKѥj0ۊSv6D_I&A  R:^':=y]VNr7%Yü24OM;0Ҵk+giwx4 :%so:j^i#WMys_<$\zIǸ{|Nxu37iw]uTWޘ<!wm #63&?|]_L!`jm.rs>@rއv.(s[n?G$J$.zݜL,v{G`f;0X x+7;S诔,>֭Da1{\qJMѧ%Z!}` "1.{xO_ж4l~=StH2Y_eB${ M 79 >ԾXr x\F-j/^_sIܔtnb'yQhM(r6^\nl@ XՋ[[tviA}쵹<ݓ"K/k7n { ~B>|G}?OR;%ڡMEUnA\TVs 3r{ב kNw&6Wz5:ȯ7h͚nɽKBSe 5By[hyfW3ڈ_I,OMU|=Y]{ָmメo$n߫۞B+/}׈=̀FFWR~\CD{7Vl kq㽞,ހLe:he!^J-ߦmOLŚ^_>_(.;v[0oPȼkpEXtwd=3kJ XSG4^F'1ޢ}xM&ŧ$vs"꼘] Gٲ@ՖyyZMy{.+'dXIadG8om<~ylʿ)r0%dznIJh㣭N}O{;zm9N7c}\]]4!tNsnc~[0Y/Y3^R`H=壋F7tAo,>mz^~^s:-u$zbT:݋|xm}ޒWv=(zw 9.g[#7VpLbeI>9D4R4 .P+{E/[D7z2|xˎx3E= ͏%nӣ`#BvSY;є6HMٻq qzK+Hs;3LVSHo~YJC\_utٸ脄+r;] XS 98ov{+2S:u'ٶj=FRf 98)enNט.ۮUL]yPVIlJ@^WO@ Ԅ2#fmXJ$h[[pP$)@@PH(U(AAA@@ @PPJJP  A@@R%@ DEB"I@P(LZ >΀qzaŻk֩us55šU.0pꩵJQuEam7vn.ns;iNWJٕ:-ݬUA.mgm]YDTU5m[l:0uT:7l}*bȖ, 'fReѩhtk)TjmCJ0uZH0lR8r5u W-GSKvխDTi*)FTk]ufkTvQmvV *ZeM5*Q/}>U{cݲaɔ.jI}h̾RݘujmEňmV:mkml봦tjdqom]r:rGu*6S)H*̨$J}ͪղE"km+u6Ѳ*V6N6Ѥ>/%PכNt'\i5g(ẊjeƧӻ5ƝЕqlk$ҭХ(Tvb5#c6҂WwjNxX۷-rt]W8vquq]Iɫ\y}1lSD JѰwsmbTk 2mJ!\ڥUӻi(D>{z֮rZ590#]kg7UPJ-iMvrrmӁR `֥ٶ6Tڋmvʊ>MrκYɝSr霵ӦswLg/\WlZ eݜV[5mlݺMv]ER͹qjϗtuXZ(V,.ݓS뽶m۪t6 "f-hԻUml5%[cZ4jh.LZjJU*٪VbMk[lekmke*֫k5L*jk PQ%fƚmeMi يFAPZN°]bB5V؊fƪZf%".Ɣ-+m RD!E*)-dŨm&KJ$c mS6*LI@3 h5*m*laٛIii]ػ$wnkVeCEift4GaM3SݹLc%BհجNEk62kkZ,tmZ-)KSIvҁ&h[5`Vˤա[wIKwrmm%VcUUGZB١ֲͬRK6 ͕l+NV[[m`MTMelTRZVXۺ ͦ-imm ]գ,[UUlmO'T4JT SډP)S $JSeJQIPɡ,?Qcp7iX$Tb9+X,L6d($WWblp)7fhYAw LcX Hz= 0n M8QhY7Mwv]eB-5{%fb݈A4M4M(0n l4Һ# XRA F(j 54Db0f6j&2I*a5dDt4v0mPhXb 7u6b!&X(3udh.1XjHi3f~!k^ץzBC5&4]b"ɳMDA Bk n Lj#3YLDUE 1LBM5u:0P$٪"hM/ѷ^=U 4C``PYf5dFE&f5B QQ `&NHw nRdRE$`fI, lF`I3qC$CMwAD$5b2uHAH, 2c L3( ȪaHvvla $hlj0$c$2L2dMH).d1@1aM $ `M46b$Rj3uu $ d44݆b2HdçN!8d01 ICMSC@MH ,ٳfɡY4݆EI$3&MI 44j @ɦ6ik,!l`!EŒj47Ca`Ba'dޙC&a0rĄdHdd2df"Ba@dRM446`fb&5$4ٰd`dņIa0@0 DI5bD;! 01ɀC2L\d2HLv2BfL )d!!3&@02Ba$ 3da2 3@j0a8rI3&``a d1I T 47aRIthd da2@2dçBNw&0;Na 3!dNI'NYꐝt:L\1a 9 Iβ&2fB00L&ٓ$ç`N0Ɂ8s&d3 2a;;ά a$&L02a0d2L0 dáC!&L&t{; ;;Β遁 L0Lt! L!2pI&`wp:I3&&I ;Cdɐ'!Ð çg@:a̒ýHf0N)J |>!B:t;; w;$̇`WSB!|| I_O"$sfa;ޝ 'Nadd3;; C&gI,Ð䓼8p``C&d3 p9y8r@{: R_I(}"J)%𐄄%WiZI]֏/!fL ÀpI8vwg$N2faӜ ó_| G_]H@/ }!;Ü3&C JX 8C{;B[HrRw; NNBqӧ$sN& 9(e!ddӠwgC;wgN)Ӂt^' ӀpJg /Nt;E>__|%/PBJ/B~a/xEǘaޝ:{8gKX7'ޢ G6 9='yrrR3&dC!$T! DEđ(PHJ| Q}>9 G)RJE"J"@4}_H'}>@|A#o(@0*{0{z H~RJ}>I| >@ O$IG)'U_"!||!RM3(( O 6 (א^|'IKނ=M0^~b! < ,s(Pxse)C$i2R% "PA&QH DE $TPBQ^< |*0mRESDOJT0$ x ~O QJ$8 H0'* /&ˉ@3;8 w'[N *6}I4ڤDQ)84'nG$@U \æNg*;:ٲVŸ*"FiQ>rx? tR`|G' >"*e $P ? p Co4ܥ;ԦvV,Fiy?Il$[~`FƤUJ7RD|7QI %Īԉ!Q*$ @CRCvREq+#DJ 8idnכ^AOgo1p6Q@!aI6)-|E_,̕i!b"Dl?lא4DԼ j`I ^M`L "0)z4^%H0A nwrRP&UJTM]M)4[ (Q3jHnӪ&1 ))$K5U$*T1x#MySk/i!D7-CWI+E)ƝJiޝpY$/4i<"YR%wDaB)n4JH:- DO@*AJ Ab$D}S̈́#Q4y0aA$B- KΗis̃|ʗ)6 m/8mADAzsz|R .}viTk(POX" FQd1$:M )I bQ(/ B"@h ZwiI *"D"լ-j8f8t-]dH@D *SqP H˞ml A#̰iE6vw(srS1yӒ*$$) 򶰯,MBEYSv{0^<8vv;+b/ ׈1}&ܱl!t[r[A(wuswv}FQS+*(Ձ_KZgcun^dq \Ѯj"1Qۗ5v"ή׌|)-Ϸeە}^ ]nͷvD^fkΡuܮi[l#l-DFF%FFխBci-Un$}s9Zo&o!pp4,w]Fw.뮻1#2̹ݝݶMꉻEPf{]:6y'h;^ĥG;ˮ|jMxs#9ŀӜ1$14N֕- xNzquȻ\u;DFK#M<nRu(#F} +̖7 jI\2y } ǝ >^WmkуGu]tɹpM;k# '9;pw.t.9]5rםsھ8s$78@ U@Jxa2sN6wW[᷂wBwsnRkr#\;k鶍bEW74LĚIwE.롹pwtb $s(AƶZ-R(65ܔvbmsrv܎K6ksprEʸ[ThlG+Q͹9sΰZ R#R׋G\ێ[v^RW7vk6Ʈ k(2R7iQ.kwhܹfXNh,jX^uն_ϵ|wuL AE|׈рr\EdaieV(&1.Z4Uc黴WuvpX".]u{wsY2blbh", iAm .q̤%<TeCHyn[WsWvֆŢXɣ& [$WJ1rWk/;vW"z$ɮ|XѱLb&F˜dIFKŁKR&鋇M6-Ջ_m_<_\;WLTS]]WFvrv[rӹAѠi-FdMFEbNبEYqZ%KK,<#Ul\.t[ZQAd؈3ܤIhLhr11\/˫+[ֹhwQ1{;m_+vlQICE\آ((dmrj1ƒ* \>oil-o1zwyjkBd1bCmTiݮlʋIE1EEE]+%`'TCіz]5jk\+$R`&XDhWw;hѓW w].Q[U b5TXR fTF hƌ"HaZnΚ EhƊŋFnuṻwcF1cQ]wv5xEU&`T(+ldJIRz+{r:%ݺ&JءKDTi2EvIbi)"FIy]gq;^(7ooex7Sknbd(E(dXB.F l*4Z"4)s%>r;)W}]ٺbvuus^rfj[ƈ؈j"DPFƂ-c*+Elh"wm_u4T^ssmͦھ#Q6n%,b7wQDD#j br) 'odvC7q˷gm[cd-\TPX64Q"5N ۔F ]}4xn.zlwqsNN f&(PDh6(K%*Ll[EPX;7F;_)^Ly QvPmXlC)tƍ FƍEnE(A`.ZB)5E+W7xL`7ӕ׫y .أMƢ&ƋBiic[*JxxZJ@oMh2TV !cI_51bȆ4h4XѢr}3r5 mĎ]ӫHWe6b(dZI+Tc64W7|׊7ntʊ3Xy"r(KnhѬj ZLljJ|ۈ WwEX}k>>nž/ծPbF(ֈQhd 1hAc[={rg;zN^%uΫuU4[Qj(4d+FJi*(mt{ռnk^nb(ڰQf,QJlhRP3RXE̤#ok^'[r-m ޷v #IЅ+EQbUX}\q\*]ܷknFQcF1i4QHbƤ,l\ TDF)#p_h}hf[]9־Tk^1,bʹi61FM FA)|h^4Dah4b"ͤXJ -ouv毤sw5,WoWJ8s[%$c2lm-&̢KXDc}%v{Xu&sh #Z Y1h؃IdA eb!Ǻޕ"az܈n\w[6'wwJkbi( H}|PɴF7֯|t2jbř`(DY"QXK&%ۘTuoKrmmWLlc3Q(1d-׷nKu܄4ɞ]>U^5H Anr DA$bĕ Eȗ۪J1RQBi64DV"boN嗽ĢQE,lh`b,Zuw{D"K4F5|Wa 0;fEE2b&mh_p+xE؏k{lj,R#ci1bŢ *5}W 'M]+(G֮{p%[t "0lRV E 6*{ZY=WNhlY6 hɤF-2"zQ=7r^nLZ^r li+E_.Ɖ"ƠWվ9ɃN|]']w6黮F*Dцm`Ė$[5)+kݸp,vڹ6",cQDk&41^ƽ7\ԵzvmrFѢ1F%IlA QhѤnD+rݹ{\#OHWCE5؍Fhؠc-lak^r1hhM0IFn`>7_%nlkp־oE6,b5)*LOKmPZJaiV,DHP!A$TX"0`aeV M&.R(CEb"4X(ՊF $RjB>neK\[FM:FѪ*"**(bX+m}kgO(7;EڹEPk% Fd4(s7v}&E}b r,`15I ւ(hn=n%ֹ^{]cb#jfQRF5zvh׹DE/m̠QhFѪM|kq|mmj 4IFرCd t5ܥ6[ݶELIY5+c@[!{ovAC`V(`UdPэQLIƱEFJJObl8h,V(,NVBp*J#cD5,EMU@h"!@ % #E$k%%F liO`{sr*֮Lj4FPd5k{\{=\E6)D`cQ-=銞/kr mC!5bQ5I=꿘u\ɤzWkF5-j((FDE/u׺)+z׍ܶ05b&ڈTT`0mޓgRi j2J,`(-5 +&ѣQȖn{mޖZۑ"*+$b AQA*oIQ4V^A[ޛhѣQPX RZKZ2Ž۶A+VD#Q`bcۖ{(bܩj 4PQT͢d>J_tIb-F1lQDbD {s{۰=^uF\DDlX֓A`7UI\IDc-Q`^G{݊%^5骹h*6+_wi(1k-}&r&T1IfC{]{^Q{Ƀj*J 6 أL#ojF۽%jEJ( "b#0B{7k"ޮ*,okn`BhЅIcEonݽMxؓ=4i6dRl1XPQcbݫ3g-UM%&,ZI,+i(m6"/tZoq{k܊LovcEPF #*j=x̽{\"ܶ bQ5@u0VOwֹ%("1Ih5%{׈`&c$F(L{6^뮭EAIIEb5E7{Bj] #\a}lXVx!v)64%D)4*Ca)=ۋ ۖ0^ۥdƓhԒ`DY6)+ۯv/gua5҈4b$cTGb}0nY4bh`14W{^=ۢ^hVb JɍRX z/ooZm'E0ih%^7 {nj{&Q4XHmJ\6*!6*FTA%w#齹tF`5lg׭-ֹn$4QQQ"^ެ֯b u^&@h4%k=*7q(/k4TQ) XѱŽv/jXTbɍEE$'pj{sXmX+8f*f`JMQ*1^뽧"+ݹKƢ,EDXLFƈu{naow4{scbcQ Ht4X,6d @׵ڽKxدyF7 5c{{o混+7-HE4!dܽ 뺽^1]2b1#dŒRQou{\s^4Td׻{ {U@Q1XF̽{UʈcHRF6-ok7vZXdRMIeAF&V+Fcc{xG(3Q5ݽʽln,`,*d(L Hphfclk{ou^,Q94X+5r7B\Rk%#{Eou^^JXI4}ۅ{tbэ^k^{#W#dl%5l۽u=d^MF-,?XwWB߭\Z* {xucW4c Th ׽{ۓ^]ݣ{ʓ1Tc ,w@UdQ X&$byokk&,h؄Q(n6MmZݫEQ2n^{k彮ǻnFfM QXbz^cݍ{5W Id3u{JWADb)b纽=׻\db,XF>_Z\O">ljMQR(Eݚu-b`¸L'Pph(6(jLE"i6UE $hHY"62^)L{hXP~GGnG\XDYOWFZXm~ſm_WODi4X#6%t+`"i b-DHX?~搣cXl_ߍܷ+FF EnY6A٭QiKbb(Ƿosi_ȬZM^5\Dc"h 4T~Lk_߭L̤EF4^ob׶/mPDh1c=p׻n{{7\%WOq{AfET},gŷ61F/}+ݽMZd-mL{Ok{mQ`IB *+6T 0SdfhMAy^mĖ/k=r#bƓAE{kow1^ۛm˗B&6+k_?jj4P_k搬h#٤ b]"2 FMSYr EQ 0:"9 bAH) $ӈlQLƋ^uBݮXh'ոI {xr{[29" *enDF+{x/yݹEb\&Nd0*`AvMDvM(ذEAdX1W%AW%a8SDRlQ~י_0EsWH?rd b",6vJ& "ł#rk\1fV1J8Y=] X*!PɊBUADɀd"䨣*ADAbGtM ͐6Qo~߫U`PrT şs_MOPl풿n~Qm,`)==w]+TEF{ڻ fP()&qJnQQOݗ?Z!H(JLi 7~~ͫdA`qeIYQa90r2,Y/}{^=jU-Gb6"C_W/un)Lb(@DX(%d$0¸J@rgܵEI_wP~oڸ#AL0W$*$PW + !qb9RV ݜfCJ " v&ћ?j,"3PX"~o_ڹ`/תb5iXlXG!\H&W~܈/ Q$X+d(+frbȰqYJZQX\9IXE0Èa09 HLK`K$fL'%dNX J( DX(P~o/G,h%2L:` *"ɧ3dq D (S qZ n~/U͊O+?QW8+2 Edd00()PS/``&aU ņ2J*%p(0 "(08$qjJIY &E .LTDPPSvq4:[M,`Pb#rQ!X #\#L Q"wN;[dF! V,PQ2̘qP Ka2b"(9 2,dʑJbYXLB\.@.*L' -Wؐ_xSDX!QrZZ&T0Lr)0\p+0)u2b&I #LT0'QdQH&W&C$9V`U1L&2-p08,LS dUr4rQAnoќG(,Up`dۄ pLaS1S0qaReb̙%`TQf-ÉT"ɐg-`P̓!+!2.E X aX8pPP*T\+&!YFeb \%XL'%d¹`̪Řp+̓""QHJɆrAJ$cS qUpa ,˭v@ U7x6Pd"̓fEp E2qLL⣆XWÃJR;*: i@U&@0&I6((\+Z3$*d/rQ!<pF Ia C:Ř[`JQdaQ0\usBbLG`UfH#.\*`T%TpUʓ!HT0+2CpE ,Xd)(́TTEfq0 ,W!8UNK RE6-p ŀ\*(LpQrL!Y0,T,kFE &)TX[M; C+H:m6 L Z Uc!vAb*I2(2[aXd&V.TG$0"1Ƚ%@a\C+ C56MJY/~x_iP L N\L%J"NFhЩ,WI ¢L0' %R,).D $`'LKIr)rZKMPP°3!R r8L0ALK[V (ST`)80\2rNFGt*1rQX$Gtd gQI008%L\l40ԬT2TSdJJ121. pQQd#e``aL2d:$¦Rb\$\.& E2 <(]͕݆Τ*gJQ 0[0r8eV6WHnӬTٱ[MXC&I&dH)! &"*a\ 1[B桲qDa¹*La(*C!0XUQq!f +UV L1T+ (Vlr2`-¦@A&CS*8&(Ik Pz9JDfJ̬L奖a-`aS+`qޤC+Oo4*l,TbfL2 *AqaC b\ Ʌf&r aS%pHs`.ĵmvs8).% T UV,p\2VWd+%\V"aSef]3xۣhR٠q%fViZ[4`.F.IJd8UPrsDB*+0pW+GTa0S Jʨa\Iw02`()8Sd!eLQcULK\(8B욈u44LS8 l:j G hl:a)+ t`&S0NZJ &L0:D0:YEJ!s#l-pݼMd;fa+2o)6)PNsS#hM6#6hkKn81[E vڸ(ej(qE5t,ҽ D8eU0Ird̅H0Lp,2gLp9VQɁ0D-I$eB8SXV +DS+2* +ak;%^0*3{dt4hIQȘւ:A`e 2^100 :**Rn͆lUc8+V):\#hI0Fd:棰:aRzTR`)QaC2(/RL &J"DI*V;ZHjqo(E+U ك02tUSWB*VKsl4GdWDG!lf[QA^ҽ3 dAX`+y`CFfIX\2`saTHDNM*a.,.jsE4*@2"`nv+b`BܒnQ 3hiơF.͚bXhf )s[vl{E E. qfLVep5]ٳTR݅Rer'LL噼t-4"_/VfedڕTGkjͅ&øLX*gSAn*PvxJ3e4e;x٢[ 0ӉT+q+qǕL*u]lf@vg4衢񇷓a6;R"{ft֩BPP Y7MPxXʍtg06UW-Tv)MT؉[lc ZLR 2```_@u ؎]5tEyltRl{J".blyK2ul{m ik5VpOa82`qXyqž4Uvk&590`0Xel0 !1Eيw-+5flS"R!s G8-T^e2)Q*Q7CiZSLZ wx=}ŖOg| zhtklUZ2ryB뀕SQauiL ŇM PC<ӍTrȈs06̊iR <{I녥ȜÌQTRo<]SQg2m<>:i'rFij}Y8fc˨ʑ33] I] I56heqNQkQѴЭ9\Ө4(gNIž= ^db[iǽNy*벸ÑEI),8+0`t8ΑJ{StۥͰo6M;=tx> xftݕ暫Sw{ifaLǖJ*QU.{Q-Rvw͎6ؘ\ M4\3ltBW4{uдo<y"'WP3Zh{t3]D5Fػ3Ej mQ|n˺ZՆ-[[U=i_'8Bݸ.L' -NyCJnWaX\)`xݴx9sn *xO=Jǭ\*aFơ7-]uMa}[y-]63Gn(ѣzi/|pӦNOE*zf^±@컌1MWumaÑ̙:V<.ҚsXǏv PKe|ч<(+ZRM7-;hg"uJn 6Tc usl)h:næݚtbq 8ѬD76uMQC̝0^JT.[*)|uN -1T\ݮ虰Y=|z\Ehy97ϧ&DM=9ѵy;US{8=i 01t.igrb|>Ғ;}_">%Zw΋ @jn[D OX=eiJ vg-o4g./qzDT0GdoJd=/vklӔH~!H EX ??sVuJopqb^ӜYD\T(6ՊgbBzVCHm$wT) Ȳq#}>k. yDxB"&8 ;@mā&HǴSxi@UQ^3в"1`CYbUNgNӞ~>u8T$ $<ڻtEp5E:.xr 3w)Zc1+bryo(qA%.:jQe2ۍb˧b{_w3ۇUBET>а ָ4p4ؤ*! 60PYU@$l0SĈ"SP9^#2B $Ad68i!Dfk6R$0m$˴c y~\PCBƚi6F$Ap5YjiL4VZYETz=b8Lf+s;[~-pۙM̽ffsԪN7Y!Tǯ"X .ϽE DX!Vr⑓dnllX\b^ bE1]rXDA;~񀏉+#U :/P#mf7UfYJsZuFf2syI;&1DPdv 54Nj!.ýݜE'0N}'げ0D&` Ǽs}˗< x !mD"m{|Ƨ7]lg&0SExH'[<ȼ&!6h1{/ىC*PVTU(s90:4 "IpO?ecPS FtH*J\> V+^?=@<Oo9;~b #T*XÎ$aYP<2T*U!R:VaY ^%ƈzʮy*[`ƹKTxXOm71fG&ENr4hl83ߠB@9~JLa 2dZw=!I)hF>=I@-vZ۲p8 Hq!b)}K-&!_[ܰ2ѶQ7Ac:fchr Pw4o"Z.ӟw9~Ï/z}AۭO$>KQQu~~mDQ""¤C_⊍i!1JR,bT1,gSRu!QTUXĈ5BZ|tըV\4Q4ah#_<,QUQ*/wu!dSV@#1^$> $A iAPEimC"wb %&0'&lEJD(x3h* T(X:$xѧhI2D# xHB<,azvzgQ/^omaG;KD眿z/ԊYyuc ־nA3$bM EqGhTNRwa,bҞwFC$J<wUYQBfEss:V`5El-&mZU]8/\jQÎo1%}j|aj|q~fbc4%֡0R@#'Jԉ AiGKU-'S}SNy]d*o_!PE>a:eO·̕kx2RKZZSKQ~);N$ ԓAAqyD2"cniy\*K9RQ寛㛘^91p"HLm쬣?0. T ,94(4^FM! `}@Ee0@=\&jP L,9Un#iXƏE=*L-lXǍ&=Kp/sܞgXn dBɈ'yC}j~N7ԻCs'Y<UC}a>TC{JͼENT8vQt3xc wt"tw;_6/ʸ1Do6)D*=zos-y=k8Ѳ=v!D f{~D}hoos~߽!GiVı#5$ 36m2f$.]CPKϓ ]'oGٮC4=oXH3 4m7)OdI:W'D"CN6+ź.\( &ip8N9]QF޸M73cX qQ;jSP{ \VvO m|-ۋoA^8W8 4'1 r=bMqt0#햂}ն~]yM:'-s wn{C 5Ag+. 湈i'6:sn:8kbTXm3"yd Û9[j5zk c1:g;Bvhn_vnsbA?91}Bb"T a~w^ Åkj`3x<\i=dwU"fz*<7aRl541NoԡnWv-Xxo}Hwfw3I\AA[s[t9LaVs/LO]~ܺ\;{=[d.L!Dely`zo'v̢m7B /ku/gEΐq!|Y8anfRuFXSwY#4I { ͸J@@50/H/lBunS Gh#˓u(^ e?7}='=%wMFr|[Tv"-8 {%)\y:DY{&zϹtU9$r|,4|#S7)PtT.ݍc˾s{4;n\.a ۗ/]|.-;ͷqI~b vWw똈4B!>o>۞6mػ[O!^[v?9xwVbBv'y^t8W,3ik-=2h`̝3HpGSwcOM#9=}vvr ( &ÚmPp,9q1cM;G^PX Y!}v lsfӃ fd81 Eyڍ^MÈy L(qmZWwcDEh4:&us8ZOVT9;+ˮ; P( >cF|>h$1驸[SS tU(f=Ʀl~^ŕƥM6w8+a`']hl.̟.{x9:_pٕFY喑dj t Z)/iG޹!uE T-OV0fcMn;>/(ź> Iwn,̋ƖlVN< 7WZo8HfWV+Y\^,nv[-lm[]}# Zo0; zmo-}-橷bق_qkh9ɱH"vApͣE`O ݆_(x߭ɏ*a]ww\L/k''uao^a|6tOx057ñg.SB:A+n/MPk5؄>^D7W %t$fjR1 &"4{pz+;{_ӹ٫"*В*m3ճ4#W 0 lR|1zys7Ik.D߾q}8%xk;VUqJYcTOdԴ0'(.g>bQu!ܓ4YA;ڏ{@őg_Rn3匘]I3#:m=}UVgkX܏o!Aɢ{cvjin>#s35Mw9j ɳVhӖ*{!OKpbpF=I,||?6aQݡpvz\^AYgC |Oe^ Fy{Ѭ]=з:d"{ywBsAIu>A5PרHQvIӃ8j&wl"Z/I Z1j]4SYg}BI$! ?X***4c\ƥmEB$ܓ]r1 \K3%wjCM؝b}o9ޥV^ڪM!!WI)e؀#-G!2 /G֐D7K)#:FsR9i7RYjG/o|?>ɮ!"RGhw>~r_\?Fqi^e\~!Pak@kZGԵKTr}Y﹈N*"*%`bv>{>"I8c-ǁupwO+까[ƹXT[$oA|E*LdgECׯzĴud`jaOw]^Hr*BuYtg珒j{{Qu4"m+ymv:R  7rSqyFI NXŦrrΚu{wwg>MCs;3q= Km Yni~ۂ:eBυS,K=|?uAw[9q u/~3:lU3`1C4o湹G/rFܷJ$s^bU|-Ar9G/3=yՂDKisݴ:>;t͠kP"L\d &d(.G<4Sά-AkNJLQ~cKCp+g\~r0vÍkw4ܦYJX(|ҶZ"^W-nC/Z%U) :FQuG dWboܟ8eHFY!6\$aI%o:Fw\wsXE'>vVGRӃU/yF.VL!L yXXMo(Q8w3OĐ̌*DzsyS)gṻޢc엨>8 Hv3ڠ(QݧQf/E* :Vt9qeg{;!I}@Ḏ@OK ܳ|\VX>P)SiYO=Ung$Wy6Q_(1'K a*oSIĩYU+ {B'(TuA;jvʽ[*1b_pmGךP>ײ4Yn Ӑ*Qy]!$ 8C0TsmDҮG* ׹[ALjDK {fh4P`hڇJEujnh#䇴?f #D!4|b{ #Sg6w5zH|²c tyӎcwp['́ ϘCTe_Bokb67t6)7!#xr9Z-nI^;eWM%o'-cӰ4!*#qCR=aćDԘ!9i֨:^m/=ۼBγ!UEEdv3Na`XƴS#Jd(g`2q9AIPq+ (*jk¸s3 ! zr,a.![V]_I2H ]7$0dQsz̘P4$3c@SqkaGPV"Z+iDvJMPwBK&fF$i/H+I>e`iid2u=r!ffX { ,R=y/<5݋ ;Ξjv9dqk+W^,.o1F?;eiKeEQEESqyIWEW/7bW7bubS/Gzv (k#QoU5U1 GjQei|axvߥnS2cCb6Qct9N׭!],c 1p7,:ͧdvKKF{Cǩ˽rYC!g{ ,,p "X3Q͖86f1yg%yexɷyKB cg}KD>#SӜKJ f^C}0:Q_^^?yLQٳ\%үzKzpQ4ʜ;"7{!n&寺蛲;۔XmsÉ''RlÚybӷ1bK9Ξwr:niΫ&u J{;MC|}>9Y}'j 'uqcSZeƉ,Lq0<{ԡi&In谌NWf_]%]lX4 "x ɬ-ۛÝV٤U֮l5 =ӽ,Z-:yP=c͗BQ{r<\zg{H|`^h u$f)RfU.1Q}2aWٴK`IP&,;b@Ͷ&Mәïr$ݶ˂toۻ.};Aَz3f㕘,oUwj{pyooq&y/}݂zFvp\)d8dWu#[\1Nˠ=%.р7m:Yx(R ۨN.C ڽN$lpyzW/>1_lZ`AoP:xs/bmh0>۵=q,euow@Sl */`=m ˏCnyuE^|nj봧qbvsOG.M -g9ьe̋hQRod-37nZlLwyq$B1M}|a/HOT1V\:߱Bt)t_^ zG=g^a2^cًj{W޹KRN wL\Eu9D53Kyc:>w_emɇ<&Y}w=m/C&!:d̹o.j`@vM0dܲ}۾>]`Kѫ1ͷuzwUt_TuW_ Y}I^i= !B7Wivh;;ou뼽Z5jSyĀ<$8Hf[.abFhԞ{rgo`̝mIX³7x}rڞzz9ޱfNίLaJ3q߭޲X˂M˳9g#wFj_+nݍ ,mFn=.!uD~;/w ;jEN .ԧmɯR['#g";&ҝY{}Zŗؓƾ;;JXͮ{ٽsO6U=1kAX .+BSf?=܏jb@zQ}Zvw vH&ю}t8AsnwT\7yGuc=->W.mȤXyOs:ά=ӫraE>o0& {㹽lY碪K֜f,XFy^={;a}زj=U'God2碠v3^DpYWدMBHf%Yy>A*6082ƞMx&pcty1ھz{3/ 3ozc*J 3oewצ{Ƭjn]&ײ}&AϷ ݤqxq%4\42 !ͺϸfٗ O:1mDP{UlKݳ .hL1oxok[`)@'QwtX J3םv{\H;>5E0\ͱ3߮7TXWHWHF]>{{.{7$zM[-|u^EƲ,v۾̦ޠX }/Uu>v'N{k{)u<^McmzLX{{8WU7SgگSi;=5Nwznejڲ?v#j,z1~;"E|bۗ{qXfz\2B} Ѿ]Y^5Ţ/o_!?*Ty{7xl}QCVYfvz wF7d;~|ogl, >܃x&2ǚI%ɾ9OW \yYA =ͳ)7X]ۏ*0l:&'$H"zkF%A͜1r}u+*rpS߭s5Ws}+k邪oy%d^҉RP)y]AR9Hi~>$B-{ۅ]6gɡZI?|RTUwܽLP*mȍhUmQ4 j%(2 : 8ܾ߮EC_yRqQaĪ^2}Lj'w/&$*&{aEM~Md$ߩQܧ_{M5]4h x Z"*Omo*,_Xy1%C& ίkůJxMI\*XNNzÔۜ,Bj 56B+B'6眳JBgS0l -Q],4ߐ yB`@~6 ;Fd9i%id6kI^ɭ1i59ghqB>$/R LfH$YDpY's$ $7ocR9[{KIUm"{z}IשPCPR '\1kE# 2Ufo'88ExT脗) : ղZb'BAA_V=mu:ÖU>~xx]lQn89 4oғ^Ӵ쵐޿QVx$QBG.J\no_^=W{w1^xU<5$yW(˝<;CV|1P<ʼnHC(<ZuW}ۧ|*sMdMb7-n~(wt3%rSL,no7yr [iRJ()T8eX)0"ٳHG!mj !LnV-h4C>Tp HI2R,"D JbW;;*&`/ŤcjXva$n{$. ' W-4|g)5Jʊ?7qѩLIEUmպ. , >hz7HIxTSs%Eǻ{g)pMNKeW*ŬTQ196CPP(AHōF<<"l79>f"8a5W#QKCHʦ0S+m'٩C-,-sTeTɔu3qzh7g(!I!ӇISnX}ٛ}B =k:ƪc_Z~]{|o}\z/o_3^%P+uT(|ʑ|Ӗ_*_-Wj5#TE܍Kc)Pa^rÕ;h^ suK/ xq*(+%HgN<ƫS7ۘ-%~ss]F\$u)C>>${.2E+i:Kd?/Ti[`zDM_rga82O%JŠ+=4~3}{ܓ:^[1Իl{p R΅,vv/np;3 ,(V /:0SHK{/Ko܌?\ڋlb7dRaq!'yb~xRq:Όq11%D%,卬}CXwkBUX,L,$;$E@{߳H~WFq-# )~v >zTX\Ct,Sڃ0:*b QOd:09㷶8:o}Y~߸TܰShh2MtiUl=Quٕu~<|uRj yagP , TCY/zrJH'u˝|Kۣ:湣sy4nwwpRw$ʇ.s{/Es:?fǛI%MYSʐ L=XZ@I:wK׺i RL~]#`QKvb#t+ÇUP32pc Gj TѢ\ds%l8!㽧\[1Dm>GȓkҔucJV!1dX(1TbZ5//=v|}C+>J:<*tda!gw(7r "QE^.]2PfBQs_z7:xya1ֶ*iY$%#Z ltX.[ڜ:~H,YF>l Ed`PjfBo- +r.T#s#۳*!=n`~h5.JaTnڦ 滝}gO&[%j(u*"H͓Pջqs]xE AH"/p5:g->FO)wUmUQoj[t "ɍaqyNjE5xĕWĩzŒҢaIVkGE q/==5.%}8b] j랄3mk%LRs>g_{.L-f\;[ yDpE7F+-촏Ox&Y)eƮkԣ|ć}4ʇͪʛqjݕ[0C6xb,k F, }zF5SnhyouQ cu%{eS:QyA򞊋4hQ">tK"'KBy[6["[.K51cYab:?^ži_XRoqMd{q_wjԵ%8nCn.@-ITT:ԉ8j1aTη`сGHVk@G_GF+Wy}rkO:mã]xGf).\ 9Zr#^1;;yC(ss纟Aw9M2i m/y^D<|k 9ؽX0$2"!rȵpF1ڋwj#в"^LZras+QPW#7}~wr^x]Bw2qchz>rm½[$Z0ż.+rV}Uj brbK-UCN+ ޜ,';ܽM9n% Nṉ:;/Bco[Quce!Q)Sj?)>*yY*6rh H̐,SQ < lzz+ Kdnn0)鸨flVz1O]lX<1=<8uk(&FmM*0xEr>{JN3X21*6AHH6S9'Tzw41|1ۤosHb !p0~GwsRL;~kuMoÒ=QWI4ԉ5b 3mB}>{ij<|Fz{F3k쩼;z|AӊDF桇to$_PK,ck-K8̗vxFbDyLy5~ԙ;~1fUc)1WnMAha=;=V`B hxXW%efKmƣxF9v{}]3wZ_]oXZA3; ݩ7xF("\29PZ\'v=W3.Qxvrz;9TTeE=_HٞZ!{˵v uxHP}Y@Exj'~R;N/^. PyW"2`'Wu`d#߱QDP@o6׆=ms~=n^c +R;=+L.]J1!SBB띕'6Zvv6v X7wtM3ˤѶ{:rO`ƴM3b8ZxjDGN7v푝ܼU ϸ7ۛQz̊tݒ |c:6WeЛ +p,w!2>}}7| 3/^'G[[5Tz6='uW᯹"H0^- {cx]2k3m_ D^MH}/)n\`;nsviw]3w3wzW:7}[l77pcU⻺~`;2vK֩ ͫKѦ!di73䅤&&5!X'4˽1er{Ev}*v31pc"zfiB}}[RH%o7]N#zZ͛٢󼊢iY%2u85G0aK$ٖpQ'jD,|_mn) {wy!5תfמ<:U*>P>^Kcka "XajG峉2.rAa^kY"`E((wԜd4jSⲔdĐODm5V0QKꏛJiZǷK[׆P5lF2h3޳{Ą* û_baiB/V/Q)UZ߼DzMTeq2Mx ?|q"uoe "&Ma$BHhuH)I'<%N5_rzϜ\+o;I8y>HTOeߖ܋F1J׽ܸZ (k\rПw\ E})ܥhT 2_vڬ',9j 67_Vgbf;6TB8D+ВXl$$? X!΁m#"e7Y0ii_d; ҳ-}Eu `8H~X"XP) ,¼pE|_}?*V8Ss~s׾=5ܳPv*#@h:eS)"F:} (,Py¼ULx[ͽ}+YQI ak!J.hŢ WJ6dA3[C*  U8+q|';B0CJ] I+mUzMjvۂa>$ $$'|"EOwhb$; !2!,L %a ~&oZX۔+bl͔WihqEtqLH)>i`#ea| ۩^ Dy(BOu&2οnjf]! "(5))YVǟ|&0dVHDa5Xkѱ],Ad1#G]\0, )8-kT;̻c%7ъuڗ3hw6쇛So0(4M  >= O~ >헓m׉9pNCԋ> :Ƭ`kYZg4uj1e2wk7{rod M9Ck#>"Z_@'J60TNn<s}Í|XBOD4bE5YLsEXqO@*= n[ޫx$ɓb4a1? rN9E6/ b75$YNCe&!§ϝm3GB$1^L3yT#_']yw1O;wuGJ 9dm*O5v6X XLau HIlkž[xmˆbߛJ i@,^"[!^P80̡8&ÙxR4Rэ -ʼn\b$&t\nb5G5hOI$`A8\YOq0+2FHT%&9P(Jwδ^dcOSI$bHHφ8^$LLL?2EEcyG󆦍MM,Y@hY$Dx$w=yzd+8u0Cd@ B9e@y@Aw\E0W.)II:+9j""'[S⩄1Q{yGB~PX#N^}0 {:qѢcNTswaעI i?bP<$pu+jZ}G(V !{t~%nn&_Ofȿ!ҍJ5˘|s+=3~:èjByQV1I ܫ+I5>~Aa5hcIHF`?.HI/i’<+Ӕ8P/lNJ+̼jXXkrws[ΦB>/Pjǩ/c*^ Ui$& Exs]9*IQKG*T"cC9,"h44kZ^fb|ݐ*  RjK;ٛ,%)iM!͐ϴB#Q'1yjm?ZIK n:]$%`[u.9qѬmWZ-ˤ Os$~ۉ{g:BםZ)traJ_ƖM d!7i`F( W Yfز)H x@~a yu9J$B,+un@E=PIBeyZ˙36Œ-іogjmyD^>ز޼uF`0bh)z\f? ^]Cr-1vKv~JU1ES;yeP+Z[6oy1ʹb)҈gwII'v5Emru mZ~*e+V´}˰cIҪM:c'#6ӬQ?:;5 A}Uz^jS$s2϶H5hNʍWT5Ŧ"6{Ȃ% N.x^׾&hAnuh.s;9sH#7xC尦D22 L噩}BK3yooowݻYaKt#r.28ruI!yUCᙢ C663s;hfzfc% p)ã֯_pwޯWrx x3uy ղ!W딫{d99>W+TnڭK'g—'P/k3h]Ge]Qv{L~my6%]:>Suo39ܜ }byG7.x=ɫB]B7.7B\l~'Ӗ.¤~%9loblT羷@Hqf8Lodi1!KyMW?m!؝w֥qn`K|'j'ǥ6-VΦkFPL틱#7bruiŊri^6֫# b8K氞V*r!o^Y;/L lfѤ=s2s5w zl?31nTxvuFIO`CS:UL)wOۯxbFEcW]P#}ȣ6k n%n2wqְ/yf9^ ėAW^nA%^kP{'gwBHoYp}L>ji dWnպX&Jx9{t/7>B6ao=/~)U+n}>L=Y:fߒeR<Biuvxt='ꮯJ4*j\s(2q:}$}rQDyɲD2Ne-w&vKrq&Ųemmr'!g{AP:% E2O0>*xzxՅz<;R+mK$sX]3]3dH'A"tMa,m1onM{is)|xwk r[z%3ƚ>ی4bcԸw8<(p5 L2 B,O+3ò:z^cF]e9HDe^+ ;Fh,gهNDzzmiQCuٛ^X˧Aש햽 E2J'g亥 x['{򕒺'=%am̷(=N*vNqe~0iI?WoXWtgxga@{ nY o\ݬz6 ٓ.?hȇNS/iHp;va/C]f57ՈNy9$ն뽅\}Zl,, ]הּdlz%J=NHfӞ7^s#1]5!L pYEܡBZY9Pvdd+Aƈ[XD>"p{zdɇ)c:ø؛2v^=y}K3sbFܬ;9Bz}G=$InqO>s1/N&q{p>p1 LvzKy#/ njjbbl#bFzw9La{q凲=96e ىWKSD{/S9QE4/S9wMaaǝ!u+:fJ̝\R׫Άb9VQ̖c,dL%Āwl/ئx;kxYXshìG)aXy<#qvxucxe^}'cلN$٤ ˹_^Z3n)Xa{!>|{D͞\s0.K-ķng= M>{5KzdHwŲNҎÛ7Uuy0yBjjoo&׎Лd$&uy4Gnw ަxfG(gڵ1pU:w;z V ourT^bHOZ<%z,UsnaP/Za6۔ui"{.2&H^xn6wP;˖-c.f`oʧUYC:،ϚC~Gs\+zAp(аSm=ɓ܊#')TO25k+ !P_i}q+9'$5:h,lF6 E .r 2@kUA (>Ft)mk։hz @dptP:t V aJ! KH WBN~@R19A-ȈWNۺ.1 >È&" 6Tl:SPwfp@FADF45@${Z)5&`Mʶ} Cܧ'RZ3܌taG&l@>.n`Ry8UQ M9w4N{;ޛeDoFvtc=wk?_0gBd>>oyT(S,,( (|!ʥx/xs)fo 4^"haqdXH'd(=k<}7Ko~E>d*H(EĚ~ߊ΢mj6n!Di ː0M h7pYQBu8iN%OQ7&Q!DAB{d`O9iyڽz:XI YtD amz e&t: $o2D ߰ܳ3=+[gL[;FtveNSyg׫ܿ{׿Wݪ,h1 ,8zؼqox=|,[WkWHF(jhwŠ(rŅ6Nnb.s\܏ga׎o8e[ zp%A9<QI{ͪe>{zr'liЇʹ"""C*Da(3(aYM{4JJ%YDWnQ㘆aRw>hw2fgκϒu^rV}W{{UlZpL!Kk6qG{L]= b|$< /oZkܬrQkc UgƏSP/Q9x QD "%H8:Ri<hKI8t@!;>I62~5LOrǤUBUŔD[ݛc ZXq>jg'^Er׾0UHE!FV!9K"L"H&~Aj{g:PH9ÏF7q>HX!B`>AQWuwܢdbC>QVyi)79ETw[/iB6D0}N`HTՠQ蓼O]3˘/+y S㔨&7 ~ l-X4.u㻚-~جFV1ƛ"G觭by{fPoFnsjH3WrٙN }::ĭ+5g"xK6G&{|1>˸3<|>R"LO ٜX׽Bb.`0:ny%/z '^ܒf8$ЊGzrXc-Džf$u#:`DwLkzmgY.vVGio*̻z]ė XQ8sZ: g.#|֮?Q)pMۣvHi>sC|LZ<U`|в*p?k:7!6=<²4z:t Lj:" B}fggCX8m&펏ۛuνé>~{}9E}àsa[.14wL4upF=w'6PǗlL(WW|Kk,%6>@e fbRr+dzݝ']瞗Ggްfi"+Z ncu+H9zxYmg՗I;be ejwtClXQ{pm(cNQSNF#zǿFڏw5CcNp 9xd-ӕ[YOU4t{J!jrAm_YZ-{"΁#}jй aܢ"ŴL?ewc 3'h+|&]o7;}T;-۝'U󽸬jntqt%Wp1 OiU3xAݦdݯ9Xv=Nv隗}cƻ;zGvXMS*}SqOXc>\s]q0rTRKzXFb[Oax֦7L< O]'_tGŞ`p+tݚ:;kh9ټG]tǎLWÙ8(A랢 ЗzfQȉ! }}E M>;iŬN (*qT]^l$:#\Ry73{9-{آiEػPv~E+KdfT"+_#:]) m1F4-jLswlz׺(ցz$ 'z\vVyBARbuH:A 6S\]n4X/$Oouy( p y(7J/=uJgqnY:\w;s*tpJ{o e=pΊycvmr\wwaYޖqԖxLk4]9}' T!+^gZ]{Sg.vS9HM[47&#B*~s!_3uSGJ爾8h&ͽ}{k a vrR {ۅrԏүVh>; ;'+y 1-0^0wbl 7w?LG|XB3Jܫ`eB6ԞU` !q׳ۉ2lDtCd8Kأqu"͠-!?;}J`{/!W"ON#^t=aqcTԦws7Gcoj|;%yȲ$žT<ݑ^W^zqY {OɤFZwGv{}̓בz!Ø Ch9kn|׷"A}K8w^l~%,<}%vhPq3{đZz Oeʎ]ܷdc:Ɨh86S1zrJmR|G)Apw*GK&#y< h8;N-Rf$*ogNM/v8=i v)oi1`s=xHKh6 zz`SE~ykY0171yz_|{ľZG =40σ_sY=I:ǍBKAr".D|;`lÅwSe sޣ;x1X Z^k޺smõ;l;<,7HձA)DjeL_`񶗝hn)y{L邍X<b,t)ǃY2^w,.r՗{jߑcw*gwq◰z4Cגc#J&5i 4)yͤ7nAhOcm"DVڞ$] blbm2w,F^o :Sn}'Czuo{Wp"OS6:mʛSK!nws/ezz猶f㾍P*Ʊ?[Zx} |"s2\S&/tskã}p6"TQP*c}rbP٬3iܬǻcXc)F:'aO>heՑܞ| 3{\\C*P->a@!*hhjoy3̀4nf_Eb0w:5}⏮+ t[-We_0D~Ƿ;"ݧ^5 ;ʝՓv" &fV;9LUM YmV:qOm_iXYpZR}nu7fjz}r7_$pt[5ۆC¡>q>1wA O)`y#%ʆsxg߼Nd{ܧ`u;w:/O=ѧEV'\3=}Kq&M kZ㽞Zmk8/;8vom,yr ftcuo [ǰU 亭: 2NNJ`tCL}vc(ɗi[U64isպ<7=|}Sgq hl v㻈zqOK3sGwhO0oxjU !ǻBrA޾Uoݓ2[*˛ ]`iE}/zi=]:an8*'{Ab0هpk+UxQi2[9ji:i^C<[ّvӽyOGO%y;~vrHOl7FJ}B3ټo#+ x v֮# x51 RLH.2QUUnf^wݿ^q1TVŵhƢ6f\س4EJ"wA* ,Y'-Em"1c^ M7@(m)\nb\nt+!8$ >'5yMU0H|b[^S7o,ma3G9\){HuȺi¶Kyݪ:>Q ȄԣYͰ8<ޥk(y}Wo޾E̹;%x4ZvMHh#mo|u7"yqH %_u/oKLY)_i0/39{:~`u q9ªE>aRO/pl8Ǵw)+ mc_Bi˝B+dž7.x<ݤ2VEM2a)gvԟICZ })dzm­ Grw2T9$[8I'Of2|AG 9'K'VEcf4xMG7PoN>7=7H|2**PTG,w'VCޭj(޷-W[I[`FEx.-_@+b}yN'*ֈ*-8<+]Ypzf2{=v`C0 caIרⓨ<I 2Fqbaz<2YX#ߨQ:)+鿮5JOdQ7e* uP~De|NcM4^RԼG!R̴=IȤ&Pmox\騩?Y""X9Xrt!DbAy( E[H$ܵzb6{J{C9e4+Msm7[tu!dQTTJR*տ[O9Ss{@!lU.h֍dsou 2m0\E$Xw]sX/-"#/y^˃>Ta#@Ma׍ ^,u0M $d; !?1AQ{[O<n3-eIv^W/(g'Im5)aL,F QҰT!j]A D44rۍj 9կkܵsvϹ9~@DqJKt/EIiݚ?616oչkn[%x,gwo^ eyM; NԝsuYהV5b  TX(Un$x]:U{Uʣbhrm\X(;ṱwn7Nj|Ϙu!XQ\j4Bu)q^]9;U$@''@ȁtl>DM-|Q ׾*`.p(,YAMx:g <ׇhUc6R$aBqm5Cv %xy/,gݏU^CJF W}2A |wυ} '|7*VMVsxUOxKVVVŌK*KٮyZo!0 w@6:7ɡǧo=oh TVٞ윬q-` sSpᚏd ޛR7yaxx/7wN7s;;"l}myԜŝǖ0fXb/<^V[o`vAnqk-xOf$3Rz9#=EQC/ }->`Btv+E{q{dԟvf0/^<⸻֖GW{+l|/9ؼ(xLPDLټ]hM˛pj.I~!a/ 2k"<-2sᲬ>]*<26oyo\_a8b]٭E\adFxAzKVݴ C{yyd[JFKeNNbo׫žkW q& nvᱢ)p)Q́"Q i/ c)jotH/Y]f^"@ ,DFгi v)51tp0 w\D|0܇Ρ]GÇF[+lU֤Z$0:Y[lgTgvmY=Xyr8,F7oxA\EXÃ7<(隰j[x [m=)ZZy=ЮpW=rq/?seO{(gЇr{w"\c}[|{WM4^}F]kJua]%9\mw-xjB,E<чܚ^ym?UmF`yKes'(6ήAcYڒ>iH9Q1_=pR]>7}PNP 5^z8z:#E{I"M#oS&08֞5">[]զ6J[݉Luxc,_iSO>@G9{s`Ãya* 띃#lH,+z+Y˔wx<җ\)Vw@eo{wRLQ|W6$Kt0|]VnX<^xm25&;iN߹A~7N}ǰzݏ;\?>E<}M;|nv f =='dô/F?% &-CUT6wZnnp{:nyޖ^e^Ҿ?q,ysV?9/;# ;w8'wzA{*7COUK\5dm1vaLJ2=llyfg0S+=˲2'Ө7_&m:X@~/ z֗w HfYFU1}5f/HHfG -:dqaܭ>wz3:ug.4N Ol4e/|ɾ۸b7ܜ?g_SKf]NB.K= LS&P=c˺[\7.`),9y`՘wo;lAkA1e넙a|6DQvʵs׍>6YH6P_x;HL&sn>˂z{zhr!7_MYF䗝oc3O5;&5S{<'J']9ankulsUSɊsOv]s)87'bS6N}\r?)8pxbvTx6qZ1;iٯ4S Dg:11>ģy~ xA<+jo>l{*~iB"+qh, sRha( `1h+sGM[S^K}F1_Z|ۋGRhІ>P$i~:>7Zf~ϭ9hX@JY[{~^Ϭ$$<@%ԖD 5A!N5N3ݽV+mHe^c59)ill$Tdʲ(+'2} x]LS2C Hd1ORsx: "KB8Z0y~<,/x :Qo۲P ùbN!DF$GgpBc,փi6 mmүKIPc S qxκvcn_(hW1~oo %SU.!Nja`bzK:şBC$AsgxUyaa{K W`ͶRš߇Ω*YMGU>ҒAOB(gKB@\ j瓜0t:rc[Ho=yjJOsekc3]K0;Ou}G52g7@Դm+_eU)ȢpQ;yԤRr!!&#9ovw}/Y<^=+*7UnZ֊r5Ư˼ IHS.E9}h7)׉U?pNZ,a$@{yKVi3Y)I!bPM>^!J6Rw|g A2atG&;zژv9 <ٝ>gnҚ=.zaU5BΘ|TgKIE09Rfug8!f+]~s=O_.pdY^vܱd-Qi5Ex䘦7:h7Njww:挒<~pj Xk2"m$P t2툒;Sk1RU'>6smQ d s6ښt*%W6Ӹm8ۧxU.;fŕ*!FC u >4f &E^4ykrgq/C\xk{N:ʄX)P*۷IĐWlT[_7˖yͮQ̫]9Ds.tS \~KZZP9F*ֹFyTeE*]Lń n8i=.6[HȠ7!I[ϖ 7{u7uHy'`DX#.lrдm;ofmqю+ջ!4Eqߙ(ty4PjR!j/m%PQ<ۙ!U"^ϓyx~q$ ƍUr樷wF\|떺"QW+)EPyy<ם*Wwq#AXԡÉ 6ˌH8IDQ̾wH8FmTJ"Lw$P&i_i#}BZ&*mulÄaOG< #6 Xa˪M+;iFI8Rvgkvi>Hu.RV ((a깴D۝ֈ3,[^ҫ[wQO<4g3!ԞPP,9GӢbd2k6 gS{/yݙXHp'ρ {ji}UPRyO{U(؏9,i+8]?rܶ0L%t$!`@}F׀*m¢eY)z֌dcAhTHHFǯj܌S fg{^a d "zuΕK;y:+1 u"a8 BL rE>F.0fJ?^D#ujkDET8On("I "zB[39/2: ovHv}TODT/#uiV,j6]=@Qd-WH7Ch4hq;K/q soQs!WG}Ai\Tkw+l;fl??3.>7۞x<{339a'x6M$1DǎxW%B"ͻL#'nCksZ\n+{uBNeMW#{di:N<'+sg#>2j*2@]iy6+O{l~Kץ>Yu{(et\lł2:n |q}r ^Q,@S#LL1 zͮ}NT`, n:R8n{r3F|T;;owv!h}[@z}]Q*Hys={^/nXr=Og^:O`*9Mظpʹ#5:5t0a-G *G=L˦rªM{g/nJPD-Sh$Z@(ݻw 7Z 82;YUOu7]0a'2bj+$rSV*$61^KN4rm}ۛgL]v^R.S;Of:(ܛo{L{BXaCdˆ͓Wt]~uo[1`eXQM@V|b=֊YBC򪡈]2iX~G7 'nŸW aVS[v@=.FsK< lݔ{JtH=+"^~]O-XX $54ޟT1,.>Bpnat'v:`Nx7[WqnwJ'"Ov~82Ya5G˚itL-y!UIEsQ|f9NkuX5<mwLصK<6P*H^tuKN5xt=p{sоݛwX2;8}A>oHY~&NT~M`ޙ`[qIB}%;Q*Xv3%iY6FW3Bޯnwk$eZ c)R